From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/third_party/Makefile.in | 31 + comm/third_party/README.asn1js | 19 + comm/third_party/README.botan | 20 + comm/third_party/README.bzip2 | 44 + comm/third_party/README.json-c | 36 + comm/third_party/README.libgcrypt | 7 + comm/third_party/README.libgpg-error | 7 + comm/third_party/README.libotr | 7 + comm/third_party/README.niwcompat | 6 + comm/third_party/README.rnp | 87 + comm/third_party/README.zlib | 53 + comm/third_party/asn1js/LICENSE | 30 + comm/third_party/asn1js/asn1js.mjs | 3913 ++++ comm/third_party/asn1js/make_bundle.sh | 17 + comm/third_party/asn1js/moz.build | 7 + comm/third_party/asn1js/moz.yaml | 91 + comm/third_party/asn1js/package.json | 77 + comm/third_party/asn1js/src/Any.ts | 22 + comm/third_party/asn1js/src/BaseBlock.ts | 186 + comm/third_party/asn1js/src/BaseStringBlock.ts | 74 + comm/third_party/asn1js/src/BitString.ts | 64 + comm/third_party/asn1js/src/BmpString.ts | 23 + comm/third_party/asn1js/src/Boolean.ts | 43 + comm/third_party/asn1js/src/CharacterString.ts | 22 + comm/third_party/asn1js/src/Choice.ts | 22 + comm/third_party/asn1js/src/Constructed.ts | 61 + comm/third_party/asn1js/src/DATE.ts | 22 + comm/third_party/asn1js/src/DateTime.ts | 22 + comm/third_party/asn1js/src/Duration.ts | 21 + comm/third_party/asn1js/src/EndOfContent.ts | 23 + comm/third_party/asn1js/src/Enumerated.ts | 22 + comm/third_party/asn1js/src/GeneralString.ts | 22 + comm/third_party/asn1js/src/GeneralizedTime.ts | 262 + comm/third_party/asn1js/src/GraphicString.ts | 22 + comm/third_party/asn1js/src/HexBlock.ts | 110 + comm/third_party/asn1js/src/IA5String.ts | 22 + comm/third_party/asn1js/src/Integer.ts | 103 + comm/third_party/asn1js/src/Null.ts | 65 + comm/third_party/asn1js/src/NumericString.ts | 22 + comm/third_party/asn1js/src/ObjectIdentifier.ts | 53 + comm/third_party/asn1js/src/OctetString.ts | 103 + comm/third_party/asn1js/src/Primitive.ts | 22 + comm/third_party/asn1js/src/PrintableString.ts | 22 + comm/third_party/asn1js/src/RawData.ts | 51 + .../asn1js/src/RelativeObjectIdentifier.ts | 54 + comm/third_party/asn1js/src/Repeated.ts | 26 + comm/third_party/asn1js/src/Sequence.ts | 22 + comm/third_party/asn1js/src/Set.ts | 22 + comm/third_party/asn1js/src/TIME.ts | 22 + comm/third_party/asn1js/src/TeletexString.ts | 22 + comm/third_party/asn1js/src/TimeOfDay.ts | 22 + comm/third_party/asn1js/src/TypeStore.ts | 71 + comm/third_party/asn1js/src/UTCTime.ts | 172 + comm/third_party/asn1js/src/UniversalString.ts | 24 + comm/third_party/asn1js/src/Utf8String.ts | 24 + comm/third_party/asn1js/src/ValueBlock.ts | 21 + comm/third_party/asn1js/src/VideotexString.ts | 22 + comm/third_party/asn1js/src/ViewWriter.ts | 22 + comm/third_party/asn1js/src/VisibleString.ts | 22 + comm/third_party/asn1js/src/index.ts | 59 + .../asn1js/src/internals/LocalBaseBlock.ts | 93 + .../src/internals/LocalBitStringValueBlock.ts | 168 + .../src/internals/LocalBmpStringValueBlock.ts | 21 + .../asn1js/src/internals/LocalBooleanValueBlock.ts | 96 + .../src/internals/LocalConstructedValueBlock.ts | 128 + .../src/internals/LocalEndOfContentValueBlock.ts | 16 + .../src/internals/LocalIdentificationBlock.ts | 280 + .../asn1js/src/internals/LocalIntegerValueBlock.ts | 330 + .../asn1js/src/internals/LocalLengthBlock.ts | 182 + .../internals/LocalObjectIdentifierValueBlock.ts | 192 + .../src/internals/LocalOctetStringValueBlock.ts | 103 + .../src/internals/LocalPrimitiveValueBlock.ts | 36 + .../LocalRelativeObjectIdentifierValueBlock.ts | 140 + .../src/internals/LocalRelativeSidValueBlock.ts | 140 + .../asn1js/src/internals/LocalSidValueBlock.ts | 197 + .../asn1js/src/internals/LocalSimpleStringBlock.ts | 34 + .../src/internals/LocalSimpleStringValueBlock.ts | 11 + .../asn1js/src/internals/LocalStringValueBlock.ts | 52 + .../LocalUniversalStringValueBlockParams.ts | 45 + .../src/internals/LocalUtf8StringValueBlock.ts | 27 + comm/third_party/asn1js/src/internals/constants.ts | 20 + comm/third_party/asn1js/src/internals/utils.ts | 81 + comm/third_party/asn1js/src/parser.ts | 301 + comm/third_party/asn1js/src/schema.ts | 475 + comm/third_party/asn1js/src/types.ts | 62 + comm/third_party/asn1js/tsconfig.json | 15 + comm/third_party/asn1js/yarn.lock | 2373 ++ comm/third_party/botan/Makefile.in | 12 + comm/third_party/botan/botan.mozbuild | 238 + comm/third_party/botan/botan_configure.py | 121 + comm/third_party/botan/configure.py | 3454 +++ comm/third_party/botan/doc/abi.rst | 21 + comm/third_party/botan/doc/api_ref/bigint.rst | 279 + .../third_party/botan/doc/api_ref/block_cipher.rst | 364 + .../third_party/botan/doc/api_ref/cipher_modes.rst | 384 + comm/third_party/botan/doc/api_ref/compression.rst | 90 + comm/third_party/botan/doc/api_ref/contents.rst | 39 + .../botan/doc/api_ref/credentials_manager.rst | 186 + comm/third_party/botan/doc/api_ref/cryptobox.rst | 32 + comm/third_party/botan/doc/api_ref/ecc.rst | 284 + comm/third_party/botan/doc/api_ref/env_vars.rst | 20 + comm/third_party/botan/doc/api_ref/ffi.rst | 1203 + comm/third_party/botan/doc/api_ref/filters.rst | 733 + comm/third_party/botan/doc/api_ref/fpe.rst | 98 + comm/third_party/botan/doc/api_ref/hash.rst | 351 + comm/third_party/botan/doc/api_ref/kdf.rst | 109 + comm/third_party/botan/doc/api_ref/keywrap.rst | 60 + .../botan/doc/api_ref/message_auth_codes.rst | 268 + comm/third_party/botan/doc/api_ref/otp.rst | 98 + comm/third_party/botan/doc/api_ref/passhash.rst | 219 + comm/third_party/botan/doc/api_ref/pbkdf.rst | 190 + comm/third_party/botan/doc/api_ref/pkcs11.rst | 1419 ++ comm/third_party/botan/doc/api_ref/psk_db.rst | 110 + comm/third_party/botan/doc/api_ref/pubkey.rst | 954 + comm/third_party/botan/doc/api_ref/python.rst | 668 + comm/third_party/botan/doc/api_ref/rng.rst | 281 + comm/third_party/botan/doc/api_ref/roughtime.rst | 6 + comm/third_party/botan/doc/api_ref/secmem.rst | 31 + comm/third_party/botan/doc/api_ref/srp.rst | 77 + .../botan/doc/api_ref/stream_ciphers.rst | 211 + comm/third_party/botan/doc/api_ref/tls.rst | 1926 ++ comm/third_party/botan/doc/api_ref/tpm.rst | 113 + comm/third_party/botan/doc/api_ref/tss.rst | 45 + comm/third_party/botan/doc/api_ref/versions.rst | 100 + comm/third_party/botan/doc/api_ref/x509.rst | 914 + comm/third_party/botan/doc/authors.txt | 102 + comm/third_party/botan/doc/building.rst | 1019 + comm/third_party/botan/doc/cli.rst | 406 + comm/third_party/botan/doc/contents.rst | 25 + comm/third_party/botan/doc/credits.rst | 156 + comm/third_party/botan/doc/deprecated.rst | 302 + comm/third_party/botan/doc/dev_ref/configure.rst | 407 + comm/third_party/botan/doc/dev_ref/contents.rst | 20 + .../botan/doc/dev_ref/continuous_integration.rst | 75 + .../third_party/botan/doc/dev_ref/contributing.rst | 268 + comm/third_party/botan/doc/dev_ref/fuzzing.rst | 91 + comm/third_party/botan/doc/dev_ref/mistakes.rst | 77 + comm/third_party/botan/doc/dev_ref/oids.rst | 43 + comm/third_party/botan/doc/dev_ref/os.rst | 61 + .../third_party/botan/doc/dev_ref/reading_list.rst | 93 + .../botan/doc/dev_ref/release_process.rst | 129 + .../botan/doc/dev_ref/test_framework.rst | 314 + comm/third_party/botan/doc/dev_ref/todo.rst | 199 + comm/third_party/botan/doc/goals.rst | 131 + comm/third_party/botan/doc/index.rst | 58 + comm/third_party/botan/doc/old_news.rst | 4336 ++++ comm/third_party/botan/doc/packaging.rst | 59 + comm/third_party/botan/doc/pgpkey.txt | 198 + comm/third_party/botan/doc/roadmap.rst | 54 + comm/third_party/botan/doc/security.rst | 352 + comm/third_party/botan/doc/side_channels.rst | 449 + comm/third_party/botan/doc/support.rst | 70 + comm/third_party/botan/license.txt | 24 + comm/third_party/botan/moz.build | 14 + comm/third_party/botan/news.rst | 1879 ++ comm/third_party/botan/readme.rst | 135 + comm/third_party/botan/src/bogo_shim/bogo_shim.cpp | 1680 ++ comm/third_party/botan/src/bogo_shim/config.json | 129 + .../botan/src/build-data/arch/alpha.txt | 7 + .../botan/src/build-data/arch/arm32.txt | 21 + .../botan/src/build-data/arch/arm64.txt | 20 + .../botan/src/build-data/arch/generic.txt | 4 + .../third_party/botan/src/build-data/arch/hppa.txt | 8 + .../third_party/botan/src/build-data/arch/ia64.txt | 6 + .../third_party/botan/src/build-data/arch/llvm.txt | 1 + .../third_party/botan/src/build-data/arch/m68k.txt | 6 + .../botan/src/build-data/arch/mips32.txt | 6 + .../botan/src/build-data/arch/mips64.txt | 5 + .../botan/src/build-data/arch/powerpcspe.txt | 3 + .../botan/src/build-data/arch/ppc32.txt | 12 + .../botan/src/build-data/arch/ppc64.txt | 17 + .../botan/src/build-data/arch/riscv32.txt | 2 + .../botan/src/build-data/arch/riscv64.txt | 3 + .../third_party/botan/src/build-data/arch/s390.txt | 1 + .../botan/src/build-data/arch/s390x.txt | 2 + .../botan/src/build-data/arch/sparc32.txt | 7 + .../botan/src/build-data/arch/sparc64.txt | 3 + .../botan/src/build-data/arch/superh.txt | 4 + comm/third_party/botan/src/build-data/arch/x32.txt | 16 + .../botan/src/build-data/arch/x86_32.txt | 32 + .../botan/src/build-data/arch/x86_64.txt | 25 + comm/third_party/botan/src/build-data/bakefile.in | 51 + .../third_party/botan/src/build-data/botan.doxy.in | 226 + comm/third_party/botan/src/build-data/botan.pc.in | 12 + comm/third_party/botan/src/build-data/buildh.in | 268 + comm/third_party/botan/src/build-data/cc/clang.txt | 85 + .../botan/src/build-data/cc/ekopath.txt | 17 + comm/third_party/botan/src/build-data/cc/gcc.txt | 99 + comm/third_party/botan/src/build-data/cc/hpcc.txt | 18 + comm/third_party/botan/src/build-data/cc/icc.txt | 24 + comm/third_party/botan/src/build-data/cc/msvc.txt | 84 + comm/third_party/botan/src/build-data/cc/pgi.txt | 15 + .../botan/src/build-data/cc/sunstudio.txt | 39 + comm/third_party/botan/src/build-data/cc/xlc.txt | 26 + comm/third_party/botan/src/build-data/cmake.in | 73 + .../botan/src/build-data/detect_arch.cpp | 76 + .../botan/src/build-data/detect_version.cpp | 60 + comm/third_party/botan/src/build-data/innosetup.in | 73 + comm/third_party/botan/src/build-data/makefile.in | 146 + comm/third_party/botan/src/build-data/oids.txt | 335 + comm/third_party/botan/src/build-data/os/aix.txt | 18 + .../botan/src/build-data/os/android.txt | 26 + .../third_party/botan/src/build-data/os/cygwin.txt | 20 + .../botan/src/build-data/os/dragonfly.txt | 17 + .../botan/src/build-data/os/emscripten.txt | 17 + .../botan/src/build-data/os/freebsd.txt | 22 + comm/third_party/botan/src/build-data/os/haiku.txt | 25 + comm/third_party/botan/src/build-data/os/hpux.txt | 20 + comm/third_party/botan/src/build-data/os/hurd.txt | 19 + .../botan/src/build-data/os/includeos.txt | 5 + comm/third_party/botan/src/build-data/os/ios.txt | 23 + comm/third_party/botan/src/build-data/os/linux.txt | 26 + comm/third_party/botan/src/build-data/os/llvm.txt | 15 + comm/third_party/botan/src/build-data/os/macos.txt | 32 + comm/third_party/botan/src/build-data/os/mingw.txt | 33 + comm/third_party/botan/src/build-data/os/nacl.txt | 6 + .../third_party/botan/src/build-data/os/netbsd.txt | 21 + comm/third_party/botan/src/build-data/os/none.txt | 4 + .../botan/src/build-data/os/openbsd.txt | 25 + comm/third_party/botan/src/build-data/os/qnx.txt | 18 + .../botan/src/build-data/os/solaris.txt | 21 + comm/third_party/botan/src/build-data/os/uwp.txt | 25 + .../botan/src/build-data/os/windows.txt | 48 + .../botan/src/build-data/policy/bsi.txt | 188 + .../botan/src/build-data/policy/modern.txt | 131 + .../botan/src/build-data/policy/nist.txt | 187 + comm/third_party/botan/src/build-data/version.txt | 11 + comm/third_party/botan/src/cli/argon2.cpp | 78 + comm/third_party/botan/src/cli/argparse.h | 280 + comm/third_party/botan/src/cli/asn1.cpp | 89 + comm/third_party/botan/src/cli/bcrypt.cpp | 89 + comm/third_party/botan/src/cli/cc_enc.cpp | 189 + comm/third_party/botan/src/cli/cli.cpp | 349 + comm/third_party/botan/src/cli/cli.h | 219 + comm/third_party/botan/src/cli/cli_exceptions.h | 47 + comm/third_party/botan/src/cli/cli_rng.cpp | 146 + comm/third_party/botan/src/cli/codec.cpp | 268 + comm/third_party/botan/src/cli/compress.cpp | 190 + comm/third_party/botan/src/cli/encryption.cpp | 127 + comm/third_party/botan/src/cli/entropy.cpp | 104 + comm/third_party/botan/src/cli/hash.cpp | 78 + comm/third_party/botan/src/cli/hmac.cpp | 78 + comm/third_party/botan/src/cli/main.cpp | 37 + comm/third_party/botan/src/cli/math.cpp | 269 + comm/third_party/botan/src/cli/pbkdf.cpp | 99 + comm/third_party/botan/src/cli/pk_crypt.cpp | 229 + comm/third_party/botan/src/cli/psk.cpp | 106 + comm/third_party/botan/src/cli/pubkey.cpp | 554 + comm/third_party/botan/src/cli/roughtime.cpp | 215 + comm/third_party/botan/src/cli/sandbox.cpp | 115 + comm/third_party/botan/src/cli/sandbox.h | 32 + comm/third_party/botan/src/cli/socket_utils.h | 105 + comm/third_party/botan/src/cli/speed.cpp | 2342 ++ comm/third_party/botan/src/cli/timing_tests.cpp | 617 + comm/third_party/botan/src/cli/tls_client.cpp | 436 + comm/third_party/botan/src/cli/tls_helpers.h | 244 + comm/third_party/botan/src/cli/tls_http_server.cpp | 579 + comm/third_party/botan/src/cli/tls_proxy.cpp | 526 + comm/third_party/botan/src/cli/tls_server.cpp | 364 + comm/third_party/botan/src/cli/tls_utils.cpp | 226 + comm/third_party/botan/src/cli/tss.cpp | 138 + comm/third_party/botan/src/cli/utils.cpp | 391 + comm/third_party/botan/src/cli/x509.cpp | 417 + comm/third_party/botan/src/configs/astyle.rc | 14 + comm/third_party/botan/src/configs/coverage.rc | 18 + comm/third_party/botan/src/configs/eclipse.xml | 167 + comm/third_party/botan/src/configs/indent.el | 55 + comm/third_party/botan/src/configs/pylint.rc | 379 + .../botan/src/configs/sonar-project.properties | 18 + comm/third_party/botan/src/configs/sphinx/conf.py | 220 + .../botan/src/configs/sphinx/templates/layout.html | 9 + comm/third_party/botan/src/fuzzer/asn1.cpp | 43 + comm/third_party/botan/src/fuzzer/barrett.cpp | 49 + comm/third_party/botan/src/fuzzer/bn_cmp.cpp | 74 + comm/third_party/botan/src/fuzzer/bn_sqr.cpp | 24 + comm/third_party/botan/src/fuzzer/cert.cpp | 22 + comm/third_party/botan/src/fuzzer/crl.cpp | 19 + comm/third_party/botan/src/fuzzer/divide.cpp | 52 + comm/third_party/botan/src/fuzzer/ecc_bp256.cpp | 16 + comm/third_party/botan/src/fuzzer/ecc_helper.h | 107 + comm/third_party/botan/src/fuzzer/ecc_p256.cpp | 15 + comm/third_party/botan/src/fuzzer/ecc_p384.cpp | 15 + comm/third_party/botan/src/fuzzer/ecc_p521.cpp | 15 + comm/third_party/botan/src/fuzzer/fuzzers.h | 150 + comm/third_party/botan/src/fuzzer/invert.cpp | 82 + comm/third_party/botan/src/fuzzer/mem_pool.cpp | 193 + comm/third_party/botan/src/fuzzer/mode_padding.cpp | 169 + comm/third_party/botan/src/fuzzer/oaep.cpp | 102 + comm/third_party/botan/src/fuzzer/ocsp.cpp | 17 + comm/third_party/botan/src/fuzzer/os2ecp.cpp | 44 + comm/third_party/botan/src/fuzzer/pkcs1.cpp | 75 + comm/third_party/botan/src/fuzzer/pkcs8.cpp | 27 + comm/third_party/botan/src/fuzzer/pow_mod.cpp | 72 + comm/third_party/botan/src/fuzzer/redc_p192.cpp | 31 + comm/third_party/botan/src/fuzzer/redc_p224.cpp | 31 + comm/third_party/botan/src/fuzzer/redc_p256.cpp | 31 + comm/third_party/botan/src/fuzzer/redc_p384.cpp | 31 + comm/third_party/botan/src/fuzzer/redc_p521.cpp | 31 + comm/third_party/botan/src/fuzzer/ressol.cpp | 44 + comm/third_party/botan/src/fuzzer/tls_client.cpp | 130 + .../botan/src/fuzzer/tls_client_hello.cpp | 18 + comm/third_party/botan/src/fuzzer/tls_server.cpp | 227 + comm/third_party/botan/src/fuzzer/uri.cpp | 20 + comm/third_party/botan/src/fuzzer/x509_dn.cpp | 41 + comm/third_party/botan/src/lib/asn1/alg_id.cpp | 109 + comm/third_party/botan/src/lib/asn1/alg_id.h | 14 + comm/third_party/botan/src/lib/asn1/asn1_obj.cpp | 238 + comm/third_party/botan/src/lib/asn1/asn1_obj.h | 475 + comm/third_party/botan/src/lib/asn1/asn1_oid.cpp | 216 + comm/third_party/botan/src/lib/asn1/asn1_oid.h | 14 + comm/third_party/botan/src/lib/asn1/asn1_print.cpp | 327 + comm/third_party/botan/src/lib/asn1/asn1_print.h | 125 + comm/third_party/botan/src/lib/asn1/asn1_str.cpp | 153 + comm/third_party/botan/src/lib/asn1/asn1_str.h | 14 + comm/third_party/botan/src/lib/asn1/asn1_time.cpp | 290 + comm/third_party/botan/src/lib/asn1/asn1_time.h | 14 + comm/third_party/botan/src/lib/asn1/ber_dec.cpp | 549 + comm/third_party/botan/src/lib/asn1/ber_dec.h | 418 + comm/third_party/botan/src/lib/asn1/der_enc.cpp | 405 + comm/third_party/botan/src/lib/asn1/der_enc.h | 227 + comm/third_party/botan/src/lib/asn1/info.txt | 7 + comm/third_party/botan/src/lib/asn1/oid_maps.cpp | 510 + comm/third_party/botan/src/lib/asn1/oids.cpp | 134 + comm/third_party/botan/src/lib/asn1/oids.h | 98 + comm/third_party/botan/src/lib/base/botan.h | 41 + comm/third_party/botan/src/lib/base/buf_comp.cpp | 54 + comm/third_party/botan/src/lib/base/buf_comp.h | 178 + comm/third_party/botan/src/lib/base/info.txt | 17 + comm/third_party/botan/src/lib/base/init.h | 35 + comm/third_party/botan/src/lib/base/key_spec.h | 14 + comm/third_party/botan/src/lib/base/lookup.h | 179 + comm/third_party/botan/src/lib/base/scan_name.cpp | 149 + comm/third_party/botan/src/lib/base/scan_name.h | 124 + comm/third_party/botan/src/lib/base/secmem.h | 136 + comm/third_party/botan/src/lib/base/sym_algo.cpp | 24 + comm/third_party/botan/src/lib/base/sym_algo.h | 190 + comm/third_party/botan/src/lib/base/symkey.cpp | 134 + comm/third_party/botan/src/lib/base/symkey.h | 150 + comm/third_party/botan/src/lib/block/aes/aes.cpp | 1017 + comm/third_party/botan/src/lib/block/aes/aes.h | 131 + .../src/lib/block/aes/aes_armv8/aes_armv8.cpp | 484 + .../botan/src/lib/block/aes/aes_armv8/info.txt | 12 + .../botan/src/lib/block/aes/aes_ni/aes_ni.cpp | 780 + .../botan/src/lib/block/aes/aes_ni/info.txt | 9 + .../src/lib/block/aes/aes_power8/aes_power8.cpp | 529 + .../botan/src/lib/block/aes/aes_power8/info.txt | 11 + .../src/lib/block/aes/aes_vperm/aes_vperm.cpp | 627 + .../botan/src/lib/block/aes/aes_vperm/info.txt | 36 + comm/third_party/botan/src/lib/block/aes/info.txt | 3 + comm/third_party/botan/src/lib/block/aria/aria.cpp | 506 + comm/third_party/botan/src/lib/block/aria/aria.h | 84 + comm/third_party/botan/src/lib/block/aria/info.txt | 7 + .../botan/src/lib/block/block_cipher.cpp | 363 + .../third_party/botan/src/lib/block/block_cipher.h | 254 + .../botan/src/lib/block/blowfish/blowfish.cpp | 456 + .../botan/src/lib/block/blowfish/blowfish.h | 62 + .../botan/src/lib/block/blowfish/info.txt | 3 + .../botan/src/lib/block/camellia/camellia.cpp | 924 + .../botan/src/lib/block/camellia/camellia.h | 73 + .../botan/src/lib/block/camellia/info.txt | 7 + .../botan/src/lib/block/cascade/cascade.cpp | 93 + .../botan/src/lib/block/cascade/cascade.h | 57 + .../botan/src/lib/block/cascade/info.txt | 7 + .../botan/src/lib/block/cast128/cast128.cpp | 471 + .../botan/src/lib/block/cast128/cast128.h | 42 + .../botan/src/lib/block/cast128/cast_sboxes.h | 197 + .../botan/src/lib/block/cast128/info.txt | 12 + .../botan/src/lib/block/cast256/cast256.cpp | 232 + .../botan/src/lib/block/cast256/cast256.h | 38 + .../botan/src/lib/block/cast256/info.txt | 7 + comm/third_party/botan/src/lib/block/des/des.cpp | 410 + comm/third_party/botan/src/lib/block/des/des.h | 67 + .../botan/src/lib/block/des/des_tab.cpp | 372 + comm/third_party/botan/src/lib/block/des/desx.cpp | 65 + comm/third_party/botan/src/lib/block/des/desx.h | 37 + comm/third_party/botan/src/lib/block/des/info.txt | 3 + .../botan/src/lib/block/gost_28147/gost_28147.cpp | 189 + .../botan/src/lib/block/gost_28147/gost_28147.h | 95 + .../botan/src/lib/block/gost_28147/info.txt | 3 + comm/third_party/botan/src/lib/block/idea/idea.cpp | 240 + comm/third_party/botan/src/lib/block/idea/idea.h | 45 + .../src/lib/block/idea/idea_sse2/idea_sse2.cpp | 208 + .../botan/src/lib/block/idea/idea_sse2/info.txt | 7 + comm/third_party/botan/src/lib/block/idea/info.txt | 3 + comm/third_party/botan/src/lib/block/info.txt | 7 + .../botan/src/lib/block/kasumi/info.txt | 3 + .../botan/src/lib/block/kasumi/kasumi.cpp | 238 + .../botan/src/lib/block/kasumi/kasumi.h | 37 + comm/third_party/botan/src/lib/block/lion/info.txt | 8 + comm/third_party/botan/src/lib/block/lion/lion.cpp | 138 + comm/third_party/botan/src/lib/block/lion/lion.h | 66 + .../botan/src/lib/block/misty1/info.txt | 3 + .../botan/src/lib/block/misty1/misty1.cpp | 263 + .../botan/src/lib/block/misty1/misty1.h | 37 + .../botan/src/lib/block/noekeon/info.txt | 3 + .../botan/src/lib/block/noekeon/noekeon.cpp | 267 + .../botan/src/lib/block/noekeon/noekeon.h | 49 + .../src/lib/block/noekeon/noekeon_simd/info.txt | 8 + .../block/noekeon/noekeon_simd/noekeon_simd.cpp | 143 + comm/third_party/botan/src/lib/block/seed/info.txt | 3 + comm/third_party/botan/src/lib/block/seed/seed.cpp | 328 + comm/third_party/botan/src/lib/block/seed/seed.h | 37 + .../botan/src/lib/block/serpent/info.txt | 11 + .../botan/src/lib/block/serpent/serpent.cpp | 299 + .../botan/src/lib/block/serpent/serpent.h | 53 + .../src/lib/block/serpent/serpent_avx2/info.txt | 17 + .../block/serpent/serpent_avx2/serpent_avx2.cpp | 169 + .../botan/src/lib/block/serpent/serpent_sbox.h | 446 + .../src/lib/block/serpent/serpent_simd/info.txt | 7 + .../block/serpent/serpent_simd/serpent_simd.cpp | 169 + .../botan/src/lib/block/shacal2/info.txt | 5 + .../botan/src/lib/block/shacal2/shacal2.cpp | 280 + .../botan/src/lib/block/shacal2/shacal2.h | 54 + .../src/lib/block/shacal2/shacal2_avx2/info.txt | 11 + .../block/shacal2/shacal2_avx2/shacal2_avx2.cpp | 122 + .../src/lib/block/shacal2/shacal2_simd/info.txt | 8 + .../block/shacal2/shacal2_simd/shacal2_simd.cpp | 119 + .../src/lib/block/shacal2/shacal2_x86/info.txt | 20 + .../lib/block/shacal2/shacal2_x86/shacal2_x86.cpp | 118 + comm/third_party/botan/src/lib/block/sm4/info.txt | 3 + comm/third_party/botan/src/lib/block/sm4/sm4.cpp | 341 + comm/third_party/botan/src/lib/block/sm4/sm4.h | 45 + .../botan/src/lib/block/sm4/sm4_armv8/info.txt | 11 + .../src/lib/block/sm4/sm4_armv8/sm4_armv8.cpp | 174 + .../botan/src/lib/block/threefish_512/info.txt | 3 + .../botan/src/lib/block/threefish_512/threefish.h | 17 + .../src/lib/block/threefish_512/threefish_512.cpp | 273 + .../src/lib/block/threefish_512/threefish_512.h | 57 + .../threefish_512/threefish_512_avx2/info.txt | 14 + .../threefish_512_avx2/threefish_512_avx2.cpp | 444 + .../botan/src/lib/block/twofish/info.txt | 3 + .../botan/src/lib/block/twofish/twofish.cpp | 326 + .../botan/src/lib/block/twofish/twofish.h | 47 + .../botan/src/lib/block/twofish/twofish_tab.cpp | 293 + comm/third_party/botan/src/lib/block/xtea/info.txt | 3 + comm/third_party/botan/src/lib/block/xtea/xtea.cpp | 134 + comm/third_party/botan/src/lib/block/xtea/xtea.h | 37 + .../botan/src/lib/codec/base32/base32.cpp | 233 + .../botan/src/lib/codec/base32/base32.h | 127 + .../botan/src/lib/codec/base32/info.txt | 3 + .../botan/src/lib/codec/base58/base58.cpp | 189 + .../botan/src/lib/codec/base58/base58.h | 76 + .../botan/src/lib/codec/base58/info.txt | 8 + .../botan/src/lib/codec/base64/base64.cpp | 248 + .../botan/src/lib/codec/base64/base64.h | 141 + .../botan/src/lib/codec/base64/info.txt | 3 + comm/third_party/botan/src/lib/codec/hex/hex.cpp | 210 + comm/third_party/botan/src/lib/codec/hex/hex.h | 148 + comm/third_party/botan/src/lib/codec/hex/info.txt | 3 + .../botan/src/lib/compat/sodium/info.txt | 17 + .../botan/src/lib/compat/sodium/sodium.h | 1453 ++ .../botan/src/lib/compat/sodium/sodium_25519.cpp | 60 + .../botan/src/lib/compat/sodium/sodium_aead.cpp | 359 + .../botan/src/lib/compat/sodium/sodium_auth.cpp | 131 + .../botan/src/lib/compat/sodium/sodium_box.cpp | 100 + .../botan/src/lib/compat/sodium/sodium_chacha.cpp | 109 + .../botan/src/lib/compat/sodium/sodium_salsa.cpp | 124 + .../src/lib/compat/sodium/sodium_secretbox.cpp | 123 + .../botan/src/lib/compat/sodium/sodium_utils.cpp | 160 + .../botan/src/lib/compression/bzip2/bzip2.cpp | 110 + .../botan/src/lib/compression/bzip2/bzip2.h | 40 + .../botan/src/lib/compression/bzip2/info.txt | 9 + .../botan/src/lib/compression/compress_utils.cpp | 196 + .../botan/src/lib/compression/compress_utils.h | 89 + .../botan/src/lib/compression/compression.cpp | 116 + .../botan/src/lib/compression/compression.h | 238 + .../third_party/botan/src/lib/compression/info.txt | 11 + .../botan/src/lib/compression/lzma/info.txt | 9 + .../botan/src/lib/compression/lzma/lzma.cpp | 95 + .../botan/src/lib/compression/lzma/lzma.h | 42 + .../botan/src/lib/compression/zlib/info.txt | 10 + .../botan/src/lib/compression/zlib/zlib.cpp | 173 + .../botan/src/lib/compression/zlib/zlib.h | 89 + .../src/lib/entropy/dev_random/dev_random.cpp | 122 + .../botan/src/lib/entropy/dev_random/dev_random.h | 37 + .../botan/src/lib/entropy/dev_random/info.txt | 11 + .../botan/src/lib/entropy/entropy_src.h | 87 + .../botan/src/lib/entropy/entropy_srcs.cpp | 235 + .../src/lib/entropy/getentropy/getentropy.cpp | 35 + .../botan/src/lib/entropy/getentropy/getentropy.h | 28 + .../botan/src/lib/entropy/getentropy/info.txt | 11 + comm/third_party/botan/src/lib/entropy/info.txt | 7 + .../botan/src/lib/entropy/proc_walk/info.txt | 11 + .../botan/src/lib/entropy/proc_walk/proc_walk.cpp | 154 + .../botan/src/lib/entropy/proc_walk/proc_walk.h | 45 + .../botan/src/lib/entropy/rdseed/info.txt | 19 + .../botan/src/lib/entropy/rdseed/rdseed.cpp | 97 + .../botan/src/lib/entropy/rdseed/rdseed.h | 28 + .../botan/src/lib/entropy/win32_stats/es_win32.cpp | 59 + .../botan/src/lib/entropy/win32_stats/es_win32.h | 27 + .../botan/src/lib/entropy/win32_stats/info.txt | 15 + comm/third_party/botan/src/lib/ffi/ffi.cpp | 297 + comm/third_party/botan/src/lib/ffi/ffi.h | 1778 ++ comm/third_party/botan/src/lib/ffi/ffi_block.cpp | 112 + comm/third_party/botan/src/lib/ffi/ffi_cert.cpp | 503 + comm/third_party/botan/src/lib/ffi/ffi_cipher.cpp | 233 + comm/third_party/botan/src/lib/ffi/ffi_fpe.cpp | 94 + comm/third_party/botan/src/lib/ffi/ffi_hash.cpp | 91 + comm/third_party/botan/src/lib/ffi/ffi_hotp.cpp | 99 + comm/third_party/botan/src/lib/ffi/ffi_kdf.cpp | 189 + comm/third_party/botan/src/lib/ffi/ffi_keywrap.cpp | 50 + comm/third_party/botan/src/lib/ffi/ffi_mac.cpp | 85 + comm/third_party/botan/src/lib/ffi/ffi_mp.cpp | 312 + comm/third_party/botan/src/lib/ffi/ffi_mp.h | 19 + comm/third_party/botan/src/lib/ffi/ffi_pk_op.cpp | 255 + comm/third_party/botan/src/lib/ffi/ffi_pkey.cpp | 279 + comm/third_party/botan/src/lib/ffi/ffi_pkey.h | 20 + .../botan/src/lib/ffi/ffi_pkey_algs.cpp | 980 + comm/third_party/botan/src/lib/ffi/ffi_rng.cpp | 183 + comm/third_party/botan/src/lib/ffi/ffi_rng.h | 19 + comm/third_party/botan/src/lib/ffi/ffi_totp.cpp | 94 + comm/third_party/botan/src/lib/ffi/ffi_util.h | 182 + comm/third_party/botan/src/lib/ffi/info.txt | 31 + .../botan/src/lib/filters/algo_filt.cpp | 96 + .../third_party/botan/src/lib/filters/b64_filt.cpp | 182 + comm/third_party/botan/src/lib/filters/b64_filt.h | 14 + .../third_party/botan/src/lib/filters/basefilt.cpp | 52 + comm/third_party/botan/src/lib/filters/basefilt.h | 18 + .../third_party/botan/src/lib/filters/buf_filt.cpp | 103 + comm/third_party/botan/src/lib/filters/buf_filt.h | 14 + .../botan/src/lib/filters/cipher_filter.cpp | 103 + .../botan/src/lib/filters/cipher_filter.h | 14 + .../botan/src/lib/filters/comp_filter.cpp | 122 + .../botan/src/lib/filters/comp_filter.h | 15 + .../third_party/botan/src/lib/filters/data_snk.cpp | 75 + comm/third_party/botan/src/lib/filters/data_snk.h | 76 + .../botan/src/lib/filters/fd_unix/fd_unix.cpp | 55 + .../botan/src/lib/filters/fd_unix/fd_unix.h | 35 + .../botan/src/lib/filters/fd_unix/info.txt | 7 + comm/third_party/botan/src/lib/filters/filter.cpp | 129 + comm/third_party/botan/src/lib/filters/filter.h | 175 + comm/third_party/botan/src/lib/filters/filters.h | 741 + .../third_party/botan/src/lib/filters/hex_filt.cpp | 170 + comm/third_party/botan/src/lib/filters/hex_filt.h | 14 + comm/third_party/botan/src/lib/filters/info.txt | 31 + comm/third_party/botan/src/lib/filters/key_filt.h | 14 + comm/third_party/botan/src/lib/filters/out_buf.cpp | 121 + comm/third_party/botan/src/lib/filters/out_buf.h | 44 + comm/third_party/botan/src/lib/filters/pipe.cpp | 311 + comm/third_party/botan/src/lib/filters/pipe.h | 379 + comm/third_party/botan/src/lib/filters/pipe_io.cpp | 47 + comm/third_party/botan/src/lib/filters/pipe_rw.cpp | 181 + .../third_party/botan/src/lib/filters/secqueue.cpp | 232 + comm/third_party/botan/src/lib/filters/secqueue.h | 74 + .../botan/src/lib/filters/threaded_fork.cpp | 153 + .../botan/src/lib/hash/blake2/blake2b.cpp | 207 + .../botan/src/lib/hash/blake2/blake2b.h | 60 + .../third_party/botan/src/lib/hash/blake2/info.txt | 3 + .../src/lib/hash/checksum/adler32/adler32.cpp | 86 + .../botan/src/lib/hash/checksum/adler32/adler32.h | 40 + .../botan/src/lib/hash/checksum/adler32/info.txt | 3 + .../botan/src/lib/hash/checksum/crc24/crc24.cpp | 252 + .../botan/src/lib/hash/checksum/crc24/crc24.h | 41 + .../botan/src/lib/hash/checksum/crc24/info.txt | 3 + .../botan/src/lib/hash/checksum/crc32/crc32.cpp | 111 + .../botan/src/lib/hash/checksum/crc32/crc32.h | 40 + .../botan/src/lib/hash/checksum/crc32/info.txt | 3 + .../botan/src/lib/hash/checksum/info.txt | 4 + .../botan/src/lib/hash/comb4p/comb4p.cpp | 110 + .../third_party/botan/src/lib/hash/comb4p/comb4p.h | 61 + .../third_party/botan/src/lib/hash/comb4p/info.txt | 3 + .../botan/src/lib/hash/gost_3411/gost_3411.cpp | 248 + .../botan/src/lib/hash/gost_3411/gost_3411.h | 47 + .../botan/src/lib/hash/gost_3411/info.txt | 7 + comm/third_party/botan/src/lib/hash/hash.cpp | 360 + comm/third_party/botan/src/lib/hash/hash.h | 91 + comm/third_party/botan/src/lib/hash/info.txt | 7 + .../third_party/botan/src/lib/hash/keccak/info.txt | 7 + .../botan/src/lib/hash/keccak/keccak.cpp | 68 + .../third_party/botan/src/lib/hash/keccak/keccak.h | 51 + comm/third_party/botan/src/lib/hash/md4/info.txt | 7 + comm/third_party/botan/src/lib/hash/md4/md4.cpp | 144 + comm/third_party/botan/src/lib/hash/md4/md4.h | 45 + comm/third_party/botan/src/lib/hash/md5/info.txt | 7 + comm/third_party/botan/src/lib/hash/md5/md5.cpp | 140 + comm/third_party/botan/src/lib/hash/md5/md5.h | 50 + .../botan/src/lib/hash/mdx_hash/info.txt | 5 + .../botan/src/lib/hash/mdx_hash/mdx_hash.cpp | 121 + .../botan/src/lib/hash/mdx_hash/mdx_hash.h | 73 + .../botan/src/lib/hash/par_hash/info.txt | 3 + .../botan/src/lib/hash/par_hash/par_hash.cpp | 86 + .../botan/src/lib/hash/par_hash/par_hash.h | 50 + .../third_party/botan/src/lib/hash/rmd160/info.txt | 7 + .../botan/src/lib/hash/rmd160/rmd160.cpp | 221 + .../third_party/botan/src/lib/hash/rmd160/rmd160.h | 41 + comm/third_party/botan/src/lib/hash/sha1/info.txt | 7 + .../third_party/botan/src/lib/hash/sha1/sha160.cpp | 190 + comm/third_party/botan/src/lib/hash/sha1/sha160.h | 75 + .../botan/src/lib/hash/sha1/sha1_armv8/info.txt | 12 + .../src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp | 207 + .../botan/src/lib/hash/sha1/sha1_sse2/info.txt | 7 + .../src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp | 336 + .../botan/src/lib/hash/sha1/sha1_x86/info.txt | 16 + .../botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp | 216 + .../botan/src/lib/hash/sha2_32/info.txt | 7 + .../botan/src/lib/hash/sha2_32/sha2_32.cpp | 278 + .../botan/src/lib/hash/sha2_32/sha2_32.h | 95 + .../src/lib/hash/sha2_32/sha2_32_armv8/info.txt | 12 + .../hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp | 204 + .../src/lib/hash/sha2_32/sha2_32_bmi2/info.txt | 12 + .../lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp | 140 + .../src/lib/hash/sha2_32/sha2_32_x86/info.txt | 16 + .../lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp | 215 + .../botan/src/lib/hash/sha2_64/info.txt | 7 + .../botan/src/lib/hash/sha2_64/sha2_64.cpp | 281 + .../botan/src/lib/hash/sha2_64/sha2_64.h | 102 + .../src/lib/hash/sha2_64/sha2_64_bmi2/info.txt | 17 + .../lib/hash/sha2_64/sha2_64_bmi2/sha2_64_bmi2.cpp | 153 + comm/third_party/botan/src/lib/hash/sha3/info.txt | 3 + comm/third_party/botan/src/lib/hash/sha3/sha3.cpp | 293 + comm/third_party/botan/src/lib/hash/sha3/sha3.h | 136 + .../botan/src/lib/hash/sha3/sha3_bmi2/info.txt | 17 + .../src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp | 133 + comm/third_party/botan/src/lib/hash/shake/info.txt | 7 + .../third_party/botan/src/lib/hash/shake/shake.cpp | 97 + comm/third_party/botan/src/lib/hash/shake/shake.h | 85 + comm/third_party/botan/src/lib/hash/skein/info.txt | 7 + .../botan/src/lib/hash/skein/skein_512.cpp | 178 + .../botan/src/lib/hash/skein/skein_512.h | 72 + comm/third_party/botan/src/lib/hash/sm3/info.txt | 7 + comm/third_party/botan/src/lib/hash/sm3/sm3.cpp | 259 + comm/third_party/botan/src/lib/hash/sm3/sm3.h | 49 + .../botan/src/lib/hash/streebog/info.txt | 3 + .../botan/src/lib/hash/streebog/streebog.cpp | 207 + .../botan/src/lib/hash/streebog/streebog.h | 72 + .../src/lib/hash/streebog/streebog_precalc.cpp | 866 + comm/third_party/botan/src/lib/hash/tiger/info.txt | 7 + .../botan/src/lib/hash/tiger/tig_tab.cpp | 364 + .../third_party/botan/src/lib/hash/tiger/tiger.cpp | 190 + comm/third_party/botan/src/lib/hash/tiger/tiger.h | 59 + .../botan/src/lib/hash/whirlpool/info.txt | 7 + .../botan/src/lib/hash/whirlpool/whirlpool.cpp | 150 + .../botan/src/lib/hash/whirlpool/whrl_tab.cpp | 540 + .../botan/src/lib/hash/whirlpool/whrlpool.h | 50 + comm/third_party/botan/src/lib/kdf/hkdf/hkdf.cpp | 122 + comm/third_party/botan/src/lib/kdf/hkdf/hkdf.h | 117 + comm/third_party/botan/src/lib/kdf/hkdf/info.txt | 7 + comm/third_party/botan/src/lib/kdf/info.txt | 12 + comm/third_party/botan/src/lib/kdf/kdf.cpp | 255 + comm/third_party/botan/src/lib/kdf/kdf.h | 196 + comm/third_party/botan/src/lib/kdf/kdf1/info.txt | 7 + comm/third_party/botan/src/lib/kdf/kdf1/kdf1.cpp | 33 + comm/third_party/botan/src/lib/kdf/kdf1/kdf1.h | 43 + .../botan/src/lib/kdf/kdf1_iso18033/info.txt | 7 + .../src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp | 38 + .../src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h | 43 + comm/third_party/botan/src/lib/kdf/kdf2/info.txt | 7 + comm/third_party/botan/src/lib/kdf/kdf2/kdf2.cpp | 38 + comm/third_party/botan/src/lib/kdf/kdf2/kdf2.h | 43 + .../third_party/botan/src/lib/kdf/prf_tls/info.txt | 8 + .../botan/src/lib/kdf/prf_tls/prf_tls.cpp | 96 + .../botan/src/lib/kdf/prf_tls/prf_tls.h | 70 + .../botan/src/lib/kdf/prf_x942/info.txt | 8 + .../botan/src/lib/kdf/prf_x942/prf_x942.cpp | 92 + .../botan/src/lib/kdf/prf_x942/prf_x942.h | 42 + .../botan/src/lib/kdf/sp800_108/info.txt | 8 + .../botan/src/lib/kdf/sp800_108/sp800_108.cpp | 170 + .../botan/src/lib/kdf/sp800_108/sp800_108.h | 135 + .../botan/src/lib/kdf/sp800_56a/info.txt | 7 + .../botan/src/lib/kdf/sp800_56a/sp800_56a.cpp | 98 + .../botan/src/lib/kdf/sp800_56a/sp800_56a.h | 103 + .../botan/src/lib/kdf/sp800_56c/info.txt | 8 + .../botan/src/lib/kdf/sp800_56c/sp800_56c.cpp | 28 + .../botan/src/lib/kdf/sp800_56c/sp800_56c.h | 61 + .../botan/src/lib/mac/cbc_mac/cbc_mac.cpp | 99 + .../botan/src/lib/mac/cbc_mac/cbc_mac.h | 50 + .../third_party/botan/src/lib/mac/cbc_mac/info.txt | 7 + comm/third_party/botan/src/lib/mac/cmac/cmac.cpp | 139 + comm/third_party/botan/src/lib/mac/cmac/cmac.h | 67 + comm/third_party/botan/src/lib/mac/cmac/info.txt | 8 + comm/third_party/botan/src/lib/mac/gmac/gmac.cpp | 134 + comm/third_party/botan/src/lib/mac/gmac/gmac.h | 64 + comm/third_party/botan/src/lib/mac/gmac/info.txt | 8 + comm/third_party/botan/src/lib/mac/hmac/hmac.cpp | 150 + comm/third_party/botan/src/lib/mac/hmac/hmac.h | 52 + comm/third_party/botan/src/lib/mac/hmac/info.txt | 7 + comm/third_party/botan/src/lib/mac/info.txt | 7 + comm/third_party/botan/src/lib/mac/mac.cpp | 171 + comm/third_party/botan/src/lib/mac/mac.h | 143 + .../botan/src/lib/mac/poly1305/info.txt | 7 + .../botan/src/lib/mac/poly1305/poly1305.cpp | 211 + .../botan/src/lib/mac/poly1305/poly1305.h | 50 + .../third_party/botan/src/lib/mac/siphash/info.txt | 3 + .../botan/src/lib/mac/siphash/siphash.cpp | 136 + .../botan/src/lib/mac/siphash/siphash.h | 47 + .../botan/src/lib/mac/x919_mac/info.txt | 7 + .../botan/src/lib/mac/x919_mac/x919_mac.cpp | 99 + .../botan/src/lib/mac/x919_mac/x919_mac.h | 51 + .../botan/src/lib/math/bigint/big_code.cpp | 200 + .../botan/src/lib/math/bigint/big_io.cpp | 62 + .../botan/src/lib/math/bigint/big_ops2.cpp | 314 + .../botan/src/lib/math/bigint/big_ops3.cpp | 214 + .../botan/src/lib/math/bigint/big_rand.cpp | 64 + .../botan/src/lib/math/bigint/bigint.cpp | 551 + .../third_party/botan/src/lib/math/bigint/bigint.h | 1153 + .../botan/src/lib/math/bigint/divide.cpp | 236 + .../third_party/botan/src/lib/math/bigint/divide.h | 101 + .../third_party/botan/src/lib/math/bigint/info.txt | 14 + comm/third_party/botan/src/lib/math/mp/info.txt | 10 + comm/third_party/botan/src/lib/math/mp/mp_asmi.h | 611 + .../third_party/botan/src/lib/math/mp/mp_comba.cpp | 2211 ++ comm/third_party/botan/src/lib/math/mp/mp_core.h | 819 + .../third_party/botan/src/lib/math/mp/mp_karat.cpp | 408 + comm/third_party/botan/src/lib/math/mp/mp_madd.h | 146 + .../third_party/botan/src/lib/math/mp/mp_monty.cpp | 133 + comm/third_party/botan/src/lib/math/mp/mp_monty.h | 31 + .../botan/src/lib/math/mp/mp_monty_n.cpp | 2614 +++ .../botan/src/lib/math/numbertheory/curve_nistp.h | 49 + .../botan/src/lib/math/numbertheory/dsa_gen.cpp | 136 + .../botan/src/lib/math/numbertheory/info.txt | 22 + .../botan/src/lib/math/numbertheory/jacobi.cpp | 52 + .../botan/src/lib/math/numbertheory/make_prm.cpp | 293 + .../botan/src/lib/math/numbertheory/mod_inv.cpp | 356 + .../botan/src/lib/math/numbertheory/monty.cpp | 444 + .../botan/src/lib/math/numbertheory/monty.h | 191 + .../botan/src/lib/math/numbertheory/monty_exp.cpp | 254 + .../botan/src/lib/math/numbertheory/monty_exp.h | 54 + .../botan/src/lib/math/numbertheory/mp_numth.cpp | 84 + .../botan/src/lib/math/numbertheory/nistp_redc.cpp | 583 + .../botan/src/lib/math/numbertheory/numthry.cpp | 268 + .../botan/src/lib/math/numbertheory/numthry.h | 296 + .../botan/src/lib/math/numbertheory/pow_mod.cpp | 328 + .../botan/src/lib/math/numbertheory/pow_mod.h | 122 + .../botan/src/lib/math/numbertheory/primality.cpp | 203 + .../botan/src/lib/math/numbertheory/primality.h | 100 + .../botan/src/lib/math/numbertheory/primes.cpp | 609 + .../botan/src/lib/math/numbertheory/reducer.cpp | 119 + .../botan/src/lib/math/numbertheory/reducer.h | 69 + .../botan/src/lib/math/numbertheory/ressol.cpp | 100 + comm/third_party/botan/src/lib/misc/aont/info.txt | 9 + .../botan/src/lib/misc/aont/package.cpp | 125 + comm/third_party/botan/src/lib/misc/aont/package.h | 49 + .../botan/src/lib/misc/cryptobox/cryptobox.cpp | 180 + .../botan/src/lib/misc/cryptobox/cryptobox.h | 79 + .../botan/src/lib/misc/cryptobox/info.txt | 14 + .../botan/src/lib/misc/fpe_fe1/fpe_fe1.cpp | 218 + .../botan/src/lib/misc/fpe_fe1/fpe_fe1.h | 123 + .../botan/src/lib/misc/fpe_fe1/info.txt | 10 + comm/third_party/botan/src/lib/misc/hotp/hotp.cpp | 63 + comm/third_party/botan/src/lib/misc/hotp/hotp.h | 14 + comm/third_party/botan/src/lib/misc/hotp/info.txt | 9 + comm/third_party/botan/src/lib/misc/hotp/otp.h | 117 + comm/third_party/botan/src/lib/misc/hotp/totp.cpp | 63 + comm/third_party/botan/src/lib/misc/hotp/totp.h | 13 + .../botan/src/lib/misc/nist_keywrap/info.txt | 7 + .../src/lib/misc/nist_keywrap/nist_keywrap.cpp | 209 + .../botan/src/lib/misc/nist_keywrap/nist_keywrap.h | 67 + .../botan/src/lib/misc/rfc3394/info.txt | 8 + .../botan/src/lib/misc/rfc3394/rfc3394.cpp | 44 + .../botan/src/lib/misc/rfc3394/rfc3394.h | 39 + .../botan/src/lib/misc/roughtime/info.txt | 10 + .../botan/src/lib/misc/roughtime/roughtime.cpp | 466 + .../botan/src/lib/misc/roughtime/roughtime.h | 167 + comm/third_party/botan/src/lib/misc/srp6/info.txt | 8 + comm/third_party/botan/src/lib/misc/srp6/srp6.cpp | 193 + comm/third_party/botan/src/lib/misc/srp6/srp6.h | 155 + comm/third_party/botan/src/lib/misc/tss/info.txt | 10 + comm/third_party/botan/src/lib/misc/tss/tss.cpp | 333 + comm/third_party/botan/src/lib/misc/tss/tss.h | 104 + comm/third_party/botan/src/lib/modes/aead/aead.cpp | 176 + comm/third_party/botan/src/lib/modes/aead/aead.h | 147 + .../botan/src/lib/modes/aead/ccm/ccm.cpp | 279 + .../third_party/botan/src/lib/modes/aead/ccm/ccm.h | 130 + .../botan/src/lib/modes/aead/ccm/info.txt | 7 + .../aead/chacha20poly1305/chacha20poly1305.cpp | 171 + .../modes/aead/chacha20poly1305/chacha20poly1305.h | 104 + .../src/lib/modes/aead/chacha20poly1305/info.txt | 8 + .../botan/src/lib/modes/aead/eax/eax.cpp | 194 + .../third_party/botan/src/lib/modes/aead/eax/eax.h | 119 + .../botan/src/lib/modes/aead/eax/info.txt | 8 + .../botan/src/lib/modes/aead/gcm/gcm.cpp | 179 + .../third_party/botan/src/lib/modes/aead/gcm/gcm.h | 117 + .../botan/src/lib/modes/aead/gcm/info.txt | 9 + comm/third_party/botan/src/lib/modes/aead/info.txt | 3 + .../botan/src/lib/modes/aead/ocb/info.txt | 8 + .../botan/src/lib/modes/aead/ocb/ocb.cpp | 533 + .../third_party/botan/src/lib/modes/aead/ocb/ocb.h | 137 + .../botan/src/lib/modes/aead/siv/info.txt | 9 + .../botan/src/lib/modes/aead/siv/siv.cpp | 211 + .../third_party/botan/src/lib/modes/aead/siv/siv.h | 129 + comm/third_party/botan/src/lib/modes/cbc/cbc.cpp | 323 + comm/third_party/botan/src/lib/modes/cbc/cbc.h | 157 + comm/third_party/botan/src/lib/modes/cbc/info.txt | 8 + comm/third_party/botan/src/lib/modes/cfb/cfb.cpp | 229 + comm/third_party/botan/src/lib/modes/cfb/cfb.h | 106 + comm/third_party/botan/src/lib/modes/cfb/info.txt | 7 + .../botan/src/lib/modes/cipher_mode.cpp | 205 + comm/third_party/botan/src/lib/modes/cipher_mode.h | 198 + comm/third_party/botan/src/lib/modes/info.txt | 9 + .../botan/src/lib/modes/mode_pad/info.txt | 3 + .../botan/src/lib/modes/mode_pad/mode_pad.cpp | 333 + .../botan/src/lib/modes/mode_pad/mode_pad.h | 160 + comm/third_party/botan/src/lib/modes/stream_mode.h | 84 + comm/third_party/botan/src/lib/modes/xts/info.txt | 8 + comm/third_party/botan/src/lib/modes/xts/xts.cpp | 248 + comm/third_party/botan/src/lib/modes/xts/xts.h | 103 + .../botan/src/lib/passhash/bcrypt/bcrypt.cpp | 181 + .../botan/src/lib/passhash/bcrypt/bcrypt.h | 49 + .../botan/src/lib/passhash/bcrypt/info.txt | 9 + .../botan/src/lib/passhash/passhash9/info.txt | 9 + .../botan/src/lib/passhash/passhash9/passhash9.cpp | 142 + .../botan/src/lib/passhash/passhash9/passhash9.h | 52 + .../botan/src/lib/pbkdf/argon2/argon2.cpp | 443 + .../botan/src/lib/pbkdf/argon2/argon2.h | 118 + .../botan/src/lib/pbkdf/argon2/argon2fmt.cpp | 125 + .../botan/src/lib/pbkdf/argon2/argon2pwhash.cpp | 154 + .../botan/src/lib/pbkdf/argon2/info.txt | 9 + .../src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.cpp | 183 + .../src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.h | 77 + .../botan/src/lib/pbkdf/bcrypt_pbkdf/info.txt | 8 + comm/third_party/botan/src/lib/pbkdf/info.txt | 13 + comm/third_party/botan/src/lib/pbkdf/pbkdf.cpp | 133 + comm/third_party/botan/src/lib/pbkdf/pbkdf.h | 246 + .../botan/src/lib/pbkdf/pbkdf1/info.txt | 7 + .../botan/src/lib/pbkdf/pbkdf1/pbkdf1.cpp | 54 + .../botan/src/lib/pbkdf/pbkdf1/pbkdf1.h | 53 + .../botan/src/lib/pbkdf/pbkdf2/info.txt | 7 + .../botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp | 228 + .../botan/src/lib/pbkdf/pbkdf2/pbkdf2.h | 117 + .../botan/src/lib/pbkdf/pgp_s2k/info.txt | 7 + .../botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp | 219 + .../botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.h | 164 + comm/third_party/botan/src/lib/pbkdf/pwdhash.cpp | 118 + comm/third_party/botan/src/lib/pbkdf/pwdhash.h | 162 + .../botan/src/lib/pbkdf/scrypt/info.txt | 10 + .../botan/src/lib/pbkdf/scrypt/scrypt.cpp | 249 + .../botan/src/lib/pbkdf/scrypt/scrypt.h | 127 + comm/third_party/botan/src/lib/pk_pad/eme.cpp | 94 + comm/third_party/botan/src/lib/pk_pad/eme.h | 94 + .../botan/src/lib/pk_pad/eme_oaep/info.txt | 7 + .../botan/src/lib/pk_pad/eme_oaep/oaep.cpp | 168 + .../botan/src/lib/pk_pad/eme_oaep/oaep.h | 62 + .../botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp | 109 + .../botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.h | 35 + .../botan/src/lib/pk_pad/eme_pkcs1/info.txt | 4 + .../botan/src/lib/pk_pad/eme_raw/eme_raw.cpp | 31 + .../botan/src/lib/pk_pad/eme_raw/eme_raw.h | 33 + .../botan/src/lib/pk_pad/eme_raw/info.txt | 3 + comm/third_party/botan/src/lib/pk_pad/emsa.cpp | 207 + comm/third_party/botan/src/lib/pk_pad/emsa.h | 107 + .../botan/src/lib/pk_pad/emsa1/emsa1.cpp | 133 + .../third_party/botan/src/lib/pk_pad/emsa1/emsa1.h | 55 + .../botan/src/lib/pk_pad/emsa1/info.txt | 3 + .../botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp | 166 + .../botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h | 94 + .../botan/src/lib/pk_pad/emsa_pkcs1/info.txt | 7 + .../botan/src/lib/pk_pad/emsa_pssr/info.txt | 7 + .../botan/src/lib/pk_pad/emsa_pssr/pssr.cpp | 291 + .../botan/src/lib/pk_pad/emsa_pssr/pssr.h | 103 + .../botan/src/lib/pk_pad/emsa_raw/emsa_raw.cpp | 92 + .../botan/src/lib/pk_pad/emsa_raw/emsa_raw.h | 47 + .../botan/src/lib/pk_pad/emsa_raw/info.txt | 3 + .../botan/src/lib/pk_pad/emsa_x931/emsa_x931.cpp | 102 + .../botan/src/lib/pk_pad/emsa_x931/emsa_x931.h | 52 + .../botan/src/lib/pk_pad/emsa_x931/info.txt | 7 + .../botan/src/lib/pk_pad/hash_id/hash_id.cpp | 163 + .../botan/src/lib/pk_pad/hash_id/hash_id.h | 34 + .../botan/src/lib/pk_pad/hash_id/info.txt | 3 + comm/third_party/botan/src/lib/pk_pad/info.txt | 18 + .../botan/src/lib/pk_pad/iso9796/info.txt | 9 + .../botan/src/lib/pk_pad/iso9796/iso9796.cpp | 322 + .../botan/src/lib/pk_pad/iso9796/iso9796.h | 98 + .../third_party/botan/src/lib/pk_pad/mgf1/info.txt | 3 + .../third_party/botan/src/lib/pk_pad/mgf1/mgf1.cpp | 36 + comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.h | 31 + comm/third_party/botan/src/lib/pk_pad/padding.cpp | 44 + comm/third_party/botan/src/lib/pk_pad/padding.h | 36 + .../botan/src/lib/prov/commoncrypto/commoncrypto.h | 62 + .../lib/prov/commoncrypto/commoncrypto_block.cpp | 164 + .../lib/prov/commoncrypto/commoncrypto_hash.cpp | 146 + .../lib/prov/commoncrypto/commoncrypto_mode.cpp | 247 + .../lib/prov/commoncrypto/commoncrypto_utils.cpp | 196 + .../src/lib/prov/commoncrypto/commoncrypto_utils.h | 35 + .../botan/src/lib/prov/commoncrypto/info.txt | 19 + .../botan/src/lib/prov/openssl/info.txt | 21 + .../botan/src/lib/prov/openssl/openssl.h | 118 + .../botan/src/lib/prov/openssl/openssl_block.cpp | 234 + .../botan/src/lib/prov/openssl/openssl_ec.cpp | 383 + .../botan/src/lib/prov/openssl/openssl_hash.cpp | 136 + .../botan/src/lib/prov/openssl/openssl_mode.cpp | 233 + .../botan/src/lib/prov/openssl/openssl_rc4.cpp | 93 + .../botan/src/lib/prov/openssl/openssl_rsa.cpp | 312 + .../third_party/botan/src/lib/prov/pkcs11/info.txt | 36 + comm/third_party/botan/src/lib/prov/pkcs11/p11.cpp | 767 + comm/third_party/botan/src/lib/prov/pkcs11/p11.h | 2930 +++ .../botan/src/lib/prov/pkcs11/p11_ecc_key.cpp | 136 + .../botan/src/lib/prov/pkcs11/p11_ecc_key.h | 223 + .../botan/src/lib/prov/pkcs11/p11_ecdh.cpp | 125 + .../botan/src/lib/prov/pkcs11/p11_ecdh.h | 127 + .../botan/src/lib/prov/pkcs11/p11_ecdsa.cpp | 213 + .../botan/src/lib/prov/pkcs11/p11_ecdsa.h | 133 + .../botan/src/lib/prov/pkcs11/p11_mechanism.cpp | 278 + .../botan/src/lib/prov/pkcs11/p11_mechanism.h | 118 + .../botan/src/lib/prov/pkcs11/p11_module.cpp | 53 + .../botan/src/lib/prov/pkcs11/p11_module.h | 15 + .../botan/src/lib/prov/pkcs11/p11_object.cpp | 227 + .../botan/src/lib/prov/pkcs11/p11_object.h | 773 + .../src/lib/prov/pkcs11/p11_randomgenerator.cpp | 31 + .../src/lib/prov/pkcs11/p11_randomgenerator.h | 70 + .../botan/src/lib/prov/pkcs11/p11_rsa.cpp | 373 + .../botan/src/lib/prov/pkcs11/p11_rsa.h | 229 + .../botan/src/lib/prov/pkcs11/p11_session.cpp | 96 + .../botan/src/lib/prov/pkcs11/p11_session.h | 15 + .../botan/src/lib/prov/pkcs11/p11_slot.cpp | 60 + .../botan/src/lib/prov/pkcs11/p11_slot.h | 15 + .../botan/src/lib/prov/pkcs11/p11_types.h | 209 + .../botan/src/lib/prov/pkcs11/p11_x509.cpp | 37 + .../botan/src/lib/prov/pkcs11/p11_x509.h | 117 + .../third_party/botan/src/lib/prov/pkcs11/pkcs11.h | 264 + .../botan/src/lib/prov/pkcs11/pkcs11f.h | 938 + .../botan/src/lib/prov/pkcs11/pkcs11t.h | 2002 ++ comm/third_party/botan/src/lib/prov/tpm/info.txt | 16 + comm/third_party/botan/src/lib/prov/tpm/tpm.cpp | 460 + comm/third_party/botan/src/lib/prov/tpm/tpm.h | 194 + comm/third_party/botan/src/lib/psk_db/info.txt | 11 + comm/third_party/botan/src/lib/psk_db/psk_db.cpp | 105 + comm/third_party/botan/src/lib/psk_db/psk_db.h | 166 + .../botan/src/lib/psk_db/psk_db_sql.cpp | 75 + comm/third_party/botan/src/lib/psk_db/psk_db_sql.h | 13 + comm/third_party/botan/src/lib/pubkey/blinding.cpp | 66 + comm/third_party/botan/src/lib/pubkey/blinding.h | 80 + .../botan/src/lib/pubkey/cecpq1/cecpq1.cpp | 51 + .../botan/src/lib/pubkey/cecpq1/cecpq1.h | 38 + .../botan/src/lib/pubkey/cecpq1/info.txt | 9 + .../botan/src/lib/pubkey/curve25519/curve25519.cpp | 143 + .../botan/src/lib/pubkey/curve25519/curve25519.h | 123 + .../botan/src/lib/pubkey/curve25519/donna.cpp | 464 + .../botan/src/lib/pubkey/curve25519/info.txt | 8 + comm/third_party/botan/src/lib/pubkey/dh/dh.cpp | 142 + comm/third_party/botan/src/lib/pubkey/dh/dh.h | 81 + comm/third_party/botan/src/lib/pubkey/dh/info.txt | 13 + .../botan/src/lib/pubkey/dl_algo/dl_algo.cpp | 84 + .../botan/src/lib/pubkey/dl_algo/dl_algo.h | 140 + .../botan/src/lib/pubkey/dl_algo/info.txt | 10 + .../botan/src/lib/pubkey/dl_group/dl_group.cpp | 646 + .../botan/src/lib/pubkey/dl_group/dl_group.h | 357 + .../botan/src/lib/pubkey/dl_group/dl_named.cpp | 175 + .../botan/src/lib/pubkey/dl_group/info.txt | 10 + .../botan/src/lib/pubkey/dlies/dlies.cpp | 219 + .../third_party/botan/src/lib/pubkey/dlies/dlies.h | 163 + .../botan/src/lib/pubkey/dlies/info.txt | 10 + comm/third_party/botan/src/lib/pubkey/dsa/dsa.cpp | 230 + comm/third_party/botan/src/lib/pubkey/dsa/dsa.h | 87 + comm/third_party/botan/src/lib/pubkey/dsa/info.txt | 12 + .../botan/src/lib/pubkey/ec_group/curve_gfp.cpp | 568 + .../botan/src/lib/pubkey/ec_group/curve_gfp.h | 265 + .../botan/src/lib/pubkey/ec_group/ec_group.cpp | 796 + .../botan/src/lib/pubkey/ec_group/ec_group.h | 398 + .../botan/src/lib/pubkey/ec_group/ec_named.cpp | 301 + .../botan/src/lib/pubkey/ec_group/info.txt | 20 + .../botan/src/lib/pubkey/ec_group/point_gfp.cpp | 731 + .../botan/src/lib/pubkey/ec_group/point_gfp.h | 447 + .../botan/src/lib/pubkey/ec_group/point_mul.cpp | 431 + .../botan/src/lib/pubkey/ec_group/point_mul.h | 85 + .../botan/src/lib/pubkey/ecc_key/ecc_key.cpp | 205 + .../botan/src/lib/pubkey/ecc_key/ecc_key.h | 172 + .../botan/src/lib/pubkey/ecc_key/info.txt | 11 + .../third_party/botan/src/lib/pubkey/ecdh/ecdh.cpp | 87 + comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.h | 106 + .../third_party/botan/src/lib/pubkey/ecdh/info.txt | 10 + .../botan/src/lib/pubkey/ecdsa/ecdsa.cpp | 308 + .../third_party/botan/src/lib/pubkey/ecdsa/ecdsa.h | 117 + .../botan/src/lib/pubkey/ecdsa/info.txt | 14 + .../botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp | 155 + .../botan/src/lib/pubkey/ecgdsa/ecgdsa.h | 96 + .../botan/src/lib/pubkey/ecgdsa/info.txt | 15 + .../botan/src/lib/pubkey/ecies/ecies.cpp | 415 + .../third_party/botan/src/lib/pubkey/ecies/ecies.h | 314 + .../botan/src/lib/pubkey/ecies/info.txt | 10 + .../botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp | 208 + .../botan/src/lib/pubkey/eckcdsa/eckcdsa.h | 96 + .../botan/src/lib/pubkey/eckcdsa/info.txt | 17 + .../botan/src/lib/pubkey/ed25519/ed25519.cpp | 102 + .../botan/src/lib/pubkey/ed25519/ed25519.h | 113 + .../botan/src/lib/pubkey/ed25519/ed25519_fe.cpp | 754 + .../botan/src/lib/pubkey/ed25519/ed25519_fe.h | 227 + .../src/lib/pubkey/ed25519/ed25519_internal.h | 119 + .../botan/src/lib/pubkey/ed25519/ed25519_key.cpp | 288 + .../botan/src/lib/pubkey/ed25519/ge.cpp | 2174 ++ .../botan/src/lib/pubkey/ed25519/info.txt | 17 + .../botan/src/lib/pubkey/ed25519/sc_muladd.cpp | 221 + .../botan/src/lib/pubkey/ed25519/sc_reduce.cpp | 159 + .../botan/src/lib/pubkey/elgamal/elgamal.cpp | 213 + .../botan/src/lib/pubkey/elgamal/elgamal.h | 85 + .../botan/src/lib/pubkey/elgamal/info.txt | 10 + .../botan/src/lib/pubkey/gost_3410/gost_3410.cpp | 253 + .../botan/src/lib/pubkey/gost_3410/gost_3410.h | 104 + .../botan/src/lib/pubkey/gost_3410/info.txt | 12 + comm/third_party/botan/src/lib/pubkey/info.txt | 31 + .../botan/src/lib/pubkey/keypair/info.txt | 6 + .../botan/src/lib/pubkey/keypair/keypair.cpp | 85 + .../botan/src/lib/pubkey/keypair/keypair.h | 85 + .../src/lib/pubkey/mce/code_based_key_gen.cpp | 298 + .../botan/src/lib/pubkey/mce/code_based_util.h | 57 + .../src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp | 314 + .../botan/src/lib/pubkey/mce/gf2m_small_m.cpp | 126 + .../botan/src/lib/pubkey/mce/gf2m_small_m.h | 221 + .../botan/src/lib/pubkey/mce/goppa_code.cpp | 234 + comm/third_party/botan/src/lib/pubkey/mce/info.txt | 18 + .../botan/src/lib/pubkey/mce/mce_internal.h | 53 + .../botan/src/lib/pubkey/mce/mce_workfactor.cpp | 112 + .../botan/src/lib/pubkey/mce/mceliece.cpp | 139 + .../botan/src/lib/pubkey/mce/mceliece.h | 141 + .../botan/src/lib/pubkey/mce/mceliece_key.cpp | 386 + .../botan/src/lib/pubkey/mce/polyn_gf2m.cpp | 806 + .../botan/src/lib/pubkey/mce/polyn_gf2m.h | 174 + .../botan/src/lib/pubkey/mceies/info.txt | 10 + .../botan/src/lib/pubkey/mceies/mceies.cpp | 110 + .../botan/src/lib/pubkey/mceies/mceies.h | 46 + .../botan/src/lib/pubkey/newhope/info.txt | 12 + .../botan/src/lib/pubkey/newhope/newhope.cpp | 800 + .../botan/src/lib/pubkey/newhope/newhope.h | 85 + .../botan/src/lib/pubkey/pbes2/info.txt | 10 + .../botan/src/lib/pubkey/pbes2/pbes2.cpp | 339 + .../third_party/botan/src/lib/pubkey/pbes2/pbes2.h | 87 + comm/third_party/botan/src/lib/pubkey/pem/info.txt | 7 + comm/third_party/botan/src/lib/pubkey/pem/pem.cpp | 169 + comm/third_party/botan/src/lib/pubkey/pem/pem.h | 91 + comm/third_party/botan/src/lib/pubkey/pk_algs.cpp | 426 + comm/third_party/botan/src/lib/pubkey/pk_algs.h | 46 + comm/third_party/botan/src/lib/pubkey/pk_keys.cpp | 145 + comm/third_party/botan/src/lib/pubkey/pk_keys.h | 329 + comm/third_party/botan/src/lib/pubkey/pk_ops.cpp | 173 + comm/third_party/botan/src/lib/pubkey/pk_ops.h | 161 + comm/third_party/botan/src/lib/pubkey/pk_ops_fwd.h | 27 + .../third_party/botan/src/lib/pubkey/pk_ops_impl.h | 231 + comm/third_party/botan/src/lib/pubkey/pkcs8.cpp | 490 + comm/third_party/botan/src/lib/pubkey/pkcs8.h | 288 + comm/third_party/botan/src/lib/pubkey/pubkey.cpp | 388 + comm/third_party/botan/src/lib/pubkey/pubkey.h | 800 + .../botan/src/lib/pubkey/rfc6979/info.txt | 8 + .../botan/src/lib/pubkey/rfc6979/rfc6979.cpp | 59 + .../botan/src/lib/pubkey/rfc6979/rfc6979.h | 55 + comm/third_party/botan/src/lib/pubkey/rsa/info.txt | 10 + comm/third_party/botan/src/lib/pubkey/rsa/rsa.cpp | 753 + comm/third_party/botan/src/lib/pubkey/rsa/rsa.h | 180 + comm/third_party/botan/src/lib/pubkey/sm2/info.txt | 14 + comm/third_party/botan/src/lib/pubkey/sm2/sm2.cpp | 306 + comm/third_party/botan/src/lib/pubkey/sm2/sm2.h | 124 + .../botan/src/lib/pubkey/sm2/sm2_enc.cpp | 267 + .../third_party/botan/src/lib/pubkey/sm2/sm2_enc.h | 15 + .../botan/src/lib/pubkey/workfactor.cpp | 66 + comm/third_party/botan/src/lib/pubkey/workfactor.h | 51 + comm/third_party/botan/src/lib/pubkey/x509_key.cpp | 106 + comm/third_party/botan/src/lib/pubkey/x509_key.h | 80 + .../third_party/botan/src/lib/pubkey/xmss/atomic.h | 55 + .../third_party/botan/src/lib/pubkey/xmss/info.txt | 40 + comm/third_party/botan/src/lib/pubkey/xmss/xmss.h | 459 + .../botan/src/lib/pubkey/xmss/xmss_address.h | 405 + .../botan/src/lib/pubkey/xmss/xmss_common_ops.cpp | 74 + .../botan/src/lib/pubkey/xmss/xmss_common_ops.h | 83 + .../botan/src/lib/pubkey/xmss/xmss_hash.cpp | 80 + .../botan/src/lib/pubkey/xmss/xmss_hash.h | 156 + .../src/lib/pubkey/xmss/xmss_index_registry.cpp | 84 + .../src/lib/pubkey/xmss/xmss_index_registry.h | 105 + .../botan/src/lib/pubkey/xmss/xmss_key_pair.h | 49 + .../botan/src/lib/pubkey/xmss/xmss_parameters.cpp | 184 + .../botan/src/lib/pubkey/xmss/xmss_parameters.h | 119 + .../botan/src/lib/pubkey/xmss/xmss_privatekey.cpp | 405 + .../botan/src/lib/pubkey/xmss/xmss_privatekey.h | 13 + .../botan/src/lib/pubkey/xmss/xmss_publickey.cpp | 129 + .../botan/src/lib/pubkey/xmss/xmss_publickey.h | 14 + .../botan/src/lib/pubkey/xmss/xmss_signature.cpp | 92 + .../botan/src/lib/pubkey/xmss/xmss_signature.h | 127 + .../lib/pubkey/xmss/xmss_signature_operation.cpp | 120 + .../src/lib/pubkey/xmss/xmss_signature_operation.h | 89 + .../botan/src/lib/pubkey/xmss/xmss_tools.h | 108 + .../pubkey/xmss/xmss_verification_operation.cpp | 138 + .../lib/pubkey/xmss/xmss_verification_operation.h | 71 + .../botan/src/lib/pubkey/xmss/xmss_wots.h | 752 + .../pubkey/xmss/xmss_wots_addressed_privatekey.h | 68 + .../pubkey/xmss/xmss_wots_addressed_publickey.h | 96 + .../src/lib/pubkey/xmss/xmss_wots_parameters.cpp | 137 + .../src/lib/pubkey/xmss/xmss_wots_parameters.h | 14 + .../src/lib/pubkey/xmss/xmss_wots_privatekey.cpp | 99 + .../src/lib/pubkey/xmss/xmss_wots_privatekey.h | 15 + .../src/lib/pubkey/xmss/xmss_wots_publickey.cpp | 72 + .../src/lib/pubkey/xmss/xmss_wots_publickey.h | 14 + .../botan/src/lib/rng/auto_rng/auto_rng.cpp | 112 + .../botan/src/lib/rng/auto_rng/auto_rng.h | 102 + .../botan/src/lib/rng/auto_rng/info.txt | 8 + .../botan/src/lib/rng/chacha_rng/chacha_rng.cpp | 87 + .../botan/src/lib/rng/chacha_rng/chacha_rng.h | 125 + .../botan/src/lib/rng/chacha_rng/info.txt | 10 + .../botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp | 197 + .../botan/src/lib/rng/hmac_drbg/hmac_drbg.h | 150 + .../botan/src/lib/rng/hmac_drbg/info.txt | 8 + comm/third_party/botan/src/lib/rng/info.txt | 3 + .../botan/src/lib/rng/processor_rng/info.txt | 20 + .../src/lib/rng/processor_rng/processor_rng.cpp | 157 + .../src/lib/rng/processor_rng/processor_rng.h | 52 + .../botan/src/lib/rng/rdrand_rng/info.txt | 13 + .../botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp | 67 + .../botan/src/lib/rng/rdrand_rng/rdrand_rng.h | 68 + comm/third_party/botan/src/lib/rng/rng.cpp | 91 + comm/third_party/botan/src/lib/rng/rng.h | 297 + .../botan/src/lib/rng/stateful_rng/info.txt | 3 + .../src/lib/rng/stateful_rng/stateful_rng.cpp | 190 + .../botan/src/lib/rng/stateful_rng/stateful_rng.h | 166 + .../botan/src/lib/rng/system_rng/info.txt | 18 + .../botan/src/lib/rng/system_rng/system_rng.cpp | 289 + .../botan/src/lib/rng/system_rng/system_rng.h | 43 + .../botan/src/lib/stream/chacha/chacha.cpp | 384 + .../botan/src/lib/stream/chacha/chacha.h | 82 + .../lib/stream/chacha/chacha_avx2/chacha_avx2.cpp | 207 + .../src/lib/stream/chacha/chacha_avx2/info.txt | 11 + .../stream/chacha/chacha_simd32/chacha_simd32.cpp | 205 + .../src/lib/stream/chacha/chacha_simd32/info.txt | 7 + .../botan/src/lib/stream/chacha/info.txt | 3 + comm/third_party/botan/src/lib/stream/ctr/ctr.cpp | 256 + comm/third_party/botan/src/lib/stream/ctr/ctr.h | 65 + comm/third_party/botan/src/lib/stream/ctr/info.txt | 7 + comm/third_party/botan/src/lib/stream/info.txt | 7 + comm/third_party/botan/src/lib/stream/ofb/info.txt | 7 + comm/third_party/botan/src/lib/stream/ofb/ofb.cpp | 92 + comm/third_party/botan/src/lib/stream/ofb/ofb.h | 56 + comm/third_party/botan/src/lib/stream/rc4/info.txt | 3 + comm/third_party/botan/src/lib/stream/rc4/rc4.cpp | 133 + comm/third_party/botan/src/lib/stream/rc4/rc4.h | 57 + .../botan/src/lib/stream/salsa20/info.txt | 3 + .../botan/src/lib/stream/salsa20/salsa20.cpp | 302 + .../botan/src/lib/stream/salsa20/salsa20.h | 54 + .../botan/src/lib/stream/shake_cipher/info.txt | 7 + .../src/lib/stream/shake_cipher/shake_cipher.cpp | 90 + .../src/lib/stream/shake_cipher/shake_cipher.h | 57 + .../botan/src/lib/stream/stream_cipher.cpp | 149 + .../botan/src/lib/stream/stream_cipher.h | 147 + .../botan/src/lib/tls/asio/asio_async_ops.h | 355 + .../botan/src/lib/tls/asio/asio_context.h | 120 + .../botan/src/lib/tls/asio/asio_error.h | 151 + .../botan/src/lib/tls/asio/asio_stream.h | 835 + comm/third_party/botan/src/lib/tls/asio/info.txt | 15 + .../botan/src/lib/tls/credentials_manager.cpp | 105 + .../botan/src/lib/tls/credentials_manager.h | 196 + comm/third_party/botan/src/lib/tls/info.txt | 54 + .../third_party/botan/src/lib/tls/msg_cert_req.cpp | 156 + .../botan/src/lib/tls/msg_cert_status.cpp | 71 + .../botan/src/lib/tls/msg_cert_verify.cpp | 110 + .../botan/src/lib/tls/msg_certificate.cpp | 109 + .../botan/src/lib/tls/msg_client_hello.cpp | 465 + .../botan/src/lib/tls/msg_client_kex.cpp | 404 + .../third_party/botan/src/lib/tls/msg_finished.cpp | 91 + .../botan/src/lib/tls/msg_hello_verify.cpp | 69 + .../botan/src/lib/tls/msg_server_hello.cpp | 251 + .../botan/src/lib/tls/msg_server_kex.cpp | 334 + .../botan/src/lib/tls/msg_session_ticket.cpp | 56 + .../botan/src/lib/tls/sessions_sql/info.txt | 7 + .../tls/sessions_sql/tls_session_manager_sql.cpp | 213 + .../lib/tls/sessions_sql/tls_session_manager_sql.h | 81 + .../botan/src/lib/tls/sessions_sqlite3/info.txt | 8 + .../tls_session_manager_sqlite.cpp | 29 + .../sessions_sqlite3/tls_session_manager_sqlite.h | 53 + comm/third_party/botan/src/lib/tls/tls_10/info.txt | 10 + comm/third_party/botan/src/lib/tls/tls_alert.cpp | 126 + comm/third_party/botan/src/lib/tls/tls_alert.h | 116 + comm/third_party/botan/src/lib/tls/tls_algos.cpp | 426 + comm/third_party/botan/src/lib/tls/tls_algos.h | 171 + .../third_party/botan/src/lib/tls/tls_blocking.cpp | 97 + comm/third_party/botan/src/lib/tls/tls_blocking.h | 103 + .../botan/src/lib/tls/tls_callbacks.cpp | 191 + comm/third_party/botan/src/lib/tls/tls_callbacks.h | 484 + .../third_party/botan/src/lib/tls/tls_cbc/info.txt | 12 + .../botan/src/lib/tls/tls_cbc/tls_cbc.cpp | 499 + .../botan/src/lib/tls/tls_cbc/tls_cbc.h | 186 + comm/third_party/botan/src/lib/tls/tls_channel.cpp | 795 + comm/third_party/botan/src/lib/tls/tls_channel.h | 318 + .../botan/src/lib/tls/tls_ciphersuite.cpp | 253 + .../botan/src/lib/tls/tls_ciphersuite.h | 189 + comm/third_party/botan/src/lib/tls/tls_client.cpp | 780 + comm/third_party/botan/src/lib/tls/tls_client.h | 169 + comm/third_party/botan/src/lib/tls/tls_exceptn.h | 52 + .../botan/src/lib/tls/tls_extensions.cpp | 660 + .../third_party/botan/src/lib/tls/tls_extensions.h | 551 + .../botan/src/lib/tls/tls_handshake_hash.cpp | 34 + .../botan/src/lib/tls/tls_handshake_hash.h | 44 + .../botan/src/lib/tls/tls_handshake_io.cpp | 480 + .../botan/src/lib/tls/tls_handshake_io.h | 218 + .../botan/src/lib/tls/tls_handshake_msg.h | 51 + .../botan/src/lib/tls/tls_handshake_state.cpp | 580 + .../botan/src/lib/tls/tls_handshake_state.h | 206 + comm/third_party/botan/src/lib/tls/tls_magic.h | 72 + comm/third_party/botan/src/lib/tls/tls_messages.h | 653 + comm/third_party/botan/src/lib/tls/tls_policy.cpp | 616 + comm/third_party/botan/src/lib/tls/tls_policy.h | 616 + comm/third_party/botan/src/lib/tls/tls_reader.h | 231 + comm/third_party/botan/src/lib/tls/tls_record.cpp | 534 + comm/third_party/botan/src/lib/tls/tls_record.h | 188 + .../botan/src/lib/tls/tls_seq_numbers.h | 174 + comm/third_party/botan/src/lib/tls/tls_server.cpp | 1025 + comm/third_party/botan/src/lib/tls/tls_server.h | 169 + .../botan/src/lib/tls/tls_server_info.h | 104 + comm/third_party/botan/src/lib/tls/tls_session.cpp | 299 + comm/third_party/botan/src/lib/tls/tls_session.h | 210 + .../botan/src/lib/tls/tls_session_key.cpp | 101 + .../botan/src/lib/tls/tls_session_key.h | 82 + .../botan/src/lib/tls/tls_session_manager.h | 160 + .../src/lib/tls/tls_session_manager_memory.cpp | 132 + .../botan/src/lib/tls/tls_suite_info.cpp | 212 + .../botan/src/lib/tls/tls_text_policy.cpp | 319 + comm/third_party/botan/src/lib/tls/tls_version.cpp | 88 + comm/third_party/botan/src/lib/tls/tls_version.h | 156 + comm/third_party/botan/src/lib/utils/assert.cpp | 54 + comm/third_party/botan/src/lib/utils/assert.h | 157 + comm/third_party/botan/src/lib/utils/bit_ops.h | 171 + .../third_party/botan/src/lib/utils/boost/info.txt | 9 + comm/third_party/botan/src/lib/utils/bswap.h | 108 + comm/third_party/botan/src/lib/utils/calendar.cpp | 124 + comm/third_party/botan/src/lib/utils/calendar.h | 91 + comm/third_party/botan/src/lib/utils/charset.cpp | 283 + comm/third_party/botan/src/lib/utils/charset.h | 80 + comm/third_party/botan/src/lib/utils/codec_base.h | 220 + comm/third_party/botan/src/lib/utils/compiler.h | 225 + .../botan/src/lib/utils/cpuid/cpuid.cpp | 231 + comm/third_party/botan/src/lib/utils/cpuid/cpuid.h | 484 + .../botan/src/lib/utils/cpuid/cpuid_arm.cpp | 237 + .../botan/src/lib/utils/cpuid/cpuid_ppc.cpp | 132 + .../botan/src/lib/utils/cpuid/cpuid_x86.cpp | 214 + .../third_party/botan/src/lib/utils/cpuid/info.txt | 7 + comm/third_party/botan/src/lib/utils/ct_utils.cpp | 83 + comm/third_party/botan/src/lib/utils/ct_utils.h | 418 + comm/third_party/botan/src/lib/utils/data_src.cpp | 214 + comm/third_party/botan/src/lib/utils/data_src.h | 181 + comm/third_party/botan/src/lib/utils/database.h | 88 + comm/third_party/botan/src/lib/utils/donna128.h | 143 + .../botan/src/lib/utils/dyn_load/dyn_load.cpp | 82 + .../botan/src/lib/utils/dyn_load/dyn_load.h | 68 + .../botan/src/lib/utils/dyn_load/info.txt | 18 + comm/third_party/botan/src/lib/utils/exceptn.cpp | 183 + comm/third_party/botan/src/lib/utils/exceptn.h | 441 + .../third_party/botan/src/lib/utils/filesystem.cpp | 144 + comm/third_party/botan/src/lib/utils/filesystem.h | 33 + .../botan/src/lib/utils/ghash/ghash.cpp | 236 + comm/third_party/botan/src/lib/utils/ghash/ghash.h | 110 + .../src/lib/utils/ghash/ghash_cpu/ghash_cpu.cpp | 207 + .../botan/src/lib/utils/ghash/ghash_cpu/info.txt | 34 + .../lib/utils/ghash/ghash_vperm/ghash_vperm.cpp | 62 + .../botan/src/lib/utils/ghash/ghash_vperm/info.txt | 8 + .../third_party/botan/src/lib/utils/ghash/info.txt | 3 + .../botan/src/lib/utils/http_util/http_util.cpp | 267 + .../botan/src/lib/utils/http_util/http_util.h | 107 + .../botan/src/lib/utils/http_util/info.txt | 11 + comm/third_party/botan/src/lib/utils/info.txt | 43 + comm/third_party/botan/src/lib/utils/loadstor.h | 701 + .../botan/src/lib/utils/locking_allocator/info.txt | 12 + .../utils/locking_allocator/locking_allocator.cpp | 75 + .../utils/locking_allocator/locking_allocator.h | 45 + comm/third_party/botan/src/lib/utils/mem_ops.cpp | 68 + comm/third_party/botan/src/lib/utils/mem_ops.h | 365 + .../botan/src/lib/utils/mem_pool/info.txt | 7 + .../botan/src/lib/utils/mem_pool/mem_pool.cpp | 435 + .../botan/src/lib/utils/mem_pool/mem_pool.h | 58 + comm/third_party/botan/src/lib/utils/mul128.h | 125 + comm/third_party/botan/src/lib/utils/mutex.h | 60 + comm/third_party/botan/src/lib/utils/os_utils.cpp | 757 + comm/third_party/botan/src/lib/utils/os_utils.h | 200 + comm/third_party/botan/src/lib/utils/parsing.cpp | 458 + comm/third_party/botan/src/lib/utils/parsing.h | 181 + .../botan/src/lib/utils/poly_dbl/info.txt | 7 + .../botan/src/lib/utils/poly_dbl/poly_dbl.cpp | 115 + .../botan/src/lib/utils/poly_dbl/poly_dbl.h | 39 + comm/third_party/botan/src/lib/utils/prefetch.h | 39 + comm/third_party/botan/src/lib/utils/read_cfg.cpp | 63 + comm/third_party/botan/src/lib/utils/read_kv.cpp | 85 + comm/third_party/botan/src/lib/utils/rotate.h | 112 + comm/third_party/botan/src/lib/utils/rounding.h | 56 + comm/third_party/botan/src/lib/utils/safeint.h | 41 + comm/third_party/botan/src/lib/utils/simd/info.txt | 27 + .../third_party/botan/src/lib/utils/simd/simd_32.h | 621 + .../botan/src/lib/utils/simd/simd_avx2/info.txt | 21 + .../botan/src/lib/utils/simd/simd_avx2/simd_avx2.h | 299 + .../botan/src/lib/utils/socket/info.txt | 18 + .../botan/src/lib/utils/socket/socket.cpp | 371 + .../botan/src/lib/utils/socket/socket.h | 64 + .../botan/src/lib/utils/socket/socket_udp.cpp | 344 + .../botan/src/lib/utils/socket/socket_udp.h | 73 + .../third_party/botan/src/lib/utils/socket/uri.cpp | 188 + comm/third_party/botan/src/lib/utils/socket/uri.h | 49 + .../botan/src/lib/utils/sqlite3/info.txt | 13 + .../botan/src/lib/utils/sqlite3/sqlite3.cpp | 166 + .../botan/src/lib/utils/sqlite3/sqlite3.h | 58 + .../botan/src/lib/utils/stl_compatibility.h | 80 + comm/third_party/botan/src/lib/utils/stl_util.h | 110 + .../botan/src/lib/utils/thread_utils/barrier.cpp | 36 + .../botan/src/lib/utils/thread_utils/barrier.h | 42 + .../botan/src/lib/utils/thread_utils/info.txt | 14 + .../botan/src/lib/utils/thread_utils/rwlock.cpp | 58 + .../botan/src/lib/utils/thread_utils/rwlock.h | 42 + .../botan/src/lib/utils/thread_utils/semaphore.cpp | 38 + .../botan/src/lib/utils/thread_utils/semaphore.h | 34 + .../src/lib/utils/thread_utils/thread_pool.cpp | 103 + .../botan/src/lib/utils/thread_utils/thread_pool.h | 82 + comm/third_party/botan/src/lib/utils/timer.cpp | 150 + comm/third_party/botan/src/lib/utils/timer.h | 185 + comm/third_party/botan/src/lib/utils/types.h | 112 + comm/third_party/botan/src/lib/utils/uuid/info.txt | 8 + comm/third_party/botan/src/lib/utils/uuid/uuid.cpp | 82 + comm/third_party/botan/src/lib/utils/uuid/uuid.h | 69 + comm/third_party/botan/src/lib/utils/version.cpp | 100 + comm/third_party/botan/src/lib/utils/version.h | 101 + .../botan/src/lib/x509/asn1_alt_name.cpp | 265 + .../third_party/botan/src/lib/x509/asn1_alt_name.h | 11 + .../botan/src/lib/x509/asn1_attribute.h | 11 + .../third_party/botan/src/lib/x509/cert_status.cpp | 125 + comm/third_party/botan/src/lib/x509/cert_status.h | 11 + comm/third_party/botan/src/lib/x509/certstor.cpp | 233 + comm/third_party/botan/src/lib/x509/certstor.h | 165 + .../x509/certstor_flatfile/certstor_flatfile.cpp | 148 + .../lib/x509/certstor_flatfile/certstor_flatfile.h | 77 + .../botan/src/lib/x509/certstor_flatfile/info.txt | 12 + .../src/lib/x509/certstor_sql/certstor_sql.cpp | 335 + .../botan/src/lib/x509/certstor_sql/certstor_sql.h | 119 + .../botan/src/lib/x509/certstor_sql/info.txt | 3 + .../lib/x509/certstor_sqlite3/certstor_sqlite.cpp | 19 + .../lib/x509/certstor_sqlite3/certstor_sqlite.h | 34 + .../botan/src/lib/x509/certstor_sqlite3/info.txt | 8 + .../lib/x509/certstor_system/certstor_system.cpp | 70 + .../src/lib/x509/certstor_system/certstor_system.h | 42 + .../botan/src/lib/x509/certstor_system/info.txt | 8 + .../x509/certstor_system_macos/certstor_macos.cpp | 470 + .../x509/certstor_system_macos/certstor_macos.h | 81 + .../src/lib/x509/certstor_system_macos/info.txt | 15 + .../certstor_system_windows/certstor_windows.cpp | 258 + .../certstor_system_windows/certstor_windows.h | 70 + .../src/lib/x509/certstor_system_windows/info.txt | 16 + comm/third_party/botan/src/lib/x509/crl_ent.cpp | 140 + comm/third_party/botan/src/lib/x509/crl_ent.h | 11 + comm/third_party/botan/src/lib/x509/datastor.cpp | 205 + comm/third_party/botan/src/lib/x509/datastor.h | 85 + comm/third_party/botan/src/lib/x509/info.txt | 12 + .../botan/src/lib/x509/key_constraint.cpp | 106 + .../botan/src/lib/x509/key_constraint.h | 11 + .../botan/src/lib/x509/name_constraint.cpp | 273 + .../botan/src/lib/x509/name_constraint.h | 11 + comm/third_party/botan/src/lib/x509/ocsp.cpp | 363 + comm/third_party/botan/src/lib/x509/ocsp.h | 282 + comm/third_party/botan/src/lib/x509/ocsp_types.cpp | 105 + comm/third_party/botan/src/lib/x509/ocsp_types.h | 11 + comm/third_party/botan/src/lib/x509/pkcs10.cpp | 304 + comm/third_party/botan/src/lib/x509/pkcs10.h | 148 + comm/third_party/botan/src/lib/x509/pkix_enums.h | 143 + comm/third_party/botan/src/lib/x509/pkix_types.h | 613 + .../botan/src/lib/x509/x509_attribute.cpp | 58 + comm/third_party/botan/src/lib/x509/x509_ca.cpp | 338 + comm/third_party/botan/src/lib/x509/x509_ca.h | 261 + comm/third_party/botan/src/lib/x509/x509_crl.cpp | 268 + comm/third_party/botan/src/lib/x509/x509_crl.h | 209 + comm/third_party/botan/src/lib/x509/x509_dn.cpp | 428 + comm/third_party/botan/src/lib/x509/x509_dn.h | 11 + comm/third_party/botan/src/lib/x509/x509_dn_ub.cpp | 60 + comm/third_party/botan/src/lib/x509/x509_ext.cpp | 1023 + comm/third_party/botan/src/lib/x509/x509_ext.h | 529 + comm/third_party/botan/src/lib/x509/x509_obj.cpp | 424 + comm/third_party/botan/src/lib/x509/x509_obj.h | 144 + comm/third_party/botan/src/lib/x509/x509cert.cpp | 956 + comm/third_party/botan/src/lib/x509/x509cert.h | 461 + comm/third_party/botan/src/lib/x509/x509opt.cpp | 100 + comm/third_party/botan/src/lib/x509/x509path.cpp | 1088 + comm/third_party/botan/src/lib/x509/x509path.h | 475 + comm/third_party/botan/src/lib/x509/x509self.cpp | 152 + comm/third_party/botan/src/lib/x509/x509self.h | 222 + comm/third_party/botan/src/python/botan2.py | 1787 ++ .../botan/src/scripts/Dockerfile.android | 17 + comm/third_party/botan/src/scripts/bench.py | 216 + comm/third_party/botan/src/scripts/build_docs.py | 242 + comm/third_party/botan/src/scripts/check.py | 89 + comm/third_party/botan/src/scripts/ci/appveyor.yml | 90 + comm/third_party/botan/src/scripts/ci/codecov.yml | 15 + comm/third_party/botan/src/scripts/ci/lgtm.yml | 31 + .../botan/src/scripts/ci/setup_appveyor.bat | 19 + .../botan/src/scripts/ci/setup_gh_actions.sh | 69 + .../botan/src/scripts/ci/setup_travis.sh | 89 + comm/third_party/botan/src/scripts/ci/travis.yml | 50 + comm/third_party/botan/src/scripts/ci_build.py | 620 + .../botan/src/scripts/ci_check_install.py | 104 + comm/third_party/botan/src/scripts/cleanup.py | 133 + comm/third_party/botan/src/scripts/comba.py | 126 + .../botan/src/scripts/create_corpus_zip.py | 48 + comm/third_party/botan/src/scripts/dist.py | 466 + .../botan/src/scripts/docker-android.sh | 11 + comm/third_party/botan/src/scripts/ffi_decls.py | 113 + comm/third_party/botan/src/scripts/fuzzer.xml | 17 + .../botan/src/scripts/gen_os_features.py | 95 + comm/third_party/botan/src/scripts/install.py | 261 + comm/third_party/botan/src/scripts/macro_checks.py | 42 + comm/third_party/botan/src/scripts/monty.py | 98 + comm/third_party/botan/src/scripts/oids.py | 337 + .../botan/src/scripts/python_unittests.py | 224 + .../botan/src/scripts/python_unittests_unix.py | 67 + .../botan/src/scripts/run_tls_attacker.py | 138 + .../botan/src/scripts/run_tls_fuzzer.py | 98 + .../botan/src/scripts/show_dependencies.py | 213 + .../botan/src/scripts/test_all_configs.py | 136 + comm/third_party/botan/src/scripts/test_cli.py | 1429 ++ .../botan/src/scripts/test_cli_crypt.py | 220 + comm/third_party/botan/src/scripts/test_fuzzers.py | 187 + comm/third_party/botan/src/scripts/test_python.py | 695 + .../botan/src/scripts/tls_scanner/boa.txt | 1 + .../botan/src/scripts/tls_scanner/policy.txt | 19 + .../botan/src/scripts/tls_scanner/readme.txt | 5 + .../botan/src/scripts/tls_scanner/tls_scanner.py | 60 + .../botan/src/scripts/tls_scanner/urls.txt | 58 + .../botan/src/scripts/tls_suite_info.py | 342 + comm/third_party/botan/src/scripts/website.py | 166 + comm/third_party/bzip2/CHANGES | 356 + comm/third_party/bzip2/Changelog.mzla | 7 + comm/third_party/bzip2/LICENSE | 42 + comm/third_party/bzip2/README | 196 + comm/third_party/bzip2/README.COMPILATION.PROBLEMS | 58 + comm/third_party/bzip2/README.XML.STUFF | 45 + comm/third_party/bzip2/blocksort.c | 1094 + comm/third_party/bzip2/bzlib.c | 1572 ++ comm/third_party/bzip2/bzlib.h | 282 + comm/third_party/bzip2/bzlib_private.h | 509 + comm/third_party/bzip2/compress.c | 672 + comm/third_party/bzip2/crctable.c | 104 + comm/third_party/bzip2/decompress.c | 652 + comm/third_party/bzip2/huffman.c | 205 + comm/third_party/bzip2/moz.build | 28 + comm/third_party/bzip2/randtable.c | 84 + comm/third_party/clang/aarch64-apple-darwin.cfg | 1 + comm/third_party/clang/aarch64-linux-gnu.cfg | 1 + comm/third_party/clang/i686-linux-gnu.cfg | 6 + comm/third_party/clang/x86_64-apple-darwin.cfg | 1 + comm/third_party/json-c/AUTHORS | 61 + comm/third_party/json-c/COPYING | 42 + comm/third_party/json-c/ChangeLog | 583 + comm/third_party/json-c/INSTALL | 2 + comm/third_party/json-c/NEWS | 1 + comm/third_party/json-c/README.html | 41 + comm/third_party/json-c/README.md | 300 + comm/third_party/json-c/RELEASE_CHECKLIST.txt | 179 + comm/third_party/json-c/STYLE.txt | 31 + comm/third_party/json-c/arraylist.c | 205 + comm/third_party/json-c/arraylist.h | 88 + comm/third_party/json-c/config.h.in | 217 + comm/third_party/json-c/debug.c | 96 + comm/third_party/json-c/debug.h | 98 + comm/third_party/json-c/json.h.cmakein | 38 + comm/third_party/json-c/json_c_version.c | 19 + comm/third_party/json-c/json_c_version.h | 55 + comm/third_party/json-c/json_config.h.in | 3 + comm/third_party/json-c/json_inttypes.h | 24 + comm/third_party/json-c/json_object.c | 1808 ++ comm/third_party/json-c/json_object.h | 1077 + comm/third_party/json-c/json_object_iterator.c | 153 + comm/third_party/json-c/json_object_iterator.h | 228 + comm/third_party/json-c/json_object_private.h | 107 + comm/third_party/json-c/json_pointer.c | 358 + comm/third_party/json-c/json_pointer.h | 123 + comm/third_party/json-c/json_tokener.c | 1300 ++ comm/third_party/json-c/json_tokener.h | 328 + comm/third_party/json-c/json_types.h | 78 + comm/third_party/json-c/json_util.c | 296 + comm/third_party/json-c/json_util.h | 121 + comm/third_party/json-c/json_visit.c | 128 + comm/third_party/json-c/json_visit.h | 101 + comm/third_party/json-c/libjson.c | 26 + comm/third_party/json-c/linkhash.c | 716 + comm/third_party/json-c/linkhash.h | 447 + comm/third_party/json-c/math_compat.h | 43 + comm/third_party/json-c/moz.build | 52 + comm/third_party/json-c/printbuf.c | 180 + comm/third_party/json-c/printbuf.h | 131 + comm/third_party/json-c/random_seed.c | 355 + comm/third_party/json-c/random_seed.h | 29 + comm/third_party/json-c/snprintf_compat.h | 41 + comm/third_party/json-c/strdup_compat.h | 16 + comm/third_party/json-c/strerror_override.c | 110 + comm/third_party/json-c/strerror_override.h | 30 + .../third_party/json-c/strerror_override_private.h | 14 + comm/third_party/json-c/vasprintf_compat.h | 67 + comm/third_party/libgcrypt/AUTHORS | 257 + comm/third_party/libgcrypt/COPYING | 340 + comm/third_party/libgcrypt/COPYING.LIB | 510 + comm/third_party/libgcrypt/ChangeLog | 13947 ++++++++++++ comm/third_party/libgcrypt/ChangeLog-2011 | 1499 ++ comm/third_party/libgcrypt/INSTALL | 234 + comm/third_party/libgcrypt/LICENSES | 239 + comm/third_party/libgcrypt/Makefile.am | 158 + comm/third_party/libgcrypt/Makefile.in | 1019 + comm/third_party/libgcrypt/NEWS | 1440 ++ comm/third_party/libgcrypt/README | 276 + comm/third_party/libgcrypt/README.GIT | 49 + comm/third_party/libgcrypt/THANKS | 168 + comm/third_party/libgcrypt/TODO | 59 + comm/third_party/libgcrypt/VERSION | 1 + comm/third_party/libgcrypt/acinclude.m4 | 392 + comm/third_party/libgcrypt/aclocal.m4 | 1201 + comm/third_party/libgcrypt/autogen.rc | 13 + comm/third_party/libgcrypt/autogen.sh | 513 + .../third_party/libgcrypt/build-aux/ChangeLog-2011 | 169 + comm/third_party/libgcrypt/build-aux/compile | 347 + comm/third_party/libgcrypt/build-aux/config.guess | 1456 ++ comm/third_party/libgcrypt/build-aux/config.rpath | 690 + comm/third_party/libgcrypt/build-aux/config.sub | 1823 ++ comm/third_party/libgcrypt/build-aux/depcomp | 791 + comm/third_party/libgcrypt/build-aux/git-log-fix | 14 + .../third_party/libgcrypt/build-aux/git-log-footer | 14 + comm/third_party/libgcrypt/build-aux/install-sh | 527 + comm/third_party/libgcrypt/build-aux/ltmain.sh | 9664 ++++++++ comm/third_party/libgcrypt/build-aux/mdate-sh | 224 + comm/third_party/libgcrypt/build-aux/missing | 215 + comm/third_party/libgcrypt/build-aux/texinfo.tex | 8638 +++++++ comm/third_party/libgcrypt/cipher/ChangeLog-2011 | 4279 ++++ comm/third_party/libgcrypt/cipher/Makefile.am | 258 + comm/third_party/libgcrypt/cipher/Makefile.in | 1445 ++ comm/third_party/libgcrypt/cipher/arcfour-amd64.S | 108 + comm/third_party/libgcrypt/cipher/arcfour.c | 216 + .../libgcrypt/cipher/asm-common-aarch64.h | 104 + .../libgcrypt/cipher/asm-common-amd64.h | 189 + .../libgcrypt/cipher/asm-common-s390x.h | 90 + .../libgcrypt/cipher/asm-inline-s390x.h | 157 + .../libgcrypt/cipher/asm-poly1305-aarch64.h | 245 + .../libgcrypt/cipher/asm-poly1305-amd64.h | 171 + .../libgcrypt/cipher/asm-poly1305-s390x.h | 140 + comm/third_party/libgcrypt/cipher/bithelp.h | 123 + comm/third_party/libgcrypt/cipher/blake2.c | 996 + .../libgcrypt/cipher/blake2b-amd64-avx2.S | 300 + .../libgcrypt/cipher/blake2s-amd64-avx.S | 278 + comm/third_party/libgcrypt/cipher/blowfish-amd64.S | 601 + comm/third_party/libgcrypt/cipher/blowfish-arm.S | 743 + comm/third_party/libgcrypt/cipher/blowfish.c | 1142 + comm/third_party/libgcrypt/cipher/bufhelp.h | 385 + .../libgcrypt/cipher/camellia-aarch64.S | 586 + .../libgcrypt/cipher/camellia-aesni-avx-amd64.S | 2618 +++ .../libgcrypt/cipher/camellia-aesni-avx2-amd64.S | 1782 ++ comm/third_party/libgcrypt/cipher/camellia-arm.S | 626 + comm/third_party/libgcrypt/cipher/camellia-glue.c | 1097 + comm/third_party/libgcrypt/cipher/camellia.c | 1413 ++ comm/third_party/libgcrypt/cipher/camellia.h | 95 + comm/third_party/libgcrypt/cipher/cast5-amd64.S | 663 + comm/third_party/libgcrypt/cipher/cast5-arm.S | 728 + comm/third_party/libgcrypt/cipher/cast5.c | 1238 + .../libgcrypt/cipher/chacha20-aarch64.S | 648 + .../libgcrypt/cipher/chacha20-amd64-avx2.S | 601 + .../libgcrypt/cipher/chacha20-amd64-ssse3.S | 1012 + .../libgcrypt/cipher/chacha20-armv7-neon.S | 393 + comm/third_party/libgcrypt/cipher/chacha20-ppc.c | 646 + comm/third_party/libgcrypt/cipher/chacha20-s390x.S | 1561 ++ comm/third_party/libgcrypt/cipher/chacha20.c | 1306 ++ comm/third_party/libgcrypt/cipher/cipher-aeswrap.c | 209 + comm/third_party/libgcrypt/cipher/cipher-cbc.c | 292 + comm/third_party/libgcrypt/cipher/cipher-ccm.c | 415 + comm/third_party/libgcrypt/cipher/cipher-cfb.c | 317 + comm/third_party/libgcrypt/cipher/cipher-cmac.c | 292 + comm/third_party/libgcrypt/cipher/cipher-ctr.c | 120 + comm/third_party/libgcrypt/cipher/cipher-eax.c | 289 + .../libgcrypt/cipher/cipher-gcm-armv7-neon.S | 341 + .../libgcrypt/cipher/cipher-gcm-armv8-aarch32-ce.S | 433 + .../libgcrypt/cipher/cipher-gcm-armv8-aarch64-ce.S | 424 + .../libgcrypt/cipher/cipher-gcm-intel-pclmul.c | 712 + comm/third_party/libgcrypt/cipher/cipher-gcm.c | 1207 + .../third_party/libgcrypt/cipher/cipher-internal.h | 809 + comm/third_party/libgcrypt/cipher/cipher-ocb.c | 761 + comm/third_party/libgcrypt/cipher/cipher-ofb.c | 108 + .../third_party/libgcrypt/cipher/cipher-poly1305.c | 375 + .../third_party/libgcrypt/cipher/cipher-selftest.c | 512 + .../third_party/libgcrypt/cipher/cipher-selftest.h | 69 + comm/third_party/libgcrypt/cipher/cipher-xts.c | 189 + comm/third_party/libgcrypt/cipher/cipher.c | 1767 ++ .../libgcrypt/cipher/crc-armv8-aarch64-ce.S | 497 + comm/third_party/libgcrypt/cipher/crc-armv8-ce.c | 229 + .../libgcrypt/cipher/crc-intel-pclmul.c | 939 + comm/third_party/libgcrypt/cipher/crc-ppc.c | 656 + comm/third_party/libgcrypt/cipher/crc.c | 955 + comm/third_party/libgcrypt/cipher/des-amd64.S | 1111 + comm/third_party/libgcrypt/cipher/des.c | 1507 ++ comm/third_party/libgcrypt/cipher/dsa-common.c | 418 + comm/third_party/libgcrypt/cipher/dsa.c | 1394 ++ comm/third_party/libgcrypt/cipher/ecc-common.h | 140 + comm/third_party/libgcrypt/cipher/ecc-curves.c | 1603 ++ comm/third_party/libgcrypt/cipher/ecc-ecdh.c | 127 + comm/third_party/libgcrypt/cipher/ecc-ecdsa.c | 248 + comm/third_party/libgcrypt/cipher/ecc-eddsa.c | 1182 + comm/third_party/libgcrypt/cipher/ecc-gost.c | 218 + comm/third_party/libgcrypt/cipher/ecc-misc.c | 438 + comm/third_party/libgcrypt/cipher/ecc-sm2.c | 569 + comm/third_party/libgcrypt/cipher/ecc.c | 1779 ++ comm/third_party/libgcrypt/cipher/elgamal.c | 1149 + comm/third_party/libgcrypt/cipher/gost-s-box.c | 266 + comm/third_party/libgcrypt/cipher/gost.h | 34 + comm/third_party/libgcrypt/cipher/gost28147.c | 553 + comm/third_party/libgcrypt/cipher/gostr3411-94.c | 383 + comm/third_party/libgcrypt/cipher/hash-common.c | 193 + comm/third_party/libgcrypt/cipher/hash-common.h | 62 + comm/third_party/libgcrypt/cipher/idea.c | 382 + comm/third_party/libgcrypt/cipher/kdf-internal.h | 40 + comm/third_party/libgcrypt/cipher/kdf.c | 503 + .../libgcrypt/cipher/keccak-armv7-neon.S | 945 + comm/third_party/libgcrypt/cipher/keccak.c | 1577 ++ .../libgcrypt/cipher/keccak_permute_32.h | 536 + .../libgcrypt/cipher/keccak_permute_64.h | 385 + comm/third_party/libgcrypt/cipher/mac-cmac.c | 524 + comm/third_party/libgcrypt/cipher/mac-gmac.c | 187 + comm/third_party/libgcrypt/cipher/mac-hmac.c | 1495 ++ comm/third_party/libgcrypt/cipher/mac-internal.h | 275 + comm/third_party/libgcrypt/cipher/mac-poly1305.c | 364 + comm/third_party/libgcrypt/cipher/mac.c | 808 + comm/third_party/libgcrypt/cipher/md.c | 1639 ++ comm/third_party/libgcrypt/cipher/md4.c | 296 + comm/third_party/libgcrypt/cipher/md5.c | 322 + .../libgcrypt/cipher/poly1305-internal.h | 64 + comm/third_party/libgcrypt/cipher/poly1305-s390x.S | 87 + comm/third_party/libgcrypt/cipher/poly1305.c | 740 + comm/third_party/libgcrypt/cipher/primegen.c | 1878 ++ .../third_party/libgcrypt/cipher/pubkey-internal.h | 105 + comm/third_party/libgcrypt/cipher/pubkey-util.c | 1160 + comm/third_party/libgcrypt/cipher/pubkey.c | 970 + comm/third_party/libgcrypt/cipher/rfc2268.c | 378 + .../libgcrypt/cipher/rijndael-aarch64.S | 514 + comm/third_party/libgcrypt/cipher/rijndael-aesni.c | 3965 ++++ comm/third_party/libgcrypt/cipher/rijndael-amd64.S | 477 + comm/third_party/libgcrypt/cipher/rijndael-arm.S | 581 + .../libgcrypt/cipher/rijndael-armv8-aarch32-ce.S | 1867 ++ .../libgcrypt/cipher/rijndael-armv8-aarch64-ce.S | 1613 ++ .../libgcrypt/cipher/rijndael-armv8-ce.c | 414 + .../libgcrypt/cipher/rijndael-internal.h | 194 + .../libgcrypt/cipher/rijndael-padlock.c | 110 + .../libgcrypt/cipher/rijndael-ppc-common.h | 342 + .../libgcrypt/cipher/rijndael-ppc-functions.h | 2020 ++ comm/third_party/libgcrypt/cipher/rijndael-ppc.c | 259 + .../third_party/libgcrypt/cipher/rijndael-ppc9le.c | 102 + comm/third_party/libgcrypt/cipher/rijndael-s390x.c | 1155 + .../libgcrypt/cipher/rijndael-ssse3-amd64-asm.S | 874 + .../libgcrypt/cipher/rijndael-ssse3-amd64.c | 743 + .../third_party/libgcrypt/cipher/rijndael-tables.h | 227 + comm/third_party/libgcrypt/cipher/rijndael.c | 2032 ++ comm/third_party/libgcrypt/cipher/rmd160.c | 529 + comm/third_party/libgcrypt/cipher/rsa-common.c | 1038 + comm/third_party/libgcrypt/cipher/rsa.c | 2035 ++ comm/third_party/libgcrypt/cipher/salsa20-amd64.S | 940 + .../libgcrypt/cipher/salsa20-armv7-neon.S | 899 + comm/third_party/libgcrypt/cipher/salsa20.c | 600 + comm/third_party/libgcrypt/cipher/scrypt.c | 322 + comm/third_party/libgcrypt/cipher/seed.c | 478 + .../libgcrypt/cipher/serpent-armv7-neon.S | 1124 + .../libgcrypt/cipher/serpent-avx2-amd64.S | 1160 + .../libgcrypt/cipher/serpent-sse2-amd64.S | 1211 + comm/third_party/libgcrypt/cipher/serpent.c | 1807 ++ .../third_party/libgcrypt/cipher/sha1-armv7-neon.S | 526 + .../libgcrypt/cipher/sha1-armv8-aarch32-ce.S | 220 + .../libgcrypt/cipher/sha1-armv8-aarch64-ce.S | 201 + comm/third_party/libgcrypt/cipher/sha1-avx-amd64.S | 429 + .../libgcrypt/cipher/sha1-avx-bmi2-amd64.S | 441 + .../libgcrypt/cipher/sha1-avx2-bmi2-amd64.S | 573 + .../libgcrypt/cipher/sha1-intel-shaext.c | 292 + .../libgcrypt/cipher/sha1-ssse3-amd64.S | 437 + comm/third_party/libgcrypt/cipher/sha1.c | 765 + comm/third_party/libgcrypt/cipher/sha1.h | 47 + .../libgcrypt/cipher/sha256-armv8-aarch32-ce.S | 231 + .../libgcrypt/cipher/sha256-armv8-aarch64-ce.S | 215 + .../libgcrypt/cipher/sha256-avx-amd64.S | 506 + .../libgcrypt/cipher/sha256-avx2-bmi2-amd64.S | 527 + .../libgcrypt/cipher/sha256-intel-shaext.c | 363 + comm/third_party/libgcrypt/cipher/sha256-ppc.c | 795 + .../libgcrypt/cipher/sha256-ssse3-amd64.S | 528 + comm/third_party/libgcrypt/cipher/sha256.c | 857 + comm/third_party/libgcrypt/cipher/sha512-arm.S | 464 + .../libgcrypt/cipher/sha512-armv7-neon.S | 450 + .../libgcrypt/cipher/sha512-avx-amd64.S | 461 + .../libgcrypt/cipher/sha512-avx2-bmi2-amd64.S | 502 + comm/third_party/libgcrypt/cipher/sha512-ppc.c | 969 + .../libgcrypt/cipher/sha512-ssse3-amd64.S | 467 + .../libgcrypt/cipher/sha512-ssse3-i386.c | 404 + comm/third_party/libgcrypt/cipher/sha512.c | 1316 ++ comm/third_party/libgcrypt/cipher/sm3.c | 473 + .../libgcrypt/cipher/sm4-aesni-avx-amd64.S | 987 + .../libgcrypt/cipher/sm4-aesni-avx2-amd64.S | 851 + comm/third_party/libgcrypt/cipher/sm4.c | 1251 + comm/third_party/libgcrypt/cipher/stribog.c | 1362 ++ comm/third_party/libgcrypt/cipher/tiger.c | 860 + .../third_party/libgcrypt/cipher/twofish-aarch64.S | 321 + comm/third_party/libgcrypt/cipher/twofish-amd64.S | 1184 + comm/third_party/libgcrypt/cipher/twofish-arm.S | 363 + .../libgcrypt/cipher/twofish-avx2-amd64.S | 1048 + comm/third_party/libgcrypt/cipher/twofish.c | 1793 ++ .../libgcrypt/cipher/whirlpool-sse2-amd64.S | 348 + comm/third_party/libgcrypt/cipher/whirlpool.c | 1535 ++ comm/third_party/libgcrypt/compat/Makefile.am | 48 + comm/third_party/libgcrypt/compat/Makefile.in | 697 + comm/third_party/libgcrypt/compat/clock.c | 36 + comm/third_party/libgcrypt/compat/compat.c | 40 + comm/third_party/libgcrypt/compat/getpid.c | 29 + comm/third_party/libgcrypt/compat/libcompat.h | 37 + comm/third_party/libgcrypt/config.h.in | 753 + comm/third_party/libgcrypt/configure | 22807 +++++++++++++++++++ comm/third_party/libgcrypt/configure.ac | 3257 +++ comm/third_party/libgcrypt/doc/ChangeLog-2011 | 488 + comm/third_party/libgcrypt/doc/DCO | 29 + comm/third_party/libgcrypt/doc/HACKING | 143 + comm/third_party/libgcrypt/doc/Makefile.am | 106 + comm/third_party/libgcrypt/doc/Makefile.in | 982 + comm/third_party/libgcrypt/doc/README.apichanges | 115 + comm/third_party/libgcrypt/doc/fips-fsm.eps | 514 + comm/third_party/libgcrypt/doc/fips-fsm.fig | 199 + comm/third_party/libgcrypt/doc/fips-fsm.pdf | Bin 0 -> 12084 bytes comm/third_party/libgcrypt/doc/fips-fsm.png | Bin 0 -> 6884 bytes comm/third_party/libgcrypt/doc/gcrypt.info | 135 + comm/third_party/libgcrypt/doc/gcrypt.info-1 | 7269 ++++++ comm/third_party/libgcrypt/doc/gcrypt.info-2 | Bin 0 -> 23526 bytes comm/third_party/libgcrypt/doc/gcrypt.texi | 6944 ++++++ comm/third_party/libgcrypt/doc/gpl.texi | 392 + comm/third_party/libgcrypt/doc/lgpl.texi | 560 + .../libgcrypt/doc/libgcrypt-modules.eps | 322 + .../libgcrypt/doc/libgcrypt-modules.fig | 193 + .../libgcrypt/doc/libgcrypt-modules.pdf | Bin 0 -> 6933 bytes .../libgcrypt/doc/libgcrypt-modules.png | Bin 0 -> 2535 bytes comm/third_party/libgcrypt/doc/stamp-vti | 4 + comm/third_party/libgcrypt/doc/version.texi | 4 + comm/third_party/libgcrypt/doc/yat2m.c | 1649 ++ comm/third_party/libgcrypt/m4/ChangeLog-2011 | 50 + comm/third_party/libgcrypt/m4/Makefile.am | 2 + comm/third_party/libgcrypt/m4/Makefile.in | 491 + comm/third_party/libgcrypt/m4/ax_cc_for_build.m4 | 77 + comm/third_party/libgcrypt/m4/gpg-error.m4 | 188 + comm/third_party/libgcrypt/m4/libtool.m4 | 8031 +++++++ comm/third_party/libgcrypt/m4/ltoptions.m4 | 384 + comm/third_party/libgcrypt/m4/ltsugar.m4 | 123 + comm/third_party/libgcrypt/m4/ltversion.m4 | 23 + comm/third_party/libgcrypt/m4/lt~obsolete.m4 | 98 + comm/third_party/libgcrypt/m4/noexecstack.m4 | 55 + comm/third_party/libgcrypt/m4/socklen.m4 | 76 + comm/third_party/libgcrypt/m4/sys_socket_h.m4 | 23 + comm/third_party/libgcrypt/mkinstalldirs | 161 + comm/third_party/libgcrypt/mpi/ChangeLog-2011 | 831 + comm/third_party/libgcrypt/mpi/Makefile.am | 179 + comm/third_party/libgcrypt/mpi/Makefile.in | 947 + comm/third_party/libgcrypt/mpi/aarch64/distfiles | 6 + .../libgcrypt/mpi/aarch64/mpi-asm-defs.h | 4 + comm/third_party/libgcrypt/mpi/aarch64/mpih-add1.S | 74 + comm/third_party/libgcrypt/mpi/aarch64/mpih-mul1.S | 99 + comm/third_party/libgcrypt/mpi/aarch64/mpih-mul2.S | 111 + comm/third_party/libgcrypt/mpi/aarch64/mpih-mul3.S | 124 + comm/third_party/libgcrypt/mpi/aarch64/mpih-sub1.S | 74 + comm/third_party/libgcrypt/mpi/alpha/README | 53 + comm/third_party/libgcrypt/mpi/alpha/distfiles | 11 + comm/third_party/libgcrypt/mpi/alpha/mpih-add1.S | 124 + comm/third_party/libgcrypt/mpi/alpha/mpih-lshift.S | 122 + comm/third_party/libgcrypt/mpi/alpha/mpih-mul1.S | 90 + comm/third_party/libgcrypt/mpi/alpha/mpih-mul2.S | 97 + comm/third_party/libgcrypt/mpi/alpha/mpih-mul3.S | 95 + comm/third_party/libgcrypt/mpi/alpha/mpih-rshift.S | 118 + comm/third_party/libgcrypt/mpi/alpha/mpih-sub1.S | 124 + comm/third_party/libgcrypt/mpi/alpha/udiv-qrnnd.S | 159 + comm/third_party/libgcrypt/mpi/amd64/distfiles | 9 + comm/third_party/libgcrypt/mpi/amd64/func_abi.h | 56 + .../third_party/libgcrypt/mpi/amd64/mpi-asm-defs.h | 4 + comm/third_party/libgcrypt/mpi/amd64/mpih-add1.S | 64 + comm/third_party/libgcrypt/mpi/amd64/mpih-lshift.S | 79 + comm/third_party/libgcrypt/mpi/amd64/mpih-mul1.S | 67 + comm/third_party/libgcrypt/mpi/amd64/mpih-mul2.S | 66 + comm/third_party/libgcrypt/mpi/amd64/mpih-mul3.S | 67 + comm/third_party/libgcrypt/mpi/amd64/mpih-rshift.S | 82 + comm/third_party/libgcrypt/mpi/amd64/mpih-sub1.S | 63 + comm/third_party/libgcrypt/mpi/arm/distfiles | 6 + comm/third_party/libgcrypt/mpi/arm/mpi-asm-defs.h | 4 + comm/third_party/libgcrypt/mpi/arm/mpih-add1.S | 76 + comm/third_party/libgcrypt/mpi/arm/mpih-mul1.S | 80 + comm/third_party/libgcrypt/mpi/arm/mpih-mul2.S | 94 + comm/third_party/libgcrypt/mpi/arm/mpih-mul3.S | 100 + comm/third_party/libgcrypt/mpi/arm/mpih-sub1.S | 77 + .../third_party/libgcrypt/mpi/asm-common-aarch64.h | 26 + comm/third_party/libgcrypt/mpi/config.links | 470 + comm/third_party/libgcrypt/mpi/ec-ed25519.c | 37 + comm/third_party/libgcrypt/mpi/ec-internal.h | 25 + comm/third_party/libgcrypt/mpi/ec.c | 2062 ++ comm/third_party/libgcrypt/mpi/generic/distfiles | 10 + .../libgcrypt/mpi/generic/mpi-asm-defs.h | 8 + comm/third_party/libgcrypt/mpi/generic/mpih-add1.c | 65 + .../libgcrypt/mpi/generic/mpih-lshift.c | 68 + comm/third_party/libgcrypt/mpi/generic/mpih-mul1.c | 62 + comm/third_party/libgcrypt/mpi/generic/mpih-mul2.c | 68 + comm/third_party/libgcrypt/mpi/generic/mpih-mul3.c | 68 + .../libgcrypt/mpi/generic/mpih-rshift.c | 67 + comm/third_party/libgcrypt/mpi/generic/mpih-sub1.c | 66 + .../libgcrypt/mpi/generic/udiv-w-sdiv.c | 133 + comm/third_party/libgcrypt/mpi/hppa/README | 84 + comm/third_party/libgcrypt/mpi/hppa/distfiles | 7 + comm/third_party/libgcrypt/mpi/hppa/mpih-add1.S | 70 + comm/third_party/libgcrypt/mpi/hppa/mpih-lshift.S | 77 + comm/third_party/libgcrypt/mpi/hppa/mpih-rshift.S | 73 + comm/third_party/libgcrypt/mpi/hppa/mpih-sub1.S | 78 + comm/third_party/libgcrypt/mpi/hppa/udiv-qrnnd.S | 297 + comm/third_party/libgcrypt/mpi/hppa1.1/distfiles | 5 + comm/third_party/libgcrypt/mpi/hppa1.1/mpih-mul1.S | 115 + comm/third_party/libgcrypt/mpi/hppa1.1/mpih-mul2.S | 117 + comm/third_party/libgcrypt/mpi/hppa1.1/mpih-mul3.S | 126 + .../third_party/libgcrypt/mpi/hppa1.1/udiv-qrnnd.S | 92 + comm/third_party/libgcrypt/mpi/i386/distfiles | 9 + comm/third_party/libgcrypt/mpi/i386/mpih-add1.S | 161 + comm/third_party/libgcrypt/mpi/i386/mpih-lshift.S | 102 + comm/third_party/libgcrypt/mpi/i386/mpih-mul1.S | 94 + comm/third_party/libgcrypt/mpi/i386/mpih-mul2.S | 96 + comm/third_party/libgcrypt/mpi/i386/mpih-mul3.S | 96 + comm/third_party/libgcrypt/mpi/i386/mpih-rshift.S | 105 + comm/third_party/libgcrypt/mpi/i386/mpih-sub1.S | 162 + comm/third_party/libgcrypt/mpi/i386/syntax.h | 94 + comm/third_party/libgcrypt/mpi/i586/README | 26 + comm/third_party/libgcrypt/mpi/i586/distfiles | 9 + comm/third_party/libgcrypt/mpi/i586/mpih-add1.S | 135 + comm/third_party/libgcrypt/mpi/i586/mpih-lshift.S | 229 + comm/third_party/libgcrypt/mpi/i586/mpih-mul1.S | 89 + comm/third_party/libgcrypt/mpi/i586/mpih-mul2.S | 93 + comm/third_party/libgcrypt/mpi/i586/mpih-mul3.S | 93 + comm/third_party/libgcrypt/mpi/i586/mpih-rshift.S | 228 + comm/third_party/libgcrypt/mpi/i586/mpih-sub1.S | 142 + comm/third_party/libgcrypt/mpi/longlong.h | 1801 ++ comm/third_party/libgcrypt/mpi/m68k/distfiles | 8 + .../libgcrypt/mpi/m68k/mc68020/distfiles | 3 + .../libgcrypt/mpi/m68k/mc68020/mpih-mul1.S | 104 + .../libgcrypt/mpi/m68k/mc68020/mpih-mul2.S | 94 + .../libgcrypt/mpi/m68k/mc68020/mpih-mul3.S | 97 + comm/third_party/libgcrypt/mpi/m68k/mpih-add1.S | 92 + comm/third_party/libgcrypt/mpi/m68k/mpih-lshift.S | 164 + comm/third_party/libgcrypt/mpi/m68k/mpih-rshift.S | 162 + comm/third_party/libgcrypt/mpi/m68k/mpih-sub1.S | 91 + comm/third_party/libgcrypt/mpi/m68k/syntax.h | 185 + comm/third_party/libgcrypt/mpi/mips3/README | 23 + comm/third_party/libgcrypt/mpi/mips3/distfiles | 10 + .../third_party/libgcrypt/mpi/mips3/mpi-asm-defs.h | 10 + comm/third_party/libgcrypt/mpi/mips3/mpih-add1.S | 124 + comm/third_party/libgcrypt/mpi/mips3/mpih-lshift.S | 97 + comm/third_party/libgcrypt/mpi/mips3/mpih-mul1.S | 89 + comm/third_party/libgcrypt/mpi/mips3/mpih-mul2.S | 101 + comm/third_party/libgcrypt/mpi/mips3/mpih-mul3.S | 101 + comm/third_party/libgcrypt/mpi/mips3/mpih-rshift.S | 95 + comm/third_party/libgcrypt/mpi/mips3/mpih-sub1.S | 125 + comm/third_party/libgcrypt/mpi/mpi-add.c | 235 + comm/third_party/libgcrypt/mpi/mpi-bit.c | 411 + comm/third_party/libgcrypt/mpi/mpi-cmp.c | 130 + comm/third_party/libgcrypt/mpi/mpi-div.c | 360 + comm/third_party/libgcrypt/mpi/mpi-gcd.c | 52 + comm/third_party/libgcrypt/mpi/mpi-inline.c | 35 + comm/third_party/libgcrypt/mpi/mpi-inline.h | 161 + comm/third_party/libgcrypt/mpi/mpi-internal.h | 300 + comm/third_party/libgcrypt/mpi/mpi-inv.c | 565 + comm/third_party/libgcrypt/mpi/mpi-mod.c | 188 + comm/third_party/libgcrypt/mpi/mpi-mpow.c | 223 + comm/third_party/libgcrypt/mpi/mpi-mul.c | 212 + comm/third_party/libgcrypt/mpi/mpi-pow.c | 772 + comm/third_party/libgcrypt/mpi/mpi-scan.c | 130 + comm/third_party/libgcrypt/mpi/mpicoder.c | 958 + comm/third_party/libgcrypt/mpi/mpih-const-time.c | 197 + comm/third_party/libgcrypt/mpi/mpih-div.c | 532 + comm/third_party/libgcrypt/mpi/mpih-mul.c | 529 + comm/third_party/libgcrypt/mpi/mpiutil.c | 780 + comm/third_party/libgcrypt/mpi/pa7100/distfiles | 3 + .../third_party/libgcrypt/mpi/pa7100/mpih-lshift.S | 96 + .../third_party/libgcrypt/mpi/pa7100/mpih-rshift.S | 92 + comm/third_party/libgcrypt/mpi/pentium4/README | 115 + comm/third_party/libgcrypt/mpi/pentium4/distfiles | 3 + .../libgcrypt/mpi/pentium4/mmx/distfiles | 2 + .../libgcrypt/mpi/pentium4/mmx/mpih-lshift.S | 457 + .../libgcrypt/mpi/pentium4/mmx/mpih-rshift.S | 453 + .../libgcrypt/mpi/pentium4/sse2/distfiles | 5 + .../libgcrypt/mpi/pentium4/sse2/mpih-add1.S | 91 + .../libgcrypt/mpi/pentium4/sse2/mpih-mul1.S | 96 + .../libgcrypt/mpi/pentium4/sse2/mpih-mul2.S | 136 + .../libgcrypt/mpi/pentium4/sse2/mpih-mul3.S | 127 + .../libgcrypt/mpi/pentium4/sse2/mpih-sub1.S | 112 + comm/third_party/libgcrypt/mpi/power/distfiles | 7 + comm/third_party/libgcrypt/mpi/power/mpih-add1.S | 87 + comm/third_party/libgcrypt/mpi/power/mpih-lshift.S | 64 + comm/third_party/libgcrypt/mpi/power/mpih-mul1.S | 115 + comm/third_party/libgcrypt/mpi/power/mpih-mul2.S | 130 + comm/third_party/libgcrypt/mpi/power/mpih-mul3.S | 135 + comm/third_party/libgcrypt/mpi/power/mpih-rshift.S | 64 + comm/third_party/libgcrypt/mpi/power/mpih-sub1.S | 88 + comm/third_party/libgcrypt/mpi/powerpc32/distfiles | 9 + .../libgcrypt/mpi/powerpc32/mpih-add1.S | 136 + .../libgcrypt/mpi/powerpc32/mpih-lshift.S | 198 + .../libgcrypt/mpi/powerpc32/mpih-mul1.S | 120 + .../libgcrypt/mpi/powerpc32/mpih-mul2.S | 127 + .../libgcrypt/mpi/powerpc32/mpih-mul3.S | 130 + .../libgcrypt/mpi/powerpc32/mpih-rshift.S | 131 + .../libgcrypt/mpi/powerpc32/mpih-sub1.S | 133 + comm/third_party/libgcrypt/mpi/powerpc32/syntax.h | 75 + comm/third_party/libgcrypt/mpi/powerpc64/distfiles | 0 comm/third_party/libgcrypt/mpi/sparc32/distfiles | 5 + comm/third_party/libgcrypt/mpi/sparc32/mpih-add1.S | 239 + .../libgcrypt/mpi/sparc32/mpih-lshift.S | 97 + .../libgcrypt/mpi/sparc32/mpih-rshift.S | 93 + comm/third_party/libgcrypt/mpi/sparc32/udiv.S | 195 + comm/third_party/libgcrypt/mpi/sparc32v8/distfiles | 4 + .../libgcrypt/mpi/sparc32v8/mpih-mul1.S | 109 + .../libgcrypt/mpi/sparc32v8/mpih-mul2.S | 132 + .../libgcrypt/mpi/sparc32v8/mpih-mul3.S | 67 + .../third_party/libgcrypt/mpi/supersparc/distfiles | 2 + comm/third_party/libgcrypt/mpi/supersparc/udiv.S | 118 + comm/third_party/libgcrypt/random/ChangeLog-2011 | 191 + comm/third_party/libgcrypt/random/Makefile.am | 69 + comm/third_party/libgcrypt/random/Makefile.in | 744 + .../libgcrypt/random/jitterentropy-base-user.h | 134 + .../libgcrypt/random/jitterentropy-base.c | 791 + comm/third_party/libgcrypt/random/jitterentropy.h | 148 + comm/third_party/libgcrypt/random/rand-internal.h | 148 + comm/third_party/libgcrypt/random/random-csprng.c | 1367 ++ comm/third_party/libgcrypt/random/random-daemon.c | 336 + comm/third_party/libgcrypt/random/random-drbg.c | 2668 +++ comm/third_party/libgcrypt/random/random-system.c | 250 + comm/third_party/libgcrypt/random/random.c | 584 + comm/third_party/libgcrypt/random/random.h | 79 + comm/third_party/libgcrypt/random/rndegd.c | 290 + comm/third_party/libgcrypt/random/rndhw.c | 230 + comm/third_party/libgcrypt/random/rndjent.c | 389 + comm/third_party/libgcrypt/random/rndlinux.c | 366 + comm/third_party/libgcrypt/random/rndunix.c | 937 + comm/third_party/libgcrypt/random/rndw32.c | 1030 + comm/third_party/libgcrypt/random/rndw32ce.c | 199 + comm/third_party/libgcrypt/src/ChangeLog-2011 | 2398 ++ comm/third_party/libgcrypt/src/Makefile.am | 162 + comm/third_party/libgcrypt/src/Makefile.in | 1361 ++ comm/third_party/libgcrypt/src/cipher-proto.h | 280 + comm/third_party/libgcrypt/src/cipher.h | 244 + comm/third_party/libgcrypt/src/context.c | 137 + comm/third_party/libgcrypt/src/context.h | 32 + comm/third_party/libgcrypt/src/dumpsexp.c | 768 + comm/third_party/libgcrypt/src/ec-context.h | 106 + comm/third_party/libgcrypt/src/fips.c | 884 + comm/third_party/libgcrypt/src/g10lib.h | 503 + comm/third_party/libgcrypt/src/gcrypt-int.h | 534 + comm/third_party/libgcrypt/src/gcrypt-testapi.h | 69 + comm/third_party/libgcrypt/src/gcrypt.h.in | 1845 ++ comm/third_party/libgcrypt/src/gcryptrnd.c | 680 + comm/third_party/libgcrypt/src/getrandom.c | 326 + comm/third_party/libgcrypt/src/global.c | 1368 ++ comm/third_party/libgcrypt/src/hmac256.c | 800 + comm/third_party/libgcrypt/src/hmac256.h | 36 + comm/third_party/libgcrypt/src/hwf-arm.c | 393 + comm/third_party/libgcrypt/src/hwf-common.h | 28 + comm/third_party/libgcrypt/src/hwf-ppc.c | 243 + comm/third_party/libgcrypt/src/hwf-s390x.c | 230 + comm/third_party/libgcrypt/src/hwf-x86.c | 409 + comm/third_party/libgcrypt/src/hwfeatures.c | 237 + comm/third_party/libgcrypt/src/libgcrypt-config.in | 201 + comm/third_party/libgcrypt/src/libgcrypt.def | 292 + comm/third_party/libgcrypt/src/libgcrypt.m4 | 167 + comm/third_party/libgcrypt/src/libgcrypt.pc.in | 18 + comm/third_party/libgcrypt/src/libgcrypt.vers | 128 + comm/third_party/libgcrypt/src/misc.c | 579 + comm/third_party/libgcrypt/src/missing-string.c | 54 + comm/third_party/libgcrypt/src/mpi.h | 327 + comm/third_party/libgcrypt/src/mpicalc.c | 627 + comm/third_party/libgcrypt/src/secmem.c | 952 + comm/third_party/libgcrypt/src/secmem.h | 42 + comm/third_party/libgcrypt/src/sexp.c | 2699 +++ comm/third_party/libgcrypt/src/stdmem.c | 246 + comm/third_party/libgcrypt/src/stdmem.h | 32 + comm/third_party/libgcrypt/src/types.h | 136 + comm/third_party/libgcrypt/src/versioninfo.rc.in | 51 + comm/third_party/libgcrypt/src/visibility.c | 1599 ++ comm/third_party/libgcrypt/src/visibility.h | 521 + comm/third_party/libgcrypt/tests/ChangeLog-2011 | 944 + comm/third_party/libgcrypt/tests/Makefile.am | 113 + comm/third_party/libgcrypt/tests/Makefile.in | 1293 ++ comm/third_party/libgcrypt/tests/README | 9 + comm/third_party/libgcrypt/tests/aeswrap.c | 284 + .../libgcrypt/tests/basic-disable-all-hwf.in | 4 + comm/third_party/libgcrypt/tests/basic.c | 14576 ++++++++++++ .../tests/basic_all_hwfeature_combinations.sh | 111 + comm/third_party/libgcrypt/tests/bench-slope.c | 2349 ++ comm/third_party/libgcrypt/tests/benchmark.c | 2037 ++ comm/third_party/libgcrypt/tests/blake2b.h | 1539 ++ comm/third_party/libgcrypt/tests/blake2s.h | 1027 + comm/third_party/libgcrypt/tests/cavs_driver.pl | 2243 ++ comm/third_party/libgcrypt/tests/cavs_tests.sh | 135 + comm/third_party/libgcrypt/tests/curves.c | 190 + comm/third_party/libgcrypt/tests/dsa-rfc6979.c | 983 + comm/third_party/libgcrypt/tests/fips186-dsa.c | 572 + comm/third_party/libgcrypt/tests/fipsdrv.c | 2865 +++ comm/third_party/libgcrypt/tests/gchash.c | 123 + comm/third_party/libgcrypt/tests/genhashdata.c | 160 + comm/third_party/libgcrypt/tests/hashtest-256g.in | 7 + comm/third_party/libgcrypt/tests/hashtest.c | 451 + comm/third_party/libgcrypt/tests/hmac.c | 203 + comm/third_party/libgcrypt/tests/keygen.c | 787 + comm/third_party/libgcrypt/tests/keygrip.c | 341 + comm/third_party/libgcrypt/tests/mpitests.c | 610 + comm/third_party/libgcrypt/tests/pkbench.c | 485 + comm/third_party/libgcrypt/tests/pkcs1v2-oaep.h | 781 + comm/third_party/libgcrypt/tests/pkcs1v2-pss.h | 968 + comm/third_party/libgcrypt/tests/pkcs1v2-v15c.h | 3919 ++++ comm/third_party/libgcrypt/tests/pkcs1v2-v15s.h | 3660 +++ comm/third_party/libgcrypt/tests/pkcs1v2.c | 676 + comm/third_party/libgcrypt/tests/prime.c | 241 + comm/third_party/libgcrypt/tests/pubkey.c | 1203 + comm/third_party/libgcrypt/tests/random.c | 826 + comm/third_party/libgcrypt/tests/rsa-16k.key | 18 + comm/third_party/libgcrypt/tests/rsacvt.c | 399 + comm/third_party/libgcrypt/tests/sha3-224.h | 1025 + comm/third_party/libgcrypt/tests/sha3-256.h | 1025 + comm/third_party/libgcrypt/tests/sha3-384.h | 1025 + comm/third_party/libgcrypt/tests/sha3-512.h | 1025 + comm/third_party/libgcrypt/tests/stopwatch.h | 113 + comm/third_party/libgcrypt/tests/t-common.h | 198 + comm/third_party/libgcrypt/tests/t-convert.c | 534 + comm/third_party/libgcrypt/tests/t-cv25519.c | 650 + comm/third_party/libgcrypt/tests/t-ed25519.c | 497 + comm/third_party/libgcrypt/tests/t-ed25519.inp | 6172 +++++ comm/third_party/libgcrypt/tests/t-ed448.c | 537 + comm/third_party/libgcrypt/tests/t-ed448.inp | 75 + comm/third_party/libgcrypt/tests/t-kdf.c | 1292 ++ comm/third_party/libgcrypt/tests/t-lock.c | 465 + comm/third_party/libgcrypt/tests/t-mpi-bit.c | 362 + comm/third_party/libgcrypt/tests/t-mpi-point.c | 1324 ++ comm/third_party/libgcrypt/tests/t-secmem.c | 209 + comm/third_party/libgcrypt/tests/t-sexp.c | 1344 ++ comm/third_party/libgcrypt/tests/t-x448.c | 593 + comm/third_party/libgcrypt/tests/testapi.c | 132 + comm/third_party/libgcrypt/tests/testdrv.c | 888 + comm/third_party/libgcrypt/tests/version.c | 165 + comm/third_party/libgpg-error/ABOUT-NLS | 1282 ++ comm/third_party/libgpg-error/AUTHORS | 71 + comm/third_party/libgpg-error/COPYING | 340 + comm/third_party/libgpg-error/COPYING.LIB | 510 + comm/third_party/libgpg-error/ChangeLog | 5386 +++++ comm/third_party/libgpg-error/ChangeLog-2011 | 1211 + comm/third_party/libgpg-error/INSTALL | 236 + comm/third_party/libgpg-error/Makefile.am | 164 + comm/third_party/libgpg-error/Makefile.in | 1024 + comm/third_party/libgpg-error/NEWS | 1125 + comm/third_party/libgpg-error/README | 168 + comm/third_party/libgpg-error/THANKS | 16 + comm/third_party/libgpg-error/VERSION | 1 + comm/third_party/libgpg-error/aclocal.m4 | 1362 ++ comm/third_party/libgpg-error/autogen.rc | 24 + comm/third_party/libgpg-error/autogen.sh | 513 + comm/third_party/libgpg-error/build-aux/compile | 347 + .../libgpg-error/build-aux/config.guess | 1486 ++ .../libgpg-error/build-aux/config.rpath | 684 + comm/third_party/libgpg-error/build-aux/config.sub | 1790 ++ comm/third_party/libgpg-error/build-aux/depcomp | 791 + .../third_party/libgpg-error/build-aux/git-log-fix | 3 + .../libgpg-error/build-aux/git-log-footer | 14 + comm/third_party/libgpg-error/build-aux/install-sh | 527 + comm/third_party/libgpg-error/build-aux/ltmain.sh | 9677 ++++++++ comm/third_party/libgpg-error/build-aux/mdate-sh | 224 + comm/third_party/libgpg-error/build-aux/missing | 215 + .../third_party/libgpg-error/build-aux/texinfo.tex | 8638 +++++++ comm/third_party/libgpg-error/config.h.in | 361 + comm/third_party/libgpg-error/configure | 20556 +++++++++++++++++ comm/third_party/libgpg-error/configure.ac | 760 + .../libgpg-error/contrib/ChangeLog-2011 | 25 + comm/third_party/libgpg-error/doc/HACKING | 81 + comm/third_party/libgpg-error/doc/Makefile.am | 91 + comm/third_party/libgpg-error/doc/Makefile.in | 1171 + comm/third_party/libgpg-error/doc/errorref.txt | 1232 + comm/third_party/libgpg-error/doc/gpgrt.info | 1262 + comm/third_party/libgpg-error/doc/gpgrt.texi | 437 + comm/third_party/libgpg-error/doc/gpl.texi | 392 + comm/third_party/libgpg-error/doc/lgpl.texi | 560 + comm/third_party/libgpg-error/doc/stamp-vti | 4 + comm/third_party/libgpg-error/doc/version.texi | 4 + comm/third_party/libgpg-error/doc/yat2m.c | 1879 ++ comm/third_party/libgpg-error/lang/Makefile.am | 22 + comm/third_party/libgpg-error/lang/Makefile.in | 691 + comm/third_party/libgpg-error/lang/README | 8 + comm/third_party/libgpg-error/lang/cl/Makefile.am | 40 + comm/third_party/libgpg-error/lang/cl/Makefile.in | 610 + comm/third_party/libgpg-error/lang/cl/README | 22 + .../libgpg-error/lang/cl/gpg-error-package.lisp | 64 + .../third_party/libgpg-error/lang/cl/gpg-error.asd | 36 + .../libgpg-error/lang/cl/gpg-error.asd.in | 36 + .../libgpg-error/lang/cl/gpg-error.lisp | 233 + .../libgpg-error/lang/cl/mkerrcodes.awk | 154 + comm/third_party/libgpg-error/libgpg-error.spec | 57 + comm/third_party/libgpg-error/libgpg-error.spec.in | 57 + comm/third_party/libgpg-error/m4/ChangeLog-2011 | 113 + comm/third_party/libgpg-error/m4/Makefile.am | 5 + comm/third_party/libgpg-error/m4/Makefile.in | 498 + comm/third_party/libgpg-error/m4/autobuild.m4 | 34 + .../third_party/libgpg-error/m4/ax_cc_for_build.m4 | 77 + comm/third_party/libgpg-error/m4/codeset.m4 | 21 + comm/third_party/libgpg-error/m4/estream.m4 | 50 + comm/third_party/libgpg-error/m4/gettext.m4 | 401 + comm/third_party/libgpg-error/m4/glibc2.m4 | 30 + comm/third_party/libgpg-error/m4/glibc21.m4 | 30 + comm/third_party/libgpg-error/m4/gnupg-misc.m4 | 35 + comm/third_party/libgpg-error/m4/iconv.m4 | 288 + comm/third_party/libgpg-error/m4/intdiv0.m4 | 70 + comm/third_party/libgpg-error/m4/intmax.m4 | 30 + comm/third_party/libgpg-error/m4/inttypes-h.m4 | 25 + comm/third_party/libgpg-error/m4/inttypes-pri.m4 | 30 + comm/third_party/libgpg-error/m4/inttypes.m4 | 25 + comm/third_party/libgpg-error/m4/inttypes_h.m4 | 26 + comm/third_party/libgpg-error/m4/isc-posix.m4 | 24 + comm/third_party/libgpg-error/m4/lcmessage.m4 | 30 + comm/third_party/libgpg-error/m4/lib-ld.m4 | 119 + comm/third_party/libgpg-error/m4/lib-link.m4 | 777 + comm/third_party/libgpg-error/m4/lib-prefix.m4 | 224 + comm/third_party/libgpg-error/m4/libtool.m4 | 8031 +++++++ comm/third_party/libgpg-error/m4/lock.m4 | 42 + comm/third_party/libgpg-error/m4/longdouble.m4 | 31 + comm/third_party/libgpg-error/m4/longlong.m4 | 23 + comm/third_party/libgpg-error/m4/ltoptions.m4 | 384 + comm/third_party/libgpg-error/m4/ltsugar.m4 | 123 + comm/third_party/libgpg-error/m4/ltversion.m4 | 23 + comm/third_party/libgpg-error/m4/lt~obsolete.m4 | 98 + comm/third_party/libgpg-error/m4/nls.m4 | 32 + comm/third_party/libgpg-error/m4/po.m4 | 453 + comm/third_party/libgpg-error/m4/printf-posix.m4 | 44 + comm/third_party/libgpg-error/m4/progtest.m4 | 91 + comm/third_party/libgpg-error/m4/readline.m4 | 66 + comm/third_party/libgpg-error/m4/signed.m4 | 17 + comm/third_party/libgpg-error/m4/size_max.m4 | 60 + comm/third_party/libgpg-error/m4/stdint_h.m4 | 26 + comm/third_party/libgpg-error/m4/threadlib.m4 | 349 + comm/third_party/libgpg-error/m4/uintmax_t.m4 | 30 + comm/third_party/libgpg-error/m4/ulonglong.m4 | 23 + comm/third_party/libgpg-error/m4/visibility.m4 | 52 + comm/third_party/libgpg-error/m4/wchar_t.m4 | 20 + comm/third_party/libgpg-error/m4/wint_t.m4 | 20 + comm/third_party/libgpg-error/m4/xsize.m4 | 13 + comm/third_party/libgpg-error/mkinstalldirs | 162 + comm/third_party/libgpg-error/po/ChangeLog-2011 | 146 + comm/third_party/libgpg-error/po/LINGUAS | 21 + comm/third_party/libgpg-error/po/Makefile.in.in | 475 + comm/third_party/libgpg-error/po/Makevars | 79 + comm/third_party/libgpg-error/po/POTFILES.in | 15 + comm/third_party/libgpg-error/po/Rules-quot | 58 + comm/third_party/libgpg-error/po/boldquot.sed | 10 + comm/third_party/libgpg-error/po/cs.gmo | Bin 0 -> 22010 bytes comm/third_party/libgpg-error/po/cs.po | 2198 ++ comm/third_party/libgpg-error/po/da.gmo | Bin 0 -> 20822 bytes comm/third_party/libgpg-error/po/da.po | 2194 ++ comm/third_party/libgpg-error/po/de.gmo | Bin 0 -> 35085 bytes comm/third_party/libgpg-error/po/de.po | 2014 ++ .../third_party/libgpg-error/po/en@boldquot.header | 25 + comm/third_party/libgpg-error/po/en@quot.header | 22 + comm/third_party/libgpg-error/po/eo.gmo | Bin 0 -> 16312 bytes comm/third_party/libgpg-error/po/eo.po | 2255 ++ comm/third_party/libgpg-error/po/es.gmo | Bin 0 -> 27013 bytes comm/third_party/libgpg-error/po/es.po | 2017 ++ comm/third_party/libgpg-error/po/fr.gmo | Bin 0 -> 22649 bytes comm/third_party/libgpg-error/po/fr.po | 2188 ++ comm/third_party/libgpg-error/po/hu.gmo | Bin 0 -> 17540 bytes comm/third_party/libgpg-error/po/hu.po | 2253 ++ comm/third_party/libgpg-error/po/insert-header.sin | 23 + comm/third_party/libgpg-error/po/it.gmo | Bin 0 -> 21084 bytes comm/third_party/libgpg-error/po/it.po | 2198 ++ comm/third_party/libgpg-error/po/ja.gmo | Bin 0 -> 38814 bytes comm/third_party/libgpg-error/po/ja.po | 1996 ++ comm/third_party/libgpg-error/po/libgpg-error.pot | 1986 ++ comm/third_party/libgpg-error/po/nl.gmo | Bin 0 -> 20438 bytes comm/third_party/libgpg-error/po/nl.po | 2201 ++ comm/third_party/libgpg-error/po/pl.gmo | Bin 0 -> 34878 bytes comm/third_party/libgpg-error/po/pl.po | 1987 ++ comm/third_party/libgpg-error/po/pt.gmo | Bin 0 -> 21316 bytes comm/third_party/libgpg-error/po/pt.po | 2197 ++ comm/third_party/libgpg-error/po/quot.sed | 6 + .../libgpg-error/po/remove-potcdate.sin | 19 + comm/third_party/libgpg-error/po/ro.gmo | Bin 0 -> 14455 bytes comm/third_party/libgpg-error/po/ro.po | 2246 ++ comm/third_party/libgpg-error/po/ru.gmo | Bin 0 -> 39786 bytes comm/third_party/libgpg-error/po/ru.po | 2016 ++ comm/third_party/libgpg-error/po/sr.gmo | Bin 0 -> 21279 bytes comm/third_party/libgpg-error/po/sr.po | 2256 ++ comm/third_party/libgpg-error/po/stamp-po | 1 + comm/third_party/libgpg-error/po/sv.gmo | Bin 0 -> 17166 bytes comm/third_party/libgpg-error/po/sv.po | 2232 ++ comm/third_party/libgpg-error/po/uk.gmo | Bin 0 -> 45209 bytes comm/third_party/libgpg-error/po/uk.po | 2007 ++ comm/third_party/libgpg-error/po/vi.gmo | Bin 0 -> 18302 bytes comm/third_party/libgpg-error/po/vi.po | 2245 ++ comm/third_party/libgpg-error/po/zh_CN.gmo | Bin 0 -> 31390 bytes comm/third_party/libgpg-error/po/zh_CN.po | 1996 ++ comm/third_party/libgpg-error/po/zh_TW.gmo | Bin 0 -> 31924 bytes comm/third_party/libgpg-error/po/zh_TW.po | 1997 ++ comm/third_party/libgpg-error/potomo | 64 + comm/third_party/libgpg-error/src/Makefile.am | 367 + comm/third_party/libgpg-error/src/Makefile.in | 1784 ++ comm/third_party/libgpg-error/src/README | 47 + comm/third_party/libgpg-error/src/argparse.c | 2852 +++ comm/third_party/libgpg-error/src/b64dec.c | 279 + comm/third_party/libgpg-error/src/b64enc.c | 386 + .../third_party/libgpg-error/src/code-from-errno.c | 69 + comm/third_party/libgpg-error/src/code-to-errno.c | 42 + comm/third_party/libgpg-error/src/err-codes.h | 936 + comm/third_party/libgpg-error/src/err-codes.h.in | 527 + comm/third_party/libgpg-error/src/err-sources.h | 88 + comm/third_party/libgpg-error/src/err-sources.h.in | 61 + comm/third_party/libgpg-error/src/errnos.in | 172 + comm/third_party/libgpg-error/src/estream-printf.c | 1904 ++ comm/third_party/libgpg-error/src/estream-printf.h | 153 + comm/third_party/libgpg-error/src/estream.c | 5414 +++++ comm/third_party/libgpg-error/src/gen-lock-obj.sh | 136 + .../libgpg-error/src/gen-posix-lock-obj.c | 175 + .../libgpg-error/src/gen-w32-lock-obj.c | 55 + comm/third_party/libgpg-error/src/gettext.h | 76 + .../libgpg-error/src/gpg-error-config-test.sh | 98 + .../libgpg-error/src/gpg-error-config-test.sh.in | 98 + .../libgpg-error/src/gpg-error-config.in | 103 + comm/third_party/libgpg-error/src/gpg-error.c | 767 + comm/third_party/libgpg-error/src/gpg-error.def.in | 245 + comm/third_party/libgpg-error/src/gpg-error.h.in | 1378 ++ comm/third_party/libgpg-error/src/gpg-error.m4 | 206 + comm/third_party/libgpg-error/src/gpg-error.pc.in | 15 + comm/third_party/libgpg-error/src/gpg-error.vers | 213 + .../libgpg-error/src/gpg-error.w32-manifest.in | 17 + comm/third_party/libgpg-error/src/gpgrt-config | 646 + comm/third_party/libgpg-error/src/gpgrt-config.in | 646 + comm/third_party/libgpg-error/src/gpgrt-int.h | 844 + comm/third_party/libgpg-error/src/gpgrt.m4 | 112 + comm/third_party/libgpg-error/src/init.c | 741 + comm/third_party/libgpg-error/src/init.h | 70 + comm/third_party/libgpg-error/src/lock.h | 24 + comm/third_party/libgpg-error/src/logging.c | 1341 ++ comm/third_party/libgpg-error/src/mkerrcodes.awk | 99 + comm/third_party/libgpg-error/src/mkerrcodes.c | 78 + comm/third_party/libgpg-error/src/mkerrcodes1.awk | 96 + comm/third_party/libgpg-error/src/mkerrcodes2.awk | 134 + comm/third_party/libgpg-error/src/mkerrnos.awk | 104 + comm/third_party/libgpg-error/src/mkheader.c | 779 + comm/third_party/libgpg-error/src/mkstrtable.awk | 189 + comm/third_party/libgpg-error/src/mkw32errmap.c | 178 + comm/third_party/libgpg-error/src/posix-lock-obj.h | 42 + comm/third_party/libgpg-error/src/posix-lock.c | 263 + comm/third_party/libgpg-error/src/posix-thread.c | 68 + comm/third_party/libgpg-error/src/protos.h | 31 + comm/third_party/libgpg-error/src/spawn-posix.c | 886 + comm/third_party/libgpg-error/src/spawn-w32.c | 920 + comm/third_party/libgpg-error/src/strerror-sym.c | 56 + comm/third_party/libgpg-error/src/strerror.c | 177 + comm/third_party/libgpg-error/src/stringutils.c | 224 + comm/third_party/libgpg-error/src/strsource-sym.c | 43 + comm/third_party/libgpg-error/src/strsource.c | 37 + comm/third_party/libgpg-error/src/syscall-clamp.c | 80 + .../src/syscfg/lock-obj-pub.aarch64-apple-darwin.h | 28 + .../lock-obj-pub.aarch64-unknown-linux-gnu.h | 26 + .../lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h | 24 + .../syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h | 25 + .../src/syscfg/lock-obj-pub.arm-apple-darwin.h | 26 + .../lock-obj-pub.arm-unknown-linux-androideabi.h | 21 + .../lock-obj-pub.arm-unknown-linux-gnueabi.h | 23 + .../syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h | 27 + .../src/syscfg/lock-obj-pub.i386-apple-darwin.h | 26 + .../src/syscfg/lock-obj-pub.i686-unknown-gnu.h | 24 + .../lock-obj-pub.i686-unknown-kfreebsd-gnu.h | 23 + .../syscfg/lock-obj-pub.i686-unknown-linux-gnu.h | 23 + .../syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h | 25 + .../syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h | 23 + .../libgpg-error/src/syscfg/lock-obj-pub.mingw32.h | 44 + .../syscfg/lock-obj-pub.mips-unknown-linux-gnu.h | 23 + .../lock-obj-pub.mips64-unknown-linux-gnuabi64.h | 25 + .../lock-obj-pub.mips64el-unknown-linux-gnuabi64.h | 25 + .../syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h | 23 + .../syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h | 23 + .../syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h | 24 + .../lock-obj-pub.powerpc-unknown-linux-gnu.h | 23 + .../lock-obj-pub.powerpc-unknown-linux-gnuspe.h | 23 + .../lock-obj-pub.powerpc64-unknown-linux-gnu.h | 25 + .../lock-obj-pub.powerpc64le-unknown-linux-gnu.h | 25 + .../lock-obj-pub.riscv32-unknown-linux-gnu.h | 23 + .../lock-obj-pub.riscv64-unknown-linux-gnu.h | 25 + .../syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h | 25 + .../syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h | 23 + .../syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h | 23 + .../syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h | 23 + .../lock-obj-pub.sparc64-unknown-linux-gnu.h | 25 + .../syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h | 25 + .../src/syscfg/lock-obj-pub.x86_64-apple-darwin.h | 28 + .../lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h | 25 + .../syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h | 25 + .../lock-obj-pub.x86_64-unknown-linux-gnux32.h | 24 + .../lock-obj-pub.x86_64-unknown-linux-musl.h | 25 + comm/third_party/libgpg-error/src/sysutils.c | 524 + comm/third_party/libgpg-error/src/thread.h | 24 + comm/third_party/libgpg-error/src/version.c | 246 + .../third_party/libgpg-error/src/versioninfo.rc.in | 54 + comm/third_party/libgpg-error/src/visibility.c | 1250 + comm/third_party/libgpg-error/src/visibility.h | 419 + comm/third_party/libgpg-error/src/w32-add.h | 67 + comm/third_party/libgpg-error/src/w32-estream.c | 1078 + comm/third_party/libgpg-error/src/w32-gettext.c | 2016 ++ comm/third_party/libgpg-error/src/w32-iconv.c | 1795 ++ comm/third_party/libgpg-error/src/w32-lock-obj.h | 38 + comm/third_party/libgpg-error/src/w32-lock.c | 161 + comm/third_party/libgpg-error/src/w32-reg.c | 154 + comm/third_party/libgpg-error/src/w32-thread.c | 46 + comm/third_party/libgpg-error/src/w32ce-add.h | 8 + comm/third_party/libgpg-error/tests/Makefile.am | 44 + comm/third_party/libgpg-error/tests/Makefile.in | 920 + .../libgpg-error/tests/etc/t-argparse.conf | 80 + comm/third_party/libgpg-error/tests/t-argparse.c | 168 + .../third_party/libgpg-error/tests/t-argparse.conf | 16 + comm/third_party/libgpg-error/tests/t-b64.c | 374 + comm/third_party/libgpg-error/tests/t-common.h | 136 + comm/third_party/libgpg-error/tests/t-lock.c | 333 + comm/third_party/libgpg-error/tests/t-logging.c | 250 + comm/third_party/libgpg-error/tests/t-malloc.c | 141 + comm/third_party/libgpg-error/tests/t-poll.c | 440 + comm/third_party/libgpg-error/tests/t-printf.c | 544 + comm/third_party/libgpg-error/tests/t-strerror.c | 63 + .../third_party/libgpg-error/tests/t-stringutils.c | 395 + comm/third_party/libgpg-error/tests/t-syserror.c | 87 + comm/third_party/libgpg-error/tests/t-version.c | 178 + comm/third_party/libotr/AUTHORS | 9 + comm/third_party/libotr/COPYING | 340 + comm/third_party/libotr/COPYING.LIB | 504 + comm/third_party/libotr/ChangeLog | 1026 + comm/third_party/libotr/INSTALL | 45 + comm/third_party/libotr/Makefile.am | 14 + comm/third_party/libotr/Makefile.in | 894 + comm/third_party/libotr/NEWS | 273 + comm/third_party/libotr/Protocol-v3.html | 1710 ++ comm/third_party/libotr/README | 382 + comm/third_party/libotr/UPGRADING | 515 + comm/third_party/libotr/aclocal.m4 | 1307 ++ comm/third_party/libotr/bootstrap | 9 + comm/third_party/libotr/config.guess | 1558 ++ comm/third_party/libotr/config.h.in | 62 + comm/third_party/libotr/config.sub | 1791 ++ comm/third_party/libotr/config/compile | 347 + comm/third_party/libotr/config/config.guess | 1530 ++ comm/third_party/libotr/config/config.sub | 1773 ++ comm/third_party/libotr/config/depcomp | 688 + comm/third_party/libotr/config/install-sh | 520 + comm/third_party/libotr/config/libtool.m4 | 8001 +++++++ comm/third_party/libotr/config/ltmain.sh | 9661 ++++++++ comm/third_party/libotr/config/ltoptions.m4 | 384 + comm/third_party/libotr/config/ltsugar.m4 | 123 + comm/third_party/libotr/config/ltversion.m4 | 23 + comm/third_party/libotr/config/lt~obsolete.m4 | 98 + comm/third_party/libotr/config/missing | 331 + comm/third_party/libotr/configure | 17285 ++++++++++++++ comm/third_party/libotr/configure.ac | 191 + comm/third_party/libotr/install-sh | 527 + comm/third_party/libotr/libotr.m4 | 134 + comm/third_party/libotr/libotr.pc.in | 11 + comm/third_party/libotr/ltmain.sh | 9661 ++++++++ .../libotr/packaging/fedora/libotr.spec | 173 + comm/third_party/libotr/src/Makefile.am | 14 + comm/third_party/libotr/src/Makefile.in | 680 + comm/third_party/libotr/src/auth.c | 1573 ++ comm/third_party/libotr/src/auth.h | 177 + comm/third_party/libotr/src/b64.c | 267 + comm/third_party/libotr/src/b64.h | 72 + comm/third_party/libotr/src/context.c | 547 + comm/third_party/libotr/src/context.h | 193 + comm/third_party/libotr/src/context_priv.c | 95 + comm/third_party/libotr/src/context_priv.h | 94 + comm/third_party/libotr/src/dh.c | 476 + comm/third_party/libotr/src/dh.h | 123 + comm/third_party/libotr/src/instag.c | 277 + comm/third_party/libotr/src/instag.h | 89 + comm/third_party/libotr/src/mem.c | 180 + comm/third_party/libotr/src/mem.h | 35 + comm/third_party/libotr/src/message.c | 2058 ++ comm/third_party/libotr/src/message.h | 440 + comm/third_party/libotr/src/privkey-t.h | 50 + comm/third_party/libotr/src/privkey.c | 938 + comm/third_party/libotr/src/privkey.h | 154 + comm/third_party/libotr/src/proto.c | 1081 + comm/third_party/libotr/src/proto.h | 174 + comm/third_party/libotr/src/serial.h | 107 + comm/third_party/libotr/src/sm.c | 998 + comm/third_party/libotr/src/sm.h | 84 + comm/third_party/libotr/src/tlv.c | 109 + comm/third_party/libotr/src/tlv.h | 78 + comm/third_party/libotr/src/userstate.c | 57 + comm/third_party/libotr/src/userstate.h | 51 + comm/third_party/libotr/src/version.h | 31 + comm/third_party/libotr/tests/Makefile.am | 11 + comm/third_party/libotr/tests/Makefile.in | 617 + .../libotr/tests/regression/Makefile.am | 5 + .../libotr/tests/regression/Makefile.in | 611 + .../libotr/tests/regression/client/Makefile.am | 16 + .../libotr/tests/regression/client/Makefile.in | 584 + .../libotr/tests/regression/client/client.c | 1158 + .../libotr/tests/regression/client/otr.key | 41 + .../libotr/tests/regression/random-msg-auth.sh | 14 + .../tests/regression/random-msg-disconnect-auth.sh | 14 + .../regression/random-msg-disconnect-frag-auth.sh | 14 + .../tests/regression/random-msg-disconnect-frag.sh | 14 + .../tests/regression/random-msg-disconnect.sh | 14 + .../libotr/tests/regression/random-msg-fast.sh | 14 + .../libotr/tests/regression/random-msg-frag.sh | 14 + .../libotr/tests/regression/random-msg.sh | 14 + comm/third_party/libotr/tests/run.sh | 26 + comm/third_party/libotr/tests/test_list | 19 + comm/third_party/libotr/tests/unit/Makefile.am | 50 + comm/third_party/libotr/tests/unit/Makefile.in | 697 + comm/third_party/libotr/tests/unit/instag.txt | 4 + comm/third_party/libotr/tests/unit/test_auth.c | 181 + comm/third_party/libotr/tests/unit/test_b64.c | 114 + comm/third_party/libotr/tests/unit/test_context.c | 214 + comm/third_party/libotr/tests/unit/test_dh.c | 515 + comm/third_party/libotr/tests/unit/test_instag.c | 222 + comm/third_party/libotr/tests/unit/test_mem.c | 58 + comm/third_party/libotr/tests/unit/test_privkey.c | 264 + comm/third_party/libotr/tests/unit/test_proto.c | 371 + comm/third_party/libotr/tests/unit/test_sm.c | 343 + comm/third_party/libotr/tests/unit/test_tlv.c | 163 + .../third_party/libotr/tests/unit/test_userstate.c | 52 + comm/third_party/libotr/tests/utils/Makefile.am | 3 + comm/third_party/libotr/tests/utils/Makefile.in | 608 + .../third_party/libotr/tests/utils/tap/Makefile.am | 7 + .../third_party/libotr/tests/utils/tap/Makefile.in | 581 + comm/third_party/libotr/tests/utils/tap/tap.c | 433 + comm/third_party/libotr/tests/utils/tap/tap.h | 89 + comm/third_party/libotr/tests/utils/tap/tap.sh | 456 + comm/third_party/libotr/tests/utils/utils.c | 18 + comm/third_party/libotr/tests/utils/utils.h | 29 + comm/third_party/libotr/toolkit/Makefile.am | 44 + comm/third_party/libotr/toolkit/Makefile.in | 787 + comm/third_party/libotr/toolkit/aes.c | 866 + comm/third_party/libotr/toolkit/aes.h | 26 + comm/third_party/libotr/toolkit/ctrmode.c | 60 + comm/third_party/libotr/toolkit/ctrmode.h | 29 + comm/third_party/libotr/toolkit/otr_mackey.c | 65 + comm/third_party/libotr/toolkit/otr_modify.c | 126 + comm/third_party/libotr/toolkit/otr_parse.c | 224 + comm/third_party/libotr/toolkit/otr_readforge.c | 133 + comm/third_party/libotr/toolkit/otr_remac.c | 143 + comm/third_party/libotr/toolkit/otr_sesskeys.c | 92 + comm/third_party/libotr/toolkit/otr_toolkit.1 | 110 + comm/third_party/libotr/toolkit/parse.c | 654 + comm/third_party/libotr/toolkit/parse.h | 163 + comm/third_party/libotr/toolkit/readotr.c | 91 + comm/third_party/libotr/toolkit/readotr.h | 29 + comm/third_party/libotr/toolkit/sesskeys.c | 98 + comm/third_party/libotr/toolkit/sesskeys.h | 34 + comm/third_party/libotr/toolkit/sha1hmac.c | 61 + comm/third_party/libotr/toolkit/sha1hmac.h | 29 + comm/third_party/moz.build | 24 + comm/third_party/niwcompat/dirent.h | 1166 + comm/third_party/niwcompat/extra_include.h | 1 + comm/third_party/niwcompat/getopt.c | 231 + comm/third_party/niwcompat/getopt.h | 33 + comm/third_party/openpgp.configure | 374 + .../rnp/bug1843535_gcc13_missing_header.patch | 27 + comm/third_party/python/fluent.migratetb/LICENSE | 13 + comm/third_party/python/fluent.migratetb/PKG-INFO | 61 + comm/third_party/python/fluent.migratetb/README.md | 44 + .../fluent.migratetb.egg-info/PKG-INFO | 61 + .../fluent.migratetb.egg-info/SOURCES.txt | 24 + .../fluent.migratetb.egg-info/dependency_links.txt | 1 + .../fluent.migratetb.egg-info/entry_points.txt | 3 + .../fluent.migratetb.egg-info/requires.txt | 6 + .../fluent.migratetb.egg-info/top_level.txt | 1 + .../python/fluent.migratetb/fluent/__init__.py | 1 + .../fluent.migratetb/fluent/migratetb/__init__.py | 5 + .../fluent.migratetb/fluent/migratetb/_context.py | 333 + .../fluent.migratetb/fluent/migratetb/blame.py | 102 + .../fluent/migratetb/changesets.py | 59 + .../fluent.migratetb/fluent/migratetb/context.py | 152 + .../fluent.migratetb/fluent/migratetb/errors.py | 22 + .../fluent.migratetb/fluent/migratetb/evaluator.py | 28 + .../fluent.migratetb/fluent/migratetb/helpers.py | 176 + .../fluent.migratetb/fluent/migratetb/merge.py | 59 + .../fluent.migratetb/fluent/migratetb/tool.py | 185 + .../fluent/migratetb/transforms.py | 580 + .../fluent.migratetb/fluent/migratetb/util.py | 114 + .../fluent.migratetb/fluent/migratetb/validator.py | 339 + comm/third_party/python/fluent.migratetb/setup.cfg | 16 + comm/third_party/python/fluent.migratetb/setup.py | 33 + comm/third_party/rnp/CHANGELOG.md | 436 + comm/third_party/rnp/LICENSE-OCB.md | 93 + comm/third_party/rnp/LICENSE.md | 178 + comm/third_party/rnp/README.adoc | 69 + comm/third_party/rnp/doc/tests/README.md | 72 + .../rnp/doc/tests/rnpkeys-generate-key.md | 192 + comm/third_party/rnp/docs/c-usage.adoc | 129 + comm/third_party/rnp/docs/cli-usage.adoc | 174 + comm/third_party/rnp/docs/code-of-conduct.adoc | 128 + comm/third_party/rnp/docs/develop.adoc | 435 + comm/third_party/rnp/docs/develop/cpp-usage.adoc | 49 + comm/third_party/rnp/docs/develop/packaging.adoc | 78 + .../rnp/docs/develop/release-workflow.adoc | 122 + comm/third_party/rnp/docs/installation.adoc | 262 + comm/third_party/rnp/docs/navigation.adoc | 18 + comm/third_party/rnp/docs/signing-keys.adoc | 5 + comm/third_party/rnp/include/rekey/rnp_key_store.h | 149 + comm/third_party/rnp/include/repgp/repgp_def.h | 505 + comm/third_party/rnp/include/rnp.h | 42 + comm/third_party/rnp/include/rnp/rnp.h | 3150 +++ comm/third_party/rnp/include/rnp/rnp_def.h | 35 + comm/third_party/rnp/include/rnp/rnp_err.h | 77 + comm/third_party/rnp/module.ver | 8 + comm/third_party/rnp/moz.build | 227 + comm/third_party/rnp/moz.yaml | 76 + comm/third_party/rnp/rnp.symbols | 240 + comm/third_party/rnp/src/common/CMakeLists.txt | 64 + comm/third_party/rnp/src/common/file-utils.cpp | 359 + comm/third_party/rnp/src/common/file-utils.h | 89 + comm/third_party/rnp/src/common/getoptwin.h | 34 + comm/third_party/rnp/src/common/str-utils.cpp | 217 + comm/third_party/rnp/src/common/str-utils.h | 63 + comm/third_party/rnp/src/common/time-utils.cpp | 96 + comm/third_party/rnp/src/common/time-utils.h | 38 + comm/third_party/rnp/src/common/uniwin.h | 60 + comm/third_party/rnp/src/examples/CMakeLists.txt | 140 + comm/third_party/rnp/src/examples/README.md | 5 + comm/third_party/rnp/src/examples/decrypt.c | 138 + comm/third_party/rnp/src/examples/dump.c | 163 + comm/third_party/rnp/src/examples/encrypt.c | 133 + comm/third_party/rnp/src/examples/generate.c | 330 + comm/third_party/rnp/src/examples/sign.c | 168 + comm/third_party/rnp/src/examples/verify.c | 165 + comm/third_party/rnp/src/fuzzing/CMakeLists.txt | 145 + comm/third_party/rnp/src/fuzzing/dump.c | 54 + comm/third_party/rnp/src/fuzzing/keyimport.c | 97 + comm/third_party/rnp/src/fuzzing/keyring.c | 52 + comm/third_party/rnp/src/fuzzing/keyring_g10.cpp | 51 + comm/third_party/rnp/src/fuzzing/keyring_kbx.c | 50 + comm/third_party/rnp/src/fuzzing/sigimport.c | 51 + comm/third_party/rnp/src/fuzzing/verify.c | 58 + comm/third_party/rnp/src/fuzzing/verify_detached.c | 59 + comm/third_party/rnp/src/lib/CMakeLists.txt | 594 + comm/third_party/rnp/src/lib/config.h.in | 72 + comm/third_party/rnp/src/lib/crypto.cpp | 244 + comm/third_party/rnp/src/lib/crypto.h | 118 + .../rnp/src/lib/crypto/backend_version.cpp | 184 + .../rnp/src/lib/crypto/backend_version.h | 44 + comm/third_party/rnp/src/lib/crypto/bn.cpp | 107 + comm/third_party/rnp/src/lib/crypto/bn.h | 64 + comm/third_party/rnp/src/lib/crypto/bn_ossl.cpp | 84 + comm/third_party/rnp/src/lib/crypto/cipher.cpp | 78 + comm/third_party/rnp/src/lib/crypto/cipher.hpp | 77 + .../rnp/src/lib/crypto/cipher_botan.cpp | 245 + .../rnp/src/lib/crypto/cipher_botan.hpp | 73 + .../third_party/rnp/src/lib/crypto/cipher_ossl.cpp | 284 + .../third_party/rnp/src/lib/crypto/cipher_ossl.hpp | 80 + comm/third_party/rnp/src/lib/crypto/common.h | 51 + comm/third_party/rnp/src/lib/crypto/dl_ossl.cpp | 200 + comm/third_party/rnp/src/lib/crypto/dl_ossl.h | 44 + comm/third_party/rnp/src/lib/crypto/dsa.cpp | 382 + comm/third_party/rnp/src/lib/crypto/dsa.h | 141 + comm/third_party/rnp/src/lib/crypto/dsa_ossl.cpp | 355 + comm/third_party/rnp/src/lib/crypto/ec.cpp | 187 + comm/third_party/rnp/src/lib/crypto/ec.h | 173 + comm/third_party/rnp/src/lib/crypto/ec_curves.cpp | 323 + comm/third_party/rnp/src/lib/crypto/ec_ossl.cpp | 349 + comm/third_party/rnp/src/lib/crypto/ec_ossl.h | 42 + comm/third_party/rnp/src/lib/crypto/ecdh.cpp | 377 + comm/third_party/rnp/src/lib/crypto/ecdh.h | 117 + comm/third_party/rnp/src/lib/crypto/ecdh_ossl.cpp | 389 + comm/third_party/rnp/src/lib/crypto/ecdh_utils.cpp | 166 + comm/third_party/rnp/src/lib/crypto/ecdh_utils.h | 47 + comm/third_party/rnp/src/lib/crypto/ecdsa.cpp | 267 + comm/third_party/rnp/src/lib/crypto/ecdsa.h | 57 + comm/third_party/rnp/src/lib/crypto/ecdsa_ossl.cpp | 190 + comm/third_party/rnp/src/lib/crypto/eddsa.cpp | 212 + comm/third_party/rnp/src/lib/crypto/eddsa.h | 54 + comm/third_party/rnp/src/lib/crypto/eddsa_ossl.cpp | 156 + comm/third_party/rnp/src/lib/crypto/elgamal.cpp | 302 + comm/third_party/rnp/src/lib/crypto/elgamal.h | 116 + .../rnp/src/lib/crypto/elgamal_ossl.cpp | 418 + comm/third_party/rnp/src/lib/crypto/hash.cpp | 160 + comm/third_party/rnp/src/lib/crypto/hash.hpp | 98 + comm/third_party/rnp/src/lib/crypto/hash_botan.hpp | 68 + .../third_party/rnp/src/lib/crypto/hash_common.cpp | 194 + comm/third_party/rnp/src/lib/crypto/hash_crc24.cpp | 288 + comm/third_party/rnp/src/lib/crypto/hash_crc24.hpp | 47 + comm/third_party/rnp/src/lib/crypto/hash_ossl.cpp | 152 + comm/third_party/rnp/src/lib/crypto/hash_ossl.hpp | 55 + .../third_party/rnp/src/lib/crypto/hash_sha1cd.cpp | 94 + .../third_party/rnp/src/lib/crypto/hash_sha1cd.hpp | 52 + comm/third_party/rnp/src/lib/crypto/mem.cpp | 68 + comm/third_party/rnp/src/lib/crypto/mem.h | 158 + comm/third_party/rnp/src/lib/crypto/mem_ossl.cpp | 113 + comm/third_party/rnp/src/lib/crypto/mpi.cpp | 119 + comm/third_party/rnp/src/lib/crypto/mpi.h | 58 + comm/third_party/rnp/src/lib/crypto/ossl_common.h | 40 + comm/third_party/rnp/src/lib/crypto/rng.cpp | 59 + comm/third_party/rnp/src/lib/crypto/rng.h | 78 + comm/third_party/rnp/src/lib/crypto/rng_ossl.cpp | 48 + comm/third_party/rnp/src/lib/crypto/rsa.cpp | 419 + comm/third_party/rnp/src/lib/crypto/rsa.h | 90 + comm/third_party/rnp/src/lib/crypto/rsa_ossl.cpp | 629 + comm/third_party/rnp/src/lib/crypto/s2k.cpp | 203 + comm/third_party/rnp/src/lib/crypto/s2k.h | 65 + comm/third_party/rnp/src/lib/crypto/s2k_ossl.cpp | 97 + comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.c | 2162 ++ comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.h | 122 + .../rnp/src/lib/crypto/sha1cd/ubc_check.c | 908 + .../rnp/src/lib/crypto/sha1cd/ubc_check.h | 62 + comm/third_party/rnp/src/lib/crypto/signatures.cpp | 281 + comm/third_party/rnp/src/lib/crypto/signatures.h | 69 + comm/third_party/rnp/src/lib/crypto/sm2.cpp | 383 + comm/third_party/rnp/src/lib/crypto/sm2.h | 79 + comm/third_party/rnp/src/lib/crypto/sm2_ossl.cpp | 76 + comm/third_party/rnp/src/lib/crypto/symmetric.cpp | 648 + comm/third_party/rnp/src/lib/crypto/symmetric.h | 252 + .../rnp/src/lib/crypto/symmetric_ossl.cpp | 644 + comm/third_party/rnp/src/lib/defaults.h | 86 + comm/third_party/rnp/src/lib/ffi-priv-types.h | 240 + comm/third_party/rnp/src/lib/fingerprint.cpp | 117 + comm/third_party/rnp/src/lib/fingerprint.h | 39 + comm/third_party/rnp/src/lib/generate-key.cpp | 467 + comm/third_party/rnp/src/lib/json-utils.cpp | 103 + comm/third_party/rnp/src/lib/json-utils.h | 91 + comm/third_party/rnp/src/lib/key-provider.cpp | 117 + comm/third_party/rnp/src/lib/key-provider.h | 120 + comm/third_party/rnp/src/lib/librnp.3.adoc | 89 + comm/third_party/rnp/src/lib/librnp.symbols | 1 + comm/third_party/rnp/src/lib/librnp.vsc | 4 + comm/third_party/rnp/src/lib/logging.cpp | 75 + comm/third_party/rnp/src/lib/logging.h | 97 + comm/third_party/rnp/src/lib/pass-provider.cpp | 56 + comm/third_party/rnp/src/lib/pass-provider.h | 61 + comm/third_party/rnp/src/lib/pgp-key.cpp | 2776 +++ comm/third_party/rnp/src/lib/pgp-key.h | 671 + comm/third_party/rnp/src/lib/rnp.cpp | 8403 +++++++ comm/third_party/rnp/src/lib/rnp/rnp_export.h | 42 + comm/third_party/rnp/src/lib/sec_profile.cpp | 228 + comm/third_party/rnp/src/lib/sec_profile.hpp | 112 + comm/third_party/rnp/src/lib/types.h | 482 + comm/third_party/rnp/src/lib/utils.cpp | 80 + comm/third_party/rnp/src/lib/utils.h | 101 + comm/third_party/rnp/src/lib/version.h.in | 52 + comm/third_party/rnp/src/librekey/g23_sexp.hpp | 71 + comm/third_party/rnp/src/librekey/kbx_blob.hpp | 162 + .../third_party/rnp/src/librekey/key_store_g10.cpp | 1243 + comm/third_party/rnp/src/librekey/key_store_g10.h | 42 + .../third_party/rnp/src/librekey/key_store_kbx.cpp | 706 + comm/third_party/rnp/src/librekey/key_store_kbx.h | 36 + .../third_party/rnp/src/librekey/key_store_pgp.cpp | 241 + comm/third_party/rnp/src/librekey/key_store_pgp.h | 83 + .../third_party/rnp/src/librekey/rnp_key_store.cpp | 803 + comm/third_party/rnp/src/librepgp/stream-armor.cpp | 1287 ++ comm/third_party/rnp/src/librepgp/stream-armor.h | 174 + .../third_party/rnp/src/librepgp/stream-common.cpp | 1212 + comm/third_party/rnp/src/librepgp/stream-common.h | 556 + comm/third_party/rnp/src/librepgp/stream-ctx.cpp | 69 + comm/third_party/rnp/src/librepgp/stream-ctx.h | 123 + comm/third_party/rnp/src/librepgp/stream-def.h | 67 + comm/third_party/rnp/src/librepgp/stream-dump.cpp | 2533 ++ comm/third_party/rnp/src/librepgp/stream-dump.h | 53 + comm/third_party/rnp/src/librepgp/stream-key.cpp | 1469 ++ comm/third_party/rnp/src/librepgp/stream-key.h | 143 + .../third_party/rnp/src/librepgp/stream-packet.cpp | 1228 + comm/third_party/rnp/src/librepgp/stream-packet.h | 323 + comm/third_party/rnp/src/librepgp/stream-parse.cpp | 2636 +++ comm/third_party/rnp/src/librepgp/stream-parse.h | 123 + comm/third_party/rnp/src/librepgp/stream-sig.cpp | 1557 ++ comm/third_party/rnp/src/librepgp/stream-sig.h | 437 + comm/third_party/rnp/src/librepgp/stream-write.cpp | 1973 ++ comm/third_party/rnp/src/librepgp/stream-write.h | 83 + comm/third_party/rnp/src/libsexp/LICENSE.md | 34 + comm/third_party/rnp/src/libsexp/README.adoc | 195 + .../rnp/src/libsexp/include/sexp/ext-key-format.h | 99 + .../rnp/src/libsexp/include/sexp/sexp-error.h | 77 + .../rnp/src/libsexp/include/sexp/sexp.h | 435 + .../rnp/src/libsexp/src/ext-key-format.cpp | 314 + .../rnp/src/libsexp/src/sexp-char-defs.cpp | 351 + .../third_party/rnp/src/libsexp/src/sexp-error.cpp | 62 + .../third_party/rnp/src/libsexp/src/sexp-input.cpp | 507 + comm/third_party/rnp/src/libsexp/src/sexp-main.cpp | 237 + .../rnp/src/libsexp/src/sexp-object.cpp | 194 + .../rnp/src/libsexp/src/sexp-output.cpp | 208 + .../rnp/src/libsexp/src/sexp-simple-string.cpp | 197 + comm/third_party/rnp/src/libsexp/version.txt | 1 + comm/third_party/rnp/src/rnp/CMakeLists.txt | 100 + comm/third_party/rnp/src/rnp/fficli.cpp | 3229 +++ comm/third_party/rnp/src/rnp/fficli.h | 295 + comm/third_party/rnp/src/rnp/moz.build | 64 + comm/third_party/rnp/src/rnp/rnp.1.adoc | 431 + comm/third_party/rnp/src/rnp/rnp.cpp | 695 + comm/third_party/rnp/src/rnp/rnpcfg.cpp | 572 + comm/third_party/rnp/src/rnp/rnpcfg.h | 219 + comm/third_party/rnp/src/rnpkeys/CMakeLists.txt | 101 + comm/third_party/rnp/src/rnpkeys/main.cpp | 136 + comm/third_party/rnp/src/rnpkeys/moz.build | 64 + comm/third_party/rnp/src/rnpkeys/rnpkeys.1.adoc | 453 + comm/third_party/rnp/src/rnpkeys/rnpkeys.cpp | 648 + comm/third_party/rnp/src/rnpkeys/rnpkeys.h | 80 + comm/third_party/rnp/src/rnpkeys/tui.cpp | 413 + comm/third_party/rnp/version.txt | 1 + comm/third_party/rnpdefs.mozbuild | 38 + comm/third_party/zlib/ChangeLog | 1590 ++ comm/third_party/zlib/FAQ | 368 + comm/third_party/zlib/INDEX | 68 + comm/third_party/zlib/LICENSE | 22 + comm/third_party/zlib/README | 118 + comm/third_party/zlib/adler32.c | 186 + comm/third_party/zlib/compress.c | 86 + comm/third_party/zlib/crc32.c | 1125 + comm/third_party/zlib/crc32.h | 9446 ++++++++ comm/third_party/zlib/deflate.c | 2217 ++ comm/third_party/zlib/deflate.h | 346 + comm/third_party/zlib/gzclose.c | 25 + comm/third_party/zlib/gzguts.h | 219 + comm/third_party/zlib/gzlib.c | 639 + comm/third_party/zlib/gzread.c | 650 + comm/third_party/zlib/gzwrite.c | 677 + comm/third_party/zlib/infback.c | 644 + comm/third_party/zlib/inffast.c | 323 + comm/third_party/zlib/inffast.h | 11 + comm/third_party/zlib/inffixed.h | 94 + comm/third_party/zlib/inflate.c | 1595 ++ comm/third_party/zlib/inflate.h | 126 + comm/third_party/zlib/inftrees.c | 304 + comm/third_party/zlib/inftrees.h | 62 + comm/third_party/zlib/moz.build | 36 + comm/third_party/zlib/moz.yaml | 73 + comm/third_party/zlib/trees.c | 1181 + comm/third_party/zlib/trees.h | 128 + comm/third_party/zlib/uncompr.c | 93 + comm/third_party/zlib/zconf.h | 547 + comm/third_party/zlib/zlib.h | 1935 ++ comm/third_party/zlib/zutil.c | 327 + comm/third_party/zlib/zutil.h | 275 + 2703 files changed, 966146 insertions(+) create mode 100644 comm/third_party/Makefile.in create mode 100644 comm/third_party/README.asn1js create mode 100644 comm/third_party/README.botan create mode 100644 comm/third_party/README.bzip2 create mode 100644 comm/third_party/README.json-c create mode 100644 comm/third_party/README.libgcrypt create mode 100644 comm/third_party/README.libgpg-error create mode 100644 comm/third_party/README.libotr create mode 100644 comm/third_party/README.niwcompat create mode 100644 comm/third_party/README.rnp create mode 100644 comm/third_party/README.zlib create mode 100644 comm/third_party/asn1js/LICENSE create mode 100644 comm/third_party/asn1js/asn1js.mjs create mode 100755 comm/third_party/asn1js/make_bundle.sh create mode 100644 comm/third_party/asn1js/moz.build create mode 100644 comm/third_party/asn1js/moz.yaml create mode 100644 comm/third_party/asn1js/package.json create mode 100644 comm/third_party/asn1js/src/Any.ts create mode 100644 comm/third_party/asn1js/src/BaseBlock.ts create mode 100644 comm/third_party/asn1js/src/BaseStringBlock.ts create mode 100644 comm/third_party/asn1js/src/BitString.ts create mode 100644 comm/third_party/asn1js/src/BmpString.ts create mode 100644 comm/third_party/asn1js/src/Boolean.ts create mode 100644 comm/third_party/asn1js/src/CharacterString.ts create mode 100644 comm/third_party/asn1js/src/Choice.ts create mode 100644 comm/third_party/asn1js/src/Constructed.ts create mode 100644 comm/third_party/asn1js/src/DATE.ts create mode 100644 comm/third_party/asn1js/src/DateTime.ts create mode 100644 comm/third_party/asn1js/src/Duration.ts create mode 100644 comm/third_party/asn1js/src/EndOfContent.ts create mode 100644 comm/third_party/asn1js/src/Enumerated.ts create mode 100644 comm/third_party/asn1js/src/GeneralString.ts create mode 100644 comm/third_party/asn1js/src/GeneralizedTime.ts create mode 100644 comm/third_party/asn1js/src/GraphicString.ts create mode 100644 comm/third_party/asn1js/src/HexBlock.ts create mode 100644 comm/third_party/asn1js/src/IA5String.ts create mode 100644 comm/third_party/asn1js/src/Integer.ts create mode 100644 comm/third_party/asn1js/src/Null.ts create mode 100644 comm/third_party/asn1js/src/NumericString.ts create mode 100644 comm/third_party/asn1js/src/ObjectIdentifier.ts create mode 100644 comm/third_party/asn1js/src/OctetString.ts create mode 100644 comm/third_party/asn1js/src/Primitive.ts create mode 100644 comm/third_party/asn1js/src/PrintableString.ts create mode 100644 comm/third_party/asn1js/src/RawData.ts create mode 100644 comm/third_party/asn1js/src/RelativeObjectIdentifier.ts create mode 100644 comm/third_party/asn1js/src/Repeated.ts create mode 100644 comm/third_party/asn1js/src/Sequence.ts create mode 100644 comm/third_party/asn1js/src/Set.ts create mode 100644 comm/third_party/asn1js/src/TIME.ts create mode 100644 comm/third_party/asn1js/src/TeletexString.ts create mode 100644 comm/third_party/asn1js/src/TimeOfDay.ts create mode 100644 comm/third_party/asn1js/src/TypeStore.ts create mode 100644 comm/third_party/asn1js/src/UTCTime.ts create mode 100644 comm/third_party/asn1js/src/UniversalString.ts create mode 100644 comm/third_party/asn1js/src/Utf8String.ts create mode 100644 comm/third_party/asn1js/src/ValueBlock.ts create mode 100644 comm/third_party/asn1js/src/VideotexString.ts create mode 100644 comm/third_party/asn1js/src/ViewWriter.ts create mode 100644 comm/third_party/asn1js/src/VisibleString.ts create mode 100644 comm/third_party/asn1js/src/index.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalBaseBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalBitStringValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalBmpStringValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalBooleanValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalConstructedValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalEndOfContentValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalIntegerValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalLengthBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalObjectIdentifierValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalOctetStringValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalPrimitiveValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalRelativeObjectIdentifierValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalRelativeSidValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalSidValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalSimpleStringBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalSimpleStringValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalStringValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalUniversalStringValueBlockParams.ts create mode 100644 comm/third_party/asn1js/src/internals/LocalUtf8StringValueBlock.ts create mode 100644 comm/third_party/asn1js/src/internals/constants.ts create mode 100644 comm/third_party/asn1js/src/internals/utils.ts create mode 100644 comm/third_party/asn1js/src/parser.ts create mode 100644 comm/third_party/asn1js/src/schema.ts create mode 100644 comm/third_party/asn1js/src/types.ts create mode 100644 comm/third_party/asn1js/tsconfig.json create mode 100644 comm/third_party/asn1js/yarn.lock create mode 100644 comm/third_party/botan/Makefile.in create mode 100644 comm/third_party/botan/botan.mozbuild create mode 100755 comm/third_party/botan/botan_configure.py create mode 100755 comm/third_party/botan/configure.py create mode 100644 comm/third_party/botan/doc/abi.rst create mode 100644 comm/third_party/botan/doc/api_ref/bigint.rst create mode 100644 comm/third_party/botan/doc/api_ref/block_cipher.rst create mode 100644 comm/third_party/botan/doc/api_ref/cipher_modes.rst create mode 100644 comm/third_party/botan/doc/api_ref/compression.rst create mode 100644 comm/third_party/botan/doc/api_ref/contents.rst create mode 100644 comm/third_party/botan/doc/api_ref/credentials_manager.rst create mode 100644 comm/third_party/botan/doc/api_ref/cryptobox.rst create mode 100644 comm/third_party/botan/doc/api_ref/ecc.rst create mode 100644 comm/third_party/botan/doc/api_ref/env_vars.rst create mode 100644 comm/third_party/botan/doc/api_ref/ffi.rst create mode 100644 comm/third_party/botan/doc/api_ref/filters.rst create mode 100644 comm/third_party/botan/doc/api_ref/fpe.rst create mode 100644 comm/third_party/botan/doc/api_ref/hash.rst create mode 100644 comm/third_party/botan/doc/api_ref/kdf.rst create mode 100644 comm/third_party/botan/doc/api_ref/keywrap.rst create mode 100644 comm/third_party/botan/doc/api_ref/message_auth_codes.rst create mode 100644 comm/third_party/botan/doc/api_ref/otp.rst create mode 100644 comm/third_party/botan/doc/api_ref/passhash.rst create mode 100644 comm/third_party/botan/doc/api_ref/pbkdf.rst create mode 100644 comm/third_party/botan/doc/api_ref/pkcs11.rst create mode 100644 comm/third_party/botan/doc/api_ref/psk_db.rst create mode 100644 comm/third_party/botan/doc/api_ref/pubkey.rst create mode 100644 comm/third_party/botan/doc/api_ref/python.rst create mode 100644 comm/third_party/botan/doc/api_ref/rng.rst create mode 100644 comm/third_party/botan/doc/api_ref/roughtime.rst create mode 100644 comm/third_party/botan/doc/api_ref/secmem.rst create mode 100644 comm/third_party/botan/doc/api_ref/srp.rst create mode 100644 comm/third_party/botan/doc/api_ref/stream_ciphers.rst create mode 100644 comm/third_party/botan/doc/api_ref/tls.rst create mode 100644 comm/third_party/botan/doc/api_ref/tpm.rst create mode 100644 comm/third_party/botan/doc/api_ref/tss.rst create mode 100644 comm/third_party/botan/doc/api_ref/versions.rst create mode 100644 comm/third_party/botan/doc/api_ref/x509.rst create mode 100644 comm/third_party/botan/doc/authors.txt create mode 100644 comm/third_party/botan/doc/building.rst create mode 100644 comm/third_party/botan/doc/cli.rst create mode 100644 comm/third_party/botan/doc/contents.rst create mode 100644 comm/third_party/botan/doc/credits.rst create mode 100644 comm/third_party/botan/doc/deprecated.rst create mode 100644 comm/third_party/botan/doc/dev_ref/configure.rst create mode 100644 comm/third_party/botan/doc/dev_ref/contents.rst create mode 100644 comm/third_party/botan/doc/dev_ref/continuous_integration.rst create mode 100644 comm/third_party/botan/doc/dev_ref/contributing.rst create mode 100644 comm/third_party/botan/doc/dev_ref/fuzzing.rst create mode 100644 comm/third_party/botan/doc/dev_ref/mistakes.rst create mode 100644 comm/third_party/botan/doc/dev_ref/oids.rst create mode 100644 comm/third_party/botan/doc/dev_ref/os.rst create mode 100644 comm/third_party/botan/doc/dev_ref/reading_list.rst create mode 100644 comm/third_party/botan/doc/dev_ref/release_process.rst create mode 100644 comm/third_party/botan/doc/dev_ref/test_framework.rst create mode 100644 comm/third_party/botan/doc/dev_ref/todo.rst create mode 100644 comm/third_party/botan/doc/goals.rst create mode 100644 comm/third_party/botan/doc/index.rst create mode 100644 comm/third_party/botan/doc/old_news.rst create mode 100644 comm/third_party/botan/doc/packaging.rst create mode 100644 comm/third_party/botan/doc/pgpkey.txt create mode 100644 comm/third_party/botan/doc/roadmap.rst create mode 100644 comm/third_party/botan/doc/security.rst create mode 100644 comm/third_party/botan/doc/side_channels.rst create mode 100644 comm/third_party/botan/doc/support.rst create mode 100644 comm/third_party/botan/license.txt create mode 100644 comm/third_party/botan/moz.build create mode 100644 comm/third_party/botan/news.rst create mode 100644 comm/third_party/botan/readme.rst create mode 100644 comm/third_party/botan/src/bogo_shim/bogo_shim.cpp create mode 100644 comm/third_party/botan/src/bogo_shim/config.json create mode 100644 comm/third_party/botan/src/build-data/arch/alpha.txt create mode 100644 comm/third_party/botan/src/build-data/arch/arm32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/arm64.txt create mode 100644 comm/third_party/botan/src/build-data/arch/generic.txt create mode 100644 comm/third_party/botan/src/build-data/arch/hppa.txt create mode 100644 comm/third_party/botan/src/build-data/arch/ia64.txt create mode 100644 comm/third_party/botan/src/build-data/arch/llvm.txt create mode 100644 comm/third_party/botan/src/build-data/arch/m68k.txt create mode 100644 comm/third_party/botan/src/build-data/arch/mips32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/mips64.txt create mode 100644 comm/third_party/botan/src/build-data/arch/powerpcspe.txt create mode 100644 comm/third_party/botan/src/build-data/arch/ppc32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/ppc64.txt create mode 100644 comm/third_party/botan/src/build-data/arch/riscv32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/riscv64.txt create mode 100644 comm/third_party/botan/src/build-data/arch/s390.txt create mode 100644 comm/third_party/botan/src/build-data/arch/s390x.txt create mode 100644 comm/third_party/botan/src/build-data/arch/sparc32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/sparc64.txt create mode 100644 comm/third_party/botan/src/build-data/arch/superh.txt create mode 100644 comm/third_party/botan/src/build-data/arch/x32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/x86_32.txt create mode 100644 comm/third_party/botan/src/build-data/arch/x86_64.txt create mode 100644 comm/third_party/botan/src/build-data/bakefile.in create mode 100644 comm/third_party/botan/src/build-data/botan.doxy.in create mode 100644 comm/third_party/botan/src/build-data/botan.pc.in create mode 100644 comm/third_party/botan/src/build-data/buildh.in create mode 100644 comm/third_party/botan/src/build-data/cc/clang.txt create mode 100644 comm/third_party/botan/src/build-data/cc/ekopath.txt create mode 100644 comm/third_party/botan/src/build-data/cc/gcc.txt create mode 100644 comm/third_party/botan/src/build-data/cc/hpcc.txt create mode 100644 comm/third_party/botan/src/build-data/cc/icc.txt create mode 100644 comm/third_party/botan/src/build-data/cc/msvc.txt create mode 100644 comm/third_party/botan/src/build-data/cc/pgi.txt create mode 100644 comm/third_party/botan/src/build-data/cc/sunstudio.txt create mode 100644 comm/third_party/botan/src/build-data/cc/xlc.txt create mode 100644 comm/third_party/botan/src/build-data/cmake.in create mode 100644 comm/third_party/botan/src/build-data/detect_arch.cpp create mode 100644 comm/third_party/botan/src/build-data/detect_version.cpp create mode 100644 comm/third_party/botan/src/build-data/innosetup.in create mode 100644 comm/third_party/botan/src/build-data/makefile.in create mode 100644 comm/third_party/botan/src/build-data/oids.txt create mode 100644 comm/third_party/botan/src/build-data/os/aix.txt create mode 100644 comm/third_party/botan/src/build-data/os/android.txt create mode 100644 comm/third_party/botan/src/build-data/os/cygwin.txt create mode 100644 comm/third_party/botan/src/build-data/os/dragonfly.txt create mode 100644 comm/third_party/botan/src/build-data/os/emscripten.txt create mode 100644 comm/third_party/botan/src/build-data/os/freebsd.txt create mode 100644 comm/third_party/botan/src/build-data/os/haiku.txt create mode 100644 comm/third_party/botan/src/build-data/os/hpux.txt create mode 100644 comm/third_party/botan/src/build-data/os/hurd.txt create mode 100644 comm/third_party/botan/src/build-data/os/includeos.txt create mode 100644 comm/third_party/botan/src/build-data/os/ios.txt create mode 100644 comm/third_party/botan/src/build-data/os/linux.txt create mode 100644 comm/third_party/botan/src/build-data/os/llvm.txt create mode 100644 comm/third_party/botan/src/build-data/os/macos.txt create mode 100644 comm/third_party/botan/src/build-data/os/mingw.txt create mode 100644 comm/third_party/botan/src/build-data/os/nacl.txt create mode 100644 comm/third_party/botan/src/build-data/os/netbsd.txt create mode 100644 comm/third_party/botan/src/build-data/os/none.txt create mode 100644 comm/third_party/botan/src/build-data/os/openbsd.txt create mode 100644 comm/third_party/botan/src/build-data/os/qnx.txt create mode 100644 comm/third_party/botan/src/build-data/os/solaris.txt create mode 100644 comm/third_party/botan/src/build-data/os/uwp.txt create mode 100644 comm/third_party/botan/src/build-data/os/windows.txt create mode 100644 comm/third_party/botan/src/build-data/policy/bsi.txt create mode 100644 comm/third_party/botan/src/build-data/policy/modern.txt create mode 100644 comm/third_party/botan/src/build-data/policy/nist.txt create mode 100644 comm/third_party/botan/src/build-data/version.txt create mode 100644 comm/third_party/botan/src/cli/argon2.cpp create mode 100644 comm/third_party/botan/src/cli/argparse.h create mode 100644 comm/third_party/botan/src/cli/asn1.cpp create mode 100644 comm/third_party/botan/src/cli/bcrypt.cpp create mode 100644 comm/third_party/botan/src/cli/cc_enc.cpp create mode 100644 comm/third_party/botan/src/cli/cli.cpp create mode 100644 comm/third_party/botan/src/cli/cli.h create mode 100644 comm/third_party/botan/src/cli/cli_exceptions.h create mode 100644 comm/third_party/botan/src/cli/cli_rng.cpp create mode 100644 comm/third_party/botan/src/cli/codec.cpp create mode 100644 comm/third_party/botan/src/cli/compress.cpp create mode 100644 comm/third_party/botan/src/cli/encryption.cpp create mode 100644 comm/third_party/botan/src/cli/entropy.cpp create mode 100644 comm/third_party/botan/src/cli/hash.cpp create mode 100644 comm/third_party/botan/src/cli/hmac.cpp create mode 100644 comm/third_party/botan/src/cli/main.cpp create mode 100644 comm/third_party/botan/src/cli/math.cpp create mode 100644 comm/third_party/botan/src/cli/pbkdf.cpp create mode 100644 comm/third_party/botan/src/cli/pk_crypt.cpp create mode 100644 comm/third_party/botan/src/cli/psk.cpp create mode 100644 comm/third_party/botan/src/cli/pubkey.cpp create mode 100644 comm/third_party/botan/src/cli/roughtime.cpp create mode 100644 comm/third_party/botan/src/cli/sandbox.cpp create mode 100644 comm/third_party/botan/src/cli/sandbox.h create mode 100644 comm/third_party/botan/src/cli/socket_utils.h create mode 100644 comm/third_party/botan/src/cli/speed.cpp create mode 100644 comm/third_party/botan/src/cli/timing_tests.cpp create mode 100644 comm/third_party/botan/src/cli/tls_client.cpp create mode 100644 comm/third_party/botan/src/cli/tls_helpers.h create mode 100644 comm/third_party/botan/src/cli/tls_http_server.cpp create mode 100644 comm/third_party/botan/src/cli/tls_proxy.cpp create mode 100644 comm/third_party/botan/src/cli/tls_server.cpp create mode 100644 comm/third_party/botan/src/cli/tls_utils.cpp create mode 100644 comm/third_party/botan/src/cli/tss.cpp create mode 100644 comm/third_party/botan/src/cli/utils.cpp create mode 100644 comm/third_party/botan/src/cli/x509.cpp create mode 100644 comm/third_party/botan/src/configs/astyle.rc create mode 100644 comm/third_party/botan/src/configs/coverage.rc create mode 100644 comm/third_party/botan/src/configs/eclipse.xml create mode 100644 comm/third_party/botan/src/configs/indent.el create mode 100644 comm/third_party/botan/src/configs/pylint.rc create mode 100644 comm/third_party/botan/src/configs/sonar-project.properties create mode 100644 comm/third_party/botan/src/configs/sphinx/conf.py create mode 100644 comm/third_party/botan/src/configs/sphinx/templates/layout.html create mode 100644 comm/third_party/botan/src/fuzzer/asn1.cpp create mode 100644 comm/third_party/botan/src/fuzzer/barrett.cpp create mode 100644 comm/third_party/botan/src/fuzzer/bn_cmp.cpp create mode 100644 comm/third_party/botan/src/fuzzer/bn_sqr.cpp create mode 100644 comm/third_party/botan/src/fuzzer/cert.cpp create mode 100644 comm/third_party/botan/src/fuzzer/crl.cpp create mode 100644 comm/third_party/botan/src/fuzzer/divide.cpp create mode 100644 comm/third_party/botan/src/fuzzer/ecc_bp256.cpp create mode 100644 comm/third_party/botan/src/fuzzer/ecc_helper.h create mode 100644 comm/third_party/botan/src/fuzzer/ecc_p256.cpp create mode 100644 comm/third_party/botan/src/fuzzer/ecc_p384.cpp create mode 100644 comm/third_party/botan/src/fuzzer/ecc_p521.cpp create mode 100644 comm/third_party/botan/src/fuzzer/fuzzers.h create mode 100644 comm/third_party/botan/src/fuzzer/invert.cpp create mode 100644 comm/third_party/botan/src/fuzzer/mem_pool.cpp create mode 100644 comm/third_party/botan/src/fuzzer/mode_padding.cpp create mode 100644 comm/third_party/botan/src/fuzzer/oaep.cpp create mode 100644 comm/third_party/botan/src/fuzzer/ocsp.cpp create mode 100644 comm/third_party/botan/src/fuzzer/os2ecp.cpp create mode 100644 comm/third_party/botan/src/fuzzer/pkcs1.cpp create mode 100644 comm/third_party/botan/src/fuzzer/pkcs8.cpp create mode 100644 comm/third_party/botan/src/fuzzer/pow_mod.cpp create mode 100644 comm/third_party/botan/src/fuzzer/redc_p192.cpp create mode 100644 comm/third_party/botan/src/fuzzer/redc_p224.cpp create mode 100644 comm/third_party/botan/src/fuzzer/redc_p256.cpp create mode 100644 comm/third_party/botan/src/fuzzer/redc_p384.cpp create mode 100644 comm/third_party/botan/src/fuzzer/redc_p521.cpp create mode 100644 comm/third_party/botan/src/fuzzer/ressol.cpp create mode 100644 comm/third_party/botan/src/fuzzer/tls_client.cpp create mode 100644 comm/third_party/botan/src/fuzzer/tls_client_hello.cpp create mode 100644 comm/third_party/botan/src/fuzzer/tls_server.cpp create mode 100644 comm/third_party/botan/src/fuzzer/uri.cpp create mode 100644 comm/third_party/botan/src/fuzzer/x509_dn.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/alg_id.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/alg_id.h create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_obj.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_obj.h create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_oid.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_oid.h create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_print.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_print.h create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_str.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_str.h create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_time.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/asn1_time.h create mode 100644 comm/third_party/botan/src/lib/asn1/ber_dec.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/ber_dec.h create mode 100644 comm/third_party/botan/src/lib/asn1/der_enc.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/der_enc.h create mode 100644 comm/third_party/botan/src/lib/asn1/info.txt create mode 100644 comm/third_party/botan/src/lib/asn1/oid_maps.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/oids.cpp create mode 100644 comm/third_party/botan/src/lib/asn1/oids.h create mode 100644 comm/third_party/botan/src/lib/base/botan.h create mode 100644 comm/third_party/botan/src/lib/base/buf_comp.cpp create mode 100644 comm/third_party/botan/src/lib/base/buf_comp.h create mode 100644 comm/third_party/botan/src/lib/base/info.txt create mode 100644 comm/third_party/botan/src/lib/base/init.h create mode 100644 comm/third_party/botan/src/lib/base/key_spec.h create mode 100644 comm/third_party/botan/src/lib/base/lookup.h create mode 100644 comm/third_party/botan/src/lib/base/scan_name.cpp create mode 100644 comm/third_party/botan/src/lib/base/scan_name.h create mode 100644 comm/third_party/botan/src/lib/base/secmem.h create mode 100644 comm/third_party/botan/src/lib/base/sym_algo.cpp create mode 100644 comm/third_party/botan/src/lib/base/sym_algo.h create mode 100644 comm/third_party/botan/src/lib/base/symkey.cpp create mode 100644 comm/third_party/botan/src/lib/base/symkey.h create mode 100644 comm/third_party/botan/src/lib/block/aes/aes.cpp create mode 100644 comm/third_party/botan/src/lib/block/aes/aes.h create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_armv8/info.txt create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_ni/aes_ni.cpp create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_ni/info.txt create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_power8/aes_power8.cpp create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_power8/info.txt create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_vperm/aes_vperm.cpp create mode 100644 comm/third_party/botan/src/lib/block/aes/aes_vperm/info.txt create mode 100644 comm/third_party/botan/src/lib/block/aes/info.txt create mode 100644 comm/third_party/botan/src/lib/block/aria/aria.cpp create mode 100644 comm/third_party/botan/src/lib/block/aria/aria.h create mode 100644 comm/third_party/botan/src/lib/block/aria/info.txt create mode 100644 comm/third_party/botan/src/lib/block/block_cipher.cpp create mode 100644 comm/third_party/botan/src/lib/block/block_cipher.h create mode 100644 comm/third_party/botan/src/lib/block/blowfish/blowfish.cpp create mode 100644 comm/third_party/botan/src/lib/block/blowfish/blowfish.h create mode 100644 comm/third_party/botan/src/lib/block/blowfish/info.txt create mode 100644 comm/third_party/botan/src/lib/block/camellia/camellia.cpp create mode 100644 comm/third_party/botan/src/lib/block/camellia/camellia.h create mode 100644 comm/third_party/botan/src/lib/block/camellia/info.txt create mode 100644 comm/third_party/botan/src/lib/block/cascade/cascade.cpp create mode 100644 comm/third_party/botan/src/lib/block/cascade/cascade.h create mode 100644 comm/third_party/botan/src/lib/block/cascade/info.txt create mode 100644 comm/third_party/botan/src/lib/block/cast128/cast128.cpp create mode 100644 comm/third_party/botan/src/lib/block/cast128/cast128.h create mode 100644 comm/third_party/botan/src/lib/block/cast128/cast_sboxes.h create mode 100644 comm/third_party/botan/src/lib/block/cast128/info.txt create mode 100644 comm/third_party/botan/src/lib/block/cast256/cast256.cpp create mode 100644 comm/third_party/botan/src/lib/block/cast256/cast256.h create mode 100644 comm/third_party/botan/src/lib/block/cast256/info.txt create mode 100644 comm/third_party/botan/src/lib/block/des/des.cpp create mode 100644 comm/third_party/botan/src/lib/block/des/des.h create mode 100644 comm/third_party/botan/src/lib/block/des/des_tab.cpp create mode 100644 comm/third_party/botan/src/lib/block/des/desx.cpp create mode 100644 comm/third_party/botan/src/lib/block/des/desx.h create mode 100644 comm/third_party/botan/src/lib/block/des/info.txt create mode 100644 comm/third_party/botan/src/lib/block/gost_28147/gost_28147.cpp create mode 100644 comm/third_party/botan/src/lib/block/gost_28147/gost_28147.h create mode 100644 comm/third_party/botan/src/lib/block/gost_28147/info.txt create mode 100644 comm/third_party/botan/src/lib/block/idea/idea.cpp create mode 100644 comm/third_party/botan/src/lib/block/idea/idea.h create mode 100644 comm/third_party/botan/src/lib/block/idea/idea_sse2/idea_sse2.cpp create mode 100644 comm/third_party/botan/src/lib/block/idea/idea_sse2/info.txt create mode 100644 comm/third_party/botan/src/lib/block/idea/info.txt create mode 100644 comm/third_party/botan/src/lib/block/info.txt create mode 100644 comm/third_party/botan/src/lib/block/kasumi/info.txt create mode 100644 comm/third_party/botan/src/lib/block/kasumi/kasumi.cpp create mode 100644 comm/third_party/botan/src/lib/block/kasumi/kasumi.h create mode 100644 comm/third_party/botan/src/lib/block/lion/info.txt create mode 100644 comm/third_party/botan/src/lib/block/lion/lion.cpp create mode 100644 comm/third_party/botan/src/lib/block/lion/lion.h create mode 100644 comm/third_party/botan/src/lib/block/misty1/info.txt create mode 100644 comm/third_party/botan/src/lib/block/misty1/misty1.cpp create mode 100644 comm/third_party/botan/src/lib/block/misty1/misty1.h create mode 100644 comm/third_party/botan/src/lib/block/noekeon/info.txt create mode 100644 comm/third_party/botan/src/lib/block/noekeon/noekeon.cpp create mode 100644 comm/third_party/botan/src/lib/block/noekeon/noekeon.h create mode 100644 comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/info.txt create mode 100644 comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/noekeon_simd.cpp create mode 100644 comm/third_party/botan/src/lib/block/seed/info.txt create mode 100644 comm/third_party/botan/src/lib/block/seed/seed.cpp create mode 100644 comm/third_party/botan/src/lib/block/seed/seed.h create mode 100644 comm/third_party/botan/src/lib/block/serpent/info.txt create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent.cpp create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent.h create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent_avx2/info.txt create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent_avx2/serpent_avx2.cpp create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent_sbox.h create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent_simd/info.txt create mode 100644 comm/third_party/botan/src/lib/block/serpent/serpent_simd/serpent_simd.cpp create mode 100644 comm/third_party/botan/src/lib/block/shacal2/info.txt create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2.cpp create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2.h create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/info.txt create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/shacal2_avx2.cpp create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/info.txt create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/shacal2_simd.cpp create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/info.txt create mode 100644 comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/shacal2_x86.cpp create mode 100644 comm/third_party/botan/src/lib/block/sm4/info.txt create mode 100644 comm/third_party/botan/src/lib/block/sm4/sm4.cpp create mode 100644 comm/third_party/botan/src/lib/block/sm4/sm4.h create mode 100644 comm/third_party/botan/src/lib/block/sm4/sm4_armv8/info.txt create mode 100644 comm/third_party/botan/src/lib/block/sm4/sm4_armv8/sm4_armv8.cpp create mode 100644 comm/third_party/botan/src/lib/block/threefish_512/info.txt create mode 100644 comm/third_party/botan/src/lib/block/threefish_512/threefish.h create mode 100644 comm/third_party/botan/src/lib/block/threefish_512/threefish_512.cpp create mode 100644 comm/third_party/botan/src/lib/block/threefish_512/threefish_512.h create mode 100644 comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/info.txt create mode 100644 comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/threefish_512_avx2.cpp create mode 100644 comm/third_party/botan/src/lib/block/twofish/info.txt create mode 100644 comm/third_party/botan/src/lib/block/twofish/twofish.cpp create mode 100644 comm/third_party/botan/src/lib/block/twofish/twofish.h create mode 100644 comm/third_party/botan/src/lib/block/twofish/twofish_tab.cpp create mode 100644 comm/third_party/botan/src/lib/block/xtea/info.txt create mode 100644 comm/third_party/botan/src/lib/block/xtea/xtea.cpp create mode 100644 comm/third_party/botan/src/lib/block/xtea/xtea.h create mode 100644 comm/third_party/botan/src/lib/codec/base32/base32.cpp create mode 100644 comm/third_party/botan/src/lib/codec/base32/base32.h create mode 100644 comm/third_party/botan/src/lib/codec/base32/info.txt create mode 100644 comm/third_party/botan/src/lib/codec/base58/base58.cpp create mode 100644 comm/third_party/botan/src/lib/codec/base58/base58.h create mode 100644 comm/third_party/botan/src/lib/codec/base58/info.txt create mode 100644 comm/third_party/botan/src/lib/codec/base64/base64.cpp create mode 100644 comm/third_party/botan/src/lib/codec/base64/base64.h create mode 100644 comm/third_party/botan/src/lib/codec/base64/info.txt create mode 100644 comm/third_party/botan/src/lib/codec/hex/hex.cpp create mode 100644 comm/third_party/botan/src/lib/codec/hex/hex.h create mode 100644 comm/third_party/botan/src/lib/codec/hex/info.txt create mode 100644 comm/third_party/botan/src/lib/compat/sodium/info.txt create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium.h create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_25519.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_aead.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_auth.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_box.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_chacha.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_salsa.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_secretbox.cpp create mode 100644 comm/third_party/botan/src/lib/compat/sodium/sodium_utils.cpp create mode 100644 comm/third_party/botan/src/lib/compression/bzip2/bzip2.cpp create mode 100644 comm/third_party/botan/src/lib/compression/bzip2/bzip2.h create mode 100644 comm/third_party/botan/src/lib/compression/bzip2/info.txt create mode 100644 comm/third_party/botan/src/lib/compression/compress_utils.cpp create mode 100644 comm/third_party/botan/src/lib/compression/compress_utils.h create mode 100644 comm/third_party/botan/src/lib/compression/compression.cpp create mode 100644 comm/third_party/botan/src/lib/compression/compression.h create mode 100644 comm/third_party/botan/src/lib/compression/info.txt create mode 100644 comm/third_party/botan/src/lib/compression/lzma/info.txt create mode 100644 comm/third_party/botan/src/lib/compression/lzma/lzma.cpp create mode 100644 comm/third_party/botan/src/lib/compression/lzma/lzma.h create mode 100644 comm/third_party/botan/src/lib/compression/zlib/info.txt create mode 100644 comm/third_party/botan/src/lib/compression/zlib/zlib.cpp create mode 100644 comm/third_party/botan/src/lib/compression/zlib/zlib.h create mode 100644 comm/third_party/botan/src/lib/entropy/dev_random/dev_random.cpp create mode 100644 comm/third_party/botan/src/lib/entropy/dev_random/dev_random.h create mode 100644 comm/third_party/botan/src/lib/entropy/dev_random/info.txt create mode 100644 comm/third_party/botan/src/lib/entropy/entropy_src.h create mode 100644 comm/third_party/botan/src/lib/entropy/entropy_srcs.cpp create mode 100644 comm/third_party/botan/src/lib/entropy/getentropy/getentropy.cpp create mode 100644 comm/third_party/botan/src/lib/entropy/getentropy/getentropy.h create mode 100644 comm/third_party/botan/src/lib/entropy/getentropy/info.txt create mode 100644 comm/third_party/botan/src/lib/entropy/info.txt create mode 100644 comm/third_party/botan/src/lib/entropy/proc_walk/info.txt create mode 100644 comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.cpp create mode 100644 comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.h create mode 100644 comm/third_party/botan/src/lib/entropy/rdseed/info.txt create mode 100644 comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp create mode 100644 comm/third_party/botan/src/lib/entropy/rdseed/rdseed.h create mode 100644 comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.cpp create mode 100644 comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.h create mode 100644 comm/third_party/botan/src/lib/entropy/win32_stats/info.txt create mode 100644 comm/third_party/botan/src/lib/ffi/ffi.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi.h create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_block.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_cert.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_cipher.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_fpe.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_hash.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_hotp.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_kdf.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_keywrap.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_mac.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_mp.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_mp.h create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_pk_op.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_pkey.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_pkey.h create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_pkey_algs.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_rng.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_rng.h create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_totp.cpp create mode 100644 comm/third_party/botan/src/lib/ffi/ffi_util.h create mode 100644 comm/third_party/botan/src/lib/ffi/info.txt create mode 100644 comm/third_party/botan/src/lib/filters/algo_filt.cpp create mode 100644 comm/third_party/botan/src/lib/filters/b64_filt.cpp create mode 100644 comm/third_party/botan/src/lib/filters/b64_filt.h create mode 100644 comm/third_party/botan/src/lib/filters/basefilt.cpp create mode 100644 comm/third_party/botan/src/lib/filters/basefilt.h create mode 100644 comm/third_party/botan/src/lib/filters/buf_filt.cpp create mode 100644 comm/third_party/botan/src/lib/filters/buf_filt.h create mode 100644 comm/third_party/botan/src/lib/filters/cipher_filter.cpp create mode 100644 comm/third_party/botan/src/lib/filters/cipher_filter.h create mode 100644 comm/third_party/botan/src/lib/filters/comp_filter.cpp create mode 100644 comm/third_party/botan/src/lib/filters/comp_filter.h create mode 100644 comm/third_party/botan/src/lib/filters/data_snk.cpp create mode 100644 comm/third_party/botan/src/lib/filters/data_snk.h create mode 100644 comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.cpp create mode 100644 comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.h create mode 100644 comm/third_party/botan/src/lib/filters/fd_unix/info.txt create mode 100644 comm/third_party/botan/src/lib/filters/filter.cpp create mode 100644 comm/third_party/botan/src/lib/filters/filter.h create mode 100644 comm/third_party/botan/src/lib/filters/filters.h create mode 100644 comm/third_party/botan/src/lib/filters/hex_filt.cpp create mode 100644 comm/third_party/botan/src/lib/filters/hex_filt.h create mode 100644 comm/third_party/botan/src/lib/filters/info.txt create mode 100644 comm/third_party/botan/src/lib/filters/key_filt.h create mode 100644 comm/third_party/botan/src/lib/filters/out_buf.cpp create mode 100644 comm/third_party/botan/src/lib/filters/out_buf.h create mode 100644 comm/third_party/botan/src/lib/filters/pipe.cpp create mode 100644 comm/third_party/botan/src/lib/filters/pipe.h create mode 100644 comm/third_party/botan/src/lib/filters/pipe_io.cpp create mode 100644 comm/third_party/botan/src/lib/filters/pipe_rw.cpp create mode 100644 comm/third_party/botan/src/lib/filters/secqueue.cpp create mode 100644 comm/third_party/botan/src/lib/filters/secqueue.h create mode 100644 comm/third_party/botan/src/lib/filters/threaded_fork.cpp create mode 100644 comm/third_party/botan/src/lib/hash/blake2/blake2b.cpp create mode 100644 comm/third_party/botan/src/lib/hash/blake2/blake2b.h create mode 100644 comm/third_party/botan/src/lib/hash/blake2/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.cpp create mode 100644 comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.h create mode 100644 comm/third_party/botan/src/lib/hash/checksum/adler32/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.cpp create mode 100644 comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.h create mode 100644 comm/third_party/botan/src/lib/hash/checksum/crc24/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.cpp create mode 100644 comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.h create mode 100644 comm/third_party/botan/src/lib/hash/checksum/crc32/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/checksum/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/comb4p/comb4p.cpp create mode 100644 comm/third_party/botan/src/lib/hash/comb4p/comb4p.h create mode 100644 comm/third_party/botan/src/lib/hash/comb4p/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.cpp create mode 100644 comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.h create mode 100644 comm/third_party/botan/src/lib/hash/gost_3411/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/hash.cpp create mode 100644 comm/third_party/botan/src/lib/hash/hash.h create mode 100644 comm/third_party/botan/src/lib/hash/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/keccak/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/keccak/keccak.cpp create mode 100644 comm/third_party/botan/src/lib/hash/keccak/keccak.h create mode 100644 comm/third_party/botan/src/lib/hash/md4/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/md4/md4.cpp create mode 100644 comm/third_party/botan/src/lib/hash/md4/md4.h create mode 100644 comm/third_party/botan/src/lib/hash/md5/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/md5/md5.cpp create mode 100644 comm/third_party/botan/src/lib/hash/md5/md5.h create mode 100644 comm/third_party/botan/src/lib/hash/mdx_hash/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.cpp create mode 100644 comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.h create mode 100644 comm/third_party/botan/src/lib/hash/par_hash/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/par_hash/par_hash.cpp create mode 100644 comm/third_party/botan/src/lib/hash/par_hash/par_hash.h create mode 100644 comm/third_party/botan/src/lib/hash/rmd160/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/rmd160/rmd160.cpp create mode 100644 comm/third_party/botan/src/lib/hash/rmd160/rmd160.h create mode 100644 comm/third_party/botan/src/lib/hash/sha1/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha160.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha160.h create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha1_x86/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.h create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha2_64/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.h create mode 100644 comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/sha2_64_bmi2.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha3/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha3/sha3.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sha3/sha3.h create mode 100644 comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp create mode 100644 comm/third_party/botan/src/lib/hash/shake/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/shake/shake.cpp create mode 100644 comm/third_party/botan/src/lib/hash/shake/shake.h create mode 100644 comm/third_party/botan/src/lib/hash/skein/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/skein/skein_512.cpp create mode 100644 comm/third_party/botan/src/lib/hash/skein/skein_512.h create mode 100644 comm/third_party/botan/src/lib/hash/sm3/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/sm3/sm3.cpp create mode 100644 comm/third_party/botan/src/lib/hash/sm3/sm3.h create mode 100644 comm/third_party/botan/src/lib/hash/streebog/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/streebog/streebog.cpp create mode 100644 comm/third_party/botan/src/lib/hash/streebog/streebog.h create mode 100644 comm/third_party/botan/src/lib/hash/streebog/streebog_precalc.cpp create mode 100644 comm/third_party/botan/src/lib/hash/tiger/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/tiger/tig_tab.cpp create mode 100644 comm/third_party/botan/src/lib/hash/tiger/tiger.cpp create mode 100644 comm/third_party/botan/src/lib/hash/tiger/tiger.h create mode 100644 comm/third_party/botan/src/lib/hash/whirlpool/info.txt create mode 100644 comm/third_party/botan/src/lib/hash/whirlpool/whirlpool.cpp create mode 100644 comm/third_party/botan/src/lib/hash/whirlpool/whrl_tab.cpp create mode 100644 comm/third_party/botan/src/lib/hash/whirlpool/whrlpool.h create mode 100644 comm/third_party/botan/src/lib/kdf/hkdf/hkdf.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/hkdf/hkdf.h create mode 100644 comm/third_party/botan/src/lib/kdf/hkdf/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/kdf.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/kdf.h create mode 100644 comm/third_party/botan/src/lib/kdf/kdf1/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/kdf1/kdf1.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/kdf1/kdf1.h create mode 100644 comm/third_party/botan/src/lib/kdf/kdf1_iso18033/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h create mode 100644 comm/third_party/botan/src/lib/kdf/kdf2/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/kdf2/kdf2.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/kdf2/kdf2.h create mode 100644 comm/third_party/botan/src/lib/kdf/prf_tls/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.h create mode 100644 comm/third_party/botan/src/lib/kdf/prf_x942/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.h create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_108/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.h create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_56a/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.h create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_56c/info.txt create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.cpp create mode 100644 comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.h create mode 100644 comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp create mode 100644 comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h create mode 100644 comm/third_party/botan/src/lib/mac/cbc_mac/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/cmac/cmac.cpp create mode 100644 comm/third_party/botan/src/lib/mac/cmac/cmac.h create mode 100644 comm/third_party/botan/src/lib/mac/cmac/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/gmac/gmac.cpp create mode 100644 comm/third_party/botan/src/lib/mac/gmac/gmac.h create mode 100644 comm/third_party/botan/src/lib/mac/gmac/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/hmac/hmac.cpp create mode 100644 comm/third_party/botan/src/lib/mac/hmac/hmac.h create mode 100644 comm/third_party/botan/src/lib/mac/hmac/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/mac.cpp create mode 100644 comm/third_party/botan/src/lib/mac/mac.h create mode 100644 comm/third_party/botan/src/lib/mac/poly1305/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp create mode 100644 comm/third_party/botan/src/lib/mac/poly1305/poly1305.h create mode 100644 comm/third_party/botan/src/lib/mac/siphash/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/siphash/siphash.cpp create mode 100644 comm/third_party/botan/src/lib/mac/siphash/siphash.h create mode 100644 comm/third_party/botan/src/lib/mac/x919_mac/info.txt create mode 100644 comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp create mode 100644 comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h create mode 100644 comm/third_party/botan/src/lib/math/bigint/big_code.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/big_io.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/big_ops2.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/big_ops3.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/big_rand.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/bigint.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/bigint.h create mode 100644 comm/third_party/botan/src/lib/math/bigint/divide.cpp create mode 100644 comm/third_party/botan/src/lib/math/bigint/divide.h create mode 100644 comm/third_party/botan/src/lib/math/bigint/info.txt create mode 100644 comm/third_party/botan/src/lib/math/mp/info.txt create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_asmi.h create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_comba.cpp create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_core.h create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_karat.cpp create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_madd.h create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_monty.cpp create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_monty.h create mode 100644 comm/third_party/botan/src/lib/math/mp/mp_monty_n.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/curve_nistp.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/dsa_gen.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/info.txt create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/jacobi.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/make_prm.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/mod_inv.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/monty.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/monty.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/monty_exp.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/monty_exp.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/mp_numth.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/nistp_redc.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/numthry.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/numthry.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/pow_mod.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/pow_mod.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/primality.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/primality.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/primes.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/reducer.cpp create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/reducer.h create mode 100644 comm/third_party/botan/src/lib/math/numbertheory/ressol.cpp create mode 100644 comm/third_party/botan/src/lib/misc/aont/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/aont/package.cpp create mode 100644 comm/third_party/botan/src/lib/misc/aont/package.h create mode 100644 comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.cpp create mode 100644 comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.h create mode 100644 comm/third_party/botan/src/lib/misc/cryptobox/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.cpp create mode 100644 comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.h create mode 100644 comm/third_party/botan/src/lib/misc/fpe_fe1/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/hotp/hotp.cpp create mode 100644 comm/third_party/botan/src/lib/misc/hotp/hotp.h create mode 100644 comm/third_party/botan/src/lib/misc/hotp/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/hotp/otp.h create mode 100644 comm/third_party/botan/src/lib/misc/hotp/totp.cpp create mode 100644 comm/third_party/botan/src/lib/misc/hotp/totp.h create mode 100644 comm/third_party/botan/src/lib/misc/nist_keywrap/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.cpp create mode 100644 comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.h create mode 100644 comm/third_party/botan/src/lib/misc/rfc3394/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.cpp create mode 100644 comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.h create mode 100644 comm/third_party/botan/src/lib/misc/roughtime/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/roughtime/roughtime.cpp create mode 100644 comm/third_party/botan/src/lib/misc/roughtime/roughtime.h create mode 100644 comm/third_party/botan/src/lib/misc/srp6/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/srp6/srp6.cpp create mode 100644 comm/third_party/botan/src/lib/misc/srp6/srp6.h create mode 100644 comm/third_party/botan/src/lib/misc/tss/info.txt create mode 100644 comm/third_party/botan/src/lib/misc/tss/tss.cpp create mode 100644 comm/third_party/botan/src/lib/misc/tss/tss.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/aead.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/aead.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/ccm/ccm.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/ccm/ccm.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/ccm/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/eax/eax.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/eax/eax.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/eax/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/gcm/gcm.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/gcm/gcm.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/gcm/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/ocb/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/ocb/ocb.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/ocb/ocb.h create mode 100644 comm/third_party/botan/src/lib/modes/aead/siv/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/aead/siv/siv.cpp create mode 100644 comm/third_party/botan/src/lib/modes/aead/siv/siv.h create mode 100644 comm/third_party/botan/src/lib/modes/cbc/cbc.cpp create mode 100644 comm/third_party/botan/src/lib/modes/cbc/cbc.h create mode 100644 comm/third_party/botan/src/lib/modes/cbc/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/cfb/cfb.cpp create mode 100644 comm/third_party/botan/src/lib/modes/cfb/cfb.h create mode 100644 comm/third_party/botan/src/lib/modes/cfb/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/cipher_mode.cpp create mode 100644 comm/third_party/botan/src/lib/modes/cipher_mode.h create mode 100644 comm/third_party/botan/src/lib/modes/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/mode_pad/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.cpp create mode 100644 comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.h create mode 100644 comm/third_party/botan/src/lib/modes/stream_mode.h create mode 100644 comm/third_party/botan/src/lib/modes/xts/info.txt create mode 100644 comm/third_party/botan/src/lib/modes/xts/xts.cpp create mode 100644 comm/third_party/botan/src/lib/modes/xts/xts.h create mode 100644 comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp create mode 100644 comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h create mode 100644 comm/third_party/botan/src/lib/passhash/bcrypt/info.txt create mode 100644 comm/third_party/botan/src/lib/passhash/passhash9/info.txt create mode 100644 comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp create mode 100644 comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/argon2/argon2.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/argon2/argon2.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/argon2/argon2fmt.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/argon2/argon2pwhash.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/argon2/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf1/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf2/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/pgp_s2k/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/pwdhash.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/pwdhash.h create mode 100644 comm/third_party/botan/src/lib/pbkdf/scrypt/info.txt create mode 100644 comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.cpp create mode 100644 comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_oaep/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/eme_raw/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa1/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_pssr/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_raw/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/emsa_x931/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/hash_id/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/iso9796/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/mgf1/info.txt create mode 100644 comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.h create mode 100644 comm/third_party/botan/src/lib/pk_pad/padding.cpp create mode 100644 comm/third_party/botan/src/lib/pk_pad/padding.h create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto.h create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_block.cpp create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_hash.cpp create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_mode.cpp create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.cpp create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.h create mode 100644 comm/third_party/botan/src/lib/prov/commoncrypto/info.txt create mode 100644 comm/third_party/botan/src/lib/prov/openssl/info.txt create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl.h create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp create mode 100644 comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/info.txt create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_module.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_module.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_object.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_object.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_session.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_session.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_types.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.cpp create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/pkcs11.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/pkcs11f.h create mode 100644 comm/third_party/botan/src/lib/prov/pkcs11/pkcs11t.h create mode 100644 comm/third_party/botan/src/lib/prov/tpm/info.txt create mode 100644 comm/third_party/botan/src/lib/prov/tpm/tpm.cpp create mode 100644 comm/third_party/botan/src/lib/prov/tpm/tpm.h create mode 100644 comm/third_party/botan/src/lib/psk_db/info.txt create mode 100644 comm/third_party/botan/src/lib/psk_db/psk_db.cpp create mode 100644 comm/third_party/botan/src/lib/psk_db/psk_db.h create mode 100644 comm/third_party/botan/src/lib/psk_db/psk_db_sql.cpp create mode 100644 comm/third_party/botan/src/lib/psk_db/psk_db_sql.h create mode 100644 comm/third_party/botan/src/lib/pubkey/blinding.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/blinding.h create mode 100644 comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.h create mode 100644 comm/third_party/botan/src/lib/pubkey/cecpq1/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.h create mode 100644 comm/third_party/botan/src/lib/pubkey/curve25519/donna.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/curve25519/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/dh/dh.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/dh/dh.h create mode 100644 comm/third_party/botan/src/lib/pubkey/dh/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.h create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_algo/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.h create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_group/dl_named.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/dl_group/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/dlies/dlies.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/dlies/dlies.h create mode 100644 comm/third_party/botan/src/lib/pubkey/dlies/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/dsa/dsa.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/dsa/dsa.h create mode 100644 comm/third_party/botan/src/lib/pubkey/dsa/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/ec_named.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ecc_key/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ecdh/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ecdsa/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ecgdsa/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ecies/ecies.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ecies/ecies.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ecies/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.h create mode 100644 comm/third_party/botan/src/lib/pubkey/eckcdsa/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_internal.h create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_key.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/ge.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/sc_muladd.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/ed25519/sc_reduce.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.h create mode 100644 comm/third_party/botan/src/lib/pubkey/elgamal/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.h create mode 100644 comm/third_party/botan/src/lib/pubkey/gost_3410/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/keypair/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/keypair/keypair.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/keypair/keypair.h create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/code_based_key_gen.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/code_based_util.h create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.h create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/goppa_code.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/mce_internal.h create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/mce_workfactor.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/mceliece.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/mceliece.h create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/mceliece_key.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.h create mode 100644 comm/third_party/botan/src/lib/pubkey/mceies/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/mceies/mceies.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/mceies/mceies.h create mode 100644 comm/third_party/botan/src/lib/pubkey/newhope/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/newhope/newhope.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/newhope/newhope.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pbes2/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pem/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/pem/pem.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pem/pem.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_algs.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_algs.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_keys.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_keys.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_ops.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_ops.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_ops_fwd.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pk_ops_impl.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pkcs8.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pkcs8.h create mode 100644 comm/third_party/botan/src/lib/pubkey/pubkey.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/pubkey.h create mode 100644 comm/third_party/botan/src/lib/pubkey/rfc6979/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.h create mode 100644 comm/third_party/botan/src/lib/pubkey/rsa/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/rsa/rsa.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/rsa/rsa.h create mode 100644 comm/third_party/botan/src/lib/pubkey/sm2/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/sm2/sm2.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/sm2/sm2.h create mode 100644 comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.h create mode 100644 comm/third_party/botan/src/lib/pubkey/workfactor.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/workfactor.h create mode 100644 comm/third_party/botan/src/lib/pubkey/x509_key.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/x509_key.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/atomic.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/info.txt create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_address.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_key_pair.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_tools.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.h create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.cpp create mode 100644 comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.h create mode 100644 comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h create mode 100644 comm/third_party/botan/src/lib/rng/auto_rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h create mode 100644 comm/third_party/botan/src/lib/rng/chacha_rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp create mode 100644 comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h create mode 100644 comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/processor_rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h create mode 100644 comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h create mode 100644 comm/third_party/botan/src/lib/rng/rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/rng.h create mode 100644 comm/third_party/botan/src/lib/rng/stateful_rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h create mode 100644 comm/third_party/botan/src/lib/rng/system_rng/info.txt create mode 100644 comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp create mode 100644 comm/third_party/botan/src/lib/rng/system_rng/system_rng.h create mode 100644 comm/third_party/botan/src/lib/stream/chacha/chacha.cpp create mode 100644 comm/third_party/botan/src/lib/stream/chacha/chacha.h create mode 100644 comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp create mode 100644 comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp create mode 100644 comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/chacha/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/ctr/ctr.cpp create mode 100644 comm/third_party/botan/src/lib/stream/ctr/ctr.h create mode 100644 comm/third_party/botan/src/lib/stream/ctr/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/ofb/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/ofb/ofb.cpp create mode 100644 comm/third_party/botan/src/lib/stream/ofb/ofb.h create mode 100644 comm/third_party/botan/src/lib/stream/rc4/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/rc4/rc4.cpp create mode 100644 comm/third_party/botan/src/lib/stream/rc4/rc4.h create mode 100644 comm/third_party/botan/src/lib/stream/salsa20/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp create mode 100644 comm/third_party/botan/src/lib/stream/salsa20/salsa20.h create mode 100644 comm/third_party/botan/src/lib/stream/shake_cipher/info.txt create mode 100644 comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp create mode 100644 comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h create mode 100644 comm/third_party/botan/src/lib/stream/stream_cipher.cpp create mode 100644 comm/third_party/botan/src/lib/stream/stream_cipher.h create mode 100644 comm/third_party/botan/src/lib/tls/asio/asio_async_ops.h create mode 100644 comm/third_party/botan/src/lib/tls/asio/asio_context.h create mode 100644 comm/third_party/botan/src/lib/tls/asio/asio_error.h create mode 100644 comm/third_party/botan/src/lib/tls/asio/asio_stream.h create mode 100644 comm/third_party/botan/src/lib/tls/asio/info.txt create mode 100644 comm/third_party/botan/src/lib/tls/credentials_manager.cpp create mode 100644 comm/third_party/botan/src/lib/tls/credentials_manager.h create mode 100644 comm/third_party/botan/src/lib/tls/info.txt create mode 100644 comm/third_party/botan/src/lib/tls/msg_cert_req.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_cert_status.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_cert_verify.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_certificate.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_client_hello.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_client_kex.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_finished.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_hello_verify.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_server_hello.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_server_kex.cpp create mode 100644 comm/third_party/botan/src/lib/tls/msg_session_ticket.cpp create mode 100644 comm/third_party/botan/src/lib/tls/sessions_sql/info.txt create mode 100644 comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp create mode 100644 comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.h create mode 100644 comm/third_party/botan/src/lib/tls/sessions_sqlite3/info.txt create mode 100644 comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.cpp create mode 100644 comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_10/info.txt create mode 100644 comm/third_party/botan/src/lib/tls/tls_alert.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_alert.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_algos.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_algos.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_blocking.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_blocking.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_callbacks.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_callbacks.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_cbc/info.txt create mode 100644 comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_channel.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_channel.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_ciphersuite.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_client.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_client.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_exceptn.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_extensions.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_extensions.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_hash.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_hash.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_io.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_io.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_msg.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_state.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_handshake_state.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_magic.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_messages.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_policy.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_policy.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_reader.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_record.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_record.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_seq_numbers.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_server.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_server.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_server_info.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_session.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_session.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_session_key.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_session_key.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_session_manager.h create mode 100644 comm/third_party/botan/src/lib/tls/tls_session_manager_memory.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_suite_info.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_text_policy.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_version.cpp create mode 100644 comm/third_party/botan/src/lib/tls/tls_version.h create mode 100644 comm/third_party/botan/src/lib/utils/assert.cpp create mode 100644 comm/third_party/botan/src/lib/utils/assert.h create mode 100644 comm/third_party/botan/src/lib/utils/bit_ops.h create mode 100644 comm/third_party/botan/src/lib/utils/boost/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/bswap.h create mode 100644 comm/third_party/botan/src/lib/utils/calendar.cpp create mode 100644 comm/third_party/botan/src/lib/utils/calendar.h create mode 100644 comm/third_party/botan/src/lib/utils/charset.cpp create mode 100644 comm/third_party/botan/src/lib/utils/charset.h create mode 100644 comm/third_party/botan/src/lib/utils/codec_base.h create mode 100644 comm/third_party/botan/src/lib/utils/compiler.h create mode 100644 comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp create mode 100644 comm/third_party/botan/src/lib/utils/cpuid/cpuid.h create mode 100644 comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp create mode 100644 comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp create mode 100644 comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp create mode 100644 comm/third_party/botan/src/lib/utils/cpuid/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/ct_utils.cpp create mode 100644 comm/third_party/botan/src/lib/utils/ct_utils.h create mode 100644 comm/third_party/botan/src/lib/utils/data_src.cpp create mode 100644 comm/third_party/botan/src/lib/utils/data_src.h create mode 100644 comm/third_party/botan/src/lib/utils/database.h create mode 100644 comm/third_party/botan/src/lib/utils/donna128.h create mode 100644 comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.cpp create mode 100644 comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.h create mode 100644 comm/third_party/botan/src/lib/utils/dyn_load/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/exceptn.cpp create mode 100644 comm/third_party/botan/src/lib/utils/exceptn.h create mode 100644 comm/third_party/botan/src/lib/utils/filesystem.cpp create mode 100644 comm/third_party/botan/src/lib/utils/filesystem.h create mode 100644 comm/third_party/botan/src/lib/utils/ghash/ghash.cpp create mode 100644 comm/third_party/botan/src/lib/utils/ghash/ghash.h create mode 100644 comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/ghash_cpu.cpp create mode 100644 comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/ghash_vperm.cpp create mode 100644 comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/ghash/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/http_util/http_util.cpp create mode 100644 comm/third_party/botan/src/lib/utils/http_util/http_util.h create mode 100644 comm/third_party/botan/src/lib/utils/http_util/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/loadstor.h create mode 100644 comm/third_party/botan/src/lib/utils/locking_allocator/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.cpp create mode 100644 comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.h create mode 100644 comm/third_party/botan/src/lib/utils/mem_ops.cpp create mode 100644 comm/third_party/botan/src/lib/utils/mem_ops.h create mode 100644 comm/third_party/botan/src/lib/utils/mem_pool/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.cpp create mode 100644 comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.h create mode 100644 comm/third_party/botan/src/lib/utils/mul128.h create mode 100644 comm/third_party/botan/src/lib/utils/mutex.h create mode 100644 comm/third_party/botan/src/lib/utils/os_utils.cpp create mode 100644 comm/third_party/botan/src/lib/utils/os_utils.h create mode 100644 comm/third_party/botan/src/lib/utils/parsing.cpp create mode 100644 comm/third_party/botan/src/lib/utils/parsing.h create mode 100644 comm/third_party/botan/src/lib/utils/poly_dbl/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.cpp create mode 100644 comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.h create mode 100644 comm/third_party/botan/src/lib/utils/prefetch.h create mode 100644 comm/third_party/botan/src/lib/utils/read_cfg.cpp create mode 100644 comm/third_party/botan/src/lib/utils/read_kv.cpp create mode 100644 comm/third_party/botan/src/lib/utils/rotate.h create mode 100644 comm/third_party/botan/src/lib/utils/rounding.h create mode 100644 comm/third_party/botan/src/lib/utils/safeint.h create mode 100644 comm/third_party/botan/src/lib/utils/simd/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/simd/simd_32.h create mode 100644 comm/third_party/botan/src/lib/utils/simd/simd_avx2/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/simd/simd_avx2/simd_avx2.h create mode 100644 comm/third_party/botan/src/lib/utils/socket/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/socket/socket.cpp create mode 100644 comm/third_party/botan/src/lib/utils/socket/socket.h create mode 100644 comm/third_party/botan/src/lib/utils/socket/socket_udp.cpp create mode 100644 comm/third_party/botan/src/lib/utils/socket/socket_udp.h create mode 100644 comm/third_party/botan/src/lib/utils/socket/uri.cpp create mode 100644 comm/third_party/botan/src/lib/utils/socket/uri.h create mode 100644 comm/third_party/botan/src/lib/utils/sqlite3/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.cpp create mode 100644 comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.h create mode 100644 comm/third_party/botan/src/lib/utils/stl_compatibility.h create mode 100644 comm/third_party/botan/src/lib/utils/stl_util.h create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/barrier.cpp create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/barrier.h create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/rwlock.cpp create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/rwlock.h create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/semaphore.cpp create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/semaphore.h create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.cpp create mode 100644 comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.h create mode 100644 comm/third_party/botan/src/lib/utils/timer.cpp create mode 100644 comm/third_party/botan/src/lib/utils/timer.h create mode 100644 comm/third_party/botan/src/lib/utils/types.h create mode 100644 comm/third_party/botan/src/lib/utils/uuid/info.txt create mode 100644 comm/third_party/botan/src/lib/utils/uuid/uuid.cpp create mode 100644 comm/third_party/botan/src/lib/utils/uuid/uuid.h create mode 100644 comm/third_party/botan/src/lib/utils/version.cpp create mode 100644 comm/third_party/botan/src/lib/utils/version.h create mode 100644 comm/third_party/botan/src/lib/x509/asn1_alt_name.cpp create mode 100644 comm/third_party/botan/src/lib/x509/asn1_alt_name.h create mode 100644 comm/third_party/botan/src/lib/x509/asn1_attribute.h create mode 100644 comm/third_party/botan/src/lib/x509/cert_status.cpp create mode 100644 comm/third_party/botan/src/lib/x509/cert_status.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_flatfile/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_sql/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_sqlite3/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system_macos/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.cpp create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.h create mode 100644 comm/third_party/botan/src/lib/x509/certstor_system_windows/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/crl_ent.cpp create mode 100644 comm/third_party/botan/src/lib/x509/crl_ent.h create mode 100644 comm/third_party/botan/src/lib/x509/datastor.cpp create mode 100644 comm/third_party/botan/src/lib/x509/datastor.h create mode 100644 comm/third_party/botan/src/lib/x509/info.txt create mode 100644 comm/third_party/botan/src/lib/x509/key_constraint.cpp create mode 100644 comm/third_party/botan/src/lib/x509/key_constraint.h create mode 100644 comm/third_party/botan/src/lib/x509/name_constraint.cpp create mode 100644 comm/third_party/botan/src/lib/x509/name_constraint.h create mode 100644 comm/third_party/botan/src/lib/x509/ocsp.cpp create mode 100644 comm/third_party/botan/src/lib/x509/ocsp.h create mode 100644 comm/third_party/botan/src/lib/x509/ocsp_types.cpp create mode 100644 comm/third_party/botan/src/lib/x509/ocsp_types.h create mode 100644 comm/third_party/botan/src/lib/x509/pkcs10.cpp create mode 100644 comm/third_party/botan/src/lib/x509/pkcs10.h create mode 100644 comm/third_party/botan/src/lib/x509/pkix_enums.h create mode 100644 comm/third_party/botan/src/lib/x509/pkix_types.h create mode 100644 comm/third_party/botan/src/lib/x509/x509_attribute.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_ca.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_ca.h create mode 100644 comm/third_party/botan/src/lib/x509/x509_crl.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_crl.h create mode 100644 comm/third_party/botan/src/lib/x509/x509_dn.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_dn.h create mode 100644 comm/third_party/botan/src/lib/x509/x509_dn_ub.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_ext.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_ext.h create mode 100644 comm/third_party/botan/src/lib/x509/x509_obj.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509_obj.h create mode 100644 comm/third_party/botan/src/lib/x509/x509cert.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509cert.h create mode 100644 comm/third_party/botan/src/lib/x509/x509opt.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509path.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509path.h create mode 100644 comm/third_party/botan/src/lib/x509/x509self.cpp create mode 100644 comm/third_party/botan/src/lib/x509/x509self.h create mode 100755 comm/third_party/botan/src/python/botan2.py create mode 100644 comm/third_party/botan/src/scripts/Dockerfile.android create mode 100755 comm/third_party/botan/src/scripts/bench.py create mode 100755 comm/third_party/botan/src/scripts/build_docs.py create mode 100644 comm/third_party/botan/src/scripts/check.py create mode 100644 comm/third_party/botan/src/scripts/ci/appveyor.yml create mode 100644 comm/third_party/botan/src/scripts/ci/codecov.yml create mode 100644 comm/third_party/botan/src/scripts/ci/lgtm.yml create mode 100644 comm/third_party/botan/src/scripts/ci/setup_appveyor.bat create mode 100755 comm/third_party/botan/src/scripts/ci/setup_gh_actions.sh create mode 100755 comm/third_party/botan/src/scripts/ci/setup_travis.sh create mode 100644 comm/third_party/botan/src/scripts/ci/travis.yml create mode 100755 comm/third_party/botan/src/scripts/ci_build.py create mode 100755 comm/third_party/botan/src/scripts/ci_check_install.py create mode 100755 comm/third_party/botan/src/scripts/cleanup.py create mode 100755 comm/third_party/botan/src/scripts/comba.py create mode 100755 comm/third_party/botan/src/scripts/create_corpus_zip.py create mode 100755 comm/third_party/botan/src/scripts/dist.py create mode 100755 comm/third_party/botan/src/scripts/docker-android.sh create mode 100755 comm/third_party/botan/src/scripts/ffi_decls.py create mode 100644 comm/third_party/botan/src/scripts/fuzzer.xml create mode 100755 comm/third_party/botan/src/scripts/gen_os_features.py create mode 100755 comm/third_party/botan/src/scripts/install.py create mode 100755 comm/third_party/botan/src/scripts/macro_checks.py create mode 100755 comm/third_party/botan/src/scripts/monty.py create mode 100755 comm/third_party/botan/src/scripts/oids.py create mode 100755 comm/third_party/botan/src/scripts/python_unittests.py create mode 100755 comm/third_party/botan/src/scripts/python_unittests_unix.py create mode 100755 comm/third_party/botan/src/scripts/run_tls_attacker.py create mode 100755 comm/third_party/botan/src/scripts/run_tls_fuzzer.py create mode 100755 comm/third_party/botan/src/scripts/show_dependencies.py create mode 100755 comm/third_party/botan/src/scripts/test_all_configs.py create mode 100755 comm/third_party/botan/src/scripts/test_cli.py create mode 100755 comm/third_party/botan/src/scripts/test_cli_crypt.py create mode 100755 comm/third_party/botan/src/scripts/test_fuzzers.py create mode 100644 comm/third_party/botan/src/scripts/test_python.py create mode 100644 comm/third_party/botan/src/scripts/tls_scanner/boa.txt create mode 100644 comm/third_party/botan/src/scripts/tls_scanner/policy.txt create mode 100644 comm/third_party/botan/src/scripts/tls_scanner/readme.txt create mode 100755 comm/third_party/botan/src/scripts/tls_scanner/tls_scanner.py create mode 100644 comm/third_party/botan/src/scripts/tls_scanner/urls.txt create mode 100755 comm/third_party/botan/src/scripts/tls_suite_info.py create mode 100755 comm/third_party/botan/src/scripts/website.py create mode 100644 comm/third_party/bzip2/CHANGES create mode 100644 comm/third_party/bzip2/Changelog.mzla create mode 100644 comm/third_party/bzip2/LICENSE create mode 100644 comm/third_party/bzip2/README create mode 100644 comm/third_party/bzip2/README.COMPILATION.PROBLEMS create mode 100644 comm/third_party/bzip2/README.XML.STUFF create mode 100644 comm/third_party/bzip2/blocksort.c create mode 100644 comm/third_party/bzip2/bzlib.c create mode 100644 comm/third_party/bzip2/bzlib.h create mode 100644 comm/third_party/bzip2/bzlib_private.h create mode 100644 comm/third_party/bzip2/compress.c create mode 100644 comm/third_party/bzip2/crctable.c create mode 100644 comm/third_party/bzip2/decompress.c create mode 100644 comm/third_party/bzip2/huffman.c create mode 100644 comm/third_party/bzip2/moz.build create mode 100644 comm/third_party/bzip2/randtable.c create mode 100644 comm/third_party/clang/aarch64-apple-darwin.cfg create mode 100644 comm/third_party/clang/aarch64-linux-gnu.cfg create mode 100644 comm/third_party/clang/i686-linux-gnu.cfg create mode 100644 comm/third_party/clang/x86_64-apple-darwin.cfg create mode 100644 comm/third_party/json-c/AUTHORS create mode 100644 comm/third_party/json-c/COPYING create mode 100644 comm/third_party/json-c/ChangeLog create mode 100644 comm/third_party/json-c/INSTALL create mode 100644 comm/third_party/json-c/NEWS create mode 100644 comm/third_party/json-c/README.html create mode 100644 comm/third_party/json-c/README.md create mode 100644 comm/third_party/json-c/RELEASE_CHECKLIST.txt create mode 100644 comm/third_party/json-c/STYLE.txt create mode 100644 comm/third_party/json-c/arraylist.c create mode 100644 comm/third_party/json-c/arraylist.h create mode 100644 comm/third_party/json-c/config.h.in create mode 100644 comm/third_party/json-c/debug.c create mode 100644 comm/third_party/json-c/debug.h create mode 100644 comm/third_party/json-c/json.h.cmakein create mode 100644 comm/third_party/json-c/json_c_version.c create mode 100644 comm/third_party/json-c/json_c_version.h create mode 100644 comm/third_party/json-c/json_config.h.in create mode 100644 comm/third_party/json-c/json_inttypes.h create mode 100644 comm/third_party/json-c/json_object.c create mode 100644 comm/third_party/json-c/json_object.h create mode 100644 comm/third_party/json-c/json_object_iterator.c create mode 100644 comm/third_party/json-c/json_object_iterator.h create mode 100644 comm/third_party/json-c/json_object_private.h create mode 100644 comm/third_party/json-c/json_pointer.c create mode 100644 comm/third_party/json-c/json_pointer.h create mode 100644 comm/third_party/json-c/json_tokener.c create mode 100644 comm/third_party/json-c/json_tokener.h create mode 100644 comm/third_party/json-c/json_types.h create mode 100644 comm/third_party/json-c/json_util.c create mode 100644 comm/third_party/json-c/json_util.h create mode 100644 comm/third_party/json-c/json_visit.c create mode 100644 comm/third_party/json-c/json_visit.h create mode 100644 comm/third_party/json-c/libjson.c create mode 100644 comm/third_party/json-c/linkhash.c create mode 100644 comm/third_party/json-c/linkhash.h create mode 100644 comm/third_party/json-c/math_compat.h create mode 100644 comm/third_party/json-c/moz.build create mode 100644 comm/third_party/json-c/printbuf.c create mode 100644 comm/third_party/json-c/printbuf.h create mode 100644 comm/third_party/json-c/random_seed.c create mode 100644 comm/third_party/json-c/random_seed.h create mode 100644 comm/third_party/json-c/snprintf_compat.h create mode 100644 comm/third_party/json-c/strdup_compat.h create mode 100644 comm/third_party/json-c/strerror_override.c create mode 100644 comm/third_party/json-c/strerror_override.h create mode 100644 comm/third_party/json-c/strerror_override_private.h create mode 100644 comm/third_party/json-c/vasprintf_compat.h create mode 100644 comm/third_party/libgcrypt/AUTHORS create mode 100644 comm/third_party/libgcrypt/COPYING create mode 100644 comm/third_party/libgcrypt/COPYING.LIB create mode 100644 comm/third_party/libgcrypt/ChangeLog create mode 100644 comm/third_party/libgcrypt/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/INSTALL create mode 100644 comm/third_party/libgcrypt/LICENSES create mode 100644 comm/third_party/libgcrypt/Makefile.am create mode 100644 comm/third_party/libgcrypt/Makefile.in create mode 100644 comm/third_party/libgcrypt/NEWS create mode 100644 comm/third_party/libgcrypt/README create mode 100644 comm/third_party/libgcrypt/README.GIT create mode 100644 comm/third_party/libgcrypt/THANKS create mode 100644 comm/third_party/libgcrypt/TODO create mode 100644 comm/third_party/libgcrypt/VERSION create mode 100644 comm/third_party/libgcrypt/acinclude.m4 create mode 100644 comm/third_party/libgcrypt/aclocal.m4 create mode 100644 comm/third_party/libgcrypt/autogen.rc create mode 100755 comm/third_party/libgcrypt/autogen.sh create mode 100644 comm/third_party/libgcrypt/build-aux/ChangeLog-2011 create mode 100755 comm/third_party/libgcrypt/build-aux/compile create mode 100755 comm/third_party/libgcrypt/build-aux/config.guess create mode 100755 comm/third_party/libgcrypt/build-aux/config.rpath create mode 100755 comm/third_party/libgcrypt/build-aux/config.sub create mode 100755 comm/third_party/libgcrypt/build-aux/depcomp create mode 100644 comm/third_party/libgcrypt/build-aux/git-log-fix create mode 100644 comm/third_party/libgcrypt/build-aux/git-log-footer create mode 100755 comm/third_party/libgcrypt/build-aux/install-sh create mode 100644 comm/third_party/libgcrypt/build-aux/ltmain.sh create mode 100755 comm/third_party/libgcrypt/build-aux/mdate-sh create mode 100755 comm/third_party/libgcrypt/build-aux/missing create mode 100644 comm/third_party/libgcrypt/build-aux/texinfo.tex create mode 100644 comm/third_party/libgcrypt/cipher/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/cipher/Makefile.am create mode 100644 comm/third_party/libgcrypt/cipher/Makefile.in create mode 100644 comm/third_party/libgcrypt/cipher/arcfour-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/arcfour.c create mode 100644 comm/third_party/libgcrypt/cipher/asm-common-aarch64.h create mode 100644 comm/third_party/libgcrypt/cipher/asm-common-amd64.h create mode 100644 comm/third_party/libgcrypt/cipher/asm-common-s390x.h create mode 100644 comm/third_party/libgcrypt/cipher/asm-inline-s390x.h create mode 100644 comm/third_party/libgcrypt/cipher/asm-poly1305-aarch64.h create mode 100644 comm/third_party/libgcrypt/cipher/asm-poly1305-amd64.h create mode 100644 comm/third_party/libgcrypt/cipher/asm-poly1305-s390x.h create mode 100644 comm/third_party/libgcrypt/cipher/bithelp.h create mode 100644 comm/third_party/libgcrypt/cipher/blake2.c create mode 100644 comm/third_party/libgcrypt/cipher/blake2b-amd64-avx2.S create mode 100644 comm/third_party/libgcrypt/cipher/blake2s-amd64-avx.S create mode 100644 comm/third_party/libgcrypt/cipher/blowfish-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/blowfish-arm.S create mode 100644 comm/third_party/libgcrypt/cipher/blowfish.c create mode 100644 comm/third_party/libgcrypt/cipher/bufhelp.h create mode 100644 comm/third_party/libgcrypt/cipher/camellia-aarch64.S create mode 100644 comm/third_party/libgcrypt/cipher/camellia-aesni-avx-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/camellia-aesni-avx2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/camellia-arm.S create mode 100644 comm/third_party/libgcrypt/cipher/camellia-glue.c create mode 100644 comm/third_party/libgcrypt/cipher/camellia.c create mode 100644 comm/third_party/libgcrypt/cipher/camellia.h create mode 100644 comm/third_party/libgcrypt/cipher/cast5-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/cast5-arm.S create mode 100644 comm/third_party/libgcrypt/cipher/cast5.c create mode 100644 comm/third_party/libgcrypt/cipher/chacha20-aarch64.S create mode 100644 comm/third_party/libgcrypt/cipher/chacha20-amd64-avx2.S create mode 100644 comm/third_party/libgcrypt/cipher/chacha20-amd64-ssse3.S create mode 100644 comm/third_party/libgcrypt/cipher/chacha20-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/chacha20-ppc.c create mode 100644 comm/third_party/libgcrypt/cipher/chacha20-s390x.S create mode 100644 comm/third_party/libgcrypt/cipher/chacha20.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-aeswrap.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-cbc.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-ccm.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-cfb.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-cmac.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-ctr.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-eax.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-gcm-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch32-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch64-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/cipher-gcm-intel-pclmul.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-gcm.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-internal.h create mode 100644 comm/third_party/libgcrypt/cipher/cipher-ocb.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-ofb.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-poly1305.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-selftest.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher-selftest.h create mode 100644 comm/third_party/libgcrypt/cipher/cipher-xts.c create mode 100644 comm/third_party/libgcrypt/cipher/cipher.c create mode 100644 comm/third_party/libgcrypt/cipher/crc-armv8-aarch64-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/crc-armv8-ce.c create mode 100644 comm/third_party/libgcrypt/cipher/crc-intel-pclmul.c create mode 100644 comm/third_party/libgcrypt/cipher/crc-ppc.c create mode 100644 comm/third_party/libgcrypt/cipher/crc.c create mode 100644 comm/third_party/libgcrypt/cipher/des-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/des.c create mode 100644 comm/third_party/libgcrypt/cipher/dsa-common.c create mode 100644 comm/third_party/libgcrypt/cipher/dsa.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-common.h create mode 100644 comm/third_party/libgcrypt/cipher/ecc-curves.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-ecdh.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-ecdsa.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-eddsa.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-gost.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-misc.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc-sm2.c create mode 100644 comm/third_party/libgcrypt/cipher/ecc.c create mode 100644 comm/third_party/libgcrypt/cipher/elgamal.c create mode 100644 comm/third_party/libgcrypt/cipher/gost-s-box.c create mode 100644 comm/third_party/libgcrypt/cipher/gost.h create mode 100644 comm/third_party/libgcrypt/cipher/gost28147.c create mode 100644 comm/third_party/libgcrypt/cipher/gostr3411-94.c create mode 100644 comm/third_party/libgcrypt/cipher/hash-common.c create mode 100644 comm/third_party/libgcrypt/cipher/hash-common.h create mode 100644 comm/third_party/libgcrypt/cipher/idea.c create mode 100644 comm/third_party/libgcrypt/cipher/kdf-internal.h create mode 100644 comm/third_party/libgcrypt/cipher/kdf.c create mode 100644 comm/third_party/libgcrypt/cipher/keccak-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/keccak.c create mode 100644 comm/third_party/libgcrypt/cipher/keccak_permute_32.h create mode 100644 comm/third_party/libgcrypt/cipher/keccak_permute_64.h create mode 100644 comm/third_party/libgcrypt/cipher/mac-cmac.c create mode 100644 comm/third_party/libgcrypt/cipher/mac-gmac.c create mode 100644 comm/third_party/libgcrypt/cipher/mac-hmac.c create mode 100644 comm/third_party/libgcrypt/cipher/mac-internal.h create mode 100644 comm/third_party/libgcrypt/cipher/mac-poly1305.c create mode 100644 comm/third_party/libgcrypt/cipher/mac.c create mode 100644 comm/third_party/libgcrypt/cipher/md.c create mode 100644 comm/third_party/libgcrypt/cipher/md4.c create mode 100644 comm/third_party/libgcrypt/cipher/md5.c create mode 100644 comm/third_party/libgcrypt/cipher/poly1305-internal.h create mode 100644 comm/third_party/libgcrypt/cipher/poly1305-s390x.S create mode 100644 comm/third_party/libgcrypt/cipher/poly1305.c create mode 100644 comm/third_party/libgcrypt/cipher/primegen.c create mode 100644 comm/third_party/libgcrypt/cipher/pubkey-internal.h create mode 100644 comm/third_party/libgcrypt/cipher/pubkey-util.c create mode 100644 comm/third_party/libgcrypt/cipher/pubkey.c create mode 100644 comm/third_party/libgcrypt/cipher/rfc2268.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-aarch64.S create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-aesni.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-arm.S create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-armv8-aarch32-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-armv8-aarch64-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-armv8-ce.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-internal.h create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-padlock.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-ppc-common.h create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-ppc-functions.h create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-ppc.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-ppc9le.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-s390x.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-ssse3-amd64-asm.S create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-ssse3-amd64.c create mode 100644 comm/third_party/libgcrypt/cipher/rijndael-tables.h create mode 100644 comm/third_party/libgcrypt/cipher/rijndael.c create mode 100644 comm/third_party/libgcrypt/cipher/rmd160.c create mode 100644 comm/third_party/libgcrypt/cipher/rsa-common.c create mode 100644 comm/third_party/libgcrypt/cipher/rsa.c create mode 100644 comm/third_party/libgcrypt/cipher/salsa20-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/salsa20-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/salsa20.c create mode 100644 comm/third_party/libgcrypt/cipher/scrypt.c create mode 100644 comm/third_party/libgcrypt/cipher/seed.c create mode 100644 comm/third_party/libgcrypt/cipher/serpent-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/serpent-avx2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/serpent-sse2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/serpent.c create mode 100644 comm/third_party/libgcrypt/cipher/sha1-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1-armv8-aarch32-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1-armv8-aarch64-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1-avx-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1-avx-bmi2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1-avx2-bmi2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1-intel-shaext.c create mode 100644 comm/third_party/libgcrypt/cipher/sha1-ssse3-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha1.c create mode 100644 comm/third_party/libgcrypt/cipher/sha1.h create mode 100644 comm/third_party/libgcrypt/cipher/sha256-armv8-aarch32-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/sha256-armv8-aarch64-ce.S create mode 100644 comm/third_party/libgcrypt/cipher/sha256-avx-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha256-avx2-bmi2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha256-intel-shaext.c create mode 100644 comm/third_party/libgcrypt/cipher/sha256-ppc.c create mode 100644 comm/third_party/libgcrypt/cipher/sha256-ssse3-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha256.c create mode 100644 comm/third_party/libgcrypt/cipher/sha512-arm.S create mode 100644 comm/third_party/libgcrypt/cipher/sha512-armv7-neon.S create mode 100644 comm/third_party/libgcrypt/cipher/sha512-avx-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha512-avx2-bmi2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha512-ppc.c create mode 100644 comm/third_party/libgcrypt/cipher/sha512-ssse3-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sha512-ssse3-i386.c create mode 100644 comm/third_party/libgcrypt/cipher/sha512.c create mode 100644 comm/third_party/libgcrypt/cipher/sm3.c create mode 100644 comm/third_party/libgcrypt/cipher/sm4-aesni-avx-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sm4-aesni-avx2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/sm4.c create mode 100644 comm/third_party/libgcrypt/cipher/stribog.c create mode 100644 comm/third_party/libgcrypt/cipher/tiger.c create mode 100644 comm/third_party/libgcrypt/cipher/twofish-aarch64.S create mode 100644 comm/third_party/libgcrypt/cipher/twofish-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/twofish-arm.S create mode 100644 comm/third_party/libgcrypt/cipher/twofish-avx2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/twofish.c create mode 100644 comm/third_party/libgcrypt/cipher/whirlpool-sse2-amd64.S create mode 100644 comm/third_party/libgcrypt/cipher/whirlpool.c create mode 100644 comm/third_party/libgcrypt/compat/Makefile.am create mode 100644 comm/third_party/libgcrypt/compat/Makefile.in create mode 100644 comm/third_party/libgcrypt/compat/clock.c create mode 100644 comm/third_party/libgcrypt/compat/compat.c create mode 100644 comm/third_party/libgcrypt/compat/getpid.c create mode 100644 comm/third_party/libgcrypt/compat/libcompat.h create mode 100644 comm/third_party/libgcrypt/config.h.in create mode 100755 comm/third_party/libgcrypt/configure create mode 100644 comm/third_party/libgcrypt/configure.ac create mode 100644 comm/third_party/libgcrypt/doc/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/doc/DCO create mode 100644 comm/third_party/libgcrypt/doc/HACKING create mode 100644 comm/third_party/libgcrypt/doc/Makefile.am create mode 100644 comm/third_party/libgcrypt/doc/Makefile.in create mode 100644 comm/third_party/libgcrypt/doc/README.apichanges create mode 100644 comm/third_party/libgcrypt/doc/fips-fsm.eps create mode 100644 comm/third_party/libgcrypt/doc/fips-fsm.fig create mode 100644 comm/third_party/libgcrypt/doc/fips-fsm.pdf create mode 100644 comm/third_party/libgcrypt/doc/fips-fsm.png create mode 100644 comm/third_party/libgcrypt/doc/gcrypt.info create mode 100644 comm/third_party/libgcrypt/doc/gcrypt.info-1 create mode 100644 comm/third_party/libgcrypt/doc/gcrypt.info-2 create mode 100644 comm/third_party/libgcrypt/doc/gcrypt.texi create mode 100644 comm/third_party/libgcrypt/doc/gpl.texi create mode 100644 comm/third_party/libgcrypt/doc/lgpl.texi create mode 100644 comm/third_party/libgcrypt/doc/libgcrypt-modules.eps create mode 100644 comm/third_party/libgcrypt/doc/libgcrypt-modules.fig create mode 100644 comm/third_party/libgcrypt/doc/libgcrypt-modules.pdf create mode 100644 comm/third_party/libgcrypt/doc/libgcrypt-modules.png create mode 100644 comm/third_party/libgcrypt/doc/stamp-vti create mode 100644 comm/third_party/libgcrypt/doc/version.texi create mode 100644 comm/third_party/libgcrypt/doc/yat2m.c create mode 100644 comm/third_party/libgcrypt/m4/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/m4/Makefile.am create mode 100644 comm/third_party/libgcrypt/m4/Makefile.in create mode 100644 comm/third_party/libgcrypt/m4/ax_cc_for_build.m4 create mode 100644 comm/third_party/libgcrypt/m4/gpg-error.m4 create mode 100644 comm/third_party/libgcrypt/m4/libtool.m4 create mode 100644 comm/third_party/libgcrypt/m4/ltoptions.m4 create mode 100644 comm/third_party/libgcrypt/m4/ltsugar.m4 create mode 100644 comm/third_party/libgcrypt/m4/ltversion.m4 create mode 100644 comm/third_party/libgcrypt/m4/lt~obsolete.m4 create mode 100644 comm/third_party/libgcrypt/m4/noexecstack.m4 create mode 100644 comm/third_party/libgcrypt/m4/socklen.m4 create mode 100644 comm/third_party/libgcrypt/m4/sys_socket_h.m4 create mode 100755 comm/third_party/libgcrypt/mkinstalldirs create mode 100644 comm/third_party/libgcrypt/mpi/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/mpi/Makefile.am create mode 100644 comm/third_party/libgcrypt/mpi/Makefile.in create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/mpi-asm-defs.h create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/aarch64/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/README create mode 100644 comm/third_party/libgcrypt/mpi/alpha/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/alpha/udiv-qrnnd.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/amd64/func_abi.h create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpi-asm-defs.h create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/amd64/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/arm/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/arm/mpi-asm-defs.h create mode 100644 comm/third_party/libgcrypt/mpi/arm/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/arm/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/arm/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/arm/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/arm/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/asm-common-aarch64.h create mode 100644 comm/third_party/libgcrypt/mpi/config.links create mode 100644 comm/third_party/libgcrypt/mpi/ec-ed25519.c create mode 100644 comm/third_party/libgcrypt/mpi/ec-internal.h create mode 100644 comm/third_party/libgcrypt/mpi/ec.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpi-asm-defs.h create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-add1.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-lshift.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-mul1.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-mul2.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-mul3.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-rshift.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/mpih-sub1.c create mode 100644 comm/third_party/libgcrypt/mpi/generic/udiv-w-sdiv.c create mode 100644 comm/third_party/libgcrypt/mpi/hppa/README create mode 100644 comm/third_party/libgcrypt/mpi/hppa/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/hppa/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa/udiv-qrnnd.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa1.1/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/hppa1.1/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa1.1/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa1.1/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/hppa1.1/udiv-qrnnd.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/i386/syntax.h create mode 100644 comm/third_party/libgcrypt/mpi/i586/README create mode 100644 comm/third_party/libgcrypt/mpi/i586/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/i586/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/longlong.h create mode 100644 comm/third_party/libgcrypt/mpi/m68k/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mc68020/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mc68020/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mc68020/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mc68020/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/m68k/syntax.h create mode 100644 comm/third_party/libgcrypt/mpi/mips3/README create mode 100644 comm/third_party/libgcrypt/mpi/mips3/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpi-asm-defs.h create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/mips3/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/mpi-add.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-bit.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-cmp.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-div.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-gcd.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-inline.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-inline.h create mode 100644 comm/third_party/libgcrypt/mpi/mpi-internal.h create mode 100644 comm/third_party/libgcrypt/mpi/mpi-inv.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-mod.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-mpow.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-mul.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-pow.c create mode 100644 comm/third_party/libgcrypt/mpi/mpi-scan.c create mode 100644 comm/third_party/libgcrypt/mpi/mpicoder.c create mode 100644 comm/third_party/libgcrypt/mpi/mpih-const-time.c create mode 100644 comm/third_party/libgcrypt/mpi/mpih-div.c create mode 100644 comm/third_party/libgcrypt/mpi/mpih-mul.c create mode 100644 comm/third_party/libgcrypt/mpi/mpiutil.c create mode 100644 comm/third_party/libgcrypt/mpi/pa7100/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/pa7100/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/pa7100/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/README create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/mmx/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/mmx/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/mmx/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/sse2/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/sse2/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/sse2/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/sse2/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/sse2/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/pentium4/sse2/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/power/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/power/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/mpih-sub1.S create mode 100644 comm/third_party/libgcrypt/mpi/powerpc32/syntax.h create mode 100644 comm/third_party/libgcrypt/mpi/powerpc64/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/sparc32/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/sparc32/mpih-add1.S create mode 100644 comm/third_party/libgcrypt/mpi/sparc32/mpih-lshift.S create mode 100644 comm/third_party/libgcrypt/mpi/sparc32/mpih-rshift.S create mode 100644 comm/third_party/libgcrypt/mpi/sparc32/udiv.S create mode 100644 comm/third_party/libgcrypt/mpi/sparc32v8/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/sparc32v8/mpih-mul1.S create mode 100644 comm/third_party/libgcrypt/mpi/sparc32v8/mpih-mul2.S create mode 100644 comm/third_party/libgcrypt/mpi/sparc32v8/mpih-mul3.S create mode 100644 comm/third_party/libgcrypt/mpi/supersparc/distfiles create mode 100644 comm/third_party/libgcrypt/mpi/supersparc/udiv.S create mode 100644 comm/third_party/libgcrypt/random/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/random/Makefile.am create mode 100644 comm/third_party/libgcrypt/random/Makefile.in create mode 100644 comm/third_party/libgcrypt/random/jitterentropy-base-user.h create mode 100644 comm/third_party/libgcrypt/random/jitterentropy-base.c create mode 100644 comm/third_party/libgcrypt/random/jitterentropy.h create mode 100644 comm/third_party/libgcrypt/random/rand-internal.h create mode 100644 comm/third_party/libgcrypt/random/random-csprng.c create mode 100644 comm/third_party/libgcrypt/random/random-daemon.c create mode 100644 comm/third_party/libgcrypt/random/random-drbg.c create mode 100644 comm/third_party/libgcrypt/random/random-system.c create mode 100644 comm/third_party/libgcrypt/random/random.c create mode 100644 comm/third_party/libgcrypt/random/random.h create mode 100644 comm/third_party/libgcrypt/random/rndegd.c create mode 100644 comm/third_party/libgcrypt/random/rndhw.c create mode 100644 comm/third_party/libgcrypt/random/rndjent.c create mode 100644 comm/third_party/libgcrypt/random/rndlinux.c create mode 100644 comm/third_party/libgcrypt/random/rndunix.c create mode 100644 comm/third_party/libgcrypt/random/rndw32.c create mode 100644 comm/third_party/libgcrypt/random/rndw32ce.c create mode 100644 comm/third_party/libgcrypt/src/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/src/Makefile.am create mode 100644 comm/third_party/libgcrypt/src/Makefile.in create mode 100644 comm/third_party/libgcrypt/src/cipher-proto.h create mode 100644 comm/third_party/libgcrypt/src/cipher.h create mode 100644 comm/third_party/libgcrypt/src/context.c create mode 100644 comm/third_party/libgcrypt/src/context.h create mode 100644 comm/third_party/libgcrypt/src/dumpsexp.c create mode 100644 comm/third_party/libgcrypt/src/ec-context.h create mode 100644 comm/third_party/libgcrypt/src/fips.c create mode 100644 comm/third_party/libgcrypt/src/g10lib.h create mode 100644 comm/third_party/libgcrypt/src/gcrypt-int.h create mode 100644 comm/third_party/libgcrypt/src/gcrypt-testapi.h create mode 100644 comm/third_party/libgcrypt/src/gcrypt.h.in create mode 100644 comm/third_party/libgcrypt/src/gcryptrnd.c create mode 100644 comm/third_party/libgcrypt/src/getrandom.c create mode 100644 comm/third_party/libgcrypt/src/global.c create mode 100644 comm/third_party/libgcrypt/src/hmac256.c create mode 100644 comm/third_party/libgcrypt/src/hmac256.h create mode 100644 comm/third_party/libgcrypt/src/hwf-arm.c create mode 100644 comm/third_party/libgcrypt/src/hwf-common.h create mode 100644 comm/third_party/libgcrypt/src/hwf-ppc.c create mode 100644 comm/third_party/libgcrypt/src/hwf-s390x.c create mode 100644 comm/third_party/libgcrypt/src/hwf-x86.c create mode 100644 comm/third_party/libgcrypt/src/hwfeatures.c create mode 100644 comm/third_party/libgcrypt/src/libgcrypt-config.in create mode 100644 comm/third_party/libgcrypt/src/libgcrypt.def create mode 100644 comm/third_party/libgcrypt/src/libgcrypt.m4 create mode 100644 comm/third_party/libgcrypt/src/libgcrypt.pc.in create mode 100644 comm/third_party/libgcrypt/src/libgcrypt.vers create mode 100644 comm/third_party/libgcrypt/src/misc.c create mode 100644 comm/third_party/libgcrypt/src/missing-string.c create mode 100644 comm/third_party/libgcrypt/src/mpi.h create mode 100644 comm/third_party/libgcrypt/src/mpicalc.c create mode 100644 comm/third_party/libgcrypt/src/secmem.c create mode 100644 comm/third_party/libgcrypt/src/secmem.h create mode 100644 comm/third_party/libgcrypt/src/sexp.c create mode 100644 comm/third_party/libgcrypt/src/stdmem.c create mode 100644 comm/third_party/libgcrypt/src/stdmem.h create mode 100644 comm/third_party/libgcrypt/src/types.h create mode 100644 comm/third_party/libgcrypt/src/versioninfo.rc.in create mode 100644 comm/third_party/libgcrypt/src/visibility.c create mode 100644 comm/third_party/libgcrypt/src/visibility.h create mode 100644 comm/third_party/libgcrypt/tests/ChangeLog-2011 create mode 100644 comm/third_party/libgcrypt/tests/Makefile.am create mode 100644 comm/third_party/libgcrypt/tests/Makefile.in create mode 100644 comm/third_party/libgcrypt/tests/README create mode 100644 comm/third_party/libgcrypt/tests/aeswrap.c create mode 100644 comm/third_party/libgcrypt/tests/basic-disable-all-hwf.in create mode 100644 comm/third_party/libgcrypt/tests/basic.c create mode 100755 comm/third_party/libgcrypt/tests/basic_all_hwfeature_combinations.sh create mode 100644 comm/third_party/libgcrypt/tests/bench-slope.c create mode 100644 comm/third_party/libgcrypt/tests/benchmark.c create mode 100644 comm/third_party/libgcrypt/tests/blake2b.h create mode 100644 comm/third_party/libgcrypt/tests/blake2s.h create mode 100755 comm/third_party/libgcrypt/tests/cavs_driver.pl create mode 100755 comm/third_party/libgcrypt/tests/cavs_tests.sh create mode 100644 comm/third_party/libgcrypt/tests/curves.c create mode 100644 comm/third_party/libgcrypt/tests/dsa-rfc6979.c create mode 100644 comm/third_party/libgcrypt/tests/fips186-dsa.c create mode 100644 comm/third_party/libgcrypt/tests/fipsdrv.c create mode 100644 comm/third_party/libgcrypt/tests/gchash.c create mode 100644 comm/third_party/libgcrypt/tests/genhashdata.c create mode 100755 comm/third_party/libgcrypt/tests/hashtest-256g.in create mode 100644 comm/third_party/libgcrypt/tests/hashtest.c create mode 100644 comm/third_party/libgcrypt/tests/hmac.c create mode 100644 comm/third_party/libgcrypt/tests/keygen.c create mode 100644 comm/third_party/libgcrypt/tests/keygrip.c create mode 100644 comm/third_party/libgcrypt/tests/mpitests.c create mode 100644 comm/third_party/libgcrypt/tests/pkbench.c create mode 100644 comm/third_party/libgcrypt/tests/pkcs1v2-oaep.h create mode 100644 comm/third_party/libgcrypt/tests/pkcs1v2-pss.h create mode 100644 comm/third_party/libgcrypt/tests/pkcs1v2-v15c.h create mode 100644 comm/third_party/libgcrypt/tests/pkcs1v2-v15s.h create mode 100644 comm/third_party/libgcrypt/tests/pkcs1v2.c create mode 100644 comm/third_party/libgcrypt/tests/prime.c create mode 100644 comm/third_party/libgcrypt/tests/pubkey.c create mode 100644 comm/third_party/libgcrypt/tests/random.c create mode 100644 comm/third_party/libgcrypt/tests/rsa-16k.key create mode 100644 comm/third_party/libgcrypt/tests/rsacvt.c create mode 100644 comm/third_party/libgcrypt/tests/sha3-224.h create mode 100644 comm/third_party/libgcrypt/tests/sha3-256.h create mode 100644 comm/third_party/libgcrypt/tests/sha3-384.h create mode 100644 comm/third_party/libgcrypt/tests/sha3-512.h create mode 100644 comm/third_party/libgcrypt/tests/stopwatch.h create mode 100644 comm/third_party/libgcrypt/tests/t-common.h create mode 100644 comm/third_party/libgcrypt/tests/t-convert.c create mode 100644 comm/third_party/libgcrypt/tests/t-cv25519.c create mode 100644 comm/third_party/libgcrypt/tests/t-ed25519.c create mode 100644 comm/third_party/libgcrypt/tests/t-ed25519.inp create mode 100644 comm/third_party/libgcrypt/tests/t-ed448.c create mode 100644 comm/third_party/libgcrypt/tests/t-ed448.inp create mode 100644 comm/third_party/libgcrypt/tests/t-kdf.c create mode 100644 comm/third_party/libgcrypt/tests/t-lock.c create mode 100644 comm/third_party/libgcrypt/tests/t-mpi-bit.c create mode 100644 comm/third_party/libgcrypt/tests/t-mpi-point.c create mode 100644 comm/third_party/libgcrypt/tests/t-secmem.c create mode 100644 comm/third_party/libgcrypt/tests/t-sexp.c create mode 100644 comm/third_party/libgcrypt/tests/t-x448.c create mode 100644 comm/third_party/libgcrypt/tests/testapi.c create mode 100644 comm/third_party/libgcrypt/tests/testdrv.c create mode 100644 comm/third_party/libgcrypt/tests/version.c create mode 100644 comm/third_party/libgpg-error/ABOUT-NLS create mode 100644 comm/third_party/libgpg-error/AUTHORS create mode 100644 comm/third_party/libgpg-error/COPYING create mode 100644 comm/third_party/libgpg-error/COPYING.LIB create mode 100644 comm/third_party/libgpg-error/ChangeLog create mode 100644 comm/third_party/libgpg-error/ChangeLog-2011 create mode 100644 comm/third_party/libgpg-error/INSTALL create mode 100644 comm/third_party/libgpg-error/Makefile.am create mode 100644 comm/third_party/libgpg-error/Makefile.in create mode 100644 comm/third_party/libgpg-error/NEWS create mode 100644 comm/third_party/libgpg-error/README create mode 100644 comm/third_party/libgpg-error/THANKS create mode 100644 comm/third_party/libgpg-error/VERSION create mode 100644 comm/third_party/libgpg-error/aclocal.m4 create mode 100644 comm/third_party/libgpg-error/autogen.rc create mode 100755 comm/third_party/libgpg-error/autogen.sh create mode 100755 comm/third_party/libgpg-error/build-aux/compile create mode 100755 comm/third_party/libgpg-error/build-aux/config.guess create mode 100755 comm/third_party/libgpg-error/build-aux/config.rpath create mode 100755 comm/third_party/libgpg-error/build-aux/config.sub create mode 100755 comm/third_party/libgpg-error/build-aux/depcomp create mode 100644 comm/third_party/libgpg-error/build-aux/git-log-fix create mode 100644 comm/third_party/libgpg-error/build-aux/git-log-footer create mode 100755 comm/third_party/libgpg-error/build-aux/install-sh create mode 100644 comm/third_party/libgpg-error/build-aux/ltmain.sh create mode 100755 comm/third_party/libgpg-error/build-aux/mdate-sh create mode 100755 comm/third_party/libgpg-error/build-aux/missing create mode 100644 comm/third_party/libgpg-error/build-aux/texinfo.tex create mode 100644 comm/third_party/libgpg-error/config.h.in create mode 100755 comm/third_party/libgpg-error/configure create mode 100644 comm/third_party/libgpg-error/configure.ac create mode 100644 comm/third_party/libgpg-error/contrib/ChangeLog-2011 create mode 100644 comm/third_party/libgpg-error/doc/HACKING create mode 100644 comm/third_party/libgpg-error/doc/Makefile.am create mode 100644 comm/third_party/libgpg-error/doc/Makefile.in create mode 100644 comm/third_party/libgpg-error/doc/errorref.txt create mode 100644 comm/third_party/libgpg-error/doc/gpgrt.info create mode 100644 comm/third_party/libgpg-error/doc/gpgrt.texi create mode 100644 comm/third_party/libgpg-error/doc/gpl.texi create mode 100644 comm/third_party/libgpg-error/doc/lgpl.texi create mode 100644 comm/third_party/libgpg-error/doc/stamp-vti create mode 100644 comm/third_party/libgpg-error/doc/version.texi create mode 100644 comm/third_party/libgpg-error/doc/yat2m.c create mode 100644 comm/third_party/libgpg-error/lang/Makefile.am create mode 100644 comm/third_party/libgpg-error/lang/Makefile.in create mode 100644 comm/third_party/libgpg-error/lang/README create mode 100644 comm/third_party/libgpg-error/lang/cl/Makefile.am create mode 100644 comm/third_party/libgpg-error/lang/cl/Makefile.in create mode 100644 comm/third_party/libgpg-error/lang/cl/README create mode 100644 comm/third_party/libgpg-error/lang/cl/gpg-error-package.lisp create mode 100644 comm/third_party/libgpg-error/lang/cl/gpg-error.asd create mode 100644 comm/third_party/libgpg-error/lang/cl/gpg-error.asd.in create mode 100644 comm/third_party/libgpg-error/lang/cl/gpg-error.lisp create mode 100644 comm/third_party/libgpg-error/lang/cl/mkerrcodes.awk create mode 100644 comm/third_party/libgpg-error/libgpg-error.spec create mode 100644 comm/third_party/libgpg-error/libgpg-error.spec.in create mode 100644 comm/third_party/libgpg-error/m4/ChangeLog-2011 create mode 100644 comm/third_party/libgpg-error/m4/Makefile.am create mode 100644 comm/third_party/libgpg-error/m4/Makefile.in create mode 100644 comm/third_party/libgpg-error/m4/autobuild.m4 create mode 100644 comm/third_party/libgpg-error/m4/ax_cc_for_build.m4 create mode 100644 comm/third_party/libgpg-error/m4/codeset.m4 create mode 100644 comm/third_party/libgpg-error/m4/estream.m4 create mode 100644 comm/third_party/libgpg-error/m4/gettext.m4 create mode 100644 comm/third_party/libgpg-error/m4/glibc2.m4 create mode 100644 comm/third_party/libgpg-error/m4/glibc21.m4 create mode 100644 comm/third_party/libgpg-error/m4/gnupg-misc.m4 create mode 100644 comm/third_party/libgpg-error/m4/iconv.m4 create mode 100644 comm/third_party/libgpg-error/m4/intdiv0.m4 create mode 100644 comm/third_party/libgpg-error/m4/intmax.m4 create mode 100644 comm/third_party/libgpg-error/m4/inttypes-h.m4 create mode 100644 comm/third_party/libgpg-error/m4/inttypes-pri.m4 create mode 100644 comm/third_party/libgpg-error/m4/inttypes.m4 create mode 100644 comm/third_party/libgpg-error/m4/inttypes_h.m4 create mode 100644 comm/third_party/libgpg-error/m4/isc-posix.m4 create mode 100644 comm/third_party/libgpg-error/m4/lcmessage.m4 create mode 100644 comm/third_party/libgpg-error/m4/lib-ld.m4 create mode 100644 comm/third_party/libgpg-error/m4/lib-link.m4 create mode 100644 comm/third_party/libgpg-error/m4/lib-prefix.m4 create mode 100644 comm/third_party/libgpg-error/m4/libtool.m4 create mode 100644 comm/third_party/libgpg-error/m4/lock.m4 create mode 100644 comm/third_party/libgpg-error/m4/longdouble.m4 create mode 100644 comm/third_party/libgpg-error/m4/longlong.m4 create mode 100644 comm/third_party/libgpg-error/m4/ltoptions.m4 create mode 100644 comm/third_party/libgpg-error/m4/ltsugar.m4 create mode 100644 comm/third_party/libgpg-error/m4/ltversion.m4 create mode 100644 comm/third_party/libgpg-error/m4/lt~obsolete.m4 create mode 100644 comm/third_party/libgpg-error/m4/nls.m4 create mode 100644 comm/third_party/libgpg-error/m4/po.m4 create mode 100644 comm/third_party/libgpg-error/m4/printf-posix.m4 create mode 100644 comm/third_party/libgpg-error/m4/progtest.m4 create mode 100644 comm/third_party/libgpg-error/m4/readline.m4 create mode 100644 comm/third_party/libgpg-error/m4/signed.m4 create mode 100644 comm/third_party/libgpg-error/m4/size_max.m4 create mode 100644 comm/third_party/libgpg-error/m4/stdint_h.m4 create mode 100644 comm/third_party/libgpg-error/m4/threadlib.m4 create mode 100644 comm/third_party/libgpg-error/m4/uintmax_t.m4 create mode 100644 comm/third_party/libgpg-error/m4/ulonglong.m4 create mode 100644 comm/third_party/libgpg-error/m4/visibility.m4 create mode 100644 comm/third_party/libgpg-error/m4/wchar_t.m4 create mode 100644 comm/third_party/libgpg-error/m4/wint_t.m4 create mode 100644 comm/third_party/libgpg-error/m4/xsize.m4 create mode 100755 comm/third_party/libgpg-error/mkinstalldirs create mode 100644 comm/third_party/libgpg-error/po/ChangeLog-2011 create mode 100644 comm/third_party/libgpg-error/po/LINGUAS create mode 100644 comm/third_party/libgpg-error/po/Makefile.in.in create mode 100644 comm/third_party/libgpg-error/po/Makevars create mode 100644 comm/third_party/libgpg-error/po/POTFILES.in create mode 100644 comm/third_party/libgpg-error/po/Rules-quot create mode 100644 comm/third_party/libgpg-error/po/boldquot.sed create mode 100644 comm/third_party/libgpg-error/po/cs.gmo create mode 100644 comm/third_party/libgpg-error/po/cs.po create mode 100644 comm/third_party/libgpg-error/po/da.gmo create mode 100644 comm/third_party/libgpg-error/po/da.po create mode 100644 comm/third_party/libgpg-error/po/de.gmo create mode 100644 comm/third_party/libgpg-error/po/de.po create mode 100644 comm/third_party/libgpg-error/po/en@boldquot.header create mode 100644 comm/third_party/libgpg-error/po/en@quot.header create mode 100644 comm/third_party/libgpg-error/po/eo.gmo create mode 100644 comm/third_party/libgpg-error/po/eo.po create mode 100644 comm/third_party/libgpg-error/po/es.gmo create mode 100644 comm/third_party/libgpg-error/po/es.po create mode 100644 comm/third_party/libgpg-error/po/fr.gmo create mode 100644 comm/third_party/libgpg-error/po/fr.po create mode 100644 comm/third_party/libgpg-error/po/hu.gmo create mode 100644 comm/third_party/libgpg-error/po/hu.po create mode 100644 comm/third_party/libgpg-error/po/insert-header.sin create mode 100644 comm/third_party/libgpg-error/po/it.gmo create mode 100644 comm/third_party/libgpg-error/po/it.po create mode 100644 comm/third_party/libgpg-error/po/ja.gmo create mode 100644 comm/third_party/libgpg-error/po/ja.po create mode 100644 comm/third_party/libgpg-error/po/libgpg-error.pot create mode 100644 comm/third_party/libgpg-error/po/nl.gmo create mode 100644 comm/third_party/libgpg-error/po/nl.po create mode 100644 comm/third_party/libgpg-error/po/pl.gmo create mode 100644 comm/third_party/libgpg-error/po/pl.po create mode 100644 comm/third_party/libgpg-error/po/pt.gmo create mode 100644 comm/third_party/libgpg-error/po/pt.po create mode 100644 comm/third_party/libgpg-error/po/quot.sed create mode 100644 comm/third_party/libgpg-error/po/remove-potcdate.sin create mode 100644 comm/third_party/libgpg-error/po/ro.gmo create mode 100644 comm/third_party/libgpg-error/po/ro.po create mode 100644 comm/third_party/libgpg-error/po/ru.gmo create mode 100644 comm/third_party/libgpg-error/po/ru.po create mode 100644 comm/third_party/libgpg-error/po/sr.gmo create mode 100644 comm/third_party/libgpg-error/po/sr.po create mode 100644 comm/third_party/libgpg-error/po/stamp-po create mode 100644 comm/third_party/libgpg-error/po/sv.gmo create mode 100644 comm/third_party/libgpg-error/po/sv.po create mode 100644 comm/third_party/libgpg-error/po/uk.gmo create mode 100644 comm/third_party/libgpg-error/po/uk.po create mode 100644 comm/third_party/libgpg-error/po/vi.gmo create mode 100644 comm/third_party/libgpg-error/po/vi.po create mode 100644 comm/third_party/libgpg-error/po/zh_CN.gmo create mode 100644 comm/third_party/libgpg-error/po/zh_CN.po create mode 100644 comm/third_party/libgpg-error/po/zh_TW.gmo create mode 100644 comm/third_party/libgpg-error/po/zh_TW.po create mode 100755 comm/third_party/libgpg-error/potomo create mode 100644 comm/third_party/libgpg-error/src/Makefile.am create mode 100644 comm/third_party/libgpg-error/src/Makefile.in create mode 100644 comm/third_party/libgpg-error/src/README create mode 100644 comm/third_party/libgpg-error/src/argparse.c create mode 100644 comm/third_party/libgpg-error/src/b64dec.c create mode 100644 comm/third_party/libgpg-error/src/b64enc.c create mode 100644 comm/third_party/libgpg-error/src/code-from-errno.c create mode 100644 comm/third_party/libgpg-error/src/code-to-errno.c create mode 100644 comm/third_party/libgpg-error/src/err-codes.h create mode 100644 comm/third_party/libgpg-error/src/err-codes.h.in create mode 100644 comm/third_party/libgpg-error/src/err-sources.h create mode 100644 comm/third_party/libgpg-error/src/err-sources.h.in create mode 100644 comm/third_party/libgpg-error/src/errnos.in create mode 100644 comm/third_party/libgpg-error/src/estream-printf.c create mode 100644 comm/third_party/libgpg-error/src/estream-printf.h create mode 100644 comm/third_party/libgpg-error/src/estream.c create mode 100755 comm/third_party/libgpg-error/src/gen-lock-obj.sh create mode 100644 comm/third_party/libgpg-error/src/gen-posix-lock-obj.c create mode 100644 comm/third_party/libgpg-error/src/gen-w32-lock-obj.c create mode 100644 comm/third_party/libgpg-error/src/gettext.h create mode 100755 comm/third_party/libgpg-error/src/gpg-error-config-test.sh create mode 100644 comm/third_party/libgpg-error/src/gpg-error-config-test.sh.in create mode 100644 comm/third_party/libgpg-error/src/gpg-error-config.in create mode 100644 comm/third_party/libgpg-error/src/gpg-error.c create mode 100644 comm/third_party/libgpg-error/src/gpg-error.def.in create mode 100644 comm/third_party/libgpg-error/src/gpg-error.h.in create mode 100644 comm/third_party/libgpg-error/src/gpg-error.m4 create mode 100644 comm/third_party/libgpg-error/src/gpg-error.pc.in create mode 100644 comm/third_party/libgpg-error/src/gpg-error.vers create mode 100644 comm/third_party/libgpg-error/src/gpg-error.w32-manifest.in create mode 100755 comm/third_party/libgpg-error/src/gpgrt-config create mode 100644 comm/third_party/libgpg-error/src/gpgrt-config.in create mode 100644 comm/third_party/libgpg-error/src/gpgrt-int.h create mode 100644 comm/third_party/libgpg-error/src/gpgrt.m4 create mode 100644 comm/third_party/libgpg-error/src/init.c create mode 100644 comm/third_party/libgpg-error/src/init.h create mode 100644 comm/third_party/libgpg-error/src/lock.h create mode 100644 comm/third_party/libgpg-error/src/logging.c create mode 100644 comm/third_party/libgpg-error/src/mkerrcodes.awk create mode 100644 comm/third_party/libgpg-error/src/mkerrcodes.c create mode 100644 comm/third_party/libgpg-error/src/mkerrcodes1.awk create mode 100644 comm/third_party/libgpg-error/src/mkerrcodes2.awk create mode 100644 comm/third_party/libgpg-error/src/mkerrnos.awk create mode 100644 comm/third_party/libgpg-error/src/mkheader.c create mode 100644 comm/third_party/libgpg-error/src/mkstrtable.awk create mode 100644 comm/third_party/libgpg-error/src/mkw32errmap.c create mode 100644 comm/third_party/libgpg-error/src/posix-lock-obj.h create mode 100644 comm/third_party/libgpg-error/src/posix-lock.c create mode 100644 comm/third_party/libgpg-error/src/posix-thread.c create mode 100644 comm/third_party/libgpg-error/src/protos.h create mode 100644 comm/third_party/libgpg-error/src/spawn-posix.c create mode 100644 comm/third_party/libgpg-error/src/spawn-w32.c create mode 100644 comm/third_party/libgpg-error/src/strerror-sym.c create mode 100644 comm/third_party/libgpg-error/src/strerror.c create mode 100644 comm/third_party/libgpg-error/src/stringutils.c create mode 100644 comm/third_party/libgpg-error/src/strsource-sym.c create mode 100644 comm/third_party/libgpg-error/src/strsource.c create mode 100644 comm/third_party/libgpg-error/src/syscall-clamp.c create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-apple-darwin.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-apple-darwin.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-androideabi.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-gnueabi.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i386-apple-darwin.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-kfreebsd-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mingw32.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64-unknown-linux-gnuabi64.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64el-unknown-linux-gnuabi64.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnuspe.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64le-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv32-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv64-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc64-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-apple-darwin.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnux32.h create mode 100644 comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-musl.h create mode 100644 comm/third_party/libgpg-error/src/sysutils.c create mode 100644 comm/third_party/libgpg-error/src/thread.h create mode 100644 comm/third_party/libgpg-error/src/version.c create mode 100644 comm/third_party/libgpg-error/src/versioninfo.rc.in create mode 100644 comm/third_party/libgpg-error/src/visibility.c create mode 100644 comm/third_party/libgpg-error/src/visibility.h create mode 100644 comm/third_party/libgpg-error/src/w32-add.h create mode 100644 comm/third_party/libgpg-error/src/w32-estream.c create mode 100644 comm/third_party/libgpg-error/src/w32-gettext.c create mode 100644 comm/third_party/libgpg-error/src/w32-iconv.c create mode 100644 comm/third_party/libgpg-error/src/w32-lock-obj.h create mode 100644 comm/third_party/libgpg-error/src/w32-lock.c create mode 100644 comm/third_party/libgpg-error/src/w32-reg.c create mode 100644 comm/third_party/libgpg-error/src/w32-thread.c create mode 100644 comm/third_party/libgpg-error/src/w32ce-add.h create mode 100644 comm/third_party/libgpg-error/tests/Makefile.am create mode 100644 comm/third_party/libgpg-error/tests/Makefile.in create mode 100644 comm/third_party/libgpg-error/tests/etc/t-argparse.conf create mode 100644 comm/third_party/libgpg-error/tests/t-argparse.c create mode 100644 comm/third_party/libgpg-error/tests/t-argparse.conf create mode 100644 comm/third_party/libgpg-error/tests/t-b64.c create mode 100644 comm/third_party/libgpg-error/tests/t-common.h create mode 100644 comm/third_party/libgpg-error/tests/t-lock.c create mode 100644 comm/third_party/libgpg-error/tests/t-logging.c create mode 100644 comm/third_party/libgpg-error/tests/t-malloc.c create mode 100644 comm/third_party/libgpg-error/tests/t-poll.c create mode 100644 comm/third_party/libgpg-error/tests/t-printf.c create mode 100644 comm/third_party/libgpg-error/tests/t-strerror.c create mode 100644 comm/third_party/libgpg-error/tests/t-stringutils.c create mode 100644 comm/third_party/libgpg-error/tests/t-syserror.c create mode 100644 comm/third_party/libgpg-error/tests/t-version.c create mode 100644 comm/third_party/libotr/AUTHORS create mode 100644 comm/third_party/libotr/COPYING create mode 100644 comm/third_party/libotr/COPYING.LIB create mode 100644 comm/third_party/libotr/ChangeLog create mode 100644 comm/third_party/libotr/INSTALL create mode 100644 comm/third_party/libotr/Makefile.am create mode 100644 comm/third_party/libotr/Makefile.in create mode 100644 comm/third_party/libotr/NEWS create mode 100644 comm/third_party/libotr/Protocol-v3.html create mode 100644 comm/third_party/libotr/README create mode 100644 comm/third_party/libotr/UPGRADING create mode 100644 comm/third_party/libotr/aclocal.m4 create mode 100755 comm/third_party/libotr/bootstrap create mode 100755 comm/third_party/libotr/config.guess create mode 100644 comm/third_party/libotr/config.h.in create mode 100755 comm/third_party/libotr/config.sub create mode 100755 comm/third_party/libotr/config/compile create mode 100755 comm/third_party/libotr/config/config.guess create mode 100755 comm/third_party/libotr/config/config.sub create mode 100755 comm/third_party/libotr/config/depcomp create mode 100755 comm/third_party/libotr/config/install-sh create mode 100644 comm/third_party/libotr/config/libtool.m4 create mode 100644 comm/third_party/libotr/config/ltmain.sh create mode 100644 comm/third_party/libotr/config/ltoptions.m4 create mode 100644 comm/third_party/libotr/config/ltsugar.m4 create mode 100644 comm/third_party/libotr/config/ltversion.m4 create mode 100644 comm/third_party/libotr/config/lt~obsolete.m4 create mode 100755 comm/third_party/libotr/config/missing create mode 100755 comm/third_party/libotr/configure create mode 100644 comm/third_party/libotr/configure.ac create mode 100755 comm/third_party/libotr/install-sh create mode 100644 comm/third_party/libotr/libotr.m4 create mode 100644 comm/third_party/libotr/libotr.pc.in create mode 100644 comm/third_party/libotr/ltmain.sh create mode 100644 comm/third_party/libotr/packaging/fedora/libotr.spec create mode 100644 comm/third_party/libotr/src/Makefile.am create mode 100644 comm/third_party/libotr/src/Makefile.in create mode 100644 comm/third_party/libotr/src/auth.c create mode 100644 comm/third_party/libotr/src/auth.h create mode 100644 comm/third_party/libotr/src/b64.c create mode 100644 comm/third_party/libotr/src/b64.h create mode 100644 comm/third_party/libotr/src/context.c create mode 100644 comm/third_party/libotr/src/context.h create mode 100644 comm/third_party/libotr/src/context_priv.c create mode 100644 comm/third_party/libotr/src/context_priv.h create mode 100644 comm/third_party/libotr/src/dh.c create mode 100644 comm/third_party/libotr/src/dh.h create mode 100644 comm/third_party/libotr/src/instag.c create mode 100644 comm/third_party/libotr/src/instag.h create mode 100644 comm/third_party/libotr/src/mem.c create mode 100644 comm/third_party/libotr/src/mem.h create mode 100644 comm/third_party/libotr/src/message.c create mode 100644 comm/third_party/libotr/src/message.h create mode 100644 comm/third_party/libotr/src/privkey-t.h create mode 100644 comm/third_party/libotr/src/privkey.c create mode 100644 comm/third_party/libotr/src/privkey.h create mode 100644 comm/third_party/libotr/src/proto.c create mode 100644 comm/third_party/libotr/src/proto.h create mode 100644 comm/third_party/libotr/src/serial.h create mode 100644 comm/third_party/libotr/src/sm.c create mode 100644 comm/third_party/libotr/src/sm.h create mode 100644 comm/third_party/libotr/src/tlv.c create mode 100644 comm/third_party/libotr/src/tlv.h create mode 100644 comm/third_party/libotr/src/userstate.c create mode 100644 comm/third_party/libotr/src/userstate.h create mode 100644 comm/third_party/libotr/src/version.h create mode 100644 comm/third_party/libotr/tests/Makefile.am create mode 100644 comm/third_party/libotr/tests/Makefile.in create mode 100644 comm/third_party/libotr/tests/regression/Makefile.am create mode 100644 comm/third_party/libotr/tests/regression/Makefile.in create mode 100644 comm/third_party/libotr/tests/regression/client/Makefile.am create mode 100644 comm/third_party/libotr/tests/regression/client/Makefile.in create mode 100644 comm/third_party/libotr/tests/regression/client/client.c create mode 100644 comm/third_party/libotr/tests/regression/client/otr.key create mode 100755 comm/third_party/libotr/tests/regression/random-msg-auth.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg-disconnect-auth.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg-disconnect-frag-auth.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg-disconnect-frag.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg-disconnect.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg-fast.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg-frag.sh create mode 100755 comm/third_party/libotr/tests/regression/random-msg.sh create mode 100755 comm/third_party/libotr/tests/run.sh create mode 100644 comm/third_party/libotr/tests/test_list create mode 100644 comm/third_party/libotr/tests/unit/Makefile.am create mode 100644 comm/third_party/libotr/tests/unit/Makefile.in create mode 100644 comm/third_party/libotr/tests/unit/instag.txt create mode 100644 comm/third_party/libotr/tests/unit/test_auth.c create mode 100644 comm/third_party/libotr/tests/unit/test_b64.c create mode 100644 comm/third_party/libotr/tests/unit/test_context.c create mode 100644 comm/third_party/libotr/tests/unit/test_dh.c create mode 100644 comm/third_party/libotr/tests/unit/test_instag.c create mode 100644 comm/third_party/libotr/tests/unit/test_mem.c create mode 100644 comm/third_party/libotr/tests/unit/test_privkey.c create mode 100644 comm/third_party/libotr/tests/unit/test_proto.c create mode 100644 comm/third_party/libotr/tests/unit/test_sm.c create mode 100644 comm/third_party/libotr/tests/unit/test_tlv.c create mode 100644 comm/third_party/libotr/tests/unit/test_userstate.c create mode 100644 comm/third_party/libotr/tests/utils/Makefile.am create mode 100644 comm/third_party/libotr/tests/utils/Makefile.in create mode 100644 comm/third_party/libotr/tests/utils/tap/Makefile.am create mode 100644 comm/third_party/libotr/tests/utils/tap/Makefile.in create mode 100644 comm/third_party/libotr/tests/utils/tap/tap.c create mode 100644 comm/third_party/libotr/tests/utils/tap/tap.h create mode 100755 comm/third_party/libotr/tests/utils/tap/tap.sh create mode 100644 comm/third_party/libotr/tests/utils/utils.c create mode 100644 comm/third_party/libotr/tests/utils/utils.h create mode 100644 comm/third_party/libotr/toolkit/Makefile.am create mode 100644 comm/third_party/libotr/toolkit/Makefile.in create mode 100644 comm/third_party/libotr/toolkit/aes.c create mode 100644 comm/third_party/libotr/toolkit/aes.h create mode 100644 comm/third_party/libotr/toolkit/ctrmode.c create mode 100644 comm/third_party/libotr/toolkit/ctrmode.h create mode 100644 comm/third_party/libotr/toolkit/otr_mackey.c create mode 100644 comm/third_party/libotr/toolkit/otr_modify.c create mode 100644 comm/third_party/libotr/toolkit/otr_parse.c create mode 100644 comm/third_party/libotr/toolkit/otr_readforge.c create mode 100644 comm/third_party/libotr/toolkit/otr_remac.c create mode 100644 comm/third_party/libotr/toolkit/otr_sesskeys.c create mode 100644 comm/third_party/libotr/toolkit/otr_toolkit.1 create mode 100644 comm/third_party/libotr/toolkit/parse.c create mode 100644 comm/third_party/libotr/toolkit/parse.h create mode 100644 comm/third_party/libotr/toolkit/readotr.c create mode 100644 comm/third_party/libotr/toolkit/readotr.h create mode 100644 comm/third_party/libotr/toolkit/sesskeys.c create mode 100644 comm/third_party/libotr/toolkit/sesskeys.h create mode 100644 comm/third_party/libotr/toolkit/sha1hmac.c create mode 100644 comm/third_party/libotr/toolkit/sha1hmac.h create mode 100644 comm/third_party/moz.build create mode 100644 comm/third_party/niwcompat/dirent.h create mode 100644 comm/third_party/niwcompat/extra_include.h create mode 100644 comm/third_party/niwcompat/getopt.c create mode 100644 comm/third_party/niwcompat/getopt.h create mode 100644 comm/third_party/openpgp.configure create mode 100644 comm/third_party/patches/rnp/bug1843535_gcc13_missing_header.patch create mode 100644 comm/third_party/python/fluent.migratetb/LICENSE create mode 100644 comm/third_party/python/fluent.migratetb/PKG-INFO create mode 100644 comm/third_party/python/fluent.migratetb/README.md create mode 100644 comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/PKG-INFO create mode 100644 comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/SOURCES.txt create mode 100644 comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/dependency_links.txt create mode 100644 comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/entry_points.txt create mode 100644 comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/requires.txt create mode 100644 comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/top_level.txt create mode 100644 comm/third_party/python/fluent.migratetb/fluent/__init__.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/__init__.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/_context.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/blame.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/changesets.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/context.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/errors.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/evaluator.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/helpers.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/merge.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/tool.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/transforms.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/util.py create mode 100644 comm/third_party/python/fluent.migratetb/fluent/migratetb/validator.py create mode 100644 comm/third_party/python/fluent.migratetb/setup.cfg create mode 100644 comm/third_party/python/fluent.migratetb/setup.py create mode 100644 comm/third_party/rnp/CHANGELOG.md create mode 100644 comm/third_party/rnp/LICENSE-OCB.md create mode 100644 comm/third_party/rnp/LICENSE.md create mode 100644 comm/third_party/rnp/README.adoc create mode 100644 comm/third_party/rnp/doc/tests/README.md create mode 100644 comm/third_party/rnp/doc/tests/rnpkeys-generate-key.md create mode 100644 comm/third_party/rnp/docs/c-usage.adoc create mode 100644 comm/third_party/rnp/docs/cli-usage.adoc create mode 100644 comm/third_party/rnp/docs/code-of-conduct.adoc create mode 100644 comm/third_party/rnp/docs/develop.adoc create mode 100644 comm/third_party/rnp/docs/develop/cpp-usage.adoc create mode 100644 comm/third_party/rnp/docs/develop/packaging.adoc create mode 100644 comm/third_party/rnp/docs/develop/release-workflow.adoc create mode 100644 comm/third_party/rnp/docs/installation.adoc create mode 100644 comm/third_party/rnp/docs/navigation.adoc create mode 100644 comm/third_party/rnp/docs/signing-keys.adoc create mode 100644 comm/third_party/rnp/include/rekey/rnp_key_store.h create mode 100644 comm/third_party/rnp/include/repgp/repgp_def.h create mode 100644 comm/third_party/rnp/include/rnp.h create mode 100644 comm/third_party/rnp/include/rnp/rnp.h create mode 100644 comm/third_party/rnp/include/rnp/rnp_def.h create mode 100644 comm/third_party/rnp/include/rnp/rnp_err.h create mode 100644 comm/third_party/rnp/module.ver create mode 100644 comm/third_party/rnp/moz.build create mode 100644 comm/third_party/rnp/moz.yaml create mode 100644 comm/third_party/rnp/rnp.symbols create mode 100644 comm/third_party/rnp/src/common/CMakeLists.txt create mode 100644 comm/third_party/rnp/src/common/file-utils.cpp create mode 100644 comm/third_party/rnp/src/common/file-utils.h create mode 100644 comm/third_party/rnp/src/common/getoptwin.h create mode 100644 comm/third_party/rnp/src/common/str-utils.cpp create mode 100644 comm/third_party/rnp/src/common/str-utils.h create mode 100644 comm/third_party/rnp/src/common/time-utils.cpp create mode 100644 comm/third_party/rnp/src/common/time-utils.h create mode 100644 comm/third_party/rnp/src/common/uniwin.h create mode 100644 comm/third_party/rnp/src/examples/CMakeLists.txt create mode 100644 comm/third_party/rnp/src/examples/README.md create mode 100644 comm/third_party/rnp/src/examples/decrypt.c create mode 100644 comm/third_party/rnp/src/examples/dump.c create mode 100644 comm/third_party/rnp/src/examples/encrypt.c create mode 100644 comm/third_party/rnp/src/examples/generate.c create mode 100644 comm/third_party/rnp/src/examples/sign.c create mode 100644 comm/third_party/rnp/src/examples/verify.c create mode 100644 comm/third_party/rnp/src/fuzzing/CMakeLists.txt create mode 100644 comm/third_party/rnp/src/fuzzing/dump.c create mode 100644 comm/third_party/rnp/src/fuzzing/keyimport.c create mode 100644 comm/third_party/rnp/src/fuzzing/keyring.c create mode 100644 comm/third_party/rnp/src/fuzzing/keyring_g10.cpp create mode 100644 comm/third_party/rnp/src/fuzzing/keyring_kbx.c create mode 100644 comm/third_party/rnp/src/fuzzing/sigimport.c create mode 100644 comm/third_party/rnp/src/fuzzing/verify.c create mode 100644 comm/third_party/rnp/src/fuzzing/verify_detached.c create mode 100755 comm/third_party/rnp/src/lib/CMakeLists.txt create mode 100644 comm/third_party/rnp/src/lib/config.h.in create mode 100644 comm/third_party/rnp/src/lib/crypto.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto.h create mode 100644 comm/third_party/rnp/src/lib/crypto/backend_version.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/backend_version.h create mode 100644 comm/third_party/rnp/src/lib/crypto/bn.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/bn.h create mode 100644 comm/third_party/rnp/src/lib/crypto/bn_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/cipher.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/cipher.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/cipher_botan.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/cipher_botan.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/cipher_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/cipher_ossl.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/common.h create mode 100644 comm/third_party/rnp/src/lib/crypto/dl_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/dl_ossl.h create mode 100644 comm/third_party/rnp/src/lib/crypto/dsa.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/dsa.h create mode 100644 comm/third_party/rnp/src/lib/crypto/dsa_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ec.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ec.h create mode 100644 comm/third_party/rnp/src/lib/crypto/ec_curves.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ec_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ec_ossl.h create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdh.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdh.h create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdh_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdh_utils.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdh_utils.h create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdsa.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdsa.h create mode 100644 comm/third_party/rnp/src/lib/crypto/ecdsa_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/eddsa.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/eddsa.h create mode 100644 comm/third_party/rnp/src/lib/crypto/eddsa_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/elgamal.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/elgamal.h create mode 100644 comm/third_party/rnp/src/lib/crypto/elgamal_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_botan.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_common.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_crc24.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_crc24.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_ossl.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_sha1cd.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/hash_sha1cd.hpp create mode 100644 comm/third_party/rnp/src/lib/crypto/mem.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/mem.h create mode 100644 comm/third_party/rnp/src/lib/crypto/mem_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/mpi.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/mpi.h create mode 100644 comm/third_party/rnp/src/lib/crypto/ossl_common.h create mode 100644 comm/third_party/rnp/src/lib/crypto/rng.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/rng.h create mode 100644 comm/third_party/rnp/src/lib/crypto/rng_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/rsa.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/rsa.h create mode 100644 comm/third_party/rnp/src/lib/crypto/rsa_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/s2k.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/s2k.h create mode 100644 comm/third_party/rnp/src/lib/crypto/s2k_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.c create mode 100644 comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.h create mode 100644 comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.c create mode 100644 comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.h create mode 100644 comm/third_party/rnp/src/lib/crypto/signatures.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/signatures.h create mode 100644 comm/third_party/rnp/src/lib/crypto/sm2.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/sm2.h create mode 100644 comm/third_party/rnp/src/lib/crypto/sm2_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/symmetric.cpp create mode 100644 comm/third_party/rnp/src/lib/crypto/symmetric.h create mode 100644 comm/third_party/rnp/src/lib/crypto/symmetric_ossl.cpp create mode 100644 comm/third_party/rnp/src/lib/defaults.h create mode 100644 comm/third_party/rnp/src/lib/ffi-priv-types.h create mode 100644 comm/third_party/rnp/src/lib/fingerprint.cpp create mode 100644 comm/third_party/rnp/src/lib/fingerprint.h create mode 100644 comm/third_party/rnp/src/lib/generate-key.cpp create mode 100644 comm/third_party/rnp/src/lib/json-utils.cpp create mode 100644 comm/third_party/rnp/src/lib/json-utils.h create mode 100644 comm/third_party/rnp/src/lib/key-provider.cpp create mode 100644 comm/third_party/rnp/src/lib/key-provider.h create mode 100644 comm/third_party/rnp/src/lib/librnp.3.adoc create mode 100644 comm/third_party/rnp/src/lib/librnp.symbols create mode 100644 comm/third_party/rnp/src/lib/librnp.vsc create mode 100644 comm/third_party/rnp/src/lib/logging.cpp create mode 100644 comm/third_party/rnp/src/lib/logging.h create mode 100644 comm/third_party/rnp/src/lib/pass-provider.cpp create mode 100644 comm/third_party/rnp/src/lib/pass-provider.h create mode 100644 comm/third_party/rnp/src/lib/pgp-key.cpp create mode 100644 comm/third_party/rnp/src/lib/pgp-key.h create mode 100644 comm/third_party/rnp/src/lib/rnp.cpp create mode 100644 comm/third_party/rnp/src/lib/rnp/rnp_export.h create mode 100644 comm/third_party/rnp/src/lib/sec_profile.cpp create mode 100644 comm/third_party/rnp/src/lib/sec_profile.hpp create mode 100644 comm/third_party/rnp/src/lib/types.h create mode 100644 comm/third_party/rnp/src/lib/utils.cpp create mode 100644 comm/third_party/rnp/src/lib/utils.h create mode 100644 comm/third_party/rnp/src/lib/version.h.in create mode 100644 comm/third_party/rnp/src/librekey/g23_sexp.hpp create mode 100644 comm/third_party/rnp/src/librekey/kbx_blob.hpp create mode 100644 comm/third_party/rnp/src/librekey/key_store_g10.cpp create mode 100644 comm/third_party/rnp/src/librekey/key_store_g10.h create mode 100644 comm/third_party/rnp/src/librekey/key_store_kbx.cpp create mode 100644 comm/third_party/rnp/src/librekey/key_store_kbx.h create mode 100644 comm/third_party/rnp/src/librekey/key_store_pgp.cpp create mode 100644 comm/third_party/rnp/src/librekey/key_store_pgp.h create mode 100644 comm/third_party/rnp/src/librekey/rnp_key_store.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-armor.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-armor.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-common.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-common.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-ctx.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-ctx.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-def.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-dump.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-dump.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-key.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-key.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-packet.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-packet.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-parse.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-parse.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-sig.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-sig.h create mode 100644 comm/third_party/rnp/src/librepgp/stream-write.cpp create mode 100644 comm/third_party/rnp/src/librepgp/stream-write.h create mode 100644 comm/third_party/rnp/src/libsexp/LICENSE.md create mode 100644 comm/third_party/rnp/src/libsexp/README.adoc create mode 100644 comm/third_party/rnp/src/libsexp/include/sexp/ext-key-format.h create mode 100644 comm/third_party/rnp/src/libsexp/include/sexp/sexp-error.h create mode 100644 comm/third_party/rnp/src/libsexp/include/sexp/sexp.h create mode 100644 comm/third_party/rnp/src/libsexp/src/ext-key-format.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-char-defs.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-error.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-input.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-main.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-object.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-output.cpp create mode 100644 comm/third_party/rnp/src/libsexp/src/sexp-simple-string.cpp create mode 100644 comm/third_party/rnp/src/libsexp/version.txt create mode 100644 comm/third_party/rnp/src/rnp/CMakeLists.txt create mode 100644 comm/third_party/rnp/src/rnp/fficli.cpp create mode 100644 comm/third_party/rnp/src/rnp/fficli.h create mode 100644 comm/third_party/rnp/src/rnp/moz.build create mode 100644 comm/third_party/rnp/src/rnp/rnp.1.adoc create mode 100644 comm/third_party/rnp/src/rnp/rnp.cpp create mode 100644 comm/third_party/rnp/src/rnp/rnpcfg.cpp create mode 100644 comm/third_party/rnp/src/rnp/rnpcfg.h create mode 100644 comm/third_party/rnp/src/rnpkeys/CMakeLists.txt create mode 100644 comm/third_party/rnp/src/rnpkeys/main.cpp create mode 100644 comm/third_party/rnp/src/rnpkeys/moz.build create mode 100644 comm/third_party/rnp/src/rnpkeys/rnpkeys.1.adoc create mode 100644 comm/third_party/rnp/src/rnpkeys/rnpkeys.cpp create mode 100644 comm/third_party/rnp/src/rnpkeys/rnpkeys.h create mode 100644 comm/third_party/rnp/src/rnpkeys/tui.cpp create mode 100644 comm/third_party/rnp/version.txt create mode 100644 comm/third_party/rnpdefs.mozbuild create mode 100644 comm/third_party/zlib/ChangeLog create mode 100644 comm/third_party/zlib/FAQ create mode 100644 comm/third_party/zlib/INDEX create mode 100644 comm/third_party/zlib/LICENSE create mode 100644 comm/third_party/zlib/README create mode 100644 comm/third_party/zlib/adler32.c create mode 100644 comm/third_party/zlib/compress.c create mode 100644 comm/third_party/zlib/crc32.c create mode 100644 comm/third_party/zlib/crc32.h create mode 100644 comm/third_party/zlib/deflate.c create mode 100644 comm/third_party/zlib/deflate.h create mode 100644 comm/third_party/zlib/gzclose.c create mode 100644 comm/third_party/zlib/gzguts.h create mode 100644 comm/third_party/zlib/gzlib.c create mode 100644 comm/third_party/zlib/gzread.c create mode 100644 comm/third_party/zlib/gzwrite.c create mode 100644 comm/third_party/zlib/infback.c create mode 100644 comm/third_party/zlib/inffast.c create mode 100644 comm/third_party/zlib/inffast.h create mode 100644 comm/third_party/zlib/inffixed.h create mode 100644 comm/third_party/zlib/inflate.c create mode 100644 comm/third_party/zlib/inflate.h create mode 100644 comm/third_party/zlib/inftrees.c create mode 100644 comm/third_party/zlib/inftrees.h create mode 100644 comm/third_party/zlib/moz.build create mode 100644 comm/third_party/zlib/moz.yaml create mode 100644 comm/third_party/zlib/trees.c create mode 100644 comm/third_party/zlib/trees.h create mode 100644 comm/third_party/zlib/uncompr.c create mode 100644 comm/third_party/zlib/zconf.h create mode 100644 comm/third_party/zlib/zlib.h create mode 100644 comm/third_party/zlib/zutil.c create mode 100644 comm/third_party/zlib/zutil.h (limited to 'comm/third_party') diff --git a/comm/third_party/Makefile.in b/comm/third_party/Makefile.in new file mode 100644 index 0000000000..fc5e8d2440 --- /dev/null +++ b/comm/third_party/Makefile.in @@ -0,0 +1,31 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/config/rules.mk + +print-%: ; @echo $* is $($*) +origin-%: ; @echo $* origin $(origin $*) + +ifdef TB_LIBOTR_PREBUILT + +ifeq (WINNT,$(OS_ARCH)) +OTR_LIBS := libotr.dll libssp-0.dll +endif + +ifeq (Darwin,$(OS_ARCH)) +OTR_LIBS := libotr.dylib +endif + +ifeq (Linux,$(OS_ARCH)) +OTR_LIBS := libotr.so +endif + +OTR_LIB_PATHS := $(foreach otrlib,$(OTR_LIBS),$(TB_LIBOTR_PREBUILT)/$(otrlib)) + +libs:: $(OTR_LIB_PATHS) + $(NSINSTALL) -t -m 755 $(OTR_LIB_PATHS) $(DIST)/bin + +endif ## TB_LIBOTR_PREBUILT diff --git a/comm/third_party/README.asn1js b/comm/third_party/README.asn1js new file mode 100644 index 0000000000..c1c98872c3 --- /dev/null +++ b/comm/third_party/README.asn1js @@ -0,0 +1,19 @@ +Directory ./asn1js contains a bundled version of asn1js, which has been obtained from: +https://github.com/PeculiarVentures/asn1.js + +For licensing information, please refer to the included documentation. + +[tag v3.0.5] + +Updating: +- cd $topsrcdir/comm +- ../mach vendor -r third_party/asn1js/moz.yaml +- Review the changes +- Commit the changes +- Run test_LDAPMessage.js + + +The tag information in this file is automatically updated. The moz.yaml file +is automatically updated. If upstream changes require updating moz.build, that +must be done with a manual step. + diff --git a/comm/third_party/README.botan b/comm/third_party/README.botan new file mode 100644 index 0000000000..6fab2ecee1 --- /dev/null +++ b/comm/third_party/README.botan @@ -0,0 +1,20 @@ +Directory ./botan contains a copy of version 2.18.2 of the Botan library, +which has been obtained from https://botan.randombit.net/releases/Botan-2.18.2.tar.xz . + +For licensing information, please refer to the included documentation. + +The SHA256SUM of the imported file is: +541a3b13f1b9d30f977c6c1ae4c7bfdfda763cda6e44de807369dce79f42307e Botan-2.18.2.tar.xz + +The following files were removed from the source distribution: +.github/ +.gitignore +.lgtm.yml +.travis.yml +src/tests + +The following files were added to the source's root by MZLA Technologies: +moz.build +botan.mozbuild +botan_configure.py +Makefile.in diff --git a/comm/third_party/README.bzip2 b/comm/third_party/README.bzip2 new file mode 100644 index 0000000000..0060ae3d20 --- /dev/null +++ b/comm/third_party/README.bzip2 @@ -0,0 +1,44 @@ +Directory ./bzip2 contains a copy of version 1.0.8 of the bzip2 library, +which has been obtained from https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz . + +For licensing information, please refer to the included documentation. + +The SHA512SUM of the imported file is: +083f5e675d73f3233c7930ebe20425a533feedeaaa9d8cc86831312a6581cefbe6ed0d08d2fa89be81082f2a5abdabca8b3c080bf97218a1bd59dc118a30b9f3 bzip2-1.0.8.tar.gz + + +The following files were removed from the source distribution's root: +Makefile +Makefile-libbz2_so +bzdiff +bzdiff.1 +bzgrep +bzgrep.1 +bzip.css +bzip2.{1,1.preformatted,c,txt} +bzip2recover.c +bzmore +bzmore.1 +dlltest.c +dlltest.dsp +entities.xml +format.pl +libbzip2.def +libbzip2.dsp +makefile.msc +manual.{html,pdf,ps,xml} +mk251.c +sample* +spewG.c +unzcrash.c +words* +xmlproc.sh +*xsl + +The following files were added to the source's root by MZLA Technologies: +Changelog.mzla +moz.build + + +Currently there is no support for building against an external bzip2 library. +See bug: diff --git a/comm/third_party/README.json-c b/comm/third_party/README.json-c new file mode 100644 index 0000000000..187915d539 --- /dev/null +++ b/comm/third_party/README.json-c @@ -0,0 +1,36 @@ +Directory ./json-c contains a copy of version 0.16 of the json-c library, +which has been obtained from https://s3.amazonaws.com/json-c_releases/releases/json-c-0.16-nodoc.tar.gz . +(Link at https://github.com/json-c/json-c/wiki). + +For licensing information, please refer to the included documentation. + +The SHA256SUM of the imported file is: +ac8a3dd6820daaca579b23fbc74664310fbc3d67f52f6707cda67d21dde5570f json-c-0.16-nodoc.tar.gz + +The following files and directories were removed from the source distribution's root: +.github/ +apps/ +bench/ +cmake/ +doc/ +fuzz/ +tests/ +.clang-format +.editorconfig +.gitignore +.travis.yml +Android.configure.mk +CMakeLists.txt +README +appveyor.yml +cmake-configure +issues_closed_for_0.{13,14,15,16}.md +json_config.h.win32 +json-c.pc.in +json-c.sym + +The following files were added to the source's root by MZLA Technologies: +config.h.in (modified copy from cmake/config.h.in) +moz.build + + diff --git a/comm/third_party/README.libgcrypt b/comm/third_party/README.libgcrypt new file mode 100644 index 0000000000..dca54c09e3 --- /dev/null +++ b/comm/third_party/README.libgcrypt @@ -0,0 +1,7 @@ +Directory ./libgcrypt contains a copy of version 1.9.2 of the libgcrypt library, +which has been obtained from https://www.gnupg.org/ftp/gcrypt/libgcrypt/ . + +For licensing information, please refer to the included documentation. + +The SHA256SUM of the imported file is: +b2c10d091513b271e47177274607b1ffba3d95b188bbfa8797f948aec9053c5a libgcrypt-1.9.2.tar.bz2 diff --git a/comm/third_party/README.libgpg-error b/comm/third_party/README.libgpg-error new file mode 100644 index 0000000000..c767ce35ed --- /dev/null +++ b/comm/third_party/README.libgpg-error @@ -0,0 +1,7 @@ +Directory ./libgpg-error contains a copy of version 1.42 of the libgpg-error library, +which has been obtained from https://www.gnupg.org/ftp/gcrypt/libgpg-error/ . + +For licensing information, please refer to the included documentation. + +The SHA256SUM of the imported file is: +fc07e70f6c615f8c4f590a8e37a9b8dd2e2ca1e9408f8e60459c67452b925e23 libgpg-error-1.42.tar.bz2 diff --git a/comm/third_party/README.libotr b/comm/third_party/README.libotr new file mode 100644 index 0000000000..e21872f983 --- /dev/null +++ b/comm/third_party/README.libotr @@ -0,0 +1,7 @@ +Directory ./libotr contains a copy of version 4.1.1 of the libotr library, +which has been obtained from https://otr.im/dist/libotr/4.1.1/libotr-4.1.1.tar.gz . + +For licensing information, please refer to the included documentation. + +The SHA256SUM of the imported file is: +8b3b182424251067a952fb4e6c7b95a21e644fbb27fbd5f8af2b2ed87ca419f5 libotr-4.1.1.tar.gz diff --git a/comm/third_party/README.niwcompat b/comm/third_party/README.niwcompat new file mode 100644 index 0000000000..ea1591da3e --- /dev/null +++ b/comm/third_party/README.niwcompat @@ -0,0 +1,6 @@ +Directory ./niwcompat contains dirent.h from vcpkg and an empty getopt.h. +to compile RNP with Clang-cl for Windows. + +niwcompat = wincompat where "win" is spelled backwards + +For licensing information, please refer to the files within. diff --git a/comm/third_party/README.rnp b/comm/third_party/README.rnp new file mode 100644 index 0000000000..f7b75e6bd1 --- /dev/null +++ b/comm/third_party/README.rnp @@ -0,0 +1,87 @@ +Directory ./rnp contains a copy of rnp which has been obtained from: +https://github.com/rnpgp/rnp + +[tag v0.17.0] + +If MZLA applied patches on top, the version number in file +third_party/rnp/src/lib/version.h will contain a suffix that lists +the upstream pull request IDs. + +For licensing information, please refer to the included documentation. + +Updates to this copy are managed by "mach vendor". The configuration file +is at rnp/moz.yaml. + + > cd comm/third_party/rnp + + # validate the YAML config file + > mach vendor -v ./moz.yaml + ./moz.yaml: OK + + # check for new upstream versions + > mach vendor --check-for-update ./moz.yaml + v0.17.0 2023-02-27T16:49:53+02:00 + + # update to a new version + > mach vendor -r v0.16.3 ./moz.yaml + + # If there are patches to apply in moz.yaml, the process is a little different + > mach vendor ./moz.yaml --patch-mode none + # followed by + > mach vendor ./moz.yaml --patch-mode only + + +Build notes: + +There are several configure options that can be added to mozconfig to control +how librnp is built. + +--with-system-librnp + Use system RNP (librnp) for OpenPGP support. + This option will not build librnp at all. In order to provide OpenPGP support, + librnp must be installed as a system package (RPM, DEB) and located where the + dynamic loader will find it or copied separately into Thunderbird's application + directory. + +--with-system-jsonc + Use system JSON-C for librnp (located with pkgconfig) + Build librnp from the in-tree sources, but link with a system-installed + libjson-c. Build flags are determined with Pkg-config/pkgconf. + +--with-system-bz2[=prefix] + Use system Bzip2 for librnp (pkgconfig/given prefix) + Build librnp from in-tree sources, link with a system libbz2. + This option does accept a prefix path (such as --with-system-bz2=/usr/local). + (Bzip2 itself does not provide a pkgconfig file. Some Linux distributions + include their own so the build system will look for one.) + +--with-system-zlib + Link librnp to a system zlib. Pkgconfig only. + +--with-librnp-backend=(botan|openssl) ** + ** "openssl" is only supported when targeting Linux. + + This option allows building librnp with the OpenSSL backend. When not provided, + it defaults to "botan". + When set to "openssl", OpenSSL will be located via Pkgconfig. + +--with-system-botan + Link librnp to a system libbotan. Pkgconfig only. Note that it is not necessary + to also set "--with-librnp-backend=botan". + +--with-openssl=prefix (Linux only) + Used with "--with-librnp-backend=openssl" to use OpenSSL installed at "prefix" + instead of one provided by Pkgconfig. Ex: --with-openssl=/usr/openssl-3 + + +OpenSSL notes: + +Only Linux targets are supported. + +OpenSSL 1.1.1 and OpenSSL 3.0.x are supported. The version is checked during +configure as RNP has slightly different code paths for 3.x. + +The OpenSSL backend has some limitations compared to Botan. The following +features are disabled: +TWOFISH, BRAINPOOL + diff --git a/comm/third_party/README.zlib b/comm/third_party/README.zlib new file mode 100644 index 0000000000..3f9ce1e94e --- /dev/null +++ b/comm/third_party/README.zlib @@ -0,0 +1,53 @@ +Directory ./zlib contains a copy of zlib which has been obtained from: +https://github.com/madler/zlib + +For licensing information, please refer to the included documentation. + +[tag v1.2.13] + +Updating: +- cd $topsrcdir/comm +- ../mach vendor -r third_party/zlib/moz.yaml +- Review the changes +- Commit the changes + +The tag information in this file is automatically updated. The moz.yaml file +is automatically updated. If upstream changes require updating moz.build, that +must be done with a manual step. + +The following files and directories were removed from the source distribution's root: +amiga +contrib +doc +examples +msdos +nintendods +old +os400 +qnx +test +watcom +win32 +CMakeLists.txt +Makefile +Makefile.in +configure +make_vms.com +treebuild.xml +zconf.h.cmakein +zconf.h.in +zlib.3 +zlib.3.pdf +zlib.map +zlib.pc.cmakein +zlib.pc.in +zlib2ansi + + +The following files were added to the source's root by MZLA Technologies: +moz.build +moz.yaml + + +Use of this distribution is not required to build Thunderbird's OpenPGP support. +You may set --enable-system-zlib at build time to dynamically link to another zlib. diff --git a/comm/third_party/asn1js/LICENSE b/comm/third_party/asn1js/LICENSE new file mode 100644 index 0000000000..8d57190329 --- /dev/null +++ b/comm/third_party/asn1js/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2014, GMO GlobalSign +Copyright (c) 2015-2022, Peculiar Ventures +All rights reserved. + +Author 2014-2019, Yury Strozhevsky + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/comm/third_party/asn1js/asn1js.mjs b/comm/third_party/asn1js/asn1js.mjs new file mode 100644 index 0000000000..a937f01dbc --- /dev/null +++ b/comm/third_party/asn1js/asn1js.mjs @@ -0,0 +1,3913 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/pvtsutils/build/index.js +var require_build = __commonJS({ + "node_modules/pvtsutils/build/index.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var ARRAY_BUFFER_NAME = "[object ArrayBuffer]"; + var BufferSourceConverter19 = class { + static isArrayBuffer(data) { + return Object.prototype.toString.call(data) === ARRAY_BUFFER_NAME; + } + static toArrayBuffer(data) { + if (this.isArrayBuffer(data)) { + return data; + } + if (data.byteLength === data.buffer.byteLength) { + return data.buffer; + } + return this.toUint8Array(data).slice().buffer; + } + static toUint8Array(data) { + return this.toView(data, Uint8Array); + } + static toView(data, type) { + if (data.constructor === type) { + return data; + } + if (this.isArrayBuffer(data)) { + return new type(data); + } + if (this.isArrayBufferView(data)) { + return new type(data.buffer, data.byteOffset, data.byteLength); + } + throw new TypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView)'"); + } + static isBufferSource(data) { + return this.isArrayBufferView(data) || this.isArrayBuffer(data); + } + static isArrayBufferView(data) { + return ArrayBuffer.isView(data) || data && this.isArrayBuffer(data.buffer); + } + static isEqual(a, b) { + const aView = BufferSourceConverter19.toUint8Array(a); + const bView = BufferSourceConverter19.toUint8Array(b); + if (aView.length !== bView.byteLength) { + return false; + } + for (let i = 0; i < aView.length; i++) { + if (aView[i] !== bView[i]) { + return false; + } + } + return true; + } + static concat(...args) { + if (Array.isArray(args[0])) { + const buffers = args[0]; + let size = 0; + for (const buffer of buffers) { + size += buffer.byteLength; + } + const res = new Uint8Array(size); + let offset = 0; + for (const buffer of buffers) { + const view = this.toUint8Array(buffer); + res.set(view, offset); + offset += view.length; + } + if (args[1]) { + return this.toView(res, args[1]); + } + return res.buffer; + } else { + return this.concat(args); + } + } + }; + var Utf8Converter = class { + static fromString(text) { + const s = unescape(encodeURIComponent(text)); + const uintArray = new Uint8Array(s.length); + for (let i = 0; i < s.length; i++) { + uintArray[i] = s.charCodeAt(i); + } + return uintArray.buffer; + } + static toString(buffer) { + const buf = BufferSourceConverter19.toUint8Array(buffer); + let encodedString = ""; + for (let i = 0; i < buf.length; i++) { + encodedString += String.fromCharCode(buf[i]); + } + const decodedString = decodeURIComponent(escape(encodedString)); + return decodedString; + } + }; + var Utf16Converter = class { + static toString(buffer, littleEndian = false) { + const arrayBuffer = BufferSourceConverter19.toArrayBuffer(buffer); + const dataView = new DataView(arrayBuffer); + let res = ""; + for (let i = 0; i < arrayBuffer.byteLength; i += 2) { + const code = dataView.getUint16(i, littleEndian); + res += String.fromCharCode(code); + } + return res; + } + static fromString(text, littleEndian = false) { + const res = new ArrayBuffer(text.length * 2); + const dataView = new DataView(res); + for (let i = 0; i < text.length; i++) { + dataView.setUint16(i * 2, text.charCodeAt(i), littleEndian); + } + return res; + } + }; + var Convert10 = class { + static isHex(data) { + return typeof data === "string" && /^[a-z0-9]+$/i.test(data); + } + static isBase64(data) { + return typeof data === "string" && /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data); + } + static isBase64Url(data) { + return typeof data === "string" && /^[a-zA-Z0-9-_]+$/i.test(data); + } + static ToString(buffer, enc = "utf8") { + const buf = BufferSourceConverter19.toUint8Array(buffer); + switch (enc.toLowerCase()) { + case "utf8": + return this.ToUtf8String(buf); + case "binary": + return this.ToBinary(buf); + case "hex": + return this.ToHex(buf); + case "base64": + return this.ToBase64(buf); + case "base64url": + return this.ToBase64Url(buf); + case "utf16le": + return Utf16Converter.toString(buf, true); + case "utf16": + case "utf16be": + return Utf16Converter.toString(buf); + default: + throw new Error(`Unknown type of encoding '${enc}'`); + } + } + static FromString(str, enc = "utf8") { + if (!str) { + return new ArrayBuffer(0); + } + switch (enc.toLowerCase()) { + case "utf8": + return this.FromUtf8String(str); + case "binary": + return this.FromBinary(str); + case "hex": + return this.FromHex(str); + case "base64": + return this.FromBase64(str); + case "base64url": + return this.FromBase64Url(str); + case "utf16le": + return Utf16Converter.fromString(str, true); + case "utf16": + case "utf16be": + return Utf16Converter.fromString(str); + default: + throw new Error(`Unknown type of encoding '${enc}'`); + } + } + static ToBase64(buffer) { + const buf = BufferSourceConverter19.toUint8Array(buffer); + if (typeof btoa !== "undefined") { + const binary = this.ToString(buf, "binary"); + return btoa(binary); + } else { + return Buffer.from(buf).toString("base64"); + } + } + static FromBase64(base64) { + const formatted = this.formatString(base64); + if (!formatted) { + return new ArrayBuffer(0); + } + if (!Convert10.isBase64(formatted)) { + throw new TypeError("Argument 'base64Text' is not Base64 encoded"); + } + if (typeof atob !== "undefined") { + return this.FromBinary(atob(formatted)); + } else { + return new Uint8Array(Buffer.from(formatted, "base64")).buffer; + } + } + static FromBase64Url(base64url) { + const formatted = this.formatString(base64url); + if (!formatted) { + return new ArrayBuffer(0); + } + if (!Convert10.isBase64Url(formatted)) { + throw new TypeError("Argument 'base64url' is not Base64Url encoded"); + } + return this.FromBase64(this.Base64Padding(formatted.replace(/\-/g, "+").replace(/\_/g, "/"))); + } + static ToBase64Url(data) { + return this.ToBase64(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, ""); + } + static FromUtf8String(text, encoding = Convert10.DEFAULT_UTF8_ENCODING) { + switch (encoding) { + case "ascii": + return this.FromBinary(text); + case "utf8": + return Utf8Converter.fromString(text); + case "utf16": + case "utf16be": + return Utf16Converter.fromString(text); + case "utf16le": + case "usc2": + return Utf16Converter.fromString(text, true); + default: + throw new Error(`Unknown type of encoding '${encoding}'`); + } + } + static ToUtf8String(buffer, encoding = Convert10.DEFAULT_UTF8_ENCODING) { + switch (encoding) { + case "ascii": + return this.ToBinary(buffer); + case "utf8": + return Utf8Converter.toString(buffer); + case "utf16": + case "utf16be": + return Utf16Converter.toString(buffer); + case "utf16le": + case "usc2": + return Utf16Converter.toString(buffer, true); + default: + throw new Error(`Unknown type of encoding '${encoding}'`); + } + } + static FromBinary(text) { + const stringLength = text.length; + const resultView = new Uint8Array(stringLength); + for (let i = 0; i < stringLength; i++) { + resultView[i] = text.charCodeAt(i); + } + return resultView.buffer; + } + static ToBinary(buffer) { + const buf = BufferSourceConverter19.toUint8Array(buffer); + let res = ""; + for (let i = 0; i < buf.length; i++) { + res += String.fromCharCode(buf[i]); + } + return res; + } + static ToHex(buffer) { + const buf = BufferSourceConverter19.toUint8Array(buffer); + const splitter = ""; + const res = []; + const len = buf.length; + for (let i = 0; i < len; i++) { + const char = buf[i].toString(16).padStart(2, "0"); + res.push(char); + } + return res.join(splitter); + } + static FromHex(hexString) { + let formatted = this.formatString(hexString); + if (!formatted) { + return new ArrayBuffer(0); + } + if (!Convert10.isHex(formatted)) { + throw new TypeError("Argument 'hexString' is not HEX encoded"); + } + if (formatted.length % 2) { + formatted = `0${formatted}`; + } + const res = new Uint8Array(formatted.length / 2); + for (let i = 0; i < formatted.length; i = i + 2) { + const c = formatted.slice(i, i + 2); + res[i / 2] = parseInt(c, 16); + } + return res.buffer; + } + static ToUtf16String(buffer, littleEndian = false) { + return Utf16Converter.toString(buffer, littleEndian); + } + static FromUtf16String(text, littleEndian = false) { + return Utf16Converter.fromString(text, littleEndian); + } + static Base64Padding(base64) { + const padCount = 4 - base64.length % 4; + if (padCount < 4) { + for (let i = 0; i < padCount; i++) { + base64 += "="; + } + } + return base64; + } + static formatString(data) { + return (data === null || data === void 0 ? void 0 : data.replace(/[\n\r\t ]/g, "")) || ""; + } + }; + Convert10.DEFAULT_UTF8_ENCODING = "utf8"; + function assign(target, ...sources) { + const res = arguments[0]; + for (let i = 1; i < arguments.length; i++) { + const obj = arguments[i]; + for (const prop in obj) { + res[prop] = obj[prop]; + } + } + return res; + } + function combine(...buf) { + const totalByteLength = buf.map((item) => item.byteLength).reduce((prev, cur) => prev + cur); + const res = new Uint8Array(totalByteLength); + let currentPos = 0; + buf.map((item) => new Uint8Array(item)).forEach((arr) => { + for (const item2 of arr) { + res[currentPos++] = item2; + } + }); + return res.buffer; + } + function isEqual(bytes1, bytes2) { + if (!(bytes1 && bytes2)) { + return false; + } + if (bytes1.byteLength !== bytes2.byteLength) { + return false; + } + const b1 = new Uint8Array(bytes1); + const b2 = new Uint8Array(bytes2); + for (let i = 0; i < bytes1.byteLength; i++) { + if (b1[i] !== b2[i]) { + return false; + } + } + return true; + } + exports.BufferSourceConverter = BufferSourceConverter19; + exports.Convert = Convert10; + exports.assign = assign; + exports.combine = combine; + exports.isEqual = isEqual; + } +}); + +// src/index.ts +var src_exports = {}; +__export(src_exports, { + Any: () => Any, + BaseBlock: () => BaseBlock, + BaseStringBlock: () => BaseStringBlock, + BitString: () => BitString, + BmpString: () => BmpString, + Boolean: () => Boolean, + CharacterString: () => CharacterString, + Choice: () => Choice, + Constructed: () => Constructed, + DATE: () => DATE, + DateTime: () => DateTime, + Duration: () => Duration, + EndOfContent: () => EndOfContent, + Enumerated: () => Enumerated, + GeneralString: () => GeneralString, + GeneralizedTime: () => GeneralizedTime, + GraphicString: () => GraphicString, + HexBlock: () => HexBlock, + IA5String: () => IA5String, + Integer: () => Integer, + Null: () => Null, + NumericString: () => NumericString, + ObjectIdentifier: () => ObjectIdentifier, + OctetString: () => OctetString, + Primitive: () => Primitive, + PrintableString: () => PrintableString, + RawData: () => RawData, + RelativeObjectIdentifier: () => RelativeObjectIdentifier, + Repeated: () => Repeated, + Sequence: () => Sequence, + Set: () => Set, + TIME: () => TIME, + TeletexString: () => TeletexString, + TimeOfDay: () => TimeOfDay, + UTCTime: () => UTCTime, + UniversalString: () => UniversalString, + Utf8String: () => Utf8String, + ValueBlock: () => ValueBlock, + VideotexString: () => VideotexString, + ViewWriter: () => ViewWriter, + VisibleString: () => VisibleString, + compareSchema: () => compareSchema, + fromBER: () => fromBER, + verifySchema: () => verifySchema +}); + +// src/internals/utils.ts +function assertBigInt() { + if (typeof BigInt === "undefined") { + throw new Error("BigInt is not defined. Your environment doesn't implement BigInt."); + } +} +function concat(buffers) { + let outputLength = 0; + let prevLength = 0; + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + outputLength += buffer.byteLength; + } + const retView = new Uint8Array(outputLength); + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + retView.set(new Uint8Array(buffer), prevLength); + prevLength += buffer.byteLength; + } + return retView.buffer; +} +function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) { + if (!(inputBuffer instanceof Uint8Array)) { + baseBlock.error = "Wrong parameter: inputBuffer must be 'Uint8Array'"; + return false; + } + if (!inputBuffer.byteLength) { + baseBlock.error = "Wrong parameter: inputBuffer has zero length"; + return false; + } + if (inputOffset < 0) { + baseBlock.error = "Wrong parameter: inputOffset less than zero"; + return false; + } + if (inputLength < 0) { + baseBlock.error = "Wrong parameter: inputLength less than zero"; + return false; + } + if (inputBuffer.byteLength - inputOffset - inputLength < 0) { + baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return false; + } + return true; +} + +// src/ViewWriter.ts +var ViewWriter = class { + constructor() { + this.items = []; + } + /** + * Writes buffer + * @param buf + */ + write(buf) { + this.items.push(buf); + } + /** + * Concatenates all buffers + * @returns Concatenated buffer + */ + final() { + return concat(this.items); + } +}; + +// src/HexBlock.ts +var pvtsutils = __toESM(require_build()); + +// src/internals/constants.ts +var powers2 = [new Uint8Array([1])]; +var digitsString = "0123456789"; +var NAME = "name"; +var VALUE_HEX_VIEW = "valueHexView"; +var IS_HEX_ONLY = "isHexOnly"; +var ID_BLOCK = "idBlock"; +var TAG_CLASS = "tagClass"; +var TAG_NUMBER = "tagNumber"; +var IS_CONSTRUCTED = "isConstructed"; +var FROM_BER = "fromBER"; +var TO_BER = "toBER"; +var LOCAL = "local"; +var EMPTY_STRING = ""; +var EMPTY_BUFFER = new ArrayBuffer(0); +var EMPTY_VIEW = new Uint8Array(0); +var END_OF_CONTENT_NAME = "EndOfContent"; +var OCTET_STRING_NAME = "OCTET STRING"; +var BIT_STRING_NAME = "BIT STRING"; + +// src/HexBlock.ts +function HexBlock(BaseClass) { + var _a; + return _a = class extends BaseClass { + constructor(...args) { + var _a2; + super(...args); + const params = args[0] || {}; + this.isHexOnly = (_a2 = params.isHexOnly) != null ? _a2 : false; + this.valueHexView = params.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(params.valueHex) : EMPTY_VIEW; + } + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + get valueHex() { + return this.valueHexView.slice().buffer; + } + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + set valueHex(value) { + this.valueHexView = new Uint8Array(value); + } + fromBER(inputBuffer, inputOffset, inputLength) { + const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer; + if (!checkBufferParams(this, view, inputOffset, inputLength)) { + return -1; + } + const endLength = inputOffset + inputLength; + this.valueHexView = view.subarray(inputOffset, endLength); + if (!this.valueHexView.length) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + this.blockLength = inputLength; + return endLength; + } + toBER(sizeOnly = false) { + if (!this.isHexOnly) { + this.error = "Flag 'isHexOnly' is not set, abort"; + return EMPTY_BUFFER; + } + if (sizeOnly) { + return new ArrayBuffer(this.valueHexView.byteLength); + } + return this.valueHexView.byteLength === this.valueHexView.buffer.byteLength ? this.valueHexView.buffer : this.valueHexView.slice().buffer; + } + /** + * Returns a JSON representation of an object + * @returns JSON object + */ + toJSON() { + return { + ...super.toJSON(), + isHexOnly: this.isHexOnly, + valueHex: pvtsutils.Convert.ToHex(this.valueHexView) + }; + } + }, _a.NAME = "hexBlock", _a; +} + +// src/internals/LocalBaseBlock.ts +var pvtsutils2 = __toESM(require_build()); +var LocalBaseBlock = class { + /** + * Aux function, need to get a block name. Need to have it here for inheritance + * @returns Returns name of the block + */ + static blockName() { + return this.NAME; + } + /** + * @deprecated since version 3.0.0 + */ + get valueBeforeDecode() { + return this.valueBeforeDecodeView.slice().buffer; + } + /** + * @deprecated since version 3.0.0 + */ + set valueBeforeDecode(value) { + this.valueBeforeDecodeView = new Uint8Array(value); + } + /** + * Creates and initializes an object instance of that class + * @param param0 Initialization parameters + */ + constructor({ + blockLength = 0, + error = EMPTY_STRING, + warnings = [], + valueBeforeDecode = EMPTY_VIEW + } = {}) { + this.blockLength = blockLength; + this.error = error; + this.warnings = warnings; + this.valueBeforeDecodeView = pvtsutils2.BufferSourceConverter.toUint8Array(valueBeforeDecode); + } + /** + * Returns a JSON representation of an object + * @returns JSON object + */ + toJSON() { + return { + blockName: this.constructor.NAME, + blockLength: this.blockLength, + error: this.error, + warnings: this.warnings, + valueBeforeDecode: pvtsutils2.Convert.ToHex(this.valueBeforeDecodeView) + }; + } +}; +/** + * Name of the block + */ +LocalBaseBlock.NAME = "baseBlock"; + +// src/ValueBlock.ts +var ValueBlock = class extends LocalBaseBlock { + fromBER(inputBuffer, inputOffset, inputLength) { + throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'"); + } + toBER(sizeOnly, writer) { + throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'"); + } +}; +ValueBlock.NAME = "valueBlock"; + +// src/BaseBlock.ts +var pvtsutils5 = __toESM(require_build()); + +// node_modules/pvutils/build/utils.es.js +function utilFromBase(inputBuffer, inputBase) { + let result = 0; + if (inputBuffer.length === 1) { + return inputBuffer[0]; + } + for (let i = inputBuffer.length - 1; i >= 0; i--) { + result += inputBuffer[inputBuffer.length - 1 - i] * Math.pow(2, inputBase * i); + } + return result; +} +function utilToBase(value, base, reserved = -1) { + const internalReserved = reserved; + let internalValue = value; + let result = 0; + let biggest = Math.pow(2, base); + for (let i = 1; i < 8; i++) { + if (value < biggest) { + let retBuf; + if (internalReserved < 0) { + retBuf = new ArrayBuffer(i); + result = i; + } else { + if (internalReserved < i) { + return new ArrayBuffer(0); + } + retBuf = new ArrayBuffer(internalReserved); + result = internalReserved; + } + const retView = new Uint8Array(retBuf); + for (let j = i - 1; j >= 0; j--) { + const basis = Math.pow(2, j * base); + retView[result - j - 1] = Math.floor(internalValue / basis); + internalValue -= retView[result - j - 1] * basis; + } + return retBuf; + } + biggest *= Math.pow(2, base); + } + return new ArrayBuffer(0); +} +function utilConcatView(...views) { + let outputLength = 0; + let prevLength = 0; + for (const view of views) { + outputLength += view.length; + } + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + for (const view of views) { + retView.set(view, prevLength); + prevLength += view.length; + } + return retView; +} +function utilDecodeTC() { + const buf = new Uint8Array(this.valueHex); + if (this.valueHex.byteLength >= 2) { + const condition1 = buf[0] === 255 && buf[1] & 128; + const condition2 = buf[0] === 0 && (buf[1] & 128) === 0; + if (condition1 || condition2) { + this.warnings.push("Needlessly long format"); + } + } + const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const bigIntView = new Uint8Array(bigIntBuffer); + for (let i = 0; i < this.valueHex.byteLength; i++) { + bigIntView[i] = 0; + } + bigIntView[0] = buf[0] & 128; + const bigInt = utilFromBase(bigIntView, 8); + const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const smallIntView = new Uint8Array(smallIntBuffer); + for (let j = 0; j < this.valueHex.byteLength; j++) { + smallIntView[j] = buf[j]; + } + smallIntView[0] &= 127; + const smallInt = utilFromBase(smallIntView, 8); + return smallInt - bigInt; +} +function utilEncodeTC(value) { + const modValue = value < 0 ? value * -1 : value; + let bigInt = 128; + for (let i = 1; i < 8; i++) { + if (modValue <= bigInt) { + if (value < 0) { + const smallInt = bigInt - modValue; + const retBuf2 = utilToBase(smallInt, 8, i); + const retView2 = new Uint8Array(retBuf2); + retView2[0] |= 128; + return retBuf2; + } + let retBuf = utilToBase(modValue, 8, i); + let retView = new Uint8Array(retBuf); + if (retView[0] & 128) { + const tempBuf = retBuf.slice(0); + const tempView = new Uint8Array(tempBuf); + retBuf = new ArrayBuffer(retBuf.byteLength + 1); + retView = new Uint8Array(retBuf); + for (let k = 0; k < tempBuf.byteLength; k++) { + retView[k + 1] = tempView[k]; + } + retView[0] = 0; + } + return retBuf; + } + bigInt *= Math.pow(2, 8); + } + return new ArrayBuffer(0); +} +function isEqualBuffer(inputBuffer1, inputBuffer2) { + if (inputBuffer1.byteLength !== inputBuffer2.byteLength) { + return false; + } + const view1 = new Uint8Array(inputBuffer1); + const view2 = new Uint8Array(inputBuffer2); + for (let i = 0; i < view1.length; i++) { + if (view1[i] !== view2[i]) { + return false; + } + } + return true; +} +function padNumber(inputNumber, fullLength) { + const str = inputNumber.toString(10); + if (fullLength < str.length) { + return ""; + } + const dif = fullLength - str.length; + const padding = new Array(dif); + for (let i = 0; i < dif; i++) { + padding[i] = "0"; + } + const paddingString = padding.join(""); + return paddingString.concat(str); +} +var log2 = Math.log(2); + +// src/internals/LocalIdentificationBlock.ts +var pvtsutils3 = __toESM(require_build()); +var LocalIdentificationBlock = class extends HexBlock(LocalBaseBlock) { + constructor({ + idBlock = {} + } = {}) { + var _a, _b, _c, _d; + super(); + if (idBlock) { + this.isHexOnly = (_a = idBlock.isHexOnly) != null ? _a : false; + this.valueHexView = idBlock.valueHex ? pvtsutils3.BufferSourceConverter.toUint8Array(idBlock.valueHex) : EMPTY_VIEW; + this.tagClass = (_b = idBlock.tagClass) != null ? _b : -1; + this.tagNumber = (_c = idBlock.tagNumber) != null ? _c : -1; + this.isConstructed = (_d = idBlock.isConstructed) != null ? _d : false; + } else { + this.tagClass = -1; + this.tagNumber = -1; + this.isConstructed = false; + } + } + toBER(sizeOnly = false) { + let firstOctet = 0; + switch (this.tagClass) { + case 1: + firstOctet |= 0; + break; + case 2: + firstOctet |= 64; + break; + case 3: + firstOctet |= 128; + break; + case 4: + firstOctet |= 192; + break; + default: + this.error = "Unknown tag class"; + return EMPTY_BUFFER; + } + if (this.isConstructed) + firstOctet |= 32; + if (this.tagNumber < 31 && !this.isHexOnly) { + const retView2 = new Uint8Array(1); + if (!sizeOnly) { + let number = this.tagNumber; + number &= 31; + firstOctet |= number; + retView2[0] = firstOctet; + } + return retView2.buffer; + } + if (!this.isHexOnly) { + const encodedBuf = utilToBase(this.tagNumber, 7); + const encodedView = new Uint8Array(encodedBuf); + const size = encodedBuf.byteLength; + const retView2 = new Uint8Array(size + 1); + retView2[0] = firstOctet | 31; + if (!sizeOnly) { + for (let i = 0; i < size - 1; i++) + retView2[i + 1] = encodedView[i] | 128; + retView2[size] = encodedView[size - 1]; + } + return retView2.buffer; + } + const retView = new Uint8Array(this.valueHexView.byteLength + 1); + retView[0] = firstOctet | 31; + if (!sizeOnly) { + const curView = this.valueHexView; + for (let i = 0; i < curView.length - 1; i++) + retView[i + 1] = curView[i] | 128; + retView[this.valueHexView.byteLength] = curView[curView.length - 1]; + } + return retView.buffer; + } + fromBER(inputBuffer, inputOffset, inputLength) { + const inputView = pvtsutils3.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return -1; + } + const tagClassMask = intBuffer[0] & 192; + switch (tagClassMask) { + case 0: + this.tagClass = 1; + break; + case 64: + this.tagClass = 2; + break; + case 128: + this.tagClass = 3; + break; + case 192: + this.tagClass = 4; + break; + default: + this.error = "Unknown tag class"; + return -1; + } + this.isConstructed = (intBuffer[0] & 32) === 32; + this.isHexOnly = false; + const tagNumberMask = intBuffer[0] & 31; + if (tagNumberMask !== 31) { + this.tagNumber = tagNumberMask; + this.blockLength = 1; + } else { + let count = 1; + let intTagNumberBuffer = this.valueHexView = new Uint8Array(255); + let tagNumberBufferMaxLength = 255; + while (intBuffer[count] & 128) { + intTagNumberBuffer[count - 1] = intBuffer[count] & 127; + count++; + if (count >= intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + if (count === tagNumberBufferMaxLength) { + tagNumberBufferMaxLength += 255; + const tempBufferView2 = new Uint8Array(tagNumberBufferMaxLength); + for (let i = 0; i < intTagNumberBuffer.length; i++) + tempBufferView2[i] = intTagNumberBuffer[i]; + intTagNumberBuffer = this.valueHexView = new Uint8Array(tagNumberBufferMaxLength); + } + } + this.blockLength = count + 1; + intTagNumberBuffer[count - 1] = intBuffer[count] & 127; + const tempBufferView = new Uint8Array(count); + for (let i = 0; i < count; i++) + tempBufferView[i] = intTagNumberBuffer[i]; + intTagNumberBuffer = this.valueHexView = new Uint8Array(count); + intTagNumberBuffer.set(tempBufferView); + if (this.blockLength <= 9) + this.tagNumber = utilFromBase(intTagNumberBuffer, 7); + else { + this.isHexOnly = true; + this.warnings.push("Tag too long, represented as hex-coded"); + } + } + if (this.tagClass === 1 && this.isConstructed) { + switch (this.tagNumber) { + case 1: + case 2: + case 5: + case 6: + case 9: + case 13: + case 14: + case 23: + case 24: + case 31: + case 32: + case 33: + case 34: + this.error = "Constructed encoding used for primitive type"; + return -1; + default: + } + } + return inputOffset + this.blockLength; + } + toJSON() { + return { + ...super.toJSON(), + tagClass: this.tagClass, + tagNumber: this.tagNumber, + isConstructed: this.isConstructed + }; + } +}; +LocalIdentificationBlock.NAME = "identificationBlock"; + +// src/internals/LocalLengthBlock.ts +var pvtsutils4 = __toESM(require_build()); +var LocalLengthBlock = class extends LocalBaseBlock { + constructor({ + lenBlock = {} + } = {}) { + var _a, _b, _c; + super(); + this.isIndefiniteForm = (_a = lenBlock.isIndefiniteForm) != null ? _a : false; + this.longFormUsed = (_b = lenBlock.longFormUsed) != null ? _b : false; + this.length = (_c = lenBlock.length) != null ? _c : 0; + } + fromBER(inputBuffer, inputOffset, inputLength) { + const view = pvtsutils4.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, view, inputOffset, inputLength)) { + return -1; + } + const intBuffer = view.subarray(inputOffset, inputOffset + inputLength); + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return -1; + } + if (intBuffer[0] === 255) { + this.error = "Length block 0xFF is reserved by standard"; + return -1; + } + this.isIndefiniteForm = intBuffer[0] === 128; + if (this.isIndefiniteForm) { + this.blockLength = 1; + return inputOffset + this.blockLength; + } + this.longFormUsed = !!(intBuffer[0] & 128); + if (this.longFormUsed === false) { + this.length = intBuffer[0]; + this.blockLength = 1; + return inputOffset + this.blockLength; + } + const count = intBuffer[0] & 127; + if (count > 8) { + this.error = "Too big integer"; + return -1; + } + if (count + 1 > intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + const lenOffset = inputOffset + 1; + const lengthBufferView = view.subarray(lenOffset, lenOffset + count); + if (lengthBufferView[count - 1] === 0) + this.warnings.push("Needlessly long encoded length"); + this.length = utilFromBase(lengthBufferView, 8); + if (this.longFormUsed && this.length <= 127) + this.warnings.push("Unnecessary usage of long length form"); + this.blockLength = count + 1; + return inputOffset + this.blockLength; + } + toBER(sizeOnly = false) { + let retBuf; + let retView; + if (this.length > 127) + this.longFormUsed = true; + if (this.isIndefiniteForm) { + retBuf = new ArrayBuffer(1); + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + retView[0] = 128; + } + return retBuf; + } + if (this.longFormUsed) { + const encodedBuf = utilToBase(this.length, 8); + if (encodedBuf.byteLength > 127) { + this.error = "Too big length"; + return EMPTY_BUFFER; + } + retBuf = new ArrayBuffer(encodedBuf.byteLength + 1); + if (sizeOnly) + return retBuf; + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + retView[0] = encodedBuf.byteLength | 128; + for (let i = 0; i < encodedBuf.byteLength; i++) + retView[i + 1] = encodedView[i]; + return retBuf; + } + retBuf = new ArrayBuffer(1); + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + retView[0] = this.length; + } + return retBuf; + } + toJSON() { + return { + ...super.toJSON(), + isIndefiniteForm: this.isIndefiniteForm, + longFormUsed: this.longFormUsed, + length: this.length + }; + } +}; +LocalLengthBlock.NAME = "lengthBlock"; + +// src/TypeStore.ts +var typeStore = {}; + +// src/BaseBlock.ts +var BaseBlock = class extends LocalBaseBlock { + constructor({ + name = EMPTY_STRING, + optional = false, + primitiveSchema, + ...parameters + } = {}, valueBlockType) { + super(parameters); + this.name = name; + this.optional = optional; + if (primitiveSchema) { + this.primitiveSchema = primitiveSchema; + } + this.idBlock = new LocalIdentificationBlock(parameters); + this.lenBlock = new LocalLengthBlock(parameters); + this.valueBlock = valueBlockType ? new valueBlockType(parameters) : new ValueBlock(parameters); + } + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + if (!this.valueBlock.error.length) + this.blockLength += this.valueBlock.blockLength; + return resultOffset; + } + toBER(sizeOnly, writer) { + const _writer = writer || new ViewWriter(); + if (!writer) { + prepareIndefiniteForm(this); + } + const idBlockBuf = this.idBlock.toBER(sizeOnly); + _writer.write(idBlockBuf); + if (this.lenBlock.isIndefiniteForm) { + _writer.write(new Uint8Array([128]).buffer); + this.valueBlock.toBER(sizeOnly, _writer); + _writer.write(new ArrayBuffer(2)); + } else { + const valueBlockBuf = this.valueBlock.toBER(sizeOnly); + this.lenBlock.length = valueBlockBuf.byteLength; + const lenBlockBuf = this.lenBlock.toBER(sizeOnly); + _writer.write(lenBlockBuf); + _writer.write(valueBlockBuf); + } + if (!writer) { + return _writer.final(); + } + return EMPTY_BUFFER; + } + toJSON() { + const object = { + ...super.toJSON(), + idBlock: this.idBlock.toJSON(), + lenBlock: this.lenBlock.toJSON(), + valueBlock: this.valueBlock.toJSON(), + name: this.name, + optional: this.optional + }; + if (this.primitiveSchema) + object.primitiveSchema = this.primitiveSchema.toJSON(); + return object; + } + toString(encoding = "ascii") { + if (encoding === "ascii") { + return this.onAsciiEncoding(); + } + return pvtsutils5.Convert.ToHex(this.toBER()); + } + onAsciiEncoding() { + return `${this.constructor.NAME} : ${pvtsutils5.Convert.ToHex(this.valueBlock.valueBeforeDecodeView)}`; + } + /** + * Determines whether two object instances are equal + * @param other Object to compare with the current object + */ + isEqual(other) { + if (this === other) { + return true; + } + if (!(other instanceof this.constructor)) { + return false; + } + const thisRaw = this.toBER(); + const otherRaw = other.toBER(); + return isEqualBuffer(thisRaw, otherRaw); + } +}; +BaseBlock.NAME = "BaseBlock"; +function prepareIndefiniteForm(baseBlock) { + if (baseBlock instanceof typeStore.Constructed) { + for (const value of baseBlock.valueBlock.value) { + if (prepareIndefiniteForm(value)) { + baseBlock.lenBlock.isIndefiniteForm = true; + } + } + } + return !!baseBlock.lenBlock.isIndefiniteForm; +} + +// src/BaseStringBlock.ts +var BaseStringBlock = class extends BaseBlock { + /** + * String value + * @since 3.0.0 + */ + getValue() { + return this.valueBlock.value; + } + /** + * String value + * @param value String value + * @since 3.0.0 + */ + setValue(value) { + this.valueBlock.value = value; + } + constructor({ + value = EMPTY_STRING, + ...parameters + } = {}, stringValueBlockType) { + super(parameters, stringValueBlockType); + if (value) { + this.fromString(value); + } + } + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + this.fromBuffer(this.valueBlock.valueHexView); + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + if (!this.valueBlock.error.length) + this.blockLength += this.valueBlock.blockLength; + return resultOffset; + } + onAsciiEncoding() { + return `${this.constructor.NAME} : '${this.valueBlock.value}'`; + } +}; +BaseStringBlock.NAME = "BaseStringBlock"; + +// src/internals/LocalPrimitiveValueBlock.ts +var LocalPrimitiveValueBlock = class extends HexBlock(ValueBlock) { + constructor({ + isHexOnly = true, + ...parameters + } = {}) { + super(parameters); + this.isHexOnly = isHexOnly; + } +}; +LocalPrimitiveValueBlock.NAME = "PrimitiveValueBlock"; + +// src/Primitive.ts +var _Primitive = class extends BaseBlock { + constructor(parameters = {}) { + super(parameters, LocalPrimitiveValueBlock); + this.idBlock.isConstructed = false; + } +}; +var Primitive = _Primitive; +(() => { + typeStore.Primitive = _Primitive; +})(); +Primitive.NAME = "PRIMITIVE"; + +// src/internals/LocalConstructedValueBlock.ts +var pvtsutils7 = __toESM(require_build()); + +// src/parser.ts +var pvtsutils6 = __toESM(require_build()); +function localChangeType(inputObject, newType) { + if (inputObject instanceof newType) { + return inputObject; + } + const newObject = new newType(); + newObject.idBlock = inputObject.idBlock; + newObject.lenBlock = inputObject.lenBlock; + newObject.warnings = inputObject.warnings; + newObject.valueBeforeDecodeView = inputObject.valueBeforeDecodeView; + return newObject; +} +function localFromBER(inputBuffer, inputOffset = 0, inputLength = inputBuffer.length) { + const incomingOffset = inputOffset; + let returnObject = new BaseBlock({}, ValueBlock); + const baseBlock = new LocalBaseBlock(); + if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) { + returnObject.error = baseBlock.error; + return { + offset: -1, + result: returnObject + }; + } + const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength); + if (!intBuffer.length) { + returnObject.error = "Zero buffer length"; + return { + offset: -1, + result: returnObject + }; + } + let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength); + if (returnObject.idBlock.warnings.length) { + returnObject.warnings.concat(returnObject.idBlock.warnings); + } + if (resultOffset === -1) { + returnObject.error = returnObject.idBlock.error; + return { + offset: -1, + result: returnObject + }; + } + inputOffset = resultOffset; + inputLength -= returnObject.idBlock.blockLength; + resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength); + if (returnObject.lenBlock.warnings.length) { + returnObject.warnings.concat(returnObject.lenBlock.warnings); + } + if (resultOffset === -1) { + returnObject.error = returnObject.lenBlock.error; + return { + offset: -1, + result: returnObject + }; + } + inputOffset = resultOffset; + inputLength -= returnObject.lenBlock.blockLength; + if (!returnObject.idBlock.isConstructed && returnObject.lenBlock.isIndefiniteForm) { + returnObject.error = "Indefinite length form used for primitive encoding form"; + return { + offset: -1, + result: returnObject + }; + } + let newASN1Type = BaseBlock; + switch (returnObject.idBlock.tagClass) { + case 1: + if (returnObject.idBlock.tagNumber >= 37 && returnObject.idBlock.isHexOnly === false) { + returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard"; + return { + offset: -1, + result: returnObject + }; + } + switch (returnObject.idBlock.tagNumber) { + case 0: + if (returnObject.idBlock.isConstructed && returnObject.lenBlock.length > 0) { + returnObject.error = "Type [UNIVERSAL 0] is reserved"; + return { + offset: -1, + result: returnObject + }; + } + newASN1Type = typeStore.EndOfContent; + break; + case 1: + newASN1Type = typeStore.Boolean; + break; + case 2: + newASN1Type = typeStore.Integer; + break; + case 3: + newASN1Type = typeStore.BitString; + break; + case 4: + newASN1Type = typeStore.OctetString; + break; + case 5: + newASN1Type = typeStore.Null; + break; + case 6: + newASN1Type = typeStore.ObjectIdentifier; + break; + case 10: + newASN1Type = typeStore.Enumerated; + break; + case 12: + newASN1Type = typeStore.Utf8String; + break; + case 13: + newASN1Type = typeStore.RelativeObjectIdentifier; + break; + case 14: + newASN1Type = typeStore.TIME; + break; + case 15: + returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + return { + offset: -1, + result: returnObject + }; + case 16: + newASN1Type = typeStore.Sequence; + break; + case 17: + newASN1Type = typeStore.Set; + break; + case 18: + newASN1Type = typeStore.NumericString; + break; + case 19: + newASN1Type = typeStore.PrintableString; + break; + case 20: + newASN1Type = typeStore.TeletexString; + break; + case 21: + newASN1Type = typeStore.VideotexString; + break; + case 22: + newASN1Type = typeStore.IA5String; + break; + case 23: + newASN1Type = typeStore.UTCTime; + break; + case 24: + newASN1Type = typeStore.GeneralizedTime; + break; + case 25: + newASN1Type = typeStore.GraphicString; + break; + case 26: + newASN1Type = typeStore.VisibleString; + break; + case 27: + newASN1Type = typeStore.GeneralString; + break; + case 28: + newASN1Type = typeStore.UniversalString; + break; + case 29: + newASN1Type = typeStore.CharacterString; + break; + case 30: + newASN1Type = typeStore.BmpString; + break; + case 31: + newASN1Type = typeStore.DATE; + break; + case 32: + newASN1Type = typeStore.TimeOfDay; + break; + case 33: + newASN1Type = typeStore.DateTime; + break; + case 34: + newASN1Type = typeStore.Duration; + break; + default: { + const newObject = returnObject.idBlock.isConstructed ? new typeStore.Constructed() : new typeStore.Primitive(); + newObject.idBlock = returnObject.idBlock; + newObject.lenBlock = returnObject.lenBlock; + newObject.warnings = returnObject.warnings; + returnObject = newObject; + } + } + break; + case 2: + case 3: + case 4: + default: { + newASN1Type = returnObject.idBlock.isConstructed ? typeStore.Constructed : typeStore.Primitive; + } + } + returnObject = localChangeType(returnObject, newASN1Type); + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length); + returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength); + return { + offset: resultOffset, + result: returnObject + }; +} +function fromBER(inputBuffer) { + if (!inputBuffer.byteLength) { + const result = new BaseBlock({}, ValueBlock); + result.error = "Input buffer has zero length"; + return { + offset: -1, + result + }; + } + return localFromBER(pvtsutils6.BufferSourceConverter.toUint8Array(inputBuffer).slice(), 0, inputBuffer.byteLength); +} + +// src/internals/LocalConstructedValueBlock.ts +function checkLen(indefiniteLength, length) { + if (indefiniteLength) { + return 1; + } + return length; +} +var LocalConstructedValueBlock = class extends ValueBlock { + constructor({ + value = [], + isIndefiniteForm = false, + ...parameters + } = {}) { + super(parameters); + this.value = value; + this.isIndefiniteForm = isIndefiniteForm; + } + fromBER(inputBuffer, inputOffset, inputLength) { + const view = pvtsutils7.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, view, inputOffset, inputLength)) { + return -1; + } + this.valueBeforeDecodeView = view.subarray(inputOffset, inputOffset + inputLength); + if (this.valueBeforeDecodeView.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + let currentOffset = inputOffset; + while (checkLen(this.isIndefiniteForm, inputLength) > 0) { + const returnObject = localFromBER(view, currentOffset, inputLength); + if (returnObject.offset === -1) { + this.error = returnObject.result.error; + this.warnings.concat(returnObject.result.warnings); + return -1; + } + currentOffset = returnObject.offset; + this.blockLength += returnObject.result.blockLength; + inputLength -= returnObject.result.blockLength; + this.value.push(returnObject.result); + if (this.isIndefiniteForm && returnObject.result.constructor.NAME === END_OF_CONTENT_NAME) { + break; + } + } + if (this.isIndefiniteForm) { + if (this.value[this.value.length - 1].constructor.NAME === END_OF_CONTENT_NAME) { + this.value.pop(); + } else { + this.warnings.push("No EndOfContent block encoded"); + } + } + return currentOffset; + } + toBER(sizeOnly, writer) { + const _writer = writer || new ViewWriter(); + for (let i = 0; i < this.value.length; i++) { + this.value[i].toBER(sizeOnly, _writer); + } + if (!writer) { + return _writer.final(); + } + return EMPTY_BUFFER; + } + toJSON() { + const object = { + ...super.toJSON(), + isIndefiniteForm: this.isIndefiniteForm, + value: [] + }; + for (const value of this.value) { + object.value.push(value.toJSON()); + } + return object; + } +}; +LocalConstructedValueBlock.NAME = "ConstructedValueBlock"; + +// src/Constructed.ts +var _Constructed = class extends BaseBlock { + constructor(parameters = {}) { + super(parameters, LocalConstructedValueBlock); + this.idBlock.isConstructed = true; + } + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + if (!this.valueBlock.error.length) + this.blockLength += this.valueBlock.blockLength; + return resultOffset; + } + /** + * @internal + */ + onAsciiEncoding() { + const values = []; + for (const value of this.valueBlock.value) { + values.push(value.toString("ascii").split("\n").map((o) => ` ${o}`).join("\n")); + } + const blockName = this.idBlock.tagClass === 3 ? `[${this.idBlock.tagNumber}]` : this.constructor.NAME; + return values.length ? `${blockName} : +${values.join("\n")}` : `${blockName} :`; + } +}; +var Constructed = _Constructed; +(() => { + typeStore.Constructed = _Constructed; +})(); +Constructed.NAME = "CONSTRUCTED"; + +// src/internals/LocalEndOfContentValueBlock.ts +var LocalEndOfContentValueBlock = class extends ValueBlock { + fromBER(inputBuffer, inputOffset, inputLength) { + return inputOffset; + } + toBER(sizeOnly) { + return EMPTY_BUFFER; + } +}; +LocalEndOfContentValueBlock.override = "EndOfContentValueBlock"; + +// src/EndOfContent.ts +var _EndOfContent = class extends BaseBlock { + constructor(parameters = {}) { + super(parameters, LocalEndOfContentValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 0; + } +}; +var EndOfContent = _EndOfContent; +(() => { + typeStore.EndOfContent = _EndOfContent; +})(); +EndOfContent.NAME = END_OF_CONTENT_NAME; + +// src/Null.ts +var _Null = class extends BaseBlock { + constructor(parameters = {}) { + super(parameters, ValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 5; + } + fromBER(inputBuffer, inputOffset, inputLength) { + if (this.lenBlock.length > 0) + this.warnings.push("Non-zero length of value block for Null type"); + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + this.blockLength += inputLength; + if (inputOffset + inputLength > inputBuffer.byteLength) { + this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return -1; + } + return inputOffset + inputLength; + } + toBER(sizeOnly, writer) { + const retBuf = new ArrayBuffer(2); + if (!sizeOnly) { + const retView = new Uint8Array(retBuf); + retView[0] = 5; + retView[1] = 0; + } + if (writer) { + writer.write(retBuf); + } + return retBuf; + } + onAsciiEncoding() { + return `${this.constructor.NAME}`; + } +}; +var Null = _Null; +(() => { + typeStore.Null = _Null; +})(); +Null.NAME = "NULL"; + +// src/internals/LocalBooleanValueBlock.ts +var pvtsutils8 = __toESM(require_build()); +var LocalBooleanValueBlock = class extends HexBlock(ValueBlock) { + get value() { + for (const octet of this.valueHexView) { + if (octet > 0) { + return true; + } + } + return false; + } + set value(value) { + this.valueHexView[0] = value ? 255 : 0; + } + constructor({ + value, + ...parameters + } = {}) { + super(parameters); + if (parameters.valueHex) { + this.valueHexView = pvtsutils8.BufferSourceConverter.toUint8Array(parameters.valueHex); + } else { + this.valueHexView = new Uint8Array(1); + } + if (value) { + this.value = value; + } + } + fromBER(inputBuffer, inputOffset, inputLength) { + const inputView = pvtsutils8.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + this.valueHexView = inputView.subarray(inputOffset, inputOffset + inputLength); + if (inputLength > 1) + this.warnings.push("Boolean value encoded in more then 1 octet"); + this.isHexOnly = true; + utilDecodeTC.call(this); + this.blockLength = inputLength; + return inputOffset + inputLength; + } + toBER() { + return this.valueHexView.slice(); + } + toJSON() { + return { + ...super.toJSON(), + value: this.value + }; + } +}; +LocalBooleanValueBlock.NAME = "BooleanValueBlock"; + +// src/Boolean.ts +var _Boolean = class extends BaseBlock { + /** + * Gets value + * @since 3.0.0 + */ + getValue() { + return this.valueBlock.value; + } + /** + * Sets value + * @param value Boolean value + * @since 3.0.0 + */ + setValue(value) { + this.valueBlock.value = value; + } + constructor(parameters = {}) { + super(parameters, LocalBooleanValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 1; + } + onAsciiEncoding() { + return `${this.constructor.NAME} : ${this.getValue}`; + } +}; +var Boolean = _Boolean; +(() => { + typeStore.Boolean = _Boolean; +})(); +Boolean.NAME = "BOOLEAN"; + +// src/OctetString.ts +var pvtsutils9 = __toESM(require_build()); + +// src/internals/LocalOctetStringValueBlock.ts +var LocalOctetStringValueBlock = class extends HexBlock(LocalConstructedValueBlock) { + constructor({ + isConstructed = false, + ...parameters + } = {}) { + super(parameters); + this.isConstructed = isConstructed; + } + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = 0; + if (this.isConstructed) { + this.isHexOnly = false; + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) + return resultOffset; + for (let i = 0; i < this.value.length; i++) { + const currentBlockName = this.value[i].constructor.NAME; + if (currentBlockName === END_OF_CONTENT_NAME) { + if (this.isIndefiniteForm) + break; + else { + this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only"; + return -1; + } + } + if (currentBlockName !== OCTET_STRING_NAME) { + this.error = "OCTET STRING may consists of OCTET STRINGs only"; + return -1; + } + } + } else { + this.isHexOnly = true; + resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + this.blockLength = inputLength; + } + return resultOffset; + } + toBER(sizeOnly, writer) { + if (this.isConstructed) + return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer); + return sizeOnly ? new ArrayBuffer(this.valueHexView.byteLength) : this.valueHexView.slice().buffer; + } + toJSON() { + return { + ...super.toJSON(), + isConstructed: this.isConstructed + }; + } +}; +LocalOctetStringValueBlock.NAME = "OctetStringValueBlock"; + +// src/OctetString.ts +var _OctetString = class extends BaseBlock { + constructor({ + idBlock = {}, + lenBlock = {}, + ...parameters + } = {}) { + var _a, _b; + (_b = parameters.isConstructed) != null ? _b : parameters.isConstructed = !!((_a = parameters.value) == null ? void 0 : _a.length); + super({ + idBlock: { + isConstructed: parameters.isConstructed, + ...idBlock + }, + lenBlock: { + ...lenBlock, + isIndefiniteForm: !!parameters.isIndefiniteForm + }, + ...parameters + }, LocalOctetStringValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 4; + } + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + if (inputLength === 0) { + if (this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + if (this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + return inputOffset; + } + if (!this.valueBlock.isConstructed) { + const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer; + const buf = view.subarray(inputOffset, inputOffset + inputLength); + try { + if (buf.byteLength) { + const asn = localFromBER(buf, 0, buf.byteLength); + if (asn.offset !== -1 && asn.offset === inputLength) { + this.valueBlock.value = [asn.result]; + } + } + } catch (e) { + } + } + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + onAsciiEncoding() { + if (this.valueBlock.isConstructed || this.valueBlock.value && this.valueBlock.value.length) { + return Constructed.prototype.onAsciiEncoding.call(this); + } + return `${this.constructor.NAME} : ${pvtsutils9.Convert.ToHex(this.valueBlock.valueHexView)}`; + } + /** + * Returns OctetString value. If OctetString is constructed, returns concatenated internal OctetString values + * @returns Array buffer + * @since 3.0.0 + */ + getValue() { + if (!this.idBlock.isConstructed) { + return this.valueBlock.valueHexView.slice().buffer; + } + const array = []; + for (const content of this.valueBlock.value) { + if (content instanceof _OctetString) { + array.push(content.valueBlock.valueHexView); + } + } + return pvtsutils9.BufferSourceConverter.concat(array); + } +}; +var OctetString = _OctetString; +(() => { + typeStore.OctetString = _OctetString; +})(); +OctetString.NAME = OCTET_STRING_NAME; + +// src/internals/LocalBitStringValueBlock.ts +var pvtsutils10 = __toESM(require_build()); +var LocalBitStringValueBlock = class extends HexBlock(LocalConstructedValueBlock) { + constructor({ + unusedBits = 0, + isConstructed = false, + ...parameters + } = {}) { + super(parameters); + this.unusedBits = unusedBits; + this.isConstructed = isConstructed; + this.blockLength = this.valueHexView.byteLength; + } + fromBER(inputBuffer, inputOffset, inputLength) { + if (!inputLength) { + return inputOffset; + } + let resultOffset = -1; + if (this.isConstructed) { + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) + return resultOffset; + for (const value of this.value) { + const currentBlockName = value.constructor.NAME; + if (currentBlockName === END_OF_CONTENT_NAME) { + if (this.isIndefiniteForm) + break; + else { + this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only"; + return -1; + } + } + if (currentBlockName !== BIT_STRING_NAME) { + this.error = "BIT STRING may consists of BIT STRINGs only"; + return -1; + } + const valueBlock = value.valueBlock; + if (this.unusedBits > 0 && valueBlock.unusedBits > 0) { + this.error = 'Using of "unused bits" inside constructive BIT STRING allowed for least one only'; + return -1; + } + this.unusedBits = valueBlock.unusedBits; + } + return resultOffset; + } + const inputView = pvtsutils10.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + this.unusedBits = intBuffer[0]; + if (this.unusedBits > 7) { + this.error = "Unused bits for BitString must be in range 0-7"; + return -1; + } + if (!this.unusedBits) { + const buf = intBuffer.subarray(1); + try { + if (buf.byteLength) { + const asn = localFromBER(buf, 0, buf.byteLength); + if (asn.offset !== -1 && asn.offset === inputLength - 1) { + this.value = [asn.result]; + } + } + } catch (e) { + } + } + this.valueHexView = intBuffer.subarray(1); + this.blockLength = intBuffer.length; + return inputOffset + inputLength; + } + toBER(sizeOnly, writer) { + if (this.isConstructed) { + return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer); + } + if (sizeOnly) { + return new ArrayBuffer(this.valueHexView.byteLength + 1); + } + if (!this.valueHexView.byteLength) { + return EMPTY_BUFFER; + } + const retView = new Uint8Array(this.valueHexView.length + 1); + retView[0] = this.unusedBits; + retView.set(this.valueHexView, 1); + return retView.buffer; + } + toJSON() { + return { + ...super.toJSON(), + unusedBits: this.unusedBits, + isConstructed: this.isConstructed + }; + } +}; +LocalBitStringValueBlock.NAME = "BitStringValueBlock"; + +// src/BitString.ts +var _BitString = class extends BaseBlock { + constructor({ + idBlock = {}, + lenBlock = {}, + ...parameters + } = {}) { + var _a, _b; + (_b = parameters.isConstructed) != null ? _b : parameters.isConstructed = !!((_a = parameters.value) == null ? void 0 : _a.length); + super({ + idBlock: { + isConstructed: parameters.isConstructed, + ...idBlock + }, + lenBlock: { + ...lenBlock, + isIndefiniteForm: !!parameters.isIndefiniteForm + }, + ...parameters + }, LocalBitStringValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 3; + } + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + onAsciiEncoding() { + if (this.valueBlock.isConstructed || this.valueBlock.value && this.valueBlock.value.length) { + return Constructed.prototype.onAsciiEncoding.call(this); + } else { + const bits = []; + const valueHex = this.valueBlock.valueHexView; + for (const byte of valueHex) { + bits.push(byte.toString(2).padStart(8, "0")); + } + const bitsStr = bits.join(""); + return `${this.constructor.NAME} : ${bitsStr.substring(0, bitsStr.length - this.valueBlock.unusedBits)}`; + } + } +}; +var BitString = _BitString; +(() => { + typeStore.BitString = _BitString; +})(); +BitString.NAME = BIT_STRING_NAME; + +// src/Integer.ts +var pvtsutils11 = __toESM(require_build()); + +// src/internals/LocalIntegerValueBlock.ts +function viewAdd(first, second) { + const c = new Uint8Array([0]); + const firstView = new Uint8Array(first); + const secondView = new Uint8Array(second); + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + const secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + let value = 0; + const max = secondViewCopyLength < firstViewCopyLength ? firstViewCopyLength : secondViewCopyLength; + let counter = 0; + for (let i = max; i >= 0; i--, counter++) { + switch (true) { + case counter < secondViewCopy.length: + value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0]; + break; + default: + value = firstViewCopy[firstViewCopyLength - counter] + c[0]; + } + c[0] = value / 10; + switch (true) { + case counter >= firstViewCopy.length: + firstViewCopy = utilConcatView(new Uint8Array([value % 10]), firstViewCopy); + break; + default: + firstViewCopy[firstViewCopyLength - counter] = value % 10; + } + } + if (c[0] > 0) + firstViewCopy = utilConcatView(c, firstViewCopy); + return firstViewCopy; +} +function power2(n) { + if (n >= powers2.length) { + for (let p = powers2.length; p <= n; p++) { + const c = new Uint8Array([0]); + let digits = powers2[p - 1].slice(0); + for (let i = digits.length - 1; i >= 0; i--) { + const newValue = new Uint8Array([(digits[i] << 1) + c[0]]); + c[0] = newValue[0] / 10; + digits[i] = newValue[0] % 10; + } + if (c[0] > 0) + digits = utilConcatView(c, digits); + powers2.push(digits); + } + } + return powers2[n]; +} +function viewSub(first, second) { + let b = 0; + const firstView = new Uint8Array(first); + const secondView = new Uint8Array(second); + const firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + const secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + let value; + let counter = 0; + for (let i = secondViewCopyLength; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b; + switch (true) { + case value < 0: + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + break; + default: + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + } + } + if (b > 0) { + for (let i = firstViewCopyLength - secondViewCopyLength + 1; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - b; + if (value < 0) { + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + } else { + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + break; + } + } + } + return firstViewCopy.slice(); +} +var _LocalIntegerValueBlock = class extends HexBlock(ValueBlock) { + constructor({ + value, + ...parameters + } = {}) { + super(parameters); + this._valueDec = 0; + if (parameters.valueHex) { + this.setValueHex(); + } + if (value !== void 0) { + this.valueDec = value; + } + } + setValueHex() { + if (this.valueHexView.length >= 4) { + this.warnings.push("Too big Integer for decoding, hex only"); + this.isHexOnly = true; + this._valueDec = 0; + } else { + this.isHexOnly = false; + if (this.valueHexView.length > 0) { + this._valueDec = utilDecodeTC.call(this); + } + } + } + set valueDec(v) { + this._valueDec = v; + this.isHexOnly = false; + this.valueHexView = new Uint8Array(utilEncodeTC(v)); + } + get valueDec() { + return this._valueDec; + } + fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) { + const offset = this.fromBER(inputBuffer, inputOffset, inputLength); + if (offset === -1) + return offset; + const view = this.valueHexView; + if (view[0] === 0 && (view[1] & 128) !== 0) { + this.valueHexView = view.subarray(1); + } else { + if (expectedLength !== 0) { + if (view.length < expectedLength) { + if (expectedLength - view.length > 1) + expectedLength = view.length + 1; + this.valueHexView = view.subarray(expectedLength - view.length); + } + } + } + return offset; + } + toDER(sizeOnly = false) { + const view = this.valueHexView; + switch (true) { + case (view[0] & 128) !== 0: + { + const updatedView = new Uint8Array(this.valueHexView.length + 1); + updatedView[0] = 0; + updatedView.set(view, 1); + this.valueHexView = updatedView; + } + break; + case (view[0] === 0 && (view[1] & 128) === 0): + { + this.valueHexView = this.valueHexView.subarray(1); + } + break; + default: + } + return this.toBER(sizeOnly); + } + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) { + return resultOffset; + } + this.setValueHex(); + return resultOffset; + } + toBER(sizeOnly) { + return sizeOnly ? new ArrayBuffer(this.valueHexView.length) : this.valueHexView.slice().buffer; + } + toJSON() { + return { + ...super.toJSON(), + valueDec: this.valueDec + }; + } + toString() { + const firstBit = this.valueHexView.length * 8 - 1; + let digits = new Uint8Array(this.valueHexView.length * 8 / 3); + let bitNumber = 0; + let currentByte; + const asn1View = this.valueHexView; + let result = ""; + let flag = false; + for (let byteNumber = asn1View.byteLength - 1; byteNumber >= 0; byteNumber--) { + currentByte = asn1View[byteNumber]; + for (let i = 0; i < 8; i++) { + if ((currentByte & 1) === 1) { + switch (bitNumber) { + case firstBit: + digits = viewSub(power2(bitNumber), digits); + result = "-"; + break; + default: + digits = viewAdd(digits, power2(bitNumber)); + } + } + bitNumber++; + currentByte >>= 1; + } + } + for (let i = 0; i < digits.length; i++) { + if (digits[i]) + flag = true; + if (flag) + result += digitsString.charAt(digits[i]); + } + if (flag === false) + result += digitsString.charAt(0); + return result; + } +}; +var LocalIntegerValueBlock = _LocalIntegerValueBlock; +LocalIntegerValueBlock.NAME = "IntegerValueBlock"; +(() => { + Object.defineProperty(_LocalIntegerValueBlock.prototype, "valueHex", { + set: function(v) { + this.valueHexView = new Uint8Array(v); + this.setValueHex(); + }, + get: function() { + return this.valueHexView.slice().buffer; + } + }); +})(); + +// src/Integer.ts +var _Integer = class extends BaseBlock { + constructor(parameters = {}) { + super(parameters, LocalIntegerValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 2; + } + /** + * Converts Integer into BigInt + * @throws Throws Error if BigInt is not supported + * @since 3.0.0 + */ + toBigInt() { + assertBigInt(); + return BigInt(this.valueBlock.toString()); + } + /** + * Creates Integer from BigInt value + * @param value BigInt value + * @returns ASN.1 Integer + * @throws Throws Error if BigInt is not supported + * @since 3.0.0 + */ + static fromBigInt(value) { + assertBigInt(); + const bigIntValue = BigInt(value); + const writer = new ViewWriter(); + const hex = bigIntValue.toString(16).replace(/^-/, ""); + const view = new Uint8Array(pvtsutils11.Convert.FromHex(hex)); + if (bigIntValue < 0) { + const first = new Uint8Array(view.length + (view[0] & 128 ? 1 : 0)); + first[0] |= 128; + const firstInt = BigInt(`0x${pvtsutils11.Convert.ToHex(first)}`); + const secondInt = firstInt + bigIntValue; + const second = pvtsutils11.BufferSourceConverter.toUint8Array(pvtsutils11.Convert.FromHex(secondInt.toString(16))); + second[0] |= 128; + writer.write(second); + } else { + if (view[0] & 128) { + writer.write(new Uint8Array([0])); + } + writer.write(view); + } + const res = new _Integer({ + valueHex: writer.final() + }); + return res; + } + convertToDER() { + const integer = new _Integer({ valueHex: this.valueBlock.valueHexView }); + integer.valueBlock.toDER(); + return integer; + } + /** + * Convert current Integer value from DER to BER format + * @returns + */ + convertFromDER() { + return new _Integer({ + valueHex: this.valueBlock.valueHexView[0] === 0 ? this.valueBlock.valueHexView.subarray(1) : this.valueBlock.valueHexView + }); + } + onAsciiEncoding() { + return `${this.constructor.NAME} : ${this.valueBlock.toString()}`; + } +}; +var Integer = _Integer; +(() => { + typeStore.Integer = _Integer; +})(); +Integer.NAME = "INTEGER"; + +// src/Enumerated.ts +var _Enumerated = class extends Integer { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 10; + } +}; +var Enumerated = _Enumerated; +(() => { + typeStore.Enumerated = _Enumerated; +})(); +Enumerated.NAME = "ENUMERATED"; + +// src/internals/LocalSidValueBlock.ts +var pvtsutils12 = __toESM(require_build()); +var LocalSidValueBlock = class extends HexBlock(ValueBlock) { + constructor({ + valueDec = -1, + isFirstSid = false, + ...parameters + } = {}) { + super(parameters); + this.valueDec = valueDec; + this.isFirstSid = isFirstSid; + } + fromBER(inputBuffer, inputOffset, inputLength) { + if (!inputLength) { + return inputOffset; + } + const inputView = pvtsutils12.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + this.valueHexView = new Uint8Array(inputLength); + for (let i = 0; i < inputLength; i++) { + this.valueHexView[i] = intBuffer[i] & 127; + this.blockLength++; + if ((intBuffer[i] & 128) === 0) + break; + } + const tempView = new Uint8Array(this.blockLength); + for (let i = 0; i < this.blockLength; i++) { + tempView[i] = this.valueHexView[i]; + } + this.valueHexView = tempView; + if ((intBuffer[this.blockLength - 1] & 128) !== 0) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + if (this.valueHexView[0] === 0) + this.warnings.push("Needlessly long format of SID encoding"); + if (this.blockLength <= 8) + this.valueDec = utilFromBase(this.valueHexView, 7); + else { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + return inputOffset + this.blockLength; + } + set valueBigInt(value) { + assertBigInt(); + let bits = BigInt(value).toString(2); + while (bits.length % 7) { + bits = "0" + bits; + } + const bytes = new Uint8Array(bits.length / 7); + for (let i = 0; i < bytes.length; i++) { + bytes[i] = parseInt(bits.slice(i * 7, i * 7 + 7), 2) + (i + 1 < bytes.length ? 128 : 0); + } + this.fromBER(bytes.buffer, 0, bytes.length); + } + toBER(sizeOnly) { + if (this.isHexOnly) { + if (sizeOnly) + return new ArrayBuffer(this.valueHexView.byteLength); + const curView = this.valueHexView; + const retView2 = new Uint8Array(this.blockLength); + for (let i = 0; i < this.blockLength - 1; i++) + retView2[i] = curView[i] | 128; + retView2[this.blockLength - 1] = curView[this.blockLength - 1]; + return retView2.buffer; + } + const encodedBuf = utilToBase(this.valueDec, 7); + if (encodedBuf.byteLength === 0) { + this.error = "Error during encoding SID value"; + return EMPTY_BUFFER; + } + const retView = new Uint8Array(encodedBuf.byteLength); + if (!sizeOnly) { + const encodedView = new Uint8Array(encodedBuf); + const len = encodedBuf.byteLength - 1; + for (let i = 0; i < len; i++) + retView[i] = encodedView[i] | 128; + retView[len] = encodedView[len]; + } + return retView; + } + toString() { + let result = ""; + if (this.isHexOnly) + result = pvtsutils12.Convert.ToHex(this.valueHexView); + else { + if (this.isFirstSid) { + let sidValue = this.valueDec; + if (this.valueDec <= 39) + result = "0."; + else { + if (this.valueDec <= 79) { + result = "1."; + sidValue -= 40; + } else { + result = "2."; + sidValue -= 80; + } + } + result += sidValue.toString(); + } else + result = this.valueDec.toString(); + } + return result; + } + toJSON() { + return { + ...super.toJSON(), + valueDec: this.valueDec, + isFirstSid: this.isFirstSid + }; + } +}; +LocalSidValueBlock.NAME = "sidBlock"; + +// src/internals/LocalObjectIdentifierValueBlock.ts +var LocalObjectIdentifierValueBlock = class extends ValueBlock { + constructor({ + value = EMPTY_STRING, + ...parameters + } = {}) { + super(parameters); + this.value = []; + if (value) { + this.fromString(value); + } + } + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = inputOffset; + while (inputLength > 0) { + const sidBlock = new LocalSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === -1) { + this.blockLength = 0; + this.error = sidBlock.error; + return resultOffset; + } + if (this.value.length === 0) + sidBlock.isFirstSid = true; + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + this.value.push(sidBlock); + } + return resultOffset; + } + toBER(sizeOnly) { + const retBuffers = []; + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) { + this.error = this.value[i].error; + return EMPTY_BUFFER; + } + retBuffers.push(valueBuf); + } + return concat(retBuffers); + } + fromString(string) { + this.value = []; + let pos1 = 0; + let pos2 = 0; + let sid = ""; + let flag = false; + do { + pos2 = string.indexOf(".", pos1); + if (pos2 === -1) + sid = string.substring(pos1); + else + sid = string.substring(pos1, pos2); + pos1 = pos2 + 1; + if (flag) { + const sidBlock = this.value[0]; + let plus = 0; + switch (sidBlock.valueDec) { + case 0: + break; + case 1: + plus = 40; + break; + case 2: + plus = 80; + break; + default: + this.value = []; + return; + } + const parsedSID = parseInt(sid, 10); + if (isNaN(parsedSID)) + return; + sidBlock.valueDec = parsedSID + plus; + flag = false; + } else { + const sidBlock = new LocalSidValueBlock(); + if (sid > Number.MAX_SAFE_INTEGER) { + assertBigInt(); + const sidValue = BigInt(sid); + sidBlock.valueBigInt = sidValue; + } else { + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) + return; + } + if (!this.value.length) { + sidBlock.isFirstSid = true; + flag = true; + } + this.value.push(sidBlock); + } + } while (pos2 !== -1); + } + toString() { + let result = ""; + let isHexOnly = false; + for (let i = 0; i < this.value.length; i++) { + isHexOnly = this.value[i].isHexOnly; + let sidStr = this.value[i].toString(); + if (i !== 0) + result = `${result}.`; + if (isHexOnly) { + sidStr = `{${sidStr}}`; + if (this.value[i].isFirstSid) + result = `2.{${sidStr} - 80}`; + else + result += sidStr; + } else + result += sidStr; + } + return result; + } + toJSON() { + const object = { + ...super.toJSON(), + value: this.toString(), + sidArray: [] + }; + for (let i = 0; i < this.value.length; i++) { + object.sidArray.push(this.value[i].toJSON()); + } + return object; + } +}; +LocalObjectIdentifierValueBlock.NAME = "ObjectIdentifierValueBlock"; + +// src/ObjectIdentifier.ts +var _ObjectIdentifier = class extends BaseBlock { + /** + * Gets string representation of Object Identifier + * @since 3.0.0 + */ + getValue() { + return this.valueBlock.toString(); + } + /** + * Sets Object Identifier value from string + * @param value String value + * @since 3.0.0 + */ + setValue(value) { + this.valueBlock.fromString(value); + } + constructor(parameters = {}) { + super(parameters, LocalObjectIdentifierValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 6; + } + onAsciiEncoding() { + return `${this.constructor.NAME} : ${this.valueBlock.toString() || "empty"}`; + } + toJSON() { + return { + ...super.toJSON(), + value: this.getValue() + }; + } +}; +var ObjectIdentifier = _ObjectIdentifier; +(() => { + typeStore.ObjectIdentifier = _ObjectIdentifier; +})(); +ObjectIdentifier.NAME = "OBJECT IDENTIFIER"; + +// src/internals/LocalRelativeSidValueBlock.ts +var pvtsutils13 = __toESM(require_build()); +var LocalRelativeSidValueBlock = class extends HexBlock(LocalBaseBlock) { + constructor({ + valueDec = 0, + ...parameters + } = {}) { + super(parameters); + this.valueDec = valueDec; + } + fromBER(inputBuffer, inputOffset, inputLength) { + if (inputLength === 0) + return inputOffset; + const inputView = pvtsutils13.BufferSourceConverter.toUint8Array(inputBuffer); + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) + return -1; + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + this.valueHexView = new Uint8Array(inputLength); + for (let i = 0; i < inputLength; i++) { + this.valueHexView[i] = intBuffer[i] & 127; + this.blockLength++; + if ((intBuffer[i] & 128) === 0) + break; + } + const tempView = new Uint8Array(this.blockLength); + for (let i = 0; i < this.blockLength; i++) + tempView[i] = this.valueHexView[i]; + this.valueHexView = tempView; + if ((intBuffer[this.blockLength - 1] & 128) !== 0) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + if (this.valueHexView[0] === 0) + this.warnings.push("Needlessly long format of SID encoding"); + if (this.blockLength <= 8) + this.valueDec = utilFromBase(this.valueHexView, 7); + else { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + return inputOffset + this.blockLength; + } + toBER(sizeOnly) { + if (this.isHexOnly) { + if (sizeOnly) + return new ArrayBuffer(this.valueHexView.byteLength); + const curView = this.valueHexView; + const retView2 = new Uint8Array(this.blockLength); + for (let i = 0; i < this.blockLength - 1; i++) + retView2[i] = curView[i] | 128; + retView2[this.blockLength - 1] = curView[this.blockLength - 1]; + return retView2.buffer; + } + const encodedBuf = utilToBase(this.valueDec, 7); + if (encodedBuf.byteLength === 0) { + this.error = "Error during encoding SID value"; + return EMPTY_BUFFER; + } + const retView = new Uint8Array(encodedBuf.byteLength); + if (!sizeOnly) { + const encodedView = new Uint8Array(encodedBuf); + const len = encodedBuf.byteLength - 1; + for (let i = 0; i < len; i++) + retView[i] = encodedView[i] | 128; + retView[len] = encodedView[len]; + } + return retView.buffer; + } + toString() { + let result = ""; + if (this.isHexOnly) + result = pvtsutils13.Convert.ToHex(this.valueHexView); + else { + result = this.valueDec.toString(); + } + return result; + } + toJSON() { + return { + ...super.toJSON(), + valueDec: this.valueDec + }; + } +}; +LocalRelativeSidValueBlock.NAME = "relativeSidBlock"; + +// src/internals/LocalRelativeObjectIdentifierValueBlock.ts +var LocalRelativeObjectIdentifierValueBlock = class extends ValueBlock { + constructor({ + value = EMPTY_STRING, + ...parameters + } = {}) { + super(parameters); + this.value = []; + if (value) { + this.fromString(value); + } + } + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = inputOffset; + while (inputLength > 0) { + const sidBlock = new LocalRelativeSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === -1) { + this.blockLength = 0; + this.error = sidBlock.error; + return resultOffset; + } + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + this.value.push(sidBlock); + } + return resultOffset; + } + toBER(sizeOnly, writer) { + const retBuffers = []; + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) { + this.error = this.value[i].error; + return EMPTY_BUFFER; + } + retBuffers.push(valueBuf); + } + return concat(retBuffers); + } + fromString(string) { + this.value = []; + let pos1 = 0; + let pos2 = 0; + let sid = ""; + do { + pos2 = string.indexOf(".", pos1); + if (pos2 === -1) + sid = string.substring(pos1); + else + sid = string.substring(pos1, pos2); + pos1 = pos2 + 1; + const sidBlock = new LocalRelativeSidValueBlock(); + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) + return true; + this.value.push(sidBlock); + } while (pos2 !== -1); + return true; + } + toString() { + let result = ""; + let isHexOnly = false; + for (let i = 0; i < this.value.length; i++) { + isHexOnly = this.value[i].isHexOnly; + let sidStr = this.value[i].toString(); + if (i !== 0) + result = `${result}.`; + if (isHexOnly) { + sidStr = `{${sidStr}}`; + result += sidStr; + } else + result += sidStr; + } + return result; + } + toJSON() { + const object = { + ...super.toJSON(), + value: this.toString(), + sidArray: [] + }; + for (let i = 0; i < this.value.length; i++) + object.sidArray.push(this.value[i].toJSON()); + return object; + } +}; +LocalRelativeObjectIdentifierValueBlock.NAME = "RelativeObjectIdentifierValueBlock"; + +// src/RelativeObjectIdentifier.ts +var _RelativeObjectIdentifier = class extends BaseBlock { + /** + * Gets string representation of Relative Object Identifier + * @since 3.0.0 + */ + getValue() { + return this.valueBlock.toString(); + } + /** + * Sets Relative Object Identifier value from string + * @param value String value + * @since 3.0.0 + */ + setValue(value) { + this.valueBlock.fromString(value); + } + constructor(parameters = {}) { + super(parameters, LocalRelativeObjectIdentifierValueBlock); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 13; + } + onAsciiEncoding() { + return `${this.constructor.NAME} : ${this.valueBlock.toString() || "empty"}`; + } + toJSON() { + return { + ...super.toJSON(), + value: this.getValue() + }; + } +}; +var RelativeObjectIdentifier = _RelativeObjectIdentifier; +(() => { + typeStore.RelativeObjectIdentifier = _RelativeObjectIdentifier; +})(); +RelativeObjectIdentifier.NAME = "RelativeObjectIdentifier"; + +// src/Sequence.ts +var _Sequence = class extends Constructed { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 16; + } +}; +var Sequence = _Sequence; +(() => { + typeStore.Sequence = _Sequence; +})(); +Sequence.NAME = "SEQUENCE"; + +// src/Set.ts +var _Set = class extends Constructed { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 17; + } +}; +var Set = _Set; +(() => { + typeStore.Set = _Set; +})(); +Set.NAME = "SET"; + +// src/internals/LocalUtf8StringValueBlock.ts +var pvtsutils15 = __toESM(require_build()); + +// src/internals/LocalSimpleStringBlock.ts +var pvtsutils14 = __toESM(require_build()); + +// src/internals/LocalStringValueBlock.ts +var LocalStringValueBlock = class extends HexBlock(ValueBlock) { + constructor({ + ...parameters + } = {}) { + super(parameters); + this.isHexOnly = true; + this.value = EMPTY_STRING; + } + toJSON() { + return { + ...super.toJSON(), + value: this.value + }; + } +}; +LocalStringValueBlock.NAME = "StringValueBlock"; + +// src/internals/LocalSimpleStringValueBlock.ts +var LocalSimpleStringValueBlock = class extends LocalStringValueBlock { +}; +LocalSimpleStringValueBlock.NAME = "SimpleStringValueBlock"; + +// src/internals/LocalSimpleStringBlock.ts +var LocalSimpleStringBlock = class extends BaseStringBlock { + constructor({ + ...parameters + } = {}) { + super(parameters, LocalSimpleStringValueBlock); + } + fromBuffer(inputBuffer) { + this.valueBlock.value = String.fromCharCode.apply(null, pvtsutils14.BufferSourceConverter.toUint8Array(inputBuffer)); + } + fromString(inputString) { + const strLen = inputString.length; + const view = this.valueBlock.valueHexView = new Uint8Array(strLen); + for (let i = 0; i < strLen; i++) + view[i] = inputString.charCodeAt(i); + this.valueBlock.value = inputString; + } +}; +LocalSimpleStringBlock.NAME = "SIMPLE STRING"; + +// src/internals/LocalUtf8StringValueBlock.ts +var LocalUtf8StringValueBlock = class extends LocalSimpleStringBlock { + fromBuffer(inputBuffer) { + this.valueBlock.valueHexView = pvtsutils15.BufferSourceConverter.toUint8Array(inputBuffer); + try { + this.valueBlock.value = pvtsutils15.Convert.ToUtf8String(inputBuffer); + } catch (ex) { + this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`); + this.valueBlock.value = pvtsutils15.Convert.ToBinary(inputBuffer); + } + } + fromString(inputString) { + this.valueBlock.valueHexView = new Uint8Array(pvtsutils15.Convert.FromUtf8String(inputString)); + this.valueBlock.value = inputString; + } +}; +LocalUtf8StringValueBlock.NAME = "Utf8StringValueBlock"; + +// src/Utf8String.ts +var _Utf8String = class extends LocalUtf8StringValueBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 12; + } +}; +var Utf8String = _Utf8String; +(() => { + typeStore.Utf8String = _Utf8String; +})(); +Utf8String.NAME = "UTF8String"; + +// src/internals/LocalBmpStringValueBlock.ts +var pvtsutils16 = __toESM(require_build()); +var LocalBmpStringValueBlock = class extends LocalSimpleStringBlock { + fromBuffer(inputBuffer) { + this.valueBlock.value = pvtsutils16.Convert.ToUtf16String(inputBuffer); + this.valueBlock.valueHexView = pvtsutils16.BufferSourceConverter.toUint8Array(inputBuffer); + } + fromString(inputString) { + this.valueBlock.value = inputString; + this.valueBlock.valueHexView = new Uint8Array(pvtsutils16.Convert.FromUtf16String(inputString)); + } +}; +LocalBmpStringValueBlock.NAME = "BmpStringValueBlock"; + +// src/BmpString.ts +var _BmpString = class extends LocalBmpStringValueBlock { + constructor({ + ...parameters + } = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 30; + } +}; +var BmpString = _BmpString; +(() => { + typeStore.BmpString = _BmpString; +})(); +BmpString.NAME = "BMPString"; + +// src/internals/LocalUniversalStringValueBlockParams.ts +var LocalUniversalStringValueBlock = class extends LocalSimpleStringBlock { + fromBuffer(inputBuffer) { + const copyBuffer = ArrayBuffer.isView(inputBuffer) ? inputBuffer.slice().buffer : inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + for (let i = 0; i < valueView.length; i += 4) { + valueView[i] = valueView[i + 3]; + valueView[i + 1] = valueView[i + 2]; + valueView[i + 2] = 0; + valueView[i + 3] = 0; + } + this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer)); + } + fromString(inputString) { + const strLength = inputString.length; + const valueHexView = this.valueBlock.valueHexView = new Uint8Array(strLength * 4); + for (let i = 0; i < strLength; i++) { + const codeBuf = utilToBase(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if (codeView.length > 4) + continue; + const dif = 4 - codeView.length; + for (let j = codeView.length - 1; j >= 0; j--) + valueHexView[i * 4 + j + dif] = codeView[j]; + } + this.valueBlock.value = inputString; + } +}; +LocalUniversalStringValueBlock.NAME = "UniversalStringValueBlock"; + +// src/UniversalString.ts +var _UniversalString = class extends LocalUniversalStringValueBlock { + constructor({ + ...parameters + } = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 28; + } +}; +var UniversalString = _UniversalString; +(() => { + typeStore.UniversalString = _UniversalString; +})(); +UniversalString.NAME = "UniversalString"; + +// src/NumericString.ts +var _NumericString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 18; + } +}; +var NumericString = _NumericString; +(() => { + typeStore.NumericString = _NumericString; +})(); +NumericString.NAME = "NumericString"; + +// src/PrintableString.ts +var _PrintableString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 19; + } +}; +var PrintableString = _PrintableString; +(() => { + typeStore.PrintableString = _PrintableString; +})(); +PrintableString.NAME = "PrintableString"; + +// src/TeletexString.ts +var _TeletexString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 20; + } +}; +var TeletexString = _TeletexString; +(() => { + typeStore.TeletexString = _TeletexString; +})(); +TeletexString.NAME = "TeletexString"; + +// src/VideotexString.ts +var _VideotexString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 21; + } +}; +var VideotexString = _VideotexString; +(() => { + typeStore.VideotexString = _VideotexString; +})(); +VideotexString.NAME = "VideotexString"; + +// src/IA5String.ts +var _IA5String = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 22; + } +}; +var IA5String = _IA5String; +(() => { + typeStore.IA5String = _IA5String; +})(); +IA5String.NAME = "IA5String"; + +// src/GraphicString.ts +var _GraphicString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 25; + } +}; +var GraphicString = _GraphicString; +(() => { + typeStore.GraphicString = _GraphicString; +})(); +GraphicString.NAME = "GraphicString"; + +// src/VisibleString.ts +var _VisibleString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 26; + } +}; +var VisibleString = _VisibleString; +(() => { + typeStore.VisibleString = _VisibleString; +})(); +VisibleString.NAME = "VisibleString"; + +// src/GeneralString.ts +var _GeneralString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 27; + } +}; +var GeneralString = _GeneralString; +(() => { + typeStore.GeneralString = _GeneralString; +})(); +GeneralString.NAME = "GeneralString"; + +// src/CharacterString.ts +var _CharacterString = class extends LocalSimpleStringBlock { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 29; + } +}; +var CharacterString = _CharacterString; +(() => { + typeStore.CharacterString = _CharacterString; +})(); +CharacterString.NAME = "CharacterString"; + +// src/UTCTime.ts +var pvtsutils17 = __toESM(require_build()); +var _UTCTime = class extends VisibleString { + constructor({ + value, + valueDate, + ...parameters + } = {}) { + super(parameters); + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + if (value) { + this.fromString(value); + this.valueBlock.valueHexView = new Uint8Array(value.length); + for (let i = 0; i < value.length; i++) + this.valueBlock.valueHexView[i] = value.charCodeAt(i); + } + if (valueDate) { + this.fromDate(valueDate); + this.valueBlock.valueHexView = new Uint8Array(this.toBuffer()); + } + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 23; + } + fromBuffer(inputBuffer) { + this.fromString(String.fromCharCode.apply(null, pvtsutils17.BufferSourceConverter.toUint8Array(inputBuffer))); + } + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns + */ + toBuffer() { + const str = this.toString(); + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + for (let i = 0; i < str.length; i++) + view[i] = str.charCodeAt(i); + return buffer; + } + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + } + toDate() { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)); + } + fromString(inputString) { + const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig; + const parserArray = parser.exec(inputString); + if (parserArray === null) { + this.error = "Wrong input string for conversion"; + return; + } + const year = parseInt(parserArray[1], 10); + if (year >= 50) + this.year = 1900 + year; + else + this.year = 2e3 + year; + this.month = parseInt(parserArray[2], 10); + this.day = parseInt(parserArray[3], 10); + this.hour = parseInt(parserArray[4], 10); + this.minute = parseInt(parserArray[5], 10); + this.second = parseInt(parserArray[6], 10); + } + toString(encoding = "iso") { + if (encoding === "iso") { + const outputArray = new Array(7); + outputArray[0] = padNumber(this.year < 2e3 ? this.year - 1900 : this.year - 2e3, 2); + outputArray[1] = padNumber(this.month, 2); + outputArray[2] = padNumber(this.day, 2); + outputArray[3] = padNumber(this.hour, 2); + outputArray[4] = padNumber(this.minute, 2); + outputArray[5] = padNumber(this.second, 2); + outputArray[6] = "Z"; + return outputArray.join(""); + } + return super.toString(encoding); + } + onAsciiEncoding() { + return `${this.constructor.NAME} : ${this.toDate().toISOString()}`; + } + toJSON() { + return { + ...super.toJSON(), + year: this.year, + month: this.month, + day: this.day, + hour: this.hour, + minute: this.minute, + second: this.second + }; + } +}; +var UTCTime = _UTCTime; +(() => { + typeStore.UTCTime = _UTCTime; +})(); +UTCTime.NAME = "UTCTime"; + +// src/GeneralizedTime.ts +var _GeneralizedTime = class extends UTCTime { + constructor(parameters = {}) { + var _a; + super(parameters); + (_a = this.millisecond) != null ? _a : this.millisecond = 0; + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 24; + } + fromDate(inputDate) { + super.fromDate(inputDate); + this.millisecond = inputDate.getUTCMilliseconds(); + } + toDate() { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)); + } + fromString(inputString) { + let isUTC = false; + let timeString = ""; + let dateTimeString = ""; + let fractionPart = 0; + let parser; + let hourDifference = 0; + let minuteDifference = 0; + if (inputString[inputString.length - 1] === "Z") { + timeString = inputString.substring(0, inputString.length - 1); + isUTC = true; + } else { + const number = new Number(inputString[inputString.length - 1]); + if (isNaN(number.valueOf())) + throw new Error("Wrong input string for conversion"); + timeString = inputString; + } + if (isUTC) { + if (timeString.indexOf("+") !== -1) + throw new Error("Wrong input string for conversion"); + if (timeString.indexOf("-") !== -1) + throw new Error("Wrong input string for conversion"); + } else { + let multiplier = 1; + let differencePosition = timeString.indexOf("+"); + let differenceString = ""; + if (differencePosition === -1) { + differencePosition = timeString.indexOf("-"); + multiplier = -1; + } + if (differencePosition !== -1) { + differenceString = timeString.substring(differencePosition + 1); + timeString = timeString.substring(0, differencePosition); + if (differenceString.length !== 2 && differenceString.length !== 4) + throw new Error("Wrong input string for conversion"); + let number = parseInt(differenceString.substring(0, 2), 10); + if (isNaN(number.valueOf())) + throw new Error("Wrong input string for conversion"); + hourDifference = multiplier * number; + if (differenceString.length === 4) { + number = parseInt(differenceString.substring(2, 4), 10); + if (isNaN(number.valueOf())) + throw new Error("Wrong input string for conversion"); + minuteDifference = multiplier * number; + } + } + } + let fractionPointPosition = timeString.indexOf("."); + if (fractionPointPosition === -1) + fractionPointPosition = timeString.indexOf(","); + if (fractionPointPosition !== -1) { + const fractionPartCheck = new Number(`0${timeString.substring(fractionPointPosition)}`); + if (isNaN(fractionPartCheck.valueOf())) + throw new Error("Wrong input string for conversion"); + fractionPart = fractionPartCheck.valueOf(); + dateTimeString = timeString.substring(0, fractionPointPosition); + } else + dateTimeString = timeString; + switch (true) { + case dateTimeString.length === 8: + parser = /(\d{4})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) + throw new Error("Wrong input string for conversion"); + break; + case dateTimeString.length === 10: + parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.minute = Math.floor(fractionResult); + fractionResult = 60 * (fractionResult - this.minute); + this.second = Math.floor(fractionResult); + fractionResult = 1e3 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case dateTimeString.length === 12: + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.second = Math.floor(fractionResult); + fractionResult = 1e3 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case dateTimeString.length === 14: + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) { + const fractionResult = 1e3 * fractionPart; + this.millisecond = Math.floor(fractionResult); + } + break; + default: + throw new Error("Wrong input string for conversion"); + } + const parserArray = parser.exec(dateTimeString); + if (parserArray === null) + throw new Error("Wrong input string for conversion"); + for (let j = 1; j < parserArray.length; j++) { + switch (j) { + case 1: + this.year = parseInt(parserArray[j], 10); + break; + case 2: + this.month = parseInt(parserArray[j], 10); + break; + case 3: + this.day = parseInt(parserArray[j], 10); + break; + case 4: + this.hour = parseInt(parserArray[j], 10) + hourDifference; + break; + case 5: + this.minute = parseInt(parserArray[j], 10) + minuteDifference; + break; + case 6: + this.second = parseInt(parserArray[j], 10); + break; + default: + throw new Error("Wrong input string for conversion"); + } + } + if (isUTC === false) { + const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + this.year = tempDate.getUTCFullYear(); + this.month = tempDate.getUTCMonth(); + this.day = tempDate.getUTCDay(); + this.hour = tempDate.getUTCHours(); + this.minute = tempDate.getUTCMinutes(); + this.second = tempDate.getUTCSeconds(); + this.millisecond = tempDate.getUTCMilliseconds(); + } + } + toString(encoding = "iso") { + if (encoding === "iso") { + const outputArray = []; + outputArray.push(padNumber(this.year, 4)); + outputArray.push(padNumber(this.month, 2)); + outputArray.push(padNumber(this.day, 2)); + outputArray.push(padNumber(this.hour, 2)); + outputArray.push(padNumber(this.minute, 2)); + outputArray.push(padNumber(this.second, 2)); + if (this.millisecond !== 0) { + outputArray.push("."); + outputArray.push(padNumber(this.millisecond, 3)); + } + outputArray.push("Z"); + return outputArray.join(""); + } + return super.toString(encoding); + } + toJSON() { + return { + ...super.toJSON(), + millisecond: this.millisecond + }; + } +}; +var GeneralizedTime = _GeneralizedTime; +(() => { + typeStore.GeneralizedTime = _GeneralizedTime; +})(); +GeneralizedTime.NAME = "GeneralizedTime"; + +// src/DATE.ts +var _DATE = class extends Utf8String { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 31; + } +}; +var DATE = _DATE; +(() => { + typeStore.DATE = _DATE; +})(); +DATE.NAME = "DATE"; + +// src/TimeOfDay.ts +var _TimeOfDay = class extends Utf8String { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 32; + } +}; +var TimeOfDay = _TimeOfDay; +(() => { + typeStore.TimeOfDay = _TimeOfDay; +})(); +TimeOfDay.NAME = "TimeOfDay"; + +// src/DateTime.ts +var _DateTime = class extends Utf8String { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 33; + } +}; +var DateTime = _DateTime; +(() => { + typeStore.DateTime = _DateTime; +})(); +DateTime.NAME = "DateTime"; + +// src/Duration.ts +var _Duration = class extends Utf8String { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 34; + } +}; +var Duration = _Duration; +(() => { + typeStore.Duration = _Duration; +})(); +Duration.NAME = "Duration"; + +// src/TIME.ts +var _TIME = class extends Utf8String { + constructor(parameters = {}) { + super(parameters); + this.idBlock.tagClass = 1; + this.idBlock.tagNumber = 14; + } +}; +var TIME = _TIME; +(() => { + typeStore.TIME = _TIME; +})(); +TIME.NAME = "TIME"; + +// src/Any.ts +var Any = class { + constructor({ + name = EMPTY_STRING, + optional = false + } = {}) { + this.name = name; + this.optional = optional; + } +}; + +// src/Choice.ts +var Choice = class extends Any { + constructor({ + value = [], + ...parameters + } = {}) { + super(parameters); + this.value = value; + } +}; + +// src/Repeated.ts +var Repeated = class extends Any { + constructor({ + value = new Any(), + local = false, + ...parameters + } = {}) { + super(parameters); + this.value = value; + this.local = local; + } +}; + +// src/RawData.ts +var pvtsutils18 = __toESM(require_build()); +var RawData = class { + /** + * @deprecated Since v3.0.0 + */ + get data() { + return this.dataView.slice().buffer; + } + /** + * @deprecated Since v3.0.0 + */ + set data(value) { + this.dataView = pvtsutils18.BufferSourceConverter.toUint8Array(value); + } + constructor({ data = EMPTY_VIEW } = {}) { + this.dataView = pvtsutils18.BufferSourceConverter.toUint8Array(data); + } + fromBER(inputBuffer, inputOffset, inputLength) { + const endLength = inputOffset + inputLength; + this.dataView = pvtsutils18.BufferSourceConverter.toUint8Array(inputBuffer).subarray(inputOffset, endLength); + return endLength; + } + toBER(sizeOnly) { + return this.dataView.slice().buffer; + } +}; + +// src/schema.ts +var pvtsutils19 = __toESM(require_build()); +function compareSchema(root, inputData, inputSchema) { + if (inputSchema instanceof Choice) { + const choiceResult = false; + for (let j = 0; j < inputSchema.value.length; j++) { + const result = compareSchema(root, inputData, inputSchema.value[j]); + if (result.verified) { + return { + verified: true, + result: root + }; + } + } + if (choiceResult === false) { + const _result = { + verified: false, + result: { + error: "Wrong values for Choice type" + } + }; + if (inputSchema.hasOwnProperty(NAME)) + _result.name = inputSchema.name; + return _result; + } + } + if (inputSchema instanceof Any) { + if (inputSchema.hasOwnProperty(NAME)) + root[inputSchema.name] = inputData; + return { + verified: true, + result: root + }; + } + if (root instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong root object" } + }; + } + if (inputData instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 data" } + }; + } + if (inputSchema instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (ID_BLOCK in inputSchema === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (FROM_BER in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (TO_BER in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + const encodedId = inputSchema.idBlock.toBER(false); + if (encodedId.byteLength === 0) { + return { + verified: false, + result: { error: "Error encoding idBlock for ASN.1 schema" } + }; + } + const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength); + if (decodedOffset === -1) { + return { + verified: false, + result: { error: "Error decoding idBlock for ASN.1 schema" } + }; + } + if (inputSchema.idBlock.hasOwnProperty(TAG_CLASS) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) { + return { + verified: false, + result: root + }; + } + if (inputSchema.idBlock.hasOwnProperty(TAG_NUMBER) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) { + return { + verified: false, + result: root + }; + } + if (inputSchema.idBlock.hasOwnProperty(IS_CONSTRUCTED) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) { + return { + verified: false, + result: root + }; + } + if (!(IS_HEX_ONLY in inputSchema.idBlock)) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) { + return { + verified: false, + result: root + }; + } + if (inputSchema.idBlock.isHexOnly) { + if (VALUE_HEX_VIEW in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + const schemaView = inputSchema.idBlock.valueHexView; + const asn1View = inputData.idBlock.valueHexView; + if (schemaView.length !== asn1View.length) { + return { + verified: false, + result: root + }; + } + for (let i = 0; i < schemaView.length; i++) { + if (schemaView[i] !== asn1View[1]) { + return { + verified: false, + result: root + }; + } + } + } + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + root[inputSchema.name] = inputData; + } + if (inputSchema instanceof typeStore.Constructed) { + let admission = 0; + let result = { + verified: false, + result: { + error: "Unknown error" + } + }; + let maxLength = inputSchema.valueBlock.value.length; + if (maxLength > 0) { + if (inputSchema.valueBlock.value[0] instanceof Repeated) { + maxLength = inputData.valueBlock.value.length; + } + } + if (maxLength === 0) { + return { + verified: true, + result: root + }; + } + if (inputData.valueBlock.value.length === 0 && inputSchema.valueBlock.value.length !== 0) { + let _optional = true; + for (let i = 0; i < inputSchema.valueBlock.value.length; i++) + _optional = _optional && (inputSchema.valueBlock.value[i].optional || false); + if (_optional) { + return { + verified: true, + result: root + }; + } + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + delete root[inputSchema.name]; + } + root.error = "Inconsistent object length"; + return { + verified: false, + result: root + }; + } + for (let i = 0; i < maxLength; i++) { + if (i - admission >= inputData.valueBlock.value.length) { + if (inputSchema.valueBlock.value[i].optional === false) { + const _result = { + verified: false, + result: root + }; + root.error = "Inconsistent length between ASN.1 data and schema"; + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + return _result; + } + } else { + if (inputSchema.valueBlock.value[0] instanceof Repeated) { + result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value); + if (result.verified === false) { + if (inputSchema.valueBlock.value[0].optional) + admission++; + else { + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + delete root[inputSchema.name]; + } + return result; + } + } + if (NAME in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].name.length > 0) { + let arrayRoot = {}; + if (LOCAL in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].local) + arrayRoot = inputData; + else + arrayRoot = root; + if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") + arrayRoot[inputSchema.valueBlock.value[0].name] = []; + arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]); + } + } else { + result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]); + if (result.verified === false) { + if (inputSchema.valueBlock.value[i].optional) + admission++; + else { + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + delete root[inputSchema.name]; + } + return result; + } + } + } + } + } + if (result.verified === false) { + const _result = { + verified: false, + result: root + }; + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + return _result; + } + return { + verified: true, + result: root + }; + } + if (inputSchema.primitiveSchema && VALUE_HEX_VIEW in inputData.valueBlock) { + const asn1 = localFromBER(inputData.valueBlock.valueHexView); + if (asn1.offset === -1) { + const _result = { + verified: false, + result: asn1.result + }; + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + return _result; + } + return compareSchema(root, asn1.result, inputSchema.primitiveSchema); + } + return { + verified: true, + result: root + }; +} +function verifySchema(inputBuffer, inputSchema) { + if (inputSchema instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema type" } + }; + } + const asn1 = localFromBER(pvtsutils19.BufferSourceConverter.toUint8Array(inputBuffer)); + if (asn1.offset === -1) { + return { + verified: false, + result: asn1.result + }; + } + return compareSchema(asn1.result, asn1.result, inputSchema); +} +export { + src_exports as asn1js +}; +/*! Bundled license information: + +pvtsutils/build/index.js: + (*! + * MIT License + * + * Copyright (c) 2017-2022 Peculiar Ventures, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + *) + +pvutils/build/utils.es.js: + (*! + Copyright (c) Peculiar Ventures, LLC + *) +*/ diff --git a/comm/third_party/asn1js/make_bundle.sh b/comm/third_party/asn1js/make_bundle.sh new file mode 100755 index 0000000000..57d87138ce --- /dev/null +++ b/comm/third_party/asn1js/make_bundle.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +yarn install +npm install --no-save esbuild + +echo 'export * as asn1js from "./src/index.ts";' | \ + ./node_modules/.bin/esbuild --bundle \ + --sourcefile=entry.js \ + --loader=ts \ + --format=esm \ + --target=es2019 \ + --log-level=verbose \ + --outfile=asn1js.mjs + +rm -rf node_modules diff --git a/comm/third_party/asn1js/moz.build b/comm/third_party/asn1js/moz.build new file mode 100644 index 0000000000..ce34f7f124 --- /dev/null +++ b/comm/third_party/asn1js/moz.build @@ -0,0 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at http://mozilla.org/MPL/2.0/. + +EXTRA_JS_MODULES += [ + "asn1js.mjs", +] diff --git a/comm/third_party/asn1js/moz.yaml b/comm/third_party/asn1js/moz.yaml new file mode 100644 index 0000000000..f9a60af27f --- /dev/null +++ b/comm/third_party/asn1js/moz.yaml @@ -0,0 +1,91 @@ +--- +# Version of this schema +schema: 1 + +bugzilla: + # Bugzilla product and component for this directory and subdirectories + product: Mailnews Core + component: LDAP Integration +# Document the source of externally hosted code +origin: + + # Short name of the package/library + name: ASN1.js + + description: ASN1js is a pure JavaScript library implementing a full ASN.1 BER decoder and encoder + + # Full URL for the package's homepage/etc + # Usually different from repository url + url: https://asn1js.org/ + + # Human-readable identifier for this version/release + # Generally "version NNN", "tag SSS", "bookmark SSS" + release: tag v3.0.5 + + # Revision to pull in + # Must be a long or short commit SHA (long preferred) + revision: v3.0.5 + + # The package's license, where possible using the mnemonic from + # https://spdx.org/licenses/ + # Multiple licenses can be specified (as a YAML list) + # A "LICENSE" file must exist containing the full license text + license: BSD-3-Clause + + # If the package's license is specified in a particular file, + # this is the name of the file. + # optional + license-file: LICENSE + +# Configuration for the automated vendoring system. +# optional +vendoring: + + # Repository URL to vendor from + # eg. https://github.com/kinetiknz/nestegg + # Any repository host can be specified here, however initially we'll only + # support automated vendoring from selected sources. + url: https://github.com/PeculiarVentures/asn1.js + + # Type of hosting for the upstream repository + # Valid values are 'gitlab', 'github', googlesource + source-hosting: github + tracking: tag + + skip-vendoring-steps: + - hg-add + - spurious-check + - update-moz-build + + # Files/paths that will not be vendored from the upstream repository + # Implicitly contains ".git", and ".gitignore" + # optional + exclude: + - .eslintrc.json + - .github/ + - .gitignore + - .mocharc.yaml + - .npmrc + - .nycrc + - CNAME + - README.md + - rollup.config.js + - test/ + - typedoc.json + + keep: + - make_bundle.sh + - make-esmodule-bundle.patch + + update-actions: + - action: run-script + script: 'make_bundle.sh' + cwd: '{yaml_dir}' + + - action: replace-in-file-regex + file: '{yaml_dir}/../README.asn1js' + pattern: '\[tag v[0-9\.]+\]' + with: '[tag {revision}]' + + - action: delete-path + path: 'build' diff --git a/comm/third_party/asn1js/package.json b/comm/third_party/asn1js/package.json new file mode 100644 index 0000000000..d0720330c1 --- /dev/null +++ b/comm/third_party/asn1js/package.json @@ -0,0 +1,77 @@ +{ + "author": { + "email": "yury@strozhevsky.com", + "name": "Yury Strozhevsky" + }, + "contributors": [ + { + "email": "rmh@unmitigatedrisk.com", + "name": "Ryan Hurst" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "devDependencies": { + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^5.23.0", + "@typescript-eslint/parser": "^5.23.0", + "asn1-test-suite": "^1.0.2", + "eslint": "^8.15.0", + "eslint-plugin-deprecation": "^1.3.2", + "mocha": "^10.0.0", + "nyc": "^15.1.0", + "rollup": "^2.72.1", + "rollup-plugin-dts": "^4.2.1", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-typescript2": "^0.31.2", + "ts-node": "^10.7.0", + "typescript": "^4.6.4" + }, + "repository": { + "type": "git", + "url": "git://github.com/PeculiarVentures/asn1.js.git" + }, + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "description": "asn1js is a pure JavaScript library implementing this standard. ASN.1 is the basis of all X.509 related data structures and numerous other protocols used on the web", + "keywords": [ + "asn1", + "parser", + "asn.1", + "ber", + "der", + "sequence", + "set", + "bitstring", + "octetstring", + "utctime", + "utf8string", + "bmpstring", + "universalstring", + "generalizedtime" + ], + "main": "build/index.js", + "module": "build/index.es.js", + "types": "build/index.d.ts", + "name": "asn1js", + "files": [ + "build", + "LICENSE", + "README.md" + ], + "scripts": { + "build": "rollup -c", + "test": "mocha", + "prepublishOnly": "npm run build", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint --fix . --ext .ts", + "coverage": "nyc npm test" + }, + "version": "3.0.5", + "license": "BSD-3-Clause" +} diff --git a/comm/third_party/asn1js/src/Any.ts b/comm/third_party/asn1js/src/Any.ts new file mode 100644 index 0000000000..36db46cc2e --- /dev/null +++ b/comm/third_party/asn1js/src/Any.ts @@ -0,0 +1,22 @@ +import { EMPTY_STRING } from "./internals/constants"; + +export interface IAny { + name: string; + optional: boolean; +} + +export type AnyParams = Partial; + +export class Any implements IAny { + + public name: string; + public optional: boolean; + + constructor({ + name = EMPTY_STRING, optional = false, + }: AnyParams = {}) { + this.name = name; + this.optional = optional; + } + +} diff --git a/comm/third_party/asn1js/src/BaseBlock.ts b/comm/third_party/asn1js/src/BaseBlock.ts new file mode 100644 index 0000000000..8a4c58528c --- /dev/null +++ b/comm/third_party/asn1js/src/BaseBlock.ts @@ -0,0 +1,186 @@ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { IBerConvertible } from "./types"; +import { LocalBaseBlockJson, LocalBaseBlockParams, LocalBaseBlock } from "./internals/LocalBaseBlock"; +import { LocalIdentificationBlock, LocalIdentificationBlockJson, LocalIdentificationBlockParams } from "./internals/LocalIdentificationBlock"; +import { LocalLengthBlock, LocalLengthBlockJson, LocalLengthBlockParams } from "./internals/LocalLengthBlock"; +import { ViewWriter } from "./ViewWriter"; +import { ValueBlock, ValueBlockJson } from "./ValueBlock"; +import { EMPTY_BUFFER, EMPTY_STRING } from "./internals/constants"; +import { typeStore } from "./TypeStore"; + +export interface IBaseBlock { + name: string; + optional: boolean; + primitiveSchema?: BaseBlock; +} + +export interface BaseBlockParams extends LocalBaseBlockParams, LocalIdentificationBlockParams, LocalLengthBlockParams, Partial { } + +export interface ValueBlockConstructor { + new(...args: any[]): T; +} + +export interface BaseBlockJson extends LocalBaseBlockJson, Omit { + idBlock: LocalIdentificationBlockJson; + lenBlock: LocalLengthBlockJson; + valueBlock: T; + primitiveSchema?: BaseBlockJson; +} + +export type StringEncoding = "ascii" | "hex"; + +export class BaseBlock extends LocalBaseBlock implements IBaseBlock, IBerConvertible { + + static { + + } + + public static override NAME = "BaseBlock"; + + public idBlock: LocalIdentificationBlock; + public lenBlock: LocalLengthBlock; + public valueBlock: T; + public name: string; + public optional: boolean; + public primitiveSchema?: BaseBlock; + + constructor({ + name = EMPTY_STRING, + optional = false, + primitiveSchema, + ...parameters + }: BaseBlockParams = {}, valueBlockType?: ValueBlockConstructor) { + super(parameters); + + this.name = name; + this.optional = optional; + if (primitiveSchema) { + this.primitiveSchema = primitiveSchema; + } + + this.idBlock = new LocalIdentificationBlock(parameters); + this.lenBlock = new LocalLengthBlock(parameters); + this.valueBlock = valueBlockType ? new valueBlockType(parameters) : new ValueBlock(parameters) as unknown as T; + } + + public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + + return resultOffset; + } + + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + + if (!this.valueBlock.error.length) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + + public toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + const _writer = writer || new ViewWriter(); + + if (!writer) { + prepareIndefiniteForm(this); + } + + const idBlockBuf = this.idBlock.toBER(sizeOnly); + + _writer.write(idBlockBuf); + + if (this.lenBlock.isIndefiniteForm) { + _writer.write(new Uint8Array([0x80]).buffer); + + this.valueBlock.toBER(sizeOnly, _writer); + + _writer.write(new ArrayBuffer(2)); + } + else { + const valueBlockBuf = this.valueBlock.toBER(sizeOnly); + this.lenBlock.length = valueBlockBuf.byteLength; + const lenBlockBuf = this.lenBlock.toBER(sizeOnly); + + _writer.write(lenBlockBuf); + _writer.write(valueBlockBuf); + } + + if (!writer) { + return _writer.final(); + } + + return EMPTY_BUFFER; + } + + public override toJSON(): BaseBlockJson { + const object: BaseBlockJson = { + ...super.toJSON(), + idBlock: this.idBlock.toJSON(), + lenBlock: this.lenBlock.toJSON(), + valueBlock: this.valueBlock.toJSON(), + name: this.name, + optional: this.optional, + }; + + + if (this.primitiveSchema) + object.primitiveSchema = this.primitiveSchema.toJSON(); + + return object as BaseBlockJson; + } + public override toString(encoding: StringEncoding = "ascii"): string { + if (encoding === "ascii") { + return this.onAsciiEncoding(); + } + + return pvtsutils.Convert.ToHex(this.toBER()); + } + + protected onAsciiEncoding(): string { + return `${(this.constructor as typeof BaseBlock).NAME} : ${pvtsutils.Convert.ToHex(this.valueBlock.valueBeforeDecodeView)}`; + } + + /** + * Determines whether two object instances are equal + * @param other Object to compare with the current object + */ + public isEqual(other: unknown): other is this { + if (this === other) { + return true; + } + + // Check input type + if (!(other instanceof this.constructor)) { + return false; + } + + const thisRaw = this.toBER(); + const otherRaw = (other as BaseBlock).toBER(); + + return pvutils.isEqualBuffer(thisRaw, otherRaw); + } + +} + +/** + * Recursive function which checks and enables isIndefiniteForm flag for constructed blocks if any child has that flag enabled + * @param baseBlock Base ASN.1 block + * @returns Returns `true` if incoming block is `indefinite form` + */ +function prepareIndefiniteForm(baseBlock: BaseBlock): boolean { + if (baseBlock instanceof typeStore.Constructed) { + for (const value of baseBlock.valueBlock.value) { + if (prepareIndefiniteForm(value)) { + baseBlock.lenBlock.isIndefiniteForm = true; + } + } + } + + return !!baseBlock.lenBlock.isIndefiniteForm; +} diff --git a/comm/third_party/asn1js/src/BaseStringBlock.ts b/comm/third_party/asn1js/src/BaseStringBlock.ts new file mode 100644 index 0000000000..606b330e0c --- /dev/null +++ b/comm/third_party/asn1js/src/BaseStringBlock.ts @@ -0,0 +1,74 @@ +import { BaseBlock, BaseBlockParams } from "./BaseBlock"; +import { IStringConvertible } from "./types"; +import { EMPTY_STRING } from "./internals/constants"; +import { LocalStringValueBlock, LocalStringValueBlockJson, LocalStringValueBlockParams } from "./internals/LocalStringValueBlock"; + +export interface BaseStringBlockParams extends BaseBlockParams, LocalStringValueBlockParams { } +export type BaseStringBlockJson = LocalStringValueBlockJson; + +export abstract class BaseStringBlock extends BaseBlock implements IStringConvertible { + + public static override NAME = "BaseStringBlock"; + + /** + * String value + * @since 3.0.0 + */ + public getValue(): string { + return this.valueBlock.value; + } + /** + * String value + * @param value String value + * @since 3.0.0 + */ + public setValue(value: string): void { + this.valueBlock.value = value; + } + + constructor({ + value = EMPTY_STRING, + ...parameters + }: BaseStringBlockParams = {}, stringValueBlockType: new () => T) { + super(parameters, stringValueBlockType); + + if (value) { + this.fromString(value); + } + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHexView); + + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + + if (!this.valueBlock.error.length) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param inputBuffer ASN.1 BER encoded array + */ + public abstract fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void; + + public abstract fromString(inputString: string): void; + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof BaseStringBlock).NAME} : '${this.valueBlock.value}'`; + } + +} diff --git a/comm/third_party/asn1js/src/BitString.ts b/comm/third_party/asn1js/src/BitString.ts new file mode 100644 index 0000000000..2c8ada83cc --- /dev/null +++ b/comm/third_party/asn1js/src/BitString.ts @@ -0,0 +1,64 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { Constructed } from "./Constructed"; +import { BIT_STRING_NAME } from "./internals/constants"; +import { LocalBitStringValueBlockParams, LocalBitStringValueBlock, LocalBitStringValueBlockJson } from "./internals/LocalBitStringValueBlock"; +import { typeStore } from "./TypeStore"; + +export interface BitStringParams extends BaseBlockParams, LocalBitStringValueBlockParams { } +export type BitStringJson = BaseBlockJson; + +export class BitString extends BaseBlock { + + static { + typeStore.BitString = this; + } + + public static override NAME = BIT_STRING_NAME; + + constructor({ + idBlock = {}, + lenBlock = {}, + ...parameters + }: BitStringParams = {}) { + parameters.isConstructed ??= !!parameters.value?.length; + super({ + idBlock: { + isConstructed: parameters.isConstructed, + ...idBlock, + }, + lenBlock: { + ...lenBlock, + isIndefiniteForm: !!parameters.isIndefiniteForm, + }, + ...parameters, + }, LocalBitStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 3; // BitString + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + + protected override onAsciiEncoding(): string { + if (this.valueBlock.isConstructed || (this.valueBlock.value && this.valueBlock.value.length)) { + return Constructed.prototype.onAsciiEncoding.call(this); + } else { + // convert bytes to bits + const bits = []; + const valueHex = this.valueBlock.valueHexView; + for (const byte of valueHex) { + bits.push(byte.toString(2).padStart(8, "0")); + } + + const bitsStr = bits.join(""); + + return `${(this.constructor as typeof BitString).NAME} : ${bitsStr.substring(0, bitsStr.length - this.valueBlock.unusedBits)}`; + } + } + +} diff --git a/comm/third_party/asn1js/src/BmpString.ts b/comm/third_party/asn1js/src/BmpString.ts new file mode 100644 index 0000000000..42f23ea773 --- /dev/null +++ b/comm/third_party/asn1js/src/BmpString.ts @@ -0,0 +1,23 @@ +import { LocalBmpStringValueBlockParams, LocalBmpStringValueBlock, LocalBmpStringValueBlockJson } from "./internals/LocalBmpStringValueBlock"; +import { typeStore } from "./TypeStore"; + +export type BmpStringParams = LocalBmpStringValueBlockParams; +export type BmpStringJson = LocalBmpStringValueBlockJson; + +export class BmpString extends LocalBmpStringValueBlock { + + static { + typeStore.BmpString = this; + } + public static override NAME = "BMPString"; + + constructor({ + ...parameters + }: BmpStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 30; // BmpString + } + +} diff --git a/comm/third_party/asn1js/src/Boolean.ts b/comm/third_party/asn1js/src/Boolean.ts new file mode 100644 index 0000000000..3bcdb05ae2 --- /dev/null +++ b/comm/third_party/asn1js/src/Boolean.ts @@ -0,0 +1,43 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { LocalBooleanValueBlockParams, LocalBooleanValueBlock, LocalBooleanValueBlockJson } from "./internals/LocalBooleanValueBlock"; +import { typeStore } from "./TypeStore"; + +export interface BooleanParams extends BaseBlockParams, LocalBooleanValueBlockParams { } +export type BooleanJson = BaseBlockJson; + +export class Boolean extends BaseBlock { + + static { + typeStore.Boolean = this; + } + + /** + * Gets value + * @since 3.0.0 + */ + public getValue(): boolean { + return this.valueBlock.value; + } + /** + * Sets value + * @param value Boolean value + * @since 3.0.0 + */ + public setValue(value: boolean): void { + this.valueBlock.value = value; + } + + public static override NAME = "BOOLEAN"; + + constructor(parameters: BooleanParams = {}) { + super(parameters, LocalBooleanValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 1; // Boolean + } + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof Boolean).NAME} : ${this.getValue}`; + } + +} diff --git a/comm/third_party/asn1js/src/CharacterString.ts b/comm/third_party/asn1js/src/CharacterString.ts new file mode 100644 index 0000000000..a15798cced --- /dev/null +++ b/comm/third_party/asn1js/src/CharacterString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type CharacterStringParams = LocalSimpleStringBlockParams; +export type CharacterStringJson = LocalSimpleStringBlockJson; + +export class CharacterString extends LocalSimpleStringBlock { + + static { + typeStore.CharacterString = this; + } + + public static override NAME = "CharacterString"; + + constructor(parameters: CharacterStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 29; // CharacterString + } + +} diff --git a/comm/third_party/asn1js/src/Choice.ts b/comm/third_party/asn1js/src/Choice.ts new file mode 100644 index 0000000000..3246bfa3c3 --- /dev/null +++ b/comm/third_party/asn1js/src/Choice.ts @@ -0,0 +1,22 @@ +import { BaseBlock } from "./BaseBlock"; +import { IAny, Any } from "./Any"; + +export interface IChoice extends IAny { + value: BaseBlock[]; +} + +export type ChoiceParams = Partial; + +export class Choice extends Any implements IChoice { + public value: BaseBlock[]; + + constructor({ + value = [], + ...parameters + }: ChoiceParams = {}) { + super(parameters); + + this.value = value; + } + +} diff --git a/comm/third_party/asn1js/src/Constructed.ts b/comm/third_party/asn1js/src/Constructed.ts new file mode 100644 index 0000000000..8fe3bc502f --- /dev/null +++ b/comm/third_party/asn1js/src/Constructed.ts @@ -0,0 +1,61 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { LocalConstructedValueBlock, LocalConstructedValueBlockJson, LocalConstructedValueBlockParams } from "./internals/LocalConstructedValueBlock"; +import { typeStore } from "./TypeStore"; + +export interface ConstructedParams extends BaseBlockParams, LocalConstructedValueBlockParams { } +export type ConstructedJson = BaseBlockJson; + +export class Constructed extends BaseBlock { + + static { + typeStore.Constructed = this; + } + + public static override NAME = "CONSTRUCTED"; + + constructor(parameters: ConstructedParams = {}) { + super(parameters, LocalConstructedValueBlock); + + this.idBlock.isConstructed = true; + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + + return resultOffset; + } + + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + + if (!this.valueBlock.error.length) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + + /** + * @internal + */ + public override onAsciiEncoding(): string { + const values = []; + for (const value of this.valueBlock.value) { + values.push(value.toString("ascii").split("\n").map(o => ` ${o}`).join("\n")); + } + const blockName = this.idBlock.tagClass === 3 + ? `[${this.idBlock.tagNumber}]` + : (this.constructor as typeof Constructed).NAME; + + return values.length + ? `${blockName} :\n${values.join("\n")}` // items + : `${blockName} :`; // empty + } + +} diff --git a/comm/third_party/asn1js/src/DATE.ts b/comm/third_party/asn1js/src/DATE.ts new file mode 100644 index 0000000000..3a6f73d144 --- /dev/null +++ b/comm/third_party/asn1js/src/DATE.ts @@ -0,0 +1,22 @@ +import { typeStore } from "./TypeStore"; +import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String"; + +export type DATEParams = Utf8StringParams; +export type DATEJson = Utf8StringJson; + +export class DATE extends Utf8String { + + static { + typeStore.DATE = this; + } + + public static override NAME = "DATE"; + + constructor(parameters: DATEParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 31; // DATE + } + +} diff --git a/comm/third_party/asn1js/src/DateTime.ts b/comm/third_party/asn1js/src/DateTime.ts new file mode 100644 index 0000000000..a30f47dbe4 --- /dev/null +++ b/comm/third_party/asn1js/src/DateTime.ts @@ -0,0 +1,22 @@ +import { typeStore } from "./TypeStore"; +import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String"; + +export type DateTimeParams = Utf8StringParams; +export type DateTimeJson = Utf8StringJson; + +export class DateTime extends Utf8String { + + static { + typeStore.DateTime = this; + } + + public static override NAME = "DateTime"; + + constructor(parameters: DateTimeParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 33; // DateTime + } + +} diff --git a/comm/third_party/asn1js/src/Duration.ts b/comm/third_party/asn1js/src/Duration.ts new file mode 100644 index 0000000000..618894e158 --- /dev/null +++ b/comm/third_party/asn1js/src/Duration.ts @@ -0,0 +1,21 @@ +import { typeStore } from "./TypeStore"; +import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String"; + +export type DurationParams = Utf8StringParams; +export type DurationJson = Utf8StringJson; + +export class Duration extends Utf8String { + + static { + typeStore.Duration = this; + } + public static override NAME = "Duration"; + + constructor(parameters: DurationParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 34; // Duration + } + +} diff --git a/comm/third_party/asn1js/src/EndOfContent.ts b/comm/third_party/asn1js/src/EndOfContent.ts new file mode 100644 index 0000000000..b0e8ccf6c9 --- /dev/null +++ b/comm/third_party/asn1js/src/EndOfContent.ts @@ -0,0 +1,23 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { END_OF_CONTENT_NAME } from "./internals/constants"; +import { LocalEndOfContentValueBlock } from "./internals/LocalEndOfContentValueBlock"; +import { typeStore } from "./TypeStore"; + +export type EndOfContentParams = BaseBlockParams; +export type EndOfContentJson = BaseBlockJson; + +export class EndOfContent extends BaseBlock { + + static { + typeStore.EndOfContent = this; + } + public static override NAME = END_OF_CONTENT_NAME; + + constructor(parameters: EndOfContentParams = {}) { + super(parameters, LocalEndOfContentValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 0; // EndOfContent + } + +} diff --git a/comm/third_party/asn1js/src/Enumerated.ts b/comm/third_party/asn1js/src/Enumerated.ts new file mode 100644 index 0000000000..53249a3cf9 --- /dev/null +++ b/comm/third_party/asn1js/src/Enumerated.ts @@ -0,0 +1,22 @@ +import { IntegerParams, Integer, IntegerJson } from "./Integer"; +import { typeStore } from "./TypeStore"; + +export type EnumeratedParams = IntegerParams; +export type EnumeratedJson = IntegerJson; + +export class Enumerated extends Integer { + + static { + typeStore.Enumerated = this; + } + + public static override NAME = "ENUMERATED"; + + constructor(parameters: EnumeratedParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 10; // Enumerated + } + +} diff --git a/comm/third_party/asn1js/src/GeneralString.ts b/comm/third_party/asn1js/src/GeneralString.ts new file mode 100644 index 0000000000..f0ce52a607 --- /dev/null +++ b/comm/third_party/asn1js/src/GeneralString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type GeneralStringParams = LocalSimpleStringBlockParams; +export type GeneralStringJson = LocalSimpleStringBlockJson; + +export class GeneralString extends LocalSimpleStringBlock { + + static { + typeStore.GeneralString = this; + } + + public static override NAME = "GeneralString"; + + constructor(parameters: GeneralStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 27; // GeneralString + } + +} diff --git a/comm/third_party/asn1js/src/GeneralizedTime.ts b/comm/third_party/asn1js/src/GeneralizedTime.ts new file mode 100644 index 0000000000..7743ae1436 --- /dev/null +++ b/comm/third_party/asn1js/src/GeneralizedTime.ts @@ -0,0 +1,262 @@ +import * as pvutils from "pvutils"; +import { typeStore } from "./TypeStore"; +import { IUTCTime, UTCTimeParams, UTCTimeJson, UTCTime, DateStringEncoding } from "./UTCTime"; + +export interface IGeneralizedTime extends IUTCTime { + millisecond: number; +} + +export type GeneralizedTimeParams = UTCTimeParams; + +export interface GeneralizedTimeJson extends UTCTimeJson { + millisecond: number; +} + +export class GeneralizedTime extends UTCTime { + + static { + typeStore.GeneralizedTime = this; + } + + public static override NAME = "GeneralizedTime"; + + public millisecond: number; + + constructor(parameters: GeneralizedTimeParams = {}) { + super(parameters); + + this.millisecond ??= 0; + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 24; // GeneralizedTime + } + + public override fromDate(inputDate: Date): void { + super.fromDate(inputDate); + this.millisecond = inputDate.getUTCMilliseconds(); + } + + public override toDate(): Date { + return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond))); + } + + public override fromString(inputString: string): void { + //#region Initial variables + let isUTC = false; + + let timeString = ""; + let dateTimeString = ""; + let fractionPart = 0; + + let parser; + + let hourDifference = 0; + let minuteDifference = 0; + //#endregion + + //#region Convert as UTC time + if (inputString[inputString.length - 1] === "Z") { + timeString = inputString.substring(0, inputString.length - 1); + + isUTC = true; + } + //#endregion + //#region Convert as local time + else { + const number = new Number(inputString[inputString.length - 1]); + + if (isNaN(number.valueOf())) + throw new Error("Wrong input string for conversion"); + + timeString = inputString; + } + //#endregion + + //#region Check that we do not have a "+" and "-" symbols inside UTC time + if (isUTC) { + if (timeString.indexOf("+") !== -1) + throw new Error("Wrong input string for conversion"); + + if (timeString.indexOf("-") !== -1) + throw new Error("Wrong input string for conversion"); + } + //#endregion + //#region Get "UTC time difference" in case of local time + else { + let multiplier = 1; + let differencePosition = timeString.indexOf("+"); + let differenceString = ""; + + if (differencePosition === -1) { + differencePosition = timeString.indexOf("-"); + multiplier = -1; + } + + if (differencePosition !== -1) { + differenceString = timeString.substring(differencePosition + 1); + timeString = timeString.substring(0, differencePosition); + + if ((differenceString.length !== 2) && (differenceString.length !== 4)) + throw new Error("Wrong input string for conversion"); + + let number = parseInt(differenceString.substring(0, 2), 10); + + if (isNaN(number.valueOf())) + throw new Error("Wrong input string for conversion"); + + hourDifference = multiplier * number; + + if (differenceString.length === 4) { + number = parseInt(differenceString.substring(2, 4), 10); + + if (isNaN(number.valueOf())) + throw new Error("Wrong input string for conversion"); + + minuteDifference = multiplier * number; + } + } + } + //#endregion + + //#region Get position of fraction point + let fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol + if (fractionPointPosition === -1) + fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol + //#endregion + + //#region Get fraction part + if (fractionPointPosition !== -1) { + const fractionPartCheck = new Number(`0${timeString.substring(fractionPointPosition)}`); + + if (isNaN(fractionPartCheck.valueOf())) + throw new Error("Wrong input string for conversion"); + + fractionPart = fractionPartCheck.valueOf(); + + dateTimeString = timeString.substring(0, fractionPointPosition); + } + else + dateTimeString = timeString; + //#endregion + + //#region Parse internal date + switch (true) { + case (dateTimeString.length === 8): // "YYYYMMDD" + parser = /(\d{4})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) + throw new Error("Wrong input string for conversion"); // Here we should not have a "fraction point" + break; + case (dateTimeString.length === 10): // "YYYYMMDDHH" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.minute = Math.floor(fractionResult); + + fractionResult = 60 * (fractionResult - this.minute); + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case (dateTimeString.length === 12): // "YYYYMMDDHHMM" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case (dateTimeString.length === 14): // "YYYYMMDDHHMMSS" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + const fractionResult = 1000 * fractionPart; + this.millisecond = Math.floor(fractionResult); + } + break; + default: + throw new Error("Wrong input string for conversion"); + } + //#endregion + + //#region Put parsed values at right places + const parserArray = parser.exec(dateTimeString); + if (parserArray === null) + throw new Error("Wrong input string for conversion"); + + for (let j = 1; j < parserArray.length; j++) { + switch (j) { + case 1: + this.year = parseInt(parserArray[j], 10); + break; + case 2: + this.month = parseInt(parserArray[j], 10); + break; + case 3: + this.day = parseInt(parserArray[j], 10); + break; + case 4: + this.hour = parseInt(parserArray[j], 10) + hourDifference; + break; + case 5: + this.minute = parseInt(parserArray[j], 10) + minuteDifference; + break; + case 6: + this.second = parseInt(parserArray[j], 10); + break; + default: + throw new Error("Wrong input string for conversion"); + } + } + //#endregion + + //#region Get final date + if (isUTC === false) { + const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + + this.year = tempDate.getUTCFullYear(); + this.month = tempDate.getUTCMonth(); + this.day = tempDate.getUTCDay(); + this.hour = tempDate.getUTCHours(); + this.minute = tempDate.getUTCMinutes(); + this.second = tempDate.getUTCSeconds(); + this.millisecond = tempDate.getUTCMilliseconds(); + } + //#endregion + } + + public override toString(encoding: DateStringEncoding = "iso"): string { + if (encoding === "iso") { + const outputArray = []; + + outputArray.push(pvutils.padNumber(this.year, 4)); + outputArray.push(pvutils.padNumber(this.month, 2)); + outputArray.push(pvutils.padNumber(this.day, 2)); + outputArray.push(pvutils.padNumber(this.hour, 2)); + outputArray.push(pvutils.padNumber(this.minute, 2)); + outputArray.push(pvutils.padNumber(this.second, 2)); + if (this.millisecond !== 0) { + outputArray.push("."); + outputArray.push(pvutils.padNumber(this.millisecond, 3)); + } + outputArray.push("Z"); + + return outputArray.join(""); + } + + return super.toString(encoding); + } + + public override toJSON(): GeneralizedTimeJson { + return { + ...super.toJSON(), + millisecond: this.millisecond, + }; + } + +} diff --git a/comm/third_party/asn1js/src/GraphicString.ts b/comm/third_party/asn1js/src/GraphicString.ts new file mode 100644 index 0000000000..3d2ab07577 --- /dev/null +++ b/comm/third_party/asn1js/src/GraphicString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type GraphicStringParams = LocalSimpleStringBlockParams; +export type GraphicStringJson = LocalSimpleStringBlockJson; + +export class GraphicString extends LocalSimpleStringBlock { + + static { + typeStore.GraphicString = this; + } + + public static override NAME = "GraphicString"; + + constructor(parameters: GraphicStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 25; // GraphicString + } + +} diff --git a/comm/third_party/asn1js/src/HexBlock.ts b/comm/third_party/asn1js/src/HexBlock.ts new file mode 100644 index 0000000000..cca34da5de --- /dev/null +++ b/comm/third_party/asn1js/src/HexBlock.ts @@ -0,0 +1,110 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import * as pvtsutils from "pvtsutils"; +import { IBerConvertible } from "./types"; +import { EMPTY_BUFFER, EMPTY_VIEW } from "./internals/constants"; +import { LocalBaseBlockConstructor } from "./internals/LocalBaseBlock"; +import { checkBufferParams } from "./internals/utils"; + +export interface IHexBlock { + isHexOnly: boolean; + valueHex: pvtsutils.BufferSource; +} + +export interface HexBlockJson extends Omit { + valueHex: string; +} + +export type HexBlockParams = Partial; +/** + * Class used as a base block for all remaining ASN.1 classes + */ +export function HexBlock(BaseClass: T) { + return class Some extends BaseClass implements IHexBlock, IBerConvertible { + + public static override NAME = "hexBlock"; + + public isHexOnly: boolean; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + public get valueHex(): ArrayBuffer { + return this.valueHexView.slice().buffer; + } + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + public set valueHex(value: ArrayBuffer) { + this.valueHexView = new Uint8Array(value); + } + /** + * Binary data in Uint8Array representation + * + * @since 3.0.0 + */ + public valueHexView: Uint8Array; + + constructor(...args: any[]) { + super(...args); + + const params: HexBlockParams = args[0] || {}; + this.isHexOnly = params.isHexOnly ?? false; + this.valueHexView = params.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(params.valueHex) : EMPTY_VIEW; + } + + public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + // Basic check for parameters + const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer; + if (!checkBufferParams(this, view, inputOffset, inputLength)) { + return -1; + } + + const endLength = inputOffset + inputLength; + + // Initial checks + this.valueHexView = view.subarray(inputOffset, endLength); + if (!this.valueHexView.length) { + this.warnings.push("Zero buffer length"); + + return inputOffset; + } + + this.blockLength = inputLength; + + return endLength; + } + + public toBER(sizeOnly = false): ArrayBuffer { + if (!this.isHexOnly) { + this.error = "Flag 'isHexOnly' is not set, abort"; + + return EMPTY_BUFFER; + } + + if (sizeOnly) { + return new ArrayBuffer(this.valueHexView.byteLength); + } + + // Don't copy data if View is not offset + return (this.valueHexView.byteLength === this.valueHexView.buffer.byteLength) + ? this.valueHexView.buffer + : this.valueHexView.slice().buffer; + } + + /** + * Returns a JSON representation of an object + * @returns JSON object + */ + public override toJSON() { + return { + ...super.toJSON(), + isHexOnly: this.isHexOnly, + valueHex: pvtsutils.Convert.ToHex(this.valueHexView), + }; + } + + }; +} diff --git a/comm/third_party/asn1js/src/IA5String.ts b/comm/third_party/asn1js/src/IA5String.ts new file mode 100644 index 0000000000..f0021cec51 --- /dev/null +++ b/comm/third_party/asn1js/src/IA5String.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type IA5StringParams = LocalSimpleStringBlockParams; +export type IA5StringJson = LocalSimpleStringBlockJson; + +export class IA5String extends LocalSimpleStringBlock { + + static { + typeStore.IA5String = this; + } + + public static override NAME = "IA5String"; + + constructor(parameters: IA5StringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 22; // IA5String + } + +} diff --git a/comm/third_party/asn1js/src/Integer.ts b/comm/third_party/asn1js/src/Integer.ts new file mode 100644 index 0000000000..fd3d1d9e70 --- /dev/null +++ b/comm/third_party/asn1js/src/Integer.ts @@ -0,0 +1,103 @@ +import * as pvtsutils from "pvtsutils"; +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { LocalIntegerValueBlockParams, LocalIntegerValueBlock, LocalIntegerValueBlockJson } from "./internals/LocalIntegerValueBlock"; +import { assertBigInt } from "./internals/utils"; +import { typeStore } from "./TypeStore"; +import { ViewWriter } from "./ViewWriter"; + +export interface IntegerParams extends BaseBlockParams, LocalIntegerValueBlockParams { } +export type IntegerJson = BaseBlockJson; + +export class Integer extends BaseBlock { + + static { + typeStore.Integer = this; + } + + public static override NAME = "INTEGER"; + + constructor(parameters: IntegerParams = {}) { + super(parameters, LocalIntegerValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 2; // Integer + } + + /** + * Converts Integer into BigInt + * @throws Throws Error if BigInt is not supported + * @since 3.0.0 + */ + public toBigInt(): bigint { + assertBigInt(); + + return BigInt(this.valueBlock.toString()); + } + + /** + * Creates Integer from BigInt value + * @param value BigInt value + * @returns ASN.1 Integer + * @throws Throws Error if BigInt is not supported + * @since 3.0.0 + */ + public static fromBigInt(value: number | string | bigint | boolean): Integer { + assertBigInt(); + + const bigIntValue = BigInt(value); + const writer = new ViewWriter(); + + const hex = bigIntValue.toString(16).replace(/^-/, ""); + const view = new Uint8Array(pvtsutils.Convert.FromHex(hex)); + + if (bigIntValue < 0) { + // a negative number + const first = new Uint8Array(view.length + (view[0] & 0x80 ? 1 : 0)); + first[0] |= 0x80; + + const firstInt = BigInt(`0x${pvtsutils.Convert.ToHex(first)}`); + const secondInt = firstInt + bigIntValue; + const second = pvtsutils.BufferSourceConverter.toUint8Array(pvtsutils.Convert.FromHex(secondInt.toString(16))); + second[0] |= 0x80; + + writer.write(second); + } else { + // a positive number + if (view[0] & 0x80) { + writer.write(new Uint8Array([0])); + } + writer.write(view); + } + + const res = new Integer({ + valueHex: writer.final(), + }); + + return res; + } + + public convertToDER(): Integer { + const integer = new Integer({ valueHex: this.valueBlock.valueHexView }); + + integer.valueBlock.toDER(); + + return integer; + } + + /** + * Convert current Integer value from DER to BER format + * @returns + */ + public convertFromDER(): Integer { + return new Integer({ + valueHex: this.valueBlock.valueHexView[0] === 0 + ? this.valueBlock.valueHexView.subarray(1) + : this.valueBlock.valueHexView, + }); + } + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof Integer).NAME} : ${this.valueBlock.toString()}`; + } + +} diff --git a/comm/third_party/asn1js/src/Null.ts b/comm/third_party/asn1js/src/Null.ts new file mode 100644 index 0000000000..8c4c4c580d --- /dev/null +++ b/comm/third_party/asn1js/src/Null.ts @@ -0,0 +1,65 @@ +import { ViewWriter } from "./ViewWriter"; +import { ValueBlock, ValueBlockJson } from "./ValueBlock"; +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { typeStore } from "./TypeStore"; + +export type NullParams = BaseBlockParams; +export type NullJson = BaseBlockJson; + +export class Null extends BaseBlock { + + static { + typeStore.Null = this; + } + + public static override NAME = "NULL"; + + constructor(parameters: NullParams = {}) { + super(parameters, ValueBlock); // We will not have a call to "Null value block" because of specified FROM_BER and TO_BER functions + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 5; // Null + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + if (this.lenBlock.length > 0) + this.warnings.push("Non-zero length of value block for Null type"); + + if (!this.idBlock.error.length) + this.blockLength += this.idBlock.blockLength; + + if (!this.lenBlock.error.length) + this.blockLength += this.lenBlock.blockLength; + + this.blockLength += inputLength; + + if ((inputOffset + inputLength) > inputBuffer.byteLength) { + this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + + return -1; + } + + return (inputOffset + inputLength); + } + + public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + const retBuf = new ArrayBuffer(2); + + if (!sizeOnly) { + const retView = new Uint8Array(retBuf); + retView[0] = 0x05; + retView[1] = 0x00; + } + + if (writer) { + writer.write(retBuf); + } + + return retBuf; + } + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof Null).NAME}`; + } + +} diff --git a/comm/third_party/asn1js/src/NumericString.ts b/comm/third_party/asn1js/src/NumericString.ts new file mode 100644 index 0000000000..a917fd1dc2 --- /dev/null +++ b/comm/third_party/asn1js/src/NumericString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type NumericStringParams = LocalSimpleStringBlockParams; +export type NumericStringJson = LocalSimpleStringBlockJson; + +export class NumericString extends LocalSimpleStringBlock { + + static { + typeStore.NumericString = this; + } + + public static override NAME = "NumericString"; + + constructor(parameters: NumericStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 18; // NumericString + } + +} diff --git a/comm/third_party/asn1js/src/ObjectIdentifier.ts b/comm/third_party/asn1js/src/ObjectIdentifier.ts new file mode 100644 index 0000000000..7608a3cf7d --- /dev/null +++ b/comm/third_party/asn1js/src/ObjectIdentifier.ts @@ -0,0 +1,53 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { LocalObjectIdentifierValueBlockParams, LocalObjectIdentifierValueBlock, LocalObjectIdentifierValueBlockJson } from "./internals/LocalObjectIdentifierValueBlock"; +import { typeStore } from "./TypeStore"; + +export interface ObjectIdentifierParams extends BaseBlockParams, LocalObjectIdentifierValueBlockParams { } +export interface ObjectIdentifierJson extends BaseBlockJson { + value: string; +} + +export class ObjectIdentifier extends BaseBlock { + + static { + typeStore.ObjectIdentifier = this; + } + + public static override NAME = "OBJECT IDENTIFIER"; + + /** + * Gets string representation of Object Identifier + * @since 3.0.0 + */ + public getValue(): string { + return this.valueBlock.toString(); + } + + /** + * Sets Object Identifier value from string + * @param value String value + * @since 3.0.0 + */ + public setValue(value: string): void { + this.valueBlock.fromString(value); + } + + constructor(parameters: ObjectIdentifierParams = {}) { + super(parameters, LocalObjectIdentifierValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER + } + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof ObjectIdentifier).NAME} : ${this.valueBlock.toString() || "empty"}`; + } + + public override toJSON(): ObjectIdentifierJson { + return { + ...super.toJSON(), + value: this.getValue(), + }; + } + +} diff --git a/comm/third_party/asn1js/src/OctetString.ts b/comm/third_party/asn1js/src/OctetString.ts new file mode 100644 index 0000000000..df57e9bc6e --- /dev/null +++ b/comm/third_party/asn1js/src/OctetString.ts @@ -0,0 +1,103 @@ +import * as pvtsutils from "pvtsutils"; +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { Constructed } from "./Constructed"; +import { LocalOctetStringValueBlockParams, LocalOctetStringValueBlock, LocalOctetStringValueBlockJson } from "./internals/LocalOctetStringValueBlock"; +import { OCTET_STRING_NAME } from "./internals/constants"; +import { localFromBER } from "./parser"; +import { typeStore } from "./TypeStore"; + +export interface OctetStringParams extends BaseBlockParams, LocalOctetStringValueBlockParams { } +export type OctetStringJson = BaseBlockJson; + +export class OctetString extends BaseBlock { + + static { + typeStore.OctetString = this; + } + + public static override NAME = OCTET_STRING_NAME; + + constructor({ + idBlock = {}, + lenBlock = {}, + ...parameters + }: OctetStringParams = {}) { + parameters.isConstructed ??= !!parameters.value?.length; + super({ + idBlock: { + isConstructed: parameters.isConstructed, + ...idBlock, + }, + lenBlock: { + ...lenBlock, + isIndefiniteForm: !!parameters.isIndefiniteForm, + }, + ...parameters, + }, LocalOctetStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 4; // OctetString + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + // Ability to encode empty OCTET STRING + if (inputLength === 0) { + if (this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + return inputOffset; + } + + if (!this.valueBlock.isConstructed) { + const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer; + const buf = view.subarray(inputOffset, inputOffset + inputLength); + try { + if (buf.byteLength) { + const asn = localFromBER(buf, 0, buf.byteLength); + if (asn.offset !== -1 && asn.offset === inputLength) { + this.valueBlock.value = [asn.result as OctetString]; + } + } + } catch (e) { + // nothing + } + } + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + + protected override onAsciiEncoding(): string { + if (this.valueBlock.isConstructed || (this.valueBlock.value && this.valueBlock.value.length)) { + return Constructed.prototype.onAsciiEncoding.call(this); + } + + return `${(this.constructor as typeof OctetString).NAME} : ${pvtsutils.Convert.ToHex(this.valueBlock.valueHexView)}`; + } + + /** + * Returns OctetString value. If OctetString is constructed, returns concatenated internal OctetString values + * @returns Array buffer + * @since 3.0.0 + */ + public getValue(): ArrayBuffer { + if (!this.idBlock.isConstructed) { + return this.valueBlock.valueHexView.slice().buffer; + } + + const array: ArrayBuffer[] = []; + for (const content of this.valueBlock.value) { + if (content instanceof OctetString) { + array.push(content.valueBlock.valueHexView); + } + } + + return pvtsutils.BufferSourceConverter.concat(array); + } + +} diff --git a/comm/third_party/asn1js/src/Primitive.ts b/comm/third_party/asn1js/src/Primitive.ts new file mode 100644 index 0000000000..49b25c343b --- /dev/null +++ b/comm/third_party/asn1js/src/Primitive.ts @@ -0,0 +1,22 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { LocalPrimitiveValueBlock, LocalPrimitiveValueBlockJson, LocalPrimitiveValueBlockParams } from "./internals/LocalPrimitiveValueBlock"; +import { typeStore } from "./TypeStore"; + +export interface PrimitiveParams extends BaseBlockParams, LocalPrimitiveValueBlockParams { } +export type PrimitiveJson = BaseBlockJson; + +export class Primitive extends BaseBlock { + + static { + typeStore.Primitive = this; + } + + public static override NAME = "PRIMITIVE"; + + constructor(parameters: PrimitiveParams = {}) { + super(parameters, LocalPrimitiveValueBlock); + + this.idBlock.isConstructed = false; + } + +} diff --git a/comm/third_party/asn1js/src/PrintableString.ts b/comm/third_party/asn1js/src/PrintableString.ts new file mode 100644 index 0000000000..3eca544079 --- /dev/null +++ b/comm/third_party/asn1js/src/PrintableString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type PrintableStringParams = LocalSimpleStringBlockParams; +export type PrintableStringJson = LocalSimpleStringBlockJson; + +export class PrintableString extends LocalSimpleStringBlock { + + static { + typeStore.PrintableString = this; + } + + public static override NAME = "PrintableString"; + + constructor(parameters: PrintableStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 19; // PrintableString + } + +} diff --git a/comm/third_party/asn1js/src/RawData.ts b/comm/third_party/asn1js/src/RawData.ts new file mode 100644 index 0000000000..86228739fc --- /dev/null +++ b/comm/third_party/asn1js/src/RawData.ts @@ -0,0 +1,51 @@ +import * as pvtsutils from "pvtsutils"; +import { IBerConvertible } from "./types"; +import { EMPTY_VIEW } from "./internals/constants"; + +export interface IRawData { + data: ArrayBuffer; +} + +export type RawDataParams = Partial; + +/** + * Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer + */ +export class RawData implements IBerConvertible { + + + /** + * @deprecated Since v3.0.0 + */ + public get data(): ArrayBuffer { + return this.dataView.slice().buffer; + } + + /** + * @deprecated Since v3.0.0 + */ + public set data(value: ArrayBuffer) { + this.dataView = pvtsutils.BufferSourceConverter.toUint8Array(value); + } + + /** + * @since 3.0.0 + */ + public dataView: Uint8Array; + + constructor({ data = EMPTY_VIEW }: RawDataParams = {}) { + this.dataView = pvtsutils.BufferSourceConverter.toUint8Array(data); + } + + public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const endLength = inputOffset + inputLength; + this.dataView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer).subarray(inputOffset, endLength); + + return endLength; + } + + public toBER(sizeOnly?: boolean): ArrayBuffer { + return this.dataView.slice().buffer; + } + +} diff --git a/comm/third_party/asn1js/src/RelativeObjectIdentifier.ts b/comm/third_party/asn1js/src/RelativeObjectIdentifier.ts new file mode 100644 index 0000000000..997220eae4 --- /dev/null +++ b/comm/third_party/asn1js/src/RelativeObjectIdentifier.ts @@ -0,0 +1,54 @@ +import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock"; +import { LocalRelativeObjectIdentifierValueBlockParams, LocalRelativeObjectIdentifierValueBlock, LocalRelativeObjectIdentifierValueBlockJson } from "./internals/LocalRelativeObjectIdentifierValueBlock"; +import { typeStore } from "./TypeStore"; + + +export interface RelativeObjectIdentifierParams extends BaseBlockParams, LocalRelativeObjectIdentifierValueBlockParams { } +export interface RelativeObjectIdentifierJson extends BaseBlockJson { + value: string; +} + +export class RelativeObjectIdentifier extends BaseBlock { + + static { + typeStore.RelativeObjectIdentifier = this; + } + + /** + * Gets string representation of Relative Object Identifier + * @since 3.0.0 + */ + public getValue(): string { + return this.valueBlock.toString(); + } + + /** + * Sets Relative Object Identifier value from string + * @param value String value + * @since 3.0.0 + */ + public setValue(value: string): void { + this.valueBlock.fromString(value); + } + + public static override NAME = "RelativeObjectIdentifier"; + + constructor(parameters: RelativeObjectIdentifierParams = {}) { + super(parameters, LocalRelativeObjectIdentifierValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 13; // RELATIVE OBJECT IDENTIFIER + } + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof RelativeObjectIdentifier).NAME} : ${this.valueBlock.toString() || "empty"}`; + } + + public override toJSON(): RelativeObjectIdentifierJson { + return { + ...super.toJSON(), + value: this.getValue(), + }; + } + +} diff --git a/comm/third_party/asn1js/src/Repeated.ts b/comm/third_party/asn1js/src/Repeated.ts new file mode 100644 index 0000000000..38142fa533 --- /dev/null +++ b/comm/third_party/asn1js/src/Repeated.ts @@ -0,0 +1,26 @@ +import { IAny, Any } from "./Any"; + +export interface IRepeated extends IAny { + value: Any; + local: boolean; +} + +export type RepeatedParams = Partial; + +export class Repeated extends Any { + + public value: Any; + public local: boolean; + + constructor({ + value = new Any(), + local = false, + ...parameters + }: RepeatedParams = {}) { + super(parameters); + + this.value = value; + this.local = local; // Could local or global array to store elements + } + +} diff --git a/comm/third_party/asn1js/src/Sequence.ts b/comm/third_party/asn1js/src/Sequence.ts new file mode 100644 index 0000000000..3303283bb2 --- /dev/null +++ b/comm/third_party/asn1js/src/Sequence.ts @@ -0,0 +1,22 @@ +import { ConstructedParams, Constructed, ConstructedJson } from "./Constructed"; +import { typeStore } from "./TypeStore"; + +export type SequenceParams = ConstructedParams; +export type SequenceJson = ConstructedJson; + +export class Sequence extends Constructed { + + static { + typeStore.Sequence = this; + } + + public static override NAME = "SEQUENCE"; + + constructor(parameters: SequenceParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 16; // Sequence + } + +} diff --git a/comm/third_party/asn1js/src/Set.ts b/comm/third_party/asn1js/src/Set.ts new file mode 100644 index 0000000000..1bbdec447c --- /dev/null +++ b/comm/third_party/asn1js/src/Set.ts @@ -0,0 +1,22 @@ +import { ConstructedParams, Constructed, ConstructedJson } from "./Constructed"; +import { typeStore } from "./TypeStore"; + +export type SetParams = ConstructedParams; +export type SetJson = ConstructedJson; + +export class Set extends Constructed { + + static { + typeStore.Set = this; + } + + public static override NAME = "SET"; + + constructor(parameters: SetParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 17; // Set + } + +} diff --git a/comm/third_party/asn1js/src/TIME.ts b/comm/third_party/asn1js/src/TIME.ts new file mode 100644 index 0000000000..97fee031b0 --- /dev/null +++ b/comm/third_party/asn1js/src/TIME.ts @@ -0,0 +1,22 @@ +import { typeStore } from "./TypeStore"; +import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String"; + +export type TIMEParams = Utf8StringParams; +export type TIMEJson = Utf8StringJson; + +export class TIME extends Utf8String { + + static { + typeStore.TIME = this; + } + + public static override NAME = "TIME"; + + constructor(parameters: TIMEParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 14; // Time + } + +} diff --git a/comm/third_party/asn1js/src/TeletexString.ts b/comm/third_party/asn1js/src/TeletexString.ts new file mode 100644 index 0000000000..0f7e38d36c --- /dev/null +++ b/comm/third_party/asn1js/src/TeletexString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type TeletexStringParams = LocalSimpleStringBlockParams; +export type TeletexStringJson = LocalSimpleStringBlockJson; + +export class TeletexString extends LocalSimpleStringBlock { + + static { + typeStore.TeletexString = this; + } + + public static override NAME = "TeletexString"; + + constructor(parameters: TeletexStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 20; // TeletexString + } + +} diff --git a/comm/third_party/asn1js/src/TimeOfDay.ts b/comm/third_party/asn1js/src/TimeOfDay.ts new file mode 100644 index 0000000000..78c8fac4ec --- /dev/null +++ b/comm/third_party/asn1js/src/TimeOfDay.ts @@ -0,0 +1,22 @@ +import { typeStore } from "./TypeStore"; +import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String"; + +export type TimeOfDayParams = Utf8StringParams; +export type TimeOfDayJson = Utf8StringJson; + +export class TimeOfDay extends Utf8String { + + static { + typeStore.TimeOfDay = this; + } + + public static override NAME = "TimeOfDay"; + + constructor(parameters: TimeOfDayParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 32; // TimeOfDay + } + +} diff --git a/comm/third_party/asn1js/src/TypeStore.ts b/comm/third_party/asn1js/src/TypeStore.ts new file mode 100644 index 0000000000..17b86ae97d --- /dev/null +++ b/comm/third_party/asn1js/src/TypeStore.ts @@ -0,0 +1,71 @@ +import type { BaseBlock } from "./BaseBlock"; +import type { BitString } from "./BitString"; +import type { BmpString } from "./BmpString"; +import type { Boolean as AsnBoolean } from "./Boolean"; +import type { CharacterString } from "./CharacterString"; +import type { Constructed } from "./Constructed"; +import type { DATE } from "./DATE"; +import type { DateTime } from "./DateTime"; +import type { Duration } from "./Duration"; +import type { EndOfContent } from "./EndOfContent"; +import type { Enumerated } from "./Enumerated"; +import type { GeneralizedTime } from "./GeneralizedTime"; +import type { GeneralString } from "./GeneralString"; +import type { GraphicString } from "./GraphicString"; +import type { IA5String } from "./IA5String"; +import type { Integer } from "./Integer"; +import type { Null } from "./Null"; +import type { NumericString } from "./NumericString"; +import type { ObjectIdentifier } from "./ObjectIdentifier"; +import type { OctetString } from "./OctetString"; +import type { Primitive } from "./Primitive"; +import type { PrintableString } from "./PrintableString"; +import type { RelativeObjectIdentifier } from "./RelativeObjectIdentifier"; +import type { Sequence } from "./Sequence"; +import type { Set } from "./Set"; +import type { TeletexString } from "./TeletexString"; +import type { TIME } from "./TIME"; +import type { TimeOfDay } from "./TimeOfDay"; +import type { UniversalString } from "./UniversalString"; +import type { UTCTime } from "./UTCTime"; +import type { Utf8String } from "./Utf8String"; +import type { VideotexString } from "./VideotexString"; +import type { VisibleString } from "./VisibleString"; + +export type AsnType = BaseBlock | EndOfContent | AsnBoolean | Integer | BitString | OctetString | Null | ObjectIdentifier | Enumerated | Utf8String | RelativeObjectIdentifier | TIME | Sequence | Set | NumericString | PrintableString | TeletexString | VideotexString | IA5String | UTCTime | GeneralizedTime | GraphicString | VisibleString | GeneralString | UniversalString | CharacterString | BmpString | DATE | TimeOfDay | DateTime | Duration | Constructed | Primitive; + +export interface TypeStore { + BitString: typeof BitString; + BmpString: typeof BmpString; + Boolean: typeof AsnBoolean; + CharacterString: typeof CharacterString; + Constructed: typeof Constructed; + DATE: typeof DATE; + DateTime: typeof DateTime; + Duration: typeof Duration; + EndOfContent: typeof EndOfContent; + Enumerated: typeof Enumerated; + GeneralizedTime: typeof GeneralizedTime; + GeneralString: typeof GeneralString; + GraphicString: typeof GraphicString; + IA5String: typeof IA5String; + Integer: typeof Integer; + Null: typeof Null; + NumericString: typeof NumericString; + ObjectIdentifier: typeof ObjectIdentifier; + OctetString: typeof OctetString; + Primitive: typeof Primitive; + PrintableString: typeof PrintableString; + RelativeObjectIdentifier: typeof RelativeObjectIdentifier; + Sequence: typeof Sequence; + Set: typeof Set; + TeletexString: typeof TeletexString; + TIME: typeof TIME; + TimeOfDay: typeof TimeOfDay; + UniversalString: typeof UniversalString; + UTCTime: typeof UTCTime; + Utf8String: typeof Utf8String; + VideotexString: typeof VideotexString; + VisibleString: typeof VisibleString; +} +export const typeStore = {} as TypeStore; diff --git a/comm/third_party/asn1js/src/UTCTime.ts b/comm/third_party/asn1js/src/UTCTime.ts new file mode 100644 index 0000000000..a387556051 --- /dev/null +++ b/comm/third_party/asn1js/src/UTCTime.ts @@ -0,0 +1,172 @@ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { BaseBlockJson, StringEncoding } from "./BaseBlock"; +import { LocalSimpleStringValueBlockJson } from "./internals/LocalSimpleStringValueBlock"; +import { IDateConvertible } from "./types"; +import { typeStore } from "./TypeStore"; +import { VisibleStringParams, VisibleString } from "./VisibleString"; + +export interface IUTCTime { + year: number; + month: number; + day: number; + hour: number; + minute: number; + second: number; +} + +export interface UTCTimeParams extends VisibleStringParams { + value?: string; + valueDate?: Date; +} +export interface UTCTimeJson extends BaseBlockJson, IUTCTime { } + +export type DateStringEncoding = StringEncoding | "iso"; + +export class UTCTime extends VisibleString implements IUTCTime, IDateConvertible { + + static { + typeStore.UTCTime = this; + } + + public static override NAME = "UTCTime"; + + public year: number; + public month: number; + public day: number; + public hour: number; + public minute: number; + public second: number; + + constructor({ + value, + valueDate, + ...parameters + }: UTCTimeParams = {}) { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + + //#region Create UTCTime from ASN.1 UTC string value + if (value) { + this.fromString(value); + + this.valueBlock.valueHexView = new Uint8Array(value.length); + + for (let i = 0; i < value.length; i++) + this.valueBlock.valueHexView[i] = value.charCodeAt(i); + } + //#endregion + //#region Create GeneralizedTime from JavaScript Date type + if (valueDate) { + this.fromDate(valueDate); + this.valueBlock.valueHexView = new Uint8Array(this.toBuffer()); + } + //#endregion + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 23; // UTCTime + } + + public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void { + this.fromString(String.fromCharCode.apply(null, pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer) as unknown as number[])); + } + + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns + */ + public toBuffer(): ArrayBuffer { + const str = this.toString(); // TODO use this.valueBlock.value and update toString + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for (let i = 0; i < str.length; i++) + view[i] = str.charCodeAt(i); + + return buffer; + } + + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + public fromDate(inputDate: Date): void { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + } + + public toDate(): Date { + return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second))); + } + + public override fromString(inputString: string): void { + //#region Parse input string + const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig; + const parserArray = parser.exec(inputString); + if (parserArray === null) { + this.error = "Wrong input string for conversion"; + + return; + } + //#endregion + //#region Store parsed values + const year = parseInt(parserArray[1], 10); + if (year >= 50) + this.year = 1900 + year; + + else + this.year = 2000 + year; + + this.month = parseInt(parserArray[2], 10); + this.day = parseInt(parserArray[3], 10); + this.hour = parseInt(parserArray[4], 10); + this.minute = parseInt(parserArray[5], 10); + this.second = parseInt(parserArray[6], 10); + //#endregion + } + + public override toString(encoding: DateStringEncoding = "iso"): string { + if (encoding === "iso") { + const outputArray = new Array(7); + + outputArray[0] = pvutils.padNumber(((this.year < 2000) ? (this.year - 1900) : (this.year - 2000)), 2); + outputArray[1] = pvutils.padNumber(this.month, 2); + outputArray[2] = pvutils.padNumber(this.day, 2); + outputArray[3] = pvutils.padNumber(this.hour, 2); + outputArray[4] = pvutils.padNumber(this.minute, 2); + outputArray[5] = pvutils.padNumber(this.second, 2); + outputArray[6] = "Z"; + + return outputArray.join(""); + } + + return super.toString(encoding); + } + + protected override onAsciiEncoding(): string { + return `${(this.constructor as typeof UTCTime).NAME} : ${this.toDate().toISOString()}`; + } + + public override toJSON(): UTCTimeJson { + return { + ...super.toJSON(), + year: this.year, + month: this.month, + day: this.day, + hour: this.hour, + minute: this.minute, + second: this.second, + }; + } + +} diff --git a/comm/third_party/asn1js/src/UniversalString.ts b/comm/third_party/asn1js/src/UniversalString.ts new file mode 100644 index 0000000000..fce5b1d0ac --- /dev/null +++ b/comm/third_party/asn1js/src/UniversalString.ts @@ -0,0 +1,24 @@ +import { LocalUniversalStringValueBlockParams, LocalUniversalStringValueBlock, LocalUniversalStringValueBlockJson } from "./internals/LocalUniversalStringValueBlockParams"; +import { typeStore } from "./TypeStore"; + +export type UniversalStringParams = LocalUniversalStringValueBlockParams; +export type UniversalStringJson = LocalUniversalStringValueBlockJson; + +export class UniversalString extends LocalUniversalStringValueBlock { + + static { + typeStore.UniversalString = this; + } + + public static override NAME = "UniversalString"; + + constructor({ + ...parameters + }: UniversalStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 28; // UniversalString + } + +} diff --git a/comm/third_party/asn1js/src/Utf8String.ts b/comm/third_party/asn1js/src/Utf8String.ts new file mode 100644 index 0000000000..2713cd1b95 --- /dev/null +++ b/comm/third_party/asn1js/src/Utf8String.ts @@ -0,0 +1,24 @@ +import { BaseBlockJson } from "./BaseBlock"; +import { BaseStringBlockParams } from "./BaseStringBlock"; +import { LocalUtf8StringValueBlockParams, LocalUtf8StringValueBlock, LocalUtf8StringValueBlockJson } from "./internals/LocalUtf8StringValueBlock"; +import { typeStore } from "./TypeStore"; + +export interface Utf8StringParams extends BaseStringBlockParams, LocalUtf8StringValueBlockParams { } +export type Utf8StringJson = BaseBlockJson; + +export class Utf8String extends LocalUtf8StringValueBlock { + + static { + typeStore.Utf8String = this; + } + + public static override NAME = "UTF8String"; + + constructor(parameters: Utf8StringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 12; // Utf8String + } + +} diff --git a/comm/third_party/asn1js/src/ValueBlock.ts b/comm/third_party/asn1js/src/ValueBlock.ts new file mode 100644 index 0000000000..9463214aef --- /dev/null +++ b/comm/third_party/asn1js/src/ValueBlock.ts @@ -0,0 +1,21 @@ +import { IBerConvertible } from "./types"; +import * as internals from "./internals/LocalBaseBlock"; +import { ViewWriter } from "./ViewWriter"; + +export type IValueBlock = internals.ILocalBaseBlock; +export type ValueBlockParams = internals.LocalBaseBlockParams; +export type ValueBlockJson = internals.LocalBaseBlockJson; + +export class ValueBlock extends internals.LocalBaseBlock implements IValueBlock, IBerConvertible { + + public static override NAME = "valueBlock"; + + public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'"); + } + + public toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'"); + } + +} diff --git a/comm/third_party/asn1js/src/VideotexString.ts b/comm/third_party/asn1js/src/VideotexString.ts new file mode 100644 index 0000000000..d1867b602e --- /dev/null +++ b/comm/third_party/asn1js/src/VideotexString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type VideotexStringParams = LocalSimpleStringBlockParams; +export type VideotexStringJson = LocalSimpleStringBlockJson; + +export class VideotexString extends LocalSimpleStringBlock { + + static { + typeStore.VideotexString = this; + } + + public static override NAME = "VideotexString"; + + constructor(parameters: VideotexStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 21; // VideotexString + } + +} diff --git a/comm/third_party/asn1js/src/ViewWriter.ts b/comm/third_party/asn1js/src/ViewWriter.ts new file mode 100644 index 0000000000..1df3a1170c --- /dev/null +++ b/comm/third_party/asn1js/src/ViewWriter.ts @@ -0,0 +1,22 @@ +import * as utils from "./internals/utils"; + +export class ViewWriter { + + public items: ArrayBuffer[] = []; + + /** + * Writes buffer + * @param buf + */ + public write(buf: ArrayBuffer): void { + this.items.push(buf); + } + + /** + * Concatenates all buffers + * @returns Concatenated buffer + */ + public final(): ArrayBuffer { + return utils.concat(this.items); + } +} diff --git a/comm/third_party/asn1js/src/VisibleString.ts b/comm/third_party/asn1js/src/VisibleString.ts new file mode 100644 index 0000000000..aead80a4cc --- /dev/null +++ b/comm/third_party/asn1js/src/VisibleString.ts @@ -0,0 +1,22 @@ +import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock"; +import { typeStore } from "./TypeStore"; + +export type VisibleStringParams = LocalSimpleStringBlockParams; +export type VisibleStringJson = LocalSimpleStringBlockJson; + +export class VisibleString extends LocalSimpleStringBlock { + + static { + typeStore.VisibleString = this; + } + + public static override NAME = "VisibleString"; + + constructor(parameters: VisibleStringParams = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 26; // VisibleString + } + +} diff --git a/comm/third_party/asn1js/src/index.ts b/comm/third_party/asn1js/src/index.ts new file mode 100644 index 0000000000..a4b15b34af --- /dev/null +++ b/comm/third_party/asn1js/src/index.ts @@ -0,0 +1,59 @@ +export * from "./types"; + +// basic +export * from "./ViewWriter"; +export * from "./HexBlock"; +export * from "./ValueBlock"; +export * from "./BaseBlock"; +export * from "./BaseStringBlock"; + +export * from "./Primitive"; +export * from "./Constructed"; +export * from "./EndOfContent"; + +// common +export * from "./Null"; +export * from "./Boolean"; +export * from "./OctetString"; +export * from "./BitString"; +export * from "./Integer"; +export * from "./Enumerated"; +export * from "./ObjectIdentifier"; +export * from "./RelativeObjectIdentifier"; +export * from "./Sequence"; +export * from "./Set"; + +// strings +export * from "./Utf8String"; +export * from "./BmpString"; +export * from "./UniversalString"; +export * from "./NumericString"; +export * from "./PrintableString"; +export * from "./TeletexString"; +export * from "./VideotexString"; +export * from "./IA5String"; +export * from "./GraphicString"; +export * from "./VisibleString"; +export * from "./GeneralString"; +export * from "./CharacterString"; + +// date and time +export * from "./UTCTime"; +export * from "./GeneralizedTime"; +export * from "./DATE"; +export * from "./TimeOfDay"; +export * from "./DateTime"; +export * from "./Duration"; +export * from "./TIME"; + +// schema types +export * from "./Any"; +export * from "./Choice"; +export * from "./Repeated"; + +// special +export * from "./RawData"; + +export { FromBerResult, fromBER } from "./parser"; +export * from "./schema"; +export { AsnType } from "./TypeStore"; \ No newline at end of file diff --git a/comm/third_party/asn1js/src/internals/LocalBaseBlock.ts b/comm/third_party/asn1js/src/internals/LocalBaseBlock.ts new file mode 100644 index 0000000000..c144c49d10 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalBaseBlock.ts @@ -0,0 +1,93 @@ +import * as pvtsutils from "pvtsutils"; +import { EMPTY_STRING, EMPTY_VIEW } from "./constants"; + +export interface ILocalBaseBlock { + blockLength: number; + error: string; + warnings: string[]; +} + +export interface LocalBaseBlockJson extends ILocalBaseBlock { + blockName: string; + valueBeforeDecode: string; +} + +export interface LocalBaseBlockParams extends Partial { + valueBeforeDecode?: pvtsutils.BufferSource; +} + +export interface LocalBaseBlockConstructor { + new(...args: any[]): T; + prototype: T; + NAME: string; + blockName(): string; +} + +/** + * Class used as a base block for all remaining ASN.1 classes + */ +export class LocalBaseBlock implements ILocalBaseBlock { + + /** + * Name of the block + */ + public static NAME = "baseBlock"; + /** + * Aux function, need to get a block name. Need to have it here for inheritance + * @returns Returns name of the block + */ + public static blockName(): string { + return this.NAME; + } + + public blockLength: number; + public error: string; + public warnings: string[]; + /** + * @deprecated since version 3.0.0 + */ + public get valueBeforeDecode(): ArrayBuffer { + return this.valueBeforeDecodeView.slice().buffer; + } + /** + * @deprecated since version 3.0.0 + */ + public set valueBeforeDecode(value: ArrayBuffer) { + this.valueBeforeDecodeView = new Uint8Array(value); + } + /** + * @since 3.0.0 + */ + public valueBeforeDecodeView: Uint8Array; + + /** + * Creates and initializes an object instance of that class + * @param param0 Initialization parameters + */ + constructor({ + blockLength = 0, + error = EMPTY_STRING, + warnings = [], + valueBeforeDecode = EMPTY_VIEW, + }: LocalBaseBlockParams = {}) { + this.blockLength = blockLength; + this.error = error; + this.warnings = warnings; + this.valueBeforeDecodeView = pvtsutils.BufferSourceConverter.toUint8Array(valueBeforeDecode); + } + + /** + * Returns a JSON representation of an object + * @returns JSON object + */ + public toJSON(): LocalBaseBlockJson { + return { + blockName: (this.constructor as typeof LocalBaseBlock).NAME, + blockLength: this.blockLength, + error: this.error, + warnings: this.warnings, + valueBeforeDecode: pvtsutils.Convert.ToHex(this.valueBeforeDecodeView), + }; + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalBitStringValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalBitStringValueBlock.ts new file mode 100644 index 0000000000..1720b55d82 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalBitStringValueBlock.ts @@ -0,0 +1,168 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as pvtsutils from "pvtsutils"; +import { ViewWriter } from "../ViewWriter"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { BIT_STRING_NAME, EMPTY_BUFFER, END_OF_CONTENT_NAME } from "./constants"; +import { LocalConstructedValueBlockParams, LocalConstructedValueBlockJson, LocalConstructedValueBlock } from "./LocalConstructedValueBlock"; +import { localFromBER } from "../parser"; +import { checkBufferParams } from "./utils"; +import type { BitString } from "../BitString"; + +export interface ILocalBitStringValueBlock { + unusedBits: number; + isConstructed: boolean; +} + +export interface LocalBitStringValueBlockParams extends HexBlockParams, LocalConstructedValueBlockParams, Partial { + value?: BitString[]; +} + +export interface LocalBitStringValueBlockJson extends HexBlockJson, LocalConstructedValueBlockJson, ILocalBitStringValueBlock { } + +export class LocalBitStringValueBlock extends HexBlock(LocalConstructedValueBlock) implements ILocalBitStringValueBlock { + + public static override NAME = "BitStringValueBlock"; + + public unusedBits: number; + public isConstructed: boolean; + + constructor({ + unusedBits = 0, + isConstructed = false, + ...parameters + }: LocalBitStringValueBlockParams = {}) { + super(parameters); + + this.unusedBits = unusedBits; + this.isConstructed = isConstructed; + this.blockLength = this.valueHexView.byteLength; + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + // Ability to decode zero-length BitString value + if (!inputLength) { + return inputOffset; + } + + let resultOffset = -1; + + // If the BIT STRING supposed to be a constructed value + if (this.isConstructed) { + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) + return resultOffset; + + for (const value of this.value) { + const currentBlockName = (value.constructor as typeof LocalBitStringValueBlock).NAME; + + if (currentBlockName === END_OF_CONTENT_NAME) { + if (this.isIndefiniteForm) + break; + else { + this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only"; + + return -1; + } + } + + if (currentBlockName !== BIT_STRING_NAME) { + this.error = "BIT STRING may consists of BIT STRINGs only"; + + return -1; + } + + const valueBlock = value.valueBlock as unknown as LocalBitStringValueBlock; + if ((this.unusedBits > 0) && (valueBlock.unusedBits > 0)) { + this.error = "Using of \"unused bits\" inside constructive BIT STRING allowed for least one only"; + + return -1; + } + + this.unusedBits = valueBlock.unusedBits; + } + + return resultOffset; + } + + const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + + //If the BitString supposed to be a primitive value + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + + this.unusedBits = intBuffer[0]; + + if (this.unusedBits > 7) { + this.error = "Unused bits for BitString must be in range 0-7"; + + return -1; + } + + if (!this.unusedBits) { + const buf = intBuffer.subarray(1); + try { + if (buf.byteLength) { + const asn = localFromBER(buf, 0, buf.byteLength); + if (asn.offset !== -1 && asn.offset === (inputLength - 1)) { + this.value = [asn.result as BitString]; + } + } + } catch (e) { + // nothing + } + } + + // Copy input buffer to internal buffer + this.valueHexView = intBuffer.subarray(1); + this.blockLength = intBuffer.length; + + return (inputOffset + inputLength); + } + + public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + if (this.isConstructed) { + return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer); + } + + if (sizeOnly) { + return new ArrayBuffer(this.valueHexView.byteLength + 1); + } + + if (!this.valueHexView.byteLength) { + return EMPTY_BUFFER; + } + + const retView = new Uint8Array(this.valueHexView.length + 1); + + retView[0] = this.unusedBits; + retView.set(this.valueHexView, 1); + + return retView.buffer; + } + + public override toJSON(): LocalBitStringValueBlockJson { + return { + ...super.toJSON(), + unusedBits: this.unusedBits, + isConstructed: this.isConstructed, + } as LocalBitStringValueBlockJson; + } +} + +export interface LocalBitStringValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalBmpStringValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalBmpStringValueBlock.ts new file mode 100644 index 0000000000..6245512755 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalBmpStringValueBlock.ts @@ -0,0 +1,21 @@ +import * as pvtsutils from "pvtsutils"; +import { LocalSimpleStringBlock, LocalSimpleStringBlockJson, LocalSimpleStringBlockParams } from "./LocalSimpleStringBlock"; + +export type LocalBmpStringValueBlockParams = LocalSimpleStringBlockParams; +export type LocalBmpStringValueBlockJson = LocalSimpleStringBlockJson; + +export class LocalBmpStringValueBlock extends LocalSimpleStringBlock { + + public static override NAME = "BmpStringValueBlock"; + + public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void { + this.valueBlock.value = pvtsutils.Convert.ToUtf16String(inputBuffer); + this.valueBlock.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + } + + public override fromString(inputString: string): void { + this.valueBlock.value = inputString; + this.valueBlock.valueHexView = new Uint8Array(pvtsutils.Convert.FromUtf16String(inputString)); + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalBooleanValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalBooleanValueBlock.ts new file mode 100644 index 0000000000..a4cdb35dee --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalBooleanValueBlock.ts @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { checkBufferParams } from "./utils"; + +export interface ILocalBooleanValueBlock { + value: boolean; +} + +export interface LocalBooleanValueBlockParams extends ValueBlockParams, HexBlockParams, Partial { } + +export interface LocalBooleanValueBlockJson extends ValueBlockJson, HexBlockJson, ILocalBooleanValueBlock { } + +export class LocalBooleanValueBlock extends HexBlock(ValueBlock) implements ILocalBooleanValueBlock { + + public static override NAME = "BooleanValueBlock"; + + public get value(): boolean { + for (const octet of this.valueHexView) { + if (octet > 0) { + return true; + } + } + + return false; + } + + public set value(value: boolean) { + this.valueHexView[0] = value ? 0xFF : 0x00; + } + + constructor({ + value, + ...parameters + }: LocalBooleanValueBlockParams = {}) { + super(parameters); + + if (parameters.valueHex) { + this.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(parameters.valueHex); + } else { + this.valueHexView = new Uint8Array(1); + } + + if (value) { + this.value = value; + } + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + // Basic check for parameters + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + + // Getting Uint8Array + this.valueHexView = inputView.subarray(inputOffset, inputOffset + inputLength); + + if (inputLength > 1) + this.warnings.push("Boolean value encoded in more then 1 octet"); + + this.isHexOnly = true; + pvutils.utilDecodeTC.call(this); + this.blockLength = inputLength; + + return (inputOffset + inputLength); + } + + public override toBER(): ArrayBuffer { + return this.valueHexView.slice(); + } + + public override toJSON(): LocalBooleanValueBlockJson { + return { + ...super.toJSON(), + value: this.value, + }; + } +} + +export interface LocalBooleanValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalConstructedValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalConstructedValueBlock.ts new file mode 100644 index 0000000000..db3ba9f35e --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalConstructedValueBlock.ts @@ -0,0 +1,128 @@ +import * as pvtsutils from "pvtsutils"; +import { LocalBaseBlockJson } from "./LocalBaseBlock"; +import { EMPTY_BUFFER, END_OF_CONTENT_NAME } from "./constants"; +import type { BaseBlock } from "../BaseBlock"; +import { ValueBlock, ValueBlockParams } from "../ValueBlock"; +import { ViewWriter } from "../ViewWriter"; +import { localFromBER } from "../parser"; +import { checkBufferParams } from "./utils"; +import type { Any } from "../Any"; + +export type ConstructedItem = BaseBlock | Any; + +export interface ILocalConstructedValueBlock { + value: ConstructedItem[]; + isIndefiniteForm: boolean; +} + +export interface LocalConstructedValueBlockParams extends ValueBlockParams, Partial { } + +export interface LocalConstructedValueBlockJson extends LocalBaseBlockJson, Omit { + value: LocalBaseBlockJson[]; +} + +function checkLen(indefiniteLength: boolean, length: number): number { + if (indefiniteLength) { + return 1; + } + + return length; +} + +export class LocalConstructedValueBlock extends ValueBlock implements ILocalConstructedValueBlock { + + public static override NAME = "ConstructedValueBlock"; + + public value: BaseBlock[]; + public isIndefiniteForm: boolean; + + constructor({ + value = [], + isIndefiniteForm = false, + ...parameters + }: LocalConstructedValueBlockParams = {}) { + super(parameters); + + this.value = value as BaseBlock[]; // It's possible to set Any type for Schema declaration + this.isIndefiniteForm = isIndefiniteForm; + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const view = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + + // Basic check for parameters + if (!checkBufferParams(this, view, inputOffset, inputLength)) { + return -1; + } + + this.valueBeforeDecodeView = view.subarray(inputOffset, inputOffset + inputLength); + + // Initial checks + if (this.valueBeforeDecodeView.length === 0) { + this.warnings.push("Zero buffer length"); + + return inputOffset; + } + + let currentOffset = inputOffset; + + while (checkLen(this.isIndefiniteForm, inputLength) > 0) { + const returnObject = localFromBER(view, currentOffset, inputLength); + if (returnObject.offset === -1) { + this.error = returnObject.result.error; + this.warnings.concat(returnObject.result.warnings); + + return -1; + } + + currentOffset = returnObject.offset; + + this.blockLength += returnObject.result.blockLength; + inputLength -= returnObject.result.blockLength; + + this.value.push(returnObject.result); + + if (this.isIndefiniteForm && (returnObject.result.constructor as typeof BaseBlock).NAME === END_OF_CONTENT_NAME) { + break; + } + } + + if (this.isIndefiniteForm) { + if ((this.value[this.value.length - 1].constructor as typeof BaseBlock).NAME === END_OF_CONTENT_NAME) { + this.value.pop(); + } else { + this.warnings.push("No EndOfContent block encoded"); + } + } + + return currentOffset; + } + + public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + const _writer = writer || new ViewWriter(); + + for (let i = 0; i < this.value.length; i++) { + this.value[i].toBER(sizeOnly, _writer); + } + + if (!writer) { + return _writer.final(); + } + + return EMPTY_BUFFER; + } + + public override toJSON(): LocalConstructedValueBlockJson { + const object: LocalConstructedValueBlockJson = { + ...super.toJSON(), + isIndefiniteForm: this.isIndefiniteForm, + value: [], + }; + + for (const value of this.value) { + object.value.push(value.toJSON()); + } + + return object; + } +} diff --git a/comm/third_party/asn1js/src/internals/LocalEndOfContentValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalEndOfContentValueBlock.ts new file mode 100644 index 0000000000..4a1db86681 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalEndOfContentValueBlock.ts @@ -0,0 +1,16 @@ +import { ValueBlock } from "../ValueBlock"; +import { EMPTY_BUFFER } from "./constants"; + +export class LocalEndOfContentValueBlock extends ValueBlock { + + public static override = "EndOfContentValueBlock"; + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + // There is no "value block" for EndOfContent type and we need to return the same offset + return inputOffset; + } + + public override toBER(sizeOnly?: boolean): ArrayBuffer { + return EMPTY_BUFFER; + } +} diff --git a/comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts b/comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts new file mode 100644 index 0000000000..d97c874b7a --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts @@ -0,0 +1,280 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { EMPTY_BUFFER, EMPTY_VIEW } from "./constants"; +import { LocalBaseBlock, LocalBaseBlockJson } from "./LocalBaseBlock"; +import { checkBufferParams } from "./utils"; + + +export interface ILocalIdentificationBlock { + tagClass: number; + tagNumber: number; + isConstructed: boolean; +} + +export interface LocalIdentificationBlockParams { + idBlock?: Partial & HexBlockParams; +} + +export interface LocalIdentificationBlockJson extends HexBlockJson, LocalBaseBlockJson, ILocalIdentificationBlock { } + + +export class LocalIdentificationBlock extends HexBlock(LocalBaseBlock) implements ILocalIdentificationBlock { + + public static override NAME = "identificationBlock"; + + public tagClass: number; + public tagNumber: number; + public isConstructed: boolean; + + constructor({ + idBlock = {}, + }: LocalIdentificationBlockParams = {}) { + super(); + + if (idBlock) { + //#region Properties from hexBlock class + this.isHexOnly = idBlock.isHexOnly ?? false; + this.valueHexView = idBlock.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(idBlock.valueHex) : EMPTY_VIEW; + //#endregion + this.tagClass = idBlock.tagClass ?? -1; + this.tagNumber = idBlock.tagNumber ?? -1; + this.isConstructed = idBlock.isConstructed ?? false; + } else { + this.tagClass = -1; + this.tagNumber = -1; + this.isConstructed = false; + } + } + + public override toBER(sizeOnly = false): ArrayBuffer { + let firstOctet = 0; + + switch (this.tagClass) { + case 1: + firstOctet |= 0x00; // UNIVERSAL + break; + case 2: + firstOctet |= 0x40; // APPLICATION + break; + case 3: + firstOctet |= 0x80; // CONTEXT-SPECIFIC + break; + case 4: + firstOctet |= 0xC0; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + + return EMPTY_BUFFER; + } + + if (this.isConstructed) + firstOctet |= 0x20; + + if (this.tagNumber < 31 && !this.isHexOnly) { + const retView = new Uint8Array(1); + + if (!sizeOnly) { + let number = this.tagNumber; + number &= 0x1F; + firstOctet |= number; + + retView[0] = firstOctet; + } + + return retView.buffer; + } + + if (!this.isHexOnly) { + const encodedBuf = pvutils.utilToBase(this.tagNumber, 7); + const encodedView = new Uint8Array(encodedBuf); + const size = encodedBuf.byteLength; + + const retView = new Uint8Array(size + 1); + retView[0] = (firstOctet | 0x1F); + + if (!sizeOnly) { + for (let i = 0; i < (size - 1); i++) + retView[i + 1] = encodedView[i] | 0x80; + + retView[size] = encodedView[size - 1]; + } + + return retView.buffer; + } + + const retView = new Uint8Array(this.valueHexView.byteLength + 1); + + retView[0] = (firstOctet | 0x1F); + + if (!sizeOnly) { + const curView = this.valueHexView; + + for (let i = 0; i < (curView.length - 1); i++) + retView[i + 1] = curView[i] | 0x80; + + retView[this.valueHexView.byteLength] = curView[curView.length - 1]; + } + + return retView.buffer; + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + + // Basic check for parameters + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + + // Getting Uint8Array from ArrayBuffer + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + + // Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + + return -1; + } + + //#region Find tag class + const tagClassMask = intBuffer[0] & 0xC0; + + switch (tagClassMask) { + case 0x00: + this.tagClass = (1); // UNIVERSAL + break; + case 0x40: + this.tagClass = (2); // APPLICATION + break; + case 0x80: + this.tagClass = (3); // CONTEXT-SPECIFIC + break; + case 0xC0: + this.tagClass = (4); // PRIVATE + break; + default: + this.error = "Unknown tag class"; + + return -1; + } + //#endregion + // Find it's constructed or not + this.isConstructed = (intBuffer[0] & 0x20) === 0x20; + + // Find tag number + this.isHexOnly = false; + const tagNumberMask = intBuffer[0] & 0x1F; + + if (tagNumberMask !== 0x1F) { + // Simple case (tag number < 31) + this.tagNumber = (tagNumberMask); + this.blockLength = 1; + } else { + // Tag number bigger or equal to 31 + let count = 1; + + let intTagNumberBuffer = this.valueHexView = new Uint8Array(255); + let tagNumberBufferMaxLength = 255; + + while (intBuffer[count] & 0x80) { + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; + count++; + + if (count >= intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + + return -1; + } + + // In case if tag number length is greater than 255 bytes (rare but possible case) + if (count === tagNumberBufferMaxLength) { + tagNumberBufferMaxLength += 255; + + const tempBufferView = new Uint8Array(tagNumberBufferMaxLength); + + for (let i = 0; i < intTagNumberBuffer.length; i++) + tempBufferView[i] = intTagNumberBuffer[i]; + + intTagNumberBuffer = this.valueHexView = new Uint8Array(tagNumberBufferMaxLength); + } + } + + this.blockLength = (count + 1); + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer + + + //#region Cut buffer + const tempBufferView = new Uint8Array(count); + + for (let i = 0; i < count; i++) + tempBufferView[i] = intTagNumberBuffer[i]; + + intTagNumberBuffer = this.valueHexView = new Uint8Array(count); + intTagNumberBuffer.set(tempBufferView); + //#endregion + //#region Try to convert long tag number to short form + if (this.blockLength <= 9) + this.tagNumber = pvutils.utilFromBase(intTagNumberBuffer, 7); + else { + this.isHexOnly = true; + this.warnings.push("Tag too long, represented as hex-coded"); + } + //#endregion + } + //#endregion + //#endregion + //#region Check if constructed encoding was using for primitive type + if (((this.tagClass === 1)) && + (this.isConstructed)) { + switch (this.tagNumber) { + case 1: // Boolean + case 2: // REAL + case 5: // Null + case 6: // OBJECT IDENTIFIER + case 9: // REAL + case 13: // RELATIVE OBJECT IDENTIFIER + case 14: // Time + case 23: + case 24: + case 31: + case 32: + case 33: + case 34: + this.error = "Constructed encoding used for primitive type"; + + return -1; + default: + } + } + //#endregion + + return (inputOffset + this.blockLength); // Return current offset in input buffer + } + + public override toJSON(): LocalIdentificationBlockJson { + return { + ...super.toJSON(), + tagClass: this.tagClass, + tagNumber: this.tagNumber, + isConstructed: this.isConstructed, + }; + } +} + +export interface LocalIdentificationBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} \ No newline at end of file diff --git a/comm/third_party/asn1js/src/internals/LocalIntegerValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalIntegerValueBlock.ts new file mode 100644 index 0000000000..3a7b299caf --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalIntegerValueBlock.ts @@ -0,0 +1,330 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as pvutils from "pvutils"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { IDerConvertible } from "../types"; +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { powers2, digitsString } from "./constants"; + +function viewAdd(first: Uint8Array, second: Uint8Array): Uint8Array { + //#region Initial variables + const c = new Uint8Array([0]); + + const firstView = new Uint8Array(first); + const secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + const secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value = 0; + + const max = (secondViewCopyLength < firstViewCopyLength) ? firstViewCopyLength : secondViewCopyLength; + + let counter = 0; + //#endregion + for (let i = max; i >= 0; i--, counter++) { + switch (true) { + case (counter < secondViewCopy.length): + value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0]; + break; + default: + value = firstViewCopy[firstViewCopyLength - counter] + c[0]; + } + + c[0] = value / 10; + + switch (true) { + case (counter >= firstViewCopy.length): + firstViewCopy = pvutils.utilConcatView(new Uint8Array([value % 10]), firstViewCopy); + break; + default: + firstViewCopy[firstViewCopyLength - counter] = value % 10; + } + } + + if (c[0] > 0) + firstViewCopy = pvutils.utilConcatView(c, firstViewCopy); + + return firstViewCopy; +} + +function power2(n: number): Uint8Array { + if (n >= powers2.length) { + for (let p = powers2.length; p <= n; p++) { + const c = new Uint8Array([0]); + let digits = (powers2[p - 1]).slice(0); + + for (let i = (digits.length - 1); i >= 0; i--) { + const newValue = new Uint8Array([(digits[i] << 1) + c[0]]); + c[0] = newValue[0] / 10; + digits[i] = newValue[0] % 10; + } + + if (c[0] > 0) + digits = pvutils.utilConcatView(c, digits); + + powers2.push(digits); + } + } + + return powers2[n]; +} + +function viewSub(first: Uint8Array, second: Uint8Array): Uint8Array { + //#region Initial variables + let b = 0; + + const firstView = new Uint8Array(first); + const secondView = new Uint8Array(second); + + const firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + const secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value; + + let counter = 0; + //#endregion + for (let i = secondViewCopyLength; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b; + + switch (true) { + case (value < 0): + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + break; + default: + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + } + } + + if (b > 0) { + for (let i = (firstViewCopyLength - secondViewCopyLength + 1); i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - b; + + if (value < 0) { + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + } + else { + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + break; + } + } + } + + return firstViewCopy.slice(); +} + +export interface ILocalIntegerValueBlock { + value: number; +} + +export interface LocalIntegerValueBlockParams extends HexBlockParams, ValueBlockParams, Partial { } + +export interface LocalIntegerValueBlockJson extends HexBlockJson, ValueBlockJson { + valueDec: number; +} + +export class LocalIntegerValueBlock extends HexBlock(ValueBlock) implements IDerConvertible { + protected setValueHex(): void { + if (this.valueHexView.length >= 4) { + this.warnings.push("Too big Integer for decoding, hex only"); + this.isHexOnly = true; + this._valueDec = 0; + } else { + this.isHexOnly = false; + + if (this.valueHexView.length > 0) { + this._valueDec = pvutils.utilDecodeTC.call(this); + } + } + } + + public static override NAME = "IntegerValueBlock"; + + static { + Object.defineProperty(this.prototype, "valueHex", { + set: function (this: LocalIntegerValueBlock, v: ArrayBuffer) { + this.valueHexView = new Uint8Array(v); + + this.setValueHex(); + }, + get: function (this: LocalIntegerValueBlock) { + return this.valueHexView.slice().buffer; + }, + }); + } + + private _valueDec = 0; + + constructor({ + value, + ...parameters + }: LocalIntegerValueBlockParams = {}) { + super(parameters); + + if (parameters.valueHex) { + this.setValueHex(); + } + + if (value !== undefined) { + this.valueDec = value; + } + } + + public set valueDec(v: number) { + this._valueDec = v; + + this.isHexOnly = false; + this.valueHexView = new Uint8Array(pvutils.utilEncodeTC(v)); + } + + public get valueDec(): number { + return this._valueDec; + } + + public fromDER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number, expectedLength = 0): number { + const offset = this.fromBER(inputBuffer, inputOffset, inputLength); + if (offset === -1) + return offset; + + const view = this.valueHexView; + + if ((view[0] === 0x00) && ((view[1] & 0x80) !== 0)) { + this.valueHexView = view.subarray(1); + } + else { + if (expectedLength !== 0) { + if (view.length < expectedLength) { + if ((expectedLength - view.length) > 1) + expectedLength = view.length + 1; + + this.valueHexView = view.subarray(expectedLength - view.length); + } + } + } + + return offset; + } + + public toDER(sizeOnly = false): ArrayBuffer { + const view = this.valueHexView; + + switch (true) { + case ((view[0] & 0x80) !== 0): + { + const updatedView = new Uint8Array(this.valueHexView.length + 1); + + updatedView[0] = 0x00; + updatedView.set(view, 1); + + this.valueHexView = updatedView; + } + break; + case ((view[0] === 0x00) && ((view[1] & 0x80) === 0)): + { + this.valueHexView = this.valueHexView.subarray(1); + } + break; + default: + } + + return this.toBER(sizeOnly); + } + + public override fromBER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number): number { + const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) { + return resultOffset; + } + + this.setValueHex(); + + return resultOffset; + } + + public override toBER(sizeOnly?: boolean): ArrayBuffer { + return sizeOnly + ? new ArrayBuffer(this.valueHexView.length) + : this.valueHexView.slice().buffer; + } + + public override toJSON(): LocalIntegerValueBlockJson { + return { + ...super.toJSON(), + valueDec: this.valueDec, + }; + } + + public override toString(): string { + //#region Initial variables + const firstBit = (this.valueHexView.length * 8) - 1; + + let digits = new Uint8Array((this.valueHexView.length * 8) / 3); + let bitNumber = 0; + let currentByte; + + const asn1View = this.valueHexView; + + let result = ""; + + let flag = false; + //#endregion + //#region Calculate number + for (let byteNumber = (asn1View.byteLength - 1); byteNumber >= 0; byteNumber--) { + currentByte = asn1View[byteNumber]; + + for (let i = 0; i < 8; i++) { + if ((currentByte & 1) === 1) { + switch (bitNumber) { + case firstBit: + digits = viewSub(power2(bitNumber), digits); + result = "-"; + break; + default: + digits = viewAdd(digits, power2(bitNumber)); + } + } + + bitNumber++; + currentByte >>= 1; + } + } + //#endregion + //#region Print number + for (let i = 0; i < digits.length; i++) { + if (digits[i]) + flag = true; + + if (flag) + result += digitsString.charAt(digits[i]); + } + + if (flag === false) + result += digitsString.charAt(0); + //#endregion + + return result; + } + +} + +export interface LocalIntegerValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalLengthBlock.ts b/comm/third_party/asn1js/src/internals/LocalLengthBlock.ts new file mode 100644 index 0000000000..a4c7940b02 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalLengthBlock.ts @@ -0,0 +1,182 @@ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { IBerConvertible } from "../types"; +import { EMPTY_BUFFER } from "./constants"; +import { LocalBaseBlock, LocalBaseBlockJson } from "./LocalBaseBlock"; +import { checkBufferParams } from "./utils"; + +export interface ILocalLengthBlock { + isIndefiniteForm: boolean; + longFormUsed: boolean; + length: number; +} + +export interface LocalLengthBlockParams { + lenBlock?: Partial; +} + +export interface LocalLengthBlockJson extends LocalBaseBlockJson, ILocalLengthBlock { + isIndefiniteForm: boolean; + longFormUsed: boolean; + length: number; +} + +export class LocalLengthBlock extends LocalBaseBlock implements ILocalLengthBlock, IBerConvertible { + + public static override NAME = "lengthBlock"; + + public isIndefiniteForm: boolean; + public longFormUsed: boolean; + public length: number; + + constructor({ + lenBlock = {}, + }: LocalLengthBlockParams = {}) { + super(); + + this.isIndefiniteForm = lenBlock.isIndefiniteForm ?? false; + this.longFormUsed = lenBlock.longFormUsed ?? false; + this.length = lenBlock.length ?? 0; + } + + + public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + const view = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + // Basic check for parameters + if (!checkBufferParams(this, view, inputOffset, inputLength)) { + return -1; + } + //#region Getting Uint8Array from ArrayBuffer + const intBuffer = view.subarray(inputOffset, inputOffset + inputLength); + //#endregion + //#region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + + return -1; + } + + if (intBuffer[0] === 0xFF) { + this.error = "Length block 0xFF is reserved by standard"; + + return -1; + } + //#endregion + //#region Check for length form type + this.isIndefiniteForm = intBuffer[0] === 0x80; + //#endregion + //#region Stop working in case of indefinite length form + if (this.isIndefiniteForm) { + this.blockLength = 1; + + return (inputOffset + this.blockLength); + } + //#endregion + //#region Check is long form of length encoding using + this.longFormUsed = !!(intBuffer[0] & 0x80); + //#endregion + //#region Stop working in case of short form of length value + if (this.longFormUsed === false) { + this.length = (intBuffer[0]); + this.blockLength = 1; + + return (inputOffset + this.blockLength); + } + //#endregion + //#region Calculate length value in case of long form + const count = intBuffer[0] & 0x7F; + + if (count > 8) // Too big length value + { + this.error = "Too big integer"; + + return -1; + } + + if ((count + 1) > intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + + return -1; + } + + const lenOffset = inputOffset + 1; + const lengthBufferView = view.subarray(lenOffset, lenOffset + count); + + if (lengthBufferView[count - 1] === 0x00) + this.warnings.push("Needlessly long encoded length"); + + this.length = pvutils.utilFromBase(lengthBufferView, 8); + + if (this.longFormUsed && (this.length <= 127)) + this.warnings.push("Unnecessary usage of long length form"); + + this.blockLength = count + 1; + //#endregion + + return (inputOffset + this.blockLength); // Return current offset in input buffer + } + + public toBER(sizeOnly = false): ArrayBuffer { + //#region Initial variables + let retBuf: ArrayBuffer; + let retView: Uint8Array; + //#endregion + if (this.length > 127) + this.longFormUsed = true; + + if (this.isIndefiniteForm) { + retBuf = new ArrayBuffer(1); + + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + retView[0] = 0x80; + } + + return retBuf; + } + + if (this.longFormUsed) { + const encodedBuf = pvutils.utilToBase(this.length, 8); + + if (encodedBuf.byteLength > 127) { + this.error = "Too big length"; + + return (EMPTY_BUFFER); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength + 1); + + if (sizeOnly) + return retBuf; + + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + retView[0] = encodedBuf.byteLength | 0x80; + + for (let i = 0; i < encodedBuf.byteLength; i++) + retView[i + 1] = encodedView[i]; + + return retBuf; + } + + retBuf = new ArrayBuffer(1); + + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + + retView[0] = this.length; + } + + return retBuf; + } + + public override toJSON(): LocalLengthBlockJson { + return { + ...super.toJSON(), + isIndefiniteForm: this.isIndefiniteForm, + longFormUsed: this.longFormUsed, + length: this.length, + }; + } +} diff --git a/comm/third_party/asn1js/src/internals/LocalObjectIdentifierValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalObjectIdentifierValueBlock.ts new file mode 100644 index 0000000000..a24b9e947a --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalObjectIdentifierValueBlock.ts @@ -0,0 +1,192 @@ +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { EMPTY_BUFFER, EMPTY_STRING } from "./constants"; +import * as utils from "./utils"; +import { LocalSidValueBlockJson, LocalSidValueBlock } from "./LocalSidValueBlock"; +import { IStringConvertible } from "../types"; + + +export interface ILocalObjectIdentifierValueBlock { + value: string; +} + +export interface LocalObjectIdentifierValueBlockParams extends ValueBlockParams, Partial { } + +export interface LocalObjectIdentifierValueBlockJson extends ValueBlockJson, ILocalObjectIdentifierValueBlock { + sidArray: LocalSidValueBlockJson[]; +} + +export class LocalObjectIdentifierValueBlock extends ValueBlock implements IStringConvertible { + + public static override NAME = "ObjectIdentifierValueBlock"; + + public value: LocalSidValueBlock[] = []; + + constructor({ + value = EMPTY_STRING, + ...parameters + }: LocalObjectIdentifierValueBlockParams = {}) { + super(parameters); + + if (value) { + this.fromString(value); + } + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + let resultOffset = inputOffset; + + while (inputLength > 0) { + const sidBlock = new LocalSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === -1) { + this.blockLength = 0; + this.error = sidBlock.error; + + return resultOffset; + } + + if (this.value.length === 0) + sidBlock.isFirstSid = true; + + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + + this.value.push(sidBlock); + } + + return resultOffset; + } + public override toBER(sizeOnly?: boolean): ArrayBuffer { + const retBuffers: ArrayBuffer[] = []; + + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) { + this.error = this.value[i].error; + + return EMPTY_BUFFER; + } + + retBuffers.push(valueBuf); + } + + return utils.concat(retBuffers); + } + + public fromString(string: string): void { + this.value = []; // Clear existing SID values + + let pos1 = 0; + let pos2 = 0; + + let sid = ""; + + let flag = false; + + // const sids = string.split("."); + // for (const sid of sids) { + + // } + do { + pos2 = string.indexOf(".", pos1); + if (pos2 === -1) + sid = string.substring(pos1); + + else + sid = string.substring(pos1, pos2); + + pos1 = pos2 + 1; + + if (flag) { + const sidBlock = this.value[0]; + + let plus = 0; + + switch (sidBlock.valueDec) { + case 0: + break; + case 1: + plus = 40; + break; + case 2: + plus = 80; + break; + default: + this.value = []; // clear SID array + + return; + } + + const parsedSID = parseInt(sid, 10); + if (isNaN(parsedSID)) + return; + + sidBlock.valueDec = parsedSID + plus; + + flag = false; + } else { + const sidBlock = new LocalSidValueBlock(); + if ((sid as any) > Number.MAX_SAFE_INTEGER) { // TODO remove as any + utils.assertBigInt(); + const sidValue = BigInt(sid); + sidBlock.valueBigInt = sidValue; + } else { + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) + return; + } + + if (!this.value.length) { + sidBlock.isFirstSid = true; + flag = true; + } + + this.value.push(sidBlock); + } + } while (pos2 !== -1); + } + + public override toString(): string { + let result = ""; + let isHexOnly = false; + + for (let i = 0; i < this.value.length; i++) { + isHexOnly = this.value[i].isHexOnly; + + let sidStr = this.value[i].toString(); + + if (i !== 0) + result = `${result}.`; + + if (isHexOnly) { + sidStr = `{${sidStr}}`; + + if (this.value[i].isFirstSid) + result = `2.{${sidStr} - 80}`; + + else + result += sidStr; + } + + else + result += sidStr; + } + + return result; + } + + public override toJSON(): LocalObjectIdentifierValueBlockJson { + const object: LocalObjectIdentifierValueBlockJson = { + ...super.toJSON(), + value: this.toString(), + sidArray: [], + }; + + for (let i = 0; i < this.value.length; i++) { + object.sidArray.push(this.value[i].toJSON()); + } + + return object; + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalOctetStringValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalOctetStringValueBlock.ts new file mode 100644 index 0000000000..fb2dfd562b --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalOctetStringValueBlock.ts @@ -0,0 +1,103 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { ViewWriter } from "../ViewWriter"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { END_OF_CONTENT_NAME, OCTET_STRING_NAME } from "./constants"; +import { LocalConstructedValueBlockParams, LocalConstructedValueBlockJson, LocalConstructedValueBlock } from "./LocalConstructedValueBlock"; +import type { OctetString } from "../OctetString"; + +export interface ILocalOctetStringValueBlock { + isConstructed: boolean; +} + +export interface LocalOctetStringValueBlockParams extends HexBlockParams, LocalConstructedValueBlockParams, Partial { + value?: OctetString[]; +} + +export interface LocalOctetStringValueBlockJson extends HexBlockJson, LocalConstructedValueBlockJson, ILocalOctetStringValueBlock { } + +export class LocalOctetStringValueBlock extends HexBlock(LocalConstructedValueBlock) { + + public static override NAME = "OctetStringValueBlock"; + + public isConstructed: boolean; + + constructor({ + isConstructed = false, + ...parameters + }: LocalOctetStringValueBlockParams = {}) { + super(parameters); + + this.isConstructed = isConstructed; + } + + public override fromBER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number): number { + let resultOffset = 0; + + if (this.isConstructed) { + this.isHexOnly = false; + + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) + return resultOffset; + + for (let i = 0; i < this.value.length; i++) { + const currentBlockName = (this.value[i].constructor as typeof LocalOctetStringValueBlock).NAME; + + if (currentBlockName === END_OF_CONTENT_NAME) { + if (this.isIndefiniteForm) + break; + else { + this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only"; + + return -1; + } + } + + if (currentBlockName !== OCTET_STRING_NAME) { + this.error = "OCTET STRING may consists of OCTET STRINGs only"; + + return -1; + } + } + } else { + this.isHexOnly = true; + + resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + this.blockLength = inputLength; + } + + return resultOffset; + } + + public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + if (this.isConstructed) + return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer); + + return sizeOnly + ? new ArrayBuffer(this.valueHexView.byteLength) + : this.valueHexView.slice().buffer; + } + + public override toJSON(): LocalOctetStringValueBlockJson { + return { + ...super.toJSON(), + isConstructed: this.isConstructed, + } as LocalOctetStringValueBlockJson; + } + +} + +export interface LocalOctetStringValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalPrimitiveValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalPrimitiveValueBlock.ts new file mode 100644 index 0000000000..7fe2408b96 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalPrimitiveValueBlock.ts @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { HexBlock, HexBlockJson, HexBlockParams } from "../HexBlock"; +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; + +export interface LocalPrimitiveValueBlockParams extends HexBlockParams, ValueBlockParams { } +export interface LocalPrimitiveValueBlockJson extends HexBlockJson, ValueBlockJson { } + +export class LocalPrimitiveValueBlock extends HexBlock(ValueBlock) { + + public static override NAME = "PrimitiveValueBlock"; + + constructor({ + isHexOnly = true, + ...parameters + }: LocalPrimitiveValueBlockParams = {}) { + super(parameters); + + this.isHexOnly = isHexOnly; + } + +} + +export interface LocalPrimitiveValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalRelativeObjectIdentifierValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalRelativeObjectIdentifierValueBlock.ts new file mode 100644 index 0000000000..13237f50ec --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalRelativeObjectIdentifierValueBlock.ts @@ -0,0 +1,140 @@ +import { ViewWriter } from "../ViewWriter"; +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { EMPTY_BUFFER, EMPTY_STRING } from "./constants"; +import * as utils from "./utils"; +import { LocalRelativeSidValueBlockJson, LocalRelativeSidValueBlock } from "./LocalRelativeSidValueBlock"; +import { IStringConvertible } from "../types"; + +export interface ILocalRelativeObjectIdentifierValueBlock { + value: string; +} + +export interface LocalRelativeObjectIdentifierValueBlockParams extends ValueBlockParams, Partial { } + +export interface LocalRelativeObjectIdentifierValueBlockJson extends ValueBlockJson, ILocalRelativeObjectIdentifierValueBlock { + sidArray: LocalRelativeSidValueBlockJson[]; +} + +export class LocalRelativeObjectIdentifierValueBlock extends ValueBlock implements IStringConvertible { + + public static override NAME = "RelativeObjectIdentifierValueBlock"; + + public value: LocalRelativeSidValueBlock[] = []; + + constructor({ + value = EMPTY_STRING, + ...parameters + }: LocalRelativeObjectIdentifierValueBlockParams = {}) { + super(parameters); + + if (value) { + this.fromString(value); + } + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + let resultOffset = inputOffset; + + while (inputLength > 0) { + const sidBlock = new LocalRelativeSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === -1) { + this.blockLength = 0; + this.error = sidBlock.error; + + return resultOffset; + } + + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + + this.value.push(sidBlock); + } + + return resultOffset; + } + + public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer { + const retBuffers: ArrayBuffer[] = []; + + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) { + this.error = this.value[i].error; + + return EMPTY_BUFFER; + } + + retBuffers.push(valueBuf); + } + + return utils.concat(retBuffers); + } + + public fromString(string: string): boolean { + this.value = []; // Clear existing SID values + + let pos1 = 0; + let pos2 = 0; + + let sid = ""; + + do { + pos2 = string.indexOf(".", pos1); + if (pos2 === -1) + sid = string.substring(pos1); + + else + sid = string.substring(pos1, pos2); + + pos1 = pos2 + 1; + + const sidBlock = new LocalRelativeSidValueBlock(); + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) + return true; + + this.value.push(sidBlock); + + } while (pos2 !== -1); + + return true; + } + + public override toString(): string { + let result = ""; + let isHexOnly = false; + + for (let i = 0; i < this.value.length; i++) { + isHexOnly = this.value[i].isHexOnly; + + let sidStr = this.value[i].toString(); + + if (i !== 0) + result = `${result}.`; + + if (isHexOnly) { + sidStr = `{${sidStr}}`; + result += sidStr; + } + else + result += sidStr; + } + + return result; + } + + public override toJSON(): LocalRelativeObjectIdentifierValueBlockJson { + const object: LocalRelativeObjectIdentifierValueBlockJson = { + ...super.toJSON(), + value: this.toString(), + sidArray: [], + }; + + for (let i = 0; i < this.value.length; i++) + object.sidArray.push(this.value[i].toJSON()); + + return object; + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalRelativeSidValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalRelativeSidValueBlock.ts new file mode 100644 index 0000000000..3a10c617aa --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalRelativeSidValueBlock.ts @@ -0,0 +1,140 @@ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { LocalBaseBlock } from "./LocalBaseBlock"; +import { EMPTY_BUFFER } from "./constants"; +import { checkBufferParams } from "./utils"; + +export interface ILocalRelativeSidValueBlock { + valueDec: number; +} + +export interface LocalRelativeSidValueBlockParams extends HexBlockParams, ValueBlockParams, Partial { } + +export interface LocalRelativeSidValueBlockJson extends HexBlockJson, ValueBlockJson, ILocalRelativeSidValueBlock { } + +export class LocalRelativeSidValueBlock extends HexBlock(LocalBaseBlock) implements ILocalRelativeSidValueBlock { + + public static override NAME = "relativeSidBlock"; + + public valueDec: number; + + constructor({ + valueDec = 0, + ...parameters + }: LocalRelativeSidValueBlockParams = {}) { + super(parameters); + + this.valueDec = valueDec; + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + if (inputLength === 0) + return inputOffset; + + const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + + // Basic check for parameters + if (!checkBufferParams(this, inputView, inputOffset, inputLength)) + return -1; + + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + + this.valueHexView = new Uint8Array(inputLength); + + for (let i = 0; i < inputLength; i++) { + this.valueHexView[i] = intBuffer[i] & 0x7F; + + this.blockLength++; + + if ((intBuffer[i] & 0x80) === 0x00) + break; + } + + //#region Adjust size of valueHex buffer + const tempView = new Uint8Array(this.blockLength); + + for (let i = 0; i < this.blockLength; i++) + tempView[i] = this.valueHexView[i]; + + this.valueHexView = tempView; + //#endregion + if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) { + this.error = "End of input reached before message was fully decoded"; + + return -1; + } + + if (this.valueHexView[0] === 0x00) + this.warnings.push("Needlessly long format of SID encoding"); + + if (this.blockLength <= 8) + this.valueDec = pvutils.utilFromBase(this.valueHexView, 7); + else { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return (inputOffset + this.blockLength); + } + + public override toBER(sizeOnly?: boolean): ArrayBuffer { + if (this.isHexOnly) { + if (sizeOnly) + return (new ArrayBuffer(this.valueHexView.byteLength)); + + const curView = this.valueHexView; + + const retView = new Uint8Array(this.blockLength); + + for (let i = 0; i < (this.blockLength - 1); i++) + retView[i] = curView[i] | 0x80; + + retView[this.blockLength - 1] = curView[this.blockLength - 1]; + + return retView.buffer; + } + + const encodedBuf = pvutils.utilToBase(this.valueDec, 7); + if (encodedBuf.byteLength === 0) { + this.error = "Error during encoding SID value"; + + return EMPTY_BUFFER; + } + + const retView = new Uint8Array(encodedBuf.byteLength); + + if (!sizeOnly) { + const encodedView = new Uint8Array(encodedBuf); + const len = encodedBuf.byteLength - 1; + + for (let i = 0; i < len; i++) + retView[i] = encodedView[i] | 0x80; + + retView[len] = encodedView[len]; + } + + return retView.buffer; + } + + public override toString(): string { + let result = ""; + + if (this.isHexOnly) + result = pvtsutils.Convert.ToHex(this.valueHexView); + else { + result = this.valueDec.toString(); + } + + return result; + } + + public override toJSON(): LocalRelativeSidValueBlockJson { + return { + ...super.toJSON(), + valueDec: this.valueDec, + }; + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalSidValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalSidValueBlock.ts new file mode 100644 index 0000000000..a9a45ba359 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalSidValueBlock.ts @@ -0,0 +1,197 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as pvtsutils from "pvtsutils"; +import * as pvutils from "pvutils"; +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { EMPTY_BUFFER } from "./constants"; +import * as utils from "./utils"; + +export interface ILocalSidValueBlock { + valueDec: number; + isFirstSid: boolean; +} + +export interface LocalSidValueBlockParams extends HexBlockParams, ValueBlockParams, Partial { } + +export interface LocalSidValueBlockJson extends HexBlockJson, ValueBlockJson, ILocalSidValueBlock { } + +export class LocalSidValueBlock extends HexBlock(ValueBlock) implements ILocalSidValueBlock { + + public static override NAME = "sidBlock"; + + public valueDec: number; + public isFirstSid: boolean; + + constructor({ + valueDec = -1, + isFirstSid = false, + ...parameters + }: LocalSidValueBlockParams = {}) { + super(parameters); + + this.valueDec = valueDec; + this.isFirstSid = isFirstSid; + } + + public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number { + if (!inputLength) { + return inputOffset; + } + const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + + // Basic check for parameters + if (!utils.checkBufferParams(this, inputView, inputOffset, inputLength)) { + return -1; + } + + const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength); + + this.valueHexView = new Uint8Array(inputLength); + + for (let i = 0; i < inputLength; i++) { + this.valueHexView[i] = intBuffer[i] & 0x7F; + + this.blockLength++; + + if ((intBuffer[i] & 0x80) === 0x00) + break; + } + + //#region Adjust size of valueHex buffer + const tempView = new Uint8Array(this.blockLength); + + for (let i = 0; i < this.blockLength; i++) { + tempView[i] = this.valueHexView[i]; + } + + this.valueHexView = tempView; + //#endregion + + if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) { + this.error = "End of input reached before message was fully decoded"; + + return -1; + } + + if (this.valueHexView[0] === 0x00) + this.warnings.push("Needlessly long format of SID encoding"); + + if (this.blockLength <= 8) + this.valueDec = pvutils.utilFromBase(this.valueHexView, 7); + else { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return (inputOffset + this.blockLength); + } + + public set valueBigInt(value: bigint) { + + utils.assertBigInt(); + + let bits = BigInt(value).toString(2); + while (bits.length % 7) { + bits = "0" + bits; + } + const bytes = new Uint8Array(bits.length / 7); + for (let i = 0; i < bytes.length; i++) { + bytes[i] = parseInt(bits.slice(i * 7, i * 7 + 7), 2) + (i + 1 < bytes.length ? 0x80 : 0); + } + this.fromBER(bytes.buffer, 0, bytes.length); + } + + public override toBER(sizeOnly?: boolean): ArrayBuffer { + if (this.isHexOnly) { + if (sizeOnly) + return (new ArrayBuffer(this.valueHexView.byteLength)); + + const curView = this.valueHexView; + const retView = new Uint8Array(this.blockLength); + + for (let i = 0; i < (this.blockLength - 1); i++) + retView[i] = curView[i] | 0x80; + + retView[this.blockLength - 1] = curView[this.blockLength - 1]; + + return retView.buffer; + } + + const encodedBuf = pvutils.utilToBase(this.valueDec, 7); + if (encodedBuf.byteLength === 0) { + this.error = "Error during encoding SID value"; + + return EMPTY_BUFFER; + } + + const retView = new Uint8Array(encodedBuf.byteLength); + + if (!sizeOnly) { + const encodedView = new Uint8Array(encodedBuf); + const len = encodedBuf.byteLength - 1; + + for (let i = 0; i < len; i++) + retView[i] = encodedView[i] | 0x80; + + retView[len] = encodedView[len]; + } + + return retView; + } + + public override toString(): string { + let result = ""; + + if (this.isHexOnly) + result = pvtsutils.Convert.ToHex(this.valueHexView); + else { + if (this.isFirstSid) { + let sidValue = this.valueDec; + + if (this.valueDec <= 39) + result = "0."; + else { + if (this.valueDec <= 79) { + result = "1."; + sidValue -= 40; + } + else { + result = "2."; + sidValue -= 80; + } + } + + result += sidValue.toString(); + } + + else + result = this.valueDec.toString(); + } + + return result; + } + + public override toJSON(): LocalSidValueBlockJson { + return { + ...super.toJSON(), + valueDec: this.valueDec, + isFirstSid: this.isFirstSid, + }; + } + +} + +export interface LocalSidValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalSimpleStringBlock.ts b/comm/third_party/asn1js/src/internals/LocalSimpleStringBlock.ts new file mode 100644 index 0000000000..a52c9e2898 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalSimpleStringBlock.ts @@ -0,0 +1,34 @@ +import * as pvtsutils from "pvtsutils"; +import { BaseBlockParams } from "../BaseBlock"; +import { BaseStringBlock } from "../BaseStringBlock"; +import { LocalSimpleStringValueBlock, LocalSimpleStringValueBlockJson, LocalSimpleStringValueBlockParams } from "./LocalSimpleStringValueBlock"; + +export interface LocalSimpleStringBlockParams extends BaseBlockParams, LocalSimpleStringValueBlockParams { } +export type LocalSimpleStringBlockJson = LocalSimpleStringValueBlockJson; + +export class LocalSimpleStringBlock extends BaseStringBlock { + + public static override NAME = "SIMPLE STRING"; + + constructor({ + ...parameters + }: LocalSimpleStringBlockParams = {}) { + super(parameters, LocalSimpleStringValueBlock); + } + + public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void { + this.valueBlock.value = String.fromCharCode.apply(null, pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer) as unknown as number[]); + } + + public fromString(inputString: string): void { + const strLen = inputString.length; + + const view = this.valueBlock.valueHexView = new Uint8Array(strLen); + + for (let i = 0; i < strLen; i++) + view[i] = inputString.charCodeAt(i); + + this.valueBlock.value = inputString; + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalSimpleStringValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalSimpleStringValueBlock.ts new file mode 100644 index 0000000000..f2ee09a8a3 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalSimpleStringValueBlock.ts @@ -0,0 +1,11 @@ +import { ILocalStringValueBlock, LocalStringValueBlockParams, LocalStringValueBlockJson, LocalStringValueBlock } from "./LocalStringValueBlock"; + +export type ILocalSimpleStringValueBlock = ILocalStringValueBlock; +export type LocalSimpleStringValueBlockParams = LocalStringValueBlockParams; +export type LocalSimpleStringValueBlockJson = LocalStringValueBlockJson; + +export class LocalSimpleStringValueBlock extends LocalStringValueBlock { + + public static override NAME = "SimpleStringValueBlock"; + +} diff --git a/comm/third_party/asn1js/src/internals/LocalStringValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalStringValueBlock.ts new file mode 100644 index 0000000000..dfd0ee19e3 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalStringValueBlock.ts @@ -0,0 +1,52 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock"; +import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock"; +import { EMPTY_STRING } from "./constants"; +import { LocalUtf8StringValueBlockParams, LocalUtf8StringValueBlockJson } from "./LocalUtf8StringValueBlock"; + +export interface ILocalStringValueBlock { + value: string; +} + +export interface LocalStringValueBlockParams extends Omit, ValueBlockParams, Partial { } + +export interface LocalStringValueBlockJson extends HexBlockJson, ValueBlockJson, ILocalStringValueBlock { } + +export abstract class LocalStringValueBlock extends HexBlock(ValueBlock) implements ILocalStringValueBlock { + + public static override NAME = "StringValueBlock"; + + public value: string; + + constructor({ + ...parameters + }: LocalUtf8StringValueBlockParams = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = EMPTY_STRING; // String representation of decoded ArrayBuffer + } + + public override toJSON(): LocalUtf8StringValueBlockJson { + return { + ...super.toJSON(), + value: this.value, + }; + } + +} + +export interface LocalStringValueBlock { + /** + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueBeforeDecode: ArrayBuffer; + /** + * Binary data in ArrayBuffer representation + * + * @deprecated since version 3.0.0 + */ + // @ts-ignore + valueHex: ArrayBuffer; +} diff --git a/comm/third_party/asn1js/src/internals/LocalUniversalStringValueBlockParams.ts b/comm/third_party/asn1js/src/internals/LocalUniversalStringValueBlockParams.ts new file mode 100644 index 0000000000..6b3b09359a --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalUniversalStringValueBlockParams.ts @@ -0,0 +1,45 @@ +import * as pvutils from "pvutils"; +import { LocalSimpleStringBlock, LocalSimpleStringBlockJson, LocalSimpleStringBlockParams } from "./LocalSimpleStringBlock"; + +export type LocalUniversalStringValueBlockParams = LocalSimpleStringBlockParams; +export type LocalUniversalStringValueBlockJson = LocalSimpleStringBlockJson; + +export class LocalUniversalStringValueBlock extends LocalSimpleStringBlock { + + public static override NAME = "UniversalStringValueBlock"; + + public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void { + const copyBuffer = ArrayBuffer.isView(inputBuffer) ? inputBuffer.slice().buffer : inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for (let i = 0; i < valueView.length; i += 4) { + valueView[i] = valueView[i + 3]; + valueView[i + 1] = valueView[i + 2]; + valueView[i + 2] = 0x00; + valueView[i + 3] = 0x00; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer) as unknown as number[]); + } + + public override fromString(inputString: string): void { + const strLength = inputString.length; + + const valueHexView = this.valueBlock.valueHexView = new Uint8Array(strLength * 4); + + for (let i = 0; i < strLength; i++) { + const codeBuf = pvutils.utilToBase(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if (codeView.length > 4) + continue; + + const dif = 4 - codeView.length; + + for (let j = (codeView.length - 1); j >= 0; j--) + valueHexView[i * 4 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + +} diff --git a/comm/third_party/asn1js/src/internals/LocalUtf8StringValueBlock.ts b/comm/third_party/asn1js/src/internals/LocalUtf8StringValueBlock.ts new file mode 100644 index 0000000000..7d578d8950 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalUtf8StringValueBlock.ts @@ -0,0 +1,27 @@ +import * as pvtsutils from "pvtsutils"; +import { LocalSimpleStringBlock, LocalSimpleStringBlockJson, LocalSimpleStringBlockParams } from "./LocalSimpleStringBlock"; + +export type LocalUtf8StringValueBlockParams = LocalSimpleStringBlockParams; +export type LocalUtf8StringValueBlockJson = LocalSimpleStringBlockJson; + +export class LocalUtf8StringValueBlock extends LocalSimpleStringBlock { + + public static override NAME = "Utf8StringValueBlock"; + + public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void { + this.valueBlock.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer); + try { + this.valueBlock.value = pvtsutils.Convert.ToUtf8String(inputBuffer); + } + catch (ex) { + this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`); + this.valueBlock.value = pvtsutils.Convert.ToBinary(inputBuffer); + } + } + + public override fromString(inputString: string): void { + this.valueBlock.valueHexView = new Uint8Array(pvtsutils.Convert.FromUtf8String(inputString)); + this.valueBlock.value = inputString; + } + +} diff --git a/comm/third_party/asn1js/src/internals/constants.ts b/comm/third_party/asn1js/src/internals/constants.ts new file mode 100644 index 0000000000..beb0bd9eb8 --- /dev/null +++ b/comm/third_party/asn1js/src/internals/constants.ts @@ -0,0 +1,20 @@ +// Declaration of global variables + +export const powers2 = [new Uint8Array([1])]; +export const digitsString = "0123456789"; +export const NAME = "name"; +export const VALUE_HEX_VIEW = "valueHexView"; +export const IS_HEX_ONLY = "isHexOnly"; +export const ID_BLOCK = "idBlock"; +export const TAG_CLASS = "tagClass"; +export const TAG_NUMBER = "tagNumber"; +export const IS_CONSTRUCTED = "isConstructed"; +export const FROM_BER = "fromBER"; +export const TO_BER = "toBER"; +export const LOCAL = "local"; +export const EMPTY_STRING = ""; +export const EMPTY_BUFFER = new ArrayBuffer(0); +export const EMPTY_VIEW = new Uint8Array(0); +export const END_OF_CONTENT_NAME = "EndOfContent"; +export const OCTET_STRING_NAME = "OCTET STRING"; +export const BIT_STRING_NAME = "BIT STRING"; diff --git a/comm/third_party/asn1js/src/internals/utils.ts b/comm/third_party/asn1js/src/internals/utils.ts new file mode 100644 index 0000000000..84d1f3164f --- /dev/null +++ b/comm/third_party/asn1js/src/internals/utils.ts @@ -0,0 +1,81 @@ +// Utility functions + +import type { LocalBaseBlock } from "./LocalBaseBlock"; + +/** + * Throws an exception if BigInt is not supported + * @throws Throws Error if BigInt is not supported + */ +export function assertBigInt(): void { + if (typeof BigInt === "undefined") { + throw new Error("BigInt is not defined. Your environment doesn't implement BigInt."); + } +} + +/** + * Concatenates buffers from the list + * @param buffers List of buffers + * @returns Concatenated buffer + */ +export function concat(buffers: ArrayBuffer[]): ArrayBuffer { + let outputLength = 0; + let prevLength = 0; + + // Calculate output length + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + outputLength += buffer.byteLength; + } + + const retView = new Uint8Array(outputLength); + + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + retView.set(new Uint8Array(buffer), prevLength); + prevLength += buffer.byteLength; + } + + return retView.buffer; +} + +/** + * Check input "Uint8Array" for common functions + * @param baseBlock + * @param inputBuffer + * @param inputOffset + * @param inputLength + * @returns + */ +export function checkBufferParams(baseBlock: LocalBaseBlock, inputBuffer: Uint8Array, inputOffset: number, inputLength: number): boolean { + if (!(inputBuffer instanceof Uint8Array)) { + baseBlock.error = "Wrong parameter: inputBuffer must be 'Uint8Array'"; + + return false; + } + + if (!inputBuffer.byteLength) { + baseBlock.error = "Wrong parameter: inputBuffer has zero length"; + + return false; + } + + if (inputOffset < 0) { + baseBlock.error = "Wrong parameter: inputOffset less than zero"; + + return false; + } + + if (inputLength < 0) { + baseBlock.error = "Wrong parameter: inputLength less than zero"; + + return false; + } + + if ((inputBuffer.byteLength - inputOffset - inputLength) < 0) { + baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + + return false; + } + + return true; +} \ No newline at end of file diff --git a/comm/third_party/asn1js/src/parser.ts b/comm/third_party/asn1js/src/parser.ts new file mode 100644 index 0000000000..51ab7dfcd8 --- /dev/null +++ b/comm/third_party/asn1js/src/parser.ts @@ -0,0 +1,301 @@ +import * as pvtsutils from "pvtsutils"; +import { ValueBlock } from "./ValueBlock"; +import { BaseBlock } from "./BaseBlock"; +import { LocalBaseBlock } from "./internals/LocalBaseBlock"; +import { AsnType, typeStore } from "./TypeStore"; +import { checkBufferParams } from "./internals/utils"; + +export interface FromBerResult { + offset: number; + result: AsnType; +} + +/** + * Local function changing a type for ASN.1 classes + * @param inputObject Incoming object + * @param newType Target type to convert + * @returns Converted object + */ +function localChangeType(inputObject: BaseBlock, newType: new () => T): T { + if (inputObject instanceof newType) { + return inputObject; + } + + const newObject = new newType(); + newObject.idBlock = inputObject.idBlock; + newObject.lenBlock = inputObject.lenBlock; + newObject.warnings = inputObject.warnings; + newObject.valueBeforeDecodeView = inputObject.valueBeforeDecodeView; + + return newObject; +} + +/** + * Internal library function for decoding ASN.1 BER + * @param inputBuffer ASN.1 BER encoded array + * @param inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param inputLength Maximum length of array of bytes which can be using in this function + * @returns + */ +export function localFromBER(inputBuffer: Uint8Array, inputOffset = 0, inputLength = inputBuffer.length): FromBerResult { + const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function + + // Create a basic ASN.1 type since we need to return errors and warnings from the function + let returnObject = new BaseBlock({}, ValueBlock); + + // Basic check for parameters + const baseBlock = new LocalBaseBlock(); + if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) { + returnObject.error = baseBlock.error; + + return { + offset: -1, + result: returnObject + }; + } + + // Getting Uint8Array subarray + const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength); + + // Initial checks + if (!intBuffer.length) { + returnObject.error = "Zero buffer length"; + + return { + offset: -1, + result: returnObject + }; + } + + // Decode identification block of ASN.1 BER structure + // console.time("idBlock"); + let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength); + if (returnObject.idBlock.warnings.length) { + returnObject.warnings.concat(returnObject.idBlock.warnings); + } + if (resultOffset === -1) { + returnObject.error = returnObject.idBlock.error; + + return { + offset: -1, + result: returnObject + }; + } + // console.timeEnd("idBlock"); + + inputOffset = resultOffset; + inputLength -= returnObject.idBlock.blockLength; + + // Decode length block of ASN.1 BER structure + // console.time("lengthBlock"); + resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength); + if (returnObject.lenBlock.warnings.length) { + returnObject.warnings.concat(returnObject.lenBlock.warnings); + } + if (resultOffset === -1) { + returnObject.error = returnObject.lenBlock.error; + + return { + offset: -1, + result: returnObject + }; + } + // console.timeEnd("lengthBlock"); + + inputOffset = resultOffset; + inputLength -= returnObject.lenBlock.blockLength; + + // Check for using indefinite length form in encoding for primitive types + if (!returnObject.idBlock.isConstructed && + returnObject.lenBlock.isIndefiniteForm) { + returnObject.error = "Indefinite length form used for primitive encoding form"; + + return { + offset: -1, + result: returnObject + }; + } + + // Switch ASN.1 block type + let newASN1Type: new () => AsnType = BaseBlock as any; + + switch (returnObject.idBlock.tagClass) { + // UNIVERSAL + case 1: + // Check for reserved tag numbers + if ((returnObject.idBlock.tagNumber >= 37) && + (returnObject.idBlock.isHexOnly === false)) { + returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard"; + + return { + offset: -1, + result: returnObject + }; + } + switch (returnObject.idBlock.tagNumber) { + case 0: // EndOfContent + // Check for EndOfContent type + if ((returnObject.idBlock.isConstructed) && + (returnObject.lenBlock.length > 0)) { + returnObject.error = "Type [UNIVERSAL 0] is reserved"; + + return { + offset: -1, + result: returnObject + }; + } + + newASN1Type = typeStore.EndOfContent; + + break; + case 1: // Boolean + newASN1Type = typeStore.Boolean; + break; + case 2: // Integer + newASN1Type = typeStore.Integer; + break; + case 3: // BitString + newASN1Type = typeStore.BitString; + break; + case 4: // OctetString + newASN1Type = typeStore.OctetString; + break; + case 5: // Null + newASN1Type = typeStore.Null; + break; + case 6: // ObjectIdentifier + newASN1Type = typeStore.ObjectIdentifier; + break; + case 10: // Enumerated + newASN1Type = typeStore.Enumerated; + break; + case 12: // Utf8String + newASN1Type = typeStore.Utf8String; + break; + case 13: // RelativeObjectIdentifier + newASN1Type = typeStore.RelativeObjectIdentifier; + break; + case 14: // TIME + newASN1Type = typeStore.TIME; + break; + case 15: + returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + + return { + offset: -1, + result: returnObject + }; + case 16: // Sequence + newASN1Type = typeStore.Sequence; + break; + case 17: // Set + newASN1Type = typeStore.Set; + break; + case 18: // NumericString + newASN1Type = typeStore.NumericString; + break; + case 19: // PrintableString + newASN1Type = typeStore.PrintableString; + break; + case 20: // TeletexString + newASN1Type = typeStore.TeletexString; + break; + case 21: // VideotexString + newASN1Type = typeStore.VideotexString; + break; + case 22: // IA5String + newASN1Type = typeStore.IA5String; + break; + case 23: // UTCTime + newASN1Type = typeStore.UTCTime; + break; + case 24: // GeneralizedTime + newASN1Type = typeStore.GeneralizedTime; + break; + case 25: // GraphicString + newASN1Type = typeStore.GraphicString; + break; + case 26: // VisibleString + newASN1Type = typeStore.VisibleString; + break; + case 27: // GeneralString + newASN1Type = typeStore.GeneralString; + break; + case 28: // UniversalString + newASN1Type = typeStore.UniversalString; + break; + case 29: // CharacterString + newASN1Type = typeStore.CharacterString; + break; + case 30: // BmpString + newASN1Type = typeStore.BmpString; + break; + case 31: // DATE + newASN1Type = typeStore.DATE; + break; + case 32: // TimeOfDay + newASN1Type = typeStore.TimeOfDay; + break; + case 33: // DateTime + newASN1Type = typeStore.DateTime; + break; + case 34: // Duration + newASN1Type = typeStore.Duration; + break; + default: { + const newObject = returnObject.idBlock.isConstructed + ? new typeStore.Constructed() + : new typeStore.Primitive(); + + newObject.idBlock = returnObject.idBlock; + newObject.lenBlock = returnObject.lenBlock; + newObject.warnings = returnObject.warnings; + + returnObject = newObject; + } + } + break; + // All other tag classes + case 2: // APPLICATION + case 3: // CONTEXT-SPECIFIC + case 4: // PRIVATE + default: { + newASN1Type = returnObject.idBlock.isConstructed + ? typeStore.Constructed + : typeStore.Primitive; + } + } + + + // Change type and perform BER decoding + returnObject = localChangeType(returnObject, newASN1Type); + // console.time("valueBlock"); + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length); + + // Coping incoming buffer for entire ASN.1 block + returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength); + // console.timeEnd("valueBlock"); + + return { + offset: resultOffset, + result: returnObject + }; +} + +/** + * Major function for decoding ASN.1 BER array into internal library structures + * @param inputBuffer ASN.1 BER encoded array of bytes + */ +export function fromBER(inputBuffer: pvtsutils.BufferSource): FromBerResult { + if (!inputBuffer.byteLength) { + const result = new BaseBlock({}, ValueBlock); + result.error = "Input buffer has zero length"; + + return { + offset: -1, + result + }; + } + + return localFromBER(pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer).slice(), 0, inputBuffer.byteLength); +} diff --git a/comm/third_party/asn1js/src/schema.ts b/comm/third_party/asn1js/src/schema.ts new file mode 100644 index 0000000000..4f07e92a13 --- /dev/null +++ b/comm/third_party/asn1js/src/schema.ts @@ -0,0 +1,475 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as pvtsutils from "pvtsutils"; +import { IS_CONSTRUCTED, EMPTY_STRING, NAME, ID_BLOCK, FROM_BER, TO_BER, TAG_CLASS, TAG_NUMBER, IS_HEX_ONLY, LOCAL, VALUE_HEX_VIEW } from "./internals/constants"; +import { Any } from "./Any"; +import { Choice } from "./Choice"; +import { Repeated } from "./Repeated"; +import { localFromBER } from "./parser"; +import { AsnType, typeStore } from "./TypeStore"; + +export type AsnSchemaType = AsnType | Any | Choice | Repeated; + +export interface CompareSchemaSuccess { + verified: true; + result: AsnType & { [key: string]: any; }; +} + +export interface CompareSchemaFail { + verified: false; + name?: string; + result: AsnType | { error: string; }; +} + +export type CompareSchemaResult = CompareSchemaSuccess | CompareSchemaFail; + +/** + * Compare of two ASN.1 object trees + * @param root Root of input ASN.1 object tree + * @param inputData Input ASN.1 object tree + * @param inputSchema Input ASN.1 schema to compare with + * @return Returns result of comparison + */ +export function compareSchema(root: AsnType, inputData: AsnType, inputSchema: AsnSchemaType): CompareSchemaResult { + //#region Special case for Choice schema element type + if (inputSchema instanceof Choice) { + const choiceResult = false; + + for (let j = 0; j < inputSchema.value.length; j++) { + const result = compareSchema(root, inputData, inputSchema.value[j]); + if (result.verified) { + return { + verified: true, + result: root + }; + } + } + + if (choiceResult === false) { + const _result: CompareSchemaResult = { + verified: false, + result: { + error: "Wrong values for Choice type" + }, + }; + + if (inputSchema.hasOwnProperty(NAME)) + _result.name = inputSchema.name; + + return _result; + } + } + //#endregion + //#region Special case for Any schema element type + if (inputSchema instanceof Any) { + //#region Add named component of ASN.1 schema + if (inputSchema.hasOwnProperty(NAME)) + (root as any)[inputSchema.name] = inputData; // TODO Such call may replace original field of the object (eg idBlock) + + + //#endregion + return { + verified: true, + result: root + }; + } + //#endregion + //#region Initial check + if ((root instanceof Object) === false) { + return { + verified: false, + result: { error: "Wrong root object" } + }; + } + + if ((inputData instanceof Object) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 data" } + }; + } + + if ((inputSchema instanceof Object) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if ((ID_BLOCK in inputSchema) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + //#endregion + //#region Comparing idBlock properties in ASN.1 data and ASN.1 schema + //#region Encode and decode ASN.1 schema idBlock + /// This encoding/decoding is necessary because could be an errors in schema definition + if ((FROM_BER in inputSchema.idBlock) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if ((TO_BER in inputSchema.idBlock) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const encodedId = inputSchema.idBlock.toBER(false); + if (encodedId.byteLength === 0) { + return { + verified: false, + result: { error: "Error encoding idBlock for ASN.1 schema" } + }; + } + + const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength); + if (decodedOffset === -1) { + return { + verified: false, + result: { error: "Error decoding idBlock for ASN.1 schema" } + }; + } + //#endregion + //#region tagClass + if (inputSchema.idBlock.hasOwnProperty(TAG_CLASS) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) { + return { + verified: false, + result: root + }; + } + //#endregion + //#region tagNumber + if (inputSchema.idBlock.hasOwnProperty(TAG_NUMBER) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) { + return { + verified: false, + result: root + }; + } + //#endregion + //#region isConstructed + if (inputSchema.idBlock.hasOwnProperty(IS_CONSTRUCTED) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) { + return { + verified: false, + result: root + }; + } + //#endregion + //#region isHexOnly + if (!(IS_HEX_ONLY in inputSchema.idBlock)) // Since 'isHexOnly' is an inherited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) { + return { + verified: false, + result: root + }; + } + //#endregion + //#region valueHex + if (inputSchema.idBlock.isHexOnly) { + if ((VALUE_HEX_VIEW in inputSchema.idBlock) === false) // Since 'valueHex' is an inherited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const schemaView = inputSchema.idBlock.valueHexView; + const asn1View = inputData.idBlock.valueHexView; + + if (schemaView.length !== asn1View.length) { + return { + verified: false, + result: root + }; + } + + for (let i = 0; i < schemaView.length; i++) { + if (schemaView[i] !== asn1View[1]) { + return { + verified: false, + result: root + }; + } + } + } + //#endregion + //#endregion + //#region Add named component of ASN.1 schema + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + (root as any)[inputSchema.name] = inputData; // TODO check field existence. If exists throw an error + } + //#endregion + //#region Getting next ASN.1 block for comparison + if (inputSchema instanceof typeStore.Constructed) { + // TODO not clear how it works for OctetString and BitString + //* if (inputSchema.idBlock.isConstructed) { + let admission = 0; + let result: CompareSchemaResult = { + verified: false, + result: { + error: "Unknown error", + } + }; + + let maxLength = inputSchema.valueBlock.value.length; + + if (maxLength > 0) { + if (inputSchema.valueBlock.value[0] instanceof Repeated) { + // @ts-ignore + maxLength = inputData.valueBlock.value.length; // TODO debug it + } + } + + //#region Special case when constructive value has no elements + if (maxLength === 0) { + return { + verified: true, + result: root + }; + } + //#endregion + //#region Special case when "inputData" has no values and "inputSchema" has all optional values + // @ts-ignore + // TODO debug it + if ((inputData.valueBlock.value.length === 0) && + (inputSchema.valueBlock.value.length !== 0)) { + let _optional = true; + + for (let i = 0; i < inputSchema.valueBlock.value.length; i++) + _optional = _optional && (inputSchema.valueBlock.value[i].optional || false); + + if (_optional) { + return { + verified: true, + result: root + }; + } + + //#region Delete early added name of block + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + delete (root as any)[inputSchema.name]; + } + //#endregion + root.error = "Inconsistent object length"; + + return { + verified: false, + result: root + }; + } + //#endregion + for (let i = 0; i < maxLength; i++) { + //#region Special case when there is an OPTIONAL element of ASN.1 schema at the end + // @ts-ignore + if ((i - admission) >= inputData.valueBlock.value.length) { + if (inputSchema.valueBlock.value[i].optional === false) { + const _result: CompareSchemaResult = { + verified: false, + result: root + }; + + root.error = "Inconsistent length between ASN.1 data and schema"; + + //#region Delete early added name of block + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) { + delete (root as any)[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //#endregion + + return _result; + } + } + + //#endregion + else { + //#region Special case for Repeated type of ASN.1 schema element + if (inputSchema.valueBlock.value[0] instanceof Repeated) { + // @ts-ignore + result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value); + if (result.verified === false) { + if (inputSchema.valueBlock.value[0].optional) + admission++; + else { + //#region Delete early added name of block + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + delete (root as any)[inputSchema.name]; + } + //#endregion + + return result; + } + } + + if ((NAME in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].name.length > 0)) { + let arrayRoot: Record = {}; + + if ((LOCAL in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].local)) + arrayRoot = inputData; + + else + arrayRoot = root; + + if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") + arrayRoot[inputSchema.valueBlock.value[0].name] = []; + + // @ts-ignore + arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]); + } + } + + //#endregion + else { + // @ts-ignore + result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]); + if (result.verified === false) { + if (inputSchema.valueBlock.value[i].optional) + admission++; + else { + //#region Delete early added name of block + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) + delete (root as any)[inputSchema.name]; + } + //#endregion + + return result; + } + } + } + } + } + + if (result.verified === false) // The situation may take place if last element is OPTIONAL and verification failed + { + const _result: CompareSchemaResult = { + verified: false, + result: root + }; + + //#region Delete early added name of block + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) { + delete (root as any)[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //#endregion + + return _result; + } + + return { + verified: true, + result: root + }; + } + //#endregion + //#region Ability to parse internal value for primitive-encoded value (value of OctetString, for example) + if (inputSchema.primitiveSchema && + (VALUE_HEX_VIEW in inputData.valueBlock)) { + //#region Decoding of raw ASN.1 data + const asn1 = localFromBER(inputData.valueBlock.valueHexView); + if (asn1.offset === -1) { + const _result: CompareSchemaResult = { + verified: false, + result: asn1.result + }; + + //#region Delete early added name of block + if (inputSchema.name) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING); + if (inputSchema.name) { + delete (root as any)[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //#endregion + + return _result; + } + //#endregion + + return compareSchema(root, asn1.result, inputSchema.primitiveSchema); + } + + return { + verified: true, + result: root + }; + //#endregion +} +/** + * ASN.1 schema verification for ArrayBuffer data + * @param inputBuffer Input BER-encoded ASN.1 data + * @param inputSchema Input ASN.1 schema to verify against to + * @return + */ + +export function verifySchema(inputBuffer: pvtsutils.BufferSource, inputSchema: AsnSchemaType): CompareSchemaResult { + //#region Initial check + if ((inputSchema instanceof Object) === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema type" } + }; + } + //#endregion + //#region Decoding of raw ASN.1 data + const asn1 = localFromBER(pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer)); + if (asn1.offset === -1) { + return { + verified: false, + result: asn1.result + }; + } + //#endregion + //#region Compare ASN.1 struct with input schema + + return compareSchema(asn1.result, asn1.result, inputSchema); + //#endregion +} diff --git a/comm/third_party/asn1js/src/types.ts b/comm/third_party/asn1js/src/types.ts new file mode 100644 index 0000000000..60b5ee414a --- /dev/null +++ b/comm/third_party/asn1js/src/types.ts @@ -0,0 +1,62 @@ + +export interface IBerConvertible { + + /** + * Base function for converting block from BER encoded array of bytes + * @param inputBuffer ASN.1 BER encoded array + * @param inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param inputLength Maximum length of array of bytes which can be using in this function + * @returns Offset after least decoded byte + */ + fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number; + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param sizeOnly Flag that we need only a size of encoding, not a real array of bytes + * @returns ASN.1 BER encoded array + */ + toBER(sizeOnly?: boolean): ArrayBuffer; +} + +export interface IDerConvertible { + /** + * Base function for converting block from DER encoded array of bytes + * @param inputBuffer ASN.1 DER encoded array + * @param inputOffset Offset in ASN.1 DER encoded array where decoding should be started + * @param inputLength Maximum length of array of bytes which can be using in this function + * @param expectedLength Expected length of converted VALUE_HEX buffer + * @returns Offset after least decoded byte + */ + fromDER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number, expectedLength?: number): number; + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (DER rules) + * @param sizeOnly Flag that we need only a size of encoding, not a real array of bytes + * @returns ASN.1 DER encoded array + */ + toDER(sizeOnly?: boolean): ArrayBuffer; +} + +export interface IStringConvertible { + /** + * Returns a string representation of an object + * @returns String representation of the class object + */ + toString(): string; + /** + * Creates a class object from the string + * @param data Input string to convert from + */ + fromString(data: string): void; +} + +export interface IDateConvertible { + /** + * Converts a class object into the JavaScrip Date Object + * @returns Date object + */ + toDate(): Date; + /** + * Creates a class object from the JavaScript Date object + * @param date Date object + */ + fromDate(date: Date): void; +} \ No newline at end of file diff --git a/comm/third_party/asn1js/tsconfig.json b/comm/third_party/asn1js/tsconfig.json new file mode 100644 index 0000000000..87c32e8273 --- /dev/null +++ b/comm/third_party/asn1js/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2019", + "module": "CommonJS", + "lib": [ + "ES2019" + ], + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "noErrorTruncation": true, + "experimentalDecorators": true + } +} \ No newline at end of file diff --git a/comm/third_party/asn1js/yarn.lock b/comm/third_party/asn1js/yarn.lock new file mode 100644 index 0000000000..25c091ea34 --- /dev/null +++ b/comm/third_party/asn1js/yarn.lock @@ -0,0 +1,2373 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + "integrity" "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==" + "resolved" "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz" + "version" "2.1.2" + dependencies: + "@jridgewell/trace-mapping" "^0.3.0" + +"@babel/code-frame@^7.16.7": + "integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz" + "version" "7.16.7" + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.17.7": + "integrity" "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==" + "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz" + "version" "7.17.7" + +"@babel/core@^7.0.0", "@babel/core@^7.7.5": + "integrity" "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==" + "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz" + "version" "7.17.9" + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.9" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.9" + "@babel/parser" "^7.17.9" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.9" + "@babel/types" "^7.17.0" + "convert-source-map" "^1.7.0" + "debug" "^4.1.0" + "gensync" "^1.0.0-beta.2" + "json5" "^2.2.1" + "semver" "^6.3.0" + +"@babel/generator@^7.17.9": + "integrity" "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz" + "version" "7.17.9" + dependencies: + "@babel/types" "^7.17.0" + "jsesc" "^2.5.1" + "source-map" "^0.5.0" + +"@babel/helper-compilation-targets@^7.17.7": + "integrity" "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==" + "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz" + "version" "7.17.7" + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-validator-option" "^7.16.7" + "browserslist" "^4.17.5" + "semver" "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7": + "integrity" "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==" + "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz" + "version" "7.16.7" + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.17.9": + "integrity" "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz" + "version" "7.17.9" + dependencies: + "@babel/template" "^7.16.7" + "@babel/types" "^7.17.0" + +"@babel/helper-hoist-variables@^7.16.7": + "integrity" "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==" + "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz" + "version" "7.16.7" + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.16.7": + "integrity" "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz" + "version" "7.16.7" + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.17.7": + "integrity" "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz" + "version" "7.17.7" + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + +"@babel/helper-simple-access@^7.17.7": + "integrity" "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==" + "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz" + "version" "7.17.7" + dependencies: + "@babel/types" "^7.17.0" + +"@babel/helper-split-export-declaration@^7.16.7": + "integrity" "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz" + "version" "7.16.7" + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + "integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz" + "version" "7.16.7" + +"@babel/helper-validator-option@^7.16.7": + "integrity" "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz" + "version" "7.16.7" + +"@babel/helpers@^7.17.9": + "integrity" "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==" + "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz" + "version" "7.17.9" + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.9" + "@babel/types" "^7.17.0" + +"@babel/highlight@^7.16.7": + "integrity" "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz" + "version" "7.17.9" + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" + +"@babel/parser@^7.16.7", "@babel/parser@^7.17.9": + "integrity" "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz" + "version" "7.17.9" + +"@babel/template@^7.16.7": + "integrity" "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz" + "version" "7.16.7" + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9": + "integrity" "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz" + "version" "7.17.9" + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.9" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.9" + "@babel/types" "^7.17.0" + "debug" "^4.1.0" + "globals" "^11.1.0" + +"@babel/types@^7.16.7", "@babel/types@^7.17.0": + "integrity" "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz" + "version" "7.17.0" + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + "to-fast-properties" "^2.0.0" + +"@cspotcode/source-map-consumer@0.8.0": + "integrity" "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==" + "resolved" "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz" + "version" "0.8.0" + +"@cspotcode/source-map-support@0.7.0": + "integrity" "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==" + "resolved" "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz" + "version" "0.7.0" + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@esbuild/linux-x64@0.17.6": + "integrity" "sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw==" + "resolved" "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.6.tgz" + "version" "0.17.6" + +"@eslint/eslintrc@^1.2.3": + "integrity" "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==" + "resolved" "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz" + "version" "1.2.3" + dependencies: + "ajv" "^6.12.4" + "debug" "^4.3.2" + "espree" "^9.3.2" + "globals" "^13.9.0" + "ignore" "^5.2.0" + "import-fresh" "^3.2.1" + "js-yaml" "^4.1.0" + "minimatch" "^3.1.2" + "strip-json-comments" "^3.1.1" + +"@humanwhocodes/config-array@^0.9.2": + "integrity" "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz" + "version" "0.9.5" + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + "debug" "^4.1.1" + "minimatch" "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + "integrity" "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + "version" "1.2.1" + +"@istanbuljs/load-nyc-config@^1.0.0": + "integrity" "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==" + "resolved" "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "camelcase" "^5.3.1" + "find-up" "^4.1.0" + "get-package-type" "^0.1.0" + "js-yaml" "^3.13.1" + "resolve-from" "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + "integrity" "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==" + "resolved" "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + "version" "0.1.3" + +"@jridgewell/resolve-uri@^3.0.3": + "integrity" "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==" + "resolved" "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz" + "version" "3.0.6" + +"@jridgewell/sourcemap-codec@^1.4.10": + "integrity" "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz" + "version" "1.4.11" + +"@jridgewell/trace-mapping@^0.3.0": + "integrity" "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==" + "resolved" "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + "version" "0.3.9" + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@nodelib/fs.scandir@2.1.5": + "integrity" "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + "version" "2.1.5" + dependencies: + "@nodelib/fs.stat" "2.0.5" + "run-parallel" "^1.1.9" + +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": + "integrity" "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + "version" "2.0.5" + +"@nodelib/fs.walk@^1.2.3": + "integrity" "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + "version" "1.2.8" + dependencies: + "@nodelib/fs.scandir" "2.1.5" + "fastq" "^1.6.0" + +"@rollup/pluginutils@^4.1.2": + "integrity" "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==" + "resolved" "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz" + "version" "4.2.1" + dependencies: + "estree-walker" "^2.0.1" + "picomatch" "^2.2.2" + +"@tsconfig/node10@^1.0.7": + "integrity" "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" + "resolved" "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz" + "version" "1.0.8" + +"@tsconfig/node12@^1.0.7": + "integrity" "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" + "resolved" "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz" + "version" "1.0.9" + +"@tsconfig/node14@^1.0.0": + "integrity" "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" + "resolved" "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz" + "version" "1.0.1" + +"@tsconfig/node16@^1.0.2": + "integrity" "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" + "resolved" "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz" + "version" "1.0.2" + +"@types/json-schema@^7.0.9": + "integrity" "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + "resolved" "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" + "version" "7.0.11" + +"@types/mocha@^9.1.1": + "integrity" "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==" + "resolved" "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz" + "version" "9.1.1" + +"@types/node@*", "@types/node@^17.0.32": + "integrity" "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" + "resolved" "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz" + "version" "17.0.32" + +"@types/resolve@0.0.8": + "integrity" "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==" + "resolved" "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz" + "version" "0.0.8" + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@^5.23.0": + "integrity" "sha512-hEcSmG4XodSLiAp1uxv/OQSGsDY6QN3TcRU32gANp+19wGE1QQZLRS8/GV58VRUoXhnkuJ3ZxNQ3T6Z6zM59DA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@typescript-eslint/scope-manager" "5.23.0" + "@typescript-eslint/type-utils" "5.23.0" + "@typescript-eslint/utils" "5.23.0" + "debug" "^4.3.2" + "functional-red-black-tree" "^1.0.1" + "ignore" "^5.1.8" + "regexpp" "^3.2.0" + "semver" "^7.3.5" + "tsutils" "^3.21.0" + +"@typescript-eslint/experimental-utils@^5.0.0": + "integrity" "sha512-rKxoCUtAHwEH6IcAoVpqipY6Th+YKW7WFspAKu0IFdbdKZpveFBeqxxE9Xn+GWikhq1o03V3VXbxIe+GdhggiQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.22.0.tgz" + "version" "5.22.0" + dependencies: + "@typescript-eslint/utils" "5.22.0" + +"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.23.0": + "integrity" "sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@typescript-eslint/scope-manager" "5.23.0" + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/typescript-estree" "5.23.0" + "debug" "^4.3.2" + +"@typescript-eslint/scope-manager@5.22.0": + "integrity" "sha512-yA9G5NJgV5esANJCO0oF15MkBO20mIskbZ8ijfmlKIvQKg0ynVKfHZ15/nhAJN5m8Jn3X5qkwriQCiUntC9AbA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.22.0.tgz" + "version" "5.22.0" + dependencies: + "@typescript-eslint/types" "5.22.0" + "@typescript-eslint/visitor-keys" "5.22.0" + +"@typescript-eslint/scope-manager@5.23.0": + "integrity" "sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/visitor-keys" "5.23.0" + +"@typescript-eslint/type-utils@5.23.0": + "integrity" "sha512-iuI05JsJl/SUnOTXA9f4oI+/4qS/Zcgk+s2ir+lRmXI+80D8GaGwoUqs4p+X+4AxDolPpEpVUdlEH4ADxFy4gw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@typescript-eslint/utils" "5.23.0" + "debug" "^4.3.2" + "tsutils" "^3.21.0" + +"@typescript-eslint/types@5.22.0": + "integrity" "sha512-T7owcXW4l0v7NTijmjGWwWf/1JqdlWiBzPqzAWhobxft0SiEvMJB56QXmeCQjrPuM8zEfGUKyPQr/L8+cFUBLw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.22.0.tgz" + "version" "5.22.0" + +"@typescript-eslint/types@5.23.0": + "integrity" "sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.23.0.tgz" + "version" "5.23.0" + +"@typescript-eslint/typescript-estree@5.22.0": + "integrity" "sha512-EyBEQxvNjg80yinGE2xdhpDYm41so/1kOItl0qrjIiJ1kX/L/L8WWGmJg8ni6eG3DwqmOzDqOhe6763bF92nOw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.22.0.tgz" + "version" "5.22.0" + dependencies: + "@typescript-eslint/types" "5.22.0" + "@typescript-eslint/visitor-keys" "5.22.0" + "debug" "^4.3.2" + "globby" "^11.0.4" + "is-glob" "^4.0.3" + "semver" "^7.3.5" + "tsutils" "^3.21.0" + +"@typescript-eslint/typescript-estree@5.23.0": + "integrity" "sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/visitor-keys" "5.23.0" + "debug" "^4.3.2" + "globby" "^11.0.4" + "is-glob" "^4.0.3" + "semver" "^7.3.5" + "tsutils" "^3.21.0" + +"@typescript-eslint/utils@5.22.0": + "integrity" "sha512-HodsGb037iobrWSUMS7QH6Hl1kppikjA1ELiJlNSTYf/UdMEwzgj0WIp+lBNb6WZ3zTwb0tEz51j0Wee3iJ3wQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.22.0.tgz" + "version" "5.22.0" + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.22.0" + "@typescript-eslint/types" "5.22.0" + "@typescript-eslint/typescript-estree" "5.22.0" + "eslint-scope" "^5.1.1" + "eslint-utils" "^3.0.0" + +"@typescript-eslint/utils@5.23.0": + "integrity" "sha512-dbgaKN21drqpkbbedGMNPCtRPZo1IOUr5EI9Jrrh99r5UW5Q0dz46RKXeSBoPV+56R6dFKpbrdhgUNSJsDDRZA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.23.0" + "@typescript-eslint/types" "5.23.0" + "@typescript-eslint/typescript-estree" "5.23.0" + "eslint-scope" "^5.1.1" + "eslint-utils" "^3.0.0" + +"@typescript-eslint/visitor-keys@5.22.0": + "integrity" "sha512-DbgTqn2Dv5RFWluG88tn0pP6Ex0ROF+dpDO1TNNZdRtLjUr6bdznjA6f/qNqJLjd2PgguAES2Zgxh/JzwzETDg==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.22.0.tgz" + "version" "5.22.0" + dependencies: + "@typescript-eslint/types" "5.22.0" + "eslint-visitor-keys" "^3.0.0" + +"@typescript-eslint/visitor-keys@5.23.0": + "integrity" "sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.23.0.tgz" + "version" "5.23.0" + dependencies: + "@typescript-eslint/types" "5.23.0" + "eslint-visitor-keys" "^3.0.0" + +"@ungap/promise-all-settled@1.1.2": + "integrity" "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" + "resolved" "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz" + "version" "1.1.2" + +"@yarn-tool/resolve-package@^1.0.40": + "integrity" "sha512-RJcBGTVywUqYGRtGkPSgJC/ozf0wK/xjUy66tXkbpL35U0o1oef4S0v23euxA/CiukqBWr2fRGtGY6FidESdTg==" + "resolved" "https://registry.npmjs.org/@yarn-tool/resolve-package/-/resolve-package-1.0.46.tgz" + "version" "1.0.46" + dependencies: + "pkg-dir" "< 6 >= 5" + "tslib" "^2.3.1" + "upath2" "^3.1.12" + +"acorn-jsx@^5.3.2": + "integrity" "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + "resolved" "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + "version" "5.3.2" + +"acorn-walk@^8.1.1": + "integrity" "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + "resolved" "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + "version" "8.2.0" + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^8.4.1", "acorn@^8.7.1": + "integrity" "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + "resolved" "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz" + "version" "8.7.1" + +"aggregate-error@^3.0.0": + "integrity" "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==" + "resolved" "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "clean-stack" "^2.0.0" + "indent-string" "^4.0.0" + +"ajv@^6.10.0", "ajv@^6.12.4": + "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" + "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + "version" "6.12.6" + dependencies: + "fast-deep-equal" "^3.1.1" + "fast-json-stable-stringify" "^2.0.0" + "json-schema-traverse" "^0.4.1" + "uri-js" "^4.2.2" + +"ansi-colors@4.1.1": + "integrity" "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + "resolved" "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" + "version" "4.1.1" + +"ansi-regex@^5.0.1": + "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + "version" "5.0.1" + +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" + dependencies: + "color-convert" "^1.9.0" + +"ansi-styles@^4.0.0", "ansi-styles@^4.1.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "color-convert" "^2.0.1" + +"anymatch@~3.1.2": + "integrity" "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==" + "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "normalize-path" "^3.0.0" + "picomatch" "^2.0.4" + +"append-transform@^2.0.0": + "integrity" "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==" + "resolved" "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "default-require-extensions" "^3.0.0" + +"archy@^1.0.0": + "integrity" "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + "resolved" "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz" + "version" "1.0.0" + +"arg@^4.1.0": + "integrity" "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + "resolved" "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + "version" "4.1.3" + +"argparse@^1.0.7": + "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "sprintf-js" "~1.0.2" + +"argparse@^2.0.1": + "integrity" "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + "version" "2.0.1" + +"array-union@^2.1.0": + "integrity" "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "resolved" "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + "version" "2.1.0" + +"asn1-test-suite@^1.0.2": + "integrity" "sha512-qerYt//ST6WaGu6gVT+Hpgnd7Dy/lptAN2AVbAOfaleoiuwbN/61z3USrGU03Yu5645xpgrXvCIuexi9i8m2aA==" + "resolved" "https://registry.npmjs.org/asn1-test-suite/-/asn1-test-suite-1.0.2.tgz" + "version" "1.0.2" + +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" + +"binary-extensions@^2.0.0": + "integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" + "version" "2.2.0" + +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" + dependencies: + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" + +"brace-expansion@^2.0.1": + "integrity" "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "balanced-match" "^1.0.0" + +"braces@^3.0.2", "braces@~3.0.2": + "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" + "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "fill-range" "^7.0.1" + +"browser-stdout@1.3.1": + "integrity" "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + "resolved" "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" + "version" "1.3.1" + +"browserslist@^4.17.5": + "integrity" "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==" + "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz" + "version" "4.20.3" + dependencies: + "caniuse-lite" "^1.0.30001332" + "electron-to-chromium" "^1.4.118" + "escalade" "^3.1.1" + "node-releases" "^2.0.3" + "picocolors" "^1.0.0" + +"builtin-modules@^3.1.0": + "integrity" "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==" + "resolved" "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz" + "version" "3.2.0" + +"caching-transform@^4.0.0": + "integrity" "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==" + "resolved" "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "hasha" "^5.0.0" + "make-dir" "^3.0.0" + "package-hash" "^4.0.0" + "write-file-atomic" "^3.0.0" + +"callsites@^3.0.0": + "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + "version" "3.1.0" + +"camelcase@^5.0.0", "camelcase@^5.3.1": + "integrity" "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + "version" "5.3.1" + +"camelcase@^6.0.0": + "integrity" "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + "version" "6.3.0" + +"caniuse-lite@^1.0.30001332": + "integrity" "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==" + "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz" + "version" "1.0.30001332" + +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" + +"chalk@^4.0.0", "chalk@^4.1.0": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"chokidar@3.5.3": + "integrity" "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==" + "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + "version" "3.5.3" + dependencies: + "anymatch" "~3.1.2" + "braces" "~3.0.2" + "glob-parent" "~5.1.2" + "is-binary-path" "~2.1.0" + "is-glob" "~4.0.1" + "normalize-path" "~3.0.0" + "readdirp" "~3.6.0" + optionalDependencies: + "fsevents" "~2.3.2" + +"clean-stack@^2.0.0": + "integrity" "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + "resolved" "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + "version" "2.2.0" + +"cliui@^6.0.0": + "integrity" "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==" + "resolved" "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "string-width" "^4.2.0" + "strip-ansi" "^6.0.0" + "wrap-ansi" "^6.2.0" + +"cliui@^7.0.2": + "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==" + "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + "version" "7.0.4" + dependencies: + "string-width" "^4.2.0" + "strip-ansi" "^6.0.0" + "wrap-ansi" "^7.0.0" + +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" + dependencies: + "color-name" "1.1.3" + +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "color-name" "~1.1.4" + +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" + +"color-name@1.1.3": + "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" + +"commondir@^1.0.1": + "integrity" "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + "resolved" "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + "version" "1.0.1" + +"concat-map@0.0.1": + "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" + +"convert-source-map@^1.7.0": + "integrity" "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==" + "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" + "version" "1.8.0" + dependencies: + "safe-buffer" "~5.1.1" + +"create-require@^1.1.0": + "integrity" "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + "resolved" "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + "version" "1.1.1" + +"cross-spawn@^7.0.0", "cross-spawn@^7.0.2": + "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + "version" "7.0.3" + dependencies: + "path-key" "^3.1.0" + "shebang-command" "^2.0.0" + "which" "^2.0.1" + +"debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.2", "debug@4.3.4": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"decamelize@^1.2.0": + "integrity" "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "resolved" "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + "version" "1.2.0" + +"decamelize@^4.0.0": + "integrity" "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==" + "resolved" "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" + "version" "4.0.0" + +"deep-is@^0.1.3": + "integrity" "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "resolved" "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + "version" "0.1.4" + +"default-require-extensions@^3.0.0": + "integrity" "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==" + "resolved" "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "strip-bom" "^4.0.0" + +"diff@^4.0.1": + "integrity" "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + "resolved" "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + "version" "4.0.2" + +"diff@5.0.0": + "integrity" "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" + "resolved" "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" + "version" "5.0.0" + +"dir-glob@^3.0.1": + "integrity" "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==" + "resolved" "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "path-type" "^4.0.0" + +"doctrine@^3.0.0": + "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "esutils" "^2.0.2" + +"electron-to-chromium@^1.4.118": + "integrity" "sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w==" + "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.118.tgz" + "version" "1.4.118" + +"emoji-regex@^8.0.0": + "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + "version" "8.0.0" + +"es6-error@^4.0.1": + "integrity" "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" + "resolved" "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz" + "version" "4.1.1" + +"esbuild@*": + "integrity" "sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q==" + "resolved" "https://registry.npmjs.org/esbuild/-/esbuild-0.17.6.tgz" + "version" "0.17.6" + optionalDependencies: + "@esbuild/android-arm" "0.17.6" + "@esbuild/android-arm64" "0.17.6" + "@esbuild/android-x64" "0.17.6" + "@esbuild/darwin-arm64" "0.17.6" + "@esbuild/darwin-x64" "0.17.6" + "@esbuild/freebsd-arm64" "0.17.6" + "@esbuild/freebsd-x64" "0.17.6" + "@esbuild/linux-arm" "0.17.6" + "@esbuild/linux-arm64" "0.17.6" + "@esbuild/linux-ia32" "0.17.6" + "@esbuild/linux-loong64" "0.17.6" + "@esbuild/linux-mips64el" "0.17.6" + "@esbuild/linux-ppc64" "0.17.6" + "@esbuild/linux-riscv64" "0.17.6" + "@esbuild/linux-s390x" "0.17.6" + "@esbuild/linux-x64" "0.17.6" + "@esbuild/netbsd-x64" "0.17.6" + "@esbuild/openbsd-x64" "0.17.6" + "@esbuild/sunos-x64" "0.17.6" + "@esbuild/win32-arm64" "0.17.6" + "@esbuild/win32-ia32" "0.17.6" + "@esbuild/win32-x64" "0.17.6" + +"escalade@^3.1.1": + "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + "version" "3.1.1" + +"escape-string-regexp@^1.0.5": + "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" + +"escape-string-regexp@^4.0.0", "escape-string-regexp@4.0.0": + "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + "version" "4.0.0" + +"eslint-plugin-deprecation@^1.3.2": + "integrity" "sha512-z93wbx9w7H/E3ogPw6AZMkkNJ6m51fTZRNZPNQqxQLmx+KKt7aLkMU9wN67s71i+VVHN4tLOZ3zT3QLbnlC0Mg==" + "resolved" "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "@typescript-eslint/experimental-utils" "^5.0.0" + "tslib" "^2.3.1" + "tsutils" "^3.21.0" + +"eslint-scope@^5.1.1": + "integrity" "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + "version" "5.1.1" + dependencies: + "esrecurse" "^4.3.0" + "estraverse" "^4.1.1" + +"eslint-scope@^7.1.1": + "integrity" "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz" + "version" "7.1.1" + dependencies: + "esrecurse" "^4.3.0" + "estraverse" "^5.2.0" + +"eslint-utils@^3.0.0": + "integrity" "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==" + "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "eslint-visitor-keys" "^2.0.0" + +"eslint-visitor-keys@^2.0.0": + "integrity" "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + "version" "2.1.0" + +"eslint-visitor-keys@^3.0.0", "eslint-visitor-keys@^3.3.0": + "integrity" "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" + "version" "3.3.0" + +"eslint@*", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^8.15.0", "eslint@>=5": + "integrity" "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==" + "resolved" "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz" + "version" "8.15.0" + dependencies: + "@eslint/eslintrc" "^1.2.3" + "@humanwhocodes/config-array" "^0.9.2" + "ajv" "^6.10.0" + "chalk" "^4.0.0" + "cross-spawn" "^7.0.2" + "debug" "^4.3.2" + "doctrine" "^3.0.0" + "escape-string-regexp" "^4.0.0" + "eslint-scope" "^7.1.1" + "eslint-utils" "^3.0.0" + "eslint-visitor-keys" "^3.3.0" + "espree" "^9.3.2" + "esquery" "^1.4.0" + "esutils" "^2.0.2" + "fast-deep-equal" "^3.1.3" + "file-entry-cache" "^6.0.1" + "functional-red-black-tree" "^1.0.1" + "glob-parent" "^6.0.1" + "globals" "^13.6.0" + "ignore" "^5.2.0" + "import-fresh" "^3.0.0" + "imurmurhash" "^0.1.4" + "is-glob" "^4.0.0" + "js-yaml" "^4.1.0" + "json-stable-stringify-without-jsonify" "^1.0.1" + "levn" "^0.4.1" + "lodash.merge" "^4.6.2" + "minimatch" "^3.1.2" + "natural-compare" "^1.4.0" + "optionator" "^0.9.1" + "regexpp" "^3.2.0" + "strip-ansi" "^6.0.1" + "strip-json-comments" "^3.1.0" + "text-table" "^0.2.0" + "v8-compile-cache" "^2.0.3" + +"espree@^9.3.2": + "integrity" "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==" + "resolved" "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz" + "version" "9.3.2" + dependencies: + "acorn" "^8.7.1" + "acorn-jsx" "^5.3.2" + "eslint-visitor-keys" "^3.3.0" + +"esprima@^4.0.0": + "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + "version" "4.0.1" + +"esquery@^1.4.0": + "integrity" "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==" + "resolved" "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "estraverse" "^5.1.0" + +"esrecurse@^4.3.0": + "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" + "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "estraverse" "^5.2.0" + +"estraverse@^4.1.1": + "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + "version" "4.3.0" + +"estraverse@^5.1.0", "estraverse@^5.2.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"estree-walker@^0.6.1": + "integrity" "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" + "resolved" "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz" + "version" "0.6.1" + +"estree-walker@^2.0.1": + "integrity" "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + "resolved" "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" + "version" "2.0.2" + +"esutils@^2.0.2": + "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + "version" "2.0.3" + +"fast-deep-equal@^3.1.1", "fast-deep-equal@^3.1.3": + "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + "version" "3.1.3" + +"fast-glob@^3.2.9": + "integrity" "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==" + "resolved" "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz" + "version" "3.2.11" + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + "glob-parent" "^5.1.2" + "merge2" "^1.3.0" + "micromatch" "^4.0.4" + +"fast-json-stable-stringify@^2.0.0": + "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + "version" "2.1.0" + +"fast-levenshtein@^2.0.6": + "integrity" "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + "version" "2.0.6" + +"fastq@^1.6.0": + "integrity" "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==" + "resolved" "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" + "version" "1.13.0" + dependencies: + "reusify" "^1.0.4" + +"file-entry-cache@^6.0.1": + "integrity" "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==" + "resolved" "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "flat-cache" "^3.0.4" + +"fill-range@^7.0.1": + "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "to-regex-range" "^5.0.1" + +"find-cache-dir@^3.2.0", "find-cache-dir@^3.3.2": + "integrity" "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==" + "resolved" "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz" + "version" "3.3.2" + dependencies: + "commondir" "^1.0.1" + "make-dir" "^3.0.2" + "pkg-dir" "^4.1.0" + +"find-up@^4.0.0", "find-up@^4.1.0": + "integrity" "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "locate-path" "^5.0.0" + "path-exists" "^4.0.0" + +"find-up@^5.0.0": + "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "locate-path" "^6.0.0" + "path-exists" "^4.0.0" + +"find-up@5.0.0": + "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "locate-path" "^6.0.0" + "path-exists" "^4.0.0" + +"flat-cache@^3.0.4": + "integrity" "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==" + "resolved" "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "flatted" "^3.1.0" + "rimraf" "^3.0.2" + +"flat@^5.0.2": + "integrity" "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" + "resolved" "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" + "version" "5.0.2" + +"flatted@^3.1.0": + "integrity" "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==" + "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz" + "version" "3.2.5" + +"foreground-child@^2.0.0": + "integrity" "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==" + "resolved" "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "cross-spawn" "^7.0.0" + "signal-exit" "^3.0.2" + +"fromentries@^1.2.0": + "integrity" "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==" + "resolved" "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz" + "version" "1.3.2" + +"fs-extra@^10.0.0": + "integrity" "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==" + "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz" + "version" "10.1.0" + dependencies: + "graceful-fs" "^4.2.0" + "jsonfile" "^6.0.1" + "universalify" "^2.0.0" + +"fs.realpath@^1.0.0": + "integrity" "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" + +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" + +"functional-red-black-tree@^1.0.1": + "integrity" "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + "resolved" "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + "version" "1.0.1" + +"gensync@^1.0.0-beta.2": + "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + "version" "1.0.0-beta.2" + +"get-caller-file@^2.0.1", "get-caller-file@^2.0.5": + "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + "version" "2.0.5" + +"get-package-type@^0.1.0": + "integrity" "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + "resolved" "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + "version" "0.1.0" + +"glob-parent@^5.1.2", "glob-parent@~5.1.2": + "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + "version" "5.1.2" + dependencies: + "is-glob" "^4.0.1" + +"glob-parent@^6.0.1": + "integrity" "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + "version" "6.0.2" + dependencies: + "is-glob" "^4.0.3" + +"glob@^7.1.3", "glob@^7.1.4", "glob@^7.1.6", "glob@7.2.0": + "integrity" "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.0.4" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" + +"globals@^13.6.0", "globals@^13.9.0": + "integrity" "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==" + "resolved" "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz" + "version" "13.13.0" + dependencies: + "type-fest" "^0.20.2" + +"globby@^11.0.4": + "integrity" "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==" + "resolved" "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + "version" "11.1.0" + dependencies: + "array-union" "^2.1.0" + "dir-glob" "^3.0.1" + "fast-glob" "^3.2.9" + "ignore" "^5.2.0" + "merge2" "^1.4.1" + "slash" "^3.0.0" + +"graceful-fs@^4.1.15", "graceful-fs@^4.1.6", "graceful-fs@^4.2.0": + "integrity" "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + "version" "4.2.10" + +"has-flag@^3.0.0": + "integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" + +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" + +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "function-bind" "^1.1.1" + +"hasha@^5.0.0": + "integrity" "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==" + "resolved" "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz" + "version" "5.2.2" + dependencies: + "is-stream" "^2.0.0" + "type-fest" "^0.8.0" + +"he@1.2.0": + "integrity" "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "resolved" "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + "version" "1.2.0" + +"html-escaper@^2.0.0": + "integrity" "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + "resolved" "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + "version" "2.0.2" + +"ignore@^5.1.8", "ignore@^5.2.0": + "integrity" "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" + "version" "5.2.0" + +"import-fresh@^3.0.0", "import-fresh@^3.2.1": + "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + "version" "3.3.0" + dependencies: + "parent-module" "^1.0.0" + "resolve-from" "^4.0.0" + +"imurmurhash@^0.1.4": + "integrity" "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + "version" "0.1.4" + +"indent-string@^4.0.0": + "integrity" "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "resolved" "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + "version" "4.0.0" + +"inflight@^1.0.4": + "integrity" "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "once" "^1.3.0" + "wrappy" "1" + +"inherits@2": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"is-binary-path@~2.1.0": + "integrity" "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==" + "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "binary-extensions" "^2.0.0" + +"is-core-module@^2.8.1": + "integrity" "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz" + "version" "2.9.0" + dependencies: + "has" "^1.0.3" + +"is-extglob@^2.1.1": + "integrity" "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + "version" "2.1.1" + +"is-fullwidth-code-point@^3.0.0": + "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + "version" "3.0.0" + +"is-glob@^4.0.0", "is-glob@^4.0.1", "is-glob@^4.0.3", "is-glob@~4.0.1": + "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" + "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "is-extglob" "^2.1.1" + +"is-module@^1.0.0": + "integrity" "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + "resolved" "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz" + "version" "1.0.0" + +"is-number@^7.0.0": + "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + "version" "7.0.0" + +"is-plain-obj@^2.1.0": + "integrity" "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" + "version" "2.1.0" + +"is-stream@^2.0.0": + "integrity" "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + "version" "2.0.1" + +"is-typedarray@^1.0.0": + "integrity" "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "resolved" "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + "version" "1.0.0" + +"is-unicode-supported@^0.1.0": + "integrity" "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + "resolved" "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + "version" "0.1.0" + +"is-windows@^1.0.2": + "integrity" "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "resolved" "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" + "version" "1.0.2" + +"isexe@^2.0.0": + "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" + +"istanbul-lib-coverage@^3.0.0", "istanbul-lib-coverage@^3.0.0-alpha.1": + "integrity" "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + "resolved" "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + "version" "3.2.0" + +"istanbul-lib-hook@^3.0.0": + "integrity" "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==" + "resolved" "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "append-transform" "^2.0.0" + +"istanbul-lib-instrument@^4.0.0": + "integrity" "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==" + "resolved" "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + "istanbul-lib-coverage" "^3.0.0" + "semver" "^6.3.0" + +"istanbul-lib-processinfo@^2.0.2": + "integrity" "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==" + "resolved" "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "archy" "^1.0.0" + "cross-spawn" "^7.0.0" + "istanbul-lib-coverage" "^3.0.0-alpha.1" + "make-dir" "^3.0.0" + "p-map" "^3.0.0" + "rimraf" "^3.0.0" + "uuid" "^3.3.3" + +"istanbul-lib-report@^3.0.0": + "integrity" "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==" + "resolved" "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "istanbul-lib-coverage" "^3.0.0" + "make-dir" "^3.0.0" + "supports-color" "^7.1.0" + +"istanbul-lib-source-maps@^4.0.0": + "integrity" "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==" + "resolved" "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + "version" "4.0.1" + dependencies: + "debug" "^4.1.1" + "istanbul-lib-coverage" "^3.0.0" + "source-map" "^0.6.1" + +"istanbul-reports@^3.0.2": + "integrity" "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==" + "resolved" "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz" + "version" "3.1.4" + dependencies: + "html-escaper" "^2.0.0" + "istanbul-lib-report" "^3.0.0" + +"js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" + +"js-yaml@^3.13.1": + "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + "version" "3.14.1" + dependencies: + "argparse" "^1.0.7" + "esprima" "^4.0.0" + +"js-yaml@^4.1.0", "js-yaml@4.1.0": + "integrity" "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "argparse" "^2.0.1" + +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" + +"json-schema-traverse@^0.4.1": + "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + "version" "0.4.1" + +"json-stable-stringify-without-jsonify@^1.0.1": + "integrity" "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "resolved" "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + "version" "1.0.1" + +"json5@^2.2.1": + "integrity" "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + "version" "2.2.1" + +"jsonfile@^6.0.1": + "integrity" "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==" + "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" + "version" "6.1.0" + dependencies: + "universalify" "^2.0.0" + optionalDependencies: + "graceful-fs" "^4.1.6" + +"levn@^0.4.1": + "integrity" "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==" + "resolved" "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + "version" "0.4.1" + dependencies: + "prelude-ls" "^1.2.1" + "type-check" "~0.4.0" + +"locate-path@^5.0.0": + "integrity" "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-locate" "^4.1.0" + +"locate-path@^6.0.0": + "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "p-locate" "^5.0.0" + +"lodash.flattendeep@^4.4.0": + "integrity" "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=" + "resolved" "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz" + "version" "4.4.0" + +"lodash.merge@^4.6.2": + "integrity" "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + "resolved" "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + "version" "4.6.2" + +"log-symbols@4.1.0": + "integrity" "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==" + "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "chalk" "^4.1.0" + "is-unicode-supported" "^0.1.0" + +"lru-cache@^6.0.0": + "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "yallist" "^4.0.0" + +"magic-string@^0.26.1": + "integrity" "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==" + "resolved" "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz" + "version" "0.26.1" + dependencies: + "sourcemap-codec" "^1.4.8" + +"make-dir@^3.0.0", "make-dir@^3.0.2": + "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==" + "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "semver" "^6.0.0" + +"make-error@^1.1.1": + "integrity" "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + "resolved" "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + "version" "1.3.6" + +"merge2@^1.3.0", "merge2@^1.4.1": + "integrity" "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "resolved" "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + "version" "1.4.1" + +"micromatch@^4.0.4": + "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + "version" "4.0.5" + dependencies: + "braces" "^3.0.2" + "picomatch" "^2.3.1" + +"minimatch@^3.0.4", "minimatch@^3.1.2": + "integrity" "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "brace-expansion" "^1.1.7" + +"minimatch@5.0.1": + "integrity" "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "brace-expansion" "^2.0.1" + +"mocha@^10.0.0": + "integrity" "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==" + "resolved" "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz" + "version" "10.0.0" + dependencies: + "@ungap/promise-all-settled" "1.1.2" + "ansi-colors" "4.1.1" + "browser-stdout" "1.3.1" + "chokidar" "3.5.3" + "debug" "4.3.4" + "diff" "5.0.0" + "escape-string-regexp" "4.0.0" + "find-up" "5.0.0" + "glob" "7.2.0" + "he" "1.2.0" + "js-yaml" "4.1.0" + "log-symbols" "4.1.0" + "minimatch" "5.0.1" + "ms" "2.1.3" + "nanoid" "3.3.3" + "serialize-javascript" "6.0.0" + "strip-json-comments" "3.1.1" + "supports-color" "8.1.1" + "workerpool" "6.2.1" + "yargs" "16.2.0" + "yargs-parser" "20.2.4" + "yargs-unparser" "2.0.0" + +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" + +"ms@2.1.3": + "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + "version" "2.1.3" + +"nanoid@3.3.3": + "integrity" "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==" + "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz" + "version" "3.3.3" + +"natural-compare@^1.4.0": + "integrity" "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "resolved" "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + "version" "1.4.0" + +"node-preload@^0.2.1": + "integrity" "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==" + "resolved" "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz" + "version" "0.2.1" + dependencies: + "process-on-spawn" "^1.0.0" + +"node-releases@^2.0.3": + "integrity" "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==" + "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz" + "version" "2.0.3" + +"normalize-path@^3.0.0", "normalize-path@~3.0.0": + "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + "version" "3.0.0" + +"nyc@^15.1.0": + "integrity" "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==" + "resolved" "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz" + "version" "15.1.0" + dependencies: + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + "caching-transform" "^4.0.0" + "convert-source-map" "^1.7.0" + "decamelize" "^1.2.0" + "find-cache-dir" "^3.2.0" + "find-up" "^4.1.0" + "foreground-child" "^2.0.0" + "get-package-type" "^0.1.0" + "glob" "^7.1.6" + "istanbul-lib-coverage" "^3.0.0" + "istanbul-lib-hook" "^3.0.0" + "istanbul-lib-instrument" "^4.0.0" + "istanbul-lib-processinfo" "^2.0.2" + "istanbul-lib-report" "^3.0.0" + "istanbul-lib-source-maps" "^4.0.0" + "istanbul-reports" "^3.0.2" + "make-dir" "^3.0.0" + "node-preload" "^0.2.1" + "p-map" "^3.0.0" + "process-on-spawn" "^1.0.0" + "resolve-from" "^5.0.0" + "rimraf" "^3.0.0" + "signal-exit" "^3.0.2" + "spawn-wrap" "^2.0.0" + "test-exclude" "^6.0.0" + "yargs" "^15.0.2" + +"once@^1.3.0": + "integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"optionator@^0.9.1": + "integrity" "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==" + "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" + "version" "0.9.1" + dependencies: + "deep-is" "^0.1.3" + "fast-levenshtein" "^2.0.6" + "levn" "^0.4.1" + "prelude-ls" "^1.2.1" + "type-check" "^0.4.0" + "word-wrap" "^1.2.3" + +"p-limit@^2.2.0": + "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + "version" "2.3.0" + dependencies: + "p-try" "^2.0.0" + +"p-limit@^3.0.2": + "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "yocto-queue" "^0.1.0" + +"p-locate@^4.1.0": + "integrity" "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "p-limit" "^2.2.0" + +"p-locate@^5.0.0": + "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-limit" "^3.0.2" + +"p-map@^3.0.0": + "integrity" "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==" + "resolved" "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "aggregate-error" "^3.0.0" + +"p-try@^2.0.0": + "integrity" "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "resolved" "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + "version" "2.2.0" + +"package-hash@^4.0.0": + "integrity" "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==" + "resolved" "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "graceful-fs" "^4.1.15" + "hasha" "^5.0.0" + "lodash.flattendeep" "^4.4.0" + "release-zalgo" "^1.0.0" + +"parent-module@^1.0.0": + "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" + "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "callsites" "^3.0.0" + +"path-exists@^4.0.0": + "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + "version" "4.0.0" + +"path-is-absolute@^1.0.0": + "integrity" "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" + +"path-is-network-drive@^1.0.13": + "integrity" "sha512-Hg74mRN6mmXV+gTm3INjFK40ncAmC/Lo4qoQaSZ+GT3hZzlKdWQSqAjqyPeW0SvObP2W073WyYEBWY9d3wOm3A==" + "resolved" "https://registry.npmjs.org/path-is-network-drive/-/path-is-network-drive-1.0.13.tgz" + "version" "1.0.13" + dependencies: + "tslib" "^2.3.1" + +"path-key@^3.1.0": + "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + "version" "3.1.1" + +"path-parse@^1.0.7": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" + +"path-strip-sep@^1.0.10": + "integrity" "sha512-JpCy+8LAJQQTO1bQsb/84s1g+/Stm3h39aOpPRBQ/paMUGVPPZChLTOTKHoaCkc/6sKuF7yVsnq5Pe1S6xQGcA==" + "resolved" "https://registry.npmjs.org/path-strip-sep/-/path-strip-sep-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "tslib" "^2.3.1" + +"path-type@^4.0.0": + "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "resolved" "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + "version" "4.0.0" + +"picocolors@^1.0.0": + "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + "version" "1.0.0" + +"picomatch@^2.0.4", "picomatch@^2.2.1", "picomatch@^2.2.2", "picomatch@^2.3.1": + "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + "version" "2.3.1" + +"pkg-dir@^4.1.0": + "integrity" "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==" + "resolved" "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + "version" "4.2.0" + dependencies: + "find-up" "^4.0.0" + +"pkg-dir@< 6 >= 5": + "integrity" "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==" + "resolved" "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "find-up" "^5.0.0" + +"prelude-ls@^1.2.1": + "integrity" "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + "version" "1.2.1" + +"process-on-spawn@^1.0.0": + "integrity" "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==" + "resolved" "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "fromentries" "^1.2.0" + +"punycode@^2.1.0": + "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + "version" "2.1.1" + +"pvtsutils@^1.3.2": + "integrity" "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==" + "resolved" "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "tslib" "^2.4.0" + +"pvutils@^1.1.3": + "integrity" "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==" + "resolved" "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz" + "version" "1.1.3" + +"queue-microtask@^1.2.2": + "integrity" "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + "version" "1.2.3" + +"randombytes@^2.1.0": + "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==" + "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "safe-buffer" "^5.1.0" + +"readdirp@~3.6.0": + "integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==" + "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + "version" "3.6.0" + dependencies: + "picomatch" "^2.2.1" + +"regexpp@^3.2.0": + "integrity" "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + "resolved" "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + "version" "3.2.0" + +"release-zalgo@^1.0.0": + "integrity" "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=" + "resolved" "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "es6-error" "^4.0.1" + +"require-directory@^2.1.1": + "integrity" "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + "version" "2.1.1" + +"require-main-filename@^2.0.0": + "integrity" "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "resolved" "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" + "version" "2.0.0" + +"resolve-from@^4.0.0": + "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + "version" "4.0.0" + +"resolve-from@^5.0.0": + "integrity" "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + "version" "5.0.0" + +"resolve@^1.11.1", "resolve@^1.20.0": + "integrity" "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz" + "version" "1.22.0" + dependencies: + "is-core-module" "^2.8.1" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"reusify@^1.0.4": + "integrity" "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "resolved" "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + "version" "1.0.4" + +"rimraf@^3.0.0", "rimraf@^3.0.2": + "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "glob" "^7.1.3" + +"rollup-plugin-dts@^4.2.1": + "integrity" "sha512-eaxQZNUJ5iQcxNGlpJ1CUgG4OSVqWjDZ3nNSWBIoGrpcote2aNphSe1RJOaSYkb8dwn3o+rYm1vvld/5z3EGSQ==" + "resolved" "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.2.1.tgz" + "version" "4.2.1" + dependencies: + "magic-string" "^0.26.1" + optionalDependencies: + "@babel/code-frame" "^7.16.7" + +"rollup-plugin-node-resolve@^5.2.0": + "integrity" "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==" + "resolved" "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz" + "version" "5.2.0" + dependencies: + "@types/resolve" "0.0.8" + "builtin-modules" "^3.1.0" + "is-module" "^1.0.0" + "resolve" "^1.11.1" + "rollup-pluginutils" "^2.8.1" + +"rollup-plugin-typescript2@^0.31.2": + "integrity" "sha512-hRwEYR1C8xDGVVMFJQdEVnNAeWRvpaY97g5mp3IeLnzhNXzSVq78Ye/BJ9PAaUfN4DXa/uDnqerifMOaMFY54Q==" + "resolved" "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.31.2.tgz" + "version" "0.31.2" + dependencies: + "@rollup/pluginutils" "^4.1.2" + "@yarn-tool/resolve-package" "^1.0.40" + "find-cache-dir" "^3.3.2" + "fs-extra" "^10.0.0" + "resolve" "^1.20.0" + "tslib" "^2.3.1" + +"rollup-pluginutils@^2.8.1": + "integrity" "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==" + "resolved" "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz" + "version" "2.8.2" + dependencies: + "estree-walker" "^0.6.1" + +"rollup@^2.70", "rollup@^2.72.1", "rollup@>=1.11.0", "rollup@>=1.26.3": + "integrity" "sha512-NTc5UGy/NWFGpSqF1lFY8z9Adri6uhyMLI6LvPAXdBKoPRFhIIiBUpt+Qg2awixqO3xvzSijjhnb4+QEZwJmxA==" + "resolved" "https://registry.npmjs.org/rollup/-/rollup-2.72.1.tgz" + "version" "2.72.1" + optionalDependencies: + "fsevents" "~2.3.2" + +"run-parallel@^1.1.9": + "integrity" "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==" + "resolved" "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "queue-microtask" "^1.2.2" + +"safe-buffer@^5.1.0": + "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + "version" "5.2.1" + +"safe-buffer@~5.1.1": + "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + "version" "5.1.2" + +"semver@^6.0.0", "semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" + +"semver@^7.3.5": + "integrity" "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" + "version" "7.3.7" + dependencies: + "lru-cache" "^6.0.0" + +"serialize-javascript@6.0.0": + "integrity" "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==" + "resolved" "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "randombytes" "^2.1.0" + +"set-blocking@^2.0.0": + "integrity" "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "resolved" "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + "version" "2.0.0" + +"shebang-command@^2.0.0": + "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "shebang-regex" "^3.0.0" + +"shebang-regex@^3.0.0": + "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + "version" "3.0.0" + +"signal-exit@^3.0.2": + "integrity" "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + "version" "3.0.7" + +"slash@^3.0.0": + "integrity" "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + "version" "3.0.0" + +"source-map@^0.5.0": + "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + "version" "0.5.7" + +"source-map@^0.6.1": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" + +"sourcemap-codec@^1.4.8": + "integrity" "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + "resolved" "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" + "version" "1.4.8" + +"spawn-wrap@^2.0.0": + "integrity" "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==" + "resolved" "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "foreground-child" "^2.0.0" + "is-windows" "^1.0.2" + "make-dir" "^3.0.0" + "rimraf" "^3.0.0" + "signal-exit" "^3.0.2" + "which" "^2.0.1" + +"sprintf-js@~1.0.2": + "integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + "version" "1.0.3" + +"string-width@^4.1.0", "string-width@^4.2.0": + "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"strip-ansi@^6.0.0", "strip-ansi@^6.0.1": + "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "ansi-regex" "^5.0.1" + +"strip-bom@^4.0.0": + "integrity" "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + "resolved" "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + "version" "4.0.0" + +"strip-json-comments@^3.1.0", "strip-json-comments@^3.1.1", "strip-json-comments@3.1.1": + "integrity" "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + "version" "3.1.1" + +"supports-color@^5.3.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" + dependencies: + "has-flag" "^3.0.0" + +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "has-flag" "^4.0.0" + +"supports-color@8.1.1": + "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + "version" "8.1.1" + dependencies: + "has-flag" "^4.0.0" + +"supports-preserve-symlinks-flag@^1.0.0": + "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + "version" "1.0.0" + +"test-exclude@^6.0.0": + "integrity" "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==" + "resolved" "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "@istanbuljs/schema" "^0.1.2" + "glob" "^7.1.4" + "minimatch" "^3.0.4" + +"text-table@^0.2.0": + "integrity" "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "resolved" "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + "version" "0.2.0" + +"to-fast-properties@^2.0.0": + "integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" + +"to-regex-range@^5.0.1": + "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "is-number" "^7.0.0" + +"ts-node@^10.7.0": + "integrity" "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==" + "resolved" "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz" + "version" "10.7.0" + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + "acorn" "^8.4.1" + "acorn-walk" "^8.1.1" + "arg" "^4.1.0" + "create-require" "^1.1.0" + "diff" "^4.0.1" + "make-error" "^1.1.1" + "v8-compile-cache-lib" "^3.0.0" + "yn" "3.1.1" + +"tslib@^1.8.1": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" + +"tslib@^2.3.1", "tslib@^2.4.0": + "integrity" "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" + "version" "2.4.0" + +"tsutils@^3.21.0": + "integrity" "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==" + "resolved" "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" + "version" "3.21.0" + dependencies: + "tslib" "^1.8.1" + +"type-check@^0.4.0", "type-check@~0.4.0": + "integrity" "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==" + "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + "version" "0.4.0" + dependencies: + "prelude-ls" "^1.2.1" + +"type-fest@^0.20.2": + "integrity" "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + "version" "0.20.2" + +"type-fest@^0.8.0": + "integrity" "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + "version" "0.8.1" + +"typedarray-to-buffer@^3.1.5": + "integrity" "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==" + "resolved" "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" + "version" "3.1.5" + dependencies: + "is-typedarray" "^1.0.0" + +"typescript@^3.7.5 || ^4.0.0", "typescript@^4.6", "typescript@^4.6.4", "typescript@>=2.4.0", "typescript@>=2.7", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta": + "integrity" "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==" + "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz" + "version" "4.6.4" + +"universalify@^2.0.0": + "integrity" "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "resolved" "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" + "version" "2.0.0" + +"upath2@^3.1.12": + "integrity" "sha512-yC3eZeCyCXFWjy7Nu4pgjLhXNYjuzuUmJiRgSSw6TJp8Emc+E4951HGPJf+bldFC5SL7oBLeNbtm1fGzXn2gxw==" + "resolved" "https://registry.npmjs.org/upath2/-/upath2-3.1.12.tgz" + "version" "3.1.12" + dependencies: + "path-is-network-drive" "^1.0.13" + "path-strip-sep" "^1.0.10" + "tslib" "^2.3.1" + +"uri-js@^4.2.2": + "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" + "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + "version" "4.4.1" + dependencies: + "punycode" "^2.1.0" + +"uuid@^3.3.3": + "integrity" "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "resolved" "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" + "version" "3.4.0" + +"v8-compile-cache-lib@^3.0.0": + "integrity" "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + "resolved" "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + "version" "3.0.1" + +"v8-compile-cache@^2.0.3": + "integrity" "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + "resolved" "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" + "version" "2.3.0" + +"which-module@^2.0.0": + "integrity" "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "resolved" "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" + "version" "2.0.0" + +"which@^2.0.1": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"word-wrap@^1.2.3": + "integrity" "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "resolved" "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" + "version" "1.2.3" + +"workerpool@6.2.1": + "integrity" "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" + "resolved" "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz" + "version" "6.2.1" + +"wrap-ansi@^6.2.0": + "integrity" "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrap-ansi@^7.0.0": + "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==" + "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + "version" "7.0.0" + dependencies: + "ansi-styles" "^4.0.0" + "string-width" "^4.1.0" + "strip-ansi" "^6.0.0" + +"wrappy@1": + "integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" + +"write-file-atomic@^3.0.0": + "integrity" "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==" + "resolved" "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" + "version" "3.0.3" + dependencies: + "imurmurhash" "^0.1.4" + "is-typedarray" "^1.0.0" + "signal-exit" "^3.0.2" + "typedarray-to-buffer" "^3.1.5" + +"y18n@^4.0.0": + "integrity" "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + "resolved" "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" + "version" "4.0.3" + +"y18n@^5.0.5": + "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + "version" "5.0.8" + +"yallist@^4.0.0": + "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + "version" "4.0.0" + +"yargs-parser@^18.1.2": + "integrity" "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" + "version" "18.1.3" + dependencies: + "camelcase" "^5.0.0" + "decamelize" "^1.2.0" + +"yargs-parser@^20.2.2": + "integrity" "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + "version" "20.2.9" + +"yargs-parser@20.2.4": + "integrity" "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" + "version" "20.2.4" + +"yargs-unparser@2.0.0": + "integrity" "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==" + "resolved" "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "camelcase" "^6.0.0" + "decamelize" "^4.0.0" + "flat" "^5.0.2" + "is-plain-obj" "^2.1.0" + +"yargs@^15.0.2": + "integrity" "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==" + "resolved" "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" + "version" "15.4.1" + dependencies: + "cliui" "^6.0.0" + "decamelize" "^1.2.0" + "find-up" "^4.1.0" + "get-caller-file" "^2.0.1" + "require-directory" "^2.1.1" + "require-main-filename" "^2.0.0" + "set-blocking" "^2.0.0" + "string-width" "^4.2.0" + "which-module" "^2.0.0" + "y18n" "^4.0.0" + "yargs-parser" "^18.1.2" + +"yargs@16.2.0": + "integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==" + "resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + "version" "16.2.0" + dependencies: + "cliui" "^7.0.2" + "escalade" "^3.1.1" + "get-caller-file" "^2.0.5" + "require-directory" "^2.1.1" + "string-width" "^4.2.0" + "y18n" "^5.0.5" + "yargs-parser" "^20.2.2" + +"yn@3.1.1": + "integrity" "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + "resolved" "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + "version" "3.1.1" + +"yocto-queue@^0.1.0": + "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + "version" "0.1.0" diff --git a/comm/third_party/botan/Makefile.in b/comm/third_party/botan/Makefile.in new file mode 100644 index 0000000000..2aaf56941f --- /dev/null +++ b/comm/third_party/botan/Makefile.in @@ -0,0 +1,12 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/config/rules.mk + +ifdef COMPILE_ENVIRONMENT +ifndef MZLA_SYSTEM_BOTAN +export:: build/build.h +endif +endif diff --git a/comm/third_party/botan/botan.mozbuild b/comm/third_party/botan/botan.mozbuild new file mode 100644 index 0000000000..50ca96d6f7 --- /dev/null +++ b/comm/third_party/botan/botan.mozbuild @@ -0,0 +1,238 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include('../rnpdefs.mozbuild') + +DEFINES['BOTAN_IS_BEING_BUILT'] = 1 +DEFINES['_REENTRANT'] = 1 + +if CONFIG['CC_TYPE'] == 'clang-cl': + DEFINES['_ENABLE_EXTENDED_ALIGNED_STORAGE'] = 1 + + CXXFLAGS += [ + '-bigobj', + '-clang:-fno-force-enable-int128', + '/EHs', + ] +else: + CXXFLAGS += [ + '-fexceptions', + '-fstack-protector' + ] + +if CONFIG['OS_ARCH'] == 'WINNT': + botan_os = 'windows' +elif CONFIG['OS_ARCH'] == 'Linux': + botan_os = 'linux' + CXXFLAGS += ['-pthread'] +else: + botan_os = CONFIG['OS_ARCH'].lower() + +# Run Botan's configure.py to generate build.h. Use --with-cmake to avoid +# writing a Makefile that would overwrite our own. +botan_generated = [ + 'build/build.h', + 'build/build_config.json', + 'CMakeLists.txt', + ] + +if CONFIG['COMPILE_ENVIRONMENT']: + GENERATED_FILES += botan_generated + botan_build = GENERATED_FILES['build/build.h'] + botan_build.script = 'botan_configure.py' + botan_build.flags = [ + '--cc-bin={}'.format(CONFIG['CXX']), + '--cpu={}'.format(CONFIG['target_cpu']), + '--os={}'.format(botan_os), + '--with-build-dir={}'.format(OBJDIR), + '--minimized-build', + '--disable-shared-library', + '--link-method=copy', + '--without-documentation', + '--distribution-info={}'.format(rnp_dist_info), + '--with-cmake', + ] + + +LOCAL_INCLUDES = ['!build/include'] + +# This list was obtained by running Botan's configure script in CMake mode +# with the desired options and extracting the information from CMakeLists.txt. +SOURCES += [ + 'src/lib/asn1/alg_id.cpp', + 'src/lib/asn1/asn1_obj.cpp', + 'src/lib/asn1/asn1_oid.cpp', + 'src/lib/asn1/asn1_print.cpp', + 'src/lib/asn1/asn1_str.cpp', + 'src/lib/asn1/asn1_time.cpp', + 'src/lib/asn1/ber_dec.cpp', + 'src/lib/asn1/der_enc.cpp', + 'src/lib/asn1/oid_maps.cpp', + 'src/lib/asn1/oids.cpp', + 'src/lib/base/buf_comp.cpp', + 'src/lib/base/scan_name.cpp', + 'src/lib/base/sym_algo.cpp', + 'src/lib/base/symkey.cpp', + 'src/lib/block/aes/aes.cpp', + 'src/lib/block/block_cipher.cpp', + 'src/lib/block/blowfish/blowfish.cpp', + 'src/lib/block/camellia/camellia.cpp', + 'src/lib/block/cast128/cast128.cpp', + 'src/lib/block/des/des.cpp', + 'src/lib/block/des/des_tab.cpp', + 'src/lib/block/des/desx.cpp', + 'src/lib/block/idea/idea.cpp', + 'src/lib/block/sm4/sm4.cpp', + 'src/lib/block/twofish/twofish.cpp', + 'src/lib/block/twofish/twofish_tab.cpp', + 'src/lib/codec/base64/base64.cpp', + 'src/lib/codec/hex/hex.cpp', + 'src/lib/entropy/entropy_srcs.cpp', + 'src/lib/ffi/ffi.cpp', + 'src/lib/ffi/ffi_block.cpp', + 'src/lib/ffi/ffi_cert.cpp', + 'src/lib/ffi/ffi_cipher.cpp', + 'src/lib/ffi/ffi_fpe.cpp', + 'src/lib/ffi/ffi_hash.cpp', + 'src/lib/ffi/ffi_hotp.cpp', + 'src/lib/ffi/ffi_kdf.cpp', + 'src/lib/ffi/ffi_keywrap.cpp', + 'src/lib/ffi/ffi_mac.cpp', + 'src/lib/ffi/ffi_mp.cpp', + 'src/lib/ffi/ffi_pk_op.cpp', + 'src/lib/ffi/ffi_pkey.cpp', + 'src/lib/ffi/ffi_pkey_algs.cpp', + 'src/lib/ffi/ffi_rng.cpp', + 'src/lib/ffi/ffi_totp.cpp', + 'src/lib/hash/checksum/crc24/crc24.cpp', + 'src/lib/hash/hash.cpp', + 'src/lib/hash/md5/md5.cpp', + 'src/lib/hash/mdx_hash/mdx_hash.cpp', + 'src/lib/hash/rmd160/rmd160.cpp', + 'src/lib/hash/sha1/sha160.cpp', + 'src/lib/hash/sha2_32/sha2_32.cpp', + 'src/lib/hash/sha2_64/sha2_64.cpp', + 'src/lib/hash/sha3/sha3.cpp', + 'src/lib/hash/sm3/sm3.cpp', + 'src/lib/kdf/kdf.cpp', + 'src/lib/kdf/kdf2/kdf2.cpp', + 'src/lib/kdf/sp800_56a/sp800_56a.cpp', + 'src/lib/mac/cmac/cmac.cpp', + 'src/lib/mac/hmac/hmac.cpp', + 'src/lib/mac/mac.cpp', + 'src/lib/math/bigint/big_code.cpp', + 'src/lib/math/bigint/big_io.cpp', + 'src/lib/math/bigint/big_ops2.cpp', + 'src/lib/math/bigint/big_ops3.cpp', + 'src/lib/math/bigint/big_rand.cpp', + 'src/lib/math/bigint/bigint.cpp', + 'src/lib/math/bigint/divide.cpp', + 'src/lib/math/mp/mp_comba.cpp', + 'src/lib/math/mp/mp_karat.cpp', + 'src/lib/math/mp/mp_monty.cpp', + 'src/lib/math/mp/mp_monty_n.cpp', + 'src/lib/math/numbertheory/dsa_gen.cpp', + 'src/lib/math/numbertheory/jacobi.cpp', + 'src/lib/math/numbertheory/make_prm.cpp', + 'src/lib/math/numbertheory/mod_inv.cpp', + 'src/lib/math/numbertheory/monty.cpp', + 'src/lib/math/numbertheory/monty_exp.cpp', + 'src/lib/math/numbertheory/mp_numth.cpp', + 'src/lib/math/numbertheory/nistp_redc.cpp', + 'src/lib/math/numbertheory/numthry.cpp', + 'src/lib/math/numbertheory/pow_mod.cpp', + 'src/lib/math/numbertheory/primality.cpp', + 'src/lib/math/numbertheory/primes.cpp', + 'src/lib/math/numbertheory/reducer.cpp', + 'src/lib/math/numbertheory/ressol.cpp', + 'src/lib/misc/nist_keywrap/nist_keywrap.cpp', + 'src/lib/misc/rfc3394/rfc3394.cpp', + 'src/lib/modes/aead/aead.cpp', + 'src/lib/modes/aead/eax/eax.cpp', + 'src/lib/modes/aead/ocb/ocb.cpp', + 'src/lib/modes/cbc/cbc.cpp', + 'src/lib/modes/cfb/cfb.cpp', + 'src/lib/modes/cipher_mode.cpp', + 'src/lib/modes/mode_pad/mode_pad.cpp', + 'src/lib/pbkdf/pbkdf.cpp', + 'src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp', + 'src/lib/pbkdf/pwdhash.cpp', + 'src/lib/pk_pad/eme.cpp', + 'src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp', + 'src/lib/pk_pad/emsa.cpp', + 'src/lib/pk_pad/emsa1/emsa1.cpp', + 'src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp', + 'src/lib/pk_pad/emsa_pssr/pssr.cpp', + 'src/lib/pk_pad/emsa_raw/emsa_raw.cpp', + 'src/lib/pk_pad/hash_id/hash_id.cpp', + 'src/lib/pk_pad/mgf1/mgf1.cpp', + 'src/lib/pk_pad/padding.cpp', + 'src/lib/pubkey/blinding.cpp', + 'src/lib/pubkey/curve25519/curve25519.cpp', + 'src/lib/pubkey/curve25519/donna.cpp', + 'src/lib/pubkey/dl_algo/dl_algo.cpp', + 'src/lib/pubkey/dl_group/dl_group.cpp', + 'src/lib/pubkey/dl_group/dl_named.cpp', + 'src/lib/pubkey/dsa/dsa.cpp', + 'src/lib/pubkey/ec_group/curve_gfp.cpp', + 'src/lib/pubkey/ec_group/ec_group.cpp', + 'src/lib/pubkey/ec_group/ec_named.cpp', + 'src/lib/pubkey/ec_group/point_gfp.cpp', + 'src/lib/pubkey/ec_group/point_mul.cpp', + 'src/lib/pubkey/ecc_key/ecc_key.cpp', + 'src/lib/pubkey/ecdh/ecdh.cpp', + 'src/lib/pubkey/ecdsa/ecdsa.cpp', + 'src/lib/pubkey/ed25519/ed25519.cpp', + 'src/lib/pubkey/ed25519/ed25519_fe.cpp', + 'src/lib/pubkey/ed25519/ed25519_key.cpp', + 'src/lib/pubkey/ed25519/ge.cpp', + 'src/lib/pubkey/ed25519/sc_muladd.cpp', + 'src/lib/pubkey/ed25519/sc_reduce.cpp', + 'src/lib/pubkey/elgamal/elgamal.cpp', + 'src/lib/pubkey/keypair/keypair.cpp', + 'src/lib/pubkey/pem/pem.cpp', + 'src/lib/pubkey/pk_algs.cpp', + 'src/lib/pubkey/pk_keys.cpp', + 'src/lib/pubkey/pk_ops.cpp', + 'src/lib/pubkey/pkcs8.cpp', + 'src/lib/pubkey/pubkey.cpp', + 'src/lib/pubkey/rsa/rsa.cpp', + 'src/lib/pubkey/sm2/sm2.cpp', + 'src/lib/pubkey/sm2/sm2_enc.cpp', + 'src/lib/pubkey/workfactor.cpp', + 'src/lib/pubkey/x509_key.cpp', + 'src/lib/rng/auto_rng/auto_rng.cpp', + 'src/lib/rng/hmac_drbg/hmac_drbg.cpp', + 'src/lib/rng/rng.cpp', + 'src/lib/rng/stateful_rng/stateful_rng.cpp', + 'src/lib/rng/system_rng/system_rng.cpp', + 'src/lib/stream/ctr/ctr.cpp', + 'src/lib/stream/stream_cipher.cpp', + 'src/lib/utils/assert.cpp', + 'src/lib/utils/calendar.cpp', + 'src/lib/utils/charset.cpp', + 'src/lib/utils/cpuid/cpuid.cpp', + 'src/lib/utils/cpuid/cpuid_arm.cpp', + 'src/lib/utils/cpuid/cpuid_ppc.cpp', + 'src/lib/utils/cpuid/cpuid_x86.cpp', + 'src/lib/utils/ct_utils.cpp', + 'src/lib/utils/data_src.cpp', + 'src/lib/utils/exceptn.cpp', + 'src/lib/utils/filesystem.cpp', + 'src/lib/utils/mem_ops.cpp', + 'src/lib/utils/os_utils.cpp', + 'src/lib/utils/parsing.cpp', + 'src/lib/utils/poly_dbl/poly_dbl.cpp', + 'src/lib/utils/read_cfg.cpp', + 'src/lib/utils/read_kv.cpp', + 'src/lib/utils/timer.cpp', + 'src/lib/utils/version.cpp', +] + +if CONFIG['CC_TYPE'] == 'clang-cl': + SOURCES += [ + 'src/lib/utils/dyn_load/dyn_load.cpp', + ] diff --git a/comm/third_party/botan/botan_configure.py b/comm/third_party/botan/botan_configure.py new file mode 100755 index 0000000000..858c1e63d3 --- /dev/null +++ b/comm/third_party/botan/botan_configure.py @@ -0,0 +1,121 @@ +#!python3 +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from __future__ import print_function, absolute_import, unicode_literals +import os +import sys +import subprocess +from mozbuild.util import system_encoding + +# This script is a wrapper for Botan's configure.py to adapt it for moz.build. +# Its main purpose is to return some output on stdout for mozbuild to handle, +# but secondary to that is to set --enable-modules. Mozbuild/Make mangle +# the list otherwise due to the embedded commas. + +botan_modules = ",".join( + ( + "aead", + "aes", + "auto_rng", + "bigint", + "blowfish", + "camellia", + "cast128", + "cbc", + "cfb", + "crc24", + "curve25519", + "des", + "dl_group", + "dsa", + "eax", + "ec_group", + "ecdh", + "ecdsa", + "ed25519", + "elgamal", + "eme_pkcs1", + "emsa_pkcs1", + "emsa_raw", + "ffi", + "hash", + "hmac", + "hmac_drbg", + "idea", + "kdf", + "md5", + "ocb", + "pgp_s2k", + "pubkey", + "rfc3394", + "rmd160", + "rsa", + "sha1", + "sha2_32", + "sha2_64", + "sha3", + "sm2", + "sm3", + "sm4", + "sp800_56a", + "system_rng", + "twofish", + ) +) + +## +here = os.path.abspath(os.path.dirname(__file__)) +configure = os.path.join(here, "configure.py") + + +# A wrapper to obtain a process' output and return code. +# Returns a tuple (retcode, stdout, stderr). +# from build/moz.configure/util.configure +def get_cmd_output(*args, **kwargs): + proc = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=os.name != "nt", + encoding=system_encoding, + errors="replace", + ) + stdout, stderr = proc.communicate() + return proc.wait(), stdout, stderr + + +def _run_configure(argv): + """Call Botan's configure.py. Arguments are passed "shell-style".""" + args = [sys.executable] + [configure] + list(argv) # passed as a tuple + botan_modules_arg = "--enable-modules={}".format(botan_modules) + args.append(botan_modules_arg) + + try: + rv = get_cmd_output(*args) + except Exception: + raise + + return rv + + +def main(output, *args): + rv = _run_configure(args) + if rv[0] == 0: + # GENERATED_FILES expects this script to write something back to output + if os.path.isfile(output.name): + with open(output.name, "r") as fp: + data = fp.read() + output.write(data) + else: + # Probably an error + raise Exception("Unable to locate real output at {}".format(output.name)) + else: + return rv + + return rv[0] + + +if __name__ == "__main__": + main(*sys.argv) diff --git a/comm/third_party/botan/configure.py b/comm/third_party/botan/configure.py new file mode 100755 index 0000000000..dd1928aa97 --- /dev/null +++ b/comm/third_party/botan/configure.py @@ -0,0 +1,3454 @@ +#!/usr/bin/env python + +""" +Configuration program for botan + +(C) 2009-2020 Jack Lloyd +(C) 2015,2016,2017 Simon Warta (Kullo GmbH) + +Botan is released under the Simplified BSD License (see license.txt) + +This script is regularly tested with CPython 2.7 and 3.5, and +occasionally tested with CPython 2.6 and PyPy 4. + +Support for CPython 2.6 will be dropped eventually, but is kept up for as +long as reasonably convenient. + +CPython 2.5 and earlier are not supported. + +On Jython target detection does not work (use --os and --cpu). +""" + +import collections +import copy +import json +import sys +import os +import os.path +import platform +import re +import shlex +import shutil +import subprocess +import traceback +import logging +import time +import errno +import optparse # pylint: disable=deprecated-module + +# An error caused by and to be fixed by the user, e.g. invalid command line argument +class UserError(Exception): + pass + + +# An error caused by bugs in this script or when reading/parsing build data files +# Those are not expected to be fixed by the user of this script +class InternalError(Exception): + pass + + +def flatten(l): + return sum(l, []) + +def normalize_source_path(source): + """ + cmake needs this, and nothing else minds + """ + return os.path.normpath(source).replace('\\', '/') + +def parse_version_file(version_path): + version_file = open(version_path) + key_and_val = re.compile(r"([a-z_]+) = ([a-zA-Z0-9:\-\']+)") + + results = {} + for line in version_file.readlines(): + if not line or line[0] == '#': + continue + match = key_and_val.match(line) + if match: + key = match.group(1) + val = match.group(2) + + if val == 'None': + val = None + elif val.startswith("'") and val.endswith("'"): + val = val[1:len(val)-1] + else: + val = int(val) + + results[key] = val + return results + +class Version(object): + """ + Version information are all static members + """ + data = {} + + @staticmethod + def get_data(): + if not Version.data: + root_dir = os.path.dirname(os.path.realpath(__file__)) + Version.data = parse_version_file(os.path.join(root_dir, 'src/build-data/version.txt')) + + suffix = Version.data["release_suffix"] + if suffix != "": + suffix_re = re.compile('-(alpha|beta|rc)[0-9]+') + + if not suffix_re.match(suffix): + raise Exception("Unexpected version suffix '%s'" % (suffix)) + return Version.data + + @staticmethod + def major(): + return Version.get_data()["release_major"] + + @staticmethod + def minor(): + return Version.get_data()["release_minor"] + + @staticmethod + def patch(): + return Version.get_data()["release_patch"] + + @staticmethod + def suffix(): + return Version.get_data()["release_suffix"] + + @staticmethod + def packed(): + # Used on macOS for dylib versioning + return Version.major() * 1000 + Version.minor() + + @staticmethod + def so_rev(): + return Version.get_data()["release_so_abi_rev"] + + @staticmethod + def release_type(): + return Version.get_data()["release_type"] + + @staticmethod + def datestamp(): + return Version.get_data()["release_datestamp"] + + @staticmethod + def as_string(): + return '%d.%d.%d%s' % (Version.major(), Version.minor(), Version.patch(), Version.suffix()) + + @staticmethod + def vc_rev(): + # Lazy load to ensure _local_repo_vc_revision() does not run before logger is set up + if Version.get_data()["release_vc_rev"] is None: + Version.data["release_vc_rev"] = Version._local_repo_vc_revision() + return Version.get_data()["release_vc_rev"] + + @staticmethod + def _local_repo_vc_revision(): + vc_command = ['git', 'rev-parse', 'HEAD'] + cmdname = vc_command[0] + + try: + vc = subprocess.Popen( + vc_command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + (stdout, stderr) = vc.communicate() + + if vc.returncode != 0: + logging.debug('Error getting rev from %s - %d (%s)', + cmdname, vc.returncode, stderr) + return 'unknown' + + rev = str(stdout).strip() + logging.debug('%s reported revision %s', cmdname, rev) + + return '%s:%s' % (cmdname, rev) + except OSError as e: + logging.debug('Error getting rev from %s - %s' % (cmdname, e.strerror)) + return 'unknown' + + + +class SourcePaths(object): + """ + A collection of paths defined by the project structure and + independent of user configurations. + All paths are relative to the base_dir, which may be relative as well (e.g. ".") + """ + + def __init__(self, base_dir): + self.base_dir = base_dir + self.doc_dir = os.path.join(self.base_dir, 'doc') + self.src_dir = os.path.join(self.base_dir, 'src') + + # dirs in src/ + self.build_data_dir = os.path.join(self.src_dir, 'build-data') + self.configs_dir = os.path.join(self.src_dir, 'configs') + self.lib_dir = os.path.join(self.src_dir, 'lib') + self.python_dir = os.path.join(self.src_dir, 'python') + self.scripts_dir = os.path.join(self.src_dir, 'scripts') + + # subdirs of src/ + self.test_data_dir = os.path.join(self.src_dir, 'tests/data') + self.sphinx_config_dir = os.path.join(self.configs_dir, 'sphinx') + + +class BuildPaths(object): # pylint: disable=too-many-instance-attributes + """ + Constructor + """ + def __init__(self, source_paths, options, modules): + self.build_dir = os.path.join(options.with_build_dir, 'build') + + self.libobj_dir = os.path.join(self.build_dir, 'obj', 'lib') + self.cliobj_dir = os.path.join(self.build_dir, 'obj', 'cli') + self.testobj_dir = os.path.join(self.build_dir, 'obj', 'test') + + self.doc_output_dir = os.path.join(self.build_dir, 'docs') + self.handbook_output_dir = os.path.join(self.doc_output_dir, 'handbook') + self.doc_output_dir_doxygen = os.path.join(self.doc_output_dir, 'doxygen') if options.with_doxygen else None + + self.include_dir = os.path.join(self.build_dir, 'include') + self.botan_include_dir = os.path.join(self.include_dir, 'botan') + self.internal_include_dir = os.path.join(self.botan_include_dir, 'internal') + self.external_include_dir = os.path.join(self.include_dir, 'external') + + self.internal_headers = sorted(flatten([m.internal_headers() for m in modules])) + self.external_headers = sorted(flatten([m.external_headers() for m in modules])) + + # this is overwritten if amalgamation is used + self.lib_sources = [normalize_source_path(s) for s in sorted(flatten([mod.sources() for mod in modules]))] + + self.public_headers = sorted(flatten([m.public_headers() for m in modules])) + + def find_sources_in(basedir, srcdir): + for (dirpath, _, filenames) in os.walk(os.path.join(basedir, srcdir)): + for filename in filenames: + if filename.endswith('.cpp') and not filename.startswith('.'): + yield os.path.join(dirpath, filename) + + def find_headers_in(basedir, srcdir): + for (dirpath, _, filenames) in os.walk(os.path.join(basedir, srcdir)): + for filename in filenames: + if filename.endswith('.h') and not filename.startswith('.'): + yield os.path.join(dirpath, filename) + + self.cli_sources = [normalize_source_path(s) for s in find_sources_in(source_paths.src_dir, 'cli')] + self.cli_headers = [normalize_source_path(s) for s in find_headers_in(source_paths.src_dir, 'cli')] + self.test_sources = [normalize_source_path(s) for s in find_sources_in(source_paths.src_dir, 'tests')] + + if options.build_fuzzers: + self.fuzzer_sources = list(find_sources_in(source_paths.src_dir, 'fuzzer')) + self.fuzzer_output_dir = os.path.join(self.build_dir, 'fuzzer') + self.fuzzobj_dir = os.path.join(self.build_dir, 'obj', 'fuzzer') + else: + self.fuzzer_sources = None + self.fuzzer_output_dir = None + self.fuzzobj_dir = None + + def build_dirs(self): + out = [ + self.libobj_dir, + self.cliobj_dir, + self.testobj_dir, + self.botan_include_dir, + self.internal_include_dir, + self.external_include_dir, + self.handbook_output_dir, + ] + if self.doc_output_dir_doxygen: + out += [self.doc_output_dir_doxygen] + if self.fuzzer_output_dir: + out += [self.fuzzobj_dir] + out += [self.fuzzer_output_dir] + return out + + def format_include_paths(self, cc, external_includes): + dash_i = cc.add_include_dir_option + output = dash_i + self.include_dir + if self.external_headers: + output += ' ' + dash_i + self.external_include_dir + for external_include in external_includes: + output += ' ' + dash_i + external_include + return output + + def src_info(self, typ): + if typ == 'lib': + return (self.lib_sources, self.libobj_dir) + elif typ == 'cli': + return (self.cli_sources, self.cliobj_dir) + elif typ == 'test': + return (self.test_sources, self.testobj_dir) + elif typ == 'fuzzer': + return (self.fuzzer_sources, self.fuzzobj_dir) + else: + raise InternalError("Unknown src info type '%s'" % (typ)) + +ACCEPTABLE_BUILD_TARGETS = ["static", "shared", "cli", "tests", "bogo_shim"] + +def process_command_line(args): # pylint: disable=too-many-locals,too-many-statements + """ + Handle command line options + Do not use logging in this method as command line options need to be + available before logging is setup. + """ + + parser = optparse.OptionParser( + formatter=optparse.IndentedHelpFormatter(max_help_position=50), + version=Version.as_string()) + + parser.add_option('--verbose', action='store_true', default=False, + help='Show debug messages') + parser.add_option('--quiet', action='store_true', default=False, + help='Show only warnings and errors') + + target_group = optparse.OptionGroup(parser, 'Target options') + + target_group.add_option('--cpu', help='set the target CPU architecture') + + target_group.add_option('--os', help='set the target operating system') + + target_group.add_option('--cc', dest='compiler', help='set the desired build compiler') + + target_group.add_option('--cc-min-version', dest='cc_min_version', default=None, + metavar='MAJOR.MINOR', + help='Set the minimal version of the target compiler. ' \ + 'Use --cc-min-version=0.0 to support all compiler versions. ' \ + 'Default is auto detection.') + + target_group.add_option('--cc-bin', dest='compiler_binary', metavar='BINARY', + help='set path to compiler binary') + + target_group.add_option('--cc-abi-flags', metavar='FLAGS', default='', + help='set compiler ABI flags') + + target_group.add_option('--cxxflags', metavar='FLAGS', default=None, + help='override all compiler flags') + + target_group.add_option('--extra-cxxflags', metavar='FLAGS', default=[], action='append', + help='set extra compiler flags') + + target_group.add_option('--ldflags', metavar='FLAGS', + help='set linker flags', default=None) + + target_group.add_option('--extra-libs', metavar='LIBS', + help='specify extra libraries to link against', default='') + + target_group.add_option('--ar-command', dest='ar_command', metavar='AR', default=None, + help='set path to static archive creator') + + target_group.add_option('--ar-options', dest='ar_options', metavar='AR_OPTIONS', default=None, + help='set options for ar') + + target_group.add_option('--msvc-runtime', metavar='RT', default=None, + help='specify MSVC runtime (MT, MD, MTd, MDd)') + + target_group.add_option('--compiler-cache', + help='specify a compiler cache to use') + + target_group.add_option('--with-endian', metavar='ORDER', default=None, + help='override byte order guess') + + target_group.add_option('--with-os-features', action='append', metavar='FEAT', + help='specify OS features to use') + target_group.add_option('--without-os-features', action='append', metavar='FEAT', + help='specify OS features to disable') + + isa_extensions = [ + 'SSE2', 'SSSE3', 'SSE4.1', 'SSE4.2', 'AVX2', 'BMI2', 'RDRAND', 'RDSEED', + 'AES-NI', 'SHA-NI', + 'AltiVec', 'NEON', 'ARMv8 Crypto', 'POWER Crypto'] + + for isa_extn_name in isa_extensions: + isa_extn = isa_extn_name.lower().replace(' ', '') + + target_group.add_option('--disable-%s' % (isa_extn), + help='disable %s intrinsics' % (isa_extn_name), + action='append_const', + const=isa_extn.replace('-', '').replace('.', '').replace(' ', ''), + dest='disable_intrinsics') + + build_group = optparse.OptionGroup(parser, 'Build options') + + build_group.add_option('--system-cert-bundle', metavar='PATH', default=None, + help='set path to trusted CA bundle') + + build_group.add_option('--with-debug-info', action='store_true', default=False, dest='with_debug_info', + help='include debug symbols') + + build_group.add_option('--with-sanitizers', action='store_true', default=False, dest='with_sanitizers', + help='enable ASan/UBSan checks') + + build_group.add_option('--enable-sanitizers', metavar='SAN', default='', + help='enable specific sanitizers') + + build_group.add_option('--with-stack-protector', dest='with_stack_protector', + action='store_false', default=None, help=optparse.SUPPRESS_HELP) + + build_group.add_option('--without-stack-protector', dest='with_stack_protector', + action='store_false', help='disable stack smashing protections') + + build_group.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage', + help='add coverage info and disable opts') + + build_group.add_option('--with-coverage-info', action='store_true', default=False, dest='with_coverage_info', + help='add coverage info') + + build_group.add_option('--enable-shared-library', dest='build_shared_lib', + action='store_true', default=None, + help=optparse.SUPPRESS_HELP) + build_group.add_option('--disable-shared-library', dest='build_shared_lib', + action='store_false', + help='disable building shared library') + + build_group.add_option('--enable-static-library', dest='build_static_lib', + action='store_true', default=None, + help=optparse.SUPPRESS_HELP) + build_group.add_option('--disable-static-library', dest='build_static_lib', + action='store_false', + help='disable building static library') + + build_group.add_option('--optimize-for-size', dest='optimize_for_size', + action='store_true', default=False, + help='optimize for code size') + + build_group.add_option('--no-optimizations', dest='no_optimizations', + action='store_true', default=False, + help='disable all optimizations (for debugging)') + + build_group.add_option('--debug-mode', action='store_true', default=False, dest='debug_mode', + help='enable debug info, disable optimizations') + + build_group.add_option('--amalgamation', dest='amalgamation', + default=False, action='store_true', + help='use amalgamation to build') + + build_group.add_option('--name-amalgamation', metavar='NAME', default='botan_all', + help='specify alternate name for amalgamation files') + + build_group.add_option('--with-build-dir', metavar='DIR', default='', + help='setup the build in DIR') + + build_group.add_option('--with-external-includedir', metavar='DIR', default=[], + help='use DIR for external includes', action='append') + + build_group.add_option('--with-external-libdir', metavar='DIR', default=[], + help='use DIR for external libs', action='append') + + build_group.add_option('--define-build-macro', metavar='DEFINE', default=[], + help='set compile-time pre-processor definition like KEY[=VALUE]', action='append') + + build_group.add_option('--with-sysroot-dir', metavar='DIR', default='', + help='use DIR for system root while cross-compiling') + + build_group.add_option('--with-openmp', default=False, action='store_true', + help='enable use of OpenMP') + + link_methods = ['symlink', 'hardlink', 'copy'] + build_group.add_option('--link-method', default=None, metavar='METHOD', + choices=link_methods, + help='choose how links to include headers are created (%s)' % ', '.join(link_methods)) + + build_group.add_option('--with-local-config', + dest='local_config', metavar='FILE', + help='include the contents of FILE into build.h') + + build_group.add_option('--distribution-info', metavar='STRING', + help='distribution specific version', + default='unspecified') + + build_group.add_option('--maintainer-mode', dest='maintainer_mode', + action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--werror-mode', dest='werror_mode', + action='store_true', default=False, + help="Prohibit compiler warnings") + + build_group.add_option('--no-store-vc-rev', action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--no-install-python-module', action='store_true', default=False, + help='skip installing Python module') + + build_group.add_option('--with-python-versions', dest='python_version', + metavar='N.M', + default='%d.%d' % (sys.version_info[0], sys.version_info[1]), + help='where to install botan2.py (def %default)') + + build_group.add_option('--disable-cc-tests', dest='enable_cc_tests', + default=True, action='store_false', + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-valgrind', help='use valgrind API', + dest='with_valgrind', action='store_true', default=False) + + # Cmake and bakefile options are hidden as they should not be used by end users + build_group.add_option('--with-cmake', action='store_true', + default=False, help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-bakefile', action='store_true', + default=False, help=optparse.SUPPRESS_HELP) + + build_group.add_option('--unsafe-fuzzer-mode', action='store_true', default=False, + help='Disable essential checks for testing') + + build_group.add_option('--build-fuzzers', dest='build_fuzzers', + metavar='TYPE', default=None, + help='Build fuzzers (afl, libfuzzer, klee, test)') + + build_group.add_option('--with-fuzzer-lib', metavar='LIB', default=None, dest='fuzzer_lib', + help='additionally link in LIB') + + build_group.add_option('--test-mode', action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-debug-asserts', action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + + build_group.add_option('--build-targets', default=None, dest="build_targets", action='append', + help="build specific targets and tools (%s)" % ', '.join(ACCEPTABLE_BUILD_TARGETS)) + + build_group.add_option('--with-pkg-config', action='store_true', default=None, + help=optparse.SUPPRESS_HELP) + build_group.add_option('--without-pkg-config', dest='with_pkg_config', action='store_false', + help=optparse.SUPPRESS_HELP) + build_group.add_option('--boost-library-name', dest='boost_libnames', default=[], + help="file name of some boost library to link", action='append') + + docs_group = optparse.OptionGroup(parser, 'Documentation Options') + + docs_group.add_option('--with-documentation', action='store_true', + help=optparse.SUPPRESS_HELP) + + docs_group.add_option('--without-documentation', action='store_false', + default=True, dest='with_documentation', + help='Skip building/installing documentation') + + docs_group.add_option('--with-sphinx', action='store_true', + default=None, help='Use Sphinx') + + docs_group.add_option('--without-sphinx', action='store_false', + dest='with_sphinx', help=optparse.SUPPRESS_HELP) + + docs_group.add_option('--with-pdf', action='store_true', + default=False, help='Use Sphinx to generate PDF doc') + + docs_group.add_option('--without-pdf', action='store_false', + dest='with_pdf', help=optparse.SUPPRESS_HELP) + + docs_group.add_option('--with-rst2man', action='store_true', + default=None, help='Use rst2man to generate man page') + + docs_group.add_option('--without-rst2man', action='store_false', + dest='with_rst2man', help=optparse.SUPPRESS_HELP) + + docs_group.add_option('--with-doxygen', action='store_true', + default=False, help='Use Doxygen') + + docs_group.add_option('--without-doxygen', action='store_false', + dest='with_doxygen', help=optparse.SUPPRESS_HELP) + + mods_group = optparse.OptionGroup(parser, 'Module selection') + + mods_group.add_option('--module-policy', dest='module_policy', + help="module policy file (see src/build-data/policy)", + metavar='POL', default=None) + + mods_group.add_option('--enable-modules', dest='enabled_modules', + metavar='MODS', action='append', + help='enable specific modules') + mods_group.add_option('--disable-modules', dest='disabled_modules', + metavar='MODS', action='append', + help='disable specific modules') + mods_group.add_option('--no-autoload', action='store_true', default=False, + help=optparse.SUPPRESS_HELP) + mods_group.add_option('--minimized-build', action='store_true', dest='no_autoload', + help='minimize build') + + # Should be derived from info.txt but this runs too early + third_party = ['boost', 'bzip2', 'lzma', 'openssl', 'commoncrypto', 'sqlite3', 'zlib', 'tpm'] + + for mod in third_party: + mods_group.add_option('--with-%s' % (mod), + help=('use %s' % (mod)) if mod in third_party else optparse.SUPPRESS_HELP, + action='append_const', + const=mod, + dest='enabled_modules') + + mods_group.add_option('--without-%s' % (mod), + help=optparse.SUPPRESS_HELP, + action='append_const', + const=mod, + dest='disabled_modules') + + mods_group.add_option('--with-everything', help=optparse.SUPPRESS_HELP, + action='store_true', default=False) + + install_group = optparse.OptionGroup(parser, 'Installation options') + + install_group.add_option('--program-suffix', metavar='SUFFIX', + help='append string to program names') + install_group.add_option('--library-suffix', metavar='SUFFIX', default='', + help='append string to library names') + + install_group.add_option('--prefix', metavar='DIR', + help='set the install prefix') + install_group.add_option('--docdir', metavar='DIR', + help='set the doc install dir') + install_group.add_option('--bindir', metavar='DIR', + help='set the binary install dir') + install_group.add_option('--libdir', metavar='DIR', + help='set the library install dir') + install_group.add_option('--mandir', metavar='DIR', + help='set the install dir for man pages') + install_group.add_option('--includedir', metavar='DIR', + help='set the include file install dir') + + info_group = optparse.OptionGroup(parser, 'Informational') + + info_group.add_option('--list-modules', dest='list_modules', + action='store_true', + help='list available modules and exit') + + info_group.add_option('--list-os-features', dest='list_os_features', + action='store_true', + help='list available OS features and exit') + + parser.add_option_group(target_group) + parser.add_option_group(build_group) + parser.add_option_group(docs_group) + parser.add_option_group(mods_group) + parser.add_option_group(install_group) + parser.add_option_group(info_group) + + # These exist only for autoconf compatibility (requested by zw for mtn) + compat_with_autoconf_options = [ + 'datadir', + 'datarootdir', + 'dvidir', + 'exec-prefix', + 'htmldir', + 'infodir', + 'libexecdir', + 'localedir', + 'localstatedir', + 'oldincludedir', + 'pdfdir', + 'psdir', + 'sbindir', + 'sharedstatedir', + 'sysconfdir' + ] + + for opt in compat_with_autoconf_options: + parser.add_option('--' + opt, help=optparse.SUPPRESS_HELP) + + (options, args) = parser.parse_args(args) + + if args != []: + raise UserError('Unhandled option(s): ' + ' '.join(args)) + + if options.with_endian not in [None, 'little', 'big']: + raise UserError('Bad value to --with-endian "%s"' % (options.with_endian)) + + if options.debug_mode: + options.no_optimizations = True + options.with_debug_info = True + + if options.with_coverage: + options.with_coverage_info = True + options.no_optimizations = True + + def parse_multiple_enable(modules): + if modules is None: + return [] + + return sorted({m for m in flatten([s.split(',') for s in modules]) if m != ''}) + + options.enabled_modules = parse_multiple_enable(options.enabled_modules) + options.disabled_modules = parse_multiple_enable(options.disabled_modules) + + options.with_os_features = parse_multiple_enable(options.with_os_features) + options.without_os_features = parse_multiple_enable(options.without_os_features) + + options.disable_intrinsics = parse_multiple_enable(options.disable_intrinsics) + + return options + +def take_options_from_env(options): + # Take some values from environment, if not set on command line + + def update_from_env(val, var, name): + if val is None: + val = os.getenv(var) + if val is not None: + logging.info('Implicit --%s=%s due to environment variable %s', name, val, var) + + return val + + if os.getenv('CXX') and options.compiler_binary is None and options.compiler is not None: + logging.info('CXX environment variable is set which will override compiler path') + + options.ar_command = update_from_env(options.ar_command, 'AR', 'ar-command') + options.ar_options = update_from_env(options.ar_options, 'AR_OPTIONS', 'ar-options') + options.compiler_binary = update_from_env(options.compiler_binary, 'CXX', 'cc-bin') + options.cxxflags = update_from_env(options.cxxflags, 'CXXFLAGS', 'cxxflags') + options.ldflags = update_from_env(options.ldflags, 'LDFLAGS', 'ldflags') + +class LexResult(object): + pass + + +class LexerError(InternalError): + def __init__(self, msg, lexfile, line): + super(LexerError, self).__init__(msg) + self.msg = msg + self.lexfile = lexfile + self.line = line + + def __str__(self): + return '%s at %s:%d' % (self.msg, self.lexfile, self.line) + +def parse_lex_dict(as_list, map_name, infofile): + if len(as_list) % 3 != 0: + raise InternalError("Lex dictionary has invalid format (input not divisible by 3): %s" % as_list) + + result = {} + for key, sep, value in [as_list[3*i:3*i+3] for i in range(0, len(as_list)//3)]: + if sep != '->': + raise InternalError("Map %s in %s has invalid format" % (map_name, infofile)) + if key in result: + raise InternalError("Duplicate map entry %s in map %s file %s" % (key, map_name, infofile)) + result[key] = value + return result + +def lex_me_harder(infofile, allowed_groups, allowed_maps, name_val_pairs): + """ + Generic lexer function for info.txt and src/build-data files + """ + out = LexResult() + + # Format as a nameable Python variable + def py_var(group): + return group.replace(':', '_') + + lexer = shlex.shlex(open(infofile), infofile, posix=True) + lexer.wordchars += '=:.<>/,-!?+*' # handle various funky chars in info.txt + + groups = allowed_groups + allowed_maps + for group in groups: + out.__dict__[py_var(group)] = [] + for (key, val) in name_val_pairs.items(): + out.__dict__[key] = val + + def lexed_tokens(): # Convert to an iterator + while True: + token = lexer.get_token() + if token != lexer.eof: + yield token + else: + return + + for token in lexed_tokens(): + match = re.match('<(.*)>', token) + + # Check for a grouping + if match is not None: + group = match.group(1) + + if group not in groups: + raise LexerError('Unknown group "%s"' % (group), + infofile, lexer.lineno) + + end_marker = '' + + token = lexer.get_token() + while token != end_marker: + out.__dict__[py_var(group)].append(token) + token = lexer.get_token() + if token is None: + raise LexerError('Group "%s" not terminated' % (group), + infofile, lexer.lineno) + + elif token in name_val_pairs.keys(): + if isinstance(out.__dict__[token], list): + out.__dict__[token].append(lexer.get_token()) + else: + out.__dict__[token] = lexer.get_token() + + else: # No match -> error + raise LexerError('Bad token "%s"' % (token), infofile, lexer.lineno) + + for group in allowed_maps: + out.__dict__[group] = parse_lex_dict(out.__dict__[group], group, infofile) + + return out + +class InfoObject(object): + def __init__(self, infofile): + """ + Constructor sets members `infofile`, `lives_in`, `parent_module` and `basename` + """ + + self.infofile = infofile + (dirname, basename) = os.path.split(infofile) + self.lives_in = dirname + if basename == 'info.txt': + (obj_dir, self.basename) = os.path.split(dirname) + if os.access(os.path.join(obj_dir, 'info.txt'), os.R_OK): + self.parent_module = os.path.basename(obj_dir) + else: + self.parent_module = None + else: + self.basename = basename.replace('.txt', '') + + +class ModuleInfo(InfoObject): + """ + Represents the information about a particular module + """ + + def __init__(self, infofile): + # pylint: disable=too-many-statements + super(ModuleInfo, self).__init__(infofile) + lex = lex_me_harder( + infofile, + ['header:internal', 'header:public', 'header:external', 'requires', + 'os_features', 'arch', 'isa', 'cc', 'comment', 'warning'], + ['defines', 'libs', 'frameworks'], + { + 'load_on': 'auto', + 'endian': 'any', + }) + + def check_header_duplicates(header_list_public, header_list_internal): + pub_header = set(header_list_public) + int_header = set(header_list_internal) + if not pub_header.isdisjoint(int_header): + logging.error("Module %s header contains same header in public and internal sections" % self.infofile) + + check_header_duplicates(lex.header_public, lex.header_internal) + + all_source_files = [] + all_header_files = [] + + for fspath in os.listdir(self.lives_in): + if fspath.endswith('.cpp'): + all_source_files.append(fspath) + elif fspath.endswith('.h'): + all_header_files.append(fspath) + + self.source = all_source_files + + # If not entry for the headers, all are assumed public + if lex.header_internal == [] and lex.header_public == []: + self.header_public = list(all_header_files) + self.header_internal = [] + else: + self.header_public = lex.header_public + self.header_internal = lex.header_internal + self.header_external = lex.header_external + + def convert_lib_list(libs): + out = {} + for (os_name, lib_list) in libs.items(): + out[os_name] = lib_list.split(',') + return out + + def combine_lines(c): + return ' '.join(c) if c else None + + # Convert remaining lex result to members + self.arch = lex.arch + self.cc = lex.cc + self.comment = combine_lines(lex.comment) + self._defines = lex.defines + self._validate_defines_content(self._defines) + self.frameworks = convert_lib_list(lex.frameworks) + self.libs = convert_lib_list(lex.libs) + self.load_on = lex.load_on + self.isa = lex.isa + self.os_features = lex.os_features + self.requires = lex.requires + self.warning = combine_lines(lex.warning) + self.endian = lex.endian + + # Modify members + self.source = [normalize_source_path(os.path.join(self.lives_in, s)) for s in self.source] + self.header_internal = [os.path.join(self.lives_in, s) for s in self.header_internal] + self.header_public = [os.path.join(self.lives_in, s) for s in self.header_public] + self.header_external = [os.path.join(self.lives_in, s) for s in self.header_external] + + # Filesystem read access check + for src in self.source + self.header_internal + self.header_public + self.header_external: + if not os.access(src, os.R_OK): + logging.error("Missing file %s in %s" % (src, infofile)) + + # Check for duplicates + def intersect_check(type_a, list_a, type_b, list_b): + intersection = set.intersection(set(list_a), set(list_b)) + if intersection: + logging.error('Headers %s marked both %s and %s' % (' '.join(intersection), type_a, type_b)) + + intersect_check('public', self.header_public, 'internal', self.header_internal) + intersect_check('public', self.header_public, 'external', self.header_external) + intersect_check('external', self.header_external, 'internal', self.header_internal) + + @staticmethod + def _validate_defines_content(defines): + for key, value in defines.items(): + if not re.match('^[0-9A-Za-z_]{3,30}$', key): + raise InternalError('Module defines key has invalid format: "%s"' % key) + if not re.match('^20[0-9]{6}$', value): + raise InternalError('Module defines value has invalid format: "%s"' % value) + + def cross_check(self, arch_info, cc_info, all_os_features, all_isa_extn): + + for feat in set(flatten([o.split(',') for o in self.os_features])): + if feat not in all_os_features: + logging.error("Module %s uses an OS feature (%s) which no OS supports", self.infofile, feat) + + for supp_cc in self.cc: + if supp_cc not in cc_info: + colon_idx = supp_cc.find(':') + # a versioned compiler dependency + if colon_idx > 0 and supp_cc[0:colon_idx] in cc_info: + pass + else: + raise InternalError('Module %s mentions unknown compiler %s' % (self.infofile, supp_cc)) + + for supp_arch in self.arch: + if supp_arch not in arch_info: + raise InternalError('Module %s mentions unknown arch %s' % (self.infofile, supp_arch)) + + def known_isa(isa): + if isa in all_isa_extn: + return True + + compound_isa = isa.split(':') + if len(compound_isa) == 2 and compound_isa[0] in arch_info and compound_isa[1] in all_isa_extn: + return True + return False + + for isa in self.isa: + if not known_isa(isa): + raise InternalError('Module %s uses unknown ISA extension %s' % (self.infofile, isa)) + + def sources(self): + return self.source + + def public_headers(self): + return self.header_public + + def internal_headers(self): + return self.header_internal + + def external_headers(self): + return self.header_external + + def isas_needed(self, arch): + isas = [] + + for isa in self.isa: + if isa.find(':') == -1: + isas.append(isa) + elif isa.startswith(arch + ':'): + isas.append(isa[len(arch)+1:]) + + return isas + + def defines(self): + return [(key + ' ' + value) for key, value in self._defines.items()] + + def compatible_cpu(self, archinfo, options): + arch_name = archinfo.basename + cpu_name = options.cpu + + if self.endian != 'any': + if self.endian != options.with_endian: + return False + + for isa in self.isa: + if isa.find(':') > 0: + (arch, isa) = isa.split(':') + + if arch != arch_name: + continue + + if isa in options.disable_intrinsics: + return False # explicitly disabled + + if isa not in archinfo.isa_extensions: + return False + + if self.arch != []: + if arch_name not in self.arch and cpu_name not in self.arch: + return False + + return True + + def compatible_os(self, os_data, options): + if not self.os_features: + return True + + def has_all(needed, provided): + for n in needed: + if n not in provided: + return False + return True + + provided_features = os_data.enabled_features(options) + + for feature_set in self.os_features: + if has_all(feature_set.split(','), provided_features): + return True + + return False + + def compatible_compiler(self, ccinfo, cc_min_version, arch): + # Check if this compiler supports the flags we need + def supported_isa_flags(ccinfo, arch): + for isa in self.isa: + if ccinfo.isa_flags_for(isa, arch) is None: + return False + return True + + # Check if module gives explicit compiler dependencies + def supported_compiler(ccinfo, cc_min_version): + if self.cc == []: + # no compiler restriction + return True + + if ccinfo.basename in self.cc: + # compiler is supported, independent of version + return True + + # Maybe a versioned compiler dep + for cc in self.cc: + try: + name, version = cc.split(":") + if name == ccinfo.basename: + min_cc_version = [int(v) for v in version.split('.')] + cur_cc_version = [int(v) for v in cc_min_version.split('.')] + # With lists of ints, this does what we want + return cur_cc_version >= min_cc_version + except ValueError: + # No version part specified + pass + + return False # compiler not listed + + return supported_isa_flags(ccinfo, arch) and supported_compiler(ccinfo, cc_min_version) + + def dependencies(self, osinfo): + # base is an implicit dep for all submodules + deps = ['base'] + if self.parent_module is not None: + deps.append(self.parent_module) + + for req in self.requires: + if req.find('?') != -1: + (cond, dep) = req.split('?') + if osinfo is None or cond in osinfo.target_features: + deps.append(dep) + else: + deps.append(req) + + return deps + + def dependencies_exist(self, modules): + """ + Ensure that all dependencies of this module actually exist, warning + about any that do not + """ + + missing = [s for s in self.dependencies(None) if s not in modules] + + if missing: + logging.error("Module '%s', dep of '%s', does not exist" % ( + missing, self.basename)) + + +class ModulePolicyInfo(InfoObject): + def __init__(self, infofile): + super(ModulePolicyInfo, self).__init__(infofile) + lex = lex_me_harder( + infofile, + ['required', 'if_available', 'prohibited'], + [], + {}) + + self.if_available = lex.if_available + self.required = lex.required + self.prohibited = lex.prohibited + + def cross_check(self, modules): + def check(tp, lst): + for mod in lst: + if mod not in modules: + logging.error("Module policy %s includes non-existent module %s in <%s>" % ( + self.infofile, mod, tp)) + + check('required', self.required) + check('if_available', self.if_available) + check('prohibited', self.prohibited) + + +class ArchInfo(InfoObject): + def __init__(self, infofile): + super(ArchInfo, self).__init__(infofile) + lex = lex_me_harder( + infofile, + ['aliases', 'isa_extensions'], + [], + { + 'endian': None, + 'family': None, + 'wordsize': 32 + }) + + self.aliases = lex.aliases + self.endian = lex.endian + self.family = lex.family + self.isa_extensions = lex.isa_extensions + self.wordsize = int(lex.wordsize) + + if self.wordsize not in [32, 64]: + logging.error('Unexpected wordsize %d for arch %s', self.wordsize, infofile) + + alphanumeric = re.compile('^[a-z0-9]+$') + for isa in self.isa_extensions: + if alphanumeric.match(isa) is None: + logging.error('Invalid name for ISA extension "%s"', isa) + + def supported_isa_extensions(self, cc, options): + isas = [] + + for isa in self.isa_extensions: + if isa not in options.disable_intrinsics: + if cc.isa_flags_for(isa, self.basename) is not None: + isas.append(isa) + + return sorted(isas) + + +class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes + def __init__(self, infofile): + super(CompilerInfo, self).__init__(infofile) + lex = lex_me_harder( + infofile, + [], + ['cpu_flags', 'cpu_flags_no_debug', 'so_link_commands', 'binary_link_commands', + 'mach_abi_linking', 'isa_flags', 'sanitizers', 'lib_flags'], + { + 'binary_name': None, + 'linker_name': None, + 'macro_name': None, + 'output_to_object': '-o ', + 'output_to_exe': '-o ', + 'add_include_dir_option': '-I', + 'add_lib_dir_option': '-L', + 'add_compile_definition_option': '-D', + 'add_sysroot_option': '', + 'add_lib_option': '-l%s', + 'add_framework_option': '-framework ', + 'preproc_flags': '-E', + 'compile_flags': '-c', + 'debug_info_flags': '-g', + 'optimization_flags': '', + 'size_optimization_flags': '', + 'sanitizer_optimization_flags': '', + 'coverage_flags': '', + 'stack_protector_flags': '', + 'shared_flags': '', + 'lang_flags': '', + 'warning_flags': '', + 'maintainer_warning_flags': '', + 'visibility_build_flags': '', + 'visibility_attribute': '', + 'ar_command': '', + 'ar_options': '', + 'ar_output_to': '', + 'werror_flags': '', + }) + + self.add_framework_option = lex.add_framework_option + self.add_include_dir_option = lex.add_include_dir_option + self.add_lib_dir_option = lex.add_lib_dir_option + self.add_lib_option = lex.add_lib_option + self.add_compile_definition_option = lex.add_compile_definition_option + self.add_sysroot_option = lex.add_sysroot_option + self.ar_command = lex.ar_command + self.ar_options = lex.ar_options + self.ar_output_to = lex.ar_output_to + self.binary_link_commands = lex.binary_link_commands + self.binary_name = lex.binary_name + self.cpu_flags = lex.cpu_flags + self.cpu_flags_no_debug = lex.cpu_flags_no_debug + self.compile_flags = lex.compile_flags + self.coverage_flags = lex.coverage_flags + self.debug_info_flags = lex.debug_info_flags + self.isa_flags = lex.isa_flags + self.lang_flags = lex.lang_flags + self.lib_flags = lex.lib_flags + self.linker_name = lex.linker_name + self.mach_abi_linking = lex.mach_abi_linking + self.macro_name = lex.macro_name + self.maintainer_warning_flags = lex.maintainer_warning_flags + self.optimization_flags = lex.optimization_flags + self.output_to_exe = lex.output_to_exe + self.output_to_object = lex.output_to_object + self.preproc_flags = lex.preproc_flags + self.sanitizers = lex.sanitizers + self.sanitizer_types = [] + self.sanitizer_optimization_flags = lex.sanitizer_optimization_flags + self.shared_flags = lex.shared_flags + self.size_optimization_flags = lex.size_optimization_flags + self.so_link_commands = lex.so_link_commands + self.stack_protector_flags = lex.stack_protector_flags + self.visibility_attribute = lex.visibility_attribute + self.visibility_build_flags = lex.visibility_build_flags + self.warning_flags = lex.warning_flags + self.werror_flags = lex.werror_flags + + def cross_check(self, os_info, arch_info, all_isas): + + for isa in self.isa_flags: + if ":" in isa: + (arch, isa) = isa.split(":") + if isa not in all_isas: + raise InternalError('Compiler %s has flags for unknown ISA %s' % (self.infofile, isa)) + if arch not in arch_info: + raise InternalError('Compiler %s has flags for unknown arch/ISA %s:%s' % (self.infofile, arch, isa)) + + for os_name in self.binary_link_commands: + if os_name in ["default", "default-debug"]: + continue + if os_name not in os_info: + raise InternalError("Compiler %s has binary_link_command for unknown OS %s" % (self.infofile, os_name)) + + for os_name in self.so_link_commands: + if os_name in ["default", "default-debug"]: + continue + if os_name not in os_info: + raise InternalError("Compiler %s has so_link_command for unknown OS %s" % (self.infofile, os_name)) + + def isa_flags_for(self, isa, arch): + if isa.find(':') > 0: + (isa_arch, isa) = isa.split(':') + if isa_arch != arch: + return '' + if isa in self.isa_flags: + return self.isa_flags[isa] + + if isa in self.isa_flags: + return self.isa_flags[isa] + arch_isa = '%s:%s' % (arch, isa) + if arch_isa in self.isa_flags: + return self.isa_flags[arch_isa] + + return None + + def get_isa_specific_flags(self, isas, arch, options): + flags = set() + + def simd32_impl(): + for simd_isa in ['sse2', 'altivec', 'neon']: + if simd_isa in arch.isa_extensions and \ + simd_isa not in options.disable_intrinsics and \ + self.isa_flags_for(simd_isa, arch.basename): + return simd_isa + return None + + for isa in isas: + + if isa == 'simd': + isa = simd32_impl() + + if isa is None: + continue + + flagset = self.isa_flags_for(isa, arch.basename) + if flagset is None: + raise UserError('Compiler %s does not support %s' % (self.basename, isa)) + flags.add(flagset) + + return " ".join(sorted(flags)) + + def gen_lib_flags(self, options, variables): + """ + Return any flags specific to building the library + (vs the cli or tests) + """ + + def flag_builder(): + if options.build_shared_lib: + yield self.shared_flags + yield self.visibility_build_flags + + if 'debug' in self.lib_flags and options.with_debug_info: + yield process_template_string(self.lib_flags['debug'], variables, self.infofile) + + + return ' '.join(list(flag_builder())) + + def gen_visibility_attribute(self, options): + if options.build_shared_lib: + return self.visibility_attribute + return '' + + def mach_abi_link_flags(self, options, debug_mode=None): + #pylint: disable=too-many-branches + + """ + Return the machine specific ABI flags + """ + + if debug_mode is None: + debug_mode = options.debug_mode + + def mach_abi_groups(): + + yield 'all' + + if options.msvc_runtime is None: + if debug_mode: + yield 'rt-debug' + else: + yield 'rt' + + for all_except in [s for s in self.mach_abi_linking.keys() if s.startswith('all!')]: + exceptions = all_except[4:].split(',') + if options.os not in exceptions and options.arch not in exceptions: + yield all_except + + yield options.os + yield options.cpu + + abi_link = set() + for what in mach_abi_groups(): + if what in self.mach_abi_linking: + flag = self.mach_abi_linking.get(what) + if flag is not None and flag != '' and flag not in abi_link: + abi_link.add(flag) + + if options.msvc_runtime: + abi_link.add("/" + options.msvc_runtime) + + if options.with_stack_protector and self.stack_protector_flags != '': + abi_link.add(self.stack_protector_flags) + + if options.with_coverage_info: + if self.coverage_flags == '': + raise UserError('No coverage handling for %s' % (self.basename)) + abi_link.add(self.coverage_flags) + + if options.with_sanitizers or options.enable_sanitizers != '': + if not self.sanitizers: + raise UserError('No sanitizer handling for %s' % (self.basename)) + + default_san = self.sanitizers['default'].split(',') + + if options.enable_sanitizers: + san = options.enable_sanitizers.split(',') + else: + san = default_san + + for s in san: + if s not in self.sanitizers: + raise UserError('No flags defined for sanitizer %s in %s' % (s, self.basename)) + + if s == 'default': + abi_link.update([self.sanitizers[x] for x in default_san]) + else: + abi_link.add(self.sanitizers[s]) + + self.sanitizer_types = san + + if options.with_openmp: + if 'openmp' not in self.mach_abi_linking: + raise UserError('No support for OpenMP for %s' % (self.basename)) + abi_link.add(self.mach_abi_linking['openmp']) + + abi_flags = ' '.join(sorted(abi_link)) + + if options.cc_abi_flags != '': + abi_flags += ' ' + options.cc_abi_flags + + return abi_flags + + def cc_warning_flags(self, options): + def gen_flags(): + yield self.warning_flags + if options.werror_mode or options.maintainer_mode: + yield self.werror_flags + if options.maintainer_mode: + yield self.maintainer_warning_flags + + return (' '.join(gen_flags())).strip() + + def cc_lang_flags(self): + return self.lang_flags + + def cc_compile_flags(self, options, with_debug_info=None, enable_optimizations=None): + #pylint: disable=too-many-branches + + def gen_flags(with_debug_info, enable_optimizations): + + sanitizers_enabled = options.with_sanitizers or (len(options.enable_sanitizers) > 0) + + if with_debug_info is None: + with_debug_info = options.with_debug_info + if enable_optimizations is None: + enable_optimizations = not options.no_optimizations + + if with_debug_info: + yield self.debug_info_flags + + if enable_optimizations: + if options.optimize_for_size: + if self.size_optimization_flags != '': + yield self.size_optimization_flags + else: + logging.warning("No size optimization flags set for current compiler") + yield self.optimization_flags + elif sanitizers_enabled and self.sanitizer_optimization_flags != '': + yield self.sanitizer_optimization_flags + else: + yield self.optimization_flags + + if options.arch in self.cpu_flags: + yield self.cpu_flags[options.arch] + + if options.arch in self.cpu_flags_no_debug: + + # Only enable these if no debug/sanitizer options enabled + + if not (options.debug_mode or sanitizers_enabled): + yield self.cpu_flags_no_debug[options.arch] + + for flag in options.extra_cxxflags: + yield flag + + for definition in options.define_build_macro: + yield self.add_compile_definition_option + definition + + return (' '.join(gen_flags(with_debug_info, enable_optimizations))).strip() + + @staticmethod + def _so_link_search(osname, debug_info): + so_link_typ = [osname, 'default'] + if debug_info: + so_link_typ = [l + '-debug' for l in so_link_typ] + so_link_typ + return so_link_typ + + def so_link_command_for(self, osname, options): + """ + Return the command needed to link a shared object + """ + + for s in self._so_link_search(osname, options.with_debug_info): + if s in self.so_link_commands: + return self.so_link_commands[s] + + raise InternalError( + "No shared library link command found for target '%s' in compiler settings '%s'" % + (osname, self.infofile)) + + def binary_link_command_for(self, osname, options): + """ + Return the command needed to link an app/test object + """ + + for s in self._so_link_search(osname, options.with_debug_info): + if s in self.binary_link_commands: + return self.binary_link_commands[s] + + return '$(LINKER)' + +class OsInfo(InfoObject): # pylint: disable=too-many-instance-attributes + def __init__(self, infofile): + super(OsInfo, self).__init__(infofile) + lex = lex_me_harder( + infofile, + ['aliases', 'target_features', 'feature_macros'], + [], + { + 'program_suffix': '', + 'obj_suffix': 'o', + 'soname_suffix': '', + 'soname_pattern_patch': '', + 'soname_pattern_abi': '', + 'soname_pattern_base': '', + 'static_suffix': 'a', + 'ar_command': 'ar', + 'ar_options': '', + 'ar_output_to': '', + 'install_root': '/usr/local', + 'header_dir': 'include', + 'bin_dir': 'bin', + 'lib_dir': 'lib', + 'doc_dir': 'share/doc', + 'man_dir': 'share/man', + 'use_stack_protector': 'true', + 'cli_exe_name': 'botan', + 'lib_prefix': 'lib', + 'library_name': 'botan{suffix}-{major}', + 'shared_lib_symlinks': 'yes', + 'default_compiler': 'gcc', + 'uses_pkg_config': 'yes', + }) + + if lex.ar_command == 'ar' and lex.ar_options == '': + lex.ar_options = 'crs' + + if lex.soname_pattern_base: + self.soname_pattern_base = lex.soname_pattern_base + if lex.soname_pattern_patch == '' and lex.soname_pattern_abi == '': + self.soname_pattern_patch = lex.soname_pattern_base + self.soname_pattern_abi = lex.soname_pattern_base + elif lex.soname_pattern_patch != '' and lex.soname_pattern_abi != '': + self.soname_pattern_patch = lex.soname_pattern_patch + self.soname_pattern_abi = lex.soname_pattern_abi + else: + # base set, only one of patch/abi set + raise InternalError("Invalid soname_patterns in %s" % (self.infofile)) + else: + if lex.soname_suffix: + self.soname_pattern_base = "libbotan{lib_suffix}-{version_major}.%s" % (lex.soname_suffix) + self.soname_pattern_abi = self.soname_pattern_base + ".{abi_rev}" + self.soname_pattern_patch = self.soname_pattern_abi + ".{version_minor}.{version_patch}" + else: + # Could not calculate soname_pattern_* + # This happens for OSs without shared library support (e.g. nacl, mingw, includeos, cygwin) + self.soname_pattern_base = None + self.soname_pattern_abi = None + self.soname_pattern_patch = None + + self._aliases = lex.aliases + self.ar_command = lex.ar_command + self.ar_options = lex.ar_options + self.bin_dir = lex.bin_dir + self.cli_exe_name = lex.cli_exe_name + self.doc_dir = lex.doc_dir + self.header_dir = lex.header_dir + self.install_root = lex.install_root + self.lib_dir = lex.lib_dir + self.lib_prefix = lex.lib_prefix + self.library_name = lex.library_name + self.man_dir = lex.man_dir + self.obj_suffix = lex.obj_suffix + self.program_suffix = lex.program_suffix + self.static_suffix = lex.static_suffix + self.target_features = lex.target_features + self.use_stack_protector = (lex.use_stack_protector == "true") + self.shared_lib_uses_symlinks = (lex.shared_lib_symlinks == 'yes') + self.default_compiler = lex.default_compiler + self.uses_pkg_config = (lex.uses_pkg_config == 'yes') + self.feature_macros = lex.feature_macros + + def matches_name(self, nm): + if nm in self._aliases: + return True + + for alias in self._aliases: + if re.match(alias, nm): + return True + return False + + def building_shared_supported(self): + return self.soname_pattern_base is not None + + def enabled_features(self, options): + feats = [] + for feat in self.target_features: + if feat not in options.without_os_features: + feats.append(feat) + for feat in options.with_os_features: + if feat not in self.target_features: + feats.append(feat) + + return sorted(feats) + + def macros(self, cc): + value = [cc.add_compile_definition_option + define + for define in self.feature_macros] + + return ' '.join(value) + +def fixup_proc_name(proc): + proc = proc.lower().replace(' ', '') + for junk in ['(tm)', '(r)']: + proc = proc.replace(junk, '') + return proc + +def canon_processor(archinfo, proc): + proc = fixup_proc_name(proc) + + # First, try to search for an exact match + for ainfo in archinfo.values(): + if ainfo.basename == proc or proc in ainfo.aliases: + return ainfo.basename + + return None + +def system_cpu_info(): + + cpu_info = [] + + if platform.machine() != '': + cpu_info.append(platform.machine()) + + if platform.processor() != '': + cpu_info.append(platform.processor()) + + if 'uname' in os.__dict__: + cpu_info.append(os.uname()[4]) + + return cpu_info + +def guess_processor(archinfo): + for info_part in system_cpu_info(): + if info_part: + match = canon_processor(archinfo, info_part) + if match is not None: + logging.debug("Matched '%s' to processor '%s'" % (info_part, match)) + return match, info_part + else: + logging.debug("Failed to deduce CPU from '%s'" % info_part) + + raise UserError('Could not determine target CPU; set with --cpu') + + +def read_textfile(filepath): + """ + Read a whole file into memory as a string + """ + if filepath is None: + return '' + + with open(filepath) as f: + return ''.join(f.readlines()) + + +def process_template_string(template_text, variables, template_source): + # pylint: disable=too-many-branches,too-many-statements + + """ + Perform template substitution + + The template language supports (un-nested) conditionals. + """ + class SimpleTemplate(object): + + def __init__(self, vals): + self.vals = vals + self.value_pattern = re.compile(r'%{([a-z][a-z_0-9\|]+)}') + self.cond_pattern = re.compile('%{(if|unless) ([a-z][a-z_0-9]+)}') + self.for_pattern = re.compile('(.*)%{for ([a-z][a-z_0-9]+)}') + self.join_pattern = re.compile('(.*)%{join ([a-z][a-z_0-9]+)}') + + def substitute(self, template): + # pylint: disable=too-many-locals + def insert_value(match): + v = match.group(1) + if v in self.vals: + return str(self.vals.get(v)) + if v.endswith('|upper'): + v = v.replace('|upper', '') + if v in self.vals: + return str(self.vals.get(v)).upper() + + raise KeyError(v) + + lines = template.splitlines() + + output = "" + idx = 0 + + while idx < len(lines): + cond_match = self.cond_pattern.match(lines[idx]) + join_match = self.join_pattern.match(lines[idx]) + for_match = self.for_pattern.match(lines[idx]) + + if cond_match: + cond_type = cond_match.group(1) + cond_var = cond_match.group(2) + + include_cond = False + + if cond_type == 'if' and cond_var in self.vals and self.vals.get(cond_var): + include_cond = True + elif cond_type == 'unless' and (cond_var not in self.vals or (not self.vals.get(cond_var))): + include_cond = True + + idx += 1 + while idx < len(lines): + if lines[idx] == '%{endif}': + break + if include_cond: + output += lines[idx] + "\n" + idx += 1 + elif join_match: + join_var = join_match.group(2) + join_str = ' ' + join_line = '%%{join %s}' % (join_var) + output += lines[idx].replace(join_line, join_str.join(self.vals[join_var])) + "\n" + elif for_match: + for_prefix = for_match.group(1) + output += for_prefix + for_var = for_match.group(2) + + if for_var not in self.vals: + raise InternalError("Unknown for loop iteration variable '%s'" % (for_var)) + + var = self.vals[for_var] + if not isinstance(var, list): + raise InternalError("For loop iteration variable '%s' is not a list" % (for_var)) + idx += 1 + + for_body = "" + while idx < len(lines): + if lines[idx] == '%{endfor}': + break + for_body += lines[idx] + "\n" + idx += 1 + + for v in var: + if isinstance(v, dict): + for_val = for_body + for ik, iv in v.items(): + for_val = for_val.replace('%{' + ik + '}', iv) + output += for_val + "\n" + else: + output += for_body.replace('%{i}', v).replace('%{i|upper}', v.upper()) + output += "\n" + else: + output += lines[idx] + "\n" + idx += 1 + + return self.value_pattern.sub(insert_value, output) + '\n' + + try: + return SimpleTemplate(variables).substitute(template_text) + except KeyError as e: + logging.error('Unbound var %s in template %s' % (e, template_source)) + except Exception as e: # pylint: disable=broad-except + logging.error('Exception %s during template processing file %s' % (e, template_source)) + +def process_template(template_file, variables): + return process_template_string(read_textfile(template_file), variables, template_file) + +def yield_objectfile_list(sources, obj_dir, obj_suffix, options): + obj_suffix = '.' + obj_suffix + + for src in sources: + (directory, filename) = os.path.split(os.path.normpath(src)) + parts = directory.split(os.sep) + + if 'src' in parts: + parts = parts[parts.index('src')+2:] + elif options.amalgamation and filename.find(options.name_amalgamation) != -1: + parts = [] + else: + raise InternalError("Unexpected file '%s/%s'" % (directory, filename)) + + if parts != []: + # Handle src/X/X.cpp -> X.o + if filename == parts[-1] + '.cpp': + name = '_'.join(parts) + '.cpp' + else: + name = '_'.join(parts) + '_' + filename + + def fixup_obj_name(name): + def remove_dups(parts): + last = None + for part in parts: + if last is None or part != last: + last = part + yield part + + return '_'.join(remove_dups(name.split('_'))) + + name = fixup_obj_name(name) + else: + name = filename + + name = name.replace('.cpp', obj_suffix) + yield os.path.join(obj_dir, name) + +def generate_build_info(build_paths, modules, cc, arch, osinfo, options): + # pylint: disable=too-many-locals + + # first create a map of src_file->owning module + + module_that_owns = {} + + for mod in modules: + for src in mod.sources(): + module_that_owns[src] = mod + + def _isa_specific_flags(src): + if os.path.basename(src) == 'test_simd.cpp': + return cc.get_isa_specific_flags(['simd'], arch, options) + + if src in module_that_owns: + module = module_that_owns[src] + isas = module.isas_needed(arch.basename) + if 'simd' in module.dependencies(osinfo): + isas.append('simd') + + return cc.get_isa_specific_flags(isas, arch, options) + + return '' + + def _build_info(sources, objects, target_type): + output = [] + for (obj_file, src) in zip(objects, sources): + info = { + 'src': src, + 'obj': obj_file, + 'isa_flags': _isa_specific_flags(src) + } + + if target_type == 'fuzzer': + fuzz_basename = os.path.basename(obj_file).replace('.' + osinfo.obj_suffix, '') + info['exe'] = os.path.join(build_paths.fuzzer_output_dir, fuzz_basename) + + output.append(info) + + return output + + out = {} + + targets = ['lib', 'cli', 'test', 'fuzzer'] + + out['isa_build_info'] = [] + + fuzzer_bin = [] + for t in targets: + src_list, src_dir = build_paths.src_info(t) + + src_key = '%s_srcs' % (t) + obj_key = '%s_objs' % (t) + build_key = '%s_build_info' % (t) + + objects = [] + build_info = [] + + if src_list is not None: + src_list.sort() + objects = list(yield_objectfile_list(src_list, src_dir, osinfo.obj_suffix, options)) + build_info = _build_info(src_list, objects, t) + + for b in build_info: + if b['isa_flags'] != '': + out['isa_build_info'].append(b) + + if t == 'fuzzer': + fuzzer_bin = [b['exe'] for b in build_info] + + out[src_key] = src_list if src_list else [] + out[obj_key] = objects + out[build_key] = build_info + + out['fuzzer_bin'] = ' '.join(fuzzer_bin) + out['cli_headers'] = build_paths.cli_headers + + return out + +def create_template_vars(source_paths, build_paths, options, modules, cc, arch, osinfo): + #pylint: disable=too-many-locals,too-many-branches,too-many-statements + + """ + Create the template variables needed to process the makefile, build.h, etc + """ + + def external_link_cmd(): + return ' '.join([cc.add_lib_dir_option + libdir for libdir in options.with_external_libdir]) + + def adjust_library_name(info_txt_libname): + """ + Apply custom library name mappings where necessary + """ + + # potentially map boost library names to the associated name provided + # via ./configure.py --boost-library-name + # + # We assume that info.txt contains the library name's "stem", i.e. + # 'boost_system'. While the user-provided (actual) library will contain + # the same stem plus a set of prefixes and/or suffixes, e.g. + # libboost_system-vc140-mt-x64-1_69.lib. We use the stem for selecting + # the correct user-provided library name override. + if options.boost_libnames and 'boost_' in info_txt_libname: + adjusted_libnames = [chosen_libname for chosen_libname in options.boost_libnames \ + if info_txt_libname in chosen_libname] + + if len(adjusted_libnames) > 1: + logging.warning('Ambiguous boost library names: %s' % ', '.join(adjusted_libnames)) + if len(adjusted_libnames) == 1: + logging.debug('Replacing boost library name %s -> %s' % (info_txt_libname, adjusted_libnames[0])) + return adjusted_libnames[0] + + return info_txt_libname + + def link_to(module_member_name): + """ + Figure out what external libraries/frameworks are needed based on selected modules + """ + if module_member_name not in ['libs', 'frameworks']: + raise InternalError("Invalid argument") + + libs = set() + for module in modules: + for (osname, module_link_to) in getattr(module, module_member_name).items(): + if osname in ['all', osinfo.basename]: + libs |= set(module_link_to) + else: + match = re.match('^all!(.*)', osname) + if match is not None: + exceptions = match.group(1).split(',') + if osinfo.basename not in exceptions: + libs |= set(module_link_to) + + return sorted([adjust_library_name(lib) for lib in libs]) + + def choose_mp_bits(): + mp_bits = arch.wordsize # allow command line override? + logging.debug('Using MP bits %d' % (mp_bits)) + return mp_bits + + def innosetup_arch(os_name, arch): + if os_name == 'windows': + inno_arch = {'x86_32': '', + 'x86_64': 'x64', + 'ia64': 'ia64'} + if arch in inno_arch: + return inno_arch[arch] + else: + logging.warning('Unknown arch %s in innosetup_arch' % (arch)) + return None + + def configure_command_line(): + # Cut absolute path from main executable (e.g. configure.py or python interpreter) + # to get the same result when configuring the same thing on different machines + main_executable = os.path.basename(sys.argv[0]) + return ' '.join([main_executable] + sys.argv[1:]) + + def cmake_escape(s): + return s.replace('(', '\\(').replace(')', '\\)') + + def sysroot_option(): + if options.with_sysroot_dir == '': + return '' + if cc.add_sysroot_option == '': + logging.error("This compiler doesn't support --sysroot option") + return cc.add_sysroot_option + options.with_sysroot_dir + + def ar_command(): + if options.ar_command: + return options.ar_command + + if cc.ar_command: + if cc.ar_command == cc.binary_name: + return options.compiler_binary or cc.binary_name + else: + return cc.ar_command + + return osinfo.ar_command + + build_dir = options.with_build_dir or os.path.curdir + program_suffix = options.program_suffix or osinfo.program_suffix + + def join_with_build_dir(path): + # For some unknown reason MinGW doesn't like ./foo + if build_dir == os.path.curdir and options.os == 'mingw': + return path + return os.path.join(build_dir, path) + + def all_targets(options): + yield 'libs' + if 'cli' in options.build_targets: + yield 'cli' + if 'tests' in options.build_targets: + yield 'tests' + if options.build_fuzzers: + yield 'fuzzers' + if 'bogo_shim' in options.build_targets: + yield 'bogo_shim' + if options.with_documentation: + yield 'docs' + + def install_targets(options): + yield 'libs' + if 'cli' in options.build_targets: + yield 'cli' + if options.with_documentation: + yield 'docs' + + def absolute_install_dir(p): + if os.path.isabs(p): + return p + return os.path.join(options.prefix or osinfo.install_root, p) + + def choose_python_exe(): + exe = sys.executable + + if options.os == 'mingw': # mingw doesn't handle the backslashes in the absolute path well + return exe.replace('\\', '/') + + return exe + + def choose_cxx_exe(): + cxx = options.compiler_binary or cc.binary_name + + if options.compiler_cache is None: + return cxx + else: + return '%s %s' % (options.compiler_cache, cxx) + + def extra_libs(libs, cc): + if libs is None: + return '' + + return ' '.join([(cc.add_lib_option % lib) for lib in libs.split(',') if lib != '']) + + variables = { + 'version_major': Version.major(), + 'version_minor': Version.minor(), + 'version_patch': Version.patch(), + 'version_suffix': Version.suffix(), + 'version_vc_rev': 'unknown' if options.no_store_vc_rev else Version.vc_rev(), + 'abi_rev': Version.so_rev(), + + 'version': Version.as_string(), + 'release_type': Version.release_type(), + 'version_datestamp': Version.datestamp(), + + 'distribution_info': options.distribution_info, + + 'macos_so_compat_ver': '%s.%s.0' % (Version.packed(), Version.so_rev()), + 'macos_so_current_ver': '%s.%s.%s' % (Version.packed(), Version.so_rev(), Version.patch()), + + 'all_targets': ' '.join(all_targets(options)), + 'install_targets': ' '.join(install_targets(options)), + + 'public_headers': sorted([os.path.basename(h) for h in build_paths.public_headers]), + 'internal_headers': sorted([os.path.basename(h) for h in build_paths.internal_headers]), + 'external_headers': sorted([os.path.basename(h) for h in build_paths.external_headers]), + + 'abs_root_dir': os.path.dirname(os.path.realpath(__file__)), + + 'base_dir': source_paths.base_dir, + 'src_dir': source_paths.src_dir, + 'test_data_dir': source_paths.test_data_dir, + 'doc_dir': source_paths.doc_dir, + 'scripts_dir': normalize_source_path(source_paths.scripts_dir), + 'python_dir': source_paths.python_dir, + + 'cli_exe_name': osinfo.cli_exe_name + program_suffix, + 'cli_exe': join_with_build_dir(osinfo.cli_exe_name + program_suffix), + 'build_cli_exe': bool('cli' in options.build_targets), + 'test_exe': join_with_build_dir('botan-test' + program_suffix), + + 'lib_prefix': osinfo.lib_prefix, + 'static_suffix': osinfo.static_suffix, + 'lib_suffix': options.library_suffix, + 'libname': osinfo.library_name.format(major=Version.major(), + minor=Version.minor(), + suffix=options.library_suffix), + + 'command_line': configure_command_line(), + 'local_config': read_textfile(options.local_config), + + 'program_suffix': program_suffix, + + 'prefix': options.prefix or osinfo.install_root, + 'bindir': absolute_install_dir(options.bindir or osinfo.bin_dir), + 'libdir': absolute_install_dir(options.libdir or osinfo.lib_dir), + 'mandir': options.mandir or osinfo.man_dir, + 'includedir': options.includedir or osinfo.header_dir, + 'docdir': options.docdir or osinfo.doc_dir, + + 'with_documentation': options.with_documentation, + 'with_sphinx': options.with_sphinx, + 'with_pdf': options.with_pdf, + 'with_rst2man': options.with_rst2man, + 'sphinx_config_dir': source_paths.sphinx_config_dir, + 'with_doxygen': options.with_doxygen, + 'maintainer_mode': options.maintainer_mode, + + 'out_dir': build_dir, + 'build_dir': build_paths.build_dir, + + 'doc_stamp_file': os.path.join(build_paths.build_dir, 'doc.stamp'), + 'makefile_path': os.path.join(build_paths.build_dir, '..', 'Makefile'), + + 'build_static_lib': options.build_static_lib, + 'build_shared_lib': options.build_shared_lib, + + 'build_fuzzers': options.build_fuzzers, + + 'build_coverage' : options.with_coverage_info or options.with_coverage, + + 'symlink_shared_lib': options.build_shared_lib and osinfo.shared_lib_uses_symlinks, + + 'libobj_dir': build_paths.libobj_dir, + 'cliobj_dir': build_paths.cliobj_dir, + 'testobj_dir': build_paths.testobj_dir, + 'fuzzobj_dir': build_paths.fuzzobj_dir, + + 'fuzzer_output_dir': build_paths.fuzzer_output_dir if build_paths.fuzzer_output_dir else '', + 'doc_output_dir': build_paths.doc_output_dir, + 'handbook_output_dir': build_paths.handbook_output_dir, + 'doc_output_dir_doxygen': build_paths.doc_output_dir_doxygen, + + 'compiler_include_dirs': '%s %s' % (build_paths.include_dir, build_paths.external_include_dir), + + 'os': options.os, + 'arch': options.arch, + 'compiler': options.compiler, + 'cpu_family': arch.family, + 'endian': options.with_endian, + 'cpu_is_64bit': arch.wordsize == 64, + + 'bakefile_arch': 'x86' if options.arch == 'x86_32' else 'x86_64', + + 'innosetup_arch': innosetup_arch(options.os, options.arch), + + 'mp_bits': choose_mp_bits(), + + 'python_exe': choose_python_exe(), + 'python_version': options.python_version, + 'install_python_module': not options.no_install_python_module, + + 'cxx': choose_cxx_exe(), + 'cxx_abi_flags': cc.mach_abi_link_flags(options), + 'linker': cc.linker_name or '$(CXX)', + 'make_supports_phony': osinfo.basename != 'windows', + + 'sanitizer_types' : sorted(cc.sanitizer_types), + + 'cc_compile_opt_flags': cc.cc_compile_flags(options, False, True), + 'cc_compile_debug_flags': cc.cc_compile_flags(options, True, False), + + # These are for CMake + 'cxx_abi_opt_flags': cc.mach_abi_link_flags(options, False), + 'cxx_abi_debug_flags': cc.mach_abi_link_flags(options, True), + + 'dash_o': cc.output_to_object, + 'dash_c': cc.compile_flags, + + 'cc_lang_flags': cc.cc_lang_flags(), + 'os_feature_macros': osinfo.macros(cc), + 'cc_sysroot': sysroot_option(), + 'cc_compile_flags': options.cxxflags or cc.cc_compile_flags(options), + 'ldflags': options.ldflags or '', + 'extra_libs': extra_libs(options.extra_libs, cc), + 'cc_warning_flags': cc.cc_warning_flags(options), + 'output_to_exe': cc.output_to_exe, + 'cc_macro': cc.macro_name, + + 'visibility_attribute': cc.gen_visibility_attribute(options), + + 'lib_link_cmd': cc.so_link_command_for(osinfo.basename, options), + 'exe_link_cmd': cc.binary_link_command_for(osinfo.basename, options), + 'external_link_cmd': external_link_cmd(), + + 'ar_command': ar_command(), + 'ar_options': options.ar_options or cc.ar_options or osinfo.ar_options, + 'ar_output_to': cc.ar_output_to, + + 'link_to': ' '.join( + [(cc.add_lib_option % lib) for lib in link_to('libs')] + + [cc.add_framework_option + fw for fw in link_to('frameworks')] + ), + + 'cmake_link_to': ' '.join( + link_to('libs') + + [('"' + cc.add_framework_option + fw + '"') for fw in link_to('frameworks')] + ), + + 'fuzzer_lib': (cc.add_lib_option % options.fuzzer_lib) if options.fuzzer_lib else '', + 'libs_used': [lib.replace('.lib', '') for lib in link_to('libs')], + + 'include_paths': build_paths.format_include_paths(cc, options.with_external_includedir), + 'module_defines': sorted(flatten([m.defines() for m in modules])), + + 'build_bogo_shim': bool('bogo_shim' in options.build_targets), + 'bogo_shim_src': os.path.join(source_paths.src_dir, 'bogo_shim', 'bogo_shim.cpp'), + + 'os_features': osinfo.enabled_features(options), + 'os_name': osinfo.basename, + 'cpu_features': arch.supported_isa_extensions(cc, options), + 'system_cert_bundle': options.system_cert_bundle, + + 'fuzzer_mode': options.unsafe_fuzzer_mode, + 'fuzzer_type': options.build_fuzzers.upper() if options.build_fuzzers else '', + + 'with_valgrind': options.with_valgrind, + 'with_openmp': options.with_openmp, + 'with_debug_asserts': options.with_debug_asserts, + 'test_mode': options.test_mode, + 'optimize_for_size': options.optimize_for_size, + + 'mod_list': sorted([m.basename for m in modules]) + } + + variables['installed_include_dir'] = os.path.join( + variables['prefix'], + variables['includedir'], + 'botan-%d' % (Version.major()), 'botan') + + if cc.basename == 'msvc' and variables['cxx_abi_flags'] != '': + # MSVC linker doesn't support/need the ABI options, + # just transfer them over to just the compiler invocations + variables['cc_compile_flags'] = '%s %s' % (variables['cxx_abi_flags'], variables['cc_compile_flags']) + variables['cxx_abi_flags'] = '' + + variables['lib_flags'] = cc.gen_lib_flags(options, variables) + variables['cmake_lib_flags'] = cmake_escape(variables['lib_flags']) + + if options.with_pkg_config: + variables['botan_pkgconfig'] = os.path.join(build_paths.build_dir, 'botan-%d.pc' % (Version.major())) + + # The name is always set because Windows build needs it + variables['static_lib_name'] = '%s%s.%s' % (variables['lib_prefix'], variables['libname'], + variables['static_suffix']) + + if options.build_shared_lib: + if osinfo.soname_pattern_base is not None: + variables['soname_base'] = osinfo.soname_pattern_base.format(**variables) + variables['shared_lib_name'] = variables['soname_base'] + + if osinfo.soname_pattern_abi is not None: + variables['soname_abi'] = osinfo.soname_pattern_abi.format(**variables) + variables['shared_lib_name'] = variables['soname_abi'] + + if osinfo.soname_pattern_patch is not None: + variables['soname_patch'] = osinfo.soname_pattern_patch.format(**variables) + + variables['lib_link_cmd'] = variables['lib_link_cmd'].format(**variables) + + lib_targets = [] + if options.build_static_lib: + lib_targets.append('static_lib_name') + if options.build_shared_lib: + lib_targets.append('shared_lib_name') + + variables['library_targets'] = ' '.join([join_with_build_dir(variables[t]) for t in lib_targets]) + + if options.os == 'llvm' or options.compiler == 'msvc': + # llvm-link and msvc require just naming the file directly + variables['link_to_botan'] = os.path.join(build_dir, variables['static_lib_name']) + else: + variables['link_to_botan'] = '%s%s %s' % (cc.add_lib_dir_option, build_dir, + (cc.add_lib_option % variables['libname'])) + + return variables + +class ModulesChooser(object): + """ + Determine which modules to load based on options, target, etc + """ + + def __init__(self, modules, module_policy, archinfo, osinfo, ccinfo, cc_min_version, options): + self._modules = modules + self._module_policy = module_policy + self._archinfo = archinfo + self._osinfo = osinfo + self._ccinfo = ccinfo + self._cc_min_version = cc_min_version + self._options = options + + self._maybe_dep = set() + self._to_load = set() + # string to set mapping with reasons as key and modules as value + self._not_using_because = collections.defaultdict(set) + + ModulesChooser._validate_dependencies_exist(self._modules) + ModulesChooser._validate_user_selection( + self._modules, self._options.enabled_modules, self._options.disabled_modules) + + def _check_usable(self, module, modname): + if not module.compatible_cpu(self._archinfo, self._options): + self._not_using_because['incompatible CPU'].add(modname) + return False + elif not module.compatible_os(self._osinfo, self._options): + self._not_using_because['incompatible OS'].add(modname) + return False + elif not module.compatible_compiler(self._ccinfo, self._cc_min_version, self._archinfo.basename): + self._not_using_because['incompatible compiler'].add(modname) + return False + return True + + @staticmethod + def _display_module_information_unused(skipped_modules): + for reason in sorted(skipped_modules.keys()): + disabled_mods = sorted(skipped_modules[reason]) + if disabled_mods: + logging.info('Skipping (%s): %s' % (reason, ' '.join(disabled_mods))) + + @staticmethod + def _display_module_information_to_load(all_modules, modules_to_load): + sorted_modules_to_load = sorted(modules_to_load) + + for modname in sorted_modules_to_load: + if all_modules[modname].comment: + logging.info('%s: %s' % (modname, all_modules[modname].comment)) + if all_modules[modname].warning: + logging.warning('%s: %s' % (modname, all_modules[modname].warning)) + if all_modules[modname].load_on == 'vendor': + logging.info('Enabling use of external dependency %s' % modname) + + if sorted_modules_to_load: + logging.info('Loading modules: %s', ' '.join(sorted_modules_to_load)) + else: + logging.error('This configuration disables every submodule and is invalid') + + @staticmethod + def _validate_state(used_modules, unused_modules): + for reason, unused_for_reason in unused_modules.items(): + intersection = unused_for_reason & used_modules + if intersection: + raise InternalError( + "Disabled modules (%s) and modules to load have common elements: %s" + % (reason, intersection)) + + @staticmethod + def _validate_dependencies_exist(modules): + for module in modules.values(): + module.dependencies_exist(modules) + + @staticmethod + def _validate_user_selection(modules, enabled_modules, disabled_modules): + for modname in enabled_modules: + if modname not in modules: + logging.error("Module not found: %s" % modname) + + for modname in disabled_modules: + if modname not in modules: + logging.warning("Disabled module not found: %s" % modname) + + def _handle_by_module_policy(self, modname, usable): + if self._module_policy is not None: + if modname in self._module_policy.required: + if not usable: + logging.error('Module policy requires module %s not usable on this platform' % (modname)) + elif modname in self._options.disabled_modules: + logging.error('Module %s was disabled but is required by policy' % (modname)) + self._to_load.add(modname) + return True + elif modname in self._module_policy.if_available: + if modname in self._options.disabled_modules: + self._not_using_because['disabled by user'].add(modname) + elif usable: + logging.debug('Enabling optional module %s' % (modname)) + self._to_load.add(modname) + return True + elif modname in self._module_policy.prohibited: + if modname in self._options.enabled_modules: + logging.error('Module %s was requested but is prohibited by policy' % (modname)) + self._not_using_because['prohibited by module policy'].add(modname) + return True + + return False + + @staticmethod + def resolve_dependencies(available_modules, dependency_table, module, loaded_modules=None): + """ + Parameters + - available_modules: modules to choose from. Constant. + - dependency_table: module to dependencies map. Constant. + - module: name of the module to resolve dependencies. Constant. + - loaded_modules: modules already loaded. Defensive copy in order to not change value for caller. + """ + if loaded_modules is None: + loaded_modules = set([]) + else: + loaded_modules = copy.copy(loaded_modules) + + if module not in available_modules: + return False, None + + loaded_modules.add(module) + for dependency in dependency_table[module]: + dependency_choices = set(dependency.split('|')) + + dependency_met = False + + if not set(dependency_choices).isdisjoint(loaded_modules): + dependency_met = True + else: + possible_mods = dependency_choices.intersection(available_modules) + + for mod in possible_mods: + ok, dependency_modules = ModulesChooser.resolve_dependencies( + available_modules, dependency_table, mod, loaded_modules) + if ok: + dependency_met = True + loaded_modules.add(mod) + loaded_modules.update(dependency_modules) + break + + if not dependency_met: + return False, None + + return True, loaded_modules + + def _modules_dependency_table(self): + out = {} + for modname in self._modules: + out[modname] = self._modules[modname].dependencies(self._osinfo) + return out + + def _resolve_dependencies_for_all_modules(self): + available_modules = set(self._to_load) | set(self._maybe_dep) + dependency_table = self._modules_dependency_table() + + successfully_loaded = set() + + for modname in self._to_load: + # This will try to recursively load all dependencies of modname + ok, modules = self.resolve_dependencies(available_modules, dependency_table, modname) + if ok: + successfully_loaded.add(modname) + successfully_loaded.update(modules) + else: + # Skip this module + pass + + self._not_using_because['dependency failure'].update(self._to_load - successfully_loaded) + self._to_load = successfully_loaded + self._maybe_dep -= successfully_loaded + + def _handle_by_load_on(self, module): # pylint: disable=too-many-branches + modname = module.basename + if module.load_on == 'never': + self._not_using_because['disabled as buggy'].add(modname) + elif module.load_on == 'request': + if self._options.with_everything: + self._to_load.add(modname) + else: + self._not_using_because['by request only'].add(modname) + elif module.load_on == 'vendor': + if self._options.with_everything: + self._to_load.add(modname) + else: + self._not_using_because['requires external dependency'].add(modname) + elif module.load_on == 'dep': + self._maybe_dep.add(modname) + + elif module.load_on == 'always': + self._to_load.add(modname) + + elif module.load_on == 'auto': + if self._options.no_autoload or self._module_policy is not None: + self._maybe_dep.add(modname) + else: + self._to_load.add(modname) + else: + logging.error('Unknown load_on %s in %s' % ( + module.load_on, modname)) + + def choose(self): + for (modname, module) in self._modules.items(): + usable = self._check_usable(module, modname) + + module_handled = self._handle_by_module_policy(modname, usable) + if module_handled: + continue + + if modname in self._options.disabled_modules: + self._not_using_because['disabled by user'].add(modname) + elif usable: + if modname in self._options.enabled_modules: + self._to_load.add(modname) # trust the user + else: + self._handle_by_load_on(module) + + if 'compression' in self._to_load: + # Confirm that we have at least one compression library enabled + # Otherwise we leave a lot of useless support code compiled in, plus a + # make_compressor call that always fails + if 'zlib' not in self._to_load and 'bzip2' not in self._to_load and 'lzma' not in self._to_load: + self._to_load.remove('compression') + self._not_using_because['no enabled compression schemes'].add('compression') + + self._resolve_dependencies_for_all_modules() + + for not_a_dep in self._maybe_dep: + self._not_using_because['not requested'].add(not_a_dep) + + ModulesChooser._validate_state(self._to_load, self._not_using_because) + ModulesChooser._display_module_information_unused(self._not_using_because) + ModulesChooser._display_module_information_to_load(self._modules, self._to_load) + + return self._to_load + +def choose_link_method(options): + """ + Choose the link method based on system availability and user request + """ + + req = options.link_method + + def useable_methods(): + + # Symbolic link support on Windows was introduced in Windows 6.0 (Vista) + # and Python 3.2. Furthermore, the SeCreateSymbolicLinkPrivilege is + # required in order to successfully create symlinks. So only try to use + # symlinks on Windows if explicitly requested. + + # MinGW declares itself as 'Windows' + host_is_windows = python_platform_identifier() in ['windows', 'cygwin'] + + if 'symlink' in os.__dict__: + if host_is_windows: + if req == 'symlink': + yield 'symlink' + else: + yield 'symlink' + + if 'link' in os.__dict__: + yield 'hardlink' + + yield 'copy' + + for method in useable_methods(): + if req is None or req == method: + logging.info('Using %s to link files into build dir ' \ + '(use --link-method to change)' % (method)) + return method + + logging.warning('Could not use link method "%s", will copy instead' % (req)) + return 'copy' + +def portable_symlink(file_path, target_dir, method): + """ + Copy or link the file, depending on what the platform offers + """ + + if not os.access(file_path, os.R_OK): + logging.warning('Missing file %s' % (file_path)) + return + + if method == 'symlink': + rel_file_path = os.path.relpath(file_path, start=target_dir) + os.symlink(rel_file_path, os.path.join(target_dir, os.path.basename(file_path))) + elif method == 'hardlink': + os.link(file_path, os.path.join(target_dir, os.path.basename(file_path))) + elif method == 'copy': + shutil.copy(file_path, target_dir) + else: + raise UserError('Unknown link method %s' % (method)) + + +class AmalgamationHelper(object): + # All include types may have trailing comment like e.g. '#include // IWYU pragma: export' + _any_include = re.compile(r'#include <(.*)>') + _botan_include = re.compile(r'#include ') + + # Only matches at the beginning of the line. By convention, this means that the include + # is not wrapped by condition macros + _unconditional_any_include = re.compile(r'^#include <(.*)>') + # stddef.h is included in ffi.h + _unconditional_std_include = re.compile(r'^#include <([^/\.]+|stddef.h)>') + + @staticmethod + def is_any_include(cpp_source_line): + match = AmalgamationHelper._any_include.search(cpp_source_line) + if match: + return match.group(1) + else: + return None + + @staticmethod + def is_botan_include(cpp_source_line): + match = AmalgamationHelper._botan_include.search(cpp_source_line) + if match: + return match.group(1) + else: + return None + + @staticmethod + def is_unconditional_any_include(cpp_source_line): + match = AmalgamationHelper._unconditional_any_include.search(cpp_source_line) + if match: + return match.group(1) + else: + return None + + @staticmethod + def is_unconditional_std_include(cpp_source_line): + match = AmalgamationHelper._unconditional_std_include.search(cpp_source_line) + if match: + return match.group(1) + else: + return None + + @staticmethod + def write_banner(fd): + fd.write("""/* +* Botan %s Amalgamation +* (C) 1999-2020 The Botan Authors +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +""" % (Version.as_string())) + + +class AmalgamationHeader(object): + def __init__(self, input_filepaths): + + self.included_already = set() + self.all_std_includes = set() + + self.file_contents = {} + for filepath in sorted(input_filepaths): + try: + contents = AmalgamationGenerator.read_header(filepath) + self.file_contents[os.path.basename(filepath)] = contents + except IOError as e: + logging.error('Error processing file %s for amalgamation: %s' % (filepath, e)) + + self.contents = '' + for name in sorted(self.file_contents): + self.contents += ''.join(list(self.header_contents(name))) + + self.header_includes = '' + for std_header in sorted(self.all_std_includes): + self.header_includes += '#include <%s>\n' % (std_header) + self.header_includes += '\n' + + def header_contents(self, name): + name = name.replace('internal/', '') + + if name in self.included_already: + return + + self.included_already.add(name) + + if name not in self.file_contents: + return + + depr_marker = 'BOTAN_DEPRECATED_HEADER(%s)\n' % (name) + if depr_marker in self.file_contents[name]: + logging.debug("Ignoring deprecated header %s", name) + return + + for line in self.file_contents[name]: + header = AmalgamationHelper.is_botan_include(line) + if header: + for c in self.header_contents(header): + yield c + else: + std_header = AmalgamationHelper.is_unconditional_std_include(line) + + if std_header: + self.all_std_includes.add(std_header) + else: + yield line + + def write_to_file(self, filepath, include_guard): + with open(filepath, 'w') as f: + AmalgamationHelper.write_banner(f) + f.write("\n#ifndef %s\n#define %s\n\n" % (include_guard, include_guard)) + f.write(self.header_includes) + f.write(self.contents) + f.write("\n#endif // %s\n" % (include_guard)) + + +class AmalgamationGenerator(object): + _header_guard_pattern = re.compile(r'^#define BOTAN_.*_H_\s*$') + _header_endif_pattern = re.compile(r'^#endif.*$') + + @staticmethod + def read_header(filepath): + encoding_kwords = {} + if sys.version_info[0] == 3: + encoding_kwords['encoding'] = 'utf8' + with open(filepath, **encoding_kwords) as f: + raw_content = f.readlines() + return AmalgamationGenerator.strip_header_goop(filepath, raw_content) + + @staticmethod + def strip_header_goop(header_name, header_lines): + lines = copy.copy(header_lines) # defensive copy + + start_header_guard_index = None + for index, line in enumerate(lines): + if AmalgamationGenerator._header_guard_pattern.match(line): + start_header_guard_index = index + break + if start_header_guard_index is None: + raise InternalError("No header guard start found in " + header_name) + + end_header_guard_index = None + for index, line in enumerate(lines): + if AmalgamationGenerator._header_endif_pattern.match(line): + end_header_guard_index = index # override with last found + if end_header_guard_index is None: + raise InternalError("No header guard end found in " + header_name) + + lines = lines[start_header_guard_index+1 : end_header_guard_index] + + # Strip leading and trailing empty lines + while lines[0].strip() == "": + lines = lines[1:] + while lines[-1].strip() == "": + lines = lines[0:-1] + + return lines + + def __init__(self, prefix, build_paths, modules, options): + self._filename_prefix = prefix + self._build_paths = build_paths + self._modules = modules + self._options = options + + def generate(self): + encoding_kwords = {} + if sys.version_info[0] == 3: + encoding_kwords['encoding'] = 'utf8' + + pub_header_amalag = AmalgamationHeader(self._build_paths.public_headers) + amalgamation_header_fsname = '%s.h' % (self._filename_prefix) + logging.info('Writing amalgamation header to %s' % (amalgamation_header_fsname)) + pub_header_amalag.write_to_file(amalgamation_header_fsname, "BOTAN_AMALGAMATION_H_") + + internal_headers_list = [] + + for hdr in self._build_paths.internal_headers: + internal_headers_list.append(hdr) + + # file descriptors for all `amalgamation_sources` + amalgamation_fsname = '%s.cpp' % (self._filename_prefix) + logging.info('Writing amalgamation source to %s' % (amalgamation_fsname)) + + amalgamation_file = open(amalgamation_fsname, 'w', **encoding_kwords) + + AmalgamationHelper.write_banner(amalgamation_file) + amalgamation_file.write('\n#include "%s"\n\n' % (amalgamation_header_fsname)) + + internal_headers = AmalgamationHeader(internal_headers_list) + amalgamation_file.write(internal_headers.header_includes) + amalgamation_file.write(internal_headers.contents) + + unconditional_headers = set([]) + + for mod in sorted(self._modules, key=lambda module: module.basename): + for src in sorted(mod.source): + with open(src, 'r', **encoding_kwords) as f: + for line in f: + if AmalgamationHelper.is_botan_include(line): + # Botan headers are inlined in amalgamation headers + continue + + if AmalgamationHelper.is_any_include(line) in unconditional_headers: + # This include (conditional or unconditional) was unconditionally added before + continue + + amalgamation_file.write(line) + unconditional_header = AmalgamationHelper.is_unconditional_any_include(line) + if unconditional_header: + unconditional_headers.add(unconditional_header) + + amalgamation_file.close() + + return ([amalgamation_fsname], [amalgamation_header_fsname]) + + +def have_program(program): + """ + Test for the existence of a program + """ + + def exe_test(path, program): + exe_file = os.path.join(path, program) + + if os.path.exists(exe_file) and os.access(exe_file, os.X_OK): + logging.debug('Found program %s in %s' % (program, path)) + return True + else: + return False + + exe_suffixes = ['', '.exe'] + + for path in os.environ['PATH'].split(os.pathsep): + for suffix in exe_suffixes: + if exe_test(path, program + suffix): + return True + + logging.debug('Program %s not found' % (program)) + return False + + +class BotanConfigureLogHandler(logging.StreamHandler, object): + def emit(self, record): + # Do the default stuff first + super(BotanConfigureLogHandler, self).emit(record) + # Exit script if and ERROR or worse occurred + if record.levelno >= logging.ERROR: + sys.exit(1) + + +def setup_logging(options): + if options.verbose: + log_level = logging.DEBUG + elif options.quiet: + log_level = logging.WARNING + else: + log_level = logging.INFO + + lh = BotanConfigureLogHandler(sys.stdout) + lh.setFormatter(logging.Formatter('%(levelname) 7s: %(message)s')) + logging.getLogger().addHandler(lh) + logging.getLogger().setLevel(log_level) + + +def load_info_files(search_dir, descr, filename_matcher, class_t): + info = {} + + def filename_matches(filename): + if isinstance(filename_matcher, str): + return filename == filename_matcher + else: + return filename_matcher.match(filename) is not None + + for (dirpath, _, filenames) in os.walk(search_dir): + for filename in filenames: + filepath = os.path.join(dirpath, filename) + if filename_matches(filename): + info_obj = class_t(filepath) + info[info_obj.basename] = info_obj + + if info: + infotxt_basenames = ' '.join(sorted(info.keys())) + logging.debug('Loaded %d %s files: %s' % (len(info), descr, infotxt_basenames)) + else: + logging.warning('Failed to load any %s files' % (descr)) + + return info + + +def load_build_data_info_files(source_paths, descr, subdir, class_t): + matcher = re.compile(r'[_a-z0-9]+\.txt$') + return load_info_files(os.path.join(source_paths.build_data_dir, subdir), descr, matcher, class_t) + + +# Workaround for Windows systems where antivirus is enabled GH #353 +def robust_rmtree(path, max_retries=5): + for _ in range(max_retries): + try: + shutil.rmtree(path) + return + except OSError: + time.sleep(0.1) + + # Final attempt, pass any exceptions up to caller. + shutil.rmtree(path) + + +# Workaround for Windows systems where antivirus is enabled GH #353 +def robust_makedirs(directory, max_retries=5): + for _ in range(max_retries): + try: + os.makedirs(directory) + return + except OSError as e: + if e.errno == errno.EEXIST: + raise + + time.sleep(0.1) + + # Final attempt, pass any exceptions up to caller. + os.makedirs(directory) + +def python_platform_identifier(): + system_from_python = platform.system().lower() + if re.match('^cygwin_.*', system_from_python): + return 'cygwin' + else: + return system_from_python + +# This is for otions that have --with-XYZ and --without-XYZ. If user does not +# set any of those, we choose a default here. +# Mutates `options` +def set_defaults_for_unset_options(options, info_arch, info_cc, info_os): # pylint: disable=too-many-branches + if options.os is None: + options.os = python_platform_identifier() + logging.info('Guessing target OS is %s (use --os to set)' % (options.os)) + + if options.os not in info_os: + def find_canonical_os_name(os_name_variant): + for (canonical_os_name, os_info) in info_os.items(): + if os_info.matches_name(os_name_variant): + return canonical_os_name + return os_name_variant # not found + options.os = find_canonical_os_name(options.os) + + def deduce_compiler_type_from_cc_bin(cc_bin): + if cc_bin.find('clang') != -1 or cc_bin in ['emcc', 'em++']: + return 'clang' + if cc_bin.find('-g++') != -1 or cc_bin.find('g++') != -1: + return 'gcc' + return None + + if options.compiler is None and options.compiler_binary is not None: + options.compiler = deduce_compiler_type_from_cc_bin(options.compiler_binary) + + if options.compiler is None: + logging.error("Could not figure out what compiler type '%s' is, use --cc to set" % ( + options.compiler_binary)) + + if options.compiler is None and options.os in info_os: + options.compiler = info_os[options.os].default_compiler + + if not have_program(info_cc[options.compiler].binary_name): + logging.error("Default compiler for system is %s but could not find binary '%s'; use --cc to set" % ( + options.compiler, info_cc[options.compiler].binary_name)) + + logging.info('Guessing to use compiler %s (use --cc or CXX to set)' % (options.compiler)) + + if options.cpu is None: + (arch, cpu) = guess_processor(info_arch) + options.arch = arch + options.cpu = cpu + logging.info('Guessing target processor is a %s (use --cpu to set)' % (options.arch)) + + # OpenBSD uses an old binutils that does not support AVX2 + if options.os == 'openbsd': + del info_cc['gcc'].isa_flags['avx2'] + + if options.with_documentation is True: + if options.with_sphinx is None and have_program('sphinx-build'): + logging.info('Found sphinx-build (use --without-sphinx to disable)') + options.with_sphinx = True + if options.with_rst2man is None and have_program('rst2man'): + logging.info('Found rst2man (use --without-rst2man to disable)') + options.with_rst2man = True + + if options.with_pkg_config is None and options.os in info_os: + options.with_pkg_config = info_os[options.os].uses_pkg_config + + if options.system_cert_bundle is None: + default_paths = [ + '/etc/ssl/certs/ca-certificates.crt', # Ubuntu, Debian, Arch, Gentoo + '/etc/pki/tls/certs/ca-bundle.crt', # RHEL + '/etc/ssl/ca-bundle.pem', # SuSE + '/etc/ssl/cert.pem', # OpenBSD, FreeBSD, Alpine + '/etc/certs/ca-certificates.crt', # Solaris + ] + + for path in default_paths: + if os.access(path, os.R_OK): + logging.info('Using %s as system certificate store', path) + options.system_cert_bundle = path + break + else: + if not os.access(options.system_cert_bundle, os.R_OK): + logging.warning('Provided system cert bundle path %s not found, ignoring', options.system_cert_bundle) + options.system_cert_bundle = None + +# Mutates `options` +def canonicalize_options(options, info_os, info_arch): + # pylint: disable=too-many-branches + + # canonical ARCH/CPU + options.arch = canon_processor(info_arch, options.cpu) + if options.arch is None: + raise UserError('Unknown or unidentifiable processor "%s"' % (options.cpu)) + + if options.cpu != options.arch: + logging.info('Canonicalized CPU target %s to %s', options.cpu, options.arch) + + # select and sanity check build targets + def canonicalize_build_targets(options): + # --build-targets was not provided: build default targets + if options.build_targets is None: + return ["cli", "tests"] + + # flatten the list of multiple --build-targets="" and comma separation + build_targets = [t.strip().lower() for ts in options.build_targets for t in ts.split(",")] + + # validate that all requested build targets are available + for build_target in build_targets: + if build_target not in ACCEPTABLE_BUILD_TARGETS: + raise UserError("unknown build target: %s" % build_target) + + # building the shared lib desired and without contradiction? + if options.build_shared_lib is None: + options.build_shared_lib = "shared" in build_targets + elif bool(options.build_shared_lib) != bool("shared" in build_targets): + raise UserError("inconsistent usage of --enable/disable-shared-library and --build-targets") + + # building the static lib desired and without contradiction? + if options.build_static_lib is None: + options.build_static_lib = "static" in build_targets + elif bool(options.build_static_lib) != bool("static" in build_targets): + raise UserError("inconsistent usage of --enable/disable-static-library and --build-targets") + + return build_targets + + options.build_targets = canonicalize_build_targets(options) + + shared_libs_supported = options.os in info_os and info_os[options.os].building_shared_supported() + + if not shared_libs_supported: + if options.build_shared_lib is True: + logging.warning('Shared libs not supported on %s, disabling shared lib support' % (options.os)) + options.build_shared_lib = False + elif options.build_shared_lib is None: + logging.info('Shared libs not supported on %s, disabling shared lib support' % (options.os)) + + if options.os == 'windows' and options.build_shared_lib is None and options.build_static_lib is None: + options.build_shared_lib = True + + if options.with_stack_protector is None: + if options.os in info_os: + options.with_stack_protector = info_os[options.os].use_stack_protector + + if options.build_shared_lib is None: + if options.os == 'windows' and options.build_static_lib: + pass + else: + options.build_shared_lib = shared_libs_supported + + if options.build_static_lib is None: + if options.os == 'windows' and options.build_shared_lib: + pass + else: + options.build_static_lib = True + + # Set default fuzzing lib + if options.build_fuzzers == 'libfuzzer' and options.fuzzer_lib is None: + options.fuzzer_lib = 'Fuzzer' + + if options.ldflags is not None: + extra_libs = [] + link_to_lib = re.compile('^-l(.*)') + for flag in options.ldflags.split(' '): + match = link_to_lib.match(flag) + if match: + extra_libs.append(match.group(1)) + + options.extra_libs += ','.join(extra_libs) + +# Checks user options for consistency +# This method DOES NOT change options on behalf of the user but explains +# why the given configuration does not work. +def validate_options(options, info_os, info_cc, available_module_policies): + # pylint: disable=too-many-branches,too-many-statements + + if options.name_amalgamation != 'botan_all': + if options.name_amalgamation == '': + raise UserError('Amalgamation basename must be non-empty') + + acceptable_name_re = re.compile('^[a-zA-Z0-9_]+$') + if acceptable_name_re.match(options.name_amalgamation) is None: + raise UserError("Amalgamation basename must match [a-zA-Z0-9_]+") + + if options.os == "java": + raise UserError("Jython detected: need --os and --cpu to set target") + + if options.os not in info_os: + raise UserError('Unknown OS "%s"; available options: %s' % ( + options.os, ' '.join(sorted(info_os.keys())))) + + if options.compiler not in info_cc: + raise UserError('Unknown compiler "%s"; available options: %s' % ( + options.compiler, ' '.join(sorted(info_cc.keys())))) + + if options.cc_min_version is not None and not re.match(r'^[0-9]+\.[0-9]+$', options.cc_min_version): + raise UserError("--cc-min-version must have the format MAJOR.MINOR") + + if options.module_policy and options.module_policy not in available_module_policies: + raise UserError("Unknown module set %s" % options.module_policy) + + if options.cpu == 'llvm' or options.os in ['llvm', 'emscripten']: + if options.compiler != 'clang': + raise UserError('LLVM target requires using Clang') + + if options.cpu != 'llvm': + raise UserError('LLVM target requires CPU target set to LLVM bitcode (llvm)') + + if options.os not in ['llvm', 'emscripten']: + raise UserError('Target OS is not an LLVM bitcode target') + + if options.build_fuzzers is not None: + if options.build_fuzzers not in ['libfuzzer', 'afl', 'klee', 'test']: + raise UserError('Bad value to --build-fuzzers') + + if options.build_fuzzers == 'klee' and options.os != 'llvm': + raise UserError('Building for KLEE requires targeting LLVM') + + if options.build_static_lib is False and options.build_shared_lib is False: + raise UserError('With both --disable-static-library and --disable-shared-library, nothing to do') + + if options.os == 'windows' and options.build_static_lib is True and options.build_shared_lib is True: + raise UserError('On Windows only one of static lib and DLL can be selected') + + if options.with_documentation is False: + if options.with_doxygen: + raise UserError('Using --with-doxygen plus --without-documentation makes no sense') + if options.with_sphinx: + raise UserError('Using --with-sphinx plus --without-documentation makes no sense') + if options.with_pdf: + raise UserError('Using --with-pdf plus --without-documentation makes no sense') + + if options.with_pdf and not options.with_sphinx: + raise UserError('Option --with-pdf requires --with-sphinx') + + if options.with_bakefile: + if options.os != 'windows' or options.compiler != 'msvc' or options.build_shared_lib is False: + raise UserError("Building via bakefile is only supported for MSVC DLL build") + + if options.arch not in ['x86_64', 'x86_32']: + raise UserError("Bakefile only supports x86 targets") + + # Warnings + if options.os == 'windows' and options.compiler != 'msvc': + logging.warning('The windows target is oriented towards MSVC; maybe you want --os=cygwin or --os=mingw') + + if options.msvc_runtime: + if options.compiler != 'msvc': + raise UserError("Makes no sense to specify MSVC runtime for %s" % (options.compiler)) + + if options.msvc_runtime not in ['MT', 'MD', 'MTd', 'MDd']: + logging.warning("MSVC runtime option '%s' not known", (options.msvc_runtime)) + +def run_compiler_preproc(options, ccinfo, source_file, default_return, extra_flags=None): + if extra_flags is None: + extra_flags = [] + + cc_bin = options.compiler_binary or ccinfo.binary_name + + cmd = cc_bin.split(' ') + ccinfo.preproc_flags.split(' ') + extra_flags + [source_file] + + try: + logging.debug("Running '%s'", ' '.join(cmd)) + stdout, _ = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True).communicate() + cc_output = stdout + except OSError as e: + logging.warning('Could not execute %s: %s' % (cmd, e)) + return default_return + + def cleanup_output(output): + return ('\n'.join([l for l in output.splitlines() if l.startswith('#') is False])).strip() + + return cleanup_output(cc_output) + +def calculate_cc_min_version(options, ccinfo, source_paths): + version_patterns = { + 'msvc': r'^ *MSVC ([0-9]{2})([0-9]{2})$', + 'gcc': r'^ *GCC ([0-9]+) ([0-9]+)$', + 'clang': r'^ *CLANG ([0-9]+) ([0-9]+)$', + 'xlc': r'^ *XLC ([0-9]+) ([0-9]+)$', + } + + unknown_pattern = r'UNKNOWN 0 0' + + if ccinfo.basename not in version_patterns: + logging.info("No compiler version detection available for %s" % (ccinfo.basename)) + return "0.0" + + detect_version_source = os.path.join(source_paths.build_data_dir, "detect_version.cpp") + + cc_output = run_compiler_preproc(options, ccinfo, detect_version_source, "0.0") + + if re.search(unknown_pattern, cc_output) is not None: + logging.warning('Failed to get version for %s from macro check' % (ccinfo.basename)) + return "0.0" + + match = re.search(version_patterns[ccinfo.basename], cc_output, flags=re.MULTILINE) + if match is None: + logging.warning("Tried to get %s version, but output '%s' does not match expected version format" % ( + ccinfo.basename, cc_output)) + return "0.0" + + major_version = int(match.group(1), 0) + minor_version = int(match.group(2), 0) + cc_version = "%d.%d" % (major_version, minor_version) + logging.info('Auto-detected compiler version %s' % (cc_version)) + + return cc_version + +def check_compiler_arch(options, ccinfo, archinfo, source_paths): + detect_version_source = os.path.join(source_paths.build_data_dir, 'detect_arch.cpp') + + abi_flags = ccinfo.mach_abi_link_flags(options).split(' ') + cc_output = run_compiler_preproc(options, ccinfo, detect_version_source, 'UNKNOWN', abi_flags).lower() + + if cc_output == '': + cc_output = run_compiler_preproc(options, ccinfo, detect_version_source, 'UNKNOWN').lower() + + if cc_output == 'unknown': + logging.warning('Unable to detect target architecture via compiler macro checks') + return None + + if cc_output not in archinfo: + # Should not happen + logging.warning("Error detecting compiler target arch: '%s'", cc_output) + return None + + logging.info('Auto-detected compiler arch %s' % (cc_output)) + return cc_output + +def do_io_for_build(cc, arch, osinfo, using_mods, build_paths, source_paths, template_vars, options): + # pylint: disable=too-many-locals,too-many-branches,too-many-statements + + try: + robust_rmtree(build_paths.build_dir) + except OSError as e: + if e.errno != errno.ENOENT: + logging.error('Problem while removing build dir: %s' % (e)) + + for build_dir in build_paths.build_dirs(): + try: + robust_makedirs(build_dir) + except OSError as e: + if e.errno != errno.EEXIST: + logging.error('Error while creating "%s": %s' % (build_dir, e)) + + def write_template(sink, template): + with open(sink, 'w') as f: + f.write(process_template(template, template_vars)) + + def in_build_dir(p): + return os.path.join(build_paths.build_dir, p) + def in_build_data(p): + return os.path.join(source_paths.build_data_dir, p) + + write_template(in_build_dir('build.h'), in_build_data('buildh.in')) + write_template(in_build_dir('botan.doxy'), in_build_data('botan.doxy.in')) + + if 'botan_pkgconfig' in template_vars: + write_template(template_vars['botan_pkgconfig'], in_build_data('botan.pc.in')) + + if options.os == 'windows': + write_template(in_build_dir('botan.iss'), in_build_data('innosetup.in')) + + link_method = choose_link_method(options) + + def link_headers(headers, visibility, directory): + logging.debug('Linking %d %s header files in %s' % (len(headers), visibility, directory)) + + for header_file in headers: + try: + portable_symlink(header_file, directory, link_method) + except OSError as e: + if e.errno != errno.EEXIST: + raise UserError('Error linking %s into %s: %s' % (header_file, directory, e)) + + link_headers(build_paths.public_headers, 'public', + build_paths.botan_include_dir) + + link_headers(build_paths.internal_headers, 'internal', + build_paths.internal_include_dir) + + link_headers(build_paths.external_headers, 'external', + build_paths.external_include_dir) + + if options.amalgamation: + (amalg_cpp_files, amalg_headers) = AmalgamationGenerator( + options.name_amalgamation, build_paths, using_mods, options).generate() + build_paths.lib_sources = amalg_cpp_files + template_vars['generated_files'] = ' '.join(amalg_cpp_files + amalg_headers) + + # Inserting an amalgamation generated using DLL visibility flags into a + # binary project will either cause errors (on Windows) or unnecessary overhead. + # Provide a hint + if options.build_shared_lib: + logging.warning('Unless you are building a DLL or .so from the amalgamation, use --disable-shared as well') + + template_vars.update(generate_build_info(build_paths, using_mods, cc, arch, osinfo, options)) + + with open(os.path.join(build_paths.build_dir, 'build_config.json'), 'w') as f: + json.dump(template_vars, f, sort_keys=True, indent=2) + + if options.with_cmake: + logging.warning("CMake build is only for development: use make for production builds") + cmake_template = os.path.join(source_paths.build_data_dir, 'cmake.in') + write_template('CMakeLists.txt', cmake_template) + elif options.with_bakefile: + logging.warning("Bakefile build is only for development: use make for production builds") + bakefile_template = os.path.join(source_paths.build_data_dir, 'bakefile.in') + write_template('botan.bkl', bakefile_template) + else: + makefile_template = os.path.join(source_paths.build_data_dir, 'makefile.in') + write_template(template_vars['makefile_path'], makefile_template) + + if options.with_rst2man: + rst2man_file = os.path.join(build_paths.build_dir, 'botan.rst') + cli_doc = os.path.join(source_paths.doc_dir, 'cli.rst') + + cli_doc_contents = open(cli_doc).readlines() + + while cli_doc_contents[0] != "\n": + cli_doc_contents.pop(0) + + rst2man_header = """ +botan +============================= + +:Subtitle: Botan command line util +:Manual section: 1 + + """.strip() + + with open(rst2man_file, 'w') as f: + f.write(rst2man_header) + f.write("\n") + for line in cli_doc_contents: + f.write(line) + + logging.info('Botan %s (revision %s) (%s %s) build setup is complete' % ( + Version.as_string(), + Version.vc_rev(), + Version.release_type(), + ('dated %d' % (Version.datestamp())) if Version.datestamp() != 0 else 'undated')) + + if options.unsafe_fuzzer_mode: + logging.warning("The fuzzer mode flag is labeled unsafe for a reason, this version is for testing only") + +def list_os_features(all_os_features, info_os): + for feat in all_os_features: + os_with_feat = [o for o in info_os.keys() if feat in info_os[o].target_features] + os_without_feat = [o for o in info_os.keys() if feat not in info_os[o].target_features] + + if len(os_with_feat) < len(os_without_feat): + print("%s: %s" % (feat, ' '.join(sorted(os_with_feat)))) + else: + print("%s: %s" % (feat, '!' + ' !'.join(sorted(os_without_feat)))) + return 0 + + +def main(argv): + """ + Main driver + """ + + # pylint: disable=too-many-locals,too-many-statements + + options = process_command_line(argv[1:]) + + setup_logging(options) + + source_paths = SourcePaths(os.path.dirname(argv[0])) + + info_modules = load_info_files(source_paths.lib_dir, 'Modules', "info.txt", ModuleInfo) + + if options.list_modules: + for mod in sorted(info_modules.keys()): + print(mod) + return 0 + + info_arch = load_build_data_info_files(source_paths, 'CPU info', 'arch', ArchInfo) + info_os = load_build_data_info_files(source_paths, 'OS info', 'os', OsInfo) + info_cc = load_build_data_info_files(source_paths, 'compiler info', 'cc', CompilerInfo) + info_module_policies = load_build_data_info_files(source_paths, 'module policy', 'policy', ModulePolicyInfo) + + all_os_features = sorted(set(flatten([o.target_features for o in info_os.values()]))) + all_defined_isas = set(flatten([a.isa_extensions for a in info_arch.values()])) + + if options.list_os_features: + return list_os_features(all_os_features, info_os) + + for mod in info_modules.values(): + mod.cross_check(info_arch, info_cc, all_os_features, all_defined_isas) + + for cc in info_cc.values(): + cc.cross_check(info_os, info_arch, all_defined_isas) + + for policy in info_module_policies.values(): + policy.cross_check(info_modules) + + logging.info('%s invoked with options "%s"', argv[0], ' '.join(argv[1:])) + logging.info('Configuring to build Botan %s (revision %s)' % ( + Version.as_string(), Version.vc_rev())) + logging.info('Running under %s', sys.version.replace('\n', '')) + + take_options_from_env(options) + + logging.info('Autodetected platform information: OS="%s" machine="%s" proc="%s"', + platform.system(), platform.machine(), platform.processor()) + + logging.debug('Known CPU names: ' + ' '.join( + sorted(flatten([[ainfo.basename] + ainfo.aliases for ainfo in info_arch.values()])))) + + set_defaults_for_unset_options(options, info_arch, info_cc, info_os) + canonicalize_options(options, info_os, info_arch) + validate_options(options, info_os, info_cc, info_module_policies) + + cc = info_cc[options.compiler] + arch = info_arch[options.arch] + osinfo = info_os[options.os] + module_policy = info_module_policies[options.module_policy] if options.module_policy else None + + if options.enable_cc_tests: + cc_min_version = options.cc_min_version or calculate_cc_min_version(options, cc, source_paths) + cc_arch = check_compiler_arch(options, cc, info_arch, source_paths) + + if options.arch != 'generic': + if cc_arch is not None and cc_arch != options.arch: + logging.error("Configured target is %s but compiler probe indicates %s", options.arch, cc_arch) + else: + cc_min_version = options.cc_min_version or "0.0" + + logging.info('Target is %s:%s-%s-%s' % ( + options.compiler, cc_min_version, options.os, options.arch)) + + def choose_endian(arch_info, options): + if options.with_endian is not None: + return options.with_endian + + if options.cpu.endswith('eb') or options.cpu.endswith('be'): + return 'big' + elif options.cpu.endswith('el') or options.cpu.endswith('le'): + return 'little' + + if arch_info.endian: + logging.info('Assuming target %s is %s endian', arch_info.basename, arch_info.endian) + return arch_info.endian + + options.with_endian = choose_endian(arch, options) + + chooser = ModulesChooser(info_modules, module_policy, arch, osinfo, cc, cc_min_version, options) + loaded_module_names = chooser.choose() + using_mods = [info_modules[modname] for modname in loaded_module_names] + + build_paths = BuildPaths(source_paths, options, using_mods) + build_paths.public_headers.append(os.path.join(build_paths.build_dir, 'build.h')) + + template_vars = create_template_vars(source_paths, build_paths, options, using_mods, cc, arch, osinfo) + + # Now we start writing to disk + do_io_for_build(cc, arch, osinfo, using_mods, build_paths, source_paths, template_vars, options) + + return 0 + +if __name__ == '__main__': + try: + sys.exit(main(argv=sys.argv)) + except UserError as e: + logging.debug(traceback.format_exc()) + logging.error(e) + except Exception as e: # pylint: disable=broad-except + # error() will stop script, so wrap all information into one call + logging.error("""%s +An internal error occurred. + +Don't panic, this is probably not your fault! Please open an issue +with the entire output at https://github.com/randombit/botan + +You'll meet friendly people happy to help!""" % traceback.format_exc()) + + sys.exit(0) diff --git a/comm/third_party/botan/doc/abi.rst b/comm/third_party/botan/doc/abi.rst new file mode 100644 index 0000000000..faf7bcc44a --- /dev/null +++ b/comm/third_party/botan/doc/abi.rst @@ -0,0 +1,21 @@ + +ABI Stability +==================== + +Botan uses semantic versioning for the API; if API features are added the minor +version increases, whereas if API compatibility breaks occur the major version +is increased. + +However no guarantees about ABI are made between releases. Maintaining an ABI +compatible release in a complex C++ API is exceedingly expensive in development +time; just adding a single member variable or virtual function is enough to +cause ABI issues. + +If ABI changes, the soname revision will increase to prevent applications from +linking against a potentially incompatible version at runtime. + +If you are concerned about long-term ABI issues, considering using the C API +instead; this subset *is* ABI stable. + +You can review a report on ABI changes to Botan at +https://abi-laboratory.pro/tracker/timeline/botan/ diff --git a/comm/third_party/botan/doc/api_ref/bigint.rst b/comm/third_party/botan/doc/api_ref/bigint.rst new file mode 100644 index 0000000000..364844fb53 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/bigint.rst @@ -0,0 +1,279 @@ +BigInt +======================================== + +``BigInt`` is Botan's implementation of a multiple-precision integer. Thanks to +C++'s operator overloading features, using ``BigInt`` is often quite similar to +using a native integer type. The number of functions related to ``BigInt`` is +quite large, and not all of them are documented here. You can find the complete +declarations in ``botan/bigint.h`` and ``botan/numthry.h``. + +.. cpp:class:: BigInt + + .. cpp:function:: BigInt() + + Create a BigInt with value zero + + .. cpp:function:: BigInt(uint64_t n) + + Create a BigInt with value *n* + + .. cpp:function:: BigInt(const std::string& str) + + Create a BigInt from a string. By default decimal is expected. With an 0x + prefix instead it is treated as hexadecimal. + + .. cpp:function:: BigInt(const uint8_t buf[], size_t length) + + Create a BigInt from a binary array (big-endian encoding). + + .. cpp:function:: BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit = true) + + Create a random BigInt of the specified size. + + .. cpp:function:: BigInt operator+(const BigInt& x, const BigInt& y) + + Add ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator+(const BigInt& x, word y) + + Add ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator+(word x, const BigInt& y) + + Add ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator-(const BigInt& x, const BigInt& y) + + Subtract ``y`` from ``x`` and return result. + + .. cpp:function:: BigInt operator-(const BigInt& x, word y) + + Subtract ``y`` from ``x`` and return result. + + .. cpp:function:: BigInt operator*(const BigInt& x, const BigInt& y) + + Multiply ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator/(const BigInt& x, const BigInt& y) + + Divide ``x`` by ``y`` and return result. + + .. cpp:function:: BigInt operator%(const BigInt& x, const BigInt& y) + + Divide ``x`` by ``y`` and return remainder. + + .. cpp:function:: word operator%(const BigInt& x, word y) + + Divide ``x`` by ``y`` and return remainder. + + .. cpp:function:: word operator<<(const BigInt& x, size_t n) + + Left shift ``x`` by ``n`` and return result. + + .. cpp:function:: word operator>>(const BigInt& x, size_t n) + + Right shift ``x`` by ``n`` and return result. + + .. cpp:function:: BigInt& operator+=(const BigInt& y) + + Add y to ``*this`` + + .. cpp:function:: BigInt& operator+=(word y) + + Add y to ``*this`` + + .. cpp:function:: BigInt& operator-=(const BigInt& y) + + Subtract y from ``*this`` + + .. cpp:function:: BigInt& operator-=(word y) + + Subtract y from ``*this`` + + .. cpp:function:: BigInt& operator*=(const BigInt& y) + + Multiply ``*this`` with y + + .. cpp:function:: BigInt& operator*=(word y) + + Multiply ``*this`` with y + + .. cpp:function:: BigInt& operator/=(const BigInt& y) + + Divide ``*this`` by y + + .. cpp:function:: BigInt& operator%=(const BigInt& y) + + Divide ``*this`` by y and set ``*this`` to the remainder. + + .. cpp:function:: word operator%=(word y) + + Divide ``*this`` by y and set ``*this`` to the remainder. + + .. cpp:function:: word operator<<=(size_t shift) + + Left shift ``*this`` by *shift* bits + + .. cpp:function:: word operator>>=(size_t shift) + + Right shift ``*this`` by *shift* bits + + .. cpp:function:: BigInt& operator++() + + Increment ``*this`` by 1 + + .. cpp:function:: BigInt& operator--() + + Decrement ``*this`` by 1 + + .. cpp:function:: BigInt operator++(int) + + Postfix increment ``*this`` by 1 + + .. cpp:function:: BigInt operator--(int) + + Postfix decrement ``*this`` by 1 + + .. cpp:function:: BigInt operator-() const + + Negation operator + + .. cpp:function:: bool operator !() const + + Return true unless ``*this`` is zero + + .. cpp:function:: void clear() + + Set ``*this`` to zero + + .. cpp:function:: size_t bytes() const + + Return number of bytes need to represent value of ``*this`` + + .. cpp:function:: size_t bits() const + + Return number of bits need to represent value of ``*this`` + + .. cpp:function:: bool is_even() const + + Return true if ``*this`` is even + + .. cpp:function:: bool is_odd() const + + Return true if ``*this`` is odd + + .. cpp:function:: bool is_nonzero() const + + Return true if ``*this`` is not zero + + .. cpp:function:: bool is_zero() const + + Return true if ``*this`` is zero + + .. cpp:function:: void set_bit(size_t n) + + Set bit *n* of ``*this`` + + .. cpp:function:: void clear_bit(size_t n) + + Clear bit *n* of ``*this`` + + .. cpp:function:: bool get_bit(size_t n) const + + Get bit *n* of ``*this`` + + .. cpp:function:: uint32_t to_u32bit() const + + Return value of ``*this`` as a 32-bit integer, if possible. + If the integer is negative or not in range, an exception is thrown. + + .. cpp:function:: bool is_negative() const + + Return true if ``*this`` is negative + + .. cpp:function:: bool is_positive() const + + Return true if ``*this`` is negative + + .. cpp:function:: BigInt abs() const + + Return absolute value of ``*this`` + + .. cpp:function:: void binary_encode(uint8_t buf[]) const + + Encode this BigInt as a big-endian integer. The sign is ignored. + + .. cpp:function:: void binary_encode(uint8_t buf[], size_t len) const + + Encode this BigInt as a big-endian integer. The sign is ignored. + If ``len`` is less than ``bytes()`` then only the low ``len`` + bytes are output. If ``len`` is greater than ``bytes()`` then + the output is padded with leading zeros. + + .. cpp:function:: void binary_decode(uint8_t buf[]) + + Decode this BigInt as a big-endian integer. + + .. cpp:function:: std::string to_dec_string() const + + Encode the integer as a decimal string. + + .. cpp:function:: std::string to_hex_string() const + + Encode the integer as a hexadecimal string. + +Number Theory +---------------------------------------- + +Number theoretic functions available include: + +.. cpp:function:: BigInt gcd(BigInt x, BigInt y) + + Returns the greatest common divisor of x and y + +.. cpp:function:: BigInt lcm(BigInt x, BigInt y) + + Returns an integer z which is the smallest integer such that z % x + == 0 and z % y == 0 + +.. cpp:function:: BigInt jacobi(BigInt a, BigInt n) + + Return Jacobi symbol of (a|n). + +.. cpp:function:: BigInt inverse_mod(BigInt x, BigInt m) + + Returns the modular inverse of x modulo m, that is, an integer + y such that (x*y) % m == 1. If no such y exists, returns zero. + +.. cpp:function:: BigInt power_mod(BigInt b, BigInt x, BigInt m) + + Returns b to the xth power modulo m. If you are doing many + exponentiations with a single fixed modulus, it is faster to use a + ``Power_Mod`` implementation. + +.. cpp:function:: BigInt ressol(BigInt x, BigInt p) + + Returns the square root modulo a prime, that is, returns a number y + such that (y*y) % p == x. Returns -1 if no such integer exists. + +.. cpp:function:: bool is_prime(BigInt n, RandomNumberGenerator& rng, \ + size_t prob = 56, double is_random = false) + + Test *n* for primality using a probabilistic algorithm (Miller-Rabin). With + this algorithm, there is some non-zero probability that true will be returned + even if *n* is actually composite. Modifying *prob* allows you to decrease the + chance of such a false positive, at the cost of increased runtime. Sufficient + tests will be run such that the chance *n* is composite is no more than 1 in + 2\ :sup:`prob`. Set *is_random* to true if (and only if) *n* was randomly + chosen (ie, there is no danger it was chosen maliciously) as far fewer tests + are needed in that case. + +.. cpp:function:: BigInt random_prime(RandomNumberGenerator& rng, \ + size_t bits, \ + BigInt coprime = 1, \ + size_t equiv = 1, \ + size_t equiv_mod = 2) + + Return a random prime number of ``bits`` bits long that is + relatively prime to ``coprime``, and equivalent to ``equiv`` modulo + ``equiv_mod``. diff --git a/comm/third_party/botan/doc/api_ref/block_cipher.rst b/comm/third_party/botan/doc/api_ref/block_cipher.rst new file mode 100644 index 0000000000..fc2b26e1d3 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/block_cipher.rst @@ -0,0 +1,364 @@ +Block Ciphers +======================= + +Block ciphers are a n-bit permutation for some small n, typically 64 or 128 +bits. They are a cryptographic primitive used to generate higher level +operations such as authenticated encryption. + +.. warning:: + + In almost all cases, a bare block cipher is not what you should be using. + You probably want an authenticated cipher mode instead (see :ref:`cipher_modes`) + This interface is used to build higher level operations (such as cipher + modes or MACs), or in the very rare situation where ECB is required, + eg for compatibility with an existing system. + +.. cpp:class:: BlockCipher + + .. cpp:function:: static std::unique_ptr create(const std::string& algo_spec, \ + const std::string& provider = "") + + Create a new block cipher object, or else return null. + + .. cpp:function:: static std::unique_ptr create_or_throw(const std::string& algo_spec, \ + const std::string& provider = "") + + Like ``create``, except instead of returning null an exception is thrown + if the cipher is not known. + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + This sets the key to the value specified. Most algorithms only accept keys + of certain lengths. If you attempt to call ``set_key`` with a key length + that is not supported, the exception ``Invalid_Key_Length`` will be + thrown. + + In all cases, ``set_key`` must be called on an object before any data + processing (encryption, decryption, etc) is done by that object. If this + is not done, an exception will be thrown. + thrown. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid keylength for + this algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: std::string name() const + + Return a human readable name for this algorithm. This is guaranteed to round-trip with + ``create`` and ``create_or_throw`` calls, ie create("Foo")->name() == "Foo" + + .. cpp:function:: void clear() + + Zero out the key. The key must be reset before the cipher object can be used. + + .. cpp:function:: BlockCipher* clone() const + + Return a newly allocated BlockCipher object of the same type as this one. + + .. cpp:function:: size_t block_size() const + + Return the size (in *bytes*) of the cipher. + + .. cpp:function:: size_t parallelism() const + + Return the parallelism underlying this implementation of the cipher. This + value can vary across versions and machines. A return value of N means that + encrypting or decrypting with N blocks can operate in parallel. + + .. cpp:function:: size_t parallel_bytes() const + + Returns ``parallelism`` multiplied by the block size as well as a small + fudge factor. That's because even ciphers that have no implicit parallelism + typically see a small speedup for being called with several blocks due to + caching effects. + + .. cpp:function:: std::string provider() const + + Return the provider type. Default value is "base" but can be any arbitrary string. + Other example values are "sse2", "avx2", "openssl". + + .. cpp:function:: void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + + Encrypt *blocks* blocks of data, taking the input from the array *in* and + placing the ciphertext into *out*. The two pointers may be identical, but + should not overlap ranges. + + .. cpp:function:: void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + + Decrypt *blocks* blocks of data, taking the input from the array *in* and + placing the plaintext into *out*. The two pointers may be identical, but + should not overlap ranges. + + .. cpp:function:: void encrypt(const uint8_t in[], uint8_t out[]) const + + Encrypt a single block. Equivalent to :cpp:func:`encrypt_n`\ (in, out, 1). + + .. cpp:function:: void encrypt(uint8_t block[]) const + + Encrypt a single block. Equivalent to :cpp:func:`encrypt_n`\ (block, block, 1) + + .. cpp:function:: void decrypt(const uint8_t in[], uint8_t out[]) const + + Decrypt a single block. Equivalent to :cpp:func:`decrypt_n`\ (in, out, 1) + + .. cpp:function:: void decrypt(uint8_t block[]) const + + Decrypt a single block. Equivalent to :cpp:func:`decrypt_n`\ (block, block, 1) + + .. cpp:function:: template void encrypt(std::vector& block) const + + Assumes ``block`` is of a multiple of the block size. + + .. cpp:function:: template void decrypt(std::vector& block) const + + Assumes ``block`` is of a multiple of the block size. + +Code Example +----------------- + +For sheer demonstrative purposes, the following code encrypts a provided single +block of plaintext with AES-256 using two different keys. + +.. code-block:: cpp + + #include + #include + #include + int main () + { + std::vector key = Botan::hex_decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + std::vector block = Botan::hex_decode("00112233445566778899AABBCCDDEEFF"); + std::unique_ptr cipher(Botan::BlockCipher::create("AES-256")); + cipher->set_key(key); + cipher->encrypt(block); + std::cout << std::endl <name() << "single block encrypt: " << Botan::hex_encode(block); + + //clear cipher for 2nd encryption with other key + cipher->clear(); + key = Botan::hex_decode("1337133713371337133713371337133713371337133713371337133713371337"); + cipher->set_key(key); + cipher->encrypt(block); + + std::cout << std::endl << cipher->name() << "single block encrypt: " << Botan::hex_encode(block); + return 0; + } + +Available Ciphers +--------------------- + +Botan includes a number of block ciphers that are specific to particular countries, as +well as a few that are included mostly due to their use in specific protocols such as PGP +but not widely used elsewhere. If you are developing new code and have no particular +opinion, use AES-256. If you desire an alternative to AES, consider Serpent, SHACAL2 or +Threefish. + +.. warning:: Avoid any 64-bit block cipher in new designs. There are + combinatoric issues that affect any 64-bit cipher that render it + insecure when large amounts of data are processed. + +AES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Comes in three variants, AES-128, AES-192, and AES-256. + +The standard 128-bit block cipher. Many modern platforms offer hardware +acceleration. However, on platforms without hardware support, AES +implementations typically are vulnerable to side channel attacks. For x86 +systems with SSSE3 but without AES-NI, Botan has an implementation which avoids +known side channels. + +Available if ``BOTAN_HAS_AES`` is defined. + +ARIA +~~~~~~ + +South Korean cipher used in industry there. No reason to use it otherwise. + +Available if ``BOTAN_HAS_ARIA`` is defined. + +Blowfish +~~~~~~~~~ + +A 64-bit cipher popular in the pre-AES era. Very slow key setup. Also used (with +bcrypt) for password hashing. + +Available if ``BOTAN_HAS_BLOWFISH`` is defined. + +CAST-128 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit cipher, commonly used in OpenPGP. + +Available if ``BOTAN_HAS_CAST128`` is defined. + +CAST-256 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 128-bit cipher that was a contestant in the NIST AES competition. +Almost never used in practice. Prefer AES or Serpent. + +Available if ``BOTAN_HAS_CAST256`` is defined. + +.. warning:: + Support for CAST-256 is deprecated and will be removed in a future major release. + +Camellia +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Comes in three variants, Camellia-128, Camellia-192, and Camellia-256. + +A Japanese design standardized by ISO, NESSIE and CRYPTREC. +Rarely used outside of Japan. + +Available if ``BOTAN_HAS_CAMELLIA`` is defined. + +Cascade +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Creates a block cipher cascade, where each block is encrypted by two ciphers +with independent keys. Useful if you're very paranoid. In practice any single +good cipher (such as Serpent, SHACAL2, or AES-256) is more than sufficient. + +Available if ``BOTAN_HAS_CASCADE`` is defined. + +DES, 3DES, DESX +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Originally designed by IBM and NSA in the 1970s. Today, DES's 56-bit key renders +it insecure to any well-resourced attacker. DESX and 3DES extend the key length, +and are still thought to be secure, modulo the limitation of a 64-bit block. +All are somewhat common in some industries such as finance. Avoid in new code. + +.. warning:: + Support for DESX is deprecated and it will be removed in a future major release. + +Available if ``BOTAN_HAS_DES`` is defined. + +GOST-28147-89 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Aka "Magma". An old 64-bit Russian cipher. Possible security issues, avoid +unless compatibility is needed. + +Available if ``BOTAN_HAS_GOST_28147_89`` is defined. + +.. warning:: + Support for this cipher is deprecated and will be removed in a future major release. + +IDEA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An older but still unbroken 64-bit cipher with a 128-bit key. Somewhat common +due to its use in PGP. Avoid in new designs. + +Available if ``BOTAN_HAS_IDEA`` is defined. + +Kasumi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit cipher used in 3GPP mobile phone protocols. There is no reason to use +it outside of this context. + +Available if ``BOTAN_HAS_KASUMI`` is defined. + +.. warning:: + Support for Kasumi is deprecated and will be removed in a future major release. + +Lion +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A "block cipher construction" which can encrypt blocks of nearly arbitrary +length. Built from a stream cipher and a hash function. Useful in certain +protocols where being able to encrypt large or arbitrary length blocks is +necessary. + +Available if ``BOTAN_HAS_LION`` is defined. + +MISTY1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit Japanese cipher standardized by NESSIE and ISO. Seemingly secure, but +quite slow and saw little adoption. No reason to use it in new code. + +Available if ``BOTAN_HAS_MISTY1`` is defined. + +.. warning:: + Support for MISTY1 is deprecated and will be removed in a future major release. + +Noekeon +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A fast 128-bit cipher by the designers of AES. Easily secured against side +channels. + +Available if ``BOTAN_HAS_NOEKEON`` is defined. + +.. warning:: + Support for Noekeon is deprecated and will be removed in a future major release. + +SEED +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A older South Korean cipher, widely used in industry there. No reason to choose it otherwise. + +Available if ``BOTAN_HAS_SEED`` is defined. + +SHACAL2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The 256-bit block cipher used inside SHA-256. Accepts up to a 512-bit key. +Fast, especially when SIMD or SHA-2 acceleration instructions are available. +Standardized by NESSIE but otherwise obscure. + +Available if ``BOTAN_HAS_SHACAL2`` is defined. + +SM4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 128-bit Chinese national cipher, required for use in certain commercial +applications in China. Quite slow. Probably no reason to use it outside of legal +requirements. + +Available if ``BOTAN_HAS_SM4`` is defined. + +Serpent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An AES contender. Widely considered the most conservative design. Fairly slow +unless SIMD instructions are available. + +Available if ``BOTAN_HAS_SERPENT`` is defined. + +Threefish-512 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 512-bit tweakable block cipher that was used in the Skein hash function. +Very fast on 64-bit processors. + +Available if ``BOTAN_HAS_THREEFISH_512`` is defined. + +Twofish +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 128-bit block cipher that was one of the AES finalists. Has a somewhat complicated key +setup and a "kitchen sink" design. + +Available if ``BOTAN_HAS_TWOFISH`` is defined. + +XTEA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit cipher popular for its simple implementation. Avoid in new code. + +Available if ``BOTAN_HAS_XTEA`` is defined. diff --git a/comm/third_party/botan/doc/api_ref/cipher_modes.rst b/comm/third_party/botan/doc/api_ref/cipher_modes.rst new file mode 100644 index 0000000000..413db70b57 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/cipher_modes.rst @@ -0,0 +1,384 @@ +.. _cipher_modes: + +Cipher Modes +===================== + +A block cipher by itself, is only able to securely encrypt a single data block. +To be able to securely encrypt data of arbitrary length, a mode of operation +applies the block cipher's single block operation repeatedly to encrypt +an entire message. + +All cipher mode implementations are are derived from the base class +:cpp:class:`Cipher_Mode`, which is declared in ``botan/cipher_mode.h``. + +.. warning:: + Using an unauthenticted cipher mode without combining it with a + :ref:`mac` is insecure. Prefer using an :ref:`aead`. + +.. cpp:class:: Cipher_Mode + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + Set the symmetric key to be used. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid + keylength for the algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t default_nonce_length() const + + Return the default (preferable) nonce size for this cipher mode. + + .. cpp:function:: bool valid_nonce_length(size_t nonce_len) const + + Return true if *nonce_len* is a valid length for a nonce with this + algorithm. + + .. cpp:function:: bool authenticated() const + + Return true if this cipher mode is authenticated + + .. cpp:function:: size_t tag_size() const + + Return the length in bytes of the authentication tag this algorithm + generates. If the mode is not authenticated, this will return 0. If the mode + is authenticated, it will return some positive value (typically somewhere + between 8 and 16). + + .. cpp:function:: void clear() + + Clear all internal state. The object will act exactly like one which was + just allocated. + + .. cpp:function:: void reset() + + Reset all message state. For example if you called :cpp:func:`start_msg`, + then :cpp:func:`process` to process some ciphertext, but then encounter an + IO error and must abandon the current message, you can call `reset`. The + object will retain the key (unlike calling :cpp:func:`clear` which also + resets the key) but the nonce and current message state will be erased. + + .. cpp:function:: void start_msg(const uint8_t* nonce, size_t nonce_len) + + Set up for processing a new message. This function must be called with a new + random value for each message. For almost all modes (excepting SIV), if the + same nonce is ever used twice with the same key, the encryption scheme loses + its confidentiality and/or authenticity properties. + + .. cpp:function:: void start(const std::vector nonce) + + Acts like :cpp:func:`start_msg`\ (nonce.data(), nonce.size()). + + .. cpp:function:: void start(const uint8_t* nonce, size_t nonce_len) + + Acts like :cpp:func:`start_msg`\ (nonce, nonce_len). + + .. cpp:function:: virtual size_t update_granularity() const + + The :cpp:class:`Cipher_Mode` interface requires message processing in multiples of the block size. + Returns size of required blocks to update and 1, if the mode can process messages of any length. + + .. cpp:function:: virtual size_t process(uint8_t* msg, size_t msg_len) + + Process msg in place and returns the number of bytes written. *msg* must + be a multiple of :cpp:func:`update_granularity`. + + .. cpp:function:: void update(secure_vector& buffer, size_t offset = 0) + + Continue processing a message in the buffer in place. The passed buffer's + size must be a multiple of :cpp:func:`update_granularity`. The first + *offset* bytes of the buffer will be ignored. + + .. cpp:function:: size_t minimum_final_size() const + + Returns the minimum size needed for :cpp:func:`finish`. + + .. cpp:function:: void finish(secure_vector& final_block, size_t offset = 0) + + Finalize the message processing with a final block of at least :cpp:func:`minimum_final_size` size. + The first *offset* bytes of the passed final block will be ignored. + +Code Example +--------------------- + +The following code encrypts the specified plaintext using AES-128/CBC +with PKCS#7 padding. + +.. warning:: + This example ignores the requirement to authenticate the ciphertext + +.. note:: + Simply replacing the string "AES-128/CBC/PKCS7" string in the example below + with "AES-128/GCM" suffices to use authenticated encryption. + +.. code-block:: cpp + + #include + #include + #include + #include + #include + + int main() + { + Botan::AutoSeeded_RNG rng; + + const std::string plaintext("Your great-grandfather gave this watch to your granddad for good luck. Unfortunately, Dane's luck wasn't as good as his old man's."); + const std::vector key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C"); + + std::unique_ptr enc = Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::ENCRYPTION); + enc->set_key(key); + + //generate fresh nonce (IV) + Botan::secure_vector iv = rng.random_vec(enc->default_nonce_length()); + + // Copy input data to a buffer that will be encrypted + Botan::secure_vector pt(plaintext.data(), plaintext.data()+plaintext.length()); + + enc->start(iv); + enc->finish(pt); + + std::cout << enc->name() << " with iv " << Botan::hex_encode(iv) << " " << Botan::hex_encode(pt) << "\n"; + return 0; + } + + +Available Unauthenticated Cipher Modes +----------------------------------------- + +.. note:: + CTR and OFB modes are also implemented, but these are treated as + :cpp:class:`Stream_Cipher`\s instead. + +CBC +~~~~~~~~~~~~ + +Available if ``BOTAN_HAS_MODE_CBC`` is defined. + +CBC requires the plaintext be padded using a reversible rule. The following +padding schemes are implemented + +PKCS#7 (RFC5652) + The last byte in the padded block defines the padding length p, the remaining padding bytes are set to p as well. +ANSI X9.23 + The last byte in the padded block defines the padding length, the remaining padding is filled with 0x00. +OneAndZeros (ISO/IEC 7816-4) + The first padding byte is set to 0x80, the remaining padding bytes are set to 0x00. + +Ciphertext stealing (CTS) is also implemented. This scheme allows the +ciphertext to have the same length as the plaintext, however using CTS +requires the input be at least one full block plus one byte. It is +also less commonly implemented. + +CFB +~~~~~~~~~~~~ + +Available if ``BOTAN_HAS_MODE_CFB`` is defined. + +CFB uses a block cipher to create a self-synchronizing stream cipher. It is used +for example in the OpenPGP protocol. There is no reason to prefer it, as it has +worse performance characteristics than modes such as CTR or CBC. + +XTS +~~~~~~~~~ + +Available if ``BOTAN_HAS_MODE_XTS`` is defined. + +XTS is a mode specialized for encrypting disk or database storage +where ciphertext expansion is not possible. XTS requires all inputs be +at least one full block (16 bytes for AES), however for any acceptable +input length, there is no ciphertext expansion. + +.. _aead: + +AEAD Mode +--------------------------- + +AEAD (Authenticated Encryption with Associated Data) modes provide message +encryption, message authentication, and the ability to authenticate additional +data that is not included in the ciphertext (such as a sequence number or +header). It is a subclass of :cpp:class:`Cipher_Mode`. + +.. cpp:class:: AEAD_Mode + + .. cpp:function:: void set_key(const SymmetricKey& key) + + Set the key + + .. cpp:function:: Key_Length_Specification key_spec() const + + Return the key length specification + + .. cpp:function:: void set_associated_data(const uint8_t ad[], size_t ad_len) + + Set any associated data for this message. For maximum portability between + different modes, this must be called after :cpp:func:`set_key` and before + :cpp:func:`start`. + + If the associated data does not change, it is not necessary to call this + function more than once, even across multiple calls to :cpp:func:`start` + and :cpp:func:`finish`. + + .. cpp:function:: void start(const uint8_t nonce[], size_t nonce_len) + + Start processing a message, using *nonce* as the unique per-message + value. It does not need to be random, simply unique (per key). + + .. warning:: + With almost all AEADs, if the same nonce is ever used to encrypt two + different messages under the same key, all security is lost. If + reliably generating unique nonces is difficult in your environment, + use SIV mode which retains security even if nonces are repeated. + + .. cpp:function:: void update(secure_vector& buffer, size_t offset = 0) + + Continue processing a message. The *buffer* is an in/out parameter and + may be resized. In particular, some modes require that all input be + consumed before any output is produced; with these modes, *buffer* will + be returned empty. + + On input, the buffer must be sized in blocks of size + :cpp:func:`update_granularity`. For instance if the update granularity + was 64, then *buffer* could be 64, 128, 192, ... bytes. + + The first *offset* bytes of *buffer* will be ignored (this allows in + place processing of a buffer that contains an initial plaintext header) + + .. cpp:function:: void finish(secure_vector& buffer, size_t offset = 0) + + Complete processing a message with a final input of *buffer*, which is + treated the same as with :cpp:func:`update`. It must contain at least + :cpp:func:`final_minimum_size` bytes. + + Note that if you have the entire message in hand, calling finish without + ever calling update is both efficient and convenient. + + .. note:: + + During decryption, if the supplied authentication tag does not + validate, finish will throw an instance of Invalid_Authentication_Tag + (aka Integrity_Failure, which was the name for this exception in + versions before 2.10, a typedef is included for compatability). + + If this occurs, all plaintext previously output via calls to update + must be destroyed and not used in any way that an attacker could + observe the effects of. This could be anything from echoing the + plaintext back (perhaps in an error message), or by making an external + RPC whose destination or contents depend on the plaintext. The only + thing you can do is buffer it, and in the event of an invalid tag, + erase the previously decrypted content from memory. + + One simply way to assure this could never happen is to never + call update, and instead always marshal the entire message + into a single buffer and call finish on it when decrypting. + + .. cpp:function:: size_t update_granularity() const + + The AEAD interface requires :cpp:func:`update` be called with blocks of + this size. This will be 1, if the mode can process any length inputs. + + .. cpp:function:: size_t final_minimum_size() const + + The AEAD interface requires :cpp:func:`finish` be called with at least + this many bytes (which may be zero, or greater than + :cpp:func:`update_granularity`) + + .. cpp:function:: bool valid_nonce_length(size_t nonce_len) const + + Returns true if *nonce_len* is a valid nonce length for this scheme. For + EAX and GCM, any length nonces are allowed. OCB allows any value between + 8 and 15 bytes. + + .. cpp:function:: size_t default_nonce_length() const + + Returns a reasonable length for the nonce, typically either 96 + bits, or the only supported length for modes which don't + support 96 bit nonces. + + +Available AEAD Modes +------------------------- + +If in doubt about what to use, pick ChaCha20Poly1305, AES-256/GCM, or AES-256/SIV. +Both ChaCha20Poly1305 and AES with GCM are widely implemented. SIV is somewhat +more obscure (and is slower than either GCM or ChaCha20Poly1305), but has +excellent security properties. + +ChaCha20Poly1305 +~~~~~~~~~~~~~~~~~~ + +Available if ``BOTAN_HAS_AEAD_CHACHA20_POLY1305`` is defined. + +Unlike the other AEADs which are based on block ciphers, this mode is based on +the ChaCha stream cipher and the Poly1305 authentication code. It is very fast +on all modern platforms. + +ChaCha20Poly1305 supports 64-bit, 96-bit, and (since 2.8) 192-bit nonces. 64-bit nonces +are the "classic" ChaCha20Poly1305 design. 96-bit nonces are used by the IETF standard +version of ChaCha20Poly1305. And 192-bit nonces is the XChaCha20Poly1305 construction, +which is somewhat less common. + +For best interop use the IETF version with 96-bit nonces. However 96 bits is small enough +that it can be dangerous to generate nonces randomly if more than ~ 2^32 messages are +encrypted under a single key, since if a nonce is ever reused ChaCha20Poly1305 becomes +insecure. It is better to use a counter for the nonce in this case. + +If you are encrypting many messages under a single key and cannot maintain a counter for +the nonce, prefer XChaCha20Poly1305 since a 192 bit nonce is large enough that randomly +chosen nonces are extremely unlikely to repeat. + +GCM +~~~~~ + +Available if ``BOTAN_HAS_AEAD_GCM`` is defined. + +NIST standard, commonly used. Requires a 128-bit block cipher. Fairly slow, +unless hardware support for carryless multiplies is available. + +OCB +~~~~~ + +Available if ``BOTAN_HAS_AEAD_OCB`` is defined. + +A block cipher based AEAD. Supports 128-bit, 256-bit and 512-bit block ciphers. +This mode is very fast and easily secured against side channels. Adoption has +been poor because it is patented in the United States, though a license is +available allowing it to be freely used by open source software. + +EAX +~~~~~ + +Available if ``BOTAN_HAS_AEAD_EAX`` is defined. + +A secure composition of CTR mode and CMAC. Supports 128-bit, 256-bit and 512-bit +block ciphers. + +SIV +~~~~~~ + +Available if ``BOTAN_HAS_AEAD_SIV`` is defined. + +Requires a 128-bit block cipher. Unlike other AEADs, SIV is "misuse resistant"; +if a nonce is repeated, SIV retains security, with the exception that if the +same nonce is used to encrypt the same message multiple times, an attacker can +detect the fact that the message was duplicated (this is simply because if both +the nonce and the message are reused, SIV will output identical ciphertexts). + +CCM +~~~~~ + +Available if ``BOTAN_HAS_AEAD_CCM`` is defined. + +A composition of CTR mode and CBC-MAC. Requires a 128-bit block cipher. This is +a NIST standard mode, but that is about all to recommend it. Prefer EAX. diff --git a/comm/third_party/botan/doc/api_ref/compression.rst b/comm/third_party/botan/doc/api_ref/compression.rst new file mode 100644 index 0000000000..5637a5a682 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/compression.rst @@ -0,0 +1,90 @@ +Lossless Data Compression +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some lossless data compression algorithms are available in botan, currently all +via third party libraries - these include zlib (including deflate and gzip +formats), bzip2, and lzma. Support for these must be enabled at build time; +you can check for them using the macros ``BOTAN_HAS_ZLIB``, ``BOTAN_HAS_BZIP2``, +and ``BOTAN_HAS_LZMA``. + +.. note:: + You should always compress *before* you encrypt, because encryption seeks to + hide the redundancy that compression is supposed to try to find and remove. + +Compression is done through the ``Compression_Algorithm`` and +``Decompression_Algorithm`` classes, both defined in `compression.h` + +Compression and decompression both work in three stages: starting a +message (``start``), continuing to process it (``update``), and then +finally completing processing the stream (``finish``). + +.. cpp:class:: Compression_Algorithm + + .. cpp:function:: void start(size_t level) + + Initialize the compression engine. This must be done before calling + ``update`` or ``finish``. The meaning of the `level` parameter varies by + the algorithm but generally takes a value between 1 and 9, with higher + values implying typically better compression from and more memory and/or + CPU time consumed by the compression process. The decompressor can always + handle input from any compressor. + + .. cpp:function:: void update(secure_vector& buf, \ + size_t offset = 0, bool flush = false) + + Compress the material in the in/out parameter ``buf``. The leading + ``offset`` bytes of ``buf`` are ignored and remain untouched; this can be + useful for ignoring packet headers. If ``flush`` is true, the + compression state is flushed, allowing the decompressor to recover the + entire message up to this point without having the see the rest of the + compressed stream. + + .. cpp::function:: void finish(secure_vector& buf, size_t offset = 0) + + Finish compressing a message. The ``buf`` and ``offset`` parameters are + treated as in ``update``. It is acceptable to call ``start`` followed by + ``finish`` with the entire message, without any intervening call to + ``update``. + +.. cpp:class:: Decompression_Algorithm + + .. cpp:function:: void start() + + Initialize the decompression engine. This must be done before calling + ``update`` or ``finish``. No level is provided here; the decompressor + can accept input generated by any compression parameters. + + .. cpp:function:: void update(secure_vector& buf, \ + size_t offset = 0) + + Decompress the material in the in/out parameter ``buf``. The leading + ``offset`` bytes of ``buf`` are ignored and remain untouched; this can be + useful for ignoring packet headers. + + This function may throw if the data seems to be invalid. + + .. cpp::function:: void finish(secure_vector& buf, size_t offset = 0) + + Finish decompressing a message. The ``buf`` and ``offset`` parameters are + treated as in ``update``. It is acceptable to call ``start`` followed by + ``finish`` with the entire message, without any intervening call to + ``update``. + + This function may throw if the data seems to be invalid. + +The easiest way to get a compressor is via the functions + +.. cpp:function:: Compression_Algorithm* make_compressor(std::string type) +.. cpp:function:: Decompression_Algorithm* make_decompressor(std::string type) + +Supported values for `type` include `zlib` (raw zlib with no checksum), +`deflate` (zlib's deflate format), `gzip`, `bz2`, and `lzma`. A null pointer +will be returned if the algorithm is unavailable. + +To use a compression algorithm in a `Pipe` use the adapter types +`Compression_Filter` and `Decompression_Filter` from `comp_filter.h`. The +constructors of both filters take a `std::string` argument (passed to +`make_compressor` or `make_decompressor`), the compression filter also takes a +`level` parameter. Finally both constructors have a parameter `buf_sz` which +specifies the size of the internal buffer that will be used - inputs will be +broken into blocks of this size. The default is 4096. diff --git a/comm/third_party/botan/doc/api_ref/contents.rst b/comm/third_party/botan/doc/api_ref/contents.rst new file mode 100644 index 0000000000..24fb274808 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/contents.rst @@ -0,0 +1,39 @@ + +API Reference +=================== + +.. toctree:: + :maxdepth: 1 + + versions + secmem + rng + hash + block_cipher + stream_ciphers + message_auth_codes + cipher_modes + pubkey + x509 + tls + credentials_manager + bigint + kdf + pbkdf + keywrap + passhash + cryptobox + srp + psk_db + filters + fpe + tss + ecc + compression + pkcs11 + tpm + otp + roughtime + ffi + env_vars + python diff --git a/comm/third_party/botan/doc/api_ref/credentials_manager.rst b/comm/third_party/botan/doc/api_ref/credentials_manager.rst new file mode 100644 index 0000000000..8f78970dbf --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/credentials_manager.rst @@ -0,0 +1,186 @@ + +Credentials Manager +================================================== + +A ``Credentials_Manager`` is a way to abstract how the application +stores credentials. The main user is the :doc:`tls` implementation. + +.. cpp:class:: Credentials_Manager + + .. cpp:function:: std::vector \ + trusted_certificate_authorities( \ + const std::string& type, \ + const std::string& context) + + Return the list of certificate stores, each of which is assumed + to contain (only) trusted certificate authorities. The + ``Credentials_Manager`` retains ownership of the + Certificate_Store pointers. + + .. note:: + + It would have been a better API to return a vector of + ``shared_ptr`` here. This may change in a future major release. + + When *type* is "tls-client", *context* will be the hostname of + the server, or empty if the hostname is not known. This allows + using a different set of certificate stores in different contexts, + for example using the system certificate store unless contacting + one particular server which uses a cert issued by an internal CA. + + When *type* is "tls-server", the *context* will again be the + hostname of the server, or empty if the client did not send a + server name indicator. For TLS servers, these CAs are the ones + trusted for signing of client certificates. If you do not want + the TLS server to ask for a client cert, + ``trusted_certificate_authorities`` should return an empty list + for *type* "tls-server". + + The default implementation returns an empty list. + + .. cpp:function:: std::vector find_cert_chain( \ + const std::vector& cert_key_types, \ + const std::vector& acceptable_CAs, \ + const std::string& type, \ + const std::string& context) + + Return the certificate chain to use to identify ourselves. The + ``acceptable_CAs`` parameter gives a list of CAs the peer trusts. + This may be empty. + + .. warning:: + If this function returns a certificate that is not one of the + types given in ``cert_key_types`` confusing handshake + failures will result. + + .. cpp:function:: std::vector cert_chain( \ + const std::vector& cert_key_types, \ + const std::string& type, \ + const std::string& context) + + Return the certificate chain to use to identify ourselves. Starting in + 2.5, prefer ``find_cert_chain`` which additionally provides the CA list. + + .. cpp:function:: std::vector cert_chain_single_type( \ + const std::string& cert_key_type, \ + const std::string& type, \ + const std::string& context) + + Return the certificate chain to use to identifier ourselves, if + we have one of type *cert_key_type* and we would like to use a + certificate in this *type*/*context*. + + .. cpp:function:: Private_Key* private_key_for(const X509_Certificate& cert, \ + const std::string& type, \ + const std::string& context) + + Return the private key for this certificate. The *cert* will be + the leaf cert of a chain returned previously by ``cert_chain`` + or ``cert_chain_single_type``. + +In versions before 1.11.34, there was an additional function on `Credentials_Manager` + + .. cpp::function:: void verify_certificate_chain( \ + const std::string& type, \ + const std::string& hostname, \ + const std::vector& cert_chain) + +This function has been replaced by `TLS::Callbacks::tls_verify_cert_chain`. + +SRP Authentication +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``Credentials_Manager`` contains the hooks used by TLS clients and +servers for SRP authentication. + +.. note:: + + Support for TLS-SRP is deprecated, and will be removed in a future + major release. When that occurs these APIs will be removed. Prefer + instead performing a standard TLS handshake, then perform a PAKE + authentication inside of (and cryptographically bound to) the TLS + channel. + +.. cpp:function:: bool attempt_srp(const std::string& type, \ + const std::string& context) + + Returns if we should consider using SRP for authentication + +.. cpp:function:: std::string srp_identifier(const std::string& type, \ + const std::string& context) + + Returns the SRP identifier we'd like to use (used by client) + +.. cpp:function:: std::string srp_password(const std::string& type, \ + const std::string& context, \ + const std::string& identifier) + + Returns the password for *identifier* (used by client) + +.. cpp:function:: bool srp_verifier(const std::string& type, \ + const std::string& context, \ + const std::string& identifier, \ + std::string& group_name, \ + BigInt& verifier, \ + std::vector& salt, \ + bool generate_fake_on_unknown) + + Returns the SRP verifier information for *identifier* (used by server) + +Preshared Keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +TLS supports the use of pre shared keys for authentication. + +.. cpp:function:: SymmetricKey psk(const std::string& type, \ + const std::string& context, \ + const std::string& identity) + + Return a symmetric key for use with *identity* + + One important special case for ``psk`` is where *type* is + "tls-server", *context* is "session-ticket" and *identity* is an + empty string. If a key is returned for this case, a TLS server + will offer session tickets to clients who can use them, and the + returned key will be used to encrypt the ticket. The server is + allowed to change the key at any time (though changing the key + means old session tickets can no longer be used for resumption, + forcing a full re-handshake when the client next connects). One + simple approach to add support for session tickets in your server + is to generate a random key the first time ``psk`` is called to + retrieve the session ticket key, cache it for later use in the + ``Credentials_Manager``, and simply let it be thrown away when the + process terminates. See :rfc:`4507` for more information about TLS + session tickets. + + A similar special case exists for DTLS cookie verification. In + this case *type* will be "tls-server" and *context* is + "dtls-cookie-secret". If no key is returned, then DTLS cookies are + not used. Similar to the session ticket key, the DTLS cookie + secret can be chosen during server startup and rotated at any time + with no ill effect. + + .. warning:: + + If DTLS cookies are not used then the server is prone to be + abused as a DoS amplifier, where the attacker sends a + relatively small client hello in a UDP packet with a forged + return address, and then the server replies to the victim with + several messages that are larger. This not only hides the + attackers address from the victim, but increases their + effective bandwidth. This is not an issue when using DTLS over + SCTP or TCP. + +.. cpp:function:: std::string psk_identity_hint(const std::string& type, \ + const std::string& context) + + Returns an identity hint which may be provided to the client. This + can help a client understand what PSK to use. + +.. cpp:function:: std::string psk_identity(const std::string& type, \ + const std::string& context, \ + const std::string& identity_hint) + + Returns the identity we would like to use given this *type* and + *context* and the optional *identity_hint*. Not all servers or + protocols will provide a hint. diff --git a/comm/third_party/botan/doc/api_ref/cryptobox.rst b/comm/third_party/botan/doc/api_ref/cryptobox.rst new file mode 100644 index 0000000000..dbade88af5 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/cryptobox.rst @@ -0,0 +1,32 @@ + +Cryptobox +======================================== + +Encryption using a passphrase +---------------------------------------- + +.. versionadded:: 1.8.6 + +This is a set of simple routines that encrypt some data using a +passphrase. There are defined in the header `cryptobox.h`, inside +namespace `Botan::CryptoBox`. + +It generates cipher and MAC keys using 8192 iterations of PBKDF2 with +HMAC(SHA-512), then encrypts using Serpent in CTR mode and authenticates using a +HMAC(SHA-512) mac of the ciphertext, truncated to 160 bits. + + .. cpp:function:: std::string encrypt(const uint8_t input[], size_t input_len, \ + const std::string& passphrase, \ + RandomNumberGenerator& rng) + + Encrypt the contents using *passphrase*. + + .. cpp:function:: std::string decrypt(const uint8_t input[], size_t input_len, \ + const std::string& passphrase) + + Decrypts something encrypted with encrypt. + + .. cpp:function:: std::string decrypt(const std::string& input, \ + const std::string& passphrase) + + Decrypts something encrypted with encrypt. diff --git a/comm/third_party/botan/doc/api_ref/ecc.rst b/comm/third_party/botan/doc/api_ref/ecc.rst new file mode 100644 index 0000000000..f522bbe3df --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/ecc.rst @@ -0,0 +1,284 @@ +Elliptic Curve Operations +============================ + +In addition to high level operations for signatures, key agreement, +and message encryption using elliptic curve cryptography, the library +contains lower level interfaces for performing operations such as +elliptic curve point multiplication. + +Only curves over prime fields are supported. + +Many of these functions take a workspace, either a vector of words or +a vector of BigInts. These are used to minimize memory allocations +during common operations. + +.. warning:: + You should only use these interfaces if you know what you are doing. + +.. cpp:class:: EC_Group + + .. cpp:function:: EC_Group(const OID& oid) + + Initialize an ``EC_Group`` using an OID referencing the curve + parameters. + + .. cpp:function:: EC_Group(const std::string& name) + + Initialize an ``EC_Group`` using a name or OID (for example + "secp256r1", or "1.2.840.10045.3.1.7") + + .. cpp:function:: EC_Group(const BigInt& p, \ + const BigInt& a, \ + const BigInt& b, \ + const BigInt& base_x, \ + const BigInt& base_y, \ + const BigInt& order, \ + const BigInt& cofactor, \ + const OID& oid = OID()) + + Initialize an elliptic curve group from the relevant parameters. This + is used for example to create custom (application-specific) curves. + + .. cpp:function:: EC_Group(const std::vector& ber_encoding) + + Initialize an ``EC_Group`` by decoding a DER encoded parameter block. + + .. cpp:function:: std::vector DER_encode(EC_Group_Encoding form) const + + Return the DER encoding of this group. + + .. cpp:function:: std::string PEM_encode() const + + Return the PEM encoding of this group (base64 of DER encoding plus + header/trailer). + + .. cpp:function:: bool a_is_minus_3() const + + Return true if the ``a`` parameter is congruent to -3 mod p. + + .. cpp:function:: bool a_is_zero() const + + Return true if the ``a`` parameter is congruent to 0 mod p. + + .. cpp:function:: size_t get_p_bits() const + + Return size of the prime in bits. + + .. cpp:function:: size_t get_p_bytes() const + + Return size of the prime in bytes. + + .. cpp:function:: size_t get_order_bits() const + + Return size of the group order in bits. + + .. cpp:function:: size_t get_order_bytes() const + + Return size of the group order in bytes. + + .. cpp:function:: const BigInt& get_p() const + + Return the prime modulus. + + .. cpp:function:: const BigInt& get_a() const + + Return the ``a`` parameter of the elliptic curve equation. + + .. cpp:function:: const BigInt& get_b() const + + Return the ``b`` parameter of the elliptic curve equation. + + .. cpp:function:: const PointGFp& get_base_point() const + + Return the groups base point element. + + .. cpp:function:: const BigInt& get_g_x() const + + Return the x coordinate of the base point element. + + .. cpp:function:: const BigInt& get_g_y() const + + Return the y coordinate of the base point element. + + .. cpp:function:: const BigInt& get_order() const + + Return the order of the group generated by the base point. + + .. cpp:function:: const BigInt& get_cofactor() const + + Return the cofactor of the curve. In most cases this will be 1. + + .. cpp:function:: BigInt mod_order(const BigInt& x) const + + Reduce argument ``x`` modulo the curve order. + + .. cpp:function:: BigInt inverse_mod_order(const BigInt& x) const + + Return inverse of argument ``x`` modulo the curve order. + + .. cpp:function:: BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const + + Multiply ``x`` and ``y`` and reduce the result modulo the curve order. + + .. cpp:function:: bool verify_public_element(const PointGFp& y) const + + Return true if ``y`` seems to be a valid group element. + + .. cpp:function:: const OID& get_curve_oid() const + + Return the OID used to identify the curve. May be empty. + + .. cpp:function:: PointGFp point(const BigInt& x, const BigInt& y) const + + Create and return a point with affine elements ``x`` and ``y``. Note + this function *does not* verify that ``x`` and ``y`` satisfy the curve + equation. + + .. cpp:function:: PointGFp point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const + + Multi-exponentiation. Returns base_point*x + pt*y. Not constant time. + (Ordinarily used for signature verification.) + + .. cpp:function:: PointGFp blinded_base_point_multiply(const BigInt& k, \ + RandomNumberGenerator& rng, \ + std::vector& ws) const + + Return ``base_point*k`` in a way that attempts to resist side channels. + + .. cpp:function:: BigInt blinded_base_point_multiply_x(const BigInt& k, \ + RandomNumberGenerator& rng, \ + std::vector& ws) const + + Like `blinded_base_point_multiply` but returns only the x coordinate. + + .. cpp:function:: PointGFp blinded_var_point_multiply(const PointGFp& point, \ + const BigInt& k, \ + RandomNumberGenerator& rng, \ + std::vector& ws) const + + Return ``point*k`` in a way that attempts to resist side channels. + + .. cpp:function:: BigInt random_scalar(RandomNumberGenerator& rng) const + + Return a random scalar (ie an integer between 1 and the group order). + + .. cpp:function:: PointGFp zero_point() const + + Return the zero point (aka the point at infinity). + + .. cpp:function:: PointGFp OS2ECP(const uint8_t bits[], size_t len) const + + Decode a point from the binary encoding. This function verifies that + the decoded point is a valid element on the curve. + + .. cpp:function:: bool verify_group(RandomNumberGenerator& rng, bool strong = false) const + + Attempt to verify the group seems valid. + + .. cpp:function:: static const std::set& known_named_groups() + + Return a list of known groups, ie groups for which ``EC_Group(name)`` + will succeed. + +.. cpp:class:: PointGFp + + Stores elliptic curve points in Jacobian representation. + + .. cpp:function:: std::vector encode(PointGFp::Compression_Type format) const + + Encode a point in a way that can later be decoded with `EC_Group::OS2ECP`. + + .. cpp:function:: PointGFp& operator+=(const PointGFp& rhs) + + Point addition. + + .. cpp:function:: PointGFp& operator-=(const PointGFp& rhs) + + Point subtraction. + + .. cpp:function:: PointGFp& operator*=(const BigInt& scalar) + + Point multiplication using Montgomery ladder. + + .. warning:: + Prefer the blinded functions in ``EC_Group`` + + .. cpp:function:: PointGFp& negate() + + Negate this point. + + .. cpp:function:: BigInt get_affine_x() const + + Return the affine ``x`` coordinate of the point. + + .. cpp:function:: BigInt get_affine_y() const + + Return the affine ``y`` coordinate of the point. + + .. cpp:function:: void force_affine() + + Convert the point to its equivalent affine coordinates. Throws + if this is the point at infinity. + + .. cpp:function:: static void force_all_affine(std::vector& points, \ + secure_vector& ws) + + Force several points to be affine at once. Uses Montgomery's + trick to reduce number of inversions required, so this is much + faster than calling ``force_affine`` on each point in sequence. + + .. cpp:function:: bool is_affine() const + + Return true if this point is in affine coordinates. + + .. cpp:function:: bool is_zero() const + + Return true if this point is zero (aka point at infinity). + + .. cpp:function:: bool on_the_curve() const + + Return true if this point is on the curve. + + .. cpp:function:: void randomize_repr(RandomNumberGenerator& rng) + + Randomize the point representation. + + .. cpp:function:: bool operator==(const PointGFp& other) const + + Point equality. This compares the affine representations. + + .. cpp:function:: void add(const PointGFp& other, std::vector& workspace) + + Point addition, taking a workspace. + + .. cpp:function:: void add_affine(const PointGFp& other, std::vector& workspace) + + Mixed (Jacobian+affine) addition, taking a workspace. + + .. warning:: + + This function assumes that ``other`` is affine, if this is + not correct the result will be invalid. + + .. cpp:function:: void mult2(std::vector& workspace) + + Point doubling. + + .. cpp:function:: void mult2i(size_t i, std::vector& workspace) + + Repeated point doubling. + + .. cpp:function:: PointGFp plus(const PointGFp& other, std::vector& workspace) const + + Point addition, returning the result. + + .. cpp:function:: PointGFp double_of(std::vector& workspace) const + + Point doubling, returning the result. + + .. cpp:function:: PointGFp zero() const + + Return the point at infinity + + + diff --git a/comm/third_party/botan/doc/api_ref/env_vars.rst b/comm/third_party/botan/doc/api_ref/env_vars.rst new file mode 100644 index 0000000000..221a225453 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/env_vars.rst @@ -0,0 +1,20 @@ +Environment Variables +====================== + +Certain environment variables can affect or tune the behavior of the +library. The variables and their behavior are described here. + +* ``BOTAN_THREAD_POOL_SIZE`` controls the number of threads which will be + created for a thread pool used for some purposes within the library. If not + set then it defaults to the number of CPUs available on the system. + +* ``BOTAN_MLOCK_POOL_SIZE`` controls the total amount of memory which will be + locked in memory using ``mlock`` or ``VirtualLock`` and managed in a memory + pool. If set to ``0`` (or indeed any value smaller than the system page size), + then the memory pool is disabled. + +* ``BOTAN_FFI_PRINT_EXCEPTIONS`` if this variable is set (to any value), then + if an exception is caught by the FFI layer, before returning an error code, it + will print the text message of the exception to stderr. This is primarily + intended for debugging. + diff --git a/comm/third_party/botan/doc/api_ref/ffi.rst b/comm/third_party/botan/doc/api_ref/ffi.rst new file mode 100644 index 0000000000..faee6e23d3 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/ffi.rst @@ -0,0 +1,1203 @@ + +FFI (C Binding) +======================================== + +.. versionadded:: 1.11.14 + +Botan's ffi module provides a C89 binding intended to be easily usable with other +language's foreign function interface (FFI) libraries. For instance the included +Python wrapper uses Python's ``ctypes`` module and the C89 API. This API is of +course also useful for programs written directly in C. + +Code examples can be found in +`the tests `_. + +Return Codes +--------------- + +Almost all functions in the Botan C interface return an ``int`` error code. The +only exceptions are a handful of functions (like +:cpp:func:`botan_ffi_api_version`) which cannot fail in any circumstances. + +The FFI functions return a non-negative integer (usually 0) to indicate success, +or a negative integer to represent an error. A few functions (like +:cpp:func:`botan_block_cipher_block_size`) return positive integers instead of +zero on success. + +The error codes returned in certain error situations may change over time. This +especially applies to very generic errors like +:cpp:enumerator:`BOTAN_FFI_ERROR_EXCEPTION_THROWN` and +:cpp:enumerator:`BOTAN_FFI_ERROR_UNKNOWN_ERROR`. For instance, before 2.8, setting +an invalid key length resulted in :cpp:enumerator:`BOTAN_FFI_ERROR_EXCEPTION_THROWN` +but now this is specially handled and returns +:cpp:enumerator:`BOTAN_FFI_ERROR_INVALID_KEY_LENGTH` instead. + +The following enum values are defined in the FFI header: + +.. cpp:enumerator:: BOTAN_FFI_SUCCESS = 0 + + Generally returned to indicate success + +.. cpp:enumerator:: BOTAN_FFI_INVALID_VERIFIER = 1 + + Note this value is positive, but still represents an error condition. In + indicates that the function completed successfully, but the value provided + was not correct. For example :cpp:func:`botan_bcrypt_is_valid` returns this + value if the password did not match the hash. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INVALID_INPUT = -1 + + The input was invalid. (Currently this error return is not used.) + +.. cpp:enumerator:: BOTAN_FFI_ERROR_BAD_MAC = -2 + + While decrypting in an AEAD mode, the tag failed to verify. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE = -10 + + Functions which write a variable amount of space return this if the indicated + buffer length was insufficient to write the data. In that case, the output + length parameter is set to the size that is required. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_EXCEPTION_THROWN = -20 + + An exception was thrown while processing this request, but no further + details are available. + + .. note:: + + If the environment variable ``BOTAN_FFI_PRINT_EXCEPTIONS`` is set to any + non-empty value, then any exception which is caught by the FFI layer will + first print the exception message to stderr before returning an + error. This is sometimes useful for debugging. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_OUT_OF_MEMORY = -21 + + Memory allocation failed + +.. cpp:enumerator:: BOTAN_FFI_ERROR_BAD_FLAG = -30 + + A value provided in a `flag` variable was unknown. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_NULL_POINTER = -31 + + A null pointer was provided as an argument where that is not allowed. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_BAD_PARAMETER = -32 + + An argument did not match the function. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_KEY_NOT_SET = -33 + + An object that requires a key normally must be keyed before use (eg before + encrypting or MACing data). If this is not done, the operation will fail and + return this error code. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INVALID_KEY_LENGTH = -34 + + An invalid key length was provided with a call to ``x_set_key``. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_NOT_IMPLEMENTED = -40 + + This is returned if the functionality is not available for some reason. For + example if you call :cpp:func:`botan_hash_init` with a named hash function + which is not enabled, this error is returned. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INVALID_OBJECT = -50 + + This is used if an object provided did not match the function. For example + calling :cpp:func:`botan_hash_destroy` on a ``botan_rng_t`` object will cause + this return. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_UNKNOWN_ERROR = -100 + + Something bad happened, but we are not sure why or how. + +Versioning +---------------------------------------- + +.. cpp:function:: uint32_t botan_ffi_api_version() + + Returns the version of the currently supported FFI API. This is + expressed in the form YYYYMMDD of the release date of this version + of the API. + +.. cpp:function:: int botan_ffi_supports_api(uint32_t version) + + Returns 0 iff the FFI version specified is supported by this + library. Otherwise returns -1. The expression + botan_ffi_supports_api(botan_ffi_api_version()) will always + evaluate to 0. A particular version of the library may also support + other (older) versions of the FFI API. + +.. cpp:function:: const char* botan_version_string() + + Returns a free-form string describing the version. The return + value is a statically allocated string. + +.. cpp:function:: uint32_t botan_version_major() + + Returns the major version of the library + +.. cpp:function:: uint32_t botan_version_minor() + + Returns the minor version of the library + +.. cpp:function:: uint32_t botan_version_patch() + + Returns the patch version of the library + +.. cpp:function:: uint32_t botan_version_datestamp() + + Returns the date this version was released as an integer YYYYMMDD, + or 0 if an unreleased version + + +FFI Versions +^^^^^^^^^^^^^ + +This maps the FFI API version to the first version of the library that +supported it. + +============== =================== +FFI Version Supported Starting +============== =================== +20191214 2.13.0 +20180713 2.8.0 +20170815 2.3.0 +20170327 2.1.0 +20150515 2.0.0 +============== =================== + +Utility Functions +---------------------------------------- + +.. const char* botan_error_description(int err) + + Return a string representation of the provided error code. If the error code + is unknown, returns the string "Unknown error". The return values are static + constant strings and should not be freed. + +.. cpp:function:: int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) + + Returns 0 if `x[0..len] == y[0..len]`, -1 otherwise. + +.. cpp:function:: int botan_hex_encode(const uint8_t* x, size_t len, char* out, uint32_t flags) + + Performs hex encoding of binary data in *x* of size *len* bytes. + The output buffer *out* must be of at least *x*2* bytes in size. + If *flags* contains ``BOTAN_FFI_HEX_LOWER_CASE``, hex encoding + will only contain lower-case letters, upper-case letters otherwise. + Returns 0 on success, 1 otherwise. + +.. cpp:function:: int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) + + Hex decode some data + +Random Number Generators +---------------------------------------- + +.. cpp:type:: opaque* botan_rng_t + + An opaque data type for a random number generator. Don't mess with it. + +.. cpp:function:: int botan_rng_init(botan_rng_t* rng, const char* rng_type) + + Initialize a random number generator object from the given + *rng_type*: "system" (or ``nullptr``): ``System_RNG``, + "user": ``AutoSeeded_RNG``, + "user-threadsafe": serialized ``AutoSeeded_RNG``, + "null": ``Null_RNG`` (always fails), + "hwrnd" or "rdrand": ``Processor_RNG`` (if available) + +.. cpp:function:: int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len) + + Get random bytes from a random number generator. + +.. cpp:function:: int botan_rng_reseed(botan_rng_t rng, size_t bits) + + Reseeds the random number generator with *bits* number of bits + from the `System_RNG`. + +.. cpp:function:: int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t src, size_t bits) + + Reseeds the random number generator with *bits* number of bits + taken from the given source RNG. + +.. cpp:function:: int botan_rng_add_entropy(botan_rng_t rng, const uint8_t seed[], size_t len) + + Adds the provided seed material to the internal RNG state. + + This call may be ignored by certain RNG instances (such as RDRAND + or, on some systems, the system RNG). + +.. cpp:function:: int botan_rng_destroy(botan_rng_t rng) + + Destroy the object created by :cpp:func:`botan_rng_init`. + +Block Ciphers +---------------------------------------- + +.. versionadded:: 2.1.0 + +This is a 'raw' interface to ECB mode block ciphers. Most applications +want the higher level cipher API which provides authenticated +encryption. This API exists as an escape hatch for applications which +need to implement custom primitives using a PRP. + +.. cpp:type:: opaque* botan_block_cipher_t + + An opaque data type for a block cipher. Don't mess with it. + +.. cpp:function:: int botan_block_cipher_init(botan_block_cipher_t* bc, const char* cipher_name) + + Create a new cipher mode object, `cipher_name` should be for example "AES-128" or "Threefish-512" + +.. cpp:function:: int botan_block_cipher_block_size(botan_block_cipher_t bc) + + Return the block size of this cipher. + +.. cpp:function:: int botan_block_cipher_name(botan_block_cipher_t cipher, \ + char* name, size_t* name_len) + + Return the name of this block cipher algorithm, which may nor may not exactly + match what was passed to :cpp:func:`botan_block_cipher_init`. + +.. cpp:function:: int botan_block_cipher_get_keyspec(botan_block_cipher_t cipher, \ + size_t* out_minimum_keylength, \ + size_t* out_maximum_keylength, \ + size_t* out_keylength_modulo) + + Return the limits on the key which can be provided to this cipher. If any of the + parameters are null, no output is written to that field. This allows retrieving only + (say) the maximum supported keylength, if that is the only information needed. + +.. cpp:function:: int botan_block_cipher_clear(botan_block_cipher_t bc) + + Clear the internal state (such as keys) of this cipher object, but do not deallocate it. + +.. cpp:function:: int botan_block_cipher_set_key(botan_block_cipher_t bc, const uint8_t key[], size_t key_len) + + Set the cipher key, which is required before encrypting or decrypting. + +.. cpp:function:: int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks) + + The key must have been set first with :cpp:func:`botan_block_cipher_set_key`. + Encrypt *blocks* blocks of data stored in *in* and place the ciphertext into *out*. + The two parameters may be the same buffer, but must not overlap. + +.. cpp:function:: int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks) + + The key must have been set first with :cpp:func:`botan_block_cipher_set_key`. + Decrypt *blocks* blocks of data stored in *in* and place the ciphertext into *out*. + The two parameters may be the same buffer, but must not overlap. + +.. cpp:function:: int botan_block_cipher_destroy(botan_block_cipher_t rng) + + Destroy the object created by :cpp:func:`botan_block_cipher_init`. + + +Hash Functions +---------------------------------------- + +.. cpp:type:: opaque* botan_hash_t + + An opaque data type for a hash. Don't mess with it. + +.. cpp:function:: botan_hash_t botan_hash_init(const char* hash, uint32_t flags) + + Creates a hash of the given name, e.g., "SHA-384". + Returns null on failure. Flags should always be zero in this version of the API. + +.. cpp:function:: int botan_hash_destroy(botan_hash_t hash) + + Destroy the object created by :cpp:func:`botan_hash_init`. + +.. cpp:function:: int botan_hash_name(botan_hash_t hash, char* name, size_t* name_len) + + Write the name of the hash function to the provided buffer. + +.. cpp:function:: int botan_hash_copy_state(botan_hash_t* dest, const botan_hash_t source) + + Copies the state of the hash object to a new hash object. + +.. cpp:function:: int botan_hash_clear(botan_hash_t hash) + + Reset the state of this object back to clean, as if no input has + been supplied. + +.. cpp:function:: size_t botan_hash_output_length(botan_hash_t hash) + + Return the output length of the hash function. + +.. cpp:function:: int botan_hash_update(botan_hash_t hash, const uint8_t* input, size_t len) + + Add input to the hash computation. + +.. cpp:function:: int botan_hash_final(botan_hash_t hash, uint8_t out[]) + + Finalize the hash and place the output in out. Exactly + :cpp:func:`botan_hash_output_length` bytes will be written. + +Message Authentication Codes +---------------------------------------- +.. cpp:type:: opaque* botan_mac_t + + An opaque data type for a MAC. Don't mess with it, but do remember + to set a random key first. + +.. cpp:function:: botan_mac_t botan_mac_init(const char* mac, uint32_t flags) + + Creates a MAC of the given name, e.g., "HMAC(SHA-384)". + Returns null on failure. Flags should always be zero in this version of the API. + +.. cpp:function:: int botan_mac_destroy(botan_mac_t mac) + + Destroy the object created by :cpp:func:`botan_mac_init`. + +.. cpp:function:: int botan_mac_clear(botan_mac_t mac) + + Reset the state of this object back to clean, as if no key and input have + been supplied. + +.. cpp:function:: size_t botan_mac_output_length(botan_mac_t mac) + + Return the output length of the MAC. + +.. cpp:function:: int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len) + + Set the random key. + +.. cpp:function:: int botan_mac_update(botan_mac_t mac, uint8_t buf[], size_t len) + + Add input to the MAC computation. + +.. cpp:function:: int botan_mac_final(botan_mac_t mac, uint8_t out[], size_t* out_len) + + Finalize the MAC and place the output in out. Exactly + :cpp:func:`botan_mac_output_length` bytes will be written. + +Symmetric Ciphers +---------------------------------------- + +.. cpp:type:: opaque* botan_cipher_t + + An opaque data type for a symmetric cipher object. Don't mess with it, but do remember + to set a random key first. And please use an AEAD. + +.. cpp:function:: botan_cipher_t botan_cipher_init(const char* cipher_name, uint32_t flags) + + Create a cipher object from a name such as "AES-256/GCM" or "Serpent/OCB". + + Flags is a bitfield; the low bitof ``flags`` specifies if encrypt or decrypt, + ie use 0 for encryption and 1 for decryption. + +.. cpp:function:: int botan_cipher_destroy(botan_cipher_t cipher) + +.. cpp:function:: int botan_cipher_clear(botan_cipher_t hash) + +.. cpp:function:: int botan_cipher_set_key(botan_cipher_t cipher, \ + const uint8_t* key, size_t key_len) + +.. cpp:function:: int botan_cipher_is_authenticated(botan_cipher_t cipher) + +.. cpp:function:: size_t botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tag_len) + + Write the tag length of the cipher to ``tag_len``. This will be zero for non-authenticated + ciphers. + +.. cpp:function:: int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl) + + Returns 1 if the nonce length is valid, or 0 otherwise. Returns -1 on error (such as + the cipher object being invalid). + +.. cpp:function:: size_t botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl) + + Return the default nonce length + +.. cpp:function:: int botan_cipher_set_associated_data(botan_cipher_t cipher, \ + const uint8_t* ad, size_t ad_len) + + Set associated data. Will fail unless the cipher is an AEAD. + +.. cpp:function:: int botan_cipher_start(botan_cipher_t cipher, \ + const uint8_t* nonce, size_t nonce_len) + + Start processing a message using the provided nonce. + +.. cpp:function:: int botan_cipher_update(botan_cipher_t cipher, \ + uint32_t flags, \ + uint8_t output[], \ + size_t output_size, \ + size_t* output_written, \ + const uint8_t input_bytes[], \ + size_t input_size, \ + size_t* input_consumed) + + Encrypt or decrypt data. + +PBKDF +---------------------------------------- + +.. cpp:function:: int botan_pbkdf(const char* pbkdf_algo, \ + uint8_t out[], size_t out_len, \ + const char* passphrase, \ + const uint8_t salt[], size_t salt_len, \ + size_t iterations) + + Derive a key from a passphrase for a number of iterations + using the given PBKDF algorithm, e.g., "PBKDF2". + +.. cpp:function:: int botan_pbkdf_timed(const char* pbkdf_algo, \ + uint8_t out[], size_t out_len, \ + const char* passphrase, \ + const uint8_t salt[], size_t salt_len, \ + size_t milliseconds_to_run, \ + size_t* out_iterations_used) + + Derive a key from a passphrase using the given PBKDF algorithm, + e.g., "PBKDF2". If *out_iterations_used* is zero, instead the + PBKDF is run until *milliseconds_to_run* milliseconds have passed. + In this case, the number of iterations run will be written to + *out_iterations_used*. + +KDF +---------------------------------------- + +.. cpp:function:: int botan_kdf(const char* kdf_algo, \ + uint8_t out[], size_t out_len, \ + const uint8_t secret[], size_t secret_len, \ + const uint8_t salt[], size_t salt_len, \ + const uint8_t label[], size_t label_len) + + Derive a key using the given KDF algorithm, e.g., "SP800-56C". + The derived key of length *out_len* bytes will be placed in *out*. + +Multiple Precision Integers +---------------------------------------- + +.. versionadded: 2.1.0 + +.. cpp:type:: opaque* botan_mp_t + + An opaque data type for a multiple precision integer. Don't mess with it. + +.. cpp:function:: int botan_mp_init(botan_mp_t* mp) + + Initialize a ``botan_mp_t``. Initial value is zero, use `botan_mp_set_X` to load a value. + +.. cpp:function:: int botan_mp_destroy(botan_mp_t mp) + + Free a ``botan_mp_t`` + +.. cpp:function:: int botan_mp_to_hex(botan_mp_t mp, char* out) + + Writes exactly ``botan_mp_num_bytes(mp)*2 + 1`` bytes to out + +.. cpp:function:: int botan_mp_to_str(botan_mp_t mp, uint8_t base, char* out, size_t* out_len) + + Base can be either 10 or 16. + +.. cpp:function:: int botan_mp_set_from_int(botan_mp_t mp, int initial_value) + + Set ``botan_mp_t`` from an integer value. + +.. cpp:function:: int botan_mp_set_from_mp(botan_mp_t dest, botan_mp_t source) + + Set ``botan_mp_t`` from another MP. + +.. cpp:function:: int botan_mp_set_from_str(botan_mp_t dest, const char* str) + + Set ``botan_mp_t`` from a string. Leading prefix of "0x" is accepted. + +.. cpp:function:: int botan_mp_num_bits(botan_mp_t n, size_t* bits) + + Return the size of ``n`` in bits. + +.. cpp:function:: int botan_mp_num_bytes(botan_mp_t n, size_t* uint8_ts) + + Return the size of ``n`` in bytes. + +.. cpp:function:: int botan_mp_to_bin(botan_mp_t mp, uint8_t vec[]) + + Writes exactly ``botan_mp_num_bytes(mp)`` to ``vec``. + +.. cpp:function:: int botan_mp_from_bin(botan_mp_t mp, const uint8_t vec[], size_t vec_len) + + Loads ``botan_mp_t`` from a binary vector (as produced by ``botan_mp_to_bin``). + +.. cpp:function:: int botan_mp_is_negative(botan_mp_t mp) + + Return 1 if ``mp`` is negative, otherwise 0. + +.. cpp:function:: int botan_mp_flip_sign(botan_mp_t mp) + + Flip the sign of ``mp``. + +.. cpp:function:: int botan_mp_add(botan_mp_t result, botan_mp_t x, botan_mp_t y) + + Add two ``botan_mp_t`` and store the output in ``result``. + +.. cpp:function:: int botan_mp_sub(botan_mp_t result, botan_mp_t x, botan_mp_t y) + + Subtract two ``botan_mp_t`` and store the output in ``result``. + +.. cpp:function:: int botan_mp_mul(botan_mp_t result, botan_mp_t x, botan_mp_t y) + + Multiply two ``botan_mp_t`` and store the output in ``result``. + +.. cpp:function:: int botan_mp_div(botan_mp_t quotient, botan_mp_t remainder, \ + botan_mp_t x, botan_mp_t y) + + Divide ``x`` by ``y`` and store the output in ``quotient`` and ``remainder``. + +.. cpp:function:: int botan_mp_mod_mul(botan_mp_t result, botan_mp_t x, botan_mp_t y, botan_mp_t mod) + + Set ``result`` to ``x`` times ``y`` modulo ``mod``. + +.. cpp:function:: int botan_mp_equal(botan_mp_t x, botan_mp_t y) + + Return 1 if ``x`` is equal to ``y``, 0 if ``x`` is not equal to ``y`` + +.. cpp:function:: int botan_mp_is_zero(const botan_mp_t x) + + Return 1 if ``x`` is equal to zero, otherwise 0. + +.. cpp:function:: int botan_mp_is_odd(const botan_mp_t x) + + Return 1 if ``x`` is odd, otherwise 0. + +.. cpp:function:: int botan_mp_is_even(const botan_mp_t x) + + Return 1 if ``x`` is even, otherwise 0. + +.. cpp:function:: int botan_mp_is_positive(const botan_mp_t x) + + Return 1 if ``x`` is greater than or equal to zero. + +.. cpp:function:: int botan_mp_is_negative(const botan_mp_t x) + + Return 1 if ``x`` is less than zero. + +.. cpp:function:: int botan_mp_to_uint32(const botan_mp_t x, uint32_t* val) + + If x fits in a 32-bit integer, set val to it and return 0. If x is out of + range an error is returned. + +.. cpp:function:: int botan_mp_cmp(int* result, botan_mp_t x, botan_mp_t y) + + Three way comparison: set result to -1 if ``x`` is less than ``y``, + 0 if ``x`` is equal to ``y``, and 1 if ``x`` is greater than ``y``. + +.. cpp:function:: int botan_mp_swap(botan_mp_t x, botan_mp_t y) + + Swap two ``botan_mp_t`` values. + +.. cpp:function:: int botan_mp_powmod(botan_mp_t out, botan_mp_t base, botan_mp_t exponent, botan_mp_t modulus) + + Modular exponentiation. + +.. cpp:function:: int botan_mp_lshift(botan_mp_t out, botan_mp_t in, size_t shift) + + Left shift by specified bit count, place result in ``out``. + +.. cpp:function:: int botan_mp_rshift(botan_mp_t out, botan_mp_t in, size_t shift) + + Right shift by specified bit count, place result in ``out``. + +.. cpp:function:: int botan_mp_mod_inverse(botan_mp_t out, botan_mp_t in, botan_mp_t modulus) + + Compute modular inverse. If no modular inverse exists (for instance because ``in`` and + ``modulus`` are not relatively prime), then sets ``out`` to -1. + +.. cpp:function:: int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits) + + Create a random ``botan_mp_t`` of the specified bit size. + +.. cpp:function:: int botan_mp_rand_range(botan_mp_t rand_out, botan_rng_t rng, \ + botan_mp_t lower_bound, botan_mp_t upper_bound) + + Create a random ``botan_mp_t`` within the provided range. + +.. cpp:function:: int botan_mp_gcd(botan_mp_t out, botan_mp_t x, botan_mp_t y) + + Compute the greatest common divisor of ``x`` and ``y``. + +.. cpp:function:: int botan_mp_is_prime(botan_mp_t n, botan_rng_t rng, size_t test_prob) + + Test if ``n`` is prime. The algorithm used (Miller-Rabin) is probabilistic, + set ``test_prob`` to the desired assurance level. For example if + ``test_prob`` is 64, then sufficient Miller-Rabin iterations will run to + assure there is at most a ``1/2**64`` chance that ``n`` is composite. + +.. cpp:function:: int botan_mp_get_bit(botan_mp_t n, size_t bit) + + Returns 0 if the specified bit of ``n`` is not set, 1 if it is set. + +.. cpp:function:: int botan_mp_set_bit(botan_mp_t n, size_t bit) + + Set the specified bit of ``n`` + +.. cpp:function:: int botan_mp_clear_bit(botan_mp_t n, size_t bit) + + Clears the specified bit of ``n`` + + +Password Hashing +---------------------------------------- + +.. cpp:function:: int botan_bcrypt_generate(uint8_t* out, size_t* out_len, \ + const char* password, \ + botan_rng_t rng, \ + size_t work_factor, \ + uint32_t flags) + + Create a password hash using Bcrypt. + The output buffer *out* should be of length 64 bytes. + The output is formatted bcrypt $2a$... + +.. cpp:function:: int botan_bcrypt_is_valid(const char* pass, const char* hash) + + Check a previously created password hash. Returns + :cpp:enumerator:`BOTAN_SUCCESS` if if this password/hash + combination is valid, :cpp:enumerator:`BOTAN_FFI_INVALID_VERIFIER` + if the combination is not valid (but otherwise well formed), + negative on error. + +Public Key Creation, Import and Export +---------------------------------------- + +.. cpp:type:: opaque* botan_privkey_t + + An opaque data type for a private key. Don't mess with it. + +.. cpp:function:: int botan_privkey_create(botan_privkey_t* key, \ + const char* algo_name, \ + const char* algo_params, \ + botan_rng_t rng) + +.. cpp:function:: int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, size_t n_bits) + + Create an RSA key of the given size + +.. cpp:function:: int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng, const char* curve) + + Create a ECDSA key of using a named curve + +.. cpp:function:: int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng, const char* curve) + + Create a ECDH key of using a named curve + +.. cpp:function:: int botan_privkey_create_mceliece(botan_privkey_t* key, botan_rng_t rng, size_t n, size_t t) + + Create a McEliece key using the specified parameters. See + :ref:`mceliece` for details on choosing parameters. + +.. cpp:function:: int botan_privkey_create_dh(botan_privkey_t* key, botan_rng_t rng, const char* params) + + Create a finite field Diffie-Hellman key using the specified named group, for example + "modp/ietf/3072". + +.. cpp:function:: int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng, \ + const uint8_t bits[], size_t len, \ + const char* password) + + Load a private key. If the key is encrypted, ``password`` will be + used to attempt decryption. + +.. cpp:function:: int botan_privkey_destroy(botan_privkey_t key) + + Destroy the object. + +.. cpp:function:: int botan_privkey_export(botan_privkey_t key, \ + uint8_t out[], size_t* out_len, \ + uint32_t flags) + + Export a public key. If flags is 1 then PEM format is used. + +.. cpp:function:: int botan_privkey_export_encrypted(botan_privkey_t key, \ + uint8_t out[], size_t* out_len, \ + botan_rng_t rng, \ + const char* passphrase, \ + const char* encryption_algo, \ + uint32_t flags) + + Deprecated, use ``botan_privkey_export_encrypted_msec`` or ``botan_privkey_export_encrypted_iter`` + +.. cpp::function:: int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key, + uint8_t out[], size_t* out_len, \ + botan_rng_t rng, \ + const char* passphrase, \ + uint32_t pbkdf_msec_runtime, \ + size_t* pbkdf_iterations_out, \ + const char* cipher_algo, \ + const char* pbkdf_algo, \ + uint32_t flags); + + Encrypt a key, running the key derivation function for ``pbkdf_msec_runtime`` milliseconds. + Returns the number of iterations used in ``pbkdf_iterations_out``. + + ``cipher_algo`` must specify a CBC mode cipher (such as "AES-128/CBC") or as + a Botan-specific extension a GCM mode may be used. + +.. cpp::function:: int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key, \ + uint8_t out[], size_t* out_len, \ + botan_rng_t rng, \ + const char* passphrase, \ + size_t pbkdf_iterations, \ + const char* cipher_algo, \ + const char* pbkdf_algo, \ + uint32_t flags); + + Encrypt a private key. The PBKDF function runs for the specified number of iterations. + At least 100,000 is recommended. + +.. cpp:function:: int botan_privkey_export_pubkey(botan_pubkey_t* out, botan_privkey_t in) + +.. cpp:function:: int botan_privkey_get_field(botan_mp_t output, \ + botan_privkey_t key, \ + const char* field_name) + + Read an algorithm specific field from the private key object, placing it into output. + For example "p" or "q" for RSA keys, or "x" for DSA keys or ECC keys. + +.. cpp:type:: opaque* botan_pubkey_t + + An opaque data type for a public key. Don't mess with it. + +.. cpp:function:: int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t len) + +.. cpp:function:: int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) + +.. cpp:function:: int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) + +.. cpp:function:: int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) + +.. cpp:function:: int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash, \ + uint8_t out[], size_t* out_len) + +.. cpp:function:: int botan_pubkey_destroy(botan_pubkey_t key) + +.. cpp:function:: int botan_pubkey_get_field(botan_mp_t output, \ + botan_pubkey_t key, \ + const char* field_name) + + Read an algorithm specific field from the public key object, placing it into output. + For example "n" or "e" for RSA keys or "p", "q", "g", and "y" for DSA keys. + +RSA specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t rsa_key) + + Set ``p`` to the first RSA prime. + +.. cpp:function:: int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t rsa_key) + + Set ``q`` to the second RSA prime. + +.. cpp:function:: int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t rsa_key) + + Set ``d`` to the RSA private exponent. + +.. cpp:function:: int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t rsa_key) + + Set ``n`` to the RSA modulus. + +.. cpp:function:: int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t rsa_key) + + Set ``e`` to the RSA public exponent. + +.. cpp:function:: int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t rsa_key) + + Set ``e`` to the RSA public exponent. + +.. cpp:function:: int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t rsa_key) + + Set ``n`` to the RSA modulus. + +.. cpp:function:: int botan_privkey_load_rsa(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t q, botan_mp_t e) + + Initialize a private RSA key using parameters p, q, and e. + +.. cpp:function:: int botan_pubkey_load_rsa(botan_pubkey_t* key, \ + botan_mp_t n, botan_mp_t e) + + Initialize a public RSA key using parameters n and e. + +DSA specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_load_dsa(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x) + + Initialize a private DSA key using group parameters p, q, and g and private key x. + +.. cpp:function:: int botan_pubkey_load_dsa(botan_pubkey_t* key, \ + botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y) + + Initialize a private DSA key using group parameters p, q, and g and public key y. + +ElGamal specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_load_elgamal(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t x) + + Initialize a private ElGamal key using group parameters p and g and private key x. + +.. cpp:function:: int botan_pubkey_load_elgamal(botan_pubkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t y) + + Initialize a public ElGamal key using group parameters p and g and public key y. + +Diffie-Hellman specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_load_dh(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t x) + + Initialize a private Diffie-Hellman key using group parameters p and g and private key x. + +.. cpp:function:: int botan_pubkey_load_dh(botan_pubkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t y) + + Initialize a public Diffie-Hellman key using group parameters p and g and public key y. + +Public Key Encryption/Decryption +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_encrypt_t + + An opaque data type for an encryption operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, \ + botan_pubkey_t key, \ + const char* padding, \ + uint32_t flags) + + Create a new operation object which can be used to encrypt using the provided + key and the specified padding scheme (such as "OAEP(SHA-256)" for use with + RSA). Flags should be 0 in this version. + +.. cpp:function:: int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op) + + Destroy the object. + +.. cpp:function:: int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, \ + size_t ptext_len, size_t* ctext_len) + + Returns an upper bound on the output length if a plaintext of length ``ptext_len`` + is encrypted with this key/parameter setting. This allows correctly sizing the + buffer that is passed to :cpp:func:`botan_pk_op_encrypt`. + +.. cpp:function:: int botan_pk_op_encrypt(botan_pk_op_encrypt_t op, \ + botan_rng_t rng, \ + uint8_t out[], size_t* out_len, \ + const uint8_t plaintext[], size_t plaintext_len) + + Encrypt the provided data using the key, placing the output in `out`. If + `out` is NULL, writes the length of what the ciphertext would have been to + `*out_len`. However this is computationally expensive (the encryption + actually occurs, then the result is discarded), so it is better to use + :cpp:func:`botan_pk_op_encrypt_output_length` to correctly size the buffer. + +.. cpp:type:: opaque* botan_pk_op_decrypt_t + + An opaque data type for a decryption operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, \ + botan_privkey_t key, \ + const char* padding, \ + uint32_t flags) + +.. cpp:function:: int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op) + +.. cpp:function:: int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, \ + size_t ctext_len, size_t* ptext_len) + + For a given ciphertext length, returns the upper bound on the size of the + plaintext that might be enclosed. This allows properly sizing the output + buffer passed to :cpp:func:`botan_pk_op_decrypt`. + +.. cpp:function:: int botan_pk_op_decrypt(botan_pk_op_decrypt_t op, \ + uint8_t out[], size_t* out_len, \ + uint8_t ciphertext[], size_t ciphertext_len) + +Signature Generation +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_sign_t + + An opaque data type for a signature generation operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_sign_create(botan_pk_op_sign_t* op, \ + botan_privkey_t key, \ + const char* hash_and_padding, \ + uint32_t flags) + + Create a signature operator for the provided key. The padding string + specifies what hash function and padding should be used, for example + "PKCS1v15(SHA-256)" or "EMSA1(SHA-384)". + +.. cpp:function:: int botan_pk_op_sign_destroy(botan_pk_op_sign_t op) + + Destroy an object created by :cpp:func:`botan_pk_op_sign_create`. + +.. cpp:function:: int botan_pk_op_sign_output_length(botan_pk_op_sign_t op, size_t* sig_len) + + Writes the length of the signatures that this signer will produce. This + allows properly sizing the buffer passed to + :cpp:func:`botan_pk_op_sign_finish`. + +.. cpp:function:: int botan_pk_op_sign_update(botan_pk_op_sign_t op, \ + const uint8_t in[], size_t in_len) + + Add bytes of the message to be signed. + +.. cpp:function:: int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng, \ + uint8_t sig[], size_t* sig_len) + + Produce a signature over all of the bytes passed to :cpp:func:`botan_pk_op_sign_update`. + Afterwards, the sign operator is reset and may be used to sign a new message. + +Signature Verification +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_verify_t + + An opaque data type for a signature verification operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_verify_create(botan_pk_op_verify_t* op, \ + botan_pubkey_t key, \ + const char* hash_and_padding, \ + uint32_t flags) + +.. cpp:function:: int botan_pk_op_verify_destroy(botan_pk_op_verify_t op) + +.. cpp:function:: int botan_pk_op_verify_update(botan_pk_op_verify_t op, \ + const uint8_t in[], size_t in_len) + + Add bytes of the message to be verified + +.. cpp:function:: int botan_pk_op_verify_finish(botan_pk_op_verify_t op, \ + const uint8_t sig[], size_t sig_len) + + Verify if the signature provided matches with the message provided as calls + to :cpp:func:`botan_pk_op_verify_update`. + +Key Agreement +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_ka_t + + An opaque data type for a key agreement operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, \ + botan_privkey_t key, \ + const char* kdf, \ + uint32_t flags) + +.. cpp:function:: int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op) + +.. cpp:function:: int botan_pk_op_key_agreement_export_public(botan_privkey_t key, \ + uint8_t out[], size_t* out_len) + +.. cpp:function:: int botan_pk_op_key_agreement(botan_pk_op_ka_t op, \ + uint8_t out[], size_t* out_len, \ + const uint8_t other_key[], size_t other_key_len, \ + const uint8_t salt[], size_t salt_len) + +.. cpp:function:: int botan_mceies_encrypt(botan_pubkey_t mce_key, \ + botan_rng_t rng, \ + const char* aead, \ + const uint8_t pt[], size_t pt_len, \ + const uint8_t ad[], size_t ad_len, \ + uint8_t ct[], size_t* ct_len) + +.. cpp:function:: int botan_mceies_decrypt(botan_privkey_t mce_key, \ + const char* aead, \ + const uint8_t ct[], size_t ct_len, \ + const uint8_t ad[], size_t ad_len, \ + uint8_t pt[], size_t* pt_len) + +X.509 Certificates +---------------------------------------- + +.. cpp:type:: opaque* botan_x509_cert_t + + An opaque data type for an X.509 certificate. Don't mess with it. + +.. cpp:function:: int botan_x509_cert_load(botan_x509_cert_t* cert_obj, \ + const uint8_t cert[], size_t cert_len) + + Load a certificate from the DER or PEM representation + +.. cpp:function:: int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* filename) + + Load a certificate from a file. + +.. cpp:function:: int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) + + Create a new object that refers to the same certificate. + +.. cpp:function:: int botan_x509_cert_destroy(botan_x509_cert_t cert) + + Destroy the certificate object + +.. cpp:function:: int botan_x509_cert_gen_selfsigned(botan_x509_cert_t* cert, \ + botan_privkey_t key, \ + botan_rng_t rng, \ + const char* common_name, \ + const char* org_name) + +.. cpp:function:: int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) + + Return the time the certificate becomes valid, as a string in form + "YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is + relative to UTC. Prefer :cpp:func:`botan_x509_cert_not_before`. + +.. cpp:function:: int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) + + Return the time the certificate expires, as a string in form + "YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is + relative to UTC. Prefer :cpp:func:`botan_x509_cert_not_after`. + +.. cpp:function:: int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) + + Return the time the certificate becomes valid, as seconds since epoch. + +.. cpp:function:: int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) + + Return the time the certificate expires, as seconds since epoch. + +.. cpp:function:: int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) + +.. cpp:function:: int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + + Return the serial number of the certificate. + +.. cpp:function:: int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + + Return the authority key ID set in the certificate, which may be empty. + +.. cpp:function:: int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + + Return the subject key ID set in the certificate, which may be empty. + +.. cpp:function:: int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, \ + uint8_t out[], size_t* out_len) + + Get the serialized representation of the public key included in this certificate + +.. cpp:function:: int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) + + Get the public key included in this certificate as a newly allocated object + +.. cpp:function:: int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, \ + const char* key, size_t index, \ + uint8_t out[], size_t* out_len) + + Get a value from the issuer DN field. + +.. cpp:function:: int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, \ + const char* key, size_t index, \ + uint8_t out[], size_t* out_len) + + Get a value from the subject DN field. + +.. cpp:function:: int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) + + Format the certificate as a free-form string. + +.. cpp:enum:: botan_x509_cert_key_constraints + + Certificate key usage constraints. Allowed values: `NO_CONSTRAINTS`, + `DIGITAL_SIGNATURE`, `NON_REPUDIATION`, `KEY_ENCIPHERMENT`, + `DATA_ENCIPHERMENT`, `KEY_AGREEMENT`, `KEY_CERT_SIGN`, + `CRL_SIGN`, `ENCIPHER_ONLY`, `DECIPHER_ONLY`. + +.. cpp:function:: int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) + + +.. cpp:function:: int botan_x509_cert_verify(int* validation_result, \ + botan_x509_cert_t cert, \ + const botan_x509_cert_t* intermediates, \ + size_t intermediates_len, \ + const botan_x509_cert_t* trusted, \ + size_t trusted_len, \ + const char* trusted_path, \ + size_t required_strength, \ + const char* hostname, \ + uint64_t reference_time) + + Verify a certificate. Returns 0 if validation was successful, 1 if + unsuccessful, or negative on error. + + Sets ``validation_result`` to a code that provides more information. + + If not needed, set ``intermediates`` to NULL and ``intermediates_len`` to + zero. + + If not needed, set ``trusted`` to NULL and ``trusted_len`` to zero. + + The ``trusted_path`` refers to a directory where one or more trusted CA + certificates are stored. It may be NULL if not needed. + + Set ``required_strength`` to indicate the minimum key and hash strength + that is allowed. For instance setting to 80 allows 1024-bit RSA and SHA-1. + Setting to 110 requires 2048-bit RSA and SHA-256 or higher. Set to zero + to accept a default. + + Set ``reference_time`` to be the time which the certificate chain is + validated against. Use zero to use the current system clock. + +.. cpp:function:: int botan_x509_cert_verify_with_crl(int* validation_result, \ + botan_x509_cert_t cert, \ + const botan_x509_cert_t* intermediates, \ + size_t intermediates_len, \ + const botan_x509_cert_t* trusted, \ + size_t trusted_len, \ + const botan_x509_crl_t* crls, \ + size_t crls_len, \ + const char* trusted_path, \ + size_t required_strength, \ + const char* hostname, \ + uint64_t reference_time) + + Certificate path validation supporting Certificate Revocation Lists. + + Works the same as ``botan_x509_cert_cerify``. + + ``crls`` is an array of ``botan_x509_crl_t`` objects, ``crls_len`` is its length. + +.. cpp:function:: const char* botan_x509_cert_validation_status(int code) + + Return a (statically allocated) string associated with the verification + result. + +X.509 Certificate Revocation Lists +---------------------------------------- + +.. cpp:type:: opaque* botan_x509_crl_t + + An opaque data type for an X.509 CRL. + +.. cpp:function:: int botan_x509_crl_load(botan_x509_crl_t* crl_obj, \ + const uint8_t crl[], size_t crl_len) + + Load a CRL from the DER or PEM representation. + +.. cpp:function:: int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* filename) + + Load a CRL from a file. + +.. cpp:function:: int botan_x509_crl_destroy(botan_x509_crl_t crl) + + Destroy the CRL object. + +.. cpp:function:: int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) + + Check whether a given ``crl`` contains a given ``cert``. + Return ``0`` when the certificate is revoked, ``-1`` otherwise. diff --git a/comm/third_party/botan/doc/api_ref/filters.rst b/comm/third_party/botan/doc/api_ref/filters.rst new file mode 100644 index 0000000000..04baebf5d0 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/filters.rst @@ -0,0 +1,733 @@ + +Pipe/Filter Message Processing +======================================== + +.. note:: + + The system described below provides a message processing system with a + straightforward API. However it makes many extra memory copies and + allocations than would otherwise be required, and also tends to make + applications using it somewhat opaque because it is not obvious what this or + that Pipe& object actually does (type of operation, number of messages + output (if any!), and so on), whereas using say a HashFunction or AEAD_Mode + provides a much better idea in the code of what operation is occurring. + + This filter interface is no longer used within the library itself + (outside a few dusty corners) and will likely not see any further major + development. However it will remain included because the API is often + convenient and many applications use it. + +Many common uses of cryptography involve processing one or more +streams of data. Botan provides services that make setting up data +flows through various operations, such as compression, encryption, and +base64 encoding. Each of these operations is implemented in what are +called *filters* in Botan. A set of filters are created and placed into +a *pipe*, and information "flows" through the pipe until it reaches +the end, where the output is collected for retrieval. If you're +familiar with the Unix shell environment, this design will sound quite +familiar. + +Here is an example that uses a pipe to base64 encode some strings:: + + Pipe pipe(new Base64_Encoder); // pipe owns the pointer + pipe.start_msg(); + pipe.write("message 1"); + pipe.end_msg(); // flushes buffers, increments message number + + // process_msg(x) is start_msg() && write(x) && end_msg() + pipe.process_msg("message2"); + + std::string m1 = pipe.read_all_as_string(0); // "message1" + std::string m2 = pipe.read_all_as_string(1); // "message2" + +Byte streams in the pipe are grouped into messages; blocks of data that +are processed in an identical fashion (ie, with the same sequence of +filter operations). Messages are delimited by calls to ``start_msg`` +and ``end_msg``. Each message in a pipe has its own identifier, which +currently is an integer that increments up from zero. + +The ``Base64_Encoder`` was allocated using ``new``; but where was it +deallocated? When a filter object is passed to a ``Pipe``, the pipe +takes ownership of the object, and will deallocate it when it is no +longer needed. + +There are two different ways to make use of messages. One is to send +several messages through a ``Pipe`` without changing the ``Pipe`` +configuration, so you end up with a sequence of messages; one use of +this would be to send a sequence of identically encrypted UDP packets, +for example (note that the *data* need not be identical; it is just +that each is encrypted, encoded, signed, etc in an identical +fashion). Another is to change the filters that are used in the +``Pipe`` between each message, by adding or removing filters; +functions that let you do this are documented in the Pipe API section. + +Botan has about 40 filters that perform different operations on data. +Here's code that uses one of them to encrypt a string with AES:: + + AutoSeeded_RNG rng, + SymmetricKey key(rng, 16); // a random 128-bit key + InitializationVector iv(rng, 16); // a random 128-bit IV + + // The algorithm we want is specified by a string + Pipe pipe(get_cipher("AES-128/CBC", key, iv, ENCRYPTION)); + + pipe.process_msg("secrets"); + pipe.process_msg("more secrets"); + + secure_vector c1 = pipe.read_all(0); + + uint8_t c2[4096] = { 0 }; + size_t got_out = pipe.read(c2, sizeof(c2), 1); + // use c2[0...got_out] + +Note the use of ``AutoSeeded_RNG``, which is a random number +generator. If you want to, you can explicitly set up the random number +generators and entropy sources you want to, however for 99% of cases +``AutoSeeded_RNG`` is preferable. + +``Pipe`` also has convenience methods for dealing with ``std::iostream``. +Here is an example of this, using the bzip2 compression filter:: + + std::ifstream in("data.bin", std::ios::binary) + std::ofstream out("data.bin.bz2", std::ios::binary) + + Pipe pipe(new Compression_Filter("bzip2", 9)); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + out << pipe; + +However there is a hitch to the code above; the complete contents of +the compressed data will be held in memory until the entire message +has been compressed, at which time the statement ``out << pipe`` is +executed, and the data is freed as it is read from the pipe and +written to the file. But if the file is very large, we might not have +enough physical memory (or even enough virtual memory!) for that to be +practical. So instead of storing the compressed data in the pipe for +reading it out later, we divert it directly to the file:: + + std::ifstream in("data.bin", std::ios::binary) + std::ofstream out("data.bin.bz2", std::ios::binary) + + Pipe pipe(new Compression_Filter("bzip2", 9), new DataSink_Stream(out)); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + +This is the first code we've seen so far that uses more than one +filter in a pipe. The output of the compressor is sent to the +``DataSink_Stream``. Anything written to a ``DataSink_Stream`` is +written to a file; the filter produces no output. As soon as the +compression algorithm finishes up a block of data, it will send it +along to the sink filter, which will immediately write it to the +stream; if you were to call ``pipe.read_all()`` after +``pipe.end_msg()``, you'd get an empty vector out. This is +particularly useful for cases where you are processing a large amount +of data, as it means you don't have to store everything in memory at +once. + +Here's an example using two computational filters:: + + AutoSeeded_RNG rng, + SymmetricKey key(rng, 32); + InitializationVector iv(rng, 16); + + Pipe encryptor(get_cipher("AES/CBC/PKCS7", key, iv, ENCRYPTION), + new Base64_Encoder); + + encryptor.start_msg(); + file >> encryptor; + encryptor.end_msg(); // flush buffers, complete computations + std::cout << encryptor; + +You can read from a pipe while you are still writing to it, which +allows you to bound the amount of memory that is in use at any one +time. A common idiom for this is:: + + pipe.start_msg(); + std::vector buffer(4096); // arbitrary size + while(infile.good()) + { + infile.read((char*)&buffer[0], buffer.size()); + const size_t got_from_infile = infile.gcount(); + pipe.write(buffer, got_from_infile); + + if(infile.eof()) + pipe.end_msg(); + + while(pipe.remaining() > 0) + { + const size_t buffered = pipe.read(buffer, buffer.size()); + outfile.write((const char*)&buffer[0], buffered); + } + } + if(infile.bad() || (infile.fail() && !infile.eof())) + throw Some_Exception(); + +Fork +--------------------------------- + +It is common that you might receive some data and want to perform more +than one operation on it (ie, encrypt it with Serpent and calculate +the SHA-256 hash of the plaintext at the same time). That's where +``Fork`` comes in. ``Fork`` is a filter that takes input and passes it +on to *one or more* filters that are attached to it. ``Fork`` changes +the nature of the pipe system completely: instead of being a linked +list, it becomes a tree or acyclic graph. + +Each filter in the fork is given its own output buffer, and thus its +own message. For example, if you had previously written two messages +into a pipe, then you start a new one with a fork that has three +paths of filter's inside it, you add three new messages to the +pipe. The data you put into the pipe is duplicated and sent +into each set of filter and the eventual output is placed into a +dedicated message slot in the pipe. + +Messages in the pipe are allocated in a depth-first manner. This is only +interesting if you are using more than one fork in a single pipe. +As an example, consider the following:: + + Pipe pipe(new Fork( + new Fork( + new Base64_Encoder, + new Fork( + NULL, + new Base64_Encoder + ) + ), + new Hex_Encoder + ) + ); + +In this case, message 0 will be the output of the first +``Base64_Encoder``, message 1 will be a copy of the input (see below +for how fork interprets NULL pointers), message 2 will be the output +of the second ``Base64_Encoder``, and message 3 will be the output of +the ``Hex_Encoder``. This results in message numbers being allocated +in a top to bottom fashion, when looked at on the screen. However, +note that there could be potential for bugs if this is not +anticipated. For example, if your code is passed a filter, and you +assume it is a "normal" one that only uses one message, your message +offsets would be wrong, leading to some confusion during output. + +If Fork's first argument is a null pointer, but a later argument is +not, then Fork will feed a copy of its input directly through. Here's +a case where that is useful:: + + // have std::string ciphertext, auth_code, key, iv, mac_key; + + Pipe pipe(new Base64_Decoder, + get_cipher("AES-128", key, iv, DECRYPTION), + new Fork( + 0, // this message gets plaintext + new MAC_Filter("HMAC(SHA-1)", mac_key) + ) + ); + + pipe.process_msg(ciphertext); + std::string plaintext = pipe.read_all_as_string(0); + secure_vector mac = pipe.read_all(1); + + if(mac != auth_code) + error(); + +Here we wanted to not only decrypt the message, but send the decrypted +text through an additional computation, in order to compute the +authentication code. + +Any filters that are attached to the pipe after the fork are +implicitly attached onto the first branch created by the fork. For +example, let's say you created this pipe:: + + Pipe pipe(new Fork(new Hash_Filter("SHA-256"), + new Hash_Filter("SHA-512")), + new Hex_Encoder); + +And then called ``start_msg``, inserted some data, then +``end_msg``. Then ``pipe`` would contain two messages. The first one +(message number 0) would contain the SHA-256 sum of the input in hex +encoded form, and the other would contain the SHA-512 sum of the input +in raw binary. In many situations you'll want to perform a sequence of +operations on multiple branches of the fork; in which case, use +the filter described in :ref:`chain`. + +There is also a ``Threaded_Fork`` which acts the same as ``Fork``, +except it runs each of the filters in its own thread. + +.. _chain: + +Chain +--------------------------------- + +A ``Chain`` filter creates a chain of filters and encapsulates them +inside a single filter (itself). This allows a sequence of filters to +become a single filter, to be passed into or out of a function, or to +a ``Fork`` constructor. + +You can call ``Chain``'s constructor with up to four ``Filter`` +pointers (they will be added in order), or with an array of filter +pointers and a ``size_t`` that tells ``Chain`` how many filters are in +the array (again, they will be attached in order). Here's the example +from the last section, using chain instead of relying on the implicit +pass through the other version used:: + + Pipe pipe(new Fork( + new Chain(new Hash_Filter("SHA-256"), new Hex_Encoder), + new Hash_Filter("SHA-512") + ) + ); + +Sources and Sinks +---------------------------------------- + +Data Sources +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``DataSource`` is a simple abstraction for a thing that stores +bytes. This type is used heavily in the areas of the API related to +ASN.1 encoding/decoding. The following types are ``DataSource``: +``Pipe``, ``SecureQueue``, and a couple of special purpose ones: +``DataSource_Memory`` and ``DataSource_Stream``. + +You can create a ``DataSource_Memory`` with an array of bytes and a +length field. The object will make a copy of the data, so you don't +have to worry about keeping that memory allocated. This is mostly for +internal use, but if it comes in handy, feel free to use it. + +A ``DataSource_Stream`` is probably more useful than the memory based +one. Its constructors take either a ``std::istream`` or a +``std::string``. If it's a stream, the data source will use the +``istream`` to satisfy read requests (this is particularly useful to +use with ``std::cin``). If the string version is used, it will attempt +to open up a file with that name and read from it. + +Data Sinks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``DataSink`` (in ``data_snk.h``) is a ``Filter`` that takes +arbitrary amounts of input, and produces no output. This means it's +doing something with the data outside the realm of what +``Filter``/``Pipe`` can handle, for example, writing it to a file +(which is what the ``DataSink_Stream`` does). There is no need for +``DataSink``s that write to a ``std::string`` or memory buffer, +because ``Pipe`` can handle that by itself. + +Here's a quick example of using a ``DataSink``, which encrypts +``in.txt`` and sends the output to ``out.txt``. There is +no explicit output operation; the writing of ``out.txt`` is +implicit:: + + DataSource_Stream in("in.txt"); + Pipe pipe(get_cipher("AES-128/CTR-BE", key, iv), + new DataSink_Stream("out.txt")); + pipe.process_msg(in); + +A real advantage of this is that even if "in.txt" is large, only as +much memory is needed for internal I/O buffers will be used. + +The Pipe API +--------------------------------- + +Initializing Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, ``Pipe`` will do nothing at all; any input placed into the +``Pipe`` will be read back unchanged. Obviously, this has limited +utility, and presumably you want to use one or more filters to somehow +process the data. First, you can choose a set of filters to initialize +the ``Pipe`` via the constructor. You can pass it either a set of up +to four filter pointers, or a pre-defined array and a length:: + + Pipe pipe1(new Filter1(/*args*/), new Filter2(/*args*/), + new Filter3(/*args*/), new Filter4(/*args*/)); + Pipe pipe2(new Filter1(/*args*/), new Filter2(/*args*/)); + + Filter* filters[5] = { + new Filter1(/*args*/), new Filter2(/*args*/), new Filter3(/*args*/), + new Filter4(/*args*/), new Filter5(/*args*/) /* more if desired... */ + }; + Pipe pipe3(filters, 5); + +This is by far the most common way to initialize a ``Pipe``. However, +occasionally a more flexible initialization strategy is necessary; +this is supported by 4 member functions. These functions may only be +used while the pipe in question is not in use; that is, either before +calling ``start_msg``, or after ``end_msg`` has been called (and no +new calls to ``start_msg`` have been made yet). + +.. cpp:function:: void Pipe::prepend(Filter* filter) + + Calling ``prepend`` will put the passed filter first in the list of + transformations. For example, if you prepend a filter implementing + encryption, and the pipe already had a filter that hex encoded the + input, then the next message processed would be first encrypted, + and *then* hex encoded. + +.. cpp:function:: void Pipe::append(Filter* filter) + + Like ``prepend``, but places the filter at the end of the message + flow. This doesn't always do what you expect if there is a fork. + +.. cpp:function:: void Pipe::pop() + + Removes the first filter in the flow. + +.. cpp:function:: void Pipe::reset() + + Removes all the filters that the pipe currently holds - it is reset + to an empty/no-op state. Any data that is being retained by the + pipe is retained after a ``reset``, and ``reset`` does not affect + message numbers (discussed later). + +Giving Data to a Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Input to a ``Pipe`` is delimited into messages, which can be read from +independently (ie, you can read 5 bytes from one message, and then all of +another message, without either read affecting any other messages). + +.. cpp:function:: void Pipe::start_msg() + + Starts a new message; if a message was already running, an exception is + thrown. After this function returns, you can call ``write``. + +.. cpp:function:: void Pipe::write(const uint8_t* input, size_t length) + +.. cpp:function:: void Pipe::write(const std::vector& input) + +.. cpp:function:: void Pipe::write(const std::string& input) + +.. cpp:function:: void Pipe::write(DataSource& input) + +.. cpp:function:: void Pipe::write(uint8_t input) + + All versions of ``write`` write the input into the filter sequence. + If a message is not currently active, an exception is thrown. + +.. cpp:function:: void Pipe::end_msg() + + End the currently active message + +Sometimes, you may want to do only a single write per message. In this +case, you can use the ``process_msg`` series of functions, which start +a message, write their argument into the pipe, and then end the +message. In this case you would not make any explicit calls to +``start_msg``/``end_msg``. + +Pipes can also be used with the ``>>`` operator, and will accept a +``std::istream``, or on Unix systems with the ``fd_unix`` module, a +Unix file descriptor. In either case, the entire contents of the file +will be read into the pipe. + +Getting Output from a Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieving the processed data from a pipe is a bit more complicated, +for various reasons. The pipe will separate each message into a +separate buffer, and you have to retrieve data from each message +independently. Each of the reader functions has a final parameter that +specifies what message to read from. If this parameter is set to +``Pipe::DEFAULT_MESSAGE``, it will read the current default message +(``DEFAULT_MESSAGE`` is also the default value of this parameter). + +Functions in ``Pipe`` related to reading include: + +.. cpp:function:: size_t Pipe::read(uint8_t* out, size_t len) + + Reads up to ``len`` bytes into ``out``, and returns the number of + bytes actually read. + +.. cpp:function:: size_t Pipe::peek(uint8_t* out, size_t len) + + Acts exactly like `read`, except the data is not actually read; the + next read will return the same data. + +.. cpp:function:: secure_vector Pipe::read_all() + + Reads the entire message into a buffer and returns it + +.. cpp:function:: std::string Pipe::read_all_as_string() + + Like ``read_all``, but it returns the data as a ``std::string``. + No encoding is done; if the message contains raw binary, so will + the string. + +.. cpp:function:: size_t Pipe::remaining() + + Returns how many bytes are left in the message + +.. cpp:function:: Pipe::message_id Pipe::default_msg() + + Returns the current default message number + +.. cpp:function:: Pipe::message_id Pipe::message_count() + + Returns the total number of messages currently in the pipe + +.. cpp:function:: Pipe::set_default_msg(Pipe::message_id msgno) + + Sets the default message number (which must be a valid message + number for that pipe). The ability to set the default message number + is particularly important in the case of using the file output + operations (``<<`` with a ``std::ostream`` or Unix file descriptor), + because there is no way to specify the message explicitly when using + the output operator. + +Pipe I/O for Unix File Descriptors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a minor feature, but it comes in handy sometimes. In all +installations of the library, Botan's ``Pipe`` object overloads the +``<<`` and ``>>`` operators for C++ iostream objects, +which is usually more than sufficient for doing I/O. + +However, there are cases where the iostream hierarchy does not map well to +local 'file types', so there is also the ability to do I/O directly with Unix +file descriptors. This is most useful when you want to read from or write to +something like a TCP or Unix-domain socket, or a pipe, since for simple file +access it's usually easier to just use C++'s file streams. + +If ``BOTAN_EXT_PIPE_UNIXFD_IO`` is defined, then you can use the +overloaded I/O operators with Unix file descriptors. For an example of this, +check out the ``hash_fd`` example, included in the Botan distribution. + +Filter Catalog +--------------------------------- + +This section documents most of the useful filters included in the +library. + +Keyed Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A few sections ago, it was mentioned that ``Pipe`` can process +multiple messages, treating each of them the same. Well, that was a +bit of a lie. There are some algorithms (in particular, block ciphers +not in ECB mode, and all stream ciphers) that change their state as +data is put through them. + +Naturally, you might well want to reset the keys or (in the case of +block cipher modes) IVs used by such filters, so multiple messages can +be processed using completely different keys, or new IVs, or new keys +and IVs, or whatever. And in fact, even for a MAC or an ECB block +cipher, you might well want to change the key used from message to +message. + +Enter ``Keyed_Filter``, which acts as an abstract interface for any +filter that is uses keys: block cipher modes, stream ciphers, MACs, +and so on. It has two functions, ``set_key`` and ``set_iv``. Calling +``set_key`` will set (or reset) the key used by the algorithm. Setting +the IV only makes sense in certain algorithms -- a call to ``set_iv`` +on an object that doesn't support IVs will cause an exception. You +must call ``set_key`` *before* calling ``set_iv``. + +Here's a example:: + + Keyed_Filter *aes, *hmac; + Pipe pipe(new Base64_Decoder, + // Note the assignments to the cast and hmac variables + aes = get_cipher("AES-128/CBC", aes_key, iv), + new Fork( + 0, // Read the section 'Fork' to understand this + new Chain( + hmac = new MAC_Filter("HMAC(SHA-1)", mac_key, 12), + new Base64_Encoder + ) + ) + ); + pipe.start_msg(); + // use pipe for a while, decrypt some stuff, derive new keys and IVs + pipe.end_msg(); + + aes->set_key(aes_key2); + aes->set_iv(iv2); + hmac->set_key(mac_key2); + + pipe.start_msg(); + // use pipe for some other things + pipe.end_msg(); + +There are some requirements to using ``Keyed_Filter`` that you must +follow. If you call ``set_key`` or ``set_iv`` on a filter that is +owned by a ``Pipe``, you must do so while the ``Pipe`` is +"unlocked". This refers to the times when no messages are being +processed by ``Pipe`` -- either before ``Pipe``'s ``start_msg`` is +called, or after ``end_msg`` is called (and no new call to +``start_msg`` has happened yet). Doing otherwise will result in +undefined behavior, probably silently getting invalid output. + +And remember: if you're resetting both values, reset the key *first*. + +Cipher Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Getting a hold of a ``Filter`` implementing a cipher is very +easy. Make sure you're including the header ``lookup.h``, and +then call ``get_cipher``. You will pass the return value +directly into a ``Pipe``. There are a couple different functions +which do varying levels of initialization: + +.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \ + SymmetricKey key, InitializationVector iv, Cipher_Dir dir) + +.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \ + SymmetricKey key, Cipher_Dir dir) + +The version that doesn't take an IV is useful for things that don't +use them, like block ciphers in ECB mode, or most stream ciphers. If +you specify a cipher spec that does want a IV, and you use the version +that doesn't take one, an exception will be thrown. The ``dir`` +argument can be either ``ENCRYPTION`` or ``DECRYPTION``. + +The cipher_spec is a string that specifies what cipher is to be +used. The general syntax for "cipher_spec" is "STREAM_CIPHER", +"BLOCK_CIPHER/MODE", or "BLOCK_CIPHER/MODE/PADDING". In the case of +stream ciphers, no mode is necessary, so just the name is +sufficient. A block cipher requires a mode of some sort, which can be +"ECB", "CBC", "CFB(n)", "OFB", "CTR-BE", or "EAX(n)". The argument to +CFB mode is how many bits of feedback should be used. If you just use +"CFB" with no argument, it will default to using a feedback equal to +the block size of the cipher. EAX mode also takes an optional bit +argument, which tells EAX how large a tag size to use~--~generally +this is the size of the block size of the cipher, which is the default +if you don't specify any argument. + +In the case of the ECB and CBC modes, a padding method can also be +specified. If it is not supplied, ECB defaults to not padding, and CBC +defaults to using PKCS #5/#7 compatible padding. The padding methods +currently available are "NoPadding", "PKCS7", "OneAndZeros", and +"CTS". CTS padding is currently only available for CBC mode, but the +others can also be used in ECB mode. + +Some example "cipher_spec arguments are: "AES-128/CBC", +"Blowfish/CTR-BE", "Serpent/XTS", and "AES-256/EAX". + +"CTR-BE" refers to counter mode where the counter is incremented as if +it were a big-endian encoded integer. This is compatible with most +other implementations, but it is possible some will use the +incompatible little endian convention. This version would be denoted +as "CTR-LE" if it were supported. + +"EAX" is a new cipher mode designed by Wagner, Rogaway, and +Bellare. It is an authenticated cipher mode (that is, no separate +authentication is needed), has provable security, and is free from +patent entanglements. It runs about half as fast as most of the other +cipher modes (like CBC, OFB, or CTR), which is not bad considering you +don't need to use an authentication code. + +Hashes and MACs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Hash functions and MACs don't need anything special when it comes to +filters. Both just take their input and produce no output until +``end_msg`` is called, at which time they complete the hash or MAC and +send that as output. + +These filters take a string naming the type to be used. If for some +reason you name something that doesn't exist, an exception will be thrown. + +.. cpp:function:: Hash_Filter::Hash_Filter(std::string hash, size_t outlen = 0) + + This constructor creates a filter that hashes its input with + ``hash``. When ``end_msg`` is called on the owning pipe, the hash is + completed and the digest is sent on to the next filter in the + pipeline. The parameter ``outlen`` specifies how many bytes of the + hash output will be passed along to the next filter when ``end_msg`` + is called. By default, it will pass the entire hash. + + Examples of names for ``Hash_Filter`` are "SHA-1" and "Whirlpool". + +.. cpp:function:: MAC_Filter::MAC_Filter(std::string mac, SymmetricKey key, size_t outlen = 0) + + This constructor takes a name for a mac, such as "HMAC(SHA-1)" or + "CMAC(AES-128)", along with a key to use. The optional ``outlen`` + works the same as in ``Hash_Filter``. + +Encoders +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Often you want your data to be in some form of text (for sending over +channels that aren't 8-bit clean, printing it, etc). The filters +``Hex_Encoder`` and ``Base64_Encoder`` will convert arbitrary binary +data into hex or base64 formats. Not surprisingly, you can use +``Hex_Decoder`` and ``Base64_Decoder`` to convert it back into its +original form. + +Both of the encoders can take a few options about how the data should +be formatted (all of which have defaults). The first is a ``bool`` +which says if the encoder should insert line breaks. This defaults to +false. Line breaks don't matter either way to the decoder, but it +makes the output a bit more appealing to the human eye, and a few +transport mechanisms (notably some email systems) limit the maximum +line length. + +The second encoder option is an integer specifying how long such lines +will be (obviously this will be ignored if line-breaking isn't being +used). The default tends to be in the range of 60-80 characters, but +is not specified. If you want a specific value, set it. Otherwise the +default should be fine. + +Lastly, ``Hex_Encoder`` takes an argument of type ``Case``, which can +be ``Uppercase`` or ``Lowercase`` (default is ``Uppercase``). This +specifies what case the characters A-F should be output as. The base64 +encoder has no such option, because it uses both upper and lower case +letters for its output. + +You can find the declarations for these types in ``hex_filt.h`` and +``b64_filt.h``. + +Writing New Filters +--------------------------------- + +The system of filters and pipes was designed in an attempt to make it +as simple as possible to write new filter types. There are four +functions that need to be implemented by a class deriving from +``Filter``: + +.. cpp:function:: std::string Filter::name() const + + This should just return a useful decription of the filter object. + +.. cpp:function:: void Filter::write(const uint8_t* input, size_t length) + + This function is what is called when a filter receives input for it + to process. The filter is not required to process the data right + away; many filters buffer their input before producing any output. A + filter will usually have ``write`` called many times during its + lifetime. + +.. cpp:function:: void Filter::send(uint8_t* output, size_t length) + + Eventually, a filter will want to produce some output to send along + to the next filter in the pipeline. It does so by calling ``send`` + with whatever it wants to send along to the next filter. There is + also a version of ``send`` taking a single byte argument, as a + convenience. + + .. note:: + + Normally a filter does not need to override ``send``, though it + can for special handling. It does however need to call this + function whenever it wants to produce output. + +.. cpp:function:: void Filter::start_msg() + + Implementing this function is optional. Implement it if your filter + would like to do some processing or setup at the start of each + message, such as allocating a data structure. + +.. cpp:function:: void Filter::end_msg() + + Implementing this function is optional. It is called when it has + been requested that filters finish up their computations. The filter + should finish up with whatever computation it is working on (for + example, a compressing filter would flush the compressor and + ``send`` the final block), and empty any buffers in preparation for + processing a fresh new set of input. + +Additionally, if necessary, filters can define a constructor that +takes any needed arguments, and a destructor to deal with deallocating +memory, closing files, etc. + diff --git a/comm/third_party/botan/doc/api_ref/fpe.rst b/comm/third_party/botan/doc/api_ref/fpe.rst new file mode 100644 index 0000000000..9d77a40864 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/fpe.rst @@ -0,0 +1,98 @@ +Format Preserving Encryption +======================================== + +Format preserving encryption (FPE) refers to a set of techniques for +encrypting data such that the ciphertext has the same format as the +plaintext. For instance, you can use FPE to encrypt credit card +numbers with valid checksums such that the ciphertext is also an +credit card number with a valid checksum, or similarly for bank +account numbers, US Social Security numbers, or even more general +mappings like English words onto other English words. + +The scheme currently implemented in botan is called FE1, and described +in the paper `Format Preserving Encryption +`_ by Mihir Bellare, Thomas +Ristenpart, Phillip Rogaway, and Till Stegers. FPE is an area of +ongoing standardization and it is likely that other schemes will be +included in the future. + +To encrypt an arbitrary value using FE1, you need to use a ranking +method. Basically, the idea is to assign an integer to every value you +might encrypt. For instance, a 16 digit credit card number consists of +a 15 digit code plus a 1 digit checksum. So to encrypt a credit card +number, you first remove the checksum, encrypt the 15 digit value +modulo 10\ :sup:`15`, and then calculate what the checksum is for the +new (ciphertext) number. Or, if you were encrypting words in a +dictionary, you could rank the words by their lexicographical order, +and choose the modulus to be the number of words in the dictionary. + +The interfaces for FE1 are defined in the header ``fpe_fe1.h``: + +.. versionadded:: 2.5.0 + +.. cpp:class:: FPE_FE1 + + .. cpp:function:: FPE_FE1(const BigInt& n, size_t rounds = 5, \ + bool compat_mode = false, \ + std::string mac_algo = "HMAC(SHA-256)") + + Initialize an FPE operation to encrypt/decrypt integers less + than *n*. It is expected that *n* is trivially factorable into + small integers. Common usage would be n to be a power of 10. + + Note that the default parameters to this constructor are + **incompatible** with the ``fe1_encrypt`` and ``fe1_decrypt`` + function originally added in 1.9.17. For compatibility, use + 3 rounds and set ``compat_mode`` to true. + + .. cpp:function:: BigInt encrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const + + Encrypts the value *x* modulo the value *n* using the *key* and *tweak* + specified. Returns an integer less than *n*. The *tweak* is a value that + does not need to be secret that parameterizes the encryption function. For + instance, if you were encrypting a database column with a single key, you + could use a per-row-unique integer index value as the tweak. The same + tweak value must be used during decryption. + + .. cpp:function:: BigInt decrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const + + Decrypts an FE1 ciphertext. The *tweak* must be the same as that provided + to the encryption function. Returns the plaintext integer. + + Note that there is not any implicit authentication or checking of data in + FE1, so if you provide an incorrect key or tweak the result is simply a + random integer. + + .. cpp:function:: BigInt encrypt(const BigInt& x, uint64_t tweak) + + Convenience version of encrypt taking an integer tweak. + + .. cpp:function:: BigInt decrypt(const BigInt& x, uint64_t tweak) + + Convenience version of decrypt taking an integer tweak. + +There are two functions that handle the entire FE1 encrypt/decrypt operation. +These are the original interface to FE1, first added in 1.9.17. However because +they do the entire setup cost for each operation, they are significantly slower +than the class-based API presented above. + +.. warning:: These functions are hardcoded to use 3 rounds, which may be + insufficient depending on the chosen modulus. + +.. cpp:function:: BigInt FPE::fe1_encrypt(const BigInt& n, const BigInt& X, \ + const SymmetricKey& key, const std::vector& tweak) + + This creates an FPE_FE1 object, sets the key, and encrypts *X* using + the provided tweak. + +.. cpp:function:: BigInt FPE::fe1_decrypt(const BigInt& n, const BigInt& X, \ + const SymmetricKey& key, const std::vector& tweak) + + This creates an FPE_FE1 object, sets the key, and decrypts *X* using + the provided tweak. + +This example encrypts a credit card number with a valid `Luhn checksum +`_ to another number with the same +format, including a correct checksum. + +.. literalinclude:: ../../src/cli/cc_enc.cpp diff --git a/comm/third_party/botan/doc/api_ref/hash.rst b/comm/third_party/botan/doc/api_ref/hash.rst new file mode 100644 index 0000000000..6198535f3c --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/hash.rst @@ -0,0 +1,351 @@ +Hash Functions and Checksums +============================= + +Hash functions are one-way functions, which map data of arbitrary size to a +fixed output length. Most of the hash functions in Botan are designed to be +cryptographically secure, which means that it is computationally infeasible to +create a collision (finding two inputs with the same hash) or preimages (given a +hash output, generating an arbitrary input with the same hash). But note that +not all such hash functions meet their goals, in particular MD4 and MD5 are +trivially broken. However they are still included due to their wide adoption in +various protocols. + +The class :cpp:class:`HashFunction` is defined in `botan/hash.h`. + +Using a hash function is typically split into three stages: initialization, +update, and finalization (often referred to as a IUF interface). The +initialization stage is implicit: after creating a hash function object, it is +ready to process data. Then update is called one or more times. Calling update +several times is equivalent to calling it once with all of the arguments +concatenated. After completing a hash computation (eg using ``final``), the +internal state is reset to begin hashing a new message. + +.. cpp:class:: HashFunction + + .. cpp:function:: static std::unique_ptr create(const std::string& name) + + Return a newly allocated hash function object, or nullptr if the + name is not recognized. + + .. cpp:function:: static std::unique_ptr create_or_throw(const std::string& name) + + Like ``create`` except that it will throw an exception instead of + returning nullptr. + + .. cpp:function:: size_t output_length() + + Return the size (in *bytes*) of the output of this function. + + .. cpp:function:: void update(const uint8_t* input, size_t length) + + Updates the computation with *input*. + + .. cpp:function:: void update(uint8_t input) + + Updates the computation with *input*. + + .. cpp:function:: void update(const std::vector& input) + + Updates the computation with *input*. + + .. cpp:function:: void update(const std::string& input) + + Updates the computation with *input*. + + .. cpp:function:: void final(uint8_t* out) + + Finalize the calculation and place the result into ``out``. + For the argument taking an array, exactly ``output_length`` bytes will + be written. After you call ``final``, the algorithm is reset to + its initial state, so it may be reused immediately. + + .. cpp:function:: secure_vector final() + + Similar to the other function of the same name, except it returns + the result in a newly allocated vector. + + .. cpp:function:: secure_vector process(const uint8_t in[], size_t length) + + Equivalent to calling ``update`` followed by ``final``. + + .. cpp:function:: secure_vector process(const std::string& in) + + Equivalent to calling ``update`` followed by ``final``. + +Code Example +------------ + +Assume we want to calculate the SHA-256, SHA-384, and SHA-3 hash digests of the STDIN stream using the Botan library. + +.. code-block:: cpp + + #include + #include + #include + int main () + { + std::unique_ptr hash1(Botan::HashFunction::create("SHA-256")); + std::unique_ptr hash2(Botan::HashFunction::create("SHA-384")); + std::unique_ptr hash3(Botan::HashFunction::create("SHA-3")); + std::vector buf(2048); + + while(std::cin.good()) + { + //read STDIN to buffer + std::cin.read(reinterpret_cast(buf.data()), buf.size()); + size_t readcount = std::cin.gcount(); + //update hash computations with read data + hash1->update(buf.data(),readcount); + hash2->update(buf.data(),readcount); + hash3->update(buf.data(),readcount); + } + std::cout << "SHA-256: " << Botan::hex_encode(hash1->final()) << std::endl; + std::cout << "SHA-384: " << Botan::hex_encode(hash2->final()) << std::endl; + std::cout << "SHA-3: " << Botan::hex_encode(hash3->final()) << std::endl; + return 0; + } + +Available Hash Functions +------------------------------ + +The following cryptographic hash functions are implemented. If in doubt, +any of SHA-384, SHA-3, or BLAKE2b are fine choices. + +BLAKE2b +^^^^^^^^^ + +Available if ``BOTAN_HAS_BLAKE2B`` is defined. + +A recently designed hash function. Very fast on 64-bit processors. Can output a +hash of any length between 1 and 64 bytes, this is specified by passing a value +to the constructor with the desired length. + +Named like "Blake2b" which selects default 512-bit output, or as +"Blake2b(256)" to select 256 bits of output. + +GOST-34.11 +^^^^^^^^^^^^^^^ + +.. deprecated:: 2.11 + +Available if ``BOTAN_HAS_GOST_34_11`` is defined. + +Russian national standard hash. It is old, slow, and has some weaknesses. Avoid +it unless you must. + +.. warning:: + As this hash function is no longer approved by the latest Russian standards, + support for GOST 34.11 hash is deprecated and will be removed in a future + major release. + +Keccak-1600 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_KECCAK`` is defined. + +An older (and incompatible) variant of SHA-3, but sometimes used. Prefer SHA-3 in +new code. + +MD4 +^^^^^^^^^ + +Available if ``BOTAN_HAS_MD4`` is defined. + +An old hash function that is now known to be trivially breakable. It is very +fast, and may still be suitable as a (non-cryptographic) checksum. + +.. warning:: + Support for MD4 is deprecated and will be removed in a future major release. + +MD5 +^^^^^^^^^ + +Available if ``BOTAN_HAS_MD5`` is defined. + +Widely used, now known to be broken. + +RIPEMD-160 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_RIPEMD160`` is defined. + +A 160 bit hash function, quite old but still thought to be secure (up to the +limit of 2**80 computation required for a collision which is possible with any +160 bit hash function). Somewhat deprecated these days. + +SHA-1 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA1`` is defined. + +Widely adopted NSA designed hash function. Starting to show significant signs of +weakness, and collisions can now be generated. Avoid in new designs. + +SHA-256 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA2_32`` is defined. + +Relatively fast 256 bit hash function, thought to be secure. + +Also includes the variant SHA-224. There is no real reason to use SHA-224. + +SHA-512 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA2_64`` is defined. + +SHA-512 is faster than SHA-256 on 64-bit processors. Also includes the +truncated variants SHA-384 and SHA-512/256, which have the advantage +of avoiding message extension attacks. + +SHA-3 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA3`` is defined. + +The new NIST standard hash. Fairly slow. + +Supports 224, 256, 384 or 512 bit outputs. SHA-3 is faster with +smaller outputs. Use as "SHA-3(256)" or "SHA-3(512)". Plain "SHA-3" +selects default 512 bit output. + +SHAKE (SHAKE-128, SHAKE-256) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHAKE`` is defined. + +These are actually XOFs (extensible output functions) based on SHA-3, which can +output a value of any byte length. For example "SHAKE-128(1024)" will produce +1024 bits of output. The specified length must be a multiple of 8. Not +specifying an output length, "SHAKE-128" defaults to a 128-bit output and +"SHAKE-256" defaults to a 256-bit output. + +.. warning:: + In the case of SHAKE-128, the default output length in insufficient + to ensure security. The choice of default lengths was a bug which is + currently retained for compatability; they should have been 256 and + 512 bits resp to match SHAKE's security level. Using the default + lengths with SHAKE is deprecated and will be removed in a future major + release. Instead, always specify the desired output length. + +SM3 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SM3`` is defined. + +Chinese national hash function, 256 bit output. Widely used in industry there. +Fast and seemingly secure, but no reason to prefer it over SHA-2 or SHA-3 unless +required. + +Skein-512 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SKEIN_512`` is defined. + +A contender for the NIST SHA-3 competition. Very fast on 64-bit systems. Can +output a hash of any length between 1 and 64 bytes. It also accepts an optional +"personalization string" which can create variants of the hash. This is useful +for domain separation. + +To set a personalization string set the second param to any value, +typically ASCII strings are used. Examples "Skein-512(256)" or +"Skein-512(384,personalization_string)". + +Streebog (Streebog-256, Streebog-512) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_STREEBOG`` is defined. + +Newly designed Russian national hash function. Due to use of input-dependent +table lookups, it is vulnerable to side channels. There is no reason to use it +unless compatibility is needed. + +.. warning:: + The Streebog Sbox has recently been revealed to have a hidden structure which + interacts with its linear layer in a way which may provide a backdoor when + used in certain ways. Avoid Streebog if at all possible. + +Tiger +^^^^^^^^^^^^^^^ + +.. deprecated:: 2.15 + +Available if ``BOTAN_HAS_TIGER`` is defined. + +An older 192-bit hash function, optimized for 64-bit systems. Possibly +vulnerable to side channels due to its use of table lookups. + +Tiger supports variable length output (16, 20 or 24 bytes) and +variable rounds (which must be at least 3). Default is 24 byte output +and 3 rounds. Specify with names like "Tiger" or "Tiger(20,5)". + +.. warning:: + There are documented (albeit impractical) attacks on the full Tiger + hash leading to preimage attacks. This indicates possibility of a + serious weakness in the hash and for this reason it is deprecated + and will be removed in a future major release of the library. + +Whirlpool +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_WHIRLPOOL`` is defined. + +A 512-bit hash function standardized by ISO and NESSIE. Relatively slow, and due +to the table based implementation it is potentially vulnerable to cache based +side channels. + +Hash Function Combiners +--------------------------- + +These are functions which combine multiple hash functions to create a new hash +function. They are typically only used in specialized applications. + +Parallel +^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_PARALLEL_HASH`` is defined. + +Parallel simply concatenates multiple hash functions. For example +"Parallel(SHA-256,SHA-512)" outputs a 256+512 bit hash created by hashing the +input with both SHA-256 and SHA-512 and concatenating the outputs. + +Note that due to the "multicollision attack" it turns out that generating a +collision for multiple parallel hash functions is no harder than generating a +collision for the strongest hash function. + +Comp4P +^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_COMB4P`` is defined. + +This combines two cryptographic hashes in such a way that preimage and collision +attacks are provably at least as hard as a preimage or collision attack on the +strongest hash. + +Checksums +---------------- + +.. note:: Checksums are not suitable for cryptographic use, but can be used for + error checking purposes. + +Adler32 +^^^^^^^^^^^ + +Available if ``BOTAN_HAS_ADLER32`` is defined. + +The Adler32 checksum is used in the zlib format. 32 bit output. + +CRC24 +^^^^^^^^^^^ + +Available if ``BOTAN_HAS_CRC24`` is defined. + +This is the CRC function used in OpenPGP. 24 bit output. + +CRC32 +^^^^^^^^^^^ + +Available if ``BOTAN_HAS_CRC32`` is defined. + +This is the 32-bit CRC used in protocols such as Ethernet, gzip, PNG, etc. diff --git a/comm/third_party/botan/doc/api_ref/kdf.rst b/comm/third_party/botan/doc/api_ref/kdf.rst new file mode 100644 index 0000000000..f0975a8cc3 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/kdf.rst @@ -0,0 +1,109 @@ + +.. _key_derivation_function: + +Key Derivation Functions +======================================== + +Key derivation functions are used to turn some amount of shared secret +material into uniform random keys suitable for use with symmetric +algorithms. An example of an input which is useful for a KDF is a +shared secret created using Diffie-Hellman key agreement. + +.. cpp:class:: KDF + + .. cpp:function:: secure_vector derive_key( \ + size_t key_len, const std::vector& secret, \ + const std::string& salt = "") const + + .. cpp:function:: secure_vector derive_key( \ + size_t key_len, const std::vector& secret, \ + const std::vector& salt) const + + .. cpp:function:: secure_vector derive_key( \ + size_t key_len, const std::vector& secret, \ + const uint8_t* salt, size_t salt_len) const + + .. cpp:function:: secure_vector derive_key( \ + size_t key_len, const uint8_t* secret, size_t secret_len, \ + const std::string& salt) const + + All variations on the same theme. Deterministically creates a + uniform random value from *secret* and *salt*. Typically *salt* is + a label or identifier, such as a session id. + +You can create a :cpp:class:`KDF` using + +.. cpp:function:: KDF* get_kdf(const std::string& algo_spec) + + +Available KDFs +------------------- + +Botan includes many different KDFs simply because different protocols and +standards have created subtly different approaches to this problem. For new +code, use HKDF which is conservative, well studied, widely implemented and NIST +approved. + +HKDF +~~~~~ + +Defined in RFC 5869, HKDF uses HMAC to process inputs. Also available +are variants HKDF-Extract and HKDF-Expand. HKDF is the combined +Extract+Expand operation. Use the combined HKDF unless you need +compatibility with some other system. + +Available if ``BOTAN_HAS_HKDF`` is defined. + +KDF2 +~~~~~ + +KDF2 comes from IEEE 1363. It uses a hash function. + +Available if ``BOTAN_HAS_KDF2`` is defined. + +KDF1-18033 +~~~~~~~~~~~~ + +KDF1 from ISO 18033-2. Very similar to (but incompatible with) KDF2. + +Available if ``BOTAN_HAS_KDF1_18033`` is defined. + +KDF1 +~~~~~~ + +KDF1 from IEEE 1363. It can only produce an output at most the length +of the hash function used. + +Available if ``BOTAN_HAS_KDF1`` is defined. + +X9.42 PRF +~~~~~~~~~~ + +A KDF from ANSI X9.42. Sometimes used for Diffie-Hellman. + +Available if ``BOTAN_HAS_X942_PRF`` is defined. + +.. warning:: + Support for X9.42 KDF is deprecated and will be removed in a future major release. + +SP800-108 +~~~~~~~~~~ + +KDFs from NIST SP 800-108. Variants include "SP800-108-Counter", +"SP800-108-Feedback" and "SP800-108-Pipeline". + +Available if ``BOTAN_HAS_SP800_108`` is defined. + +SP800-56A +~~~~~~~~~~ + +KDF from NIST SP 800-56A. + +Available if ``BOTAN_HAS_SP800_56A`` is defined. + +SP800-56C +~~~~~~~~~~ + +KDF from NIST SP 800-56C. + +Available if ``BOTAN_HAS_SP800_56C`` is defined. diff --git a/comm/third_party/botan/doc/api_ref/keywrap.rst b/comm/third_party/botan/doc/api_ref/keywrap.rst new file mode 100644 index 0000000000..5c3aac0a3e --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/keywrap.rst @@ -0,0 +1,60 @@ +AES Key Wrapping +================================= + +NIST specifies two mechanisms for wrapping (encrypting) symmetric keys using +another key. The first (and older, more widely supported) method requires the +input be a multiple of 8 bytes long. The other allows any length input, though +only up to 2**32 bytes. + +These algorithms are described in NIST SP 800-38F, and RFCs 3394 and 5649. + +This API, defined in ``nist_keywrap.h``, first became available in version 2.4.0 + +These functions take an arbitrary 128-bit block cipher object, which must +already have been keyed with the key encryption key. NIST only allows these +functions with AES, but any 128-bit cipher will do and some other implementations +(such as in OpenSSL) do also allow other ciphers. Use AES for best interop. + +.. cpp:function:: std::vector nist_key_wrap(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This performs KW (key wrap) mode. The input must be a multiple of 8 bytes long. + +.. cpp:function:: secure_vector nist_key_unwrap(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This unwraps the result of nist_key_wrap, or throw Invalid_Authentication_Tag on error. + +.. cpp:function:: std::vector nist_key_wrap_padded(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This performs KWP (key wrap with padding) mode. The input can be any length. + +.. cpp:function:: secure_vector nist_key_unwrap_padded(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This unwraps the result of nist_key_wrap_padded, or throws Invalid_Authentication_Tag + on error. + +RFC 3394 Interface +----------------------------- + +This is an older interface that was first available (with slight changes) in +1.10, and available in its current form since 2.0 release. It uses a 128-bit, +192-bit, or 256-bit key to encrypt an input key. AES is always used. The input +must be a multiple of 8 bytes; if not an exception is thrown. + +This interface is defined in ``rfc3394.h``. + +.. cpp:function:: secure_vector rfc3394_keywrap(const secure_vector& key, \ + const SymmetricKey& kek) + + Wrap the input key using kek (the key encryption key), and return the result. It will + be 8 bytes longer than the input key. + +.. cpp:function:: secure_vector rfc3394_keyunwrap(const secure_vector& key, \ + const SymmetricKey& kek) + + Unwrap a key wrapped with rfc3394_keywrap. + + diff --git a/comm/third_party/botan/doc/api_ref/message_auth_codes.rst b/comm/third_party/botan/doc/api_ref/message_auth_codes.rst new file mode 100644 index 0000000000..a3391a3105 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/message_auth_codes.rst @@ -0,0 +1,268 @@ + +.. _mac: + +Message Authentication Codes (MAC) +=================================== + +A Message Authentication Code algorithm computes a tag over a message utilizing +a shared secret key. Thus a valid tag confirms the authenticity and integrity of +the message. Only entities in possession of the shared secret key are able to +verify the tag. + +.. note:: + + When combining a MAC with unauthenticated encryption mode, prefer to first + encrypt the message and then MAC the ciphertext. The alternative is to MAC + the plaintext, which depending on exact usage can suffer serious security + issues. For a detailed discussion of this issue see the paper "The Order of + Encryption and Authentication for Protecting Communications" by Hugo + Krawczyk + +The Botan MAC computation is split into five stages. + +#. Instantiate the MAC algorithm. +#. Set the secret key. +#. Process IV. +#. Process data. +#. Finalize the MAC computation. + +.. cpp:class:: MessageAuthenticationCode + + .. cpp:function:: std::string name() const + + Returns a human-readable string of the name of this algorithm. + + .. cpp:function:: void clear() + + Clear the key. + + .. cpp:function:: MessageAuthenticationCode* clone() const + + Return a newly allocated object of the same type as this one. + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + Set the shared MAC key for the calculation. This function has to be called before the data is processed. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid + keylength for the algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: void start(const uint8_t* nonce, size_t nonce_len) + + Set the IV for the MAC calculation. Note that not all MAC algorithms require an IV. + If an IV is required, the function has to be called before the data is processed. + For algorithms that don't require it, the call can be omitted, or else called + with ``nonce_len`` of zero. + + .. cpp:function:: void update(const uint8_t* input, size_t length) + + Process the passed data. + + .. cpp:function:: void update(const secure_vector& in) + + Process the passed data. + + .. cpp:function:: void update(uint8_t in) + + Process a single byte. + + .. cpp:function:: void final(uint8_t* out) + + Complete the MAC computation and write the calculated tag to the passed byte array. + + .. cpp:function:: secure_vector final() + + Complete the MAC computation and return the calculated tag. + + .. cpp:function:: bool verify_mac(const uint8_t* mac, size_t length) + + Finalize the current MAC computation and compare the result to the passed + ``mac``. Returns ``true``, if the verification is successful and false + otherwise. + + +Code Examples +------------------------ + +The following example computes an HMAC with a random key then verifies the tag. + + #include + #include + #include + #include + + std::string compute_mac(const std::string& msg, const Botan::secure_vector& key) + { + auto hmac = Botan::MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + + hmac->set_key(key); + hmac->update(msg); + + return Botan::hex_encode(hmac->final()); + } + + int main() + { + Botan::System_RNG rng; + + const auto key = rng.random_vec(32); // 256 bit random key + + // "Message" != "Mussage" so tags will also not match + std::string tag1 = compute_mac("Message", key); + std::string tag2 = compute_mac("Mussage", key); + assert(tag1 != tag2); + + // Recomputing with original input message results in identical tag + std::string tag3 = compute_mac("Message", key); + assert(tag1 == tag3); + } + + +The following example code computes a AES-256 GMAC and subsequently verifies the +tag. Unlike most other MACs, GMAC requires a nonce *which must not repeat or +all security is lost*. + +.. code-block:: cpp + + #include + #include + #include + + int main() + { + const std::vector key = Botan::hex_decode("1337133713371337133713371337133713371337133713371337133713371337"); + const std::vector nonce = Botan::hex_decode("FFFFFFFFFFFFFFFFFFFFFFFF"); + const std::vector data = Botan::hex_decode("6BC1BEE22E409F96E93D7E117393172A"); + std::unique_ptr mac(Botan::MessageAuthenticationCode::create("GMAC(AES-256)")); + if(!mac) + return 1; + mac->set_key(key); + mac->start(nonce); + mac->update(data); + Botan::secure_vector tag = mac->final(); + std::cout << mac->name() << ": " << Botan::hex_encode(tag) << std::endl; + + //Verify created MAC + mac->start(nonce); + mac->update(data); + std::cout << "Verification: " << (mac->verify_mac(tag) ? "success" : "failure"); + return 0; + } + +The following example code computes a valid AES-128 CMAC tag and modifies the +data to demonstrate a MAC verification failure. + +.. code-block:: cpp + + #include + #include + #include + + int main() + { + const std::vector key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C"); + std::vector data = Botan::hex_decode("6BC1BEE22E409F96E93D7E117393172A"); + std::unique_ptr mac(Botan::MessageAuthenticationCode::create("CMAC(AES-128)")); + if(!mac) + return 1; + mac->set_key(key); + mac->update(data); + Botan::secure_vector tag = mac->final(); + //Corrupting data + data.back()++; + //Verify with corrupted data + mac->update(data); + std::cout << "Verification with malformed data: " << (mac->verify_mac(tag) ? "success" : "failure"); + return 0; + } + +Available MACs +------------------------------------------ + +Currently the following MAC algorithms are available in Botan. In new code, +default to HMAC with a strong hash like SHA-256 or SHA-384. + +CBC-MAC +~~~~~~~~~~~~ + +An older authentication code based on a block cipher. Serious security problems, +in particular **insecure** if messages of several different lengths are +authenticated. Avoid unless required for compatibility. + +Available if ``BOTAN_HAS_CBC_MAC`` is defined. + +.. warning:: + CBC-MAC support is deprecated and will be removed in a future major release. + +CMAC +~~~~~~~~~~~~ + +A modern CBC-MAC variant that avoids the security problems of plain CBC-MAC. +Approved by NIST. Also sometimes called OMAC. + +Available if ``BOTAN_HAS_CMAC`` is defined. + +GMAC +~~~~~~~~~~~~ + +GMAC is related to the GCM authenticated cipher mode. It is quite slow unless +hardware support for carryless multiplications is available. A new nonce +must be used with **each** message authenticated, or otherwise all security is +lost. + +Available if ``BOTAN_HAS_GMAC`` is defined. + +.. warning:: + Due to the nonce requirement, GMAC is exceptionally fragile. Avoid it unless + absolutely required. + +HMAC +~~~~~~~~~~~~ + +A message authentication code based on a hash function. Very commonly used. + +Available if ``BOTAN_HAS_HMAC`` is defined. + +Poly1305 +~~~~~~~~~~~~ + +A polynomial mac (similar to GMAC). Very fast, but tricky to use safely. Forms +part of the ChaCha20Poly1305 AEAD mode. A new key must be used for **each** +message, or all security is lost. + +Available if ``BOTAN_HAS_POLY1305`` is defined. + +.. warning:: + Due to the nonce requirement, Poly1305 is exceptionally fragile. Avoid it unless + absolutely required. + +SipHash +~~~~~~~~~~~~ + +A modern and very fast PRF. Produces only a 64-bit output. Defaults to +"SipHash(2,4)" which is the recommended configuration, using 2 rounds for each +input block and 4 rounds for finalization. + +Available if ``BOTAN_HAS_SIPHASH`` is defined. + +X9.19-MAC +~~~~~~~~~~~~ + +A CBC-MAC variant sometimes used in finance. Always uses DES. +Sometimes called the "DES retail MAC", also standardized in ISO 9797-1. + +It is slow and has known attacks. Avoid unless required. + +Available if ``BOTAN_HAS_X919_MAC`` is defined. diff --git a/comm/third_party/botan/doc/api_ref/otp.rst b/comm/third_party/botan/doc/api_ref/otp.rst new file mode 100644 index 0000000000..133201b4e6 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/otp.rst @@ -0,0 +1,98 @@ +One Time Passwords +======================== + +.. versionadded:: 2.2.0 + +One time password schemes are a user authentication method that relies on a +fixed secret key which is used to derive a sequence of short passwords, each of +which is accepted only once. Commonly this is used to implement two-factor +authentication (2FA), where the user authenticates using both a conventional +password (or a public key signature) and an OTP generated by a small device such +as a mobile phone. + +Botan implements the HOTP and TOTP schemes from RFC 4226 and 6238. + +Since the range of possible OTPs is quite small, applications must rate limit +OTP authentication attempts to some small number per second. Otherwise an attacker +could quickly try all 1000000 6-digit OTPs in a brief amount of time. + +HOTP +^^^^^^ + +HOTP generates OTPs that are a short numeric sequence, between 6 and 8 digits +(most applications use 6 digits), created using the HMAC of a 64-bit counter +value. If the counter ever repeats the OTP will also repeat, thus both parties +must assure the counter only increments and is never repeated or +decremented. Thus both client and server must keep track of the next counter +expected. + +Anyone with access to the client-specific secret key can authenticate as that +client, so it should be treated with the same security consideration as would be +given to any other symmetric key or plaintext password. + +.. cpp:class:: HOTP + + Implement counter-based OTP + + .. cpp:function:: HOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", size_t digits = 6) + + Initialize an HOTP instance with a secret key (specific to each client), + a hash algorithm (must be SHA-1, SHA-256, or SHA-512), and the number of + digits with each OTP (must be 6, 7, or 8). + + In RFC 4226, HOTP is only defined with SHA-1, but many HOTP + implementations support SHA-256 as an extension. The collision attacks + on SHA-1 do not have any known effect on HOTP's security. + + .. cpp:function:: uint32_t generate_hotp(uint64_t counter) + + Return the OTP associated with a specific counter value. + + .. cpp:function:: std::pair verify_hotp(uint32_t otp, \ + uint64_t starting_counter, size_t resync_range = 0) + + Check if a provided OTP matches the one that should be generated for + the specified counter. + + The *starting_counter* should be the counter of the last successful + authentication plus 1. If *resync_resync* is greater than 0, some number + of counter values above *starting_counter* will also be checked if + necessary. This is useful for instance when a client mistypes an OTP on + entry; the authentication will fail so the server will not update its + counter, but the client device will subsequently show the OTP for the + next counter. Depending on the environment a *resync_range* of 3 to 10 + might be appropriate. + + Returns a pair of (is_valid,next_counter_to_use). If the OTP is invalid + then always returns (false,starting_counter), since the last successful + authentication counter has not changed. + + +TOTP +^^^^^^^^^^ + +TOTP is based on the same algorithm as HOTP, but instead of a counter a +timestamp is used. + +.. cpp:class:: TOTP + + .. cpp:function:: TOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", \ + size_t digits = 6, size_t time_step = 30) + + Setup to perform TOTP authentication using secret key *key*. + + .. cpp:function:: uint32_t generate_totp(std::chrono::system_clock::time_point time_point) + + .. cpp:function:: uint32_t generate_totp(uint64_t unix_time) + + Generate and return a TOTP code based on a timestamp. + + .. cpp:function:: bool verify_totp(uint32_t otp, std::chrono::system_clock::time_point time, \ + size_t clock_drift_accepted = 0) + + .. cpp:function:: bool verify_totp(uint32_t otp, uint64_t unix_time, \ + size_t clock_drift_accepted = 0) + + Return true if the provided OTP code is correct for the provided + timestamp. If required, use *clock_drift_accepted* to deal with + the client and server having slightly different clocks. diff --git a/comm/third_party/botan/doc/api_ref/passhash.rst b/comm/third_party/botan/doc/api_ref/passhash.rst new file mode 100644 index 0000000000..4ef26f7bea --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/passhash.rst @@ -0,0 +1,219 @@ +Password Hashing +======================================== + +Storing passwords for user authentication purposes in plaintext is the +simplest but least secure method; when an attacker compromises the +database in which the passwords are stored, they immediately gain +access to all of them. Often passwords are reused among multiple +services or machines, meaning once a password to a single service is +known an attacker has a substantial head start on attacking other +machines. + +The general approach is to store, instead of the password, the output +of a one way function of the password. Upon receiving an +authentication request, the authenticating party can recompute the one way +function and compare the value just computed with the one that was +stored. If they match, then the authentication request succeeds. But +when an attacker gains access to the database, they only have the +output of the one way function, not the original password. + +Common hash functions such as SHA-256 are one way, but used alone they +have problems for this purpose. What an attacker can do, upon gaining +access to such a stored password database, is hash common dictionary +words and other possible passwords, storing them in a list. Then he +can search through his list; if a stored hash and an entry in his list +match, then he has found the password. Even worse, this can happen +*offline*: an attacker can begin hashing common passwords days, +months, or years before ever gaining access to the database. In +addition, if two users choose the same password, the one way function +output will be the same for both of them, which will be visible upon +inspection of the database. + +There are two solutions to these problems: salting and +iteration. Salting refers to including, along with the password, a +randomly chosen value which perturbs the one way function. Salting can +reduce the effectiveness of offline dictionary generation, because for +each potential password, an attacker would have to compute the one way +function output for all possible salts. It also prevents the same +password from producing the same output, as long as the salts do not +collide. Choosing n-bit salts randomly, salt collisions become likely +only after about 2\ :sup:\ `(n/2)` salts have been generated. Choosing a +large salt (say 80 to 128 bits) ensures this is very unlikely. Note +that in password hashing salt collisions are unfortunate, but not +fatal - it simply allows the attacker to attack those two passwords in +parallel easier than they would otherwise be able to. + +The other approach, iteration, refers to the general technique of +forcing multiple one way function evaluations when computing the +output, to slow down the operation. For instance if hashing a single +password requires running SHA-256 100,000 times instead of just once, +that will slow down user authentication by a factor of 100,000, but +user authentication happens quite rarely, and usually there are more +expensive operations that need to occur anyway (network and database +I/O, etc). On the other hand, an attacker who is attempting to break a +database full of stolen password hashes will be seriously +inconvenienced by a factor of 100,000 slowdown; they will be able to +only test at a rate of .0001% of what they would without iterations +(or, equivalently, will require 100,000 times as many zombie botnet +hosts). + +Memory usage while checking a password is also a consideration; if the +computation requires using a certain minimum amount of memory, then an +attacker can become memory-bound, which may in particular make +customized cracking hardware more expensive. Some password hashing +designs, such as scrypt, explicitly attempt to provide this. The +bcrypt approach requires over 4 KiB of RAM (for the Blowfish key +schedule) and may also make some hardware attacks more expensive. + +Botan provides three techniques for password hashing: Argon2, bcrypt, and +passhash9 (based on PBKDF2). + +Argon2 +---------------------------------------- + +.. versionadded:: 2.11.0 + +Argon2 is the winner of the PHC (Password Hashing Competition) and provides +a tunable memory hard password hash. It has a standard string encoding, which looks like:: + + "$argon2i$v=19$m=8192,t=10,p=3$YWFhYWFhYWE$itkWB9ODqTd85wUsoib7pfpVTNGMOu0ZJan1odl25V8" + +Argon2 has three tunable parameters: ``M``, ``p``, and ``t``. ``M`` gives the +total memory consumption of the algorithm in kilobytes. Increasing ``p`` +increases the available parallelism of the computation. The ``t`` parameter +gives the number of passes which are made over the data. + +.. note:: + Currently Botan does not make use of ``p`` > 1, so it is best to set it to 1 + to minimize any advantage to highly parallel cracking attempts. + +There are three variants of Argon2, namely Argon2d, Argon2i and Argon2id. +Argon2d uses data dependent table lookups with may leak information about the +password via side channel attacks, and is **not recommended** for password +hashing. Argon2i uses data independent table lookups and is immune to these +attacks, but at the cost of requiring higher ``t`` for security. Argon2id uses a +hybrid approach which is thought to be highly secure. The algorithm designers +recommend using Argon2id with ``t`` and ``p`` both equal to 1 and ``M`` set to +the largest amount of memory usable in your environment. + +.. cpp:function:: std::string argon2_generate_pwhash(const char* password, size_t password_len, \ + RandomNumberGenerator& rng, \ + size_t p, size_t M, size_t t, \ + size_t y = 2, size_t salt_len = 16, size_t output_len = 32) + + Generate an Argon2 hash of the specified password. The ``y`` parameter specifies + the variant: 0 for Argon2d, 1 for Argon2i, and 2 for Argon2id. + +.. cpp:function:: bool argon2_check_pwhash(const char* password, size_t password_len, \ + const std::string& hash) + + Verify an Argon2 password hash against the provided password. Returns false if + the input hash seems malformed or if the computed hash does not match. + +Bcrypt +---------------------------------------- + +`Bcrypt `_ is a +password hashing scheme originally designed for use in OpenBSD, but numerous +other implementations exist. It is made available by including ``bcrypt.h``. + +It has the advantage that it requires a small amount (4K) of fast RAM +to compute, which can make hardware password cracking somewhat more +expensive. + +Bcrypt provides outputs that look like this:: + + "$2a$12$7KIYdyv8Bp32WAvc.7YvI.wvRlyVn0HP/EhPmmOyMQA4YKxINO0p2" + +.. note:: + + Due to the design of bcrypt, the password is effectively truncated at 72 + characters; further characters are ignored and do not change the hash. To + support longer passwords, one common approach is to pre-hash the password + with SHA-256, then run bcrypt using the hex or base64 encoding of the hash as + the password. (Many bcrypt implementations truncate the password at the first + NULL character, so hashing the raw binary SHA-256 may cause problems. Botan's + bcrypt implementation will hash whatever values are given in the + ``std::string`` including any embedded NULLs so this is not an issue, but + might cause interop problems if another library needs to validate the + password hashes.) + +.. cpp:function:: std::string generate_bcrypt(const std::string& password, \ + RandomNumberGenerator& rng, \ + uint16_t work_factor = 12, \ + char bcrypt_version = "a") + + Takes the password to hash, a rng, and a work factor. + The resulting password hash is returned as a string. + + Higher work factors increase the amount of time the algorithm runs, + increasing the cost of cracking attempts. The increase is exponential, so a + work factor of 12 takes roughly twice as long as work factor 11. The default + work factor was set to 10 up until the 2.8.0 release. + + It is recommended to set the work factor as high as your system can tolerate + (from a performance and latency perspective) since higher work factors greatly + improve the security against GPU-based attacks. For example, for protecting + high value administrator passwords, consider using work factor 15 or 16; at + these work factors each bcrypt computation takes several seconds. Since admin + logins will be relatively uncommon, it might be acceptable for each login + attempt to take some time. As of 2018, a good password cracking rig (with 8 + NVIDIA 1080 cards) can attempt about 1 billion bcrypt computations per month + for work factor 13. For work factor 12, it can do twice as many. For work + factor 15, it can do only one quarter as many attempts. + + Due to bugs affecting various implementations of bcrypt, several different + variants of the algorithm are defined. As of 2.7.0 Botan supports generating + (or checking) the 2a, 2b, and 2y variants. Since Botan has never been + affected by any of the bugs which necessitated these version upgrades, all + three versions are identical beyond the version identifier. Which variant to + use is controlled by the ``bcrypt_version`` argument. + + The bcrypt work factor must be at least 4 (though at this work factor bcrypt + is not very secure). The bcrypt format allows up to 31, but Botan currently + rejects all work factors greater than 18 since even that work factor requires + roughly 15 seconds of computation on a fast machine. + +.. cpp:function:: bool check_bcrypt(const std::string& password, \ + const std::string& hash) + + Takes a password and a bcrypt output and returns true if the + password is the same as the one that was used to generate the + bcrypt hash. + +.. _passhash9: + +Passhash9 +---------------------------------------- + +Botan also provides a password hashing technique called passhash9, in +``passhash9.h``, which is based on PBKDF2. + +Passhash9 hashes look like:: + + "$9$AAAKxwMGNPSdPkOKJS07Xutm3+1Cr3ytmbnkjO6LjHzCMcMQXvcT" + +This function should be secure with the proper parameters, and will remain in +the library for the foreseeable future, but it is specific to Botan rather than +being a widely used password hash. Prefer bcrypt or Argon2. + +.. warning:: + + This password format string ("$9$") conflicts with the format used + for scrypt password hashes on Cisco systems. + +.. cpp:function:: std::string generate_passhash9(const std::string& password, \ + RandomNumberGenerator& rng, uint16_t work_factor = 15, uint8_t alg_id = 4) + + Functions much like ``generate_bcrypt``. The last parameter, + ``alg_id``, specifies which PRF to use. Currently defined values are + 0: HMAC(SHA-1), 1: HMAC(SHA-256), 2: CMAC(Blowfish), 3: HMAC(SHA-384), 4: HMAC(SHA-512) + + The work factor must be greater than zero and less than 512. This performs + 10000 * ``work_factor`` PBKDF2 iterations, using 96 bits of salt taken from + ``rng``. Using work factor of 10 or more is recommended. + +.. cpp:function:: bool check_passhash9(const std::string& password, \ + const std::string& hash) + + Functions much like ``check_bcrypt`` diff --git a/comm/third_party/botan/doc/api_ref/pbkdf.rst b/comm/third_party/botan/doc/api_ref/pbkdf.rst new file mode 100644 index 0000000000..92f59f2780 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/pbkdf.rst @@ -0,0 +1,190 @@ + +.. _pbkdf: + +Password Based Key Derivation +======================================== + +Often one needs to convert a human readable password into a cryptographic +key. It is useful to slow down the computation of these computations in order to +reduce the speed of brute force search, thus they are parameterized in some +way which allows their required computation to be tuned. + +PBKDF +--------- + +:cpp:class:`PBKDF` is the older API for this functionality, presented in header +``pbkdf.h``. It does not support Scrypt, nor will it be able to support other +future hashes (such as Argon2) that may be added in the future. In addition, +this API requires the passphrase be entered as a ``std::string``, which means +the secret will be stored in memory that will not be zeroed. + +.. cpp:class:: PBKDF + + .. cpp:function:: void pbkdf_iterations(uint8_t out[], size_t out_len, \ + const std::string& passphrase, \ + const uint8_t salt[], size_t salt_len, \ + size_t iterations) const + + Run the PBKDF algorithm for the specified number of iterations, + with the given salt, and write output to the buffer. + + .. cpp:function:: void pbkdf_timed(uint8_t out[], size_t out_len, \ + const std::string& passphrase, \ + const uint8_t salt[], size_t salt_len, \ + std::chrono::milliseconds msec, \ + size_t& iterations) const + + Choose (via short run-time benchmark) how many iterations to perform + in order to run for roughly msec milliseconds. Writes the number + of iterations used to reference argument. + + .. cpp:function:: OctetString derive_key( \ + size_t output_len, const std::string& passphrase, \ + const uint8_t* salt, size_t salt_len, \ + size_t iterations) const + + Computes a key from *passphrase* and the *salt* (of length + *salt_len* bytes) using an algorithm-specific interpretation of + *iterations*, producing a key of length *output_len*. + + Use an iteration count of at least 10000. The salt should be + randomly chosen by a good random number generator (see + :ref:`random_number_generators` for how), or at the very least + unique to this usage of the passphrase. + + If you call this function again with the same parameters, you will + get the same key. + +PasswordHash +-------------- + +.. versionadded:: 2.8.0 + +This API has two classes, one representing the algorithm (such as +"PBKDF2(SHA-256)", or "Scrypt") and the other representing a specific instance +of the problem which is fully specified (say "Scrypt" with N=8192,r=64,p=8). + +.. cpp:class:: PasswordHash + + .. cpp:function:: void derive_key(uint8_t out[], size_t out_len, \ + const char* password, const size_t password_len, \ + const uint8_t salt[], size_t salt_len) const + + Derive a key, placing it into output + + .. cpp:function:: std::string to_string() const + + Return a descriptive string including the parameters (iteration count, etc) + +The ``PasswordHashFamily`` creates specific instances of ``PasswordHash``: + +.. cpp:class:: PasswordHashFamily + + .. cpp:function:: static std::unique_ptr create(const std::string& what) + + For example "PBKDF2(SHA-256)", "Scrypt", "OpenPGP-S2K(SHA-384)". Returns + null if not available. + + .. cpp:function:: std::unique_ptr default_params() const + + Create a default instance of the password hashing algorithm. Be warned the + value returned here may change from release to release. + + .. cpp:function:: std::unique_ptr tune(size_t output_len, std::chrono::milliseconds msec) const + + Return a password hash instance tuned to run for approximately ``msec`` + milliseconds when producing an output of length ``output_len``. (Accuracy + may vary, use the command line utility ``botan pbkdf_tune`` to check.) + + .. cpp:function:: std::unique_ptr from_params( \ + size_t i1, size_t i2 = 0, size_t i3 = 0) const + + Create a password hash using some scheme specific format. + Eg PBKDF2 and PGP-S2K set iterations in i1 + Scrypt uses N,r,p in i{1-3} + Bcrypt-PBKDF just has iterations + Argon2{i,d,id} would use iterations, memory, parallelism for i{1-3}, and Argon2 type is part of the family. + + Values not needed should be set to 0. + +Available Schemes +---------------------- + +PBKDF2 +^^^^^^^^^^^^ + +PBKDF2 is the "standard" password derivation scheme, widely implemented in many +different libraries. It uses HMAC internally. + +Scrypt +^^^^^^^^^^ + +Scrypt is a relatively newer design which is "memory hard" - in +addition to requiring large amounts of CPU power it uses a large block +of memory to compute the hash. This makes brute force attacks using +ASICs substantially more expensive. + +Scrypt is not supported through :cpp:class:`PBKDF`, only :cpp:class:`PasswordHash`, +starting in 2.8.0. In addition, starting in version 2.7.0, scrypt is available +with this function: + +.. cpp:function:: void scrypt(uint8_t output[], size_t output_len, \ + const std::string& password, \ + const uint8_t salt[], size_t salt_len, \ + size_t N, size_t r, size_t p) + + Computes the Scrypt using the password and salt, and produces an output + of arbitrary length. + + The N, r, p parameters control how much work and memory Scrypt + uses. N is the primary control of the workfactor, and must be a + power of 2. For interactive logins use 32768, for protection of + secret keys or backups use 1048576. + + The r parameter controls how 'wide' the internal hashing operation + is. It also increases the amount of memory that is used. Values + from 1 to 8 are reasonable. + + Setting p parameter to greater than one splits up the work in a way + that up to p processors can work in parallel. + + As a general recommendation, use N=32768, r=8, p=1 + +Argon2 +^^^^^^^^^^ + +.. versionadded:: 2.11.0 + +Argon2 is the winner of the PHC (Password Hashing Competition) and +provides a tunable memory hard PBKDF. + +OpenPGP S2K +^^^^^^^^^^^^ + +.. warning:: + + The OpenPGP algorithm is weak and strange, and should be avoided unless + implementing OpenPGP. + +There are some oddities about OpenPGP's S2K algorithms that are documented +here. For one thing, it uses the iteration count in a strange manner; instead of +specifying how many times to iterate the hash, it tells how many *bytes* should +be hashed in total (including the salt). So the exact iteration count will +depend on the size of the salt (which is fixed at 8 bytes by the OpenPGP +standard, though the implementation will allow any salt size) and the size of +the passphrase. + +To get what OpenPGP calls "Simple S2K", set iterations to 0, and do not specify +a salt. To get "Salted S2K", again leave the iteration count at 0, but give an +8-byte salt. "Salted and Iterated S2K" requires an 8-byte salt and some +iteration count (this should be significantly larger than the size of the +longest passphrase that might reasonably be used; somewhere from 1024 to 65536 +would probably be about right). Using both a reasonably sized salt and a large +iteration count is highly recommended to prevent password guessing attempts. + +PBKDF1 +^^^^^^^^^^^^ + +PBKDF1 is an old scheme that can only produce an output length at most +as long as the hash function. It is deprecated and will be removed in +a future release. It is not supported through :cpp:class:`PasswordHash`. diff --git a/comm/third_party/botan/doc/api_ref/pkcs11.rst b/comm/third_party/botan/doc/api_ref/pkcs11.rst new file mode 100644 index 0000000000..9e0ddfa679 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/pkcs11.rst @@ -0,0 +1,1419 @@ +.. _pkcs11: + +PKCS#11 +======================================== + +.. versionadded:: 1.11.31 + +| + +PKCS#11 is a platform-independent interface for accessing smart cards and +hardware security modules (HSM). Vendors of PKCS#11 compatible devices usually +provide a so called middleware or "PKCS#11 module" which implements the PKCS#11 +standard. This middleware translates calls from the platform-independent PKCS#11 +API to device specific calls. So application developers don't have to write smart card +or HSM specific code for each device they want to support. + + .. note:: + + The Botan PKCS#11 interface is implemented against version v2.40 of the standard. + +Botan wraps the C PKCS#11 API to provide a C++ PKCS#11 interface. This is done +in two levels of abstraction: a low level API (see :ref:`pkcs11_low_level`) and +a high level API (see :ref:`pkcs11_high_level`). The low level API provides +access to all functions that are specified by the standard. The high level API +represents an object oriented approach to use PKCS#11 compatible devices but +only provides a subset of the functions described in the standard. + +To use the PKCS#11 implementation the ``pkcs11`` module has to be enabled. + + .. note:: + + Both PKCS#11 APIs live in the namespace ``Botan::PKCS11`` + +.. _pkcs11_low_level: + +Low Level API +---------------------------------------- + +The PKCS#11 standards committee provides header files (``pkcs11.h``, ``pkcs11f.h`` and +``pkcs11t.h``) which define the PKCS#11 API in the C programming language. These +header files could be used directly to access PKCS#11 compatible smart cards or +HSMs. The external header files are shipped with Botan in version v2.4 of the standard. The PKCS#11 low +level API wraps the original PKCS#11 API, but still allows to access all functions described in the +standard and has the advantage that it is a C++ interface with features like RAII, exceptions +and automatic memory management. + +The low level API is implemented by the :cpp:class:`LowLevel` class and can be accessed by +including the header ``botan/p11.h``. + +Preface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All constants that belong together in the PKCS#11 standard are grouped into C++ +enum classes. For example the different user types are grouped in the +:cpp:enum:`UserType` enumeration: + +.. cpp:enum-class:: UserType : CK_USER_TYPE + + .. cpp:enumerator:: UserType::SO = CKU_SO + .. cpp:enumerator:: UserType::User = CKU_USER + .. cpp:enumerator:: UserType::ContextSpecific = CKU_CONTEXT_SPECIFIC + +Additionally, all types that are used by the low or high level API are mapped by +type aliases to more C++ like names. For instance: + +.. cpp:type:: FunctionListPtr = CK_FUNCTION_LIST_PTR + +.. rubric:: C-API Wrapping + +There is at least one method in the :cpp:class:`LowLevel` class that corresponds to a PKCS#11 +function. For example the :cpp:func:`C_GetSlotList` method in the :cpp:class:`LowLevel` class is defined as follows: + +.. cpp:class:: LowLevel + + .. cpp:function:: bool C_GetSlotList(Bbool token_present, SlotId* slot_list_ptr, Ulong* count_ptr, ReturnValue* return_value = ThrowException) const + +The :cpp:class:`LowLevel` class calls the PKCS#11 function from the function list of the PKCS#11 module: + + .. code-block:: c + + CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)( CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pulCount ) + +Where it makes sense there is also an overload of the :cpp:class:`LowLevel` method to make usage easier and safer: + + .. cpp:function:: bool C_GetSlotList( bool token_present, std::vector& slot_ids, ReturnValue* return_value = ThrowException ) const + +With this overload the user of this API just has to pass a vector of :cpp:type:`SlotId` instead of pointers +to preallocated memory for the slot list and the number of elements. Additionally, there is no need +to call the method twice in order to determine the number of elements first. + +Another example is the :cpp:func:`C_InitPIN` overload: + + .. cpp:function:: template bool C_InitPIN( SessionHandle session, const std::vector& pin, ReturnValue* return_value = ThrowException ) const + +The templated ``pin`` parameter allows to pass the PIN as a ``std::vector`` or a ``secure_vector``. +If used with a ``secure_vector`` it is assured that the memory is securely erased when the ``pin`` object is no longer needed. + +Error Handling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All possible PKCS#11 return values are represented by the enum class: + +.. cpp:enum-class:: ReturnValue : CK_RV + +All methods of the :cpp:class:`LowLevel` class have a default parameter ``ReturnValue* return_value = ThrowException``. +This parameter controls the error handling of all :cpp:class:`LowLevel` methods. The default +behavior ``return_value = ThrowException`` is to throw an exception if the method does +not complete successfully. If a non-``NULL`` pointer is passed, ``return_value`` receives the +return value of the PKCS#11 function and no exception is thrown. In case ``nullptr`` is +passed as ``return_value``, the exact return value is ignored and the method just returns +``true`` if the function succeeds and ``false`` otherwise. + +Getting started +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An object of this class can be instantiated by providing a :cpp:type:`FunctionListPtr` to the :cpp:class:`LowLevel` constructor: + + .. cpp:function:: explicit LowLevel(FunctionListPtr ptr) + +The :cpp:class:`LowLevel` class provides a static method to retrieve a :cpp:type:`FunctionListPtr` +from a PKCS#11 module file: + + .. cpp:function:: static bool C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr, ReturnValue* return_value = ThrowException) + +---------- + +Code Example: Object Instantiation + + .. code-block:: cpp + + Botan::Dynamically_Loaded_Library pkcs11_module( "C:\\pkcs11-middleware\\library.dll" ); + Botan::PKCS11::FunctionListPtr func_list = nullptr; + Botan::PKCS11::LowLevel::C_GetFunctionList( pkcs11_module, &func_list ); + Botan::PKCS11::LowLevel p11_low_level( func_list ); + +---------- + +Code Example: PKCS#11 Module Initialization + + .. code-block:: cpp + + Botan::PKCS11::LowLevel p11_low_level(func_list); + + Botan::PKCS11::C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, + static_cast(Botan::PKCS11::Flag::OsLockingOk), nullptr }; + + p11_low_level.C_Initialize(&init_args); + + // work with the token + + p11_low_level.C_Finalize(nullptr); + +More code examples can be found in the test suite in the ``test_pkcs11_low_level.cpp`` file. + +.. _pkcs11_high_level: + +High Level API +---------------------------------------- + +The high level API provides access to the most commonly used PKCS#11 functionality in an +object oriented manner. Functionality of the high level API includes: + +* Loading/unloading of PKCS#11 modules +* Initialization of tokens +* Change of PIN/SO-PIN +* Session management +* Random number generation +* Enumeration of objects on the token (certificates, public keys, private keys) +* Import/export/deletion of certificates +* Generation/import/export/deletion of RSA and EC public and private keys +* Encryption/decryption using RSA with support for OAEP and PKCS1-v1_5 (and raw) +* Signature generation/verification using RSA with support for PSS and PKCS1-v1_5 (and raw) +* Signature generation/verification using ECDSA +* Key derivation using ECDH + +Module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:class:`Module` class represents a PKCS#11 shared library (module) and is defined in +``botan/p11_module.h``. + +It is constructed from a a file path to a PKCS#11 module and optional :cpp:type:`C_InitializeArgs`: + +.. cpp:class:: Module + + .. code-block:: cpp + + Module(const std::string& file_path, C_InitializeArgs init_args = + { nullptr, nullptr, nullptr, nullptr, static_cast(Flag::OsLockingOk), nullptr }) + + It loads the shared library and calls :cpp:func:`C_Initialize` with the provided :cpp:type:`C_InitializeArgs`. + On destruction of the object :cpp:func:`C_Finalize` is called. + +There are two more methods in this class. One is for reloading the shared library +and reinitializing the PKCS#11 module: + + .. code-block:: cpp + + void reload(C_InitializeArgs init_args = + { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr }); + +The other one is for getting general information about the PKCS#11 module: + + .. cpp:function:: Info get_info() const + + This function calls :cpp:func:`C_GetInfo` internally. + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::Module module( "C:\\pkcs11-middleware\\library.dll" ); + + // Sometimes useful if a newly connected token is not detected by the PKCS#11 module + module.reload(); + + Botan::PKCS11::Info info = module.get_info(); + + // print library version + std::cout << std::to_string( info.libraryVersion.major ) << "." + << std::to_string( info.libraryVersion.minor ) << std::endl; + +Slot +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:class:`Slot` class represents a PKCS#11 slot and is defined in +``botan/p11_slot.h``. + +A PKCS#11 slot is usually a smart card reader that potentially contains a token. + +.. cpp:class:: Slot + + .. cpp:function:: Slot(Module& module, SlotId slot_id) + + To instantiate this class a reference to a :cpp:class:`Module` object and a ``slot_id`` have to be passed + to the constructor. + + .. cpp:function:: static std::vector get_available_slots(Module& module, bool token_present) + + Retrieve available slot ids by calling this static method. + + The parameter ``token_present`` controls whether all slots or only slots with a + token attached are returned by this method. This method calls :cpp:func:`C_GetSlotList()`. + + .. cpp:function:: SlotInfo get_slot_info() const + + Returns information about the slot. Calls :cpp:func:`C_GetSlotInfo`. + + .. cpp:function:: TokenInfo get_token_info() const + + Obtains information about a particular token in the system. Calls :cpp:func:`C_GetTokenInfo`. + + .. cpp:function:: std::vector get_mechanism_list() const + + Obtains a list of mechanism types supported by the slot. Calls :cpp:func:`C_GetMechanismList`. + + .. cpp:function:: MechanismInfo get_mechanism_info(MechanismType mechanism_type) const + + Obtains information about a particular mechanism possibly supported by a slot. + Calls :cpp:func:`C_GetMechanismInfo`. + + .. cpp:function:: void initialize(const std::string& label, const secure_string& so_pin) const + + Calls :cpp:func:`C_InitToken` to initialize the token. The ``label`` must not exceed 32 bytes. + The current PIN of the security officer must be passed in ``so_pin`` if the token + is reinitialized or if it's a factory new token, the ``so_pin`` that is passed will initially be set. + +---------- + +Code example: + + .. code-block:: cpp + + // only slots with connected token + std::vector slots = Botan::PKCS11::Slot::get_available_slots( module, true ); + + // use first slot + Botan::PKCS11::Slot slot( module, slots.at( 0 ) ); + + // print firmware version of the slot + Botan::PKCS11::SlotInfo slot_info = slot.get_slot_info(); + std::cout << std::to_string( slot_info.firmwareVersion.major ) << "." + << std::to_string( slot_info.firmwareVersion.minor ) << std::endl; + + // print firmware version of the token + Botan::PKCS11::TokenInfo token_info = slot.get_token_info(); + std::cout << std::to_string( token_info.firmwareVersion.major ) << "." + << std::to_string( token_info.firmwareVersion.minor ) << std::endl; + + // retrieve all mechanisms supported by the token + std::vector mechanisms = slot.get_mechanism_list(); + + // retrieve information about a particular mechanism + Botan::PKCS11::MechanismInfo mech_info = + slot.get_mechanism_info( Botan::PKCS11::MechanismType::RsaPkcsOaep ); + + // maximum RSA key length supported: + std::cout << mech_info.ulMaxKeySize << std::endl; + + // initialize the token + Botan::PKCS11::secure_string so_pin( 8, '0' ); + slot.initialize( "Botan PKCS11 documentation test label", so_pin ); + +Session +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:class:`Session` class represents a PKCS#11 session and is defined in ``botan/p11_session.h``. + +A session is a logical connection between an application and a token. + +.. cpp:class:: Session + + There are two constructors to create a new session and one constructor to + take ownership of an existing session. The destructor calls + :cpp:func:`C_Logout` if a user is logged in to this session and always + :cpp:func:`C_CloseSession`. + + .. cpp:function:: Session(Slot& slot, bool read_only) + + To initialize a session object a :cpp:class:`Slot` has to be specified on which the session + should operate. ``read_only`` specifies whether the session should be read only or read write. + Calls :cpp:func:`C_OpenSession`. + + .. cpp:function:: Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback) + + Creates a new session by passing a :cpp:class:`Slot`, session ``flags``, ``callback_data`` and a + ``notify_callback``. Calls :cpp:func:`C_OpenSession`. + + .. cpp:function:: Session(Slot& slot, SessionHandle handle) + + Takes ownership of an existing session by passing :cpp:class:`Slot` and a session ``handle``. + + .. cpp:function:: SessionHandle release() + + Returns the released :cpp:type:`SessionHandle` + + .. cpp:function:: void login(UserType userType, const secure_string& pin) + + Login to this session by passing :cpp:enum:`UserType` and ``pin``. Calls :cpp:func:`C_Login`. + + .. cpp:function:: void logoff() + + Logout from this session. Not mandatory because on destruction of the :cpp:class:`Session` object + this is done automatically. + + .. cpp:function:: SessionInfo get_info() const + + Returns information about this session. Calls :cpp:func:`C_GetSessionInfo`. + + .. cpp:function:: void set_pin(const secure_string& old_pin, const secure_string& new_pin) const + + Calls :cpp:func:`C_SetPIN` to change the PIN of the logged in user using the ``old_pin``. + + .. cpp:function:: void init_pin(const secure_string& new_pin) + + Calls :cpp:func:`C_InitPIN` to change or initialize the PIN using the SO_PIN (requires a logged in session). + +---------- + +Code example: + + .. code-block:: cpp + + // open read only session + { + Botan::PKCS11::Session read_only_session( slot, true ); + } + + // open read write session + { + Botan::PKCS11::Session read_write_session( slot, false ); + } + + // open read write session by passing flags + { + Botan::PKCS11::Flags flags = + Botan::PKCS11::flags( Botan::PKCS11::Flag::SerialSession | Botan::PKCS11::Flag::RwSession ); + + Botan::PKCS11::Session read_write_session( slot, flags, nullptr, nullptr ); + } + + // move ownership of a session + { + Botan::PKCS11::Session session( slot, false ); + Botan::PKCS11::SessionHandle handle = session.release(); + + Botan::PKCS11::Session session2( slot, handle ); + } + + Botan::PKCS11::Session session( slot, false ); + + // get session info + Botan::PKCS11::SessionInfo info = session.get_info(); + std::cout << info.slotID << std::endl; + + // login + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + // set pin + Botan::PKCS11::secure_string new_pin = { '6', '5', '4', '3', '2', '1' }; + session.set_pin( pin, new_pin ); + + // logoff + session.logoff(); + + // log in as security officer + Botan::PKCS11::secure_string so_pin = { '0', '0', '0', '0', '0', '0', '0', '0' }; + session.login( Botan::PKCS11::UserType::SO, so_pin ); + + // change pin to old pin + session.init_pin( pin ); + +Objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 objects consist of various attributes (:c:type:`CK_ATTRIBUTE`). For example :c:macro:`CKA_TOKEN` +describes if a PKCS#11 object is a session object or a token object. The helper class :cpp:class:`AttributeContainer` +helps with storing these attributes. The class is defined in ``botan/p11_object.h``. + +.. cpp:class:: AttributeContainer + +Attributes can be set in an :cpp:class:`AttributeContainer` by various ``add_`` methods: + + .. cpp:function:: void add_class(ObjectClass object_class) + + Add a class attribute (:c:macro:`CKA_CLASS` / :cpp:enumerator:`AttributeType::Class`) + + .. cpp:function:: void add_string(AttributeType attribute, const std::string& value) + + Add a string attribute (e.g. :c:macro:`CKA_LABEL` / :cpp:enumerator:`AttributeType::Label`). + + .. cpp:function:: void AttributeContainer::add_binary(AttributeType attribute, const uint8_t* value, size_t length) + + Add a binary attribute (e.g. :c:macro:`CKA_ID` / :cpp:enumerator:`AttributeType::Id`). + + .. cpp:function:: template void AttributeContainer::add_binary(AttributeType attribute, const std::vector& binary) + + Add a binary attribute by passing a ``vector``/``secure_vector`` (e.g. :c:macro:`CKA_ID` / :cpp:enumerator:`AttributeType::Id`). + + .. cpp:function:: void AttributeContainer::add_bool(AttributeType attribute, bool value) + + Add a bool attribute (e.g. :c:macro:`CKA_SENSITIVE` / :cpp:enumerator:`AttributeType::Sensitive`). + + .. cpp:function:: template void AttributeContainer::add_numeric(AttributeType attribute, T value) + + Add a numeric attribute (e.g. :c:macro:`CKA_MODULUS_BITS` / :cpp:enumerator:`AttributeType::ModulusBits`). + +.. rubric:: Object Properties + +The PKCS#11 standard defines the mandatory and optional attributes for each object class. +The mandatory and optional attribute requirements are mapped in so called property classes. +Mandatory attributes are set in the constructor, optional attributes can be set via ``set_`` methods. + +In the top hierarchy is the :cpp:class:`ObjectProperties` class which inherits from the :cpp:class:`AttributeContainer`. +This class represents the common attributes of all PKCS#11 objects. + +.. cpp:class:: ObjectProperties : public AttributeContainer + +The constructor is defined as follows: + + .. cpp:function:: ObjectProperties(ObjectClass object_class) + + Every PKCS#11 object needs an object class attribute. + +The next level defines the :cpp:class:`StorageObjectProperties` class which inherits from +:cpp:class:`ObjectProperties`. + +.. cpp:class:: StorageObjectProperties : public ObjectProperties + +The only mandatory attribute is the object class, so the constructor is +defined as follows: + + .. cpp:function:: StorageObjectProperties(ObjectClass object_class) + +But in contrast to the :cpp:class:`ObjectProperties` class there are various setter methods. For example to +set the :cpp:enumerator:`AttributeType::Label`: + + .. cpp:function:: void set_label(const std::string& label) + + Sets the label description of the object (RFC2279 string). + +The remaining hierarchy is defined as follows: + +* :cpp:class:`DataObjectProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`CertificateProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`DomainParameterProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`KeyProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`PublicKeyProperties` inherits from :cpp:class:`KeyProperties` +* :cpp:class:`PrivateKeyProperties` inherits from :cpp:class:`KeyProperties` +* :cpp:class:`SecretKeyProperties` inherits from :cpp:class:`KeyProperties` + +PKCS#11 objects themselves are represented by the :cpp:class:`Object` class. + +.. cpp:class:: Object + +Following constructors are defined: + + .. cpp:function:: Object(Session& session, ObjectHandle handle) + + Takes ownership over an existing object. + + .. cpp:function:: Object(Session& session, const ObjectProperties& obj_props) + + Creates a new object with the :cpp:class:`ObjectProperties` provided in ``obj_props``. + +The other methods are: + + .. cpp:function:: secure_vector get_attribute_value(AttributeType attribute) const + + Returns the value of the given attribute (using :cpp:func:`C_GetAttributeValue`) + + .. cpp:function:: void set_attribute_value(AttributeType attribute, const secure_vector& value) const + + Sets the given value for the attribute (using :cpp:func:`C_SetAttributeValue`) + + .. cpp:function:: void destroy() const + + Destroys the object. + + .. cpp:function:: ObjectHandle copy(const AttributeContainer& modified_attributes) const + + Allows to copy the object with modified attributes. + +And static methods to search for objects: + + .. cpp:function:: template static std::vector search(Session& session, const std::vector& search_template) + + Searches for all objects of the given type that match ``search_template``. + + .. cpp:function:: template static std::vector search(Session& session, const std::string& label) + + Searches for all objects of the given type using the label (:c:macro:`CKA_LABEL`). + + .. cpp:function:: template static std::vector search(Session& session, const std::vector& id) + + Searches for all objects of the given type using the id (:c:macro:`CKA_ID`). + + .. cpp:function:: template static std::vector search(Session& session, const std::string& label, const std::vector& id) + + Searches for all objects of the given type using the label (:c:macro:`CKA_LABEL`) and id (:c:macro:`CKA_ID`). + + .. cpp:function:: template static std::vector search(Session& session) + + Searches for all objects of the given type. + +.. rubric:: The ObjectFinder + +Another way for searching objects is to use the :cpp:class:`ObjectFinder` class. This class +manages calls to the ``C_FindObjects*`` functions: :cpp:func:`C_FindObjectsInit`, :cpp:func:`C_FindObjects` +and :cpp:func:`C_FindObjectsFinal`. + +.. cpp:class:: ObjectFinder + +The constructor has the following signature: + + .. cpp:function:: ObjectFinder(Session& session, const std::vector& search_template) + + A search can be prepared with an :cpp:class:`ObjectSearcher` by passing a :cpp:class:`Session` and a ``search_template``. + +The actual search operation is started by calling the :cpp:func:`find` method: + + .. cpp:function:: std::vector find(std::uint32_t max_count = 100) const + + Starts or continues a search for token and session objects that match a template. ``max_count`` + specifies the maximum number of search results (object handles) that are returned. + + .. cpp:function:: void finish() + + Finishes the search operation manually to allow a new :cpp:class:`ObjectFinder` to exist. + Otherwise the search is finished by the destructor. + +---------- + +Code example: + + .. code-block:: cpp + + // create an simple data object + Botan::secure_vector value = { 0x00, 0x01 ,0x02, 0x03 }; + std::size_t id = 1337; + std::string label = "test data object"; + + // set properties of the new object + Botan::PKCS11::DataObjectProperties data_obj_props; + data_obj_props.set_label( label ); + data_obj_props.set_value( value ); + data_obj_props.set_token( true ); + data_obj_props.set_modifiable( true ); + data_obj_props.set_object_id( Botan::DER_Encoder().encode( id ).get_contents_unlocked() ); + + // create the object + Botan::PKCS11::Object data_obj( session, data_obj_props ); + + // get label of this object + Botan::PKCS11::secure_string retrieved_label = + data_obj.get_attribute_value( Botan::PKCS11::AttributeType::Label ); + + // set a new label + Botan::PKCS11::secure_string new_label = { 'B', 'o', 't', 'a', 'n' }; + data_obj.set_attribute_value( Botan::PKCS11::AttributeType::Label, new_label ); + + // copy the object + Botan::PKCS11::AttributeContainer copy_attributes; + copy_attributes.add_string( Botan::PKCS11::AttributeType::Label, "copied object" ); + Botan::PKCS11::ObjectHandle copied_obj_handle = data_obj.copy( copy_attributes ); + + // search for an object + Botan::PKCS11::AttributeContainer search_template; + search_template.add_string( Botan::PKCS11::AttributeType::Label, "Botan" ); + auto found_objs = + Botan::PKCS11::Object::search( session, search_template.attributes() ); + + // destroy the object + data_obj.destroy(); + +RSA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 RSA support is implemented in ````. + +.. rubric:: RSA Public Keys + +PKCS#11 RSA public keys are provided by the class :cpp:class:`PKCS11_RSA_PublicKey`. This class +inherits from :cpp:class:`RSA_PublicKey` and :cpp:class:`Object`. Furthermore there are two property classes defined +to generate and import RSA public keys analogous to the other property classes described +before: :cpp:class:`RSA_PublicKeyGenerationProperties` and :cpp:class:`RSA_PublicKeyImportProperties`. + +.. cpp:class:: PKCS11_RSA_PublicKey : public RSA_PublicKey, public Object + + .. cpp:function:: PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 RSA public keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props) + + This constructor can be used to import an existing RSA public key with the :cpp:class:`RSA_PublicKeyImportProperties` + passed in ``pubkey_props`` to the token. + +.. rubric:: RSA Private Keys + +The support for PKCS#11 RSA private keys is implemented in a similar way. There are two property +classes: :cpp:class:`RSA_PrivateKeyGenerationProperties` and :cpp:class:`RSA_PrivateKeyImportProperties`. The :cpp:class:`PKCS11_RSA_PrivateKey` +class implements the actual support for PKCS#11 RSA private keys. This class inherits from :cpp:class:`Private_Key`, +:cpp:class:`RSA_PublicKey` and :cpp:class:`Object`. In contrast to the public key class there is a third constructor +to generate private keys directly on the token or in the session and one method to export private keys. + +.. cpp:class:: PKCS11_RSA_PrivateKey : public Private_Key, public RSA_PublicKey, public Object + + .. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 RSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props) + + This constructor can be used to import an existing RSA private key with the :cpp:class:`RSA_PrivateKeyImportProperties` + passed in ``priv_key_props`` to the token. + + .. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props) + + Generates a new PKCS#11 RSA private key with bit length provided in ``bits`` and the :cpp:class:`RSA_PrivateKeyGenerationProperties` + passed in ``priv_key_props``. + + .. cpp:function:: RSA_PrivateKey export_key() const + + Returns the exported :cpp:class:`RSA_PrivateKey`. + +PKCS#11 RSA key pairs can be generated with the following free function: + + .. cpp:function:: PKCS11_RSA_KeyPair PKCS11::generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props, const RSA_PrivateKeyGenerationProperties& priv_props) + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + /************ import RSA private key *************/ + + // create private key in software + Botan::AutoSeeded_RNG rng; + Botan::RSA_PrivateKey priv_key_sw( rng, 2048 ); + + // set the private key import properties + Botan::PKCS11::RSA_PrivateKeyImportProperties + priv_import_props( priv_key_sw.get_n(), priv_key_sw.get_d() ); + + priv_import_props.set_pub_exponent( priv_key_sw.get_e() ); + priv_import_props.set_prime_1( priv_key_sw.get_p() ); + priv_import_props.set_prime_2( priv_key_sw.get_q() ); + priv_import_props.set_coefficient( priv_key_sw.get_c() ); + priv_import_props.set_exponent_1( priv_key_sw.get_d1() ); + priv_import_props.set_exponent_2( priv_key_sw.get_d2() ); + + priv_import_props.set_token( true ); + priv_import_props.set_private( true ); + priv_import_props.set_decrypt( true ); + priv_import_props.set_sign( true ); + + // import + Botan::PKCS11::PKCS11_RSA_PrivateKey priv_key( session, priv_import_props ); + + /************ export PKCS#11 RSA private key *************/ + Botan::RSA_PrivateKey exported = priv_key.export_key(); + + /************ import RSA public key *************/ + + // set the public key import properties + Botan::PKCS11::RSA_PublicKeyImportProperties pub_import_props( priv_key.get_n(), priv_key.get_e() ); + pub_import_props.set_token( true ); + pub_import_props.set_encrypt( true ); + pub_import_props.set_private( false ); + + // import + Botan::PKCS11::PKCS11_RSA_PublicKey public_key( session, pub_import_props ); + + /************ generate RSA private key *************/ + + Botan::PKCS11::RSA_PrivateKeyGenerationProperties priv_generate_props; + priv_generate_props.set_token( true ); + priv_generate_props.set_private( true ); + priv_generate_props.set_sign( true ); + priv_generate_props.set_decrypt( true ); + priv_generate_props.set_label( "BOTAN_TEST_RSA_PRIV_KEY" ); + + Botan::PKCS11::PKCS11_RSA_PrivateKey private_key2( session, 2048, priv_generate_props ); + + /************ generate RSA key pair *************/ + + Botan::PKCS11::RSA_PublicKeyGenerationProperties pub_generate_props( 2048UL ); + pub_generate_props.set_pub_exponent(); + pub_generate_props.set_label( "BOTAN_TEST_RSA_PUB_KEY" ); + pub_generate_props.set_token( true ); + pub_generate_props.set_encrypt( true ); + pub_generate_props.set_verify( true ); + pub_generate_props.set_private( false ); + + Botan::PKCS11::PKCS11_RSA_KeyPair rsa_keypair = + Botan::PKCS11::generate_rsa_keypair( session, pub_generate_props, priv_generate_props ); + + /************ RSA encrypt *************/ + + Botan::secure_vector plaintext = { 0x00, 0x01, 0x02, 0x03 }; + Botan::PK_Encryptor_EME encryptor( rsa_keypair.first, rng, "Raw" ); + auto ciphertext = encryptor.encrypt( plaintext, rng ); + + /************ RSA decrypt *************/ + + Botan::PK_Decryptor_EME decryptor( rsa_keypair.second, rng, "Raw" ); + plaintext = decryptor.decrypt( ciphertext ); + + /************ RSA sign *************/ + + Botan::PK_Signer signer( rsa_keypair.second, rng, "EMSA4(SHA-256)", Botan::IEEE_1363 ); + auto signature = signer.sign_message( plaintext, rng ); + + /************ RSA verify *************/ + + Botan::PK_Verifier verifier( rsa_keypair.first, "EMSA4(SHA-256)", Botan::IEEE_1363 ); + auto ok = verifier.verify_message( plaintext, signature ); + +ECDSA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 ECDSA support is implemented in ````. + +.. rubric:: ECDSA Public Keys + +PKCS#11 ECDSA public keys are provided by the class :cpp:class:`PKCS11_ECDSA_PublicKey`. This class +inherits from :cpp:class:`PKCS11_EC_PublicKey` and :cpp:class:`ECDSA_PublicKey`. The necessary property classes +are defined in ````. For public keys there are :cpp:class:`EC_PublicKeyGenerationProperties` +and :cpp:class:`EC_PublicKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDSA_PublicKey : public PKCS11_EC_PublicKey, public virtual ECDSA_PublicKey + + .. cpp:function:: PKCS11_ECDSA_PublicKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDSA_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + + This constructor can be used to import an existing ECDSA public key with the :cpp:class:`EC_PublicKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const + + Returns the exported :cpp:class:`ECDSA_PublicKey`. + +.. rubric:: ECDSA Private Keys + +The class :cpp:class:`PKCS11_ECDSA_PrivateKey` inherits from :cpp:class:`PKCS11_EC_PrivateKey` and implements support +for PKCS#11 ECDSA private keys. There are two property classes for key generation +and import: :cpp:class:`EC_PrivateKeyGenerationProperties` and :cpp:class:`EC_PrivateKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDSA_PrivateKey : public PKCS11_EC_PrivateKey + + .. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + + This constructor can be used to import an existing ECDSA private key with the :cpp:class:`EC_PrivateKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, const std::vector& ec_params, const EC_PrivateKeyGenerationProperties& props) + + This constructor can be used to generate a new ECDSA private key with the :cpp:class:`EC_PrivateKeyGenerationProperties` + passed in ``props`` on the token. The ``ec_params`` parameter is the DER-encoding of an + ANSI X9.62 Parameters value. + + .. cpp:function:: ECDSA_PrivateKey export_key() const + + Returns the exported :cpp:class:`ECDSA_PrivateKey`. + +PKCS#11 ECDSA key pairs can be generated with the following free function: + + .. cpp:function:: PKCS11_ECDSA_KeyPair PKCS11::generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props) + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + /************ import ECDSA private key *************/ + + // create private key in software + Botan::AutoSeeded_RNG rng; + + Botan::ECDSA_PrivateKey priv_key_sw( rng, Botan::EC_Group( "secp256r1" ) ); + priv_key_sw.set_parameter_encoding( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ); + + // set the private key import properties + Botan::PKCS11::EC_PrivateKeyImportProperties priv_import_props( + priv_key_sw.DER_domain(), priv_key_sw.private_value() ); + + priv_import_props.set_token( true ); + priv_import_props.set_private( true ); + priv_import_props.set_sign( true ); + priv_import_props.set_extractable( true ); + + // label + std::string label = "test ECDSA key"; + priv_import_props.set_label( label ); + + // import to card + Botan::PKCS11::PKCS11_ECDSA_PrivateKey priv_key( session, priv_import_props ); + + /************ export PKCS#11 ECDSA private key *************/ + Botan::ECDSA_PrivateKey priv_exported = priv_key.export_key(); + + /************ import ECDSA public key *************/ + + // import to card + Botan::PKCS11::EC_PublicKeyImportProperties pub_import_props( priv_key_sw.DER_domain(), + Botan::DER_Encoder().encode( EC2OSP( priv_key_sw.public_point(), Botan::PointGFp::UNCOMPRESSED ), + Botan::OCTET_STRING ).get_contents_unlocked() ); + + pub_import_props.set_token( true ); + pub_import_props.set_verify( true ); + pub_import_props.set_private( false ); + + // label + label = "test ECDSA pub key"; + pub_import_props.set_label( label ); + + Botan::PKCS11::PKCS11_ECDSA_PublicKey public_key( session, pub_import_props ); + + /************ export PKCS#11 ECDSA public key *************/ + Botan::ECDSA_PublicKey pub_exported = public_key.export_key(); + + /************ generate PKCS#11 ECDSA private key *************/ + Botan::PKCS11::EC_PrivateKeyGenerationProperties priv_generate_props; + priv_generate_props.set_token( true ); + priv_generate_props.set_private( true ); + priv_generate_props.set_sign( true ); + + Botan::PKCS11::PKCS11_ECDSA_PrivateKey pk( session, + Botan::EC_Group( "secp256r1" ).DER_encode( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ), + priv_generate_props ); + + /************ generate PKCS#11 ECDSA key pair *************/ + + Botan::PKCS11::EC_PublicKeyGenerationProperties pub_generate_props( + Botan::EC_Group( "secp256r1" ).DER_encode(Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ) ); + + pub_generate_props.set_label( "BOTAN_TEST_ECDSA_PUB_KEY" ); + pub_generate_props.set_token( true ); + pub_generate_props.set_verify( true ); + pub_generate_props.set_private( false ); + pub_generate_props.set_modifiable( true ); + + Botan::PKCS11::PKCS11_ECDSA_KeyPair key_pair = Botan::PKCS11::generate_ecdsa_keypair( session, + pub_generate_props, priv_generate_props ); + + /************ PKCS#11 ECDSA sign and verify *************/ + + std::vector plaintext( 20, 0x01 ); + + Botan::PK_Signer signer( key_pair.second, rng, "Raw", Botan::IEEE_1363, "pkcs11" ); + auto signature = signer.sign_message( plaintext, rng ); + + Botan::PK_Verifier token_verifier( key_pair.first, "Raw", Botan::IEEE_1363, "pkcs11" ); + bool ecdsa_ok = token_verifier.verify_message( plaintext, signature ); + +ECDH +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 ECDH support is implemented in ````. + +.. rubric:: ECDH Public Keys + +PKCS#11 ECDH public keys are provided by the class :cpp:class:`PKCS11_ECDH_PublicKey`. This class +inherits from :cpp:class:`PKCS11_EC_PublicKey`. The necessary property classes +are defined in ````. For public keys there are :cpp:class:`EC_PublicKeyGenerationProperties` +and :cpp:class:`EC_PublicKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDH_PublicKey : public PKCS11_EC_PublicKey + + .. cpp:function:: PKCS11_ECDH_PublicKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDH private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDH_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + + This constructor can be used to import an existing ECDH public key with the :cpp:class:`EC_PublicKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: ECDH_PublicKey export_key() const + + Returns the exported :cpp:class:`ECDH_PublicKey`. + +.. rubric:: ECDH Private Keys + +The class :cpp:class:`PKCS11_ECDH_PrivateKey` inherits from :cpp:class:`PKCS11_EC_PrivateKey` and :cpp:class:`PK_Key_Agreement_Key` +and implements support for PKCS#11 ECDH private keys. There are two +property classes. One for key generation and one for import: :cpp:class:`EC_PrivateKeyGenerationProperties` and +:cpp:class:`EC_PrivateKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDH_PrivateKey : public virtual PKCS11_EC_PrivateKey, public virtual PK_Key_Agreement_Key + + .. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDH private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + + This constructor can be used to import an existing ECDH private key with the :cpp:class:`EC_PrivateKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, const std::vector& ec_params, const EC_PrivateKeyGenerationProperties& props) + + This constructor can be used to generate a new ECDH private key with the :cpp:class:`EC_PrivateKeyGenerationProperties` + passed in ``props`` on the token. The ``ec_params`` parameter is the DER-encoding of an + ANSI X9.62 Parameters value. + + .. cpp:function:: ECDH_PrivateKey export_key() const + + Returns the exported :cpp:class:`ECDH_PrivateKey`. + +PKCS#11 ECDH key pairs can be generated with the following free function: + +.. cpp:function:: PKCS11_ECDH_KeyPair PKCS11::generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props) + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + /************ import ECDH private key *************/ + + Botan::AutoSeeded_RNG rng; + + // create private key in software + Botan::ECDH_PrivateKey priv_key_sw( rng, Botan::EC_Group( "secp256r1" ) ); + priv_key_sw.set_parameter_encoding( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ); + + // set import properties + Botan::PKCS11::EC_PrivateKeyImportProperties priv_import_props( + priv_key_sw.DER_domain(), priv_key_sw.private_value() ); + + priv_import_props.set_token( true ); + priv_import_props.set_private( true ); + priv_import_props.set_derive( true ); + priv_import_props.set_extractable( true ); + + // label + std::string label = "test ECDH key"; + priv_import_props.set_label( label ); + + // import to card + Botan::PKCS11::PKCS11_ECDH_PrivateKey priv_key( session, priv_import_props ); + + /************ export ECDH private key *************/ + Botan::ECDH_PrivateKey exported = priv_key.export_key(); + + /************ import ECDH public key *************/ + + // set import properties + Botan::PKCS11::EC_PublicKeyImportProperties pub_import_props( priv_key_sw.DER_domain(), + Botan::DER_Encoder().encode( EC2OSP( priv_key_sw.public_point(), Botan::PointGFp::UNCOMPRESSED ), + Botan::OCTET_STRING ).get_contents_unlocked() ); + + pub_import_props.set_token( true ); + pub_import_props.set_private( false ); + pub_import_props.set_derive( true ); + + // label + label = "test ECDH pub key"; + pub_import_props.set_label( label ); + + // import + Botan::PKCS11::PKCS11_ECDH_PublicKey pub_key( session, pub_import_props ); + + /************ export ECDH private key *************/ + Botan::ECDH_PublicKey exported_pub = pub_key.export_key(); + + /************ generate ECDH private key *************/ + + Botan::PKCS11::EC_PrivateKeyGenerationProperties priv_generate_props; + priv_generate_props.set_token( true ); + priv_generate_props.set_private( true ); + priv_generate_props.set_derive( true ); + + Botan::PKCS11::PKCS11_ECDH_PrivateKey priv_key2( session, + Botan::EC_Group( "secp256r1" ).DER_encode( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ), + priv_generate_props ); + + /************ generate ECDH key pair *************/ + + Botan::PKCS11::EC_PublicKeyGenerationProperties pub_generate_props( + Botan::EC_Group( "secp256r1" ).DER_encode( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ) ); + + pub_generate_props.set_label( label + "_PUB_KEY" ); + pub_generate_props.set_token( true ); + pub_generate_props.set_derive( true ); + pub_generate_props.set_private( false ); + pub_generate_props.set_modifiable( true ); + + Botan::PKCS11::PKCS11_ECDH_KeyPair key_pair = Botan::PKCS11::generate_ecdh_keypair( + session, pub_generate_props, priv_generate_props ); + + /************ ECDH derive *************/ + + Botan::PKCS11::PKCS11_ECDH_KeyPair key_pair_other = Botan::PKCS11::generate_ecdh_keypair( + session, pub_generate_props, priv_generate_props ); + + Botan::PK_Key_Agreement ka( key_pair.second, rng, "Raw", "pkcs11" ); + Botan::PK_Key_Agreement kb( key_pair_other.second, rng, "Raw", "pkcs11" ); + + Botan::SymmetricKey alice_key = ka.derive_key( 32, + Botan::unlock( Botan::EC2OSP( key_pair_other.first.public_point(), + Botan::PointGFp::UNCOMPRESSED ) ) ); + + Botan::SymmetricKey bob_key = kb.derive_key( 32, + Botan::unlock( Botan::EC2OSP( key_pair.first.public_point(), + Botan::PointGFp::UNCOMPRESSED ) ) ); + + bool eq = alice_key == bob_key; + +RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The PKCS#11 RNG is defined in ````. The class :cpp:class:`PKCS11_RNG` +implements the :cpp:class:`Hardware_RNG` interface. + +.. cpp:class:: PKCS11_RNG : public Hardware_RNG + + .. cpp:function:: PKCS11_RNG(Session& session) + + A PKCS#11 :cpp:class:`Session` must be passed to instantiate a ``PKCS11_RNG``. + + .. cpp:function:: void randomize(uint8_t output[], std::size_t length) override + + Calls :cpp:func:`C_GenerateRandom` to generate random data. + + .. cpp:function:: void add_entropy(const uint8_t in[], std::size_t length) override + + Calls :cpp:func:`C_SeedRandom` to add entropy to the random generation function of the token/middleware. + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::PKCS11_RNG p11_rng( session ); + + /************ generate random data *************/ + std::vector random( 20 ); + p11_rng.randomize( random.data(), random.size() ); + + /************ add entropy *************/ + Botan::AutoSeeded_RNG auto_rng; + auto auto_rng_random = auto_rng.random_vec( 20 ); + p11_rng.add_entropy( auto_rng_random.data(), auto_rng_random.size() ); + + /************ use PKCS#11 RNG to seed HMAC_DRBG *************/ + Botan::HMAC_DRBG drbg( Botan::MessageAuthenticationCode::create( "HMAC(SHA-512)" ), p11_rng ); + drbg.randomize( random.data(), random.size() ); + +Token Management Functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The header file ```` also defines some free functions for token management: + + .. cpp:function:: void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin) + + Initializes a token by passing a :cpp:class:`Slot`, a ``label`` and the ``so_pin`` of the security officer. + + .. cpp:function:: void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin) + + Change PIN with ``old_pin`` to ``new_pin``. + + .. cpp:function:: void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin) + + Change SO_PIN with ``old_so_pin`` to new ``new_so_pin``. + + .. cpp:function:: void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin) + + Sets user ``pin`` with ``so_pin``. + +---------- + +Code example: + + .. code-block:: cpp + + /************ set pin *************/ + + Botan::PKCS11::Module module( Middleware_path ); + + // only slots with connected token + std::vector slots = Botan::PKCS11::Slot::get_available_slots( module, true ); + + // use first slot + Botan::PKCS11::Slot slot( module, slots.at( 0 ) ); + + Botan::PKCS11::secure_string so_pin = { '1', '2', '3', '4', '5', '6', '7', '8' }; + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + Botan::PKCS11::secure_string test_pin = { '6', '5', '4', '3', '2', '1' }; + + // set pin + Botan::PKCS11::set_pin( slot, so_pin, test_pin ); + + // change back + Botan::PKCS11::set_pin( slot, so_pin, pin ); + + /************ initialize *************/ + Botan::PKCS11::initialize_token( slot, "Botan handbook example", so_pin, pin ); + + /************ change pin *************/ + Botan::PKCS11::change_pin( slot, pin, test_pin ); + + // change back + Botan::PKCS11::change_pin( slot, test_pin, pin ); + + /************ change security officer pin *************/ + Botan::PKCS11::change_so_pin( slot, so_pin, test_pin ); + + // change back + Botan::PKCS11::change_so_pin( slot, test_pin, so_pin ); + +X.509 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The header file ```` defines the property class :cpp:class:`X509_CertificateProperties` +and the class :cpp:class:`PKCS11_X509_Certificate`. + +.. cpp:class:: PKCS11_X509_Certificate : public Object, public X509_Certificate + + .. cpp:function:: PKCS11_X509_Certificate(Session& session, ObjectHandle handle) + + Allows to use existing certificates on the token by passing a valid :cpp:type:`ObjectHandle`. + + .. cpp:function:: PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props) + + Allows to import an existing X.509 certificate to the token with the :cpp:class:`X509_CertificateProperties` + passed in ``props``. + +---------- + +Code example: + + .. code-block:: cpp + + // load existing certificate + Botan::X509_Certificate root( "test.crt" ); + + // set props + Botan::PKCS11::X509_CertificateProperties props( + Botan::DER_Encoder().encode( root.subject_dn() ).get_contents_unlocked(), root.BER_encode() ); + + props.set_label( "Botan PKCS#11 test certificate" ); + props.set_private( false ); + props.set_token( true ); + + // import + Botan::PKCS11::PKCS11_X509_Certificate pkcs11_cert( session, props ); + + // load by handle + Botan::PKCS11::PKCS11_X509_Certificate pkcs11_cert2( session, pkcs11_cert.handle() ); + +Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The PKCS#11 tests are not executed automatically because the depend on an external +PKCS#11 module/middleware. The test tool has to be executed with ``--pkcs11-lib=`` +followed with the path of the PKCS#11 module and a second argument which controls the +PKCS#11 tests that are executed. Passing ``pkcs11`` will execute all PKCS#11 tests but it's +also possible to execute only a subset with the following arguments: + +- pkcs11-ecdh +- pkcs11-ecdsa +- pkcs11-lowlevel +- pkcs11-manage +- pkcs11-module +- pkcs11-object +- pkcs11-rng +- pkcs11-rsa +- pkcs11-session +- pkcs11-slot +- pkcs11-x509 + +The following PIN and SO-PIN/PUK values are used in tests: + +- PIN 123456 +- SO-PIN/PUK 12345678 + + .. warning:: + + Unlike the CardOS (4.4, 5.0, 5.3), the aforementioned SO-PIN/PUK is + inappropriate for Gemalto (IDPrime MD 3840) cards, as it must be a byte array + of length 24. For this reason some of the tests for Gemalto card involving + SO-PIN will fail. You run into a risk of exceding login attempts and as a + result locking your card! Currently, specifying pin via command-line option + is not implemented, and therefore the desired PIN must be modified in the + header src/tests/test_pkcs11.h: + + .. code-block:: cpp + + // SO PIN is expected to be set to "12345678" prior to running the tests + const std::string SO_PIN = "12345678"; + const auto SO_PIN_SECVEC = Botan::PKCS11::secure_string(SO_PIN.begin(), SO_PIN.end()); + + +Tested/Supported Smartcards +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You are very welcome to contribute your own test results for other testing environments or other cards. + + +Test results + ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| Smartcard | Status | OS | Midleware | Botan | Errors | ++=====================================+===========================================+===================================================+===================================================+===================================================+===================================================+ +| CardOS 4.4 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [50]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| CardOS 5.0 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [51]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| CardOS 5.3 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [52]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| CardOS 5.3 | mostly works | Windows 10, 64-bit, version 1903 | API Version 5.5.1 (Cryptoki v2.11) | 2.12.0 unreleased, Cryptoki v2.40 | [53]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| Gemalto IDPrime MD 3840 | mostly works | Windows 10, 64-bit, version 1709 | IDGo 800, v1.2.4 (Cryptoki v2.20) | 2.4.0, Cryptoki v2.40 | [54]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| SoftHSM 2.3.0 (OpenSSL 1.0.2g) | works | Windows 10, 64-bit, version 1709 | Cryptoki v2.40 | 2.4.0, Cryptoki v2.40 | | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| SoftHSM 2.5.0 (OpenSSL 1.1.1) | works | Windows 10, 64-bit, version 1803 | Cryptoki v2.40 | 2.11.0, Cryptoki v2.40 | | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ + +.. [50] Failing operations for CardOS 4.4: + + - object_copy [20]_ + + - rsa_privkey_export [21]_ + - rsa_generate_private_key [22]_ + - rsa_sign_verify [23]_ + + - ecdh_privkey_import [3]_ + - ecdh_privkey_export [2]_ + - ecdh_pubkey_import [4]_ + - ecdh_pubkey_export [4]_ + - ecdh_generate_private_key [3]_ + - ecdh_generate_keypair [3]_ + - ecdh_derive [3]_ + + - ecdsa_privkey_import [3]_ + - ecdsa_privkey_export [2]_ + - ecdsa_pubkey_import [4]_ + - ecdsa_pubkey_export [4]_ + - ecdsa_generate_private_key [3]_ + - ecdsa_generate_keypair [3]_ + - ecdsa_sign_verify [3]_ + + - rng_add_entropy [5]_ + + +.. [51] Failing operations for CardOS 5.0 + + - object_copy [20]_ + + - rsa_privkey_export [21]_ + - rsa_generate_private_key [22]_ + - rsa_sign_verify [23]_ + + - ecdh_privkey_export [2]_ + - ecdh_pubkey_import [4]_ + - ecdh_generate_private_key [32]_ + - ecdh_generate_keypair [3]_ + - ecdh_derive [33]_ + + - ecdsa_privkey_export [2]_ + - ecdsa_generate_private_key [30]_ + - ecdsa_generate_keypair [30]_ + - ecdsa_sign_verify [30]_ + + - rng_add_entropy [5]_ + +.. [52] Failing operations for CardOS 5.3 + + - object_copy [20]_ + + - rsa_privkey_export [21]_ + - rsa_generate_private_key [22]_ + - rsa_sign_verify [23]_ + + - ecdh_privkey_export [2]_ + - ecdh_pubkey_import [6]_ + - ecdh_pubkey_export [6]_ + - ecdh_generate_private_key [30]_ + - ecdh_generate_keypair [31]_ + - ecdh_derive [30]_ + + - ecdsa_privkey_export [2]_ + - ecdsa_pubkey_import [6]_ + - ecdsa_pubkey_export [6]_ + - ecdsa_generate_private_key [31]_ + - ecdsa_generate_keypair [31]_ + - ecdsa_sign_verify [34]_ + + - rng_add_entropy [5]_ + +.. [53] Failing operations for CardOS 5.3 (middelware 5.5.1) + + - ecdh_privkey_export [2]_ + - ecdh_generate_private_key [35]_ + - ecdsa_privkey_export [2]_ + - ecdsa_generate_private_key [36]_ + - c_copy_object [4]_ + + - object_copy [4]_ + + - rng_add_entropy [5]_ + + - rsa_sign_verify [3]_ + - rsa_privkey_export [2]_ + - rsa_generate_private_key [9]_ + +.. [54] Failing operations for Gemalto IDPrime MD 3840 + + - session_login_logout [2]_ + - session_info [2]_ + - set_pin [2]_ + - initialize [2]_ + - change_so_pin [2]_ + + - object_copy [20]_ + + - rsa_generate_private_key [7]_ + - rsa_encrypt_decrypt [8]_ + - rsa_sign_verify [2]_ + + - rng_add_entropy [5]_ + +Error descriptions + +.. [2] CKR_ARGUMENTS_BAD (0x7=7) +.. [3] CKR_MECHANISM_INVALID (0x70=112) +.. [4] CKR_FUNCTION_NOT_SUPPORTED (0x54=84) +.. [5] CKR_RANDOM_SEED_NOT_SUPPORTED (0x120=288) +.. [6] CKM_X9_42_DH_KEY_PAIR_GEN | CKR_DEVICE_ERROR (0x30=48) +.. [7] CKR_TEMPLATE_INCONSISTENT (0xD1=209) +.. [8] CKR_ENCRYPTED_DATA_INVALID | CKM_SHA256_RSA_PKCS (0x40=64) +.. [9] CKR_TEMPLATE_INCOMPLETE (0xD0=208) + +.. [20] Test fails due to unsupported copy function (CKR_FUNCTION_NOT_SUPPORTED) +.. [21] Generating private key for extraction with property extractable fails (CKR_ARGUMENTS_BAD) +.. [22] Generate rsa private key operation fails (CKR_TEMPLATE_INCOMPLETE) +.. [23] Raw RSA sign-verify fails (CKR_MECHANISM_INVALID) + +.. [30] Invalid argument Decoding error: BER: Value truncated +.. [31] Invalid argument Decoding error: BER: Length field is to large +.. [32] Invalid argument OS2ECP: Unknown format type 155 +.. [33] Invalid argument OS2ECP: Unknown format type 92 +.. [34] Invalid argument OS2ECP: Unknown format type 57 +.. [35] Invalid argument OS2ECP: Unknown format type 82 +.. [36] Invalid argument OS2ECP: Unknown format type 102 diff --git a/comm/third_party/botan/doc/api_ref/psk_db.rst b/comm/third_party/botan/doc/api_ref/psk_db.rst new file mode 100644 index 0000000000..d9f8bf79be --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/psk_db.rst @@ -0,0 +1,110 @@ +PSK Database +====================== + +.. versionadded:: 2.4.0 + +Many applications need to store pre-shared keys (hereafter PSKs) for +authentication purposes. + +An abstract interface to PSK stores, along with some implementations +of same, are provided in ``psk_db.h`` + +.. cpp:class:: PSK_Database + + .. cpp:function:: bool is_encrypted() const + + Returns true if (at least) the PSKs themselves are encrypted. Returns + false if PSKs are stored in plaintext. + + .. cpp:function:: std::set list_names() const + + Return the set of valid names stored in the database, ie values for which + ``get`` will return a value. + + .. cpp:function:: void set(const std::string& name, const uint8_t psk[], size_t psk_len) + + Save a PSK. If ``name`` already exists, the current value will be + overwritten. + + .. cpp:function:: secure_vector get(const std::string& name) const + + Return a value saved with ``set``. Throws an exception if ``name`` doesn't + exist. + + .. cpp:function:: void remove(const std::string& name) + + Remove ``name`` from the database. If ``name`` doesn't exist, ignores the request. + + .. cpp::function:: std::string get_str(const std::string& name) const + + Like ``get`` but casts the return value to a string. + + .. cpp:function:: void set_str(const std::string& name, const std::string& psk) + + Like ``set`` but accepts the psk as a string (eg for a password). + + .. cpp:function:: template void set_vec(const std::string& name, \ + const std::vector& psk) + + Like ``set`` but accepting a vector. + +The same header also provides a specific instantiation of ``PSK_Database`` which +encrypts both names and PSKs. It must be subclassed to provide the storage. + +.. cpp:class:: Encrypted_PSK_Database : public PSK_Database + + .. cpp:function:: Encrypted_PSK_Database(const secure_vector& master_key) + + Initializes or opens a PSK database. The master key is used the secure the + contents. It may be of any length. If encrypting PSKs under a passphrase, + use a suitable key derivation scheme (such as PBKDF2) to derive the secret + key. If the master key is lost, all PSKs stored are unrecoverable. + + Both names and values are encrypted using NIST key wrapping (see NIST + SP800-38F) with AES-256. First the master key is used with HMAC(SHA-256) + to derive two 256-bit keys, one for encrypting all names and the other to + key an instance of HMAC(SHA-256). Values are each encrypted under an + individual key created by hashing the encrypted name with HMAC. This + associates the encrypted key with the name, and prevents an attacker with + write access to the data store from taking an encrypted key associated + with one entity and copying it to another entity. + + Names and PSKs are both padded to the next multiple of 8 bytes, providing + some obfuscation of the length. + + One artifact of the names being encrypted is that is is possible to use + multiple different master keys with the same underlying storage. Each + master key will be responsible for a subset of the keys. An attacker who + knows one of the keys will be able to tell there are other values + encrypted under another key, but will not be able to tell how many other + master keys are in use. + + .. cpp:function:: virtual void kv_set(const std::string& index, const std::string& value) = 0 + + Save an encrypted value. Both ``index`` and ``value`` will be non-empty + base64 encoded strings. + + .. cpp:function:: virtual std::string kv_get(const std::string& index) const = 0 + + Return a value saved with ``kv_set``, or return the empty string. + + .. cpp:function:: virtual void kv_del(const std::string& index) = 0 + + Remove a value saved with ``kv_set``. + + .. cpp:function:: virtual std::set kv_get_all() const = 0 + + Return all active names (ie values for which ``kv_get`` will return a + non-empty string). + +A subclass of ``Encrypted_PSK_Database`` which stores data in a SQL database +is also available. + +.. cpp:class:: Encrypted_PSK_Database_SQL : public Encrypted_PSK_Database + + .. cpp:function:: Encrypted_PSK_Database_SQL(const secure_vector& master_key, \ + std::shared_ptr db, \ + const std::string& table_name) + + Creates or uses the named table in ``db``. The SQL schema of the table is + ``(psk_name TEXT PRIMARY KEY, psk_value TEXT)``. diff --git a/comm/third_party/botan/doc/api_ref/pubkey.rst b/comm/third_party/botan/doc/api_ref/pubkey.rst new file mode 100644 index 0000000000..a8b93b4573 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/pubkey.rst @@ -0,0 +1,954 @@ +Public Key Cryptography +================================= + +Public key cryptography (also called asymmetric cryptography) is a collection +of techniques allowing for encryption, signatures, and key agreement. + +Key Objects +---------------------------------------- + +Public and private keys are represented by classes ``Public_Key`` and it's +subclass ``Private_Key``. The use of inheritance here means that a +``Private_Key`` can be converted into a reference to a public key. + +None of the functions on ``Public_Key`` and ``Private_Key`` itself are +particularly useful for users of the library, because 'bare' public key +operations are *very insecure*. The only purpose of these functions is to +provide a clean interface that higher level operations can be built on. So +really the only thing you need to know is that when a function takes a +reference to a ``Public_Key``, it can take any public key or private key, and +similarly for ``Private_Key``. + +Types of ``Public_Key`` include ``RSA_PublicKey``, ``DSA_PublicKey``, +``ECDSA_PublicKey``, ``ECKCDSA_PublicKey``, ``ECGDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, +``Curve25519_PublicKey``, ``ElGamal_PublicKey``, ``McEliece_PublicKey``, ``XMSS_PublicKey`` +and ``GOST_3410_PublicKey``. There are corresponding ``Private_Key`` classes for each of these algorithms. + +.. _creating_new_private_keys: + +Creating New Private Keys +---------------------------------------- + +Creating a new private key requires two things: a source of random numbers +(see :ref:`random_number_generators`) and some algorithm specific parameters +that define the *security level* of the resulting key. For instance, the +security level of an RSA key is (at least in part) defined by the length of +the public key modulus in bits. So to create a new RSA private key, you would +call + +.. cpp:function:: RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, size_t bits) + + A constructor that creates a new random RSA private key with a modulus + of length *bits*. + + RSA key generation is relatively slow, and can take an unpredictable + amount of time. Generating a 2048 bit RSA key might take 5 to 10 + seconds on a slow machine like a Raspberry Pi 2. Even on a fast + desktop it might take up to half a second. In a GUI blocking for + that long can be a problem. The usual approach is to perform key + generation in a new thread, with a animated modal UI element so the + user knows the application is still alive. If you wish to provide a + progress estimate things get a bit complicated but some library + users documented their approach in + `a blog post `_. + +Algorithms based on the discrete-logarithm problem use what is called a +*group*; a group can safely be used with many keys, and for some operations, +like key agreement, the two keys *must* use the same group. There are +currently two kinds of discrete logarithm groups supported in botan: the +integers modulo a prime, represented by :ref:`dl_group`, and elliptic curves +in GF(p), represented by :ref:`ec_group`. A rough generalization is that the +larger the group is, the more secure the algorithm is, but correspondingly the +slower the operations will be. + +Given a ``DL_Group``, you can create new DSA, Diffie-Hellman and ElGamal key pairs with + +.. cpp:function:: DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + + The optional *x* parameter to each of these constructors is a private key + value. This allows you to create keys where the private key is formed by + some special technique; for instance you can use the hash of a password (see + :ref:`pbkdf` for how to do that) as a private key value. Normally, you would + leave the value as zero, letting the class generate a new random key. + +Finally, given an ``EC_Group`` object, you can create a new ECDSA, ECKCDSA, ECGDSA, +ECDH, or GOST 34.10-2001 private key with + +.. cpp:function:: ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: ECKCDSA_PrivateKey::ECKCDSA_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: ECGDSA_PrivateKey::ECGDSA_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: ECDH_PrivateKey::ECDH_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. _serializing_private_keys: + +Serializing Private Keys Using PKCS #8 +---------------------------------------- + +The standard format for serializing a private key is PKCS #8, the operations +for which are defined in ``pkcs8.h``. It supports both unencrypted and +encrypted storage. + +.. cpp:function:: secure_vector PKCS8::BER_encode(const Private_Key& key, \ + RandomNumberGenerator& rng, const std::string& password, const std::string& pbe_algo = "") + + Takes any private key object, serializes it, encrypts it using + *password*, and returns a binary structure representing the private + key. + + The final (optional) argument, *pbe_algo*, specifies a particular + password based encryption (or PBE) algorithm. If you don't specify a + PBE, a sensible default will be used. + + The currently supported PBE is PBES2 from PKCS5. Format is as follows: + ``PBE-PKCS5v20(CIPHER,PBKDF)``. Since 2.8.0, ``PBES2(CIPHER,PBKDF)`` also works. + Cipher can be any block cipher with /CBC or /GCM appended, for example + "AES-128/CBC" or "Camellia-256/GCM". For best interop with other systems, use + AES in CBC mode. The PBKDF can be either the name of a hash function (in which + case PBKDF2 is used with that hash) or "Scrypt", which causes the scrypt + memory hard password hashing function to be used. Scrypt is supported since + version 2.7.0. + + Use `PBE-PKCS5v20(AES-256/CBC,SHA-256)` if you want to ensure the keys can + be imported by different software packages. Use + `PBE-PKCS5v20(AES-256/GCM,Scrypt)` for best security assuming you do not + care about interop. + + For ciphers you can use anything which has an OID defined for CBC, GCM or SIV + modes. Currently this includes AES, Camellia, Serpent, Twofish, and SM4. Most + other libraries only support CBC mode for private key encryption. GCM has + been supported in PBES2 since 1.11.10. SIV has been supported since 2.8. + +.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key, \ + RandomNumberGenerator& rng, const std::string& pass, const std::string& pbe_algo = "") + + This formats the key in the same manner as ``BER_encode``, but additionally + encodes it into a text format with identifying headers. Using PEM encoding + is *highly* recommended for many reasons, including compatibility with other + software, for transmission over 8-bit unclean channels, because it can be + identified by a human without special tools, and because it sometimes allows + more sane behavior of tools that process the data. + +Unencrypted serialization is also supported. + +.. warning:: + + In most situations, using unencrypted private key storage is a bad idea, + because anyone can come along and grab the private key without having to + know any passwords or other secrets. Unless you have very particular + security requirements, always use the versions that encrypt the key based on + a passphrase, described above. + +.. cpp:function:: secure_vector PKCS8::BER_encode(const Private_Key& key) + + Serializes the private key and returns the result. + +.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key) + + Serializes the private key, base64 encodes it, and returns the + result. + +Last but not least, there are some functions that will load (and +decrypt, if necessary) a PKCS #8 private key: + +.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, \ + RandomNumberGenerator& rng, const User_Interface& ui) + +.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, \ + RandomNumberGenerator& rng, std::string passphrase = "") + +.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, \ + RandomNumberGenerator& rng, const User_Interface& ui) + +.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, \ + RandomNumberGenerator& rng, const std::string& passphrase = "") + +These functions will return an object allocated key object based on the data +from whatever source it is using (assuming, of course, the source is in fact +storing a representation of a private key, and the decryption was +successful). The encoding used (PEM or BER) need not be specified; the format +will be detected automatically. The key is allocated with ``new``, and should +be released with ``delete`` when you are done with it. The first takes a +generic ``DataSource`` that you have to create - the other is a simple wrapper +functions that take either a filename or a memory buffer and create the +appropriate ``DataSource``. + +The versions taking a ``std::string`` attempt to decrypt using the password +given (if the key is encrypted; if it is not, the passphase value will be +ignored). If the passphrase does not decrypt the key, an exception will be +thrown. + +The ones taking a ``User_Interface`` provide a simple callback interface which +makes handling incorrect passphrases and such a bit simpler. A +``User_Interface`` has very little to do with talking to users; it's just a +way to glue together Botan and whatever user interface you happen to be using. + +.. note:: + + In a future version, it is likely that ``User_Interface`` will be + replaced by a simple callback using ``std::function``. + +To use ``User_Interface``, derive a subclass and implement: + +.. cpp:function:: std::string User_Interface::get_passphrase(const std::string& what, \ + const std::string& source, UI_Result& result) const + + The ``what`` argument specifies what the passphrase is needed for (for + example, PKCS #8 key loading passes ``what`` as "PKCS #8 private key"). This + lets you provide the user with some indication of *why* your application is + asking for a passphrase; feel free to pass the string through ``gettext(3)`` + or moral equivalent for i18n purposes. Similarly, ``source`` specifies where + the data in question came from, if available (for example, a file name). If + the source is not available for whatever reason, then ``source`` will be an + empty string; be sure to account for this possibility. + + The function returns the passphrase as the return value, and a status code + in ``result`` (either ``OK`` or ``CANCEL_ACTION``). If ``CANCEL_ACTION`` is + returned in ``result``, then the return value will be ignored, and the + caller will take whatever action is necessary (typically, throwing an + exception stating that the passphrase couldn't be determined). In the + specific case of PKCS #8 key decryption, a ``Decoding_Error`` exception will + be thrown; your UI should assume this can happen, and provide appropriate + error handling (such as putting up a dialog box informing the user of the + situation, and canceling the operation in progress). + +.. _serializing_public_keys: + +Serializing Public Keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To import and export public keys, use: + +.. cpp:function:: std::vector X509::BER_encode(const Public_Key& key) + +.. cpp:function:: std::string X509::PEM_encode(const Public_Key& key) + +.. cpp:function:: Public_Key* X509::load_key(DataSource& in) + +.. cpp:function:: Public_Key* X509::load_key(const secure_vector& buffer) + +.. cpp:function:: Public_Key* X509::load_key(const std::string& filename) + + These functions operate in the same way as the ones described in + :ref:`serializing_private_keys`, except that no encryption option is + available. + +.. _dl_group: + +DL_Group +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As described in :ref:`creating_new_private_keys`, a discrete logarithm group +can be shared among many keys, even keys created by users who do not trust +each other. However, it is necessary to trust the entity who created the +group; that is why organization like NIST use algorithms which generate groups +in a deterministic way such that creating a bogus group would require breaking +some trusted cryptographic primitive like SHA-2. + +Instantiating a ``DL_Group`` simply requires calling + +.. cpp:function:: DL_Group::DL_Group(const std::string& name) + + The *name* parameter is a specially formatted string that consists of three + things, the type of the group ("modp" or "dsa"), the creator of the group, + and the size of the group in bits, all delimited by '/' characters. + + Currently all "modp" groups included in botan are ones defined by the + Internet Engineering Task Force, so the provider is "ietf", and the strings + look like "modp/ietf/N" where N can be any of 1024, 1536, 2048, 3072, + 4096, 6144, or 8192. This group type is used for Diffie-Hellman and ElGamal + algorithms. + + The other type, "dsa" is used for DSA keys. They can also be used with + Diffie-Hellman and ElGamal, but this is less common. The currently available + groups are "dsa/jce/1024" and "dsa/botan/N" with N being 2048 or 3072. The + "jce" groups are the standard DSA groups used in the Java Cryptography + Extensions, while the "botan" groups were randomly generated using the + FIPS 186-3 algorithm by the library maintainers. + +You can generate a new random group using + +.. cpp:function:: DL_Group::DL_Group(RandomNumberGenerator& rng, \ + PrimeType type, size_t pbits, size_t qbits = 0) + + The *type* can be either ``Strong``, ``Prime_Subgroup``, or + ``DSA_Kosherizer``. *pbits* specifies the size of the prime in + bits. If the *type* is ``Prime_Subgroup`` or ``DSA_Kosherizer``, + then *qbits* specifies the size of the subgroup. + +You can serialize a ``DL_Group`` using + +.. cpp:function:: secure_vector DL_Group::DER_Encode(Format format) + +or + +.. cpp:function:: std::string DL_Group::PEM_encode(Format format) + +where *format* is any of + +* ``ANSI_X9_42`` (or ``DH_PARAMETERS``) for modp groups +* ``ANSI_X9_57`` (or ``DSA_PARAMETERS``) for DSA-style groups +* ``PKCS_3`` is an older format for modp groups; it should only + be used for backwards compatibility. + +You can reload a serialized group using + +.. cpp:function:: void DL_Group::BER_decode(DataSource& source, Format format) + +.. cpp:function:: void DL_Group::PEM_decode(DataSource& source) + +Code Example +""""""""""""""""" +The example below creates a new 2048 bit ``DL_Group``, prints the generated +parameters and ANSI_X9_42 encodes the created group for further usage with DH. + +.. code-block:: cpp + + #include + #include + #include + #include + + int main() + { + std::unique_ptr rng(new Botan::AutoSeeded_RNG); + std::unique_ptr group(new Botan::DL_Group(*rng.get(), Botan::DL_Group::Strong, 2048)); + std::cout << std::endl << "p: " << group->get_p(); + std::cout << std::endl << "q: " << group->get_q(); + std::cout << std::endl << "g: " << group->get_q(); + std::cout << std::endl << "ANSI_X9_42: " << std::endl << group->PEM_encode(Botan::DL_Group::ANSI_X9_42); + + return 0; + } + + +.. _ec_group: + +EC_Group +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An ``EC_Group`` is initialized by passing the name of the +group to be used to the constructor. These groups have +semi-standardized names like "secp256r1" and "brainpool512r1". + +Key Checking +--------------------------------- + +Most public key algorithms have limitations or restrictions on their +parameters. For example RSA requires an odd exponent, and algorithms +based on the discrete logarithm problem need a generator > 1. + +Each public key type has a function + +.. cpp:function:: bool Public_Key::check_key(RandomNumberGenerator& rng, bool strong) + + This function performs a number of algorithm-specific tests that the key + seems to be mathematically valid and consistent, and returns true if all of + the tests pass. + + It does not have anything to do with the validity of the key for any + particular use, nor does it have anything to do with certificates that link + a key (which, after all, is just some numbers) with a user or other + entity. If *strong* is ``true``, then it does "strong" checking, which + includes expensive operations like primality checking. + +As key checks are not automatically performed they must be called +manually after loading keys from untrusted sources. If a key from an untrusted source +is not checked, the implementation might be vulnerable to algorithm specific attacks. + +The following example loads the Subject Public Key from the x509 certificate ``cert.pem`` and checks the +loaded key. If the key check fails a respective error is thrown. + +.. code-block:: cpp + + #include + #include + #include + + int main() + { + Botan::X509_Certificate cert("cert.pem"); + std::unique_ptr rng(new Botan::AutoSeeded_RNG); + std::unique_ptr key(cert.subject_public_key()); + if(!key->check_key(*rng.get(), false)) + { + throw std::invalid_argument("Loaded key is invalid"); + } + } + +Encryption +--------------------------------- + +Safe public key encryption requires the use of a padding scheme which hides +the underlying mathematical properties of the algorithm. Additionally, they +will add randomness, so encrypting the same plaintext twice produces two +different ciphertexts. + +The primary interface for encryption is + +.. cpp:class:: PK_Encryptor + + .. cpp:function:: secure_vector encrypt( \ + const uint8_t* in, size_t length, RandomNumberGenerator& rng) const + + .. cpp:function:: secure_vector encrypt( \ + const std::vector& in, RandomNumberGenerator& rng) const + + These encrypt a message, returning the ciphertext. + + .. cpp:function:: size_t maximum_input_size() const + + Returns the maximum size of the message that can be processed, in + bytes. If you call :cpp:func:`PK_Encryptor::encrypt` with a value larger + than this the operation will fail with an exception. + +:cpp:class:`PK_Encryptor` is only an interface - to actually encrypt you have +to create an implementation, of which there are currently three available in the +library, :cpp:class:`PK_Encryptor_EME`, :cpp:class:`DLIES_Encryptor` and +:cpp:class:`ECIES_Encryptor`. DLIES is a hybrid encryption scheme (from +IEEE 1363) that uses the DH key agreement technique in combination with a KDF, a +MAC and a symmetric encryption algorithm to perform message encryption. ECIES is +similar to DLIES, but uses ECDH for the key agreement. Normally, public key +encryption is done using algorithms which support it directly, such as RSA or +ElGamal; these use the EME class: + +.. cpp:class:: PK_Encryptor_EME + + .. cpp:function:: PK_Encryptor_EME(const Public_Key& key, std::string eme) + + With *key* being the key you want to encrypt messages to. The padding + method to use is specified in *eme*. + + The recommended values for *eme* is "EME1(SHA-1)" or "EME1(SHA-256)". If + you need compatibility with protocols using the PKCS #1 v1.5 standard, + you can also use "EME-PKCS1-v1_5". + +.. cpp:class:: DLIES_Encryptor + + Available in the header ``dlies.h`` + + .. cpp:function:: DLIES_Encryptor(const DH_PrivateKey& own_priv_key, \ + RandomNumberGenerator& rng, KDF* kdf, MessageAuthenticationCode* mac, \ + size_t mac_key_len = 20) + + Where *kdf* is a key derivation function (see + :ref:`key_derivation_function`) and *mac* is a + MessageAuthenticationCode. The encryption is performed by XORing the + message with a stream of bytes provided by the KDF. + + .. cpp:function:: DLIES_Encryptor(const DH_PrivateKey& own_priv_key, \ + RandomNumberGenerator& rng, KDF* kdf, Cipher_Mode* cipher, \ + size_t cipher_key_len, MessageAuthenticationCode* mac, \ + size_t mac_key_len = 20) + + Instead of XORing the message a block cipher can be specified. + +.. cpp:class:: ECIES_Encryptor + + Available in the header ``ecies.h``. + + Parameters for encryption and decryption are set by the + :cpp:class:`ECIES_System_Params` class which stores the EC domain parameters, + the KDF (see :ref:`key_derivation_function`), the cipher (see + :ref:`cipher_modes`) and the MAC. + + .. cpp:function:: ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, \ + const ECIES_System_Params& ecies_params, \ + RandomNumberGenerator& rng) + + Where *private_key* is the key to use for the key agreement. The system + parameters are specified in *ecies_params* and the RNG to use is passed in + *rng*. + + .. cpp:function:: ECIES_Encryptor(RandomNumberGenerator& rng, \ + const ECIES_System_Params& ecies_params) + + Creates an ephemeral private key which is used for the key agreement. + +The decryption classes are named :cpp:class:`PK_Decryptor`, +:cpp:class:`PK_Decryptor_EME`, :cpp:class:`DLIES_Decryptor` and +:cpp:class:`ECIES_Decryptor`. They are created in the exact same way, except +they take the private key, and the processing function is named ``decrypt``. + + +Botan implements the following encryption algorithms and padding schemes: + +1. RSA + - "PKCS1v15" || "EME-PKCS1-v1_5" + - "OAEP" || "EME-OAEP" || "EME1" || "EME1(SHA-1)" || "EME1(SHA-256)" +#. DLIES +#. ECIES +#. SM2 + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following Code sample reads a PKCS #8 keypair from the passed location and +subsequently encrypts a fixed plaintext with the included public key, using EME1 +with SHA-256. For the sake of completeness, the ciphertext is then decrypted using +the private key. + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + #include + int main (int argc, char* argv[]) + { + if(argc!=2) + return 1; + std::string plaintext("Your great-grandfather gave this watch to your granddad for good luck. Unfortunately, Dane's luck wasn't as good as his old man's."); + std::vector pt(plaintext.data(),plaintext.data()+plaintext.length()); + std::unique_ptr rng(new Botan::AutoSeeded_RNG); + + //load keypair + std::unique_ptr kp(Botan::PKCS8::load_key(argv[1],*rng.get())); + + //encrypt with pk + Botan::PK_Encryptor_EME enc(*kp,*rng.get(), "EME1(SHA-256)"); + std::vector ct = enc.encrypt(pt,*rng.get()); + + //decrypt with sk + Botan::PK_Decryptor_EME dec(*kp,*rng.get(), "EME1(SHA-256)"); + std::cout << std::endl << "enc: " << Botan::hex_encode(ct) << std::endl << "dec: "<< Botan::hex_encode(dec.decrypt(ct)); + + return 0; + } + + +Signatures +--------------------------------- + +Signature generation is performed using + +.. cpp:class:: PK_Signer + + .. cpp:function:: PK_Signer(const Private_Key& key, \ + const std::string& emsa, \ + Signature_Format format = IEEE_1363) + + Constructs a new signer object for the private key *key* using the + signature format *emsa*. The key must support signature operations. In + the current version of the library, this includes RSA, DSA, ECDSA, ECKCDSA, + ECGDSA, GOST 34.10-2001. Other signature schemes may be supported in the future. + + .. note:: + + Botan both supports non-deterministic and deterministic (as per RFC + 6979) DSA and ECDSA signatures. Deterministic signatures are compatible + in the way that they can be verified with a non-deterministic implementation. + If the ``rfc6979`` module is enabled, deterministic DSA and ECDSA signatures + will be generated. + + Currently available values for *emsa* include EMSA1, EMSA2, EMSA3, EMSA4, + and Raw. All of them, except Raw, take a parameter naming a message + digest function to hash the message with. The Raw encoding signs the + input directly; if the message is too big, the signing operation will + fail. Raw is not useful except in very specialized applications. Examples + are "EMSA1(SHA-1)" and "EMSA4(SHA-256)". + + For RSA, use EMSA4 (also called PSS) unless you need compatibility with + software that uses the older PKCS #1 v1.5 standard, in which case use + EMSA3 (also called "EMSA-PKCS1-v1_5"). For DSA, ECDSA, ECKCDSA, ECGDSA and + GOST 34.10-2001 you should use EMSA1. + + The *format* defaults to ``IEEE_1363`` which is the only available + format for RSA. For DSA, ECDSA, ECGDSA and ECKCDSA you can also use + ``DER_SEQUENCE``, which will format the signature as an ASN.1 + SEQUENCE value. + + .. cpp:function:: void update(const uint8_t* in, size_t length) + .. cpp:function:: void update(const std::vector& in) + .. cpp:function:: void update(uint8_t in) + + These add more data to be included in the signature + computation. Typically, the input will be provided directly to a + hash function. + + .. cpp:function:: secure_vector signature(RandomNumberGenerator& rng) + + Creates the signature and returns it + + .. cpp:function:: secure_vector sign_message( \ + const uint8_t* in, size_t length, RandomNumberGenerator& rng) + + .. cpp:function:: secure_vector sign_message( \ + const std::vector& in, RandomNumberGenerator& rng) + + These functions are equivalent to calling + :cpp:func:`PK_Signer::update` and then + :cpp:func:`PK_Signer::signature`. Any data previously provided + using ``update`` will be included. + +Signatures are verified using + +.. cpp:class:: PK_Verifier + + .. cpp:function:: PK_Verifier(const Public_Key& pub_key, \ + const std::string& emsa, Signature_Format format = IEEE_1363) + + Construct a new verifier for signatures associated with public + key *pub_key*. The *emsa* and *format* should be the same as + that used by the signer. + + .. cpp:function:: void update(const uint8_t* in, size_t length) + .. cpp:function:: void update(const std::vector& in) + .. cpp:function:: void update(uint8_t in) + + Add further message data that is purportedly associated with the + signature that will be checked. + + .. cpp:function:: bool check_signature(const uint8_t* sig, size_t length) + .. cpp:function:: bool check_signature(const std::vector& sig) + + Check to see if *sig* is a valid signature for the message data + that was written in. Return true if so. This function clears the + internal message state, so after this call you can call + :cpp:func:`PK_Verifier::update` to start verifying another + message. + + .. cpp:function:: bool verify_message(const uint8_t* msg, size_t msg_length, \ + const uint8_t* sig, size_t sig_length) + + .. cpp:function:: bool verify_message(const std::vector& msg, \ + const std::vector& sig) + + These are equivalent to calling :cpp:func:`PK_Verifier::update` + on *msg* and then calling :cpp:func:`PK_Verifier::check_signature` + on *sig*. + + +Botan implements the following signature algorithms: + +1. RSA +#. DSA +#. ECDSA +#. ECGDSA +#. ECKDSA +#. GOST 34.10-2001 +#. Ed25519 +#. SM2 + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following sample program below demonstrates the generation of a new ECDSA keypair over the curve secp512r1 +and a ECDSA signature using EMSA1 with SHA-256. Subsequently the computed signature is validated. + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + + int main() + { + Botan::AutoSeeded_RNG rng; + // Generate ECDSA keypair + Botan::ECDSA_PrivateKey key(rng, Botan::EC_Group("secp521r1")); + + std::string text("This is a tasty burger!"); + std::vector data(text.data(),text.data()+text.length()); + // sign data + Botan::PK_Signer signer(key, rng, "EMSA1(SHA-256)"); + signer.update(data); + std::vector signature = signer.signature(rng); + std::cout << "Signature:" << std::endl << Botan::hex_encode(signature); + // verify signature + Botan::PK_Verifier verifier(key, "EMSA1(SHA-256)"); + verifier.update(data); + std::cout << std::endl << "is " << (verifier.check_signature(signature)? "valid" : "invalid"); + return 0; + } + + +Ed25519 Variants +^^^^^^^^^^^^^^^^^^ + +Most signature schemes in Botan follow a hash-then-sign paradigm. That is, the +entire message is digested to a fixed length representative using a collision +resistant hash function, and then the digest is signed. Ed25519 instead signs +the message directly. This is beneficial, in that the Ed25519 design should +remain secure even in the (extremely unlikely) event that a collision attack on +SHA-512 is found. However it means the entire message must be buffered in +memory, which can be a problem for many applications which might need to sign +large inputs. To use this variety of Ed25519, use a padding name of "Pure". + +Ed25519ph (pre-hashed) instead hashes the message with SHA-512 and then signs +the digest plus a special prefix specified in RFC 8032. To use it, specify +padding name "Ed25519ph". + +Another variant of pre-hashing is used by GnuPG. There the message is digested +with any hash function, then the digest is signed. To use it, specify any valid +hash function. Even if SHA-512 is used, this variant is not compatible with +Ed25519ph. + +For best interop with other systems, prefer "Ed25519ph". + +Key Agreement +--------------------------------- + +You can get a hold of a ``PK_Key_Agreement_Scheme`` object by calling +``get_pk_kas`` with a key that is of a type that supports key +agreement (such as a Diffie-Hellman key stored in a ``DH_PrivateKey`` +object), and the name of a key derivation function. This can be "Raw", +meaning the output of the primitive itself is returned as the key, or +"KDF1(hash)" or "KDF2(hash)" where "hash" is any string you happen to +like (hopefully you like strings like "SHA-256" or "RIPEMD-160"), or +"X9.42-PRF(keywrap)", which uses the PRF specified in ANSI X9.42. It +takes the name or OID of the key wrap algorithm that will be used to +encrypt a content encryption key. + +How key agreement works is that you trade public values with some +other party, and then each of you runs a computation with the other's +value and your key (this should return the same result to both +parties). This computation can be called by using +``derive_key`` with either a byte array/length pair, or a +``secure_vector`` than holds the public value of the other +party. The last argument to either call is a number that specifies how +long a key you want. + +Depending on the KDF you're using, you *might not* get back a key +of the size you requested. In particular "Raw" will return a number +about the size of the Diffie-Hellman modulus, and KDF1 can only return +a key that is the same size as the output of the hash. KDF2, on the +other hand, will always give you a key exactly as long as you request, +regardless of the underlying hash used with it. The key returned is a +``SymmetricKey``, ready to pass to a block cipher, MAC, or other +symmetric algorithm. + +The public value that should be used can be obtained by calling +``public_data``, which exists for any key that is associated with a +key agreement algorithm. It returns a ``secure_vector``. + +"KDF2(SHA-256)" is by far the preferred algorithm for key derivation +in new applications. The X9.42 algorithm may be useful in some +circumstances, but unless you need X9.42 compatibility, KDF2 is easier +to use. + + +Botan implements the following key agreement methods: + +1. ECDH over GF(p) Weierstrass curves +#. ECDH over x25519 +#. DH over prime fields +#. McEliece +#. NewHope + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The code below performs an unauthenticated ECDH key agreement using the secp521r elliptic curve and +applies the key derivation function KDF2(SHA-256) with 256 bit output length to the computed shared secret. + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + + int main() + { + Botan::AutoSeeded_RNG rng; + // ec domain and + Botan::EC_Group domain("secp521r1"); + std::string kdf = "KDF2(SHA-256)"; + // generate ECDH keys + Botan::ECDH_PrivateKey keyA(rng, domain); + Botan::ECDH_PrivateKey keyB(rng, domain); + // Construct key agreements + Botan::PK_Key_Agreement ecdhA(keyA,rng,kdf); + Botan::PK_Key_Agreement ecdhB(keyB,rng,kdf); + // Agree on shared secret and derive symmetric key of 256 bit length + Botan::secure_vector sA = ecdhA.derive_key(32,keyB.public_value()).bits_of(); + Botan::secure_vector sB = ecdhB.derive_key(32,keyA.public_value()).bits_of(); + + if(sA != sB) + return 1; + + std::cout << "agreed key: " << std::endl << Botan::hex_encode(sA); + return 0; + } + + +.. _mceliece: + +McEliece +-------------------------- + +McEliece is a cryptographic scheme based on error correcting codes which is +thought to be resistant to quantum computers. First proposed in 1978, it is fast +and patent-free. Variants have been proposed and broken, but with suitable +parameters the original scheme remains secure. However the public keys are quite +large, which has hindered deployment in the past. + +The implementation of McEliece in Botan was contributed by cryptosource GmbH. It +is based on the implementation HyMES, with the kind permission of Nicolas +Sendrier and INRIA to release a C++ adaption of their original C code under the +Botan license. It was then modified by Falko Strenzke to add side channel and +fault attack countermeasures. You can read more about the implementation at +http://www.cryptosource.de/docs/mceliece_in_botan.pdf + +Encryption in the McEliece scheme consists of choosing a message block of size +`n`, encoding it in the error correcting code which is the public key, then +adding `t` bit errors. The code is created such that knowing only the public +key, decoding `t` errors is intractable, but with the additional knowledge of +the secret structure of the code a fast decoding technique exists. + +The McEliece implementation in HyMES, and also in Botan, uses an optimization to +reduce the public key size, by converting the public key into a systemic code. +This means a portion of the public key is a identity matrix, and can be excluded +from the published public key. However it also means that in McEliece the +plaintext is represented directly in the ciphertext, with only a small number of +bit errors. Thus it is absolutely essential to only use McEliece with a CCA2 +secure scheme. + +One such scheme, KEM, is provided in Botan currently. It it a somewhat unusual +scheme in that it outputs two values, a symmetric key for use with an AEAD, and +an encrypted key. It does this by choosing a random plaintext (n - log2(n)*t +bits) using ``McEliece_PublicKey::random_plaintext_element``. Then a random +error mask is chosen and the message is coded and masked. The symmetric key is +SHA-512(plaintext || error_mask). As long as the resulting key is used with a +secure AEAD scheme (which can be used for transporting arbitrary amounts of +data), CCA2 security is provided. + +In ``mcies.h`` there are functions for this combination: + +.. cpp:function:: secure_vector mceies_encrypt(const McEliece_PublicKey& pubkey, \ + const secure_vector& pt, \ + uint8_t ad[], size_t ad_len, \ + RandomNumberGenerator& rng, \ + const std::string& aead = "AES-256/OCB") + +.. cpp:function:: secure_vector mceies_decrypt(const McEliece_PrivateKey& privkey, \ + const secure_vector& ct, \ + uint8_t ad[], size_t ad_len, \ + const std::string& aead = "AES-256/OCB") + +For a given security level (SL) a McEliece key would use +parameters n and t, and have the corresponding key sizes listed: + ++-----+------+-----+---------------+----------------+ +| SL | n | t | public key KB | private key KB | ++=====+======+=====+===============+================+ +| 80 | 1632 | 33 | 59 | 140 | ++-----+------+-----+---------------+----------------+ +| 107 | 2280 | 45 | 128 | 300 | ++-----+------+-----+---------------+----------------+ +| 128 | 2960 | 57 | 195 | 459 | ++-----+------+-----+---------------+----------------+ +| 147 | 3408 | 67 | 265 | 622 | ++-----+------+-----+---------------+----------------+ +| 191 | 4624 | 95 | 516 | 1234 | ++-----+------+-----+---------------+----------------+ +| 256 | 6624 | 115 | 942 | 2184 | ++-----+------+-----+---------------+----------------+ + +You can check the speed of McEliece with the suggested parameters above +using ``botan speed McEliece`` + + +eXtended Merkle Signature Scheme (XMSS) +---------------------------------------- + +Botan implements the single tree version of the eXtended Merkle Signature +Scheme (XMSS) using Winternitz One Time Signatures+ (WOTS+). The implementation +is based on `RFC 8391 "XMSS: eXtended Merkle Signature Scheme" +`_. + +XMSS uses the Botan interfaces for public key cryptography. +The following algorithms are implemented: + +1. XMSS-SHA2_10_256 +# XMSS-SHA2_16_256 +# XMSS-SHA2_20_256 +# XMSS-SHA2_10_512 +# XMSS-SHA2_16_512 +# XMSS-SHA2_20_512 +# XMSS-SHAKE_10_256 +# XMSS-SHAKE_16_256 +# XMSS-SHAKE_20_256 +# XMSS-SHAKE_10_512 +# XMSS-SHAKE_16_512 +# XMSS-SHAKE_20_512 + +The algorithm name contains the hash function name, tree height and digest +width defined by the corresponding parameter set. Choosing `XMSS-SHA2_10_256` +for instance will use the SHA2-256 hash function to generate a tree of height +ten. + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following code snippet shows a minimum example on how to create an XMSS +public/private key pair and how to use these keys to create and verify a +signature: + +.. code-block:: cpp + + #include + #include + #include + #include + + int main() + { + // Create a random number generator used for key generation. + Botan::AutoSeeded_RNG rng; + + // create a new public/private key pair using SHA2 256 as hash + // function and a tree height of 10. + Botan::XMSS_PrivateKey private_key( + Botan::XMSS_Parameters::xmss_algorithm_t::XMSS_SHA2_10_256, + rng); + Botan::XMSS_PublicKey public_key(private_key); + + // create signature operation using the private key. + std::unique_ptr sig_op = + private_key.create_signature_op(rng, "", ""); + + // create and sign a message using the signature operation. + Botan::secure_vector msg { 0x01, 0x02, 0x03, 0x04 }; + sig_op->update(msg.data(), msg.size()); + Botan::secure_vector sig = sig_op->sign(rng); + + // create verification operation using the public key + std::unique_ptr ver_op = + public_key.create_verification_op("", ""); + + // verify the signature for the previously generated message. + ver_op->update(msg.data(), msg.size()); + if(ver_op->is_valid_signature(sig.data(), sig.size())) + { + std::cout << "Success." << std::endl; + } + else + { + std::cout << "Error." << std::endl; + } + } diff --git a/comm/third_party/botan/doc/api_ref/python.rst b/comm/third_party/botan/doc/api_ref/python.rst new file mode 100644 index 0000000000..e863b648b4 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/python.rst @@ -0,0 +1,668 @@ + +Python Binding +======================================== + +.. versionadded:: 1.11.14 + +.. highlight:: python + +.. py:module:: botan + +The Python binding is based on the `ffi` module of botan and the +`ctypes` module of the Python standard library. + +Starting in 2.8, the class names were renamed to match Python standard +conventions. However aliases are defined which allow older code to +continue to work; the older names are mentioned as "previously X". +These aliases will be removed in a future major release. + +Versioning +---------------------------------------- +.. py:function:: version_major() + + Returns the major number of the library version. + +.. py:function:: version_minor() + + Returns the minor number of the library version. + +.. py:function:: version_patch() + + Returns the patch number of the library version. + +.. py:function:: version_string() + + Returns a free form version string for the library + +Random Number Generators +---------------------------------------- + +.. py:class:: RandomNumberGenerator(rng_type = 'system') + + Previously ``rng`` + + Type 'user' also allowed (userspace HMAC_DRBG seeded from system + rng). The system RNG is very cheap to create, as just a single file + handle or CSP handle is kept open, from first use until shutdown, + no matter how many 'system' rng instances are created. Thus it is + easy to use the RNG in a one-off way, with `botan.RandomNumberGenerator().get(32)`. + + .. py:method:: get(length) + + Return some bytes + + .. py:method:: reseed(bits = 256) + + Meaningless on system RNG, on userspace RNG causes a reseed/rekey + + .. py:method:: reseed_from_rng(source_rng, bits = 256) + + Take bits from the source RNG and use it to seed ``self`` + + .. py:method:: add_entropy(seed) + + Add some unpredictable seed data to the RNG + +Hash Functions +---------------------------------------- + +.. py:class:: HashFunction(algo) + + Previously ``hash_function`` + + The ``algo`` param is a string (eg 'SHA-1', 'SHA-384', 'BLAKE2b') + + .. py:method:: algo_name() + + Returns the name of this algorithm + + .. py:method:: clear() + + Clear state + + .. py:method:: output_length() + + Return output length in bytes + + .. py:method:: update(x) + + Add some input + + .. py:method:: final() + + Returns the hash of all input provided, resets + for another message. + +Message Authentication Codes +---------------------------------------- + +.. py:class:: MsgAuthCode(algo) + + Previously ``message_authentication_code`` + + Algo is a string (eg 'HMAC(SHA-256)', 'Poly1305', 'CMAC(AES-256)') + + .. py:method:: algo_name() + + Returns the name of this algorithm + + .. py:method:: clear() + + Clear internal state including the key + + .. py:method:: output_length() + + Return the output length in bytes + + .. py:method:: set_key(key) + + Set the key + + .. py:method:: update(x) + + Add some input + + .. py:method:: final() + + Returns the MAC of all input provided, resets + for another message with the same key. + +Ciphers +---------------------------------------- + +.. py:class:: SymmetricCipher(object, algo, encrypt = True) + + Previously ``cipher`` + + The algorithm is spcified as a string (eg 'AES-128/GCM', + 'Serpent/OCB(12)', 'Threefish-512/EAX'). + + Set the second param to False for decryption + + .. py:method:: algo_name() + + Returns the name of this algorithm + + .. py:method:: tag_length() + + Returns the tag length (0 for unauthenticated modes) + + .. py:method:: default_nonce_length() + + Returns default nonce length + + .. py:method:: update_granularity() + + Returns update block size. Call to update() must provide input + of exactly this many bytes + + .. py:method:: is_authenticated() + + Returns True if this is an AEAD mode + + .. py:method:: valid_nonce_length(nonce_len) + + Returns True if nonce_len is a valid nonce len for this mode + + .. py:method:: clear() + + Resets all state + + .. py:method:: set_key(key) + + Set the key + + .. py:method:: set_assoc_data(ad) + + Sets the associated data. Fails if this is not an AEAD mode + + .. py:method:: start(nonce) + + Start processing a message using nonce + + .. py:method:: update(txt) + + Consumes input text and returns output. Input text must be of + update_granularity() length. Alternately, always call finish + with the entire message, avoiding calls to update entirely + + .. py:method:: finish(txt = None) + + Finish processing (with an optional final input). May throw if + message authentication checks fail, in which case all plaintext + previously processed must be discarded. You may call finish() + with the entire message + +Bcrypt +---------------------------------------- + +.. py:function:: bcrypt(passwd, rng, work_factor = 10) + + Provided the password and an RNG object, returns a bcrypt string + +.. py:function:: check_bcrypt(passwd, bcrypt) + + Check a bcrypt hash against the provided password, returning True + iff the password matches. + +PBKDF +---------------------------------------- + +.. py:function:: pbkdf(algo, password, out_len, iterations = 100000, salt = None) + + Runs a PBKDF2 algo specified as a string (eg 'PBKDF2(SHA-256)', + 'PBKDF2(CMAC(Blowfish))'). Runs with specified iterations, with + meaning depending on the algorithm. The salt can be provided or + otherwise is randomly chosen. In any case it is returned from the + call. + + Returns out_len bytes of output (or potentially less depending on + the algorithm and the size of the request). + + Returns tuple of salt, iterations, and psk + +.. py:function:: pbkdf_timed(algo, password, out_len, ms_to_run = 300, salt = rng().get(12)) + + Runs for as many iterations as needed to consumed ms_to_run + milliseconds on whatever we're running on. Returns tuple of salt, + iterations, and psk + +Scrypt +--------------- + +.. versionadded:: 2.8.0 + +.. py:function:: scrypt(out_len, password, salt, N=1024, r=8, p=8) + + Runs Scrypt key derivation function over the specified password + and salt using Scrypt parameters N, r, p. + +KDF +---------------------------------------- + +.. py:function:: kdf(algo, secret, out_len, salt) + + Performs a key derviation function (such as "HKDF(SHA-384)") over + the provided secret and salt values. Returns a value of the + specified length. + +Public Key +---------------------------------------- + +.. py:class:: PublicKey(object) + + Previously ``public_key`` + + .. py:classmethod:: load(val) + + Load a public key. The value should be a PEM or DER blob. + + .. py:classmethod:: load_rsa(n, e) + + Load an RSA public key giving the modulus and public exponent + as integers. + + .. py:classmethod:: load_dsa(p, q, g, y) + + Load an DSA public key giving the parameters and public value + as integers. + + .. py:classmethod:: load_dh(p, g, y) + + Load an Diffie-Hellman public key giving the parameters and + public value as integers. + + .. py:classmethod:: load_elgamal(p, q, g, y) + + Load an ElGamal public key giving the parameters and + public value as integers. + + .. py:classmethod:: load_ecdsa(curve, pub_x, pub_y) + + Load an ECDSA public key giving the curve as a string + (like "secp256r1") and the public point as a pair of + integers giving the affine coordinates. + + .. py:classmethod:: load_ecdh(curve, pub_x, pub_y) + + Load an ECDH public key giving the curve as a string + (like "secp256r1") and the public point as a pair of + integers giving the affine coordinates. + + .. py:classmethod:: load_sm2(curve, pub_x, pub_y) + + Load a SM2 public key giving the curve as a string (like + "sm2p256v1") and the public point as a pair of integers giving + the affine coordinates. + + .. py:method:: check_key(rng_obj, strong=True): + + Test the key for consistency. If ``strong`` is ``True`` then + more expensive tests are performed. + + .. py:method:: export(pem=False) + + Exports the public key using the usual X.509 SPKI representation. + If ``pem`` is True, the result is a PEM encoded string. Otherwise + it is a binary DER value. + + .. py:method:: to_der() + + Like ``self.export(False)`` + + .. py:method:: to_pem() + + Like ``self.export(True)`` + + .. py:method:: get_field(field_name) + + Return an integer field related to the public key. The valid field names + vary depending on the algorithm. For example RSA public modulus can be + extracted with ``rsa_key.get_field("n")``. + + .. py:method:: fingerprint(hash = 'SHA-256') + + Returns a hash of the public key + + .. py:method:: algo_name() + + Returns the algorithm name + + .. py:method:: estimated_strength() + + Returns the estimated strength of this key against known attacks + (NFS, Pollard's rho, etc) + +Private Key +---------------------------------------- + +.. py:class:: PrivateKey + + Previously ``private_key`` + + .. py:classmethod:: create(algo, param, rng) + + Creates a new private key. The parameter type/value depends on + the algorithm. For "rsa" is is the size of the key in bits. + For "ecdsa" and "ecdh" it is a group name (for instance + "secp256r1"). For "ecdh" there is also a special case for group + "curve25519" (which is actually a completely distinct key type + with a non-standard encoding). + + .. py:classmethod:: load(val, passphrase="") + + Return a private key (DER or PEM formats accepted) + + .. py:classmethod:: load_rsa(p, q, e) + + Return a private RSA key + + .. py:classmethod:: load_dsa(p, q, g, x) + + Return a private DSA key + + .. py:classmethod:: load_dh(p, g, x) + + Return a private DH key + + .. py:classmethod:: load_elgamal(p, q, g, x) + + Return a private ElGamal key + + .. py:classmethod:: load_ecdsa(curve, x) + + Return a private ECDSA key + + .. py:classmethod:: load_ecdh(curve, x) + + Return a private ECDH key + + .. py:classmethod:: load_sm2(curve, x) + + Return a private SM2 key + + .. py:method:: get_public_key() + + Return a public_key object + + .. py:method:: to_pem() + + Return the PEM encoded private key (unencrypted). Like ``self.export(True)`` + + .. py:method:: to_der() + + Return the PEM encoded private key (unencrypted). Like ``self.export(False)`` + + .. py:method:: check_key(rng_obj, strong=True): + + Test the key for consistency. If ``strong`` is ``True`` then + more expensive tests are performed. + + .. py:method:: algo_name() + + Returns the algorithm name + + .. py:method:: export(pem=False) + + Exports the private key in PKCS8 format. If ``pem`` is True, the + result is a PEM encoded string. Otherwise it is a binary DER + value. The key will not be encrypted. + + .. py:method:: export_encrypted(passphrase, rng, pem=False, msec=300, cipher=None, pbkdf=None) + + Exports the private key in PKCS8 format, encrypted using the + provided passphrase. If ``pem`` is True, the result is a PEM + encoded string. Otherwise it is a binary DER value. + + .. py:method:: get_field(field_name) + + Return an integer field related to the public key. The valid field names + vary depending on the algorithm. For example first RSA secret prime can be + extracted with ``rsa_key.get_field("p")``. This function can also be + used to extract the public parameters. + +Public Key Operations +---------------------------------------- + +.. py:class:: PKEncrypt(pubkey, padding) + + Previously ``pk_op_encrypt`` + + .. py:method:: encrypt(msg, rng) + +.. py:class:: PKDecrypt(privkey, padding) + + Previously ``pk_op_decrypt`` + + .. py:method:: decrypt(msg) + +.. py:class:: PKSign(privkey, hash_w_padding) + + Previously ``pk_op_sign`` + + .. py:method:: update(msg) + .. py:method:: finish(rng) + +.. py:class:: PKVerify(pubkey, hash_w_padding) + + Previously ``pk_op_verify`` + + .. py:method:: update(msg) + .. py:method:: check_signature(signature) + +.. py:class:: PKKeyAgreement(privkey, kdf) + + Previously ``pk_op_key_agreement`` + + .. py:method:: public_value() + + Returns the public value to be passed to the other party + + .. py:method:: agree(other, key_len, salt) + + Returns a key derived by the KDF. + +Multiple Precision Integers (MPI) +------------------------------------- +.. versionadded:: 2.8.0 + +.. py:class:: MPI(initial_value=None, radix=None) + + Initialize an MPI object with specified value, left as zero otherwise. The + ``initial_value`` should be an ``int``, ``str``, or ``MPI``. + The ``radix`` value should be set to 16 when initializing from a base 16 `str` value. + + + Most of the usual arithmetic operators (``__add__``, ``__mul__``, etc) are + defined. + + .. py:method:: inverse_mod(modulus) + + Return the inverse of ``self`` modulo ``modulus``, or zero if no inverse exists + + .. py:method:: is_prime(rng, prob=128) + + Test if ``self`` is prime + + .. py:method:: pow_mod(exponent, modulus): + + Return ``self`` to the ``exponent`` power modulo ``modulus`` + + .. py:method:: mod_mul(other, modulus): + + Return the multiplication product of ``self`` and ``other`` modulo ``modulus`` + + .. py:method:: gcd(other): + + Return the greatest common divisor of ``self`` and ``other`` + + +Format Preserving Encryption (FE1 scheme) +----------------------------------------- +.. versionadded:: 2.8.0 + +.. py:class:: FormatPreservingEncryptionFE1(modulus, key, rounds=5, compat_mode=False) + + Initialize an instance for format preserving encryption + + .. py:method:: encrypt(msg, tweak) + + The msg should be a botan2.MPI or an object which can be converted to one + + .. py:method:: decrypt(msg, tweak) + + The msg should be a botan2.MPI or an object which can be converted to one + +HOTP +----------------------------------------- +.. versionadded:: 2.8.0 + +.. py:class:: HOTP(key, hash="SHA-1", digits=6) + + .. py:method:: generate(counter) + + Generate an HOTP code for the provided counter + + .. py:method:: check(code, counter, resync_range=0) + + Check if provided ``code`` is the correct code for ``counter``. + If ``resync_range`` is greater than zero, HOTP also checks + up to ``resync_range`` following counter values. + + Returns a tuple of (bool,int) where the boolean indicates if the + code was valid, and the int indicates the next counter value + that should be used. If the code did not verify, the next + counter value is always identical to the counter that was passed + in. If the code did verify and resync_range was zero, then the + next counter will always be counter+1. + +X509Cert +----------------------------------------- + +.. py:class:: X509Cert(filename=None, buf=None) + + .. py:method:: time_starts() + + Return the time the certificate becomes valid, as a string in form + "YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is + relative to UTC. + + .. py:method:: time_expires() + + Return the time the certificate expires, as a string in form + "YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is + relative to UTC. + + .. py:method:: to_string() + + Format the certificate as a free-form string. + + .. py:method:: fingerprint(hash_algo='SHA-256') + + Return a fingerprint for the certificate, which is basically just a hash + of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash + function is allowed. + + .. py:method:: serial_number() + + Return the serial number of the certificate. + + .. py:method:: authority_key_id() + + Return the authority key ID set in the certificate, which may be empty. + + .. py:method:: subject_key_id() + + Return the subject key ID set in the certificate, which may be empty. + + .. py:method:: subject_public_key_bits() + + Get the serialized representation of the public key included in this certificate. + + .. py:method:: subject_public_key() + + Get the public key included in this certificate as an object of class ``PublicKey``. + + .. py:method:: subject_dn(key, index) + + Get a value from the subject DN field. + + ``key`` specifies a value to get, for instance ``"Name"`` or `"Country"`. + + .. py:method:: issuer_dn(key, index) + + Get a value from the issuer DN field. + + ``key`` specifies a value to get, for instance ``"Name"`` or `"Country"`. + + .. py:method:: hostname_match(hostname) + + Return True if the Common Name (CN) field of the certificate matches a given ``hostname``. + + .. py:method:: not_before() + + Return the time the certificate becomes valid, as seconds since epoch. + + .. py:method:: not_after() + + Return the time the certificate expires, as seconds since epoch. + + .. py:method:: allowed_usage(usage_list) + + Return True if the certificates Key Usage extension contains all constraints given in ``usage_list``. + Also return True if the certificate doesn't have this extension. + Example usage constraints are: ``"DIGITAL_SIGNATURE"``, ``"KEY_CERT_SIGN"``, ``"CRL_SIGN"``. + + .. py:method:: verify(intermediates=None, \ + trusted=None, \ + trusted_path=None, \ + required_strength=0, \ + hostname=None, \ + reference_time=0 \ + crls=None) + + Verify a certificate. Returns 0 if validation was successful, returns a positive error code + if the validation was unsuccesful. + + ``intermediates`` is a list of untrusted subauthorities. + + ``trusted`` is a list of trusted root CAs. + + The `trusted_path` refers to a directory where one or more trusted CA + certificates are stored. + + Set ``required_strength`` to indicate the minimum key and hash strength + that is allowed. For instance setting to 80 allows 1024-bit RSA and SHA-1. + Setting to 110 requires 2048-bit RSA and SHA-256 or higher. Set to zero + to accept a default. + + If ``hostname`` is given, it will be checked against the certificates CN field. + + Set ``reference_time`` to be the time which the certificate chain is + validated against. Use zero (default) to use the current system clock. + + ``crls`` is a list of CRLs issued by either trusted or untrusted authorities. + + .. py:classmethod:: validation_status(error_code) + + Return an informative string associated with the verification return code. + + .. py:method:: is_revoked(self, crl) + + Check if the certificate (``self``) is revoked on the given ``crl``. + +X509CRL +----------------------------------------- + +.. py:class:: X509CRL(filename=None, buf=None) + + Class representing an X.509 Certificate Revocation List. + + A CRL in PEM or DER format can be loaded from a file, with the ``filename`` argument, + or from a bytestring, with the ``buf`` argument. + + + + + + diff --git a/comm/third_party/botan/doc/api_ref/rng.rst b/comm/third_party/botan/doc/api_ref/rng.rst new file mode 100644 index 0000000000..01c27f73cf --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/rng.rst @@ -0,0 +1,281 @@ +.. _random_number_generators: + +Random Number Generators +======================================== + +.. cpp:class:: RandomNumberGenerator + + The base class for all RNG objects, is declared in ``rng.h``. + + .. cpp:function:: void randomize(uint8_t* output_array, size_t length) + + Places *length* random bytes into the provided buffer. + + .. cpp:function:: void randomize_with_input(uint8_t* data, size_t length, \ + const uint8_t* extra_input, size_t extra_input_len) + + Like randomize, but first incorporates the additional input field into the + state of the RNG. The additional input could be anything which + parameterizes this request. Not all RNG types accept additional inputs, + the value will be silently ignored when not supported. + + .. cpp:function:: void randomize_with_ts_input(uint8_t* data, size_t length) + + Creates a buffer with some timestamp values and calls ``randomize_with_input`` + + .. note:: + + When RDRAND is enabled and available at runtime, instead of timestamps + the output of RDRAND is used as the additional data. + + .. cpp:function:: uint8_t next_byte() + + Generates a single random byte and returns it. Note that calling this + function several times is much slower than calling ``randomize`` once to + produce multiple bytes at a time. + + .. cpp:function:: void add_entropy(const uint8_t* data, size_t length) + + Incorporates provided data into the state of the PRNG, if at all possible. + This works for most RNG types, including the system and TPM RNGs. But if + the RNG doesn't support this operation, the data is dropped, no error is + indicated. + + .. cpp:function:: bool accepts_input() const + + This function returns ``false`` if it is known that this RNG object cannot + accept external inputs. In this case, any calls to + :cpp:func:`RandomNumberGenerator::add_entropy` will be ignored. + + .. cpp:function:: void reseed_from_rng(RandomNumberGenerator& rng, \ + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS) + + Reseed by calling ``rng`` to acquire ``poll_bits`` data. + + +RNG Types +---------------------------------------- + +Several different RNG types are implemented. Some access hardware RNGs, which +are only available on certain platforms. Others are mostly useful in specific +situations. + +Generally prefer using the system RNG, or if not available use ``AutoSeeded_RNG`` +which is intended to provide best possible behavior in a userspace PRNG. + +System_RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On systems which support it, in ``system_rng.h`` you can access a shared +reference to a process global instance of the system PRNG (using interfaces such +as ``/dev/urandom``, ``getrandom``, ``arc4random``, or ``RtlGenRandom``): + +.. cpp:function:: RandomNumberGenerator& system_rng() + + Returns a reference to the system RNG + +There is also a wrapper class ``System_RNG`` which simply invokes on +the return value of ``system_rng()``. This is useful in situations where +you may sometimes want to use the system RNG and a userspace RNG in others, +for example:: + + std::unique_ptr rng; + #if defined(BOTAN_HAS_SYSTEM_RNG) + rng.reset(new System_RNG); + #else + rng.reset(new AutoSeeded_RNG); + #endif + +Unlike nearly any other object in Botan it is acceptable to share a single +instance of ``System_RNG`` between threads, because the underlying RNG is itself +thread safe due to being serialized by a mutex in the kernel itself. + +AutoSeeded_RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +AutoSeeded_RNG is type naming a 'best available' userspace PRNG. The +exact definition of this has changed over time and may change in the +future, fortunately there is no compatibility concerns when changing +any RNG since the only expectation is it produces bits +indistinguishable from random. + +.. note:: Starting in 2.16.0, AutoSeeded_RNG uses an internal lock and so is + safe to share among threads. However if possible it is still better to + use a RNG per thread as otherwise the RNG object needlessly creates a + point of contention. In previous versions, the RNG does not have an + internal lock and all access to it must be serialized. + +The current version uses HMAC_DRBG with either SHA-384 or SHA-256. The +initial seed is generated either by the system PRNG (if available) or +a default set of entropy sources. These are also used for periodic +reseeding of the RNG state. + +HMAC_DRBG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +HMAC DRBG is a random number generator designed by NIST and specified +in SP 800-90A. It seems to be the most conservative generator of the +NIST approved options. + +It can be instantiated with any HMAC but is typically used with +SHA-256, SHA-384, or SHA-512, as these are the hash functions approved +for this use by NIST. + +HMAC_DRBG's constructors are: + +.. cpp:class:: HMAC_DRBG + + .. cpp:function:: HMAC_DRBG(std::unique_ptr prf, \ + RandomNumberGenerator& underlying_rng, \ + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \ + size_t max_number_of_bytes_per_request = 64 * 1024) + + Creates a DRBG which will automatically reseed as required by making + calls to ``underlying_rng`` either after being invoked + ``reseed_interval`` times, or if use of ``fork`` system call is + detected. + + You can disable automatic reseeding by setting ``reseed_interval`` to + zero, in which case ``underlying_rng`` will only be invoked in the case + of ``fork``. + + The specification of HMAC DRBG requires that each invocation produce no + more than 64 kibibytes of data. However, the RNG interface allows + producing arbitrary amounts of data in a single request. To accommodate + this, ``HMAC_DRBG`` treats requests for more data as if they were + multiple requests each of (at most) the maximum size. You can specify a + smaller maximum size with ``max_number_of_bytes_per_request``. There is + normally no reason to do this. + + .. cpp:function:: HMAC_DRBG(std::unique_ptr prf, \ + Entropy_Sources& entropy_sources, \ + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \ + size_t max_number_of_bytes_per_request = 64 * 1024) + + Like above function, but instead of an RNG taking a set of entropy + sources to seed from as required. + + .. cpp:function:: HMAC_DRBG(std::unique_ptr prf, \ + RandomNumberGenerator& underlying_rng, \ + Entropy_Sources& entropy_sources, \ + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \ + size_t max_number_of_bytes_per_request = 64 * 1024) + + Like above function, but taking both an RNG and a set of entropy + sources to seed from as required. + + .. cpp:function:: HMAC_DRBG(std::unique_ptr prf) + + Creates an unseeded DRBG. You must explicitly provide seed data later + on in order to use this RNG. This is primarily useful for deterministic + key generation. + + Since no source of data is available to automatically reseed, automatic + reseeding is disabled when this constructor is used. If the RNG object + detects that ``fork`` system call was used without it being + subsequently reseeded, it will throw an exception. + + .. cpp:function:: HMAC_DRBG(const std::string& hmac_hash) + + Like the constructor just taking a PRF, except instead of a PRF object, + a string specifying what hash to use with HMAC is provided. + +ChaCha_RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a very fast userspace PRNG based on ChaCha20 and HMAC(SHA-256). The key +for ChaCha is derived by hashing entropy inputs with HMAC. Then the ChaCha +keystream generator is run, first to generate the new HMAC key (used for any +future entropy additions), then the desired RNG outputs. + +This RNG composes two primitives thought to be secure (ChaCha and HMAC) in a +simple and well studied way (the extract-then-expand paradigm), but is still an +ad-hoc and non-standard construction. It is included because it is roughly 20x +faster then HMAC_DRBG (basically running as fast as ChaCha can generate +keystream bits), and certain applications need access to a very fast RNG. + +One thing applications using ``ChaCha_RNG`` need to be aware of is that for +performance reasons, no backtracking resistance is implemented in the RNG +design. An attacker who recovers the ``ChaCha_RNG`` state can recover the output +backwards in time to the last rekey and forwards to the next rekey. + +An explicit reseeding (:cpp:func:`RandomNumberGenerator::add_entropy`) or +providing any input to the RNG +(:cpp:func:`RandomNumberGenerator::randomize_with_ts_input`, +:cpp:func:`RandomNumberGenerator::randomize_with_input`) is sufficient to cause +a reseeding. Or, if a RNG or entropy source was provided to the ``ChaCha_RNG`` +constructor, then reseeding will be performed automatically after a certain +interval of requests. + +Processor_RNG +^^^^^^^^^^^^^^^^^ + +This RNG type directly invokes a CPU instruction capable of generating +a cryptographically secure random number. On x86 it uses ``rdrand``, +on POWER ``darn``. If the relevant instruction is not available, the +constructor of the class will throw at runtime. You can test +beforehand by checking the result of ``Processor_RNG::available()``. + +TPM_RNG +^^^^^^^^^^^^^^^^^ + +This RNG type allows using the RNG exported from a TPM chip. + +PKCS11_RNG +^^^^^^^^^^^^^^^^^ + +This RNG type allows using the RNG exported from a hardware token accessed via PKCS11. + +Entropy Sources +--------------------------------- + +An ``EntropySource`` is an abstract representation of some method of +gather "real" entropy. This tends to be very system dependent. The +*only* way you should use an ``EntropySource`` is to pass it to a PRNG +that will extract entropy from it -- never use the output directly for +any kind of key or nonce generation! + +``EntropySource`` has a pair of functions for getting entropy from +some external source, called ``fast_poll`` and ``slow_poll``. These +pass a buffer of bytes to be written; the functions then return how +many bytes of entropy were gathered. + +Note for writers of ``EntropySource`` subclasses: it isn't necessary +to use any kind of cryptographic hash on your output. The data +produced by an EntropySource is only used by an application after it +has been hashed by the ``RandomNumberGenerator`` that asked for the +entropy, thus any hashing you do will be wasteful of both CPU cycles +and entropy. + +The following entropy sources are currently used: + + * The system RNG (``arc4random``, ``/dev/urandom``, or ``RtlGenRandom``). + * RDRAND and RDSEED are used if available, but not counted as contributing entropy + * ``/dev/random`` and ``/dev/urandom``. This may be redundant with the system RNG + * ``getentropy``, only used on OpenBSD currently + * ``/proc`` walk: read files in ``/proc``. Last ditch protection against + flawed system RNG. + * Win32 stats: takes snapshot of current system processes. Last ditch + protection against flawed system RNG. + +Fork Safety +--------------------------------- + +On Unix platforms, the ``fork()`` and ``clone()`` system calls can +be used to spawn a new child process. Fork safety ensures that the +child process doesn't see the same output of random bytes as the +parent process. Botan tries to ensure fork safety by feeding the +process ID into the internal state of the random generator and by +automatically reseeding the random generator if the process ID +changed between two requests of random bytes. However, this does +not protect against PID wrap around. The process ID is usually +implemented as a 16 bit integer. In this scenario, a process will +spawn a new child process, which exits the parent process and +spawns a new child process himself. If the PID wrapped around, the +second child process may get assigned the process ID of it's +grandparent and the fork safety can not be ensured. + +Therefore, it is strongly recommended to explicitly reseed any +userspace random generators after forking a new process. If this is +not possible in your application, prefer using the system PRNG +instead. diff --git a/comm/third_party/botan/doc/api_ref/roughtime.rst b/comm/third_party/botan/doc/api_ref/roughtime.rst new file mode 100644 index 0000000000..8e6cd7c20d --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/roughtime.rst @@ -0,0 +1,6 @@ +Roughtime +=========== + +.. versionadded:: 2.13.0 + +Botan includes a Roughtime client, available in ``botan/roughtime.h`` diff --git a/comm/third_party/botan/doc/api_ref/secmem.rst b/comm/third_party/botan/doc/api_ref/secmem.rst new file mode 100644 index 0000000000..8dd479b7e8 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/secmem.rst @@ -0,0 +1,31 @@ + +Memory container +======================================== + +A major concern with mixing modern multi-user OSes and cryptographic +code is that at any time the code (including secret keys) could be +swapped to disk, where it can later be read by an attacker, or left +floating around in memory for later retrieval. + +For this reason the library uses a ``std::vector`` with a custom +allocator that will zero memory before deallocation, named via typedef +as ``secure_vector``. Because it is simply a STL vector with a custom +allocator, it has an identical API to the ``std::vector`` you know and +love. + +Some operating systems offer the ability to lock memory into RAM, +preventing swapping from occurring. Typically this operation is +restricted to privileged users (root or admin), however some OSes +including Linux and FreeBSD allow normal users to lock a small amount +of memory. On these systems, allocations first attempt to allocate out +of this small locked pool, and then if that fails will fall back to +normal heap allocations. + +The ``secure_vector`` template is only meant for primitive data types +(bytes or ints): if you want a container of higher level Botan +objects, you can just use a ``std::vector``, since these objects know +how to clear themselves when they are destroyed. You cannot, however, +have a ``std::vector`` (or any other container) of ``Pipe`` objects or +filters, because these types have pointers to other filters, and +implementing copy constructors for these types would be both hard and +quite expensive (vectors of pointers to such objects is fine, though). diff --git a/comm/third_party/botan/doc/api_ref/srp.rst b/comm/third_party/botan/doc/api_ref/srp.rst new file mode 100644 index 0000000000..cf0386b539 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/srp.rst @@ -0,0 +1,77 @@ +Secure Remote Password +======================================== + +The library contains an implementation of the +`SRP6-a `_ password authenticated +key exchange protocol in ``srp6.h``. + +A SRP client provides what is called a SRP *verifier* to the server. +This verifier is based on a password, but the password cannot be +easily derived from the verifier (however brute force attacks are +possible). Later, the client and server can perform an SRP exchange, +which results in a shared secret key. This key can be used for mutual +authentication and/or encryption. + +SRP works in a discrete logarithm group. Special parameter sets for +SRP6 are defined, denoted in the library as "modp/srp/", for +example "modp/srp/2048". + +.. warning:: + + While knowledge of the verifier does not easily allow an attacker + to get the raw password, they could still use the verifier to + impersonate the server to the client, so verifiers should be + protected as carefully as a plaintext password would be. + +.. cpp:function:: BigInt generate_srp6_verifier( \ + const std::string& username, \ + const std::string& password, \ + const std::vector& salt, \ + const std::string& group_id, \ + const std::string& hash_id) + + Generates a new verifier using the specified password and salt. + This is stored by the server. The salt must also be stored. Later, + the given username and password are used to by the client during + the key agreement step. + +.. cpp:function:: std::string srp6_group_identifier( \ + const BigInt& N, const BigInt& g) + +.. cpp:class:: SRP6_Server_Session + + .. cpp:function:: BigInt step1(const BigInt& v, \ + const std::string& group_id, \ + const std::string& hash_id, \ + RandomNumberGenerator& rng) + + Takes a verifier (generated by generate_srp6_verifier) along + with the group_id, and output a value `B` which is provided to + the client. + + .. cpp:function:: SymmetricKey step2(const BigInt& A) + + Takes the parameter A generated by srp6_client_agree, + and return the shared secret key. + + In the event of an impersonation attack (or wrong username/password, etc) + no error occurs, but the key returned will be different on the two sides. + The two sides must verify each other, for example by using the shared + secret to key an HMAC and then exchanging authenticated messages. + +.. cpp:function:: std::pair srp6_client_agree( \ + const std::string& username, \ + const std::string& password, \ + const std::string& group_id, \ + const std::string& hash_id, \ + const std::vector& salt, \ + const BigInt& B, \ + RandomNumberGenerator& rng) + + The client receives these parameters from the server, except for + the username and password which are provided by the user. The + parameter B is the output of `step1`. + + The client agreement step outputs a shared symmetric key along + with the parameter A which is returned to the server (and allows + it the compute the shared key). diff --git a/comm/third_party/botan/doc/api_ref/stream_ciphers.rst b/comm/third_party/botan/doc/api_ref/stream_ciphers.rst new file mode 100644 index 0000000000..dfee40970f --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/stream_ciphers.rst @@ -0,0 +1,211 @@ +Stream Ciphers +======================== + +In contrast to block ciphers, stream ciphers operate on a plaintext stream +instead of blocks. Thus encrypting data results in changing the internal state +of the cipher and encryption of plaintext with arbitrary length is possible in +one go (in byte amounts). All implemented stream ciphers derive from the base +class :cpp:class:`StreamCipher` (`botan/stream_cipher.h`). + +.. warning:: + + Using a stream cipher without an authentication code is extremely insecure, + because an attacker can trivially modify messages. Prefer using an + authenticated cipher mode such as GCM or SIV. + +.. warning:: + + Encrypting more than one message with the same key requires careful management + of initialization vectors. Otherwise the keystream will be reused, which causes + the security of the cipher to completely fail. + +.. cpp:class:: StreamCipher + + .. cpp:function:: std::string name() const + + Returns a human-readable string of the name of this algorithm. + + .. cpp:function:: void clear() + + Clear the key. + + .. cpp:function:: StreamCipher* clone() const + + Return a newly allocated object of the same type as this one. + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + Set the stream cipher key. If the length is not accepted, an + ``Invalid_Key_Length`` exception is thrown. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid + keylength for the algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: bool valid_iv_length(size_t iv_len) const + + This function returns true if and only if *length* is a valid IV length for + the stream cipher. Some ciphers do not support IVs at all, and will return + false for any value except zero. + + .. cpp:function:: size_t default_iv_length() const + + Returns some default IV size, normally the largest IV supported by the cipher. + If this function returns zero, then IVs are not supported and any call to + ``set_iv`` with a non-empty value will fail. + + .. cpp:function:: void set_iv(const uint8_t*, size_t len) + + Load IV into the stream cipher state. This should happen after the key is + set and before any operation (encrypt/decrypt/seek) is called. + + If the cipher does not support IVs, then a call with ``len`` equal to zero + will be accepted and any other length will cause a ``Invalid_IV_Length`` + exception. + + .. cpp:function:: void seek(uint64_t offset) + + Sets the state of the stream cipher and keystream according to the passed + *offset*, exactly as if *offset* bytes had first been encrypted. The key + and (if required) the IV have to be set before this can be called. Not all + ciphers support seeking; such objects will throw ``Not_Implemented`` in + this case. + + .. cpp:function:: void cipher(const uint8_t* in, uint8_t* out, size_t n) + + Processes *n* bytes plain/ciphertext from *in* and writes the result to *out*. + + .. cpp:function:: void cipher1(uint8_t* inout, size_t n) + + Processes *n* bytes plain/ciphertext in place. Acts like :cpp:func:`cipher`\ (inout, inout, n). + + .. cpp:function:: void encipher(std::vector inout) + .. cpp:function:: void encrypt(std::vector inout) + .. cpp:function:: void decrypt(std::vector inout) + + Processes plain/ciphertext *inout* in place. Acts like :cpp:func:`cipher`\ (inout.data(), inout.data(), inout.size()). + +Code Example +----------------- + +The following code encrypts a provided plaintext using ChaCha20. + +.. code-block:: cpp + + #include + #include + #include + #include + + int main() + { + std::string plaintext("This is a tasty burger!"); + std::vector pt(plaintext.data(),plaintext.data()+plaintext.length()); + const std::vector key = Botan::hex_decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + std::unique_ptr cipher(Botan::StreamCipher::create("ChaCha(20)")); + + //generate fresh nonce (IV) + std::unique_ptr rng(new Botan::AutoSeeded_RNG); + std::vector iv(8); + rng->randomize(iv.data(),iv.size()); + + //set key and IV + cipher->set_key(key); + cipher->set_iv(iv.data(),iv.size()); + cipher->encipher(pt); + + std::cout << cipher->name() << " with iv " << Botan::hex_encode(iv) << ": " + << Botan::hex_encode(pt) << "\n"; + return 0; + } + +Available Stream Ciphers +---------------------------- + +Botan provides the following stream ciphers. If in doubt use ChaCha20 or CTR(AES-256). + +CTR-BE +~~~~~~~ + +A cipher mode that converts a block cipher into a stream cipher. It offers +parallel execution and can seek within the output stream, both useful +properties. + +CTR mode requires an IV which can be any length up to the block size of the +underlying cipher. If it is shorter than the block size, sufficient zero bytes +are appended. + +It is possible to choose the width of the counter portion, which can improve +performance somewhat, but limits the maximum number of bytes that can safely be +encrypted. Different protocols have different conventions for the width of the +counter portion. This is done by specifying with width (which must be at least 4 +bytes, allowing to encrypt 2\ :sup:`32` blocks of data) for example +"CTR(AES-256,8)" to select a 64-bit counter. + +(The ``-BE`` suffix refers to big-endian convention for the counter. +This is the most common case.) + +OFB +~~~~~ + +Another stream cipher based on a block cipher. Unlike CTR mode, it does not +allow parallel execution or seeking within the output stream. Prefer CTR. + +Available if ``BOTAN_HAS_OFB`` is defined. + +ChaCha +~~~~~~~~ + +A very fast cipher, now widely deployed in TLS as part of the ChaCha20Poly1305 +AEAD. Can be used with 8 (fast but dangerous), 12 (balance), or 20 rounds +(conservative). Even with 20 rounds, ChaCha is very fast. Use 20 rounds. + +ChaCha supports an optional IV (which defaults to all zeros). It can be of +length 64, 96 or (since 2.8) 192 bits. Using ChaCha with a 192 bit nonce is also +known as XChaCha. + +Available if ``BOTAN_HAS_CHACHA`` is defined. + +Salsa20 +~~~~~~~~~ + +An earlier iteration of the ChaCha design, this cipher is popular due to its use +in the libsodium library. Prefer ChaCha. + +Salsa supports an optional IV (which defaults to all zeros). It can be of length +64 or 192 bits. Using Salsa with a 192 bit nonce is also known as XSalsa. + +Available if ``BOTAN_HAS_SALSA20`` is defined. + +SHAKE-128 +~~~~~~~~~~~~ + +This is the SHAKE-128 XOF exposed as a stream cipher. It is slower than ChaCha +and somewhat obscure. It does not support IVs or seeking within the cipher +stream. + +Available if ``BOTAN_HAS_SHAKE_CIPHER`` is defined. + +RC4 +~~~~ + +An old and very widely deployed stream cipher notable for its simplicity. It +does not support IVs or seeking within the cipher stream. + +.. warning:: + + RC4 is now badly broken. **Avoid in new code** and use only if required for + compatibility with existing systems. + +Available if ``BOTAN_HAS_RC4`` is defined. diff --git a/comm/third_party/botan/doc/api_ref/tls.rst b/comm/third_party/botan/doc/api_ref/tls.rst new file mode 100644 index 0000000000..fdffeda26a --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/tls.rst @@ -0,0 +1,1926 @@ +Transport Layer Security (TLS) +======================================== + +.. versionadded:: 1.11.0 + +Botan has client and server implementations of various versions of the +TLS protocol, including TLS v1.0, TLS v1.1, and TLS v1.2. As of +version 1.11.13, support for the insecure SSLv3 protocol has been +removed. + +There is also support for DTLS (v1.0 and v1.2), a variant of TLS +adapted for operation on datagram transports such as UDP and +SCTP. DTLS support should be considered as beta quality and further +testing is invited. + +The TLS implementation does not know anything about sockets or the +network layer. Instead, it calls a user provided callback (hereafter +``output_fn``) whenever it has data that it would want to send to the +other party (for instance, by writing it to a network socket), and +whenever the application receives some data from the counterparty (for +instance, by reading from a network socket) it passes that information +to TLS using :cpp:func:`TLS::Channel::received_data`. If the data +passed in results in some change in the state, such as a handshake +completing, or some data or an alert being received from the other +side, then the appropriate user provided callback will be invoked. + +If the reader is familiar with OpenSSL's BIO layer, it might be analogous +to saying the only way of interacting with Botan's TLS is via a `BIO_mem` I/O +abstraction. This makes the library completely agnostic to how you +write your network layer, be it blocking sockets, libevent, asio, a +message queue, lwIP on RTOS, some carrier pigeons, etc. + +Starting in 1.11.31, the application callbacks are encapsulated as the class +``TLS::Callbacks`` with the following members. The first four (``tls_emit_data``, +``tls_record_received``, ``tls_alert``, and ``tls_session_established``) are +mandatory for using TLS, all others are optional and provide additional +information about the connection. + + .. cpp:function:: void tls_emit_data(const uint8_t data[], size_t data_len) + + Mandatory. The TLS stack requests that all bytes of *data* be queued up to send to the + counterparty. After this function returns, the buffer containing *data* will + be overwritten, so a copy of the input must be made if the callback + cannot send the data immediately. + + As an example you could ``send`` to perform a blocking write on a socket, + or append the data to a queue managed by your application, and initiate + an asynchronous write. + + For TLS all writes must occur *in the order requested*. + For DTLS this ordering is not strictly required, but is still recommended. + + .. cpp:function:: void tls_record_received(uint64_t rec_no, const uint8_t data[], size_t data_len) + + Mandatory. Called once for each application_data record which is received, with the + matching (TLS level) record sequence number. + + Currently empty records are ignored and do not instigate a callback, + but this may change in a future release. + + As with ``tls_emit_data``, the array will be overwritten sometime after + the callback returns, so a copy should be made if needed. + + For TLS the record number will always increase. + + For DTLS, it is possible to receive records with the `rec_no` field out of + order, or with gaps, corresponding to reordered or lost datagrams. + + .. cpp:function:: void tls_alert(Alert alert) + + Mandatory. Called when an alert is received from the peer. Note that alerts + received before the handshake is complete are not authenticated and + could have been inserted by a MITM attacker. + + .. cpp:function:: bool tls_session_established(const TLS::Session& session) + + Mandatory. Called whenever a negotiation completes. This can happen more + than once on any connection, if renegotiation occurs. The *session* parameter + provides information about the session which was just established. + + If this function returns false, the session will not be cached + for later resumption. + + If this function wishes to cancel the handshake, it can throw an + exception which will send a close message to the counterparty and + reset the connection state. + + .. cpp:function:: void tls_verify_cert_chain(const std::vector& cert_chain, \ + const std::vector>& ocsp_responses, \ + const std::vector& trusted_roots, \ + Usage_Type usage, \ + const std::string& hostname, \ + const Policy& policy) + + Optional - default implementation should work for many users. + It can be overridden for implementing extra validation routines + such as public key pinning. + + Verifies the certificate chain in *cert_chain*, assuming the leaf + certificate is the first element. Throws an exception if any + error makes this certificate chain unacceptable. + + If usage is `Usage_Type::TLS_SERVER_AUTH`, then *hostname* should + match the information in the server certificate. If usage is + `TLS_CLIENT_AUTH`, then *hostname* specifies the host the client + is authenticating against (from SNI); the callback can use this for + any special site specific auth logic. + + The `ocsp_responses` is a possibly empty list of OCSP responses provided by + the server. In the current implementation of TLS OCSP stapling, only a + single OCSP response can be returned. A existing TLS extension allows the + server to send multiple OCSP responses, this extension may be supported in + the future in which case more than one OCSP response may be given during + this callback. + + The `trusted_roots` parameter was returned by a call from the associated + `Credentials_Manager`. + + The `policy` provided is the policy for the TLS session which is + being authenticated using this certificate chain. It can be consulted + for values such as allowable signature methods and key sizes. + + .. cpp:function:: std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const + + Called by default `tls_verify_cert_chain` to set timeout for online OCSP requests + on the certificate chain. Return 0 to disable OCSP. Current default is 0. + + .. cpp:function:: std::string tls_server_choose_app_protocol(const std::vector& client_protos) + + Optional. Called by the server when a client includes a list of protocols in the ALPN extension. + The server then choose which protocol to use, or "" to disable sending any ALPN response. + The default implementation returns the empty string all of the time, effectively disabling + ALPN responses. + + .. cpp:function:: void tls_session_activated() + + Optional. By default does nothing. This is called when the session is + activated, that is once it is possible to send or receive data on the + channel. In particular it is possible for an implementation of this + function to perform an initial write on the channel. + + .. cpp:function:: std::vector tls_provide_cert_status(const std::vector& chain, \ + const Certificate_Status_Request& csr) + + Optional. This can return a cached OCSP response. This is only + used on the server side, and only if the client requests OCSP + stapling. + + .. cpp:function:: std::string tls_peer_network_identity() + + Optional. Return a string that identifies the peer in some unique way + (for example, by formatting the remote IP and port into a string). + This is currently used to bind DTLS cookies to the network identity. + + .. cpp:function:: void tls_inspect_handshake_msg(const Handshake_Message&) + + This callback is optional, and can be used to inspect all handshake messages + while the session establishment occurs. + + .. cpp:function:: void tls_modify_extensions(Extensions& extn, Connection_Side which_side) + + This callback is optional, and can be used to modify extensions before they + are sent to the peer. For example this enables adding a custom extension, + or replacing or removing an extension set by the library. + + .. cpp:function:: void tls_examine_extensions(const Extensions& extn, Connection_Side which_side) + + This callback is optional, and can be used to examine extensions sent by + the peer. + + .. cpp:function:: void tls_log_error(const char* msg) + + Optional logging for an error message. (Not currently used) + + .. cpp:function:: void tls_log_debug(const char* msg) + + Optional logging for an debug message. (Not currently used) + + .. cpp:function:: void tls_log_debug_bin(const char* descr, const uint8_t val[], size_t len) + + Optional logging for an debug value. (Not currently used) + + .. cpp:function:: std::string tls_decode_group_param(TLS::Group_Params group_param) + + Optional. Called by the server when a client hello includes a list of supported groups in the + supported_groups extension and by the client when decoding the server key exchange including the selected curve identifier. + The function should return the name of the DH group or elliptic curve the passed + TLS group identifier should be mapped to. Therefore this callback enables the use of custom + elliptic curves or DH groups in TLS, if both client and server map the custom identifiers correctly. + Please note that it is required to allow the group TLS identifier in + in the used :cpp:class:`TLS::Policy`. + +Versions from 1.11.0 to 1.11.30 did not have ``TLS::Callbacks`` and instead +used independent std::functions to pass the various callback functions. +This interface is currently still included but is deprecated and will be removed +in a future release. For the documentation for this interface, please check +the docs for 1.11.30. This version of the manual only documents the new interface +added in 1.11.31. + +TLS Channels +---------------------------------------- + +TLS servers and clients share an interface called `TLS::Channel`. A +TLS channel (either client or server object) has these methods +available: + +.. cpp:class:: TLS::Channel + + .. cpp:function:: size_t received_data(const uint8_t buf[], size_t buf_size) + .. cpp:function:: size_t received_data(const std::vector& buf) + + This function is used to provide data sent by the counterparty + (eg data that you read off the socket layer). Depending on the + current protocol state and the amount of data provided this may + result in one or more callback functions that were provided to + the constructor being called. + + The return value of ``received_data`` specifies how many more + bytes of input are needed to make any progress, unless the end of + the data fell exactly on a message boundary, in which case it + will return 0 instead. + + .. cpp:function:: void send(const uint8_t buf[], size_t buf_size) + .. cpp:function:: void send(const std::string& str) + .. cpp:function:: void send(const std::vector& vec) + + Create one or more new TLS application records containing the + provided data and send them. This will eventually result in at + least one call to the ``output_fn`` callback before ``send`` + returns. + + If the current TLS connection state is unable to transmit new + application records (for example because a handshake has not + yet completed or the connection has already ended due to an + error) an exception will be thrown. + + .. cpp:function:: void close() + + A close notification is sent to the counterparty, and the + internal state is cleared. + + .. cpp:function:: void send_alert(const Alert& alert) + + Some other alert is sent to the counterparty. If the alert is + fatal, the internal state is cleared. + + .. cpp:function:: bool is_active() + + Returns true if and only if a handshake has been completed on + this connection and the connection has not been subsequently + closed. + + .. cpp:function:: bool is_closed() + + Returns true if and only if either a close notification or a + fatal alert message have been either sent or received. + + .. cpp:function:: bool timeout_check() + + This function does nothing unless the channel represents a DTLS + connection and a handshake is actively in progress. In this case + it will check the current timeout state and potentially initiate + retransmission of handshake packets. Returns true if a timeout + condition occurred. + + .. cpp:function:: void renegotiate(bool force_full_renegotiation = false) + + Initiates a renegotiation. The counterparty is allowed by the + protocol to ignore this request. If a successful renegotiation + occurs, the *handshake_cb* callback will be called again. + + If *force_full_renegotiation* is false, then the client will + attempt to simply renew the current session - this will refresh + the symmetric keys but will not change the session master + secret. Otherwise it will initiate a completely new session. + + For a server, if *force_full_renegotiation* is false, then a + session resumption will be allowed if the client attempts + it. Otherwise the server will prevent resumption and force the + creation of a new session. + + .. cpp:function:: std::vector peer_cert_chain() + + Returns the certificate chain of the counterparty. When acting + as a client, this value will be non-empty unless the client's + policy allowed anonymous connections and the server then chose + an anonymous ciphersuite. Acting as a server, this value will + ordinarily be empty, unless the server requested a certificate + and the client responded with one. + + .. cpp:function:: SymmetricKey key_material_export( \ + const std::string& label, \ + const std::string& context, \ + size_t length) + + Returns an exported key of *length* bytes derived from *label*, + *context*, and the session's master secret and client and server + random values. This key will be unique to this connection, and + as long as the session master secret remains secure an attacker + should not be able to guess the key. + + Per :rfc:`5705`, *label* should begin with "EXPERIMENTAL" unless + the label has been standardized in an RFC. + +.. _tls_client: + +TLS Clients +---------------------------------------- + +.. cpp:class:: TLS::Client + + .. cpp:function:: Client( \ + Callbacks& callbacks, \ + Session_Manager& session_manager, \ + Credentials_Manager& creds, \ + const Policy& policy, \ + RandomNumberGenerator& rng, \ + const Server_Information& server_info = Server_Information(), \ + const Protocol_Version offer_version = Protocol_Version::latest_tls_version(), \ + const std::vector& next_protocols = std::vector(), \ + size_t reserved_io_buffer_size = 16*1024 \ + ) + + Initialize a new TLS client. The constructor will immediately + initiate a new session. + + The *callbacks* parameter specifies the various application callbacks + which pertain to this particular client connection. + + The *session_manager* is an interface for storing TLS sessions, + which allows for session resumption upon reconnecting to a server. + In the absence of a need for persistent sessions, use + :cpp:class:`TLS::Session_Manager_In_Memory` which caches + connections for the lifetime of a single process. See + :ref:`tls_session_managers` for more about session managers. + + The *credentials_manager* is an interface that will be called to + retrieve any certificates, secret keys, pre-shared keys, or SRP + information; see :doc:`credentials_manager` for more information. + + Use the optional *server_info* to specify the DNS name of the + server you are attempting to connect to, if you know it. This helps + the server select what certificate to use and helps the client + validate the connection. + + Note that the server name indicator name must be a FQDN. IP + addresses are not allowed by RFC 6066 and may lead to interoperability + problems. + + Use the optional *offer_version* to control the version of TLS you + wish the client to offer. Normally, you'll want to offer the most + recent version of (D)TLS that is available, however some broken + servers are intolerant of certain versions being offered, and for + classes of applications that have to deal with such servers + (typically web browsers) it may be necessary to implement a version + backdown strategy if the initial attempt fails. + + .. warning:: + + Implementing such a backdown strategy allows an attacker to + downgrade your connection to the weakest protocol that both you + and the server support. + + Setting *offer_version* is also used to offer DTLS instead of TLS; + use :cpp:func:`TLS::Protocol_Version::latest_dtls_version`. + + Optionally, the client will advertise *app_protocols* to the + server using the ALPN extension. + + The optional *reserved_io_buffer_size* specifies how many bytes to + pre-allocate in the I/O buffers. Use this if you want to control + how much memory the channel uses initially (the buffers will be + resized as needed to process inputs). Otherwise some reasonable + default is used. + +Code Example +^^^^^^^^^^^^ +A minimal example of a TLS client is provided below. +The full code for a TLS client using BSD sockets is in `src/cli/tls_client.cpp` + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls server, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls server, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls server was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + }; + + /** + * @brief Credentials storage for the tls client. + * + * It returns a list of trusted CA certificates from a local directory. + * TLS client authentication is disabled. See src/lib/tls/credentials_manager.h. + */ + class Client_Credentials : public Botan::Credentials_Manager + { + public: + Client_Credentials() + { + // Here we base trust on the system managed trusted CA list + m_stores.push_back(new Botan::System_Certificate_Store); + } + + std::vector trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // return a list of certificates of CAs we trust for tls server certificates + // ownership of the pointers remains with Credentials_Manager + return m_stores; + } + + std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& type, + const std::string& context) override + { + // when using tls client authentication (optional), return + // a certificate chain being sent to the tls server, + // else an empty list + return std::vector(); + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // when returning a chain in cert_chain(), return the private key + // associated with the leaf certificate here + return nullptr; + } + + private: + std::vector m_stores; + }; + + int main() + { + // prepare all the parameters + Callbacks callbacks; + Botan::AutoSeeded_RNG rng; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Client_Credentials creds; + Botan::TLS::Strict_Policy policy; + + // open the tls connection + Botan::TLS::Client client(callbacks, + session_mgr, + creds, + policy, + rng, + Botan::TLS::Server_Information("botan.randombit.net", 443), + Botan::TLS::Protocol_Version::TLS_V12); + + while(!client.is_closed()) + { + // read data received from the tls server, e.g., using BSD sockets or boost asio + // ... + + // send data to the tls server using client.send_data() + } + } + +.. _tls_server: + +TLS Servers +---------------------------------------- + +.. cpp:class:: TLS::Server + + .. cpp:function:: Server( \ + Callbacks& callbacks, \ + Session_Manager& session_manager, \ + Credentials_Manager& creds, \ + const Policy& policy, \ + RandomNumberGenerator& rng, \ + bool is_datagram = false, \ + size_t reserved_io_buffer_size = 16*1024 \ + ) + +The first 5 arguments as well as the final argument +*reserved_io_buffer_size*, are treated similarly to the :ref:`client +`. + +If a client sends the ALPN extension, the ``callbacks`` function +``tls_server_choose_app_protocol`` will be called and the result +sent back to the client. If the empty string is returned, the server +will not send an ALPN response. The function can also throw an exception +to abort the handshake entirely, the ALPN specification says that if this +occurs the alert should be of type `NO_APPLICATION_PROTOCOL`. + +The optional argument *is_datagram* specifies if this is a TLS or DTLS +server; unlike clients, which know what type of protocol (TLS vs DTLS) +they are negotiating from the start via the *offer_version*, servers +would not until they actually received a client hello. + +Code Example +^^^^^^^^^^^^ +A minimal example of a TLS server is provided below. +The full code for a TLS server using asio is in `src/cli/tls_proxy.cpp`. + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + #include + + #include + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls client, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls client, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls client was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + }; + + /** + * @brief Credentials storage for the tls server. + * + * It returns a certificate and the associated private key to + * authenticate the tls server to the client. + * TLS client authentication is not requested. + * See src/lib/tls/credentials_manager.h. + */ + class Server_Credentials : public Botan::Credentials_Manager + { + public: + Server_Credentials() : m_key(Botan::PKCS8::load_key("botan.randombit.net.key")) + { + } + + std::vector trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // if client authentication is required, this function + // shall return a list of certificates of CAs we trust + // for tls client certificates, otherwise return an empty list + return std::vector(); + } + + std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& type, + const std::string& context) override + { + // return the certificate chain being sent to the tls client + // e.g., the certificate file "botan.randombit.net.crt" + return { Botan::X509_Certificate("botan.randombit.net.crt") }; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // return the private key associated with the leaf certificate, + // in this case the one associated with "botan.randombit.net.crt" + return &m_key; + } + + private: + std::unique_ptr m_key; + }; + + int main() + { + // prepare all the parameters + Callbacks callbacks; + Botan::AutoSeeded_RNG rng; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Server_Credentials creds; + Botan::TLS::Strict_Policy policy; + + // accept tls connection from client + Botan::TLS::Server server(callbacks, + session_mgr, + creds, + policy, + rng); + + // read data received from the tls client, e.g., using BSD sockets or boost asio + // and pass it to server.received_data(). + // ... + + // send data to the tls client using server.send_data() + // ... + } + +.. _tls_sessions: + +TLS Sessions +---------------------------------------- + +TLS allows clients and servers to support *session resumption*, where +the end point retains some information about an established session +and then reuse that information to bootstrap a new session in way that +is much cheaper computationally than a full handshake. + +Every time your handshake callback is called, a new session has been +established, and a ``TLS::Session`` is included that provides +information about that session: + +.. note:: + + The serialization format of Session is not considered stable and is allowed + to change even across minor releases. In the event of such a change, old + sessions will no longer be able to be resumed. + +.. cpp:class:: TLS::Session + + .. cpp:function:: Protocol_Version version() const + + Returns the :cpp:class:`protocol version ` + that was negotiated + + .. cpp:function:: Ciphersuite ciphersite() const + + Returns the :cpp:class:`ciphersuite ` that + was negotiated. + + .. cpp:function:: Server_Information server_info() const + + Returns information that identifies the server side of the + connection. This is useful for the client in that it + identifies what was originally passed to the constructor. For + the server, it includes the name the client specified in the + server name indicator extension. + + .. cpp:function:: std::vector peer_certs() const + + Returns the certificate chain of the peer + + .. cpp:function:: std::string srp_identifier() const + + If an SRP ciphersuite was used, then this is the identifier + that was used for authentication. + + .. cpp:function:: bool secure_renegotiation() const + + Returns ``true`` if the connection was negotiated with the + correct extensions to prevent the renegotiation attack. + + .. cpp:function:: std::vector encrypt(const SymmetricKey& key, \ + RandomNumberGenerator& rng) + + Encrypts a session using a symmetric key *key* and returns a raw + binary value that can later be passed to ``decrypt``. The key + may be of any length. The format is described in + :ref:`tls_session_encryption`. + + .. cpp:function:: static Session decrypt(const uint8_t ciphertext[], \ + size_t length, \ + const SymmetricKey& key) + + Decrypts a session that was encrypted previously with ``encrypt`` and + ``key``, or throws an exception if decryption fails. + + .. cpp:function:: secure_vector DER_encode() const + + Returns a serialized version of the session. + + .. warning:: The return value of ``DER_encode`` contains the + master secret for the session, and an attacker who + recovers it could recover plaintext of previous + sessions or impersonate one side to the other. + +.. _tls_session_managers: + +TLS Session Managers +---------------------------------------- + +You may want sessions stored in a specific format or storage type. To +do so, implement the ``TLS::Session_Manager`` interface and pass your +implementation to the ``TLS::Client`` or ``TLS::Server`` constructor. + +.. cpp:class:: TLS::Session_Mananger + + .. cpp:function:: void save(const Session& session) + + Save a new *session*. It is possible that this sessions session + ID will replicate a session ID already stored, in which case the + new session information should overwrite the previous information. + + .. cpp:function:: void remove_entry(const std::vector& session_id) + + Remove the session identified by *session_id*. Future attempts + at resumption should fail for this session. + + .. cpp:function:: bool load_from_session_id(const std::vector& session_id, \ + Session& session) + + Attempt to resume a session identified by *session_id*. If + located, *session* is set to the session data previously passed + to *save*, and ``true`` is returned. Otherwise *session* is not + modified and ``false`` is returned. + + .. cpp:function:: bool load_from_server_info(const Server_Information& server, \ + Session& session) + + Attempt to resume a session with a known server. + + .. cpp:function:: std::chrono::seconds session_lifetime() const + + Returns the expected maximum lifetime of a session when using + this session manager. Will return 0 if the lifetime is unknown + or has no explicit expiration policy. + +.. _tls_session_manager_inmem: + +In Memory Session Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``TLS::Session_Manager_In_Memory`` implementation saves sessions +in memory, with an upper bound on the maximum number of sessions and +the lifetime of a session. + +It is safe to share a single object across many threads as it uses a +lock internally. + +.. cpp:class:: TLS::Session_Managers_In_Memory + + .. cpp:function:: Session_Manager_In_Memory(RandomNumberGenerator& rng, \ + size_t max_sessions = 1000, \ + std::chrono::seconds session_lifetime = 7200) + + Limits the maximum number of saved sessions to *max_sessions*, and + expires all sessions older than *session_lifetime*. + +Noop Session Mananger +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``TLS::Session_Manager_Noop`` implementation does not save +sessions at all, and thus session resumption always fails. Its +constructor has no arguments. + +SQLite3 Session Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This session manager is only available if support for SQLite3 was +enabled at build time. If the macro +``BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER`` is defined, then +``botan/tls_session_manager_sqlite.h`` contains +``TLS::Session_Manager_SQLite`` which stores sessions persistently to +a sqlite3 database. The session data is encrypted using a passphrase, +and stored in two tables, named ``tls_sessions`` (which holds the +actual session information) and ``tls_sessions_metadata`` (which holds +the PBKDF information). + +.. warning:: The hostnames associated with the saved sessions are + stored in the database in plaintext. This may be a + serious privacy risk in some applications. + +.. cpp:class:: TLS::Session_Manager_SQLite + + .. cpp:function:: Session_Manager_SQLite( \ + const std::string& passphrase, \ + RandomNumberGenerator& rng, \ + const std::string& db_filename, \ + size_t max_sessions = 1000, \ + std::chrono::seconds session_lifetime = 7200) + + Uses the sqlite3 database named by *db_filename*. + +TLS Policies +---------------------------------------- + +``TLS::Policy`` is how an application can control details of what will +be negotiated during a handshake. The base class acts as the default +policy. There is also a ``Strict_Policy`` (which forces only secure +options, reducing compatibility) and ``Text_Policy`` which reads +policy settings from a file. + +.. cpp:class:: TLS::Policy + + .. cpp:function:: std::vector allowed_ciphers() const + + Returns the list of ciphers we are willing to negotiate, in order + of preference. + + Clients send a list of ciphersuites in order of preference, + servers are free to choose any of them. Some servers will use the + clients preferences, others choose from the clients list + prioritizing based on its preferences. + + No export key exchange mechanisms or ciphersuites are supported + by botan. The null encryption ciphersuites (which provide only + authentication, sending data in cleartext) are also not supported + by the implementation and cannot be negotiated. + + Cipher names without an explicit mode refers to CBC+HMAC ciphersuites. + + Default value: "ChaCha20Poly1305", "AES-256/GCM", "AES-128/GCM" + + Also allowed: "AES-256", "AES-128", + "AES-256/CCM", "AES-128/CCM", "AES-256/CCM(8)", "AES-128/CCM(8)", + "Camellia-256/GCM", "Camellia-128/GCM", "ARIA-256/GCM", "ARIA-128/GCM", + "Camellia-256", "Camellia-128" + + Also allowed (though currently experimental): "AES-128/OCB(12)", + "AES-256/OCB(12)" + + In versions up to 2.8.0, the CBC and CCM ciphersuites "AES-256", + "AES-128", "AES-256/CCM" and "AES-128/CCM" were enabled by default. + + Also allowed (although **not recommended**): "SEED", "3DES" + + .. note:: + + Before 1.11.30 only the non-standard ChaCha20Poly1305 ciphersuite + was implemented. The RFC 7905 ciphersuites are supported in 1.11.30 + onwards. + + .. note:: + + Support for the broken RC4 cipher was removed in 1.11.17 + + .. note:: + + SEED and 3DES are deprecated and will be removed in a future release. + + .. cpp:function:: std::vector allowed_macs() const + + Returns the list of algorithms we are willing to use for + message authentication, in order of preference. + + Default: "AEAD", "SHA-256", "SHA-384", "SHA-1" + + A plain hash function indicates HMAC + + .. note:: + + SHA-256 is preferred over SHA-384 in CBC mode because the + protections against the Lucky13 attack are somewhat more + effective for SHA-256 than SHA-384. + + .. cpp:function:: std::vector allowed_key_exchange_methods() const + + Returns the list of key exchange methods we are willing to use, + in order of preference. + + Default: "CECPQ1", "ECDH", "DH" + + .. note:: + + CECPQ1 key exchange provides post-quantum security to the key exchange + by combining NewHope with a standard x25519 ECDH exchange. This prevents + an attacker, even one with a quantum computer, from later decrypting the + contents of a recorded TLS transcript. The NewHope algorithm is very + fast, but adds roughly 4 KiB of additional data transfer to every TLS + handshake. And even if NewHope ends up completely broken, the 'extra' + x25519 exchange secures the handshake. + + For applications where the additional data transfer size is unacceptable, + simply allow only ECDH key exchange in the application policy. DH + exchange also often involves transferring several additional Kb (without + the benefit of post quantum security) so if CECPQ1 is being disabled for + traffic overhead reasons, DH should also be avoided. + + Also allowed: "RSA", "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK" + + .. note:: + + Static RSA ciphersuites are disabled by default since 1.11.34. + In addition to not providing forward security, any server which is + willing to negotiate these ciphersuites exposes themselves to a variety + of chosen ciphertext oracle attacks which are all easily avoided by + signing (as in PFS) instead of decrypting. + + .. note:: + + In order to enable RSA, SRP, or PSK ciphersuites one must also enable + authentication method "IMPLICIT", see :cpp:func:`allowed_signature_methods`. + + .. cpp:function:: std::vector allowed_signature_hashes() const + + Returns the list of hash algorithms we are willing to use for + public key signatures, in order of preference. + + Default: "SHA-512", "SHA-384", "SHA-256" + + Also allowed (although **not recommended**): "SHA-1" + + .. note:: + + This is only used with TLS v1.2. In earlier versions of the + protocol, signatures are fixed to using only SHA-1 (for + DSA/ECDSA) or a MD5/SHA-1 pair (for RSA). + + .. cpp:function:: std::vector allowed_signature_methods() const + + Default: "ECDSA", "RSA" + + Also allowed (disabled by default): "DSA", "IMPLICIT", "ANONYMOUS" + + "IMPLICIT" enables ciphersuites which are authenticated not by a signature + but through a side-effect of the key exchange. In particular this setting + is required to enable PSK, SRP, and static RSA ciphersuites. + + "ANONYMOUS" allows purely anonymous DH/ECDH key exchanges. **Enabling this + is not recommended** + + .. note:: + + Both DSA authentication and anonymous DH ciphersuites are deprecated, + and will be removed in a future release. + + .. cpp:function:: std::vector key_exchange_groups() const + + Return a list of ECC curve and DH group TLS identifiers we are willing to use, in order of preference. + The default ordering puts the best performing ECC first. + + Default: + Group_Params::X25519, + Group_Params::SECP256R1, Group_Params::BRAINPOOL256R1, + Group_Params::SECP384R1, Group_Params::BRAINPOOL384R1, + Group_Params::SECP521R1, Group_Params::BRAINPOOL512R1, + Group_Params::FFDHE_2048, Group_Params::FFDHE_3072, Group_Params::FFDHE_4096, + Group_Params::FFDHE_6144, Group_Params::FFDHE_8192 + + No other values are currently defined. + + .. cpp:function:: bool use_ecc_point_compression() const + + Prefer ECC point compression. + + Signals that we prefer ECC points to be compressed when transmitted to us. + The other party may not support ECC point compression and therefore may still + send points uncompressed. + + Note that the certificate used during authentication must also follow the other + party's preference. + + Default: false + + .. note:: + + Support for EC point compression is deprecated and will be removed in a + future major release. + + .. cpp:function:: bool acceptable_protocol_version(Protocol_Version version) + + Return true if this version of the protocol is one that we are + willing to negotiate. + + Default: Accepts TLS v1.2 and DTLS v1.2, and rejects all older versions. + + .. cpp:function:: bool server_uses_own_ciphersuite_preferences() const + + If this returns true, a server will pick the cipher it prefers the + most out of the client's list. Otherwise, it will negotiate the + first cipher in the client's ciphersuite list that it supports. + + Default: true + + .. cpp:function:: bool allow_client_initiated_renegotiation() const + + If this function returns true, a server will accept a + client-initiated renegotiation attempt. Otherwise it will send + the client a non-fatal ``no_renegotiation`` alert. + + Default: false + + .. cpp:function:: bool allow_server_initiated_renegotiation() const + + If this function returns true, a client will accept a + server-initiated renegotiation attempt. Otherwise it will send + the server a non-fatal ``no_renegotiation`` alert. + + Default: false + + .. cpp:function:: bool abort_connection_on_undesired_renegotiation() const + + If a renegotiation attempt is being rejected due to the configuration of + :cpp:func:`TLS::Policy::allow_client_initiated_renegotiation` or + :cpp:func:`TLS::Policy::allow_server_initiated_renegotiation`, and + this function returns true then the connection is closed with a fatal + alert instead of the default warning alert. + + Default: false + + .. cpp:function:: bool allow_insecure_renegotiation() const + + If this function returns true, we will allow renegotiation attempts + even if the counterparty does not support the RFC 5746 extensions. + + .. warning:: Returning true here could expose you to attacks + + Default: false + + .. cpp:function:: size_t minimum_signature_strength() const + + Return the minimum strength (as ``n``, representing ``2**n`` work) + we will accept for a signature algorithm on any certificate. + + Use 80 to enable RSA-1024 (*not recommended*), or 128 to require + either ECC or large (~3000 bit) RSA keys. + + Default: 110 (allowing 2048 bit RSA) + + .. cpp:function:: bool require_cert_revocation_info() const + + If this function returns true, and a ciphersuite using certificates was + negotiated, then we must have access to a valid CRL or OCSP response in + order to trust the certificate. + + .. warning:: Returning false here could expose you to attacks + + Default: true + + .. cpp:function:: Group_Params default_dh_group() const + + For ephemeral Diffie-Hellman key exchange, the server sends a + group parameter. Return the 2 Byte TLS group identifier specifying the group parameter a + server should use. + + Default: 2048 bit IETF IPsec group ("modp/ietf/2048") + + .. cpp:function:: size_t minimum_dh_group_size() const + + Return the minimum size in bits for a Diffie-Hellman group that a + client will accept. Due to the design of the protocol the client + has only two options - accept the group, or reject it with a + fatal alert then attempt to reconnect after disabling ephemeral + Diffie-Hellman. + + Default: 2048 bits + + .. cpp:function:: bool allow_tls10() const + + Return true from here to allow TLS v1.0. Since 2.8.0, returns + ``false`` by default. + + .. cpp:function:: bool allow_tls11() const + + Return true from here to allow TLS v1.1. Since 2.8.0, returns + ``false`` by default. + + .. cpp:function:: bool allow_tls12() const + + Return true from here to allow TLS v1.2. Returns ``true`` by default. + + .. cpp:function:: size_t minimum_rsa_bits() const + + Minimum accepted RSA key size. Default 2048 bits. + + .. cpp:function:: size_t minimum_dsa_group_size() const + + Minimum accepted DSA key size. Default 2048 bits. + + .. cpp:function:: size_t minimum_ecdsa_group_size() const + + Minimum size for ECDSA keys (256 bits). + + .. cpp:function:: size_t minimum_ecdh_group_size() const + + Minimum size for ECDH keys (255 bits). + + .. cpp:function:: void check_peer_key_acceptable(const Public_Key& public_key) const + + Allows the policy to examine peer public keys. Throw an exception + if the key should be rejected. Default implementation checks + against policy values `minimum_dh_group_size`, `minimum_rsa_bits`, + `minimum_ecdsa_group_size`, and `minimum_ecdh_group_size`. + + .. cpp:function:: bool hide_unknown_users() const + + The SRP and PSK suites work using an identifier along with a + shared secret. If this function returns true, when an identifier + that the server does not recognize is provided by a client, a + random shared secret will be generated in such a way that a + client should not be able to tell the difference between the + identifier not being known and the secret being wrong. This can + help protect against some username probing attacks. If it + returns false, the server will instead send an + ``unknown_psk_identity`` alert when an unknown identifier is + used. + + Default: false + + .. cpp:function:: u32bit session_ticket_lifetime() const + + Return the lifetime of session tickets. Each session includes the + start time. Sessions resumptions using tickets older than + ``session_ticket_lifetime`` seconds will fail, forcing a full + renegotiation. + + Default: 86400 seconds (1 day) + +TLS Ciphersuites +---------------------------------------- + +.. cpp:class:: TLS::Ciphersuite + + .. cpp:function:: uint16_t ciphersuite_code() const + + Return the numerical code for this ciphersuite + + .. cpp:function:: std::string to_string() const + + Return the full name of ciphersuite (for example + "RSA_WITH_RC4_128_SHA" or "ECDHE_RSA_WITH_AES_128_GCM_SHA256") + + .. cpp:function:: std::string kex_algo() const + + Return the key exchange algorithm of this ciphersuite + + .. cpp:function:: std::string sig_algo() const + + Return the signature algorithm of this ciphersuite + + .. cpp:function:: std::string cipher_algo() const + + Return the cipher algorithm of this ciphersuite + + .. cpp:function:: std::string mac_algo() const + + Return the authentication algorithm of this ciphersuite + + .. cpp:function:: bool acceptable_ciphersuite(const Ciphersuite& suite) const + + Return true if ciphersuite is accepted by the policy. + + Allows an application to reject any ciphersuites, which are + undesirable for whatever reason without having to reimplement + :cpp:func:`TLS::Ciphersuite::ciphersuite_list` + + .. cpp:function:: std::vector ciphersuite_list(Protocol_Version version, bool have_srp) const + + Return allowed ciphersuites in order of preference + + Allows an application to have full control over ciphersuites + by returning desired ciphersuites in preference order. + +.. _tls_alerts: + +TLS Alerts +---------------------------------------- + +A ``TLS::Alert`` is passed to every invocation of a channel's *alert_cb*. + +.. cpp:class:: TLS::Alert + + .. cpp:function:: is_valid() const + + Return true if this alert is not a null alert + + .. cpp:function:: is_fatal() const + + Return true if this alert is fatal. A fatal alert causes the + connection to be immediately disconnected. Otherwise, the alert + is a warning and the connection remains valid. + + .. cpp:function:: Type type() const + + Returns the type of the alert as an enum + + .. cpp:function:: std::string type_string() + + Returns the type of the alert as a string + +TLS Protocol Version +---------------------------------------- + +TLS has several different versions with slightly different behaviors. +The ``TLS::Protocol_Version`` class represents a specific version: + +.. cpp:class:: TLS::Protocol_Version + + .. cpp:enum:: Version_Code + + ``TLS_V10``, ``TLS_V11``, ``TLS_V12``, ``DTLS_V10``, ``DTLS_V12`` + + .. cpp:function:: Protocol_Version(Version_Code named_version) + + Create a specific version + + .. cpp:function:: uint8_t major_version() const + + Returns major number of the protocol version + + .. cpp:function:: uint8_t minor_version() const + + Returns minor number of the protocol version + + .. cpp:function:: std::string to_string() const + + Returns string description of the version, for instance "TLS + v1.1" or "DTLS v1.0". + + .. cpp:function:: static Protocol_Version latest_tls_version() + + Returns the latest version of the TLS protocol known to the library + (currently TLS v1.2) + + .. cpp:function:: static Protocol_Version latest_dtls_version() + + Returns the latest version of the DTLS protocol known to the + library (currently DTLS v1.2) + +TLS Custom Curves +---------------------------------------- + +The supported_groups TLS extension is used in the client hello to advertise a list of supported elliptic curves +and DH groups. The server subsequently selects one of the groups, which is supported by both endpoints. +The groups are represented by their TLS identifier. This 2 Byte identifier is standardized for commonly used groups and curves. +In addition, the standard reserves the identifiers 0xFE00 to 0xFEFF for custom groups or curves. + +Using non standardized custom curves is however not recommended and can be a serious risk if an +insecure curve is used. Still, it might be desired in some scenarios to use custom curves or groups in the TLS handshake. + +To use custom curves with the Botan :cpp:class:`TLS::Client` or :cpp:class:`TLS::Server` the following additional adjustments have to be implemented +as shown in the following code examples. + +1. Registration of the custom curve +2. Implementation TLS callback ``tls_decode_group_param`` +3. Adjustment of the TLS policy by allowing the custom curve + +Client Code Example +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + + #include + #include + + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls server, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls server, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls server was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + std::string tls_decode_group_param(Botan::TLS::Group_Params group_param) override + { + // handle TLS group identifier decoding and return name as string + // return empty string to indicate decoding failure + + switch(static_cast(group_param)) + { + case 0xFE00: + return "testcurve1102"; + default: + //decode non-custom groups + return Botan::TLS::Callbacks::tls_decode_group_param(group_param); + } + } + }; + + /** + * @brief Credentials storage for the tls client. + * + * It returns a list of trusted CA certificates from a local directory. + * TLS client authentication is disabled. See src/lib/tls/credentials_manager.h. + */ + class Client_Credentials : public Botan::Credentials_Manager + { + public: + std::vector trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // return a list of certificates of CAs we trust for tls server certificates, + // e.g., all the certificates in the local directory "cas" + return { new Botan::Certificate_Store_In_Memory("cas") }; + } + + std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& type, + const std::string& context) override + { + // when using tls client authentication (optional), return + // a certificate chain being sent to the tls server, + // else an empty list + return std::vector(); + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // when returning a chain in cert_chain(), return the private key + // associated with the leaf certificate here + return nullptr; + } + }; + + class Client_Policy : public Botan::TLS::Strict_Policy + { + public: + std::vector key_exchange_groups() const override + { + // modified strict policy to allow our custom curves + return + { + static_cast(0xFE00) + }; + } + }; + + int main() + { + // prepare rng + Botan::AutoSeeded_RNG rng; + + // prepare custom curve + + // prepare curve parameters + const Botan::BigInt p("0x92309a3e88b94312f36891a2055725bb35ab51af96b3a651d39321b7bbb8c51575a76768c9b6b323"); + const Botan::BigInt a("0x4f30b8e311f6b2dce62078d70b35dacb96aa84b758ab5a8dff0c9f7a2a1ff466c19988aa0acdde69"); + const Botan::BigInt b("0x9045A513CFFF9AE1F1CC84039D852D240344A1D5C9DB203C844089F855C387823EB6FCDDF49C909C"); + + const Botan::BigInt x("0x9120f3779a31296cefcb5a5a08831f1a6d438ad5a3f2ce60585ac19c74eebdc65cadb96bb92622c7"); + const Botan::BigInt y("0x836db8251c152dfee071b72c6b06c5387d82f1b5c30c5a5b65ee9429aa2687e8426d5d61276a4ede"); + const Botan::BigInt order("0x248c268fa22e50c4bcda24688155c96ecd6ad46be5c82d7a6be6e7068cb5d1ca72b2e07e8b90d853"); + + const Botan::BigInt cofactor(4); + + const Botan::OID oid("1.2.3.1"); + + // create EC_Group object to register the curve + Botan::EC_Group testcurve1102(p, a, b, x, y, order, cofactor, oid); + + if(!testcurve1102.verify_group(rng)) + { + // Warning: if verify_group returns false the curve parameters are insecure + } + + // register name to specified oid + Botan::OIDS::add_oid(oid, "testcurve1102"); + + // prepare all the parameters + Callbacks callbacks; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Client_Credentials creds; + Client_Policy policy; + + // open the tls connection + Botan::TLS::Client client(callbacks, + session_mgr, + creds, + policy, + rng, + Botan::TLS::Server_Information("botan.randombit.net", 443), + Botan::TLS::Protocol_Version::TLS_V12); + + + while(!client.is_closed()) + { + // read data received from the tls server, e.g., using BSD sockets or boost asio + // ... + + // send data to the tls server using client.send_data() + + } + } + +Server Code Example +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: cpp + + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls client, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls client, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls client was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + + std::string tls_decode_group_param(Botan::TLS::Group_Params group_param) override + { + // handle TLS group identifier decoding and return name as string + // return empty string to indicate decoding failure + + switch(static_cast(group_param)) + { + case 0xFE00: + return "testcurve1102"; + default: + //decode non-custom groups + return Botan::TLS::Callbacks::tls_decode_group_param(group_param); + } + } + }; + + /** + * @brief Credentials storage for the tls server. + * + * It returns a certificate and the associated private key to + * authenticate the tls server to the client. + * TLS client authentication is not requested. + * See src/lib/tls/credentials_manager.h. + */ + class Server_Credentials : public Botan::Credentials_Manager + { + public: + Server_Credentials() : m_key(Botan::PKCS8::load_key("botan.randombit.net.key") + { + } + + std::vector trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // if client authentication is required, this function + // shall return a list of certificates of CAs we trust + // for tls client certificates, otherwise return an empty list + return std::vector(); + } + + std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& type, + const std::string& context) override + { + // return the certificate chain being sent to the tls client + // e.g., the certificate file "botan.randombit.net.crt" + return { Botan::X509_Certificate("botan.randombit.net.crt") }; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // return the private key associated with the leaf certificate, + // in this case the one associated with "botan.randombit.net.crt" + return m_key.get(); + } + + private: + std::unique_ptr m_key; + }; + + class Server_Policy : public Botan::TLS::Strict_Policy + { + public: + std::vector key_exchange_groups() const override + { + // modified strict policy to allow our custom curves + return + { + static_cast(0xFE00) + }; + } + }; + + int main() + { + + // prepare rng + Botan::AutoSeeded_RNG rng; + + // prepare custom curve + + // prepare curve parameters + const Botan::BigInt p("0x92309a3e88b94312f36891a2055725bb35ab51af96b3a651d39321b7bbb8c51575a76768c9b6b323"); + const Botan::BigInt a("0x4f30b8e311f6b2dce62078d70b35dacb96aa84b758ab5a8dff0c9f7a2a1ff466c19988aa0acdde69"); + const Botan::BigInt b("0x9045A513CFFF9AE1F1CC84039D852D240344A1D5C9DB203C844089F855C387823EB6FCDDF49C909C"); + + const Botan::BigInt x("0x9120f3779a31296cefcb5a5a08831f1a6d438ad5a3f2ce60585ac19c74eebdc65cadb96bb92622c7"); + const Botan::BigInt y("0x836db8251c152dfee071b72c6b06c5387d82f1b5c30c5a5b65ee9429aa2687e8426d5d61276a4ede"); + const Botan::BigInt order("0x248c268fa22e50c4bcda24688155c96ecd6ad46be5c82d7a6be6e7068cb5d1ca72b2e07e8b90d853"); + + const Botan::BigInt cofactor(4); + + const Botan::OID oid("1.2.3.1"); + + // create EC_Group object to register the curve + Botan::EC_Group testcurve1102(p, a, b, x, y, order, cofactor, oid); + + if(!testcurve1102.verify_group(rng)) + { + // Warning: if verify_group returns false the curve parameters are insecure + } + + // register name to specified oid + Botan::OIDS::add_oid(oid, "testcurve1102"); + + // prepare all the parameters + Callbacks callbacks; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Server_Credentials creds; + Server_Policy policy; + + // accept tls connection from client + Botan::TLS::Server server(callbacks, + session_mgr, + creds, + policy, + rng); + + // read data received from the tls client, e.g., using BSD sockets or boost asio + // and pass it to server.received_data(). + // ... + + // send data to the tls client using server.send_data() + // ... + } + +TLS Stream +---------------------------------------- + +:cpp:class:`TLS::Stream` offers a Boost.Asio compatible wrapper around :cpp:class:`TLS::Client` and :cpp:class:`TLS::Server`. +It can be used as an alternative to Boost.Asio's `ssl::stream `_ with minor adjustments to the using code. +It offers the following interface: + +.. cpp:class:: template TLS::Stream + + *StreamLayer* specifies the type of the stream's *next layer*, for example a `Boost.Asio TCP socket `_. + *ChannelT* is the type of the stream's *native handle*; it defaults to :cpp:class:`TLS::Channel` and should not be specified manually. + + .. cpp:function:: template \ + explicit Stream(Context& context, Args&& ... args) + + Construct a new TLS stream. + The *context* parameter will be used to initialize the underlying *native handle*, i.e. the :ref:`TLS::Client ` or :ref:`TLS::Server `, when :cpp:func:`handshake` is called. + Using code must ensure the context is kept alive for the lifetime of the stream. + The further *args* will be forwarded to the *next layer*'s constructor. + + .. cpp:function:: template \ + explicit Stream(Arg&& arg, Context& context) + + Convenience constructor for :cpp:class:`boost::asio::ssl::stream` compatibility. + The parameters have the same meaning as for the first constructor, but their order is changed and only one argument can be passed to the *next layer* constructor. + + + .. cpp:function:: void handshake(Connection_Side side, boost::system::error_code& ec) + + Set up the *native handle* and perform the TLS handshake. + + .. cpp:function:: void handshake(Connection_Side side) + + Overload of :cpp:func:`handshake` that throws an exception if an error occurs. + + .. cpp:function:: template \ + DEDUCED async_handshake(Connection_Side side, HandshakeHandler&& handler) + + Asynchronous variant of :cpp:func:`handshake`. + The function returns immediately and calls the *handler* callback function after performing asynchronous I/O to complete the TLS handshake. + The return type is an automatically deduced specialization of :cpp:class:`boost::asio::async_result`, depending on the *HandshakeHandler* type. + + + .. cpp:function:: void shutdown(boost::system::error_code& ec) + + Calls :cpp:func:`TLS::Channel::close` on the native handle and writes the TLS alert to the *next layer*. + + .. cpp:function:: void shutdown() + + Overload of :cpp:func:`shutdown` that throws an exception if an error occurs. + + .. cpp:function:: template \ + void async_shutdown(ShutdownHandler&& handler) + + Asynchronous variant of :cpp:func:`shutdown`. + The function returns immediately and calls the *handler* callback function after performing asynchronous I/O to complete the TLS shutdown. + + + .. cpp:function:: template \ + std::size_t read_some(const MutableBufferSequence& buffers, boost::system::error_code& ec) + + Reads encrypted data from the *next layer*, decrypts it, and writes it into the provided *buffers*. + If an error occurs, *error_code* is set. + Returns the number of bytes read. + + .. cpp:function:: template \ + std::size_t read_some(const MutableBufferSequence& buffers) + + Overload of :cpp:func:`read_some` that throws an exception if an error occurs. + + .. cpp:function:: template \ + DEDUCED async_read_some(const MutableBufferSequence& buffers, ReadHandler&& handler) + + Asynchronous variant of :cpp:func:`read_some`. + The function returns immediately and calls the *handler* callback function after writing the decrypted data into the provided *buffers*. + The return type is an automatically deduced specialization of :cpp:class:`boost::asio::async_result`, depending on the *ReadHandler* type. + *ReadHandler* should suffice the `requirements to a Boost.Asio read handler `_. + + + .. cpp:function:: template \ + std::size_t write_some(const ConstBufferSequence& buffers, boost::system::error_code& ec) + + Encrypts data from the provided *buffers* and writes it to the *next layer*. + If an error occurs, *error_code* is set. + Returns the number of bytes written. + + .. cpp:function:: template \ + std::size_t write_some(const ConstBufferSequence& buffers) + + Overload of :cpp:func:`write_some` that throws an exception rather than setting an error code. + + .. cpp:function:: template \ + DEDUCED async_write_some(const ConstBufferSequence& buffers, WriteHandler&& handler) + + Asynchronous variant of :cpp:func:`write_some`. + The function returns immediately and calls the *handler* callback function after writing the encrypted data to the *next layer*. + The return type is an automatically deduced specialization of :cpp:class:`boost::asio::async_result`, depending on the *WriteHandler* type. + *WriteHandler* should suffice the `requirements to a Boost.Asio write handler `_. + +.. cpp:class:: TLS::Context + + A helper class to initialize and configure the Stream's underlying *native handle* (see :cpp:class:`TLS::Client` and :cpp:class:`TLS::Server`). + + .. cpp:function:: Context(Credentials_Manager& credentialsManager, \ + RandomNumberGenerator& randomNumberGenerator, \ + Session_Manager& sessionManager, \ + Policy& policy, \ + Server_Information serverInfo = Server_Information()) + + Constructor for TLS::Context. + + .. cpp:function:: void set_verify_callback(Verify_Callback_T callback) + + Set a user-defined callback function for certificate chain verification. This + will cause the stream to override the default implementation of the + :cpp:func:`tls_verify_cert_chain` callback. + +TLS Stream Client Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The code below illustrates how to build a simple HTTPS client based on the TLS Stream and Boost.Beast. When run, it fetches the content of `https://botan.randombit.net/news.html` and prints it to stdout. + +.. code-block:: cpp + + #include + + #include + #include + #include + + #include + #include + #include + + namespace http = boost::beast::http; + namespace _ = boost::asio::placeholders; + + // very basic credentials manager + class Credentials_Manager : public Botan::Credentials_Manager + { + public: + Credentials_Manager() {} + + std::vector + trusted_certificate_authorities(const std::string&, const std::string&) override + { + return {&cert_store_}; + } + + private: + Botan::System_Certificate_Store cert_store_; + }; + + // a simple https client based on TLS::Stream + class client + { + public: + client(boost::asio::io_context& io_context, + boost::asio::ip::tcp::resolver::iterator endpoint_iterator, + http::request req) + : request_(req) + , ctx_(credentials_mgr_, + rng_, + session_mgr_, + policy_, + Botan::TLS::Server_Information()) + , stream_(io_context, ctx_) + { + boost::asio::async_connect(stream_.lowest_layer(), endpoint_iterator, + boost::bind(&client::handle_connect, this, _::error)); + } + + void handle_connect(const boost::system::error_code& error) + { + if(error) + { + std::cout << "Connect failed: " << error.message() << "\n"; + return; + } + stream_.async_handshake(Botan::TLS::Connection_Side::CLIENT, + boost::bind(&client::handle_handshake, this, _::error)); + } + + void handle_handshake(const boost::system::error_code& error) + { + if(error) + { + std::cout << "Handshake failed: " << error.message() << "\n"; + return; + } + http::async_write(stream_, request_, + boost::bind(&client::handle_write, this, _::error, _::bytes_transferred)); + } + + void handle_write(const boost::system::error_code& error, size_t) + { + if(error) + { + std::cout << "Write failed: " << error.message() << "\n"; + return; + } + http::async_read(stream_, reply_, response_, + boost::bind(&client::handle_read, this, _::error, _::bytes_transferred)); + } + + void handle_read(const boost::system::error_code& error, size_t) + { + if(!error) + { + std::cout << "Reply: "; + std::cout << response_.body() << "\n"; + } + else + { + std::cout << "Read failed: " << error.message() << "\n"; + } + } + + private: + http::request request_; + http::response response_; + boost::beast::flat_buffer reply_; + + Botan::TLS::Session_Manager_Noop session_mgr_; + Botan::AutoSeeded_RNG rng_; + Credentials_Manager credentials_mgr_; + Botan::TLS::Policy policy_; + + Botan::TLS::Context ctx_; + Botan::TLS::Stream stream_; + }; + + int main() + { + boost::asio::io_context io_context; + + boost::asio::ip::tcp::resolver resolver(io_context); + boost::asio::ip::tcp::resolver::query query("botan.randombit.net", "443"); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + + http::request req; + req.version(11); + req.method(http::verb::get); + req.target("/news.html"); + req.set(http::field::host, "botan.randombit.net"); + + client c(io_context, iterator, req); + + io_context.run(); + } + +.. _tls_session_encryption: + +TLS Session Encryption +------------------------- + +A unified format is used for encrypting TLS sessions either for durable storage +(on client or server) or when creating TLS session tickets. This format is *not +stable* even across the same major version. + +The current session encryption scheme was introduced in 2.13.0, replacing the +format previously used since 1.11.13. + +Session encryption accepts a key of any length, though for best security a key +of 256 bits should be used. This master key is used to key an instance of HMAC +using the SHA-512/256 hash. + +First a "key name" or identifier is created, by HMAC'ing the fixed string "BOTAN +TLS SESSION KEY NAME" and truncating to 4 bytes. This is the initial prefix of +the encrypted session, and will remain fixed as long as the same ticket key is +used. This allows quickly rejecting sessions which are encrypted using an +unknown or incorrect key. + +Then a key used for AES-256 in GCM mode is created by first choosing a 128 bit +random seed, and HMAC'ing it to produce a 256-bit value. This means for any one +master key as many as 2\ :sup:`128` GCM keys can be created. This is done +because NIST recommends that when using random nonces no one GCM key be used to +encrypt more than 2\ :sup:`32` messages (to avoid the possiblity of nonce +reuse). + +A random 96-bit nonce is created and included in the header. + +AES in GCM is used to encrypt and authenticate the serialized session. The +key name, key seed, and AEAD nonce are all included as additional data. diff --git a/comm/third_party/botan/doc/api_ref/tpm.rst b/comm/third_party/botan/doc/api_ref/tpm.rst new file mode 100644 index 0000000000..7598c4bd81 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/tpm.rst @@ -0,0 +1,113 @@ +Trusted Platform Module (TPM) +========================================== + +.. versionadded:: 1.11.26 + +Some computers come with a TPM, which is a small side processor which can +perform certain operations which include RSA key generation and signing, a +random number generator, accessing a small amount of NVRAM, and a set of PCRs +which can be used to measure software state (this is TPMs most famous use, for +authenticating a boot sequence). + +The TPM NVRAM and PCR APIs are not supported by Botan at this time, patches welcome. + +Currently only v1.2 TPMs are supported, and the only TPM library supported is +TrouSerS (http://trousers.sourceforge.net/). Hopefully both of these limitations +will be removed in a future release, in order to support newer TPM v2.0 systems. +The current code has been tested with an ST TPM running in a Lenovo laptop. + +Test for TPM support with the macro ``BOTAN_HAS_TPM``, include ````. + +First, create a connection to the TPM with a ``TPM_Context``. The context is +passed to all other TPM operations, and should remain alive as long as any other +TPM object which the context was passed to is still alive, otherwise errors or +even an application crash are possible. In the future, the API may change to +using ``shared_ptr`` to remove this problem. + +.. cpp:class:: TPM_Context + + .. cpp:function:: TPM_Context(pin_cb cb, const char* srk_password) + + The (somewhat improperly named) pin_cb callback type takes a std::string as + an argument, which is an informative message for the user. It should return + a string containing the password entered by the user. + + Normally the SRK password is null. Use nullptr to signal this. + +The TPM contains a RNG of unknown design or quality. If that doesn't scare you +off, you can use it with ``TPM_RNG`` which implements the standard +``RandomNumberGenerator`` interface. + +.. cpp:class:: TPM_RNG + + .. cpp:function:: TPM_RNG(TPM_Context& ctx) + + Initialize a TPM RNG object. After initialization, reading from + this RNG reads from the hardware? RNG on the TPM. + +The v1.2 TPM uses only RSA, but because this key is implemented completely in +hardware it uses a different private key type, with a somewhat different API to +match the TPM's behavior. + +.. cpp:class:: TPM_PrivateKey + + .. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, size_t bits, const char* key_password) + + Create a new RSA key stored on the TPM. The bits should be either 1024 + or 2048; the TPM interface hypothetically allows larger keys but in + practice no v1.2 TPM hardware supports them. + + The TPM processor is not fast, be prepared for this to take a while. + + The key_password is the password to the TPM key ? + + .. cpp:function:: std::string register_key(TPM_Storage_Type storage_type) + + Registers a key with the TPM. The storage_type can be either + `TPM_Storage_Type::User` or `TPM_Storage_Type::System`. If System, the + key is stored on the TPM itself. If User, it is stored on the local hard + drive in a database maintained by an intermediate piece of system + software (which actual interacts with the physical TPM on behalf of any + number of applications calling the TPM API). + + The TPM has only some limited space to store private keys and may reject + requests to store the key. + + In either case the key is encrypted with an RSA key which was generated + on the TPM and which it will not allow to be exported. Thus (so goes the + theory) without physically attacking the TPM + + Returns a UUID which can be passed back to constructor below. + + .. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, const std::string& uuid, \ + TPM_Storage_Type storage_type) + + Load a registered key. The UUID was returned by the ``register_key`` function. + + .. cpp:function:: std::vector export_blob() const + + Export the key as an encrypted blob. This blob can later be presented + back to the same TPM to load the key. + + .. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, const std::vector& blob) + + Load a TPM key previously exported as a blob with ``export_blob``. + + .. cpp:function:: std::unique_ptr public_key() const + + Return the public key associated with this TPM private key. + + TPM does not store public keys, nor does it support signature verification. + + .. cpp:function:: TSS_HKEY handle() const + + Returns the bare TSS key handle. Use if you need to call the raw TSS API. + +A ``TPM_PrivateKey`` can be passed to a ``PK_Signer`` constructor and used to +sign messages just like any other key. Only PKCS #1 v1.5 signatures are supported +by the v1.2 TPM. + +.. cpp:function:: std::vector TPM_PrivateKey::registered_keys(TPM_Context& ctx) + + This static function returns the list of all keys (in URL format) + registered with the system diff --git a/comm/third_party/botan/doc/api_ref/tss.rst b/comm/third_party/botan/doc/api_ref/tss.rst new file mode 100644 index 0000000000..947b835d0a --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/tss.rst @@ -0,0 +1,45 @@ +Threshold Secret Sharing +======================================== + +.. versionadded:: 1.9.1 + +Threshold secret sharing allows splitting a secret into ``N`` shares such that +``M`` (for specified ``M`` <= ``N``) is sufficient to recover the secret, but an +attacker with ``M - 1`` shares cannot derive any information about the secret. + +The implementation in Botan follows an expired Internet draft +"draft-mcgrew-tss-03". Several other implementations of this TSS format exist. + +.. cpp:class:: RTSS_Share + + .. cpp:function:: static std::vector split(uint8_t M, uint8_t N, \ + const uint8_t secret[], uint16_t secret_len, \ + const std::vector& identifier, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + + Split a secret. The identifier is an optional key identifier which may be + up to 16 bytes long. Shorter identifiers are padded with zeros. + + The hash function must be either "SHA-1", "SHA-256", or "None" to disable + the checksum. + + This will return a vector of length ``N``, any ``M`` of these shares is + sufficient to reconstruct the data. + + .. cpp:function:: static secure_vector reconstruct(const std::vector& shares) + + Given a sufficient number of shares, reconstruct a secret. + + .. cpp:function:: RTSS_Share(const uint8_t data[], size_t len) + + Read a TSS share as a sequence of bytes. + + .. cpp:function:: const secure_vector& data() const + + Return the data of this share. + + .. cpp:function:: uint8_t share_id() const + + Return the share ID which will be in the range 1...255 + diff --git a/comm/third_party/botan/doc/api_ref/versions.rst b/comm/third_party/botan/doc/api_ref/versions.rst new file mode 100644 index 0000000000..511141b75f --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/versions.rst @@ -0,0 +1,100 @@ + +Versioning +======================================== + +All versions are of the tuple (major,minor,patch). + +As of Botan 2.0.0, Botan uses semantic versioning. The minor number increases if +any feature addition is made. The patch version is used to indicate a release +where only bug fixes were applied. If an incompatible API change is required, +the major version will be increased. + +The library has functions for checking compile-time and runtime versions. + +The build-time version information is defined in `botan/build.h` + +.. c:macro:: BOTAN_VERSION_MAJOR + + The major version of the release. + +.. c:macro:: BOTAN_VERSION_MINOR + + The minor version of the release. + +.. c:macro:: BOTAN_VERSION_PATCH + + The patch version of the release. + +.. c:macro:: BOTAN_VERSION_DATESTAMP + + Expands to an integer of the form YYYYMMDD if this is an official + release, or 0 otherwise. For instance, 1.10.1, which was released + on July 11, 2011, has a `BOTAN_VERSION_DATESTAMP` of 20110711. + +.. c:macro:: BOTAN_DISTRIBUTION_INFO + + .. versionadded:: 1.9.3 + + A macro expanding to a string that is set at build time using the + ``--distribution-info`` option. It allows a packager of the library + to specify any distribution-specific patches. If no value is given + at build time, the value is the string "unspecified". + +.. c:macro:: BOTAN_VERSION_VC_REVISION + + .. versionadded:: 1.10.1 + + A macro expanding to a string that is set to a revision identifier + corresponding to the source, or "unknown" if this could not be + determined. It is set for all official releases, and for builds that + originated from within a git checkout. + +The runtime version information, and some helpers for compile time +version checks, are included in `botan/version.h` + +.. cpp:function:: std::string version_string() + + Returns a single-line string containing relevant information about + this build and version of the library in an unspecified format. + +.. cpp:function:: uint32_t version_major() + + Returns the major part of the version. + +.. cpp:function:: uint32_t version_minor() + + Returns the minor part of the version. + +.. cpp:function:: uint32_t version_patch() + + Returns the patch part of the version. + +.. cpp:function:: uint32_t version_datestamp() + + Return the datestamp of the release (or 0 if the current version is + not an official release). + +.. cpp:function:: std::string runtime_version_check(uint32_t major, uint32_t minor, uint32_t patch) + + Call this function with the compile-time version being built against, eg:: + + Botan::runtime_version_check(BOTAN_VERSION_MAJOR, BOTAN_VERSION_MINOR, BOTAN_VERSION_PATCH) + + It will return an empty string if the versions match, or otherwise + an error message indicating the discrepancy. This only is useful in + dynamic libraries, where it is possible to compile and run against + different versions. + +.. c:macro:: BOTAN_VERSION_CODE_FOR(maj,min,patch) + + Return a value that can be used to compare versions. The current + (compile-time) version is available as the macro + `BOTAN_VERSION_CODE`. For instance, to choose one code path for + version 2.1.0 and later, and another code path for older releases:: + + #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,1,0) + // 2.1+ code path + #else + // code path for older versions + #endif + diff --git a/comm/third_party/botan/doc/api_ref/x509.rst b/comm/third_party/botan/doc/api_ref/x509.rst new file mode 100644 index 0000000000..cbf3d531e1 --- /dev/null +++ b/comm/third_party/botan/doc/api_ref/x509.rst @@ -0,0 +1,914 @@ +.. _x509_certificates: + +X.509 Certificates and CRLs +================================= + +A certificate is a binding between some identifying information +(called a *subject*) and a public key. This binding is asserted by a +signature on the certificate, which is placed there by some authority +(the *issuer*) that at least claims that it knows the subject named in +the certificate really "owns" the private key corresponding to the +public key in the certificate. + +The major certificate format in use today is X.509v3, used for instance in the +:doc:`tls` protocol. A X.509 certificate is represented by the class +``X509_Certificate``. The data of an X.509 certificate is stored as a +``shared_ptr`` to a structure containing the decoded information. So copying +``X509_Certificate`` objects is quite cheap. + + +.. cpp:class:: X509_Certificate + + .. cpp:function:: X509_Certificate(const std::string& filename) + + Load a certificate from a file. PEM or DER is accepted. + + .. cpp:function:: X509_Certificate(const std::vector& in) + + Load a certificate from a byte string. + + .. cpp:function:: X509_Certificate(DataSource& source) + + Load a certificate from an abstract ``DataSource``. + + .. cpp:function:: X509_DN subject_dn() const + + Returns the distinguished name (DN) of the certificate's subject. This is + the primary place where information about the subject of the certificate is + stored. However "modern" information that doesn't fit in the X.500 + framework, such as DNS name, email, IP address, or XMPP address, appears + instead in the subject alternative name. + + .. cpp:function:: X509_DN issuer_dn() const + + Returns the distinguished name (DN) of the certificate's issuer, ie the CA + that issued this certificate. + + .. cpp:function:: const AlternativeName& subject_alt_name() const + + Return the subjects alternative name. This is used to store + values like associated URIs, DNS addresses, and email addresses. + + .. cpp:function:: const AlternativeName& issuer_alt_name() const + + Return alternative names for the issuer. + + .. cpp:function:: std::unique_ptr load_subject_public_key() const + + Deserialize the stored public key and return a new object. This + might throw, if it happens that the public key object stored in + the certificate is malformed in some way, or in the case that the + public key algorithm used is not supported by the library. + + See :ref:`serializing_public_keys` for more information about what to do + with the returned object. It may be any type of key, in principle, though + RSA and ECDSA are most common. + + .. cpp:function:: std::vector subject_public_key_bits() const + + Return the binary encoding of the subject public key. This value (or a hash of + it) is used in various protocols, eg for public key pinning. + + .. cpp:function:: AlgorithmIdentifier subject_public_key_algo() const + + Return an algorithm identifier that identifies the algorithm used in the + subject's public key. + + .. cpp:function:: std::vector serial_number() const + + Return the certificates serial number. The tuple of issuer DN and + serial number should be unique. + + .. cpp:function:: std::vector raw_subject_dn() const + + Return the binary encoding of the subject DN. + + .. cpp:function:: std::vector raw_issuer_dn() const + + Return the binary encoding of the issuer DN. + + .. cpp:function:: X509_Time not_before() const + + Returns the point in time the certificate becomes valid + + .. cpp:function:: X509_Time not_after() const + + Returns the point in time the certificate expires + + .. cpp:function:: const Extensions& v3_extensions() const + + Returns all extensions of this certificate. You can use this + to examine any extension data associated with the certificate, + including custom extensions the library doesn't know about. + + .. cpp:function:: std::vector authority_key_id() const + + Return the authority key id, if set. This is an arbitrary string; in the + issuing certificate this will be the subject key id. + + .. cpp:function:: std::vector subject_key_id() const + + Return the subject key id, if set. + + .. cpp:function:: bool allowed_extended_usage(const OID& usage) const + + Return true if and only if the usage OID appears in the extended key usage + extension. Also will return true if the extended key usage extension is + not used in the current certificate. + + .. cpp:function:: std::vector extended_key_usage() const + + Return the list of extended key usages. May be empty. + + .. cpp:function:: std::string fingerprint(const std::string& hash_fn = "SHA-1") const + + Return a fingerprint for the certificate, which is basically just a hash + of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash + function is allowed. + + .. cpp:function:: Key_Constraints constraints() const + + Returns either an enumeration listing key constraints (what the + associated key can be used for) or ``NO_CONSTRAINTS`` if the + relevant extension was not included. Example values are + ``DIGITAL_SIGNATURE`` and ``KEY_CERT_SIGN``. More than one value + might be specified. + + .. cpp:function:: bool matches_dns_name(const std::string& name) const + + Check if the certificate's subject alternative name DNS fields + match ``name``. This function also handles wildcard certificates. + + .. cpp:function:: std::string to_string() const + + Returns a free-form human readable string describing the certificate. + + .. cpp:function:: std::string PEM_encode() const + + Returns the PEM encoding of the certificate + + .. cpp:function:: std::vector BER_encode() const + + Returns the DER/BER encoding of the certificate + +X.509 Distinguished Names +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. cpp:class:: X509_DN + + .. cpp:function:: bool has_field(const std::string& attr) const + + Returns true if ``get_attribute`` or ``get_first_attribute`` will return a value. + + .. cpp:function:: std::vector get_attribute(const std::string& attr) const + + Return all attributes associated with a certain attribute type. + + .. cpp:function:: std::string get_first_attribute(const std::string& attr) const + + Like ``get_attribute`` but returns just the first attribute, or + empty if the DN has no attribute of the specified type. + + .. cpp:function:: std::multimap get_attributes() const + + Get all attributes of the DN. The OID maps to a DN component such as + 2.5.4.10 ("Organization"), and the strings are UTF-8 encoded. + + .. cpp:function:: std::multimap contents() const + + Similar to ``get_attributes``, but the OIDs are decoded to strings. + + .. cpp:function:: void add_attribute(const std::string& key, const std::string& val) + + Add an attribute to a DN. + + .. cpp:function:: void add_attribute(const OID& oid, const std::string& val) + + Add an attribute to a DN using an OID instead of string-valued attribute type. + +The ``X509_DN`` type also supports iostream extraction and insertion operators, +for formatted input and output. + +X.509v3 Extensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +X.509v3 specifies a large number of possible extensions. Botan supports some, +but by no means all of them. The following listing lists which X.509v3 +extensions are supported and notes areas where there may be problems with the +handling. + + - Key Usage and Extended Key Usage: No problems known. + + - Basic Constraints: No problems known. A self-signed v1 certificate + is assumed to be a CA, while a v3 certificate is marked as a CA if + and only if the basic constraints extension is present and set for + a CA cert. + + - Subject Alternative Names: Only the "rfc822Name", "dNSName", and + "uniformResourceIdentifier" and raw IPv4 fields will be stored; all + others are ignored. + + - Issuer Alternative Names: Same restrictions as the Subject + Alternative Names extension. New certificates generated by Botan + never include the issuer alternative name. + + - Authority Key Identifier: Only the version using KeyIdentifier is + supported. If the GeneralNames version is used and the extension is + critical, an exception is thrown. If both the KeyIdentifier and GeneralNames + versions are present, then the KeyIdentifier will be used, and the + GeneralNames ignored. + + - Subject Key Identifier: No problems known. + + - Name Constraints: No problems known (though encoding is not supported). + +Any unknown critical extension in a certificate will lead to an +exception during path validation. + +Extensions are handled by a special class taking care of encoding +and decoding. It also supports encoding and decoding of custom extensions. +To do this, it internally keeps two lists of extensions. Different lookup +functions are provided to search them. + +.. note:: + + Validation of custom extensions during path validation is currently not supported. + +.. cpp:class:: Extensions + + .. cpp:function:: void add(Certificate_Extension* extn, bool critical = false) + + Adds a new extension to the extensions object. If an extension of the same + type already exists, ``extn`` will replace it. If ``critical`` is true the + extension will be marked as critical in the encoding. + + .. cpp:function:: bool add_new(Certificate_Extension* extn, bool critical = false) + + Like ``add`` but an existing extension will not be replaced. Returns true if the + extension was used, false if an extension of the same type was already in place. + + .. cpp:function:: void replace(Certificate_Extension* extn, bool critical = false) + + Adds an extension to the list or replaces it, if the same + extension was already added + + .. cpp:function:: std::unique_ptr get(const OID& oid) const + + Searches for an extension by OID and returns the result + + .. cpp:function:: template \ + std::unique_ptr get_raw(const OID& oid) + + Searches for an extension by OID and returns the result. + Only the unknown extensions, that is, extensions types that are not + listed above, are searched for by this function. + + .. cpp:function:: std::vector, bool>> extensions() const + + Returns the list of extensions together with the corresponding + criticality flag. Only contains the supported extension types + listed above. + + .. cpp:function:: std::map, bool>> extensions_raw() const + + Returns the list of extensions as raw, encoded bytes + together with the corresponding criticality flag. + Contains all extensions, known as well as unknown extensions. + +Certificate Revocation Lists +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It will occasionally happen that a certificate must be revoked before +its expiration date. Examples of this happening include the private +key being compromised, or the user to which it has been assigned +leaving an organization. Certificate revocation lists are an answer to +this problem (though online certificate validation techniques are +starting to become somewhat more popular). Every once in a while the +CA will release a new CRL, listing all certificates that have been +revoked. Also included is various pieces of information like what time +a particular certificate was revoked, and for what reason. In most +systems, it is wise to support some form of certificate revocation, +and CRLs handle this easily. + +For most users, processing a CRL is quite easy. All you have to do is +call the constructor, which will take a filename (or a +``DataSource&``). The CRLs can either be in raw BER/DER, or in PEM +format; the constructor will figure out which format without any extra +information. For example:: + + X509_CRL crl1("crl1.der"); + + DataSource_Stream in("crl2.pem"); + X509_CRL crl2(in); + +After that, pass the ``X509_CRL`` object to a ``Certificate_Store`` object +with + +.. cpp:function:: void Certificate_Store::add_crl(const X509_CRL& crl) + +and all future verifications will take into account the provided CRL. + +Certificate Stores +---------------------------------------- + +An object of type ``Certificate_Store`` is a generalized interface to +an external source for certificates (and CRLs). Examples of such a +store would be one that looked up the certificates in a SQL database, +or by contacting a CGI script running on a HTTP server. There are +currently three mechanisms for looking up a certificate, and one for +retrieving CRLs. By default, most of these mechanisms will return an +empty ``std::shared_ptr`` of ``X509_Certificate``. This storage mechanism +is *only* queried when doing certificate validation: it allows you to +distribute only the root key with an application, and let some online +method handle getting all the other certificates that are needed to +validate an end entity certificate. In particular, the search routines +will not attempt to access the external database. + +The certificate lookup methods are ``find_cert`` (by Subject +Distinguished Name and optional Subject Key Identifier) and +``find_cert_by_pubkey_sha1`` (by SHA-1 hash of the certificate's +public key). The Subject Distinguished Name is given as a ``X509_DN``, +while the SKID parameter takes a ``std::vector`` containing +the subject key identifier in raw binary. Both lookup methods are +mandatory to implement. + +Finally, there is a method for finding a CRL, called ``find_crl_for``, +that takes an ``X509_Certificate`` object, and returns a +``std::shared_ptr`` of ``X509_CRL``. The ``std::shared_ptr`` return +type makes it easy to return no CRLs by returning ``nullptr`` +(eg, if the certificate store doesn't support retrieving CRLs). +Implementing the function is optional, and by default will return +``nullptr``. + +Certificate stores are used in the :doc:`tls` module to store a +list of trusted certificate authorities. + +In Memory Certificate Store +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The in memory certificate store keeps all objects in memory only. +Certificates can be loaded from disk initially, but also added +later. + +.. cpp:class:: Certificate_Store_In_Memory + + .. cpp:function:: Certificate_Store_In_Memory(const std::string& dir) + + Attempt to parse all files in ``dir`` (including subdirectories) + as certificates. Ignores errors. + + .. cpp:function:: Certificate_Store_In_Memory(const X509_Certificate& cert) + + Adds given certificate to the store + + .. cpp:function:: Certificate_Store_In_Memory() + + Create an empty store + + .. cpp:function:: void add_certificate(const X509_Certificate& cert) + + Add a certificate to the store + + .. cpp:function:: void add_certificate(std::shared_ptr cert) + + Add a certificate already in a shared_ptr to the store + + .. cpp:function:: void add_crl(const X509_CRL& crl) + + Add a certificate revocation list (CRL) to the store. + + .. cpp:function:: void add_crl(std::shared_ptr crl) + + Add a certificate revocation list (CRL) to the store as a shared_ptr + +SQL-backed Certificate Stores +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The SQL-backed certificate stores store all objects in an SQL database. They +also additionally provide private key storage and revocation of individual +certificates. + +.. cpp:class:: Certificate_Store_In_SQL + + .. cpp:function:: Certificate_Store_In_SQL(const std::shared_ptr db, \ + const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "") + + Create or open an existing certificate store from an SQL database. + The password in ``passwd`` will be used to encrypt private keys. + + .. cpp:function:: bool insert_cert(const X509_Certificate& cert) + + Inserts ``cert`` into the store. Returns `false` if the certificate is + already known and `true` if insertion was successful. + + .. cpp:function:: remove_cert(const X509_Certificate& cert) + + Removes ``cert`` from the store. Returns `false` if the certificate could not + be found and `true` if removal was successful. + + .. cpp:function:: std::shared_ptr find_key(const X509_Certificate&) const + + Returns the private key for "cert" or an empty shared_ptr if none was found + + .. cpp:function:: std::vector> \ + find_certs_for_key(const Private_Key& key) const + + Returns all certificates for private key ``key`` + + .. cpp:function:: bool insert_key(const X509_Certificate& cert, const Private_Key& key) + + Inserts ``key`` for ``cert`` into the store, returns `false` if the key is + already known and `true` if insertion was successful. + + .. cpp:function:: void remove_key(const Private_Key& key) + + Removes ``key`` from the store + + .. cpp:function:: void revoke_cert(const X509_Certificate&, CRL_Code, \ + const X509_Time& time = X509_Time()) + + Marks ``cert`` as revoked starting from ``time`` + + .. cpp:function:: void affirm_cert(const X509_Certificate&) + + Reverses the revocation for ``cert`` + + .. cpp:function:: std::vector generate_crls() const + + Generates CRLs for all certificates marked as revoked. + A CRL is returned for each unique issuer DN. + +The ``Certificate_Store_In_SQL`` class operates on an abstract ``SQL_Database`` +object. If support for sqlite3 was enabled at build time, Botan includes an +implementation of this interface for sqlite3, and a subclass of +``Certificate_Store_In_SQL`` which creates or opens a sqlite3 database. + +.. cpp:class:: Certificate_Store_In_SQLite + + .. cpp:function:: Certificate_Store_In_SQLite(const std::string& db_path, \ + const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "") + + Create or open an existing certificate store from an sqlite database file. + The password in ``passwd`` will be used to encrypt private keys. + +Path Validation +---------------------------------------- + +The process of validating a certificate chain up to a trusted root is +called `path validation`, and in botan that operation is handled by a +set of functions in ``x509path.h`` named ``x509_path_validate``: + +.. cpp:function:: Path_Validation_Result \ + x509_path_validate(const X509_Certificate& end_cert, \ + const Path_Validation_Restrictions& restrictions, \ + const Certificate_Store& store, const std::string& hostname = "", \ + Usage_Type usage = Usage_Type::UNSPECIFIED, \ + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), \ + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), \ + const std::vector>& ocsp_resp = std::vector>()) + + The last five parameters are optional. ``hostname`` specifies a hostname which is + matched against the subject DN in ``end_cert`` according to RFC 6125. + An empty hostname disables hostname validation. + ``usage`` specifies key usage restrictions that are compared + to the key usage fields in `end_cert` according to RFC 5280, if not set to + ``UNSPECIFIED``. ``validation_time`` allows setting the time point at which all certificates + are validated. This is really only useful for testing. The default is the + current system clock's current time. ``ocsp_timeout`` sets the timeout for + OCSP requests. The default of 0 disables OCSP checks completely. + ``ocsp_resp`` allows adding additional OCSP responses retrieved from outside + of the path validation. Note that OCSP online checks are done only + as long as the http_util module was compiled in. Availability of online + OCSP checks can be checked using the macro BOTAN_HAS_ONLINE_REVOCATION_CHECKS. + + For the different flavors of ``x509_path_validate``, check ``x509path.h``. + +The result of the validation is returned as a class: + +.. cpp:class:: Path_Validation_Result + + Specifies the result of the validation + + .. cpp:function:: bool successful_validation() const + + Returns true if a certificate path from *end_cert* to a trusted + root was found and all path validation checks passed. + + .. cpp:function:: std::string result_string() const + + Returns a descriptive string of the validation status (for + instance "Verified", "Certificate is not yet valid", or + "Signature error"). This is the string value of + the `result` function below. + + .. cpp:function:: const X509_Certificate& trust_root() const + + If the validation was successful, returns the certificate which + is acting as the trust root for *end_cert*. + + .. cpp:function:: const std::vector& cert_path() const + + Returns the full certificate path starting with the end entity + certificate and ending in the trust root. + + .. cpp:function:: Certificate_Status_Code result() const + + Returns the 'worst' error that occurred during validation. For + instance, we do not want an expired certificate with an invalid + signature to be reported to the user as being simply expired (a + relatively innocuous and common error) when the signature isn't + even valid. + + .. cpp:function:: const std::vector>& all_statuses() const + + For each certificate in the chain, returns a set of status which + indicate all errors which occurred during validation. This is + primarily useful for diagnostic purposes. + + .. cpp:function:: std::set trusted_hashes() const + + Returns the set of all cryptographic hash functions which are + implicitly trusted for this validation to be correct. + + +A ``Path_Validation_Restrictions`` is passed to the path +validator and specifies restrictions and options for the validation +step. The two constructors are: + + .. cpp:function:: Path_Validation_Restrictions(bool require_rev, \ + size_t minimum_key_strength, \ + bool ocsp_all_intermediates, \ + const std::set& trusted_hashes) + + If `require_rev` is true, then any path without revocation + information (CRL or OCSP check) is rejected with the code + `NO_REVOCATION_DATA`. The `minimum_key_strength` parameter + specifies the minimum strength of public key signature we will + accept is. The set of hash names `trusted_hashes` indicates which + hash functions we'll accept for cryptographic signatures. Any + untrusted hash will cause the error case `UNTRUSTED_HASH`. + + .. cpp:function:: Path_Validation_Restrictions(bool require_rev = false, \ + size_t minimum_key_strength = 80, \ + bool ocsp_all_intermediates = false) + + A variant of the above with some convenient defaults. The current + default `minimum_key_strength` of 80 roughly corresponds to 1024 + bit RSA. The set of trusted hashes is set to all SHA-2 variants, + and, if `minimum_key_strength` is less than or equal to 80, then + SHA-1 signatures will also be accepted. + +Creating New Certificates +--------------------------------- + +A CA is represented by the type ``X509_CA``, which can be found in +``x509_ca.h``. A CA always needs its own certificate, which can either +be a self-signed certificate (see below on how to create one) or one +issued by another CA (see the section on PKCS #10 requests). Creating +a CA object is done by the following constructor: + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + +The private ``key`` is the private key corresponding to the public key in the +CA's certificate. ``hash_fn`` is the name of the hash function to use +for signing, e.g., `SHA-256`. ``rng`` is queried for random during signing. + +There is an alternative constructor that lets you set additional options, namely +the padding scheme that will be used by the X509_CA object to sign certificates +and certificate revocation lists. If the padding is not set explicitly, the CA +will use the padding scheme that was used when signing the CA certificate. + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key, \ + const std::map& opts, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + +The only option valid at this moment is "padding". The supported padding schemes +can be found in src/lib/pubkey/padding.cpp. Some alternative names for the +padding schemes are understood, as well. + +Requests for new certificates are supplied to a CA in the form of PKCS +#10 certificate requests (called a ``PKCS10_Request`` object in +Botan). These are decoded in a similar manner to +certificates/CRLs/etc. A request is vetted by humans (who somehow +verify that the name in the request corresponds to the name of the +entity who requested it), and then signed by a CA key, generating a +new certificate: + +.. cpp:function:: X509_Certificate \ + X509_CA::sign_request(const PKCS10_Request& req, \ + RandomNumberGenerator& rng, \ + const X509_Time& not_before, \ + const X509_Time& not_after) + +Generating CRLs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As mentioned previously, the ability to process CRLs is highly +important in many PKI systems. In fact, according to strict X.509 +rules, you must not validate any certificate if the appropriate CRLs +are not available (though hardly any systems are that strict). In any +case, a CA should have a valid CRL available at all times. + +Of course, you might be wondering what to do if no certificates have +been revoked. Never fear; empty CRLs, which revoke nothing at all, can +be issued. To generate a new, empty CRL, just call + +.. cpp:function:: X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, \ + uint32_t next_update = 0) + + This function will return a new, empty CRL. The ``next_update`` parameter is + the number of seconds before the CRL expires. If it is set to the (default) + value of zero, then a reasonable default (currently 7 days) will be used. + +On the other hand, you may have issued a CRL before. In that case, you will +want to issue a new CRL that contains all previously revoked +certificates, along with any new ones. This is done by calling + +.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, \ + std::vector new_entries, RandomNumberGenerator& rng, \ + size_t next_update = 0) + + Where ``last_crl`` is the last CRL this CA issued, and + ``new_entries`` is a list of any newly revoked certificates. The + function returns a new ``X509_CRL`` to make available for + clients. + +The ``CRL_Entry`` type is a structure that contains, at a minimum, the serial +number of the revoked certificate. As serial numbers are never repeated, the +pairing of an issuer and a serial number (should) distinctly identify any +certificate. In this case, we represent the serial number as a +``secure_vector`` called ``serial``. There are two additional (optional) +values, an enumeration called ``CRL_Code`` that specifies the reason for +revocation (``reason``), and an object that represents the time that the +certificate became invalid (if this information is known). + +If you wish to remove an old entry from the CRL, insert a new entry for the +same cert, with a ``reason`` code of ``REMOVE_FROM_CRL``. For example, if a +revoked certificate has expired 'normally', there is no reason to continue to +explicitly revoke it, since clients will reject the cert as expired in any +case. + +Self-Signed Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generating a new self-signed certificate can often be useful, for +example when setting up a new root CA, or for use in specialized +protocols. The library provides a utility function for this: + +.. cpp:function:: X509_Certificate create_self_signed_cert( \ + const X509_Cert_Options& opts, const Private_Key& key, \ + const std::string& hash_fn, RandomNumberGenerator& rng) + + Where ``key`` is the private key you wish to use (the public key, + used in the certificate itself is extracted from the private key), + and ``opts`` is an structure that has various bits of information + that will be used in creating the certificate (this structure, and + its use, is discussed below). + +Creating PKCS #10 Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Also in ``x509self.h``, there is a function for generating new PKCS #10 +certificate requests: + +.. cpp:function:: PKCS10_Request create_cert_req( \ + const X509_Cert_Options& opts, const Private_Key& key, \ + const std::string& hash_fn, RandomNumberGenerator& rng) + +This function acts quite similarly to +:cpp:func:`create_self_signed_cert`, except it instead returns a PKCS +#10 certificate request. After creating it, one would typically +transmit it to a CA, who signs it and returns a freshly minted X.509 +certificate. + +.. cpp:function:: PKCS10_Request PKCS10_Request::create(const Private_Key& key, \ + const X509_DN& subject_dn, \ + const Extensions& extensions, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng, \ + const std::string& padding_scheme = "", \ + const std::string& challenge = "") + + This function (added in 2.5) is similar to ``create_cert_req`` but allows + specifying all the parameters directly. In fact ``create_cert_req`` just + creates the DN and extensions from the options, then uses this call to + actually create the ``PKCS10_Request`` object. + + +Certificate Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +What is this ``X509_Cert_Options`` thing we've been passing around? +It's a class representing a bunch of information that will end up +being stored into the certificate. This information comes in 3 major +flavors: information about the subject (CA or end-user), the validity +period of the certificate, and restrictions on the usage of the +certificate. For special cases, you can also add custom X.509v3 +extensions. + +First and foremost is a number of ``std::string`` members, which +contains various bits of information about the user: ``common_name``, +``serial_number``, ``country``, ``organization``, ``org_unit``, +``locality``, ``state``, ``email``, ``dns_name``, and ``uri``. As many +of these as possible should be filled it (especially an email +address), though the only required ones are ``common_name`` and +``country``. + +Additionally there are a small selection of ``std::vector`` +members, which allow space for repeating elements: +``more_org_units`` and ``more_dns``. + +There is another value that is only useful when creating a PKCS #10 +request, which is called ``challenge``. This is a challenge password, +which you can later use to request certificate revocation (*if* the CA +supports doing revocations in this manner). + +Then there is the validity period; these are set with ``not_before`` +and ``not_after``. Both of these functions also take a +``std::string``, which specifies when the certificate should start +being valid, and when it should stop being valid. If you don't set the +starting validity period, it will automatically choose the current +time. If you don't set the ending time, it will choose the starting +time plus a default time period. The arguments to these functions +specify the time in the following format: "2002/11/27 1:50:14". The +time is in 24-hour format, and the date is encoded as +year/month/day. The date must be specified, but you can omit the time +or trailing parts of it, for example "2002/11/27 1:50" or +"2002/11/27". + +Third, you can set constraints on a key. The one you're mostly likely +to want to use is to create (or request) a CA certificate, which can +be done by calling the member function ``CA_key``. This should only be +used when needed. + +Moreover, you can specify the padding scheme to be used when digital signatures +are computed by calling function ``set_padding_scheme`` with a string +representing the padding scheme. This way, you can control the padding scheme +for self-signed certificates and PKCS #10 requests. The padding scheme used by +a CA when building a certificate or a certificate revocation list can be set in +the ``X509_CA`` constructor. The supported padding schemes can be found in +src/lib/pubkey/padding.cpp. Some alternative names for the padding schemes are +understood, as well. + +Other constraints can be set by calling the member functions +``add_constraints`` and ``add_ex_constraints``. The first takes a +``Key_Constraints`` value, and replaces any previously set value. If +no value is set, then the certificate key is marked as being valid for +any usage. You can set it to any of the following (for more than one +usage, OR them together): ``DIGITAL_SIGNATURE``, ``NON_REPUDIATION``, +``KEY_ENCIPHERMENT``, ``DATA_ENCIPHERMENT``, ``KEY_AGREEMENT``, +``KEY_CERT_SIGN``, ``CRL_SIGN``, ``ENCIPHER_ONLY``, +``DECIPHER_ONLY``. Many of these have quite special semantics, so you +should either consult the appropriate standards document (such as RFC +5280), or just not call ``add_constraints``, in which case the +appropriate values will be chosen for you. + +The second function, ``add_ex_constraints``, allows you to specify an +OID that has some meaning with regards to restricting the key to +particular usages. You can, if you wish, specify any OID you like, but +there is a set of standard ones that other applications will be able +to understand. These are the ones specified by the PKIX standard, and +are named "PKIX.ServerAuth" (for TLS server authentication), +"PKIX.ClientAuth" (for TLS client authentication), "PKIX.CodeSigning", +"PKIX.EmailProtection" (most likely for use with S/MIME), +"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and +"PKIX.TimeStamping". You can call "add_ex_constraints" any number of +times - each new OID will be added to the list to include in the +certificate. + +Lastly, you can add any X.509v3 extensions in the `extensions` member, which is +useful if you want to encode a custom extension, or encode an extension in a way +differently from how Botan defaults. + +OCSP Requests +---------------------------------------- + +A client makes an OCSP request to what is termed an 'OCSP responder'. This +responder returns a signed response attesting that the certificate in question +has not been revoked. The most recent OCSP specification is as of this +writing :rfc:`6960`. + +Normally OCSP validation happens automatically as part of X.509 certificate +validation, as long as OCSP is enabled (by setting a non-zero ``ocsp_timeout`` +in the call to ``x509_path_validate``, or for TLS by implementing the related +``tls_verify_cert_chain_ocsp_timeout`` callback and returning a non-zero value +from that). So most applications should not need to directly manipulate OCSP +request and response objects. + +For those that do, the primary ocsp interface is in ``ocsp.h``. First a request +must be formed, using information contained in the subject certificate and in +the subject's issuing certificate. + +.. cpp:class:: OCSP::Request + + .. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \ + const BigInt& subject_serial) + + Create a new OCSP request + + .. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \ + const X509_Certificate& subject_cert) + + Variant of the above, using serial number from ``subject_cert``. + + .. cpp:function:: std::vector BER_encode() const + + Encode the current OCSP request as a binary string. + + .. cpp:function:: std::string base64_encode() const + + Encode the current OCSP request as a base64 string. + +Then the response is parsed and validated, and if valid, can be consulted +for certificate status information. + +.. cpp:class:: OCSP::Response + + .. cpp:function:: OCSP::Response(const uint8_t response_bits[], size_t response_bits_len) + + Attempts to parse ``response_bits`` as an OCSP response. Throws an + exception if parsing fails. Note that this does not verify that the OCSP + response is valid (ie that the signature is correct), merely that the + ASN.1 structure matches an OCSP response. + + .. cpp:function:: Certificate_Status_Code check_signature( \ + const std::vector& trust_roots, \ + const std::vector>& cert_path = const std::vector>()) const + + Find the issuing certificate of the OCSP response, and check the signature. + + If possible, pass the full certificate path being validated in + the optional ``cert_path`` argument: this additional information + helps locate the OCSP signer's certificate in some cases. If this + does not return ``Certificate_Status_Code::OCSP_SIGNATURE_OK``, + then the request must not be be used further. + + .. cpp:function:: Certificate_Status_Code verify_signature(const X509_Certificate& issuing_cert) const + + If the certificate that issued the OCSP response is already known (eg, + because in some specific application all the OCSP responses will always + be signed by a single trusted issuer whose cert is baked into the code) + this provides an alternate version of `check_signature`. + + .. cpp:function:: Certificate_Status_Code status_for(const X509_Certificate& issuer, \ + const X509_Certificate& subject, \ + std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const + + Assuming the signature is valid, returns the status for the subject certificate. + Make sure to get the ordering of the issuer and subject certificates correct. + + The ``ref_time`` is normally just the system clock, but can be used if + validation against some other reference time is desired (such as for + testing, to verify an old previously valid OCSP response, or to use an + alternate time source such as the Roughtime protocol instead of the local + client system clock). + + .. cpp:function:: const X509_Time& produced_at() const + + Return the time this OCSP response was (claimed to be) produced at. + + .. cpp:function:: const X509_DN& signer_name() const + + Return the distinguished name of the signer. This is used to help + find the issuing certificate. + + This field is optional in OCSP responses, and may not be set. + + .. cpp:function:: const std::vector& signer_key_hash() const + + Return the SHA-1 hash of the public key of the signer. This is used to + help find the issuing certificate. The ``Certificate_Store`` API + ``find_cert_by_pubkey_sha1`` can search on this value. + + This field is optional in OCSP responses, and may not be set. + + .. cpp:function:: const std::vector& raw_bits() const + + Return the entire raw ASN.1 blob (for debugging or specialized decoding needs) + +One common way of making OCSP requests is via HTTP, see :rfc:`2560` +Appendix A for details. A basic implementation of this is the function +``online_check``, which is available as long as the ``http_util`` module +was compiled in; check by testing for the macro ``BOTAN_HAS_HTTP_UTIL``. + +.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \ + const BigInt& subject_serial, \ + const std::string& ocsp_responder, \ + const Certificate_Store* trusted_roots) + + Assemble a OCSP request for serial number ``subject_serial`` and attempt to request + it to responder at URI ``ocsp_responder`` over a new HTTP socket, parses and returns + the response. If trusted_roots is not null, then the response is additionally + validated using OCSP response API ``check_signature``. Otherwise, this call must be + performed later by the application. + +.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \ + const X509_Certificate& subject, \ + const Certificate_Store* trusted_roots) + + Variant of the above but uses serial number and OCSP responder URI from ``subject``. diff --git a/comm/third_party/botan/doc/authors.txt b/comm/third_party/botan/doc/authors.txt new file mode 100644 index 0000000000..abaaab024a --- /dev/null +++ b/comm/third_party/botan/doc/authors.txt @@ -0,0 +1,102 @@ +Alastair Houghton +Alexander Bluhm (genua GmbH) +Alex Gaynor +Alf-André Walla +Allan L. Bazinet +Alon Bar-Lev +Andrew Moon +Antonio Coratelli +Atanas Filyanov +Baruch Burstein +Bhaskar Biswas +Bi11 +Bogdan Gusiev +Chris Desjardins +Christian Mainka (Hackmanit GmbH) +Christopher Bläsius +Christoph Ludwig +cryptosource GmbH +cynecx +Dan Brown +Daniel Neus (Rohde & Schwarz Cybersecurity) +Daniel Seither (Kullo GmbH) +Daniel Wyatt +Eric Cornelius +Erwan Chaussy +etcimon +Evgeny Pokhilko +Fabian Weissberg +Falko Strenzke (cryptosource GmbH) +Felix Yan +FlexSecure GmbH +Florent Le Coz +Francis Dupont +Frank Schoenmann +Google Inc +Gustavo Serra Scalet +guywithcrookedface +Hannes Rantzsch +Harry Reimann +Hegedüs Márton Csaba +Hubert Bugaj +ilovezfs +J08nY +Jack Lloyd +Jeffrey Walton +Joel Low +joerg +Jose Luis Pereira (Fyde Inc.) +Juraj Somorovsky (Hackmanit GmbH) +Justin Karneges +Kai Michaelis (Rohde & Schwarz Cybersecurity) +Kirill A. Korinsky +Konstantinos Kolelis +Krzysztof Kwiatkowski +Lauri Nurmi +Luca Piccarreta +Manuel Hartl +Marcus Brinkmann +Markus Wanner +Martin Doering +Matej Kenda (TopIT d.o.o.) +Mathieu Souchaud +Matthew Gregan +Matthias Gierlings (Hackmanit GmbH) +Matt Johnston +Nathan Hourt +Nicolas Sendrier +Nuno Goncalves +Ori Peleg +Patrick Sona +Patrick Wildt +Patrik Fiedler +Peter J Jones +Philippe Lieser (Rohde & Schwarz Cybersecurity) +Philipp Weber (Rohde & Schwarz Cybersecurity) +Projet SECRET, INRIA, Rocquencourt +René Korthaus (Rohde & Schwarz Cybersecurity) +René Meusel +Ribose Inc +Robert Dailey +Ryuhei Mori +schregger +Sergii Cherkavskyi +seu +Shlomi Fish +Simon Cogliani +Simon Warta (Kullo GmbH) +slaviber +souch +t0b3 +tcely +Technische Universitat Darmstadt +Tim Oesterreich +Tobias @neverhub +Tomasz Frydrych +Uri Blumenthal +Vaclav Ovsik +Volker Aßmann +Yuri +Yves Jerschow +Zoltan Gyarmati +0xdefaced diff --git a/comm/third_party/botan/doc/building.rst b/comm/third_party/botan/doc/building.rst new file mode 100644 index 0000000000..c5f5925f16 --- /dev/null +++ b/comm/third_party/botan/doc/building.rst @@ -0,0 +1,1019 @@ +.. _building: + +Building The Library +================================= + +This document describes how to build Botan on Unix/POSIX and Windows +systems. The POSIX oriented descriptions should apply to most +common Unix systems (including OS X), along with POSIX-ish systems +like BeOS, QNX, and Plan 9. Currently, systems other than Windows and +POSIX (such as VMS, MacOS 9, OS/390, OS/400, ...) are not supported by +the build system, primarily due to lack of access. Please contact the +maintainer if you would like to build Botan on such a system. + +Botan's build is controlled by configure.py, which is a `Python +`_ script. Python 2.6 or later is required. + +.. highlight:: none + +For the impatient, this works for most systems:: + + $ ./configure.py [--prefix=/some/directory] + $ make + $ make install + +Or using ``nmake``, if you're compiling on Windows with Visual C++. On +platforms that do not understand the '#!' convention for beginning +script files, or that have Python installed in an unusual spot, you +might need to prefix the ``configure.py`` command with ``python`` or +``/path/to/python``:: + + $ python ./configure.py [arguments] + +Configuring the Build +--------------------------------- + +The first step is to run ``configure.py``, which is a Python script +that creates various directories, config files, and a Makefile for +building everything. This script should run under a vanilla install of +Python 2.6, 2.7, or 3.x. + +The script will attempt to guess what kind of system you are trying to +compile for (and will print messages telling you what it guessed). +You can override this process by passing the options ``--cc``, +``--os``, and ``--cpu``. + +You can pass basically anything reasonable with ``--cpu``: the script +knows about a large number of different architectures, their +sub-models, and common aliases for them. You should only select the +64-bit version of a CPU (such as "sparc64" or "mips64") if your +operating system knows how to handle 64-bit object code - a 32-bit +kernel on a 64-bit CPU will generally not like 64-bit code. + +By default the script tries to figure out what will work on your +system, and use that. It will print a display at the end showing which +algorithms have and have not been enabled. For instance on one system +we might see lines like:: + + INFO: Skipping (dependency failure): certstor_sqlite3 sessions_sqlite3 + INFO: Skipping (incompatible CPU): aes_power8 + INFO: Skipping (incompatible OS): darwin_secrandom getentropy win32_stats + INFO: Skipping (incompatible compiler): aes_armv8 pmull sha1_armv8 sha2_32_armv8 + INFO: Skipping (no enabled compression schemes): compression + INFO: Skipping (requires external dependency): boost bzip2 lzma openssl sqlite3 tpm zlib + +The ones that are skipped because they are require an external +dependency have to be explicitly asked for, because they rely on third +party libraries which your system might not have or that you might not +want the resulting binary to depend on. For instance to enable zlib +support, add ``--with-zlib`` to your invocation of ``configure.py``. +All available modules can be listed with ``--list-modules``. + +You can control which algorithms and modules are built using the +options ``--enable-modules=MODS`` and ``--disable-modules=MODS``, for +instance ``--enable-modules=zlib`` and ``--disable-modules=xtea,idea``. +Modules not listed on the command line will simply be loaded if needed +or if configured to load by default. If you use ``--minimized-build``, +only the most core modules will be included; you can then explicitly +enable things that you want to use with ``--enable-modules``. This is +useful for creating a minimal build targeting to a specific +application, especially in conjunction with the amalgamation option; +see :ref:`amalgamation` and :ref:`minimized_builds`. + +For instance:: + + $ ./configure.py --minimized-build --enable-modules=rsa,eme_oaep,emsa_pssr + +will set up a build that only includes RSA, OAEP, PSS along with any +required dependencies. Note that a minimized build does not by default +include any random number generator, which is needed for example to +generate keys, nonces and IVs. See :doc:`api_ref/rng` on which random number +generators are available. + +Cross Compiling +--------------------- + +Cross compiling refers to building software on one type of host (say Linux +x86-64) but creating a binary for some other type (say MinGW x86-32). This is +completely supported by the build system. To extend the example, we must tell +`configure.py` to use the MinGW tools:: + + $ ./configure.py --os=mingw --cpu=x86_32 --cc-bin=i686-w64-mingw32-g++ --ar-command=i686-w64-mingw32-ar + ... + $ make + ... + $ file botan.exe + botan.exe: PE32 executable (console) Intel 80386, for MS Windows + +.. note:: + For whatever reason, some distributions of MinGW lack support for + threading or mutexes in the C++ standard library. You can work around + this by disabling thread support using ``--without-os-feature=threads`` + +You can also specify the alternate tools by setting the `CXX` and `AR` +environment variables (instead of the `--cc-bin` and `--ar-command` options), as +is commonly done with autoconf builds. + +On Unix +---------------- + +The basic build procedure on Unix and Unix-like systems is:: + + $ ./configure.py [--enable-modules=] [--cc=CC] + $ make + $ make check + +If the tests look OK, install:: + + $ make install + +On Unix systems the script will default to using GCC; use ``--cc`` if +you want something else. For instance use ``--cc=icc`` for Intel C++ +and ``--cc=clang`` for Clang. + +The ``make install`` target has a default directory in which it will +install Botan (typically ``/usr/local``). You can override this by +using the ``--prefix`` argument to ``configure.py``, like so:: + + $ ./configure.py --prefix=/opt + +On some systems shared libraries might not be immediately visible to +the runtime linker. For example, on Linux you may have to edit +``/etc/ld.so.conf`` and run ``ldconfig`` (as root) in order for new +shared libraries to be picked up by the linker. An alternative is to +set your ``LD_LIBRARY_PATH`` shell variable to include the directory +that the Botan libraries were installed into. + +On macOS +-------------- + +A build on macOS works much like that on any other Unix-like system. + +To build a universal binary for macOS, you need to set some additional +build flags. Do this with the `configure.py` flag `--cc-abi-flags`:: + + --cc-abi-flags="-force_cpusubtype_ALL -mmacosx-version-min=10.4 -arch i386 -arch ppc" + +On Windows +-------------- + +.. note:: + + The earliest versions of Windows supported are Windows 7 and Windows 2008 R2 + +You need to have a copy of Python installed, and have both Python and +your chosen compiler in your path. Open a command shell (or the SDK +shell), and run:: + + $ python configure.py --cc=msvc --os=windows + $ nmake + $ nmake check + $ nmake install + +Botan supports the nmake replacement `Jom `_ +which enables you to run multiple build jobs in parallel. + +For MinGW, use:: + + $ python configure.py --cc=gcc --os=mingw + $ make + +By default the install target will be ``C:\botan``; you can modify +this with the ``--prefix`` option. + +When building your applications, all you have to do is tell the +compiler to look for both include files and library files in +``C:\botan``, and it will find both. Or you can move them to a +place where they will be in the default compiler search paths (consult +your documentation and/or local expert for details). + + +For iOS using XCode +------------------------- + +For iOS, you typically build for 3 architectures: armv7 (32 bit, older +iOS devices), armv8-a (64 bit, recent iOS devices) and x86_64 for +the iPhone simulator. You can build for these 3 architectures and then +create a universal binary containing code for all of these +architectures, so you can link to Botan for the simulator as well as +for an iOS device. + +To cross compile for armv7, configure and make with:: + + $ ./configure.py --os=ios --prefix="iphone-32" --cpu=armv7 --cc=clang \ + --cc-abi-flags="-arch armv7" + $ xcrun --sdk iphoneos make install + +To cross compile for armv8-a, configure and make with:: + + $ ./configure.py --os=ios --prefix="iphone-64" --cpu=armv8-a --cc=clang \ + --cc-abi-flags="-arch arm64" + $ xcrun --sdk iphoneos make install + +To compile for the iPhone Simulator, configure and make with:: + + $ ./configure.py --os=ios --prefix="iphone-simulator" --cpu=x86_64 --cc=clang \ + --cc-abi-flags="-arch x86_64" + $ xcrun --sdk iphonesimulator make install + +Now create the universal binary and confirm the library is compiled +for all three architectures:: + + $ xcrun --sdk iphoneos lipo -create -output libbotan-2.a \ + iphone-32/lib/libbotan-2.a \ + iphone-64/lib/libbotan-2.a \ + iphone-simulator/lib/libbotan-2.a + $ xcrun --sdk iphoneos lipo -info libbotan-2.a + Architectures in the fat file: libbotan-2.a are: armv7 x86_64 armv64 + +The resulting static library can be linked to your app in Xcode. + +For Android +--------------------- + +Modern versions of Android NDK use Clang and support C++11. Simply +configure using the appropriate NDK compiler:: + + $ export CXX=/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang++ + $ ./configure.py --os=android --cc=clang --cpu=arm64 + +Docker +^^^^^^^^^^^ + +To build android version, there is the possibility to use +the docker way:: + + sudo ANDROID_SDK_VER=21 ANDROID_ARCH=arm64 src/scripts/docker-android.sh + +This will produce the docker-builds/android folder containing +each architecture compiled. + +Emscripten (WebAssembly) +--------------------------- + +To build for WebAssembly using Emscripten, try:: + + CXX=em++ ./configure.py --cc=clang --cpu=llvm --os=emscripten + make + +This will produce bitcode files ``botan-test.bc`` and ``botan.bc`` +along with a static archive ``libbotan-2.a`` which can linked with +other modules. To convert the tests into a WASM file which can be +executed on a browser, use:: + + em++ -s ALLOW_MEMORY_GROWTH=1 -s DISABLE_EXCEPTION_CATCHING=0 -s WASM=1 \ + --preload-file src/tests/data botan-test.bc -o botan-test.html + +Supporting Older Distros +-------------------------- + +Some "stable" distributions, notably RHEL/CentOS, ship very obsolete +versions of binutils, which do not support more recent CPU instructions. +As a result when building you may receive errors like:: + + Error: no such instruction: `sha256rnds2 %xmm0,%xmm4,%xmm3' + +Depending on how old your binutils is, you may need to disable BMI2, +AVX2, SHA-NI, and/or RDSEED. These can be disabled by passing the +flags ``--disable-bmi2``, ``--disable-avx2``, ``--disable-sha-ni``, +and ``--disable-rdseed`` to ``configure.py``. + +Other Build-Related Tasks +---------------------------------------- + +.. _building_docs: + +Building The Documentation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are two documentation options available, Sphinx and Doxygen. +Sphinx will be used if ``sphinx-build`` is detected in the PATH, or if +``--with-sphinx`` is used at configure time. Doxygen is only enabled +if ``--with-doxygen`` is used. Both are generated by the makefile +target ``docs``. + + +.. _amalgamation: + +The Amalgamation Build +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can also configure Botan to be built using only a single source file; this +is quite convenient if you plan to embed the library into another application. + +To generate the amalgamation, run ``configure.py`` with whatever options you +would ordinarily use, along with the option ``--amalgamation``. This will create +two (rather large) files, ``botan_all.h`` and ``botan_all.cpp``. + +.. note:: + + The library will as usual be configured to target some specific operating + system and CPU architecture. You can use the CPU target "generic" if you need + to target multiple CPU architectures, but this has the effect of disabling + *all* CPU specific features such as SIMD, AES instruction sets, or inline + assembly. If you need to ship amalgamations for multiple targets, it would be + better to create different amalgamation files for each individual target. + +Whenever you would have included a botan header, you can then include +``botan_all.h``, and include ``botan_all.cpp`` along with the rest of the source +files in your build. If you want to be able to easily switch between amalgamated +and non-amalgamated versions (for instance to take advantage of prepackaged +versions of botan on operating systems that support it), you can instead ignore +``botan_all.h`` and use the headers from ``build/include`` as normal. + +You can also build the library using Botan's build system (as normal) but +utilizing the amalgamation instead of the individual source files by running +something like ``./configure.py --amalgamation && make``. This is essentially a +very simple form of link time optimization; because the entire library source is +visible to the compiler, it has more opportunities for interprocedural +optimizations. Additionally (assuming you are not making use of a compiler +cache such as ``ccache`` or ``sccache``) amalgamation builds usually have +significantly shorter compile times for full rebuilds. + +Modules Relying on Third Party Libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Currently ``configure.py`` cannot detect if external libraries are +available, so using them is controlled explicitly at build time +by the user using + + - ``--with-bzip2`` enables the filters providing bzip2 compression and + decompression. Requires the bzip2 development libraries to be installed. + + - ``--with-zlib`` enables the filters providing zlib compression and + decompression. Requires the zlib development libraries to be installed. + + - ``--with-lzma`` enables the filters providing lzma compression and + decompression. Requires the lzma development libraries to be installed. + + - ``--with-sqlite3`` enables using sqlite3 databases in various contexts + (TLS session cache, PSK database, etc). + + - ``--with-openssl`` adds an engine that uses OpenSSL for some ciphers, hashes, + and public key operations. OpenSSL 1.0.2 or later is supported. LibreSSL can + also be used. + + - ``--with-tpm`` adds support for using TPM hardware via the TrouSerS library. + + - ``--with-boost`` enables using some Boost libraries. In particular + Boost.Filesystem is used for a few operations (but on most platforms, a + native API equivalent is available), and Boost.Asio is used to provide a few + extra TLS related command line utilities. + +Multiple Builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It may be useful to run multiple builds with different configurations. +Specify ``--with-build-dir=`` to set up a build environment in a +different directory. + +Setting Distribution Info +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The build allows you to set some information about what distribution +this build of the library comes from. It is particularly relevant to +people packaging the library for wider distribution, to signify what +distribution this build is from. Applications can test this value by +checking the string value of the macro ``BOTAN_DISTRIBUTION_INFO``. It +can be set using the ``--distribution-info`` flag to ``configure.py``, +and otherwise defaults to "unspecified". For instance, a `Gentoo +`_ ebuild might set it with +``--distribution-info="Gentoo ${PVR}"`` where ``${PVR}`` is an ebuild +variable automatically set to a combination of the library and ebuild +versions. + +Local Configuration Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You may want to do something peculiar with the configuration; to +support this there is a flag to ``configure.py`` called +``--with-local-config=``. The contents of the file are +inserted into ``build/build.h`` which is (indirectly) included +into every Botan header and source file. + +Enabling or Disabling Use of Certain OS Features +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Botan uses compile-time flags to enable or disable use of certain operating +specific functions. You can also override these at build time if desired. + +The default feature flags are given in the files in ``src/build-data/os`` in the +``target_features`` block. For example Linux defines flags like ``proc_fs``, +``getauxval``, and ``sockets``. The ``configure.py`` option +``--list-os-features`` will display all the feature flags for all operating +system targets. + +To disable a default-enabled flag, use ``--without-os-feature=feat1,feat2,...`` + +To enable a flag that isn't otherwise enabled, use ``--with-os-feature=feat``. +For example, modern Linux systems support the ``getentropy`` call, but it is not +enabled by default because many older systems lack it. However if you know you +will only deploy to recently updated systems you can use +``--with-os-feature=getentropy`` to enable it. + +A special case if dynamic loading, which applications for certain environments +will want to disable. There is no specific feature flag for this, but +``--disable-modules=dyn_load`` will prevent it from being used. + +.. note:: Disabling ``dyn_load`` module will also disable the PKCS #11 + wrapper, which relies on dynamic loading. + +Configuration Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are some configuration parameters which you may want to tweak +before building the library. These can be found in ``build.h``. This +file is overwritten every time the configure script is run (and does +not exist until after you run the script for the first time). + +Also included in ``build/build.h`` are macros which let applications +check which features are included in the current version of the +library. All of them begin with ``BOTAN_HAS_``. For example, if +``BOTAN_HAS_RSA`` is defined, then an application knows that this +version of the library has RSA available. + +``BOTAN_MP_WORD_BITS``: This macro controls the size of the words used for +calculations with the MPI implementation in Botan. It must be set to either 32 +or 64 bits. The default is chosen based on the target processor. There is +normally no reason to change this. + +``BOTAN_DEFAULT_BUFFER_SIZE``: This constant is used as the size of +buffers throughout Botan. The default should be fine for most +purposes, reduce if you are very concerned about runtime memory usage. + +Building Applications +---------------------------------------- + +Unix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Botan usually links in several different system libraries (such as +``librt`` or ``libz``), depending on which modules are configured at +compile time. In many environments, particularly ones using static +libraries, an application has to link against the same libraries as +Botan for the linking step to succeed. But how does it figure out what +libraries it *is* linked against? + +The answer is to ask the ``botan`` command line tool using +the ``config`` and ``version`` commands. + +``botan version``: Print the Botan version number. + +``botan config prefix``: If no argument, print the prefix where Botan is +installed (such as ``/opt`` or ``/usr/local``). + +``botan config cflags``: Print options that should be passed to the +compiler whenever a C++ file is compiled. Typically this is used for +setting include paths. + +``botan config libs``: Print options for which libraries to link to +(this will include a reference to the botan library itself). + +Your ``Makefile`` can run ``botan config`` and get the options +necessary for getting your application to compile and link, regardless +of whatever crazy libraries Botan might be linked against. + +Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +No special help exists for building applications on Windows. However, +given that typically Windows software is distributed as binaries, this +is less of a problem - only the developer needs to worry about it. As +long as they can remember where they installed Botan, they just have +to set the appropriate flags in their Makefile/project file. + +Language Wrappers +---------------------------------------- + +Building the Python wrappers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Python wrappers for Botan use ctypes and the C89 API so no special +build step is required, just import botan2.py + +See :doc:`Python Bindings ` for more information about +the Python bindings. + +.. _minimized_builds: + +Minimized Builds +-------------------- + +Many developers wish to configure a minimized build which contains only the +specific features their application will use. In general this is straighforward: +use ``--minimized-build`` plus ``--enable-modules=`` to enable the specific modules +you wish to use. Any such configurations should build and pass the tests; if you +encounter a case where it doesn't please file an issue. + +The only trick is knowing which features you want to enable. The most common +difficulty comes with entropy sources. By default, none are enabled, which means +if you attempt to use ``AutoSeeded_RNG``, it will fail. The easiest resolution +is to also enable ``system_rng`` which can act as either an entropy source or +used directly as the RNG. + +If you are building for x86, ARM, or POWER, it can be beneficial to enable +hardware support for the relevant instruction sets with modules such as +``aes_ni`` and ``clmul`` for x86, or ``aes_armv8``, ``pmull``, and +``sha2_32_armv8`` on ARMv8. SIMD optimizations such as ``chacha_avx2`` also can +provide substantial performance improvements. + +.. note:: + In a future release, hardware specific modules will be enabled by default if + the underlying "base" module is enabled. + +If you are building a TLS application, you may (or may not) want to include +``tls_cbc`` which enables support for CBC ciphersuites. If ``tls_cbc`` is +disabled, then it will not be possible to negotiate TLS v1.0/v1.1. In general +this should be considered a feature; only enable this if you need backward +compatability with obsolete clients or servers. + +For TLS another useful feature which is not enabled by default is the +ChaCha20Poly1305 ciphersuites. To enable these, add ``chacha20poly1305``. + + +Configure Script Options +--------------------------- + +``--cpu=CPU`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the target CPU architecture. If not used, the arch of the current +system is detected (using Python's platform module) and used. + +``--os=OS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the target operating system. + +``--cc=COMPILER`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the desired build compiler + +``--cc-min-version=MAJOR.MINOR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the minimal version of the target +compiler. Use --cc-min-version=0.0 to support all compiler +versions. Default is auto detection. + +``--cc-bin=BINARY`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set path to compiler binary + +If not provided, the value of the ``CXX`` environment variable is used if set. + +``--cc-abi-flags=FLAGS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set ABI flags, which for the purposes of this option mean options +which should be passed to both the compiler and linker. + +``--cxxflags=FLAGS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Override all compiler flags. This is equivalent to setting ``CXXFLAGS`` +in the environment. + +``--extra-cxxflags=FLAGS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set extra compiler flags, which are appended to the default set. This +is useful if you want to set just one or two additional options but +leave the normal logic for selecting flags alone. + +``--ldflags=FLAGS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set flags to pass to the linker. This is equivalent to setting ``LDFLAGS`` + +``--ar-command=AR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the path to the tool to use to create static archives (``ar``). +This is normally only used for cross-compilation. + +If not provided, the value of the ``AR`` environment variable is used if set. + +``--ar-options=AR_OPTIONS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Specify the options to pass to ``ar``. + +If not provided, the value of the ``AR_OPTIONS`` environment variable is used if set. + +``--msvc-runtime=RT`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Specify the MSVC runtime to use (MT, MD, MTd, or MDd). If not specified, +picks either MD or MDd depending on if debug mode is set. + +``--with-endian=ORDER`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The parameter should be either "little" or "big". If not used then if +the target architecture has a default, that is used. Otherwise left +unspecified, which causes less optimal codepaths to be used but will +work on either little or big endian. + +``--with-os-features=FEAT`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Specify an OS feature to enable. See ``src/build-data/os`` and +``doc/os.rst`` for more information. + +``--without-os-features=FEAT`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Specify an OS feature to disable. + +``--disable-sse2`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of SSE2 intrinsics + +``--disable-ssse3`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of SSSE3 intrinsics + +``--disable-sse4.1`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of SSE4.1 intrinsics + +``--disable-sse4.2`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of SSE4.2 intrinsics + +``--disable-avx2`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of AVX2 intrinsics + +``--disable-bmi2`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of BMI2 intrinsics + +``--disable-rdrand`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of RDRAND intrinsics + +``--disable-rdseed`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of RDSEED intrinsics + +``--disable-aes-ni`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of AES-NI intrinsics + +``--disable-sha-ni`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of SHA-NI intrinsics + +``--disable-altivec`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of AltiVec intrinsics + +``--disable-neon`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of NEON intrinsics + +``--disable-armv8crypto`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of ARMv8 Crypto intrinsics + +``--disable-powercrypto`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable use of POWER Crypto intrinsics + +``--with-debug-info`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Include debug symbols. + +``--with-sanitizers`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable some default set of sanitizer checks. What exactly is enabled +depends on the compiler. + +``--enable-sanitizers=SAN`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable specific sanitizers. See ``src/build-data/cc`` for more information. + +``--without-stack-protector`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable stack smashing protections. **not recommended** + +``--with-coverage`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Add coverage info and disable optimizations + +``--with-coverage-info`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Add coverage info, but leave optimizations alone + +``--disable-shared-library`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable building a shared library + +``--disable-static-library`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable building static library + +``--optimize-for-size`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Optimize for code size. + +``--no-optimizations`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable all optimizations for debugging. + +``--debug-mode`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable debug info and disable optimizations + +``--amalgamation`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use amalgamation to build + +``--system-cert-bundle=PATH`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set a path to a file containing one or more trusted CA certificates in +PEM format. If not given, some default locations are checked. + +``--with-build-dir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Setup the build in a specified directory instead of ``./build`` + +``--with-external-includedir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Search for includes in this directory. Provide this parameter multiple times to +define multiple additional include directories. + +``--with-external-libdir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Add DIR to the link path. Provide this parameter multiple times to define +multiple additional library link directories. + +``--define-build-macro`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set a compile-time pre-processor definition (i.e. add a -D... to the compiler +invocations). Provide this parameter multiple times to add multiple compile-time +definitions. Both KEY=VALUE and KEY (without specific value) are supported. + +``--with-sysroot-dir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use specified dir for system root while cross-compiling + +``--with-openmp`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable use of OpenMP + +``--link-method=METHOD`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +During build setup a directory linking to each header file is created. +Choose how the links are performed (options are "symlink", "hardlink", +or "copy"). + +``--with-local-config=FILE`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Include the contents of FILE into the generated build.h + +``--distribution-info=STRING`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set distribution specific version information + +``--maintainer-mode`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A build configuration used by library developers, which enables extra +warnings and turns most warnings into errors. + +.. warning:: + + When this option is used, all relevant warnings available in the + most recent release of GCC/Clang are enabled, so it may fail to + build if your compiler is not sufficiently recent. In addition + there may be non-default configurations or unusual platforms which + cause warnings which are converted to errors. Patches addressing + such warnings are welcome, but otherwise no support is available + when using this option. + +``--werror-mode`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Turns most warnings into errors. + +``--no-install-python-module`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Skip installing Python module. + +``--with-python-versions=N.M`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Where to install botan2.py. By default this is chosen to be the +version of Python that is running ``configure.py``. + +``--with-valgrind`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use valgrind API to perform additional checks. Not needed by end users. + +``--unsafe-fuzzer-mode`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable essential checks for testing. **UNSAFE FOR PRODUCTION** + +``--build-fuzzers=TYPE`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Select which interface the fuzzer uses. Options are "afl", +"libfuzzer", "klee", or "test". The "test" mode builds fuzzers that +read one input from stdin and then exit. + +``--with-fuzzer-lib=LIB`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Specify an additional library that fuzzer binaries must link with. + +``--build-targets=BUILD_TARGETS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Build only the specific targets and tools +(``static``, ``shared``, ``cli``, ``tests``, ``bogo_shim``). + +``--boost-library-name`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Provide an alternative name for a boost library. Depending on the platform and +boost's build configuration these library names differ significantly (see `Boost docs +`_). +The provided library name must be suitable as identifier in a linker parameter, +e.g on unix: ``boost_system`` or windows: ``libboost_regex-vc71-x86-1_70``. + +``--without-documentation`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Skip building/installing documentation + +``--with-sphinx`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use Sphinx to generate the handbook + +``--with-pdf`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use Sphinx to generate PDF doc + +``--with-rst2man`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use rst2man to generate a man page for the CLI + +``--with-doxygen`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use Doxygen to generate API reference + +``--module-policy=POL`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The option ``--module-policy=POL`` enables modules required by and +disables modules prohibited by a text policy in ``src/build-data/policy``. +Additional modules can be enabled if not prohibited by the policy. +Currently available policies include ``bsi``, ``nist`` and ``modern``:: + + $ ./configure.py --module-policy=bsi --enable-modules=tls,xts + +``--enable-modules=MODS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable some specific modules + +``--disable-modules=MODS`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Disable some specific modules + +``--minimized-build`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Start with the bare minimum. This is mostly useful in conjuction with +``--enable-modules`` to get a build that has just the features a +particular application requires. + +``--with-boost`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use Boost.Asio for networking support. This primarily affects the +command line utils. + +``--with-bzip2`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable bzip2 compression + +``--with-lzma`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable lzma compression + +``--with-zlib`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable using zlib compression + +``--with-openssl`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable using OpenSSL for certain operations + +``--with-commoncrypto`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable using CommonCrypto for certain operations + +``--with-sqlite3`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable using sqlite3 for data storage + +``--with-tpm`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enable support for TPM + +``--program-suffix=SUFFIX`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A string to append to all program binaries. + +``--library-suffix=SUFFIX`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A string to append to all library names. + +``--prefix=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the install prefix. + +``--docdir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the documentation installation dir. + +``--bindir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the binary installation dir. + +``--libdir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the library installation dir. + +``--mandir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the man page installation dir. + +``--includedir=DIR`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Set the include file installation dir. diff --git a/comm/third_party/botan/doc/cli.rst b/comm/third_party/botan/doc/cli.rst new file mode 100644 index 0000000000..98f9f06d4c --- /dev/null +++ b/comm/third_party/botan/doc/cli.rst @@ -0,0 +1,406 @@ +Command Line Interface +======================================== +.. highlight:: sh + +Outline +------------ + +The ``botan`` program is a command line tool for using a broad variety +of functions of the Botan library in the shell. + +All commands follow the syntax ``botan ``. + +If ``botan`` is run with an unknown command, or without any command, or with the +``--help`` option, all available commands will be printed. If a particular +command is run with the ``--help`` option (like ``botan --help``) +some information about the usage of the command is printed. + +Starting in version 2.9, commands that take a passphrase (such as +``gen_bcrypt`` or ``pkcs8``) will also accept the literal ``-`` to mean +ask for the passphrase on the terminal. If supported by the operating +system, echo will be disabled while reading the passphrase. + +Most arguments that take a path to a file will also accept the literal ``-`` +to mean the file content should be read from STDIN instead. + +Hash Function +---------------- +``hash --algo=SHA-256 --buf-size=4096 --no-fsname --format=hex *files`` + Compute the *algo* digest over the data in any number of *files*. If + no files are listed on the command line, the input source defaults + to standard input. Unless the ``--no-fsname`` option is given, the + filename is printed alongside the hash, in the style of tools such + as ``sha256sum``. + +Password Hash +---------------- +``gen_argon2 --mem=65536 --p=1 --t=1 password`` + Calculate the Argon2 password digest of *password*. *mem* is the amount of + memory to use in Kb, *p* the parallelization parameter and *t* the number of + iterations to use. + +``check_argon2 password hash`` + Checks if the Argon2 hash of the passed *password* equals the passed *hash* value. + +``gen_bcrypt --work-factor=12 password`` + Calculate the bcrypt password digest of *password*. *work-factor* is an + integer between 4 and 18. A higher *work-factor* value results in a + more expensive hash calculation. + +``check_bcrypt password hash`` + Checks if the bcrypt hash of the passed *password* equals the passed *hash* value. + +``pbkdf_tune --algo=Scrypt --max-mem=256 --output-len=32 --check *times`` + Tunes the PBKDF algorithm specified with ``--algo=`` for the given *times*. + +HMAC +---------------- +``hmac --hash=SHA-256 --buf-size=4096 --no-fsname key files`` + Compute the HMAC tag with the cryptographic hash function *hash* + using the key in file *key* over the data in *files*. *files* + defaults to STDIN. Unless the ``--no-fsname`` option is given, the + filename is printed alongside the HMAC value. + +Encryption +---------------- +``encryption --buf-size=4096 --decrypt --mode= --key= --iv= --ad=`` + Encrypt a given file with the specified *mode*. If ``--decrypt`` is provided + the file is decrypted instead. + +Public Key Cryptography +------------------------------------- +``keygen --algo=RSA --params= --passphrase= --pbe= --pbe-millis=300 --provider= --der-out`` + Generate a PKCS #8 *algo* private key. If *der-out* is passed, the pair is BER + encoded. Otherwise, PEM encoding is used. To protect the PKCS #8 formatted + key, it is recommended to encrypt it with a provided *passphrase*. *pbe* is + the name of the desired encryption algorithm, which uses *pbe-millis* + milliseconds to derive the encryption key from the passed + *passphrase*. Algorithm specific parameters, as the desired bit length of an + RSA key, can be passed with *params*. + + - For RSA *params* specifies the bit length of the RSA modulus. It defaults to 3072. + - For DH *params* specifies the DH parameters. It defaults to modp/ietf/2048. + - For DSA *params* specifies the DSA parameters. It defaults to dsa/botan/2048. + - For EC algorithms *params* specifies the elliptic curve. It defaults to secp256r1. + + The default *pbe* algorithm is "PBES2(AES-256/CBC,SHA-256)". + + With PBES2 scheme, you can select any CBC or GCM mode cipher which has an OID + defined (such as 3DES, Camellia, SM4, Twofish or Serpent). However most other + implementations support only AES or 3DES in CBC mode. You can also choose + Scrypt instead of PBKDF2, by using "Scrypt" instead of the name of a hash + function, for example "PBES2(AES-256/CBC,Scrypt)". Scrypt is also supported by + some other implementations including OpenSSL. + +``pkcs8 --pass-in= --pub-out --der-out --pass-out= --pbe= --pbe-millis=300 key`` + Open a PKCS #8 formatted key at *key*. If *key* is encrypted, the passphrase + must be passed as *pass-in*. It is possible to (re)encrypt the read key with + the passphrase passed as *pass-out*. The parameters *pbe-millis* and *pbe* + work similarly to ``keygen``. + +``sign --der-format --passphrase= --hash=SHA-256 --emsa= --provider= key file`` + Sign the data in *file* using the PKCS #8 private key *key*. If *key* is + encrypted, the used passphrase must be passed as *pass-in*. *emsa* specifies + the signature scheme and *hash* the cryptographic hash function used in the + scheme. + + - For RSA signatures EMSA4 (RSA-PSS) is the default scheme. + - For ECDSA and DSA *emsa* defaults to EMSA1 (signing the hash directly) + + For ECDSA and DSA, the option ``--der-format`` outputs the signature as an + ASN.1 encoded blob. Some other tools (including ``openssl``) default to this + format. + + The signature is formatted for your screen using base64. + +``verify --der-format --hash=SHA-256 --emsa= pubkey file signature`` + Verify the authenticity of the data in *file* with the provided signature + *signature* and the public key *pubkey*. Similarly to the signing process, + *emsa* specifies the signature scheme and *hash* the cryptographic hash + function used in the scheme. + +``gen_dl_group --pbits=1024 --qbits=0 --seed= --type=subgroup`` + Generate ANSI X9.42 encoded Diffie-Hellman group parameters. + + - If *type=subgroup* is passed, the size of the prime subgroup q is sampled + as a prime of *qbits* length and p is *pbits* long. If *qbits* is not + passed, its length is estimated from *pbits* as described in RFC 3766. + - If *type=strong* is passed, p is sampled as a safe prime with length + *pbits* and the prime subgroup has size q with *pbits*-1 length. + - If *type=dsa* is used, p and q are generated by the algorithm specified in + FIPS 186-4. If the ``--seed`` parameter is used, it allows to select the + seed value, instead of one being randomly generated. If the seed does not + in fact generate a valid DSA group, the command will fail. + +``dl_group_info --pem name`` + Print raw Diffie-Hellman parameters (p,g) of the standardized DH group + *name*. If *pem* is set, the X9.42 encoded group is printed. + +``ec_group_info --pem name`` + Print raw elliptic curve domain parameters of the standardized curve *name*. If + *pem* is set, the encoded domain is printed. + +``pk_encrypt --aead=AES-256/GCM rsa_pubkey datafile`` + Encrypts ``datafile`` using the specified AEAD algorithm, under a key protected + by the specified RSA public key. + +``pk_decrypt rsa_privkey datafile`` + Decrypts a file encrypted with ``pk_encrypt``. If the key is encrypted using a + password, it will be prompted for on the terminal. + +``fingerprint --no-fsname --algo=SHA-256 *keys`` + Calculate the public key fingerprint of the *keys*. + +``pk_workfactor --type=rsa bits`` + Provide an estimate of the strength of a public key based on it's size. + ``--type=`` can be "rsa", "dl" or "dl_exp". + +X.509 +---------------------------------------------- + +``gen_pkcs10 key CN --country= --organization= --ca --path-limit=1 --email= --dns= --ext-ku= --key-pass= --hash=SHA-256 --emsa=`` + Generate a PKCS #10 certificate signing request (CSR) using the passed PKCS #8 + private key *key*. If the private key is encrypted, the decryption passphrase + *key-pass* has to be passed.*emsa* specifies the padding scheme to be used + when calculating the signature. + + - For RSA keys EMSA4 (RSA-PSS) is the default scheme. + - For ECDSA, DSA, ECGDSA, ECKCDSA and GOST-34.10 keys *emsa* defaults to EMSA1. + +``gen_self_signed key CN --country= --dns= --organization= --email= --path-limit=1 --days=365 --key-pass= --ca --hash=SHA-256 --emsa= --der`` + Generate a self signed X.509 certificate using the PKCS #8 private key + *key*. If the private key is encrypted, the decryption passphrase *key-pass* + has to be passed. If *ca* is passed, the certificate is marked for certificate + authority (CA) usage. *emsa* specifies the padding scheme to be used when + calculating the signature. + + - For RSA keys EMSA4 (RSA-PSS) is the default scheme. + - For ECDSA, DSA, ECGDSA, ECKCDSA and GOST-34.10 keys *emsa* defaults to EMSA1. + +``sign_cert --ca-key-pass= --hash=SHA-256 --duration=365 --emsa= ca_cert ca_key pkcs10_req`` + Create a CA signed X.509 certificate from the information contained in the + PKCS #10 CSR *pkcs10_req*. The CA certificate is passed as *ca_cert* and the + respective PKCS #8 private key as *ca_key*. If the private key is encrypted, + the decryption passphrase *ca-key-pass* has to be passed. The created + certificate has a validity period of *duration* days. *emsa* specifies the + padding scheme to be used when calculating the signature. *emsa* defaults to + the padding scheme used in the CA certificate. + +``ocsp_check --timeout=3000 subject issuer`` + Verify an X.509 certificate against the issuers OCSP responder. Pass the + certificate to validate as *subject* and the CA certificate as *issuer*. + +``cert_info --fingerprint file`` + Parse X.509 PEM certificate and display data fields. If ``--fingerprint`` is + used, the certificate's fingerprint is also printed. + +``cert_verify subject *ca_certs`` + Verify if the provided X.509 certificate *subject* can be successfully + validated. The list of trusted CA certificates is passed with *ca_certs*, + which is a list of one or more certificates. + +``trust_roots --dn --dn-only --display`` + List the certificates in the system trust store. + +TLS Server/Client +----------------------- + +The ``--policy=`` argument of the TLS commands specifies the TLS policy to use. +The policy can be any of the the strings "default", "suiteb_128", "suiteb_192", +"bsi", "strict", or "all" to denote built-in policies, or it can name a file +from which a policy description will be read. + +``tls_ciphers --policy=default --version=tls1.2`` + Prints the list of ciphersuites that will be offered under a particular + policy/version. + +``tls_client host --port=443 --print-certs --policy=default --tls1.0 --tls1.1 --tls1.2 --skip-system-cert-store --trusted-cas= --session-db= --session-db-pass= --next-protocols= --type=tcp`` + Implements a testing TLS client, which connects to *host* via TCP or UDP on + port *port*. The TLS version can be set with the flags *tls1.0*, *tls1.1* and + *tls1.2* of which the lowest specified version is automatically chosen. If + none of the TLS version flags is set, the latest supported version is + chosen. The client honors the TLS policy specified with *policy* and + prints all certificates in the chain, if *print-certs* is passed. + *next-protocols* is a comma separated list and specifies the protocols to + advertise with Application-Layer Protocol Negotiation (ALPN). + +``tls_server cert key --port=443 --type=tcp --policy=default --dump-traces= --max-clients=0 --socket-id=0`` + Implements a testing TLS server, which allows TLS clients to connect and which + echos any data that is sent to it. Binds to either TCP or UDP on port + *port*. The server uses the certificate *cert* and the respective PKCS #8 + private key *key*. The server honors the TLS policy specified with *policy*. + *socket-id* is only available on FreeBSD and sets the *so_user_cookie* value + of the used socket. + +``tls_http_server cert key --port=443 --policy=default --threads=0 --max-clients=0 --session-db --session-db-pass=`` + Only available if Boost.Asio support was enabled. Provides a simple HTTP server + which replies to all requests with an informational text output. The server + honors the TLS policy specified with *policy*. + +``tls_proxy listen_port target_host target_port server_cert server_key--policy=default --threads=0 --max-clients=0 --session-db= --session-db-pass=`` + Only available if Boost.Asio support was enabled. Listens on a port and + forwards all connects to a target server specified at + ``target_host`` and ``target_port``. + +``tls_client_hello --hex input`` + Parse and print a TLS client hello message. + +Number Theory +----------------------- +``is_prime --prob=56 n`` + Test if the integer *n* is composite or prime with a Miller-Rabin primality test with *(prob+2)/2* iterations. + +``factor n`` + Factor the integer *n* using a combination of trial division by small primes, and Pollard's Rho algorithm. + It can in reasonable time factor integers up to 110 bits or so. + +``gen_prime --count=1 bits`` + Samples *count* primes with a length of *bits* bits. + +``mod_inverse n mod`` + Calculates a modular inverse. + +PSK Database +-------------------- + +The PSK database commands are only available if sqlite3 support was compiled in. + +``psk_set db db_key name psk`` + Using the PSK database named db and encrypting under the (hex) key ``db_key``, + save the provided psk (also hex) under ``name``:: + + $ botan psk_set psk.db deadba55 bunny f00fee + +``psk_get db db_key name`` + Get back a value saved with ``psk_set``:: + + $ botan psk_get psk.db deadba55 bunny + f00fee + +``psk_list db db_key`` + List all values saved to the database under the given key:: + + $ botan psk_list psk.db deadba55 + bunny + +Secret Sharing +------------------ + +Split a file into several shares. + +``tss_split M N data_file --id= --share-prefix=share --share-suffix=tss --hash=SHA-256`` + Split a file into ``N`` pieces any ``M`` of which suffices to + recover the original input. The ID allows specifying a unique key ID + which may be up to 16 bytes long, this ensures that shares can be + uniquely matched. If not specified a random 16 byte value is + used. A checksum can be appended to the data to help verify correct + recovery, this can be disabled using ``--hash=None``. + +``tss_recover *shares`` + Recover some data split by ``tss_split``. If insufficient number of + shares are provided an error is printed. + +Data Encoding/Decoding +------------------------ + +``base32_dec file`` + Encode *file* to Base32. + +``base32_enc file`` + Decode Base32 encoded *file*. + +``base58_enc --check file`` + Encode *file* to Base58. If ``--check`` is provided Base58Check is used. + +``base58_dec --check file`` + Decode Base58 encoded *file*. If ``--check`` is provided Base58Check is used. + +``base64_dec file`` + Encode *file* to Base64. + +``base64_enc file`` + Decode Base64 encoded *file*. + +``hex_dec file`` + Encode *file* to Hex. + +``hex_enc file`` + Decode Hex encoded *file*. + +Miscellaneous Commands +------------------------------------- +``version --full`` + Print the version number. If option ``--full`` is provided, + additional details are printed. + +``has_command cmd`` + Test if the command *cmd* is available. + +``config info_type`` + Prints build information, useful for applications which want to + build against the library. The ``info_type`` argument can be any of + ``prefix``, ``cflags``, ``ldflags``, or ``libs``. This is + similar to information provided by the ``pkg-config`` tool. + +``cpuid`` + List available processor flags (AES-NI, SIMD extensions, ...). + +``cpu_clock --test-duration=500`` + Estimate the speed of the CPU cycle counter. + +``asn1print --skip-context-specific --print-limit=4096 --bin-limit=2048 --max-depth=64 --pem file``` + Decode and print *file* with ASN.1 Basic Encoding Rules (BER). If flag ``--pem`` is + used, or the filename ends in ``.pem``, then PEM encoding is assumed. Otherwise + the input is assumed to be binary DER/BER. + +``http_get --redirects=1 --timeout=3000 url`` + Retrieve resource from the passed http *url*. + +``speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos`` + Measures the speed of the passed *algos*. If no *algos* are passed all + available speed tests are executed. *msec* (in milliseconds) sets the period + of measurement for each algorithm. The *buf-size* option allows testing the + same algorithm on one or more input sizes, for example + ``speed --buf-size=136,1500 AES-128/GCM`` tests the performance of GCM for + small and large packet sizes. + *format* can be "default", "table" or "json". + +``timing_test test_type --test-data-file= --test-data-dir=src/tests/data/timing --warmup-runs=1000 --measurement-runs=10000`` + Run various timing side channel tests. + +``rng --format=hex --system --rdrand --auto --entropy --drbg --drbg-seed= *bytes`` + Sample *bytes* random bytes from the specified random number generator. If + *system* is set, the system RNG is used. If *rdrand* is set, the hardware + RDRAND instruction is used. If *auto* is set, AutoSeeded_RNG is used, seeded + with the system RNG if available or the global entropy source otherwise. If + *entropy* is set, AutoSeeded_RNG is used, seeded with the global entropy + source. If *drbg* is set, HMAC_DRBG is used seeded with *drbg-seed*. + +``entropy --truncate-at=128 source`` + Sample a raw entropy source. + +``cc_encrypt CC passphrase --tweak=`` + Encrypt the passed valid credit card number *CC* using FPE encryption and the + passphrase *passphrase*. The key is derived from the passphrase using PBKDF2 + with SHA256. Due to the nature of FPE, the ciphertext is also a credit card + number with a valid checksum. *tweak* is public and parameterizes the + encryption function. + +``cc_decrypt CC passphrase --tweak=`` + Decrypt the passed valid ciphertext *CC* using FPE decryption with + the passphrase *passphrase* and the tweak *tweak*. + +``roughtime_check --raw-time chain-file`` + Parse and validate a Roughtime chain file. + +``roughtime --raw-time --chain-file=roughtime-chain --max-chain-size=128 --check-local-clock=60 --host= --pubkey= --servers-file=`` + Retrieve time from a Roughtime server and store it in a chain file. + +``uuid`` + Generate and print a random UUID. + +``compress --type=gzip --level=6 --buf-size=8192 file`` + Compress a given file. + +``decompress --buf-size=8192 file`` + Decompress a given compressed archive. diff --git a/comm/third_party/botan/doc/contents.rst b/comm/third_party/botan/doc/contents.rst new file mode 100644 index 0000000000..dadbd49475 --- /dev/null +++ b/comm/third_party/botan/doc/contents.rst @@ -0,0 +1,25 @@ + +Contents +======================================== + +.. toctree:: + + index + goals + support + building + api_ref/contents + cli + deprecated + roadmap + credits + abi + packaging + security + side_channels + dev_ref/contents + +.. toctree:: + :hidden: + + old_news diff --git a/comm/third_party/botan/doc/credits.rst b/comm/third_party/botan/doc/credits.rst new file mode 100644 index 0000000000..a2b48bf243 --- /dev/null +++ b/comm/third_party/botan/doc/credits.rst @@ -0,0 +1,156 @@ + +Credits +======================================== + +This is at least a partial credits-file of people that have contributed +to botan. It is sorted by name and formatted to allow easy grepping +and beautification by scripts. The fields are name (N), email (E), +web-address (W), PGP key ID and fingerprint (P), description (D), +snail-mail address (S), and Bitcoin address (B). + +.. highlight:: none + +:: + + N: Alexander Bluhm + W: https://www.genua.de/ + P: 1E3B BEA4 6C20 EA00 2FFC DE4D C5F4 83AD DEE8 6380 + D: improve support for OpenBSD + S: Kirchheim, Germany + + N: Charles Brockman + W: http://www.securitygenetics.com/ + D: documentation editing + S: Oregon, USA + + N: Simon Cogliani + E: simon.cogliani@tanker.io + W: https://www.tanker.io/ + P: EA73 D0AF 5A81 A61A 8931 C2CA C9AB F2E4 3820 4F25 + D: Getting keystream of ChaCha + S: Paris, France + + N: Martin Doering + E: doering@cdc.informatik.tu-darmstadt.de + D: GF(p) arithmetic + + N: Olivier de Gaalon + D: SQLite encryption codec (src/contrib/sqlite) + + N: Matthias Gierlings + E: matthias.gierlings@hackmanit.de + W: https://www.hackmanit.de/ + P: 39E0 D270 19A4 B356 05D0 29AE 1BD3 49CF 744A 02FF + D: GMAC, Extended Hash-Based Signatures (XMSS) + S: Bochum, Germany + + N: Matthew Gregan + D: Binary file I/O support, allocator fixes + + N: Hany Greiss + D: Windows porting + + N: Manuel Hartl + E: hartl@flexsecure.de + W: http://www.flexsecure.de/ + D: ECDSA, ECDH + + N: Yves Jerschow + E: yves.jerschow@uni-duesseldorf.de + D: Optimizations for memory load/store and HMAC + D: Support for IPv4 addresses in X.509 alternative names + S: Germany + + N: Matt Johnston + D: Allocator fixes and optimizations, decompressor fixes + + N: Peter J. Jones + E: pjones@pmade.org + D: Bzip2 compression module + S: Colorado, USA + + N: Justin Karneges + D: Qt support modules (mutexes and types), X.509 API design + + N: Vojtech Kral + E: vojtech@kral.hk + D: LZMA compression module + S: Czech Republic + + N: Matej Kenda + E: matej.kenda@topit.si + D: Locking in Algo_Registry for Windows OS + S: Slovenia + + N: René Korthaus + E: r.korthaus@sirrix.com + W: https://www.sirrix.com + P: C196 FF9D 3DDC A5E7 F98C E745 9AD0 F9FA 587E 74D6 + D: CI, ECGDSA, ECKCDSA + S: Bochum, Germany + + N: Adam Langley + E: agl@imperialviolet.org + D: Curve25519 + + N: Jack Lloyd + E: jack@randombit.net + W: https://www.randombit.net/ + P: 3F69 2E64 6D92 3BBE E7AE 9258 5C0F 96E8 4EC1 6D6B + B: 1DwxWb2J4vuX4vjsbzaCXW696rZfeamahz + D: Original designer/author, maintainer 2001-current + S: Vermont, USA + + N: Joel Low + D: DLL symbol visibility and Windows DLL support in general + D: Threaded_Fork + + N: Christoph Ludwig + E: ludwig@fh-worms.de + D: GP(p) arithmetic + + N: Vaclav Ovsik + E: vaclav.ovsik@i.cz + D: Perl XS module (src/contrib/perl-xs) + + N: Luca Piccarreta + E: luca.piccarreta@gmail.com + D: x86/amd64 assembler, BigInt optimizations, Win32 mutex module + S: Italy + + N: Daniel Seither + E: post@tiwoc.de + D: iOS support, improved Android support, improved MSVC support + + N: Falko Strenzke + E: fstrenzke@cryptosource.de + W: http://www.cryptosource.de + D: McEliece, GF(p) arithmetic, CVC, Shanks-Tonelli algorithm + S: Darmstadt, Germany + + N: Simon Warta + E: simon@kullo.net + W: https://www.kullo.net + D: Build system + S: Germany + + N: Philipp Weber + E: p.weber@sirrix.com + W: https://sirrix.com/ + D: KDF1-18033, ECIES + S: Saarland, Germany + + N: Daniel Neus + E: d.neus@sirrix.com + W: https://sirrix.com/ + D: CI, PKCS#11, RdSeed, BSI module policy + S: Bochum, Germany + + N: Erwan Chaussy + D: Base32, Base64 matching Base32 implementation + S: France + + N: Daniel Wyatt (on behalf of Ribose Inc) + E: daniel.wyatt@ribose.com + W: https://www.ribose.com/ + D: SM3, Streebog, various minor contributions diff --git a/comm/third_party/botan/doc/deprecated.rst b/comm/third_party/botan/doc/deprecated.rst new file mode 100644 index 0000000000..e306786201 --- /dev/null +++ b/comm/third_party/botan/doc/deprecated.rst @@ -0,0 +1,302 @@ +Deprecated Features +======================== + +Certain functionality is deprecated and is likely to be removed in +a future major release. + +To help warn users, macros are used to annotate deprecated functions +and headers. These warnings are enabled by default, but can be +disabled by defining the macro ``BOTAN_NO_DEPRECATED_WARNINGS`` prior +to including any Botan headers. + +.. warning:: + Not all of the functionality which is currently deprecated has an + associated warning. + +If you are using something which is currently deprecated and there +doesn't seem to be an obvious alternative, contact the developers to +explain your use case if you want to make sure your code continues to +work. + +TLS Protocol Deprecations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following TLS protocol features are deprecated and will be removed +in a future major release: + +- Support for TLSv1.0/v1.1 and DTLS v1.0 + +- All support for DSA ciphersuites/certificates + +- Support for point compression in TLS. This is supported in v1.2 but + removed in v1.3. For simplicity it will be removed in v1.2 also. + +- Support for using SHA-1 to sign TLS v1.2 ServerKeyExchange. + +- All CBC mode ciphersuites. This includes all available 3DES and SEED + ciphersuites. This implies also removing Encrypt-then-MAC extension. + +- All ciphersuites using DH key exchange (DHE-DSS, DHE-RSA, DHE-PSK, anon DH) + +- Support for renegotiation in TLS v1.2 + +- All ciphersuites using static RSA key exchange + +- All anonymous (DH/ECDH) ciphersuites. This does not include PSK and + ECDHE-PSK, which will be retained. + +- SRP ciphersuites. This is implied by the removal of CBC mode, since + all available SRP ciphersuites use CBC. To avoid use of obsolete + ciphers, it would be better to instead perform a standard TLS + negotiation, then a PAKE authentication within (and bound to) the + TLS channel. + +- OCB ciphersuites using 128-bit keys + +Deprecated Functionality +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This section lists cryptographic functionality which will be removed +in a future major release. + +- Block ciphers CAST-256, GOST 28147, Kasumi, MISTY1, DESX, XTEA, Noekeon + +- Hash functions GOST 34.11-94, Tiger, MD4 + +- X9.42 KDF + +- DLIES + +- MCEIES + +- CBC-MAC + +- PBKDF1 key derivation + +- GCM support for 64-bit tags + +- Weak or rarely used ECC builtin groups including "secp160k1", "secp160r1", + "secp160r2", "secp192k1", "secp224k1", + "brainpool160r1", "brainpool192r1", "brainpool224r1", "brainpool320r1", + "x962_p192v2", "x962_p192v3", "x962_p239v1", "x962_p239v2", "x962_p239v3". + +- All built in MODP groups < 2048 bits + +- Support for explicit ECC curve parameters and ImplicitCA encoded parameters in + EC_Group and all users (including X.509 certificates and PKCS#8 private keys). + +- All pre-created DSA groups + +- All support for loading, generating or using RSA keys with a public + exponent larger than 2**64-1 + +- All or nothing package transform (``package.h``) + + +Deprecated Headers +^^^^^^^^^^^^^^^^^^^^^^ + +* The following headers and all functionality contained within them + are outright deprecated, and will be removed entirely in a future + major release. Most are either simply forwarding includes to another + (still public) header, or contain functionality which is entirely + deprecated. Consult the relevent file for more information. + ``basefilt.h``, ``botan.h``, ``buf_filt.h``, ``cipher_filter.h``, ``comp_filter.h``, + ``compiler.h``, ``init.h``, ``key_filt.h``, ``lookup.h``, ``sm2_enc.h``, ``threefish.h``, + ``xmss_key_pair.h`` + +* The following headers have useful functionality but which we wish to + hide from applications to allow easier library evolution. They will + be made internal in a future major release, and will only be + available to the library itself. In most cases, there is an + alternative available. For example instead of using algorithm + specific interfaces, use X::create to create the object dynamically. + + Block cipher headers (interact using BlockCipher interface): + ``aes.h``, + ``aria.h``, + ``blowfish.h``, + ``camellia.h``, + ``cascade.h``, + ``cast128.h``, + ``cast256.h``, + ``des.h``, + ``desx.h``, + ``gost_28147.h``, + ``idea.h``, + ``kasumi.h``, + ``lion.h``, + ``misty1.h``, + ``noekeon.h``, + ``seed.h``, + ``serpent.h``, + ``shacal2.h``, + ``sm4.h``, + ``threefish_512.h``, + ``twofish.h``, + ``xtea.h``, + + Hash function headers (interact using HashFunction interface): + ``adler32.h``, + ``blake2b.h``, + ``comb4p.h``, + ``crc24.h``, + ``crc32.h``, + ``gost_3411.h``, + ``keccak.h``, + ``md4.h``, + ``md5.h``, + ``par_hash.h``, + ``rmd160.h``, + ``sha160.h``, + ``sha2_32.h``, + ``sha2_64.h``, + ``sha3.h``, + ``shake.h``, + ``skein_512.h``, + ``sm3.h``, + ``streebog.h``, + ``tiger.h``, + ``whrlpool.h``, + + MAC headers: + ``cbc_mac.h``, + ``cmac.h``, + ``gmac.h``, + ``hmac.h``, + ``poly1305.h``, + ``siphash.h``, + ``x919_mac.h``, + + Stream cipher headers: + ``chacha.h``, + ``ctr.h``, + ``ofb.h``, + ``rc4.h``, + ``salsa20.h``, + + Cipher mode headers: + ``cbc.h``, + ``ccm.h``, + ``cfb.h``, + ``chacha20poly1305.h``, + ``eax.h``, + ``gcm.h``, + ``ocb.h``, + ``shake_cipher.h``, + ``siv.h``, + ``xts.h``, + + KDF headers: + ``hkdf.h``, + ``kdf1.h``, + ``kdf1_iso18033.h``, + ``kdf2.h``, + ``prf_tls.h``, + ``prf_x942.h``, + ``sp800_108.h``, + ``sp800_56a.h``, + ``sp800_56c.h``, + + PBKDF headers: + ``bcrypt_pbkdf.h``, + ``pbkdf1.h``, + ``pbkdf2.h``, + ``pgp_s2k.h``, + ``scrypt.h``, + + Internal implementation headers - seemingly no reason for applications to use: + ``blinding.h``, + ``curve_gfp.h``, + ``curve_nistp.h``, + ``datastor.h``, + ``divide.h``, + ``eme.h``, + ``eme_pkcs.h``, + ``eme_raw.h``, + ``emsa.h``, + ``emsa1.h``, + ``emsa_pkcs1.h``, + ``emsa_raw.h``, + ``emsa_x931.h``, + ``gf2m_small_m.h``, + ``ghash.h``, + ``iso9796.h``, + ``keypair.h``, + ``mdx_hash.h``, + ``mode_pad.h``, + ``mul128.h``, + ``oaep.h``, + ``pbes2.h``, + ``polyn_gf2m.h``, + ``pow_mod.h``, + ``pssr.h``, + ``reducer.h``, + ``rfc6979.h``, + ``scan_name.h``, + ``stream_mode.h``, + ``tls_algos.h``, + ``tls_magic.h``, + ``xmss_common_ops.h``, + ``xmss_hash.h``, + ``xmss_index_registry.h``, + ``xmss_tools.h``, + + Utility headers, nominally useful in applications but not a core part of + the library API and most are just sufficient for what the library needs + to implement other functionality. + ``atomic.h``, + ``bswap.h``, + ``charset.h``, + ``compiler.h``, + ``cpuid.h``, + ``http_util.h``, + ``loadstor.h``, + ``locking_allocator.h``, + ``parsing.h``, + ``rotate.h``, + ``secqueue.h``, + ``stl_compatibility.h``, + ``uuid.h``, + + Merged into other headers: + ``alg_id.h``, ``asn1_oid.h``, ``asn1_str.h``, and ``asn1_time.h`` - use ``asn1_obj.h`` + +Other API deprecations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Directly accessing the member variables of types ``calendar_point``, + ``ASN1_Attribute``, ``AlgorithmIdentifier``, and ``BER_Object`` + +- Using a default output length for "SHAKE-128" and "SHAKE-256". Instead, + always specify the desired output length. + +- Currently, for certain KDFs, if KDF interface is invoked with a + requested output length larger than supported by the KDF, it returns + instead a truncated key. In a future major release, instead if KDF + is called with a length larger than it supports an exception will be + thrown. + +- The TLS constructors taking ``std::function`` for callbacks. Instead + use the ``TLS::Callbacks`` interface. + +- Using ``X509_Certificate::subject_info`` and ``issuer_info`` to access any + information that is not included in the DN or subject alternative name. Prefer + using the specific assessor functions for other data, eg instead of + ``cert.subject_info("X509.Certificate.serial")`` use ``cert.serial_number()``. + +- The ``Buffered_Computation`` base class. In a future release the + class will be removed, and all of member functions instead declared + directly on ``MessageAuthenticationCode`` and ``HashFunction``. So + this only affects you if you are directly referencing + ``Botan::Buffered_Computation`` in some way. + +Deprecated Build Targets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Configuring a build (with ``configure.py``) using Python2. In a future + major release, Python3 will be required. + +- Platform support for Google Native Client + +- Support for PathScale and HP compilers diff --git a/comm/third_party/botan/doc/dev_ref/configure.rst b/comm/third_party/botan/doc/dev_ref/configure.rst new file mode 100644 index 0000000000..7eb8358edf --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/configure.rst @@ -0,0 +1,407 @@ +Understanding configure.py +============================ + +.. highlight:: none + +Botan's build is handled with a custom Python script, ``configure.py``. +This document tries to explain how configure works. + +.. note:: + You only need to read this if you are modifying the library, + or debugging some problem with your build. For how to use it, + see :ref:`building`. + +Build Structure +-------------------- + +Modules are a group of related source and header files, which can be +individually enabled or disabled at build time. Modules can depend on +other modules; if a dependency is not available then the module itself +is also removed from the list. Examples of modules in the existing +codebase are ``asn1`` and ``x509``, Since ``x509`` depends on (among +other things) ``asn1``, disabling ``asn1`` will also disable ``x509``. + +Most modules define one or more macros, which application code can use +to detect the modules presence or absence. The value of each macro is +a datestamp, in the form YYYYMMDD which indicates the last time this +module changed in a way that would be visible to an application. For +example if a class gains a new function, the datestamp should be +incremented. That allows applications to detect if the new feature is +available. + +What ``configure.py`` does +----------------------------- + +First, all command line options are parsed. + +Then all of the files giving information about target CPUs, compilers, +etc are parsed and sanity checked. + +In ``calculate_cc_min_version`` the compiler version is detected using +the preprocessor. + +Then in ``check_compiler_arch`` the target architecture are detected, again +using the preprocessor. + +Now that the target is identified and options have been parsed, the modules to +include into the artifact are picked, in ``ModulesChooser``. + +In ``create_template_vars``, a dictionary of variables is created which describe +different aspects of the build. These are serialized to +``build/build_config.json``. + +Up until this point no changes have been made on disk. This occurs in +``do_io_for_build``. Build output directories are created, and header files are +linked into ``build/include/botan``. Templates are processed to create the +Makefile, ``build.h`` and other artifacts. + +When Modifying ``configure.py`` +-------------------------------- + +For now, any changes to ``configure.py`` must work under both CPython 2.7 and +CPython 3.x. In a future major release, support for CPython2 will be dropped, +but until then if making modifications verify the code works as expected on +both versions. + +Run ``./src/scripts/ci_build.py lint`` to run Pylint checks after any change. + +Template Language +-------------------- + +Various output files are generated by processing input files using a simple +template language. All input files are stored in ``src/build-data`` and use the +suffix ``.in``. Anything not recognized as a template command is passed through +to the output unmodified. The template elements are: + + * Variable substitution, ``%{variable_name}``. The configure script creates + many variables for various purposes, this allows getting their value within + the output. If a variable is not defined, an error occurs. + + If a variable reference ends with ``|upper``, the value is uppercased before + being inserted into the template output. + + * Iteration, ``%{for variable} block %{endfor}``. This iterates over a list and + repeats the block as many times as it is included. Variables within the block + are expanded. The two template elements ``%{for ...}`` and ``%{endfor}`` must + appear on lines with no text before or after. + + * Conditional inclusion, ``%{if variable} block %{endif}``. If the variable + named is defined and true (in the Python sense of the word; if the variable + is empty or zero it is considered false), then the block will be included and + any variables expanded. As with the for loop syntax, both the start and end + of the conditional must be on their own lines with no additional text. + +Adding a new module +-------------------- + +Create a directory in the appropriate place and create a info.txt file. + +Syntax of ``info.txt`` +------------------------ + +.. warning:: + + The syntax described here is documented to make it easier to use + and understand, but it is not considered part of the public API + contract. That is, the developers are allowed to change the syntax + at any time on the assumption that all users are contained within + the library itself. If that happens this document will be updated. + +Modules and files describing information about the system use the same +parser and have common syntactical elements. + +Comments begin with '#' and continue to end of line. + +There are three main types: maps, lists, and variables. + +A map has a syntax like:: + + + NAME1 -> VALUE1 + NAME2 -> VALUE2 + ... + + +The interpretation of the names and values will depend on the map's name +and what type of file is being parsed. + +A list has similar syntax, it just doesn't have values:: + + + ELEM1 + ELEM2 + ... + + +Lastly there are single value variables like:: + + VAR1 SomeValue + VAR2 "Quotes Can Be Used (And will be stripped out)" + VAR3 42 + +Variables can have string, integer or boolean values. Boolean values +are specified with 'yes' or 'no'. + +Module Syntax +--------------------- + +The ``info.txt`` files have the following elements. Not all are required; a minimal +file for a module with no dependencies might just contain a macro define. + +Lists: + * ``comment`` and ``warning`` provides block-comments which + are displayed to the user at build time. + * ``requires`` is a list of module dependencies. An ``os_features`` can be + specified as a condition for needing the dependency by writing it before + the module name and separated by a ``?``, e.g. ``rtlgenrandom?dyn_load``. + * ``header:internal`` is the list of headers (from the current module) + which are internal-only. + * ``header:public`` is a the list of headers (from the + current module) which should be exported for public use. If neither + ``header:internal`` nor ``header:public`` are used then all headers + in the current directory are assumed public. + + .. note:: If you omit a header from both internal and public lists, it will + be ignored. + + * ``header:external`` is used when naming headers which are included + in the source tree but might be replaced by an external version. This is used + for the PKCS11 headers. + * ``arch`` is a list of architectures this module may be used on. + * ``isa`` lists ISA features which must be enabled to use this module. + Can be proceeded by an ``arch`` name followed by a ``:`` if it is only needed + on a specific architecture, e.g. ``x86_64:ssse3``. + * ``cc`` is a list of compilers which can be used with this module. If the + compiler name is suffixed with a version (like "gcc:5.0") then only compilers + with that minimum version can use the module. + * ``os_features`` is a list of OS features which are required in order to use this + module. Each line can specify one or more features combined with ','. Alternatives + can be specified on additional lines. + +Maps: + * ``defines`` is a map from macros to datestamps. These macros will be defined in + the generated ``build.h``. + * ``libs`` specifies additional libraries which should be linked if this module is + included. It maps from the OS name to a list of libraries (comma seperated). + * ``frameworks`` is a macOS/iOS specific feature which maps from an OS name to + a framework. + +Variables: + * ``load_on`` Can take on values ``never``, ``always``, ``auto``, ``dep`` or ``vendor``. + TODO describe the behavior of these + * ``endian`` Required endian for the module (``any`` (default), ``little``, ``big``) + +An example:: + + # Disable this by default + load_on never + + + sse2 + + + + DEFINE1 -> 20180104 + DEFINE2 -> 20190301 + + + + I have eaten + the plums + that were in + the icebox + + + + There are no more plums + + + + header1.h + + + + header_helper.h + whatever.h + + + + x86_64 + + + + gcc:4.9 # gcc 4.8 doesn't work for + clang + + + # Can work with POSIX+getentropy or Win32 + + posix1,getentropy + win32 + + + + macos -> FramyMcFramerson + + + + qnx -> foo,bar,baz + solaris -> socket + + +Supporting a new CPU type +--------------------------- + +CPU information is stored in ``src/build-data/arch``. + +There is also a file ``src/build-data/detect_arch.cpp`` which is used +for build-time architecture detection using the compiler preprocessor. +Supporting this is optional but recommended. + +Lists: + * ``aliases`` is a list of alternative names for the CPU architecture. + * ``isa_extensions`` is a list of possible ISA extensions that can be used on + this architecture. For example x86-64 has extensions "sse2", "ssse3", + "avx2", "aesni", ... + +Variables: + * ``endian`` if defined should be "little" or "big". This can also be + controlled or overridden at build time. + * ``family`` can specify a family group for several related architecture. + For example both x86_32 and x86_64 use ``family`` of "x86". + * ``wordsize`` is the default wordsize, which controls the size of limbs + in the multi precision integers. If not set, defaults to 32. + +Supporting a new compiler +--------------------------- + +Compiler information is stored in ``src/build-data/cc``. Looking over +those files will probably help understanding, especially the ones for +GCC and Clang which are most complete. + +In addition to the info file, for compilers there is a file +``src/build-data/detect_version.cpp``. The ``configure.py`` script runs the +preprocessor over this file to attempt to detect the compiler +version. Supporting this is not strictly necessary. + +Maps: + * ``binary_link_commands`` gives the command to use to run the linker, + it maps from operating system name to the command to use. It uses + the entry "default" for any OS not otherwise listed. + * ``cpu_flags_no_debug`` unused, will be removed + * ``cpu_flags`` used to emit CPU specific flags, for example LLVM + bitcode target uses ``-emit-llvm`` flag. Rarely needed. + * ``isa_flags`` maps from CPU extensions (like NEON or AES-NI) to + compiler flags which enable that extension. These have the same name + as the ISA flags listed in the architecture files. + * ``lib_flags`` has a single possible entry "debug" which if set maps + to additional flags to pass when building a debug library. + Rarely needed. + * ``mach_abi_linking`` specifies flags to enable when building and + linking on a particular CPU. This is usually flags that modify + ABI. There is a special syntax supported here + "all!os1,arch1,os2,arch2" which allows setting ABI flags which are + used for all but the named operating systems and/or architectures. + * ``sanitizers`` is a map of sanitizers the compiler supports. It must + include "default" which is a list of sanitizers to include by default + when sanitizers are requested. The other keys should map to compiler + flags. + * ``so_link_commands`` maps from operating system to the command to + use to build a shared object. + +Variables: + * ``binary_name`` the default name of the compiler binary. + * ``linker_name`` the name of the linker to use with this compiler. + * ``macro_name`` a macro of the for ``BOTAN_BUILD_COMPILER_IS_XXX`` + will be defined. + * ``output_to_object`` (default "-o") gives the compiler option used to + name the output object. + * ``output_to_exe`` (default "-o") gives the compiler option used to + name the output object. + * ``add_include_dir_option`` (default "-I") gives the compiler option used + to specify an additional include dir. + * ``add_lib_dir_option`` (default "-L") gives the compiler option used + to specify an additional library dir. + * ``add_sysroot_option`` gives the compiler option used to specify the sysroot. + * ``add_lib_option`` (default "-l%s") gives the compiler option to + link in a library. ``%s`` will be replaced with the library name. + * ``add_framework_option`` (default "-framework") gives the compiler option + to add a macOS framework. + * ``preproc_flags`` (default "-E") gives the compiler option used to run + the preprocessor. + * ``compile_flags`` (default "-c") gives the compiler option used to compile a file. + * ``debug_info_flags`` (default "-g") gives the compiler option used to enable debug info. + * ``optimization_flags`` gives the compiler optimization flags to use. + * ``size_optimization_flags`` gives compiler optimization flags to use when + compiling for size. If not set then ``--optimize-for-size`` will use + the default optimization flags. + * ``sanitizer_optimization_flags`` gives compiler optimization flags to use + when building with sanitizers. + * ``coverage_flags`` gives the compiler flags to use when generating coverage + information. + * ``stack_protector_flags`` gives compiler flags to enable stack overflow checking. + * ``shared_flags`` gives compiler flags to use when generation shared libraries. + * ``lang_flags`` gives compiler flags used to enable the required version of C++. + * ``warning_flags`` gives warning flags to enable. + * ``maintainer_warning_flags`` gives extra warning flags to enable during maintainer + mode builds. + * ``visibility_build_flags`` gives compiler flags to control symbol visibility + when generation shared libraries. + * ``visibility_attribute`` gives the attribute to use in the ``BOTAN_DLL`` macro + to specify visibility when generation shared libraries. + * ``ar_command`` gives the command to build static libraries + * ``ar_options`` gives the options to pass to ``ar_command``, if not set here + takes this from the OS specific information. + * ``ar_output_to`` gives the flag to pass to ``ar_command`` to specify where to + output the static library. + * ``werror_flags`` gives the complier flags to treat warnings as errors. + +Supporting a new OS +--------------------------- + +Operating system information is stored in ``src/build-data/os``. + +Lists: + * ``aliases`` is a list of alternative names which will be accepted + * ``target_features`` is a list of target specific OS features. Some of these + are supported by many OSes (for example "posix1") others are specific to + just one or two OSes (such as "getauxval"). Adding a value here causes a new + macro ``BOTAN_TARGET_OS_HAS_XXX`` to be defined at build time. Use + ``configure.py --list-os-features`` to list the currently defined OS + features. + * ``feature_macros`` is a list of macros to define. + +Variables: + * ``ar_command`` gives the command to build static libraries + * ``ar_options`` gives the options to pass to ``ar_command`` + * ``ar_output_to`` gives the flag to pass to ``ar_command`` to specify where to + output the static library. + * ``bin_dir`` (default "bin") specifies where binaries should be installed, + relative to install_root. + * ``cli_exe_name`` (default "botan") specifies the name of the command line utility. + * ``default_compiler`` specifies the default compiler to use for this OS. + * ``doc_dir`` (default "doc") specifies where documentation should be installed, + relative to install_root + * ``header_dir`` (default "include") specifies where include files + should be installed, relative to install_root + * ``install_root`` (default "/usr/local") specifies where to install + by default. + * ``lib_dir`` (default "lib") specifies where library should be installed, + relative to install_root. + * ``lib_prefix`` (default "lib") prefix to add to the library name + * ``library_name`` + * ``man_dir`` specifies where man files should be installed, relative to install_root + * ``obj_suffix`` (default "o") specifies the suffix used for object files + * ``program_suffix`` (default "") specifies the suffix used for executables + * ``shared_lib_symlinks`` (default "yes) specifies if symbolic names should be + created from the base and patch soname to the library name. + * ``soname_pattern_abi`` + * ``soname_pattern_base`` + * ``soname_pattern_patch`` + * ``soname_suffix`` file extension to use for shared library if ``soname_pattern_base`` + is not specified. + * ``static_suffix`` (default "a") file extension to use for static library. + * ``use_stack_protector`` (default "true") specify if by default stack smashing + protections should be enabled. + * ``uses_pkg_config`` (default "yes") specify if by default a pkg-config file + should be created. diff --git a/comm/third_party/botan/doc/dev_ref/contents.rst b/comm/third_party/botan/doc/dev_ref/contents.rst new file mode 100644 index 0000000000..6505762e1f --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/contents.rst @@ -0,0 +1,20 @@ +Developer Reference +===================== + +This section contains information useful to people making +contributions to the library + +.. toctree:: + :maxdepth: 1 + + contributing + configure + test_framework + continuous_integration + fuzzing + release_process + todo + os + oids + reading_list + mistakes diff --git a/comm/third_party/botan/doc/dev_ref/continuous_integration.rst b/comm/third_party/botan/doc/dev_ref/continuous_integration.rst new file mode 100644 index 0000000000..a109301e66 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/continuous_integration.rst @@ -0,0 +1,75 @@ +Continuous Integration and Automated Testing +=============================================== + +CI Build Script +---------------- + +The Travis and AppVeyor builds are orchestrated using a script +``src/scripts/ci_build.py``. This allows one to easily reproduce the CI process +on a local machine. + +Travis CI +----------- + +https://travis-ci.com/github/randombit/botan + +This is the primary CI, and tests the Linux, macOS, and iOS builds. Among other +things it runs tests using valgrind, compilation on various architectures +(currently including ARM, PPC64, and S390x), MinGW build, and a build that +produces the coverage report. + +The Travis configurations is in ``src/scripts/ci/travis.yml``, which executes a +setup script ``src/scripts/ci/setup_travis.sh`` to install needed packages. +Then ``src/scripts/ci_build.py`` is invoked. + +AppVeyor +---------- + +https://ci.appveyor.com/project/randombit/botan + +Runs a build/test cycle using MSVC on Windows. Like Travis it uses +``src/scripts/ci_build.py``. The AppVeyor setup script is in +``src/scripts/ci/setup_appveyor.bat`` + +The AppVeyor build uses `sccache `_ as a +compiler cache. Since that is not available in the AppVeyor images, the setup +script downloads a release binary from the upstream repository. + +LGTM +--------- + +https://lgtm.com/projects/g/randombit/botan/ + +An automated linter that is integrated with Github. It automatically checks each +incoming PR. It also supports custom queries/alerts, which likely would be worth +investigating but is not something currently in use. + +Coverity +--------- + +https://scan.coverity.com/projects/624 + +An automated source code scanner. Use of Coverity scanner is rate-limited, +sometimes it is very slow to produce a new report, and occasionally the service +goes offline for days or weeks at a time. New reports are kicked off manually by +rebasing branch ``coverity_scan`` against the most recent master and force +pushing it. + +Sonar +------- + +https://sonarcloud.io/dashboard?id=botan + +Sonar scanner is another software quality scanner. Unfortunately a recent update +of their scanner caused it to take over an hour to produce a report which caused +Travis CI timeouts, so it has been disabled. It should be re-enabled to run on +demand in the same way Coverity is. + +OSS-Fuzz +---------- + +https://github.com/google/oss-fuzz/ + +OSS-Fuzz is a distributed fuzzer run by Google. Every night, each library fuzzers +in ``src/fuzzer`` are built and run on many machines, with any findings reported +to the developers via email. diff --git a/comm/third_party/botan/doc/dev_ref/contributing.rst b/comm/third_party/botan/doc/dev_ref/contributing.rst new file mode 100644 index 0000000000..f6effb3f36 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/contributing.rst @@ -0,0 +1,268 @@ + +Notes for New Contributors +=================================== + +Source Code Layout +------------------------------------------------- + +Under ``src`` there are directories + +* ``lib`` is the library itself, more on that below +* ``cli`` is the command line application ``botan`` +* ``tests`` contain what you would expect. Input files go under ``tests/data``. +* ``build-data`` contains files read by the configure script. For + example ``build-data/cc/gcc.txt`` describes various gcc options. +* ``scripts`` contains misc scripts: install, distribution, various + codegen things. Scripts controlling CI go under ``scripts/ci``. +* ``configs`` contains configuration files for emacs, astyle, pylint, etc +* ``python/botan2.py`` is the Python ctypes wrapper + +Library Layout +---------------------------------------- + +* ``base`` defines some high level types +* ``utils`` contains various utility functions and types +* ``codec`` has hex, base64 +* ``block`` contains the block cipher implementations +* ``modes`` contains block cipher modes (CBC, GCM, etc) +* ``stream`` contains the stream ciphers +* ``hash`` contains the hash function implementations +* ``passhash`` contains password hashing algorithms for authentication +* ``kdf`` contains the key derivation functions +* ``mac`` contains the message authentication codes +* ``pbkdf`` contains password hashing algorithms for key derivation +* ``math`` is the big integer math library. It is divided into three parts: + ``mp`` which are the low level algorithms; ``bigint`` which is a C++ wrapper + around ``mp``, and ``numbertheory`` which contains higher level algorithms like + primality testing and exponentiation +* ``pubkey`` contains the public key algorithms +* ``pk_pad`` contains padding schemes for public key algorithms +* ``rng`` contains the random number generators +* ``entropy`` has various entropy sources used by some of the RNGs +* ``asn1`` is the DER encoder/decoder +* ``x509`` is X.509 certificates, PKCS #10 requests, OCSP +* ``tls`` contains the TLS implementation +* ``filters`` is a filter/pipe API for data transforms +* ``compression`` has the compression wrappers (zlib, bzip2, lzma) +* ``ffi`` is the C99 API +* ``prov`` contains bindings to external libraries like OpenSSL and PKCS #11 +* ``misc`` contains odds and ends: format preserving encryption, SRP, threshold + secret sharing, all or nothing transform, and others + +Sending patches +---------------------------------------- + +All contributions should be submitted as pull requests via GitHub +(https://github.com/randombit/botan). If you are planning a large +change email the mailing list or open a discussion ticket on github +before starting out to make sure you are on the right path. And once +you have something written, free to open a [WIP] PR for early review +and comment. + +If possible please sign your git commits using a PGP key. +See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for +instructions on how to set this up. + +Depending on what your change is, your PR should probably also include an update +to ``news.rst`` with a note explaining the change. If your change is a +simple bug fix, a one sentence description is perhaps sufficient. If there is an +existing ticket on GitHub with discussion or other information, reference it in +your change note as 'GH #000'. + +Update ``doc/credits.txt`` with your information so people know what you did! + +If you are interested in contributing but don't know where to start check out +``doc/dev_ref/todo.rst`` for some ideas - these are changes we would almost +certainly accept once they've passed code review. + +Also, try building and testing it on whatever hardware you have handy, +especially unusual platforms, or using C++ compilers other than the regularly +tested GCC, Clang, and Visual Studio. + +FFI Additions +---------------- + +If adding a new function declaration to ``ffi.h``, the same PR must +also add the same declaration in the Python binding ``botan2.py``, in +addition the new API functionality must be exposed to Python and a +test written in Python. + +Git Usage +---------------------------------------- + +Do *NOT* merge ``master`` into your topic branch, this creates +needless commits and noise in history. Instead, as needed, rebase your +branch against master (``git rebase -i master``) and force push the +branch to update the PR. If the GitHub PR page does not report any +merge conflicts and nobody asks you to rebase, you don't need to +rebase. + +Try to keep your history clean and use rebase to squash your commits +as needed. If your diff is less than roughly 100 lines, it should +probably be a single commit. Only split commits as needed to help with +review/understanding of the change. + +Python +---------------------------------------- + +Scripts should be in Python whenever possible. + +For configure.py (and helper scripts install.py, cleanup.py and build_docs.py) +the target is stock (no modules outside the standard library) CPython 2.7 plus +latest CPython 3.x. Support for CPython 2.6, PyPy, etc is great when viable (in +the sense of not causing problems for 2.7 or 3.x, and not requiring huge blocks +of version dependent code). As running this program successfully is required for +a working build, making it as portable as possible is considered key. + +The python wrapper botan2.py targets CPython 2.7, 3.x, and latest PyPy. Note that +a single file is used to avoid dealing with any of Python's various crazy module +distribution issues. + +For random scripts not typically run by an end-user (codegen, visualization, and +so on) there isn't any need to worry about 2.6 and even just running under +Python2 xor Python3 is acceptable if needed. Here it's fine to depend on any +useful modules such as graphviz or matplotlib, regardless if it is available +from a stock CPython install. Since Python2 is now end of life, prefer Python3 +for new scripts of this sort. + +Build Tools and Hints +---------------------------------------- + +If you don't already use it for all your C/C++ development, install ``ccache`` +(or on Windows, ``sccache``) right now, and configure a large cache on a fast +disk. It allows for very quick rebuilds by caching the compiler output. + +Use ``--enable-sanitizers=`` flag to enable various sanitizer checks. Supported +values including "address" and "undefined" for GCC and Clang. GCC also supports +"iterator" (checked iterators), and Clang supports "memory" (MSan) and +"coverage" (for fuzzing). + +On Linux if you have the ``lcov`` and ``gcov`` tools installed, then running +``./src/scripts/ci_build.py coverage`` will produce a coverage enabled build, +run the tests, test the fuzzers against a corpus, and produce an HTML report +of total coverage. This coverage build requires the development headers for +zlib, bzip2, liblzma, OpenSSL, TrouSerS (libtspi), and Sqlite3. + +Copyright Notice +---------------------------------------- + +At the top of any new file add a comment with a copyright and a reference to the +license, for example:: + + /* + * (C) 20xx Copyright Holder + * Botan is released under the Simplified BSD License (see license.txt) + */ + +If you are making a substantial or non-trivial change to an existing file, add +or update your own copyright statement at the top of each file. + +Style Conventions +---------------------------------------- + +When writing your code remember the need for it to be easily understood by +reviewers and auditors, both at the time of the patch submission and in the +future. + +Avoid complicated template metaprogramming where possible. It has its places but +should be used judiciously. + +When designing a new API (for use either by library users or just internally) +try writing out the calling code first. That is, write out some code calling +your idealized API, then just implement that API. This can often help avoid +cut-and-paste by creating the correct abstractions needed to solve the problem +at hand. + +The C++11 ``auto`` keyword is very convenient but only use it when the type +truly is obvious (considering also the potential for unexpected integer +conversions and the like, such as an apparent uint8_t being promoted to an int). + +If a variable is defined and not modified, declare it ``const``. Some exception +for very short-lived variables, but generally speaking being able to read the +declaration and know it will not be modified is useful. + +Use ``override`` annotations whenever overriding a virtual function. If +introducing a new type that is not intended for derivation, mark it ``final``. + +Avoid explicit ``delete`` - use RAII. + +Use ``m_`` prefix on all member variables. + +For formatting, there are configs for emacs and astyle in ``src/configs``. +No tabs, and remove trailing whitespace. + +Prefer using braces on both sides of if/else blocks, even if only using a single +statement. The current code doesn't always do this. + +Avoid ``using namespace`` declarations, even inside of single functions. One +allowed exception is ``using namespace std::placeholders`` in functions which +use ``std::bind``. (But, don't use ``std::bind`` - use a lambda instead). + +Use ``::`` to explicitly refer to the global namespace (eg, when calling an OS +or external library function like ``::select`` or ``::sqlite3_open``). + +Use of External Dependencies +---------------------------------------- + +Compiler Dependencies +~~~~~~~~~~~~~~~~~~~~~~~ + +The library should always be as functional as possible when compiled with just +C++11. However, feel free to use the full C++11 language. No accomodations are +made for compilers that are incomplete or buggy. + +Use of compiler extensions is fine whenever appropriate; this is typically +restricted to a single file or an internal header. Compiler extensions used +currently include native uint128_t, SIMD intrinsics, inline asm syntax and so +on, so there are some existing examples of appropriate use. + +Generally intrinsics or inline asm is preferred over bare assembly to avoid +calling convention issues among different platforms; the improvement in +maintainability is seen as worth any potential performance tradeoff. One risk +with intrinsics is that the compiler might rewrite your clever const-time SIMD +into something with a conditional jump, but code intended to be const-time +should in any case be annotated so it can be checked at runtime with tools. + +Operating System Dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're adding a small OS dependency in some larger piece of code, try to +contain the actual non-portable operations to utils/os_utils.* and then call +them from there. + +As a policy, operating systems which are not supported by their original vendor +are not supported by Botan either. Patches that complicate the code in order to +support obsolete operating systems will likely be rejected. In writing OS +specific code, feel free to assume roughly POSIX 2008, or for Windows, Windows 8 +/Server 2012 (which are as of this writing the oldest versions still supported +by Microsoft). + +Some operating systems, such as OpenBSD, only support the latest release. For +such cases, it's acceptable to add code that requires APIs added in the most +recent release of that OS as soon as the release is available. + +Library Dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Any external library dependency - even optional ones - is met with as one PR +submitter put it "great skepticism". + +At every API boundary there is potential for confusion that does not exist when +the call stack is all contained within the boundary. So the additional API +really needs to pull its weight. For example a simple text parser or such which +can be trivially implemented is not really for consideration. As a rough idea of +the bar, equate the viewed cost of an external dependency as at least 1000 +additional lines of code in the library. That is, if the library really does +need this functionality, and it can be done in the library for less than that, +then it makes sense to just write the code. Yup. + +Currently the (optional) external dependencies of the library are OpenSSL (for +access to fast and side channel hardened RSA, ECDSA, AES), some compression +libraries (zlib, bzip2, lzma), sqlite3 database, Trousers (TPM integration), +plus various operating system utilities like basic filesystem operations. These +provide major pieces of functionality which seem worth the trouble of +maintaining an integration with. + +At this point the most plausible examples of an appropriate new external +dependency are all deeper integrations with system level cryptographic systems +(CommonCrypto, CryptoAPI, /dev/crypto, iOS keychain, TPM 2.0, etc) diff --git a/comm/third_party/botan/doc/dev_ref/fuzzing.rst b/comm/third_party/botan/doc/dev_ref/fuzzing.rst new file mode 100644 index 0000000000..46e60fb533 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/fuzzing.rst @@ -0,0 +1,91 @@ +Fuzzing The Library +============================ + +Botan comes with a set of fuzzing endpoints which can be used to test +the library. + +.. highlight:: shell + +Fuzzing with libFuzzer +------------------------ + +To fuzz with libFuzzer (https://llvm.org/docs/LibFuzzer.html), you'll first +need to compile libFuzzer:: + + $ svn co https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libFuzzer + $ cd libFuzzer && clang -c -g -O2 -std=c++11 *.cpp + $ ar cr libFuzzer.a libFuzzer/*.o + +Then build the fuzzers:: + + $ ./configure.py --cc=clang --build-fuzzer=libfuzzer --unsafe-fuzzer-mode \ + --enable-sanitizers=coverage,address,undefined + $ make fuzzers + +Enabling 'coverage' sanitizer flags is required for libFuzzer to work. +Address sanitizer and undefined sanitizer are optional. + +The fuzzer binaries will be in `build/fuzzer`. Simply pick one and run it, optionally +also passing a directory containing corpus inputs. + +Using `libfuzzer` build mode implicitly assumes the fuzzers need to +link with `libFuzzer`; if another library is needed (for example in +OSS-Fuzz, which uses `libFuzzingEngine`), use the flag +`--with-fuzzer-lib` to specify the desired name. + +Fuzzing with AFL +-------------------- + +To fuzz with AFL (http://lcamtuf.coredump.cx/afl/):: + + $ ./configure.py --with-sanitizers --build-fuzzer=afl --unsafe-fuzzer-mode --cc-bin=afl-g++ + $ make fuzzers + +For AFL sanitizers are optional. You can also use `afl-clang-fast++` +or `afl-clang++`, be sure to set `--cc=clang` also. + +The fuzzer binaries will be in `build/fuzzer`. To run them you need to +run under `afl-fuzz`:: + + $ afl-fuzz -i corpus_path -o output_path ./build/fuzzer/binary + +Fuzzing with TLS-Attacker +-------------------------- + +TLS-Attacker (https://github.com/RUB-NDS/TLS-Attacker) includes a mode for fuzzing +TLS servers. A prebuilt copy of TLS-Attacker is available in a git repository:: + + $ git clone --depth 1 https://github.com/randombit/botan-ci-tools.git + +To run it against Botan's server:: + + $ ./configure.py --with-sanitizers + $ make botan + $ ./src/scripts/run_tls_attacker.py ./botan ./botan-ci-tools + +Output and logs from the fuzzer are placed into `/tmp`. See the +TLS-Attacker documentation for more information about how to use this +tool. + +Input Corpus +----------------------- + +AFL requires an input corpus, and libFuzzer can certainly make good +use of it. + +Some crypto corpus repositories include + +* https://github.com/randombit/crypto-corpus +* https://github.com/mozilla/nss-fuzzing-corpus +* https://github.com/google/boringssl/tree/master/fuzz +* https://github.com/openssl/openssl/tree/master/fuzz/corpora + +Adding new fuzzers +--------------------- + +New fuzzers are created by adding a source file to `src/fuzzers` which +have the signature: + +``void fuzz(const uint8_t in[], size_t len)`` + +After adding your fuzzer, rerun ``./configure.py`` and build. diff --git a/comm/third_party/botan/doc/dev_ref/mistakes.rst b/comm/third_party/botan/doc/dev_ref/mistakes.rst new file mode 100644 index 0000000000..6ea9ea927e --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/mistakes.rst @@ -0,0 +1,77 @@ + +Mistakes Were Made +=================== + +These are mistakes made early on in the project's history which are difficult to +fix now, but mentioned in the hope they may serve as an example for others. + +C++ API +--------- + +As an implementation language, I still think C++ is the best choice (or at least +the best choice available in early '00s) at offering good performance, +reasonable abstractions, and low overhead. But the user API should have been +pure C with opaque structs (rather like the FFI layer, which was added much +later). Then an expressive C++ API could be built on top of the C API. This +would have given us a stable ABI, allowed C applications to use the library, and +(these days) make it easier to progressively rewrite the library in Rust. + +Public Algorithm Specific Classes +------------------------------------ + +Classes like AES_128 and SHA_256 should never have been exposed to applications. +Intead such operations should have been accessible only via the higher level +interfaces (here BlockCipher and HashFunction). This would substantially reduce +the overall API and ABI surface. + +These interfaces are now deprecated, and perhaps will be able to be +removed eventually. + +Header Directories +------------------- + +It would have been better to install all headers as ``X/header.h`` +where ``X`` is the base dir in the source, eg ``block/aes128.h``, +``hash/md5.h``, ... + +Exceptions +----------- + +Constant ABI headaches from this, and it impacts performance and makes APIs +harder to understand. Should have been handled with a result<> type instead. + +Virtual inheritance +--------------------- + +This was used in the public key interfaces and the hierarchy is a tangle. +Public and private keys should be distinct classes, with a function on private +keys that creates a new object corresponding to the public key. + +Cipher Interface +------------------ + +The cipher interface taking a secure_vector that it reads from and writes to was +an artifact of an earlier design which supported both compression and encryption +in a single API. But it leads to inefficient copies. + +(I am hoping this issue can be somewhat fixed by introducing a new cipher API +and implementing the old API in terms of the new one.) + +Pipe Interface +---------------- + +On the surface this API seems very convenient and easy to use. And it is. But +the downside is it makes the application code totally opaque; some bytes go into +a Pipe object and then come out the end transformed in some way. What happens in +between? Unless the Pipe was built in the same function and you can see the +parameters to the constructor, there is no way to find out. + +The problems with the Pipe API are documented, and it is no longer used within +the library itself. But since many people seem to like it and many applications +use it, we are stuck at least with maintaining it as it currently exists. + +License +--------- + +MIT is more widely used and doesn't have the ambiguity surrounding the +various flavors of BSD. diff --git a/comm/third_party/botan/doc/dev_ref/oids.rst b/comm/third_party/botan/doc/dev_ref/oids.rst new file mode 100644 index 0000000000..6aac1a5a72 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/oids.rst @@ -0,0 +1,43 @@ +Private OID Assignments +========================== + +The library uses some OIDs under a private arc assigned by IANA, +1.3.6.1.4.1.25258 + +Values currently assigned are:: + + randombit OBJECT IDENTIFIER ::= { 1 3 6 1 4 1 25258 } + + publicKey OBJECT IDENTIFIER ::= { randombit 1 } + + mceliece OBJECT IDENTIFIER ::= { publicKey 3 } + -- { publicKey 4 } previously used as private X25519 + -- { publicKey 5 } previously used for XMSS draft 6 + gost-3410-with-sha256 OBJECT IDENTIFIER ::= { publicKey 6 1 } + kyber OBJECT IDENTIFIER ::= { publicKey 7 } + xmss OBJECT IDENTIFIER ::= { publicKey 8 } + + symmetricKey OBJECT IDENTIFIER ::= { randombit 3 } + + ocbModes OBJECT IDENTIFIER ::= { symmetricKey 2 } + + aes-128-ocb OBJECT IDENTIFIER ::= { ocbModes 1 } + aes-192-ocb OBJECT IDENTIFIER ::= { ocbModes 2 } + aes-256-ocb OBJECT IDENTIFIER ::= { ocbModes 3 } + serpent-256-ocb OBJECT IDENTIFIER ::= { ocbModes 4 } + twofish-256-ocb OBJECT IDENTIFIER ::= { ocbModes 5 } + camellia-128-ocb OBJECT IDENTIFIER ::= { ocbModes 6 } + camellia-192-ocb OBJECT IDENTIFIER ::= { ocbModes 7 } + camellia-256-ocb OBJECT IDENTIFIER ::= { ocbModes 8 } + + sivModes OBJECT IDENTIFIER ::= { symmetricKey 4 } + + aes-128-siv OBJECT IDENTIFIER ::= { sivModes 1 } + aes-192-siv OBJECT IDENTIFIER ::= { sivModes 2 } + aes-256-siv OBJECT IDENTIFIER ::= { sivModes 3 } + serpent-256-siv OBJECT IDENTIFIER ::= { sivModes 4 } + twofish-256-siv OBJECT IDENTIFIER ::= { sivModes 5 } + camellia-128-siv OBJECT IDENTIFIER ::= { sivModes 6 } + camellia-192-siv OBJECT IDENTIFIER ::= { sivModes 7 } + camellia-256-siv OBJECT IDENTIFIER ::= { sivModes 8 } + sm4-128-siv OBJECT IDENTIFIER ::= { sivModes 9 } diff --git a/comm/third_party/botan/doc/dev_ref/os.rst b/comm/third_party/botan/doc/dev_ref/os.rst new file mode 100644 index 0000000000..eee3e09b76 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/os.rst @@ -0,0 +1,61 @@ +OS Features +======================================== + +A summary of OS features as defined in ``src/build-data/os``. + +:: + + a: aix + a: android + c: cygwin + d: dragonfly + e: emscripten + f: freebsd + h: haiku + h: hpux + h: hurd + i: includeos + i: ios + l: linux + l: llvm + m: macos + m: mingw + n: nacl + n: netbsd + o: openbsd + q: qnx + s: solaris + u: uwp + w: windows + +.. csv-table:: + :header: "Feature", "a", "a", "c", "d", "e", "f", "h", "h", "h", "i", "i", "l", "l", "m", "m", "n", "n", "o", "q", "s", "u", "w" + + "apple_keychain", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " " + "arc4random", " ", "X", " ", "X", " ", "X", " ", " ", " ", " ", "X", " ", " ", "X", " ", " ", "X", "X", " ", " ", " ", " " + "cap_enter", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " + "certificate_store", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X" + "clock_gettime", "X", "X", " ", "X", " ", "X", "X", "X", "X", " ", " ", "X", " ", "X", " ", " ", "X", "X", "X", "X", " ", " " + "commoncrypto", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " " + "crypto_ng", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " " + "dev_random", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", " ", "X", " ", " ", "X", "X", "X", "X", " ", " " + "elf_aux_info", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " + "explicit_bzero", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " " + "explicit_memset", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " " + "filesystem", "X", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X", " ", "X", "X", "X", "X", "X", "X" + "getauxval", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " + "getentropy", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", "X", " ", " ", " ", " " + "pledge", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " " + "posix1", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", " ", " ", "X", "X", "X", "X", " ", " " + "posix_mlock", "X", "X", " ", "X", " ", "X", " ", "X", "X", " ", "X", "X", " ", "X", " ", " ", "X", "X", "X", "X", " ", " " + "proc_fs", "X", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", " ", "X", " ", " " + "rtlgenrandom", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", "X" + "rtlsecurezeromemory", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", "X" + "sockets", "X", "X", "X", "X", " ", "X", "X", "X", "X", " ", "X", "X", " ", "X", " ", " ", "X", "X", "X", "X", " ", " " + "threads", "X", "X", "X", "X", " ", "X", "X", "X", "X", " ", "X", "X", " ", "X", "X", "X", "X", "X", "X", "X", "X", "X" + "virtual_lock", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", " ", "X" + "win32", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X", "X" + "winsock2", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", "X" + +.. note:: + This file is auto generated by ``src/scripts/gen_os_features.py``. Dont modify it manually. diff --git a/comm/third_party/botan/doc/dev_ref/reading_list.rst b/comm/third_party/botan/doc/dev_ref/reading_list.rst new file mode 100644 index 0000000000..1b27d05d69 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/reading_list.rst @@ -0,0 +1,93 @@ +Reading List +================ + +These are papers, articles and books that are interesting or useful from the +perspective of crypto implementation. + +Papers +-------- + +Implementation Techniques +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* "Randomizing the Montgomery Powering Ladder" + Le, Tan, Tunstall https://eprint.iacr.org/2015/657 + A variant of Algorithm 7 is used for GF(p) point multplications when + BOTAN_POINTGFP_BLINDED_MULTIPLY_USE_MONTGOMERY_LADDER is set + +* "Accelerating AES with vector permute instructions" + Mike Hamburg https://shiftleft.org/papers/vector_aes/ + His public doman assembly code was rewritten into SSS3 intrinsics + for aes_ssse3. + +* "Elliptic curves and their implementation" Langley + http://www.imperialviolet.org/2010/12/04/ecc.html + Describes sparse representations for ECC math + +Random Number Generation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* "On Extract-then-Expand Key Derivation Functions and an HMAC-based KDF" + Hugo Krawczyk http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.131.8254 + RNG design underlying HMAC_RNG + +AES Side Channels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* "Software mitigations to hedge AES against cache-based software side + channel vulnerabilities" https://eprint.iacr.org/2006/052.pdf + +* "Cache Games - Bringing Access-Based Cache Attacks on AES to Practice" + http://www.ieee-security.org/TC/SP2011/PAPERS/2011/paper031.pdf + +* "Cache-Collision Timing Attacks Against AES" Bonneau, Mironov + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.88.4753 + +Public Key Side Channels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* "Fast Elliptic Curve Multiplications Resistant against Side Channel Attacks" + http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.98.1028&rep=rep1&type=pdf + +* "Resistance against Differential Power Analysis for Elliptic Curve Cryptosystems" + Coron http://www.jscoron.fr/publications/dpaecc.pdf + +* "Further Results and Considerations on Side Channel Attacks on RSA" + Klima, Rosa https://eprint.iacr.org/2002/071 + Side channel attacks on RSA-KEM and MGF1-SHA1 + +* "Side-Channel Attacks on the McEliece and Niederreiter Public-Key Cryptosystems" + Avanzi, Hoerder, Page, and Tunstall https://eprint.iacr.org/2010/479 + +* "Minimum Requirements for Evaluating Side-Channel Attack Resistance + of Elliptic Curve Implementations" BSI + https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Zertifizierung/Interpretationen/AIS_46_ECCGuide_e_pdf.pdf + +Books +------ + +* "Handbook of Elliptic and Hyperelliptic Curve Cryptography" + Cohen and Frey https://www.hyperelliptic.org/HEHCC/ + An excellent reference for ECC math, algorithms, and side channels + +* "Post-Quantum Cryptography" Bernstein, Buchmann, Dahmen + Covers code, lattice, and hash based cryptography + +Standards +----------- + +* IEEE 1363 http://grouper.ieee.org/groups/1363/ + Very influential early in the library lifetime, so a lot of terminology used + in the public key (such as "EME" for message encoding) code comes from here. + +* ISO/IEC 18033-2 http://www.shoup.net/iso/std4.pdf + RSA-KEM, PSEC-KEM + +* NIST SP 800-108 + http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf + KDF schemes + +* NIST SP 800-90A + http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf + HMAC_DRBG, Hash_DRBG, CTR_DRBG, maybe one other thing? + diff --git a/comm/third_party/botan/doc/dev_ref/release_process.rst b/comm/third_party/botan/doc/dev_ref/release_process.rst new file mode 100644 index 0000000000..1dd0842643 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/release_process.rst @@ -0,0 +1,129 @@ +Release Process and Checklist +======================================== + +Releases are done quarterly, normally on the first non-holiday Monday +of January, April, July and October. A feature freeze goes into effect +starting 9 days before the release. + +.. highlight:: shell + +.. note:: + + This information is only useful if you are a developer of botan who + is creating a new release of the library. + +Pre Release Testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Kick off a Coverity scan a day or so before the planned release. + +Do maintainer-mode builds with Clang and GCC to catch any warnings +that should be corrected. Also check Visual C++ build logs for any +warnings that should be addressed. + +And remember that CI doesn't test everything. In particular, not all +tests run under valgrind or on the qemu cross builds due to time +constraints. So before release: + + - Run under valgrind, building with ``--with-valgrind`` flag + - Using Clang sanitizers (ASan + UbSan) + - Native compile on FreeBSD x86-64 + - Native compile on at least one unusual platform (AIX, NetBSD, ...) + - Build the website content to detect any Doxygen problems + - Test many build configurations (using `src/scripts/test_all_configs.py`) + - Build/test SoftHSM + +Confirm that the release notes in ``news.rst`` are accurate and +complete and that the version number in ``version.txt`` is correct. + +Tag the Release +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Update the release date in the release notes and change the entry for +the appropriate branch in ``readme.rst`` to point to the new release. + +Now check in, and backport changes to the release branch:: + + $ git commit readme.rst news.rst -m "Update for 2.6.13 release" + $ git checkout release-2 + $ git merge master + $ git tag 2.6.13 + +Build The Release Tarballs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The release script is ``src/scripts/dist.py`` and must be run from a +git workspace. + + $ src/scripts/dist.py 2.6.13 + +One useful option is ``--output-dir``, which specifies where the +output will be placed. + +Now do a final build/test of the released tarball. + +The ``--pgp-key-id`` option is used to specify a PGP keyid. If set, +the script assumes that it can execute GnuPG and will attempt to +create signatures for the tarballs. The default value is ``EFBADFBC``, +which is the official signing key. You can use ``--pgp-key-id=none`` +to avoid creating any signature, though official distributed releases +*should not* be released without signatures. + +The releases served on the official site are taken from the contents +in a git repository:: + + $ git checkout git@botan.randombit.net:/srv/git/botan-releases.git + $ src/scripts/dist.py 2.6.13 --output-dir=botan-releases + $ cd botan-releases + $ sha256sum Botan-2.6.13.tgz >> sha256sums.txt + $ git add . + $ git commit -m "Release version 2.6.13" + $ git push origin master + +A cron job updates the live site every 10 minutes. + +Push to GitHub +^^^^^^^^^^^^^^^^^^ + +Don't forget to also push tags:: + + $ git push origin --tags release-2 master + +Build The Windows Installer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: + We haven't distributed Windows binaries for some time. + +On Windows, run ``configure.py`` to setup a build:: + + $ python ./configure.py --cc=msvc --cpu=$ARCH --distribution-info=unmodified + +After completing the build (and running the tests), use `InnoSetup +`_ to create the installer. A +InnoSetup script is created from ``src/build-data/innosetup.in`` and +placed in ``build/botan.iss`` by ``configure.py``. Create the +installer either via the InnoSetup GUI by opening the ``iss`` file and +selecting the 'Compile' option, or using the ``iscc`` command line +tool. If all goes well it will produce an executable with a name like +``botan-2.6.13-x86_64.exe``. Sign the installers with GPG. + +Update The Website +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The website content is created by ``src/scripts/website.py``. + +The website is mirrored automatically from a git repository which must be updated:: + + $ git checkout git@botan.randombit.net:/srv/git/botan-website.git + $ ./src/scripts/website.py --output botan-website + $ cd botan-website + $ git add . + $ git commit -m "Update for 2.6.13" + $ git push origin master + +Announce The Release +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Send an email to the botan-announce and botan-devel mailing lists +noting that a new release is available. diff --git a/comm/third_party/botan/doc/dev_ref/test_framework.rst b/comm/third_party/botan/doc/dev_ref/test_framework.rst new file mode 100644 index 0000000000..241c51bd1a --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/test_framework.rst @@ -0,0 +1,314 @@ +Test Framework +================ + +Botan uses a custom-built test framework. Some portions of it are +quite similar to assertion-based test frameworks such as Catch or +Gtest, but it also includes many features which are well suited for +testing cryptographic algorithms. + +The intent is that the test framework and the test suite evolve +symbiotically; as a general rule of thumb if a new function would make +the implementation of just two distinct tests simpler, it is worth +adding to the framework on the assumption it will prove useful again. +Feel free to propose changes to the test system. + +When writing a new test, there are three key classes that are used, +namely ``Test``, ``Test::Result``, and ``Text_Based_Test``. A ``Test`` +(or ``Test_Based_Test``) runs and returns one or more ``Test::Result``. + +Namespaces in Test +------------------- + +The test code lives in a distinct namespace (``Botan_Tests``) and all +code in the tests which calls into the library should use the +namespace prefix ``Botan::`` rather than a ``using namespace`` +declaration. This makes it easier to see where the test is actually +invoking the library, and makes it easier to reuse test code for +applications. + +Test Data +----------- + +The test framework is heavily data driven. As of this writing, there +is about 1 Mib of test code and 17 MiB of test data. For most (though +certainly not all) tests, it is better to add a data file representing +the input and outputs, and run the tests over it. Data driven tests +make adding or editing tests easier, for example by writing scripts +which produce new test data and output it in the expected format. + +Test +-------- + +.. cpp:class:: Test + + .. cpp:function:: virtual std::vector run() = 0 + + This is the key function of a ``Test``: it executes and returns a + list of results. Almost all other functions on ``Test`` are + static functions which just serve as helper functions for ``run``. + + .. cpp:function:: static std::string read_data_file(const std::string& path) + + Return the contents of a data file and return it as a string. + + .. cpp:function:: static std::vector read_binary_data_file(const std::string& path) + + Return the contents of a data file and return it as a vector of + bytes. + + .. cpp:function:: static std::string data_file(const std::string& what) + + An alternative to ``read_data_file`` and ``read_binary_file``, + use only as a last result, typically for library APIs which + themselves accept a filename rather than a data blob. + + .. cpp:function:: static bool run_long_tests() const + + Returns true if the user gave option ``--run-long-tests``. Use + this to gate particularly time-intensive tests. + + .. cpp:function:: static Botan::RandomNumberGenerator& rng() + + Returns a reference to a fast, not cryptographically secure + random number generator. It is deterministicly seeded with the + seed logged by the test runner, so it is possible to reproduce + results in "random" tests. + +Tests are registered using the macro ``BOTAN_REGISTER_TEST`` which +takes 2 arguments: the name of the test and the name of the test class. +For example given a ``Test`` instance named ``MyTest``, use:: + + BOTAN_REGISTER_TEST("mytest", MyTest); + +All test names should contain only lowercase letters, numbers, and +underscore. + +Test::Result +------------- + +.. cpp:class:: Test::Result + + A ``Test::Result`` records one or more tests on a particular topic + (say "AES-128/CBC" or "ASN.1 date parsing"). Most of the test functions + return true or false if the test was successful or not; this allows + performing conditional blocks as a result of earlier tests:: + + if(result.test_eq("first value", produced, expected)) + { + // further tests that rely on the initial test being correct + } + + Only the most commonly used functions on ``Test::Result`` are documented here, + see the header ``tests.h`` for more. + + .. cpp:function:: Test::Result(const std::string& who) + + Create a test report on a particular topic. This will be displayed in the + test results. + + .. cpp:function:: bool test_success() + + Report a test that was successful. + + .. cpp:function:: bool test_success(const std::string& note) + + Report a test that was successful, including some comment. + + .. cpp:function:: bool test_failure(const std::string& err) + + Report a test failure of some kind. The error string will be logged. + + .. cpp:function:: bool test_failure(const std::string& what, const std::string& error) + + Report a test failure of some kind, with a description of what failed and + what the error was. + + .. cpp:function:: void test_failure(const std::string& what, const uint8_t buf[], size_t buf_len) + + Report a test failure due to some particular input, which is provided as + arguments. Normally this is only used if the test was using some + randomized input which unexpectedly failed, since if the input is + hardcoded or from a file it is easier to just reference the test number. + + .. cpp:function:: bool test_eq(const std::string& what, const std::string& produced, const std::string& expected) + + Compare to strings for equality. + + .. cpp:function:: bool test_ne(const std::string& what, const std::string& produced, const std::string& expected) + + Compare to strings for non-equality. + + .. cpp:function:: bool test_eq(const char* producer, const std::string& what, \ + const uint8_t produced[], size_t produced_len, \ + const uint8_t expected[], size_t expected_len) + + Compare two arrays for equality. + + .. cpp:function:: bool test_ne(const char* producer, const std::string& what, \ + const uint8_t produced[], size_t produced_len, \ + const uint8_t expected[], size_t expected_len) + + Compare two arrays for non-equality. + + .. cpp:function:: bool test_eq(const std::string& producer, const std::string& what, \ + const std::vector& produced, \ + const std::vector& expected) + + Compare two vectors for equality. + + .. cpp:function:: bool test_ne(const std::string& producer, const std::string& what, \ + const std::vector& produced, \ + const std::vector& expected) + + Compare two vectors for non-equality. + + .. cpp:function:: bool confirm(const std::string& what, bool expr) + + Test that some expression evaluates to ``true``. + + .. cpp:function:: template bool test_not_null(const std::string& what, T* ptr) + + Verify that the pointer is not null. + + .. cpp:function:: bool test_lt(const std::string& what, size_t produced, size_t expected) + + Test that ``produced`` < ``expected``. + + .. cpp:function:: bool test_lte(const std::string& what, size_t produced, size_t expected) + + Test that ``produced`` <= ``expected``. + + .. cpp:function:: bool test_gt(const std::string& what, size_t produced, size_t expected) + + Test that ``produced`` > ``expected``. + + .. cpp:function:: bool test_gte(const std::string& what, size_t produced, size_t expected) + + Test that ``produced`` >= ``expected``. + + .. cpp:function:: bool test_throws(const std::string& what, std::function fn) + + Call a function and verify it throws an exception of some kind. + + .. cpp:function:: bool test_throws(const std::string& what, const std::string& expected, std::function fn) + + Call a function and verify it throws an exception of some kind + and that the exception message exactly equals ``expected``. + +Text_Based_Test +----------------- + +A ``Text_Based_Text`` runs tests that are produced from a text file +with a particular format which looks somewhat like an INI-file:: + + # Comments begin with # and continue to end of line + [Header] + # Test 1 + Key1 = Value1 + Key2 = Value2 + + # Test 2 + Key1 = Value1 + Key2 = Value2 + +.. cpp:class:: VarMap + + An object of this type is passed to each invocation of the text-based test. + It is used to access the test variables. All access takes a key, which is + one of the strings which was passed to the constructor of ``Text_Based_Text``. + Accesses are either required (``get_req_foo``), in which case an exception is + throwing if the key is not set, or optional (``get_opt_foo``) in which case + the test provides a default value which is returned if the key was not set + for this particular instance of the test. + + .. cpp:function:: std::vector get_req_bin(const std::string& key) const + + Return a required binary string. The input is assumed to be hex encoded. + + .. cpp:function:: std::vector get_opt_bin(const std::string& key) const + + Return an optional binary string. The input is assumed to be hex encoded. + + .. cpp:function:: std::vector> get_req_bin_list(const std::string& key) const + + .. cpp:function:: Botan::BigInt get_req_bn(const std::string& key) const + + Return a required BigInt. The input can be decimal or (with "0x" prefix) hex encoded. + + .. cpp:function:: Botan::BigInt get_opt_bn(const std::string& key, const Botan::BigInt& def_value) const + + Return an optional BigInt. The input can be decimal or (with "0x" prefix) hex encoded. + + .. cpp:function:: std::string get_req_str(const std::string& key) const + + Return a required text string. + + .. cpp:function:: std::string get_opt_str(const std::string& key, const std::string& def_value) const + + Return an optional text string. + + .. cpp:function:: size_t get_req_sz(const std::string& key) const + + Return a required integer. The input should be decimal. + + .. cpp:function:: size_t get_opt_sz(const std::string& key, const size_t def_value) const + + Return an optional integer. The input should be decimal. + +.. cpp:class:: Text_Based_Test : public Test + + .. cpp:function:: Text_Based_Test(const std::string& input_file, \ + const std::string& required_keys, \ + const std::string& optional_keys = "") + + This constructor is + + .. note:: + The final element of required_keys is the "output key", that is + the key which signifies the boundary between one test and the next. + When this key is seen, ``run_one_test`` will be invoked. In the + test input file, this key must always appear least for any particular + test. All the other keys may appear in any order. + + .. cpp:function:: Test::Result run_one_test(const std::string& header, \ + const VarMap& vars) + + Runs a single test and returns the result of it. The ``header`` + parameter gives the value (if any) set in a ``[Header]`` block. + This can be useful to distinguish several types of tests within a + single file, for example "[Valid]" and "[Invalid]". + + .. cpp:function:: bool clear_between_callbacks() const + + By default this function returns ``false``. If it returns + ``true``, then when processing the data in the file, variables + are not cleared between tests. This can be useful when several + tests all use some common parameters. + +Test Runner +------------- + +If you are simply writing a new test there should be no need to modify +the runner, however it can be useful to be aware of its abilities. + +The runner can run tests concurrently across many cores. By default single +threaded execution is used, but you can use ``--test-threads`` option to +specify the number of threads to use. If you use ``--test-threads=0`` then +the runner will probe the number of active CPUs and use that (but limited +to at most 16). If you want to run across many cores on a large machine, +explicitly specify a thread count. The speedup is close to linear. + +The RNG used in the tests is deterministic, and the seed is logged for each +execution. You can cause the random sequence to repeat using ``--drbg-seed`` +option. + +.. note:: + Currently the RNG is seeded just once at the start of execution. So you + must run the exact same sequence of tests as the original test run in + order to get reproducible results. + +If you are trying to track down a bug that happens only occasionally, two very +useful options are ``--test-runs`` and ``--abort-on-first-fail``. The first +takes an integer and runs the specified test cases that many times. The second +causes abort to be called on the very first failed test. This is sometimes +useful when tracing a memory corruption bug. diff --git a/comm/third_party/botan/doc/dev_ref/todo.rst b/comm/third_party/botan/doc/dev_ref/todo.rst new file mode 100644 index 0000000000..891475caa9 --- /dev/null +++ b/comm/third_party/botan/doc/dev_ref/todo.rst @@ -0,0 +1,199 @@ +Todo List +======================================== + +Feel free to take one of these on if it interests you. Before starting +out on something, send an email to the dev list or open a discussion +ticket on GitHub to make sure you're on the right track. + +Request a new feature by opening a pull request to update this file. + +Ciphers, Hashes, PBKDF +---------------------------------------- + +* Stiched AES/GCM mode for CPUs supporting both AES and CLMUL +* Combine AES-NI, ARMv8 and POWER AES implementations (as already done for CLMUL) +* Vector permute AES only supports little-endian systems; fix for big-endian +* SM4 using AES-NI (https://github.com/mjosaarinen/sm4ni) or vector permute +* Poly1305 using AVX2 +* ChaCha using SSSE3 +* Skein-MAC +* PMAC +* SIV-PMAC +* GCM-SIV (RFC 8452) +* EME* tweakable block cipher (https://eprint.iacr.org/2004/125) +* FFX format preserving encryption (NIST 800-38G) +* SHA-512 using BMI2+AVX2 +* Constant time DES using bitslicing and/or BMI2 +* Threefish-1024 +* SIMD evaluation of SHA-2 and SHA-3 compression functions +* Adiantum (https://eprint.iacr.org/2018/720) +* CRC using clmul/pmull + +Public Key Crypto, Math +---------------------------------------- + +* Short vector optimization for BigInt +* Abstract representation of ECC point elements to allow specific + implementations of the field arithmetic depending upon the curve. +* Use NAF (joint sparse form) for ECC multi-exponentiation +* Curves for pairings (BN-256, BLS12-381) +* Identity based encryption +* Paillier homomorphic cryptosystem +* Socialist Millionaires Protocol (needed for OTRv3) +* Hashing onto an elliptic curve (draft-irtf-cfrg-hash-to-curve) +* New PAKEs (pending CFRG bakeoff results) +* New post quantum schemes (pending NIST contest results) +* SPHINX password store (https://eprint.iacr.org/2018/695) +* X448 and Ed448 +* Use GLV decomposition to speed up secp256k1 operations + +Utility Functions +------------------ + +* Add a memory span type +* Make Memory_Pool more concurrent (currently uses a global lock) +* Guarded integer type to prevent overflow bugs +* Add logging callbacks +* Add latency tracing framework + +Multiparty Protocols +---------------------- + +* Distributed key generation for DL, RSA +* Threshold signing, decryption + +External Providers, Hardware Support +---------------------------------------- + +* Add support ARMv8.4-A SHA-512, SHA-3, SM3 and RNG +* Aarch64 inline asm for BigInt +* Extend OpenSSL provider (DH, HMAC, CMAC, GCM) +* Support using BoringSSL instead of OpenSSL or LibreSSL +* /dev/crypto provider (ciphers, hashes) +* Windows CryptoNG provider (ciphers, hashes) +* Extend Apple CommonCrypto provider (HMAC, CMAC, RSA, ECDSA, ECDH) +* Add support for iOS keychain access +* POWER8 SHA-2 extensions (GH #1486 + #1487) +* Add support VPSUM on big-endian PPC64 (GH #2252) +* Better TPM support: NVRAM, PCR measurements, sealing +* Add support for TPM 2.0 hardware +* Support Intel QuickAssist accelerator cards + +TLS +---------------------------------------- + +* Make DTLS support optional at build time +* Improve/optimize DTLS defragmentation and retransmission +* Implement logging callbacks for TLS +* Make RSA optional at build time +* Make finite field DH optional at build time +* Authentication using TOFU (sqlite3 storage) +* Certificate pinning (using TACK?) +* Certificate Transparency extensions +* TLS supplemental authorization data (RFC 4680, RFC 5878) +* DTLS-SCTP (RFC 6083) + +PKIX +---------------------------------------- + +* Further tests of validation API (see GH #785) +* Test suite for validation of 'real world' cert chains (GH #611) +* Improve output of X509_Certificate::to_string + This is a free-form string for human consumption so the only constraints + are being informative and concise. (GH #656) +* X.509 policy constraints +* OCSP responder logic + +New Protocols / Formats +---------------------------------------- + +* ACME protocol +* PKCS7 / Cryptographic Message Syntax +* PKCS12 / PFX +* Off-The-Record v3 https://otr.cypherpunks.ca/ +* Certificate Management Protocol (RFC 5273); requires CMS +* Fernet symmetric encryption (https://cryptography.io/en/latest/fernet/) +* RNCryptor format (https://github.com/RNCryptor/RNCryptor) +* Useful OpenPGP subset 1: symmetrically encrypted files. + Not aiming to process arbitrary OpenPGP, but rather produce + something that happens to be readable by `gpg` and is relatively + simple to process for decryption. Require AEAD mode (EAX/OCB). +* Useful OpenPGP subset 2: Process OpenPGP public keys +* Useful OpenPGP subset 3: Verification of OpenPGP signatures + +Cleanups +----------- + +* Split test_ffi.cpp into multiple files +* Unicode path support on Windows (GH #1615) +* The X.509 path validation tests have much duplicated logic + +Compat Headers +---------------- + +* OpenSSL compatible API headers: EVP, TLS, certificates, etc + +New C APIs +---------------------------------------- + +* PKCS10 requests +* Certificate signing +* Expose TLS +* Expose NIST key wrap with padding +* Expose secret sharing +* Expose deterministic PRNG +* base32 +* base58 +* DL_Group +* EC_Group + +Python +---------------- + +* Anywhere Pylint warnings too-many-locals, too-many-branches, or + too-many-statements are skipped, fix the code so Pylint no longer warns. + +* Write a CLI or HTTPS client in Python + +Build/Test +---------------------------------------- + +* Start using GitHub Actions for CI, especially Windows builds +* Create Docker image for Travis that runs 18.04 and has all + the tools we need pre-installed. +* Code signing for Windows installers +* Test runner python script that captures backtraces and other + debug info during CI +* Support hardcoding all test vectors into the botan-test binary + so it can run as a standalone item (copied to a device, etc) +* Run iOS binary under simulator in CI +* Run Android binary under simulator in CI +* Run the TPM tests against an emulator + (https://github.com/PeterHuewe/tpm-emulator) +* Add clang-tidy, clang-analyzer, cppcheck to CI +* Add support for vxWorks +* Add support for Fuschia OS +* Add support for CloudABI +* Add support for SGX + +CLI +---------------------------------------- + +* Add a ``--completion`` option to dump autocomplete info, write + support for autocompletion in bash/zsh. +* Refactor ``speed`` +* Change `tls_server` to be a tty<->socket app, like `tls_client` is, + instead of a bogus echo server. +* `encrypt` / `decrypt` tools providing password based file encryption +* Add ECM factoring +* Clone of `minisign` signature utility +* Implementation of `tlsdate` +* Password store utility +* TOTP calculator + +Documentation +---------------------------------------- + +* X.509 certs, path validation +* Specific docs covering one major topic (RSA, ECDSA, AES/GCM, ...) +* Some howto style docs (setting up CA, ...) diff --git a/comm/third_party/botan/doc/goals.rst b/comm/third_party/botan/doc/goals.rst new file mode 100644 index 0000000000..840e1bd818 --- /dev/null +++ b/comm/third_party/botan/doc/goals.rst @@ -0,0 +1,131 @@ + +Project Goals +================================ + +Botan seeks to be a broadly applicable library that can be used to implement a +range of secure distributed systems. + +The library has the following project goals guiding changes. It does not succeed +in all of these areas in every way just yet, but it describes the system that is +the desired end result. Over time further progress is made in each. + +* Secure and reliable. The implementations must of course be correct and well + tested, and attacks such as side channels and fault attacks should be + accounted for where necessary. The library should never crash, or invoke + undefined behavior, regardless of circumstances. + +* Implement schemes important in practice. It should be practical to implement + any real-world crypto protocol using just what the library provides. It is + worth some (limited) additional complexity in the library, in order to expand + the set of applications which can easily adopt Botan. + +* Ease of use. It should be straightforward for an application programmer to do + whatever it is they need to do. There should be one obvious way to perform any + operation. The API should be predicable, and follow the "principle of least + astonishment" in its design. This is not just a nicety; confusing APIs often + result in errors that end up compromising security. + +* Simplicity of design, clarity of code, ease of review. The code should be easy + to read and understand by other library developers, users seeking to better + understand the behavior of the code, and by professional reviewers looking for + bugs. This is important because bugs in convoluted code can easily escape + multiple expert reviews, and end up living on for years. + +* Well tested. The code should be correct against the spec, with as close to + 100% test coverage as possible. All available static and dynamic analysis + tools at our disposal should be used, including fuzzers, symbolic execution, + and protocol specific tools. Within reason, all warnings from compilers and + static analyzers should be addressed, even if they seem like false positives, + because that maximizes the signal value of new warnings from the tool. + +* Safe defaults. Policies should aim to be highly restrictive by default, and if + they must be made less restrictive by certain applications, it should be + obvious to the developer that they are doing something unsafe. + +* Post quantum security. Possibly a practical quantum computer that can break + RSA and ECC will never be built, but the future is notoriously hard to predict. + It seems prudent to begin designing and deploying systems now which have at + least the option of using a post-quantum scheme. Botan provides a conservative + selection of algorithms thought to be post-quantum secure. + +* Performance. Botan does not in every case strive to be faster than every other + software implementation, but performance should be competitive and over time + new optimizations are identified and applied. + +* Support whatever I/O mechanism the application wants. Allow the application to + control all aspects of how the network is contacted, and ensure the API makes + asynchronous operations easy to handle. This both insulates Botan from + system-specific details and allows the application to use whatever networking + style they please. + +* Portability to modern systems. Botan does not run everywhere, and we actually + do not want it to (see non-goals below). But we do want it to run on anything + that someone is deploying new applications on. That includes both major + platforms like Windows, Linux, Android and iOS, and also promising new systems + such as IncludeOS and Fuchsia. + +* Well documented. Ideally every public API would have some place in the manual + describing its usage. + +* Useful command line utility. The botan command line tool should be flexible + and featured enough to replace similar tools such as ``openssl`` for everyday + users. + +Non-Goals +------------------------- + +There are goals some crypto libraries have, but which Botan actively does not +seek to address. + +* Deep embedded support. Botan requires a heap, C++ exceptions, and RTTI, and at + least in terms of performance optimizations effectively assumes a 32 or 64 bit + processor. It is not suitable for deploying on, say FreeRTOS running on a + MSP430, or smartcard with an 8 bit CPU and 256 bytes RAM. A larger SoC, such + as a Cortex-A7 running Linux, is entirely within scope. + +* Implementing every crypto scheme in existence. The focus is on algorithms + which are in practical use in systems deployed now, as well as promising + algorithms for future deployment. Many algorithms which were of interest + in the past but never saw widespread deployment and have no compelling + benefit over other designs have been removed to simplify the codebase. + +* Portable to obsolete systems. There is no reason for crypto software to + support ancient OS platforms like SunOS or Windows 2000, since these unpatched + systems are completely unsafe anyway. The additional complexity supporting + such platforms just creates more room for bugs. + +* Portable to every C++ compiler ever made. Over time Botan moves forward to + both take advantage of new language/compiler features, and to shed workarounds + for dealing with bugs in ancient compilers, allowing further simplifications + in the codebase. The set of supported compilers is fixed for each new release + branch, for example Botan 2.x will always support GCC 4.8. But a future 3.x + release version will likely increase the required versions for all compilers. + +* FIPS 140 validation. The primary developer was (long ago) a consultant with a + NIST approved testing lab. He does not have a positive view of the process or + results, particularly when it comes to Level 1 software validations. The only + benefit of a Level 1 validation is to allow for government sales, and the cost + of validation includes enormous amounts of time and money, adding 'checks' + that are useless or actively harmful, then freezing the software so security + updates cannot be applied in the future. It does force a certain minimum + standard (ie, FIPS Level 1 does assure AES and RSA are probably implemented + correctly) but this is an issue of interop not security since Level 1 does not + seriously consider attacks of any kind. Any security budget would be far + better spent on a review from a specialized crypto consultancy, who would look + for actual flaws. + + That said it would be easy to add a "FIPS 140" build mode to Botan, which just + disabled all the builtin crypto and wrapped whatever the most recent OpenSSL + FIPS module exports. + +* Educational purposes. The library code is intended to be easy to read and + review, and so might be useful in an educational context. However it does not + contain any toy ciphers (unless you count DES and RC4) nor any tools for + simple cryptanalysis. Generally the manual and source comments assume previous + knowledge on the basic concepts involved. + +* User proof. Some libraries provide a very high level API in an attempt to save + the user from themselves. Occasionally they succeed. It would be appropriate + and useful to build such an API on top of Botan, but Botan itself wants to + cover a broad set of uses cases and some of these involve having pointy things + within reach. diff --git a/comm/third_party/botan/doc/index.rst b/comm/third_party/botan/doc/index.rst new file mode 100644 index 0000000000..50808c2714 --- /dev/null +++ b/comm/third_party/botan/doc/index.rst @@ -0,0 +1,58 @@ + +Getting Started +======================================== + +If you need to build the library first, start with :doc:`building`. +Some Linux distributions include packages for Botan, so building from +source may not be required on your system. + +.. only:: html + + The :ref:`genindex` and :ref:`search` may be useful to get started. + +.. only:: html and website + + You can also download this manual as a `PDF `_. + +Examples +---------- + +Some examples of usage are included in this documentation. However a better +source for example code is in the implementation of the +`command line interface `_, +which was intentionally written to act as practical examples of usage. + +Books and other references +---------------------------- + +You should have some knowledge of cryptography *before* trying to use +the library. This is an area where it is very easy to make mistakes, +and where things are often subtle and/or counterintuitive. Obviously +the library tries to provide things at a high level precisely to +minimize the number of ways things can go wrong, but naive use will +almost certainly not result in a secure system. + +Especially recommended are: + +- *Cryptography Engineering* + by Niels Ferguson, Bruce Schneier, and Tadayoshi Kohno + +- `Security Engineering -- A Guide to Building Dependable Distributed Systems + `_ by Ross Anderson + +- `Handbook of Applied Cryptography `_ + by Alfred J. Menezes, Paul C. Van Oorschot, and Scott A. Vanstone + +If you're doing something non-trivial or unique, you might want to at +the very least ask for review/input at a place such as the +`metzdowd `_ or +`randombit `_ +mailing lists or the +`cryptography stack exchange `_. +And (if possible) pay a professional cryptographer or security company +to review your design and code. + + +.. toctree:: + :maxdepth: 1 + :numbered: diff --git a/comm/third_party/botan/doc/old_news.rst b/comm/third_party/botan/doc/old_news.rst new file mode 100644 index 0000000000..161bf487bc --- /dev/null +++ b/comm/third_party/botan/doc/old_news.rst @@ -0,0 +1,4336 @@ +Release Notes: 0.7.0 to 1.11.34 +======================================== + +Version 1.10.17, 2017-10-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Address a side channel affecting modular exponentiation. An attacker + capable of a local or cross-VM cache analysis attack may be able + to recover bits of secret exponents as used in RSA, DH, etc. + CVE-2017-14737 + +* Workaround a miscompilation bug in GCC 7 on x86-32 affecting GOST-34.11 + hash function. (GH #1192 #1148 #882) + +* Add SecureVector::data() function which returns the start of the + buffer. This makes it slightly simpler to support both 1.10 and 2.x + APIs in the same codebase. + +* When compiled by a C++11 (or later) compiler, a template typedef of + SecureVector, secure_vector, is added. In 2.x this class is a + std::vector with a custom allocator, so has a somewhat different + interface than SecureVector in 1.10. But this makes it slightly + simpler to support both 1.10 and 2.x APIs in the same codebase. + +* Fix a bug that prevented `configure.py` from running under Python3 + +* Botan 1.10.x does not support the OpenSSL 1.1 API. Now the build + will `#error` if OpenSSL 1.1 is detected. Avoid `--with-openssl` + if compiling against 1.1 or later. (GH #753) + +* Import patches from Debian adding basic support for building on + aarch64, ppc64le, or1k, and mipsn32 platforms. + +Version 1.10.16, 2017-04-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug in X509 DN string comparisons that could result in out of bound + reads. This could result in information leakage, denial of service, or + potentially incorrect certificate validation results. (CVE-2017-2801) + +* Avoid throwing during a destructor since this is undefined in C++11 + and rarely a good idea. (GH #930) + +Version 1.10.15, 2017-01-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug causing modular exponentiations done modulo even numbers + to almost always be incorrect, unless the values were small. This + bug is not known to affect any cryptographic operation in Botan. (GH #754) + +* Avoid use of C++11 std::to_string in some code added in 1.10.14 (GH #747 #834) + +Version 1.11.34, 2016-11-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix integer overflow during BER decoding, found by Falko Strenzke. + This bug is not thought to be directly exploitable but upgrading ASAP + is advised. (CVE-2016-9132) + +* Add post-quantum signature scheme XMSS. Provides either 128 or 256 bit + (post-quantum) security, with small public and private keys, fast + verification, and reasonably small signatures (2500 bytes for 128-bit + security). Signature generation is very slow, on the order of seconds. And + very importantly the signature scheme is stateful: each leaf index must only + be used once, or all security is lost. In the appropriate system where + signatures are rarely generated (such as code signing) XMSS makes an excellent + choice. (GH #717 #736) + +* Add support for CECPQ1 TLS ciphersuites. These use a combination of x25519 + ECDH and NewHope to provide post-quantum security. The ciphersuites are not + IETF standard, but is compatible with BoringSSL. (GH #729) + +* Add support for client-side OCSP stapling to TLS. (GH #738) + +* Previously both public and private keys performed automatic self testing after + generation or loading. However this often caused unexpected application + performance problems, and so has been removed. Instead applications must call + check_key explicitly. (GH #704) + +* Fix TLS session resumption bugs which caused resumption failures if an + application used a single session cache for both TLS and DTLS. (GH #688) + +* Add SHAKE-128 and SHAKE-256 XOFs as hash functions supporting paramaterized + output lengths. + +* Add MessageAuthenticationCode::start_msg interface, for MACs which require or + can use a nonce (GH #691) + +* Add GMAC, a MAC based on GCM (GH #488 / #691) + +* Add ESP block cipher padding from RFC 4304. GH #724 + +* Incompatible change to HKDF: previously the HKDF type in Botan was only the + Expand half of HKDF. Now HKDF is the full Extract-then-Expand KDF, and + HKDF_Extract and HKDF_Expand are available. If you previously used HKDF, you + must switch to using HKDF_Expand. (GH #723) + +* Add Cipher_Mode::reset which resets message-specific state, allowing + discarding state but allowing continued processing under the same key. (GH #552) + +* The ability to add OIDs at runtime has been removed. This additionally removes + a global lock which was acquired on each OID lookup. (GH #706) + +* The default TLS policy now disables static RSA ciphersuites, all DSA + ciphersuites, and the AES CCM-8 ciphersuites. Disabling static RSA by default + protects servers from oracle attacks, as well as enforcing a forward secure + ciphersuite. Some applications may be forced to re-enable RSA for interop + reasons. DSA and CCM-8 are rarely used, and likely should not be negotiated + outside of special circumstances. + +* The default TLS policy now prefers ChaCha20Poly1305 cipher over any AES mode. + +* The default TLS policy now orders ECC curve preferences in order by performance, + with x25519 first, then P-256, then P-521, then the rest. + +* Add a BSD sockets version of the HTTP client code used for OCSP. GH #699 + +* Export the public key workfactor functions (GH #734) and add tests for them. + +* HMAC_DRBG allows configuring maximum number of bytes before reseed check (GH #690) + +* Salsa20 now accepts a null IV as equivalent to an all-zero one (GH #697) + +* Optimize ECKCDSA verification (GH #700 #701 #702) + +* The deprecated RNGs HMAC_RNG and X9.31 RNG have been removed. Now the only + userspace PRNG included in the library is HMAC_DRBG. (GH #692) + +* The entropy sources for EGD and BeOS, as well as the Unix entropy source which + executed processes to get statistical data have been removed. (GH #692) + +* The openpgp module (which just implemented OpenPGP compatible base64 encoding + and decoding, nothing else) has been removed. + +* Added new configure.py argument `--optimize-for-size`. Currently just sets + the flag for code size optimizations with the compiler, but may have other + effects in the future. + +* Fixed bug in Threaded_Fork causing incorrect computations (GH #695 #716) + +* Add DSA deterministic parameter generation test from FIPS 186-3. + +* Fix PKCS11_ECDSA_PrivateKey::check_key (GH #712) + +* Fixed problems running configure.py outside of the base directory + +* The BOTAN_ENTROPY_PROC_FS_PATH value in build.h was being ignored (GH #708) + +* Add speed tests for ECGDSA and ECKCDSA (GH #696) + +* Fix a crash in speed command for Salsa20 (GH #697) + +* Allow a custom ECC curve to be specified at build time, for application or + system specific curves. (GH #636 #710) + +* Use NOMINMAX on Windows to avoid problems in amalgamation build. (GH #740) + +* Add support to output bakefiles with new `configure.py` option `--with-bakefile`. + (GH #360 #720) + +* The function `zero_mem` has been renamed `secure_scrub_memory` + +* More tests for pipe/filter (GH #689 #693), AEADs (GH #552), KDF::name (GH #727), + +* Add a test suite for timing analysis for TLS CBC decryption, OAEP decryption, + and PKCS #1 v1.5 decryption. These operations all have the feature that if an + attacker can distinguish internal operations, such as through a variance in + timing, they can use this oracle to decrypt arbitrary ciphertexts. GH #733 + +* Add a test suite for testing and fuzzing with TLS-Attacker, a tool for + analyzing TLS libraries. (https://github.com/RUB-NDS/TLS-Attacker) + +* Add a fuzzing framework. Supports fuzzing some APIs using AFL and libFuzzer. + +* Added documentation for PKCS #11 (GH #725) + +* The LibraryInitializer type is no longer needed and is now deprecated. + +* The license and news files were moved from doc to the top level directory. + There should not be any other visible change (eg, to the installed version) + as a result of this move. + +* Fixed some problems when running configure.py outside of the base directory, + especially when using relative paths. + +* Add (back) the Perl XS wrapper and sqlite encryption code. + +Version 1.10.14, 2016-11-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* NOTE WELL: Botan 1.10.x is supported for security patches only until + 2017-12-31 + +* Fix integer overflow during BER decoding, found by Falko Strenzke. + This bug is not thought to be directly exploitable but upgrading ASAP + is advised. (CVE-2016-9132) + +* Fix two cases where (in error situations) an exception would be + thrown from a destructor, causing a call to std::terminate. + +* When RC4 is disabled in the build, also prevent it from being + included in the OpenSSL provider. (GH #638) + +Version 1.11.33, 2016-10-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Avoid side channel during OAEP decryption. (CVE-2016-8871) + +* A countermeasure for the Lucky13 timing attack against CBC-based TLS + ciphersuites has been added. (GH #675) + +* Added X25519-based key exchange for TLS (GH #673) + +* Add Certificate_Store_In_SQL which supports storing certs, keys, and + revocation information in a SQL database. Subclass Certificate_Store_In_SQLite + specializes with support for SQLite3 databases. (GH #631) + +* The Certificate_Store interface has been changed to deal with + ``std::shared_ptrs`` instead of raw pointers (GH #471 #631) + +* Add support for official SHA-3. Keccak-1600 was already supported + but used different padding from FIPS 202. (GH #669) + +* Add SHAKE-128 based stream cipher. (GH #669) + +* NewHope key exchange now supports the SHA-256/AES-128-CTR scheme + used by BoringSSL in addition to the SHA-3/SHAKE-128 parameters used + by the reference implementation. (GH #669) + +* Add support for the TLS Supported Point Formats Extension from RFC 4492. Adds + ``TLS::Policy::use_ecc_point_compression`` policy option. If supported on both + sides, ECC points can be sent in compressed format which saves a few bytes + during the handshake. (GH #645) + +* Fix entropy source selection bug on Windows, which caused the CryptoAPI + entropy source to be not available under its normal name "win32_cryptoapi" but + instead "dev_random". GH #644 + +* Accept read-only access to ``/dev/urandom``. System_RNG previously required + read-write access, to allow applications to provide inputs to the system + PRNG. But local security policies might only allow read-only access, as is the + case with Ubuntu's AppArmor profile for applications in the Snappy binary + format. If opening read/write fails, System_RNG silently backs down to + read-only, in which case calls to ``add_entropy`` on that object will fail. + (GH #647 #648) + +* Fix use of Win32 CryptoAPI RNG as an entropy source, which was accidentally + disabled due to empty list of acceptable providers being specified. Typically + the library would fall back to gathering entropy from OS functions returning + statistical information, but if this functionality was disabled in the build a + ``PRNG_Unseeded`` exception would result. (GH #655) + +* Add support for building the library as part of the IncludeOS unikernel. + This included making filesystem and threading support optional. (GH #665) + +* Added ISA annotations so that with GCC (all supported versions) and + Clang (since 3.7) it is no longer required to compile amalgamation + files with ABI specific flags such as ``-maes``. (GH #665) + +* Internal cleanups to TLS CBC record handling. TLS CBC ciphersuites + can now be disabled by disabling ``tls_cbc`` module. (GH #642 #659) + +* Internal cleanups to the object lookup code eliminates most global locks and + all use of static initializers (GH #668 #465) + +* Avoid ``static_assert`` triggering under MSVC debug builds (GH #646) + +* The antique PBKDF1 password hashing scheme is deprecated and will be + removed in a future release. It was only used to support the equally + ancient PBES1 private key encryption scheme, which was removed in 1.11.8. + +* Added MSVC debug/checked iterator builds (GH #666 #667) + +* Added Linux ppc64le cross compile target to Travis CI (GH #654) + +* If RC4 is disabled, also disable it coming from the OpenSSL provider (GH #641) + +* Add TLS message parsing tests (GH #640) + +* Updated BSI policy to prohibit DES, HKDF, HMAC_RNG (GH #649) + +* Documentation improvements (GH #660 #662 #663 #670) + +Version 1.11.32, 2016-09-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for the NewHope Ring-LWE key encapsulation algorithm. This scheme + provides an estimated ~200 bit security level against a quantum attacker while + also being very fast and requiring only modest message sizes of 1824 and 2048 + bytes for initiator and responder, resp. This version is tested as having + bit-for-bit identical output as the reference implementation by the authors. + + Be warned that NewHope is still a very new scheme and may yet fall to analysis. + For best assurance, NewHope should be used only in combination with another + key exchange mechanism, such as ECDH. + +* New TLS callbacks API. Instead of numerous std::function callbacks, the + application passes an object implementing the TLS::Callbacks interface, which + has virtual functions matching the previous callbacks (plus some extras). + Full source compatability with previous versions is maintained for now, but + the old interface is deprecated and will be removed in a future release. The + manual has been updated to reflect the changes. (GH #457 and #567) + +* Add support for TLS Encrypt-then-MAC extension (GH #492 and #578), which fixes + the known issues in the TLS CBC-HMAC construction. + +* The format of the TLS session struct has changed (to support EtM), so old + TLS session caches will be invalidated. + +* How the library presents optimized algorithm implementations has changed. For + example with the algorithm AES-128, previously there were three BlockCipher + classes AES_128, AES_128_SSSE3, and AES_128_NI which used (resp) a table-based + implementation vulnerable to side channels, a constant time version using + SSSE3 SIMD extensions on modern x86, and x86 AES-NI instructions. Using the + correct version at runtime required using ``BlockCipher::create``. Now, only + the class AES_128 is presented, and the best available version is always used + based on CPUID checks. The tests have been extended to selectively disable + CPUID bits to ensure all available versions are tested. (GH #477 #623) + + Removes API classes AES_128_NI, AES_192_NI, AES_256_NI, AES_128_SSSE3, + AES_192_SSSE3 AES_256_SSSE3, IDEA_SSE2, Noekeon_SIMD, Serpent_SIMD, + Threefish_512_AVX2, SHA_160_SSE2 + +* The deprecated algorithms Rabin-Williams, Nyberg-Rueppel, MARS, RC2, RC5, RC6, + SAFER-SK, TEA, MD2, HAS-160, and RIPEMD-128 have been removed. (GH #580) + +* A new Cipher_Mode interface ``process`` allows encryption/decryption of + buffers without requiring copying into ``secure_vector`` first. (GH #516) + +* Fix verification of self-issued certificates (GH #634) + +* SSE2 optimizations for ChaCha, 60% faster on both Westmere and Skylake (GH #616) + +* The HMAC_RNG constructor added in 1.11.31 that took both an RNG and an + entropy source list ignored the entropy sources. + +* The configure option ``--via-amalgamation`` was renamed to ``--amalgamation``. + The configure option ``--gen-amalgamation`` was removed. It did generate + amalgamations but build Botan without amalgamation. Users should migrate to + ``--amalgamation``. (GH #621) + +* DH keys did not automatically self-test after being generated, contrary to + the current behavior for other key types. + +* Add tests for TLS 1.2 PRF (GH #628) + +Version 1.11.31, 2016-08-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix undefined behavior in Curve25519 on platforms without a native 128-bit + integer type. This was known to produce incorrect results on 32-bit ARM + under Clang. GH #532 (CVE-2016-6878) + +* If X509_Certificate::allowed_usage was called with more than one Key_Usage + set in the enum value, the function would return true if *any* of the allowed + usages were set, instead of if *all* of the allowed usages are set. + GH #591 (CVE-2016-6879) + +* Incompatible changes in DLIES: Previously the input to the KDF was + the concatenation of the (ephemeral) public key and the secret value + derived by the key agreement operation. Now the input is only the + secret value obtained by the key agreement operation. That's how it + is specified in the original paper "DHIES: An encryption scheme + based on Diffie-Hellman Problem" or in BSI technical guideline + TR-02102-1 for example. In addition to the already present + XOR-encrypion/decryption mode it's now possible to use DLIES with a + block cipher. Furthermore the order of the output was changed from + {public key, tag, ciphertext} to {public key, ciphertext, tag}. Both + modes are compatible with BouncyCastle. + +* Add initial PKCS #11 support (GH #507). Currently includes a low level + wrapper to all of PKCS #11 (p11.h) and high level code for RSA and ECDSA + signatures and hardware RNG access. + +* Add ECIES encryption scheme, compatible with BouncyCastle (GH #483) + +* Add ECKCDSA signature algorithm (GH #504) + +* Add KDF1 from ISO 18033 (GH #483) + +* Add FRP256v1 curve (GH #551) + +* Changes for userspace PRNGs HMAC_DRBG and HMAC_RNG (GH #520 and #593) + + These RNGs now derive from Stateful_RNG which handles issues like periodic + reseeding and (on Unix) detecting use of fork. Previously these measures were + included only in HMAC_RNG. + + Stateful_RNG allows reseeding from another RNG and/or a specified set of + entropy sources. For example it is possible to configure a HMAC_DRBG to reseed + using a PKCS #11 token RNG, the CPU's RDSEED instruction, and the system RNG + but disabling all other entropy polls. + +* AutoSeeded_RNG now uses NIST SP800-90a HMAC_DRBG(SHA-384). (GH #520) + +* On Windows and Unix systems, the system PRNG is used as the sole reseeding + source for a default AutoSeeded_RNG, completely skipping the standard entropy + polling code. New constructors allow specifying the reseed RNG and/or entropy + sources. (GH #520) + +* The `hres_timer` entropy source module has been removed. Timestamp inputs to + the RNG are now handled as additional_data inputs to HMAC_DRBG. + +* Add RDRAND_RNG which directly exposes the CPU RNG (GH #543) + +* Add PKCS #1 v1.5 id for SHA-512/256 (GH #554) + +* Add X509_Time::to_std_timepoint (GH #560) + +* Fix a bug in ANSI X9.23 padding mode, which returned one byte more + than the given block size (GH #529). + +* Fix bug in SipHash::clear, which did not reset all state (GH #547) + +* Fixes for FreeBSD (GH #517) and OpenBSD (GH #523). The compiler defaults + to Clang on FreeBSD now. + +* SonarQube static analysis integration (GH #592) + +* Switched Travis CI to Ubuntu 14.04 LTS (GH #592) + +* Added ARM32, ARM64, PPC32, PPC64, and MinGW x86 cross compile targets to Travis CI (GH #608) + +* Clean up in TLS ciphersuite handling (GH #583) + +* Threefish-512 AVX2 optimization work (GH #581) + +* Remove build configuration host and timestamp from build.h + This makes this header reproducible and allows using ccache's direct mode + (GH #586 see also #587) + +* Prevent building for x86-64 with x86-32 compiler and the reverse (GH #585) + +* Avoid build problem on 32-bit userspace ARMv8 (GH #563) + +* Refactor of internal MP headers (GH #549) + +* Avoid MSVC C4100 warning (GH #525) + +* Change botan.exe to botan-cli.exe on Windows to workaround VC issue (GH #584) + +* More tests for RSA-KEM (GH #538), DH (GH #556), EME (GH #553), + cipher mode padding (GH #529), CTS mode (GH #531), + KDF1/ISO18033 (GH #537), OctetString (GH #545), OIDs (GH #546), + parallel hash (GH #548), charset handling (GH #555), + BigInt (GH #558), HMAC_DRBG (GH #598 #600) + +* New deprecations. See the full list in doc/deprecated.txt + + The X9.31 and HMAC_RNG RNGs are deprecated. + If you need a userspace PRNG, use HMAC_DRBG (or AutoSeeded_RNG + which is HMAC_DRBG with defaults). + + Support for getting entropy from EGD is deprecated, and will be + removed in a future release. The developers believe that it is + unlikely that any modern system requires EGD and so the code is now + dead weight. If you rely on EGD support, you should contact the + developers by email or GitHub ASAP. + + The TLS ciphersuites using 3DES and SEED are deprecated and will be + removed in a future release. + + ECB mode Cipher_Mode is deprecated and will be removed in a future + release. + + Support for BeOS/Haiku has not been tested in 5+ years and is in an + unknown state. Unless reports are received of successful builds and + use on this platform, support for BeOS/Haiku will be removed in a + future release. + +Version 1.11.30, 2016-06-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In 1.11.23 a bug was introduced such that CBC-encrypted TLS packets + containing no plaintext bytes at all were incorrectly rejected with + a MAC failure. Records like this are used by OpenSSL in TLS 1.0 + connections in order to randomize the IV. + +* A bug in GCM caused incorrect results if the 32-bit counter field + overflowed. This bug has no implications on the security but affects + interoperability. + + With a 96-bit nonce, this could only occur if at least 2**32 128-bit + blocks (64 GiB) were encrypted. This actually exceeds the maximum + allowable length of a GCM plaintext; when messages longer than + 2**32 - 2 blocks are encrypted, GCM loses its security properties. + + In addition to 96-bit nonces, GCM also supports nonces of arbitrary + length using a different method which hashes the provided nonce + under the authentication key. When using such a nonce, the last 4 + bytes of the resulting CTR input might be near the overflow + boundary, with the probability of incorrect overflow increasing with + longer messages. when encrypting 256 MiB of data under a random 128 + bit nonce, an incorrect result would be produced about 1/256 of the + time. With 1 MiB texts, the probability of error is reduced to 1/65536. + + Since TLS uses GCM with 96 bit nonces and limits the length of any + record to far less than 64 GiB, TLS GCM ciphersuites are not + affected by this bug. + + Reported by Juraj Somorovsky, described also in "Nonce-Disrespecting + Adversaries: Practical Forgery Attacks on GCM in TLS" + (https://eprint.iacr.org/2016/475.pdf) + +* Previously when generating a new self-signed certificate or PKCS #10 + request, the subject DN was required to contain both common name + (CN) and country (C) fields. These restrictions have been removed. + GH #496 + +* The Transform and Keyed_Transform interfaces has been removed. The + two concrete implementations of these interfaces were Cipher_Mode + and Compressor_Transform. The Cipher_Mode interface remains unchanged + as the Transform and Keyed_Transform signatures have moved to it; + no changes to Cipher_Mode usage should be necessary. Any uses of + Transform& or Keyed_Transform& to refer to a cipher should be replaced + by Cipher_Mode&. The compression algorithm interface has changed; the start + function now takes the per-message compression ratio to use. Previously the + compression level to use had to be set once, at creation time, and + the required ``secure_vector`` argument to ``start`` was required to be empty. + The new API is documented in `compression.rst` in the manual. + +* Add IETF versions of the ChaCha20Poly1305 TLS ciphersuites from + draft-ietf-tls-chacha20-poly1305-04. The previously implemented + (non-standard) ChaCha20Poly1305 ciphersuites from + draft-agl-tls-chacha20poly1305 remain but are deprecated. + +* The OCB TLS ciphersuites have been updated to use the new nonce + scheme from draft-zauner-tls-aes-ocb-04. This is incompatible with + previous versions of the draft, and the ciphersuite numbers used for + the (still experimental) OCB ciphersuites have changed. + +* Previously an unknown critical extension caused X.509 certificate + parsing to fail; such a cert could not be created at all. Now + parsing succeeds and the certificate validation fails with + an error indicating an unknown critical extension. GH #469 + +* X509_CRL previously had an option to cause it to ignore unknown + critical extensions. This has been removed. + +* Added StreamCipher::seek allowing seeking to arbitrary position + in the key stream. Currently only implemented for ChaCha. (GH #497) + +* Added support for ChaCha stream cipher with 8 or 12 rounds. + +* Add ECGDSA signature algorithm (GH #479) + +* Add support for label argument to KDFs (GH #495) + +* Add NIST SP800-108 and 56C KDFs (GH #481) + +* Support for Card Verifiable Certificates and the obsolete EMSA1_BSI + signature padding scheme have been removed. (GH #487) + +* A bug in the IETF version of ChaCha20Poly1305 (with 96 bit nonces) + caused incorrect computation when the plaintext or AAD was exactly + a multiple of 16 bytes. + +* Fix return type of TLS_Reader::get_u32bit, which was truncated to + 16 bits. This only affected decoding of session ticket lifetimes. + GH #478 + +* Fix OS X dylib naming problem (GH #468 #467) + +* Fix bcrypt function under Python 3 (GH #461) + +* The ``unix_procs`` entropy source is deprecated and will be removed + in a future release. This entropy source attempts to get entropy by + running Unix programs like ``arp``, ``netstat``, and ``dmesg`` which + produce information which may be difficult for a remote attacker to + guess. This exists primarily as a last-ditch for Unix systems + without ``/dev/random``. But at this point such systems effectively + no longer exist, and the use of ``fork`` and ``exec`` by the library + complicates effective application sandboxing. + +* Changes to avoid implicit cast warnings in Visual C++ (GH #484) + +Version 1.10.13, 2016-04-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Use constant time modular inverse algorithm to avoid possible + side channel attack against ECDSA (CVE-2016-2849) + +* Use constant time PKCS #1 unpadding to avoid possible side channel + attack against RSA decryption (CVE-2015-7827) + +* Avoid a compilation problem in OpenSSL engine when ECDSA was + disabled. Gentoo bug 542010 + +Version 1.11.29, 2016-03-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CVE-2016-2849 DSA and ECDSA used a modular inverse function which + had input dependent loops. It is possible a side channel attack on + this function could be used to recover sufficient information about + the nonce k to mount a lattice attack and recover the private key. + Found by Sean Devlin. + +* CVE-2016-2850 The TLS client did not check that the signature + algorithm or ECC curve a v1.2 server used was actually acceptable by + the policy. This would allow a server who ignored the preferences + indicated in the client to use a weak algorithm, and may allow MITM + attacks by an attacker who can break MD5 signatures or 160 bit ECC + in real time. The server similarly failed to check on the hash a + client used during client certificate authentication. + +* Reject empty TLS records at the record processing layer since such a + record is not valid regardless of the record type. Later checks + already correctly rejected empty records, but during processing such + a record, a pointer to the end of the vector was created, causing a + assertion failure under checked iterators. Found by Juraj Somorovsky. + +* Add PK_Decryptor::decrypt_or_random which allows an application to + atomically (in constant time) check that a decrypted ciphertext has + the expected length and/or apply content checks on the result. This + is used by the TLS server for decrypting PKCS #1 v1.5 RSA ciphertexts. + Previously the server used a implementation which was potentially + vulnerable to side channels. + +* Add support for processing X.509 name constraint extension during + path validation. GH #454 + +* Add X509_Certificate::v3_extensions which allows retreiving the + raw binary of all certificate extensions, including those which + are not known to the library. This allows processing of custom + extensions. GH #437 + +* Add support for module policies which are a preconfigured set of + acceptable or prohibited modules. A policy based on BSI TR-02102-1 + is included. GH #439 #446 + +* Support for the deprecated TLS heartbeat extension has been removed. + +* Support for the deprecated TLS minimum fragment length extension has + been removed. + +* SRP6 support is now optional in TLS + +* Support for negotiating MD5 and SHA-224 signatures in TLS v1.2 has + been removed. MD5 signatures are demonstratably insecure in TLS, + SHA-224 is rarely used. + +* Support for negotiating ECC curves secp160r1, secp160r2, secp160k1, + secp192k1, secp192r1 (P-192), secp224k1, secp224r1 (P-224), and + secp256k1 have been removed from the TLS implementation. All were + already disabled in the default policy. + +* HMAC_RNG now has an explicit check for fork using pid comparisons. + It also includes the pid and system and CPU clocks into the PRF + computation to help reduce the risk of pid wraparound. Even so, + applications using fork and userspace RNGs should explicitly reseed + all such RNGs whenever possible. + +* Deprecation warning: support for DSA certificates in TLS is + deprecated and will be removed in a future release. + +* Deprecation warning: in addition to the algorithms deprecated in + 1.11.26, the following algorithms are now deprecated and will be + removed in a future release: Rabin-Williams signatures, TEA, XTEA. + +* Deprecation warning: the library has a number of compiled in MODP + and ECC DL parameters. All MODP parameter sets under 2048 bits and + all ECC parameters under 256 bits are deprecated and will be removed + in a future release. This includes the MODP groups "modp/ietf/1024", + "modp/srp/1024", "modp/ietf/1536", "modp/srp/1536" and the ECC + groups "secp160k1", "secp160r1", "secp160r2", "secp192k1", + "secp192r1", "secp224k1", "secp224r1", "brainpool160r1", + "brainpool192r1", "brainpool224r1", "x962_p192v2", "x962_p192v3", + "x962_p239v1", "x962_p239v2" and "x962_p239v3". Additionally all + compiled in DSA parameter sets ("dsa/jce/1024", "dsa/botan/2048", + and "dsa/botan/3072") are also deprecated. + +* RDSEED/RDRAND polling now retries if the operation fails. GH #373 + +* Fix various minor bugs found by static analysis with PVS-Studio (GH#421), + Clang analyzer (GH #441), cppcheck (GH #444, #445), and Coverity. + +* Add --with-valgrind configure option to enable building against the + valgrind client API. This currently enables checking of const time + operations using memcheck. + +* Fix remaining Wshadow warnings. Enable Wshadow in build. GH #427 + +* Use noexcept in VS 2015 GH #429 + +* On Windows allow the user to explicitly request symlinks be used + as part of the build. Likely only useful for someone working on + the library itself. GH #430 + +* Remove use of TickCount64 introduced in 1.11.27 which caused problem + with downstream distributors/users building XP compatiable binaries + which is still an option even in VS 2015 + +* MCEIES requires KDF1 at runtime but did not require it be enabled + in the build. GH #369 + +* Small optimizations to Keccak hash + +* Support for locking allocator on Windows using VirtualLock. GH #450 + +Version 1.8.15, 2016-02-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* NOTE WELL: Botan 1.8 is not supported for security issues anymore. + Moving to 1.10 or 1.11 is certainly recommended. +* Fix CVE-2014-9742: Insufficient randomness in Miller-Rabin primality check +* Fix CVE-2016-2194: Infinite loop in modulur square root algorithm +* Fix CVE-2015-5726: Crash in BER decoder +* Fix CVE-2015-5727: Excess memory allocation in BER decoder + Note: Unlike the fix in 1.10 which checks that the source actually + contains enough data to satisfy the read before allocating the + memory, 1.8.15 simply rejects all ASN.1 blocks larger than 1 MiB. + This simpler check avoids the problem without breaking ABI. + +Version 1.10.12, 2016-02-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In 1.10.11, the check in PointGFp intended to check the affine y + argument actually checked the affine x again. Reported by Remi Gacogne + + The CVE-2016-2195 overflow is not exploitable in 1.10.11 due to an + additional check in the multiplication function itself which was + also added in that release, so there are no security implications + from the missed check. However to avoid confusion the change was + pushed in a new release immediately. + + The 1.10.11 release notes incorrectly identified CVE-2016-2195 as CVE-2016-2915 + +Version 1.10.11, 2016-02-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Resolve heap overflow in ECC point decoding. CVE-2016-2195 + +* Resolve infinite loop in modular square root algorithm. + CVE-2016-2194 + +* Correct BigInt::to_u32bit to not fail on integers of exactly 32 bits. + GH #239 + +Version 1.11.28, 2016-02-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* One of the checks added while addressing CVE-2016-2195 was incorrect + and could cause needless assertion failures. + +Version 1.11.27, 2016-02-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* SECURITY: Avoid heap overflow in ECC point decoding. This could + likely result in remote code execution. CVE-2016-2195 + +* SECURITY: Avoid one word heap overflow in P-521 reduction function. + This could potentially lead to remote code execution or other + attack. CVE-2016-2196. + +* SECURITY: Avoid infinite or near-infinite loop during modular square + root algorithm with invalid inputs. CVE-2016-2194 + +* Add Blake2b hash function. GH #413 + +* Use ``m_`` prefix on all member variables. GH #398 and #407 + +* Use final qualifier on many classes. GH #408 + +* Use noreturn attribute on assertion failure function to assist + static analysis. GH #403 + +* Use TickCount64 and MemoryStatusEx in the Windows entropy source. + Note these calls are only available in Vista/Server 2008. No + accomodations are made for XP or Server 2003, both of which are + no longer patched by the vendor. GH #365 + +Version 1.11.26, 2016-01-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Deprecation warnings: Nyberg-Rueppel signatures, MARS, RC2, RC5, + RC6, SAFER, HAS-160, RIPEMD-128, MD2 and support for the TLS minimum + fragment length extensions are all being considered for removal in a + future release. If there is a compelling use case for keeping any of + them in the library, please open a discussion ticket on GitHub. + +* Support for the TLS extended master secret extension (RFC 7627) has + been added. + +* The format of serialized TLS sessions has changed to add a flag + indicating support for the extended master secret flag, which is + needed for proper handling of the extension. + +* Root all exceptions thrown by the library in the ``Botan::Exception`` class. + Previously the library would in many cases throw ``std::runtime_error`` + or ``std::invalid_argument`` exceptions which would make it hard to + determine the source of the error in some cases. + +* The command line interface has been mostly rewritten. The syntax of + many of the sub-programs has changed, and a number have been + extended with new features and options. + +* Correct an error in PointGFp multiplication when multiplying a point + by the scalar value 3. PointGFp::operator* would instead erronously + compute it as if the scalar was 1 instead. + +* Enable RdRand entropy source on Windows/MSVC. GH #364 + +* Add Intel's RdSeed as entropy source. GH #370 + +* Add preliminary support for accessing TPM v1.2 devices. Currently + random number generation, RSA key generation, and signing are + supported. Tested using Trousers and an ST TPM + +* Add generalized interface for KEM (key encapsulation) techniques. Convert + McEliece KEM to use it. The previous interfaces McEliece_KEM_Encryptor and + McEliece_KEM_Decryptor have been removed. The new KEM interface now uses a KDF + to hash the resulting keys; to get the same output as previously provided by + McEliece_KEM_Encryptor, use "KDF1(SHA-512)" and request exactly 64 bytes. + +* Add support for RSA-KEM from ISO 18033-2 + +* Add support for ECDH in the OpenSSL provider + +* Fix a bug in DataSource::discard_next() which could cause either an + infinite loop or the discarding of an incorrect number of bytes. + Reported on mailing list by Falko Strenzke. + +* Previously if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK was defined, + the code doing low level loads/stores would use pointer casts to + access larger words out of a (potentially misaligned) byte array, + rather than using byte-at-a-time accesses. However even on platforms + such as x86 where this works, it triggers UBSan errors under Clang. + Instead use memcpy, which the C standard says is usable for such + purposes even with misaligned values. With recent GCC and Clang, the + same code seems to be emitted for either approach. + +* Avoid calling memcpy, memset, or memmove with a length of zero to + avoid undefined behavior, as calling these functions with an invalid + or null pointer, even with a length of zero, is invalid. Often there + are corner cases where this can occur, such as pointing to the very + end of a buffer. + +* The function ``RandomNumberGenerator::gen_mask`` (added in 1.11.20) + had undefined behavior when called with a bits value of 32 or + higher, and was tested to behave in unpleasant ways (such as + returning zero) when compiled by common compilers. This function was + not being used anywhere in the library and rather than support + something without a use case to justify it it seemed simpler to + remove it. Undefined behavior found by Daniel Neus. + +* Support for using ``ctgrind`` for checking const time blocks has + been replaced by calling the valgrind memcheck APIs directly. This + allows const-time behavior to be tested without requiring a modified + valgrind binary. Adding the appropriate calls requires defining + BOTAN_HAS_VALGRIND in build.h. A binary compiled with this flag set + can still run normally (though with some slight runtime overhead). + +* Export MGF1 function mgf1_mask GH #380 + +* Work around a problem with some antivirus programs which causes the + ``shutil.rmtree`` and ``os.makedirs`` Python calls to occasionally + fail. The could prevent ``configure.py`` from running sucessfully + on such systems. GH #353 + +* Let ``configure.py`` run under CPython 2.6. GH #362 + +Version 1.11.25, 2015-12-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In this release the test suite has been largely rewritten. Previously the + tests had internally used several different test helper frameworks created or + adopted over time, each of which was insufficient on its own for testing the + entire library. These have been fully converged on a new framework which + suffices for all of the tests. There should be no user-visible change as a + result of this, except that the output format of `botan-test` has changed. + +* Improved side channel countermeasures for the table based AES implementation. + The 4K T tables are computed (once) at runtime to avoid various cache based + attacks which are possible due to shared VMM mappings of read only tables. + Additionally every cache line of the table is read from prior to processing + the block(s). + +* Support for the insecure ECC groups secp112r1, secp112r2, secp128r1, and + secp128r2 has been removed. + +* The portable version of GCM has been changed to run using only + constant time operations. + +* Work around a bug in MSVC 2013 std::mutex which on some Windows + versions can result in a deadlock during static initialization. On + Windows a CriticalSection is used instead. Analysis and patch from + Matej Kenda (TopIT d.o.o.). GH #321 + +* The OpenSSL implementation of RC4 would return the wrong value from `name` if + leading bytes of the keystream had been skipped in the output. + +* Fixed the signature of the FFI function botan_pubkey_destroy, which took the + wrong type and was not usable. + +* The TLS client would erronously reject any server key exchange packet smaller + than 6 bytes. This prevented negotiating a plain PSK TLS ciphersuite with an + empty identity hint. ECDHE_PSK and DHE_PSK suites were not affected. + +* Fixed a bug that would cause the TLS client to occasionally reject a valid + server key exchange message as having an invalid signature. This only affected + DHE and SRP ciphersuites. + +* Support for negotiating use of SHA-224 in TLS has been disabled in the + default policy. + +* Added `remove_all` function to the `TLS::Session_Manager` interface + +* Avoid GCC warning in pedantic mode when including bigint.h GH #330 + +Version 1.11.24, 2015-11-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* When the bugs affecting X.509 path validation were fixed in 1.11.23, a check + in Credentials_Manager::verify_certificate_chain was accidentally removed + which caused path validation failures not to be signaled to the TLS layer. + Thus in 1.11.23 certificate authentication in TLS is bypassed. + Reported by Florent Le Coz in GH #324 + +* Fixed an endian dependency in McEliece key generation which caused + keys to be generated differently on big and little endian systems, + even when using a deterministic PRNG with the same seed. + +* In `configure,py`, the flags for controlling use of debug, sanitizer, and + converage information have been split out into individual options + `--with-debug-info`, `--with-sanitizers`, and `--with-coverage`. These allow + enabling more than one in a build in a controlled way. The `--build-mode` flag + added in 1.11.17 has been removed. + +Version 1.11.23, 2015-10-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CVE-2015-7824: An information leak allowed padding oracle attacks against + TLS CBC decryption. Found in a review by Sirrix AG and 3curity GmbH. + +* CVE-2015-7825: Validating a malformed certificate chain could cause an + infinite loop. Found in a review by Sirrix AG and 3curity GmbH. + +* CVE-2015-7826: X.509 path validation violated RFC 6125 and would accept + certificates which should not validate under those rules. In particular botan + would accept wildcard certificates as matching in situations where it should + not (for example it would erroneously accept ``*.example.com`` as a valid + wildcard for ``foo.bar.example.com``) + +* CVE-2015-7827: The routines for decoding PKCS #1 encryption and OAEP blocks + have been rewritten to run without secret indexes or branches. These + cryptographic operations are vulnerable to oracle attacks, including via side + channels such as timing or cache-based analysis. In theory it would be + possible to attack the previous implementations using such a side channel, + which could allow an attacker to mount a plaintext recovery attack. + + By writing the code such that it does not depend on secret inputs for branch + or memory indexes, such a side channel would be much less likely to exist. + + The OAEP code has previously made an attempt at constant time operation, but + it used a construct which many compilers converted into a conditional jump. + +* Add support for using ctgrind (https://github.com/agl/ctgrind) to test that + sections of code do not use secret inputs to decide branches or memory indexes. + The testing relies on dynamic checking using valgrind. + + So far PKCS #1 decoding, OAEP decoding, Montgomery reduction, IDEA, and + Curve25519 have been notated and confirmed to be constant time on Linux/x86-64 + when compiled by gcc. + +* Public key operations can now be used with specified providers by passing an + additional parameter to the constructor of the PK operation. + +* OpenSSL RSA provider now supports signature creation and verification. + +* The blinding code used for RSA, Diffie-Hellman, ElGamal and Rabin-Williams now + periodically reinitializes the sequence of blinding values instead of always + deriving the next value by squaring the previous ones. The reinitializion + interval can be controlled by the build.h parameter BOTAN_BLINDING_REINIT_INTERVAL. + +* A bug decoding DTLS client hellos prevented session resumption for succeeding. + +* DL_Group now prohibits creating a group smaller than 1024 bits. + +* Add System_RNG type. Previously the global system RNG was only accessible via + `system_rng` which returned a reference to the object. However is at times + useful to have a unique_ptr which will be either the + system RNG or an AutoSeeded_RNG, depending on availability, which this + additional type allows. + +* New command line tools `dl_group` and `prime` + +* The `configure.py` option `--no-autoload` is now also available + under the more understandable name `--minimized-build`. + +* Note: 1.11.22 was briefly released on 2015-10-26. The only difference between + the two was a fix for a compilation problem in the OpenSSL RSA code. As the + 1.11.22 release had already been tagged it was simpler to immediately release + 1.11.23 rather than redo the release. + +Version 1.11.21, 2015-10-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add new methods for creating types such as BlockCiphers or HashFunctions, + T::providers() returning list of provider for a type, and T::create() creating + a new object of a specified provider. The functions in lookup.h forward to + these new APIs. A change to the lookup system in 1.11.14 had caused problems + with static libraries (GH #52). These problems have been fixed as part of these + changes. GH #279 + +* Fix loading McEliece public or private keys with PKCS::load_key / X509::load_key + +* Add `mce` command line tool for McEliece key generation and file encryption + +* Add Darwin_SecRandom entropy source which uses `SecRandomCopyBytes` + API call for OS X and iOS, as this call is accessible even from a + sandboxed application. GH #288 + +* Add new HMAC_DRBG constructor taking a name for the MAC to use, rather + than a pointer to an object. + +* The OCaml module is now a separate project at + https://github.com/randombit/botan-ocaml + +* The encrypted sqlite database support in contrib has moved to + https://github.com/randombit/botan-sqlite + +* The Perl XS module has been removed as it was no longer maintained. + +Version 1.11.20, 2015-09-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Additional countermeasures were added to ECC point multiplications + including exponent blinding and randomization of the point + representation to help protect against side channel attacks. + +* An ECDSA provider using OpenSSL has been added. + +* The ordering of algorithm priorities has been reversed. Previously + 255 was the lowest priority and 0 was the highest priority. Now it + is the reverse, with 0 being lowest priority and 255 being highest. + The default priority for the base algorithms is 100. This only + affects external providers or applications which directly set + provider preferences. + +* On OS X, rename libs to avoid trailing version numbers, e.g. + libbotan-1.11.dylib.19 -> libbotan-1.11.19.dylib. This was requested + by the Homebrew project package audit. GH #241, #260 + +* Enable use of CPUID interface with clang. GH #232 + +* Add support for MSVC 2015 debug builds by satisfying C++ allocator + requirements. SO 31802806, GH #236 + +* Make `X509_Time` string parsing and `to_u32bit()` more strict to avoid + integer overflows and other potentially dangerous misinterpretations. + GH #240, #243 + +* Remove all 'extern "C"' declarations from src/lib/math/mp/ because some + of those did throw exceptions and thus cannot be C methods. GH #249 + +* Fix build configuration for clang debug on Linux. GH #250 + +* Fix zlib error when compressing an empty buffer. GH #265 + +* Fix iOS builds by allowing multiple compiler flags with the same name. + GH #266 + +* Fix Solaris build issue caused by `RLIMIT_MEMLOCK`. GH #262 + +Version 1.11.19, 2015-08-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* SECURITY: The BER decoder would crash due to reading from offset 0 + of an empty vector if it encountered a BIT STRING which did not + contain any data at all. As the type requires a 1 byte field this is + not valid BER but could occur in malformed data. Found with afl. + CVE-2015-5726 + +* SECURITY: The BER decoder would allocate a fairly arbitrary amount + of memory in a length field, even if there was no chance the read + request would succeed. This might cause the process to run out of + memory or invoke the OOM killer. Found with afl. + CVE-2015-5727 + +* The TLS heartbeat extension is deprecated and unless strong arguments + are raised in its favor it will be removed in a future release. + Comment at https://github.com/randombit/botan/issues/187 + +* The x86-32 assembly versions of MD4, MD5, SHA-1, and Serpent and the + x86-64 version of SHA-1 have been removed. With compilers from this + decade the C++ versions are significantly faster. The SSE2 versions + of SHA-1 and Serpent remain, as they are still the fastest version + for processors with SIMD extensions. GH #216 + +* BigInt::to_u32bit would fail if the value was exactly 32 bits. + GH #220 + +* Botan is now fully compaitible with _GLIBCXX_DEBUG. GH #73 + +* BigInt::random_integer distribution was not uniform. GH #108 + +* Added unit testing framework Catch. GH #169 + +* Fix `make install`. GH #181, #186 + +* Public header `fs.h` moved to `internal/filesystem.h`. Added filesystem + support for MSVC 2013 when boost is not available, allowing tests to run on + those systems. GH #198, #199 + +* Added os "android" and fix Android compilation issues. GH #203 + +* Drop support for Python 2.6 for all Botan Python scripts. GH #217 + +Version 1.10.10, 2015-08-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* SECURITY: The BER decoder would crash due to reading from offset 0 + of an empty vector if it encountered a BIT STRING which did not + contain any data at all. As the type requires a 1 byte field this is + not valid BER but could occur in malformed data. Found with afl. + CVE-2015-5726 + +* SECURITY: The BER decoder would allocate a fairly arbitrary amount + of memory in a length field, even if there was no chance the read + request would succeed. This might cause the process to run out of + memory or invoke the OOM killer. Found with afl. + CVE-2015-5727 + +* Due to an ABI incompatible (though not API incompatible) change in + this release, the version number of the shared object has been + increased. + +* The default TLS policy no longer allows RC4. + +* Fix a signed integer overflow in Blue Midnight Wish that may cause + incorrect computations or undefined behavior. + +Version 1.11.18, 2015-07-05 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In this release Botan has switched VCS from ``monotone`` to ``git``, + and is now hosted on github at https://github.com/randombit/botan + +* The TLS client called ``std::set_difference`` on an invalid iterator + pair. This could potentially lead to a crash depending on the + compiler and STL implementation. It also would trigger assertion + failures when using checked iterators. GH #73 + +* Remove code constructs which triggered errors under MSVC and GCC + debug iterators. The primary of these was an idiom of ``&vec[x]`` to + create a pointer offset of a ``std::vector``. This failed when x was + set equal to ``vec.size()`` to create the one-past-the-end address. + The pointer in question was never dereferenced, but it triggered + the iterator debugging checks which prevented using these valuble + analysis tools. From Simon Warta and Daniel Seither. GH #125 + +* Several incorrect or missing module dependencies have been fixed. These + often prevented a successful build of a minimized amalgamation when + only a small set of algorithms were specified. GH #71 + From Simon Warta. + +* Add an initial binding to OCaml. Currently only hashes, RNGs, and + bcrypt are supported. + +* The default key size generated by the ``keygen`` tool has increased + to 2048 bits. From Rene Korthaus. + +* The ``Botan_types`` namespace, which contained ``using`` declarations + for (just) ``Botan::byte`` and ``Botan::u32bit``, has been removed. + Any use should be replaced by ``using`` declarations for those types + directly. + +Version 1.11.17, 2015-06-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* All support for the insecure RC4 stream cipher has been removed + from the TLS implementation. + +* Fix decoding of TLS maximum fragment length. Regardless of what + value was actually negotiated, TLS would treat it as a negotiated + limit of 4096. + +* Fix the configure.py flag ``--disable-aes-ni`` which did nothing of + the sort. + +* Fixed nmake clean target. GitHub #104 + +* Correct buffering logic in ``Compression_Filter``. GitHub #93 and #95 + +Version 1.11.16, 2015-03-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* TLS has changed from using the non-standard NPN extension to the IETF + standardized ALPN extension for negotiating an application-level protocol. + Unfortunately the semantics of the exchange have changed with ALPN. Using + NPN, the server offered a list of protocols it advertised, and then the + client chose its favorite. With ALPN, the client offers a list of protocols + and the server chooses. The the signatures of both the TLS::Client and + TLS::Server constructors have changed to support this new flow. + +* Optimized ECDSA signature verification thanks to an observation by + Dr. Falko Strenzke. On some systems verifications are between 1.5 + and 2 times faster than in 1.11.15. + +* RSA encrypt and decrypt operations using OpenSSL have been added. + +* Public key operation types now handle all aspects of the operation, + such as hashing and padding for signatures. This change allows + supporting specialized implementations which only support particular + padding types. + +* Added global timeout to HMAC_RNG entropy reseed. The defaults are + the values set in the build.h macros ``BOTAN_RNG_AUTO_RESEED_TIMEOUT`` + and ``BOTAN_RNG_RESEED_DEFAULT_TIMEOUT``, but can be overriden + on a specific poll with the new API call reseed_with_timeout. + +* Fixed Python cipher update_granularity() and default_nonce_length() + functions + +* The library now builds on Visual C++ 2013 + +* The GCM update granularity was reduced from 4096 to 16 bytes. + +* Fix a bug that prevented building the amalgamation until a non-amalgamation + configuration was performed first in the same directory. + +* Add Travis CI integration. Github pull 60. + +Version 1.11.15, 2015-03-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Support for RC4 in TLS, already disabled by default, is now deprecated. + The RC4 ciphersuites will be removed entirely in a future release. + +* A bug in ffi.cpp meant Python could only encrypt. Github issue 53. + +* When comparing two ASN.1 algorithm identifiers, consider empty and + NULL parameters the same. + +* Fixed memory leaks in TLS and cipher modes introduced in 1.11.14 + +* MARK-4 failed when OpenSSL was enabled in the build in 1.11.14 + because the OpenSSL version ignored the skip parameter. + +* Fix compilation problem on OS X/clang + +* Use BOTAN_NOEXCEPT macro to work around lack of noexcept in VS 2013 + +Version 1.11.14, 2015-02-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The global state object previously used by the library has been removed. + This includes the global PRNG. The library can be safely initialized + multiple times without harm. + + The engine code has also been removed, replaced by a much lighter-weight + object registry system which provides lookups in faster time and with less + memory overhead than the previous approach. + + One caveat of the current system with regards to static linking: because only + symbols already mentioned elsewhere in the program are included in the final + link step, few algorithms will be available through the lookup system by + default, even though they were compiled into the library. Your application + must explicitly reference the types you require or they will not end up + being available in the final binary. See also Github issue #52 + + If you intend to build your application against a static library and don't + want to explicitly reference each algo object you might attempt to look up by + string, consider either building with ``--via-amalgamation``, or else (much + simpler) using the amalgamation directly. + +* The new ``ffi`` submodule provides a simple C API/ABI for a number of useful + operations (hashing, ciphers, public key operations, etc) which is easily + accessed using the FFI modules included in many languages. + +* A new Python wrapper (in ``src/lib/python/botan.py``) using ``ffi`` and the Python + ``ctypes`` module is available. The old Boost.Python wrapper has been removed. + +* Add specialized reducers for P-192, P-224, P-256, and P-384 + +* OCB mode, which provides a fast and constant time AEAD mode without requiring + hardware support, is now supported in TLS, following + draft-zauner-tls-aes-ocb-01. Because this specification is not yet finalized + is not yet enabled by the default policy, and the ciphersuite numbers used are + in the experimental range and may conflict with other uses. + +* Add ability to read TLS policy from a text file using ``TLS::Text_Policy``. + +* The amalgamation now splits off any ISA specific code (for instance, that + requiring SSSE3 instruction sets) into a new file named (for instance) + ``botan_all_ssse3.cpp``. This allows the main amalgamation file to be compiled + without any special flags, so ``--via-amalgamation`` builds actually work now. + This is disabled with the build option ``--single-amalgamation-file`` + +* PBKDF and KDF operations now provide a way to write the desired output + directly to an application-specified area rather than always allocating a new + heap buffer. + +* HKDF, previously provided using a non-standard interface, now uses the + standard KDF interface and is retrievable using get_kdf. + +* It is once again possible to build the complete test suite without requiring + any boost libraries. This is currently only supported on systems supporting + the readdir interface. + +* Remove use of memset_s which caused problems with amalgamation on OS X. + Github 42, 45 + +* The memory usage of the counter mode implementation has been reduced. + Previously it encrypted 256 blocks in parallel as this leads to a slightly + faster counter increment operation. Instead CTR_BE simply encrypts a buffer + equal in size to the advertised parallelism of the cipher implementation. + This is not measurably slower, and dramatically reduces the memory use of + CTR mode. + +* The memory allocator available on Unix systems which uses mmap and mlock to + lock a pool of memory now checks environment variable BOTAN_MLOCK_POOL_SIZE + and interprets it as an integer. If the value set to a smaller value then the + library would originally have allocated (based on resource limits) the user + specified size is used instead. You can also set the variable to 0 to + disable the pool entirely. Previously the allocator would consume all + available mlocked memory, this allows botan to coexist with an application + which wants to mlock memory for its own uses. + +* The botan-config script previously installed on Unix systems has been + removed. Its functionality is replaced by the ``config`` command of the + ``botan`` tool executable, for example ``botan config cflags`` instead of + ``botan-config --cflags``. + +* Added a target for POWER8 processors + +Version 1.11.13, 2015-01-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* All support for the insecure SSLv3 protocol and the server support + for processing SSLv2 client hellos has been removed. + +* The command line tool now has ``tls_proxy`` which negotiates TLS with + clients and forwards the plaintext to a specified port. + +* Add MCEIES, a McEliece-based integrated encryption system using + AES-256 in OCB mode for message encryption/authentication. + +* Add DTLS-SRTP negotiation defined in RFC 5764 + +* Add SipHash + +* Add SHA-512/256 + +* The format of serialized TLS sessions has changed. Additiionally, PEM + formatted sessions now use the label of "TLS SESSION" instead of "SSL SESSION" + +* Serialized TLS sessions are now encrypted using AES-256/GCM instead of a + CBC+HMAC construction. + +* The cryptobox_psk module added in 1.11.4 and previously used for TLS session + encryption has been removed. + +* When sending a TLS heartbeat message, the number of pad bytes to use can now + be specified, making it easier to use for PMTU discovery. + +* If available, zero_mem now uses RtlSecureZeroMemory or memset_s instead of a + byte-at-a-time loop. + +* The functions base64_encode and base64_decode would erroneously + throw an exception if passed a zero-length input. Github issue 37. + +* The Python install script added in version 1.11.10 failed to place the + headers into a versioned subdirectory. + +* Fix the install script when running under Python3. + +* Avoid code that triggers iterator debugging asserts under MSVC 2013. Github + pull 36 from Simon Warta. + +Version 1.11.12, 2015-01-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Curve25519. The implementation is based on curve25519-donna-c64.c + by Adam Langley. New (completely non-standard) OIDs and formats for + encrypting Curve25519 keys under PKCS #8 and including them in + certificates and CRLs have been defined. + +* Add Poly1305, based on the implementation poly1305-donna by Andrew Moon. + +* Add the ChaCha20Poly1305 AEADs defined in draft-irtf-cfrg-chacha20-poly1305-03 + and draft-agl-tls-chacha20poly1305-04. + +* Add ChaCha20Poly1305 ciphersuites for TLS compatible with Google's servers + following draft-agl-tls-chacha20poly1305-04 + +* When encrypted as PKCS #8 structures, Curve25519 and McEliece + private keys default to using AES-256/GCM instead of AES-256/CBC + +* Define OIDs for OCB mode with AES, Serpent and Twofish. + +Version 1.11.11, 2014-12-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The Sqlite3 wrapper has been abstracted to a simple interface for + SQL dbs in general, though Sqlite3 remains the only implementation. + The main logic of the TLS session manager which stored encrypted + sessions to a Sqlite3 database (``TLS::Session_Manager_SQLite``) has + been moved to the new ``TLS::Session_Manager_SQL``. The Sqlite3 + manager API remains the same but now just subclasses + ``TLS::Session_Manager_SQL`` and has a constructor instantiate the + concrete database instance. + + Applications which would like to use a different db can now do so + without having to reimplement the session cache logic simply by + implementing a database wrapper subtype. + +* The CryptGenRandom entropy source is now also used on MinGW. + +* The system_rng API is now also available on systems with CryptGenRandom + +* With GCC use -fstack-protector for linking as well as compiling, + as this is required on MinGW. Github issue 34. + +* Fix missing dependency in filters that caused compilation problem + in amalgamation builds. Github issue 33. + +* SSLv3 support is officially deprecated and will be removed in a + future release. + +Version 1.10.9, 2014-12-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed EAX tag verification to run in constant time + +* The default TLS policy now disables SSLv3. + +* A crash could occur when reading from a blocking random device if + the device initially indicated that entropy was available but + a concurrent process drained the entropy pool before the + read was initiated. + +* Fix decoding indefinite length BER constructs that contain a context + sensitive tag of zero. Github pull 26 from Janusz Chorko. + +* The ``botan-config`` script previously tried to guess its prefix from + the location of the binary. However this was error prone, and now + the script assumes the final installation prefix matches the value + set during the build. Github issue 29. + +Version 1.11.10, 2014-12-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* An implementation of McEliece code-based public key encryption based + on INRIA's HyMES and secured against a variety of side-channels was + contributed by cryptosource GmbH. The original version is LGPL but + cryptosource has secured permission to release an adaptation under a + BSD license. A CCA2-secure KEM scheme is also included. + + The implementation is further described in + http://www.cryptosource.de/docs/mceliece_in_botan.pdf and + http://cryptosource.de/news_mce_in_botan_en.html + +* DSA and ECDSA now create RFC 6979 deterministic signatures. + +* Add support for TLS fallback signaling (draft-ietf-tls-downgrade-scsv-00). + Clients will send a fallback SCSV if the version passed to the Client + constructor is less than the latest version supported by local policy, so + applications implementing fallback are protected. Servers always check the + SCSV. + +* In previous versions a TLS::Server could service either TLS or DTLS + connections depending on policy settings and what type of client hello it + received. This has changed and now a Server object is initialized for + either TLS or DTLS operation. The default policy previously prohibited + DTLS, precisely to prevent a TCP server from being surprised by a DTLS + connection. The default policy now allows TLS v1.0 or higher or DTLS v1.2. + +* Fixed a bug in CCM mode which caused it to produce incorrect tags when used + with a value of L other than 2. This affected CCM TLS ciphersuites, which + use L=3. Thanks to Manuel Pégourié-Gonnard for the anaylsis and patch. + Bugzilla 270. + +* DTLS now supports timeouts and handshake retransmits. Timeout checking + is triggered by the application calling the new TLS::Channel::timeout_check. + +* Add a TLS policy hook to disable putting the value of the local clock in hello + random fields. + +* All compression operations previously available as Filters are now + performed via the Transformation API, which minimizes memory copies. + Compression operations are still available through the Filter API + using new general compression/decompression filters in comp_filter.h + +* The zlib module now also supports gzip compression and decompression. + +* Avoid a crash in low-entropy situations when reading from /dev/random, when + select indicated the device was readable but by the time we start the read the + entropy pool had been depleted. + +* The Miller-Rabin primality test function now takes a parameter allowing the + user to directly specify the maximum false negative probability they are + willing to accept. + +* PKCS #8 private keys can now be encrypted using GCM mode instead of + unauthenticated CBC. The default remains CBC for compatibility. + +* The default PKCS #8 encryption scheme has changed to use PBKDF2 with + SHA-256 instead of SHA-1 + +* A specialized reducer for P-521 was added. + +* On Linux the mlock allocator will use MADV_DONTDUMP on the pool so + that the contents are not included in coredumps. + +* A new interface for directly using a system-provided PRNG is + available in system_rng.h. Currently only systems with /dev/urandom + are supported. + +* Fix decoding indefinite length BER constructs that contain a context sensitive + tag of zero. Github pull 26 from Janusz Chorko. + +* The GNU MP engine has been removed. + +* Added AltiVec detection for POWER8 processors. + +* Add a new install script written in Python which replaces shell hackery in the + makefiles. + +* Various modifications to better support Visual C++ 2013 and 2015. Github + issues 11, 17, 18, 21, 22. + +Version 1.10.8, 2014-04-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* SECURITY: Fix a bug in primality testing introduced in 1.8.3 which + caused only a single random base, rather than a sequence of random + bases, to be used in the Miller-Rabin test. This increased the + probability that a non-prime would be accepted, for instance a 1024 + bit number would be incorrectly classed as prime with probability + around 2^-40. Reported by Jeff Marrison. CVE-2014-9742 + +* The key length limit on HMAC has been raised to 512 bytes, allowing + the use of very long passphrases with PBKDF2. + +Version 1.11.9, 2014-04-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* SECURITY: Fix a bug in primality testing introduced in 1.8.3 which + caused only a single random base, rather than a sequence of random + bases, to be used in the Miller-Rabin test. This increased the + probability that a non-prime would be accepted, for instance a 1024 + bit number would be incorrectly classed as prime with probability + around 2^-40. Reported by Jeff Marrison. CVE-2014-9742 + +* X.509 path validation now returns a set of all errors that occurred + during validation, rather than immediately returning the first + detected error. This prevents a seemingly innocuous error (such as + an expired certificate) from hiding an obviously serious error + (such as an invalid signature). The Certificate_Status_Code enum is + now ordered by severity, and the most severe error is returned by + Path_Validation_Result::result(). The entire set of status codes is + available with the new all_statuses call. + +* Fixed a bug in OCSP response decoding which would cause an error + when attempting to decode responses from some widely used + responders. + +* An implementation of HMAC_DRBG RNG from NIST SP800-90A has been + added. Like the X9.31 PRNG implementation, it uses another + underlying RNG for seeding material. + +* An implementation of the RFC 6979 deterministic nonce generator has + been added. + +* Fix a bug in certificate path validation which prevented successful + validation if intermediate certificates were presented out of order. + +* Fix a bug introduced in 1.11.5 which could cause crashes or other + incorrect behavior when a cipher mode filter was followed in the + pipe by another filter, and that filter had a non-empty start_msg. + +* The types.h header now uses stdint.h rather than cstdint to avoid + problems with Clang on OS X. + +Version 1.11.8, 2014-02-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The ``botan`` command line application introduced in 1.11.7 is now + installed along with the library. + +* A bug in certificate path validation introduced in 1.11.6 which + caused all CRL signature checks to fail has been corrected. + +* The ChaCha20 stream cipher has been added. + +* The ``Transformation`` class no longer implements an interface for keying, + this has been moved to a new subclass ``Keyed_Transformation``. + +* The ``Algorithm`` class, which previously acted as a global base for + various types (ciphers, hashes, etc) has been removed. + +* CMAC now supports 256 and 512 bit block ciphers, which also allows + the use of larger block ciphers with EAX mode. In particular this + allows using Threefish in EAX mode. + +* The antique PBES1 private key encryption scheme (which only supports + DES or 64-bit RC2) has been removed. + +* The Square, Skipjack, and Luby-Rackoff block ciphers have been removed. + +* The Blue Midnight Wish hash function has been removed. + +* Skein-512 no longer supports output lengths greater than 512 bits. + +* Skein did not reset its internal state properly if clear() was + called, causing it to produce incorrect results for the following + message. It was reset correctly in final() so most usages should not + be affected. + +* A number of public key padding schemes have been renamed to match + the most common notation; for instance EME1 is now called OAEP and + EMSA4 is now called PSSR. Aliases are set which should allow all + current applications to continue to work unmodified. + +* A bug in CFB encryption caused a few bytes past the end of the final + block to be read. The actual output was not affected. + +* Fix compilation errors in the tests that occurred with minimized + builds. Contributed by Markus Wanner. + +* Add a new ``--destdir`` option to ``configure.py`` which controls + where the install target will place the output. The ``--prefix`` + option continues to set the location where the library expects to be + eventually installed. + +* Many class destructors which previously deleted memory have been + removed in favor of using ``unique_ptr``. + +* Various portability fixes for Clang, Windows, Visual C++ 2013, OS X, + and x86-32. + +Version 1.11.7, 2014-01-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Botan's basic numeric types are now defined in terms of the + C99/C++11 standard integer types. For instance ``u32bit`` is now a + typedef for ``uint32_t``, and both names are included in the library + namespace. This should not result in any application-visible + changes. + +* There are now two executable outputs of the build, ``botan-test``, + which runs the tests, and ``botan`` which is used as a driver to call + into various subcommands which can also act as examples of library + use, much in the manner of the ``openssl`` command. It understands the + commands ``base64``, ``asn1``, ``x509``, ``tls_client``, ``tls_server``, + ``bcrypt``, ``keygen``, ``speed``, and various others. As part of this + change many obsolete, duplicated, or one-off examples were removed, + while others were extended with new functionality. Contributions of + new subcommands, new bling for exising ones, or documentation in any + form is welcome. + +* Fix a bug in Lion, which was broken by a change in 1.11.0. The + problem was not noticed before as Lion was also missing a test vector + in previous releases. + +Version 1.10.7, 2013-12-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* OAEP had two bugs, one of which allowed it to be used even if the + key was too small, and the other of which would cause a crash during + decryption if the EME data was too large for the associated key. + +Version 1.11.6, 2013-12-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The Boost filesystem and asio libraries are now being used by default. + Pass ``--without-boost`` to ``configure.py`` to disable. + +* The default TLS policy no longer allows SSLv3 or RC4. + +* OAEP had two bugs, one of which allowed it to be used even if the + key was too small, and the other of which would cause a crash during + decryption if the EME data was too large for the associated key. + +* GCM mode now uses the Intel clmul instruction when available + +* Add the Threefish-512 tweakable block cipher, including an AVX2 version + +* Add SIV (from :rfc:`5297`) as a nonce-based AEAD + +* Add HKDF (from :rfc:`5869`) using an experimental PRF interface + +* Add HTTP utility functions and OCSP online checking + +* Add TLS::Policy::acceptable_ciphersuite hook to disable ciphersuites + on an ad-hoc basis. + +* TLS::Session_Manager_In_Memory's constructor now requires a RNG + +Version 1.10.6, 2013-11-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The device reading entropy source now attempts to read from all + available devices. Previously it would break out early if a partial + read from a blocking source occurred, not continuing to read from a + non-blocking device. This would cause the library to fall back on + slower and less reliable techniques for collecting PRNG seed + material. Reported by Rickard Bellgrim. + +* HMAC_RNG (the default PRNG implementation) now automatically reseeds + itself periodically. Previously reseeds only occurred on explicit + application request. + +* Fix an encoding error in EC_Group when encoding using EC_DOMPAR_ENC_OID. + Reported by fxdupont on github. + +* In EMSA2 and Randpool, avoid calling name() on objects after deleting them if + the provided algorithm objects are not suitable for use. Found by Clang + analyzer, reported by Jeffrey Walton. + +* If X509_Store was copied, the u32bit containing how long to cache validation + results was not initialized, potentially causing results to be cached for + significant amounts of time. This could allow a certificate to be considered + valid after its issuing CA's cert expired. Expiration of the end-entity cert + is always checked, and reading a CRL always causes the status to be reset, so + this issue does not affect revocation. Found by Coverity scanner. + +* Avoid off by one causing a potentially unterminated string to be passed to + the connect system call if the library was configured to use a very long path + name for the EGD socket. Found by Coverity Scanner. + +* In PK_Encryptor_EME, PK_Decryptor_EME, PK_Verifier, and PK_Key_Agreement, + avoid dereferencing an unitialized pointer if no engine supported operations + on the key object given. Found by Coverity scanner. + +* Avoid leaking a file descriptor in the /dev/random and EGD entropy sources if + stdin (file descriptor 0) was closed. Found by Coverity scanner. + +* Avoid a potentially undefined operation in the bit rotation operations. Not + known to have caused problems under any existing compiler, but might have + caused problems in the future. Caught by Clang sanitizer, reported by Jeffrey + Walton. + +* Increase default hash iterations from 10000 to 50000 in PBES1 and PBES2 + +* Add a fix for mips64el builds from Brad Smith. + +Version 1.11.5, 2013-11-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The TLS callback signatures have changed - there are now two distinct + callbacks for application data and alerts. TLS::Client and TLS::Server have + constructors which continue to accept the old callback and use it for both + operations. + +* The entropy collector that read from randomness devices had two bugs - it + would break out of the poll as soon as any read succeeded, and it selected on + each device individually. When a blocking source was first in the device list + and the entropy pool was running low, the reader might either block in select + until eventually timing out (continuing on to read from /dev/urandom instead), + or read just a few bytes, skip /dev/urandom, fail to satisfy the entropy + target, and the poll would continue using other (slower) sources. This caused + substantial performance/latency problems in RNG heavy applications. Now all + devices are selected over at once, with the effect that a full read from + urandom always occurs, along with however much (if any) output is available + from blocking sources. + +* Previously AutoSeeded_RNG referenced a globally shared PRNG instance. + Now each instance has distinct state. + +* The entropy collector that runs Unix programs to collect statistical + data now runs multiple processes in parallel, greatly reducing poll + times on some systems. + +* The Randpool RNG implementation was removed. + +* All existing cipher mode implementations (such as CBC and XTS) have been + converted from filters to using the interface previously provided by + AEAD modes which allows for in-place message + processing. Code which directly references the filter objects will break, but + an adaptor filter allows usage through get_cipher as usual. + +* An implementation of CCM mode from RFC 3601 has been added, as well as CCM + ciphersuites for TLS. + +* The implementation of OCB mode now supports 64 and 96 bit tags + +* Optimized computation of XTS tweaks, producing a substantial speedup + +* Add support for negotiating Brainpool ECC curves in TLS + +* TLS v1.2 will not negotiate plain SHA-1 signatures by default. + +* TLS channels now support sending a ``std::vector`` + +* Add a generic 64x64->128 bit multiply instruction operation in mul128.h + +* Avoid potentially undefined operations in the bit rotation operations. Not + known to have caused problems under existing compilers but might break in the + future. Found by Clang sanitizer, reported by Jeffrey Walton. + +Version 1.11.4, 2013-07-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CPU specific extensions are now always compiled if support for the + operations is available at build time, and flags enabling use of + extra operations (such as SSE2) are only included when compiling + files which specifically request support. This means, for instance, + that the SSSE3 and AES-NI implementations of AES are always included + in x86 builds, relying on runtime cpuid checking to prevent their + use on CPUs that do not support those operations. + +* The default TLS policy now only accepts TLS, to minimize surprise + for servers which might not expect to negotiate DTLS. Previously a + server would by default negotiate either protocol type (clients + would only accept the same protocol type as they + offered). Applications which use DTLS or combined TLS/DTLS need to + override ``Policy::acceptable_protocol_version``. + +* The TLS channels now accept a new parameter specifying how many + bytes to preallocate for the record handling buffers, which allows + an application some control over how much memory is used at runtime + for a particular connection. + +* Applications can now send arbitrary TLS alert messages using + ``TLS::Channel::send_alert`` + +* A new TLS policy ``NSA_Suite_B_128`` is available, which + will negotiate only the 128-bit security NSA Suite B. See + :rfc:`6460` for more information about Suite B. + +* Adds a new interface for benchmarking, ``time_algorithm_ops``, + which returns a map of operations to operations per second. For + instance now both encrypt and decrypt speed of a block cipher can be + checked, as well as the key schedule of all keyed algorithms. It + additionally supports AEAD modes. + +* Rename ARC4 to RC4 + +Version 1.11.3, 2013-04-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add a new interface for AEAD modes (``AEAD_Mode``). + +* Implementations of the OCB and GCM authenticated cipher modes are + now included. + +* Support for TLS GCM ciphersuites is now available. + +* A new TLS policy mechanism + ``TLS::Policy::server_uses_own_ciphersuite_preferences`` + controls how a server chooses a ciphersuite. Previously it always + chose its most preferred cipher out of the client's list, but this + can allow configuring a server to choose by the client's preferences + instead. + +* ``Keyed_Filter`` now supports returning a + ``Key_Length_Specification`` so the full details of what + keylengths are supported is now available in keyed filters. + +* The experimental and rarely used Turing and WiderWAKE stream ciphers + have been removed + +* New functions for symmetric encryption are included in cryptobox.h + though interfaces and formats are subject to change. + +* A new function ``algorithm_kat_detailed`` returns a string + providing information about failures, instead of just a pass/fail + indicator as in ``algorithm_kat``. + +Version 1.10.5, 2013-03-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* A potential crash in the AES-NI implementation of the AES-192 key + schedule (caused by misaligned loads) has been fixed. + +* A previously conditional operation in Montgomery multiplication and + squaring is now always performed, removing a possible timing + channel. + +* Use correct flags for creating a shared library on OS X under Clang. + +* Fix a compile time incompatibility with Visual C++ 2012. + +Version 1.11.2, 2013-03-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* A bug in the release script caused the ``botan_version.py`` included + in 1.11.1`` to be invalid, which required a manual edit to fix + (Bugzilla 226) + +* Previously ``clear_mem`` was implemented by an inlined call to + ``std::memset``. However an optimizing compiler might notice cases + where the memset could be skipped in cases allowed by the standard. + Now ``clear_mem`` calls ``zero_mem`` which is compiled separately and + which zeros out the array through a volatile pointer. It is possible + some compiler with some optimization setting (especially with + something like LTO) might still skip the writes. It would be nice if + there was an automated way to test this. + +* The new filter ``Threaded_Fork`` acts like a normal + ``Fork``, sending its input to a number of different + filters, but each subchain of filters in the fork runs in its own + thread. Contributed by Joel Low. + +* The default TLS policy formerly preferred AES over RC4, and allowed + 3DES by default. Now the default policy is to negotiate only either + AES or RC4, and to prefer RC4. + +* New TLS ``Blocking_Client`` provides a thread per + connection style API similar to that provided in 1.10 + +* The API of ``Credentials_Manager::trusted_certificate_authorities`` + has changed to return a vector of ``Certificate_Store*`` instead of + ``X509_Certificate``. This allows the list of trusted CAs to be + more easily updated dynamically or loaded lazily. + +* The ``asn1_int.h`` header was split into ``asn1_alt_name.h``, + ``asn1_attribute.h`` and ``asn1_time.h``. + +Version 1.10.4, 2013-01-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Avoid a conditional operation in the power mod implementations on if + a nibble of the exponent was zero or not. This may help protect + against certain forms of side channel attacks. + +* The SRP6 code was checking for invalid values as specified in RFC + 5054, specifically values equal to zero mod p. However SRP would + accept negative A/B values, or ones larger than p, neither of which + should occur in a normal run of the protocol. These values are now + rejected. Credits to Timothy Prepscius for pointing out these values + are not normally used and probably signal something fishy. + +* The return value of version_string is now a compile time constant + string, so version information can be more easily extracted from + binaries. + +Version 1.11.1, 2012-10-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Initial support for DTLS (both v1.0 and v1.2) is available in this +release, though it should be considered highly experimental. Currently +timeouts and retransmissions are not handled. + +The ``TLS::Client`` constructor now takes the version to +offer to the server. The policy hook ``TLS::Policy`` function +`pref_version``, which previously controlled this, has been removed. + +`TLS::Session_Manager_In_Memory`` now chooses a random +256-bit key at startup and encrypts all sessions (using the existing +`TLS::Session::encrypt`` mechanism) while they are stored in +memory. This is primarily to reduce pressure on locked memory, as each +session normally requires 48 bytes of locked memory for the master +secret, whereas now only 32 bytes are needed total. This change may +also make it slightly harder for an attacker to extract session data +from memory dumps (eg with a cold boot attack). + +The keys used in TLS session encryption were previously uniquely +determined by the master key. Now the encrypted session blob includes +two 80 bit salts which are used in the derivation of the cipher and +MAC keys. + +The ``secure_renegotiation`` flag is now considered an aspect of the +connection rather than the session, which matches the behavior of +other implementations. As the format has changed, sessions saved to +persistent storage by 1.11.0 will not load in this version and vice +versa. In either case this will not cause any errors, the session will +simply not resume and instead a full handshake will occur. + +New policy hooks ``TLS::Policy::acceptable_protocol_version``, +`TLS::Policy::allow_server_initiated_renegotiation``, and +`TLS::Policy::negotiate_heartbeat_support`` were added. + +TLS clients were not sending a next protocol message during a session +resumption, which would cause resumption failures with servers that +support NPN if NPN was being offered by the client. + +A bug caused heartbeat requests sent by the counterparty during a +handshake to be passed to the application callback as if they were +heartbeat responses. + +Support for TLS key material export as specified in :rfc:`5705` has +been added, available via ``TLS::Channel::key_material_export`` + +A new function ``Public_Key::estimated_strength`` returns +an estimate for the upper bound of the strength of the key. For +instance for an RSA key, it will return an estimate of how many +operations GNFS would take to factor the key. + +A new ``Path_Validation_Result`` code has been added +``SIGNATURE_METHOD_TOO_WEAK``. By default signatures created with keys +below 80 bits of strength (as estimated by ``estimated_strength``) are +rejected. This level can be modified using a parameter to the +``Path_Validation_Restrictions`` constructor. + +The SRP6 code was checking for invalid values as specified in +:rfc:`5054`, ones equal to zero mod p, however it would accept +negative A/B values, or ones larger than p, neither of which should +occur in a normal run of the protocol. These values are now +rejected. Credits to Timothy Prepscius for pointing out these values +are not normally used and probably signal something fishy. + +Several ``BigInt`` functions have been removed, including +``operator[]``, ``assign``, ``get_reg``, and ``grow_reg``. The version +of ``data`` that returns a mutable pointer has been renamed +``mutable_data``. Support for octal conversions has been removed. + +The constructor ``BigInt(NumberType type, size_t n)`` has been +removed, replaced by ``BigInt::power_of_2``. + +In 1.11.0, when compiled by GCC, the AES-NI implementation of AES-192 +would crash if the mlock-based allocator was used due to an alignment +issue. + +Version 1.11.0, 2012-07-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + In this release, many new features of C++11 are being used in the + library. Currently GCC 4.7 and Clang 3.1 are known to work well. + This version of the library cannot be compiled by or used with a + C++98 compiler. + +There have been many changes and improvements to TLS. The interface +is now purely event driven and does not directly interact with +sockets. New TLS features include TLS v1.2 support, client +certificate authentication, renegotiation, session tickets, and +session resumption. Session information can be saved in memory or to +an encrypted SQLite3 database. Newly supported TLS ciphersuite +algorithms include using SHA-2 for message authentication, pre shared +keys and SRP for authentication and key exchange, ECC algorithms for +key exchange and signatures, and anonymous DH/ECDH key exchange. + +Support for OCSP has been added. Currently only client-side support +exists. + +The API for X.509 path validation has changed, with +``x509_path_validate`` in x509path.h now handles path validation and +``Certificate_Store`` handles storage of certificates and CRLs. + +The memory container types have changed substantially. The +``MemoryVector`` and ``SecureVector`` container types have been +removed, and an alias of ``std::vector`` using an allocator that +clears memory named ``secure_vector`` is used for key material, with +plain ``std::vector`` being used for everything else. + +The technique used for mlock'ing memory on Linux and BSD systems is +much improved. Now a single page-aligned block of memory (the exact +limit of what we can mlock) is mmap'ed, with allocations being done +using a best-fit allocator and all metadata held outside the mmap'ed +range, in an effort to make best use of the very limited amount of +memory current Linux kernels allow unpriveledged users to lock. + +A filter using LZMA was contributed by Vojtech Kral. It is available +if LZMA support was enabled at compilation time by passing +``--with-lzma`` to ``configure.py``. + +:rfc:`5915` adds some extended information which can be included in +ECC private keys which the ECC key decoder did not expect, causing an +exception when such a key was loaded. In particular, recent versions +of OpenSSL use these fields. Now these fields are decoded properly, +and if the public key value is included it is used, as otherwise the +public key needs to be rederived from the private key. However the +library does not include these fields on encoding keys for +compatibility with software that does not expect them (including older +versions of botan). + +Version 1.8.14, 2012-07-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The malloc allocator would return null instead of throwing in the + event of an allocation failure, which could cause an application + crash due to null pointer dereference where normally an exception + would occur. + +* Recent versions of OpenSSL include extra information in ECC private + keys, the presence of which caused an exception when such a key was + loaded by botan. The decoding of ECC private keys has been changed to + ignore these fields if they are set. + +* AutoSeeded_RNG has been changed to prefer ``/dev/random`` over + ``/dev/urandom`` + +* Fix detection of s390x (Debian bug 638347) + +Version 1.10.3, 2012-07-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A change in 1.10.2 accidentally broke ABI compatibility with 1.10.1 +and earlier versions, causing programs compiled against 1.10.1 to +crash if linked with 1.10.2 at runtime. + +Recent versions of OpenSSL include extra information in ECC private +keys, the presence of which caused an exception when such a key was +loaded by botan. The decoding of ECC private keys has been changed to +ignore these fields if they are set. + +Version 1.10.2, 2012-06-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Several TLS bugs were fixed in this release, including a major +omission that the renegotiation extension was not being used. As the +1.10 implementation of TLS does not properly support renegotiation, +the approach in this release is simply to send the renegotiation +extension SCSV, which should protect the client against any handshake +splicing. In addition renegotiation attempts are handled properly +instead of causing handshake failures - all hello requests, and all +client hellos after the initial negotiation, are ignored. Some +bugs affecting DSA server authentication were also fixed. + +By popular request, ``Pipe::reset`` no longer requires that message +processing be completed, a requirement that caused problems when a +Filter's end_msg call threw an exception, after which point the Pipe +object was no longer usable. + +Support for getting entropy using the rdrand instruction introduced in +Intel's Ivy Bridge processors has been added. In previous releases, +the ``CPUID::has_rdrand`` function was checking the wrong cpuid bit, +and would false positive on AMD Bulldozer processors. + +An implementation of SRP-6a compatible with the specification in RFC +5054 is now available in ``srp6.h``. In 1.11, this is being used for +TLS-SRP, but may be useful in other environments as well. + +An implementation of the Camellia block cipher was added, again largely +for use in TLS. + +If ``clock_gettime`` is available on the system, hres_timer will poll all +the available clock types. + +AltiVec is now detected on IBM POWER7 processors and on OpenBSD systems. +The OpenBSD support was contributed by Brad Smith. + +The Qt mutex wrapper was broken and would not compile with any recent +version of Qt. Taking this as a clear indication that it is not in use, +it has been removed. + +Avoid setting the soname on OpenBSD, as it doesn't support it (Bugzilla 158) + +A compilation problem in the dynamic loader that prevented using +dyn_load under MinGW GCC has been fixed. + +A common error for people using MinGW is to target GCC on Windows, +however the 'Windows' target assumes the existence of Visual C++ +runtime functions which do not exist in MinGW. Now, configuring for +GCC on Windows will cause the configure.py to warn that likely you +wanted to configure for either MinGW or Cygwin, not the generic +Windows target. + +A bug in configure.py would cause it to interpret ``--cpu=s390x`` as +``s390``. This may have affected other CPUs as well. Now configure.py +searches for an exact match, and only if no exact match is found will +it search for substring matches. + +An incompatibility in configure.py with the subprocess module included +in Python 3.1 has been fixed (Bugzilla 157). + +The exception catching syntax of configure.py has been changed to the +Python 3.x syntax. This syntax also works with Python 2.6 and 2.7, but +not with any earlier Python 2 release. A simple search and replace +will allow running it under Python 2.5: +``perl -pi -e 's/except (.*) as (.*):/except $1, $2:/g' configure.py`` + +Note that Python 2.4 is not supported at all. + +Version 1.10.1, 2011-07-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* A race condition in ``Algorithm_Factory`` could cause crashes in + multithreaded code. + +* The return value of ``name`` has changed for GOST 28147-89 and + Skein-512. GOST's ``name`` now includes the name of the sbox, and + Skein's includes the personalization string (if nonempty). This + allows an object to be properly roundtripped, which is necessary to + fix the race condition described above. + +* A new distribution script is now included, as + ``src/build-data/scripts/dist.py`` + +* The ``build.h`` header now includes, if available, an identifier of + the source revision that was used. This identifier is also included + in the result of ``version_string``. + +Version 1.8.13, 2011-07-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* A race condition in ``Algorithm_Factory`` could cause crashes in + multithreaded code. + +Version 1.10.0, 2011-06-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Detection for the rdrand instruction being added to upcoming Intel + Ivy Bridge processors has been added. + +* A template specialization of std::swap was added for the memory + container types. + +Version 1.8.12, 2011-06-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* If EMSA3(Raw) was used for more than one signature, it would produce + incorrect output. + +* Fix the --enable-debug option to configure.py + +* Improve OS detection on Cygwin + +* Fix compilation under Sun Studio 12 on Solaris + +* Fix a memory leak in the constructors of DataSource_Stream and + DataSink_Stream which would occur if opening the file failed (Bugzilla 144) + +Version 1.9.18, 2011-06-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fourth release candidate for 1.10.0 + +* The GOST 34.10 verification operation was not ensuring that s and r + were both greater than zero. This could potentially have meant it + would have accepted an invalid all-zero signature as valid for any + message. Due to how ECC points are internally represented it instead + resulted in an exception being thrown. + +* A simple multiexponentation algorithm is now used in ECDSA and + GOST-34.10 signature verification, leading to 20 to 25% improvements + in ECDSA and 25% to 40% improvements in GOST-34.10 verification + performance. + +* The internal representation of elliptic curve points has been + modified to use Montgomery representation exclusively, resulting in + reduced memory usage and a 10 to 20% performance improvement for + ECDSA and ECDH. + +* In OAEP decoding, scan for the delimiter bytes using a loop that is + written without conditionals so as to help avoid timing analysis. + Unfortunately GCC at least is 'smart' enough to compile it to + jumps anyway. + +* The SSE2 implementation of IDEA did not work correctly when compiled + by Clang, because the trick it used to emulate a 16 bit unsigned + compare in SSE (which doesn't contain one natively) relied on signed + overflow working in the 'usual' way. A different method that doesn't + rely on signed overflow is now used. + +* Add support for compiling SSL using Visual C++ 2010's TR1 + implementation. + +* Fix a bug under Visual C++ 2010 which would cause ``hex_encode`` to + crash if given a zero-sized input to encode. + +* A new build option ``--via-amalgamation`` will first generate the + single-file amalgamation, then build the library from that single + file. This option requires a lot of memory and does not parallelize, + but the resulting library is smaller and may be faster. + +* On Unix, the library and header paths have been changed to allow + parallel installation of different versions of the library. Headers + are installed into ``/include/botan-1.9/botan``, libraries + are named ``libbotan-1.9``, and ``botan-config`` is now namespaced + (so in this release ``botan-config-1.9``). All of these embedded + versions will be 1.10 in the upcoming stable release. + +* The soname system has been modified. In this release the library + soname is ``libbotan-1.9.so.0``, with the full library being named + ``libbotan-1.9.so.0.18``. The ``0`` is the ABI version, and will be + incremented whenever a breaking ABI change is made. + +* TR1 support is not longer automatically assumed under older versions + of GCC + +* Functions for base64 decoding that work standalone (without needing + to use a pipe) have been added to ``base64.h`` + +* The function ``BigInt::to_u32bit`` was inadvertently removed in 1.9.11 + and has been added back. + +* The function ``BigInt::get_substring`` did not work correctly with a + *length* argument of 32. + +* The implementation of ``FD_ZERO`` on Solaris uses ``memset`` and + assumes the caller included ``string.h`` on its behalf. Do so to + fix compilation in the ``dev_random`` and ``unix_procs`` entropy + sources. Patch from Jeremy C. Reed. + +* Add two different configuration targets for Atom, since some are + 32-bit and some are 64-bit. The 'atom' target now refers to the + 64-bit implementations, use 'atom32' to target the 32-bit + processors. + +* The (incomplete) support for CMS and card verifiable certificates + are disabled by default; add ``--enable-modules=cms`` or + ``--enable-modules=cvc`` during configuration to turn them back on. + +Version 1.9.17, 2011-04-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Third release candidate for 1.10.0 + +* The format preserving encryption method currently available was + presented in the header ``fpe.h`` and the functions ``fpe_encrypt`` + and ``fpe_decrypt``. These were renamed as it is likely that other + FPE schemes will be included in the future. The header is now + ``fpe_fe1.h``, and the functions are named ``fe1_encrypt`` and + ``fe1_decrypt``. + +* New options to ``configure.py`` control what tools are used for + documentation generation. The ``--with-sphinx`` option enables using + Sphinx to convert ReST into HTML; otherwise the ReST sources are + installed directly. If ``--with-doxygen`` is used, Doxygen will run + as well. Documentation generation can be triggered via the ``docs`` + target in the makefile; it will also be installed by the install + target on Unix. + +* A bug in 1.9.16 effectively disabled support for runtime CPU feature + detection on x86 under GCC in that release. + +* A mostly internal change, all references to "ia32" and "amd64" have + been changed to the vendor neutral and probably easier to understand + "x86-32" and "x86-64". For instance, the "mp_amd64" module has been + renamed "mp_x86_64", and the macro indicating x86-32 has changed + from ``BOTAN_TARGET_ARCH_IS_IA32`` to + ``BOTAN_TARGET_ARCH_IS_X86_32``. The classes calling assembly have + also been renamed. + +* Similiarly to the above change, the AES implemenations using the + AES-NI instruction set have been renamed from AES_XXX_Intel to + AES_XXX_NI. + +* Systems that are identified as ``sun4u`` will default to compiling for + 32-bit SPARCv9 code rather than 64-bit. This matches the still + common convention for 32-bit SPARC userspaces. If you want 64-bit + code on such as system, use ``--cpu=sparc64``. + +* Some minor fixes for compiling botan under the BeOS + clone/continuation `Haiku `_. + +* Further updates to the documentation + +Version 1.9.16, 2011-04-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Second release candidate for 1.10.0 + +* The documentation, previously written in LaTeX, is now in + reStructuredText suitable for processing by `Sphinx + `_, which can generate nicely formatted + HTML and PDFs. The documentation has also been greatly updated and + expanded. + +* The class ``EC_Domain_Params`` has been renamed ``EC_Group``, with a + typedef for backwards compatibility. + +* The ``EC_Group`` string constructor didn't understand the standard + names like "secp160r1", forcing use of the OIDs. + +* Two constructors for ECDSA private keys, the one that creates a new + random key, and the one that provides a preset private key as a + ``BigInt``, have been merged. This matches the existing interface + for DSA and DH keys. If you previously used the version taking a + ``BigInt`` private key, you'll have to additionally pass in a + ``RandomNumberGenerator`` object starting in this release. + +* It is now possible to create ECDH keys with a preset ``BigInt`` + private key; previously no method for this was available. + +* The overload of ``generate_passhash9`` that takes an explicit + algorithm identifier has been merged with the one that does not. + The algorithm identifier code has been moved from the second + parameter to the fourth. + +* Change shared library versioning to match the normal Unix + conventions. Instead of ``libbotan-X.Y.Z.so``, the shared lib is + named ``libbotan-X.Y.so.Z``; this allows the runtime linker to do + its runtime linky magic. It can be safely presumed that any change + in the major or minor version indicates ABI incompatibility. + +* Remove the socket wrapper code; it was not actually used by anything + in the library, only in the examples, and you can use whatever kind + of (blocking) socket interface you like with the SSL/TLS code. It's + available as socket.h in the examples directory if you want to use + it. + +* Disable the by-default 'strong' checking of private keys that are + loaded from storage. You can always request key material sanity + checking using Private_Key::check_key. + +* Bring back removed functions ``min_keylength_of``, + ``max_keylength_of``, ``keylength_multiple_of`` in ``lookup.h`` to + avoid breaking applications written against 1.8 + +Version 1.9.15, 2011-03-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* First release candidate for 1.10.0 + +* Modify how message expansion is done in SHA-256 and SHA-512. + Instead of expanding the entire message at the start, compute them + in the minimum number of registers. Values are computed 15 rounds + before they are needed. On a Core i7-860, GCC 4.5.2, went from 143 + to 157 MiB/s in SHA-256, and 211 to 256 MiB/s in SHA-512. + +* Pipe will delete empty output queues as soon as they are no longer + needed, even if earlier messages still have data unread. However an + (empty) entry in a deque of pointers will remain until all prior + messages are completely emptied. + +* Avoid reading the SPARC ``%tick`` register on OpenBSD as unlike the + Linux and NetBSD kernels, it will not trap and emulate it for us, + causing a illegal instruction crash. + +* Improve detection and autoconfiguration for ARM processors. Thanks + go out to the the `Tahoe-LAFS Software Foundation + `_, who donated a Sheevaplug that I'll be + using to figure out how to make the cryptographic primitives + Tahoe-LAFS relies on faster, particularly targeting the ARMv5TE. + +Version 1.9.14, 2011-03-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for bcrypt, OpenBSD's password hashing scheme. + +* Add support for NIST's AES key wrapping algorithm, as described in + :rfc:`3394`. It is available by including ``rfc3394.h``. + +* Fix an infinite loop in zlib filters introduced in 1.9.11 (Bugzilla 142) + +Version 1.9.13, 2011-02-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +GOST 34.10 signatures were being formatted in a way that was not +compatible with other implemenations, and specifically how GOST is +used in DNSSEC. + +The Keccak hash function was updated to the tweaked variant proposed +for round 3 of the NIST hash competition. This version is not +compatible with the previous algorithm. + +A new option ``--distribution-info`` was added to the configure +script. It allows the user building the library to set any +distribution-specific notes on the build, which are available as a +macro ``BOTAN_DISTRIBUTION_INFO``. The default value is +'unspecified'. If you are building an unmodified version of botan +(especially for distribution), and want to indicate to applications +that this is the case, consider using +``--distribution-info=pristine``. If you are making any patches or +modifications, it is recommended to use +``--distribution-info=[Distribution Name] [Version]``, for instance +'FooNix 1.9.13-r3'. + +Some bugs preventing compilation under Clang 2.9 and Sun Studio 12 +were fixed. + +The DER/BER codecs use ``size_t`` instead of ``u32bit`` for small +integers + +Version 1.9.12, 2010-12-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add the Keccak hash function +* Fix compilation problems in Python wrappers +* Fix compilation problem in OpenSSL engine +* Update SQLite3 database encryption codec + +Version 1.9.11, 2010-11-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The TLS API has changed substantially and now relies heavily on + TR1's ``std::function`` is now required. Additionally, it is + required that all callers derive a subclass of TLS_Policy and pass + it to a client or server object. Please remember that the TLS + interface/API is currently unstable and will very likely change + further before TLS is included in a stable release. A handshake + failure that occurred when RC4 was negotiated has also been fixed. + +* Some possible timing channels in the implementations of Montgomery + reduction and the IDEA key schedule were removed. The table-based + AES implementation uses smaller tables in the first round to help + make some timing/cache attacks harder. + +* The library now uses size_t instead of u32bit to represent + lengths. Also the interfaces for the memory containers have changed + substantially to better match STL container interfaces; + MemoryRegion::append, MemoryRegion::destroy, and MemoryRegion::set + were all removed, and several other functions, like clear and + resize, have changed meaning. + +* Update Skein-512 to match the v1.3 specification +* Fix a number of CRL encoding and decoding bugs +* Counter mode now always encrypts 256 blocks in parallel +* Use small tables in the first round of AES +* Removed AES class: app must choose AES-128, AES-192, or AES-256 +* Add hex encoding/decoding functions that can be used without a Pipe +* Add base64 encoding functions that can be used without a Pipe +* Add to_string function to X509_Certificate +* Add support for dynamic engine loading on Windows +* Replace BlockCipher::BLOCK_SIZE attribute with function block_size() +* Replace HashFunction::HASH_BLOCK_SIZE attribute with hash_block_size() +* Move PBKDF lookup to engine system +* The IDEA key schedule has been changed to run in constant time +* Add Algorithm and Key_Length_Specification classes +* Switch default PKCS #8 encryption algorithm from AES-128 to AES-256 +* Allow using PBKDF2 with empty passphrases +* Add compile-time deprecation warnings for GCC, Clang, and MSVC +* Support use of HMAC(SHA-256) and CMAC(Blowfish) in passhash9 +* Improve support for Intel Atom processors +* Fix compilation problems under Sun Studio and Clang + +Version 1.8.11, 2010-11-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a number of CRL encoding and decoding bugs +* When building a debug library under VC++, use the debug runtime +* Fix compilation under Sun Studio on Linux and Solaris +* Add several functions for compatibility with 1.9 +* In the examples, read most input files as binary +* The Perl build script has been removed in this release + +Version 1.8.10, 2010-08-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Switch default PKCS #8 encryption algorithm from 3DES to AES-256 +* Increase default hash iterations from 2048 to 10000 in PBES1 and PBES2 +* Use small tables in the first round of AES +* Add PBKDF typedef and get_pbkdf for better compatibility with 1.9 +* Add version of S2K::derive_key taking salt and iteration count +* Enable the /proc-walking entropy source on NetBSD +* Fix the doxygen makefile target + +Version 1.9.10, 2010-08-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add a constant-time AES implementation using SSSE3. This code is + based on public domain assembly written by `Mike Hamburg + `_, and described in his CHES + 2009 paper "Accelerating AES with Vector Permute Instructions". In + addition to being constant time, it is also significantly faster + than the table-based implementation on some processors. The current + code has been tested with GCC 4.5, Visual C++ 2008, and Clang 2.8. + +* Support for dynamically loading Engine objects at runtime was also + added. Currently only system that use ``dlopen``-style dynamic + linking are supported. + +* On GCC 4.3 and later, use the byteswap intrinsic functions. + +* Drop support for building with Python 2.4 + +* Fix benchmarking of block ciphers in ECB mode + +* Consolidate the two x86 assembly engines + +* Rename S2K to PBKDF + +Version 1.9.9, 2010-06-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A new pure virtual function has been added to ``Filter``, ``name`` +which simply returns some useful identifier for the object. Any +out-of-tree ``Filter`` implementations will need to be updated. + +Add ``Keyed_Filter::valid_iv_length`` which makes it possible to query +as to what IV length(s) a particular filter allows. Previously, +partially because there was no such query mechanism, if a filter did +not support IVs at all, then calls to ``set_iv`` would be silently +ignored. Now an exception about the invalid IV length will be thrown. + +The default iteration count for the password based encryption schemes +has been increased from 2048 to 10000. This should make +password-guessing attacks against private keys encrypted with versions +after this release somewhat harder. + +New functions for encoding public and private keys to binary, +``X509::BER_encode`` and ``PKCS8::BER_encode`` have been added. + +Problems compiling under Apple's version of GCC 4.2.1 and on 64-bit +MIPS systems using GCC 4.4 or later were fixed. + +The coverage of Doxygen documentation comments has significantly +improved in this release. + +Version 1.8.9, 2010-06-16 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Use constant time multiplication in IDEA + +* Avoid possible timing attack against OAEP decoding + +* Add new X509::BER_encode and PKCS8::BER_encode + +* Enable DLL builds under Windows + +* Add Win32 installer support + +* Add support for the Clang compiler + +* Fix problem in semcem.h preventing build under Clang or GCC 3.4 + +* Fix bug that prevented creation of DSA groups under 1024 bits + +* Fix crash in GMP_Engine if library is shutdown and reinitialized and + a PK algorithm was used after the second init + +* Work around problem with recent binutils in x86-64 SHA-1 + +* The Perl build script is no longer supported and refuses to run by + default. If you really want to use it, pass + ``--i-know-this-is-broken`` to the script. + +Version 1.9.8, 2010-06-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for wide multiplications on 64-bit Windows +* Use constant time multiplication in IDEA +* Avoid possible timing attack against OAEP decoding +* Removed FORK-256; rarely used and it has been broken +* Rename ``--use-boost-python`` to ``--with-boost-python`` +* Skip building shared libraries on MinGW/Cygwin +* Fix creation of 512 and 768 bit DL groups using the DSA kosherizer +* Fix compilation on GCC versions before 4.3 (missing cpuid.h) +* Fix compilation under the Clang compiler + +Version 1.9.7, 2010-04-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* TLS: Support reading SSLv2 client hellos +* TLS: Add support for SEED ciphersuites (RFC 4162) +* Add Comb4P hash combiner function + +* Fix checking of EMSA_Raw signatures with leading 0 bytes, valid + signatures could be rejected in certain scenarios. + +Version 1.9.6, 2010-04-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* TLS: Add support for TLS v1.1 +* TLS: Support server name indicator extension +* TLS: Fix server handshake +* TLS: Fix server using DSA certificates +* TLS: Avoid timing channel between CBC padding check and MAC verification + +Version 1.9.5, 2010-03-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Numerous ECC optimizations +* Fix GOST 34.10-2001 X.509 key loading +* Allow PK_Signer's fault protection checks to be toggled off +* Avoid using pool-based locking allocator if we can't mlock +* Remove all runtime options +* New BER_Decoder::{decode_and_check, decode_octet_string_bigint} +* Remove SecureBuffer in favor of SecureVector length parameter +* HMAC_RNG: Perform a poll along with user-supplied entropy +* Fix crash in MemoryRegion if Allocator::get failed +* Fix small compilation problem on FreeBSD + +Version 1.9.4, 2010-03-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add the Ajisai SSLv3/TLSv1.0 implementation + +* Add GOST 34.10-2001 public key signature scheme +* Add SIMD implementation of Noekeon + +* Add SSE2 implementation of IDEA + +* Extend Salsa20 to support longer IVs (XSalsa20) + +* Perform XTS encryption and decryption in parallel where possible + +* Perform CBC decryption in parallel where possible + +* Add SQLite3 db encryption codec, contributed by Olivier de Gaalon + +* Add a block cipher cascade construction + +* Add support for password hashing for authentication (passhash9.h) + +* Add support for Win32 high resolution system timers + +* Major refactoring and API changes in the public key code + +* PK_Signer class now verifies all signatures before releasing them to + the caller; this should help prevent a wide variety of fault + attacks, though it does have the downside of hurting signature + performance, particularly for DSA/ECDSA. + +* Changed S2K interface: derive_key now takes salt, iteration count + +* Remove dependency on TR1 shared_ptr in ECC and CVC code + +* Renamed ECKAEG to its more usual name, ECDH + +* Fix crash in GMP_Engine if library is shutdown and reinitialized + +* Fix an invalid memory read in MD4 + +* Fix Visual C++ static builds + +* Remove Timer class entirely + +* Switch default PKCS #8 encryption algorithm from 3DES to AES-128 + +* New configuration option, ``--gen-amalgamation``, creates a pair of + files (``botan_all.cpp`` and ``botan_all.h``) which contain the + contents of the library as it would have normally been compiled + based on the set configuration. + +* Many headers are now explicitly internal-use-only and are not installed + +* Greatly improve the Win32 installer + +* Several fixes for Visual C++ debug builds + +Version 1.9.3, 2009-11-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add new AES implementation using Intel's AES instruction intrinsics +* Add an implementation of format preserving encryption +* Allow use of any hash function in X.509 certificate creation +* Optimizations for MARS, Skipjack, and AES +* Set macros for available SIMD instructions in build.h +* Add support for using InnoSetup to package Windows builds +* By default build a DLL on Windows + +Version 1.8.8, 2009-11-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Alter Skein-512 to match the tweaked 1.2 specification +* Fix use of inline asm for access to x86 bswap function +* Allow building the library without AES enabled +* Add 'powerpc64' alias to ppc64 arch for Gentoo ebuild + +Version 1.9.2, 2009-11-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add SIMD version of XTEA +* Support both SSE2 and AltiVec SIMD for Serpent and XTEA +* Optimizations for SHA-1 and SHA-2 +* Add AltiVec runtime detection +* Fix x86 CPU identification with Intel C++ and Visual C++ + +Version 1.9.1, 2009-10-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Better support for Python and Perl wrappers +* Add an implementation of Blue Midnight Wish (Round 2 tweak version) +* Modify Skein-512 to match the tweaked 1.2 specification +* Add threshold secret sharing (draft-mcgrew-tss-02) +* Add runtime cpu feature detection for x86/x86-64 +* Add code for general runtime self testing for hashes, MACs, and ciphers +* Optimize XTEA; twice as fast as before on Core2 and Opteron +* Convert CTR_BE and OFB from filters to stream ciphers +* New parsing code for SCAN algorithm names +* Enable SSE2 optimizations under Visual C++ +* Remove all use of C++ exception specifications +* Add support for GNU/Hurd and Clang/LLVM + +Version 1.8.7, 2009-09-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix processing multiple messages in XTS mode +* Add --no-autoload option to configure.py, for minimized builds + +Version 1.9.0, 2009-09-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for parallel invocation of block ciphers where possible +* Add SSE2 implementation of Serpent +* Add Rivest's package transform (an all or nothing transform) +* Minor speedups to the Turing key schedule +* Fix processing multiple messages in XTS mode +* Add --no-autoload option to configure.py, for minimized builds +* The previously used configure.pl script is no longer supported + +Version 1.8.6, 2009-08-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Cryptobox, a set of simple password-based encryption routines +* Only read world-readable files when walking /proc for entropy +* Fix building with TR1 disabled +* Fix x86 bswap support for Visual C++ +* Fixes for compilation under Sun C++ +* Add support for Dragonfly BSD (contributed by Patrick Georgi) +* Add support for the Open64 C++ compiler +* Build fixes for MIPS systems running Linux +* Minor changes to license, now equivalent to the FreeBSD/NetBSD license + +Version 1.8.5, 2009-07-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Change configure.py to work on stock Python 2.4 +* Avoid a crash in Skein_512::add_data processing a zero-length input +* Small build fixes for SPARC, ARM, and HP-PA processors +* The test suite now returns an error code from main() if any tests failed + +Version 1.8.4, 2009-07-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug in nonce generation in the Miller-Rabin test + +Version 1.8.3, 2009-07-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add a new Python configuration script +* Add the Skein-512 SHA-3 candidate hash function +* Add the XTS block cipher mode from IEEE P1619 +* Fix random_prime when generating a prime of less than 7 bits +* Improve handling of low-entropy situations during PRNG seeding +* Change random device polling to prefer /dev/urandom over /dev/random +* Use an input insensitive implementation of same_mem instead of memcmp +* Correct DataSource::discard_next to return the number of discarded bytes +* Provide a default value for AutoSeeded_RNG::reseed +* Fix Gentoo bug 272242 + +Version 1.8.2, 2009-04-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Make entropy polling more flexible and in most cases faster +* GOST 28147 now supports multiple sbox parameters +* Added the GOST 34.11 hash function +* Fix botan-config problems on MacOS X + +Version 1.8.1, 2009-01-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Avoid a valgrind warning in es_unix.cpp on 32-bit Linux +* Fix memory leak in PKCS8 load_key and encrypt_key +* Relicense api.tex from CC-By-SA 2.5 to BSD +* Fix botan-config on MacOS X, Solaris + +Version 1.8.0, 2008-12-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix compilation on Solaris with GCC + +Version 1.7.24, 2008-12-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a compatibility problem with SHA-512/EMSA3 signature padding +* Fix bug preventing EGD/PRNGD entropy poller from working +* Fix integer overflow in Pooling_Allocator::get_more_core (bug id #27) +* Add EMSA3_Raw, a variant of EMSA3 called CKM_RSA_PKCS in PKCS #11 +* Add support for SHA-224 in EMSA2 and EMSA3 PK signature padding schemes +* Add many more test vectors for RSA with EMSA2, EMSA3, and EMSA4 +* Wrap private structs in SSE2 SHA-1 code in anonymous namespace +* Change configure.pl's CPU autodetection output to be more consistent +* Disable using OpenSSL's AES due to crashes of unknown cause +* Fix warning in /proc walking entropy poller +* Fix compilation with IBM XLC for Cell 0.9-200709 + +Version 1.7.23, 2008-11-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Change to use TR1 (thus enabling ECDSA) with GCC and ICC +* Optimize almost all hash functions, especially MD4 and Tiger +* Add configure.pl options --{with,without}-{bzip2,zlib,openssl,gnump} +* Change Timer to be pure virtual, and add ANSI_Clock_Timer +* Cache socket descriptors in the EGD entropy source +* Avoid bogging down startup in /proc walking entropy source +* Remove Buffered_EntropySource helper class +* Add a Default_Benchmark_Timer typedef in benchmark.h +* Add examples using benchmark.h and Algorithm_Factory +* Add ECC tests from InSiTo +* Minor documentation updates + +Version 1.7.22, 2008-11-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add provider preferences to Algorithm_Factory +* Fix memory leaks in PBE_PKCS5v20 and get_pbe introduced in 1.7.21 +* Optimize AES encryption and decryption (about 10% faster) +* Enable SSE2 optimized SHA-1 implementation on Intel Prescott CPUs +* Fix nanoseconds overflow in benchmark code +* Remove Engine::add_engine + +Version 1.7.21, 2008-11-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Make algorithm lookup much more configuable +* Add facilities for runtime performance testing of algorithms +* Drop use of entropy estimation in the PRNGs +* Increase intervals between HMAC_RNG automatic reseeding +* Drop InitializerOptions class, all options but thread safety + +Version 1.7.20, 2008-11-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Namespace pkg-config file by major and minor versions +* Cache device descriptors in Device_EntropySource +* Split base.h into {block_cipher,stream_cipher,mac,hash}.h +* Removed get_mgf function from lookup.h + +Version 1.7.19, 2008-11-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add HMAC_RNG, based on a design by Hugo Krawczyk +* Optimized the Turing stream cipher (about 20% faster on x86-64) +* Modify Randpool's reseeding algorithm to poll more sources +* Add a new AutoSeeded_RNG in auto_rng.h +* OpenPGP_S2K changed to take hash object instead of name +* Add automatic identification for Intel's Prescott processors + +Version 1.7.18, 2008-10-22 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Doxygen comments from InSiTo +* Add ECDSA and ECKAEG benchmarks +* Add configure.pl switch --with-tr1-implementation +* Fix configure.pl's --with-endian and --with-unaligned-mem options +* Added support for pkg-config +* Optimize byteswap with x86 inline asm for Visual C++ by Yves Jerschow +* Use const references to avoid copying overhead in CurveGFp, GFpModulus + +Version 1.7.17, 2008-10-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add missing ECDSA object identifiers +* Fix error in x86 and x86-64 assembler affecting GF(p) math +* Remove Boost dependency from GF(p) math +* Modify botan-config to not print -L/usr/lib or -L/usr/local/lib +* Add BOTAN_DLL macro to over 30 classes missing it +* Rename the two SHA-2 base classes for consistency + +Version 1.7.16, 2008-10-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add several missing pieces needed for ECDSA and ECKAEG +* Add Card Verifiable Certificates from InSiTo +* Add SHA-224 from InSiTo +* Add BSI variant of EMSA1 from InSiTo +* Add GF(p) and ECDSA tests from InSiTo +* Split ECDSA and ECKAEG into distinct modules +* Allow OpenSSL and GNU MP engines to be built with public key algos disabled +* Rename sha256.h to sha2_32.h and sha_64.h to sha2_64.h + +Version 1.7.15, 2008-10-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add GF(p) arithmetic from InSiTo +* Add ECDSA and ECKAEG implementations from InSiTo +* Minimize internal dependencies, allowing for smaller build configurations +* Add new User Manual and Architecture Guide from FlexSecure GmbH +* Alter configure.pl options for better autotools compatibility +* Update build instructions for recent changes to configure.pl +* Fix CPU detection using /proc/cpuinfo + +Version 1.7.14, 2008-09-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Split library into parts allowing modular builds +* Add (very preliminary) CMS support to the main library +* Some constructors now require object pointers instead of names +* Support multiple implementations of the same algorithm +* Build support for Pentium-M processors, from Derek Scherger +* Build support for MinGW/MSYS, from Zbigniew Zagorski +* Use inline assembly for bswap on 32-bit x86 + +Version 1.7.13, 2008-09-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add SSLv3 MAC, SSLv3 PRF, and TLS v1.0 PRF from Ajisai +* Allow all examples to compile even if compression not enabled +* Make CMAC's polynomial doubling operation a public class method +* Use the -m64 flag when compiling with Sun Forte on x86-64 +* Clean up and slightly optimize CMAC::final_result + +Version 1.7.12, 2008-09-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add x86 assembly for Visual Studio C++, by Luca Piccarreta +* Add a Perl XS module, by Vaclav Ovsik +* Add SWIG-based wrapper for Botan +* Add SSE2 implementation of SHA-1, by Dean Gaudet +* Remove the BigInt::sig_words cache due to bugs +* Combined the 4 Blowfish sboxes, suggested by Yves Jerschow +* Changed BigInt::grow_by and BigInt::grow_to to be non-const +* Add private assignment operators to classes that don't support assignment +* Benchmark RSA encryption and signatures +* Added test programs for random_prime and ressol +* Add high resolution timers for IA-64, HP-PA, S390x +* Reduce use of the RNG during benchmarks +* Fix builds on STI Cell PPU +* Add support for IBM's XLC compiler +* Add IETF 8192 bit MODP group + +Version 1.7.11, 2008-09-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the Salsa20 stream cipher +* Optimized Montgomery reduction, Karatsuba squaring +* Added 16x16->32 word Comba multiplication and squaring +* Use a much larger Karatsuba cutoff point +* Remove bigint_mul_add_words +* Inlined several BigInt functions +* Add useful information to the generated build.h +* Rename alg_{ia32,amd64} modules to asm_{ia32,amd64} +* Fix the Windows build + +Version 1.7.10, 2008-09-05 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Public key benchmarks run using a selection of random keys +* New benchmark timer options are clock_gettime, gettimeofday, times, clock +* Including reinterpret_cast optimization for xor_buf in default header +* Split byte swapping and word rotation functions into distinct headers +* Add IETF modp 6144 group and 2048 and 3072 bit DSS groups +* Optimizes BigInt right shift +* Add aliases in DL_Group::Format enum +* BigInt now caches the significant word count + +Version 1.6.5, 2008-08-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add noexec stack marker for GNU linker in assembly code +* Fix autoconfiguration problem on x86 with GCC 4.2 and 4.3 + +Version 1.7.9, 2008-08-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Make clear() in most algorithm base classes a pure virtual +* Add noexec stack marker for GNU linker in assembly code +* Avoid string operations in ressol +* Compilation fixes for MinGW and Visual Studio C++ 2008 +* Some autoconfiguration fixes for Windows + +Version 1.7.8, 2008-07-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the block cipher Noekeon +* Remove global deref_alias function +* X509_Store takes timeout options as constructor arguments +* Add Shanks-Tonelli algorithm, contributed by FlexSecure GmbH +* Extend random_prime() for generating primes of any bit length +* Remove Config class +* Allow adding new entropy via base RNG interface +* Reseeding a X9.31 PRNG also reseeds the underlying PRNG + +Version 1.7.7, 2008-06-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Remove the global PRNG object +* The PK filter objects were removed +* Add a test suite for the ANSI X9.31 PRNG +* Much cleaner and (mostly) thread-safe reimplementation of es_ftw +* Remove both default arguments to ANSI_X931_RNG's constructor +* Remove the randomizing version of OctetString::change +* Make the cipher and MAC to use in Randpool configurable +* Move RandomNumberGenerator declaration to rng.h +* RSA_PrivateKey will not generate keys smaller than 1024 bits +* Fix an error decoding BER UNIVERSAL types with special taggings + +Version 1.7.6, 2008-05-05 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initial support for Windows DLLs, from Joel Low +* Reset the position pointer when a new block is generated in X9.32 PRNG +* Timer objects are now treated as entropy sources +* Moved several ASN.1-related enums from enums.h to an appropriate header +* Removed the AEP module, due to inability to test +* Removed Global_RNG and rng.h +* Removed system_clock +* Removed Library_State::UI and the pulse callback logic + +Version 1.7.5, 2008-04-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The API of X509_CA::sign_request was altered to avoid race conditions +* New type Pipe::message_id to represent the Pipe message number +* Remove the Named_Mutex_Holder for a small performance gain +* Removed several unused or rarely used functions from Config +* Ignore spaces inside of a decimal string in BigInt::decode +* Allow using a std::istream to initialize a DataSource_Stream object +* Fix compilation problem in zlib compression module +* The chunk sized used by Pooling_Allocator is now a compile time setting +* The size of random blinding factors is now a compile time setting +* The install target no longer tries to set a particular owner/group + +Version 1.7.4, 2008-03-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Use unaligned memory read/writes on systems that allow it, for performance +* Assembly for x86-64 for accessing the bswap instruction +* Use larger buffers in ARC4 and WiderWAKE for significant throughput increase +* Unroll loops in SHA-160 for a few percent increase in performance +* Fix compilation with GCC 3.2 in es_ftw and es_unix +* Build fix for NetBSD systems +* Prevent es_dev from being built except on Unix systems + +Version 1.6.4, 2008-03-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a compilation problem with Visual Studio C++ 2003 + +Version 1.7.3, 2008-01-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* New invocation syntax for configure.pl with several new options +* Support for IPv4 addresses in a subject alternative name +* New fast poll for the generic Unix entropy source (es_unix) +* The es_file entropy source has been replaced by the es_dev module +* The malloc allocator does not inherit from Pooling_Allocator anymore +* The path that es_unix will search in are now fully user-configurable +* Truncate X9.42 PRF output rather than allow counter overflow +* PowerPC is now assumed to be big-endian + +Version 1.7.2, 2007-10-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initialize the global library state lazily +* Add plain CBC-MAC for backwards compatibility with old systems +* Clean up some of the self test code +* Throw a sensible exception if a DL_Group is not found +* Truncate KDF2 output rather than allowing counter overflow +* Add newly assigned OIDs for SHA-2 and DSA with SHA-224/256 +* Fix a Visual Studio compilation problem in x509stat.cpp + +Version 1.6.3, 2007-07-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a race condition in the algorithm lookup cache +* Fix problems building the memory pool on some versions of Visual C++ + +Version 1.7.1, 2007-07-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a race condition in the algorithm object cache +* HMAC key schedule optimization +* The build header sets a macro defining endianness, if known +* New word load/store abstraction allowing further optimization +* Modify most of the library to avoid use the C-style casts +* Use higher resolution timers in symmetric benchmarks + +Version 1.7.0, 2007-05-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* DSA parameter generation now follows FIPS 186-3 +* Added OIDs for Rabin-Williams and Nyberg-Rueppel +* Somewhat better support for out of tree builds +* Minor optimizations for RC2 and Tiger +* Documentation updates +* Update the todo list + +Version 1.6.2, 2007-03-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix autodection on Athlon64s running Linux +* Fix builds on QNX and compilers using STLport +* Remove a call to abort() that crept into production + +Version 1.6.1, 2007-01-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix some base64 decoder bugs +* Add a new option to base64 encoding, to always append a newline +* Fix some build problems under Visual Studio with debug enabled +* Fix a bug in BER_Decoder that was triggered under some compilers + +Version 1.6.0, 2006-12-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Minor cleanups versus 1.5.13 + +Version 1.5.13, 2006-12-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Compilation fixes for the bzip2, zlib, and GNU MP modules +* Better support for Intel C++ and EKOpath C++ on x86-64 + +Version 1.5.12, 2006-10-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Cleanups in the initialization routines +* Add some x86-64 assembly for multiply-add +* Fix problems generating very small (below 384 bit) RSA keys +* Support out of tree builds +* Bring some of the documentation up to date +* More improvements to the Python bindings + +Version 1.5.11, 2006-09-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Removed the Algorithm base class +* Various cleanups in the public key inheritance hierarchy +* Major overhaul of the configure/build setup +* Added x86 assembler implementations of Serpent and low-level MPI code +* Optimizations for the SHA-1 x86 assembler +* Various improvements to the Python wrappers +* Work around a Visual Studio compiler bug + +Version 1.5.10, 2006-08-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add x86 assembler versions of MD4, MD5, and SHA-1 +* Expand InitializerOptions' language to support on/off switches +* Fix definition of OID 2.5.4.8; was accidentally changed in 1.5.9 +* Fix possible resource leaks in the mmap allocator +* Slightly optimized buffering in MDx_HashFunction +* Initialization failures are dealt with somewhat better +* Add an example implementing Pollard's Rho algorithm +* Better option handling in the test/benchmark tool +* Expand the xor_ciph example to support longer keys +* Some updates to the documentation + +Version 1.5.9, 2006-07-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed bitrot in the AEP engine +* Fix support for marking certificate/CRL extensions as critical +* Significant cleanups in the library state / initialization code +* LibraryInitializer takes an explicit InitializerOptions object +* Make Mutex_Factory an abstract class, add Default_Mutex_Factory +* Change configuration access to using global_state() +* Add support for global named mutexes throughout the library +* Add some STL wrappers for the delete operator +* Change how certificates are created to be more flexible and general + +Version 1.5.8, 2006-06-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Many internal cleanups to the X.509 cert/CRL code +* Allow for application code to support new X.509 extensions +* Change the return type of X509_Certificate::{subject,issuer}_info +* Allow for alternate character set handling mechanisms +* Fix a bug that was slowing squaring performance somewhat +* Fix a very hard to hit overflow bug in the C version of word3_muladd +* Minor cleanups to the assembler modules +* Disable es_unix module on FreeBSD due to build problem on FreeBSD 6.1 +* Support for GCC 2.95.x has been dropped in this release + +Version 1.5.7, 2006-05-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Further, major changes to the BER/DER coding system +* Updated the Qt mutex module to use Mutex_Factory +* Moved the library global state object into an anonymous namespace +* Drop the Visual C++ x86 assembly module due to bugs + +Version 1.5.6, 2006-03-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The low-level DER/BER coding system was redesigned and rewritten +* Portions of the certificate code were cleaned up internally +* Use macros to substantially clean up the GCC assembly code +* Added 32-bit x86 assembly for Visual C++ (by Luca Piccarreta) +* Avoid a couple of spurious warnings under Visual C++ +* Some slight cleanups in X509_PublicKey::key_id + +Version 1.5.5, 2006-02-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a potential infinite loop in the memory pool code (Matt Johnston) +* Made Pooling_Allocator::Memory_Block an actual class of sorts +* Some small optimizations to the division and modulo computations +* Cleaned up the implementation of some of the BigInt operators +* Reduced use of dynamic memory allocation in low-level BigInt functions +* A few simplifications in the Randpool mixing function +* Removed power(), as it was not particularly useful (or fast) +* Fixed some annoying bugs in the benchmark code +* Added a real credits file + +Version 1.5.4, 2006-01-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Integrated x86 and amd64 assembly code, contributed by Luca Piccarreta +* Fixed a memory access off-by-one in the Karatsuba code +* Changed Pooling_Allocator's free list search to a log(N) algorithm +* Merged ModularReducer with its only subclass, Barrett_Reducer +* Fixed sign-handling bugs in some of the division and modulo code +* Renamed the module description files to modinfo.txt +* Further cleanups in the initialization code +* Removed BigInt::add and BigInt::sub +* Merged all the division-related functions into just divide() +* Modified the functions to allow for better optimizations +* Made the number of bits polled from an EntropySource user configurable +* Avoid including in +* Fixed some build problems with Sun Forte +* Removed some dead code from bigint_modop +* Fix the definition of same_mem + +Version 1.5.3, 2006-01-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Many optimizations in the low-level multiple precision integer code +* Added hooks for assembly implementations of the MPI code +* Support for the X.509 issuer alternative name extension in new certs +* Fixed a bug in the decompression modules; found and patched by Matt Johnston +* New Windows mutex module (mux_win32), by Luca Piccarreta +* Changed the Windows timer module to use QueryPerformanceCounter +* mem_pool.cpp was using std::set iterators instead of std::multiset ones +* Fixed a bug in X509_CA preventing users from disabling particular extensions +* Fixed the mp_asm64 module, which was entirely broken in 1.5.2 +* Fixed some module build problems on FreeBSD and Tru64 + +Version 1.4.12, 2006-01-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an off-by-one memory read in MISTY1::key() +* Fixed a nasty memory leak in Output_Buffers::retire() +* Changed maximum HMAC keylength to 1024 bits +* Fixed a build problem in the hardware timer module on 64-bit PowerPC + +Version 1.5.2, 2006-01-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an off-by-one memory read in MISTY1::key() +* Fixed a nasty memory leak in Output_Buffers::retire() +* Reimplemented the memory allocator from scratch +* Improved memory caching in Montgomery exponentiation +* Optimizations for multiple precision addition and subtraction +* Fixed a build problem in the hardware timer module on 64-bit PowerPC +* Changed default Karatsuba cutoff to 12 words (was 14) +* Removed MemoryRegion::bits(), which was unused and incorrect +* Changed maximum HMAC keylength to 1024 bits +* Various minor Makefile and build system changes +* Avoid using std::min in to bypass Windows libc macro pollution +* Switched checks/clock.cpp back to using clock() by default +* Enabled the symmetric algorithm tests, which were accidentally off in 1.5.1 +* Removed the Default_Mutex's unused clone() member function + +Version 1.5.1, 2006-01-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Implemented Montgomery exponentiation +* Implemented generalized Karatsuba multiplication and squaring +* Implemented Comba squaring for 4, 6, and 8 word inputs +* Added new Modular_Exponentiator and Power_Mod classes +* Removed FixedBase_Exp and FixedExponent_Exp +* Fixed a performance regression in get_allocator introduced in 1.5.0 +* Engines can now offer S2K algorithms and block cipher padding methods +* Merged the remaining global 'algolist' code into Default_Engine +* The low-level MPI code is linked as C again +* Replaced BigInt's get_nibble with the more general get_substring +* Some documentation updates + +Version 1.5.0, 2006-01-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Moved all global/shared library state into a single object +* Mutex objects are created through mutex factories instead of a global +* Removed ::get_mutex(), ::initialize_mutex(), and Mutex::clone() +* Removed the RNG_Quality enum entirely +* There is now only a single global-use PRNG +* Removed the no_aliases and no_oids options for LibraryInitializer +* Removed the deprecated algorithms SEAL, ISAAC, and HAVAL +* Change es_ftw to use unbuffered I/O + +Version 1.4.11, 2005-12-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Changed Whirlpool diffusion matrix to match updated algorithm spec +* Fixed several engine module build errors introduced in 1.4.10 +* Fixed two build problems in es_capi; reported by Matthew Gregan +* Added a constructor to DataSource_Memory taking a std::string +* Placing the same Filter in multiple Pipes triggers an exception +* The configure script accepts --docdir and --libdir +* Merged doc/rngs.txt into the main API document +* Thanks to Joel Low for several bug reports on early tarballs of 1.4.11 + +Version 1.4.10, 2005-12-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added an implementation of KASUMI, the block cipher used in 3G phones +* Refactored Pipe; output queues are now managed by a distinct class +* Made certain Filter facilities only available to subclasses of Fanout_Filter +* There is no longer any overhead in Pipe for a message that has been read out +* It is now possible to generate RSA keys as small as 128 bits +* Changed some of the core classes to derive from Algorithm as a virtual base +* Changed Randpool to use HMAC instead of a plain hash as the mixing function +* Fixed a bug in the allocators; found and fixed by Matthew Gregan +* Enabled the use of binary file I/O, when requested by the application +* The OpenSSL engine's block cipher code was missing some deallocation calls +* Disabled the es_ftw module on NetBSD, due to header problems there +* Fixed a problem preventing tm_hard from building on MacOS X on PowerPC +* Some cleanups for the modules that use inline assembler +* config.h is now stored in build/ instead of build/include/botan/ +* The header util.h was split into bit_ops.h, parsing.h, and util.h +* Cleaned up some redundant include directives + +Version 1.4.9, 2005-11-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the IBM-created AES candidate algorithm MARS +* Added the South Korean block cipher SEED +* Added the stream cipher Turing +* Added the new hash function FORK-256 +* Deprecated the ISAAC stream cipher +* Twofish and RC6 are significantly faster with GCC +* Much better support for 64-bit PowerPC +* Added support for high-resolution PowerPC timers +* Fixed a bug in the configure script causing problems on FreeBSD +* Changed ANSI X9.31 to support arbitrary block ciphers +* Make the configure script a bit less noisy +* Added more test vectors for some algorithms, including all the AES finalists +* Various cosmetic source code cleanups + +Version 1.4.8, 2005-10-16 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Resolved a bad performance problem in the allocators; fix by Matt Johnston +* Worked around a Visual Studio 2003 compilation problem introduced in 1.4.7 +* Renamed OMAC to CMAC to match the official NIST naming +* Added single byte versions of update() to PK_Signer and PK_Verifier +* Removed the unused reverse_bits and reverse_bytes functions + +Version 1.4.7, 2005-09-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed major performance problems with recent versions of GNU C++ +* Added an implementation of the X9.31 PRNG +* Removed the X9.17 and FIPS 186-2 PRNG algorithms +* Changed defaults to use X9.31 PRNGs as global PRNG objects +* Documentation updates to reflect the PRNG changes +* Some cleanups related to the engine code +* Removed two useless headers, base_eng.h and secalloc.h +* Removed PK_Verifier::valid_signature +* Fixed configure/build system bugs affecting MacOS X builds +* Added support for the EKOPath x86-64 compiler +* Added missing destructor for BlockCipherModePaddingMethod +* Fix some build problems with Visual C++ 2005 beta +* Fix some build problems with Visual C++ 2003 Workshop + +Version 1.4.6, 2005-03-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix an error in the shutdown code introduced in 1.4.5 +* Setting base/pkcs8_tries to 0 disables the builtin fail-out +* Support for XMPP identifiers in X.509 certificates +* Duplicate entries in X.509 DNs are removed +* More fixes for Borland C++, from Friedemann Kleint +* Add a workaround for buggy iostreams + +Version 1.4.5, 2005-02-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for AES encryption of private keys +* Minor fixes for PBES2 parameter decoding +* Internal cleanups for global state variables +* GCC 3.x version detection was broken in non-English locales +* Work around a Sun Forte bug affecting mem_pool.h +* Several fixes for Borland C++ 5.5, from Friedemann Kleint +* Removed inclusion of init.h into base.h +* Fixed a major bug in reading from certificate stores +* Cleaned up a couple of mutex leaks +* Removed some left-over debugging code +* Removed SSL3_MAC, SSL3_PRF, and TLS_PRF + +Version 1.4.4, 2004-12-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Further tweaks to the pooling allocator +* Modified EMSA3 to support SSL/TLS signatures +* Changes to support Qt/QCA, from Justin Karneges +* Moved mux_qt module code into mod_qt +* Fixes for HP-UX from Mike Desjardins + +Version 1.4.3, 2004-11-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Split up SecureAllocator into Allocator and Pooling_Allocator +* Memory locking allocators are more likely to be used +* Fixed the placement of includes in some modules +* Fixed broken installation procedure +* Fixes in configure script to support alternate install programs +* Modules can specify the minimum version they support + +Version 1.4.2, 2004-10-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a major CRL handling bug +* Cipher and hash operations can be offloaded to engines +* Added support for cipher and hash offload in OpenSSL engine +* Improvements for 64-bit CPUs without a widening multiply instruction +* Support for SHA2-* and Whirlpool with EMSA2 +* Fixed a long-standing build problem with conflicting include files +* Fixed some examples that hadn't been updated for 1.4.x +* Portability fixes for Solaris, BSD, HP-UX, and others +* Lots of fixes and cleanups in the configure script +* Updated the Gentoo ebuild file + +Version 1.4.1, 2004-10-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed major errors in the X.509 and PKCS #8 copy_key functions +* Added a LAST_MESSAGE meta-message number for Pipe +* Added new aliases (3DES and DES-EDE) for Triple-DES +* Added some new functions to PK_Verifier +* Cleaned up the KDF interface +* Disabled tm_posix on BSD due to header issues +* Fixed a build problem on PowerPC with GNU C++ pre-3.4 + +Version 1.4.0, 2004-06-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the FIPS 186 RNG back +* Added copy_key functions for X.509 public keys and PKCS #8 private keys +* Fixed PKCS #1 signatures with RIPEMD-128 +* Moved some code around to avoid warnings with Sun ONE compiler +* Fixed a bug in botan-config affecting OpenBSD +* Fixed some build problems on Tru64, HP-UX +* Fixed compile problems with Intel C++, Compaq C++ + +Version 1.3.14, 2004-06-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for AEP's AEP1000/AEP2000 crypto cards +* Added a Mutex module using Qt, from Justin Karneges +* Added support for engine loading in LibraryInitializer +* Tweaked SecureAllocator, giving 20% better performance under heavy load +* Added timer and memory locking modules for Win32 (tm_win32, ml_win32) +* Renamed PK_Engine to Engine_Core +* Improved the Karatsuba cutoff points +* Fixes for compiling with GCC 3.4 and Sun C++ 5.5 +* Fixes for Linux/s390, OpenBSD, and Solaris +* Added support for Linux/s390x +* The configure script was totally broken for 'generic' OS +* Removed Montgomery reduction due to bugs +* Removed an unused header, pkcs8alg.h +* check --validate returns an error code if any tests failed +* Removed duplicate entry in Unix command list for es_unix +* Moved the Cert_Usage enumeration into X509_Store +* Added new timing methods for PK benchmarks, clock_gettime and RDTSC +* Fixed a few minor bugs in the configure script +* Removed some deprecated functions from x509cert.h and pkcs10.h +* Removed the 'minimal' module, has to be updated for Engine support +* Changed MP_WORD_BITS macro to BOTAN_MP_WORD_BITS to clean up namespace +* Documentation updates + +Version 1.3.13, 2004-05-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major fixes for Cygwin builds +* Minor MacOS X install fixes +* The configure script is a little better at picking the right modules +* Removed ml_unix from the 'unix' module set for Cygwin compatibility +* Fixed a stupid compile problem in pkcs10.h + +Version 1.3.12, 2004-05-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added ability to remove old entries from CRLs +* Swapped the first two arguments of X509_CA::update_crl() +* Added an < operator for MemoryRegion, so it can be used as a std::map key +* Changed X.509 searching by DNS name from substring to full string compares +* Renamed a few X509_Certificate and PKCS10_Request member functions +* Fixed a problem when decoding some PKCS #10 requests +* Hex_Decoder would not check inputs, reported by Vaclav Ovsik +* Changed default CRL expire time from 30 days to 7 days +* X509_CRL's default PEM header is now "X509 CRL", for OpenSSL compatibility +* Corrected errors in the API doc, fixes from Ken Perano +* More documentation about the Pipe/Filter code + +Version 1.3.11, 2004-04-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed two show-stopping bugs in PKCS10_Request +* Added some sanity checks in Pipe/Filter +* The DNS and URI entries would get swapped in subjectAlternativeNames +* MAC_Filter is now willing to not take a key at creation time +* Setting the expiration times of certs and CRLs is more flexible +* Fixed problems building on AIX with GCC +* Fixed some problems in the tutorial pointed out by Dominik Vogt +* Documentation updates + +Version 1.3.10, 2004-03-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for OpenPGP's ASCII armor format +* Cleaned up the RNG system; seeding is much more flexible +* Added simple autoconfiguration abilities to configure.pl +* Fixed a GCC 2.95.x compile problem +* Updated the example configuration file +* Documentation updates + +Version 1.3.9, 2004-03-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added an engine using OpenSSL (requires 0.9.7 or later) +* X509_Certificate would lose email addresses stored in the DN +* Fixed a missing initialization in a BigInt constructor +* Fixed several Visual C++ compile problems +* Fixed some BeOS build problems +* Fixed the WiderWake benchmark + +Version 1.3.8, 2003-12-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initial introduction of engine support, which separates PK keys from + the underlying operations. An engine using GNU MP was added. + +* DSA, DH, NR, and ElGamal constructors accept taking just the private + key again since the public key is easily derived from it. + +* Montgomery reduction support was added. +* ElGamal keys now support being imported/exported as ASN.1 objects +* Added Montgomery reductions +* Added an engine that uses GNU MP (requires 4.1 or later) +* Removed the obsolete mp_gmp module +* Moved several initialization/shutdown functions to init.h +* Major refactoring of the memory containers +* New non-locking container, MemoryVector +* Fixed 64-bit problems in BigInt::set_bit/clear_bit +* Renamed PK_Key::check_params() to check_key() +* Some incompatible changes to OctetString +* Added version checking macros in version.h +* Removed the fips140 module pending rewrite +* Added some functions and hooks to help GUIs +* Moved more shared code into MDx_HashFunction +* Added a policy hook for specifying the encoding of X.509 strings + +Version 1.3.7, 2003-12-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a big security problem in es_unix (use of untrusted PATH) +* Fixed several stability problems in es_unix +* Expanded the list of programs es_unix will try to use +* SecureAllocator now only preallocates blocks in special cases +* Added a special case in Global_RNG::seed for forcing a full poll +* Removed the FIPS 186 RNG added in 1.3.5 pending further testing +* Configure updates for PowerPC CPUs +* Removed the (never tested) VAX support +* Added support for S/390 Linux + +Version 1.3.6, 2003-12-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added a new module 'minimal', which disables most algorithms +* SecureAllocator allocates a few blocks at startup +* A few minor MPI cleanups +* RPM spec file cleanups and fixes + +Version 1.3.5, 2003-11-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major improvements in ASN.1 string handling +* Added partial support for ASN.1 UTF8 STRINGs and BMP STRINGs +* Added partial support for the X.509v3 certificate policies extension +* Centralized the handling of character set information +* Added FIPS 140-2 startup self tests +* Added a module (fips140) for doing extra FIPS 140-2 tests +* Added FIPS 186-2 RNG +* Improved ASN.1 BIT STRING handling +* Removed a memory leak in PKCS10_Request +* The encoding of DirectoryString now follows PKIX guidelines +* Fixed some of the character set dependencies +* Fixed a DER encoding error for tags greater than 30 +* The BER decoder can now handle tags larger than 30 +* Fixed tm_hard.cpp to recognize SPARC on more systems +* Workarounds for a GCC 2.95.x bug in x509find.cpp +* RPM changed to install into /usr instead of /usr/local +* Added support for QNX + +Version 1.2.8, 2003-11-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Merged several important bug fixes from 1.3.x + +Version 1.3.4, 2003-11-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added a module that does certain MPI operations using GNU MP +* Added the X9.42 Diffie-Hellman PRF +* The Zlib and Bzip2 objects now use custom allocators +* Added member functions for directly hashing/MACing SecureVectors +* Minor optimizations to the MPI addition and subtraction algorithms +* Some cleanups in the low-level MPI code +* Created separate AES-{128,192,256} objects + +Version 1.3.3, 2003-11-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The library can now be repeatedly initialized and shutdown without crashing +* Fixed an off-by-one error in the CTS code +* Fixed an error in the EMSA4 verification code +* Fixed a memory leak in mutex.cpp (pointed out by James Widener) +* Fixed a memory leak in Pthread_Mutex +* Fixed several memory leaks in the testing code +* Bulletproofed the EMSA/EME/KDF/MGF retrieval functions +* Minor cleanups in SecureAllocator +* Removed a needless mutex guarding the (stateless) global timer +* Fixed a piece of bash-specific code in botan-config +* X.509 objects report more information about decoding errors +* Cleaned up some of the exception handling +* Updated the example config file with new OIDSs +* Moved the build instructions into a separate document, building.tex + +Version 1.3.2, 2003-11-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a bug preventing DSA signatures from verifying on X.509 objects +* Made the X509_Store search routines more efficient and flexible +* Added a function to X509_PublicKey to do easy public/private key matching +* Added support for decoding indefinite length BER data +* Changed Pipe's peek() to take an offset +* Removed Filter::set_owns in favor of the new incr_owns function +* Removed BigInt::zero() and BigInt::one() +* Renamed the PEM related options from base/pem_* to pem/* +* Added an option to specify the line width when encoding PEM +* Removed the "rng/safe_longterm" option; it's always on now +* Changed the cipher used for RNG super-encryption from ARC4 to WiderWake4+1 +* Cleaned up the base64/hex encoders and decoders +* Added an ASN.1/BER decoder as an example +* AES had its internals marked 'public' in previous versions +* Changed the value of the ASN.1 NO_OBJECT enum +* Various new hacks in the configure script +* Removed the already nominal support for SunOS + +Version 1.3.1, 2003-11-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Generalized a few pieces of the DER encoder +* PKCS8::load_key would fail if handed an unencrypted key +* Added a failsafe so PKCS #8 key decoding can't go into an infinite loop + +Version 1.3.0, 2003-11-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major redesign of the PKCS #8 private key import/export system +* Added a small amount of UI interface code for getting passphrases +* Added heuristics that tell if a key, cert, etc is stored as PEM or BER +* Removed CS-Cipher, SHARK, ThreeWay, MD5-MAC, and EMAC +* Removed certain deprecated constructors of RSA, DSA, DH, RW, NR +* Made PEM decoding more forgiving of extra text before the header + +Version 1.2.7, 2003-10-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for reading configuration files +* Added constructors so NR and RW keys can be imported easily +* Fixed mp_asm64, which was completely broken in 1.2.6 +* Removed tm_hw_ia32 module; replaced by tm_hard +* Added support for loading certain oddly formed RSA certificates +* Fixed spelling of NON_REPUDIATION enum +* Renamed the option default_to_ca to v1_assume_ca +* Fixed a minor bug in X.509 certificate generation +* Fixed a latent bug in the OID lookup code +* Updated the RPM spec file +* Added to the tutorial + +Version 1.2.6, 2003-07-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major performance increase for PK algorithms on most 64-bit systems +* Cleanups in the low-level MPI code to support asm implementations +* Fixed build problems with some versions of Compaq's C++ compiler +* Removed useless constructors for NR public and private keys +* Removed support for the patch_file directive in module files +* Removed several deprecated functions + +Version 1.2.5, 2003-06-22 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a tricky and long-standing memory leak in Pipe +* Major cleanups and fixes in the memory allocation system +* Removed alloc_mlock, which has been superseded by the ml_unix module +* Removed a denial of service vulnerability in X509_Store +* Fixed compilation problems with VS .NET 2003 and Codewarrior 8 +* Added another variant of PKCS8::load_key, taking a memory buffer +* Fixed various minor/obscure bugs which occurred when MP_WORD_BITS != 32 +* BigInt::operator%=(word) was a no-op if the input was a power of 2 +* Fixed portability problems in BigInt::to_u32bit +* Fixed major bugs in SSL3-MAC +* Cleaned up some messes in the PK algorithms +* Cleanups and extensions for OMAC and EAX +* Made changes to the entropy estimation function +* Added a 'beos' module set for use on BeOS +* Officially deprecated a few X509:: and PKCS8:: functions +* Moved the contents of primes.h to numthry.h +* Moved the contents of x509opt.h to x509self.h +* Removed the (empty) desx.h header +* Documentation updates + +Version 1.2.4, 2003-05-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a bug in EMSA1 affecting NR signature verification +* Fixed a few latent bugs in BigInt related to word size +* Removed an unused function, mp_add2_nc, from the MPI implementation +* Reorganized the core MPI files + +Version 1.2.3, 2003-05-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a bug that prevented DSA/NR key generation +* Fixed a bug that prevented importing some root CA certs +* Fixed a bug in the BER decoder when handing optional bit or byte strings +* Fixed the encoding of authorityKeyIdentifier in X509_CA +* Added a sanity check in PBKDF2 for zero length passphrases +* Added versions of X509::load_key and PKCS8::load_key that take a file name +* X509_CA generates 128 bit serial numbers now +* Added tests to check PK key generation +* Added a simplistic X.509 CA example +* Cleaned up some of the examples + +Version 1.2.2, 2003-05-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add checks to prevent any BigInt bugs from revealing an RSA or RW key +* Changed the interface of Global_RNG::seed +* Major improvements for the es_unix module +* Added another Win32 entropy source, es_win32 +* The Win32 CryptoAPI entropy source can now poll multiple providers +* Improved the BeOS entropy source +* Renamed pipe_unixfd module to fd_unix +* Fixed a file descriptor leak in the EGD module +* Fixed a few locking bugs + +Version 1.2.1, 2003-05-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added ANSI X9.23 compatible CBC padding +* Added an entropy source using Win32 CryptoAPI +* Removed the Pipe I/O operators taking a FILE* +* Moved the BigInt encoding/decoding functions into the BigInt class +* Integrated several fixes for VC++ 7 (from Hany Greiss) +* Fixed the configure.pl script for Windows builds + +Version 1.2.0, 2003-04-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Tweaked the Karatsuba cut-off points +* Increased the allowed keylength of HMAC and Blowfish +* Removed the 'mpi_ia32' module, pending rewrite +* Workaround a GCC 2.95.x bug in eme1.cpp + +Version 1.1.13, 2003-04-22 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added OMAC +* Added EAX authenticated cipher mode +* Diffie-Hellman would not do blinding in some cases +* Optimized the OFB and CTR modes +* Corrected Skipjack's word ordering, as per NIST clarification +* Support for all subject/issuer attribute types required by RFC 3280 +* The removeFromCRL CRL reason code is now handled correctly +* Increased the flexibility of the allocators +* Renamed Rijndael to AES, created aes.h, deleted rijndael.h +* Removed support for the 'no_timer' LibraryInitializer option +* Removed 'es_pthr' module, pending further testing +* Cleaned up get_ciph.cpp + +Version 1.1.12, 2003-04-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a ASN.1 string encoding bug +* Fixed a pair of X509_DN encoding problems +* Base64_Decoder and Hex_Decoder can now validate input +* Removed support for the LibraryInitializer option 'egd_path' +* Added tests for DSA X.509 and PKCS #8 key formats +* Removed a long deprecated feature of DH_PrivateKey's constructor +* Updated the RPM .spec file +* Major documentation updates + +Version 1.1.11, 2003-04-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added PKCS #10 certificate requests +* Changed X509_Store searching interface to be more flexible +* Added a generic Certificate_Store interface +* Added a function for generating self-signed X.509 certs +* Cleanups and changes to X509_CA +* New examples for PKCS #10 and self-signed certificates +* Some documentation updates + +Version 1.1.10, 2003-04-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* X509_CA can now generate new X.509 CRLs +* Added blinding for RSA, RW, DH, and ElGamal to prevent timing attacks +* More certificate and CRL extensions/attributes are supported +* Better DN handling in X.509 certificates/CRLs +* Added a DataSink hierarchy (suggested by Jim Darby) +* Consolidated SecureAllocator and ManagedAllocator +* Many cleanups and generalizations +* Added a (slow) pthreads based EntropySource +* Fixed some threading bugs + +Version 1.1.9, 2003-02-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for using X.509v2 CRLs +* Fixed several bugs in the path validation algorithm +* Certificates can be verified for a particular usage +* Algorithm for comparing distinguished names now follows X.509 +* Cleaned up the code for the es_beos, es_ftw, es_unix modules +* Documentation updates + +Version 1.1.8, 2003-01-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixes for the certificate path validation algorithm in X509_Store +* Fixed a bug affecting X509_Certificate::is_ca_cert() +* Added a general configuration interface for policy issues +* Cleanups and API changes in the X.509 CA, cert, and store code +* Made various options available for X509_CA users +* Changed X509_Time's interface to work around time_t problems +* Fixed a theoretical weakness in Randpool's entropy mixing function +* Fixed problems compiling with GCC 2.95.3 and GCC 2.96 +* Fixed a configure bug (reported by Jon Wilson) affecting MinGW + +Version 1.0.2, 2003-01-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an obscure SEGFAULT causing bug in Pipe +* Fixed an obscure but dangerous bug in SecureVector::swap + +Version 1.1.7, 2003-01-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an obscure but dangerous bug in SecureVector::swap +* Consolidated SHA-384 and SHA-512 to save code space +* Added SSL3-MAC and SSL3-PRF +* Documentation updates, including a new tutorial + +Version 1.1.6, 2002-12-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initial support for X.509v3 certificates and CAs +* Major redesign/rewrite of the ASN.1 encoding/decoding code +* Added handling for DSA/NR signatures encoded as DER SEQUENCEs +* Documented the generic cipher lookup interface +* Added an (untested) entropy source for BeOS +* Various cleanups and bug fixes + +Version 1.1.5, 2002-11-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the discrete logarithm integrated encryption system (DLIES) +* Various optimizations for BigInt +* Added support for assembler optimizations in modules +* Added BigInt x86 optimizations module (mpi_ia32) + +Version 1.1.4, 2002-11-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Speedup of 15-30% for PK algorithms +* Implemented the PBES2 encryption scheme +* Fixed a potential bug in decoding RSA and RW private keys +* Changed the DL_Group class interface to handle different formats better +* Added support for PKCS #3 encoded DH parameters +* X9.42 DH parameters use a PEM label of 'X942 DH PARAMETERS' +* Added key pair consistency checking +* Fixed a compatibility problem with gcc 2.96 (pointed out by Hany Greiss) +* A botan-config script is generated at configure time +* Documentation updates + +Version 1.1.3, 2002-11-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added a generic public/private key loading interface +* Fixed a small encoding bug in RSA, RW, and DH +* Changed the PK encryption/decryption interface classes +* ECB supports using padding methods +* Added a function-based interface for library initialization +* Added support for RIPEMD-128 and Tiger PKCS#1 v1.5 signatures +* The cipher mode benchmarks now use 128-bit AES instead of DES +* Removed some obsolete typedefs +* Removed OpenCL support (opencl.h, the OPENCL_* macros, etc) +* Added tests for PKCS #8 encoding/decoding +* Added more tests for ECB and CBC + +Version 1.1.2, 2002-10-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Support for PKCS #8 encoded RSA, DSA, and DH private keys +* Support for Diffie-Hellman X.509 public keys +* Major reorganization of how X.509 keys are handled +* Added PKCS #5 v2.0's PBES1 encryption scheme +* Added a generic cipher lookup interface +* Added the WiderWake4+1 stream cipher +* Added support for sync-able stream ciphers +* Added a 'paranoia level' option for the LibraryInitializer +* More security for RNG output meant for long term keys +* Added documentation for some of the new 1.1.x features +* CFB's feedback argument is now specified in bits +* Renamed CTR class to CTR_BE +* Updated the RSA and DSA examples to use X.509 and PKCS #8 key formats + +Version 1.1.1, 2002-10-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the Korean hash function HAS-160 +* Partial support for RSA and DSA X.509 public keys +* Added a mostly functional BER encoder/decoder +* Added support for non-deterministic MAC functions +* Initial support for PEM encoding/decoding +* Internal cleanups in the PK algorithms +* Several new convenience functions in Pipe +* Fixed two nasty bugs in Pipe +* Messed with the entropy sources for es_unix +* Discrete logarithm groups are checked for safety more closely now +* For compatibility with GnuPG, ElGamal now supports DSA-style groups + +Version 1.0.1, 2002-09-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a minor bug in Randpool::random() +* Added some new aliases and typedefs for 1.1.x compatibility +* The 4096-bit RSA benchmark key was decimal instead of hex +* EMAC was returning an incorrect name + +Version 1.1.0, 2002-09-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added entropy estimation to the RNGs +* Improved the overall design of both Randpool and ANSI_X917_RNG +* Added a separate RNG for nonce generation +* Added window exponentiation support in power_mod +* Added a get_s2k function and the PKCS #5 S2K algorithms +* Added the TLSv1 PRF +* Replaced BlockCipherModeIV typedef with InitializationVector class +* Renamed PK_Key_Agreement_Scheme to PK_Key_Agreement +* Renamed SHA1 -> SHA_160 and SHA2_x -> SHA_x +* Added support for RIPEMD-160 PKCS#1 v1.5 signatures +* Changed the key agreement scheme interface +* Changed the S2K and KDF interfaces +* Better SCAN compatibility for HAVAL, Tiger, MISTY1, SEAL, RC5, SAFER-SK +* Added support for variable-pass Tiger +* Major speedup for Rabin-Williams key generation + +Version 1.0.0, 2002-08-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Octal I/O of BigInt is now supported +* Fixed portability problems in the es_egd module +* Generalized IV handling in the block cipher modes +* Added Karatsuba multiplication and k-ary exponentiation +* Fixed a problem in the multiplication routines + +Version 0.9.2, 2002-08-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* DH_PrivateKey::public_value() was returning the wrong value +* Various BigInt optimizations +* The filters.h header now includes hex.h and base64.h +* Moved Counter mode to ctr.h +* Fixed a couple minor problems with VC++ 7 +* Fixed problems with the RPM spec file + +Version 0.9.1, 2002-08-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Grand rename from OpenCL to Botan +* Major optimizations for the PK algorithms +* Added ElGamal encryption +* Added Whirlpool +* Tweaked memory allocation parameters +* Improved the method of seeding the global RNG +* Moved pkcs1.h to eme_pkcs.h +* Added more test vectors for some algorithms +* Fixed error reporting in the BigInt tests +* Removed Default_Timer, it was pointless +* Added some new example applications +* Removed some old examples that weren't that interesting +* Documented the compression modules + +Version 0.9.0, 2002-08-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* EMSA4 supports variable salt size +* PK_* can take a string naming the encoding method to use +* Started writing some internals documentation + +Version 0.8.7, 2002-07-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed bugs in EME1 and EMSA4 +* Fixed a potential crash at shutdown +* Cipher modes returned an ill-formed name +* Removed various deprecated types and headers +* Cleaned up the Pipe interface a bit +* Minor additions to the documentation +* First stab at a Visual C++ makefile (doc/Makefile.vc7) + +Version 0.8.6, 2002-07-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added EMSA4 (aka PSS) +* Brought the manual up to date; many corrections and additions +* Added a parallel hash function construction +* Lookup supports all available algorithms now +* Lazy initialization of the lookup tables +* Made more discrete logarithm groups available through get_dl_group() +* StreamCipher_Filter supports seeking (if the underlying cipher does) +* Minor optimization for GCD calculations +* Renamed SAFER_SK128 to SAFER_SK +* Removed many previously deprecated functions +* Some now-obsolete functions, headers, and types have been deprecated +* Fixed some bugs in DSA prime generation +* DL_Group had a constructor for DSA-style prime gen but it wasn't defined +* Reversed the ordering of the two arguments to SEAL's constructor +* Fixed a threading problem in the PK algorithms +* Fixed a minor memory leak in lookup.cpp +* Fixed pk_types.h (it was broken in 0.8.5) +* Made validation tests more verbose +* Updated the check and example applications + +Version 0.8.5, 2002-07-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major changes to constructors for DL-based cryptosystems (DSA, NR, DH) +* Added a DL_Group class +* Reworking of the pubkey internals +* Support in lookup for aliases and PK algorithms +* Renamed CAST5 to CAST_128 and CAST256 to CAST_256 +* Added EMSA1 +* Reorganization of header files +* LibraryInitializer will install new allocator types if requested +* Fixed a bug in Diffie-Hellman key generation +* Did a workaround in pipe.cpp for GCC 2.95.x on Linux +* Removed some debugging code from init.cpp that made FTW ES useless +* Better checking for invalid arguments in the PK algorithms +* Reduced Base64 and Hex default line length (if line breaking is used) +* Fixes for HP's aCC compiler +* Cleanups in BigInt + +Version 0.8.4, 2002-07-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added Nyberg-Rueppel signatures +* Added Diffie-Hellman key exchange (kex interface is subject to change) +* Added KDF2 +* Enhancements to the lookup API +* Many things formerly taking pointers to algorithms now take names +* Speedups for prime generation +* LibraryInitializer has support for seeding the global RNG +* Reduced SAFER-SK128 memory consumption +* Reversed the ordering of public and private key values in DSA constructor +* Fixed serious bugs in MemoryMapping_Allocator +* Fixed memory leak in Lion +* FTW_EntropySource was not closing the files it read +* Fixed line breaking problem in Hex_Encoder + +Version 0.8.3, 2002-06-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added DSA and Rabin-Williams signature schemes +* Added EMSA3 +* Added PKCS#1 v1.5 encryption padding +* Added Filters for PK algorithms +* Added a Keyed_Filter class +* LibraryInitializer processes arguments now +* Major revamp of the PK interface classes +* Changed almost all of the Filters for non-template operation +* Changed HMAC, Lion, Luby-Rackoff to non-template classes +* Some fairly minor BigInt optimizations +* Added simple benchmarking for PK algorithms +* Added hooks for fixed base and fixed exponent modular exponentiation +* Added some examples for using RSA +* Numerous bugfixes and cleanups +* Documentation updates + +Version 0.8.2, 2002-05-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added an (experimental) algorithm lookup interface +* Added code for directly testing BigInt +* Added SHA2-384 +* Optimized SHA2-512 +* Major optimization for Adler32 (thanks to Dan Nicolaescu) +* Various minor optimizations in BigInt and related areas +* Fixed two bugs in X9.19 MAC, both reported by Darren Starsmore +* Fixed a bug in BufferingFilter +* Made a few fixes for MacOS X +* Added a workaround in configure.pl for GCC 2.95.x +* Better support for PowerPC, ARM, and Alpha +* Some more cleanups + +Version 0.8.1, 2002-05-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major code cleanup (check doc/deprecated.txt) +* Various bugs fixed, including several portability problems +* Renamed MessageAuthCode to MessageAuthenticationCode +* A replacement for X917 is in x917_rng.h +* Changed EMAC to non-template class +* Added ANSI X9.19 compatible CBC-MAC +* TripleDES now supports 128 bit keys + +Version 0.8.0, 2002-04-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Merged BigInt: many bugfixes and optimizations since alpha2 +* Added RSA (rsa.h) +* Added EMSA2 (emsa2.h) +* Lots of new interface code for public key algorithms (pk_base.h, pubkey.h) +* Changed some interfaces, including SymmetricKey, to support the global rng +* Fixed a serious bug in ManagedAllocator +* Renamed RIPEMD128 to RIPEMD_128 and RIPEMD160 to RIPEMD_160 +* Removed some deprecated stuff +* Added a global random number generator (rng.h) +* Added clone functions to most of the basic algorithms +* Added a library initializer class (init.h) +* Version macros in version.h +* Moved the base classes from opencl.h to base.h +* Renamed the bzip2 module to comp_bzip2 and zlib to comp_zlib +* Documentation updates for the new stuff (still incomplete) +* Many new deprecated things: check doc/deprecated.txt + +Version 0.7.10, 2002-04-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added EGD_EntropySource module (es_egd) +* Added a file tree walking EntropySource (es_ftw) +* Added MemoryLocking_Allocator module (alloc_mlock) +* Renamed the pthr_mux, unix_rnd, and mmap_mem modules +* Changed timer mechanism; the clock method can be switched on the fly. +* Renamed MmapDisk_Allocator to MemoryMapping_Allocator +* Renamed ent_file.h to es_file.h (ent_file.h is around, but deprecated) +* Fixed several bugs in MemoryMapping_Allocator +* Added more default sources for Unix_EntropySource +* Changed SecureBuffer to use same allocation methods as SecureVector +* Added bigint_divcore into mp_core to support BigInt alpha2 release +* Removed some Pipe functions deprecated since 0.7.8 +* Some fixes for the configure program + +Version 0.7.9, 2002-03-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Memory allocation substantially revamped +* Added memory allocation method based on mmap(2) in the mmap_mem module +* Added ECB and CTS block cipher modes (ecb.h, cts.h) +* Added a Mutex interface (mutex.h) +* Added module pthr_mux, implementing the Mutex interface +* Added Threaded Filter interface (thr_filt.h) +* All algorithms can now by keyed with SymmetricKey objects +* More testing occurs with --validate (expected failures) +* Fixed two bugs reported by Hany Greiss, in Luby-Rackoff and RC6 +* Fixed a buffering bug in Bzip_Decompress and Zlib_Decompress +* Made X917 safer (and about 1/3 as fast) +* Documentation updates + +Version 0.7.8, 2002-02-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* More capabilities for Pipe, inspired by SysV STREAMS, including peeking, + better buffering, and stack ops. NOT BACKWARDS COMPATIBLE: SEE DOCUMENTATION +* Added a BufferingFilter class +* Added popen() based EntropySource for generic Unix systems (unix_rnd) +* Moved 'devrand' module into main distribution (ent_file.h), renamed to + File_EntropySource, and changed interface somewhat. +* Made Randpool somewhat more conservative and also 25% faster +* Minor fixes and updates for the configure script +* Added some tweaks for memory allocation +* Documentation updates for the new Pipe interface +* Fixed various minor bugs +* Added a couple of new example programs (stack and hasher2) + +Version 0.7.7, 2001-11-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Filter::send now works in the constructor of a Filter subclass +* You may now have to include explicitly in some code +* Added preliminary PK infrastructure classes in pubkey.h and pkbase.h +* Enhancements to SecureVector (append, destroy functions) +* New infrastructure for secure memory allocation +* Added IEEE P1363 primitives MGF1, EME1, KDF1 +* Rijndael optimizations and cleanups +* Changed CipherMode to BlockCipherMode(B*) +* Fixed a nasty bug in pipe_unixfd +* Added portions of the BigInt code into the main library +* Support for VAX, SH, POWER, PowerPC-64, Intel C++ + +Version 0.7.6, 2001-10-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed several serious bugs in SecureVector created in 0.7.5 +* Square optimizations +* Fixed shared objects on MacOS X and HP-UX +* Fixed static libs for KCC 4.0; works with KCC 3.4g as well +* Full support for Athlon and K6 processors using GCC +* Added a table of prime numbers < 2**16 (primes.h) +* Some minor documentation updates + +Version 0.7.5, 2001-08-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Split checksum.h into adler32.h, crc24.h, and crc32.h +* Split modes.h into cbc.h, cfb.h, and ofb.h +* CBC_wPadding* has been replaced by CBC_Encryption and CBC_Decryption +* Added OneAndZeros and NoPadding methods for CBC +* Added Lion, a very fast block cipher construction +* Added an S2K base class (s2k.h) and an OpenPGP_S2K class (pgp_s2k.h) +* Basic types (ciphers, hashes, etc) know their names now (call name()) +* Changed the EntropySource type somewhat +* Big speed-ups for ISAAC, Adler32, CRC24, and CRC32 +* Optimized CAST-256, DES, SAFER-SK, Serpent, SEAL, MD2, and RIPEMD-160 +* Some semantics of SecureVector have changed slightly +* The mlock module has been removed for the time being +* Added string handling functions for hashes and MACs +* Various non-user-visible cleanups +* Shared library soname is now set to the full version number + +Version 0.7.4, 2001-07-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* New modules: Zlib, gettimeofday and x86 RTC timers, Unix I/O for Pipe +* Fixed a vast number of errors in the config script/makefile/specfile +* Pipe now has a stdio(3) interface as well as C++ iostreams +* ARC4 supports skipping the first N bytes of the cipher stream (ala MARK4) +* Bzip2 supports decompressing multiple concatenated streams, and flushing +* Added a simple 'overall average' score to the benchmarks +* Fixed a small bug in the POSIX timer module +* Removed a very-unlikely-to-occur bug in most of the hash functions +* filtbase.h now includes , not +* Minor documentation updates + +Version 0.7.3, 2001-06-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix build problems on Solaris/SPARC +* Fix build problems with Perl versions < 5.6 +* Fixed some stupid code that broke on a few compilers +* Added string handling functions to Pipe +* MISTY1 optimizations + +Version 0.7.2, 2001-06-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Build system supports modules +* Added modules for mlock, a /dev/random EntropySource, POSIX1.b timers +* Added Bzip2 compression filter, contributed by Peter Jones +* GNU make no longer required (tested with 4.4BSD pmake and Solaris make) +* Fixed minor bug in several of the hash functions +* Various other minor fixes and changes +* Updates to the documentation + +Version 0.7.1, 2001-05-16 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Rewrote configure script: more consistent and complete +* Made it easier to find out parameters of types at run time (opencl.h) +* New functions for finding the version being used (version.h) +* New SymmetricKey interface for Filters (symkey.h) +* InvalidKeyLength now records what the invalid key length was +* Optimized DES, CS-Cipher, MISTY1, Skipjack, XTEA +* Changed GOST to use correct S-box ordering (incompatible change) +* Benchmark code was almost totally rewritten +* Many more entries in the test vector file +* Fixed minor and idiotic bug in check.cpp + +Version 0.7.0, 2001-03-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* First public release diff --git a/comm/third_party/botan/doc/packaging.rst b/comm/third_party/botan/doc/packaging.rst new file mode 100644 index 0000000000..f77000b89b --- /dev/null +++ b/comm/third_party/botan/doc/packaging.rst @@ -0,0 +1,59 @@ +Notes for Distributors +======================== + +This document has information for anyone who is packaging copies of Botan for +use by downstream developers, such as through a Linux distribution or other +package management system. + +Recommended Options +------------------------ + +In most environments, zlib, bzip2, and sqlite are already installed, so there is +no reason to not include support for them in Botan as well. Build with options +``--with-zlib --with-bzip2 --with-sqlite3`` to enable these features. + +Even though OpenSSL is also typically already installed, using +``--with-openssl`` by default is *not recommended*. OpenSSL is sometimes faster +and sometimes slower than Botan, and the relative speeds vary depending on the +algorithm and CPU. + +Set Path to the System CA bundle +--------------------------------- + +Most Unix/Linux systems maintain a list of trusted CA certificates at some well +known path like ``/etc/ssl/certs/ca-certificates.crt`` or +``/etc/ssl/cert.pem``. Unfortunately the exact path varies between systems. Use +``--system-cert-bundle=PATH`` to set this path. If the option is not used, +``configure.py`` tries a list of known locations. + +Set Distribution Info +------------------------ + +If your distribution of Botan involves creating library binaries, use the +configure.py flag ``--distribution-info=`` to set the version of your +packaging. For example Foonix OS might distribute its 4th revision of the +package for Botan 2.1.3 using ``--distribution-info='Foonix 2.1.3-4'``. The +string is completely free-form, since it depends on how the distribution numbers +releases and packages. + +Any value set with ``--distribution-info`` flag will be included in the version +string, and can read through the ``BOTAN_DISTRIBUTION_INFO`` macro. + +Minimize Distribution Patches +------------------------------ + +We (Botan upstream) *strongly* prefer that downstream distributions maintain no +long-term patches against Botan. Even if it is a build problem which probably +only affects your environment, please open an issue on github and include the +patch you are using. Perhaps the issue does affect other users, and even if not +it would be better for everyone if the library were improved so it were not +necessary for the patch to be created in the first place. For example, having to +modify or remove a build data file, or edit the makefile after generation, +suggests an area where the build system is insufficiently flexible. + +Obviously nothing in the BSD-2 license prevents you from distributing patches or +modified versions of Botan however you please. But long term patches by +downstream distributors have a tendency to bitrot and sometimes even result in +security problems (such as in the Debian OpenSSL RNG fiasco) because the patches +are never reviewed by the library developers. So we try to discourage them, and +work to ensure they are never necessary. diff --git a/comm/third_party/botan/doc/pgpkey.txt b/comm/third_party/botan/doc/pgpkey.txt new file mode 100644 index 0000000000..78a8a2dc52 --- /dev/null +++ b/comm/third_party/botan/doc/pgpkey.txt @@ -0,0 +1,198 @@ +The following PGP key is used to sign all releases: + +pub 2048R/EFBADFBC 2004-10-30 + Key fingerprint = 621D AF64 11E1 851C 4CF9 A2E1 6211 EBF1 EFBA DFBC +uid Botan Distribution Key + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.17 (GNU/Linux) + +mQELBEGD1j0BCADHxPJkPcjJE+4Dlisx2hVc0Dj6JI1MSLrkM8R+2bOhVUSferxP +T1EMPhfrAdOHTAloyvRThJztnZsNKqfLL49GGcBLdEGAVNks1pG37Teze5Lx1XIu +zJFrozL2sqBy5C6nHpFgd1tcD68Rah2wp0u2cR9owXf1IqKdEfuo661+MTv7wTB1 +4hKV75nB7ZO6676SEZRILYM+7RJwKAKEmEPJc6hEf94VXn9ecNzaTlHgYkjhz9db +LOd3od9XvuUw+LMR1dwBqMxbvR90MiXjbedDEkbArcZB9YOAIvEX/lC3qaW4XJt4 +iwHWl/YVZEfALcvQywe2CDrH5hO794wd9MpBAAYptBZCb3RhbiBEaXN0cmlidXRp +b24gS2V5iQEqBBMBAgAUAhsDAh4BAheABQJKfFpnBBUKCQgACgkQYhHr8e+637xk +PQf/aOi78XenwwvFrwXOVIVTdZIf8rK1zJksf26h09UD8uVV6z5iiTcpn86+eN9p +6Ar8IH3tD+JuFnPSwZ/r9MNC2XZwenYo4Gb14jqM6/9hBe328vmeM4Y1G7bD4HrL +kgV5WEyokqm3zbp3FBLr3Vh68TAC5JB9aHevra+cCA2u3vBNI3YUM5z4TdO150P3 +J00whkqImQEUni8bgxvllBLFM+uhucsX3HZWkoDEpotbg8yd0bqMkiPEyMr1OnJq +eDVDMrB5wnyLgLFfRAAw3mopM0C1PNOAHr/BIYiaDHX2OwnOfep8rMDoRVf2Ge0D +DBgsJJ6LduQHLeg403SHWL2F6YkCHAQTAQIABgUCQYPWUgAKCRBcD5boTsFta+r9 +EACWVis7YcaGkKKgRB/5ox8rM36XVhMXdh/hnnGHt5rapbbRRkRHRcWU8WIcFO1A +59+TfwNNd8gN1MEt/5aX5KHWVKHBDexJgIxm6Dm1pisYHf/dnYQPM18hmqqwNlKY +97hFkPpHd7enrtc/SvGbQhhLXYlpwBrdMl76e9xJLnnrRQksxegGPo8cr+C9HTs1 +Lwa8zzBxyBwYBYX+0moDkDShEhuXx6mEOXrGvQanJuIvpoIwGH+62E65MbJGlwWp +w/MAtm2jFhBIhGV0bqJCFp9zIgdNgfskBaPr0oilbuJQZqP0Iqe/6CCt4XkS51yW +ZqxjLAFpEpvDec4PGw3witKf/koGon9X8C035+nEjLBrWy18Q91vw2USyLI+mm9d +iMAS8pY2gomfxBO2VwYHJryZykjCYQkccRA1tHteRj4gqTObo0Ak47y5MnplTWwi +40oP7K2cfhCRBmMioxmYES4xsHEupfRBo3xr1Jq9q0t688WTT1NXHPMPoueF9mKZ +Cf2pa9aHsqBmWTm3sCaNQKGubCDBEUmJUyndmSatJyYM7NVYoUp6EfqMACFuTNdB +sjKMh7aWVikQpbJDfA1BIU3lZeqgjgrghVAWkEOBfhG0IVZj+RVCJpsqoTJ8asY2 +VreArSCyr/VnLEnfuH/QpgvCiCbepo3E34DJt4SaAOO2ZohGBBARAgAGBQJMGVc1 +AAoJEKY/LL36AvvMgsoAn2G7kXd09BF7ffk1Sfh174SVrvM9AKC7+R7x0+yV3SCd +JkkUOo3xR5cOxw== +=1QuR +-----END PGP PUBLIC KEY BLOCK----- + +This key can be used to contact the primary maintainer: + +pub rsa3072/57123B60 2015-03-23 + Key fingerprint = 4E60 C735 51AF 2188 DF0A 5A62 78E9 8043 5712 3B60 + uid Jack Lloyd + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBFUQXRMBDACZJvcSkr+GNDtIdP9fQWRXByriiIKvuKbqU8KGdhTcPeKwl3y3 +l1W9XsWA2DJ8QDKo4ZcV0lycszIvwBLZllJJWSVNFKxJK2IW33xcIo9dhNqj+hcz +LxKtBlBU3QKXdQ9+VKSY4EpO6gt/ar21PV+EQcFA9UtT1mRKVqY0pGGxqfQjrOss +rJKoJyA+1trH4ir7+0/524HNzsBj3B1GmrYfstspqetXyVQ1DoFiThUnj/zJGes5 +uW9laI9VBgrtMTBbYrylBytXiF0Flzx+bd21krgL37NH2uU0EHPjSx571q/XGG2U +4iOEPvPu7vtV8Rpqd0xQyaHcpoHNklcfND1c/6uZG1Sx9atDScRYHinUZvtTRtN+ +OY5vW+H7LJqT6CeMjh6Ev53V+0JCDZFQLaBdP/NanSQBUhPkyfyQSiqWOSuaMD6n +Eu+BigmzwDlsauuReTJ65gdIGI9Egt7Ax/ooKpBvPkWeT+GORKTs+qGy6sbKXrTe +crFFN/HZPWAJ+c8AEQEAAbQhSmFjayBMbG95ZCA8amFjay5sbG95ZEBnbWFpbC5j +b20+iQG9BBMBCAAnAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheABQJXT0JHBQkE +IBi0AAoJEHjpgENXEjtgqIQL/28NiIuK+yZNvfEDifjatDUnmgaCVoF2cy02Wa1z +pKg7l2ccQBKzAoqN3j4GkgL1gxi96dp+rwgL5bwpRpVIrNLs1gFyIYDGxf/XZlbG +m8ezOA62uz8ErIdAURK+LvCpIabth7++mnUwQioGRZCjNBp6Nx7QLM2cK8n+PqMh +oLl6UZ4p3PZM76ygxOdukTXD9ExDVoiQIFCy+eh0g3JnIP6s0oAsnAl407UCqbXf +ahXI0jnaioAfpBKcWV8TGG/KQ1Ln2v5Xt56SDdYKogt0xaY8u8RAELI9Gwkhhuf/ +t5kJmA/8J0qEUKUv7r8X/52PcZdjOGMnawT0mtWb13zqbAHGMhq+vW1HNwfprfes +lqfbiJ5iUC6bammgOaUao14T3wzzuk0jP2VK7owpfLTgycAkbAis5M4gmfZwbiU2 ++tZVU/h7E0THG7OQxbvMPeD5lcp2o4DlYqmpn07tGymiqUyqWdpHsCWS/EQYT+oN +uZQ8GeVGJq+A/WIUzDzGjQp+JokB1AQTAQoAPgIbAwULCQgHAgYVCAkKCwIEFgID +AQIeAQIXgBYhBE5gxzVRryGI3wpaYnjpgENXEjtgBQJeII8fBQkK8WWMAAoJEHjp +gENXEjtgk8EL/3HCYNwfdn2XWcbOcvGC2avq0yzxKkhtk+7fu7LbyEp7EL+ipA+f +gB7o/72ZeebVQHG8CYuYVvQzKI891hccyfQ/DfVuBrNvHq06+On6/YJuaKriP4i8 +YewgJj2LKjoE1+aL6/3HmoTrlXD0h8CBuKtVptGOVxsMfVK2fkIH5pGZajMP9egV +ETIgDxLdO7FeJ4jro2fg8w+e/PqqruBxwQrdzzvjW+EqxcFNnql4CzP8JpQVuNMp +Sh1QxilrnMDIGo8l8cZ4kMIeS3V+WJuNmTo/0hbH30qMKn/vKC9CwmTxazG12X7N +9n0u0wuN8TFoAZsiYwGKiPygGxjtOzLbK9nDVd7ShFreEoFlOuTCMbc8FSk7FEGX +prgybH0if7vXM0D5dA5MYhQi8yDmgCyg8vFF3kvMqVvIidOBre0xmZI35tgufduw +ZppI4+PzrTMyLe0V6f13Sa6vE8S/hqq0FByGWUsRyfqbvmXYINxOqNxEuJ+mLhSE +pyP0Qh0c9EmQLbQgSmFjayBMbG95ZCA8bGxveWRAcmFuZG9tYml0Lm5ldD6JAbkE +EwECACMFAlUQXRMCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRB46YBD +VxI7YI8aC/9GY4DNepqtopq1YlY1XrtyLg3tGzKvJVHXw07kGZiuvFOYXJcDzuKh +FaGuIKxJ+7PvreOXycD/9/WFXyCwvhczMgbRf3lFqkjQdmvnwmIGUfZL3pqorJDd +SjKiaXk8/NJBEBHlTN199bFECTzBr48keGHrzUPUYh2U3wo8CNW5ZsHHHmibjeoO +pfdLgK+dnUNwOk3/nEZtWUd9cTwCnd5vyxt7I1p1ntb3JLAEd4z5wd2afJHbjQZ3 +uiTQBXDUd1PFH6I6fI7L+UeU+tGNPe3fe6G+zNhxmJPKBPEwzTA/r6iuLrQwNBHY +PYm6J/fKBDU117Hnwuz4W9RSVVrtizCWIba6EptFencigruCHaO4CWbFl71Cu8n6 +ibEINHdKpE9qQzSD5kHfwsJ6FVnl9Qk8yJqh9U7NF/C8hHLbpF9J5n4WfN3qZyFp +UMbsEVp6Rhv/ObnxwaqNYWCqCyiCawsNk//ks4Xr+HmePJ3XA9lzvgVCoMEra+n1 +RbHCEGImpUmJARwEEAEIAAYFAlYaUEwACgkQYhHr8e+637zLeQf+OdP/xE2YyFUJ +L1+xEKHpvAeN+98Vn1C2sTmotNIaPwVBY9FLeA484IWdFwnJfXx1gQyybxlytz4B +ZuC7Jzu60OEmk5IFRIqQoVywEXWCOUg/UEBWZm+ZcRzIFciqj9PcOfpt6s/aSZd5 ++Rcm5HUGALYCqek2s9nGO8a1Wnk4m9d1u/RAGlxFM2the1v5p597ItGhcOP3tjWV +PPOuTe0E+/FI3ZxpotKGdfS6F/GB2bP7kma2iVO621Cs9wsYmrZEamKpax7X7p9m +yaAG0YRdCTslFd/EOTLOllPhy58DTr7qyswBPEI0x8WEDTE0G0IdQYNmLq4kuzeO +aIlcUMULzYkBvwQTAQIAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheABQJX +T0JHBQkEIBi0AAoJEHjpgENXEjtg6wEL/0Eh78RRRk5DjWpbPuIQZFbScNlPHuVT +oNL3YNgtPvyF576aExl7ObpwsRAXPr6XxCYWhNW18ffgP42kZccGp6ACq8bhzh7g +lbjnaAR0+78Of8DHWkCYwV00kEF3QKkNRUNDSgqLC5m+QWl1os5qRhmBcfNU4/zz +51RzHqXcEPEZuHeInmrz496BNwzl/2eXnRGYENpc3FCBNsdvWwzaSotNJzdh4jFF +1eSSUFpJ6FMKRHxvtx1G8+1FjJ/NHMBjf/ulnuukl/Hf5KB/n8VWSiCD5c8X5hED +0lj9YHSJH1Q6rft5iWO+R1MyWlxZ2xJzZD5wfZ7gBEp8b32NH5mMmZqBhh5u/M7b +kpgr5ETrKlTCuARFdjzkXVfG0VszBRCFMpCmO4WAucLYEcJvqJhxOayVoFP10taC +Ouo+hPWM6v4WGMaWydcmcygscoF7u/K69om4h6kw/b2eB4DqMUe4GsaYbZHFfN/n +0FHUgQ7flpX2O5rnTrQ++Yle+fc8g36KSIkB1gQTAQoAQAIbAwcLCQgHAwIBBhUI +AgkKCwQWAgMBAh4BAheAFiEETmDHNVGvIYjfClpieOmAQ1cSO2AFAl4gjywFCQrx +ZYwACgkQeOmAQ1cSO2DZbwv/Z1+f7l71wUh44A4ovbpmK+IqhNMqDwdpltWOzT2V +UJQOrcWNIwtnycZ61S31/8XuDwOeh0xYIPYN7uayjwLpqLaPQPnU51ETH4/beCAh +ExgK9KCPrxuKmdzkTkmgsw1IFlE+iPSN58Bz0oX0KXs31JXb27RfPMK1StZqaJj3 +zyq+TVnokpw8IQlWNyDuER50m0q1khim4qguXpKBKNJecmnaJVWZUwYjfoP8aOQB +3LybmGpsMshkwirueeoRBcGiqdPofTxBQYbeRVa3JWdBBuWKh6m4eYl6mvHIEdzG +7KmPG/bWCJSf8fVBcm/MH65aa7CcoKkCPuN+vDq9w3/Yp8+pxQlQFaRqvHGhQkxb +xvn2kmgZt7CDRJYjYaD++I598S6YecA2hstNh8lj1YyPgU4/wFJ8N27+pI13koda +n7tXx8LO6WjH45SPDgTEaO3i65rUQ3NHhQ8gGa8GUrTc1G+kzCG6+WvhYRrwn5gC +Z+39H2CXLtWzgx0qvyXNqToGtB9KYWNrIExsb3lkIDxqYWNrQHJhbmRvbWJpdC5u +ZXQ+iQG9BBMBCAAnBQJYCsPpAhsDBQkEIBi0BQsJCAcCBhUICQoLAgQWAgMBAh4B +AheAAAoJEHjpgENXEjtgqiML/3u7F/QhLb9FabkuicFrxmsHrNs2M6EKlSB3ZCjM +1krH/Ca59PpK4tjG8pC1FzJyb95vwE93qwl0yR+/K1PU94fudN9FFEHpcDIgh/rH +QEZg9fZWZe6EmizJA7kbYrJvqZr7x/cmMV17EQHSJMPKiboAkaKejm7m7CiPpoU4 +fPATesU2wbN5uifSVsKWJYv28O0SawkoUC1aTG1HTxAblEriivQ5c2R45VcylcGd +BG17xztSttiREG5nuzk26ZeB/19kLhgSAYEack+EQegFkzKxGQ2R4ScaZulqjjaB +mQ688P56R2E+ly+Vjga3tck9ydxu/3KBvMqdEs1NSjx+74ULS4XwpPr+lVffKBOK +r/5RC+jr5Z692rN3+IukkBG3a2iKJdRPcTSCeq4qZ75ZdYb5KCZK83Mh8jAaqd7g +utimOTbywFBJeBWlDfAIolrQTMe8+wuOhWq48sdevxUMospb1RQ/oqq+DPGyNFN9 +hMdAxEvJaffEdSge/QyrTiMll4kB1AQTAQoAPgIbAwULCQgHAgYVCAkKCwIEFgID +AQIeAQIXgBYhBE5gxzVRryGI3wpaYnjpgENXEjtgBQJeII8sBQkK8WWMAAoJEHjp +gENXEjtgHqsL/0+CKqak4LUcrXuHUj0pcbNsr8RNRqHon+ICVQhOyYcZkUkGmUic +4CVl3Gsus8kEfQmM9yP4T/+7CqDUFMDBihKnZ7evYJ2/SLmrjbmfdnQFIC03gjUa +i2QlInpBU2CFWJOmlm8tJt3fnQ6whAIj9380kJFkLDP7XBP5LN6YkCiCvopT3Jr8 +sunOxxG/uT2oy+mXDsySPAr0NRvkymc7tGqO62Qst0ZYsrR4wnVGZNdmsdYN6jt8 +/2JQasOaIEFgYXLB4XqxjYrfcZryeESCeDorXSRvpreokJoOZpeThdDpGC32JHkI +CBz1BaH5j8DJSedZN/LJdWi63E+eR6V8sFPvpt6oPgCELATskVZzOepFUlpr+5Vi ++/aCv2TvFfUkMh/Oa3dOn2k83a5kSuT66ODkfs8IOEII51tApSsUngs/JlNvD8iX +8INgBnb8DJUen1FucmAwOhl9Uzh3VuBbWW3mB2uCwwQVHHL49NURP/S3TvoFrWbF +IXM7NLfQA+nubLkBjQRVEF0TAQwA3o0T99H866uziNzpJpWhwpJn7+kZdWvFD9kW +htruQmrT0MtBnbW8diSrvAysC1r0PqAflstn3TEjpJzJH19hNZgNd0MfHxKDsyPd +kqHGOvW1CJxE9PoE/hYuoEgJ2VRZX/84JEWTXcbx94M75lPxg/91VSuPef3+bB84 +ebs2lvs8df8sW4PKj/URdlnKrDf8uUj7P7W4EoVgPZarMvDxKb9T5qPM/rLTjBSR +/jlWMuQUjZs+ToJVg23ZO84TMg7fMEA3oNItIU5Nif1TBHa+um+gmwOONJGNyNtn +/y4UJZ8uGBPAx5BwfSPEevjtCzZygCkcEAgHnt5Lpn/LhWNrdjQA2lvnUW7swM9d +BdbiDz0YxMgQq7b8pQ3+icYhiHomz1Fg1/xIn7BpDQ1QtcAyTUAB+SeXYCmX2ApE +MfoS969Bc9UjoSU5NnDiCobP3EaoL6BuaHZSZLmfwH+crZ3QAw37V6VkBqlMUV04 +yEx0N4GT7UZFD+3/OwtNQ9JJFUsXABEBAAGJAZ8EGAECAAkFAlUQXRMCGwwACgkQ +eOmAQ1cSO2DeuAwAgMmCe4Rjud64kwjMfI7n1rxf72Kn1d94M3CNqomTSsiipJ2Q +iqMbwjoLiVt4vSmcbOWK528SZCKPiGdI185STnygbJF3JR4r14LYp5n4ezeyoy4C +GVgiH5FHqJ+jmSrFH+B6jqJcpLxWoNBGKqhJKsuqEhTuRCIVxBZzfBhpI5Rc2lnO ++VOUxgzio/1ivO7x0bW0pJPd+ZaLyX39OYcg+2ySAHR3NN2Qp7aRmkkUWq5i2ita +0JDAX7Ca0DTY0wfCtDPCH9Go3P3BQTCFBUFr8DynTB0SyQsVBle3c+djwYdBXPn2 +0CuiXDeR6zT9Wu2AJQVLu2+af3EjqUnG95CI3oRzbPmBvAoFKGRK+imLSDzdgt5I +0+sIgGYtII6bUCOxcXexBrMRioAaEHqqJsKy55vGemurxBr+PTCyrufxk7trpx1y +eG7h8Xdh1ZxpaUJQrPNZvxZdeh4Jo4rGYPkiCwaIDGc8q+wGB7WsyGUKgkmEkSZS +XDGg/rs23aYdtiH9 +=M25I +-----END PGP PUBLIC KEY BLOCK----- + + +This key is used for signing git commits: + +pub rsa2048/AB50F90D 2016-03-03 [SC] [expires: 2020-03-02] + Key fingerprint = 1175 1014 9DF4 18AB D19C B06D 9FFD 596F AB50 F90D + uid Jack Lloyd (Git Signing Key) + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFbYWi4BCACjgz3gYgWMybPLiovNLnLonG0ex2y9kJgsR+Pm08L2fwCVCaHx +wjlK5Oq04x3bvujZk7P0TThqS1WonYtEiVxz3Hcvt7rlU5fSCj/1uYmZV+mbPBdY +f/yXMx3UD1UkZrdzbM21L78dfOoLZ2ybyuk4QOEad/AkouDCUA2pY3DJdNyX8Aee +dBdQ+sQqF6DyDz4SDY+KAq3nFmmT04bdkiL9sZb2HUokxIdeA6HIR+CxxFaZzrYW +Ky4iNPS1Zxv5D1KmpZzUOfN9RTgkbdRltgWxjpB+DFNUkpu3hYm/Y9lTPqGBt2C8 +JfIS5OaHxUVz0A+DtIGy+lk8/O5ek4suQBZ3ABEBAAG0MUphY2sgTGxveWQgKEdp +dCBTaWduaW5nIEtleSkgPGphY2tAcmFuZG9tYml0Lm5ldD6JAVcEEwEIAEECGwMF +CwkIBwIGFQgJCgsCBBYCAwECHgECF4ACGQEWIQQRdRAUnfQYq9GcsG2f/Vlvq1D5 +DQUCXl5bBQUJDSmbVwAKCRCf/Vlvq1D5DcTHB/9t0LZYlso93Jdq+ozRNTuo/SJl +MdViPlZ+upLi/5DqXBzUsNp9S4NkaaCendOIPbugSiGwWMk8LQpb7pTlbVFUJoem +Y0BUwuS5uk6YK4gxrTFl1P+VCbLA3UjXch1GWfh8JSp7SMcC0vcPd3WmuI06VdiU +sMeWThP56UA9SJbwWM735bosgYtdE3BMnEjDmvnmLcM3cn+saW+TkTFr/kkGjFHA +1Fg62vRfvsPokq5S1PdUjE7eY5u2W2r94mMcS/kY/Xg470XsBSbyjIviqX2irXgf +Ln0bmqsxNWiedocdVrdsk4n98eLXosKq4HKSWO9fwlwbF6P78K5Ygu1z2eGXiQE9 +BBMBCAAnBQJYD2ybAhsDBQkHhM4ABQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJ +EJ/9WW+rUPkNXfIIAIOgepYeZN2HL2T3A8pk+5JR2cfBoRufYgnG6mVHPejgZDW+ +9PH1tPDgidnePw3/jfD1oskt1VwOCkqaSBAcG2QeOBEklcsrQuvOfW7B7XFydYGw +T9Fm8/sxekiGjDQQWQEEH4j3Vt1GlI2sJrpqMe/WMXISsEnLfw0kDspUSlFOn8oy +rBU9Pd8KaSi38lp05a9Mcun5enJ3JpQHQ5RlNXDNh/Sn9NZ+MKWggytZqIy82jnv +6zo0raZDup4hLKopjen/SINR5XcwRK2lUtYVwwQH8FHG9IkeVJNWJkVCdZLB08sq +4WHRbtVjy6mpvEHTmolAtHjLSiV5W50LDKLwX260MkphY2sgTGxveWQgKEdpdCBT +aWduaW5nIEtleSkgPGxsb3lkQHJhbmRvbWJpdC5uZXQ+iQE9BBMBCAAnBQJW2FwD +AhsDBQkHhM4ABQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEJ/9WW+rUPkNK3cI +AI+6M5JixbjdyoVSDor0RW4u5h6UESe2mRZ5YFzh8F5uGms8PE5HrIZAfNVy9lJr +DoLSPpeb5KLAdGpaJ1NuJJ2glYzZFYr05gVHgCKJgfo6jkW22XnwO+vyXK+6TB6A +ExgO0RdN5aZcHL8KCfCWncVsWvF8d2cvbdb3sTfqtZoZ0l1DyYA62pz5BZd+iySj +nWGsL9YM53pC6hhq62onSqfv0X0fqzZ3+zIqTgVMOJxIFCXBiUBkHEuizUULfPrP +xfAiaEQcaOcpEos+/OsG3e3nFmXEAlDa9ZsS2VEaZ/nFJPIaKeDXt80ptScnxp2t +lecw8hR/OfJJ6MFMw4W/J8WJAZwEEAEIAAYFAlbYXDcACgkQeOmAQ1cSO2C8Kwv/ +ebJNrhMoknG5dSPVJpJxL0ta/m4KYBjX94VsB6Ofz96UmnNlCe9Exbi02ecLygQf +B9UUv7nsrORGOSoIEIV/RSYgN2eYUM21DHddlgVG3DTRrG//iV6rzAdgkZdRkxBh +nzeFJRv4TMmnRQXM2x+gjognDWLpjgdvkRFcv5l6fTH24IldcdymnvmqBmsLvqoK +Fj13CtsDjngp5gGgp/ieIW6sPmgQX1pJCWHFDe/0qcjvuy0fKMq0Oyd0/8dXCnNa +wPb/9xlQY+lCpHILfvFsVty5djqHqDNKEBuYxyPjHICPGRukSK+zCS0EE8nz/oxo +r4OIr5svawfIO5Zw69USo01jC+K1OSRJQthFft5GqTwkfHniYJSVh7K1rPI/H35t +f+XZLBwlafWs7vQb8XZfAPzhqw9blc5RS478rqzNQ0F1PHITjbaSCkMCgaNa2aea +oIw9uQjp6uB2T4xGAeqsd6JPrr5g1VZFPqthXdiDu6JmN4aVksG/SCx2Cwv2qiuS +=kPHM +-----END PGP PUBLIC KEY BLOCK----- diff --git a/comm/third_party/botan/doc/roadmap.rst b/comm/third_party/botan/doc/roadmap.rst new file mode 100644 index 0000000000..6a5808d562 --- /dev/null +++ b/comm/third_party/botan/doc/roadmap.rst @@ -0,0 +1,54 @@ + +Development Roadmap +======================================== + +Near Term Plans +---------------------------------------- + +Here is an outline for the development plans over the next 12-18 months, as of +June 2019. + +TLS Hardening/Testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Leverage TLS-Attacker better, for example using custom workflows. Add +interop testing with OpenSSL as part of CI. Improve fuzzer coverage. + +Expose TLS at FFI layer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Exposing TLS to C would allow for many new applications to make use of Botan. + +TLS v1.3 +^^^^^^^^^^^^^^^ + +A complete implementation of TLS v1.3 is planned. DTLS v1.3 may or may not be +supported as well. + +Botan 3.x +---------------------------------------- + +Botan 3 is currently planned for release in 2021. Botan 2 will remain +supported for several years past that, to allow plenty of time for +applications to switch over. + +This version will adopt C++17 and use new std types such as string_view, +optional, and any, along with adopting memory span and guarded integer +types. All deprecated features/APIs of 2.x (which notably includes TLS v1.0/v1.1 +support) will be removed. Beyond explicitly deprecated functionality, there +should be no breaking API changes in the transition to 3.x + +Features currently targeted for Botan 3 include + +* New post-quantum algorithms: especially a CCA2 secure encryption scheme and a + lattice-based signature scheme are of interest. + +* Password Authenticated Key Exchanges: one or more modern PAKEs + (such as SPAKE2+ or OPAQUE) to replace SRP. + +* Elliptic Curve Pairings: useful in many interesting protocols. + BN-256 and BLS12-381 seem the most likely. + +* New ASN.1 library + +Some of these features may end being backported to Botan 2 as well. diff --git a/comm/third_party/botan/doc/security.rst b/comm/third_party/botan/doc/security.rst new file mode 100644 index 0000000000..3a2059879c --- /dev/null +++ b/comm/third_party/botan/doc/security.rst @@ -0,0 +1,352 @@ + +.. highlight:: none + +Security Advisories +======================================== + +If you think you have found a security bug in Botan please contact +Jack Lloyd (jack@randombit.net). If you would like to encrypt your +mail please use:: + + pub rsa3072/57123B60 2015-03-23 + Key fingerprint = 4E60 C735 51AF 2188 DF0A 5A62 78E9 8043 5712 3B60 + uid Jack Lloyd + +This key can be found in the file ``doc/pgpkey.txt`` or online at +https://keybase.io/jacklloyd and on most PGP keyservers. + +2020 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* 2020-07-05: Failure to enforce name constraints on alternative names + + The path validation algorithm enforced name constraints on the primary DN + included in the certificate but failed to do so against alternative DNs which + may be included in the subject alternative name. This would allow a corrupted + sub-CA which was constrained by a name constraints extension in its own + certificate to issue a certificate containing a prohibited DN. Until 2.15.0, + there was no API to access these alternative name DNs so it is unlikely that + any application would make incorrect access control decisions on the basis of + the incorrect DN. Reported by Mario Korth of Ruhr-Universität Bochum. + + Introduced in 1.11.29, fixed in 2.15.0 + +* 2020-03-24: Side channel during CBC padding + + The CBC padding operations were not constant time and as a result would leak + the length of the plaintext values which were being padded to an attacker + running a side channel attack via shared resources such as cache or branch + predictor. No information about the contents was leaked, but the length alone + might be used to make inferences about the contents. This issue affects TLS + CBC ciphersuites as well as CBC encryption using PKCS7 or other similar padding + mechanisms. In all cases, the unpadding operations were already constant time + and are not affected. Reported by Maximilian Blochberger of Universität + Hamburg. + + Fixed in 2.14.0, all prior versions affected. + +2018 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* 2018-12-17 (CVE-2018-20187): Side channel during ECC key generation + + A timing side channel during ECC key generation could leak information about + the high bits of the secret scalar. Such information allows an attacker to + perform a brute force attack on the key somewhat more efficiently than they + would otherwise. Found by Ján JanÄár using ECTester. + + Introduced in 1.11.20, fixed in 2.8.0. + +* 2018-06-13 (CVE-2018-12435): ECDSA side channel + + A side channel in the ECDSA signature operation could allow a local attacker + to recover the secret key. Found by Keegan Ryan of NCC Group. + + Bug introduced in 2.5.0, fixed in 2.7.0. The 1.10 branch is not affected. + +* 2018-04-10 (CVE-2018-9860): Memory overread in TLS CBC decryption + + An off by one error in TLS CBC decryption meant that for a particular + malformed ciphertext, the receiver would miscompute a length field and HMAC + exactly 64K bytes of data following the record buffer as if it was part of the + message. This cannot be used to leak information since the MAC comparison will + subsequently fail and the connection will be closed. However it might be used + for denial of service. Found by OSS-Fuzz. + + Bug introduced in 1.11.32, fixed in 2.6.0 + +* 2018-03-29 (CVE-2018-9127): Invalid wildcard match + + RFC 6125 wildcard matching was incorrectly implemented, so that a wildcard + certificate such as ``b*.domain.com`` would match any hosts ``*b*.domain.com`` + instead of just server names beginning with ``b``. The host and certificate + would still have to be in the same domain name. Reported by Fabian Weißberg of + Rohde and Schwarz Cybersecurity. + + Bug introduced in 2.2.0, fixed in 2.5.0 + +2017 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* 2017-10-02 (CVE-2017-14737): Potential side channel using cache information + + In the Montgomery exponentiation code, a table of precomputed values + is used. An attacker able to analyze which cache lines were accessed + (perhaps via an active attack such as Prime+Probe) could recover + information about the exponent. Identified in "CacheD: Identifying + Cache-Based Timing Channels in Production Software" by Wang, Wang, + Liu, Zhang, and Wu (Usenix Security 2017). + + Fixed in 1.10.17 and 2.3.0, all prior versions affected. + +* 2017-07-16: Failure to fully zeroize memory before free + + The secure_allocator type attempts to zeroize memory before freeing it. Due to + a error sometimes only a portion of the memory would be zeroed, because of a + confusion between the number of elements vs the number of bytes that those + elements use. So byte vectors would always be fully zeroed (since the two + notions result in the same value), but for example with an array of 32-bit + integers, only the first 1/4 of the elements would be zeroed before being + deallocated. This may result in information leakage, if an attacker can access + memory on the heap. Reported by Roman Pozlevich. + + Bug introduced in 1.11.10, fixed in 2.2.0 + +* 2017-04-04 (CVE-2017-2801): Incorrect comparison in X.509 DN strings + + Botan's implementation of X.509 name comparisons had a flaw which + could result in an out of bound memory read while processing a + specially formed DN. This could potentially be exploited for + information disclosure or denial of service, or result in incorrect + validation results. Found independently by Aleksandar Nikolic of + Cisco Talos, and OSS-Fuzz automated fuzzing infrastructure. + + Bug introduced in 1.6.0 or earlier, fixed in 2.1.0 and 1.10.16 + +* 2017-03-23 (CVE-2017-7252): Incorrect bcrypt computation + + Botan's implementation of bcrypt password hashing scheme truncated long + passwords at 56 characters, instead of at bcrypt's standard 72 characters + limit. Passwords with lengths between these two bounds could be cracked more + easily than should be the case due to the final password bytes being ignored. + Found and reported by Solar Designer. + + Bug introduced in 1.11.0, fixed in 2.1.0. + +2016 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* 2016-11-27 (CVE-2016-9132) Integer overflow in BER decoder + + While decoding BER length fields, an integer overflow could occur. This could + occur while parsing untrusted inputs such as X.509 certificates. The overflow + does not seem to lead to any obviously exploitable condition, but exploitation + cannot be positively ruled out. Only 32-bit platforms are likely affected; to + cause an overflow on 64-bit the parsed data would have to be many gigabytes. + Bug found by Falko Strenzke, cryptosource GmbH. + + Fixed in 1.10.14 and 1.11.34, all prior versions affected. + +* 2016-10-26 (CVE-2016-8871) OAEP side channel + + A side channel in OAEP decoding could be used to distinguish RSA ciphertexts + that did or did not have a leading 0 byte. For an attacker capable of + precisely measuring the time taken for OAEP decoding, this could be used as an + oracle allowing decryption of arbitrary RSA ciphertexts. Remote exploitation + seems difficult as OAEP decoding is always paired with RSA decryption, which + takes substantially more (and variable) time, and so will tend to mask the + timing channel. This attack does seems well within reach of a local attacker + capable of a cache or branch predictor based side channel attack. Finding, + analysis, and patch by Juraj Somorovsky. + + Introduced in 1.11.29, fixed in 1.11.33 + +* 2016-08-30 (CVE-2016-6878) Undefined behavior in Curve25519 + + On systems without a native 128-bit integer type, the Curve25519 code invoked + undefined behavior. This was known to produce incorrect results on 32-bit ARM + when compiled by Clang. + + Introduced in 1.11.12, fixed in 1.11.31 + +* 2016-08-30 (CVE-2016-6879) Bad result from X509_Certificate::allowed_usage + + If allowed_usage was called with more than one Key_Usage set in the enum + value, the function would return true if *any* of the allowed usages were set, + instead of if *all* of the allowed usages are set. This could be used to + bypass an application key usage check. Credit to Daniel Neus of Rohde & + Schwarz Cybersecurity for finding this issue. + + Introduced in 1.11.0, fixed in 1.11.31 + +* 2016-03-17 (CVE-2016-2849): ECDSA side channel + + ECDSA (and DSA) signature algorithms perform a modular inverse on the + signature nonce `k`. The modular inverse algorithm used had input dependent + loops, and it is possible a side channel attack could recover sufficient + information about the nonce to eventually recover the ECDSA secret key. Found + by Sean Devlin. + + Introduced in 1.7.15, fixed in 1.10.13 and 1.11.29 + +* 2016-03-17 (CVE-2016-2850): Failure to enforce TLS policy + + TLS v1.2 allows negotiating which signature algorithms and hash functions each + side is willing to accept. However received signatures were not actually + checked against the specified policy. This had the effect of allowing a + server to use an MD5 or SHA-1 signature, even though the default policy + prohibits it. The same issue affected client cert authentication. + + The TLS client also failed to verify that the ECC curve the server chose to + use was one which was acceptable by the client policy. + + Introduced in 1.11.0, fixed in 1.11.29 + +* 2016-02-01 (CVE-2016-2196): Overwrite in P-521 reduction + + The P-521 reduction function would overwrite zero to one word + following the allocated block. This could potentially result + in remote code execution or a crash. Found with AFL + + Introduced in 1.11.10, fixed in 1.11.27 + +* 2016-02-01 (CVE-2016-2195): Heap overflow on invalid ECC point + + The PointGFp constructor did not check that the affine coordinate + arguments were less than the prime, but then in curve multiplication + assumed that both arguments if multiplied would fit into an integer + twice the size of the prime. + + The bigint_mul and bigint_sqr functions received the size of the + output buffer, but only used it to dispatch to a faster algorithm in + cases where there was sufficient output space to call an unrolled + multiplication function. + + The result is a heap overflow accessible via ECC point decoding, + which accepted untrusted inputs. This is likely exploitable for + remote code execution. + + On systems which use the mlock pool allocator, it would allow an + attacker to overwrite memory held in secure_vector objects. After + this point the write will hit the guard page at the end of the + mmap'ed region so it probably could not be used for code execution + directly, but would allow overwriting adjacent key material. + + Found by Alex Gaynor fuzzing with AFL + + Introduced in 1.9.18, fixed in 1.11.27 and 1.10.11 + +* 2016-02-01 (CVE-2016-2194): Infinite loop in modular square root algorithm + + The ressol function implements the Tonelli-Shanks algorithm for + finding square roots could be sent into a nearly infinite loop due + to a misplaced conditional check. This could occur if a composite + modulus is provided, as this algorithm is only defined for primes. + This function is exposed to attacker controlled input via the OS2ECP + function during ECC point decompression. Found by AFL + + Introduced in 1.7.15, fixed in 1.11.27 and 1.10.11 + +2015 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* 2015-11-04: TLS certificate authentication bypass + + When the bugs affecting X.509 path validation were fixed in 1.11.22, a check + in Credentials_Manager::verify_certificate_chain was accidentally removed + which caused path validation failures not to be signaled to the TLS layer. So + for affected versions, certificate authentication in TLS is bypassed. As a + workaround, applications can override the call and implement the correct + check. Reported by Florent Le Coz in GH #324 + + Introduced in 1.11.22, fixed in 1.11.24 + +* 2015-10-26 (CVE-2015-7824): Padding oracle attack on TLS + + A padding oracle attack was possible against TLS CBC ciphersuites because if a + certain length check on the packet fields failed, a different alert type than + one used for message authentication failure would be returned to the sender. + This check triggering would leak information about the value of the padding + bytes and could be used to perform iterative decryption. + + As with most such oracle attacks, the danger depends on the underlying + protocol - HTTP servers are particularly vulnerable. The current analysis + suggests that to exploit it an attacker would first have to guess several + bytes of plaintext, but again this is quite possible in many situations + including HTTP. + + Found in a review by Sirrix AG and 3curity GmbH. + + Introduced in 1.11.0, fixed in 1.11.22 + +* 2015-10-26 (CVE-2015-7825): Infinite loop during certificate path validation + + When evaluating a certificate path, if a loop in the certificate chain + was encountered (for instance where C1 certifies C2, which certifies C1) + an infinite loop would occur eventually resulting in memory exhaustion. + Found in a review by Sirrix AG and 3curity GmbH. + + Introduced in 1.11.6, fixed in 1.11.22 + +* 2015-10-26 (CVE-2015-7826): Acceptance of invalid certificate names + + RFC 6125 specifies how to match a X.509v3 certificate against a DNS name + for application usage. + + Otherwise valid certificates using wildcards would be accepted as matching + certain hostnames that should they should not according to RFC 6125. For + example a certificate issued for ``*.example.com`` should match + ``foo.example.com`` but not ``example.com`` or ``bar.foo.example.com``. Previously + Botan would accept such a certificate as also valid for ``bar.foo.example.com``. + + RFC 6125 also requires that when matching a X.509 certificate against a DNS + name, the CN entry is only compared if no subjectAlternativeName entry is + available. Previously X509_Certificate::matches_dns_name would always check + both names. + + Found in a review by Sirrix AG and 3curity GmbH. + + Introduced in 1.11.0, fixed in 1.11.22 + +* 2015-10-26 (CVE-2015-7827): PKCS #1 v1.5 decoding was not constant time + + During RSA decryption, how long decoding of PKCS #1 v1.5 padding took was + input dependent. If these differences could be measured by an attacker, it + could be used to mount a Bleichenbacher million-message attack. PKCS #1 v1.5 + decoding has been rewritten to use a sequence of operations which do not + contain any input-dependent indexes or jumps. Notations for checking constant + time blocks with ctgrind (https://github.com/agl/ctgrind) were added to PKCS + #1 decoding among other areas. Found in a review by Sirrix AG and 3curity GmbH. + + Fixed in 1.11.22 and 1.10.13. Affected all previous versions. + +* 2015-08-03 (CVE-2015-5726): Crash in BER decoder + + The BER decoder would crash due to reading from offset 0 of an empty vector if + it encountered a BIT STRING which did not contain any data at all. This can be + used to easily crash applications reading untrusted ASN.1 data, but does not + seem exploitable for code execution. Found with afl. + + Fixed in 1.11.19 and 1.10.10, affected all previous versions of 1.10 and 1.11 + +* 2015-08-03 (CVE-2015-5727): Excess memory allocation in BER decoder + + The BER decoder would allocate a fairly arbitrary amount of memory in a length + field, even if there was no chance the read request would succeed. This might + cause the process to run out of memory or invoke the OOM killer. Found with afl. + + Fixed in 1.11.19 and 1.10.10, affected all previous versions of 1.10 and 1.11 + +2014 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* 2014-04-10 (CVE-2014-9742): Insufficient randomness in Miller-Rabin primality check + + A bug in the Miller-Rabin primality test resulted in only a single random base + being used instead of a sequence of such bases. This increased the probability + that a non-prime would be accepted by is_prime or that a randomly generated + prime might actually be composite. The probability of a random 1024 bit + number being incorrectly classed as prime with a single base is around 2^-40. + Reported by Jeff Marrison. + + Introduced in 1.8.3, fixed in 1.10.8 and 1.11.9 diff --git a/comm/third_party/botan/doc/side_channels.rst b/comm/third_party/botan/doc/side_channels.rst new file mode 100644 index 0000000000..1f94874f07 --- /dev/null +++ b/comm/third_party/botan/doc/side_channels.rst @@ -0,0 +1,449 @@ +Side Channels +========================= + +Many cryptographic systems can be easily broken by side channels. This document +notes side channel protections which are currently implemented, as well as areas +of the code which are known to be vulnerable to side channels. The latter are +obviously all open for future improvement. + +The following text assumes the reader is already familiar with cryptographic +implementations, side channel attacks, and common countermeasures. + +Modular Exponentiation +------------------------ + +Modular exponentiation uses a fixed window algorithm with Montgomery +representation. A side channel silent table lookup is used to access the +precomputed powers. The caller provides the maximum possible bit length of the +exponent, and the exponent is zero-padded as required. For example, in a DSA +signature with 256-bit q, the caller will specify a maximum length of exponent +of 256 bits, even if the k that was generated was 250 bits. This avoids leaking +the length of the exponent through the number of loop iterations. +See monty_exp.cpp and monty.cpp + +Karatsuba multiplication algorithm avoids any conditional branches; in +cases where different operations must be performed it instead uses masked +operations. See mp_karat.cpp for details. + +The Montgomery reduction is written to run in constant time. +The final reduction is handled with a masked subtraction. See mp_monty.cpp. + +Barrett Reduction +-------------------- + +The Barrett reduction code is written to avoid input dependent branches. The +Barrett algorithm only works for inputs up to a certain size, and larger values +fall back on a different (slower) division algorithm. This secondary algorithm +is also const time, but the branch allows detecting when a value larger than +2^{2k} was reduced, where k is the word length of the modulus. This leaks only +the size of the two values, and not anything else about their value. + +RSA +---------------------- + +Blinding is always used to protect private key operations (there is no way to +turn it off). Both base blinding and exponent blinding are used. + +For base blinding, as an optimization, instead of choosing a new random mask and +inverse with each decryption, both the mask and its inverse are simply squared +to choose the next blinding factor. This is much faster than computing a fresh +value each time, and the additional relation is thought to provide only minimal +useful information for an attacker. Every BOTAN_BLINDING_REINIT_INTERVAL +(default 64) operations, a new starting point is chosen. + +Exponent blinding uses new values for each signature, with 64 bit masks. + +RSA signing uses the CRT optimization, which is much faster but vulnerable to +trivial fault attacks [RsaFault] which can result in the key being entirely +compromised. To protect against this (or any other computational error which +would have the same effect as a fault attack in this case), after every private +key operation the result is checked for consistency with the public key. This +introduces only slight additional overhead and blocks most fault attacks; it is +possible to use a second fault attack to bypass this verification, but such a +double fault attack requires significantly more control on the part of an +attacker than a BellCore style attack, which is possible if any error at all +occurs during either modular exponentiation involved in the RSA signature +operation. + +See blinding.cpp and rsa.cpp. + +If the OpenSSL provider is enabled, then no explicit blinding is done; we assume +OpenSSL handles this. See openssl_rsa.cpp. + +Decryption of PKCS #1 v1.5 Ciphertexts +---------------------------------------- + +This padding scheme is used with RSA, and is very vulnerable to errors. In a +scenario where an attacker can repeatedly present RSA ciphertexts, and a +legitimate key holder will attempt to decrypt each ciphertext and simply +indicates to the attacker if the PKCS padding was valid or not (without +revealing any additional information), the attacker can use this behavior as an +oracle to perform iterative decryption of arbitrary RSA ciphertexts encrypted +under that key. This is the famous million message attack [MillionMsg]. A side +channel such as a difference in time taken to handle valid and invalid RSA +ciphertexts is enough to mount the attack [MillionMsgTiming]. + +As a first step, the PKCS v1.5 decoding operation runs without any +conditional jumps or indexes, with the only variance in runtime being +based on the length of the public modulus, which is public information. + +Preventing the attack in full requires some application level changes. In +protocols which know the expected length of the encrypted key, PK_Decryptor +provides the function `decrypt_or_random` which first generates a random fake +key, then decrypts the presented ciphertext, then in constant time either copies +out the random key or the decrypted plaintext depending on if the ciphertext was +valid or not (valid padding and expected plaintext length). Then in the case of +an attack, the protocol will carry on with a randomly chosen key, which will +presumably cause total failure in a way that does not allow an attacker to +distinguish (via any timing or other side channel, nor any error messages +specific to the one situation vs the other) if the RSA padding was valid or +invalid. + +One very important user of PKCS #1 v1.5 encryption is the TLS protocol. In TLS, +some extra versioning information is embedded in the plaintext message, along +with the key. It turns out that this version information must be treated in an +identical (constant-time) way with the PKCS padding, or again the system is +broken. [VersionOracle]. This is supported by a special version of +PK_Decryptor::decrypt_or_random that additionally allows verifying one or more +content bytes, in addition to the PKCS padding. + +See eme_pkcs.cpp and pubkey.cpp. + +Verification of PKCS #1 v1.5 Signatures +---------------------------------------- + +One way of verifying PKCS #1 v1.5 signature padding is to decode it with an +ASN.1 BER parser. However such a design commonly leads to accepting signatures +besides the (single) valid RSA PKCS #1 v1.5 signature for any given message, +because often the BER parser accepts variations of the encoding which are +actually invalid. It also needlessly exposes the BER parser to untrusted inputs. + +It is safer and simpler to instead re-encode the hash value we are expecting +using the PKCS #1 v1.5 encoding rules, and const time compare our expected +encoding with the output of the RSA operation. So that is what Botan does. + +See emsa_pkcs.cpp. + +OAEP +---------------------- + +RSA OAEP is (PKCS#1 v2) is the recommended version of RSA encoding standard, +because it is not directly vulnerable to Bleichenbacher attack. However, if +implemented incorrectly, a side channel can be presented to an attacker and +create an oracle for decrypting RSA ciphertexts [OaepTiming]. + +This attack is avoided in Botan by making the OAEP decoding operation run +without any conditional jumps or indexes, with the only variance in runtime +coming from the length of the RSA key (which is public information). + +See eme_oaep.cpp. + +ECC point decoding +---------------------- + +The API function OS2ECP, which is used to convert byte strings to ECC points, +verifies that all points satisfy the ECC curve equation. Points that do not +satisfy the equation are invalid, and can sometimes be used to break +protocols ([InvalidCurve] [InvalidCurveTLS]). See point_gfp.cpp. + +ECC scalar multiply +---------------------- + +There are several different implementations of ECC scalar multiplications which +depend on the API invoked. This include ``PointGFp::operator*``, +``EC_Group::blinded_base_point_multiply`` and +``EC_Group::blinded_var_point_multiply``. + +The ``PointGFp::operator*`` implementation uses the Montgomery ladder, which is +fairly resistant to side channels. However it leaks the size of the scalar, +because the loop iterations are bounded by the scalar size. It should not be +used in cases when the scalar is a secret. + +Both ``blinded_base_point_multiply`` and ``blinded_var_point_multiply`` apply +side channel countermeasures. The scalar is masked by a multiple of the group +order (this is commonly called Coron's first countermeasure [CoronDpa]), +currently the mask is an 80 bit random value. + +Botan stores all ECC points in Jacobian representation. This form allows faster +computation by representing points (x,y) as (X,Y,Z) where x=X/Z^2 and +y=Y/Z^3. As the representation is redundant, for any randomly chosen non-zero r, +(X*r^2,Y*r^3,Z*r) is an equivalent point. Changing the point values prevents an +attacker from mounting attacks based on the input point remaining unchanged over +multiple executions. This is commonly called Coron's third countermeasure, see +again [CoronDpa]. + +The base point multiplication algorithm is a comb-like technique which +precomputes ``P^i,(2*P)^i,(3*P)^i`` for all ``i`` in the range of valid scalars. +This means the scalar multiplication involves only point additions and no +doublings, which may help against attacks which rely on distinguishing between +point doublings and point additions. The elements of the table are accessed by +masked lookups, so as not to leak information about bits of the scalar via a +cache side channel. However, whenever 3 sequential bits of the (masked) scalar +are all 0, no operation is performed in that iteration of the loop. This exposes +the scalar multiply to a cache-based side channel attack; scalar blinding is +necessary to prevent this attack from leaking information about the scalar. + +The variable point multiplication algorithm uses a fixed-window algorithm. Since +this is normally invoked using untrusted points (eg during ECDH key exchange) it +randomizes all inputs to prevent attacks which are based on chosen input +points. The table of precomputed multiples is accessed using a masked lookup +which should not leak information about the secret scalar to an attacker who can +mount a cache-based side channel attack. + +See point_gfp.cpp and point_mul.cpp + +ECDH +---------------------- + +ECDH verifies (through its use of OS2ECP) that all input points received from +the other party satisfy the curve equation. This prevents twist attacks. The +same check is performed on the output point, which helps prevent fault attacks. + +ECDSA +---------------------- + +Inversion of the ECDSA nonce k must be done in constant time, as any leak of +even a single bit of the nonce can be sufficient to allow recovering the private +key. In Botan all inverses modulo an odd number are performed using a constant +time algorithm due to Niels Möller. + +x25519 +---------------------- + +The x25519 code is independent of the main Weierstrass form ECC code, instead +based on curve25519-donna-c64.c by Adam Langley. The code seems immune to cache +based side channels. It does make use of integer multiplications; on some old +CPUs these multiplications take variable time and might allow a side channel +attack. This is not considered a problem on modern processors. + +TLS CBC ciphersuites +---------------------- + +The original TLS v1.0 CBC Mac-then-Encrypt mode is vulnerable to an oracle +attack. If an attacker can distinguish padding errors through different error +messages [TlsCbcOracle] or via a side channel attack like [Lucky13], they can +abuse the server as a decryption oracle. + +The side channel protection for Lucky13 follows the approach proposed in the +Lucky13 paper. It is not perfectly constant time, but does hide the padding +oracle in practice. Tools to test TLS CBC decoding are included in the timing +tests. See https://github.com/randombit/botan/pull/675 for more information. + +The Encrypt-then-MAC extension, which completely avoids the side channel, is +implemented and used by default for CBC ciphersuites. + +CBC mode padding +---------------------- + +In theory, any good protocol protects CBC ciphertexts with a MAC. But in +practice, some protocols are not good and cannot be fixed immediately. To avoid +making a bad problem worse, the code to handle decoding CBC ciphertext padding +bytes runs in constant time, depending only on the block size of the cipher. + +AES +---------------------- + +Some x86, ARMv8 and POWER processors support AES instructions which +are fast and are thought to be side channel silent. These instructions +are used when available. + +On CPUs which do not have hardware AES instructions but do support SIMD vectors +with a byte shuffle (including x86's SSSE3, ARM's NEON and PowerPC AltiVec), a +version of AES is implemented which is side channel silent. This implementation +is based on code by Mike Hamburg [VectorAes], see aes_vperm.cpp. + +On all other processors, a constant time bitsliced implementation is used. This +is typically slower than the vector permute implementation, and additionally for +best performance multiple blocks must be processed in parellel. So modes such +as CTR, GCM or XTS are relatively fast, but others such as CBC encryption +suffer. + +GCM +--------------------- + +On platforms that support a carryless multiply instruction (ARMv8 and recent x86), +GCM is fast and constant time. + +On all other platforms, GCM uses an algorithm based on precomputing all powers +of H from 1 to 128. Then for every bit of the input a mask is formed which +allows conditionally adding that power without leaking information via a cache +side channel. There is also an SSSE3 variant of this algorithm which is somewhat +faster on processors which have SSSE3 but no AES-NI instructions. + +OCB +----------------------- + +It is straightforward to implement OCB mode in a efficient way that does not +depend on any secret branches or lookups. See ocb.cpp for the implementation. + +Poly1305 +---------------------- + +The Poly1305 implementation does not have any secret lookups or conditionals. +The code is based on the public domain version by Andrew Moon. + +DES/3DES +---------------------- + +The DES implementation uses table lookups, and is likely vulnerable to side +channel attacks. DES or 3DES should be avoided in new systems. The proper fix +would be a scalar bitsliced implementation, this is not seen as worth the +engineering investment given these algorithms end of life status. + +Twofish +------------------------ + +This algorithm uses table lookups with secret sboxes. No cache-based side +channel attack on Twofish has ever been published, but it is possible nobody +sufficiently skilled has ever tried. + +ChaCha20, Serpent, Threefish, ... +----------------------------------- + +Some algorithms including ChaCha, Salsa, Serpent and Threefish are 'naturally' +silent to cache and timing side channels on all recent processors. + +IDEA +--------------- + +IDEA encryption, decryption, and key schedule are implemented to take constant +time regardless of their inputs. + +Hash Functions +------------------------- + +Most hash functions included in Botan such as MD5, SHA-1, SHA-2, SHA-3, Skein, +and BLAKE2 do not require any input-dependent memory lookups, and so seem to not be +affected by common CPU side channels. However the implementations of Whirlpool +and Streebog use table lookups and probably can be attacked by side channels. + +Memory comparisons +---------------------- + +The function same_mem in header mem_ops.h provides a constant-time comparison +function. It is used when comparing MACs or other secret values. It is also +exposed for application use. + +Memory zeroizing +---------------------- + +There is no way in portable C/C++ to zero out an array before freeing it, in +such a way that it is guaranteed that the compiler will not elide the +'additional' (seemingly unnecessary) writes to zero out the memory. + +The function secure_scrub_memory (in mem_ops.cpp) uses some system specific +trick to zero out an array. If possible an OS provided routine (such as +``RtlSecureZeroMemory`` or ``explicit_bzero``) is used. + +On other platforms, by default the trick of referencing memset through a +volatile function pointer is used. This approach is not guaranteed to work on +all platforms, and currently there is no systematic check of the resulting +binary function that it is compiled as expected. But, it is the best approach +currently known and has been verified to work as expected on common platforms. + +If BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO is set to 0 in build.h (not the default) a +byte at a time loop through a volatile pointer is used to overwrite the array. + +Memory allocation +---------------------- + +Botan's secure_vector type is a std::vector with a custom allocator. The +allocator calls secure_scrub_memory before freeing memory. + +Some operating systems support an API call to lock a range of pages +into memory, such that they will never be swapped out (``mlock`` on POSIX, +``VirtualLock`` on Windows). On many POSIX systems ``mlock`` is only usable by +root, but on Linux, FreeBSD and possibly other systems a small amount +of memory can be locked by processes without extra credentials. + +If available, Botan uses such a region for storing key material. A page-aligned +block of memory is allocated and locked, then the memory is scrubbed before +freeing. This memory pool is used by secure_vector when available. It can be +disabled at runtime setting the environment variable BOTAN_MLOCK_POOL_SIZE to 0. + +Automated Analysis +--------------------- + +Currently the main tool used by the Botan developers for testing for side +channels at runtime is valgrind; valgrind's runtime API is used to taint memory +values, and any jumps or indexes using data derived from these values will cause +a valgrind warning. This technique was first used by Adam Langley in ctgrind. +See header ct_utils.h. + +To check, install valgrind, configure the build with --with-valgrind, and run +the tests. + +.. highlight:: shell + +There is also a test utility built into the command line util, `timing_test`, +which runs an operation on several different inputs many times in order to +detect simple timing differences. The output can be processed using the +Mona timing report library (https://github.com/seecurity/mona-timing-report). +To run a timing report (here for example pow_mod):: + + $ ./botan timing_test pow_mod > pow_mod.raw + +This must be run from a checkout of the source, or otherwise ``--test-data-dir=`` +must be used to point to the expected input files. + +Build and run the Mona report as:: + + $ git clone https://github.com/seecurity/mona-timing-report.git + $ cd mona-timing-report + $ ant + $ java -jar ReportingTool.jar --lowerBound=0.4 --upperBound=0.5 --inputFile=pow_mod.raw --name=PowMod + +This will produce plots and an HTML file in subdirectory starting with +``reports_`` followed by a representation of the current date and time. + +References +--------------- + +[Aes256Sc] Neve, Tiri "On the complexity of side-channel attacks on AES-256" +(https://eprint.iacr.org/2007/318.pdf) + +[AesCacheColl] Bonneau, Mironov "Cache-Collision Timing Attacks Against AES" +(http://www.jbonneau.com/doc/BM06-CHES-aes_cache_timing.pdf) + +[CoronDpa] Coron, +"Resistance against Differential Power Analysis for Elliptic Curve Cryptosystems" +(https://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.1.5695) + +[InvalidCurve] Biehl, Meyer, Müller: Differential fault attacks on +elliptic curve cryptosystems +(https://www.iacr.org/archive/crypto2000/18800131/18800131.pdf) + +[InvalidCurveTLS] Jager, Schwenk, Somorovsky: Practical Invalid Curve +Attacks on TLS-ECDH +(https://www.nds.rub.de/research/publications/ESORICS15/) + +[SafeCurves] Bernstein, Lange: SafeCurves: choosing safe curves for +elliptic-curve cryptography. (https://safecurves.cr.yp.to) + +[Lucky13] AlFardan, Paterson "Lucky Thirteen: Breaking the TLS and DTLS Record Protocols" +(http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) + +[MillionMsg] Bleichenbacher "Chosen Ciphertext Attacks Against Protocols Based +on the RSA Encryption Standard PKCS1" +(https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.8543) + +[MillionMsgTiming] Meyer, Somorovsky, Weiss, Schwenk, Schinzel, Tews: Revisiting +SSL/TLS Implementations: New Bleichenbacher Side Channels and Attacks +(https://www.nds.rub.de/research/publications/mswsst2014-bleichenbacher-usenix14/) + +[OaepTiming] Manger, "A Chosen Ciphertext Attack on RSA Optimal Asymmetric +Encryption Padding (OAEP) as Standardized in PKCS #1 v2.0" +(http://archiv.infsec.ethz.ch/education/fs08/secsem/Manger01.pdf) + +[RsaFault] Boneh, Demillo, Lipton +"On the importance of checking cryptographic protocols for faults" +(https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.9764) + +[RandomMonty] Le, Tan, Tunstall "Randomizing the Montgomery Powering Ladder" +(https://eprint.iacr.org/2015/657) + +[VectorAes] Hamburg, "Accelerating AES with Vector Permute Instructions" +https://shiftleft.org/papers/vector_aes/vector_aes.pdf + +[VersionOracle] Klíma, Pokorný, Rosa "Attacking RSA-based Sessions in SSL/TLS" +(https://eprint.iacr.org/2003/052) diff --git a/comm/third_party/botan/doc/support.rst b/comm/third_party/botan/doc/support.rst new file mode 100644 index 0000000000..7f0ffc2a05 --- /dev/null +++ b/comm/third_party/botan/doc/support.rst @@ -0,0 +1,70 @@ +Support Information +======================= + +Supported Platforms +------------------------ + +For Botan 2, the tier-1 supported platforms are + +* Linux x86-64, GCC 4.8 or higher +* Linux x86-64, Clang 3.5 or higher +* Linux aarch64, GCC 4.8+ +* Linux ppc64le, GCC 4.8+ +* Windows x86-64, Visual C++ 2015 and 2017 + +These platforms are all tested by continuous integration, and the developers +have access to hardware in order to test patches. Problems affecting these +platforms are considered release blockers. + +For Botan 2, the tier-2 supported platforms are + +* Linux x86-32, GCC 4.8+ +* Linux arm32, GCC 4.8+ +* Windows x86-64, MinGW GCC +* macOS x86-64, XCode Clang +* iOS aarch64, XCode Clang +* Android aarch64, NDK Clang +* FreeBSD x86-64, Clang 3.8+ + +Some (but not all) of the tier-2 platforms are tested by CI. Everything should +work, and if problems are encountered, the developers will probably be able to +help. But they are not as carefully tested as tier-1. + +Of course most other modern OSes such as QNX, AIX, OpenBSD, NetBSD, and Solaris +also work just fine. Some are tested occasionally, usually just before a new +release. But very little code specific to these platforms is written by the +primary developers. For example, any functionality in the library which +utilizes OpenBSD specific APIs was likely contributed by someone interested in +that platform. + +In theory any working C++11 compiler is fine but in practice, we only regularly +test with GCC, Clang, and Visual C++. Recent versions of IBM XLC can compile +the library but occasionally codegen bugs occur. Several other compilers (such +as Intel and PGI) are supported by the build system but are not tested by the +developers and may have build or codegen problems. Patches to improve support +for these compilers is welcome. + +Branch Support Status +------------------------- + +Following table provides the support status for Botan branches as of +September 2020. Any branch not listed here (including 1.11) is no +longer supported. Dates in the future are approximate. + +============== ============== ========================== ============ +Branch First Release End of Active Development End of Life +============== ============== ========================== ============ +1.8 2008-12-08 2010-08-31 2016-02-13 +1.10 2011-06-20 2012-07-10 2018-12-31 +2.x 2017-01-06 2020-10-05 2024-01-01 or later +3.x 2021? ? ? +============== ============== ========================== ============ + +"Active development" refers to adding new features and optimizations. At the +conclusion of the active development phase, only bugfixes are applied. + +Getting Help +------------------ + +To get help with Botan, open an issue on +`GitHub `_ diff --git a/comm/third_party/botan/license.txt b/comm/third_party/botan/license.txt new file mode 100644 index 0000000000..f586fb88f0 --- /dev/null +++ b/comm/third_party/botan/license.txt @@ -0,0 +1,24 @@ +Copyright (C) 1999-2020 The Botan Authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/comm/third_party/botan/moz.build b/comm/third_party/botan/moz.build new file mode 100644 index 0000000000..93692a6b2b --- /dev/null +++ b/comm/third_party/botan/moz.build @@ -0,0 +1,14 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library("botan") +FINAL_LIBRARY = "rnp" + +# Honor --with-system-botan +if CONFIG["MZLA_SYSTEM_BOTAN"]: + OS_LIBS += CONFIG["MZLA_BOTAN_LIBS"] +else: + include("./botan.mozbuild") diff --git a/comm/third_party/botan/news.rst b/comm/third_party/botan/news.rst new file mode 100644 index 0000000000..7da4db1890 --- /dev/null +++ b/comm/third_party/botan/news.rst @@ -0,0 +1,1879 @@ +Release Notes +======================================== + +Version 2.18.2, 2021-10-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Avoid using short exponents when encrypting in ElGamal, as some PGP + implementations generate keys with parameters that are weak when + short exponents are used (GH #2794) + +* Fix a low risk OAEP decryption side channel (GH #2797) + +* Work around a miscompilation of SHA-3 caused by a bug in Clang 12 + and XCode 13. (GH #2826) + +* Remove support in OpenSSL provider for algorithms which are + disabled by default in OpenSSL 3.0 (GH #2823, #2814) + +* Add CI based on GitHub actions to replace Travis CI (GH #2632) + +* Fix the online OCSP test, as the certificate involved had expired. + (GH #2799) + +* Fix some test failures induced by the expiration of the trust root + "DST Root CA X3" (GH #2820) + +Version 2.18.1, 2021-05-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a build regression in 2.18.0 which caused linker flags which + contain ``-l`` within them (such as ``-fuse-linker-plugin``) to + be misinterpreted. (GH #2715) + +* Fix a bug which caused decoding a certificate which contained + more than one name in a single RDN. (GH #2611 #2630 #2724) + +* Fix a bug which caused OID lookup failures when run in a locale + which uses thousands separators (pt_BR was reported as having + this issue). (GH #2732 #2730 #2237) + +* DNS names in name constraints were compared with case sensitivity, which + could cause valid certificates to be rejected. (GH #2739 #2735) + +* X.509 name constraint extensions were rejected if non-critical. RFC 5280 + requires conforming CAs issue such extensions as critical, but not all + certificates are compliant, and all other known implementations do not + require this. (GH #2739 #2736) + +* X.509 name constraints were incorrectly applied to the certificate which + included the constraint. (GH #2739 #2737) + +Version 2.18.0, 2021-04-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for implementing custom RNG objects through the + FFI interface (GH #2627 #2600) + +* Improve safegcd bounds, improving runtime performance (GH #2628 #2619) + +* Fix a bug introduced in 2.9.0 where BigInt::operator< would return + an incorrect result if both operands were negative. (GH #2641 #2638) + +* Reject non-TLS messages as quickly as possible without waiting for + a full record. (GH #2676) + +* Add build support for RISC-V 32 + +* Fixes for TLS::Stream::async_shutdown (GH #2673) + +* Fix a regression introduced in 2.17.0 where LDFLAGS which add an extra + library (such as ``-latomic`` needed on SPARC) were not always applied + effectively. (GH #2622 #2623 #2625) + +Version 2.17.3, 2020-12-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CVE-2021-24115 Change base64, base58, base32, and hex encoding and + decoding operations to run in constant time (GH #2549) + +* Fix a build problem on PPC64 building with Clang (GH #2547) + +* Fix an install problem introduced in 2.17.2 affecting MSVC 2015 + +* Fix use of -L flag in linking when configured using ``--with-external-libdir`` + (GH #2496) + +* Fix a build problem on big-endian PowerPC related to VSX instructions + in the AES code. (GH #2515) + +Version 2.17.2, 2020-11-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix an build problem on ppc64 introduced with certain recent + versions of GCC or binutils where using the DARN instruction + requires using an appropriate -mcpu flag to enable the instruction + in the assembler. (GH #2481 2463) + +* Resolve an issue in the modular square root algorithm where a loop + to find a quadratic non-residue could, for a carefully chosen + composite modulus, not terminate in a timely manner. (GH #2482 #2476) + +* Fix a regression in MinGW builds introduced in 2.17.1 + +Version 2.17.1, 2020-11-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a build problem that could occur if Python was not in the PATH. + This was known to occur on some installations of macOS. + +* Re-enable support for the x86 CLMUL instruction on Visual C++, which was + accidentally disabled starting in 2.12.0. (GH #2460) + +Version 2.17.0, 2020-11-05 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug in ECDSA which could occur when the group size and hash length + differ. In this case, on occasion the generated signature would not be + accepted by other ECDSA implementations. This was particularly likely to + affect users of 160-bit or 239-bit curves. (GH #2433 #2415) + +* Fix a bug in ECDSA verification when the public key was chosen to be + a small multiple of the group generator. In that case, verification + would fail even if the signature was actually valid. (GH #2425) + +* SIV's functionality of supporting multiple associated data inputs has been + generalized onto the AEAD_Mode interface. However at the moment SIV is the + only AEAD implemented which supports more than one AD. (GH #2440) + +* The contents of ASN.1 headers ``asn1_str.h``, ``asn1_time.h``, ``asn1_oid.h`` + and ``alg_id.h`` have been moved to ``asn1_obj.h``. The header files remain + but simply forward the include to ``asn1_obj.h``. These now-empty header files + are deprecated, and will be removed in a future major release. (GH #2441) + +* The contents of X.509/PKIX headers ``asn1_attribute.h`` ``asn1_alt_name.h`` + ``name_constraint.h`` ``x509_dn.h`` ``cert_status.h`` and ``key_constraint.h`` + have been merged into ``pkix_enums.h`` (for enumerations) and ``pkix_types.h`` + (for all other definitions). The previous header files remain but simply + forward the include to the new header containing the definition. These + now-empty header files are deprecated, and will be removed in a future major + release. (GH #2441) + +* A number of other headers including those related to HOTP/TOTP, XMSS, + PKCS11, PSK_DB have also been merged. Any now deprecated/empty headers + simply include the new header and issue a deprecation warning. + (GH #2443 #2446 #2447 2448 #2449) + +* Small optimizations in the non-hardware assisted AES key generation + code path (GH #2417 #2418) + +* Move the GHASH code to a new module in utils, making it possible + to build GMAC support without requiring GCM (GH #2416) + +* Add more detection logic for AVX-512 features (GH #2430) + +* Avoid std::is_pod which is deprecated in C++20 (GH #2429) + +* Fix a bug parsing deeply nested cipher names (GH #2426) + +* Add support for ``aarch64_be`` target CPU (GH #2422) + +* Fix order of linker flags so they are always applied effectively (GH #2420) + +* Prevent requesting DER encoding of signatures when the algorithm + did not support it (GH #2419) + +Version 2.16.0, 2020-10-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Now userspace PRNG objects (such as AutoSeeded_RNG and HMAC_DRBG) + use an internal lock, which allows safe concurrent use. This however + is purely a precaution in case of accidental sharing of such RNG + objects; for performance reasons it is always preferable to use + a RNG per thread if a userspace RNG is needed. (GH #2399) + +* DL_Group and EC_Group objects now track if they were created from a + known trusted group (such as P-256 or an IPsec DH parameter). If + so, then verification tests can be relaxed, as compared to + parameters which may have been maliciously constructed in order to + pass primality checks. (GH #2409) + +* RandomNumberGenerator::add_entropy_T assumed its input was a POD + type but did not verify this. (GH #2403) + +* Support OCSP responders that live on a non-standard port (GH #2401) + +* Add support for Solaris sandbox (GH #2385) + +* Support suffixes on release numbers for alpha/beta releases (GH #2404) + +* Fix a bug in EAX which allowed requesting a 0 length tag, which had + the effect of using a full length tag. Instead omit the length field, + or request the full tag length explicitly. (GH #2392 #2390) + +* Fix a memory leak in GCM where if passed an unsuitable block cipher + (eg not 128 bit) it would throw an exception and leak the cipher + object. (GH #2392 #2388) + +Version 2.15.0, 2020-07-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug where the name constraint extension did not constrain the + alternative DN field which can be included in a subject alternative name. This + would allow a corrupted sub-CA which was otherwise constrained by a name + constraint to issue a certificate with a prohibited DN. + +* Fix a bug in the TLS server during client authentication where where + if a (disabled by default) static RSA ciphersuite was selected, then + no certificate request would be sent. This would have an equivalent + effect to a client which simply replied with an empty Certificate + message. (GH #2367) + +* Replace the T-Tables implementation of AES with a 32-bit bitsliced + version. As a result AES is now constant time on all processors. + (GH #2346 #2348 #2353 #2329 #2355) + +* In TLS, enforce that the key usage given in the server certificate + allows the operation being performed in the ciphersuite. (GH #2367) + +* In X.509 certificates, verify that the algorithm parameters are + the expected NULL or empty. (GH #2367) + +* Change the HMAC key schedule to attempt to reduce the information + leaked from the key schedule with regards to the length of the key, + as this is at times (as for example in PBKDF2) sensitive information. + (GH #2362) + +* Add Processor_RNG which wraps RDRAND or the POWER DARN RNG + instructions. The previous RDRAND_RNG interface is deprecated. + (GH #2352) + +* The documentation claimed that mlocked pages were created with a + guard page both before and after. However only a trailing guard page + was used. Add a leading guard page. (GH #2334) + +* Add support for generating and verifying DER-encoded ECDSA signatures + in the C and Python interfaces. (GH #2357 #2356) + +* Workaround a bug in GCC's UbSan which triggered on a code sequence + in XMSS (GH #2322) + +* When building documentation using Sphinx avoid parallel builds with + version 3.0 due to a bug in that version (GH #2326 #2324) + +* Fix a memory leak in the CommonCrypto block cipher calls (GH #2371) + +* Fix a flaky test that would occasionally fail when running the tests + with a large number of threads. (GH #2325 #2197) + +* Additional algorithms are now deprecated: XTEA, GOST, and Tiger. + They will be removed in a future major release. + +Version 2.14.0, 2020-04-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for using POWER8+ VPSUMD instruction to accelerate GCM + (GH #2247) + +* Optimize the vector permute AES implementation, especially improving + performance on ARMv7, Aarch64, and POWER. (GH #2243) + +* Use a new algorithm for modular inversions which is both faster and + more resistant to side channel attacks. (GH #2287 #2296 #2301) + +* Address an issue in CBC padding which would leak the length of the + plaintext which was being padded. Unpadding during decryption was + not affected. Thanks to Maximilian Blochberger for reporting this. + (GH #2312) + +* Optimize NIST prime field reductions, improving ECDSA by 3-9% (GH #2295) + +* Increase the size of the ECC blinding mask and scale it based on the + size of the group order. (GH #880 #893 #2308) + +* Add server side support for the TLS asio wrapper. (GH #2229) + +* Add support for using Windows certificate store on MinGW (GH #2280) + +* Use the library thread pool instead of a new thread for RSA computations, + improving signature performance by up to 20%. (GH #2257) + +* Precompute and cache additional fields in ``X509_Certificate`` (GH #2250) + +* Add a CLI utility ``cpu_clock`` which estimates the speed of the + processor cycle counter. (GH #2251) + +* Fix a bug which prevented using DER-encoded ECDSA signatures with a PKCS11 + key (GH #2293) + +* Enable use of raw block ciphers from CommonCrypto (GH #2278) + +* Support for splitting up the amalgamation file by ABI extension has + been removed. Instead only ``botan_all.cpp`` and ``botan_all.h`` are + generated. (GH #2246) + +* Improve support for baremetal systems with no underlying OS, with + target OS ``none`` (GH #2303 #2304 #2305) + +* The build system now avoids using ``-rpath=$ORIGIN`` or (on macOS) + install_name which allowed running the tests from the build + directory without setting ``LD_LIBRARY_PATH``/``DYLD_LIBRARY_PATH`` + environment variables. Instead set the dynamic linker variables + appropriately, or use ``make check``. (GH #2294 #2302) + +* Add new option ``--name-amalgamation`` which allows naming the + amalgamation output, instead of the default ``botan_all``. (GH #2246) + +* Avoid using symbolic links on Windows (GH #2288 #2286 #2285) + +* Fix a bug that prevented compilation of the amalgamation on ARM and + POWER processors (GH #2245 #2241) + +* Fix some build problems under Intel C++ (GH #2260) + +* Remove use of Toolhelp Windows library, which was known to trigger + false positives under some antivirus systems. (GH #2261) + +* Fix a compilation problem when building on Windows in Unicode mode. + Add Unicode build to CI to prevent regressions. (GH #2254 #2256) + +* Work around a GCC bug affecting old libc (GH #2235) + +* Workaround a bug in macOS 10.15 which caused a test to crash. + (GH #2279 #2268) + +* Avoid a crash in PKCS8::load_key due to a bug in Clang 8. + (GH #2277) + +Version 2.13.0, 2020-01-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Roughtime client (GH #2143 #1842) + +* Add support for XMSS X.509 certificates (GH #2172) + +* Add support for X.509 CRLs in FFI layer and Python wrapper (GH #2213) + +* It is now possible to disable TLS v1.0/v1.1 and DTLS v1.0 at build time. + (GH #2188) + +* The format of encrypted TLS sessions has changed, which will invalidate all + existing session tickets. The new format will make it easier to support ticket + key rotation in the future. (GH #2225) + +* Improve RSA key generation performance (GH #2148) + +* Make gcd computation constant-time (GH #2147) + +* Add AVX2 implementation of SHACAL2 (GH #2196) + +* Update BSI policy to reflect 2019 update of TR 02102-2 (GH #2195) + +* Support more functionality for X.509 in the Python API (GH #2165) + +* Add ``generic`` CPU target useful when building for some new or unusual + platform. + +* Disable MD5 in BSI or NIST modes (GH #2188) + +* Disable stack protector on MinGW as it causes crashes with some recent + versions. (GH #2187) + +* On Windows the DLL is now installed into the binary directory (GH #2233) + +* Previously Windows required an explicit ``.lib`` suffix be added when + providing an explicit library name, as is used for example for Boost. + Now the ``.lib`` suffix is implicit, and should be omitted. + +* Remove the 32-bit x86 inline asm for Visual C++ as it seemed to not offer + much in the way of improved performance. (GH #2204 #256) + +* Resolve all compile time warnings generated by GCC, Clang and MSVC. + Modify CI to compile with warnings-as-errors. (GH #2170 #2206 #2211 #2212) + +* Fix bugs linking to 3rd party libraries on Windows due to invalid + link specifiers. (GH #2210 #2215) + +* Add long input and NIST Monte-Carlo hash function tests. + +* Fix a bug introduced in 2.12.0 where ``TLS::Channel::is_active`` and + ``TLS::Channel::is_closed`` could simultaneously return true. + (GH #2174 #2171) + +* Use ``std::shared_ptr`` instead of ``boost::shared_ptr`` in some examples. + (GH #2155) + +Version 2.12.1, 2019-10-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug that prevented building with nmake (GH #2142 #2141) + +* Fix an issue where make install would attempt to build targets which + were disabled. (GH #2140) + +* If the option ``--without-documentation`` is used, avoid invoking the + documentation build script. (GH #2138) + +* Fix a bug that prevented compilation on x86-32 using GCC 4.9 (GH #2139) + +* Fix a bug in CCM encryption, where it was possible to call ``finish`` without + ever setting a nonce (GH #2151 #2150) + +* Improve ECIES/DLIES interfaces. If no initialization vector was set, they + would typically produce hard to understand exceptions. (GH #2151 #2150) + +Version 2.12.0, 2019-10-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Many currently public headers are being deprecated. If any such header is + included by an application, a warning is issued at compile time. Headers + issuing this warning will be made internal in a future major release. + (GH #2061) + +* RSA signature performance improvements (GH #2068 #2070) + +* Performance improvements for GCM (GH #2024 #2099 #2119), OCB (#2122), + XTS (#2123) and ChaCha20Poly1305 (GH #2117), especially for small messages. + +* Add support for constant time AES using NEON and AltiVec (GH #2093 #2095 #2100) + +* Improve performance of POWER8 AES instructions (GH #2096) + +* Add support for the POWER9 hardware random number generator (GH #2026) + +* Add support for 64-bit version of RDRAND, doubling performance on x86-64 (GH #934 #2022) + +* In DTLS server, support a client crashing and then reconnecting from + the same source port, as described in RFC 6347 sec 4.2.8 (GH #2029) + +* Optimize DTLS MTU splitting to split precisely to the set MTU (GH #2042) + +* Add support for the TLS v1.3 downgrade indicator. (GH #2027) + +* Improve the error messages generated when an invalid TLS state transition occurs + (GH #2030) + +* Fix some edge cases around TLS close_notify support. (GH #2054) + +* Modifications to support GOST 34.10-2012 signatures (GH #2055 #2056 #1860 #1897) + +* Add some new APIs on ``OID`` objects (GH #2057) + +* Properly decode OCSP responses which indicate an error (GH #2110) + +* Add a function to remove an X.509 extension from an Extensions object. + (GH #2101 #2073 #2065) + +* Support Argon2 outputs longer than 64 bytes (GH #2079 #2078) + +* Correct a bug in CAST-128 which caused incorrect computation using + 11, 13, 14, or 15 byte keys. (GH #2081) + +* Fix a bug which would cause Streebog to produce incorrect outputs for + certain messages (GH #2082 #2083) + +* Fix a bug that prevented loading EC points with an affine x or y + value of 0. For certain curves such points can exist. (GH #2102) + +* Fix a bug which would cause PBKDF2 to go into a very long loop if + it was requested to use an iteration count of 0. (GH #2090 #2088) + +* The BearSSL provider has been removed (GH #2020) + +* Add a new ``entropy`` cli which allows sampling the output of the entropy sources. + +* Add new ``base32_enc`` and ``base32_dec`` cli for base32 encoding operations. (GH #2111) + +* Support setting TLS policies in CLIs like ``tls_client`` and ``tls_proxy_server`` (GH #2047) + +* The tests now run in multithreaded mode by default. Provide option ``--test-threads=1`` to + return to previous single-threaded behavior. (GH #2071 #2075) + +* Cleanups in TLS record layer (GH #2021) + +* Fix typos in some OCSP enums which used "OSCP" instead. (GH #2048) + +* In the Python module, avoid trying to load DLLs for names that don't match the current + platform (GH #2062 #2059) + +* In the Python module, also look for ``botan.dll`` so Python wrapper can run on Windows. + (GH #2059 #2060) + +* Add support for TOTP algorithm to the Python module. (GH #2112) + +* Now the minimum Windows target is set to Windows 7 (GH #2036 #2028) + +* Add ``BOTAN_FORCE_INLINE`` macro to resolve a performance issue with BLAKE2b on MSVC + (GH #2092 #2089) + +* Avoid using ``__GNUG__`` in headers that may be consumed by a C compiler (GH #2013) + +* Improve the PKCS11 tests (GH #2115) + +* Fix a warning from Klocwork (GH #2128 #2129) + +* Fix a bug which caused amalgamation builds to fail on iOS (GH #2045) + +* Support disabling thread local storage, needed for building on old iOS (GH #2045) + +* Add a script to help with building for Android, using Docker (GH #2016 #2033 #513) + +* Add Android NDK build to Travis CI (GH #2017) + +Version 2.11.0, 2019-07-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Argon2 PBKDF and password hash (GH #459 #1981 #1987) + +* Add Bcrypt-PBKDF (GH #1990) + +* Add a libsodium compat layer in sodium.h (GH #1996) + +* XMSS now follows RFC 8391 which is incompatible with previous versions, which + had followed draft 6. (GH #1858 #2003) + +* Add server side support for issuing DTLS HelloVerifyRequest messages + (GH #1999) + +* Add a shim allowing testing Botan against the BoringSSL test suite, + and fix a number of bugs in TLS found using it. + (GH #1954 #1955 #1956 #1959 #1966 #1970) + +* Add support for the TLS v1.3 supported_versions extension. (GH #1976) + +* Add Ed25519ph compatible with RFC 8032 (GH #1699 #2000) + +* Add support for OCSP stapling on server side. (GH #1703 #1967) + +* Add a ``boost::asio`` TLS stream compatible with ``boost::asio::ssl``. + (GH #1839 #1927 #1992) + +* Add a certificate store for Linux/Unix systems. (GH #1885 #1936) + +* Add a certificate store for Windows systems. (GH #1931) + +* Add a generic ``System_Certificate_Store`` which wraps Windows, macOS, + and Linux certificate stores. (GH #1893) + +* Fix verification rooted in a v1 certificate which previously would fail. + (GH #1890) + +* Add ability to specify the maximum age of an OCSP response which does not + have the nextUpdate field set. (GH #1974 #1995) + +* Fix X509_DN::operator< which could erroneously return true in both + directions (ie, DN1 < DN2 && DN2 < DN1). This would break STL + containers using a DN as the key. (GH #1938) + +* It is now possible to create intermediate CA certificates using the + command line interface. (GH #1879 #1889) + +* Add a new build time option to set where the system stores trusted + certificates. (GH #1888) + +* New ``trust_roots`` CLI that examines the system certificate store. + (GH #1893) + +* Fix bugs and add many new features in the Python wrapper. + (GH #1899 #1900 #1901 #1902 #1903 #1904 #1906 #1907 #1915) + +* Various FFI interfaces which are redundant with other APIs are now + deprecated. The deprecation message suggests the alternate API to use. + (GH #1915) + +* Fix decoding of RSA-OAEP certificates. (GH #1943 #1944) + +* Allow setting multiple organization unit fields in a certificate or + certificate request. (GH #1939) + +* Increase the maximum allowed year in ASN1_Time to 3100. This works + around a problem parsing certs in AppVeyor's trust store. + +* Add ``--format`` option to ``rng`` CLI command allowing to format + as base64, base58 or binary in addition to hex. (GH #1945) + +* Remove use of table lookups for IP/FP transforms in DES (GH #1928) + +* Improve the tests for SRP6 (GH #1917 #1923) + +* Document the build system + +* When available use POSIX ``sysconf`` to detect the number of CPUs (GH #1877) + +* Add functionality to handle Boost naming conventions on different platforms, + especially affecting Windows. Enable Boost in AppVeyor builds. (GH #1964) + +* Add alternate implementation of ``getauxval`` for older Android (GH #1962) + +* Add ``configure.py`` option allowing to set arbitrary macros during build. + (GH #1960) + +* Use FreeBSD's ``elf_aux_info`` to detect ARM and POWER CPU features + (GH #1895) + +* Use FreeBSD's ``PROT_MAX`` to prevent mmap regions from being made executable + later. (GH #2001) + +* Fix a memory leak in the tests (GH #1886) + +* Fix an issue building with the new Boost 1.70 (GH #1881 #1880) + +* Fix an issue with UbSan in the tests (GH #1892) + +* Remove use of ``-mabi`` flag when building on MIPS64 (GH #1918) + +* Make it possible to specify additional libraries in ``LDFLAGS`` (GH #1916) + +* Fix some warnings from Clang 8 (GH #1941) + +* Fix the makefile .PHONY syntax (GH #1874) + +* Fix build issue with SoftHSM 2.5.0 (GH #1986) + +Version 2.10.0, 2019-03-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Notice: the developers plan to switch from gzip to xz compression for + releases starting in 2.11. If this is a problem please comment at + https://github.com/randombit/botan/issues/1872 + +* Warning: XMSS currently implements draft-06 which is not compatible with the + final RFC 8391 specification. A PR is open to fix this, however it will break + all current uses of XMSS. If you are currently using XMSS please comment at + https://github.com/randombit/botan/pull/1858. Otherwise the PR will be merged + and support for draft-06 will be removed starting in 2.11. + +* Added a new certificate store implementation that can access the + MacOS keychain certificate store. (GH #1830) + +* Redesigned ``Memory_Pool`` class, which services allocations out of a + set of pages locked into memory (using ``mlock``/``VirtualLock``). It is now + faster and with improved exploit mitigations. (GH #1800) + +* Add BMI2 implementations of SHA-512 and SHA-3 which improve performance by + 25-35% on common CPUs. (GH #1815) + +* Unroll SHA-3 computation improving performance by 10-12% (GH #1838) + +* Add a ``Thread_Pool`` class. It is now possible to run the tests in multiple + threads with ``--test-threads=N`` flag to select the number of threads to use. + Use ``--test-threads=0`` to run with as many CPU cores as are available on the + current system. The default remains single threaded. (GH #1819) + +* XMSS signatures now uses a global thread pool instead of spawning new threads + for each usage. This improves signature generation performance by between 10% + and 60% depending on architecture and core count. (GH #1864) + +* Some functions related to encoding and decoding BigInts have been deprecated. + (GH #1817) + +* Binary encoding and decoding of BigInts has been optimized by performing + word-size operations when possible. (GH #1817) + +* Rename the exception ``Integrity_Failure`` to ``Invalid_Authentication_Tag`` to make + its meaning and usage more clear. The old name remains as a typedef. (GH #1816) + +* Support for using Boost ``filesystem`` and MSVC's ``std::filesystem`` have been + removed, since already POSIX and Win32 versions had to be maintained for + portability. (GH #1814) + +* Newly generated McEliece and XMSS keys now default to being encrypted using + SIV mode, support for which was added in 2.8.0. Previously GCM was used by + default for these algorithms. + +* Use ``arc4random`` on Android systems (GH #1851) + +* Fix the encoding of PGP-S2K iteration counts (GH #1853 #1854) + +* Add a facility for sandboxing the command line util. Currently FreeBSD + (Capsicum) and OpenBSD (``pledge``) sandboxes are supported. (GH #1808) + +* Use ``if constexpr`` when available. + +* Disable building shared libs on iOS as it was broken and it is not clear shared + libraries are ever useful on iOS (GH #1865) + +* Renamed the ``darwin`` build target to ``macos``. This should not cause any + user-visible change. (GH #1866) + +* Add support for using ``sccache`` to cache the Windows CI build (GH #1807) + +* Add ``--extra-cxxflags`` option which allows adding compilation flags without + overriding the default set. (GH #1826) + +* Add ``--format=`` option to the ``hash`` cli which allows formatting the output + as base64 or base58, default output remains hex. + +* Add ``base58_enc`` and ``base58_dec`` cli utils for base58 encoding/decoding. + (GH #1848) + +* Enable ``getentropy`` by default on macOS (GH #1862) + +* Avoid using ``-momit-leaf-frame-pointer`` flags, since ``-fomit-frame-pointer`` + is already the default with recent versions of GCC. + +* Fix XLC sanitizer flags. + +* Rename ``Blake2b`` class to ``BLAKE2b`` to match the official name. There is + a typedef for compat. + +* Fix a bug where loading a raw ``Ed25519_PublicKey`` of incorrect length would + lead to a crash. (GH #1850) + +* Fix a bug that caused compilation problems using CryptoNG PRNG. (GH #1832) + +* Extended SHAKE-128 cipher to support any key between 1 and 160 bytes, instead + of only multiples of 8 bytes. + +* Minor HMAC optimizations. + +* Build fixes for GNU/Hurd. + +* Fix a bug that prevented generating or verifying Ed25519 signatures in the CLI + (GH #1828 #1829) + +* Fix a compilation error when building the amalgamation outside of the original + source directory when AVX2 was enabled. (GH #1812) + +* Fix a crash when creating the amalgamation if a header file was edited on + Windows but then the amalgamation was built on Linux (GH #1763) + +Version 2.9.0, 2019-01-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CVE-2018-20187 Address a side channel during ECC key generation, + which used an unblinded Montgomery ladder. As a result, a timing + attack can reveal information about the high bits of the secret key. + +* Fix bugs in TLS which caused negotiation failures when the client + used an unknown signature algorithm or version (GH #1711 #1709 #1708) + +* Fix bug affecting GCM, EAX and ChaCha20Poly1305 where if the associated data + was set after starting a message, the new AD was not reflected in the produced + tag. Now with these modes setting an AD after beginning a message throws an + exception. + +* Use a smaller sieve which improves performance of prime generation. + +* Fixed a bug that caused ChaCha to produce incorrect output after encrypting + 256 GB. (GH #1728) + +* Add NEON and AltiVec implementations of ChaCha (GH #1719 #1728 #1729) + +* Optimize AVX2 ChaCha (GH #1730) + +* Many more operations in BigInt, ECC and RSA code paths are either fully const time + or avoid problematic branches that could potentially be exploited in a side + channel attack. (GH #1738 #1750 #1754 #1755 #1757 #1758 #1759 #1762 #1765 + #1770 #1773 #1774 #1779 #1780 #1794 #1795 #1796 #1797) + +* Several optimizations for BigInt and ECC, improving ECDSA performance by as + much as 30%. (GH #1734 #1737 #1777 #1750 #1737 #1788) + +* Support recovering an ECDSA public key from a message/signature pair (GH #664 #1784) + +* Add base58 encoding/decoding functions (GH #1783) + +* In the command line interface, add support for reading passphrases from the + terminal with echo disabled (GH #1756) + +* Add ``CT::Mask`` type to simplify const-time programming (GH #1751) + +* Add new configure options ``--disable-bmi2``, ``--disable-rdrand``, + and ``--disable-rdseed`` to prevent use of those instruction sets. + +* Add ``error_type`` and ``error_code`` functions to Exception type (GH #1744) + +* Now on POSIX systems ``posix_memalign`` is used instead of ``mmap`` for + allocating the page-locked memory pool. This avoids issues with ``fork``. + (GH #602 #1798) + +* When available, use RDRAND to generate the additional data in + ``Stateful_RNG::randomize_with_ts_input`` + +* Use vzeroall/vzeroupper intrinsics to avoid AVX2/SSE transition penalties. + +* Support for Visual C++ 2013 has been removed (GH #1557 #1697) + +* Resolve a memory leak when verifying ECDSA signatures with versions + of OpenSSL before 1.1.0 (GH #1698) + +* Resolve a memory leak using ECDH via OpenSSL (GH #1767) + +* Fix an error in XTS which prohibited encrypting values which were + exactly the same length as the underlying block size. Messages of + this size are allowed by the standard and other XTS implementations. + (GH #1706) + +* Resolve a bug in TSS which resulted in it using an incorrect length + field in the shares. Now the correct length is encoded, but either + correct or buggy lengths are accepted when decoding. (GH #1722) + +* Correct a bug when reducing a negative ``BigInt`` modulo a small power of 2. + (GH #1755) + +* Add CLI utils for threshold secret splitting. (GH #1722) + +* Fix a bug introduced in 2.8.0 that caused compilation failure if using + a single amalgamation file with AVX2 enabled. (GH #1700) + +* Add an explicit OS target for Emscripten and improve support for it. + (GH #1702) + +* Fix small issues when building for QNX + +* Switch the Travis CI build to using Ubuntu 16.04 (GH #1767) + +* Add options to ``configure.py`` to disable generation of ``pkg-config`` + file, and (for systems where ``pkg-config`` support defaults to off, + like Windows), to enable generating it. (GH #1268) + +* Modify ``configure.py`` to accept empty lists or trailing/extra commas. + (GH #1705) + +Version 2.8.0, 2018-10-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for using Apple CommonCrypto library for hashing (GH #1667), + cipher modes (GH #1674) and block ciphers (GH #1673). + +* Support for negotiating TLS versions 1.0 and 1.1 is disabled in the default + TLS policy. In addition, support for negotiating TLS ciphersuites using CBC or + CCM mode is disabled by default. Applications which need to interop with old + peers must enable these in their TLS policy object. (GH #1651) + +* During primality testing, use a Lucas test in addition to Miller-Rabin. It is + possible to construct a composite integer which passes n Miller-Rabin tests + with probability (1/4)^n. So for a incautious verifier using a small number + of tests (under 16 or so) it is possible if unlikely they would accept such a + composite as prime. Adding a Lucas test precludes such an attack. (GH #1636) + +* Add XChaCha and XChaCha20Poly1305 (GH #1640) + +* Add AVX2 implementations of ChaCha (GH #1662) and Serpent (GH #1660) + +* Add a new password hashing interface in pwdhash.h (GH #1670) + +* C binding improvements. Added functions to get name and supported + keylengths of cipher, hash and MAC objects, support for FE1 format + preserving encryption (GH #1625 #1646), functions to load and save + RSA keys in PKCS #1 format (GH #1621), HOTP and TOTP algorithms, + scrypt, certificate verification (GH #1647), functions to get the + output length of public key operations (GH #1642), and functions for + loading and serializing X25519 keys (GH #1681) + +* Support for building with BOTAN_MP_WORD_BITS set to 8 or 16 has been removed. + +* Previously SM2 had two distinct key types, one for signatures and another for + encryption. They have now been merged into a single key type since in practice + it seems the same key is at times used for both operations. (GH #1637) + +* The ``Cipher_Mode`` class now derives from ``SymmetricAlgorithm`` (GH #1639) + +* Add support for using the ARMv8 instructions for SM4 encryption (GH #1622) + +* The entropy source using ``SecRandomCopyBytes`` has been removed as it was + redundant with other entropy sources (GH #1668) + +* The Python module has much better error checking and reporting, and offers new + functionality such as scrypt, MPI and FPE. (GH #1643 #1646) + +* Fixed a bug that caused CCM to fail with an exception when used with L=8 + (GH #1631 #1632) + +* The default bcrypt work factor has been increased from 10 to 12. + +* The default algorithm used in passhash9 has changed from SHA-256 to SHA-512, + and the default work factor increased from 10 to 15. + +* In ECC private keys, include the public key data for compatibility with + GnuTLS (GH #1634 #1635) + +* Add support for using Linux ``getrandom`` syscall to access the system PRNG. + This is disabled by default, use ``--with-os-feature=getrandom`` to enable. + +* It is now possible to encrypt private keys using SIV mode. + +* The FFI function botan_privkey_load now ignores its rng argument. + +* Resolve a problem when building under Visual C++ 15.8 (GH #1624) + +* Fix a bug in XSalsa20 (192-bit Salsa nonces) where if set_iv was called twice + without calling set_key, the resulting encryption was incorrect. (GH #1640) + +* Handle an error seen when verifying invalid ECDSA signatures using LibreSSL + on non x86-64 platforms (GH #1627 #1628) + +* Fix bugs in PKCS7 and X9.23 CBC padding schemes, which would ignore + the first byte in the event the padding took up the entire block. (GH #1690) + +* Correct bugs which would cause CFB, OCB, and GCM modes to crash when they + were used in an unkeyed state. (GH #1639) + +* Optimizations for SM4 and Poly1305 + +* Avoid a cache side channel in the AES key schedule + +* Add ``pk_encrypt`` and ``pk_decrypt`` CLI operations + +* Now ``asn1print`` CLI defaults to printing context-specific fields. + +* Use codec_base for Base64, which matches how Base32 is implemented (GH #1597) + +* The ``cast`` module has been split up into ``cast128`` and ``cast256`` (GH #1685) + +* When building under Visual C++ 2013, the user must acknowledge the upcoming + removal of support using the configure.py flag ``--ack-vc2013-deprecated`` + (GH #1557) + +Version 2.7.0, 2018-07-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CVE-2018-12435 Avoid a side channel in ECDSA signature generation (GH #1604) + +* Avoid a side channel in RSA key generation due to use of a non-constant time + gcd algorithm. (GH #1542 #1556) + +* Optimize prime generation, especially improving RSA key generation. (GH #1542) + +* Make Karatsuba multiplication, Montgomery field operations, Barrett reduction + and Montgomery exponentiation const time (GH #1540 #1606 #1609 #1610) + +* Optimizations for elliptic curve operations especially improving reductions + and inversions modulo NIST primes (GH #1534 #1538 #1545 #1546 #1547 #1550) + +* Add 24 word wide Comba multiplication, improving 3072-bit RSA and DH by ~25%. + (GH #1564) + +* Unroll Montgomery reduction for specific sizes (GH #1603) + +* Improved performance of signature verification in ECGDSA, ECKCDSA, + SM2 and GOST by 10-15%. + +* XMSS optimizations (GH #1583 #1585) + +* Fix an error that meant XMSS would only sign half as many signatures as is + allowed (GH #1582) + +* Add support for base32 encoding/decoding (GH #1541) + +* Add BMI2 optimized version of SHA-256, 40% faster on Skylake (GH #1584) + +* Allow the year to be up to 2200 in ASN.1 time objects. Previously this + was limited to 2100. (GH #1536) + +* Add support for Scrypt password hashing (GH #1570) + +* Add support for using Scrypt for private key encryption (GH #1574) + +* Optimizations for DES/3DES, approx 50% faster when used in certain modes such + as CBC decrypt or CTR. + +* XMSS signature verification did not check that the signature was of + the expected length which could lead to a crash. (GH #1537) + +* The bcrypt variants 2b and 2y are now supported. + +* Support for 192-bit Suite B TLS profile is now implemented, as the 128-bit + Suite B is since 2015 not allowed anymore. + +* Previously botan allowed GCM to be used with an empty nonce, which is not + allowed by the specification. Now such nonces are rejected. + +* Avoid problems on Windows when compiling in Unicode mode (GH #1615 #1616) + +* Previously for ASN.1 encoded signatures (eg ECDSA) Botan would accept any + valid BER encoding. Now only the single valid DER encoding is accepted. + +* Correct an error that could in rare cases cause an internal error exception + when doing computations with the P-224 curve. + +* Optimizations to reduce allocations/copies during DER encoding and BER + decoding (GH #1571 #1572 #1600) + +* Botan generates X.509 subject key IDs by hashing the public key with whatever + hash function is being used to sign the certificate. However especially for + SHA-512 this caused SKIDs that were far longer than necessary. Now all SKIDs + are truncated to 192 bits. + +* In the test suite use ``mkstemp`` to create temporary files instead of + creating them in the current working directory. (GH #1533 #1530) + +* It is now possible to safely override ``CXX`` when invoking make in addition + to when ``configure.py`` is run. (GH #1579) + +* OIDs for Camellia and SM4 in CBC and GCM mode are now defined, making it + possible to use this algorithms for private key encryption. + +* Avoid creating symlinks to the shared object on OpenBSD (#1535) + +* The ``factor`` command runs much faster on larger inputs now. + +* Support for Windows Phone/UWP was deprecated starting in 2.5. This deprecation + has been reversed as it seems UWP is still actively used. (GH #1586 #1587) + +* Support for Visual C++ 2013 is deprecated, and will be removed in Jan 2019. + +* Added support for GCC's --sysroot option to configure.py for cross-compiling. + +Version 2.6.0, 2018-04-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* CVE-2018-9860 Fix a bug decrypting TLS CBC ciphertexts which could + for a malformed ciphertext cause the decryptor to read and HMAC an + additional 64K bytes of data which is not part of the record. This + could cause a crash if the read went into unmapped memory. No + information leak or out of bounds write occurs. + +* Add support for OAEP labels (GH #1508) + +* RSA signing is about 15% faster (GH #1523) and RSA verification is + about 50% faster. + +* Add exponent blinding to RSA (GH #1523) + +* Add ``Cipher_Mode::create`` and ``AEAD_Mode::create`` (GH #1527) + +* Fix bug in TLS server introduced in 2.5 which caused connection to + fail if the client offered any signature algorithm not known to the + server (for example RSA/SHA-224). + +* Fix a bug in inline asm that would with GCC 7.3 cause incorrect + computations and an infinite loop during the tests. (GH #1524 #1529) + +Version 2.5.0, 2018-04-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix error in certificate wildcard matching (CVE-2018-9127), where a + wildcard cert for ``b*.example.com`` would be accepted as a match for + any host with name ``*b*.example.com`` (GH #1519) + +* Add support for RSA-PSS signatures in TLS (GH #1285) + +* Ed25519 certificates are now supported (GH #1501) + +* Many optimizations in ECC operations. ECDSA signatures are 8-10 times faster. + ECDSA verification is about twice as fast. ECDH key agreement is 3-4 times + faster. (GH #1457 #1478) + +* Implement product scanning Montgomery reduction, which improves Diffie-Hellman + and RSA performance by 10 to 20% on most platforms. (GH #1472) + +* DSA signing and verification performance has improved by 30-50%. + +* Add a new Credentials_Manager callback that specifies which CAs the server + has indicated it trusts (GH #1395 fixing #1261) + +* Add new TLS::Callbacks methods that allow creating or removing extensions, + as well as examining extensions sent by the peer (GH #1394 #1186) + +* Add new TLS::Callbacks methods that allow an application to + negotiate use of custom elliptic curves. (GH #1448) + +* Add ability to create custom elliptic curves (GH #1441 #1444) + +* Add support for POWER8 AES instructions (GH #1459 #1393 #1206) + +* Fix DSA/ECDSA handling of hashes longer than the group order (GH #1502 #986) + +* The default encoding of ECC public keys has changed from compressed + to uncompressed point representation. This improves compatibility with + some common software packages including Golang's standard library. + (GH #1480 #1483) + +* It is now possible to create DNs with custom components. (GH #1490 #1492) + +* It is now possible to specify the serial number of created certificates, + instead of using the default 128-bit random integer. (GH #1489 #1491) + +* Change DL_Group and EC_Group to store their data as shared_ptr for + fast copying. Also both classes precompute additional useful values + (eg for modular reductions). (GH #1435 #1454) + +* On Windows platforms RtlGenRandom is now used in preference to CryptoAPI + or CryptoNG libraries. (GH #1494) + +* Make it possible for PKCS10 requests to include custom extensions. This also + makes it possible to use multiple SubjectAlternativeNames of a single type in + a request, which was previously not possible. (GH #1429 #1428) + +* Add new optimized interface for FE1 format preserving encryption. By caching a + number of values computed in the course of the FPE calculation, it provides a + 6-7x speedup versus the old API. (GH #1469) + +* Add DSA and ElGamal keygen functions to FFI (#1426) + +* Add ``Pipe::prepend_filter`` to replace deprecated ``Pipe::prepend`` (GH #1402) + +* Fix a memory leak in the OpenSSL block cipher integration, introduced in 2.2.0 + +* Use an improved algorithm for generating safe primes which is several tens of + times faster. Also, fix a bug in the prime sieving algorithm which caused + standard prime generation (like for RSA keys) to be slower than necessary. + (GH #1413 #1411) + +* Correct the return value of ``PK_Encryptor::maximum_input_size`` which + reported a much too small value (GH #1410) + +* Remove use of CPU specific optimization flags, instead the user should set + these via CXXFLAGS if desired. (GH #1392) + +* Resolve an issue that would cause a crash in the tests if they were run on + a machine without SSE2/NEON/VMX instructions. (GH #1495) + +* The Python module now tries to load DLLs from a list of names and + uses the first one which successfully loads and indicates it + supports the desired API level. (GH #1497) + +* Various minor optimizations for SHA-3 (GH #1433 #1434) + +* The output of ``botan --help`` has been improved (GH #1387) + +* Add ``--der-format`` flag to command line utils, making it possible verify + DSA/ECDSA signatures generated by OpenSSL command line (GH #1409) + +* Add support for ``--library-suffix`` option to ``configure.py`` (GH #1405 #1404) + +* Use feature flags to enable/disable system specific code (GH #1378) + +* Add ``--msvc-runtime`` option to allow using static runtime (GH #1499 #210) + +* Add ``--enable-sanitizers=`` option to allow specifying which sanitizers to + enable. The existing ``--with-sanitizers`` option just enables some default + set which is known to work with the minimum required compiler versions. + +* Use either ``rst2man`` or ``rst2man.py`` for generating man page as + distributions differ on where this program is installed (GH #1516) + +* The threefish module has been renamed threefish_512 since that is the + algorithm it provides. (GH #1477) + +* The Perl XS based wrapper has been removed, as it was unmaintained and + broken. (GH #1412) + +* The sqlite3 encryption patch under ``contrib`` has been removed. It + is still maintained by the original author at + https://github.com/OlivierJG/botansqlite3 + +* Support for Windows Phone is deprecated. + +Version 2.4.0, 2018-01-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Several build improvements requested by downstream packagers, including the + ability to disable building the static library. All makefile constructs that + were specific to nmake or GNU make have been eliminated, thus the option + ``--makefile-style`` which was previously used to select the makefile type has + also been removed. (GH #1230 #1237 #1300 #1318 #1319 #1324 #1325 #1346) + +* Support for negotiating the DH group as specified in RFC 7919 is now available + in TLS (GH #1263) + +* Support for ARIA-GCM ciphersuites are now available in TLS. They are disabled + by default. (GH #1284) + +* Add support for generating and verifying X.509 objects (certificates, CRLs, + etc) using RSA-PSS signatures (GH #1270 and #1368) + +* Add support for AES key wrapping with padding, as specified in RFC 5649 and + NIST SP 800-38F (GH #1301) + +* OCSP requests made during certificate verification had the potential to hang + forever. Now the sockets are non-blocking and a timeout is enforced. (GH #1360 + fixing GH #1326) + +* Add ``Public_Key::fingerprint_public`` which allows fingerprinting the public key. + The previously available ``Private_Key::fingerprint`` is deprecated, now + ``Private_Key::fingerprint_private`` should be used if this is required. + (GH #1357) + +* ECC certificates generated by Botan used an invalid encoding for the + parameters field, which was rejected by some certificate validation libraries + notably BouncyCastle. (GH #1367) + +* Loading an ECC key which used OID encoding for the domain parameters, then + saving it, would result in a key using the explicit parameters encoding. + Now the OID encoding is retained. (GH #1365) + +* Correct various problems in certificate path validation that arose when + multiple paths could be constructed leading to a trusted root but due to + other constraints only some of them validated. (GH #1363) + +* It is now possible for certificate validation to return warning indicators, + such as that the distinguished name is not within allowed limits or that a + certificate with a negative serial number was observed. (GH #1363 #1359) + +* XMSS signatures now are multi-threaded for improved performance (GH #1267) + +* Fix a bug that caused the TLS peer cert list to be empty on a resumed session. + (GH #1303 #1342) + +* Increase the maximum HMAC key length from 512 bytes to 4096 bytes. This allows + using a DH key exchange in TLS with a group greater than 4096 bits. (GH #1316) + +* Fix a bug in the TLS server where, on receiving an SSLv3 client hello, it + would attempt to negotiate TLS v1.2. Now a protocol_version alert is sent. + Found with tlsfuzzer. (GH #1316) + +* Fix several bugs related to sending the wrong TLS alert type in various error + scenarios, caught with tlsfuzzer. + +* Add support for a ``tls_http_server`` command line utility which responds to + simple GET requests. This is useful for testing against a browser, or various + TLS test tools which expect the underlying protocol to be HTTP. (GH #1315) + +* Add an interface for generic PSK data stores, as well as an implementation + which encrypts stored values with AES key wrapping. (GH #1302) + +* Optimize GCM mode on systems both with and without carryless multiply + support. This includes a new base case implementation (still constant time), a + new SSSE3 implementation for systems with SSSE3 but not clmul, and better + algorithms for systems with clmul and pmull. (GH #1253 #1263) + +* Various optimizations for OCB, CFB, CTR, SM3, SM4, GMAC, BLAKE2b, Blowfish, + Twofish, CAST-128, and CRC24 (GH #1281) + +* Salsa20 now supports the seek operation. + +* Add ``EC_Group::known_named_groups`` (GH #1339) + +* Symmetric algorithms (block ciphers, stream ciphers, MACs) now verify that a + key was set before accepting data. Previously attempting to use an unkeyed + object would instead result in either a crash or invalid outputs. (GH #1279) + +* The X509 certificate, CRL and PKCS10 types have been heavily refactored + internally. Previously all data of these types was serialized to strings, then + in the event a more complicated data structure (such as X509_DN) was needed, + it would be recreated from the string representation. However the round trip + process was not perfect and could cause fields to become lost. This approach + is no longer used, fixing several bugs (GH #1010 #1089 #1242 #1252). The + internal data is now stored in a ``shared_ptr``, so copying such objects is + now very cheap. (GH #884) + +* ASN.1 string objects previously held their contents as ISO 8859-1 codepoints. + However this led to certificates which contained strings outside of this + character set (eg in Cyrillic, Greek, or Chinese) being rejected. Now the + strings are always converted to UTF-8, which allows representing any + character. In addition, UCS-4 strings are now supported. + (GH #1113 #1250 #1287 #1289) + +* It is now possible to create an uninitialized X509_Certificate object. Such an + object will throw if any attempt to access its members is made. (GH #1335) + +* In BER decoder, avoid unbounded stack recursion when parsing nested indefinite + length values. Now at most 16 nested indefinite length values are accepted, + anything deeper resulting in a decoding error. (GH #1304 OSS-Fuzz 4353). + +* A new ASN.1 printer API allows generating a string representation of arbitrary + BER data. This is used in the ``asn1print`` command line utility and may be + useful in other applications, for instance for debugging. + +* New functions for bit rotations that distinguish rotating by a compile-time + constant vs a runtime variable rotation. This allows better optimizations in + both cases. Notably performance of CAST-128 and CAST-256 are substantially + improved. (GH #1247) + +* TLS CBC ciphersuites now are implemented using the standard CBC code, instead + of reimplementing CBC inside the TLS stack. This allows for parallel + decryption of TLS CBC ciphertexts, and improves performance especially when + using AES hardware support. (GH #1269) + +* Add callbacks to make it possible for an application using TLS to provide + custom implementations of signature schemes, eg when offloading the + computations to another device. (GH #1332) + +* Use a direct calculation for calendar computations instead of relying on + non-portable operating system interfaces. (GH #1336) + +* Fix a bug in the amalgamation generation which could cause build failures on + some systems including macOS. (GH #1264 #1265) + +* A particular code sequence in TLS handshake would always (with an ECC + ciphersuite) result in an exception being thrown and then caught. This has + changed so no exception is thrown. (GH #1275) + +* The code for byteswapping has been improved for ARMv7 and for Windows x86-64 + systems using MSVC. (GH #1274) + +* The GMAC class no longer derives from GHASH. This should not cause any + noticeable change for applications. (GH #1253) + +* The base implementation of AES now uses a single 4K table, instead of 4 such + tables. This offers a significant improvement against cache-based side + channels without hurting performance too much. In addition the table is now + guaranteed to be aligned on a cache line, which ensures the additional + countermeasure of reading each cache line works as expected. (GH #1255) + +* In TLS client resumption, avoid sending a OCSP stapling request. This caused + resumption failures with some servers. (GH #1276) + +* The overhead of making a call through the FFI layer has been reduced. + +* The IDs for SHA-3 PKCSv1.5 signatures added in 2.3.0 were incorrect. They have + been changed to use the correct encoding, and a test added to ensure such + errors do not recur. + +* Counter mode allows setting a configurable width of the counter. Previously it + was allowed for a counter of even 8 bits wide, which would mean the keystream + would repeat after just 256 blocks. Now it requires the width be at least 32 + bits. The only way this feature could be used was by manually constructing a + ``CTR_BE`` object and setting the second parameter to something in the range + of 1 to 3. + +* A new mechanism for formatting ASN.1 data is included in ``asn1_print.h``. + This is the same functionality used by the command line ``asn1print`` util, + now cleaned up and moved to the library. + +* Add ``Pipe::append_filter``. This is like the existing (deprecated) + ``Pipe::append``, the difference being that ``append_filter`` only + allows modification before the first call to ``start_msg``. (GH #1306 #1307) + +* The size of ASN1_Tag is increased to 32 bits. This avoids a problem + with UbSan (GH #751) + +* Fix a bug affecting bzip2 compression. In certain circumstances, compression + would fail with ``BZ_SEQUENCE_ERROR`` due to calling bzlib in an way it does + not support. (GH #1308 #1309) + +* In 2.3.0, final annotations were added to many classes including the TLS + policies (like ``Strict_Policy`` and ``BSI_TR_02102_2``). However it is + reasonable and useful for an application to derive from one of these policies, so + as to create an application specific policy that is based on a library-provided + policy, but with a few tweaks. So the final annotations have been removed on + these classes. (GH #1292) + +* A new option ``--with-pdf`` enables building a PDF copy of the handbook. + (GH #1337) + +* A new option ``--with-rst2man`` enables building a man page for the + command line util using Docutils rst2man. (GH #1349) + +* Support for NEON is now enabled under Clang. + +* Now the compiler version is detected using the preprocessor, instead of trying + to parse the output of the compiler's version string, which was subject to + problems with localization. (GH #1358) + +* By default the gzip compressor will not include a timestamp in the header. + The timestamp can be set by passing it to the ``Gzip_Compression`` + constructor. + +* Resolve a performance regression on Windows involving the system stats + entropy source. (GH #1369) + +* Add an OID for RIPEMD-160 + +* Fixes for CMake build (GH #1251) + +* Avoid some signed overflow warnings (GH #1220 #1245) + +* As upstream support for Native Client has been deprecated by Google, support + is now also deprecated in Botan and will be removed in a future release. + +* The Perl-XS wrapper has not been maintained in many years. It is now deprecated, + and if no attempts are made to revive it, it will be removed in a future release. + +* Support for building on IRIX has been removed. + +Version 2.3.0, 2017-10-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Address a side channel affecting modular exponentiation. An attacker + capable of a local or cross-VM cache analysis attack may be able + to recover bits of secret exponents as used in RSA, DH, etc. + CVE-2017-14737 + +* Add the SHACAL2 block cipher, including optimizations using SIMD and SHA-NI + instructions. (GH #1151) + +* Add the ARIA block cipher (GH #1004 and #1157) + +* Add support for the ARMv8 AES instructions (GH #1182 and #1146) + +* Add support for the ARMv8 PMULL instruction (GH #1181 and #842) + +* On macOS and iOS the ``System_RNG`` class is now implemented using ``arc4random``. + Previously the system RNG class was not available on iOS. (GH #1219) + +* Optimized the CMAC polynomial doubling operation, and removed a small timing + channel due to a conditional operation. + +* Added support for the ECDHE_PSK AEAD TLS ciphersuites from + draft-ietf-tls-ecdhe-psk-aead-05. + +* SM2 encryption and signature schemes were previously hardcoded to use SM3 + hash, now any hash is allowed. (GH #1188) + +* SM2 encryption in 2.2.0 followed an obsolete version of the standard. The + format of the ciphertext changed in a more recent revision of the standard, + and now uses an ASN.1 encoding. Botan has changed to reflect this format, + which is compatible with GmSSL (GH #1218) + +* OCB mode now supports 192, 256 and 512 bit block ciphers. (GH #1205) + +* XTS mode now supports 256-bit and 512-bit block ciphers. + +* Add ids to allow SHA-3 signatures with PKCSv1.5 (GH #1184) + +* Add support for ``PSSR_Raw`` signatures which PSS sign an externally derived + hash. (GH #1212 #1211) + +* GCM now supports truncated tags in the range 96...128 bits. GCM had + previously supported 64-bit truncated tags, but these are known to + be insecure and are now deprecated. (GH #1210 #1207) + +* Add a new TLS policy hook ``allow_client_initiated_renegotiation`` which is the + parallel of the existing ``allow_server_initiated_renegotiation``. If set to + false, servers will reject attempts by the client to renegotiation the + session, instead sending a ``no_renegotiation`` warning alert. Note that the + default is ``false``, ie that client renegotiation is now prohibited by default. + (GH #872) + +* Add HKDF-Expand-Label function which is used in TLS v1.3 and QUIC protocols. + (GH #1226) + +* Fix decoding of ECC keys that use extensions from RFC 5915 (GH #1208) + +* The entropy source that called CryptGenRandom has been removed, and + replaced by a version which invokes the system PRNG, which may + be CryptGenRandom or some other source. (GH #1180) + +* Add support for gathering entropy using the Crypt-NG BCryptGenRandom + API. This is necessary to build for Windows Phone/Windows Store. (GH #1180) + +* Extend "Raw" signature padding (which allows signing a hash computed + externally) to optionally take a hash function name. In this case, it will be + verified that the input matches the expected hash size. This also will + control the hash algorithm used for RFC 6979 deterministic nonces; previously + SHA-512 was always used for RFC 6979 nonces with "Raw". (GH #1153) + +* The advertised FFI API version has increased. This should have happened + already in 2.2 but was neglected. The ``botan_ffi_supports_api`` call will + return true for either the current or older versions of the API version since + no backwards incompatible changes have occurred. + +* Add new C89 API functions ``botan_hex_decode``, ``botan_base64_encode``, + ``botan_base64_decode``, ``botan_constant_time_compare``. + +* Add new C89 API functions ``botan_privkey_load_dh``, ``botan_pubkey_load_dh``, + and ``botan_privkey_create_dh`` (GH #1155) + +* Add ``is_passhash9_alg_supported`` (GH #1154) + +* The ``power_mod`` function now supports negative bases (GH #1179 #1168) + +* Add a new command line utility for examining TLS client hellos. + +* Added a new target for LLVM bitcode (GH #1169) + +* Improve support for Windows Phone (GH #1180 #796 #794) + +* Correct return value of ``botan_pk_op_verify_finish``. In 2.2.0 this function + returned -1 on invalid signature, instead of 1 which was used in 2.0, 2.1, and + now again in 2.3. (GH #1189 #1187) + +* Allow loading unencrypted private keys via FFI API (GH #1197) + +* Add new command line options ``--rng-type=drbg`` and ``--drbg-seed`` which + allow running commands with a deterministic RNG. (GH #1169) + +* Fix a number of warnings seen under Visual C++ (GH #1171 #795) + +* Workaround a GCC 7 bug that caused miscompilation of the GOST-34.11 hash + function on x86-32. (GH #882 #1148) + +* Fix a bug in SIMD_4x32 which affected little-endian PowerPC processors. + This would cause test failures for Serpent, among other problems. + +* Fix Altivec runtime detection, which was broken starting in Botan 2.1.0 + +* Optimized the verification of TLS CBC padding bytes. Previously the check + examined every byte of the record, even though at most 256 bytes of padding + may be appended. (GH #1227) + +* Simplified definition of ``Botan::secure_allocator``. In particular, not + defining the ``construct`` and ``destroy`` methods avoids a performance problem + under MSVC. (GH #1228 and #1229) + +* The ``secure_allocator`` class now uses ``calloc`` and ``free`` instead of + ``new`` and ``delete``. In addition the actual allocation operation is hidden + inside of compiled functions, which significantly reduces code size. (GH #1231) + +* The ``secure_scrub_memory`` function now uses ``explicit_bzero`` on OpenBSD. + +* Previously ARM feature detection (NEON, AES, ...) relied on getauxval, which + is only supported on Linux and Android. Now iOS is supported, by checking the + model name/version and matching it against known versions. Unfortunately this + is the best available technique on iOS. On Aarch64 systems that are not iOS or + Linux/Android, a technique based on trial execution while catching SIGILL is + used. (GH #1213) + +* The output of ``botan config libs`` was incorrect, it produced ``-lbotan-2.X`` + where X is the minor version, instead of the actual lib name ``-lbotan-2``. + +* Add ``constant_time_compare`` as better named equivalent of ``same_mem``. + +* Silence a Clang warning in ``create_private_key`` (GH #1150) + +* The fuzzers have been better integrated with the main build. See the + handbook for details. (GH #1158) + +* The Travis CI and AppVeyor CI builds are now run via a Python script. This + makes it easier to replicate the behavior of the CI build locally. Also a + number of changes were made to improve the turnaround time of CI builds. + (GH #1162 #1199) + +* Add support for Win32 filesystem operation, so the tests pass completely + on MinGW now (GH #1203) + +* Added a script to automate running TLS-Attacker tests. + +* The distribution script now creates reproducible outputs, by + forcing all modification times, uids, etc to values fixed by the release date. + (GH #1217) + +* The ``BOTAN_DLL`` macro has been split up into ``BOTAN_PUBLIC_API``, + ``BOTAN_UNSTABLE_API`` and ``BOTAN_TEST_API`` which allows + indicating in the header the API stability of the export. All three + are defined as ``BOTAN_DLL`` so overriding just that macro continues + to work as before. (GH #1216) + +* Optimize ``bigint_divop`` when a double-word type is available. (GH #494) + +* Fix several memory leaks in the tests. Additionally a false positive + leak seen under ``valgrind`` in the ``fork`` tests for the RNG was resolved. + +* Export ``CurveGFp_Repr`` type (only used internally) to resolve a + long standing UBSan warning. (GH #453) + +* Now ``-fstack-protector`` and similar flags that affect linking are exported + in ``botan config ldflags`` as they already were in the ``pkg-config`` output. + (GH #863) + +* Remove double underscore in header guards to avoid using names + reserved by ISO C++. (GH #512) + +* Additions to the SRP documentation (GH #1029) + +* The package transform (in ``package.h``) is now deprecated, and will be + removed in a future release. (GH #1215) + +* Add more tests for the const-time utils (GH #1214) + +* Fix a bug in FFI tests that caused the test files not to be found when using + ``--data-dir`` option (GH #1149) + +* C++ ``final`` annotations have been added to classes which are not + intended for derivation. This keyword was already in use but was not + applied consistently. + +* A typedef ``SecureVector`` has been added for the ``secure_vector`` type. + This makes porting code from 1.10 to 2.x API slightly simpler. + +* Header files have been cleaned up to remove unnecessary inclusions. In some + cases it may be required to include additional botan headers to get all the + declarations that were previously visible. For example, ``bigint.h`` no longer + includes ``rng.h``, but just forward declares ``RandomNumberGenerator``. + +* Improved support for IBM xlc compiler. + +Version 2.2.0, 2017-08-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add the Ed25519 signature scheme (GH #1066) + +* The format of x25519 keys, which previously used a non-standard encoding, + has changed to match the upcoming IETF specification. (GH #1076) + +* Add the SM2 signature scheme (GH #1082) + +* Add the SM2 public key encryption scheme (GH #1142) + +* Add the SM3 hash function (GH #996) + +* Add the Streebog (GOST R 34.11-2012) hash function (GH #1114) + +* Add the SM4 block cipher (GH #1080) + +* Add the PGP S2K algorithm (GH #1060) + +* Add SP 800-56A KDF (GH #1040) + +* Add ChaCha_RNG which is a very fast and completely non-standard + random bit generator (GH #1137) + +* Add support for SHA-1 and SHA-2 instructions added in Intel Goldmont + (GH #826) + +* Add support for SHA-1 and SHA-2 instructions added in ARMv8 (GH #844) + +* Add support for HOTP (RFC 4226) and TOTP (RFC 6238) + one-time-password algorithms (GH #1054) + +* Fix a bug that caused secure_allocator to not fully zeroize blocks + when sizeof(T) was greater than 1. + +* Add HashFunction::copy_state which allows efficiently computing the + hash of several messages with a common prefix (GH #1056 #1037) + +* ECC keys now encode their parameters using an OID instead of a literal + encoding of the domain parameters. This will lead to smaller public and + private keys in most instances. (GH #1093) + +* The OpenSSL backend now supports the 1.1.0 API (GH #1056) + +* Add a preliminary provider using BearSSL, currently EC and hashes supported + (GH #1094) + +* Fix a bug in certificate path length checking that could cause valid + chains to be rejected. (GH #1053) + +* It is possible for CBC, CFB, and stream ciphers to carry over the + nonce from the previous message, which is needed by some applications. + This worked in 1.10 but broke in 2.0. (GH #1044 fixing GH #864) + +* Avoid recursion in BER_Decoder::get_next_object which could cause + stack exhaustion. (GH #989) + +* Fix missing flush in DataSink_Stream::end_msg. (GH #972 fixing GH #972) + +* Allow to seek in the big endian counter mode of operation (GH #999) + +* Support loading ElGamal keys through FFI interface (GH #1008) + +* Support Windows sockets in ``http_util`` (allowing OCSP checks on Windows), + as well as in the TLS command line utils (GH #1138). + +* The ``--destdir`` flag to ``configure.py`` has been removed. Instead use + the ``DESTDIR`` environment variable at install time. This change was + done to more closely match how autoconf handles this case. + (GH #1139 #1111 #997 #996). + +* Many changes to configure.py and botan2.py to make them pylint clean + (GH #1041 #1002 #984) + +* Add command line utils ``hmac`` (GH #1001), ``encryption`` (GH #359), + ``hex_enc``, and ``hex_dec``. + +* Fix an error in ``sign_cert`` command line util, which ignored the + ``--ca-key-pass`` option. (GH #1106) + +* The ``speed`` util can now benchmark multiple buffer sizes (GH #1084) + +* Fix return value of FFI botan_bcrypt_is_valid (GH #1033) + +* Support generating RSA keys using OpenSSL (GH #1035) + +* Add new FFI functions botan_hash_block_size (GH #1036), + botan_hash_copy_state (GH #1059), botan_scrub_mem + +* Add support for RFC 3394 keywrap through FFI (GH #1135) + +* Support AES-CBC ciphers via OpenSSL (GH #1022) + +* Add function to return certificates included in OCSP response (GH #1123) + +* Complete wildcard handling for X.509 certificates (GH #1017) + +* Add some missing functions to TLS::Text_Policy (GH #1023) + +* It was previously possible to use ``--single-amalgamation-file`` + without ``--amalgamation``, though it did not do anything useful. Now + ``--single-amalgamation-file`` requires ``--amalgamation`` also be set + on the command line. + +Version 2.1.0, 2017-04-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix incorrect truncation in Bcrypt. Passwords in length between 56 and 72 + characters were truncated at 56 characters. Found and reported by Solar Designer. + (CVE-2017-7252) (GH #938) + +* Fix a bug in X509 DN string comparisons that could result in out of bound + reads. This could result in information leakage, denial of service, or + potentially incorrect certificate validation results. Found independently + by Cisco Talos team and OSS-Fuzz. (CVE-2017-2801) + +* Correct minimum work factor for Bcrypt password hashes. All other + implementations require the work factor be at least 4. Previously Botan simply + required it be greater than zero. (GH #938) + +* Converge on a single side channel silent EC blinded multiply algorithm. + Uses Montgomery ladder with order/2 bits scalar blinding and point randomization + now by default. (GH #893) + +* Add ability to search for certificates using the SHA-256 of the distinguished name. + (GH #900) + +* Support a 0-length IV in ChaCha stream cipher. Such an IV is treated + identically to an 8-byte IV of all zeros. + +* Add new interfaces to the C API including multiple precision integers, key + validity tests, block ciphers, and extracting algorithm specific key parameters + (such as the modulus and public exponent from RSA public keys). GH #899 #944 + #946 #961 #964 + +* The PKCS11 module did not require any external dependencies, so it + has been enabled by default. The ``--with-pkcs11`` and ``--without-pkcs11`` + flags to ``configure.py`` have been removed. PKCS11 can still be disabled + using ``--disable-modules=pkcs11`` (GH #837) + +* Add ``OS::run_cpu_instruction_probe`` for runtime probing of ISA extensions. + Supporting this requires system-specific techniques, currently Windows SEH and + Unix signal handling are supported. + +* Add support for ARM NEON in the SIMD_4x32 type + +* Add support for ARM CPU feature detection using getauxval (GH #843) + +* Previously Botan forbid any use of times past 2037 to avoid Y2038 issues. + Now this restriction is only in place on systems which have a 32-bit + ``time_t``. (GH #933 fixing #917) + +* Add generic type decoder function to BER decoder (GH #897) + +* Fix portability or build problems affecting Sun Studio compiler (GH #846), + Solaris, ppc64le, DragonflyBSD (GH #887) + +* Add ``--with-external-libdir`` to configure.py (GH #857 fixing #19 #767) + +* Add ``OS::get_high_resolution_clock`` which returns the best resolution + clock available on the system. + +* Change ``OS::get_processor_timestamp`` to return 0 if no hardware + cycle counter is available. Previously it silently fell back on some + other clock type. + +* Report cycles/byte in the output of ``botan speed``. + +* Add speed tests for modular exponentiations and ECC scalar multiplies. + +* Avoid using IP address for SNI in ``tls_client``. (GH #942) + +* Add command line util ``timing_test`` which enables running + timing-based side channel analysis of TLS CBC decryption, ECC scalar + multiplies, OAEP decoding, and other operations which are prone to + providing an oracle via side channel. This replaces the standalone + timing test suite added in 1.11.34, which has been removed. + +* Various cleanups and refactorings (GH #965) + +* Add wrapper of C++14 make_unique (GH #974) + +* Fix pkg-config output when --build-dir was used (GH #936) + +* Make it possible to disable `-fstack-protector` using a build-time flag. + GH #863 + +* Add tests for TLS DSA ciphersuites, more Noekeon tests, others. + +* Avoid a GCC warning that triggered on the public key types (GH #849) + +* Fix various warnings flagged by pylint and pyflakes linters in + configure.py and botan.py (GH #832 #836 #839 #962 #975) + +* Improve support for OpenBSD including using getentropy (GH #954) + for PRNG seeding, and arc4random to access system RNG (GH #953) + +* Add ability to build through CMake. As of now this is only supported + for development rather than production builds. (GH #967) + +* Rename python wrapper to botan2.py (GH #847) + +* Change name constraint test to use a fixed reference time. Test certs have expired. + +* Increase Miller-Rabin iterations for DSA primes to match FIPS 186-4. (GH #881) + +* Fix possible ISO 9796-2 padding side channel, and add a missing length check (GH #891) + +* In command line utility, prefer the system RNG if it is available. + +Version 2.0.1, 2017-01-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Change an unintended behavior of 2.0.0, which named the include + directory ``botan-2.0``. Since future release of Botan-2 should be + compatible with code written against old versions, there does not + seem to be any reason to version the include directory with the + minor number. (GH #830 #833) + +* Fix a bug which caused an error when building on Cygwin or + other platforms where shared libraries are not supported. + (GH #821) + +* Enable use of readdir on Cygwin, which allows the tests to run (GH #824) + +* Switch to readthedocs Sphinx theme by default (GH #822 #823) + +Version 2.0.0, 2017-01-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* With this release the project adopts Semantic Versioning (GH #766) + +* Fix a longstanding bug in modular exponentiation which caused most + exponentiations modulo an even number to have an incorrect result; such moduli + occur only rarely in cryptographic contexts. (GH #754) + +* Fix a bug in BigInt multiply operation, introduced in 1.11.30, which could + cause incorrect results. Found by OSS-Fuzz fuzzing the ressol function, where + the bug manifested as an incorrect modular exponentiation. OSS-Fuzz bug #287 + +* Fix a bug that meant the "ietf/modp/6144" and "ietf/modp/8192" discrete log + groups used an incorrect value for the generator, specifically the value + (p-1)/2 was used instead of the correct value of 2. + +* The DL_Group enum value X942_DH_PARAMETERS has been renamed + ANSI_X9_42_DH_PARAMETERS to avoid a conflict with Windows headers (GH #482) + +* Change default PEM header for X942 DH to match OpenSSL. Either version is + accepted on reading. (GH #818) + +* DL_Group strong generation previously set the generator to 2. However + sometimes 2 generates the entire group mod p, rather than the subgroup mod q. + This is invalid by X9.42 standard, and exposes incautious applications to + small subgroup attacks. Now DL_Group uses the smallest g which is a quadratic + residue. (GH #818) + +* Add iOS build target instead of piggybacking on OS X configuration. (GH #793) + +* Changes all Public_Key derived class ctors to take a std::vector instead of a + secure_vector for the DER encoded public key bits. (GH #768) + +* Allow use of custom extensions when creating X.509 certificates (GH #744) + +* The default TLS policy now requires 2048 or larger DH groups by default. + +* Add BSI_TR_02102_2 TLS::Policy subclass representing BSI TR-02102-2 recommendations. + +* The default Path_Validation_Restrictions constructor has changed to + require at least 110 bit signature strength. This means 1024 bit RSA + certificates and also SHA-1 certificates are rejected by default. + Both settings were already the default for certificate validation in + TLS handshake, but this changes it for applications also. + +* Add ISO 9796-2 signature padding schemes DS2 and DS3. These schemes provide + message recovery (part or all of the plaintext message can be recovered from + the signature alone) and are used by some industry protocols. (GH #759) + +* Rewrite all the code that handles parsing CBC padding bytes to run without + conditional jumps or loads. (GH #765 #728) + +* Fix deref of invalid memory location in TLS client when the server chooses a + ciphersuite value larger than the largest TLS ciphersuite ID compiled into the + table. This might conceivably cause a crash in rare circumstances, but does + not seem to be further exploitable. (GH #758) + +* Rename Public_Key::x509_subject_public_key, which does not return a + X.509 SubjectPublicKey, to public_key_bits. Add a new non-virtual function + Public_Key::subject_public_key which does exactly that. (GH #685 #757) + +* Rename Private_Key::pkcs8_private_key, which does not return a + PKCS#8 private key, to private_key_bits. Add a new non-virtual function + Private_Key::private_key_info which does exactly that. (GH #685 #757) + +* The deprecated ECB Cipher_Mode class has been removed (GH #756) + +* The class SRP6_Authenticator_File (in srp6_files.h) was meant to parse GnuTLS + SRP files. But it was completely untested, and it turns out due to several + problems it was completely unable to parse any SRP file correctly. It has + been removed, with a future replacement planned that can handle both + flat files (in the actual SRP format) or using a SQL database. + +* Fix tests errors when write access to /dev/urandom is prohibited (GH #748) + +* Add more Diffie-Hellman tests (GH #790), tests for RSA blinding, others. + +* Add `tls_ciphers` command which prints the ciphersuites a client + hello will contain, depending on the policy specified. + +* Prevent TLS from negotiating SHA-2 ciphersuites in TLS v1.0/v1.1. These + ciphersuites are technically not defined except for v1.2, so disable + them in older protocols. (GH #496) + +* Documentation: add project goals (GH #788) and side channel info (GH #787) + +Older Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The release notes for versions 0.7.0 through 1.11.34 can be found in + ``doc/old_news.rst`` diff --git a/comm/third_party/botan/readme.rst b/comm/third_party/botan/readme.rst new file mode 100644 index 0000000000..019b772d58 --- /dev/null +++ b/comm/third_party/botan/readme.rst @@ -0,0 +1,135 @@ +Botan: Crypto and TLS for Modern C++ +======================================== + +Botan (Japanese for peony flower) is a C++ cryptography library released under the +permissive `Simplified BSD `_ license. + +Botan's goal is to be the best option for cryptography in C++ by offering the +tools necessary to implement a range of practical systems, such as TLS protocol, +X.509 certificates, modern AEAD ciphers, PKCS#11 and TPM hardware support, +password hashing, and post quantum crypto schemes. A Python binding is included, +and several other `language bindings +`_ are available. +It is used in many `open source and commercial products `_. +The library is accompanied by a featureful +`command line interface `_. + +See the `documentation `_ for more +information about included features. + +Development is coordinated on `GitHub `_ +and contributions are welcome. If you need help, please open an issue on +`GitHub `_ or email the +`botan-devel mailing list `_. +New releases are announced on the `botan-announce mailing list +`_. +If you think you have found a security issue, see the `security page +`_ for contact information. + +The latest release is +`2.18.2 `_ +`(sig) `_, +released on 2021-10-25. +All releases are signed with a `PGP key `_. +See the `release notes `_ for +what is new. Botan is also available through most +`distributions `_ +such as Fedora, Debian, Arch and Homebrew. + +.. image:: https://api.travis-ci.com/randombit/botan.svg?branch=master + :target: https://travis-ci.com/github/randombit/botan + :alt: Travis CI status + +.. image:: https://ci.appveyor.com/api/projects/status/n9f94dljd03j2lce/branch/master?svg=true + :target: https://ci.appveyor.com/project/randombit/botan/branch/master + :alt: AppVeyor CI status + +.. image:: https://codecov.io/github/randombit/botan/coverage.svg?branch=master + :target: https://codecov.io/github/randombit/botan + :alt: Code coverage report + +.. image:: https://img.shields.io/lgtm/alerts/g/randombit/botan.svg + :target: https://lgtm.com/projects/g/randombit/botan/alerts/ + :alt: LGTM alerts + +.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/botan.svg + :target: https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_botan/latest + :alt: OSS-Fuzz status + +.. image:: https://scan.coverity.com/projects/624/badge.svg + :target: https://scan.coverity.com/projects/624 + :alt: Coverity results + +.. image:: https://repology.org/badge/tiny-repos/botan.svg + :target: https://repology.org/project/botan/versions + :alt: Packaging status + +.. image:: https://bestpractices.coreinfrastructure.org/projects/531/badge + :target: https://bestpractices.coreinfrastructure.org/projects/531 + :alt: CII Best Practices statement + +Find Enclosed +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Transport Layer Security (TLS) Protocol +---------------------------------------- + +* TLS v1.0, v1.1, and v1.2. The broken SSLv3 protocol is no longer supported. +* DTLS v1.0 and v1.2 are adaptations of TLS to datagram operation. +* Supported extensions include session tickets, SNI, ALPN, OCSP stapling, + encrypt-then-mac CBC, and extended master secret. +* Supports authentication using preshared keys (PSK) or passwords (SRP) +* Supports record encryption with ChaCha20Poly1305, AES/OCB, AES/GCM, AES/CCM, + Camellia/GCM as well as legacy CBC ciphersuites. +* Key exchange using CECPQ1, ECDH, FFDHE, or RSA + +Public Key Infrastructure +---------------------------------------- + +* X.509v3 certificates and CRL creation and handling +* PKIX certificate path validation, including name constraints. +* OCSP request creation and response handling +* PKCS #10 certificate request generation and processing +* Access to Windows, macOS and Unix system certificate stores +* SQL database backed certificate store + +Public Key Cryptography +---------------------------------------- + +* RSA signatures and encryption +* DH and ECDH key agreement +* Signature schemes ECDSA, DSA, Ed25519, ECGDSA, ECKCDSA, SM2, GOST 34.10 +* Post-quantum signature scheme XMSS +* Post-quantum key agreement schemes McEliece and NewHope +* ElGamal encryption +* Padding schemes OAEP, PSS, PKCS #1 v1.5, X9.31 + +Ciphers, hashes, MACs, and checksums +---------------------------------------- + +* Authenticated cipher modes EAX, OCB, GCM, SIV, CCM, (X)ChaCha20Poly1305 +* Cipher modes CTR, CBC, XTS, CFB, OFB +* Block ciphers AES, ARIA, Blowfish, Camellia, CAST-128, DES/3DES, IDEA, + Lion, Noekeon, SEED, Serpent, SHACAL2, SM4, Threefish-512, Twofish +* Stream ciphers (X)ChaCha20, (X)Salsa20, SHAKE-128, RC4 +* Hash functions SHA-1, SHA-2, SHA-3, MD4, MD5, RIPEMD-160, BLAKE2b, + Skein-512, SM3, Streebog, Whirlpool +* Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, X9.19 DES-MAC +* Non-cryptographic checksums Adler32, CRC24, CRC32 + +Other Useful Things +---------------------------------------- + +* Full C++ PKCS #11 API wrapper +* Interfaces for TPM v1.2 device access +* Simple compression API wrapping zlib, bzip2, and lzma libraries +* RNG wrappers for system RNG and hardware RNGs +* HMAC_DRBG and entropy collection system for userspace RNGs +* Password hashing schemes PBKDF2, Argon2, Scrypt, bcrypt +* SRP-6a password authenticated key exchange +* Key derivation functions including HKDF, KDF2, SP 800-108, SP 800-56A, SP 800-56C +* HOTP and TOTP algorithms +* Format preserving encryption scheme FE1 +* Threshold secret sharing +* NIST key wrapping +* Boost.Asio compatible TLS client stream diff --git a/comm/third_party/botan/src/bogo_shim/bogo_shim.cpp b/comm/third_party/botan/src/bogo_shim/bogo_shim.cpp new file mode 100644 index 0000000000..1f09cd5fa4 --- /dev/null +++ b/comm/third_party/botan/src/bogo_shim/bogo_shim.cpp @@ -0,0 +1,1680 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +/* +* This is a shim for testing Botan against BoringSSL's test TLS stack (BoGo). +* +* Instructions on use should go here. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_SOCKETS) + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +namespace { + +int shim_output(const std::string& s, int rc = 0) + { + std::cout << s << "\n"; + return rc; + } + +void shim_log(const std::string& s) + { + if(::getenv("BOTAN_BOGO_SHIM_LOG")) + { + static FILE* log = std::fopen("/tmp/bogo_shim.log", "w"); + struct timeval tv; + ::gettimeofday(&tv, nullptr); + std::fprintf(log, "%lld.%lu: %s\n", static_cast(tv.tv_sec), tv.tv_usec, s.c_str()); + std::fflush(log); + } + } + +void BOTAN_NORETURN shim_exit_with_error(const std::string& s, int rc = 1) + { + shim_log("Exiting with " + s); + std::cerr << s << "\n"; + std::exit(rc); + } + +std::string map_to_bogo_error(const std::string& e) + { + shim_log("Original error " + e); + + static const std::unordered_map err_map + { + { "Application data before handshake done", ":APPLICATION_DATA_INSTEAD_OF_HANDSHAKE:" }, + { "Bad Hello_Request, has non-zero size", ":BAD_HELLO_REQUEST:" }, + { "Bad code for TLS alert level", ":UNKNOWN_ALERT_TYPE:" }, + { "Bad extension size", ":DECODE_ERROR:" }, + { "Bad length in hello verify request", ":DECODE_ERROR:" }, + { "Bad lengths in DTLS header", ":BAD_HANDSHAKE_RECORD:" }, + { "Bad signature on server key exchange", ":BAD_SIGNATURE:" }, + { "Bad size (1) for TLS alert message", ":BAD_ALERT:" }, + { "Bad size (4) for TLS alert message", ":BAD_ALERT:" }, + { "CERTIFICATE decoding failed with PEM: No PEM header found", ":CANNOT_PARSE_LEAF_CERT:" }, + { "Can't agree on a ciphersuite with client", ":NO_SHARED_CIPHER:" }, + { "Can't interleave application and handshake data", ":UNEXPECTED_RECORD:" }, + { "Certificate chain exceeds policy specified maximum size", ":EXCESSIVE_MESSAGE_SIZE:" }, + { "Certificate key type did not match ciphersuite", ":WRONG_CERTIFICATE_TYPE:" }, + { "Certificate usage constraints do not allow this ciphersuite", ":KEY_USAGE_BIT_INCORRECT:" }, + { "Certificate: Message malformed", ":DECODE_ERROR:" }, + { "Channel::key_material_export cannot export during renegotiation", "failed to export keying material" }, + { "Client cert verify failed", ":BAD_SIGNATURE:" }, + { "Client did not offer NULL compression", ":INVALID_COMPRESSION_LIST:" }, + { "Client offered TLS version with major version under 3", ":UNSUPPORTED_PROTOCOL:" }, + { "Client offered DTLS version with major version 0xFF", ":UNSUPPORTED_PROTOCOL:" }, + { "Client policy prohibits insecure renegotiation", ":RENEGOTIATION_MISMATCH:" }, + { "Client policy prohibits renegotiation", ":NO_RENEGOTIATION:" }, + { "Client resumed extended ms session without sending extension", ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" }, + { "Client signalled fallback SCSV, possible attack", ":INAPPROPRIATE_FALLBACK:" }, + { "Client version DTLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" }, + { "Client version TLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" }, + { "Client version TLS v1.1 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" }, + { "Client: No certificates sent by server", ":DECODE_ERROR:" }, + { "Counterparty sent inconsistent key and sig types", ":WRONG_SIGNATURE_TYPE:" }, + { "Downgrade attack detected", ":TLS13_DOWNGRADE:" }, + { "Empty ALPN protocol not allowed", ":PARSE_TLSEXT:" }, + { "Encoding error: Cannot encode PSS string, output length too small", ":NO_COMMON_SIGNATURE_ALGORITHMS:" }, + { "Expected TLS but got a record with DTLS version", ":WRONG_VERSION_NUMBER:" }, + { "Finished message didn't verify", ":DIGEST_CHECK_FAILED:" }, + { "Got unexpected TLS record version", ":WRONG_VERSION_NUMBER:" }, + { "Inconsistent length in certificate request", ":DECODE_ERROR:" }, + { "Inconsistent values in fragmented DTLS handshake header", ":FRAGMENT_MISMATCH:" }, + { "Invalid CertificateRequest: Length field outside parameters", ":DECODE_ERROR:" }, + { "Invalid CertificateVerify: Extra bytes at end of message", ":DECODE_ERROR:" }, + { "Invalid Certificate_Status: invalid length field", ":DECODE_ERROR:" }, + { "Invalid ChangeCipherSpec", ":BAD_CHANGE_CIPHER_SPEC:" }, + { "Invalid ClientHello: Length field outside parameters", ":DECODE_ERROR:" }, + { "Invalid ClientKeyExchange: Extra bytes at end of message", ":DECODE_ERROR:" }, + { "Invalid ServerKeyExchange: Extra bytes at end of message", ":DECODE_ERROR:" }, + { "Invalid SessionTicket: Extra bytes at end of message", ":DECODE_ERROR:" }, + { "Invalid authentication tag: ChaCha20Poly1305 tag check failed", ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:" }, + { "Invalid authentication tag: GCM tag check failed", ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:" }, + { "Message authentication failure", ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:" }, + { "No shared TLS version", ":UNSUPPORTED_PROTOCOL:" }, + { "No shared DTLS version", ":UNSUPPORTED_PROTOCOL:" }, + { "OS2ECP: Unknown format type 251", ":BAD_ECPOINT:" }, + { "Policy forbids all available TLS version", ":NO_SUPPORTED_VERSIONS_ENABLED:" }, + { "Policy forbids all available DTLS version", ":NO_SUPPORTED_VERSIONS_ENABLED:" }, + { "Policy refuses to accept signing with any hash supported by peer", ":NO_COMMON_SIGNATURE_ALGORITHMS:" }, + { "Policy requires client send a certificate, but it did not", ":PEER_DID_NOT_RETURN_A_CERTIFICATE:" }, + { "Received a record that exceeds maximum size", ":ENCRYPTED_LENGTH_TOO_LONG:" }, + { "Received unexpected record version in initial record", ":WRONG_VERSION_NUMBER:" }, + { "Received unexpected record version", ":WRONG_VERSION_NUMBER:" }, + { "Received application data after connection closure", ":APPLICATION_DATA_ON_SHUTDOWN:" }, + { "Received handshake data after connection closure", ":NO_RENEGOTIATION:" }, + { "Server certificate changed during renegotiation", ":SERVER_CERT_CHANGED:" }, + { "Server changed its mind about extended master secret", ":RENEGOTIATION_EMS_MISMATCH:" }, + { "Server changed its mind about secure renegotiation", ":RENEGOTIATION_MISMATCH:" }, + { "Server changed version after renegotiation", ":WRONG_SSL_VERSION:" }, + { "Server downgraded version after renegotiation", ":WRONG_SSL_VERSION:" }, + { "Server policy prohibits renegotiation", ":NO_RENEGOTIATION:" }, + { "Server replied using a ciphersuite not allowed in version it offered", ":WRONG_CIPHER_RETURNED:" }, + { "Server replied with DTLS-SRTP alg we did not send", ":BAD_SRTP_PROTECTION_PROFILE_LIST:" }, + { "Server replied with ciphersuite we didn't send", ":WRONG_CIPHER_RETURNED:" }, + { "Server replied with later version than client offered", ":UNSUPPORTED_PROTOCOL:" }, + { "Server replied with non-null compression method", ":UNSUPPORTED_COMPRESSION_ALGORITHM:" }, + { "Server replied with some unknown ciphersuite", ":UNKNOWN_CIPHER_RETURNED:" }, + { "Server replied with unsupported extensions: 0", ":UNEXPECTED_EXTENSION:" }, + { "Server replied with unsupported extensions: 1234", ":UNEXPECTED_EXTENSION:" }, + { "Server replied with unsupported extensions: 16", ":UNEXPECTED_EXTENSION:" }, + { "Server replied with unsupported extensions: 43", ":UNEXPECTED_EXTENSION:" }, + { "Server replied with unsupported extensions: 5", ":UNEXPECTED_EXTENSION:" }, + { "Server resumed session and removed extended master secret", ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" }, + { "Server resumed session but added extended master secret", ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:" }, + { "Server resumed session but with wrong version", ":OLD_SESSION_VERSION_NOT_RETURNED:" }, + { "Server sent ECC curve prohibited by policy", ":WRONG_CURVE:" }, + { "Server sent an unsupported extension", ":UNEXPECTED_EXTENSION:" }, + { "Server sent bad values for secure renegotiation", ":RENEGOTIATION_MISMATCH:" }, + { "Server version DTLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" }, + { "Server version TLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" }, + { "Server version TLS v1.1 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" }, + { "Server_Hello_Done: Must be empty, and is not", ":DECODE_ERROR:" }, + { "Simulated OCSP callback failure", ":OCSP_CB_ERROR:" }, + { "Simulating cert verify callback failure", ":CERT_CB_ERROR:" }, + { "Simulating failure from OCSP response callback", ":OCSP_CB_ERROR:" }, + { "TLS plaintext record is larger than allowed maximum", ":DATA_LENGTH_TOO_LONG:" }, + { "TLS signature extension did not allow for RSA/SHA-256 signature", ":WRONG_SIGNATURE_TYPE:", }, + { "Test requires rejecting cert", ":CERTIFICATE_VERIFY_FAILED:" }, + { "Unexpected ALPN protocol", ":INVALID_ALPN_PROTOCOL:" }, + { "Unexpected record type 42 from counterparty", ":UNEXPECTED_RECORD:" }, + + { "Unexpected state transition in handshake got a certificate_request expected server_hello_done seen server_hello+server_key_exchange", ":UNEXPECTED_MESSAGE:" }, + { "Unexpected state transition in handshake got a certificate_request expected server_key_exchange|server_hello_done seen server_hello", ":UNEXPECTED_MESSAGE:" }, + { "Unexpected state transition in handshake got a certificate_status expected certificate seen server_hello", ":UNEXPECTED_MESSAGE:" }, + { "Unexpected state transition in handshake got a change_cipher_spec expected certificate_verify seen client_hello+certificate+client_key_exchange", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a change_cipher_spec expected client_key_exchange seen client_hello", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a change_cipher_spec expected new_session_ticket seen server_hello+certificate+certificate_status+server_key_exchange+server_hello_done", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a client_key_exchange expected certificate seen client_hello", ":UNEXPECTED_MESSAGE:" }, + { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen client_hello", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen client_hello+client_key_exchange", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen server_hello", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen server_hello+certificate+certificate_status+server_key_exchange+server_hello_done+new_session_ticket", ":UNEXPECTED_RECORD:" }, + { "Unexpected state transition in handshake got a hello_request expected server_hello", ":UNEXPECTED_MESSAGE:" }, + { "Unexpected state transition in handshake got a server_hello_done expected server_key_exchange seen server_hello+certificate+certificate_status", ":UNEXPECTED_MESSAGE:" }, + { "Unexpected state transition in handshake got a server_key_exchange not expecting messages", ":BAD_HELLO_REQUEST:" }, + { "Unexpected state transition in handshake got a server_key_exchange expected certificate_request|server_hello_done seen server_hello+certificate+certificate_status", ":UNEXPECTED_MESSAGE:" }, + + { "Unknown TLS handshake message type 43", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 44", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 45", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 46", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 53", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 54", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 55", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 56", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 57", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 58", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 6", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 62", ":UNEXPECTED_MESSAGE:" }, + { "Unknown TLS handshake message type 64", ":UNEXPECTED_MESSAGE:" }, + { "signature_algorithm_of_scheme: Unknown signature algorithm enum", ":WRONG_SIGNATURE_TYPE:" }, + }; + + auto err_map_i = err_map.find(e); + if(err_map_i != err_map.end()) + return err_map_i->second; + + return "Unmapped error: '" + e + "'"; + } + +class Shim_Exception final : public std::exception + { + public: + Shim_Exception(const std::string& msg, int rc = 1) : + m_msg(msg), m_rc(rc) {} + + const char* what() const noexcept override { return m_msg.c_str(); } + + int rc() const { return m_rc; } + private: + const std::string m_msg; + int m_rc; + }; + +#if defined(BOTAN_TARGET_OS_HAS_SOCKETS) + +class Shim_Socket final + { + private: + typedef int socket_type; + typedef ssize_t socket_op_ret_type; + static void close_socket(socket_type s) { ::close(s); } + static std::string get_last_socket_error() { return ::strerror(errno); } + + public: + Shim_Socket(const std::string& hostname, int port) : m_socket(-1) + { + addrinfo hints; + std::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + addrinfo* res; + + const std::string service = std::to_string(port); + int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res); + shim_log("Connecting " + hostname + ":" + service); + + if(rc != 0) + { + throw Shim_Exception("Name resolution failed for " + hostname); + } + + for(addrinfo* rp = res; (m_socket == -1) && (rp != nullptr); rp = rp->ai_next) + { + if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) + continue; + + m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + if(m_socket == -1) + { + // unsupported socket type? + continue; + } + + int err = ::connect(m_socket, rp->ai_addr, rp->ai_addrlen); + + if(err != 0) + { + ::close(m_socket); + m_socket = -1; + } + } + + if(m_socket < 0) + throw Shim_Exception("Failed to connect to host"); + } + + ~Shim_Socket() + { + ::close(m_socket); + m_socket = -1; + } + + void write(const uint8_t buf[], size_t len) + { + if(m_socket < 0) + throw Shim_Exception("Socket was bad on write"); + size_t sent_so_far = 0; + while(sent_so_far != len) + { + const size_t left = len - sent_so_far; + socket_op_ret_type sent = ::send(m_socket, Botan::cast_uint8_ptr_to_char(&buf[sent_so_far]), left, MSG_NOSIGNAL); + if(sent < 0) + { + if(errno == EPIPE) + return; + else + throw Shim_Exception("Socket write failed", errno); + } + else + sent_so_far += static_cast(sent); + } + } + + size_t read(uint8_t buf[], size_t len) + { + if(m_socket < 0) + throw Shim_Exception("Socket was bad on read"); + socket_op_ret_type got = ::read(m_socket, Botan::cast_uint8_ptr_to_char(buf), len); + + if(got < 0) + { + if(errno == ECONNRESET) + return 0; + throw Shim_Exception("Socket read failed: " + std::string(strerror(errno))); + } + + return static_cast(got); + } + + void read_exactly(uint8_t buf[], size_t len) + { + if(m_socket < 0) + throw Shim_Exception("Socket was bad on read"); + + while(len > 0) + { + socket_op_ret_type got = ::read(m_socket, Botan::cast_uint8_ptr_to_char(buf), len); + + if(got == 0) + throw Shim_Exception("Socket read EOF"); + else if(got < 0) + throw Shim_Exception("Socket read failed: " + std::string(strerror(errno))); + + buf += static_cast(got); + len -= static_cast(got); + } + } + + private: + socket_type m_socket; + }; + +#endif + +std::set combine_options( + const std::set& a, + const std::set& b, + const std::set& c, + const std::set& d) + { + std::set combined; + + for(auto i : a) + combined.insert(i); + for(auto i : b) + combined.insert(i); + for(auto i : c) + combined.insert(i); + for(auto i : d) + combined.insert(i); + + return combined; + } + +class Shim_Arguments final + { + public: + Shim_Arguments(const std::set& flags, + const std::set& string_opts, + const std::set& base64_opts, + const std::set& int_opts, + const std::set& int_vec_opts) : + m_flags(flags), + m_string_opts(string_opts), + m_base64_opts(base64_opts), + m_int_opts(int_opts), + m_int_vec_opts(int_vec_opts), + m_all_options(combine_options(string_opts, base64_opts, int_opts, int_vec_opts)) + {} + + void parse_args(char* argv[]); + + bool flag_set(const std::string& flag) const + { + if(m_flags.count(flag) == 0) + throw Shim_Exception("Unknown bool flag " + flag); + + return m_parsed_flags.count(flag); + } + + std::string test_name() const + { + return get_string_opt("test-name"); + } + + std::string get_string_opt(const std::string& key) const + { + if(m_string_opts.count(key) == 0) + throw Shim_Exception("Unknown string key " + key); + return get_opt(key); + } + + std::string get_string_opt_or_else(const std::string& key, const std::string& def) const + { + if(m_string_opts.count(key) == 0) + throw Shim_Exception("Unknown string key " + key); + if(!option_used(key)) + return def; + return get_opt(key); + } + + std::vector get_b64_opt(const std::string& key) const + { + if(m_base64_opts.count(key) == 0) + throw Shim_Exception("Unknown base64 key " + key); + return Botan::unlock(Botan::base64_decode(get_opt(key))); + } + + size_t get_int_opt(const std::string& key) const + { + if(m_int_opts.count(key) == 0) + throw Shim_Exception("Unknown int key " + key); + return Botan::to_u32bit(get_opt(key)); + } + + size_t get_int_opt_or_else(const std::string& key, size_t def) const + { + if(m_int_opts.count(key) == 0) + throw Shim_Exception("Unknown int key " + key); + if(!option_used(key)) + return def; + + return Botan::to_u32bit(get_opt(key)); + } + + std::vector get_int_vec_opt(const std::string& key) const + { + if(m_int_vec_opts.count(key) == 0) + throw Shim_Exception("Unknown int vec key " + key); + + auto i = m_parsed_int_vec_opts.find(key); + if(i == m_parsed_int_vec_opts.end()) + return std::vector(); + else + return i->second; + } + + std::vector get_alpn_string_vec_opt(const std::string& option) const + { + // hack used for alpn list (relies on all ALPNs being 3 chars long...) + char delim = 0x03; + + if(option_used(option)) + return Botan::split_on(get_string_opt(option), delim); + else + return std::vector(); + } + + bool option_used(const std::string& key) const + { + if(m_all_options.count(key) == 0) + throw Shim_Exception("Invalid option " + key); + if(m_parsed_opts.find(key) != m_parsed_opts.end()) + return true; + if(m_parsed_int_vec_opts.find(key) != m_parsed_int_vec_opts.end()) + return true; + return false; + } + + private: + std::string get_opt(const std::string& key) const + { + auto i = m_parsed_opts.find(key); + if(i == m_parsed_opts.end()) + throw Shim_Exception("Option " + key + " was not provided"); + return i->second; + } + + const std::set m_flags; + const std::set m_string_opts; + const std::set m_base64_opts; + const std::set m_int_opts; + const std::set m_int_vec_opts; + const std::set m_all_options; + + std::set m_parsed_flags; + std::map m_parsed_opts; + std::map> m_parsed_int_vec_opts; + }; + +void Shim_Arguments::parse_args(char* argv[]) + { + int i = 1; // skip argv[0] + + while(argv[i] != nullptr) + { + const std::string param(argv[i]); + + if(param.find("-") == 0) + { + const std::string flag_name = param.substr(1, std::string::npos); + + if(m_flags.count(flag_name)) + { + shim_log("flag " + flag_name); + m_parsed_flags.insert(flag_name); + i += 1; + } + else if(m_all_options.count(flag_name)) + { + if(argv[i+1] == nullptr) + throw Shim_Exception("Expected argument following " + param); + std::string val(argv[i+1]); + shim_log("param " + flag_name + "=" + val); + + if(m_int_vec_opts.count(flag_name)) + { + const size_t v = Botan::to_u32bit(val); + m_parsed_int_vec_opts[flag_name].push_back(v); + } + else + { + m_parsed_opts[flag_name] = val; + } + i += 2; + } + else + { + shim_log("Unknown option " + param); + throw Shim_Exception("Unknown option " + param, 89); + } + } + else + { + shim_log("Unknown option " + param); + throw Shim_Exception("Unknown option " + param, 89); + } + } + } + +std::unique_ptr parse_options(char* argv[]) + { + const std::set bogo_shim_flags = { + "allow-false-start-without-alpn", + "allow-unknown-alpn-protos", + "async", + "cbc-record-splitting", + "check-close-notify", + "decline-alpn", + "decline-ocsp-callback", + "dtls", + "enable-all-curves", + "enable-channel-id", + "enable-early-data", + "enable-ed25519", + "enable-grease", + "enable-ocsp-stapling", + "enable-signed-cert-timestamps", + "enforce-rsa-key-usage", + //"expect-accept-early-data", + "expect-extended-master-secret", + "expect-no-offer-early-data", + "expect-no-secure-renegotiation", + "expect-no-session", + "expect-no-session-id", + //"expect-reject-early-data", + "expect-secure-renegotiation", + "expect-session-id", + "expect-session-miss", + "expect-sha256-client-cert", + "expect-ticket-renewal", + "expect-ticket-supports-early-data", + //"expect-tls13-downgrade", + "expect-verify-result", + "expect-no-hrr", + //"export-traffic-secrets", + "fail-cert-callback", + //"fail-ddos-callback", + //"fail-early-callback", + "fail-ocsp-callback", + "fallback-scsv", + //"false-start", + "forbid-renegotiation-after-handshake", + "handoff", + "handshake-never-done", + "handshake-twice", + "handshaker-resume", + //"ignore-tls13-downgrade", + "implicit-handshake", + "install-cert-compression-algs", + "install-ddos-callback", + "is-handshaker-supported", + //"jdk11-workaround", + //"key-update", + "no-op-extra-handshake", + "no-rsa-pss-rsae-certs", + "no-ticket", + "no-tls1", + "no-tls11", + "no-tls12", + "no-tls13", // implict due to 1.3 not being implemented + "on-resume-no-ticket", + //"on-resume-verify-fail", + //"partial-write", + //"peek-then-read", + //"read-with-unfinished-write", + "renegotiate-freely", + "renegotiate-ignore", + "renegotiate-once", + //"renew-ticket", + "require-any-client-certificate", + "retain-only-sha256-client-cert", + //"reverify-on-resume", + "select-empty-alpn", + "send-alert", + "server", + "server-preference", + "set-ocsp-in-callback", + "shim-shuts-down", + "shim-writes-first", + //"tls-unique", + "use-custom-verify-callback", + "use-early-callback", + "use-export-context", + "use-exporter-between-reads", + "use-ocsp-callback", + //"use-old-client-cert-callback", + //"use-ticket-callback", + "verify-fail", + "verify-peer", + //"verify-peer-if-no-obc", + "write-different-record-sizes", + }; + + const std::set bogo_shim_string_opts = { + "advertise-alpn", + //"advertise-npn", + "cert-file", + "cipher", + //"delegated-credential", + "expect-advertised-alpn", + "expect-alpn", + "expect-client-ca-list", + "expect-late-alpn", + "expect-msg-callback", + //"expect-next-proto", + "expect-peer-cert-file", + "expect-server-name", + "export-context", + "export-label", + "handshaker-path", + "host-name", + "key-file", + "psk", + "psk-identity", + "select-alpn", + "select-next-proto", + "srtp-profiles", + "test-name", + "use-client-ca-list", + //"send-channel-id", + //"write-settings", + }; + + const std::set bogo_shim_base64_opts = { + "expect-certificate-types", + //"expect-channel-id", + "expect-ocsp-response", + //"expect-quic-transport-params", + //"expect-signed-cert-timestamps", + "ocsp-response", + //"quic-transport-params", + //"signed-cert-timestamps", + //"ticket-key", /* we use a different ticket format from Boring */ + //"token-binding-params", + }; + + const std::set bogo_shim_int_opts { + "expect-cipher-aes", + "expect-cipher-no-aes", + "expect-curve-id", + "expect-peer-signature-algorithm", + "expect-ticket-age-skew", + "expect-token-binding-param", + "expect-total-renegotiations", + "expect-version", + //"export-early-keying-material", + "export-keying-material", + "initial-timeout-duration-ms", + "max-cert-list", + //"max-send-fragment", + "max-version", + "min-version", + "mtu", + "port", + "read-size", + "resume-count", + "resumption-delay", + }; + + const std::set bogo_shim_int_vec_opts { + "curves", + "expect-peer-verify-pref", + "signing-prefs", + "verify-prefs", + }; + + std::unique_ptr args( + new Shim_Arguments(bogo_shim_flags, + bogo_shim_string_opts, + bogo_shim_base64_opts, + bogo_shim_int_opts, + bogo_shim_int_vec_opts)); + + // may throw: + args->parse_args(argv); + + return args; + } + +class Shim_Policy final : public Botan::TLS::Policy + { + public: + Shim_Policy(const Shim_Arguments& args) : m_args(args), m_sessions(0) {} + + void incr_session_established() { m_sessions += 1; } + + std::vector allowed_ciphers() const override + { + return { + "AES-256/OCB(12)", + "AES-128/OCB(12)", + "ChaCha20Poly1305", + "AES-256/GCM", + "AES-128/GCM", + "AES-256/CCM", + "AES-128/CCM", + "AES-256/CCM(8)", + "AES-128/CCM(8)", + "Camellia-256/GCM", + "Camellia-128/GCM", + "ARIA-256/GCM", + "ARIA-128/GCM", + "AES-256", + "AES-128", + "Camellia-256", + "Camellia-128", + "SEED", + "3DES", + }; + + } + + std::vector allowed_signature_hashes() const override + { + if(m_args.option_used("signing-prefs")) + { + std::vector pref_hash; + for(size_t pref : m_args.get_int_vec_opt("signing-prefs")) + { + const auto scheme = static_cast(pref); + if(Botan::TLS::signature_scheme_is_known(scheme) == false) + continue; + pref_hash.push_back(Botan::TLS::hash_function_of_scheme(scheme)); + } + + if(m_args.flag_set("server")) + pref_hash.push_back("SHA-256"); + return pref_hash; + } + else + { + return { "SHA-512", "SHA-384", "SHA-256", "SHA-1" }; + } + } + + //std::vector allowed_macs() const override; + + std::vector allowed_key_exchange_methods() const override + { + return { + "ECDHE_PSK", + "DHE_PSK", + "PSK", + "CECPQ1", + "ECDH", + "DH", + "RSA", + }; + } + + std::vector allowed_signature_methods() const override + { + return { + "ECDSA", + "RSA", + "IMPLICIT", + }; + + } + + std::vector allowed_signature_schemes() const override + { + if(m_args.option_used("signing-prefs")) + { + std::vector schemes; + for(size_t pref : m_args.get_int_vec_opt("signing-prefs")) + { + schemes.push_back(static_cast(pref)); + } + + // BoGo gets sad if these are not included in our signature_algorithms extension + if(!m_args.flag_set("server")) + { + schemes.push_back(Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA256); + schemes.push_back(Botan::TLS::Signature_Scheme::ECDSA_SHA256); + } + + return schemes; + } + + if(m_args.option_used("verify-prefs")) + { + std::vector schemes; + for(size_t pref : m_args.get_int_vec_opt("verify-prefs")) + { + schemes.push_back(static_cast(pref)); + } + + return schemes; + } + + return Botan::TLS::Policy::allowed_signature_schemes(); + } + + //size_t minimum_signature_strength() const override; + + //bool require_cert_revocation_info() const override; + + std::vector key_exchange_groups() const override + { + if(m_args.option_used("curves")) + { + std::vector groups; + for(size_t pref : m_args.get_int_vec_opt("curves")) + { + groups.push_back(static_cast(pref)); + } + + return groups; + } + + return Botan::TLS::Policy::key_exchange_groups(); + } + + bool use_ecc_point_compression() const override { return false; } // BoGo expects this + + //Botan::TLS::Group_Params choose_key_exchange_group(const std::vector& peer_groups) const override; + + bool require_client_certificate_authentication() const override + { + return m_args.flag_set("require-any-client-certificate"); + } + + bool request_client_certificate_authentication() const override + { + return m_args.flag_set("verify-peer") || + m_args.flag_set("fail-cert-callback") || + require_client_certificate_authentication(); + } + + bool allow_insecure_renegotiation() const override + { + if(m_args.flag_set("expect-no-secure-renegotiation")) + return true; + else + return false; + } + + //bool include_time_in_hello_random() const override; + + bool allow_client_initiated_renegotiation() const override + { + if(m_args.flag_set("renegotiate-freely")) + return true; + + if(m_args.flag_set("renegotiate-once") && m_sessions <= 1) + return true; + + return false; + } + + bool allow_server_initiated_renegotiation() const override + { + return allow_client_initiated_renegotiation(); // same logic + } + + bool allow_version(Botan::TLS::Protocol_Version version) const + { + if(m_args.option_used("min-version")) + { + const uint16_t min_version_16 = static_cast(m_args.get_int_opt("min-version")); + Botan::TLS::Protocol_Version min_version(min_version_16 >> 8, min_version_16 & 0xFF); + if(min_version > version) + return false; + } + + if(m_args.option_used("max-version")) + { + const uint16_t max_version_16 = static_cast(m_args.get_int_opt("max-version")); + Botan::TLS::Protocol_Version max_version(max_version_16 >> 8, max_version_16 & 0xFF); + if(version > max_version) + return false; + } + + return version.known_version(); + } + + bool allow_tls10() const override + { + return !m_args.flag_set("dtls") && + !m_args.flag_set("no-tls1") && + allow_version(Botan::TLS::Protocol_Version::TLS_V10); + } + + bool allow_tls11() const override + { + return !m_args.flag_set("dtls") && !m_args.flag_set("no-tls11") && allow_version(Botan::TLS::Protocol_Version::TLS_V11); + } + + bool allow_tls12() const override + { + return !m_args.flag_set("dtls") && !m_args.flag_set("no-tls12") && allow_version(Botan::TLS::Protocol_Version::TLS_V12); + } + + bool allow_dtls10() const override + { + return m_args.flag_set("dtls") && !m_args.flag_set("no-tls1") && allow_version(Botan::TLS::Protocol_Version::DTLS_V10); + } + + bool allow_dtls12() const override + { + return m_args.flag_set("dtls") && !m_args.flag_set("no-tls12") && allow_version(Botan::TLS::Protocol_Version::DTLS_V12); + } + + //Botan::TLS::Group_Params default_dh_group() const override; + + //size_t minimum_dh_group_size() const override; + + size_t minimum_ecdsa_group_size() const override { return 224; } + + size_t minimum_ecdh_group_size() const override { return 224; } + + //size_t minimum_rsa_bits() const override; + + //size_t minimum_dsa_group_size() const override; + + //void check_peer_key_acceptable(const Botan::Public_Key& public_key) const override; + + //bool hide_unknown_users() const override; + + //uint32_t session_ticket_lifetime() const override; + + std::vector srtp_profiles() const override + { + if(m_args.option_used("srtp-profiles")) + { + std::string srtp = m_args.get_string_opt("srtp-profiles"); + + if(srtp == "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + return {1,2}; + else if(srtp == "SRTP_AES128_CM_SHA1_80") + return {1}; + else + shim_exit_with_error("unknown srtp-profiles"); + } + else + return {}; + } + + bool only_resume_with_exact_version() const override + { + return false; + } + + bool send_fallback_scsv(Botan::TLS::Protocol_Version) const override + { + return m_args.flag_set("fallback-scsv"); + } + + //bool server_uses_own_ciphersuite_preferences() const override; + + //bool negotiate_encrypt_then_mac() const override; + + bool support_cert_status_message() const override + { + if(m_args.flag_set("server")) + { + if(!m_args.option_used("ocsp-response")) + return false; + if(m_args.flag_set("decline-ocsp-callback")) + return false; + } + return true; + } + + std::vector ciphersuite_list(Botan::TLS::Protocol_Version version, + bool have_srp) const override; + + size_t dtls_default_mtu() const override + { + return m_args.get_int_opt_or_else("mtu", 1500); + } + + //size_t dtls_initial_timeout() const override; + + //size_t dtls_maximum_timeout() const override; + + bool allow_resumption_for_renegotiation() const override + { + return false; // BoGo expects this + } + + bool abort_connection_on_undesired_renegotiation() const override + { + if(m_args.flag_set("renegotiate-ignore")) + return false; + else + return true; + } + + size_t maximum_certificate_chain_size() const override + { + return m_args.get_int_opt_or_else("max-cert-list", 0); + } + + private: + const Shim_Arguments& m_args; + size_t m_sessions; + }; + +std::vector Shim_Policy::ciphersuite_list(Botan::TLS::Protocol_Version version, + bool have_srp) const + { + std::vector ciphersuite_codes; + + const std::string cipher_limit = m_args.get_string_opt_or_else("cipher", ""); + if(cipher_limit == "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:[TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384|TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256|TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_128_CBC_SHA:[TLS_RSA_WITH_AES_256_GCM_SHA384|TLS_RSA_WITH_AES_256_CBC_SHA]") + { + std::vector suites = { + "ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "ECDHE_RSA_WITH_AES_256_CBC_SHA", + "RSA_WITH_AES_256_GCM_SHA384", + "RSA_WITH_AES_256_CBC_SHA", + }; + + for(auto suite_name : suites) + { + const auto suite = Botan::TLS::Ciphersuite::from_name(suite_name); + if(suite.valid() == false) + shim_exit_with_error("Bad ciphersuite name " + suite_name); + ciphersuite_codes.push_back(suite.ciphersuite_code()); + } + } + else + { + // Hack: go in reverse order to avoid preferring 3DES + auto ciphersuites = Botan::TLS::Ciphersuite::all_known_ciphersuites(); + for(auto i = ciphersuites.rbegin(); i != ciphersuites.rend(); ++i) + { + const auto suite = *i; + // Can we use it? + if(suite.valid() == false) + continue; + + // Are we doing SRP? + if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA) + continue; + + if(cipher_limit != "") + { + if(cipher_limit == "DEFAULT:!AES") + { + const std::string suite_algo = suite.cipher_algo(); + + if(suite_algo == "AES-128" || suite_algo == "AES-256" || + suite_algo == "AES-128/GCM" || suite_algo == "AES-256/GCM" || + suite_algo == "AES-128/CCM" || suite_algo == "AES-256/CCM" || + suite_algo == "AES-128/CCM(8)" || suite_algo == "AES-256/CCM(8)" || + suite_algo == "AES-128/OCB(12)" || suite_algo == "AES-256/OCB(12)") + { + continue; + } + } + else + { + shim_exit_with_error("Unknown cipher " + cipher_limit); + } + } + + if(!version.supports_aead_modes()) + { + // Are we doing AEAD in a non-AEAD version? + if(suite.mac_algo() == "AEAD") + continue; + + // Older (v1.0/v1.1) versions also do not support any hash but SHA-1 + if(suite.mac_algo() != "SHA-1") + continue; + } + + ciphersuite_codes.push_back(suite.ciphersuite_code()); + } + } + + return ciphersuite_codes; + } + +class Shim_Credentials final : public Botan::Credentials_Manager + { + public: + Shim_Credentials(const Shim_Arguments& args) : m_args(args) + { + m_psk_identity = m_args.get_string_opt_or_else("psk-identity", ""); + + const std::string psk_str = m_args.get_string_opt_or_else("psk", ""); + m_psk = Botan::SymmetricKey(reinterpret_cast(psk_str.data()), psk_str.size()); + + if(m_args.option_used("key-file") && m_args.option_used("cert-file")) + { + Botan::DataSource_Stream key_stream(m_args.get_string_opt("key-file")); + m_key = Botan::PKCS8::load_key(key_stream); + + Botan::DataSource_Stream cert_stream(m_args.get_string_opt("cert-file")); + + while(!cert_stream.end_of_data()) + { + try + { + m_cert_chain.push_back(Botan::X509_Certificate(cert_stream)); + } + catch(...) {} + } + } + } + + std::string psk_identity(const std::string& /*type*/, + const std::string& /*context*/, + const std::string& /*identity_hint*/) override + { + return m_psk_identity; + } + + std::string psk_identity_hint(const std::string& /*type*/, + const std::string& /*context*/) override + { + return m_psk_identity; + } + + Botan::SymmetricKey psk(const std::string& type, + const std::string& context, + const std::string& identity) override + { + if(type == "tls-server" && context == "session-ticket") + { + if(!m_args.flag_set("no-ticket") && !m_args.flag_set("on-resume-no-ticket")) + return Botan::SymmetricKey("ABCDEF0123456789"); + } + + if(type == "tls-server" && context == "dtls-cookie-secret") + { + return Botan::SymmetricKey("F00FB00FD00F100F700F"); + } + + if(identity != m_psk_identity) + throw Shim_Exception("Unexpected PSK identity"); + return m_psk; + } + + std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& /*type*/, + const std::string& /*context*/) override + { + if(m_args.flag_set("fail-cert-callback")) + throw std::runtime_error("Simulating cert verify callback failure"); + + if(m_key != nullptr && m_cert_chain.size() > 0) + { + for(std::string t : cert_key_types) + { + if(t == m_key->algo_name()) + return m_cert_chain; + } + } + + return {}; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& /*cert*/, + const std::string& /*type*/, + const std::string& /*context*/) override + { + // assumes cert == m_cert + return m_key.get(); + } + + private: + const Shim_Arguments& m_args; + Botan::SymmetricKey m_psk; + std::string m_psk_identity; + std::unique_ptr m_key; + std::vector m_cert_chain; + }; + +class Shim_Callbacks final : public Botan::TLS::Callbacks + { + public: + Shim_Callbacks(const Shim_Arguments& args, Shim_Socket& socket, Shim_Policy& policy) : + m_channel(nullptr), + m_args(args), + m_policy(policy), + m_socket(socket), + m_is_datagram(args.flag_set("dtls")), + m_warning_alerts(0), + m_empty_records(0), + m_sessions_established(0), + m_got_close(false) + {} + + size_t sessions_established() const { return m_sessions_established; } + + void set_channel(Botan::TLS::Channel* channel) + { + m_channel = channel; + } + + bool saw_close_notify() const { return m_got_close; } + + void tls_emit_data(const uint8_t data[], size_t size) override + { + shim_log("sending record of len " + std::to_string(size)); + + if(m_is_datagram) + { + std::vector packet(size + 5); + + packet[0] = 'P'; + for(size_t i = 0; i != 4; ++i) + packet[i+1] = static_cast((size >> (24-8*i)) & 0xFF); + std::memcpy(packet.data() + 5, data, size); + + m_socket.write(packet.data(), packet.size()); + } + else + { + m_socket.write(data, size); + } + } + + std::vector tls_provide_cert_status(const std::vector&, + const Botan::TLS::Certificate_Status_Request&) override + { + if(m_args.flag_set("use-ocsp-callback") && m_args.flag_set("fail-ocsp-callback")) + throw std::runtime_error("Simulating failure from OCSP response callback"); + + if(m_args.flag_set("decline-ocsp-callback")) + return {}; + + if(m_args.option_used("ocsp-response")) + { + return m_args.get_b64_opt("ocsp-response"); + } + + return {}; + } + + void tls_record_received(uint64_t /*seq_no*/, const uint8_t data[], size_t size) override + { + if(size == 0) + { + m_empty_records += 1; + if(m_empty_records > 32) + shim_exit_with_error(":TOO_MANY_EMPTY_FRAGMENTS:"); + } + else + { + m_empty_records = 0; + } + + shim_log("Reflecting application_data len " + std::to_string(size)); + + std::vector buf(data, data + size); + for(size_t i = 0; i != size; ++i) + buf[i] ^= 0xFF; + + m_channel->send(buf); + } + + bool tls_verify_message(const Botan::Public_Key& key, + const std::string& emsa, + Botan::Signature_Format format, + const std::vector& msg, + const std::vector& sig) override + { + if(m_args.option_used("expect-peer-signature-algorithm")) + { + const auto scheme = static_cast(m_args.get_int_opt("expect-peer-signature-algorithm")); + if(scheme != Botan::TLS::Signature_Scheme::NONE) + { + const std::string exp_emsa = Botan::TLS::padding_string_for_scheme(scheme); + if(emsa != exp_emsa) + shim_exit_with_error("Unexpected signature scheme got " + emsa + " expected " + exp_emsa); + } + } + return Botan::TLS::Callbacks::tls_verify_message(key, emsa, format, msg, sig); + } + + void tls_verify_cert_chain(const std::vector& /*cert_chain*/, + const std::vector>& /*ocsp_responses*/, + const std::vector& /*trusted_roots*/, + Botan::Usage_Type /*usage*/, + const std::string& /*hostname*/, + const Botan::TLS::Policy& /*policy*/) override + { + if(m_args.flag_set("enable-ocsp-stapling") && + m_args.flag_set("use-ocsp-callback") && + m_args.flag_set("fail-ocsp-callback")) + { + throw Botan::TLS::TLS_Exception(Botan::TLS::Alert::BAD_CERTIFICATE_STATUS_RESPONSE, + "Simulated OCSP callback failure"); + } + + if(m_args.flag_set("verify-peer") && m_args.flag_set("verify-fail")) + { + throw Botan::TLS::TLS_Exception(Botan::TLS::Alert::BAD_CERTIFICATE, + "Test requires rejecting cert"); + } + } + + std::string tls_server_choose_app_protocol(const std::vector& client_protos) override + { + if(client_protos.empty()) + return ""; // shouldn't happen? + + if(m_args.flag_set("decline-alpn")) + return ""; + + if(m_args.option_used("expect-advertised-alpn")) + { + const std::vector expected = m_args.get_alpn_string_vec_opt("expect-advertised-alpn"); + + if(client_protos != expected) + shim_exit_with_error("Bad ALPN from client"); + } + + if(m_args.option_used("select-alpn")) + return m_args.get_string_opt("select-alpn"); + + return client_protos[0]; // if not configured just pick something + } + + void tls_alert(Botan::TLS::Alert alert) override + { + if(alert.is_fatal()) + shim_log("Got a fatal alert " + alert.type_string()); + else + shim_log("Got a warning alert " + alert.type_string()); + + if(alert.type() == Botan::TLS::Alert::RECORD_OVERFLOW) + { + shim_exit_with_error(":TLSV1_ALERT_RECORD_OVERFLOW:"); + } + + if(alert.type() == Botan::TLS::Alert::DECOMPRESSION_FAILURE) + { + shim_exit_with_error(":SSLV3_ALERT_DECOMPRESSION_FAILURE:"); + } + + if(!alert.is_fatal()) + { + m_warning_alerts++; + if(m_warning_alerts > 5) + shim_exit_with_error(":TOO_MANY_WARNING_ALERTS:"); + } + + if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY) + { + if(m_got_close == false && !m_args.flag_set("shim-shuts-down")) + { + shim_log("Sending return close notify"); + m_channel->send_alert(alert); + } + m_got_close = true; + } + else if(alert.is_fatal()) + { + shim_exit_with_error("Unexpected fatal alert " + alert.type_string()); + } + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + shim_log("Session established: " + Botan::hex_encode(session.session_id()) + + " version " + session.version().to_string() + + " cipher " + session.ciphersuite().to_string() + + " EMS " + std::to_string(session.supports_extended_master_secret())); + // probably need tests here? + + m_policy.incr_session_established(); + m_sessions_established++; + + if(m_args.flag_set("expect-no-session-id")) + { + // BoGo expects that ticket issuance implies no stateful session... + if(!m_args.flag_set("server") && session.session_id().size() > 0) + shim_exit_with_error("Unexpectedly got a session ID"); + } + else if(m_args.flag_set("expect-session-id")) + { + if(session.session_id().empty()) + shim_exit_with_error("Unexpectedly got no session ID"); + } + + if(m_args.option_used("expect-version")) + { + if(session.version().version_code() != m_args.get_int_opt("expect-version")) + shim_exit_with_error("Unexpected version"); + } + + if(m_args.flag_set("expect-secure-renegotiation")) + { + if(m_channel->secure_renegotiation_supported() == false) + shim_exit_with_error("Expected secure renegotiation"); + } + else if(m_args.flag_set("expect-no-secure-renegotiation")) + { + if(m_channel->secure_renegotiation_supported() == true) + shim_exit_with_error("Expected no secure renegotation"); + } + + if(m_args.flag_set("expect-extended-master-secret")) + { + if(session.supports_extended_master_secret() == false) + shim_exit_with_error("Expected extended maseter secret"); + } + + return true; + } + + void tls_session_activated() override + { + if(m_args.flag_set("send-alert")) + { + m_channel->send_fatal_alert(Botan::TLS::Alert::DECOMPRESSION_FAILURE); + return; + } + + if(size_t length = m_args.get_int_opt_or_else("export-keying-material", 0)) + { + const std::string label = m_args.get_string_opt("export-label"); + const std::string context = m_args.get_string_opt("export-context"); + const auto exported = m_channel->key_material_export(label, context, length); + shim_log("Sending " + std::to_string(length) + " bytes of key material"); + m_channel->send(exported.bits_of()); + } + + const std::string alpn = m_channel->application_protocol(); + + if(m_args.option_used("expect-alpn")) + { + if(alpn != m_args.get_string_opt("expect-alpn")) + shim_exit_with_error("Got unexpected ALPN"); + } + + if(alpn == "baz" && !m_args.flag_set("allow-unknown-alpn-protos")) + { + throw Botan::TLS::TLS_Exception(Botan::TLS::Alert::ILLEGAL_PARAMETER, + "Unexpected ALPN protocol"); + } + + if(m_args.flag_set("shim-shuts-down")) + { + shim_log("Shim shutting down"); + m_channel->close(); + } + + if(m_args.flag_set("write-different-record-sizes")) + { + static const size_t record_sizes[] = { + 0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769 + }; + + std::vector buf(32769, 0x42); + + for(size_t sz : record_sizes) + { + m_channel->send(buf.data(), sz); + } + + m_channel->close(); + } + } + + private: + Botan::TLS::Channel* m_channel; + const Shim_Arguments& m_args; + Shim_Policy& m_policy; + Shim_Socket& m_socket; + const bool m_is_datagram; + size_t m_warning_alerts; + size_t m_empty_records; + size_t m_sessions_established; + bool m_got_close; + }; + +} + +int main(int /*argc*/, char* argv[]) + { + try + { + std::unique_ptr args = parse_options(argv); + + if(args->flag_set("is-handshaker-supported")) + { + return shim_output("No\n"); + } + + const uint16_t port = static_cast(args->get_int_opt("port")); + const size_t resume_count = args->get_int_opt_or_else("resume-count", 0); + const bool is_server = args->flag_set("server"); + const bool is_datagram = args->flag_set("dtls"); + + const size_t buf_size = args->get_int_opt_or_else("read-size", 18*1024); + + Botan::ChaCha_RNG rng(Botan::secure_vector(64)); + Botan::TLS::Session_Manager_In_Memory session_manager(rng, 1024); + Shim_Credentials creds(*args); + + for(size_t i = 0; i != resume_count+1; ++i) + { + Shim_Socket socket("localhost", port); + + shim_log("Connection " + std::to_string(i+1) + "/" + std::to_string(resume_count+1)); + + Shim_Policy policy(*args); + Shim_Callbacks callbacks(*args, socket, policy); + + std::unique_ptr chan; + + if(is_server) + { + chan.reset(new Botan::TLS::Server(callbacks, session_manager, creds, policy, rng, is_datagram)); + } + else + { + Botan::TLS::Protocol_Version offer_version = policy.latest_supported_version(is_datagram); + shim_log("Offering " + offer_version.to_string()); + + std::string host_name = args->get_string_opt_or_else("host-name", "localhost"); + if(args->test_name().find("UnsolicitedServerNameAck-TLS1") == 0) + host_name = ""; // avoid sending SNI for this test + + Botan::TLS::Server_Information server_info(host_name, port); + const std::vector next_protocols = args->get_alpn_string_vec_opt("advertise-alpn"); + chan.reset(new Botan::TLS::Client(callbacks, session_manager, creds, policy, rng, + server_info, offer_version, next_protocols)); + } + + callbacks.set_channel(chan.get()); + + std::vector buf(buf_size); + + for(;;) + { + if(is_datagram) + { + uint8_t opcode; + size_t got = socket.read(&opcode, 1); + if(got == 0) + { + shim_log("EOF on socket"); + break; + } + + if(opcode == 'P') + { + uint8_t len_bytes[4]; + socket.read_exactly(len_bytes, sizeof(len_bytes)); + + size_t packet_len = Botan::load_be(len_bytes, 0); + + if(buf.size() < packet_len) + buf.resize(packet_len); + socket.read_exactly(buf.data(), packet_len); + + chan->received_data(buf.data(), packet_len); + } + else if(opcode == 'T') + { + uint8_t timeout_ack = 't'; + + uint8_t timeout_bytes[8]; + socket.read_exactly(timeout_bytes, sizeof(timeout_bytes)); + + const uint64_t nsec = Botan::load_be(timeout_bytes, 0); + + shim_log("Timeout nsec " + std::to_string(nsec)); + + // FIXME handle this! + + socket.write(&timeout_ack, 1); // ack it anyway + } + else + shim_exit_with_error("Unknown opcode " + std::to_string(opcode)); + } + else + { + size_t got = socket.read(buf.data(), buf.size()); + if(got == 0) + { + shim_log("EOF on socket"); + break; + } + + shim_log("Got packet of " + std::to_string(got)); + + if(args->flag_set("use-exporter-between-reads") && chan->is_active()) + { + chan->key_material_export("some label", "some context", 42); + } + const size_t needed = chan->received_data(buf.data(), got); + + if(needed) + shim_log("Short read still need " + std::to_string(needed)); + } + } + + if(args->flag_set("check-close-notify")) + { + if(!callbacks.saw_close_notify()) + throw Shim_Exception("Unexpected SSL_shutdown result: -1 != 1"); + } + + if(args->option_used("expect-total-renegotiations")) + { + const size_t exp = args->get_int_opt("expect-total-renegotiations"); + + if(exp != callbacks.sessions_established() - 1) + throw Shim_Exception("Unexpected number of renegotiations: saw " + + std::to_string(callbacks.sessions_established() - 1) + + " exp " + std::to_string(exp)); + } + shim_log("End of resume loop"); + } + + } + catch(Shim_Exception& e) + { + shim_exit_with_error(e.what(), e.rc()); + } + catch(std::exception& e) + { + shim_exit_with_error(map_to_bogo_error(e.what())); + } + catch(...) + { + shim_exit_with_error("Unknown exception", 3); + } + return 0; + } diff --git a/comm/third_party/botan/src/bogo_shim/config.json b/comm/third_party/botan/src/bogo_shim/config.json new file mode 100644 index 0000000000..24295a868a --- /dev/null +++ b/comm/third_party/botan/src/bogo_shim/config.json @@ -0,0 +1,129 @@ +{ + "LooseErrorTests": { + "AppDataBeforeHandshake": "BoGo expects different error before vs after CCS", + "AppDataBeforeHandshake-Empty": "Invalid record message", + "ServerHelloBogusCipher": "Unexpected error", + "Garbage": "Decoding error", + "Resume-Client-CipherMismatch": "Unexpected error", + "InvalidECDHPoint-Server": "Unexpected error", + "NoSharedCipher": "Unexpected error" + }, + + "DisabledTests": { + "*KeyUpdate*": "No TLS 1.3", + "*TLS13*": "No TLS 1.3", + "Server-JDK11*": "No TLS 1.3", + "*Binder*": "No TLS 1.3", + "PartialEncryptedExtensionsWithServerHello": "No TLS 1.3", + "Client-RejectJDK11DowngradeRandom": "No TLS 1.3", + "FragmentedClientVersion": "No TLS 1.3", + "NoExportEarlyKeyingMaterial*": "No TLS 1.3", + "EarlyDataEnabled*": "No TLS 1.3", + "DelegatedCredentials*": "No TLS 1.3", + "ExportTrafficSecrets-*": "No TLS 1.3", + "IgnoreClientVersionOrder": "No TLS 1.3", + "Resume-Server-OmitPSKsOnSecondClientHello": "No TLS 1.3", + "Http*": "No support for HTTP detection", + + "DuplicateCertCompressionExt*": "No support for 1.3 cert compression extension", + + "SupportedVersionSelection-TLS12": "We just ignore the version extension in this case", + + "Downgrade-*-Client-Ignore": "Not possible to ignore downgrade indicator", + "Downgrade-TLS12-*": "Not a downgrade when we don't support v1.3", + + "*SSL3*": "No SSLv3", + "*SSLv3*": "No SSLv3", + + "*NPN*": "No support for NPN", + "ALPNServer-Preferred-*": "No support for NPN", + "*-NextProtocol": "No support for NPN", + + "*SignedCertificateTimestamp*": "No support for SCT", + "*SCT*": "No support for SCT", + "Renegotiation-ChangeAuthProperties": "No support for SCT", + "UnsolicitedCertificateExtensions-TLS*": "No support for SCT", + + "*NULL-SHA*": "No support for NULL ciphers", + "*WITH_NULL*": "No support for NULL ciphers", + "*GREASE*": "No support for GREASE", + "QUICTransportParams*": "No support for QUIC", + "*ChannelID*": "No support for ChannelID", + "*TokenBinding*": "No support for Token Binding", + "ClientHelloPadding": "No support for client hello padding extension", + "TLSUnique*": "Not supported", + "*CECPQ2*": "Not implemented", + "PQExperimentSignal*": "Not implemented", + "*P-224*": "P-224 not supported in TLS", + "*V2ClientHello*": "No support for SSLv2 client hellos", + "*Ed25519*": "Ed25519 not implemented in TLS", + "Http*": "Stack does not have detection logic for HTTP", + "*FalseStart*": "Botan doesn't do false start", + "MaxSendFragment*": "Maximum fragment extension not supported", + "ExportKeyingMaterial-EmptyContext*": "No support for empty context", + + "Peek-*": "No peek API", + "*OldCallback*": "BoringSSL specific API test", + "*Renegotiate-Client-Explicit*": "BoringSSL specific API test", + "CBCRecordSplittingPartialWrite*": "BoringSSL specific API test", + "TicketCallback*": "BoringSSL specific API test", + "Server-DDoS*": "BoringSSL specific API test", + "RetainOnlySHA256-*": "BoringSSL specific API test", + "Renegotiate-Client-UnfinishedWrite": "BoringSSL specific API test", + "FailEarlyCallback": "BoringSSL specific API test", + + "ShimTicketRewritable": "Botan has a different ticket format", + "Resume-Server-DeclineCrossVersion*": "Botan has a different ticket format", + "Resume-Server-DeclineBadCipher*": "Botan has a different ticket format", + "Resume-Server-CipherNotPreferred*": "Botan has a different ticket format", + + "TLS*-NoTicket-NoAccept": "BoGo expects that if ticket is issued stateful resumption is impossible", + + "CheckLeafCurve": "Botan doesn't care what curve an ECDSA cert uses", + + "CertificateVerificationDoesNotFailOnResume*": "Botan doesn't support reverify on resume", + "CertificateVerificationFailsOnResume*": "Botan doesn't support reverify on resume", + "CertificateVerificationPassesOnResume*": "Botan doesn't support reverify on resume", + + "CipherNegotiation-2": "No support for cipher equivalence classes", + "CipherNegotiation-3": "No support for cipher equivalence classes", + "CipherNegotiation-4": "No support for cipher equivalence classes", + "CipherNegotiation-5": "No support for cipher equivalence classes", + "CipherNegotiation-8": "No support for cipher equivalence classes", + + "ALPNServer-SelectEmpty-*": "Botan treats empty ALPN from callback as a decline", + + "AppDataAfterChangeCipherSpec-DTLS*": "BoringSSL DTLS drops out of order AppData, we reject", + + "Resume-Client-NoResume-TLS1-TLS11": "BoGo expects resumption attempt sends latest version", + "Resume-Client-NoResume-TLS1-TLS12": "BoGo expects resumption attempt sends latest version", + "Resume-Client-NoResume-TLS11-TLS12": "BoGo expects resumption attempt sends latest version", + "Resume-Client-NoResume-TLS1-TLS12-DTLS": "BoGo expects resumption attempt sends latest version", + + "Resume-Client-Mismatch-TLS1-TLS11": "BoGo expects resumption attempt sends latest version", + "Resume-Client-Mismatch-TLS1-TLS12": "BoGo expects resumption attempt sends latest version", + "Resume-Client-Mismatch-TLS11-TLS12": "BoGo expects resumption attempt sends latest version", + "Resume-Client-Mismatch-TLS1-TLS12-DTLS": "BoGo expects resumption attempt sends latest version", + + "CurveTest-*-Compressed*": "Point compression is supported, which BoGo doesn't expect", + "PointFormat-*-MissingUncompressed": "Point compression is supported, which BoGo doesn't expect", + + "RSAPSSSupport-ConfigPSS-NoCerts-TLS12-*": "Needs investigation", + "RSAPSSSupport-Default-NoCerts-TLS12-*": "Needs investigation", + + "DTLS-Retransmit*": "Shim needs timeout support", + + "DTLS-StrayRetransmitFinished-ClientFull": "Needs investigation", + "DTLS-StrayRetransmitFinished-ServerResume": "Needs investigation", + + "SRTP-Server-IgnoreMKI-*": "Non-empty MKI is rejected (bug)", + + "Renegotiate-Client-Packed": "Packing HelloRequest with Finished loses the HelloRequest (bug)", + "SendHalfHelloRequest*PackHandshake": "Packing HelloRequest with Finished loses the HelloRequest (bug)", + + "PartialClientFinishedWithClientHello": "Need to check for buffered messages when CCS (bug)", + "SendUnencryptedFinished-DTLS": "Need to check for buffered messages when CCS (bug)", + + "RSAKeyUsage-*-UnenforcedTLS*": "We always enforce key usage" + } +} diff --git a/comm/third_party/botan/src/build-data/arch/alpha.txt b/comm/third_party/botan/src/build-data/arch/alpha.txt new file mode 100644 index 0000000000..c251cbee9c --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/alpha.txt @@ -0,0 +1,7 @@ +endian little +wordsize 64 + + +axp +alphaaxp + diff --git a/comm/third_party/botan/src/build-data/arch/arm32.txt b/comm/third_party/botan/src/build-data/arch/arm32.txt new file mode 100644 index 0000000000..6e2f70bcf9 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/arm32.txt @@ -0,0 +1,21 @@ +endian little +family arm + + +arm +armeb +armel # For Debian +armhf # For Debian +evbarm # For NetBSD + +armv7 +armv7l +armv7a +armv7-a + +armv8l # For AlpineLinux + + + +neon + diff --git a/comm/third_party/botan/src/build-data/arch/arm64.txt b/comm/third_party/botan/src/build-data/arch/arm64.txt new file mode 100644 index 0000000000..5205295125 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/arm64.txt @@ -0,0 +1,20 @@ +endian little +wordsize 64 + +family arm + + +aarch64 +aarch64_be +armv8 +armv8-a + + + +neon +armv8crypto +armv8sm3 +armv8sm4 +armv8sha3 +armv8sha512 + diff --git a/comm/third_party/botan/src/build-data/arch/generic.txt b/comm/third_party/botan/src/build-data/arch/generic.txt new file mode 100644 index 0000000000..0b5e7e45c8 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/generic.txt @@ -0,0 +1,4 @@ + +# This target can be used when building an amalgamation which must +# be built on multiple architectures, or when targetting a CPU +# which the build system doesn't know about. diff --git a/comm/third_party/botan/src/build-data/arch/hppa.txt b/comm/third_party/botan/src/build-data/arch/hppa.txt new file mode 100644 index 0000000000..8828126b65 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/hppa.txt @@ -0,0 +1,8 @@ + +hp-pa +parisc +parisc64 +pa-risc +hp-parisc +hp-pa-risc + diff --git a/comm/third_party/botan/src/build-data/arch/ia64.txt b/comm/third_party/botan/src/build-data/arch/ia64.txt new file mode 100644 index 0000000000..8a448ff881 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/ia64.txt @@ -0,0 +1,6 @@ +wordsize 64 + + +itanium +itanic + diff --git a/comm/third_party/botan/src/build-data/arch/llvm.txt b/comm/third_party/botan/src/build-data/arch/llvm.txt new file mode 100644 index 0000000000..3b8c13ffd5 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/llvm.txt @@ -0,0 +1 @@ +wordsize 64 diff --git a/comm/third_party/botan/src/build-data/arch/m68k.txt b/comm/third_party/botan/src/build-data/arch/m68k.txt new file mode 100644 index 0000000000..f171f4534f --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/m68k.txt @@ -0,0 +1,6 @@ +endian big + + +680x0 +68k + diff --git a/comm/third_party/botan/src/build-data/arch/mips32.txt b/comm/third_party/botan/src/build-data/arch/mips32.txt new file mode 100644 index 0000000000..d9849e8484 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/mips32.txt @@ -0,0 +1,6 @@ + +mips +mipsbe # RedHat +mipsle # RedHat +mipsel # Debian + diff --git a/comm/third_party/botan/src/build-data/arch/mips64.txt b/comm/third_party/botan/src/build-data/arch/mips64.txt new file mode 100644 index 0000000000..6d67128ede --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/mips64.txt @@ -0,0 +1,5 @@ +wordsize 64 + + +mips64el + diff --git a/comm/third_party/botan/src/build-data/arch/powerpcspe.txt b/comm/third_party/botan/src/build-data/arch/powerpcspe.txt new file mode 100644 index 0000000000..37d3b3c0f6 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/powerpcspe.txt @@ -0,0 +1,3 @@ +endian big + +family ppc diff --git a/comm/third_party/botan/src/build-data/arch/ppc32.txt b/comm/third_party/botan/src/build-data/arch/ppc32.txt new file mode 100644 index 0000000000..da8b7654ad --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/ppc32.txt @@ -0,0 +1,12 @@ +endian big + +family ppc + + +powerpc +ppc + + + +altivec + diff --git a/comm/third_party/botan/src/build-data/arch/ppc64.txt b/comm/third_party/botan/src/build-data/arch/ppc64.txt new file mode 100644 index 0000000000..4b871e85e1 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/ppc64.txt @@ -0,0 +1,17 @@ +endian big + +family ppc +wordsize 64 + + +powerpc64 +powerpc64le +ppc64le +ppc64el + + + +altivec +powercrypto +power9 + diff --git a/comm/third_party/botan/src/build-data/arch/riscv32.txt b/comm/third_party/botan/src/build-data/arch/riscv32.txt new file mode 100644 index 0000000000..c8c258a00e --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/riscv32.txt @@ -0,0 +1,2 @@ +family riscv +endian little diff --git a/comm/third_party/botan/src/build-data/arch/riscv64.txt b/comm/third_party/botan/src/build-data/arch/riscv64.txt new file mode 100644 index 0000000000..8aa90eddf3 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/riscv64.txt @@ -0,0 +1,3 @@ +family riscv +endian little +wordsize 64 diff --git a/comm/third_party/botan/src/build-data/arch/s390.txt b/comm/third_party/botan/src/build-data/arch/s390.txt new file mode 100644 index 0000000000..64a1abdd37 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/s390.txt @@ -0,0 +1 @@ +endian big diff --git a/comm/third_party/botan/src/build-data/arch/s390x.txt b/comm/third_party/botan/src/build-data/arch/s390x.txt new file mode 100644 index 0000000000..eb6a87d69b --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/s390x.txt @@ -0,0 +1,2 @@ +endian big +wordsize 64 diff --git a/comm/third_party/botan/src/build-data/arch/sparc32.txt b/comm/third_party/botan/src/build-data/arch/sparc32.txt new file mode 100644 index 0000000000..0680fdfc3d --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/sparc32.txt @@ -0,0 +1,7 @@ +endian big + +family sparc + + +sparc + diff --git a/comm/third_party/botan/src/build-data/arch/sparc64.txt b/comm/third_party/botan/src/build-data/arch/sparc64.txt new file mode 100644 index 0000000000..b01c8277fd --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/sparc64.txt @@ -0,0 +1,3 @@ +family sparc +wordsize 64 +endian big diff --git a/comm/third_party/botan/src/build-data/arch/superh.txt b/comm/third_party/botan/src/build-data/arch/superh.txt new file mode 100644 index 0000000000..6af6dbe682 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/superh.txt @@ -0,0 +1,4 @@ + + +sh4 + diff --git a/comm/third_party/botan/src/build-data/arch/x32.txt b/comm/third_party/botan/src/build-data/arch/x32.txt new file mode 100644 index 0000000000..d69e1247d7 --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/x32.txt @@ -0,0 +1,16 @@ +endian little + +family x86 + + +aesni +avx2 +bmi2 +rdrand +rdseed +sha +sse2 +sse41 +sse42 +ssse3 + diff --git a/comm/third_party/botan/src/build-data/arch/x86_32.txt b/comm/third_party/botan/src/build-data/arch/x86_32.txt new file mode 100644 index 0000000000..cd4ede4e9a --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/x86_32.txt @@ -0,0 +1,32 @@ +endian little + +family x86 + + +ia32 +x86 +ix86 +80x86 +i86pc # for Solaris +x86pc # for QNX +bepc # for Haiku + +i686-at386 # for Hurd + +i686 +i586 +i386 + + + +aesni +avx2 +bmi2 +rdrand +rdseed +sha +sse2 +sse41 +sse42 +ssse3 + diff --git a/comm/third_party/botan/src/build-data/arch/x86_64.txt b/comm/third_party/botan/src/build-data/arch/x86_64.txt new file mode 100644 index 0000000000..729363e6fa --- /dev/null +++ b/comm/third_party/botan/src/build-data/arch/x86_64.txt @@ -0,0 +1,25 @@ +endian little +wordsize 64 + +family x86 + + +amd64 +x86-64 +em64t +x64 +x86_amd64 + + + +aesni +avx2 +bmi2 +rdrand +rdseed +sha +sse2 +sse41 +sse42 +ssse3 + diff --git a/comm/third_party/botan/src/build-data/bakefile.in b/comm/third_party/botan/src/build-data/bakefile.in new file mode 100644 index 0000000000..a1c0ff134e --- /dev/null +++ b/comm/third_party/botan/src/build-data/bakefile.in @@ -0,0 +1,51 @@ +toolsets = vs2013; +shared-library botan { + defines = "BOTAN_DLL=__declspec(dllexport)"; + sources { +%{for lib_srcs} + %{i} +%{endfor} + } +} + +program cli { + deps = botan; + sources { +%{for cli_srcs} + %{i} +%{endfor} + } + + headers { +%{for cli_headers} + %{i} +%{endfor} + } + +} + +program tests { + deps = botan; + sources { +%{for test_srcs} + %{i} +%{endfor} + } +} + +includedirs += build/include/; +includedirs += build/include/external; + +%{for libs_used} +libs += "%{i}"; +%{endfor} + +archs = %{bakefile_arch}; + +vs2013.option.ClCompile.DisableSpecificWarnings = "4250;4251;4275"; +vs2013.option.ClCompile.WarningLevel = Level4; +vs2013.option.ClCompile.ExceptionHandling = SyncCThrow; +vs2013.option.ClCompile.RuntimeTypeInfo = true; +if ( $(config) == Release ) { + vs2013.option.Configuration.WholeProgramOptimization = true; +} diff --git a/comm/third_party/botan/src/build-data/botan.doxy.in b/comm/third_party/botan/src/build-data/botan.doxy.in new file mode 100644 index 0000000000..0fb801f55a --- /dev/null +++ b/comm/third_party/botan/src/build-data/botan.doxy.in @@ -0,0 +1,226 @@ +# Doxyfile 1.5.4 + +PROJECT_NAME = Botan +PROJECT_NUMBER = %{version} +PROJECT_BRIEF = Crypto and TLS for C++11 +OUTPUT_DIRECTORY = %{doc_output_dir}/doxygen +DOXYFILE_ENCODING = UTF-8 +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# Set this to NO to get warnings about undocumented members/classes +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = + +%{if maintainer_mode} +WARN_AS_ERROR = YES +%{endif} + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = %{src_dir}/lib +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */wrap/* +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = . +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +GENERATE_HTMLHELP = NO +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# Configuration options related to other output formats +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = BOTAN_HAS_AES_ARMV8 \ + BOTAN_HAS_AES_NI \ + BOTAN_HAS_AES_POWER8 \ + BOTAN_HAS_AES_VPERM \ + BOTAN_HAS_CHACHA_SIMD32 \ + BOTAN_HAS_CHACHA_AVX2 \ + BOTAN_HAS_IDEA_SSE2 \ + BOTAN_HAS_NOEKEON_SIMD \ + BOTAN_HAS_SERPENT_SIMD \ + BOTAN_HAS_SERPENT_AVX2 \ + BOTAN_HAS_SHA1_SSE2 \ + BOTAN_HAS_SHA2_32_X86 \ + BOTAN_HAS_SHA2_32_X86_BMI2 \ + BOTAN_HAS_SHA2_64_BMI2 \ + BOTAN_HAS_SHA3_BMI2 \ + BOTAN_HAS_SHACAL2_SIMD \ + BOTAN_HAS_SHACAL2_AVX2 \ + BOTAN_HAS_SHACAL2_X86 \ + BOTAN_HAS_SM4_ARMV8 \ + BOTAN_HAS_THREEFISH_512_AVX2 \ + BOTAN_HAS_GHASH_CLMUL_CPU \ + BOTAN_HAS_GHASH_CLMUL_VPERM \ + BOTAN_DEPRECATED(msg)= \ + BOTAN_DEPRECATED_API(msg)= \ + BOTAN_PUBLIC_API(maj,min)= \ + BOTAN_HAS_TLS \ + BOTAN_HAS_BOOST_ASIO \ + BOOST_VERSION=106600 + + +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/comm/third_party/botan/src/build-data/botan.pc.in b/comm/third_party/botan/src/build-data/botan.pc.in new file mode 100644 index 0000000000..7139436f93 --- /dev/null +++ b/comm/third_party/botan/src/build-data/botan.pc.in @@ -0,0 +1,12 @@ +prefix=%{prefix} +exec_prefix=${prefix} +libdir=%{libdir} +includedir=${prefix}/include/botan-%{version_major} + +Name: Botan +Description: Crypto and TLS for C++11 +Version: %{version} + +Libs: -L${libdir} -l%{libname} %{cxx_abi_flags} +Libs.private: %{link_to} +Cflags: -I${includedir} diff --git a/comm/third_party/botan/src/build-data/buildh.in b/comm/third_party/botan/src/build-data/buildh.in new file mode 100644 index 0000000000..cede20ace7 --- /dev/null +++ b/comm/third_party/botan/src/build-data/buildh.in @@ -0,0 +1,268 @@ +#ifndef BOTAN_BUILD_CONFIG_H_ +#define BOTAN_BUILD_CONFIG_H_ + +/* +* Build configuration for Botan %{version} +* +* Automatically generated from +* '%{command_line}' +* +* Target +* - Compiler: %{cxx} %{cxx_abi_flags} %{cc_lang_flags} %{cc_compile_flags} +* - Arch: %{arch} +* - OS: %{os} +*/ + +#define BOTAN_VERSION_MAJOR %{version_major} +#define BOTAN_VERSION_MINOR %{version_minor} +#define BOTAN_VERSION_PATCH %{version_patch} +#define BOTAN_VERSION_DATESTAMP %{version_datestamp} + +%{if version_suffix} +#define BOTAN_VERSION_SUFFIX %{version_suffix} +#define BOTAN_VERSION_SUFFIX_STR "%{version_suffix}" +%{endif} + +#define BOTAN_VERSION_RELEASE_TYPE "%{release_type}" + +#define BOTAN_VERSION_VC_REVISION "%{version_vc_rev}" + +#define BOTAN_DISTRIBUTION_INFO "%{distribution_info}" + +/* How many bits per limb in a BigInt */ +#define BOTAN_MP_WORD_BITS %{mp_bits} + +%{if fuzzer_mode} +#define BOTAN_UNSAFE_FUZZER_MODE +%{endif} +%{if fuzzer_type} +#define BOTAN_FUZZER_IS_%{fuzzer_type} +%{endif} + +#define BOTAN_INSTALL_PREFIX R"(%{prefix})" +#define BOTAN_INSTALL_HEADER_DIR R"(%{includedir}/botan-%{version_major})" +#define BOTAN_INSTALL_LIB_DIR R"(%{libdir})" +#define BOTAN_LIB_LINK "%{link_to}" +#define BOTAN_LINK_FLAGS "%{cxx_abi_flags}" + +%{if system_cert_bundle} +#define BOTAN_SYSTEM_CERT_BUNDLE "%{system_cert_bundle}" +%{endif} + +#ifndef BOTAN_DLL + #define BOTAN_DLL %{visibility_attribute} +#endif + +/* Target identification and feature test macros */ + +#define BOTAN_TARGET_OS_IS_%{os_name|upper} + +%{for os_features} +#define BOTAN_TARGET_OS_HAS_%{i|upper} +%{endfor} + +#define BOTAN_BUILD_COMPILER_IS_%{cc_macro} + +%{for sanitizer_types} +#define BOTAN_HAS_SANITIZER_%{i|upper} +%{endfor} + +%{if test_mode} +#define BOTAN_TEST_MODE +%{endif} + +#define BOTAN_TARGET_ARCH_IS_%{arch|upper} +%{if endian} +#define BOTAN_TARGET_CPU_IS_%{endian|upper}_ENDIAN +%{endif} +%{if cpu_family} +#define BOTAN_TARGET_CPU_IS_%{cpu_family|upper}_FAMILY +%{endif} +%{if cpu_is_64bit} +#define BOTAN_TARGET_CPU_HAS_NATIVE_64BIT +%{endif} + +%{for cpu_features} +#define BOTAN_TARGET_SUPPORTS_%{i|upper} +%{endfor} + +%{if with_valgrind} +#define BOTAN_HAS_VALGRIND +%{endif} + +%{if with_openmp} +#define BOTAN_TARGET_HAS_OPENMP +%{endif} + +%{if with_debug_asserts} +#define BOTAN_ENABLE_DEBUG_ASSERTS +%{endif} + +%{if optimize_for_size} +#define BOTAN_OPTIMIZE_FOR_SIZE +%{endif} + +/* +* Module availability definitions +*/ +%{for module_defines} +#define BOTAN_HAS_%{i} +%{endfor} + +/* +* Local/misc configuration options (if any) follow +*/ +%{local_config} + +/* +* Things you can edit (but probably shouldn't) +*/ + +#if !defined(BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES) + + #if defined(BOTAN_NO_DEPRECATED) + #define BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES private + #else + #define BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES public + #endif + +#endif + +/* How much to allocate for a buffer of no particular size */ +#define BOTAN_DEFAULT_BUFFER_SIZE 1024 + +/* +* Total maximum amount of RAM (in KiB) we will lock into memory, even +* if the OS would let us lock more +*/ +#define BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB 512 + +/* +* If BOTAN_MEM_POOL_USE_MMU_PROTECTIONS is defined, the Memory_Pool +* class used for mlock'ed memory will use OS calls to set page +* permissions so as to prohibit access to pages on the free list, then +* enable read/write access when the page is set to be used. This will +* turn (some) use after free bugs into a crash. +* +* The additional syscalls have a substantial performance impact, which +* is why this option is not enabled by default. +*/ +#if defined(BOTAN_HAS_VALGRIND) || defined(BOTAN_ENABLE_DEBUG_ASSERTS) + #define BOTAN_MEM_POOL_USE_MMU_PROTECTIONS +#endif + +/* +* If enabled uses memset via volatile function pointer to zero memory, +* otherwise does a byte at a time write via a volatile pointer. +*/ +#define BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO 1 + +/* +* Normally blinding is performed by choosing a random starting point (plus +* its inverse, of a form appropriate to the algorithm being blinded), and +* then choosing new blinding operands by successive squaring of both +* values. This is much faster than computing a new starting point but +* introduces some possible corelation +* +* To avoid possible leakage problems in long-running processes, the blinder +* periodically reinitializes the sequence. This value specifies how often +* a new sequence should be started. +*/ +#define BOTAN_BLINDING_REINIT_INTERVAL 64 + +/* +* Userspace RNGs like HMAC_DRBG will reseed after a specified number +* of outputs are generated. Set to zero to disable automatic reseeding. +*/ +#define BOTAN_RNG_DEFAULT_RESEED_INTERVAL 1024 +#define BOTAN_RNG_RESEED_POLL_BITS 256 + +#define BOTAN_RNG_AUTO_RESEED_TIMEOUT std::chrono::milliseconds(10) +#define BOTAN_RNG_RESEED_DEFAULT_TIMEOUT std::chrono::milliseconds(50) + +/* +* Specifies (in order) the list of entropy sources that will be used +* to seed an in-memory RNG. +*/ +#define BOTAN_ENTROPY_DEFAULT_SOURCES \ + { "rdseed", "hwrng", "p9_darn", "getentropy", "dev_random", \ + "system_rng", "proc_walk", "system_stats" } + +/* Multiplier on a block cipher's native parallelism */ +#define BOTAN_BLOCK_CIPHER_PAR_MULT 4 + +/* +* These control the RNG used by the system RNG interface +*/ +#define BOTAN_SYSTEM_RNG_DEVICE "/dev/urandom" +#define BOTAN_SYSTEM_RNG_POLL_DEVICES { "/dev/urandom", "/dev/random" } + +/* +* This directory will be monitored by ProcWalking_EntropySource and +* the contents provided as entropy inputs to the RNG. May also be +* usefully set to something like "/sys", depending on the system being +* deployed to. Set to an empty string to disable. +*/ +#define BOTAN_ENTROPY_PROC_FS_PATH "/proc" + +/* +* These paramaters control how many bytes to read from the system +* PRNG, and how long to block if applicable. The timeout only applies +* to reading /dev/urandom and company. +*/ +#define BOTAN_SYSTEM_RNG_POLL_REQUEST 64 +#define BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS 20 + +/* +* When a PBKDF is self-tuning parameters, it will attempt to take about this +* amount of time to self-benchmark. +*/ +#define BOTAN_PBKDF_TUNING_TIME std::chrono::milliseconds(10) + +/* +* If no way of dynamically determining the cache line size for the +* system exists, this value is used as the default. Used by the side +* channel countermeasures rather than for alignment purposes, so it is +* better to be on the smaller side if the exact value cannot be +* determined. Typically 32 or 64 bytes on modern CPUs. +*/ +#if !defined(BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE) + #define BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE 32 +#endif + +/** +* Controls how AutoSeeded_RNG is instantiated +*/ +#if !defined(BOTAN_AUTO_RNG_HMAC) + + #if defined(BOTAN_HAS_SHA2_64) + #define BOTAN_AUTO_RNG_HMAC "HMAC(SHA-384)" + #elif defined(BOTAN_HAS_SHA2_32) + #define BOTAN_AUTO_RNG_HMAC "HMAC(SHA-256)" + #elif defined(BOTAN_HAS_SHA3) + #define BOTAN_AUTO_RNG_HMAC "HMAC(SHA-3(256))" + #elif defined(BOTAN_HAS_SHA1) + #define BOTAN_AUTO_RNG_HMAC "HMAC(SHA-1)" + #endif + /* Otherwise, no hash found: leave BOTAN_AUTO_RNG_HMAC undefined */ + +#endif + +/* Check for a common build problem */ + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) && ((defined(_MSC_VER) && !defined(_WIN64)) || \ + (defined(__clang__) && !defined(__x86_64__)) || \ + (defined(__GNUG__) && !defined(__x86_64__))) + #error "Trying to compile Botan configured as x86_64 with non-x86_64 compiler." +#endif + +#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && ((defined(_MSC_VER) && defined(_WIN64)) || \ + (defined(__clang__) && !defined(__i386__)) || \ + (defined(__GNUG__) && !defined(__i386__))) + + #error "Trying to compile Botan configured as x86_32 with non-x86_32 compiler." +#endif + +#include + +#endif diff --git a/comm/third_party/botan/src/build-data/cc/clang.txt b/comm/third_party/botan/src/build-data/cc/clang.txt new file mode 100644 index 0000000000..a9c9be87f9 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/clang.txt @@ -0,0 +1,85 @@ +macro_name CLANG + +binary_name clang++ + +lang_flags "-std=c++11 -D_REENTRANT" + +warning_flags "-Wall -Wextra -Wpedantic -Wshadow -Wstrict-aliasing -Wstrict-overflow=5 -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual" + +werror_flags "-Werror -Wno-error=unused-parameter -Wno-error=unreachable-code -Wno-error=unused-lambda-capture" + +maintainer_warning_flags "-Wunreachable-code -Wdocumentation -Qunused-arguments" + +optimization_flags "-O3" +sanitizer_optimization_flags "-O1 -fno-optimize-sibling-calls -fno-omit-frame-pointer" +size_optimization_flags "-Os" + +add_sysroot_option "--sysroot=" + + +default -> address,undefined + +address -> "-fsanitize=address" +undefined -> "-fsanitize=undefined -fno-sanitize-recover=undefined" +coverage -> "-fsanitize=fuzzer-no-link" +memory -> "-fsanitize=memory" + + +shared_flags "-fPIC" +coverage_flags "--coverage" +stack_protector_flags "-fstack-protector" + +visibility_build_flags "-fvisibility=hidden" +visibility_attribute '__attribute__((visibility("default")))' + + +macos -> "$(CXX) -dynamiclib -fPIC -install_name $(INSTALLED_LIB_DIR)/{soname_abi} -current_version {macos_so_current_ver} -compatibility_version {macos_so_compat_ver}" + +# The default works for GNU ld and several other Unix linkers +default -> "$(CXX) -shared -fPIC -Wl,-soname,{soname_abi}" + + + +default -> "$(LINKER)" +llvm -> "llvm-link" +emscripten -> "em++" + + + +sse2 -> "-msse2" +ssse3 -> "-mssse3" +sse41 -> "-msse4.1" +sse42 -> "-msse4.2" +avx2 -> "-mavx2" +bmi2 -> "-mbmi -mbmi2" +aesni -> "-maes -mpclmul" +rdrand -> "-mrdrnd" +rdseed -> "-mrdseed" +sha -> "-msha" +altivec -> "-maltivec" + +ppc64:powercrypto -> "-mcrypto -mvsx" +ppc64:power9 -> "-mcpu=power9" + +arm64:armv8crypto -> "-march=armv8+crypto" + +arm32:neon -> "-mfpu=neon" +arm64:neon -> "" + + + +llvm -> "-emit-llvm -fno-use-cxa-atexit" + + + +all!haiku,llvm -> "-pthread" + +openmp -> "-fopenmp" + +x86_32 -> "-m32" +x86_64 -> "-m64" +ppc64 -> "-m64" + +macos -> "-stdlib=libc++" +ios -> "-stdlib=libc++" + diff --git a/comm/third_party/botan/src/build-data/cc/ekopath.txt b/comm/third_party/botan/src/build-data/cc/ekopath.txt new file mode 100644 index 0000000000..490396ac43 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/ekopath.txt @@ -0,0 +1,17 @@ +macro_name PATHSCALE + +binary_name pathCC + +optimization_flags "-O3" + +lang_flags "-D_REENTRANT -ansi -Wno-long-long" +warning_flags "-W -Wall" + +ar_command pathCC +ar_options "-ar -o" + +shared_flags "-fPIC" + + +default -> "$(CXX) -shared -fPIC -Wl,-soname,{soname_abi}" + diff --git a/comm/third_party/botan/src/build-data/cc/gcc.txt b/comm/third_party/botan/src/build-data/cc/gcc.txt new file mode 100644 index 0000000000..711c48f76c --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/gcc.txt @@ -0,0 +1,99 @@ +macro_name GCC + +binary_name g++ + +lang_flags "-std=c++11 -D_REENTRANT" + +# This should only contain flags which are included in GCC 4.8 +warning_flags "-Wall -Wextra -Wpedantic -Wstrict-aliasing -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual -Wzero-as-null-pointer-constant -Wnon-virtual-dtor" + +# Boost headers have 0 as nullptr and non-virtual-dtor issues so we can't werror on them +werror_flags "-Werror -Wno-error=strict-overflow -Wno-error=zero-as-null-pointer-constant -Wno-error=non-virtual-dtor" + +maintainer_warning_flags "-Wstrict-overflow=5 -Wold-style-cast -Wsuggest-override -Wshadow -Wextra-semi" + +optimization_flags "-O3" +sanitizer_optimization_flags "-O1 -fno-optimize-sibling-calls -fno-omit-frame-pointer" +size_optimization_flags "-Os" + +shared_flags "-fPIC" +coverage_flags "--coverage" +stack_protector_flags "-fstack-protector" + +add_sysroot_option "--sysroot=" + + +default -> iterator,address + +iterator -> "-D_GLIBCXX_DEBUG" +address -> "-fsanitize=address" +undefined -> "-fsanitize=undefined -fno-sanitize-recover=undefined" + + +visibility_build_flags "-fvisibility=hidden" +visibility_attribute '__attribute__((visibility("default")))' + + +# The default works for GNU ld and several other Unix linkers +default -> "$(CXX) -shared -fPIC -Wl,-soname,{soname_abi}" + +# macOS, HP-UX, and Solaris linkers use different syntax +macos -> "$(CXX) -dynamiclib -fPIC -install_name $(INSTALLED_LIB_DIR)/{soname_abi}" +hpux -> "$(CXX) -shared -fPIC -Wl,+h,{soname_abi}" +solaris -> "$(CXX) -shared -fPIC -Wl,-h,{soname_abi}" + +# AIX and OpenBSD don't use sonames at all +aix -> "$(CXX) -shared -fPIC" +openbsd -> "$(CXX) -shared -fPIC" + + + +default -> "$(LINKER)" + + + +sse2 -> "-msse2" +ssse3 -> "-mssse3" +sse41 -> "-msse4.1" +sse42 -> "-msse4.2" +avx2 -> "-mavx2" +bmi2 -> "-mbmi -mbmi2" +aesni -> "-maes -mpclmul" +rdrand -> "-mrdrnd" +rdseed -> "-mrdseed" +sha -> "-msha" +altivec -> "-maltivec" + +powercrypto -> "-mcrypto -mvsx" +ppc64:power9 -> "-mcpu=power9" + +arm64:armv8crypto -> "" +arm64:armv8sm3 -> "-march=armv8.2-a+sm4" +arm64:armv8sm4 -> "-march=armv8.2-a+sm4" +arm64:armv8sha512 -> "-march=armv8.2-a+sha3" +arm64:armv8sha3 -> "-march=armv8.2-a+sha3" + +# For Aarch32 -mfpu=neon is required +# For Aarch64 NEON is enabled by default +arm32:neon -> "-mfpu=neon" +arm64:neon -> "" + + +# Flags set here are included at compile and link time + +all!haiku,qnx,none -> "-pthread" + +openmp -> "-fopenmp" + +s390 -> "-m31" +s390x -> "-m64" +sparc32 -> "-m32 -mno-app-regs" +sparc64 -> "-m64 -mno-app-regs" +ppc64 -> "-m64" +x86_32 -> "-m32" +x86_64 -> "-m64" +x32 -> "-mx32" + +qnx -> "-fexceptions" +cygwin -> "-U__STRICT_ANSI__" + diff --git a/comm/third_party/botan/src/build-data/cc/hpcc.txt b/comm/third_party/botan/src/build-data/cc/hpcc.txt new file mode 100644 index 0000000000..cbe50c37d9 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/hpcc.txt @@ -0,0 +1,18 @@ +macro_name HP_ACC + +binary_name aCC + +lang_flags "-AA -ext +eh -z" +optimization_flags "+O2" +warning_flags "+w" +shared_flags "+Z" + + +hppa1.0 -> "+DAportable" +hppa1.1 -> "+DA1.1" +hppa2.0 -> "+DA2.0W" + + + +default -> "$(CXX) +Z -b -Wl,+h,{soname_abi}" # Documented in cc(1), but not CC(1) (?) + diff --git a/comm/third_party/botan/src/build-data/cc/icc.txt b/comm/third_party/botan/src/build-data/cc/icc.txt new file mode 100644 index 0000000000..c8a1aa3dc7 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/icc.txt @@ -0,0 +1,24 @@ +macro_name INTEL + +binary_name icpc + +optimization_flags "-O2" +size_optimization_flags "-Os" + +lang_flags "-std=c++11" +warning_flags "-w1" +shared_flags "-fPIC" + + +sse2 -> "-msse2" +ssse3 -> "-mssse3" +sse41 -> "-msse4.1" +sse42 -> "-msse4.2" +avx2 -> "-march=core-avx2" +aesni -> "-march=corei7" +rdrand -> "-march=core-avx-i" + + + +default -> "$(CXX) -fPIC -shared -Wl,-soname,{soname_abi}" + diff --git a/comm/third_party/botan/src/build-data/cc/msvc.txt b/comm/third_party/botan/src/build-data/cc/msvc.txt new file mode 100644 index 0000000000..25e39d2227 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/msvc.txt @@ -0,0 +1,84 @@ +macro_name MSVC + +binary_name cl +linker_name link + +output_to_object "/Fo" +output_to_exe "/OUT:" + +add_include_dir_option "/I" +add_lib_dir_option "/LIBPATH:" +add_compile_definition_option "/D" +add_lib_option "%s.lib" + +compile_flags "/nologo /c" + +optimization_flags "/O2 /Oi" +size_optimization_flags "/O1 /Os" + +# for debug info in the object file: +#debug_info_flags "/Z7" + +# for using a PDB file: +debug_info_flags "/Zi /FS" + +preproc_flags "/nologo /EP" + +lang_flags "/EHs /GR" + +# 4250: diamond inheritence warning +# 4251: STL types used in DLL interface +# 4275: ??? +# 4127: conditional expression is constant, consider using if constexpr +warning_flags "/W4 /wd4250 /wd4251 /wd4275 /wd4127" + +werror_flags "/WX" + +visibility_build_flags "/DBOTAN_DLL=__declspec(dllexport)" +visibility_attribute "__declspec(dllimport)" + +ar_command lib +ar_options "/nologo" +ar_output_to "/OUT:" + + +default -> iterator + +iterator -> "/D_ITERATOR_DEBUG_LEVEL=1" + + + +sse2 -> "" +ssse3 -> "" +sse41 -> "" +sse42 -> "" +x86_64:avx2 -> "/arch:AVX" +bmi2 -> "" +aesni -> "" +clmul -> "" +rdrand -> "" +rdseed -> "" +sha -> "" + + + +debug -> "/Fd%{build_dir}/%{libname}%{lib_suffix}.pdb" + + + +default -> "$(LINKER) /DLL" +default-debug -> "$(LINKER) /DLL /DEBUG" + + + +default -> "$(LINKER)" +default-debug -> "$(LINKER) /DEBUG" + + + +all -> "/bigobj" + +# These can be overridden with --msvc-runtime option +rt -> "/MD" +rt-debug -> "/MDd" + diff --git a/comm/third_party/botan/src/build-data/cc/pgi.txt b/comm/third_party/botan/src/build-data/cc/pgi.txt new file mode 100644 index 0000000000..811578cdca --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/pgi.txt @@ -0,0 +1,15 @@ +macro_name PGI + +binary_name pgc++ + +lang_flags "-std=c++11" + +optimization_flags "-O3" +shared_flags "-fPIC" + +visibility_build_flags "-fvisibility=hidden" +visibility_attribute '__attribute__((visibility("default")))' + + +default -> "$(CXX) -shared -fPIC -Wl,-soname,{soname_abi}" + diff --git a/comm/third_party/botan/src/build-data/cc/sunstudio.txt b/comm/third_party/botan/src/build-data/cc/sunstudio.txt new file mode 100644 index 0000000000..3dd8e00b02 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/sunstudio.txt @@ -0,0 +1,39 @@ +macro_name SUN_STUDIO + +binary_name CC + +optimization_flags "-xO2" + +shared_flags "-KPIC" +warning_flags "+w -erroff=truncwarn,wnoretvalue,wlessrestrictedthrow" +lang_flags "-std=c++11 +p -features=extensions" + +ar_command CC +ar_options "-xar -o" + + +default -> "$(CXX) -G -h{soname_abi}" + + + +# Needed on some Linux distros +linux -> "-library=stlport4" + +sparc64 -> "-m64 -xarch=sparc" +x86_64 -> "-m64" + + + +# Botan needs C++11, and that requires Sun Studio 12.4 or above. +# Sun Studio 12.4 supports upto -xarch=avx2, but the processor must support it +# AESNI requires -xarch=aes, and RDRAND requires -xarch=avx_i. +# https://docs.oracle.com/cd/E37069_01/html/E37074/bjapp.html#OSSCGbkazd +sse2 -> "-xarch=sse2" +ssse3 -> "-xarch=ssse3" +sse41 -> "-xarch=sse4.1" +sse42 -> "-xarch=sse4.2" +aesni -> "-xarch=aes" +avx -> "-xarch=avx" +rdrand -> "-xarch=avx_i" +avx2 -> "-xarch=avx2" + diff --git a/comm/third_party/botan/src/build-data/cc/xlc.txt b/comm/third_party/botan/src/build-data/cc/xlc.txt new file mode 100644 index 0000000000..a54b7f91f0 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cc/xlc.txt @@ -0,0 +1,26 @@ +macro_name XLC + +binary_name xlC + +optimization_flags "-O2" + +lang_flags "-std=c++11" + +visibility_build_flags "-fvisibility=hidden" +visibility_attribute '__attribute__((visibility("default")))' + + +altivec -> "-qaltivec" + + + +default -> "$(CXX) -qmkshrobj" + + + +default -> address + +all -> "-qcheck=all" +address -> "-qcheck=bounds:stackclobber:unset" +undefined -> "-qcheck=nullptr:divzero" + diff --git a/comm/third_party/botan/src/build-data/cmake.in b/comm/third_party/botan/src/build-data/cmake.in new file mode 100644 index 0000000000..2e4ea86448 --- /dev/null +++ b/comm/third_party/botan/src/build-data/cmake.in @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 2.8.0) +project(botan) + +if(POLICY CMP0042) +cmake_policy(SET CMP0042 NEW) +endif() + +set(BOTAN_SOURCES +%{for lib_srcs} + "%{i}" +%{endfor} +) + +set(BOTAN_CLI +%{for cli_srcs} + "%{i}" +%{endfor} +) + +set(BOTAN_TESTS +%{for test_srcs} + "%{i}" +%{endfor} +) + +%{for isa_build_info} +set_source_files_properties("%{src}" PROPERTIES COMPILE_FLAGS "%{isa_flags}") +%{endfor} + +option(ENABLED_OPTIONAL_WARINIGS "If enabled more strict warning policy will be used" OFF) +option(ENABLED_LTO "If enabled link time optimization will be used" OFF) + +set(COMPILER_FEATURES_RELEASE %{cc_lang_flags} %{cc_compile_opt_flags} %{cxx_abi_opt_flags}) +set(COMPILER_FEATURES_DEBUG %{cc_lang_flags} %{cc_compile_debug_flags} %{cxx_abi_debug_flags}) +set(COMPILER_FEATURES $<$>:${COMPILER_FEATURES_RELEASE}> $<$:${COMPILER_FEATURES_DEBUG}>) +set(SHARED_FEATURES %{cmake_lib_flags}) +set(STATIC_FEATURES -DBOTAN_DLL=) +set(COMPILER_WARNINGS %{cc_warning_flags}) +set(COMPILER_INCLUDE_DIRS %{compiler_include_dirs}) +if(ENABLED_LTO) + set(COMPILER_FEATURES ${COMPILER_FEATURES} -lto) +endif() +if(ENABLED_OPTIONAL_WARINIGS) + set(COMPILER_OPTIONAL_WARNINGS -Wsign-promo -Wctor-dtor-privacy -Wdeprecated -Winit-self -Wnon-virtual-dtor -Wunused-macros -Wold-style-cast -Wuninitialized) +endif() + +add_library(${PROJECT_NAME} STATIC ${BOTAN_SOURCES}) +target_link_libraries(${PROJECT_NAME} PUBLIC %{cmake_link_to}) +target_compile_options(${PROJECT_NAME} PUBLIC ${COMPILER_WARNINGS} ${COMPILER_FEATURES} ${COMPILER_OPTIONAL_WARNINGS} PRIVATE ${STATIC_FEATURES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${COMPILER_INCLUDE_DIRS}) + +set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}-static) + +add_library(${PROJECT_NAME}_shared SHARED ${BOTAN_SOURCES}) +target_link_libraries(${PROJECT_NAME}_shared PUBLIC %{cmake_link_to}) +target_compile_options(${PROJECT_NAME}_shared PUBLIC ${COMPILER_WARNINGS} ${COMPILER_FEATURES} ${COMPILER_OPTIONAL_WARNINGS} PRIVATE ${SHARED_FEATURES}) +target_include_directories(${PROJECT_NAME}_shared PUBLIC ${COMPILER_INCLUDE_DIRS}) +set_target_properties(${PROJECT_NAME}_shared PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) + +add_executable(${PROJECT_NAME}_cli ${BOTAN_CLI}) +target_link_libraries(${PROJECT_NAME}_cli PRIVATE ${PROJECT_NAME}_shared ) +set_target_properties(${PROJECT_NAME}_cli PROPERTIES OUTPUT_NAME ${PROJECT_NAME}-cli) + +add_executable(${PROJECT_NAME}_tests ${BOTAN_TESTS}) +target_link_libraries(${PROJECT_NAME}_tests PRIVATE ${PROJECT_NAME}_shared ) +set_target_properties(${PROJECT_NAME}_tests PROPERTIES OUTPUT_NAME botan-test) + +set(GLOBAL_CONFIGURATION_FILES configure.py .gitignore news.rst readme.rst) +file(GLOB_RECURSE CONFIGURATION_FILES src/configs/* ) +file(GLOB_RECURSE DOCUMENTATION_FILES doc/* ) +file(GLOB_RECURSE HEADER_FILES src/*.h ) +file(GLOB_RECURSE INFO_FILES src/lib/*info.txt ) +add_custom_target(CONFIGURATION_DUMMY SOURCES ${GLOBAL_CONFIGURATION_FILES} ${CONFIGURATION_FILES} ${DOCUMENTATION_FILES} ${INFO_FILES} ${HEADER_FILES}) diff --git a/comm/third_party/botan/src/build-data/detect_arch.cpp b/comm/third_party/botan/src/build-data/detect_arch.cpp new file mode 100644 index 0000000000..4de58922fe --- /dev/null +++ b/comm/third_party/botan/src/build-data/detect_arch.cpp @@ -0,0 +1,76 @@ + +#if defined(__x86_64__) && defined(__ILP32__) + X32 + +#elif defined(__x86_64__) || defined(_M_X64) + X86_64 + +#elif defined(__i386__) || defined(__i386) || defined(_M_IX86) + X86_32 + +#elif defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) + ARM64 + +#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_ARCH_7A__) + ARM32 + +#elif defined(__powerpc64__) || defined(__ppc64__) || defined(_ARCH_PPC64) + PPC64 + +#elif defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC) + + #if defined(__SPE__) + POWERPCSPE + #else + PPC32 + #endif + +#elif defined(__mips__) || defined(__mips) + + #if defined(__LP64__) || defined(_LP64) + MIPS64 + #else + MIPS32 + #endif + +#elif defined(__sparc__) + + #if defined(__LP64__) || defined(_LP64) + SPARC64 + #else + SPARC32 + #endif + +#elif defined(__alpha__) + ALPHA + +#elif defined(__hppa__) || defined(__hppa) + HPPA + +#elif defined(__ia64__) + IA64 + +#elif defined(__m68k__) + M68K + +#elif defined(__sh__) + SH + +#elif defined(__s390x__) + S390X + +#elif defined(__s390__) + S390 + +#elif defined(__riscv) + + #if defined(__LP64__) + RISCV64 + #else + RISCV32 + #endif + +#else + UNKNOWN + +#endif diff --git a/comm/third_party/botan/src/build-data/detect_version.cpp b/comm/third_party/botan/src/build-data/detect_version.cpp new file mode 100644 index 0000000000..8e08c63b91 --- /dev/null +++ b/comm/third_party/botan/src/build-data/detect_version.cpp @@ -0,0 +1,60 @@ +/* +* This file is preprocessed to produce output that is examined by +* configure.py to determine the compilers version number. +*/ + +#if defined(_MSC_VER) + + /* + _MSC_VER Defined as an integer literal that encodes the major and + minor number elements of the compiler's version number. The major + number is the first element of the period-delimited version number + and the minor number is the second element. For example, if the + version number of the Visual C++ compiler is 17.00.51106.1, the + _MSC_VER macro evaluates to 1700. + https://msdn.microsoft.com/en-us/library/b0084kay.aspx + */ + MSVC _MSC_VER + +#elif defined(__ibmxl__) + + XLC __ibmxl_version__ __ibmxl_release__ + +#elif defined(__clang__) && defined(__apple_build_version__) + + /* + Map Apple LLVM versions as used in XCode back to standard Clang. + This is not exact since the versions used in XCode are actually + forks of Clang and do not coorespond perfectly to standard Clang + releases. In addition we don't bother mapping very old versions + (anything before XCode 7 is treated like Clang 3.5, which is the + oldest version we support) and for "future" versions we simply + treat them as Clang 4.0, since we don't currenly rely on any + features not included in 4.0 + */ + + #if __clang_major__ >= 9 + CLANG 4 0 + #elif __clang_major__ == 8 + CLANG 3 9 + #elif __clang_major__ == 7 && __clang_minor__ == 3 + CLANG 3 8 + #elif __clang_major__ == 7 + CLANG 3 7 + #else + CLANG 3 5 + #endif + +#elif defined(__clang__) + + CLANG __clang_major__ __clang_minor__ + +#elif defined(__GNUG__) + + GCC __GNUC__ __GNUC_MINOR__ + +#else + + UNKNOWN 0 0 + +#endif diff --git a/comm/third_party/botan/src/build-data/innosetup.in b/comm/third_party/botan/src/build-data/innosetup.in new file mode 100644 index 0000000000..86df5f27bf --- /dev/null +++ b/comm/third_party/botan/src/build-data/innosetup.in @@ -0,0 +1,73 @@ +; A script for packaging botan with InnoSetup + +[Setup] +AppName=Botan +AppVerName=Botan %{version} + +AppPublisher=Jack Lloyd +AppPublisherURL=https://botan.randombit.net/ +AppVersion=%{version} + +VersionInfoCopyright=Copyright (C) 1999-2012 Jack Lloyd and others +VersionInfoVersion=%{version_major}.%{version_minor}.%{version_patch}.0 + +; Require at least Windows XP +MinVersion=5.1 + +ArchitecturesAllowed=%{innosetup_arch} +ArchitecturesInstallIn64BitMode=%{innosetup_arch} + +DefaultDirName={pf}\botan +DefaultGroupName=botan + +SolidCompression=yes + +OutputDir=. +OutputBaseFilename=botan-%{version}-%{arch} + +[Types] +Name: "user"; Description: "User" +Name: "devel"; Description: "Developer" +Name: "custom"; Description: "Custom"; Flags: iscustom + +[Components] +name: "dll"; Description: "Runtime DLLs"; Types: user devel custom; Flags: fixed +name: "implib"; Description: "Import Library"; Types: devel +name: "includes"; Description: "Include Files"; Types: devel +name: "docs"; Description: "Developer Documentation"; Types: devel + +[Files] +; DLL and license file is always included +Source: "..\doc\license.rst"; DestDir: "{app}"; Components: dll; AfterInstall: ConvertLineEndings +Source: "..\botan.dll"; DestDir: "{app}"; Components: dll +Source: "..\botan.dll.manifest"; DestDir: "{app}"; Components: dll; Flags: skipifsourcedoesntexist + +Source: "include\botan\*"; DestDir: "{app}\include\botan"; Components: includes; AfterInstall: ConvertLineEndings + +Source: "..\doc\*.rst"; DestDir: "{app}\doc"; Excludes: "license.rst"; Components: docs; AfterInstall: ConvertLineEndings + +Source: "..\doc\examples\*.cpp"; DestDir: "{app}\doc\examples"; Components: docs; AfterInstall: ConvertLineEndings + +Source: "..\botan.exp"; DestDir: "{app}"; Components: implib +Source: "..\botan.lib"; DestDir: "{app}"; Components: implib + +[Code] +const + LF = #10; + CR = #13; + CRLF = CR + LF; + +procedure ConvertLineEndings(); + var + FilePath : String; + FileContents : String; +begin + FilePath := ExpandConstant(CurrentFileName) + + if ExtractFileName(CurrentFileName) <> 'build.h' then + begin + LoadStringFromFile(FilePath, FileContents); + StringChangeEx(FileContents, LF, CRLF, False); + SaveStringToFile(FilePath, FileContents, False); + end; +end; diff --git a/comm/third_party/botan/src/build-data/makefile.in b/comm/third_party/botan/src/build-data/makefile.in new file mode 100644 index 0000000000..16d077e82a --- /dev/null +++ b/comm/third_party/botan/src/build-data/makefile.in @@ -0,0 +1,146 @@ + +# This makefile was generated using '%{command_line}' + +# Paths to relevant programs + +CXX = %{cxx} +LINKER = %{linker} +AR = %{ar_command} +AR_OPTIONS = %{ar_options} +PYTHON_EXE = %{python_exe} + +# Compiler Flags + +ABI_FLAGS = %{cc_sysroot} %{cxx_abi_flags} +LANG_FLAGS = %{cc_lang_flags} %{os_feature_macros} +CXXFLAGS = %{cc_compile_flags} -DBOTAN_IS_BEING_BUILT +WARN_FLAGS = %{cc_warning_flags} +LIB_FLAGS = %{lib_flags} +LDFLAGS = %{ldflags} + +EXE_LINK_CMD = %{exe_link_cmd} + +LIB_LINKS_TO = %{external_link_cmd} %{link_to} +EXE_LINKS_TO = %{link_to_botan} $(LIB_LINKS_TO) %{extra_libs} + +BUILD_FLAGS = $(ABI_FLAGS) $(LANG_FLAGS) $(CXXFLAGS) $(WARN_FLAGS) + +SCRIPTS_DIR = %{scripts_dir} +INSTALLED_LIB_DIR = %{libdir} + +# The primary target +all: %{all_targets} + +# Executable targets +CLI = %{cli_exe} +TEST = %{test_exe} +LIBRARIES = %{library_targets} + +cli: $(CLI) +tests: $(TEST) +libs: $(LIBRARIES) +docs: %{doc_stamp_file} + +# Misc targets + +%{if make_supports_phony} +.PHONY: all cli libs tests check docs clean distclean install +%{endif} + +%{doc_stamp_file}: %{doc_dir}/*.rst %{doc_dir}/api_ref/*.rst %{doc_dir}/dev_ref/*.rst + "$(PYTHON_EXE)" "$(SCRIPTS_DIR)/build_docs.py" --build-dir="%{build_dir}" + +clean: + "$(PYTHON_EXE)" "$(SCRIPTS_DIR)/cleanup.py" --build-dir="%{build_dir}" + +distclean: + "$(PYTHON_EXE)" "$(SCRIPTS_DIR)/cleanup.py" --build-dir="%{build_dir}" --distclean + +install: %{install_targets} + "$(PYTHON_EXE)" "$(SCRIPTS_DIR)/install.py" --prefix="%{prefix}" --build-dir="%{build_dir}" --bindir="%{bindir}" --libdir="%{libdir}" --docdir="%{docdir}" --includedir="%{includedir}" + +check: tests + "$(PYTHON_EXE)" "$(SCRIPTS_DIR)/check.py" --build-dir="%{build_dir}" + +# Object Files +LIBOBJS = %{join lib_objs} + +CLIOBJS = %{join cli_objs} + +TESTOBJS = %{join test_objs} + +# Executable targets + +$(CLI): $(LIBRARIES) $(CLIOBJS) + $(EXE_LINK_CMD) $(ABI_FLAGS) $(CLIOBJS) $(LDFLAGS) $(EXE_LINKS_TO) %{output_to_exe}$@ + +$(TEST): $(LIBRARIES) $(TESTOBJS) + $(EXE_LINK_CMD) $(ABI_FLAGS) $(TESTOBJS) $(LDFLAGS) $(EXE_LINKS_TO) %{output_to_exe}$@ + +%{if build_fuzzers} + +FUZZERS = %{fuzzer_bin} + +fuzzers: $(LIBRARIES) $(FUZZERS) + +fuzzer_corpus: + git clone --depth=1 https://github.com/randombit/crypto-corpus.git fuzzer_corpus + +fuzzer_corpus_zip: fuzzer_corpus + ./src/scripts/create_corpus_zip.py fuzzer_corpus %{fuzzobj_dir} + +%{endif} + +%{if build_bogo_shim} + +bogo_shim: %{out_dir}/botan_bogo_shim + +# BoGo shim +%{out_dir}/botan_bogo_shim: %{bogo_shim_src} $(LIBRARIES) + $(CXX) $(BUILD_FLAGS) %{include_paths} %{bogo_shim_src} $(LDFLAGS) $(EXE_LINKS_TO) %{output_to_exe}$@ + +%{endif} + +# Library targets + +%{if build_static_lib} + +%{out_dir}/%{static_lib_name}: $(LIBOBJS) + $(AR) $(AR_OPTIONS) %{ar_output_to}$@ $(LIBOBJS) + +%{endif} + +%{if build_shared_lib} + +%{out_dir}/%{shared_lib_name}: $(LIBOBJS) + %{lib_link_cmd} $(ABI_FLAGS) $(LDFLAGS) $(LIBOBJS) $(LIB_LINKS_TO) %{output_to_exe}$@ +%{endif} +%{if symlink_shared_lib} + cd %{out_dir} && ln -fs %{shared_lib_name} %{soname_base} + cd %{out_dir} && ln -fs %{shared_lib_name} %{soname_patch} +%{endif} + +# Build Commands + +%{for lib_build_info} +%{obj}: %{src} + $(CXX) $(LIB_FLAGS) $(BUILD_FLAGS) %{isa_flags} %{include_paths} %{dash_c} %{src} %{dash_o}$@ +%{endfor} + +%{for cli_build_info} +%{obj}: %{src} + $(CXX) $(BUILD_FLAGS) %{isa_flags} %{include_paths} %{dash_c} %{src} %{dash_o}$@ +%{endfor} + +%{for test_build_info} +%{obj}: %{src} + $(CXX) $(BUILD_FLAGS) %{isa_flags} %{include_paths} %{dash_c} %{src} %{dash_o}$@ +%{endfor} + +%{for fuzzer_build_info} +%{obj}: %{src} + $(CXX) $(BUILD_FLAGS) %{isa_flags} %{include_paths} %{dash_c} %{src} %{dash_o}$@ + +%{exe}: %{obj} $(LIBRARIES) + $(EXE_LINK_CMD) $(ABI_FLAGS) %{obj} $(EXE_LINKS_TO) %{fuzzer_lib} %{output_to_exe}$@ +%{endfor} diff --git a/comm/third_party/botan/src/build-data/oids.txt b/comm/third_party/botan/src/build-data/oids.txt new file mode 100644 index 0000000000..03ce80a843 --- /dev/null +++ b/comm/third_party/botan/src/build-data/oids.txt @@ -0,0 +1,335 @@ +# Regenerate with ./src/scripts/oids.py oids > src/lib/asn1/oid_maps.cpp +# AND ./src/scripts/oids.py dn_ub > src/lib/x509/x509_dn_ub.cpp +# (if you modified something under [dn] +# AND ./src/scripts/oids.py pads > src/lib/pk_pad/padding.cpp +# (if you modified something under [signature] + +# Public key types +[pubkey] +1.2.840.113549.1.1.1 = RSA +2.5.8.1.1 = RSA +1.2.840.10040.4.1 = DSA +1.2.840.10046.2.1 = DH +1.3.6.1.4.1.3029.1.2.1 = ElGamal +1.3.6.1.4.1.25258.1.3 = McEliece +1.3.101.110 = Curve25519 +1.3.101.112 = Ed25519 + +# XMSS +1.3.6.1.4.1.25258.1.5 = XMSS-draft6 +1.3.6.1.4.1.25258.1.8 = XMSS-draft12 +# draft-vangeest-x509-hash-sigs-03 +0.4.0.127.0.15.1.1.13.0 = XMSS + +# X9.62 ecPublicKey, valid for ECDSA and ECDH (RFC 3279 sec 2.3.5) +1.2.840.10045.2.1 = ECDSA +1.3.132.1.12 = ECDH + +1.2.156.10197.1.301.1 = SM2_Sig +1.2.156.10197.1.301.1 = SM2 +1.2.156.10197.1.301.2 = SM2_Kex +1.2.156.10197.1.301.3 = SM2_Enc + +# ecgPublicKey (see https://www.teletrust.de/projekte/oid/) +1.3.36.3.3.2.5.2.1 = ECGDSA + +# EC-KCDSA mechanism (Elliptic Curve KCDSA) +1.0.14888.3.0.5 = ECKCDSA + +1.2.643.2.2.19 = GOST-34.10 +1.2.643.7.1.1.1.1 = GOST-34.10-2012-256 +1.2.643.7.1.1.1.2 = GOST-34.10-2012-512 + +# OpenPGP (RFC4880bis) +1.3.6.1.4.1.11591.15.1 = OpenPGP.Ed25519 +1.3.6.1.4.1.3029.1.5.1 = OpenPGP.Curve25519 + +[cipher] +# Cipher modes +1.3.14.3.2.7 = DES/CBC +1.2.840.113549.3.7 = TripleDES/CBC +1.2.840.113533.7.66.10 = CAST-128/CBC +2.16.840.1.101.3.4.1.2 = AES-128/CBC +2.16.840.1.101.3.4.1.22 = AES-192/CBC +2.16.840.1.101.3.4.1.42 = AES-256/CBC +1.2.410.200004.1.4 = SEED/CBC +1.2.156.10197.1.104.2 = SM4/CBC + +1.2.840.113549.1.9.16.3.18 = ChaCha20Poly1305 + +2.16.840.1.101.3.4.1.6 = AES-128/GCM +2.16.840.1.101.3.4.1.26 = AES-192/GCM +2.16.840.1.101.3.4.1.46 = AES-256/GCM + +2.16.840.1.101.3.4.1.7 = AES-128/CCM +2.16.840.1.101.3.4.1.27 = AES-192/CCM +2.16.840.1.101.3.4.1.47 = AES-256/CCM + +1.2.392.200011.61.1.1.1.2 = Camellia-128/CBC +1.2.392.200011.61.1.1.1.3 = Camellia-192/CBC +1.2.392.200011.61.1.1.1.4 = Camellia-256/CBC + +0.3.4401.5.3.1.9.6 = Camellia-128/GCM +0.3.4401.5.3.1.9.26 = Camellia-192/GCM +0.3.4401.5.3.1.9.46 = Camellia-256/GCM + +1.2.156.10197.1.104.8 = SM4/GCM + +1.3.6.1.4.1.25258.3.1 = Serpent/CBC +1.3.6.1.4.1.25258.3.2 = Threefish-512/CBC +1.3.6.1.4.1.25258.3.3 = Twofish/CBC + +1.3.6.1.4.1.25258.3.101 = Serpent/GCM +1.3.6.1.4.1.25258.3.102 = Twofish/GCM + +1.3.6.1.4.1.25258.3.2.1 = AES-128/OCB +1.3.6.1.4.1.25258.3.2.2 = AES-192/OCB +1.3.6.1.4.1.25258.3.2.3 = AES-256/OCB +1.3.6.1.4.1.25258.3.2.4 = Serpent/OCB +1.3.6.1.4.1.25258.3.2.5 = Twofish/OCB +1.3.6.1.4.1.25258.3.2.6 = Camellia-128/OCB +1.3.6.1.4.1.25258.3.2.7 = Camellia-192/OCB +1.3.6.1.4.1.25258.3.2.8 = Camellia-256/OCB + +1.2.156.10197.1.104.100 = SM4/OCB + +1.3.6.1.4.1.25258.3.4.1 = AES-128/SIV +1.3.6.1.4.1.25258.3.4.2 = AES-192/SIV +1.3.6.1.4.1.25258.3.4.3 = AES-256/SIV +1.3.6.1.4.1.25258.3.4.4 = Serpent/SIV +1.3.6.1.4.1.25258.3.4.5 = Twofish/SIV +1.3.6.1.4.1.25258.3.4.6 = Camellia-128/SIV +1.3.6.1.4.1.25258.3.4.7 = Camellia-192/SIV +1.3.6.1.4.1.25258.3.4.8 = Camellia-256/SIV +1.3.6.1.4.1.25258.3.4.9 = SM4/SIV + +[hash] +# Hash functions +1.2.840.113549.2.5 = MD5 +1.3.6.1.4.1.11591.12.2 = Tiger(24,3) +1.2.156.10197.1.401 = SM3 +1.3.14.3.2.26 = SHA-160 +1.3.36.3.2.1 = RIPEMD-160 +1.2.643.7.1.1.2.2 = Streebog-256 +1.2.643.7.1.1.2.3 = Streebog-512 + +# From NIST: +2.16.840.1.101.3.4.2.1 = SHA-256 +2.16.840.1.101.3.4.2.2 = SHA-384 +2.16.840.1.101.3.4.2.3 = SHA-512 +2.16.840.1.101.3.4.2.4 = SHA-224 +2.16.840.1.101.3.4.2.6 = SHA-512-256 +2.16.840.1.101.3.4.2.7 = SHA-3(224) +2.16.840.1.101.3.4.2.8 = SHA-3(256) +2.16.840.1.101.3.4.2.9 = SHA-3(384) +2.16.840.1.101.3.4.2.10 = SHA-3(512) +2.16.840.1.101.3.4.2.11 = SHAKE-128 +2.16.840.1.101.3.4.2.12 = SHAKE-256 + +[mac] +# MACs +1.2.840.113549.2.7 = HMAC(SHA-160) +1.2.840.113549.2.8 = HMAC(SHA-224) +1.2.840.113549.2.9 = HMAC(SHA-256) +1.2.840.113549.2.10 = HMAC(SHA-384) +1.2.840.113549.2.11 = HMAC(SHA-512) +1.2.840.113549.2.13 = HMAC(SHA-512-256) + +[keywrap] +# Keywrap algorithms +1.2.840.113549.1.9.16.3.6 = KeyWrap.TripleDES +1.2.840.113533.7.66.15 = KeyWrap.CAST-128 +2.16.840.1.101.3.4.1.5 = KeyWrap.AES-128 +2.16.840.1.101.3.4.1.25 = KeyWrap.AES-192 +2.16.840.1.101.3.4.1.45 = KeyWrap.AES-256 + +[compression] +1.2.840.113549.1.9.16.3.8 = Compression.Zlib + +# Signature algos +[signature] +1.2.840.113549.1.1.4 = RSA/EMSA3(MD5) +1.2.840.113549.1.1.5 = RSA/EMSA3(SHA-160) +1.2.840.113549.1.1.8 = MGF1 +1.2.840.113549.1.1.10 = RSA/EMSA4 +1.2.840.113549.1.1.11 = RSA/EMSA3(SHA-256) +1.2.840.113549.1.1.12 = RSA/EMSA3(SHA-384) +1.2.840.113549.1.1.13 = RSA/EMSA3(SHA-512) +1.2.840.113549.1.1.14 = RSA/EMSA3(SHA-224) +1.2.840.113549.1.1.16 = RSA/EMSA3(SHA-512-256) +1.3.36.3.3.1.2 = RSA/EMSA3(RIPEMD-160) + +1.2.156.10197.1.501 = SM2_Sig/SM3 +1.2.156.10197.1.504 = RSA/EMSA3(SM3) + +1.2.840.10040.4.3 = DSA/EMSA1(SHA-160) + +2.16.840.1.101.3.4.3.1 = DSA/EMSA1(SHA-224) +2.16.840.1.101.3.4.3.2 = DSA/EMSA1(SHA-256) +2.16.840.1.101.3.4.3.3 = DSA/EMSA1(SHA-384) +2.16.840.1.101.3.4.3.4 = DSA/EMSA1(SHA-512) +2.16.840.1.101.3.4.3.5 = DSA/EMSA1(SHA-3(224)) +2.16.840.1.101.3.4.3.6 = DSA/EMSA1(SHA-3(256)) +2.16.840.1.101.3.4.3.7 = DSA/EMSA1(SHA-3(384)) +2.16.840.1.101.3.4.3.8 = DSA/EMSA1(SHA-3(512)) + +2.16.840.1.101.3.4.3.9 = ECDSA/EMSA1(SHA-3(224)) +2.16.840.1.101.3.4.3.10 = ECDSA/EMSA1(SHA-3(256)) +2.16.840.1.101.3.4.3.11 = ECDSA/EMSA1(SHA-3(384)) +2.16.840.1.101.3.4.3.12 = ECDSA/EMSA1(SHA-3(512)) + +2.16.840.1.101.3.4.3.13 = RSA/EMSA3(SHA-3(224)) +2.16.840.1.101.3.4.3.14 = RSA/EMSA3(SHA-3(256)) +2.16.840.1.101.3.4.3.15 = RSA/EMSA3(SHA-3(384)) +2.16.840.1.101.3.4.3.16 = RSA/EMSA3(SHA-3(512)) + +1.2.840.10045.4.1 = ECDSA/EMSA1(SHA-160) +1.2.840.10045.4.3.1 = ECDSA/EMSA1(SHA-224) +1.2.840.10045.4.3.2 = ECDSA/EMSA1(SHA-256) +1.2.840.10045.4.3.3 = ECDSA/EMSA1(SHA-384) +1.2.840.10045.4.3.4 = ECDSA/EMSA1(SHA-512) + +1.3.36.3.3.2.5.4.1 = ECGDSA/EMSA1(RIPEMD-160) +1.3.36.3.3.2.5.4.2 = ECGDSA/EMSA1(SHA-160) +1.3.36.3.3.2.5.4.3 = ECGDSA/EMSA1(SHA-224) +1.3.36.3.3.2.5.4.4 = ECGDSA/EMSA1(SHA-256) +1.3.36.3.3.2.5.4.5 = ECGDSA/EMSA1(SHA-384) +1.3.36.3.3.2.5.4.6 = ECGDSA/EMSA1(SHA-512) + +1.2.410.200004.1.100.4.3 = ECKCDSA/EMSA1(SHA-1) +1.2.410.200004.1.100.4.4 = ECKCDSA/EMSA1(SHA-224) +1.2.410.200004.1.100.4.5 = ECKCDSA/EMSA1(SHA-256) + +1.2.643.2.2.3 = GOST-34.10/EMSA1(GOST-R-34.11-94) + +1.2.643.7.1.1.3.2 = GOST-34.10-2012-256/EMSA1(Streebog-256) +1.2.643.7.1.1.3.3 = GOST-34.10-2012-512/EMSA1(Streebog-512) + +1.3.6.1.4.1.25258.1.6.1 = GOST-34.10-2012-256/EMSA1(SHA-256) + +# Encryption algos +[encryption] +1.2.840.113549.1.1.7 = RSA/OAEP + +# DN with upper bounds from RFC 5280, Appendix A +[dn] +2.5.4.3 = X520.CommonName = 64 +2.5.4.4 = X520.Surname = 40 +2.5.4.5 = X520.SerialNumber = 64 +2.5.4.6 = X520.Country = 3 +2.5.4.7 = X520.Locality = 128 +2.5.4.8 = X520.State = 128 +2.5.4.9 = X520.StreetAddress = 128 +2.5.4.10 = X520.Organization = 64 +2.5.4.11 = X520.OrganizationalUnit = 64 +2.5.4.12 = X520.Title = 64 +# the following three types are naming attributes of type "X520name" and inherit its bound +2.5.4.42 = X520.GivenName = 32768 +2.5.4.43 = X520.Initials = 32768 +2.5.4.44 = X520.GenerationalQualifier = 32768 +2.5.4.46 = X520.DNQualifier = 64 +2.5.4.65 = X520.Pseudonym = 128 + +[pbe] +1.2.840.113549.1.5.12 = PKCS5.PBKDF2 +1.2.840.113549.1.5.13 = PBES2 +1.2.840.113549.1.5.13 = PBE-PKCS5v20 + +1.3.6.1.4.1.11591.4.11 = Scrypt + +[pkcs9] +1.2.840.113549.1.9.1 = PKCS9.EmailAddress +1.2.840.113549.1.9.2 = PKCS9.UnstructuredName +1.2.840.113549.1.9.3 = PKCS9.ContentType +1.2.840.113549.1.9.4 = PKCS9.MessageDigest +1.2.840.113549.1.9.7 = PKCS9.ChallengePassword +1.2.840.113549.1.9.14 = PKCS9.ExtensionRequest + +[pkix] +2.5.29.14 = X509v3.SubjectKeyIdentifier +2.5.29.15 = X509v3.KeyUsage +2.5.29.16 = X509v3.PrivateKeyUsagePeriod +2.5.29.17 = X509v3.SubjectAlternativeName +2.5.29.18 = X509v3.IssuerAlternativeName +2.5.29.19 = X509v3.BasicConstraints +2.5.29.20 = X509v3.CRLNumber +2.5.29.21 = X509v3.ReasonCode +2.5.29.23 = X509v3.HoldInstructionCode +2.5.29.24 = X509v3.InvalidityDate +2.5.29.28 = X509v3.CRLIssuingDistributionPoint +2.5.29.30 = X509v3.NameConstraints +2.5.29.31 = X509v3.CRLDistributionPoints +2.5.29.32 = X509v3.CertificatePolicies +2.5.29.35 = X509v3.AuthorityKeyIdentifier +2.5.29.36 = X509v3.PolicyConstraints +2.5.29.37 = X509v3.ExtendedKeyUsage +1.3.6.1.5.5.7.1.1 = PKIX.AuthorityInformationAccess + +2.5.29.32.0 = X509v3.AnyPolicy + +1.2.643.100.111 = GOST.SubjectSigningTool +1.2.643.100.112 = GOST.IssuerSigningTool + +1.2.643.100.1 = GOST.OGRN +1.2.643.3.131.1.1 = GOST.INN + +1.3.6.1.5.5.7.3.1 = PKIX.ServerAuth +1.3.6.1.5.5.7.3.2 = PKIX.ClientAuth +1.3.6.1.5.5.7.3.3 = PKIX.CodeSigning +1.3.6.1.5.5.7.3.4 = PKIX.EmailProtection +1.3.6.1.5.5.7.3.5 = PKIX.IPsecEndSystem +1.3.6.1.5.5.7.3.6 = PKIX.IPsecTunnel +1.3.6.1.5.5.7.3.7 = PKIX.IPsecUser +1.3.6.1.5.5.7.3.8 = PKIX.TimeStamping +1.3.6.1.5.5.7.3.9 = PKIX.OCSPSigning + +1.3.6.1.5.5.7.8.5 = PKIX.XMPPAddr + +1.3.6.1.5.5.7.48.1 = PKIX.OCSP +1.3.6.1.5.5.7.48.1.1 = PKIX.OCSP.BasicResponse +1.3.6.1.5.5.7.48.2 = PKIX.CertificateAuthorityIssuers + +1.3.6.1.4.1.311.20.2.2 = Microsoft SmartcardLogon +1.3.6.1.4.1.311.20.2.3 = Microsoft UPN + +2.16.840.1.113730.1.13 = Certificate Comment + +# ECC param sets +[ecc_param] +1.3.132.0.8 = secp160r1 +1.3.132.0.9 = secp160k1 +1.3.132.0.10 = secp256k1 +1.3.132.0.30 = secp160r2 +1.3.132.0.31 = secp192k1 +1.3.132.0.32 = secp224k1 +1.3.132.0.33 = secp224r1 +1.3.132.0.34 = secp384r1 +1.3.132.0.35 = secp521r1 +1.3.6.1.4.1.8301.3.1.2.9.0.38 = secp521r1 + +1.2.840.10045.3.1.1 = secp192r1 +1.2.840.10045.3.1.2 = x962_p192v2 +1.2.840.10045.3.1.3 = x962_p192v3 +1.2.840.10045.3.1.4 = x962_p239v1 +1.2.840.10045.3.1.5 = x962_p239v2 +1.2.840.10045.3.1.6 = x962_p239v3 +1.2.840.10045.3.1.7 = secp256r1 + +1.2.156.10197.1.301 = sm2p256v1 + +1.3.36.3.3.2.8.1.1.1 = brainpool160r1 +1.3.36.3.3.2.8.1.1.3 = brainpool192r1 +1.3.36.3.3.2.8.1.1.5 = brainpool224r1 +1.3.36.3.3.2.8.1.1.7 = brainpool256r1 +1.3.36.3.3.2.8.1.1.9 = brainpool320r1 +1.3.36.3.3.2.8.1.1.11 = brainpool384r1 +1.3.36.3.3.2.8.1.1.13 = brainpool512r1 + +1.2.250.1.223.101.256.1 = frp256v1 + +1.2.643.7.1.2.1.1.1 = gost_256A +1.2.643.7.1.2.1.1.2 = gost_256B +1.2.643.7.1.2.1.2.1 = gost_512A +1.2.643.7.1.2.1.2.2 = gost_512B +1.2.643.2.2.35.1 = gost_256A +1.2.643.2.2.36.0 = gost_256A diff --git a/comm/third_party/botan/src/build-data/os/aix.txt b/comm/third_party/botan/src/build-data/os/aix.txt new file mode 100644 index 0000000000..fd8cf2eb1e --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/aix.txt @@ -0,0 +1,18 @@ + +soname_suffix "so" + +use_stack_protector no + + +posix1 +posix_mlock +clock_gettime +dev_random +proc_fs + +atomics +sockets +threads +thread_local +filesystem + diff --git a/comm/third_party/botan/src/build-data/os/android.txt b/comm/third_party/botan/src/build-data/os/android.txt new file mode 100644 index 0000000000..f8f61f7b42 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/android.txt @@ -0,0 +1,26 @@ + +soname_suffix "so" + + +posix1 +posix_mlock +clock_gettime + +# arc4random_buf preferably backed-up by Chacha20 rather +# than RC4. can possibly be disabled by --without-os-feature=arc4random +arc4random +dev_random + +# getauxval is available in Android NDK for min API 18 and in Crystax NDK +# for all min API levels. Use --without-os-feature=getauxval to disable +getauxval + +# Added in API 28 +#getentropy + +atomics +sockets +threads +thread_local +filesystem + diff --git a/comm/third_party/botan/src/build-data/os/cygwin.txt b/comm/third_party/botan/src/build-data/os/cygwin.txt new file mode 100644 index 0000000000..dabc018c3d --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/cygwin.txt @@ -0,0 +1,20 @@ + +program_suffix .exe + +# Cygwin supports shared libs fine, but there are problems with making a Botan +# shared library when libraries it depends on are static-only (such as libz). +# So until I can figure out a work-around, it's disabled. + +install_root c:\Botan +doc_dir docs + + +posix1 +dev_random + +atomics +sockets +threads +thread_local +filesystem + diff --git a/comm/third_party/botan/src/build-data/os/dragonfly.txt b/comm/third_party/botan/src/build-data/os/dragonfly.txt new file mode 100644 index 0000000000..f2cc1cb76f --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/dragonfly.txt @@ -0,0 +1,17 @@ + +soname_suffix "so" + + +posix1 +posix_mlock +clock_gettime +proc_fs +dev_random +arc4random + +atomics +sockets +threads +thread_local +filesystem + diff --git a/comm/third_party/botan/src/build-data/os/emscripten.txt b/comm/third_party/botan/src/build-data/os/emscripten.txt new file mode 100644 index 0000000000..0068fb171a --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/emscripten.txt @@ -0,0 +1,17 @@ + +obj_suffix bc + +static_suffix a +program_suffix .bc + +ar_command emar +ar_options cr + +use_stack_protector no + + +atomics +filesystem +dev_random +posix1 + diff --git a/comm/third_party/botan/src/build-data/os/freebsd.txt b/comm/third_party/botan/src/build-data/os/freebsd.txt new file mode 100644 index 0000000000..1b9b3817de --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/freebsd.txt @@ -0,0 +1,22 @@ + +soname_suffix "so" + +default_compiler clang + + +posix1 +posix_mlock +clock_gettime +dev_random +arc4random +explicit_bzero +cap_enter +elf_aux_info +getentropy + +atomics +sockets +threads +thread_local +filesystem + diff --git a/comm/third_party/botan/src/build-data/os/haiku.txt b/comm/third_party/botan/src/build-data/os/haiku.txt new file mode 100644 index 0000000000..7a4bcbe892 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/haiku.txt @@ -0,0 +1,25 @@ + +soname_suffix "so" + +install_root /boot +header_dir develop/headers +lib_dir system/lib +doc_dir system/documentation + +use_stack_protector no + + +posix1 +clock_gettime +dev_random + +atomics +sockets +threads +thread_local +filesystem + + + +beos + diff --git a/comm/third_party/botan/src/build-data/os/hpux.txt b/comm/third_party/botan/src/build-data/os/hpux.txt new file mode 100644 index 0000000000..ea699910cb --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/hpux.txt @@ -0,0 +1,20 @@ + +# It is "sl" on HP-PA, but HP-UX on PA is EOL +soname_suffix "so" + + +posix1 +posix_mlock +clock_gettime +dev_random + +atomics +sockets +threads +thread_local +filesystem + + + +hp-ux + diff --git a/comm/third_party/botan/src/build-data/os/hurd.txt b/comm/third_party/botan/src/build-data/os/hurd.txt new file mode 100644 index 0000000000..589b99e2d9 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/hurd.txt @@ -0,0 +1,19 @@ + +soname_suffix "so" + + +posix1 +posix_mlock +dev_random +clock_gettime + +atomics +sockets +threads +thread_local +filesystem + + + +gnu + diff --git a/comm/third_party/botan/src/build-data/os/includeos.txt b/comm/third_party/botan/src/build-data/os/includeos.txt new file mode 100644 index 0000000000..7e45eb47c2 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/includeos.txt @@ -0,0 +1,5 @@ + +posix1 +dev_random +atomics + diff --git a/comm/third_party/botan/src/build-data/os/ios.txt b/comm/third_party/botan/src/build-data/os/ios.txt new file mode 100644 index 0000000000..c65f243058 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/ios.txt @@ -0,0 +1,23 @@ + +default_compiler clang + +uses_pkg_config no + +doc_dir doc + + +posix1 +posix_mlock +arc4random + +commoncrypto + +atomics +sockets +threads +thread_local +filesystem + + + + diff --git a/comm/third_party/botan/src/build-data/os/linux.txt b/comm/third_party/botan/src/build-data/os/linux.txt new file mode 100644 index 0000000000..daf98f2b61 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/linux.txt @@ -0,0 +1,26 @@ + +soname_suffix "so" + + +posix1 +posix_mlock + +dev_random +proc_fs +clock_gettime +getauxval + +# these are not enabled by default as only available in newer kernel/glibc +#getrandom +#getentropy + +atomics +sockets +threads +thread_local +filesystem + + + +linux-gnu + diff --git a/comm/third_party/botan/src/build-data/os/llvm.txt b/comm/third_party/botan/src/build-data/os/llvm.txt new file mode 100644 index 0000000000..0cda2f7e80 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/llvm.txt @@ -0,0 +1,15 @@ + +obj_suffix bc + +static_suffix bc +program_suffix .bc + +ar_command llvm-link +ar_options -o + +use_stack_protector no + + +filesystem +atomics + diff --git a/comm/third_party/botan/src/build-data/os/macos.txt b/comm/third_party/botan/src/build-data/os/macos.txt new file mode 100644 index 0000000000..b603d18dfc --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/macos.txt @@ -0,0 +1,32 @@ + +default_compiler clang + +soname_pattern_base "lib{libname}.dylib" +soname_pattern_abi "lib{libname}.{abi_rev}.dylib" +soname_pattern_patch "lib{libname}.{abi_rev}.{version_minor}.{version_patch}.dylib" + +doc_dir doc + + +posix1 +posix_mlock +arc4random +getentropy +dev_random +clock_gettime + +commoncrypto +apple_keychain + +atomics +sockets +threads +thread_local +filesystem + + + +darwin +macosx +osx + diff --git a/comm/third_party/botan/src/build-data/os/mingw.txt b/comm/third_party/botan/src/build-data/os/mingw.txt new file mode 100644 index 0000000000..b2cc2f0b80 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/mingw.txt @@ -0,0 +1,33 @@ + +program_suffix .exe +obj_suffix o +static_suffix a + +install_root /mingw +header_dir include +lib_dir lib +doc_dir share/doc + +# see https://sourceforge.net/p/mingw-w64/bugs/755/ +use_stack_protector no + + +_WIN32_WINNT=0x0600 + + + +msys +mingw32.* + + + +win32 +rtlgenrandom +virtual_lock + +atomics +threads +thread_local +filesystem +certificate_store + diff --git a/comm/third_party/botan/src/build-data/os/nacl.txt b/comm/third_party/botan/src/build-data/os/nacl.txt new file mode 100644 index 0000000000..0cb08ab936 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/nacl.txt @@ -0,0 +1,6 @@ + + + +threads +thread_local + diff --git a/comm/third_party/botan/src/build-data/os/netbsd.txt b/comm/third_party/botan/src/build-data/os/netbsd.txt new file mode 100644 index 0000000000..9be8a1f8ac --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/netbsd.txt @@ -0,0 +1,21 @@ + +soname_suffix "so" + + +posix1 +posix_mlock +clock_gettime +dev_random +arc4random +explicit_memset + +atomics +sockets +threads +thread_local +filesystem + + + +_NETBSD_SOURCE + diff --git a/comm/third_party/botan/src/build-data/os/none.txt b/comm/third_party/botan/src/build-data/os/none.txt new file mode 100644 index 0000000000..d514a5ef7c --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/none.txt @@ -0,0 +1,4 @@ + + + + diff --git a/comm/third_party/botan/src/build-data/os/openbsd.txt b/comm/third_party/botan/src/build-data/os/openbsd.txt new file mode 100644 index 0000000000..70f49e6ac8 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/openbsd.txt @@ -0,0 +1,25 @@ + +soname_pattern_base "lib{libname}.so" +soname_pattern_abi "lib{libname}.so.{abi_rev}.{version_minor}" +soname_pattern_patch "lib{libname}.so.{abi_rev}.{version_minor}" + +shared_lib_symlinks no + +default_compiler clang + + +posix1 +posix_mlock +clock_gettime +dev_random +arc4random +getentropy +explicit_bzero +pledge + +atomics +sockets +threads +thread_local +filesystem + diff --git a/comm/third_party/botan/src/build-data/os/qnx.txt b/comm/third_party/botan/src/build-data/os/qnx.txt new file mode 100644 index 0000000000..feedf5f753 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/qnx.txt @@ -0,0 +1,18 @@ +soname_suffix "so" + + +posix1 +posix_mlock +clock_gettime +dev_random + +atomics +sockets +threads +thread_local +filesystem + + + +_QNX_SOURCE + diff --git a/comm/third_party/botan/src/build-data/os/solaris.txt b/comm/third_party/botan/src/build-data/os/solaris.txt new file mode 100644 index 0000000000..4ca9b0e8ca --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/solaris.txt @@ -0,0 +1,21 @@ + +soname_suffix "so" + + +posix1 +posix_mlock +clock_gettime +dev_random +proc_fs + +atomics +threads +thread_local +sockets +filesystem +setppriv + + + +sunos + diff --git a/comm/third_party/botan/src/build-data/os/uwp.txt b/comm/third_party/botan/src/build-data/os/uwp.txt new file mode 100644 index 0000000000..eb79c65ed2 --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/uwp.txt @@ -0,0 +1,25 @@ + +# ? +program_suffix .exe +obj_suffix obj +static_suffix lib + +install_root c:\\Botan +doc_dir docs + + +win32 +winsock2 +crypto_ng + +rtlsecurezeromemory + +atomics +threads +thread_local +filesystem + + + +winphone + diff --git a/comm/third_party/botan/src/build-data/os/windows.txt b/comm/third_party/botan/src/build-data/os/windows.txt new file mode 100644 index 0000000000..07bfefb13b --- /dev/null +++ b/comm/third_party/botan/src/build-data/os/windows.txt @@ -0,0 +1,48 @@ + +cli_exe_name botan-cli + +program_suffix .exe +obj_suffix obj +static_suffix lib +lib_prefix '' + +shared_lib_symlinks no + +default_compiler msvc + +uses_pkg_config no + +# For historical reasons? the library does not have the major number on Windows +# This should probably be fixed in a future major release. +library_name 'botan{suffix}' + +soname_pattern_base "{libname}.dll" + +install_root c:\\Botan +doc_dir docs + + +_WIN32_WINNT=0x0600 + + + +win32 +winsock2 + +rtlgenrandom +rtlsecurezeromemory + +virtual_lock + +atomics +threads +thread_local +filesystem + +certificate_store + + + +win32 +MSWin32 + diff --git a/comm/third_party/botan/src/build-data/policy/bsi.txt b/comm/third_party/botan/src/build-data/policy/bsi.txt new file mode 100644 index 0000000000..719afc8368 --- /dev/null +++ b/comm/third_party/botan/src/build-data/policy/bsi.txt @@ -0,0 +1,188 @@ + +# block +aes + +# modes +ccm +gcm +cbc +mode_pad + +# stream +ctr + +# hash +sha2_32 +sha2_64 +sha3 + +# mac +cmac +hmac +gmac + +# kdf +kdf1_iso18033 +sp800_108 +sp800_56c + +# pk_pad +eme_oaep +emsa_pssr +emsa1 +iso9796 + +# pubkey +dlies +dh +rsa +dsa +ecdsa +ecgdsa +ecies +eckcdsa +ecdh +xmss + +# rng +auto_rng +hmac_drbg + + + +# block +aes_ni +aes_vperm +aes_armv8 +aes_power8 + +# modes +ghash_cpu +ghash_vperm + +# hash +sha2_32_x86 +sha2_32_armv8 +sha2_32_bmi2 +sha2_64_bmi2 +sha3_bmi2 + +# entropy sources +dev_random +proc_walk +rdseed +win32_stats + +# rng +processor_rng +system_rng + +# utils +http_util # needed by x509 for OCSP online checks +locking_allocator +simd + + + +# block +aria +blowfish +camellia +cascade +cast128 +cast256 +des +gost_28147 +idea +idea_sse2 +kasumi +lion +misty1 +noekeon +noekeon_simd +seed +serpent +serpent_simd +serpent_avx2 +shacal2 +shacal2_x86 +shacal2_simd +sm4 +threefish_512 +threefish_512_avx2 +twofish +xtea + +# modes +chacha20poly1305 +eax +ocb +siv +cfb + +# stream +chacha +chacha_simd32 +chacha_avx2 +ofb +rc4 +salsa20 +shake_cipher + +# kdf +hkdf +kdf1 +kdf2 +prf_x942 +sp800_56a + +# pubkey +cecpq1 +curve25519 +ed25519 +elgamal +gost_3410 +mce +mceies +rfc6979 +newhope +sm2 + +# pk_pad +#eme_pkcs1 // needed for tls +#emsa_pkcs1 // needed for tls +emsa_raw +emsa_x931 + +# hash +blake2 +comb4p +gost_3411 +md4 +md5 +rmd160 +shake +skein +#sha1 // needed for x509 +sm3 +streebog +tiger +whirlpool +keccak + +# rng +chacha_rng + +# mac +cbc_mac +poly1305 +siphash +x919_mac + +# misc +bcrypt + +# tls +tls_10 + + diff --git a/comm/third_party/botan/src/build-data/policy/modern.txt b/comm/third_party/botan/src/build-data/policy/modern.txt new file mode 100644 index 0000000000..ce2b3fd2ab --- /dev/null +++ b/comm/third_party/botan/src/build-data/policy/modern.txt @@ -0,0 +1,131 @@ + +aes +serpent +threefish_512 +chacha + +sha2_32 +sha2_64 +blake2 +skein +keccak +sha3 + +gcm +ocb +chacha20poly1305 + +kdf2 +hkdf +cmac +hmac +poly1305 +siphash + +pbkdf2 +bcrypt + +# required for private key encryption +pbes2 + +ed25519 +curve25519 +ecdh +ecdsa +rsa +rfc6979 + +eme_oaep +emsa_pssr +emsa1 + +auto_rng +hmac_drbg + + + +ffi + +tls +prf_tls +newhope +ed25519 + +ghash_cpu +ghash_vperm + +locking_allocator +http_util # needed by x509 for OCSP online checks + +aes_ni +aes_vperm +aes_armv8 +aes_power8 +serpent_simd +serpent_avx2 +threefish_512_avx2 +chacha_simd32 +chacha_avx2 + +sha1_sse2 +sha1_x86 +sha1_armv8 +sha2_32_x86 +sha2_32_armv8 +sha2_32_bmi2 +sha2_64_bmi2 +sha3_bmi2 + +simd + +sessions_sql +certstor_sql + +system_rng +processor_rng + +# entropy sources +dev_random +proc_walk +rdseed +win32_stats + + + +# Just say no to TLS 1.0 +tls_cbc + +cast128 +cast256 +des +gost_28147 +idea +idea_sse2 +kasumi +lion +misty1 +rc4 +seed +xtea + +cbc_mac +x919_mac + +# MD5 and SHA1 are broken but not prohibited. They are widely in use +# in non-crypto contexts and are required by TLS currently +md4 +gost_3411 + +cfb +ofb + +elgamal +gost_3410 + +emsa_x931 +pbkdf1 +prf_x942 + +passhash9 +cryptobox + diff --git a/comm/third_party/botan/src/build-data/policy/nist.txt b/comm/third_party/botan/src/build-data/policy/nist.txt new file mode 100644 index 0000000000..e4a19b4fea --- /dev/null +++ b/comm/third_party/botan/src/build-data/policy/nist.txt @@ -0,0 +1,187 @@ + +des +aes + +gcm +ccm +ctr +cbc +mode_pad + +# hash +sha2_32 +sha2_64 +sha3 + +# mac +cmac +hmac +gmac + +# kdf +sp800_108 +sp800_56a +sp800_56c + +shake + +# pk_pad +eme_oaep +emsa_pssr +emsa1 + +# pubkey +dh +rsa +dsa +ecdsa +ecdh + +# rng +auto_rng +hmac_drbg + +# keywrap +rfc3394 + + + +# block +aes_ni +aes_vperm +aes_armv8 +aes_power8 + +# hash +sha2_32_x86 +sha2_32_armv8 +sha2_32_bmi2 +sha2_64_bmi2 +sha3_bmi2 + +# modes +ghash_cpu +ghash_vperm + +# hash +sha2_32_x86 +sha2_32_armv8 + +# entropy sources +dev_random +proc_walk +rdseed +win32_stats + +# rng +system_rng + +# utils +http_util # needed by x509 for OCSP online checks +locking_allocator +simd + + + +# block +aria +blowfish +camellia +cascade +cast128 +cast256 +gost_28147 +idea +idea_sse2 +kasumi +lion +misty1 +noekeon +noekeon_simd +seed +serpent +serpent_simd +serpent_avx2 +sm4 +shacal2 +shacal2_x86 +shacal2_simd +threefish_512 +threefish_512_avx2 +twofish +xtea + +# modes +chacha20poly1305 +eax +ocb +siv +cfb + +# stream +chacha +chacha_simd32 +chacha_avx2 +shake_cipher +ofb +rc4 +salsa20 + +# kdf +hkdf +kdf1 +kdf2 +prf_x942 + +# pubkey +curve25519 +ed25519 +ecgdsa +eckcdsa +elgamal +gost_3410 +mce +mceies +rfc6979 +newhope +cecpq1 +xmss +sm2 + +# pk_pad +#eme_pkcs1 // needed for tls +#emsa_pkcs1 // needed for tls +emsa_raw +emsa_x931 + +# hash +blake2 +comb4p +gost_3411 +md5 +md4 +rmd160 +skein +#sha1 // needed for x509 +sm3 +streebog +tiger +whirlpool + +# rng +chacha_rng + +# mac +cbc_mac +poly1305 +siphash +x919_mac + +# misc +bcrypt + +# tls +tls_10 +tls_cbc + + diff --git a/comm/third_party/botan/src/build-data/version.txt b/comm/third_party/botan/src/build-data/version.txt new file mode 100644 index 0000000000..e6fa783442 --- /dev/null +++ b/comm/third_party/botan/src/build-data/version.txt @@ -0,0 +1,11 @@ + +release_major = 2 +release_minor = 18 +release_patch = 2 +release_suffix = '' +release_so_abi_rev = 18 + +# These are set by the distribution script +release_vc_rev = 'git:a44f1489239e80937ca67564ff103421e5584069' +release_datestamp = 20211025 +release_type = 'release' diff --git a/comm/third_party/botan/src/cli/argon2.cpp b/comm/third_party/botan/src/cli/argon2.cpp new file mode 100644 index 0000000000..2b07027c33 --- /dev/null +++ b/comm/third_party/botan/src/cli/argon2.cpp @@ -0,0 +1,78 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_ARGON2) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_ARGON2) + +class Generate_Argon2 final : public Command + { + public: + Generate_Argon2() : Command("gen_argon2 --mem=65536 --p=1 --t=1 password") {} + + std::string group() const override + { + return "passhash"; + } + + std::string description() const override + { + return "Calculate Argon2 password hash"; + } + + void go() override + { + const std::string password = get_passphrase_arg("Passphrase to hash", "password"); + const size_t M = get_arg_sz("mem"); + const size_t p = get_arg_sz("p"); + const size_t t = get_arg_sz("t"); + + output() << Botan::argon2_generate_pwhash(password.data(), password.size(), rng(), p, M, t) << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("gen_argon2", Generate_Argon2); + +class Check_Argon2 final : public Command + { + public: + Check_Argon2() : Command("check_argon2 password hash") {} + + std::string group() const override + { + return "passhash"; + } + + std::string description() const override + { + return "Verify Argon2 password hash"; + } + + void go() override + { + const std::string password = get_passphrase_arg("Password to check", "password"); + const std::string hash = get_arg("hash"); + + const bool ok = Botan::argon2_check_pwhash(password.data(), password.size(), hash); + + output() << "Password is " << (ok ? "valid" : "NOT valid") << std::endl; + + if(ok == false) + set_return_code(1); + } + }; + +BOTAN_REGISTER_COMMAND("check_argon2", Check_Argon2); + +#endif // argon2 + +} diff --git a/comm/third_party/botan/src/cli/argparse.h b/comm/third_party/botan/src/cli/argparse.h new file mode 100644 index 0000000000..4df4a10c83 --- /dev/null +++ b/comm/third_party/botan/src/cli/argparse.h @@ -0,0 +1,280 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CLI_ARGPARSE_H_ +#define BOTAN_CLI_ARGPARSE_H_ + +#include +#include +#include +#include +#include +#include "cli_exceptions.h" + +namespace Botan_CLI { + +class Argument_Parser final + { + public: + Argument_Parser(const std::string& spec, + const std::vector& extra_flags = {}, + const std::vector& extra_opts = {}); + + void parse_args(const std::vector& params); + + bool flag_set(const std::string& flag) const; + + bool has_arg(const std::string& opt_name) const; + std::string get_arg(const std::string& option) const; + + std::string get_arg_or(const std::string& option, const std::string& otherwise) const; + + size_t get_arg_sz(const std::string& option) const; + + std::vector get_arg_list(const std::string& what) const; + + private: + // set in constructor + std::vector m_spec_args; + std::set m_spec_flags; + std::map m_spec_opts; + std::string m_spec_rest; + + // set in parse_args() + std::map m_user_args; + std::set m_user_flags; + std::vector m_user_rest; + }; + +bool Argument_Parser::flag_set(const std::string& flag_name) const + { + return m_user_flags.count(flag_name) > 0; + } + +bool Argument_Parser::has_arg(const std::string& opt_name) const + { + return m_user_args.count(opt_name) > 0; + } + +std::string Argument_Parser::get_arg(const std::string& opt_name) const + { + auto i = m_user_args.find(opt_name); + if(i == m_user_args.end()) + { + // this shouldn't occur unless you passed the wrong thing to get_arg + throw CLI_Error("Unknown option " + opt_name + " used (program bug)"); + } + return i->second; + } + +std::string Argument_Parser::get_arg_or(const std::string& opt_name, const std::string& otherwise) const + { + auto i = m_user_args.find(opt_name); + if(i == m_user_args.end() || i->second.empty()) + { + return otherwise; + } + return i->second; + } + +size_t Argument_Parser::get_arg_sz(const std::string& opt_name) const + { + const std::string s = get_arg(opt_name); + + try + { + return static_cast(std::stoul(s)); + } + catch(std::exception&) + { + throw CLI_Usage_Error("Invalid integer value '" + s + "' for option " + opt_name); + } + } + +std::vector Argument_Parser::get_arg_list(const std::string& what) const + { + if(what == m_spec_rest) + return m_user_rest; + + return Botan::split_on(get_arg(what), ','); + } + +void Argument_Parser::parse_args(const std::vector& params) + { + std::vector args; + for(auto const& param : params) + { + if(param.find("--") == 0) + { + // option + const auto eq = param.find('='); + + if(eq == std::string::npos) + { + const std::string opt_name = param.substr(2, std::string::npos); + + if(m_spec_flags.count(opt_name) == 0) + { + if(m_spec_opts.count(opt_name)) + { + throw CLI_Usage_Error("Invalid usage of option --" + opt_name + + " without value"); + } + else + { + throw CLI_Usage_Error("Unknown flag --" + opt_name); + } + } + m_user_flags.insert(opt_name); + } + else + { + const std::string opt_name = param.substr(2, eq - 2); + const std::string opt_val = param.substr(eq + 1, std::string::npos); + + if(m_spec_opts.count(opt_name) == 0) + { + throw CLI_Usage_Error("Unknown option --" + opt_name); + } + + m_user_args.insert(std::make_pair(opt_name, opt_val)); + } + } + else + { + // argument + args.push_back(param); + } + } + + if(flag_set("help")) + return; + + if(args.size() < m_spec_args.size()) + { + // not enough arguments + throw CLI_Usage_Error("Invalid argument count, got " + + std::to_string(args.size()) + + " expected " + + std::to_string(m_spec_args.size())); + } + + bool seen_stdin_flag = false; + size_t arg_i = 0; + for(auto const& arg : m_spec_args) + { + m_user_args.insert(std::make_pair(arg, args[arg_i])); + + if(args[arg_i] == "-") + { + if(seen_stdin_flag) + { + throw CLI_Usage_Error("Cannot specify '-' (stdin) more than once"); + } + seen_stdin_flag = true; + } + + ++arg_i; + } + + if(m_spec_rest.empty()) + { + if(arg_i != args.size()) + { + throw CLI_Usage_Error("Too many arguments"); + } + } + else + { + m_user_rest.assign(args.begin() + arg_i, args.end()); + } + + // Now insert any defaults for options not supplied by the user + for(auto const& opt : m_spec_opts) + { + if(m_user_args.count(opt.first) == 0) + { + m_user_args.insert(opt); + } + } + } + +Argument_Parser::Argument_Parser(const std::string& spec, + const std::vector& extra_flags, + const std::vector& extra_opts) + { + class CLI_Error_Invalid_Spec final : public CLI_Error + { + public: + explicit CLI_Error_Invalid_Spec(const std::string& bad_spec) + : CLI_Error("Invalid command spec '" + bad_spec + "'") {} + }; + + const std::vector parts = Botan::split_on(spec, ' '); + + if(parts.size() == 0) + { + throw CLI_Error_Invalid_Spec(spec); + } + + for(size_t i = 1; i != parts.size(); ++i) + { + const std::string s = parts[i]; + + if(s.empty()) // ?!? (shouldn't happen) + { + throw CLI_Error_Invalid_Spec(spec); + } + + if(s.size() > 2 && s[0] == '-' && s[1] == '-') + { + // option or flag + + auto eq = s.find('='); + + if(eq == std::string::npos) + { + m_spec_flags.insert(s.substr(2, std::string::npos)); + } + else + { + m_spec_opts.insert(std::make_pair(s.substr(2, eq - 2), s.substr(eq + 1, std::string::npos))); + } + } + else if(s[0] == '*') + { + // rest argument + if(m_spec_rest.empty() && s.size() > 2) + { + m_spec_rest = s.substr(1, std::string::npos); + } + else + { + throw CLI_Error_Invalid_Spec(spec); + } + } + else + { + // named argument + if(!m_spec_rest.empty()) // rest arg wasn't last + { + throw CLI_Error_Invalid_Spec(spec); + } + + m_spec_args.push_back(s); + } + } + + for(std::string flag : extra_flags) + m_spec_flags.insert(flag); + for(std::string opt : extra_opts) + m_spec_opts.insert(std::make_pair(opt, "")); + } + + +} + +#endif diff --git a/comm/third_party/botan/src/cli/asn1.cpp b/comm/third_party/botan/src/cli/asn1.cpp new file mode 100644 index 0000000000..32cec2c253 --- /dev/null +++ b/comm/third_party/botan/src/cli/asn1.cpp @@ -0,0 +1,89 @@ +/* +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_ASN1) + +#include +#include + +#if defined(BOTAN_HAS_PEM_CODEC) + #include +#endif + +namespace Botan_CLI { + +class ASN1_Printer final : public Command + { + public: + ASN1_Printer() : Command("asn1print --skip-context-specific --print-limit=4096 --bin-limit=2048 --max-depth=64 --pem file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Decode and print file with ASN.1 Basic Encoding Rules (BER)"; + } + + bool first_n(const std::vector& data, size_t n, uint8_t b) + { + if(data.size() < n) + return false; + + for(size_t i = 0; i != n; ++i) + if(data[i] != b) + return false; + + return true; + } + + void go() override + { + const std::string input = get_arg("file"); + const size_t print_limit = get_arg_sz("print-limit"); + const size_t bin_limit = get_arg_sz("bin-limit"); + const bool print_context_specific = flag_set("skip-context-specific") == false; + const size_t max_depth = get_arg_sz("max-depth"); + + const size_t value_column = 60; + const size_t initial_level = 0; + + std::vector file_contents = slurp_file(input); + std::vector data; + + if(flag_set("pem") || + (input.size() > 4 && input.substr(input.size() - 4) == ".pem") || + (file_contents.size() > 20 && first_n(file_contents, 5, '-'))) + { +#if defined(BOTAN_HAS_PEM_CODEC) + std::string pem_label; + Botan::DataSource_Memory src(file_contents); + data = unlock(Botan::PEM_Code::decode(src, pem_label)); +#else + throw CLI_Error_Unsupported("PEM decoding not available in this build"); +#endif + } + else + { + data.swap(file_contents); + } + + Botan::ASN1_Pretty_Printer printer(print_limit, bin_limit, print_context_specific, + initial_level, value_column, max_depth); + + printer.print_to_stream(output(), data.data(), data.size()); + } + }; + +BOTAN_REGISTER_COMMAND("asn1print", ASN1_Printer); + +} + +#endif // BOTAN_HAS_ASN1 && BOTAN_HAS_PEM_CODEC diff --git a/comm/third_party/botan/src/cli/bcrypt.cpp b/comm/third_party/botan/src/cli/bcrypt.cpp new file mode 100644 index 0000000000..68e77b8e60 --- /dev/null +++ b/comm/third_party/botan/src/cli/bcrypt.cpp @@ -0,0 +1,89 @@ +/* +* (C) 2009,2010,2014,2015,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_BCRYPT) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_BCRYPT) + +class Generate_Bcrypt final : public Command + { + public: + Generate_Bcrypt() : Command("gen_bcrypt --work-factor=12 password") {} + + std::string group() const override + { + return "passhash"; + } + + std::string description() const override + { + return "Calculate bcrypt password hash"; + } + + void go() override + { + const std::string password = get_passphrase_arg("Passphrase to hash", "password"); + const size_t wf = get_arg_sz("work-factor"); + + if(wf < 4 || wf > 18) + { + error_output() << "Invalid bcrypt work factor\n"; + } + else + { + const uint16_t wf16 = static_cast(wf); + output() << Botan::generate_bcrypt(password, rng(), wf16) << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("gen_bcrypt", Generate_Bcrypt); + +class Check_Bcrypt final : public Command + { + public: + Check_Bcrypt() : Command("check_bcrypt password hash") {} + + std::string group() const override + { + return "passhash"; + } + + std::string description() const override + { + return "Verify bcrypt password hash"; + } + + void go() override + { + const std::string password = get_passphrase_arg("Password to check", "password"); + const std::string hash = get_arg("hash"); + + if(hash.length() != 60) + { + error_output() << "Note: bcrypt '" << hash << "' has wrong length and cannot be valid\n"; + } + + const bool ok = Botan::check_bcrypt(password, hash); + + output() << "Password is " << (ok ? "valid" : "NOT valid") << std::endl; + + if(ok == false) + set_return_code(1); + } + }; + +BOTAN_REGISTER_COMMAND("check_bcrypt", Check_Bcrypt); + +#endif // bcrypt + +} diff --git a/comm/third_party/botan/src/cli/cc_enc.cpp b/comm/third_party/botan/src/cli/cc_enc.cpp new file mode 100644 index 0000000000..509b996012 --- /dev/null +++ b/comm/third_party/botan/src/cli/cc_enc.cpp @@ -0,0 +1,189 @@ +/* +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include + +#if defined(BOTAN_HAS_FPE_FE1) && defined(BOTAN_HAS_PBKDF) + +#include +#include + +namespace Botan_CLI { + +namespace { + +uint8_t luhn_checksum(uint64_t cc_number) + { + uint8_t sum = 0; + + bool alt = false; + while(cc_number) + { + uint8_t digit = cc_number % 10; + if(alt) + { + digit *= 2; + if(digit > 9) + { + digit -= 9; + } + } + + sum += digit; + + cc_number /= 10; + alt = !alt; + } + + return (sum % 10); + } + +bool luhn_check(uint64_t cc_number) + { + return (luhn_checksum(cc_number) == 0); + } + +uint64_t cc_rank(uint64_t cc_number) + { + // Remove Luhn checksum + return cc_number / 10; + } + +uint64_t cc_derank(uint64_t cc_number) + { + for(size_t i = 0; i != 10; ++i) + { + if(luhn_check(cc_number * 10 + i)) + { + return (cc_number * 10 + i); + } + } + + return 0; + } + +uint64_t encrypt_cc_number(uint64_t cc_number, + const Botan::secure_vector& key, + const std::vector& tweak) + { + const Botan::BigInt n = 1000000000000000; + + const uint64_t cc_ranked = cc_rank(cc_number); + + const Botan::BigInt c = Botan::FPE::fe1_encrypt(n, cc_ranked, key, tweak); + + if(c.bits() > 50) + { + throw Botan::Internal_Error("FPE produced a number too large"); + } + + uint64_t enc_cc = 0; + for(size_t i = 0; i != 7; ++i) + { + enc_cc = (enc_cc << 8) | c.byte_at(6 - i); + } + return cc_derank(enc_cc); + } + +uint64_t decrypt_cc_number(uint64_t enc_cc, + const Botan::secure_vector& key, + const std::vector& tweak) + { + const Botan::BigInt n = 1000000000000000; + + const uint64_t cc_ranked = cc_rank(enc_cc); + + const Botan::BigInt c = Botan::FPE::fe1_decrypt(n, cc_ranked, key, tweak); + + if(c.bits() > 50) + { + throw CLI_Error("FPE produced a number too large"); + } + + uint64_t dec_cc = 0; + for(size_t i = 0; i != 7; ++i) + { + dec_cc = (dec_cc << 8) | c.byte_at(6 - i); + } + return cc_derank(dec_cc); + } + +} + +class CC_Encrypt final : public Command + { + public: + CC_Encrypt() : Command("cc_encrypt CC passphrase --tweak=") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Encrypt the passed valid credit card number using FPE encryption"; + } + + void go() override + { + const uint64_t cc_number = std::stoull(get_arg("CC")); + const std::vector tweak = Botan::hex_decode(get_arg("tweak")); + const std::string pass = get_arg("passphrase"); + + std::unique_ptr pbkdf(Botan::PBKDF::create("PBKDF2(SHA-256)")); + if(!pbkdf) + { + throw CLI_Error_Unsupported("PBKDF", "PBKDF2(SHA-256)"); + } + + Botan::secure_vector key = pbkdf->pbkdf_iterations(32, pass, tweak.data(), tweak.size(), 100000); + + output() << encrypt_cc_number(cc_number, key, tweak) << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("cc_encrypt", CC_Encrypt); + +class CC_Decrypt final : public Command + { + public: + CC_Decrypt() : Command("cc_decrypt CC passphrase --tweak=") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Decrypt the passed valid ciphertext credit card number using FPE decryption"; + } + + void go() override + { + const uint64_t cc_number = std::stoull(get_arg("CC")); + const std::vector tweak = Botan::hex_decode(get_arg("tweak")); + const std::string pass = get_arg("passphrase"); + + std::unique_ptr pbkdf(Botan::PBKDF::create("PBKDF2(SHA-256)")); + if(!pbkdf) + { + throw CLI_Error_Unsupported("PBKDF", "PBKDF2(SHA-256)"); + } + + Botan::secure_vector key = pbkdf->pbkdf_iterations(32, pass, tweak.data(), tweak.size(), 100000); + + output() << decrypt_cc_number(cc_number, key, tweak) << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("cc_decrypt", CC_Decrypt); + +} + +#endif // FPE && PBKDF diff --git a/comm/third_party/botan/src/cli/cli.cpp b/comm/third_party/botan/src/cli/cli.cpp new file mode 100644 index 0000000000..1fc5ed116e --- /dev/null +++ b/comm/third_party/botan/src/cli/cli.cpp @@ -0,0 +1,349 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include "argparse.h" +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_HEX_CODEC) + #include +#endif + +#if defined(BOTAN_HAS_BASE64_CODEC) + #include +#endif + +#if defined(BOTAN_HAS_BASE58_CODEC) + #include +#endif + +namespace Botan_CLI { + +Command::Command(const std::string& cmd_spec) : m_spec(cmd_spec) + { + // for checking all spec strings at load time + //m_args.reset(new Argument_Parser(m_spec)); + } + +Command::~Command() { /* for unique_ptr */ } + +std::string Command::cmd_name() const + { + return m_spec.substr(0, m_spec.find(' ')); + } + +std::string Command::help_text() const + { + return "Usage: " + m_spec; + } + +int Command::run(const std::vector& params) + { + try + { + m_args.reset(new Argument_Parser(m_spec, + {"verbose", "help"}, + {"output", "error-output", "rng-type", "drbg-seed"})); + + m_args->parse_args(params); + + if(m_args->has_arg("output")) + { + const std::string output_file = get_arg("output"); + + if(output_file != "") + { + m_output_stream.reset(new std::ofstream(output_file, std::ios::binary)); + if(!m_output_stream->good()) + throw CLI_IO_Error("opening", output_file); + } + } + + if(m_args->has_arg("error-output")) + { + const std::string output_file = get_arg("error-output"); + + if(output_file != "") + { + m_error_output_stream.reset(new std::ofstream(output_file, std::ios::binary)); + if(!m_error_output_stream->good()) + throw CLI_IO_Error("opening", output_file); + } + } + + if(flag_set("help")) + { + output() << help_text() << "\n"; + return 2; + } + + this->go(); + return m_return_code; + } + catch(CLI_Usage_Error& e) + { + error_output() << "Usage error: " << e.what() << "\n"; + error_output() << help_text() << "\n"; + return 1; + } + catch(std::exception& e) + { + error_output() << "Error: " << e.what() << "\n"; + return 2; + } + catch(...) + { + error_output() << "Error: unknown exception\n"; + return 2; + } + } + +bool Command::flag_set(const std::string& flag_name) const + { + return m_args->flag_set(flag_name); + } + +std::string Command::get_arg(const std::string& opt_name) const + { + return m_args->get_arg(opt_name); + } + +/* +* Like get_arg() but if the argument was not specified or is empty, returns otherwise +*/ +std::string Command::get_arg_or(const std::string& opt_name, const std::string& otherwise) const + { + return m_args->get_arg_or(opt_name, otherwise); + } + +size_t Command::get_arg_sz(const std::string& opt_name) const + { + return m_args->get_arg_sz(opt_name); + } + +uint16_t Command::get_arg_u16(const std::string& opt_name) const + { + const size_t val = get_arg_sz(opt_name); + if(static_cast(val) != val) + throw CLI_Usage_Error("Argument " + opt_name + " has value out of allowed range"); + return static_cast(val); + } + +uint32_t Command::get_arg_u32(const std::string& opt_name) const + { + const size_t val = get_arg_sz(opt_name); + if(static_cast(val) != val) + throw CLI_Usage_Error("Argument " + opt_name + " has value out of allowed range"); + return static_cast(val); + } + +std::vector Command::get_arg_list(const std::string& what) const + { + return m_args->get_arg_list(what); + } + +std::ostream& Command::output() + { + if(m_output_stream.get()) + { + return *m_output_stream; + } + return std::cout; + } + +std::ostream& Command::error_output() + { + if(m_error_output_stream.get()) + { + return *m_error_output_stream; + } + return std::cerr; + } + +std::vector Command::slurp_file(const std::string& input_file, + size_t buf_size) const + { + std::vector buf; + auto insert_fn = [&](const uint8_t b[], size_t l) + { + buf.insert(buf.end(), b, b + l); + }; + this->read_file(input_file, insert_fn, buf_size); + return buf; + } + +std::string Command::slurp_file_as_str(const std::string& input_file, + size_t buf_size) const + { + std::string str; + auto insert_fn = [&](const uint8_t b[], size_t l) + { + str.append(reinterpret_cast(b), l); + }; + this->read_file(input_file, insert_fn, buf_size); + return str; + } + +void Command::read_file(const std::string& input_file, + std::function consumer_fn, + size_t buf_size) const + { + if(input_file == "-") + { + do_read_file(std::cin, consumer_fn, buf_size); + } + else + { + std::ifstream in(input_file, std::ios::binary); + if(!in) + { + throw CLI_IO_Error("reading file", input_file); + } + do_read_file(in, consumer_fn, buf_size); + } + } + +void Command::do_read_file(std::istream& in, + std::function consumer_fn, + size_t buf_size) const + { + // Avoid an infinite loop on --buf-size=0 + std::vector buf(buf_size == 0 ? 4096 : buf_size); + + while(in.good()) + { + in.read(reinterpret_cast(buf.data()), buf.size()); + const size_t got = static_cast(in.gcount()); + consumer_fn(buf.data(), got); + } + } + +Botan::RandomNumberGenerator& Command::rng() + { + if(m_rng == nullptr) + { + m_rng = cli_make_rng(get_arg("rng-type"), get_arg("drbg-seed")); + } + + return *m_rng.get(); + } + +std::string Command::get_passphrase_arg(const std::string& prompt, const std::string& opt_name) + { + const std::string s = get_arg(opt_name); + if(s != "-") + return s; + return get_passphrase(prompt); + } + +namespace { + +bool echo_suppression_supported() + { + auto echo = Botan::OS::suppress_echo_on_terminal(); + return (echo != nullptr); + } + +} + +std::string Command::get_passphrase(const std::string& prompt) + { + if(echo_suppression_supported() == false) + error_output() << "Warning: terminal echo suppression not enabled for this platform\n"; + + error_output() << prompt << ": " << std::flush; + std::string pass; + + auto echo_suppress = Botan::OS::suppress_echo_on_terminal(); + + std::getline(std::cin, pass); + + return pass; + } + +//static +std::string Command::format_blob(const std::string& format, + const uint8_t bits[], size_t len) + { +#if defined(BOTAN_HAS_HEX_CODEC) + if(format == "hex") + { + return Botan::hex_encode(bits, len); + } +#endif + +#if defined(BOTAN_HAS_BASE64_CODEC) + if(format == "base64") + { + return Botan::base64_encode(bits, len); + } +#endif + +#if defined(BOTAN_HAS_BASE58_CODEC) + if(format == "base58") + { + return Botan::base58_encode(bits, len); + } + if(format == "base58check") + { + return Botan::base58_check_encode(bits, len); + } +#endif + + // If we supported format, we would have already returned + throw CLI_Usage_Error("Unknown or unsupported format type"); + } + +// Registration code + +Command::Registration::Registration(const std::string& name, Command::cmd_maker_fn maker_fn) + { + std::map& reg = Command::global_registry(); + + if(reg.count(name) > 0) + { + throw CLI_Error("Duplicated registration of command " + name); + } + + reg.insert(std::make_pair(name, maker_fn)); + } + +//static +std::map& Command::global_registry() + { + static std::map g_cmds; + return g_cmds; + } + +//static +std::vector Command::registered_cmds() + { + std::vector cmds; + for(auto& cmd : Command::global_registry()) + cmds.push_back(cmd.first); + return cmds; + } + +//static +std::unique_ptr Command::get_cmd(const std::string& name) + { + const std::map& reg = Command::global_registry(); + + std::unique_ptr r; + auto i = reg.find(name); + if(i != reg.end()) + { + r.reset(i->second()); + } + + return r; + } + +} diff --git a/comm/third_party/botan/src/cli/cli.h b/comm/third_party/botan/src/cli/cli.h new file mode 100644 index 0000000000..6ddf34d025 --- /dev/null +++ b/comm/third_party/botan/src/cli/cli.h @@ -0,0 +1,219 @@ +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CLI_H_ +#define BOTAN_CLI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "cli_exceptions.h" + +namespace Botan { + +class RandomNumberGenerator; + +} + +namespace Botan_CLI { + +class Argument_Parser; + +/* Declared in cli_rng.cpp */ +std::unique_ptr +cli_make_rng(const std::string& type = "", const std::string& hex_drbg_seed = ""); + +class Command + { + public: + + /** + * Get a registered command + */ + static std::unique_ptr get_cmd(const std::string& name); + + static std::vector registered_cmds(); + + /** + * The spec string specifies the format of the command line, eg for + * a somewhat complicated command: + * cmd_name --flag --option1= --option2=opt2val input1 input2 *rest + * + * By default this is the value returned by help_text() + * + * The first value is always the command name. Options may appear + * in any order. Named arguments are taken from the command line + * in the order they appear in the spec. + * + * --flag can optionally be specified, and takes no value. + * Check for it in go() with flag_set() + * + * --option1 is an option whose default value (if the option + * does not appear on the command line) is the empty string. + * + * --option2 is an option whose default value is opt2val + * Read the values in go() using get_arg or get_arg_sz. + * + * The values input1 and input2 specify named arguments which must + * be provided. They are also access via get_arg/get_arg_sz + * Because options and arguments for a single command share the same + * namespace you can't have a spec like: + * cmd --input input + * but you hopefully didn't want to do that anyway. + * + * The leading '*' on '*rest' specifies that all remaining arguments + * should be packaged in a list which is available as get_arg_list("rest"). + * This can only appear on a single value and should be the final + * named argument. + * + * Every command has implicit flags --help, --verbose and implicit + * options --output= and --error-output= which override the default + * use of std::cout and std::cerr. + * + * Use of --help is captured in run() and returns help_text(). + * Use of --verbose can be checked with verbose() or flag_set("verbose") + */ + explicit Command(const std::string& cmd_spec); + + virtual ~Command(); + + int run(const std::vector& params); + + virtual std::string group() const = 0; + + virtual std::string description() const = 0; + + virtual std::string help_text() const; + + const std::string& cmd_spec() const + { + return m_spec; + } + + std::string cmd_name() const; + + protected: + + /* + * The actual functionality of the cli command implemented in subclass. + * The return value from main will be zero. + */ + virtual void go() = 0; + + void set_return_code(int rc) { m_return_code = rc; } + + std::ostream& output(); + + std::ostream& error_output(); + + bool verbose() const + { + return flag_set("verbose"); + } + + std::string get_passphrase(const std::string& prompt); + + bool flag_set(const std::string& flag_name) const; + + static std::string format_blob(const std::string& format, const uint8_t bits[], size_t len); + + template + static std::string format_blob(const std::string& format, + const std::vector& vec) + { + return format_blob(format, vec.data(), vec.size()); + } + + std::string get_arg(const std::string& opt_name) const; + + /** + * Like get_arg but if the value is '-' then reads a passphrase from + * the terminal with echo suppressed. + */ + std::string get_passphrase_arg(const std::string& prompt, + const std::string& opt_name); + + /* + * Like get_arg() but if the argument was not specified or is empty, returns otherwise + */ + std::string get_arg_or(const std::string& opt_name, const std::string& otherwise) const; + + size_t get_arg_sz(const std::string& opt_name) const; + + uint16_t get_arg_u16(const std::string& opt_name) const; + + uint32_t get_arg_u32(const std::string& opt_name) const; + + std::vector get_arg_list(const std::string& what) const; + + /* + * Read an entire file into memory and return the contents + */ + std::vector slurp_file(const std::string& input_file, + size_t buf_size = 0) const; + + std::string slurp_file_as_str(const std::string& input_file, + size_t buf_size = 0) const; + + /* + * Read a file calling consumer_fn() with the inputs + */ + void read_file(const std::string& input_file, + std::function consumer_fn, + size_t buf_size = 0) const; + + + void do_read_file(std::istream& in, + std::function consumer_fn, + size_t buf_size = 0) const; + + template + void write_output(const std::vector& vec) + { + output().write(reinterpret_cast(vec.data()), vec.size()); + } + + Botan::RandomNumberGenerator& rng(); + + private: + typedef std::function cmd_maker_fn; + static std::map& global_registry(); + + void parse_spec(); + + // set in constructor + std::string m_spec; + + std::unique_ptr m_args; + std::unique_ptr m_output_stream; + std::unique_ptr m_error_output_stream; + + std::unique_ptr m_rng; + + // possibly set by calling set_return_code() + int m_return_code = 0; + + public: + // the registry interface: + + class Registration final + { + public: + Registration(const std::string& name, cmd_maker_fn maker_fn); + }; + }; + +#define BOTAN_REGISTER_COMMAND(name, CLI_Class) \ + Botan_CLI::Command::Registration reg_cmd_ ## CLI_Class(name, \ + []() -> Botan_CLI::Command* { return new CLI_Class; }) + +} + +#endif diff --git a/comm/third_party/botan/src/cli/cli_exceptions.h b/comm/third_party/botan/src/cli/cli_exceptions.h new file mode 100644 index 0000000000..c88d170271 --- /dev/null +++ b/comm/third_party/botan/src/cli/cli_exceptions.h @@ -0,0 +1,47 @@ +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CLI_EXCEPTIONS_H_ +#define BOTAN_CLI_EXCEPTIONS_H_ + +namespace Botan_CLI { + +class CLI_Error : public std::runtime_error + { + public: + explicit CLI_Error(const std::string& s) : std::runtime_error(s) {} + }; + +class CLI_IO_Error final : public CLI_Error + { + public: + CLI_IO_Error(const std::string& op, const std::string& who) : + CLI_Error("Error " + op + " " + who) {} + }; + +class CLI_Usage_Error final : public CLI_Error + { + public: + explicit CLI_Usage_Error(const std::string& what) : CLI_Error(what) {} + }; + +/* Thrown eg when a requested feature was compiled out of the library + or is not available, eg hashing with MD2 +*/ +class CLI_Error_Unsupported final : public CLI_Error + { + public: + + CLI_Error_Unsupported(const std::string& msg) : CLI_Error(msg) {} + + CLI_Error_Unsupported(const std::string& what, + const std::string& who) + : CLI_Error(what + " with '" + who + "' unsupported or not available") {} + }; + +} + +#endif diff --git a/comm/third_party/botan/src/cli/cli_rng.cpp b/comm/third_party/botan/src/cli/cli_rng.cpp new file mode 100644 index 0000000000..e3eee0c035 --- /dev/null +++ b/comm/third_party/botan/src/cli/cli_rng.cpp @@ -0,0 +1,146 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include +#include +#include +#include + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include +#endif + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + #include +#endif + +#if defined(BOTAN_HAS_HMAC_DRBG) + #include +#endif + +namespace Botan_CLI { + +std::unique_ptr +cli_make_rng(const std::string& rng_type, const std::string& hex_drbg_seed) + { +#if defined(BOTAN_HAS_SYSTEM_RNG) + if(rng_type == "system" || rng_type.empty()) + { + return std::unique_ptr(new Botan::System_RNG); + } +#endif + + const std::vector drbg_seed = Botan::hex_decode(hex_drbg_seed); + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + if(rng_type == "auto" || rng_type == "entropy" || rng_type.empty()) + { + std::unique_ptr rng; + + if(rng_type == "entropy") + rng.reset(new Botan::AutoSeeded_RNG(Botan::Entropy_Sources::global_sources())); + else + rng.reset(new Botan::AutoSeeded_RNG); + + if(drbg_seed.size() > 0) + rng->add_entropy(drbg_seed.data(), drbg_seed.size()); + return rng; + } +#endif + +#if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32) + if(rng_type == "drbg" || (rng_type.empty() && drbg_seed.empty() == false)) + { + std::unique_ptr mac = + Botan::MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + std::unique_ptr rng(new Botan::HMAC_DRBG(std::move(mac))); + rng->add_entropy(drbg_seed.data(), drbg_seed.size()); + + if(rng->is_seeded() == false) + throw CLI_Error("For " + rng->name() + " a seed of at least " + + std::to_string(rng->security_level()/8) + + " bytes must be provided"); + + return std::unique_ptr(rng.release()); + } +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + if(rng_type == "rdrand" || rng_type == "cpu" || rng_type.empty()) + { + if(Botan::Processor_RNG::available()) + return std::unique_ptr(new Botan::Processor_RNG); + else if(rng_type.empty() == false) + throw CLI_Error("RNG instruction not supported on this processor"); + } +#endif + + if(rng_type.empty()) + throw CLI_Error_Unsupported("No random number generator seems to be available in the current build"); + else + throw CLI_Error_Unsupported("RNG", rng_type); + } + +class RNG final : public Command + { + public: + RNG() : Command("rng --format=hex --system --rdrand --auto --entropy --drbg --drbg-seed= *bytes") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Sample random bytes from the specified rng"; + } + + void go() override + { + const std::string format = get_arg("format"); + std::string type = get_arg("rng-type"); + + if(type.empty()) + { + for(std::string flag : { "system", "rdrand", "auto", "entropy", "drbg" }) + { + if(flag_set(flag)) + { + type = flag; + break; + } + } + } + + const std::string drbg_seed = get_arg("drbg-seed"); + std::unique_ptr rng = cli_make_rng(type, drbg_seed); + + for(const std::string& req : get_arg_list("bytes")) + { + const size_t req_len = Botan::to_u32bit(req); + const auto blob = rng->random_vec(req_len); + + if(format == "binary" || format == "raw") + { + output().write(reinterpret_cast(blob.data()), blob.size()); + } + else + { + output() << format_blob(format, blob) << "\n"; + } + } + } + }; + +BOTAN_REGISTER_COMMAND("rng", RNG); + +} diff --git a/comm/third_party/botan/src/cli/codec.cpp b/comm/third_party/botan/src/cli/codec.cpp new file mode 100644 index 0000000000..48388d1a7a --- /dev/null +++ b/comm/third_party/botan/src/cli/codec.cpp @@ -0,0 +1,268 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_HEX_CODEC) + #include +#endif + +#if defined(BOTAN_HAS_BASE32_CODEC) + #include +#endif + +#if defined(BOTAN_HAS_BASE58_CODEC) + #include +#endif + +#if defined(BOTAN_HAS_BASE64_CODEC) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_HEX_CODEC) + +class Hex_Encode final : public Command + { + public: + Hex_Encode() : Command("hex_enc file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Hex encode a given file"; + } + + void go() override + { + auto hex_enc_f = [&](const uint8_t b[], size_t l) { output() << Botan::hex_encode(b, l); }; + this->read_file(get_arg("file"), hex_enc_f, 2); + } + }; + +BOTAN_REGISTER_COMMAND("hex_enc", Hex_Encode); + +class Hex_Decode final : public Command + { + public: + Hex_Decode() : Command("hex_dec file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Hex decode a given file"; + } + + void go() override + { + auto hex_dec_f = [&](const uint8_t b[], size_t l) + { + std::vector bin = Botan::hex_decode(reinterpret_cast(b), l); + output().write(reinterpret_cast(bin.data()), bin.size()); + }; + + this->read_file(get_arg("file"), hex_dec_f, 2); + } + }; + +BOTAN_REGISTER_COMMAND("hex_dec", Hex_Decode); + +#endif + +#if defined(BOTAN_HAS_BASE58_CODEC) + +class Base58_Encode final : public Command + { + public: + Base58_Encode() : Command("base58_enc --check file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Encode given file to Base58"; + } + + void go() override + { + auto data = slurp_file(get_arg("file")); + + if(flag_set("check")) + output() << Botan::base58_check_encode(data); + else + output() << Botan::base58_encode(data); + } + }; + +BOTAN_REGISTER_COMMAND("base58_enc", Base58_Encode); + +class Base58_Decode final : public Command + { + public: + Base58_Decode() : Command("base58_dec --check file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Decode Base58 encoded file"; + } + + void go() override + { + auto data = slurp_file_as_str(get_arg("file")); + + std::vector bin; + + if(flag_set("check")) + bin = Botan::base58_check_decode(data); + else + bin = Botan::base58_decode(data); + + output().write(reinterpret_cast(bin.data()), bin.size()); + } + }; + +BOTAN_REGISTER_COMMAND("base58_dec", Base58_Decode); + +#endif // base58 + +#if defined(BOTAN_HAS_BASE32_CODEC) + +class Base32_Encode final : public Command + { + public: + Base32_Encode() : Command("base32_enc file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Encode given file to Base32"; + } + + void go() override + { + auto onData = [&](const uint8_t b[], size_t l) + { + output() << Botan::base32_encode(b, l); + }; + this->read_file(get_arg("file"), onData, 768); + } + }; + +BOTAN_REGISTER_COMMAND("base32_enc", Base32_Encode); + +class Base32_Decode final : public Command + { + public: + Base32_Decode() : Command("base32_dec file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Decode Base32 encoded file"; + } + + void go() override + { + auto write_bin = [&](const uint8_t b[], size_t l) + { + Botan::secure_vector bin = Botan::base32_decode(reinterpret_cast(b), l); + output().write(reinterpret_cast(bin.data()), bin.size()); + }; + + this->read_file(get_arg("file"), write_bin, 1024); + } + }; + +BOTAN_REGISTER_COMMAND("base32_dec", Base32_Decode); + +#endif // base32 + +#if defined(BOTAN_HAS_BASE64_CODEC) + +class Base64_Encode final : public Command + { + public: + Base64_Encode() : Command("base64_enc file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Encode given file to Base64"; + } + + void go() override + { + auto onData = [&](const uint8_t b[], size_t l) + { + output() << Botan::base64_encode(b, l); + }; + this->read_file(get_arg("file"), onData, 768); + } + }; + +BOTAN_REGISTER_COMMAND("base64_enc", Base64_Encode); + +class Base64_Decode final : public Command + { + public: + Base64_Decode() : Command("base64_dec file") {} + + std::string group() const override + { + return "codec"; + } + + std::string description() const override + { + return "Decode Base64 encoded file"; + } + + void go() override + { + auto write_bin = [&](const uint8_t b[], size_t l) + { + Botan::secure_vector bin = Botan::base64_decode(reinterpret_cast(b), l); + output().write(reinterpret_cast(bin.data()), bin.size()); + }; + + this->read_file(get_arg("file"), write_bin, 1024); + } + }; + +BOTAN_REGISTER_COMMAND("base64_dec", Base64_Decode); + +#endif // base64 + +} diff --git a/comm/third_party/botan/src/cli/compress.cpp b/comm/third_party/botan/src/cli/compress.cpp new file mode 100644 index 0000000000..e62acd7636 --- /dev/null +++ b/comm/third_party/botan/src/cli/compress.cpp @@ -0,0 +1,190 @@ +/* +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_COMPRESSION) + #include + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_COMPRESSION) + +class Compress final : public Command + { + public: + Compress() : Command("compress --type=gzip --level=6 --buf-size=8192 file") {} + + std::string output_filename(const std::string& input_fsname, const std::string& comp_type) + { + const std::map suffixes = + { + { "zlib", "zlib" }, + { "gzip", "gz" }, + { "bzip2", "bz2" }, + { "lzma", "xz" }, + }; + + auto suffix_info = suffixes.find(comp_type); + if(suffixes.count(comp_type) == 0) + { + throw CLI_Error_Unsupported("Compressing", comp_type); + } + + return input_fsname + "." + suffix_info->second; + } + + std::string group() const override + { + return "compression"; + } + + std::string description() const override + { + return "Compress a given file"; + } + + void go() override + { + const std::string comp_type = get_arg("type"); + const size_t buf_size = get_arg_sz("buf-size"); + const size_t comp_level = get_arg_sz("level"); + + std::unique_ptr compress; + + compress.reset(Botan::make_compressor(comp_type)); + + if(!compress) + { + throw CLI_Error_Unsupported("Compression", comp_type); + } + + const std::string in_file = get_arg("file"); + std::ifstream in(in_file, std::ios::binary); + + if(!in.good()) + { + throw CLI_IO_Error("reading", in_file); + } + + const std::string out_file = output_filename(in_file, comp_type); + std::ofstream out(out_file, std::ios::binary); + if(!out.good()) + { + throw CLI_IO_Error("writing", out_file); + } + + Botan::secure_vector buf; + + compress->start(comp_level); + + while(in.good()) + { + buf.resize(buf_size); + in.read(reinterpret_cast(buf.data()), buf.size()); + buf.resize(in.gcount()); + + compress->update(buf); + + out.write(reinterpret_cast(buf.data()), buf.size()); + } + + buf.clear(); + compress->finish(buf); + out.write(reinterpret_cast(buf.data()), buf.size()); + out.close(); + } + }; + +BOTAN_REGISTER_COMMAND("compress", Compress); + +class Decompress final : public Command + { + public: + Decompress() : Command("decompress --buf-size=8192 file") {} + + void parse_extension(const std::string& in_file, + std::string& out_file, + std::string& suffix) + { + auto last_dot = in_file.find_last_of('.'); + if(last_dot == std::string::npos || last_dot == 0) + { + throw CLI_Error("No extension detected in filename '" + in_file + "'"); + } + + out_file = in_file.substr(0, last_dot); + suffix = in_file.substr(last_dot + 1, std::string::npos); + } + + std::string group() const override + { + return "compression"; + } + + std::string description() const override + { + return "Decompress a given compressed archive"; + } + + void go() override + { + const size_t buf_size = get_arg_sz("buf-size"); + const std::string in_file = get_arg("file"); + std::string out_file, suffix; + parse_extension(in_file, out_file, suffix); + + std::ifstream in(in_file, std::ios::binary); + + if(!in.good()) + { + throw CLI_IO_Error("reading", in_file); + } + + std::unique_ptr decompress; + + decompress.reset(Botan::make_decompressor(suffix)); + + if(!decompress) + { + throw CLI_Error_Unsupported("Decompression", suffix); + } + + std::ofstream out(out_file, std::ios::binary); + if(!out.good()) + { + throw CLI_IO_Error("writing", out_file); + } + + Botan::secure_vector buf; + + decompress->start(); + + while(in.good()) + { + buf.resize(buf_size); + in.read(reinterpret_cast(buf.data()), buf.size()); + buf.resize(in.gcount()); + + decompress->update(buf); + + out.write(reinterpret_cast(buf.data()), buf.size()); + } + + buf.clear(); + decompress->finish(buf); + out.write(reinterpret_cast(buf.data()), buf.size()); + out.close(); + } + }; + +BOTAN_REGISTER_COMMAND("decompress", Decompress); + +#endif + +} diff --git a/comm/third_party/botan/src/cli/encryption.cpp b/comm/third_party/botan/src/cli/encryption.cpp new file mode 100644 index 0000000000..fa8de7cfdb --- /dev/null +++ b/comm/third_party/botan/src/cli/encryption.cpp @@ -0,0 +1,127 @@ +/* +* (C) 2015,2017 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if (defined(BOTAN_HAS_AES) || defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)) && defined(BOTAN_HAS_AEAD_MODES) + +#include +#include +#include + +namespace Botan_CLI { + +namespace { + +auto VALID_MODES = std::map{ + // Don't add algorithms here without extending tests + // in `src/scripts/test_cli_crypt.py` + { "aes-128-cfb", "AES-128/CFB" }, + { "aes-192-cfb", "AES-192/CFB" }, + { "aes-256-cfb", "AES-256/CFB" }, + { "aes-128-gcm", "AES-128/GCM" }, + { "aes-192-gcm", "AES-192/GCM" }, + { "aes-256-gcm", "AES-256/GCM" }, + { "aes-128-ocb", "AES-128/OCB" }, + { "aes-128-xts", "AES-128/XTS" }, + { "aes-256-xts", "AES-256/XTS" }, + { "chacha20poly1305", "ChaCha20Poly1305" }, +}; + +Botan::secure_vector +do_crypt(const std::string &cipher, + const std::vector &input, + const Botan::SymmetricKey &key, + const Botan::InitializationVector &iv, + const std::vector& ad, + Botan::Cipher_Dir direction) + { + if(iv.size() == 0) + throw CLI_Usage_Error("IV must not be empty"); + + // TODO: implement streaming + + std::unique_ptr processor(Botan::Cipher_Mode::create(cipher, direction)); + if(!processor) + throw CLI_Error("Cipher algorithm not found"); + + // Set key + processor->set_key(key); + + if(Botan::AEAD_Mode* aead = dynamic_cast(processor.get())) + { + aead->set_ad(ad); + } + else if(ad.size() != 0) + { + throw CLI_Usage_Error("Cannot specify associated data with non-AEAD mode"); + } + + // Set IV + processor->start(iv.bits_of()); + + Botan::secure_vector buf(input.begin(), input.end()); + processor->finish(buf); + + return buf; + } + +} + +class Encryption final : public Command + { + public: + Encryption() : Command("encryption --buf-size=4096 --decrypt --mode= --key= --iv= --ad=") {} + + std::string group() const override + { + return "encryption"; + } + + std::string description() const override + { + return "Encrypt or decrypt a given file"; + } + + void go() override + { + std::string mode = get_arg_or("mode", ""); + if (!VALID_MODES.count(mode)) + { + std::ostringstream error; + error << "Invalid mode: '" << mode << "'\n" + << "valid modes are:"; + for (auto valid_mode : VALID_MODES) error << " " << valid_mode.first; + + throw CLI_Usage_Error(error.str()); + } + + const std::string key_hex = get_arg("key"); + const std::string iv_hex = get_arg("iv"); + const std::string ad_hex = get_arg_or("ad", ""); + const size_t buf_size = get_arg_sz("buf-size"); + + const std::vector input = this->slurp_file("-", buf_size); + + if (verbose()) + { + error_output() << "Got " << input.size() << " bytes of input data.\n"; + } + + const Botan::SymmetricKey key(key_hex); + const Botan::InitializationVector iv(iv_hex); + const std::vector ad = Botan::hex_decode(ad_hex); + + auto direction = flag_set("decrypt") ? Botan::Cipher_Dir::DECRYPTION : Botan::Cipher_Dir::ENCRYPTION; + write_output(do_crypt(VALID_MODES[mode], input, key, iv, ad, direction)); + } + }; + +BOTAN_REGISTER_COMMAND("encryption", Encryption); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/entropy.cpp b/comm/third_party/botan/src/cli/entropy.cpp new file mode 100644 index 0000000000..0404afb995 --- /dev/null +++ b/comm/third_party/botan/src/cli/entropy.cpp @@ -0,0 +1,104 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include "../tests/test_rng.h" // FIXME + +#include + +#if defined(BOTAN_HAS_COMPRESSION) +#include +#endif + +namespace Botan_CLI { + +class Entropy final : public Command + { + public: + Entropy() : Command("entropy --truncate-at=128 source") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Sample a raw entropy source"; + } + + void go() override + { + const std::string req_source = get_arg("source"); + const size_t truncate_sample = get_arg_sz("truncate-at"); + + auto& entropy_sources = Botan::Entropy_Sources::global_sources(); + + std::vector sources; + if(req_source == "all") + sources = entropy_sources.enabled_sources(); + else + sources.push_back(req_source); + + for(std::string source : sources) + { + Botan_Tests::SeedCapturing_RNG rng; + const size_t entropy_estimate = entropy_sources.poll_just(rng, source); + + if(rng.samples() == 0) + { + output() << "Source " << source << " is unavailable\n"; + continue; + } + + const auto& sample = rng.seed_material(); + + output() << "Polling " << source << " gathered " << sample.size() + << " bytes in " << rng.samples() << " outputs with estimated entropy " + << entropy_estimate << "\n"; + +#if defined(BOTAN_HAS_COMPRESSION) + if(!sample.empty()) + { + std::unique_ptr comp(Botan::make_compressor("zlib")); + if(comp) + { + try + { + Botan::secure_vector compressed; + compressed.assign(sample.begin(), sample.end()); + comp->start(9); + comp->finish(compressed); + + if(compressed.size() < sample.size()) + { + output() << "Sample from " << source << " was zlib compressed from " << sample.size() + << " bytes to " << compressed.size() << " bytes\n"; + } + } + catch(std::exception& e) + { + error_output() << "Error while attempting to compress: " << e.what() << "\n"; + } + } + } +#endif + + if(sample.size() <= truncate_sample) + { + output() << Botan::hex_encode(sample) << "\n"; + } + else if(truncate_sample > 0) + { + output() << Botan::hex_encode(&sample[0], truncate_sample) << "...\n"; + } + } + } + }; + +BOTAN_REGISTER_COMMAND("entropy", Entropy); + +} diff --git a/comm/third_party/botan/src/cli/hash.cpp b/comm/third_party/botan/src/cli/hash.cpp new file mode 100644 index 0000000000..8e59b2ab56 --- /dev/null +++ b/comm/third_party/botan/src/cli/hash.cpp @@ -0,0 +1,78 @@ +/* +* (C) 2009,2010,2014,2015,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_HASH) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_HASH) + +class Hash final : public Command + { + public: + Hash() : Command("hash --algo=SHA-256 --buf-size=4096 --no-fsname --format=hex *files") {} + + std::string group() const override + { + return "hash"; + } + + std::string description() const override + { + return "Compute the message digest of given file(s)"; + } + + void go() override + { + const std::string hash_algo = get_arg("algo"); + const std::string format = get_arg("format"); + const size_t buf_size = get_arg_sz("buf-size"); + const bool no_fsname = flag_set("no-fsname"); + + std::unique_ptr hash_fn(Botan::HashFunction::create(hash_algo)); + + if(!hash_fn) + { + throw CLI_Error_Unsupported("hashing", hash_algo); + } + + std::vector files = get_arg_list("files"); + if(files.empty()) + { + files.push_back("-"); + } // read stdin if no arguments on command line + + for(const std::string& fsname : files) + { + try + { + auto update_hash = [&](const uint8_t b[], size_t l) { hash_fn->update(b, l); }; + read_file(fsname, update_hash, buf_size); + + const std::string digest = format_blob(format, hash_fn->final()); + + if(no_fsname) + output() << digest << "\n"; + else + output() << digest << " " << fsname << "\n"; + } + catch(CLI_IO_Error& e) + { + error_output() << e.what() << "\n"; + } + } + } + }; + +BOTAN_REGISTER_COMMAND("hash", Hash); + +#endif + +} diff --git a/comm/third_party/botan/src/cli/hmac.cpp b/comm/third_party/botan/src/cli/hmac.cpp new file mode 100644 index 0000000000..5b7345c50e --- /dev/null +++ b/comm/third_party/botan/src/cli/hmac.cpp @@ -0,0 +1,78 @@ +/* +* (C) 2009,2010,2014,2015 Jack Lloyd +* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#include + +#if defined(BOTAN_HAS_MAC) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_HMAC) + +class HMAC final : public Command + { + public: + HMAC() : Command("hmac --hash=SHA-256 --buf-size=4096 --no-fsname key *files") {} + + std::string group() const override + { + return "hmac"; + } + + std::string description() const override + { + return "Compute the HMAC tag of given file(s)"; + } + + void go() override + { + const bool no_fsname = flag_set("no-fsname"); + const std::string hash_algo = get_arg("hash"); + std::unique_ptr hmac = + Botan::MessageAuthenticationCode::create("HMAC(" + hash_algo + ")"); + + if(!hmac) + { throw CLI_Error_Unsupported("HMAC", hash_algo); } + + hmac->set_key(slurp_file(get_arg("key"))); + + const size_t buf_size = get_arg_sz("buf-size"); + + std::vector files = get_arg_list("files"); + if(files.empty()) + { files.push_back("-"); } // read stdin if no arguments on command line + + for(const std::string& fsname : files) + { + try + { + auto update_hmac = [&](const uint8_t b[], size_t l) { hmac->update(b, l); }; + read_file(fsname, update_hmac, buf_size); + output() << Botan::hex_encode(hmac->final()); + + if(no_fsname == false) + output() << " " << fsname; + + output() << "\n"; + } + catch(CLI_IO_Error& e) + { + error_output() << e.what() << "\n"; + } + } + } + }; + +BOTAN_REGISTER_COMMAND("hmac", HMAC); + +#endif // hmac + +} diff --git a/comm/third_party/botan/src/cli/main.cpp b/comm/third_party/botan/src/cli/main.cpp new file mode 100644 index 0000000000..1f806a9066 --- /dev/null +++ b/comm/third_party/botan/src/cli/main.cpp @@ -0,0 +1,37 @@ +/* +* (C) 2009,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include +#include +#include + +int main(int argc, char* argv[]) + { + std::cerr << Botan::runtime_version_check(BOTAN_VERSION_MAJOR, BOTAN_VERSION_MINOR, BOTAN_VERSION_PATCH); + + std::string cmd_name = "help"; + + if(argc >= 2) + { + cmd_name = argv[1]; + if(cmd_name == "--help" || cmd_name == "-h") + cmd_name = "help"; + if(cmd_name == "--version" || cmd_name == "-V") + cmd_name = "version"; + } + + std::unique_ptr cmd(Botan_CLI::Command::get_cmd(cmd_name)); + + if(!cmd) + { + std::cout << "Unknown command " << cmd_name << " (try --help)\n"; + return 1; + } + + std::vector args(argv + std::min(argc, 2), argv + argc); + return cmd->run(args); + } diff --git a/comm/third_party/botan/src/cli/math.cpp b/comm/third_party/botan/src/cli/math.cpp new file mode 100644 index 0000000000..1268cd3e53 --- /dev/null +++ b/comm/third_party/botan/src/cli/math.cpp @@ -0,0 +1,269 @@ +/* +* (C) 2009,2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_NUMBERTHEORY) + +#include +#include +#include + +namespace Botan_CLI { + +class Modular_Inverse final : public Command + { + public: + Modular_Inverse() : Command("mod_inverse n mod") {} + + std::string group() const override + { + return "numtheory"; + } + + std::string description() const override + { + return "Calculates a modular inverse"; + } + + void go() override + { + const Botan::BigInt n(get_arg("n")); + const Botan::BigInt mod(get_arg("mod")); + + output() << Botan::inverse_mod(n, mod) << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("mod_inverse", Modular_Inverse); + +class Gen_Prime final : public Command + { + public: + Gen_Prime() : Command("gen_prime --count=1 bits") {} + + std::string group() const override + { + return "numtheory"; + } + + std::string description() const override + { + return "Samples one or more primes"; + } + + void go() override + { + const size_t bits = get_arg_sz("bits"); + const size_t cnt = get_arg_sz("count"); + + for(size_t i = 0; i != cnt; ++i) + { + const Botan::BigInt p = Botan::random_prime(rng(), bits); + output() << p << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("gen_prime", Gen_Prime); + +class Is_Prime final : public Command + { + public: + Is_Prime() : Command("is_prime --prob=56 n") {} + + std::string group() const override + { + return "numtheory"; + } + + std::string description() const override + { + return "Test if the integer n is composite or prime"; + } + + void go() override + { + Botan::BigInt n(get_arg("n")); + const size_t prob = get_arg_sz("prob"); + const bool prime = Botan::is_prime(n, rng(), prob); + + output() << n << " is " << (prime ? "probably prime" : "composite") << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("is_prime", Is_Prime); + +/* +* Factor integers using a combination of trial division by small +* primes, and Pollard's Rho algorithm +*/ +class Factor final : public Command + { + public: + Factor() : Command("factor n") {} + + std::string group() const override + { + return "numtheory"; + } + + std::string description() const override + { + return "Factor a given integer"; + } + + void go() override + { + Botan::BigInt n(get_arg("n")); + + std::vector factors = factorize(n, rng()); + std::sort(factors.begin(), factors.end()); + + output() << n << ": "; + std::copy(factors.begin(), factors.end(), std::ostream_iterator(output(), " ")); + output() << std::endl; + } + + private: + + std::vector factorize(const Botan::BigInt& n_in, + Botan::RandomNumberGenerator& rng) + { + Botan::BigInt n = n_in; + std::vector factors = remove_small_factors(n); + + while(n != 1) + { + if(Botan::is_prime(n, rng)) + { + factors.push_back(n); + break; + } + + Botan::BigInt a_factor = 0; + while(a_factor == 0) + { + a_factor = rho(n, rng); + } + + std::vector rho_factored = factorize(a_factor, rng); + for(size_t j = 0; j != rho_factored.size(); j++) + { + factors.push_back(rho_factored[j]); + } + + n /= a_factor; + } + + return factors; + } + + /* + * Pollard's Rho algorithm, as described in the MIT algorithms book. + * Uses Brent's cycle finding + */ + Botan::BigInt rho(const Botan::BigInt& n, Botan::RandomNumberGenerator& rng) + { + auto monty_n = std::make_shared(n); + + const Botan::Montgomery_Int one(monty_n, monty_n->R1(), false); + + Botan::Montgomery_Int x(monty_n, Botan::BigInt::random_integer(rng, 2, n - 3), false); + Botan::Montgomery_Int y = x; + Botan::Montgomery_Int z = one; + Botan::Montgomery_Int t(monty_n); + Botan::BigInt d; + + Botan::secure_vector ws; + + size_t i = 1, k = 2; + + while(true) + { + i++; + + if(i >= 0xFFFF0000) // bad seed? too slow? bail out + { + break; + } + + x.square_this(ws); // x = x^2 + x.add(one, ws); + + t = y; + t.sub(x, ws); + + z.mul_by(t, ws); + + if(i == k || i % 128 == 0) + { + d = Botan::gcd(z.value(), n); + z = one; + + if(d == n) + { + // TODO Should rewind here + break; + } + + if(d != 1) + return d; + } + + if(i == k) + { + y = x; + k = 2 * k; + } + } + + // failed + return 0; + } + + // Remove (and return) any small (< 2^16) factors + std::vector remove_small_factors(Botan::BigInt& n) + { + std::vector factors; + + while(n.is_even()) + { + factors.push_back(2); + n /= 2; + } + + for(size_t j = 0; j != Botan::PRIME_TABLE_SIZE; j++) + { + uint16_t prime = Botan::PRIMES[j]; + if(n < prime) + { + break; + } + + Botan::BigInt x = Botan::gcd(n, prime); + + if(x != 1) + { + n /= x; + + while(x != 1) + { + x /= prime; + factors.push_back(prime); + } + } + } + + return factors; + } + }; + +BOTAN_REGISTER_COMMAND("factor", Factor); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/pbkdf.cpp b/comm/third_party/botan/src/cli/pbkdf.cpp new file mode 100644 index 0000000000..d17c492203 --- /dev/null +++ b/comm/third_party/botan/src/cli/pbkdf.cpp @@ -0,0 +1,99 @@ +/* +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_PBKDF) + #include + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_PBKDF) + +class PBKDF_Tune final : public Command + { + public: + PBKDF_Tune() : Command("pbkdf_tune --algo=Scrypt --max-mem=256 --output-len=32 --check *times") {} + + std::string group() const override + { + return "passhash"; + } + + std::string description() const override + { + return "Tune a PBKDF algo"; + } + + void go() override + { + const size_t output_len = get_arg_sz("output-len"); + const std::string algo = get_arg("algo"); + const size_t max_mem = get_arg_sz("max-mem"); + const bool check_time = flag_set("check"); + + std::unique_ptr pwdhash_fam = + Botan::PasswordHashFamily::create(algo); + + if(!pwdhash_fam) + throw CLI_Error_Unsupported("Password hashing", algo); + + for(const std::string& time : get_arg_list("times")) + { + std::unique_ptr pwhash; + + if(time == "default") + { + pwhash = pwdhash_fam->default_params(); + } + else + { + size_t msec = 0; + try + { + msec = std::stoul(time); + } + catch(std::exception&) + { + throw CLI_Usage_Error("Unknown time value '" + time + "' for pbkdf_tune"); + } + + pwhash = pwdhash_fam->tune(output_len, std::chrono::milliseconds(msec), max_mem); + } + + output() << "For " << time << " ms selected " << pwhash->to_string(); + + if(pwhash->total_memory_usage() > 0) + { + output() << " using " << pwhash->total_memory_usage()/(1024*1024) << " MiB"; + } + + if(check_time) + { + std::vector outbuf(output_len); + const uint8_t salt[8] = { 0 }; + + const uint64_t start_ns = Botan::OS::get_system_timestamp_ns(); + pwhash->derive_key(outbuf.data(), outbuf.size(), + "test", 4, salt, sizeof(salt)); + const uint64_t end_ns = Botan::OS::get_system_timestamp_ns(); + const uint64_t dur_ns = end_ns - start_ns; + + output() << " took " << (dur_ns / 1000000.0) << " msec to compute"; + } + + output() << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("pbkdf_tune", PBKDF_Tune); + +#endif + +} diff --git a/comm/third_party/botan/src/cli/pk_crypt.cpp b/comm/third_party/botan/src/cli/pk_crypt.cpp new file mode 100644 index 0000000000..111a60129f --- /dev/null +++ b/comm/third_party/botan/src/cli/pk_crypt.cpp @@ -0,0 +1,229 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_AEAD_MODES) && defined(BOTAN_HAS_EME_OAEP) && defined(BOTAN_HAS_SHA2_32) && defined(BOTAN_HAS_PEM_CODEC) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan_CLI { + +namespace { + +class PK_Encrypt final : public Command + { + public: + PK_Encrypt() : Command("pk_encrypt --aead=AES-256/GCM pubkey datafile") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Encrypt a file using a RSA public key"; + } + + void go() override + { + std::unique_ptr key(Botan::X509::load_key(get_arg("pubkey"))); + if(!key) + { + throw CLI_Error("Unable to load public key"); + } + + if(key->algo_name() != "RSA") + { + throw CLI_Usage_Error("This function requires an RSA key"); + } + + const std::string OAEP_HASH = "SHA-256"; + const std::string aead_algo = get_arg("aead"); + + std::unique_ptr aead = + Botan::AEAD_Mode::create(aead_algo, Botan::ENCRYPTION); + + if(!aead) + throw CLI_Usage_Error("The AEAD '" + aead_algo + "' is not available"); + + const Botan::OID aead_oid = Botan::OID::from_string(aead_algo); + if(aead_oid.empty()) + throw CLI_Usage_Error("No OID defined for AEAD '" + aead_algo + "'"); + + Botan::secure_vector data; + auto insert_fn = [&](const uint8_t b[], size_t l) + { + data.insert(data.end(), b, b + l); + }; + this->read_file(get_arg("datafile"), insert_fn); + + const Botan::AlgorithmIdentifier hash_id(OAEP_HASH, Botan::AlgorithmIdentifier::USE_EMPTY_PARAM); + const Botan::AlgorithmIdentifier pk_alg_id("RSA/OAEP", hash_id.BER_encode()); + + Botan::PK_Encryptor_EME enc(*key, rng(), "OAEP(" + OAEP_HASH + ")"); + + const Botan::secure_vector file_key = rng().random_vec(aead->key_spec().maximum_keylength()); + + const std::vector encrypted_key = enc.encrypt(file_key, rng()); + + const Botan::secure_vector nonce = rng().random_vec(aead->default_nonce_length()); + aead->set_key(file_key); + aead->set_associated_data_vec(encrypted_key); + aead->start(nonce); + + aead->finish(data); + + std::vector buf; + Botan::DER_Encoder der(buf); + + der.start_cons(Botan::SEQUENCE) + .encode(pk_alg_id) + .encode(encrypted_key, Botan::OCTET_STRING) + .encode(aead_oid) + .encode(nonce, Botan::OCTET_STRING) + .encode(data, Botan::OCTET_STRING) + .end_cons(); + + output() << Botan::PEM_Code::encode(buf, "PUBKEY ENCRYPTED MESSAGE", 72); + } + }; + +BOTAN_REGISTER_COMMAND("pk_encrypt", PK_Encrypt); + +class PK_Decrypt final : public Command + { + public: + PK_Decrypt() : Command("pk_decrypt privkey datafile") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Decrypt a file using a RSA private key"; + } + + void go() override + { + Botan::DataSource_Stream input_stream(get_arg("privkey")); + auto get_pass = [this]() { return get_passphrase("Password"); }; + std::unique_ptr key = Botan::PKCS8::load_key(input_stream, get_pass); + + if(!key) + { + throw CLI_Error("Unable to load public key"); + } + + if(key->algo_name() != "RSA") + { + throw CLI_Usage_Error("This function requires an RSA key"); + } + + Botan::secure_vector data; + std::vector encrypted_key; + std::vector nonce; + Botan::AlgorithmIdentifier pk_alg_id; + Botan::OID aead_oid; + + try + { + Botan::DataSource_Stream input(get_arg("datafile")); + + Botan::BER_Decoder(Botan::PEM_Code::decode_check_label(input, "PUBKEY ENCRYPTED MESSAGE")) + .start_cons(Botan::SEQUENCE) + .decode(pk_alg_id) + .decode(encrypted_key, Botan::OCTET_STRING) + .decode(aead_oid) + .decode(nonce, Botan::OCTET_STRING) + .decode(data, Botan::OCTET_STRING) + .end_cons(); + } + catch(Botan::Decoding_Error&) + { + error_output() << "Parsing input file failed: invalid format?\n"; + return set_return_code(1); + } + + const std::string aead_algo = Botan::OIDS::oid2str_or_empty(aead_oid); + if(aead_algo == "") + { + error_output() << "Ciphertext was encrypted with an unknown algorithm"; + return set_return_code(1); + } + + if(pk_alg_id.get_oid() != Botan::OID::from_string("RSA/OAEP")) + { + error_output() << "Ciphertext was encrypted with something other than RSA/OAEP"; + return set_return_code(1); + } + + Botan::AlgorithmIdentifier oaep_hash_id; + Botan::BER_Decoder(pk_alg_id.get_parameters()).decode(oaep_hash_id); + + const std::string oaep_hash = Botan::OIDS::oid2str_or_empty(oaep_hash_id.get_oid()); + + if(oaep_hash.empty()) + { + error_output() << "Unknown hash function used with OAEP, OID " << oaep_hash_id.get_oid().to_string() << "\n"; + return set_return_code(1); + } + + if(oaep_hash_id.get_parameters().empty() == false) + { + error_output() << "Unknown OAEP parameters used\n"; + return set_return_code(1); + } + + std::unique_ptr aead = + Botan::AEAD_Mode::create_or_throw(aead_algo, Botan::DECRYPTION); + + const size_t expected_keylen = aead->key_spec().maximum_keylength(); + + Botan::PK_Decryptor_EME dec(*key, rng(), "OAEP(" + oaep_hash + ")"); + + const Botan::secure_vector file_key = + dec.decrypt_or_random(encrypted_key.data(), + encrypted_key.size(), + expected_keylen, + rng()); + + aead->set_key(file_key); + aead->set_associated_data_vec(encrypted_key); + aead->start(nonce); + + try + { + aead->finish(data); + + output().write(reinterpret_cast(data.data()), data.size()); + } + catch(Botan::Integrity_Failure&) + { + error_output() << "Message authentication failure, possible ciphertext tampering\n"; + return set_return_code(1); + } + } + }; + +BOTAN_REGISTER_COMMAND("pk_decrypt", PK_Decrypt); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/cli/psk.cpp b/comm/third_party/botan/src/cli/psk.cpp new file mode 100644 index 0000000000..35e38292d9 --- /dev/null +++ b/comm/third_party/botan/src/cli/psk.cpp @@ -0,0 +1,106 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_PSK_DB) && defined(BOTAN_HAS_SQLITE3) + +#include +#include +#include + +namespace Botan_CLI { + +class PSK_Tool_Base : public Command + { + public: + PSK_Tool_Base(const std::string& spec) : Command(spec) {} + + std::string group() const override + { + return "psk"; + } + + void go() override + { + const std::string db_filename = get_arg("db"); + const Botan::secure_vector db_key = Botan::hex_decode_locked(get_passphrase_arg("Database key", "db_key")); + + std::shared_ptr db = std::make_shared(db_filename); + Botan::Encrypted_PSK_Database_SQL psk(db_key, db, "psk"); + + psk_operation(psk); + } + + private: + virtual void psk_operation(Botan::PSK_Database& db) = 0; + }; + +class PSK_Tool_Set final : public PSK_Tool_Base + { + public: + PSK_Tool_Set() : PSK_Tool_Base("psk_set db db_key name psk") {} + + std::string description() const override + { + return "Save a PSK encrypted in the database"; + } + + private: + void psk_operation(Botan::PSK_Database& db) override + { + const std::string name = get_arg("name"); + const Botan::secure_vector psk = Botan::hex_decode_locked(get_passphrase_arg("PSK", "psk")); + db.set_vec(name, psk); + } + }; + +class PSK_Tool_Get final : public PSK_Tool_Base + { + public: + PSK_Tool_Get() : PSK_Tool_Base("psk_get db db_key name") {} + + std::string description() const override + { + return "Read a value saved with psk_set"; + } + + private: + void psk_operation(Botan::PSK_Database& db) override + { + const std::string name = get_arg("name"); + const Botan::secure_vector val = db.get(name); + output() << Botan::hex_encode(val) << "\n"; + } + }; + +class PSK_Tool_List final : public PSK_Tool_Base + { + public: + PSK_Tool_List() : PSK_Tool_Base("psk_list db db_key") {} + + std::string description() const override + { + return "List all values saved to the database"; + } + + private: + void psk_operation(Botan::PSK_Database& db) override + { + const std::set names = db.list_names(); + + for(std::string name : names) + output() << name << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("psk_set", PSK_Tool_Set); +BOTAN_REGISTER_COMMAND("psk_get", PSK_Tool_Get); +BOTAN_REGISTER_COMMAND("psk_list", PSK_Tool_List); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/pubkey.cpp b/comm/third_party/botan/src/cli/pubkey.cpp new file mode 100644 index 0000000000..7c7e1bfc0d --- /dev/null +++ b/comm/third_party/botan/src/cli/pubkey.cpp @@ -0,0 +1,554 @@ +/* +* (C) 2010,2014,2015,2019 Jack Lloyd +* (C) 2019 Matthias Gierlings +* (C) 2015 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOTAN_HAS_DL_GROUP) + #include +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + #include +#endif + +namespace Botan_CLI { + +class PK_Keygen final : public Command + { + public: + PK_Keygen() : Command("keygen --algo=RSA --params= --passphrase= --pbe= --pbe-millis=300 --provider= --der-out") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Generate a PKCS #8 private key"; + } + + void go() override + { + const std::string algo = get_arg("algo"); + const std::string params = get_arg("params"); + const std::string provider = get_arg("provider"); + + std::unique_ptr key = + Botan::create_private_key(algo, rng(), params, provider); + + if(!key) + { + throw CLI_Error_Unsupported("keygen", algo); + } + + const std::string pass = get_passphrase_arg("Key passphrase", "passphrase"); + const bool der_out = flag_set("der-out"); + + const std::chrono::milliseconds pbe_millis(get_arg_sz("pbe-millis")); + const std::string pbe = get_arg("pbe"); + + if(der_out) + { + if(pass.empty()) + { + write_output(Botan::PKCS8::BER_encode(*key)); + } + else + { + write_output(Botan::PKCS8::BER_encode(*key, rng(), pass, pbe_millis, pbe)); + } + } + else + { + if(pass.empty()) + { + output() << Botan::PKCS8::PEM_encode(*key); + } + else + { + output() << Botan::PKCS8::PEM_encode(*key, rng(), pass, pbe_millis, pbe); + } + } + } + }; + +BOTAN_REGISTER_COMMAND("keygen", PK_Keygen); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +namespace { + +std::string choose_sig_padding(const std::string& key, const std::string& emsa, const std::string& hash) + { + std::string emsa_or_default = [&]() -> std::string + { + if(!emsa.empty()) + { + return emsa; + } + + if(key == "RSA") + { + return "EMSA4"; + } // PSS + else if(key == "ECDSA" || key == "DSA") + { + return "EMSA1"; + } + else if(key == "Ed25519") + { + return ""; + } + else + { + return "EMSA1"; + } + }(); + + if(emsa_or_default.empty()) + { + return hash; + } + + return emsa_or_default + "(" + hash + ")"; + } + +} + +class PK_Fingerprint final : public Command + { + public: + PK_Fingerprint() : Command("fingerprint --no-fsname --algo=SHA-256 *keys") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Calculate a public key fingerprint"; + } + + void go() override + { + const std::string hash_algo = get_arg("algo"); + const bool no_fsname = flag_set("no-fsname"); + + for(std::string key_file : get_arg_list("keys")) + { + std::unique_ptr key( + key_file == "-" + ? Botan::X509::load_key(this->slurp_file("-", 4096)) + : Botan::X509::load_key(key_file)); + + const std::string fprint = key->fingerprint_public(hash_algo); + + if(no_fsname || key_file == "-") + { output() << fprint << "\n"; } + else + { output() << key_file << ": " << fprint << "\n"; } + } + } + }; + +BOTAN_REGISTER_COMMAND("fingerprint", PK_Fingerprint); + +class PK_Sign final : public Command + { + public: + PK_Sign() : Command("sign --der-format --passphrase= --hash=SHA-256 --emsa= --provider= key file") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Sign arbitrary data"; + } + + void go() override + { + const std::string key_file = get_arg("key"); + const std::string passphrase = get_passphrase_arg("Passphrase for " + key_file, "passphrase"); + + Botan::DataSource_Stream input(key_file); + std::unique_ptr key = Botan::PKCS8::load_key(input, passphrase); + + if(!key) + { + throw CLI_Error("Unable to load private key"); + } + + const std::string sig_padding = + choose_sig_padding(key->algo_name(), get_arg("emsa"), get_arg("hash")); + + const Botan::Signature_Format format = + flag_set("der-format") ? Botan::DER_SEQUENCE : Botan::IEEE_1363; + + const std::string provider = get_arg("provider"); + + Botan::PK_Signer signer(*key, rng(), sig_padding, format, provider); + + auto onData = [&signer](const uint8_t b[], size_t l) + { + signer.update(b, l); + }; + this->read_file(get_arg("file"), onData); + + std::vector sig { signer.signature(rng()) }; + + if(key->stateful_operation()) + { + std::ofstream updated_key(key_file); + if(passphrase.empty()) + { updated_key << Botan::PKCS8::PEM_encode(*key); } + else + { updated_key << Botan::PKCS8::PEM_encode(*key, rng(), passphrase); } + } + + output() << Botan::base64_encode(sig) << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("sign", PK_Sign); + +class PK_Verify final : public Command + { + public: + PK_Verify() : Command("verify --der-format --hash=SHA-256 --emsa= pubkey file signature") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Verify the authenticity of the given file with the provided signature"; + } + + void go() override + { + std::unique_ptr key(Botan::X509::load_key(get_arg("pubkey"))); + if(!key) + { + throw CLI_Error("Unable to load public key"); + } + + const std::string sig_padding = + choose_sig_padding(key->algo_name(), get_arg("emsa"), get_arg("hash")); + + const Botan::Signature_Format format = + flag_set("der-format") ? Botan::DER_SEQUENCE : Botan::IEEE_1363; + + Botan::PK_Verifier verifier(*key, sig_padding, format); + auto onData = [&verifier](const uint8_t b[], size_t l) + { + verifier.update(b, l); + }; + this->read_file(get_arg("file"), onData); + + const Botan::secure_vector signature = + Botan::base64_decode(this->slurp_file_as_str(get_arg("signature"))); + + const bool valid = verifier.check_signature(signature); + + output() << "Signature is " << (valid ? "valid" : "invalid") << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("verify", PK_Verify); + +class PKCS8_Tool final : public Command + { + public: + PKCS8_Tool() : Command("pkcs8 --pass-in= --pub-out --der-out --pass-out= --pbe= --pbe-millis=300 key") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Open a PKCS #8 formatted key"; + } + + void go() override + { + const std::string key_file = get_arg("key"); + const std::string pass_in = get_passphrase_arg("Password for " + key_file, "pass-in"); + + Botan::DataSource_Memory key_src(slurp_file(key_file)); + std::unique_ptr key; + + if(pass_in.empty()) + { + key.reset(Botan::PKCS8::load_key(key_src, rng())); + } + else + { + key.reset(Botan::PKCS8::load_key(key_src, rng(), pass_in)); + } + + const std::chrono::milliseconds pbe_millis(get_arg_sz("pbe-millis")); + const std::string pbe = get_arg("pbe"); + const bool der_out = flag_set("der-out"); + + if(flag_set("pub-out")) + { + if(der_out) + { + write_output(Botan::X509::BER_encode(*key)); + } + else + { + output() << Botan::X509::PEM_encode(*key); + } + } + else + { + const std::string pass_out = get_passphrase_arg("Passphrase to encrypt key", "pass-out"); + + if(der_out) + { + if(pass_out.empty()) + { + write_output(Botan::PKCS8::BER_encode(*key)); + } + else + { + write_output(Botan::PKCS8::BER_encode(*key, rng(), pass_out, pbe_millis, pbe)); + } + } + else + { + if(pass_out.empty()) + { + output() << Botan::PKCS8::PEM_encode(*key); + } + else + { + output() << Botan::PKCS8::PEM_encode(*key, rng(), pass_out, pbe_millis, pbe); + } + } + } + } + }; + +BOTAN_REGISTER_COMMAND("pkcs8", PKCS8_Tool); + +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + +class EC_Group_Info final : public Command + { + public: + EC_Group_Info() : Command("ec_group_info --pem name") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Print raw elliptic curve domain parameters of the standardized curve name"; + } + + void go() override + { + Botan::EC_Group ec_group(get_arg("name")); + + if(flag_set("pem")) + { + output() << ec_group.PEM_encode(); + } + else + { + output() << "P = " << std::hex << ec_group.get_p() << "\n" + << "A = " << std::hex << ec_group.get_a() << "\n" + << "B = " << std::hex << ec_group.get_b() << "\n" + << "N = " << std::hex << ec_group.get_order() << "\n" + << "G = " << ec_group.get_g_x() << "," << ec_group.get_g_y() << "\n"; + } + + } + }; + +BOTAN_REGISTER_COMMAND("ec_group_info", EC_Group_Info); + +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + +class DL_Group_Info final : public Command + { + public: + DL_Group_Info() : Command("dl_group_info --pem name") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Print raw Diffie-Hellman parameters (p,g) of the standardized DH group name"; + } + + void go() override + { + Botan::DL_Group dl_group(get_arg("name")); + + if(flag_set("pem")) + { + output() << dl_group.PEM_encode(Botan::DL_Group::ANSI_X9_42_DH_PARAMETERS); + } + else + { + output() << "P = " << std::hex << dl_group.get_p() << "\n" + << "G = " << dl_group.get_g() << "\n"; + } + + } + }; + +BOTAN_REGISTER_COMMAND("dl_group_info", DL_Group_Info); + +class PK_Workfactor final : public Command + { + public: + PK_Workfactor() : Command("pk_workfactor --type=rsa bits") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Provide estimate of strength of public key based on size"; + } + + void go() override + { + const size_t bits = get_arg_sz("bits"); + const std::string type = get_arg("type"); + + if(type == "rsa") + { output() << Botan::if_work_factor(bits) << "\n"; } + else if(type == "dl") + { output() << Botan::dl_work_factor(bits) << "\n"; } + else if(type == "dl_exp") + { output() << Botan::dl_exponent_size(bits) << "\n"; } + else + { throw CLI_Usage_Error("Unknown type for pk_workfactor"); } + } + }; + +BOTAN_REGISTER_COMMAND("pk_workfactor", PK_Workfactor); + +class Gen_DL_Group final : public Command + { + public: + Gen_DL_Group() : Command("gen_dl_group --pbits=1024 --qbits=0 --seed= --type=subgroup") {} + + std::string group() const override + { + return "pubkey"; + } + + std::string description() const override + { + return "Generate ANSI X9.42 encoded Diffie-Hellman group parameters"; + } + + void go() override + { + const size_t pbits = get_arg_sz("pbits"); + const size_t qbits = get_arg_sz("qbits"); + + const std::string type = get_arg("type"); + const std::string seed_str = get_arg("seed"); + + if(type == "strong") + { + if(seed_str.size() > 0) + { throw CLI_Usage_Error("Seed only supported for DSA param gen"); } + Botan::DL_Group grp(rng(), Botan::DL_Group::Strong, pbits); + output() << grp.PEM_encode(Botan::DL_Group::ANSI_X9_42); + } + else if(type == "subgroup") + { + if(seed_str.size() > 0) + { throw CLI_Usage_Error("Seed only supported for DSA param gen"); } + Botan::DL_Group grp(rng(), Botan::DL_Group::Prime_Subgroup, pbits, qbits); + output() << grp.PEM_encode(Botan::DL_Group::ANSI_X9_42); + } + else if(type == "dsa") + { + size_t dsa_qbits = qbits; + if(dsa_qbits == 0) + { + if(pbits == 1024) + { dsa_qbits = 160; } + else if(pbits == 2048 || pbits == 3072) + { dsa_qbits = 256; } + else + { throw CLI_Usage_Error("Invalid DSA p/q sizes"); } + } + + if(seed_str.empty()) + { + Botan::DL_Group grp(rng(), Botan::DL_Group::DSA_Kosherizer, pbits, dsa_qbits); + output() << grp.PEM_encode(Botan::DL_Group::ANSI_X9_42); + } + else + { + const std::vector seed = Botan::hex_decode(seed_str); + Botan::DL_Group grp(rng(), seed, pbits, dsa_qbits); + output() << grp.PEM_encode(Botan::DL_Group::ANSI_X9_42); + } + + } + else + { + throw CLI_Usage_Error("Invalid DL type '" + type + "'"); + } + } + }; + +BOTAN_REGISTER_COMMAND("gen_dl_group", Gen_DL_Group); + +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/cli/roughtime.cpp b/comm/third_party/botan/src/cli/roughtime.cpp new file mode 100644 index 0000000000..ff38fe1c43 --- /dev/null +++ b/comm/third_party/botan/src/cli/roughtime.cpp @@ -0,0 +1,215 @@ +/* +* Roughtime +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_ROUGHTIME) + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Botan_CLI { + +class RoughtimeCheck final : public Command + { + public: + RoughtimeCheck() : Command("roughtime_check --raw-time chain-file") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Parse and validate Roughtime chain file"; + } + + void go() override + { + const auto chain = Botan::Roughtime::Chain(slurp_file_as_str(get_arg("chain-file"))); + unsigned i = 0; + for(const auto& response : chain.responses()) + { + output() << std::setw(3) << ++i << ": UTC "; + if(flag_set("raw-time")) + { output() << Botan::Roughtime::Response::sys_microseconds64(response.utc_midpoint()).time_since_epoch().count(); } + else + { output() << Botan::calendar_value(response.utc_midpoint()).to_string(); } + output() << " (+-" << Botan::Roughtime::Response::microseconds32(response.utc_radius()).count() << "us)\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("roughtime_check", RoughtimeCheck); + +class Roughtime final : public Command + { + public: + Roughtime() : + Command("roughtime --raw-time --chain-file=roughtime-chain --max-chain-size=128 --check-local-clock=60 --host= --pubkey= --servers-file=") {} + + std::string help_text() const override + { + return Command::help_text() + R"( + +--servers-file= + List of servers that will queried in sequence. + + File contents syntax: + + + Example servers: + Cloudflare-Roughtime ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= udp roughtime.cloudflare.com:2002 + Google-Sandbox-Roughtime ed25519 etPaaIxcBMY1oUeGpwvPMCJMwlRVNxv51KK/tktoJTQ= udp roughtime.sandbox.google.com:2002 + +--chain-file= + Succesfull queries are appended to this file. + If limit of --max-chain-size records is reached, the oldest records are truncated. + This queries records can be replayed using command roughtime_check . + + File contents syntax: + +)"; + } + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Retrieve time from Roughtime server"; + } + + void query(std::unique_ptr& chain, + const size_t max_chain_size, + const std::string& address, + const Botan::Ed25519_PublicKey& public_key) + { + Botan::Roughtime::Nonce nonce; + Botan::Roughtime::Nonce blind; + if(chain) + { + blind = Botan::Roughtime::Nonce(rng()); + nonce = chain->next_nonce(blind); + } + else + { + nonce = Botan::Roughtime::Nonce(rng()); + } + const auto response_raw = Botan::Roughtime::online_request(address, nonce, std::chrono::seconds(5)); + const auto response = Botan::Roughtime::Response::from_bits(response_raw, nonce); + if(flag_set("raw-time")) + { output() << "UTC " << Botan::Roughtime::Response::sys_microseconds64(response.utc_midpoint()).time_since_epoch().count(); } + else + { output() << "UTC " << Botan::calendar_value(response.utc_midpoint()).to_string(); } + output() << " (+-" << Botan::Roughtime::Response::microseconds32(response.utc_radius()).count() << "us)"; + if(!response.validate(public_key)) + { + error_output() << "ERROR: Public key does not match!\n"; + set_return_code(1); + return; + } + const auto tolerance = get_arg_sz("check-local-clock"); + if(tolerance) + { + const auto now = std::chrono::system_clock::now(); + const auto diff_abs = now >= response.utc_midpoint() ? now - response.utc_midpoint() : response.utc_midpoint() - now; + if(diff_abs > (response.utc_radius() + std::chrono::seconds(tolerance))) + { + error_output() << "ERROR: Local clock mismatch\n"; + set_return_code(1); + return; + } + output() << " Local clock match"; + } + if(chain) + chain->append({response_raw, public_key, blind}, max_chain_size); + output() << '\n'; + } + + void go() override + { + + const auto max_chain_size = get_arg_sz("max-chain-size"); + const auto chain_file = get_arg("chain-file"); + const auto servers_file = get_arg_or("servers-file", ""); + const auto host = get_arg_or("host", ""); + const auto pk = get_arg_or("pubkey", ""); + + std::unique_ptr chain; + if(!chain_file.empty() && max_chain_size >= 1) + { + try + { + chain.reset(new Botan::Roughtime::Chain(slurp_file_as_str(chain_file))); + } + catch(const CLI_IO_Error&) + { + chain.reset(new Botan::Roughtime::Chain()); //file is to still be created + } + } + + const bool from_servers_file = !servers_file.empty(); + const bool from_host_and_pk = !host.empty() && !pk.empty(); + if(from_servers_file == from_host_and_pk) + { + error_output() << "Please specify either --servers-file or --host and --pubkey\n"; + set_return_code(1); + return; + } + + if(!servers_file.empty()) + { + const auto servers = Botan::Roughtime::servers_from_str(slurp_file_as_str(servers_file)); + + for(const auto& s : servers) + { + output() << std::setw(25) << std::left << s.name() << ": "; + for(const auto& a : s.addresses()) + { + try + { + query(chain, max_chain_size, a, s.public_key()); + break; + } + catch(const std::exception& ex) //network error, try next address + { + error_output() << ex.what() << '\n'; + } + } + } + + } + else + { + query(chain, max_chain_size, host, Botan::Ed25519_PublicKey(Botan::base64_decode(pk))); + } + + if(chain) + { + std::ofstream out(chain_file); + out << chain->to_string(); + } + } + }; + +BOTAN_REGISTER_COMMAND("roughtime", Roughtime); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/sandbox.cpp b/comm/third_party/botan/src/cli/sandbox.cpp new file mode 100644 index 0000000000..6ac8007af2 --- /dev/null +++ b/comm/third_party/botan/src/cli/sandbox.cpp @@ -0,0 +1,115 @@ +/* +* (C) 2019 David Carlier +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "sandbox.h" +#include + +#if defined(BOTAN_TARGET_OS_HAS_PLEDGE) + #include +#elif defined(BOTAN_TARGET_OS_HAS_CAP_ENTER) + #include + #include +#elif defined(BOTAN_TARGET_OS_HAS_SETPPRIV) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_TARGET_OS_HAS_SETPPRIV) +struct SandboxPrivDelete { + void operator()(priv_set_t *ps) + { + ::priv_emptyset(ps); + ::priv_freeset(ps); + } +}; +#endif + +Sandbox::Sandbox() + { +#if defined(BOTAN_TARGET_OS_HAS_PLEDGE) + m_name = "pledge"; +#elif defined(BOTAN_TARGET_OS_HAS_CAP_ENTER) + m_name = "capsicum"; +#elif defined(BOTAN_TARGET_OS_HAS_SETPPRIV) + m_name = "privilege"; +#else + m_name = ""; +#endif + } + +bool Sandbox::init() + { + Botan::initialize_allocator(); + +#if defined(BOTAN_TARGET_OS_HAS_PLEDGE) + const static char *opts = "stdio rpath inet error"; + return (::pledge(opts, nullptr) == 0); +#elif defined(BOTAN_TARGET_OS_HAS_CAP_ENTER) + cap_rights_t wt, rd; + + if (::cap_rights_init(&wt, CAP_READ, CAP_WRITE) == nullptr) + { + return false; + } + + if (::cap_rights_init(&rd, CAP_FCNTL, CAP_EVENT, CAP_READ) == nullptr) + { + return false; + } + + if (::cap_rights_limit(STDOUT_FILENO, &wt) == -1) + { + return false; + } + + if (::cap_rights_limit(STDERR_FILENO, &wt) == -1) + { + return false; + } + + if (::cap_rights_limit(STDIN_FILENO, &rd) == -1) + { + return false; + } + + return (::cap_enter() == 0); +#elif defined(BOTAN_TARGET_OS_HAS_SETPPRIV) + priv_set_t *tmp; + std::unique_ptr ps; + const char *const priv_perms[] = { + PRIV_PROC_FORK, + PRIV_PROC_EXEC, + PRIV_PROC_INFO, + PRIV_PROC_SESSION, + }; + + if ((tmp = ::priv_allocset()) == nullptr) + { + return false; + } + + ps = std::unique_ptr(tmp); + ::priv_basicset(ps.get()); + + for (auto perm: priv_perms) + { + if (::priv_delset(ps.get(), perm) == -1) + { + return false; + } + } + + return true; +#else + return true; +#endif + } + +Sandbox::~Sandbox() + { + } +} diff --git a/comm/third_party/botan/src/cli/sandbox.h b/comm/third_party/botan/src/cli/sandbox.h new file mode 100644 index 0000000000..2d6f5c4df8 --- /dev/null +++ b/comm/third_party/botan/src/cli/sandbox.h @@ -0,0 +1,32 @@ +/* +* (C) 2019 David Carlier +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CLI_SANDBOX_H_ +#define BOTAN_CLI_SANDBOX_H_ + +#include + +namespace Botan_CLI { + +class Sandbox + { + public: + explicit Sandbox(); + virtual ~Sandbox(); + + bool init(); + + const std::string& name() const + { + return m_name; + } + + private: + std::string m_name; + }; +} + +#endif diff --git a/comm/third_party/botan/src/cli/socket_utils.h b/comm/third_party/botan/src/cli/socket_utils.h new file mode 100644 index 0000000000..d52b5a0e7c --- /dev/null +++ b/comm/third_party/botan/src/cli/socket_utils.h @@ -0,0 +1,105 @@ +/* +* (C) 2014,2017 Jack Lloyd +* 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CLI_SOCKET_UTILS_H_ +#define BOTAN_CLI_SOCKET_UTILS_H_ + +#include +#include "cli_exceptions.h" + +#if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + +#include +#include + +typedef SOCKET socket_type; + +inline socket_type invalid_socket() { return INVALID_SOCKET; } + +typedef size_t ssize_t; +typedef int sendrecv_len_type; + +inline void close_socket(socket_type s) { ::closesocket(s); } + +#define STDIN_FILENO _fileno(stdin) + +inline void init_sockets() + { + WSAData wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + + if(::WSAStartup(wsa_version, &wsa_data) != 0) + { + throw Botan_CLI::CLI_Error("WSAStartup() failed: " + std::to_string(WSAGetLastError())); + } + + if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) + { + ::WSACleanup(); + throw Botan_CLI::CLI_Error("Could not find a usable version of Winsock.dll"); + } + } + +inline void stop_sockets() + { + ::WSACleanup(); + } + +inline std::string err_to_string(int e) + { + // TODO use strerror_s here + return "Error code " + std::to_string(e); + } + +inline int close(int fd) + { + return ::closesocket(fd); + } + +inline int read(int s, void* buf, size_t len) + { + return ::recv(s, reinterpret_cast(buf), static_cast(len), 0); + } + +inline int send(int s, const uint8_t* buf, size_t len, int flags) + { + return ::send(s, reinterpret_cast(buf), static_cast(len), flags); + } + +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef int socket_type; +typedef size_t sendrecv_len_type; + +inline socket_type invalid_socket() { return -1; } +inline void close_socket(socket_type s) { ::close(s); } + +inline void init_sockets() {} +inline void stop_sockets() {} + +inline std::string err_to_string(int e) + { + return std::strerror(e); + } + +#endif + +#if !defined(MSG_NOSIGNAL) + #define MSG_NOSIGNAL 0 +#endif + +#endif diff --git a/comm/third_party/botan/src/cli/speed.cpp b/comm/third_party/botan/src/cli/speed.cpp new file mode 100644 index 0000000000..b8454d2a7a --- /dev/null +++ b/comm/third_party/botan/src/cli/speed.cpp @@ -0,0 +1,2342 @@ +/* +* (C) 2009,2010,2014,2015,2017,2018 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include "../tests/test_rng.h" // FIXME + +#include +#include +#include +#include +#include +#include +#include + +// Always available: +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BIGINT) + #include + #include +#endif + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_HASH) + #include +#endif + +#if defined(BOTAN_HAS_CIPHER_MODES) + #include +#endif + +#if defined(BOTAN_HAS_MAC) + #include +#endif + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include +#endif + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include +#endif + +#if defined(BOTAN_HAS_HMAC_DRBG) + #include +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + #include +#endif + +#if defined(BOTAN_HAS_CHACHA_RNG) + #include +#endif + +#if defined(BOTAN_HAS_FPE_FE1) + #include +#endif + +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) + #include +#endif + +#if defined(BOTAN_HAS_COMPRESSION) + #include +#endif + +#if defined(BOTAN_HAS_POLY_DBL) + #include +#endif + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + #include + #include + #include + #include + #include +#endif + +#if defined(BOTAN_HAS_NUMBERTHEORY) + #include + #include + #include + #include +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + #include +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + #include +#endif + +#if defined(BOTAN_HAS_MCELIECE) + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include +#endif + +#if defined(BOTAN_HAS_NEWHOPE) + #include +#endif + +#if defined(BOTAN_HAS_SCRYPT) + #include +#endif + +#if defined(BOTAN_HAS_ARGON2) + #include +#endif + +#if defined(BOTAN_HAS_BCRYPT) + #include +#endif + +#if defined(BOTAN_HAS_PASSHASH9) + #include +#endif + +namespace Botan_CLI { + +using Botan::Timer; + +namespace { + +class JSON_Output final + { + public: + void add(const Timer& timer) { m_results.push_back(timer); } + + std::string print() const + { + std::ostringstream out; + + out << "[\n"; + + for(size_t i = 0; i != m_results.size(); ++i) + { + if(i != 0) + out << ","; + + const Timer& t = m_results[i]; + + out << '{'; + out << "\"algo\": \"" << t.get_name() << "\", "; + out << "\"op\": \"" << t.doing() << "\", "; + + out << "\"events\": " << t.events() << ", "; + if(t.cycles_consumed() > 0) + out << "\"cycles\": " << t.cycles_consumed() << ", "; + if(t.buf_size() > 0) + { + out << "\"bps\": " << static_cast(t.events() / (t.value() / 1000000000.0)) << ", "; + out << "\"buf_size\": " << t.buf_size() << ", "; + } + + out << "\"nanos\": " << t.value(); + + out << "}\n"; + } + out << "]\n"; + + return out.str(); + } + private: + std::vector m_results; + }; + +class Summary final + { + public: + Summary() {} + + void add(const Timer& t) + { + if(t.buf_size() == 0) + { + m_ops_entries.push_back(t); + } + else + { + m_bps_entries[std::make_pair(t.doing(), t.get_name())].push_back(t); + } + } + + std::string print() + { + const size_t name_padding = 35; + const size_t op_name_padding = 16; + const size_t op_padding = 16; + + std::ostringstream result_ss; + result_ss << std::fixed; + + if(m_bps_entries.size() > 0) + { + result_ss << "\n"; + + // add table header + result_ss << std::setw(name_padding) << std::left << "algo" + << std::setw(op_name_padding) << std::left << "operation"; + + for(const Timer& t : m_bps_entries.begin()->second) + { + result_ss << std::setw(op_padding) << std::right << (std::to_string(t.buf_size()) + " bytes"); + } + result_ss << "\n"; + + // add table entries + for(const auto& entry : m_bps_entries) + { + if(entry.second.empty()) + continue; + + result_ss << std::setw(name_padding) << std::left << (entry.first.second) + << std::setw(op_name_padding) << std::left << (entry.first.first); + + for(const Timer& t : entry.second) + { + + if(t.events() == 0) + { + result_ss << std::setw(op_padding) << std::right << "N/A"; + } + else + { + result_ss << std::setw(op_padding) << std::right + << std::setprecision(2) << (t.bytes_per_second() / 1000.0); + } + } + + result_ss << "\n"; + } + + result_ss << "\n[results are the number of 1000s bytes processed per second]\n"; + } + + if(m_ops_entries.size() > 0) + { + result_ss << std::setprecision(6) << "\n"; + + // sort entries + std::sort(m_ops_entries.begin(), m_ops_entries.end()); + + // add table header + result_ss << std::setw(name_padding) << std::left << "algo" + << std::setw(op_name_padding) << std::left << "operation" + << std::setw(op_padding) << std::right << "sec/op" + << std::setw(op_padding) << std::right << "op/sec" + << "\n"; + + // add table entries + for(const Timer& entry : m_ops_entries) + { + result_ss << std::setw(name_padding) << std::left << entry.get_name() + << std::setw(op_name_padding) << std::left << entry.doing() + << std::setw(op_padding) << std::right << entry.seconds_per_event() + << std::setw(op_padding) << std::right << entry.events_per_second() + << "\n"; + } + } + + return result_ss.str(); + } + + private: + std::map, std::vector> m_bps_entries; + std::vector m_ops_entries; + }; + +std::vector unique_buffer_sizes(const std::string& cmdline_arg) + { + const size_t MAX_BUF_SIZE = 64*1024*1024; + + std::set buf; + for(std::string size_str : Botan::split_on(cmdline_arg, ',')) + { + size_t x = 0; + try + { + size_t converted = 0; + x = static_cast(std::stoul(size_str, &converted, 0)); + + if(converted != size_str.size()) + throw CLI_Usage_Error("Invalid integer"); + } + catch(std::exception&) + { + throw CLI_Usage_Error("Invalid integer value '" + size_str + "' for option buf-size"); + } + + if(x == 0) + throw CLI_Usage_Error("Cannot have a zero-sized buffer"); + + if(x > MAX_BUF_SIZE) + throw CLI_Usage_Error("Specified buffer size is too large"); + + buf.insert(x); + } + + return std::vector(buf.begin(), buf.end()); + } + +} + +class Speed final : public Command + { + public: + Speed() + : Command("speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos") {} + + std::vector default_benchmark_list() + { + /* + This is not intended to be exhaustive: it just hits the high + points of the most interesting or widely used algorithms. + */ + + return { + /* Block ciphers */ + "AES-128", + "AES-192", + "AES-256", + "ARIA-128", + "ARIA-192", + "ARIA-256", + "Blowfish", + "CAST-128", + "CAST-256", + "Camellia-128", + "Camellia-192", + "Camellia-256", + "DES", + "TripleDES", + "GOST-28147-89", + "IDEA", + "KASUMI", + "MISTY1", + "Noekeon", + "SHACAL2", + "SM4", + "Serpent", + "Threefish-512", + "Twofish", + "XTEA", + + /* Cipher modes */ + "AES-128/CBC", + "AES-128/CTR-BE", + "AES-128/EAX", + "AES-128/OCB", + "AES-128/GCM", + "AES-128/XTS", + "AES-128/SIV", + + "Serpent/CBC", + "Serpent/CTR-BE", + "Serpent/EAX", + "Serpent/OCB", + "Serpent/GCM", + "Serpent/XTS", + "Serpent/SIV", + + "ChaCha20Poly1305", + + /* Stream ciphers */ + "RC4", + "Salsa20", + "ChaCha20", + + /* Hashes */ + "SHA-160", + "SHA-256", + "SHA-512", + "SHA-3(256)", + "SHA-3(512)", + "RIPEMD-160", + "Skein-512", + "Blake2b", + "Tiger", + "Whirlpool", + + /* MACs */ + "CMAC(AES-128)", + "HMAC(SHA-256)", + + /* pubkey */ + "RSA", + "DH", + "ECDH", + "ECDSA", + "Ed25519", + "Curve25519", + "NEWHOPE", + "McEliece", + }; + } + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Measures the speed of algorithms"; + } + + void go() override + { + std::chrono::milliseconds msec(get_arg_sz("msec")); + const std::string provider = get_arg("provider"); + std::vector ecc_groups = Botan::split_on(get_arg("ecc-groups"), ','); + const std::string format = get_arg("format"); + const std::string clock_ratio = get_arg("cpu-clock-ratio"); + m_clock_speed = get_arg_sz("cpu-clock-speed"); + + m_clock_cycle_ratio = std::strtod(clock_ratio.c_str(), nullptr); + + /* + * This argument is intended to be the ratio between the cycle counter + * and the actual machine cycles. It is extremely unlikely that there is + * any machine where the cycle counter increments faster than the actual + * clock. + */ + if(m_clock_cycle_ratio < 0.0 || m_clock_cycle_ratio > 1.0) + throw CLI_Usage_Error("Unlikely CPU clock ratio of " + clock_ratio); + + m_clock_cycle_ratio = 1.0 / m_clock_cycle_ratio; + + if(m_clock_speed != 0 && Botan::OS::get_cpu_cycle_counter() != 0) + { + error_output() << "The --cpu-clock-speed option is only intended to be used on " + "platforms without access to a cycle counter.\n" + "Expected incorrect results\n\n"; + } + + if(format == "table") + m_summary.reset(new Summary); + else if(format == "json") + m_json.reset(new JSON_Output); + else if(format != "default") + throw CLI_Usage_Error("Unknown --format type '" + format + "'"); + +#if defined(BOTAN_HAS_ECC_GROUP) + if(ecc_groups.empty()) + { + ecc_groups = { "secp256r1", "brainpool256r1", + "secp384r1", "brainpool384r1", + "secp521r1", "brainpool512r1" }; + } + else if(ecc_groups.size() == 1 && ecc_groups[0] == "all") + { + auto all = Botan::EC_Group::known_named_groups(); + ecc_groups.assign(all.begin(), all.end()); + } +#endif + + std::vector algos = get_arg_list("algos"); + + const std::vector buf_sizes = unique_buffer_sizes(get_arg("buf-size")); + + for(std::string cpuid_to_clear : Botan::split_on(get_arg("clear-cpuid"), ',')) + { + auto bits = Botan::CPUID::bit_from_string(cpuid_to_clear); + if(bits.empty()) + { + error_output() << "Warning don't know CPUID flag '" << cpuid_to_clear << "'\n"; + } + + for(auto bit : bits) + { + Botan::CPUID::clear_cpuid_bit(bit); + } + } + + if(verbose() || m_summary) + { + output() << Botan::version_string() << "\n" + << "CPUID: " << Botan::CPUID::to_string() << "\n\n"; + } + + const bool using_defaults = (algos.empty()); + if(using_defaults) + { + algos = default_benchmark_list(); + } + + for(auto algo : algos) + { + using namespace std::placeholders; + + if(false) + { + // Since everything might be disabled, need a block to else if from + } +#if defined(BOTAN_HAS_HASH) + else if(Botan::HashFunction::providers(algo).size() > 0) + { + bench_providers_of( + algo, provider, msec, buf_sizes, + std::bind(&Speed::bench_hash, this, _1, _2, _3, _4)); + } +#endif +#if defined(BOTAN_HAS_BLOCK_CIPHER) + else if(Botan::BlockCipher::providers(algo).size() > 0) + { + bench_providers_of( + algo, provider, msec, buf_sizes, + std::bind(&Speed::bench_block_cipher, this, _1, _2, _3, _4)); + } +#endif +#if defined(BOTAN_HAS_STREAM_CIPHER) + else if(Botan::StreamCipher::providers(algo).size() > 0) + { + bench_providers_of( + algo, provider, msec, buf_sizes, + std::bind(&Speed::bench_stream_cipher, this, _1, _2, _3, _4)); + } +#endif +#if defined(BOTAN_HAS_CIPHER_MODES) + else if(auto enc = Botan::Cipher_Mode::create(algo, Botan::ENCRYPTION, provider)) + { + auto dec = Botan::Cipher_Mode::create_or_throw(algo, Botan::DECRYPTION, provider); + bench_cipher_mode(*enc, *dec, msec, buf_sizes); + } +#endif +#if defined(BOTAN_HAS_MAC) + else if(Botan::MessageAuthenticationCode::providers(algo).size() > 0) + { + bench_providers_of( + algo, provider, msec, buf_sizes, + std::bind(&Speed::bench_mac, this, _1, _2, _3, _4)); + } +#endif +#if defined(BOTAN_HAS_RSA) + else if(algo == "RSA") + { + bench_rsa(provider, msec); + } + else if(algo == "RSA_keygen") + { + bench_rsa_keygen(provider, msec); + } +#endif +#if defined(BOTAN_HAS_ECDSA) + else if(algo == "ECDSA") + { + bench_ecdsa(ecc_groups, provider, msec); + } + else if(algo == "ecdsa_recovery") + { + bench_ecdsa_recovery(ecc_groups, provider, msec); + } +#endif +#if defined(BOTAN_HAS_SM2) + else if(algo == "SM2") + { + bench_sm2(ecc_groups, provider, msec); + } +#endif +#if defined(BOTAN_HAS_ECKCDSA) + else if(algo == "ECKCDSA") + { + bench_eckcdsa(ecc_groups, provider, msec); + } +#endif +#if defined(BOTAN_HAS_GOST_34_10_2001) + else if(algo == "GOST-34.10") + { + bench_gost_3410(provider, msec); + } +#endif +#if defined(BOTAN_HAS_ECGDSA) + else if(algo == "ECGDSA") + { + bench_ecgdsa(ecc_groups, provider, msec); + } +#endif +#if defined(BOTAN_HAS_ED25519) + else if(algo == "Ed25519") + { + bench_ed25519(provider, msec); + } +#endif +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + else if(algo == "DH") + { + bench_dh(provider, msec); + } +#endif +#if defined(BOTAN_HAS_DSA) + else if(algo == "DSA") + { + bench_dsa(provider, msec); + } +#endif +#if defined(BOTAN_HAS_ELGAMAL) + else if(algo == "ElGamal") + { + bench_elgamal(provider, msec); + } +#endif +#if defined(BOTAN_HAS_ECDH) + else if(algo == "ECDH") + { + bench_ecdh(ecc_groups, provider, msec); + } +#endif +#if defined(BOTAN_HAS_CURVE_25519) + else if(algo == "Curve25519") + { + bench_curve25519(provider, msec); + } +#endif +#if defined(BOTAN_HAS_MCELIECE) + else if(algo == "McEliece") + { + bench_mceliece(provider, msec); + } +#endif +#if defined(BOTAN_HAS_XMSS_RFC8391) + else if(algo == "XMSS") + { + bench_xmss(provider, msec); + } +#endif +#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA_RNG) + else if(algo == "NEWHOPE") + { + bench_newhope(provider, msec); + } +#endif +#if defined(BOTAN_HAS_SCRYPT) + else if(algo == "scrypt") + { + bench_scrypt(provider, msec); + } +#endif +#if defined(BOTAN_HAS_ARGON2) + else if(algo == "argon2") + { + bench_argon2(provider, msec); + } +#endif +#if defined(BOTAN_HAS_BCRYPT) + else if(algo == "bcrypt") + { + bench_bcrypt(); + } +#endif +#if defined(BOTAN_HAS_PASSHASH9) + else if(algo == "passhash9") + { + bench_passhash9(); + } +#endif +#if defined(BOTAN_HAS_POLY_DBL) + else if(algo == "poly_dbl") + { + bench_poly_dbl(msec); + } +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + else if(algo == "modexp") + { + bench_modexp(msec); + } +#endif + +#if defined(BOTAN_HAS_BIGINT) + else if(algo == "mp_mul") + { + bench_mp_mul(msec); + } + else if(algo == "mp_div") + { + bench_mp_div(msec); + } + else if(algo == "mp_div10") + { + bench_mp_div10(msec); + } +#endif + +#if defined(BOTAN_HAS_NUMBERTHEORY) + else if(algo == "primality_test") + { + bench_primality_tests(msec); + } + else if(algo == "random_prime") + { + bench_random_prime(msec); + } + else if(algo == "inverse_mod") + { + bench_inverse_mod(msec); + } + else if(algo == "bn_redc") + { + bench_bn_redc(msec); + } + else if(algo == "nistp_redc") + { + bench_nistp_redc(msec); + } +#endif + +#if defined(BOTAN_HAS_FPE_FE1) + else if(algo == "fpe_fe1") + { + bench_fpe_fe1(msec); + } +#endif + +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) + else if(algo == "rfc3394") + { + bench_rfc3394(msec); + } +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + else if(algo == "ecc_mult") + { + bench_ecc_mult(ecc_groups, msec); + } + else if(algo == "ecc_ops") + { + bench_ecc_ops(ecc_groups, msec); + } + else if(algo == "ecc_init") + { + bench_ecc_init(ecc_groups, msec); + } + else if(algo == "os2ecp") + { + bench_os2ecp(ecc_groups, msec); + } +#endif + else if(algo == "RNG") + { +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + Botan::AutoSeeded_RNG auto_rng; + bench_rng(auto_rng, "AutoSeeded_RNG (with reseed)", msec, buf_sizes); +#endif + +#if defined(BOTAN_HAS_SYSTEM_RNG) + bench_rng(Botan::system_rng(), "System_RNG", msec, buf_sizes); +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + if(Botan::Processor_RNG::available()) + { + Botan::Processor_RNG hwrng; + bench_rng(hwrng, "Processor_RNG", msec, buf_sizes); + } +#endif + +#if defined(BOTAN_HAS_HMAC_DRBG) + for(std::string hash : { "SHA-256", "SHA-384", "SHA-512" }) + { + Botan::HMAC_DRBG hmac_drbg(hash); + bench_rng(hmac_drbg, hmac_drbg.name(), msec, buf_sizes); + } +#endif + +#if defined(BOTAN_HAS_CHACHA_RNG) + // Provide a dummy seed + Botan::ChaCha_RNG chacha_rng(Botan::secure_vector(32)); + bench_rng(chacha_rng, "ChaCha_RNG", msec, buf_sizes); +#endif + + } + else if(algo == "entropy") + { + bench_entropy_sources(msec); + } + else + { + if(verbose() || !using_defaults) + { + error_output() << "Unknown algorithm '" << algo << "'\n"; + } + } + } + + if(m_json) + { + output() << m_json->print(); + } + if(m_summary) + { + output() << m_summary->print() << "\n"; + } + + if(verbose() && m_clock_speed == 0 && m_cycles_consumed > 0 && m_ns_taken > 0) + { + const double seconds = static_cast(m_ns_taken) / 1000000000; + const double Hz = static_cast(m_cycles_consumed) / seconds; + const double MHz = Hz / 1000000; + output() << "\nEstimated clock speed " << MHz << " MHz\n"; + } + } + + private: + + size_t m_clock_speed = 0; + double m_clock_cycle_ratio = 0.0; + uint64_t m_cycles_consumed = 0; + uint64_t m_ns_taken = 0; + std::unique_ptr m_summary; + std::unique_ptr m_json; + + void record_result(const std::unique_ptr& t) + { + m_ns_taken += t->value(); + m_cycles_consumed += t->cycles_consumed(); + if(m_json) + { + m_json->add(*t); + } + else + { + output() << t->to_string() << std::flush; + if(m_summary) + m_summary->add(*t); + } + } + + template + using bench_fn = std::function&)>; + + template + void bench_providers_of(const std::string& algo, + const std::string& provider, /* user request, if any */ + const std::chrono::milliseconds runtime, + const std::vector& buf_sizes, + bench_fn bench_one) + { + for(auto const& prov : T::providers(algo)) + { + if(provider.empty() || provider == prov) + { + auto p = T::create(algo, prov); + + if(p) + { + bench_one(*p, prov, runtime, buf_sizes); + } + } + } + } + + std::unique_ptr make_timer(const std::string& name, + uint64_t event_mult = 1, + const std::string& what = "", + const std::string& provider = "", + size_t buf_size = 0) + { + return std::unique_ptr( + new Timer(name, provider, what, event_mult, buf_size, + m_clock_cycle_ratio, m_clock_speed)); + } + + std::unique_ptr make_timer(const std::string& algo, + const std::string& provider, + const std::string& what) + { + return make_timer(algo, 1, what, provider, 0); + } + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + void bench_block_cipher(Botan::BlockCipher& cipher, + const std::string& provider, + std::chrono::milliseconds runtime, + const std::vector& buf_sizes) + { + std::unique_ptr ks_timer = make_timer(cipher.name(), provider, "key schedule"); + + const Botan::SymmetricKey key(rng(), cipher.maximum_keylength()); + ks_timer->run([&]() { cipher.set_key(key); }); + + const size_t bs = cipher.block_size(); + std::set buf_sizes_in_blocks; + for(size_t buf_size : buf_sizes) + { + if(buf_size % bs == 0) + buf_sizes_in_blocks.insert(buf_size); + else + buf_sizes_in_blocks.insert(buf_size + bs - (buf_size % bs)); + } + + for(size_t buf_size : buf_sizes_in_blocks) + { + std::vector buffer(buf_size); + const size_t blocks = buf_size / bs; + + std::unique_ptr encrypt_timer = make_timer(cipher.name(), buffer.size(), "encrypt", provider, buf_size); + std::unique_ptr decrypt_timer = make_timer(cipher.name(), buffer.size(), "decrypt", provider, buf_size); + + encrypt_timer->run_until_elapsed(runtime, [&]() { cipher.encrypt_n(&buffer[0], &buffer[0], blocks); }); + record_result(encrypt_timer); + + decrypt_timer->run_until_elapsed(runtime, [&]() { cipher.decrypt_n(&buffer[0], &buffer[0], blocks); }); + record_result(decrypt_timer); + } + } +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + void bench_stream_cipher( + Botan::StreamCipher& cipher, + const std::string& provider, + const std::chrono::milliseconds runtime, + const std::vector& buf_sizes) + { + for(auto buf_size : buf_sizes) + { + Botan::secure_vector buffer = rng().random_vec(buf_size); + + std::unique_ptr encrypt_timer = make_timer(cipher.name(), buffer.size(), "encrypt", provider, buf_size); + + const Botan::SymmetricKey key(rng(), cipher.maximum_keylength()); + cipher.set_key(key); + + if(cipher.valid_iv_length(12)) + { + const Botan::InitializationVector iv(rng(), 12); + cipher.set_iv(iv.begin(), iv.size()); + } + + while(encrypt_timer->under(runtime)) + { + encrypt_timer->run([&]() { cipher.encipher(buffer); }); + } + + record_result(encrypt_timer); + } + } +#endif + +#if defined(BOTAN_HAS_HASH) + void bench_hash( + Botan::HashFunction& hash, + const std::string& provider, + const std::chrono::milliseconds runtime, + const std::vector& buf_sizes) + { + std::vector output(hash.output_length()); + + for(auto buf_size : buf_sizes) + { + Botan::secure_vector buffer = rng().random_vec(buf_size); + + std::unique_ptr timer = make_timer(hash.name(), buffer.size(), "hash", provider, buf_size); + timer->run_until_elapsed(runtime, [&]() { hash.update(buffer); hash.final(output.data()); }); + record_result(timer); + } + } +#endif + +#if defined(BOTAN_HAS_MAC) + void bench_mac( + Botan::MessageAuthenticationCode& mac, + const std::string& provider, + const std::chrono::milliseconds runtime, + const std::vector& buf_sizes) + { + std::vector output(mac.output_length()); + + for(auto buf_size : buf_sizes) + { + Botan::secure_vector buffer = rng().random_vec(buf_size); + + const Botan::SymmetricKey key(rng(), mac.maximum_keylength()); + mac.set_key(key); + mac.start(nullptr, 0); + + std::unique_ptr timer = make_timer(mac.name(), buffer.size(), "mac", provider, buf_size); + timer->run_until_elapsed(runtime, [&]() { mac.update(buffer); }); + timer->run([&]() { mac.final(output.data()); }); + record_result(timer); + } + } +#endif + +#if defined(BOTAN_HAS_CIPHER_MODES) + void bench_cipher_mode( + Botan::Cipher_Mode& enc, + Botan::Cipher_Mode& dec, + const std::chrono::milliseconds runtime, + const std::vector& buf_sizes) + { + std::unique_ptr ks_timer = make_timer(enc.name(), enc.provider(), "key schedule"); + + const Botan::SymmetricKey key(rng(), enc.key_spec().maximum_keylength()); + + ks_timer->run([&]() { enc.set_key(key); }); + ks_timer->run([&]() { dec.set_key(key); }); + + record_result(ks_timer); + + for(auto buf_size : buf_sizes) + { + Botan::secure_vector buffer = rng().random_vec(buf_size); + + std::unique_ptr encrypt_timer = make_timer(enc.name(), buffer.size(), "encrypt", enc.provider(), buf_size); + std::unique_ptr decrypt_timer = make_timer(dec.name(), buffer.size(), "decrypt", dec.provider(), buf_size); + + Botan::secure_vector iv = rng().random_vec(enc.default_nonce_length()); + + if(buf_size >= enc.minimum_final_size()) + { + while(encrypt_timer->under(runtime) && decrypt_timer->under(runtime)) + { + // Must run in this order, or AEADs will reject the ciphertext + encrypt_timer->run([&]() { enc.start(iv); enc.finish(buffer); }); + + decrypt_timer->run([&]() { dec.start(iv); dec.finish(buffer); }); + + if(iv.size() > 0) + { + iv[iv.size()-1] += 1; + } + } + } + + record_result(encrypt_timer); + record_result(decrypt_timer); + } + } +#endif + + void bench_rng( + Botan::RandomNumberGenerator& rng, + const std::string& rng_name, + const std::chrono::milliseconds runtime, + const std::vector& buf_sizes) + { + for(auto buf_size : buf_sizes) + { + Botan::secure_vector buffer(buf_size); + +#if defined(BOTAN_HAS_SYSTEM_RNG) + rng.reseed_from_rng(Botan::system_rng(), 256); +#endif + + std::unique_ptr timer = make_timer(rng_name, buffer.size(), "generate", "", buf_size); + timer->run_until_elapsed(runtime, [&]() { rng.randomize(buffer.data(), buffer.size()); }); + record_result(timer); + } + } + + void bench_entropy_sources(const std::chrono::milliseconds) + { + Botan::Entropy_Sources& srcs = Botan::Entropy_Sources::global_sources(); + + for(auto src : srcs.enabled_sources()) + { + size_t entropy_bits = 0; + Botan_Tests::SeedCapturing_RNG rng; + + std::unique_ptr timer = make_timer(src, "", "bytes"); + timer->run([&]() { entropy_bits = srcs.poll_just(rng, src); }); + + size_t compressed_size = 0; + +#if defined(BOTAN_HAS_ZLIB) + std::unique_ptr comp(Botan::make_compressor("zlib")); + + if(comp) + { + Botan::secure_vector compressed; + compressed.assign(rng.seed_material().begin(), rng.seed_material().end()); + comp->start(9); + comp->finish(compressed); + + compressed_size = compressed.size(); + } +#endif + + std::ostringstream msg; + + msg << "Entropy source " << src << " output " << rng.seed_material().size() << " bytes" + << " estimated entropy " << entropy_bits << " in " << timer->milliseconds() << " ms"; + + if(compressed_size > 0) + { + msg << " output compressed to " << compressed_size << " bytes"; + } + + msg << " total samples " << rng.samples() << "\n"; + + timer->set_custom_msg(msg.str()); + + record_result(timer); + } + } + +#if defined(BOTAN_HAS_ECC_GROUP) + void bench_ecc_ops(const std::vector& groups, const std::chrono::milliseconds runtime) + { + for(std::string group_name : groups) + { + const Botan::EC_Group ec_group(group_name); + + std::unique_ptr add_timer = make_timer(group_name + " add"); + std::unique_ptr addf_timer = make_timer(group_name + " addf"); + std::unique_ptr dbl_timer = make_timer(group_name + " dbl"); + + const Botan::PointGFp& base_point = ec_group.get_base_point(); + Botan::PointGFp non_affine_pt = ec_group.get_base_point() * 1776; // create a non-affine point + Botan::PointGFp pt = ec_group.get_base_point(); + + std::vector ws(Botan::PointGFp::WORKSPACE_SIZE); + + while(add_timer->under(runtime) && addf_timer->under(runtime) && dbl_timer->under(runtime)) + { + dbl_timer->run([&]() { pt.mult2(ws); }); + add_timer->run([&]() { pt.add(non_affine_pt, ws); }); + addf_timer->run([&]() { pt.add_affine(base_point, ws); }); + } + + record_result(dbl_timer); + record_result(add_timer); + record_result(addf_timer); + } + } + + void bench_ecc_init(const std::vector& groups, const std::chrono::milliseconds runtime) + { + for(std::string group_name : groups) + { + std::unique_ptr timer = make_timer(group_name + " initialization"); + + while(timer->under(runtime)) + { + Botan::EC_Group::clear_registered_curve_data(); + timer->run([&]() { Botan::EC_Group group(group_name); }); + } + + record_result(timer); + } + } + + void bench_ecc_mult(const std::vector& groups, const std::chrono::milliseconds runtime) + { + for(std::string group_name : groups) + { + const Botan::EC_Group ec_group(group_name); + + std::unique_ptr mult_timer = make_timer(group_name + " Montgomery ladder"); + std::unique_ptr blinded_mult_timer = make_timer(group_name + " blinded comb"); + std::unique_ptr blinded_var_mult_timer = make_timer(group_name + " blinded window"); + + const Botan::PointGFp& base_point = ec_group.get_base_point(); + + std::vector ws; + + while(mult_timer->under(runtime) && + blinded_mult_timer->under(runtime) && + blinded_var_mult_timer->under(runtime)) + { + const Botan::BigInt scalar(rng(), ec_group.get_p_bits()); + + const Botan::PointGFp r1 = mult_timer->run([&]() { return base_point * scalar; }); + + const Botan::PointGFp r2 = blinded_mult_timer->run( + [&]() { return ec_group.blinded_base_point_multiply(scalar, rng(), ws); }); + + const Botan::PointGFp r3 = blinded_var_mult_timer->run( + [&]() { return ec_group.blinded_var_point_multiply(base_point, scalar, rng(), ws); }); + + BOTAN_ASSERT_EQUAL(r1, r2, "Same point computed by Montgomery and comb"); + BOTAN_ASSERT_EQUAL(r1, r3, "Same point computed by Montgomery and window"); + } + + record_result(mult_timer); + record_result(blinded_mult_timer); + record_result(blinded_var_mult_timer); + } + } + + void bench_os2ecp(const std::vector& groups, const std::chrono::milliseconds runtime) + { + std::unique_ptr uncmp_timer = make_timer("OS2ECP uncompressed"); + std::unique_ptr cmp_timer = make_timer("OS2ECP compressed"); + + for(std::string group_name : groups) + { + const Botan::EC_Group ec_group(group_name); + + while(uncmp_timer->under(runtime) && cmp_timer->under(runtime)) + { + const Botan::BigInt k(rng(), 256); + const Botan::PointGFp p = ec_group.get_base_point() * k; + const std::vector os_cmp = p.encode(Botan::PointGFp::COMPRESSED); + const std::vector os_uncmp = p.encode(Botan::PointGFp::UNCOMPRESSED); + + uncmp_timer->run([&]() { ec_group.OS2ECP(os_uncmp); }); + cmp_timer->run([&]() { ec_group.OS2ECP(os_cmp); }); + } + + record_result(uncmp_timer); + record_result(cmp_timer); + } + } + +#endif + +#if defined(BOTAN_HAS_FPE_FE1) + + void bench_fpe_fe1(const std::chrono::milliseconds runtime) + { + const Botan::BigInt n = 1000000000000000; + + std::unique_ptr enc_timer = make_timer("FPE_FE1 encrypt"); + std::unique_ptr dec_timer = make_timer("FPE_FE1 decrypt"); + + const Botan::SymmetricKey key(rng(), 32); + const std::vector tweak(8); // 8 zeros + + Botan::BigInt x = 1; + + Botan::FPE_FE1 fpe_fe1(n); + fpe_fe1.set_key(key); + + while(enc_timer->under(runtime)) + { + enc_timer->start(); + x = fpe_fe1.encrypt(x, tweak.data(), tweak.size()); + enc_timer->stop(); + } + + for(size_t i = 0; i != enc_timer->events(); ++i) + { + dec_timer->start(); + x = fpe_fe1.decrypt(x, tweak.data(), tweak.size()); + dec_timer->stop(); + } + + BOTAN_ASSERT(x == 1, "FPE works"); + + record_result(enc_timer); + record_result(dec_timer); + } +#endif + +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) + + void bench_rfc3394(const std::chrono::milliseconds runtime) + { + std::unique_ptr wrap_timer = make_timer("RFC3394 AES-256 key wrap"); + std::unique_ptr unwrap_timer = make_timer("RFC3394 AES-256 key unwrap"); + + const Botan::SymmetricKey kek(rng(), 32); + Botan::secure_vector key(64, 0); + + while(wrap_timer->under(runtime)) + { + wrap_timer->start(); + key = Botan::rfc3394_keywrap(key, kek); + wrap_timer->stop(); + + unwrap_timer->start(); + key = Botan::rfc3394_keyunwrap(key, kek); + unwrap_timer->stop(); + + key[0] += 1; + } + + record_result(wrap_timer); + record_result(unwrap_timer); + } +#endif + +#if defined(BOTAN_HAS_BIGINT) + + void bench_mp_mul(const std::chrono::milliseconds runtime) + { + std::chrono::milliseconds runtime_per_size = runtime; + for(size_t bits : { 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096 }) + { + std::unique_ptr mul_timer = make_timer("BigInt mul " + std::to_string(bits)); + std::unique_ptr sqr_timer = make_timer("BigInt sqr " + std::to_string(bits)); + + const Botan::BigInt y(rng(), bits); + Botan::secure_vector ws; + + while(mul_timer->under(runtime_per_size)) + { + Botan::BigInt x(rng(), bits); + + sqr_timer->start(); + x.square(ws); + sqr_timer->stop(); + + x.mask_bits(bits); + + mul_timer->start(); + x.mul(y, ws); + mul_timer->stop(); + } + + record_result(mul_timer); + record_result(sqr_timer); + } + + } + + void bench_mp_div(const std::chrono::milliseconds runtime) + { + std::chrono::milliseconds runtime_per_size = runtime; + + for(size_t n_bits : { 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096 }) + { + const size_t q_bits = n_bits / 2; + const std::string bit_descr = std::to_string(n_bits) + "/" + std::to_string(q_bits); + + std::unique_ptr div_timer = make_timer("BigInt div " + bit_descr); + std::unique_ptr ct_div_timer = make_timer("BigInt ct_div " + bit_descr); + + Botan::BigInt y; + Botan::BigInt x; + Botan::secure_vector ws; + + Botan::BigInt q1, r1, q2, r2; + + while(ct_div_timer->under(runtime_per_size)) + { + x.randomize(rng(), n_bits); + y.randomize(rng(), q_bits); + + div_timer->start(); + Botan::vartime_divide(x, y, q1, r1); + div_timer->stop(); + + ct_div_timer->start(); + Botan::ct_divide(x, y, q2, r2); + ct_div_timer->stop(); + + BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok"); + BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok"); + } + + record_result(div_timer); + record_result(ct_div_timer); + } + } + + void bench_mp_div10(const std::chrono::milliseconds runtime) + { + std::chrono::milliseconds runtime_per_size = runtime; + + for(size_t n_bits : { 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096 }) + { + const std::string bit_descr = std::to_string(n_bits) + "/10"; + + std::unique_ptr div_timer = make_timer("BigInt div " + bit_descr); + std::unique_ptr ct_div_timer = make_timer("BigInt ct_div " + bit_descr); + + Botan::BigInt x; + Botan::secure_vector ws; + + const Botan::BigInt ten(10); + Botan::BigInt q1, r1, q2; + uint8_t r2; + + while(ct_div_timer->under(runtime_per_size)) + { + x.randomize(rng(), n_bits); + + div_timer->start(); + Botan::vartime_divide(x, ten, q1, r1); + div_timer->stop(); + + ct_div_timer->start(); + Botan::ct_divide_u8(x, 10, q2, r2); + ct_div_timer->stop(); + + BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok"); + BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok"); + } + + record_result(div_timer); + record_result(ct_div_timer); + } + } + +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + + void bench_modexp(const std::chrono::milliseconds runtime) + { + for(size_t group_bits : { 1024, 1536, 2048, 3072, 4096 }) + { + const std::string group_bits_str = std::to_string(group_bits); + const Botan::DL_Group group("modp/srp/" + group_bits_str); + + const size_t e_bits = Botan::dl_exponent_size(group_bits); + const size_t f_bits = group_bits - 1; + + const Botan::BigInt random_e(rng(), e_bits); + const Botan::BigInt random_f(rng(), f_bits); + + std::unique_ptr e_timer = make_timer(group_bits_str + " short exponent"); + std::unique_ptr f_timer = make_timer(group_bits_str + " full exponent"); + + while(f_timer->under(runtime)) + { + e_timer->run([&]() { group.power_g_p(random_e); }); + f_timer->run([&]() { group.power_g_p(random_f); }); + } + + record_result(e_timer); + record_result(f_timer); + } + } +#endif + +#if defined(BOTAN_HAS_NUMBERTHEORY) + void bench_nistp_redc(const std::chrono::milliseconds runtime) + { + Botan::secure_vector ws; + + std::unique_ptr p192_timer = make_timer("P-192 redc"); + Botan::BigInt r192(rng(), 192*2 - 1); + while(p192_timer->under(runtime)) + { + Botan::BigInt r = r192; + p192_timer->run([&]() { Botan::redc_p192(r, ws); }); + r192 += 1; + } + record_result(p192_timer); + + std::unique_ptr p224_timer = make_timer("P-224 redc"); + Botan::BigInt r224(rng(), 224*2 - 1); + while(p224_timer->under(runtime)) + { + Botan::BigInt r = r224; + p224_timer->run([&]() { Botan::redc_p224(r, ws); }); + r224 += 1; + } + record_result(p224_timer); + + std::unique_ptr p256_timer = make_timer("P-256 redc"); + Botan::BigInt r256(rng(), 256*2 - 1); + while(p256_timer->under(runtime)) + { + Botan::BigInt r = r256; + p256_timer->run([&]() { Botan::redc_p256(r, ws); }); + r256 += 1; + } + record_result(p256_timer); + + std::unique_ptr p384_timer = make_timer("P-384 redc"); + Botan::BigInt r384(rng(), 384*2 - 1); + while(p384_timer->under(runtime)) + { + Botan::BigInt r = r384; + p384_timer->run([&]() { Botan::redc_p384(r384, ws); }); + r384 += 1; + } + record_result(p384_timer); + + std::unique_ptr p521_timer = make_timer("P-521 redc"); + Botan::BigInt r521(rng(), 521*2 - 1); + while(p521_timer->under(runtime)) + { + Botan::BigInt r = r521; + p521_timer->run([&]() { Botan::redc_p521(r521, ws); }); + r521 += 1; + } + record_result(p521_timer); + } + + void bench_bn_redc(const std::chrono::milliseconds runtime) + { + for(size_t bitsize : { 512, 1024, 2048, 4096 }) + { + Botan::BigInt p(rng(), bitsize); + + std::string bit_str = std::to_string(bitsize); + std::unique_ptr barrett_timer = make_timer("Barrett-" + bit_str); + std::unique_ptr schoolbook_timer = make_timer("Schoolbook-" + bit_str); + + Botan::Modular_Reducer mod_p(p); + + while(schoolbook_timer->under(runtime)) + { + const Botan::BigInt x(rng(), p.bits() * 2 - 2); + + const Botan::BigInt r1 = barrett_timer->run( + [&] { return mod_p.reduce(x); }); + const Botan::BigInt r2 = schoolbook_timer->run( + [&] { return x % p; }); + + BOTAN_ASSERT(r1 == r2, "Computed different results"); + } + + record_result(barrett_timer); + record_result(schoolbook_timer); + } + } + + void bench_inverse_mod(const std::chrono::milliseconds runtime) + { + for(size_t bits : { 256, 384, 512, 1024, 2048 }) + { + const std::string bit_str = std::to_string(bits); + + std::unique_ptr timer = make_timer("inverse_mod-" + bit_str); + + while(timer->under(runtime)) + { + const Botan::BigInt x(rng(), bits - 1); + Botan::BigInt mod(rng(), bits); + + const Botan::BigInt x_inv = timer->run( + [&] { return Botan::inverse_mod(x, mod); }); + + if(x_inv == 0) + { + const Botan::BigInt g = gcd(x, mod); + BOTAN_ASSERT(g != 1, "Inversion only fails if gcd(x, mod) > 1"); + } + else + { + const Botan::BigInt check = (x_inv*x) % mod; + BOTAN_ASSERT_EQUAL(check, 1, "Const time inversion correct"); + } + } + + record_result(timer); + } + } + + void bench_primality_tests(const std::chrono::milliseconds runtime) + { + for(size_t bits : { 256, 512, 1024 }) + { + std::unique_ptr mr_timer = make_timer("Miller-Rabin-" + std::to_string(bits)); + std::unique_ptr bpsw_timer = make_timer("Bailie-PSW-" + std::to_string(bits)); + std::unique_ptr lucas_timer = make_timer("Lucas-" + std::to_string(bits)); + + Botan::BigInt n = Botan::random_prime(rng(), bits); + + while(lucas_timer->under(runtime)) + { + Botan::Modular_Reducer mod_n(n); + + mr_timer->run([&]() { + return Botan::is_miller_rabin_probable_prime(n, mod_n, rng(), 2); }); + + bpsw_timer->run([&]() { + return Botan::is_bailie_psw_probable_prime(n, mod_n); }); + + lucas_timer->run([&]() { + return Botan::is_lucas_probable_prime(n, mod_n); }); + + n += 2; + } + + record_result(mr_timer); + record_result(bpsw_timer); + record_result(lucas_timer); + } + } + + void bench_random_prime(const std::chrono::milliseconds runtime) + { + const size_t coprime = 65537; // simulates RSA key gen + + for(size_t bits : { 256, 384, 512, 768, 1024, 1536 }) + { + std::unique_ptr genprime_timer = make_timer("random_prime " + std::to_string(bits)); + std::unique_ptr gensafe_timer = make_timer("random_safe_prime " + std::to_string(bits)); + std::unique_ptr is_prime_timer = make_timer("is_prime " + std::to_string(bits)); + + while(gensafe_timer->under(runtime)) + { + const Botan::BigInt p = genprime_timer->run([&] + { + return Botan::random_prime(rng(), bits, coprime); + }); + + if(!is_prime_timer->run([&] { return Botan::is_prime(p, rng(), 64, true); })) + { + error_output() << "Generated prime " << p << " which failed a primality test"; + } + + const Botan::BigInt sg = gensafe_timer->run([&] + { + return Botan::random_safe_prime(rng(), bits); + }); + + if(!is_prime_timer->run([&] { return Botan::is_prime(sg, rng(), 64, true); })) + { + error_output() << "Generated safe prime " << sg << " which failed a primality test"; + } + + if(!is_prime_timer->run([&] { return Botan::is_prime(sg / 2, rng(), 64, true); })) + { + error_output() << "Generated prime " << sg/2 << " which failed a primality test"; + } + + // Now test p+2, p+4, ... which may or may not be prime + for(size_t i = 2; i <= 64; i += 2) + { + is_prime_timer->run([&]() { Botan::is_prime(p + i, rng(), 64, true); }); + } + } + + record_result(genprime_timer); + record_result(gensafe_timer); + record_result(is_prime_timer); + } + } +#endif + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + void bench_pk_enc( + const Botan::Private_Key& key, + const std::string& nm, + const std::string& provider, + const std::string& padding, + std::chrono::milliseconds msec) + { + std::vector plaintext, ciphertext; + + Botan::PK_Encryptor_EME enc(key, rng(), padding, provider); + Botan::PK_Decryptor_EME dec(key, rng(), padding, provider); + + std::unique_ptr enc_timer = make_timer(nm + " " + padding, provider, "encrypt"); + std::unique_ptr dec_timer = make_timer(nm + " " + padding, provider, "decrypt"); + + while(enc_timer->under(msec) || dec_timer->under(msec)) + { + // Generate a new random ciphertext to decrypt + if(ciphertext.empty() || enc_timer->under(msec)) + { + rng().random_vec(plaintext, enc.maximum_input_size()); + ciphertext = enc_timer->run([&]() { return enc.encrypt(plaintext, rng()); }); + } + + if(dec_timer->under(msec)) + { + const auto dec_pt = dec_timer->run([&]() { return dec.decrypt(ciphertext); }); + + if(!(dec_pt == plaintext)) // sanity check + { + error_output() << "Bad roundtrip in PK encrypt/decrypt bench\n"; + } + } + } + + record_result(enc_timer); + record_result(dec_timer); + } + + void bench_pk_ka(const std::string& algo, + const std::string& nm, + const std::string& params, + const std::string& provider, + std::chrono::milliseconds msec) + { + const std::string kdf = "KDF2(SHA-256)"; // arbitrary choice + + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + std::unique_ptr key1(keygen_timer->run([&] + { + return Botan::create_private_key(algo, rng(), params); + })); + std::unique_ptr key2(keygen_timer->run([&] + { + return Botan::create_private_key(algo, rng(), params); + })); + + record_result(keygen_timer); + + const Botan::PK_Key_Agreement_Key& ka_key1 = dynamic_cast(*key1); + const Botan::PK_Key_Agreement_Key& ka_key2 = dynamic_cast(*key2); + + Botan::PK_Key_Agreement ka1(ka_key1, rng(), kdf, provider); + Botan::PK_Key_Agreement ka2(ka_key2, rng(), kdf, provider); + + const std::vector ka1_pub = ka_key1.public_value(); + const std::vector ka2_pub = ka_key2.public_value(); + + std::unique_ptr ka_timer = make_timer(nm, provider, "key agreements"); + + while(ka_timer->under(msec)) + { + Botan::SymmetricKey symkey1 = ka_timer->run([&]() { return ka1.derive_key(32, ka2_pub); }); + Botan::SymmetricKey symkey2 = ka_timer->run([&]() { return ka2.derive_key(32, ka1_pub); }); + + if(symkey1 != symkey2) + { + error_output() << "Key agreement mismatch in PK bench\n"; + } + } + + record_result(ka_timer); + } + + void bench_pk_kem(const Botan::Private_Key& key, + const std::string& nm, + const std::string& provider, + const std::string& kdf, + std::chrono::milliseconds msec) + { + Botan::PK_KEM_Decryptor dec(key, rng(), kdf, provider); + Botan::PK_KEM_Encryptor enc(key, rng(), kdf, provider); + + std::unique_ptr kem_enc_timer = make_timer(nm, provider, "KEM encrypt"); + std::unique_ptr kem_dec_timer = make_timer(nm, provider, "KEM decrypt"); + + while(kem_enc_timer->under(msec) && kem_dec_timer->under(msec)) + { + Botan::secure_vector encap_key, enc_shared_key; + Botan::secure_vector salt = rng().random_vec(16); + + kem_enc_timer->start(); + enc.encrypt(encap_key, enc_shared_key, 64, rng(), salt); + kem_enc_timer->stop(); + + kem_dec_timer->start(); + Botan::secure_vector dec_shared_key = dec.decrypt(encap_key, 64, salt); + kem_dec_timer->stop(); + + if(enc_shared_key != dec_shared_key) + { + error_output() << "KEM mismatch in PK bench\n"; + } + } + + record_result(kem_enc_timer); + record_result(kem_dec_timer); + } + + void bench_pk_sig_ecc(const std::string& algo, + const std::string& emsa, + const std::string& provider, + const std::vector& params, + std::chrono::milliseconds msec) + { + for(std::string grp : params) + { + const std::string nm = grp.empty() ? algo : (algo + "-" + grp); + + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + std::unique_ptr key(keygen_timer->run([&] + { + return Botan::create_private_key(algo, rng(), grp); + })); + + record_result(keygen_timer); + bench_pk_sig(*key, nm, provider, emsa, msec); + } + } + + size_t bench_pk_sig(const Botan::Private_Key& key, + const std::string& nm, + const std::string& provider, + const std::string& padding, + std::chrono::milliseconds msec) + { + std::vector message, signature, bad_signature; + + Botan::PK_Signer sig(key, rng(), padding, Botan::IEEE_1363, provider); + Botan::PK_Verifier ver(key, padding, Botan::IEEE_1363, provider); + + std::unique_ptr sig_timer = make_timer(nm + " " + padding, provider, "sign"); + std::unique_ptr ver_timer = make_timer(nm + " " + padding, provider, "verify"); + + size_t invalid_sigs = 0; + + while(ver_timer->under(msec) || sig_timer->under(msec)) + { + if(signature.empty() || sig_timer->under(msec)) + { + /* + Length here is kind of arbitrary, but 48 bytes fits into a single + hash block so minimizes hashing overhead versus the PK op itself. + */ + rng().random_vec(message, 48); + + signature = sig_timer->run([&]() { return sig.sign_message(message, rng()); }); + + bad_signature = signature; + bad_signature[rng().next_byte() % bad_signature.size()] ^= rng().next_nonzero_byte(); + } + + if(ver_timer->under(msec)) + { + const bool verified = ver_timer->run([&] + { + return ver.verify_message(message, signature); + }); + + if(!verified) + { + invalid_sigs += 1; + } + + const bool verified_bad = ver_timer->run([&] + { + return ver.verify_message(message, bad_signature); + }); + + if(verified_bad) + { + error_output() << "Bad signature accepted in PK signature bench\n"; + } + } + } + + if(invalid_sigs > 0) + error_output() << invalid_sigs << " generated signatures rejected in PK signature bench\n"; + + const size_t events = static_cast(std::min(sig_timer->events(), ver_timer->events())); + + record_result(sig_timer); + record_result(ver_timer); + + return events; + } +#endif + +#if defined(BOTAN_HAS_RSA) + void bench_rsa_keygen(const std::string& provider, + std::chrono::milliseconds msec) + { + for(size_t keylen : { 1024, 2048, 3072, 4096 }) + { + const std::string nm = "RSA-" + std::to_string(keylen); + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + while(keygen_timer->under(msec)) + { + std::unique_ptr key(keygen_timer->run([&] { + return Botan::create_private_key("RSA", rng(), std::to_string(keylen)); + })); + + BOTAN_ASSERT(key->check_key(rng(), true), "Key is ok"); + } + + record_result(keygen_timer); + } + } + + void bench_rsa(const std::string& provider, + std::chrono::milliseconds msec) + { + for(size_t keylen : { 1024, 2048, 3072, 4096 }) + { + const std::string nm = "RSA-" + std::to_string(keylen); + + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + std::unique_ptr key(keygen_timer->run([&] + { + return Botan::create_private_key("RSA", rng(), std::to_string(keylen)); + })); + + record_result(keygen_timer); + + // Using PKCS #1 padding so OpenSSL provider can play along + bench_pk_sig(*key, nm, provider, "EMSA-PKCS1-v1_5(SHA-256)", msec); + + //bench_pk_sig(*key, nm, provider, "PSSR(SHA-256)", msec); + //bench_pk_enc(*key, nm, provider, "EME-PKCS1-v1_5", msec); + //bench_pk_enc(*key, nm, provider, "OAEP(SHA-1)", msec); + } + } +#endif + +#if defined(BOTAN_HAS_ECDSA) + void bench_ecdsa(const std::vector& groups, + const std::string& provider, + std::chrono::milliseconds msec) + { + return bench_pk_sig_ecc("ECDSA", "EMSA1(SHA-256)", provider, groups, msec); + } + + void bench_ecdsa_recovery(const std::vector& groups, + const std::string&, + std::chrono::milliseconds msec) + { + for(std::string group_name : groups) + { + Botan::EC_Group group(group_name); + std::unique_ptr recovery_timer = make_timer("ECDSA recovery " + group_name); + + while(recovery_timer->under(msec)) + { + Botan::ECDSA_PrivateKey key(rng(), group); + + std::vector message(group.get_order_bits() / 8); + rng().randomize(message.data(), message.size()); + + Botan::PK_Signer signer(key, rng(), "Raw"); + signer.update(message); + std::vector signature = signer.signature(rng()); + + Botan::PK_Verifier verifier(key, "Raw", Botan::IEEE_1363, "base"); + verifier.update(message); + BOTAN_ASSERT(verifier.check_signature(signature), "Valid signature"); + + Botan::BigInt r(signature.data(), signature.size()/2); + Botan::BigInt s(signature.data() + signature.size()/2, signature.size()/2); + + const uint8_t v = key.recovery_param(message, r, s); + + recovery_timer->run([&]() { + Botan::ECDSA_PublicKey pubkey(group, message, r, s, v); + BOTAN_ASSERT(pubkey.public_point() == key.public_point(), "Recovered public key"); + }); + } + + record_result(recovery_timer); + } + + } + +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + void bench_eckcdsa(const std::vector& groups, + const std::string& provider, + std::chrono::milliseconds msec) + { + return bench_pk_sig_ecc("ECKCDSA", "EMSA1(SHA-256)", provider, groups, msec); + } +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + void bench_gost_3410(const std::string& provider, + std::chrono::milliseconds msec) + { + return bench_pk_sig_ecc("GOST-34.10", "EMSA1(GOST-34.11)", provider, {"gost_256A"}, msec); + } +#endif + +#if defined(BOTAN_HAS_SM2) + void bench_sm2(const std::vector& groups, + const std::string& provider, + std::chrono::milliseconds msec) + { + return bench_pk_sig_ecc("SM2_Sig", "SM3", provider, groups, msec); + } +#endif + +#if defined(BOTAN_HAS_ECGDSA) + void bench_ecgdsa(const std::vector& groups, + const std::string& provider, + std::chrono::milliseconds msec) + { + return bench_pk_sig_ecc("ECGDSA", "EMSA1(SHA-256)", provider, groups, msec); + } +#endif + +#if defined(BOTAN_HAS_ED25519) + void bench_ed25519(const std::string& provider, + std::chrono::milliseconds msec) + { + return bench_pk_sig_ecc("Ed25519", "Pure", provider, std::vector{""}, msec); + } +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + void bench_dh(const std::string& provider, + std::chrono::milliseconds msec) + { + for(size_t bits : { 1024, 1536, 2048, 3072, 4096, 6144, 8192 }) + { + bench_pk_ka("DH", + "DH-" + std::to_string(bits), + "modp/ietf/" + std::to_string(bits), + provider, msec); + } + } +#endif + +#if defined(BOTAN_HAS_DSA) + void bench_dsa(const std::string& provider, std::chrono::milliseconds msec) + { + for(size_t bits : { 1024, 2048, 3072 }) + { + const std::string nm = "DSA-" + std::to_string(bits); + + const std::string params = + (bits == 1024) ? "dsa/jce/1024" : ("dsa/botan/" + std::to_string(bits)); + + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + std::unique_ptr key(keygen_timer->run([&] + { + return Botan::create_private_key("DSA", rng(), params); + })); + + record_result(keygen_timer); + + bench_pk_sig(*key, nm, provider, "EMSA1(SHA-256)", msec); + } + } +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + void bench_elgamal(const std::string& provider, std::chrono::milliseconds msec) + { + for(size_t keylen : { 1024, 2048, 3072, 4096 }) + { + const std::string nm = "ElGamal-" + std::to_string(keylen); + + const std::string params = "modp/ietf/" + std::to_string(keylen); + + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + std::unique_ptr key(keygen_timer->run([&] + { + return Botan::create_private_key("ElGamal", rng(), params); + })); + + record_result(keygen_timer); + + bench_pk_enc(*key, nm, provider, "EME-PKCS1-v1_5", msec); + } + } +#endif + +#if defined(BOTAN_HAS_ECDH) + void bench_ecdh(const std::vector& groups, + const std::string& provider, + std::chrono::milliseconds msec) + { + for(std::string grp : groups) + { + bench_pk_ka("ECDH", "ECDH-" + grp, grp, provider, msec); + } + } +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + void bench_curve25519(const std::string& provider, + std::chrono::milliseconds msec) + { + bench_pk_ka("Curve25519", "Curve25519", "", provider, msec); + } +#endif + +#if defined(BOTAN_HAS_MCELIECE) + void bench_mceliece(const std::string& provider, + std::chrono::milliseconds msec) + { + /* + SL=80 n=1632 t=33 - 59 KB pubkey 140 KB privkey + SL=107 n=2480 t=45 - 128 KB pubkey 300 KB privkey + SL=128 n=2960 t=57 - 195 KB pubkey 459 KB privkey + SL=147 n=3408 t=67 - 265 KB pubkey 622 KB privkey + SL=191 n=4624 t=95 - 516 KB pubkey 1234 KB privkey + SL=256 n=6624 t=115 - 942 KB pubkey 2184 KB privkey + */ + + const std::vector> mce_params = + { + { 2480, 45 }, + { 2960, 57 }, + { 3408, 67 }, + { 4624, 95 }, + { 6624, 115 } + }; + + for(auto params : mce_params) + { + size_t n = params.first; + size_t t = params.second; + + const std::string nm = "McEliece-" + std::to_string(n) + "," + std::to_string(t) + + " (WF=" + std::to_string(Botan::mceliece_work_factor(n, t)) + ")"; + + std::unique_ptr keygen_timer = make_timer(nm, provider, "keygen"); + + std::unique_ptr key(keygen_timer->run([&] + { + return new Botan::McEliece_PrivateKey(rng(), n, t); + })); + + record_result(keygen_timer); + bench_pk_kem(*key, nm, provider, "KDF2(SHA-256)", msec); + } + } +#endif + +#if defined(BOTAN_HAS_XMSS_RFC8391) + void bench_xmss(const std::string& provider, + std::chrono::milliseconds msec) + { + /* + We only test H10 signatures here since already they are quite slow (a + few seconds per signature). On a fast machine, H16 signatures take 1-2 + minutes to generate and H20 signatures take 5-10 minutes to generate + */ + std::vector xmss_params + { + "XMSS-SHA2_10_256", + "XMSS-SHAKE_10_256", + "XMSS-SHA2_10_512", + "XMSS-SHAKE_10_512", + }; + + for(std::string params : xmss_params) + { + std::unique_ptr keygen_timer = make_timer(params, provider, "keygen"); + + std::unique_ptr key(keygen_timer->run([&] + { + return Botan::create_private_key("XMSS", rng(), params); + })); + + record_result(keygen_timer); + if(bench_pk_sig(*key, params, provider, "", msec) == 1) + break; + } + } +#endif + +#if defined(BOTAN_HAS_POLY_DBL) + void bench_poly_dbl(std::chrono::milliseconds msec) + { + for(size_t sz : { 8, 16, 24, 32, 64, 128 }) + { + std::unique_ptr be_timer = make_timer("poly_dbl_be_" + std::to_string(sz)); + std::unique_ptr le_timer = make_timer("poly_dbl_le_" + std::to_string(sz)); + + std::vector buf(sz); + rng().randomize(buf.data(), sz); + + be_timer->run_until_elapsed(msec, [&]() { Botan::poly_double_n(buf.data(), buf.data(), sz); }); + le_timer->run_until_elapsed(msec, [&]() { Botan::poly_double_n_le(buf.data(), buf.data(), sz); }); + + record_result(be_timer); + record_result(le_timer); + } + } +#endif + +#if defined(BOTAN_HAS_BCRYPT) + + void bench_bcrypt() + { + const std::string password = "not a very good password"; + + for(uint8_t work_factor = 4; work_factor <= 14; ++work_factor) + { + std::unique_ptr timer = make_timer("bcrypt wf=" + std::to_string(work_factor)); + + timer->run([&] { + Botan::generate_bcrypt(password, rng(), work_factor); + }); + + record_result(timer); + } + } +#endif + +#if defined(BOTAN_HAS_PASSHASH9) + + void bench_passhash9() + { + const std::string password = "not a very good password"; + + for(uint8_t alg = 0; alg <= 4; ++alg) + { + if(Botan::is_passhash9_alg_supported(alg) == false) + continue; + + for(auto work_factor : { 10, 15 }) + { + std::unique_ptr timer = make_timer("passhash9 alg=" + std::to_string(alg) + + " wf=" + std::to_string(work_factor)); + + timer->run([&] { + Botan::generate_passhash9(password, rng(), static_cast(work_factor), alg); + }); + + record_result(timer); + } + } + } +#endif + +#if defined(BOTAN_HAS_SCRYPT) + + void bench_scrypt(const std::string& /*provider*/, + std::chrono::milliseconds msec) + { + + for(size_t N : { 8192, 16384, 32768, 65536 }) + { + for(size_t r : { 1, 8, 16 }) + { + for(size_t p : { 1, 4 }) + { + std::unique_ptr scrypt_timer = make_timer( + "scrypt-" + std::to_string(N) + "-" + + std::to_string(r) + "-" + std::to_string(p) + + " (" + std::to_string(Botan::scrypt_memory_usage(N, r, p) / (1024*1024)) + " MiB)"); + + uint8_t out[64]; + uint8_t salt[8]; + rng().randomize(salt, sizeof(salt)); + + while(scrypt_timer->under(msec)) + { + scrypt_timer->run([&] { + Botan::scrypt(out, sizeof(out), "password", + salt, sizeof(salt), N, r, p); + }); + } + + record_result(scrypt_timer); + + if(scrypt_timer->events() == 1) + break; + } + } + } + + } + +#endif + +#if defined(BOTAN_HAS_ARGON2) + + void bench_argon2(const std::string& /*provider*/, + std::chrono::milliseconds msec) + { + const uint8_t mode = 2; // Argon2id + + for(size_t M : { 8*1024, 64*1024, 256*1024 }) + { + for(size_t t : { 1, 2, 4 }) + { + for(size_t p : { 1 }) + { + std::unique_ptr timer = make_timer( + "Argon2id M=" + std::to_string(M) + " t=" + std::to_string(t) + " p=" + std::to_string(p)); + + uint8_t out[64]; + uint8_t salt[16]; + rng().randomize(salt, sizeof(salt)); + + while(timer->under(msec)) + { + timer->run([&] { + Botan::argon2(out, sizeof(out), "password", 8, + salt, sizeof(salt), nullptr, 0, nullptr, 0, + mode, p, M, t); + }); + } + + record_result(timer); + } + } + } + } + +#endif + +#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA_RNG) + void bench_newhope(const std::string& /*provider*/, + std::chrono::milliseconds msec) + { + const std::string nm = "NEWHOPE"; + + std::unique_ptr keygen_timer = make_timer(nm, "", "keygen"); + std::unique_ptr shareda_timer = make_timer(nm, "", "shareda"); + std::unique_ptr sharedb_timer = make_timer(nm, "", "sharedb"); + + Botan::ChaCha_RNG nh_rng(Botan::secure_vector(32)); + + while(sharedb_timer->under(msec)) + { + std::vector send_a(Botan::NEWHOPE_SENDABYTES), send_b(Botan::NEWHOPE_SENDBBYTES); + std::vector shared_a(32), shared_b(32); + + Botan::newhope_poly sk_a; + + keygen_timer->start(); + Botan::newhope_keygen(send_a.data(), &sk_a, nh_rng); + keygen_timer->stop(); + + sharedb_timer->start(); + Botan::newhope_sharedb(shared_b.data(), send_b.data(), send_a.data(), nh_rng); + sharedb_timer->stop(); + + shareda_timer->start(); + Botan::newhope_shareda(shared_a.data(), &sk_a, send_b.data()); + shareda_timer->stop(); + + BOTAN_ASSERT(shared_a == shared_b, "Same derived key"); + } + + record_result(keygen_timer); + record_result(shareda_timer); + record_result(sharedb_timer); + } +#endif + + }; + +BOTAN_REGISTER_COMMAND("speed", Speed); + +} diff --git a/comm/third_party/botan/src/cli/timing_tests.cpp b/comm/third_party/botan/src/cli/timing_tests.cpp new file mode 100644 index 0000000000..a9904ae2e8 --- /dev/null +++ b/comm/third_party/botan/src/cli/timing_tests.cpp @@ -0,0 +1,617 @@ +/* +* Timing Analysis Tests +* +* These tests are not for performance, but verifying that two inputs are not handled +* in a way that is vulnerable to simple timing attacks. +* +* Produces output which can be analyzed with the Mona reporting library +* +* $ git clone https://github.com/seecurity/mona-timing-report.git +* $ cd mona-timing-report && ant +* $ java -jar ReportingTool.jar --lowerBound=0.4 --upperBound=0.5 --inputFile=$file --name=$file +* +* (C) 2016 Juraj Somorovsky - juraj.somorovsky@hackmanit.de +* (C) 2017 Neverhub +* (C) 2017,2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include +#include +#include + +#include +#include + +#if defined(BOTAN_HAS_BIGINT) + #include +#endif + +#if defined(BOTAN_HAS_NUMBERTHEORY) + #include +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + #include +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + #include +#endif + +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_RAW) + #include + #include +#endif + +#if defined(BOTAN_HAS_TLS_CBC) + #include + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include + #include +#endif + +namespace Botan_CLI { + +typedef uint64_t ticks; + +class Timing_Test + { + public: + Timing_Test() + { + /* + A constant seed is ok here since the timing test rng just needs to be + "random" but not cryptographically secure - even std::rand() would be ok. + */ + const std::string drbg_seed(64, 'A'); + m_rng = cli_make_rng("", drbg_seed); // throws if it can't find anything to use + } + + virtual ~Timing_Test() = default; + + std::vector> execute_evaluation( + const std::vector& inputs, + size_t warmup_runs, + size_t measurement_runs); + + virtual std::vector prepare_input(const std::string& input) + { + return Botan::hex_decode(input); + } + + virtual ticks measure_critical_function(const std::vector& input) = 0; + + protected: + static ticks get_ticks() + { + // Returns CPU counter or best approximation (monotonic clock of some kind) + //return Botan::OS::get_high_resolution_clock(); + return Botan::OS::get_system_timestamp_ns(); + } + + Botan::RandomNumberGenerator& timing_test_rng() + { + return (*m_rng); + } + + private: + std::unique_ptr m_rng; + }; + +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_PKCS1) && defined(BOTAN_HAS_EME_RAW) + +class Bleichenbacker_Timing_Test final : public Timing_Test + { + public: + Bleichenbacker_Timing_Test(size_t keysize) + : m_privkey(timing_test_rng(), keysize) + , m_pubkey(m_privkey) + , m_enc(m_pubkey, timing_test_rng(), "Raw") + , m_dec(m_privkey, timing_test_rng(), "PKCS1v15") {} + + std::vector prepare_input(const std::string& input) override + { + const std::vector input_vector = Botan::hex_decode(input); + const std::vector encrypted = m_enc.encrypt(input_vector, timing_test_rng()); + return encrypted; + } + + ticks measure_critical_function(const std::vector& input) override + { + const ticks start = get_ticks(); + m_dec.decrypt_or_random(input.data(), m_ctext_length, m_expected_content_size, timing_test_rng()); + const ticks end = get_ticks(); + return (end - start); + } + + private: + const size_t m_expected_content_size = 48; + const size_t m_ctext_length = 256; + Botan::RSA_PrivateKey m_privkey; + Botan::RSA_PublicKey m_pubkey; + Botan::PK_Encryptor_EME m_enc; + Botan::PK_Decryptor_EME m_dec; + }; + +#endif + +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_OAEP) && defined(BOTAN_HAS_EME_RAW) + +/* +* Test Manger OAEP side channel +* +* "A Chosen Ciphertext Attack on RSA Optimal Asymmetric Encryption +* Padding (OAEP) as Standardized in PKCS #1 v2.0" James Manger +* http://archiv.infsec.ethz.ch/education/fs08/secsem/Manger01.pdf +*/ +class Manger_Timing_Test final : public Timing_Test + { + public: + Manger_Timing_Test(size_t keysize) + : m_privkey(timing_test_rng(), keysize) + , m_pubkey(m_privkey) + , m_enc(m_pubkey, timing_test_rng(), m_encrypt_padding) + , m_dec(m_privkey, timing_test_rng(), m_decrypt_padding) {} + + std::vector prepare_input(const std::string& input) override + { + const std::vector input_vector = Botan::hex_decode(input); + const std::vector encrypted = m_enc.encrypt(input_vector, timing_test_rng()); + return encrypted; + } + + ticks measure_critical_function(const std::vector& input) override + { + ticks start = get_ticks(); + try + { + m_dec.decrypt(input.data(), m_ctext_length); + } + catch(Botan::Decoding_Error&) + { + } + ticks end = get_ticks(); + + return (end - start); + } + + private: + const std::string m_encrypt_padding = "Raw"; + const std::string m_decrypt_padding = "EME1(SHA-256)"; + const size_t m_ctext_length = 256; + Botan::RSA_PrivateKey m_privkey; + Botan::RSA_PublicKey m_pubkey; + Botan::PK_Encryptor_EME m_enc; + Botan::PK_Decryptor_EME m_dec; + }; + +#endif + +#if defined(BOTAN_HAS_TLS_CBC) + +/* +* Test handling of countermeasure to the Lucky13 attack +*/ +class Lucky13_Timing_Test final : public Timing_Test + { + public: + Lucky13_Timing_Test(const std::string& mac_name, size_t mac_keylen) + : m_mac_algo(mac_name) + , m_mac_keylen(mac_keylen) + , m_dec(Botan::BlockCipher::create_or_throw("AES-128"), + Botan::MessageAuthenticationCode::create_or_throw("HMAC(" + m_mac_algo + ")"), + 16, m_mac_keylen, Botan::TLS::Protocol_Version::TLS_V11, false) {} + + std::vector prepare_input(const std::string& input) override; + ticks measure_critical_function(const std::vector& input) override; + + private: + const std::string m_mac_algo; + const size_t m_mac_keylen; + Botan::TLS::TLS_CBC_HMAC_AEAD_Decryption m_dec; + }; + +std::vector Lucky13_Timing_Test::prepare_input(const std::string& input) + { + const std::vector input_vector = Botan::hex_decode(input); + const std::vector key(16); + const std::vector iv(16); + + std::unique_ptr enc(Botan::Cipher_Mode::create("AES-128/CBC/NoPadding", Botan::ENCRYPTION)); + enc->set_key(key); + enc->start(iv); + Botan::secure_vector buf(input_vector.begin(), input_vector.end()); + enc->finish(buf); + + return unlock(buf); + } + +ticks Lucky13_Timing_Test::measure_critical_function(const std::vector& input) + { + Botan::secure_vector data(input.begin(), input.end()); + Botan::secure_vector aad(13); + const Botan::secure_vector iv(16); + Botan::secure_vector key(16 + m_mac_keylen); + + m_dec.set_key(unlock(key)); + m_dec.set_ad(unlock(aad)); + m_dec.start(unlock(iv)); + + ticks start = get_ticks(); + try + { + m_dec.finish(data); + } + catch(Botan::TLS::TLS_Exception&) + { + } + ticks end = get_ticks(); + return (end - start); + } + +#endif + +#if defined(BOTAN_HAS_ECDSA) + +class ECDSA_Timing_Test final : public Timing_Test + { + public: + ECDSA_Timing_Test(std::string ecgroup); + + ticks measure_critical_function(const std::vector& input) override; + + private: + const Botan::EC_Group m_group; + const Botan::ECDSA_PrivateKey m_privkey; + const Botan::BigInt& m_x; + std::vector m_ws; + Botan::BigInt m_b, m_b_inv; + }; + +ECDSA_Timing_Test::ECDSA_Timing_Test(std::string ecgroup) + : m_group(ecgroup) + , m_privkey(timing_test_rng(), m_group) + , m_x(m_privkey.private_value()) + { + m_b = m_group.random_scalar(timing_test_rng()); + m_b_inv = m_group.inverse_mod_order(m_b); + } + +ticks ECDSA_Timing_Test::measure_critical_function(const std::vector& input) + { + const Botan::BigInt k(input.data(), input.size()); + Botan::BigInt m(5); // fixed message to minimize noise + + ticks start = get_ticks(); + + // the following ECDSA operations involve and should not leak any information about k + const Botan::BigInt r = m_group.mod_order( + m_group.blinded_base_point_multiply_x(k, timing_test_rng(), m_ws)); + const Botan::BigInt k_inv = m_group.inverse_mod_order(k); + + m_b = m_group.square_mod_order(m_b); + m_b_inv = m_group.square_mod_order(m_b_inv); + + m = m_group.multiply_mod_order(m_b, m_group.mod_order(m)); + const Botan::BigInt xr_m = m_group.mod_order(m_group.multiply_mod_order(m_x, m_b, r) + m); + + const Botan::BigInt s = m_group.multiply_mod_order(k_inv, xr_m, m_b_inv); + + BOTAN_UNUSED(r, s); + + ticks end = get_ticks(); + + return (end - start); + } + +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + +class ECC_Mul_Timing_Test final : public Timing_Test + { + public: + ECC_Mul_Timing_Test(std::string ecgroup) : + m_group(ecgroup) + {} + + ticks measure_critical_function(const std::vector& input) override; + + private: + const Botan::EC_Group m_group; + std::vector m_ws; + }; + +ticks ECC_Mul_Timing_Test::measure_critical_function(const std::vector& input) + { + const Botan::BigInt k(input.data(), input.size()); + + ticks start = get_ticks(); + + const Botan::PointGFp k_times_P = m_group.blinded_base_point_multiply(k, timing_test_rng(), m_ws); + + ticks end = get_ticks(); + + return (end - start); + } + +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + +class Powmod_Timing_Test final : public Timing_Test + { + public: + Powmod_Timing_Test(const std::string& dl_group) : m_group(dl_group) + { + } + + ticks measure_critical_function(const std::vector& input) override; + private: + Botan::DL_Group m_group; + }; + +ticks Powmod_Timing_Test::measure_critical_function(const std::vector& input) + { + const Botan::BigInt x(input.data(), input.size()); + const size_t max_x_bits = m_group.p_bits(); + + ticks start = get_ticks(); + + const Botan::BigInt g_x_p = m_group.power_g_p(x, max_x_bits); + + ticks end = get_ticks(); + + return (end - start); + } + +#endif + +#if defined(BOTAN_HAS_NUMBERTHEORY) + +class Invmod_Timing_Test final : public Timing_Test + { + public: + Invmod_Timing_Test(size_t p_bits) + { + m_p = Botan::random_prime(timing_test_rng(), p_bits); + } + + ticks measure_critical_function(const std::vector& input) override; + + private: + Botan::BigInt m_p; + }; + +ticks Invmod_Timing_Test::measure_critical_function(const std::vector& input) + { + const Botan::BigInt k(input.data(), input.size()); + + ticks start = get_ticks(); + + const Botan::BigInt inv = inverse_mod(k, m_p); + + ticks end = get_ticks(); + + return (end - start); + } + +#endif + +std::vector> Timing_Test::execute_evaluation( + const std::vector& raw_inputs, + size_t warmup_runs, size_t measurement_runs) + { + std::vector> all_results(raw_inputs.size()); + std::vector> inputs(raw_inputs.size()); + + for(auto& result : all_results) + { + result.reserve(measurement_runs); + } + + for(size_t i = 0; i != inputs.size(); ++i) + { + inputs[i] = prepare_input(raw_inputs[i]); + } + + // arbitrary upper bounds of 1 and 10 million resp + if(warmup_runs > 1000000 || measurement_runs > 100000000) + { + throw CLI_Error("Requested execution counts too large, rejecting"); + } + + size_t total_runs = 0; + std::vector results(inputs.size()); + + while(total_runs < (warmup_runs + measurement_runs)) + { + for(size_t i = 0; i != inputs.size(); ++i) + { + results[i] = measure_critical_function(inputs[i]); + } + + total_runs++; + + if(total_runs > warmup_runs) + { + for(size_t i = 0; i != results.size(); ++i) + { + all_results[i].push_back(results[i]); + } + } + } + + return all_results; + } + +class Timing_Test_Command final : public Command + { + public: + Timing_Test_Command() + : Command("timing_test test_type --test-data-file= --test-data-dir=src/tests/data/timing " + "--warmup-runs=5000 --measurement-runs=50000") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Run various timing side channel tests"; + } + + void go() override + { + const std::string test_type = get_arg("test_type"); + const size_t warmup_runs = get_arg_sz("warmup-runs"); + const size_t measurement_runs = get_arg_sz("measurement-runs"); + + std::unique_ptr test = lookup_timing_test(test_type); + + if(!test) + { + throw CLI_Error("Unknown or unavailable test type '" + test_type + "'"); + } + + std::string filename = get_arg_or("test-data-file", ""); + + if(filename.empty()) + { + const std::string test_data_dir = get_arg("test-data-dir"); + filename = test_data_dir + "/" + test_type + ".vec"; + } + + std::vector lines = read_testdata(filename); + + std::vector> results = test->execute_evaluation(lines, warmup_runs, measurement_runs); + + size_t unique_id = 0; + std::ostringstream oss; + for(size_t secret_id = 0; secret_id != results.size(); ++secret_id) + { + for(size_t i = 0; i != results[secret_id].size(); ++i) + { + oss << unique_id++ << ";" << secret_id << ";" << results[secret_id][i] << "\n"; + } + } + + output() << oss.str(); + } + private: + + std::vector read_testdata(const std::string& filename) + { + std::vector lines; + std::ifstream infile(filename); + if(infile.good() == false) + { + throw CLI_Error("Error reading test data from '" + filename + "'"); + } + std::string line; + while(std::getline(infile, line)) + { + if(line.size() > 0 && line.at(0) != '#') + { + lines.push_back(line); + } + } + return lines; + } + + std::unique_ptr lookup_timing_test(const std::string& test_type); + + std::string help_text() const override + { + // TODO check feature macros + return (Command::help_text() + + "\ntest_type can take on values " + "bleichenbacher " + "manger " + "ecdsa " + "ecc_mul " + "inverse_mod " + "pow_mod " + "lucky13sec3 " + "lucky13sec4sha1 " + "lucky13sec4sha256 " + "lucky13sec4sha384 " + ); + } + }; + +BOTAN_REGISTER_COMMAND("timing_test", Timing_Test_Command); + +std::unique_ptr Timing_Test_Command::lookup_timing_test(const std::string& test_type) + { +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_PKCS1) && defined(BOTAN_HAS_EME_RAW) + if(test_type == "bleichenbacher") + { + return std::unique_ptr(new Bleichenbacker_Timing_Test(2048)); + } +#endif + +#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_OAEP) && defined(BOTAN_HAS_EME_RAW) + if(test_type == "manger") + { + return std::unique_ptr(new Manger_Timing_Test(2048)); + } +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(test_type == "ecdsa") + { + return std::unique_ptr(new ECDSA_Timing_Test("secp384r1")); + } +#endif + +#if defined(BOTAN_HAS_ECC_GROUP) + if(test_type == "ecc_mul") + { + return std::unique_ptr(new ECC_Mul_Timing_Test("brainpool512r1")); + } +#endif + +#if defined(BOTAN_HAS_NUMBERTHEORY) + if(test_type == "inverse_mod") + { + return std::unique_ptr(new Invmod_Timing_Test(512)); + } +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + if(test_type == "pow_mod") + { + return std::unique_ptr(new Powmod_Timing_Test("modp/ietf/1024")); + } +#endif + +#if defined(BOTAN_HAS_TLS_CBC) + if(test_type == "lucky13sec3" || test_type == "lucky13sec4sha1") + { + return std::unique_ptr(new Lucky13_Timing_Test("SHA-1", 20)); + } + if(test_type == "lucky13sec4sha256") + { + return std::unique_ptr(new Lucky13_Timing_Test("SHA-256", 32)); + } + if(test_type == "lucky13sec4sha384") + { + return std::unique_ptr(new Lucky13_Timing_Test("SHA-384", 48)); + } +#endif + + BOTAN_UNUSED(test_type); + + return nullptr; + } + + +} diff --git a/comm/third_party/botan/src/cli/tls_client.cpp b/comm/third_party/botan/src/cli/tls_client.cpp new file mode 100644 index 0000000000..9541f8fbc4 --- /dev/null +++ b/comm/third_party/botan/src/cli/tls_client.cpp @@ -0,0 +1,436 @@ +/* +* (C) 2014,2015 Jack Lloyd +* 2016 Matthias Gierlings +* 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_TLS) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) && defined(BOTAN_TARGET_OS_HAS_SOCKETS) + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) + #include +#endif + +#include +#include + +#include "socket_utils.h" +#include "tls_helpers.h" + +namespace Botan_CLI { + +class CLI_Policy final : public Botan::TLS::Policy + { + public: + + CLI_Policy(Botan::TLS::Protocol_Version req_version) : m_version(req_version) {} + + std::vector allowed_ciphers() const override + { + // Allow CBC mode only in versions which don't support AEADs + if(m_version.supports_aead_modes() == false) + { + return { "AES-256", "AES-128" }; + } + + return Botan::TLS::Policy::allowed_ciphers(); + } + + bool allow_tls10() const override { return m_version == Botan::TLS::Protocol_Version::TLS_V10; } + bool allow_tls11() const override { return m_version == Botan::TLS::Protocol_Version::TLS_V11; } + bool allow_tls12() const override { return m_version == Botan::TLS::Protocol_Version::TLS_V12; } + + private: + Botan::TLS::Protocol_Version m_version; + }; + +class TLS_Client final : public Command, public Botan::TLS::Callbacks + { + public: + TLS_Client() + : Command("tls_client host --port=443 --print-certs --policy=default " + "--tls1.0 --tls1.1 --tls1.2 " + "--skip-system-cert-store --trusted-cas= " + "--session-db= --session-db-pass= --next-protocols= --type=tcp") + { + init_sockets(); + } + + ~TLS_Client() + { + stop_sockets(); + } + + std::string group() const override + { + return "tls"; + } + + std::string description() const override + { + return "Connect to a host using TLS/DTLS"; + } + + void go() override + { + // TODO client cert auth + + std::unique_ptr session_mgr; + + const std::string sessions_db = get_arg("session-db"); + const std::string host = get_arg("host"); + const uint16_t port = get_arg_u16("port"); + const std::string transport = get_arg("type"); + const std::string next_protos = get_arg("next-protocols"); + const bool use_system_cert_store = flag_set("skip-system-cert-store") == false; + const std::string trusted_CAs = get_arg("trusted-cas"); + + if(!sessions_db.empty()) + { +#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) + const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass"); + session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db)); +#else + error_output() << "Ignoring session DB file, sqlite not enabled\n"; +#endif + } + + if(!session_mgr) + { + session_mgr.reset(new Botan::TLS::Session_Manager_In_Memory(rng())); + } + + auto policy = load_tls_policy(get_arg("policy")); + + if(transport != "tcp" && transport != "udp") + { + throw CLI_Usage_Error("Invalid transport type '" + transport + "' for TLS"); + } + + const bool use_tcp = (transport == "tcp"); + + const std::vector protocols_to_offer = Botan::split_on(next_protos, ','); + + Botan::TLS::Protocol_Version version = + use_tcp ? Botan::TLS::Protocol_Version::TLS_V12 : Botan::TLS::Protocol_Version::DTLS_V12; + + if(flag_set("tls1.0")) + { + version = Botan::TLS::Protocol_Version::TLS_V10; + if(!policy) + policy.reset(new CLI_Policy(version)); + } + else if(flag_set("tls1.1")) + { + version = Botan::TLS::Protocol_Version::TLS_V11; + if(!policy) + policy.reset(new CLI_Policy(version)); + } + else if(flag_set("tls1.2")) + { + version = Botan::TLS::Protocol_Version::TLS_V12; + if(!policy) + policy.reset(new CLI_Policy(version)); + } + else if(!policy) + { + policy.reset(new Botan::TLS::Policy); + } + + if(policy->acceptable_protocol_version(version) == false) + { + throw CLI_Usage_Error("The policy specified does not allow the requested TLS version"); + } + + struct sockaddr_storage addrbuf; + std::string hostname; + if(!host.empty() && + inet_pton(AF_INET, host.c_str(), &addrbuf) != 1 && + inet_pton(AF_INET6, host.c_str(), &addrbuf) != 1) + { + hostname = host; + } + + m_sockfd = connect_to_host(host, port, use_tcp); + + Basic_Credentials_Manager creds(use_system_cert_store, trusted_CAs); + + Botan::TLS::Client client(*this, *session_mgr, creds, *policy, rng(), + Botan::TLS::Server_Information(hostname, port), + version, protocols_to_offer); + + bool first_active = true; + + while(!client.is_closed()) + { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(m_sockfd, &readfds); + + if(client.is_active()) + { + FD_SET(STDIN_FILENO, &readfds); + if(first_active && !protocols_to_offer.empty()) + { + std::string app = client.application_protocol(); + if(app != "") + { + output() << "Server choose protocol: " << client.application_protocol() << "\n"; + } + first_active = false; + } + } + + struct timeval timeout = { 1, 0 }; + + ::select(static_cast(m_sockfd + 1), &readfds, nullptr, nullptr, &timeout); + + if(FD_ISSET(m_sockfd, &readfds)) + { + uint8_t buf[4 * 1024] = { 0 }; + + ssize_t got = ::read(m_sockfd, buf, sizeof(buf)); + + if(got == 0) + { + output() << "EOF on socket\n"; + break; + } + else if(got == -1) + { + output() << "Socket error: " << errno << " " << err_to_string(errno) << "\n"; + continue; + } + + client.received_data(buf, got); + } + + if(FD_ISSET(STDIN_FILENO, &readfds)) + { + uint8_t buf[1024] = { 0 }; + ssize_t got = read(STDIN_FILENO, buf, sizeof(buf)); + + if(got == 0) + { + output() << "EOF on stdin\n"; + client.close(); + break; + } + else if(got == -1) + { + output() << "Stdin error: " << errno << " " << err_to_string(errno) << "\n"; + continue; + } + + if(got == 2 && buf[1] == '\n') + { + char cmd = buf[0]; + + if(cmd == 'R' || cmd == 'r') + { + output() << "Client initiated renegotiation\n"; + client.renegotiate(cmd == 'R'); + } + else if(cmd == 'Q') + { + output() << "Client initiated close\n"; + client.close(); + } + } + else + { + client.send(buf, got); + } + } + + if(client.timeout_check()) + { + output() << "Timeout detected\n"; + } + } + + ::close(m_sockfd); + } + + private: + socket_type connect_to_host(const std::string& host, uint16_t port, bool tcp) + { + addrinfo hints; + Botan::clear_mem(&hints, 1); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM; + addrinfo* res, *rp = nullptr; + + if(::getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res) != 0) + { + throw CLI_Error("getaddrinfo failed for " + host); + } + + socket_type fd = 0; + + for(rp = res; rp != nullptr; rp = rp->ai_next) + { + fd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + if(fd == invalid_socket()) + { + continue; + } + + if(::connect(fd, rp->ai_addr, static_cast(rp->ai_addrlen)) != 0) + { + ::close(fd); + continue; + } + + break; + } + + ::freeaddrinfo(res); + + if(rp == nullptr) // no address succeeded + { + throw CLI_Error("connect failed"); + } + + return fd; + } + + void tls_verify_cert_chain( + const std::vector& cert_chain, + const std::vector>& ocsp, + const std::vector& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname, + const Botan::TLS::Policy& policy) override + { + if(cert_chain.empty()) + { + throw Botan::Invalid_Argument("Certificate chain was empty"); + } + + Botan::Path_Validation_Restrictions restrictions( + policy.require_cert_revocation_info(), + policy.minimum_signature_strength()); + + auto ocsp_timeout = std::chrono::milliseconds(1000); + + Botan::Path_Validation_Result result = Botan::x509_path_validate( + cert_chain, + restrictions, + trusted_roots, + hostname, + usage, + std::chrono::system_clock::now(), + ocsp_timeout, + ocsp); + + output() << "Certificate validation status: " << result.result_string() << "\n"; + if(result.successful_validation()) + { + auto status = result.all_statuses(); + + if(status.size() > 0 && status[0].count(Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD)) + { + output() << "Valid OCSP response for this server\n"; + } + } + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + output() << "Handshake complete, " << session.version().to_string() + << " using " << session.ciphersuite().to_string() << "\n"; + + if(!session.session_id().empty()) + { + output() << "Session ID " << Botan::hex_encode(session.session_id()) << "\n"; + } + + if(!session.session_ticket().empty()) + { + output() << "Session ticket " << Botan::hex_encode(session.session_ticket()) << "\n"; + } + + if(flag_set("print-certs")) + { + const std::vector& certs = session.peer_certs(); + + for(size_t i = 0; i != certs.size(); ++i) + { + output() << "Certificate " << i + 1 << "/" << certs.size() << "\n"; + output() << certs[i].to_string(); + output() << certs[i].PEM_encode(); + } + } + + return true; + } + + static void dgram_socket_write(int sockfd, const uint8_t buf[], size_t length) + { + int r = ::send(sockfd, buf, length, MSG_NOSIGNAL); + + if(r == -1) + { + throw CLI_Error("Socket write failed errno=" + std::to_string(errno)); + } + } + + void tls_emit_data(const uint8_t buf[], size_t length) override + { + size_t offset = 0; + + while(length) + { + ssize_t sent = ::send(m_sockfd, buf + offset, length, MSG_NOSIGNAL); + + if(sent == -1) + { + if(errno == EINTR) + { + sent = 0; + } + else + { + throw CLI_Error("Socket write failed errno=" + std::to_string(errno)); + } + } + + offset += sent; + length -= sent; + } + } + + void tls_alert(Botan::TLS::Alert alert) override + { + output() << "Alert: " << alert.type_string() << "\n"; + } + + void tls_record_received(uint64_t /*seq_no*/, const uint8_t buf[], size_t buf_size) override + { + for(size_t i = 0; i != buf_size; ++i) + { + output() << buf[i]; + } + } + + socket_type m_sockfd = invalid_socket(); + }; + +BOTAN_REGISTER_COMMAND("tls_client", TLS_Client); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/tls_helpers.h b/comm/third_party/botan/src/cli/tls_helpers.h new file mode 100644 index 0000000000..653a106e0b --- /dev/null +++ b/comm/third_party/botan/src/cli/tls_helpers.h @@ -0,0 +1,244 @@ +/* +* (C) 2014,2015,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CLI_TLS_HELPERS_H_ +#define BOTAN_CLI_TLS_HELPERS_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "cli_exceptions.h" + +#if defined(BOTAN_HAS_CERTSTOR_SYSTEM) + #include +#endif + +inline bool value_exists(const std::vector& vec, + const std::string& val) + { + for(size_t i = 0; i != vec.size(); ++i) + { + if(vec[i] == val) + { + return true; + } + } + return false; + } + +class Basic_Credentials_Manager : public Botan::Credentials_Manager + { + public: + Basic_Credentials_Manager(bool use_system_store, + const std::string& ca_path) + { + if(ca_path.empty() == false) + { + m_certstores.push_back(std::make_shared(ca_path)); + } + +#if defined(BOTAN_HAS_CERTSTOR_SYSTEM) + if(use_system_store) + { + m_certstores.push_back(std::make_shared()); + } +#else + BOTAN_UNUSED(use_system_store); +#endif + } + + Basic_Credentials_Manager(Botan::RandomNumberGenerator& rng, + const std::string& server_crt, + const std::string& server_key) + { + Certificate_Info cert; + + cert.key.reset(Botan::PKCS8::load_key(server_key, rng)); + + Botan::DataSource_Stream in(server_crt); + while(!in.end_of_data()) + { + try + { + cert.certs.push_back(Botan::X509_Certificate(in)); + } + catch(std::exception&) + { + } + } + + // TODO: attempt to validate chain ourselves + + m_creds.push_back(cert); + } + + std::vector + trusted_certificate_authorities(const std::string& type, + const std::string& /*hostname*/) override + { + std::vector v; + + // don't ask for client certs + if(type == "tls-server") + { + return v; + } + + for(auto const& cs : m_certstores) + { + v.push_back(cs.get()); + } + + return v; + } + + std::vector cert_chain( + const std::vector& algos, + const std::string& type, + const std::string& hostname) override + { + BOTAN_UNUSED(type); + + for(auto const& i : m_creds) + { + if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end()) + { + continue; + } + + if(hostname != "" && !i.certs[0].matches_dns_name(hostname)) + { + continue; + } + + return i.certs; + } + + return std::vector(); + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& /*type*/, + const std::string& /*context*/) override + { + for(auto const& i : m_creds) + { + if(cert == i.certs[0]) + { + return i.key.get(); + } + } + + return nullptr; + } + + private: + struct Certificate_Info + { + std::vector certs; + std::shared_ptr key; + }; + + std::vector m_creds; + std::vector> m_certstores; + }; + +class TLS_All_Policy final : public Botan::TLS::Policy + { + public: + std::vector allowed_ciphers() const override + { + return std::vector + { + "ChaCha20Poly1305", + "AES-256/OCB(12)", + "AES-128/OCB(12)", + "AES-256/GCM", + "AES-128/GCM", + "AES-256/CCM", + "AES-128/CCM", + "AES-256/CCM(8)", + "AES-128/CCM(8)", + "Camellia-256/GCM", + "Camellia-128/GCM", + "ARIA-256/GCM", + "ARIA-128/GCM", + "AES-256", + "AES-128", + "Camellia-256", + "Camellia-128", + "SEED" + "3DES" + }; + } + + std::vector allowed_key_exchange_methods() const override + { + return { "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK", "CECPQ1", "ECDH", "DH", "RSA" }; + } + + std::vector allowed_signature_methods() const override + { + return { "ECDSA", "RSA", "DSA", "IMPLICIT" }; + } + + bool allow_tls10() const override { return true; } + bool allow_tls11() const override { return true; } + bool allow_tls12() const override { return true; } + }; + +inline std::unique_ptr load_tls_policy(const std::string policy_type) + { + std::unique_ptr policy; + + if(policy_type == "default" || policy_type == "") + { + policy.reset(new Botan::TLS::Policy); + } + else if(policy_type == "suiteb_128") + { + policy.reset(new Botan::TLS::NSA_Suite_B_128); + } + else if(policy_type == "suiteb_192" || policy_type == "suiteb") + { + policy.reset(new Botan::TLS::NSA_Suite_B_192); + } + else if(policy_type == "strict") + { + policy.reset(new Botan::TLS::Strict_Policy); + } + else if(policy_type == "bsi") + { + policy.reset(new Botan::TLS::BSI_TR_02102_2); + } + else if(policy_type == "datagram") + { + policy.reset(new Botan::TLS::Strict_Policy); + } + else if(policy_type == "all" || policy_type == "everything") + { + policy.reset(new TLS_All_Policy); + } + else + { + // assume it's a file + std::ifstream policy_stream(policy_type); + if(!policy_stream.good()) + { + throw Botan_CLI::CLI_Usage_Error("Unknown TLS policy: not a file or known short name"); + } + policy.reset(new Botan::TLS::Text_Policy(policy_stream)); + } + + return policy; + } + +#endif diff --git a/comm/third_party/botan/src/cli/tls_http_server.cpp b/comm/third_party/botan/src/cli/tls_http_server.cpp new file mode 100644 index 0000000000..aaf740fcf3 --- /dev/null +++ b/comm/third_party/botan/src/cli/tls_http_server.cpp @@ -0,0 +1,579 @@ +/* +* (C) 2014,2015,2017,2019 Jack Lloyd +* (C) 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_TLS) && defined(BOTAN_HAS_BOOST_ASIO) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +#include +#include +#include +#include +#include +#include +#include + +#define _GLIBCXX_HAVE_GTHR_DEFAULT +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) + #include +#endif + +#include "tls_helpers.h" + +#if BOOST_VERSION >= 107000 +#define GET_IO_SERVICE(s) (static_cast((s).get_executor().context())) +#else +#define GET_IO_SERVICE(s) ((s).get_io_service()) +#endif + +namespace Botan_CLI { + +namespace { + +using boost::asio::ip::tcp; + +inline void log_exception(const char* where, const std::exception& e) + { + std::cout << where << ' ' << e.what() << std::endl; + } + +class ServerStatus + { + public: + ServerStatus(size_t max_clients) : m_max_clients(max_clients), m_clients_serviced(0) {} + + bool should_exit() const + { + if(m_max_clients == 0) + return false; + + return clients_serviced() >= m_max_clients; + } + + void client_serviced() { m_clients_serviced++; } + + size_t clients_serviced() const { return m_clients_serviced.load(); } + private: + size_t m_max_clients; + std::atomic m_clients_serviced; + }; + +/* +* This is an incomplete and highly buggy HTTP request parser. It is just +* barely sufficient to handle a GET request sent by a browser. +*/ +class HTTP_Parser final + { + public: + class Request + { + public: + const std::string& verb() const { return m_verb; } + const std::string& location() const { return m_location; } + const std::map& headers() const { return m_headers; } + + Request(const std::string& verb, + const std::string& location, + const std::map& headers) : + m_verb(verb), + m_location(location), + m_headers(headers) + {} + + private: + std::string m_verb; + std::string m_location; + std::map m_headers; + }; + + class Callbacks + { + public: + virtual void handle_http_request(const Request& request) = 0; + virtual ~Callbacks() = default; + }; + + HTTP_Parser(Callbacks& cb) : m_cb(cb) {} + + void consume_input(const uint8_t buf[], size_t buf_len) + { + m_req_buf.append(reinterpret_cast(buf), buf_len); + + std::istringstream strm(m_req_buf); + + std::string http_version; + std::string verb; + std::string location; + std::map headers; + + strm >> verb >> location >> http_version; + + if(verb.empty() || location.empty()) + return; + + while(true) + { + std::string header_line; + std::getline(strm, header_line); + + if(header_line == "\r") + { + continue; + } + + auto delim = header_line.find(": "); + if(delim == std::string::npos) + { + break; + } + + const std::string hdr_name = header_line.substr(0, delim); + const std::string hdr_val = header_line.substr(delim + 2, std::string::npos); + + headers[hdr_name] = hdr_val; + + if(headers.size() > 1024) + throw Botan::Invalid_Argument("Too many HTTP headers sent in request"); + } + + if(verb != "" && location != "") + { + Request req(verb, location, headers); + m_cb.handle_http_request(req); + m_req_buf.clear(); + } + else + printf("ignoring\n"); + } + private: + Callbacks& m_cb; + std::string m_req_buf; + }; + +static const size_t READBUF_SIZE = 4096; + +class TLS_Asio_HTTP_Session final : public std::enable_shared_from_this, + public Botan::TLS::Callbacks, + public HTTP_Parser::Callbacks + { + public: + typedef std::shared_ptr pointer; + + static pointer create( + boost::asio::io_service& io, + Botan::TLS::Session_Manager& session_manager, + Botan::Credentials_Manager& credentials, + Botan::TLS::Policy& policy) + { + return pointer(new TLS_Asio_HTTP_Session(io, session_manager, credentials, policy)); + } + + tcp::socket& client_socket() + { + return m_client_socket; + } + + void start() + { + m_c2s.resize(READBUF_SIZE); + client_read(boost::system::error_code(), 0); // start read loop + } + + void stop() + { + m_tls.close(); + } + + private: + TLS_Asio_HTTP_Session(boost::asio::io_service& io, + Botan::TLS::Session_Manager& session_manager, + Botan::Credentials_Manager& credentials, + Botan::TLS::Policy& policy) + : m_strand(io) + , m_client_socket(io) + , m_rng(cli_make_rng()) + , m_tls(*this, session_manager, credentials, policy, *m_rng) {} + + void client_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if(error) + { + return stop(); + } + + try + { + m_tls.received_data(&m_c2s[0], bytes_transferred); + } + catch(Botan::Exception& e) + { + log_exception("TLS connection failed", e); + return stop(); + } + + m_client_socket.async_read_some( + boost::asio::buffer(&m_c2s[0], m_c2s.size()), + m_strand.wrap( + boost::bind( + &TLS_Asio_HTTP_Session::client_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + + void handle_client_write_completion(const boost::system::error_code& error) + { + if(error) + { + return stop(); + } + + m_s2c.clear(); + + if(m_s2c_pending.empty() && m_tls.is_closed()) + { + m_client_socket.close(); + } + tls_emit_data(nullptr, 0); // initiate another write if needed + } + + std::string tls_server_choose_app_protocol(const std::vector& /*client_protos*/) override + { + return "http/1.1"; + } + + void tls_record_received(uint64_t /*rec_no*/, const uint8_t buf[], size_t buf_len) override + { + if(!m_http_parser) + m_http_parser.reset(new HTTP_Parser(*this)); + + m_http_parser->consume_input(buf, buf_len); + } + + std::string summarize_request(const HTTP_Parser::Request& request) + { + std::ostringstream strm; + + strm << "Client " << client_socket().remote_endpoint().address().to_string() + << " requested " << request.verb() << " " << request.location() << "\n"; + + if(request.headers().empty() == false) + { + strm << "Client HTTP headers:\n"; + for(auto kv : request.headers()) + strm << " " << kv.first << ": " << kv.second << "\n"; + } + + return strm.str(); + } + + void handle_http_request(const HTTP_Parser::Request& request) override + { + std::ostringstream response; + if(request.verb() == "GET") + { + if(request.location() == "/" || request.location() == "/status") + { + const std::string http_summary = summarize_request(request); + + const std::string report = m_session_summary + m_chello_summary + http_summary; + + response << "HTTP/1.0 200 OK\r\n"; + response << "Server: " << Botan::version_string() << "\r\n"; + response << "Content-Type: text/plain\r\n"; + response << "Content-Length: " << report.size() << "\r\n"; + response << "\r\n"; + + response << report; + } + else + { + response << "HTTP/1.0 404 Not Found\r\n\r\n"; + } + } + else + { + response << "HTTP/1.0 405 Method Not Allowed\r\n\r\n"; + } + + const std::string response_str = response.str(); + m_tls.send(response_str); + m_tls.close(); + } + + void tls_emit_data(const uint8_t buf[], size_t buf_len) override + { + if(buf_len > 0) + { + m_s2c_pending.insert(m_s2c_pending.end(), buf, buf + buf_len); + } + + // no write now active and we still have output pending + if(m_s2c.empty() && !m_s2c_pending.empty()) + { + std::swap(m_s2c_pending, m_s2c); + + boost::asio::async_write( + m_client_socket, + boost::asio::buffer(&m_s2c[0], m_s2c.size()), + m_strand.wrap( + boost::bind( + &TLS_Asio_HTTP_Session::handle_client_write_completion, + shared_from_this(), + boost::asio::placeholders::error))); + } + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + std::ostringstream strm; + + strm << "TLS negotiation with " << Botan::version_string() << " test server\n\n"; + + strm << "Version: " << session.version().to_string() << "\n"; + strm << "Ciphersuite: " << session.ciphersuite().to_string() << "\n"; + if(session.session_id().empty() == false) + { + strm << "SessionID: " << Botan::hex_encode(session.session_id()) << "\n"; + } + if(session.server_info().hostname() != "") + { + strm << "SNI: " << session.server_info().hostname() << "\n"; + } + + m_session_summary = strm.str(); + return true; + } + + void tls_inspect_handshake_msg(const Botan::TLS::Handshake_Message& message) override + { + if(message.type() == Botan::TLS::CLIENT_HELLO) + { + const Botan::TLS::Client_Hello& client_hello = dynamic_cast(message); + + std::ostringstream strm; + + strm << "Client random: " << Botan::hex_encode(client_hello.random()) << "\n"; + + strm << "Client offered following ciphersuites:\n"; + for(uint16_t suite_id : client_hello.ciphersuites()) + { + Botan::TLS::Ciphersuite ciphersuite = Botan::TLS::Ciphersuite::by_id(suite_id); + + strm << " - 0x" + << std::hex << std::setfill('0') << std::setw(4) << suite_id + << std::dec << std::setfill(' ') << std::setw(0) << " "; + + if(ciphersuite.valid()) + strm << ciphersuite.to_string() << "\n"; + else if(suite_id == 0x00FF) + strm << "Renegotiation SCSV\n"; + else + strm << "Unknown ciphersuite\n"; + } + + m_chello_summary = strm.str(); + } + + } + + void tls_alert(Botan::TLS::Alert alert) override + { + if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY) + { + m_tls.close(); + return; + } + else + { + std::cout << "Alert " << alert.type_string() << std::endl; + } + } + + boost::asio::io_service::strand m_strand; + + tcp::socket m_client_socket; + + std::unique_ptr m_rng; + Botan::TLS::Server m_tls; + std::string m_chello_summary; + std::string m_session_summary; + std::unique_ptr m_http_parser; + + std::vector m_c2s; + std::vector m_s2c; + std::vector m_s2c_pending; + }; + +class TLS_Asio_HTTP_Server final + { + public: + typedef TLS_Asio_HTTP_Session session; + + TLS_Asio_HTTP_Server( + boost::asio::io_service& io, unsigned short port, + Botan::Credentials_Manager& creds, + Botan::TLS::Policy& policy, + Botan::TLS::Session_Manager& session_mgr, + size_t max_clients) + : m_acceptor(io, tcp::endpoint(tcp::v4(), port)) + , m_creds(creds) + , m_policy(policy) + , m_session_manager(session_mgr) + , m_status(max_clients) + { + session::pointer new_session = make_session(); + + m_acceptor.async_accept( + new_session->client_socket(), + boost::bind( + &TLS_Asio_HTTP_Server::handle_accept, + this, + new_session, + boost::asio::placeholders::error)); + } + + private: + session::pointer make_session() + { + return session::create( + GET_IO_SERVICE(m_acceptor), + m_session_manager, + m_creds, + m_policy); + } + + void handle_accept(session::pointer new_session, + const boost::system::error_code& error) + { + if(!error) + { + new_session->start(); + new_session = make_session(); + + m_status.client_serviced(); + + if(m_status.should_exit() == false) + { + m_acceptor.async_accept( + new_session->client_socket(), + boost::bind( + &TLS_Asio_HTTP_Server::handle_accept, + this, + new_session, + boost::asio::placeholders::error)); + } + } + } + + tcp::acceptor m_acceptor; + + Botan::Credentials_Manager& m_creds; + Botan::TLS::Policy& m_policy; + Botan::TLS::Session_Manager& m_session_manager; + ServerStatus m_status; + }; + +} + +class TLS_HTTP_Server final : public Command + { + public: + TLS_HTTP_Server() : Command("tls_http_server server_cert server_key " + "--port=443 --policy=default --threads=0 --max-clients=0 " + "--session-db= --session-db-pass=") {} + + std::string group() const override + { + return "tls"; + } + + std::string description() const override + { + return "Provides a simple HTTP server"; + } + + size_t thread_count() const + { + if(size_t t = get_arg_sz("threads")) + return t; + if(size_t t = Botan::OS::get_cpu_available()) + return t; + return 2; + } + + void go() override + { + const uint16_t listen_port = get_arg_u16("port"); + + const std::string server_crt = get_arg("server_cert"); + const std::string server_key = get_arg("server_key"); + + const size_t num_threads = thread_count(); + const size_t max_clients = get_arg_sz("max-clients"); + + Basic_Credentials_Manager creds(rng(), server_crt, server_key); + + auto policy = load_tls_policy(get_arg("policy")); + + std::unique_ptr session_mgr; + + const std::string sessions_db = get_arg("session-db"); + + if(!sessions_db.empty()) + { +#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) + const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass"); + session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db)); +#else + throw CLI_Error_Unsupported("Sqlite3 support not available"); +#endif + } + + if(!session_mgr) + { + session_mgr.reset(new Botan::TLS::Session_Manager_In_Memory(rng())); + } + + boost::asio::io_service io; + + TLS_Asio_HTTP_Server server(io, listen_port, creds, *policy, *session_mgr, max_clients); + + std::vector> threads; + + // run forever... first thread is main calling io.run below + for(size_t i = 2; i <= num_threads; ++i) + { + threads.push_back(std::make_shared([&io]() { io.run(); })); + } + + io.run(); + + for(size_t i = 0; i < threads.size(); ++i) + { + threads[i]->join(); + } + } + }; + +BOTAN_REGISTER_COMMAND("tls_http_server", TLS_HTTP_Server); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/tls_proxy.cpp b/comm/third_party/botan/src/cli/tls_proxy.cpp new file mode 100644 index 0000000000..bd96530c20 --- /dev/null +++ b/comm/third_party/botan/src/cli/tls_proxy.cpp @@ -0,0 +1,526 @@ +/* +* TLS Server Proxy +* (C) 2014,2015,2019 Jack Lloyd +* (C) 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_TLS) && defined(BOTAN_HAS_BOOST_ASIO) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +#include +#include +#include +#include +#include + +#define _GLIBCXX_HAVE_GTHR_DEFAULT +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) + #include +#endif + +#include "tls_helpers.h" + +#if BOOST_VERSION >= 107000 +#define GET_IO_SERVICE(s) (static_cast((s).get_executor().context())) +#else +#define GET_IO_SERVICE(s) ((s).get_io_service()) +#endif + +namespace Botan_CLI { + +namespace { + +using boost::asio::ip::tcp; + +void log_exception(const char* where, const std::exception& e) + { + std::cout << where << ' ' << e.what() << std::endl; + } + +void log_error(const char* where, const boost::system::error_code& error) + { + std::cout << where << ' ' << error.message() << std::endl; + } + +void log_binary_message(const char* where, const uint8_t buf[], size_t buf_len) + { + BOTAN_UNUSED(where, buf, buf_len); + //std::cout << where << ' ' << Botan::hex_encode(buf, buf_len) << std::endl; + } + +void log_text_message(const char* where, const uint8_t buf[], size_t buf_len) + { + BOTAN_UNUSED(where, buf, buf_len); + //const char* c = reinterpret_cast(buf); + //std::cout << where << ' ' << std::string(c, c + buf_len) << std::endl; + } + +class ServerStatus + { + public: + ServerStatus(size_t max_clients) : m_max_clients(max_clients), m_clients_serviced(0) {} + + bool should_exit() const + { + if(m_max_clients == 0) + return false; + + return clients_serviced() >= m_max_clients; + } + + void client_serviced() { m_clients_serviced++; } + + size_t clients_serviced() const { return m_clients_serviced.load(); } + private: + size_t m_max_clients; + std::atomic m_clients_serviced; + }; + +class tls_proxy_session final : public std::enable_shared_from_this, + public Botan::TLS::Callbacks + { + public: + enum { readbuf_size = 17 * 1024 }; + + typedef std::shared_ptr pointer; + + static pointer create( + boost::asio::io_service& io, + Botan::TLS::Session_Manager& session_manager, + Botan::Credentials_Manager& credentials, + Botan::TLS::Policy& policy, + tcp::resolver::iterator endpoints) + { + return pointer( + new tls_proxy_session( + io, + session_manager, + credentials, + policy, + endpoints) + ); + } + + tcp::socket& client_socket() + { + return m_client_socket; + } + + void start() + { + m_c2p.resize(readbuf_size); + client_read(boost::system::error_code(), 0); // start read loop + } + + void stop() + { + if(m_is_closed == false) + { + /* + Don't need to talk to the server anymore + Client socket is closed during write callback + */ + m_server_socket.close(); + m_tls.close(); + m_is_closed = true; + } + } + + private: + tls_proxy_session( + boost::asio::io_service& io, + Botan::TLS::Session_Manager& session_manager, + Botan::Credentials_Manager& credentials, + Botan::TLS::Policy& policy, + tcp::resolver::iterator endpoints) + : m_strand(io) + , m_server_endpoints(endpoints) + , m_client_socket(io) + , m_server_socket(io) + , m_rng(cli_make_rng()) + , m_tls(*this, + session_manager, + credentials, + policy, + *m_rng) {} + + void client_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if(error) + { + log_error("Read failed", error); + stop(); + return; + } + + try + { + if(!m_tls.is_active()) + { + log_binary_message("From client", &m_c2p[0], bytes_transferred); + } + m_tls.received_data(&m_c2p[0], bytes_transferred); + } + catch(Botan::Exception& e) + { + log_exception("TLS connection failed", e); + stop(); + return; + } + + m_client_socket.async_read_some( + boost::asio::buffer(&m_c2p[0], m_c2p.size()), + m_strand.wrap( + boost::bind( + &tls_proxy_session::client_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + + void handle_client_write_completion(const boost::system::error_code& error) + { + if(error) + { + log_error("Client write", error); + stop(); + return; + } + + m_p2c.clear(); + + if(m_p2c_pending.empty() && m_tls.is_closed()) + { + m_client_socket.close(); + } + tls_emit_data(nullptr, 0); // initiate another write if needed + } + + void handle_server_write_completion(const boost::system::error_code& error) + { + if(error) + { + log_error("Server write", error); + stop(); + return; + } + + m_p2s.clear(); + proxy_write_to_server(nullptr, 0); // initiate another write if needed + } + + void tls_record_received(uint64_t /*rec_no*/, const uint8_t buf[], size_t buf_len) override + { + // Immediately bounce message to server + proxy_write_to_server(buf, buf_len); + } + + void tls_emit_data(const uint8_t buf[], size_t buf_len) override + { + if(buf_len > 0) + { + m_p2c_pending.insert(m_p2c_pending.end(), buf, buf + buf_len); + } + + // no write now active and we still have output pending + if(m_p2c.empty() && !m_p2c_pending.empty()) + { + std::swap(m_p2c_pending, m_p2c); + + log_binary_message("To Client", &m_p2c[0], m_p2c.size()); + + boost::asio::async_write( + m_client_socket, + boost::asio::buffer(&m_p2c[0], m_p2c.size()), + m_strand.wrap( + boost::bind( + &tls_proxy_session::handle_client_write_completion, + shared_from_this(), + boost::asio::placeholders::error))); + } + } + + void proxy_write_to_server(const uint8_t buf[], size_t buf_len) + { + if(buf_len > 0) + { + m_p2s_pending.insert(m_p2s_pending.end(), buf, buf + buf_len); + } + + // no write now active and we still have output pending + if(m_p2s.empty() && !m_p2s_pending.empty()) + { + std::swap(m_p2s_pending, m_p2s); + + log_text_message("To Server", &m_p2s[0], m_p2s.size()); + + boost::asio::async_write( + m_server_socket, + boost::asio::buffer(&m_p2s[0], m_p2s.size()), + m_strand.wrap( + boost::bind( + &tls_proxy_session::handle_server_write_completion, + shared_from_this(), + boost::asio::placeholders::error))); + } + } + + void server_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if(error) + { + log_error("Server read failed", error); + stop(); + return; + } + + try + { + if(bytes_transferred) + { + log_text_message("Server to client", &m_s2p[0], m_s2p.size()); + log_binary_message("Server to client", &m_s2p[0], m_s2p.size()); + m_tls.send(&m_s2p[0], bytes_transferred); + } + } + catch(Botan::Exception& e) + { + log_exception("TLS connection failed", e); + stop(); + return; + } + + m_s2p.resize(readbuf_size); + + m_server_socket.async_read_some( + boost::asio::buffer(&m_s2p[0], m_s2p.size()), + m_strand.wrap( + boost::bind(&tls_proxy_session::server_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + m_hostname = session.server_info().hostname(); + + auto onConnect = [this](boost::system::error_code ec, tcp::resolver::iterator /*endpoint*/) + { + if(ec) + { + log_error("Server connection", ec); + return; + } + server_read(boost::system::error_code(), 0); // start read loop + proxy_write_to_server(nullptr, 0); + }; + async_connect(m_server_socket, m_server_endpoints, onConnect); + return true; + } + + void tls_alert(Botan::TLS::Alert alert) override + { + if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY) + { + m_tls.close(); + return; + } + } + + boost::asio::io_service::strand m_strand; + + tcp::resolver::iterator m_server_endpoints; + + tcp::socket m_client_socket; + tcp::socket m_server_socket; + + std::unique_ptr m_rng; + Botan::TLS::Server m_tls; + std::string m_hostname; + + std::vector m_c2p; + std::vector m_p2c; + std::vector m_p2c_pending; + + std::vector m_s2p; + std::vector m_p2s; + std::vector m_p2s_pending; + + bool m_is_closed = false; + }; + +class tls_proxy_server final + { + public: + typedef tls_proxy_session session; + + tls_proxy_server( + boost::asio::io_service& io, unsigned short port, + tcp::resolver::iterator endpoints, + Botan::Credentials_Manager& creds, + Botan::TLS::Policy& policy, + Botan::TLS::Session_Manager& session_mgr, + size_t max_clients) + : m_acceptor(io, tcp::endpoint(tcp::v4(), port)) + , m_server_endpoints(endpoints) + , m_creds(creds) + , m_policy(policy) + , m_session_manager(session_mgr) + , m_status(max_clients) + { + session::pointer new_session = make_session(); + + m_acceptor.async_accept( + new_session->client_socket(), + boost::bind( + &tls_proxy_server::handle_accept, + this, + new_session, + boost::asio::placeholders::error)); + } + + private: + session::pointer make_session() + { + return session::create( + GET_IO_SERVICE(m_acceptor), + m_session_manager, + m_creds, + m_policy, + m_server_endpoints); + } + + void handle_accept(session::pointer new_session, + const boost::system::error_code& error) + { + if(!error) + { + new_session->start(); + new_session = make_session(); + + m_status.client_serviced(); + + if(m_status.should_exit() == false) + { + m_acceptor.async_accept( + new_session->client_socket(), + boost::bind( + &tls_proxy_server::handle_accept, + this, + new_session, + boost::asio::placeholders::error)); + } + } + } + + tcp::acceptor m_acceptor; + tcp::resolver::iterator m_server_endpoints; + + Botan::Credentials_Manager& m_creds; + Botan::TLS::Policy& m_policy; + Botan::TLS::Session_Manager& m_session_manager; + ServerStatus m_status; + }; + +} + +class TLS_Proxy final : public Command + { + public: + TLS_Proxy() : Command("tls_proxy listen_port target_host target_port server_cert server_key " + "--policy=default --threads=0 --max-clients=0 --session-db= --session-db-pass=") {} + + std::string group() const override + { + return "tls"; + } + + std::string description() const override + { + return "Proxies requests between a TLS client and a TLS server"; + } + + size_t thread_count() const + { + if(size_t t = get_arg_sz("threads")) + return t; + if(size_t t = Botan::OS::get_cpu_available()) + return t; + return 2; + } + + void go() override + { + const uint16_t listen_port = get_arg_u16("listen_port"); + const std::string target = get_arg("target_host"); + const std::string target_port = get_arg("target_port"); + + const std::string server_crt = get_arg("server_cert"); + const std::string server_key = get_arg("server_key"); + + const size_t num_threads = thread_count(); + const size_t max_clients = get_arg_sz("max-clients"); + + Basic_Credentials_Manager creds(rng(), server_crt, server_key); + + auto policy = load_tls_policy(get_arg("policy")); + + boost::asio::io_service io; + + tcp::resolver resolver(io); + auto server_endpoint_iterator = resolver.resolve({ target, target_port }); + + std::unique_ptr session_mgr; + +#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) + const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass"); + const std::string sessions_db = get_arg("session-db"); + + if(!sessions_db.empty()) + { + session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db)); + } +#endif + if(!session_mgr) + { + session_mgr.reset(new Botan::TLS::Session_Manager_In_Memory(rng())); + } + + tls_proxy_server server(io, listen_port, server_endpoint_iterator, creds, *policy, *session_mgr, max_clients); + + std::vector> threads; + + // run forever... first thread is main calling io.run below + for(size_t i = 2; i <= num_threads; ++i) + { + threads.push_back(std::make_shared([&io]() { io.run(); })); + } + + io.run(); + + for(size_t i = 0; i < threads.size(); ++i) + { + threads[i]->join(); + } + } + }; + +BOTAN_REGISTER_COMMAND("tls_proxy", TLS_Proxy); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/tls_server.cpp b/comm/third_party/botan/src/cli/tls_server.cpp new file mode 100644 index 0000000000..c39061e64d --- /dev/null +++ b/comm/third_party/botan/src/cli/tls_server.cpp @@ -0,0 +1,364 @@ +/* +* TLS echo server using BSD sockets +* (C) 2014 Jack Lloyd +* 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" +#include "sandbox.h" + +#if defined(BOTAN_HAS_TLS) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) && \ + defined(BOTAN_TARGET_OS_HAS_SOCKETS) + +#if defined(SO_USER_COOKIE) +#define SOCKET_ID 1 +#else +#define SOCKET_ID 0 +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "tls_helpers.h" +#include "socket_utils.h" + +namespace Botan_CLI { + +class TLS_Server final : public Command, public Botan::TLS::Callbacks + { + public: +#if SOCKET_ID + TLS_Server() : Command("tls_server cert key --port=443 --type=tcp --policy=default --dump-traces= --max-clients=0 --socket-id=0") +#else + TLS_Server() : Command("tls_server cert key --port=443 --type=tcp --policy=default --dump-traces= --max-clients=0") +#endif + { + init_sockets(); + } + + ~TLS_Server() + { + stop_sockets(); + } + + std::string group() const override + { + return "tls"; + } + + std::string description() const override + { + return "Accept TLS/DTLS connections from TLS/DTLS clients"; + } + + void go() override + { + const std::string server_crt = get_arg("cert"); + const std::string server_key = get_arg("key"); + const uint16_t port = get_arg_u16("port"); + const size_t max_clients = get_arg_sz("max-clients"); + const std::string transport = get_arg("type"); + const std::string dump_traces_to = get_arg("dump-traces"); +#if SOCKET_ID + m_socket_id = get_arg_sz("socket-id"); +#endif + + if(transport != "tcp" && transport != "udp") + { + throw CLI_Usage_Error("Invalid transport type '" + transport + "' for TLS"); + } + + m_is_tcp = (transport == "tcp"); + + auto policy = load_tls_policy(get_arg("policy")); + + Botan::TLS::Session_Manager_In_Memory session_manager(rng()); // TODO sqlite3 + + Basic_Credentials_Manager creds(rng(), server_crt, server_key); + + output() << "Listening for new connections on " << transport << " port " << port << std::endl; + + if(!m_sandbox.init()) + { + error_output() << "Failed sandboxing\n"; + return; + } + + socket_type server_fd = make_server_socket(port); + size_t clients_served = 0; + + while(true) + { + if(max_clients > 0 && clients_served >= max_clients) + break; + + if(m_is_tcp) + { + m_socket = ::accept(server_fd, nullptr, nullptr); + } + else + { + struct sockaddr_in from; + socklen_t from_len = sizeof(sockaddr_in); + + void* peek_buf = nullptr; + size_t peek_len = 0; + +#if defined(BOTAN_TARGET_OS_IS_MACOS) + // macOS handles zero size buffers differently - it will return 0 even if there's no incoming data, + // and after that connect() will fail as sockaddr_in from is not initialized + int dummy; + peek_buf = &dummy; + peek_len = sizeof(dummy); +#endif + + if(::recvfrom(server_fd, static_cast(peek_buf), static_cast(peek_len), + MSG_PEEK, reinterpret_cast(&from), &from_len) != 0) + { + throw CLI_Error("Could not peek next packet"); + } + + if(::connect(server_fd, reinterpret_cast(&from), from_len) != 0) + { + throw CLI_Error("Could not connect UDP socket"); + } + m_socket = server_fd; + } + + clients_served++; + + Botan::TLS::Server server( + *this, + session_manager, + creds, + *policy, + rng(), + m_is_tcp == false); + + std::unique_ptr dump_stream; + + if(!dump_traces_to.empty()) + { + uint64_t timestamp = Botan::OS::get_high_resolution_clock(); + const std::string dump_file = + dump_traces_to + "/tls_" + std::to_string(timestamp) + ".bin"; + dump_stream.reset(new std::ofstream(dump_file.c_str())); + } + + try + { + while(!server.is_closed()) + { + try + { + uint8_t buf[4 * 1024] = { 0 }; + ssize_t got = ::recv(m_socket, Botan::cast_uint8_ptr_to_char(buf), sizeof(buf), 0); + + if(got == -1) + { + error_output() << "Error in socket read - " << err_to_string(errno) << std::endl; + break; + } + + if(got == 0) + { + error_output() << "EOF on socket" << std::endl; + break; + } + + if(dump_stream) + { + dump_stream->write(reinterpret_cast(buf), got); + } + + server.received_data(buf, got); + + while(server.is_active() && !m_pending_output.empty()) + { + std::string output = m_pending_output.front(); + m_pending_output.pop_front(); + server.send(output); + + if(output == "quit\n") + { + server.close(); + } + } + } + catch(std::exception& e) + { + error_output() << "Connection problem: " << e.what() << std::endl; + if(m_is_tcp) + { + close_socket(m_socket); + m_socket = invalid_socket(); + } + } + } + } + catch(Botan::Exception& e) + { + error_output() << "Connection failed: " << e.what() << "\n"; + } + + if(m_is_tcp) + { + close_socket(m_socket); + m_socket = invalid_socket(); + } + } + + close_socket(server_fd); + } + private: + socket_type make_server_socket(uint16_t port) + { + const int type = m_is_tcp ? SOCK_STREAM : SOCK_DGRAM; + + socket_type fd = ::socket(PF_INET, type, 0); + if(fd == invalid_socket()) + { + throw CLI_Error("Unable to acquire socket"); + } + + sockaddr_in socket_info; + Botan::clear_mem(&socket_info, 1); + socket_info.sin_family = AF_INET; + socket_info.sin_port = htons(port); + + // FIXME: support limiting listeners + socket_info.sin_addr.s_addr = INADDR_ANY; + + if(::bind(fd, reinterpret_cast(&socket_info), sizeof(struct sockaddr)) != 0) + { + close_socket(fd); + throw CLI_Error("server bind failed"); + } + + if(m_is_tcp) + { + if(::listen(fd, 100) != 0) + { + close_socket(fd); + throw CLI_Error("listen failed"); + } + } + if(m_socket_id > 0) + { +#if SOCKET_ID + // Other oses could have other means to trace sockets +#if defined(SO_USER_COOKIE) + if(::setsockopt(fd, SOL_SOCKET, SO_USER_COOKIE, reinterpret_cast(&m_socket_id), sizeof(m_socket_id)) != 0) + { + // Failed but not world-ending issue + output() << "set socket cookie id failed" << std::endl; + } +#endif +#endif + } + return fd; + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + output() << "Handshake complete, " << session.version().to_string() + << " using " << session.ciphersuite().to_string() << std::endl; + + if(!session.session_id().empty()) + { + output() << "Session ID " << Botan::hex_encode(session.session_id()) << std::endl; + } + + if(!session.session_ticket().empty()) + { + output() << "Session ticket " << Botan::hex_encode(session.session_ticket()) << std::endl; + } + + return true; + } + + void tls_record_received(uint64_t, const uint8_t input[], size_t input_len) override + { + for(size_t i = 0; i != input_len; ++i) + { + const char c = static_cast(input[i]); + m_line_buf += c; + if(c == '\n') + { + m_pending_output.push_back(m_line_buf); + m_line_buf.clear(); + } + } + } + + void tls_emit_data(const uint8_t buf[], size_t length) override + { + if(m_is_tcp) + { + ssize_t sent = ::send(m_socket, buf, static_cast(length), MSG_NOSIGNAL); + + if(sent == -1) + { + error_output() << "Error writing to socket - " << err_to_string(errno) << std::endl; + } + else if(sent != static_cast(length)) + { + error_output() << "Packet of length " << length << " truncated to " << sent << std::endl; + } + } + else + { + while(length) + { + ssize_t sent = ::send(m_socket, buf, static_cast(length), MSG_NOSIGNAL); + + if(sent == -1) + { + if(errno == EINTR) + { + sent = 0; + } + else + { + throw CLI_Error("Socket write failed"); + } + } + + buf += sent; + length -= sent; + } + } + } + + void tls_alert(Botan::TLS::Alert alert) override + { + output() << "Alert: " << alert.type_string() << std::endl; + } + + std::string tls_server_choose_app_protocol(const std::vector&) override + { + // we ignore whatever the client sends here + return "echo/0.1"; + } + + socket_type m_socket = invalid_socket(); + bool m_is_tcp = false; + uint32_t m_socket_id = 0; + std::string m_line_buf; + std::list m_pending_output; + Sandbox m_sandbox; + }; + +BOTAN_REGISTER_COMMAND("tls_server", TLS_Server); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/tls_utils.cpp b/comm/third_party/botan/src/cli/tls_utils.cpp new file mode 100644 index 0000000000..c98cbc50f4 --- /dev/null +++ b/comm/third_party/botan/src/cli/tls_utils.cpp @@ -0,0 +1,226 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_TLS) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +#include +#include +#include +#include +#include +#include + +#include "tls_helpers.h" + +namespace Botan_CLI { + +class TLS_Ciphersuites final : public Command + { + public: + TLS_Ciphersuites() + : Command("tls_ciphers --policy=default --version=tls1.2") {} + + static Botan::TLS::Protocol_Version::Version_Code tls_version_from_str(const std::string& str) + { + if(str == "tls1.2" || str == "TLS1.2" || str == "TLS-1.2") + { + return Botan::TLS::Protocol_Version::TLS_V12; + } + else if(str == "tls1.1" || str == "TLS1.1" || str == "TLS-1.1") + { + return Botan::TLS::Protocol_Version::TLS_V11; + } + else if(str == "tls1.0" || str == "TLS1.1" || str == "TLS-1.1") + { + return Botan::TLS::Protocol_Version::TLS_V10; + } + if(str == "dtls1.2" || str == "DTLS1.2" || str == "DTLS-1.2") + { + return Botan::TLS::Protocol_Version::DTLS_V12; + } + else if(str == "dtls1.0" || str == "DTLS1.0" || str == "DTLS-1.0") + { + return Botan::TLS::Protocol_Version::DTLS_V10; + } + else + { + throw CLI_Error("Unknown TLS version '" + str + "'"); + } + } + + std::string group() const override + { + return "tls"; + } + + std::string description() const override + { + return "Lists all ciphersuites for a policy and TLS version"; + } + + void go() override + { + const std::string policy_type = get_arg("policy"); + const Botan::TLS::Protocol_Version version(tls_version_from_str(get_arg("version"))); + const bool with_srp = false; // fixme + + auto policy = load_tls_policy(policy_type); + + if(policy->acceptable_protocol_version(version) == false) + { + error_output() << "Error: the policy specified does not allow the given TLS version\n"; + return; + } + + for(uint16_t suite_id : policy->ciphersuite_list(version, with_srp)) + { + const Botan::TLS::Ciphersuite suite(Botan::TLS::Ciphersuite::by_id(suite_id)); + output() << suite.to_string() << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("tls_ciphers", TLS_Ciphersuites); + +class TLS_Client_Hello_Reader final : public Command + { + public: + TLS_Client_Hello_Reader() + : Command("tls_client_hello --hex input") {} + + std::string group() const override + { + return "tls"; + } + + std::string description() const override + { + return "Parse a TLS client hello message"; + } + + void go() override + { + const std::string input_file = get_arg("input"); + std::vector input; + + if(flag_set("hex")) + { + input = Botan::hex_decode(slurp_file_as_str(input_file)); + } + else + { + input = slurp_file(input_file); + } + + if(input.size() < 45) + { + error_output() << "Input too short to be valid\n"; + return; + } + + // Input also contains the record layer header, strip it + if(input[0] == 22) + { + const size_t len = Botan::make_uint16(input[3], input[4]); + + if(input.size() != len + 5) + { + error_output() << "Record layer length invalid\n"; + return; + } + + input = std::vector(input.begin() + 5, input.end()); + } + + // Assume the handshake header is there, strip it + if(input[0] == 1) + { + const size_t hs_len = Botan::make_uint32(0, input[1], input[2], input[3]); + + if(input.size() != hs_len + 4) + { + error_output() << "Handshake layer length invalid\n"; + return; + } + + input = std::vector(input.begin() + 4, input.end()); + } + + try + { + Botan::TLS::Client_Hello hello(input); + + output() << format_hello(hello); + } + catch(std::exception& e) + { + error_output() << "Parsing client hello failed: " << e.what() << "\n"; + } + } + + private: + std::string format_hello(const Botan::TLS::Client_Hello& hello) + { + std::ostringstream oss; + oss << "Version: " << hello.version().to_string() << "\n" + << "Random: " << Botan::hex_encode(hello.random()) << "\n"; + + if(!hello.session_id().empty()) + oss << "SessionID: " << Botan::hex_encode(hello.session_id()) << "\n"; + for(uint16_t csuite_id : hello.ciphersuites()) + { + auto csuite = Botan::TLS::Ciphersuite::by_id(csuite_id); + if(csuite.valid()) + oss << "Cipher: " << csuite.to_string() << "\n"; + else if(csuite_id == 0x00FF) + oss << "Cipher: EMPTY_RENEGOTIATION_INFO_SCSV\n"; + else + oss << "Cipher: Unknown (" << std::hex << csuite_id << ")\n"; + } + + oss << "Supported signature schemes: "; + + if(hello.signature_schemes().empty()) + { + oss << "Did not send signature_algorithms extension\n"; + } + else + { + for(Botan::TLS::Signature_Scheme scheme : hello.signature_schemes()) + { + try + { + auto s = sig_scheme_to_string(scheme); + oss << s << " "; + } + catch(...) + { + oss << "(" << std::hex << static_cast(scheme) << ") "; + } + } + oss << "\n"; + } + + std::map hello_flags; + hello_flags["ALPN"] = hello.supports_alpn(); + hello_flags["Encrypt Then Mac"] = hello.supports_encrypt_then_mac(); + hello_flags["Extended Master Secret"] = hello.supports_extended_master_secret(); + hello_flags["Session Ticket"] = hello.supports_session_ticket(); + + for(auto&& i : hello_flags) + oss << "Supports " << i.first << "? " << (i.second ? "yes" : "no") << "\n"; + + return oss.str(); + } + }; + +BOTAN_REGISTER_COMMAND("tls_client_hello", TLS_Client_Hello_Reader); + +} + +#endif diff --git a/comm/third_party/botan/src/cli/tss.cpp b/comm/third_party/botan/src/cli/tss.cpp new file mode 100644 index 0000000000..0756616b2a --- /dev/null +++ b/comm/third_party/botan/src/cli/tss.cpp @@ -0,0 +1,138 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_THRESHOLD_SECRET_SHARING) + #include + #include + #include + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_THRESHOLD_SECRET_SHARING) + +class TSS_Split final : public Command + { + public: + TSS_Split() : Command("tss_split M N input --id= --share-prefix=share --share-suffix=tss --hash=SHA-256") {} + + std::string group() const override + { + return "tss"; + } + + std::string description() const override + { + return "Split a secret into parts"; + } + + void go() override + { + const std::string hash_algo = get_arg("hash"); + const std::string input = get_arg("input"); + const std::string id_str = get_arg("id"); + const std::string share_prefix = get_arg("share-prefix"); + const std::string share_suffix = get_arg("share-suffix"); + const size_t N = get_arg_sz("N"); + const size_t M = get_arg_sz("M"); + + if(M <= 1 || N <= 1 || M > N || N >= 255) + throw CLI_Usage_Error("Invalid N/M parameters for secret splitting"); + + Botan::secure_vector secret = slurp_file_lvec(input); + + if(secret.size() > 0xFFFF) + throw CLI_Usage_Error("Secret is too large for this TSS format"); + + std::vector id = Botan::hex_decode(id_str); + + if(id.empty()) + { + id.resize(16); + rng().randomize(id.data(), id.size()); + } + + std::vector shares = + Botan::RTSS_Share::split(static_cast(M), static_cast(N), + secret.data(), static_cast(secret.size()), + id, hash_algo, rng()); + + for(size_t i = 0; i != shares.size(); ++i) + { + const std::string share_name = share_prefix + std::to_string(i + 1) + "." + share_suffix; + std::ofstream out(share_name.c_str()); + if(!out) + throw CLI_Error("Failed to open output file " + share_name); + + out.write(reinterpret_cast(shares[i].data().data()), shares[i].data().size()); + } + + } + + private: + Botan::secure_vector slurp_file_lvec(const std::string& input_file) + { + Botan::secure_vector buf; + auto insert_fn = [&](const uint8_t b[], size_t l) + { + buf.insert(buf.end(), b, b + l); + }; + this->read_file(input_file, insert_fn, 4096); + return buf; + } + }; + +BOTAN_REGISTER_COMMAND("tss_split", TSS_Split); + +class TSS_Recover final : public Command + { + public: + TSS_Recover() : Command("tss_recover *shares") {} + + std::string group() const override + { + return "tss"; + } + + std::string description() const override + { + return "Recover a split secret"; + } + + void go() override + { + const std::vector share_names = get_arg_list("shares"); + + if(share_names.empty()) + { + output() << help_text() << "\n"; + this->set_return_code(1); + return; + } + + std::vector shares; + + for(std::string share_fsname : get_arg_list("shares")) + { + auto v = slurp_file(share_fsname); + shares.push_back(Botan::RTSS_Share(v.data(), v.size())); + } + + Botan::secure_vector rec = Botan::RTSS_Share::reconstruct(shares); + + output().write(Botan::cast_uint8_ptr_to_char(rec.data()), rec.size()); + } + }; + +BOTAN_REGISTER_COMMAND("tss_recover", TSS_Recover); + +#endif + +} + diff --git a/comm/third_party/botan/src/cli/utils.cpp b/comm/third_party/botan/src/cli/utils.cpp new file mode 100644 index 0000000000..c6d013029a --- /dev/null +++ b/comm/third_party/botan/src/cli/utils.cpp @@ -0,0 +1,391 @@ +/* +* (C) 2009,2010,2014,2015 Jack Lloyd +* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_HTTP_UTIL) + #include +#endif + +#if defined(BOTAN_HAS_UUID) + #include +#endif + +namespace Botan_CLI { + +class Print_Help final : public Command + { + public: + Print_Help() : Command("help") {} + + std::string help_text() const override + { + std::map>> grouped_commands; + + auto reg_commands = Command::registered_cmds(); + for(const auto& cmd_name : reg_commands) + { + auto cmd = Command::get_cmd(cmd_name); + if(cmd) + { + grouped_commands[cmd->group()].push_back(std::move(cmd)); + } + } + + const std::map groups_description { + { "encryption", "Encryption" }, + { "compression", "Compression" }, + { "codec", "Encoders/Decoders" }, + { "hash", "Hash Functions" }, + { "hmac", "HMAC" }, + { "info", "Informational" }, + { "numtheory", "Number Theory" }, + { "passhash", "Password Hashing" }, + { "psk", "PSK Database" }, + { "pubkey", "Public Key Cryptography" }, + { "tls", "TLS" }, + { "tss", "Secret Sharing" }, + { "x509", "X.509" }, + { "misc", "Miscellaneous" } + }; + + std::ostringstream oss; + + oss << "Usage: botan \n"; + oss << "All commands support --verbose --help --output= --error-output= --rng-type= --drbg-seed=\n\n"; + oss << "Available commands:\n\n"; + + for(const auto& commands : grouped_commands) + { + std::string desc = commands.first; + if(desc.empty()) + { + continue; + } + + oss << Botan::search_map(groups_description, desc, desc) << ":\n"; + for(auto& cmd : commands.second) + { + oss << " " << std::setw(16) << std::left << cmd->cmd_name() << " " << cmd->description() << "\n"; + } + oss << "\n"; + } + + return oss.str(); + } + + std::string group() const override + { + return ""; + } + + std::string description() const override + { + return "Prints a help string"; + } + + void go() override + { + this->set_return_code(1); + output() << help_text(); + } + }; + +BOTAN_REGISTER_COMMAND("help", Print_Help); + +class Has_Command final : public Command + { + public: + Has_Command() : Command("has_command cmd") {} + + std::string group() const override + { + return "info"; + } + + std::string description() const override + { + return "Test if a command is available"; + } + + void go() override + { + const std::string cmd = get_arg("cmd"); + + bool exists = false; + for(auto registered_cmd : Command::registered_cmds()) + { + if(cmd == registered_cmd) + { + exists = true; + break; + } + } + + if(verbose()) + { + output() << "Command '" << cmd << "' is " + << (exists ? "": "not ") << "available\n"; + } + + if(exists == false) + this->set_return_code(1); + } + }; + +BOTAN_REGISTER_COMMAND("has_command", Has_Command); + +class Config_Info final : public Command + { + public: + Config_Info() : Command("config info_type") {} + + std::string help_text() const override + { + return "Usage: config info_type\n" + " prefix: Print install prefix\n" + " cflags: Print include params\n" + " ldflags: Print linker params\n" + " libs: Print libraries\n"; + } + + std::string group() const override + { + return "info"; + } + + std::string description() const override + { + return "Print the used prefix, cflags, ldflags or libs"; + } + + void go() override + { + const std::string arg = get_arg("info_type"); + + if(arg == "prefix") + { + output() << BOTAN_INSTALL_PREFIX << "\n"; + } + else if(arg == "cflags") + { + output() << "-I" << BOTAN_INSTALL_PREFIX << "/" << BOTAN_INSTALL_HEADER_DIR << "\n"; + } + else if(arg == "ldflags") + { + if(*BOTAN_LINK_FLAGS) + output() << BOTAN_LINK_FLAGS << ' '; + output() << "-L" << BOTAN_INSTALL_LIB_DIR << "\n"; + } + else if(arg == "libs") + { + output() << "-lbotan-" << Botan::version_major() << " " << BOTAN_LIB_LINK << "\n"; + } + else + { + throw CLI_Usage_Error("Unknown option to botan config " + arg); + } + } + }; + +BOTAN_REGISTER_COMMAND("config", Config_Info); + +class Version_Info final : public Command + { + public: + Version_Info() : Command("version --full") {} + + std::string group() const override + { + return "info"; + } + + std::string description() const override + { + return "Print version info"; + } + + void go() override + { + if(flag_set("full")) + { + output() << Botan::version_string() << "\n"; + } + else + { + output() << Botan::short_version_string() << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("version", Version_Info); + +class Print_Cpuid final : public Command + { + public: + Print_Cpuid() : Command("cpuid") {} + + std::string group() const override + { + return "info"; + } + + std::string description() const override + { + return "List available processor flags (aes_ni, SIMD extensions, ...)"; + } + + void go() override + { + output() << "CPUID flags: " << Botan::CPUID::to_string() << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("cpuid", Print_Cpuid); + +class Cycle_Counter final : public Command + { + public: + Cycle_Counter() : Command("cpu_clock --test-duration=500") {} + + std::string group() const override + { + return "info"; + } + + std::string description() const override + { + return "Estimate the speed of the CPU cycle counter"; + } + + void go() override + { + if(Botan::OS::get_cpu_cycle_counter() == 0) + { + output() << "No CPU cycle counter on this machine\n"; + return; + } + + const uint64_t test_duration_ns = get_arg_sz("test-duration") * 1000000; + + if(test_duration_ns == 0) + { + output() << "Invalid test duration\n"; + return; + } + + const uint64_t cc_start = Botan::OS::get_cpu_cycle_counter(); + const uint64_t ns_start = Botan::OS::get_system_timestamp_ns(); + + uint64_t cc_end = 0; + uint64_t ns_end = ns_start; + + while((ns_end - ns_start) < test_duration_ns) + { + ns_end = Botan::OS::get_system_timestamp_ns(); + cc_end = Botan::OS::get_cpu_cycle_counter(); + } + + if(cc_end <= cc_start) + { + output() << "Cycle counter seems to have wrapped, try again\n"; + return; + } + + if(ns_end <= ns_start) + { + output() << "System clock seems to have wrapped (?!?)\n"; + return; + } + + const uint64_t ns_duration = ns_end - ns_start; + const uint64_t cc_duration = cc_end - cc_start; + + const double ratio = static_cast(cc_duration) / ns_duration; + + if(ratio >= 1.0) + { + // GHz + output() << "Estimated CPU clock " << std::setprecision(2) << ratio << " GHz\n"; + } + else + { + // MHz + output() << "Estimated CPU clock " << static_cast(ratio * 1000) << " MHz\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("cpu_clock", Cycle_Counter); + +#if defined(BOTAN_HAS_UUID) + +class Print_UUID final : public Command + { + public: + Print_UUID() : Command("uuid") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Print a random UUID"; + } + + void go() override + { + Botan::UUID uuid(rng()); + output() << uuid.to_string() << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("uuid", Print_UUID); + +#endif + +#if defined(BOTAN_HAS_HTTP_UTIL) + +class HTTP_Get final : public Command + { + public: + HTTP_Get() : Command("http_get --redirects=1 --timeout=3000 url") {} + + std::string group() const override + { + return "misc"; + } + + std::string description() const override + { + return "Retrieve resource from the passed http/https url"; + } + + void go() override + { + const std::string url = get_arg("url"); + const std::chrono::milliseconds timeout(get_arg_sz("timeout")); + const size_t redirects = get_arg_sz("redirects"); + + output() << Botan::HTTP::GET_sync(url, redirects, timeout) << "\n"; + } + }; + +BOTAN_REGISTER_COMMAND("http_get", HTTP_Get); + +#endif // http_util + +} diff --git a/comm/third_party/botan/src/cli/x509.cpp b/comm/third_party/botan/src/cli/x509.cpp new file mode 100644 index 0000000000..a92ec1309e --- /dev/null +++ b/comm/third_party/botan/src/cli/x509.cpp @@ -0,0 +1,417 @@ +/* +* (C) 2010,2014,2015,2018 Jack Lloyd +* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "cli.h" + +#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_OCSP) + #include +#endif + +#if defined(BOTAN_HAS_CERTSTOR_SYSTEM) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_CERTSTOR_SYSTEM) + +class Trust_Root_Info final : public Command + { + public: + Trust_Root_Info() : Command("trust_roots --dn --dn-only --display") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "List certs in the system trust store"; + } + + void go() override + { + Botan::System_Certificate_Store trust_roots; + + const auto dn_list = trust_roots.all_subjects(); + + if(flag_set("dn-only")) + { + for(auto dn : dn_list) + output() << dn << "\n"; + } + else + { + for(auto dn : dn_list) + { + // Some certstores have more than one cert with a particular DN + for(auto cert : trust_roots.find_all_certs(dn, std::vector())) + { + if(flag_set("dn")) + output() << "# " << dn << "\n"; + + if(flag_set("display")) + output() << cert->to_string() << "\n"; + + output() << cert->PEM_encode() << "\n"; + } + } + + } + } + + }; + +BOTAN_REGISTER_COMMAND("trust_roots", Trust_Root_Info); + +#endif + +class Sign_Cert final : public Command + { + public: + Sign_Cert() + : Command("sign_cert --ca-key-pass= --hash=SHA-256 " + "--duration=365 --emsa= ca_cert ca_key pkcs10_req") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "Create a CA-signed X.509 certificate from a PKCS #10 CSR"; + } + + void go() override + { + Botan::X509_Certificate ca_cert(get_arg("ca_cert")); + + const std::string key_file = get_arg("ca_key"); + const std::string pass = get_passphrase_arg("Password for " + key_file, "ca-key-pass"); + const std::string emsa = get_arg("emsa"); + const std::string hash = get_arg("hash"); + + std::unique_ptr key; + if(!pass.empty()) + { + key.reset(Botan::PKCS8::load_key(key_file, rng(), pass)); + } + else + { + key.reset(Botan::PKCS8::load_key(key_file, rng())); + } + + if(!key) + { + throw CLI_Error("Failed to load key from " + key_file); + } + + std::map options; + if(emsa.empty() == false) + options["padding"] = emsa; + + Botan::X509_CA ca(ca_cert, *key, options, hash, rng()); + + Botan::PKCS10_Request req(get_arg("pkcs10_req")); + + auto now = std::chrono::system_clock::now(); + + Botan::X509_Time start_time(now); + + typedef std::chrono::duration> days; + + Botan::X509_Time end_time(now + days(get_arg_sz("duration"))); + + Botan::X509_Certificate new_cert = ca.sign_request(req, rng(), start_time, end_time); + + output() << new_cert.PEM_encode(); + } + }; + +BOTAN_REGISTER_COMMAND("sign_cert", Sign_Cert); + +class Cert_Info final : public Command + { + public: + Cert_Info() : Command("cert_info --fingerprint file") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "Parse X.509 certificate and display data fields"; + } + + void go() override + { + const std::string arg_file = get_arg("file"); + + std::vector data = slurp_file(get_arg("file")); + + Botan::DataSource_Memory in(data); + + while(!in.end_of_data()) + { + try + { + Botan::X509_Certificate cert(in); + + try + { + output() << cert.to_string() << std::endl; + } + catch(Botan::Exception& e) + { + // to_string failed - report the exception and continue + output() << "X509_Certificate::to_string failed: " << e.what() << "\n"; + } + + if(flag_set("fingerprint")) + output() << "Fingerprint: " << cert.fingerprint("SHA-256") << std::endl; + } + catch(Botan::Exception& e) + { + if(!in.end_of_data()) + { + output() << "X509_Certificate parsing failed " << e.what() << "\n"; + } + } + } + } + }; + +BOTAN_REGISTER_COMMAND("cert_info", Cert_Info); + +#if defined(BOTAN_HAS_OCSP) && defined(BOTAN_HAS_HTTP_UTIL) + +class OCSP_Check final : public Command + { + public: + OCSP_Check() : Command("ocsp_check --timeout=3000 subject issuer") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "Verify an X.509 certificate against the issuers OCSP responder"; + } + + void go() override + { + Botan::X509_Certificate subject(get_arg("subject")); + Botan::X509_Certificate issuer(get_arg("issuer")); + std::chrono::milliseconds timeout(get_arg_sz("timeout")); + + Botan::Certificate_Store_In_Memory cas; + cas.add_certificate(issuer); + Botan::OCSP::Response resp = Botan::OCSP::online_check(issuer, subject, &cas, timeout); + + auto status = resp.status_for(issuer, subject, std::chrono::system_clock::now()); + + if(status == Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD) + { + output() << "OCSP check OK\n"; + } + else + { + output() << "OCSP check failed " << Botan::Path_Validation_Result::status_string(status) << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("ocsp_check", OCSP_Check); + +#endif // OCSP && HTTP + +class Cert_Verify final : public Command + { + public: + Cert_Verify() : Command("cert_verify subject *ca_certs") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "Verify if the passed X.509 certificate passes path validation"; + } + + void go() override + { + Botan::X509_Certificate subject_cert(get_arg("subject")); + Botan::Certificate_Store_In_Memory trusted; + + for(auto const& certfile : get_arg_list("ca_certs")) + { + trusted.add_certificate(Botan::X509_Certificate(certfile)); + } + + Botan::Path_Validation_Restrictions restrictions; + + Botan::Path_Validation_Result result = + Botan::x509_path_validate(subject_cert, + restrictions, + trusted); + + if(result.successful_validation()) + { + output() << "Certificate passes validation checks\n"; + } + else + { + output() << "Certificate did not validate - " << result.result_string() << "\n"; + } + } + }; + +BOTAN_REGISTER_COMMAND("cert_verify", Cert_Verify); + +class Gen_Self_Signed final : public Command + { + public: + Gen_Self_Signed() + : Command("gen_self_signed key CN --country= --dns= " + "--organization= --email= --path-limit=1 --days=365 --key-pass= --ca --hash=SHA-256 --emsa= --der") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "Generate a self signed X.509 certificate"; + } + + void go() override + { + const std::string key_file = get_arg("key"); + const std::string passphrase = get_passphrase_arg("Passphrase for " + key_file, "key-pass"); + std::unique_ptr key(Botan::PKCS8::load_key(key_file, rng(), passphrase)); + + if(!key) + { + throw CLI_Error("Failed to load key from " + get_arg("key")); + } + + const uint32_t lifetime = static_cast(get_arg_sz("days") * 24 * 60 * 60); + + Botan::X509_Cert_Options opts("", lifetime); + + opts.common_name = get_arg("CN"); + opts.country = get_arg("country"); + opts.organization = get_arg("organization"); + opts.email = get_arg("email"); + opts.more_dns = Botan::split_on(get_arg("dns"), ','); + const bool der_format = flag_set("der"); + + std::string emsa = get_arg("emsa"); + + if(emsa.empty() == false) + opts.set_padding_scheme(emsa); + + if(flag_set("ca")) + { + opts.CA_key(get_arg_sz("path-limit")); + } + + Botan::X509_Certificate cert = Botan::X509::create_self_signed_cert(opts, *key, get_arg("hash"), rng()); + + if(der_format) + { + auto der = cert.BER_encode(); + output().write(reinterpret_cast(der.data()), der.size()); + } + else + output() << cert.PEM_encode(); + } + }; + +BOTAN_REGISTER_COMMAND("gen_self_signed", Gen_Self_Signed); + +class Generate_PKCS10 final : public Command + { + public: + Generate_PKCS10() + : Command("gen_pkcs10 key CN --country= --organization= " + "--ca --path-limit=1 --email= --dns= --ext-ku= --key-pass= --hash=SHA-256 --emsa=") {} + + std::string group() const override + { + return "x509"; + } + + std::string description() const override + { + return "Generate a PKCS #10 certificate signing request (CSR)"; + } + + void go() override + { + std::unique_ptr key(Botan::PKCS8::load_key(get_arg("key"), rng(), get_arg("key-pass"))); + + if(!key) + { + throw CLI_Error("Failed to load key from " + get_arg("key")); + } + + Botan::X509_Cert_Options opts; + + opts.common_name = get_arg("CN"); + opts.country = get_arg("country"); + opts.organization = get_arg("organization"); + opts.email = get_arg("email"); + opts.more_dns = Botan::split_on(get_arg("dns"), ','); + + if(flag_set("ca")) + { + opts.CA_key(get_arg_sz("path-limit")); + } + + for(std::string ext_ku : Botan::split_on(get_arg("ext-ku"), ',')) + { + opts.add_ex_constraint(ext_ku); + } + + std::string emsa = get_arg("emsa"); + + if(emsa.empty() == false) + opts.set_padding_scheme(emsa); + + Botan::PKCS10_Request req = Botan::X509::create_cert_req(opts, *key, get_arg("hash"), rng()); + + output() << req.PEM_encode(); + } + }; + +BOTAN_REGISTER_COMMAND("gen_pkcs10", Generate_PKCS10); + +} + +#endif diff --git a/comm/third_party/botan/src/configs/astyle.rc b/comm/third_party/botan/src/configs/astyle.rc new file mode 100644 index 0000000000..dd2c7a35db --- /dev/null +++ b/comm/third_party/botan/src/configs/astyle.rc @@ -0,0 +1,14 @@ +--style=whitesmith +--indent=spaces=3 +--attach-namespaces +--break-one-line-headers +--convert-tabs +--max-code-length=120 +--indent-preproc-block +#--pad-oper +--pad-comma +--unpad-paren +--align-pointer=type +--align-reference=type +-j # --add-braces / --add-brackets +-J # --add-one-line-braces / --add-one-line-brackets diff --git a/comm/third_party/botan/src/configs/coverage.rc b/comm/third_party/botan/src/configs/coverage.rc new file mode 100644 index 0000000000..d93af43e2e --- /dev/null +++ b/comm/third_party/botan/src/configs/coverage.rc @@ -0,0 +1,18 @@ +# .coveragerc to control coverage.py +[run] +branch = True + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain if non-runnable code isn't run: + if 0: + def main + if __name__ == .__main__.: + + # Exclude tests + def test + diff --git a/comm/third_party/botan/src/configs/eclipse.xml b/comm/third_party/botan/src/configs/eclipse.xml new file mode 100644 index 0000000000..3fff4b0968 --- /dev/null +++ b/comm/third_party/botan/src/configs/eclipse.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/comm/third_party/botan/src/configs/indent.el b/comm/third_party/botan/src/configs/indent.el new file mode 100644 index 0000000000..7fa2540b0d --- /dev/null +++ b/comm/third_party/botan/src/configs/indent.el @@ -0,0 +1,55 @@ +; This Emacs Lips code defines the indentation style used in Botan. If doesn't +; get everything perfectly correct, but it's pretty close. Copy this code into +; your .emacs file, or use M-x eval-buffer. Make sure to also set +; indent-tabs-mode to nil so spaces are inserted instead. +; +; This style is basically Whitesmiths style with 3 space indents (the Emacs +; "whitesmith" style seems more like a weird Whitesmiths/Allman mutant style). +; +; To activate using this style, open the file you want to edit and run this: +; M-x c-set-style and then enter "botan". + +(setq botan-style '( + (c-basic-offset . 3) + (c-comment-only-line-offset . 0) + (c-offsets-alist + (c . 0) + (comment-intro . 0) + + (statement-block-intro . 0) + (statement-cont . +) + + (substatement . +) + (substatement-open . +) + + (block-open . +) + (block-close . 0) + + (defun-open . +) + (defun-close . 0) + (defun-block-intro . 0) + (func-decl-cont . +) + + (class-open . +) + (class-close . +) + (inclass . +) + (access-label . -) + (inline-open . +) + (inline-close . 0) + + (extern-lang-open . 0) + (extern-lang-close . 0) + (inextern-lang . 0) + + (statement-case-open +) + + (namespace-open . 0) + (namespace-close . 0) + (innamespace . 0) + + (label . 0) + ) +)) + +(add-hook 'c++-mode-common-hook + (function (lambda () (c-add-style "botan" botan-style nil)))) diff --git a/comm/third_party/botan/src/configs/pylint.rc b/comm/third_party/botan/src/configs/pylint.rc new file mode 100644 index 0000000000..dd7e907474 --- /dev/null +++ b/comm/third_party/botan/src/configs/pylint.rc @@ -0,0 +1,379 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=3 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" + +disable=missing-docstring,no-else-return,logging-not-lazy,locally-disabled,import-outside-toplevel,super-with-arguments,raise-missing-from + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{0,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{0,30}$ + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,45}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,45}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{0,45}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{0,45}$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{1,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{1,30}$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,45}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,45}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). This supports can work +# with qualified names. +ignored-classes=LexResult,argv + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_[a-z]*$ + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=180 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=3500 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=8 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=32 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=32 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/comm/third_party/botan/src/configs/sonar-project.properties b/comm/third_party/botan/src/configs/sonar-project.properties new file mode 100644 index 0000000000..38c214642f --- /dev/null +++ b/comm/third_party/botan/src/configs/sonar-project.properties @@ -0,0 +1,18 @@ +sonar.host.url=https://sonarcloud.io + +sonar.organization=randombit-github +sonar.projectKey=botan + +sonar.cfamily.threads=3 + +sonar.projectName=Botan +sonar.sources=src +sonar.language=cpp +sonar.cpp.file.suffixes=.cpp,.h +sonar.cfamily.build-wrapper-output=bw-outputs +sonar.sourceEncoding=UTF-8 + +# Sonar thinks these are duplicates +sonar.exclusions=build/include/botan/*.h,build/include/botan/internal/*.h,build/include/external/*.h + +sonar.cfamily.llvm-cov.reportPath=build/cov_report.txt diff --git a/comm/third_party/botan/src/configs/sphinx/conf.py b/comm/third_party/botan/src/configs/sphinx/conf.py new file mode 100644 index 0000000000..cc39de1966 --- /dev/null +++ b/comm/third_party/botan/src/configs/sphinx/conf.py @@ -0,0 +1,220 @@ +# -* coding: utf-8 -*- +# Sphinx configuration file + +import sys +import re + +#import sphinx + +def check_for_tag(tag): + # Nasty hack :( + try: + opt_t = sys.argv.index('-t') + opt_tag = sys.argv.index(tag) + return opt_t + 1 == opt_tag + except ValueError: + return False + + +def parse_version_file(version_path): + version_file = open(version_path) + key_and_val = re.compile(r"([a-z_]+) = ([a-zA-Z0-9:\-\']+)") + + results = {} + for line in version_file.readlines(): + if not line or line[0] == '#': + continue + match = key_and_val.match(line) + if match: + key = match.group(1) + val = match.group(2) + + if val == 'None': + val = None + elif val.startswith("'") and val.endswith("'"): + val = val[1:len(val)-1] + else: + val = int(val) + + results[key] = val + return results + +version_info = parse_version_file('../../build-data/version.txt') + +version_major = version_info['release_major'] +version_minor = version_info['release_minor'] +version_patch = version_info['release_patch'] + +is_website_build = check_for_tag('website') + +needs_sphinx = '1.2' + +templates_path = ['templates'] + +source_suffix = '.rst' + +source_encoding = 'utf-8-sig' + +master_doc = 'contents' + +project = u'botan' +copyright = u'2000-2017, The Botan Authors' + +version = '%d.%d' % (version_major, version_minor) +release = '%d.%d.%d' % (version_major, version_minor, version_patch) + +#today = '' +today_fmt = '%Y-%m-%d' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = False + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +highlight_language = 'cpp' + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +try: + # On Arch this is python-sphinx_rtd_theme + import sphinx_rtd_theme + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +except ImportError as e: + html_theme = 'agogo' + html_theme_path = [] + print("Ignoring ImportError and using old theme") + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = 'Botan' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '%Y-%m-%d' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +html_show_copyright = False + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +if is_website_build: + html_use_opensearch = 'https://botan.randombit.net/' +else: + html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'botandoc' + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). + +authors = u'Jack Lloyd \\and Daniel Neus \\and Ren\u00e9 Korthaus \\and Juraj Somorovsky \\and Tobias Niemann' +latex_documents = [ + ('contents', 'botan.tex', u'Botan Reference Guide', authors, 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +latex_show_pagerefs = False + +# If true, show URL addresses after external links. +latex_show_urls = 'inline' + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +latex_domain_indices = False + +latex_elements = { + 'printindex': '\\footnotesize\\raggedright\\printindex' +} diff --git a/comm/third_party/botan/src/configs/sphinx/templates/layout.html b/comm/third_party/botan/src/configs/sphinx/templates/layout.html new file mode 100644 index 0000000000..c907c75974 --- /dev/null +++ b/comm/third_party/botan/src/configs/sphinx/templates/layout.html @@ -0,0 +1,9 @@ +{% extends "!layout.html" %} + +{% block header %} +
+
+

{{ shorttitle|e }}

+
+
+{% endblock %} diff --git a/comm/third_party/botan/src/fuzzer/asn1.cpp b/comm/third_party/botan/src/fuzzer/asn1.cpp new file mode 100644 index 0000000000..89073991d1 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/asn1.cpp @@ -0,0 +1,43 @@ +/* +* (C) 2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +class ASN1_Parser final : public Botan::ASN1_Formatter + { + public: + ASN1_Parser() : Botan::ASN1_Formatter(true, 64) {} + + protected: + std::string format(Botan::ASN1_Tag, Botan::ASN1_Tag, size_t, size_t, + const std::string&) const override + { + return ""; + } + + std::string format_bin(Botan::ASN1_Tag, Botan::ASN1_Tag, + const std::vector&) const override + { + return ""; + } + }; + +void fuzz(const uint8_t in[], size_t len) + { + try + { + /* + * Here we use an uninitialized ofstream so the fuzzer doesn't spend time + * on actual output formatting, no memory is allocated, etc. + */ + std::ofstream out; + ASN1_Parser printer; + printer.print_to_stream(out, in, len); + } + catch(Botan::Exception& e) { } + } diff --git a/comm/third_party/botan/src/fuzzer/barrett.cpp b/comm/third_party/botan/src/fuzzer/barrett.cpp new file mode 100644 index 0000000000..ebc6001971 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/barrett.cpp @@ -0,0 +1,49 @@ +/* +* (C) 2018,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + static const size_t max_bits = 4096; + + if(len <= 4) + return; + + if(len > 2*(max_bits/8)) + return; + + const size_t x_len = 2 * ((len + 2) / 3); + + Botan::BigInt x = Botan::BigInt::decode(in, x_len); + const Botan::BigInt p = Botan::BigInt::decode(in + x_len, len - x_len); + + if(p.is_zero()) + return; + + const size_t x_bits = x.bits(); + if(x_bits % 8 == 0 && x_bits / 8 == x_len) + x.flip_sign(); + + const Botan::BigInt ref = x % p; + + const Botan::Modular_Reducer mod_p(p); + const Botan::BigInt z = mod_p.reduce(x); + + const Botan::BigInt ct = ct_modulo(x, p); + + if(ref != z || ref != ct) + { + FUZZER_WRITE_AND_CRASH("X = " << x << "\n" + << "P = " << p << "\n" + << "Barrett = " << z << "\n" + << "Ct = " << ct << "\n" + << "Ref = " << ref << "\n"); + } + } diff --git a/comm/third_party/botan/src/fuzzer/bn_cmp.cpp b/comm/third_party/botan/src/fuzzer/bn_cmp.cpp new file mode 100644 index 0000000000..48c25f3247 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/bn_cmp.cpp @@ -0,0 +1,74 @@ +/* +* (C) 2021 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" + +#include + +void fuzz(const uint8_t in[], size_t len) + { + const size_t max_bits = 512; + + if(len < 3 || len > 1 + 2*(max_bits/8)) + return; + + const uint8_t signs = in[0]; + const size_t x_len = (len - 1) / 2; + + Botan::BigInt x = Botan::BigInt::decode(in + 1, x_len); + Botan::BigInt y = Botan::BigInt::decode(in + 1 + x_len, len - x_len - 1); + + if(signs & 1) + x.flip_sign(); + if(signs & 2) + y.flip_sign(); + + const Botan::BigInt d1 = x - y; + const Botan::BigInt d2 = y - x; + + FUZZER_ASSERT_TRUE(d1.cmp(d2, false) == 0); + + const bool is_eq = (x == y); + const bool is_lt = (x < y); + const bool is_gt = (x > y); + const bool is_lte = (x <= y); + const bool is_gte = (x >= y); + + if(is_eq) + { + FUZZER_ASSERT_TRUE(d1.is_zero()); + FUZZER_ASSERT_TRUE(d2.is_zero()); + } + + if(is_lte) + { + FUZZER_ASSERT_TRUE(is_lt || is_eq); + } + + if(is_gte) + { + FUZZER_ASSERT_TRUE(is_gt || is_eq); + } + + if(is_lt) + { + FUZZER_ASSERT_TRUE(!is_gt); + FUZZER_ASSERT_TRUE(d1.is_nonzero()); + FUZZER_ASSERT_TRUE(d2.is_nonzero()); + FUZZER_ASSERT_TRUE(d1.is_negative()); + FUZZER_ASSERT_TRUE(d2.is_positive()); + } + + if(is_gt) + { + FUZZER_ASSERT_TRUE(!is_lt); + FUZZER_ASSERT_TRUE(d1.is_nonzero()); + FUZZER_ASSERT_TRUE(d2.is_nonzero()); + FUZZER_ASSERT_TRUE(d1.is_positive()); + FUZZER_ASSERT_TRUE(d2.is_negative()); + } + } + diff --git a/comm/third_party/botan/src/fuzzer/bn_sqr.cpp b/comm/third_party/botan/src/fuzzer/bn_sqr.cpp new file mode 100644 index 0000000000..f507c4a79c --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/bn_sqr.cpp @@ -0,0 +1,24 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" + +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 8192/8) + return; + + Botan::BigInt x = Botan::BigInt::decode(in, len); + + Botan::BigInt x_sqr = square(x); + Botan::BigInt x_mul = x * x; + + FUZZER_ASSERT_EQUAL(x_sqr, x_mul); + } + diff --git a/comm/third_party/botan/src/fuzzer/cert.cpp b/comm/third_party/botan/src/fuzzer/cert.cpp new file mode 100644 index 0000000000..215a294002 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/cert.cpp @@ -0,0 +1,22 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > max_fuzzer_input_size) + return; + + try + { + Botan::DataSource_Memory input(in, len); + Botan::X509_Certificate cert(input); + } + catch(Botan::Exception& e) { } + } diff --git a/comm/third_party/botan/src/fuzzer/crl.cpp b/comm/third_party/botan/src/fuzzer/crl.cpp new file mode 100644 index 0000000000..e41d523a91 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/crl.cpp @@ -0,0 +1,19 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::DataSource_Memory input(in, len); + Botan::X509_CRL crl(input); + } + catch(Botan::Exception& e) {} + } diff --git a/comm/third_party/botan/src/fuzzer/divide.cpp b/comm/third_party/botan/src/fuzzer/divide.cpp new file mode 100644 index 0000000000..b6342ff7d8 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/divide.cpp @@ -0,0 +1,52 @@ +/* +* (C) 2015,2016,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len % 2 == 1 || len > 2*4096/8) + return; + + // Save on allocations by making these static + static Botan::BigInt x, y, q, r, ct_q, ct_r, z; + + x = Botan::BigInt::decode(in, len / 2); + y = Botan::BigInt::decode(in + len / 2, len / 2); + + if(y == 0) + return; + + Botan::divide(x, y, q, r); + + FUZZER_ASSERT_TRUE(r < y); + + z = q*y + r; + + FUZZER_ASSERT_EQUAL(z, x); + + Botan::ct_divide(x, y, ct_q, ct_r); + + FUZZER_ASSERT_EQUAL(q, ct_q); + FUZZER_ASSERT_EQUAL(r, ct_r); + + // Now divide by just low byte of y + + y = y.byte_at(0); + if(y == 0) + y = 251; + Botan::divide(x, y, q, r); + + z = q*y + r; + FUZZER_ASSERT_EQUAL(z, x); + + uint8_t r8; + Botan::ct_divide_u8(x, y.byte_at(0), ct_q, r8); + FUZZER_ASSERT_EQUAL(ct_q, q); + FUZZER_ASSERT_EQUAL(r8, r.byte_at(0)); + + } + diff --git a/comm/third_party/botan/src/fuzzer/ecc_bp256.cpp b/comm/third_party/botan/src/fuzzer/ecc_bp256.cpp new file mode 100644 index 0000000000..4c1186f06a --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ecc_bp256.cpp @@ -0,0 +1,16 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*256/8) + return; + + static Botan::EC_Group bp256("brainpool256r1"); + return check_ecc_math(bp256, in, len); + } diff --git a/comm/third_party/botan/src/fuzzer/ecc_helper.h b/comm/third_party/botan/src/fuzzer/ecc_helper.h new file mode 100644 index 0000000000..4df23a5722 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ecc_helper.h @@ -0,0 +1,107 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef ECC_HELPERS_H_ +#define ECC_HELPERS_H_ + +#include "fuzzers.h" +#include +#include +#include + +namespace { + +inline std::ostream& operator<<(std::ostream& o, const Botan::PointGFp& point) + { + o << point.get_affine_x() << "," << point.get_affine_y(); + return o; + } + +Botan::BigInt decompress_point(bool yMod2, + const Botan::BigInt& x, + const Botan::BigInt& curve_p, + const Botan::BigInt& curve_a, + const Botan::BigInt& curve_b) + { + Botan::BigInt xpow3 = x * x * x; + + Botan::BigInt g = curve_a * x; + g += xpow3; + g += curve_b; + g = g % curve_p; + + Botan::BigInt z = ressol(g, curve_p); + + if(z < 0) + throw Botan::Exception("Could not perform square root"); + + if(z.get_bit(0) != yMod2) + z = curve_p - z; + + return z; + } + +void check_ecc_math(const Botan::EC_Group& group, + const uint8_t in[], size_t len) + { + // These depend only on the group, which is also static + static const Botan::PointGFp base_point = group.get_base_point(); + + // This is shared across runs to reduce overhead + static std::vector ws(Botan::PointGFp::WORKSPACE_SIZE); + + const size_t hlen = len / 2; + const Botan::BigInt a = Botan::BigInt::decode(in, hlen); + const Botan::BigInt b = Botan::BigInt::decode(in + hlen, len - hlen); + const Botan::BigInt c = a + b; + + const Botan::PointGFp P1 = base_point * a; + const Botan::PointGFp Q1 = base_point * b; + const Botan::PointGFp R1 = base_point * c; + + const Botan::PointGFp S1 = P1 + Q1; + const Botan::PointGFp T1 = Q1 + P1; + + FUZZER_ASSERT_EQUAL(S1, R1); + FUZZER_ASSERT_EQUAL(T1, R1); + + const Botan::PointGFp P2 = group.blinded_base_point_multiply(a, fuzzer_rng(), ws); + const Botan::PointGFp Q2 = group.blinded_base_point_multiply(b, fuzzer_rng(), ws); + const Botan::PointGFp R2 = group.blinded_base_point_multiply(c, fuzzer_rng(), ws); + const Botan::PointGFp S2 = P2 + Q2; + const Botan::PointGFp T2 = Q2 + P2; + + FUZZER_ASSERT_EQUAL(S2, R2); + FUZZER_ASSERT_EQUAL(T2, R2); + + const Botan::PointGFp P3 = group.blinded_var_point_multiply(base_point, a, fuzzer_rng(), ws); + const Botan::PointGFp Q3 = group.blinded_var_point_multiply(base_point, b, fuzzer_rng(), ws); + const Botan::PointGFp R3 = group.blinded_var_point_multiply(base_point, c, fuzzer_rng(), ws); + const Botan::PointGFp S3 = P3 + Q3; + const Botan::PointGFp T3 = Q3 + P3; + + FUZZER_ASSERT_EQUAL(S3, R3); + FUZZER_ASSERT_EQUAL(T3, R3); + + FUZZER_ASSERT_EQUAL(S1, S2); + FUZZER_ASSERT_EQUAL(S1, S3); + + try + { + const auto yp = decompress_point(true, a, group.get_p(), group.get_a(), group.get_b()); + const auto pt_p = group.blinded_var_point_multiply(group.point(a, yp), b, fuzzer_rng(), ws); + + const auto yn = -yp; + const auto pt_n = group.blinded_var_point_multiply(group.point(a, yn), b, fuzzer_rng(), ws); + + FUZZER_ASSERT_EQUAL(pt_p, -pt_n); + } + catch(...) {} + } + +} + +#endif diff --git a/comm/third_party/botan/src/fuzzer/ecc_p256.cpp b/comm/third_party/botan/src/fuzzer/ecc_p256.cpp new file mode 100644 index 0000000000..c00be71b62 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ecc_p256.cpp @@ -0,0 +1,15 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*256/8) + return; + static Botan::EC_Group p256("secp256r1"); + return check_ecc_math(p256, in, len); + } diff --git a/comm/third_party/botan/src/fuzzer/ecc_p384.cpp b/comm/third_party/botan/src/fuzzer/ecc_p384.cpp new file mode 100644 index 0000000000..1b58da9584 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ecc_p384.cpp @@ -0,0 +1,15 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*384/8) + return; + static Botan::EC_Group p384("secp384r1"); + return check_ecc_math(p384, in, len); + } diff --git a/comm/third_party/botan/src/fuzzer/ecc_p521.cpp b/comm/third_party/botan/src/fuzzer/ecc_p521.cpp new file mode 100644 index 0000000000..3b9ed2d5c9 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ecc_p521.cpp @@ -0,0 +1,15 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include "ecc_helper.h" + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*(521+7)/8) + return; + static Botan::EC_Group p521("secp521r1"); + return check_ecc_math(p521, in, len); + } diff --git a/comm/third_party/botan/src/fuzzer/fuzzers.h b/comm/third_party/botan/src/fuzzer/fuzzers.h new file mode 100644 index 0000000000..ee78f7a6dd --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/fuzzers.h @@ -0,0 +1,150 @@ +/* +* (C) 2015,2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FUZZER_DRIVER_H_ +#define BOTAN_FUZZER_DRIVER_H_ + +#include +#include // for setenv +#include +#include +#include +#include + +static const size_t max_fuzzer_input_size = 8192; + +extern void fuzz(const uint8_t in[], size_t len); + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len); + +extern "C" int LLVMFuzzerInitialize(int *, char ***) + { + /* + * This disables the mlock pool, as overwrites within the pool are + * opaque to ASan or other instrumentation. + */ + ::setenv("BOTAN_MLOCK_POOL_SIZE", "0", 1); + return 0; + } + +// Called by main() in libFuzzer or in main for AFL below +extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len) + { + if(len <= max_fuzzer_input_size) + { + fuzz(in, len); + } + return 0; + } + +// Some helpers for the fuzzer jigs + +inline Botan::RandomNumberGenerator& fuzzer_rng() + { + static Botan::ChaCha_RNG rng(Botan::secure_vector(32)); + return rng; + } + +#define FUZZER_WRITE_AND_CRASH(expr) \ + do { std::cerr << expr; abort(); } while(0) + +#define FUZZER_ASSERT_EQUAL(x, y) do { \ + if(x != y) { \ + FUZZER_WRITE_AND_CRASH(#x << " = " << x << " !=\n" \ + << #y << " = " << y << "\n"); \ + } } while(0) + +#define FUZZER_ASSERT_TRUE(e) \ + do { \ + if(!(e)) { \ + FUZZER_WRITE_AND_CRASH("Expression " << #e << " was false"); \ + } } while(0) + +#if defined(BOTAN_FUZZER_IS_AFL) || defined(BOTAN_FUZZER_IS_TEST) + +/* Stub for AFL */ + +#if defined(BOTAN_FUZZER_IS_AFL) && !defined(__AFL_COMPILER) + #error "Build configured for AFL but not being compiled by AFL compiler" +#endif + +#if defined(BOTAN_FUZZER_IS_TEST) + +#include + +namespace { + +int fuzz_files(char* files[]) + { + for(size_t i = 0; files[i]; ++i) + { + std::ifstream in(files[i]); + + if(in.good()) + { + std::vector buf(max_fuzzer_input_size); + in.read((char*)buf.data(), buf.size()); + const size_t got = in.gcount(); + buf.resize(got); + buf.shrink_to_fit(); + + LLVMFuzzerTestOneInput(buf.data(), got); + } + } + + return 0; + } + +} + +#endif + +int main(int argc, char* argv[]) + { + LLVMFuzzerInitialize(&argc, &argv); + +#if defined(BOTAN_FUZZER_IS_TEST) + if(argc > 1) + { + return fuzz_files(&argv[1]); + } +#endif + +#if defined(__AFL_LOOP) + while(__AFL_LOOP(1000)) +#endif + { + std::vector buf(max_fuzzer_input_size); + std::cin.read((char*)buf.data(), buf.size()); + const size_t got = std::cin.gcount(); + + buf.resize(got); + buf.shrink_to_fit(); + + LLVMFuzzerTestOneInput(buf.data(), got); + } + } + +#elif defined(BOTAN_FUZZER_IS_KLEE) + +#include + +int main(int argc, char* argv[]) + { + LLVMFuzzerInitialize(&argc, &argv); + + uint8_t input[max_fuzzer_input_size] = { 0 }; + klee_make_symbolic(&input, sizeof(input), "input"); + + size_t input_len = klee_range(0, sizeof(input), "input_len"); + + LLVMFuzzerTestOneInput(input, input_len); + } + +#endif + +#endif diff --git a/comm/third_party/botan/src/fuzzer/invert.cpp b/comm/third_party/botan/src/fuzzer/invert.cpp new file mode 100644 index 0000000000..5d34512f30 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/invert.cpp @@ -0,0 +1,82 @@ +/* +* (C) 2015,2016,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include + +namespace { + +Botan::BigInt ref_inverse_mod(const Botan::BigInt& n, const Botan::BigInt& mod) + { + if(n == 0 || mod < 2) + return 0; + if(n.is_even() && mod.is_even()) + return 0; + Botan::BigInt u = mod, v = n; + Botan::BigInt A = 1, B = 0, C = 0, D = 1; + + while(u.is_nonzero()) + { + const size_t u_zero_bits = Botan::low_zero_bits(u); + u >>= u_zero_bits; + for(size_t i = 0; i != u_zero_bits; ++i) + { + if(A.is_odd() || B.is_odd()) + { A += n; B -= mod; } + A >>= 1; B >>= 1; + } + + const size_t v_zero_bits = Botan::low_zero_bits(v); + v >>= v_zero_bits; + for(size_t i = 0; i != v_zero_bits; ++i) + { + if(C.is_odd() || D.is_odd()) + { C += n; D -= mod; } + C >>= 1; D >>= 1; + } + + if(u >= v) { u -= v; A -= C; B -= D; } + else { v -= u; C -= A; D -= B; } + } + + if(v != 1) + return 0; // no modular inverse + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static const size_t max_bits = 4096; + + if(len > 2*max_bits/8) + return; + + const Botan::BigInt x = Botan::BigInt::decode(in, len / 2); + Botan::BigInt mod = Botan::BigInt::decode(in + len / 2, len - len / 2); + + if(mod < 2) + return; + + const Botan::BigInt lib = Botan::inverse_mod(x, mod); + const Botan::BigInt ref = ref_inverse_mod(x, mod); + + if(ref != lib) + { + FUZZER_WRITE_AND_CRASH("X = " << x << "\n" + << "Mod = " << mod << "\n" + << "GCD(X,Mod) = " << gcd(x, mod) << "\n" + << "RefInv(X,Mod) = " << ref << "\n" + << "LibInv(X,Mod) = " << lib << "\n" + << "RefCheck = " << (x*ref)%mod << "\n" + << "LibCheck = " << (x*lib)%mod << "\n"); + } + } + diff --git a/comm/third_party/botan/src/fuzzer/mem_pool.cpp b/comm/third_party/botan/src/fuzzer/mem_pool.cpp new file mode 100644 index 0000000000..7227462887 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/mem_pool.cpp @@ -0,0 +1,193 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include +#include +#include +#include + +#include + +namespace { + +size_t compute_expected_alignment(size_t plen) + { + if(Botan::is_power_of_2(plen)) + { + return plen; + } + else + { + return 8; + } + } + +struct RawPage + { + public: + RawPage(void* p) : m_p(p) {} + ~RawPage() { std::free(m_p); } + + RawPage(const RawPage& other) = default; + RawPage& operator=(const RawPage& other) = default; + + RawPage(RawPage&& other) : m_p(nullptr) + { + std::swap(m_p, other.m_p); + } + + RawPage& operator=(RawPage&& other) + { + if(this != &other) + { + std::swap(m_p, other.m_p); + } + return (*this); + } + + void* ptr() const { return m_p; } + private: + void* m_p; + }; + +std::vector allocate_raw_pages(size_t count, size_t page_size) + { + std::vector pages; + pages.reserve(count); + + for(size_t i = 0; i != count; ++i) + { + void* ptr = nullptr; + + int rc = ::posix_memalign(&ptr, page_size, page_size); + FUZZER_ASSERT_EQUAL(rc, 0); + + if(ptr) + { + pages.push_back(RawPage(ptr)); + } + } + + return pages; + } + +} + +void fuzz(const uint8_t in[], size_t in_len) + { + const size_t page_count = 4; + const size_t page_size = 4096; + + // static to avoid repeated allocations + static std::vector raw_mem = allocate_raw_pages(page_count, page_size); + + std::vector mem_pages; + mem_pages.reserve(raw_mem.size()); + for(size_t i = 0; i != raw_mem.size(); ++i) + mem_pages.push_back(raw_mem[i].ptr()); + + Botan::Memory_Pool pool(mem_pages, page_size); + std::map ptrs; + + while(in_len > 0) + { + const uint8_t op = in[0] % 2; + size_t idx = (in[0] >> 1); + in += 1; + in_len -= 1; + + if(in_len > 0 && idx < 4) + { + idx = idx * 256 + in[0]; + in += 1; + in_len -= 1; + } + + //printf("%d %d\n", op, idx); + + if(op == 0) + { + const size_t plen = idx + 1; // ensure non-zero + uint8_t* p = static_cast(pool.allocate(plen)); + + if(p) + { + const size_t expected_alignment = compute_expected_alignment(plen); + const size_t alignment = reinterpret_cast(p) % expected_alignment; + if(alignment != 0) + { + FUZZER_WRITE_AND_CRASH("Pointer allocated non-aligned pointer " << static_cast(p) << " for len " << plen + << " expected " << expected_alignment << " got " << alignment); + } + + //printf("alloc %d -> %p\n", plen, p); + + for(size_t i = 0; i != plen; ++i) + { + if(p[i] != 0) + { + FUZZER_WRITE_AND_CRASH("Pool gave out non-zeroed memory"); + } + } + + // verify it becomes zeroed later + std::memset(p, idx, plen); + + auto insert = ptrs.insert(std::make_pair(p, plen)); + if(insert.second == false) + { + FUZZER_WRITE_AND_CRASH("Pointer " << static_cast(p) << " already existed\n"); + } + + auto itr = insert.first; + + // Verify this pointer doesn't overlap with the one before it + if(itr != ptrs.begin()) + { + auto before = std::prev(itr); + auto ptr_before = *before; + + if(ptr_before.first + ptr_before.second > p) + { + FUZZER_WRITE_AND_CRASH("Previous " << static_cast(ptr_before.first) << "/" << ptr_before.second << + " overlaps with new " << static_cast(p)); + } + } + + auto after = std::next(itr); + + if(after != ptrs.end()) + { + if(p + plen > after->first) + { + FUZZER_WRITE_AND_CRASH("New " << static_cast(p) << "/" << plen + << " overlaps following " << static_cast(after->first)); + } + } + } + } + else if(op == 1) + { + if(ptrs.empty()) + return; + + size_t which_ptr = idx % ptrs.size(); + + auto itr = ptrs.begin(); + + while(which_ptr-- > 0) + { + ++itr; + } + + //printf("free %p %d\n", itr->first, itr->second); + FUZZER_ASSERT_TRUE(pool.deallocate(itr->first, itr->second)); + ptrs.erase(itr); + } + } + } diff --git a/comm/third_party/botan/src/fuzzer/mode_padding.cpp b/comm/third_party/botan/src/fuzzer/mode_padding.cpp new file mode 100644 index 0000000000..c366530dd1 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/mode_padding.cpp @@ -0,0 +1,169 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +namespace { + +size_t ref_pkcs7_unpad(const uint8_t in[], size_t len) + { + if(len <= 2) + return len; + + const size_t padding_length = in[len-1]; + + if(padding_length == 0 || padding_length > len) + return len; + + const size_t padding_start = len - padding_length; + + for(size_t i = padding_start; i != len; ++i) + { + if(in[i] != padding_length) + return len; + } + + return len - padding_length; + } + +size_t ref_x923_unpad(const uint8_t in[], size_t len) + { + if(len <= 2) + return len; + + const size_t padding_length = in[len-1]; + + if(padding_length == 0 || padding_length > len) + return len; + const size_t padding_start = len - padding_length; + + for(size_t i = padding_start; i != len - 1; ++i) + { + if(in[i] != 0) + { + return len; + } + } + + return len - padding_length; + } + +size_t ref_oneandzero_unpad(const uint8_t in[], size_t len) + { + if(len <= 2) + return len; + + size_t idx = len - 1; + + for(;;) + { + if(in[idx] == 0) + { + if(idx == 0) + return len; + idx -= 1; + continue; + } + else if(in[idx] == 0x80) + { + return idx; + } + else + return len; + } + + return len; + } + +size_t ref_esp_unpad(const uint8_t in[], size_t len) + { + if(len <= 2) + return len; + + const size_t padding_bytes = in[len - 1]; + + if(padding_bytes == 0 || padding_bytes > len) + { + return len; + } + + const size_t padding_start = len - padding_bytes; + for(size_t i = padding_start; i != len; ++i) + { + if(in[i] != (i - padding_start + 1)) + { + return len; + } + } + + return len - padding_bytes; + } + +uint16_t ref_tls_cbc_unpad(const uint8_t in[], size_t len) + { + if(len == 0) + return 0; + + const size_t padding_length = in[(len-1)]; + + if(padding_length >= len) + return 0; + + /* + * TLS v1.0 and up require all the padding bytes be the same value + * and allows up to 255 bytes. + */ + for(size_t i = 0; i != 1 + padding_length; ++i) + { + if(in[(len-i-1)] != padding_length) + return 0; + } + return padding_length + 1; + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static Botan::PKCS7_Padding pkcs7; + static Botan::ANSI_X923_Padding x923; + static Botan::OneAndZeros_Padding oneandzero; + static Botan::ESP_Padding esp; + + if(pkcs7.valid_blocksize(len)) + { + const size_t ct_pkcs7 = pkcs7.unpad(in, len); + const size_t ref_pkcs7 = ref_pkcs7_unpad(in, len); + FUZZER_ASSERT_EQUAL(ct_pkcs7, ref_pkcs7); + } + + if(x923.valid_blocksize(len)) + { + const size_t ct_x923 = x923.unpad(in, len); + const size_t ref_x923 = ref_x923_unpad(in, len); + FUZZER_ASSERT_EQUAL(ct_x923, ref_x923); + } + + if(oneandzero.valid_blocksize(len)) + { + const size_t ct_oneandzero = oneandzero.unpad(in, len); + const size_t ref_oneandzero = ref_oneandzero_unpad(in, len); + FUZZER_ASSERT_EQUAL(ct_oneandzero, ref_oneandzero); + } + + if(esp.valid_blocksize(len)) + { + const size_t ct_esp = esp.unpad(in, len); + const size_t ref_esp = ref_esp_unpad(in, len); + FUZZER_ASSERT_EQUAL(ct_esp, ref_esp); + } + + const uint16_t ct_cbc = Botan::TLS::check_tls_cbc_padding(in, len); + const uint16_t ref_cbc = ref_tls_cbc_unpad(in, len); + FUZZER_ASSERT_EQUAL(ct_cbc, ref_cbc); + } diff --git a/comm/third_party/botan/src/fuzzer/oaep.cpp b/comm/third_party/botan/src/fuzzer/oaep.cpp new file mode 100644 index 0000000000..3d8275bded --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/oaep.cpp @@ -0,0 +1,102 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" + +#include +#include + +namespace { + +Botan::secure_vector +ref_oaep_unpad(uint8_t& valid_mask, + const uint8_t in[], size_t len, + const Botan::secure_vector& Phash) + { + const size_t hlen = Phash.size(); + + if(len < 2*hlen + 1) + { + return Botan::secure_vector(); + } + + for(size_t i = hlen; i != 2*hlen; ++i) + { + if(in[i] != Phash[i-hlen]) + { + return Botan::secure_vector(); + } + } + + for(size_t i = 2*hlen; i != len; ++i) + { + if(in[i] != 0x00 && in[i] != 0x01) + { + return Botan::secure_vector(); + } + + if(in[i] == 0x01) + { + valid_mask = 0xFF; + return Botan::secure_vector(in + i + 1, in + len); + } + } + + return Botan::secure_vector(); + } + +inline bool all_zeros(const Botan::secure_vector& v) + { + for(size_t i = 0; i != v.size(); ++i) + { + if(v[i] != 0) + return false; + } + return true; + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static const Botan::secure_vector Phash = { 1, 2, 3, 4 }; + + uint8_t lib_valid_mask = 0; + const Botan::secure_vector lib_output = Botan::oaep_find_delim(lib_valid_mask, in, len, Phash); + FUZZER_ASSERT_TRUE(lib_valid_mask == 0 || lib_valid_mask == 0xFF); + + uint8_t ref_valid_mask = 0; + const Botan::secure_vector ref_output = ref_oaep_unpad(ref_valid_mask, in, len, Phash); + FUZZER_ASSERT_TRUE(ref_valid_mask == 0 || ref_valid_mask == 0xFF); + + if(ref_valid_mask == 0xFF && lib_valid_mask == 0x00) + { + FUZZER_WRITE_AND_CRASH("Ref accepted but library rejected, output " << Botan::hex_encode(ref_output) << "\n"); + } + else if(ref_valid_mask == 0x00 && lib_valid_mask == 0xFF) + { + FUZZER_WRITE_AND_CRASH("Lib accepted but ref rejected, output = " << Botan::hex_encode(lib_output) << "\n"); + } + + if(ref_valid_mask == 0x00) + { + FUZZER_ASSERT_TRUE(all_zeros(ref_output)); + } + + if(lib_valid_mask == 0x00) + { + FUZZER_ASSERT_TRUE(all_zeros(lib_output)); + } + + if(ref_valid_mask && lib_valid_mask) + { + if(ref_output != lib_output) + { + FUZZER_WRITE_AND_CRASH("Ref and lib both accepted but produced different output:" + << " ref = " << Botan::hex_encode(ref_output) + << " lib = " << Botan::hex_encode(lib_output)); + } + } + } diff --git a/comm/third_party/botan/src/fuzzer/ocsp.cpp b/comm/third_party/botan/src/fuzzer/ocsp.cpp new file mode 100644 index 0000000000..0db265b8df --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ocsp.cpp @@ -0,0 +1,17 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::OCSP::Response response(in, len); + } + catch(Botan::Exception& e) { } + } diff --git a/comm/third_party/botan/src/fuzzer/os2ecp.cpp b/comm/third_party/botan/src/fuzzer/os2ecp.cpp new file mode 100644 index 0000000000..cb4a50b474 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/os2ecp.cpp @@ -0,0 +1,44 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" +#include +#include + +namespace { + +void check_os2ecp(const Botan::EC_Group& group, const uint8_t in[], size_t len) + { + try + { + Botan::PointGFp point = group.OS2ECP(in, len); + } + catch(Botan::Exception& e) {} + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + if(len >= 256) + return; + + static Botan::EC_Group p192("secp192r1"); + static Botan::EC_Group p224("secp224r1"); + static Botan::EC_Group p256("secp256r1"); + static Botan::EC_Group p384("secp384r1"); + static Botan::EC_Group p521("secp521r1"); + static Botan::EC_Group bp256("brainpool256r1"); + static Botan::EC_Group bp512("brainpool512r1"); + + check_os2ecp(p192, in, len); + check_os2ecp(p224, in, len); + check_os2ecp(p256, in, len); + check_os2ecp(p384, in, len); + check_os2ecp(p521, in, len); + check_os2ecp(p521, in, len); + check_os2ecp(bp256, in, len); + check_os2ecp(bp512, in, len); + } diff --git a/comm/third_party/botan/src/fuzzer/pkcs1.cpp b/comm/third_party/botan/src/fuzzer/pkcs1.cpp new file mode 100644 index 0000000000..8a297ff7f6 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/pkcs1.cpp @@ -0,0 +1,75 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ +#include "fuzzers.h" + +#include +#include + +namespace { + +std::vector simple_pkcs1_unpad(const uint8_t in[], size_t len) + { + if(len < 10) + throw Botan::Decoding_Error("bad len"); + + if(in[0] != 0 || in[1] != 2) + throw Botan::Decoding_Error("bad header field"); + + for(size_t i = 2; i < len; ++i) + { + if(in[i] == 0) + { + if(i < 10) // at least 8 padding bytes required + throw Botan::Decoding_Error("insufficient padding bytes"); + return std::vector(in + i + 1, in + len); + } + } + + throw Botan::Decoding_Error("delim not found"); + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static Botan::EME_PKCS1v15 pkcs1; + + Botan::secure_vector lib_result; + std::vector ref_result; + bool lib_rejected = false, ref_rejected = false; + + try + { + uint8_t valid_mask = 0; + Botan::secure_vector decoded = (static_cast(&pkcs1))->unpad(valid_mask, in, len); + + if(valid_mask == 0) + lib_rejected = true; + else if(valid_mask == 0xFF) + lib_rejected = false; + else + FUZZER_WRITE_AND_CRASH("Invalid valid_mask from unpad"); + } + catch(Botan::Decoding_Error&) { lib_rejected = true; } + + try + { + ref_result = simple_pkcs1_unpad(in, len); + } + catch(Botan::Decoding_Error& e) { ref_rejected = true; } + + if(lib_rejected == true && ref_rejected == false) + { + FUZZER_WRITE_AND_CRASH("Library rejected input accepted by ref " + << Botan::hex_encode(ref_result)); + } + else if(ref_rejected == true && lib_rejected == false) + { + FUZZER_WRITE_AND_CRASH("Library accepted input rejected by ref " + << Botan::hex_encode(lib_result)); + } + // otherwise the two implementations agree + } diff --git a/comm/third_party/botan/src/fuzzer/pkcs8.cpp b/comm/third_party/botan/src/fuzzer/pkcs8.cpp new file mode 100644 index 0000000000..72a3046494 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/pkcs8.cpp @@ -0,0 +1,27 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + Botan::DataSource_Memory input(in, len); + std::unique_ptr key = Botan::PKCS8::load_key(input); + } + catch(Botan::Exception& e) { } + + /* + * This avoids OOMs in OSS-Fuzz caused by storing precomputations + * for thousands of curves randomly generated by the fuzzer. + */ + Botan::EC_Group::clear_registered_curve_data(); + } diff --git a/comm/third_party/botan/src/fuzzer/pow_mod.cpp b/comm/third_party/botan/src/fuzzer/pow_mod.cpp new file mode 100644 index 0000000000..28350480cb --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/pow_mod.cpp @@ -0,0 +1,72 @@ +/* +* (C) 2016,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +namespace { + +Botan::BigInt simple_power_mod(Botan::BigInt x, + Botan::BigInt n, + const Botan::BigInt& p) + { + if(n == 0) + { + if(p == 1) + return 0; + return 1; + } + + Botan::Modular_Reducer mod_p(p); + Botan::BigInt y = 1; + + while(n > 1) + { + if(n.is_odd()) + { + y = mod_p.multiply(x, y); + } + x = mod_p.square(x); + n >>= 1; + } + return mod_p.multiply(x, y); + } + +} + +void fuzz(const uint8_t in[], size_t len) + { + static const size_t max_bits = 2048; + + if(len % 3 != 0) + return; + + const size_t part_size = len / 3; + + if(part_size * 8 > max_bits) + return; + + const Botan::BigInt g = Botan::BigInt::decode(in, part_size); + const Botan::BigInt x = Botan::BigInt::decode(in + part_size, part_size); + const Botan::BigInt p = Botan::BigInt::decode(in + 2*part_size, part_size); + + try + { + const Botan::BigInt ref = simple_power_mod(g, x, p); + const Botan::BigInt z = Botan::power_mod(g, x, p); + + if(ref != z) + { + FUZZER_WRITE_AND_CRASH("G = " << g << "\n" + << "X = " << x << "\n" + << "P = " << p << "\n" + << "Z = " << z << "\n" + << "R = " << ref << "\n"); + } + } + catch(Botan::Exception& e) {} + } diff --git a/comm/third_party/botan/src/fuzzer/redc_p192.cpp b/comm/third_party/botan/src/fuzzer/redc_p192.cpp new file mode 100644 index 0000000000..6898cdbb95 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/redc_p192.cpp @@ -0,0 +1,31 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*192/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p192(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt input = Botan::BigInt::decode(in, len); + + if(input < prime_2) + { + const Botan::BigInt ref = prime_redc.reduce(input); + + Botan::secure_vector ws; + Botan::redc_p192(input, ws); + + FUZZER_ASSERT_EQUAL(ref, input); + } + } diff --git a/comm/third_party/botan/src/fuzzer/redc_p224.cpp b/comm/third_party/botan/src/fuzzer/redc_p224.cpp new file mode 100644 index 0000000000..b2dbac16e5 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/redc_p224.cpp @@ -0,0 +1,31 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*224/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p224(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt input = Botan::BigInt::decode(in, len); + + if(input < prime_2) + { + const Botan::BigInt ref = prime_redc.reduce(input); + + Botan::secure_vector ws; + Botan::redc_p224(input, ws); + + FUZZER_ASSERT_EQUAL(ref, input); + } + } diff --git a/comm/third_party/botan/src/fuzzer/redc_p256.cpp b/comm/third_party/botan/src/fuzzer/redc_p256.cpp new file mode 100644 index 0000000000..4c3809f089 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/redc_p256.cpp @@ -0,0 +1,31 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*256/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p256(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt input = Botan::BigInt::decode(in, len); + + if(input < prime_2) + { + const Botan::BigInt ref = prime_redc.reduce(input); + + Botan::secure_vector ws; + Botan::redc_p256(input, ws); + + FUZZER_ASSERT_EQUAL(ref, input); + } + } diff --git a/comm/third_party/botan/src/fuzzer/redc_p384.cpp b/comm/third_party/botan/src/fuzzer/redc_p384.cpp new file mode 100644 index 0000000000..1c3a777a0a --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/redc_p384.cpp @@ -0,0 +1,31 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*384/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p384(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt input = Botan::BigInt::decode(in, len); + + if(input < prime_2) + { + const Botan::BigInt ref = prime_redc.reduce(input); + + Botan::secure_vector ws; + Botan::redc_p384(input, ws); + + FUZZER_ASSERT_EQUAL(ref, input); + } + } diff --git a/comm/third_party/botan/src/fuzzer/redc_p521.cpp b/comm/third_party/botan/src/fuzzer/redc_p521.cpp new file mode 100644 index 0000000000..e148c94bb7 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/redc_p521.cpp @@ -0,0 +1,31 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > 2*(521+7)/8) + return; + + static const Botan::BigInt& prime = Botan::prime_p521(); + static const Botan::BigInt prime_2 = prime * prime; + static Botan::Modular_Reducer prime_redc(prime); + + Botan::BigInt input = Botan::BigInt::decode(in, len); + + if(input < prime_2) + { + const Botan::BigInt ref = prime_redc.reduce(input); + + Botan::secure_vector ws; + Botan::redc_p521(input, ws); + + FUZZER_ASSERT_EQUAL(ref, input); + } + } diff --git a/comm/third_party/botan/src/fuzzer/ressol.cpp b/comm/third_party/botan/src/fuzzer/ressol.cpp new file mode 100644 index 0000000000..99d48f98be --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/ressol.cpp @@ -0,0 +1,44 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + // Ressol is mostly used for ECC point decompression so best to test smaller sizes + static const size_t p_bits = 256; + static const Botan::BigInt p = random_prime(fuzzer_rng(), p_bits); + static const Botan::Modular_Reducer mod_p(p); + + if(len > p_bits / 8) + return; + + try + { + const Botan::BigInt a = Botan::BigInt::decode(in, len); + Botan::BigInt a_sqrt = Botan::ressol(a, p); + + if(a_sqrt > 0) + { + const Botan::BigInt a_redc = mod_p.reduce(a); + const Botan::BigInt z = mod_p.square(a_sqrt); + + if(z != a_redc) + { + FUZZER_WRITE_AND_CRASH("A = " << a << "\n" + << "P = " << p << "\n" + << "R = " << a_sqrt << "\n" + << "Z = " << z << "\n"); + } + } + } + catch(Botan::Exception& e) {} + + return; + } + diff --git a/comm/third_party/botan/src/fuzzer/tls_client.cpp b/comm/third_party/botan/src/fuzzer/tls_client.cpp new file mode 100644 index 0000000000..a5c8137bfc --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/tls_client.cpp @@ -0,0 +1,130 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +class Fuzzer_TLS_Client_Creds : public Botan::Credentials_Manager + { + public: + std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } + std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } + Botan::SymmetricKey psk(const std::string&, const std::string&, const std::string&) override + { + return Botan::SymmetricKey("AABBCCDDEEFF00112233445566778899"); + } + }; + +class Fuzzer_TLS_Policy : public Botan::TLS::Policy + { + public: + std::vector ciphersuite_list(Botan::TLS::Protocol_Version version, + bool have_srp) const + { + std::vector ciphersuites; + + for(auto&& suite : Botan::TLS::Ciphersuite::all_known_ciphersuites()) + { + if(suite.valid() == false) + continue; + + // Are we doing SRP? + if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA) + continue; + + if(!version.supports_aead_modes()) + { + // Are we doing AEAD in a non-AEAD version? + if(suite.mac_algo() == "AEAD") + continue; + + // Older (v1.0/v1.1) versions also do not support any hash but SHA-1 + if(suite.mac_algo() != "SHA-1") + continue; + } + + ciphersuites.push_back(suite.ciphersuite_code()); + } + + return ciphersuites; + } + }; + +class Fuzzer_TLS_Client_Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t[], size_t) override + { + // discard + } + + void tls_record_received(uint64_t, const uint8_t[], size_t) override + { + // ignore peer data + } + + void tls_alert(Botan::TLS::Alert) override + { + // ignore alert + } + + bool tls_session_established(const Botan::TLS::Session&) override + { + return true; // cache it + } + + void tls_verify_cert_chain( + const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname, + const Botan::TLS::Policy& policy) override + { + try + { + // try to validate to exercise those code paths + Botan::TLS::Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, + trusted_roots, usage, hostname, policy); + } + catch(...) + { + // ignore validation result + } + } + + }; + +void fuzz(const uint8_t in[], size_t len) + { + if(len == 0) + return; + + Botan::TLS::Session_Manager_Noop session_manager; + Fuzzer_TLS_Policy policy; + Botan::TLS::Protocol_Version client_offer = Botan::TLS::Protocol_Version::TLS_V12; + Botan::TLS::Server_Information info("server.name", 443); + Fuzzer_TLS_Client_Callbacks callbacks; + Fuzzer_TLS_Client_Creds creds; + + Botan::TLS::Client client(callbacks, + session_manager, + creds, + policy, + fuzzer_rng(), + info, + client_offer); + + try + { + client.received_data(in, len); + } + catch(std::exception& e) + { + } + + } + diff --git a/comm/third_party/botan/src/fuzzer/tls_client_hello.cpp b/comm/third_party/botan/src/fuzzer/tls_client_hello.cpp new file mode 100644 index 0000000000..28c77c9b6d --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/tls_client_hello.cpp @@ -0,0 +1,18 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + try + { + std::vector v(in, in + len); + Botan::TLS::Client_Hello ch(v); + } + catch(Botan::Exception& e) {} + } diff --git a/comm/third_party/botan/src/fuzzer/tls_server.cpp b/comm/third_party/botan/src/fuzzer/tls_server.cpp new file mode 100644 index 0000000000..d45ff5f5ce --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/tls_server.cpp @@ -0,0 +1,227 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include + +const char* fixed_rsa_key = + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCe6qqpMQVJ7zCJ\n" + "oSnpxia0yO6M7Ie3FGqPcd0DzueC+kWPvuHQ+PpP5vfO6qqRaDVII37PFX5NUZQm\n" + "GK/rAm7spjIHTCMgqSZ8pN13LU8m1gDwIdu9al16LXN9zZjB67uLlFn2trtLi234\n" + "i0cnyeF8IC0cz7tgCOzMSVEBcqJjkdgGrZ3WUgOXecVm2lXVrYlEiaSxFp4VOE9k\n" + "RFeVrELCjmNtc4hRd1yJsF+vObCtvyqGYQE1Qcb0MVSQDBHMkiUVmO6zuW7td5ef\n" + "O/1OyntQJGyVa+SnWbkSLCybta2J7MreHENrF5GA0K1KL140SNRHeWifRMuNQua7\n" + "qmKXMBTFAgMBAAECggEAIk3fxyQI0zvpy1vZ01ft1QqmzA7nAPNMSWi33/GS8iga\n" + "SfxXfKeySPs/tQ/dAARxs//NiOBH4mLgyxR7LQzaawU5OXALCSraXv+ruuUx990s\n" + "WKnGaG4EfbJAAwEVn47Gbkv425P4fEc91vAhzQn8PbIoatbAyOtESpjs/pYDTeC/\n" + "mnJId8gqO90cqyRECEMjk9sQ8iEjWPlik4ayGlUVbeeMu6/pJ9F8IZEgkLZiNDAB\n" + "4anmOFaT7EmqUjI4IlcaqfbbXyDXlvWUYukidEss+CNvPuqbQHBDnpFVvBxdDR2N\n" + "Uj2D5Xd5blcIe2/+1IVRnznjoQ5zvutzb7ThBmMehQKBgQDOITKG0ht2kXLxjVoR\n" + "r/pVpx+f3hs3H7wE0+vrLHoQgkVjpMWXQ47YuZTT9rCOOYNI2cMoH2D27t1j78/B\n" + "9kGYABUVpvQQ+6amqJDI1eYI6e68TPueEDjeALfSCdmPNiI3lZZrCIK9XLpkoy8K\n" + "tGYBRRJ+JJxjj1zPXj9SGshPgwKBgQDFXUtoxY3mCStH3+0b1qxGG9r1L5goHEmd\n" + "Am8WBYDheNpL0VqPNzouhuM/ZWMGyyAs/py6aLATe+qhR1uX5vn7LVZwjCSONZ4j\n" + "7ieEEUh1BHetPI1oI5PxgokRYfVuckotqVseanI/536Er3Yf2FXNQ1/ceVp9WykX\n" + "3mYTKMhQFwKBgQDKakcXpZNaZ5IcKdZcsBZ/rdGcR5sqEnursf9lvRNQytwg8Vkn\n" + "JSxNHlBLpV/TCh8lltHRwJ6TXhUBYij+KzhWbx5FWOErHDOWTMmArqtp7W6GcoJT\n" + "wVJWjxXzp8CApYQMWVSQXpckJL7UvHohZO0WKiHyxTjde5aD++TqV2qEyQKBgBbD\n" + "jvoTpy08K4DLxCZs2Uvw1I1pIuylbpwsdrGciuP2s38BM6fHH+/T4Qwj3osfDKQD\n" + "7gHWJ1Dn/wUBHQBlRLoC3bB3iZPZfVb5lhc2gxv0GvWhQVIcoGi/vJ2DpfJKPmIL\n" + "4ZWdg3X5dm9JaZ98rVDSj5D3ckd5J0E4hp95GbmbAoGBAJJHM4O9lx60tIjw9Sf/\n" + "QmKWyUk0NLnt8DcgRMW7fVxtzPNDy9DBKGIkDdWZ2s+ForICA3C9WSxBC1EOEHGG\n" + "xkg2xKt66CeutGroP6M191mHQrRClt1VbEYzQFX21BCk5kig9i/BURyoTHtFiV+t\n" + "kbf4VLg8Vk9u/R3RU1HsYWhe\n" + "-----END PRIVATE KEY-----\n"; + +const char* fixed_rsa_cert = + "-----BEGIN CERTIFICATE-----\n" + "MIIDUDCCAjgCCQD7pIb1ZsoafjANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJW\n" + "VDEQMA4GA1UECAwHVmVybW9udDEWMBQGA1UEBwwNVGhlIEludGVybmV0czEUMBIG\n" + "A1UECgwLTWFuZ29zIFIgVXMxGzAZBgNVBAMMEnNlcnZlci5leGFtcGxlLmNvbTAe\n" + "Fw0xNjAxMDYxNzQ3MjNaFw0yNjAxMDMxNzQ3MjNaMGoxCzAJBgNVBAYTAlZUMRAw\n" + "DgYDVQQIDAdWZXJtb250MRYwFAYDVQQHDA1UaGUgSW50ZXJuZXRzMRQwEgYDVQQK\n" + "DAtNYW5nb3MgUiBVczEbMBkGA1UEAwwSc2VydmVyLmV4YW1wbGUuY29tMIIBIjAN\n" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnuqqqTEFSe8wiaEp6cYmtMjujOyH\n" + "txRqj3HdA87ngvpFj77h0Pj6T+b3zuqqkWg1SCN+zxV+TVGUJhiv6wJu7KYyB0wj\n" + "IKkmfKTddy1PJtYA8CHbvWpdei1zfc2Yweu7i5RZ9ra7S4tt+ItHJ8nhfCAtHM+7\n" + "YAjszElRAXKiY5HYBq2d1lIDl3nFZtpV1a2JRImksRaeFThPZERXlaxCwo5jbXOI\n" + "UXdcibBfrzmwrb8qhmEBNUHG9DFUkAwRzJIlFZjus7lu7XeXnzv9Tsp7UCRslWvk\n" + "p1m5Eiwsm7WtiezK3hxDaxeRgNCtSi9eNEjUR3lon0TLjULmu6pilzAUxQIDAQAB\n" + "MA0GCSqGSIb3DQEBCwUAA4IBAQA1eZGc/4V7z/E/6eG0hVkzoAZeuTcSP7WqBSx+\n" + "OP2yh0163UYjoa6nehmkKYQQ9PbYPZGzIcl+dBFyYzy6jcp0NdtzpWnTFrjl4rMq\n" + "akcQ1D0LTYjJXVP9G/vF/SvatOFeVTnQmLlLt/a8ZtRUINqejeZZPzH8ifzFW6tu\n" + "mlhTVIEKyPHpxClh5Y3ubw/mZYygekFTqMkTx3FwJxKU8J6rYGZxanWAODUIvCUo\n" + "Fxer1qC5Love3uWl3vXPLEZWZdORnExSRByzz2immBP2vX4zYZoeZRhTQ9ae1TIV\n" + "Dk02a/1AOJZdZReDbgXhlqaUx5pk/rzo4mDzvu5HSCeXmClz\n" + "-----END CERTIFICATE-----\n"; + +class Fuzzer_TLS_Server_Creds : public Botan::Credentials_Manager + { + public: + Fuzzer_TLS_Server_Creds() + { + Botan::DataSource_Memory cert_in(fixed_rsa_cert); + Botan::DataSource_Memory key_in(fixed_rsa_key); + + m_rsa_cert.reset(new Botan::X509_Certificate(cert_in)); + //m_rsa_key.reset(Botan::PKCS8::load_key(key_in, fuzzer_rng()); + } + + std::vector cert_chain( + const std::vector& algos, + const std::string& /*type*/, + const std::string& /*hostname*/) override + { + std::vector v; + + for(auto algo : algos) + { + if(algo == "RSA") + { + v.push_back(*m_rsa_cert); + break; + } + } + + return v; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& /*cert*/, + const std::string& /*type*/, + const std::string& /*context*/) override + { + return m_rsa_key.get(); + } + + std::string psk_identity_hint(const std::string&, const std::string&) override { return "psk_hint"; } + std::string psk_identity(const std::string&, const std::string&, const std::string&) override { return "psk_id"; } + Botan::SymmetricKey psk(const std::string&, const std::string&, const std::string&) override + { + return Botan::SymmetricKey("AABBCCDDEEFF00112233445566778899"); + } + private: + std::unique_ptr m_rsa_cert; + std::unique_ptr m_rsa_key; + }; + +class Fuzzer_TLS_Policy : public Botan::TLS::Policy + { + public: + std::vector ciphersuite_list(Botan::TLS::Protocol_Version version, + bool have_srp) const + { + std::vector ciphersuites; + + for(auto&& suite : Botan::TLS::Ciphersuite::all_known_ciphersuites()) + { + if(suite.valid() == false) + continue; + + // Are we doing SRP? + if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA) + continue; + + if(!version.supports_aead_modes()) + { + // Are we doing AEAD in a non-AEAD version? + if(suite.mac_algo() == "AEAD") + continue; + + // Older (v1.0/v1.1) versions also do not support any hash but SHA-1 + if(suite.mac_algo() != "SHA-1") + continue; + } + + ciphersuites.push_back(suite.ciphersuite_code()); + } + + return ciphersuites; + } + }; + +class Fuzzer_TLS_Server_Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t[], size_t) override + { + // discard + } + + void tls_record_received(uint64_t, const uint8_t[], size_t) override + { + // ignore peer data + } + + void tls_alert(Botan::TLS::Alert) override + { + // ignore alert + } + + bool tls_session_established(const Botan::TLS::Session&) override + { + return true; // cache it + } + + std::string tls_server_choose_app_protocol(const std::vector& client_protos) override + { + if(client_protos.size() > 1) + return client_protos[0]; + else + return "fuzzy"; + } + + void tls_verify_cert_chain( + const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname, + const Botan::TLS::Policy& policy) override + { + try + { + // try to validate to exercise those code paths + Botan::TLS::Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, + trusted_roots, usage, hostname, policy); + } + catch(...) + { + // ignore validation result + } + } + + }; + +void fuzz(const uint8_t in[], size_t len) + { + if(len <= 1) + return; + + Botan::TLS::Session_Manager_Noop session_manager; + Fuzzer_TLS_Policy policy; + Botan::TLS::Server_Information info("server.name", 443); + Fuzzer_TLS_Server_Creds creds; + Fuzzer_TLS_Server_Callbacks callbacks; + + const bool is_datagram = in[0] & 1; + + Botan::TLS::Server server(callbacks, + session_manager, + creds, + policy, + fuzzer_rng(), + is_datagram); + + try + { + server.received_data(in + 1, len - 1); + } + catch(std::exception& e) + { + } + } diff --git a/comm/third_party/botan/src/fuzzer/uri.cpp b/comm/third_party/botan/src/fuzzer/uri.cpp new file mode 100644 index 0000000000..89066d283e --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/uri.cpp @@ -0,0 +1,20 @@ +/* +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include + +void fuzz(const uint8_t in[], size_t len) + { + if(len > max_fuzzer_input_size) + return; + + try + { + Botan::URI::fromAny(std::string(reinterpret_cast(in), len)); + } + catch(Botan::Exception& e) { } + } diff --git a/comm/third_party/botan/src/fuzzer/x509_dn.cpp b/comm/third_party/botan/src/fuzzer/x509_dn.cpp new file mode 100644 index 0000000000..9fc062cfb4 --- /dev/null +++ b/comm/third_party/botan/src/fuzzer/x509_dn.cpp @@ -0,0 +1,41 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "fuzzers.h" +#include +#include +#include + +void fuzz(const uint8_t in[], size_t len) + { + Botan::X509_DN dn1; + Botan::X509_DN dn2; + + try + { + Botan::BER_Decoder ber(in, len); + dn1.decode_from(ber); + dn2.decode_from(ber); + } + catch(...) { return; } + + const bool eq = dn1 == dn2; + const bool lt1 = dn1 < dn2; + const bool lt2 = dn2 < dn1; + + if(lt1 == false && lt2 == false) + { + FUZZER_ASSERT_TRUE(eq); + } + else + { + // one is less than the other + FUZZER_ASSERT_TRUE(lt1 || lt2); + + // it is not the case that both are less than the other + FUZZER_ASSERT_TRUE(!lt1 || !lt2); + } + } diff --git a/comm/third_party/botan/src/lib/asn1/alg_id.cpp b/comm/third_party/botan/src/lib/asn1/alg_id.cpp new file mode 100644 index 0000000000..1e82f29955 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/alg_id.cpp @@ -0,0 +1,109 @@ +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + const std::vector& param) : + oid(alg_id), + parameters(param) + {} + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + const std::vector& param) : + AlgorithmIdentifier(OID::from_string(alg_id), param) + {} + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + Encoding_Option option) : + oid(alg_id), + parameters() + { + const uint8_t DER_NULL[] = { 0x05, 0x00 }; + + if(option == USE_NULL_PARAM) + parameters.assign(DER_NULL, DER_NULL + 2); + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + Encoding_Option option) : + oid(OID::from_string(alg_id)), + parameters() + { + const uint8_t DER_NULL[] = { 0x05, 0x00 }; + + if(option == USE_NULL_PARAM) + parameters.assign(DER_NULL, DER_NULL + 2); + } + +bool AlgorithmIdentifier::parameters_are_null() const + { + return (parameters.size() == 2 && (parameters[0] == 0x05) && (parameters[1] == 0x00)); + } + +bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + if(a1.get_oid() != a2.get_oid()) + return false; + + /* + * Treat NULL and empty as equivalent + */ + if(a1.parameters_are_null_or_empty() && + a2.parameters_are_null_or_empty()) + { + return true; + } + + return (a1.get_parameters() == a2.get_parameters()); + } + +bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + return !(a1 == a2); + } + +/* +* DER encode an AlgorithmIdentifier +*/ +void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(get_oid()) + .raw_bytes(get_parameters()) + .end_cons(); + } + +/* +* Decode a BER encoded AlgorithmIdentifier +*/ +void AlgorithmIdentifier::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .raw_bytes(parameters) + .end_cons(); + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/alg_id.h b/comm/third_party/botan/src/lib/asn1/alg_id.h new file mode 100644 index 0000000000..88e54466d3 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/alg_id.h @@ -0,0 +1,14 @@ +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ALGORITHM_IDENTIFIER_H_ +#define BOTAN_ALGORITHM_IDENTIFIER_H_ + +#include +BOTAN_DEPRECATED_HEADER(alg_id.h) + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/asn1_obj.cpp b/comm/third_party/botan/src/lib/asn1/asn1_obj.cpp new file mode 100644 index 0000000000..8243552648 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_obj.cpp @@ -0,0 +1,238 @@ +/* +* ASN.1 Internals +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +std::vector ASN1_Object::BER_encode() const + { + std::vector output; + DER_Encoder der(output); + this->encode_into(der); + return output; + } + +/* +* Check a type invariant on BER data +*/ +void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_, + const std::string& descr) const + { + if(this->is_a(type_tag_, class_tag_) == false) + { + std::stringstream msg; + + msg << "Tag mismatch when decoding " << descr << " got "; + + if(class_tag == NO_OBJECT && type_tag == NO_OBJECT) + { + msg << "EOF"; + } + else + { + if(class_tag == UNIVERSAL || class_tag == CONSTRUCTED) + { + msg << asn1_tag_to_string(type_tag); + } + else + { + msg << std::to_string(type_tag); + } + + msg << "/" << asn1_class_to_string(class_tag); + } + + msg << " expected "; + + if(class_tag_ == UNIVERSAL || class_tag_ == CONSTRUCTED) + { + msg << asn1_tag_to_string(type_tag_); + } + else + { + msg << std::to_string(type_tag_); + } + + msg << "/" << asn1_class_to_string(class_tag_); + + throw BER_Decoding_Error(msg.str()); + } + } + +bool BER_Object::is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const + { + return (type_tag == type_tag_ && class_tag == class_tag_); + } + +bool BER_Object::is_a(int type_tag_, ASN1_Tag class_tag_) const + { + return is_a(ASN1_Tag(type_tag_), class_tag_); + } + +void BER_Object::set_tagging(ASN1_Tag t, ASN1_Tag c) + { + type_tag = t; + class_tag = c; + } + +std::string asn1_class_to_string(ASN1_Tag type) + { + switch(type) + { + case UNIVERSAL: + return "UNIVERSAL"; + case CONSTRUCTED: + return "CONSTRUCTED"; + case CONTEXT_SPECIFIC: + return "CONTEXT_SPECIFIC"; + case APPLICATION: + return "APPLICATION"; + case CONSTRUCTED | CONTEXT_SPECIFIC: + return "PRIVATE"; + case Botan::NO_OBJECT: + return "NO_OBJECT"; + default: + return "CLASS(" + std::to_string(static_cast(type)) + ")"; + } + } + +std::string asn1_tag_to_string(ASN1_Tag type) + { + switch(type) + { + case Botan::SEQUENCE: + return "SEQUENCE"; + + case Botan::SET: + return "SET"; + + case Botan::PRINTABLE_STRING: + return "PRINTABLE STRING"; + + case Botan::NUMERIC_STRING: + return "NUMERIC STRING"; + + case Botan::IA5_STRING: + return "IA5 STRING"; + + case Botan::T61_STRING: + return "T61 STRING"; + + case Botan::UTF8_STRING: + return "UTF8 STRING"; + + case Botan::VISIBLE_STRING: + return "VISIBLE STRING"; + + case Botan::BMP_STRING: + return "BMP STRING"; + + case Botan::UNIVERSAL_STRING: + return "UNIVERSAL STRING"; + + case Botan::UTC_TIME: + return "UTC TIME"; + + case Botan::GENERALIZED_TIME: + return "GENERALIZED TIME"; + + case Botan::OCTET_STRING: + return "OCTET STRING"; + + case Botan::BIT_STRING: + return "BIT STRING"; + + case Botan::ENUMERATED: + return "ENUMERATED"; + + case Botan::INTEGER: + return "INTEGER"; + + case Botan::NULL_TAG: + return "NULL"; + + case Botan::OBJECT_ID: + return "OBJECT"; + + case Botan::BOOLEAN: + return "BOOLEAN"; + + case Botan::NO_OBJECT: + return "NO_OBJECT"; + + default: + return "TAG(" + std::to_string(static_cast(type)) + ")"; + } + } + +/* +* BER Decoding Exceptions +*/ +BER_Decoding_Error::BER_Decoding_Error(const std::string& str) : + Decoding_Error("BER: " + str) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) : + BER_Decoding_Error(str + ": " + std::to_string(tag)) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, + ASN1_Tag tag1, ASN1_Tag tag2) : + BER_Decoding_Error(str + ": " + std::to_string(tag1) + "/" + std::to_string(tag2)) {} + +namespace ASN1 { + +/* +* Put some arbitrary bytes into a SEQUENCE +*/ +std::vector put_in_sequence(const std::vector& contents) + { + return ASN1::put_in_sequence(contents.data(), contents.size()); + } + +std::vector put_in_sequence(const uint8_t bits[], size_t len) + { + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .raw_bytes(bits, len) + .end_cons(); + return output; + } + +/* +* Convert a BER object into a string object +*/ +std::string to_string(const BER_Object& obj) + { + return std::string(cast_uint8_ptr_to_char(obj.bits()), + obj.length()); + } + +/* +* Do heuristic tests for BER data +*/ +bool maybe_BER(DataSource& source) + { + uint8_t first_u8; + if(!source.peek_byte(first_u8)) + { + BOTAN_ASSERT_EQUAL(source.read_byte(first_u8), 0, "Expected EOF"); + throw Stream_IO_Error("ASN1::maybe_BER: Source was empty"); + } + + if(first_u8 == (SEQUENCE | CONSTRUCTED)) + return true; + return false; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/asn1/asn1_obj.h b/comm/third_party/botan/src/lib/asn1/asn1_obj.h new file mode 100644 index 0000000000..0ce4437712 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_obj.h @@ -0,0 +1,475 @@ +/* +* (C) 1999-2007,2018,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_OBJECT_TYPES_H_ +#define BOTAN_ASN1_OBJECT_TYPES_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class BER_Decoder; +class DER_Encoder; + +/** +* ASN.1 Type and Class Tags +* This will become an enum class in a future major release +*/ +enum ASN1_Tag : uint32_t { + UNIVERSAL = 0x00, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + + CONSTRUCTED = 0x20, + + PRIVATE = CONSTRUCTED | CONTEXT_SPECIFIC, + + EOC = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL_TAG = 0x05, + OBJECT_ID = 0x06, + ENUMERATED = 0x0A, + SEQUENCE = 0x10, + SET = 0x11, + + UTF8_STRING = 0x0C, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + IA5_STRING = 0x16, + VISIBLE_STRING = 0x1A, + UNIVERSAL_STRING = 0x1C, + BMP_STRING = 0x1E, + + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + UTC_OR_GENERALIZED_TIME = 0x19, + + NO_OBJECT = 0xFF00, + DIRECTORY_STRING = 0xFF01 +}; + +std::string BOTAN_UNSTABLE_API asn1_tag_to_string(ASN1_Tag type); +std::string BOTAN_UNSTABLE_API asn1_class_to_string(ASN1_Tag type); + +/** +* Basic ASN.1 Object Interface +*/ +class BOTAN_PUBLIC_API(2,0) ASN1_Object + { + public: + /** + * Encode whatever this object is into to + * @param to the DER_Encoder that will be written to + */ + virtual void encode_into(DER_Encoder& to) const = 0; + + /** + * Decode whatever this object is from from + * @param from the BER_Decoder that will be read from + */ + virtual void decode_from(BER_Decoder& from) = 0; + + /** + * Return the encoding of this object. This is a convenience + * method when just one object needs to be serialized. Use + * DER_Encoder for complicated encodings. + */ + std::vector BER_encode() const; + + ASN1_Object() = default; + ASN1_Object(const ASN1_Object&) = default; + ASN1_Object & operator=(const ASN1_Object&) = default; + virtual ~ASN1_Object() = default; + }; + +/** +* BER Encoded Object +*/ +class BOTAN_PUBLIC_API(2,0) BER_Object final + { + public: + BER_Object() : type_tag(NO_OBJECT), class_tag(UNIVERSAL) {} + + BER_Object(const BER_Object& other) = default; + + BER_Object& operator=(const BER_Object& other) = default; + + BER_Object(BER_Object&& other) = default; + + BER_Object& operator=(BER_Object&& other) = default; + + bool is_set() const { return type_tag != NO_OBJECT; } + + ASN1_Tag tagging() const { return ASN1_Tag(type() | get_class()); } + + ASN1_Tag type() const { return type_tag; } + ASN1_Tag get_class() const { return class_tag; } + + const uint8_t* bits() const { return value.data(); } + + size_t length() const { return value.size(); } + + void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& descr = "object") const; + + bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const; + + bool is_a(int type_tag, ASN1_Tag class_tag) const; + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * The following member variables are public for historical reasons, but + * will be made private in a future major release. Use the accessor + * functions above. + */ + ASN1_Tag type_tag, class_tag; + secure_vector value; + + private: + + friend class BER_Decoder; + + void set_tagging(ASN1_Tag type_tag, ASN1_Tag class_tag); + + uint8_t* mutable_bits(size_t length) + { + value.resize(length); + return value.data(); + } + }; + +/* +* ASN.1 Utility Functions +*/ +class DataSource; + +namespace ASN1 { + +std::vector put_in_sequence(const std::vector& val); +std::vector put_in_sequence(const uint8_t bits[], size_t len); +std::string to_string(const BER_Object& obj); + +/** +* Heuristics tests; is this object possibly BER? +* @param src a data source that will be peeked at but not modified +*/ +bool maybe_BER(DataSource& src); + +} + +/** +* General BER Decoding Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) BER_Decoding_Error : public Decoding_Error + { + public: + explicit BER_Decoding_Error(const std::string&); + }; + +/** +* Exception For Incorrect BER Taggings +*/ +class BOTAN_PUBLIC_API(2,0) BER_Bad_Tag final : public BER_Decoding_Error + { + public: + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag); + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag1, ASN1_Tag tag2); + }; + +/** +* This class represents ASN.1 object identifiers. +*/ +class BOTAN_PUBLIC_API(2,0) OID final : public ASN1_Object + { + public: + + /** + * Create an uninitialied OID object + */ + explicit OID() {} + + /** + * Construct an OID from a string. + * @param str a string in the form "a.b.c" etc., where a,b,c are numbers + */ + explicit OID(const std::string& str); + + /** + * Initialize an OID from a sequence of integer values + */ + explicit OID(std::initializer_list init) : m_id(init) {} + + /** + * Initialize an OID from a vector of integer values + */ + explicit OID(std::vector&& init) : m_id(init) {} + + /** + * Construct an OID from a string. + * @param str a string in the form "a.b.c" etc., where a,b,c are numbers + * or any known OID name (for example "RSA" or "X509v3.SubjectKeyIdentifier") + */ + static OID from_string(const std::string& str); + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + /** + * Find out whether this OID is empty + * @return true is no OID value is set + */ + bool empty() const { return m_id.empty(); } + + /** + * Find out whether this OID has a value + * @return true is this OID has a value + */ + bool has_value() const { return (m_id.empty() == false); } + + /** + * Get this OID as list (vector) of its components. + * @return vector representing this OID + */ + const std::vector& get_components() const { return m_id; } + + const std::vector& get_id() const { return get_components(); } + + /** + * Get this OID as a string + * @return string representing this OID + */ + std::string BOTAN_DEPRECATED("Use OID::to_string") as_string() const + { + return this->to_string(); + } + + /** + * Get this OID as a dotted-decimal string + * @return string representing this OID + */ + std::string to_string() const; + + /** + * If there is a known name associated with this OID, return that. + * Otherwise return the result of to_string + */ + std::string to_formatted_string() const; + + /** + * Compare two OIDs. + * @return true if they are equal, false otherwise + */ + bool operator==(const OID& other) const + { + return m_id == other.m_id; + } + + /** + * Reset this instance to an empty OID. + */ + void BOTAN_DEPRECATED("Avoid mutation of OIDs") clear() { m_id.clear(); } + + /** + * Add a component to this OID. + * @param new_comp the new component to add to the end of this OID + * @return reference to *this + */ + BOTAN_DEPRECATED("Avoid mutation of OIDs") OID& operator+=(uint32_t new_comp) + { + m_id.push_back(new_comp); + return (*this); + } + + private: + std::vector m_id; + }; + +/** +* Append another component onto the OID. +* @param oid the OID to add the new component to +* @param new_comp the new component to add +*/ +OID BOTAN_PUBLIC_API(2,0) operator+(const OID& oid, uint32_t new_comp); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is not equal to b +*/ +inline bool operator!=(const OID& a, const OID& b) + { + return !(a == b); + } + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is lexicographically smaller than b +*/ +bool BOTAN_PUBLIC_API(2,0) operator<(const OID& a, const OID& b); + +/** +* Time (GeneralizedTime/UniversalTime) +*/ +class BOTAN_PUBLIC_API(2,0) ASN1_Time final : public ASN1_Object + { + public: + /// DER encode a ASN1_Time + void encode_into(DER_Encoder&) const override; + + // Decode a BER encoded ASN1_Time + void decode_from(BER_Decoder&) override; + + /// Return an internal string representation of the time + std::string to_string() const; + + /// Returns a human friendly string replesentation of no particular formatting + std::string readable_string() const; + + /// Return if the time has been set somehow + bool time_is_set() const; + + /// Compare this time against another + int32_t cmp(const ASN1_Time& other) const; + + /// Create an invalid ASN1_Time + ASN1_Time() = default; + + /// Create a ASN1_Time from a time point + explicit ASN1_Time(const std::chrono::system_clock::time_point& time); + + /// Create an ASN1_Time from string + ASN1_Time(const std::string& t_spec, ASN1_Tag tag); + + /// Returns a STL timepoint object + std::chrono::system_clock::time_point to_std_timepoint() const; + + /// Return time since epoch + uint64_t time_since_epoch() const; + + private: + void set_to(const std::string& t_spec, ASN1_Tag); + bool passes_sanity_check() const; + + uint32_t m_year = 0; + uint32_t m_month = 0; + uint32_t m_day = 0; + uint32_t m_hour = 0; + uint32_t m_minute = 0; + uint32_t m_second = 0; + ASN1_Tag m_tag = NO_OBJECT; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_PUBLIC_API(2,0) operator==(const ASN1_Time&, const ASN1_Time&); +bool BOTAN_PUBLIC_API(2,0) operator!=(const ASN1_Time&, const ASN1_Time&); +bool BOTAN_PUBLIC_API(2,0) operator<=(const ASN1_Time&, const ASN1_Time&); +bool BOTAN_PUBLIC_API(2,0) operator>=(const ASN1_Time&, const ASN1_Time&); +bool BOTAN_PUBLIC_API(2,0) operator<(const ASN1_Time&, const ASN1_Time&); +bool BOTAN_PUBLIC_API(2,0) operator>(const ASN1_Time&, const ASN1_Time&); + +typedef ASN1_Time X509_Time; + +/** +* ASN.1 string type +* This class normalizes all inputs to a UTF-8 std::string +*/ +class BOTAN_PUBLIC_API(2,0) ASN1_String final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + ASN1_Tag tagging() const { return m_tag; } + + const std::string& value() const { return m_utf8_str; } + + size_t size() const { return value().size(); } + + bool empty() const { return m_utf8_str.empty(); } + + std::string BOTAN_DEPRECATED("Use value() to get UTF-8 string instead") + iso_8859() const; + + /** + * Return true iff this is a tag for a known string type we can handle. + * This ignores string types that are not supported, eg teletexString + */ + static bool is_string_type(ASN1_Tag tag); + + bool operator==(const ASN1_String& other) const + { return value() == other.value(); } + + explicit ASN1_String(const std::string& utf8 = ""); + ASN1_String(const std::string& utf8, ASN1_Tag tag); + private: + std::vector m_data; + std::string m_utf8_str; + ASN1_Tag m_tag; + }; + +/** +* Algorithm Identifier +*/ +class BOTAN_PUBLIC_API(2,0) AlgorithmIdentifier final : public ASN1_Object + { + public: + enum Encoding_Option { USE_NULL_PARAM, USE_EMPTY_PARAM }; + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + AlgorithmIdentifier() = default; + + AlgorithmIdentifier(const OID& oid, Encoding_Option enc); + AlgorithmIdentifier(const std::string& oid_name, Encoding_Option enc); + + AlgorithmIdentifier(const OID& oid, const std::vector& params); + AlgorithmIdentifier(const std::string& oid_name, const std::vector& params); + + const OID& get_oid() const { return oid; } + const std::vector& get_parameters() const { return parameters; } + + bool parameters_are_null() const; + bool parameters_are_empty() const { return parameters.empty(); } + + bool parameters_are_null_or_empty() const + { + return parameters_are_empty() || parameters_are_null(); + } + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * These values are public for historical reasons, but in a future release + * they will be made private. Do not access them. + */ + OID oid; + std::vector parameters; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_PUBLIC_API(2,0) operator==(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); +bool BOTAN_PUBLIC_API(2,0) operator!=(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/asn1_oid.cpp b/comm/third_party/botan/src/lib/asn1/asn1_oid.cpp new file mode 100644 index 0000000000..cbbe3a4cbb --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_oid.cpp @@ -0,0 +1,216 @@ +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +// returns empty on invalid +std::vector parse_oid_str(const std::string& oid) + { + try + { + std::string elem; + std::vector oid_elems; + + for(char c : oid) + { + if(c == '.') + { + if(elem.empty()) + return std::vector(); + oid_elems.push_back(to_u32bit(elem)); + elem.clear(); + } + else + { + elem += c; + } + } + + if(elem.empty()) + return std::vector(); + oid_elems.push_back(to_u32bit(elem)); + + if(oid_elems.size() < 2) + return std::vector(); + + return oid_elems; + } + catch(Invalid_Argument&) // thrown by to_u32bit + { + return std::vector(); + } + } + +} + +//static +OID OID::from_string(const std::string& str) + { + if(str.empty()) + throw Invalid_Argument("OID::from_string argument must be non-empty"); + + const OID o = OIDS::str2oid_or_empty(str); + if(o.has_value()) + return o; + + std::vector raw = parse_oid_str(str); + + if(raw.size() > 0) + return OID(std::move(raw)); + + throw Lookup_Error("No OID associated with name " + str); + } + +/* +* ASN.1 OID Constructor +*/ +OID::OID(const std::string& oid_str) + { + if(!oid_str.empty()) + { + m_id = parse_oid_str(oid_str); + + if(m_id.size() < 2 || m_id[0] > 2) + throw Invalid_OID(oid_str); + if((m_id[0] == 0 || m_id[0] == 1) && m_id[1] > 39) + throw Invalid_OID(oid_str); + } + } + +/* +* Return this OID as a string +*/ +std::string OID::to_string() const + { + std::ostringstream oss; + oss.imbue(std::locale("C")); + for(size_t i = 0; i != m_id.size(); ++i) + { + oss << m_id[i]; + if(i != m_id.size() - 1) + oss << "."; + } + return oss.str(); + } + +std::string OID::to_formatted_string() const + { + const std::string s = OIDS::oid2str_or_empty(*this); + if(!s.empty()) + return s; + return this->to_string(); + } + +/* +* Append another component to the OID +*/ +OID operator+(const OID& oid, uint32_t new_component) + { + std::vector val = oid.get_components(); + val.push_back(new_component); + return OID(std::move(val)); + } + +/* +* Compare two OIDs +*/ +bool operator<(const OID& a, const OID& b) + { + const std::vector& oid1 = a.get_components(); + const std::vector& oid2 = b.get_components(); + + return std::lexicographical_compare(oid1.begin(), oid1.end(), + oid2.begin(), oid2.end()); + } + +/* +* DER encode an OBJECT IDENTIFIER +*/ +void OID::encode_into(DER_Encoder& der) const + { + if(m_id.size() < 2) + throw Invalid_Argument("OID::encode_into: OID is invalid"); + + std::vector encoding; + + if(m_id[0] > 2 || m_id[1] >= 40) + throw Encoding_Error("Invalid OID prefix, cannot encode"); + + encoding.push_back(static_cast(40 * m_id[0] + m_id[1])); + + for(size_t i = 2; i != m_id.size(); ++i) + { + if(m_id[i] == 0) + encoding.push_back(0); + else + { + size_t blocks = high_bit(m_id[i]) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + BOTAN_ASSERT(blocks > 0, "Math works"); + + for(size_t j = 0; j != blocks - 1; ++j) + encoding.push_back(0x80 | ((m_id[i] >> 7*(blocks-j-1)) & 0x7F)); + encoding.push_back(m_id[i] & 0x7F); + } + } + der.add_object(OBJECT_ID, UNIVERSAL, encoding); + } + +/* +* Decode a BER encoded OBJECT IDENTIFIER +*/ +void OID::decode_from(BER_Decoder& decoder) + { + BER_Object obj = decoder.get_next_object(); + if(obj.tagging() != OBJECT_ID) + throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging()); + + const size_t length = obj.length(); + const uint8_t* bits = obj.bits(); + + if(length < 2 && !(length == 1 && bits[0] == 0)) + { + throw BER_Decoding_Error("OID encoding is too short"); + } + + m_id.clear(); + m_id.push_back(bits[0] / 40); + m_id.push_back(bits[0] % 40); + + size_t i = 0; + while(i != length - 1) + { + uint32_t component = 0; + while(i != length - 1) + { + ++i; + + if(component >> (32-7)) + throw Decoding_Error("OID component overflow"); + + component = (component << 7) + (bits[i] & 0x7F); + + if(!(bits[i] & 0x80)) + break; + } + m_id.push_back(component); + } + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/asn1_oid.h b/comm/third_party/botan/src/lib/asn1/asn1_oid.h new file mode 100644 index 0000000000..91c5da9d8d --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_oid.h @@ -0,0 +1,14 @@ +/* +* ASN.1 OID +* (C) 1999-2007,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_OID_H_ +#define BOTAN_ASN1_OID_H_ + +#include +BOTAN_DEPRECATED_HEADER(asn1_oid.h) + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/asn1_print.cpp b/comm/third_party/botan/src/lib/asn1/asn1_print.cpp new file mode 100644 index 0000000000..faadad02b6 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_print.cpp @@ -0,0 +1,327 @@ +/* +* (C) 2014,2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +bool all_printable_chars(const uint8_t bits[], size_t bits_len) + { + for(size_t i = 0; i != bits_len; ++i) + { + int c = bits[i]; + if(c > 127) + return false; + + if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false) + return false; + } + return true; + } + +/* +* Special hack to handle GeneralName [2] and [6] (DNS name and URI) +*/ +bool possibly_a_general_name(const uint8_t bits[], size_t bits_len) + { + if(bits_len <= 2) + return false; + + if(bits[0] != 0x82 && bits[0] != 0x86) + return false; + + if(bits[1] != bits_len - 2) + return false; + + if(all_printable_chars(bits + 2, bits_len - 2) == false) + return false; + + return true; + } + +} + +std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const + { + std::ostringstream output; + print_to_stream(output, in, len); + return output.str(); + } + +void ASN1_Formatter::print_to_stream(std::ostream& output, + const uint8_t in[], + size_t len) const + { + BER_Decoder dec(in, len); + decode(output, dec, 0); + } + +void ASN1_Formatter::decode(std::ostream& output, + BER_Decoder& decoder, + size_t level) const + { + BER_Object obj = decoder.get_next_object(); + + const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth); + + while(obj.is_set()) + { + const ASN1_Tag type_tag = obj.type(); + const ASN1_Tag class_tag = obj.get_class(); + const size_t length = obj.length(); + + /* hack to insert the tag+length back in front of the stuff now + that we've gotten the type info */ + std::vector bits; + DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length()); + + BER_Decoder data(bits); + + if(class_tag & CONSTRUCTED) + { + BER_Decoder cons_info(obj.bits(), obj.length()); + + if(recurse_deeper) + { + output << format(type_tag, class_tag, level, length, ""); + decode(output, cons_info, level + 1); // recurse + } + else + { + output << format(type_tag, class_tag, level, length, + format_bin(type_tag, class_tag, bits)); + } + } + else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC)) + { + bool success_parsing_cs = false; + + if(m_print_context_specific) + { + try + { + if(possibly_a_general_name(bits.data(), bits.size())) + { + output << format(type_tag, class_tag, level, level, + std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2)); + success_parsing_cs = true; + } + else if(recurse_deeper) + { + std::vector inner_bits; + data.decode(inner_bits, type_tag); + + BER_Decoder inner(inner_bits); + std::ostringstream inner_data; + decode(inner_data, inner, level + 1); // recurse + output << inner_data.str(); + success_parsing_cs = true; + } + } + catch(...) + { + } + } + + if(success_parsing_cs == false) + { + output << format(type_tag, class_tag, level, length, + format_bin(type_tag, class_tag, bits)); + } + } + else if(type_tag == OBJECT_ID) + { + OID oid; + data.decode(oid); + + std::string out = OIDS::oid2str_or_empty(oid); + if(out.empty()) + { + out = oid.to_string(); + } + else + { + out += " [" + oid.to_string() + "]"; + } + + output << format(type_tag, class_tag, level, length, out); + } + else if(type_tag == INTEGER || type_tag == ENUMERATED) + { + BigInt number; + + if(type_tag == INTEGER) + { + data.decode(number); + } + else if(type_tag == ENUMERATED) + { + data.decode(number, ENUMERATED, class_tag); + } + + std::vector rep = BigInt::encode(number); + if(rep.empty()) // if zero + rep.resize(1); + + output << format(type_tag, class_tag, level, length, hex_encode(rep)); + } + else if(type_tag == BOOLEAN) + { + bool boolean; + data.decode(boolean); + output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false")); + } + else if(type_tag == NULL_TAG) + { + output << format(type_tag, class_tag, level, length, ""); + } + else if(type_tag == OCTET_STRING || type_tag == BIT_STRING) + { + std::vector decoded_bits; + data.decode(decoded_bits, type_tag); + bool printing_octet_string_worked = false; + + if(recurse_deeper) + { + try + { + BER_Decoder inner(decoded_bits); + + std::ostringstream inner_data; + decode(inner_data, inner, level + 1); // recurse + + output << format(type_tag, class_tag, level, length, ""); + output << inner_data.str(); + printing_octet_string_worked = true; + } + catch(...) + { + } + } + + if(!printing_octet_string_worked) + { + output << format(type_tag, class_tag, level, length, + format_bin(type_tag, class_tag, decoded_bits)); + } + } + else if(ASN1_String::is_string_type(type_tag)) + { + ASN1_String str; + data.decode(str); + output << format(type_tag, class_tag, level, length, str.value()); + } + else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME) + { + ASN1_Time time; + data.decode(time); + output << format(type_tag, class_tag, level, length, time.readable_string()); + } + else + { + output << "Unknown ASN.1 tag class=" << static_cast(class_tag) + << " type=" << static_cast(type_tag) << "\n"; + } + + obj = decoder.get_next_object(); + } + } + +namespace { + +std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(class_tag == UNIVERSAL) + return asn1_tag_to_string(type_tag); + + if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET)) + return asn1_tag_to_string(type_tag); + + std::string name; + + if(class_tag & CONSTRUCTED) + name += "cons "; + + name += "[" + std::to_string(type_tag) + "]"; + + if(class_tag & APPLICATION) + { + name += " appl"; + } + if(class_tag & CONTEXT_SPECIFIC) + { + name += " context"; + } + + return name; + } + +} + +std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t level, + size_t length, + const std::string& value) const + { + bool should_skip = false; + + if(value.length() > m_print_limit) + { + should_skip = true; + } + + if((type_tag == OCTET_STRING || type_tag == BIT_STRING) && + value.length() > m_print_binary_limit) + { + should_skip = true; + } + + level += m_initial_level; + + std::ostringstream oss; + + oss << " d=" << std::setw(2) << level + << ", l=" << std::setw(4) << length << ":" + << std::string(level + 1, ' ') << format_type(type_tag, class_tag); + + if(value != "" && !should_skip) + { + const size_t current_pos = static_cast(oss.tellp()); + const size_t spaces_to_align = + (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos); + + oss << std::string(spaces_to_align, ' ') << value; + } + + oss << "\n"; + + return oss.str(); + } + +std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/, + ASN1_Tag /*class_tag*/, + const std::vector& vec) const + { + if(all_printable_chars(vec.data(), vec.size())) + { + return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size()); + } + else + return hex_encode(vec); + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/asn1_print.h b/comm/third_party/botan/src/lib/asn1/asn1_print.h new file mode 100644 index 0000000000..a6bc6b15f2 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_print.h @@ -0,0 +1,125 @@ +/* +* (C) 2014,2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_PRINT_H_ +#define BOTAN_ASN1_PRINT_H_ + +#include +#include +#include +#include + +namespace Botan { + +class BER_Decoder; + +/** +* Format ASN.1 data and call a virtual to format +*/ +class BOTAN_PUBLIC_API(2,4) ASN1_Formatter + { + public: + virtual ~ASN1_Formatter() = default; + + /** + * @param print_context_specific if true, try to parse nested context specific data. + * @param max_depth do not recurse more than this many times. If zero, recursion + * is unbounded. + */ + ASN1_Formatter(bool print_context_specific, size_t max_depth) : + m_print_context_specific(print_context_specific), + m_max_depth(max_depth) + {} + + void print_to_stream(std::ostream& out, + const uint8_t in[], + size_t len) const; + + std::string print(const uint8_t in[], size_t len) const; + + template + std::string print(const std::vector& vec) const + { + return print(vec.data(), vec.size()); + } + + protected: + /** + * This is called for each element + */ + virtual std::string format(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t level, + size_t length, + const std::string& value) const = 0; + + /** + * This is called to format binary elements that we don't know how to + * convert to a string The result will be passed as value to format; the + * tags are included as a hint to aid decoding. + */ + virtual std::string format_bin(ASN1_Tag type_tag, + ASN1_Tag class_tag, + const std::vector& vec) const = 0; + + private: + void decode(std::ostream& output, + BER_Decoder& decoder, + size_t level) const; + + const bool m_print_context_specific; + const size_t m_max_depth; + }; + +/** +* Format ASN.1 data into human readable output. The exact form of the output for +* any particular input is not guaranteed and may change from release to release. +*/ +class BOTAN_PUBLIC_API(2,4) ASN1_Pretty_Printer final : public ASN1_Formatter + { + public: + /** + * @param print_limit strings larger than this are not printed + * @param print_binary_limit binary strings larger than this are not printed + * @param print_context_specific if true, try to parse nested context specific data. + * @param initial_level the initial depth (0 or 1 are the only reasonable values) + * @param value_column ASN.1 values are lined up at this column in output + * @param max_depth do not recurse more than this many times. If zero, recursion + * is unbounded. + */ + ASN1_Pretty_Printer(size_t print_limit = 4096, + size_t print_binary_limit = 2048, + bool print_context_specific = true, + size_t initial_level = 0, + size_t value_column = 60, + size_t max_depth = 64) : + ASN1_Formatter(print_context_specific, max_depth), + m_print_limit(print_limit), + m_print_binary_limit(print_binary_limit), + m_initial_level(initial_level), + m_value_column(value_column) + {} + + private: + std::string format(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t level, + size_t length, + const std::string& value) const override; + + std::string format_bin(ASN1_Tag type_tag, + ASN1_Tag class_tag, + const std::vector& vec) const override; + + const size_t m_print_limit; + const size_t m_print_binary_limit; + const size_t m_initial_level; + const size_t m_value_column; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/asn1_str.cpp b/comm/third_party/botan/src/lib/asn1/asn1_str.cpp new file mode 100644 index 0000000000..6a31c5bb2f --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_str.cpp @@ -0,0 +1,153 @@ +/* +* Simple ASN.1 String Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Choose an encoding for the string +*/ +ASN1_Tag choose_encoding(const std::string& str) + { + static const uint8_t IS_PRINTABLE[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + for(size_t i = 0; i != str.size(); ++i) + { + if(!IS_PRINTABLE[static_cast(str[i])]) + { + return UTF8_STRING; + } + } + return PRINTABLE_STRING; + } + +void assert_is_string_type(ASN1_Tag tag) + { + if(!ASN1_String::is_string_type(tag)) + { + throw Invalid_Argument("ASN1_String: Unknown string type " + + std::to_string(tag)); + } + } + +} + +//static +bool ASN1_String::is_string_type(ASN1_Tag tag) + { + return (tag == NUMERIC_STRING || + tag == PRINTABLE_STRING || + tag == VISIBLE_STRING || + tag == T61_STRING || + tag == IA5_STRING || + tag == UTF8_STRING || + tag == BMP_STRING || + tag == UNIVERSAL_STRING); + } + + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : m_utf8_str(str), m_tag(t) + { + if(m_tag == DIRECTORY_STRING) + { + m_tag = choose_encoding(m_utf8_str); + } + + assert_is_string_type(m_tag); + } + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str) : + m_utf8_str(str), + m_tag(choose_encoding(m_utf8_str)) + {} + +/* +* Return this string in ISO 8859-1 encoding +*/ +std::string ASN1_String::iso_8859() const + { + return utf8_to_latin1(m_utf8_str); + } + +/* +* DER encode an ASN1_String +*/ +void ASN1_String::encode_into(DER_Encoder& encoder) const + { + if(m_data.empty()) + { + encoder.add_object(tagging(), UNIVERSAL, m_utf8_str); + } + else + { + // If this string was decoded, reserialize using original encoding + encoder.add_object(tagging(), UNIVERSAL, m_data.data(), m_data.size()); + } + } + +/* +* Decode a BER encoded ASN1_String +*/ +void ASN1_String::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + + assert_is_string_type(obj.type()); + + m_tag = obj.type(); + m_data.assign(obj.bits(), obj.bits() + obj.length()); + + if(m_tag == BMP_STRING) + { + m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size()); + } + else if(m_tag == UNIVERSAL_STRING) + { + m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size()); + } + else + { + // All other supported string types are UTF-8 or some subset thereof + m_utf8_str = ASN1::to_string(obj); + } + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/asn1_str.h b/comm/third_party/botan/src/lib/asn1/asn1_str.h new file mode 100644 index 0000000000..fed4950cc3 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_str.h @@ -0,0 +1,14 @@ +/* +* ASN.1 string type +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_STRING_H_ +#define BOTAN_ASN1_STRING_H_ + +#include +BOTAN_DEPRECATED_HEADER(asn1_str.h) + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/asn1_time.cpp b/comm/third_party/botan/src/lib/asn1/asn1_time.cpp new file mode 100644 index 0000000000..004be27b97 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_time.cpp @@ -0,0 +1,290 @@ +/* +* X.509 Time Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +ASN1_Time::ASN1_Time(const std::chrono::system_clock::time_point& time) + { + calendar_point cal = calendar_value(time); + + m_year = cal.get_year(); + m_month = cal.get_month(); + m_day = cal.get_day(); + m_hour = cal.get_hour(); + m_minute = cal.get_minutes(); + m_second = cal.get_seconds(); + + m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME; + } + +ASN1_Time::ASN1_Time(const std::string& t_spec, ASN1_Tag tag) + { + set_to(t_spec, tag); + } + +void ASN1_Time::encode_into(DER_Encoder& der) const + { + BOTAN_ARG_CHECK(m_tag == UTC_TIME || m_tag == GENERALIZED_TIME, + "ASN1_Time: Bad encoding tag"); + + der.add_object(m_tag, UNIVERSAL, to_string()); + } + +void ASN1_Time::decode_from(BER_Decoder& source) + { + BER_Object ber_time = source.get_next_object(); + + set_to(ASN1::to_string(ber_time), ber_time.type()); + } + +std::string ASN1_Time::to_string() const + { + if(time_is_set() == false) + throw Invalid_State("ASN1_Time::to_string: No time set"); + + uint32_t full_year = m_year; + + if(m_tag == UTC_TIME) + { + if(m_year < 1950 || m_year >= 2050) + throw Encoding_Error("ASN1_Time: The time " + readable_string() + + " cannot be encoded as a UTCTime"); + + full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900); + } + + const uint64_t YEAR_FACTOR = 10000000000ULL; + const uint64_t MON_FACTOR = 100000000; + const uint64_t DAY_FACTOR = 1000000; + const uint64_t HOUR_FACTOR = 10000; + const uint64_t MIN_FACTOR = 100; + + const uint64_t int_repr = + YEAR_FACTOR * full_year + + MON_FACTOR * m_month + + DAY_FACTOR * m_day + + HOUR_FACTOR * m_hour + + MIN_FACTOR * m_minute + + m_second; + + std::string repr = std::to_string(int_repr) + "Z"; + + uint32_t desired_size = (m_tag == UTC_TIME) ? 13 : 15; + + while(repr.size() < desired_size) + repr = "0" + repr; + + return repr; + } + +std::string ASN1_Time::readable_string() const + { + if(time_is_set() == false) + throw Invalid_State("ASN1_Time::readable_string: No time set"); + + // desired format: "%04d/%02d/%02d %02d:%02d:%02d UTC" + std::stringstream output; + output << std::setfill('0') + << std::setw(4) << m_year << "/" + << std::setw(2) << m_month << "/" + << std::setw(2) << m_day + << " " + << std::setw(2) << m_hour << ":" + << std::setw(2) << m_minute << ":" + << std::setw(2) << m_second + << " UTC"; + + return output.str(); + } + +bool ASN1_Time::time_is_set() const + { + return (m_year != 0); + } + +int32_t ASN1_Time::cmp(const ASN1_Time& other) const + { + if(time_is_set() == false) + throw Invalid_State("ASN1_Time::cmp: No time set"); + + const int32_t EARLIER = -1, LATER = 1, SAME_TIME = 0; + + if(m_year < other.m_year) return EARLIER; + if(m_year > other.m_year) return LATER; + if(m_month < other.m_month) return EARLIER; + if(m_month > other.m_month) return LATER; + if(m_day < other.m_day) return EARLIER; + if(m_day > other.m_day) return LATER; + if(m_hour < other.m_hour) return EARLIER; + if(m_hour > other.m_hour) return LATER; + if(m_minute < other.m_minute) return EARLIER; + if(m_minute > other.m_minute) return LATER; + if(m_second < other.m_second) return EARLIER; + if(m_second > other.m_second) return LATER; + + return SAME_TIME; + } + +void ASN1_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) + { + if(spec_tag == UTC_OR_GENERALIZED_TIME) + { + try + { + set_to(t_spec, GENERALIZED_TIME); + return; + } + catch(Invalid_Argument&) {} // Not a generalized time. Continue + + try + { + set_to(t_spec, UTC_TIME); + return; + } + catch(Invalid_Argument&) {} // Not a UTC time. Continue + + throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime."); + } + + BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag."); + + BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty."); + + BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z"); + + if(spec_tag == GENERALIZED_TIME) + { + BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string"); + } + else if(spec_tag == UTC_TIME) + { + BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string"); + } + + const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4; + + std::vector params; + std::string current; + + for(size_t j = 0; j != YEAR_SIZE; ++j) + current += t_spec[j]; + params.push_back(current); + current.clear(); + + for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j) + { + current += t_spec[j]; + if(current.size() == 2) + { + params.push_back(current); + current.clear(); + } + } + + m_year = to_u32bit(params[0]); + m_month = to_u32bit(params[1]); + m_day = to_u32bit(params[2]); + m_hour = to_u32bit(params[3]); + m_minute = to_u32bit(params[4]); + m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0; + m_tag = spec_tag; + + if(spec_tag == UTC_TIME) + { + if(m_year >= 50) m_year += 1900; + else m_year += 2000; + } + + if(!passes_sanity_check()) + throw Invalid_Argument("Time " + t_spec + " does not seem to be valid"); + } + +/* +* Do a general sanity check on the time +*/ +bool ASN1_Time::passes_sanity_check() const + { + // AppVeyor's trust store includes a cert with expiration date in 3016 ... + if(m_year < 1950 || m_year > 3100) + return false; + if(m_month == 0 || m_month > 12) + return false; + + const uint32_t days_in_month[12] = { 31, 28+1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if(m_day == 0 || m_day > days_in_month[m_month-1]) + return false; + + if(m_month == 2 && m_day == 29) + { + if(m_year % 4 != 0) + return false; // not a leap year + + if(m_year % 100 == 0 && m_year % 400 != 0) + return false; + } + + if(m_hour >= 24 || m_minute >= 60 || m_second > 60) + return false; + + if (m_tag == UTC_TIME) + { + /* + UTCTime limits the value of components such that leap seconds + are not covered. See "UNIVERSAL 23" in "Information technology + Abstract Syntax Notation One (ASN.1): Specification of basic notation" + + http://www.itu.int/ITU-T/studygroups/com17/languages/ + */ + if(m_second > 59) + { + return false; + } + } + + return true; + } + +std::chrono::system_clock::time_point ASN1_Time::to_std_timepoint() const + { + return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint(); + } + +uint64_t ASN1_Time::time_since_epoch() const + { + auto tp = this->to_std_timepoint(); + return std::chrono::duration_cast(tp.time_since_epoch()).count(); + } + +/* +* Compare two ASN1_Times for in various ways +*/ +bool operator==(const ASN1_Time& t1, const ASN1_Time& t2) + { return (t1.cmp(t2) == 0); } +bool operator!=(const ASN1_Time& t1, const ASN1_Time& t2) + { return (t1.cmp(t2) != 0); } + +bool operator<=(const ASN1_Time& t1, const ASN1_Time& t2) + { return (t1.cmp(t2) <= 0); } +bool operator>=(const ASN1_Time& t1, const ASN1_Time& t2) + { return (t1.cmp(t2) >= 0); } + +bool operator<(const ASN1_Time& t1, const ASN1_Time& t2) + { return (t1.cmp(t2) < 0); } +bool operator>(const ASN1_Time& t1, const ASN1_Time& t2) + { return (t1.cmp(t2) > 0); } + +} diff --git a/comm/third_party/botan/src/lib/asn1/asn1_time.h b/comm/third_party/botan/src/lib/asn1/asn1_time.h new file mode 100644 index 0000000000..55ef82e052 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/asn1_time.h @@ -0,0 +1,14 @@ +/* +* ASN.1 Time Representation +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_TIME_H_ +#define BOTAN_ASN1_TIME_H_ + +#include +BOTAN_DEPRECATED_HEADER(asn1_time.h) + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/ber_dec.cpp b/comm/third_party/botan/src/lib/asn1/ber_dec.cpp new file mode 100644 index 0000000000..c5af2f9338 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/ber_dec.cpp @@ -0,0 +1,549 @@ +/* +* BER Decoder +* (C) 1999-2008,2015,2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* This value is somewhat arbitrary. OpenSSL allows up to 128 nested +* indefinite length sequences. If you increase this, also increase the +* limit in the test in test_asn1.cpp +*/ +const size_t ALLOWED_EOC_NESTINGS = 16; + +/* +* BER decode an ASN.1 type tag +*/ +size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag) + { + uint8_t b; + if(!ber->read_byte(b)) + { + class_tag = type_tag = NO_OBJECT; + return 0; + } + + if((b & 0x1F) != 0x1F) + { + type_tag = ASN1_Tag(b & 0x1F); + class_tag = ASN1_Tag(b & 0xE0); + return 1; + } + + size_t tag_bytes = 1; + class_tag = ASN1_Tag(b & 0xE0); + + size_t tag_buf = 0; + while(true) + { + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Long-form tag truncated"); + if(tag_buf & 0xFF000000) + throw BER_Decoding_Error("Long-form tag overflowed 32 bits"); + ++tag_bytes; + tag_buf = (tag_buf << 7) | (b & 0x7F); + if((b & 0x80) == 0) break; + } + type_tag = ASN1_Tag(tag_buf); + return tag_bytes; + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource* src, size_t allow_indef); + +/* +* BER decode an ASN.1 length field +*/ +size_t decode_length(DataSource* ber, size_t& field_size, size_t allow_indef) + { + uint8_t b; + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Length field not found"); + field_size = 1; + if((b & 0x80) == 0) + return b; + + field_size += (b & 0x7F); + if(field_size > 5) + throw BER_Decoding_Error("Length field is too large"); + + if(field_size == 1) + { + if(allow_indef == 0) + { + throw BER_Decoding_Error("Nested EOC markers too deep, rejecting to avoid stack exhaustion"); + } + else + { + return find_eoc(ber, allow_indef - 1); + } + } + + size_t length = 0; + + for(size_t i = 0; i != field_size - 1; ++i) + { + if(get_byte(0, length) != 0) + throw BER_Decoding_Error("Field length overflow"); + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Corrupted length field"); + length = (length << 8) | b; + } + return length; + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource* ber, size_t allow_indef) + { + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE), data; + + while(true) + { + const size_t got = ber->peek(buffer.data(), buffer.size(), data.size()); + if(got == 0) + break; + + data += std::make_pair(buffer.data(), got); + } + + DataSource_Memory source(data); + data.clear(); + + size_t length = 0; + while(true) + { + ASN1_Tag type_tag, class_tag; + size_t tag_size = decode_tag(&source, type_tag, class_tag); + if(type_tag == NO_OBJECT) + break; + + size_t length_size = 0; + size_t item_size = decode_length(&source, length_size, allow_indef); + source.discard_next(item_size); + + length = BOTAN_CHECKED_ADD(length, item_size); + length = BOTAN_CHECKED_ADD(length, tag_size); + length = BOTAN_CHECKED_ADD(length, length_size); + + if(type_tag == EOC && class_tag == UNIVERSAL) + break; + } + return length; + } + +class DataSource_BERObject final : public DataSource + { + public: + size_t read(uint8_t out[], size_t length) override + { + BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); + const size_t got = std::min(m_obj.length() - m_offset, length); + copy_mem(out, m_obj.bits() + m_offset, got); + m_offset += got; + return got; + } + + size_t peek(uint8_t out[], size_t length, size_t peek_offset) const override + { + BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); + const size_t bytes_left = m_obj.length() - m_offset; + + if(peek_offset >= bytes_left) + return 0; + + const size_t got = std::min(bytes_left - peek_offset, length); + copy_mem(out, m_obj.bits() + peek_offset, got); + return got; + } + + bool check_available(size_t n) override + { + BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); + return (n <= (m_obj.length() - m_offset)); + } + + bool end_of_data() const override + { + return get_bytes_read() == m_obj.length(); + } + + size_t get_bytes_read() const override { return m_offset; } + + explicit DataSource_BERObject(BER_Object&& obj) : m_obj(std::move(obj)), m_offset(0) {} + + private: + BER_Object m_obj; + size_t m_offset; + }; + +} + +/* +* Check if more objects are there +*/ +bool BER_Decoder::more_items() const + { + if(m_source->end_of_data() && !m_pushed.is_set()) + return false; + return true; + } + +/* +* Verify that no bytes remain in the source +*/ +BER_Decoder& BER_Decoder::verify_end() + { + return verify_end("BER_Decoder::verify_end called, but data remains"); + } + +/* +* Verify that no bytes remain in the source +*/ +BER_Decoder& BER_Decoder::verify_end(const std::string& err) + { + if(!m_source->end_of_data() || m_pushed.is_set()) + throw Decoding_Error(err); + return (*this); + } + +/* +* Discard all the bytes remaining in the source +*/ +BER_Decoder& BER_Decoder::discard_remaining() + { + uint8_t buf; + while(m_source->read_byte(buf)) + {} + return (*this); + } + +/* +* Return the BER encoding of the next object +*/ +BER_Object BER_Decoder::get_next_object() + { + BER_Object next; + + if(m_pushed.is_set()) + { + std::swap(next, m_pushed); + return next; + } + + for(;;) + { + ASN1_Tag type_tag, class_tag; + decode_tag(m_source, type_tag, class_tag); + next.set_tagging(type_tag, class_tag); + if(next.is_set() == false) // no more objects + return next; + + size_t field_size; + const size_t length = decode_length(m_source, field_size, ALLOWED_EOC_NESTINGS); + if(!m_source->check_available(length)) + throw BER_Decoding_Error("Value truncated"); + + uint8_t* out = next.mutable_bits(length); + if(m_source->read(out, length) != length) + throw BER_Decoding_Error("Value truncated"); + + if(next.tagging() == EOC) + continue; + else + break; + } + + return next; + } + +/* +* Push a object back into the stream +*/ +void BER_Decoder::push_back(const BER_Object& obj) + { + if(m_pushed.is_set()) + throw Invalid_State("BER_Decoder: Only one push back is allowed"); + m_pushed = obj; + } + +void BER_Decoder::push_back(BER_Object&& obj) + { + if(m_pushed.is_set()) + throw Invalid_State("BER_Decoder: Only one push back is allowed"); + m_pushed = std::move(obj); + } + +BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + return BER_Decoder(std::move(obj), this); + } + +/* +* Finish decoding a CONSTRUCTED type +*/ +BER_Decoder& BER_Decoder::end_cons() + { + if(!m_parent) + throw Invalid_State("BER_Decoder::end_cons called with null parent"); + if(!m_source->end_of_data()) + throw Decoding_Error("BER_Decoder::end_cons called with data left"); + return (*m_parent); + } + +BER_Decoder::BER_Decoder(BER_Object&& obj, BER_Decoder* parent) + { + m_data_src.reset(new DataSource_BERObject(std::move(obj))); + m_source = m_data_src.get(); + m_parent = parent; + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(DataSource& src) + { + m_source = &src; + } + +/* +* BER_Decoder Constructor + */ +BER_Decoder::BER_Decoder(const uint8_t data[], size_t length) + { + m_data_src.reset(new DataSource_Memory(data, length)); + m_source = m_data_src.get(); + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const secure_vector& data) + { + m_data_src.reset(new DataSource_Memory(data)); + m_source = m_data_src.get(); + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const std::vector& data) + { + m_data_src.reset(new DataSource_Memory(data.data(), data.size())); + m_source = m_data_src.get(); + } + +/* +* BER_Decoder Copy Constructor +*/ +BER_Decoder::BER_Decoder(const BER_Decoder& other) + { + m_source = other.m_source; + + // take ownership + std::swap(m_data_src, other.m_data_src); + m_parent = other.m_parent; + } + +/* +* Request for an object to decode itself +*/ +BER_Decoder& BER_Decoder::decode(ASN1_Object& obj, + ASN1_Tag, ASN1_Tag) + { + obj.decode_from(*this); + return (*this); + } + +/* +* Decode a BER encoded NULL +*/ +BER_Decoder& BER_Decoder::decode_null() + { + BER_Object obj = get_next_object(); + obj.assert_is_a(NULL_TAG, UNIVERSAL); + if(obj.length() > 0) + throw BER_Decoding_Error("NULL object had nonzero size"); + return (*this); + } + +BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) + { + secure_vector out_vec; + decode(out_vec, OCTET_STRING); + out = BigInt::decode(out_vec.data(), out_vec.size()); + return (*this); + } + +/* +* Decode a BER encoded BOOLEAN +*/ +BER_Decoder& BER_Decoder::decode(bool& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.length() != 1) + throw BER_Decoding_Error("BER boolean value had invalid size"); + + out = (obj.bits()[0]) ? true : false; + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(size_t& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.is_negative()) + throw BER_Decoding_Error("Decoded small integer value was negative"); + + if(integer.bits() > 32) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + out = 0; + for(size_t i = 0; i != 4; ++i) + out = (out << 8) | integer.byte_at(3-i); + + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +uint64_t BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t T_bytes) + { + if(T_bytes > 8) + throw BER_Decoding_Error("Can't decode small integer over 8 bytes"); + + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.bits() > 8*T_bytes) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + uint64_t out = 0; + for(size_t i = 0; i != 8; ++i) + out = (out << 8) | integer.byte_at(7-i); + + return out; + } + +/* +* Decode a BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(BigInt& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.length() == 0) + { + out = 0; + } + else + { + const bool negative = (obj.bits()[0] & 0x80) ? true : false; + + if(negative) + { + secure_vector vec(obj.bits(), obj.bits() + obj.length()); + for(size_t i = obj.length(); i > 0; --i) + if(vec[i-1]--) + break; + for(size_t i = 0; i != obj.length(); ++i) + vec[i] = ~vec[i]; + out = BigInt(vec.data(), vec.size()); + out.flip_sign(); + } + else + { + out = BigInt(obj.bits(), obj.length()); + } + } + + return (*this); + } + +namespace { + +template +void asn1_decode_binary_string(std::vector& buffer, + const BER_Object& obj, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + obj.assert_is_a(type_tag, class_tag); + + if(real_type == OCTET_STRING) + { + buffer.assign(obj.bits(), obj.bits() + obj.length()); + } + else + { + if(obj.length() == 0) + throw BER_Decoding_Error("Invalid BIT STRING"); + if(obj.bits()[0] >= 8) + throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); + + buffer.resize(obj.length() - 1); + + if(obj.length() > 1) + copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1); + } + } + +} + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(secure_vector& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag); + return (*this); + } + +BER_Decoder& BER_Decoder::decode(std::vector& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag); + return (*this); + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/ber_dec.h b/comm/third_party/botan/src/lib/asn1/ber_dec.h new file mode 100644 index 0000000000..1fb8c4a9da --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/ber_dec.h @@ -0,0 +1,418 @@ +/* +* BER Decoder +* (C) 1999-2010,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BER_DECODER_H_ +#define BOTAN_BER_DECODER_H_ + +#include +#include + +namespace Botan { + +class BigInt; + +/** +* BER Decoding Object +*/ +class BOTAN_PUBLIC_API(2,0) BER_Decoder final + { + public: + /** + * Set up to BER decode the data in buf of length len + */ + BER_Decoder(const uint8_t buf[], size_t len); + + /** + * Set up to BER decode the data in vec + */ + explicit BER_Decoder(const secure_vector& vec); + + /** + * Set up to BER decode the data in vec + */ + explicit BER_Decoder(const std::vector& vec); + + /** + * Set up to BER decode the data in src + */ + explicit BER_Decoder(DataSource& src); + + /** + * Set up to BER decode the data in obj + */ + BER_Decoder(const BER_Object& obj) : + BER_Decoder(obj.bits(), obj.length()) {} + + /** + * Set up to BER decode the data in obj + */ + BER_Decoder(BER_Object&& obj) : + BER_Decoder(std::move(obj), nullptr) {} + + BER_Decoder(const BER_Decoder& other); + + BER_Decoder& operator=(const BER_Decoder&) = delete; + + /** + * Get the next object in the data stream. + * If EOF, returns an object with type NO_OBJECT. + */ + BER_Object get_next_object(); + + BER_Decoder& get_next(BER_Object& ber) + { + ber = get_next_object(); + return (*this); + } + + /** + * Push an object back onto the stream. Throws if another + * object was previously pushed and has not been subsequently + * read out. + */ + void push_back(const BER_Object& obj); + + /** + * Push an object back onto the stream. Throws if another + * object was previously pushed and has not been subsequently + * read out. + */ + void push_back(BER_Object&& obj); + + /** + * Return true if there is at least one more item remaining + */ + bool more_items() const; + + /** + * Verify the stream is concluded, throws otherwise. + * Returns (*this) + */ + BER_Decoder& verify_end(); + + /** + * Verify the stream is concluded, throws otherwise. + * Returns (*this) + */ + BER_Decoder& verify_end(const std::string& err_msg); + + /** + * Discard any data that remains unread + * Returns (*this) + */ + BER_Decoder& discard_remaining(); + + /** + * Start decoding a constructed data (sequence or set) + */ + BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL); + + /** + * Finish decoding a constructed data, throws if any data remains. + * Returns the parent of *this (ie the object on which start_cons was called). + */ + BER_Decoder& end_cons(); + + /** + * Get next object and copy value to POD type + * Asserts value length is equal to POD type sizeof. + * Asserts Type tag and optional Class tag according to parameters. + * Copy value to POD type (struct, union, C-style array, std::array, etc.). + * @param out POD type reference where to copy object value + * @param type_tag ASN1_Tag enum to assert type on object read + * @param class_tag ASN1_Tag enum to assert class on object read (default: CONTEXT_SPECIFIC) + * @return this reference + */ + template + BER_Decoder& get_next_value(T &out, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + static_assert(std::is_standard_layout::value && std::is_trivial::value, "Type must be POD"); + + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if (obj.length() != sizeof(T)) + throw BER_Decoding_Error( + "Size mismatch. Object value size is " + + std::to_string(obj.length()) + + "; Output type size is " + + std::to_string(sizeof(T))); + + copy_mem(reinterpret_cast(&out), obj.bits(), obj.length()); + + return (*this); + } + + /* + * Save all the bytes remaining in the source + */ + template + BER_Decoder& raw_bytes(std::vector& out) + { + out.clear(); + uint8_t buf; + while(m_source->read_byte(buf)) + out.push_back(buf); + return (*this); + } + + BER_Decoder& decode_null(); + + /** + * Decode a BER encoded BOOLEAN + */ + BER_Decoder& decode(bool& out) + { + return decode(out, BOOLEAN, UNIVERSAL); + } + + /* + * Decode a small BER encoded INTEGER + */ + BER_Decoder& decode(size_t& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + + /* + * Decode a BER encoded INTEGER + */ + BER_Decoder& decode(BigInt& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + + std::vector get_next_octet_string() + { + std::vector out_vec; + decode(out_vec, OCTET_STRING); + return out_vec; + } + + /* + * BER decode a BIT STRING or OCTET STRING + */ + template + BER_Decoder& decode(std::vector& out, ASN1_Tag real_type) + { + return decode(out, real_type, real_type, UNIVERSAL); + } + + BER_Decoder& decode(bool& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(size_t& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(BigInt& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(std::vector& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(secure_vector& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(class ASN1_Object& obj, + ASN1_Tag type_tag = NO_OBJECT, + ASN1_Tag class_tag = NO_OBJECT); + + /** + * Decode an integer value which is typed as an octet string + */ + BER_Decoder& decode_octet_string_bigint(BigInt& b); + + uint64_t decode_constrained_integer(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t T_bytes); + + template BER_Decoder& decode_integer_type(T& out) + { + return decode_integer_type(out, INTEGER, UNIVERSAL); + } + + template + BER_Decoder& decode_integer_type(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + out = static_cast(decode_constrained_integer(type_tag, class_tag, sizeof(out))); + return (*this); + } + + template + BER_Decoder& decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value = T()); + + template + BER_Decoder& decode_optional_implicit( + T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + ASN1_Tag real_type, + ASN1_Tag real_class, + const T& default_value = T()); + + template + BER_Decoder& decode_list(std::vector& out, + ASN1_Tag type_tag = SEQUENCE, + ASN1_Tag class_tag = UNIVERSAL); + + template + BER_Decoder& decode_and_check(const T& expected, + const std::string& error_msg) + { + T actual; + decode(actual); + + if(actual != expected) + throw Decoding_Error(error_msg); + + return (*this); + } + + /* + * Decode an OPTIONAL string type + */ + template + BER_Decoder& decode_optional_string(std::vector& out, + ASN1_Tag real_type, + uint16_t type_no, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + BER_Object obj = get_next_object(); + + ASN1_Tag type_tag = static_cast(type_no); + + if(obj.is_a(type_tag, class_tag)) + { + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) + { + BER_Decoder(std::move(obj)).decode(out, real_type).verify_end(); + } + else + { + push_back(std::move(obj)); + decode(out, real_type, type_tag, class_tag); + } + } + else + { + out.clear(); + push_back(std::move(obj)); + } + + return (*this); + } + + private: + BER_Decoder(BER_Object&& obj, BER_Decoder* parent); + + BER_Decoder* m_parent = nullptr; + BER_Object m_pushed; + // either m_data_src.get() or an unowned pointer + DataSource* m_source; + mutable std::unique_ptr m_data_src; + }; + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template +BER_Decoder& BER_Decoder::decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.is_a(type_tag, class_tag)) + { + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) + { + BER_Decoder(std::move(obj)).decode(out).verify_end(); + } + else + { + push_back(std::move(obj)); + decode(out, type_tag, class_tag); + } + } + else + { + out = default_value; + push_back(std::move(obj)); + } + + return (*this); + } + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template +BER_Decoder& BER_Decoder::decode_optional_implicit( + T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + ASN1_Tag real_type, + ASN1_Tag real_class, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.is_a(type_tag, class_tag)) + { + obj.set_tagging(real_type, real_class); + push_back(std::move(obj)); + decode(out, real_type, real_class); + } + else + { + // Not what we wanted, push it back on the stream + out = default_value; + push_back(std::move(obj)); + } + + return (*this); + } +/* +* Decode a list of homogenously typed values +*/ +template +BER_Decoder& BER_Decoder::decode_list(std::vector& vec, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Decoder list = start_cons(type_tag, class_tag); + + while(list.more_items()) + { + T value; + list.decode(value); + vec.push_back(std::move(value)); + } + + list.end_cons(); + + return (*this); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/der_enc.cpp b/comm/third_party/botan/src/lib/asn1/der_enc.cpp new file mode 100644 index 0000000000..056766f435 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/der_enc.cpp @@ -0,0 +1,405 @@ +/* +* DER Encoder +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* DER encode an ASN.1 type tag +*/ +void encode_tag(std::vector& encoded_tag, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if((class_tag | 0xE0) != 0xE0) + throw Encoding_Error("DER_Encoder: Invalid class tag " + + std::to_string(class_tag)); + + if(type_tag <= 30) + { + encoded_tag.push_back(static_cast(type_tag | class_tag)); + } + else + { + size_t blocks = high_bit(static_cast(type_tag)) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + BOTAN_ASSERT_NOMSG(blocks > 0); + + encoded_tag.push_back(static_cast(class_tag | 0x1F)); + for(size_t i = 0; i != blocks - 1; ++i) + encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F)); + encoded_tag.push_back(type_tag & 0x7F); + } + } + +/* +* DER encode an ASN.1 length field +*/ +void encode_length(std::vector& encoded_length, size_t length) + { + if(length <= 127) + { + encoded_length.push_back(static_cast(length)); + } + else + { + const size_t bytes_needed = significant_bytes(length); + + encoded_length.push_back(static_cast(0x80 | bytes_needed)); + + for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i) + encoded_length.push_back(get_byte(i, length)); + } + } + +} + +DER_Encoder::DER_Encoder(secure_vector& vec) + { + m_append_output = [&vec](const uint8_t b[], size_t l) + { + vec.insert(vec.end(), b, b + l); + }; + } + +DER_Encoder::DER_Encoder(std::vector& vec) + { + m_append_output = [&vec](const uint8_t b[], size_t l) + { + vec.insert(vec.end(), b, b + l); + }; + } + +/* +* Push the encoded SEQUENCE/SET to the encoder stream +*/ +void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der) + { + const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag | CONSTRUCTED); + + if(m_type_tag == SET) + { + std::sort(m_set_contents.begin(), m_set_contents.end()); + for(size_t i = 0; i != m_set_contents.size(); ++i) + m_contents += m_set_contents[i]; + m_set_contents.clear(); + } + + der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size()); + m_contents.clear(); + } + +/* +* Add an encoded value to the SEQUENCE/SET +*/ +void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length) + { + if(m_type_tag == SET) + m_set_contents.push_back(secure_vector(data, data + length)); + else + m_contents += std::make_pair(data, length); + } + +void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len, + const uint8_t val[], size_t val_len) + { + if(m_type_tag == SET) + { + secure_vector m; + m.reserve(hdr_len + val_len); + m += std::make_pair(hdr, hdr_len); + m += std::make_pair(val, val_len); + m_set_contents.push_back(std::move(m)); + } + else + { + m_contents += std::make_pair(hdr, hdr_len); + m_contents += std::make_pair(val, val_len); + } + } + +/* +* Return the type and class taggings +*/ +ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const + { + return ASN1_Tag(m_type_tag | m_class_tag); + } + +/* +* DER_Sequence Constructor +*/ +DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) : + m_type_tag(t1), m_class_tag(t2) + { + } + +/* +* Return the encoded contents +*/ +secure_vector DER_Encoder::get_contents() + { + if(m_subsequences.size() != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + if(m_append_output) + throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); + + secure_vector output; + std::swap(output, m_default_outbuf); + return output; + } + +std::vector DER_Encoder::get_contents_unlocked() + { + if(m_subsequences.size() != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + if(m_append_output) + throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); + + std::vector output(m_default_outbuf.begin(), m_default_outbuf.end()); + m_default_outbuf.clear(); + return output; + } + +/* +* Start a new ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + m_subsequences.push_back(DER_Sequence(type_tag, class_tag)); + return (*this); + } + +/* +* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::end_cons() + { + if(m_subsequences.empty()) + throw Invalid_State("DER_Encoder::end_cons: No such sequence"); + + DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size()-1]); + m_subsequences.pop_back(); + last_seq.push_contents(*this); + + return (*this); + } + +/* +* Start a new ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no) + { + ASN1_Tag type_tag = static_cast(type_no); + + // This would confuse DER_Sequence + if(type_tag == SET) + throw Internal_Error("DER_Encoder.start_explicit(SET) not supported"); + + return start_cons(type_tag, CONTEXT_SPECIFIC); + } + +/* +* Finish the current ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::end_explicit() + { + return end_cons(); + } + +/* +* Write raw bytes into the stream +*/ +DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length) + { + if(m_subsequences.size()) + { + m_subsequences[m_subsequences.size()-1].add_bytes(bytes, length); + } + else if(m_append_output) + { + m_append_output(bytes, length); + } + else + { + m_default_outbuf += std::make_pair(bytes, length); + } + + return (*this); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const uint8_t rep[], size_t length) + { + std::vector hdr; + encode_tag(hdr, type_tag, class_tag); + encode_length(hdr, length); + + if(m_subsequences.size()) + { + m_subsequences[m_subsequences.size()-1].add_bytes(hdr.data(), hdr.size(), rep, length); + } + else if(m_append_output) + { + m_append_output(hdr.data(), hdr.size()); + m_append_output(rep, length); + } + else + { + m_default_outbuf += hdr; + m_default_outbuf += std::make_pair(rep, length); + } + + return (*this); + } + +/* +* Encode a NULL object +*/ +DER_Encoder& DER_Encoder::encode_null() + { + return add_object(NULL_TAG, UNIVERSAL, nullptr, 0); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true) + { + return encode(is_true, BOOLEAN, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n) + { + return encode(BigInt(n), INTEGER, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n) + { + return encode(n, INTEGER, UNIVERSAL); + } + +/* +* Encode this object +*/ +DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, + ASN1_Tag real_type) + { + return encode(bytes, length, real_type, real_type, UNIVERSAL); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + uint8_t val = is_true ? 0xFF : 0x00; + return add_object(type_tag, class_tag, &val, 1); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(BigInt(n), type_tag, class_tag); + } + +/* +* DER encode an INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n == 0) + return add_object(type_tag, class_tag, 0); + + const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0; + secure_vector contents(extra_zero + n.bytes()); + n.binary_encode(&contents[extra_zero]); + if(n < 0) + { + for(size_t i = 0; i != contents.size(); ++i) + contents[i] = ~contents[i]; + for(size_t i = contents.size(); i > 0; --i) + if(++contents[i-1]) + break; + } + + return add_object(type_tag, class_tag, contents); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string"); + + if(real_type == BIT_STRING) + { + secure_vector encoded; + encoded.push_back(0); + encoded += std::make_pair(bytes, length); + return add_object(type_tag, class_tag, encoded); + } + else + return add_object(type_tag, class_tag, bytes, length); + } + +DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) + { + obj.encode_into(*this); + return (*this); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& rep_str) + { + const uint8_t* rep = cast_char_ptr_to_uint8(rep_str.data()); + const size_t rep_len = rep_str.size(); + return add_object(type_tag, class_tag, rep, rep_len); + } + +/* +* Write the encoding of the byte +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, + ASN1_Tag class_tag, uint8_t rep) + { + return add_object(type_tag, class_tag, &rep, 1); + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/der_enc.h b/comm/third_party/botan/src/lib/asn1/der_enc.h new file mode 100644 index 0000000000..93d53f4b91 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/der_enc.h @@ -0,0 +1,227 @@ +/* +* DER Encoder +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DER_ENCODER_H_ +#define BOTAN_DER_ENCODER_H_ + +#include +#include +#include + +namespace Botan { + +class BigInt; + +/** +* General DER Encoding Object +*/ +class BOTAN_PUBLIC_API(2,0) DER_Encoder final + { + public: + typedef std::function append_fn; + + /** + * DER encode, writing to an internal buffer + * Use get_contents or get_contents_unlocked to read the results + * after all encoding is completed. + */ + DER_Encoder() = default; + + /** + * DER encode, writing to @param vec + * If this constructor is used, get_contents* may not be called. + */ + DER_Encoder(secure_vector& vec); + + /** + * DER encode, writing to @param vec + * If this constructor is used, get_contents* may not be called. + */ + DER_Encoder(std::vector& vec); + + /** + * DER encode, calling append to write output + * If this constructor is used, get_contents* may not be called. + */ + DER_Encoder(append_fn append) : m_append_output(append) {} + + secure_vector get_contents(); + + /** + * Return the encoded contents as a std::vector + * + * If using this function, instead pass a std::vector to the + * contructor of DER_Encoder where the output will be placed. This + * avoids several unecessary copies. + */ + std::vector BOTAN_DEPRECATED("Use DER_Encoder(vector) instead") get_contents_unlocked(); + + DER_Encoder& start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag = UNIVERSAL); + DER_Encoder& end_cons(); + + DER_Encoder& start_explicit(uint16_t type_tag); + DER_Encoder& end_explicit(); + + /** + * Insert raw bytes directly into the output stream + */ + DER_Encoder& raw_bytes(const uint8_t val[], size_t len); + + template + DER_Encoder& raw_bytes(const std::vector& val) + { + return raw_bytes(val.data(), val.size()); + } + + DER_Encoder& encode_null(); + DER_Encoder& encode(bool b); + DER_Encoder& encode(size_t s); + DER_Encoder& encode(const BigInt& n); + DER_Encoder& encode(const uint8_t val[], size_t len, ASN1_Tag real_type); + + template + DER_Encoder& encode(const std::vector& vec, ASN1_Tag real_type) + { + return encode(vec.data(), vec.size(), real_type); + } + + DER_Encoder& encode(bool b, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(size_t s, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const BigInt& n, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const uint8_t v[], size_t len, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + template + DER_Encoder& encode(const std::vector& bytes, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(bytes.data(), bytes.size(), + real_type, type_tag, class_tag); + } + + template + DER_Encoder& encode_optional(const T& value, const T& default_value) + { + if(value != default_value) + encode(value); + return (*this); + } + + template + DER_Encoder& encode_list(const std::vector& values) + { + for(size_t i = 0; i != values.size(); ++i) + encode(values[i]); + return (*this); + } + + /* + * Request for an object to encode itself to this stream + */ + DER_Encoder& encode(const ASN1_Object& obj); + + /* + * Conditionally write some values to the stream + */ + DER_Encoder& encode_if(bool pred, DER_Encoder& enc) + { + if(pred) + return raw_bytes(enc.get_contents()); + return (*this); + } + + DER_Encoder& encode_if(bool pred, const ASN1_Object& obj) + { + if(pred) + encode(obj); + return (*this); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const uint8_t rep[], size_t length); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::vector& rep) + { + return add_object(type_tag, class_tag, rep.data(), rep.size()); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const secure_vector& rep) + { + return add_object(type_tag, class_tag, rep.data(), rep.size()); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& str); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + uint8_t val); + + private: + class DER_Sequence final + { + public: + ASN1_Tag tag_of() const; + + void push_contents(DER_Encoder& der); + + void add_bytes(const uint8_t val[], size_t len); + + void add_bytes(const uint8_t hdr[], size_t hdr_len, + const uint8_t val[], size_t val_len); + + DER_Sequence(ASN1_Tag, ASN1_Tag); + + DER_Sequence(DER_Sequence&& seq) + { + std::swap(m_type_tag, seq.m_type_tag); + std::swap(m_class_tag, seq.m_class_tag); + std::swap(m_contents, seq.m_contents); + std::swap(m_set_contents, seq.m_set_contents); + } + + DER_Sequence& operator=(DER_Sequence&& seq) + { + std::swap(m_type_tag, seq.m_type_tag); + std::swap(m_class_tag, seq.m_class_tag); + std::swap(m_contents, seq.m_contents); + std::swap(m_set_contents, seq.m_set_contents); + return (*this); + } + + DER_Sequence(const DER_Sequence& seq) = default; + + DER_Sequence& operator=(const DER_Sequence& seq) = default; + + private: + ASN1_Tag m_type_tag, m_class_tag; + secure_vector m_contents; + std::vector< secure_vector > m_set_contents; + }; + + append_fn m_append_output; + secure_vector m_default_outbuf; + std::vector m_subsequences; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/asn1/info.txt b/comm/third_party/botan/src/lib/asn1/info.txt new file mode 100644 index 0000000000..4772e1ca70 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/info.txt @@ -0,0 +1,7 @@ + +ASN1 -> 20171109 + + + +bigint + diff --git a/comm/third_party/botan/src/lib/asn1/oid_maps.cpp b/comm/third_party/botan/src/lib/asn1/oid_maps.cpp new file mode 100644 index 0000000000..d385dfd840 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/oid_maps.cpp @@ -0,0 +1,510 @@ +/* +* OID maps +* +* This file was automatically generated by ./src/scripts/oids.py on 2019-10-21 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::unordered_map OIDS::load_oid2str_map() + { + return std::unordered_map{ + { "0.3.4401.5.3.1.9.26", "Camellia-192/GCM" }, + { "0.3.4401.5.3.1.9.46", "Camellia-256/GCM" }, + { "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" }, + { "0.4.0.127.0.15.1.1.13.0", "XMSS" }, + { "1.0.14888.3.0.5", "ECKCDSA" }, + { "1.2.156.10197.1.104.100", "SM4/OCB" }, + { "1.2.156.10197.1.104.2", "SM4/CBC" }, + { "1.2.156.10197.1.104.8", "SM4/GCM" }, + { "1.2.156.10197.1.301", "sm2p256v1" }, + { "1.2.156.10197.1.301.1", "SM2" }, + { "1.2.156.10197.1.301.2", "SM2_Kex" }, + { "1.2.156.10197.1.301.3", "SM2_Enc" }, + { "1.2.156.10197.1.401", "SM3" }, + { "1.2.156.10197.1.501", "SM2_Sig/SM3" }, + { "1.2.156.10197.1.504", "RSA/EMSA3(SM3)" }, + { "1.2.250.1.223.101.256.1", "frp256v1" }, + { "1.2.392.200011.61.1.1.1.2", "Camellia-128/CBC" }, + { "1.2.392.200011.61.1.1.1.3", "Camellia-192/CBC" }, + { "1.2.392.200011.61.1.1.1.4", "Camellia-256/CBC" }, + { "1.2.410.200004.1.100.4.3", "ECKCDSA/EMSA1(SHA-1)" }, + { "1.2.410.200004.1.100.4.4", "ECKCDSA/EMSA1(SHA-224)" }, + { "1.2.410.200004.1.100.4.5", "ECKCDSA/EMSA1(SHA-256)" }, + { "1.2.410.200004.1.4", "SEED/CBC" }, + { "1.2.643.100.1", "GOST.OGRN" }, + { "1.2.643.100.111", "GOST.SubjectSigningTool" }, + { "1.2.643.100.112", "GOST.IssuerSigningTool" }, + { "1.2.643.2.2.19", "GOST-34.10" }, + { "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)" }, + { "1.2.643.2.2.35.1", "gost_256A" }, + { "1.2.643.2.2.36.0", "gost_256A" }, + { "1.2.643.3.131.1.1", "GOST.INN" }, + { "1.2.643.7.1.1.1.1", "GOST-34.10-2012-256" }, + { "1.2.643.7.1.1.1.2", "GOST-34.10-2012-512" }, + { "1.2.643.7.1.1.2.2", "Streebog-256" }, + { "1.2.643.7.1.1.2.3", "Streebog-512" }, + { "1.2.643.7.1.1.3.2", "GOST-34.10-2012-256/EMSA1(Streebog-256)" }, + { "1.2.643.7.1.1.3.3", "GOST-34.10-2012-512/EMSA1(Streebog-512)" }, + { "1.2.643.7.1.2.1.1.1", "gost_256A" }, + { "1.2.643.7.1.2.1.1.2", "gost_256B" }, + { "1.2.643.7.1.2.1.2.1", "gost_512A" }, + { "1.2.643.7.1.2.1.2.2", "gost_512B" }, + { "1.2.840.10040.4.1", "DSA" }, + { "1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)" }, + { "1.2.840.10045.2.1", "ECDSA" }, + { "1.2.840.10045.3.1.1", "secp192r1" }, + { "1.2.840.10045.3.1.2", "x962_p192v2" }, + { "1.2.840.10045.3.1.3", "x962_p192v3" }, + { "1.2.840.10045.3.1.4", "x962_p239v1" }, + { "1.2.840.10045.3.1.5", "x962_p239v2" }, + { "1.2.840.10045.3.1.6", "x962_p239v3" }, + { "1.2.840.10045.3.1.7", "secp256r1" }, + { "1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)" }, + { "1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)" }, + { "1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)" }, + { "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)" }, + { "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)" }, + { "1.2.840.10046.2.1", "DH" }, + { "1.2.840.113533.7.66.10", "CAST-128/CBC" }, + { "1.2.840.113533.7.66.15", "KeyWrap.CAST-128" }, + { "1.2.840.113549.1.1.1", "RSA" }, + { "1.2.840.113549.1.1.10", "RSA/EMSA4" }, + { "1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)" }, + { "1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)" }, + { "1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)" }, + { "1.2.840.113549.1.1.14", "RSA/EMSA3(SHA-224)" }, + { "1.2.840.113549.1.1.16", "RSA/EMSA3(SHA-512-256)" }, + { "1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)" }, + { "1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)" }, + { "1.2.840.113549.1.1.7", "RSA/OAEP" }, + { "1.2.840.113549.1.1.8", "MGF1" }, + { "1.2.840.113549.1.5.12", "PKCS5.PBKDF2" }, + { "1.2.840.113549.1.5.13", "PBE-PKCS5v20" }, + { "1.2.840.113549.1.9.1", "PKCS9.EmailAddress" }, + { "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest" }, + { "1.2.840.113549.1.9.16.3.18", "ChaCha20Poly1305" }, + { "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES" }, + { "1.2.840.113549.1.9.16.3.8", "Compression.Zlib" }, + { "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" }, + { "1.2.840.113549.1.9.3", "PKCS9.ContentType" }, + { "1.2.840.113549.1.9.4", "PKCS9.MessageDigest" }, + { "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword" }, + { "1.2.840.113549.2.10", "HMAC(SHA-384)" }, + { "1.2.840.113549.2.11", "HMAC(SHA-512)" }, + { "1.2.840.113549.2.13", "HMAC(SHA-512-256)" }, + { "1.2.840.113549.2.5", "MD5" }, + { "1.2.840.113549.2.7", "HMAC(SHA-160)" }, + { "1.2.840.113549.2.8", "HMAC(SHA-224)" }, + { "1.2.840.113549.2.9", "HMAC(SHA-256)" }, + { "1.2.840.113549.3.7", "TripleDES/CBC" }, + { "1.3.101.110", "Curve25519" }, + { "1.3.101.112", "Ed25519" }, + { "1.3.132.0.10", "secp256k1" }, + { "1.3.132.0.30", "secp160r2" }, + { "1.3.132.0.31", "secp192k1" }, + { "1.3.132.0.32", "secp224k1" }, + { "1.3.132.0.33", "secp224r1" }, + { "1.3.132.0.34", "secp384r1" }, + { "1.3.132.0.35", "secp521r1" }, + { "1.3.132.0.8", "secp160r1" }, + { "1.3.132.0.9", "secp160k1" }, + { "1.3.132.1.12", "ECDH" }, + { "1.3.14.3.2.26", "SHA-160" }, + { "1.3.14.3.2.7", "DES/CBC" }, + { "1.3.36.3.2.1", "RIPEMD-160" }, + { "1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)" }, + { "1.3.36.3.3.2.5.2.1", "ECGDSA" }, + { "1.3.36.3.3.2.5.4.1", "ECGDSA/EMSA1(RIPEMD-160)" }, + { "1.3.36.3.3.2.5.4.2", "ECGDSA/EMSA1(SHA-160)" }, + { "1.3.36.3.3.2.5.4.3", "ECGDSA/EMSA1(SHA-224)" }, + { "1.3.36.3.3.2.5.4.4", "ECGDSA/EMSA1(SHA-256)" }, + { "1.3.36.3.3.2.5.4.5", "ECGDSA/EMSA1(SHA-384)" }, + { "1.3.36.3.3.2.5.4.6", "ECGDSA/EMSA1(SHA-512)" }, + { "1.3.36.3.3.2.8.1.1.1", "brainpool160r1" }, + { "1.3.36.3.3.2.8.1.1.11", "brainpool384r1" }, + { "1.3.36.3.3.2.8.1.1.13", "brainpool512r1" }, + { "1.3.36.3.3.2.8.1.1.3", "brainpool192r1" }, + { "1.3.36.3.3.2.8.1.1.5", "brainpool224r1" }, + { "1.3.36.3.3.2.8.1.1.7", "brainpool256r1" }, + { "1.3.36.3.3.2.8.1.1.9", "brainpool320r1" }, + { "1.3.6.1.4.1.11591.12.2", "Tiger(24,3)" }, + { "1.3.6.1.4.1.11591.15.1", "OpenPGP.Ed25519" }, + { "1.3.6.1.4.1.11591.4.11", "Scrypt" }, + { "1.3.6.1.4.1.25258.1.3", "McEliece" }, + { "1.3.6.1.4.1.25258.1.5", "XMSS-draft6" }, + { "1.3.6.1.4.1.25258.1.6.1", "GOST-34.10-2012-256/EMSA1(SHA-256)" }, + { "1.3.6.1.4.1.25258.1.8", "XMSS-draft12" }, + { "1.3.6.1.4.1.25258.3.1", "Serpent/CBC" }, + { "1.3.6.1.4.1.25258.3.101", "Serpent/GCM" }, + { "1.3.6.1.4.1.25258.3.102", "Twofish/GCM" }, + { "1.3.6.1.4.1.25258.3.2", "Threefish-512/CBC" }, + { "1.3.6.1.4.1.25258.3.2.1", "AES-128/OCB" }, + { "1.3.6.1.4.1.25258.3.2.2", "AES-192/OCB" }, + { "1.3.6.1.4.1.25258.3.2.3", "AES-256/OCB" }, + { "1.3.6.1.4.1.25258.3.2.4", "Serpent/OCB" }, + { "1.3.6.1.4.1.25258.3.2.5", "Twofish/OCB" }, + { "1.3.6.1.4.1.25258.3.2.6", "Camellia-128/OCB" }, + { "1.3.6.1.4.1.25258.3.2.7", "Camellia-192/OCB" }, + { "1.3.6.1.4.1.25258.3.2.8", "Camellia-256/OCB" }, + { "1.3.6.1.4.1.25258.3.3", "Twofish/CBC" }, + { "1.3.6.1.4.1.25258.3.4.1", "AES-128/SIV" }, + { "1.3.6.1.4.1.25258.3.4.2", "AES-192/SIV" }, + { "1.3.6.1.4.1.25258.3.4.3", "AES-256/SIV" }, + { "1.3.6.1.4.1.25258.3.4.4", "Serpent/SIV" }, + { "1.3.6.1.4.1.25258.3.4.5", "Twofish/SIV" }, + { "1.3.6.1.4.1.25258.3.4.6", "Camellia-128/SIV" }, + { "1.3.6.1.4.1.25258.3.4.7", "Camellia-192/SIV" }, + { "1.3.6.1.4.1.25258.3.4.8", "Camellia-256/SIV" }, + { "1.3.6.1.4.1.25258.3.4.9", "SM4/SIV" }, + { "1.3.6.1.4.1.3029.1.2.1", "ElGamal" }, + { "1.3.6.1.4.1.3029.1.5.1", "OpenPGP.Curve25519" }, + { "1.3.6.1.4.1.311.20.2.2", "Microsoft SmartcardLogon" }, + { "1.3.6.1.4.1.311.20.2.3", "Microsoft UPN" }, + { "1.3.6.1.4.1.8301.3.1.2.9.0.38", "secp521r1" }, + { "1.3.6.1.5.5.7.1.1", "PKIX.AuthorityInformationAccess" }, + { "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth" }, + { "1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth" }, + { "1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning" }, + { "1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection" }, + { "1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem" }, + { "1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel" }, + { "1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser" }, + { "1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping" }, + { "1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning" }, + { "1.3.6.1.5.5.7.48.1", "PKIX.OCSP" }, + { "1.3.6.1.5.5.7.48.1.1", "PKIX.OCSP.BasicResponse" }, + { "1.3.6.1.5.5.7.48.2", "PKIX.CertificateAuthorityIssuers" }, + { "1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr" }, + { "2.16.840.1.101.3.4.1.2", "AES-128/CBC" }, + { "2.16.840.1.101.3.4.1.22", "AES-192/CBC" }, + { "2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192" }, + { "2.16.840.1.101.3.4.1.26", "AES-192/GCM" }, + { "2.16.840.1.101.3.4.1.27", "AES-192/CCM" }, + { "2.16.840.1.101.3.4.1.42", "AES-256/CBC" }, + { "2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256" }, + { "2.16.840.1.101.3.4.1.46", "AES-256/GCM" }, + { "2.16.840.1.101.3.4.1.47", "AES-256/CCM" }, + { "2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128" }, + { "2.16.840.1.101.3.4.1.6", "AES-128/GCM" }, + { "2.16.840.1.101.3.4.1.7", "AES-128/CCM" }, + { "2.16.840.1.101.3.4.2.1", "SHA-256" }, + { "2.16.840.1.101.3.4.2.10", "SHA-3(512)" }, + { "2.16.840.1.101.3.4.2.11", "SHAKE-128" }, + { "2.16.840.1.101.3.4.2.12", "SHAKE-256" }, + { "2.16.840.1.101.3.4.2.2", "SHA-384" }, + { "2.16.840.1.101.3.4.2.3", "SHA-512" }, + { "2.16.840.1.101.3.4.2.4", "SHA-224" }, + { "2.16.840.1.101.3.4.2.6", "SHA-512-256" }, + { "2.16.840.1.101.3.4.2.7", "SHA-3(224)" }, + { "2.16.840.1.101.3.4.2.8", "SHA-3(256)" }, + { "2.16.840.1.101.3.4.2.9", "SHA-3(384)" }, + { "2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)" }, + { "2.16.840.1.101.3.4.3.10", "ECDSA/EMSA1(SHA-3(256))" }, + { "2.16.840.1.101.3.4.3.11", "ECDSA/EMSA1(SHA-3(384))" }, + { "2.16.840.1.101.3.4.3.12", "ECDSA/EMSA1(SHA-3(512))" }, + { "2.16.840.1.101.3.4.3.13", "RSA/EMSA3(SHA-3(224))" }, + { "2.16.840.1.101.3.4.3.14", "RSA/EMSA3(SHA-3(256))" }, + { "2.16.840.1.101.3.4.3.15", "RSA/EMSA3(SHA-3(384))" }, + { "2.16.840.1.101.3.4.3.16", "RSA/EMSA3(SHA-3(512))" }, + { "2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)" }, + { "2.16.840.1.101.3.4.3.3", "DSA/EMSA1(SHA-384)" }, + { "2.16.840.1.101.3.4.3.4", "DSA/EMSA1(SHA-512)" }, + { "2.16.840.1.101.3.4.3.5", "DSA/EMSA1(SHA-3(224))" }, + { "2.16.840.1.101.3.4.3.6", "DSA/EMSA1(SHA-3(256))" }, + { "2.16.840.1.101.3.4.3.7", "DSA/EMSA1(SHA-3(384))" }, + { "2.16.840.1.101.3.4.3.8", "DSA/EMSA1(SHA-3(512))" }, + { "2.16.840.1.101.3.4.3.9", "ECDSA/EMSA1(SHA-3(224))" }, + { "2.16.840.1.113730.1.13", "Certificate Comment" }, + { "2.5.29.14", "X509v3.SubjectKeyIdentifier" }, + { "2.5.29.15", "X509v3.KeyUsage" }, + { "2.5.29.16", "X509v3.PrivateKeyUsagePeriod" }, + { "2.5.29.17", "X509v3.SubjectAlternativeName" }, + { "2.5.29.18", "X509v3.IssuerAlternativeName" }, + { "2.5.29.19", "X509v3.BasicConstraints" }, + { "2.5.29.20", "X509v3.CRLNumber" }, + { "2.5.29.21", "X509v3.ReasonCode" }, + { "2.5.29.23", "X509v3.HoldInstructionCode" }, + { "2.5.29.24", "X509v3.InvalidityDate" }, + { "2.5.29.28", "X509v3.CRLIssuingDistributionPoint" }, + { "2.5.29.30", "X509v3.NameConstraints" }, + { "2.5.29.31", "X509v3.CRLDistributionPoints" }, + { "2.5.29.32", "X509v3.CertificatePolicies" }, + { "2.5.29.32.0", "X509v3.AnyPolicy" }, + { "2.5.29.35", "X509v3.AuthorityKeyIdentifier" }, + { "2.5.29.36", "X509v3.PolicyConstraints" }, + { "2.5.29.37", "X509v3.ExtendedKeyUsage" }, + { "2.5.4.10", "X520.Organization" }, + { "2.5.4.11", "X520.OrganizationalUnit" }, + { "2.5.4.12", "X520.Title" }, + { "2.5.4.3", "X520.CommonName" }, + { "2.5.4.4", "X520.Surname" }, + { "2.5.4.42", "X520.GivenName" }, + { "2.5.4.43", "X520.Initials" }, + { "2.5.4.44", "X520.GenerationalQualifier" }, + { "2.5.4.46", "X520.DNQualifier" }, + { "2.5.4.5", "X520.SerialNumber" }, + { "2.5.4.6", "X520.Country" }, + { "2.5.4.65", "X520.Pseudonym" }, + { "2.5.4.7", "X520.Locality" }, + { "2.5.4.8", "X520.State" }, + { "2.5.4.9", "X520.StreetAddress" }, + { "2.5.8.1.1", "RSA" } + }; + } + +std::unordered_map OIDS::load_str2oid_map() + { + return std::unordered_map{ + { "AES-128/CBC", OID({2,16,840,1,101,3,4,1,2}) }, + { "AES-128/CCM", OID({2,16,840,1,101,3,4,1,7}) }, + { "AES-128/GCM", OID({2,16,840,1,101,3,4,1,6}) }, + { "AES-128/OCB", OID({1,3,6,1,4,1,25258,3,2,1}) }, + { "AES-128/SIV", OID({1,3,6,1,4,1,25258,3,4,1}) }, + { "AES-192/CBC", OID({2,16,840,1,101,3,4,1,22}) }, + { "AES-192/CCM", OID({2,16,840,1,101,3,4,1,27}) }, + { "AES-192/GCM", OID({2,16,840,1,101,3,4,1,26}) }, + { "AES-192/OCB", OID({1,3,6,1,4,1,25258,3,2,2}) }, + { "AES-192/SIV", OID({1,3,6,1,4,1,25258,3,4,2}) }, + { "AES-256/CBC", OID({2,16,840,1,101,3,4,1,42}) }, + { "AES-256/CCM", OID({2,16,840,1,101,3,4,1,47}) }, + { "AES-256/GCM", OID({2,16,840,1,101,3,4,1,46}) }, + { "AES-256/OCB", OID({1,3,6,1,4,1,25258,3,2,3}) }, + { "AES-256/SIV", OID({1,3,6,1,4,1,25258,3,4,3}) }, + { "CAST-128/CBC", OID({1,2,840,113533,7,66,10}) }, + { "Camellia-128/CBC", OID({1,2,392,200011,61,1,1,1,2}) }, + { "Camellia-128/GCM", OID({0,3,4401,5,3,1,9,6}) }, + { "Camellia-128/OCB", OID({1,3,6,1,4,1,25258,3,2,6}) }, + { "Camellia-128/SIV", OID({1,3,6,1,4,1,25258,3,4,6}) }, + { "Camellia-192/CBC", OID({1,2,392,200011,61,1,1,1,3}) }, + { "Camellia-192/GCM", OID({0,3,4401,5,3,1,9,26}) }, + { "Camellia-192/OCB", OID({1,3,6,1,4,1,25258,3,2,7}) }, + { "Camellia-192/SIV", OID({1,3,6,1,4,1,25258,3,4,7}) }, + { "Camellia-256/CBC", OID({1,2,392,200011,61,1,1,1,4}) }, + { "Camellia-256/GCM", OID({0,3,4401,5,3,1,9,46}) }, + { "Camellia-256/OCB", OID({1,3,6,1,4,1,25258,3,2,8}) }, + { "Camellia-256/SIV", OID({1,3,6,1,4,1,25258,3,4,8}) }, + { "Certificate Comment", OID({2,16,840,1,113730,1,13}) }, + { "ChaCha20Poly1305", OID({1,2,840,113549,1,9,16,3,18}) }, + { "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) }, + { "Curve25519", OID({1,3,101,110}) }, + { "DES/CBC", OID({1,3,14,3,2,7}) }, + { "DH", OID({1,2,840,10046,2,1}) }, + { "DSA", OID({1,2,840,10040,4,1}) }, + { "DSA/EMSA1(SHA-160)", OID({1,2,840,10040,4,3}) }, + { "DSA/EMSA1(SHA-224)", OID({2,16,840,1,101,3,4,3,1}) }, + { "DSA/EMSA1(SHA-256)", OID({2,16,840,1,101,3,4,3,2}) }, + { "DSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,5}) }, + { "DSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,6}) }, + { "DSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,7}) }, + { "DSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,8}) }, + { "DSA/EMSA1(SHA-384)", OID({2,16,840,1,101,3,4,3,3}) }, + { "DSA/EMSA1(SHA-512)", OID({2,16,840,1,101,3,4,3,4}) }, + { "ECDH", OID({1,3,132,1,12}) }, + { "ECDSA", OID({1,2,840,10045,2,1}) }, + { "ECDSA/EMSA1(SHA-160)", OID({1,2,840,10045,4,1}) }, + { "ECDSA/EMSA1(SHA-224)", OID({1,2,840,10045,4,3,1}) }, + { "ECDSA/EMSA1(SHA-256)", OID({1,2,840,10045,4,3,2}) }, + { "ECDSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,9}) }, + { "ECDSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,10}) }, + { "ECDSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,11}) }, + { "ECDSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,12}) }, + { "ECDSA/EMSA1(SHA-384)", OID({1,2,840,10045,4,3,3}) }, + { "ECDSA/EMSA1(SHA-512)", OID({1,2,840,10045,4,3,4}) }, + { "ECGDSA", OID({1,3,36,3,3,2,5,2,1}) }, + { "ECGDSA/EMSA1(RIPEMD-160)", OID({1,3,36,3,3,2,5,4,1}) }, + { "ECGDSA/EMSA1(SHA-160)", OID({1,3,36,3,3,2,5,4,2}) }, + { "ECGDSA/EMSA1(SHA-224)", OID({1,3,36,3,3,2,5,4,3}) }, + { "ECGDSA/EMSA1(SHA-256)", OID({1,3,36,3,3,2,5,4,4}) }, + { "ECGDSA/EMSA1(SHA-384)", OID({1,3,36,3,3,2,5,4,5}) }, + { "ECGDSA/EMSA1(SHA-512)", OID({1,3,36,3,3,2,5,4,6}) }, + { "ECKCDSA", OID({1,0,14888,3,0,5}) }, + { "ECKCDSA/EMSA1(SHA-1)", OID({1,2,410,200004,1,100,4,3}) }, + { "ECKCDSA/EMSA1(SHA-224)", OID({1,2,410,200004,1,100,4,4}) }, + { "ECKCDSA/EMSA1(SHA-256)", OID({1,2,410,200004,1,100,4,5}) }, + { "Ed25519", OID({1,3,101,112}) }, + { "ElGamal", OID({1,3,6,1,4,1,3029,1,2,1}) }, + { "GOST-34.10", OID({1,2,643,2,2,19}) }, + { "GOST-34.10-2012-256", OID({1,2,643,7,1,1,1,1}) }, + { "GOST-34.10-2012-256/EMSA1(SHA-256)", OID({1,3,6,1,4,1,25258,1,6,1}) }, + { "GOST-34.10-2012-256/EMSA1(Streebog-256)", OID({1,2,643,7,1,1,3,2}) }, + { "GOST-34.10-2012-512", OID({1,2,643,7,1,1,1,2}) }, + { "GOST-34.10-2012-512/EMSA1(Streebog-512)", OID({1,2,643,7,1,1,3,3}) }, + { "GOST-34.10/EMSA1(GOST-R-34.11-94)", OID({1,2,643,2,2,3}) }, + { "GOST.INN", OID({1,2,643,3,131,1,1}) }, + { "GOST.IssuerSigningTool", OID({1,2,643,100,112}) }, + { "GOST.OGRN", OID({1,2,643,100,1}) }, + { "GOST.SubjectSigningTool", OID({1,2,643,100,111}) }, + { "HMAC(SHA-160)", OID({1,2,840,113549,2,7}) }, + { "HMAC(SHA-224)", OID({1,2,840,113549,2,8}) }, + { "HMAC(SHA-256)", OID({1,2,840,113549,2,9}) }, + { "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) }, + { "HMAC(SHA-512)", OID({1,2,840,113549,2,11}) }, + { "HMAC(SHA-512-256)", OID({1,2,840,113549,2,13}) }, + { "KeyWrap.AES-128", OID({2,16,840,1,101,3,4,1,5}) }, + { "KeyWrap.AES-192", OID({2,16,840,1,101,3,4,1,25}) }, + { "KeyWrap.AES-256", OID({2,16,840,1,101,3,4,1,45}) }, + { "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) }, + { "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) }, + { "MD5", OID({1,2,840,113549,2,5}) }, + { "MGF1", OID({1,2,840,113549,1,1,8}) }, + { "McEliece", OID({1,3,6,1,4,1,25258,1,3}) }, + { "Microsoft SmartcardLogon", OID({1,3,6,1,4,1,311,20,2,2}) }, + { "Microsoft UPN", OID({1,3,6,1,4,1,311,20,2,3}) }, + { "OpenPGP.Curve25519", OID({1,3,6,1,4,1,3029,1,5,1}) }, + { "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) }, + { "PBE-PKCS5v20", OID({1,2,840,113549,1,5,13}) }, + { "PBES2", OID({1,2,840,113549,1,5,13}) }, + { "PKCS5.PBKDF2", OID({1,2,840,113549,1,5,12}) }, + { "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) }, + { "PKCS9.ContentType", OID({1,2,840,113549,1,9,3}) }, + { "PKCS9.EmailAddress", OID({1,2,840,113549,1,9,1}) }, + { "PKCS9.ExtensionRequest", OID({1,2,840,113549,1,9,14}) }, + { "PKCS9.MessageDigest", OID({1,2,840,113549,1,9,4}) }, + { "PKCS9.UnstructuredName", OID({1,2,840,113549,1,9,2}) }, + { "PKIX.AuthorityInformationAccess", OID({1,3,6,1,5,5,7,1,1}) }, + { "PKIX.CertificateAuthorityIssuers", OID({1,3,6,1,5,5,7,48,2}) }, + { "PKIX.ClientAuth", OID({1,3,6,1,5,5,7,3,2}) }, + { "PKIX.CodeSigning", OID({1,3,6,1,5,5,7,3,3}) }, + { "PKIX.EmailProtection", OID({1,3,6,1,5,5,7,3,4}) }, + { "PKIX.IPsecEndSystem", OID({1,3,6,1,5,5,7,3,5}) }, + { "PKIX.IPsecTunnel", OID({1,3,6,1,5,5,7,3,6}) }, + { "PKIX.IPsecUser", OID({1,3,6,1,5,5,7,3,7}) }, + { "PKIX.OCSP", OID({1,3,6,1,5,5,7,48,1}) }, + { "PKIX.OCSP.BasicResponse", OID({1,3,6,1,5,5,7,48,1,1}) }, + { "PKIX.OCSPSigning", OID({1,3,6,1,5,5,7,3,9}) }, + { "PKIX.ServerAuth", OID({1,3,6,1,5,5,7,3,1}) }, + { "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) }, + { "PKIX.XMPPAddr", OID({1,3,6,1,5,5,7,8,5}) }, + { "RIPEMD-160", OID({1,3,36,3,2,1}) }, + { "RSA", OID({1,2,840,113549,1,1,1}) }, + { "RSA/EMSA3(MD5)", OID({1,2,840,113549,1,1,4}) }, + { "RSA/EMSA3(RIPEMD-160)", OID({1,3,36,3,3,1,2}) }, + { "RSA/EMSA3(SHA-160)", OID({1,2,840,113549,1,1,5}) }, + { "RSA/EMSA3(SHA-224)", OID({1,2,840,113549,1,1,14}) }, + { "RSA/EMSA3(SHA-256)", OID({1,2,840,113549,1,1,11}) }, + { "RSA/EMSA3(SHA-3(224))", OID({2,16,840,1,101,3,4,3,13}) }, + { "RSA/EMSA3(SHA-3(256))", OID({2,16,840,1,101,3,4,3,14}) }, + { "RSA/EMSA3(SHA-3(384))", OID({2,16,840,1,101,3,4,3,15}) }, + { "RSA/EMSA3(SHA-3(512))", OID({2,16,840,1,101,3,4,3,16}) }, + { "RSA/EMSA3(SHA-384)", OID({1,2,840,113549,1,1,12}) }, + { "RSA/EMSA3(SHA-512)", OID({1,2,840,113549,1,1,13}) }, + { "RSA/EMSA3(SHA-512-256)", OID({1,2,840,113549,1,1,16}) }, + { "RSA/EMSA3(SM3)", OID({1,2,156,10197,1,504}) }, + { "RSA/EMSA4", OID({1,2,840,113549,1,1,10}) }, + { "RSA/OAEP", OID({1,2,840,113549,1,1,7}) }, + { "SEED/CBC", OID({1,2,410,200004,1,4}) }, + { "SHA-160", OID({1,3,14,3,2,26}) }, + { "SHA-224", OID({2,16,840,1,101,3,4,2,4}) }, + { "SHA-256", OID({2,16,840,1,101,3,4,2,1}) }, + { "SHA-3(224)", OID({2,16,840,1,101,3,4,2,7}) }, + { "SHA-3(256)", OID({2,16,840,1,101,3,4,2,8}) }, + { "SHA-3(384)", OID({2,16,840,1,101,3,4,2,9}) }, + { "SHA-3(512)", OID({2,16,840,1,101,3,4,2,10}) }, + { "SHA-384", OID({2,16,840,1,101,3,4,2,2}) }, + { "SHA-512", OID({2,16,840,1,101,3,4,2,3}) }, + { "SHA-512-256", OID({2,16,840,1,101,3,4,2,6}) }, + { "SHAKE-128", OID({2,16,840,1,101,3,4,2,11}) }, + { "SHAKE-256", OID({2,16,840,1,101,3,4,2,12}) }, + { "SM2", OID({1,2,156,10197,1,301,1}) }, + { "SM2_Enc", OID({1,2,156,10197,1,301,3}) }, + { "SM2_Kex", OID({1,2,156,10197,1,301,2}) }, + { "SM2_Sig", OID({1,2,156,10197,1,301,1}) }, + { "SM2_Sig/SM3", OID({1,2,156,10197,1,501}) }, + { "SM3", OID({1,2,156,10197,1,401}) }, + { "SM4/CBC", OID({1,2,156,10197,1,104,2}) }, + { "SM4/GCM", OID({1,2,156,10197,1,104,8}) }, + { "SM4/OCB", OID({1,2,156,10197,1,104,100}) }, + { "SM4/SIV", OID({1,3,6,1,4,1,25258,3,4,9}) }, + { "Scrypt", OID({1,3,6,1,4,1,11591,4,11}) }, + { "Serpent/CBC", OID({1,3,6,1,4,1,25258,3,1}) }, + { "Serpent/GCM", OID({1,3,6,1,4,1,25258,3,101}) }, + { "Serpent/OCB", OID({1,3,6,1,4,1,25258,3,2,4}) }, + { "Serpent/SIV", OID({1,3,6,1,4,1,25258,3,4,4}) }, + { "Streebog-256", OID({1,2,643,7,1,1,2,2}) }, + { "Streebog-512", OID({1,2,643,7,1,1,2,3}) }, + { "Threefish-512/CBC", OID({1,3,6,1,4,1,25258,3,2}) }, + { "Tiger(24,3)", OID({1,3,6,1,4,1,11591,12,2}) }, + { "TripleDES/CBC", OID({1,2,840,113549,3,7}) }, + { "Twofish/CBC", OID({1,3,6,1,4,1,25258,3,3}) }, + { "Twofish/GCM", OID({1,3,6,1,4,1,25258,3,102}) }, + { "Twofish/OCB", OID({1,3,6,1,4,1,25258,3,2,5}) }, + { "Twofish/SIV", OID({1,3,6,1,4,1,25258,3,4,5}) }, + { "X509v3.AnyPolicy", OID({2,5,29,32,0}) }, + { "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) }, + { "X509v3.BasicConstraints", OID({2,5,29,19}) }, + { "X509v3.CRLDistributionPoints", OID({2,5,29,31}) }, + { "X509v3.CRLIssuingDistributionPoint", OID({2,5,29,28}) }, + { "X509v3.CRLNumber", OID({2,5,29,20}) }, + { "X509v3.CertificatePolicies", OID({2,5,29,32}) }, + { "X509v3.ExtendedKeyUsage", OID({2,5,29,37}) }, + { "X509v3.HoldInstructionCode", OID({2,5,29,23}) }, + { "X509v3.InvalidityDate", OID({2,5,29,24}) }, + { "X509v3.IssuerAlternativeName", OID({2,5,29,18}) }, + { "X509v3.KeyUsage", OID({2,5,29,15}) }, + { "X509v3.NameConstraints", OID({2,5,29,30}) }, + { "X509v3.PolicyConstraints", OID({2,5,29,36}) }, + { "X509v3.PrivateKeyUsagePeriod", OID({2,5,29,16}) }, + { "X509v3.ReasonCode", OID({2,5,29,21}) }, + { "X509v3.SubjectAlternativeName", OID({2,5,29,17}) }, + { "X509v3.SubjectKeyIdentifier", OID({2,5,29,14}) }, + { "X520.CommonName", OID({2,5,4,3}) }, + { "X520.Country", OID({2,5,4,6}) }, + { "X520.DNQualifier", OID({2,5,4,46}) }, + { "X520.GenerationalQualifier", OID({2,5,4,44}) }, + { "X520.GivenName", OID({2,5,4,42}) }, + { "X520.Initials", OID({2,5,4,43}) }, + { "X520.Locality", OID({2,5,4,7}) }, + { "X520.Organization", OID({2,5,4,10}) }, + { "X520.OrganizationalUnit", OID({2,5,4,11}) }, + { "X520.Pseudonym", OID({2,5,4,65}) }, + { "X520.SerialNumber", OID({2,5,4,5}) }, + { "X520.State", OID({2,5,4,8}) }, + { "X520.StreetAddress", OID({2,5,4,9}) }, + { "X520.Surname", OID({2,5,4,4}) }, + { "X520.Title", OID({2,5,4,12}) }, + { "XMSS", OID({0,4,0,127,0,15,1,1,13,0}) }, + { "XMSS-draft12", OID({1,3,6,1,4,1,25258,1,8}) }, + { "XMSS-draft6", OID({1,3,6,1,4,1,25258,1,5}) }, + { "brainpool160r1", OID({1,3,36,3,3,2,8,1,1,1}) }, + { "brainpool192r1", OID({1,3,36,3,3,2,8,1,1,3}) }, + { "brainpool224r1", OID({1,3,36,3,3,2,8,1,1,5}) }, + { "brainpool256r1", OID({1,3,36,3,3,2,8,1,1,7}) }, + { "brainpool320r1", OID({1,3,36,3,3,2,8,1,1,9}) }, + { "brainpool384r1", OID({1,3,36,3,3,2,8,1,1,11}) }, + { "brainpool512r1", OID({1,3,36,3,3,2,8,1,1,13}) }, + { "frp256v1", OID({1,2,250,1,223,101,256,1}) }, + { "gost_256A", OID({1,2,643,7,1,2,1,1,1}) }, + { "gost_256B", OID({1,2,643,7,1,2,1,1,2}) }, + { "gost_512A", OID({1,2,643,7,1,2,1,2,1}) }, + { "gost_512B", OID({1,2,643,7,1,2,1,2,2}) }, + { "secp160k1", OID({1,3,132,0,9}) }, + { "secp160r1", OID({1,3,132,0,8}) }, + { "secp160r2", OID({1,3,132,0,30}) }, + { "secp192k1", OID({1,3,132,0,31}) }, + { "secp192r1", OID({1,2,840,10045,3,1,1}) }, + { "secp224k1", OID({1,3,132,0,32}) }, + { "secp224r1", OID({1,3,132,0,33}) }, + { "secp256k1", OID({1,3,132,0,10}) }, + { "secp256r1", OID({1,2,840,10045,3,1,7}) }, + { "secp384r1", OID({1,3,132,0,34}) }, + { "secp521r1", OID({1,3,132,0,35}) }, + { "sm2p256v1", OID({1,2,156,10197,1,301}) }, + { "x962_p192v2", OID({1,2,840,10045,3,1,2}) }, + { "x962_p192v3", OID({1,2,840,10045,3,1,3}) }, + { "x962_p239v1", OID({1,2,840,10045,3,1,4}) }, + { "x962_p239v2", OID({1,2,840,10045,3,1,5}) }, + { "x962_p239v3", OID({1,2,840,10045,3,1,6}) } + }; + } + +} + diff --git a/comm/third_party/botan/src/lib/asn1/oids.cpp b/comm/third_party/botan/src/lib/asn1/oids.cpp new file mode 100644 index 0000000000..bece7a9b47 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/oids.cpp @@ -0,0 +1,134 @@ +/* +* OID Registry +* (C) 1999-2008,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +class OID_Map final + { + public: + void add_oid(const OID& oid, const std::string& str) + { + add_str2oid(oid, str); + add_oid2str(oid, str); + } + + void add_str2oid(const OID& oid, const std::string& str) + { + lock_guard_type lock(m_mutex); + auto i = m_str2oid.find(str); + if(i == m_str2oid.end()) + m_str2oid.insert(std::make_pair(str, oid)); + } + + void add_oid2str(const OID& oid, const std::string& str) + { + const std::string oid_str = oid.to_string(); + lock_guard_type lock(m_mutex); + auto i = m_oid2str.find(oid_str); + if(i == m_oid2str.end()) + m_oid2str.insert(std::make_pair(oid_str, str)); + } + + std::string oid2str(const OID& oid) + { + const std::string oid_str = oid.to_string(); + + lock_guard_type lock(m_mutex); + + auto i = m_oid2str.find(oid_str); + if(i != m_oid2str.end()) + return i->second; + + return ""; + } + + OID str2oid(const std::string& str) + { + lock_guard_type lock(m_mutex); + auto i = m_str2oid.find(str); + if(i != m_str2oid.end()) + return i->second; + + return OID(); + } + + bool have_oid(const std::string& str) + { + lock_guard_type lock(m_mutex); + return m_str2oid.find(str) != m_str2oid.end(); + } + + static OID_Map& global_registry() + { + static OID_Map g_map; + return g_map; + } + + private: + + OID_Map() + { + m_str2oid = OIDS::load_str2oid_map(); + m_oid2str = OIDS::load_oid2str_map(); + } + + mutex_type m_mutex; + std::unordered_map m_str2oid; + std::unordered_map m_oid2str; + }; + +} + +void OIDS::add_oid(const OID& oid, const std::string& name) + { + OID_Map::global_registry().add_oid(oid, name); + } + +void OIDS::add_oidstr(const char* oidstr, const char* name) + { + add_oid(OID(oidstr), name); + } + +void OIDS::add_oid2str(const OID& oid, const std::string& name) + { + OID_Map::global_registry().add_oid2str(oid, name); + } + +void OIDS::add_str2oid(const OID& oid, const std::string& name) + { + OID_Map::global_registry().add_str2oid(oid, name); + } + +std::string OIDS::oid2str_or_empty(const OID& oid) + { + return OID_Map::global_registry().oid2str(oid); + } + +OID OIDS::str2oid_or_empty(const std::string& name) + { + return OID_Map::global_registry().str2oid(name); + } + +std::string OIDS::oid2str_or_throw(const OID& oid) + { + const std::string s = OIDS::oid2str_or_empty(oid); + if(s.empty()) + throw Lookup_Error("No name associated with OID " + oid.to_string()); + return s; + } + +bool OIDS::have_oid(const std::string& name) + { + return OID_Map::global_registry().have_oid(name); + } + +} diff --git a/comm/third_party/botan/src/lib/asn1/oids.h b/comm/third_party/botan/src/lib/asn1/oids.h new file mode 100644 index 0000000000..9af451fe41 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/oids.h @@ -0,0 +1,98 @@ +/* +* OID Registry +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OIDS_H_ +#define BOTAN_OIDS_H_ + +#include +#include + +namespace Botan { + +namespace OIDS { + +/** +* Register an OID to string mapping. +* @param oid the oid to register +* @param name the name to be associated with the oid +*/ +BOTAN_UNSTABLE_API void add_oid(const OID& oid, const std::string& name); + +BOTAN_UNSTABLE_API void add_oid2str(const OID& oid, const std::string& name); +BOTAN_UNSTABLE_API void add_str2oid(const OID& oid, const std::string& name); + +BOTAN_UNSTABLE_API void add_oidstr(const char* oidstr, const char* name); + +std::unordered_map load_oid2str_map(); +std::unordered_map load_str2oid_map(); + +/** +* Resolve an OID +* @param oid the OID to look up +* @return name associated with this OID, or an empty string +*/ +BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID& oid); + +/** +* Find the OID to a name. The lookup will be performed in the +* general OID section of the configuration. +* @param name the name to resolve +* @return OID associated with the specified name +*/ +BOTAN_UNSTABLE_API OID str2oid_or_empty(const std::string& name); + +BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID& oid); + +/** +* See if an OID exists in the internal table. +* @param oid the oid to check for +* @return true if the oid is registered +*/ +BOTAN_UNSTABLE_API bool BOTAN_DEPRECATED("Just lookup the value instead") have_oid(const std::string& oid); + +/** +* Tests whether the specified OID stands for the specified name. +* @param oid the OID to check +* @param name the name to check +* @return true if the specified OID stands for the specified name +*/ +inline bool BOTAN_DEPRECATED("Use oid == OID::from_string(name)") name_of(const OID& oid, const std::string& name) + { + return (oid == str2oid_or_empty(name)); + } + +/** +* Prefer oid2str_or_empty +*/ +inline std::string lookup(const OID& oid) + { + return oid2str_or_empty(oid); + } + +/** +* Prefer str2oid_or_empty +*/ +inline OID lookup(const std::string& name) + { + return str2oid_or_empty(name); + } + +inline std::string BOTAN_DEPRECATED("Use oid2str_or_empty") oid2str(const OID& oid) + { + return oid2str_or_empty(oid); + } + +inline OID BOTAN_DEPRECATED("Use str2oid_or_empty") str2oid(const std::string& name) + { + return str2oid_or_empty(name); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/botan.h b/comm/third_party/botan/src/lib/base/botan.h new file mode 100644 index 0000000000..a473e8fbf2 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/botan.h @@ -0,0 +1,41 @@ +/* +* A vague catch all include file for Botan +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BOTAN_H_ +#define BOTAN_BOTAN_H_ + +/* +* There is no real reason for this header to exist beyond historical +* reasons. The application should instead include the specific header +* files that define the interfaces it intends to use. +* +* This header file will be removed in Botan 3.x +*/ + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include +#endif + +#if defined(BOTAN_HAS_FILTERS) + #include +#endif + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + #include + #include +#endif + +BOTAN_DEPRECATED_HEADER(botan.h) + +#endif diff --git a/comm/third_party/botan/src/lib/base/buf_comp.cpp b/comm/third_party/botan/src/lib/base/buf_comp.cpp new file mode 100644 index 0000000000..e9a33c9d7f --- /dev/null +++ b/comm/third_party/botan/src/lib/base/buf_comp.cpp @@ -0,0 +1,54 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +void Buffered_Computation::update_be(uint16_t val) + { + uint8_t inb[sizeof(val)]; + store_be(val, inb); + add_data(inb, sizeof(inb)); + } + +void Buffered_Computation::update_be(uint32_t val) + { + uint8_t inb[sizeof(val)]; + store_be(val, inb); + add_data(inb, sizeof(inb)); + } + +void Buffered_Computation::update_be(uint64_t val) + { + uint8_t inb[sizeof(val)]; + store_be(val, inb); + add_data(inb, sizeof(inb)); + } + +void Buffered_Computation::update_le(uint16_t val) + { + uint8_t inb[sizeof(val)]; + store_le(val, inb); + add_data(inb, sizeof(inb)); + } + +void Buffered_Computation::update_le(uint32_t val) + { + uint8_t inb[sizeof(val)]; + store_le(val, inb); + add_data(inb, sizeof(inb)); + } + +void Buffered_Computation::update_le(uint64_t val) + { + uint8_t inb[sizeof(val)]; + store_le(val, inb); + add_data(inb, sizeof(inb)); + } + +} diff --git a/comm/third_party/botan/src/lib/base/buf_comp.h b/comm/third_party/botan/src/lib/base/buf_comp.h new file mode 100644 index 0000000000..31bf485295 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/buf_comp.h @@ -0,0 +1,178 @@ +/* +* Buffered Computation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BUFFERED_COMPUTATION_H_ +#define BOTAN_BUFFERED_COMPUTATION_H_ + +#include +#include + +namespace Botan { + +/** +* This class represents any kind of computation which uses an internal +* state, such as hash functions or MACs +*/ +class BOTAN_PUBLIC_API(2,0) Buffered_Computation + { + public: + /** + * @return length of the output of this function in bytes + */ + virtual size_t output_length() const = 0; + + /** + * Add new input to process. + * @param in the input to process as a byte array + * @param length of param in in bytes + */ + void update(const uint8_t in[], size_t length) { add_data(in, length); } + + /** + * Add new input to process. + * @param in the input to process as a secure_vector + */ + void update(const secure_vector& in) + { + add_data(in.data(), in.size()); + } + + /** + * Add new input to process. + * @param in the input to process as a std::vector + */ + void update(const std::vector& in) + { + add_data(in.data(), in.size()); + } + + void update_be(uint16_t val); + void update_be(uint32_t val); + void update_be(uint64_t val); + + void update_le(uint16_t val); + void update_le(uint32_t val); + void update_le(uint64_t val); + + /** + * Add new input to process. + * @param str the input to process as a std::string. Will be interpreted + * as a byte array based on the strings encoding. + */ + void update(const std::string& str) + { + add_data(cast_char_ptr_to_uint8(str.data()), str.size()); + } + + /** + * Process a single byte. + * @param in the byte to process + */ + void update(uint8_t in) { add_data(&in, 1); } + + /** + * Complete the computation and retrieve the + * final result. + * @param out The byte array to be filled with the result. + * Must be of length output_length() + */ + void final(uint8_t out[]) { final_result(out); } + + /** + * Complete the computation and retrieve the + * final result. + * @return secure_vector holding the result + */ + secure_vector final() + { + secure_vector output(output_length()); + final_result(output.data()); + return output; + } + + std::vector final_stdvec() + { + std::vector output(output_length()); + final_result(output.data()); + return output; + } + + template + void final(std::vector& out) + { + out.resize(output_length()); + final_result(out.data()); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a byte array + * @param length the length of the byte array + * @result the result of the call to final() + */ + secure_vector process(const uint8_t in[], size_t length) + { + add_data(in, length); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector process(const secure_vector& in) + { + add_data(in.data(), in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector process(const std::vector& in) + { + add_data(in.data(), in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a string + * @result the result of the call to final() + */ + secure_vector process(const std::string& in) + { + update(in); + return final(); + } + + virtual ~Buffered_Computation() = default; + private: + /** + * Add more data to the computation + * @param input is an input buffer + * @param length is the length of input in bytes + */ + virtual void add_data(const uint8_t input[], size_t length) = 0; + + /** + * Write the final output to out + * @param out is an output buffer of output_length() + */ + virtual void final_result(uint8_t out[]) = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/info.txt b/comm/third_party/botan/src/lib/base/info.txt new file mode 100644 index 0000000000..fd3f7b8905 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/info.txt @@ -0,0 +1,17 @@ + +botan.h +buf_comp.h +init.h +key_spec.h +lookup.h +secmem.h +scan_name.h +sym_algo.h +symkey.h + + + +hex +rng +utils + diff --git a/comm/third_party/botan/src/lib/base/init.h b/comm/third_party/botan/src/lib/base/init.h new file mode 100644 index 0000000000..668650846b --- /dev/null +++ b/comm/third_party/botan/src/lib/base/init.h @@ -0,0 +1,35 @@ +/* +* Library Initialization +* (C) 1999-2008,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LIBRARY_INITIALIZER_H_ +#define BOTAN_LIBRARY_INITIALIZER_H_ + +#include +#include + +namespace Botan { + +BOTAN_DEPRECATED_HEADER(init.h) + +/* +* Previously botan had state whose lifetime had to be explicitly +* managed by the application. As of 1.11.14 this is no longer the +* case, and this class is no longer needed and kept only for backwards +* compatibility. +*/ +class BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("LibraryInitializer is no longer required") LibraryInitializer final + { + public: + explicit LibraryInitializer(const std::string& /*ignored*/ = "") { } + + static void initialize(const std::string& /*ignored*/ = "") {} + static void deinitialize() {} + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/key_spec.h b/comm/third_party/botan/src/lib/base/key_spec.h new file mode 100644 index 0000000000..85dcebe37e --- /dev/null +++ b/comm/third_party/botan/src/lib/base/key_spec.h @@ -0,0 +1,14 @@ +/* +* Symmetric Key Length Specification +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEY_LEN_SPECIFICATION_H_ +#define BOTAN_KEY_LEN_SPECIFICATION_H_ + +#include +BOTAN_DEPRECATED_HEADER(key_spec.h) + +#endif diff --git a/comm/third_party/botan/src/lib/base/lookup.h b/comm/third_party/botan/src/lib/base/lookup.h new file mode 100644 index 0000000000..4a14230db0 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/lookup.h @@ -0,0 +1,179 @@ +/* +* Algorithm Lookup +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LOOKUP_H_ +#define BOTAN_LOOKUP_H_ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_HASH) + #include +#endif + +#if defined(BOTAN_HAS_MAC) + #include +#endif + +namespace Botan { + +BOTAN_DEPRECATED_HEADER(lookup.h) + +/* +* As of 1.11.26 this header is deprecated. Instead use the calls T::create and +* T::providers (as demonstrated in the implementation below). +*/ + +/* +* Get an algorithm object +* NOTE: these functions create and return new objects, letting the +* caller assume ownership of them +*/ + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + +/** +* Block cipher factory method. +* +* @param algo_spec the name of the desired block cipher +* @param provider the provider to use +* @return pointer to the block cipher object +*/ +BOTAN_DEPRECATED("Use BlockCipher::create") +inline BlockCipher* get_block_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return BlockCipher::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use BlockCipher::create_or_throw") +inline std::unique_ptr make_block_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return BlockCipher::create_or_throw(algo_spec, provider); + } + +BOTAN_DEPRECATED("Use BlockCipher::providers") +inline std::vector get_block_cipher_providers(const std::string& algo_spec) + { + return BlockCipher::providers(algo_spec); + } + +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +/** +* Stream cipher factory method. +* +* @param algo_spec the name of the desired stream cipher +* @param provider the provider to use +* @return pointer to the stream cipher object +*/ +BOTAN_DEPRECATED("Use StreamCipher::create") +inline StreamCipher* get_stream_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return StreamCipher::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use StreamCipher::create_or_throw") +inline std::unique_ptr make_stream_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return StreamCipher::create_or_throw(algo_spec, provider); + } + +BOTAN_DEPRECATED("Use StreamCipher::providers") +inline std::vector get_stream_cipher_providers(const std::string& algo_spec) + { + return StreamCipher::providers(algo_spec); + } + +#endif + +#if defined(BOTAN_HAS_HASH) + +/** +* Hash function factory method. +* +* @param algo_spec the name of the desired hash function +* @param provider the provider to use +* @return pointer to the hash function object +*/ +BOTAN_DEPRECATED("Use HashFunction::create") +inline HashFunction* get_hash_function(const std::string& algo_spec, + const std::string& provider = "") + { + return HashFunction::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use HashFunction::create_or_throw") +inline std::unique_ptr make_hash_function(const std::string& algo_spec, + const std::string& provider = "") + { + return HashFunction::create_or_throw(algo_spec, provider); + } + +BOTAN_DEPRECATED("Use HashFunction::create") +inline HashFunction* get_hash(const std::string& algo_spec, + const std::string& provider = "") + { + return HashFunction::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use HashFunction::providers") +inline std::vector get_hash_function_providers(const std::string& algo_spec) + { + return HashFunction::providers(algo_spec); + } + +#endif + +#if defined(BOTAN_HAS_MAC) +/** +* MAC factory method. +* +* @param algo_spec the name of the desired MAC +* @param provider the provider to use +* @return pointer to the MAC object +*/ +BOTAN_DEPRECATED("MessageAuthenticationCode::create") +inline MessageAuthenticationCode* get_mac(const std::string& algo_spec, + const std::string& provider = "") + { + return MessageAuthenticationCode::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("MessageAuthenticationCode::create_or_throw") +inline std::unique_ptr make_message_auth(const std::string& algo_spec, + const std::string& provider = "") + { + return MessageAuthenticationCode::create(algo_spec, provider); + } + +BOTAN_DEPRECATED("MessageAuthenticationCode::providers") +inline std::vector get_mac_providers(const std::string& algo_spec) + { + return MessageAuthenticationCode::providers(algo_spec); + } +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/scan_name.cpp b/comm/third_party/botan/src/lib/base/scan_name.cpp new file mode 100644 index 0000000000..f79866ba61 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/scan_name.cpp @@ -0,0 +1,149 @@ +/* +* SCAN Name Abstraction +* (C) 2008-2009,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +std::string make_arg(const std::vector>& name, size_t start) + { + std::string output = name[start].second; + size_t level = name[start].first; + + size_t paren_depth = 0; + + for(size_t i = start + 1; i != name.size(); ++i) + { + if(name[i].first <= name[start].first) + break; + + if(name[i].first > level) + { + output += "(" + name[i].second; + ++paren_depth; + } + else if(name[i].first < level) + { + for (size_t j = name[i].first; j < level; j++) { + output += ")"; + --paren_depth; + } + output += "," + name[i].second; + } + else + { + if(output[output.size() - 1] != '(') + output += ","; + output += name[i].second; + } + + level = name[i].first; + } + + for(size_t i = 0; i != paren_depth; ++i) + output += ")"; + + return output; + } + +} + +SCAN_Name::SCAN_Name(const char* algo_spec) : SCAN_Name(std::string(algo_spec)) + { + } + +SCAN_Name::SCAN_Name(std::string algo_spec) : m_orig_algo_spec(algo_spec), m_alg_name(), m_args(), m_mode_info() + { + if(algo_spec.size() == 0) + throw Invalid_Argument("Expected algorithm name, got empty string"); + + std::vector> name; + size_t level = 0; + std::pair accum = std::make_pair(level, ""); + + const std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; + + for(size_t i = 0; i != algo_spec.size(); ++i) + { + char c = algo_spec[i]; + + if(c == '/' || c == ',' || c == '(' || c == ')') + { + if(c == '(') + ++level; + else if(c == ')') + { + if(level == 0) + throw Decoding_Error(decoding_error + "Mismatched parens"); + --level; + } + + if(c == '/' && level > 0) + accum.second.push_back(c); + else + { + if(accum.second != "") + name.push_back(accum); + accum = std::make_pair(level, ""); + } + } + else + accum.second.push_back(c); + } + + if(accum.second != "") + name.push_back(accum); + + if(level != 0) + throw Decoding_Error(decoding_error + "Missing close paren"); + + if(name.size() == 0) + throw Decoding_Error(decoding_error + "Empty name"); + + m_alg_name = name[0].second; + + bool in_modes = false; + + for(size_t i = 1; i != name.size(); ++i) + { + if(name[i].first == 0) + { + m_mode_info.push_back(make_arg(name, i)); + in_modes = true; + } + else if(name[i].first == 1 && !in_modes) + m_args.push_back(make_arg(name, i)); + } + } + +std::string SCAN_Name::arg(size_t i) const + { + if(i >= arg_count()) + throw Invalid_Argument("SCAN_Name::arg " + std::to_string(i) + + " out of range for '" + to_string() + "'"); + return m_args[i]; + } + +std::string SCAN_Name::arg(size_t i, const std::string& def_value) const + { + if(i >= arg_count()) + return def_value; + return m_args[i]; + } + +size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const + { + if(i >= arg_count()) + return def_value; + return to_u32bit(m_args[i]); + } + +} diff --git a/comm/third_party/botan/src/lib/base/scan_name.h b/comm/third_party/botan/src/lib/base/scan_name.h new file mode 100644 index 0000000000..069783d1bb --- /dev/null +++ b/comm/third_party/botan/src/lib/base/scan_name.h @@ -0,0 +1,124 @@ +/* +* SCAN Name Abstraction +* (C) 2008,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SCAN_NAME_H_ +#define BOTAN_SCAN_NAME_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(scan_name.h) + +namespace Botan { + +/** +A class encapsulating a SCAN name (similar to JCE conventions) +http://www.users.zetnet.co.uk/hopwood/crypto/scan/ +*/ +class BOTAN_PUBLIC_API(2,0) SCAN_Name final + { + public: + /** + * Create a SCAN_Name + * @param algo_spec A SCAN-format name + */ + explicit SCAN_Name(const char* algo_spec); + + /** + * Create a SCAN_Name + * @param algo_spec A SCAN-format name + */ + explicit SCAN_Name(std::string algo_spec); + + /** + * @return original input string + */ + const std::string& to_string() const { return m_orig_algo_spec; } + + BOTAN_DEPRECATED("Use SCAN_Name::to_string") const std::string& as_string() const + { + return this->to_string(); + } + + /** + * @return algorithm name + */ + const std::string& algo_name() const { return m_alg_name; } + + /** + * @return number of arguments + */ + size_t arg_count() const { return m_args.size(); } + + /** + * @param lower is the lower bound + * @param upper is the upper bound + * @return if the number of arguments is between lower and upper + */ + bool arg_count_between(size_t lower, size_t upper) const + { return ((arg_count() >= lower) && (arg_count() <= upper)); } + + /** + * @param i which argument + * @return ith argument + */ + std::string arg(size_t i) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument or the default value + */ + std::string arg(size_t i, const std::string& def_value) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument as an integer, or the default value + */ + size_t arg_as_integer(size_t i, size_t def_value) const; + + /** + * @return cipher mode (if any) + */ + std::string cipher_mode() const + { return (m_mode_info.size() >= 1) ? m_mode_info[0] : ""; } + + /** + * @return cipher mode padding (if any) + */ + std::string cipher_mode_pad() const + { return (m_mode_info.size() >= 2) ? m_mode_info[1] : ""; } + + private: + std::string m_orig_algo_spec; + std::string m_alg_name; + std::vector m_args; + std::vector m_mode_info; + }; + +// This is unrelated but it is convenient to stash it here +template +std::vector probe_providers_of(const std::string& algo_spec, + const std::vector& possible) + { + std::vector providers; + for(auto&& prov : possible) + { + std::unique_ptr o(T::create(algo_spec, prov)); + if(o) + { + providers.push_back(prov); // available + } + } + return providers; + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/secmem.h b/comm/third_party/botan/src/lib/base/secmem.h new file mode 100644 index 0000000000..a5ba5857a9 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/secmem.h @@ -0,0 +1,136 @@ +/* +* Secure Memory Buffers +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SECURE_MEMORY_BUFFERS_H_ +#define BOTAN_SECURE_MEMORY_BUFFERS_H_ + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +#include +#include + +namespace Botan { + +template +class secure_allocator + { + public: + /* + * Assert exists to prevent someone from doing something that will + * probably crash anyway (like secure_vector where ~non_POD_t + * deletes a member pointer which was zeroed before it ran). + * MSVC in debug mode uses non-integral proxy types in container types + * like std::vector, thus we disable the check there. + */ +#if !defined(_ITERATOR_DEBUG_LEVEL) || _ITERATOR_DEBUG_LEVEL == 0 + static_assert(std::is_integral::value, "secure_allocator supports only integer types"); +#endif + + typedef T value_type; + typedef std::size_t size_type; + + secure_allocator() noexcept = default; + secure_allocator(const secure_allocator&) noexcept = default; + secure_allocator& operator=(const secure_allocator&) noexcept = default; + ~secure_allocator() noexcept = default; + + template + secure_allocator(const secure_allocator&) noexcept {} + + T* allocate(std::size_t n) + { + return static_cast(allocate_memory(n, sizeof(T))); + } + + void deallocate(T* p, std::size_t n) + { + deallocate_memory(p, n, sizeof(T)); + } + }; + +template inline bool +operator==(const secure_allocator&, const secure_allocator&) + { return true; } + +template inline bool +operator!=(const secure_allocator&, const secure_allocator&) + { return false; } + +template using secure_vector = std::vector>; +template using secure_deque = std::deque>; + +// For better compatibility with 1.10 API +template using SecureVector = secure_vector; + +template +std::vector unlock(const secure_vector& in) + { + return std::vector(in.begin(), in.end()); + } + +template +std::vector& +operator+=(std::vector& out, + const std::vector& in) + { + out.reserve(out.size() + in.size()); + out.insert(out.end(), in.begin(), in.end()); + return out; + } + +template +std::vector& operator+=(std::vector& out, T in) + { + out.push_back(in); + return out; + } + +template +std::vector& operator+=(std::vector& out, + const std::pair& in) + { + out.reserve(out.size() + in.second); + out.insert(out.end(), in.first, in.first + in.second); + return out; + } + +template +std::vector& operator+=(std::vector& out, + const std::pair& in) + { + out.reserve(out.size() + in.second); + out.insert(out.end(), in.first, in.first + in.second); + return out; + } + +/** +* Zeroise the values; length remains unchanged +* @param vec the vector to zeroise +*/ +template +void zeroise(std::vector& vec) + { + clear_mem(vec.data(), vec.size()); + } + +/** +* Zeroise the values then free the memory +* @param vec the vector to zeroise and free +*/ +template +void zap(std::vector& vec) + { + zeroise(vec); + vec.clear(); + vec.shrink_to_fit(); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/sym_algo.cpp b/comm/third_party/botan/src/lib/base/sym_algo.cpp new file mode 100644 index 0000000000..fff4afbd14 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/sym_algo.cpp @@ -0,0 +1,24 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +void SymmetricAlgorithm::throw_key_not_set_error() const + { + throw Key_Not_Set(name()); + } + +void SymmetricAlgorithm::set_key(const uint8_t key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + +} diff --git a/comm/third_party/botan/src/lib/base/sym_algo.h b/comm/third_party/botan/src/lib/base/sym_algo.h new file mode 100644 index 0000000000..41d9992927 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/sym_algo.h @@ -0,0 +1,190 @@ +/* +* Symmetric Algorithm Base Class +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYMMETRIC_ALGORITHM_H_ +#define BOTAN_SYMMETRIC_ALGORITHM_H_ + +#include +#include + +namespace Botan { + +/** +* Represents the length requirements on an algorithm key +*/ +class BOTAN_PUBLIC_API(2,0) Key_Length_Specification final + { + public: + /** + * Constructor for fixed length keys + * @param keylen the supported key length + */ + explicit Key_Length_Specification(size_t keylen) : + m_min_keylen(keylen), + m_max_keylen(keylen), + m_keylen_mod(1) + { + } + + /** + * Constructor for variable length keys + * @param min_k the smallest supported key length + * @param max_k the largest supported key length + * @param k_mod the number of bytes the key must be a multiple of + */ + Key_Length_Specification(size_t min_k, + size_t max_k, + size_t k_mod = 1) : + m_min_keylen(min_k), + m_max_keylen(max_k ? max_k : min_k), + m_keylen_mod(k_mod) + { + } + + /** + * @param length is a key length in bytes + * @return true iff this length is a valid length for this algo + */ + bool valid_keylength(size_t length) const + { + return ((length >= m_min_keylen) && + (length <= m_max_keylen) && + (length % m_keylen_mod == 0)); + } + + /** + * @return minimum key length in bytes + */ + size_t minimum_keylength() const + { + return m_min_keylen; + } + + /** + * @return maximum key length in bytes + */ + size_t maximum_keylength() const + { + return m_max_keylen; + } + + /** + * @return key length multiple in bytes + */ + size_t keylength_multiple() const + { + return m_keylen_mod; + } + + /* + * Multiplies all length requirements with the given factor + * @param n the multiplication factor + * @return a key length specification multiplied by the factor + */ + Key_Length_Specification multiple(size_t n) const + { + return Key_Length_Specification(n * m_min_keylen, + n * m_max_keylen, + n * m_keylen_mod); + } + + private: + size_t m_min_keylen, m_max_keylen, m_keylen_mod; + }; + +/** +* This class represents a symmetric algorithm object. +*/ +class BOTAN_PUBLIC_API(2,0) SymmetricAlgorithm + { + public: + virtual ~SymmetricAlgorithm() = default; + + /** + * Reset the state. + */ + virtual void clear() = 0; + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * @return maximum allowed key length + */ + size_t maximum_keylength() const + { + return key_spec().maximum_keylength(); + } + + /** + * @return minimum allowed key length + */ + size_t minimum_keylength() const + { + return key_spec().minimum_keylength(); + } + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this object. + * @param key the SymmetricKey to be set. + */ + void set_key(const SymmetricKey& key) + { + set_key(key.begin(), key.length()); + } + + template + void set_key(const std::vector& key) + { + set_key(key.data(), key.size()); + } + + /** + * Set the symmetric key of this object. + * @param key the to be set as a byte array. + * @param length in bytes of key param + */ + void set_key(const uint8_t key[], size_t length); + + /** + * @return the algorithm name + */ + virtual std::string name() const = 0; + + protected: + void verify_key_set(bool cond) const + { + if(cond == false) + throw_key_not_set_error(); + } + + private: + void throw_key_not_set_error() const; + + /** + * Run the key schedule + * @param key the key + * @param length of key + */ + virtual void key_schedule(const uint8_t key[], size_t length) = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/base/symkey.cpp b/comm/third_party/botan/src/lib/base/symkey.cpp new file mode 100644 index 0000000000..1e1781c675 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/symkey.cpp @@ -0,0 +1,134 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an OctetString from RNG output +*/ +OctetString::OctetString(RandomNumberGenerator& rng, + size_t len) + { + rng.random_vec(m_data, len); + } + +/* +* Create an OctetString from a hex string +*/ +OctetString::OctetString(const std::string& hex_string) + { + if(!hex_string.empty()) + { + m_data.resize(1 + hex_string.length() / 2); + m_data.resize(hex_decode(m_data.data(), hex_string)); + } + } + +/* +* Create an OctetString from a byte string +*/ +OctetString::OctetString(const uint8_t in[], size_t n) + { + m_data.assign(in, in + n); + } + +/* +* Set the parity of each key byte to odd +*/ +void OctetString::set_odd_parity() + { + const uint8_t ODD_PARITY[256] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, + 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, + 0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52, + 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, + 0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83, + 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, + 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, + 0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, + 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3, + 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, + 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, + 0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, + 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3, + 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, + 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, + 0xFD, 0xFD, 0xFE, 0xFE }; + + for(size_t j = 0; j != m_data.size(); ++j) + m_data[j] = ODD_PARITY[m_data[j]]; + } + +/* +* Hex encode an OctetString +*/ +std::string OctetString::to_string() const + { + return hex_encode(m_data.data(), m_data.size()); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString& OctetString::operator^=(const OctetString& k) + { + if(&k == this) { zeroise(m_data); return (*this); } + xor_buf(m_data.data(), k.begin(), std::min(length(), k.length())); + return (*this); + } + +/* +* Equality Operation for OctetStrings +*/ +bool operator==(const OctetString& s1, const OctetString& s2) + { + return (s1.bits_of() == s2.bits_of()); + } + +/* +* Unequality Operation for OctetStrings +*/ +bool operator!=(const OctetString& s1, const OctetString& s2) + { + return !(s1 == s2); + } + +/* +* Append Operation for OctetStrings +*/ +OctetString operator+(const OctetString& k1, const OctetString& k2) + { + secure_vector out; + out += k1.bits_of(); + out += k2.bits_of(); + return OctetString(out); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString operator^(const OctetString& k1, const OctetString& k2) + { + secure_vector out(std::max(k1.length(), k2.length())); + + copy_mem(out.data(), k1.begin(), k1.length()); + xor_buf(out.data(), k2.begin(), k2.length()); + return OctetString(out); + } + +} diff --git a/comm/third_party/botan/src/lib/base/symkey.h b/comm/third_party/botan/src/lib/base/symkey.h new file mode 100644 index 0000000000..69becdd4e0 --- /dev/null +++ b/comm/third_party/botan/src/lib/base/symkey.h @@ -0,0 +1,150 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYMKEY_H_ +#define BOTAN_SYMKEY_H_ + +#include +#include + +namespace Botan { + +/** +* Octet String +*/ +class BOTAN_PUBLIC_API(2,0) OctetString final + { + public: + /** + * @return size of this octet string in bytes + */ + size_t length() const { return m_data.size(); } + size_t size() const { return m_data.size(); } + + /** + * @return this object as a secure_vector + */ + secure_vector bits_of() const { return m_data; } + + /** + * @return start of this string + */ + const uint8_t* begin() const { return m_data.data(); } + + /** + * @return end of this string + */ + const uint8_t* end() const { return begin() + m_data.size(); } + + /** + * @return this encoded as hex + */ + std::string to_string() const; + + std::string BOTAN_DEPRECATED("Use OctetString::to_string") as_string() const + { + return this->to_string(); + } + + /** + * XOR the contents of another octet string into this one + * @param other octet string + * @return reference to this + */ + OctetString& operator^=(const OctetString& other); + + /** + * Force to have odd parity + */ + void set_odd_parity(); + + /** + * Create a new OctetString + * @param str is a hex encoded string + */ + explicit OctetString(const std::string& str = ""); + + /** + * Create a new random OctetString + * @param rng is a random number generator + * @param len is the desired length in bytes + */ + OctetString(class RandomNumberGenerator& rng, size_t len); + + /** + * Create a new OctetString + * @param in is an array + * @param len is the length of in in bytes + */ + OctetString(const uint8_t in[], size_t len); + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const secure_vector& in) : m_data(in) {} + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const std::vector& in) : m_data(in.begin(), in.end()) {} + + private: + secure_vector m_data; + }; + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is equal to y +*/ +BOTAN_PUBLIC_API(2,0) bool operator==(const OctetString& x, + const OctetString& y); + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is not equal to y +*/ +BOTAN_PUBLIC_API(2,0) bool operator!=(const OctetString& x, + const OctetString& y); + +/** +* Concatenate two strings +* @param x an octet string +* @param y an octet string +* @return x concatenated with y +*/ +BOTAN_PUBLIC_API(2,0) OctetString operator+(const OctetString& x, + const OctetString& y); + +/** +* XOR two strings +* @param x an octet string +* @param y an octet string +* @return x XORed with y +*/ +BOTAN_PUBLIC_API(2,0) OctetString operator^(const OctetString& x, + const OctetString& y); + + +/** +* Alternate name for octet string showing intent to use as a key +*/ +using SymmetricKey = OctetString; + +/** +* Alternate name for octet string showing intent to use as an IV +*/ +using InitializationVector = OctetString; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/aes/aes.cpp b/comm/third_party/botan/src/lib/block/aes/aes.cpp new file mode 100644 index 0000000000..88d6e9027f --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes.cpp @@ -0,0 +1,1017 @@ +/* +* (C) 1999-2010,2015,2017,2018,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +#if defined(BOTAN_HAS_AES_POWER8) || defined(BOTAN_HAS_AES_ARMV8) || defined(BOTAN_HAS_AES_NI) + #define BOTAN_HAS_HW_AES_SUPPORT +#endif + +/* +* One of three AES implementation strategies are used to get a constant time +* implementation which is immune to common cache/timing based side channels: +* +* - If AES hardware support is available (AES-NI, POWER8, Aarch64) use that +* +* - If 128-bit SIMD with byte shuffles are available (SSSE3, NEON, or Altivec), +* use the vperm technique published by Mike Hamburg at CHES 2009. +* +* - If no hardware or SIMD support, fall back to a constant time bitsliced +* implementation. This uses 32-bit words resulting in 2 blocks being processed +* in parallel. Moving to 4 blocks (with 64-bit words) would approximately +* double performance on 64-bit CPUs. Likewise moving to 128 bit SIMD would +* again approximately double performance vs 64-bit. However the assumption is +* that most 64-bit CPUs either have hardware AES or SIMD shuffle support and +* that the majority of users falling back to this code will be 32-bit cores. +* If this assumption proves to be unsound, the bitsliced code can easily be +* extended to operate on either 32 or 64 bit words depending on the native +* wordsize of the target processor. +* +* Useful references +* +* - "Accelerating AES with Vector Permute Instructions" Mike Hamburg +* https://www.shiftleft.org/papers/vector_aes/vector_aes.pdf +* +* - "Faster and Timing-Attack Resistant AES-GCM" Käsper and Schwabe +* https://eprint.iacr.org/2009/129.pdf +* +* - "A new combinational logic minimization technique with applications to cryptology." +* Boyar and Peralta https://eprint.iacr.org/2009/191.pdf +* +* - "A depth-16 circuit for the AES S-box" Boyar and Peralta +* https://eprint.iacr.org/2011/332.pdf +* +* - "A Very Compact S-box for AES" Canright +* https://www.iacr.org/archive/ches2005/032.pdf +* https://core.ac.uk/download/pdf/36694529.pdf (extended) +*/ + +namespace { + +/* +This is an AES sbox circuit which can execute in bitsliced mode up to 32x in +parallel. + +The circuit is from the "Circuit Minimization Team" group +http://www.cs.yale.edu/homes/peralta/CircuitStuff/CMT.html +http://www.cs.yale.edu/homes/peralta/CircuitStuff/SLP_AES_113.txt + +This circuit has size 113 and depth 27. In software it is much faster than +circuits which are considered faster for hardware purposes (where circuit depth +is the critical constraint), because unlike in hardware, on common CPUs we can +only execute - at best - 3 or 4 logic operations per cycle. So a smaller circuit +is superior. On an x86-64 machine this circuit is about 15% faster than the +circuit of size 128 and depth 16 given in "A depth-16 circuit for the AES S-box". + +Another circuit for AES Sbox of size 102 and depth 24 is describted in "New +Circuit Minimization Techniques for Smaller and Faster AES SBoxes" +[https://eprint.iacr.org/2019/802] however it relies on "non-standard" gates +like MUX, NOR, NAND, etc and so in practice in bitsliced software, its size is +actually a bit larger than this circuit, as few CPUs have such instructions and +otherwise they must be emulated using a sequence of available bit operations. +*/ +void AES_SBOX(uint32_t V[8]) + { + const uint32_t U0 = V[0]; + const uint32_t U1 = V[1]; + const uint32_t U2 = V[2]; + const uint32_t U3 = V[3]; + const uint32_t U4 = V[4]; + const uint32_t U5 = V[5]; + const uint32_t U6 = V[6]; + const uint32_t U7 = V[7]; + + const uint32_t y14 = U3 ^ U5; + const uint32_t y13 = U0 ^ U6; + const uint32_t y9 = U0 ^ U3; + const uint32_t y8 = U0 ^ U5; + const uint32_t t0 = U1 ^ U2; + const uint32_t y1 = t0 ^ U7; + const uint32_t y4 = y1 ^ U3; + const uint32_t y12 = y13 ^ y14; + const uint32_t y2 = y1 ^ U0; + const uint32_t y5 = y1 ^ U6; + const uint32_t y3 = y5 ^ y8; + const uint32_t t1 = U4 ^ y12; + const uint32_t y15 = t1 ^ U5; + const uint32_t y20 = t1 ^ U1; + const uint32_t y6 = y15 ^ U7; + const uint32_t y10 = y15 ^ t0; + const uint32_t y11 = y20 ^ y9; + const uint32_t y7 = U7 ^ y11; + const uint32_t y17 = y10 ^ y11; + const uint32_t y19 = y10 ^ y8; + const uint32_t y16 = t0 ^ y11; + const uint32_t y21 = y13 ^ y16; + const uint32_t y18 = U0 ^ y16; + const uint32_t t2 = y12 & y15; + const uint32_t t3 = y3 & y6; + const uint32_t t4 = t3 ^ t2; + const uint32_t t5 = y4 & U7; + const uint32_t t6 = t5 ^ t2; + const uint32_t t7 = y13 & y16; + const uint32_t t8 = y5 & y1; + const uint32_t t9 = t8 ^ t7; + const uint32_t t10 = y2 & y7; + const uint32_t t11 = t10 ^ t7; + const uint32_t t12 = y9 & y11; + const uint32_t t13 = y14 & y17; + const uint32_t t14 = t13 ^ t12; + const uint32_t t15 = y8 & y10; + const uint32_t t16 = t15 ^ t12; + const uint32_t t17 = t4 ^ y20; + const uint32_t t18 = t6 ^ t16; + const uint32_t t19 = t9 ^ t14; + const uint32_t t20 = t11 ^ t16; + const uint32_t t21 = t17 ^ t14; + const uint32_t t22 = t18 ^ y19; + const uint32_t t23 = t19 ^ y21; + const uint32_t t24 = t20 ^ y18; + const uint32_t t25 = t21 ^ t22; + const uint32_t t26 = t21 & t23; + const uint32_t t27 = t24 ^ t26; + const uint32_t t28 = t25 & t27; + const uint32_t t29 = t28 ^ t22; + const uint32_t t30 = t23 ^ t24; + const uint32_t t31 = t22 ^ t26; + const uint32_t t32 = t31 & t30; + const uint32_t t33 = t32 ^ t24; + const uint32_t t34 = t23 ^ t33; + const uint32_t t35 = t27 ^ t33; + const uint32_t t36 = t24 & t35; + const uint32_t t37 = t36 ^ t34; + const uint32_t t38 = t27 ^ t36; + const uint32_t t39 = t29 & t38; + const uint32_t t40 = t25 ^ t39; + const uint32_t t41 = t40 ^ t37; + const uint32_t t42 = t29 ^ t33; + const uint32_t t43 = t29 ^ t40; + const uint32_t t44 = t33 ^ t37; + const uint32_t t45 = t42 ^ t41; + const uint32_t z0 = t44 & y15; + const uint32_t z1 = t37 & y6; + const uint32_t z2 = t33 & U7; + const uint32_t z3 = t43 & y16; + const uint32_t z4 = t40 & y1; + const uint32_t z5 = t29 & y7; + const uint32_t z6 = t42 & y11; + const uint32_t z7 = t45 & y17; + const uint32_t z8 = t41 & y10; + const uint32_t z9 = t44 & y12; + const uint32_t z10 = t37 & y3; + const uint32_t z11 = t33 & y4; + const uint32_t z12 = t43 & y13; + const uint32_t z13 = t40 & y5; + const uint32_t z14 = t29 & y2; + const uint32_t z15 = t42 & y9; + const uint32_t z16 = t45 & y14; + const uint32_t z17 = t41 & y8; + const uint32_t tc1 = z15 ^ z16; + const uint32_t tc2 = z10 ^ tc1; + const uint32_t tc3 = z9 ^ tc2; + const uint32_t tc4 = z0 ^ z2; + const uint32_t tc5 = z1 ^ z0; + const uint32_t tc6 = z3 ^ z4; + const uint32_t tc7 = z12 ^ tc4; + const uint32_t tc8 = z7 ^ tc6; + const uint32_t tc9 = z8 ^ tc7; + const uint32_t tc10 = tc8 ^ tc9; + const uint32_t tc11 = tc6 ^ tc5; + const uint32_t tc12 = z3 ^ z5; + const uint32_t tc13 = z13 ^ tc1; + const uint32_t tc14 = tc4 ^ tc12; + const uint32_t S3 = tc3 ^ tc11; + const uint32_t tc16 = z6 ^ tc8; + const uint32_t tc17 = z14 ^ tc10; + const uint32_t tc18 = ~tc13 ^ tc14; + const uint32_t S7 = z12 ^ tc18; + const uint32_t tc20 = z15 ^ tc16; + const uint32_t tc21 = tc2 ^ z11; + const uint32_t S0 = tc3 ^ tc16; + const uint32_t S6 = tc10 ^ tc18; + const uint32_t S4 = tc14 ^ S3; + const uint32_t S1 = ~(S3 ^ tc16); + const uint32_t tc26 = tc17 ^ tc20; + const uint32_t S2 = ~(tc26 ^ z17); + const uint32_t S5 = tc21 ^ tc17; + + V[0] = S0; + V[1] = S1; + V[2] = S2; + V[3] = S3; + V[4] = S4; + V[5] = S5; + V[6] = S6; + V[7] = S7; + } + +/* +A circuit for inverse AES Sbox of size 121 and depth 21 from +http://www.cs.yale.edu/homes/peralta/CircuitStuff/CMT.html +http://www.cs.yale.edu/homes/peralta/CircuitStuff/Sinv.txt +*/ +void AES_INV_SBOX(uint32_t V[8]) + { + const uint32_t U0 = V[0]; + const uint32_t U1 = V[1]; + const uint32_t U2 = V[2]; + const uint32_t U3 = V[3]; + const uint32_t U4 = V[4]; + const uint32_t U5 = V[5]; + const uint32_t U6 = V[6]; + const uint32_t U7 = V[7]; + + const uint32_t Y0 = U0 ^ U3; + const uint32_t Y2 = ~(U1 ^ U3); + const uint32_t Y4 = U0 ^ Y2; + const uint32_t RTL0 = U6 ^ U7; + const uint32_t Y1 = Y2 ^ RTL0; + const uint32_t Y7 = ~(U2 ^ Y1); + const uint32_t RTL1 = U3 ^ U4; + const uint32_t Y6 = ~(U7 ^ RTL1); + const uint32_t Y3 = Y1 ^ RTL1; + const uint32_t RTL2 = ~(U0 ^ U2); + const uint32_t Y5 = U5 ^ RTL2; + const uint32_t sa1 = Y0 ^ Y2; + const uint32_t sa0 = Y1 ^ Y3; + const uint32_t sb1 = Y4 ^ Y6; + const uint32_t sb0 = Y5 ^ Y7; + const uint32_t ah = Y0 ^ Y1; + const uint32_t al = Y2 ^ Y3; + const uint32_t aa = sa0 ^ sa1; + const uint32_t bh = Y4 ^ Y5; + const uint32_t bl = Y6 ^ Y7; + const uint32_t bb = sb0 ^ sb1; + const uint32_t ab20 = sa0 ^ sb0; + const uint32_t ab22 = al ^ bl; + const uint32_t ab23 = Y3 ^ Y7; + const uint32_t ab21 = sa1 ^ sb1; + const uint32_t abcd1 = ah & bh; + const uint32_t rr1 = Y0 & Y4; + const uint32_t ph11 = ab20 ^ abcd1; + const uint32_t t01 = Y1 & Y5; + const uint32_t ph01 = t01 ^ abcd1; + const uint32_t abcd2 = al & bl; + const uint32_t r1 = Y2 & Y6; + const uint32_t pl11 = ab22 ^ abcd2; + const uint32_t r2 = Y3 & Y7; + const uint32_t pl01 = r2 ^ abcd2; + const uint32_t r3 = sa0 & sb0; + const uint32_t vr1 = aa & bb; + const uint32_t pr1 = vr1 ^ r3; + const uint32_t wr1 = sa1 & sb1; + const uint32_t qr1 = wr1 ^ r3; + const uint32_t ab0 = ph11 ^ rr1; + const uint32_t ab1 = ph01 ^ ab21; + const uint32_t ab2 = pl11 ^ r1; + const uint32_t ab3 = pl01 ^ qr1; + const uint32_t cp1 = ab0 ^ pr1; + const uint32_t cp2 = ab1 ^ qr1; + const uint32_t cp3 = ab2 ^ pr1; + const uint32_t cp4 = ab3 ^ ab23; + const uint32_t tinv1 = cp3 ^ cp4; + const uint32_t tinv2 = cp3 & cp1; + const uint32_t tinv3 = cp2 ^ tinv2; + const uint32_t tinv4 = cp1 ^ cp2; + const uint32_t tinv5 = cp4 ^ tinv2; + const uint32_t tinv6 = tinv5 & tinv4; + const uint32_t tinv7 = tinv3 & tinv1; + const uint32_t d2 = cp4 ^ tinv7; + const uint32_t d0 = cp2 ^ tinv6; + const uint32_t tinv8 = cp1 & cp4; + const uint32_t tinv9 = tinv4 & tinv8; + const uint32_t tinv10 = tinv4 ^ tinv2; + const uint32_t d1 = tinv9 ^ tinv10; + const uint32_t tinv11 = cp2 & cp3; + const uint32_t tinv12 = tinv1 & tinv11; + const uint32_t tinv13 = tinv1 ^ tinv2; + const uint32_t d3 = tinv12 ^ tinv13; + const uint32_t sd1 = d1 ^ d3; + const uint32_t sd0 = d0 ^ d2; + const uint32_t dl = d0 ^ d1; + const uint32_t dh = d2 ^ d3; + const uint32_t dd = sd0 ^ sd1; + const uint32_t abcd3 = dh & bh; + const uint32_t rr2 = d3 & Y4; + const uint32_t t02 = d2 & Y5; + const uint32_t abcd4 = dl & bl; + const uint32_t r4 = d1 & Y6; + const uint32_t r5 = d0 & Y7; + const uint32_t r6 = sd0 & sb0; + const uint32_t vr2 = dd & bb; + const uint32_t wr2 = sd1 & sb1; + const uint32_t abcd5 = dh & ah; + const uint32_t r7 = d3 & Y0; + const uint32_t r8 = d2 & Y1; + const uint32_t abcd6 = dl & al; + const uint32_t r9 = d1 & Y2; + const uint32_t r10 = d0 & Y3; + const uint32_t r11 = sd0 & sa0; + const uint32_t vr3 = dd & aa; + const uint32_t wr3 = sd1 & sa1; + const uint32_t ph12 = rr2 ^ abcd3; + const uint32_t ph02 = t02 ^ abcd3; + const uint32_t pl12 = r4 ^ abcd4; + const uint32_t pl02 = r5 ^ abcd4; + const uint32_t pr2 = vr2 ^ r6; + const uint32_t qr2 = wr2 ^ r6; + const uint32_t p0 = ph12 ^ pr2; + const uint32_t p1 = ph02 ^ qr2; + const uint32_t p2 = pl12 ^ pr2; + const uint32_t p3 = pl02 ^ qr2; + const uint32_t ph13 = r7 ^ abcd5; + const uint32_t ph03 = r8 ^ abcd5; + const uint32_t pl13 = r9 ^ abcd6; + const uint32_t pl03 = r10 ^ abcd6; + const uint32_t pr3 = vr3 ^ r11; + const uint32_t qr3 = wr3 ^ r11; + const uint32_t p4 = ph13 ^ pr3; + const uint32_t S7 = ph03 ^ qr3; + const uint32_t p6 = pl13 ^ pr3; + const uint32_t p7 = pl03 ^ qr3; + const uint32_t S3 = p1 ^ p6; + const uint32_t S6 = p2 ^ p6; + const uint32_t S0 = p3 ^ p6; + const uint32_t X11 = p0 ^ p2; + const uint32_t S5 = S0 ^ X11; + const uint32_t X13 = p4 ^ p7; + const uint32_t X14 = X11 ^ X13; + const uint32_t S1 = S3 ^ X14; + const uint32_t X16 = p1 ^ S7; + const uint32_t S2 = X14 ^ X16; + const uint32_t X18 = p0 ^ p4; + const uint32_t X19 = S5 ^ X16; + const uint32_t S4 = X18 ^ X19; + + V[0] = S0; + V[1] = S1; + V[2] = S2; + V[3] = S3; + V[4] = S4; + V[5] = S5; + V[6] = S6; + V[7] = S7; + } + +inline void bit_transpose(uint32_t B[8]) + { + swap_bits(B[1], B[0], 0x55555555, 1); + swap_bits(B[3], B[2], 0x55555555, 1); + swap_bits(B[5], B[4], 0x55555555, 1); + swap_bits(B[7], B[6], 0x55555555, 1); + + swap_bits(B[2], B[0], 0x33333333, 2); + swap_bits(B[3], B[1], 0x33333333, 2); + swap_bits(B[6], B[4], 0x33333333, 2); + swap_bits(B[7], B[5], 0x33333333, 2); + + swap_bits(B[4], B[0], 0x0F0F0F0F, 4); + swap_bits(B[5], B[1], 0x0F0F0F0F, 4); + swap_bits(B[6], B[2], 0x0F0F0F0F, 4); + swap_bits(B[7], B[3], 0x0F0F0F0F, 4); + } + +inline void ks_expand(uint32_t B[8], const uint32_t K[], size_t r) + { + /* + This is bit_transpose of K[r..r+4] || K[r..r+4], we can save some computation + due to knowing the first and second halves are the same data. + */ + for(size_t i = 0; i != 4; ++i) + B[i] = K[r + i]; + + swap_bits(B[1], B[0], 0x55555555, 1); + swap_bits(B[3], B[2], 0x55555555, 1); + + swap_bits(B[2], B[0], 0x33333333, 2); + swap_bits(B[3], B[1], 0x33333333, 2); + + B[4] = B[0]; + B[5] = B[1]; + B[6] = B[2]; + B[7] = B[3]; + + swap_bits(B[4], B[0], 0x0F0F0F0F, 4); + swap_bits(B[5], B[1], 0x0F0F0F0F, 4); + swap_bits(B[6], B[2], 0x0F0F0F0F, 4); + swap_bits(B[7], B[3], 0x0F0F0F0F, 4); + } + +inline void shift_rows(uint32_t B[8]) + { + // 3 0 1 2 7 4 5 6 10 11 8 9 14 15 12 13 17 18 19 16 21 22 23 20 24 25 26 27 28 29 30 31 +#if defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + for(size_t i = 0; i != 8; i += 2) + { + uint64_t x = (static_cast(B[i]) << 32) | B[i+1]; + x = bit_permute_step(x, 0x0022331100223311, 2); + x = bit_permute_step(x, 0x0055005500550055, 1); + B[i] = static_cast(x >> 32); + B[i+1] = static_cast(x); + } +#else + for(size_t i = 0; i != 8; ++i) + { + uint32_t x = B[i]; + x = bit_permute_step(x, 0x00223311, 2); + x = bit_permute_step(x, 0x00550055, 1); + B[i] = x; + } +#endif + } + +inline void inv_shift_rows(uint32_t B[8]) + { + // Inverse of shift_rows, just inverting the steps + +#if defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + for(size_t i = 0; i != 8; i += 2) + { + uint64_t x = (static_cast(B[i]) << 32) | B[i+1]; + x = bit_permute_step(x, 0x0055005500550055, 1); + x = bit_permute_step(x, 0x0022331100223311, 2); + B[i] = static_cast(x >> 32); + B[i+1] = static_cast(x); + } +#else + for(size_t i = 0; i != 8; ++i) + { + uint32_t x = B[i]; + x = bit_permute_step(x, 0x00550055, 1); + x = bit_permute_step(x, 0x00223311, 2); + B[i] = x; + } +#endif + } + +inline void mix_columns(uint32_t B[8]) + { + // carry high bits in B[0] to positions in 0x1b == 0b11011 + const uint32_t X2[8] = { + B[1], + B[2], + B[3], + B[4] ^ B[0], + B[5] ^ B[0], + B[6], + B[7] ^ B[0], + B[0], + }; + + for(size_t i = 0; i != 8; i++) + { + const uint32_t X3 = B[i] ^ X2[i]; + B[i] = X2[i] ^ rotr<8>(B[i]) ^ rotr<16>(B[i]) ^ rotr<24>(X3); + } + } + +void inv_mix_columns(uint32_t B[8]) + { + /* + OpenSSL's bsaes implementation credits Jussi Kivilinna with the lovely + matrix decomposition + + | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 | + | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 | + | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 | + | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 | + + Notice the first component is simply the MixColumns matrix. So we can + multiply first by (05,00,04,00) then perform MixColumns to get the equivalent + of InvMixColumn. + */ + const uint32_t X4[8] = { + B[2], + B[3], + B[4] ^ B[0], + B[5] ^ B[0] ^ B[1], + B[6] ^ B[1], + B[7] ^ B[0], + B[0] ^ B[1], + B[1], + }; + + for(size_t i = 0; i != 8; i++) + { + const uint32_t X5 = X4[i] ^ B[i]; + B[i] = X5 ^ rotr<16>(X4[i]); + } + + mix_columns(B); + } + +/* +* AES Encryption +*/ +void aes_encrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks, + const secure_vector& EK) + { + BOTAN_ASSERT(EK.size() == 44 || EK.size() == 52 || EK.size() == 60, "Key was set"); + + const size_t rounds = (EK.size() - 4) / 4; + + uint32_t KS[13*8] = { 0 }; // actual maximum is (rounds - 1) * 8 + for(size_t i = 0; i < rounds - 1; i += 1) + { + ks_expand(&KS[8*i], EK.data(), 4*i + 4); + } + + const size_t BLOCK_SIZE = 16; + const size_t BITSLICED_BLOCKS = 8*sizeof(uint32_t) / BLOCK_SIZE; + + while(blocks > 0) + { + const size_t this_loop = std::min(blocks, BITSLICED_BLOCKS); + + uint32_t B[8] = { 0 }; + + load_be(B, in, this_loop*4); + + for(size_t i = 0; i != 8; ++i) + B[i] ^= EK[i % 4]; + + bit_transpose(B); + + for(size_t r = 0; r != rounds - 1; ++r) + { + AES_SBOX(B); + shift_rows(B); + mix_columns(B); + + for(size_t i = 0; i != 8; ++i) + B[i] ^= KS[8*r + i]; + } + + // Final round: + AES_SBOX(B); + shift_rows(B); + bit_transpose(B); + + for(size_t i = 0; i != 8; ++i) + B[i] ^= EK[4*rounds + i % 4]; + + copy_out_be(out, this_loop*4*sizeof(uint32_t), B); + + in += this_loop * BLOCK_SIZE; + out += this_loop * BLOCK_SIZE; + blocks -= this_loop; + } + } + +/* +* AES Decryption +*/ +void aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks, + const secure_vector& DK) + { + BOTAN_ASSERT(DK.size() == 44 || DK.size() == 52 || DK.size() == 60, "Key was set"); + + const size_t rounds = (DK.size() - 4) / 4; + + uint32_t KS[13*8] = { 0 }; // actual maximum is (rounds - 1) * 8 + for(size_t i = 0; i < rounds - 1; i += 1) + { + ks_expand(&KS[8*i], DK.data(), 4*i + 4); + } + + const size_t BLOCK_SIZE = 16; + const size_t BITSLICED_BLOCKS = 8*sizeof(uint32_t) / BLOCK_SIZE; + + while(blocks > 0) + { + const size_t this_loop = std::min(blocks, BITSLICED_BLOCKS); + + uint32_t B[8] = { 0 }; + + load_be(B, in, this_loop*4); + + for(size_t i = 0; i != 8; ++i) + B[i] ^= DK[i % 4]; + + bit_transpose(B); + + for(size_t r = 0; r != rounds - 1; ++r) + { + AES_INV_SBOX(B); + inv_shift_rows(B); + inv_mix_columns(B); + + for(size_t i = 0; i != 8; ++i) + B[i] ^= KS[8*r + i]; + } + + // Final round: + AES_INV_SBOX(B); + inv_shift_rows(B); + bit_transpose(B); + + for(size_t i = 0; i != 8; ++i) + B[i] ^= DK[4*rounds + i % 4]; + + copy_out_be(out, this_loop*4*sizeof(uint32_t), B); + + in += this_loop * BLOCK_SIZE; + out += this_loop * BLOCK_SIZE; + blocks -= this_loop; + } + } + +inline uint32_t xtime32(uint32_t s) + { + const uint32_t lo_bit = 0x01010101; + const uint32_t mask = 0x7F7F7F7F; + const uint32_t poly = 0x1B; + + return ((s & mask) << 1) ^ (((s >> 7) & lo_bit) * poly); + } + +inline uint32_t InvMixColumn(uint32_t s1) + { + const uint32_t s2 = xtime32(s1); + const uint32_t s4 = xtime32(s2); + const uint32_t s8 = xtime32(s4); + const uint32_t s9 = s8 ^ s1; + const uint32_t s11 = s9 ^ s2; + const uint32_t s13 = s9 ^ s4; + const uint32_t s14 = s8 ^ s4 ^ s2; + + return s14 ^ rotr<8>(s9) ^ rotr<16>(s13) ^ rotr<24>(s11); + } + +void InvMixColumn_x4(uint32_t x[4]) + { + x[0] = InvMixColumn(x[0]); + x[1] = InvMixColumn(x[1]); + x[2] = InvMixColumn(x[2]); + x[3] = InvMixColumn(x[3]); + } + +uint32_t SE_word(uint32_t x) + { + uint32_t I[8] = { 0 }; + + for(size_t i = 0; i != 8; ++i) + I[i] = (x >> (7-i)) & 0x01010101; + + AES_SBOX(I); + + x = 0; + + for(size_t i = 0; i != 8; ++i) + x |= ((I[i] & 0x01010101) << (7-i)); + + return x; + } + +void aes_key_schedule(const uint8_t key[], size_t length, + secure_vector& EK, + secure_vector& DK, + bool bswap_keys = false) + { + static const uint32_t RC[10] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; + + const size_t X = length / 4; + + // Can't happen, but make static analyzers happy + BOTAN_ASSERT_NOMSG(X == 4 || X == 6 || X == 8); + + const size_t rounds = (length / 4) + 6; + + // Help the optimizer + BOTAN_ASSERT_NOMSG(rounds == 10 || rounds == 12 || rounds == 14); + + CT::poison(key, length); + + EK.resize(length + 28); + DK.resize(length + 28); + + for(size_t i = 0; i != X; ++i) + EK[i] = load_be(key, i); + + for(size_t i = X; i < 4*(rounds+1); i += X) + { + EK[i] = EK[i-X] ^ RC[(i-X)/X] ^ rotl<8>(SE_word(EK[i-1])); + + for(size_t j = 1; j != X && (i+j) < EK.size(); ++j) + { + EK[i+j] = EK[i+j-X]; + + if(X == 8 && j == 4) + EK[i+j] ^= SE_word(EK[i+j-1]); + else + EK[i+j] ^= EK[i+j-1]; + } + } + + for(size_t i = 0; i != 4*(rounds+1); i += 4) + { + DK[i ] = EK[4*rounds - i ]; + DK[i+1] = EK[4*rounds - i+1]; + DK[i+2] = EK[4*rounds - i+2]; + DK[i+3] = EK[4*rounds - i+3]; + } + + for(size_t i = 4; i != 4*rounds; i += 4) + { + InvMixColumn_x4(&DK[i]); + } + + if(bswap_keys) + { + // HW AES on little endian needs the subkeys to be byte reversed + for(size_t i = 0; i != EK.size(); ++i) + EK[i] = reverse_bytes(EK[i]); + for(size_t i = 0; i != DK.size(); ++i) + DK[i] = reverse_bytes(DK[i]); + } + + CT::unpoison(EK.data(), EK.size()); + CT::unpoison(DK.data(), DK.size()); + CT::unpoison(key, length); + } + +size_t aes_parallelism() + { +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return 4; // pipelined + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return 2; // pipelined + } +#endif + + // bitsliced: + return 2; + } + +const char* aes_provider() + { +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return "cpu"; + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return "vperm"; + } +#endif + + return "base"; + } + +} + +std::string AES_128::provider() const { return aes_provider(); } +std::string AES_192::provider() const { return aes_provider(); } +std::string AES_256::provider() const { return aes_provider(); } + +size_t AES_128::parallelism() const { return aes_parallelism(); } +size_t AES_192::parallelism() const { return aes_parallelism(); } +size_t AES_256::parallelism() const { return aes_parallelism(); } + +void AES_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return hw_aes_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_encrypt_n(in, out, blocks); + } +#endif + + aes_encrypt_n(in, out, blocks, m_EK); + } + +void AES_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return hw_aes_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_decrypt_n(in, out, blocks); + } +#endif + + aes_decrypt_n(in, out, blocks, m_DK); + } + +void AES_128::key_schedule(const uint8_t key[], size_t length) + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return aes_key_schedule(key, length, m_EK, m_DK, CPUID::is_little_endian()); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_key_schedule(key, length); + } +#endif + + aes_key_schedule(key, length, m_EK, m_DK); + } + +void AES_128::clear() + { + zap(m_EK); + zap(m_DK); + } + +void AES_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return hw_aes_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_encrypt_n(in, out, blocks); + } +#endif + + aes_encrypt_n(in, out, blocks, m_EK); + } + +void AES_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return hw_aes_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_decrypt_n(in, out, blocks); + } +#endif + + aes_decrypt_n(in, out, blocks, m_DK); + } + +void AES_192::key_schedule(const uint8_t key[], size_t length) + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return aes_key_schedule(key, length, m_EK, m_DK, CPUID::is_little_endian()); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_key_schedule(key, length); + } +#endif + + aes_key_schedule(key, length, m_EK, m_DK); + } + +void AES_192::clear() + { + zap(m_EK); + zap(m_DK); + } + +void AES_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return hw_aes_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_encrypt_n(in, out, blocks); + } +#endif + + aes_encrypt_n(in, out, blocks, m_EK); + } + +void AES_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return hw_aes_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_decrypt_n(in, out, blocks); + } +#endif + + aes_decrypt_n(in, out, blocks, m_DK); + } + +void AES_256::key_schedule(const uint8_t key[], size_t length) + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_HW_AES_SUPPORT) + if(CPUID::has_hw_aes()) + { + return aes_key_schedule(key, length, m_EK, m_DK, CPUID::is_little_endian()); + } +#endif + +#if defined(BOTAN_HAS_AES_VPERM) + if(CPUID::has_vperm()) + { + return vperm_key_schedule(key, length); + } +#endif + + aes_key_schedule(key, length, m_EK, m_DK); + } + +void AES_256::clear() + { + zap(m_EK); + zap(m_DK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/aes/aes.h b/comm/third_party/botan/src/lib/block/aes/aes.h new file mode 100644 index 0000000000..76248200d4 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes.h @@ -0,0 +1,131 @@ +/* +* AES +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AES_H_ +#define BOTAN_AES_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(aes.h) + +namespace Botan { + +/** +* AES-128 +*/ +class BOTAN_PUBLIC_API(2,0) AES_128 final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + std::string name() const override { return "AES-128"; } + BlockCipher* clone() const override { return new AES_128; } + size_t parallelism() const override; + + private: + void key_schedule(const uint8_t key[], size_t length) override; + +#if defined(BOTAN_HAS_AES_VPERM) + void vperm_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void vperm_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void vperm_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_POWER8) || defined(BOTAN_HAS_AES_ARMV8) || defined(BOTAN_HAS_AES_NI) + void hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + secure_vector m_EK, m_DK; + }; + +/** +* AES-192 +*/ +class BOTAN_PUBLIC_API(2,0) AES_192 final : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + std::string name() const override { return "AES-192"; } + BlockCipher* clone() const override { return new AES_192; } + size_t parallelism() const override; + + private: +#if defined(BOTAN_HAS_AES_VPERM) + void vperm_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void vperm_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void vperm_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_POWER8) || defined(BOTAN_HAS_AES_ARMV8) || defined(BOTAN_HAS_AES_NI) + void hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_EK, m_DK; + }; + +/** +* AES-256 +*/ +class BOTAN_PUBLIC_API(2,0) AES_256 final : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + + std::string name() const override { return "AES-256"; } + BlockCipher* clone() const override { return new AES_256; } + size_t parallelism() const override; + + private: +#if defined(BOTAN_HAS_AES_VPERM) + void vperm_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void vperm_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void vperm_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_POWER8) || defined(BOTAN_HAS_AES_ARMV8) || defined(BOTAN_HAS_AES_NI) + void hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_EK, m_DK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp b/comm/third_party/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp new file mode 100644 index 0000000000..9766bf88c9 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp @@ -0,0 +1,484 @@ +/* +* AES using ARMv8 +* Contributed by Jeffrey Walton +* +* Further changes +* (C) 2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +#define AES_ENC_4_ROUNDS(K) \ + do \ + { \ + B0 = vaesmcq_u8(vaeseq_u8(B0, K)); \ + B1 = vaesmcq_u8(vaeseq_u8(B1, K)); \ + B2 = vaesmcq_u8(vaeseq_u8(B2, K)); \ + B3 = vaesmcq_u8(vaeseq_u8(B3, K)); \ + } while(0) + +#define AES_ENC_4_LAST_ROUNDS(K, K2) \ + do \ + { \ + B0 = veorq_u8(vaeseq_u8(B0, K), K2); \ + B1 = veorq_u8(vaeseq_u8(B1, K), K2); \ + B2 = veorq_u8(vaeseq_u8(B2, K), K2); \ + B3 = veorq_u8(vaeseq_u8(B3, K), K2); \ + } while(0) + +#define AES_DEC_4_ROUNDS(K) \ + do \ + { \ + B0 = vaesimcq_u8(vaesdq_u8(B0, K)); \ + B1 = vaesimcq_u8(vaesdq_u8(B1, K)); \ + B2 = vaesimcq_u8(vaesdq_u8(B2, K)); \ + B3 = vaesimcq_u8(vaesdq_u8(B3, K)); \ + } while(0) + +#define AES_DEC_4_LAST_ROUNDS(K, K2) \ + do \ + { \ + B0 = veorq_u8(vaesdq_u8(B0, K), K2); \ + B1 = veorq_u8(vaesdq_u8(B1, K), K2); \ + B2 = veorq_u8(vaesdq_u8(B2, K), K2); \ + B3 = veorq_u8(vaesdq_u8(B3, K), K2); \ + } while(0) + +/* +* AES-128 Encryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_128::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const uint8_t *skey = reinterpret_cast(m_EK.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0*16); + const uint8x16_t K1 = vld1q_u8(skey + 1*16); + const uint8x16_t K2 = vld1q_u8(skey + 2*16); + const uint8x16_t K3 = vld1q_u8(skey + 3*16); + const uint8x16_t K4 = vld1q_u8(skey + 4*16); + const uint8x16_t K5 = vld1q_u8(skey + 5*16); + const uint8x16_t K6 = vld1q_u8(skey + 6*16); + const uint8x16_t K7 = vld1q_u8(skey + 7*16); + const uint8x16_t K8 = vld1q_u8(skey + 8*16); + const uint8x16_t K9 = vld1q_u8(skey + 9*16); + const uint8x16_t K10 = vld1q_u8(skey + 10*16); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_ENC_4_ROUNDS(K0); + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_LAST_ROUNDS(K9, K10); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesmcq_u8(vaeseq_u8(B, K0)); + B = vaesmcq_u8(vaeseq_u8(B, K1)); + B = vaesmcq_u8(vaeseq_u8(B, K2)); + B = vaesmcq_u8(vaeseq_u8(B, K3)); + B = vaesmcq_u8(vaeseq_u8(B, K4)); + B = vaesmcq_u8(vaeseq_u8(B, K5)); + B = vaesmcq_u8(vaeseq_u8(B, K6)); + B = vaesmcq_u8(vaeseq_u8(B, K7)); + B = vaesmcq_u8(vaeseq_u8(B, K8)); + B = veorq_u8(vaeseq_u8(B, K9), K10); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-128 Decryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_128::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const uint8_t *skey = reinterpret_cast(m_DK.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0*16); + const uint8x16_t K1 = vld1q_u8(skey + 1*16); + const uint8x16_t K2 = vld1q_u8(skey + 2*16); + const uint8x16_t K3 = vld1q_u8(skey + 3*16); + const uint8x16_t K4 = vld1q_u8(skey + 4*16); + const uint8x16_t K5 = vld1q_u8(skey + 5*16); + const uint8x16_t K6 = vld1q_u8(skey + 6*16); + const uint8x16_t K7 = vld1q_u8(skey + 7*16); + const uint8x16_t K8 = vld1q_u8(skey + 8*16); + const uint8x16_t K9 = vld1q_u8(skey + 9*16); + const uint8x16_t K10 = vld1q_u8(skey + 10*16); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_DEC_4_ROUNDS(K0); + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_LAST_ROUNDS(K9, K10); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesimcq_u8(vaesdq_u8(B, K0)); + B = vaesimcq_u8(vaesdq_u8(B, K1)); + B = vaesimcq_u8(vaesdq_u8(B, K2)); + B = vaesimcq_u8(vaesdq_u8(B, K3)); + B = vaesimcq_u8(vaesdq_u8(B, K4)); + B = vaesimcq_u8(vaesdq_u8(B, K5)); + B = vaesimcq_u8(vaesdq_u8(B, K6)); + B = vaesimcq_u8(vaesdq_u8(B, K7)); + B = vaesimcq_u8(vaesdq_u8(B, K8)); + B = veorq_u8(vaesdq_u8(B, K9), K10); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-192 Encryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_192::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const uint8_t *skey = reinterpret_cast(m_EK.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0*16); + const uint8x16_t K1 = vld1q_u8(skey + 1*16); + const uint8x16_t K2 = vld1q_u8(skey + 2*16); + const uint8x16_t K3 = vld1q_u8(skey + 3*16); + const uint8x16_t K4 = vld1q_u8(skey + 4*16); + const uint8x16_t K5 = vld1q_u8(skey + 5*16); + const uint8x16_t K6 = vld1q_u8(skey + 6*16); + const uint8x16_t K7 = vld1q_u8(skey + 7*16); + const uint8x16_t K8 = vld1q_u8(skey + 8*16); + const uint8x16_t K9 = vld1q_u8(skey + 9*16); + const uint8x16_t K10 = vld1q_u8(skey + 10*16); + const uint8x16_t K11 = vld1q_u8(skey + 11*16); + const uint8x16_t K12 = vld1q_u8(skey + 12*16); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_ENC_4_ROUNDS(K0); + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_LAST_ROUNDS(K11, K12); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesmcq_u8(vaeseq_u8(B, K0)); + B = vaesmcq_u8(vaeseq_u8(B, K1)); + B = vaesmcq_u8(vaeseq_u8(B, K2)); + B = vaesmcq_u8(vaeseq_u8(B, K3)); + B = vaesmcq_u8(vaeseq_u8(B, K4)); + B = vaesmcq_u8(vaeseq_u8(B, K5)); + B = vaesmcq_u8(vaeseq_u8(B, K6)); + B = vaesmcq_u8(vaeseq_u8(B, K7)); + B = vaesmcq_u8(vaeseq_u8(B, K8)); + B = vaesmcq_u8(vaeseq_u8(B, K9)); + B = vaesmcq_u8(vaeseq_u8(B, K10)); + B = veorq_u8(vaeseq_u8(B, K11), K12); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-192 Decryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_192::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const uint8_t *skey = reinterpret_cast(m_DK.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0*16); + const uint8x16_t K1 = vld1q_u8(skey + 1*16); + const uint8x16_t K2 = vld1q_u8(skey + 2*16); + const uint8x16_t K3 = vld1q_u8(skey + 3*16); + const uint8x16_t K4 = vld1q_u8(skey + 4*16); + const uint8x16_t K5 = vld1q_u8(skey + 5*16); + const uint8x16_t K6 = vld1q_u8(skey + 6*16); + const uint8x16_t K7 = vld1q_u8(skey + 7*16); + const uint8x16_t K8 = vld1q_u8(skey + 8*16); + const uint8x16_t K9 = vld1q_u8(skey + 9*16); + const uint8x16_t K10 = vld1q_u8(skey + 10*16); + const uint8x16_t K11 = vld1q_u8(skey + 11*16); + const uint8x16_t K12 = vld1q_u8(skey + 12*16); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_DEC_4_ROUNDS(K0); + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_LAST_ROUNDS(K11, K12); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesimcq_u8(vaesdq_u8(B, K0)); + B = vaesimcq_u8(vaesdq_u8(B, K1)); + B = vaesimcq_u8(vaesdq_u8(B, K2)); + B = vaesimcq_u8(vaesdq_u8(B, K3)); + B = vaesimcq_u8(vaesdq_u8(B, K4)); + B = vaesimcq_u8(vaesdq_u8(B, K5)); + B = vaesimcq_u8(vaesdq_u8(B, K6)); + B = vaesimcq_u8(vaesdq_u8(B, K7)); + B = vaesimcq_u8(vaesdq_u8(B, K8)); + B = vaesimcq_u8(vaesdq_u8(B, K9)); + B = vaesimcq_u8(vaesdq_u8(B, K10)); + B = veorq_u8(vaesdq_u8(B, K11), K12); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-256 Encryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_256::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const uint8_t *skey = reinterpret_cast(m_EK.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0*16); + const uint8x16_t K1 = vld1q_u8(skey + 1*16); + const uint8x16_t K2 = vld1q_u8(skey + 2*16); + const uint8x16_t K3 = vld1q_u8(skey + 3*16); + const uint8x16_t K4 = vld1q_u8(skey + 4*16); + const uint8x16_t K5 = vld1q_u8(skey + 5*16); + const uint8x16_t K6 = vld1q_u8(skey + 6*16); + const uint8x16_t K7 = vld1q_u8(skey + 7*16); + const uint8x16_t K8 = vld1q_u8(skey + 8*16); + const uint8x16_t K9 = vld1q_u8(skey + 9*16); + const uint8x16_t K10 = vld1q_u8(skey + 10*16); + const uint8x16_t K11 = vld1q_u8(skey + 11*16); + const uint8x16_t K12 = vld1q_u8(skey + 12*16); + const uint8x16_t K13 = vld1q_u8(skey + 13*16); + const uint8x16_t K14 = vld1q_u8(skey + 14*16); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_ENC_4_ROUNDS(K0); + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_ROUNDS(K12); + AES_ENC_4_LAST_ROUNDS(K13, K14); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesmcq_u8(vaeseq_u8(B, K0)); + B = vaesmcq_u8(vaeseq_u8(B, K1)); + B = vaesmcq_u8(vaeseq_u8(B, K2)); + B = vaesmcq_u8(vaeseq_u8(B, K3)); + B = vaesmcq_u8(vaeseq_u8(B, K4)); + B = vaesmcq_u8(vaeseq_u8(B, K5)); + B = vaesmcq_u8(vaeseq_u8(B, K6)); + B = vaesmcq_u8(vaeseq_u8(B, K7)); + B = vaesmcq_u8(vaeseq_u8(B, K8)); + B = vaesmcq_u8(vaeseq_u8(B, K9)); + B = vaesmcq_u8(vaeseq_u8(B, K10)); + B = vaesmcq_u8(vaeseq_u8(B, K11)); + B = vaesmcq_u8(vaeseq_u8(B, K12)); + B = veorq_u8(vaeseq_u8(B, K13), K14); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-256 Decryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_256::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const uint8_t *skey = reinterpret_cast(m_DK.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0*16); + const uint8x16_t K1 = vld1q_u8(skey + 1*16); + const uint8x16_t K2 = vld1q_u8(skey + 2*16); + const uint8x16_t K3 = vld1q_u8(skey + 3*16); + const uint8x16_t K4 = vld1q_u8(skey + 4*16); + const uint8x16_t K5 = vld1q_u8(skey + 5*16); + const uint8x16_t K6 = vld1q_u8(skey + 6*16); + const uint8x16_t K7 = vld1q_u8(skey + 7*16); + const uint8x16_t K8 = vld1q_u8(skey + 8*16); + const uint8x16_t K9 = vld1q_u8(skey + 9*16); + const uint8x16_t K10 = vld1q_u8(skey + 10*16); + const uint8x16_t K11 = vld1q_u8(skey + 11*16); + const uint8x16_t K12 = vld1q_u8(skey + 12*16); + const uint8x16_t K13 = vld1q_u8(skey + 13*16); + const uint8x16_t K14 = vld1q_u8(skey + 14*16); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_DEC_4_ROUNDS(K0); + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_ROUNDS(K12); + AES_DEC_4_LAST_ROUNDS(K13, K14); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesimcq_u8(vaesdq_u8(B, K0)); + B = vaesimcq_u8(vaesdq_u8(B, K1)); + B = vaesimcq_u8(vaesdq_u8(B, K2)); + B = vaesimcq_u8(vaesdq_u8(B, K3)); + B = vaesimcq_u8(vaesdq_u8(B, K4)); + B = vaesimcq_u8(vaesdq_u8(B, K5)); + B = vaesimcq_u8(vaesdq_u8(B, K6)); + B = vaesimcq_u8(vaesdq_u8(B, K7)); + B = vaesimcq_u8(vaesdq_u8(B, K8)); + B = vaesimcq_u8(vaesdq_u8(B, K9)); + B = vaesimcq_u8(vaesdq_u8(B, K10)); + B = vaesimcq_u8(vaesdq_u8(B, K11)); + B = vaesimcq_u8(vaesdq_u8(B, K12)); + B = veorq_u8(vaesdq_u8(B, K13), K14); + vst1q_u8(out+16*i, B); + } + } + +#undef AES_ENC_4_ROUNDS +#undef AES_ENC_4_LAST_ROUNDS +#undef AES_DEC_4_ROUNDS +#undef AES_DEC_4_LAST_ROUNDS + +} diff --git a/comm/third_party/botan/src/lib/block/aes/aes_armv8/info.txt b/comm/third_party/botan/src/lib/block/aes/aes_armv8/info.txt new file mode 100644 index 0000000000..1864f215b4 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_armv8/info.txt @@ -0,0 +1,12 @@ + +AES_ARMV8 -> 20170903 + + + +armv8crypto + + + +gcc:5 +clang:3.8 + diff --git a/comm/third_party/botan/src/lib/block/aes/aes_ni/aes_ni.cpp b/comm/third_party/botan/src/lib/block/aes/aes_ni/aes_ni.cpp new file mode 100644 index 0000000000..76c695f32c --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_ni/aes_ni.cpp @@ -0,0 +1,780 @@ +/* +* AES using AES-NI instructions +* (C) 2009,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_128_key_expansion(__m128i key, __m128i key_with_rcon) + { + key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(3,3,3,3)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + return _mm_xor_si128(key, key_with_rcon); + } + +BOTAN_FUNC_ISA("ssse3") +void aes_192_key_expansion(__m128i* K1, __m128i* K2, __m128i key2_with_rcon, + uint32_t out[], bool last) + { + __m128i key1 = *K1; + __m128i key2 = *K2; + + key2_with_rcon = _mm_shuffle_epi32(key2_with_rcon, _MM_SHUFFLE(1,1,1,1)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, key2_with_rcon); + + *K1 = key1; + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), key1); + + if(last) + return; + + key2 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4)); + key2 = _mm_xor_si128(key2, _mm_shuffle_epi32(key1, _MM_SHUFFLE(3,3,3,3))); + + *K2 = key2; + out[4] = _mm_cvtsi128_si32(key2); + out[5] = _mm_cvtsi128_si32(_mm_srli_si128(key2, 4)); + } + +/* +* The second half of the AES-256 key expansion (other half same as AES-128) +*/ +BOTAN_FUNC_ISA("ssse3,aes") +__m128i aes_256_key_expansion(__m128i key, __m128i key2) + { + __m128i key_with_rcon = _mm_aeskeygenassist_si128(key2, 0x00); + key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(2,2,2,2)); + + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + return _mm_xor_si128(key, key_with_rcon); + } + +} + +#define AES_ENC_4_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesenc_si128(B0, K); \ + B1 = _mm_aesenc_si128(B1, K); \ + B2 = _mm_aesenc_si128(B2, K); \ + B3 = _mm_aesenc_si128(B3, K); \ + } while(0) + +#define AES_ENC_4_LAST_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesenclast_si128(B0, K); \ + B1 = _mm_aesenclast_si128(B1, K); \ + B2 = _mm_aesenclast_si128(B2, K); \ + B3 = _mm_aesenclast_si128(B3, K); \ + } while(0) + +#define AES_DEC_4_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesdec_si128(B0, K); \ + B1 = _mm_aesdec_si128(B1, K); \ + B2 = _mm_aesdec_si128(B2, K); \ + B3 = _mm_aesdec_si128(B3, K); \ + } while(0) + +#define AES_DEC_4_LAST_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesdeclast_si128(B0, K); \ + B1 = _mm_aesdeclast_si128(B1, K); \ + B2 = _mm_aesdeclast_si128(B2, K); \ + B3 = _mm_aesdeclast_si128(B3, K); \ + } while(0) + +/* +* AES-128 Encryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_128::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(m_EK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_LAST_ROUNDS(K10); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenclast_si128(B, K10); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-128 Decryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_128::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(m_DK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_LAST_ROUNDS(K10); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdeclast_si128(B, K10); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-128 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_128::aesni_key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(44); + m_DK.resize(44); + + #define AES_128_key_exp(K, RCON) \ + aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON)) + + const __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); + const __m128i K1 = AES_128_key_exp(K0, 0x01); + const __m128i K2 = AES_128_key_exp(K1, 0x02); + const __m128i K3 = AES_128_key_exp(K2, 0x04); + const __m128i K4 = AES_128_key_exp(K3, 0x08); + const __m128i K5 = AES_128_key_exp(K4, 0x10); + const __m128i K6 = AES_128_key_exp(K5, 0x20); + const __m128i K7 = AES_128_key_exp(K6, 0x40); + const __m128i K8 = AES_128_key_exp(K7, 0x80); + const __m128i K9 = AES_128_key_exp(K8, 0x1B); + const __m128i K10 = AES_128_key_exp(K9, 0x36); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + _mm_storeu_si128(EK_mm , K0); + _mm_storeu_si128(EK_mm + 1, K1); + _mm_storeu_si128(EK_mm + 2, K2); + _mm_storeu_si128(EK_mm + 3, K3); + _mm_storeu_si128(EK_mm + 4, K4); + _mm_storeu_si128(EK_mm + 5, K5); + _mm_storeu_si128(EK_mm + 6, K6); + _mm_storeu_si128(EK_mm + 7, K7); + _mm_storeu_si128(EK_mm + 8, K8); + _mm_storeu_si128(EK_mm + 9, K9); + _mm_storeu_si128(EK_mm + 10, K10); + + // Now generate decryption keys + + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + _mm_storeu_si128(DK_mm , K10); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K9)); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K8)); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K7)); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K6)); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K5)); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K4)); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K3)); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K2)); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K1)); + _mm_storeu_si128(DK_mm + 10, K0); + } + +/* +* AES-192 Encryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_192::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(m_EK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_LAST_ROUNDS(K12); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenc_si128(B, K10); + B = _mm_aesenc_si128(B, K11); + B = _mm_aesenclast_si128(B, K12); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-192 Decryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_192::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(m_DK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_LAST_ROUNDS(K12); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdec_si128(B, K10); + B = _mm_aesdec_si128(B, K11); + B = _mm_aesdeclast_si128(B, K12); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-192 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_192::aesni_key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(52); + m_DK.resize(52); + + __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); + __m128i K1 = _mm_loadu_si128(reinterpret_cast(key + 8)); + K1 = _mm_srli_si128(K1, 8); + + load_le(m_EK.data(), key, 6); + + #define AES_192_key_exp(RCON, EK_OFF) \ + aes_192_key_expansion(&K0, &K1, \ + _mm_aeskeygenassist_si128(K1, RCON), \ + &m_EK[EK_OFF], EK_OFF == 48) + + AES_192_key_exp(0x01, 6); + AES_192_key_exp(0x02, 12); + AES_192_key_exp(0x04, 18); + AES_192_key_exp(0x08, 24); + AES_192_key_exp(0x10, 30); + AES_192_key_exp(0x20, 36); + AES_192_key_exp(0x40, 42); + AES_192_key_exp(0x80, 48); + + #undef AES_192_key_exp + + // Now generate decryption keys + const __m128i* EK_mm = reinterpret_cast(m_EK.data()); + + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + _mm_storeu_si128(DK_mm , _mm_loadu_si128(EK_mm + 12)); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 11))); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 10))); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 9))); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 8))); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 7))); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 6))); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 5))); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 4))); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 3))); + _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 2))); + _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 1))); + _mm_storeu_si128(DK_mm + 12, _mm_loadu_si128(EK_mm + 0)); + } + +/* +* AES-256 Encryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_256::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(m_EK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + const __m128i K13 = _mm_loadu_si128(key_mm + 13); + const __m128i K14 = _mm_loadu_si128(key_mm + 14); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_ROUNDS(K12); + AES_ENC_4_ROUNDS(K13); + AES_ENC_4_LAST_ROUNDS(K14); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenc_si128(B, K10); + B = _mm_aesenc_si128(B, K11); + B = _mm_aesenc_si128(B, K12); + B = _mm_aesenc_si128(B, K13); + B = _mm_aesenclast_si128(B, K14); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-256 Decryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_256::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast(m_DK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + const __m128i K13 = _mm_loadu_si128(key_mm + 13); + const __m128i K14 = _mm_loadu_si128(key_mm + 14); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_ROUNDS(K12); + AES_DEC_4_ROUNDS(K13); + AES_DEC_4_LAST_ROUNDS(K14); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdec_si128(B, K10); + B = _mm_aesdec_si128(B, K11); + B = _mm_aesdec_si128(B, K12); + B = _mm_aesdec_si128(B, K13); + B = _mm_aesdeclast_si128(B, K14); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-256 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_256::aesni_key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(60); + m_DK.resize(60); + + const __m128i K0 = _mm_loadu_si128(reinterpret_cast(key)); + const __m128i K1 = _mm_loadu_si128(reinterpret_cast(key + 16)); + + const __m128i K2 = aes_128_key_expansion(K0, _mm_aeskeygenassist_si128(K1, 0x01)); + const __m128i K3 = aes_256_key_expansion(K1, K2); + + const __m128i K4 = aes_128_key_expansion(K2, _mm_aeskeygenassist_si128(K3, 0x02)); + const __m128i K5 = aes_256_key_expansion(K3, K4); + + const __m128i K6 = aes_128_key_expansion(K4, _mm_aeskeygenassist_si128(K5, 0x04)); + const __m128i K7 = aes_256_key_expansion(K5, K6); + + const __m128i K8 = aes_128_key_expansion(K6, _mm_aeskeygenassist_si128(K7, 0x08)); + const __m128i K9 = aes_256_key_expansion(K7, K8); + + const __m128i K10 = aes_128_key_expansion(K8, _mm_aeskeygenassist_si128(K9, 0x10)); + const __m128i K11 = aes_256_key_expansion(K9, K10); + + const __m128i K12 = aes_128_key_expansion(K10, _mm_aeskeygenassist_si128(K11, 0x20)); + const __m128i K13 = aes_256_key_expansion(K11, K12); + + const __m128i K14 = aes_128_key_expansion(K12, _mm_aeskeygenassist_si128(K13, 0x40)); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + _mm_storeu_si128(EK_mm , K0); + _mm_storeu_si128(EK_mm + 1, K1); + _mm_storeu_si128(EK_mm + 2, K2); + _mm_storeu_si128(EK_mm + 3, K3); + _mm_storeu_si128(EK_mm + 4, K4); + _mm_storeu_si128(EK_mm + 5, K5); + _mm_storeu_si128(EK_mm + 6, K6); + _mm_storeu_si128(EK_mm + 7, K7); + _mm_storeu_si128(EK_mm + 8, K8); + _mm_storeu_si128(EK_mm + 9, K9); + _mm_storeu_si128(EK_mm + 10, K10); + _mm_storeu_si128(EK_mm + 11, K11); + _mm_storeu_si128(EK_mm + 12, K12); + _mm_storeu_si128(EK_mm + 13, K13); + _mm_storeu_si128(EK_mm + 14, K14); + + // Now generate decryption keys + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + _mm_storeu_si128(DK_mm , K14); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K13)); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K12)); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K11)); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K10)); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K9)); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K8)); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K7)); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K6)); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K5)); + _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(K4)); + _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(K3)); + _mm_storeu_si128(DK_mm + 12, _mm_aesimc_si128(K2)); + _mm_storeu_si128(DK_mm + 13, _mm_aesimc_si128(K1)); + _mm_storeu_si128(DK_mm + 14, K0); + } + +#undef AES_ENC_4_ROUNDS +#undef AES_ENC_4_LAST_ROUNDS +#undef AES_DEC_4_ROUNDS +#undef AES_DEC_4_LAST_ROUNDS + +} diff --git a/comm/third_party/botan/src/lib/block/aes/aes_ni/info.txt b/comm/third_party/botan/src/lib/block/aes/aes_ni/info.txt new file mode 100644 index 0000000000..2e9749fb8e --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_ni/info.txt @@ -0,0 +1,9 @@ + +AES_NI -> 20131128 + + + +sse2 +ssse3 +aesni + diff --git a/comm/third_party/botan/src/lib/block/aes/aes_power8/aes_power8.cpp b/comm/third_party/botan/src/lib/block/aes/aes_power8/aes_power8.cpp new file mode 100644 index 0000000000..18bc85933b --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_power8/aes_power8.cpp @@ -0,0 +1,529 @@ +/* +* AES using POWER8/POWER9 crypto extensions +* +* Contributed by Jeffrey Walton +* +* Further changes +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include +#undef vector +#undef bool + +namespace Botan { + +typedef __vector unsigned long long Altivec64x2; +typedef __vector unsigned int Altivec32x4; +typedef __vector unsigned char Altivec8x16; + +namespace { + +inline Altivec8x16 reverse_vec(Altivec8x16 src) + { + if(CPUID::is_little_endian()) + { + const Altivec8x16 mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + const Altivec8x16 zero = {0}; + return vec_perm(src, zero, mask); + } + else + { + return src; + } + } + +inline Altivec64x2 load_key(const uint32_t key[]) + { + return (Altivec64x2)reverse_vec((Altivec8x16)vec_vsx_ld(0, key));; + } + +inline Altivec64x2 load_block(const uint8_t src[]) + { + return (Altivec64x2)reverse_vec(vec_vsx_ld(0, src)); + } + +inline void store_block(Altivec64x2 src, uint8_t dest[]) + { + vec_vsx_st(reverse_vec((Altivec8x16)src), 0, dest); + } + +inline void store_blocks(Altivec64x2 B0, Altivec64x2 B1, + Altivec64x2 B2, Altivec64x2 B3, + uint8_t out[]) + { + store_block(B0, out); + store_block(B1, out+16); + store_block(B2, out+16*2); + store_block(B3, out+16*3); + } + +#define AES_XOR_4(B0, B1, B2, B3, K) do { \ + B0 = vec_xor(B0, K); \ + B1 = vec_xor(B1, K); \ + B2 = vec_xor(B2, K); \ + B3 = vec_xor(B3, K); \ + } while(0) + +#define AES_ENCRYPT_4(B0, B1, B2, B3, K) do { \ + B0 = __builtin_crypto_vcipher(B0, K); \ + B1 = __builtin_crypto_vcipher(B1, K); \ + B2 = __builtin_crypto_vcipher(B2, K); \ + B3 = __builtin_crypto_vcipher(B3, K); \ + } while(0) + +#define AES_ENCRYPT_4_LAST(B0, B1, B2, B3, K) do { \ + B0 = __builtin_crypto_vcipherlast(B0, K); \ + B1 = __builtin_crypto_vcipherlast(B1, K); \ + B2 = __builtin_crypto_vcipherlast(B2, K); \ + B3 = __builtin_crypto_vcipherlast(B3, K); \ + } while(0) + +#define AES_DECRYPT_4(B0, B1, B2, B3, K) do { \ + B0 = __builtin_crypto_vncipher(B0, K); \ + B1 = __builtin_crypto_vncipher(B1, K); \ + B2 = __builtin_crypto_vncipher(B2, K); \ + B3 = __builtin_crypto_vncipher(B3, K); \ + } while(0) + +#define AES_DECRYPT_4_LAST(B0, B1, B2, B3, K) do { \ + B0 = __builtin_crypto_vncipherlast(B0, K); \ + B1 = __builtin_crypto_vncipherlast(B1, K); \ + B2 = __builtin_crypto_vncipherlast(B2, K); \ + B3 = __builtin_crypto_vncipherlast(B3, K); \ + } while(0) + +} + +BOTAN_FUNC_ISA("crypto") +void AES_128::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const Altivec64x2 K0 = load_key(&m_EK[0]); + const Altivec64x2 K1 = load_key(&m_EK[4]); + const Altivec64x2 K2 = load_key(&m_EK[8]); + const Altivec64x2 K3 = load_key(&m_EK[12]); + const Altivec64x2 K4 = load_key(&m_EK[16]); + const Altivec64x2 K5 = load_key(&m_EK[20]); + const Altivec64x2 K6 = load_key(&m_EK[24]); + const Altivec64x2 K7 = load_key(&m_EK[28]); + const Altivec64x2 K8 = load_key(&m_EK[32]); + const Altivec64x2 K9 = load_key(&m_EK[36]); + const Altivec64x2 K10 = load_key(&m_EK[40]); + + while(blocks >= 4) + { + Altivec64x2 B0 = load_block(in); + Altivec64x2 B1 = load_block(in+16); + Altivec64x2 B2 = load_block(in+16*2); + Altivec64x2 B3 = load_block(in+16*3); + + AES_XOR_4(B0, B1, B2, B3, K0); + AES_ENCRYPT_4(B0, B1, B2, B3, K1); + AES_ENCRYPT_4(B0, B1, B2, B3, K2); + AES_ENCRYPT_4(B0, B1, B2, B3, K3); + AES_ENCRYPT_4(B0, B1, B2, B3, K4); + AES_ENCRYPT_4(B0, B1, B2, B3, K5); + AES_ENCRYPT_4(B0, B1, B2, B3, K6); + AES_ENCRYPT_4(B0, B1, B2, B3, K7); + AES_ENCRYPT_4(B0, B1, B2, B3, K8); + AES_ENCRYPT_4(B0, B1, B2, B3, K9); + AES_ENCRYPT_4_LAST(B0, B1, B2, B3, K10); + + store_blocks(B0, B1, B2, B3, out); + + out += 4*16; + in += 4*16; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + Altivec64x2 B = load_block(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vcipher(B, K1); + B = __builtin_crypto_vcipher(B, K2); + B = __builtin_crypto_vcipher(B, K3); + B = __builtin_crypto_vcipher(B, K4); + B = __builtin_crypto_vcipher(B, K5); + B = __builtin_crypto_vcipher(B, K6); + B = __builtin_crypto_vcipher(B, K7); + B = __builtin_crypto_vcipher(B, K8); + B = __builtin_crypto_vcipher(B, K9); + B = __builtin_crypto_vcipherlast(B, K10); + + store_block(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_128::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const Altivec64x2 K0 = load_key(&m_EK[40]); + const Altivec64x2 K1 = load_key(&m_EK[36]); + const Altivec64x2 K2 = load_key(&m_EK[32]); + const Altivec64x2 K3 = load_key(&m_EK[28]); + const Altivec64x2 K4 = load_key(&m_EK[24]); + const Altivec64x2 K5 = load_key(&m_EK[20]); + const Altivec64x2 K6 = load_key(&m_EK[16]); + const Altivec64x2 K7 = load_key(&m_EK[12]); + const Altivec64x2 K8 = load_key(&m_EK[8]); + const Altivec64x2 K9 = load_key(&m_EK[4]); + const Altivec64x2 K10 = load_key(&m_EK[0]); + + while(blocks >= 4) + { + Altivec64x2 B0 = load_block(in); + Altivec64x2 B1 = load_block(in+16); + Altivec64x2 B2 = load_block(in+16*2); + Altivec64x2 B3 = load_block(in+16*3); + + AES_XOR_4(B0, B1, B2, B3, K0); + AES_DECRYPT_4(B0, B1, B2, B3, K1); + AES_DECRYPT_4(B0, B1, B2, B3, K2); + AES_DECRYPT_4(B0, B1, B2, B3, K3); + AES_DECRYPT_4(B0, B1, B2, B3, K4); + AES_DECRYPT_4(B0, B1, B2, B3, K5); + AES_DECRYPT_4(B0, B1, B2, B3, K6); + AES_DECRYPT_4(B0, B1, B2, B3, K7); + AES_DECRYPT_4(B0, B1, B2, B3, K8); + AES_DECRYPT_4(B0, B1, B2, B3, K9); + AES_DECRYPT_4_LAST(B0, B1, B2, B3, K10); + + store_blocks(B0, B1, B2, B3, out); + + out += 4*16; + in += 4*16; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + Altivec64x2 B = load_block(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vncipher(B, K1); + B = __builtin_crypto_vncipher(B, K2); + B = __builtin_crypto_vncipher(B, K3); + B = __builtin_crypto_vncipher(B, K4); + B = __builtin_crypto_vncipher(B, K5); + B = __builtin_crypto_vncipher(B, K6); + B = __builtin_crypto_vncipher(B, K7); + B = __builtin_crypto_vncipher(B, K8); + B = __builtin_crypto_vncipher(B, K9); + B = __builtin_crypto_vncipherlast(B, K10); + + store_block(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_192::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const Altivec64x2 K0 = load_key(&m_EK[0]); + const Altivec64x2 K1 = load_key(&m_EK[4]); + const Altivec64x2 K2 = load_key(&m_EK[8]); + const Altivec64x2 K3 = load_key(&m_EK[12]); + const Altivec64x2 K4 = load_key(&m_EK[16]); + const Altivec64x2 K5 = load_key(&m_EK[20]); + const Altivec64x2 K6 = load_key(&m_EK[24]); + const Altivec64x2 K7 = load_key(&m_EK[28]); + const Altivec64x2 K8 = load_key(&m_EK[32]); + const Altivec64x2 K9 = load_key(&m_EK[36]); + const Altivec64x2 K10 = load_key(&m_EK[40]); + const Altivec64x2 K11 = load_key(&m_EK[44]); + const Altivec64x2 K12 = load_key(&m_EK[48]); + + while(blocks >= 4) + { + Altivec64x2 B0 = load_block(in); + Altivec64x2 B1 = load_block(in+16); + Altivec64x2 B2 = load_block(in+16*2); + Altivec64x2 B3 = load_block(in+16*3); + + AES_XOR_4(B0, B1, B2, B3, K0); + AES_ENCRYPT_4(B0, B1, B2, B3, K1); + AES_ENCRYPT_4(B0, B1, B2, B3, K2); + AES_ENCRYPT_4(B0, B1, B2, B3, K3); + AES_ENCRYPT_4(B0, B1, B2, B3, K4); + AES_ENCRYPT_4(B0, B1, B2, B3, K5); + AES_ENCRYPT_4(B0, B1, B2, B3, K6); + AES_ENCRYPT_4(B0, B1, B2, B3, K7); + AES_ENCRYPT_4(B0, B1, B2, B3, K8); + AES_ENCRYPT_4(B0, B1, B2, B3, K9); + AES_ENCRYPT_4(B0, B1, B2, B3, K10); + AES_ENCRYPT_4(B0, B1, B2, B3, K11); + AES_ENCRYPT_4_LAST(B0, B1, B2, B3, K12); + + store_blocks(B0, B1, B2, B3, out); + + out += 4*16; + in += 4*16; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + Altivec64x2 B = load_block(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vcipher(B, K1); + B = __builtin_crypto_vcipher(B, K2); + B = __builtin_crypto_vcipher(B, K3); + B = __builtin_crypto_vcipher(B, K4); + B = __builtin_crypto_vcipher(B, K5); + B = __builtin_crypto_vcipher(B, K6); + B = __builtin_crypto_vcipher(B, K7); + B = __builtin_crypto_vcipher(B, K8); + B = __builtin_crypto_vcipher(B, K9); + B = __builtin_crypto_vcipher(B, K10); + B = __builtin_crypto_vcipher(B, K11); + B = __builtin_crypto_vcipherlast(B, K12); + + store_block(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_192::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const Altivec64x2 K0 = load_key(&m_EK[48]); + const Altivec64x2 K1 = load_key(&m_EK[44]); + const Altivec64x2 K2 = load_key(&m_EK[40]); + const Altivec64x2 K3 = load_key(&m_EK[36]); + const Altivec64x2 K4 = load_key(&m_EK[32]); + const Altivec64x2 K5 = load_key(&m_EK[28]); + const Altivec64x2 K6 = load_key(&m_EK[24]); + const Altivec64x2 K7 = load_key(&m_EK[20]); + const Altivec64x2 K8 = load_key(&m_EK[16]); + const Altivec64x2 K9 = load_key(&m_EK[12]); + const Altivec64x2 K10 = load_key(&m_EK[8]); + const Altivec64x2 K11 = load_key(&m_EK[4]); + const Altivec64x2 K12 = load_key(&m_EK[0]); + + while(blocks >= 4) + { + Altivec64x2 B0 = load_block(in); + Altivec64x2 B1 = load_block(in+16); + Altivec64x2 B2 = load_block(in+16*2); + Altivec64x2 B3 = load_block(in+16*3); + + AES_XOR_4(B0, B1, B2, B3, K0); + AES_DECRYPT_4(B0, B1, B2, B3, K1); + AES_DECRYPT_4(B0, B1, B2, B3, K2); + AES_DECRYPT_4(B0, B1, B2, B3, K3); + AES_DECRYPT_4(B0, B1, B2, B3, K4); + AES_DECRYPT_4(B0, B1, B2, B3, K5); + AES_DECRYPT_4(B0, B1, B2, B3, K6); + AES_DECRYPT_4(B0, B1, B2, B3, K7); + AES_DECRYPT_4(B0, B1, B2, B3, K8); + AES_DECRYPT_4(B0, B1, B2, B3, K9); + AES_DECRYPT_4(B0, B1, B2, B3, K10); + AES_DECRYPT_4(B0, B1, B2, B3, K11); + AES_DECRYPT_4_LAST(B0, B1, B2, B3, K12); + + store_blocks(B0, B1, B2, B3, out); + + out += 4*16; + in += 4*16; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + Altivec64x2 B = load_block(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vncipher(B, K1); + B = __builtin_crypto_vncipher(B, K2); + B = __builtin_crypto_vncipher(B, K3); + B = __builtin_crypto_vncipher(B, K4); + B = __builtin_crypto_vncipher(B, K5); + B = __builtin_crypto_vncipher(B, K6); + B = __builtin_crypto_vncipher(B, K7); + B = __builtin_crypto_vncipher(B, K8); + B = __builtin_crypto_vncipher(B, K9); + B = __builtin_crypto_vncipher(B, K10); + B = __builtin_crypto_vncipher(B, K11); + B = __builtin_crypto_vncipherlast(B, K12); + + store_block(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_256::hw_aes_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const Altivec64x2 K0 = load_key(&m_EK[0]); + const Altivec64x2 K1 = load_key(&m_EK[4]); + const Altivec64x2 K2 = load_key(&m_EK[8]); + const Altivec64x2 K3 = load_key(&m_EK[12]); + const Altivec64x2 K4 = load_key(&m_EK[16]); + const Altivec64x2 K5 = load_key(&m_EK[20]); + const Altivec64x2 K6 = load_key(&m_EK[24]); + const Altivec64x2 K7 = load_key(&m_EK[28]); + const Altivec64x2 K8 = load_key(&m_EK[32]); + const Altivec64x2 K9 = load_key(&m_EK[36]); + const Altivec64x2 K10 = load_key(&m_EK[40]); + const Altivec64x2 K11 = load_key(&m_EK[44]); + const Altivec64x2 K12 = load_key(&m_EK[48]); + const Altivec64x2 K13 = load_key(&m_EK[52]); + const Altivec64x2 K14 = load_key(&m_EK[56]); + + while(blocks >= 4) + { + Altivec64x2 B0 = load_block(in); + Altivec64x2 B1 = load_block(in+16); + Altivec64x2 B2 = load_block(in+16*2); + Altivec64x2 B3 = load_block(in+16*3); + + AES_XOR_4(B0, B1, B2, B3, K0); + AES_ENCRYPT_4(B0, B1, B2, B3, K1); + AES_ENCRYPT_4(B0, B1, B2, B3, K2); + AES_ENCRYPT_4(B0, B1, B2, B3, K3); + AES_ENCRYPT_4(B0, B1, B2, B3, K4); + AES_ENCRYPT_4(B0, B1, B2, B3, K5); + AES_ENCRYPT_4(B0, B1, B2, B3, K6); + AES_ENCRYPT_4(B0, B1, B2, B3, K7); + AES_ENCRYPT_4(B0, B1, B2, B3, K8); + AES_ENCRYPT_4(B0, B1, B2, B3, K9); + AES_ENCRYPT_4(B0, B1, B2, B3, K10); + AES_ENCRYPT_4(B0, B1, B2, B3, K11); + AES_ENCRYPT_4(B0, B1, B2, B3, K12); + AES_ENCRYPT_4(B0, B1, B2, B3, K13); + AES_ENCRYPT_4_LAST(B0, B1, B2, B3, K14); + + store_blocks(B0, B1, B2, B3, out); + + out += 4*16; + in += 4*16; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + Altivec64x2 B = load_block(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vcipher(B, K1); + B = __builtin_crypto_vcipher(B, K2); + B = __builtin_crypto_vcipher(B, K3); + B = __builtin_crypto_vcipher(B, K4); + B = __builtin_crypto_vcipher(B, K5); + B = __builtin_crypto_vcipher(B, K6); + B = __builtin_crypto_vcipher(B, K7); + B = __builtin_crypto_vcipher(B, K8); + B = __builtin_crypto_vcipher(B, K9); + B = __builtin_crypto_vcipher(B, K10); + B = __builtin_crypto_vcipher(B, K11); + B = __builtin_crypto_vcipher(B, K12); + B = __builtin_crypto_vcipher(B, K13); + B = __builtin_crypto_vcipherlast(B, K14); + + store_block(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_256::hw_aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const Altivec64x2 K0 = load_key(&m_EK[56]); + const Altivec64x2 K1 = load_key(&m_EK[52]); + const Altivec64x2 K2 = load_key(&m_EK[48]); + const Altivec64x2 K3 = load_key(&m_EK[44]); + const Altivec64x2 K4 = load_key(&m_EK[40]); + const Altivec64x2 K5 = load_key(&m_EK[36]); + const Altivec64x2 K6 = load_key(&m_EK[32]); + const Altivec64x2 K7 = load_key(&m_EK[28]); + const Altivec64x2 K8 = load_key(&m_EK[24]); + const Altivec64x2 K9 = load_key(&m_EK[20]); + const Altivec64x2 K10 = load_key(&m_EK[16]); + const Altivec64x2 K11 = load_key(&m_EK[12]); + const Altivec64x2 K12 = load_key(&m_EK[8]); + const Altivec64x2 K13 = load_key(&m_EK[4]); + const Altivec64x2 K14 = load_key(&m_EK[0]); + + while(blocks >= 4) + { + Altivec64x2 B0 = load_block(in); + Altivec64x2 B1 = load_block(in+16); + Altivec64x2 B2 = load_block(in+16*2); + Altivec64x2 B3 = load_block(in+16*3); + + AES_XOR_4(B0, B1, B2, B3, K0); + AES_DECRYPT_4(B0, B1, B2, B3, K1); + AES_DECRYPT_4(B0, B1, B2, B3, K2); + AES_DECRYPT_4(B0, B1, B2, B3, K3); + AES_DECRYPT_4(B0, B1, B2, B3, K4); + AES_DECRYPT_4(B0, B1, B2, B3, K5); + AES_DECRYPT_4(B0, B1, B2, B3, K6); + AES_DECRYPT_4(B0, B1, B2, B3, K7); + AES_DECRYPT_4(B0, B1, B2, B3, K8); + AES_DECRYPT_4(B0, B1, B2, B3, K9); + AES_DECRYPT_4(B0, B1, B2, B3, K10); + AES_DECRYPT_4(B0, B1, B2, B3, K11); + AES_DECRYPT_4(B0, B1, B2, B3, K12); + AES_DECRYPT_4(B0, B1, B2, B3, K13); + AES_DECRYPT_4_LAST(B0, B1, B2, B3, K14); + + store_blocks(B0, B1, B2, B3, out); + + out += 4*16; + in += 4*16; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + Altivec64x2 B = load_block(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vncipher(B, K1); + B = __builtin_crypto_vncipher(B, K2); + B = __builtin_crypto_vncipher(B, K3); + B = __builtin_crypto_vncipher(B, K4); + B = __builtin_crypto_vncipher(B, K5); + B = __builtin_crypto_vncipher(B, K6); + B = __builtin_crypto_vncipher(B, K7); + B = __builtin_crypto_vncipher(B, K8); + B = __builtin_crypto_vncipher(B, K9); + B = __builtin_crypto_vncipher(B, K10); + B = __builtin_crypto_vncipher(B, K11); + B = __builtin_crypto_vncipher(B, K12); + B = __builtin_crypto_vncipher(B, K13); + B = __builtin_crypto_vncipherlast(B, K14); + + store_block(B, out); + + out += 16; + in += 16; + } + } + +#undef AES_XOR_4 +#undef AES_ENCRYPT_4 +#undef AES_ENCRYPT_4_LAST +#undef AES_DECRYPT_4 +#undef AES_DECRYPT_4_LAST + +} diff --git a/comm/third_party/botan/src/lib/block/aes/aes_power8/info.txt b/comm/third_party/botan/src/lib/block/aes/aes_power8/info.txt new file mode 100644 index 0000000000..df569edd50 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_power8/info.txt @@ -0,0 +1,11 @@ + +AES_POWER8 -> 20180223 + + + +ppc64 + + + +powercrypto + diff --git a/comm/third_party/botan/src/lib/block/aes/aes_vperm/aes_vperm.cpp b/comm/third_party/botan/src/lib/block/aes/aes_vperm/aes_vperm.cpp new file mode 100644 index 0000000000..4ae6bb2236 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_vperm/aes_vperm.cpp @@ -0,0 +1,627 @@ +/* +* AES using vector permutes (SSSE3, NEON) +* (C) 2010,2016,2019 Jack Lloyd +* +* Based on public domain x86-64 assembly written by Mike Hamburg, +* described in "Accelerating AES with Vector Permute Instructions" +* (CHES 2009). His original code is available at +* https://crypto.stanford.edu/vpaes/ +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_SIMD_USE_SSE2) + #include +#endif + +namespace Botan { + +namespace { + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) shuffle(SIMD_4x32 a, SIMD_4x32 b) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_shuffle_epi8(a.raw(), b.raw())); +#elif defined(BOTAN_SIMD_USE_NEON) + const uint8x16_t tbl = vreinterpretq_u8_u32(a.raw()); + const uint8x16_t idx = vreinterpretq_u8_u32(b.raw()); + +#if defined(BOTAN_TARGET_ARCH_IS_ARM32) + const uint8x8x2_t tbl2 = { vget_low_u8(tbl), vget_high_u8(tbl) }; + + return SIMD_4x32(vreinterpretq_u32_u8( + vcombine_u8(vtbl2_u8(tbl2, vget_low_u8(idx)), + vtbl2_u8(tbl2, vget_high_u8(idx))))); + +#else + return SIMD_4x32(vreinterpretq_u32_u8(vqtbl1q_u8(tbl, idx))); +#endif + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + const auto zero = vec_splat_s8(0x00); + const auto mask = vec_cmplt((__vector signed char)b.raw(), zero); + const auto r = vec_perm((__vector signed char)a.raw(), (__vector signed char)a.raw(), (__vector unsigned char)b.raw()); + return SIMD_4x32((__vector unsigned int)vec_sel(r, zero, mask)); + +#else + #error "No shuffle implementation available" +#endif + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) alignr8(SIMD_4x32 a, SIMD_4x32 b) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_alignr_epi8(a.raw(), b.raw(), 8)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vextq_u32(b.raw(), a.raw(), 2)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const __vector unsigned char mask = {8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}; + return SIMD_4x32(vec_perm(b.raw(), a.raw(), mask)); +#else + #error "No alignr8 implementation available" +#endif + } + +const SIMD_4x32 k_ipt1 = SIMD_4x32(0x5A2A7000, 0xC2B2E898, 0x52227808, 0xCABAE090); +const SIMD_4x32 k_ipt2 = SIMD_4x32(0x317C4D00, 0x4C01307D, 0xB0FDCC81, 0xCD80B1FC); + +const SIMD_4x32 k_inv1 = SIMD_4x32(0x0D080180, 0x0E05060F, 0x0A0B0C02, 0x04070309); +const SIMD_4x32 k_inv2 = SIMD_4x32(0x0F0B0780, 0x01040A06, 0x02050809, 0x030D0E0C); + +const SIMD_4x32 sb1u = SIMD_4x32(0xCB503E00, 0xB19BE18F, 0x142AF544, 0xA5DF7A6E); +const SIMD_4x32 sb1t = SIMD_4x32(0xFAE22300, 0x3618D415, 0x0D2ED9EF, 0x3BF7CCC1); +const SIMD_4x32 sbou = SIMD_4x32(0x6FBDC700, 0xD0D26D17, 0xC502A878, 0x15AABF7A); +const SIMD_4x32 sbot = SIMD_4x32(0x5FBB6A00, 0xCFE474A5, 0x412B35FA, 0x8E1E90D1); + +const SIMD_4x32 sboud = SIMD_4x32(0x7EF94000, 0x1387EA53, 0xD4943E2D, 0xC7AA6DB9); +const SIMD_4x32 sbotd = SIMD_4x32(0x93441D00, 0x12D7560F, 0xD8C58E9C, 0xCA4B8159); + +const SIMD_4x32 mc_forward[4] = { + SIMD_4x32(0x00030201, 0x04070605, 0x080B0A09, 0x0C0F0E0D), + SIMD_4x32(0x04070605, 0x080B0A09, 0x0C0F0E0D, 0x00030201), + SIMD_4x32(0x080B0A09, 0x0C0F0E0D, 0x00030201, 0x04070605), + SIMD_4x32(0x0C0F0E0D, 0x00030201, 0x04070605, 0x080B0A09) +}; + +const SIMD_4x32 vperm_sr[4] = { + SIMD_4x32(0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C), + SIMD_4x32(0x0F0A0500, 0x030E0904, 0x07020D08, 0x0B06010C), + SIMD_4x32(0x0B020900, 0x0F060D04, 0x030A0108, 0x070E050C), + SIMD_4x32(0x070A0D00, 0x0B0E0104, 0x0F020508, 0x0306090C), +}; + +const SIMD_4x32 rcon[10] = { + SIMD_4x32(0x00000070, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x0000002A, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x00000098, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x00000008, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x0000004D, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x0000007C, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x0000007D, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x00000081, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x0000001F, 0x00000000, 0x00000000, 0x00000000), + SIMD_4x32(0x00000083, 0x00000000, 0x00000000, 0x00000000), +}; + +const SIMD_4x32 sb2u = SIMD_4x32(0x0B712400, 0xE27A93C6, 0xBC982FCD, 0x5EB7E955); +const SIMD_4x32 sb2t = SIMD_4x32(0x0AE12900, 0x69EB8840, 0xAB82234A, 0xC2A163C8); + +const SIMD_4x32 k_dipt1 = SIMD_4x32(0x0B545F00, 0x0F505B04, 0x114E451A, 0x154A411E); +const SIMD_4x32 k_dipt2 = SIMD_4x32(0x60056500, 0x86E383E6, 0xF491F194, 0x12771772); + +const SIMD_4x32 sb9u = SIMD_4x32(0x9A86D600, 0x851C0353, 0x4F994CC9, 0xCAD51F50); +const SIMD_4x32 sb9t = SIMD_4x32(0xECD74900, 0xC03B1789, 0xB2FBA565, 0x725E2C9E); + +const SIMD_4x32 sbeu = SIMD_4x32(0x26D4D000, 0x46F29296, 0x64B4F6B0, 0x22426004); +const SIMD_4x32 sbet = SIMD_4x32(0xFFAAC100, 0x0C55A6CD, 0x98593E32, 0x9467F36B); + +const SIMD_4x32 sbdu = SIMD_4x32(0xE6B1A200, 0x7D57CCDF, 0x882A4439, 0xF56E9B13); +const SIMD_4x32 sbdt = SIMD_4x32(0x24C6CB00, 0x3CE2FAF7, 0x15DEEFD3, 0x2931180D); + +const SIMD_4x32 sbbu = SIMD_4x32(0x96B44200, 0xD0226492, 0xB0F2D404, 0x602646F6); +const SIMD_4x32 sbbt = SIMD_4x32(0xCD596700, 0xC19498A6, 0x3255AA6B, 0xF3FF0C3E); + +const SIMD_4x32 mcx[4] = { + SIMD_4x32(0x0C0F0E0D, 0x00030201, 0x04070605, 0x080B0A09), + SIMD_4x32(0x080B0A09, 0x0C0F0E0D, 0x00030201, 0x04070605), + SIMD_4x32(0x04070605, 0x080B0A09, 0x0C0F0E0D, 0x00030201), + SIMD_4x32(0x00030201, 0x04070605, 0x080B0A09, 0x0C0F0E0D), +}; + +const SIMD_4x32 mc_backward[4] = { + SIMD_4x32(0x02010003, 0x06050407, 0x0A09080B, 0x0E0D0C0F), + SIMD_4x32(0x0E0D0C0F, 0x02010003, 0x06050407, 0x0A09080B), + SIMD_4x32(0x0A09080B, 0x0E0D0C0F, 0x02010003, 0x06050407), + SIMD_4x32(0x06050407, 0x0A09080B, 0x0E0D0C0F, 0x02010003), +}; + +const SIMD_4x32 lo_nibs_mask = SIMD_4x32::splat_u8(0x0F); + +inline SIMD_4x32 low_nibs(SIMD_4x32 x) + { + return lo_nibs_mask & x; + } + +inline SIMD_4x32 high_nibs(SIMD_4x32 x) + { + return (x.shr<4>() & lo_nibs_mask); + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_enc_first_round(SIMD_4x32 B, SIMD_4x32 K) + { + return shuffle(k_ipt1, low_nibs(B)) ^ shuffle(k_ipt2, high_nibs(B)) ^ K; + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_enc_round(SIMD_4x32 B, SIMD_4x32 K, size_t r) + { + const SIMD_4x32 Bh = high_nibs(B); + SIMD_4x32 Bl = low_nibs(B); + const SIMD_4x32 t2 = shuffle(k_inv2, Bl); + Bl ^= Bh; + + const SIMD_4x32 t5 = Bl ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bh)); + const SIMD_4x32 t6 = Bh ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bl)); + + const SIMD_4x32 t7 = shuffle(sb1t, t6) ^ shuffle(sb1u, t5) ^ K; + const SIMD_4x32 t8 = shuffle(sb2t, t6) ^ shuffle(sb2u, t5) ^ shuffle(t7, mc_forward[r % 4]); + + return shuffle(t8, mc_forward[r % 4]) ^ shuffle(t7, mc_backward[r % 4]) ^ t8; + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_enc_last_round(SIMD_4x32 B, SIMD_4x32 K, size_t r) + { + const SIMD_4x32 Bh = high_nibs(B); + SIMD_4x32 Bl = low_nibs(B); + const SIMD_4x32 t2 = shuffle(k_inv2, Bl); + Bl ^= Bh; + + const SIMD_4x32 t5 = Bl ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bh)); + const SIMD_4x32 t6 = Bh ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bl)); + + return shuffle(shuffle(sbou, t5) ^ shuffle(sbot, t6) ^ K, vperm_sr[r % 4]); + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_dec_first_round(SIMD_4x32 B, SIMD_4x32 K) + { + return shuffle(k_dipt1, low_nibs(B)) ^ shuffle(k_dipt2, high_nibs(B)) ^ K; + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_dec_round(SIMD_4x32 B, SIMD_4x32 K, size_t r) + { + const SIMD_4x32 Bh = high_nibs(B); + B = low_nibs(B); + const SIMD_4x32 t2 = shuffle(k_inv2, B); + + B ^= Bh; + + const SIMD_4x32 t5 = B ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bh)); + const SIMD_4x32 t6 = Bh ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, B)); + + const SIMD_4x32 mc = mcx[(r-1)%4]; + + const SIMD_4x32 t8 = shuffle(sb9t, t6) ^ shuffle(sb9u, t5) ^ K; + const SIMD_4x32 t9 = shuffle(t8, mc) ^ shuffle(sbdu, t5) ^ shuffle(sbdt, t6); + const SIMD_4x32 t12 = shuffle(t9, mc) ^ shuffle(sbbu, t5) ^ shuffle(sbbt, t6); + return shuffle(t12, mc) ^ shuffle(sbeu, t5) ^ shuffle(sbet, t6); + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_dec_last_round(SIMD_4x32 B, SIMD_4x32 K, size_t r) + { + const uint32_t which_sr = ((((r - 1) << 4) ^ 48) & 48) / 16; + + const SIMD_4x32 Bh = high_nibs(B); + B = low_nibs(B); + const SIMD_4x32 t2 = shuffle(k_inv2, B); + + B ^= Bh; + + const SIMD_4x32 t5 = B ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bh)); + const SIMD_4x32 t6 = Bh ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, B)); + + const SIMD_4x32 x = shuffle(sboud, t5) ^ shuffle(sbotd, t6) ^ K; + return shuffle(x, vperm_sr[which_sr]); + } + +void BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) + vperm_encrypt_blocks(const uint8_t in[], uint8_t out[], size_t blocks, + const SIMD_4x32 K[], size_t rounds) + { + CT::poison(in, blocks * 16); + + const size_t blocks2 = blocks - (blocks % 2); + + for(size_t i = 0; i != blocks2; i += 2) + { + SIMD_4x32 B0 = SIMD_4x32::load_le(in + i*16); + SIMD_4x32 B1 = SIMD_4x32::load_le(in + (i+1)*16); + + B0 = aes_enc_first_round(B0, K[0]); + B1 = aes_enc_first_round(B1, K[0]); + + for(size_t r = 1; r != rounds; ++r) + { + B0 = aes_enc_round(B0, K[r], r); + B1 = aes_enc_round(B1, K[r], r); + } + + B0 = aes_enc_last_round(B0, K[rounds], rounds); + B1 = aes_enc_last_round(B1, K[rounds], rounds); + + B0.store_le(out + i*16); + B1.store_le(out + (i+1)*16); + } + + for(size_t i = blocks2; i < blocks; ++i) + { + SIMD_4x32 B = SIMD_4x32::load_le(in + i*16); // ??? + + B = aes_enc_first_round(B, K[0]); + + for(size_t r = 1; r != rounds; ++r) + { + B = aes_enc_round(B, K[r], r); + } + + B = aes_enc_last_round(B, K[rounds], rounds); + B.store_le(out + i*16); + } + + CT::unpoison(in, blocks * 16); + CT::unpoison(out, blocks * 16); + } + +void BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) + vperm_decrypt_blocks(const uint8_t in[], uint8_t out[], size_t blocks, + const SIMD_4x32 K[], size_t rounds) + { + CT::poison(in, blocks * 16); + + const size_t blocks2 = blocks - (blocks % 2); + + for(size_t i = 0; i != blocks2; i += 2) + { + SIMD_4x32 B0 = SIMD_4x32::load_le(in + i*16); + SIMD_4x32 B1 = SIMD_4x32::load_le(in + (i+1)*16); + + B0 = aes_dec_first_round(B0, K[0]); + B1 = aes_dec_first_round(B1, K[0]); + + for(size_t r = 1; r != rounds; ++r) + { + B0 = aes_dec_round(B0, K[r], r); + B1 = aes_dec_round(B1, K[r], r); + } + + B0 = aes_dec_last_round(B0, K[rounds], rounds); + B1 = aes_dec_last_round(B1, K[rounds], rounds); + + B0.store_le(out + i*16); + B1.store_le(out + (i+1)*16); + } + + for(size_t i = blocks2; i < blocks; ++i) + { + SIMD_4x32 B = SIMD_4x32::load_le(in + i*16); // ??? + + B = aes_dec_first_round(B, K[0]); + + for(size_t r = 1; r != rounds; ++r) + { + B = aes_dec_round(B, K[r], r); + } + + B = aes_dec_last_round(B, K[rounds], rounds); + B.store_le(out + i*16); + } + + CT::unpoison(in, blocks * 16); + CT::unpoison(out, blocks * 16); + } + +} + +void AES_128::vperm_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const SIMD_4x32 K[11] = { + SIMD_4x32(&m_EK[4* 0]), SIMD_4x32(&m_EK[4* 1]), SIMD_4x32(&m_EK[4* 2]), + SIMD_4x32(&m_EK[4* 3]), SIMD_4x32(&m_EK[4* 4]), SIMD_4x32(&m_EK[4* 5]), + SIMD_4x32(&m_EK[4* 6]), SIMD_4x32(&m_EK[4* 7]), SIMD_4x32(&m_EK[4* 8]), + SIMD_4x32(&m_EK[4* 9]), SIMD_4x32(&m_EK[4*10]), + }; + + return vperm_encrypt_blocks(in, out, blocks, K, 10); + } + +void AES_128::vperm_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const SIMD_4x32 K[11] = { + SIMD_4x32(&m_DK[4* 0]), SIMD_4x32(&m_DK[4* 1]), SIMD_4x32(&m_DK[4* 2]), + SIMD_4x32(&m_DK[4* 3]), SIMD_4x32(&m_DK[4* 4]), SIMD_4x32(&m_DK[4* 5]), + SIMD_4x32(&m_DK[4* 6]), SIMD_4x32(&m_DK[4* 7]), SIMD_4x32(&m_DK[4* 8]), + SIMD_4x32(&m_DK[4* 9]), SIMD_4x32(&m_DK[4*10]), + }; + + return vperm_decrypt_blocks(in, out, blocks, K, 10); + } + +void AES_192::vperm_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const SIMD_4x32 K[13] = { + SIMD_4x32(&m_EK[4* 0]), SIMD_4x32(&m_EK[4* 1]), SIMD_4x32(&m_EK[4* 2]), + SIMD_4x32(&m_EK[4* 3]), SIMD_4x32(&m_EK[4* 4]), SIMD_4x32(&m_EK[4* 5]), + SIMD_4x32(&m_EK[4* 6]), SIMD_4x32(&m_EK[4* 7]), SIMD_4x32(&m_EK[4* 8]), + SIMD_4x32(&m_EK[4* 9]), SIMD_4x32(&m_EK[4*10]), SIMD_4x32(&m_EK[4*11]), + SIMD_4x32(&m_EK[4*12]), + }; + + return vperm_encrypt_blocks(in, out, blocks, K, 12); + } + +void AES_192::vperm_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const SIMD_4x32 K[13] = { + SIMD_4x32(&m_DK[4* 0]), SIMD_4x32(&m_DK[4* 1]), SIMD_4x32(&m_DK[4* 2]), + SIMD_4x32(&m_DK[4* 3]), SIMD_4x32(&m_DK[4* 4]), SIMD_4x32(&m_DK[4* 5]), + SIMD_4x32(&m_DK[4* 6]), SIMD_4x32(&m_DK[4* 7]), SIMD_4x32(&m_DK[4* 8]), + SIMD_4x32(&m_DK[4* 9]), SIMD_4x32(&m_DK[4*10]), SIMD_4x32(&m_DK[4*11]), + SIMD_4x32(&m_DK[4*12]), + }; + + return vperm_decrypt_blocks(in, out, blocks, K, 12); + } + +void AES_256::vperm_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const SIMD_4x32 K[15] = { + SIMD_4x32(&m_EK[4* 0]), SIMD_4x32(&m_EK[4* 1]), SIMD_4x32(&m_EK[4* 2]), + SIMD_4x32(&m_EK[4* 3]), SIMD_4x32(&m_EK[4* 4]), SIMD_4x32(&m_EK[4* 5]), + SIMD_4x32(&m_EK[4* 6]), SIMD_4x32(&m_EK[4* 7]), SIMD_4x32(&m_EK[4* 8]), + SIMD_4x32(&m_EK[4* 9]), SIMD_4x32(&m_EK[4*10]), SIMD_4x32(&m_EK[4*11]), + SIMD_4x32(&m_EK[4*12]), SIMD_4x32(&m_EK[4*13]), SIMD_4x32(&m_EK[4*14]), + }; + + return vperm_encrypt_blocks(in, out, blocks, K, 14); + } + +void AES_256::vperm_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const SIMD_4x32 K[15] = { + SIMD_4x32(&m_DK[4* 0]), SIMD_4x32(&m_DK[4* 1]), SIMD_4x32(&m_DK[4* 2]), + SIMD_4x32(&m_DK[4* 3]), SIMD_4x32(&m_DK[4* 4]), SIMD_4x32(&m_DK[4* 5]), + SIMD_4x32(&m_DK[4* 6]), SIMD_4x32(&m_DK[4* 7]), SIMD_4x32(&m_DK[4* 8]), + SIMD_4x32(&m_DK[4* 9]), SIMD_4x32(&m_DK[4*10]), SIMD_4x32(&m_DK[4*11]), + SIMD_4x32(&m_DK[4*12]), SIMD_4x32(&m_DK[4*13]), SIMD_4x32(&m_DK[4*14]), + }; + + return vperm_decrypt_blocks(in, out, blocks, K, 14); + } + +namespace { + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) + aes_schedule_transform(SIMD_4x32 input, + SIMD_4x32 table_1, + SIMD_4x32 table_2) + { + return shuffle(table_1, low_nibs(input)) ^ shuffle(table_2, high_nibs(input)); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_mangle(SIMD_4x32 k, uint8_t round_no) + { + const SIMD_4x32 mc_forward0(0x00030201, 0x04070605, 0x080B0A09, 0x0C0F0E0D); + + SIMD_4x32 t = shuffle(k ^ SIMD_4x32::splat_u8(0x5B), mc_forward0); + SIMD_4x32 t2 = t; + t = shuffle(t, mc_forward0); + t2 = t ^ t2 ^ shuffle(t, mc_forward0); + return shuffle(t2, vperm_sr[round_no % 4]); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_mangle_dec(SIMD_4x32 k, uint8_t round_no) + { + const SIMD_4x32 mc_forward0(0x00030201, 0x04070605, 0x080B0A09, 0x0C0F0E0D); + + const SIMD_4x32 dsk[8] = { + SIMD_4x32(0x7ED9A700, 0xB6116FC8, 0x82255BFC, 0x4AED9334), + SIMD_4x32(0x27143300, 0x45765162, 0xE9DAFDCE, 0x8BB89FAC), + SIMD_4x32(0xCCA86400, 0x27438FEB, 0xADC90561, 0x4622EE8A), + SIMD_4x32(0x4F92DD00, 0x815C13CE, 0xBD602FF2, 0x73AEE13C), + SIMD_4x32(0x01C6C700, 0x03C4C502, 0xFA3D3CFB, 0xF83F3EF9), + SIMD_4x32(0x38CFF700, 0xEE1921D6, 0x7384BC4B, 0xA5526A9D), + SIMD_4x32(0x53732000, 0xE3C390B0, 0x10306343, 0xA080D3F3), + SIMD_4x32(0x036982E8, 0xA0CA214B, 0x8CE60D67, 0x2F45AEC4), + }; + + SIMD_4x32 t = aes_schedule_transform(k, dsk[0], dsk[1]); + SIMD_4x32 output = shuffle(t, mc_forward0); + + t = aes_schedule_transform(t, dsk[2], dsk[3]); + output = shuffle(t ^ output, mc_forward0); + + t = aes_schedule_transform(t, dsk[4], dsk[5]); + output = shuffle(t ^ output, mc_forward0); + + t = aes_schedule_transform(t, dsk[6], dsk[7]); + output = shuffle(t ^ output, mc_forward0); + + return shuffle(output, vperm_sr[round_no % 4]); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_mangle_last(SIMD_4x32 k, uint8_t round_no) + { + const SIMD_4x32 out_tr1(0xD6B66000, 0xFF9F4929, 0xDEBE6808, 0xF7974121); + const SIMD_4x32 out_tr2(0x50BCEC00, 0x01EDBD51, 0xB05C0CE0, 0xE10D5DB1); + + k = shuffle(k, vperm_sr[round_no % 4]); + k ^= SIMD_4x32::splat_u8(0x5B); + return aes_schedule_transform(k, out_tr1, out_tr2); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_mangle_last_dec(SIMD_4x32 k) + { + const SIMD_4x32 deskew1(0x47A4E300, 0x07E4A340, 0x5DBEF91A, 0x1DFEB95A); + const SIMD_4x32 deskew2(0x83EA6900, 0x5F36B5DC, 0xF49D1E77, 0x2841C2AB); + + k ^= SIMD_4x32::splat_u8(0x5B); + return aes_schedule_transform(k, deskew1, deskew2); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_round(SIMD_4x32 input1, SIMD_4x32 input2) + { + SIMD_4x32 smeared = input2 ^ input2.shift_elems_left<1>(); + smeared ^= smeared.shift_elems_left<2>(); + smeared ^= SIMD_4x32::splat_u8(0x5B); + + const SIMD_4x32 Bh = high_nibs(input1); + SIMD_4x32 Bl = low_nibs(input1); + + const SIMD_4x32 t2 = shuffle(k_inv2, Bl); + + Bl ^= Bh; + + SIMD_4x32 t5 = Bl ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bh)); + SIMD_4x32 t6 = Bh ^ shuffle(k_inv1, t2 ^ shuffle(k_inv1, Bl)); + + return smeared ^ shuffle(sb1u, t5) ^ shuffle(sb1t, t6); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_round(SIMD_4x32 rc, SIMD_4x32 input1, SIMD_4x32 input2) + { + // This byte shuffle is equivalent to alignr<1>(shuffle32(input1, (3,3,3,3))); + const SIMD_4x32 shuffle3333_15 = SIMD_4x32::splat(0x0C0F0E0D); + return aes_schedule_round(shuffle(input1, shuffle3333_15), input2 ^ rc); + } + +SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) aes_schedule_192_smear(SIMD_4x32 x, SIMD_4x32 y) + { + const SIMD_4x32 shuffle3332 = + SIMD_4x32(0x0B0A0908, 0x0F0E0D0C, 0x0F0E0D0C, 0x0F0E0D0C); + const SIMD_4x32 shuffle2000 = + SIMD_4x32(0x03020100, 0x03020100, 0x03020100, 0x0B0A0908); + + const SIMD_4x32 zero_top_half(0, 0, 0xFFFFFFFF, 0xFFFFFFFF); + y &= zero_top_half; + return y ^ shuffle(x, shuffle3332) ^ shuffle(y, shuffle2000); + } + +} + +void AES_128::vperm_key_schedule(const uint8_t keyb[], size_t) + { + m_EK.resize(11*4); + m_DK.resize(11*4); + + SIMD_4x32 key = SIMD_4x32::load_le(keyb); + + shuffle(key, vperm_sr[2]).store_le(&m_DK[4*10]); + + key = aes_schedule_transform(key, k_ipt1, k_ipt2); + key.store_le(&m_EK[0]); + + for(size_t i = 1; i != 10; ++i) + { + key = aes_schedule_round(rcon[i-1], key, key); + + aes_schedule_mangle(key, (12-i) % 4).store_le(&m_EK[4*i]); + + aes_schedule_mangle_dec(key, (10-i)%4).store_le(&m_DK[4*(10-i)]); + } + + key = aes_schedule_round(rcon[9], key, key); + aes_schedule_mangle_last(key, 2).store_le(&m_EK[4*10]); + aes_schedule_mangle_last_dec(key).store_le(&m_DK[0]); + } + +void AES_192::vperm_key_schedule(const uint8_t keyb[], size_t) + { + m_EK.resize(13*4); + m_DK.resize(13*4); + + SIMD_4x32 key1 = SIMD_4x32::load_le(keyb); + SIMD_4x32 key2 = SIMD_4x32::load_le(keyb + 8); + + shuffle(key1, vperm_sr[0]).store_le(&m_DK[12*4]); + + key1 = aes_schedule_transform(key1, k_ipt1, k_ipt2); + key2 = aes_schedule_transform(key2, k_ipt1, k_ipt2); + + key1.store_le(&m_EK[0]); + + for(size_t i = 0; i != 4; ++i) + { + // key2 with 8 high bytes masked off + SIMD_4x32 t = key2; + key2 = aes_schedule_round(rcon[2*i], key2, key1); + const SIMD_4x32 key2t = alignr8(key2, t); + aes_schedule_mangle(key2t, (i+3)%4).store_le(&m_EK[4*(3*i+1)]); + aes_schedule_mangle_dec(key2t, (i+3)%4).store_le(&m_DK[4*(11-3*i)]); + + t = aes_schedule_192_smear(key2, t); + + aes_schedule_mangle(t, (i+2)%4).store_le(&m_EK[4*(3*i+2)]); + aes_schedule_mangle_dec(t, (i+2)%4).store_le(&m_DK[4*(10-3*i)]); + + key2 = aes_schedule_round(rcon[2*i+1], t, key2); + + if(i == 3) + { + aes_schedule_mangle_last(key2, (i+1)%4).store_le(&m_EK[4*(3*i+3)]); + aes_schedule_mangle_last_dec(key2).store_le(&m_DK[4*(9-3*i)]); + } + else + { + aes_schedule_mangle(key2, (i+1)%4).store_le(&m_EK[4*(3*i+3)]); + aes_schedule_mangle_dec(key2, (i+1)%4).store_le(&m_DK[4*(9-3*i)]); + } + + key1 = key2; + key2 = aes_schedule_192_smear(key2, t); + } + } + +void AES_256::vperm_key_schedule(const uint8_t keyb[], size_t) + { + m_EK.resize(15*4); + m_DK.resize(15*4); + + SIMD_4x32 key1 = SIMD_4x32::load_le(keyb); + SIMD_4x32 key2 = SIMD_4x32::load_le(keyb + 16); + + shuffle(key1, vperm_sr[2]).store_le(&m_DK[4*14]); + + key1 = aes_schedule_transform(key1, k_ipt1, k_ipt2); + key2 = aes_schedule_transform(key2, k_ipt1, k_ipt2); + + key1.store_le(&m_EK[0]); + aes_schedule_mangle(key2, 3).store_le(&m_EK[4]); + + aes_schedule_mangle_dec(key2, 1).store_le(&m_DK[4*13]); + + const SIMD_4x32 shuffle3333 = SIMD_4x32::splat(0x0F0E0D0C); + + for(size_t i = 2; i != 14; i += 2) + { + const SIMD_4x32 k_t = key2; + key1 = key2 = aes_schedule_round(rcon[(i/2)-1], key2, key1); + + aes_schedule_mangle(key2, i % 4).store_le(&m_EK[4*i]); + aes_schedule_mangle_dec(key2, (i+2)%4).store_le(&m_DK[4*(14-i)]); + + key2 = aes_schedule_round(shuffle(key2, shuffle3333), k_t); + + aes_schedule_mangle(key2, (i-1)%4).store_le(&m_EK[4*(i+1)]); + aes_schedule_mangle_dec(key2, (i+1)%4).store_le(&m_DK[4*(13-i)]); + } + + key2 = aes_schedule_round(rcon[6], key2, key1); + + aes_schedule_mangle_last(key2, 2).store_le(&m_EK[4*14]); + aes_schedule_mangle_last_dec(key2).store_le(&m_DK[0]); + } + +} diff --git a/comm/third_party/botan/src/lib/block/aes/aes_vperm/info.txt b/comm/third_party/botan/src/lib/block/aes/aes_vperm/info.txt new file mode 100644 index 0000000000..0b7eabaace --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/aes_vperm/info.txt @@ -0,0 +1,36 @@ + +AES_VPERM -> 20190901 + + +endian little + + +x86_32:sse2 +x86_64:sse2 +x86_32:ssse3 +x86_64:ssse3 +arm32:neon +arm64:neon +ppc32:altivec +ppc64:altivec + + + +x86_32 +x86_64 +arm32 +arm64 +ppc32 +ppc64 + + + +simd + + + +gcc +clang +msvc:19.10 # VC 2017 +sunstudio + diff --git a/comm/third_party/botan/src/lib/block/aes/info.txt b/comm/third_party/botan/src/lib/block/aes/info.txt new file mode 100644 index 0000000000..62455cf2c3 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aes/info.txt @@ -0,0 +1,3 @@ + +AES -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/aria/aria.cpp b/comm/third_party/botan/src/lib/block/aria/aria.cpp new file mode 100644 index 0000000000..79105a88c4 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aria/aria.cpp @@ -0,0 +1,506 @@ +/* +* ARIA +* Adapted for Botan by Jeffrey Walton, public domain +* +* Further changes +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +* +* This ARIA implementation is based on the 32-bit implementation by Aaram Yun from the +* National Security Research Institute, KOREA. Aaram Yun's implementation is based on +* the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from +* the Korea Internet & Security Agency website. +* RFC 5794, A Description of the ARIA Encryption Algorithm, +* Korea +* Internet & Security Agency homepage +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +namespace ARIA_F { + +alignas(64) +const uint32_t S1[256]={ + 0x00636363,0x007c7c7c,0x00777777,0x007b7b7b,0x00f2f2f2,0x006b6b6b,0x006f6f6f,0x00c5c5c5, + 0x00303030,0x00010101,0x00676767,0x002b2b2b,0x00fefefe,0x00d7d7d7,0x00ababab,0x00767676, + 0x00cacaca,0x00828282,0x00c9c9c9,0x007d7d7d,0x00fafafa,0x00595959,0x00474747,0x00f0f0f0, + 0x00adadad,0x00d4d4d4,0x00a2a2a2,0x00afafaf,0x009c9c9c,0x00a4a4a4,0x00727272,0x00c0c0c0, + 0x00b7b7b7,0x00fdfdfd,0x00939393,0x00262626,0x00363636,0x003f3f3f,0x00f7f7f7,0x00cccccc, + 0x00343434,0x00a5a5a5,0x00e5e5e5,0x00f1f1f1,0x00717171,0x00d8d8d8,0x00313131,0x00151515, + 0x00040404,0x00c7c7c7,0x00232323,0x00c3c3c3,0x00181818,0x00969696,0x00050505,0x009a9a9a, + 0x00070707,0x00121212,0x00808080,0x00e2e2e2,0x00ebebeb,0x00272727,0x00b2b2b2,0x00757575, + 0x00090909,0x00838383,0x002c2c2c,0x001a1a1a,0x001b1b1b,0x006e6e6e,0x005a5a5a,0x00a0a0a0, + 0x00525252,0x003b3b3b,0x00d6d6d6,0x00b3b3b3,0x00292929,0x00e3e3e3,0x002f2f2f,0x00848484, + 0x00535353,0x00d1d1d1,0x00000000,0x00ededed,0x00202020,0x00fcfcfc,0x00b1b1b1,0x005b5b5b, + 0x006a6a6a,0x00cbcbcb,0x00bebebe,0x00393939,0x004a4a4a,0x004c4c4c,0x00585858,0x00cfcfcf, + 0x00d0d0d0,0x00efefef,0x00aaaaaa,0x00fbfbfb,0x00434343,0x004d4d4d,0x00333333,0x00858585, + 0x00454545,0x00f9f9f9,0x00020202,0x007f7f7f,0x00505050,0x003c3c3c,0x009f9f9f,0x00a8a8a8, + 0x00515151,0x00a3a3a3,0x00404040,0x008f8f8f,0x00929292,0x009d9d9d,0x00383838,0x00f5f5f5, + 0x00bcbcbc,0x00b6b6b6,0x00dadada,0x00212121,0x00101010,0x00ffffff,0x00f3f3f3,0x00d2d2d2, + 0x00cdcdcd,0x000c0c0c,0x00131313,0x00ececec,0x005f5f5f,0x00979797,0x00444444,0x00171717, + 0x00c4c4c4,0x00a7a7a7,0x007e7e7e,0x003d3d3d,0x00646464,0x005d5d5d,0x00191919,0x00737373, + 0x00606060,0x00818181,0x004f4f4f,0x00dcdcdc,0x00222222,0x002a2a2a,0x00909090,0x00888888, + 0x00464646,0x00eeeeee,0x00b8b8b8,0x00141414,0x00dedede,0x005e5e5e,0x000b0b0b,0x00dbdbdb, + 0x00e0e0e0,0x00323232,0x003a3a3a,0x000a0a0a,0x00494949,0x00060606,0x00242424,0x005c5c5c, + 0x00c2c2c2,0x00d3d3d3,0x00acacac,0x00626262,0x00919191,0x00959595,0x00e4e4e4,0x00797979, + 0x00e7e7e7,0x00c8c8c8,0x00373737,0x006d6d6d,0x008d8d8d,0x00d5d5d5,0x004e4e4e,0x00a9a9a9, + 0x006c6c6c,0x00565656,0x00f4f4f4,0x00eaeaea,0x00656565,0x007a7a7a,0x00aeaeae,0x00080808, + 0x00bababa,0x00787878,0x00252525,0x002e2e2e,0x001c1c1c,0x00a6a6a6,0x00b4b4b4,0x00c6c6c6, + 0x00e8e8e8,0x00dddddd,0x00747474,0x001f1f1f,0x004b4b4b,0x00bdbdbd,0x008b8b8b,0x008a8a8a, + 0x00707070,0x003e3e3e,0x00b5b5b5,0x00666666,0x00484848,0x00030303,0x00f6f6f6,0x000e0e0e, + 0x00616161,0x00353535,0x00575757,0x00b9b9b9,0x00868686,0x00c1c1c1,0x001d1d1d,0x009e9e9e, + 0x00e1e1e1,0x00f8f8f8,0x00989898,0x00111111,0x00696969,0x00d9d9d9,0x008e8e8e,0x00949494, + 0x009b9b9b,0x001e1e1e,0x00878787,0x00e9e9e9,0x00cecece,0x00555555,0x00282828,0x00dfdfdf, + 0x008c8c8c,0x00a1a1a1,0x00898989,0x000d0d0d,0x00bfbfbf,0x00e6e6e6,0x00424242,0x00686868, + 0x00414141,0x00999999,0x002d2d2d,0x000f0f0f,0x00b0b0b0,0x00545454,0x00bbbbbb,0x00161616 +}; + +alignas(64) +const uint32_t S2[256]={ + 0xe200e2e2,0x4e004e4e,0x54005454,0xfc00fcfc,0x94009494,0xc200c2c2,0x4a004a4a,0xcc00cccc, + 0x62006262,0x0d000d0d,0x6a006a6a,0x46004646,0x3c003c3c,0x4d004d4d,0x8b008b8b,0xd100d1d1, + 0x5e005e5e,0xfa00fafa,0x64006464,0xcb00cbcb,0xb400b4b4,0x97009797,0xbe00bebe,0x2b002b2b, + 0xbc00bcbc,0x77007777,0x2e002e2e,0x03000303,0xd300d3d3,0x19001919,0x59005959,0xc100c1c1, + 0x1d001d1d,0x06000606,0x41004141,0x6b006b6b,0x55005555,0xf000f0f0,0x99009999,0x69006969, + 0xea00eaea,0x9c009c9c,0x18001818,0xae00aeae,0x63006363,0xdf00dfdf,0xe700e7e7,0xbb00bbbb, + 0x00000000,0x73007373,0x66006666,0xfb00fbfb,0x96009696,0x4c004c4c,0x85008585,0xe400e4e4, + 0x3a003a3a,0x09000909,0x45004545,0xaa00aaaa,0x0f000f0f,0xee00eeee,0x10001010,0xeb00ebeb, + 0x2d002d2d,0x7f007f7f,0xf400f4f4,0x29002929,0xac00acac,0xcf00cfcf,0xad00adad,0x91009191, + 0x8d008d8d,0x78007878,0xc800c8c8,0x95009595,0xf900f9f9,0x2f002f2f,0xce00cece,0xcd00cdcd, + 0x08000808,0x7a007a7a,0x88008888,0x38003838,0x5c005c5c,0x83008383,0x2a002a2a,0x28002828, + 0x47004747,0xdb00dbdb,0xb800b8b8,0xc700c7c7,0x93009393,0xa400a4a4,0x12001212,0x53005353, + 0xff00ffff,0x87008787,0x0e000e0e,0x31003131,0x36003636,0x21002121,0x58005858,0x48004848, + 0x01000101,0x8e008e8e,0x37003737,0x74007474,0x32003232,0xca00caca,0xe900e9e9,0xb100b1b1, + 0xb700b7b7,0xab00abab,0x0c000c0c,0xd700d7d7,0xc400c4c4,0x56005656,0x42004242,0x26002626, + 0x07000707,0x98009898,0x60006060,0xd900d9d9,0xb600b6b6,0xb900b9b9,0x11001111,0x40004040, + 0xec00ecec,0x20002020,0x8c008c8c,0xbd00bdbd,0xa000a0a0,0xc900c9c9,0x84008484,0x04000404, + 0x49004949,0x23002323,0xf100f1f1,0x4f004f4f,0x50005050,0x1f001f1f,0x13001313,0xdc00dcdc, + 0xd800d8d8,0xc000c0c0,0x9e009e9e,0x57005757,0xe300e3e3,0xc300c3c3,0x7b007b7b,0x65006565, + 0x3b003b3b,0x02000202,0x8f008f8f,0x3e003e3e,0xe800e8e8,0x25002525,0x92009292,0xe500e5e5, + 0x15001515,0xdd00dddd,0xfd00fdfd,0x17001717,0xa900a9a9,0xbf00bfbf,0xd400d4d4,0x9a009a9a, + 0x7e007e7e,0xc500c5c5,0x39003939,0x67006767,0xfe00fefe,0x76007676,0x9d009d9d,0x43004343, + 0xa700a7a7,0xe100e1e1,0xd000d0d0,0xf500f5f5,0x68006868,0xf200f2f2,0x1b001b1b,0x34003434, + 0x70007070,0x05000505,0xa300a3a3,0x8a008a8a,0xd500d5d5,0x79007979,0x86008686,0xa800a8a8, + 0x30003030,0xc600c6c6,0x51005151,0x4b004b4b,0x1e001e1e,0xa600a6a6,0x27002727,0xf600f6f6, + 0x35003535,0xd200d2d2,0x6e006e6e,0x24002424,0x16001616,0x82008282,0x5f005f5f,0xda00dada, + 0xe600e6e6,0x75007575,0xa200a2a2,0xef00efef,0x2c002c2c,0xb200b2b2,0x1c001c1c,0x9f009f9f, + 0x5d005d5d,0x6f006f6f,0x80008080,0x0a000a0a,0x72007272,0x44004444,0x9b009b9b,0x6c006c6c, + 0x90009090,0x0b000b0b,0x5b005b5b,0x33003333,0x7d007d7d,0x5a005a5a,0x52005252,0xf300f3f3, + 0x61006161,0xa100a1a1,0xf700f7f7,0xb000b0b0,0xd600d6d6,0x3f003f3f,0x7c007c7c,0x6d006d6d, + 0xed00eded,0x14001414,0xe000e0e0,0xa500a5a5,0x3d003d3d,0x22002222,0xb300b3b3,0xf800f8f8, + 0x89008989,0xde00dede,0x71007171,0x1a001a1a,0xaf00afaf,0xba00baba,0xb500b5b5,0x81008181 +}; + +alignas(64) +const uint32_t X1[256]={ + 0x52520052,0x09090009,0x6a6a006a,0xd5d500d5,0x30300030,0x36360036,0xa5a500a5,0x38380038, + 0xbfbf00bf,0x40400040,0xa3a300a3,0x9e9e009e,0x81810081,0xf3f300f3,0xd7d700d7,0xfbfb00fb, + 0x7c7c007c,0xe3e300e3,0x39390039,0x82820082,0x9b9b009b,0x2f2f002f,0xffff00ff,0x87870087, + 0x34340034,0x8e8e008e,0x43430043,0x44440044,0xc4c400c4,0xdede00de,0xe9e900e9,0xcbcb00cb, + 0x54540054,0x7b7b007b,0x94940094,0x32320032,0xa6a600a6,0xc2c200c2,0x23230023,0x3d3d003d, + 0xeeee00ee,0x4c4c004c,0x95950095,0x0b0b000b,0x42420042,0xfafa00fa,0xc3c300c3,0x4e4e004e, + 0x08080008,0x2e2e002e,0xa1a100a1,0x66660066,0x28280028,0xd9d900d9,0x24240024,0xb2b200b2, + 0x76760076,0x5b5b005b,0xa2a200a2,0x49490049,0x6d6d006d,0x8b8b008b,0xd1d100d1,0x25250025, + 0x72720072,0xf8f800f8,0xf6f600f6,0x64640064,0x86860086,0x68680068,0x98980098,0x16160016, + 0xd4d400d4,0xa4a400a4,0x5c5c005c,0xcccc00cc,0x5d5d005d,0x65650065,0xb6b600b6,0x92920092, + 0x6c6c006c,0x70700070,0x48480048,0x50500050,0xfdfd00fd,0xeded00ed,0xb9b900b9,0xdada00da, + 0x5e5e005e,0x15150015,0x46460046,0x57570057,0xa7a700a7,0x8d8d008d,0x9d9d009d,0x84840084, + 0x90900090,0xd8d800d8,0xabab00ab,0x00000000,0x8c8c008c,0xbcbc00bc,0xd3d300d3,0x0a0a000a, + 0xf7f700f7,0xe4e400e4,0x58580058,0x05050005,0xb8b800b8,0xb3b300b3,0x45450045,0x06060006, + 0xd0d000d0,0x2c2c002c,0x1e1e001e,0x8f8f008f,0xcaca00ca,0x3f3f003f,0x0f0f000f,0x02020002, + 0xc1c100c1,0xafaf00af,0xbdbd00bd,0x03030003,0x01010001,0x13130013,0x8a8a008a,0x6b6b006b, + 0x3a3a003a,0x91910091,0x11110011,0x41410041,0x4f4f004f,0x67670067,0xdcdc00dc,0xeaea00ea, + 0x97970097,0xf2f200f2,0xcfcf00cf,0xcece00ce,0xf0f000f0,0xb4b400b4,0xe6e600e6,0x73730073, + 0x96960096,0xacac00ac,0x74740074,0x22220022,0xe7e700e7,0xadad00ad,0x35350035,0x85850085, + 0xe2e200e2,0xf9f900f9,0x37370037,0xe8e800e8,0x1c1c001c,0x75750075,0xdfdf00df,0x6e6e006e, + 0x47470047,0xf1f100f1,0x1a1a001a,0x71710071,0x1d1d001d,0x29290029,0xc5c500c5,0x89890089, + 0x6f6f006f,0xb7b700b7,0x62620062,0x0e0e000e,0xaaaa00aa,0x18180018,0xbebe00be,0x1b1b001b, + 0xfcfc00fc,0x56560056,0x3e3e003e,0x4b4b004b,0xc6c600c6,0xd2d200d2,0x79790079,0x20200020, + 0x9a9a009a,0xdbdb00db,0xc0c000c0,0xfefe00fe,0x78780078,0xcdcd00cd,0x5a5a005a,0xf4f400f4, + 0x1f1f001f,0xdddd00dd,0xa8a800a8,0x33330033,0x88880088,0x07070007,0xc7c700c7,0x31310031, + 0xb1b100b1,0x12120012,0x10100010,0x59590059,0x27270027,0x80800080,0xecec00ec,0x5f5f005f, + 0x60600060,0x51510051,0x7f7f007f,0xa9a900a9,0x19190019,0xb5b500b5,0x4a4a004a,0x0d0d000d, + 0x2d2d002d,0xe5e500e5,0x7a7a007a,0x9f9f009f,0x93930093,0xc9c900c9,0x9c9c009c,0xefef00ef, + 0xa0a000a0,0xe0e000e0,0x3b3b003b,0x4d4d004d,0xaeae00ae,0x2a2a002a,0xf5f500f5,0xb0b000b0, + 0xc8c800c8,0xebeb00eb,0xbbbb00bb,0x3c3c003c,0x83830083,0x53530053,0x99990099,0x61610061, + 0x17170017,0x2b2b002b,0x04040004,0x7e7e007e,0xbaba00ba,0x77770077,0xd6d600d6,0x26260026, + 0xe1e100e1,0x69690069,0x14140014,0x63630063,0x55550055,0x21210021,0x0c0c000c,0x7d7d007d +}; + +alignas(64) +const uint32_t X2[256]={ + 0x30303000,0x68686800,0x99999900,0x1b1b1b00,0x87878700,0xb9b9b900,0x21212100,0x78787800, + 0x50505000,0x39393900,0xdbdbdb00,0xe1e1e100,0x72727200,0x09090900,0x62626200,0x3c3c3c00, + 0x3e3e3e00,0x7e7e7e00,0x5e5e5e00,0x8e8e8e00,0xf1f1f100,0xa0a0a000,0xcccccc00,0xa3a3a300, + 0x2a2a2a00,0x1d1d1d00,0xfbfbfb00,0xb6b6b600,0xd6d6d600,0x20202000,0xc4c4c400,0x8d8d8d00, + 0x81818100,0x65656500,0xf5f5f500,0x89898900,0xcbcbcb00,0x9d9d9d00,0x77777700,0xc6c6c600, + 0x57575700,0x43434300,0x56565600,0x17171700,0xd4d4d400,0x40404000,0x1a1a1a00,0x4d4d4d00, + 0xc0c0c000,0x63636300,0x6c6c6c00,0xe3e3e300,0xb7b7b700,0xc8c8c800,0x64646400,0x6a6a6a00, + 0x53535300,0xaaaaaa00,0x38383800,0x98989800,0x0c0c0c00,0xf4f4f400,0x9b9b9b00,0xededed00, + 0x7f7f7f00,0x22222200,0x76767600,0xafafaf00,0xdddddd00,0x3a3a3a00,0x0b0b0b00,0x58585800, + 0x67676700,0x88888800,0x06060600,0xc3c3c300,0x35353500,0x0d0d0d00,0x01010100,0x8b8b8b00, + 0x8c8c8c00,0xc2c2c200,0xe6e6e600,0x5f5f5f00,0x02020200,0x24242400,0x75757500,0x93939300, + 0x66666600,0x1e1e1e00,0xe5e5e500,0xe2e2e200,0x54545400,0xd8d8d800,0x10101000,0xcecece00, + 0x7a7a7a00,0xe8e8e800,0x08080800,0x2c2c2c00,0x12121200,0x97979700,0x32323200,0xababab00, + 0xb4b4b400,0x27272700,0x0a0a0a00,0x23232300,0xdfdfdf00,0xefefef00,0xcacaca00,0xd9d9d900, + 0xb8b8b800,0xfafafa00,0xdcdcdc00,0x31313100,0x6b6b6b00,0xd1d1d100,0xadadad00,0x19191900, + 0x49494900,0xbdbdbd00,0x51515100,0x96969600,0xeeeeee00,0xe4e4e400,0xa8a8a800,0x41414100, + 0xdadada00,0xffffff00,0xcdcdcd00,0x55555500,0x86868600,0x36363600,0xbebebe00,0x61616100, + 0x52525200,0xf8f8f800,0xbbbbbb00,0x0e0e0e00,0x82828200,0x48484800,0x69696900,0x9a9a9a00, + 0xe0e0e000,0x47474700,0x9e9e9e00,0x5c5c5c00,0x04040400,0x4b4b4b00,0x34343400,0x15151500, + 0x79797900,0x26262600,0xa7a7a700,0xdedede00,0x29292900,0xaeaeae00,0x92929200,0xd7d7d700, + 0x84848400,0xe9e9e900,0xd2d2d200,0xbababa00,0x5d5d5d00,0xf3f3f300,0xc5c5c500,0xb0b0b000, + 0xbfbfbf00,0xa4a4a400,0x3b3b3b00,0x71717100,0x44444400,0x46464600,0x2b2b2b00,0xfcfcfc00, + 0xebebeb00,0x6f6f6f00,0xd5d5d500,0xf6f6f600,0x14141400,0xfefefe00,0x7c7c7c00,0x70707000, + 0x5a5a5a00,0x7d7d7d00,0xfdfdfd00,0x2f2f2f00,0x18181800,0x83838300,0x16161600,0xa5a5a500, + 0x91919100,0x1f1f1f00,0x05050500,0x95959500,0x74747400,0xa9a9a900,0xc1c1c100,0x5b5b5b00, + 0x4a4a4a00,0x85858500,0x6d6d6d00,0x13131300,0x07070700,0x4f4f4f00,0x4e4e4e00,0x45454500, + 0xb2b2b200,0x0f0f0f00,0xc9c9c900,0x1c1c1c00,0xa6a6a600,0xbcbcbc00,0xececec00,0x73737300, + 0x90909000,0x7b7b7b00,0xcfcfcf00,0x59595900,0x8f8f8f00,0xa1a1a100,0xf9f9f900,0x2d2d2d00, + 0xf2f2f200,0xb1b1b100,0x00000000,0x94949400,0x37373700,0x9f9f9f00,0xd0d0d000,0x2e2e2e00, + 0x9c9c9c00,0x6e6e6e00,0x28282800,0x3f3f3f00,0x80808000,0xf0f0f000,0x3d3d3d00,0xd3d3d300, + 0x25252500,0x8a8a8a00,0xb5b5b500,0xe7e7e700,0x42424200,0xb3b3b300,0xc7c7c700,0xeaeaea00, + 0xf7f7f700,0x4c4c4c00,0x11111100,0x33333300,0x03030300,0xa2a2a200,0xacacac00,0x60606000 +}; + +inline void ARIA_FO(uint32_t& T0, uint32_t& T1, uint32_t& T2, uint32_t& T3) + { + T0 = S1[get_byte(0,T0)] ^ S2[get_byte(1,T0)] ^ X1[get_byte(2,T0)] ^ X2[get_byte(3,T0)]; + T1 = S1[get_byte(0,T1)] ^ S2[get_byte(1,T1)] ^ X1[get_byte(2,T1)] ^ X2[get_byte(3,T1)]; + T2 = S1[get_byte(0,T2)] ^ S2[get_byte(1,T2)] ^ X1[get_byte(2,T2)] ^ X2[get_byte(3,T2)]; + T3 = S1[get_byte(0,T3)] ^ S2[get_byte(1,T3)] ^ X1[get_byte(2,T3)] ^ X2[get_byte(3,T3)]; + + T1 ^= T2; + T2 ^= T3; T0 ^= T1; + T3 ^= T1; T2 ^= T0; + T1 ^= T2; + + T1 = ((T1 << 8) & 0xFF00FF00) | ((T1 >> 8) & 0x00FF00FF); + T2 = rotr<16>(T2); + T3 = reverse_bytes(T3); + + T1 ^= T2; + T2 ^= T3; T0 ^= T1; + T3 ^= T1; T2 ^= T0; + T1 ^= T2; + } + +inline void ARIA_FE(uint32_t& T0, uint32_t& T1, uint32_t& T2, uint32_t& T3) + { + T0 = X1[get_byte(0,T0)] ^ X2[get_byte(1,T0)] ^ S1[get_byte(2,T0)] ^ S2[get_byte(3,T0)]; + T1 = X1[get_byte(0,T1)] ^ X2[get_byte(1,T1)] ^ S1[get_byte(2,T1)] ^ S2[get_byte(3,T1)]; + T2 = X1[get_byte(0,T2)] ^ X2[get_byte(1,T2)] ^ S1[get_byte(2,T2)] ^ S2[get_byte(3,T2)]; + T3 = X1[get_byte(0,T3)] ^ X2[get_byte(1,T3)] ^ S1[get_byte(2,T3)] ^ S2[get_byte(3,T3)]; + + T1 ^= T2; + T2 ^= T3; T0 ^= T1; + T3 ^= T1; T2 ^= T0; + T1 ^= T2; + + T3 = ((T3 << 8) & 0xFF00FF00) | ((T3 >> 8) & 0x00FF00FF); + T0 = rotr<16>(T0); + T1 = reverse_bytes(T1); + + T1 ^= T2; + T2 ^= T3; T0 ^= T1; + T3 ^= T1; T2 ^= T0; + T1 ^= T2; + } + +/* +* ARIA encryption and decryption +*/ +void transform(const uint8_t in[], uint8_t out[], size_t blocks, + const secure_vector& KS) + { + /* + * Hit every cache line of S1, S2, X1, X2 + * + * The initializer of Z ensures Z == 0xFFFFFFFF for any cache line + * size that is a power of 2 and <= 512 + */ + const size_t cache_line_size = CPUID::cache_line_size(); + + volatile uint32_t Z = 0x11101010; + for(size_t i = 0; i < 256; i += cache_line_size / sizeof(uint32_t)) + { + Z |= S1[i] | S2[i] | X1[i] | X2[i]; + } + + const size_t ROUNDS = (KS.size() / 4) - 1; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t t0, t1, t2, t3; + load_be(in + 16*i, t0, t1, t2, t3); + + t0 &= Z; + + for(size_t r = 0; r < ROUNDS; r += 2) + { + t0 ^= KS[4*r]; + t1 ^= KS[4*r+1]; + t2 ^= KS[4*r+2]; + t3 ^= KS[4*r+3]; + ARIA_FO(t0,t1,t2,t3); + + t0 ^= KS[4*r+4]; + t1 ^= KS[4*r+5]; + t2 ^= KS[4*r+6]; + t3 ^= KS[4*r+7]; + + if(r != ROUNDS-2) + ARIA_FE(t0,t1,t2,t3); + } + + out[16*i+ 0] = static_cast(X1[get_byte(0,t0)] ) ^ get_byte(0, KS[4*ROUNDS]); + out[16*i+ 1] = static_cast(X2[get_byte(1,t0)]>>8) ^ get_byte(1, KS[4*ROUNDS]); + out[16*i+ 2] = static_cast(S1[get_byte(2,t0)] ) ^ get_byte(2, KS[4*ROUNDS]); + out[16*i+ 3] = static_cast(S2[get_byte(3,t0)] ) ^ get_byte(3, KS[4*ROUNDS]); + out[16*i+ 4] = static_cast(X1[get_byte(0,t1)] ) ^ get_byte(0, KS[4*ROUNDS+1]); + out[16*i+ 5] = static_cast(X2[get_byte(1,t1)]>>8) ^ get_byte(1, KS[4*ROUNDS+1]); + out[16*i+ 6] = static_cast(S1[get_byte(2,t1)] ) ^ get_byte(2, KS[4*ROUNDS+1]); + out[16*i+ 7] = static_cast(S2[get_byte(3,t1)] ) ^ get_byte(3, KS[4*ROUNDS+1]); + out[16*i+ 8] = static_cast(X1[get_byte(0,t2)] ) ^ get_byte(0, KS[4*ROUNDS+2]); + out[16*i+ 9] = static_cast(X2[get_byte(1,t2)]>>8) ^ get_byte(1, KS[4*ROUNDS+2]); + out[16*i+10] = static_cast(S1[get_byte(2,t2)] ) ^ get_byte(2, KS[4*ROUNDS+2]); + out[16*i+11] = static_cast(S2[get_byte(3,t2)] ) ^ get_byte(3, KS[4*ROUNDS+2]); + out[16*i+12] = static_cast(X1[get_byte(0,t3)] ) ^ get_byte(0, KS[4*ROUNDS+3]); + out[16*i+13] = static_cast(X2[get_byte(1,t3)]>>8) ^ get_byte(1, KS[4*ROUNDS+3]); + out[16*i+14] = static_cast(S1[get_byte(2,t3)] ) ^ get_byte(2, KS[4*ROUNDS+3]); + out[16*i+15] = static_cast(S2[get_byte(3,t3)] ) ^ get_byte(3, KS[4*ROUNDS+3]); + } + } + +// n-bit right shift of Y XORed to X +template +inline void ARIA_ROL128(const uint32_t X[4], const uint32_t Y[4], uint32_t KS[4]) + { + // MSVC is not generating a "rotate immediate". Constify to help it along. + static const size_t Q = 4 - (N / 32); + static const size_t R = N % 32; + static_assert(R > 0 && R < 32, "Rotation in range for type"); + KS[0] = (X[0]) ^ ((Y[(Q )%4])>>R) ^ ((Y[(Q+3)%4])<<(32-R)); + KS[1] = (X[1]) ^ ((Y[(Q+1)%4])>>R) ^ ((Y[(Q )%4])<<(32-R)); + KS[2] = (X[2]) ^ ((Y[(Q+2)%4])>>R) ^ ((Y[(Q+1)%4])<<(32-R)); + KS[3] = (X[3]) ^ ((Y[(Q+3)%4])>>R) ^ ((Y[(Q+2)%4])<<(32-R)); + } + +/* +* ARIA Key Schedule +*/ +void key_schedule(secure_vector& ERK, + secure_vector& DRK, + const uint8_t key[], size_t length) + { + const uint32_t KRK[3][4] = { + {0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0}, + {0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0}, + {0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e} + }; + + const size_t CK0 = (length / 8) - 2; + const size_t CK1 = (CK0 + 1) % 3; + const size_t CK2 = (CK1 + 1) % 3; + + uint32_t w0[4]; + uint32_t w1[4]; + uint32_t w2[4]; + uint32_t w3[4]; + + w0[0] = load_be(key,0); + w0[1] = load_be(key,1); + w0[2] = load_be(key,2); + w0[3] = load_be(key,3); + + w1[0] = w0[0] ^ KRK[CK0][0]; + w1[1] = w0[1] ^ KRK[CK0][1]; + w1[2] = w0[2] ^ KRK[CK0][2]; + w1[3] = w0[3] ^ KRK[CK0][3]; + + ARIA_FO(w1[0], w1[1], w1[2], w1[3]); + + if(length == 24 || length == 32) + { + w1[0] ^= load_be(key,4); + w1[1] ^= load_be(key,5); + } + if(length == 32) + { + w1[2] ^= load_be(key,6); + w1[3] ^= load_be(key,7); + } + + w2[0] = w1[0] ^ KRK[CK1][0]; + w2[1] = w1[1] ^ KRK[CK1][1]; + w2[2] = w1[2] ^ KRK[CK1][2]; + w2[3] = w1[3] ^ KRK[CK1][3]; + + ARIA_FE(w2[0], w2[1], w2[2], w2[3]); + + w2[0] ^= w0[0]; + w2[1] ^= w0[1]; + w2[2] ^= w0[2]; + w2[3] ^= w0[3]; + + w3[0] = w2[0] ^ KRK[CK2][0]; + w3[1] = w2[1] ^ KRK[CK2][1]; + w3[2] = w2[2] ^ KRK[CK2][2]; + w3[3] = w2[3] ^ KRK[CK2][3]; + + ARIA_FO(w3[0], w3[1], w3[2], w3[3]); + + w3[0] ^= w1[0]; + w3[1] ^= w1[1]; + w3[2] ^= w1[2]; + w3[3] ^= w1[3]; + + if(length == 16) + ERK.resize(4*13); + else if(length == 24) + ERK.resize(4*15); + else if(length == 32) + ERK.resize(4*17); + + ARIA_ROL128<19>(w0, w1, &ERK[ 0]); + ARIA_ROL128<19>(w1, w2, &ERK[ 4]); + ARIA_ROL128<19>(w2, w3, &ERK[ 8]); + ARIA_ROL128<19>(w3, w0, &ERK[12]); + ARIA_ROL128<31>(w0, w1, &ERK[16]); + ARIA_ROL128<31>(w1, w2, &ERK[20]); + ARIA_ROL128<31>(w2, w3, &ERK[24]); + ARIA_ROL128<31>(w3, w0, &ERK[28]); + ARIA_ROL128<67>(w0, w1, &ERK[32]); + ARIA_ROL128<67>(w1, w2, &ERK[36]); + ARIA_ROL128<67>(w2, w3, &ERK[40]); + ARIA_ROL128<67>(w3, w0, &ERK[44]); + ARIA_ROL128<97>(w0, w1, &ERK[48]); + + if(length == 24 || length == 32) + { + ARIA_ROL128<97>(w1, w2, &ERK[52]); + ARIA_ROL128<97>(w2, w3, &ERK[56]); + + if(length == 32) + { + ARIA_ROL128< 97>(w3, w0, &ERK[60]); + ARIA_ROL128<109>(w0, w1, &ERK[64]); + } + } + + // Now create the decryption key schedule + DRK.resize(ERK.size()); + + for(size_t i = 0; i != DRK.size(); i += 4) + { + DRK[i ] = ERK[ERK.size()-4-i]; + DRK[i+1] = ERK[ERK.size()-3-i]; + DRK[i+2] = ERK[ERK.size()-2-i]; + DRK[i+3] = ERK[ERK.size()-1-i]; + } + + for(size_t i = 4; i != DRK.size() - 4; i += 4) + { + for(size_t j = 0; j != 4; ++j) + { + DRK[i+j] = rotr<8>(DRK[i+j]) ^ + rotr<16>(DRK[i+j]) ^ + rotr<24>(DRK[i+j]); + } + + DRK[i+1] ^= DRK[i+2]; DRK[i+2] ^= DRK[i+3]; + DRK[i+0] ^= DRK[i+1]; DRK[i+3] ^= DRK[i+1]; + DRK[i+2] ^= DRK[i+0]; DRK[i+1] ^= DRK[i+2]; + + DRK[i+1] = ((DRK[i+1] << 8) & 0xFF00FF00) | ((DRK[i+1] >> 8) & 0x00FF00FF); + DRK[i+2] = rotr<16>(DRK[i+2]); + DRK[i+3] = reverse_bytes(DRK[i+3]); + + DRK[i+1] ^= DRK[i+2]; DRK[i+2] ^= DRK[i+3]; + DRK[i+0] ^= DRK[i+1]; DRK[i+3] ^= DRK[i+1]; + DRK[i+2] ^= DRK[i+0]; DRK[i+1] ^= DRK[i+2]; + } + } + +} + +} + +void ARIA_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_ERK.size() > 0); + ARIA_F::transform(in, out, blocks, m_ERK); + } + +void ARIA_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_ERK.size() > 0); + ARIA_F::transform(in, out, blocks, m_ERK); + } + +void ARIA_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_ERK.size() > 0); + ARIA_F::transform(in, out, blocks, m_ERK); + } + +void ARIA_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DRK.size() > 0); + ARIA_F::transform(in, out, blocks, m_DRK); + } + +void ARIA_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DRK.size() > 0); + ARIA_F::transform(in, out, blocks, m_DRK); + } + +void ARIA_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DRK.size() > 0); + ARIA_F::transform(in, out, blocks, m_DRK); + } + +void ARIA_128::key_schedule(const uint8_t key[], size_t length) + { + ARIA_F::key_schedule(m_ERK, m_DRK, key, length); + } + +void ARIA_192::key_schedule(const uint8_t key[], size_t length) + { + ARIA_F::key_schedule(m_ERK, m_DRK, key, length); + } + +void ARIA_256::key_schedule(const uint8_t key[], size_t length) + { + ARIA_F::key_schedule(m_ERK, m_DRK, key, length); + } + +void ARIA_128::clear() + { + zap(m_ERK); + zap(m_DRK); + } + +void ARIA_192::clear() + { + zap(m_ERK); + zap(m_DRK); + } + +void ARIA_256::clear() + { + zap(m_ERK); + zap(m_DRK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/aria/aria.h b/comm/third_party/botan/src/lib/block/aria/aria.h new file mode 100644 index 0000000000..507226b7d3 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aria/aria.h @@ -0,0 +1,84 @@ +/* +* ARIA +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +* +* This ARIA implementation is based on the 32-bit implementation by Aaram Yun from the +* National Security Research Institute, KOREA. Aaram Yun's implementation is based on +* the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from +* the Korea Internet & Security Agency website. +* RFC 5794, A Description of the ARIA Encryption Algorithm, +* Korea +* Internet & Security Agency homepage +*/ + +#ifndef BOTAN_ARIA_H_ +#define BOTAN_ARIA_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(aria.h) + +namespace Botan { + +/** +* ARIA-128 +*/ +class BOTAN_PUBLIC_API(2,3) ARIA_128 final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "ARIA-128"; } + BlockCipher* clone() const override { return new ARIA_128; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + // Encryption and Decryption round keys. + secure_vector m_ERK, m_DRK; + }; + +/** +* ARIA-192 +*/ +class BOTAN_PUBLIC_API(2,3) ARIA_192 final : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "ARIA-192"; } + BlockCipher* clone() const override { return new ARIA_192; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + // Encryption and Decryption round keys. + secure_vector m_ERK, m_DRK; + }; + +/** +* ARIA-256 +*/ +class BOTAN_PUBLIC_API(2,3) ARIA_256 final : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "ARIA-256"; } + BlockCipher* clone() const override { return new ARIA_256; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + // Encryption and Decryption round keys. + secure_vector m_ERK, m_DRK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/aria/info.txt b/comm/third_party/botan/src/lib/block/aria/info.txt new file mode 100644 index 0000000000..78c16726c8 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/aria/info.txt @@ -0,0 +1,7 @@ + +ARIA -> 20170415 + + + +aria.h + diff --git a/comm/third_party/botan/src/lib/block/block_cipher.cpp b/comm/third_party/botan/src/lib/block/block_cipher.cpp new file mode 100644 index 0000000000..fb0564646e --- /dev/null +++ b/comm/third_party/botan/src/lib/block/block_cipher.cpp @@ -0,0 +1,363 @@ +/* +* Block Ciphers +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_AES) + #include +#endif + +#if defined(BOTAN_HAS_ARIA) + #include +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + #include +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + #include +#endif + +#if defined(BOTAN_HAS_CAST_128) + #include +#endif + +#if defined(BOTAN_HAS_CAST_256) + #include +#endif + +#if defined(BOTAN_HAS_CASCADE) + #include +#endif + +#if defined(BOTAN_HAS_DES) + #include + #include +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) + #include +#endif + +#if defined(BOTAN_HAS_IDEA) + #include +#endif + +#if defined(BOTAN_HAS_KASUMI) + #include +#endif + +#if defined(BOTAN_HAS_LION) + #include +#endif + +#if defined(BOTAN_HAS_MISTY1) + #include +#endif + +#if defined(BOTAN_HAS_NOEKEON) + #include +#endif + +#if defined(BOTAN_HAS_SEED) + #include +#endif + +#if defined(BOTAN_HAS_SERPENT) + #include +#endif + +#if defined(BOTAN_HAS_SHACAL2) + #include +#endif + +#if defined(BOTAN_HAS_SM4) + #include +#endif + +#if defined(BOTAN_HAS_TWOFISH) + #include +#endif + +#if defined(BOTAN_HAS_THREEFISH_512) + #include +#endif + +#if defined(BOTAN_HAS_XTEA) + #include +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +#if defined(BOTAN_HAS_COMMONCRYPTO) + #include +#endif + +namespace Botan { + +std::unique_ptr +BlockCipher::create(const std::string& algo, + const std::string& provider) + { +#if defined(BOTAN_HAS_COMMONCRYPTO) + if(provider.empty() || provider == "commoncrypto") + { + if(auto bc = make_commoncrypto_block_cipher(algo)) + return bc; + + if(!provider.empty()) + return nullptr; + } +#endif + +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + if(auto bc = make_openssl_block_cipher(algo)) + return bc; + + if(!provider.empty()) + return nullptr; + } +#endif + + // TODO: CryptoAPI + // TODO: /dev/crypto + + // Only base providers from here on out + if(provider.empty() == false && provider != "base") + return nullptr; + +#if defined(BOTAN_HAS_AES) + if(algo == "AES-128") + { + return std::unique_ptr(new AES_128); + } + + if(algo == "AES-192") + { + return std::unique_ptr(new AES_192); + } + + if(algo == "AES-256") + { + return std::unique_ptr(new AES_256); + } +#endif + +#if defined(BOTAN_HAS_ARIA) + if(algo == "ARIA-128") + { + return std::unique_ptr(new ARIA_128); + } + + if(algo == "ARIA-192") + { + return std::unique_ptr(new ARIA_192); + } + + if(algo == "ARIA-256") + { + return std::unique_ptr(new ARIA_256); + } +#endif + +#if defined(BOTAN_HAS_SERPENT) + if(algo == "Serpent") + { + return std::unique_ptr(new Serpent); + } +#endif + +#if defined(BOTAN_HAS_SHACAL2) + if(algo == "SHACAL2") + { + return std::unique_ptr(new SHACAL2); + } +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(algo == "Twofish") + { + return std::unique_ptr(new Twofish); + } +#endif + +#if defined(BOTAN_HAS_THREEFISH_512) + if(algo == "Threefish-512") + { + return std::unique_ptr(new Threefish_512); + } +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + if(algo == "Blowfish") + { + return std::unique_ptr(new Blowfish); + } +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + if(algo == "Camellia-128") + { + return std::unique_ptr(new Camellia_128); + } + + if(algo == "Camellia-192") + { + return std::unique_ptr(new Camellia_192); + } + + if(algo == "Camellia-256") + { + return std::unique_ptr(new Camellia_256); + } +#endif + +#if defined(BOTAN_HAS_DES) + if(algo == "DES") + { + return std::unique_ptr(new DES); + } + + if(algo == "DESX") + { + return std::unique_ptr(new DESX); + } + + if(algo == "TripleDES" || algo == "3DES" || algo == "DES-EDE") + { + return std::unique_ptr(new TripleDES); + } +#endif + +#if defined(BOTAN_HAS_NOEKEON) + if(algo == "Noekeon") + { + return std::unique_ptr(new Noekeon); + } +#endif + +#if defined(BOTAN_HAS_CAST_128) + if(algo == "CAST-128" || algo == "CAST5") + { + return std::unique_ptr(new CAST_128); + } +#endif + +#if defined(BOTAN_HAS_CAST_256) + if(algo == "CAST-256") + { + return std::unique_ptr(new CAST_256); + } +#endif + +#if defined(BOTAN_HAS_IDEA) + if(algo == "IDEA") + { + return std::unique_ptr(new IDEA); + } +#endif + +#if defined(BOTAN_HAS_KASUMI) + if(algo == "KASUMI") + { + return std::unique_ptr(new KASUMI); + } +#endif + +#if defined(BOTAN_HAS_MISTY1) + if(algo == "MISTY1") + { + return std::unique_ptr(new MISTY1); + } +#endif + +#if defined(BOTAN_HAS_SEED) + if(algo == "SEED") + { + return std::unique_ptr(new SEED); + } +#endif + +#if defined(BOTAN_HAS_SM4) + if(algo == "SM4") + { + return std::unique_ptr(new SM4); + } +#endif + +#if defined(BOTAN_HAS_XTEA) + if(algo == "XTEA") + { + return std::unique_ptr(new XTEA); + } +#endif + + const SCAN_Name req(algo); + +#if defined(BOTAN_HAS_GOST_28147_89) + if(req.algo_name() == "GOST-28147-89") + { + return std::unique_ptr(new GOST_28147_89(req.arg(0, "R3411_94_TestParam"))); + } +#endif + +#if defined(BOTAN_HAS_CASCADE) + if(req.algo_name() == "Cascade" && req.arg_count() == 2) + { + std::unique_ptr c1(BlockCipher::create(req.arg(0))); + std::unique_ptr c2(BlockCipher::create(req.arg(1))); + + if(c1 && c2) + return std::unique_ptr(new Cascade_Cipher(c1.release(), c2.release())); + } +#endif + +#if defined(BOTAN_HAS_LION) + if(req.algo_name() == "Lion" && req.arg_count_between(2, 3)) + { + std::unique_ptr hash(HashFunction::create(req.arg(0))); + std::unique_ptr stream(StreamCipher::create(req.arg(1))); + + if(hash && stream) + { + const size_t block_size = req.arg_as_integer(2, 1024); + return std::unique_ptr(new Lion(hash.release(), stream.release(), block_size)); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr +BlockCipher::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto bc = BlockCipher::create(algo, provider)) + { + return bc; + } + throw Lookup_Error("Block cipher", algo, provider); + } + +std::vector BlockCipher::providers(const std::string& algo) + { + return probe_providers_of(algo, { "base", "openssl", "commoncrypto" }); + } + +} diff --git a/comm/third_party/botan/src/lib/block/block_cipher.h b/comm/third_party/botan/src/lib/block/block_cipher.h new file mode 100644 index 0000000000..68cdd1afe0 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/block_cipher.h @@ -0,0 +1,254 @@ +/* +* Block Cipher Base Class +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BLOCK_CIPHER_H_ +#define BOTAN_BLOCK_CIPHER_H_ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents a block cipher object. +*/ +class BOTAN_PUBLIC_API(2,0) BlockCipher : public SymmetricAlgorithm + { + public: + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector providers(const std::string& algo_spec); + + /** + * @return block size of this algorithm + */ + virtual size_t block_size() const = 0; + + /** + * @return native parallelism of this cipher in blocks + */ + virtual size_t parallelism() const { return 1; } + + /** + * @return prefererred parallelism of this cipher in bytes + */ + size_t parallel_bytes() const + { + return parallelism() * block_size() * BOTAN_BLOCK_CIPHER_PAR_MULT; + } + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + /** + * Encrypt a block. + * @param in The plaintext block to be encrypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the encrypted block. + * Must be of length block_size(). + */ + void encrypt(const uint8_t in[], uint8_t out[]) const + { encrypt_n(in, out, 1); } + + /** + * Decrypt a block. + * @param in The ciphertext block to be decypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the decrypted block. + * Must be of length block_size(). + */ + void decrypt(const uint8_t in[], uint8_t out[]) const + { decrypt_n(in, out, 1); } + + /** + * Encrypt a block. + * @param block the plaintext block to be encrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void encrypt(uint8_t block[]) const { encrypt_n(block, block, 1); } + + /** + * Decrypt a block. + * @param block the ciphertext block to be decrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void decrypt(uint8_t block[]) const { decrypt_n(block, block, 1); } + + /** + * Encrypt one or more blocks + * @param block the input/output buffer (multiple of block_size()) + */ + template + void encrypt(std::vector& block) const + { + return encrypt_n(block.data(), block.data(), block.size() / block_size()); + } + + /** + * Decrypt one or more blocks + * @param block the input/output buffer (multiple of block_size()) + */ + template + void decrypt(std::vector& block) const + { + return decrypt_n(block.data(), block.data(), block.size() / block_size()); + } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + */ + template + void encrypt(const std::vector& in, + std::vector& out) const + { + return encrypt_n(in.data(), out.data(), in.size() / block_size()); + } + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + */ + template + void decrypt(const std::vector& in, + std::vector& out) const + { + return decrypt_n(in.data(), out.data(), in.size() / block_size()); + } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void encrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks) const = 0; + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void decrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks) const = 0; + + virtual void encrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const + { + const size_t BS = block_size(); + xor_buf(data, mask, blocks * BS); + encrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + virtual void decrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const + { + const size_t BS = block_size(); + xor_buf(data, mask, blocks * BS); + decrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + /** + * @return new object representing the same algorithm as *this + */ + virtual BlockCipher* clone() const = 0; + + virtual ~BlockCipher() = default; + }; + +/** +* Tweakable block ciphers allow setting a tweak which is a non-keyed +* value which affects the encryption/decryption operation. +*/ +class BOTAN_PUBLIC_API(2,8) Tweakable_Block_Cipher : public BlockCipher + { + public: + /** + * Set the tweak value. This must be called after setting a key. The value + * persists until either set_tweak, set_key, or clear is called. + * Different algorithms support different tweak length(s). If called with + * an unsupported length, Invalid_Argument will be thrown. + */ + virtual void set_tweak(const uint8_t tweak[], size_t len) = 0; + }; + +/** +* Represents a block cipher with a single fixed block size +*/ +template +class Block_Cipher_Fixed_Params : public BaseClass + { + public: + enum { BLOCK_SIZE = BS }; + size_t block_size() const final override { return BS; } + + // override to take advantage of compile time constant block size + void encrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const final override + { + xor_buf(data, mask, blocks * BS); + this->encrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + void decrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const final override + { + xor_buf(data, mask, blocks * BS); + this->decrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + Key_Length_Specification key_spec() const final override + { + return Key_Length_Specification(KMIN, KMAX, KMOD); + } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/blowfish/blowfish.cpp b/comm/third_party/botan/src/lib/block/blowfish/blowfish.cpp new file mode 100644 index 0000000000..ecb9f82e36 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/blowfish/blowfish.cpp @@ -0,0 +1,456 @@ +/* +* Blowfish +* (C) 1999-2011,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +const uint32_t P_INIT[18] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, + 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B }; + +const uint32_t S_INIT[1024] = { + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, + 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, + 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, + 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, + 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, + 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, 0xEF845D5D, 0xE98575B1, + 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, + 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, + 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, + 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, + 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, + 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, + 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, + 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, + 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, + 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, + 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, + 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705, + 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, + 0x226800BB, 0x57B8E0AF, 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, + 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, + 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A, 0x4B7A70E9, 0xB5B32944, + 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, + 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, + 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, + 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, + 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, + 0x3280BBA1, 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, + 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, + 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, + 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, + 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, + 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, + 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, + 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, + 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, + 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, + 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, + 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, + 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, + 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, + 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, + 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, + 0xE6E39F2B, 0xDB83ADF7, 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, + 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, + 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, + 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, + 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, + 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, + 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, + 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, + 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, + 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, + 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, + 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, + 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, + 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, + 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, + 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, + 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, + 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, + 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, 0x2338EA63, + 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, + 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, + 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0, + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, + 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, + 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, + 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, + 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, + 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, 0xE029AC71, 0xE019A5E6, + 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, + 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, + 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, + 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, + 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, + 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, + 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, + 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, + 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, + 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, + 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, + 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623, + 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, + 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, + 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, + 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 }; + +inline uint32_t BFF(uint32_t X, const secure_vector& S) + { + return ((S[ get_byte(0, X)] + S[256+get_byte(1, X)]) ^ + S[512+get_byte(2, X)]) + S[768+get_byte(3, X)]; + } + +} + +/* +* Blowfish Encryption +*/ +void Blowfish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_S.empty() == false); + + while(blocks >= 4) + { + uint32_t L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t r = 0; r != 16; r += 2) + { + L0 ^= m_P[r]; + L1 ^= m_P[r]; + L2 ^= m_P[r]; + L3 ^= m_P[r]; + R0 ^= BFF(L0, m_S); + R1 ^= BFF(L1, m_S); + R2 ^= BFF(L2, m_S); + R3 ^= BFF(L3, m_S); + + R0 ^= m_P[r+1]; + R1 ^= m_P[r+1]; + R2 ^= m_P[r+1]; + R3 ^= m_P[r+1]; + L0 ^= BFF(R0, m_S); + L1 ^= BFF(R1, m_S); + L2 ^= BFF(R2, m_S); + L3 ^= BFF(R3, m_S); + } + + L0 ^= m_P[16]; R0 ^= m_P[17]; + L1 ^= m_P[16]; R1 ^= m_P[17]; + L2 ^= m_P[16]; R2 ^= m_P[17]; + L3 ^= m_P[16]; R3 ^= m_P[17]; + + store_be(out, R0, L0, R1, L1, R2, L2, R3, L3); + + in += 4*BLOCK_SIZE; + out += 4*BLOCK_SIZE; + blocks -= 4; + } + + while(blocks) + { + uint32_t L, R; + load_be(in, L, R); + + for(size_t r = 0; r != 16; r += 2) + { + L ^= m_P[r]; + R ^= BFF(L, m_S); + + R ^= m_P[r+1]; + L ^= BFF(R, m_S); + } + + L ^= m_P[16]; R ^= m_P[17]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + blocks--; + } + } + +/* +* Blowfish Decryption +*/ +void Blowfish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_S.empty() == false); + + while(blocks >= 4) + { + uint32_t L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t r = 17; r != 1; r -= 2) + { + L0 ^= m_P[r]; + L1 ^= m_P[r]; + L2 ^= m_P[r]; + L3 ^= m_P[r]; + R0 ^= BFF(L0, m_S); + R1 ^= BFF(L1, m_S); + R2 ^= BFF(L2, m_S); + R3 ^= BFF(L3, m_S); + + R0 ^= m_P[r-1]; + R1 ^= m_P[r-1]; + R2 ^= m_P[r-1]; + R3 ^= m_P[r-1]; + + L0 ^= BFF(R0, m_S); + L1 ^= BFF(R1, m_S); + L2 ^= BFF(R2, m_S); + L3 ^= BFF(R3, m_S); + } + + L0 ^= m_P[1]; R0 ^= m_P[0]; + L1 ^= m_P[1]; R1 ^= m_P[0]; + L2 ^= m_P[1]; R2 ^= m_P[0]; + L3 ^= m_P[1]; R3 ^= m_P[0]; + + store_be(out, R0, L0, R1, L1, R2, L2, R3, L3); + + in += 4*BLOCK_SIZE; + out += 4*BLOCK_SIZE; + blocks -= 4; + } + + while(blocks) + { + uint32_t L, R; + load_be(in, L, R); + + for(size_t r = 17; r != 1; r -= 2) + { + L ^= m_P[r]; + R ^= BFF(L, m_S); + + R ^= m_P[r-1]; + L ^= BFF(R, m_S); + } + + L ^= m_P[1]; R ^= m_P[0]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + blocks--; + } + } + +/* +* Blowfish Key Schedule +*/ +void Blowfish::key_schedule(const uint8_t key[], size_t length) + { + m_P.resize(18); + copy_mem(m_P.data(), P_INIT, 18); + + m_S.resize(1024); + copy_mem(m_S.data(), S_INIT, 1024); + + key_expansion(key, length, nullptr, 0); + } + +void Blowfish::key_expansion(const uint8_t key[], + size_t length, + const uint8_t salt[], + size_t salt_length) + { + BOTAN_ASSERT_NOMSG(salt_length % 4 == 0); + + for(size_t i = 0, j = 0; i != 18; ++i, j += 4) + m_P[i] ^= make_uint32(key[(j ) % length], key[(j+1) % length], + key[(j+2) % length], key[(j+3) % length]); + + const size_t P_salt_offset = (salt_length > 0) ? 18 % (salt_length / 4) : 0; + + uint32_t L = 0, R = 0; + generate_sbox(m_P, L, R, salt, salt_length, 0); + generate_sbox(m_S, L, R, salt, salt_length, P_salt_offset); + } + +/* +* Modified key schedule used for bcrypt password hashing +*/ +void Blowfish::salted_set_key(const uint8_t key[], size_t length, + const uint8_t salt[], size_t salt_length, + size_t workfactor, bool salt_first) + { + BOTAN_ARG_CHECK(salt_length > 0 && salt_length % 4 == 0, + "Invalid salt length for Blowfish salted key schedule"); + + if(length > 72) + { + // Truncate longer passwords to the 72 char bcrypt limit + length = 72; + } + + m_P.resize(18); + copy_mem(m_P.data(), P_INIT, 18); + + m_S.resize(1024); + copy_mem(m_S.data(), S_INIT, 1024); + key_expansion(key, length, salt, salt_length); + + if(workfactor > 0) + { + const size_t rounds = static_cast(1) << workfactor; + + for(size_t r = 0; r != rounds; ++r) + { + if(salt_first) + { + key_expansion(salt, salt_length, nullptr, 0); + key_expansion(key, length, nullptr, 0); + } + else + { + key_expansion(key, length, nullptr, 0); + key_expansion(salt, salt_length, nullptr, 0); + } + } + } + } + +/* +* Generate one of the Sboxes +*/ +void Blowfish::generate_sbox(secure_vector& box, + uint32_t& L, uint32_t& R, + const uint8_t salt[], + size_t salt_length, + size_t salt_off) const + { + for(size_t i = 0; i != box.size(); i += 2) + { + if(salt_length > 0) + { + L ^= load_be(salt, (i + salt_off) % (salt_length / 4)); + R ^= load_be(salt, (i + salt_off + 1) % (salt_length / 4)); + } + + for(size_t r = 0; r != 16; r += 2) + { + L ^= m_P[r]; + R ^= BFF(L, m_S); + + R ^= m_P[r+1]; + L ^= BFF(R, m_S); + } + + uint32_t T = R; R = L ^ m_P[16]; L = T ^ m_P[17]; + box[i] = L; + box[i+1] = R; + } + } + +/* +* Clear memory of sensitive data +*/ +void Blowfish::clear() + { + zap(m_P); + zap(m_S); + } + +} diff --git a/comm/third_party/botan/src/lib/block/blowfish/blowfish.h b/comm/third_party/botan/src/lib/block/blowfish/blowfish.h new file mode 100644 index 0000000000..3ba39cbdbb --- /dev/null +++ b/comm/third_party/botan/src/lib/block/blowfish/blowfish.h @@ -0,0 +1,62 @@ +/* +* Blowfish +* (C) 1999-2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BLOWFISH_H_ +#define BOTAN_BLOWFISH_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(blowfish.h) + +namespace Botan { + +/** +* Blowfish +*/ +class BOTAN_PUBLIC_API(2,0) Blowfish final : public Block_Cipher_Fixed_Params<8, 1, 56> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + /** + * Modified EKSBlowfish key schedule, used for bcrypt password hashing + */ + void salted_set_key(const uint8_t key[], size_t key_length, + const uint8_t salt[], size_t salt_length, + const size_t workfactor, bool salt_first = false); + + BOTAN_DEPRECATED("Use Blowfish::salted_set_key taking salt length") + void eks_key_schedule(const uint8_t key[], size_t key_length, + const uint8_t salt[16], size_t workfactor) + { + salted_set_key(key, key_length, salt, 16, workfactor); + } + + void clear() override; + std::string name() const override { return "Blowfish"; } + BlockCipher* clone() const override { return new Blowfish; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + void key_expansion(const uint8_t key[], + size_t key_length, + const uint8_t salt[], + size_t salt_length); + + void generate_sbox(secure_vector& box, + uint32_t& L, uint32_t& R, + const uint8_t salt[], + size_t salt_length, + size_t salt_off) const; + + secure_vector m_S, m_P; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/blowfish/info.txt b/comm/third_party/botan/src/lib/block/blowfish/info.txt new file mode 100644 index 0000000000..cc72634dfc --- /dev/null +++ b/comm/third_party/botan/src/lib/block/blowfish/info.txt @@ -0,0 +1,3 @@ + +BLOWFISH -> 20180718 + diff --git a/comm/third_party/botan/src/lib/block/camellia/camellia.cpp b/comm/third_party/botan/src/lib/block/camellia/camellia.cpp new file mode 100644 index 0000000000..557b3012db --- /dev/null +++ b/comm/third_party/botan/src/lib/block/camellia/camellia.cpp @@ -0,0 +1,924 @@ +/* +* Camellia +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +alignas(64) const uint64_t Camellia_SBOX1[256] = { +0x7070700070000070, 0x8282820082000082, 0x2C2C2C002C00002C, 0xECECEC00EC0000EC, +0xB3B3B300B30000B3, 0x2727270027000027, 0xC0C0C000C00000C0, 0xE5E5E500E50000E5, +0xE4E4E400E40000E4, 0x8585850085000085, 0x5757570057000057, 0x3535350035000035, +0xEAEAEA00EA0000EA, 0x0C0C0C000C00000C, 0xAEAEAE00AE0000AE, 0x4141410041000041, +0x2323230023000023, 0xEFEFEF00EF0000EF, 0x6B6B6B006B00006B, 0x9393930093000093, +0x4545450045000045, 0x1919190019000019, 0xA5A5A500A50000A5, 0x2121210021000021, +0xEDEDED00ED0000ED, 0x0E0E0E000E00000E, 0x4F4F4F004F00004F, 0x4E4E4E004E00004E, +0x1D1D1D001D00001D, 0x6565650065000065, 0x9292920092000092, 0xBDBDBD00BD0000BD, +0x8686860086000086, 0xB8B8B800B80000B8, 0xAFAFAF00AF0000AF, 0x8F8F8F008F00008F, +0x7C7C7C007C00007C, 0xEBEBEB00EB0000EB, 0x1F1F1F001F00001F, 0xCECECE00CE0000CE, +0x3E3E3E003E00003E, 0x3030300030000030, 0xDCDCDC00DC0000DC, 0x5F5F5F005F00005F, +0x5E5E5E005E00005E, 0xC5C5C500C50000C5, 0x0B0B0B000B00000B, 0x1A1A1A001A00001A, +0xA6A6A600A60000A6, 0xE1E1E100E10000E1, 0x3939390039000039, 0xCACACA00CA0000CA, +0xD5D5D500D50000D5, 0x4747470047000047, 0x5D5D5D005D00005D, 0x3D3D3D003D00003D, +0xD9D9D900D90000D9, 0x0101010001000001, 0x5A5A5A005A00005A, 0xD6D6D600D60000D6, +0x5151510051000051, 0x5656560056000056, 0x6C6C6C006C00006C, 0x4D4D4D004D00004D, +0x8B8B8B008B00008B, 0x0D0D0D000D00000D, 0x9A9A9A009A00009A, 0x6666660066000066, +0xFBFBFB00FB0000FB, 0xCCCCCC00CC0000CC, 0xB0B0B000B00000B0, 0x2D2D2D002D00002D, +0x7474740074000074, 0x1212120012000012, 0x2B2B2B002B00002B, 0x2020200020000020, +0xF0F0F000F00000F0, 0xB1B1B100B10000B1, 0x8484840084000084, 0x9999990099000099, +0xDFDFDF00DF0000DF, 0x4C4C4C004C00004C, 0xCBCBCB00CB0000CB, 0xC2C2C200C20000C2, +0x3434340034000034, 0x7E7E7E007E00007E, 0x7676760076000076, 0x0505050005000005, +0x6D6D6D006D00006D, 0xB7B7B700B70000B7, 0xA9A9A900A90000A9, 0x3131310031000031, +0xD1D1D100D10000D1, 0x1717170017000017, 0x0404040004000004, 0xD7D7D700D70000D7, +0x1414140014000014, 0x5858580058000058, 0x3A3A3A003A00003A, 0x6161610061000061, +0xDEDEDE00DE0000DE, 0x1B1B1B001B00001B, 0x1111110011000011, 0x1C1C1C001C00001C, +0x3232320032000032, 0x0F0F0F000F00000F, 0x9C9C9C009C00009C, 0x1616160016000016, +0x5353530053000053, 0x1818180018000018, 0xF2F2F200F20000F2, 0x2222220022000022, +0xFEFEFE00FE0000FE, 0x4444440044000044, 0xCFCFCF00CF0000CF, 0xB2B2B200B20000B2, +0xC3C3C300C30000C3, 0xB5B5B500B50000B5, 0x7A7A7A007A00007A, 0x9191910091000091, +0x2424240024000024, 0x0808080008000008, 0xE8E8E800E80000E8, 0xA8A8A800A80000A8, +0x6060600060000060, 0xFCFCFC00FC0000FC, 0x6969690069000069, 0x5050500050000050, +0xAAAAAA00AA0000AA, 0xD0D0D000D00000D0, 0xA0A0A000A00000A0, 0x7D7D7D007D00007D, +0xA1A1A100A10000A1, 0x8989890089000089, 0x6262620062000062, 0x9797970097000097, +0x5454540054000054, 0x5B5B5B005B00005B, 0x1E1E1E001E00001E, 0x9595950095000095, +0xE0E0E000E00000E0, 0xFFFFFF00FF0000FF, 0x6464640064000064, 0xD2D2D200D20000D2, +0x1010100010000010, 0xC4C4C400C40000C4, 0x0000000000000000, 0x4848480048000048, +0xA3A3A300A30000A3, 0xF7F7F700F70000F7, 0x7575750075000075, 0xDBDBDB00DB0000DB, +0x8A8A8A008A00008A, 0x0303030003000003, 0xE6E6E600E60000E6, 0xDADADA00DA0000DA, +0x0909090009000009, 0x3F3F3F003F00003F, 0xDDDDDD00DD0000DD, 0x9494940094000094, +0x8787870087000087, 0x5C5C5C005C00005C, 0x8383830083000083, 0x0202020002000002, +0xCDCDCD00CD0000CD, 0x4A4A4A004A00004A, 0x9090900090000090, 0x3333330033000033, +0x7373730073000073, 0x6767670067000067, 0xF6F6F600F60000F6, 0xF3F3F300F30000F3, +0x9D9D9D009D00009D, 0x7F7F7F007F00007F, 0xBFBFBF00BF0000BF, 0xE2E2E200E20000E2, +0x5252520052000052, 0x9B9B9B009B00009B, 0xD8D8D800D80000D8, 0x2626260026000026, +0xC8C8C800C80000C8, 0x3737370037000037, 0xC6C6C600C60000C6, 0x3B3B3B003B00003B, +0x8181810081000081, 0x9696960096000096, 0x6F6F6F006F00006F, 0x4B4B4B004B00004B, +0x1313130013000013, 0xBEBEBE00BE0000BE, 0x6363630063000063, 0x2E2E2E002E00002E, +0xE9E9E900E90000E9, 0x7979790079000079, 0xA7A7A700A70000A7, 0x8C8C8C008C00008C, +0x9F9F9F009F00009F, 0x6E6E6E006E00006E, 0xBCBCBC00BC0000BC, 0x8E8E8E008E00008E, +0x2929290029000029, 0xF5F5F500F50000F5, 0xF9F9F900F90000F9, 0xB6B6B600B60000B6, +0x2F2F2F002F00002F, 0xFDFDFD00FD0000FD, 0xB4B4B400B40000B4, 0x5959590059000059, +0x7878780078000078, 0x9898980098000098, 0x0606060006000006, 0x6A6A6A006A00006A, +0xE7E7E700E70000E7, 0x4646460046000046, 0x7171710071000071, 0xBABABA00BA0000BA, +0xD4D4D400D40000D4, 0x2525250025000025, 0xABABAB00AB0000AB, 0x4242420042000042, +0x8888880088000088, 0xA2A2A200A20000A2, 0x8D8D8D008D00008D, 0xFAFAFA00FA0000FA, +0x7272720072000072, 0x0707070007000007, 0xB9B9B900B90000B9, 0x5555550055000055, +0xF8F8F800F80000F8, 0xEEEEEE00EE0000EE, 0xACACAC00AC0000AC, 0x0A0A0A000A00000A, +0x3636360036000036, 0x4949490049000049, 0x2A2A2A002A00002A, 0x6868680068000068, +0x3C3C3C003C00003C, 0x3838380038000038, 0xF1F1F100F10000F1, 0xA4A4A400A40000A4, +0x4040400040000040, 0x2828280028000028, 0xD3D3D300D30000D3, 0x7B7B7B007B00007B, +0xBBBBBB00BB0000BB, 0xC9C9C900C90000C9, 0x4343430043000043, 0xC1C1C100C10000C1, +0x1515150015000015, 0xE3E3E300E30000E3, 0xADADAD00AD0000AD, 0xF4F4F400F40000F4, +0x7777770077000077, 0xC7C7C700C70000C7, 0x8080800080000080, 0x9E9E9E009E00009E }; + +alignas(64) const uint64_t Camellia_SBOX2[256] = { +0x00E0E0E0E0E00000, 0x0005050505050000, 0x0058585858580000, 0x00D9D9D9D9D90000, +0x0067676767670000, 0x004E4E4E4E4E0000, 0x0081818181810000, 0x00CBCBCBCBCB0000, +0x00C9C9C9C9C90000, 0x000B0B0B0B0B0000, 0x00AEAEAEAEAE0000, 0x006A6A6A6A6A0000, +0x00D5D5D5D5D50000, 0x0018181818180000, 0x005D5D5D5D5D0000, 0x0082828282820000, +0x0046464646460000, 0x00DFDFDFDFDF0000, 0x00D6D6D6D6D60000, 0x0027272727270000, +0x008A8A8A8A8A0000, 0x0032323232320000, 0x004B4B4B4B4B0000, 0x0042424242420000, +0x00DBDBDBDBDB0000, 0x001C1C1C1C1C0000, 0x009E9E9E9E9E0000, 0x009C9C9C9C9C0000, +0x003A3A3A3A3A0000, 0x00CACACACACA0000, 0x0025252525250000, 0x007B7B7B7B7B0000, +0x000D0D0D0D0D0000, 0x0071717171710000, 0x005F5F5F5F5F0000, 0x001F1F1F1F1F0000, +0x00F8F8F8F8F80000, 0x00D7D7D7D7D70000, 0x003E3E3E3E3E0000, 0x009D9D9D9D9D0000, +0x007C7C7C7C7C0000, 0x0060606060600000, 0x00B9B9B9B9B90000, 0x00BEBEBEBEBE0000, +0x00BCBCBCBCBC0000, 0x008B8B8B8B8B0000, 0x0016161616160000, 0x0034343434340000, +0x004D4D4D4D4D0000, 0x00C3C3C3C3C30000, 0x0072727272720000, 0x0095959595950000, +0x00ABABABABAB0000, 0x008E8E8E8E8E0000, 0x00BABABABABA0000, 0x007A7A7A7A7A0000, +0x00B3B3B3B3B30000, 0x0002020202020000, 0x00B4B4B4B4B40000, 0x00ADADADADAD0000, +0x00A2A2A2A2A20000, 0x00ACACACACAC0000, 0x00D8D8D8D8D80000, 0x009A9A9A9A9A0000, +0x0017171717170000, 0x001A1A1A1A1A0000, 0x0035353535350000, 0x00CCCCCCCCCC0000, +0x00F7F7F7F7F70000, 0x0099999999990000, 0x0061616161610000, 0x005A5A5A5A5A0000, +0x00E8E8E8E8E80000, 0x0024242424240000, 0x0056565656560000, 0x0040404040400000, +0x00E1E1E1E1E10000, 0x0063636363630000, 0x0009090909090000, 0x0033333333330000, +0x00BFBFBFBFBF0000, 0x0098989898980000, 0x0097979797970000, 0x0085858585850000, +0x0068686868680000, 0x00FCFCFCFCFC0000, 0x00ECECECECEC0000, 0x000A0A0A0A0A0000, +0x00DADADADADA0000, 0x006F6F6F6F6F0000, 0x0053535353530000, 0x0062626262620000, +0x00A3A3A3A3A30000, 0x002E2E2E2E2E0000, 0x0008080808080000, 0x00AFAFAFAFAF0000, +0x0028282828280000, 0x00B0B0B0B0B00000, 0x0074747474740000, 0x00C2C2C2C2C20000, +0x00BDBDBDBDBD0000, 0x0036363636360000, 0x0022222222220000, 0x0038383838380000, +0x0064646464640000, 0x001E1E1E1E1E0000, 0x0039393939390000, 0x002C2C2C2C2C0000, +0x00A6A6A6A6A60000, 0x0030303030300000, 0x00E5E5E5E5E50000, 0x0044444444440000, +0x00FDFDFDFDFD0000, 0x0088888888880000, 0x009F9F9F9F9F0000, 0x0065656565650000, +0x0087878787870000, 0x006B6B6B6B6B0000, 0x00F4F4F4F4F40000, 0x0023232323230000, +0x0048484848480000, 0x0010101010100000, 0x00D1D1D1D1D10000, 0x0051515151510000, +0x00C0C0C0C0C00000, 0x00F9F9F9F9F90000, 0x00D2D2D2D2D20000, 0x00A0A0A0A0A00000, +0x0055555555550000, 0x00A1A1A1A1A10000, 0x0041414141410000, 0x00FAFAFAFAFA0000, +0x0043434343430000, 0x0013131313130000, 0x00C4C4C4C4C40000, 0x002F2F2F2F2F0000, +0x00A8A8A8A8A80000, 0x00B6B6B6B6B60000, 0x003C3C3C3C3C0000, 0x002B2B2B2B2B0000, +0x00C1C1C1C1C10000, 0x00FFFFFFFFFF0000, 0x00C8C8C8C8C80000, 0x00A5A5A5A5A50000, +0x0020202020200000, 0x0089898989890000, 0x0000000000000000, 0x0090909090900000, +0x0047474747470000, 0x00EFEFEFEFEF0000, 0x00EAEAEAEAEA0000, 0x00B7B7B7B7B70000, +0x0015151515150000, 0x0006060606060000, 0x00CDCDCDCDCD0000, 0x00B5B5B5B5B50000, +0x0012121212120000, 0x007E7E7E7E7E0000, 0x00BBBBBBBBBB0000, 0x0029292929290000, +0x000F0F0F0F0F0000, 0x00B8B8B8B8B80000, 0x0007070707070000, 0x0004040404040000, +0x009B9B9B9B9B0000, 0x0094949494940000, 0x0021212121210000, 0x0066666666660000, +0x00E6E6E6E6E60000, 0x00CECECECECE0000, 0x00EDEDEDEDED0000, 0x00E7E7E7E7E70000, +0x003B3B3B3B3B0000, 0x00FEFEFEFEFE0000, 0x007F7F7F7F7F0000, 0x00C5C5C5C5C50000, +0x00A4A4A4A4A40000, 0x0037373737370000, 0x00B1B1B1B1B10000, 0x004C4C4C4C4C0000, +0x0091919191910000, 0x006E6E6E6E6E0000, 0x008D8D8D8D8D0000, 0x0076767676760000, +0x0003030303030000, 0x002D2D2D2D2D0000, 0x00DEDEDEDEDE0000, 0x0096969696960000, +0x0026262626260000, 0x007D7D7D7D7D0000, 0x00C6C6C6C6C60000, 0x005C5C5C5C5C0000, +0x00D3D3D3D3D30000, 0x00F2F2F2F2F20000, 0x004F4F4F4F4F0000, 0x0019191919190000, +0x003F3F3F3F3F0000, 0x00DCDCDCDCDC0000, 0x0079797979790000, 0x001D1D1D1D1D0000, +0x0052525252520000, 0x00EBEBEBEBEB0000, 0x00F3F3F3F3F30000, 0x006D6D6D6D6D0000, +0x005E5E5E5E5E0000, 0x00FBFBFBFBFB0000, 0x0069696969690000, 0x00B2B2B2B2B20000, +0x00F0F0F0F0F00000, 0x0031313131310000, 0x000C0C0C0C0C0000, 0x00D4D4D4D4D40000, +0x00CFCFCFCFCF0000, 0x008C8C8C8C8C0000, 0x00E2E2E2E2E20000, 0x0075757575750000, +0x00A9A9A9A9A90000, 0x004A4A4A4A4A0000, 0x0057575757570000, 0x0084848484840000, +0x0011111111110000, 0x0045454545450000, 0x001B1B1B1B1B0000, 0x00F5F5F5F5F50000, +0x00E4E4E4E4E40000, 0x000E0E0E0E0E0000, 0x0073737373730000, 0x00AAAAAAAAAA0000, +0x00F1F1F1F1F10000, 0x00DDDDDDDDDD0000, 0x0059595959590000, 0x0014141414140000, +0x006C6C6C6C6C0000, 0x0092929292920000, 0x0054545454540000, 0x00D0D0D0D0D00000, +0x0078787878780000, 0x0070707070700000, 0x00E3E3E3E3E30000, 0x0049494949490000, +0x0080808080800000, 0x0050505050500000, 0x00A7A7A7A7A70000, 0x00F6F6F6F6F60000, +0x0077777777770000, 0x0093939393930000, 0x0086868686860000, 0x0083838383830000, +0x002A2A2A2A2A0000, 0x00C7C7C7C7C70000, 0x005B5B5B5B5B0000, 0x00E9E9E9E9E90000, +0x00EEEEEEEEEE0000, 0x008F8F8F8F8F0000, 0x0001010101010000, 0x003D3D3D3D3D0000 }; + +alignas(64) const uint64_t Camellia_SBOX3[256] = { +0x3800383800383800, 0x4100414100414100, 0x1600161600161600, 0x7600767600767600, +0xD900D9D900D9D900, 0x9300939300939300, 0x6000606000606000, 0xF200F2F200F2F200, +0x7200727200727200, 0xC200C2C200C2C200, 0xAB00ABAB00ABAB00, 0x9A009A9A009A9A00, +0x7500757500757500, 0x0600060600060600, 0x5700575700575700, 0xA000A0A000A0A000, +0x9100919100919100, 0xF700F7F700F7F700, 0xB500B5B500B5B500, 0xC900C9C900C9C900, +0xA200A2A200A2A200, 0x8C008C8C008C8C00, 0xD200D2D200D2D200, 0x9000909000909000, +0xF600F6F600F6F600, 0x0700070700070700, 0xA700A7A700A7A700, 0x2700272700272700, +0x8E008E8E008E8E00, 0xB200B2B200B2B200, 0x4900494900494900, 0xDE00DEDE00DEDE00, +0x4300434300434300, 0x5C005C5C005C5C00, 0xD700D7D700D7D700, 0xC700C7C700C7C700, +0x3E003E3E003E3E00, 0xF500F5F500F5F500, 0x8F008F8F008F8F00, 0x6700676700676700, +0x1F001F1F001F1F00, 0x1800181800181800, 0x6E006E6E006E6E00, 0xAF00AFAF00AFAF00, +0x2F002F2F002F2F00, 0xE200E2E200E2E200, 0x8500858500858500, 0x0D000D0D000D0D00, +0x5300535300535300, 0xF000F0F000F0F000, 0x9C009C9C009C9C00, 0x6500656500656500, +0xEA00EAEA00EAEA00, 0xA300A3A300A3A300, 0xAE00AEAE00AEAE00, 0x9E009E9E009E9E00, +0xEC00ECEC00ECEC00, 0x8000808000808000, 0x2D002D2D002D2D00, 0x6B006B6B006B6B00, +0xA800A8A800A8A800, 0x2B002B2B002B2B00, 0x3600363600363600, 0xA600A6A600A6A600, +0xC500C5C500C5C500, 0x8600868600868600, 0x4D004D4D004D4D00, 0x3300333300333300, +0xFD00FDFD00FDFD00, 0x6600666600666600, 0x5800585800585800, 0x9600969600969600, +0x3A003A3A003A3A00, 0x0900090900090900, 0x9500959500959500, 0x1000101000101000, +0x7800787800787800, 0xD800D8D800D8D800, 0x4200424200424200, 0xCC00CCCC00CCCC00, +0xEF00EFEF00EFEF00, 0x2600262600262600, 0xE500E5E500E5E500, 0x6100616100616100, +0x1A001A1A001A1A00, 0x3F003F3F003F3F00, 0x3B003B3B003B3B00, 0x8200828200828200, +0xB600B6B600B6B600, 0xDB00DBDB00DBDB00, 0xD400D4D400D4D400, 0x9800989800989800, +0xE800E8E800E8E800, 0x8B008B8B008B8B00, 0x0200020200020200, 0xEB00EBEB00EBEB00, +0x0A000A0A000A0A00, 0x2C002C2C002C2C00, 0x1D001D1D001D1D00, 0xB000B0B000B0B000, +0x6F006F6F006F6F00, 0x8D008D8D008D8D00, 0x8800888800888800, 0x0E000E0E000E0E00, +0x1900191900191900, 0x8700878700878700, 0x4E004E4E004E4E00, 0x0B000B0B000B0B00, +0xA900A9A900A9A900, 0x0C000C0C000C0C00, 0x7900797900797900, 0x1100111100111100, +0x7F007F7F007F7F00, 0x2200222200222200, 0xE700E7E700E7E700, 0x5900595900595900, +0xE100E1E100E1E100, 0xDA00DADA00DADA00, 0x3D003D3D003D3D00, 0xC800C8C800C8C800, +0x1200121200121200, 0x0400040400040400, 0x7400747400747400, 0x5400545400545400, +0x3000303000303000, 0x7E007E7E007E7E00, 0xB400B4B400B4B400, 0x2800282800282800, +0x5500555500555500, 0x6800686800686800, 0x5000505000505000, 0xBE00BEBE00BEBE00, +0xD000D0D000D0D000, 0xC400C4C400C4C400, 0x3100313100313100, 0xCB00CBCB00CBCB00, +0x2A002A2A002A2A00, 0xAD00ADAD00ADAD00, 0x0F000F0F000F0F00, 0xCA00CACA00CACA00, +0x7000707000707000, 0xFF00FFFF00FFFF00, 0x3200323200323200, 0x6900696900696900, +0x0800080800080800, 0x6200626200626200, 0x0000000000000000, 0x2400242400242400, +0xD100D1D100D1D100, 0xFB00FBFB00FBFB00, 0xBA00BABA00BABA00, 0xED00EDED00EDED00, +0x4500454500454500, 0x8100818100818100, 0x7300737300737300, 0x6D006D6D006D6D00, +0x8400848400848400, 0x9F009F9F009F9F00, 0xEE00EEEE00EEEE00, 0x4A004A4A004A4A00, +0xC300C3C300C3C300, 0x2E002E2E002E2E00, 0xC100C1C100C1C100, 0x0100010100010100, +0xE600E6E600E6E600, 0x2500252500252500, 0x4800484800484800, 0x9900999900999900, +0xB900B9B900B9B900, 0xB300B3B300B3B300, 0x7B007B7B007B7B00, 0xF900F9F900F9F900, +0xCE00CECE00CECE00, 0xBF00BFBF00BFBF00, 0xDF00DFDF00DFDF00, 0x7100717100717100, +0x2900292900292900, 0xCD00CDCD00CDCD00, 0x6C006C6C006C6C00, 0x1300131300131300, +0x6400646400646400, 0x9B009B9B009B9B00, 0x6300636300636300, 0x9D009D9D009D9D00, +0xC000C0C000C0C000, 0x4B004B4B004B4B00, 0xB700B7B700B7B700, 0xA500A5A500A5A500, +0x8900898900898900, 0x5F005F5F005F5F00, 0xB100B1B100B1B100, 0x1700171700171700, +0xF400F4F400F4F400, 0xBC00BCBC00BCBC00, 0xD300D3D300D3D300, 0x4600464600464600, +0xCF00CFCF00CFCF00, 0x3700373700373700, 0x5E005E5E005E5E00, 0x4700474700474700, +0x9400949400949400, 0xFA00FAFA00FAFA00, 0xFC00FCFC00FCFC00, 0x5B005B5B005B5B00, +0x9700979700979700, 0xFE00FEFE00FEFE00, 0x5A005A5A005A5A00, 0xAC00ACAC00ACAC00, +0x3C003C3C003C3C00, 0x4C004C4C004C4C00, 0x0300030300030300, 0x3500353500353500, +0xF300F3F300F3F300, 0x2300232300232300, 0xB800B8B800B8B800, 0x5D005D5D005D5D00, +0x6A006A6A006A6A00, 0x9200929200929200, 0xD500D5D500D5D500, 0x2100212100212100, +0x4400444400444400, 0x5100515100515100, 0xC600C6C600C6C600, 0x7D007D7D007D7D00, +0x3900393900393900, 0x8300838300838300, 0xDC00DCDC00DCDC00, 0xAA00AAAA00AAAA00, +0x7C007C7C007C7C00, 0x7700777700777700, 0x5600565600565600, 0x0500050500050500, +0x1B001B1B001B1B00, 0xA400A4A400A4A400, 0x1500151500151500, 0x3400343400343400, +0x1E001E1E001E1E00, 0x1C001C1C001C1C00, 0xF800F8F800F8F800, 0x5200525200525200, +0x2000202000202000, 0x1400141400141400, 0xE900E9E900E9E900, 0xBD00BDBD00BDBD00, +0xDD00DDDD00DDDD00, 0xE400E4E400E4E400, 0xA100A1A100A1A100, 0xE000E0E000E0E000, +0x8A008A8A008A8A00, 0xF100F1F100F1F100, 0xD600D6D600D6D600, 0x7A007A7A007A7A00, +0xBB00BBBB00BBBB00, 0xE300E3E300E3E300, 0x4000404000404000, 0x4F004F4F004F4F00 }; + +alignas(64) const uint64_t Camellia_SBOX4[256] = { +0x7070007000007070, 0x2C2C002C00002C2C, 0xB3B300B30000B3B3, 0xC0C000C00000C0C0, +0xE4E400E40000E4E4, 0x5757005700005757, 0xEAEA00EA0000EAEA, 0xAEAE00AE0000AEAE, +0x2323002300002323, 0x6B6B006B00006B6B, 0x4545004500004545, 0xA5A500A50000A5A5, +0xEDED00ED0000EDED, 0x4F4F004F00004F4F, 0x1D1D001D00001D1D, 0x9292009200009292, +0x8686008600008686, 0xAFAF00AF0000AFAF, 0x7C7C007C00007C7C, 0x1F1F001F00001F1F, +0x3E3E003E00003E3E, 0xDCDC00DC0000DCDC, 0x5E5E005E00005E5E, 0x0B0B000B00000B0B, +0xA6A600A60000A6A6, 0x3939003900003939, 0xD5D500D50000D5D5, 0x5D5D005D00005D5D, +0xD9D900D90000D9D9, 0x5A5A005A00005A5A, 0x5151005100005151, 0x6C6C006C00006C6C, +0x8B8B008B00008B8B, 0x9A9A009A00009A9A, 0xFBFB00FB0000FBFB, 0xB0B000B00000B0B0, +0x7474007400007474, 0x2B2B002B00002B2B, 0xF0F000F00000F0F0, 0x8484008400008484, +0xDFDF00DF0000DFDF, 0xCBCB00CB0000CBCB, 0x3434003400003434, 0x7676007600007676, +0x6D6D006D00006D6D, 0xA9A900A90000A9A9, 0xD1D100D10000D1D1, 0x0404000400000404, +0x1414001400001414, 0x3A3A003A00003A3A, 0xDEDE00DE0000DEDE, 0x1111001100001111, +0x3232003200003232, 0x9C9C009C00009C9C, 0x5353005300005353, 0xF2F200F20000F2F2, +0xFEFE00FE0000FEFE, 0xCFCF00CF0000CFCF, 0xC3C300C30000C3C3, 0x7A7A007A00007A7A, +0x2424002400002424, 0xE8E800E80000E8E8, 0x6060006000006060, 0x6969006900006969, +0xAAAA00AA0000AAAA, 0xA0A000A00000A0A0, 0xA1A100A10000A1A1, 0x6262006200006262, +0x5454005400005454, 0x1E1E001E00001E1E, 0xE0E000E00000E0E0, 0x6464006400006464, +0x1010001000001010, 0x0000000000000000, 0xA3A300A30000A3A3, 0x7575007500007575, +0x8A8A008A00008A8A, 0xE6E600E60000E6E6, 0x0909000900000909, 0xDDDD00DD0000DDDD, +0x8787008700008787, 0x8383008300008383, 0xCDCD00CD0000CDCD, 0x9090009000009090, +0x7373007300007373, 0xF6F600F60000F6F6, 0x9D9D009D00009D9D, 0xBFBF00BF0000BFBF, +0x5252005200005252, 0xD8D800D80000D8D8, 0xC8C800C80000C8C8, 0xC6C600C60000C6C6, +0x8181008100008181, 0x6F6F006F00006F6F, 0x1313001300001313, 0x6363006300006363, +0xE9E900E90000E9E9, 0xA7A700A70000A7A7, 0x9F9F009F00009F9F, 0xBCBC00BC0000BCBC, +0x2929002900002929, 0xF9F900F90000F9F9, 0x2F2F002F00002F2F, 0xB4B400B40000B4B4, +0x7878007800007878, 0x0606000600000606, 0xE7E700E70000E7E7, 0x7171007100007171, +0xD4D400D40000D4D4, 0xABAB00AB0000ABAB, 0x8888008800008888, 0x8D8D008D00008D8D, +0x7272007200007272, 0xB9B900B90000B9B9, 0xF8F800F80000F8F8, 0xACAC00AC0000ACAC, +0x3636003600003636, 0x2A2A002A00002A2A, 0x3C3C003C00003C3C, 0xF1F100F10000F1F1, +0x4040004000004040, 0xD3D300D30000D3D3, 0xBBBB00BB0000BBBB, 0x4343004300004343, +0x1515001500001515, 0xADAD00AD0000ADAD, 0x7777007700007777, 0x8080008000008080, +0x8282008200008282, 0xECEC00EC0000ECEC, 0x2727002700002727, 0xE5E500E50000E5E5, +0x8585008500008585, 0x3535003500003535, 0x0C0C000C00000C0C, 0x4141004100004141, +0xEFEF00EF0000EFEF, 0x9393009300009393, 0x1919001900001919, 0x2121002100002121, +0x0E0E000E00000E0E, 0x4E4E004E00004E4E, 0x6565006500006565, 0xBDBD00BD0000BDBD, +0xB8B800B80000B8B8, 0x8F8F008F00008F8F, 0xEBEB00EB0000EBEB, 0xCECE00CE0000CECE, +0x3030003000003030, 0x5F5F005F00005F5F, 0xC5C500C50000C5C5, 0x1A1A001A00001A1A, +0xE1E100E10000E1E1, 0xCACA00CA0000CACA, 0x4747004700004747, 0x3D3D003D00003D3D, +0x0101000100000101, 0xD6D600D60000D6D6, 0x5656005600005656, 0x4D4D004D00004D4D, +0x0D0D000D00000D0D, 0x6666006600006666, 0xCCCC00CC0000CCCC, 0x2D2D002D00002D2D, +0x1212001200001212, 0x2020002000002020, 0xB1B100B10000B1B1, 0x9999009900009999, +0x4C4C004C00004C4C, 0xC2C200C20000C2C2, 0x7E7E007E00007E7E, 0x0505000500000505, +0xB7B700B70000B7B7, 0x3131003100003131, 0x1717001700001717, 0xD7D700D70000D7D7, +0x5858005800005858, 0x6161006100006161, 0x1B1B001B00001B1B, 0x1C1C001C00001C1C, +0x0F0F000F00000F0F, 0x1616001600001616, 0x1818001800001818, 0x2222002200002222, +0x4444004400004444, 0xB2B200B20000B2B2, 0xB5B500B50000B5B5, 0x9191009100009191, +0x0808000800000808, 0xA8A800A80000A8A8, 0xFCFC00FC0000FCFC, 0x5050005000005050, +0xD0D000D00000D0D0, 0x7D7D007D00007D7D, 0x8989008900008989, 0x9797009700009797, +0x5B5B005B00005B5B, 0x9595009500009595, 0xFFFF00FF0000FFFF, 0xD2D200D20000D2D2, +0xC4C400C40000C4C4, 0x4848004800004848, 0xF7F700F70000F7F7, 0xDBDB00DB0000DBDB, +0x0303000300000303, 0xDADA00DA0000DADA, 0x3F3F003F00003F3F, 0x9494009400009494, +0x5C5C005C00005C5C, 0x0202000200000202, 0x4A4A004A00004A4A, 0x3333003300003333, +0x6767006700006767, 0xF3F300F30000F3F3, 0x7F7F007F00007F7F, 0xE2E200E20000E2E2, +0x9B9B009B00009B9B, 0x2626002600002626, 0x3737003700003737, 0x3B3B003B00003B3B, +0x9696009600009696, 0x4B4B004B00004B4B, 0xBEBE00BE0000BEBE, 0x2E2E002E00002E2E, +0x7979007900007979, 0x8C8C008C00008C8C, 0x6E6E006E00006E6E, 0x8E8E008E00008E8E, +0xF5F500F50000F5F5, 0xB6B600B60000B6B6, 0xFDFD00FD0000FDFD, 0x5959005900005959, +0x9898009800009898, 0x6A6A006A00006A6A, 0x4646004600004646, 0xBABA00BA0000BABA, +0x2525002500002525, 0x4242004200004242, 0xA2A200A20000A2A2, 0xFAFA00FA0000FAFA, +0x0707000700000707, 0x5555005500005555, 0xEEEE00EE0000EEEE, 0x0A0A000A00000A0A, +0x4949004900004949, 0x6868006800006868, 0x3838003800003838, 0xA4A400A40000A4A4, +0x2828002800002828, 0x7B7B007B00007B7B, 0xC9C900C90000C9C9, 0xC1C100C10000C1C1, +0xE3E300E30000E3E3, 0xF4F400F40000F4F4, 0xC7C700C70000C7C7, 0x9E9E009E00009E9E }; + +alignas(64) const uint64_t Camellia_SBOX5[256] = { +0x00E0E0E000E0E0E0, 0x0005050500050505, 0x0058585800585858, 0x00D9D9D900D9D9D9, +0x0067676700676767, 0x004E4E4E004E4E4E, 0x0081818100818181, 0x00CBCBCB00CBCBCB, +0x00C9C9C900C9C9C9, 0x000B0B0B000B0B0B, 0x00AEAEAE00AEAEAE, 0x006A6A6A006A6A6A, +0x00D5D5D500D5D5D5, 0x0018181800181818, 0x005D5D5D005D5D5D, 0x0082828200828282, +0x0046464600464646, 0x00DFDFDF00DFDFDF, 0x00D6D6D600D6D6D6, 0x0027272700272727, +0x008A8A8A008A8A8A, 0x0032323200323232, 0x004B4B4B004B4B4B, 0x0042424200424242, +0x00DBDBDB00DBDBDB, 0x001C1C1C001C1C1C, 0x009E9E9E009E9E9E, 0x009C9C9C009C9C9C, +0x003A3A3A003A3A3A, 0x00CACACA00CACACA, 0x0025252500252525, 0x007B7B7B007B7B7B, +0x000D0D0D000D0D0D, 0x0071717100717171, 0x005F5F5F005F5F5F, 0x001F1F1F001F1F1F, +0x00F8F8F800F8F8F8, 0x00D7D7D700D7D7D7, 0x003E3E3E003E3E3E, 0x009D9D9D009D9D9D, +0x007C7C7C007C7C7C, 0x0060606000606060, 0x00B9B9B900B9B9B9, 0x00BEBEBE00BEBEBE, +0x00BCBCBC00BCBCBC, 0x008B8B8B008B8B8B, 0x0016161600161616, 0x0034343400343434, +0x004D4D4D004D4D4D, 0x00C3C3C300C3C3C3, 0x0072727200727272, 0x0095959500959595, +0x00ABABAB00ABABAB, 0x008E8E8E008E8E8E, 0x00BABABA00BABABA, 0x007A7A7A007A7A7A, +0x00B3B3B300B3B3B3, 0x0002020200020202, 0x00B4B4B400B4B4B4, 0x00ADADAD00ADADAD, +0x00A2A2A200A2A2A2, 0x00ACACAC00ACACAC, 0x00D8D8D800D8D8D8, 0x009A9A9A009A9A9A, +0x0017171700171717, 0x001A1A1A001A1A1A, 0x0035353500353535, 0x00CCCCCC00CCCCCC, +0x00F7F7F700F7F7F7, 0x0099999900999999, 0x0061616100616161, 0x005A5A5A005A5A5A, +0x00E8E8E800E8E8E8, 0x0024242400242424, 0x0056565600565656, 0x0040404000404040, +0x00E1E1E100E1E1E1, 0x0063636300636363, 0x0009090900090909, 0x0033333300333333, +0x00BFBFBF00BFBFBF, 0x0098989800989898, 0x0097979700979797, 0x0085858500858585, +0x0068686800686868, 0x00FCFCFC00FCFCFC, 0x00ECECEC00ECECEC, 0x000A0A0A000A0A0A, +0x00DADADA00DADADA, 0x006F6F6F006F6F6F, 0x0053535300535353, 0x0062626200626262, +0x00A3A3A300A3A3A3, 0x002E2E2E002E2E2E, 0x0008080800080808, 0x00AFAFAF00AFAFAF, +0x0028282800282828, 0x00B0B0B000B0B0B0, 0x0074747400747474, 0x00C2C2C200C2C2C2, +0x00BDBDBD00BDBDBD, 0x0036363600363636, 0x0022222200222222, 0x0038383800383838, +0x0064646400646464, 0x001E1E1E001E1E1E, 0x0039393900393939, 0x002C2C2C002C2C2C, +0x00A6A6A600A6A6A6, 0x0030303000303030, 0x00E5E5E500E5E5E5, 0x0044444400444444, +0x00FDFDFD00FDFDFD, 0x0088888800888888, 0x009F9F9F009F9F9F, 0x0065656500656565, +0x0087878700878787, 0x006B6B6B006B6B6B, 0x00F4F4F400F4F4F4, 0x0023232300232323, +0x0048484800484848, 0x0010101000101010, 0x00D1D1D100D1D1D1, 0x0051515100515151, +0x00C0C0C000C0C0C0, 0x00F9F9F900F9F9F9, 0x00D2D2D200D2D2D2, 0x00A0A0A000A0A0A0, +0x0055555500555555, 0x00A1A1A100A1A1A1, 0x0041414100414141, 0x00FAFAFA00FAFAFA, +0x0043434300434343, 0x0013131300131313, 0x00C4C4C400C4C4C4, 0x002F2F2F002F2F2F, +0x00A8A8A800A8A8A8, 0x00B6B6B600B6B6B6, 0x003C3C3C003C3C3C, 0x002B2B2B002B2B2B, +0x00C1C1C100C1C1C1, 0x00FFFFFF00FFFFFF, 0x00C8C8C800C8C8C8, 0x00A5A5A500A5A5A5, +0x0020202000202020, 0x0089898900898989, 0x0000000000000000, 0x0090909000909090, +0x0047474700474747, 0x00EFEFEF00EFEFEF, 0x00EAEAEA00EAEAEA, 0x00B7B7B700B7B7B7, +0x0015151500151515, 0x0006060600060606, 0x00CDCDCD00CDCDCD, 0x00B5B5B500B5B5B5, +0x0012121200121212, 0x007E7E7E007E7E7E, 0x00BBBBBB00BBBBBB, 0x0029292900292929, +0x000F0F0F000F0F0F, 0x00B8B8B800B8B8B8, 0x0007070700070707, 0x0004040400040404, +0x009B9B9B009B9B9B, 0x0094949400949494, 0x0021212100212121, 0x0066666600666666, +0x00E6E6E600E6E6E6, 0x00CECECE00CECECE, 0x00EDEDED00EDEDED, 0x00E7E7E700E7E7E7, +0x003B3B3B003B3B3B, 0x00FEFEFE00FEFEFE, 0x007F7F7F007F7F7F, 0x00C5C5C500C5C5C5, +0x00A4A4A400A4A4A4, 0x0037373700373737, 0x00B1B1B100B1B1B1, 0x004C4C4C004C4C4C, +0x0091919100919191, 0x006E6E6E006E6E6E, 0x008D8D8D008D8D8D, 0x0076767600767676, +0x0003030300030303, 0x002D2D2D002D2D2D, 0x00DEDEDE00DEDEDE, 0x0096969600969696, +0x0026262600262626, 0x007D7D7D007D7D7D, 0x00C6C6C600C6C6C6, 0x005C5C5C005C5C5C, +0x00D3D3D300D3D3D3, 0x00F2F2F200F2F2F2, 0x004F4F4F004F4F4F, 0x0019191900191919, +0x003F3F3F003F3F3F, 0x00DCDCDC00DCDCDC, 0x0079797900797979, 0x001D1D1D001D1D1D, +0x0052525200525252, 0x00EBEBEB00EBEBEB, 0x00F3F3F300F3F3F3, 0x006D6D6D006D6D6D, +0x005E5E5E005E5E5E, 0x00FBFBFB00FBFBFB, 0x0069696900696969, 0x00B2B2B200B2B2B2, +0x00F0F0F000F0F0F0, 0x0031313100313131, 0x000C0C0C000C0C0C, 0x00D4D4D400D4D4D4, +0x00CFCFCF00CFCFCF, 0x008C8C8C008C8C8C, 0x00E2E2E200E2E2E2, 0x0075757500757575, +0x00A9A9A900A9A9A9, 0x004A4A4A004A4A4A, 0x0057575700575757, 0x0084848400848484, +0x0011111100111111, 0x0045454500454545, 0x001B1B1B001B1B1B, 0x00F5F5F500F5F5F5, +0x00E4E4E400E4E4E4, 0x000E0E0E000E0E0E, 0x0073737300737373, 0x00AAAAAA00AAAAAA, +0x00F1F1F100F1F1F1, 0x00DDDDDD00DDDDDD, 0x0059595900595959, 0x0014141400141414, +0x006C6C6C006C6C6C, 0x0092929200929292, 0x0054545400545454, 0x00D0D0D000D0D0D0, +0x0078787800787878, 0x0070707000707070, 0x00E3E3E300E3E3E3, 0x0049494900494949, +0x0080808000808080, 0x0050505000505050, 0x00A7A7A700A7A7A7, 0x00F6F6F600F6F6F6, +0x0077777700777777, 0x0093939300939393, 0x0086868600868686, 0x0083838300838383, +0x002A2A2A002A2A2A, 0x00C7C7C700C7C7C7, 0x005B5B5B005B5B5B, 0x00E9E9E900E9E9E9, +0x00EEEEEE00EEEEEE, 0x008F8F8F008F8F8F, 0x0001010100010101, 0x003D3D3D003D3D3D }; + +alignas(64) const uint64_t Camellia_SBOX6[256] = { +0x3800383838003838, 0x4100414141004141, 0x1600161616001616, 0x7600767676007676, +0xD900D9D9D900D9D9, 0x9300939393009393, 0x6000606060006060, 0xF200F2F2F200F2F2, +0x7200727272007272, 0xC200C2C2C200C2C2, 0xAB00ABABAB00ABAB, 0x9A009A9A9A009A9A, +0x7500757575007575, 0x0600060606000606, 0x5700575757005757, 0xA000A0A0A000A0A0, +0x9100919191009191, 0xF700F7F7F700F7F7, 0xB500B5B5B500B5B5, 0xC900C9C9C900C9C9, +0xA200A2A2A200A2A2, 0x8C008C8C8C008C8C, 0xD200D2D2D200D2D2, 0x9000909090009090, +0xF600F6F6F600F6F6, 0x0700070707000707, 0xA700A7A7A700A7A7, 0x2700272727002727, +0x8E008E8E8E008E8E, 0xB200B2B2B200B2B2, 0x4900494949004949, 0xDE00DEDEDE00DEDE, +0x4300434343004343, 0x5C005C5C5C005C5C, 0xD700D7D7D700D7D7, 0xC700C7C7C700C7C7, +0x3E003E3E3E003E3E, 0xF500F5F5F500F5F5, 0x8F008F8F8F008F8F, 0x6700676767006767, +0x1F001F1F1F001F1F, 0x1800181818001818, 0x6E006E6E6E006E6E, 0xAF00AFAFAF00AFAF, +0x2F002F2F2F002F2F, 0xE200E2E2E200E2E2, 0x8500858585008585, 0x0D000D0D0D000D0D, +0x5300535353005353, 0xF000F0F0F000F0F0, 0x9C009C9C9C009C9C, 0x6500656565006565, +0xEA00EAEAEA00EAEA, 0xA300A3A3A300A3A3, 0xAE00AEAEAE00AEAE, 0x9E009E9E9E009E9E, +0xEC00ECECEC00ECEC, 0x8000808080008080, 0x2D002D2D2D002D2D, 0x6B006B6B6B006B6B, +0xA800A8A8A800A8A8, 0x2B002B2B2B002B2B, 0x3600363636003636, 0xA600A6A6A600A6A6, +0xC500C5C5C500C5C5, 0x8600868686008686, 0x4D004D4D4D004D4D, 0x3300333333003333, +0xFD00FDFDFD00FDFD, 0x6600666666006666, 0x5800585858005858, 0x9600969696009696, +0x3A003A3A3A003A3A, 0x0900090909000909, 0x9500959595009595, 0x1000101010001010, +0x7800787878007878, 0xD800D8D8D800D8D8, 0x4200424242004242, 0xCC00CCCCCC00CCCC, +0xEF00EFEFEF00EFEF, 0x2600262626002626, 0xE500E5E5E500E5E5, 0x6100616161006161, +0x1A001A1A1A001A1A, 0x3F003F3F3F003F3F, 0x3B003B3B3B003B3B, 0x8200828282008282, +0xB600B6B6B600B6B6, 0xDB00DBDBDB00DBDB, 0xD400D4D4D400D4D4, 0x9800989898009898, +0xE800E8E8E800E8E8, 0x8B008B8B8B008B8B, 0x0200020202000202, 0xEB00EBEBEB00EBEB, +0x0A000A0A0A000A0A, 0x2C002C2C2C002C2C, 0x1D001D1D1D001D1D, 0xB000B0B0B000B0B0, +0x6F006F6F6F006F6F, 0x8D008D8D8D008D8D, 0x8800888888008888, 0x0E000E0E0E000E0E, +0x1900191919001919, 0x8700878787008787, 0x4E004E4E4E004E4E, 0x0B000B0B0B000B0B, +0xA900A9A9A900A9A9, 0x0C000C0C0C000C0C, 0x7900797979007979, 0x1100111111001111, +0x7F007F7F7F007F7F, 0x2200222222002222, 0xE700E7E7E700E7E7, 0x5900595959005959, +0xE100E1E1E100E1E1, 0xDA00DADADA00DADA, 0x3D003D3D3D003D3D, 0xC800C8C8C800C8C8, +0x1200121212001212, 0x0400040404000404, 0x7400747474007474, 0x5400545454005454, +0x3000303030003030, 0x7E007E7E7E007E7E, 0xB400B4B4B400B4B4, 0x2800282828002828, +0x5500555555005555, 0x6800686868006868, 0x5000505050005050, 0xBE00BEBEBE00BEBE, +0xD000D0D0D000D0D0, 0xC400C4C4C400C4C4, 0x3100313131003131, 0xCB00CBCBCB00CBCB, +0x2A002A2A2A002A2A, 0xAD00ADADAD00ADAD, 0x0F000F0F0F000F0F, 0xCA00CACACA00CACA, +0x7000707070007070, 0xFF00FFFFFF00FFFF, 0x3200323232003232, 0x6900696969006969, +0x0800080808000808, 0x6200626262006262, 0x0000000000000000, 0x2400242424002424, +0xD100D1D1D100D1D1, 0xFB00FBFBFB00FBFB, 0xBA00BABABA00BABA, 0xED00EDEDED00EDED, +0x4500454545004545, 0x8100818181008181, 0x7300737373007373, 0x6D006D6D6D006D6D, +0x8400848484008484, 0x9F009F9F9F009F9F, 0xEE00EEEEEE00EEEE, 0x4A004A4A4A004A4A, +0xC300C3C3C300C3C3, 0x2E002E2E2E002E2E, 0xC100C1C1C100C1C1, 0x0100010101000101, +0xE600E6E6E600E6E6, 0x2500252525002525, 0x4800484848004848, 0x9900999999009999, +0xB900B9B9B900B9B9, 0xB300B3B3B300B3B3, 0x7B007B7B7B007B7B, 0xF900F9F9F900F9F9, +0xCE00CECECE00CECE, 0xBF00BFBFBF00BFBF, 0xDF00DFDFDF00DFDF, 0x7100717171007171, +0x2900292929002929, 0xCD00CDCDCD00CDCD, 0x6C006C6C6C006C6C, 0x1300131313001313, +0x6400646464006464, 0x9B009B9B9B009B9B, 0x6300636363006363, 0x9D009D9D9D009D9D, +0xC000C0C0C000C0C0, 0x4B004B4B4B004B4B, 0xB700B7B7B700B7B7, 0xA500A5A5A500A5A5, +0x8900898989008989, 0x5F005F5F5F005F5F, 0xB100B1B1B100B1B1, 0x1700171717001717, +0xF400F4F4F400F4F4, 0xBC00BCBCBC00BCBC, 0xD300D3D3D300D3D3, 0x4600464646004646, +0xCF00CFCFCF00CFCF, 0x3700373737003737, 0x5E005E5E5E005E5E, 0x4700474747004747, +0x9400949494009494, 0xFA00FAFAFA00FAFA, 0xFC00FCFCFC00FCFC, 0x5B005B5B5B005B5B, +0x9700979797009797, 0xFE00FEFEFE00FEFE, 0x5A005A5A5A005A5A, 0xAC00ACACAC00ACAC, +0x3C003C3C3C003C3C, 0x4C004C4C4C004C4C, 0x0300030303000303, 0x3500353535003535, +0xF300F3F3F300F3F3, 0x2300232323002323, 0xB800B8B8B800B8B8, 0x5D005D5D5D005D5D, +0x6A006A6A6A006A6A, 0x9200929292009292, 0xD500D5D5D500D5D5, 0x2100212121002121, +0x4400444444004444, 0x5100515151005151, 0xC600C6C6C600C6C6, 0x7D007D7D7D007D7D, +0x3900393939003939, 0x8300838383008383, 0xDC00DCDCDC00DCDC, 0xAA00AAAAAA00AAAA, +0x7C007C7C7C007C7C, 0x7700777777007777, 0x5600565656005656, 0x0500050505000505, +0x1B001B1B1B001B1B, 0xA400A4A4A400A4A4, 0x1500151515001515, 0x3400343434003434, +0x1E001E1E1E001E1E, 0x1C001C1C1C001C1C, 0xF800F8F8F800F8F8, 0x5200525252005252, +0x2000202020002020, 0x1400141414001414, 0xE900E9E9E900E9E9, 0xBD00BDBDBD00BDBD, +0xDD00DDDDDD00DDDD, 0xE400E4E4E400E4E4, 0xA100A1A1A100A1A1, 0xE000E0E0E000E0E0, +0x8A008A8A8A008A8A, 0xF100F1F1F100F1F1, 0xD600D6D6D600D6D6, 0x7A007A7A7A007A7A, +0xBB00BBBBBB00BBBB, 0xE300E3E3E300E3E3, 0x4000404040004040, 0x4F004F4F4F004F4F }; + +alignas(64) const uint64_t Camellia_SBOX7[256] = { +0x7070007070700070, 0x2C2C002C2C2C002C, 0xB3B300B3B3B300B3, 0xC0C000C0C0C000C0, +0xE4E400E4E4E400E4, 0x5757005757570057, 0xEAEA00EAEAEA00EA, 0xAEAE00AEAEAE00AE, +0x2323002323230023, 0x6B6B006B6B6B006B, 0x4545004545450045, 0xA5A500A5A5A500A5, +0xEDED00EDEDED00ED, 0x4F4F004F4F4F004F, 0x1D1D001D1D1D001D, 0x9292009292920092, +0x8686008686860086, 0xAFAF00AFAFAF00AF, 0x7C7C007C7C7C007C, 0x1F1F001F1F1F001F, +0x3E3E003E3E3E003E, 0xDCDC00DCDCDC00DC, 0x5E5E005E5E5E005E, 0x0B0B000B0B0B000B, +0xA6A600A6A6A600A6, 0x3939003939390039, 0xD5D500D5D5D500D5, 0x5D5D005D5D5D005D, +0xD9D900D9D9D900D9, 0x5A5A005A5A5A005A, 0x5151005151510051, 0x6C6C006C6C6C006C, +0x8B8B008B8B8B008B, 0x9A9A009A9A9A009A, 0xFBFB00FBFBFB00FB, 0xB0B000B0B0B000B0, +0x7474007474740074, 0x2B2B002B2B2B002B, 0xF0F000F0F0F000F0, 0x8484008484840084, +0xDFDF00DFDFDF00DF, 0xCBCB00CBCBCB00CB, 0x3434003434340034, 0x7676007676760076, +0x6D6D006D6D6D006D, 0xA9A900A9A9A900A9, 0xD1D100D1D1D100D1, 0x0404000404040004, +0x1414001414140014, 0x3A3A003A3A3A003A, 0xDEDE00DEDEDE00DE, 0x1111001111110011, +0x3232003232320032, 0x9C9C009C9C9C009C, 0x5353005353530053, 0xF2F200F2F2F200F2, +0xFEFE00FEFEFE00FE, 0xCFCF00CFCFCF00CF, 0xC3C300C3C3C300C3, 0x7A7A007A7A7A007A, +0x2424002424240024, 0xE8E800E8E8E800E8, 0x6060006060600060, 0x6969006969690069, +0xAAAA00AAAAAA00AA, 0xA0A000A0A0A000A0, 0xA1A100A1A1A100A1, 0x6262006262620062, +0x5454005454540054, 0x1E1E001E1E1E001E, 0xE0E000E0E0E000E0, 0x6464006464640064, +0x1010001010100010, 0x0000000000000000, 0xA3A300A3A3A300A3, 0x7575007575750075, +0x8A8A008A8A8A008A, 0xE6E600E6E6E600E6, 0x0909000909090009, 0xDDDD00DDDDDD00DD, +0x8787008787870087, 0x8383008383830083, 0xCDCD00CDCDCD00CD, 0x9090009090900090, +0x7373007373730073, 0xF6F600F6F6F600F6, 0x9D9D009D9D9D009D, 0xBFBF00BFBFBF00BF, +0x5252005252520052, 0xD8D800D8D8D800D8, 0xC8C800C8C8C800C8, 0xC6C600C6C6C600C6, +0x8181008181810081, 0x6F6F006F6F6F006F, 0x1313001313130013, 0x6363006363630063, +0xE9E900E9E9E900E9, 0xA7A700A7A7A700A7, 0x9F9F009F9F9F009F, 0xBCBC00BCBCBC00BC, +0x2929002929290029, 0xF9F900F9F9F900F9, 0x2F2F002F2F2F002F, 0xB4B400B4B4B400B4, +0x7878007878780078, 0x0606000606060006, 0xE7E700E7E7E700E7, 0x7171007171710071, +0xD4D400D4D4D400D4, 0xABAB00ABABAB00AB, 0x8888008888880088, 0x8D8D008D8D8D008D, +0x7272007272720072, 0xB9B900B9B9B900B9, 0xF8F800F8F8F800F8, 0xACAC00ACACAC00AC, +0x3636003636360036, 0x2A2A002A2A2A002A, 0x3C3C003C3C3C003C, 0xF1F100F1F1F100F1, +0x4040004040400040, 0xD3D300D3D3D300D3, 0xBBBB00BBBBBB00BB, 0x4343004343430043, +0x1515001515150015, 0xADAD00ADADAD00AD, 0x7777007777770077, 0x8080008080800080, +0x8282008282820082, 0xECEC00ECECEC00EC, 0x2727002727270027, 0xE5E500E5E5E500E5, +0x8585008585850085, 0x3535003535350035, 0x0C0C000C0C0C000C, 0x4141004141410041, +0xEFEF00EFEFEF00EF, 0x9393009393930093, 0x1919001919190019, 0x2121002121210021, +0x0E0E000E0E0E000E, 0x4E4E004E4E4E004E, 0x6565006565650065, 0xBDBD00BDBDBD00BD, +0xB8B800B8B8B800B8, 0x8F8F008F8F8F008F, 0xEBEB00EBEBEB00EB, 0xCECE00CECECE00CE, +0x3030003030300030, 0x5F5F005F5F5F005F, 0xC5C500C5C5C500C5, 0x1A1A001A1A1A001A, +0xE1E100E1E1E100E1, 0xCACA00CACACA00CA, 0x4747004747470047, 0x3D3D003D3D3D003D, +0x0101000101010001, 0xD6D600D6D6D600D6, 0x5656005656560056, 0x4D4D004D4D4D004D, +0x0D0D000D0D0D000D, 0x6666006666660066, 0xCCCC00CCCCCC00CC, 0x2D2D002D2D2D002D, +0x1212001212120012, 0x2020002020200020, 0xB1B100B1B1B100B1, 0x9999009999990099, +0x4C4C004C4C4C004C, 0xC2C200C2C2C200C2, 0x7E7E007E7E7E007E, 0x0505000505050005, +0xB7B700B7B7B700B7, 0x3131003131310031, 0x1717001717170017, 0xD7D700D7D7D700D7, +0x5858005858580058, 0x6161006161610061, 0x1B1B001B1B1B001B, 0x1C1C001C1C1C001C, +0x0F0F000F0F0F000F, 0x1616001616160016, 0x1818001818180018, 0x2222002222220022, +0x4444004444440044, 0xB2B200B2B2B200B2, 0xB5B500B5B5B500B5, 0x9191009191910091, +0x0808000808080008, 0xA8A800A8A8A800A8, 0xFCFC00FCFCFC00FC, 0x5050005050500050, +0xD0D000D0D0D000D0, 0x7D7D007D7D7D007D, 0x8989008989890089, 0x9797009797970097, +0x5B5B005B5B5B005B, 0x9595009595950095, 0xFFFF00FFFFFF00FF, 0xD2D200D2D2D200D2, +0xC4C400C4C4C400C4, 0x4848004848480048, 0xF7F700F7F7F700F7, 0xDBDB00DBDBDB00DB, +0x0303000303030003, 0xDADA00DADADA00DA, 0x3F3F003F3F3F003F, 0x9494009494940094, +0x5C5C005C5C5C005C, 0x0202000202020002, 0x4A4A004A4A4A004A, 0x3333003333330033, +0x6767006767670067, 0xF3F300F3F3F300F3, 0x7F7F007F7F7F007F, 0xE2E200E2E2E200E2, +0x9B9B009B9B9B009B, 0x2626002626260026, 0x3737003737370037, 0x3B3B003B3B3B003B, +0x9696009696960096, 0x4B4B004B4B4B004B, 0xBEBE00BEBEBE00BE, 0x2E2E002E2E2E002E, +0x7979007979790079, 0x8C8C008C8C8C008C, 0x6E6E006E6E6E006E, 0x8E8E008E8E8E008E, +0xF5F500F5F5F500F5, 0xB6B600B6B6B600B6, 0xFDFD00FDFDFD00FD, 0x5959005959590059, +0x9898009898980098, 0x6A6A006A6A6A006A, 0x4646004646460046, 0xBABA00BABABA00BA, +0x2525002525250025, 0x4242004242420042, 0xA2A200A2A2A200A2, 0xFAFA00FAFAFA00FA, +0x0707000707070007, 0x5555005555550055, 0xEEEE00EEEEEE00EE, 0x0A0A000A0A0A000A, +0x4949004949490049, 0x6868006868680068, 0x3838003838380038, 0xA4A400A4A4A400A4, +0x2828002828280028, 0x7B7B007B7B7B007B, 0xC9C900C9C9C900C9, 0xC1C100C1C1C100C1, +0xE3E300E3E3E300E3, 0xF4F400F4F4F400F4, 0xC7C700C7C7C700C7, 0x9E9E009E9E9E009E }; + +alignas(64) const uint64_t Camellia_SBOX8[256] = { +0x7070700070707000, 0x8282820082828200, 0x2C2C2C002C2C2C00, 0xECECEC00ECECEC00, +0xB3B3B300B3B3B300, 0x2727270027272700, 0xC0C0C000C0C0C000, 0xE5E5E500E5E5E500, +0xE4E4E400E4E4E400, 0x8585850085858500, 0x5757570057575700, 0x3535350035353500, +0xEAEAEA00EAEAEA00, 0x0C0C0C000C0C0C00, 0xAEAEAE00AEAEAE00, 0x4141410041414100, +0x2323230023232300, 0xEFEFEF00EFEFEF00, 0x6B6B6B006B6B6B00, 0x9393930093939300, +0x4545450045454500, 0x1919190019191900, 0xA5A5A500A5A5A500, 0x2121210021212100, +0xEDEDED00EDEDED00, 0x0E0E0E000E0E0E00, 0x4F4F4F004F4F4F00, 0x4E4E4E004E4E4E00, +0x1D1D1D001D1D1D00, 0x6565650065656500, 0x9292920092929200, 0xBDBDBD00BDBDBD00, +0x8686860086868600, 0xB8B8B800B8B8B800, 0xAFAFAF00AFAFAF00, 0x8F8F8F008F8F8F00, +0x7C7C7C007C7C7C00, 0xEBEBEB00EBEBEB00, 0x1F1F1F001F1F1F00, 0xCECECE00CECECE00, +0x3E3E3E003E3E3E00, 0x3030300030303000, 0xDCDCDC00DCDCDC00, 0x5F5F5F005F5F5F00, +0x5E5E5E005E5E5E00, 0xC5C5C500C5C5C500, 0x0B0B0B000B0B0B00, 0x1A1A1A001A1A1A00, +0xA6A6A600A6A6A600, 0xE1E1E100E1E1E100, 0x3939390039393900, 0xCACACA00CACACA00, +0xD5D5D500D5D5D500, 0x4747470047474700, 0x5D5D5D005D5D5D00, 0x3D3D3D003D3D3D00, +0xD9D9D900D9D9D900, 0x0101010001010100, 0x5A5A5A005A5A5A00, 0xD6D6D600D6D6D600, +0x5151510051515100, 0x5656560056565600, 0x6C6C6C006C6C6C00, 0x4D4D4D004D4D4D00, +0x8B8B8B008B8B8B00, 0x0D0D0D000D0D0D00, 0x9A9A9A009A9A9A00, 0x6666660066666600, +0xFBFBFB00FBFBFB00, 0xCCCCCC00CCCCCC00, 0xB0B0B000B0B0B000, 0x2D2D2D002D2D2D00, +0x7474740074747400, 0x1212120012121200, 0x2B2B2B002B2B2B00, 0x2020200020202000, +0xF0F0F000F0F0F000, 0xB1B1B100B1B1B100, 0x8484840084848400, 0x9999990099999900, +0xDFDFDF00DFDFDF00, 0x4C4C4C004C4C4C00, 0xCBCBCB00CBCBCB00, 0xC2C2C200C2C2C200, +0x3434340034343400, 0x7E7E7E007E7E7E00, 0x7676760076767600, 0x0505050005050500, +0x6D6D6D006D6D6D00, 0xB7B7B700B7B7B700, 0xA9A9A900A9A9A900, 0x3131310031313100, +0xD1D1D100D1D1D100, 0x1717170017171700, 0x0404040004040400, 0xD7D7D700D7D7D700, +0x1414140014141400, 0x5858580058585800, 0x3A3A3A003A3A3A00, 0x6161610061616100, +0xDEDEDE00DEDEDE00, 0x1B1B1B001B1B1B00, 0x1111110011111100, 0x1C1C1C001C1C1C00, +0x3232320032323200, 0x0F0F0F000F0F0F00, 0x9C9C9C009C9C9C00, 0x1616160016161600, +0x5353530053535300, 0x1818180018181800, 0xF2F2F200F2F2F200, 0x2222220022222200, +0xFEFEFE00FEFEFE00, 0x4444440044444400, 0xCFCFCF00CFCFCF00, 0xB2B2B200B2B2B200, +0xC3C3C300C3C3C300, 0xB5B5B500B5B5B500, 0x7A7A7A007A7A7A00, 0x9191910091919100, +0x2424240024242400, 0x0808080008080800, 0xE8E8E800E8E8E800, 0xA8A8A800A8A8A800, +0x6060600060606000, 0xFCFCFC00FCFCFC00, 0x6969690069696900, 0x5050500050505000, +0xAAAAAA00AAAAAA00, 0xD0D0D000D0D0D000, 0xA0A0A000A0A0A000, 0x7D7D7D007D7D7D00, +0xA1A1A100A1A1A100, 0x8989890089898900, 0x6262620062626200, 0x9797970097979700, +0x5454540054545400, 0x5B5B5B005B5B5B00, 0x1E1E1E001E1E1E00, 0x9595950095959500, +0xE0E0E000E0E0E000, 0xFFFFFF00FFFFFF00, 0x6464640064646400, 0xD2D2D200D2D2D200, +0x1010100010101000, 0xC4C4C400C4C4C400, 0x0000000000000000, 0x4848480048484800, +0xA3A3A300A3A3A300, 0xF7F7F700F7F7F700, 0x7575750075757500, 0xDBDBDB00DBDBDB00, +0x8A8A8A008A8A8A00, 0x0303030003030300, 0xE6E6E600E6E6E600, 0xDADADA00DADADA00, +0x0909090009090900, 0x3F3F3F003F3F3F00, 0xDDDDDD00DDDDDD00, 0x9494940094949400, +0x8787870087878700, 0x5C5C5C005C5C5C00, 0x8383830083838300, 0x0202020002020200, +0xCDCDCD00CDCDCD00, 0x4A4A4A004A4A4A00, 0x9090900090909000, 0x3333330033333300, +0x7373730073737300, 0x6767670067676700, 0xF6F6F600F6F6F600, 0xF3F3F300F3F3F300, +0x9D9D9D009D9D9D00, 0x7F7F7F007F7F7F00, 0xBFBFBF00BFBFBF00, 0xE2E2E200E2E2E200, +0x5252520052525200, 0x9B9B9B009B9B9B00, 0xD8D8D800D8D8D800, 0x2626260026262600, +0xC8C8C800C8C8C800, 0x3737370037373700, 0xC6C6C600C6C6C600, 0x3B3B3B003B3B3B00, +0x8181810081818100, 0x9696960096969600, 0x6F6F6F006F6F6F00, 0x4B4B4B004B4B4B00, +0x1313130013131300, 0xBEBEBE00BEBEBE00, 0x6363630063636300, 0x2E2E2E002E2E2E00, +0xE9E9E900E9E9E900, 0x7979790079797900, 0xA7A7A700A7A7A700, 0x8C8C8C008C8C8C00, +0x9F9F9F009F9F9F00, 0x6E6E6E006E6E6E00, 0xBCBCBC00BCBCBC00, 0x8E8E8E008E8E8E00, +0x2929290029292900, 0xF5F5F500F5F5F500, 0xF9F9F900F9F9F900, 0xB6B6B600B6B6B600, +0x2F2F2F002F2F2F00, 0xFDFDFD00FDFDFD00, 0xB4B4B400B4B4B400, 0x5959590059595900, +0x7878780078787800, 0x9898980098989800, 0x0606060006060600, 0x6A6A6A006A6A6A00, +0xE7E7E700E7E7E700, 0x4646460046464600, 0x7171710071717100, 0xBABABA00BABABA00, +0xD4D4D400D4D4D400, 0x2525250025252500, 0xABABAB00ABABAB00, 0x4242420042424200, +0x8888880088888800, 0xA2A2A200A2A2A200, 0x8D8D8D008D8D8D00, 0xFAFAFA00FAFAFA00, +0x7272720072727200, 0x0707070007070700, 0xB9B9B900B9B9B900, 0x5555550055555500, +0xF8F8F800F8F8F800, 0xEEEEEE00EEEEEE00, 0xACACAC00ACACAC00, 0x0A0A0A000A0A0A00, +0x3636360036363600, 0x4949490049494900, 0x2A2A2A002A2A2A00, 0x6868680068686800, +0x3C3C3C003C3C3C00, 0x3838380038383800, 0xF1F1F100F1F1F100, 0xA4A4A400A4A4A400, +0x4040400040404000, 0x2828280028282800, 0xD3D3D300D3D3D300, 0x7B7B7B007B7B7B00, +0xBBBBBB00BBBBBB00, 0xC9C9C900C9C9C900, 0x4343430043434300, 0xC1C1C100C1C1C100, +0x1515150015151500, 0xE3E3E300E3E3E300, 0xADADAD00ADADAD00, 0xF4F4F400F4F4F400, +0x7777770077777700, 0xC7C7C700C7C7C700, 0x8080800080808000, 0x9E9E9E009E9E9E00 }; + +namespace Camellia_F { + +/* +* We use the slow byte-wise version of F in the first and last rounds +* to help protect against side channels analyzing cache hits on the +* larger sbox tables. +*/ +uint64_t F_SLOW(uint64_t v, uint64_t K) + { + alignas(64) + static const uint8_t SBOX[256] = { + 0x70, 0x82, 0x2C, 0xEC, 0xB3, 0x27, 0xC0, 0xE5, 0xE4, 0x85, 0x57, + 0x35, 0xEA, 0x0C, 0xAE, 0x41, 0x23, 0xEF, 0x6B, 0x93, 0x45, 0x19, + 0xA5, 0x21, 0xED, 0x0E, 0x4F, 0x4E, 0x1D, 0x65, 0x92, 0xBD, 0x86, + 0xB8, 0xAF, 0x8F, 0x7C, 0xEB, 0x1F, 0xCE, 0x3E, 0x30, 0xDC, 0x5F, + 0x5E, 0xC5, 0x0B, 0x1A, 0xA6, 0xE1, 0x39, 0xCA, 0xD5, 0x47, 0x5D, + 0x3D, 0xD9, 0x01, 0x5A, 0xD6, 0x51, 0x56, 0x6C, 0x4D, 0x8B, 0x0D, + 0x9A, 0x66, 0xFB, 0xCC, 0xB0, 0x2D, 0x74, 0x12, 0x2B, 0x20, 0xF0, + 0xB1, 0x84, 0x99, 0xDF, 0x4C, 0xCB, 0xC2, 0x34, 0x7E, 0x76, 0x05, + 0x6D, 0xB7, 0xA9, 0x31, 0xD1, 0x17, 0x04, 0xD7, 0x14, 0x58, 0x3A, + 0x61, 0xDE, 0x1B, 0x11, 0x1C, 0x32, 0x0F, 0x9C, 0x16, 0x53, 0x18, + 0xF2, 0x22, 0xFE, 0x44, 0xCF, 0xB2, 0xC3, 0xB5, 0x7A, 0x91, 0x24, + 0x08, 0xE8, 0xA8, 0x60, 0xFC, 0x69, 0x50, 0xAA, 0xD0, 0xA0, 0x7D, + 0xA1, 0x89, 0x62, 0x97, 0x54, 0x5B, 0x1E, 0x95, 0xE0, 0xFF, 0x64, + 0xD2, 0x10, 0xC4, 0x00, 0x48, 0xA3, 0xF7, 0x75, 0xDB, 0x8A, 0x03, + 0xE6, 0xDA, 0x09, 0x3F, 0xDD, 0x94, 0x87, 0x5C, 0x83, 0x02, 0xCD, + 0x4A, 0x90, 0x33, 0x73, 0x67, 0xF6, 0xF3, 0x9D, 0x7F, 0xBF, 0xE2, + 0x52, 0x9B, 0xD8, 0x26, 0xC8, 0x37, 0xC6, 0x3B, 0x81, 0x96, 0x6F, + 0x4B, 0x13, 0xBE, 0x63, 0x2E, 0xE9, 0x79, 0xA7, 0x8C, 0x9F, 0x6E, + 0xBC, 0x8E, 0x29, 0xF5, 0xF9, 0xB6, 0x2F, 0xFD, 0xB4, 0x59, 0x78, + 0x98, 0x06, 0x6A, 0xE7, 0x46, 0x71, 0xBA, 0xD4, 0x25, 0xAB, 0x42, + 0x88, 0xA2, 0x8D, 0xFA, 0x72, 0x07, 0xB9, 0x55, 0xF8, 0xEE, 0xAC, + 0x0A, 0x36, 0x49, 0x2A, 0x68, 0x3C, 0x38, 0xF1, 0xA4, 0x40, 0x28, + 0xD3, 0x7B, 0xBB, 0xC9, 0x43, 0xC1, 0x15, 0xE3, 0xAD, 0xF4, 0x77, + 0xC7, 0x80, 0x9E }; + + const uint64_t x = v ^ K; + + const uint8_t t1 = SBOX[get_byte(0, x)]; + const uint8_t t2 = rotl<1>(SBOX[get_byte(1, x)]); + const uint8_t t3 = rotl<7>(SBOX[get_byte(2, x)]); + const uint8_t t4 = SBOX[rotl<1>(get_byte(3, x))]; + const uint8_t t5 = rotl<1>(SBOX[get_byte(4, x)]); + const uint8_t t6 = rotl<7>(SBOX[get_byte(5, x)]); + const uint8_t t7 = SBOX[rotl<1>(get_byte(6, x))]; + const uint8_t t8 = SBOX[get_byte(7, x)]; + + const uint8_t y1 = t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8; + const uint8_t y2 = t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8; + const uint8_t y3 = t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8; + const uint8_t y4 = t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7; + const uint8_t y5 = t1 ^ t2 ^ t6 ^ t7 ^ t8; + const uint8_t y6 = t2 ^ t3 ^ t5 ^ t7 ^ t8; + const uint8_t y7 = t3 ^ t4 ^ t5 ^ t6 ^ t8; + const uint8_t y8 = t1 ^ t4 ^ t5 ^ t6 ^ t7; + + return make_uint64(y1, y2, y3, y4, y5, y6, y7, y8); + } + +inline uint64_t F(uint64_t v, uint64_t K) + { + const uint64_t x = v ^ K; + + return Camellia_SBOX1[get_byte(0, x)] ^ + Camellia_SBOX2[get_byte(1, x)] ^ + Camellia_SBOX3[get_byte(2, x)] ^ + Camellia_SBOX4[get_byte(3, x)] ^ + Camellia_SBOX5[get_byte(4, x)] ^ + Camellia_SBOX6[get_byte(5, x)] ^ + Camellia_SBOX7[get_byte(6, x)] ^ + Camellia_SBOX8[get_byte(7, x)]; + } + +inline uint64_t FL(uint64_t v, uint64_t K) + { + uint32_t x1 = static_cast(v >> 32); + uint32_t x2 = static_cast(v & 0xFFFFFFFF); + + const uint32_t k1 = static_cast(K >> 32); + const uint32_t k2 = static_cast(K & 0xFFFFFFFF); + + x2 ^= rotl<1>(x1 & k1); + x1 ^= (x2 | k2); + + return ((static_cast(x1) << 32) | x2); + } + +inline uint64_t FLINV(uint64_t v, uint64_t K) + { + uint32_t x1 = static_cast(v >> 32); + uint32_t x2 = static_cast(v & 0xFFFFFFFF); + + const uint32_t k1 = static_cast(K >> 32); + const uint32_t k2 = static_cast(K & 0xFFFFFFFF); + + x1 ^= (x2 | k2); + x2 ^= rotl<1>(x1 & k1); + + return ((static_cast(x1) << 32) | x2); + } + +/* +* Camellia Encryption +*/ +void encrypt(const uint8_t in[], uint8_t out[], size_t blocks, + const secure_vector& SK, const size_t rounds) + { + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) + { + uint64_t D1, D2; + load_be(in + 16*i, D1, D2); + + const uint64_t* K = SK.data(); + + D1 ^= *K++; + D2 ^= *K++; + + D2 ^= F_SLOW(D1, *K++); + D1 ^= F_SLOW(D2, *K++); + + for(size_t r = 1; r != rounds - 1; ++r) + { + if(r % 3 == 0) + { + D1 = FL (D1, *K++); + D2 = FLINV(D2, *K++); + } + + D2 ^= F(D1, *K++); + D1 ^= F(D2, *K++); + } + + D2 ^= F_SLOW(D1, *K++); + D1 ^= F_SLOW(D2, *K++); + + D2 ^= *K++; + D1 ^= *K++; + + store_be(out + 16*i, D2, D1); + } + } + +/* +* Camellia Decryption +*/ +void decrypt(const uint8_t in[], uint8_t out[], size_t blocks, + const secure_vector& SK, const size_t rounds) + { + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) + { + uint64_t D1, D2; + load_be(in + 16*i, D1, D2); + + const uint64_t* K = &SK[SK.size()-1]; + + D2 ^= *K--; + D1 ^= *K--; + + D2 ^= F_SLOW(D1, *K--); + D1 ^= F_SLOW(D2, *K--); + + for(size_t r = 1; r != rounds - 1; ++r) + { + if(r % 3 == 0) + { + D1 = FL (D1, *K--); + D2 = FLINV(D2, *K--); + } + + D2 ^= F(D1, *K--); + D1 ^= F(D2, *K--); + } + + D2 ^= F_SLOW(D1, *K--); + D1 ^= F_SLOW(D2, *K--); + + D1 ^= *K--; + D2 ^= *K; + + store_be(out + 16*i, D2, D1); + } + } + +uint64_t left_rot_hi(uint64_t h, uint64_t l, size_t shift) + { + return (h << shift) | (l >> (64-shift)); + } + +uint64_t left_rot_lo(uint64_t h, uint64_t l, size_t shift) + { + return (h >> (64-shift)) | (l << shift); + } + +/* +* Camellia Key Schedule +*/ +void key_schedule(secure_vector& SK, const uint8_t key[], size_t length) + { + const uint64_t Sigma1 = 0xA09E667F3BCC908B; + const uint64_t Sigma2 = 0xB67AE8584CAA73B2; + const uint64_t Sigma3 = 0xC6EF372FE94F82BE; + const uint64_t Sigma4 = 0x54FF53A5F1D36F1C; + const uint64_t Sigma5 = 0x10E527FADE682D1D; + const uint64_t Sigma6 = 0xB05688C2B3E6C1FD; + + const uint64_t KL_H = load_be(key, 0); + const uint64_t KL_L = load_be(key, 1); + + const uint64_t KR_H = (length >= 24) ? load_be(key, 2) : 0; + const uint64_t KR_L = + (length == 32) ? load_be(key, 3) : ((length == 24) ? ~KR_H : 0); + + uint64_t D1 = KL_H ^ KR_H; + uint64_t D2 = KL_L ^ KR_L; + D2 ^= F(D1, Sigma1); + D1 ^= F(D2, Sigma2); + D1 ^= KL_H; + D2 ^= KL_L; + D2 ^= F(D1, Sigma3); + D1 ^= F(D2, Sigma4); + + const uint64_t KA_H = D1; + const uint64_t KA_L = D2; + + D1 = KA_H ^ KR_H; + D2 = KA_L ^ KR_L; + D2 ^= F(D1, Sigma5); + D1 ^= F(D2, Sigma6); + + const uint64_t KB_H = D1; + const uint64_t KB_L = D2; + + if(length == 16) + { + SK.resize(26); + + SK[ 0] = KL_H; + SK[ 1] = KL_L; + SK[ 2] = KA_H; + SK[ 3] = KA_L; + SK[ 4] = left_rot_hi(KL_H, KL_L, 15); + SK[ 5] = left_rot_lo(KL_H, KL_L, 15); + SK[ 6] = left_rot_hi(KA_H, KA_L, 15); + SK[ 7] = left_rot_lo(KA_H, KA_L, 15); + SK[ 8] = left_rot_hi(KA_H, KA_L, 30); + SK[ 9] = left_rot_lo(KA_H, KA_L, 30); + SK[10] = left_rot_hi(KL_H, KL_L, 45); + SK[11] = left_rot_lo(KL_H, KL_L, 45); + SK[12] = left_rot_hi(KA_H, KA_L, 45); + SK[13] = left_rot_lo(KL_H, KL_L, 60); + SK[14] = left_rot_hi(KA_H, KA_L, 60); + SK[15] = left_rot_lo(KA_H, KA_L, 60); + SK[16] = left_rot_lo(KL_H, KL_L, 77-64); + SK[17] = left_rot_hi(KL_H, KL_L, 77-64); + SK[18] = left_rot_lo(KL_H, KL_L, 94-64); + SK[19] = left_rot_hi(KL_H, KL_L, 94-64); + SK[20] = left_rot_lo(KA_H, KA_L, 94-64); + SK[21] = left_rot_hi(KA_H, KA_L, 94-64); + SK[22] = left_rot_lo(KL_H, KL_L, 111-64); + SK[23] = left_rot_hi(KL_H, KL_L, 111-64); + SK[24] = left_rot_lo(KA_H, KA_L, 111-64); + SK[25] = left_rot_hi(KA_H, KA_L, 111-64); + } + else + { + SK.resize(34); + + SK[ 0] = KL_H; + SK[ 1] = KL_L; + SK[ 2] = KB_H; + SK[ 3] = KB_L; + + SK[ 4] = left_rot_hi(KR_H, KR_L, 15); + SK[ 5] = left_rot_lo(KR_H, KR_L, 15); + SK[ 6] = left_rot_hi(KA_H, KA_L, 15); + SK[ 7] = left_rot_lo(KA_H, KA_L, 15); + + SK[ 8] = left_rot_hi(KR_H, KR_L, 30); + SK[ 9] = left_rot_lo(KR_H, KR_L, 30); + SK[10] = left_rot_hi(KB_H, KB_L, 30); + SK[11] = left_rot_lo(KB_H, KB_L, 30); + + SK[12] = left_rot_hi(KL_H, KL_L, 45); + SK[13] = left_rot_lo(KL_H, KL_L, 45); + SK[14] = left_rot_hi(KA_H, KA_L, 45); + SK[15] = left_rot_lo(KA_H, KA_L, 45); + + SK[16] = left_rot_hi(KL_H, KL_L, 60); + SK[17] = left_rot_lo(KL_H, KL_L, 60); + SK[18] = left_rot_hi(KR_H, KR_L, 60); + SK[19] = left_rot_lo(KR_H, KR_L, 60); + SK[20] = left_rot_hi(KB_H, KB_L, 60); + SK[21] = left_rot_lo(KB_H, KB_L, 60); + + SK[22] = left_rot_lo(KL_H, KL_L, 77-64); + SK[23] = left_rot_hi(KL_H, KL_L, 77-64); + SK[24] = left_rot_lo(KA_H, KA_L, 77-64); + SK[25] = left_rot_hi(KA_H, KA_L, 77-64); + + SK[26] = left_rot_lo(KR_H, KR_L, 94-64); + SK[27] = left_rot_hi(KR_H, KR_L, 94-64); + SK[28] = left_rot_lo(KA_H, KA_L, 94-64); + SK[29] = left_rot_hi(KA_H, KA_L, 94-64); + SK[30] = left_rot_lo(KL_H, KL_L, 111-64); + SK[31] = left_rot_hi(KL_H, KL_L, 111-64); + SK[32] = left_rot_lo(KB_H, KB_L, 111-64); + SK[33] = left_rot_hi(KB_H, KB_L, 111-64); + } + } + +} + +} + +void Camellia_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SK.empty() == false); + Camellia_F::encrypt(in, out, blocks, m_SK, 9); + } + +void Camellia_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SK.empty() == false); + Camellia_F::encrypt(in, out, blocks, m_SK, 12); + } + +void Camellia_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SK.empty() == false); + Camellia_F::encrypt(in, out, blocks, m_SK, 12); + } + +void Camellia_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SK.empty() == false); + Camellia_F::decrypt(in, out, blocks, m_SK, 9); + } + +void Camellia_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SK.empty() == false); + Camellia_F::decrypt(in, out, blocks, m_SK, 12); + } + +void Camellia_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SK.empty() == false); + Camellia_F::decrypt(in, out, blocks, m_SK, 12); + } + +void Camellia_128::key_schedule(const uint8_t key[], size_t length) + { + Camellia_F::key_schedule(m_SK, key, length); + } + +void Camellia_192::key_schedule(const uint8_t key[], size_t length) + { + Camellia_F::key_schedule(m_SK, key, length); + } + +void Camellia_256::key_schedule(const uint8_t key[], size_t length) + { + Camellia_F::key_schedule(m_SK, key, length); + } + +void Camellia_128::clear() + { + zap(m_SK); + } + +void Camellia_192::clear() + { + zap(m_SK); + } + +void Camellia_256::clear() + { + zap(m_SK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/camellia/camellia.h b/comm/third_party/botan/src/lib/block/camellia/camellia.h new file mode 100644 index 0000000000..4995eb0c93 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/camellia/camellia.h @@ -0,0 +1,73 @@ +/* +* Camellia +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CAMELLIA_H_ +#define BOTAN_CAMELLIA_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(camellia.h) + +namespace Botan { + +/** +* Camellia-128 +*/ +class BOTAN_PUBLIC_API(2,0) Camellia_128 final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "Camellia-128"; } + BlockCipher* clone() const override { return new Camellia_128; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_SK; + }; + +/** +* Camellia-192 +*/ +class BOTAN_PUBLIC_API(2,0) Camellia_192 final : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "Camellia-192"; } + BlockCipher* clone() const override { return new Camellia_192; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_SK; + }; + +/** +* Camellia-256 +*/ +class BOTAN_PUBLIC_API(2,0) Camellia_256 final : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "Camellia-256"; } + BlockCipher* clone() const override { return new Camellia_256; } + private: + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_SK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/camellia/info.txt b/comm/third_party/botan/src/lib/block/camellia/info.txt new file mode 100644 index 0000000000..c70a7f3451 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/camellia/info.txt @@ -0,0 +1,7 @@ + +CAMELLIA -> 20150922 + + + +camellia.h + diff --git a/comm/third_party/botan/src/lib/block/cascade/cascade.cpp b/comm/third_party/botan/src/lib/block/cascade/cascade.cpp new file mode 100644 index 0000000000..6607fd5b27 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cascade/cascade.cpp @@ -0,0 +1,93 @@ +/* +* Block Cipher Cascade +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +void Cascade_Cipher::encrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks) const + { + size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size()); + size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size()); + + m_cipher1->encrypt_n(in, out, c1_blocks); + m_cipher2->encrypt_n(out, out, c2_blocks); + } + +void Cascade_Cipher::decrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks) const + { + size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size()); + size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size()); + + m_cipher2->decrypt_n(in, out, c2_blocks); + m_cipher1->decrypt_n(out, out, c1_blocks); + } + +void Cascade_Cipher::key_schedule(const uint8_t key[], size_t) + { + const uint8_t* key2 = key + m_cipher1->maximum_keylength(); + + m_cipher1->set_key(key , m_cipher1->maximum_keylength()); + m_cipher2->set_key(key2, m_cipher2->maximum_keylength()); + } + +void Cascade_Cipher::clear() + { + m_cipher1->clear(); + m_cipher2->clear(); + } + +std::string Cascade_Cipher::name() const + { + return "Cascade(" + m_cipher1->name() + "," + m_cipher2->name() + ")"; + } + +BlockCipher* Cascade_Cipher::clone() const + { + return new Cascade_Cipher(m_cipher1->clone(), + m_cipher2->clone()); + } + +namespace { + +size_t euclids_algorithm(size_t a, size_t b) + { + while(b != 0) + { + size_t t = b; + b = a % b; + a = t; + } + + return a; + } + +size_t block_size_for_cascade(size_t bs, size_t bs2) + { + if(bs == bs2) + return bs; + + const size_t gcd = euclids_algorithm(bs, bs2); + + return (bs * bs2) / gcd; + } + +} + +Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) : + m_cipher1(c1), m_cipher2(c2) + { + m_block = block_size_for_cascade(c1->block_size(), c2->block_size()); + + BOTAN_ASSERT(m_block % c1->block_size() == 0 && + m_block % c2->block_size() == 0, + "Combined block size is a multiple of each ciphers block"); + } + +} diff --git a/comm/third_party/botan/src/lib/block/cascade/cascade.h b/comm/third_party/botan/src/lib/block/cascade/cascade.h new file mode 100644 index 0000000000..26f5133811 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cascade/cascade.h @@ -0,0 +1,57 @@ +/* +* Block Cipher Cascade +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CASCADE_H_ +#define BOTAN_CASCADE_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cascade.h) + +namespace Botan { + +/** +* Block Cipher Cascade +*/ +class BOTAN_PUBLIC_API(2,0) Cascade_Cipher final : public BlockCipher + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + size_t block_size() const override { return m_block; } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(m_cipher1->maximum_keylength() + + m_cipher2->maximum_keylength()); + } + + void clear() override; + std::string name() const override; + BlockCipher* clone() const override; + + /** + * Create a cascade of two block ciphers + * @param cipher1 the first cipher + * @param cipher2 the second cipher + */ + Cascade_Cipher(BlockCipher* cipher1, BlockCipher* cipher2); + + Cascade_Cipher(const Cascade_Cipher&) = delete; + Cascade_Cipher& operator=(const Cascade_Cipher&) = delete; + private: + void key_schedule(const uint8_t[], size_t) override; + + size_t m_block; + std::unique_ptr m_cipher1, m_cipher2; + }; + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/cascade/info.txt b/comm/third_party/botan/src/lib/block/cascade/info.txt new file mode 100644 index 0000000000..15f5b22627 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cascade/info.txt @@ -0,0 +1,7 @@ + +CASCADE -> 20131128 + + + +cascade.h + diff --git a/comm/third_party/botan/src/lib/block/cast128/cast128.cpp b/comm/third_party/botan/src/lib/block/cast128/cast128.cpp new file mode 100644 index 0000000000..bcb273be7a --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast128/cast128.cpp @@ -0,0 +1,471 @@ +/* +* CAST-128 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* CAST-128 Round Type 1 +*/ +inline uint32_t F1(uint32_t R, uint32_t MK, uint8_t RK) + { + const uint32_t T = rotl_var(MK + R, RK); + return (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) - + CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-128 Round Type 2 +*/ +inline uint32_t F2(uint32_t R, uint32_t MK, uint8_t RK) + { + const uint32_t T = rotl_var(MK ^ R, RK); + return (CAST_SBOX1[get_byte(0, T)] - CAST_SBOX2[get_byte(1, T)] + + CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-128 Round Type 3 +*/ +inline uint32_t F3(uint32_t R, uint32_t MK, uint8_t RK) + { + const uint32_t T = rotl_var(MK - R, RK); + return ((CAST_SBOX1[get_byte(0, T)] + CAST_SBOX2[get_byte(1, T)]) ^ + CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)]; + } + +} + +/* +* CAST-128 Encryption +*/ +void CAST_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0, L1, R1; + load_be(in, L0, R0, L1, R1); + + L0 ^= F1(R0, m_MK[ 0], m_RK[ 0]); + L1 ^= F1(R1, m_MK[ 0], m_RK[ 0]); + R0 ^= F2(L0, m_MK[ 1], m_RK[ 1]); + R1 ^= F2(L1, m_MK[ 1], m_RK[ 1]); + L0 ^= F3(R0, m_MK[ 2], m_RK[ 2]); + L1 ^= F3(R1, m_MK[ 2], m_RK[ 2]); + R0 ^= F1(L0, m_MK[ 3], m_RK[ 3]); + R1 ^= F1(L1, m_MK[ 3], m_RK[ 3]); + L0 ^= F2(R0, m_MK[ 4], m_RK[ 4]); + L1 ^= F2(R1, m_MK[ 4], m_RK[ 4]); + R0 ^= F3(L0, m_MK[ 5], m_RK[ 5]); + R1 ^= F3(L1, m_MK[ 5], m_RK[ 5]); + L0 ^= F1(R0, m_MK[ 6], m_RK[ 6]); + L1 ^= F1(R1, m_MK[ 6], m_RK[ 6]); + R0 ^= F2(L0, m_MK[ 7], m_RK[ 7]); + R1 ^= F2(L1, m_MK[ 7], m_RK[ 7]); + L0 ^= F3(R0, m_MK[ 8], m_RK[ 8]); + L1 ^= F3(R1, m_MK[ 8], m_RK[ 8]); + R0 ^= F1(L0, m_MK[ 9], m_RK[ 9]); + R1 ^= F1(L1, m_MK[ 9], m_RK[ 9]); + L0 ^= F2(R0, m_MK[10], m_RK[10]); + L1 ^= F2(R1, m_MK[10], m_RK[10]); + R0 ^= F3(L0, m_MK[11], m_RK[11]); + R1 ^= F3(L1, m_MK[11], m_RK[11]); + L0 ^= F1(R0, m_MK[12], m_RK[12]); + L1 ^= F1(R1, m_MK[12], m_RK[12]); + R0 ^= F2(L0, m_MK[13], m_RK[13]); + R1 ^= F2(L1, m_MK[13], m_RK[13]); + L0 ^= F3(R0, m_MK[14], m_RK[14]); + L1 ^= F3(R1, m_MK[14], m_RK[14]); + R0 ^= F1(L0, m_MK[15], m_RK[15]); + R1 ^= F1(L1, m_MK[15], m_RK[15]); + + store_be(out, R0, L0, R1, L1); + + blocks -= 2; + out += 2 * BLOCK_SIZE; + in += 2 * BLOCK_SIZE; + } + + if(blocks) + { + uint32_t L, R; + load_be(in, L, R); + + L ^= F1(R, m_MK[ 0], m_RK[ 0]); + R ^= F2(L, m_MK[ 1], m_RK[ 1]); + L ^= F3(R, m_MK[ 2], m_RK[ 2]); + R ^= F1(L, m_MK[ 3], m_RK[ 3]); + L ^= F2(R, m_MK[ 4], m_RK[ 4]); + R ^= F3(L, m_MK[ 5], m_RK[ 5]); + L ^= F1(R, m_MK[ 6], m_RK[ 6]); + R ^= F2(L, m_MK[ 7], m_RK[ 7]); + L ^= F3(R, m_MK[ 8], m_RK[ 8]); + R ^= F1(L, m_MK[ 9], m_RK[ 9]); + L ^= F2(R, m_MK[10], m_RK[10]); + R ^= F3(L, m_MK[11], m_RK[11]); + L ^= F1(R, m_MK[12], m_RK[12]); + R ^= F2(L, m_MK[13], m_RK[13]); + L ^= F3(R, m_MK[14], m_RK[14]); + R ^= F1(L, m_MK[15], m_RK[15]); + + store_be(out, R, L); + } + } + +/* +* CAST-128 Decryption +*/ +void CAST_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0, L1, R1; + load_be(in, L0, R0, L1, R1); + + L0 ^= F1(R0, m_MK[15], m_RK[15]); + L1 ^= F1(R1, m_MK[15], m_RK[15]); + R0 ^= F3(L0, m_MK[14], m_RK[14]); + R1 ^= F3(L1, m_MK[14], m_RK[14]); + L0 ^= F2(R0, m_MK[13], m_RK[13]); + L1 ^= F2(R1, m_MK[13], m_RK[13]); + R0 ^= F1(L0, m_MK[12], m_RK[12]); + R1 ^= F1(L1, m_MK[12], m_RK[12]); + L0 ^= F3(R0, m_MK[11], m_RK[11]); + L1 ^= F3(R1, m_MK[11], m_RK[11]); + R0 ^= F2(L0, m_MK[10], m_RK[10]); + R1 ^= F2(L1, m_MK[10], m_RK[10]); + L0 ^= F1(R0, m_MK[ 9], m_RK[ 9]); + L1 ^= F1(R1, m_MK[ 9], m_RK[ 9]); + R0 ^= F3(L0, m_MK[ 8], m_RK[ 8]); + R1 ^= F3(L1, m_MK[ 8], m_RK[ 8]); + L0 ^= F2(R0, m_MK[ 7], m_RK[ 7]); + L1 ^= F2(R1, m_MK[ 7], m_RK[ 7]); + R0 ^= F1(L0, m_MK[ 6], m_RK[ 6]); + R1 ^= F1(L1, m_MK[ 6], m_RK[ 6]); + L0 ^= F3(R0, m_MK[ 5], m_RK[ 5]); + L1 ^= F3(R1, m_MK[ 5], m_RK[ 5]); + R0 ^= F2(L0, m_MK[ 4], m_RK[ 4]); + R1 ^= F2(L1, m_MK[ 4], m_RK[ 4]); + L0 ^= F1(R0, m_MK[ 3], m_RK[ 3]); + L1 ^= F1(R1, m_MK[ 3], m_RK[ 3]); + R0 ^= F3(L0, m_MK[ 2], m_RK[ 2]); + R1 ^= F3(L1, m_MK[ 2], m_RK[ 2]); + L0 ^= F2(R0, m_MK[ 1], m_RK[ 1]); + L1 ^= F2(R1, m_MK[ 1], m_RK[ 1]); + R0 ^= F1(L0, m_MK[ 0], m_RK[ 0]); + R1 ^= F1(L1, m_MK[ 0], m_RK[ 0]); + + store_be(out, R0, L0, R1, L1); + + blocks -= 2; + out += 2 * BLOCK_SIZE; + in += 2 * BLOCK_SIZE; + } + + if(blocks) + { + uint32_t L, R; + load_be(in, L, R); + + L ^= F1(R, m_MK[15], m_RK[15]); + R ^= F3(L, m_MK[14], m_RK[14]); + L ^= F2(R, m_MK[13], m_RK[13]); + R ^= F1(L, m_MK[12], m_RK[12]); + L ^= F3(R, m_MK[11], m_RK[11]); + R ^= F2(L, m_MK[10], m_RK[10]); + L ^= F1(R, m_MK[ 9], m_RK[ 9]); + R ^= F3(L, m_MK[ 8], m_RK[ 8]); + L ^= F2(R, m_MK[ 7], m_RK[ 7]); + R ^= F1(L, m_MK[ 6], m_RK[ 6]); + L ^= F3(R, m_MK[ 5], m_RK[ 5]); + R ^= F2(L, m_MK[ 4], m_RK[ 4]); + L ^= F1(R, m_MK[ 3], m_RK[ 3]); + R ^= F3(L, m_MK[ 2], m_RK[ 2]); + L ^= F2(R, m_MK[ 1], m_RK[ 1]); + R ^= F1(L, m_MK[ 0], m_RK[ 0]); + + store_be(out, R, L); + } + } + +/* +* CAST-128 Key Schedule +*/ +void CAST_128::key_schedule(const uint8_t key[], size_t length) + { + m_MK.resize(48); + m_RK.resize(48); + + secure_vector key16(16); + copy_mem(key16.data(), key, length); + + secure_vector X(4); + for(size_t i = 0; i != 4; ++i) + X[i] = load_be(key16.data(), i); + + cast_ks(m_MK, X); + + secure_vector RK32(48); + cast_ks(RK32, X); + + for(size_t i = 0; i != 16; ++i) + m_RK[i] = RK32[i] % 32; + } + +void CAST_128::clear() + { + zap(m_MK); + zap(m_RK); + } + +/* +* S-Box Based Key Expansion +*/ +void CAST_128::cast_ks(secure_vector& K, + secure_vector& X) + { + alignas(64) static const uint32_t S5[256] = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, + 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, + 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, + 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, + 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, + 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, + 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, + 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, + 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, + 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, + 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, + 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, + 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, + 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, + 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, + 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, + 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, + 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, + 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, + 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, + 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, + 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; + + alignas(64) static const uint32_t S6[256] = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, + 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, + 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, + 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, + 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, + 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, + 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, + 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, + 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, + 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, + 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, + 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, + 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, + 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, + 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, + 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, + 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, + 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, + 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, + 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, + 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, + 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; + + alignas(64) static const uint32_t S7[256] = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, + 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, + 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, + 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, + 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, + 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, + 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, + 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, + 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, + 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, + 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, + 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, + 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, + 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, + 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, + 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, + 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, + 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, + 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, + 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, + 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, + 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; + + alignas(64) static const uint32_t S8[256] = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, + 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, + 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, + 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, + 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, + 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, + 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, + 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, + 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, + 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, + 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, + 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, + 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, + 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, + 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, + 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, + 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, + 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, + 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, + 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, + 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, + 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; + + class ByteReader final + { + public: + uint8_t operator()(size_t i) const + { + return static_cast(m_X[i/4] >> (8*(3 - (i%4)))); + } + + explicit ByteReader(const uint32_t* x) : m_X(x) {} + private: + const uint32_t* m_X; + }; + + secure_vector Z(4); + ByteReader x(X.data()), z(Z.data()); + + Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; + Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; + Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; + Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; + K[ 0] = S5[z( 8)] ^ S6[z( 9)] ^ S7[z( 7)] ^ S8[z( 6)] ^ S5[z( 2)]; + K[ 1] = S5[z(10)] ^ S6[z(11)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S6[z( 6)]; + K[ 2] = S5[z(12)] ^ S6[z(13)] ^ S7[z( 3)] ^ S8[z( 2)] ^ S7[z( 9)]; + K[ 3] = S5[z(14)] ^ S6[z(15)] ^ S7[z( 1)] ^ S8[z( 0)] ^ S8[z(12)]; + X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; + X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; + X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; + X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; + K[ 4] = S5[x( 3)] ^ S6[x( 2)] ^ S7[x(12)] ^ S8[x(13)] ^ S5[x( 8)]; + K[ 5] = S5[x( 1)] ^ S6[x( 0)] ^ S7[x(14)] ^ S8[x(15)] ^ S6[x(13)]; + K[ 6] = S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 8)] ^ S8[x( 9)] ^ S7[x( 3)]; + K[ 7] = S5[x( 5)] ^ S6[x( 4)] ^ S7[x(10)] ^ S8[x(11)] ^ S8[x( 7)]; + Z[0] = X[0] ^ S5[x(13)] ^ S6[x(15)] ^ S7[x(12)] ^ S8[x(14)] ^ S7[x( 8)]; + Z[1] = X[2] ^ S5[z( 0)] ^ S6[z( 2)] ^ S7[z( 1)] ^ S8[z( 3)] ^ S8[x(10)]; + Z[2] = X[3] ^ S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 5)] ^ S8[z( 4)] ^ S5[x( 9)]; + Z[3] = X[1] ^ S5[z(10)] ^ S6[z( 9)] ^ S7[z(11)] ^ S8[z( 8)] ^ S6[x(11)]; + K[ 8] = S5[z( 3)] ^ S6[z( 2)] ^ S7[z(12)] ^ S8[z(13)] ^ S5[z( 9)]; + K[ 9] = S5[z( 1)] ^ S6[z( 0)] ^ S7[z(14)] ^ S8[z(15)] ^ S6[z(12)]; + K[10] = S5[z( 7)] ^ S6[z( 6)] ^ S7[z( 8)] ^ S8[z( 9)] ^ S7[z( 2)]; + K[11] = S5[z( 5)] ^ S6[z( 4)] ^ S7[z(10)] ^ S8[z(11)] ^ S8[z( 6)]; + X[0] = Z[2] ^ S5[z( 5)] ^ S6[z( 7)] ^ S7[z( 4)] ^ S8[z( 6)] ^ S7[z( 0)]; + X[1] = Z[0] ^ S5[x( 0)] ^ S6[x( 2)] ^ S7[x( 1)] ^ S8[x( 3)] ^ S8[z( 2)]; + X[2] = Z[1] ^ S5[x( 7)] ^ S6[x( 6)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S5[z( 1)]; + X[3] = Z[3] ^ S5[x(10)] ^ S6[x( 9)] ^ S7[x(11)] ^ S8[x( 8)] ^ S6[z( 3)]; + K[12] = S5[x( 8)] ^ S6[x( 9)] ^ S7[x( 7)] ^ S8[x( 6)] ^ S5[x( 3)]; + K[13] = S5[x(10)] ^ S6[x(11)] ^ S7[x( 5)] ^ S8[x( 4)] ^ S6[x( 7)]; + K[14] = S5[x(12)] ^ S6[x(13)] ^ S7[x( 3)] ^ S8[x( 2)] ^ S7[x( 8)]; + K[15] = S5[x(14)] ^ S6[x(15)] ^ S7[x( 1)] ^ S8[x( 0)] ^ S8[x(13)]; + } + +} diff --git a/comm/third_party/botan/src/lib/block/cast128/cast128.h b/comm/third_party/botan/src/lib/block/cast128/cast128.h new file mode 100644 index 0000000000..a5f2a64019 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast128/cast128.h @@ -0,0 +1,42 @@ +/* +* CAST-128 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CAST128_H_ +#define BOTAN_CAST128_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cast128.h) + +namespace Botan { + +/** +* CAST-128 +*/ +class BOTAN_PUBLIC_API(2,0) CAST_128 final : public Block_Cipher_Fixed_Params<8, 11, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "CAST-128"; } + BlockCipher* clone() const override { return new CAST_128; } + + private: + void key_schedule(const uint8_t[], size_t) override; + + static void cast_ks(secure_vector& ks, + secure_vector& user_key); + + secure_vector m_MK; + secure_vector m_RK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/cast128/cast_sboxes.h b/comm/third_party/botan/src/lib/block/cast128/cast_sboxes.h new file mode 100644 index 0000000000..f4d005cc94 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast128/cast_sboxes.h @@ -0,0 +1,197 @@ +/* +* S-Box Tables for CAST-128 and CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CAST_SBOX_TABLES_H_ +#define BOTAN_CAST_SBOX_TABLES_H_ + +#include + +namespace Botan { + +alignas(64) const uint32_t CAST_SBOX1[256] = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, + 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, + 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, + 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, + 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, + 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, + 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, + 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, + 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, + 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, + 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, + 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, + 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, + 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, + 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, + 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, + 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, + 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, + 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, + 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, + 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, + 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; + +alignas(64) const uint32_t CAST_SBOX2[256] = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, + 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, + 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, + 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, + 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, + 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, + 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, + 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, + 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, + 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, + 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, + 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, + 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, + 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, + 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, + 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, + 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, + 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, + 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, + 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, + 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, + 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; + +alignas(64) const uint32_t CAST_SBOX3[256] = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, + 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, + 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, + 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, + 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, + 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, + 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, + 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, + 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, + 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, + 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, + 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, + 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, + 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, + 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, + 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, + 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, + 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, + 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, + 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, + 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, + 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; + +alignas(64) const uint32_t CAST_SBOX4[256] = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, + 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, + 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, + 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, + 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, + 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, + 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, + 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, + 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, + 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, + 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, + 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, + 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, + 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, + 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, + 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, + 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, + 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, + 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, + 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, + 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, + 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/cast128/info.txt b/comm/third_party/botan/src/lib/block/cast128/info.txt new file mode 100644 index 0000000000..6e6cf30abe --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast128/info.txt @@ -0,0 +1,12 @@ + +CAST -> 20131128 +CAST_128 -> 20171203 + + + +cast_sboxes.h + + + +cast128.h + diff --git a/comm/third_party/botan/src/lib/block/cast256/cast256.cpp b/comm/third_party/botan/src/lib/block/cast256/cast256.cpp new file mode 100644 index 0000000000..226955f7cb --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast256/cast256.cpp @@ -0,0 +1,232 @@ +/* +* CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* CAST-256 Round Type 1 +*/ +void round1(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) + { + const uint32_t T = rotl_var(MK + in, RK); + out ^= (CAST_SBOX1[get_byte(0, T)] ^ CAST_SBOX2[get_byte(1, T)]) - + CAST_SBOX3[get_byte(2, T)] + CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-256 Round Type 2 +*/ +void round2(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) + { + const uint32_t T = rotl_var(MK ^ in, RK); + out ^= (CAST_SBOX1[get_byte(0, T)] - CAST_SBOX2[get_byte(1, T)] + + CAST_SBOX3[get_byte(2, T)]) ^ CAST_SBOX4[get_byte(3, T)]; + } + +/* +* CAST-256 Round Type 3 +*/ +void round3(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) + { + const uint32_t T = rotl_var(MK - in, RK); + out ^= ((CAST_SBOX1[get_byte(0, T)] + CAST_SBOX2[get_byte(1, T)]) ^ + CAST_SBOX3[get_byte(2, T)]) - CAST_SBOX4[get_byte(3, T)]; + } + +} + +/* +* CAST-256 Encryption +*/ +void CAST_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t A = load_be(in, 0); + uint32_t B = load_be(in, 1); + uint32_t C = load_be(in, 2); + uint32_t D = load_be(in, 3); + + round1(C, D, m_MK[ 0], m_RK[ 0]); round2(B, C, m_MK[ 1], m_RK[ 1]); + round3(A, B, m_MK[ 2], m_RK[ 2]); round1(D, A, m_MK[ 3], m_RK[ 3]); + round1(C, D, m_MK[ 4], m_RK[ 4]); round2(B, C, m_MK[ 5], m_RK[ 5]); + round3(A, B, m_MK[ 6], m_RK[ 6]); round1(D, A, m_MK[ 7], m_RK[ 7]); + round1(C, D, m_MK[ 8], m_RK[ 8]); round2(B, C, m_MK[ 9], m_RK[ 9]); + round3(A, B, m_MK[10], m_RK[10]); round1(D, A, m_MK[11], m_RK[11]); + round1(C, D, m_MK[12], m_RK[12]); round2(B, C, m_MK[13], m_RK[13]); + round3(A, B, m_MK[14], m_RK[14]); round1(D, A, m_MK[15], m_RK[15]); + round1(C, D, m_MK[16], m_RK[16]); round2(B, C, m_MK[17], m_RK[17]); + round3(A, B, m_MK[18], m_RK[18]); round1(D, A, m_MK[19], m_RK[19]); + round1(C, D, m_MK[20], m_RK[20]); round2(B, C, m_MK[21], m_RK[21]); + round3(A, B, m_MK[22], m_RK[22]); round1(D, A, m_MK[23], m_RK[23]); + round1(D, A, m_MK[27], m_RK[27]); round3(A, B, m_MK[26], m_RK[26]); + round2(B, C, m_MK[25], m_RK[25]); round1(C, D, m_MK[24], m_RK[24]); + round1(D, A, m_MK[31], m_RK[31]); round3(A, B, m_MK[30], m_RK[30]); + round2(B, C, m_MK[29], m_RK[29]); round1(C, D, m_MK[28], m_RK[28]); + round1(D, A, m_MK[35], m_RK[35]); round3(A, B, m_MK[34], m_RK[34]); + round2(B, C, m_MK[33], m_RK[33]); round1(C, D, m_MK[32], m_RK[32]); + round1(D, A, m_MK[39], m_RK[39]); round3(A, B, m_MK[38], m_RK[38]); + round2(B, C, m_MK[37], m_RK[37]); round1(C, D, m_MK[36], m_RK[36]); + round1(D, A, m_MK[43], m_RK[43]); round3(A, B, m_MK[42], m_RK[42]); + round2(B, C, m_MK[41], m_RK[41]); round1(C, D, m_MK[40], m_RK[40]); + round1(D, A, m_MK[47], m_RK[47]); round3(A, B, m_MK[46], m_RK[46]); + round2(B, C, m_MK[45], m_RK[45]); round1(C, D, m_MK[44], m_RK[44]); + + store_be(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-256 Decryption +*/ +void CAST_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t A = load_be(in, 0); + uint32_t B = load_be(in, 1); + uint32_t C = load_be(in, 2); + uint32_t D = load_be(in, 3); + + round1(C, D, m_MK[44], m_RK[44]); round2(B, C, m_MK[45], m_RK[45]); + round3(A, B, m_MK[46], m_RK[46]); round1(D, A, m_MK[47], m_RK[47]); + round1(C, D, m_MK[40], m_RK[40]); round2(B, C, m_MK[41], m_RK[41]); + round3(A, B, m_MK[42], m_RK[42]); round1(D, A, m_MK[43], m_RK[43]); + round1(C, D, m_MK[36], m_RK[36]); round2(B, C, m_MK[37], m_RK[37]); + round3(A, B, m_MK[38], m_RK[38]); round1(D, A, m_MK[39], m_RK[39]); + round1(C, D, m_MK[32], m_RK[32]); round2(B, C, m_MK[33], m_RK[33]); + round3(A, B, m_MK[34], m_RK[34]); round1(D, A, m_MK[35], m_RK[35]); + round1(C, D, m_MK[28], m_RK[28]); round2(B, C, m_MK[29], m_RK[29]); + round3(A, B, m_MK[30], m_RK[30]); round1(D, A, m_MK[31], m_RK[31]); + round1(C, D, m_MK[24], m_RK[24]); round2(B, C, m_MK[25], m_RK[25]); + round3(A, B, m_MK[26], m_RK[26]); round1(D, A, m_MK[27], m_RK[27]); + round1(D, A, m_MK[23], m_RK[23]); round3(A, B, m_MK[22], m_RK[22]); + round2(B, C, m_MK[21], m_RK[21]); round1(C, D, m_MK[20], m_RK[20]); + round1(D, A, m_MK[19], m_RK[19]); round3(A, B, m_MK[18], m_RK[18]); + round2(B, C, m_MK[17], m_RK[17]); round1(C, D, m_MK[16], m_RK[16]); + round1(D, A, m_MK[15], m_RK[15]); round3(A, B, m_MK[14], m_RK[14]); + round2(B, C, m_MK[13], m_RK[13]); round1(C, D, m_MK[12], m_RK[12]); + round1(D, A, m_MK[11], m_RK[11]); round3(A, B, m_MK[10], m_RK[10]); + round2(B, C, m_MK[ 9], m_RK[ 9]); round1(C, D, m_MK[ 8], m_RK[ 8]); + round1(D, A, m_MK[ 7], m_RK[ 7]); round3(A, B, m_MK[ 6], m_RK[ 6]); + round2(B, C, m_MK[ 5], m_RK[ 5]); round1(C, D, m_MK[ 4], m_RK[ 4]); + round1(D, A, m_MK[ 3], m_RK[ 3]); round3(A, B, m_MK[ 2], m_RK[ 2]); + round2(B, C, m_MK[ 1], m_RK[ 1]); round1(C, D, m_MK[ 0], m_RK[ 0]); + + store_be(out, A, B, C, D); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* CAST-256 Key Schedule +*/ +void CAST_256::key_schedule(const uint8_t key[], size_t length) + { + static const uint32_t KEY_MASK[192] = { + 0x5A827999, 0xC95C653A, 0x383650DB, 0xA7103C7C, 0x15EA281D, 0x84C413BE, + 0xF39DFF5F, 0x6277EB00, 0xD151D6A1, 0x402BC242, 0xAF05ADE3, 0x1DDF9984, + 0x8CB98525, 0xFB9370C6, 0x6A6D5C67, 0xD9474808, 0x482133A9, 0xB6FB1F4A, + 0x25D50AEB, 0x94AEF68C, 0x0388E22D, 0x7262CDCE, 0xE13CB96F, 0x5016A510, + 0xBEF090B1, 0x2DCA7C52, 0x9CA467F3, 0x0B7E5394, 0x7A583F35, 0xE9322AD6, + 0x580C1677, 0xC6E60218, 0x35BFEDB9, 0xA499D95A, 0x1373C4FB, 0x824DB09C, + 0xF1279C3D, 0x600187DE, 0xCEDB737F, 0x3DB55F20, 0xAC8F4AC1, 0x1B693662, + 0x8A432203, 0xF91D0DA4, 0x67F6F945, 0xD6D0E4E6, 0x45AAD087, 0xB484BC28, + 0x235EA7C9, 0x9238936A, 0x01127F0B, 0x6FEC6AAC, 0xDEC6564D, 0x4DA041EE, + 0xBC7A2D8F, 0x2B541930, 0x9A2E04D1, 0x0907F072, 0x77E1DC13, 0xE6BBC7B4, + 0x5595B355, 0xC46F9EF6, 0x33498A97, 0xA2237638, 0x10FD61D9, 0x7FD74D7A, + 0xEEB1391B, 0x5D8B24BC, 0xCC65105D, 0x3B3EFBFE, 0xAA18E79F, 0x18F2D340, + 0x87CCBEE1, 0xF6A6AA82, 0x65809623, 0xD45A81C4, 0x43346D65, 0xB20E5906, + 0x20E844A7, 0x8FC23048, 0xFE9C1BE9, 0x6D76078A, 0xDC4FF32B, 0x4B29DECC, + 0xBA03CA6D, 0x28DDB60E, 0x97B7A1AF, 0x06918D50, 0x756B78F1, 0xE4456492, + 0x531F5033, 0xC1F93BD4, 0x30D32775, 0x9FAD1316, 0x0E86FEB7, 0x7D60EA58, + 0xEC3AD5F9, 0x5B14C19A, 0xC9EEAD3B, 0x38C898DC, 0xA7A2847D, 0x167C701E, + 0x85565BBF, 0xF4304760, 0x630A3301, 0xD1E41EA2, 0x40BE0A43, 0xAF97F5E4, + 0x1E71E185, 0x8D4BCD26, 0xFC25B8C7, 0x6AFFA468, 0xD9D99009, 0x48B37BAA, + 0xB78D674B, 0x266752EC, 0x95413E8D, 0x041B2A2E, 0x72F515CF, 0xE1CF0170, + 0x50A8ED11, 0xBF82D8B2, 0x2E5CC453, 0x9D36AFF4, 0x0C109B95, 0x7AEA8736, + 0xE9C472D7, 0x589E5E78, 0xC7784A19, 0x365235BA, 0xA52C215B, 0x14060CFC, + 0x82DFF89D, 0xF1B9E43E, 0x6093CFDF, 0xCF6DBB80, 0x3E47A721, 0xAD2192C2, + 0x1BFB7E63, 0x8AD56A04, 0xF9AF55A5, 0x68894146, 0xD7632CE7, 0x463D1888, + 0xB5170429, 0x23F0EFCA, 0x92CADB6B, 0x01A4C70C, 0x707EB2AD, 0xDF589E4E, + 0x4E3289EF, 0xBD0C7590, 0x2BE66131, 0x9AC04CD2, 0x099A3873, 0x78742414, + 0xE74E0FB5, 0x5627FB56, 0xC501E6F7, 0x33DBD298, 0xA2B5BE39, 0x118FA9DA, + 0x8069957B, 0xEF43811C, 0x5E1D6CBD, 0xCCF7585E, 0x3BD143FF, 0xAAAB2FA0, + 0x19851B41, 0x885F06E2, 0xF738F283, 0x6612DE24, 0xD4ECC9C5, 0x43C6B566, + 0xB2A0A107, 0x217A8CA8, 0x90547849, 0xFF2E63EA, 0x6E084F8B, 0xDCE23B2C, + 0x4BBC26CD, 0xBA96126E, 0x296FFE0F, 0x9849E9B0, 0x0723D551, 0x75FDC0F2, + 0xE4D7AC93, 0x53B19834, 0xC28B83D5, 0x31656F76, 0xA03F5B17, 0x0F1946B8 }; + + static const uint8_t KEY_ROT[32] = { + 0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0A, 0x1B, 0x0C, + 0x1D, 0x0E, 0x1F, 0x10, 0x01, 0x12, 0x03, 0x14, 0x05, 0x16, + 0x07, 0x18, 0x09, 0x1A, 0x0B, 0x1C, 0x0D, 0x1E, 0x0F, 0x00, + 0x11, 0x02 }; + + m_MK.resize(48); + m_RK.resize(48); + + secure_vector K(8); + for(size_t i = 0; i != length; ++i) + K[i/4] = (K[i/4] << 8) + key[i]; + + uint32_t A = K[0], B = K[1], C = K[2], D = K[3], + E = K[4], F = K[5], G = K[6], H = K[7]; + + for(size_t i = 0; i != 48; i += 4) + { + round1(G, H, KEY_MASK[4*i+ 0], KEY_ROT[(4*i+ 0) % 32]); + round2(F, G, KEY_MASK[4*i+ 1], KEY_ROT[(4*i+ 1) % 32]); + round3(E, F, KEY_MASK[4*i+ 2], KEY_ROT[(4*i+ 2) % 32]); + round1(D, E, KEY_MASK[4*i+ 3], KEY_ROT[(4*i+ 3) % 32]); + round2(C, D, KEY_MASK[4*i+ 4], KEY_ROT[(4*i+ 4) % 32]); + round3(B, C, KEY_MASK[4*i+ 5], KEY_ROT[(4*i+ 5) % 32]); + round1(A, B, KEY_MASK[4*i+ 6], KEY_ROT[(4*i+ 6) % 32]); + round2(H, A, KEY_MASK[4*i+ 7], KEY_ROT[(4*i+ 7) % 32]); + round1(G, H, KEY_MASK[4*i+ 8], KEY_ROT[(4*i+ 8) % 32]); + round2(F, G, KEY_MASK[4*i+ 9], KEY_ROT[(4*i+ 9) % 32]); + round3(E, F, KEY_MASK[4*i+10], KEY_ROT[(4*i+10) % 32]); + round1(D, E, KEY_MASK[4*i+11], KEY_ROT[(4*i+11) % 32]); + round2(C, D, KEY_MASK[4*i+12], KEY_ROT[(4*i+12) % 32]); + round3(B, C, KEY_MASK[4*i+13], KEY_ROT[(4*i+13) % 32]); + round1(A, B, KEY_MASK[4*i+14], KEY_ROT[(4*i+14) % 32]); + round2(H, A, KEY_MASK[4*i+15], KEY_ROT[(4*i+15) % 32]); + + m_RK[i ] = (A % 32); + m_RK[i+1] = (C % 32); + m_RK[i+2] = (E % 32); + m_RK[i+3] = (G % 32); + m_MK[i ] = H; + m_MK[i+1] = F; + m_MK[i+2] = D; + m_MK[i+3] = B; + } + } + +void CAST_256::clear() + { + zap(m_MK); + zap(m_RK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/cast256/cast256.h b/comm/third_party/botan/src/lib/block/cast256/cast256.h new file mode 100644 index 0000000000..3c30169372 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast256/cast256.h @@ -0,0 +1,38 @@ +/* +* CAST-256 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CAST256_H_ +#define BOTAN_CAST256_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cast256.h) + +namespace Botan { + +/** +* CAST-256 +*/ +class BOTAN_PUBLIC_API(2,0) CAST_256 final : public Block_Cipher_Fixed_Params<16, 4, 32, 4> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "CAST-256"; } + BlockCipher* clone() const override { return new CAST_256; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_MK; + secure_vector m_RK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/cast256/info.txt b/comm/third_party/botan/src/lib/block/cast256/info.txt new file mode 100644 index 0000000000..b109fe0533 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/cast256/info.txt @@ -0,0 +1,7 @@ + +CAST_256 -> 20171203 + + + +cast128 + diff --git a/comm/third_party/botan/src/lib/block/des/des.cpp b/comm/third_party/botan/src/lib/block/des/des.cpp new file mode 100644 index 0000000000..0aa9e6a791 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/des/des.cpp @@ -0,0 +1,410 @@ +/* +* DES +* (C) 1999-2008,2018 Jack Lloyd +* +* Based on a public domain implemenation by Phil Karn (who in turn +* credited Richard Outerbridge and Jim Gillogly) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* DES Key Schedule +*/ +void des_key_schedule(uint32_t round_key[32], const uint8_t key[8]) + { + static const uint8_t ROT[16] = { 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1 }; + + uint32_t C = ((key[7] & 0x80) << 20) | ((key[6] & 0x80) << 19) | + ((key[5] & 0x80) << 18) | ((key[4] & 0x80) << 17) | + ((key[3] & 0x80) << 16) | ((key[2] & 0x80) << 15) | + ((key[1] & 0x80) << 14) | ((key[0] & 0x80) << 13) | + ((key[7] & 0x40) << 13) | ((key[6] & 0x40) << 12) | + ((key[5] & 0x40) << 11) | ((key[4] & 0x40) << 10) | + ((key[3] & 0x40) << 9) | ((key[2] & 0x40) << 8) | + ((key[1] & 0x40) << 7) | ((key[0] & 0x40) << 6) | + ((key[7] & 0x20) << 6) | ((key[6] & 0x20) << 5) | + ((key[5] & 0x20) << 4) | ((key[4] & 0x20) << 3) | + ((key[3] & 0x20) << 2) | ((key[2] & 0x20) << 1) | + ((key[1] & 0x20) ) | ((key[0] & 0x20) >> 1) | + ((key[7] & 0x10) >> 1) | ((key[6] & 0x10) >> 2) | + ((key[5] & 0x10) >> 3) | ((key[4] & 0x10) >> 4); + uint32_t D = ((key[7] & 0x02) << 26) | ((key[6] & 0x02) << 25) | + ((key[5] & 0x02) << 24) | ((key[4] & 0x02) << 23) | + ((key[3] & 0x02) << 22) | ((key[2] & 0x02) << 21) | + ((key[1] & 0x02) << 20) | ((key[0] & 0x02) << 19) | + ((key[7] & 0x04) << 17) | ((key[6] & 0x04) << 16) | + ((key[5] & 0x04) << 15) | ((key[4] & 0x04) << 14) | + ((key[3] & 0x04) << 13) | ((key[2] & 0x04) << 12) | + ((key[1] & 0x04) << 11) | ((key[0] & 0x04) << 10) | + ((key[7] & 0x08) << 8) | ((key[6] & 0x08) << 7) | + ((key[5] & 0x08) << 6) | ((key[4] & 0x08) << 5) | + ((key[3] & 0x08) << 4) | ((key[2] & 0x08) << 3) | + ((key[1] & 0x08) << 2) | ((key[0] & 0x08) << 1) | + ((key[3] & 0x10) >> 1) | ((key[2] & 0x10) >> 2) | + ((key[1] & 0x10) >> 3) | ((key[0] & 0x10) >> 4); + + for(size_t i = 0; i != 16; ++i) + { + C = ((C << ROT[i]) | (C >> (28-ROT[i]))) & 0x0FFFFFFF; + D = ((D << ROT[i]) | (D >> (28-ROT[i]))) & 0x0FFFFFFF; + round_key[2*i ] = ((C & 0x00000010) << 22) | ((C & 0x00000800) << 17) | + ((C & 0x00000020) << 16) | ((C & 0x00004004) << 15) | + ((C & 0x00000200) << 11) | ((C & 0x00020000) << 10) | + ((C & 0x01000000) >> 6) | ((C & 0x00100000) >> 4) | + ((C & 0x00010000) << 3) | ((C & 0x08000000) >> 2) | + ((C & 0x00800000) << 1) | ((D & 0x00000010) << 8) | + ((D & 0x00000002) << 7) | ((D & 0x00000001) << 2) | + ((D & 0x00000200) ) | ((D & 0x00008000) >> 2) | + ((D & 0x00000088) >> 3) | ((D & 0x00001000) >> 7) | + ((D & 0x00080000) >> 9) | ((D & 0x02020000) >> 14) | + ((D & 0x00400000) >> 21); + round_key[2*i+1] = ((C & 0x00000001) << 28) | ((C & 0x00000082) << 18) | + ((C & 0x00002000) << 14) | ((C & 0x00000100) << 10) | + ((C & 0x00001000) << 9) | ((C & 0x00040000) << 6) | + ((C & 0x02400000) << 4) | ((C & 0x00008000) << 2) | + ((C & 0x00200000) >> 1) | ((C & 0x04000000) >> 10) | + ((D & 0x00000020) << 6) | ((D & 0x00000100) ) | + ((D & 0x00000800) >> 1) | ((D & 0x00000040) >> 3) | + ((D & 0x00010000) >> 4) | ((D & 0x00000400) >> 5) | + ((D & 0x00004000) >> 10) | ((D & 0x04000000) >> 13) | + ((D & 0x00800000) >> 14) | ((D & 0x00100000) >> 18) | + ((D & 0x01000000) >> 24) | ((D & 0x08000000) >> 26); + } + } + +inline uint32_t spbox(uint32_t T0, uint32_t T1) + { + return DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + } + +/* +* DES Encryption +*/ +inline void des_encrypt(uint32_t& Lr, uint32_t& Rr, + const uint32_t round_key[32]) + { + uint32_t L = Lr; + uint32_t R = Rr; + for(size_t i = 0; i != 16; i += 2) + { + L ^= spbox(rotr<4>(R) ^ round_key[2*i ], R ^ round_key[2*i+1]); + R ^= spbox(rotr<4>(L) ^ round_key[2*i+2], L ^ round_key[2*i+3]); + } + + Lr = L; + Rr = R; + } + +inline void des_encrypt_x2(uint32_t& L0r, uint32_t& R0r, + uint32_t& L1r, uint32_t& R1r, + const uint32_t round_key[32]) + { + uint32_t L0 = L0r; + uint32_t R0 = R0r; + uint32_t L1 = L1r; + uint32_t R1 = R1r; + + for(size_t i = 0; i != 16; i += 2) + { + L0 ^= spbox(rotr<4>(R0) ^ round_key[2*i ], R0 ^ round_key[2*i+1]); + L1 ^= spbox(rotr<4>(R1) ^ round_key[2*i ], R1 ^ round_key[2*i+1]); + + R0 ^= spbox(rotr<4>(L0) ^ round_key[2*i+2], L0 ^ round_key[2*i+3]); + R1 ^= spbox(rotr<4>(L1) ^ round_key[2*i+2], L1 ^ round_key[2*i+3]); + } + + L0r = L0; + R0r = R0; + L1r = L1; + R1r = R1; + } + +/* +* DES Decryption +*/ +inline void des_decrypt(uint32_t& Lr, uint32_t& Rr, + const uint32_t round_key[32]) + { + uint32_t L = Lr; + uint32_t R = Rr; + for(size_t i = 16; i != 0; i -= 2) + { + L ^= spbox(rotr<4>(R) ^ round_key[2*i - 2], R ^ round_key[2*i - 1]); + R ^= spbox(rotr<4>(L) ^ round_key[2*i - 4], L ^ round_key[2*i - 3]); + } + Lr = L; + Rr = R; + } + +inline void des_decrypt_x2(uint32_t& L0r, uint32_t& R0r, + uint32_t& L1r, uint32_t& R1r, + const uint32_t round_key[32]) + { + uint32_t L0 = L0r; + uint32_t R0 = R0r; + uint32_t L1 = L1r; + uint32_t R1 = R1r; + + for(size_t i = 16; i != 0; i -= 2) + { + L0 ^= spbox(rotr<4>(R0) ^ round_key[2*i - 2], R0 ^ round_key[2*i - 1]); + L1 ^= spbox(rotr<4>(R1) ^ round_key[2*i - 2], R1 ^ round_key[2*i - 1]); + + R0 ^= spbox(rotr<4>(L0) ^ round_key[2*i - 4], L0 ^ round_key[2*i - 3]); + R1 ^= spbox(rotr<4>(L1) ^ round_key[2*i - 4], L1 ^ round_key[2*i - 3]); + } + + L0r = L0; + R0r = R0; + L1r = L1; + R1r = R1; + } + +inline void des_IP(uint32_t& L, uint32_t& R, const uint8_t block[]) + { + // IP sequence by Wei Dai, taken from public domain Crypto++ + L = load_be(block, 0); + R = load_be(block, 1); + + uint32_t T; + R = rotl<4>(R); + T = (L ^ R) & 0xF0F0F0F0; + L ^= T; + R = rotr<20>(R ^ T); + T = (L ^ R) & 0xFFFF0000; + L ^= T; + R = rotr<18>(R ^ T); + T = (L ^ R) & 0x33333333; + L ^= T; + R = rotr<6>(R ^ T); + T = (L ^ R) & 0x00FF00FF; + L ^= T; + R = rotl<9>(R ^ T); + T = (L ^ R) & 0xAAAAAAAA; + L = rotl<1>(L ^ T); + R ^= T; + } + +inline void des_FP(uint32_t L, uint32_t R, uint8_t out[]) + { + // FP sequence by Wei Dai, taken from public domain Crypto++ + uint32_t T; + + R = rotr<1>(R); + T = (L ^ R) & 0xAAAAAAAA; + R ^= T; + L = rotr<9>(L ^ T); + T = (L ^ R) & 0x00FF00FF; + R ^= T; + L = rotl<6>(L ^ T); + T = (L ^ R) & 0x33333333; + R ^= T; + L = rotl<18>(L ^ T); + T = (L ^ R) & 0xFFFF0000; + R ^= T; + L = rotl<20>(L ^ T); + T = (L ^ R) & 0xF0F0F0F0; + R ^= T; + L = rotr<4>(L ^ T); + + store_be(out, R, L); + } + +} + +/* +* DES Encryption +*/ +void DES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_encrypt_x2(L0, R0, L1, R1, m_round_key.data()); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i < blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + des_encrypt(L, R, m_round_key.data()); + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* DES Decryption +*/ +void DES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_decrypt_x2(L0, R0, L1, R1, m_round_key.data()); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i < blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + des_decrypt(L, R, m_round_key.data()); + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* DES Key Schedule +*/ +void DES::key_schedule(const uint8_t key[], size_t) + { + m_round_key.resize(32); + des_key_schedule(m_round_key.data(), key); + } + +void DES::clear() + { + zap(m_round_key); + } + +/* +* TripleDES Encryption +*/ +void TripleDES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_encrypt_x2(L0, R0, L1, R1, &m_round_key[0]); + des_decrypt_x2(R0, L0, R1, L1, &m_round_key[32]); + des_encrypt_x2(L0, R0, L1, R1, &m_round_key[64]); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + + des_encrypt(L, R, &m_round_key[0]); + des_decrypt(R, L, &m_round_key[32]); + des_encrypt(L, R, &m_round_key[64]); + + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* TripleDES Decryption +*/ +void TripleDES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_decrypt_x2(L0, R0, L1, R1, &m_round_key[64]); + des_encrypt_x2(R0, L0, R1, L1, &m_round_key[32]); + des_decrypt_x2(L0, R0, L1, R1, &m_round_key[0]); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + + des_decrypt(L, R, &m_round_key[64]); + des_encrypt(R, L, &m_round_key[32]); + des_decrypt(L, R, &m_round_key[0]); + + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* TripleDES Key Schedule +*/ +void TripleDES::key_schedule(const uint8_t key[], size_t length) + { + m_round_key.resize(3*32); + des_key_schedule(&m_round_key[0], key); + des_key_schedule(&m_round_key[32], key + 8); + + if(length == 24) + des_key_schedule(&m_round_key[64], key + 16); + else + copy_mem(&m_round_key[64], &m_round_key[0], 32); + } + +void TripleDES::clear() + { + zap(m_round_key); + } + +} diff --git a/comm/third_party/botan/src/lib/block/des/des.h b/comm/third_party/botan/src/lib/block/des/des.h new file mode 100644 index 0000000000..d8bbcfdd10 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/des/des.h @@ -0,0 +1,67 @@ +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DES_H_ +#define BOTAN_DES_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(des.h) + +namespace Botan { + +/** +* DES +*/ +class BOTAN_PUBLIC_API(2,0) DES final : public Block_Cipher_Fixed_Params<8, 8> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "DES"; } + BlockCipher* clone() const override { return new DES; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_round_key; + }; + +/** +* Triple DES +*/ +class BOTAN_PUBLIC_API(2,0) TripleDES final : public Block_Cipher_Fixed_Params<8, 16, 24, 8> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "TripleDES"; } + BlockCipher* clone() const override { return new TripleDES; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_round_key; + }; + +/* +* DES Tables +*/ +extern const uint32_t DES_SPBOX1[256]; +extern const uint32_t DES_SPBOX2[256]; +extern const uint32_t DES_SPBOX3[256]; +extern const uint32_t DES_SPBOX4[256]; +extern const uint32_t DES_SPBOX5[256]; +extern const uint32_t DES_SPBOX6[256]; +extern const uint32_t DES_SPBOX7[256]; +extern const uint32_t DES_SPBOX8[256]; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/des/des_tab.cpp b/comm/third_party/botan/src/lib/block/des/des_tab.cpp new file mode 100644 index 0000000000..cb6ab4e7e9 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/des/des_tab.cpp @@ -0,0 +1,372 @@ +/* +* Substitution/Permutation Tables for DES +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +alignas(64) const uint32_t DES_SPBOX1[256] = { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, + 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, + 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, + 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, + 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, + 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, + 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, + 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, + 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, + 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, + 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, + 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; + +alignas(64) const uint32_t DES_SPBOX2[256] = { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, + 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, + 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, + 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, + 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, + 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, + 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, + 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, + 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, + 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, + 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, + 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; + +alignas(64) const uint32_t DES_SPBOX3[256] = { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, + 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, + 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, + 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, + 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, + 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, + 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, + 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, + 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, + 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, + 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, + 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; + +alignas(64) const uint32_t DES_SPBOX4[256] = { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, + 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, + 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; + +alignas(64) const uint32_t DES_SPBOX5[256] = { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, + 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, + 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, + 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, + 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, + 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, + 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, + 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, + 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, + 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, + 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, + 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; + +alignas(64) const uint32_t DES_SPBOX6[256] = { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, + 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, + 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, + 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, + 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, + 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, + 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, + 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, + 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, + 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, + 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, + 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; + +alignas(64) const uint32_t DES_SPBOX7[256] = { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, + 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, + 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, + 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, + 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, + 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, + 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, + 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, + 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, + 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, + 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, + 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; + +alignas(64) const uint32_t DES_SPBOX8[256] = { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, + 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, + 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, + 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, + 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, + 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, + 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, + 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, + 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, + 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, + 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, + 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; + +} diff --git a/comm/third_party/botan/src/lib/block/des/desx.cpp b/comm/third_party/botan/src/lib/block/des/desx.cpp new file mode 100644 index 0000000000..e869b3ebf8 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/des/desx.cpp @@ -0,0 +1,65 @@ +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +* DESX Encryption +*/ +void DESX::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K1.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, m_K1.data(), BLOCK_SIZE); + m_des.encrypt(out); + xor_buf(out, m_K2.data(), BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Decryption +*/ +void DESX::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K1.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, m_K2.data(), BLOCK_SIZE); + m_des.decrypt(out); + xor_buf(out, m_K1.data(), BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Key Schedule +*/ +void DESX::key_schedule(const uint8_t key[], size_t) + { + m_K1.assign(key, key + 8); + m_des.set_key(key + 8, 8); + m_K2.assign(key + 16, key + 24); + } + +void DESX::clear() + { + m_des.clear(); + zap(m_K1); + zap(m_K2); + } + +} diff --git a/comm/third_party/botan/src/lib/block/des/desx.h b/comm/third_party/botan/src/lib/block/des/desx.h new file mode 100644 index 0000000000..0189a99826 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/des/desx.h @@ -0,0 +1,37 @@ +/* +* DESX +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DESX_H_ +#define BOTAN_DESX_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(desx.h) + +namespace Botan { + +/** +* DESX +*/ +class BOTAN_PUBLIC_API(2,0) DESX final : public Block_Cipher_Fixed_Params<8, 24> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "DESX"; } + BlockCipher* clone() const override { return new DESX; } + private: + void key_schedule(const uint8_t[], size_t) override; + secure_vector m_K1, m_K2; + DES m_des; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/des/info.txt b/comm/third_party/botan/src/lib/block/des/info.txt new file mode 100644 index 0000000000..05f85b523c --- /dev/null +++ b/comm/third_party/botan/src/lib/block/des/info.txt @@ -0,0 +1,3 @@ + +DES -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/gost_28147/gost_28147.cpp b/comm/third_party/botan/src/lib/block/gost_28147/gost_28147.cpp new file mode 100644 index 0000000000..2b8aa031e8 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/gost_28147/gost_28147.cpp @@ -0,0 +1,189 @@ +/* +* GOST 28147-89 +* (C) 1999-2009,2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +uint8_t GOST_28147_89_Params::sbox_entry(size_t row, size_t col) const + { + const uint8_t x = m_sboxes[4 * col + (row / 2)]; + return (row % 2 == 0) ? (x >> 4) : (x & 0x0F); + } + +uint8_t GOST_28147_89_Params::sbox_pair(size_t row, size_t col) const + { + const uint8_t x = m_sboxes[4 * (col % 16) + row]; + const uint8_t y = m_sboxes[4 * (col / 16) + row]; + return (x >> 4) | (y << 4); + } + +GOST_28147_89_Params::GOST_28147_89_Params(const std::string& n) : m_name(n) + { + // Encoded in the packed fromat from RFC 4357 + + // GostR3411_94_TestParamSet (OID 1.2.643.2.2.31.0) + static const uint8_t GOST_R_3411_TEST_PARAMS[64] = { + 0x4E, 0x57, 0x64, 0xD1, 0xAB, 0x8D, 0xCB, 0xBF, 0x94, 0x1A, 0x7A, + 0x4D, 0x2C, 0xD1, 0x10, 0x10, 0xD6, 0xA0, 0x57, 0x35, 0x8D, 0x38, + 0xF2, 0xF7, 0x0F, 0x49, 0xD1, 0x5A, 0xEA, 0x2F, 0x8D, 0x94, 0x62, + 0xEE, 0x43, 0x09, 0xB3, 0xF4, 0xA6, 0xA2, 0x18, 0xC6, 0x98, 0xE3, + 0xC1, 0x7C, 0xE5, 0x7E, 0x70, 0x6B, 0x09, 0x66, 0xF7, 0x02, 0x3C, + 0x8B, 0x55, 0x95, 0xBF, 0x28, 0x39, 0xB3, 0x2E, 0xCC }; + + // GostR3411-94-CryptoProParamSet (OID 1.2.643.2.2.31.1) + static const uint8_t GOST_R_3411_CRYPTOPRO_PARAMS[64] = { + 0xA5, 0x74, 0x77, 0xD1, 0x4F, 0xFA, 0x66, 0xE3, 0x54, 0xC7, 0x42, + 0x4A, 0x60, 0xEC, 0xB4, 0x19, 0x82, 0x90, 0x9D, 0x75, 0x1D, 0x4F, + 0xC9, 0x0B, 0x3B, 0x12, 0x2F, 0x54, 0x79, 0x08, 0xA0, 0xAF, 0xD1, + 0x3E, 0x1A, 0x38, 0xC7, 0xB1, 0x81, 0xC6, 0xE6, 0x56, 0x05, 0x87, + 0x03, 0x25, 0xEB, 0xFE, 0x9C, 0x6D, 0xF8, 0x6D, 0x2E, 0xAB, 0xDE, + 0x20, 0xBA, 0x89, 0x3C, 0x92, 0xF8, 0xD3, 0x53, 0xBC }; + + if(m_name == "R3411_94_TestParam") + m_sboxes = GOST_R_3411_TEST_PARAMS; + else if(m_name == "R3411_CryptoPro") + m_sboxes = GOST_R_3411_CRYPTOPRO_PARAMS; + else + throw Invalid_Argument("GOST_28147_89_Params: Unknown " + m_name); + } + +/* +* GOST Constructor +*/ +GOST_28147_89::GOST_28147_89(const GOST_28147_89_Params& param) : m_SBOX(1024) + { + // Convert the parallel 4x4 sboxes into larger word-based sboxes + + for(size_t i = 0; i != 256; ++i) + { + m_SBOX[i ] = rotl<11, uint32_t>(param.sbox_pair(0, i)); + m_SBOX[i+256] = rotl<19, uint32_t>(param.sbox_pair(1, i)); + m_SBOX[i+512] = rotl<27, uint32_t>(param.sbox_pair(2, i)); + m_SBOX[i+768] = rotl< 3, uint32_t>(param.sbox_pair(3, i)); + } + } + +std::string GOST_28147_89::name() const + { + /* + 'Guess' the right name for the sbox on the basis of the values. + This would need to be updated if support for other sbox parameters + is added. Preferably, we would just store the string value in the + constructor, but can't break binary compat. + */ + std::string sbox_name = ""; + if(m_SBOX[0] == 0x00072000) + sbox_name = "R3411_94_TestParam"; + else if(m_SBOX[0] == 0x0002D000) + sbox_name = "R3411_CryptoPro"; + else + throw Internal_Error("GOST-28147 unrecognized sbox value"); + + return "GOST-28147-89(" + sbox_name + ")"; + } + +/* +* Two rounds of GOST +*/ +#define GOST_2ROUND(N1, N2, R1, R2) \ + do { \ + uint32_t T0 = N1 + m_EK[R1]; \ + N2 ^= m_SBOX[get_byte(3, T0)] | \ + m_SBOX[get_byte(2, T0)+256] | \ + m_SBOX[get_byte(1, T0)+512] | \ + m_SBOX[get_byte(0, T0)+768]; \ + \ + uint32_t T1 = N2 + m_EK[R2]; \ + N1 ^= m_SBOX[get_byte(3, T1)] | \ + m_SBOX[get_byte(2, T1)+256] | \ + m_SBOX[get_byte(1, T1)+512] | \ + m_SBOX[get_byte(0, T1)+768]; \ + } while(0) + +/* +* GOST Encryption +*/ +void GOST_28147_89::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t N1 = load_le(in, 0); + uint32_t N2 = load_le(in, 1); + + for(size_t j = 0; j != 3; ++j) + { + GOST_2ROUND(N1, N2, 0, 1); + GOST_2ROUND(N1, N2, 2, 3); + GOST_2ROUND(N1, N2, 4, 5); + GOST_2ROUND(N1, N2, 6, 7); + } + + GOST_2ROUND(N1, N2, 7, 6); + GOST_2ROUND(N1, N2, 5, 4); + GOST_2ROUND(N1, N2, 3, 2); + GOST_2ROUND(N1, N2, 1, 0); + + store_le(out, N2, N1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* GOST Decryption +*/ +void GOST_28147_89::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t N1 = load_le(in, 0); + uint32_t N2 = load_le(in, 1); + + GOST_2ROUND(N1, N2, 0, 1); + GOST_2ROUND(N1, N2, 2, 3); + GOST_2ROUND(N1, N2, 4, 5); + GOST_2ROUND(N1, N2, 6, 7); + + for(size_t j = 0; j != 3; ++j) + { + GOST_2ROUND(N1, N2, 7, 6); + GOST_2ROUND(N1, N2, 5, 4); + GOST_2ROUND(N1, N2, 3, 2); + GOST_2ROUND(N1, N2, 1, 0); + } + + store_le(out, N2, N1); + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* GOST Key Schedule +*/ +void GOST_28147_89::key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(8); + for(size_t i = 0; i != 8; ++i) + m_EK[i] = load_le(key, i); + } + +void GOST_28147_89::clear() + { + zap(m_EK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/gost_28147/gost_28147.h b/comm/third_party/botan/src/lib/block/gost_28147/gost_28147.h new file mode 100644 index 0000000000..f71bb28bd9 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/gost_28147/gost_28147.h @@ -0,0 +1,95 @@ +/* +* GOST 28147-89 +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_GOST_28147_89_H_ +#define BOTAN_GOST_28147_89_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(gost_28147.h) + +namespace Botan { + +/** +* The GOST 28147-89 block cipher uses a set of 4 bit Sboxes, however +* the standard does not actually define these Sboxes; they are +* considered a local configuration issue. Several different sets are +* used. +*/ +class BOTAN_PUBLIC_API(2,0) GOST_28147_89_Params final + { + public: + /** + * @param row the row + * @param col the column + * @return sbox entry at this row/column + */ + uint8_t sbox_entry(size_t row, size_t col) const; + + /** + * @return name of this parameter set + */ + std::string param_name() const { return m_name; } + + /** + * Return a representation used for building larger tables + * For internal use + */ + uint8_t sbox_pair(size_t row, size_t col) const; + + /** + * Default GOST parameters are the ones given in GOST R 34.11 for + * testing purposes; these sboxes are also used by Crypto++, and, + * at least according to Wikipedia, the Central Bank of Russian + * Federation + * @param name of the parameter set + */ + explicit GOST_28147_89_Params(const std::string& name = "R3411_94_TestParam"); + private: + const uint8_t* m_sboxes; + std::string m_name; + }; + +/** +* GOST 28147-89 +*/ +class BOTAN_PUBLIC_API(2,0) GOST_28147_89 final : public Block_Cipher_Fixed_Params<8, 32> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string name() const override; + BlockCipher* clone() const override { return new GOST_28147_89(m_SBOX); } + + /** + * @param params the sbox parameters to use + */ + explicit GOST_28147_89(const GOST_28147_89_Params& params); + + explicit GOST_28147_89(const std::string& param_name) : + GOST_28147_89(GOST_28147_89_Params(param_name)) {} + private: + explicit GOST_28147_89(const std::vector& other_SBOX) : + m_SBOX(other_SBOX), m_EK(8) {} + + void key_schedule(const uint8_t[], size_t) override; + + /* + * The sbox is not secret, this is just a larger expansion of it + * which we generate at runtime for faster execution + */ + std::vector m_SBOX; + + secure_vector m_EK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/gost_28147/info.txt b/comm/third_party/botan/src/lib/block/gost_28147/info.txt new file mode 100644 index 0000000000..17fc971591 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/gost_28147/info.txt @@ -0,0 +1,3 @@ + +GOST_28147_89 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/idea/idea.cpp b/comm/third_party/botan/src/lib/block/idea/idea.cpp new file mode 100644 index 0000000000..f8f5ceb348 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/idea/idea.cpp @@ -0,0 +1,240 @@ +/* +* IDEA +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Multiplication modulo 65537 +*/ +inline uint16_t mul(uint16_t x, uint16_t y) + { + const uint32_t P = static_cast(x) * y; + const auto P_mask = CT::Mask(CT::Mask::is_zero(P)); + + const uint32_t P_hi = P >> 16; + const uint32_t P_lo = P & 0xFFFF; + + const uint16_t carry = (P_lo < P_hi); + const uint16_t r_1 = static_cast((P_lo - P_hi) + carry); + const uint16_t r_2 = 1 - x - y; + + return P_mask.select(r_2, r_1); + } + +/* +* Find multiplicative inverses modulo 65537 +* +* 65537 is prime; thus Fermat's little theorem tells us that +* x^65537 == x modulo 65537, which means +* x^(65537-2) == x^-1 modulo 65537 since +* x^(65537-2) * x == 1 mod 65537 +* +* Do the exponentiation with a basic square and multiply: all bits are +* of exponent are 1 so we always multiply +*/ +uint16_t mul_inv(uint16_t x) + { + uint16_t y = x; + + for(size_t i = 0; i != 15; ++i) + { + y = mul(y, y); // square + y = mul(y, x); + } + + return y; + } + +/** +* IDEA is involutional, depending only on the key schedule +*/ +void idea_op(const uint8_t in[], uint8_t out[], size_t blocks, const uint16_t K[52]) + { + const size_t BLOCK_SIZE = 8; + + CT::poison(in, blocks * 8); + CT::poison(out, blocks * 8); + CT::poison(K, 52); + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) + { + uint16_t X1, X2, X3, X4; + load_be(in + BLOCK_SIZE*i, X1, X2, X3, X4); + + for(size_t j = 0; j != 8; ++j) + { + X1 = mul(X1, K[6*j+0]); + X2 += K[6*j+1]; + X3 += K[6*j+2]; + X4 = mul(X4, K[6*j+3]); + + const uint16_t T0 = X3; + X3 = mul(X3 ^ X1, K[6*j+4]); + + const uint16_t T1 = X2; + X2 = mul((X2 ^ X4) + X3, K[6*j+5]); + X3 += X2; + + X1 ^= X2; + X4 ^= X3; + X2 ^= T0; + X3 ^= T1; + } + + X1 = mul(X1, K[48]); + X2 += K[50]; + X3 += K[49]; + X4 = mul(X4, K[51]); + + store_be(out + BLOCK_SIZE*i, X1, X3, X2, X4); + } + + CT::unpoison(in, blocks * 8); + CT::unpoison(out, blocks * 8); + CT::unpoison(K, 52); + } + +} + +size_t IDEA::parallelism() const + { +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + return 8; + } +#endif + + return 1; + } + +std::string IDEA::provider() const + { +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + return "sse2"; + } +#endif + + return "base"; + } + +/* +* IDEA Encryption +*/ +void IDEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + while(blocks >= 8) + { + sse2_idea_op_8(in, out, m_EK.data()); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + } +#endif + + idea_op(in, out, blocks, m_EK.data()); + } + +/* +* IDEA Decryption +*/ +void IDEA::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + while(blocks >= 8) + { + sse2_idea_op_8(in, out, m_DK.data()); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + } +#endif + + idea_op(in, out, blocks, m_DK.data()); + } + +/* +* IDEA Key Schedule +*/ +void IDEA::key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(52); + m_DK.resize(52); + + CT::poison(key, 16); + CT::poison(m_EK.data(), 52); + CT::poison(m_DK.data(), 52); + + secure_vector K(2); + + K[0] = load_be(key, 0); + K[1] = load_be(key, 1); + + for(size_t off = 0; off != 48; off += 8) + { + for(size_t i = 0; i != 8; ++i) + m_EK[off+i] = static_cast(K[i/4] >> (48-16*(i % 4))); + + const uint64_t Kx = (K[0] >> 39); + const uint64_t Ky = (K[1] >> 39); + + K[0] = (K[0] << 25) | Ky; + K[1] = (K[1] << 25) | Kx; + } + + for(size_t i = 0; i != 4; ++i) + m_EK[48+i] = static_cast(K[i/4] >> (48-16*(i % 4))); + + m_DK[0] = mul_inv(m_EK[48]); + m_DK[1] = -m_EK[49]; + m_DK[2] = -m_EK[50]; + m_DK[3] = mul_inv(m_EK[51]); + + for(size_t i = 0; i != 8*6; i += 6) + { + m_DK[i+4] = m_EK[46-i]; + m_DK[i+5] = m_EK[47-i]; + m_DK[i+6] = mul_inv(m_EK[42-i]); + m_DK[i+7] = -m_EK[44-i]; + m_DK[i+8] = -m_EK[43-i]; + m_DK[i+9] = mul_inv(m_EK[45-i]); + } + + std::swap(m_DK[49], m_DK[50]); + + CT::unpoison(key, 16); + CT::unpoison(m_EK.data(), 52); + CT::unpoison(m_DK.data(), 52); + } + +void IDEA::clear() + { + zap(m_EK); + zap(m_DK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/idea/idea.h b/comm/third_party/botan/src/lib/block/idea/idea.h new file mode 100644 index 0000000000..e5e51606b9 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/idea/idea.h @@ -0,0 +1,45 @@ +/* +* IDEA +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_IDEA_H_ +#define BOTAN_IDEA_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(idea.h) + +namespace Botan { + +/** +* IDEA +*/ +class BOTAN_PUBLIC_API(2,0) IDEA final : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + std::string name() const override { return "IDEA"; } + BlockCipher* clone() const override { return new IDEA; } + size_t parallelism() const override; + + private: +#if defined(BOTAN_HAS_IDEA_SSE2) + void sse2_idea_op_8(const uint8_t in[64], uint8_t out[64], const uint16_t EK[52]) const; +#endif + + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_EK, m_DK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/idea/idea_sse2/idea_sse2.cpp b/comm/third_party/botan/src/lib/block/idea/idea_sse2/idea_sse2.cpp new file mode 100644 index 0000000000..93648cfc7a --- /dev/null +++ b/comm/third_party/botan/src/lib/block/idea/idea_sse2/idea_sse2.cpp @@ -0,0 +1,208 @@ +/* +* IDEA in SSE2 +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +BOTAN_FUNC_ISA("sse2") +inline __m128i mul(__m128i X, uint16_t K_16) + { + const __m128i zeros = _mm_set1_epi16(0); + const __m128i ones = _mm_set1_epi16(1); + + const __m128i K = _mm_set1_epi16(K_16); + + const __m128i X_is_zero = _mm_cmpeq_epi16(X, zeros); + const __m128i K_is_zero = _mm_cmpeq_epi16(K, zeros); + + const __m128i mul_lo = _mm_mullo_epi16(X, K); + const __m128i mul_hi = _mm_mulhi_epu16(X, K); + + __m128i T = _mm_sub_epi16(mul_lo, mul_hi); + + // Unsigned compare; cmp = 1 if mul_lo < mul_hi else 0 + const __m128i subs = _mm_subs_epu16(mul_hi, mul_lo); + const __m128i cmp = _mm_min_epu8( + _mm_or_si128(subs, _mm_srli_epi16(subs, 8)), ones); + + T = _mm_add_epi16(T, cmp); + + /* Selection: if X[i] is zero then assign 1-K + if K is zero then assign 1-X[i] + + Could if() off value of K_16 for the second, but this gives a + constant time implementation which is a nice bonus. + */ + + T = _mm_or_si128( + _mm_andnot_si128(X_is_zero, T), + _mm_and_si128(_mm_sub_epi16(ones, K), X_is_zero)); + + T = _mm_or_si128( + _mm_andnot_si128(K_is_zero, T), + _mm_and_si128(_mm_sub_epi16(ones, X), K_is_zero)); + + return T; + } + +/* +* 4x8 matrix transpose +* +* FIXME: why do I need the extra set of unpack_epi32 here? Inverse in +* transpose_out doesn't need it. Something with the shuffle? Removing +* that extra unpack could easily save 3-4 cycles per block, and would +* also help a lot with register pressure on 32-bit x86 +*/ +BOTAN_FUNC_ISA("sse2") +void transpose_in(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) + { + __m128i T0 = _mm_unpackhi_epi32(B0, B1); + __m128i T1 = _mm_unpacklo_epi32(B0, B1); + __m128i T2 = _mm_unpackhi_epi32(B2, B3); + __m128i T3 = _mm_unpacklo_epi32(B2, B3); + + __m128i T4 = _mm_unpacklo_epi32(T0, T1); + __m128i T5 = _mm_unpackhi_epi32(T0, T1); + __m128i T6 = _mm_unpacklo_epi32(T2, T3); + __m128i T7 = _mm_unpackhi_epi32(T2, T3); + + T0 = _mm_shufflehi_epi16(T4, _MM_SHUFFLE(1, 3, 0, 2)); + T1 = _mm_shufflehi_epi16(T5, _MM_SHUFFLE(1, 3, 0, 2)); + T2 = _mm_shufflehi_epi16(T6, _MM_SHUFFLE(1, 3, 0, 2)); + T3 = _mm_shufflehi_epi16(T7, _MM_SHUFFLE(1, 3, 0, 2)); + + T0 = _mm_shufflelo_epi16(T0, _MM_SHUFFLE(1, 3, 0, 2)); + T1 = _mm_shufflelo_epi16(T1, _MM_SHUFFLE(1, 3, 0, 2)); + T2 = _mm_shufflelo_epi16(T2, _MM_SHUFFLE(1, 3, 0, 2)); + T3 = _mm_shufflelo_epi16(T3, _MM_SHUFFLE(1, 3, 0, 2)); + + T0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shuffle_epi32(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + B0 = _mm_unpacklo_epi64(T0, T2); + B1 = _mm_unpackhi_epi64(T0, T2); + B2 = _mm_unpacklo_epi64(T1, T3); + B3 = _mm_unpackhi_epi64(T1, T3); + } + +/* +* 4x8 matrix transpose (reverse) +*/ +BOTAN_FUNC_ISA("sse2") +void transpose_out(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) + { + __m128i T0 = _mm_unpacklo_epi64(B0, B1); + __m128i T1 = _mm_unpacklo_epi64(B2, B3); + __m128i T2 = _mm_unpackhi_epi64(B0, B1); + __m128i T3 = _mm_unpackhi_epi64(B2, B3); + + T0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shuffle_epi32(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + T0 = _mm_shufflehi_epi16(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shufflehi_epi16(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shufflehi_epi16(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shufflehi_epi16(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + T0 = _mm_shufflelo_epi16(T0, _MM_SHUFFLE(3, 1, 2, 0)); + T1 = _mm_shufflelo_epi16(T1, _MM_SHUFFLE(3, 1, 2, 0)); + T2 = _mm_shufflelo_epi16(T2, _MM_SHUFFLE(3, 1, 2, 0)); + T3 = _mm_shufflelo_epi16(T3, _MM_SHUFFLE(3, 1, 2, 0)); + + B0 = _mm_unpacklo_epi32(T0, T1); + B1 = _mm_unpackhi_epi32(T0, T1); + B2 = _mm_unpacklo_epi32(T2, T3); + B3 = _mm_unpackhi_epi32(T2, T3); + } + +} + +/* +* 8 wide IDEA encryption/decryption in SSE2 +*/ +BOTAN_FUNC_ISA("sse2") +void IDEA::sse2_idea_op_8(const uint8_t in[64], uint8_t out[64], const uint16_t EK[52]) const + { + CT::poison(in, 64); + CT::poison(out, 64); + CT::poison(EK, 52); + + const __m128i* in_mm = reinterpret_cast(in); + + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + transpose_in(B0, B1, B2, B3); + + // byte swap + B0 = _mm_or_si128(_mm_slli_epi16(B0, 8), _mm_srli_epi16(B0, 8)); + B1 = _mm_or_si128(_mm_slli_epi16(B1, 8), _mm_srli_epi16(B1, 8)); + B2 = _mm_or_si128(_mm_slli_epi16(B2, 8), _mm_srli_epi16(B2, 8)); + B3 = _mm_or_si128(_mm_slli_epi16(B3, 8), _mm_srli_epi16(B3, 8)); + + for(size_t i = 0; i != 8; ++i) + { + B0 = mul(B0, EK[6*i+0]); + B1 = _mm_add_epi16(B1, _mm_set1_epi16(EK[6*i+1])); + B2 = _mm_add_epi16(B2, _mm_set1_epi16(EK[6*i+2])); + B3 = mul(B3, EK[6*i+3]); + + __m128i T0 = B2; + B2 = _mm_xor_si128(B2, B0); + B2 = mul(B2, EK[6*i+4]); + + __m128i T1 = B1; + + B1 = _mm_xor_si128(B1, B3); + B1 = _mm_add_epi16(B1, B2); + B1 = mul(B1, EK[6*i+5]); + + B2 = _mm_add_epi16(B2, B1); + + B0 = _mm_xor_si128(B0, B1); + B1 = _mm_xor_si128(B1, T0); + B3 = _mm_xor_si128(B3, B2); + B2 = _mm_xor_si128(B2, T1); + } + + B0 = mul(B0, EK[48]); + B1 = _mm_add_epi16(B1, _mm_set1_epi16(EK[50])); + B2 = _mm_add_epi16(B2, _mm_set1_epi16(EK[49])); + B3 = mul(B3, EK[51]); + + // byte swap + B0 = _mm_or_si128(_mm_slli_epi16(B0, 8), _mm_srli_epi16(B0, 8)); + B1 = _mm_or_si128(_mm_slli_epi16(B1, 8), _mm_srli_epi16(B1, 8)); + B2 = _mm_or_si128(_mm_slli_epi16(B2, 8), _mm_srli_epi16(B2, 8)); + B3 = _mm_or_si128(_mm_slli_epi16(B3, 8), _mm_srli_epi16(B3, 8)); + + transpose_out(B0, B2, B1, B3); + + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B2); + _mm_storeu_si128(out_mm + 2, B1); + _mm_storeu_si128(out_mm + 3, B3); + + CT::unpoison(in, 64); + CT::unpoison(out, 64); + CT::unpoison(EK, 52); + } + +} diff --git a/comm/third_party/botan/src/lib/block/idea/idea_sse2/info.txt b/comm/third_party/botan/src/lib/block/idea/idea_sse2/info.txt new file mode 100644 index 0000000000..b0ca2d02fa --- /dev/null +++ b/comm/third_party/botan/src/lib/block/idea/idea_sse2/info.txt @@ -0,0 +1,7 @@ + +IDEA_SSE2 -> 20131128 + + + +sse2 + diff --git a/comm/third_party/botan/src/lib/block/idea/info.txt b/comm/third_party/botan/src/lib/block/idea/info.txt new file mode 100644 index 0000000000..bcbdce03f1 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/idea/info.txt @@ -0,0 +1,3 @@ + +IDEA -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/info.txt b/comm/third_party/botan/src/lib/block/info.txt new file mode 100644 index 0000000000..b03a8c8f59 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/info.txt @@ -0,0 +1,7 @@ + +BLOCK_CIPHER -> 20131128 + + + +block_cipher.h + diff --git a/comm/third_party/botan/src/lib/block/kasumi/info.txt b/comm/third_party/botan/src/lib/block/kasumi/info.txt new file mode 100644 index 0000000000..b48183ca90 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/kasumi/info.txt @@ -0,0 +1,3 @@ + +KASUMI -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/kasumi/kasumi.cpp b/comm/third_party/botan/src/lib/block/kasumi/kasumi.cpp new file mode 100644 index 0000000000..819567b1c1 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/kasumi/kasumi.cpp @@ -0,0 +1,238 @@ +/* +* KASUMI +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* KASUMI S-Boxes +*/ +alignas(64) const uint8_t KASUMI_SBOX_S7[128] = { + 0x36, 0x32, 0x3E, 0x38, 0x16, 0x22, 0x5E, 0x60, 0x26, 0x06, 0x3F, 0x5D, + 0x02, 0x12, 0x7B, 0x21, 0x37, 0x71, 0x27, 0x72, 0x15, 0x43, 0x41, 0x0C, + 0x2F, 0x49, 0x2E, 0x1B, 0x19, 0x6F, 0x7C, 0x51, 0x35, 0x09, 0x79, 0x4F, + 0x34, 0x3C, 0x3A, 0x30, 0x65, 0x7F, 0x28, 0x78, 0x68, 0x46, 0x47, 0x2B, + 0x14, 0x7A, 0x48, 0x3D, 0x17, 0x6D, 0x0D, 0x64, 0x4D, 0x01, 0x10, 0x07, + 0x52, 0x0A, 0x69, 0x62, 0x75, 0x74, 0x4C, 0x0B, 0x59, 0x6A, 0x00, 0x7D, + 0x76, 0x63, 0x56, 0x45, 0x1E, 0x39, 0x7E, 0x57, 0x70, 0x33, 0x11, 0x05, + 0x5F, 0x0E, 0x5A, 0x54, 0x5B, 0x08, 0x23, 0x67, 0x20, 0x61, 0x1C, 0x42, + 0x66, 0x1F, 0x1A, 0x2D, 0x4B, 0x04, 0x55, 0x5C, 0x25, 0x4A, 0x50, 0x31, + 0x44, 0x1D, 0x73, 0x2C, 0x40, 0x6B, 0x6C, 0x18, 0x6E, 0x53, 0x24, 0x4E, + 0x2A, 0x13, 0x0F, 0x29, 0x58, 0x77, 0x3B, 0x03 }; + +alignas(64) const uint16_t KASUMI_SBOX_S9[512] = { + 0x00A7, 0x00EF, 0x00A1, 0x017B, 0x0187, 0x014E, 0x0009, 0x0152, 0x0026, + 0x00E2, 0x0030, 0x0166, 0x01C4, 0x0181, 0x005A, 0x018D, 0x00B7, 0x00FD, + 0x0093, 0x014B, 0x019F, 0x0154, 0x0033, 0x016A, 0x0132, 0x01F4, 0x0106, + 0x0052, 0x00D8, 0x009F, 0x0164, 0x00B1, 0x00AF, 0x00F1, 0x01E9, 0x0025, + 0x00CE, 0x0011, 0x0000, 0x014D, 0x002C, 0x00FE, 0x017A, 0x003A, 0x008F, + 0x00DC, 0x0051, 0x0190, 0x005F, 0x0003, 0x013B, 0x00F5, 0x0036, 0x00EB, + 0x00DA, 0x0195, 0x01D8, 0x0108, 0x00AC, 0x01EE, 0x0173, 0x0122, 0x018F, + 0x004C, 0x00A5, 0x00C5, 0x018B, 0x0079, 0x0101, 0x01E0, 0x01A7, 0x00D4, + 0x00F0, 0x001C, 0x01CE, 0x00B0, 0x0196, 0x01FB, 0x0120, 0x00DF, 0x01F5, + 0x0197, 0x00F9, 0x0109, 0x0059, 0x00BA, 0x00DD, 0x01AC, 0x00A4, 0x004A, + 0x01B8, 0x00C4, 0x01CA, 0x01A5, 0x015E, 0x00A3, 0x00E8, 0x009E, 0x0086, + 0x0162, 0x000D, 0x00FA, 0x01EB, 0x008E, 0x00BF, 0x0045, 0x00C1, 0x01A9, + 0x0098, 0x00E3, 0x016E, 0x0087, 0x0158, 0x012C, 0x0114, 0x00F2, 0x01B5, + 0x0140, 0x0071, 0x0116, 0x000B, 0x00F3, 0x0057, 0x013D, 0x0024, 0x005D, + 0x01F0, 0x001B, 0x01E7, 0x01BE, 0x01E2, 0x0029, 0x0044, 0x009C, 0x01C9, + 0x0083, 0x0146, 0x0193, 0x0153, 0x0014, 0x0027, 0x0073, 0x01BA, 0x007C, + 0x01DB, 0x0180, 0x01FC, 0x0035, 0x0070, 0x00AA, 0x01DF, 0x0097, 0x007E, + 0x00A9, 0x0049, 0x010C, 0x0117, 0x0141, 0x00A8, 0x016C, 0x016B, 0x0124, + 0x002E, 0x01F3, 0x0189, 0x0147, 0x0144, 0x0018, 0x01C8, 0x010B, 0x009D, + 0x01CC, 0x01E8, 0x01AA, 0x0135, 0x00E5, 0x01B7, 0x01FA, 0x00D0, 0x010F, + 0x015D, 0x0191, 0x01B2, 0x00EC, 0x0010, 0x00D1, 0x0167, 0x0034, 0x0038, + 0x0078, 0x00C7, 0x0115, 0x01D1, 0x01A0, 0x00FC, 0x011F, 0x00F6, 0x0006, + 0x0053, 0x0131, 0x01A4, 0x0159, 0x0099, 0x01F6, 0x0041, 0x003D, 0x00F4, + 0x011A, 0x00AD, 0x00DE, 0x01A2, 0x0043, 0x0182, 0x0170, 0x0105, 0x0065, + 0x01DC, 0x0123, 0x00C3, 0x01AE, 0x0031, 0x004F, 0x00A6, 0x014A, 0x0118, + 0x017F, 0x0175, 0x0080, 0x017E, 0x0198, 0x009B, 0x01EF, 0x016F, 0x0184, + 0x0112, 0x006B, 0x01CB, 0x01A1, 0x003E, 0x01C6, 0x0084, 0x00E1, 0x00CB, + 0x013C, 0x00EA, 0x000E, 0x012D, 0x005B, 0x01F7, 0x011E, 0x01A8, 0x00D3, + 0x015B, 0x0133, 0x008C, 0x0176, 0x0023, 0x0067, 0x007D, 0x01AB, 0x0013, + 0x00D6, 0x01C5, 0x0092, 0x01F2, 0x013A, 0x01BC, 0x00E6, 0x0100, 0x0149, + 0x00C6, 0x011D, 0x0032, 0x0074, 0x004E, 0x019A, 0x000A, 0x00CD, 0x01FE, + 0x00AB, 0x00E7, 0x002D, 0x008B, 0x01D3, 0x001D, 0x0056, 0x01F9, 0x0020, + 0x0048, 0x001A, 0x0156, 0x0096, 0x0139, 0x01EA, 0x01AF, 0x00EE, 0x019B, + 0x0145, 0x0095, 0x01D9, 0x0028, 0x0077, 0x00AE, 0x0163, 0x00B9, 0x00E9, + 0x0185, 0x0047, 0x01C0, 0x0111, 0x0174, 0x0037, 0x006E, 0x00B2, 0x0142, + 0x000C, 0x01D5, 0x0188, 0x0171, 0x00BE, 0x0001, 0x006D, 0x0177, 0x0089, + 0x00B5, 0x0058, 0x004B, 0x0134, 0x0104, 0x01E4, 0x0062, 0x0110, 0x0172, + 0x0113, 0x019C, 0x006F, 0x0150, 0x013E, 0x0004, 0x01F8, 0x01EC, 0x0103, + 0x0130, 0x004D, 0x0151, 0x01B3, 0x0015, 0x0165, 0x012F, 0x014C, 0x01E3, + 0x0012, 0x002F, 0x0055, 0x0019, 0x01F1, 0x01DA, 0x0121, 0x0064, 0x010D, + 0x0128, 0x01DE, 0x010E, 0x006A, 0x001F, 0x0068, 0x01B1, 0x0054, 0x019E, + 0x01E6, 0x018A, 0x0060, 0x0063, 0x009A, 0x01FF, 0x0094, 0x019D, 0x0169, + 0x0199, 0x00FF, 0x00A2, 0x00D7, 0x012E, 0x00C9, 0x010A, 0x015F, 0x0157, + 0x0090, 0x01B9, 0x016D, 0x006C, 0x012A, 0x00FB, 0x0022, 0x00B6, 0x01FD, + 0x008A, 0x00D2, 0x014F, 0x0085, 0x0137, 0x0160, 0x0148, 0x008D, 0x018C, + 0x015A, 0x007B, 0x013F, 0x01C2, 0x0119, 0x01AD, 0x00E4, 0x01BB, 0x01E1, + 0x005C, 0x0194, 0x01E5, 0x01A6, 0x00F8, 0x0129, 0x0017, 0x00D5, 0x0082, + 0x01D2, 0x0016, 0x00D9, 0x011B, 0x0046, 0x0126, 0x0168, 0x01A3, 0x007F, + 0x0138, 0x0179, 0x0007, 0x01D4, 0x00C2, 0x0002, 0x0075, 0x0127, 0x01CF, + 0x0102, 0x00E0, 0x01BF, 0x00F7, 0x00BB, 0x0050, 0x018E, 0x011C, 0x0161, + 0x0069, 0x0186, 0x012B, 0x01D7, 0x01D6, 0x00B8, 0x0039, 0x00C8, 0x015C, + 0x003F, 0x00CC, 0x00BC, 0x0021, 0x01C3, 0x0061, 0x001E, 0x0136, 0x00DB, + 0x005E, 0x00A0, 0x0081, 0x01ED, 0x0040, 0x00B3, 0x0107, 0x0066, 0x00BD, + 0x00CF, 0x0072, 0x0192, 0x01B6, 0x01DD, 0x0183, 0x007A, 0x00C0, 0x002A, + 0x017D, 0x0005, 0x0091, 0x0076, 0x00B4, 0x01C1, 0x0125, 0x0143, 0x0088, + 0x017C, 0x002B, 0x0042, 0x003C, 0x01C7, 0x0155, 0x01BD, 0x00CA, 0x01B0, + 0x0008, 0x00ED, 0x000F, 0x0178, 0x01B4, 0x01D0, 0x003B, 0x01CD }; + +/* +* KASUMI FI Function +*/ +uint16_t FI(uint16_t I, uint16_t K) + { + uint16_t D9 = (I >> 7); + uint8_t D7 = (I & 0x7F); + D9 = KASUMI_SBOX_S9[D9] ^ D7; + D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); + + D7 ^= (K >> 9); + D9 = KASUMI_SBOX_S9[D9 ^ (K & 0x1FF)] ^ D7; + D7 = KASUMI_SBOX_S7[D7] ^ (D9 & 0x7F); + return static_cast(D7 << 9) | D9; + } + +} + +/* +* KASUMI Encryption +*/ +void KASUMI::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint16_t B0 = load_be(in, 0); + uint16_t B1 = load_be(in, 1); + uint16_t B2 = load_be(in, 2); + uint16_t B3 = load_be(in, 3); + + for(size_t j = 0; j != 8; j += 2) + { + const uint16_t* K = &m_EK[8*j]; + + uint16_t R = B1 ^ (rotl<1>(B0) & K[0]); + uint16_t L = B0 ^ (rotl<1>(R) | K[1]); + + L = FI(L ^ K[ 2], K[ 3]) ^ R; + R = FI(R ^ K[ 4], K[ 5]) ^ L; + L = FI(L ^ K[ 6], K[ 7]) ^ R; + + R = B2 ^= R; + L = B3 ^= L; + + R = FI(R ^ K[10], K[11]) ^ L; + L = FI(L ^ K[12], K[13]) ^ R; + R = FI(R ^ K[14], K[15]) ^ L; + + R ^= (rotl<1>(L) & K[8]); + L ^= (rotl<1>(R) | K[9]); + + B0 ^= L; + B1 ^= R; + } + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* KASUMI Decryption +*/ +void KASUMI::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint16_t B0 = load_be(in, 0); + uint16_t B1 = load_be(in, 1); + uint16_t B2 = load_be(in, 2); + uint16_t B3 = load_be(in, 3); + + for(size_t j = 0; j != 8; j += 2) + { + const uint16_t* K = &m_EK[8*(6-j)]; + + uint16_t L = B2, R = B3; + + L = FI(L ^ K[10], K[11]) ^ R; + R = FI(R ^ K[12], K[13]) ^ L; + L = FI(L ^ K[14], K[15]) ^ R; + + L ^= (rotl<1>(R) & K[8]); + R ^= (rotl<1>(L) | K[9]); + + R = B0 ^= R; + L = B1 ^= L; + + L ^= (rotl<1>(R) & K[0]); + R ^= (rotl<1>(L) | K[1]); + + R = FI(R ^ K[2], K[3]) ^ L; + L = FI(L ^ K[4], K[5]) ^ R; + R = FI(R ^ K[6], K[7]) ^ L; + + B2 ^= L; + B3 ^= R; + } + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* KASUMI Key Schedule +*/ +void KASUMI::key_schedule(const uint8_t key[], size_t) + { + static const uint16_t RC[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, + 0xFEDC, 0xBA98, 0x7654, 0x3210 }; + + secure_vector K(16); + for(size_t i = 0; i != 8; ++i) + { + K[i] = load_be(key, i); + K[i+8] = K[i] ^ RC[i]; + } + + m_EK.resize(64); + + for(size_t i = 0; i != 8; ++i) + { + m_EK[8*i ] = rotl<2>(K[(i+0) % 8]); + m_EK[8*i+1] = rotl<1>(K[(i+2) % 8 + 8]); + m_EK[8*i+2] = rotl<5>(K[(i+1) % 8]); + m_EK[8*i+3] = K[(i+4) % 8 + 8]; + m_EK[8*i+4] = rotl<8>(K[(i+5) % 8]); + m_EK[8*i+5] = K[(i+3) % 8 + 8]; + m_EK[8*i+6] = rotl<13>(K[(i+6) % 8]); + m_EK[8*i+7] = K[(i+7) % 8 + 8]; + } + } + +void KASUMI::clear() + { + zap(m_EK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/kasumi/kasumi.h b/comm/third_party/botan/src/lib/block/kasumi/kasumi.h new file mode 100644 index 0000000000..9ea09a1036 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/kasumi/kasumi.h @@ -0,0 +1,37 @@ +/* +* KASUMI +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KASUMI_H_ +#define BOTAN_KASUMI_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(kasumi.h) + +namespace Botan { + +/** +* KASUMI, the block cipher used in 3G telephony +*/ +class BOTAN_PUBLIC_API(2,0) KASUMI final : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "KASUMI"; } + BlockCipher* clone() const override { return new KASUMI; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_EK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/lion/info.txt b/comm/third_party/botan/src/lib/block/lion/info.txt new file mode 100644 index 0000000000..a7b93e92ee --- /dev/null +++ b/comm/third_party/botan/src/lib/block/lion/info.txt @@ -0,0 +1,8 @@ + +LION -> 20131128 + + + +stream +hash + diff --git a/comm/third_party/botan/src/lib/block/lion/lion.cpp b/comm/third_party/botan/src/lib/block/lion/lion.cpp new file mode 100644 index 0000000000..c9589a46ac --- /dev/null +++ b/comm/third_party/botan/src/lib/block/lion/lion.cpp @@ -0,0 +1,138 @@ +/* +* Lion +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Lion Encryption +*/ +void Lion::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_key1.empty() == false); + + const size_t LEFT_SIZE = left_size(); + const size_t RIGHT_SIZE = right_size(); + + secure_vector buffer_vec(LEFT_SIZE); + uint8_t* buffer = buffer_vec.data(); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(buffer, in, m_key1.data(), LEFT_SIZE); + m_cipher->set_key(buffer, LEFT_SIZE); + m_cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); + + m_hash->update(out + LEFT_SIZE, RIGHT_SIZE); + m_hash->final(buffer); + xor_buf(out, in, buffer, LEFT_SIZE); + + xor_buf(buffer, out, m_key2.data(), LEFT_SIZE); + m_cipher->set_key(buffer, LEFT_SIZE); + m_cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); + + in += m_block_size; + out += m_block_size; + } + } + +/* +* Lion Decryption +*/ +void Lion::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_key1.empty() == false); + + const size_t LEFT_SIZE = left_size(); + const size_t RIGHT_SIZE = right_size(); + + secure_vector buffer_vec(LEFT_SIZE); + uint8_t* buffer = buffer_vec.data(); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(buffer, in, m_key2.data(), LEFT_SIZE); + m_cipher->set_key(buffer, LEFT_SIZE); + m_cipher->cipher(in + LEFT_SIZE, out + LEFT_SIZE, RIGHT_SIZE); + + m_hash->update(out + LEFT_SIZE, RIGHT_SIZE); + m_hash->final(buffer); + xor_buf(out, in, buffer, LEFT_SIZE); + + xor_buf(buffer, out, m_key1.data(), LEFT_SIZE); + m_cipher->set_key(buffer, LEFT_SIZE); + m_cipher->cipher1(out + LEFT_SIZE, RIGHT_SIZE); + + in += m_block_size; + out += m_block_size; + } + } + +/* +* Lion Key Schedule +*/ +void Lion::key_schedule(const uint8_t key[], size_t length) + { + clear(); + + const size_t half = length / 2; + + m_key1.resize(left_size()); + m_key2.resize(left_size()); + clear_mem(m_key1.data(), m_key1.size()); + clear_mem(m_key2.data(), m_key2.size()); + copy_mem(m_key1.data(), key, half); + copy_mem(m_key2.data(), key + half, half); + } + +/* +* Return the name of this type +*/ +std::string Lion::name() const + { + return "Lion(" + m_hash->name() + "," + + m_cipher->name() + "," + + std::to_string(block_size()) + ")"; + } + +/* +* Return a clone of this object +*/ +BlockCipher* Lion::clone() const + { + return new Lion(m_hash->clone(), m_cipher->clone(), block_size()); + } + +/* +* Clear memory of sensitive data +*/ +void Lion::clear() + { + zap(m_key1); + zap(m_key2); + m_hash->clear(); + m_cipher->clear(); + } + +/* +* Lion Constructor +*/ +Lion::Lion(HashFunction* hash, StreamCipher* cipher, size_t bs) : + m_block_size(std::max(2*hash->output_length() + 1, bs)), + m_hash(hash), + m_cipher(cipher) + { + if(2*left_size() + 1 > m_block_size) + throw Invalid_Argument(name() + ": Chosen block size is too small"); + + if(!m_cipher->valid_keylength(left_size())) + throw Invalid_Argument(name() + ": This stream/hash combo is invalid"); + } + +} diff --git a/comm/third_party/botan/src/lib/block/lion/lion.h b/comm/third_party/botan/src/lib/block/lion/lion.h new file mode 100644 index 0000000000..fa8e9f4145 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/lion/lion.h @@ -0,0 +1,66 @@ +/* +* Lion +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LION_H_ +#define BOTAN_LION_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(lion.h) + +namespace Botan { + +/** +* Lion is a block cipher construction designed by Ross Anderson and +* Eli Biham, described in "Two Practical and Provably Secure Block +* Ciphers: BEAR and LION". It has a variable block size and is +* designed to encrypt very large blocks (up to a megabyte) + +* https://www.cl.cam.ac.uk/~rja14/Papers/bear-lion.pdf +*/ +class BOTAN_PUBLIC_API(2,0) Lion final : public BlockCipher + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + size_t block_size() const override { return m_block_size; } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(2, 2*m_hash->output_length(), 2); + } + + void clear() override; + std::string name() const override; + BlockCipher* clone() const override; + + /** + * @param hash the hash to use internally + * @param cipher the stream cipher to use internally + * @param block_size the size of the block to use + */ + Lion(HashFunction* hash, + StreamCipher* cipher, + size_t block_size); + private: + void key_schedule(const uint8_t[], size_t) override; + + size_t left_size() const { return m_hash->output_length(); } + size_t right_size() const { return m_block_size - left_size(); } + + const size_t m_block_size; + std::unique_ptr m_hash; + std::unique_ptr m_cipher; + secure_vector m_key1, m_key2; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/misty1/info.txt b/comm/third_party/botan/src/lib/block/misty1/info.txt new file mode 100644 index 0000000000..bf21dd4390 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/misty1/info.txt @@ -0,0 +1,3 @@ + +MISTY1 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/misty1/misty1.cpp b/comm/third_party/botan/src/lib/block/misty1/misty1.cpp new file mode 100644 index 0000000000..ba5b06abec --- /dev/null +++ b/comm/third_party/botan/src/lib/block/misty1/misty1.cpp @@ -0,0 +1,263 @@ +/* +* MISTY1 +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +alignas(64) static const uint8_t MISTY1_SBOX_S7[128] = { + 0x1B, 0x32, 0x33, 0x5A, 0x3B, 0x10, 0x17, 0x54, 0x5B, 0x1A, 0x72, 0x73, + 0x6B, 0x2C, 0x66, 0x49, 0x1F, 0x24, 0x13, 0x6C, 0x37, 0x2E, 0x3F, 0x4A, + 0x5D, 0x0F, 0x40, 0x56, 0x25, 0x51, 0x1C, 0x04, 0x0B, 0x46, 0x20, 0x0D, + 0x7B, 0x35, 0x44, 0x42, 0x2B, 0x1E, 0x41, 0x14, 0x4B, 0x79, 0x15, 0x6F, + 0x0E, 0x55, 0x09, 0x36, 0x74, 0x0C, 0x67, 0x53, 0x28, 0x0A, 0x7E, 0x38, + 0x02, 0x07, 0x60, 0x29, 0x19, 0x12, 0x65, 0x2F, 0x30, 0x39, 0x08, 0x68, + 0x5F, 0x78, 0x2A, 0x4C, 0x64, 0x45, 0x75, 0x3D, 0x59, 0x48, 0x03, 0x57, + 0x7C, 0x4F, 0x62, 0x3C, 0x1D, 0x21, 0x5E, 0x27, 0x6A, 0x70, 0x4D, 0x3A, + 0x01, 0x6D, 0x6E, 0x63, 0x18, 0x77, 0x23, 0x05, 0x26, 0x76, 0x00, 0x31, + 0x2D, 0x7A, 0x7F, 0x61, 0x50, 0x22, 0x11, 0x06, 0x47, 0x16, 0x52, 0x4E, + 0x71, 0x3E, 0x69, 0x43, 0x34, 0x5C, 0x58, 0x7D }; + +alignas(64) static const uint16_t MISTY1_SBOX_S9[512] = { + 0x01C3, 0x00CB, 0x0153, 0x019F, 0x01E3, 0x00E9, 0x00FB, 0x0035, 0x0181, + 0x00B9, 0x0117, 0x01EB, 0x0133, 0x0009, 0x002D, 0x00D3, 0x00C7, 0x014A, + 0x0037, 0x007E, 0x00EB, 0x0164, 0x0193, 0x01D8, 0x00A3, 0x011E, 0x0055, + 0x002C, 0x001D, 0x01A2, 0x0163, 0x0118, 0x014B, 0x0152, 0x01D2, 0x000F, + 0x002B, 0x0030, 0x013A, 0x00E5, 0x0111, 0x0138, 0x018E, 0x0063, 0x00E3, + 0x00C8, 0x01F4, 0x001B, 0x0001, 0x009D, 0x00F8, 0x01A0, 0x016D, 0x01F3, + 0x001C, 0x0146, 0x007D, 0x00D1, 0x0082, 0x01EA, 0x0183, 0x012D, 0x00F4, + 0x019E, 0x01D3, 0x00DD, 0x01E2, 0x0128, 0x01E0, 0x00EC, 0x0059, 0x0091, + 0x0011, 0x012F, 0x0026, 0x00DC, 0x00B0, 0x018C, 0x010F, 0x01F7, 0x00E7, + 0x016C, 0x00B6, 0x00F9, 0x00D8, 0x0151, 0x0101, 0x014C, 0x0103, 0x00B8, + 0x0154, 0x012B, 0x01AE, 0x0017, 0x0071, 0x000C, 0x0047, 0x0058, 0x007F, + 0x01A4, 0x0134, 0x0129, 0x0084, 0x015D, 0x019D, 0x01B2, 0x01A3, 0x0048, + 0x007C, 0x0051, 0x01CA, 0x0023, 0x013D, 0x01A7, 0x0165, 0x003B, 0x0042, + 0x00DA, 0x0192, 0x00CE, 0x00C1, 0x006B, 0x009F, 0x01F1, 0x012C, 0x0184, + 0x00FA, 0x0196, 0x01E1, 0x0169, 0x017D, 0x0031, 0x0180, 0x010A, 0x0094, + 0x01DA, 0x0186, 0x013E, 0x011C, 0x0060, 0x0175, 0x01CF, 0x0067, 0x0119, + 0x0065, 0x0068, 0x0099, 0x0150, 0x0008, 0x0007, 0x017C, 0x00B7, 0x0024, + 0x0019, 0x00DE, 0x0127, 0x00DB, 0x00E4, 0x01A9, 0x0052, 0x0109, 0x0090, + 0x019C, 0x01C1, 0x0028, 0x01B3, 0x0135, 0x016A, 0x0176, 0x00DF, 0x01E5, + 0x0188, 0x00C5, 0x016E, 0x01DE, 0x01B1, 0x00C3, 0x01DF, 0x0036, 0x00EE, + 0x01EE, 0x00F0, 0x0093, 0x0049, 0x009A, 0x01B6, 0x0069, 0x0081, 0x0125, + 0x000B, 0x005E, 0x00B4, 0x0149, 0x01C7, 0x0174, 0x003E, 0x013B, 0x01B7, + 0x008E, 0x01C6, 0x00AE, 0x0010, 0x0095, 0x01EF, 0x004E, 0x00F2, 0x01FD, + 0x0085, 0x00FD, 0x00F6, 0x00A0, 0x016F, 0x0083, 0x008A, 0x0156, 0x009B, + 0x013C, 0x0107, 0x0167, 0x0098, 0x01D0, 0x01E9, 0x0003, 0x01FE, 0x00BD, + 0x0122, 0x0089, 0x00D2, 0x018F, 0x0012, 0x0033, 0x006A, 0x0142, 0x00ED, + 0x0170, 0x011B, 0x00E2, 0x014F, 0x0158, 0x0131, 0x0147, 0x005D, 0x0113, + 0x01CD, 0x0079, 0x0161, 0x01A5, 0x0179, 0x009E, 0x01B4, 0x00CC, 0x0022, + 0x0132, 0x001A, 0x00E8, 0x0004, 0x0187, 0x01ED, 0x0197, 0x0039, 0x01BF, + 0x01D7, 0x0027, 0x018B, 0x00C6, 0x009C, 0x00D0, 0x014E, 0x006C, 0x0034, + 0x01F2, 0x006E, 0x00CA, 0x0025, 0x00BA, 0x0191, 0x00FE, 0x0013, 0x0106, + 0x002F, 0x01AD, 0x0172, 0x01DB, 0x00C0, 0x010B, 0x01D6, 0x00F5, 0x01EC, + 0x010D, 0x0076, 0x0114, 0x01AB, 0x0075, 0x010C, 0x01E4, 0x0159, 0x0054, + 0x011F, 0x004B, 0x00C4, 0x01BE, 0x00F7, 0x0029, 0x00A4, 0x000E, 0x01F0, + 0x0077, 0x004D, 0x017A, 0x0086, 0x008B, 0x00B3, 0x0171, 0x00BF, 0x010E, + 0x0104, 0x0097, 0x015B, 0x0160, 0x0168, 0x00D7, 0x00BB, 0x0066, 0x01CE, + 0x00FC, 0x0092, 0x01C5, 0x006F, 0x0016, 0x004A, 0x00A1, 0x0139, 0x00AF, + 0x00F1, 0x0190, 0x000A, 0x01AA, 0x0143, 0x017B, 0x0056, 0x018D, 0x0166, + 0x00D4, 0x01FB, 0x014D, 0x0194, 0x019A, 0x0087, 0x01F8, 0x0123, 0x00A7, + 0x01B8, 0x0141, 0x003C, 0x01F9, 0x0140, 0x002A, 0x0155, 0x011A, 0x01A1, + 0x0198, 0x00D5, 0x0126, 0x01AF, 0x0061, 0x012E, 0x0157, 0x01DC, 0x0072, + 0x018A, 0x00AA, 0x0096, 0x0115, 0x00EF, 0x0045, 0x007B, 0x008D, 0x0145, + 0x0053, 0x005F, 0x0178, 0x00B2, 0x002E, 0x0020, 0x01D5, 0x003F, 0x01C9, + 0x01E7, 0x01AC, 0x0044, 0x0038, 0x0014, 0x00B1, 0x016B, 0x00AB, 0x00B5, + 0x005A, 0x0182, 0x01C8, 0x01D4, 0x0018, 0x0177, 0x0064, 0x00CF, 0x006D, + 0x0100, 0x0199, 0x0130, 0x015A, 0x0005, 0x0120, 0x01BB, 0x01BD, 0x00E0, + 0x004F, 0x00D6, 0x013F, 0x01C4, 0x012A, 0x0015, 0x0006, 0x00FF, 0x019B, + 0x00A6, 0x0043, 0x0088, 0x0050, 0x015F, 0x01E8, 0x0121, 0x0073, 0x017E, + 0x00BC, 0x00C2, 0x00C9, 0x0173, 0x0189, 0x01F5, 0x0074, 0x01CC, 0x01E6, + 0x01A8, 0x0195, 0x001F, 0x0041, 0x000D, 0x01BA, 0x0032, 0x003D, 0x01D1, + 0x0080, 0x00A8, 0x0057, 0x01B9, 0x0162, 0x0148, 0x00D9, 0x0105, 0x0062, + 0x007A, 0x0021, 0x01FF, 0x0112, 0x0108, 0x01C0, 0x00A9, 0x011D, 0x01B0, + 0x01A6, 0x00CD, 0x00F3, 0x005C, 0x0102, 0x005B, 0x01D9, 0x0144, 0x01F6, + 0x00AD, 0x00A5, 0x003A, 0x01CB, 0x0136, 0x017F, 0x0046, 0x00E1, 0x001E, + 0x01DD, 0x00E6, 0x0137, 0x01FA, 0x0185, 0x008C, 0x008F, 0x0040, 0x01B5, + 0x00BE, 0x0078, 0x0000, 0x00AC, 0x0110, 0x015E, 0x0124, 0x0002, 0x01BC, + 0x00A2, 0x00EA, 0x0070, 0x01FC, 0x0116, 0x015C, 0x004C, 0x01C2 }; + +/* +* MISTY1 FI Function +*/ +uint16_t FI(uint16_t input, uint16_t key7, uint16_t key9) + { + uint16_t D9 = input >> 7, D7 = input & 0x7F; + D9 = MISTY1_SBOX_S9[D9] ^ D7; + D7 = (MISTY1_SBOX_S7[D7] ^ key7 ^ D9) & 0x7F; + D9 = MISTY1_SBOX_S9[D9 ^ key9] ^ D7; + return static_cast(D7 << 9) | D9; + } + +} + +/* +* MISTY1 Encryption +*/ +void MISTY1::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint16_t B0 = load_be(in, 0); + uint16_t B1 = load_be(in, 1); + uint16_t B2 = load_be(in, 2); + uint16_t B3 = load_be(in, 3); + + for(size_t j = 0; j != 12; j += 3) + { + const uint16_t* RK = &m_EK[8 * j]; + + B1 ^= B0 & RK[0]; + B0 ^= B1 | RK[1]; + B3 ^= B2 & RK[2]; + B2 ^= B3 | RK[3]; + + uint16_t T0, T1; + + T0 = FI(B0 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B1; + T1 = FI(B1 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; + T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; + + B2 ^= T1 ^ RK[13]; + B3 ^= T0; + + T0 = FI(B2 ^ RK[14], RK[15], RK[16]) ^ B3; + T1 = FI(B3 ^ RK[17], RK[18], RK[19]) ^ T0; + T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; + + B0 ^= T1 ^ RK[23]; + B1 ^= T0; + } + + B1 ^= B0 & m_EK[96]; + B0 ^= B1 | m_EK[97]; + B3 ^= B2 & m_EK[98]; + B2 ^= B3 | m_EK[99]; + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MISTY1 Decryption +*/ +void MISTY1::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint16_t B0 = load_be(in, 2); + uint16_t B1 = load_be(in, 3); + uint16_t B2 = load_be(in, 0); + uint16_t B3 = load_be(in, 1); + + for(size_t j = 0; j != 12; j += 3) + { + const uint16_t* RK = &m_DK[8 * j]; + + B2 ^= B3 | RK[0]; + B3 ^= B2 & RK[1]; + B0 ^= B1 | RK[2]; + B1 ^= B0 & RK[3]; + + uint16_t T0, T1; + + T0 = FI(B2 ^ RK[ 4], RK[ 5], RK[ 6]) ^ B3; + T1 = FI(B3 ^ RK[ 7], RK[ 8], RK[ 9]) ^ T0; + T0 = FI(T0 ^ RK[10], RK[11], RK[12]) ^ T1; + + B0 ^= T1 ^ RK[13]; + B1 ^= T0; + + T0 = FI(B0 ^ RK[14], RK[15], RK[16]) ^ B1; + T1 = FI(B1 ^ RK[17], RK[18], RK[19]) ^ T0; + T0 = FI(T0 ^ RK[20], RK[21], RK[22]) ^ T1; + + B2 ^= T1 ^ RK[23]; + B3 ^= T0; + } + + B2 ^= B3 | m_DK[96]; + B3 ^= B2 & m_DK[97]; + B0 ^= B1 | m_DK[98]; + B1 ^= B0 & m_DK[99]; + + store_be(out, B0, B1, B2, B3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* MISTY1 Key Schedule +*/ +void MISTY1::key_schedule(const uint8_t key[], size_t length) + { + secure_vector KS(32); + for(size_t i = 0; i != length / 2; ++i) + KS[i] = load_be(key, i); + + for(size_t i = 0; i != 8; ++i) + { + KS[i+ 8] = FI(KS[i], KS[(i+1) % 8] >> 9, KS[(i+1) % 8] & 0x1FF); + KS[i+16] = KS[i+8] >> 9; + KS[i+24] = KS[i+8] & 0x1FF; + } + + /* + * Precomputed indexes for the orderings of the subkeys (MISTY1 reuses + * values) + */ + static const uint8_t EK_ORDER[100] = { + 0x00, 0x0E, 0x0A, 0x04, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, + 0x1B, 0x04, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, 0x1C, 0x05, + 0x01, 0x0F, 0x0B, 0x05, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, + 0x1D, 0x06, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, 0x1E, 0x07, + 0x02, 0x08, 0x0C, 0x06, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, + 0x1F, 0x00, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, 0x18, 0x01, + 0x03, 0x09, 0x0D, 0x07, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, + 0x19, 0x02, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, 0x1A, 0x03, + 0x04, 0x0A, 0x0E, 0x00 }; + + static const uint8_t DK_ORDER[100] = { + 0x00, 0x0E, 0x0A, 0x04, 0x07, 0x14, 0x1C, 0x01, 0x10, 0x18, 0x06, 0x12, + 0x1A, 0x03, 0x06, 0x13, 0x1B, 0x00, 0x17, 0x1F, 0x05, 0x11, 0x19, 0x02, + 0x07, 0x0D, 0x09, 0x03, 0x05, 0x12, 0x1A, 0x07, 0x16, 0x1E, 0x04, 0x10, + 0x18, 0x01, 0x04, 0x11, 0x19, 0x06, 0x15, 0x1D, 0x03, 0x17, 0x1F, 0x00, + 0x06, 0x0C, 0x08, 0x02, 0x03, 0x10, 0x18, 0x05, 0x14, 0x1C, 0x02, 0x16, + 0x1E, 0x07, 0x02, 0x17, 0x1F, 0x04, 0x13, 0x1B, 0x01, 0x15, 0x1D, 0x06, + 0x05, 0x0B, 0x0F, 0x01, 0x01, 0x16, 0x1E, 0x03, 0x12, 0x1A, 0x00, 0x14, + 0x1C, 0x05, 0x00, 0x15, 0x1D, 0x02, 0x11, 0x19, 0x07, 0x13, 0x1B, 0x04, + 0x04, 0x0A, 0x0E, 0x00 }; + + m_EK.resize(100); + m_DK.resize(100); + + for(size_t i = 0; i != 100; ++i) + { + m_EK[i] = KS[EK_ORDER[i]]; + m_DK[i] = KS[DK_ORDER[i]]; + } + } + +void MISTY1::clear() + { + zap(m_EK); + zap(m_DK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/misty1/misty1.h b/comm/third_party/botan/src/lib/block/misty1/misty1.h new file mode 100644 index 0000000000..b6c4abbd53 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/misty1/misty1.h @@ -0,0 +1,37 @@ +/* +* MISTY1 +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MISTY1_H_ +#define BOTAN_MISTY1_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(misty1.h) + +namespace Botan { + +/** +* MISTY1 with 8 rounds +*/ +class BOTAN_PUBLIC_API(2,0) MISTY1 final : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "MISTY1"; } + BlockCipher* clone() const override { return new MISTY1; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_EK, m_DK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/noekeon/info.txt b/comm/third_party/botan/src/lib/block/noekeon/info.txt new file mode 100644 index 0000000000..f3445eb7e6 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/noekeon/info.txt @@ -0,0 +1,3 @@ + +NOEKEON -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/noekeon/noekeon.cpp b/comm/third_party/botan/src/lib/block/noekeon/noekeon.cpp new file mode 100644 index 0000000000..0a820c7014 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/noekeon/noekeon.cpp @@ -0,0 +1,267 @@ +/* +* Noekeon +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Noekeon's Theta Operation +*/ +inline void theta(uint32_t& A0, uint32_t& A1, + uint32_t& A2, uint32_t& A3, + const uint32_t EK[4]) + { + uint32_t T = A0 ^ A2; + T ^= rotl<8>(T) ^ rotr<8>(T); + A1 ^= T; + A3 ^= T; + + A0 ^= EK[0]; + A1 ^= EK[1]; + A2 ^= EK[2]; + A3 ^= EK[3]; + + T = A1 ^ A3; + T ^= rotl<8>(T) ^ rotr<8>(T); + A0 ^= T; + A2 ^= T; + } + +/* +* Theta With Null Key +*/ +inline void theta(uint32_t& A0, uint32_t& A1, + uint32_t& A2, uint32_t& A3) + { + uint32_t T = A0 ^ A2; + T ^= rotl<8>(T) ^ rotr<8>(T); + A1 ^= T; + A3 ^= T; + + T = A1 ^ A3; + T ^= rotl<8>(T) ^ rotr<8>(T); + A0 ^= T; + A2 ^= T; + } + +/* +* Noekeon's Gamma S-Box Layer +*/ +inline void gamma(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) + { + A1 ^= ~A3 & ~A2; + A0 ^= A2 & A1; + + uint32_t T = A3; + A3 = A0; + A0 = T; + + A2 ^= A0 ^ A1 ^ A3; + + A1 ^= ~A3 & ~A2; + A0 ^= A2 & A1; + } + +} + +size_t Noekeon::parallelism() const + { +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + return 4; + } +#endif + + return 1; + } + +std::string Noekeon::provider() const + { +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + return "simd"; + } +#endif + + return "base"; + } + +/* +* Noekeon Round Constants +*/ +const uint8_t Noekeon::RC[] = { + 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, + 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, + 0xD4 }; + +/* +* Noekeon Encryption +*/ +void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_encrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t A0 = load_be(in, 0); + uint32_t A1 = load_be(in, 1); + uint32_t A2 = load_be(in, 2); + uint32_t A3 = load_be(in, 3); + + for(size_t j = 0; j != 16; ++j) + { + A0 ^= RC[j]; + theta(A0, A1, A2, A3, m_EK.data()); + + A1 = rotl<1>(A1); + A2 = rotl<5>(A2); + A3 = rotl<2>(A3); + + gamma(A0, A1, A2, A3); + + A1 = rotr<1>(A1); + A2 = rotr<5>(A2); + A3 = rotr<2>(A3); + } + + A0 ^= RC[16]; + theta(A0, A1, A2, A3, m_EK.data()); + + store_be(out, A0, A1, A2, A3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Noekeon Encryption +*/ +void Noekeon::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_decrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t A0 = load_be(in, 0); + uint32_t A1 = load_be(in, 1); + uint32_t A2 = load_be(in, 2); + uint32_t A3 = load_be(in, 3); + + for(size_t j = 16; j != 0; --j) + { + theta(A0, A1, A2, A3, m_DK.data()); + A0 ^= RC[j]; + + A1 = rotl<1>(A1); + A2 = rotl<5>(A2); + A3 = rotl<2>(A3); + + gamma(A0, A1, A2, A3); + + A1 = rotr<1>(A1); + A2 = rotr<5>(A2); + A3 = rotr<2>(A3); + } + + theta(A0, A1, A2, A3, m_DK.data()); + A0 ^= RC[0]; + + store_be(out, A0, A1, A2, A3); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Noekeon Key Schedule +*/ +void Noekeon::key_schedule(const uint8_t key[], size_t) + { + uint32_t A0 = load_be(key, 0); + uint32_t A1 = load_be(key, 1); + uint32_t A2 = load_be(key, 2); + uint32_t A3 = load_be(key, 3); + + for(size_t i = 0; i != 16; ++i) + { + A0 ^= RC[i]; + theta(A0, A1, A2, A3); + + A1 = rotl<1>(A1); + A2 = rotl<5>(A2); + A3 = rotl<2>(A3); + + gamma(A0, A1, A2, A3); + + A1 = rotr<1>(A1); + A2 = rotr<5>(A2); + A3 = rotr<2>(A3); + } + + A0 ^= RC[16]; + + m_DK.resize(4); + m_DK[0] = A0; + m_DK[1] = A1; + m_DK[2] = A2; + m_DK[3] = A3; + + theta(A0, A1, A2, A3); + + m_EK.resize(4); + m_EK[0] = A0; + m_EK[1] = A1; + m_EK[2] = A2; + m_EK[3] = A3; + } + +/* +* Clear memory of sensitive data +*/ +void Noekeon::clear() + { + zap(m_EK); + zap(m_DK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/noekeon/noekeon.h b/comm/third_party/botan/src/lib/block/noekeon/noekeon.h new file mode 100644 index 0000000000..9e7e4a5ff6 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/noekeon/noekeon.h @@ -0,0 +1,49 @@ +/* +* Noekeon +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NOEKEON_H_ +#define BOTAN_NOEKEON_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(noekeon.h) + +namespace Botan { + +/** +* Noekeon +*/ +class BOTAN_PUBLIC_API(2,0) Noekeon final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + std::string provider() const override; + void clear() override; + std::string name() const override { return "Noekeon"; } + BlockCipher* clone() const override { return new Noekeon; } + size_t parallelism() const override; + + private: +#if defined(BOTAN_HAS_NOEKEON_SIMD) + void simd_encrypt_4(const uint8_t in[], uint8_t out[]) const; + void simd_decrypt_4(const uint8_t in[], uint8_t out[]) const; +#endif + + /** + * The Noekeon round constants + */ + static const uint8_t RC[17]; + + void key_schedule(const uint8_t[], size_t) override; + secure_vector m_EK, m_DK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/info.txt b/comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/info.txt new file mode 100644 index 0000000000..a09e491b5c --- /dev/null +++ b/comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/info.txt @@ -0,0 +1,8 @@ + +NOEKEON_SIMD -> 20160903 + + + +noekeon +simd + diff --git a/comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/noekeon_simd.cpp b/comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/noekeon_simd.cpp new file mode 100644 index 0000000000..83467a054c --- /dev/null +++ b/comm/third_party/botan/src/lib/block/noekeon/noekeon_simd/noekeon_simd.cpp @@ -0,0 +1,143 @@ +/* +* Noekeon in SIMD +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Noekeon's Theta Operation +*/ +#define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3) \ + do { \ + SIMD_4x32 T = A0 ^ A2; \ + T ^= T.rotl<8>() ^ T.rotr<8>(); \ + A1 ^= T; \ + A3 ^= T; \ + \ + A0 ^= K0; \ + A1 ^= K1; \ + A2 ^= K2; \ + A3 ^= K3; \ + \ + T = A1 ^ A3; \ + T ^= T.rotl<8>() ^ T.rotr<8>(); \ + A0 ^= T; \ + A2 ^= T; \ + } while(0) + +/* +* Noekeon's Gamma S-Box Layer +*/ +#define NOK_SIMD_GAMMA(A0, A1, A2, A3) \ + do \ + { \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + \ + SIMD_4x32 T = A3; \ + A3 = A0; \ + A0 = T; \ + \ + A2 ^= A0 ^ A1 ^ A3; \ + \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + } while(0) + +/* +* Noekeon Encryption +*/ +void Noekeon::simd_encrypt_4(const uint8_t in[], uint8_t out[]) const + { + const SIMD_4x32 K0 = SIMD_4x32::splat(m_EK[0]); + const SIMD_4x32 K1 = SIMD_4x32::splat(m_EK[1]); + const SIMD_4x32 K2 = SIMD_4x32::splat(m_EK[2]); + const SIMD_4x32 K3 = SIMD_4x32::splat(m_EK[3]); + + SIMD_4x32 A0 = SIMD_4x32::load_be(in ); + SIMD_4x32 A1 = SIMD_4x32::load_be(in + 16); + SIMD_4x32 A2 = SIMD_4x32::load_be(in + 32); + SIMD_4x32 A3 = SIMD_4x32::load_be(in + 48); + + SIMD_4x32::transpose(A0, A1, A2, A3); + + for(size_t i = 0; i != 16; ++i) + { + A0 ^= SIMD_4x32::splat(RC[i]); + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A1 = A1.rotl<1>(); + A2 = A2.rotl<5>(); + A3 = A3.rotl<2>(); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1 = A1.rotr<1>(); + A2 = A2.rotr<5>(); + A3 = A3.rotr<2>(); + } + + A0 ^= SIMD_4x32::splat(RC[16]); + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + SIMD_4x32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + } + +/* +* Noekeon Encryption +*/ +void Noekeon::simd_decrypt_4(const uint8_t in[], uint8_t out[]) const + { + const SIMD_4x32 K0 = SIMD_4x32::splat(m_DK[0]); + const SIMD_4x32 K1 = SIMD_4x32::splat(m_DK[1]); + const SIMD_4x32 K2 = SIMD_4x32::splat(m_DK[2]); + const SIMD_4x32 K3 = SIMD_4x32::splat(m_DK[3]); + + SIMD_4x32 A0 = SIMD_4x32::load_be(in ); + SIMD_4x32 A1 = SIMD_4x32::load_be(in + 16); + SIMD_4x32 A2 = SIMD_4x32::load_be(in + 32); + SIMD_4x32 A3 = SIMD_4x32::load_be(in + 48); + + SIMD_4x32::transpose(A0, A1, A2, A3); + + for(size_t i = 0; i != 16; ++i) + { + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A0 ^= SIMD_4x32::splat(RC[16-i]); + + A1 = A1.rotl<1>(); + A2 = A2.rotl<5>(); + A3 = A3.rotl<2>(); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1 = A1.rotr<1>(); + A2 = A2.rotr<5>(); + A3 = A3.rotr<2>(); + } + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + A0 ^= SIMD_4x32::splat(RC[0]); + + SIMD_4x32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + } + +} diff --git a/comm/third_party/botan/src/lib/block/seed/info.txt b/comm/third_party/botan/src/lib/block/seed/info.txt new file mode 100644 index 0000000000..dd395eda1a --- /dev/null +++ b/comm/third_party/botan/src/lib/block/seed/info.txt @@ -0,0 +1,3 @@ + +SEED -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/seed/seed.cpp b/comm/third_party/botan/src/lib/block/seed/seed.cpp new file mode 100644 index 0000000000..e596c70acb --- /dev/null +++ b/comm/third_party/botan/src/lib/block/seed/seed.cpp @@ -0,0 +1,328 @@ +/* +* SEED +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +alignas(64) const uint32_t SEED_S0[256] = { + 0x2989A1A8, 0x05858184, 0x16C6D2D4, 0x13C3D3D0, 0x14445054, 0x1D0D111C, + 0x2C8CA0AC, 0x25052124, 0x1D4D515C, 0x03434340, 0x18081018, 0x1E0E121C, + 0x11415150, 0x3CCCF0FC, 0x0ACAC2C8, 0x23436360, 0x28082028, 0x04444044, + 0x20002020, 0x1D8D919C, 0x20C0E0E0, 0x22C2E2E0, 0x08C8C0C8, 0x17071314, + 0x2585A1A4, 0x0F8F838C, 0x03030300, 0x3B4B7378, 0x3B8BB3B8, 0x13031310, + 0x12C2D2D0, 0x2ECEE2EC, 0x30407070, 0x0C8C808C, 0x3F0F333C, 0x2888A0A8, + 0x32023230, 0x1DCDD1DC, 0x36C6F2F4, 0x34447074, 0x2CCCE0EC, 0x15859194, + 0x0B0B0308, 0x17475354, 0x1C4C505C, 0x1B4B5358, 0x3D8DB1BC, 0x01010100, + 0x24042024, 0x1C0C101C, 0x33437370, 0x18889098, 0x10001010, 0x0CCCC0CC, + 0x32C2F2F0, 0x19C9D1D8, 0x2C0C202C, 0x27C7E3E4, 0x32427270, 0x03838380, + 0x1B8B9398, 0x11C1D1D0, 0x06868284, 0x09C9C1C8, 0x20406060, 0x10405050, + 0x2383A3A0, 0x2BCBE3E8, 0x0D0D010C, 0x3686B2B4, 0x1E8E929C, 0x0F4F434C, + 0x3787B3B4, 0x1A4A5258, 0x06C6C2C4, 0x38487078, 0x2686A2A4, 0x12021210, + 0x2F8FA3AC, 0x15C5D1D4, 0x21416160, 0x03C3C3C0, 0x3484B0B4, 0x01414140, + 0x12425250, 0x3D4D717C, 0x0D8D818C, 0x08080008, 0x1F0F131C, 0x19899198, + 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37C7F3F4, 0x21C1E1E0, + 0x3DCDF1FC, 0x36467274, 0x2F0F232C, 0x27072324, 0x3080B0B0, 0x0B8B8388, + 0x0E0E020C, 0x2B8BA3A8, 0x2282A2A0, 0x2E4E626C, 0x13839390, 0x0D4D414C, + 0x29496168, 0x3C4C707C, 0x09090108, 0x0A0A0208, 0x3F8FB3BC, 0x2FCFE3EC, + 0x33C3F3F0, 0x05C5C1C4, 0x07878384, 0x14041014, 0x3ECEF2FC, 0x24446064, + 0x1ECED2DC, 0x2E0E222C, 0x0B4B4348, 0x1A0A1218, 0x06060204, 0x21012120, + 0x2B4B6368, 0x26466264, 0x02020200, 0x35C5F1F4, 0x12829290, 0x0A8A8288, + 0x0C0C000C, 0x3383B3B0, 0x3E4E727C, 0x10C0D0D0, 0x3A4A7278, 0x07474344, + 0x16869294, 0x25C5E1E4, 0x26062224, 0x00808080, 0x2D8DA1AC, 0x1FCFD3DC, + 0x2181A1A0, 0x30003030, 0x37073334, 0x2E8EA2AC, 0x36063234, 0x15051114, + 0x22022220, 0x38083038, 0x34C4F0F4, 0x2787A3A4, 0x05454144, 0x0C4C404C, + 0x01818180, 0x29C9E1E8, 0x04848084, 0x17879394, 0x35053134, 0x0BCBC3C8, + 0x0ECEC2CC, 0x3C0C303C, 0x31417170, 0x11011110, 0x07C7C3C4, 0x09898188, + 0x35457174, 0x3BCBF3F8, 0x1ACAD2D8, 0x38C8F0F8, 0x14849094, 0x19495158, + 0x02828280, 0x04C4C0C4, 0x3FCFF3FC, 0x09494148, 0x39093138, 0x27476364, + 0x00C0C0C0, 0x0FCFC3CC, 0x17C7D3D4, 0x3888B0B8, 0x0F0F030C, 0x0E8E828C, + 0x02424240, 0x23032320, 0x11819190, 0x2C4C606C, 0x1BCBD3D8, 0x2484A0A4, + 0x34043034, 0x31C1F1F0, 0x08484048, 0x02C2C2C0, 0x2F4F636C, 0x3D0D313C, + 0x2D0D212C, 0x00404040, 0x3E8EB2BC, 0x3E0E323C, 0x3C8CB0BC, 0x01C1C1C0, + 0x2A8AA2A8, 0x3A8AB2B8, 0x0E4E424C, 0x15455154, 0x3B0B3338, 0x1CCCD0DC, + 0x28486068, 0x3F4F737C, 0x1C8C909C, 0x18C8D0D8, 0x0A4A4248, 0x16465254, + 0x37477374, 0x2080A0A0, 0x2DCDE1EC, 0x06464244, 0x3585B1B4, 0x2B0B2328, + 0x25456164, 0x3ACAF2F8, 0x23C3E3E0, 0x3989B1B8, 0x3181B1B0, 0x1F8F939C, + 0x1E4E525C, 0x39C9F1F8, 0x26C6E2E4, 0x3282B2B0, 0x31013130, 0x2ACAE2E8, + 0x2D4D616C, 0x1F4F535C, 0x24C4E0E4, 0x30C0F0F0, 0x0DCDC1CC, 0x08888088, + 0x16061214, 0x3A0A3238, 0x18485058, 0x14C4D0D4, 0x22426260, 0x29092128, + 0x07070304, 0x33033330, 0x28C8E0E8, 0x1B0B1318, 0x05050104, 0x39497178, + 0x10809090, 0x2A4A6268, 0x2A0A2228, 0x1A8A9298 }; + +alignas(64) const uint32_t SEED_S1[256] = { + 0x38380830, 0xE828C8E0, 0x2C2D0D21, 0xA42686A2, 0xCC0FCFC3, 0xDC1ECED2, + 0xB03383B3, 0xB83888B0, 0xAC2F8FA3, 0x60204060, 0x54154551, 0xC407C7C3, + 0x44044440, 0x6C2F4F63, 0x682B4B63, 0x581B4B53, 0xC003C3C3, 0x60224262, + 0x30330333, 0xB43585B1, 0x28290921, 0xA02080A0, 0xE022C2E2, 0xA42787A3, + 0xD013C3D3, 0x90118191, 0x10110111, 0x04060602, 0x1C1C0C10, 0xBC3C8CB0, + 0x34360632, 0x480B4B43, 0xEC2FCFE3, 0x88088880, 0x6C2C4C60, 0xA82888A0, + 0x14170713, 0xC404C4C0, 0x14160612, 0xF434C4F0, 0xC002C2C2, 0x44054541, + 0xE021C1E1, 0xD416C6D2, 0x3C3F0F33, 0x3C3D0D31, 0x8C0E8E82, 0x98188890, + 0x28280820, 0x4C0E4E42, 0xF436C6F2, 0x3C3E0E32, 0xA42585A1, 0xF839C9F1, + 0x0C0D0D01, 0xDC1FCFD3, 0xD818C8D0, 0x282B0B23, 0x64264662, 0x783A4A72, + 0x24270723, 0x2C2F0F23, 0xF031C1F1, 0x70324272, 0x40024242, 0xD414C4D0, + 0x40014141, 0xC000C0C0, 0x70334373, 0x64274763, 0xAC2C8CA0, 0x880B8B83, + 0xF437C7F3, 0xAC2D8DA1, 0x80008080, 0x1C1F0F13, 0xC80ACAC2, 0x2C2C0C20, + 0xA82A8AA2, 0x34340430, 0xD012C2D2, 0x080B0B03, 0xEC2ECEE2, 0xE829C9E1, + 0x5C1D4D51, 0x94148490, 0x18180810, 0xF838C8F0, 0x54174753, 0xAC2E8EA2, + 0x08080800, 0xC405C5C1, 0x10130313, 0xCC0DCDC1, 0x84068682, 0xB83989B1, + 0xFC3FCFF3, 0x7C3D4D71, 0xC001C1C1, 0x30310131, 0xF435C5F1, 0x880A8A82, + 0x682A4A62, 0xB03181B1, 0xD011C1D1, 0x20200020, 0xD417C7D3, 0x00020202, + 0x20220222, 0x04040400, 0x68284860, 0x70314171, 0x04070703, 0xD81BCBD3, + 0x9C1D8D91, 0x98198991, 0x60214161, 0xBC3E8EB2, 0xE426C6E2, 0x58194951, + 0xDC1DCDD1, 0x50114151, 0x90108090, 0xDC1CCCD0, 0x981A8A92, 0xA02383A3, + 0xA82B8BA3, 0xD010C0D0, 0x80018181, 0x0C0F0F03, 0x44074743, 0x181A0A12, + 0xE023C3E3, 0xEC2CCCE0, 0x8C0D8D81, 0xBC3F8FB3, 0x94168692, 0x783B4B73, + 0x5C1C4C50, 0xA02282A2, 0xA02181A1, 0x60234363, 0x20230323, 0x4C0D4D41, + 0xC808C8C0, 0x9C1E8E92, 0x9C1C8C90, 0x383A0A32, 0x0C0C0C00, 0x2C2E0E22, + 0xB83A8AB2, 0x6C2E4E62, 0x9C1F8F93, 0x581A4A52, 0xF032C2F2, 0x90128292, + 0xF033C3F3, 0x48094941, 0x78384870, 0xCC0CCCC0, 0x14150511, 0xF83BCBF3, + 0x70304070, 0x74354571, 0x7C3F4F73, 0x34350531, 0x10100010, 0x00030303, + 0x64244460, 0x6C2D4D61, 0xC406C6C2, 0x74344470, 0xD415C5D1, 0xB43484B0, + 0xE82ACAE2, 0x08090901, 0x74364672, 0x18190911, 0xFC3ECEF2, 0x40004040, + 0x10120212, 0xE020C0E0, 0xBC3D8DB1, 0x04050501, 0xF83ACAF2, 0x00010101, + 0xF030C0F0, 0x282A0A22, 0x5C1E4E52, 0xA82989A1, 0x54164652, 0x40034343, + 0x84058581, 0x14140410, 0x88098981, 0x981B8B93, 0xB03080B0, 0xE425C5E1, + 0x48084840, 0x78394971, 0x94178793, 0xFC3CCCF0, 0x1C1E0E12, 0x80028282, + 0x20210121, 0x8C0C8C80, 0x181B0B13, 0x5C1F4F53, 0x74374773, 0x54144450, + 0xB03282B2, 0x1C1D0D11, 0x24250521, 0x4C0F4F43, 0x00000000, 0x44064642, + 0xEC2DCDE1, 0x58184850, 0x50124252, 0xE82BCBE3, 0x7C3E4E72, 0xD81ACAD2, + 0xC809C9C1, 0xFC3DCDF1, 0x30300030, 0x94158591, 0x64254561, 0x3C3C0C30, + 0xB43686B2, 0xE424C4E0, 0xB83B8BB3, 0x7C3C4C70, 0x0C0E0E02, 0x50104050, + 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393, + 0x34370733, 0xE427C7E3, 0x24240420, 0xA42484A0, 0xC80BCBC3, 0x50134353, + 0x080A0A02, 0x84078783, 0xD819C9D1, 0x4C0C4C40, 0x80038383, 0x8C0F8F83, + 0xCC0ECEC2, 0x383B0B33, 0x480A4A42, 0xB43787B3 }; + +alignas(64) const uint32_t SEED_S2[256] = { + 0xA1A82989, 0x81840585, 0xD2D416C6, 0xD3D013C3, 0x50541444, 0x111C1D0D, + 0xA0AC2C8C, 0x21242505, 0x515C1D4D, 0x43400343, 0x10181808, 0x121C1E0E, + 0x51501141, 0xF0FC3CCC, 0xC2C80ACA, 0x63602343, 0x20282808, 0x40440444, + 0x20202000, 0x919C1D8D, 0xE0E020C0, 0xE2E022C2, 0xC0C808C8, 0x13141707, + 0xA1A42585, 0x838C0F8F, 0x03000303, 0x73783B4B, 0xB3B83B8B, 0x13101303, + 0xD2D012C2, 0xE2EC2ECE, 0x70703040, 0x808C0C8C, 0x333C3F0F, 0xA0A82888, + 0x32303202, 0xD1DC1DCD, 0xF2F436C6, 0x70743444, 0xE0EC2CCC, 0x91941585, + 0x03080B0B, 0x53541747, 0x505C1C4C, 0x53581B4B, 0xB1BC3D8D, 0x01000101, + 0x20242404, 0x101C1C0C, 0x73703343, 0x90981888, 0x10101000, 0xC0CC0CCC, + 0xF2F032C2, 0xD1D819C9, 0x202C2C0C, 0xE3E427C7, 0x72703242, 0x83800383, + 0x93981B8B, 0xD1D011C1, 0x82840686, 0xC1C809C9, 0x60602040, 0x50501040, + 0xA3A02383, 0xE3E82BCB, 0x010C0D0D, 0xB2B43686, 0x929C1E8E, 0x434C0F4F, + 0xB3B43787, 0x52581A4A, 0xC2C406C6, 0x70783848, 0xA2A42686, 0x12101202, + 0xA3AC2F8F, 0xD1D415C5, 0x61602141, 0xC3C003C3, 0xB0B43484, 0x41400141, + 0x52501242, 0x717C3D4D, 0x818C0D8D, 0x00080808, 0x131C1F0F, 0x91981989, + 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xF3F437C7, 0xE1E021C1, + 0xF1FC3DCD, 0x72743646, 0x232C2F0F, 0x23242707, 0xB0B03080, 0x83880B8B, + 0x020C0E0E, 0xA3A82B8B, 0xA2A02282, 0x626C2E4E, 0x93901383, 0x414C0D4D, + 0x61682949, 0x707C3C4C, 0x01080909, 0x02080A0A, 0xB3BC3F8F, 0xE3EC2FCF, + 0xF3F033C3, 0xC1C405C5, 0x83840787, 0x10141404, 0xF2FC3ECE, 0x60642444, + 0xD2DC1ECE, 0x222C2E0E, 0x43480B4B, 0x12181A0A, 0x02040606, 0x21202101, + 0x63682B4B, 0x62642646, 0x02000202, 0xF1F435C5, 0x92901282, 0x82880A8A, + 0x000C0C0C, 0xB3B03383, 0x727C3E4E, 0xD0D010C0, 0x72783A4A, 0x43440747, + 0x92941686, 0xE1E425C5, 0x22242606, 0x80800080, 0xA1AC2D8D, 0xD3DC1FCF, + 0xA1A02181, 0x30303000, 0x33343707, 0xA2AC2E8E, 0x32343606, 0x11141505, + 0x22202202, 0x30383808, 0xF0F434C4, 0xA3A42787, 0x41440545, 0x404C0C4C, + 0x81800181, 0xE1E829C9, 0x80840484, 0x93941787, 0x31343505, 0xC3C80BCB, + 0xC2CC0ECE, 0x303C3C0C, 0x71703141, 0x11101101, 0xC3C407C7, 0x81880989, + 0x71743545, 0xF3F83BCB, 0xD2D81ACA, 0xF0F838C8, 0x90941484, 0x51581949, + 0x82800282, 0xC0C404C4, 0xF3FC3FCF, 0x41480949, 0x31383909, 0x63642747, + 0xC0C000C0, 0xC3CC0FCF, 0xD3D417C7, 0xB0B83888, 0x030C0F0F, 0x828C0E8E, + 0x42400242, 0x23202303, 0x91901181, 0x606C2C4C, 0xD3D81BCB, 0xA0A42484, + 0x30343404, 0xF1F031C1, 0x40480848, 0xC2C002C2, 0x636C2F4F, 0x313C3D0D, + 0x212C2D0D, 0x40400040, 0xB2BC3E8E, 0x323C3E0E, 0xB0BC3C8C, 0xC1C001C1, + 0xA2A82A8A, 0xB2B83A8A, 0x424C0E4E, 0x51541545, 0x33383B0B, 0xD0DC1CCC, + 0x60682848, 0x737C3F4F, 0x909C1C8C, 0xD0D818C8, 0x42480A4A, 0x52541646, + 0x73743747, 0xA0A02080, 0xE1EC2DCD, 0x42440646, 0xB1B43585, 0x23282B0B, + 0x61642545, 0xF2F83ACA, 0xE3E023C3, 0xB1B83989, 0xB1B03181, 0x939C1F8F, + 0x525C1E4E, 0xF1F839C9, 0xE2E426C6, 0xB2B03282, 0x31303101, 0xE2E82ACA, + 0x616C2D4D, 0x535C1F4F, 0xE0E424C4, 0xF0F030C0, 0xC1CC0DCD, 0x80880888, + 0x12141606, 0x32383A0A, 0x50581848, 0xD0D414C4, 0x62602242, 0x21282909, + 0x03040707, 0x33303303, 0xE0E828C8, 0x13181B0B, 0x01040505, 0x71783949, + 0x90901080, 0x62682A4A, 0x22282A0A, 0x92981A8A }; + +alignas(64) const uint32_t SEED_S3[256] = { + 0x08303838, 0xC8E0E828, 0x0D212C2D, 0x86A2A426, 0xCFC3CC0F, 0xCED2DC1E, + 0x83B3B033, 0x88B0B838, 0x8FA3AC2F, 0x40606020, 0x45515415, 0xC7C3C407, + 0x44404404, 0x4F636C2F, 0x4B63682B, 0x4B53581B, 0xC3C3C003, 0x42626022, + 0x03333033, 0x85B1B435, 0x09212829, 0x80A0A020, 0xC2E2E022, 0x87A3A427, + 0xC3D3D013, 0x81919011, 0x01111011, 0x06020406, 0x0C101C1C, 0x8CB0BC3C, + 0x06323436, 0x4B43480B, 0xCFE3EC2F, 0x88808808, 0x4C606C2C, 0x88A0A828, + 0x07131417, 0xC4C0C404, 0x06121416, 0xC4F0F434, 0xC2C2C002, 0x45414405, + 0xC1E1E021, 0xC6D2D416, 0x0F333C3F, 0x0D313C3D, 0x8E828C0E, 0x88909818, + 0x08202828, 0x4E424C0E, 0xC6F2F436, 0x0E323C3E, 0x85A1A425, 0xC9F1F839, + 0x0D010C0D, 0xCFD3DC1F, 0xC8D0D818, 0x0B23282B, 0x46626426, 0x4A72783A, + 0x07232427, 0x0F232C2F, 0xC1F1F031, 0x42727032, 0x42424002, 0xC4D0D414, + 0x41414001, 0xC0C0C000, 0x43737033, 0x47636427, 0x8CA0AC2C, 0x8B83880B, + 0xC7F3F437, 0x8DA1AC2D, 0x80808000, 0x0F131C1F, 0xCAC2C80A, 0x0C202C2C, + 0x8AA2A82A, 0x04303434, 0xC2D2D012, 0x0B03080B, 0xCEE2EC2E, 0xC9E1E829, + 0x4D515C1D, 0x84909414, 0x08101818, 0xC8F0F838, 0x47535417, 0x8EA2AC2E, + 0x08000808, 0xC5C1C405, 0x03131013, 0xCDC1CC0D, 0x86828406, 0x89B1B839, + 0xCFF3FC3F, 0x4D717C3D, 0xC1C1C001, 0x01313031, 0xC5F1F435, 0x8A82880A, + 0x4A62682A, 0x81B1B031, 0xC1D1D011, 0x00202020, 0xC7D3D417, 0x02020002, + 0x02222022, 0x04000404, 0x48606828, 0x41717031, 0x07030407, 0xCBD3D81B, + 0x8D919C1D, 0x89919819, 0x41616021, 0x8EB2BC3E, 0xC6E2E426, 0x49515819, + 0xCDD1DC1D, 0x41515011, 0x80909010, 0xCCD0DC1C, 0x8A92981A, 0x83A3A023, + 0x8BA3A82B, 0xC0D0D010, 0x81818001, 0x0F030C0F, 0x47434407, 0x0A12181A, + 0xC3E3E023, 0xCCE0EC2C, 0x8D818C0D, 0x8FB3BC3F, 0x86929416, 0x4B73783B, + 0x4C505C1C, 0x82A2A022, 0x81A1A021, 0x43636023, 0x03232023, 0x4D414C0D, + 0xC8C0C808, 0x8E929C1E, 0x8C909C1C, 0x0A32383A, 0x0C000C0C, 0x0E222C2E, + 0x8AB2B83A, 0x4E626C2E, 0x8F939C1F, 0x4A52581A, 0xC2F2F032, 0x82929012, + 0xC3F3F033, 0x49414809, 0x48707838, 0xCCC0CC0C, 0x05111415, 0xCBF3F83B, + 0x40707030, 0x45717435, 0x4F737C3F, 0x05313435, 0x00101010, 0x03030003, + 0x44606424, 0x4D616C2D, 0xC6C2C406, 0x44707434, 0xC5D1D415, 0x84B0B434, + 0xCAE2E82A, 0x09010809, 0x46727436, 0x09111819, 0xCEF2FC3E, 0x40404000, + 0x02121012, 0xC0E0E020, 0x8DB1BC3D, 0x05010405, 0xCAF2F83A, 0x01010001, + 0xC0F0F030, 0x0A22282A, 0x4E525C1E, 0x89A1A829, 0x46525416, 0x43434003, + 0x85818405, 0x04101414, 0x89818809, 0x8B93981B, 0x80B0B030, 0xC5E1E425, + 0x48404808, 0x49717839, 0x87939417, 0xCCF0FC3C, 0x0E121C1E, 0x82828002, + 0x01212021, 0x8C808C0C, 0x0B13181B, 0x4F535C1F, 0x47737437, 0x44505414, + 0x82B2B032, 0x0D111C1D, 0x05212425, 0x4F434C0F, 0x00000000, 0x46424406, + 0xCDE1EC2D, 0x48505818, 0x42525012, 0xCBE3E82B, 0x4E727C3E, 0xCAD2D81A, + 0xC9C1C809, 0xCDF1FC3D, 0x00303030, 0x85919415, 0x45616425, 0x0C303C3C, + 0x86B2B436, 0xC4E0E424, 0x8BB3B83B, 0x4C707C3C, 0x0E020C0E, 0x40505010, + 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013, + 0x07333437, 0xC7E3E427, 0x04202424, 0x84A0A424, 0xCBC3C80B, 0x43535013, + 0x0A02080A, 0x87838407, 0xC9D1D819, 0x4C404C0C, 0x83838003, 0x8F838C0F, + 0xCEC2CC0E, 0x0B33383B, 0x4A42480A, 0x87B3B437 }; + +/* +* SEED G Function +*/ +inline uint32_t SEED_G(uint32_t X) + { + return (SEED_S0[get_byte(3, X)] ^ SEED_S1[get_byte(2, X)] ^ + SEED_S2[get_byte(1, X)] ^ SEED_S3[get_byte(0, X)]); + } + +} + +/* +* SEED Encryption +*/ +void SEED::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t B0 = load_be(in, 0); + uint32_t B1 = load_be(in, 1); + uint32_t B2 = load_be(in, 2); + uint32_t B3 = load_be(in, 3); + + for(size_t j = 0; j != 16; j += 2) + { + uint32_t T0, T1; + + T0 = B2 ^ m_K[2*j]; + T1 = SEED_G(B2 ^ B3 ^ m_K[2*j+1]); + T0 = SEED_G(T1 + T0); + T1 = SEED_G(T1 + T0); + B1 ^= T1; + B0 ^= T0 + T1; + + T0 = B0 ^ m_K[2*j+2]; + T1 = SEED_G(B0 ^ B1 ^ m_K[2*j+3]); + T0 = SEED_G(T1 + T0); + T1 = SEED_G(T1 + T0); + B3 ^= T1; + B2 ^= T0 + T1; + } + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SEED Decryption +*/ +void SEED::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t B0 = load_be(in, 0); + uint32_t B1 = load_be(in, 1); + uint32_t B2 = load_be(in, 2); + uint32_t B3 = load_be(in, 3); + + for(size_t j = 0; j != 16; j += 2) + { + uint32_t T0, T1; + + T0 = B2 ^ m_K[30-2*j]; + T1 = SEED_G(B2 ^ B3 ^ m_K[31-2*j]); + T0 = SEED_G(T1 + T0); + T1 = SEED_G(T1 + T0); + B1 ^= T1; + B0 ^= T0 + T1; + + T0 = B0 ^ m_K[28-2*j]; + T1 = SEED_G(B0 ^ B1 ^ m_K[29-2*j]); + T0 = SEED_G(T1 + T0); + T1 = SEED_G(T1 + T0); + B3 ^= T1; + B2 ^= T0 + T1; + } + + store_be(out, B2, B3, B0, B1); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SEED Key Schedule +*/ +void SEED::key_schedule(const uint8_t key[], size_t) + { + const uint32_t RC[16] = { + 0x9E3779B9, 0x3C6EF373, 0x78DDE6E6, 0xF1BBCDCC, + 0xE3779B99, 0xC6EF3733, 0x8DDE6E67, 0x1BBCDCCF, + 0x3779B99E, 0x6EF3733C, 0xDDE6E678, 0xBBCDCCF1, + 0x779B99E3, 0xEF3733C6, 0xDE6E678D, 0xBCDCCF1B + }; + + secure_vector WK(4); + + for(size_t i = 0; i != 4; ++i) + WK[i] = load_be(key, i); + + m_K.resize(32); + + for(size_t i = 0; i != 16; i += 2) + { + m_K[2*i ] = SEED_G(WK[0] + WK[2] - RC[i]); + m_K[2*i+1] = SEED_G(WK[1] - WK[3] + RC[i]) ^ m_K[2*i]; + + uint32_t T = (WK[0] & 0xFF) << 24; + WK[0] = (WK[0] >> 8) | (get_byte(3, WK[1]) << 24); + WK[1] = (WK[1] >> 8) | T; + + m_K[2*i+2] = SEED_G(WK[0] + WK[2] - RC[i+1]); + m_K[2*i+3] = SEED_G(WK[1] - WK[3] + RC[i+1]) ^ m_K[2*i+2]; + + T = get_byte(0, WK[3]); + WK[3] = (WK[3] << 8) | get_byte(0, WK[2]); + WK[2] = (WK[2] << 8) | T; + } + } + +void SEED::clear() + { + zap(m_K); + } + +} diff --git a/comm/third_party/botan/src/lib/block/seed/seed.h b/comm/third_party/botan/src/lib/block/seed/seed.h new file mode 100644 index 0000000000..a616243135 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/seed/seed.h @@ -0,0 +1,37 @@ +/* +* SEED +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SEED_H_ +#define BOTAN_SEED_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(seed.h) + +namespace Botan { + +/** +* SEED, a Korean block cipher +*/ +class BOTAN_PUBLIC_API(2,0) SEED final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "SEED"; } + BlockCipher* clone() const override { return new SEED; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_K; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/serpent/info.txt b/comm/third_party/botan/src/lib/block/serpent/info.txt new file mode 100644 index 0000000000..89b860ce4f --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/info.txt @@ -0,0 +1,11 @@ + +SERPENT -> 20131128 + + + +serpent.h + + + +serpent_sbox.h + diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent.cpp b/comm/third_party/botan/src/lib/block/serpent/serpent.cpp new file mode 100644 index 0000000000..ff37a177c7 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent.cpp @@ -0,0 +1,299 @@ +/* +* Serpent +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_SERPENT_SIMD) || defined(BOTAN_HAS_SERPENT_AVX2) + #include +#endif + +namespace Botan { + +namespace { + +/* +* Serpent's Linear Transform +*/ +inline void transform(uint32_t& B0, uint32_t& B1, uint32_t& B2, uint32_t& B3) + { + B0 = rotl<13>(B0); B2 = rotl<3>(B2); + B1 ^= B0 ^ B2; B3 ^= B2 ^ (B0 << 3); + B1 = rotl<1>(B1); B3 = rotl<7>(B3); + B0 ^= B1 ^ B3; B2 ^= B3 ^ (B1 << 7); + B0 = rotl<5>(B0); B2 = rotl<22>(B2); + } + +/* +* Serpent's Inverse Linear Transform +*/ +inline void i_transform(uint32_t& B0, uint32_t& B1, uint32_t& B2, uint32_t& B3) + { + B2 = rotr<22>(B2); B0 = rotr<5>(B0); + B2 ^= B3 ^ (B1 << 7); B0 ^= B1 ^ B3; + B3 = rotr<7>(B3); B1 = rotr<1>(B1); + B3 ^= B2 ^ (B0 << 3); B1 ^= B0 ^ B2; + B2 = rotr<3>(B2); B0 = rotr<13>(B0); + } + +} + +/* +* XOR a key block with a data block +*/ +#define key_xor(round, B0, B1, B2, B3) \ + B0 ^= m_round_key[4*round ]; \ + B1 ^= m_round_key[4*round+1]; \ + B2 ^= m_round_key[4*round+2]; \ + B3 ^= m_round_key[4*round+3]; + +/* +* Serpent Encryption +*/ +void Serpent::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + +#if defined(BOTAN_HAS_SERPENT_AVX2) + if(CPUID::has_avx2()) + { + while(blocks >= 8) + { + avx2_encrypt_8(in, out); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + } +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_encrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + + BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) + { + uint32_t B0, B1, B2, B3; + load_le(in + 16*i, B0, B1, B2, B3); + + key_xor( 0,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 8,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(16,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(24,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + store_le(out + 16*i, B0, B1, B2, B3); + } + } + +/* +* Serpent Decryption +*/ +void Serpent::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + +#if defined(BOTAN_HAS_SERPENT_AVX2) + if(CPUID::has_avx2()) + { + while(blocks >= 8) + { + avx2_decrypt_8(in, out); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + } +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_decrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + + BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) + { + uint32_t B0, B1, B2, B3; + load_le(in + 16*i, B0, B1, B2, B3); + + key_xor(32,B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + store_le(out + 16*i, B0, B1, B2, B3); + } + } + +#undef key_xor +#undef transform +#undef i_transform + +/* +* Serpent Key Schedule +*/ +void Serpent::key_schedule(const uint8_t key[], size_t length) + { + const uint32_t PHI = 0x9E3779B9; + + secure_vector W(140); + for(size_t i = 0; i != length / 4; ++i) + W[i] = load_le(key, i); + + W[length / 4] |= uint32_t(1) << ((length%4)*8); + + for(size_t i = 8; i != 140; ++i) + { + uint32_t wi = W[i-8] ^ W[i-5] ^ W[i-3] ^ W[i-1] ^ PHI ^ uint32_t(i-8); + W[i] = rotl<11>(wi); + } + + SBoxE0(W[ 20],W[ 21],W[ 22],W[ 23]); + SBoxE0(W[ 52],W[ 53],W[ 54],W[ 55]); + SBoxE0(W[ 84],W[ 85],W[ 86],W[ 87]); + SBoxE0(W[116],W[117],W[118],W[119]); + + SBoxE1(W[ 16],W[ 17],W[ 18],W[ 19]); + SBoxE1(W[ 48],W[ 49],W[ 50],W[ 51]); + SBoxE1(W[ 80],W[ 81],W[ 82],W[ 83]); + SBoxE1(W[112],W[113],W[114],W[115]); + + SBoxE2(W[ 12],W[ 13],W[ 14],W[ 15]); + SBoxE2(W[ 44],W[ 45],W[ 46],W[ 47]); + SBoxE2(W[ 76],W[ 77],W[ 78],W[ 79]); + SBoxE2(W[108],W[109],W[110],W[111]); + + SBoxE3(W[ 8],W[ 9],W[ 10],W[ 11]); + SBoxE3(W[ 40],W[ 41],W[ 42],W[ 43]); + SBoxE3(W[ 72],W[ 73],W[ 74],W[ 75]); + SBoxE3(W[104],W[105],W[106],W[107]); + SBoxE3(W[136],W[137],W[138],W[139]); + + SBoxE4(W[ 36],W[ 37],W[ 38],W[ 39]); + SBoxE4(W[ 68],W[ 69],W[ 70],W[ 71]); + SBoxE4(W[100],W[101],W[102],W[103]); + SBoxE4(W[132],W[133],W[134],W[135]); + + SBoxE5(W[ 32],W[ 33],W[ 34],W[ 35]); + SBoxE5(W[ 64],W[ 65],W[ 66],W[ 67]); + SBoxE5(W[ 96],W[ 97],W[ 98],W[ 99]); + SBoxE5(W[128],W[129],W[130],W[131]); + + SBoxE6(W[ 28],W[ 29],W[ 30],W[ 31]); + SBoxE6(W[ 60],W[ 61],W[ 62],W[ 63]); + SBoxE6(W[ 92],W[ 93],W[ 94],W[ 95]); + SBoxE6(W[124],W[125],W[126],W[127]); + + SBoxE7(W[ 24],W[ 25],W[ 26],W[ 27]); + SBoxE7(W[ 56],W[ 57],W[ 58],W[ 59]); + SBoxE7(W[ 88],W[ 89],W[ 90],W[ 91]); + SBoxE7(W[120],W[121],W[122],W[123]); + + m_round_key.assign(W.begin() + 8, W.end()); + } + +void Serpent::clear() + { + zap(m_round_key); + } + +std::string Serpent::provider() const + { +#if defined(BOTAN_HAS_SERPENT_AVX2) + if(CPUID::has_avx2()) + { + return "avx2"; + } +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(CPUID::has_simd_32()) + { + return "simd"; + } +#endif + + return "base"; + } + +#undef key_xor + +} diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent.h b/comm/third_party/botan/src/lib/block/serpent/serpent.h new file mode 100644 index 0000000000..64eb8a8b04 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent.h @@ -0,0 +1,53 @@ +/* +* Serpent +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SERPENT_H_ +#define BOTAN_SERPENT_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(serpent.h) + +namespace Botan { + +/** +* Serpent is the most conservative of the AES finalists +* https://www.cl.cam.ac.uk/~rja14/serpent.html +*/ +class BOTAN_PUBLIC_API(2,0) Serpent final : public Block_Cipher_Fixed_Params<16, 16, 32, 8> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string provider() const override; + std::string name() const override { return "Serpent"; } + BlockCipher* clone() const override { return new Serpent; } + + size_t parallelism() const override { return 4; } + + private: + +#if defined(BOTAN_HAS_SERPENT_SIMD) + void simd_encrypt_4(const uint8_t in[64], uint8_t out[64]) const; + void simd_decrypt_4(const uint8_t in[64], uint8_t out[64]) const; +#endif + +#if defined(BOTAN_HAS_SERPENT_AVX2) + void avx2_encrypt_8(const uint8_t in[64], uint8_t out[64]) const; + void avx2_decrypt_8(const uint8_t in[64], uint8_t out[64]) const; +#endif + + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_round_key; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent_avx2/info.txt b/comm/third_party/botan/src/lib/block/serpent/serpent_avx2/info.txt new file mode 100644 index 0000000000..b0fbfb334e --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent_avx2/info.txt @@ -0,0 +1,17 @@ + +SERPENT_AVX2 -> 20180824 + + + +avx2 + + + +simd_avx2 + + +# We must exclude MSVC due to #2120 + +gcc +clang + diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent_avx2/serpent_avx2.cpp b/comm/third_party/botan/src/lib/block/serpent/serpent_avx2/serpent_avx2.cpp new file mode 100644 index 0000000000..0db332035d --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent_avx2/serpent_avx2.cpp @@ -0,0 +1,169 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + + +#define key_xor(round, B0, B1, B2, B3) \ + do { \ + B0 ^= SIMD_8x32::splat(m_round_key[4*round ]); \ + B1 ^= SIMD_8x32::splat(m_round_key[4*round+1]); \ + B2 ^= SIMD_8x32::splat(m_round_key[4*round+2]); \ + B3 ^= SIMD_8x32::splat(m_round_key[4*round+3]); \ + } while(0) + +/* +* Serpent's linear transformations +*/ +#define transform(B0, B1, B2, B3) \ + do { \ + B0 = B0.rotl<13>(); \ + B2 = B2.rotl<3>(); \ + B1 ^= B0 ^ B2; \ + B3 ^= B2 ^ B0.shl<3>(); \ + B1 = B1.rotl<1>(); \ + B3 = B3.rotl<7>(); \ + B0 ^= B1 ^ B3; \ + B2 ^= B3 ^ B1.shl<7>(); \ + B0 = B0.rotl<5>(); \ + B2 = B2.rotl<22>(); \ + } while(0) + +#define i_transform(B0, B1, B2, B3) \ + do { \ + B2 = B2.rotr<22>(); \ + B0 = B0.rotr<5>(); \ + B2 ^= B3 ^ B1.shl<7>(); \ + B0 ^= B1 ^ B3; \ + B3 = B3.rotr<7>(); \ + B1 = B1.rotr<1>(); \ + B3 ^= B2 ^ B0.shl<3>(); \ + B1 ^= B0 ^ B2; \ + B2 = B2.rotr<3>(); \ + B0 = B0.rotr<13>(); \ + } while(0) + +BOTAN_FUNC_ISA("avx2") +void Serpent::avx2_encrypt_8(const uint8_t in[128], uint8_t out[128]) const + { + SIMD_8x32::reset_registers(); + + SIMD_8x32 B0 = SIMD_8x32::load_le(in); + SIMD_8x32 B1 = SIMD_8x32::load_le(in + 32); + SIMD_8x32 B2 = SIMD_8x32::load_le(in + 64); + SIMD_8x32 B3 = SIMD_8x32::load_le(in + 96); + + SIMD_8x32::transpose(B0, B1, B2, B3); + + key_xor( 0,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 8,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(16,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(24,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + SIMD_8x32::transpose(B0, B1, B2, B3); + B0.store_le(out); + B1.store_le(out + 32); + B2.store_le(out + 64); + B3.store_le(out + 96); + + SIMD_8x32::zero_registers(); + } + +BOTAN_FUNC_ISA("avx2") +void Serpent::avx2_decrypt_8(const uint8_t in[128], uint8_t out[128]) const + { + SIMD_8x32::reset_registers(); + + SIMD_8x32 B0 = SIMD_8x32::load_le(in); + SIMD_8x32 B1 = SIMD_8x32::load_le(in + 32); + SIMD_8x32 B2 = SIMD_8x32::load_le(in + 64); + SIMD_8x32 B3 = SIMD_8x32::load_le(in + 96); + + SIMD_8x32::transpose(B0, B1, B2, B3); + + key_xor(32,B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + SIMD_8x32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 32); + B2.store_le(out + 64); + B3.store_le(out + 96); + + SIMD_8x32::zero_registers(); + } + +#undef key_xor +#undef transform +#undef i_transform + +} diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent_sbox.h b/comm/third_party/botan/src/lib/block/serpent/serpent_sbox.h new file mode 100644 index 0000000000..31471e7247 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent_sbox.h @@ -0,0 +1,446 @@ +/* +* Serpent SBox Expressions +* (C) 1999-2007,2013 Jack Lloyd +* +* The sbox expressions used here were discovered by Dag Arne Osvik and +* are described in his paper "Speeding Up Serpent". +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SERPENT_SBOX_H_ +#define BOTAN_SERPENT_SBOX_H_ + +#include + +template +BOTAN_FORCE_INLINE void SBoxE0(T& a, T& b, T& c, T& d) + { + d ^= a; + T t0 = b; + b &= d; + t0 ^= c; + b ^= a; + a |= d; + a ^= t0; + t0 ^= d; + d ^= c; + c |= b; + c ^= t0; + t0 = ~t0; + t0 |= b; + b ^= d; + b ^= t0; + d |= a; + b ^= d; + t0 ^= d; + d = a; + a = b; + b = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE1(T& a, T& b, T& c, T& d) + { + a = ~a; + c = ~c; + T t0 = a; + a &= b; + c ^= a; + a |= d; + d ^= c; + b ^= a; + a ^= t0; + t0 |= b; + b ^= d; + c |= a; + c &= t0; + a ^= b; + b &= c; + b ^= a; + a &= c; + t0 ^= a; + a = c; + c = d; + d = b; + b = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE2(T& a, T& b, T& c, T& d) + { + T t0 = a; + a &= c; + a ^= d; + c ^= b; + c ^= a; + d |= t0; + d ^= b; + t0 ^= c; + b = d; + d |= t0; + d ^= a; + a &= b; + t0 ^= a; + b ^= d; + b ^= t0; + a = c; + c = b; + b = d; + d = ~t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE3(T& a, T& b, T& c, T& d) + { + T t0 = a; + a |= d; + d ^= b; + b &= t0; + t0 ^= c; + c ^= d; + d &= a; + t0 |= b; + d ^= t0; + a ^= b; + t0 &= a; + b ^= d; + t0 ^= c; + b |= a; + b ^= c; + a ^= d; + c = b; + b |= d; + a ^= b; + b = c; + c = d; + d = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE4(T& a, T& b, T& c, T& d) + { + b ^= d; + d = ~d; + c ^= d; + d ^= a; + T t0 = b; + b &= d; + b ^= c; + t0 ^= d; + a ^= t0; + c &= t0; + c ^= a; + a &= b; + d ^= a; + t0 |= b; + t0 ^= a; + a |= d; + a ^= c; + c &= d; + a = ~a; + t0 ^= c; + c = a; + a = b; + b = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE5(T& a, T& b, T& c, T& d) + { + a ^= b; + b ^= d; + d = ~d; + T t0 = b; + b &= a; + c ^= d; + b ^= c; + c |= t0; + t0 ^= d; + d &= b; + d ^= a; + t0 ^= b; + t0 ^= c; + c ^= a; + a &= d; + c = ~c; + a ^= t0; + t0 |= d; + t0 ^= c; + c = a; + a = b; + b = d; + d = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE6(T& a, T& b, T& c, T& d) + { + c = ~c; + T t0 = d; + d &= a; + a ^= t0; + d ^= c; + c |= t0; + b ^= d; + c ^= a; + a |= b; + c ^= b; + t0 ^= a; + a |= d; + a ^= c; + t0 ^= d; + t0 ^= a; + d = ~d; + c &= t0; + d ^= c; + c = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxE7(T& a, T& b, T& c, T& d) + { + T t0 = b; + b |= c; + b ^= d; + t0 ^= c; + c ^= b; + d |= t0; + d &= a; + t0 ^= c; + d ^= b; + b |= t0; + b ^= a; + a |= t0; + a ^= c; + b ^= t0; + c ^= b; + b &= a; + b ^= t0; + c = ~c; + c |= a; + t0 ^= c; + c = b; + b = d; + d = a; + a = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD0(T& a, T& b, T& c, T& d) + { + c = ~c; + T t0 = b; + b |= a; + t0 = ~t0; + b ^= c; + c |= t0; + b ^= d; + a ^= t0; + c ^= a; + a &= d; + t0 ^= a; + a |= b; + a ^= c; + d ^= t0; + c ^= b; + d ^= a; + d ^= b; + c &= d; + t0 ^= c; + c = b; + b = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD1(T& a, T& b, T& c, T& d) + { + T t0 = b; + b ^= d; + d &= b; + t0 ^= c; + d ^= a; + a |= b; + c ^= d; + a ^= t0; + a |= c; + b ^= d; + a ^= b; + b |= d; + b ^= a; + t0 = ~t0; + t0 ^= b; + b |= a; + b ^= a; + b |= t0; + d ^= b; + b = a; + a = t0; + t0 = c; + c = d; + d = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD2(T& a, T& b, T& c, T& d) + { + c ^= d; + d ^= a; + T t0 = d; + d &= c; + d ^= b; + b |= c; + b ^= t0; + t0 &= d; + c ^= d; + t0 &= a; + t0 ^= c; + c &= b; + c |= a; + d = ~d; + c ^= d; + a ^= d; + a &= b; + d ^= t0; + d ^= a; + a = b; + b = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD3(T& a, T& b, T& c, T& d) + { + T t0 = c; + c ^= b; + a ^= c; + t0 &= c; + t0 ^= a; + a &= b; + b ^= d; + d |= t0; + c ^= d; + a ^= d; + b ^= t0; + d &= c; + d ^= b; + b ^= a; + b |= c; + a ^= d; + b ^= t0; + a ^= b; + t0 = a; + a = c; + c = d; + d = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD4(T& a, T& b, T& c, T& d) + { + T t0 = c; + c &= d; + c ^= b; + b |= d; + b &= a; + t0 ^= c; + t0 ^= b; + b &= c; + a = ~a; + d ^= t0; + b ^= d; + d &= a; + d ^= c; + a ^= b; + c &= a; + d ^= a; + c ^= t0; + c |= d; + d ^= a; + c ^= b; + b = d; + d = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD5(T& a, T& b, T& c, T& d) + { + b = ~b; + T t0 = d; + c ^= b; + d |= a; + d ^= c; + c |= b; + c &= a; + t0 ^= d; + c ^= t0; + t0 |= a; + t0 ^= b; + b &= c; + b ^= d; + t0 ^= c; + d &= t0; + t0 ^= b; + d ^= t0; + t0 = ~t0; + d ^= a; + a = b; + b = t0; + t0 = d; + d = c; + c = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD6(T& a, T& b, T& c, T& d) + { + a ^= c; + T t0 = c; + c &= a; + t0 ^= d; + c = ~c; + d ^= b; + c ^= d; + t0 |= a; + a ^= c; + d ^= t0; + t0 ^= b; + b &= d; + b ^= a; + a ^= d; + a |= c; + d ^= b; + t0 ^= a; + a = b; + b = c; + c = t0; + } + +template +BOTAN_FORCE_INLINE void SBoxD7(T& a, T& b, T& c, T& d) + { + T t0 = c; + c ^= a; + a &= d; + t0 |= d; + c = ~c; + d ^= b; + b |= a; + a ^= c; + c &= t0; + d &= t0; + b ^= c; + c ^= a; + a |= c; + t0 ^= b; + a ^= d; + d ^= t0; + t0 |= a; + d ^= c; + t0 ^= c; + c = b; + b = a; + a = d; + d = t0; + } + +#endif diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent_simd/info.txt b/comm/third_party/botan/src/lib/block/serpent/serpent_simd/info.txt new file mode 100644 index 0000000000..f7dadf33fc --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent_simd/info.txt @@ -0,0 +1,7 @@ + +SERPENT_SIMD -> 20160903 + + + +simd + diff --git a/comm/third_party/botan/src/lib/block/serpent/serpent_simd/serpent_simd.cpp b/comm/third_party/botan/src/lib/block/serpent/serpent_simd/serpent_simd.cpp new file mode 100644 index 0000000000..8ac783ba5c --- /dev/null +++ b/comm/third_party/botan/src/lib/block/serpent/serpent_simd/serpent_simd.cpp @@ -0,0 +1,169 @@ +/* +* Serpent (SIMD) +* (C) 2009,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +#define key_xor(round, B0, B1, B2, B3) \ + do { \ + B0 ^= SIMD_4x32::splat(m_round_key[4*round ]); \ + B1 ^= SIMD_4x32::splat(m_round_key[4*round+1]); \ + B2 ^= SIMD_4x32::splat(m_round_key[4*round+2]); \ + B3 ^= SIMD_4x32::splat(m_round_key[4*round+3]); \ + } while(0) + +/* +* Serpent's linear transformations +*/ +#define transform(B0, B1, B2, B3) \ + do { \ + B0 = B0.rotl<13>(); \ + B2 = B2.rotl<3>(); \ + B1 ^= B0 ^ B2; \ + B3 ^= B2 ^ B0.shl<3>(); \ + B1 = B1.rotl<1>(); \ + B3 = B3.rotl<7>(); \ + B0 ^= B1 ^ B3; \ + B2 ^= B3 ^ B1.shl<7>(); \ + B0 = B0.rotl<5>(); \ + B2 = B2.rotl<22>(); \ + } while(0) + +#define i_transform(B0, B1, B2, B3) \ + do { \ + B2 = B2.rotr<22>(); \ + B0 = B0.rotr<5>(); \ + B2 ^= B3 ^ B1.shl<7>(); \ + B0 ^= B1 ^ B3; \ + B3 = B3.rotr<7>(); \ + B1 = B1.rotr<1>(); \ + B3 ^= B2 ^ B0.shl<3>(); \ + B1 ^= B0 ^ B2; \ + B2 = B2.rotr<3>(); \ + B0 = B0.rotr<13>(); \ + } while(0) + +/* +* SIMD Serpent Encryption of 4 blocks in parallel +*/ +void Serpent::simd_encrypt_4(const uint8_t in[64], uint8_t out[64]) const + { + SIMD_4x32 B0 = SIMD_4x32::load_le(in); + SIMD_4x32 B1 = SIMD_4x32::load_le(in + 16); + SIMD_4x32 B2 = SIMD_4x32::load_le(in + 32); + SIMD_4x32 B3 = SIMD_4x32::load_le(in + 48); + + SIMD_4x32::transpose(B0, B1, B2, B3); + + key_xor( 0,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 1,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 2,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 3,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 4,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 5,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 6,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 7,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor( 8,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor( 9,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(10,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(11,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(12,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(13,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(14,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(15,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor(16,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(17,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(18,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(19,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(20,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(21,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(22,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(23,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3); + + key_xor(24,B0,B1,B2,B3); SBoxE0(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(25,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(26,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(27,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(28,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(29,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(30,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3); + key_xor(31,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3); + + SIMD_4x32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 16); + B2.store_le(out + 32); + B3.store_le(out + 48); + } + +/* +* SIMD Serpent Decryption of 4 blocks in parallel +*/ +void Serpent::simd_decrypt_4(const uint8_t in[64], uint8_t out[64]) const + { + SIMD_4x32 B0 = SIMD_4x32::load_le(in); + SIMD_4x32 B1 = SIMD_4x32::load_le(in + 16); + SIMD_4x32 B2 = SIMD_4x32::load_le(in + 32); + SIMD_4x32 B3 = SIMD_4x32::load_le(in + 48); + + SIMD_4x32::transpose(B0, B1, B2, B3); + + key_xor(32,B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3); + + i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3); + i_transform(B0,B1,B2,B3); SBoxD0(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3); + + SIMD_4x32::transpose(B0, B1, B2, B3); + + B0.store_le(out); + B1.store_le(out + 16); + B2.store_le(out + 32); + B3.store_le(out + 48); + } + +#undef key_xor +#undef transform +#undef i_transform + +} diff --git a/comm/third_party/botan/src/lib/block/shacal2/info.txt b/comm/third_party/botan/src/lib/block/shacal2/info.txt new file mode 100644 index 0000000000..62e00503f9 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/info.txt @@ -0,0 +1,5 @@ + +SHACAL2 -> 20170813 + + + diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2.cpp b/comm/third_party/botan/src/lib/block/shacal2/shacal2.cpp new file mode 100644 index 0000000000..b0c57f2359 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2.cpp @@ -0,0 +1,280 @@ +/* +* SHACAL-2 +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +inline void SHACAL2_Fwd(uint32_t A, uint32_t B, uint32_t C, uint32_t& D, + uint32_t E, uint32_t F, uint32_t G, uint32_t& H, + uint32_t RK) + { + const uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); + const uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); + + H += E_rho + ((E & F) ^ (~E & G)) + RK; + D += H; + H += A_rho + ((A & B) | ((A | B) & C)); + } + +inline void SHACAL2_Rev(uint32_t A, uint32_t B, uint32_t C, uint32_t& D, + uint32_t E, uint32_t F, uint32_t G, uint32_t& H, + uint32_t RK) + { + const uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); + const uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); + + H -= A_rho + ((A & B) | ((A | B) & C)); + D -= H; + H -= E_rho + ((E & F) ^ (~E & G)) + RK; + } + +} + +/* +* SHACAL2 Encryption +*/ +void SHACAL2::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + +#if defined(BOTAN_HAS_SHACAL2_X86) + if(CPUID::has_intel_sha()) + { + return x86_encrypt_blocks(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_AVX2) + if(CPUID::has_avx2()) + { + while(blocks >= 8) + { + avx2_encrypt_8(in, out); + in += 8*BLOCK_SIZE; + out += 8*BLOCK_SIZE; + blocks -= 8; + } + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_encrypt_4(in, out); + in += 4*BLOCK_SIZE; + out += 4*BLOCK_SIZE; + blocks -= 4; + } + } +#endif + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t A = load_be(in, 0); + uint32_t B = load_be(in, 1); + uint32_t C = load_be(in, 2); + uint32_t D = load_be(in, 3); + uint32_t E = load_be(in, 4); + uint32_t F = load_be(in, 5); + uint32_t G = load_be(in, 6); + uint32_t H = load_be(in, 7); + + for(size_t r = 0; r != 64; r += 8) + { + SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r+0]); + SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r+1]); + SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r+2]); + SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r+3]); + SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r+4]); + SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r+5]); + SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r+6]); + SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r+7]); + } + + store_be(out, A, B, C, D, E, F, G, H); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SHACAL2 Encryption +*/ +void SHACAL2::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + +#if defined(BOTAN_HAS_SHACAL2_AVX2) + if(CPUID::has_avx2()) + { + while(blocks >= 8) + { + avx2_decrypt_8(in, out); + in += 8*BLOCK_SIZE; + out += 8*BLOCK_SIZE; + blocks -= 8; + } + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_decrypt_4(in, out); + in += 4*BLOCK_SIZE; + out += 4*BLOCK_SIZE; + blocks -= 4; + } + } +#endif + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t A = load_be(in, 0); + uint32_t B = load_be(in, 1); + uint32_t C = load_be(in, 2); + uint32_t D = load_be(in, 3); + uint32_t E = load_be(in, 4); + uint32_t F = load_be(in, 5); + uint32_t G = load_be(in, 6); + uint32_t H = load_be(in, 7); + + for(size_t r = 0; r != 64; r += 8) + { + SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63-r]); + SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62-r]); + SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61-r]); + SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60-r]); + SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59-r]); + SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58-r]); + SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57-r]); + SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56-r]); + } + + store_be(out, A, B, C, D, E, F, G, H); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SHACAL2 Key Schedule +*/ +void SHACAL2::key_schedule(const uint8_t key[], size_t len) + { + const uint32_t RC[64] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + }; + + if(m_RK.empty()) + m_RK.resize(64); + else + clear_mem(m_RK.data(), m_RK.size()); + + load_be(m_RK.data(), key, len/4); + + for(size_t i = 16; i != 64; ++i) + { + const uint32_t sigma0_15 = rotr< 7>(m_RK[i-15]) ^ rotr<18>(m_RK[i-15]) ^ (m_RK[i-15] >> 3); + const uint32_t sigma1_2 = rotr<17>(m_RK[i- 2]) ^ rotr<19>(m_RK[i- 2]) ^ (m_RK[i- 2] >> 10); + m_RK[i] = m_RK[i-16] + sigma0_15 + m_RK[i-7] + sigma1_2; + } + + for(size_t i = 0; i != 64; ++i) + { + m_RK[i] += RC[i]; + } + } + +size_t SHACAL2::parallelism() const + { +#if defined(BOTAN_HAS_SHACAL2_X86) + if(CPUID::has_intel_sha()) + { + return 4; + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_AVX2) + if(CPUID::has_avx2()) + { + return 8; + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_SIMD) + if(CPUID::has_simd_32()) + { + return 4; + } +#endif + + return 1; + } + +std::string SHACAL2::provider() const + { +#if defined(BOTAN_HAS_SHACAL2_X86) + if(CPUID::has_intel_sha()) + { + return "intel_sha"; + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_AVX2) + if(CPUID::has_avx2()) + { + return "avx2"; + } +#endif + +#if defined(BOTAN_HAS_SHACAL2_SIMD) + if(CPUID::has_simd_32()) + { + return "simd"; + } +#endif + + return "base"; + } + +/* +* Clear memory of sensitive data +*/ +void SHACAL2::clear() + { + zap(m_RK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2.h b/comm/third_party/botan/src/lib/block/shacal2/shacal2.h new file mode 100644 index 0000000000..b752a03390 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2.h @@ -0,0 +1,54 @@ +/* +* SHACAL-2 +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHACAL2_H_ +#define BOTAN_SHACAL2_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(shacal2.h) + +namespace Botan { + +/** +* SHACAL2 +*/ +class BOTAN_PUBLIC_API(2,3) SHACAL2 final : public Block_Cipher_Fixed_Params<32, 16, 64, 4> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + std::string provider() const override; + void clear() override; + std::string name() const override { return "SHACAL2"; } + BlockCipher* clone() const override { return new SHACAL2; } + size_t parallelism() const override; + + private: + void key_schedule(const uint8_t[], size_t) override; + +#if defined(BOTAN_HAS_SHACAL2_SIMD) + void simd_encrypt_4(const uint8_t in[], uint8_t out[]) const; + void simd_decrypt_4(const uint8_t in[], uint8_t out[]) const; +#endif + +#if defined(BOTAN_HAS_SHACAL2_AVX2) + void avx2_encrypt_8(const uint8_t in[], uint8_t out[]) const; + void avx2_decrypt_8(const uint8_t in[], uint8_t out[]) const; +#endif + +#if defined(BOTAN_HAS_SHACAL2_X86) + void x86_encrypt_blocks(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + secure_vector m_RK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/info.txt b/comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/info.txt new file mode 100644 index 0000000000..a0b5ce1a97 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/info.txt @@ -0,0 +1,11 @@ + +SHACAL2_AVX2 -> 20180826 + + + +avx2 + + + +simd_avx2 + diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/shacal2_avx2.cpp b/comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/shacal2_avx2.cpp new file mode 100644 index 0000000000..a465a38286 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2_avx2/shacal2_avx2.cpp @@ -0,0 +1,122 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +void BOTAN_FORCE_INLINE BOTAN_FUNC_ISA("avx2") + SHACAL2_Fwd(const SIMD_8x32& A, const SIMD_8x32& B, const SIMD_8x32& C, SIMD_8x32& D, + const SIMD_8x32& E, const SIMD_8x32& F, const SIMD_8x32& G, SIMD_8x32& H, + uint32_t RK) + { + H += E.rho<6,11,25>() + ((E & F) ^ (~E & G)) + SIMD_8x32::splat(RK); + D += H; + H += A.rho<2,13,22>() + ((A & B) | ((A | B) & C)); + } + +void BOTAN_FORCE_INLINE BOTAN_FUNC_ISA("avx2") + SHACAL2_Rev(const SIMD_8x32& A, const SIMD_8x32& B, const SIMD_8x32& C, SIMD_8x32& D, + const SIMD_8x32& E, const SIMD_8x32& F, const SIMD_8x32& G, SIMD_8x32& H, + uint32_t RK) + { + H -= A.rho<2,13,22>() + ((A & B) | ((A | B) & C)); + D -= H; + H -= E.rho<6,11,25>() + ((E & F) ^ (~E & G)) + SIMD_8x32::splat(RK); + } + +} + +void BOTAN_FUNC_ISA("avx2") SHACAL2::avx2_encrypt_8(const uint8_t in[], uint8_t out[]) const + { + SIMD_8x32::reset_registers(); + + SIMD_8x32 A = SIMD_8x32::load_be(in); + SIMD_8x32 B = SIMD_8x32::load_be(in+32); + SIMD_8x32 C = SIMD_8x32::load_be(in+64); + SIMD_8x32 D = SIMD_8x32::load_be(in+96); + + SIMD_8x32 E = SIMD_8x32::load_be(in+128); + SIMD_8x32 F = SIMD_8x32::load_be(in+160); + SIMD_8x32 G = SIMD_8x32::load_be(in+192); + SIMD_8x32 H = SIMD_8x32::load_be(in+224); + + SIMD_8x32::transpose(A, B, C, D, E, F, G, H); + + for(size_t r = 0; r != 64; r += 8) + { + SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r+0]); + SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r+1]); + SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r+2]); + SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r+3]); + SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r+4]); + SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r+5]); + SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r+6]); + SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r+7]); + } + + SIMD_8x32::transpose(A, B, C, D, E, F, G, H); + + A.store_be(out); + B.store_be(out+32); + C.store_be(out+64); + D.store_be(out+96); + + E.store_be(out+128); + F.store_be(out+160); + G.store_be(out+192); + H.store_be(out+224); + + SIMD_8x32::zero_registers(); + } + +BOTAN_FUNC_ISA("avx2") void SHACAL2::avx2_decrypt_8(const uint8_t in[], uint8_t out[]) const + { + SIMD_8x32::reset_registers(); + + SIMD_8x32 A = SIMD_8x32::load_be(in); + SIMD_8x32 B = SIMD_8x32::load_be(in+32); + SIMD_8x32 C = SIMD_8x32::load_be(in+64); + SIMD_8x32 D = SIMD_8x32::load_be(in+96); + + SIMD_8x32 E = SIMD_8x32::load_be(in+128); + SIMD_8x32 F = SIMD_8x32::load_be(in+160); + SIMD_8x32 G = SIMD_8x32::load_be(in+192); + SIMD_8x32 H = SIMD_8x32::load_be(in+224); + + SIMD_8x32::transpose(A, B, C, D, E, F, G, H); + + for(size_t r = 0; r != 64; r += 8) + { + SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63-r]); + SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62-r]); + SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61-r]); + SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60-r]); + SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59-r]); + SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58-r]); + SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57-r]); + SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56-r]); + } + + SIMD_8x32::transpose(A, B, C, D, E, F, G, H); + + A.store_be(out); + B.store_be(out+32); + C.store_be(out+64); + D.store_be(out+96); + + E.store_be(out+128); + F.store_be(out+160); + G.store_be(out+192); + H.store_be(out+224); + + SIMD_8x32::zero_registers(); + } + +} diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/info.txt b/comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/info.txt new file mode 100644 index 0000000000..8d715c668c --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/info.txt @@ -0,0 +1,8 @@ + +SHACAL2_SIMD -> 20170813 + + + +shacal2 +simd + diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/shacal2_simd.cpp b/comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/shacal2_simd.cpp new file mode 100644 index 0000000000..6d15faf1a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2_simd/shacal2_simd.cpp @@ -0,0 +1,119 @@ +/* +* SHACAL-2 using SIMD +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +inline +void SHACAL2_Fwd(const SIMD_4x32& A, const SIMD_4x32& B, const SIMD_4x32& C, SIMD_4x32& D, + const SIMD_4x32& E, const SIMD_4x32& F, const SIMD_4x32& G, SIMD_4x32& H, + uint32_t RK) + { + H += E.rho<6,11,25>() + ((E & F) ^ (~E & G)) + SIMD_4x32::splat(RK); + D += H; + H += A.rho<2,13,22>() + ((A & B) | ((A | B) & C)); + } + +inline +void SHACAL2_Rev(const SIMD_4x32& A, const SIMD_4x32& B, const SIMD_4x32& C, SIMD_4x32& D, + const SIMD_4x32& E, const SIMD_4x32& F, const SIMD_4x32& G, SIMD_4x32& H, + uint32_t RK) + { + H -= A.rho<2,13,22>() + ((A & B) | ((A | B) & C)); + D -= H; + H -= E.rho<6,11,25>() + ((E & F) ^ (~E & G)) + SIMD_4x32::splat(RK); + } + +} + +void SHACAL2::simd_encrypt_4(const uint8_t in[], uint8_t out[]) const + { + SIMD_4x32 A = SIMD_4x32::load_be(in); + SIMD_4x32 E = SIMD_4x32::load_be(in+16); + SIMD_4x32 B = SIMD_4x32::load_be(in+32); + SIMD_4x32 F = SIMD_4x32::load_be(in+48); + + SIMD_4x32 C = SIMD_4x32::load_be(in+64); + SIMD_4x32 G = SIMD_4x32::load_be(in+80); + SIMD_4x32 D = SIMD_4x32::load_be(in+96); + SIMD_4x32 H = SIMD_4x32::load_be(in+112); + + SIMD_4x32::transpose(A, B, C, D); + SIMD_4x32::transpose(E, F, G, H); + + for(size_t r = 0; r != 64; r += 8) + { + SHACAL2_Fwd(A, B, C, D, E, F, G, H, m_RK[r+0]); + SHACAL2_Fwd(H, A, B, C, D, E, F, G, m_RK[r+1]); + SHACAL2_Fwd(G, H, A, B, C, D, E, F, m_RK[r+2]); + SHACAL2_Fwd(F, G, H, A, B, C, D, E, m_RK[r+3]); + SHACAL2_Fwd(E, F, G, H, A, B, C, D, m_RK[r+4]); + SHACAL2_Fwd(D, E, F, G, H, A, B, C, m_RK[r+5]); + SHACAL2_Fwd(C, D, E, F, G, H, A, B, m_RK[r+6]); + SHACAL2_Fwd(B, C, D, E, F, G, H, A, m_RK[r+7]); + } + + SIMD_4x32::transpose(A, B, C, D); + SIMD_4x32::transpose(E, F, G, H); + + A.store_be(out); + E.store_be(out+16); + B.store_be(out+32); + F.store_be(out+48); + + C.store_be(out+64); + G.store_be(out+80); + D.store_be(out+96); + H.store_be(out+112); + } + +void SHACAL2::simd_decrypt_4(const uint8_t in[], uint8_t out[]) const + { + SIMD_4x32 A = SIMD_4x32::load_be(in); + SIMD_4x32 E = SIMD_4x32::load_be(in+16); + SIMD_4x32 B = SIMD_4x32::load_be(in+32); + SIMD_4x32 F = SIMD_4x32::load_be(in+48); + + SIMD_4x32 C = SIMD_4x32::load_be(in+64); + SIMD_4x32 G = SIMD_4x32::load_be(in+80); + SIMD_4x32 D = SIMD_4x32::load_be(in+96); + SIMD_4x32 H = SIMD_4x32::load_be(in+112); + + SIMD_4x32::transpose(A, B, C, D); + SIMD_4x32::transpose(E, F, G, H); + + for(size_t r = 0; r != 64; r += 8) + { + SHACAL2_Rev(B, C, D, E, F, G, H, A, m_RK[63-r]); + SHACAL2_Rev(C, D, E, F, G, H, A, B, m_RK[62-r]); + SHACAL2_Rev(D, E, F, G, H, A, B, C, m_RK[61-r]); + SHACAL2_Rev(E, F, G, H, A, B, C, D, m_RK[60-r]); + SHACAL2_Rev(F, G, H, A, B, C, D, E, m_RK[59-r]); + SHACAL2_Rev(G, H, A, B, C, D, E, F, m_RK[58-r]); + SHACAL2_Rev(H, A, B, C, D, E, F, G, m_RK[57-r]); + SHACAL2_Rev(A, B, C, D, E, F, G, H, m_RK[56-r]); + } + + SIMD_4x32::transpose(A, B, C, D); + SIMD_4x32::transpose(E, F, G, H); + + A.store_be(out); + E.store_be(out+16); + B.store_be(out+32); + F.store_be(out+48); + + C.store_be(out+64); + G.store_be(out+80); + D.store_be(out+96); + H.store_be(out+112); + } + +} diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/info.txt b/comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/info.txt new file mode 100644 index 0000000000..2988330482 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/info.txt @@ -0,0 +1,20 @@ + +SHACAL2_X86 -> 20170814 + + + +shacal2 + + + +sha +sse2 +ssse3 + + + +gcc:5.0 +clang:3.9 +msvc:19.0 # MSVS 2015 + + diff --git a/comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/shacal2_x86.cpp b/comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/shacal2_x86.cpp new file mode 100644 index 0000000000..1611d6c9b6 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/shacal2/shacal2_x86/shacal2_x86.cpp @@ -0,0 +1,118 @@ +/* +* SHACAL-2 using x86 SHA extensions +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +Only encryption is supported since the inverse round function would +require a different instruction +*/ + +BOTAN_FUNC_ISA("sha,ssse3") +void SHACAL2::x86_encrypt_blocks(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i MASK1 = _mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); + const __m128i MASK2 = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); + + const __m128i* RK_mm = reinterpret_cast(m_RK.data()); + const __m128i* in_mm = reinterpret_cast(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + while(blocks >= 2) + { + __m128i B0_0 = _mm_loadu_si128(in_mm); + __m128i B0_1 = _mm_loadu_si128(in_mm+1); + __m128i B1_0 = _mm_loadu_si128(in_mm+2); + __m128i B1_1 = _mm_loadu_si128(in_mm+3); + + __m128i TMP = _mm_shuffle_epi8(_mm_unpacklo_epi64(B0_0, B0_1), MASK2); + B0_1 = _mm_shuffle_epi8(_mm_unpackhi_epi64(B0_0, B0_1), MASK2); + B0_0 = TMP; + + TMP = _mm_shuffle_epi8(_mm_unpacklo_epi64(B1_0, B1_1), MASK2); + B1_1 = _mm_shuffle_epi8(_mm_unpackhi_epi64(B1_0, B1_1), MASK2); + B1_0 = TMP; + + for(size_t i = 0; i != 8; ++i) + { + const __m128i RK0 = _mm_loadu_si128(RK_mm + 2*i); + const __m128i RK2 = _mm_loadu_si128(RK_mm + 2*i+1); + const __m128i RK1 = _mm_srli_si128(RK0, 8); + const __m128i RK3 = _mm_srli_si128(RK2, 8); + + B0_1 = _mm_sha256rnds2_epu32(B0_1, B0_0, RK0); + B1_1 = _mm_sha256rnds2_epu32(B1_1, B1_0, RK0); + + B0_0 = _mm_sha256rnds2_epu32(B0_0, B0_1, RK1); + B1_0 = _mm_sha256rnds2_epu32(B1_0, B1_1, RK1); + + B0_1 = _mm_sha256rnds2_epu32(B0_1, B0_0, RK2); + B1_1 = _mm_sha256rnds2_epu32(B1_1, B1_0, RK2); + + B0_0 = _mm_sha256rnds2_epu32(B0_0, B0_1, RK3); + B1_0 = _mm_sha256rnds2_epu32(B1_0, B1_1, RK3); + } + + TMP = _mm_shuffle_epi8(_mm_unpackhi_epi64(B0_0, B0_1), MASK1); + B0_1 = _mm_shuffle_epi8(_mm_unpacklo_epi64(B0_0, B0_1), MASK1); + B0_0 = TMP; + + TMP = _mm_shuffle_epi8(_mm_unpackhi_epi64(B1_0, B1_1), MASK1); + B1_1 = _mm_shuffle_epi8(_mm_unpacklo_epi64(B1_0, B1_1), MASK1); + B1_0 = TMP; + + // Save state + _mm_storeu_si128(out_mm + 0, B0_0); + _mm_storeu_si128(out_mm + 1, B0_1); + _mm_storeu_si128(out_mm + 2, B1_0); + _mm_storeu_si128(out_mm + 3, B1_1); + + blocks -= 2; + in_mm += 4; + out_mm += 4; + } + + while(blocks) + { + __m128i B0 = _mm_loadu_si128(in_mm); + __m128i B1 = _mm_loadu_si128(in_mm+1); + + __m128i TMP = _mm_shuffle_epi8(_mm_unpacklo_epi64(B0, B1), MASK2); + B1 = _mm_shuffle_epi8(_mm_unpackhi_epi64(B0, B1), MASK2); + B0 = TMP; + + for(size_t i = 0; i != 8; ++i) + { + const __m128i RK0 = _mm_loadu_si128(RK_mm + 2*i); + const __m128i RK2 = _mm_loadu_si128(RK_mm + 2*i+1); + const __m128i RK1 = _mm_srli_si128(RK0, 8); + const __m128i RK3 = _mm_srli_si128(RK2, 8); + + B1 = _mm_sha256rnds2_epu32(B1, B0, RK0); + B0 = _mm_sha256rnds2_epu32(B0, B1, RK1); + B1 = _mm_sha256rnds2_epu32(B1, B0, RK2); + B0 = _mm_sha256rnds2_epu32(B0, B1, RK3); + } + + TMP = _mm_shuffle_epi8(_mm_unpackhi_epi64(B0, B1), MASK1); + B1 = _mm_shuffle_epi8(_mm_unpacklo_epi64(B0, B1), MASK1); + B0 = TMP; + + // Save state + _mm_storeu_si128(out_mm, B0); + _mm_storeu_si128(out_mm + 1, B1); + + blocks--; + in_mm += 2; + out_mm += 2; + } + } + +} diff --git a/comm/third_party/botan/src/lib/block/sm4/info.txt b/comm/third_party/botan/src/lib/block/sm4/info.txt new file mode 100644 index 0000000000..32561f6d6f --- /dev/null +++ b/comm/third_party/botan/src/lib/block/sm4/info.txt @@ -0,0 +1,3 @@ + +SM4 -> 20170716 + diff --git a/comm/third_party/botan/src/lib/block/sm4/sm4.cpp b/comm/third_party/botan/src/lib/block/sm4/sm4.cpp new file mode 100644 index 0000000000..8198330e6e --- /dev/null +++ b/comm/third_party/botan/src/lib/block/sm4/sm4.cpp @@ -0,0 +1,341 @@ +/* +* SM4 +* (C) 2017 Ribose Inc +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +alignas(64) +const uint8_t SM4_SBOX[256] = { +0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, +0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, +0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, +0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, +0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, +0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, +0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, +0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, +0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, +0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, +0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, +0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, +0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, +0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, +0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, +0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48 +}; + +/* +* SM4_SBOX_T[j] == L(SM4_SBOX[j]). +*/ +alignas(64) +const uint32_t SM4_SBOX_T[256] = { + 0x8ED55B5B, 0xD0924242, 0x4DEAA7A7, 0x06FDFBFB, 0xFCCF3333, 0x65E28787, + 0xC93DF4F4, 0x6BB5DEDE, 0x4E165858, 0x6EB4DADA, 0x44145050, 0xCAC10B0B, + 0x8828A0A0, 0x17F8EFEF, 0x9C2CB0B0, 0x11051414, 0x872BACAC, 0xFB669D9D, + 0xF2986A6A, 0xAE77D9D9, 0x822AA8A8, 0x46BCFAFA, 0x14041010, 0xCFC00F0F, + 0x02A8AAAA, 0x54451111, 0x5F134C4C, 0xBE269898, 0x6D482525, 0x9E841A1A, + 0x1E061818, 0xFD9B6666, 0xEC9E7272, 0x4A430909, 0x10514141, 0x24F7D3D3, + 0xD5934646, 0x53ECBFBF, 0xF89A6262, 0x927BE9E9, 0xFF33CCCC, 0x04555151, + 0x270B2C2C, 0x4F420D0D, 0x59EEB7B7, 0xF3CC3F3F, 0x1CAEB2B2, 0xEA638989, + 0x74E79393, 0x7FB1CECE, 0x6C1C7070, 0x0DABA6A6, 0xEDCA2727, 0x28082020, + 0x48EBA3A3, 0xC1975656, 0x80820202, 0xA3DC7F7F, 0xC4965252, 0x12F9EBEB, + 0xA174D5D5, 0xB38D3E3E, 0xC33FFCFC, 0x3EA49A9A, 0x5B461D1D, 0x1B071C1C, + 0x3BA59E9E, 0x0CFFF3F3, 0x3FF0CFCF, 0xBF72CDCD, 0x4B175C5C, 0x52B8EAEA, + 0x8F810E0E, 0x3D586565, 0xCC3CF0F0, 0x7D196464, 0x7EE59B9B, 0x91871616, + 0x734E3D3D, 0x08AAA2A2, 0xC869A1A1, 0xC76AADAD, 0x85830606, 0x7AB0CACA, + 0xB570C5C5, 0xF4659191, 0xB2D96B6B, 0xA7892E2E, 0x18FBE3E3, 0x47E8AFAF, + 0x330F3C3C, 0x674A2D2D, 0xB071C1C1, 0x0E575959, 0xE99F7676, 0xE135D4D4, + 0x661E7878, 0xB4249090, 0x360E3838, 0x265F7979, 0xEF628D8D, 0x38596161, + 0x95D24747, 0x2AA08A8A, 0xB1259494, 0xAA228888, 0x8C7DF1F1, 0xD73BECEC, + 0x05010404, 0xA5218484, 0x9879E1E1, 0x9B851E1E, 0x84D75353, 0x00000000, + 0x5E471919, 0x0B565D5D, 0xE39D7E7E, 0x9FD04F4F, 0xBB279C9C, 0x1A534949, + 0x7C4D3131, 0xEE36D8D8, 0x0A020808, 0x7BE49F9F, 0x20A28282, 0xD4C71313, + 0xE8CB2323, 0xE69C7A7A, 0x42E9ABAB, 0x43BDFEFE, 0xA2882A2A, 0x9AD14B4B, + 0x40410101, 0xDBC41F1F, 0xD838E0E0, 0x61B7D6D6, 0x2FA18E8E, 0x2BF4DFDF, + 0x3AF1CBCB, 0xF6CD3B3B, 0x1DFAE7E7, 0xE5608585, 0x41155454, 0x25A38686, + 0x60E38383, 0x16ACBABA, 0x295C7575, 0x34A69292, 0xF7996E6E, 0xE434D0D0, + 0x721A6868, 0x01545555, 0x19AFB6B6, 0xDF914E4E, 0xFA32C8C8, 0xF030C0C0, + 0x21F6D7D7, 0xBC8E3232, 0x75B3C6C6, 0x6FE08F8F, 0x691D7474, 0x2EF5DBDB, + 0x6AE18B8B, 0x962EB8B8, 0x8A800A0A, 0xFE679999, 0xE2C92B2B, 0xE0618181, + 0xC0C30303, 0x8D29A4A4, 0xAF238C8C, 0x07A9AEAE, 0x390D3434, 0x1F524D4D, + 0x764F3939, 0xD36EBDBD, 0x81D65757, 0xB7D86F6F, 0xEB37DCDC, 0x51441515, + 0xA6DD7B7B, 0x09FEF7F7, 0xB68C3A3A, 0x932FBCBC, 0x0F030C0C, 0x03FCFFFF, + 0xC26BA9A9, 0xBA73C9C9, 0xD96CB5B5, 0xDC6DB1B1, 0x375A6D6D, 0x15504545, + 0xB98F3636, 0x771B6C6C, 0x13ADBEBE, 0xDA904A4A, 0x57B9EEEE, 0xA9DE7777, + 0x4CBEF2F2, 0x837EFDFD, 0x55114444, 0xBDDA6767, 0x2C5D7171, 0x45400505, + 0x631F7C7C, 0x50104040, 0x325B6969, 0xB8DB6363, 0x220A2828, 0xC5C20707, + 0xF531C4C4, 0xA88A2222, 0x31A79696, 0xF9CE3737, 0x977AEDED, 0x49BFF6F6, + 0x992DB4B4, 0xA475D1D1, 0x90D34343, 0x5A124848, 0x58BAE2E2, 0x71E69797, + 0x64B6D2D2, 0x70B2C2C2, 0xAD8B2626, 0xCD68A5A5, 0xCB955E5E, 0x624B2929, + 0x3C0C3030, 0xCE945A5A, 0xAB76DDDD, 0x867FF9F9, 0xF1649595, 0x5DBBE6E6, + 0x35F2C7C7, 0x2D092424, 0xD1C61717, 0xD66FB9B9, 0xDEC51B1B, 0x94861212, + 0x78186060, 0x30F3C3C3, 0x897CF5F5, 0x5CEFB3B3, 0xD23AE8E8, 0xACDF7373, + 0x794C3535, 0xA0208080, 0x9D78E5E5, 0x56EDBBBB, 0x235E7D7D, 0xC63EF8F8, + 0x8BD45F5F, 0xE7C82F2F, 0xDD39E4E4, 0x68492121 }; + +inline uint32_t SM4_T_slow(uint32_t b) + { + const uint32_t t = make_uint32(SM4_SBOX[get_byte(0,b)], + SM4_SBOX[get_byte(1,b)], + SM4_SBOX[get_byte(2,b)], + SM4_SBOX[get_byte(3,b)]); + + // L linear transform + return t ^ rotl<2>(t) ^ rotl<10>(t) ^ rotl<18>(t) ^ rotl<24>(t); + } + +inline uint32_t SM4_T(uint32_t b) + { + return SM4_SBOX_T[get_byte(0,b)] ^ + rotr< 8>(SM4_SBOX_T[get_byte(1,b)]) ^ + rotr<16>(SM4_SBOX_T[get_byte(2,b)]) ^ + rotr<24>(SM4_SBOX_T[get_byte(3,b)]); + } + +// Variant of T for key schedule +inline uint32_t SM4_Tp(uint32_t b) + { + const uint32_t t = make_uint32(SM4_SBOX[get_byte(0,b)], + SM4_SBOX[get_byte(1,b)], + SM4_SBOX[get_byte(2,b)], + SM4_SBOX[get_byte(3,b)]); + + // L' linear transform + return t ^ rotl<13>(t) ^ rotl<23>(t); + } + +#define SM4_E_RNDS(B, R, F) do { \ + B##0 ^= F(B##1 ^ B##2 ^ B##3 ^ m_RK[4*R+0]); \ + B##1 ^= F(B##2 ^ B##3 ^ B##0 ^ m_RK[4*R+1]); \ + B##2 ^= F(B##3 ^ B##0 ^ B##1 ^ m_RK[4*R+2]); \ + B##3 ^= F(B##0 ^ B##1 ^ B##2 ^ m_RK[4*R+3]); \ + } while(0) + +#define SM4_D_RNDS(B, R, F) do { \ + B##0 ^= F(B##1 ^ B##2 ^ B##3 ^ m_RK[4*R+3]); \ + B##1 ^= F(B##2 ^ B##3 ^ B##0 ^ m_RK[4*R+2]); \ + B##2 ^= F(B##3 ^ B##0 ^ B##1 ^ m_RK[4*R+1]); \ + B##3 ^= F(B##0 ^ B##1 ^ B##2 ^ m_RK[4*R+0]); \ + } while(0) + +} + +/* +* SM4 Encryption +*/ +void SM4::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + +#if defined(BOTAN_HAS_SM4_ARMV8) + if(CPUID::has_arm_sm4()) + return sm4_armv8_encrypt(in, out, blocks); +#endif + + while(blocks >= 2) + { + uint32_t B0 = load_be(in, 0); + uint32_t B1 = load_be(in, 1); + uint32_t B2 = load_be(in, 2); + uint32_t B3 = load_be(in, 3); + + uint32_t C0 = load_be(in, 4); + uint32_t C1 = load_be(in, 5); + uint32_t C2 = load_be(in, 6); + uint32_t C3 = load_be(in, 7); + + SM4_E_RNDS(B, 0, SM4_T_slow); + SM4_E_RNDS(C, 0, SM4_T_slow); + SM4_E_RNDS(B, 1, SM4_T); + SM4_E_RNDS(C, 1, SM4_T); + SM4_E_RNDS(B, 2, SM4_T); + SM4_E_RNDS(C, 2, SM4_T); + SM4_E_RNDS(B, 3, SM4_T); + SM4_E_RNDS(C, 3, SM4_T); + SM4_E_RNDS(B, 4, SM4_T); + SM4_E_RNDS(C, 4, SM4_T); + SM4_E_RNDS(B, 5, SM4_T); + SM4_E_RNDS(C, 5, SM4_T); + SM4_E_RNDS(B, 6, SM4_T); + SM4_E_RNDS(C, 6, SM4_T); + SM4_E_RNDS(B, 7, SM4_T_slow); + SM4_E_RNDS(C, 7, SM4_T_slow); + + store_be(out, B3, B2, B1, B0, C3, C2, C1, C0); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t B0 = load_be(in, 0); + uint32_t B1 = load_be(in, 1); + uint32_t B2 = load_be(in, 2); + uint32_t B3 = load_be(in, 3); + + SM4_E_RNDS(B, 0, SM4_T_slow); + SM4_E_RNDS(B, 1, SM4_T); + SM4_E_RNDS(B, 2, SM4_T); + SM4_E_RNDS(B, 3, SM4_T); + SM4_E_RNDS(B, 4, SM4_T); + SM4_E_RNDS(B, 5, SM4_T); + SM4_E_RNDS(B, 6, SM4_T); + SM4_E_RNDS(B, 7, SM4_T_slow); + + store_be(out, B3, B2, B1, B0); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* SM4 Decryption +*/ +void SM4::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_RK.empty() == false); + +#if defined(BOTAN_HAS_SM4_ARMV8) + if(CPUID::has_arm_sm4()) + return sm4_armv8_decrypt(in, out, blocks); +#endif + + while(blocks >= 2) + { + uint32_t B0 = load_be(in, 0); + uint32_t B1 = load_be(in, 1); + uint32_t B2 = load_be(in, 2); + uint32_t B3 = load_be(in, 3); + + uint32_t C0 = load_be(in, 4); + uint32_t C1 = load_be(in, 5); + uint32_t C2 = load_be(in, 6); + uint32_t C3 = load_be(in, 7); + + SM4_D_RNDS(B, 7, SM4_T_slow); + SM4_D_RNDS(C, 7, SM4_T_slow); + SM4_D_RNDS(B, 6, SM4_T); + SM4_D_RNDS(C, 6, SM4_T); + SM4_D_RNDS(B, 5, SM4_T); + SM4_D_RNDS(C, 5, SM4_T); + SM4_D_RNDS(B, 4, SM4_T); + SM4_D_RNDS(C, 4, SM4_T); + SM4_D_RNDS(B, 3, SM4_T); + SM4_D_RNDS(C, 3, SM4_T); + SM4_D_RNDS(B, 2, SM4_T); + SM4_D_RNDS(C, 2, SM4_T); + SM4_D_RNDS(B, 1, SM4_T); + SM4_D_RNDS(C, 1, SM4_T); + SM4_D_RNDS(B, 0, SM4_T_slow); + SM4_D_RNDS(C, 0, SM4_T_slow); + + store_be(out, B3, B2, B1, B0, C3, C2, C1, C0); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t B0 = load_be(in, 0); + uint32_t B1 = load_be(in, 1); + uint32_t B2 = load_be(in, 2); + uint32_t B3 = load_be(in, 3); + + SM4_D_RNDS(B, 7, SM4_T_slow); + SM4_D_RNDS(B, 6, SM4_T); + SM4_D_RNDS(B, 5, SM4_T); + SM4_D_RNDS(B, 4, SM4_T); + SM4_D_RNDS(B, 3, SM4_T); + SM4_D_RNDS(B, 2, SM4_T); + SM4_D_RNDS(B, 1, SM4_T); + SM4_D_RNDS(B, 0, SM4_T_slow); + + store_be(out, B3, B2, B1, B0); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +#undef SM4_E_RNDS +#undef SM4_D_RNDS + +/* +* SM4 Key Schedule +*/ +void SM4::key_schedule(const uint8_t key[], size_t) + { + // System parameter or family key + const uint32_t FK[4] = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc }; + + const uint32_t CK[32] = { + 0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269, + 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9, + 0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249, + 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9, + 0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229, + 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299, + 0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209, + 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279 + }; + + secure_vector K(4); + K[0] = load_be(key, 0) ^ FK[0]; + K[1] = load_be(key, 1) ^ FK[1]; + K[2] = load_be(key, 2) ^ FK[2]; + K[3] = load_be(key, 3) ^ FK[3]; + + m_RK.resize(32); + for(size_t i = 0; i != 32; ++i) + { + K[i % 4] ^= SM4_Tp(K[(i+1)%4] ^ K[(i+2)%4] ^ K[(i+3)%4] ^ CK[i]); + m_RK[i] = K[i % 4]; + } + } + +void SM4::clear() + { + zap(m_RK); + } + +size_t SM4::parallelism() const + { +#if defined(BOTAN_HAS_SM4_ARMV8) + if(CPUID::has_arm_sm4()) + { + return 4; + } +#endif + + return 1; + } + +std::string SM4::provider() const + { +#if defined(BOTAN_HAS_SM4_ARMV8) + if(CPUID::has_arm_sm4()) + { + return "armv8"; + } +#endif + + return "base"; + } + +} diff --git a/comm/third_party/botan/src/lib/block/sm4/sm4.h b/comm/third_party/botan/src/lib/block/sm4/sm4.h new file mode 100644 index 0000000000..637ffd4bee --- /dev/null +++ b/comm/third_party/botan/src/lib/block/sm4/sm4.h @@ -0,0 +1,45 @@ +/* +* SM4 +* (C) 2017 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SM4_H_ +#define BOTAN_SM4_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sm4.h) + +namespace Botan { + +/** +* SM4 +*/ +class BOTAN_PUBLIC_API(2,2) SM4 final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "SM4"; } + BlockCipher* clone() const override { return new SM4; } + + std::string provider() const override; + size_t parallelism() const override; + private: + void key_schedule(const uint8_t[], size_t) override; + +#if defined(BOTAN_HAS_SM4_ARMV8) + void sm4_armv8_encrypt(const uint8_t in[], uint8_t out[], size_t blocks) const; + void sm4_armv8_decrypt(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + secure_vector m_RK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/sm4/sm4_armv8/info.txt b/comm/third_party/botan/src/lib/block/sm4/sm4_armv8/info.txt new file mode 100644 index 0000000000..03ff034395 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/sm4/sm4_armv8/info.txt @@ -0,0 +1,11 @@ + +SM4_ARMV8 -> 20180709 + + + +armv8sm4 + + + +gcc:8 + diff --git a/comm/third_party/botan/src/lib/block/sm4/sm4_armv8/sm4_armv8.cpp b/comm/third_party/botan/src/lib/block/sm4/sm4_armv8/sm4_armv8.cpp new file mode 100644 index 0000000000..9e7a71a102 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/sm4/sm4_armv8/sm4_armv8.cpp @@ -0,0 +1,174 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +static const uint8_t qswap_tbl[16] = { + 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 +}; + +static const uint8_t bswap_tbl[16] = { + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +}; + +inline uint32x4_t qswap_32(uint32x4_t B) + { + return vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(B), vld1q_u8(qswap_tbl))); + } + +inline uint32x4_t bswap_32(uint32x4_t B) + { + return vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(B))); + } + +/* + Swap both the quad-words and bytes within each word + equivalent to return bswap_32(qswap_32(B)) +*/ +inline uint32x4_t bqswap_32(uint32x4_t B) + { + return vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(B), vld1q_u8(bswap_tbl))); + } + +#define SM4_E(B0, B1, B2, B3, K) do { \ + B0 = vsm4eq_u32(B0, K); \ + B1 = vsm4eq_u32(B1, K); \ + B2 = vsm4eq_u32(B2, K); \ + B3 = vsm4eq_u32(B3, K); \ + } while(0) + +} + +void BOTAN_FUNC_ISA("arch=armv8.2-a+sm4") +SM4::sm4_armv8_encrypt(const uint8_t input8[], uint8_t output8[], size_t blocks) const + { + const uint32x4_t K0 = vld1q_u32(&m_RK[ 0]); + const uint32x4_t K1 = vld1q_u32(&m_RK[ 4]); + const uint32x4_t K2 = vld1q_u32(&m_RK[ 8]); + const uint32x4_t K3 = vld1q_u32(&m_RK[12]); + const uint32x4_t K4 = vld1q_u32(&m_RK[16]); + const uint32x4_t K5 = vld1q_u32(&m_RK[20]); + const uint32x4_t K6 = vld1q_u32(&m_RK[24]); + const uint32x4_t K7 = vld1q_u32(&m_RK[28]); + + const uint32_t* input32 = reinterpret_cast(reinterpret_cast(input8)); + uint32_t* output32 = reinterpret_cast(reinterpret_cast(output8)); + + while(blocks >= 4) + { + uint32x4_t B0 = bswap_32(vld1q_u32(input32)); + uint32x4_t B1 = bswap_32(vld1q_u32(input32+4)); + uint32x4_t B2 = bswap_32(vld1q_u32(input32+8)); + uint32x4_t B3 = bswap_32(vld1q_u32(input32+12)); + + SM4_E(B0, B1, B2, B3, K0); + SM4_E(B0, B1, B2, B3, K1); + SM4_E(B0, B1, B2, B3, K2); + SM4_E(B0, B1, B2, B3, K3); + SM4_E(B0, B1, B2, B3, K4); + SM4_E(B0, B1, B2, B3, K5); + SM4_E(B0, B1, B2, B3, K6); + SM4_E(B0, B1, B2, B3, K7); + + vst1q_u32(output32 , bqswap_32(B0)); + vst1q_u32(output32+ 4, bqswap_32(B1)); + vst1q_u32(output32+ 8, bqswap_32(B2)); + vst1q_u32(output32+12, bqswap_32(B3)); + + input32 += 4*4; + output32 += 4*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32x4_t B = bswap_32(vld1q_u32(input32)); + + B = vsm4eq_u32(B, K0); + B = vsm4eq_u32(B, K1); + B = vsm4eq_u32(B, K2); + B = vsm4eq_u32(B, K3); + B = vsm4eq_u32(B, K4); + B = vsm4eq_u32(B, K5); + B = vsm4eq_u32(B, K6); + B = vsm4eq_u32(B, K7); + + vst1q_u32(output32, bqswap_32(B)); + + input32 += 4; + output32 += 4; + } + } + +void BOTAN_FUNC_ISA("arch=armv8.2-a+sm4") +SM4::sm4_armv8_decrypt(const uint8_t input8[], uint8_t output8[], size_t blocks) const + { + const uint32x4_t K0 = qswap_32(vld1q_u32(&m_RK[ 0])); + const uint32x4_t K1 = qswap_32(vld1q_u32(&m_RK[ 4])); + const uint32x4_t K2 = qswap_32(vld1q_u32(&m_RK[ 8])); + const uint32x4_t K3 = qswap_32(vld1q_u32(&m_RK[12])); + const uint32x4_t K4 = qswap_32(vld1q_u32(&m_RK[16])); + const uint32x4_t K5 = qswap_32(vld1q_u32(&m_RK[20])); + const uint32x4_t K6 = qswap_32(vld1q_u32(&m_RK[24])); + const uint32x4_t K7 = qswap_32(vld1q_u32(&m_RK[28])); + + const uint32_t* input32 = reinterpret_cast(reinterpret_cast(input8)); + uint32_t* output32 = reinterpret_cast(reinterpret_cast(output8)); + + while(blocks >= 4) + { + uint32x4_t B0 = bswap_32(vld1q_u32(input32)); + uint32x4_t B1 = bswap_32(vld1q_u32(input32+4)); + uint32x4_t B2 = bswap_32(vld1q_u32(input32+8)); + uint32x4_t B3 = bswap_32(vld1q_u32(input32+12)); + + SM4_E(B0, B1, B2, B3, K7); + SM4_E(B0, B1, B2, B3, K6); + SM4_E(B0, B1, B2, B3, K5); + SM4_E(B0, B1, B2, B3, K4); + SM4_E(B0, B1, B2, B3, K3); + SM4_E(B0, B1, B2, B3, K2); + SM4_E(B0, B1, B2, B3, K1); + SM4_E(B0, B1, B2, B3, K0); + + vst1q_u32(output32 , bqswap_32(B0)); + vst1q_u32(output32+ 4, bqswap_32(B1)); + vst1q_u32(output32+ 8, bqswap_32(B2)); + vst1q_u32(output32+12, bqswap_32(B3)); + + input32 += 4*4; + output32 += 4*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32x4_t B = bswap_32(vld1q_u32(input32)); + + B = vsm4eq_u32(B, K7); + B = vsm4eq_u32(B, K6); + B = vsm4eq_u32(B, K5); + B = vsm4eq_u32(B, K4); + B = vsm4eq_u32(B, K3); + B = vsm4eq_u32(B, K2); + B = vsm4eq_u32(B, K1); + B = vsm4eq_u32(B, K0); + + vst1q_u32(output32, bqswap_32(B)); + + input32 += 4; + output32 += 4; + } + } + +#undef SM4_E + +} diff --git a/comm/third_party/botan/src/lib/block/threefish_512/info.txt b/comm/third_party/botan/src/lib/block/threefish_512/info.txt new file mode 100644 index 0000000000..e122236794 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/threefish_512/info.txt @@ -0,0 +1,3 @@ + +THREEFISH_512 -> 20131224 + diff --git a/comm/third_party/botan/src/lib/block/threefish_512/threefish.h b/comm/third_party/botan/src/lib/block/threefish_512/threefish.h new file mode 100644 index 0000000000..f866a717ff --- /dev/null +++ b/comm/third_party/botan/src/lib/block/threefish_512/threefish.h @@ -0,0 +1,17 @@ +/* +* Threefish +* (C) 2013,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_THREEFISH_H_ +#define BOTAN_THREEFISH_H_ + +// This header is deprecated and will be removed in a future major release + +#include + +BOTAN_DEPRECATED_HEADER(threefish.h) + +#endif diff --git a/comm/third_party/botan/src/lib/block/threefish_512/threefish_512.cpp b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512.cpp new file mode 100644 index 0000000000..e34a9e0dca --- /dev/null +++ b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512.cpp @@ -0,0 +1,273 @@ +/* +* Threefish-512 +* (C) 2013,2014,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +#define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X0 += X4; \ + X1 += X5; \ + X2 += X6; \ + X3 += X7; \ + X4 = rotl(X4); \ + X5 = rotl(X5); \ + X6 = rotl(X6); \ + X7 = rotl(X7); \ + X4 ^= X0; \ + X5 ^= X1; \ + X6 ^= X2; \ + X7 ^= X3; \ + } while(0) + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 += m_K[(r ) % 9]; \ + X1 += m_K[(r+1) % 9]; \ + X2 += m_K[(r+2) % 9]; \ + X3 += m_K[(r+3) % 9]; \ + X4 += m_K[(r+4) % 9]; \ + X5 += m_K[(r+5) % 9] + m_T[(r ) % 3]; \ + X6 += m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ + X7 += m_K[(r+7) % 9] + (r); \ + } while(0) + +#define THREEFISH_ENC_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22); \ + THREEFISH_INJECT_KEY(R2); \ + } while(0) + +void Threefish_512::skein_feedfwd(const secure_vector& M, + const secure_vector& T) + { + BOTAN_ASSERT(m_K.size() == 9, "Key was set"); + BOTAN_ASSERT(M.size() == 8, "Single block"); + + m_T[0] = T[0]; + m_T[1] = T[1]; + m_T[2] = T[0] ^ T[1]; + + uint64_t X0 = M[0]; + uint64_t X1 = M[1]; + uint64_t X2 = M[2]; + uint64_t X3 = M[3]; + uint64_t X4 = M[4]; + uint64_t X5 = M[5]; + uint64_t X6 = M[6]; + uint64_t X7 = M[7]; + + THREEFISH_INJECT_KEY(0); + + THREEFISH_ENC_8_ROUNDS(1,2); + THREEFISH_ENC_8_ROUNDS(3,4); + THREEFISH_ENC_8_ROUNDS(5,6); + THREEFISH_ENC_8_ROUNDS(7,8); + THREEFISH_ENC_8_ROUNDS(9,10); + THREEFISH_ENC_8_ROUNDS(11,12); + THREEFISH_ENC_8_ROUNDS(13,14); + THREEFISH_ENC_8_ROUNDS(15,16); + THREEFISH_ENC_8_ROUNDS(17,18); + + m_K[0] = M[0] ^ X0; + m_K[1] = M[1] ^ X1; + m_K[2] = M[2] ^ X2; + m_K[3] = M[3] ^ X3; + m_K[4] = M[4] ^ X4; + m_K[5] = M[5] ^ X5; + m_K[6] = M[6] ^ X6; + m_K[7] = M[7] ^ X7; + + m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ + m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; + } + +size_t Threefish_512::parallelism() const + { +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return 2; + } +#endif + + return 1; + } + +std::string Threefish_512::provider() const + { +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return "avx2"; + } +#endif + + return "base"; + } + +void Threefish_512::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K.empty() == false); + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return avx2_encrypt_n(in, out, blocks); + } +#endif + + BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) + { + uint64_t X0, X1, X2, X3, X4, X5, X6, X7; + load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); + + THREEFISH_INJECT_KEY(0); + + THREEFISH_ENC_8_ROUNDS(1,2); + THREEFISH_ENC_8_ROUNDS(3,4); + THREEFISH_ENC_8_ROUNDS(5,6); + THREEFISH_ENC_8_ROUNDS(7,8); + THREEFISH_ENC_8_ROUNDS(9,10); + THREEFISH_ENC_8_ROUNDS(11,12); + THREEFISH_ENC_8_ROUNDS(13,14); + THREEFISH_ENC_8_ROUNDS(15,16); + THREEFISH_ENC_8_ROUNDS(17,18); + + store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); + } + } + +#undef THREEFISH_ENC_8_ROUNDS +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_ROUND + +void Threefish_512::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K.empty() == false); + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return avx2_decrypt_n(in, out, blocks); + } +#endif + +#define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X4 ^= X0; \ + X5 ^= X1; \ + X6 ^= X2; \ + X7 ^= X3; \ + X4 = rotr(X4); \ + X5 = rotr(X5); \ + X6 = rotr(X6); \ + X7 = rotr(X7); \ + X0 -= X4; \ + X1 -= X5; \ + X2 -= X6; \ + X3 -= X7; \ + } while(0) + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 -= m_K[(r ) % 9]; \ + X1 -= m_K[(r+1) % 9]; \ + X2 -= m_K[(r+2) % 9]; \ + X3 -= m_K[(r+3) % 9]; \ + X4 -= m_K[(r+4) % 9]; \ + X5 -= m_K[(r+5) % 9] + m_T[(r ) % 3]; \ + X6 -= m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ + X7 -= m_K[(r+7) % 9] + (r); \ + } while(0) + +#define THREEFISH_DEC_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17); \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24); \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56); \ + THREEFISH_ROUND(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39); \ + THREEFISH_ROUND(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42); \ + THREEFISH_ROUND(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37); \ + THREEFISH_INJECT_KEY(R2); \ + } while(0) + + BOTAN_PARALLEL_SIMD_FOR(size_t i = 0; i < blocks; ++i) + { + uint64_t X0, X1, X2, X3, X4, X5, X6, X7; + load_le(in + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); + + THREEFISH_INJECT_KEY(18); + + THREEFISH_DEC_8_ROUNDS(17,16); + THREEFISH_DEC_8_ROUNDS(15,14); + THREEFISH_DEC_8_ROUNDS(13,12); + THREEFISH_DEC_8_ROUNDS(11,10); + THREEFISH_DEC_8_ROUNDS(9,8); + THREEFISH_DEC_8_ROUNDS(7,6); + THREEFISH_DEC_8_ROUNDS(5,4); + THREEFISH_DEC_8_ROUNDS(3,2); + THREEFISH_DEC_8_ROUNDS(1,0); + + store_le(out + BLOCK_SIZE*i, X0, X1, X2, X3, X4, X5, X6, X7); + } + +#undef THREEFISH_DEC_8_ROUNDS +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_ROUND + } + +void Threefish_512::set_tweak(const uint8_t tweak[], size_t len) + { + BOTAN_ARG_CHECK(len == 16, "Threefish-512 requires 128 bit tweak"); + + m_T.resize(3); + m_T[0] = load_le(tweak, 0); + m_T[1] = load_le(tweak, 1); + m_T[2] = m_T[0] ^ m_T[1]; + } + +void Threefish_512::key_schedule(const uint8_t key[], size_t) + { + // todo: define key schedule for smaller keys + m_K.resize(9); + + for(size_t i = 0; i != 8; ++i) + m_K[i] = load_le(key, i); + + m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ + m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; + + // Reset tweak to all zeros on key reset + m_T.resize(3); + zeroise(m_T); + } + +void Threefish_512::clear() + { + zap(m_K); + zap(m_T); + } + +} diff --git a/comm/third_party/botan/src/lib/block/threefish_512/threefish_512.h b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512.h new file mode 100644 index 0000000000..f3adf71a92 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512.h @@ -0,0 +1,57 @@ +/* +* Threefish-512 +* (C) 2013,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_THREEFISH_512_H_ +#define BOTAN_THREEFISH_512_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(threefish_512.h) + +namespace Botan { + +/** +* Threefish-512 +*/ +class BOTAN_PUBLIC_API(2,0) Threefish_512 final : + public Block_Cipher_Fixed_Params<64, 64, 0, 1, Tweakable_Block_Cipher> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void set_tweak(const uint8_t tweak[], size_t len) override; + + void clear() override; + std::string provider() const override; + std::string name() const override { return "Threefish-512"; } + BlockCipher* clone() const override { return new Threefish_512; } + size_t parallelism() const override; + + private: + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + void avx2_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void avx2_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + void key_schedule(const uint8_t key[], size_t key_len) override; + + // Interface for Skein + friend class Skein_512; + + void skein_feedfwd(const secure_vector& M, + const secure_vector& T); + + // Private data + secure_vector m_T; + secure_vector m_K; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/info.txt b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/info.txt new file mode 100644 index 0000000000..b5374c4406 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/info.txt @@ -0,0 +1,14 @@ + +THREEFISH_512_AVX2 -> 20160903 + + + +avx2 + + + +gcc +clang +msvc +icc + diff --git a/comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/threefish_512_avx2.cpp b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/threefish_512_avx2.cpp new file mode 100644 index 0000000000..0ceea2d7f0 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/threefish_512/threefish_512_avx2/threefish_512_avx2.cpp @@ -0,0 +1,444 @@ +/* +* Threefish-512 using AVX2 +* (C) 2013,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +BOTAN_FUNC_ISA("avx2") +inline void interleave_epi64(__m256i& X0, __m256i& X1) + { + // interleave X0 and X1 qwords + // (X0,X1,X2,X3),(X4,X5,X6,X7) -> (X0,X2,X4,X6),(X1,X3,X5,X7) + + const __m256i T0 = _mm256_unpacklo_epi64(X0, X1); + const __m256i T1 = _mm256_unpackhi_epi64(X0, X1); + + X0 = _mm256_permute4x64_epi64(T0, _MM_SHUFFLE(3,1,2,0)); + X1 = _mm256_permute4x64_epi64(T1, _MM_SHUFFLE(3,1,2,0)); + } + +BOTAN_FUNC_ISA("avx2") +inline void deinterleave_epi64(__m256i& X0, __m256i& X1) + { + const __m256i T0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(3,1,2,0)); + const __m256i T1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(3,1,2,0)); + + X0 = _mm256_unpacklo_epi64(T0, T1); + X1 = _mm256_unpackhi_epi64(T0, T1); + } + +BOTAN_FUNC_ISA("avx2") +inline void rotate_keys(__m256i& R0, __m256i& R1, __m256i R2) + { + /* + Behold. The key schedule progresses like so. The values + loop back to the originals after the rounds are complete + so we don't need to reload for starting the next block. + + R0 R1 R2 + K1,K2,K3 (7,5,3,1),(8,6,4,2),(0,7,5,3) + K3,K4,K5 (0,7,5,3),(1,8,6,4),(2,0,7,5) + K5,K6,K7 (2,0,7,5),(3,1,8,6),(4,2,0,7) + + K7,K8,K0 (4,2,0,7),(5,3,1,8),(6,4,2,0) + K0,K1,K2 (6,4,2,0),(7,5,3,1),(8,6,4,2) + K2,K3,K4 (8,6,4,2),(0,7,5,3),(1,8,6,4) + + K4,K5,K6 (1,8,6,4),(2,0,7,5),(3,1,8,6) + K6,K7,K8 (3,1,8,6),(4,2,0,7),(5,3,1,8) + K8,K0,K1 (5,3,1,8),(6,4,2,0),(7,5,3,1) + + To compute the values for the next round: + X0 is X2 from the last round + X1 becomes (X0[4],X1[1:3]) + X2 becomes (X1[4],X2[1:3]) + + Uses 3 permutes and 2 blends, is there a faster way? + */ + __m256i T0 = _mm256_permute4x64_epi64(R0, _MM_SHUFFLE(0,0,0,0)); + __m256i T1 = _mm256_permute4x64_epi64(R1, _MM_SHUFFLE(0,3,2,1)); + __m256i T2 = _mm256_permute4x64_epi64(R2, _MM_SHUFFLE(0,3,2,1)); + + R0 = _mm256_blend_epi32(T1, T0, 0xC0); + R1 = _mm256_blend_epi32(T2, T1, 0xC0); + } + + +} + +BOTAN_FUNC_ISA("avx2") +void Threefish_512::avx2_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + _mm256_zeroupper(); + + const uint64_t* K = m_K.data(); + const uint64_t* T_64 = m_T.data(); + + const __m256i ROTATE_1 = _mm256_set_epi64x(37,19,36,46); + const __m256i ROTATE_2 = _mm256_set_epi64x(42,14,27,33); + const __m256i ROTATE_3 = _mm256_set_epi64x(39,36,49,17); + const __m256i ROTATE_4 = _mm256_set_epi64x(56,54, 9,44); + const __m256i ROTATE_5 = _mm256_set_epi64x(24,34,30,39); + const __m256i ROTATE_6 = _mm256_set_epi64x(17,10,50,13); + const __m256i ROTATE_7 = _mm256_set_epi64x(43,39,29,25); + const __m256i ROTATE_8 = _mm256_set_epi64x(22,56,35, 8); + +#define THREEFISH_ROUND(X0, X1, SHL) \ + do { \ + const __m256i SHR = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHL); \ + X0 = _mm256_add_epi64(X0, X1); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(0, 3, 2, 1)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + } while(0) + +#define THREEFISH_ROUND_2(X0, X1, X2, X3, SHL) \ + do { \ + const __m256i SHR = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHL); \ + X0 = _mm256_add_epi64(X0, X1); \ + X2 = _mm256_add_epi64(X2, X3); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X3 = _mm256_or_si256(_mm256_sllv_epi64(X3, SHL), _mm256_srlv_epi64(X3, SHR)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X3 = _mm256_xor_si256(X3, X2); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(0, 3, 2, 1)); \ + X2 = _mm256_permute4x64_epi64(X2, _MM_SHUFFLE(0, 3, 2, 1)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + X3 = _mm256_permute4x64_epi64(X3, _MM_SHUFFLE(1, 2, 3, 0)); \ + } while(0) + +#define THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + const __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_add_epi64(X0, K0); \ + X1 = _mm256_add_epi64(X1, K1); \ + X1 = _mm256_add_epi64(X1, _mm256_set_epi64x(R,0,0,0)); \ + X0 = _mm256_add_epi64(X0, T0); \ + X1 = _mm256_add_epi64(X1, T1); \ + } while(0) + +#define THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_add_epi64(X0, K0); \ + X2 = _mm256_add_epi64(X2, K0); \ + X1 = _mm256_add_epi64(X1, K1); \ + X3 = _mm256_add_epi64(X3, K1); \ + T1 = _mm256_add_epi64(T1, _mm256_set_epi64x(R,0,0,0)); \ + X0 = _mm256_add_epi64(X0, T0); \ + X2 = _mm256_add_epi64(X2, T0); \ + X1 = _mm256_add_epi64(X1, T1); \ + X3 = _mm256_add_epi64(X3, T1); \ + } while(0) + +#define THREEFISH_ENC_8_ROUNDS(X0, X1, R, K0, K1, K2, T0, T1, T2) \ + do { \ + rotate_keys(K1, K2, K0); \ + THREEFISH_ROUND(X0, X1, ROTATE_1); \ + THREEFISH_ROUND(X0, X1, ROTATE_2); \ + THREEFISH_ROUND(X0, X1, ROTATE_3); \ + THREEFISH_ROUND(X0, X1, ROTATE_4); \ + THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0, T1); \ + \ + THREEFISH_ROUND(X0, X1, ROTATE_5); \ + THREEFISH_ROUND(X0, X1, ROTATE_6); \ + THREEFISH_ROUND(X0, X1, ROTATE_7); \ + THREEFISH_ROUND(X0, X1, ROTATE_8); \ + THREEFISH_INJECT_KEY(X0, X1, R+1, K1, K2, T2, T0); \ + } while(0) + +#define THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K0, K1, K2, T0, T1, T2) \ + do { \ + rotate_keys(K1, K2, K0); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_1); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_2); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_3); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_4); \ + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0, T1); \ + \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_5); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_6); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_7); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_8); \ + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R+1, K1, K2, T2, T0); \ + } while(0) + + __m256i K0 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]); + __m256i K1 = _mm256_set_epi64x(K[6], K[4], K[2], K[0]); + __m256i K2 = _mm256_set_epi64x(K[7], K[5], K[3], K[1]); + + const __m256i* in_mm = reinterpret_cast(in); + __m256i* out_mm = reinterpret_cast<__m256i*>(out); + + while(blocks >= 2) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + __m256i X2 = _mm256_loadu_si256(in_mm++); + __m256i X3 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + interleave_epi64(X0, X1); + interleave_epi64(X2, X3); + + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, 0, K1, K2, 2, 3); + + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 1, K2,K0,K1, 1, 2, 3); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 3, K1,K2,K0, 2, 3, 1); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 5, K0,K1,K2, 3, 1, 2); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 7, K2,K0,K1, 1, 2, 3); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 9, K1,K2,K0, 2, 3, 1); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 11, K0,K1,K2, 3, 1, 2); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 13, K2,K0,K1, 1, 2, 3); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 15, K1,K2,K0, 2, 3, 1); + THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 17, K0,K1,K2, 3, 1, 2); + + deinterleave_epi64(X0, X1); + deinterleave_epi64(X2, X3); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + _mm256_storeu_si256(out_mm++, X2); + _mm256_storeu_si256(out_mm++, X3); + + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + interleave_epi64(X0, X1); + + THREEFISH_INJECT_KEY(X0, X1, 0, K1, K2, 2, 3); + + THREEFISH_ENC_8_ROUNDS(X0, X1, 1, K2,K0,K1, 1, 2, 3); + THREEFISH_ENC_8_ROUNDS(X0, X1, 3, K1,K2,K0, 2, 3, 1); + THREEFISH_ENC_8_ROUNDS(X0, X1, 5, K0,K1,K2, 3, 1, 2); + THREEFISH_ENC_8_ROUNDS(X0, X1, 7, K2,K0,K1, 1, 2, 3); + THREEFISH_ENC_8_ROUNDS(X0, X1, 9, K1,K2,K0, 2, 3, 1); + THREEFISH_ENC_8_ROUNDS(X0, X1, 11, K0,K1,K2, 3, 1, 2); + THREEFISH_ENC_8_ROUNDS(X0, X1, 13, K2,K0,K1, 1, 2, 3); + THREEFISH_ENC_8_ROUNDS(X0, X1, 15, K1,K2,K0, 2, 3, 1); + THREEFISH_ENC_8_ROUNDS(X0, X1, 17, K0,K1,K2, 3, 1, 2); + + deinterleave_epi64(X0, X1); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + } + + _mm256_zeroall(); + +#undef THREEFISH_ENC_8_ROUNDS +#undef THREEFISH_ROUND +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_DEC_2_8_ROUNDS +#undef THREEFISH_ROUND_2 +#undef THREEFISH_INJECT_KEY_2 + } + +BOTAN_FUNC_ISA("avx2") +void Threefish_512::avx2_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + _mm256_zeroupper(); + + const uint64_t* K = m_K.data(); + const uint64_t* T_64 = m_T.data(); + + const __m256i ROTATE_1 = _mm256_set_epi64x(37,19,36,46); + const __m256i ROTATE_2 = _mm256_set_epi64x(42,14,27,33); + const __m256i ROTATE_3 = _mm256_set_epi64x(39,36,49,17); + const __m256i ROTATE_4 = _mm256_set_epi64x(56,54, 9,44); + const __m256i ROTATE_5 = _mm256_set_epi64x(24,34,30,39); + const __m256i ROTATE_6 = _mm256_set_epi64x(17,10,50,13); + const __m256i ROTATE_7 = _mm256_set_epi64x(43,39,29,25); + const __m256i ROTATE_8 = _mm256_set_epi64x(22,56,35, 8); + +#define THREEFISH_ROUND(X0, X1, SHR) \ + do { \ + const __m256i SHL = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHR); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(2, 1, 0, 3)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X0 = _mm256_sub_epi64(X0, X1); \ + } while(0) + +#define THREEFISH_ROUND_2(X0, X1, X2, X3, SHR) \ + do { \ + const __m256i SHL = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHR); \ + X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(2, 1, 0, 3)); \ + X2 = _mm256_permute4x64_epi64(X2, _MM_SHUFFLE(2, 1, 0, 3)); \ + X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \ + X3 = _mm256_permute4x64_epi64(X3, _MM_SHUFFLE(1, 2, 3, 0)); \ + X1 = _mm256_xor_si256(X1, X0); \ + X3 = _mm256_xor_si256(X3, X2); \ + X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \ + X3 = _mm256_or_si256(_mm256_sllv_epi64(X3, SHL), _mm256_srlv_epi64(X3, SHR)); \ + X0 = _mm256_sub_epi64(X0, X1); \ + X2 = _mm256_sub_epi64(X2, X3); \ + } while(0) + +#define THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + const __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_sub_epi64(X0, K0); \ + X1 = _mm256_sub_epi64(X1, K1); \ + X1 = _mm256_sub_epi64(X1, _mm256_set_epi64x(R, 0, 0, 0)); \ + X0 = _mm256_sub_epi64(X0, T0); \ + X1 = _mm256_sub_epi64(X1, T1); \ + } while(0) + +#define THREEFISH_DEC_8_ROUNDS(X0, X1, R, K1, K2, K3, T0, T1, T2) \ + do { \ + THREEFISH_INJECT_KEY(X0, X1, R+1, K2, K3, T2, T0); \ + THREEFISH_ROUND(X0, X1, ROTATE_8); \ + THREEFISH_ROUND(X0, X1, ROTATE_7); \ + THREEFISH_ROUND(X0, X1, ROTATE_6); \ + THREEFISH_ROUND(X0, X1, ROTATE_5); \ + \ + THREEFISH_INJECT_KEY(X0, X1, R, K1, K2, T0, T1); \ + THREEFISH_ROUND(X0, X1, ROTATE_4); \ + THREEFISH_ROUND(X0, X1, ROTATE_3); \ + THREEFISH_ROUND(X0, X1, ROTATE_2); \ + THREEFISH_ROUND(X0, X1, ROTATE_1); \ + } while(0) + +#define THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0I, T1I) \ + do { \ + const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \ + __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \ + X0 = _mm256_sub_epi64(X0, K0); \ + X2 = _mm256_sub_epi64(X2, K0); \ + X1 = _mm256_sub_epi64(X1, K1); \ + X3 = _mm256_sub_epi64(X3, K1); \ + T1 = _mm256_add_epi64(T1, _mm256_set_epi64x(R,0,0,0)); \ + X0 = _mm256_sub_epi64(X0, T0); \ + X2 = _mm256_sub_epi64(X2, T0); \ + X1 = _mm256_sub_epi64(X1, T1); \ + X3 = _mm256_sub_epi64(X3, T1); \ + } while(0) + +#define THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, R, K1, K2, K3, T0, T1, T2) \ + do { \ + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R+1, K2, K3, T2, T0); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_8); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_7); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_6); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_5); \ + \ + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K1, K2, T0, T1); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_4); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_3); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_2); \ + THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_1); \ + } while(0) + + /* + v1.0 key schedule: 9 ymm registers (only need 2 or 3) + (0,1,2,3),(4,5,6,7) [8] + then mutating with vpermq + */ + const __m256i K0 = _mm256_set_epi64x(K[6], K[4], K[2], K[0]); + const __m256i K1 = _mm256_set_epi64x(K[7], K[5], K[3], K[1]); + const __m256i K2 = _mm256_set_epi64x(K[8], K[6], K[4], K[2]); + const __m256i K3 = _mm256_set_epi64x(K[0], K[7], K[5], K[3]); + const __m256i K4 = _mm256_set_epi64x(K[1], K[8], K[6], K[4]); + const __m256i K5 = _mm256_set_epi64x(K[2], K[0], K[7], K[5]); + const __m256i K6 = _mm256_set_epi64x(K[3], K[1], K[8], K[6]); + const __m256i K7 = _mm256_set_epi64x(K[4], K[2], K[0], K[7]); + const __m256i K8 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]); + + const __m256i* in_mm = reinterpret_cast(in); + __m256i* out_mm = reinterpret_cast<__m256i*>(out); + + while(blocks >= 2) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + __m256i X2 = _mm256_loadu_si256(in_mm++); + __m256i X3 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + interleave_epi64(X0, X1); + interleave_epi64(X2, X3); + + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 17, K8,K0,K1, 3, 1, 2); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 15, K6,K7,K8, 2, 3, 1); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 13, K4,K5,K6, 1, 2, 3); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 11, K2,K3,K4, 3, 1, 2); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 9, K0,K1,K2, 2, 3, 1); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 7, K7,K8,K0, 1, 2, 3); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 5, K5,K6,K7, 3, 1, 2); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 3, K3,K4,K5, 2, 3, 1); + THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 1, K1,K2,K3, 1, 2, 3); + + THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, 0, K0, K1, 2, 3); + + deinterleave_epi64(X0, X1); + deinterleave_epi64(X2, X3); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + _mm256_storeu_si256(out_mm++, X2); + _mm256_storeu_si256(out_mm++, X3); + + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m256i X0 = _mm256_loadu_si256(in_mm++); + __m256i X1 = _mm256_loadu_si256(in_mm++); + + const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0); + + interleave_epi64(X0, X1); + + THREEFISH_DEC_8_ROUNDS(X0, X1, 17, K8,K0,K1, 3, 1, 2); + THREEFISH_DEC_8_ROUNDS(X0, X1, 15, K6,K7,K8, 2, 3, 1); + THREEFISH_DEC_8_ROUNDS(X0, X1, 13, K4,K5,K6, 1, 2, 3); + THREEFISH_DEC_8_ROUNDS(X0, X1, 11, K2,K3,K4, 3, 1, 2); + THREEFISH_DEC_8_ROUNDS(X0, X1, 9, K0,K1,K2, 2, 3, 1); + THREEFISH_DEC_8_ROUNDS(X0, X1, 7, K7,K8,K0, 1, 2, 3); + THREEFISH_DEC_8_ROUNDS(X0, X1, 5, K5,K6,K7, 3, 1, 2); + THREEFISH_DEC_8_ROUNDS(X0, X1, 3, K3,K4,K5, 2, 3, 1); + THREEFISH_DEC_8_ROUNDS(X0, X1, 1, K1,K2,K3, 1, 2, 3); + + THREEFISH_INJECT_KEY(X0, X1, 0, K0, K1, 2, 3); + + deinterleave_epi64(X0, X1); + + _mm256_storeu_si256(out_mm++, X0); + _mm256_storeu_si256(out_mm++, X1); + } + +#undef THREEFISH_DEC_8_ROUNDS +#undef THREEFISH_ROUND +#undef THREEFISH_INJECT_KEY +#undef THREEFISH_DEC_2_8_ROUNDS +#undef THREEFISH_ROUND_2 +#undef THREEFISH_INJECT_KEY_2 + + _mm256_zeroall(); + } + +} diff --git a/comm/third_party/botan/src/lib/block/twofish/info.txt b/comm/third_party/botan/src/lib/block/twofish/info.txt new file mode 100644 index 0000000000..9febbc8dd2 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/twofish/info.txt @@ -0,0 +1,3 @@ + +TWOFISH -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/twofish/twofish.cpp b/comm/third_party/botan/src/lib/block/twofish/twofish.cpp new file mode 100644 index 0000000000..3a508dc9d5 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/twofish/twofish.cpp @@ -0,0 +1,326 @@ +/* +* Twofish +* (C) 1999-2007,2017 Jack Lloyd +* +* The key schedule implemenation is based on a public domain +* implementation by Matthew Skala +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +inline void TF_E(uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, + uint32_t RK1, uint32_t RK2, + const secure_vector& SB) + { + uint32_t X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ + SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; + uint32_t Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ + SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; + + X += Y; + Y += X; + + X += RK1; + Y += RK2; + + C = rotr<1>(C ^ X); + D = rotl<1>(D) ^ Y; + } + +inline void TF_D(uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, + uint32_t RK1, uint32_t RK2, + const secure_vector& SB) + { + uint32_t X = SB[ get_byte(3, A)] ^ SB[256+get_byte(2, A)] ^ + SB[512+get_byte(1, A)] ^ SB[768+get_byte(0, A)]; + uint32_t Y = SB[ get_byte(0, B)] ^ SB[256+get_byte(3, B)] ^ + SB[512+get_byte(2, B)] ^ SB[768+get_byte(1, B)]; + + X += Y; + Y += X; + + X += RK1; + Y += RK2; + + C = rotl<1>(C) ^ X; + D = rotr<1>(D ^ Y); + } + +} + +/* +* Twofish Encryption +*/ +void Twofish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SB.empty() == false); + + while(blocks >= 2) + { + uint32_t A0, B0, C0, D0; + uint32_t A1, B1, C1, D1; + load_le(in, A0, B0, C0, D0, A1, B1, C1, D1); + + A0 ^= m_RK[0]; + A1 ^= m_RK[0]; + B0 ^= m_RK[1]; + B1 ^= m_RK[1]; + C0 ^= m_RK[2]; + C1 ^= m_RK[2]; + D0 ^= m_RK[3]; + D1 ^= m_RK[3]; + + for(size_t k = 8; k != 40; k += 4) + { + TF_E(A0, B0, C0, D0, m_RK[k+0], m_RK[k+1], m_SB); + TF_E(A1, B1, C1, D1, m_RK[k+0], m_RK[k+1], m_SB); + + TF_E(C0, D0, A0, B0, m_RK[k+2], m_RK[k+3], m_SB); + TF_E(C1, D1, A1, B1, m_RK[k+2], m_RK[k+3], m_SB); + } + + C0 ^= m_RK[4]; + C1 ^= m_RK[4]; + D0 ^= m_RK[5]; + D1 ^= m_RK[5]; + A0 ^= m_RK[6]; + A1 ^= m_RK[6]; + B0 ^= m_RK[7]; + B1 ^= m_RK[7]; + + store_le(out, C0, D0, A0, B0, C1, D1, A1, B1); + + blocks -= 2; + out += 2*BLOCK_SIZE; + in += 2*BLOCK_SIZE; + } + + if(blocks) + { + uint32_t A, B, C, D; + load_le(in, A, B, C, D); + + A ^= m_RK[0]; + B ^= m_RK[1]; + C ^= m_RK[2]; + D ^= m_RK[3]; + + for(size_t k = 8; k != 40; k += 4) + { + TF_E(A, B, C, D, m_RK[k ], m_RK[k+1], m_SB); + TF_E(C, D, A, B, m_RK[k+2], m_RK[k+3], m_SB); + } + + C ^= m_RK[4]; + D ^= m_RK[5]; + A ^= m_RK[6]; + B ^= m_RK[7]; + + store_le(out, C, D, A, B); + } + } + +/* +* Twofish Decryption +*/ +void Twofish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_SB.empty() == false); + + while(blocks >= 2) + { + uint32_t A0, B0, C0, D0; + uint32_t A1, B1, C1, D1; + load_le(in, A0, B0, C0, D0, A1, B1, C1, D1); + + A0 ^= m_RK[4]; + A1 ^= m_RK[4]; + B0 ^= m_RK[5]; + B1 ^= m_RK[5]; + C0 ^= m_RK[6]; + C1 ^= m_RK[6]; + D0 ^= m_RK[7]; + D1 ^= m_RK[7]; + + for(size_t k = 40; k != 8; k -= 4) + { + TF_D(A0, B0, C0, D0, m_RK[k-2], m_RK[k-1], m_SB); + TF_D(A1, B1, C1, D1, m_RK[k-2], m_RK[k-1], m_SB); + + TF_D(C0, D0, A0, B0, m_RK[k-4], m_RK[k-3], m_SB); + TF_D(C1, D1, A1, B1, m_RK[k-4], m_RK[k-3], m_SB); + } + + C0 ^= m_RK[0]; + C1 ^= m_RK[0]; + D0 ^= m_RK[1]; + D1 ^= m_RK[1]; + A0 ^= m_RK[2]; + A1 ^= m_RK[2]; + B0 ^= m_RK[3]; + B1 ^= m_RK[3]; + + store_le(out, C0, D0, A0, B0, C1, D1, A1, B1); + + blocks -= 2; + out += 2*BLOCK_SIZE; + in += 2*BLOCK_SIZE; + } + + if(blocks) + { + uint32_t A, B, C, D; + load_le(in, A, B, C, D); + + A ^= m_RK[4]; + B ^= m_RK[5]; + C ^= m_RK[6]; + D ^= m_RK[7]; + + for(size_t k = 40; k != 8; k -= 4) + { + TF_D(A, B, C, D, m_RK[k-2], m_RK[k-1], m_SB); + TF_D(C, D, A, B, m_RK[k-4], m_RK[k-3], m_SB); + } + + C ^= m_RK[0]; + D ^= m_RK[1]; + A ^= m_RK[2]; + B ^= m_RK[3]; + + store_le(out, C, D, A, B); + } + } + +/* +* Twofish Key Schedule +*/ +void Twofish::key_schedule(const uint8_t key[], size_t length) + { + m_SB.resize(1024); + m_RK.resize(40); + + secure_vector S(16); + + for(size_t i = 0; i != length; ++i) + { + /* + * Do one column of the RS matrix multiplcation + */ + if(key[i]) + { + uint8_t X = POLY_TO_EXP[key[i] - 1]; + + uint8_t RS1 = RS[(4*i ) % 32]; + uint8_t RS2 = RS[(4*i+1) % 32]; + uint8_t RS3 = RS[(4*i+2) % 32]; + uint8_t RS4 = RS[(4*i+3) % 32]; + + S[4*(i/8) ] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; + S[4*(i/8)+1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; + S[4*(i/8)+2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; + S[4*(i/8)+3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; + } + } + + if(length == 16) + { + for(size_t i = 0; i != 256; ++i) + { + m_SB[ i] = MDS0[Q0[Q0[i]^S[ 0]]^S[ 4]]; + m_SB[256+i] = MDS1[Q0[Q1[i]^S[ 1]]^S[ 5]]; + m_SB[512+i] = MDS2[Q1[Q0[i]^S[ 2]]^S[ 6]]; + m_SB[768+i] = MDS3[Q1[Q1[i]^S[ 3]]^S[ 7]]; + } + + for(size_t i = 0; i < 40; i += 2) + { + uint32_t X = MDS0[Q0[Q0[i ]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[i ]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[i ]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[i ]^key[11]]^key[ 3]]; + uint32_t Y = MDS0[Q0[Q0[i+1]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[i+1]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[i+1]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[i+1]^key[15]]^key[ 7]]; + Y = rotl<8>(Y); + X += Y; Y += X; + + m_RK[i] = X; + m_RK[i+1] = rotl<9>(Y); + } + } + else if(length == 24) + { + for(size_t i = 0; i != 256; ++i) + { + m_SB[ i] = MDS0[Q0[Q0[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]; + m_SB[256+i] = MDS1[Q0[Q1[Q1[i]^S[ 1]]^S[ 5]]^S[ 9]]; + m_SB[512+i] = MDS2[Q1[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]; + m_SB[768+i] = MDS3[Q1[Q1[Q0[i]^S[ 3]]^S[ 7]]^S[11]]; + } + + for(size_t i = 0; i < 40; i += 2) + { + uint32_t X = MDS0[Q0[Q0[Q1[i ]^key[16]]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[Q1[i ]^key[17]]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[Q0[i ]^key[18]]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[Q0[i ]^key[19]]^key[11]]^key[ 3]]; + uint32_t Y = MDS0[Q0[Q0[Q1[i+1]^key[20]]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[Q1[i+1]^key[21]]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[Q0[i+1]^key[22]]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[Q0[i+1]^key[23]]^key[15]]^key[ 7]]; + Y = rotl<8>(Y); + X += Y; Y += X; + + m_RK[i] = X; + m_RK[i+1] = rotl<9>(Y); + } + } + else if(length == 32) + { + for(size_t i = 0; i != 256; ++i) + { + m_SB[ i] = MDS0[Q0[Q0[Q1[Q1[i]^S[ 0]]^S[ 4]]^S[ 8]]^S[12]]; + m_SB[256+i] = MDS1[Q0[Q1[Q1[Q0[i]^S[ 1]]^S[ 5]]^S[ 9]]^S[13]]; + m_SB[512+i] = MDS2[Q1[Q0[Q0[Q0[i]^S[ 2]]^S[ 6]]^S[10]]^S[14]]; + m_SB[768+i] = MDS3[Q1[Q1[Q0[Q1[i]^S[ 3]]^S[ 7]]^S[11]]^S[15]]; + } + + for(size_t i = 0; i < 40; i += 2) + { + uint32_t X = MDS0[Q0[Q0[Q1[Q1[i ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^ + MDS1[Q0[Q1[Q1[Q0[i ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^ + MDS2[Q1[Q0[Q0[Q0[i ]^key[26]]^key[18]]^key[10]]^key[ 2]] ^ + MDS3[Q1[Q1[Q0[Q1[i ]^key[27]]^key[19]]^key[11]]^key[ 3]]; + uint32_t Y = MDS0[Q0[Q0[Q1[Q1[i+1]^key[28]]^key[20]]^key[12]]^key[ 4]] ^ + MDS1[Q0[Q1[Q1[Q0[i+1]^key[29]]^key[21]]^key[13]]^key[ 5]] ^ + MDS2[Q1[Q0[Q0[Q0[i+1]^key[30]]^key[22]]^key[14]]^key[ 6]] ^ + MDS3[Q1[Q1[Q0[Q1[i+1]^key[31]]^key[23]]^key[15]]^key[ 7]]; + Y = rotl<8>(Y); + X += Y; Y += X; + + m_RK[i] = X; + m_RK[i+1] = rotl<9>(Y); + } + } + } + +/* +* Clear memory of sensitive data +*/ +void Twofish::clear() + { + zap(m_SB); + zap(m_RK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/twofish/twofish.h b/comm/third_party/botan/src/lib/block/twofish/twofish.h new file mode 100644 index 0000000000..027e2c7011 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/twofish/twofish.h @@ -0,0 +1,47 @@ +/* +* Twofish +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TWOFISH_H_ +#define BOTAN_TWOFISH_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(twofish.h) + +namespace Botan { + +/** +* Twofish, an AES finalist +*/ +class BOTAN_PUBLIC_API(2,0) Twofish final : public Block_Cipher_Fixed_Params<16, 16, 32, 8> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "Twofish"; } + BlockCipher* clone() const override { return new Twofish; } + private: + void key_schedule(const uint8_t[], size_t) override; + + static const uint32_t MDS0[256]; + static const uint32_t MDS1[256]; + static const uint32_t MDS2[256]; + static const uint32_t MDS3[256]; + static const uint8_t Q0[256]; + static const uint8_t Q1[256]; + static const uint8_t RS[32]; + static const uint8_t EXP_TO_POLY[255]; + static const uint8_t POLY_TO_EXP[255]; + + secure_vector m_SB, m_RK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/block/twofish/twofish_tab.cpp b/comm/third_party/botan/src/lib/block/twofish/twofish_tab.cpp new file mode 100644 index 0000000000..acdb35560a --- /dev/null +++ b/comm/third_party/botan/src/lib/block/twofish/twofish_tab.cpp @@ -0,0 +1,293 @@ +/* +* S-Box and MDS Tables for Twofish +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +alignas(64) const uint8_t Twofish::Q0[256] = { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0 }; + +alignas(64) const uint8_t Twofish::Q1[256] = { + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 }; + +alignas(64) const uint8_t Twofish::RS[32] = { + 0x01, 0xA4, 0x02, 0xA4, 0xA4, 0x56, 0xA1, 0x55, 0x55, 0x82, 0xFC, 0x87, + 0x87, 0xF3, 0xC1, 0x5A, 0x5A, 0x1E, 0x47, 0x58, 0x58, 0xC6, 0xAE, 0xDB, + 0xDB, 0x68, 0x3D, 0x9E, 0x9E, 0xE5, 0x19, 0x03 }; + +alignas(64) const uint8_t Twofish::EXP_TO_POLY[255] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2, + 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6, + 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A, + 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63, + 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C, + 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07, + 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88, + 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12, + 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7, + 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C, + 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8, + 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25, + 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A, + 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE, + 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC, + 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E, + 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92, + 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89, + 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB, + 0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1, + 0x8F, 0x53, 0xA6 }; + +alignas(64) const uint8_t Twofish::POLY_TO_EXP[255] = { + 0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19, + 0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A, + 0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C, + 0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B, + 0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47, + 0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D, + 0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8, + 0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C, + 0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83, + 0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48, + 0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26, + 0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E, + 0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3, + 0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9, + 0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A, + 0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D, + 0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75, + 0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84, + 0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64, + 0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49, + 0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF, + 0x85, 0xC8, 0xA1 }; + +alignas(64) const uint32_t Twofish::MDS0[256] = { + 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, + 0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, + 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32, + 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1, + 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, + 0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, + 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1, + 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5, + 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, + 0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, + 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0, + 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796, + 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, + 0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, + 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3, + 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8, + 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, + 0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, + 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C, + 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9, + 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, + 0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, + 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72, + 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E, + 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, + 0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, + 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39, + 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01, + 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, + 0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, + 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5, + 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64, + 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, + 0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, + 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E, + 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E, + 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, + 0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, + 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2, + 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9, + 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, + 0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, + 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91 }; + +alignas(64) const uint32_t Twofish::MDS1[256] = { + 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, + 0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, + 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020, + 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141, + 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, + 0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, + 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A, + 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757, + 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, + 0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, + 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9, + 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656, + 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, + 0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, + 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414, + 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3, + 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, + 0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, + 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5, + 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282, + 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, + 0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, + 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202, + 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC, + 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, + 0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, + 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808, + 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272, + 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, + 0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, + 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505, + 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5, + 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, + 0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, + 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF, + 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3, + 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, + 0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, + 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6, + 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF, + 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, + 0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, + 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8 }; + +alignas(64) const uint32_t Twofish::MDS2[256] = { + 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, + 0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, + 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A, + 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783, + 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, + 0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, + 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB, + 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA, + 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, + 0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, + 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C, + 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07, + 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, + 0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, + 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035, + 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96, + 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, + 0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, + 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F, + 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD, + 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, + 0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, + 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA, + 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85, + 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, + 0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, + 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D, + 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B, + 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, + 0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, + 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086, + 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D, + 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, + 0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, + 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691, + 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D, + 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, + 0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, + 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E, + 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9, + 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, + 0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, + 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF }; + +alignas(64) const uint32_t Twofish::MDS3[256] = { + 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, + 0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, + 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643, + 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77, + 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, + 0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, + 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3, + 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216, + 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, + 0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, + 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF, + 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7, + 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, + 0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, + 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA, + 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C, + 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, + 0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, + 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D, + 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE, + 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, + 0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, + 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B, + 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4, + 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, + 0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, + 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE, + 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB, + 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, + 0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, + 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E, + 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8, + 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, + 0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, + 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718, + 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA, + 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, + 0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, + 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882, + 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D, + 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, + 0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, + 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8 }; + +} diff --git a/comm/third_party/botan/src/lib/block/xtea/info.txt b/comm/third_party/botan/src/lib/block/xtea/info.txt new file mode 100644 index 0000000000..b9b9ad3652 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/xtea/info.txt @@ -0,0 +1,3 @@ + +XTEA -> 20131128 + diff --git a/comm/third_party/botan/src/lib/block/xtea/xtea.cpp b/comm/third_party/botan/src/lib/block/xtea/xtea.cpp new file mode 100644 index 0000000000..7d815529ff --- /dev/null +++ b/comm/third_party/botan/src/lib/block/xtea/xtea.cpp @@ -0,0 +1,134 @@ +/* +* XTEA +* (C) 1999-2009,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* XTEA Encryption +*/ +void XTEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + const uint32_t* EK = &m_EK[0]; + + const size_t blocks4 = blocks / 4; + const size_t blocks_left = blocks % 4; + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; i++) + { + uint32_t L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t r = 0; r != 32; ++r) + { + L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*r]; + L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*r]; + L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*r]; + L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*r]; + + R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*r+1]; + R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*r+1]; + R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*r+1]; + R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*r+1]; + } + + store_be(out + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); + } + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks_left; ++i) + { + uint32_t L, R; + load_be(in + BLOCK_SIZE*(4*blocks4+i), L, R); + + for(size_t r = 0; r != 32; ++r) + { + L += (((R << 4) ^ (R >> 5)) + R) ^ EK[2*r]; + R += (((L << 4) ^ (L >> 5)) + L) ^ EK[2*r+1]; + } + + store_be(out + BLOCK_SIZE*(4*blocks4+i), L, R); + } + } + +/* +* XTEA Decryption +*/ +void XTEA::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + + const uint32_t* EK = &m_EK[0]; + + const size_t blocks4 = blocks / 4; + const size_t blocks_left = blocks % 4; + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; i++) + { + uint32_t L0, R0, L1, R1, L2, R2, L3, R3; + load_be(in + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); + + for(size_t r = 0; r != 32; ++r) + { + R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*r]; + R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*r]; + R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*r]; + R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*r]; + + L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*r]; + L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*r]; + L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*r]; + L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*r]; + } + + store_be(out + 4*BLOCK_SIZE*i, L0, R0, L1, R1, L2, R2, L3, R3); + } + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks_left; ++i) + { + uint32_t L, R; + load_be(in + BLOCK_SIZE*(4*blocks4+i), L, R); + + for(size_t r = 0; r != 32; ++r) + { + R -= (((L << 4) ^ (L >> 5)) + L) ^ m_EK[63 - 2*r]; + L -= (((R << 4) ^ (R >> 5)) + R) ^ m_EK[62 - 2*r]; + } + + store_be(out + BLOCK_SIZE*(4*blocks4+i), L, R); + } + } + +/* +* XTEA Key Schedule +*/ +void XTEA::key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(64); + + secure_vector UK(4); + for(size_t i = 0; i != 4; ++i) + UK[i] = load_be(key, i); + + uint32_t D = 0; + for(size_t i = 0; i != 64; i += 2) + { + m_EK[i ] = D + UK[D % 4]; + D += 0x9E3779B9; + m_EK[i+1] = D + UK[(D >> 11) % 4]; + } + } + +void XTEA::clear() + { + zap(m_EK); + } + +} diff --git a/comm/third_party/botan/src/lib/block/xtea/xtea.h b/comm/third_party/botan/src/lib/block/xtea/xtea.h new file mode 100644 index 0000000000..bae0bc7e63 --- /dev/null +++ b/comm/third_party/botan/src/lib/block/xtea/xtea.h @@ -0,0 +1,37 @@ +/* +* XTEA +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_XTEA_H_ +#define BOTAN_XTEA_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(xtea.h) + +namespace Botan { + +/** +* XTEA +*/ +class BOTAN_PUBLIC_API(2,0) XTEA final : public Block_Cipher_Fixed_Params<8, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "XTEA"; } + BlockCipher* clone() const override { return new XTEA; } + + private: + void key_schedule(const uint8_t[], size_t) override; + secure_vector m_EK; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/codec/base32/base32.cpp b/comm/third_party/botan/src/lib/codec/base32/base32.cpp new file mode 100644 index 0000000000..224dae9916 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base32/base32.cpp @@ -0,0 +1,233 @@ +/* +* Base32 Encoding and Decoding +* (C) 2018 Erwan Chaussy +* (C) 2018,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class Base32 final + { + public: + static inline std::string name() noexcept + { + return "base32"; + } + + static inline size_t encoding_bytes_in() noexcept + { + return m_encoding_bytes_in; + } + static inline size_t encoding_bytes_out() noexcept + { + return m_encoding_bytes_out; + } + + static inline size_t decoding_bytes_in() noexcept + { + return m_encoding_bytes_out; + } + static inline size_t decoding_bytes_out() noexcept + { + return m_encoding_bytes_in; + } + + static inline size_t bits_consumed() noexcept + { + return m_encoding_bits; + } + static inline size_t remaining_bits_before_padding() noexcept + { + return m_remaining_bits_before_padding; + } + + static inline size_t encode_max_output(size_t input_length) + { + return (round_up(input_length, m_encoding_bytes_in) / m_encoding_bytes_in) * m_encoding_bytes_out; + } + static inline size_t decode_max_output(size_t input_length) + { + return (round_up(input_length, m_encoding_bytes_out) * m_encoding_bytes_in) / m_encoding_bytes_out; + } + + static void encode(char out[8], const uint8_t in[5]) noexcept; + + static uint8_t lookup_binary_value(char input) noexcept; + + static bool check_bad_char(uint8_t bin, char input, bool ignore_ws); + + static void decode(uint8_t* out_ptr, const uint8_t decode_buf[8]) + { + out_ptr[0] = (decode_buf[0] << 3) | (decode_buf[1] >> 2); + out_ptr[1] = (decode_buf[1] << 6) | (decode_buf[2] << 1) | (decode_buf[3] >> 4); + out_ptr[2] = (decode_buf[3] << 4) | (decode_buf[4] >> 1); + out_ptr[3] = (decode_buf[4] << 7) | (decode_buf[5] << 2) | (decode_buf[6] >> 3); + out_ptr[4] = (decode_buf[6] << 5) | decode_buf[7]; + } + + static inline size_t bytes_to_remove(size_t final_truncate) + { + return final_truncate ? (final_truncate / 2) + 1 : 0; + } + + private: + static const size_t m_encoding_bits = 5; + static const size_t m_remaining_bits_before_padding = 6; + + static const size_t m_encoding_bytes_in = 5; + static const size_t m_encoding_bytes_out = 8; + }; + +namespace { + +char lookup_base32_char(uint8_t x) + { + BOTAN_DEBUG_ASSERT(x < 32); + + const auto in_AZ = CT::Mask::is_lt(x, 26); + + const char c_AZ = 'A' + x; + const char c_27 = '2' + (x - 26); + + return in_AZ.select(c_AZ, c_27); + } + +} + +//static +void Base32::encode(char out[8], const uint8_t in[5]) noexcept + { + const uint8_t b0 = (in[0] & 0xF8) >> 3; + const uint8_t b1 = ((in[0] & 0x07) << 2) | (in[1] >> 6); + const uint8_t b2 = ((in[1] & 0x3E) >> 1); + const uint8_t b3 = ((in[1] & 0x01) << 4) | (in[2] >> 4); + const uint8_t b4 = ((in[2] & 0x0F) << 1) | (in[3] >> 7); + const uint8_t b5 = ((in[3] & 0x7C) >> 2); + const uint8_t b6 = ((in[3] & 0x03) << 3) | (in[4] >> 5); + const uint8_t b7 = in[4] & 0x1F; + + out[0] = lookup_base32_char(b0); + out[1] = lookup_base32_char(b1); + out[2] = lookup_base32_char(b2); + out[3] = lookup_base32_char(b3); + out[4] = lookup_base32_char(b4); + out[5] = lookup_base32_char(b5); + out[6] = lookup_base32_char(b6); + out[7] = lookup_base32_char(b7); + } + +//static +uint8_t Base32::lookup_binary_value(char input) noexcept + { + const uint8_t c = static_cast(input); + + const auto is_alpha_upper = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('Z')); + const auto is_decimal = CT::Mask::is_within_range(c, uint8_t('2'), uint8_t('7')); + + const auto is_equal = CT::Mask::is_equal(c, uint8_t('=')); + const auto is_whitespace = CT::Mask::is_any_of(c, { + uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') + }); + + const uint8_t c_upper = c - uint8_t('A'); + const uint8_t c_decim = c - uint8_t('2') + 26; + + uint8_t ret = 0xFF; // default value + + ret = is_alpha_upper.select(c_upper, ret); + ret = is_decimal.select(c_decim, ret); + ret = is_equal.select(0x81, ret); + ret = is_whitespace.select(0x80, ret); + + return ret; + } + +//static +bool Base32::check_bad_char(uint8_t bin, char input, bool ignore_ws) + { + if(bin <= 0x1F) + { + return true; + } + else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) + { + std::string bad_char(1, input); + if(bad_char == "\t") + { bad_char = "\\t"; } + else if(bad_char == "\n") + { bad_char = "\\n"; } + else if(bad_char == "\r") + { bad_char = "\\r"; } + + throw Invalid_Argument( + std::string("base32_decode: invalid base32 character '") + + bad_char + "'"); + } + return false; + } + +} + +size_t base32_encode(char out[], + const uint8_t in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + return base_encode(Base32(), out, in, input_length, input_consumed, final_inputs); + } + +std::string base32_encode(const uint8_t input[], + size_t input_length) + { + return base_encode_to_string(Base32(), input, input_length); + } + +size_t base32_decode(uint8_t out[], + const char in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws) + { + return base_decode(Base32(), out, in, input_length, input_consumed, final_inputs, ignore_ws); + } + +size_t base32_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + return base_decode_full(Base32(), output, input, input_length, ignore_ws); + } + +size_t base32_decode(uint8_t output[], + const std::string& input, + bool ignore_ws) + { + return base32_decode(output, input.data(), input.length(), ignore_ws); + } + +secure_vector base32_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + return base_decode_to_vec>(Base32(), input, input_length, ignore_ws); + } + +secure_vector base32_decode(const std::string& input, + bool ignore_ws) + { + return base32_decode(input.data(), input.size(), ignore_ws); + } + +} diff --git a/comm/third_party/botan/src/lib/codec/base32/base32.h b/comm/third_party/botan/src/lib/codec/base32/base32.h new file mode 100644 index 0000000000..d2bcb3e6ab --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base32/base32.h @@ -0,0 +1,127 @@ +/* +* Base32 Encoding and Decoding +* (C) 2018 Erwan Chaussy +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE32_CODEC_H_ +#define BOTAN_BASE32_CODEC_H_ + +#include +#include + +namespace Botan { + +/** +* Perform base32 encoding +* @param output an array of at least base32_encode_max_output bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2, 7) base32_encode(char output[], + const uint8_t input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs); + +/** +* Perform base32 encoding +* @param input some input +* @param input_length length of input in bytes +* @return base32 representation of input +*/ +std::string BOTAN_PUBLIC_API(2, 7) base32_encode(const uint8_t input[], + size_t input_length); + +/** +* Perform base32 encoding +* @param input some input +* @return base32 representation of input +*/ +template +std::string base32_encode(const std::vector& input) + { + return base32_encode(input.data(), input.size()); + } + +/** +* Perform base32 decoding +* @param output an array of at least base32_decode_max_output bytes +* @param input some base32 input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2, 7) base32_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true); + +/** +* Perform base32 decoding +* @param output an array of at least base32_decode_max_output bytes +* @param input some base32 input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2, 7) base32_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base32 decoding +* @param output an array of at least base32_decode_max_output bytes +* @param input some base32 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2, 7) base32_decode(uint8_t output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform base32 decoding +* @param input some base32 input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base32 output +*/ +secure_vector BOTAN_PUBLIC_API(2, 7) base32_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base32 decoding +* @param input some base32 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base32 output +*/ +secure_vector BOTAN_PUBLIC_API(2, 7) base32_decode(const std::string& input, + bool ignore_ws = true); + +} // namespace Botan + +#endif diff --git a/comm/third_party/botan/src/lib/codec/base32/info.txt b/comm/third_party/botan/src/lib/codec/base32/info.txt new file mode 100644 index 0000000000..8e414c5a33 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base32/info.txt @@ -0,0 +1,3 @@ + +BASE32_CODEC -> 20180418 + diff --git a/comm/third_party/botan/src/lib/codec/base58/base58.cpp b/comm/third_party/botan/src/lib/codec/base58/base58.cpp new file mode 100644 index 0000000000..a6d509012d --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base58/base58.cpp @@ -0,0 +1,189 @@ +/* +* (C) 2018,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +uint32_t sha256_d_checksum(const uint8_t input[], size_t input_length) + { + std::unique_ptr sha256 = HashFunction::create_or_throw("SHA-256"); + + std::vector checksum(32); + + sha256->update(input, input_length); + sha256->final(checksum); + + sha256->update(checksum); + sha256->final(checksum); + + return load_be(checksum.data(), 0); + } + +char lookup_base58_char(uint8_t x) + { + // "123456789 ABCDEFGH JKLMN PQRSTUVWXYZ abcdefghijk mnopqrstuvwxyz" + BOTAN_DEBUG_ASSERT(x < 58); + + const auto is_dec_19 = CT::Mask::is_lte(x, 8); + const auto is_alpha_AH = CT::Mask::is_within_range(x, 9, 16); + const auto is_alpha_JN = CT::Mask::is_within_range(x, 17, 21); + const auto is_alpha_PZ = CT::Mask::is_within_range(x, 22, 32); + const auto is_alpha_ak = CT::Mask::is_within_range(x, 33, 43); + // otherwise in 'm'-'z' + + const char c_19 = '1' + x; + const char c_AH = 'A' + (x - 9); + const char c_JN = 'J' + (x - 17); + const char c_PZ = 'P' + (x - 22); + const char c_ak = 'a' + (x - 33); + const char c_mz = 'm' + (x - 44); + + char ret = c_mz; + ret = is_dec_19.select(c_19, ret); + ret = is_alpha_AH.select(c_AH, ret); + ret = is_alpha_JN.select(c_JN, ret); + ret = is_alpha_PZ.select(c_PZ, ret); + ret = is_alpha_ak.select(c_ak, ret); + + return ret; + } + +std::string base58_encode(BigInt v, size_t leading_zeros) + { + const uint8_t radix = 58; + + std::string result; + BigInt q; + + while(v.is_nonzero()) + { + uint8_t r; + ct_divide_u8(v, radix, q, r); + result.push_back(lookup_base58_char(r)); + v.swap(q); + } + + for(size_t i = 0; i != leading_zeros; ++i) + result.push_back('1'); // 'zero' byte + + return std::string(result.rbegin(), result.rend()); + } + +template +size_t count_leading_zeros(const T input[], size_t input_length, Z zero) + { + size_t leading_zeros = 0; + + while(leading_zeros < input_length && input[leading_zeros] == zero) + leading_zeros += 1; + + return leading_zeros; + } + +uint8_t base58_value_of(char input) + { + // "123456789 ABCDEFGH JKLMN PQRSTUVWXYZ abcdefghijk mnopqrstuvwxyz" + + const uint8_t c = static_cast(input); + + const auto is_dec_19 = CT::Mask::is_within_range(c, uint8_t('1'), uint8_t('9')); + const auto is_alpha_AH = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('H')); + const auto is_alpha_JN = CT::Mask::is_within_range(c, uint8_t('J'), uint8_t('N')); + const auto is_alpha_PZ = CT::Mask::is_within_range(c, uint8_t('P'), uint8_t('Z')); + + const auto is_alpha_ak = CT::Mask::is_within_range(c, uint8_t('a'), uint8_t('k')); + const auto is_alpha_mz = CT::Mask::is_within_range(c, uint8_t('m'), uint8_t('z')); + + const uint8_t c_dec_19 = c - uint8_t('1'); + const uint8_t c_AH = c - uint8_t('A') + 9; + const uint8_t c_JN = c - uint8_t('J') + 17; + const uint8_t c_PZ = c - uint8_t('P') + 22; + + const uint8_t c_ak = c - uint8_t('a') + 33; + const uint8_t c_mz = c - uint8_t('m') + 44; + + uint8_t ret = 0xFF; // default value + + ret = is_dec_19.select(c_dec_19, ret); + ret = is_alpha_AH.select(c_AH, ret); + ret = is_alpha_JN.select(c_JN, ret); + ret = is_alpha_PZ.select(c_PZ, ret); + ret = is_alpha_ak.select(c_ak, ret); + ret = is_alpha_mz.select(c_mz, ret); + return ret; + } + +} + +std::string base58_encode(const uint8_t input[], size_t input_length) + { + BigInt v(input, input_length); + return base58_encode(v, count_leading_zeros(input, input_length, 0)); + } + +std::string base58_check_encode(const uint8_t input[], size_t input_length) + { + BigInt v(input, input_length); + v <<= 32; + v += sha256_d_checksum(input, input_length); + return base58_encode(v, count_leading_zeros(input, input_length, 0)); + } + +std::vector base58_decode(const char input[], size_t input_length) + { + const size_t leading_zeros = count_leading_zeros(input, input_length, '1'); + + BigInt v; + + for(size_t i = leading_zeros; i != input_length; ++i) + { + const char c = input[i]; + + if(c == ' ' || c == '\n') + continue; + + const uint8_t idx = base58_value_of(c); + + if(idx == 0xFF) + throw Decoding_Error("Invalid base58"); + + v *= 58; + v += idx; + } + + std::vector output(v.bytes() + leading_zeros); + v.binary_encode(output.data() + leading_zeros); + return output; + } + +std::vector base58_check_decode(const char input[], size_t input_length) + { + std::vector dec = base58_decode(input, input_length); + + if(dec.size() < 4) + throw Decoding_Error("Invalid base58 too short for checksum"); + + const uint32_t computed_checksum = sha256_d_checksum(dec.data(), dec.size() - 4); + const uint32_t checksum = load_be(&dec[dec.size()-4], 0); + + if(checksum != computed_checksum) + throw Decoding_Error("Invalid base58 checksum"); + + dec.resize(dec.size() - 4); + + return dec; + } + +} diff --git a/comm/third_party/botan/src/lib/codec/base58/base58.h b/comm/third_party/botan/src/lib/codec/base58/base58.h new file mode 100644 index 0000000000..4654a0557c --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base58/base58.h @@ -0,0 +1,76 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE58_CODEC_H_ +#define BOTAN_BASE58_CODEC_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Perform base58 encoding +* +* This is raw base58 encoding, without the checksum +*/ +std::string +BOTAN_PUBLIC_API(2,9) base58_encode(const uint8_t input[], + size_t input_length); + +/** +* Perform base58 encoding with checksum +*/ +std::string +BOTAN_PUBLIC_API(2,9) base58_check_encode(const uint8_t input[], + size_t input_length); + + +/** +* Perform base58 decoding +* +* This is raw base58 encoding, without the checksum +*/ +std::vector +BOTAN_PUBLIC_API(2,9) base58_decode(const char input[], + size_t input_length); + +/** +* Perform base58 decoding with checksum +*/ +std::vector +BOTAN_PUBLIC_API(2,9) base58_check_decode(const char input[], + size_t input_length); + + +// Some convenience wrappers: + +template +inline std::string base58_encode(const std::vector& vec) + { + return base58_encode(vec.data(), vec.size()); + } + +template +inline std::string base58_check_encode(const std::vector& vec) + { + return base58_check_encode(vec.data(), vec.size()); + } + +inline std::vector base58_decode(const std::string& s) + { + return base58_decode(s.data(), s.size()); + } + +inline std::vector base58_check_decode(const std::string& s) + { + return base58_check_decode(s.data(), s.size()); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/codec/base58/info.txt b/comm/third_party/botan/src/lib/codec/base58/info.txt new file mode 100644 index 0000000000..0b09c016d0 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base58/info.txt @@ -0,0 +1,8 @@ + +BASE58_CODEC -> 20181209 + + + +sha2_32 +bigint + diff --git a/comm/third_party/botan/src/lib/codec/base64/base64.cpp b/comm/third_party/botan/src/lib/codec/base64/base64.cpp new file mode 100644 index 0000000000..93675f0e34 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base64/base64.cpp @@ -0,0 +1,248 @@ +/* +* Base64 Encoding and Decoding +* (C) 2010,2015,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class Base64 final + { + public: + static inline std::string name() noexcept + { + return "base64"; + } + + static inline size_t encoding_bytes_in() noexcept + { + return m_encoding_bytes_in; + } + static inline size_t encoding_bytes_out() noexcept + { + return m_encoding_bytes_out; + } + + static inline size_t decoding_bytes_in() noexcept + { + return m_encoding_bytes_out; + } + static inline size_t decoding_bytes_out() noexcept + { + return m_encoding_bytes_in; + } + + static inline size_t bits_consumed() noexcept + { + return m_encoding_bits; + } + static inline size_t remaining_bits_before_padding() noexcept + { + return m_remaining_bits_before_padding; + } + + static inline size_t encode_max_output(size_t input_length) + { + return (round_up(input_length, m_encoding_bytes_in) / m_encoding_bytes_in) * m_encoding_bytes_out; + } + static inline size_t decode_max_output(size_t input_length) + { + return (round_up(input_length, m_encoding_bytes_out) * m_encoding_bytes_in) / m_encoding_bytes_out; + } + + static void encode(char out[8], const uint8_t in[5]) noexcept; + + static uint8_t lookup_binary_value(char input) noexcept; + + static bool check_bad_char(uint8_t bin, char input, bool ignore_ws); + + static void decode(uint8_t* out_ptr, const uint8_t decode_buf[4]) + { + out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); + out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); + out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; + } + + static inline size_t bytes_to_remove(size_t final_truncate) + { + return final_truncate; + } + + private: + static const size_t m_encoding_bits = 6; + static const size_t m_remaining_bits_before_padding = 8; + + static const size_t m_encoding_bytes_in = 3; + static const size_t m_encoding_bytes_out = 4; + }; + +char lookup_base64_char(uint8_t x) + { + BOTAN_DEBUG_ASSERT(x < 64); + + const auto in_az = CT::Mask::is_within_range(x, 26, 51); + const auto in_09 = CT::Mask::is_within_range(x, 52, 61); + const auto eq_plus = CT::Mask::is_equal(x, 62); + const auto eq_slash = CT::Mask::is_equal(x, 63); + + const char c_AZ = 'A' + x; + const char c_az = 'a' + (x - 26); + const char c_09 = '0' + (x - 2*26); + const char c_plus = '+'; + const char c_slash = '/'; + + char ret = c_AZ; + ret = in_az.select(c_az, ret); + ret = in_09.select(c_09, ret); + ret = eq_plus.select(c_plus, ret); + ret = eq_slash.select(c_slash, ret); + + return ret; + } + +//static +void Base64::encode(char out[8], const uint8_t in[5]) noexcept + { + const uint8_t b0 = (in[0] & 0xFC) >> 2; + const uint8_t b1 = ((in[0] & 0x03) << 4) | (in[1] >> 4); + const uint8_t b2 = ((in[1] & 0x0F) << 2) | (in[2] >> 6); + const uint8_t b3 = in[2] & 0x3F; + out[0] = lookup_base64_char(b0); + out[1] = lookup_base64_char(b1); + out[2] = lookup_base64_char(b2); + out[3] = lookup_base64_char(b3); + } + +//static +uint8_t Base64::lookup_binary_value(char input) noexcept + { + const uint8_t c = static_cast(input); + + const auto is_alpha_upper = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('Z')); + const auto is_alpha_lower = CT::Mask::is_within_range(c, uint8_t('a'), uint8_t('z')); + const auto is_decimal = CT::Mask::is_within_range(c, uint8_t('0'), uint8_t('9')); + + const auto is_plus = CT::Mask::is_equal(c, uint8_t('+')); + const auto is_slash = CT::Mask::is_equal(c, uint8_t('/')); + const auto is_equal = CT::Mask::is_equal(c, uint8_t('=')); + + const auto is_whitespace = CT::Mask::is_any_of(c, { + uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') + }); + + const uint8_t c_upper = c - uint8_t('A'); + const uint8_t c_lower = c - uint8_t('a') + 26; + const uint8_t c_decim = c - uint8_t('0') + 2*26; + + uint8_t ret = 0xFF; // default value + + ret = is_alpha_upper.select(c_upper, ret); + ret = is_alpha_lower.select(c_lower, ret); + ret = is_decimal.select(c_decim, ret); + ret = is_plus.select(62, ret); + ret = is_slash.select(63, ret); + ret = is_equal.select(0x81, ret); + ret = is_whitespace.select(0x80, ret); + + return ret; + } + +//static +bool Base64::check_bad_char(uint8_t bin, char input, bool ignore_ws) + { + if(bin <= 0x3F) + { + return true; + } + else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) + { + std::string bad_char(1, input); + if(bad_char == "\t") + { bad_char = "\\t"; } + else if(bad_char == "\n") + { bad_char = "\\n"; } + else if(bad_char == "\r") + { bad_char = "\\r"; } + + throw Invalid_Argument( + std::string("base64_decode: invalid base64 character '") + + bad_char + "'"); + } + return false; + } + +} + +size_t base64_encode(char out[], + const uint8_t in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + return base_encode(Base64(), out, in, input_length, input_consumed, final_inputs); + } + +std::string base64_encode(const uint8_t input[], + size_t input_length) + { + return base_encode_to_string(Base64(), input, input_length); + } + +size_t base64_decode(uint8_t out[], + const char in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws) + { + return base_decode(Base64(), out, in, input_length, input_consumed, final_inputs, ignore_ws); + } + +size_t base64_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + return base_decode_full(Base64(), output, input, input_length, ignore_ws); + } + +size_t base64_decode(uint8_t output[], + const std::string& input, + bool ignore_ws) + { + return base64_decode(output, input.data(), input.length(), ignore_ws); + } + +secure_vector base64_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + return base_decode_to_vec>(Base64(), input, input_length, ignore_ws); + } + +secure_vector base64_decode(const std::string& input, + bool ignore_ws) + { + return base64_decode(input.data(), input.size(), ignore_ws); + } + +size_t base64_encode_max_output(size_t input_length) + { + return Base64::encode_max_output(input_length); + } + +size_t base64_decode_max_output(size_t input_length) + { + return Base64::decode_max_output(input_length); + } + +} diff --git a/comm/third_party/botan/src/lib/codec/base64/base64.h b/comm/third_party/botan/src/lib/codec/base64/base64.h new file mode 100644 index 0000000000..a20d03b0f7 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base64/base64.h @@ -0,0 +1,141 @@ +/* +* Base64 Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE64_CODEC_H_ +#define BOTAN_BASE64_CODEC_H_ + +#include +#include + +namespace Botan { + +/** +* Perform base64 encoding +* @param output an array of at least base64_encode_max_output bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_encode(char output[], + const uint8_t input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs); + +/** +* Perform base64 encoding +* @param input some input +* @param input_length length of input in bytes +* @return base64adecimal representation of input +*/ +std::string BOTAN_PUBLIC_API(2,0) base64_encode(const uint8_t input[], + size_t input_length); + +/** +* Perform base64 encoding +* @param input some input +* @return base64adecimal representation of input +*/ +template +std::string base64_encode(const std::vector& input) + { + return base64_encode(input.data(), input.size()); + } + +/** +* Perform base64 decoding +* @param output an array of at least base64_decode_max_output bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least base64_decode_max_output bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least base64_decode_max_output bytes +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_decode(uint8_t output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +secure_vector BOTAN_PUBLIC_API(2,0) base64_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +secure_vector BOTAN_PUBLIC_API(2,0) base64_decode(const std::string& input, + bool ignore_ws = true); + +/** +* Calculate the size of output buffer for base64_encode +* @param input_length the length of input in bytes +* @return the size of output buffer in bytes +*/ +size_t BOTAN_PUBLIC_API(2,1) base64_encode_max_output(size_t input_length); + +/** +* Calculate the size of output buffer for base64_decode +* @param input_length the length of input in bytes +* @return the size of output buffer in bytes +*/ +size_t BOTAN_PUBLIC_API(2,1) base64_decode_max_output(size_t input_length); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/codec/base64/info.txt b/comm/third_party/botan/src/lib/codec/base64/info.txt new file mode 100644 index 0000000000..ceed636053 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/base64/info.txt @@ -0,0 +1,3 @@ + +BASE64_CODEC -> 20131128 + diff --git a/comm/third_party/botan/src/lib/codec/hex/hex.cpp b/comm/third_party/botan/src/lib/codec/hex/hex.cpp new file mode 100644 index 0000000000..1ae21f398b --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/hex/hex.cpp @@ -0,0 +1,210 @@ +/* +* Hex Encoding and Decoding +* (C) 2010,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +char hex_encode_nibble(uint8_t n, bool uppercase) + { + BOTAN_DEBUG_ASSERT(n <= 15); + + const auto in_09 = CT::Mask::is_lt(n, 10); + + const char c_09 = n + '0'; + const char c_af = n + (uppercase ? 'A' : 'a') - 10; + + return in_09.select(c_09, c_af); + } + +} + +void hex_encode(char output[], + const uint8_t input[], + size_t input_length, + bool uppercase) + { + for(size_t i = 0; i != input_length; ++i) + { + const uint8_t n0 = (input[i] >> 4) & 0xF; + const uint8_t n1 = (input[i] ) & 0xF; + + output[2*i ] = hex_encode_nibble(n0, uppercase); + output[2*i+1] = hex_encode_nibble(n1, uppercase); + } + } + +std::string hex_encode(const uint8_t input[], + size_t input_length, + bool uppercase) + { + std::string output(2 * input_length, 0); + + if(input_length) + hex_encode(&output.front(), input, input_length, uppercase); + + return output; + } + +namespace { + +uint8_t hex_char_to_bin(char input) + { + const uint8_t c = static_cast(input); + + const auto is_alpha_upper = CT::Mask::is_within_range(c, uint8_t('A'), uint8_t('F')); + const auto is_alpha_lower = CT::Mask::is_within_range(c, uint8_t('a'), uint8_t('f')); + const auto is_decimal = CT::Mask::is_within_range(c, uint8_t('0'), uint8_t('9')); + + const auto is_whitespace = CT::Mask::is_any_of(c, { + uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r') + }); + + const uint8_t c_upper = c - uint8_t('A') + 10; + const uint8_t c_lower = c - uint8_t('a') + 10; + const uint8_t c_decim = c - uint8_t('0'); + + uint8_t ret = 0xFF; // default value + + ret = is_alpha_upper.select(c_upper, ret); + ret = is_alpha_lower.select(c_lower, ret); + ret = is_decimal.select(c_decim, ret); + ret = is_whitespace.select(0x80, ret); + + return ret; + } + +} + + +size_t hex_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws) + { + uint8_t* out_ptr = output; + bool top_nibble = true; + + clear_mem(output, input_length / 2); + + for(size_t i = 0; i != input_length; ++i) + { + const uint8_t bin = hex_char_to_bin(input[i]); + + if(bin >= 0x10) + { + if(bin == 0x80 && ignore_ws) + continue; + + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + + throw Invalid_Argument( + std::string("hex_decode: invalid hex character '") + + bad_char + "'"); + } + + if(top_nibble) + *out_ptr |= bin << 4; + else + *out_ptr |= bin; + + top_nibble = !top_nibble; + if(top_nibble) + ++out_ptr; + } + + input_consumed = input_length; + size_t written = (out_ptr - output); + + /* + * We only got half of a uint8_t at the end; zap the half-written + * output and mark it as unread + */ + if(!top_nibble) + { + *out_ptr = 0; + input_consumed -= 1; + } + + return written; + } + +size_t hex_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = hex_decode(output, input, input_length, + consumed, ignore_ws); + + if(consumed != input_length) + throw Invalid_Argument("hex_decode: input did not have full bytes"); + + return written; + } + +size_t hex_decode(uint8_t output[], + const std::string& input, + bool ignore_ws) + { + return hex_decode(output, input.data(), input.length(), ignore_ws); + } + +secure_vector hex_decode_locked(const char input[], + size_t input_length, + bool ignore_ws) + { + secure_vector bin(1 + input_length / 2); + + size_t written = hex_decode(bin.data(), + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +secure_vector hex_decode_locked(const std::string& input, + bool ignore_ws) + { + return hex_decode_locked(input.data(), input.size(), ignore_ws); + } + +std::vector hex_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + std::vector bin(1 + input_length / 2); + + size_t written = hex_decode(bin.data(), + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +std::vector hex_decode(const std::string& input, + bool ignore_ws) + { + return hex_decode(input.data(), input.size(), ignore_ws); + } + +} diff --git a/comm/third_party/botan/src/lib/codec/hex/hex.h b/comm/third_party/botan/src/lib/codec/hex/hex.h new file mode 100644 index 0000000000..330d8a69a5 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/hex/hex.h @@ -0,0 +1,148 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HEX_CODEC_H_ +#define BOTAN_HEX_CODEC_H_ + +#include +#include + +namespace Botan { + +/** +* Perform hex encoding +* @param output an array of at least input_length*2 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +*/ +void BOTAN_PUBLIC_API(2,0) hex_encode(char output[], + const uint8_t input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +std::string BOTAN_PUBLIC_API(2,0) hex_encode(const uint8_t input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +template +std::string hex_encode(const std::vector& input, + bool uppercase = true) + { + return hex_encode(input.data(), input.size(), uppercase); + } + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) hex_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) hex_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) hex_decode(uint8_t output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +std::vector BOTAN_PUBLIC_API(2,0) +hex_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +std::vector BOTAN_PUBLIC_API(2,0) +hex_decode(const std::string& input, + bool ignore_ws = true); + + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +secure_vector BOTAN_PUBLIC_API(2,0) +hex_decode_locked(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +secure_vector BOTAN_PUBLIC_API(2,0) +hex_decode_locked(const std::string& input, + bool ignore_ws = true); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/codec/hex/info.txt b/comm/third_party/botan/src/lib/codec/hex/info.txt new file mode 100644 index 0000000000..6ee27e57c2 --- /dev/null +++ b/comm/third_party/botan/src/lib/codec/hex/info.txt @@ -0,0 +1,3 @@ + +HEX_CODEC -> 20131128 + diff --git a/comm/third_party/botan/src/lib/compat/sodium/info.txt b/comm/third_party/botan/src/lib/compat/sodium/info.txt new file mode 100644 index 0000000000..4adc853d9a --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/info.txt @@ -0,0 +1,17 @@ + +SODIUM_API -> 20190615 + + + +chacha +salsa20 +poly1305 +chacha20poly1305 +curve25519 +ed25519 +sha2_32 +sha2_64 +hmac +siphash +system_rng + diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium.h b/comm/third_party/botan/src/lib/compat/sodium/sodium.h new file mode 100644 index 0000000000..821fd4f5d0 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium.h @@ -0,0 +1,1453 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SODIUM_COMPAT_H_ +#define BOTAN_SODIUM_COMPAT_H_ + +#include + +namespace Botan { + +/** +* The Sodium namespace contains a partial implementation of the +* libsodium API. +*/ +namespace Sodium { + +// sodium/randombytes.h +enum Sodium_Constants : size_t { + SODIUM_SIZE_MAX = 0xFFFFFFFF, + + crypto_aead_chacha20poly1305_ABYTES = 16, + crypto_aead_chacha20poly1305_KEYBYTES = 32, + crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_aead_chacha20poly1305_NPUBBYTES = 8, + crypto_aead_chacha20poly1305_NSECBYTES = 0, + + crypto_aead_chacha20poly1305_ietf_ABYTES = 16, + crypto_aead_chacha20poly1305_ietf_KEYBYTES = 32, + crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_aead_chacha20poly1305_ietf_NPUBBYTES = 12, + crypto_aead_chacha20poly1305_ietf_NSECBYTES = 0, + + crypto_aead_xchacha20poly1305_ietf_ABYTES = 16, + crypto_aead_xchacha20poly1305_ietf_KEYBYTES = 32, + crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES = 24, + crypto_aead_xchacha20poly1305_ietf_NSECBYTES = 0, + + crypto_auth_hmacsha256_BYTES = 32, + crypto_auth_hmacsha256_KEYBYTES = 32, + crypto_auth_hmacsha512256_BYTES = 32, + crypto_auth_hmacsha512256_KEYBYTES = 32, + crypto_auth_hmacsha512_BYTES = 64, + crypto_auth_hmacsha512_KEYBYTES = 32, + + crypto_auth_BYTES = crypto_auth_hmacsha512256_BYTES, + crypto_auth_KEYBYTES = crypto_auth_hmacsha512256_KEYBYTES, + + crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32, + crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16, + crypto_box_curve25519xsalsa20poly1305_MACBYTES = 16, + crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_box_curve25519xsalsa20poly1305_NONCEBYTES = 24, + crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32, + crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32, + crypto_box_curve25519xsalsa20poly1305_SEEDBYTES = 32, + crypto_box_curve25519xsalsa20poly1305_ZEROBYTES = crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES + crypto_box_curve25519xsalsa20poly1305_MACBYTES, + + crypto_box_BEFORENMBYTES = crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES, + crypto_box_BOXZEROBYTES = crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES, + crypto_box_MACBYTES = crypto_box_curve25519xsalsa20poly1305_MACBYTES, + crypto_box_MESSAGEBYTES_MAX = crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX, + crypto_box_NONCEBYTES = crypto_box_curve25519xsalsa20poly1305_NONCEBYTES, + crypto_box_PUBLICKEYBYTES = crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES, + crypto_box_SECRETKEYBYTES = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES, + crypto_box_SEEDBYTES = crypto_box_curve25519xsalsa20poly1305_SEEDBYTES, + crypto_box_ZEROBYTES = crypto_box_curve25519xsalsa20poly1305_ZEROBYTES, + + crypto_core_hchacha20_CONSTBYTES = 16, + crypto_core_hchacha20_INPUTBYTES = 16, + crypto_core_hchacha20_KEYBYTES = 32, + crypto_core_hchacha20_OUTPUTBYTES = 32, + + crypto_core_hsalsa20_CONSTBYTES = 16, + crypto_core_hsalsa20_INPUTBYTES = 16, + crypto_core_hsalsa20_KEYBYTES = 32, + crypto_core_hsalsa20_OUTPUTBYTES = 32, + + crypto_hash_sha256_BYTES = 32, + crypto_hash_sha512_BYTES = 64, + crypto_hash_BYTES = crypto_hash_sha512_BYTES, + + crypto_onetimeauth_poly1305_BYTES = 16, + crypto_onetimeauth_poly1305_KEYBYTES = 32, + crypto_onetimeauth_BYTES = crypto_onetimeauth_poly1305_BYTES, + crypto_onetimeauth_KEYBYTES = crypto_onetimeauth_poly1305_KEYBYTES, + + crypto_scalarmult_curve25519_BYTES = 32, + crypto_scalarmult_curve25519_SCALARBYTES = 32, + crypto_scalarmult_BYTES = crypto_scalarmult_curve25519_BYTES, + crypto_scalarmult_SCALARBYTES = crypto_scalarmult_curve25519_SCALARBYTES, + + crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES = 16, + crypto_secretbox_xsalsa20poly1305_KEYBYTES = 32, + crypto_secretbox_xsalsa20poly1305_MACBYTES = 16, + crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_secretbox_xsalsa20poly1305_NONCEBYTES = 24, + crypto_secretbox_xsalsa20poly1305_ZEROBYTES = crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES + crypto_secretbox_xsalsa20poly1305_MACBYTES, + + crypto_secretbox_BOXZEROBYTES = crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES, + crypto_secretbox_KEYBYTES = crypto_secretbox_xsalsa20poly1305_KEYBYTES, + crypto_secretbox_MACBYTES = crypto_secretbox_xsalsa20poly1305_MACBYTES, + crypto_secretbox_MESSAGEBYTES_MAX = crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX, + crypto_secretbox_NONCEBYTES = crypto_secretbox_xsalsa20poly1305_NONCEBYTES, + crypto_secretbox_ZEROBYTES = crypto_secretbox_xsalsa20poly1305_ZEROBYTES, + + crypto_shorthash_siphash24_BYTES = 8, + crypto_shorthash_siphash24_KEYBYTES = 16, + crypto_shorthash_BYTES = crypto_shorthash_siphash24_BYTES, + crypto_shorthash_KEYBYTES = crypto_shorthash_siphash24_KEYBYTES, + + crypto_sign_ed25519_BYTES = 64, + crypto_sign_ed25519_MESSAGEBYTES_MAX = (SODIUM_SIZE_MAX - crypto_sign_ed25519_BYTES), + crypto_sign_ed25519_PUBLICKEYBYTES = 32, + crypto_sign_ed25519_SECRETKEYBYTES = (32 + 32), + crypto_sign_ed25519_SEEDBYTES = 32, + crypto_sign_BYTES = crypto_sign_ed25519_BYTES, + crypto_sign_MESSAGEBYTES_MAX = crypto_sign_ed25519_MESSAGEBYTES_MAX, + crypto_sign_PUBLICKEYBYTES = crypto_sign_ed25519_PUBLICKEYBYTES, + crypto_sign_SECRETKEYBYTES = crypto_sign_ed25519_SECRETKEYBYTES, + crypto_sign_SEEDBYTES = crypto_sign_ed25519_SEEDBYTES, + + crypto_stream_chacha20_KEYBYTES = 32, + crypto_stream_chacha20_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_stream_chacha20_NONCEBYTES = 8, + crypto_stream_chacha20_ietf_KEYBYTES = 32, + crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_stream_chacha20_ietf_NONCEBYTES = 12, + crypto_stream_salsa20_KEYBYTES = 32, + crypto_stream_salsa20_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_stream_salsa20_NONCEBYTES = 8, + crypto_stream_xchacha20_KEYBYTES = 32, + crypto_stream_xchacha20_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_stream_xchacha20_NONCEBYTES = 24, + crypto_stream_xsalsa20_KEYBYTES = 32, + crypto_stream_xsalsa20_MESSAGEBYTES_MAX = SODIUM_SIZE_MAX, + crypto_stream_xsalsa20_NONCEBYTES = 24, + crypto_stream_KEYBYTES = crypto_stream_xsalsa20_KEYBYTES, + crypto_stream_MESSAGEBYTES_MAX = crypto_stream_xsalsa20_MESSAGEBYTES_MAX, + crypto_stream_NONCEBYTES = crypto_stream_xsalsa20_NONCEBYTES, + + crypto_verify_16_BYTES = 16, + crypto_verify_32_BYTES = 32, + crypto_verify_64_BYTES = 64, + + randombytes_SEEDBYTES = 32, +}; + +inline const char* sodium_version_string() { return "Botan Sodium Compat"; } + +inline int sodium_library_version_major() { return 0; } + +inline int sodium_library_version_minor() { return 0; } + +inline int sodium_library_minimal() { return 0; } + +inline int sodium_init() { return 0; } + +// sodium/crypto_verify_{16,32,64}.h + +BOTAN_PUBLIC_API(2,11) +int crypto_verify_16(const uint8_t x[16], const uint8_t y[16]); + +BOTAN_PUBLIC_API(2,11) +int crypto_verify_32(const uint8_t x[32], const uint8_t y[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_verify_64(const uint8_t x[64], const uint8_t y[64]); + +// sodium/utils.h +BOTAN_PUBLIC_API(2,11) +void sodium_memzero(void* ptr, size_t len); + +BOTAN_PUBLIC_API(2,11) +int sodium_memcmp(const void* x, const void* y, size_t len); + +BOTAN_PUBLIC_API(2,11) +int sodium_compare(const uint8_t x[], const uint8_t y[], size_t len); + +BOTAN_PUBLIC_API(2,11) +int sodium_is_zero(const uint8_t nonce[], size_t nlen); + +BOTAN_PUBLIC_API(2,11) +void sodium_increment(uint8_t n[], size_t nlen); + +BOTAN_PUBLIC_API(2,11) +void sodium_add(uint8_t a[], const uint8_t b[], size_t len); + +BOTAN_PUBLIC_API(2,11) +void* sodium_malloc(size_t size); + +BOTAN_PUBLIC_API(2,11) +void* sodium_allocarray(size_t count, size_t size); + +BOTAN_PUBLIC_API(2,11) +void sodium_free(void* ptr); + +BOTAN_PUBLIC_API(2,11) +int sodium_mprotect_noaccess(void* ptr); + +BOTAN_PUBLIC_API(2,11) +int sodium_mprotect_readwrite(void* ptr); + +// sodium/randombytes.h + +inline size_t randombytes_seedbytes() { return randombytes_SEEDBYTES; } + +BOTAN_PUBLIC_API(2,11) +void randombytes_buf(void* buf, size_t size); + +BOTAN_PUBLIC_API(2,11) +void randombytes_buf_deterministic(void* buf, size_t size, + const uint8_t seed[randombytes_SEEDBYTES]); + +BOTAN_PUBLIC_API(2,11) +uint32_t randombytes_uniform(uint32_t upper_bound); + +inline uint32_t randombytes_random() + { + uint32_t x = 0; + randombytes_buf(&x, 4); + return x; + } + +inline void randombytes_stir() {} + +inline int randombytes_close() { return 0; } + +inline const char* randombytes_implementation_name() + { + return "botan"; + } + +inline void randombytes(uint8_t buf[], size_t buf_len) + { + return randombytes_buf(buf, buf_len); + } + +// sodium/crypto_secretbox_xsalsa20poly1305.h + +inline size_t crypto_secretbox_xsalsa20poly1305_keybytes() + { + return crypto_secretbox_xsalsa20poly1305_KEYBYTES; + } + +inline size_t crypto_secretbox_xsalsa20poly1305_noncebytes() + { + return crypto_secretbox_xsalsa20poly1305_NONCEBYTES; + } + +inline size_t crypto_secretbox_xsalsa20poly1305_macbytes() + { + return crypto_secretbox_xsalsa20poly1305_MACBYTES; + } + +inline size_t crypto_secretbox_xsalsa20poly1305_messagebytes_max() + { + return crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_secretbox_xsalsa20poly1305(uint8_t ctext[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_secretbox_xsalsa20poly1305_open(uint8_t ptext[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t key[]); + +inline void crypto_secretbox_xsalsa20poly1305_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +inline size_t crypto_secretbox_xsalsa20poly1305_boxzerobytes() + { + return crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES; + } + +inline size_t crypto_secretbox_xsalsa20poly1305_zerobytes() + { + return crypto_secretbox_xsalsa20poly1305_ZEROBYTES; + } + +// sodium/crypto_secretbox.h + +inline size_t crypto_secretbox_keybytes() { return crypto_secretbox_KEYBYTES; } + +inline size_t crypto_secretbox_noncebytes() { return crypto_secretbox_NONCEBYTES; } + +inline size_t crypto_secretbox_macbytes() { return crypto_secretbox_MACBYTES; } + +inline size_t crypto_secretbox_messagebytes_max() { return crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX; } + +inline const char* crypto_secretbox_primitive() { return "xsalsa20poly1305"; } + +BOTAN_PUBLIC_API(2,11) +int crypto_secretbox_detached(uint8_t ctext[], uint8_t mac[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_secretbox_open_detached(uint8_t ptext[], + const uint8_t ctext[], + const uint8_t mac[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t key[]); + +inline int crypto_secretbox_easy(uint8_t ctext[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_secretbox_detached(ctext + crypto_secretbox_MACBYTES, ctext, + ptext, ptext_len, nonce, key); + } + +inline int crypto_secretbox_open_easy(uint8_t out[], const uint8_t ctext[], size_t ctext_len, + const uint8_t nonce[], const uint8_t key[]) + { + if(ctext_len < crypto_secretbox_MACBYTES) + { + return -1; + } + + return crypto_secretbox_open_detached(out, ctext + crypto_secretbox_MACBYTES, + ctext, ctext_len - crypto_secretbox_MACBYTES, + nonce, key); + } + +inline void crypto_secretbox_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +inline size_t crypto_secretbox_zerobytes() + { + return crypto_secretbox_ZEROBYTES; + } + +inline size_t crypto_secretbox_boxzerobytes() + { + return crypto_secretbox_BOXZEROBYTES; + } + +inline int crypto_secretbox(uint8_t ctext[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_secretbox_xsalsa20poly1305(ctext, ptext, ptext_len, nonce, key); + } + +inline int crypto_secretbox_open(uint8_t ptext[], const uint8_t ctext[], + size_t ctext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_secretbox_xsalsa20poly1305_open(ptext, ctext, ctext_len, nonce, key); + } + +// sodium/crypto_aead_xchacha20poly1305.h + +inline size_t crypto_aead_chacha20poly1305_ietf_keybytes() + { + return crypto_aead_chacha20poly1305_ietf_KEYBYTES; + } + +inline size_t crypto_aead_chacha20poly1305_ietf_nsecbytes() + { + return crypto_aead_chacha20poly1305_ietf_NSECBYTES; + } + +inline size_t crypto_aead_chacha20poly1305_ietf_npubbytes() + { + return crypto_aead_chacha20poly1305_ietf_NPUBBYTES; + } + +inline size_t crypto_aead_chacha20poly1305_ietf_abytes() + { + return crypto_aead_chacha20poly1305_ietf_ABYTES; + } + +inline size_t crypto_aead_chacha20poly1305_ietf_messagebytes_max() + { + return crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_ietf_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_ietf_decrypt(uint8_t ptext[], + unsigned long long* ptext_len, + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_ietf_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + unsigned long long* mac_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_ietf_decrypt_detached(uint8_t m[], + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]); + +inline void crypto_aead_chacha20poly1305_ietf_keygen(uint8_t k[32]) + { + return randombytes_buf(k, crypto_aead_chacha20poly1305_ietf_KEYBYTES); + } + +inline size_t crypto_aead_chacha20poly1305_keybytes() + { + return crypto_aead_chacha20poly1305_KEYBYTES; + } + +inline size_t crypto_aead_chacha20poly1305_nsecbytes() + { + return crypto_aead_chacha20poly1305_NSECBYTES; + } + +inline size_t crypto_aead_chacha20poly1305_npubbytes() + { + return crypto_aead_chacha20poly1305_NPUBBYTES; + } + +inline size_t crypto_aead_chacha20poly1305_abytes() + { + return crypto_aead_chacha20poly1305_ABYTES; + } + +inline size_t crypto_aead_chacha20poly1305_messagebytes_max() + { + return crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_decrypt(uint8_t m[], + unsigned long long* ptext_len, + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + unsigned long long* mac_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_chacha20poly1305_decrypt_detached(uint8_t m[], + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]); + +inline void crypto_aead_chacha20poly1305_keygen(uint8_t k[32]) + { + randombytes_buf(k, 32); + } + +// sodium/crypto_aead_xchacha20poly1305.h + +inline size_t crypto_aead_xchacha20poly1305_ietf_keybytes() + { + return crypto_aead_xchacha20poly1305_ietf_KEYBYTES; + } + +inline size_t crypto_aead_xchacha20poly1305_ietf_nsecbytes() + { + return crypto_aead_xchacha20poly1305_ietf_NSECBYTES; + } + +inline size_t crypto_aead_xchacha20poly1305_ietf_npubbytes() + { + return crypto_aead_xchacha20poly1305_ietf_NPUBBYTES; + } + +inline size_t crypto_aead_xchacha20poly1305_ietf_abytes() + { + return crypto_aead_xchacha20poly1305_ietf_ABYTES; + } + +inline size_t crypto_aead_xchacha20poly1305_ietf_messagebytes_max() + { + return crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_xchacha20poly1305_ietf_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_xchacha20poly1305_ietf_decrypt(uint8_t ptext[], + unsigned long long* ptext_len, + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + unsigned long long* mac_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(uint8_t ptext[], + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]); + +inline void crypto_aead_xchacha20poly1305_ietf_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_box_curve25519xsalsa20poly1305.h + +inline size_t crypto_box_curve25519xsalsa20poly1305_seedbytes() + { + return crypto_box_curve25519xsalsa20poly1305_SEEDBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_publickeybytes() + { + return crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_secretkeybytes() + { + return crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_beforenmbytes() + { + return crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_noncebytes() + { + return crypto_box_curve25519xsalsa20poly1305_NONCEBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_macbytes() + { + return crypto_box_curve25519xsalsa20poly1305_MACBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_messagebytes_max() + { + return crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_boxzerobytes() + { + return crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES; + } + +inline size_t crypto_box_curve25519xsalsa20poly1305_zerobytes() + { + return crypto_box_curve25519xsalsa20poly1305_ZEROBYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_box_curve25519xsalsa20poly1305_seed_keypair(uint8_t pk[32], + uint8_t sk[32], + const uint8_t seed[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_box_curve25519xsalsa20poly1305_keypair(uint8_t pk[32], + uint8_t sk[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_box_curve25519xsalsa20poly1305_beforenm(uint8_t key[], + const uint8_t pk[32], + const uint8_t sk[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_box_curve25519xsalsa20poly1305(uint8_t ctext[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t pk[32], + const uint8_t sk[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_box_curve25519xsalsa20poly1305_open(uint8_t ptext[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t pk[32], + const uint8_t sk[32]); + +inline int crypto_box_curve25519xsalsa20poly1305_afternm(uint8_t ctext[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_secretbox_xsalsa20poly1305(ctext, ptext, ptext_len, nonce, key); + } + +inline int crypto_box_curve25519xsalsa20poly1305_open_afternm(uint8_t ptext[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_secretbox_xsalsa20poly1305_open(ptext, ctext, ctext_len, nonce, key); + } + +// sodium/crypto_box.h + +inline size_t crypto_box_seedbytes() + { + return crypto_box_SEEDBYTES; + } + +inline size_t crypto_box_publickeybytes() + { + return crypto_box_PUBLICKEYBYTES; + } + +inline size_t crypto_box_secretkeybytes() + { + return crypto_box_SECRETKEYBYTES; + } + +inline size_t crypto_box_noncebytes() + { + return crypto_box_NONCEBYTES; + } + +inline size_t crypto_box_macbytes() + { + return crypto_box_MACBYTES; + } + +inline size_t crypto_box_messagebytes_max() + { + return crypto_box_MESSAGEBYTES_MAX; + } + +inline size_t crypto_box_beforenmbytes() + { + return crypto_box_BEFORENMBYTES; + } + +inline const char* crypto_box_primitive() { return "curve25519xsalsa20poly1305"; } + +inline int crypto_box_seed_keypair(uint8_t pk[32], uint8_t sk[32], + const uint8_t seed[]) + { + return crypto_box_curve25519xsalsa20poly1305_seed_keypair(pk, sk, seed); + } + +inline int crypto_box_keypair(uint8_t pk[32], uint8_t sk[32]) + { + return crypto_box_curve25519xsalsa20poly1305_keypair(pk, sk); + } + +BOTAN_PUBLIC_API(2,11) +int crypto_box_detached(uint8_t ctext[], uint8_t mac[], + const uint8_t ptext[], size_t ptext_len, + const uint8_t nonce[], const uint8_t pk[32], + const uint8_t sk[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_box_open_detached(uint8_t ptext[], const uint8_t ctext[], + const uint8_t mac[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t pk[32], + const uint8_t sk[32]); + +inline int crypto_box_easy(uint8_t ctext[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t pk[32], const uint8_t sk[32]) + { + return crypto_box_detached(ctext + crypto_box_MACBYTES, ctext, ptext, ptext_len, nonce, pk, sk); + } + +inline int crypto_box_open_easy(uint8_t ptext[], const uint8_t ctext[], + size_t ctext_len, const uint8_t nonce[], + const uint8_t pk[32], const uint8_t sk[32]) + { + if(ctext_len < crypto_box_MACBYTES) + { + return -1; + } + + return crypto_box_open_detached(ptext, ctext + crypto_box_MACBYTES, + ctext, ctext_len - crypto_box_MACBYTES, + nonce, pk, sk); + } + +inline int crypto_box_beforenm(uint8_t key[], const uint8_t pk[32], + const uint8_t sk[32]) + { + return crypto_box_curve25519xsalsa20poly1305_beforenm(key, pk, sk); + } + +inline int crypto_box_afternm(uint8_t ctext[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_box_curve25519xsalsa20poly1305_afternm(ctext, ptext, ptext_len, nonce, key); + } + +inline int crypto_box_open_afternm(uint8_t ptext[], const uint8_t ctext[], + size_t ctext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_box_curve25519xsalsa20poly1305_open_afternm(ptext, ctext, ctext_len, nonce, key); + } + +inline int crypto_box_open_detached_afternm(uint8_t ptext[], const uint8_t ctext[], + const uint8_t mac[], + size_t ctext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_secretbox_open_detached(ptext, ctext, mac, ctext_len, nonce, key); + } + +inline int crypto_box_open_easy_afternm(uint8_t ptext[], const uint8_t ctext[], + size_t ctext_len, const uint8_t nonce[], + const uint8_t key[]) + { + if(ctext_len < crypto_box_MACBYTES) + { + return -1; + } + + return crypto_box_open_detached_afternm(ptext, ctext + crypto_box_MACBYTES, + ctext, ctext_len - crypto_box_MACBYTES, + nonce, key); + } + +inline int crypto_box_detached_afternm(uint8_t ctext[], uint8_t mac[], + const uint8_t ptext[], size_t ptext_len, + const uint8_t nonce[], const uint8_t key[]) + { + return crypto_secretbox_detached(ctext, mac, ptext, ptext_len, nonce, key); + } + +inline int crypto_box_easy_afternm(uint8_t ctext[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_box_detached_afternm(ctext + crypto_box_MACBYTES, ctext, ptext, ptext_len, nonce, key); + } + +inline size_t crypto_box_zerobytes() { return crypto_box_ZEROBYTES; } + +inline size_t crypto_box_boxzerobytes() { return crypto_box_BOXZEROBYTES; } + +inline int crypto_box(uint8_t ctext[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t pk[32], const uint8_t sk[32]) + { + return crypto_box_curve25519xsalsa20poly1305(ctext, ptext, ptext_len, nonce, pk, sk); + } + +inline int crypto_box_open(uint8_t ptext[], const uint8_t ctext[], + size_t ctext_len, const uint8_t nonce[], + const uint8_t pk[32], const uint8_t sk[32]) + { + return crypto_box_curve25519xsalsa20poly1305_open(ptext, ctext, ctext_len, nonce, pk, sk); + } + +// sodium/crypto_hash_sha512.h + +inline size_t crypto_hash_sha512_bytes() { return crypto_hash_sha512_BYTES; } + +BOTAN_PUBLIC_API(2,11) +int crypto_hash_sha512(uint8_t out[64], const uint8_t in[], size_t in_len); + +// sodium/crypto_auth_hmacsha512.h + +inline size_t crypto_auth_hmacsha512_bytes() { return crypto_auth_hmacsha512_BYTES; } + +inline size_t crypto_auth_hmacsha512_keybytes() { return crypto_auth_hmacsha512_KEYBYTES; } + +BOTAN_PUBLIC_API(2,11) +int crypto_auth_hmacsha512(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_auth_hmacsha512_verify(const uint8_t h[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +inline void crypto_auth_hmacsha512_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_auth_hmacsha512256.h + +inline size_t crypto_auth_hmacsha512256_bytes() + { + return crypto_auth_hmacsha512256_BYTES; + } + +inline size_t crypto_auth_hmacsha512256_keybytes() + { + return crypto_auth_hmacsha512256_KEYBYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_auth_hmacsha512256(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_auth_hmacsha512256_verify(const uint8_t h[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +inline void crypto_auth_hmacsha512256_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_auth.h + +inline size_t crypto_auth_bytes() { return crypto_auth_BYTES; } + +inline size_t crypto_auth_keybytes() { return crypto_auth_KEYBYTES; } + +inline const char* crypto_auth_primitive() { return "hmacsha512256"; } + +inline int crypto_auth(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t key[]) + { + return crypto_auth_hmacsha512256(out, in, in_len, key); + } + +inline int crypto_auth_verify(const uint8_t mac[], const uint8_t in[], + size_t in_len, const uint8_t key[]) + { + return crypto_auth_hmacsha512256_verify(mac, in, in_len, key); + } + +inline void crypto_auth_keygen(uint8_t k[]) + { + return randombytes_buf(k, crypto_auth_KEYBYTES); + } + +// sodium/crypto_hash_sha256.h + +inline size_t crypto_hash_sha256_bytes() + { + return crypto_hash_sha256_BYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_hash_sha256(uint8_t out[], const uint8_t in[], size_t in_len); + +// sodium/crypto_auth_hmacsha256.h + +inline size_t crypto_auth_hmacsha256_bytes() + { + return crypto_auth_hmacsha256_BYTES; + } + +inline size_t crypto_auth_hmacsha256_keybytes() + { + return crypto_auth_hmacsha256_KEYBYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_auth_hmacsha256(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_auth_hmacsha256_verify(const uint8_t h[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +inline void crypto_auth_hmacsha256_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_stream_xsalsa20.h + +inline size_t crypto_stream_xsalsa20_keybytes() + { + return crypto_stream_xsalsa20_KEYBYTES; + } + +inline size_t crypto_stream_xsalsa20_noncebytes() + { + return crypto_stream_xsalsa20_NONCEBYTES; + } + +inline size_t crypto_stream_xsalsa20_messagebytes_max() + { + return crypto_stream_xsalsa20_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_xsalsa20(uint8_t out[], size_t ctext_len, + const uint8_t nonce[], const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_xsalsa20_xor(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_xsalsa20_xor_ic(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]); + +inline void crypto_stream_xsalsa20_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_core_hsalsa20.h + +inline size_t crypto_core_hsalsa20_outputbytes() + { + return crypto_core_hsalsa20_OUTPUTBYTES; + } + +inline size_t crypto_core_hsalsa20_inputbytes() + { + return crypto_core_hsalsa20_INPUTBYTES; + } + +inline size_t crypto_core_hsalsa20_keybytes() + { + return crypto_core_hsalsa20_KEYBYTES; + } + +inline size_t crypto_core_hsalsa20_constbytes() + { + return crypto_core_hsalsa20_CONSTBYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_core_hsalsa20(uint8_t out[], const uint8_t in[], + const uint8_t key[], const uint8_t c[]); + +// sodium/crypto_hash.h + +inline size_t crypto_hash_bytes() + { + return crypto_hash_BYTES; + } + +inline int crypto_hash(uint8_t out[], const uint8_t in[], size_t in_len) + { + return crypto_hash_sha512(out, in, in_len); + } + +inline const char* crypto_hash_primitive() { return "sha512"; } + +// sodium/crypto_onetimeauth_poly1305.h + +inline size_t crypto_onetimeauth_poly1305_bytes() + { + return crypto_onetimeauth_poly1305_BYTES; + } + +inline size_t crypto_onetimeauth_poly1305_keybytes() + { + return crypto_onetimeauth_poly1305_KEYBYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_onetimeauth_poly1305(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_onetimeauth_poly1305_verify(const uint8_t h[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]); + +inline void crypto_onetimeauth_poly1305_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_onetimeauth.h + +inline size_t crypto_onetimeauth_bytes() { return crypto_onetimeauth_BYTES; } + +inline size_t crypto_onetimeauth_keybytes() { return crypto_onetimeauth_KEYBYTES; } + +inline const char* crypto_onetimeauth_primitive() { return "poly1305"; } + +inline int crypto_onetimeauth(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t key[]) + { + return crypto_onetimeauth_poly1305(out, in, in_len, key); + } + +inline int crypto_onetimeauth_verify(const uint8_t h[], const uint8_t in[], + size_t in_len, const uint8_t key[]) + { + return crypto_onetimeauth_poly1305_verify(h, in, in_len, key); + } + +inline void crypto_onetimeauth_keygen(uint8_t k[32]) + { + return crypto_onetimeauth_poly1305_keygen(k); + } + +// sodium/crypto_scalarmult_curve25519.h + +inline size_t crypto_scalarmult_curve25519_bytes() + { + return crypto_scalarmult_curve25519_BYTES; + } + +inline size_t crypto_scalarmult_curve25519_scalarbytes() + { + return crypto_scalarmult_curve25519_SCALARBYTES; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t basepoint[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]); + +// sodium/crypto_scalarmult.h + +inline size_t crypto_scalarmult_bytes() { return crypto_scalarmult_curve25519_bytes(); } + +inline size_t crypto_scalarmult_scalarbytes() { return crypto_scalarmult_curve25519_scalarbytes(); } + +inline const char* crypto_scalarmult_primitive() { return "curve25519"; } + +inline int crypto_scalarmult_base(uint8_t out[], const uint8_t scalar[]) + { + return crypto_scalarmult_curve25519_base(out, scalar); + } + +inline int crypto_scalarmult(uint8_t out[], const uint8_t scalar[], const uint8_t base[]) + { + return crypto_scalarmult_curve25519(out, scalar, base); + } + +// sodium/crypto_stream_chacha20.h + +inline size_t crypto_stream_chacha20_keybytes() + { + return crypto_stream_chacha20_KEYBYTES; + } + +inline size_t crypto_stream_chacha20_noncebytes() + { + return crypto_stream_chacha20_NONCEBYTES; + } + +inline size_t crypto_stream_chacha20_messagebytes_max() + { + return crypto_stream_chacha20_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_chacha20(uint8_t out[], size_t ctext_len, + const uint8_t nonce[], const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_chacha20_xor(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_chacha20_xor_ic(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]); + +inline void crypto_stream_chacha20_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +inline size_t crypto_stream_chacha20_ietf_keybytes() + { + return crypto_stream_chacha20_ietf_KEYBYTES; + } + +inline size_t crypto_stream_chacha20_ietf_noncebytes() + { + return crypto_stream_chacha20_ietf_NONCEBYTES; + } + +inline size_t crypto_stream_chacha20_ietf_messagebytes_max() + { + return crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_chacha20_ietf(uint8_t out[], size_t ctext_len, + const uint8_t nonce[], const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_chacha20_ietf_xor(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_chacha20_ietf_xor_ic(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], uint32_t ic, + const uint8_t key[]); + +inline void crypto_stream_chacha20_ietf_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_stream_xchacha20.h + +inline size_t crypto_stream_xchacha20_keybytes() + { + return crypto_stream_xchacha20_KEYBYTES; + } + +inline size_t crypto_stream_xchacha20_noncebytes() + { + return crypto_stream_xchacha20_NONCEBYTES; + } + +inline size_t crypto_stream_xchacha20_messagebytes_max() + { + return crypto_stream_xchacha20_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_xchacha20(uint8_t out[], size_t ctext_len, + const uint8_t nonce[], const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_xchacha20_xor(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_xchacha20_xor_ic(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]); + +inline void crypto_stream_xchacha20_keygen(uint8_t k[32]) + { + return randombytes_buf(k, crypto_stream_xchacha20_KEYBYTES); + } + +// sodium/crypto_stream_salsa20.h + +inline size_t crypto_stream_salsa20_keybytes() + { + return crypto_stream_xsalsa20_KEYBYTES; + } + +inline size_t crypto_stream_salsa20_noncebytes() + { + return crypto_stream_salsa20_NONCEBYTES; + } + +inline size_t crypto_stream_salsa20_messagebytes_max() + { + return crypto_stream_salsa20_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_salsa20(uint8_t out[], size_t ctext_len, + const uint8_t nonce[], const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_salsa20_xor(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, const uint8_t nonce[], + const uint8_t key[]); + +BOTAN_PUBLIC_API(2,11) +int crypto_stream_salsa20_xor_ic(uint8_t out[], const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]); + +inline void crypto_stream_salsa20_keygen(uint8_t k[32]) + { + return randombytes_buf(k, 32); + } + +// sodium/crypto_stream.h + +inline size_t crypto_stream_keybytes() { return crypto_stream_xsalsa20_keybytes(); } + +inline size_t crypto_stream_noncebytes() { return crypto_stream_xsalsa20_noncebytes(); } + +inline size_t crypto_stream_messagebytes_max() { return crypto_stream_MESSAGEBYTES_MAX; } + +inline const char* crypto_stream_primitive() { return "xsalsa20"; } + +inline int crypto_stream(uint8_t out[], size_t out_len, + const uint8_t nonce[24], const uint8_t key[32]) + { + return crypto_stream_xsalsa20(out, out_len, nonce, key); + } + +inline int crypto_stream_xor(uint8_t out[], const uint8_t in[], size_t in_len, + const uint8_t nonce[24], const uint8_t key[32]) + { + return crypto_stream_xsalsa20_xor(out, in, in_len, nonce, key); + } + +inline void crypto_stream_keygen(uint8_t key[32]) + { + return randombytes_buf(key, 32); + } + +// sodium/crypto_shorthash_siphash24.h + +inline size_t crypto_shorthash_siphash24_bytes() { return crypto_shorthash_siphash24_BYTES; } + +inline size_t crypto_shorthash_siphash24_keybytes() { return crypto_shorthash_siphash24_KEYBYTES; } + +BOTAN_PUBLIC_API(2,11) +int crypto_shorthash_siphash24(uint8_t out[8], const uint8_t in[], size_t in_len, const uint8_t key[16]); + +// sodium/crypto_shorthash.h + +inline size_t crypto_shorthash_bytes() { return crypto_shorthash_siphash24_bytes(); } + +inline size_t crypto_shorthash_keybytes() { return crypto_shorthash_siphash24_keybytes(); } + +inline const char* crypto_shorthash_primitive() { return "siphash24"; } + +inline int crypto_shorthash(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t k[16]) + { + return crypto_shorthash_siphash24(out, in, in_len, k); + } + +inline void crypto_shorthash_keygen(uint8_t k[16]) + { + randombytes_buf(k, crypto_shorthash_siphash24_KEYBYTES); + } + +// sodium/crypto_sign_ed25519.h + +inline size_t crypto_sign_ed25519_bytes() + { + return crypto_sign_ed25519_BYTES; + } + +inline size_t crypto_sign_ed25519_seedbytes() + { + return crypto_sign_ed25519_SEEDBYTES; + } + +inline size_t crypto_sign_ed25519_publickeybytes() + { + return crypto_sign_ed25519_PUBLICKEYBYTES; + } + +inline size_t crypto_sign_ed25519_secretkeybytes() + { + return crypto_sign_ed25519_SECRETKEYBYTES; + } + +inline size_t crypto_sign_ed25519_messagebytes_max() + { + return crypto_sign_ed25519_MESSAGEBYTES_MAX; + } + +BOTAN_PUBLIC_API(2,11) +int crypto_sign_ed25519_detached(uint8_t sig[], + unsigned long long* sig_len, + const uint8_t msg[], + size_t msg_len, + const uint8_t sk[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_sign_ed25519_verify_detached(const uint8_t sig[], + const uint8_t msg[], + size_t msg_len, + const uint8_t pk[32]); + +BOTAN_PUBLIC_API(2,11) +int crypto_sign_ed25519_keypair(uint8_t pk[32], uint8_t sk[64]); + +BOTAN_PUBLIC_API(2,11) +int crypto_sign_ed25519_seed_keypair(uint8_t pk[], uint8_t sk[], + const uint8_t seed[]); + +// sodium/crypto_sign.h + +inline size_t crypto_sign_bytes() + { + return crypto_sign_BYTES; + } + +inline size_t crypto_sign_seedbytes() + { + return crypto_sign_SEEDBYTES; + } + +inline size_t crypto_sign_publickeybytes() + { + return crypto_sign_PUBLICKEYBYTES; + } + +inline size_t crypto_sign_secretkeybytes() + { + return crypto_sign_SECRETKEYBYTES; + } + +inline size_t crypto_sign_messagebytes_max() + { + return crypto_sign_MESSAGEBYTES_MAX; + } + +inline const char* crypto_sign_primitive() + { + return "ed25519"; + } + +inline int crypto_sign_seed_keypair(uint8_t pk[32], uint8_t sk[32], + const uint8_t seed[]) + { + return crypto_sign_ed25519_seed_keypair(pk, sk, seed); + } + +inline int crypto_sign_keypair(uint8_t pk[32], uint8_t sk[32]) + { + return crypto_sign_ed25519_keypair(pk, sk); + } + +inline int crypto_sign_detached(uint8_t sig[], unsigned long long* sig_len, + const uint8_t msg[], size_t msg_len, + const uint8_t sk[32]) + { + return crypto_sign_ed25519_detached(sig, sig_len, msg, msg_len, sk); + } + +inline int crypto_sign_verify_detached(const uint8_t sig[], + const uint8_t in[], + size_t in_len, + const uint8_t pk[32]) + { + return crypto_sign_ed25519_verify_detached(sig, in, in_len, pk); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_25519.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_25519.cpp new file mode 100644 index 0000000000..e1e44b9ad4 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_25519.cpp @@ -0,0 +1,60 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +int Sodium::crypto_scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]) + { + curve25519_donna(out, scalar, point); + return 0; + } + +int Sodium::crypto_scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]) + { + curve25519_basepoint(out, scalar); + return 0; + } +int Sodium::crypto_sign_ed25519_detached(uint8_t sig[], + unsigned long long* sig_len, + const uint8_t msg[], + size_t msg_len, + const uint8_t sk[32]) + { + ed25519_sign(sig, msg, msg_len, sk, nullptr, 0); + + if(sig_len) + *sig_len = 64; + return 0; + } + +int Sodium::crypto_sign_ed25519_verify_detached(const uint8_t sig[], + const uint8_t msg[], + size_t msg_len, + const uint8_t pk[32]) + { + const bool ok = ed25519_verify(msg, msg_len, sig, pk, nullptr, 0); + return ok ? 0 : -1; + } + +int Sodium::crypto_sign_ed25519_keypair(uint8_t pk[32], uint8_t sk[64]) + { + secure_vector seed(32); + randombytes_buf(seed.data(), seed.size()); + return crypto_sign_ed25519_seed_keypair(pk, sk, seed.data()); + } + +int Sodium::crypto_sign_ed25519_seed_keypair(uint8_t pk[], uint8_t sk[], + const uint8_t seed[]) + { + ed25519_gen_keypair(pk, sk, seed); + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_aead.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_aead.cpp new file mode 100644 index 0000000000..0d6f35eaf7 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_aead.cpp @@ -0,0 +1,359 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +int sodium_aead_chacha20poly1305_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + size_t nonce_len, + const uint8_t key[]) + { + auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", ENCRYPTION); + + chacha20poly1305->set_key(key, 32); + chacha20poly1305->set_associated_data(ad, ad_len); + chacha20poly1305->start(nonce, nonce_len); + + // FIXME do this in-place + secure_vector buf; + buf.reserve(ptext_len + 16); + buf.assign(ptext, ptext + ptext_len); + + chacha20poly1305->finish(buf); + + copy_mem(ctext, buf.data(), buf.size()); + if(ctext_len) + *ctext_len = buf.size(); + return 0; + } + +int sodium_aead_chacha20poly1305_decrypt(uint8_t ptext[], + unsigned long long* ptext_len, + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + size_t nonce_len, + const uint8_t key[]) + { + if(ctext_len < 16) + return -1; + + *ptext_len = 0; + + auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", DECRYPTION); + + chacha20poly1305->set_key(key, 32); + chacha20poly1305->set_associated_data(ad, ad_len); + chacha20poly1305->start(nonce, nonce_len); + + // FIXME do this in-place + secure_vector buf; + buf.assign(ctext, ctext + ctext_len); + + try + { + chacha20poly1305->finish(buf); + } + catch(Invalid_Authentication_Tag&) + { + return -1; + } + + *ptext_len = ctext_len - 16; + + copy_mem(ptext, buf.data(), buf.size()); + return 0; + } + +int sodium_aead_chacha20poly1305_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + size_t nonce_len, + const uint8_t key[]) + { + auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", ENCRYPTION); + + chacha20poly1305->set_key(key, 32); + chacha20poly1305->set_associated_data(ad, ad_len); + chacha20poly1305->start(nonce, nonce_len); + + // FIXME do this in-place + secure_vector buf; + buf.reserve(ptext_len + 16); + buf.assign(ptext, ptext + ptext_len); + + chacha20poly1305->finish(buf); + + copy_mem(ctext, buf.data(), ptext_len); + copy_mem(mac, buf.data() + ptext_len, 16); + return 0; + } + +int sodium_aead_chacha20poly1305_decrypt_detached(uint8_t ptext[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + size_t nonce_len, + const uint8_t key[]) + { + auto chacha20poly1305 = AEAD_Mode::create_or_throw("ChaCha20Poly1305", DECRYPTION); + + chacha20poly1305->set_key(key, 32); + chacha20poly1305->set_associated_data(ad, ad_len); + chacha20poly1305->start(nonce, nonce_len); + + // FIXME do this in-place + secure_vector buf; + buf.reserve(ctext_len + 16); + buf.assign(ctext, ctext + ctext_len); + buf.insert(buf.end(), mac, mac + 16); + + try + { + chacha20poly1305->finish(buf); + } + catch(Invalid_Authentication_Tag&) + { + return -1; + } + + copy_mem(ptext, buf.data(), buf.size()); + return 0; + } + +} + +int Sodium::crypto_aead_chacha20poly1305_ietf_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + return sodium_aead_chacha20poly1305_encrypt( + ctext, ctext_len, ptext, ptext_len, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_ietf_decrypt(uint8_t ptext[], + unsigned long long* ptext_len, + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + return sodium_aead_chacha20poly1305_decrypt( + ptext, ptext_len, ctext, ctext_len, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_ietf_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + unsigned long long* mac_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + if(mac_len) + *mac_len = 16; + + return sodium_aead_chacha20poly1305_encrypt_detached( + ctext, mac, ptext, ptext_len, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_ietf_decrypt_detached(uint8_t ptext[], + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + return sodium_aead_chacha20poly1305_decrypt_detached( + ptext, ctext, ctext_len, mac, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + return sodium_aead_chacha20poly1305_encrypt( + ctext, ctext_len, ptext, ptext_len, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_decrypt(uint8_t ptext[], + unsigned long long* ptext_len, + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + return sodium_aead_chacha20poly1305_decrypt( + ptext, ptext_len, ctext, ctext_len, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + unsigned long long* mac_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + if(mac_len) + *mac_len = 16; + + return sodium_aead_chacha20poly1305_encrypt_detached( + ctext, mac, ptext, ptext_len, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); + } + +int Sodium::crypto_aead_chacha20poly1305_decrypt_detached(uint8_t ptext[], + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + return sodium_aead_chacha20poly1305_decrypt_detached( + ptext, ctext, ctext_len, mac, + ad, ad_len, nonce, crypto_aead_chacha20poly1305_npubbytes(), key); + } + +int Sodium::crypto_aead_xchacha20poly1305_ietf_encrypt(uint8_t ctext[], + unsigned long long* ctext_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + return sodium_aead_chacha20poly1305_encrypt( + ctext, ctext_len, ptext, ptext_len, + ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_xchacha20poly1305_ietf_decrypt(uint8_t ptext[], + unsigned long long* ptext_len, + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + + return sodium_aead_chacha20poly1305_decrypt( + ptext, ptext_len, ctext, ctext_len, + ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_xchacha20poly1305_ietf_encrypt_detached(uint8_t ctext[], + uint8_t mac[], + unsigned long long* mac_len, + const uint8_t ptext[], + size_t ptext_len, + const uint8_t ad[], + size_t ad_len, + const uint8_t unused_secret_nonce[], + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + if(mac_len) + *mac_len = 16; + + return sodium_aead_chacha20poly1305_encrypt_detached( + ctext, mac, ptext, ptext_len, + ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); + } + +int Sodium::crypto_aead_xchacha20poly1305_ietf_decrypt_detached(uint8_t ptext[], + uint8_t unused_secret_nonce[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t mac[], + const uint8_t ad[], + size_t ad_len, + const uint8_t nonce[], + const uint8_t key[]) + { + BOTAN_UNUSED(unused_secret_nonce); + return sodium_aead_chacha20poly1305_decrypt_detached( + ptext, ctext, ctext_len, mac, + ad, ad_len, nonce, crypto_aead_xchacha20poly1305_ietf_npubbytes(), key); + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_auth.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_auth.cpp new file mode 100644 index 0000000000..747b8af33e --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_auth.cpp @@ -0,0 +1,131 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +int Sodium::crypto_hash_sha512(uint8_t out[64], const uint8_t in[], size_t in_len) + { + auto sha512 = HashFunction::create_or_throw("SHA-512"); + sha512->update(in, in_len); + sha512->final(out); + return 0; + } + +int Sodium::crypto_hash_sha256(uint8_t out[], const uint8_t in[], size_t in_len) + { + auto sha256 = HashFunction::create_or_throw("SHA-256"); + sha256->update(in, in_len); + sha256->final(out); + return 0; + } + +int Sodium::crypto_shorthash_siphash24(uint8_t out[8], const uint8_t in[], + size_t in_len, const uint8_t key[16]) + { + auto mac = MessageAuthenticationCode::create_or_throw("SipHash(2,4)"); + mac->set_key(key, crypto_shorthash_siphash24_KEYBYTES); + mac->update(in, in_len); + mac->final(out); + return 0; + } + +int Sodium::crypto_onetimeauth_poly1305(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + auto mac = MessageAuthenticationCode::create_or_throw("Poly1305"); + mac->set_key(key, crypto_onetimeauth_poly1305_KEYBYTES); + mac->update(in, in_len); + mac->final(out); + return 0; + } + +int Sodium::crypto_onetimeauth_poly1305_verify(const uint8_t mac[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + secure_vector computed(crypto_onetimeauth_poly1305_BYTES); + crypto_onetimeauth_poly1305(computed.data(), in, in_len, key); + return crypto_verify_16(computed.data(), mac) ? 0 : -1; + } + +int Sodium::crypto_auth_hmacsha512(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + auto mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); + mac->set_key(key, crypto_auth_hmacsha512_KEYBYTES); + mac->update(in, in_len); + mac->final(out); + return 0; + } + +int Sodium::crypto_auth_hmacsha512_verify(const uint8_t mac[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + secure_vector computed(crypto_auth_hmacsha512_BYTES); + crypto_auth_hmacsha512(computed.data(), in, in_len, key); + return crypto_verify_64(computed.data(), mac) ? 0 : -1; + } + +int Sodium::crypto_auth_hmacsha512256(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + auto mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); + mac->set_key(key, crypto_auth_hmacsha512256_KEYBYTES); + mac->update(in, in_len); + + secure_vector buf(64); + mac->final(buf); + + copy_mem(out, buf.data(), crypto_auth_hmacsha512256_BYTES); + return 0; + } + +int Sodium::crypto_auth_hmacsha512256_verify(const uint8_t mac[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + secure_vector computed(crypto_auth_hmacsha512256_BYTES); + crypto_auth_hmacsha512256(computed.data(), in, in_len, key); + return crypto_verify_32(computed.data(), mac) ? 0 : -1; + } + +int Sodium::crypto_auth_hmacsha256(uint8_t out[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + auto mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + mac->set_key(key, crypto_auth_hmacsha256_KEYBYTES); + mac->update(in, in_len); + mac->final(out); + return 0; + } + +int Sodium::crypto_auth_hmacsha256_verify(const uint8_t mac[], + const uint8_t in[], + size_t in_len, + const uint8_t key[]) + { + secure_vector computed(crypto_auth_hmacsha256_BYTES); + crypto_auth_hmacsha256(computed.data(), in, in_len, key); + return crypto_verify_32(computed.data(), mac) ? 0 : -1; + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_box.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_box.cpp new file mode 100644 index 0000000000..52b9a03036 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_box.cpp @@ -0,0 +1,100 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +int Sodium::crypto_box_curve25519xsalsa20poly1305_seed_keypair(uint8_t pk[32], + uint8_t sk[32], + const uint8_t seed[32]) + { + secure_vector digest(64); + crypto_hash_sha512(digest.data(), seed, 32); + copy_mem(sk, digest.data(), 32); + return crypto_scalarmult_curve25519_base(pk, sk); + } + +int Sodium::crypto_box_curve25519xsalsa20poly1305_keypair(uint8_t pk[32], + uint8_t sk[32]) + { + randombytes_buf(sk, 32); + return crypto_scalarmult_curve25519_base(pk, sk); + } + +int Sodium::crypto_box_curve25519xsalsa20poly1305_beforenm(uint8_t key[], + const uint8_t pk[32], + const uint8_t sk[32]) + { + const uint8_t zero[16] = { 0 }; + secure_vector shared(32); + + if(crypto_scalarmult_curve25519(shared.data(), sk, pk) != 0) + return -1; + + return crypto_core_hsalsa20(key, zero, shared.data(), nullptr); + } + +int Sodium::crypto_box_curve25519xsalsa20poly1305(uint8_t ctext[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t pk[32], + const uint8_t sk[32]) + { + secure_vector shared(32); + + if(crypto_box_curve25519xsalsa20poly1305_beforenm(shared.data(), pk, sk) != 0) + return -1; + + return crypto_box_curve25519xsalsa20poly1305_afternm(ctext, ptext, ptext_len, nonce, shared.data()); + } + +int Sodium::crypto_box_curve25519xsalsa20poly1305_open(uint8_t ptext[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t pk[32], + const uint8_t sk[32]) + { + secure_vector shared(32); + + if(crypto_box_curve25519xsalsa20poly1305_beforenm(shared.data(), pk, sk) != 0) + return -1; + + return crypto_box_curve25519xsalsa20poly1305_open_afternm(ptext, ctext, ctext_len, nonce, shared.data()); + } + +int Sodium::crypto_box_detached(uint8_t ctext[], uint8_t mac[], + const uint8_t ptext[], size_t ptext_len, + const uint8_t nonce[], const uint8_t pk[32], + const uint8_t sk[32]) + { + secure_vector shared(32); + + if(crypto_box_beforenm(shared.data(), pk, sk) != 0) + return -1; + + return crypto_box_detached_afternm(ctext, mac, ptext, ptext_len, nonce, shared.data()); + } + +int Sodium::crypto_box_open_detached(uint8_t ptext[], const uint8_t ctext[], + const uint8_t mac[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t pk[32], + const uint8_t sk[32]) + { + secure_vector shared(32); + + if(crypto_box_beforenm(shared.data(), pk, sk) != 0) + return -1; + + return crypto_box_open_detached_afternm(ptext, ctext, mac, ctext_len, nonce, shared.data()); + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_chacha.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_chacha.cpp new file mode 100644 index 0000000000..fed7a52f6f --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_chacha.cpp @@ -0,0 +1,109 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +int Sodium::crypto_stream_chacha20(uint8_t out[], size_t out_len, + const uint8_t nonce[], const uint8_t key[]) + { + auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); + chacha->set_key(key, crypto_stream_chacha20_KEYBYTES); + chacha->set_iv(nonce, crypto_stream_chacha20_NONCEBYTES); + chacha->write_keystream(out, out_len); + return 0; + } + +int Sodium::crypto_stream_chacha20_xor(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_stream_chacha20_xor_ic(out, in, in_len, nonce, 0, key); + } + +int Sodium::crypto_stream_chacha20_xor_ic(uint8_t out[], const uint8_t in[], + size_t in_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]) + { + if((ic >> 6) != 0) // otherwise multiply overflows + return -1; + + auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); + chacha->set_key(key, crypto_stream_chacha20_KEYBYTES); + chacha->set_iv(nonce, crypto_stream_chacha20_NONCEBYTES); + chacha->seek(ic * 64); + chacha->cipher(in, out, in_len); + return 0; + } + +int Sodium::crypto_stream_chacha20_ietf(uint8_t out[], size_t out_len, + const uint8_t nonce[], const uint8_t key[]) + { + auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); + chacha->set_key(key, crypto_stream_chacha20_ietf_KEYBYTES); + chacha->set_iv(nonce, crypto_stream_chacha20_ietf_NONCEBYTES); + chacha->write_keystream(out, out_len); + return 0; + } + +int Sodium::crypto_stream_chacha20_ietf_xor(uint8_t out[], + const uint8_t in[], size_t in_len, + const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_stream_chacha20_ietf_xor_ic(out, in, in_len, nonce, 0, key); + } + +int Sodium::crypto_stream_chacha20_ietf_xor_ic(uint8_t out[], + const uint8_t in[], size_t in_len, + const uint8_t nonce[], uint32_t ic, + const uint8_t key[]) + { + auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); + chacha->set_key(key, crypto_stream_chacha20_ietf_KEYBYTES); + chacha->set_iv(nonce, crypto_stream_chacha20_ietf_NONCEBYTES); + chacha->seek(static_cast(ic) * 64); + chacha->cipher(in, out, in_len); + return 0; + } + +int Sodium::crypto_stream_xchacha20(uint8_t out[], size_t out_len, + const uint8_t nonce[], const uint8_t key[]) + { + auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); + chacha->set_key(key, crypto_stream_xchacha20_KEYBYTES); + chacha->set_iv(nonce, crypto_stream_xchacha20_NONCEBYTES); + chacha->write_keystream(out, out_len); + return 0; + } + +int Sodium::crypto_stream_xchacha20_xor(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_stream_xchacha20_xor_ic(out, in, in_len, nonce, 0, key); + } + +int Sodium::crypto_stream_xchacha20_xor_ic(uint8_t out[], const uint8_t in[], + size_t in_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]) + { + if((ic >> 6) != 0) // otherwise multiply overflows + return -1; + + auto chacha = StreamCipher::create_or_throw("ChaCha(20)"); + chacha->set_key(key, crypto_stream_xchacha20_KEYBYTES); + chacha->set_iv(nonce, crypto_stream_xchacha20_NONCEBYTES); + chacha->seek(ic * 64); + chacha->cipher(in, out, in_len); + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_salsa.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_salsa.cpp new file mode 100644 index 0000000000..c1465a9bb5 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_salsa.cpp @@ -0,0 +1,124 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +int Sodium::crypto_core_hsalsa20(uint8_t out[], const uint8_t in[], + const uint8_t key[], const uint8_t c[]) + { + uint32_t in32[16] = { 0 }; + + static const uint32_t SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + if(c == nullptr) + { + in32[0] = SIGMA[0]; + in32[5] = SIGMA[1]; + in32[10] = SIGMA[2]; + in32[15] = SIGMA[3]; + } + else + { + in32[0] = load_le(c, 0); + in32[5] = load_le(c, 1); + in32[10] = load_le(c, 2); + in32[15] = load_le(c, 3); + } + + in32[1] = load_le(key, 0); + in32[2] = load_le(key, 1); + in32[3] = load_le(key, 2); + in32[4] = load_le(key, 3); + + in32[6] = load_le(in, 0); + in32[7] = load_le(in, 1); + in32[8] = load_le(in, 2); + in32[9] = load_le(in, 3); + + in32[11] = load_le(key, 4); + in32[12] = load_le(key, 5); + in32[13] = load_le(key, 6); + in32[14] = load_le(key, 7); + + uint32_t out32[8] = { 0 }; + Salsa20::hsalsa20(out32, in32); + + copy_out_le(out, 32, out32); + return 0; + } + +int Sodium::crypto_stream_salsa20(uint8_t out[], size_t out_len, + const uint8_t nonce[], const uint8_t key[]) + { + Salsa20 salsa; + salsa.set_key(key, crypto_stream_salsa20_KEYBYTES); + salsa.set_iv(nonce, crypto_stream_salsa20_NONCEBYTES); + salsa.write_keystream(out, out_len); + return 0; + } + +int Sodium::crypto_stream_salsa20_xor(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_stream_salsa20_xor_ic(out, in, in_len, nonce, 0, key); + } + +int Sodium::crypto_stream_salsa20_xor_ic(uint8_t out[], const uint8_t in[], + size_t in_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]) + { + if((ic >> 6) != 0) // otherwise multiply overflows + return -1; + + Salsa20 salsa; + salsa.set_key(key, crypto_stream_salsa20_KEYBYTES); + salsa.set_iv(nonce, crypto_stream_salsa20_NONCEBYTES); + salsa.seek(ic * 64); + salsa.cipher(in, out, in_len); + return 0; + } + +int Sodium::crypto_stream_xsalsa20(uint8_t out[], size_t out_len, + const uint8_t nonce[], const uint8_t key[]) + { + Salsa20 salsa; + salsa.set_key(key, crypto_stream_xsalsa20_KEYBYTES); + salsa.set_iv(nonce, crypto_stream_xsalsa20_NONCEBYTES); + salsa.write_keystream(out, out_len); + return 0; + } + +int Sodium::crypto_stream_xsalsa20_xor(uint8_t out[], const uint8_t in[], + size_t in_len, const uint8_t nonce[], + const uint8_t key[]) + { + return crypto_stream_xsalsa20_xor_ic(out, in, in_len, nonce, 0, key); + } + +int Sodium::crypto_stream_xsalsa20_xor_ic(uint8_t out[], const uint8_t in[], + size_t in_len, + const uint8_t nonce[], uint64_t ic, + const uint8_t key[]) + { + if((ic >> 6) != 0) // otherwise multiply overflows + return -1; + + Salsa20 salsa; + salsa.set_key(key, crypto_stream_xsalsa20_KEYBYTES); + salsa.set_iv(nonce, crypto_stream_xsalsa20_NONCEBYTES); + salsa.seek(ic * 64); + salsa.cipher(in, out, in_len); + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_secretbox.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_secretbox.cpp new file mode 100644 index 0000000000..255e0631b1 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_secretbox.cpp @@ -0,0 +1,123 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +int Sodium::crypto_secretbox_xsalsa20poly1305(uint8_t ctext[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t key[]) + { + if(ptext_len < 32) + return -1; + + auto salsa = StreamCipher::create_or_throw("Salsa20"); + salsa->set_key(key, crypto_secretbox_KEYBYTES); + salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); + + secure_vector auth_key(32); + salsa->write_keystream(auth_key.data(), auth_key.size()); + + salsa->cipher(ptext + 32, ctext + 32, ptext_len - 32); + + auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); + poly1305->set_key(auth_key); + poly1305->update(ctext + 32, ptext_len - 32); + poly1305->final(ctext + 16); + + clear_mem(ctext, 16); + return 0; + } + +int Sodium::crypto_secretbox_xsalsa20poly1305_open(uint8_t ptext[], + const uint8_t ctext[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t key[]) + { + if(ctext_len < crypto_box_curve25519xsalsa20poly1305_ZEROBYTES) + { + return -1; + } + + auto salsa = StreamCipher::create_or_throw("Salsa20"); + salsa->set_key(key, crypto_secretbox_KEYBYTES); + salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); + + secure_vector auth_key(32); + salsa->write_keystream(auth_key.data(), auth_key.size()); + + auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); + poly1305->set_key(auth_key); + poly1305->update(ctext + 32, ctext_len - 32); + secure_vector computed = poly1305->final(); + + if(!constant_time_compare(computed.data(), ctext + 16, 16)) + return -1; + + salsa->cipher(ctext + 32, ptext + 32, ctext_len - 32); + + clear_mem(ptext, 32); + return 0; + } + +int Sodium::crypto_secretbox_detached(uint8_t ctext[], uint8_t mac[], + const uint8_t ptext[], + size_t ptext_len, + const uint8_t nonce[], + const uint8_t key[]) + { + auto salsa = StreamCipher::create_or_throw("Salsa20"); + salsa->set_key(key, crypto_secretbox_KEYBYTES); + salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); + + secure_vector auth_key(32); + salsa->write_keystream(auth_key.data(), auth_key.size()); + + salsa->cipher(ptext, ctext, ptext_len); + + auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); + poly1305->set_key(auth_key); + poly1305->update(ctext, ptext_len); + poly1305->final(mac); + + return 0; + } + +int Sodium::crypto_secretbox_open_detached(uint8_t ptext[], + const uint8_t ctext[], + const uint8_t mac[], + size_t ctext_len, + const uint8_t nonce[], + const uint8_t key[]) + { + auto salsa = StreamCipher::create_or_throw("Salsa20"); + salsa->set_key(key, crypto_secretbox_KEYBYTES); + salsa->set_iv(nonce, crypto_secretbox_NONCEBYTES); + + secure_vector auth_key(32); + salsa->write_keystream(auth_key.data(), auth_key.size()); + + auto poly1305 = MessageAuthenticationCode::create_or_throw("Poly1305"); + poly1305->set_key(auth_key); + poly1305->update(ctext, ctext_len); + secure_vector computed_mac = poly1305->final(); + + if(!constant_time_compare(mac, computed_mac.data(), computed_mac.size())) + return -1; + + salsa->cipher(ctext, ptext, ctext_len); + + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/compat/sodium/sodium_utils.cpp b/comm/third_party/botan/src/lib/compat/sodium/sodium_utils.cpp new file mode 100644 index 0000000000..3f0a6c84e7 --- /dev/null +++ b/comm/third_party/botan/src/lib/compat/sodium/sodium_utils.cpp @@ -0,0 +1,160 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +void Sodium::randombytes_buf(void* buf, size_t len) + { + system_rng().randomize(static_cast(buf), len); + } + +uint32_t Sodium::randombytes_uniform(uint32_t upper_bound) + { + if(upper_bound <= 1) + return 0; + + // Not completely uniform + uint64_t x; + randombytes_buf(&x, sizeof(x)); + return x % upper_bound; + } + +void Sodium::randombytes_buf_deterministic(void* buf, size_t size, const uint8_t seed[randombytes_SEEDBYTES]) + { + const unsigned char nonce[12] = { + 'L', 'i', 'b', 's', 'o', 'd', 'i', 'u', 'm', 'D', 'R', 'G' + }; + + ChaCha chacha(20); + chacha.set_key(seed, randombytes_SEEDBYTES); + chacha.set_iv(nonce, sizeof(nonce)); + chacha.write_keystream(static_cast(buf), size); + } + +int Sodium::crypto_verify_16(const uint8_t x[16], const uint8_t y[16]) + { + return same_mem(x, y, 16); + } + +int Sodium::crypto_verify_32(const uint8_t x[32], const uint8_t y[32]) + { + return same_mem(x, y, 32); + } + +int Sodium::crypto_verify_64(const uint8_t x[64], const uint8_t y[64]) + { + return same_mem(x, y, 64); + } + +void Sodium::sodium_memzero(void* ptr, size_t len) + { + secure_scrub_memory(ptr, len); + } + +int Sodium::sodium_memcmp(const void* x, const void* y, size_t len) + { + const bool same = constant_time_compare(static_cast(x), static_cast(y), len); + return same ? 0 : -1; + } + +int Sodium::sodium_compare(const uint8_t x[], const uint8_t y[], size_t len) + { + const uint8_t LT = static_cast(-1); + const uint8_t EQ = 0; + const uint8_t GT = 1; + + uint8_t result = EQ; // until found otherwise + + for(size_t i = 0; i != len; ++i) + { + const auto is_eq = CT::Mask::is_equal(x[i], y[i]); + const auto is_lt = CT::Mask::is_lt(x[i], y[i]); + result = is_eq.select(result, is_lt.select(LT, GT)); + } + + return static_cast(result); + } + +int Sodium::sodium_is_zero(const uint8_t b[], size_t len) + { + uint8_t sum = 0; + for(size_t i = 0; i != len; ++i) + sum |= b[i]; + return static_cast(CT::Mask::expand(sum).if_not_set_return(1)); + } + +void Sodium::sodium_increment(uint8_t b[], size_t len) + { + uint8_t carry = 1; + for(size_t i = 0; i != len; ++i) + { + b[i] += carry; + carry &= (b[i] == 0); + } + } + +void Sodium::sodium_add(uint8_t a[], const uint8_t b[], size_t len) + { + uint8_t carry = 0; + for(size_t i = 0; i != len; ++i) + { + a[i] += b[i] + carry; + carry = (a[i] < b[i]); + } + } + +void* Sodium::sodium_malloc(size_t size) + { + const uint64_t len = size; + + if(size + sizeof(len) < size) + return nullptr; + + uint8_t* p = static_cast(std::calloc(size + sizeof(len), 1)); + store_le(len, p); + return p + 8; + } + +void Sodium::sodium_free(void* ptr) + { + if(ptr == nullptr) + return; + + uint8_t* p = static_cast(ptr) - 8; + const uint64_t len = load_le(p, 0); + secure_scrub_memory(ptr, static_cast(len)); + std::free(p); + } + +void* Sodium::sodium_allocarray(size_t count, size_t size) + { + const size_t bytes = count * size; + if(bytes < count || bytes < size) + return nullptr; + return sodium_malloc(bytes); + } + +int Sodium::sodium_mprotect_noaccess(void* ptr) + { + OS::page_prohibit_access(ptr); + return 0; + } + +int Sodium::sodium_mprotect_readwrite(void* ptr) + { + OS::page_allow_access(ptr); + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/compression/bzip2/bzip2.cpp b/comm/third_party/botan/src/lib/compression/bzip2/bzip2.cpp new file mode 100644 index 0000000000..c9dfc2ce82 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/bzip2/bzip2.cpp @@ -0,0 +1,110 @@ +/* +* Bzip2 Compressor +* (C) 2001 Peter J Jones +* 2001-2007,2014 Jack Lloyd +* 2006 Matt Johnston +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#define BZ_NO_STDIO +#include + +namespace Botan { + +namespace { + +class Bzip2_Stream : public Zlib_Style_Stream + { + public: + Bzip2_Stream() + { + streamp()->opaque = alloc(); + streamp()->bzalloc = Compression_Alloc_Info::malloc; + streamp()->bzfree = Compression_Alloc_Info::free; + } + + uint32_t run_flag() const override { return BZ_RUN; } + uint32_t flush_flag() const override { return BZ_FLUSH; } + uint32_t finish_flag() const override { return BZ_FINISH; } + }; + +class Bzip2_Compression_Stream final : public Bzip2_Stream + { + public: + explicit Bzip2_Compression_Stream(size_t block_size) + { + /* + * Defaults to 900k blocks as the computation cost of + * compression is not overly affected by the size, though + * more memory is required. + */ + if(block_size == 0 || block_size >= 9) + block_size = 9; + + int rc = BZ2_bzCompressInit(streamp(), block_size, 0, 0); + + if(rc != BZ_OK) + throw Compression_Error("BZ2_bzCompressInit", ErrorType::Bzip2Error, rc); + } + + ~Bzip2_Compression_Stream() + { + BZ2_bzCompressEnd(streamp()); + } + + bool run(uint32_t flags) override + { + int rc = BZ2_bzCompress(streamp(), flags); + + if(rc < 0) + throw Compression_Error("BZ2_bzCompress", ErrorType::Bzip2Error, rc); + + return (rc == BZ_STREAM_END); + } + }; + +class Bzip2_Decompression_Stream final : public Bzip2_Stream + { + public: + Bzip2_Decompression_Stream() + { + int rc = BZ2_bzDecompressInit(streamp(), 0, 0); + + if(rc != BZ_OK) + throw Compression_Error("BZ2_bzDecompressInit", ErrorType::Bzip2Error, rc); + } + + ~Bzip2_Decompression_Stream() + { + BZ2_bzDecompressEnd(streamp()); + } + + bool run(uint32_t) override + { + int rc = BZ2_bzDecompress(streamp()); + + if(rc != BZ_OK && rc != BZ_STREAM_END) + throw Compression_Error("BZ2_bzDecompress", ErrorType::Bzip2Error, rc); + + return (rc == BZ_STREAM_END); + } + }; + +} + +Compression_Stream* Bzip2_Compression::make_stream(size_t comp_level) const + { + return new Bzip2_Compression_Stream(comp_level); + } + +Compression_Stream* Bzip2_Decompression::make_stream() const + { + return new Bzip2_Decompression_Stream; + } + +} diff --git a/comm/third_party/botan/src/lib/compression/bzip2/bzip2.h b/comm/third_party/botan/src/lib/compression/bzip2/bzip2.h new file mode 100644 index 0000000000..e056d55021 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/bzip2/bzip2.h @@ -0,0 +1,40 @@ +/* +* Bzip2 Compressor +* (C) 2001 Peter J Jones +* 2001-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BZIP2_H_ +#define BOTAN_BZIP2_H_ + +#include + +namespace Botan { + +/** +* Bzip2 Compression +*/ +class BOTAN_PUBLIC_API(2,0) Bzip2_Compression final : public Stream_Compression + { + public: + std::string name() const override { return "Bzip2_Compression"; } + private: + Compression_Stream* make_stream(size_t comp_level) const override; + }; + +/** +* Bzip2 Deccompression +*/ +class BOTAN_PUBLIC_API(2,0) Bzip2_Decompression final : public Stream_Decompression + { + public: + std::string name() const override { return "Bzip2_Decompression"; } + private: + Compression_Stream* make_stream() const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/compression/bzip2/info.txt b/comm/third_party/botan/src/lib/compression/bzip2/info.txt new file mode 100644 index 0000000000..8826df2f96 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/bzip2/info.txt @@ -0,0 +1,9 @@ + +BZIP2 -> 20160412 + + +load_on vendor + + +all -> bz2 + diff --git a/comm/third_party/botan/src/lib/compression/compress_utils.cpp b/comm/third_party/botan/src/lib/compression/compress_utils.cpp new file mode 100644 index 0000000000..f49a0ede12 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/compress_utils.cpp @@ -0,0 +1,196 @@ +/* +* Compression Utils +* (C) 2014,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +void* Compression_Alloc_Info::do_malloc(size_t n, size_t size) + { + // TODO maximum length check here? + void* ptr = std::calloc(n, size); + + /* + * Return null rather than throwing here as we are being called by a + * C library and it may not be possible for an exception to unwind + * the call stack from here. The compression library is expecting a + * function written in C and a null return on error, which it will + * send upwards to the compression wrappers. + */ + + if(ptr) + { + m_current_allocs[ptr] = n * size; + } + + return ptr; + } + +void Compression_Alloc_Info::do_free(void* ptr) + { + if(ptr) + { + auto i = m_current_allocs.find(ptr); + + if(i == m_current_allocs.end()) + throw Internal_Error("Compression_Alloc_Info::free got pointer not allocated by us"); + + secure_scrub_memory(ptr, i->second); + std::free(ptr); + m_current_allocs.erase(i); + } + } + +void Stream_Compression::clear() + { + m_stream.reset(); + } + +void Stream_Compression::start(size_t level) + { + m_stream.reset(make_stream(level)); + } + +void Stream_Compression::process(secure_vector& buf, size_t offset, uint32_t flags) + { + BOTAN_ASSERT(m_stream, "Initialized"); + BOTAN_ASSERT(buf.size() >= offset, "Offset is sane"); + + // bzip doesn't like being called with no input and BZ_RUN + if(buf.size() == offset && flags == m_stream->run_flag()) + { + return; + } + + if(m_buffer.size() < buf.size() + offset) + m_buffer.resize(buf.size() + offset); + + // If the output buffer has zero length, .data() might return nullptr. This would + // make some compression algorithms (notably those provided by zlib) fail. + // Any small positive value works fine, but we choose 32 as it is the smallest power + // of two that is large enough to hold all the headers and trailers of the common + // formats, preventing further resizings to make room for output data. + if(m_buffer.size() == 0) + m_buffer.resize(32); + + m_stream->next_in(buf.data() + offset, buf.size() - offset); + m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset); + + while(true) + { + const bool stream_end = m_stream->run(flags); + + if(stream_end) + { + BOTAN_ASSERT(m_stream->avail_in() == 0, "After stream is done, no input remains to be processed"); + m_buffer.resize(m_buffer.size() - m_stream->avail_out()); + break; + } + else if(m_stream->avail_out() == 0) + { + const size_t added = 8 + m_buffer.size(); + m_buffer.resize(m_buffer.size() + added); + m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added); + } + else if(m_stream->avail_in() == 0) + { + m_buffer.resize(m_buffer.size() - m_stream->avail_out()); + break; + } + } + + copy_mem(m_buffer.data(), buf.data(), offset); + buf.swap(m_buffer); + } + +void Stream_Compression::update(secure_vector& buf, size_t offset, bool flush) + { + BOTAN_ASSERT(m_stream, "Initialized"); + process(buf, offset, flush ? m_stream->flush_flag() : m_stream->run_flag()); + } + +void Stream_Compression::finish(secure_vector& buf, size_t offset) + { + BOTAN_ASSERT(m_stream, "Initialized"); + process(buf, offset, m_stream->finish_flag()); + clear(); + } + +void Stream_Decompression::clear() + { + m_stream.reset(); + } + +void Stream_Decompression::start() + { + m_stream.reset(make_stream()); + } + +void Stream_Decompression::process(secure_vector& buf, size_t offset, uint32_t flags) + { + BOTAN_ASSERT(m_stream, "Initialized"); + BOTAN_ASSERT(buf.size() >= offset, "Offset is sane"); + + if(m_buffer.size() < buf.size() + offset) + m_buffer.resize(buf.size() + offset); + + m_stream->next_in(buf.data() + offset, buf.size() - offset); + m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset); + + while(true) + { + const bool stream_end = m_stream->run(flags); + + if(stream_end) + { + if(m_stream->avail_in() == 0) // all data consumed? + { + m_buffer.resize(m_buffer.size() - m_stream->avail_out()); + clear(); + break; + } + + // More data follows: try to process as a following stream + const size_t read = (buf.size() - offset) - m_stream->avail_in(); + start(); + m_stream->next_in(buf.data() + offset + read, buf.size() - offset - read); + } + + if(m_stream->avail_out() == 0) + { + const size_t added = 8 + m_buffer.size(); + m_buffer.resize(m_buffer.size() + added); + m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added); + } + else if(m_stream->avail_in() == 0) + { + m_buffer.resize(m_buffer.size() - m_stream->avail_out()); + break; + } + } + + copy_mem(m_buffer.data(), buf.data(), offset); + buf.swap(m_buffer); + } + +void Stream_Decompression::update(secure_vector& buf, size_t offset) + { + process(buf, offset, m_stream->run_flag()); + } + +void Stream_Decompression::finish(secure_vector& buf, size_t offset) + { + if(buf.size() != offset || m_stream.get()) + process(buf, offset, m_stream->finish_flag()); + + if(m_stream.get()) + throw Invalid_State(name() + " finished but not at stream end"); + } + +} diff --git a/comm/third_party/botan/src/lib/compression/compress_utils.h b/comm/third_party/botan/src/lib/compression/compress_utils.h new file mode 100644 index 0000000000..396fc47bed --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/compress_utils.h @@ -0,0 +1,89 @@ +/* +* Compression utility header +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_COMPRESSION_UTILS_H_ +#define BOTAN_COMPRESSION_UTILS_H_ + +#include +#include +#include + +namespace Botan { + +/* +* Allocation Size Tracking Helper for Zlib/Bzlib/LZMA +*/ +class Compression_Alloc_Info final + { + public: + template + static void* malloc(void* self, T n, T size) + { + return static_cast(self)->do_malloc(n, size); + } + + static void free(void* self, void* ptr) + { + static_cast(self)->do_free(ptr); + } + + private: + void* do_malloc(size_t n, size_t size); + void do_free(void* ptr); + + std::unordered_map m_current_allocs; + }; + +/** +* Wrapper for Zlib/Bzlib/LZMA stream types +*/ +template +class Zlib_Style_Stream : public Compression_Stream + { + public: + void next_in(uint8_t* b, size_t len) override + { + m_stream.next_in = reinterpret_cast(b); + m_stream.avail_in = len; + } + + void next_out(uint8_t* b, size_t len) override + { + m_stream.next_out = reinterpret_cast(b); + m_stream.avail_out = len; + } + + size_t avail_in() const override { return m_stream.avail_in; } + + size_t avail_out() const override { return m_stream.avail_out; } + + Zlib_Style_Stream() + { + clear_mem(&m_stream, 1); + m_allocs.reset(new Compression_Alloc_Info); + } + + ~Zlib_Style_Stream() + { + clear_mem(&m_stream, 1); + m_allocs.reset(); + } + + protected: + typedef Stream stream_t; + + stream_t* streamp() { return &m_stream; } + + Compression_Alloc_Info* alloc() { return m_allocs.get(); } + private: + stream_t m_stream; + std::unique_ptr m_allocs; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/compression/compression.cpp b/comm/third_party/botan/src/lib/compression/compression.cpp new file mode 100644 index 0000000000..361bf7dd3c --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/compression.cpp @@ -0,0 +1,116 @@ +/* +* Compression Factory +* (C) 2014,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_ZLIB) + #include +#endif + +#if defined(BOTAN_HAS_BZIP2) + #include +#endif + +#if defined(BOTAN_HAS_LZMA) + #include +#endif + +namespace Botan { + +Compression_Algorithm* make_compressor(const std::string& name) + { +#if defined(BOTAN_HAS_ZLIB) + if(name == "Zlib" || name == "zlib") + return new Zlib_Compression; + if(name == "Gzip" || name == "gzip" || name == "gz") + return new Gzip_Compression; + if(name == "Deflate" || name == "deflate") + return new Deflate_Compression; +#endif + +#if defined(BOTAN_HAS_BZIP2) + if(name == "bzip2" || name == "bz2" || name == "Bzip2") + return new Bzip2_Compression; +#endif + +#if defined(BOTAN_HAS_LZMA) + if(name == "lzma" || name == "xz" || name == "LZMA") + return new LZMA_Compression; +#endif + + BOTAN_UNUSED(name); + return nullptr; + } + +//static +std::unique_ptr +Compression_Algorithm::create(const std::string& algo) + { + std::unique_ptr compressor(make_compressor(algo)); + return compressor; + } + +//static +std::unique_ptr +Compression_Algorithm::create_or_throw(const std::string& algo) + { + if(auto compressor = Compression_Algorithm::create(algo)) + { + return compressor; + } + throw Lookup_Error("Compression", algo, ""); + } + +Decompression_Algorithm* make_decompressor(const std::string& name) + { +#if defined(BOTAN_HAS_ZLIB) + if(name == "Zlib" || name == "zlib") + return new Zlib_Decompression; + if(name == "Gzip" || name == "gzip" || name == "gz") + return new Gzip_Decompression; + if(name == "Deflate" || name == "deflate") + return new Deflate_Decompression; +#endif + +#if defined(BOTAN_HAS_BZIP2) + if(name == "bzip2" || name == "bz2" || name == "Bzip2") + return new Bzip2_Decompression; +#endif + +#if defined(BOTAN_HAS_LZMA) + if(name == "lzma" || name == "xz" || name == "LZMA") + return new LZMA_Decompression; +#endif + + BOTAN_UNUSED(name); + return nullptr; + } + +//static +std::unique_ptr +Decompression_Algorithm::create(const std::string& algo) + { + std::unique_ptr decompressor(make_decompressor(algo)); + return decompressor; + } + +//static +std::unique_ptr +Decompression_Algorithm::create_or_throw(const std::string& algo) + { + if(auto decompressor = Decompression_Algorithm::create(algo)) + { + return decompressor; + } + throw Lookup_Error("Decompression", algo, ""); + } + +} + diff --git a/comm/third_party/botan/src/lib/compression/compression.h b/comm/third_party/botan/src/lib/compression/compression.h new file mode 100644 index 0000000000..217fae623a --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/compression.h @@ -0,0 +1,238 @@ +/* +* Compression Transform +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_COMPRESSION_TRANSFORM_H_ +#define BOTAN_COMPRESSION_TRANSFORM_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Interface for a compression algorithm. +*/ +class BOTAN_PUBLIC_API(2,0) Compression_Algorithm + { + public: + /** + * Create an instance based on a name, or return null if the + * algo combination cannot be found. + */ + static std::unique_ptr + create(const std::string& algo_spec); + + /** + * Create an instance based on a name + * @param algo_spec algorithm name + * Throws Lookup_Error if not found. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec); + + /** + * Begin compressing. Most compression algorithms offer a tunable + * time/compression tradeoff parameter generally represented by + * an integer in the range of 1 to 9. + * + * If 0 or a value out of range is provided, a compression algorithm + * specific default is used. + */ + virtual void start(size_t comp_level = 0) = 0; + + /** + * Process some data. + * @param buf in/out parameter which will possibly be resized or swapped + * @param offset an offset into blocks to begin processing + * @param flush if true the compressor will be told to flush state + */ + virtual void update(secure_vector& buf, size_t offset = 0, bool flush = false) = 0; + + /** + * Finish compressing + * + * @param final_block in/out parameter + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector& final_block, size_t offset = 0) = 0; + + /** + * @return name of the compression algorithm + */ + virtual std::string name() const = 0; + + /** + * Reset the state and abort the current message; start can be + * called again to process a new message. + */ + virtual void clear() = 0; + + virtual ~Compression_Algorithm() = default; + }; + +/* +* Interface for a decompression algorithm. +*/ +class BOTAN_PUBLIC_API(2,0) Decompression_Algorithm + { + public: + /** + * Create an instance based on a name, or return null if the + * algo combination cannot be found. + */ + static std::unique_ptr + create(const std::string& algo_spec); + + /** + * Create an instance based on a name + * @param algo_spec algorithm name + * Throws Lookup_Error if not found. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec); + + /** + * Begin decompressing. + * Decompression does not support levels, as compression does. + */ + virtual void start() = 0; + + /** + * Process some data. + * @param buf in/out parameter which will possibly be resized or swapped + * @param offset an offset into blocks to begin processing + */ + virtual void update(secure_vector& buf, size_t offset = 0) = 0; + + /** + * Finish decompressing + * + * @param final_block in/out parameter + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector& final_block, size_t offset = 0) = 0; + + /** + * @return name of the decompression algorithm + */ + virtual std::string name() const = 0; + + /** + * Reset the state and abort the current message; start can be + * called again to process a new message. + */ + virtual void clear() = 0; + + virtual ~Decompression_Algorithm() = default; + }; + +BOTAN_PUBLIC_API(2,0) Compression_Algorithm* make_compressor(const std::string& type); +BOTAN_PUBLIC_API(2,0) Decompression_Algorithm* make_decompressor(const std::string& type); + +/** +* An error that occurred during compression (or decompression) +*/ +class BOTAN_PUBLIC_API(2,9) Compression_Error : public Exception + { + public: + + /** + * @param func_name the name of the compression API that was called + * (eg "BZ2_bzCompressInit" or "lzma_code") + * @param type what library this came from + * @param rc the error return code from the compression API. The + * interpretation of this value will depend on the library. + */ + Compression_Error(const char* func_name, ErrorType type, int rc) : + Exception("Compression API " + std::string(func_name) + + " failed with return code " + std::to_string(rc)), + m_type(type), + m_rc(rc) + {} + + ErrorType error_type() const noexcept override { return m_type; } + + int error_code() const noexcept override { return m_rc; } + + private: + ErrorType m_type; + int m_rc; + }; + +/** +* Adapts a zlib style API +*/ +class Compression_Stream + { + public: + virtual ~Compression_Stream() = default; + + virtual void next_in(uint8_t* b, size_t len) = 0; + + virtual void next_out(uint8_t* b, size_t len) = 0; + + virtual size_t avail_in() const = 0; + + virtual size_t avail_out() const = 0; + + virtual uint32_t run_flag() const = 0; + virtual uint32_t flush_flag() const = 0; + virtual uint32_t finish_flag() const = 0; + + virtual bool run(uint32_t flags) = 0; + }; + +/** +* Used to implement compression using Compression_Stream +*/ +class Stream_Compression : public Compression_Algorithm + { + public: + void update(secure_vector& buf, size_t offset, bool flush) final override; + + void finish(secure_vector& buf, size_t offset) final override; + + void clear() final override; + + private: + void start(size_t level) final override; + + void process(secure_vector& buf, size_t offset, uint32_t flags); + + virtual Compression_Stream* make_stream(size_t level) const = 0; + + secure_vector m_buffer; + std::unique_ptr m_stream; + }; + +/** +* FIXME add doc +*/ +class Stream_Decompression : public Decompression_Algorithm + { + public: + void update(secure_vector& buf, size_t offset) final override; + + void finish(secure_vector& buf, size_t offset) final override; + + void clear() final override; + + private: + void start() final override; + + void process(secure_vector& buf, size_t offset, uint32_t flags); + + virtual Compression_Stream* make_stream() const = 0; + + secure_vector m_buffer; + std::unique_ptr m_stream; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/compression/info.txt b/comm/third_party/botan/src/lib/compression/info.txt new file mode 100644 index 0000000000..fade2e51aa --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/info.txt @@ -0,0 +1,11 @@ + +COMPRESSION -> 20141117 + + + +compress_utils.h + + + +compression.h + diff --git a/comm/third_party/botan/src/lib/compression/lzma/info.txt b/comm/third_party/botan/src/lib/compression/lzma/info.txt new file mode 100644 index 0000000000..477a7b7951 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/lzma/info.txt @@ -0,0 +1,9 @@ + +LZMA -> 20160412 + + +load_on vendor + + +all -> lzma + diff --git a/comm/third_party/botan/src/lib/compression/lzma/lzma.cpp b/comm/third_party/botan/src/lib/compression/lzma/lzma.cpp new file mode 100644 index 0000000000..73bb9eb89f --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/lzma/lzma.cpp @@ -0,0 +1,95 @@ +/* +* Lzma Compressor +* (C) 2001 Peter J Jones +* 2001-2007,2014 Jack Lloyd +* 2006 Matt Johnston +* 2012 Vojtech Kral +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class LZMA_Stream : public Zlib_Style_Stream + { + public: + LZMA_Stream() + { + m_allocator.opaque = alloc(); + m_allocator.alloc = Compression_Alloc_Info::malloc; + m_allocator.free = Compression_Alloc_Info::free; + streamp()->allocator = &m_allocator; + } + + ~LZMA_Stream() + { + ::lzma_end(streamp()); + } + + bool run(uint32_t flags) override + { + lzma_ret rc = ::lzma_code(streamp(), static_cast(flags)); + + if(rc != LZMA_OK && rc != LZMA_STREAM_END) + throw Compression_Error("lzma_code", ErrorType::LzmaError, rc); + + return (rc == LZMA_STREAM_END); + } + + uint32_t run_flag() const override { return LZMA_RUN; } + uint32_t flush_flag() const override { return LZMA_FULL_FLUSH; } + uint32_t finish_flag() const override { return LZMA_FINISH; } + private: + ::lzma_allocator m_allocator; + }; + +class LZMA_Compression_Stream final : public LZMA_Stream + { + public: + explicit LZMA_Compression_Stream(size_t level) + { + if(level == 0) + level = 6; // default + else if(level > 9) + level = 9; // clamp to maximum allowed value + + lzma_ret rc = ::lzma_easy_encoder(streamp(), level, LZMA_CHECK_CRC64); + + if(rc != LZMA_OK) + throw Compression_Error("lzam_easy_encoder", ErrorType::LzmaError, rc); + } + }; + +class LZMA_Decompression_Stream final : public LZMA_Stream + { + public: + LZMA_Decompression_Stream() + { + lzma_ret rc = ::lzma_stream_decoder(streamp(), UINT64_MAX, + LZMA_TELL_UNSUPPORTED_CHECK); + + if(rc != LZMA_OK) + throw Compression_Error("lzma_stream_decoder", ErrorType::LzmaError, rc); + } + }; + +} + +Compression_Stream* LZMA_Compression::make_stream(size_t level) const + { + return new LZMA_Compression_Stream(level); + } + +Compression_Stream* LZMA_Decompression::make_stream() const + { + return new LZMA_Decompression_Stream; + } + +} diff --git a/comm/third_party/botan/src/lib/compression/lzma/lzma.h b/comm/third_party/botan/src/lib/compression/lzma/lzma.h new file mode 100644 index 0000000000..02a1f8c8da --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/lzma/lzma.h @@ -0,0 +1,42 @@ +/* +* Lzma Compressor +* (C) 2001 Peter J Jones +* 2001-2007 Jack Lloyd +* 2012 Vojtech Kral +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LZMA_H_ +#define BOTAN_LZMA_H_ + +#include + +namespace Botan { + +/** +* LZMA Compression +*/ +class BOTAN_PUBLIC_API(2,0) LZMA_Compression final : public Stream_Compression + { + public: + std::string name() const override { return "LZMA_Compression"; } + + private: + Compression_Stream* make_stream(size_t level) const override; + }; + +/** +* LZMA Deccompression +*/ +class BOTAN_PUBLIC_API(2,0) LZMA_Decompression final : public Stream_Decompression + { + public: + std::string name() const override { return "LZMA_Decompression"; } + private: + Compression_Stream* make_stream() const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/compression/zlib/info.txt b/comm/third_party/botan/src/lib/compression/zlib/info.txt new file mode 100644 index 0000000000..1102bc5e1e --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/zlib/info.txt @@ -0,0 +1,10 @@ + +ZLIB -> 20160412 + + +load_on vendor + + +all!windows -> z +windows -> zlib + diff --git a/comm/third_party/botan/src/lib/compression/zlib/zlib.cpp b/comm/third_party/botan/src/lib/compression/zlib/zlib.cpp new file mode 100644 index 0000000000..285bc4e916 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/zlib/zlib.cpp @@ -0,0 +1,173 @@ +/* +* Zlib Compressor +* (C) 2001 Peter J Jones +* 2001-2007,2014 Jack Lloyd +* 2006 Matt Johnston +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class Zlib_Stream : public Zlib_Style_Stream + { + public: + Zlib_Stream() + { + streamp()->opaque = alloc(); + streamp()->zalloc = Compression_Alloc_Info::malloc; + streamp()->zfree = Compression_Alloc_Info::free; + } + + uint32_t run_flag() const override { return Z_NO_FLUSH; } + uint32_t flush_flag() const override { return Z_SYNC_FLUSH; } + uint32_t finish_flag() const override { return Z_FINISH; } + + int compute_window_bits(int wbits, int wbits_offset) const + { + if(wbits_offset == -1) + return -wbits; + else + return wbits + wbits_offset; + } + }; + +class Zlib_Compression_Stream : public Zlib_Stream + { + public: + Zlib_Compression_Stream(size_t level, int wbits, int wbits_offset = 0) + { + wbits = compute_window_bits(wbits, wbits_offset); + + if(level >= 9) + level = 9; + else if(level == 0) + level = 6; + + int rc = ::deflateInit2(streamp(), level, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); + + if(rc != Z_OK) + throw Compression_Error("deflateInit2", ErrorType::ZlibError, rc); + } + + ~Zlib_Compression_Stream() + { + ::deflateEnd(streamp()); + } + + bool run(uint32_t flags) override + { + int rc = ::deflate(streamp(), flags); + + if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) + throw Compression_Error("zlib deflate", ErrorType::ZlibError, rc); + + return (rc == Z_STREAM_END); + } + }; + +class Zlib_Decompression_Stream : public Zlib_Stream + { + public: + Zlib_Decompression_Stream(int wbits, int wbits_offset = 0) + { + int rc = ::inflateInit2(streamp(), compute_window_bits(wbits, wbits_offset)); + + if(rc != Z_OK) + throw Compression_Error("inflateInit2", ErrorType::ZlibError, rc); + } + + ~Zlib_Decompression_Stream() + { + ::inflateEnd(streamp()); + } + + bool run(uint32_t flags) override + { + int rc = ::inflate(streamp(), flags); + + if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) + throw Compression_Error("zlib inflate", ErrorType::ZlibError, rc); + + return (rc == Z_STREAM_END); + } + }; + +class Deflate_Compression_Stream final : public Zlib_Compression_Stream + { + public: + Deflate_Compression_Stream(size_t level, int wbits) : + Zlib_Compression_Stream(level, wbits, -1) {} + }; + +class Deflate_Decompression_Stream final : public Zlib_Decompression_Stream + { + public: + explicit Deflate_Decompression_Stream(int wbits) : Zlib_Decompression_Stream(wbits, -1) {} + }; + +class Gzip_Compression_Stream final : public Zlib_Compression_Stream + { + public: + Gzip_Compression_Stream(size_t level, int wbits, uint8_t os_code, uint64_t hdr_time) : + Zlib_Compression_Stream(level, wbits, 16) + { + clear_mem(&m_header, 1); + m_header.os = os_code; + m_header.time = static_cast(hdr_time); + + int rc = deflateSetHeader(streamp(), &m_header); + if(rc != Z_OK) + throw Compression_Error("deflateSetHeader", ErrorType::ZlibError, rc); + } + + private: + ::gz_header m_header; + }; + +class Gzip_Decompression_Stream final : public Zlib_Decompression_Stream + { + public: + explicit Gzip_Decompression_Stream(int wbits) : Zlib_Decompression_Stream(wbits, 16) {} + }; + +} + +Compression_Stream* Zlib_Compression::make_stream(size_t level) const + { + return new Zlib_Compression_Stream(level, 15); + } + +Compression_Stream* Zlib_Decompression::make_stream() const + { + return new Zlib_Decompression_Stream(15); + } + +Compression_Stream* Deflate_Compression::make_stream(size_t level) const + { + return new Deflate_Compression_Stream(level, 15); + } + +Compression_Stream* Deflate_Decompression::make_stream() const + { + return new Deflate_Decompression_Stream(15); + } + +Compression_Stream* Gzip_Compression::make_stream(size_t level) const + { + return new Gzip_Compression_Stream(level, 15, m_os_code, m_hdr_time); + } + +Compression_Stream* Gzip_Decompression::make_stream() const + { + return new Gzip_Decompression_Stream(15); + } + +} diff --git a/comm/third_party/botan/src/lib/compression/zlib/zlib.h b/comm/third_party/botan/src/lib/compression/zlib/zlib.h new file mode 100644 index 0000000000..cc00603446 --- /dev/null +++ b/comm/third_party/botan/src/lib/compression/zlib/zlib.h @@ -0,0 +1,89 @@ +/* +* Zlib Compressor +* (C) 2001 Peter J Jones +* 2001-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ZLIB_H_ +#define BOTAN_ZLIB_H_ + +#include + +namespace Botan { + +/** +* Zlib Compression +*/ +class BOTAN_PUBLIC_API(2,0) Zlib_Compression final : public Stream_Compression + { + public: + std::string name() const override { return "Zlib_Compression"; } + private: + Compression_Stream* make_stream(size_t level) const override; + }; + +/** +* Zlib Decompression +*/ +class BOTAN_PUBLIC_API(2,0) Zlib_Decompression final : public Stream_Decompression + { + public: + std::string name() const override { return "Zlib_Decompression"; } + private: + Compression_Stream* make_stream() const override; + }; + +/** +* Deflate Compression +*/ +class BOTAN_PUBLIC_API(2,0) Deflate_Compression final : public Stream_Compression + { + public: + std::string name() const override { return "Deflate_Compression"; } + private: + Compression_Stream* make_stream(size_t level) const override; + }; + +/** +* Deflate Decompression +*/ +class BOTAN_PUBLIC_API(2,0) Deflate_Decompression final : public Stream_Decompression + { + public: + std::string name() const override { return "Deflate_Decompression"; } + private: + Compression_Stream* make_stream() const override; + }; + +/** +* Gzip Compression +*/ +class BOTAN_PUBLIC_API(2,0) Gzip_Compression final : public Stream_Compression + { + public: + explicit Gzip_Compression(uint8_t os_code = 255, uint64_t hdr_time = 0) : + m_hdr_time(hdr_time), m_os_code(os_code) {} + + std::string name() const override { return "Gzip_Compression"; } + private: + Compression_Stream* make_stream(size_t level) const override; + const uint64_t m_hdr_time; + const uint8_t m_os_code; + }; + +/** +* Gzip Decompression +*/ +class BOTAN_PUBLIC_API(2,0) Gzip_Decompression final : public Stream_Decompression + { + public: + std::string name() const override { return "Gzip_Decompression"; } + private: + Compression_Stream* make_stream() const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/dev_random/dev_random.cpp b/comm/third_party/botan/src/lib/entropy/dev_random/dev_random.cpp new file mode 100644 index 0000000000..44fcbace3f --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/dev_random/dev_random.cpp @@ -0,0 +1,122 @@ +/* +* Reader of /dev/random and company +* (C) 1999-2009,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +Device_EntropySource constructor +Open a file descriptor to each (available) device in fsnames +*/ +Device_EntropySource::Device_EntropySource(const std::vector& fsnames) + { +#ifndef O_NONBLOCK + #define O_NONBLOCK 0 +#endif + +#ifndef O_NOCTTY + #define O_NOCTTY 0 +#endif + + const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; + + m_max_fd = 0; + + for(auto fsname : fsnames) + { + int fd = ::open(fsname.c_str(), flags); + + if(fd < 0) + { + /* + ENOENT or EACCES is normal as some of the named devices may not exist + on this system. But any other errno value probably indicates + either a bug in the application or file descriptor exhaustion. + */ + if(errno != ENOENT && errno != EACCES) + throw System_Error("Opening OS RNG device failed", errno); + } + else + { + if(fd > FD_SETSIZE) + { + ::close(fd); + throw Invalid_State("Open of OS RNG succeeded but returned fd is too large for fd_set"); + } + + m_dev_fds.push_back(fd); + m_max_fd = std::max(m_max_fd, fd); + } + } + } + +/** +Device_EntropySource destructor: close all open devices +*/ +Device_EntropySource::~Device_EntropySource() + { + for(int fd : m_dev_fds) + { + // ignoring return value here, can't throw in destructor anyway + ::close(fd); + } + } + +/** +* Gather entropy from a RNG device +*/ +size_t Device_EntropySource::poll(RandomNumberGenerator& rng) + { + size_t bits = 0; + + if(m_dev_fds.size() > 0) + { + fd_set read_set; + FD_ZERO(&read_set); + + for(int dev_fd : m_dev_fds) + { + FD_SET(dev_fd, &read_set); + } + + secure_vector io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST); + + struct ::timeval timeout; + timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000); + timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000; + + if(::select(m_max_fd + 1, &read_set, nullptr, nullptr, &timeout) > 0) + { + for(int dev_fd : m_dev_fds) + { + if(FD_ISSET(dev_fd, &read_set)) + { + const ssize_t got = ::read(dev_fd, io_buf.data(), io_buf.size()); + + if(got > 0) + { + rng.add_entropy(io_buf.data(), static_cast(got)); + bits += got * 8; + } + } + } + } + } + + return bits; + } + +} diff --git a/comm/third_party/botan/src/lib/entropy/dev_random/dev_random.h b/comm/third_party/botan/src/lib/entropy/dev_random/dev_random.h new file mode 100644 index 0000000000..6195f85648 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/dev_random/dev_random.h @@ -0,0 +1,37 @@ +/* +* /dev/random EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_DEVICE_H_ +#define BOTAN_ENTROPY_SRC_DEVICE_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Entropy source reading from kernel devices like /dev/random +*/ +class Device_EntropySource final : public Entropy_Source + { + public: + std::string name() const override { return "dev_random"; } + + size_t poll(RandomNumberGenerator& rng) override; + + explicit Device_EntropySource(const std::vector& fsnames); + + ~Device_EntropySource(); + private: + std::vector m_dev_fds; + int m_max_fd; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/dev_random/info.txt b/comm/third_party/botan/src/lib/entropy/dev_random/info.txt new file mode 100644 index 0000000000..3872411f30 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/dev_random/info.txt @@ -0,0 +1,11 @@ + +ENTROPY_SRC_DEV_RANDOM -> 20131128 + + + +dev_random.h + + + +dev_random,posix1 + diff --git a/comm/third_party/botan/src/lib/entropy/entropy_src.h b/comm/third_party/botan/src/lib/entropy/entropy_src.h new file mode 100644 index 0000000000..56e5bd53e5 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/entropy_src.h @@ -0,0 +1,87 @@ +/* +* EntropySource +* (C) 2008,2009,2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_H_ +#define BOTAN_ENTROPY_H_ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Abstract interface to a source of entropy +*/ +class BOTAN_PUBLIC_API(2,0) Entropy_Source + { + public: + /** + * Return a new entropy source of a particular type, or null + * Each entropy source may require substantial resources (eg, a file handle + * or socket instance), so try to share them among multiple RNGs, or just + * use the preconfigured global list accessed by Entropy_Sources::global_sources() + */ + static std::unique_ptr create(const std::string& type); + + /** + * @return name identifying this entropy source + */ + virtual std::string name() const = 0; + + /** + * Perform an entropy gathering poll + * @param rng will be provided with entropy via calls to add_entropy + * @return conservative estimate of actual entropy added to rng during poll + */ + virtual size_t poll(RandomNumberGenerator& rng) = 0; + + Entropy_Source() = default; + Entropy_Source(const Entropy_Source& other) = delete; + Entropy_Source(Entropy_Source&& other) = delete; + Entropy_Source& operator=(const Entropy_Source& other) = delete; + + virtual ~Entropy_Source() = default; + }; + +class BOTAN_PUBLIC_API(2,0) Entropy_Sources final + { + public: + static Entropy_Sources& global_sources(); + + void add_source(std::unique_ptr src); + + std::vector enabled_sources() const; + + size_t poll(RandomNumberGenerator& rng, + size_t bits, + std::chrono::milliseconds timeout); + + /** + * Poll just a single named source. Ordinally only used for testing + */ + size_t poll_just(RandomNumberGenerator& rng, const std::string& src); + + Entropy_Sources() = default; + explicit Entropy_Sources(const std::vector& sources); + + Entropy_Sources(const Entropy_Sources& other) = delete; + Entropy_Sources(Entropy_Sources&& other) = delete; + Entropy_Sources& operator=(const Entropy_Sources& other) = delete; + + private: + std::vector> m_srcs; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/entropy_srcs.cpp b/comm/third_party/botan/src/lib/entropy/entropy_srcs.cpp new file mode 100644 index 0000000000..e6573e2963 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/entropy_srcs.cpp @@ -0,0 +1,235 @@ +/* +* Entropy Source Polling +* (C) 2008-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DARN) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) + #include + #include +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_SYSTEM_RNG) + +class System_RNG_EntropySource final : public Entropy_Source + { + public: + size_t poll(RandomNumberGenerator& rng) override + { + const size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS; + rng.reseed_from_rng(system_rng(), poll_bits); + return poll_bits; + } + + std::string name() const override { return "system_rng"; } + }; + +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + +class Processor_RNG_EntropySource final : public Entropy_Source + { + public: + size_t poll(RandomNumberGenerator& rng) override + { + /* + * Intel's documentation for RDRAND at + * https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide + * claims that software can guarantee a reseed event by polling enough data: + * "There is an upper bound of 511 samples per seed in the implementation + * where samples are 128 bits in size and can provide two 64-bit random + * numbers each." + * + * By requesting 65536 bits we are asking for 512 samples and thus are assured + * that at some point in producing the output, at least one reseed of the + * internal state will occur. + * + * The reseeding conditions of the POWER and ARM processor RNGs are not known + * but probably work in a somewhat similar manner. The exact amount requested + * may be tweaked if and when such conditions become publically known. + */ + const size_t poll_bits = 65536; + rng.reseed_from_rng(m_hwrng, poll_bits); + // Avoid trusting a black box, don't count this as contributing entropy: + return 0; + } + + std::string name() const override { return m_hwrng.name(); } + private: + Processor_RNG m_hwrng; + }; + +#endif + +} + +std::unique_ptr Entropy_Source::create(const std::string& name) + { +#if defined(BOTAN_HAS_SYSTEM_RNG) + if(name == "system_rng" || name == "win32_cryptoapi") + { + return std::unique_ptr(new System_RNG_EntropySource); + } +#endif + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + if(name == "hwrng" || name == "rdrand" || name == "p9_darn") + { + if(Processor_RNG::available()) + { + return std::unique_ptr(new Processor_RNG_EntropySource); + } + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED) + if(name == "rdseed") + { + return std::unique_ptr(new Intel_Rdseed); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) + if(name == "getentropy") + { + return std::unique_ptr(new Getentropy); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + if(name == "dev_random") + { + return std::unique_ptr(new Device_EntropySource(BOTAN_SYSTEM_RNG_POLL_DEVICES)); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) + if(name == "proc_walk" && OS::running_in_privileged_state() == false) + { + const std::string root_dir = BOTAN_ENTROPY_PROC_FS_PATH; + if(!root_dir.empty()) + return std::unique_ptr(new ProcWalking_EntropySource(root_dir)); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + if(name == "system_stats") + { + return std::unique_ptr(new Win32_EntropySource); + } +#endif + + BOTAN_UNUSED(name); + return std::unique_ptr(); + } + +void Entropy_Sources::add_source(std::unique_ptr src) + { + if(src.get()) + { + m_srcs.push_back(std::move(src)); + } + } + +std::vector Entropy_Sources::enabled_sources() const + { + std::vector sources; + for(size_t i = 0; i != m_srcs.size(); ++i) + { + sources.push_back(m_srcs[i]->name()); + } + return sources; + } + +size_t Entropy_Sources::poll(RandomNumberGenerator& rng, + size_t poll_bits, + std::chrono::milliseconds timeout) + { + typedef std::chrono::system_clock clock; + + auto deadline = clock::now() + timeout; + + size_t bits_collected = 0; + + for(size_t i = 0; i != m_srcs.size(); ++i) + { + bits_collected += m_srcs[i]->poll(rng); + + if (bits_collected >= poll_bits || clock::now() > deadline) + break; + } + + return bits_collected; + } + +size_t Entropy_Sources::poll_just(RandomNumberGenerator& rng, const std::string& the_src) + { + for(size_t i = 0; i != m_srcs.size(); ++i) + { + if(m_srcs[i]->name() == the_src) + { + return m_srcs[i]->poll(rng); + } + } + + return 0; + } + +Entropy_Sources::Entropy_Sources(const std::vector& sources) + { + for(auto&& src_name : sources) + { + add_source(Entropy_Source::create(src_name)); + } + } + +Entropy_Sources& Entropy_Sources::global_sources() + { + static Entropy_Sources global_entropy_sources(BOTAN_ENTROPY_DEFAULT_SOURCES); + + return global_entropy_sources; + } + +} + diff --git a/comm/third_party/botan/src/lib/entropy/getentropy/getentropy.cpp b/comm/third_party/botan/src/lib/entropy/getentropy/getentropy.cpp new file mode 100644 index 0000000000..7e87367a20 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/getentropy/getentropy.cpp @@ -0,0 +1,35 @@ +/* +* System Call getentropy(2) +* (C) 2017 Alexander Bluhm (genua GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) || defined(BOTAN_TARGET_OS_IS_FREEBSD) + #include +#else + #include +#endif + +namespace Botan { + +/** +* Gather 256 bytes entropy from getentropy(2). Note that maximum +* buffer size is limited to 256 bytes. On OpenBSD this does neither +* block nor fail. +*/ +size_t Getentropy::poll(RandomNumberGenerator& rng) + { + secure_vector buf(256); + + if(::getentropy(buf.data(), buf.size()) == 0) + { + rng.add_entropy(buf.data(), buf.size()); + return buf.size() * 8; + } + + return 0; + } +} diff --git a/comm/third_party/botan/src/lib/entropy/getentropy/getentropy.h b/comm/third_party/botan/src/lib/entropy/getentropy/getentropy.h new file mode 100644 index 0000000000..26783cf78a --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/getentropy/getentropy.h @@ -0,0 +1,28 @@ +/* +* Entropy Source Using OpenBSD getentropy(2) system call +* (C) 2017 Alexander Bluhm (genua GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_GETENTROPY_H_ +#define BOTAN_ENTROPY_SRC_GETENTROPY_H_ + +#include + +namespace Botan { + +/** +* Entropy source using the getentropy(2) system call first introduced in +* OpenBSD 5.6 and added to Solaris 11.3. +*/ +class Getentropy final : public Entropy_Source + { + public: + std::string name() const override { return "getentropy"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/getentropy/info.txt b/comm/third_party/botan/src/lib/entropy/getentropy/info.txt new file mode 100644 index 0000000000..886e57151f --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/getentropy/info.txt @@ -0,0 +1,11 @@ + +ENTROPY_SRC_GETENTROPY -> 20170327 + + + +getentropy.h + + + +getentropy + diff --git a/comm/third_party/botan/src/lib/entropy/info.txt b/comm/third_party/botan/src/lib/entropy/info.txt new file mode 100644 index 0000000000..57f1930b99 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/info.txt @@ -0,0 +1,7 @@ + +ENTROPY_SOURCE -> 20151120 + + + +rng + diff --git a/comm/third_party/botan/src/lib/entropy/proc_walk/info.txt b/comm/third_party/botan/src/lib/entropy/proc_walk/info.txt new file mode 100644 index 0000000000..2bba7e276b --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/proc_walk/info.txt @@ -0,0 +1,11 @@ + +ENTROPY_SRC_PROC_WALKER -> 20131128 + + + +proc_walk.h + + + +posix1,proc_fs + diff --git a/comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.cpp b/comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.cpp new file mode 100644 index 0000000000..d780cbf739 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.cpp @@ -0,0 +1,154 @@ +/* +* Entropy source based on reading files in /proc on the assumption +* that a remote attacker will have difficulty guessing some of them. +* +* (C) 1999-2008,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309 +#endif + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class Directory_Walker final : public File_Descriptor_Source + { + public: + explicit Directory_Walker(const std::string& root) : + m_cur_dir(std::make_pair(nullptr, "")) + { + if(DIR* root_dir = ::opendir(root.c_str())) + m_cur_dir = std::make_pair(root_dir, root); + } + + ~Directory_Walker() + { + if(m_cur_dir.first) + ::closedir(m_cur_dir.first); + } + + int next_fd() override; + private: + std::pair get_next_dirent(); + + std::pair m_cur_dir; + std::deque m_dirlist; + }; + +std::pair Directory_Walker::get_next_dirent() + { + while(m_cur_dir.first) + { + if(struct dirent* dir = ::readdir(m_cur_dir.first)) + return std::make_pair(dir, m_cur_dir.second); + + ::closedir(m_cur_dir.first); + m_cur_dir = std::make_pair(nullptr, ""); + + while(!m_dirlist.empty() && !m_cur_dir.first) + { + const std::string next_dir_name = m_dirlist[0]; + m_dirlist.pop_front(); + + if(DIR* next_dir = ::opendir(next_dir_name.c_str())) + m_cur_dir = std::make_pair(next_dir, next_dir_name); + } + } + + return std::make_pair(nullptr, ""); // nothing left + } + +int Directory_Walker::next_fd() + { + while(true) + { + std::pair entry = get_next_dirent(); + + if(!entry.first) + break; // no more dirs + + const std::string filename = entry.first->d_name; + + if(filename == "." || filename == "..") + continue; + + const std::string full_path = entry.second + "/" + filename; + + struct stat stat_buf; + if(::lstat(full_path.c_str(), &stat_buf) == -1) + continue; + + if(S_ISDIR(stat_buf.st_mode)) + { + m_dirlist.push_back(full_path); + } + else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH)) + { + int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY); + + if(fd >= 0) + return fd; + } + } + + return -1; + } + +} + +size_t ProcWalking_EntropySource::poll(RandomNumberGenerator& rng) + { + const size_t MAX_FILES_READ_PER_POLL = 2048; + + lock_guard_type lock(m_mutex); + + if(!m_dir) + m_dir.reset(new Directory_Walker(m_path)); + + m_buf.resize(4096); + + size_t bits = 0; + + for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i) + { + int fd = m_dir->next_fd(); + + // If we've exhaused this walk of the directory, halt the poll + if(fd == -1) + { + m_dir.reset(); + break; + } + + ssize_t got = ::read(fd, m_buf.data(), m_buf.size()); + ::close(fd); + + if(got > 0) + { + rng.add_entropy(m_buf.data(), static_cast(got)); + + // Conservative estimate of 4 bits per file + bits += 4; + } + + if(bits > 128) + break; + } + + return bits; + } + +} diff --git a/comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.h b/comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.h new file mode 100644 index 0000000000..4c5013d29c --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/proc_walk/proc_walk.h @@ -0,0 +1,45 @@ +/* +* File Tree Walking EntropySource +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_PROC_WALK_H_ +#define BOTAN_ENTROPY_SRC_PROC_WALK_H_ + +#include +#include + +namespace Botan { + +class File_Descriptor_Source + { + public: + virtual int next_fd() = 0; + virtual ~File_Descriptor_Source() = default; + }; + +/** +* File Tree Walking Entropy Source +*/ +class ProcWalking_EntropySource final : public Entropy_Source + { + public: + std::string name() const override { return "proc_walk"; } + + size_t poll(RandomNumberGenerator& rng) override; + + explicit ProcWalking_EntropySource(const std::string& root_dir) : + m_path(root_dir), m_dir(nullptr) {} + + private: + const std::string m_path; + mutex_type m_mutex; + std::unique_ptr m_dir; + secure_vector m_buf; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/rdseed/info.txt b/comm/third_party/botan/src/lib/entropy/rdseed/info.txt new file mode 100644 index 0000000000..ee822ad7c0 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/rdseed/info.txt @@ -0,0 +1,19 @@ + +ENTROPY_SRC_RDSEED -> 20151218 + + + +rdseed +sse2 # for mm_pause see #2139 + + + +rdseed.h + + + +gcc +clang +icc +msvc + diff --git a/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp b/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp new file mode 100644 index 0000000000..1830edf9de --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.cpp @@ -0,0 +1,97 @@ +/* +* Entropy Source Using Intel's rdseed instruction +* (C) 2015 Daniel Neus +* (C) 2015,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include + +namespace Botan { + +namespace { + +BOTAN_FUNC_ISA("rdseed") +bool read_rdseed(secure_vector& seed) + { + /* + * RDSEED is not guaranteed to generate an output within any specific number + * of attempts. However in testing on a Skylake system, with all hyperthreads + * occupied in tight RDSEED loops, RDSEED will still usually succeed in under + * 150 attempts. The maximum ever seen was 230 attempts until success. When + * idle, RDSEED usually succeeds in 1 or 2 attempts. + * + * We set an upper bound of 512 attempts, because it is possible that due + * to firmware issue RDSEED is simply broken and never succeeds. We do not + * want to loop forever in that case. If we exceed that limit, then we assume + * the hardware is actually just broken, and stop the poll. + */ + const size_t RDSEED_RETRIES = 512; + + for(size_t i = 0; i != RDSEED_RETRIES; ++i) + { + uint32_t r = 0; + int cf = 0; + +#if defined(BOTAN_USE_GCC_INLINE_ASM) + asm("rdseed %0; adcl $0,%1" : + "=r" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); +#else + cf = _rdseed32_step(&r); +#endif + + if(1 == cf) + { + seed.push_back(r); + return true; + } + + // Intel suggests pausing if RDSEED fails. + _mm_pause(); + } + + return false; // failed to produce an output after many attempts + } + +} + +size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) + { + const size_t RDSEED_BYTES = 1024; + static_assert(RDSEED_BYTES % 4 == 0, "Bad RDSEED configuration"); + + if(CPUID::has_rdseed()) + { + secure_vector seed; + seed.reserve(RDSEED_BYTES / 4); + + for(size_t p = 0; p != RDSEED_BYTES / 4; ++p) + { + /* + If at any point we exceed our retry count, we stop the entire seed + gathering process. This situation will only occur in situations of + extremely high RDSEED utilization. If RDSEED is currently so highly + contended, then the rest of the poll is likely to also face contention and + it is better to quit now rather than (presumably) face very high retry + times for the rest of the poll. + */ + if(!read_rdseed(seed)) + break; + } + + if(seed.size() > 0) + { + rng.add_entropy(reinterpret_cast(seed.data()), + seed.size() * sizeof(uint32_t)); + } + } + + // RDSEED is used but not trusted + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.h b/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.h new file mode 100644 index 0000000000..da94bc0a10 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/rdseed/rdseed.h @@ -0,0 +1,28 @@ +/* +* Entropy Source Using Intel's rdseed instruction +* (C) 2015 Jack Lloyd, Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_RDSEED_H_ +#define BOTAN_ENTROPY_SRC_RDSEED_H_ + +#include + +namespace Botan { + +/** +* Entropy source using the rdseed instruction first introduced on +* Intel's Broadwell architecture. +*/ +class Intel_Rdseed final : public Entropy_Source + { + public: + std::string name() const override { return "rdseed"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.cpp b/comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.cpp new file mode 100644 index 0000000000..3a175bf19d --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.cpp @@ -0,0 +1,59 @@ +/* +* (C) 1999-2009,2016,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#define NOMINMAX 1 +#define _WINSOCKAPI_ // stop windows.h including winsock.h +#include + +namespace Botan { + +size_t Win32_EntropySource::poll(RandomNumberGenerator& rng) + { + rng.add_entropy_T(::GetTickCount()); + rng.add_entropy_T(::GetMessagePos()); + rng.add_entropy_T(::GetMessageTime()); + rng.add_entropy_T(::GetInputState()); + + rng.add_entropy_T(::GetCurrentProcessId()); + rng.add_entropy_T(::GetCurrentThreadId()); + + SYSTEM_INFO sys_info; + ::GetSystemInfo(&sys_info); + rng.add_entropy_T(sys_info); + + MEMORYSTATUSEX mem_info; + ::GlobalMemoryStatusEx(&mem_info); + rng.add_entropy_T(mem_info); + + POINT point; + ::GetCursorPos(&point); + rng.add_entropy_T(point); + + ::GetCaretPos(&point); + rng.add_entropy_T(point); + + /* + Potential other sources to investigate + + GetProductInfo + GetComputerNameExA + GetSystemFirmwareTable + GetVersionExA + GetProcessorSystemCycleTime + GetProcessHandleCount(GetCurrentProcess()) + GetThreadTimes(GetCurrentThread()) + QueryThreadCycleTime + QueryIdleProcessorCycleTime + QueryUnbiasedInterruptTime + */ + + // We assume all of the above is basically junk + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.h b/comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.h new file mode 100644 index 0000000000..2b11ee0801 --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/win32_stats/es_win32.h @@ -0,0 +1,27 @@ +/* +* Win32 EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_WIN32_H_ +#define BOTAN_ENTROPY_SRC_WIN32_H_ + +#include + +namespace Botan { + +/** +* Win32 Entropy Source +*/ +class Win32_EntropySource final : public Entropy_Source + { + public: + std::string name() const override { return "system_stats"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/entropy/win32_stats/info.txt b/comm/third_party/botan/src/lib/entropy/win32_stats/info.txt new file mode 100644 index 0000000000..1123403b5d --- /dev/null +++ b/comm/third_party/botan/src/lib/entropy/win32_stats/info.txt @@ -0,0 +1,15 @@ + +ENTROPY_SRC_WIN32 -> 20200209 + + + +es_win32.h + + + +win32 + + + +windows -> user32 + diff --git a/comm/third_party/botan/src/lib/ffi/ffi.cpp b/comm/third_party/botan/src/lib/ffi/ffi.cpp new file mode 100644 index 0000000000..9126394ed3 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi.cpp @@ -0,0 +1,297 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan_FFI { + +int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) + { + std::string val; + if(Botan::OS::read_env_variable(val, "BOTAN_FFI_PRINT_EXCEPTIONS") == true && val != "") + { + std::fprintf(stderr, "in %s exception '%s' returning %d\n", func_name, exn, rc); + } + return rc; + } + +namespace { + +int ffi_map_error_type(Botan::ErrorType err) + { + switch(err) + { + case Botan::ErrorType::Unknown: + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + + case Botan::ErrorType::SystemError: + case Botan::ErrorType::IoError: + case Botan::ErrorType::OpenSSLError: + case Botan::ErrorType::Pkcs11Error: + case Botan::ErrorType::CommonCryptoError: + case Botan::ErrorType::TPMError: + case Botan::ErrorType::ZlibError: + case Botan::ErrorType::Bzip2Error: + case Botan::ErrorType::LzmaError: + case Botan::ErrorType::DatabaseError: + return BOTAN_FFI_ERROR_SYSTEM_ERROR; + + case Botan::ErrorType::NotImplemented: + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + case Botan::ErrorType::OutOfMemory: + return BOTAN_FFI_ERROR_OUT_OF_MEMORY; + case Botan::ErrorType::InternalError: + return BOTAN_FFI_ERROR_INTERNAL_ERROR; + case Botan::ErrorType::InvalidObjectState: + return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE; + case Botan::ErrorType::KeyNotSet: + return BOTAN_FFI_ERROR_KEY_NOT_SET; + case Botan::ErrorType::InvalidArgument: + case Botan::ErrorType::InvalidNonceLength: + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + case Botan::ErrorType::EncodingFailure: + case Botan::ErrorType::DecodingFailure: + return BOTAN_FFI_ERROR_INVALID_INPUT; + + case Botan::ErrorType::InvalidTag: + return BOTAN_FFI_ERROR_BAD_MAC; + + case Botan::ErrorType::InvalidKeyLength: + return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH; + case Botan::ErrorType::LookupError: + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + case Botan::ErrorType::HttpError: + return BOTAN_FFI_ERROR_HTTP_ERROR; + case Botan::ErrorType::TLSError: + return BOTAN_FFI_ERROR_TLS_ERROR; + case Botan::ErrorType::RoughtimeError: + return BOTAN_FFI_ERROR_ROUGHTIME_ERROR; + } + + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + } + +} + +int ffi_guard_thunk(const char* func_name, std::function thunk) + { + try + { + return thunk(); + } + catch(std::bad_alloc&) + { + return ffi_error_exception_thrown(func_name, "bad_alloc", BOTAN_FFI_ERROR_OUT_OF_MEMORY); + } + catch(Botan_FFI::FFI_Error& e) + { + return ffi_error_exception_thrown(func_name, e.what(), e.error_code()); + } + catch(Botan::Exception& e) + { + return ffi_error_exception_thrown(func_name, e.what(), ffi_map_error_type(e.error_type())); + } + catch(std::exception& e) + { + return ffi_error_exception_thrown(func_name, e.what()); + } + catch(...) + { + return ffi_error_exception_thrown(func_name, "unknown exception"); + } + + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + } + +} + +extern "C" { + +using namespace Botan_FFI; + +const char* botan_error_description(int err) + { + switch(err) + { + case BOTAN_FFI_SUCCESS: + return "OK"; + + case BOTAN_FFI_INVALID_VERIFIER: + return "Invalid verifier"; + + case BOTAN_FFI_ERROR_INVALID_INPUT: + return "Invalid input"; + + case BOTAN_FFI_ERROR_BAD_MAC: + return "Invalid authentication code"; + + case BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE: + return "Insufficient buffer space"; + + case BOTAN_FFI_ERROR_EXCEPTION_THROWN: + return "Exception thrown"; + + case BOTAN_FFI_ERROR_OUT_OF_MEMORY: + return "Out of memory"; + + case BOTAN_FFI_ERROR_SYSTEM_ERROR: + return "Error while calling system API"; + + case BOTAN_FFI_ERROR_INTERNAL_ERROR: + return "Internal error"; + + case BOTAN_FFI_ERROR_BAD_FLAG: + return "Bad flag"; + + case BOTAN_FFI_ERROR_NULL_POINTER: + return "Null pointer argument"; + + case BOTAN_FFI_ERROR_BAD_PARAMETER: + return "Bad parameter"; + + case BOTAN_FFI_ERROR_KEY_NOT_SET: + return "Key not set on object"; + + case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH: + return "Invalid key length"; + + case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE: + return "Invalid object state"; + + case BOTAN_FFI_ERROR_NOT_IMPLEMENTED: + return "Not implemented"; + + case BOTAN_FFI_ERROR_INVALID_OBJECT: + return "Invalid object handle"; + + case BOTAN_FFI_ERROR_TLS_ERROR: + return "TLS error"; + + case BOTAN_FFI_ERROR_HTTP_ERROR: + return "HTTP error"; + + case BOTAN_FFI_ERROR_UNKNOWN_ERROR: + return "Unknown error"; + } + + return "Unknown error"; + } + +/* +* Versioning +*/ +uint32_t botan_ffi_api_version() + { + return BOTAN_HAS_FFI; + } + +int botan_ffi_supports_api(uint32_t api_version) + { + // This is the API introduced in 2.18 + if(api_version == 20210220) + return BOTAN_FFI_SUCCESS; + + // This is the API introduced in 2.13 + if(api_version == 20191214) + return BOTAN_FFI_SUCCESS; + + // This is the API introduced in 2.8 + if(api_version == 20180713) + return BOTAN_FFI_SUCCESS; + + // This is the API introduced in 2.3 + if(api_version == 20170815) + return BOTAN_FFI_SUCCESS; + + // This is the API introduced in 2.1 + if(api_version == 20170327) + return BOTAN_FFI_SUCCESS; + + // This is the API introduced in 2.0 + if(api_version == 20150515) + return BOTAN_FFI_SUCCESS; + + // Something else: + return -1; + } + +const char* botan_version_string() + { + return Botan::version_cstr(); + } + +uint32_t botan_version_major() { return Botan::version_major(); } +uint32_t botan_version_minor() { return Botan::version_minor(); } +uint32_t botan_version_patch() { return Botan::version_patch(); } +uint32_t botan_version_datestamp() { return Botan::version_datestamp(); } + +int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) + { + return Botan::constant_time_compare(x, y, len) ? 0 : -1; + } + +int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) + { + return botan_constant_time_compare(x, y, len); + } + +int botan_scrub_mem(void* mem, size_t bytes) + { + Botan::secure_scrub_memory(mem, bytes); + return BOTAN_FFI_SUCCESS; + } + +int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) + { + return ffi_guard_thunk(__func__, [=]() -> int { + const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0; + Botan::hex_encode(out, in, len, uppercase); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + const std::vector bin = Botan::hex_decode(hex_str, in_len); + return Botan_FFI::write_vec_output(out, out_len, bin); + }); + } + +int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + const std::string base64 = Botan::base64_encode(in, len); + return Botan_FFI::write_str_output(out, out_len, base64); + }); + } + +int botan_base64_decode(const char* base64_str, size_t in_len, + uint8_t* out, size_t* out_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(*out_len < Botan::base64_decode_max_output(in_len)) + { + *out_len = Botan::base64_decode_max_output(in_len); + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + } + + *out_len = Botan::base64_decode(out, std::string(base64_str, in_len)); + return BOTAN_FFI_SUCCESS; + }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi.h b/comm/third_party/botan/src/lib/ffi/ffi.h new file mode 100644 index 0000000000..ff7fc4b95f --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi.h @@ -0,0 +1,1778 @@ +/* +* FFI (C89 API) +* (C) 2015,2017 Jack Lloyd +* (C) 2021 René Fischer +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FFI_H_ +#define BOTAN_FFI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +This header exports some of botan's functionality via a C89 interface. This API +is uesd by the Python, OCaml, Rust and Ruby bindings via those languages +respective ctypes/FFI libraries. + +The API is intended to be as easy as possible to call from other +languages, which often have easy ways to call C, because C. But some C +code is easier to deal with than others, so to make things easy this +API follows a few simple rules: + +- All interactions are via pointers to opaque structs. No need to worry about + structure padding issues and the like. + +- All functions return an int error code (except the version calls, which are + assumed to always have something to say). + +- Use simple types: size_t for lengths, const char* NULL terminated strings, + uint8_t for binary. + +- No ownership of memory transfers across the API boundary. The API will + consume data from const pointers, and will produce output by writing to + buffers provided by (and allocated by) the caller. + +- If exporting a value (a string or a blob) the function takes a pointer to the + output array and a read/write pointer to the length. If the length is insufficient, an + error is returned. So passing nullptr/0 allows querying the final value. + + Note this does not apply to all functions, like `botan_hash_final` + which is not idempotent and are documented specially. But it's a + general theory of operation. + + TODO: + - Doxygen comments for all functions/params + - TLS +*/ + +#include +#include +#include + +/** +* Error codes +* +* If you add a new value here be sure to also add it in +* botan_error_description +*/ +enum BOTAN_FFI_ERROR { + BOTAN_FFI_SUCCESS = 0, + BOTAN_FFI_INVALID_VERIFIER = 1, + + BOTAN_FFI_ERROR_INVALID_INPUT = -1, + BOTAN_FFI_ERROR_BAD_MAC = -2, + + BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE = -10, + + BOTAN_FFI_ERROR_EXCEPTION_THROWN = -20, + BOTAN_FFI_ERROR_OUT_OF_MEMORY = -21, + BOTAN_FFI_ERROR_SYSTEM_ERROR = -22, + BOTAN_FFI_ERROR_INTERNAL_ERROR = -23, + + BOTAN_FFI_ERROR_BAD_FLAG = -30, + BOTAN_FFI_ERROR_NULL_POINTER = -31, + BOTAN_FFI_ERROR_BAD_PARAMETER = -32, + BOTAN_FFI_ERROR_KEY_NOT_SET = -33, + BOTAN_FFI_ERROR_INVALID_KEY_LENGTH = -34, + BOTAN_FFI_ERROR_INVALID_OBJECT_STATE = -35, + + BOTAN_FFI_ERROR_NOT_IMPLEMENTED = -40, + BOTAN_FFI_ERROR_INVALID_OBJECT = -50, + + BOTAN_FFI_ERROR_TLS_ERROR = -75, + BOTAN_FFI_ERROR_HTTP_ERROR = -76, + BOTAN_FFI_ERROR_ROUGHTIME_ERROR = -77, + + BOTAN_FFI_ERROR_UNKNOWN_ERROR = -100, +}; + +/** +* Convert an error code into a string. Returns "Unknown error" +* if the error code is not a known one. +*/ +BOTAN_PUBLIC_API(2,8) const char* botan_error_description(int err); + +/** +* Return the version of the currently supported FFI API. This is +* expressed in the form YYYYMMDD of the release date of this version +* of the API. +*/ +BOTAN_PUBLIC_API(2,0) uint32_t botan_ffi_api_version(void); + +/** +* Return 0 (ok) if the version given is one this library supports. +* botan_ffi_supports_api(botan_ffi_api_version()) will always return 0. +*/ +BOTAN_PUBLIC_API(2,0) int botan_ffi_supports_api(uint32_t api_version); + +/** +* Return a free-form version string, e.g., 2.0.0 +*/ +BOTAN_PUBLIC_API(2,0) const char* botan_version_string(void); + +/** +* Return the major version of the library +*/ +BOTAN_PUBLIC_API(2,0) uint32_t botan_version_major(void); + +/** +* Return the minor version of the library +*/ +BOTAN_PUBLIC_API(2,0) uint32_t botan_version_minor(void); + +/** +* Return the patch version of the library +*/ +BOTAN_PUBLIC_API(2,0) uint32_t botan_version_patch(void); + +/** +* Return the date this version was released as +* an integer, or 0 if an unreleased version +*/ +BOTAN_PUBLIC_API(2,0) uint32_t botan_version_datestamp(void); + +/** +* Returns 0 if x[0..len] == y[0..len], or otherwise -1 +*/ +BOTAN_PUBLIC_API(2,3) int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len); + +/** +* Deprecated equivalent to botan_constant_time_compare +*/ +BOTAN_PUBLIC_API(2,0) int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len); + +/** +* Clear out memory using a system specific approach to bypass elision by the +* compiler (currently using RtlSecureZeroMemory or tricks with volatile pointers). +*/ +BOTAN_PUBLIC_API(2,2) int botan_scrub_mem(void* mem, size_t bytes); + +#define BOTAN_FFI_HEX_LOWER_CASE 1 + +/** +* Perform hex encoding +* @param x is some binary data +* @param len length of x in bytes +* @param out an array of at least x*2 bytes +* @param flags flags out be upper or lower case? +* @return 0 on success, 1 on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_hex_encode(const uint8_t* x, size_t len, char* out, uint32_t flags); + +/** +* Perform hex decoding +* @param hex_str a string of hex chars (whitespace is ignored) +* @param in_len the length of hex_str +* @param out the output buffer should be at least strlen(hex_str)/2 bytes +* @param out_len the size of out +*/ +BOTAN_PUBLIC_API(2,3) int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len); + +/** +* Perform base64 encoding +*/ +BOTAN_PUBLIC_API(2,3) int botan_base64_encode(const uint8_t* x, size_t len, char* out, size_t* out_len); + + +/** +* Perform base64 decoding +*/ +BOTAN_PUBLIC_API(2,3) int botan_base64_decode(const char* base64_str, size_t in_len, + uint8_t* out, size_t* out_len); + +/** +* RNG type +*/ +typedef struct botan_rng_struct* botan_rng_t; + +/** +* Initialize a random number generator object +* @param rng rng object +* @param rng_type type of the rng, possible values: +* "system": system RNG +* "user": userspace RNG +* "user-threadsafe": userspace RNG, with internal locking +* "rdrand": directly read RDRAND +* Set rng_type to null to let the library choose some default. +*/ +BOTAN_PUBLIC_API(2,0) int botan_rng_init(botan_rng_t* rng, const char* rng_type); + +/** +* Initialize a custom random number generator from a set of callback functions +* @param rng rng object +* @param rng_name name of the rng +* @param context An application-specific context passed to the callback functions +* @param get_cb Callback for getting random bytes from the rng, return 0 for success +* @param add_entry_cb Callback for adding entropy to the rng, return 0 for success, may be NULL +* @param destroy_cb Callback called when rng is destroyed, may be NULL +*/ +BOTAN_PUBLIC_API(2,18) int botan_rng_init_custom(botan_rng_t* rng_out, const char* rng_name, void* context, + int(* get_cb)(void* context, uint8_t* out, size_t out_len), + int(* add_entropy_cb)(void* context, const uint8_t input[], size_t length), + void(* destroy_cb)(void* context)); + +/** +* Get random bytes from a random number generator +* @param rng rng object +* @param out output buffer of size out_len +* @param out_len number of requested bytes +* @return 0 on success, negative on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len); + +/** +* Reseed a random number generator +* Uses the System_RNG as a seed generator. +* +* @param rng rng object +* @param bits number of bits to to reseed with +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_rng_reseed(botan_rng_t rng, size_t bits); + +/** +* Reseed a random number generator +* +* @param rng rng object +* @param source_rng the rng that will be read from +* @param bits number of bits to to reseed with +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,8) int botan_rng_reseed_from_rng(botan_rng_t rng, + botan_rng_t source_rng, + size_t bits); + +/** +* Add some seed material to a random number generator +* +* @param rng rng object +* @param entropy the data to add +* @param entropy_len length of entropy buffer +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,8) int botan_rng_add_entropy(botan_rng_t rng, + const uint8_t* entropy, + size_t entropy_len); + +/** +* Frees all resources of the random number generator object +* @param rng rng object +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_rng_destroy(botan_rng_t rng); + +/* +* Hash type +*/ +typedef struct botan_hash_struct* botan_hash_t; + +/** +* Initialize a hash function object +* @param hash hash object +* @param hash_name name of the hash function, e.g., "SHA-384" +* @param flags should be 0 in current API revision, all other uses are reserved +* and return BOTAN_FFI_ERROR_BAD_FLAG +*/ +BOTAN_PUBLIC_API(2,0) int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags); + +/** +* Copy the state of a hash function object +* @param dest destination hash object +* @param source source hash object +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,2) int botan_hash_copy_state(botan_hash_t *dest, const botan_hash_t source); + +/** +* Writes the output length of the hash function to *output_length +* @param hash hash object +* @param output_length output buffer to hold the hash function output length +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_hash_output_length(botan_hash_t hash, size_t* output_length); + +/** +* Writes the block size of the hash function to *block_size +* @param hash hash object +* @param block_size output buffer to hold the hash function output length +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,2) int botan_hash_block_size(botan_hash_t hash, size_t* block_size); + +/** +* Send more input to the hash function +* @param hash hash object +* @param in input buffer +* @param in_len number of bytes to read from the input buffer +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_hash_update(botan_hash_t hash, const uint8_t* in, size_t in_len); + +/** +* Finalizes the hash computation and writes the output to +* out[0:botan_hash_output_length()] then reinitializes for computing +* another digest as if botan_hash_clear had been called. +* @param hash hash object +* @param out output buffer +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_hash_final(botan_hash_t hash, uint8_t out[]); + +/** +* Reinitializes the state of the hash computation. A hash can +* be computed (with update/final) immediately. +* @param hash hash object +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_hash_clear(botan_hash_t hash); + +/** +* Frees all resources of the hash object +* @param hash hash object +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_hash_destroy(botan_hash_t hash); + +/** +* Get the name of this hash function +* @param hash the object to read +* @param name output buffer +* @param name_len on input, the length of buffer, on success the number of bytes written +*/ +BOTAN_PUBLIC_API(2,8) int botan_hash_name(botan_hash_t hash, char* name, size_t* name_len); + +/* +* Message Authentication type +*/ +typedef struct botan_mac_struct* botan_mac_t; + +/** +* Initialize a message authentication code object +* @param mac mac object +* @param mac_name name of the hash function, e.g., "HMAC(SHA-384)" +* @param flags should be 0 in current API revision, all other uses are reserved +* and return a negative value (error code) +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags); + +/** +* Writes the output length of the message authentication code to *output_length +* @param mac mac object +* @param output_length output buffer to hold the MAC output length +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_output_length(botan_mac_t mac, size_t* output_length); + +/** +* Sets the key on the MAC +* @param mac mac object +* @param key buffer holding the key +* @param key_len size of the key buffer in bytes +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len); + +/** +* Send more input to the message authentication code +* @param mac mac object +* @param buf input buffer +* @param len number of bytes to read from the input buffer +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len); + +/** +* Finalizes the MAC computation and writes the output to +* out[0:botan_mac_output_length()] then reinitializes for computing +* another MAC as if botan_mac_clear had been called. +* @param mac mac object +* @param out output buffer +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_final(botan_mac_t mac, uint8_t out[]); + +/** +* Reinitializes the state of the MAC computation. A MAC can +* be computed (with update/final) immediately. +* @param mac mac object +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_clear(botan_mac_t mac); + +/** +* Get the name of this MAC +* @param mac the object to read +* @param name output buffer +* @param name_len on input, the length of buffer, on success the number of bytes written +*/ +BOTAN_PUBLIC_API(2,8) int botan_mac_name(botan_mac_t mac, char* name, size_t* name_len); + +/** +* Get the key length limits of this auth code +* @param mac the object to read +* @param out_minimum_keylength if non-NULL, will be set to minimum keylength of MAC +* @param out_maximum_keylength if non-NULL, will be set to maximum keylength of MAC +* @param out_keylength_modulo if non-NULL will be set to byte multiple of valid keys +*/ +BOTAN_PUBLIC_API(2,8) int botan_mac_get_keyspec(botan_mac_t mac, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength, + size_t* out_keylength_modulo); + +/** +* Frees all resources of the MAC object +* @param mac mac object +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_mac_destroy(botan_mac_t mac); + +/* +* Cipher modes +*/ +typedef struct botan_cipher_struct* botan_cipher_t; + +#define BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION 1 +#define BOTAN_CIPHER_INIT_FLAG_ENCRYPT 0 +#define BOTAN_CIPHER_INIT_FLAG_DECRYPT 1 + +/** +* Initialize a cipher object +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_init(botan_cipher_t* cipher, const char* name, uint32_t flags); + +/** +* Return the name of the cipher object +*/ +BOTAN_PUBLIC_API(2,8) int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len); + +/** +* Return the output length of this cipher, for a particular input length. +*/ +BOTAN_PUBLIC_API(2,8) int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t* out_len); + +/** +* Return if the specified nonce length is valid for this cipher +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl); + +/** +* Get the tag length of the cipher (0 for non-AEAD modes) +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tag_size); + +/** +* Get the default nonce length of this cipher +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl); + +/** +* Return the update granularity of the cipher; botan_cipher_update must be +* called with blocks of this size, except for the final. +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug); + +/** +* Get information about the key lengths. Prefer botan_cipher_get_keyspec +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_query_keylen(botan_cipher_t, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength); + +/** +* Get information about the supported key lengths. +*/ +BOTAN_PUBLIC_API(2,8) int botan_cipher_get_keyspec(botan_cipher_t, + size_t* min_keylen, + size_t* max_keylen, + size_t* mod_keylen); + +/** +* Set the key for this cipher object +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_set_key(botan_cipher_t cipher, + const uint8_t* key, size_t key_len); + +/** +* Reset the message specific state for this cipher. +* Without resetting the keys, this resets the nonce, and any state +* associated with any message bits that have been processed so far. +* +* It is conceptually equivalent to calling botan_cipher_clear followed +* by botan_cipher_set_key with the original key. +*/ +BOTAN_PUBLIC_API(2,8) int botan_cipher_reset(botan_cipher_t cipher); + +/** +* Set the associated data. Will fail if cipher is not an AEAD +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_set_associated_data(botan_cipher_t cipher, + const uint8_t* ad, size_t ad_len); + +/** +* Begin processing a new message using the provided nonce +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_start(botan_cipher_t cipher, + const uint8_t* nonce, size_t nonce_len); + +#define BOTAN_CIPHER_UPDATE_FLAG_FINAL (1U << 0) + +/** +* Encrypt some data +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_update(botan_cipher_t cipher, + uint32_t flags, + uint8_t output[], + size_t output_size, + size_t* output_written, + const uint8_t input_bytes[], + size_t input_size, + size_t* input_consumed); + +/** +* Reset the key, nonce, AD and all other state on this cipher object +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_clear(botan_cipher_t hash); + +/** +* Destroy the cipher object +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_cipher_destroy(botan_cipher_t cipher); + +/* +* Derive a key from a passphrase for a number of iterations +* @param pbkdf_algo PBKDF algorithm, e.g., "PBKDF2(SHA-256)" +* @param out buffer to store the derived key, must be of out_len bytes +* @param out_len the desired length of the key to produce +* @param passphrase the password to derive the key from +* @param salt a randomly chosen salt +* @param salt_len length of salt in bytes +* @param iterations the number of iterations to use (use 10K or more) +* @return 0 on success, a negative value on failure +* +* Deprecated: use +* botan_pwdhash(pbkdf_algo, iterations, 0, 0, out, out_len, +* passphrase, 0, salt, salt_len); +*/ +BOTAN_PUBLIC_API(2,0) int +BOTAN_DEPRECATED("Use botan_pwdhash") +botan_pbkdf(const char* pbkdf_algo, + uint8_t out[], size_t out_len, + const char* passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations); + +/** +* Derive a key from a passphrase, running until msec time has elapsed. +* @param pbkdf_algo PBKDF algorithm, e.g., "PBKDF2(SHA-256)" +* @param out buffer to store the derived key, must be of out_len bytes +* @param out_len the desired length of the key to produce +* @param passphrase the password to derive the key from +* @param salt a randomly chosen salt +* @param salt_len length of salt in bytes +* @param milliseconds_to_run if iterations is zero, then instead the PBKDF is +* run until milliseconds_to_run milliseconds has passed +* @param out_iterations_used set to the number iterations executed +* @return 0 on success, a negative value on failure +* +* Deprecated: use +* +* botan_pwdhash_timed(pbkdf_algo, +* static_cast(ms_to_run), +* iterations_used, +* nullptr, +* nullptr, +* out, out_len, +* password, 0, +* salt, salt_len); +*/ +BOTAN_PUBLIC_API(2,0) int botan_pbkdf_timed(const char* pbkdf_algo, + uint8_t out[], size_t out_len, + const char* passphrase, + const uint8_t salt[], size_t salt_len, + size_t milliseconds_to_run, + size_t* out_iterations_used); + + +/* +* Derive a key from a passphrase +* @param algo PBKDF algorithm, e.g., "PBKDF2(SHA-256)" or "Scrypt" +* @param param1 the first PBKDF algorithm parameter +* @param param2 the second PBKDF algorithm parameter (may be zero if unneeded) +* @param param3 the third PBKDF algorithm parameter (may be zero if unneeded) +* @param out buffer to store the derived key, must be of out_len bytes +* @param out_len the desired length of the key to produce +* @param passphrase the password to derive the key from +* @param passphrase_len if > 0, specifies length of password. If len == 0, then +* strlen will be called on passphrase to compute the length. +* @param salt a randomly chosen salt +* @param salt_len length of salt in bytes +* @return 0 on success, a negative value on failure +*/ +int BOTAN_PUBLIC_API(2,8) botan_pwdhash( + const char* algo, + size_t param1, + size_t param2, + size_t param3, + uint8_t out[], + size_t out_len, + const char* passphrase, + size_t passphrase_len, + const uint8_t salt[], + size_t salt_len); + +/* +* Derive a key from a passphrase +* @param pbkdf_algo PBKDF algorithm, e.g., "Scrypt" or "PBKDF2(SHA-256)" +* @param msec the desired runtime in milliseconds +* @param param1 will be set to the first password hash parameter +* @param param2 will be set to the second password hash parameter +* @param param3 will be set to the third password hash parameter +* @param out buffer to store the derived key, must be of out_len bytes +* @param out_len the desired length of the key to produce +* @param passphrase the password to derive the key from +* @param passphrase_len if > 0, specifies length of password. If len == 0, then +* strlen will be called on passphrase to compute the length. +* @param salt a randomly chosen salt +* @param salt_len length of salt in bytes +* @return 0 on success, a negative value on failure +*/ +int BOTAN_PUBLIC_API(2,8) botan_pwdhash_timed( + const char* algo, + uint32_t msec, + size_t* param1, + size_t* param2, + size_t* param3, + uint8_t out[], + size_t out_len, + const char* passphrase, + size_t passphrase_len, + const uint8_t salt[], + size_t salt_len); + +/** +* Derive a key using scrypt +* Deprecated; use +* botan_pwdhash("Scrypt", N, r, p, out, out_len, password, 0, salt, salt_len); +*/ +BOTAN_PUBLIC_API(2,8) int +BOTAN_DEPRECATED("Use botan_pwdhash") +botan_scrypt(uint8_t out[], size_t out_len, + const char* passphrase, + const uint8_t salt[], size_t salt_len, + size_t N, size_t r, size_t p); + +/** +* Derive a key +* @param kdf_algo KDF algorithm, e.g., "SP800-56C" +* @param out buffer holding the derived key, must be of length out_len +* @param out_len the desired output length in bytes +* @param secret the secret input +* @param secret_len size of secret in bytes +* @param salt a diversifier +* @param salt_len size of salt in bytes +* @param label purpose for the derived keying material +* @param label_len size of label in bytes +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_kdf(const char* kdf_algo, + uint8_t out[], size_t out_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len); + +/* +* Raw Block Cipher (PRP) interface +*/ +typedef struct botan_block_cipher_struct* botan_block_cipher_t; + +/** +* Initialize a block cipher object +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_init(botan_block_cipher_t* bc, + const char* cipher_name); + +/** +* Destroy a block cipher object +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_destroy(botan_block_cipher_t bc); + +/** +* Reinitializes the block cipher +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_clear(botan_block_cipher_t bc); + +/** +* Set the key for a block cipher instance +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_set_key(botan_block_cipher_t bc, + const uint8_t key[], size_t len); + +/** +* Return the positive block size of this block cipher, or negative to +* indicate an error +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_block_size(botan_block_cipher_t bc); + +/** +* Encrypt one or more blocks with the cipher +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc, + const uint8_t in[], + uint8_t out[], + size_t blocks); + +/** +* Decrypt one or more blocks with the cipher +*/ +BOTAN_PUBLIC_API(2,1) int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc, + const uint8_t in[], + uint8_t out[], + size_t blocks); + +/** +* Get the name of this block cipher +* @param cipher the object to read +* @param name output buffer +* @param name_len on input, the length of buffer, on success the number of bytes written +*/ +BOTAN_PUBLIC_API(2,8) int botan_block_cipher_name(botan_block_cipher_t cipher, + char* name, size_t* name_len); + + +/** +* Get the key length limits of this block cipher +* @param cipher the object to read +* @param out_minimum_keylength if non-NULL, will be set to minimum keylength of cipher +* @param out_maximum_keylength if non-NULL, will be set to maximum keylength of cipher +* @param out_keylength_modulo if non-NULL will be set to byte multiple of valid keys +*/ +BOTAN_PUBLIC_API(2,8) int botan_block_cipher_get_keyspec(botan_block_cipher_t cipher, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength, + size_t* out_keylength_modulo); + +/* +* Multiple precision integers (MPI) +*/ +typedef struct botan_mp_struct* botan_mp_t; + +/** +* Initialize an MPI +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_init(botan_mp_t* mp); + +/** +* Destroy (deallocate) an MPI +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_destroy(botan_mp_t mp); + +/** +* Convert the MPI to a hex string. Writes botan_mp_num_bytes(mp)*2 + 1 bytes +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_to_hex(const botan_mp_t mp, char* out); + +/** +* Convert the MPI to a string. Currently base == 10 and base == 16 are supported. +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_to_str(const botan_mp_t mp, uint8_t base, char* out, size_t* out_len); + +/** +* Set the MPI to zero +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_clear(botan_mp_t mp); + +/** +* Set the MPI value from an int +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_set_from_int(botan_mp_t mp, int initial_value); + +/** +* Set the MPI value from another MP object +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source); + +/** +* Set the MPI value from a string +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_set_from_str(botan_mp_t dest, const char* str); + +/** +* Set the MPI value from a string with arbitrary radix. +* For arbitrary being 10 or 16. +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_set_from_radix_str(botan_mp_t dest, const char* str, size_t radix); + +/** +* Return the number of significant bits in the MPI +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_num_bits(const botan_mp_t n, size_t* bits); + +/** +* Return the number of significant bytes in the MPI +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_num_bytes(const botan_mp_t n, size_t* bytes); + +/* +* Convert the MPI to a big-endian binary string. Writes botan_mp_num_bytes to vec +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[]); + +/* +* Set an MP to the big-endian binary value +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_from_bin(const botan_mp_t mp, const uint8_t vec[], size_t vec_len); + +/* +* Convert the MPI to a uint32_t, if possible. Fails if MPI is negative or too large. +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val); + +/** +* This function should have been named mp_is_non_negative. Returns 1 +* iff mp is greater than *or equal to* zero. Use botan_mp_is_negative +* to detect negative numbers, botan_mp_is_zero to check for zero. +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_is_positive(const botan_mp_t mp); + +/** +* Return 1 iff mp is less than 0 +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_is_negative(const botan_mp_t mp); + +BOTAN_PUBLIC_API(2,1) int botan_mp_flip_sign(botan_mp_t mp); + +BOTAN_PUBLIC_API(2,1) int botan_mp_is_zero(const botan_mp_t mp); + +BOTAN_PUBLIC_API(2,1) BOTAN_DEPRECATED("Use botan_mp_get_bit(0)") +int botan_mp_is_odd(const botan_mp_t mp); +BOTAN_PUBLIC_API(2,1) BOTAN_DEPRECATED("Use botan_mp_get_bit(0)") +int botan_mp_is_even(const botan_mp_t mp); + +BOTAN_PUBLIC_API(2,8) int botan_mp_add_u32(botan_mp_t result, const botan_mp_t x, uint32_t y); +BOTAN_PUBLIC_API(2,8) int botan_mp_sub_u32(botan_mp_t result, const botan_mp_t x, uint32_t y); + +BOTAN_PUBLIC_API(2,1) int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y); +BOTAN_PUBLIC_API(2,1) int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y); +BOTAN_PUBLIC_API(2,1) int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y); + +BOTAN_PUBLIC_API(2,1) int botan_mp_div(botan_mp_t quotient, + botan_mp_t remainder, + const botan_mp_t x, const botan_mp_t y); + +BOTAN_PUBLIC_API(2,1) int botan_mp_mod_mul(botan_mp_t result, const botan_mp_t x, + const botan_mp_t y, const botan_mp_t mod); + +/* +* Returns 0 if x != y +* Returns 1 if x == y +* Returns negative number on error +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_equal(const botan_mp_t x, const botan_mp_t y); + +/* +* Sets *result to comparison result: +* -1 if x < y, 0 if x == y, 1 if x > y +* Returns negative number on error or zero on success +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_cmp(int* result, const botan_mp_t x, const botan_mp_t y); + +/* +* Swap two botan_mp_t +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_swap(botan_mp_t x, botan_mp_t y); + +/* Return (base^exponent) % modulus */ +BOTAN_PUBLIC_API(2,1) int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus); + +BOTAN_PUBLIC_API(2,1) int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift); +BOTAN_PUBLIC_API(2,1) int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift); + +BOTAN_PUBLIC_API(2,1) int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus); + +BOTAN_PUBLIC_API(2,1) int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits); + +BOTAN_PUBLIC_API(2,1) int botan_mp_rand_range(botan_mp_t rand_out, botan_rng_t rng, + const botan_mp_t lower_bound, const botan_mp_t upper_bound); + +BOTAN_PUBLIC_API(2,1) int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y); + +/** +* Returns 0 if n is not prime +* Returns 1 if n is prime +* Returns negative number on error +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_is_prime(const botan_mp_t n, botan_rng_t rng, size_t test_prob); + +/** +* Returns 0 if specified bit of n is not set +* Returns 1 if specified bit of n is set +* Returns negative number on error +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_get_bit(const botan_mp_t n, size_t bit); + +/** +* Set the specified bit +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_set_bit(botan_mp_t n, size_t bit); + +/** +* Clear the specified bit +*/ +BOTAN_PUBLIC_API(2,1) int botan_mp_clear_bit(botan_mp_t n, size_t bit); + +/* Bcrypt password hashing */ + +/** +* Create a password hash using Bcrypt +* @param out buffer holding the password hash, should be of length 64 bytes +* @param out_len the desired output length in bytes +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* @param flags should be 0 in current API revision, all other uses are reserved +* and return BOTAN_FFI_ERROR_BAD_FLAG +* @return 0 on success, a negative value on failure + +* Output is formatted bcrypt $2a$... +*/ +BOTAN_PUBLIC_API(2,0) int botan_bcrypt_generate(uint8_t* out, size_t* out_len, + const char* password, + botan_rng_t rng, + size_t work_factor, + uint32_t flags); + +/** +* Check a previously created password hash +* @param pass the password to check against +* @param hash the stored hash to check against +* @return 0 if if this password/hash combination is valid, +* 1 if the combination is not valid (but otherwise well formed), +* negative on error +*/ +BOTAN_PUBLIC_API(2,0) int botan_bcrypt_is_valid(const char* pass, const char* hash); + +/* +* Public/private key creation, import, ... +*/ +typedef struct botan_privkey_struct* botan_privkey_t; + +/** +* Create a new private key +* @param key the new object will be placed here +* @param algo_name something like "RSA" or "ECDSA" +* @param algo_params is specific to the algorithm. For RSA, specifies +* the modulus bit length. For ECC is the name of the curve. +* @param rng a random number generator +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_create(botan_privkey_t* key, + const char* algo_name, + const char* algo_params, + botan_rng_t rng); + +#define BOTAN_CHECK_KEY_EXPENSIVE_TESTS 1 + +BOTAN_PUBLIC_API(2,0) int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags); + +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create") +int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, size_t n_bits); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create") +int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng, const char* params); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create") +int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng, const char* params); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create") +int botan_privkey_create_mceliece(botan_privkey_t* key, botan_rng_t rng, size_t n, size_t t); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create") +int botan_privkey_create_dh(botan_privkey_t* key, botan_rng_t rng, const char* param); + +/** + * Generates DSA key pair. Gives to a caller control over key length + * and order of a subgroup 'q'. + * + * @param key handler to the resulting key + * @param rng initialized PRNG + * @param pbits length of the key in bits. Must be between in range (1024, 3072) + * and multiple of 64. Bit size of the prime 'p' + * @param qbits order of the subgroup. Must be in range (160, 256) and multiple + * of 8 + * + * @returns BOTAN_FFI_SUCCESS Success, `key' initialized with DSA key + * @returns BOTAN_FFI_ERROR_NULL_POINTER either `key' or `rng' is NULL + * @returns BOTAN_FFI_ERROR_BAD_PARAMETER unexpected value for either `pbits' or + * `qbits' + * @returns BOTAN_FFI_ERROR_NOT_IMPLEMENTED functionality not implemented + * +*/ +BOTAN_PUBLIC_API(2,5) int botan_privkey_create_dsa( + botan_privkey_t* key, + botan_rng_t rng, + size_t pbits, + size_t qbits); + +/** + * Generates ElGamal key pair. Caller has a control over key length + * and order of a subgroup 'q'. Function is able to use two types of + * primes: + * * if pbits-1 == qbits then safe primes are used for key generation + * * otherwise generation uses group of prime order + * + * @param key handler to the resulting key + * @param rng initialized PRNG + * @param pbits length of the key in bits. Must be at least 1024 + * @param qbits order of the subgroup. Must be at least 160 + * + * @returns BOTAN_FFI_SUCCESS Success, `key' initialized with DSA key + * @returns BOTAN_FFI_ERROR_NULL_POINTER either `key' or `rng' is NULL + * @returns BOTAN_FFI_ERROR_BAD_PARAMETER unexpected value for either `pbits' or + * `qbits' + * @returns BOTAN_FFI_ERROR_NOT_IMPLEMENTED functionality not implemented + * +*/ +BOTAN_PUBLIC_API(2,5) int botan_privkey_create_elgamal( + botan_privkey_t* key, + botan_rng_t rng, + size_t pbits, + size_t qbits); + +/** +* Input currently assumed to be PKCS #8 structure; +* Set password to NULL to indicate no encryption expected +* Starting in 2.8.0, the rng parameter is unused and may be set to null +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_load(botan_privkey_t* key, + botan_rng_t rng, + const uint8_t bits[], size_t len, + const char* password); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_destroy(botan_privkey_t key); + +#define BOTAN_PRIVKEY_EXPORT_FLAG_DER 0 +#define BOTAN_PRIVKEY_EXPORT_FLAG_PEM 1 + +/** +* On input *out_len is number of bytes in out[] +* On output *out_len is number of bytes written (or required) +* If out is not big enough no output is written, *out_len is set and 1 is returned +* Returns 0 on success and sets +* If some other error occurs a negative integer is returned. +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_export(botan_privkey_t key, + uint8_t out[], size_t* out_len, + uint32_t flags); + +BOTAN_PUBLIC_API(2,8) int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len); + +/** +* Set encryption_algo to NULL or "" to have the library choose a default (recommended) +*/ +BOTAN_DEPRECATED("Use botan_privkey_export_encrypted_pbkdf_{msec,iter}") +BOTAN_PUBLIC_API(2,0) int botan_privkey_export_encrypted(botan_privkey_t key, + uint8_t out[], size_t* out_len, + botan_rng_t rng, + const char* passphrase, + const char* encryption_algo, + uint32_t flags); + +/* +* Export a private key, running PBKDF for specified amount of time +* @param key the private key to export +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key, + uint8_t out[], size_t* out_len, + botan_rng_t rng, + const char* passphrase, + uint32_t pbkdf_msec_runtime, + size_t* pbkdf_iterations_out, + const char* cipher_algo, + const char* pbkdf_algo, + uint32_t flags); + +/** +* Export a private key using the specified number of iterations. +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key, + uint8_t out[], size_t* out_len, + botan_rng_t rng, + const char* passphrase, + size_t pbkdf_iterations, + const char* cipher_algo, + const char* pbkdf_algo, + uint32_t flags); + +typedef struct botan_pubkey_struct* botan_pubkey_t; + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t len); + +BOTAN_PUBLIC_API(2,0) int botan_privkey_export_pubkey(botan_pubkey_t* out, botan_privkey_t in); + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags); + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len); + +/** +* Returns 0 if key is valid, negative if invalid key or some other error +*/ +BOTAN_PUBLIC_API(2,0) int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags); + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate); + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash, + uint8_t out[], size_t* out_len); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_pubkey_destroy(botan_pubkey_t key); + +/* +* Get arbitrary named fields from public or privat keys +*/ +BOTAN_PUBLIC_API(2,0) int botan_pubkey_get_field(botan_mp_t output, + botan_pubkey_t key, + const char* field_name); + +BOTAN_PUBLIC_API(2,0) int botan_privkey_get_field(botan_mp_t output, + botan_privkey_t key, + const char* field_name); + +/* +* Algorithm specific key operations: RSA +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_load_rsa(botan_privkey_t* key, + botan_mp_t p, + botan_mp_t q, + botan_mp_t e); + +BOTAN_PUBLIC_API(2,8) int botan_privkey_load_rsa_pkcs1(botan_privkey_t* key, + const uint8_t bits[], + size_t len); + +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field") +int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t rsa_key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field") +int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t rsa_key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field") +int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t rsa_key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field") +int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t rsa_key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field") +int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t rsa_key); + +BOTAN_PUBLIC_API(2,8) int botan_privkey_rsa_get_privkey(botan_privkey_t rsa_key, + uint8_t out[], size_t* out_len, + uint32_t flags); + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_load_rsa(botan_pubkey_t* key, + botan_mp_t n, + botan_mp_t e); + +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field") +int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t rsa_key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field") +int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t rsa_key); + +/* +* Algorithm specific key operations: DSA +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_load_dsa(botan_privkey_t* key, + botan_mp_t p, + botan_mp_t q, + botan_mp_t g, + botan_mp_t x); + +BOTAN_PUBLIC_API(2,0) int botan_pubkey_load_dsa(botan_pubkey_t* key, + botan_mp_t p, + botan_mp_t q, + botan_mp_t g, + botan_mp_t y); + +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field") +int botan_privkey_dsa_get_x(botan_mp_t n, botan_privkey_t key); + +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field") +int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field") +int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field") +int botan_pubkey_dsa_get_g(botan_mp_t d, botan_pubkey_t key); +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field") +int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key); + +/* +* Loads Diffie Hellman private key +* +* @param key variable populated with key material +* @param p prime order of a Z_p group +* @param g group generator +* @param x private key +* +* @pre key is NULL on input +* @post function allocates memory and assigns to `key' +* +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_load_dh(botan_privkey_t* key, + botan_mp_t p, + botan_mp_t g, + botan_mp_t x); +/** +* Loads Diffie Hellman public key +* +* @param key variable populated with key material +* @param p prime order of a Z_p group +* @param g group generator +* @param y public key +* +* @pre key is NULL on input +* @post function allocates memory and assigns to `key' +* +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_pubkey_load_dh(botan_pubkey_t* key, + botan_mp_t p, + botan_mp_t g, + botan_mp_t y); + +/* +* Algorithm specific key operations: ElGamal +*/ + +/** +* Loads ElGamal public key +* @param key variable populated with key material +* @param p prime order of a Z_p group +* @param g group generator +* @param y public key +* +* @pre key is NULL on input +* @post function allocates memory and assigns to `key' +* +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_pubkey_load_elgamal(botan_pubkey_t* key, + botan_mp_t p, + botan_mp_t g, + botan_mp_t y); + +/** +* Loads ElGamal private key +* +* @param key variable populated with key material +* @param p prime order of a Z_p group +* @param g group generator +* @param x private key +* +* @pre key is NULL on input +* @post function allocates memory and assigns to `key' +* +* @return 0 on success, a negative value on failure +*/ +BOTAN_PUBLIC_API(2,0) int botan_privkey_load_elgamal(botan_privkey_t* key, + botan_mp_t p, + botan_mp_t g, + botan_mp_t x); + +/* +* Algorithm specific key operations: Ed25519 +*/ + +BOTAN_PUBLIC_API(2,2) int botan_privkey_load_ed25519(botan_privkey_t* key, + const uint8_t privkey[32]); + +BOTAN_PUBLIC_API(2,2) int botan_pubkey_load_ed25519(botan_pubkey_t* key, + const uint8_t pubkey[32]); + +BOTAN_PUBLIC_API(2,2) int botan_privkey_ed25519_get_privkey(botan_privkey_t key, + uint8_t output[64]); + +BOTAN_PUBLIC_API(2,2) int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key, + uint8_t pubkey[32]); + +/* +* Algorithm specific key operations: X25519 +*/ + +BOTAN_PUBLIC_API(2,8) int botan_privkey_load_x25519(botan_privkey_t* key, + const uint8_t privkey[32]); + +BOTAN_PUBLIC_API(2,8) int botan_pubkey_load_x25519(botan_pubkey_t* key, + const uint8_t pubkey[32]); + +BOTAN_PUBLIC_API(2,8) int botan_privkey_x25519_get_privkey(botan_privkey_t key, + uint8_t output[32]); + +BOTAN_PUBLIC_API(2,8) int botan_pubkey_x25519_get_pubkey(botan_pubkey_t key, + uint8_t pubkey[32]); + +/* +* Algorithm specific key operations: ECDSA and ECDH +*/ +BOTAN_PUBLIC_API(2,2) +int botan_privkey_load_ecdsa(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) +int botan_pubkey_load_ecdsa(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) +int botan_pubkey_load_ecdh(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) +int botan_privkey_load_ecdh(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) +int botan_pubkey_load_sm2(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) +int botan_privkey_load_sm2(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) BOTAN_DEPRECATED("Use botan_pubkey_load_sm2") +int botan_pubkey_load_sm2_enc(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name); + +BOTAN_PUBLIC_API(2,2) BOTAN_DEPRECATED("Use botan_privkey_load_sm2") +int botan_privkey_load_sm2_enc(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name); + +BOTAN_PUBLIC_API(2,3) +int botan_pubkey_sm2_compute_za(uint8_t out[], + size_t* out_len, + const char* ident, + const char* hash_algo, + const botan_pubkey_t key); + +/* +* Public Key Encryption +*/ +typedef struct botan_pk_op_encrypt_struct* botan_pk_op_encrypt_t; + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, + botan_pubkey_t key, + const char* padding, + uint32_t flags); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op); + +BOTAN_PUBLIC_API(2,8) int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, + size_t ptext_len, + size_t* ctext_len); + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_encrypt(botan_pk_op_encrypt_t op, + botan_rng_t rng, + uint8_t out[], + size_t* out_len, + const uint8_t plaintext[], + size_t plaintext_len); + +/* +* Public Key Decryption +*/ +typedef struct botan_pk_op_decrypt_struct* botan_pk_op_decrypt_t; + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, + botan_privkey_t key, + const char* padding, + uint32_t flags); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op); + +BOTAN_PUBLIC_API(2,8) int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, + size_t ctext_len, + size_t* ptext_len); + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_decrypt(botan_pk_op_decrypt_t op, + uint8_t out[], size_t* out_len, + const uint8_t ciphertext[], size_t ciphertext_len); + +/* +* Signature Generation +*/ + +#define BOTAN_PUBKEY_DER_FORMAT_SIGNATURE 1 + +typedef struct botan_pk_op_sign_struct* botan_pk_op_sign_t; + +BOTAN_PUBLIC_API(2,0) +int botan_pk_op_sign_create(botan_pk_op_sign_t* op, + botan_privkey_t key, + const char* hash_and_padding, + uint32_t flags); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_pk_op_sign_destroy(botan_pk_op_sign_t op); + +BOTAN_PUBLIC_API(2,8) int botan_pk_op_sign_output_length(botan_pk_op_sign_t op, size_t* olen); + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len); + +BOTAN_PUBLIC_API(2,0) +int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng, + uint8_t sig[], size_t* sig_len); + +/* +* Signature Verification +*/ +typedef struct botan_pk_op_verify_struct* botan_pk_op_verify_t; + +BOTAN_PUBLIC_API(2,0) +int botan_pk_op_verify_create(botan_pk_op_verify_t* op, + botan_pubkey_t key, + const char* hash_and_padding, + uint32_t flags); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_pk_op_verify_destroy(botan_pk_op_verify_t op); + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len); +BOTAN_PUBLIC_API(2,0) int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len); + +/* +* Key Agreement +*/ +typedef struct botan_pk_op_ka_struct* botan_pk_op_ka_t; + +BOTAN_PUBLIC_API(2,0) +int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, + botan_privkey_t key, + const char* kdf, + uint32_t flags); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op); + +BOTAN_PUBLIC_API(2,0) int botan_pk_op_key_agreement_export_public(botan_privkey_t key, + uint8_t out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,8) int botan_pk_op_key_agreement_size(botan_pk_op_ka_t op, size_t* out_len); + +BOTAN_PUBLIC_API(2,0) +int botan_pk_op_key_agreement(botan_pk_op_ka_t op, + uint8_t out[], size_t* out_len, + const uint8_t other_key[], size_t other_key_len, + const uint8_t salt[], size_t salt_len); + +BOTAN_PUBLIC_API(2,0) int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len); + + +/* +* +* @param mce_key must be a McEliece key +* ct_len should be pt_len + n/8 + a few? +*/ +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Poorly specified, avoid in new code") +int botan_mceies_encrypt(botan_pubkey_t mce_key, + botan_rng_t rng, + const char* aead, + const uint8_t pt[], size_t pt_len, + const uint8_t ad[], size_t ad_len, + uint8_t ct[], size_t* ct_len); + +BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Poorly specified, avoid in new code") +int botan_mceies_decrypt(botan_privkey_t mce_key, + const char* aead, + const uint8_t ct[], size_t ct_len, + const uint8_t ad[], size_t ad_len, + uint8_t pt[], size_t* pt_len); + +/* +* X.509 certificates +**************************/ + +typedef struct botan_x509_cert_struct* botan_x509_cert_t; + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert[], size_t cert_len); +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* filename); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_destroy(botan_x509_cert_t cert); + +BOTAN_PUBLIC_API(2,8) int botan_x509_cert_dup(botan_x509_cert_t* new_cert, botan_x509_cert_t cert); + +/* Prefer botan_x509_cert_not_before and botan_x509_cert_not_after */ +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len); +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,8) int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch); +BOTAN_PUBLIC_API(2,8) int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch); + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, + uint8_t out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key); + +BOTAN_PUBLIC_API(2,0) +int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,0) +int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len); + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len); + +/* Must match values of Key_Constraints in key_constraints.h */ +enum botan_x509_cert_key_constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 32768, + NON_REPUDIATION = 16384, + KEY_ENCIPHERMENT = 8192, + DATA_ENCIPHERMENT = 4096, + KEY_AGREEMENT = 2048, + KEY_CERT_SIGN = 1024, + CRL_SIGN = 512, + ENCIPHER_ONLY = 256, + DECIPHER_ONLY = 128 +}; + +BOTAN_PUBLIC_API(2,0) int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage); + +/** +* Check if the certificate matches the specified hostname via alternative name or CN match. +* RFC 5280 wildcards also supported. +*/ +BOTAN_PUBLIC_API(2,5) int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname); + +/** +* Returns 0 if the validation was successful, 1 if validation failed, +* and negative on error. A status code with details is written to +* *validation_result +* +* Intermediates or trusted lists can be null +* Trusted path can be null +*/ +BOTAN_PUBLIC_API(2,8) int botan_x509_cert_verify( + int* validation_result, + botan_x509_cert_t cert, + const botan_x509_cert_t* intermediates, + size_t intermediates_len, + const botan_x509_cert_t* trusted, + size_t trusted_len, + const char* trusted_path, + size_t required_strength, + const char* hostname, + uint64_t reference_time); + +/** +* Returns a pointer to a static character string explaining the status code, +* or else NULL if unknown. +*/ +BOTAN_PUBLIC_API(2,8) const char* botan_x509_cert_validation_status(int code); + +/* +* X.509 CRL +**************************/ + +typedef struct botan_x509_crl_struct* botan_x509_crl_t; + +BOTAN_PUBLIC_API(2,13) int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path); +BOTAN_PUBLIC_API(2,13) int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len); + +BOTAN_PUBLIC_API(2,13) int botan_x509_crl_destroy(botan_x509_crl_t crl); + +/** + * Given a CRL and a certificate, + * check if the certificate is revoked on that particular CRL + */ +BOTAN_PUBLIC_API(2,13) int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert); + +/** + * Different flavor of `botan_x509_cert_verify`, supports revocation lists. + * CRLs are passed as an array, same as intermediates and trusted CAs + */ +BOTAN_PUBLIC_API(2,13) int botan_x509_cert_verify_with_crl( + int* validation_result, + botan_x509_cert_t cert, + const botan_x509_cert_t* intermediates, + size_t intermediates_len, + const botan_x509_cert_t* trusted, + size_t trusted_len, + const botan_x509_crl_t* crls, + size_t crls_len, + const char* trusted_path, + size_t required_strength, + const char* hostname, + uint64_t reference_time); + +/** + * Key wrapping as per RFC 3394 + */ +BOTAN_PUBLIC_API(2,2) +int botan_key_wrap3394(const uint8_t key[], size_t key_len, + const uint8_t kek[], size_t kek_len, + uint8_t wrapped_key[], size_t *wrapped_key_len); + +BOTAN_PUBLIC_API(2,2) +int botan_key_unwrap3394(const uint8_t wrapped_key[], size_t wrapped_key_len, + const uint8_t kek[], size_t kek_len, + uint8_t key[], size_t *key_len); + +/** +* HOTP +*/ + +typedef struct botan_hotp_struct* botan_hotp_t; + +/** +* Initialize a HOTP instance +*/ +BOTAN_PUBLIC_API(2,8) +int botan_hotp_init(botan_hotp_t* hotp, + const uint8_t key[], size_t key_len, + const char* hash_algo, + size_t digits); + +/** +* Destroy a HOTP instance +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,8) +int botan_hotp_destroy(botan_hotp_t hotp); + +/** +* Generate a HOTP code for the provided counter +*/ +BOTAN_PUBLIC_API(2,8) +int botan_hotp_generate(botan_hotp_t hotp, + uint32_t* hotp_code, + uint64_t hotp_counter); + +/** +* Verify a HOTP code +*/ +BOTAN_PUBLIC_API(2,8) +int botan_hotp_check(botan_hotp_t hotp, + uint64_t* next_hotp_counter, + uint32_t hotp_code, + uint64_t hotp_counter, + size_t resync_range); + + +/** +* TOTP +*/ + +typedef struct botan_totp_struct* botan_totp_t; + +/** +* Initialize a TOTP instance +*/ +BOTAN_PUBLIC_API(2,8) +int botan_totp_init(botan_totp_t* totp, + const uint8_t key[], size_t key_len, + const char* hash_algo, + size_t digits, + size_t time_step); + +/** +* Destroy a TOTP instance +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,8) +int botan_totp_destroy(botan_totp_t totp); + +/** +* Generate a TOTP code for the provided timestamp +* @param totp the TOTP object +* @param totp_code the OTP code will be written here +* @param timestamp the current local timestamp +*/ +BOTAN_PUBLIC_API(2,8) +int botan_totp_generate(botan_totp_t totp, + uint32_t* totp_code, + uint64_t timestamp); + +/** +* Verify a TOTP code +* @param totp the TOTP object +* @param totp_code the presented OTP +* @param timestamp the current local timestamp +* @param acceptable_clock_drift specifies the acceptable amount +* of clock drift (in terms of time steps) between the two hosts. +*/ +BOTAN_PUBLIC_API(2,8) +int botan_totp_check(botan_totp_t totp, + uint32_t totp_code, + uint64_t timestamp, + size_t acceptable_clock_drift); + + +/** +* Format Preserving Encryption +*/ + +typedef struct botan_fpe_struct* botan_fpe_t; + +#define BOTAN_FPE_FLAG_FE1_COMPAT_MODE 1 + +BOTAN_PUBLIC_API(2,8) +int botan_fpe_fe1_init(botan_fpe_t* fpe, botan_mp_t n, + const uint8_t key[], size_t key_len, + size_t rounds, uint32_t flags); + +/** +* @return 0 if success, error if invalid object handle +*/ +BOTAN_PUBLIC_API(2,8) +int botan_fpe_destroy(botan_fpe_t fpe); + +BOTAN_PUBLIC_API(2,8) +int botan_fpe_encrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len); + +BOTAN_PUBLIC_API(2,8) +int botan_fpe_decrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/ffi/ffi_block.cpp b/comm/third_party/botan/src/lib/ffi/ffi_block.cpp new file mode 100644 index 0000000000..fa5c25c57e --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_block.cpp @@ -0,0 +1,112 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +extern "C" { + +using namespace Botan_FFI; + +BOTAN_FFI_DECLARE_STRUCT(botan_block_cipher_struct, Botan::BlockCipher, 0x64C29716); + +int botan_block_cipher_init(botan_block_cipher_t* bc, const char* bc_name) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(bc == nullptr || bc_name == nullptr || *bc_name == 0) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *bc = nullptr; + + std::unique_ptr cipher(Botan::BlockCipher::create(bc_name)); + if(cipher == nullptr) + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + *bc = new botan_block_cipher_struct(cipher.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +/** +* Destroy a block cipher object +*/ +int botan_block_cipher_destroy(botan_block_cipher_t bc) + { + return BOTAN_FFI_CHECKED_DELETE(bc); + } + +int botan_block_cipher_clear(botan_block_cipher_t bc) + { + return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.clear(); }); + } + +/** +* Set the key for a block cipher instance +*/ +int botan_block_cipher_set_key(botan_block_cipher_t bc, + const uint8_t key[], size_t len) + { + if(key == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.set_key(key, len); }); + } + +/** +* Return the positive block size of this block cipher, or negative to +* indicate an error +*/ +int botan_block_cipher_block_size(botan_block_cipher_t bc) + { + return BOTAN_FFI_RETURNING(Botan::BlockCipher, bc, b, + { return static_cast(b.block_size()); }); + } + +int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc, + const uint8_t in[], + uint8_t out[], + size_t blocks) + { + if(in == nullptr || out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.encrypt_n(in, out, blocks); }); + } + +int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc, + const uint8_t in[], + uint8_t out[], + size_t blocks) + { + if(in == nullptr || out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.decrypt_n(in, out, blocks); }); + } + +int botan_block_cipher_name(botan_block_cipher_t cipher, char* name, size_t* name_len) + { + if(name_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::BlockCipher, cipher, bc, { + return write_str_output(name, name_len, bc.name()); }); + } + +int botan_block_cipher_get_keyspec(botan_block_cipher_t cipher, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength, + size_t* out_keylength_modulo) + { + return BOTAN_FFI_DO(Botan::BlockCipher, cipher, bc, { + if(out_minimum_keylength) + *out_minimum_keylength = bc.minimum_keylength(); + if(out_maximum_keylength) + *out_maximum_keylength = bc.maximum_keylength(); + if(out_keylength_modulo) + *out_keylength_modulo = bc.key_spec().keylength_multiple(); + }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_cert.cpp b/comm/third_party/botan/src/lib/ffi/ffi_cert.cpp new file mode 100644 index 0000000000..1baaa18d6b --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_cert.cpp @@ -0,0 +1,503 @@ +/* +* (C) 2015,2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + #include + #include + #include + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + +BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937); + +#endif + +int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) + { + if(!cert_obj || !cert_path) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr c(new Botan::X509_Certificate(cert_path)); + *cert_obj = new botan_x509_cert_struct(c.release()); + return BOTAN_FFI_SUCCESS; + }); + +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) + { + if(!cert_obj) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr c(new Botan::X509_Certificate(safe_get(cert))); + *cert_obj = new botan_x509_cert_struct(c.release()); + return BOTAN_FFI_SUCCESS; + }); + +#else + BOTAN_UNUSED(cert); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) + { + if(!cert_obj || !cert_bits) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DataSource_Memory bits(cert_bits, cert_bits_len); + std::unique_ptr c(new Botan::X509_Certificate(bits)); + *cert_obj = new botan_x509_cert_struct(c.release()); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(cert_bits_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) + { + if(key == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *key = nullptr; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr publicKey = safe_get(cert).load_subject_public_key(); + *key = new botan_pubkey_struct(publicKey.release()); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(cert); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.issuer_info(key).at(index)); }); +#else + BOTAN_UNUSED(cert, key, index, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.subject_info(key).at(index)); }); +#else + BOTAN_UNUSED(cert, key, index, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.to_string()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_RETURNING(Botan::X509_Certificate, cert, c, { + const Botan::Key_Constraints k = static_cast(key_usage); + if(c.allowed_usage(k)) + return BOTAN_FFI_SUCCESS; + return 1; + }); +#else + BOTAN_UNUSED(cert, key_usage); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_destroy(botan_x509_cert_t cert) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_CHECKED_DELETE(cert); +#else + BOTAN_UNUSED(cert); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.not_before().to_string()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.not_after().to_string()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { + *time_since_epoch = c.not_before().time_since_epoch(); + }); +#else + BOTAN_UNUSED(cert, time_since_epoch); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { + *time_since_epoch = c.not_after().time_since_epoch(); + }); +#else + BOTAN_UNUSED(cert, time_since_epoch); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.serial_number()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.fingerprint(hash)); }); +#else + BOTAN_UNUSED(cert, hash, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.authority_key_id()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_key_id()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_public_key_bits()); }); +#else + BOTAN_UNUSED(cert, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) + { + if(hostname == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, + { return c.matches_dns_name(hostname) ? 0 : -1; }); +#else + BOTAN_UNUSED(cert); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_verify(int* result_code, + botan_x509_cert_t cert, + const botan_x509_cert_t* intermediates, + size_t intermediates_len, + const botan_x509_cert_t* trusted, + size_t trusted_len, + const char* trusted_path, + size_t required_strength, + const char* hostname_cstr, + uint64_t reference_time) + { + if(required_strength == 0) + required_strength = 110; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return ffi_guard_thunk(__func__, [=]() -> int { + const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr); + const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED; + const auto validation_time = reference_time == 0 ? + std::chrono::system_clock::now() : + std::chrono::system_clock::from_time_t(static_cast(reference_time)); + + std::vector end_certs; + end_certs.push_back(safe_get(cert)); + for(size_t i = 0; i != intermediates_len; ++i) + end_certs.push_back(safe_get(intermediates[i])); + + std::unique_ptr trusted_from_path; + std::unique_ptr trusted_extra; + std::vector trusted_roots; + + if(trusted_path && *trusted_path) + { + trusted_from_path.reset(new Botan::Certificate_Store_In_Memory(trusted_path)); + trusted_roots.push_back(trusted_from_path.get()); + } + + if(trusted_len > 0) + { + trusted_extra.reset(new Botan::Certificate_Store_In_Memory); + for(size_t i = 0; i != trusted_len; ++i) + { + trusted_extra->add_certificate(safe_get(trusted[i])); + } + trusted_roots.push_back(trusted_extra.get()); + } + + Botan::Path_Validation_Restrictions restrictions(false, required_strength); + + auto validation_result = Botan::x509_path_validate(end_certs, + restrictions, + trusted_roots, + hostname, + usage, + validation_time); + + if(result_code) + *result_code = static_cast(validation_result.result()); + + if(validation_result.successful_validation()) + return 0; + else + return 1; + }); +#else + BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted); + BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +const char* botan_x509_cert_validation_status(int code) + { + if(code < 0) + return nullptr; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + Botan::Certificate_Status_Code sc = static_cast(code); + return Botan::to_string(sc); +#else + return nullptr; +#endif + } + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + +BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910); + +#endif + +int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) + { + if(!crl_obj || !crl_path) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr c(new Botan::X509_CRL(crl_path)); + *crl_obj = new botan_x509_crl_struct(c.release()); + return BOTAN_FFI_SUCCESS; + }); + +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) + { + if(!crl_obj || !crl_bits) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DataSource_Memory bits(crl_bits, crl_bits_len); + std::unique_ptr c(new Botan::X509_CRL(bits)); + *crl_obj = new botan_x509_crl_struct(c.release()); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(crl_bits_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_crl_destroy(botan_x509_crl_t crl) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_CHECKED_DELETE(crl); +#else + BOTAN_UNUSED(crl); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) + { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_RETURNING(Botan::X509_CRL, crl, c, { + return c.is_revoked(safe_get(cert)) ? 0 : -1; + }); +#else + BOTAN_UNUSED(cert); + BOTAN_UNUSED(crl); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_x509_cert_verify_with_crl( + int* result_code, + botan_x509_cert_t cert, + const botan_x509_cert_t* intermediates, + size_t intermediates_len, + const botan_x509_cert_t* trusted, + size_t trusted_len, + const botan_x509_crl_t* crls, + size_t crls_len, + const char* trusted_path, + size_t required_strength, + const char* hostname_cstr, + uint64_t reference_time) + { + if(required_strength == 0) + required_strength = 110; + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return ffi_guard_thunk(__func__, [=]() -> int { + const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr); + const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED; + const auto validation_time = reference_time == 0 ? + std::chrono::system_clock::now() : + std::chrono::system_clock::from_time_t(static_cast(reference_time)); + + std::vector end_certs; + end_certs.push_back(safe_get(cert)); + for(size_t i = 0; i != intermediates_len; ++i) + end_certs.push_back(safe_get(intermediates[i])); + + std::unique_ptr trusted_from_path; + std::unique_ptr trusted_extra; + std::unique_ptr trusted_crls; + std::vector trusted_roots; + + if(trusted_path && *trusted_path) + { + trusted_from_path.reset(new Botan::Certificate_Store_In_Memory(trusted_path)); + trusted_roots.push_back(trusted_from_path.get()); + } + + if(trusted_len > 0) + { + trusted_extra.reset(new Botan::Certificate_Store_In_Memory); + for(size_t i = 0; i != trusted_len; ++i) + { + trusted_extra->add_certificate(safe_get(trusted[i])); + } + trusted_roots.push_back(trusted_extra.get()); + } + + if(crls_len > 0) + { + trusted_crls.reset(new Botan::Certificate_Store_In_Memory); + for(size_t i = 0; i != crls_len; ++i) + { + trusted_crls->add_crl(safe_get(crls[i])); + } + trusted_roots.push_back(trusted_crls.get()); + } + + Botan::Path_Validation_Restrictions restrictions(false, required_strength); + + auto validation_result = Botan::x509_path_validate(end_certs, + restrictions, + trusted_roots, + hostname, + usage, + validation_time); + + if(result_code) + *result_code = static_cast(validation_result.result()); + + if(validation_result.successful_validation()) + return 0; + else + return 1; + }); +#else + BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted); + BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_cipher.cpp b/comm/third_party/botan/src/lib/ffi/ffi_cipher.cpp new file mode 100644 index 0000000000..17f443c895 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_cipher.cpp @@ -0,0 +1,233 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +extern "C" { + +using namespace Botan_FFI; + +struct botan_cipher_struct final : public botan_struct + { + explicit botan_cipher_struct(Botan::Cipher_Mode* x) : botan_struct(x) {} + Botan::secure_vector m_buf; + }; + +int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags) + { + return ffi_guard_thunk(__func__, [=]() -> int { + const bool encrypt_p = ((flags & BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION) == BOTAN_CIPHER_INIT_FLAG_ENCRYPT); + const Botan::Cipher_Dir dir = encrypt_p ? Botan::ENCRYPTION : Botan::DECRYPTION; + std::unique_ptr mode(Botan::Cipher_Mode::create(cipher_name, dir)); + if(!mode) + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + *cipher = new botan_cipher_struct(mode.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_cipher_destroy(botan_cipher_t cipher) + { + return BOTAN_FFI_CHECKED_DELETE(cipher); + } + +int botan_cipher_clear(botan_cipher_t cipher) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.clear(); }); + } + +int botan_cipher_reset(botan_cipher_t cipher) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.reset(); }); + } + +int botan_cipher_output_length(botan_cipher_t cipher, size_t in_len, size_t* out_len) + { + if(out_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *out_len = c.output_length(in_len); }); + } + +int botan_cipher_query_keylen(botan_cipher_t cipher, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { + *out_minimum_keylength = c.key_spec().minimum_keylength(); + *out_maximum_keylength = c.key_spec().maximum_keylength(); + }); + } + +int botan_cipher_get_keyspec(botan_cipher_t cipher, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength, + size_t* out_keylength_modulo) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { + if(out_minimum_keylength) + *out_minimum_keylength = c.key_spec().minimum_keylength(); + if(out_maximum_keylength) + *out_maximum_keylength = c.key_spec().maximum_keylength(); + if(out_keylength_modulo) + *out_keylength_modulo = c.key_spec().keylength_multiple(); + }); + } + +int botan_cipher_set_key(botan_cipher_t cipher, + const uint8_t* key, size_t key_len) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.set_key(key, key_len); }); + } + +int botan_cipher_start(botan_cipher_t cipher_obj, + const uint8_t* nonce, size_t nonce_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::Cipher_Mode& cipher = safe_get(cipher_obj); + cipher.start(nonce, nonce_len); + cipher_obj->m_buf.reserve(cipher.update_granularity()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_cipher_update(botan_cipher_t cipher_obj, + uint32_t flags, + uint8_t output_ptr[], + size_t orig_output_size, + size_t* output_written, + const uint8_t input_ptr[], + size_t orig_input_size, + size_t* input_consumed) + { + return ffi_guard_thunk(__func__, [=]() -> int { + + size_t input_size = orig_input_size; + size_t output_size = orig_output_size; + const uint8_t* input = input_ptr; + uint8_t* output = output_ptr; + + using namespace Botan; + Cipher_Mode& cipher = safe_get(cipher_obj); + secure_vector& mbuf = cipher_obj->m_buf; + + const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL); + + if(final_input) + { + mbuf.assign(input, input + input_size); + *input_consumed = input_size; + *output_written = 0; + + try + { + cipher.finish(mbuf); + } + catch(Invalid_Authentication_Tag&) + { + return BOTAN_FFI_ERROR_BAD_MAC; + } + + *output_written = mbuf.size(); + + if(mbuf.size() <= output_size) + { + copy_mem(output, mbuf.data(), mbuf.size()); + mbuf.clear(); + return BOTAN_FFI_SUCCESS; + } + + return -1; + } + + if(input_size == 0) + { + // Currently must take entire buffer in this case + *output_written = mbuf.size(); + if(output_size >= mbuf.size()) + { + copy_mem(output, mbuf.data(), mbuf.size()); + mbuf.clear(); + return BOTAN_FFI_SUCCESS; + } + + return -1; + } + + const size_t ud = cipher.update_granularity(); + BOTAN_ASSERT(cipher.update_granularity() > cipher.minimum_final_size(), "logic error"); + + mbuf.resize(ud); + size_t taken = 0, written = 0; + + while(input_size >= ud && output_size >= ud) + { + // FIXME we can use process here and avoid the copy + copy_mem(mbuf.data(), input, ud); + cipher.update(mbuf); + + input_size -= ud; + copy_mem(output, mbuf.data(), ud); + input += ud; + taken += ud; + + output_size -= ud; + output += ud; + written += ud; + } + + *output_written = written; + *input_consumed = taken; + + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_cipher_set_associated_data(botan_cipher_t cipher, + const uint8_t* ad, + size_t ad_len) + { + return BOTAN_FFI_RETURNING(Botan::Cipher_Mode, cipher, c, { + if(Botan::AEAD_Mode* aead = dynamic_cast(&c)) + { + aead->set_associated_data(ad, ad_len); + return BOTAN_FFI_SUCCESS; + } + return BOTAN_FFI_ERROR_BAD_PARAMETER; + }); + } + +int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl) + { + return BOTAN_FFI_RETURNING(Botan::Cipher_Mode, cipher, c, { + return c.valid_nonce_length(nl) ? 1 : 0; + }); + } + +int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *nl = c.default_nonce_length(); }); + } + +int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *ug = c.update_granularity(); }); + } + +int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *tl = c.tag_size(); }); + } + +int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len) + { + return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { + return write_str_output(name, name_len, c.name()); }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_fpe.cpp b/comm/third_party/botan/src/lib/ffi/ffi_fpe.cpp new file mode 100644 index 0000000000..01706ea201 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_fpe.cpp @@ -0,0 +1,94 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_FPE_FE1) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +#if defined(BOTAN_HAS_FPE_FE1) + +BOTAN_FFI_DECLARE_STRUCT(botan_fpe_struct, Botan::FPE_FE1, 0xD49FB820); + +#endif + +int botan_fpe_fe1_init(botan_fpe_t* fpe, botan_mp_t n, + const uint8_t key[], size_t key_len, + size_t rounds, uint32_t flags) + { +#if defined(BOTAN_HAS_FPE_FE1) + + return ffi_guard_thunk(__func__, [=]() { + + if(fpe == nullptr || key == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *fpe = nullptr; + + if(flags != 0 && flags != BOTAN_FPE_FLAG_FE1_COMPAT_MODE) + return BOTAN_FFI_ERROR_BAD_FLAG; + + const bool compat_mode = (flags & BOTAN_FPE_FLAG_FE1_COMPAT_MODE); + + std::unique_ptr fpe_obj( + new Botan::FPE_FE1(safe_get(n), rounds, compat_mode)); + + fpe_obj->set_key(key, key_len); + + *fpe = new botan_fpe_struct(fpe_obj.release()); + return BOTAN_FFI_SUCCESS; + }); +#else + *fpe = nullptr; + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_fpe_destroy(botan_fpe_t fpe) + { +#if defined(BOTAN_HAS_FPE_FE1) + return BOTAN_FFI_CHECKED_DELETE(fpe); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_fpe_encrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len) + { +#if defined(BOTAN_HAS_FPE_FE1) + return ffi_guard_thunk(__func__, [=]() { + Botan::BigInt r = safe_get(fpe).encrypt(safe_get(x), tweak, tweak_len); + safe_get(x) = r; + return BOTAN_FFI_SUCCESS; + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_fpe_decrypt(botan_fpe_t fpe, botan_mp_t x, const uint8_t tweak[], size_t tweak_len) + { +#if defined(BOTAN_HAS_FPE_FE1) + return ffi_guard_thunk(__func__, [=]() { + Botan::BigInt r = safe_get(fpe).decrypt(safe_get(x), tweak, tweak_len); + safe_get(x) = r; + return BOTAN_FFI_SUCCESS; + }); + +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_hash.cpp b/comm/third_party/botan/src/lib/ffi/ffi_hash.cpp new file mode 100644 index 0000000000..12eb92301e --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_hash.cpp @@ -0,0 +1,91 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +extern "C" { + +using namespace Botan_FFI; + +BOTAN_FFI_DECLARE_STRUCT(botan_hash_struct, Botan::HashFunction, 0x1F0A4F84); + +int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(hash == nullptr || hash_name == nullptr || *hash_name == 0) + return BOTAN_FFI_ERROR_NULL_POINTER; + if(flags != 0) + return BOTAN_FFI_ERROR_BAD_FLAG; + + std::unique_ptr h = Botan::HashFunction::create(hash_name); + if(h == nullptr) + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + *hash = new botan_hash_struct(h.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_hash_destroy(botan_hash_t hash) + { + return BOTAN_FFI_CHECKED_DELETE(hash); + } + +int botan_hash_output_length(botan_hash_t hash, size_t* out) + { + if(out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.output_length(); }); + } + +int botan_hash_block_size(botan_hash_t hash, size_t* out) + { + if(out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.hash_block_size(); }); + } + +int botan_hash_clear(botan_hash_t hash) + { + return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.clear(); }); + } + +int botan_hash_update(botan_hash_t hash, const uint8_t* buf, size_t len) + { + if(len == 0) + return 0; + + if(buf == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.update(buf, len); }); + } + +int botan_hash_final(botan_hash_t hash, uint8_t out[]) + { + if(out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.final(out); }); + } + +int botan_hash_copy_state(botan_hash_t* dest, const botan_hash_t source) + { + return BOTAN_FFI_DO(Botan::HashFunction, source, src, { + *dest = new botan_hash_struct(src.copy_state().release()); }); + } + +int botan_hash_name(botan_hash_t hash, char* name, size_t* name_len) + { + if(name_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { + return write_str_output(name, name_len, h.name()); }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_hotp.cpp b/comm/third_party/botan/src/lib/ffi/ffi_hotp.cpp new file mode 100644 index 0000000000..74f059d502 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_hotp.cpp @@ -0,0 +1,99 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_HOTP) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +#if defined(BOTAN_HAS_HOTP) + +BOTAN_FFI_DECLARE_STRUCT(botan_hotp_struct, Botan::HOTP, 0x89CBF191); + +#endif + +int botan_hotp_init(botan_hotp_t* hotp, + const uint8_t key[], size_t key_len, + const char* hash_algo, + size_t digits) + { + if(hotp == nullptr || key == nullptr || hash_algo == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *hotp = nullptr; + +#if defined(BOTAN_HAS_HOTP) + return ffi_guard_thunk(__func__, [=]() -> int { + + *hotp = new botan_hotp_struct( + new Botan::HOTP(key, key_len, hash_algo, digits)); + + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(hotp, key, key_len, hash_algo, digits); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_hotp_destroy(botan_hotp_t hotp) + { +#if defined(BOTAN_HAS_HOTP) + return BOTAN_FFI_CHECKED_DELETE(hotp); +#else + BOTAN_UNUSED(hotp); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_hotp_generate(botan_hotp_t hotp, + uint32_t* hotp_code, + uint64_t hotp_counter) + { +#if defined(BOTAN_HAS_HOTP) + if(hotp == nullptr || hotp_code == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::HOTP, hotp, h, { + *hotp_code = h.generate_hotp(hotp_counter); + }); + +#else + BOTAN_UNUSED(hotp, hotp_code, hotp_counter); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_hotp_check(botan_hotp_t hotp, + uint64_t* next_hotp_counter, + uint32_t hotp_code, + uint64_t hotp_counter, + size_t resync_range) + { +#if defined(BOTAN_HAS_HOTP) + return BOTAN_FFI_RETURNING(Botan::HOTP, hotp, h, { + + auto resp = h.verify_hotp(hotp_code, hotp_counter, resync_range); + + if(next_hotp_counter) + *next_hotp_counter = resp.second; + + return (resp.first == true) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER; + }); + +#else + BOTAN_UNUSED(hotp, next_hotp_counter, hotp_code, hotp_counter, resync_range); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_kdf.cpp b/comm/third_party/botan/src/lib/ffi/ffi_kdf.cpp new file mode 100644 index 0000000000..d38dd594bd --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_kdf.cpp @@ -0,0 +1,189 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BCRYPT) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +int botan_pbkdf(const char* algo, uint8_t out[], size_t out_len, + const char* pass, const uint8_t salt[], size_t salt_len, + size_t iterations) + { + return botan_pwdhash(algo, + iterations, + 0, + 0, + out, out_len, + pass, 0, + salt, salt_len); + } + +int botan_pbkdf_timed(const char* algo, + uint8_t out[], size_t out_len, + const char* password, + const uint8_t salt[], size_t salt_len, + size_t ms_to_run, + size_t* iterations_used) + { + return botan_pwdhash_timed(algo, + static_cast(ms_to_run), + iterations_used, + nullptr, + nullptr, + out, out_len, + password, 0, + salt, salt_len); + } + +int botan_pwdhash( + const char* algo, + size_t param1, + size_t param2, + size_t param3, + uint8_t out[], + size_t out_len, + const char* password, + size_t password_len, + const uint8_t salt[], + size_t salt_len) + { + if(algo == nullptr || password == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(password_len == 0) + password_len = std::strlen(password); + + return ffi_guard_thunk(__func__, [=]() -> int { + auto pwdhash_fam = Botan::PasswordHashFamily::create(algo); + + if(!pwdhash_fam) + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + auto pwdhash = pwdhash_fam->from_params(param1, param2, param3); + + pwdhash->derive_key(out, out_len, + password, password_len, + salt, salt_len); + + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pwdhash_timed( + const char* algo, + uint32_t msec, + size_t* param1, + size_t* param2, + size_t* param3, + uint8_t out[], + size_t out_len, + const char* password, + size_t password_len, + const uint8_t salt[], + size_t salt_len) + { + if(algo == nullptr || password == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(password_len == 0) + password_len = std::strlen(password); + + return ffi_guard_thunk(__func__, [=]() -> int { + + auto pwdhash_fam = Botan::PasswordHashFamily::create(algo); + + if(!pwdhash_fam) + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + auto pwdhash = pwdhash_fam->tune(out_len, std::chrono::milliseconds(msec)); + + if(param1) + *param1 = pwdhash->iterations(); + if(param2) + *param2 = pwdhash->parallelism(); + if(param3) + *param3 = pwdhash->memory_param(); + + pwdhash->derive_key(out, out_len, + password, password_len, + salt, salt_len); + + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_kdf(const char* kdf_algo, + uint8_t out[], size_t out_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr kdf(Botan::get_kdf(kdf_algo)); + kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_scrypt(uint8_t out[], size_t out_len, + const char* password, + const uint8_t salt[], size_t salt_len, + size_t N, size_t r, size_t p) + { + return botan_pwdhash("Scrypt", N, r, p, + out, out_len, + password, 0, + salt, salt_len); + } + +int botan_bcrypt_generate(uint8_t* out, size_t* out_len, + const char* pass, + botan_rng_t rng_obj, size_t wf, + uint32_t flags) + { +#if defined(BOTAN_HAS_BCRYPT) + return ffi_guard_thunk(__func__, [=]() -> int { + if(out == nullptr || out_len == nullptr || pass == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(flags != 0) + return BOTAN_FFI_ERROR_BAD_FLAG; + + if(wf < 4 || wf > 18) + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + const std::string bcrypt = Botan::generate_bcrypt(pass, rng, static_cast(wf)); + return write_str_output(out, out_len, bcrypt); + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_bcrypt_is_valid(const char* pass, const char* hash) + { +#if defined(BOTAN_HAS_BCRYPT) + return ffi_guard_thunk(__func__, [=]() -> int { + return Botan::check_bcrypt(pass, hash) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER; + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_keywrap.cpp b/comm/third_party/botan/src/lib/ffi/ffi_keywrap.cpp new file mode 100644 index 0000000000..f74904cb7f --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_keywrap.cpp @@ -0,0 +1,50 @@ +/* +* (C) 2017 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +int botan_key_wrap3394(const uint8_t key[], size_t key_len, + const uint8_t kek[], size_t kek_len, + uint8_t wrapped_key[], size_t* wrapped_key_len) + { +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) + return ffi_guard_thunk(__func__, [=]() -> int { + const Botan::SymmetricKey kek_sym(kek, kek_len); + const Botan::secure_vector key_pt(key, key + key_len); + const Botan::secure_vector key_ct = Botan::rfc3394_keywrap(key_pt, kek_sym); + return write_vec_output(wrapped_key, wrapped_key_len, key_ct); + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_key_unwrap3394(const uint8_t wrapped_key[], size_t wrapped_key_len, + const uint8_t kek[], size_t kek_len, + uint8_t key[], size_t* key_len) + { +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) + return ffi_guard_thunk(__func__, [=]() -> int { + const Botan::SymmetricKey kek_sym(kek, kek_len); + const Botan::secure_vector key_ct(wrapped_key, wrapped_key + wrapped_key_len); + const Botan::secure_vector key_pt = Botan::rfc3394_keyunwrap(key_ct, kek_sym); + return write_vec_output(key, key_len, key_pt); + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_mac.cpp b/comm/third_party/botan/src/lib/ffi/ffi_mac.cpp new file mode 100644 index 0000000000..3b6cc3bef4 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_mac.cpp @@ -0,0 +1,85 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +extern "C" { + +using namespace Botan_FFI; + +BOTAN_FFI_DECLARE_STRUCT(botan_mac_struct, Botan::MessageAuthenticationCode, 0xA06E8FC1); + +int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(!mac || !mac_name || flags != 0) + return BOTAN_FFI_ERROR_NULL_POINTER; + + std::unique_ptr m = + Botan::MessageAuthenticationCode::create(mac_name); + + if(m == nullptr) + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + *mac = new botan_mac_struct(m.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_mac_destroy(botan_mac_t mac) + { + return BOTAN_FFI_CHECKED_DELETE(mac); + } + +int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.set_key(key, key_len); }); + } + +int botan_mac_output_length(botan_mac_t mac, size_t* out) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { *out = m.output_length(); }); + } + +int botan_mac_clear(botan_mac_t mac) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.clear(); }); + } + +int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.update(buf, len); }); + } + +int botan_mac_final(botan_mac_t mac, uint8_t out[]) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.final(out); }); + } + +int botan_mac_name(botan_mac_t mac, char* name, size_t* name_len) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { + return write_str_output(name, name_len, m.name()); }); + } + +int botan_mac_get_keyspec(botan_mac_t mac, + size_t* out_minimum_keylength, + size_t* out_maximum_keylength, + size_t* out_keylength_modulo) + { + return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { + if(out_minimum_keylength) + *out_minimum_keylength = m.minimum_keylength(); + if(out_maximum_keylength) + *out_maximum_keylength = m.maximum_keylength(); + if(out_keylength_modulo) + *out_keylength_modulo = m.key_spec().keylength_multiple(); + }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_mp.cpp b/comm/third_party/botan/src/lib/ffi/ffi_mp.cpp new file mode 100644 index 0000000000..68869e6ecf --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_mp.cpp @@ -0,0 +1,312 @@ +/* +* (C) 2015,2017 Jack Lloyd +* (C) 2017 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + +using namespace Botan_FFI; + +int botan_mp_init(botan_mp_t* mp_out) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(mp_out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *mp_out = new botan_mp_struct(new Botan::BigInt); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_mp_clear(botan_mp_t mp) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.clear(); }); + } + +int botan_mp_set_from_int(botan_mp_t mp, int initial_value) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { + if(initial_value >= 0) + { + bn = Botan::BigInt(static_cast(initial_value)); + } + else + { + bn = Botan::BigInt(static_cast(-initial_value)); + bn.flip_sign(); + } + }); + } + +int botan_mp_set_from_str(botan_mp_t mp, const char* str) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn = Botan::BigInt(str); }); + } + +int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { + Botan::BigInt::Base base; + if(radix == 10) + base = Botan::BigInt::Decimal; + else if(radix == 16) + base = Botan::BigInt::Hexadecimal; + else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + const uint8_t* bytes = Botan::cast_char_ptr_to_uint8(str); + const size_t len = strlen(str); + + bn = Botan::BigInt(bytes, len, base); + }); + } + +int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source) + { + return BOTAN_FFI_DO(Botan::BigInt, dest, bn, { bn = safe_get(source); }); + } + +int botan_mp_is_negative(const botan_mp_t mp) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_negative() ? 1 : 0; }); + } + +int botan_mp_is_positive(const botan_mp_t mp) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_positive() ? 1 : 0; }); + } + +int botan_mp_flip_sign(botan_mp_t mp) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.flip_sign(); }); + } + +int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_decode(bin, bin_len); }); + } + +int botan_mp_to_hex(const botan_mp_t mp, char* out) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { + const std::string hex = bn.to_hex_string(); + std::memcpy(out, hex.c_str(), 1 + hex.size()); + }); + } + +int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { + + if(digit_base == 0 || digit_base == 10) + return write_str_output(out, out_len, bn.to_dec_string()); + else if(digit_base == 16) + return write_str_output(out, out_len, bn.to_hex_string()); + else + return BOTAN_FFI_ERROR_BAD_PARAMETER; + }); + } + +int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[]) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_encode(vec); }); + } + +int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val) + { + if(val == nullptr) + { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { *val = bn.to_u32bit(); }); + } + +int botan_mp_destroy(botan_mp_t mp) + { + return BOTAN_FFI_CHECKED_DELETE(mp); + } + +int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, result, res, { + if(result == x) + res += safe_get(y); + else + res = safe_get(x) + safe_get(y); + }); + } + +int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, result, res, { + if(result == x) + res -= safe_get(y); + else + res = safe_get(x) - safe_get(y); + }); + } + +int botan_mp_add_u32(botan_mp_t result, const botan_mp_t x, uint32_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, result, res, { + if(result == x) + res += static_cast(y); + else + res = safe_get(x) + static_cast(y); + }); + } + +int botan_mp_sub_u32(botan_mp_t result, const botan_mp_t x, uint32_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, result, res, { + if(result == x) + res -= static_cast(y); + else + res = safe_get(x) - static_cast(y); + }); + } + +int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, result, res, { + if(result == x) + res *= safe_get(y); + else + res = safe_get(x) * safe_get(y); + }); + } + +int botan_mp_div(botan_mp_t quotient, + botan_mp_t remainder, + const botan_mp_t x, const botan_mp_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, quotient, q, { + Botan::BigInt r; + Botan::vartime_divide(safe_get(x), safe_get(y), q, r); + safe_get(remainder) = r; + }); + } + +int botan_mp_equal(const botan_mp_t x_w, const botan_mp_t y_w) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, x_w, x, { return x == safe_get(y_w); }); + } + +int botan_mp_is_zero(const botan_mp_t mp) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_zero(); }); + } + +int botan_mp_is_odd(const botan_mp_t mp) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_odd(); }); + } + +int botan_mp_is_even(const botan_mp_t mp) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_even(); }); + } + +int botan_mp_cmp(int* result, const botan_mp_t x_w, const botan_mp_t y_w) + { + return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { *result = x.cmp(safe_get(y_w)); }); + } + +int botan_mp_swap(botan_mp_t x_w, botan_mp_t y_w) + { + return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { x.swap(safe_get(y_w)); }); + } + +// Return (base^exponent) % modulus +int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus) + { + return BOTAN_FFI_DO(Botan::BigInt, out, o, + { o = Botan::power_mod(safe_get(base), safe_get(exponent), safe_get(modulus)); }); + } + +int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift) + { + return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) << shift; }); + } + +int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift) + { + return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) >> shift; }); + } + +int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus) + { + return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::inverse_mod(safe_get(in), safe_get(modulus)); }); + } + +int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus) + { + return BOTAN_FFI_DO(Botan::BigInt, out, o, { + Botan::Modular_Reducer reducer(safe_get(modulus)); + o = reducer.multiply(safe_get(x), safe_get(y)); + }); + } + +int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits) + { + return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { + safe_get(rand_out).randomize(r, bits); }); + } + +int botan_mp_rand_range(botan_mp_t rand_out, + botan_rng_t rng, + const botan_mp_t lower, + const botan_mp_t upper) + { + return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { + safe_get(rand_out) = Botan::BigInt::random_integer(r, safe_get(lower), safe_get(upper)); }); + } + +int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y) + { + return BOTAN_FFI_DO(Botan::BigInt, out, o, { + o = Botan::gcd(safe_get(x), safe_get(y)); }); + } + +int botan_mp_is_prime(const botan_mp_t mp, botan_rng_t rng, size_t test_prob) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, mp, n, + { return (Botan::is_prime(n, safe_get(rng), test_prob)) ? 1 : 0; }); + } + +int botan_mp_get_bit(const botan_mp_t mp, size_t bit) + { + return BOTAN_FFI_RETURNING(Botan::BigInt, mp, n, { return (n.get_bit(bit)); }); + } + +int botan_mp_set_bit(botan_mp_t mp, size_t bit) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.set_bit(bit); }); + } + +int botan_mp_clear_bit(botan_mp_t mp, size_t bit) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.clear_bit(bit); }); + } + +int botan_mp_num_bits(const botan_mp_t mp, size_t* bits) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bits = n.bits(); }); + } + +int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes) + { + return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_mp.h b/comm/third_party/botan/src/lib/ffi/ffi_mp.h new file mode 100644 index 0000000000..3cc85b66a3 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_mp.h @@ -0,0 +1,19 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FFI_MP_H_ +#define BOTAN_FFI_MP_H_ + +#include +#include + +extern "C" { + +BOTAN_FFI_DECLARE_STRUCT(botan_mp_struct, Botan::BigInt, 0xC828B9D2); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/ffi/ffi_pk_op.cpp b/comm/third_party/botan/src/lib/ffi/ffi_pk_op.cpp new file mode 100644 index 0000000000..2efb297aca --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_pk_op.cpp @@ -0,0 +1,255 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +extern "C" { + +using namespace Botan_FFI; + +BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3); +BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37); +BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F); +BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936); +BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1); + +int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, + botan_pubkey_t key_obj, + const char* padding, + uint32_t flags) + { + if(op == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) + return BOTAN_FFI_ERROR_BAD_FLAG; + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + + std::unique_ptr pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), Botan::system_rng(), padding)); + *op = new botan_pk_op_encrypt_struct(pk.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op) + { + return BOTAN_FFI_CHECKED_DELETE(op); + } + +int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, size_t ptext_len, size_t* ctext_len) + { + if(ctext_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, { *ctext_len = o.ciphertext_length(ptext_len); }); + } + +int botan_pk_op_encrypt(botan_pk_op_encrypt_t op, + botan_rng_t rng_obj, + uint8_t out[], size_t* out_len, + const uint8_t plaintext[], size_t plaintext_len) + { + return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, { + return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj))); + }); + } + +/* +* Public Key Decryption +*/ +int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, + botan_privkey_t key_obj, + const char* padding, + uint32_t flags) + { + if(op == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(flags != 0) + return BOTAN_FFI_ERROR_BAD_FLAG; + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + + std::unique_ptr pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), Botan::system_rng(), padding)); + *op = new botan_pk_op_decrypt_struct(pk.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op) + { + return BOTAN_FFI_CHECKED_DELETE(op); + } + +int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, size_t ctext_len, size_t* ptext_len) + { + if(ptext_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, { *ptext_len = o.plaintext_length(ctext_len); }); + } + +int botan_pk_op_decrypt(botan_pk_op_decrypt_t op, + uint8_t out[], size_t* out_len, + const uint8_t ciphertext[], size_t ciphertext_len) + { + return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, { + return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len)); + }); + } + +/* +* Signature Generation +*/ +int botan_pk_op_sign_create(botan_pk_op_sign_t* op, + botan_privkey_t key_obj, + const char* hash, + uint32_t flags) + { + if(op == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) + return BOTAN_FFI_ERROR_BAD_FLAG; + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + + auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::DER_SEQUENCE : Botan::IEEE_1363; + + std::unique_ptr pk(new Botan::PK_Signer(safe_get(key_obj), Botan::system_rng(), hash, format)); + *op = new botan_pk_op_sign_struct(pk.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pk_op_sign_destroy(botan_pk_op_sign_t op) + { + return BOTAN_FFI_CHECKED_DELETE(op); + } + +int botan_pk_op_sign_output_length(botan_pk_op_sign_t op, size_t* sig_len) + { + if(sig_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { *sig_len = o.signature_length(); }); + } + +int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len) + { + return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { o.update(in, in_len); }); + } + +int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { + return write_vec_output(out, out_len, o.signature(safe_get(rng_obj))); + }); + } + +int botan_pk_op_verify_create(botan_pk_op_verify_t* op, + botan_pubkey_t key_obj, + const char* hash, + uint32_t flags) + { + if(op == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) + return BOTAN_FFI_ERROR_BAD_FLAG; + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::DER_SEQUENCE : Botan::IEEE_1363; + std::unique_ptr pk(new Botan::PK_Verifier(safe_get(key_obj), hash, format)); + *op = new botan_pk_op_verify_struct(pk.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pk_op_verify_destroy(botan_pk_op_verify_t op) + { + return BOTAN_FFI_CHECKED_DELETE(op); + } + +int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len) + { + return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, { o.update(in, in_len); }); + } + +int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len) + { + return BOTAN_FFI_RETURNING(Botan::PK_Verifier, op, o, { + const bool legit = o.check_signature(sig, sig_len); + + if(legit) + return BOTAN_FFI_SUCCESS; + else + return BOTAN_FFI_INVALID_VERIFIER; + }); + } + +int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, + botan_privkey_t key_obj, + const char* kdf, + uint32_t flags) + { + if(op == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(flags != 0) + return BOTAN_FFI_ERROR_BAD_FLAG; + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + std::unique_ptr pk(new Botan::PK_Key_Agreement(safe_get(key_obj), Botan::system_rng(), kdf)); + *op = new botan_pk_op_ka_struct(pk.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op) + { + return BOTAN_FFI_CHECKED_DELETE(op); + } + +int botan_pk_op_key_agreement_export_public(botan_privkey_t key, + uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + if(auto kak = dynamic_cast(&k)) + return write_vec_output(out, out_len, kak->public_value()); + return BOTAN_FFI_ERROR_BAD_FLAG; + }); + } + +int botan_pk_op_key_agreement_size(botan_pk_op_ka_t op, size_t* out_len) + { + return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, { + if(out_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + *out_len = o.agreed_value_size(); + }); + } + +int botan_pk_op_key_agreement(botan_pk_op_ka_t op, + uint8_t out[], size_t* out_len, + const uint8_t other_key[], size_t other_key_len, + const uint8_t salt[], size_t salt_len) + { + return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, { + auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of(); + return write_vec_output(out, out_len, k); + }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_pkey.cpp b/comm/third_party/botan/src/lib/ffi/ffi_pkey.cpp new file mode 100644 index 0000000000..2fb3d338e2 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_pkey.cpp @@ -0,0 +1,279 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_HASH_ID) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +int botan_privkey_create(botan_privkey_t* key_obj, + const char* algo_name, + const char* algo_params, + botan_rng_t rng_obj) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(key_obj == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *key_obj = nullptr; + if(rng_obj == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + std::unique_ptr key( + Botan::create_private_key(algo_name ? algo_name : "RSA", + rng, + algo_params ? algo_params : "")); + + if(key) + { + *key_obj = new botan_privkey_struct(key.release()); + return BOTAN_FFI_SUCCESS; + } + else + { + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + } + }); + } + +int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj, + const uint8_t bits[], size_t len, + const char* password) + { + BOTAN_UNUSED(rng_obj); + + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DataSource_Memory src(bits, len); + + std::unique_ptr pkcs8; + + if(password == nullptr) + { + pkcs8 = Botan::PKCS8::load_key(src); + } + else + { + pkcs8 = Botan::PKCS8::load_key(src, std::string(password)); + } + + if(pkcs8) + { + *key = new botan_privkey_struct(pkcs8.release()); + return BOTAN_FFI_SUCCESS; + } + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + }); + } + +int botan_privkey_destroy(botan_privkey_t key) + { + return BOTAN_FFI_CHECKED_DELETE(key); + } + +int botan_pubkey_load(botan_pubkey_t* key, + const uint8_t bits[], size_t bits_len) + { + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DataSource_Memory src(bits, bits_len); + std::unique_ptr pubkey(Botan::X509::load_key(src)); + + if(pubkey == nullptr) + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + + *key = new botan_pubkey_struct(pubkey.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pubkey_destroy(botan_pubkey_t key) + { + return BOTAN_FFI_CHECKED_DELETE(key); + } + +int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) + { + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr + pubkey(Botan::X509::load_key(Botan::X509::BER_encode(safe_get(key_obj)))); + + *pubout = new botan_pubkey_struct(pubkey.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); }); + } + +int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); }); + } + +int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) + { + const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS); + + return BOTAN_FFI_RETURNING(Botan::Public_Key, key, k, { + return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT; + }); + } + +int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) + { + const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS); + return BOTAN_FFI_RETURNING(Botan::Private_Key, key, k, { + return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT; + }); + } + +int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + return write_vec_output(out, out_len, Botan::X509::BER_encode(k)); + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + return write_str_output(out, out_len, Botan::X509::PEM_encode(k)); + else + return BOTAN_FFI_ERROR_BAD_FLAG; + }); + } + +int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + return write_vec_output(out, out_len, Botan::PKCS8::BER_encode(k)); + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + return write_str_output(out, out_len, Botan::PKCS8::PEM_encode(k)); + else + return BOTAN_FFI_ERROR_BAD_FLAG; + }); + } + +int botan_privkey_export_encrypted(botan_privkey_t key, + uint8_t out[], size_t* out_len, + botan_rng_t rng_obj, + const char* pass, + const char* /*ignored - pbe*/, + uint32_t flags) + { + return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags); + } + +int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key, + uint8_t out[], size_t* out_len, + botan_rng_t rng_obj, + const char* pass, + uint32_t pbkdf_msec, + size_t* pbkdf_iters_out, + const char* maybe_cipher, + const char* maybe_pbkdf_hash, + uint32_t flags) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + const std::chrono::milliseconds pbkdf_time(pbkdf_msec); + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + const std::string cipher = (maybe_cipher ? maybe_cipher : ""); + const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : ""); + + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + { + return write_vec_output(out, out_len, + Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash)); + } + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + { + return write_str_output(out, out_len, + Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash)); + } + else + { + return -2; + } + }); + } + +int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key, + uint8_t out[], size_t* out_len, + botan_rng_t rng_obj, + const char* pass, + size_t pbkdf_iter, + const char* maybe_cipher, + const char* maybe_pbkdf_hash, + uint32_t flags) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + const std::string cipher = (maybe_cipher ? maybe_cipher : ""); + const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : ""); + + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + { + return write_vec_output(out, out_len, + Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash)); + } + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + { + return write_str_output(out, out_len, + Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash)); + } + else + { + return -2; + } + }); + } + +int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { *estimate = k.estimated_strength(); }); + } + +int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, + uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + std::unique_ptr h(Botan::HashFunction::create(hash_fn)); + return write_vec_output(out, out_len, h->process(k.public_key_bits())); + }); + } + +int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) + { +#if defined(BOTAN_HAS_HASH_ID) + return ffi_guard_thunk(__func__, [=]() -> int { + const std::vector hash_id = Botan::pkcs_hash_id(hash_name); + return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size()); + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_pkey.h b/comm/third_party/botan/src/lib/ffi/ffi_pkey.h new file mode 100644 index 0000000000..de5e19dd08 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_pkey.h @@ -0,0 +1,20 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FFI_PKEY_H_ +#define BOTAN_FFI_PKEY_H_ + +#include +#include + +extern "C" { + +BOTAN_FFI_DECLARE_STRUCT(botan_pubkey_struct, Botan::Public_Key, 0x2C286519); +BOTAN_FFI_DECLARE_STRUCT(botan_privkey_struct, Botan::Private_Key, 0x7F96385E); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/ffi/ffi_pkey_algs.cpp b/comm/third_party/botan/src/lib/ffi/ffi_pkey_algs.cpp new file mode 100644 index 0000000000..9f5d543100 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_pkey_algs.cpp @@ -0,0 +1,980 @@ +/* +* (C) 2015,2017 Jack Lloyd +* (C) 2017 Ribose Inc +* (C) 2018 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + #include +#endif + +#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY) + #include +#endif + +#if defined(BOTAN_HAS_RSA) + #include +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include +#endif + +#if defined(BOTAN_HAS_DSA) + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include +#endif + +#if defined(BOTAN_HAS_SM2) + #include +#endif + +#if defined(BOTAN_HAS_ECDH) + #include +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + #include +#endif + +#if defined(BOTAN_HAS_ED25519) + #include +#endif + +#if defined(BOTAN_HAS_MCELIECE) + #include +#endif + +#if defined(BOTAN_HAS_MCEIES) + #include +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include +#endif + + +namespace { + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + +// These are always called within an existing try/catch block + +template +int privkey_load_ec(std::unique_ptr& key, + const Botan::BigInt& scalar, + const char* curve_name) + { + if(curve_name == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + Botan::Null_RNG null_rng; + Botan::EC_Group grp(curve_name); + key.reset(new ECPrivateKey_t(null_rng, grp, scalar)); + return BOTAN_FFI_SUCCESS; + } + +template +int pubkey_load_ec(std::unique_ptr& key, + const Botan::BigInt& public_x, + const Botan::BigInt& public_y, + const char* curve_name) + { + if(curve_name == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + Botan::EC_Group grp(curve_name); + Botan::PointGFp uncompressed_point = grp.point(public_x, public_y); + key.reset(new ECPublicKey_t(grp, uncompressed_point)); + return BOTAN_FFI_SUCCESS; + } + +#endif + +Botan::BigInt pubkey_get_field(const Botan::Public_Key& key, + const std::string& field) + { + // Maybe this should be `return key.get_integer_field(field_name)`? + +#if defined(BOTAN_HAS_RSA) + if(const Botan::RSA_PublicKey* rsa = dynamic_cast(&key)) + { + if(field == "n") + return rsa->get_n(); + else if(field == "e") + return rsa->get_e(); + else + throw Botan_FFI::FFI_Error("Bad field", BOTAN_FFI_ERROR_BAD_PARAMETER); + } +#endif + +#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY) + // Handles DSA, ElGamal, etc + if(const Botan::DL_Scheme_PublicKey* dl = dynamic_cast(&key)) + { + if(field == "p") + return dl->group_p(); + else if(field == "q") + return dl->group_q(); + else if(field == "g") + return dl->group_g(); + else if(field == "y") + return dl->get_y(); + else + throw Botan_FFI::FFI_Error("Bad field", BOTAN_FFI_ERROR_BAD_PARAMETER); + } +#endif + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + if(const Botan::EC_PublicKey* ecc = dynamic_cast(&key)) + { + if(field == "public_x") + return ecc->public_point().get_affine_x(); + else if(field == "public_y") + return ecc->public_point().get_affine_y(); + else if(field == "base_x") + return ecc->domain().get_g_x(); + else if(field == "base_y") + return ecc->domain().get_g_y(); + else if(field == "p") + return ecc->domain().get_p(); + else if(field == "a") + return ecc->domain().get_a(); + else if(field == "b") + return ecc->domain().get_b(); + else if(field == "cofactor") + return ecc->domain().get_cofactor(); + else if(field == "order") + return ecc->domain().get_order(); + else + throw Botan_FFI::FFI_Error("Bad field", BOTAN_FFI_ERROR_BAD_PARAMETER); + } +#endif + + // Some other algorithm type not supported by this function + throw Botan_FFI::FFI_Error("Field getter not implemented for this algorithm type", + BOTAN_FFI_ERROR_NOT_IMPLEMENTED); + } + +Botan::BigInt privkey_get_field(const Botan::Private_Key& key, + const std::string& field) + { + //return key.get_integer_field(field); + +#if defined(BOTAN_HAS_RSA) + + if(const Botan::RSA_PrivateKey* rsa = dynamic_cast(&key)) + { + if(field == "p") + return rsa->get_p(); + else if(field == "q") + return rsa->get_q(); + else if(field == "d") + return rsa->get_d(); + else if(field == "c") + return rsa->get_c(); + else if(field == "d1") + return rsa->get_d1(); + else if(field == "d2") + return rsa->get_d2(); + else + return pubkey_get_field(key, field); + } +#endif + +#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY) + // Handles DSA, ElGamal, etc + if(const Botan::DL_Scheme_PrivateKey* dl = dynamic_cast(&key)) + { + if(field == "x") + return dl->get_x(); + else + return pubkey_get_field(key, field); + } +#endif + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + if(const Botan::EC_PrivateKey* ecc = dynamic_cast(&key)) + { + if(field == "x") + return ecc->private_value(); + else + return pubkey_get_field(key, field); + } +#endif + + return pubkey_get_field(key, field); + } + +} + +extern "C" { + +using namespace Botan_FFI; + +int botan_pubkey_get_field(botan_mp_t output, + botan_pubkey_t key, + const char* field_name_cstr) + { + if(field_name_cstr == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + const std::string field_name(field_name_cstr); + + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + safe_get(output) = pubkey_get_field(k, field_name); + }); + } + +int botan_privkey_get_field(botan_mp_t output, + botan_privkey_t key, + const char* field_name_cstr) + { + if(field_name_cstr == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + const std::string field_name(field_name_cstr); + + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + safe_get(output) = privkey_get_field(k, field_name); + }); + } + +/* RSA specific operations */ + +int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits) + { + if(n_bits < 1024 || n_bits > 16*1024) + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + std::string n_str = std::to_string(n_bits); + + return botan_privkey_create(key_obj, "RSA", n_str.c_str(), rng_obj); + } + +int botan_privkey_load_rsa(botan_privkey_t* key, + botan_mp_t rsa_p, botan_mp_t rsa_q, botan_mp_t rsa_e) + { +#if defined(BOTAN_HAS_RSA) + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + *key = new botan_privkey_struct(new Botan::RSA_PrivateKey(safe_get(rsa_p), + safe_get(rsa_q), + safe_get(rsa_e))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, rsa_p, rsa_q, rsa_e); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_load_rsa_pkcs1(botan_privkey_t* key, + const uint8_t bits[], + size_t len) + { +#if defined(BOTAN_HAS_RSA) + *key = nullptr; + + Botan::secure_vector src(bits, bits + len); + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::AlgorithmIdentifier alg_id("RSA", Botan::AlgorithmIdentifier::USE_NULL_PARAM); + *key = new botan_privkey_struct(new Botan::RSA_PrivateKey(alg_id, src)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, bits, len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_rsa(botan_pubkey_t* key, + botan_mp_t n, botan_mp_t e) + { +#if defined(BOTAN_HAS_RSA) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + *key = new botan_pubkey_struct(new Botan::RSA_PublicKey(safe_get(n), safe_get(e))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, n, e); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t key) + { + return botan_privkey_get_field(p, key, "p"); + } + +int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t key) + { + return botan_privkey_get_field(q, key, "q"); + } + +int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t key) + { + return botan_privkey_get_field(n, key, "n"); + } + +int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t key) + { + return botan_privkey_get_field(e, key, "e"); + } + +int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t key) + { + return botan_privkey_get_field(d, key, "d"); + } + +int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t key) + { + return botan_pubkey_get_field(e, key, "e"); + } + +int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t key) + { + return botan_pubkey_get_field(n, key, "n"); + } + +int botan_privkey_rsa_get_privkey(botan_privkey_t rsa_key, + uint8_t out[], size_t* out_len, + uint32_t flags) + { +#if defined(BOTAN_HAS_RSA) + return BOTAN_FFI_DO(Botan::Private_Key, rsa_key, k, { + if(const Botan::RSA_PrivateKey* rsa = dynamic_cast(&k)) + { + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + return write_vec_output(out, out_len, rsa->private_key_bits()); + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + return write_str_output(out, out_len, Botan::PEM_Code::encode(rsa->private_key_bits(), + "RSA PRIVATE KEY")); + else + return BOTAN_FFI_ERROR_BAD_FLAG; + } + else + { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + }); +#else + BOTAN_UNUSED(rsa_key, out, out_len); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +/* DSA specific operations */ +int botan_privkey_create_dsa(botan_privkey_t* key, botan_rng_t rng_obj, size_t pbits, size_t qbits) + { +#if defined(BOTAN_HAS_DSA) + + if ((rng_obj == nullptr) || (key == nullptr)) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if ((pbits % 64) || (qbits % 8) || + (pbits < 1024) || (pbits > 3072) || + (qbits < 160) || (qbits > 256)) { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + Botan::DL_Group group(rng, Botan::DL_Group::Prime_Subgroup, pbits, qbits); + *key = new botan_privkey_struct(new Botan::DSA_PrivateKey(rng, group)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, rng_obj, pbits, qbits); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_load_dsa(botan_privkey_t* key, + botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x) + { +#if defined(BOTAN_HAS_DSA) + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::Null_RNG null_rng; + Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g)); + *key = new botan_privkey_struct(new Botan::DSA_PrivateKey(null_rng, group, safe_get(x))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, p, q, g, x); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_dsa(botan_pubkey_t* key, + botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y) + { +#if defined(BOTAN_HAS_DSA) + *key = nullptr; + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g)); + *key = new botan_pubkey_struct(new Botan::DSA_PublicKey(group, safe_get(y))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, p, q, g, y); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_dsa_get_x(botan_mp_t x, botan_privkey_t key) + { + return botan_privkey_get_field(x, key, "x"); + } + +int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key) + { + return botan_pubkey_get_field(p, key, "p"); + } + +int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key) + { + return botan_pubkey_get_field(q, key, "q"); + } + +int botan_pubkey_dsa_get_g(botan_mp_t g, botan_pubkey_t key) + { + return botan_pubkey_get_field(g, key, "g"); + } + +int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key) + { + return botan_pubkey_get_field(y, key, "y"); + } + +int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) + { + return botan_privkey_create(key_obj, "ECDSA", param_str, rng_obj); + } + +/* ECDSA specific operations */ + +int botan_pubkey_load_ecdsa(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name) + { +#if defined(BOTAN_HAS_ECDSA) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr p_key; + + int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name); + if(rc == BOTAN_FFI_SUCCESS) + *key = new botan_pubkey_struct(p_key.release()); + + return rc; + }); +#else + BOTAN_UNUSED(key, public_x, public_y, curve_name); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_load_ecdsa(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name) + { +#if defined(BOTAN_HAS_ECDSA) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr p_key; + int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name); + if(rc == BOTAN_FFI_SUCCESS) + *key = new botan_privkey_struct(p_key.release()); + return rc; + }); +#else + BOTAN_UNUSED(key, scalar, curve_name); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +/* ElGamal specific operations */ +int botan_privkey_create_elgamal(botan_privkey_t* key, + botan_rng_t rng_obj, + size_t pbits, + size_t qbits) + { +#if defined(BOTAN_HAS_ELGAMAL) + + if ((rng_obj == nullptr) || (key == nullptr)) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if ((pbits < 1024) || (qbits<160)) { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + + Botan::DL_Group::PrimeType prime_type = ((pbits-1) == qbits) + ? Botan::DL_Group::Strong + : Botan::DL_Group::Prime_Subgroup; + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + Botan::DL_Group group(rng, prime_type, pbits, qbits); + *key = new botan_privkey_struct(new Botan::ElGamal_PrivateKey(rng, group)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, rng_obj, pbits); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_elgamal(botan_pubkey_t* key, + botan_mp_t p, botan_mp_t g, botan_mp_t y) + { +#if defined(BOTAN_HAS_ELGAMAL) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DL_Group group(safe_get(p), safe_get(g)); + *key = new botan_pubkey_struct(new Botan::ElGamal_PublicKey(group, safe_get(y))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, p, g, y); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_load_elgamal(botan_privkey_t* key, + botan_mp_t p, botan_mp_t g, botan_mp_t x) + { +#if defined(BOTAN_HAS_ELGAMAL) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::Null_RNG null_rng; + Botan::DL_Group group(safe_get(p), safe_get(g)); + *key = new botan_privkey_struct(new Botan::ElGamal_PrivateKey(null_rng, group, safe_get(x))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, p, g, x); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +/* Diffie Hellman specific operations */ + +int botan_privkey_create_dh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) + { + return botan_privkey_create(key_obj, "DH", param_str, rng_obj); + } + +int botan_privkey_load_dh(botan_privkey_t* key, + botan_mp_t p, botan_mp_t g, botan_mp_t x) + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::Null_RNG null_rng; + Botan::DL_Group group(safe_get(p), safe_get(g)); + *key = new botan_privkey_struct(new Botan::DH_PrivateKey(null_rng, group, safe_get(x))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, p, g, x); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_dh(botan_pubkey_t* key, + botan_mp_t p, botan_mp_t g, botan_mp_t y) + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::DL_Group group(safe_get(p), safe_get(g)); + *key = new botan_pubkey_struct(new Botan::DH_PublicKey(group, safe_get(y))); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, p, g, y); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +/* ECDH + x25519 specific operations */ + +int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) + { + if(param_str == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + const std::string params(param_str); + + if(params == "curve25519") + return botan_privkey_create(key_obj, "Curve25519", "", rng_obj); + + return botan_privkey_create(key_obj, "ECDH", param_str, rng_obj); + } + +int botan_pubkey_load_ecdh(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name) + { +#if defined(BOTAN_HAS_ECDH) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr p_key; + int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name); + + if(rc == BOTAN_FFI_SUCCESS) + *key = new botan_pubkey_struct(p_key.release()); + return rc; + }); +#else + BOTAN_UNUSED(key, public_x, public_y, curve_name); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_load_ecdh(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name) + { +#if defined(BOTAN_HAS_ECDH) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr p_key; + int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name); + if(rc == BOTAN_FFI_SUCCESS) + *key = new botan_privkey_struct(p_key.release()); + return rc; + }); +#else + BOTAN_UNUSED(key, scalar, curve_name); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +/* SM2 specific operations */ + +int botan_pubkey_sm2_compute_za(uint8_t out[], + size_t* out_len, + const char* ident, + const char* hash_algo, + const botan_pubkey_t key) + { + if(out == nullptr || out_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + if(ident == nullptr || hash_algo == nullptr || key == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + +#if defined(BOTAN_HAS_SM2) + return ffi_guard_thunk(__func__, [=]() -> int { + const Botan::Public_Key& pub_key = safe_get(key); + const Botan::EC_PublicKey* ec_key = dynamic_cast(&pub_key); + + if(ec_key == nullptr) + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + if(ec_key->algo_name() != "SM2") + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + const std::string ident_str(ident); + std::unique_ptr hash = + Botan::HashFunction::create_or_throw(hash_algo); + + const std::vector za = + Botan::sm2_compute_za(*hash, ident_str, ec_key->domain(), ec_key->public_point()); + + return write_vec_output(out, out_len, za); + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_sm2(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name) + { +#if defined(BOTAN_HAS_SM2) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr p_key; + if(!pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name)) + { + *key = new botan_pubkey_struct(p_key.release()); + return BOTAN_FFI_SUCCESS; + } + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + }); +#else + BOTAN_UNUSED(key, public_x, public_y, curve_name); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_load_sm2(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name) + { +#if defined(BOTAN_HAS_SM2) + return ffi_guard_thunk(__func__, [=]() -> int { + std::unique_ptr p_key; + int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name); + + if(rc == BOTAN_FFI_SUCCESS) + *key = new botan_privkey_struct(p_key.release()); + return rc; + }); +#else + BOTAN_UNUSED(key, scalar, curve_name); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_sm2_enc(botan_pubkey_t* key, + const botan_mp_t public_x, + const botan_mp_t public_y, + const char* curve_name) + { + return botan_pubkey_load_sm2(key, public_x, public_y, curve_name); + } + +int botan_privkey_load_sm2_enc(botan_privkey_t* key, + const botan_mp_t scalar, + const char* curve_name) + { + return botan_privkey_load_sm2(key, scalar, curve_name); + } + +/* Ed25519 specific operations */ + +int botan_privkey_load_ed25519(botan_privkey_t* key, + const uint8_t privkey[32]) + { +#if defined(BOTAN_HAS_ED25519) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + const Botan::secure_vector privkey_vec(privkey, privkey + 32); + *key = new botan_privkey_struct(new Botan::Ed25519_PrivateKey(privkey_vec)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, privkey); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_ed25519(botan_pubkey_t* key, + const uint8_t pubkey[32]) + { +#if defined(BOTAN_HAS_ED25519) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + const std::vector pubkey_vec(pubkey, pubkey + 32); + *key = new botan_pubkey_struct(new Botan::Ed25519_PublicKey(pubkey_vec)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, pubkey); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_ed25519_get_privkey(botan_privkey_t key, + uint8_t output[64]) + { +#if defined(BOTAN_HAS_ED25519) + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + if(Botan::Ed25519_PrivateKey* ed = dynamic_cast(&k)) + { + const Botan::secure_vector& ed_key = ed->get_private_key(); + if(ed_key.size() != 64) + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + Botan::copy_mem(output, ed_key.data(), ed_key.size()); + return BOTAN_FFI_SUCCESS; + } + else + { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + }); +#else + BOTAN_UNUSED(key, output); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key, + uint8_t output[32]) + { +#if defined(BOTAN_HAS_ED25519) + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + if(Botan::Ed25519_PublicKey* ed = dynamic_cast(&k)) + { + const std::vector& ed_key = ed->get_public_key(); + if(ed_key.size() != 32) + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + Botan::copy_mem(output, ed_key.data(), ed_key.size()); + return BOTAN_FFI_SUCCESS; + } + else + { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + }); +#else + BOTAN_UNUSED(key, output); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +/* X25519 specific operations */ + +int botan_privkey_load_x25519(botan_privkey_t* key, + const uint8_t privkey[32]) + { +#if defined(BOTAN_HAS_X25519) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + const Botan::secure_vector privkey_vec(privkey, privkey + 32); + *key = new botan_privkey_struct(new Botan::X25519_PrivateKey(privkey_vec)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, privkey); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_load_x25519(botan_pubkey_t* key, + const uint8_t pubkey[32]) + { +#if defined(BOTAN_HAS_X25519) + *key = nullptr; + return ffi_guard_thunk(__func__, [=]() -> int { + const std::vector pubkey_vec(pubkey, pubkey + 32); + *key = new botan_pubkey_struct(new Botan::X25519_PublicKey(pubkey_vec)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(key, pubkey); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_x25519_get_privkey(botan_privkey_t key, + uint8_t output[32]) + { +#if defined(BOTAN_HAS_X25519) + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + if(Botan::X25519_PrivateKey* x25519 = dynamic_cast(&k)) + { + const Botan::secure_vector& x25519_key = x25519->get_x(); + if(x25519_key.size() != 32) + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + Botan::copy_mem(output, x25519_key.data(), x25519_key.size()); + return BOTAN_FFI_SUCCESS; + } + else + { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + }); +#else + BOTAN_UNUSED(key, output); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_pubkey_x25519_get_pubkey(botan_pubkey_t key, + uint8_t output[32]) + { +#if defined(BOTAN_HAS_X25519) + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + if(Botan::X25519_PublicKey* x25519 = dynamic_cast(&k)) + { + const std::vector& x25519_key = x25519->public_value(); + if(x25519_key.size() != 32) + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + Botan::copy_mem(output, x25519_key.data(), x25519_key.size()); + return BOTAN_FFI_SUCCESS; + } + else + { + return BOTAN_FFI_ERROR_BAD_PARAMETER; + } + }); +#else + BOTAN_UNUSED(key, output); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_privkey_create_mceliece(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n, size_t t) + { + const std::string mce_params = std::to_string(n) + "," + std::to_string(t); + return botan_privkey_create(key_obj, "McEliece", mce_params.c_str(), rng_obj); + } + +int botan_mceies_decrypt(botan_privkey_t mce_key_obj, + const char* aead, + const uint8_t ct[], size_t ct_len, + const uint8_t ad[], size_t ad_len, + uint8_t out[], size_t* out_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::Private_Key& key = safe_get(mce_key_obj); + +#if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES) + Botan::McEliece_PrivateKey* mce = dynamic_cast(&key); + if(!mce) + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + const Botan::secure_vector pt = mceies_decrypt(*mce, ct, ct_len, ad, ad_len, aead); + return write_vec_output(out, out_len, pt); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + }); + } + +int botan_mceies_encrypt(botan_pubkey_t mce_key_obj, + botan_rng_t rng_obj, + const char* aead, + const uint8_t pt[], size_t pt_len, + const uint8_t ad[], size_t ad_len, + uint8_t out[], size_t* out_len) + { + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::Public_Key& key = safe_get(mce_key_obj); + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + +#if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES) + Botan::McEliece_PublicKey* mce = dynamic_cast(&key); + if(!mce) + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + Botan::secure_vector ct = mceies_encrypt(*mce, pt, pt_len, ad, ad_len, rng, aead); + return write_vec_output(out, out_len, ct); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_rng.cpp b/comm/third_party/botan/src/lib/ffi/ffi_rng.cpp new file mode 100644 index 0000000000..7bb365a248 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_rng.cpp @@ -0,0 +1,183 @@ +/* +* (C) 2015,2017 Jack Lloyd +* (C) 2021 René Fischer +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +#include + +#if defined(BOTAN_HAS_PROCESSOR_RNG) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +int botan_rng_init(botan_rng_t* rng_out, const char* rng_type) + { + return ffi_guard_thunk(__func__, [=]() -> int { + if(rng_out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + const std::string rng_type_s(rng_type ? rng_type : "system"); + + std::unique_ptr rng; + + if(rng_type_s == "system") + { + rng.reset(new Botan::System_RNG); + } + else if(rng_type_s == "user" || rng_type_s == "user-threadsafe") + { + rng.reset(new Botan::AutoSeeded_RNG); + } + else if(rng_type_s == "null") + { + rng.reset(new Botan::Null_RNG); + } +#if defined(BOTAN_HAS_PROCESSOR_RNG) + else if((rng_type_s == "rdrand" || rng_type_s == "hwrng") && Botan::Processor_RNG::available()) + { + rng.reset(new Botan::Processor_RNG); + } +#endif + + if(!rng) + { + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + } + + *rng_out = new botan_rng_struct(rng.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_rng_init_custom(botan_rng_t* rng_out, const char* rng_name, void* context, + int(* get_cb)(void* context, uint8_t* out, size_t out_len), + int(* add_entropy_cb)(void* context, const uint8_t input[], size_t length), + void(* destroy_cb)(void* context)) +{ +return ffi_guard_thunk(__func__,[=]() -> int { + if(rng_out == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(rng_name == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(get_cb == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + class Custom_RNG : public Botan::RandomNumberGenerator + { + public: + Custom_RNG(const std::string& name, void* context, + int(* get_cb)(void* context, uint8_t* out, size_t out_len), + int(* add_entropy_cb)(void* context, const uint8_t input[], size_t length), + void(* destroy_cb)(void* context)) : + m_name(name) + { + m_context = context; + m_get_cb = get_cb; + m_add_entropy_cb = add_entropy_cb; + m_destroy_cb = destroy_cb; + } + + ~Custom_RNG() + { + if(m_destroy_cb) + { + m_destroy_cb(m_context); + } + } + + void randomize(uint8_t output[], size_t length) override + { + int rc = m_get_cb(m_context, output, length); + if(rc) + { + throw Botan::Invalid_State("Failed to get random from C callback, rc=" + std::to_string(rc)); + } + } + + bool accepts_input() const override + { + return m_add_entropy_cb != nullptr; + } + + void add_entropy(const uint8_t input[], size_t length) override + { + if(m_add_entropy_cb == nullptr) + { + return; + } + + int rc = m_add_entropy_cb(m_context, input, length); + if(rc) + { + throw Botan::Invalid_State("Failed to add entropy via C callback, rc=" + std::to_string(rc)); + } + } + + std::string name() const override + { + return m_name; + } + + void clear() override + { + } + + bool is_seeded() const override + { + return true; + } + + private: + std::string m_name; + void* m_context; + std::function m_get_cb; + std::function m_add_entropy_cb; + std::function m_destroy_cb; + }; + + std::unique_ptr rng(new Custom_RNG(rng_name, context, get_cb, add_entropy_cb, destroy_cb)); + + *rng_out = new botan_rng_struct(rng.release()); + return BOTAN_FFI_SUCCESS; + }); +} + +int botan_rng_destroy(botan_rng_t rng) + { + return BOTAN_FFI_CHECKED_DELETE(rng); + } + +int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len) + { + return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.randomize(out, out_len); }); + } + +int botan_rng_reseed(botan_rng_t rng, size_t bits) + { + return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(Botan::system_rng(), bits); }); + } + +int botan_rng_add_entropy(botan_rng_t rng, const uint8_t* input, size_t len) + { + return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.add_entropy(input, len); }); + } + +int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t source_rng, size_t bits) + { + return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(safe_get(source_rng), bits); }); + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_rng.h b/comm/third_party/botan/src/lib/ffi/ffi_rng.h new file mode 100644 index 0000000000..2117853c47 --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_rng.h @@ -0,0 +1,19 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FFI_RNG_H_ +#define BOTAN_FFI_RNG_H_ + +#include +#include + +extern "C" { + +BOTAN_FFI_DECLARE_STRUCT(botan_rng_struct, Botan::RandomNumberGenerator, 0x4901F9C1); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/ffi/ffi_totp.cpp b/comm/third_party/botan/src/lib/ffi/ffi_totp.cpp new file mode 100644 index 0000000000..9ca8e8e6ae --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_totp.cpp @@ -0,0 +1,94 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_TOTP) + #include +#endif + +extern "C" { + +using namespace Botan_FFI; + +#if defined(BOTAN_HAS_TOTP) + +BOTAN_FFI_DECLARE_STRUCT(botan_totp_struct, Botan::TOTP, 0x3D9D2CD1); + +#endif + +int botan_totp_init(botan_totp_t* totp, + const uint8_t key[], size_t key_len, + const char* hash_algo, + size_t digits, + size_t time_step) + { + if(totp == nullptr || key == nullptr || hash_algo == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *totp = nullptr; + +#if defined(BOTAN_HAS_TOTP) + return ffi_guard_thunk(__func__, [=]() -> int { + + *totp = new botan_totp_struct( + new Botan::TOTP(key, key_len, hash_algo, digits, time_step)); + + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(totp, key, key_len, hash_algo, digits, time_step); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_totp_destroy(botan_totp_t totp) + { +#if defined(BOTAN_HAS_TOTP) + return BOTAN_FFI_CHECKED_DELETE(totp); +#else + BOTAN_UNUSED(totp); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_totp_generate(botan_totp_t totp, + uint32_t* totp_code, + uint64_t timestamp) + { +#if defined(BOTAN_HAS_TOTP) + if(totp == nullptr || totp_code == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::TOTP, totp, t, { + *totp_code = t.generate_totp(timestamp); + }); + +#else + BOTAN_UNUSED(totp, totp_code, timestamp); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_totp_check(botan_totp_t totp, + uint32_t totp_code, + uint64_t timestamp, + size_t acceptable_clock_drift) + { +#if defined(BOTAN_HAS_TOTP) + return BOTAN_FFI_RETURNING(Botan::TOTP, totp, t, { + const bool ok = t.verify_totp(totp_code, timestamp, acceptable_clock_drift); + return (ok ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER); + }); + +#else + BOTAN_UNUSED(totp, totp_code, timestamp, acceptable_clock_drift); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/ffi/ffi_util.h b/comm/third_party/botan/src/lib/ffi/ffi_util.h new file mode 100644 index 0000000000..4269aa3e8c --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/ffi_util.h @@ -0,0 +1,182 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FFI_UTILS_H_ +#define BOTAN_FFI_UTILS_H_ + +#include +#include +#include +#include +#include +#include + +namespace Botan_FFI { + +class BOTAN_UNSTABLE_API FFI_Error final : public Botan::Exception + { + public: + FFI_Error(const std::string& what, int err_code) : + Exception("FFI error", what), + m_err_code(err_code) + {} + + int error_code() const noexcept override { return m_err_code; } + + Botan::ErrorType error_type() const noexcept override { return Botan::ErrorType::InvalidArgument; } + + private: + int m_err_code; + }; + +template +struct botan_struct + { + public: + botan_struct(T* obj) : m_magic(MAGIC), m_obj(obj) {} + virtual ~botan_struct() { m_magic = 0; m_obj.reset(); } + + bool magic_ok() const { return (m_magic == MAGIC); } + + T* unsafe_get() const + { + return m_obj.get(); + } + private: + uint32_t m_magic = 0; + std::unique_ptr m_obj; + }; + +#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \ + struct NAME final : public Botan_FFI::botan_struct { explicit NAME(TYPE* x) : botan_struct(x) {} } + +// Declared in ffi.cpp +int ffi_error_exception_thrown(const char* func_name, const char* exn, + int rc = BOTAN_FFI_ERROR_EXCEPTION_THROWN); + +template +T& safe_get(botan_struct* p) + { + if(!p) + throw FFI_Error("Null pointer argument", BOTAN_FFI_ERROR_NULL_POINTER); + if(p->magic_ok() == false) + throw FFI_Error("Bad magic in ffi object", BOTAN_FFI_ERROR_INVALID_OBJECT); + + if(T* t = p->unsafe_get()) + return *t; + + throw FFI_Error("Invalid object pointer", BOTAN_FFI_ERROR_INVALID_OBJECT); + } + +int ffi_guard_thunk(const char* func_name, std::function); + +template +int apply_fn(botan_struct* o, const char* func_name, F func) + { + if(!o) + return BOTAN_FFI_ERROR_NULL_POINTER; + + if(o->magic_ok() == false) + return BOTAN_FFI_ERROR_INVALID_OBJECT; + + T* p = o->unsafe_get(); + if(p == nullptr) + return BOTAN_FFI_ERROR_INVALID_OBJECT; + + return ffi_guard_thunk(func_name, [&]() { return func(*p); }); + } + +#define BOTAN_FFI_DO(T, obj, param, block) \ + apply_fn(obj, __func__, \ + [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; }) + +/* +* Like BOTAN_FFI_DO but with no trailing return with the expectation +* that the block always returns a value. This exists because otherwise +* MSVC warns about the dead return after the block in FFI_DO. +*/ +#define BOTAN_FFI_RETURNING(T, obj, param, block) \ + apply_fn(obj, __func__, \ + [=](T& param) -> int { do { block } while(0); }) + +template +int ffi_delete_object(botan_struct* obj, const char* func_name) + { + try + { + if(obj == nullptr) + return BOTAN_FFI_SUCCESS; // ignore delete of null objects + + if(obj->magic_ok() == false) + return BOTAN_FFI_ERROR_INVALID_OBJECT; + + delete obj; + return BOTAN_FFI_SUCCESS; + } + catch(std::exception& e) + { + return ffi_error_exception_thrown(func_name, e.what()); + } + catch(...) + { + return ffi_error_exception_thrown(func_name, "unknown exception"); + } + } + +#define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, __func__) + +inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len) + { + if(out_len == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + const size_t avail = *out_len; + *out_len = buf_len; + + if((avail >= buf_len) && (out != nullptr)) + { + Botan::copy_mem(out, buf, buf_len); + return BOTAN_FFI_SUCCESS; + } + else + { + if(out != nullptr) + { + Botan::clear_mem(out, avail); + } + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + } + } + +template +int write_vec_output(uint8_t out[], size_t* out_len, const std::vector& buf) + { + return write_output(out, out_len, buf.data(), buf.size()); + } + +inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str) + { + return write_output(out, out_len, + Botan::cast_char_ptr_to_uint8(str.data()), + str.size() + 1); + } + +inline int write_str_output(char out[], size_t* out_len, const std::string& str) + { + return write_str_output(Botan::cast_char_ptr_to_uint8(out), out_len, str); + } + +inline int write_str_output(char out[], size_t* out_len, const std::vector& str_vec) + { + return write_output(Botan::cast_char_ptr_to_uint8(out), + out_len, + str_vec.data(), + str_vec.size()); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/ffi/info.txt b/comm/third_party/botan/src/lib/ffi/info.txt new file mode 100644 index 0000000000..865beb61ed --- /dev/null +++ b/comm/third_party/botan/src/lib/ffi/info.txt @@ -0,0 +1,31 @@ + +FFI -> 20210220 + + + +ffi_mp.h +ffi_pkey.h +ffi_rng.h +ffi_util.h + + + +ffi.h + + + +block +stream +hash +aead +kdf +pbkdf +pubkey +pem +bigint +sha2_32 +#x509 +#tls +system_rng +auto_rng + diff --git a/comm/third_party/botan/src/lib/filters/algo_filt.cpp b/comm/third_party/botan/src/lib/filters/algo_filt.cpp new file mode 100644 index 0000000000..c944b72e5b --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/algo_filt.cpp @@ -0,0 +1,96 @@ +/* +* Filters +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher) : + m_buffer(BOTAN_DEFAULT_BUFFER_SIZE), + m_cipher(cipher) + { + } + +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key) : + StreamCipher_Filter(cipher) + { + m_cipher->set_key(key); + } + +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : + m_buffer(BOTAN_DEFAULT_BUFFER_SIZE), + m_cipher(StreamCipher::create_or_throw(sc_name)) + { + } + +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, const SymmetricKey& key) : + StreamCipher_Filter(sc_name) + { + m_cipher->set_key(key); + } + +void StreamCipher_Filter::write(const uint8_t input[], size_t length) + { + while(length) + { + size_t copied = std::min(length, m_buffer.size()); + m_cipher->cipher(input, m_buffer.data(), copied); + send(m_buffer, copied); + input += copied; + length -= copied; + } + } + +#endif + +#if defined(BOTAN_HAS_HASH) + +Hash_Filter::Hash_Filter(const std::string& hash_name, size_t len) : + m_hash(HashFunction::create_or_throw(hash_name)), + m_out_len(len) + { + } + +void Hash_Filter::end_msg() + { + secure_vector output = m_hash->final(); + if(m_out_len) + send(output, std::min(m_out_len, output.size())); + else + send(output); + } +#endif + +#if defined(BOTAN_HAS_MAC) + +MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) : + m_mac(MessageAuthenticationCode::create_or_throw(mac_name)), + m_out_len(len) + { + } + +MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, size_t len) : + MAC_Filter(mac_name, len) + { + m_mac->set_key(key); + } + +void MAC_Filter::end_msg() + { + secure_vector output = m_mac->final(); + if(m_out_len) + send(output, std::min(m_out_len, output.size())); + else + send(output); + } + +#endif + +} diff --git a/comm/third_party/botan/src/lib/filters/b64_filt.cpp b/comm/third_party/botan/src/lib/filters/b64_filt.cpp new file mode 100644 index 0000000000..8cbba1a6e5 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/b64_filt.cpp @@ -0,0 +1,182 @@ +/* +* Base64 Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Base64_Encoder Constructor +*/ +Base64_Encoder::Base64_Encoder(bool breaks, size_t length, bool t_n) : + m_line_length(breaks ? length : 0), + m_trailing_newline(t_n && breaks), + m_in(48), + m_out(64), + m_position(0), + m_out_position(0) + { + } + +/* +* Encode and send a block +*/ +void Base64_Encoder::encode_and_send(const uint8_t input[], size_t length, + bool final_inputs) + { + while(length) + { + const size_t proc = std::min(length, m_in.size()); + + size_t consumed = 0; + size_t produced = base64_encode(cast_uint8_ptr_to_char(m_out.data()), + input, proc, consumed, final_inputs); + + do_output(m_out.data(), produced); + + // FIXME: s/proc/consumed/? + input += proc; + length -= proc; + } + } + +/* +* Handle the output +*/ +void Base64_Encoder::do_output(const uint8_t input[], size_t length) + { + if(m_line_length == 0) + send(input, length); + else + { + size_t remaining = length, offset = 0; + while(remaining) + { + size_t sent = std::min(m_line_length - m_out_position, remaining); + send(input + offset, sent); + m_out_position += sent; + remaining -= sent; + offset += sent; + if(m_out_position == m_line_length) + { + send('\n'); + m_out_position = 0; + } + } + } + } + +/* +* Convert some data into Base64 +*/ +void Base64_Encoder::write(const uint8_t input[], size_t length) + { + buffer_insert(m_in, m_position, input, length); + if(m_position + length >= m_in.size()) + { + encode_and_send(m_in.data(), m_in.size()); + input += (m_in.size() - m_position); + length -= (m_in.size() - m_position); + while(length >= m_in.size()) + { + encode_and_send(input, m_in.size()); + input += m_in.size(); + length -= m_in.size(); + } + copy_mem(m_in.data(), input, length); + m_position = 0; + } + m_position += length; + } + +/* +* Flush buffers +*/ +void Base64_Encoder::end_msg() + { + encode_and_send(m_in.data(), m_position, true); + + if(m_trailing_newline || (m_out_position && m_line_length)) + send('\n'); + + m_out_position = m_position = 0; + } + +/* +* Base64_Decoder Constructor +*/ +Base64_Decoder::Base64_Decoder(Decoder_Checking c) : + m_checking(c), m_in(64), m_out(48), m_position(0) + { + } + +/* +* Convert some data from Base64 +*/ +void Base64_Decoder::write(const uint8_t input[], size_t length) + { + while(length) + { + size_t to_copy = std::min(length, m_in.size() - m_position); + if(to_copy == 0) + { + m_in.resize(m_in.size()*2); + m_out.resize(m_out.size()*2); + } + copy_mem(&m_in[m_position], input, to_copy); + m_position += to_copy; + + size_t consumed = 0; + size_t written = base64_decode(m_out.data(), + cast_uint8_ptr_to_char(m_in.data()), + m_position, + consumed, + false, + m_checking != FULL_CHECK); + + send(m_out, written); + + if(consumed != m_position) + { + copy_mem(m_in.data(), m_in.data() + consumed, m_position - consumed); + m_position = m_position - consumed; + } + else + m_position = 0; + + length -= to_copy; + input += to_copy; + } + } + +/* +* Flush buffers +*/ +void Base64_Decoder::end_msg() + { + size_t consumed = 0; + size_t written = base64_decode(m_out.data(), + cast_uint8_ptr_to_char(m_in.data()), + m_position, + consumed, + true, + m_checking != FULL_CHECK); + + send(m_out, written); + + const bool not_full_bytes = consumed != m_position; + + m_position = 0; + + if(not_full_bytes) + throw Invalid_Argument("Base64_Decoder: Input not full bytes"); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/b64_filt.h b/comm/third_party/botan/src/lib/filters/b64_filt.h new file mode 100644 index 0000000000..af7bb7cf2f --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/b64_filt.h @@ -0,0 +1,14 @@ +/* +* Base64 Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE64_FILTER_H_ +#define BOTAN_BASE64_FILTER_H_ + +#include +BOTAN_DEPRECATED_HEADER(b64_filt.h) + +#endif diff --git a/comm/third_party/botan/src/lib/filters/basefilt.cpp b/comm/third_party/botan/src/lib/filters/basefilt.cpp new file mode 100644 index 0000000000..b34b70bd65 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/basefilt.cpp @@ -0,0 +1,52 @@ +/* +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + if(f1) { attach(f1); incr_owns(); } + if(f2) { attach(f2); incr_owns(); } + if(f3) { attach(f3); incr_owns(); } + if(f4) { attach(f4); incr_owns(); } + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* filters[], size_t count) + { + for(size_t j = 0; j != count; ++j) + if(filters[j]) + { + attach(filters[j]); + incr_owns(); + } + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* filters[], size_t count) + { + set_next(filters, count); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/basefilt.h b/comm/third_party/botan/src/lib/filters/basefilt.h new file mode 100644 index 0000000000..422989b759 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/basefilt.h @@ -0,0 +1,18 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASEFILT_H_ +#define BOTAN_BASEFILT_H_ + +// This header is deprecated and will be removed in a future major release + +#include + +BOTAN_DEPRECATED_HEADER(basefilt.h) + +#endif diff --git a/comm/third_party/botan/src/lib/filters/buf_filt.cpp b/comm/third_party/botan/src/lib/filters/buf_filt.cpp new file mode 100644 index 0000000000..0e34a56dd6 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/buf_filt.cpp @@ -0,0 +1,103 @@ +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Buffered_Filter Constructor +*/ +Buffered_Filter::Buffered_Filter(size_t b, size_t f) : + m_main_block_mod(b), m_final_minimum(f) + { + if(m_main_block_mod == 0) + throw Invalid_Argument("m_main_block_mod == 0"); + + if(m_final_minimum > m_main_block_mod) + throw Invalid_Argument("m_final_minimum > m_main_block_mod"); + + m_buffer.resize(2 * m_main_block_mod); + m_buffer_pos = 0; + } + +/* +* Buffer input into blocks, trying to minimize copying +*/ +void Buffered_Filter::write(const uint8_t input[], size_t input_size) + { + if(!input_size) + return; + + if(m_buffer_pos + input_size >= m_main_block_mod + m_final_minimum) + { + size_t to_copy = std::min(m_buffer.size() - m_buffer_pos, input_size); + + copy_mem(&m_buffer[m_buffer_pos], input, to_copy); + m_buffer_pos += to_copy; + + input += to_copy; + input_size -= to_copy; + + size_t total_to_consume = + round_down(std::min(m_buffer_pos, + m_buffer_pos + input_size - m_final_minimum), + m_main_block_mod); + + buffered_block(m_buffer.data(), total_to_consume); + + m_buffer_pos -= total_to_consume; + + copy_mem(m_buffer.data(), m_buffer.data() + total_to_consume, m_buffer_pos); + } + + if(input_size >= m_final_minimum) + { + size_t full_blocks = (input_size - m_final_minimum) / m_main_block_mod; + size_t to_copy = full_blocks * m_main_block_mod; + + if(to_copy) + { + buffered_block(input, to_copy); + + input += to_copy; + input_size -= to_copy; + } + } + + copy_mem(&m_buffer[m_buffer_pos], input, input_size); + m_buffer_pos += input_size; + } + +/* +* Finish/flush operation +*/ +void Buffered_Filter::end_msg() + { + if(m_buffer_pos < m_final_minimum) + throw Invalid_State("Buffered filter end_msg without enough input"); + + size_t spare_blocks = (m_buffer_pos - m_final_minimum) / m_main_block_mod; + + if(spare_blocks) + { + size_t spare_bytes = m_main_block_mod * spare_blocks; + buffered_block(m_buffer.data(), spare_bytes); + buffered_final(&m_buffer[spare_bytes], m_buffer_pos - spare_bytes); + } + else + { + buffered_final(m_buffer.data(), m_buffer_pos); + } + + m_buffer_pos = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/filters/buf_filt.h b/comm/third_party/botan/src/lib/filters/buf_filt.h new file mode 100644 index 0000000000..1f9ed3eff0 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/buf_filt.h @@ -0,0 +1,14 @@ +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BUFFERED_FILTER_H_ +#define BOTAN_BUFFERED_FILTER_H_ + +#include +BOTAN_DEPRECATED_HEADER(buf_filt.h) + +#endif diff --git a/comm/third_party/botan/src/lib/filters/cipher_filter.cpp b/comm/third_party/botan/src/lib/filters/cipher_filter.cpp new file mode 100644 index 0000000000..720aeac6fd --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/cipher_filter.cpp @@ -0,0 +1,103 @@ +/* +* Filter interface for Cipher_Modes +* (C) 2013,2014,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +size_t choose_update_size(size_t update_granularity) + { + const size_t target_size = 1024; + + if(update_granularity >= target_size) + return update_granularity; + + return round_up(target_size, update_granularity); + } + +} + +Cipher_Mode_Filter::Cipher_Mode_Filter(Cipher_Mode* mode) : + Buffered_Filter(choose_update_size(mode->update_granularity()), + mode->minimum_final_size()), + m_mode(mode), + m_nonce(mode->default_nonce_length()), + m_buffer(m_mode->update_granularity()) + { + } + +std::string Cipher_Mode_Filter::name() const + { + return m_mode->name(); + } + +void Cipher_Mode_Filter::set_iv(const InitializationVector& iv) + { + m_nonce = unlock(iv.bits_of()); + } + +void Cipher_Mode_Filter::set_key(const SymmetricKey& key) + { + m_mode->set_key(key); + } + +Key_Length_Specification Cipher_Mode_Filter::key_spec() const + { + return m_mode->key_spec(); + } + +bool Cipher_Mode_Filter::valid_iv_length(size_t length) const + { + return m_mode->valid_nonce_length(length); + } + +void Cipher_Mode_Filter::write(const uint8_t input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void Cipher_Mode_Filter::end_msg() + { + Buffered_Filter::end_msg(); + } + +void Cipher_Mode_Filter::start_msg() + { + if(m_nonce.empty() && !m_mode->valid_nonce_length(0)) + throw Invalid_State("Cipher " + m_mode->name() + " requires a fresh nonce for each message"); + + m_mode->start(m_nonce); + m_nonce.clear(); + } + +void Cipher_Mode_Filter::buffered_block(const uint8_t input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_mode->update_granularity(), input_length); + + m_buffer.assign(input, input + take); + m_mode->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Cipher_Mode_Filter::buffered_final(const uint8_t input[], size_t input_length) + { + secure_vector buf(input, input + input_length); + m_mode->finish(buf); + send(buf); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/cipher_filter.h b/comm/third_party/botan/src/lib/filters/cipher_filter.h new file mode 100644 index 0000000000..84fc58b6ee --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/cipher_filter.h @@ -0,0 +1,14 @@ +/* +* Filter interface for ciphers +* (C) 2013,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CIPHER_FILTER_H_ +#define BOTAN_CIPHER_FILTER_H_ + +#include +BOTAN_DEPRECATED_HEADER(cipher_filter.h) + +#endif diff --git a/comm/third_party/botan/src/lib/filters/comp_filter.cpp b/comm/third_party/botan/src/lib/filters/comp_filter.cpp new file mode 100644 index 0000000000..c2814460ae --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/comp_filter.cpp @@ -0,0 +1,122 @@ +/* +* Filter interface for compression +* (C) 2014,2015,2016 Jack Lloyd +* (C) 2015 Matej Kenda +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_COMPRESSION) + #include +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_COMPRESSION) + +Compression_Filter::Compression_Filter(const std::string& type, size_t level, size_t bs) : + m_comp(make_compressor(type)), + m_buffersize(std::max(bs, 256)), + m_level(level) + { + if(!m_comp) + { + throw Invalid_Argument("Compression type '" + type + "' not found"); + } + } + +Compression_Filter::~Compression_Filter() { /* for unique_ptr */ } + +std::string Compression_Filter::name() const + { + return m_comp->name(); + } + +void Compression_Filter::start_msg() + { + m_comp->start(m_level); + } + +void Compression_Filter::write(const uint8_t input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_buffersize, input_length); + BOTAN_ASSERT(take > 0, "Consumed something"); + + m_buffer.assign(input, input + take); + m_comp->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Compression_Filter::flush() + { + m_buffer.clear(); + m_comp->update(m_buffer, 0, true); + send(m_buffer); + } + +void Compression_Filter::end_msg() + { + m_buffer.clear(); + m_comp->finish(m_buffer); + send(m_buffer); + } + +Decompression_Filter::Decompression_Filter(const std::string& type, size_t bs) : + m_comp(make_decompressor(type)), + m_buffersize(std::max(bs, 256)) + { + if(!m_comp) + { + throw Invalid_Argument("Compression type '" + type + "' not found"); + } + } + +Decompression_Filter::~Decompression_Filter() { /* for unique_ptr */ } + +std::string Decompression_Filter::name() const + { + return m_comp->name(); + } + +void Decompression_Filter::start_msg() + { + m_comp->start(); + } + +void Decompression_Filter::write(const uint8_t input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_buffersize, input_length); + BOTAN_ASSERT(take > 0, "Consumed something"); + + m_buffer.assign(input, input + take); + m_comp->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Decompression_Filter::end_msg() + { + m_buffer.clear(); + m_comp->finish(m_buffer); + send(m_buffer); + } + +#endif + +} diff --git a/comm/third_party/botan/src/lib/filters/comp_filter.h b/comm/third_party/botan/src/lib/filters/comp_filter.h new file mode 100644 index 0000000000..86b587ac30 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/comp_filter.h @@ -0,0 +1,15 @@ +/* +* Filter interface for compression +* (C) 2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_COMPRESSION_FILTER_H_ +#define BOTAN_COMPRESSION_FILTER_H_ + +BOTAN_DEPRECATED_HEADER(comp_filter.h) + +#include + +#endif diff --git a/comm/third_party/botan/src/lib/filters/data_snk.cpp b/comm/third_party/botan/src/lib/filters/data_snk.cpp new file mode 100644 index 0000000000..9f0ddff96d --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/data_snk.cpp @@ -0,0 +1,75 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* 2017 Philippe Lieser +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + #include +#endif + +namespace Botan { + +/* +* Write to a stream +*/ +void DataSink_Stream::write(const uint8_t out[], size_t length) + { + m_sink.write(cast_uint8_ptr_to_char(out), length); + if(!m_sink.good()) + throw Stream_IO_Error("DataSink_Stream: Failure writing to " + + m_identifier); + } + +/* +* Flush the stream +*/ +void DataSink_Stream::end_msg() + { + m_sink.flush(); + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(std::ostream& out, + const std::string& name) : + m_identifier(name), + m_sink(out) + { + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(const std::string& path, + bool use_binary) : + m_identifier(path), + m_sink_memory(new std::ofstream(path, use_binary ? std::ios::binary : std::ios::out)), + m_sink(*m_sink_memory) + { + if(!m_sink.good()) + { + throw Stream_IO_Error("DataSink_Stream: Failure opening " + path); + } + } +#endif + +/* +* DataSink_Stream Destructor +*/ +DataSink_Stream::~DataSink_Stream() + { + // for ~unique_ptr + } + +} diff --git a/comm/third_party/botan/src/lib/filters/data_snk.h b/comm/third_party/botan/src/lib/filters/data_snk.h new file mode 100644 index 0000000000..49484b1c1a --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/data_snk.h @@ -0,0 +1,76 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2017 Philippe Lieser +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DATA_SINK_H_ +#define BOTAN_DATA_SINK_H_ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents abstract data sink objects. +*/ +class BOTAN_PUBLIC_API(2,0) DataSink : public Filter + { + public: + bool attachable() override { return false; } + DataSink() = default; + virtual ~DataSink() = default; + + DataSink& operator=(const DataSink&) = delete; + DataSink(const DataSink&) = delete; + }; + +/** +* This class represents a data sink which writes its output to a stream. +*/ +class BOTAN_PUBLIC_API(2,0) DataSink_Stream final : public DataSink + { + public: + /** + * Construct a DataSink_Stream from a stream. + * @param stream the stream to write to + * @param name identifier + */ + DataSink_Stream(std::ostream& stream, + const std::string& name = ""); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + + /** + * Construct a DataSink_Stream from a filesystem path name. + * @param pathname the name of the file to open a stream to + * @param use_binary indicates whether to treat the file + * as a binary file or not + */ + DataSink_Stream(const std::string& pathname, + bool use_binary = false); +#endif + + std::string name() const override { return m_identifier; } + + void write(const uint8_t[], size_t) override; + + void end_msg() override; + + ~DataSink_Stream(); + + private: + const std::string m_identifier; + + // May be null, if m_sink was an external reference + std::unique_ptr m_sink_memory; + std::ostream& m_sink; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.cpp b/comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.cpp new file mode 100644 index 0000000000..657dde3b40 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.cpp @@ -0,0 +1,55 @@ +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Write data from a pipe into a Unix fd +*/ +int operator<<(int fd, Pipe& pipe) + { + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(pipe.remaining()) + { + size_t got = pipe.read(buffer.data(), buffer.size()); + size_t position = 0; + while(got) + { + ssize_t ret = ::write(fd, &buffer[position], got); + if(ret < 0) + throw Stream_IO_Error("Pipe output operator (unixfd) has failed"); + + position += static_cast(ret); + got -= static_cast(ret); + } + } + return fd; + } + +/* +* Read data from a Unix fd into a pipe +*/ +int operator>>(int fd, Pipe& pipe) + { + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(true) + { + ssize_t ret = ::read(fd, buffer.data(), buffer.size()); + if(ret < 0) + throw Stream_IO_Error("Pipe input operator (unixfd) has failed"); + else if(ret == 0) + break; + pipe.write(buffer.data(), static_cast(ret)); + } + return fd; + } + +} diff --git a/comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.h b/comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.h new file mode 100644 index 0000000000..b5a3a4cd8b --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/fd_unix/fd_unix.h @@ -0,0 +1,35 @@ +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PIPE_UNIXFD_H_ +#define BOTAN_PIPE_UNIXFD_H_ + +#include + +namespace Botan { + +class Pipe; + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out file descriptor for an open output stream +* @param pipe the pipe +*/ +int BOTAN_PUBLIC_API(2,0) operator<<(int out, Pipe& pipe); + +/** +* File descriptor input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in file descriptor for an open input stream +* @param pipe the pipe +*/ +int BOTAN_PUBLIC_API(2,0) operator>>(int in, Pipe& pipe); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/filters/fd_unix/info.txt b/comm/third_party/botan/src/lib/filters/fd_unix/info.txt new file mode 100644 index 0000000000..109c9c9abe --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/fd_unix/info.txt @@ -0,0 +1,7 @@ + +PIPE_UNIXFD_IO -> 20131128 + + + +posix1 + diff --git a/comm/third_party/botan/src/lib/filters/filter.cpp b/comm/third_party/botan/src/lib/filters/filter.cpp new file mode 100644 index 0000000000..6653fc7815 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/filter.cpp @@ -0,0 +1,129 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Filter Constructor +*/ +Filter::Filter() + { + m_next.resize(1); + m_port_num = 0; + m_filter_owns = 0; + m_owned = false; + } + +/* +* Send data to all ports +*/ +void Filter::send(const uint8_t input[], size_t length) + { + if(!length) + return; + + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + { + if(m_write_queue.size()) + m_next[j]->write(m_write_queue.data(), m_write_queue.size()); + m_next[j]->write(input, length); + nothing_attached = false; + } + + if(nothing_attached) + m_write_queue += std::make_pair(input, length); + else + m_write_queue.clear(); + } + +/* +* Start a new message +*/ +void Filter::new_msg() + { + start_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + m_next[j]->new_msg(); + } + +/* +* End the current message +*/ +void Filter::finish_msg() + { + end_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + m_next[j]->finish_msg(); + } + +/* +* Attach a filter to the current port +*/ +void Filter::attach(Filter* new_filter) + { + if(new_filter) + { + Filter* last = this; + while(last->get_next()) + last = last->get_next(); + last->m_next[last->current_port()] = new_filter; + } + } + +/* +* Set the active port on a filter +*/ +void Filter::set_port(size_t new_port) + { + if(new_port >= total_ports()) + throw Invalid_Argument("Filter: Invalid port number"); + m_port_num = new_port; + } + +/* +* Return the next Filter in the logical chain +*/ +Filter* Filter::get_next() const + { + if(m_port_num < m_next.size()) + return m_next[m_port_num]; + return nullptr; + } + +/* +* Set the next Filters +*/ +void Filter::set_next(Filter* filters[], size_t size) + { + m_next.clear(); + + m_port_num = 0; + m_filter_owns = 0; + + while(size && filters && (filters[size-1] == nullptr)) + --size; + + if(filters && size) + m_next.assign(filters, filters + size); + } + +/* +* Return the total number of ports +*/ +size_t Filter::total_ports() const + { + return m_next.size(); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/filter.h b/comm/third_party/botan/src/lib/filters/filter.h new file mode 100644 index 0000000000..94b9c6ccd0 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/filter.h @@ -0,0 +1,175 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FILTER_H_ +#define BOTAN_FILTER_H_ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents general abstract filter objects. +*/ +class BOTAN_PUBLIC_API(2,0) Filter + { + public: + /** + * @return descriptive name for this filter + */ + virtual std::string name() const = 0; + + /** + * Write a portion of a message to this filter. + * @param input the input as a byte array + * @param length the length of the byte array input + */ + virtual void write(const uint8_t input[], size_t length) = 0; + + /** + * Start a new message. Must be closed by end_msg() before another + * message can be started. + */ + virtual void start_msg() { /* default empty */ } + + /** + * Notify that the current message is finished; flush buffers and + * do end-of-message processing (if any). + */ + virtual void end_msg() { /* default empty */ } + + /** + * Check whether this filter is an attachable filter. + * @return true if this filter is attachable, false otherwise + */ + virtual bool attachable() { return true; } + + virtual ~Filter() = default; + protected: + /** + * @param in some input for the filter + * @param length the length of in + */ + virtual void send(const uint8_t in[], size_t length); + + /** + * @param in some input for the filter + */ + void send(uint8_t in) { send(&in, 1); } + + /** + * @param in some input for the filter + */ + template + void send(const std::vector& in) + { + send(in.data(), in.size()); + } + + /** + * @param in some input for the filter + * @param length the number of bytes of in to send + */ + template + void send(const std::vector& in, size_t length) + { + BOTAN_ASSERT_NOMSG(length <= in.size()); + send(in.data(), length); + } + + Filter(); + + Filter(const Filter&) = delete; + + Filter& operator=(const Filter&) = delete; + + private: + /** + * Start a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void new_msg(); + + /** + * End a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void finish_msg(); + + friend class Pipe; + friend class Fanout_Filter; + + size_t total_ports() const; + size_t current_port() const { return m_port_num; } + + /** + * Set the active port + * @param new_port the new value + */ + void set_port(size_t new_port); + + size_t owns() const { return m_filter_owns; } + + /** + * Attach another filter to this one + * @param f filter to attach + */ + void attach(Filter* f); + + /** + * @param filters the filters to set + * @param count number of items in filters + */ + void set_next(Filter* filters[], size_t count); + Filter* get_next() const; + + secure_vector m_write_queue; + std::vector m_next; // not owned + size_t m_port_num, m_filter_owns; + + // true if filter belongs to a pipe --> prohibit filter sharing! + bool m_owned; + }; + +/** +* This is the abstract Fanout_Filter base class. +**/ +class BOTAN_PUBLIC_API(2,0) Fanout_Filter : public Filter + { + protected: + /** + * Increment the number of filters past us that we own + */ + void incr_owns() { ++m_filter_owns; } + + void set_port(size_t n) { Filter::set_port(n); } + + void set_next(Filter* f[], size_t n) { Filter::set_next(f, n); } + + void attach(Filter* f) { Filter::attach(f); } + + private: + friend class Threaded_Fork; + using Filter::m_write_queue; + using Filter::total_ports; + using Filter::m_next; + }; + +/** +* The type of checking to be performed by decoders: +* NONE - no checks, IGNORE_WS - perform checks, but ignore +* whitespaces, FULL_CHECK - perform checks, also complain +* about white spaces. +*/ +enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/filters/filters.h b/comm/third_party/botan/src/lib/filters/filters.h new file mode 100644 index 0000000000..c19e1a749c --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/filters.h @@ -0,0 +1,741 @@ +/* +* Common Filters +* (C) 1999-2007,2015 Jack Lloyd +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FILTERS_H_ +#define BOTAN_FILTERS_H_ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + #include +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_HASH) + #include +#endif + +#if defined(BOTAN_HAS_MAC) + #include +#endif + +namespace Botan { + +/** +* Filter mixin that breaks input into blocks, useful for +* cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Buffered_Filter + { + public: + /** + * Write bytes into the buffered filter, which will them emit them + * in calls to buffered_block in the subclass + * @param in the input bytes + * @param length of in in bytes + */ + void write(const uint8_t in[], size_t length); + + template + void write(const std::vector& in, size_t length) + { + write(in.data(), length); + } + + /** + * Finish a message, emitting to buffered_block and buffered_final + * Will throw an exception if less than final_minimum bytes were + * written into the filter. + */ + void end_msg(); + + /** + * Initialize a Buffered_Filter + * @param block_size the function buffered_block will be called + * with inputs which are a multiple of this size + * @param final_minimum the function buffered_final will be called + * with at least this many bytes. + */ + Buffered_Filter(size_t block_size, size_t final_minimum); + + virtual ~Buffered_Filter() = default; + protected: + /** + * The block processor, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be a multiple + * of block_size + */ + virtual void buffered_block(const uint8_t input[], size_t length) = 0; + + /** + * The final block, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be at least + * final_minimum bytes + */ + virtual void buffered_final(const uint8_t input[], size_t length) = 0; + + /** + * @return block size of inputs + */ + size_t buffered_block_size() const { return m_main_block_mod; } + + /** + * @return current position in the buffer + */ + size_t current_position() const { return m_buffer_pos; } + + /** + * Reset the buffer position + */ + void buffer_reset() { m_buffer_pos = 0; } + private: + size_t m_main_block_mod, m_final_minimum; + + secure_vector m_buffer; + size_t m_buffer_pos; + }; + +/** +* This class represents keyed filters, i.e. filters that have to be +* fed with a key in order to function. +*/ +class BOTAN_PUBLIC_API(2,0) Keyed_Filter : public Filter + { + public: + /** + * Set the key of this filter + * @param key the key to use + */ + virtual void set_key(const SymmetricKey& key) = 0; + + /** + * Set the initialization vector of this filter. Note: you should + * call set_iv() only after you have called set_key() + * @param iv the initialization vector to use + */ + virtual void set_iv(const InitializationVector& iv) + { + if(iv.length() != 0) + throw Invalid_IV_Length(name(), iv.length()); + } + + /** + * Check whether a key length is valid for this filter + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * Check whether an IV length is valid for this filter + * @param length the IV length to be checked for validity + * @return true if the IV length is valid, false otherwise + */ + virtual bool valid_iv_length(size_t length) const + { return (length == 0); } + }; + +/** +* Filter interface for cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Cipher_Mode_Filter final : public Keyed_Filter, + private Buffered_Filter + { + public: + explicit Cipher_Mode_Filter(Cipher_Mode* t); + + explicit Cipher_Mode_Filter(std::unique_ptr t) : + Cipher_Mode_Filter(t.release()) {} + + void set_iv(const InitializationVector& iv) override; + + void set_key(const SymmetricKey& key) override; + + Key_Length_Specification key_spec() const override; + + bool valid_iv_length(size_t length) const override; + + std::string name() const override; + + private: + void write(const uint8_t input[], size_t input_length) override; + void start_msg() override; + void end_msg() override; + + void buffered_block(const uint8_t input[], size_t input_length) override; + void buffered_final(const uint8_t input[], size_t input_length) override; + + std::unique_ptr m_mode; + std::vector m_nonce; + secure_vector m_buffer; + }; + +// deprecated aliases, will be removed in a future major release +typedef Cipher_Mode_Filter Transform_Filter; +typedef Transform_Filter Transformation_Filter; + +/* +* Get a cipher object +*/ + +/** +* Factory method for general symmetric cipher filters. No key will be +* set in the filter. +* +* @param algo_spec the name of the desired cipher +* @param direction determines whether the filter will be an encrypting or +* decrypting filter +* @return pointer to the encryption or decryption filter +*/ +inline Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction) + { + std::unique_ptr c(Cipher_Mode::create_or_throw(algo_spec, direction)); + return new Cipher_Mode_Filter(c.release()); + } + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to the encryption or decryption filter +*/ +inline Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction) + { + Keyed_Filter* cipher = get_cipher(algo_spec, direction); + cipher->set_key(key); + return cipher; + } + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param iv the initialization vector to be used +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to newly allocated encryption or decryption filter +*/ +inline Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction) + { + Keyed_Filter* cipher = get_cipher(algo_spec, key, direction); + if(iv.length()) + cipher->set_iv(iv); + return cipher; + } + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +/** +* Stream Cipher Filter +*/ +class BOTAN_PUBLIC_API(2,0) StreamCipher_Filter final : public Keyed_Filter + { + public: + + std::string name() const override { return m_cipher->name(); } + + /** + * Write input data + * @param input data + * @param input_len length of input in bytes + */ + void write(const uint8_t input[], size_t input_len) override; + + bool valid_iv_length(size_t iv_len) const override + { return m_cipher->valid_iv_length(iv_len); } + + /** + * Set the initialization vector for this filter. + * @param iv the initialization vector to set + */ + void set_iv(const InitializationVector& iv) override + { + m_cipher->set_iv(iv.begin(), iv.length()); + } + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) override { m_cipher->set_key(key); } + + Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); } + + /** + * Construct a stream cipher filter. + * @param cipher a cipher object to use + */ + explicit StreamCipher_Filter(StreamCipher* cipher); + + /** + * Construct a stream cipher filter. + * @param cipher a cipher object to use + * @param key the key to use inside this filter + */ + StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + */ + explicit StreamCipher_Filter(const std::string& cipher); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + * @param key the key to use inside this filter + */ + StreamCipher_Filter(const std::string& cipher, const SymmetricKey& key); + private: + secure_vector m_buffer; + std::unique_ptr m_cipher; + }; +#endif + +#if defined(BOTAN_HAS_HASH) + +/** +* Hash Filter. +*/ +class BOTAN_PUBLIC_API(2,0) Hash_Filter final : public Filter + { + public: + void write(const uint8_t input[], size_t len) override { m_hash->update(input, len); } + void end_msg() override; + + std::string name() const override { return m_hash->name(); } + + /** + * Construct a hash filter. + * @param hash the hash function to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(HashFunction* hash, size_t len = 0) : + m_hash(hash), m_out_len(len) {} + + /** + * Construct a hash filter. + * @param request the name of the hash algorithm to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(const std::string& request, size_t len = 0); + + private: + std::unique_ptr m_hash; + const size_t m_out_len; + }; +#endif + +#if defined(BOTAN_HAS_MAC) + +/** +* MessageAuthenticationCode Filter. +*/ +class BOTAN_PUBLIC_API(2,0) MAC_Filter final : public Keyed_Filter + { + public: + void write(const uint8_t input[], size_t len) override { m_mac->update(input, len); } + void end_msg() override; + + std::string name() const override { return m_mac->name(); } + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) override { m_mac->set_key(key); } + + Key_Length_Specification key_spec() const override { return m_mac->key_spec(); } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the MAC to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac, + size_t out_len = 0) : + m_mac(mac), + m_out_len(out_len) + { + } + + /** + * Construct a MAC filter. + * @param mac the MAC to use + * @param key the MAC key to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac, + const SymmetricKey& key, + size_t out_len = 0) : + m_mac(mac), + m_out_len(out_len) + { + m_mac->set_key(key); + } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the name of the MAC to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, size_t len = 0); + + /** + * Construct a MAC filter. + * @param mac the name of the MAC to use + * @param key the MAC key to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, const SymmetricKey& key, + size_t len = 0); + private: + std::unique_ptr m_mac; + const size_t m_out_len; + }; +#endif + +#if defined(BOTAN_HAS_COMPRESSION) + +class Compression_Algorithm; +class Decompression_Algorithm; + +/** +* Filter interface for compression +*/ +class BOTAN_PUBLIC_API(2,0) Compression_Filter final : public Filter + { + public: + void start_msg() override; + void write(const uint8_t input[], size_t input_length) override; + void end_msg() override; + + void flush(); + + std::string name() const override; + + Compression_Filter(const std::string& type, + size_t compression_level, + size_t buffer_size = 4096); + + ~Compression_Filter(); + private: + std::unique_ptr m_comp; + size_t m_buffersize, m_level; + secure_vector m_buffer; + }; + +/** +* Filter interface for decompression +*/ +class BOTAN_PUBLIC_API(2,0) Decompression_Filter final : public Filter + { + public: + void start_msg() override; + void write(const uint8_t input[], size_t input_length) override; + void end_msg() override; + + std::string name() const override; + + Decompression_Filter(const std::string& type, + size_t buffer_size = 4096); + + ~Decompression_Filter(); + private: + std::unique_ptr m_comp; + std::size_t m_buffersize; + secure_vector m_buffer; + }; + +#endif + +/** +* This class represents a Base64 encoder. +*/ +class BOTAN_PUBLIC_API(2,0) Base64_Encoder final : public Filter + { + public: + std::string name() const override { return "Base64_Encoder"; } + + /** + * Input a part of a message to the encoder. + * @param input the message to input as a byte array + * @param length the length of the byte array input + */ + void write(const uint8_t input[], size_t length) override; + + /** + * Inform the Encoder that the current message shall be closed. + */ + void end_msg() override; + + /** + * Create a base64 encoder. + * @param breaks whether to use line breaks in the output + * @param length the length of the lines of the output + * @param t_n whether to use a trailing newline + */ + Base64_Encoder(bool breaks = false, size_t length = 72, + bool t_n = false); + private: + void encode_and_send(const uint8_t input[], size_t length, + bool final_inputs = false); + void do_output(const uint8_t output[], size_t length); + + const size_t m_line_length; + const bool m_trailing_newline; + std::vector m_in, m_out; + size_t m_position, m_out_position; + }; + +/** +* This object represents a Base64 decoder. +*/ +class BOTAN_PUBLIC_API(2,0) Base64_Decoder final : public Filter + { + public: + std::string name() const override { return "Base64_Decoder"; } + + /** + * Input a part of a message to the decoder. + * @param input the message to input as a byte array + * @param length the length of the byte array input + */ + void write(const uint8_t input[], size_t length) override; + + /** + * Finish up the current message + */ + void end_msg() override; + + /** + * Create a base64 decoder. + * @param checking the type of checking that shall be performed by + * the decoder + */ + explicit Base64_Decoder(Decoder_Checking checking = NONE); + private: + const Decoder_Checking m_checking; + std::vector m_in, m_out; + size_t m_position; + }; + +/** +* Converts arbitrary binary data to hex strings, optionally with +* newlines inserted +*/ +class BOTAN_PUBLIC_API(2,0) Hex_Encoder final : public Filter + { + public: + /** + * Whether to use uppercase or lowercase letters for the encoded string. + */ + enum Case { Uppercase, Lowercase }; + + std::string name() const override { return "Hex_Encoder"; } + + void write(const uint8_t in[], size_t length) override; + void end_msg() override; + + /** + * Create a hex encoder. + * @param the_case the case to use in the encoded strings. + */ + explicit Hex_Encoder(Case the_case); + + /** + * Create a hex encoder. + * @param newlines should newlines be used + * @param line_length if newlines are used, how long are lines + * @param the_case the case to use in the encoded strings + */ + Hex_Encoder(bool newlines = false, + size_t line_length = 72, + Case the_case = Uppercase); + private: + void encode_and_send(const uint8_t[], size_t); + + const Case m_casing; + const size_t m_line_length; + std::vector m_in, m_out; + size_t m_position, m_counter; + }; + +/** +* Converts hex strings to bytes +*/ +class BOTAN_PUBLIC_API(2,0) Hex_Decoder final : public Filter + { + public: + std::string name() const override { return "Hex_Decoder"; } + + void write(const uint8_t[], size_t) override; + void end_msg() override; + + /** + * Construct a Hex Decoder using the specified + * character checking. + * @param checking the checking to use during decoding. + */ + explicit Hex_Decoder(Decoder_Checking checking = NONE); + private: + const Decoder_Checking m_checking; + std::vector m_in, m_out; + size_t m_position; + }; + +/** +* BitBucket is a filter which simply discards all inputs +*/ +class BOTAN_PUBLIC_API(2,0) BitBucket final : public Filter + { + public: + void write(const uint8_t[], size_t) override { /* discard */ } + + std::string name() const override { return "BitBucket"; } + }; + +/** +* This class represents Filter chains. A Filter chain is an ordered +* concatenation of Filters, the input to a Chain sequentially passes +* through all the Filters contained in the Chain. +*/ + +class BOTAN_PUBLIC_API(2,0) Chain final : public Fanout_Filter + { + public: + void write(const uint8_t input[], size_t length) override { send(input, length); } + + std::string name() const override { return "Chain"; } + + /** + * Construct a chain of up to four filters. The filters are set + * up in the same order as the arguments. + */ + Chain(Filter* = nullptr, Filter* = nullptr, + Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a chain from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Chain(Filter* filter_arr[], size_t length); + }; + +/** +* This class represents a fork filter, whose purpose is to fork the +* flow of data. It causes an input message to result in n messages at +* the end of the filter, where n is the number of forks. +*/ +class BOTAN_PUBLIC_API(2,0) Fork : public Fanout_Filter + { + public: + void write(const uint8_t input[], size_t length) override { send(input, length); } + void set_port(size_t n) { Fanout_Filter::set_port(n); } + + std::string name() const override { return "Fork"; } + + /** + * Construct a Fork filter with up to four forks. + */ + Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Fork(Filter* filter_arr[], size_t length); + }; + +#if defined(BOTAN_HAS_THREAD_UTILS) + +/** +* This class is a threaded version of the Fork filter. While this uses +* threads, the class itself is NOT thread-safe. This is meant as a drop- +* in replacement for Fork where performance gains are possible. +*/ +class BOTAN_PUBLIC_API(2,0) Threaded_Fork final : public Fork + { + public: + std::string name() const override; + + /** + * Construct a Threaded_Fork filter with up to four forks. + */ + Threaded_Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Threaded_Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Threaded_Fork(Filter* filter_arr[], size_t length); + + ~Threaded_Fork(); + + private: + void set_next(Filter* f[], size_t n); + void send(const uint8_t in[], size_t length) override; + void thread_delegate_work(const uint8_t input[], size_t length); + void thread_entry(Filter* filter); + + std::vector> m_threads; + std::unique_ptr m_thread_data; + }; +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/filters/hex_filt.cpp b/comm/third_party/botan/src/lib/filters/hex_filt.cpp new file mode 100644 index 0000000000..761c73ade1 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/hex_filt.cpp @@ -0,0 +1,170 @@ +/* +* Hex Encoder/Decoder +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Size used for internal buffer in hex encoder/decoder +*/ +const size_t HEX_CODEC_BUFFER_SIZE = 256; + +/* +* Hex_Encoder Constructor +*/ +Hex_Encoder::Hex_Encoder(bool breaks, size_t length, Case c) : + m_casing(c), m_line_length(breaks ? length : 0) + { + m_in.resize(HEX_CODEC_BUFFER_SIZE); + m_out.resize(2*m_in.size()); + m_counter = m_position = 0; + } + +/* +* Hex_Encoder Constructor +*/ +Hex_Encoder::Hex_Encoder(Case c) : m_casing(c), m_line_length(0) + { + m_in.resize(HEX_CODEC_BUFFER_SIZE); + m_out.resize(2*m_in.size()); + m_counter = m_position = 0; + } + +/* +* Encode and send a block +*/ +void Hex_Encoder::encode_and_send(const uint8_t block[], size_t length) + { + hex_encode(cast_uint8_ptr_to_char(m_out.data()), + block, length, + m_casing == Uppercase); + + if(m_line_length == 0) + send(m_out, 2*length); + else + { + size_t remaining = 2*length, offset = 0; + while(remaining) + { + size_t sent = std::min(m_line_length - m_counter, remaining); + send(&m_out[offset], sent); + m_counter += sent; + remaining -= sent; + offset += sent; + if(m_counter == m_line_length) + { + send('\n'); + m_counter = 0; + } + } + } + } + +/* +* Convert some data into hex format +*/ +void Hex_Encoder::write(const uint8_t input[], size_t length) + { + buffer_insert(m_in, m_position, input, length); + if(m_position + length >= m_in.size()) + { + encode_and_send(m_in.data(), m_in.size()); + input += (m_in.size() - m_position); + length -= (m_in.size() - m_position); + while(length >= m_in.size()) + { + encode_and_send(input, m_in.size()); + input += m_in.size(); + length -= m_in.size(); + } + copy_mem(m_in.data(), input, length); + m_position = 0; + } + m_position += length; + } + +/* +* Flush buffers +*/ +void Hex_Encoder::end_msg() + { + encode_and_send(m_in.data(), m_position); + if(m_counter && m_line_length) + send('\n'); + m_counter = m_position = 0; + } + +/* +* Hex_Decoder Constructor +*/ +Hex_Decoder::Hex_Decoder(Decoder_Checking c) : m_checking(c) + { + m_in.resize(HEX_CODEC_BUFFER_SIZE); + m_out.resize(m_in.size() / 2); + m_position = 0; + } + +/* +* Convert some data from hex format +*/ +void Hex_Decoder::write(const uint8_t input[], size_t length) + { + while(length) + { + size_t to_copy = std::min(length, m_in.size() - m_position); + copy_mem(&m_in[m_position], input, to_copy); + m_position += to_copy; + + size_t consumed = 0; + size_t written = hex_decode(m_out.data(), + cast_uint8_ptr_to_char(m_in.data()), + m_position, + consumed, + m_checking != FULL_CHECK); + + send(m_out, written); + + if(consumed != m_position) + { + copy_mem(m_in.data(), m_in.data() + consumed, m_position - consumed); + m_position = m_position - consumed; + } + else + m_position = 0; + + length -= to_copy; + input += to_copy; + } + } + +/* +* Flush buffers +*/ +void Hex_Decoder::end_msg() + { + size_t consumed = 0; + size_t written = hex_decode(m_out.data(), + cast_uint8_ptr_to_char(m_in.data()), + m_position, + consumed, + m_checking != FULL_CHECK); + + send(m_out, written); + + const bool not_full_bytes = consumed != m_position; + + m_position = 0; + + if(not_full_bytes) + throw Invalid_Argument("Hex_Decoder: Input not full bytes"); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/hex_filt.h b/comm/third_party/botan/src/lib/filters/hex_filt.h new file mode 100644 index 0000000000..b529b52990 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/hex_filt.h @@ -0,0 +1,14 @@ +/* +* Hex Encoder/Decoder +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HEX_FILTER_H_ +#define BOTAN_HEX_FILTER_H_ + +#include +BOTAN_DEPRECATED_HEADER(hex_filt.h) + +#endif diff --git a/comm/third_party/botan/src/lib/filters/info.txt b/comm/third_party/botan/src/lib/filters/info.txt new file mode 100644 index 0000000000..2fe9335795 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/info.txt @@ -0,0 +1,31 @@ + +FILTERS -> 20160415 +CODEC_FILTERS -> 20131128 + + + +basefilt.h +comp_filter.h +cipher_filter.h +buf_filt.h +key_filt.h + +b64_filt.h +hex_filt.h + +secqueue.h + +data_snk.h +filter.h +filters.h +pipe.h + + + +out_buf.h + + + +modes +base64 + diff --git a/comm/third_party/botan/src/lib/filters/key_filt.h b/comm/third_party/botan/src/lib/filters/key_filt.h new file mode 100644 index 0000000000..3d85d886ab --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/key_filt.h @@ -0,0 +1,14 @@ +/* +* Keyed_Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEYED_FILTER_H_ +#define BOTAN_KEYED_FILTER_H_ + +#include +BOTAN_DEPRECATED_HEADER(key_filt.h) + +#endif diff --git a/comm/third_party/botan/src/lib/filters/out_buf.cpp b/comm/third_party/botan/src/lib/filters/out_buf.cpp new file mode 100644 index 0000000000..645cc08236 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/out_buf.cpp @@ -0,0 +1,121 @@ +/* +* Pipe Output Buffer +* (C) 1999-2007,2011 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Read data from a message +*/ +size_t Output_Buffers::read(uint8_t output[], size_t length, + Pipe::message_id msg) + { + SecureQueue* q = get(msg); + if(q) + return q->read(output, length); + return 0; + } + +/* +* Peek at data in a message +*/ +size_t Output_Buffers::peek(uint8_t output[], size_t length, + size_t stream_offset, + Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->peek(output, length, stream_offset); + return 0; + } + +/* +* Check available bytes in a message +*/ +size_t Output_Buffers::remaining(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->size(); + return 0; + } + +/* +* Return the total bytes of a message that have already been read. +*/ +size_t Output_Buffers::get_bytes_read(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if (q) + return q->get_bytes_read(); + return 0; + } + +/* +* Add a new output queue +*/ +void Output_Buffers::add(SecureQueue* queue) + { + BOTAN_ASSERT(queue, "queue was provided"); + + BOTAN_ASSERT(m_buffers.size() < m_buffers.max_size(), + "Room was available in container"); + + m_buffers.push_back(std::unique_ptr(queue)); + } + +/* +* Retire old output queues +*/ +void Output_Buffers::retire() + { + for(size_t i = 0; i != m_buffers.size(); ++i) + if(m_buffers[i] && m_buffers[i]->size() == 0) + { + m_buffers[i].reset(); + } + + while(m_buffers.size() && !m_buffers[0]) + { + m_buffers.pop_front(); + m_offset = m_offset + Pipe::message_id(1); + } + } + +/* +* Get a particular output queue +*/ +SecureQueue* Output_Buffers::get(Pipe::message_id msg) const + { + if(msg < m_offset) + return nullptr; + + BOTAN_ASSERT(msg < message_count(), "Message number is in range"); + + return m_buffers[msg-m_offset].get(); + } + +/* +* Return the total number of messages +*/ +Pipe::message_id Output_Buffers::message_count() const + { + return (m_offset + m_buffers.size()); + } + +/* +* Output_Buffers Constructor +*/ +Output_Buffers::Output_Buffers() + { + m_offset = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/filters/out_buf.h b/comm/third_party/botan/src/lib/filters/out_buf.h new file mode 100644 index 0000000000..d6efbdaf27 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/out_buf.h @@ -0,0 +1,44 @@ +/* +* Output Buffer +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OUTPUT_BUFFER_H_ +#define BOTAN_OUTPUT_BUFFER_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Container of output buffers for Pipe +*/ +class Output_Buffers final + { + public: + size_t read(uint8_t[], size_t, Pipe::message_id); + size_t peek(uint8_t[], size_t, size_t, Pipe::message_id) const; + size_t get_bytes_read(Pipe::message_id) const; + size_t remaining(Pipe::message_id) const; + + void add(class SecureQueue*); + void retire(); + + Pipe::message_id message_count() const; + + Output_Buffers(); + private: + class SecureQueue* get(Pipe::message_id) const; + + std::deque> m_buffers; + Pipe::message_id m_offset; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/filters/pipe.cpp b/comm/third_party/botan/src/lib/filters/pipe.cpp new file mode 100644 index 0000000000..0bba81bf2d --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/pipe.cpp @@ -0,0 +1,311 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* A Filter that does nothing +*/ +class Null_Filter final : public Filter + { + public: + void write(const uint8_t input[], size_t length) override + { send(input, length); } + + std::string name() const override { return "Null"; } + }; + +} + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : + Pipe({f1,f2,f3,f4}) + { + } + +/* +* Pipe Constructor +*/ +Pipe::Pipe(std::initializer_list args) + { + m_outputs.reset(new Output_Buffers); + m_pipe = nullptr; + m_default_read = 0; + m_inside_msg = false; + + for(auto i = args.begin(); i != args.end(); ++i) + do_append(*i); + } + +/* +* Pipe Destructor +*/ +Pipe::~Pipe() + { + destruct(m_pipe); + } + +/* +* Reset the Pipe +*/ +void Pipe::reset() + { + destruct(m_pipe); + m_pipe = nullptr; + m_inside_msg = false; + } + +/* +* Destroy the Pipe +*/ +void Pipe::destruct(Filter* to_kill) + { + if(!to_kill || dynamic_cast(to_kill)) + return; + for(size_t j = 0; j != to_kill->total_ports(); ++j) + destruct(to_kill->m_next[j]); + delete to_kill; + } + +/* +* Test if the Pipe has any data in it +*/ +bool Pipe::end_of_data() const + { + return (remaining() == 0); + } + +/* +* Set the default read message +*/ +void Pipe::set_default_msg(message_id msg) + { + if(msg >= message_count()) + throw Invalid_Argument("Pipe::set_default_msg: msg number is too high"); + m_default_read = msg; + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const uint8_t input[], size_t length) + { + start_msg(); + write(input, length); + end_msg(); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const secure_vector& input) + { + process_msg(input.data(), input.size()); + } + +void Pipe::process_msg(const std::vector& input) + { + process_msg(input.data(), input.size()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const std::string& input) + { + process_msg(cast_char_ptr_to_uint8(input.data()), input.length()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(DataSource& input) + { + start_msg(); + write(input); + end_msg(); + } + +/* +* Start a new message +*/ +void Pipe::start_msg() + { + if(m_inside_msg) + throw Invalid_State("Pipe::start_msg: Message was already started"); + if(m_pipe == nullptr) + m_pipe = new Null_Filter; + find_endpoints(m_pipe); + m_pipe->new_msg(); + m_inside_msg = true; + } + +/* +* End the current message +*/ +void Pipe::end_msg() + { + if(!m_inside_msg) + throw Invalid_State("Pipe::end_msg: Message was already ended"); + m_pipe->finish_msg(); + clear_endpoints(m_pipe); + if(dynamic_cast(m_pipe)) + { + delete m_pipe; + m_pipe = nullptr; + } + m_inside_msg = false; + + m_outputs->retire(); + } + +/* +* Find the endpoints of the Pipe +*/ +void Pipe::find_endpoints(Filter* f) + { + for(size_t j = 0; j != f->total_ports(); ++j) + if(f->m_next[j] && !dynamic_cast(f->m_next[j])) + find_endpoints(f->m_next[j]); + else + { + SecureQueue* q = new SecureQueue; + f->m_next[j] = q; + m_outputs->add(q); + } + } + +/* +* Remove the SecureQueues attached to the Filter +*/ +void Pipe::clear_endpoints(Filter* f) + { + if(!f) return; + for(size_t j = 0; j != f->total_ports(); ++j) + { + if(f->m_next[j] && dynamic_cast(f->m_next[j])) + f->m_next[j] = nullptr; + clear_endpoints(f->m_next[j]); + } + } + +void Pipe::append(Filter* filter) + { + do_append(filter); + } + +void Pipe::append_filter(Filter* filter) + { + if(m_outputs->message_count() != 0) + throw Invalid_State("Cannot call Pipe::append_filter after start_msg"); + + do_append(filter); + } + +void Pipe::prepend(Filter* filter) + { + do_prepend(filter); + } + +void Pipe::prepend_filter(Filter* filter) + { + if(m_outputs->message_count() != 0) + throw Invalid_State("Cannot call Pipe::prepend_filter after start_msg"); + + do_prepend(filter); + } + +/* +* Append a Filter to the Pipe +*/ +void Pipe::do_append(Filter* filter) + { + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); + if(filter->m_owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + if(m_inside_msg) + throw Invalid_State("Cannot append to a Pipe while it is processing"); + + filter->m_owned = true; + + if(!m_pipe) m_pipe = filter; + else m_pipe->attach(filter); + } + +/* +* Prepend a Filter to the Pipe +*/ +void Pipe::do_prepend(Filter* filter) + { + if(m_inside_msg) + throw Invalid_State("Cannot prepend to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast(filter)) + throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); + if(filter->m_owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->m_owned = true; + + if(m_pipe) filter->attach(m_pipe); + m_pipe = filter; + } + +/* +* Pop a Filter off the Pipe +*/ +void Pipe::pop() + { + if(m_inside_msg) + throw Invalid_State("Cannot pop off a Pipe while it is processing"); + + if(!m_pipe) + return; + + if(m_pipe->total_ports() > 1) + throw Invalid_State("Cannot pop off a Filter with multiple ports"); + + size_t to_remove = m_pipe->owns() + 1; + + while(to_remove--) + { + std::unique_ptr to_destroy(m_pipe); + m_pipe = m_pipe->m_next[0]; + } + } + +/* +* Return the number of messages in this Pipe +*/ +Pipe::message_id Pipe::message_count() const + { + return m_outputs->message_count(); + } + +/* +* Static Member Variables +*/ +const Pipe::message_id Pipe::LAST_MESSAGE = + static_cast(-2); + +const Pipe::message_id Pipe::DEFAULT_MESSAGE = + static_cast(-1); + +} diff --git a/comm/third_party/botan/src/lib/filters/pipe.h b/comm/third_party/botan/src/lib/filters/pipe.h new file mode 100644 index 0000000000..03b5160835 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/pipe.h @@ -0,0 +1,379 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PIPE_H_ +#define BOTAN_PIPE_H_ + +#include +#include +#include +#include + +namespace Botan { + +class Filter; +class Output_Buffers; + +/** +* This class represents pipe objects. +* A set of filters can be placed into a pipe, and information flows +* through the pipe until it reaches the end, where the output is +* collected for retrieval. If you're familiar with the Unix shell +* environment, this design will sound quite familiar. +*/ +class BOTAN_PUBLIC_API(2,0) Pipe final : public DataSource + { + public: + /** + * An opaque type that identifies a message in this Pipe + */ + typedef size_t message_id; + + /** + * Exception if you use an invalid message as an argument to + * read, remaining, etc + */ + class BOTAN_PUBLIC_API(2,0) Invalid_Message_Number final : public Invalid_Argument + { + public: + /** + * @param where the error occurred + * @param msg the invalid message id that was used + */ + Invalid_Message_Number(const std::string& where, message_id msg) : + Invalid_Argument("Pipe::" + where + ": Invalid message number " + + std::to_string(msg)) + {} + }; + + /** + * A meta-id for whatever the last message is + */ + static const message_id LAST_MESSAGE; + + /** + * A meta-id for the default message (set with set_default_msg) + */ + static const message_id DEFAULT_MESSAGE; + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the byte array to write + * @param length the length of the byte array in + */ + void write(const uint8_t in[], size_t length); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the secure_vector containing the data to write + */ + void write(const secure_vector& in) + { write(in.data(), in.size()); } + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the std::vector containing the data to write + */ + void write(const std::vector& in) + { write(in.data(), in.size()); } + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the string containing the data to write + */ + void write(const std::string& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the DataSource to read the data from + */ + void write(DataSource& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in a single byte to be written + */ + void write(uint8_t in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the byte array containing the data to write + * @param length the length of the byte array to write + */ + void process_msg(const uint8_t in[], size_t length); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the secure_vector containing the data to write + */ + void process_msg(const secure_vector& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the secure_vector containing the data to write + */ + void process_msg(const std::vector& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the string containing the data to write + */ + void process_msg(const std::string& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the DataSource providing the data to write + */ + void process_msg(DataSource& in); + + /** + * Find out how many bytes are ready to read. + * @param msg the number identifying the message + * for which the information is desired + * @return number of bytes that can still be read + */ + size_t remaining(message_id msg = DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT; + + /** + * Read the default message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @return number of bytes actually read into output + */ + size_t read(uint8_t output[], size_t length) override BOTAN_WARN_UNUSED_RESULT; + + /** + * Read a specified message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @param msg the number identifying the message to read from + * @return number of bytes actually read into output + */ + size_t read(uint8_t output[], size_t length, message_id msg) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read a single byte from the pipe. Moves the internal offset so + * that every call to read will return a new portion of the + * message. + * + * @param output the byte to write the result to + * @param msg the message to read from + * @return number of bytes actually read into output + */ + size_t read(uint8_t& output, message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return secure_vector holding the contents of the pipe + */ + secure_vector read_all(message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return string holding the contents of the pipe + */ + std::string read_all_as_string(message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read from the default message but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @return number of bytes actually peeked and written into output + */ + size_t peek(uint8_t output[], size_t length, size_t offset) const override BOTAN_WARN_UNUSED_RESULT; + + /** Read from the specified message but do not modify the + * internal offset. Consecutive calls to peek() will return + * portions of the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(uint8_t output[], size_t length, + size_t offset, message_id msg) const BOTAN_WARN_UNUSED_RESULT; + + /** Read a single byte from the specified message but do not + * modify the internal offset. Consecutive calls to peek() will + * return portions of the message starting at the same position. + * @param output the byte to write the peeked message byte to + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(uint8_t& output, size_t offset, + message_id msg = DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT; + + /** + * @return the number of bytes read from the default message. + */ + size_t get_bytes_read() const override; + + /** + * @return the number of bytes read from the specified message. + */ + size_t get_bytes_read(message_id msg) const; + + bool check_available(size_t n) override; + bool check_available_msg(size_t n, message_id msg); + + /** + * @return currently set default message + */ + size_t default_msg() const { return m_default_read; } + + /** + * Set the default message + * @param msg the number identifying the message which is going to + * be the new default message + */ + void set_default_msg(message_id msg); + + /** + * Get the number of messages the are in this pipe. + * @return number of messages the are in this pipe + */ + message_id message_count() const; + + /** + * Test whether this pipe has any data that can be read from. + * @return true if there is more data to read, false otherwise + */ + bool end_of_data() const override; + + /** + * Start a new message in the pipe. A potential other message in this pipe + * must be closed with end_msg() before this function may be called. + */ + void start_msg(); + + /** + * End the current message. + */ + void end_msg(); + + /** + * Insert a new filter at the front of the pipe + * Deprecated because runtime modification of Pipes is deprecated. + * You can instead use prepend_filter which only works before the first + * message is processed. + * @param filt the new filter to insert + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void prepend(Filter* filt); + + /** + * Insert a new filter at the back of the pipe + * Deprecated because runtime modification of Pipes is deprecated. + * You can instead use append_filter which only works before the first + * message is processed. + * @param filt the new filter to insert + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void append(Filter* filt); + + /** + * Remove the first filter at the front of the pipe. + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void pop(); + + /** + * Reset this pipe to an empty pipe. + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void reset(); + + /** + * Append a new filter onto the filter sequence. This may only be + * called immediately after initial construction, before _any_ + * calls to start_msg have been made. + * + * This function (unlike append) is not deprecated, as it allows + * only modification of the pipe at initialization (before use) + * rather than after messages have been processed. + */ + void append_filter(Filter* filt); + + /** + * Prepend a new filter onto the filter sequence. This may only be + * called immediately after initial construction, before _any_ + * calls to start_msg have been made. + * + * This function (unlike prepend) is not deprecated, as it allows + * only modification of the pipe at initialization (before use) + * rather than after messages have been processed. + */ + void prepend_filter(Filter* filt); + + /** + * Construct a Pipe of up to four filters. The filters are set up + * in the same order as the arguments. + */ + Pipe(Filter* = nullptr, Filter* = nullptr, + Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Pipe from a list of filters + * @param filters the set of filters to use + */ + explicit Pipe(std::initializer_list filters); + + Pipe(const Pipe&) = delete; + Pipe& operator=(const Pipe&) = delete; + + ~Pipe(); + private: + void destruct(Filter*); + void do_append(Filter* filt); + void do_prepend(Filter* filt); + void find_endpoints(Filter*); + void clear_endpoints(Filter*); + + message_id get_message_no(const std::string&, message_id) const; + + Filter* m_pipe; + std::unique_ptr m_outputs; + message_id m_default_read; + bool m_inside_msg; + }; + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out an output stream +* @param pipe the pipe +*/ +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, Pipe& pipe); + +/** +* Stream input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in the input stream +* @param pipe the pipe +*/ +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, Pipe& pipe); + +} + +#if defined(BOTAN_HAS_PIPE_UNIXFD_IO) + #include +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/filters/pipe_io.cpp b/comm/third_party/botan/src/lib/filters/pipe_io.cpp new file mode 100644 index 0000000000..a909cba725 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/pipe_io.cpp @@ -0,0 +1,47 @@ +/* +* Pipe I/O +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Write data from a pipe into an ostream +*/ +std::ostream& operator<<(std::ostream& stream, Pipe& pipe) + { + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(stream.good() && pipe.remaining()) + { + const size_t got = pipe.read(buffer.data(), buffer.size()); + stream.write(cast_uint8_ptr_to_char(buffer.data()), got); + } + if(!stream.good()) + throw Stream_IO_Error("Pipe output operator (iostream) has failed"); + return stream; + } + +/* +* Read data from an istream into a pipe +*/ +std::istream& operator>>(std::istream& stream, Pipe& pipe) + { + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(stream.good()) + { + stream.read(cast_uint8_ptr_to_char(buffer.data()), buffer.size()); + const size_t got = static_cast(stream.gcount()); + pipe.write(buffer.data(), got); + } + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("Pipe input operator (iostream) has failed"); + return stream; + } + +} diff --git a/comm/third_party/botan/src/lib/filters/pipe_rw.cpp b/comm/third_party/botan/src/lib/filters/pipe_rw.cpp new file mode 100644 index 0000000000..dc7b973727 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/pipe_rw.cpp @@ -0,0 +1,181 @@ +/* +* Pipe Reading/Writing +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Look up the canonical ID for a queue +*/ +Pipe::message_id Pipe::get_message_no(const std::string& func_name, + message_id msg) const + { + if(msg == DEFAULT_MESSAGE) + msg = default_msg(); + else if(msg == LAST_MESSAGE) + msg = message_count() - 1; + + if(msg >= message_count()) + throw Invalid_Message_Number(func_name, msg); + + return msg; + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const uint8_t input[], size_t length) + { + if(!m_inside_msg) + throw Invalid_State("Cannot write to a Pipe while it is not processing"); + m_pipe->write(input, length); + } + +/* +* Write a string into a Pipe +*/ +void Pipe::write(const std::string& str) + { + write(cast_char_ptr_to_uint8(str.data()), str.size()); + } + +/* +* Write a single byte into a Pipe +*/ +void Pipe::write(uint8_t input) + { + write(&input, 1); + } + +/* +* Write the contents of a DataSource into a Pipe +*/ +void Pipe::write(DataSource& source) + { + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(!source.end_of_data()) + { + size_t got = source.read(buffer.data(), buffer.size()); + write(buffer.data(), got); + } + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(uint8_t output[], size_t length, message_id msg) + { + return m_outputs->read(output, length, get_message_no("read", msg)); + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(uint8_t output[], size_t length) + { + return read(output, length, DEFAULT_MESSAGE); + } + +/* +* Read a single byte from the pipe +*/ +size_t Pipe::read(uint8_t& out, message_id msg) + { + return read(&out, 1, msg); + } + +/* +* Return all data in the pipe +*/ +secure_vector Pipe::read_all(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + secure_vector buffer(remaining(msg)); + size_t got = read(buffer.data(), buffer.size(), msg); + buffer.resize(got); + return buffer; + } + +/* +* Return all data in the pipe as a string +*/ +std::string Pipe::read_all_as_string(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + secure_vector buffer(BOTAN_DEFAULT_BUFFER_SIZE); + std::string str; + str.reserve(remaining(msg)); + + while(true) + { + size_t got = read(buffer.data(), buffer.size(), msg); + if(got == 0) + break; + str.append(cast_uint8_ptr_to_char(buffer.data()), got); + } + + return str; + } + +/* +* Find out how many bytes are ready to read +*/ +size_t Pipe::remaining(message_id msg) const + { + return m_outputs->remaining(get_message_no("remaining", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(uint8_t output[], size_t length, + size_t offset, message_id msg) const + { + return m_outputs->peek(output, length, offset, get_message_no("peek", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(uint8_t output[], size_t length, size_t offset) const + { + return peek(output, length, offset, DEFAULT_MESSAGE); + } + +/* +* Peek at a byte in the pipe +*/ +size_t Pipe::peek(uint8_t& out, size_t offset, message_id msg) const + { + return peek(&out, 1, offset, msg); + } + +size_t Pipe::get_bytes_read() const + { + return m_outputs->get_bytes_read(default_msg()); + } + +size_t Pipe::get_bytes_read(message_id msg) const + { + return m_outputs->get_bytes_read(msg); + } + +bool Pipe::check_available(size_t n) + { + return (n <= remaining(default_msg())); + } + +bool Pipe::check_available_msg(size_t n, message_id msg) + { + return (n <= remaining(msg)); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/secqueue.cpp b/comm/third_party/botan/src/lib/filters/secqueue.cpp new file mode 100644 index 0000000000..1c8d281493 --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/secqueue.cpp @@ -0,0 +1,232 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/** +* A node in a SecureQueue +*/ +class SecureQueueNode final + { + public: + SecureQueueNode() : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE) + { m_next = nullptr; m_start = m_end = 0; } + + ~SecureQueueNode() { m_next = nullptr; m_start = m_end = 0; } + + size_t write(const uint8_t input[], size_t length) + { + size_t copied = std::min(length, m_buffer.size() - m_end); + copy_mem(m_buffer.data() + m_end, input, copied); + m_end += copied; + return copied; + } + + size_t read(uint8_t output[], size_t length) + { + size_t copied = std::min(length, m_end - m_start); + copy_mem(output, m_buffer.data() + m_start, copied); + m_start += copied; + return copied; + } + + size_t peek(uint8_t output[], size_t length, size_t offset = 0) + { + const size_t left = m_end - m_start; + if(offset >= left) return 0; + size_t copied = std::min(length, left - offset); + copy_mem(output, m_buffer.data() + m_start + offset, copied); + return copied; + } + + size_t size() const { return (m_end - m_start); } + private: + friend class SecureQueue; + SecureQueueNode* m_next; + secure_vector m_buffer; + size_t m_start, m_end; + }; + +/* +* Create a SecureQueue +*/ +SecureQueue::SecureQueue() + { + m_bytes_read = 0; + set_next(nullptr, 0); + m_head = m_tail = new SecureQueueNode; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue::SecureQueue(const SecureQueue& input) : + Fanout_Filter(), DataSource() + { + m_bytes_read = 0; + set_next(nullptr, 0); + + m_head = m_tail = new SecureQueueNode; + SecureQueueNode* temp = input.m_head; + while(temp) + { + write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start); + temp = temp->m_next; + } + } + +/* +* Destroy this SecureQueue +*/ +void SecureQueue::destroy() + { + SecureQueueNode* temp = m_head; + while(temp) + { + SecureQueueNode* holder = temp->m_next; + delete temp; + temp = holder; + } + m_head = m_tail = nullptr; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue& SecureQueue::operator=(const SecureQueue& input) + { + if(this == &input) + return *this; + + destroy(); + m_bytes_read = input.get_bytes_read(); + m_head = m_tail = new SecureQueueNode; + SecureQueueNode* temp = input.m_head; + while(temp) + { + write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start); + temp = temp->m_next; + } + return (*this); + } + +/* +* Add some bytes to the queue +*/ +void SecureQueue::write(const uint8_t input[], size_t length) + { + if(!m_head) + m_head = m_tail = new SecureQueueNode; + while(length) + { + const size_t n = m_tail->write(input, length); + input += n; + length -= n; + if(length) + { + m_tail->m_next = new SecureQueueNode; + m_tail = m_tail->m_next; + } + } + } + +/* +* Read some bytes from the queue +*/ +size_t SecureQueue::read(uint8_t output[], size_t length) + { + size_t got = 0; + while(length && m_head) + { + const size_t n = m_head->read(output, length); + output += n; + got += n; + length -= n; + if(m_head->size() == 0) + { + SecureQueueNode* holder = m_head->m_next; + delete m_head; + m_head = holder; + } + } + m_bytes_read += got; + return got; + } + +/* +* Read data, but do not remove it from queue +*/ +size_t SecureQueue::peek(uint8_t output[], size_t length, size_t offset) const + { + SecureQueueNode* current = m_head; + + while(offset && current) + { + if(offset >= current->size()) + { + offset -= current->size(); + current = current->m_next; + } + else + break; + } + + size_t got = 0; + while(length && current) + { + const size_t n = current->peek(output, length, offset); + offset = 0; + output += n; + got += n; + length -= n; + current = current->m_next; + } + return got; + } + +/** +* Return how many bytes have been read so far. +*/ +size_t SecureQueue::get_bytes_read() const + { + return m_bytes_read; + } + +/* +* Return how many bytes the queue holds +*/ +size_t SecureQueue::size() const + { + SecureQueueNode* current = m_head; + size_t count = 0; + + while(current) + { + count += current->size(); + current = current->m_next; + } + return count; + } + +/* +* Test if the queue has any data in it +*/ +bool SecureQueue::end_of_data() const + { + return (size() == 0); + } + +bool SecureQueue::empty() const + { + return (size() == 0); + } + +} diff --git a/comm/third_party/botan/src/lib/filters/secqueue.h b/comm/third_party/botan/src/lib/filters/secqueue.h new file mode 100644 index 0000000000..42d2f09e2d --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/secqueue.h @@ -0,0 +1,74 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SECURE_QUEUE_H_ +#define BOTAN_SECURE_QUEUE_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(secqueue.h) + +namespace Botan { + +/** +* A queue that knows how to zeroize itself +*/ +class BOTAN_PUBLIC_API(2,0) SecureQueue final : public Fanout_Filter, public DataSource + { + public: + std::string name() const override { return "Queue"; } + + void write(const uint8_t[], size_t) override; + + size_t read(uint8_t[], size_t) override; + size_t peek(uint8_t[], size_t, size_t = 0) const override; + size_t get_bytes_read() const override; + + bool end_of_data() const override; + + bool empty() const; + + bool check_available(size_t n) override { return n <= size(); } + + /** + * @return number of bytes available in the queue + */ + size_t size() const; + + bool attachable() override { return false; } + + /** + * SecureQueue assignment + * @param other the queue to copy + */ + SecureQueue& operator=(const SecureQueue& other); + + /** + * SecureQueue default constructor (creates empty queue) + */ + SecureQueue(); + + /** + * SecureQueue copy constructor + * @param other the queue to copy + */ + SecureQueue(const SecureQueue& other); + + ~SecureQueue() { destroy(); } + + private: + void destroy(); + size_t m_bytes_read; + class SecureQueueNode* m_head; + class SecureQueueNode* m_tail; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/filters/threaded_fork.cpp b/comm/third_party/botan/src/lib/filters/threaded_fork.cpp new file mode 100644 index 0000000000..2d77f9fd1c --- /dev/null +++ b/comm/third_party/botan/src/lib/filters/threaded_fork.cpp @@ -0,0 +1,153 @@ +/* +* Threaded Fork +* (C) 2013 Joel Low +* 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_THREAD_UTILS) + +#include +#include +#include + +namespace Botan { + +struct Threaded_Fork_Data + { + /* + * Semaphore for indicating that there is work to be done (or to + * quit) + */ + Semaphore m_input_ready_semaphore; + + /* + * Synchronises all threads to complete processing data in lock-step. + */ + Barrier m_input_complete_barrier; + + /* + * The work that needs to be done. This should be only when the threads + * are NOT running (i.e. before notifying the work condition, after + * the input_complete_barrier has reset.) + */ + const uint8_t* m_input = nullptr; + + /* + * The length of the work that needs to be done. + */ + size_t m_input_length = 0; + }; + +/* +* Threaded_Fork constructor +*/ +Threaded_Fork::Threaded_Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : + Fork(nullptr, static_cast(0)), + m_thread_data(new Threaded_Fork_Data) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Threaded_Fork constructor +*/ +Threaded_Fork::Threaded_Fork(Filter* filters[], size_t count) : + Fork(nullptr, static_cast(0)), + m_thread_data(new Threaded_Fork_Data) + { + set_next(filters, count); + } + +Threaded_Fork::~Threaded_Fork() + { + m_thread_data->m_input = nullptr; + m_thread_data->m_input_length = 0; + + m_thread_data->m_input_ready_semaphore.release(m_threads.size()); + + for(auto& thread : m_threads) + thread->join(); + } + +std::string Threaded_Fork::name() const + { + return "Threaded Fork"; + } + +void Threaded_Fork::set_next(Filter* f[], size_t n) + { + Fork::set_next(f, n); + n = m_next.size(); + + if(n < m_threads.size()) + m_threads.resize(n); + else + { + m_threads.reserve(n); + for(size_t i = m_threads.size(); i != n; ++i) + { + m_threads.push_back( + std::shared_ptr( + new std::thread( + std::bind(&Threaded_Fork::thread_entry, this, m_next[i])))); + } + } + } + +void Threaded_Fork::send(const uint8_t input[], size_t length) + { + if(m_write_queue.size()) + thread_delegate_work(m_write_queue.data(), m_write_queue.size()); + thread_delegate_work(input, length); + + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + nothing_attached = false; + + if(nothing_attached) + m_write_queue += std::make_pair(input, length); + else + m_write_queue.clear(); + } + +void Threaded_Fork::thread_delegate_work(const uint8_t input[], size_t length) + { + //Set the data to do. + m_thread_data->m_input = input; + m_thread_data->m_input_length = length; + + //Let the workers start processing. + m_thread_data->m_input_complete_barrier.wait(total_ports() + 1); + m_thread_data->m_input_ready_semaphore.release(total_ports()); + + //Wait for all the filters to finish processing. + m_thread_data->m_input_complete_barrier.sync(); + + //Reset the thread data + m_thread_data->m_input = nullptr; + m_thread_data->m_input_length = 0; + } + +void Threaded_Fork::thread_entry(Filter* filter) + { + while(true) + { + m_thread_data->m_input_ready_semaphore.acquire(); + + if(!m_thread_data->m_input) + break; + + filter->write(m_thread_data->m_input, m_thread_data->m_input_length); + m_thread_data->m_input_complete_barrier.sync(); + } + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/blake2/blake2b.cpp b/comm/third_party/botan/src/lib/hash/blake2/blake2b.cpp new file mode 100644 index 0000000000..0280d0c8b3 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/blake2/blake2b.cpp @@ -0,0 +1,207 @@ +/* +* BLAKE2b +* (C) 2016 cynecx +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_IVU64COUNT = 8 +}; + +const uint64_t blake2b_IV[BLAKE2B_IVU64COUNT] = { + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 +}; + +} + +BLAKE2b::BLAKE2b(size_t output_bits) : + m_output_bits(output_bits), + m_buffer(BLAKE2B_BLOCKBYTES), + m_bufpos(0), + m_H(BLAKE2B_IVU64COUNT) + { + if(output_bits == 0 || output_bits > 512 || output_bits % 8 != 0) + { + throw Invalid_Argument("Bad output bits size for BLAKE2b"); + } + + state_init(); + } + +void BLAKE2b::state_init() + { + copy_mem(m_H.data(), blake2b_IV, BLAKE2B_IVU64COUNT); + m_H[0] ^= 0x01010000 ^ static_cast(output_length()); + m_T[0] = m_T[1] = 0; + m_F[0] = m_F[1] = 0; + m_bufpos = 0; + } + +namespace { + +BOTAN_FORCE_INLINE void G(uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d, + uint64_t M0, uint64_t M1) + { + a = a + b + M0; + d = rotr<32>(d ^ a); + c = c + d; + b = rotr<24>(b ^ c); + a = a + b + M1; + d = rotr<16>(d ^ a); + c = c + d; + b = rotr<63>(b ^ c); + } + +template +BOTAN_FORCE_INLINE void ROUND(uint64_t* v, const uint64_t* M) + { + G(v[ 0], v[ 4], v[ 8], v[12], M[i0], M[i1]); + G(v[ 1], v[ 5], v[ 9], v[13], M[i2], M[i3]); + G(v[ 2], v[ 6], v[10], v[14], M[i4], M[i5]); + G(v[ 3], v[ 7], v[11], v[15], M[i6], M[i7]); + G(v[ 0], v[ 5], v[10], v[15], M[i8], M[i9]); + G(v[ 1], v[ 6], v[11], v[12], M[iA], M[iB]); + G(v[ 2], v[ 7], v[ 8], v[13], M[iC], M[iD]); + G(v[ 3], v[ 4], v[ 9], v[14], M[iE], M[iF]); + } + + +} + +void BLAKE2b::compress(const uint8_t* input, size_t blocks, uint64_t increment) + { + for(size_t b = 0; b != blocks; ++b) + { + m_T[0] += increment; + if(m_T[0] < increment) + { + m_T[1]++; + } + + uint64_t M[16]; + uint64_t v[16]; + load_le(M, input, 16); + + input += BLAKE2B_BLOCKBYTES; + + for(size_t i = 0; i < 8; i++) + v[i] = m_H[i]; + for(size_t i = 0; i != 8; ++i) + v[i + 8] = blake2b_IV[i]; + + v[12] ^= m_T[0]; + v[13] ^= m_T[1]; + v[14] ^= m_F[0]; + v[15] ^= m_F[1]; + + ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M); + ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M); + ROUND<11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4>(v, M); + ROUND< 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8>(v, M); + ROUND< 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13>(v, M); + ROUND< 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9>(v, M); + ROUND<12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11>(v, M); + ROUND<13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10>(v, M); + ROUND< 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5>(v, M); + ROUND<10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0>(v, M); + ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M); + ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M); + + for(size_t i = 0; i < 8; i++) + { + m_H[i] ^= v[i] ^ v[i + 8]; + } + } + } + +void BLAKE2b::add_data(const uint8_t input[], size_t length) + { + if(length == 0) + return; + + if(m_bufpos > 0) + { + if(m_bufpos < BLAKE2B_BLOCKBYTES) + { + const size_t take = std::min(BLAKE2B_BLOCKBYTES - m_bufpos, length); + copy_mem(&m_buffer[m_bufpos], input, take); + m_bufpos += take; + length -= take; + input += take; + } + + if(m_bufpos == m_buffer.size() && length > 0) + { + compress(m_buffer.data(), 1, BLAKE2B_BLOCKBYTES); + m_bufpos = 0; + } + } + + if(length > BLAKE2B_BLOCKBYTES) + { + const size_t full_blocks = ((length-1) / BLAKE2B_BLOCKBYTES); + compress(input, full_blocks, BLAKE2B_BLOCKBYTES); + + input += full_blocks * BLAKE2B_BLOCKBYTES; + length -= full_blocks * BLAKE2B_BLOCKBYTES; + } + + if(length > 0) + { + copy_mem(&m_buffer[m_bufpos], input, length); + m_bufpos += length; + } + } + +void BLAKE2b::final_result(uint8_t output[]) + { + if(m_bufpos != BLAKE2B_BLOCKBYTES) + clear_mem(&m_buffer[m_bufpos], BLAKE2B_BLOCKBYTES - m_bufpos); + m_F[0] = 0xFFFFFFFFFFFFFFFF; + compress(m_buffer.data(), 1, m_bufpos); + copy_out_vec_le(output, output_length(), m_H); + state_init(); + } + +std::string BLAKE2b::name() const + { + return "BLAKE2b(" + std::to_string(m_output_bits) + ")"; + } + +HashFunction* BLAKE2b::clone() const + { + return new BLAKE2b(m_output_bits); + } + +std::unique_ptr BLAKE2b::copy_state() const + { + return std::unique_ptr(new BLAKE2b(*this)); + } + +void BLAKE2b::clear() + { + zeroise(m_H); + zeroise(m_buffer); + m_bufpos = 0; + state_init(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/blake2/blake2b.h b/comm/third_party/botan/src/lib/hash/blake2/blake2b.h new file mode 100644 index 0000000000..9b0b655f25 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/blake2/blake2b.h @@ -0,0 +1,60 @@ +/* +* BLAKE2b +* (C) 2016 cynecx +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BLAKE2B_H_ +#define BOTAN_BLAKE2B_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(blake2b.h) + +namespace Botan { + +/** +* BLAKE2B +*/ +class BOTAN_PUBLIC_API(2,0) BLAKE2b final : public HashFunction + { + public: + /** + * @param output_bits the output size of BLAKE2b in bits + */ + explicit BLAKE2b(size_t output_bits = 512); + + size_t hash_block_size() const override { return 128; } + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override; + std::string name() const override; + void clear() override; + + std::unique_ptr copy_state() const override; + + private: + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + void state_init(); + void compress(const uint8_t* data, size_t blocks, uint64_t increment); + + const size_t m_output_bits; + + secure_vector m_buffer; + size_t m_bufpos; + + secure_vector m_H; + uint64_t m_T[2]; + uint64_t m_F[2]; + }; + +typedef BLAKE2b Blake2b; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/blake2/info.txt b/comm/third_party/botan/src/lib/hash/blake2/info.txt new file mode 100644 index 0000000000..b99be46015 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/blake2/info.txt @@ -0,0 +1,3 @@ + +BLAKE2B -> 20130131 + diff --git a/comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.cpp b/comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.cpp new file mode 100644 index 0000000000..329ba99a88 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.cpp @@ -0,0 +1,86 @@ +/* +* Adler32 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +void adler32_update(const uint8_t input[], size_t length, + uint16_t& S1, uint16_t& S2) + { + uint32_t S1x = S1; + uint32_t S2x = S2; + + while(length >= 16) + { + S1x += input[ 0]; S2x += S1x; + S1x += input[ 1]; S2x += S1x; + S1x += input[ 2]; S2x += S1x; + S1x += input[ 3]; S2x += S1x; + S1x += input[ 4]; S2x += S1x; + S1x += input[ 5]; S2x += S1x; + S1x += input[ 6]; S2x += S1x; + S1x += input[ 7]; S2x += S1x; + S1x += input[ 8]; S2x += S1x; + S1x += input[ 9]; S2x += S1x; + S1x += input[10]; S2x += S1x; + S1x += input[11]; S2x += S1x; + S1x += input[12]; S2x += S1x; + S1x += input[13]; S2x += S1x; + S1x += input[14]; S2x += S1x; + S1x += input[15]; S2x += S1x; + input += 16; + length -= 16; + } + + for(size_t j = 0; j != length; ++j) + { + S1x += input[j]; + S2x += S1x; + } + + S1 = S1x % 65521; + S2 = S2x % 65521; + } + +} + +/* +* Update an Adler32 Checksum +*/ +void Adler32::add_data(const uint8_t input[], size_t length) + { + const size_t PROCESS_AMOUNT = 5552; + + while(length >= PROCESS_AMOUNT) + { + adler32_update(input, PROCESS_AMOUNT, m_S1, m_S2); + input += PROCESS_AMOUNT; + length -= PROCESS_AMOUNT; + } + + adler32_update(input, length, m_S1, m_S2); + } + +/* +* Finalize an Adler32 Checksum +*/ +void Adler32::final_result(uint8_t output[]) + { + store_be(output, m_S2, m_S1); + clear(); + } + +std::unique_ptr Adler32::copy_state() const + { + return std::unique_ptr(new Adler32(*this)); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.h b/comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.h new file mode 100644 index 0000000000..cd84a7597e --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/adler32/adler32.h @@ -0,0 +1,40 @@ +/* +* Adler32 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ADLER32_H_ +#define BOTAN_ADLER32_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(adler32.h) + +namespace Botan { + +/** +* The Adler32 checksum, used in zlib +*/ +class BOTAN_PUBLIC_API(2,0) Adler32 final : public HashFunction + { + public: + std::string name() const override { return "Adler32"; } + size_t output_length() const override { return 4; } + HashFunction* clone() const override { return new Adler32; } + std::unique_ptr copy_state() const override; + + void clear() override { m_S1 = 1; m_S2 = 0; } + + Adler32() { clear(); } + ~Adler32() { clear(); } + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + uint16_t m_S1, m_S2; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/checksum/adler32/info.txt b/comm/third_party/botan/src/lib/hash/checksum/adler32/info.txt new file mode 100644 index 0000000000..4ddcb2e08b --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/adler32/info.txt @@ -0,0 +1,3 @@ + +ADLER32 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.cpp b/comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.cpp new file mode 100644 index 0000000000..cfec0471c2 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.cpp @@ -0,0 +1,252 @@ +/* +* CRC24 +* (C) 1999-2007 Jack Lloyd +* (C) 2017 [Ribose Inc](https://www.ribose.com). Performed by Krzysztof Kwiatkowski. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +alignas(64) const uint32_t CRC24_T0[256] = { + 0x00000000, 0x00FB4C86, 0x000DD58A, 0x00F6990C, 0x00E1E693, 0x001AAA15, 0x00EC3319, + 0x00177F9F, 0x003981A1, 0x00C2CD27, 0x0034542B, 0x00CF18AD, 0x00D86732, 0x00232BB4, + 0x00D5B2B8, 0x002EFE3E, 0x00894EC5, 0x00720243, 0x00849B4F, 0x007FD7C9, 0x0068A856, + 0x0093E4D0, 0x00657DDC, 0x009E315A, 0x00B0CF64, 0x004B83E2, 0x00BD1AEE, 0x00465668, + 0x005129F7, 0x00AA6571, 0x005CFC7D, 0x00A7B0FB, 0x00E9D10C, 0x00129D8A, 0x00E40486, + 0x001F4800, 0x0008379F, 0x00F37B19, 0x0005E215, 0x00FEAE93, 0x00D050AD, 0x002B1C2B, + 0x00DD8527, 0x0026C9A1, 0x0031B63E, 0x00CAFAB8, 0x003C63B4, 0x00C72F32, 0x00609FC9, + 0x009BD34F, 0x006D4A43, 0x009606C5, 0x0081795A, 0x007A35DC, 0x008CACD0, 0x0077E056, + 0x00591E68, 0x00A252EE, 0x0054CBE2, 0x00AF8764, 0x00B8F8FB, 0x0043B47D, 0x00B52D71, + 0x004E61F7, 0x00D2A319, 0x0029EF9F, 0x00DF7693, 0x00243A15, 0x0033458A, 0x00C8090C, + 0x003E9000, 0x00C5DC86, 0x00EB22B8, 0x00106E3E, 0x00E6F732, 0x001DBBB4, 0x000AC42B, + 0x00F188AD, 0x000711A1, 0x00FC5D27, 0x005BEDDC, 0x00A0A15A, 0x00563856, 0x00AD74D0, + 0x00BA0B4F, 0x004147C9, 0x00B7DEC5, 0x004C9243, 0x00626C7D, 0x009920FB, 0x006FB9F7, + 0x0094F571, 0x00838AEE, 0x0078C668, 0x008E5F64, 0x007513E2, 0x003B7215, 0x00C03E93, + 0x0036A79F, 0x00CDEB19, 0x00DA9486, 0x0021D800, 0x00D7410C, 0x002C0D8A, 0x0002F3B4, + 0x00F9BF32, 0x000F263E, 0x00F46AB8, 0x00E31527, 0x001859A1, 0x00EEC0AD, 0x00158C2B, + 0x00B23CD0, 0x00497056, 0x00BFE95A, 0x0044A5DC, 0x0053DA43, 0x00A896C5, 0x005E0FC9, + 0x00A5434F, 0x008BBD71, 0x0070F1F7, 0x008668FB, 0x007D247D, 0x006A5BE2, 0x00911764, + 0x00678E68, 0x009CC2EE, 0x00A44733, 0x005F0BB5, 0x00A992B9, 0x0052DE3F, 0x0045A1A0, + 0x00BEED26, 0x0048742A, 0x00B338AC, 0x009DC692, 0x00668A14, 0x00901318, 0x006B5F9E, + 0x007C2001, 0x00876C87, 0x0071F58B, 0x008AB90D, 0x002D09F6, 0x00D64570, 0x0020DC7C, + 0x00DB90FA, 0x00CCEF65, 0x0037A3E3, 0x00C13AEF, 0x003A7669, 0x00148857, 0x00EFC4D1, + 0x00195DDD, 0x00E2115B, 0x00F56EC4, 0x000E2242, 0x00F8BB4E, 0x0003F7C8, 0x004D963F, + 0x00B6DAB9, 0x004043B5, 0x00BB0F33, 0x00AC70AC, 0x00573C2A, 0x00A1A526, 0x005AE9A0, + 0x0074179E, 0x008F5B18, 0x0079C214, 0x00828E92, 0x0095F10D, 0x006EBD8B, 0x00982487, + 0x00636801, 0x00C4D8FA, 0x003F947C, 0x00C90D70, 0x003241F6, 0x00253E69, 0x00DE72EF, + 0x0028EBE3, 0x00D3A765, 0x00FD595B, 0x000615DD, 0x00F08CD1, 0x000BC057, 0x001CBFC8, + 0x00E7F34E, 0x00116A42, 0x00EA26C4, 0x0076E42A, 0x008DA8AC, 0x007B31A0, 0x00807D26, + 0x009702B9, 0x006C4E3F, 0x009AD733, 0x00619BB5, 0x004F658B, 0x00B4290D, 0x0042B001, + 0x00B9FC87, 0x00AE8318, 0x0055CF9E, 0x00A35692, 0x00581A14, 0x00FFAAEF, 0x0004E669, + 0x00F27F65, 0x000933E3, 0x001E4C7C, 0x00E500FA, 0x001399F6, 0x00E8D570, 0x00C62B4E, + 0x003D67C8, 0x00CBFEC4, 0x0030B242, 0x0027CDDD, 0x00DC815B, 0x002A1857, 0x00D154D1, + 0x009F3526, 0x006479A0, 0x0092E0AC, 0x0069AC2A, 0x007ED3B5, 0x00859F33, 0x0073063F, + 0x00884AB9, 0x00A6B487, 0x005DF801, 0x00AB610D, 0x00502D8B, 0x00475214, 0x00BC1E92, + 0x004A879E, 0x00B1CB18, 0x00167BE3, 0x00ED3765, 0x001BAE69, 0x00E0E2EF, 0x00F79D70, + 0x000CD1F6, 0x00FA48FA, 0x0001047C, 0x002FFA42, 0x00D4B6C4, 0x00222FC8, 0x00D9634E, + 0x00CE1CD1, 0x00355057, 0x00C3C95B, 0x003885DD }; + +alignas(64) const uint32_t CRC24_T1[256] = { + 0x00000000, 0x00488F66, 0x00901ECD, 0x00D891AB, 0x00DB711C, 0x0093FE7A, 0x004B6FD1, + 0x0003E0B7, 0x00B6E338, 0x00FE6C5E, 0x0026FDF5, 0x006E7293, 0x006D9224, 0x00251D42, + 0x00FD8CE9, 0x00B5038F, 0x006CC771, 0x00244817, 0x00FCD9BC, 0x00B456DA, 0x00B7B66D, + 0x00FF390B, 0x0027A8A0, 0x006F27C6, 0x00DA2449, 0x0092AB2F, 0x004A3A84, 0x0002B5E2, + 0x00015555, 0x0049DA33, 0x00914B98, 0x00D9C4FE, 0x00D88EE3, 0x00900185, 0x0048902E, + 0x00001F48, 0x0003FFFF, 0x004B7099, 0x0093E132, 0x00DB6E54, 0x006E6DDB, 0x0026E2BD, + 0x00FE7316, 0x00B6FC70, 0x00B51CC7, 0x00FD93A1, 0x0025020A, 0x006D8D6C, 0x00B44992, + 0x00FCC6F4, 0x0024575F, 0x006CD839, 0x006F388E, 0x0027B7E8, 0x00FF2643, 0x00B7A925, + 0x0002AAAA, 0x004A25CC, 0x0092B467, 0x00DA3B01, 0x00D9DBB6, 0x009154D0, 0x0049C57B, + 0x00014A1D, 0x004B5141, 0x0003DE27, 0x00DB4F8C, 0x0093C0EA, 0x0090205D, 0x00D8AF3B, + 0x00003E90, 0x0048B1F6, 0x00FDB279, 0x00B53D1F, 0x006DACB4, 0x002523D2, 0x0026C365, + 0x006E4C03, 0x00B6DDA8, 0x00FE52CE, 0x00279630, 0x006F1956, 0x00B788FD, 0x00FF079B, + 0x00FCE72C, 0x00B4684A, 0x006CF9E1, 0x00247687, 0x00917508, 0x00D9FA6E, 0x00016BC5, + 0x0049E4A3, 0x004A0414, 0x00028B72, 0x00DA1AD9, 0x009295BF, 0x0093DFA2, 0x00DB50C4, + 0x0003C16F, 0x004B4E09, 0x0048AEBE, 0x000021D8, 0x00D8B073, 0x00903F15, 0x00253C9A, + 0x006DB3FC, 0x00B52257, 0x00FDAD31, 0x00FE4D86, 0x00B6C2E0, 0x006E534B, 0x0026DC2D, + 0x00FF18D3, 0x00B797B5, 0x006F061E, 0x00278978, 0x002469CF, 0x006CE6A9, 0x00B47702, + 0x00FCF864, 0x0049FBEB, 0x0001748D, 0x00D9E526, 0x00916A40, 0x00928AF7, 0x00DA0591, + 0x0002943A, 0x004A1B5C, 0x0096A282, 0x00DE2DE4, 0x0006BC4F, 0x004E3329, 0x004DD39E, + 0x00055CF8, 0x00DDCD53, 0x00954235, 0x002041BA, 0x0068CEDC, 0x00B05F77, 0x00F8D011, + 0x00FB30A6, 0x00B3BFC0, 0x006B2E6B, 0x0023A10D, 0x00FA65F3, 0x00B2EA95, 0x006A7B3E, + 0x0022F458, 0x002114EF, 0x00699B89, 0x00B10A22, 0x00F98544, 0x004C86CB, 0x000409AD, + 0x00DC9806, 0x00941760, 0x0097F7D7, 0x00DF78B1, 0x0007E91A, 0x004F667C, 0x004E2C61, + 0x0006A307, 0x00DE32AC, 0x0096BDCA, 0x00955D7D, 0x00DDD21B, 0x000543B0, 0x004DCCD6, + 0x00F8CF59, 0x00B0403F, 0x0068D194, 0x00205EF2, 0x0023BE45, 0x006B3123, 0x00B3A088, + 0x00FB2FEE, 0x0022EB10, 0x006A6476, 0x00B2F5DD, 0x00FA7ABB, 0x00F99A0C, 0x00B1156A, + 0x006984C1, 0x00210BA7, 0x00940828, 0x00DC874E, 0x000416E5, 0x004C9983, 0x004F7934, + 0x0007F652, 0x00DF67F9, 0x0097E89F, 0x00DDF3C3, 0x00957CA5, 0x004DED0E, 0x00056268, + 0x000682DF, 0x004E0DB9, 0x00969C12, 0x00DE1374, 0x006B10FB, 0x00239F9D, 0x00FB0E36, + 0x00B38150, 0x00B061E7, 0x00F8EE81, 0x00207F2A, 0x0068F04C, 0x00B134B2, 0x00F9BBD4, + 0x00212A7F, 0x0069A519, 0x006A45AE, 0x0022CAC8, 0x00FA5B63, 0x00B2D405, 0x0007D78A, + 0x004F58EC, 0x0097C947, 0x00DF4621, 0x00DCA696, 0x009429F0, 0x004CB85B, 0x0004373D, + 0x00057D20, 0x004DF246, 0x009563ED, 0x00DDEC8B, 0x00DE0C3C, 0x0096835A, 0x004E12F1, + 0x00069D97, 0x00B39E18, 0x00FB117E, 0x002380D5, 0x006B0FB3, 0x0068EF04, 0x00206062, + 0x00F8F1C9, 0x00B07EAF, 0x0069BA51, 0x00213537, 0x00F9A49C, 0x00B12BFA, 0x00B2CB4D, + 0x00FA442B, 0x0022D580, 0x006A5AE6, 0x00DF5969, 0x0097D60F, 0x004F47A4, 0x0007C8C2, + 0x00042875, 0x004CA713, 0x009436B8, 0x00DCB9DE }; + +alignas(64) const uint32_t CRC24_T2[256] = { + 0x00000000, 0x00D70983, 0x00555F80, 0x00825603, 0x0051F286, 0x0086FB05, 0x0004AD06, + 0x00D3A485, 0x0059A88B, 0x008EA108, 0x000CF70B, 0x00DBFE88, 0x00085A0D, 0x00DF538E, + 0x005D058D, 0x008A0C0E, 0x00491C91, 0x009E1512, 0x001C4311, 0x00CB4A92, 0x0018EE17, + 0x00CFE794, 0x004DB197, 0x009AB814, 0x0010B41A, 0x00C7BD99, 0x0045EB9A, 0x0092E219, + 0x0041469C, 0x00964F1F, 0x0014191C, 0x00C3109F, 0x006974A4, 0x00BE7D27, 0x003C2B24, + 0x00EB22A7, 0x00388622, 0x00EF8FA1, 0x006DD9A2, 0x00BAD021, 0x0030DC2F, 0x00E7D5AC, + 0x006583AF, 0x00B28A2C, 0x00612EA9, 0x00B6272A, 0x00347129, 0x00E378AA, 0x00206835, + 0x00F761B6, 0x007537B5, 0x00A23E36, 0x00719AB3, 0x00A69330, 0x0024C533, 0x00F3CCB0, + 0x0079C0BE, 0x00AEC93D, 0x002C9F3E, 0x00FB96BD, 0x00283238, 0x00FF3BBB, 0x007D6DB8, + 0x00AA643B, 0x0029A4CE, 0x00FEAD4D, 0x007CFB4E, 0x00ABF2CD, 0x00785648, 0x00AF5FCB, + 0x002D09C8, 0x00FA004B, 0x00700C45, 0x00A705C6, 0x002553C5, 0x00F25A46, 0x0021FEC3, + 0x00F6F740, 0x0074A143, 0x00A3A8C0, 0x0060B85F, 0x00B7B1DC, 0x0035E7DF, 0x00E2EE5C, + 0x00314AD9, 0x00E6435A, 0x00641559, 0x00B31CDA, 0x003910D4, 0x00EE1957, 0x006C4F54, + 0x00BB46D7, 0x0068E252, 0x00BFEBD1, 0x003DBDD2, 0x00EAB451, 0x0040D06A, 0x0097D9E9, + 0x00158FEA, 0x00C28669, 0x001122EC, 0x00C62B6F, 0x00447D6C, 0x009374EF, 0x001978E1, + 0x00CE7162, 0x004C2761, 0x009B2EE2, 0x00488A67, 0x009F83E4, 0x001DD5E7, 0x00CADC64, + 0x0009CCFB, 0x00DEC578, 0x005C937B, 0x008B9AF8, 0x00583E7D, 0x008F37FE, 0x000D61FD, + 0x00DA687E, 0x00506470, 0x00876DF3, 0x00053BF0, 0x00D23273, 0x000196F6, 0x00D69F75, + 0x0054C976, 0x0083C0F5, 0x00A9041B, 0x007E0D98, 0x00FC5B9B, 0x002B5218, 0x00F8F69D, + 0x002FFF1E, 0x00ADA91D, 0x007AA09E, 0x00F0AC90, 0x0027A513, 0x00A5F310, 0x0072FA93, + 0x00A15E16, 0x00765795, 0x00F40196, 0x00230815, 0x00E0188A, 0x00371109, 0x00B5470A, + 0x00624E89, 0x00B1EA0C, 0x0066E38F, 0x00E4B58C, 0x0033BC0F, 0x00B9B001, 0x006EB982, + 0x00ECEF81, 0x003BE602, 0x00E84287, 0x003F4B04, 0x00BD1D07, 0x006A1484, 0x00C070BF, + 0x0017793C, 0x00952F3F, 0x004226BC, 0x00918239, 0x00468BBA, 0x00C4DDB9, 0x0013D43A, + 0x0099D834, 0x004ED1B7, 0x00CC87B4, 0x001B8E37, 0x00C82AB2, 0x001F2331, 0x009D7532, + 0x004A7CB1, 0x00896C2E, 0x005E65AD, 0x00DC33AE, 0x000B3A2D, 0x00D89EA8, 0x000F972B, + 0x008DC128, 0x005AC8AB, 0x00D0C4A5, 0x0007CD26, 0x00859B25, 0x005292A6, 0x00813623, + 0x00563FA0, 0x00D469A3, 0x00036020, 0x0080A0D5, 0x0057A956, 0x00D5FF55, 0x0002F6D6, + 0x00D15253, 0x00065BD0, 0x00840DD3, 0x00530450, 0x00D9085E, 0x000E01DD, 0x008C57DE, + 0x005B5E5D, 0x0088FAD8, 0x005FF35B, 0x00DDA558, 0x000AACDB, 0x00C9BC44, 0x001EB5C7, + 0x009CE3C4, 0x004BEA47, 0x00984EC2, 0x004F4741, 0x00CD1142, 0x001A18C1, 0x009014CF, + 0x00471D4C, 0x00C54B4F, 0x001242CC, 0x00C1E649, 0x0016EFCA, 0x0094B9C9, 0x0043B04A, + 0x00E9D471, 0x003EDDF2, 0x00BC8BF1, 0x006B8272, 0x00B826F7, 0x006F2F74, 0x00ED7977, + 0x003A70F4, 0x00B07CFA, 0x00677579, 0x00E5237A, 0x00322AF9, 0x00E18E7C, 0x003687FF, + 0x00B4D1FC, 0x0063D87F, 0x00A0C8E0, 0x0077C163, 0x00F59760, 0x00229EE3, 0x00F13A66, + 0x002633E5, 0x00A465E6, 0x00736C65, 0x00F9606B, 0x002E69E8, 0x00AC3FEB, 0x007B3668, + 0x00A892ED, 0x007F9B6E, 0x00FDCD6D, 0x002AC4EE }; + +alignas(64) const uint32_t CRC24_T3[256] = { + 0x00000000, 0x00520936, 0x00A4126C, 0x00F61B5A, 0x004825D8, 0x001A2CEE, 0x00EC37B4, + 0x00BE3E82, 0x006B0636, 0x00390F00, 0x00CF145A, 0x009D1D6C, 0x002323EE, 0x00712AD8, + 0x00873182, 0x00D538B4, 0x00D60C6C, 0x0084055A, 0x00721E00, 0x00201736, 0x009E29B4, + 0x00CC2082, 0x003A3BD8, 0x006832EE, 0x00BD0A5A, 0x00EF036C, 0x00191836, 0x004B1100, + 0x00F52F82, 0x00A726B4, 0x00513DEE, 0x000334D8, 0x00AC19D8, 0x00FE10EE, 0x00080BB4, + 0x005A0282, 0x00E43C00, 0x00B63536, 0x00402E6C, 0x0012275A, 0x00C71FEE, 0x009516D8, + 0x00630D82, 0x003104B4, 0x008F3A36, 0x00DD3300, 0x002B285A, 0x0079216C, 0x007A15B4, + 0x00281C82, 0x00DE07D8, 0x008C0EEE, 0x0032306C, 0x0060395A, 0x00962200, 0x00C42B36, + 0x00111382, 0x00431AB4, 0x00B501EE, 0x00E708D8, 0x0059365A, 0x000B3F6C, 0x00FD2436, + 0x00AF2D00, 0x00A37F36, 0x00F17600, 0x00076D5A, 0x0055646C, 0x00EB5AEE, 0x00B953D8, + 0x004F4882, 0x001D41B4, 0x00C87900, 0x009A7036, 0x006C6B6C, 0x003E625A, 0x00805CD8, + 0x00D255EE, 0x00244EB4, 0x00764782, 0x0075735A, 0x00277A6C, 0x00D16136, 0x00836800, + 0x003D5682, 0x006F5FB4, 0x009944EE, 0x00CB4DD8, 0x001E756C, 0x004C7C5A, 0x00BA6700, + 0x00E86E36, 0x005650B4, 0x00045982, 0x00F242D8, 0x00A04BEE, 0x000F66EE, 0x005D6FD8, + 0x00AB7482, 0x00F97DB4, 0x00474336, 0x00154A00, 0x00E3515A, 0x00B1586C, 0x006460D8, + 0x003669EE, 0x00C072B4, 0x00927B82, 0x002C4500, 0x007E4C36, 0x0088576C, 0x00DA5E5A, + 0x00D96A82, 0x008B63B4, 0x007D78EE, 0x002F71D8, 0x00914F5A, 0x00C3466C, 0x00355D36, + 0x00675400, 0x00B26CB4, 0x00E06582, 0x00167ED8, 0x004477EE, 0x00FA496C, 0x00A8405A, + 0x005E5B00, 0x000C5236, 0x0046FF6C, 0x0014F65A, 0x00E2ED00, 0x00B0E436, 0x000EDAB4, + 0x005CD382, 0x00AAC8D8, 0x00F8C1EE, 0x002DF95A, 0x007FF06C, 0x0089EB36, 0x00DBE200, + 0x0065DC82, 0x0037D5B4, 0x00C1CEEE, 0x0093C7D8, 0x0090F300, 0x00C2FA36, 0x0034E16C, + 0x0066E85A, 0x00D8D6D8, 0x008ADFEE, 0x007CC4B4, 0x002ECD82, 0x00FBF536, 0x00A9FC00, + 0x005FE75A, 0x000DEE6C, 0x00B3D0EE, 0x00E1D9D8, 0x0017C282, 0x0045CBB4, 0x00EAE6B4, + 0x00B8EF82, 0x004EF4D8, 0x001CFDEE, 0x00A2C36C, 0x00F0CA5A, 0x0006D100, 0x0054D836, + 0x0081E082, 0x00D3E9B4, 0x0025F2EE, 0x0077FBD8, 0x00C9C55A, 0x009BCC6C, 0x006DD736, + 0x003FDE00, 0x003CEAD8, 0x006EE3EE, 0x0098F8B4, 0x00CAF182, 0x0074CF00, 0x0026C636, + 0x00D0DD6C, 0x0082D45A, 0x0057ECEE, 0x0005E5D8, 0x00F3FE82, 0x00A1F7B4, 0x001FC936, + 0x004DC000, 0x00BBDB5A, 0x00E9D26C, 0x00E5805A, 0x00B7896C, 0x00419236, 0x00139B00, + 0x00ADA582, 0x00FFACB4, 0x0009B7EE, 0x005BBED8, 0x008E866C, 0x00DC8F5A, 0x002A9400, + 0x00789D36, 0x00C6A3B4, 0x0094AA82, 0x0062B1D8, 0x0030B8EE, 0x00338C36, 0x00618500, + 0x00979E5A, 0x00C5976C, 0x007BA9EE, 0x0029A0D8, 0x00DFBB82, 0x008DB2B4, 0x00588A00, + 0x000A8336, 0x00FC986C, 0x00AE915A, 0x0010AFD8, 0x0042A6EE, 0x00B4BDB4, 0x00E6B482, + 0x00499982, 0x001B90B4, 0x00ED8BEE, 0x00BF82D8, 0x0001BC5A, 0x0053B56C, 0x00A5AE36, + 0x00F7A700, 0x00229FB4, 0x00709682, 0x00868DD8, 0x00D484EE, 0x006ABA6C, 0x0038B35A, + 0x00CEA800, 0x009CA136, 0x009F95EE, 0x00CD9CD8, 0x003B8782, 0x00698EB4, 0x00D7B036, + 0x0085B900, 0x0073A25A, 0x0021AB6C, 0x00F493D8, 0x00A69AEE, 0x005081B4, 0x00028882, + 0x00BCB600, 0x00EEBF36, 0x0018A46C, 0x004AAD5A }; + +inline uint32_t process8(uint32_t crc, uint8_t data) + { + return (crc >> 8) ^ CRC24_T0[(crc & 0xff) ^ data]; + } + +inline uint32_t process32(uint32_t crc, uint32_t word) + { + crc ^= word; + crc = CRC24_T3[(crc >> 0) & 0xff] + ^ CRC24_T2[(crc >> 8) & 0xff] + ^ CRC24_T1[(crc >> 16) & 0xff] + ^ CRC24_T0[(crc >> 24) & 0xff]; + return crc; + } +} + +std::unique_ptr CRC24::copy_state() const + { + return std::unique_ptr(new CRC24(*this)); + } + +/* +* Update a CRC24 Checksum +* +* Implementation uses Slicing-by-N algorithm described in +* "Novel Table Lookup-Based Algorithms for High-Performance +* CRC Generation", by M.Kounavis. +* +* This algorithm uses 4 precomputed look-up tables. First +* table T0 is computed same way as in a method proposed +* by D. Sarwate (1988). Then T_1, T2 and T3 are computed +* in following way: +* +* T1[j] = (T0[j] >> 8) ^ T0[ T0[j] & 0xFF ] +* T2[j] = (T1[j] >> 8) ^ T0[ T1[j] & 0xFF ] +* T3[j] = (T2[j] >> 8) ^ T0[ T2[j] & 0xFF ] +* +*/ +void CRC24::add_data(const uint8_t input[], size_t length) + { + uint32_t d[4]; + uint32_t tmp = m_crc; + + // Input is word aligned if WA & input == 0 + static const uint8_t WA = (BOTAN_MP_WORD_BITS/8) - 1; + + // Ensure input is word aligned before processing in parallel + for(;length && (reinterpret_cast(input) & WA); length--) + tmp = process8(tmp, *input++); + + while(length >= 16) + { + load_le(d, input, 4); + tmp = process32(tmp, d[0]); + tmp = process32(tmp, d[1]); + tmp = process32(tmp, d[2]); + tmp = process32(tmp, d[3]); + + input += 16; + length -= 16; + } + + while(length--) + tmp = process8(tmp, *input++); + + m_crc = tmp & 0xffffff; + } + +/* +* Finalize a CRC24 Checksum +*/ +void CRC24::final_result(uint8_t output[]) + { + output[0] = get_byte(3, m_crc); + output[1] = get_byte(2, m_crc); + output[2] = get_byte(1, m_crc); + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.h b/comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.h new file mode 100644 index 0000000000..1809740a40 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/crc24/crc24.h @@ -0,0 +1,41 @@ +/* +* CRC24 +* (C) 1999-2007 Jack Lloyd +* (C) 2017 [Ribose Inc](https://www.ribose.com). Performed by Krzysztof Kwiatkowski. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CRC24_H_ +#define BOTAN_CRC24_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(crc24.h) + +namespace Botan { + +/** +* 24-bit cyclic redundancy check +*/ +class BOTAN_PUBLIC_API(2,0) CRC24 final : public HashFunction + { + public: + std::string name() const override { return "CRC24"; } + size_t output_length() const override { return 3; } + HashFunction* clone() const override { return new CRC24; } + std::unique_ptr copy_state() const override; + + void clear() override { m_crc = 0XCE04B7L; } + + CRC24() { clear(); } + ~CRC24() { clear(); } + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + uint32_t m_crc; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/checksum/crc24/info.txt b/comm/third_party/botan/src/lib/hash/checksum/crc24/info.txt new file mode 100644 index 0000000000..3c5070cc4a --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/crc24/info.txt @@ -0,0 +1,3 @@ + +CRC24 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.cpp b/comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.cpp new file mode 100644 index 0000000000..1a76764a80 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.cpp @@ -0,0 +1,111 @@ +/* +* CRC32 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::unique_ptr CRC32::copy_state() const + { + return std::unique_ptr(new CRC32(*this)); + } + +namespace { + +const uint32_t CRC32_T0[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; + +} + +/* +* Update a CRC32 Checksum +*/ +void CRC32::add_data(const uint8_t input[], size_t length) + { + uint32_t tmp = m_crc; + while(length >= 16) + { + tmp = CRC32_T0[(tmp ^ input[ 0]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 1]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 2]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 3]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 4]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 5]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 6]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 7]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 8]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[ 9]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[10]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[11]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[12]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[13]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[14]) & 0xFF] ^ (tmp >> 8); + tmp = CRC32_T0[(tmp ^ input[15]) & 0xFF] ^ (tmp >> 8); + input += 16; + length -= 16; + } + + for(size_t i = 0; i != length; ++i) + tmp = CRC32_T0[(tmp ^ input[i]) & 0xFF] ^ (tmp >> 8); + + m_crc = tmp; + } + +/* +* Finalize a CRC32 Checksum +*/ +void CRC32::final_result(uint8_t output[]) + { + m_crc ^= 0xFFFFFFFF; + store_be(m_crc, output); + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.h b/comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.h new file mode 100644 index 0000000000..f712b42cac --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/crc32/crc32.h @@ -0,0 +1,40 @@ +/* +* CRC32 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CRC32_H_ +#define BOTAN_CRC32_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(crc32.h) + +namespace Botan { + +/** +* 32-bit cyclic redundancy check +*/ +class BOTAN_PUBLIC_API(2,0) CRC32 final : public HashFunction + { + public: + std::string name() const override { return "CRC32"; } + size_t output_length() const override { return 4; } + HashFunction* clone() const override { return new CRC32; } + std::unique_ptr copy_state() const override; + + void clear() override { m_crc = 0xFFFFFFFF; } + + CRC32() { clear(); } + ~CRC32() { clear(); } + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + uint32_t m_crc; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/checksum/crc32/info.txt b/comm/third_party/botan/src/lib/hash/checksum/crc32/info.txt new file mode 100644 index 0000000000..7d3e452398 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/crc32/info.txt @@ -0,0 +1,3 @@ + +CRC32 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/hash/checksum/info.txt b/comm/third_party/botan/src/lib/hash/checksum/info.txt new file mode 100644 index 0000000000..5aab13b59f --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/checksum/info.txt @@ -0,0 +1,4 @@ + + +hash + diff --git a/comm/third_party/botan/src/lib/hash/comb4p/comb4p.cpp b/comm/third_party/botan/src/lib/hash/comb4p/comb4p.cpp new file mode 100644 index 0000000000..419e00df54 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/comb4p/comb4p.cpp @@ -0,0 +1,110 @@ +/* +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +void comb4p_round(secure_vector& out, + const secure_vector& in, + uint8_t round_no, + HashFunction& h1, + HashFunction& h2) + { + h1.update(round_no); + h2.update(round_no); + + h1.update(in.data(), in.size()); + h2.update(in.data(), in.size()); + + secure_vector h_buf = h1.final(); + xor_buf(out.data(), h_buf.data(), std::min(out.size(), h_buf.size())); + + h_buf = h2.final(); + xor_buf(out.data(), h_buf.data(), std::min(out.size(), h_buf.size())); + } + +} + +Comb4P::Comb4P(HashFunction* h1, HashFunction* h2) : + m_hash1(h1), m_hash2(h2) + { + if(m_hash1->name() == m_hash2->name()) + throw Invalid_Argument("Comb4P: Must use two distinct hashes"); + + if(m_hash1->output_length() != m_hash2->output_length()) + throw Invalid_Argument("Comb4P: Incompatible hashes " + + m_hash1->name() + " and " + + m_hash2->name()); + + clear(); + } + +size_t Comb4P::hash_block_size() const + { + if(m_hash1->hash_block_size() == m_hash2->hash_block_size()) + return m_hash1->hash_block_size(); + + /* + * Return LCM of the block sizes? This would probably be OK for + * HMAC, which is the main thing relying on knowing the block size. + */ + return 0; + } + +void Comb4P::clear() + { + m_hash1->clear(); + m_hash2->clear(); + + // Prep for processing next message, if any + m_hash1->update(0); + m_hash2->update(0); + } + +std::unique_ptr Comb4P::copy_state() const + { + std::unique_ptr copy(new Comb4P); + copy->m_hash1 = m_hash1->copy_state(); + copy->m_hash2 = m_hash2->copy_state(); + // work around GCC 4.8 bug + return std::unique_ptr(copy.release()); + } + +void Comb4P::add_data(const uint8_t input[], size_t length) + { + m_hash1->update(input, length); + m_hash2->update(input, length); + } + +void Comb4P::final_result(uint8_t out[]) + { + secure_vector h1 = m_hash1->final(); + secure_vector h2 = m_hash2->final(); + + // First round + xor_buf(h1.data(), h2.data(), std::min(h1.size(), h2.size())); + + // Second round + comb4p_round(h2, h1, 1, *m_hash1, *m_hash2); + + // Third round + comb4p_round(h1, h2, 2, *m_hash1, *m_hash2); + + copy_mem(out , h1.data(), h1.size()); + copy_mem(out + h1.size(), h2.data(), h2.size()); + + // Prep for processing next message, if any + m_hash1->update(0); + m_hash2->update(0); + } + +} + diff --git a/comm/third_party/botan/src/lib/hash/comb4p/comb4p.h b/comm/third_party/botan/src/lib/hash/comb4p/comb4p.h new file mode 100644 index 0000000000..518314c17d --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/comb4p/comb4p.h @@ -0,0 +1,61 @@ +/* +* Comb4P hash combiner +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_COMB4P_H_ +#define BOTAN_COMB4P_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(comb4p.h) + +namespace Botan { + +/** +* Combines two hash functions using a Feistel scheme. Described in +* "On the Security of Hash Function Combiners", Anja Lehmann +*/ +class BOTAN_PUBLIC_API(2,0) Comb4P final : public HashFunction + { + public: + /** + * @param h1 the first hash + * @param h2 the second hash + */ + Comb4P(HashFunction* h1, HashFunction* h2); + + size_t hash_block_size() const override; + + size_t output_length() const override + { + return m_hash1->output_length() + m_hash2->output_length(); + } + + HashFunction* clone() const override + { + return new Comb4P(m_hash1->clone(), m_hash2->clone()); + } + + std::unique_ptr copy_state() const override; + + std::string name() const override + { + return "Comb4P(" + m_hash1->name() + "," + m_hash2->name() + ")"; + } + + void clear() override; + private: + Comb4P() = default; + + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + std::unique_ptr m_hash1, m_hash2; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/comb4p/info.txt b/comm/third_party/botan/src/lib/hash/comb4p/info.txt new file mode 100644 index 0000000000..1bfac599ed --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/comb4p/info.txt @@ -0,0 +1,3 @@ + +COMB4P -> 20131128 + diff --git a/comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.cpp b/comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.cpp new file mode 100644 index 0000000000..e3bcd21102 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.cpp @@ -0,0 +1,248 @@ +/* +* GOST 34.11 +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/** +* GOST 34.11 Constructor +*/ +GOST_34_11::GOST_34_11() : + m_cipher(GOST_28147_89_Params("R3411_CryptoPro")), + m_buffer(32), + m_sum(32), + m_hash(32) + { + m_count = 0; + m_position = 0; + } + +void GOST_34_11::clear() + { + m_cipher.clear(); + zeroise(m_sum); + zeroise(m_hash); + m_count = 0; + m_position = 0; + } + +std::unique_ptr GOST_34_11::copy_state() const + { + return std::unique_ptr(new GOST_34_11(*this)); + } + +/** +* Hash additional inputs +*/ +void GOST_34_11::add_data(const uint8_t input[], size_t length) + { + m_count += length; + + if(m_position) + { + buffer_insert(m_buffer, m_position, input, length); + + if(m_position + length >= hash_block_size()) + { + compress_n(m_buffer.data(), 1); + input += (hash_block_size() - m_position); + length -= (hash_block_size() - m_position); + m_position = 0; + } + } + + const size_t full_blocks = length / hash_block_size(); + const size_t remaining = length % hash_block_size(); + + if(full_blocks) + compress_n(input, full_blocks); + + buffer_insert(m_buffer, m_position, input + full_blocks * hash_block_size(), remaining); + m_position += remaining; + } + +/** +* The GOST 34.11 compression function +*/ +void GOST_34_11::compress_n(const uint8_t input[], size_t blocks) + { + for(size_t i = 0; i != blocks; ++i) + { + for(uint16_t j = 0, carry = 0; j != 32; ++j) + { + uint16_t s = m_sum[j] + input[32*i+j] + carry; + carry = get_byte(0, s); + m_sum[j] = get_byte(1, s); + } + + uint8_t S[32] = { 0 }; + + uint64_t U[4], V[4]; + load_be(U, m_hash.data(), 4); + load_be(V, input + 32*i, 4); + + for(size_t j = 0; j != 4; ++j) + { + uint8_t key[32] = { 0 }; + + // P transformation + for(size_t k = 0; k != 4; ++k) + { + const uint64_t UVk = U[k] ^ V[k]; + for(size_t l = 0; l != 8; ++l) + key[4*l+k] = get_byte(l, UVk); + } + + m_cipher.set_key(key, 32); + m_cipher.encrypt(&m_hash[8*j], S + 8*j); + + if(j == 3) + break; + + // A(x) + uint64_t A_U = U[0]; + U[0] = U[1]; + U[1] = U[2]; + U[2] = U[3]; + U[3] = U[0] ^ A_U; + + if(j == 1) // C_3 + { + U[0] ^= 0x00FF00FF00FF00FF; + U[1] ^= 0xFF00FF00FF00FF00; + U[2] ^= 0x00FFFF00FF0000FF; + U[3] ^= 0xFF000000FFFF00FF; + } + + // A(A(x)) + uint64_t AA_V_1 = V[0] ^ V[1]; + uint64_t AA_V_2 = V[1] ^ V[2]; + V[0] = V[2]; + V[1] = V[3]; + V[2] = AA_V_1; + V[3] = AA_V_2; + } + + uint8_t S2[32] = { 0 }; + + // 12 rounds of psi + S2[ 0] = S[24]; + S2[ 1] = S[25]; + S2[ 2] = S[26]; + S2[ 3] = S[27]; + S2[ 4] = S[28]; + S2[ 5] = S[29]; + S2[ 6] = S[30]; + S2[ 7] = S[31]; + S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30]; + S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31]; + S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30]; + S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31]; + S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28]; + S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29]; + S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30]; + S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31]; + S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28]; + S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29]; + S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30]; + S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31]; + S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30]; + S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31]; + S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26]; + S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27]; + S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28]; + S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29]; + S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; + S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; + S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28]; + S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29]; + + xor_buf(S, S2, input + 32*i, 32); + + S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30]; + S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31]; + + copy_mem(S, S+2, 30); + S[30] = S2[0]; + S[31] = S2[1]; + + xor_buf(S, m_hash.data(), 32); + + // 61 rounds of psi + S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; + S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; + S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28]; + S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29]; + S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30]; + S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31]; + S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30]; + S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31]; + S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28]; + S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29]; + S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30]; + S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31]; + S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24]; + S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25]; + S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26]; + S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27]; + S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28]; + S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29]; + S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30]; + S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31]; + S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^ + S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; + S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^ + S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; + S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^ + S[24] ^ S[26] ^ S[28]; + S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^ + S[25] ^ S[27] ^ S[29]; + S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^ + S[26] ^ S[28] ^ S[30]; + S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^ + S[27] ^ S[29] ^ S[31]; + S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28]; + S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29]; + S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30]; + S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31]; + + copy_mem(m_hash.data(), S2, 32); + } + } + +/** +* Produce the final GOST 34.11 output +*/ +void GOST_34_11::final_result(uint8_t out[]) + { + if(m_position) + { + clear_mem(m_buffer.data() + m_position, m_buffer.size() - m_position); + compress_n(m_buffer.data(), 1); + } + + secure_vector length_buf(32); + const uint64_t bit_count = m_count * 8; + store_le(bit_count, length_buf.data()); + + secure_vector sum_buf = m_sum; + + compress_n(length_buf.data(), 1); + compress_n(sum_buf.data(), 1); + + copy_mem(out, m_hash.data(), 32); + + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.h b/comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.h new file mode 100644 index 0000000000..51d7aa4777 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/gost_3411/gost_3411.h @@ -0,0 +1,47 @@ +/* +* GOST 34.11 +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_GOST_3411_H_ +#define BOTAN_GOST_3411_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(gost_3411.h) + +namespace Botan { + +/** +* GOST 34.11 +*/ +class BOTAN_PUBLIC_API(2,0) GOST_34_11 final : public HashFunction + { + public: + std::string name() const override { return "GOST-R-34.11-94" ; } + size_t output_length() const override { return 32; } + size_t hash_block_size() const override { return 32; } + HashFunction* clone() const override { return new GOST_34_11; } + std::unique_ptr copy_state() const override; + + void clear() override; + + GOST_34_11(); + private: + void compress_n(const uint8_t input[], size_t blocks); + + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + + GOST_28147_89 m_cipher; + secure_vector m_buffer, m_sum, m_hash; + size_t m_position; + uint64_t m_count; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/gost_3411/info.txt b/comm/third_party/botan/src/lib/hash/gost_3411/info.txt new file mode 100644 index 0000000000..31749c3022 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/gost_3411/info.txt @@ -0,0 +1,7 @@ + +GOST_34_11 -> 20131128 + + + +gost_28147 + diff --git a/comm/third_party/botan/src/lib/hash/hash.cpp b/comm/third_party/botan/src/lib/hash/hash.cpp new file mode 100644 index 0000000000..63218006c9 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/hash.cpp @@ -0,0 +1,360 @@ +/* +* Hash Functions +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_ADLER32) + #include +#endif + +#if defined(BOTAN_HAS_CRC24) + #include +#endif + +#if defined(BOTAN_HAS_CRC32) + #include +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + #include +#endif + +#if defined(BOTAN_HAS_KECCAK) + #include +#endif + +#if defined(BOTAN_HAS_MD4) + #include +#endif + +#if defined(BOTAN_HAS_MD5) + #include +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + #include +#endif + +#if defined(BOTAN_HAS_SHA1) + #include +#endif + +#if defined(BOTAN_HAS_SHA2_32) + #include +#endif + +#if defined(BOTAN_HAS_SHA2_64) + #include +#endif + +#if defined(BOTAN_HAS_SHA3) + #include +#endif + +#if defined(BOTAN_HAS_SHAKE) + #include +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + #include +#endif + +#if defined(BOTAN_HAS_STREEBOG) + #include +#endif + +#if defined(BOTAN_HAS_SM3) + #include +#endif + +#if defined(BOTAN_HAS_TIGER) + #include +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + #include +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + #include +#endif + +#if defined(BOTAN_HAS_COMB4P) + #include +#endif + +#if defined(BOTAN_HAS_BLAKE2B) + #include +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +#if defined(BOTAN_HAS_COMMONCRYPTO) + #include +#endif + +namespace Botan { + +std::unique_ptr HashFunction::create(const std::string& algo_spec, + const std::string& provider) + { + +#if defined(BOTAN_HAS_COMMONCRYPTO) + if(provider.empty() || provider == "commoncrypto") + { + if(auto hash = make_commoncrypto_hash(algo_spec)) + return hash; + + if(!provider.empty()) + return nullptr; + } +#endif + +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + if(auto hash = make_openssl_hash(algo_spec)) + return hash; + + if(!provider.empty()) + return nullptr; + } +#endif + + if(provider.empty() == false && provider != "base") + return nullptr; // unknown provider + +#if defined(BOTAN_HAS_SHA1) + if(algo_spec == "SHA-160" || + algo_spec == "SHA-1" || + algo_spec == "SHA1") + { + return std::unique_ptr(new SHA_160); + } +#endif + +#if defined(BOTAN_HAS_SHA2_32) + if(algo_spec == "SHA-224") + { + return std::unique_ptr(new SHA_224); + } + + if(algo_spec == "SHA-256") + { + return std::unique_ptr(new SHA_256); + } +#endif + +#if defined(BOTAN_HAS_SHA2_64) + if(algo_spec == "SHA-384") + { + return std::unique_ptr(new SHA_384); + } + + if(algo_spec == "SHA-512") + { + return std::unique_ptr(new SHA_512); + } + + if(algo_spec == "SHA-512-256") + { + return std::unique_ptr(new SHA_512_256); + } +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + if(algo_spec == "RIPEMD-160") + { + return std::unique_ptr(new RIPEMD_160); + } +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(algo_spec == "Whirlpool") + { + return std::unique_ptr(new Whirlpool); + } +#endif + +#if defined(BOTAN_HAS_MD5) + if(algo_spec == "MD5") + { + return std::unique_ptr(new MD5); + } +#endif + +#if defined(BOTAN_HAS_MD4) + if(algo_spec == "MD4") + { + return std::unique_ptr(new MD4); + } +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + if(algo_spec == "GOST-R-34.11-94" || algo_spec == "GOST-34.11") + { + return std::unique_ptr(new GOST_34_11); + } +#endif + +#if defined(BOTAN_HAS_ADLER32) + if(algo_spec == "Adler32") + { + return std::unique_ptr(new Adler32); + } +#endif + +#if defined(BOTAN_HAS_CRC24) + if(algo_spec == "CRC24") + { + return std::unique_ptr(new CRC24); + } +#endif + +#if defined(BOTAN_HAS_CRC32) + if(algo_spec == "CRC32") + { + return std::unique_ptr(new CRC32); + } +#endif + + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_TIGER) + if(req.algo_name() == "Tiger") + { + return std::unique_ptr( + new Tiger(req.arg_as_integer(0, 24), + req.arg_as_integer(1, 3))); + } +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + if(req.algo_name() == "Skein-512") + { + return std::unique_ptr( + new Skein_512(req.arg_as_integer(0, 512), req.arg(1, ""))); + } +#endif + +#if defined(BOTAN_HAS_BLAKE2B) + if(req.algo_name() == "Blake2b" || req.algo_name() == "BLAKE2b") + { + return std::unique_ptr( + new Blake2b(req.arg_as_integer(0, 512))); + } +#endif + +#if defined(BOTAN_HAS_KECCAK) + if(req.algo_name() == "Keccak-1600") + { + return std::unique_ptr( + new Keccak_1600(req.arg_as_integer(0, 512))); + } +#endif + +#if defined(BOTAN_HAS_SHA3) + if(req.algo_name() == "SHA-3") + { + return std::unique_ptr( + new SHA_3(req.arg_as_integer(0, 512))); + } +#endif + +#if defined(BOTAN_HAS_SHAKE) + if(req.algo_name() == "SHAKE-128") + { + return std::unique_ptr(new SHAKE_128(req.arg_as_integer(0, 128))); + } + if(req.algo_name() == "SHAKE-256") + { + return std::unique_ptr(new SHAKE_256(req.arg_as_integer(0, 256))); + } +#endif + +#if defined(BOTAN_HAS_STREEBOG) + if(algo_spec == "Streebog-256") + { + return std::unique_ptr(new Streebog_256); + } + if(algo_spec == "Streebog-512") + { + return std::unique_ptr(new Streebog_512); + } +#endif + +#if defined(BOTAN_HAS_SM3) + if(algo_spec == "SM3") + { + return std::unique_ptr(new SM3); + } +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(req.algo_name() == "Whirlpool") + { + return std::unique_ptr(new Whirlpool); + } +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + if(req.algo_name() == "Parallel") + { + std::vector> hashes; + + for(size_t i = 0; i != req.arg_count(); ++i) + { + auto h = HashFunction::create(req.arg(i)); + if(!h) + { + return nullptr; + } + hashes.push_back(std::move(h)); + } + + return std::unique_ptr(new Parallel(hashes)); + } +#endif + +#if defined(BOTAN_HAS_COMB4P) + if(req.algo_name() == "Comb4P" && req.arg_count() == 2) + { + std::unique_ptr h1(HashFunction::create(req.arg(0))); + std::unique_ptr h2(HashFunction::create(req.arg(1))); + + if(h1 && h2) + return std::unique_ptr(new Comb4P(h1.release(), h2.release())); + } +#endif + + + return nullptr; + } + +//static +std::unique_ptr +HashFunction::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto hash = HashFunction::create(algo, provider)) + { + return hash; + } + throw Lookup_Error("Hash", algo, provider); + } + +std::vector HashFunction::providers(const std::string& algo_spec) + { + return probe_providers_of(algo_spec, {"base", "openssl", "commoncrypto"}); + } + +} + diff --git a/comm/third_party/botan/src/lib/hash/hash.h b/comm/third_party/botan/src/lib/hash/hash.h new file mode 100644 index 0000000000..8c6440e650 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/hash.h @@ -0,0 +1,91 @@ +/* +* Hash Function Base Class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HASH_FUNCTION_BASE_CLASS_H_ +#define BOTAN_HASH_FUNCTION_BASE_CLASS_H_ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents hash function (message digest) objects +*/ +class BOTAN_PUBLIC_API(2,0) HashFunction : public Buffered_Computation + { + public: + /** + * Create an instance based on a name, or return null if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws Lookup_Error if not found. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector providers(const std::string& algo_spec); + + /** + * @return new object representing the same algorithm as *this + */ + virtual HashFunction* clone() const = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + virtual ~HashFunction() = default; + + /** + * Reset the state. + */ + virtual void clear() = 0; + + /** + * @return the hash function name + */ + virtual std::string name() const = 0; + + /** + * @return hash block size as defined for this algorithm + */ + virtual size_t hash_block_size() const { return 0; } + + /** + * Return a new hash object with the same state as *this. This + * allows computing the hash of several messages with a common + * prefix more efficiently than would otherwise be possible. + * + * This function should be called `clone` but that was already + * used for the case of returning an uninitialized object. + * @return new hash object + */ + virtual std::unique_ptr copy_state() const = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/info.txt b/comm/third_party/botan/src/lib/hash/info.txt new file mode 100644 index 0000000000..8d38170589 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/info.txt @@ -0,0 +1,7 @@ + +HASH -> 20180112 + + + +hash.h + diff --git a/comm/third_party/botan/src/lib/hash/keccak/info.txt b/comm/third_party/botan/src/lib/hash/keccak/info.txt new file mode 100644 index 0000000000..6f7345af87 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/keccak/info.txt @@ -0,0 +1,7 @@ + +KECCAK -> 20131128 + + + +sha3 + diff --git a/comm/third_party/botan/src/lib/hash/keccak/keccak.cpp b/comm/third_party/botan/src/lib/hash/keccak/keccak.cpp new file mode 100644 index 0000000000..b8196495c6 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/keccak/keccak.cpp @@ -0,0 +1,68 @@ +/* +* Keccak +* (C) 2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +std::unique_ptr Keccak_1600::copy_state() const + { + return std::unique_ptr(new Keccak_1600(*this)); + } + +Keccak_1600::Keccak_1600(size_t output_bits) : + m_output_bits(output_bits), + m_bitrate(1600 - 2*output_bits), + m_S(25), + m_S_pos(0) + { + // We only support the parameters for the SHA-3 proposal + + if(output_bits != 224 && output_bits != 256 && + output_bits != 384 && output_bits != 512) + throw Invalid_Argument("Keccak_1600: Invalid output length " + + std::to_string(output_bits)); + } + +std::string Keccak_1600::name() const + { + return "Keccak-1600(" + std::to_string(m_output_bits) + ")"; + } + +HashFunction* Keccak_1600::clone() const + { + return new Keccak_1600(m_output_bits); + } + +void Keccak_1600::clear() + { + zeroise(m_S); + m_S_pos = 0; + } + +void Keccak_1600::add_data(const uint8_t input[], size_t length) + { + m_S_pos = SHA_3::absorb(m_bitrate, m_S, m_S_pos, input, length); + } + +void Keccak_1600::final_result(uint8_t output[]) + { + SHA_3::finish(m_bitrate, m_S, m_S_pos, 0x01, 0x80); + + /* + * We never have to run the permutation again because we only support + * limited output lengths + */ + copy_out_vec_le(output, m_output_bits/8, m_S); + + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/keccak/keccak.h b/comm/third_party/botan/src/lib/hash/keccak/keccak.h new file mode 100644 index 0000000000..083d7fc5a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/keccak/keccak.h @@ -0,0 +1,51 @@ +/* +* Keccak +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KECCAK_H_ +#define BOTAN_KECCAK_H_ + +#include +#include +#include + +namespace Botan { + +BOTAN_FUTURE_INTERNAL_HEADER(keccak.h) + +/** +* Keccak[1600], a SHA-3 candidate +*/ +class BOTAN_PUBLIC_API(2,0) Keccak_1600 final : public HashFunction + { + public: + + /** + * @param output_bits the size of the hash output; must be one of + * 224, 256, 384, or 512 + */ + explicit Keccak_1600(size_t output_bits = 512); + + size_t hash_block_size() const override { return m_bitrate / 8; } + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override; + std::unique_ptr copy_state() const override; + std::string name() const override; + void clear() override; + + private: + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + size_t m_output_bits, m_bitrate; + secure_vector m_S; + size_t m_S_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/md4/info.txt b/comm/third_party/botan/src/lib/hash/md4/info.txt new file mode 100644 index 0000000000..fde5168adf --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/md4/info.txt @@ -0,0 +1,7 @@ + +MD4 -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/md4/md4.cpp b/comm/third_party/botan/src/lib/hash/md4/md4.cpp new file mode 100644 index 0000000000..9cc92e1e38 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/md4/md4.cpp @@ -0,0 +1,144 @@ +/* +* MD4 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +std::unique_ptr MD4::copy_state() const + { + return std::unique_ptr(new MD4(*this)); + } + +namespace { + +inline void FF4(uint32_t& A, uint32_t& B, uint32_t& C, uint32_t& D, + uint32_t M0, uint32_t M1, uint32_t M2, uint32_t M3) + + { + A += (D ^ (B & (C ^ D))) + M0; + A = rotl<3>(A); + + D += (C ^ (A & (B ^ C))) + M1; + D = rotl<7>(D); + + C += (B ^ (D & (A ^ B))) + M2; + C = rotl<11>(C); + + B += (A ^ (C & (D ^ A))) + M3; + B = rotl<19>(B); + } + +inline void GG4(uint32_t& A, uint32_t& B, uint32_t& C, uint32_t& D, + uint32_t M0, uint32_t M1, uint32_t M2, uint32_t M3) + + { + A += ((B & C) | (D & (B | C))) + M0 + 0x5A827999; + A = rotl<3>(A); + + D += ((A & B) | (C & (A | B))) + M1 + 0x5A827999; + D = rotl<5>(D); + + C += ((D & A) | (B & (D | A))) + M2 + 0x5A827999; + C = rotl<9>(C); + + B += ((C & D) | (A & (C | D))) + M3 + 0x5A827999; + B = rotl<13>(B); + } + +inline void HH4(uint32_t& A, uint32_t& B, uint32_t& C, uint32_t& D, + uint32_t M0, uint32_t M1, uint32_t M2, uint32_t M3) + + { + A += (B ^ C ^ D) + M0 + 0x6ED9EBA1; + A = rotl<3>(A); + + D += (A ^ B ^ C) + M1 + 0x6ED9EBA1; + D = rotl<9>(D); + + C += (A ^ B ^ D) + M2 + 0x6ED9EBA1; + C = rotl<11>(C); + + B += (A ^ C ^ D) + M3 + 0x6ED9EBA1; + B = rotl<15>(B); + } + +} + +/* +* MD4 Compression Function +*/ +void MD4::compress_n(const uint8_t input[], size_t blocks) + { + uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3]; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t M00 = load_le(input, 0); + uint32_t M01 = load_le(input, 1); + uint32_t M02 = load_le(input, 2); + uint32_t M03 = load_le(input, 3); + uint32_t M04 = load_le(input, 4); + uint32_t M05 = load_le(input, 5); + uint32_t M06 = load_le(input, 6); + uint32_t M07 = load_le(input, 7); + uint32_t M08 = load_le(input, 8); + uint32_t M09 = load_le(input, 9); + uint32_t M10 = load_le(input, 10); + uint32_t M11 = load_le(input, 11); + uint32_t M12 = load_le(input, 12); + uint32_t M13 = load_le(input, 13); + uint32_t M14 = load_le(input, 14); + uint32_t M15 = load_le(input, 15); + + FF4(A, B, C, D, M00, M01, M02, M03); + FF4(A, B, C, D, M04, M05, M06, M07); + FF4(A, B, C, D, M08, M09, M10, M11); + FF4(A, B, C, D, M12, M13, M14, M15); + + GG4(A, B, C, D, M00, M04, M08, M12); + GG4(A, B, C, D, M01, M05, M09, M13); + GG4(A, B, C, D, M02, M06, M10, M14); + GG4(A, B, C, D, M03, M07, M11, M15); + + HH4(A, B, C, D, M00, M08, M04, M12); + HH4(A, B, C, D, M02, M10, M06, M14); + HH4(A, B, C, D, M01, M09, M05, M13); + HH4(A, B, C, D, M03, M11, M07, M15); + + A = (m_digest[0] += A); + B = (m_digest[1] += B); + C = (m_digest[2] += C); + D = (m_digest[3] += D); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void MD4::copy_out(uint8_t output[]) + { + copy_out_vec_le(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void MD4::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + } + +} diff --git a/comm/third_party/botan/src/lib/hash/md4/md4.h b/comm/third_party/botan/src/lib/hash/md4/md4.h new file mode 100644 index 0000000000..0e6f5dc080 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/md4/md4.h @@ -0,0 +1,45 @@ +/* +* MD4 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MD4_H_ +#define BOTAN_MD4_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(md4.h) + +namespace Botan { + +/** +* MD4 +*/ +class BOTAN_PUBLIC_API(2,0) MD4 final : public MDx_HashFunction + { + public: + std::string name() const override { return "MD4"; } + size_t output_length() const override { return 16; } + HashFunction* clone() const override { return new MD4; } + std::unique_ptr copy_state() const override; + + void clear() override; + + MD4() : MDx_HashFunction(64, false, true), m_digest(4) + { clear(); } + + private: + void compress_n(const uint8_t input[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + /** + * The digest value + */ + secure_vector m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/md5/info.txt b/comm/third_party/botan/src/lib/hash/md5/info.txt new file mode 100644 index 0000000000..5e0aadec88 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/md5/info.txt @@ -0,0 +1,7 @@ + +MD5 -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/md5/md5.cpp b/comm/third_party/botan/src/lib/hash/md5/md5.cpp new file mode 100644 index 0000000000..590af4641f --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/md5/md5.cpp @@ -0,0 +1,140 @@ +/* +* MD5 +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +std::unique_ptr MD5::copy_state() const + { + return std::unique_ptr(new MD5(*this)); + } + +namespace { + +/* +* MD5 FF Function +*/ +template +inline void FF(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) + { + A += (D ^ (B & (C ^ D))) + M; + A = rotl(A) + B; + } + +/* +* MD5 GG Function +*/ +template +inline void GG(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) + { + A += (C ^ (D & (B ^ C))) + M; + A = rotl(A) + B; + } + +/* +* MD5 HH Function +*/ +template +inline void HH(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) + { + A += (B ^ C ^ D) + M; + A = rotl(A) + B; + } + +/* +* MD5 II Function +*/ +template +inline void II(uint32_t& A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) + { + A += (C ^ (B | ~D)) + M; + A = rotl(A) + B; + } + +} + +/* +* MD5 Compression Function +*/ +void MD5::compress_n(const uint8_t input[], size_t blocks) + { + uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(m_M.data(), input, m_M.size()); + + FF< 7>(A,B,C,D,m_M[ 0]+0xD76AA478); FF<12>(D,A,B,C,m_M[ 1]+0xE8C7B756); + FF<17>(C,D,A,B,m_M[ 2]+0x242070DB); FF<22>(B,C,D,A,m_M[ 3]+0xC1BDCEEE); + FF< 7>(A,B,C,D,m_M[ 4]+0xF57C0FAF); FF<12>(D,A,B,C,m_M[ 5]+0x4787C62A); + FF<17>(C,D,A,B,m_M[ 6]+0xA8304613); FF<22>(B,C,D,A,m_M[ 7]+0xFD469501); + FF< 7>(A,B,C,D,m_M[ 8]+0x698098D8); FF<12>(D,A,B,C,m_M[ 9]+0x8B44F7AF); + FF<17>(C,D,A,B,m_M[10]+0xFFFF5BB1); FF<22>(B,C,D,A,m_M[11]+0x895CD7BE); + FF< 7>(A,B,C,D,m_M[12]+0x6B901122); FF<12>(D,A,B,C,m_M[13]+0xFD987193); + FF<17>(C,D,A,B,m_M[14]+0xA679438E); FF<22>(B,C,D,A,m_M[15]+0x49B40821); + + GG< 5>(A,B,C,D,m_M[ 1]+0xF61E2562); GG< 9>(D,A,B,C,m_M[ 6]+0xC040B340); + GG<14>(C,D,A,B,m_M[11]+0x265E5A51); GG<20>(B,C,D,A,m_M[ 0]+0xE9B6C7AA); + GG< 5>(A,B,C,D,m_M[ 5]+0xD62F105D); GG< 9>(D,A,B,C,m_M[10]+0x02441453); + GG<14>(C,D,A,B,m_M[15]+0xD8A1E681); GG<20>(B,C,D,A,m_M[ 4]+0xE7D3FBC8); + GG< 5>(A,B,C,D,m_M[ 9]+0x21E1CDE6); GG< 9>(D,A,B,C,m_M[14]+0xC33707D6); + GG<14>(C,D,A,B,m_M[ 3]+0xF4D50D87); GG<20>(B,C,D,A,m_M[ 8]+0x455A14ED); + GG< 5>(A,B,C,D,m_M[13]+0xA9E3E905); GG< 9>(D,A,B,C,m_M[ 2]+0xFCEFA3F8); + GG<14>(C,D,A,B,m_M[ 7]+0x676F02D9); GG<20>(B,C,D,A,m_M[12]+0x8D2A4C8A); + + HH< 4>(A,B,C,D,m_M[ 5]+0xFFFA3942); HH<11>(D,A,B,C,m_M[ 8]+0x8771F681); + HH<16>(C,D,A,B,m_M[11]+0x6D9D6122); HH<23>(B,C,D,A,m_M[14]+0xFDE5380C); + HH< 4>(A,B,C,D,m_M[ 1]+0xA4BEEA44); HH<11>(D,A,B,C,m_M[ 4]+0x4BDECFA9); + HH<16>(C,D,A,B,m_M[ 7]+0xF6BB4B60); HH<23>(B,C,D,A,m_M[10]+0xBEBFBC70); + HH< 4>(A,B,C,D,m_M[13]+0x289B7EC6); HH<11>(D,A,B,C,m_M[ 0]+0xEAA127FA); + HH<16>(C,D,A,B,m_M[ 3]+0xD4EF3085); HH<23>(B,C,D,A,m_M[ 6]+0x04881D05); + HH< 4>(A,B,C,D,m_M[ 9]+0xD9D4D039); HH<11>(D,A,B,C,m_M[12]+0xE6DB99E5); + HH<16>(C,D,A,B,m_M[15]+0x1FA27CF8); HH<23>(B,C,D,A,m_M[ 2]+0xC4AC5665); + + II< 6>(A,B,C,D,m_M[ 0]+0xF4292244); II<10>(D,A,B,C,m_M[ 7]+0x432AFF97); + II<15>(C,D,A,B,m_M[14]+0xAB9423A7); II<21>(B,C,D,A,m_M[ 5]+0xFC93A039); + II< 6>(A,B,C,D,m_M[12]+0x655B59C3); II<10>(D,A,B,C,m_M[ 3]+0x8F0CCC92); + II<15>(C,D,A,B,m_M[10]+0xFFEFF47D); II<21>(B,C,D,A,m_M[ 1]+0x85845DD1); + II< 6>(A,B,C,D,m_M[ 8]+0x6FA87E4F); II<10>(D,A,B,C,m_M[15]+0xFE2CE6E0); + II<15>(C,D,A,B,m_M[ 6]+0xA3014314); II<21>(B,C,D,A,m_M[13]+0x4E0811A1); + II< 6>(A,B,C,D,m_M[ 4]+0xF7537E82); II<10>(D,A,B,C,m_M[11]+0xBD3AF235); + II<15>(C,D,A,B,m_M[ 2]+0x2AD7D2BB); II<21>(B,C,D,A,m_M[ 9]+0xEB86D391); + + A = (m_digest[0] += A); + B = (m_digest[1] += B); + C = (m_digest[2] += C); + D = (m_digest[3] += D); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void MD5::copy_out(uint8_t output[]) + { + copy_out_vec_le(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void MD5::clear() + { + MDx_HashFunction::clear(); + zeroise(m_M); + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + } + +} diff --git a/comm/third_party/botan/src/lib/hash/md5/md5.h b/comm/third_party/botan/src/lib/hash/md5/md5.h new file mode 100644 index 0000000000..182145523d --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/md5/md5.h @@ -0,0 +1,50 @@ +/* +* MD5 +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MD5_H_ +#define BOTAN_MD5_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(md5.h) + +namespace Botan { + +/** +* MD5 +*/ +class BOTAN_PUBLIC_API(2,0) MD5 final : public MDx_HashFunction + { + public: + std::string name() const override { return "MD5"; } + size_t output_length() const override { return 16; } + HashFunction* clone() const override { return new MD5; } + std::unique_ptr copy_state() const override; + + void clear() override; + + MD5() : MDx_HashFunction(64, false, true), m_M(16), m_digest(4) + { clear(); } + + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + /** + * The message buffer + */ + secure_vector m_M; + + /** + * The digest value + */ + secure_vector m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/mdx_hash/info.txt b/comm/third_party/botan/src/lib/hash/mdx_hash/info.txt new file mode 100644 index 0000000000..6a509f1be9 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/mdx_hash/info.txt @@ -0,0 +1,5 @@ + +MDX_HASH_FUNCTION -> 20131128 + + +load_on dep diff --git a/comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.cpp b/comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.cpp new file mode 100644 index 0000000000..64ae516a82 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.cpp @@ -0,0 +1,121 @@ +/* +* Merkle-Damgard Hash Function +* (C) 1999-2008,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* MDx_HashFunction Constructor +*/ +MDx_HashFunction::MDx_HashFunction(size_t block_len, + bool byte_big_endian, + bool bit_big_endian, + uint8_t cnt_size) : + m_pad_char(bit_big_endian == true ? 0x80 : 0x01), + m_counter_size(cnt_size), + m_block_bits(ceil_log2(block_len)), + m_count_big_endian(byte_big_endian), + m_count(0), + m_buffer(block_len), + m_position(0) + { + if(!is_power_of_2(block_len)) + throw Invalid_Argument("MDx_HashFunction block length must be a power of 2"); + if(m_block_bits < 3 || m_block_bits > 16) + throw Invalid_Argument("MDx_HashFunction block size too large or too small"); + if(m_counter_size < 8 || m_counter_size > block_len) + throw Invalid_State("MDx_HashFunction invalid counter length"); + } + +/* +* Clear memory of sensitive data +*/ +void MDx_HashFunction::clear() + { + zeroise(m_buffer); + m_count = m_position = 0; + } + +/* +* Update the hash +*/ +void MDx_HashFunction::add_data(const uint8_t input[], size_t length) + { + const size_t block_len = static_cast(1) << m_block_bits; + + m_count += length; + + if(m_position) + { + buffer_insert(m_buffer, m_position, input, length); + + if(m_position + length >= block_len) + { + compress_n(m_buffer.data(), 1); + input += (block_len - m_position); + length -= (block_len - m_position); + m_position = 0; + } + } + + // Just in case the compiler can't figure out block_len is a power of 2 + const size_t full_blocks = length >> m_block_bits; + const size_t remaining = length & (block_len - 1); + + if(full_blocks > 0) + { + compress_n(input, full_blocks); + } + + buffer_insert(m_buffer, m_position, input + full_blocks * block_len, remaining); + m_position += remaining; + } + +/* +* Finalize a hash +*/ +void MDx_HashFunction::final_result(uint8_t output[]) + { + const size_t block_len = static_cast(1) << m_block_bits; + + clear_mem(&m_buffer[m_position], block_len - m_position); + m_buffer[m_position] = m_pad_char; + + if(m_position >= block_len - m_counter_size) + { + compress_n(m_buffer.data(), 1); + zeroise(m_buffer); + } + + write_count(&m_buffer[block_len - m_counter_size]); + + compress_n(m_buffer.data(), 1); + copy_out(output); + clear(); + } + +/* +* Write the count bits to the buffer +*/ +void MDx_HashFunction::write_count(uint8_t out[]) + { + BOTAN_ASSERT_NOMSG(m_counter_size <= output_length()); + BOTAN_ASSERT_NOMSG(m_counter_size >= 8); + + const uint64_t bit_count = m_count * 8; + + if(m_count_big_endian) + store_be(bit_count, out + m_counter_size - 8); + else + store_le(bit_count, out + m_counter_size - 8); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.h b/comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.h new file mode 100644 index 0000000000..a061e9c8a3 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/mdx_hash/mdx_hash.h @@ -0,0 +1,73 @@ +/* +* MDx Hash Function +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MDX_BASE_H_ +#define BOTAN_MDX_BASE_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(mdx_hash.h) + +namespace Botan { + +/** +* MDx Hash Function Base Class +*/ +class BOTAN_PUBLIC_API(2,0) MDx_HashFunction : public HashFunction + { + public: + /** + * @param block_length is the number of bytes per block, which must + * be a power of 2 and at least 8. + * @param big_byte_endian specifies if the hash uses big-endian bytes + * @param big_bit_endian specifies if the hash uses big-endian bits + * @param counter_size specifies the size of the counter var in bytes + */ + MDx_HashFunction(size_t block_length, + bool big_byte_endian, + bool big_bit_endian, + uint8_t counter_size = 8); + + size_t hash_block_size() const override final { return m_buffer.size(); } + protected: + void add_data(const uint8_t input[], size_t length) override final; + void final_result(uint8_t output[]) override final; + + /** + * Run the hash's compression function over a set of blocks + * @param blocks the input + * @param block_n the number of blocks + */ + virtual void compress_n(const uint8_t blocks[], size_t block_n) = 0; + + void clear() override; + + /** + * Copy the output to the buffer + * @param buffer to put the output into + */ + virtual void copy_out(uint8_t buffer[]) = 0; + + /** + * Write the count, if used, to this spot + * @param out where to write the counter to + */ + virtual void write_count(uint8_t out[]); + private: + const uint8_t m_pad_char; + const uint8_t m_counter_size; + const uint8_t m_block_bits; + const bool m_count_big_endian; + + uint64_t m_count; + secure_vector m_buffer; + size_t m_position; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/par_hash/info.txt b/comm/third_party/botan/src/lib/hash/par_hash/info.txt new file mode 100644 index 0000000000..b04e0f4df1 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/par_hash/info.txt @@ -0,0 +1,3 @@ + +PARALLEL_HASH -> 20131128 + diff --git a/comm/third_party/botan/src/lib/hash/par_hash/par_hash.cpp b/comm/third_party/botan/src/lib/hash/par_hash/par_hash.cpp new file mode 100644 index 0000000000..a0297dfe85 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/par_hash/par_hash.cpp @@ -0,0 +1,86 @@ +/* +* Parallel Hash +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +void Parallel::add_data(const uint8_t input[], size_t length) + { + for(auto&& hash : m_hashes) + hash->update(input, length); + } + +void Parallel::final_result(uint8_t out[]) + { + size_t offset = 0; + + for(auto&& hash : m_hashes) + { + hash->final(out + offset); + offset += hash->output_length(); + } + } + +size_t Parallel::output_length() const + { + size_t sum = 0; + + for(auto&& hash : m_hashes) + sum += hash->output_length(); + return sum; + } + +std::string Parallel::name() const + { + std::vector names; + + for(auto&& hash : m_hashes) + names.push_back(hash->name()); + + return "Parallel(" + string_join(names, ',') + ")"; + } + +HashFunction* Parallel::clone() const + { + std::vector> hash_copies; + + for(auto&& hash : m_hashes) + hash_copies.push_back(std::unique_ptr(hash->clone())); + + return new Parallel(hash_copies); + } + +std::unique_ptr Parallel::copy_state() const + { + std::vector> hash_clones; + + for(const std::unique_ptr& hash : m_hashes) + { + hash_clones.push_back(hash->copy_state()); + } + + return std::unique_ptr(new Parallel(hash_clones)); + } + +void Parallel::clear() + { + for(auto&& hash : m_hashes) + hash->clear(); + } + +Parallel::Parallel(std::vector>& h) + { + for(size_t i = 0; i != h.size(); ++i) + { + m_hashes.push_back(std::unique_ptr(h[i].release())); + } + } + + +} diff --git a/comm/third_party/botan/src/lib/hash/par_hash/par_hash.h b/comm/third_party/botan/src/lib/hash/par_hash/par_hash.h new file mode 100644 index 0000000000..8942cfe4db --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/par_hash/par_hash.h @@ -0,0 +1,50 @@ +/* +* Parallel Hash +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PARALLEL_HASH_H_ +#define BOTAN_PARALLEL_HASH_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(par_hash.h) + +namespace Botan { + +/** +* Parallel Hashes +*/ +class BOTAN_PUBLIC_API(2,0) Parallel final : public HashFunction + { + public: + void clear() override; + std::string name() const override; + HashFunction* clone() const override; + std::unique_ptr copy_state() const override; + + size_t output_length() const override; + + /** + * @param hashes a set of hashes to compute in parallel + * Takes ownership of all pointers + */ + explicit Parallel(std::vector>& hashes); + + Parallel(const Parallel&) = delete; + Parallel& operator=(const Parallel&) = delete; + private: + Parallel() = delete; + + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + + std::vector> m_hashes; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/rmd160/info.txt b/comm/third_party/botan/src/lib/hash/rmd160/info.txt new file mode 100644 index 0000000000..53e2f993d9 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/rmd160/info.txt @@ -0,0 +1,7 @@ + +RIPEMD_160 -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/rmd160/rmd160.cpp b/comm/third_party/botan/src/lib/hash/rmd160/rmd160.cpp new file mode 100644 index 0000000000..2fa8f84d0d --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/rmd160/rmd160.cpp @@ -0,0 +1,221 @@ +/* +* RIPEMD-160 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +std::unique_ptr RIPEMD_160::copy_state() const + { + return std::unique_ptr(new RIPEMD_160(*this)); + } + +namespace { + +/* +* RIPEMD-160 F1 Function +*/ +template +inline void F1(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, + uint32_t M) + { + A += (B ^ C ^ D) + M; + A = rotl(A) + E; + C = rotl<10>(C); + } + +/* +* RIPEMD-160 F2 Function +*/ +template +inline void F2(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, + uint32_t M) + { + A += (D ^ (B & (C ^ D))) + M; + A = rotl(A) + E; + C = rotl<10>(C); + } + +/* +* RIPEMD-160 F3 Function +*/ +template +inline void F3(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, + uint32_t M) + { + A += (D ^ (B | ~C)) + M; + A = rotl(A) + E; + C = rotl<10>(C); + } + +/* +* RIPEMD-160 F4 Function +*/ +template +inline void F4(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, + uint32_t M) + { + A += (C ^ (D & (B ^ C))) + M; + A = rotl(A) + E; + C = rotl<10>(C); + } + +/* +* RIPEMD-160 F5 Function +*/ +template +inline void F5(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E, + uint32_t M) + { + A += (B ^ (C | ~D)) + M; + A = rotl(A) + E; + C = rotl<10>(C); + } + +} + +/* +* RIPEMD-160 Compression Function +*/ +void RIPEMD_160::compress_n(const uint8_t input[], size_t blocks) + { + const uint32_t MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1, + MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0xA953FD4E, + MAGIC6 = 0x50A28BE6, MAGIC7 = 0x5C4DD124, + MAGIC8 = 0x6D703EF3, MAGIC9 = 0x7A6D76E9; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(m_M.data(), input, m_M.size()); + + uint32_t A1 = m_digest[0], A2 = A1, + B1 = m_digest[1], B2 = B1, + C1 = m_digest[2], C2 = C1, + D1 = m_digest[3], D2 = D1, + E1 = m_digest[4], E2 = E1; + + F1<11>(A1,B1,C1,D1,E1,m_M[ 0] ); F5< 8>(A2,B2,C2,D2,E2,m_M[ 5]+MAGIC6); + F1<14>(E1,A1,B1,C1,D1,m_M[ 1] ); F5< 9>(E2,A2,B2,C2,D2,m_M[14]+MAGIC6); + F1<15>(D1,E1,A1,B1,C1,m_M[ 2] ); F5< 9>(D2,E2,A2,B2,C2,m_M[ 7]+MAGIC6); + F1<12>(C1,D1,E1,A1,B1,m_M[ 3] ); F5<11>(C2,D2,E2,A2,B2,m_M[ 0]+MAGIC6); + F1< 5>(B1,C1,D1,E1,A1,m_M[ 4] ); F5<13>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC6); + F1< 8>(A1,B1,C1,D1,E1,m_M[ 5] ); F5<15>(A2,B2,C2,D2,E2,m_M[ 2]+MAGIC6); + F1< 7>(E1,A1,B1,C1,D1,m_M[ 6] ); F5<15>(E2,A2,B2,C2,D2,m_M[11]+MAGIC6); + F1< 9>(D1,E1,A1,B1,C1,m_M[ 7] ); F5< 5>(D2,E2,A2,B2,C2,m_M[ 4]+MAGIC6); + F1<11>(C1,D1,E1,A1,B1,m_M[ 8] ); F5< 7>(C2,D2,E2,A2,B2,m_M[13]+MAGIC6); + F1<13>(B1,C1,D1,E1,A1,m_M[ 9] ); F5< 7>(B2,C2,D2,E2,A2,m_M[ 6]+MAGIC6); + F1<14>(A1,B1,C1,D1,E1,m_M[10] ); F5< 8>(A2,B2,C2,D2,E2,m_M[15]+MAGIC6); + F1<15>(E1,A1,B1,C1,D1,m_M[11] ); F5<11>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC6); + F1< 6>(D1,E1,A1,B1,C1,m_M[12] ); F5<14>(D2,E2,A2,B2,C2,m_M[ 1]+MAGIC6); + F1< 7>(C1,D1,E1,A1,B1,m_M[13] ); F5<14>(C2,D2,E2,A2,B2,m_M[10]+MAGIC6); + F1< 9>(B1,C1,D1,E1,A1,m_M[14] ); F5<12>(B2,C2,D2,E2,A2,m_M[ 3]+MAGIC6); + F1< 8>(A1,B1,C1,D1,E1,m_M[15] ); F5< 6>(A2,B2,C2,D2,E2,m_M[12]+MAGIC6); + + F2< 7>(E1,A1,B1,C1,D1,m_M[ 7]+MAGIC2); F4< 9>(E2,A2,B2,C2,D2,m_M[ 6]+MAGIC7); + F2< 6>(D1,E1,A1,B1,C1,m_M[ 4]+MAGIC2); F4<13>(D2,E2,A2,B2,C2,m_M[11]+MAGIC7); + F2< 8>(C1,D1,E1,A1,B1,m_M[13]+MAGIC2); F4<15>(C2,D2,E2,A2,B2,m_M[ 3]+MAGIC7); + F2<13>(B1,C1,D1,E1,A1,m_M[ 1]+MAGIC2); F4< 7>(B2,C2,D2,E2,A2,m_M[ 7]+MAGIC7); + F2<11>(A1,B1,C1,D1,E1,m_M[10]+MAGIC2); F4<12>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC7); + F2< 9>(E1,A1,B1,C1,D1,m_M[ 6]+MAGIC2); F4< 8>(E2,A2,B2,C2,D2,m_M[13]+MAGIC7); + F2< 7>(D1,E1,A1,B1,C1,m_M[15]+MAGIC2); F4< 9>(D2,E2,A2,B2,C2,m_M[ 5]+MAGIC7); + F2<15>(C1,D1,E1,A1,B1,m_M[ 3]+MAGIC2); F4<11>(C2,D2,E2,A2,B2,m_M[10]+MAGIC7); + F2< 7>(B1,C1,D1,E1,A1,m_M[12]+MAGIC2); F4< 7>(B2,C2,D2,E2,A2,m_M[14]+MAGIC7); + F2<12>(A1,B1,C1,D1,E1,m_M[ 0]+MAGIC2); F4< 7>(A2,B2,C2,D2,E2,m_M[15]+MAGIC7); + F2<15>(E1,A1,B1,C1,D1,m_M[ 9]+MAGIC2); F4<12>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC7); + F2< 9>(D1,E1,A1,B1,C1,m_M[ 5]+MAGIC2); F4< 7>(D2,E2,A2,B2,C2,m_M[12]+MAGIC7); + F2<11>(C1,D1,E1,A1,B1,m_M[ 2]+MAGIC2); F4< 6>(C2,D2,E2,A2,B2,m_M[ 4]+MAGIC7); + F2< 7>(B1,C1,D1,E1,A1,m_M[14]+MAGIC2); F4<15>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC7); + F2<13>(A1,B1,C1,D1,E1,m_M[11]+MAGIC2); F4<13>(A2,B2,C2,D2,E2,m_M[ 1]+MAGIC7); + F2<12>(E1,A1,B1,C1,D1,m_M[ 8]+MAGIC2); F4<11>(E2,A2,B2,C2,D2,m_M[ 2]+MAGIC7); + + F3<11>(D1,E1,A1,B1,C1,m_M[ 3]+MAGIC3); F3< 9>(D2,E2,A2,B2,C2,m_M[15]+MAGIC8); + F3<13>(C1,D1,E1,A1,B1,m_M[10]+MAGIC3); F3< 7>(C2,D2,E2,A2,B2,m_M[ 5]+MAGIC8); + F3< 6>(B1,C1,D1,E1,A1,m_M[14]+MAGIC3); F3<15>(B2,C2,D2,E2,A2,m_M[ 1]+MAGIC8); + F3< 7>(A1,B1,C1,D1,E1,m_M[ 4]+MAGIC3); F3<11>(A2,B2,C2,D2,E2,m_M[ 3]+MAGIC8); + F3<14>(E1,A1,B1,C1,D1,m_M[ 9]+MAGIC3); F3< 8>(E2,A2,B2,C2,D2,m_M[ 7]+MAGIC8); + F3< 9>(D1,E1,A1,B1,C1,m_M[15]+MAGIC3); F3< 6>(D2,E2,A2,B2,C2,m_M[14]+MAGIC8); + F3<13>(C1,D1,E1,A1,B1,m_M[ 8]+MAGIC3); F3< 6>(C2,D2,E2,A2,B2,m_M[ 6]+MAGIC8); + F3<15>(B1,C1,D1,E1,A1,m_M[ 1]+MAGIC3); F3<14>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC8); + F3<14>(A1,B1,C1,D1,E1,m_M[ 2]+MAGIC3); F3<12>(A2,B2,C2,D2,E2,m_M[11]+MAGIC8); + F3< 8>(E1,A1,B1,C1,D1,m_M[ 7]+MAGIC3); F3<13>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC8); + F3<13>(D1,E1,A1,B1,C1,m_M[ 0]+MAGIC3); F3< 5>(D2,E2,A2,B2,C2,m_M[12]+MAGIC8); + F3< 6>(C1,D1,E1,A1,B1,m_M[ 6]+MAGIC3); F3<14>(C2,D2,E2,A2,B2,m_M[ 2]+MAGIC8); + F3< 5>(B1,C1,D1,E1,A1,m_M[13]+MAGIC3); F3<13>(B2,C2,D2,E2,A2,m_M[10]+MAGIC8); + F3<12>(A1,B1,C1,D1,E1,m_M[11]+MAGIC3); F3<13>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC8); + F3< 7>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC3); F3< 7>(E2,A2,B2,C2,D2,m_M[ 4]+MAGIC8); + F3< 5>(D1,E1,A1,B1,C1,m_M[12]+MAGIC3); F3< 5>(D2,E2,A2,B2,C2,m_M[13]+MAGIC8); + + F4<11>(C1,D1,E1,A1,B1,m_M[ 1]+MAGIC4); F2<15>(C2,D2,E2,A2,B2,m_M[ 8]+MAGIC9); + F4<12>(B1,C1,D1,E1,A1,m_M[ 9]+MAGIC4); F2< 5>(B2,C2,D2,E2,A2,m_M[ 6]+MAGIC9); + F4<14>(A1,B1,C1,D1,E1,m_M[11]+MAGIC4); F2< 8>(A2,B2,C2,D2,E2,m_M[ 4]+MAGIC9); + F4<15>(E1,A1,B1,C1,D1,m_M[10]+MAGIC4); F2<11>(E2,A2,B2,C2,D2,m_M[ 1]+MAGIC9); + F4<14>(D1,E1,A1,B1,C1,m_M[ 0]+MAGIC4); F2<14>(D2,E2,A2,B2,C2,m_M[ 3]+MAGIC9); + F4<15>(C1,D1,E1,A1,B1,m_M[ 8]+MAGIC4); F2<14>(C2,D2,E2,A2,B2,m_M[11]+MAGIC9); + F4< 9>(B1,C1,D1,E1,A1,m_M[12]+MAGIC4); F2< 6>(B2,C2,D2,E2,A2,m_M[15]+MAGIC9); + F4< 8>(A1,B1,C1,D1,E1,m_M[ 4]+MAGIC4); F2<14>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC9); + F4< 9>(E1,A1,B1,C1,D1,m_M[13]+MAGIC4); F2< 6>(E2,A2,B2,C2,D2,m_M[ 5]+MAGIC9); + F4<14>(D1,E1,A1,B1,C1,m_M[ 3]+MAGIC4); F2< 9>(D2,E2,A2,B2,C2,m_M[12]+MAGIC9); + F4< 5>(C1,D1,E1,A1,B1,m_M[ 7]+MAGIC4); F2<12>(C2,D2,E2,A2,B2,m_M[ 2]+MAGIC9); + F4< 6>(B1,C1,D1,E1,A1,m_M[15]+MAGIC4); F2< 9>(B2,C2,D2,E2,A2,m_M[13]+MAGIC9); + F4< 8>(A1,B1,C1,D1,E1,m_M[14]+MAGIC4); F2<12>(A2,B2,C2,D2,E2,m_M[ 9]+MAGIC9); + F4< 6>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC4); F2< 5>(E2,A2,B2,C2,D2,m_M[ 7]+MAGIC9); + F4< 5>(D1,E1,A1,B1,C1,m_M[ 6]+MAGIC4); F2<15>(D2,E2,A2,B2,C2,m_M[10]+MAGIC9); + F4<12>(C1,D1,E1,A1,B1,m_M[ 2]+MAGIC4); F2< 8>(C2,D2,E2,A2,B2,m_M[14]+MAGIC9); + + F5< 9>(B1,C1,D1,E1,A1,m_M[ 4]+MAGIC5); F1< 8>(B2,C2,D2,E2,A2,m_M[12] ); + F5<15>(A1,B1,C1,D1,E1,m_M[ 0]+MAGIC5); F1< 5>(A2,B2,C2,D2,E2,m_M[15] ); + F5< 5>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC5); F1<12>(E2,A2,B2,C2,D2,m_M[10] ); + F5<11>(D1,E1,A1,B1,C1,m_M[ 9]+MAGIC5); F1< 9>(D2,E2,A2,B2,C2,m_M[ 4] ); + F5< 6>(C1,D1,E1,A1,B1,m_M[ 7]+MAGIC5); F1<12>(C2,D2,E2,A2,B2,m_M[ 1] ); + F5< 8>(B1,C1,D1,E1,A1,m_M[12]+MAGIC5); F1< 5>(B2,C2,D2,E2,A2,m_M[ 5] ); + F5<13>(A1,B1,C1,D1,E1,m_M[ 2]+MAGIC5); F1<14>(A2,B2,C2,D2,E2,m_M[ 8] ); + F5<12>(E1,A1,B1,C1,D1,m_M[10]+MAGIC5); F1< 6>(E2,A2,B2,C2,D2,m_M[ 7] ); + F5< 5>(D1,E1,A1,B1,C1,m_M[14]+MAGIC5); F1< 8>(D2,E2,A2,B2,C2,m_M[ 6] ); + F5<12>(C1,D1,E1,A1,B1,m_M[ 1]+MAGIC5); F1<13>(C2,D2,E2,A2,B2,m_M[ 2] ); + F5<13>(B1,C1,D1,E1,A1,m_M[ 3]+MAGIC5); F1< 6>(B2,C2,D2,E2,A2,m_M[13] ); + F5<14>(A1,B1,C1,D1,E1,m_M[ 8]+MAGIC5); F1< 5>(A2,B2,C2,D2,E2,m_M[14] ); + F5<11>(E1,A1,B1,C1,D1,m_M[11]+MAGIC5); F1<15>(E2,A2,B2,C2,D2,m_M[ 0] ); + F5< 8>(D1,E1,A1,B1,C1,m_M[ 6]+MAGIC5); F1<13>(D2,E2,A2,B2,C2,m_M[ 3] ); + F5< 5>(C1,D1,E1,A1,B1,m_M[15]+MAGIC5); F1<11>(C2,D2,E2,A2,B2,m_M[ 9] ); + F5< 6>(B1,C1,D1,E1,A1,m_M[13]+MAGIC5); F1<11>(B2,C2,D2,E2,A2,m_M[11] ); + + C1 = m_digest[1] + C1 + D2; + m_digest[1] = m_digest[2] + D1 + E2; + m_digest[2] = m_digest[3] + E1 + A2; + m_digest[3] = m_digest[4] + A1 + B2; + m_digest[4] = m_digest[0] + B1 + C2; + m_digest[0] = C1; + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void RIPEMD_160::copy_out(uint8_t output[]) + { + copy_out_vec_le(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void RIPEMD_160::clear() + { + MDx_HashFunction::clear(); + zeroise(m_M); + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + } + +} diff --git a/comm/third_party/botan/src/lib/hash/rmd160/rmd160.h b/comm/third_party/botan/src/lib/hash/rmd160/rmd160.h new file mode 100644 index 0000000000..2ee3116808 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/rmd160/rmd160.h @@ -0,0 +1,41 @@ +/* +* RIPEMD-160 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RIPEMD_160_H_ +#define BOTAN_RIPEMD_160_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(rmd160.h) + +namespace Botan { + +/** +* RIPEMD-160 +*/ +class BOTAN_PUBLIC_API(2,0) RIPEMD_160 final : public MDx_HashFunction + { + public: + std::string name() const override { return "RIPEMD-160"; } + size_t output_length() const override { return 20; } + HashFunction* clone() const override { return new RIPEMD_160; } + std::unique_ptr copy_state() const override; + + void clear() override; + + RIPEMD_160() : MDx_HashFunction(64, false, true), m_M(16), m_digest(5) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector m_M, m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/sha1/info.txt b/comm/third_party/botan/src/lib/hash/sha1/info.txt new file mode 100644 index 0000000000..6d326af1c9 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/info.txt @@ -0,0 +1,7 @@ + +SHA1 -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha160.cpp b/comm/third_party/botan/src/lib/hash/sha1/sha160.cpp new file mode 100644 index 0000000000..5893c5dc77 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha160.cpp @@ -0,0 +1,190 @@ +/* +* SHA-160 +* (C) 1999-2008,2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +std::unique_ptr SHA_160::copy_state() const + { + return std::unique_ptr(new SHA_160(*this)); + } + +namespace SHA1_F { + +namespace { + +/* +* SHA-160 F1 Function +*/ +inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotl<5>(A); + B = rotl<30>(B); + } + +} + +} + +/* +* SHA-160 Compression Function +*/ +void SHA_160::compress_n(const uint8_t input[], size_t blocks) + { + using namespace SHA1_F; + +#if defined(BOTAN_HAS_SHA1_X86_SHA_NI) + if(CPUID::has_intel_sha()) + { + return sha1_compress_x86(m_digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA1_ARMV8) + if(CPUID::has_arm_sha1()) + { + return sha1_armv8_compress_n(m_digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) + if(CPUID::has_sse2()) + { + return sse2_compress_n(m_digest, input, blocks); + } + +#endif + + uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], + D = m_digest[3], E = m_digest[4]; + + m_W.resize(80); + + for(size_t i = 0; i != blocks; ++i) + { + load_be(m_W.data(), input, 16); + + for(size_t j = 16; j != 80; j += 8) + { + m_W[j ] = rotl<1>(m_W[j-3] ^ m_W[j-8] ^ m_W[j-14] ^ m_W[j-16]); + m_W[j+1] = rotl<1>(m_W[j-2] ^ m_W[j-7] ^ m_W[j-13] ^ m_W[j-15]); + m_W[j+2] = rotl<1>(m_W[j-1] ^ m_W[j-6] ^ m_W[j-12] ^ m_W[j-14]); + m_W[j+3] = rotl<1>(m_W[j ] ^ m_W[j-5] ^ m_W[j-11] ^ m_W[j-13]); + m_W[j+4] = rotl<1>(m_W[j+1] ^ m_W[j-4] ^ m_W[j-10] ^ m_W[j-12]); + m_W[j+5] = rotl<1>(m_W[j+2] ^ m_W[j-3] ^ m_W[j- 9] ^ m_W[j-11]); + m_W[j+6] = rotl<1>(m_W[j+3] ^ m_W[j-2] ^ m_W[j- 8] ^ m_W[j-10]); + m_W[j+7] = rotl<1>(m_W[j+4] ^ m_W[j-1] ^ m_W[j- 7] ^ m_W[j- 9]); + } + + F1(A, B, C, D, E, m_W[ 0]); F1(E, A, B, C, D, m_W[ 1]); + F1(D, E, A, B, C, m_W[ 2]); F1(C, D, E, A, B, m_W[ 3]); + F1(B, C, D, E, A, m_W[ 4]); F1(A, B, C, D, E, m_W[ 5]); + F1(E, A, B, C, D, m_W[ 6]); F1(D, E, A, B, C, m_W[ 7]); + F1(C, D, E, A, B, m_W[ 8]); F1(B, C, D, E, A, m_W[ 9]); + F1(A, B, C, D, E, m_W[10]); F1(E, A, B, C, D, m_W[11]); + F1(D, E, A, B, C, m_W[12]); F1(C, D, E, A, B, m_W[13]); + F1(B, C, D, E, A, m_W[14]); F1(A, B, C, D, E, m_W[15]); + F1(E, A, B, C, D, m_W[16]); F1(D, E, A, B, C, m_W[17]); + F1(C, D, E, A, B, m_W[18]); F1(B, C, D, E, A, m_W[19]); + + F2(A, B, C, D, E, m_W[20]); F2(E, A, B, C, D, m_W[21]); + F2(D, E, A, B, C, m_W[22]); F2(C, D, E, A, B, m_W[23]); + F2(B, C, D, E, A, m_W[24]); F2(A, B, C, D, E, m_W[25]); + F2(E, A, B, C, D, m_W[26]); F2(D, E, A, B, C, m_W[27]); + F2(C, D, E, A, B, m_W[28]); F2(B, C, D, E, A, m_W[29]); + F2(A, B, C, D, E, m_W[30]); F2(E, A, B, C, D, m_W[31]); + F2(D, E, A, B, C, m_W[32]); F2(C, D, E, A, B, m_W[33]); + F2(B, C, D, E, A, m_W[34]); F2(A, B, C, D, E, m_W[35]); + F2(E, A, B, C, D, m_W[36]); F2(D, E, A, B, C, m_W[37]); + F2(C, D, E, A, B, m_W[38]); F2(B, C, D, E, A, m_W[39]); + + F3(A, B, C, D, E, m_W[40]); F3(E, A, B, C, D, m_W[41]); + F3(D, E, A, B, C, m_W[42]); F3(C, D, E, A, B, m_W[43]); + F3(B, C, D, E, A, m_W[44]); F3(A, B, C, D, E, m_W[45]); + F3(E, A, B, C, D, m_W[46]); F3(D, E, A, B, C, m_W[47]); + F3(C, D, E, A, B, m_W[48]); F3(B, C, D, E, A, m_W[49]); + F3(A, B, C, D, E, m_W[50]); F3(E, A, B, C, D, m_W[51]); + F3(D, E, A, B, C, m_W[52]); F3(C, D, E, A, B, m_W[53]); + F3(B, C, D, E, A, m_W[54]); F3(A, B, C, D, E, m_W[55]); + F3(E, A, B, C, D, m_W[56]); F3(D, E, A, B, C, m_W[57]); + F3(C, D, E, A, B, m_W[58]); F3(B, C, D, E, A, m_W[59]); + + F4(A, B, C, D, E, m_W[60]); F4(E, A, B, C, D, m_W[61]); + F4(D, E, A, B, C, m_W[62]); F4(C, D, E, A, B, m_W[63]); + F4(B, C, D, E, A, m_W[64]); F4(A, B, C, D, E, m_W[65]); + F4(E, A, B, C, D, m_W[66]); F4(D, E, A, B, C, m_W[67]); + F4(C, D, E, A, B, m_W[68]); F4(B, C, D, E, A, m_W[69]); + F4(A, B, C, D, E, m_W[70]); F4(E, A, B, C, D, m_W[71]); + F4(D, E, A, B, C, m_W[72]); F4(C, D, E, A, B, m_W[73]); + F4(B, C, D, E, A, m_W[74]); F4(A, B, C, D, E, m_W[75]); + F4(E, A, B, C, D, m_W[76]); F4(D, E, A, B, C, m_W[77]); + F4(C, D, E, A, B, m_W[78]); F4(B, C, D, E, A, m_W[79]); + + A = (m_digest[0] += A); + B = (m_digest[1] += B); + C = (m_digest[2] += C); + D = (m_digest[3] += D); + E = (m_digest[4] += E); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void SHA_160::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_160::clear() + { + MDx_HashFunction::clear(); + zeroise(m_W); + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + } + +} diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha160.h b/comm/third_party/botan/src/lib/hash/sha1/sha160.h new file mode 100644 index 0000000000..bbab2e8532 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha160.h @@ -0,0 +1,75 @@ +/* +* SHA-160 +* (C) 1999-2007,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA_160_H_ +#define BOTAN_SHA_160_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sha160.h) + +namespace Botan { + +/** +* NIST's SHA-160 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_160 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-160"; } + size_t output_length() const override { return 20; } + HashFunction* clone() const override { return new SHA_160; } + std::unique_ptr copy_state() const override; + + void clear() override; + + SHA_160() : MDx_HashFunction(64, true, true), m_digest(5) + { + clear(); + } + + private: + void compress_n(const uint8_t[], size_t blocks) override; + +#if defined(BOTAN_HAS_SHA1_ARMV8) + static void sha1_armv8_compress_n(secure_vector& digest, + const uint8_t blocks[], + size_t block_count); +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) + static void sse2_compress_n(secure_vector& digest, + const uint8_t blocks[], + size_t block_count); +#endif + +#if defined(BOTAN_HAS_SHA1_X86_SHA_NI) + // Using x86 SHA instructions in Intel Goldmont and Cannonlake + static void sha1_compress_x86(secure_vector& digest, + const uint8_t blocks[], + size_t block_count); +#endif + + + void copy_out(uint8_t[]) override; + + /** + * The digest value + */ + secure_vector m_digest; + + /** + * The message buffer + */ + secure_vector m_W; + }; + +typedef SHA_160 SHA_1; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/info.txt b/comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/info.txt new file mode 100644 index 0000000000..51409c943c --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/info.txt @@ -0,0 +1,12 @@ + +SHA1_ARMV8 -> 20170117 + + + +armv8crypto + + + +gcc:4.9 +clang:3.8 + diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp b/comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp new file mode 100644 index 0000000000..3dc9f43d85 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp @@ -0,0 +1,207 @@ +/* +* SHA-1 using CPU instructions in ARMv8 +* +* Contributed by Jeffrey Walton. Based on public domain code by +* Johannes Schneiders, Skip Hovsmith and Barry O'Rourke. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* SHA-1 using CPU instructions in ARMv8 +*/ +//static +#if defined(BOTAN_HAS_SHA1_ARMV8) +BOTAN_FUNC_ISA("+crypto") +void SHA_160::sha1_armv8_compress_n(secure_vector& digest, const uint8_t input8[], size_t blocks) + { + uint32x4_t ABCD; + uint32_t E0; + + // Load magic constants + const uint32x4_t C0 = vdupq_n_u32(0x5A827999); + const uint32x4_t C1 = vdupq_n_u32(0x6ED9EBA1); + const uint32x4_t C2 = vdupq_n_u32(0x8F1BBCDC); + const uint32x4_t C3 = vdupq_n_u32(0xCA62C1D6); + + ABCD = vld1q_u32(&digest[0]); + E0 = digest[4]; + + // Intermediate void* cast due to https://llvm.org/bugs/show_bug.cgi?id=20670 + const uint32_t* input32 = reinterpret_cast(reinterpret_cast(input8)); + + while (blocks) + { + // Save current hash + const uint32x4_t ABCD_SAVED = ABCD; + const uint32_t E0_SAVED = E0; + + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP1; + uint32_t E1; + + MSG0 = vld1q_u32(input32 + 0); + MSG1 = vld1q_u32(input32 + 4); + MSG2 = vld1q_u32(input32 + 8); + MSG3 = vld1q_u32(input32 + 12); + + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG1))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG2))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG3))); + + TMP0 = vaddq_u32(MSG0, C0); + TMP1 = vaddq_u32(MSG1, C0); + + // Rounds 0-3 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C0); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 4-7 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C0); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 8-11 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C0); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 12-15 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C1); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 16-19 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C1); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 20-23 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C1); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 24-27 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C1); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 28-31 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C1); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 32-35 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C2); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 36-39 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C2); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 40-43 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C2); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 44-47 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C2); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 48-51 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C2); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 52-55 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C3); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 56-59 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C3); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 60-63 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C3); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 64-67 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C3); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 68-71 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C3); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + + // Rounds 72-75 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + + // Rounds 76-79 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + + // Add state back + E0 += E0_SAVED; + ABCD = vaddq_u32(ABCD_SAVED, ABCD); + + input32 += 64/4; + blocks--; + } + + // Save digest + vst1q_u32(&digest[0], ABCD); + digest[4] = E0; + } +#endif + +} diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/info.txt b/comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/info.txt new file mode 100644 index 0000000000..2aee95b15c --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/info.txt @@ -0,0 +1,7 @@ + +SHA1_SSE2 -> 20160803 + + + +sse2 + diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp b/comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp new file mode 100644 index 0000000000..7371ca08f5 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp @@ -0,0 +1,336 @@ +/* +* SHA-1 using SSE2 +* Based on public domain code by Dean Gaudet +* (http://arctic.org/~dean/crypto/sha1.html) +* (C) 2009-2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace SHA1_SSE2_F { + +namespace { + +/* +* First 16 bytes just need byte swapping. Preparing just means +* adding in the round constants. +*/ + +#define prep00_15(P, W) \ + do { \ + W = _mm_shufflehi_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ + W = _mm_shufflelo_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ + W = _mm_or_si128(_mm_slli_epi16(W, 8), \ + _mm_srli_epi16(W, 8)); \ + P.u128 = _mm_add_epi32(W, K00_19); \ + } while(0) + +/* +For each multiple of 4, t, we want to calculate this: + +W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); +W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); +W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); +W[t+3] = rol(W[t] ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); + +we'll actually calculate this: + +W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); +W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); +W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); +W[t+3] = rol( 0 ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); +W[t+3] ^= rol(W[t+0], 1); + +the parameters are: + +W0 = &W[t-16]; +W1 = &W[t-12]; +W2 = &W[t- 8]; +W3 = &W[t- 4]; + +and on output: +prepared = W0 + K +W0 = W[t]..W[t+3] +*/ + +/* note that there is a step here where i want to do a rol by 1, which +* normally would look like this: +* +* r1 = psrld r0,$31 +* r0 = pslld r0,$1 +* r0 = por r0,r1 +* +* but instead i do this: +* +* r1 = pcmpltd r0,zero +* r0 = paddd r0,r0 +* r0 = psub r0,r1 +* +* because pcmpltd and paddd are available in both MMX units on +* efficeon, pentium-m, and opteron but shifts are available in +* only one unit. +*/ +#define prep(prep, XW0, XW1, XW2, XW3, K) \ + do { \ + __m128i r0, r1, r2, r3; \ + \ + /* load W[t-4] 16-byte aligned, and shift */ \ + r3 = _mm_srli_si128((XW3), 4); \ + r0 = (XW0); \ + /* get high 64-bits of XW0 into low 64-bits */ \ + r1 = _mm_shuffle_epi32((XW0), _MM_SHUFFLE(1,0,3,2)); \ + /* load high 64-bits of r1 */ \ + r1 = _mm_unpacklo_epi64(r1, (XW1)); \ + r2 = (XW2); \ + \ + r0 = _mm_xor_si128(r1, r0); \ + r2 = _mm_xor_si128(r3, r2); \ + r0 = _mm_xor_si128(r2, r0); \ + /* unrotated W[t]..W[t+2] in r0 ... still need W[t+3] */ \ + \ + r2 = _mm_slli_si128(r0, 12); \ + r1 = _mm_cmplt_epi32(r0, _mm_setzero_si128()); \ + r0 = _mm_add_epi32(r0, r0); /* shift left by 1 */ \ + r0 = _mm_sub_epi32(r0, r1); /* r0 has W[t]..W[t+2] */ \ + \ + r3 = _mm_srli_epi32(r2, 30); \ + r2 = _mm_slli_epi32(r2, 2); \ + \ + r0 = _mm_xor_si128(r0, r3); \ + r0 = _mm_xor_si128(r0, r2); /* r0 now has W[t+3] */ \ + \ + (XW0) = r0; \ + (prep).u128 = _mm_add_epi32(r0, K); \ + } while(0) + +/* +* SHA-160 F1 Function +*/ +inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (D ^ (B & (C ^ D))) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += ((B & C) | ((B | C) & D)) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +} + +} + +/* +* SHA-160 Compression Function using SSE for message expansion +*/ +//static +BOTAN_FUNC_ISA("sse2") +void SHA_160::sse2_compress_n(secure_vector& digest, const uint8_t input[], size_t blocks) + { + using namespace SHA1_SSE2_F; + + const __m128i K00_19 = _mm_set1_epi32(0x5A827999); + const __m128i K20_39 = _mm_set1_epi32(0x6ED9EBA1); + const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC); + const __m128i K60_79 = _mm_set1_epi32(0xCA62C1D6); + + uint32_t A = digest[0], + B = digest[1], + C = digest[2], + D = digest[3], + E = digest[4]; + + const __m128i* input_mm = reinterpret_cast(input); + + for(size_t i = 0; i != blocks; ++i) + { + union v4si { + uint32_t u32[4]; + __m128i u128; + }; + + v4si P0, P1, P2, P3; + + __m128i W0 = _mm_loadu_si128(&input_mm[0]); + prep00_15(P0, W0); + + __m128i W1 = _mm_loadu_si128(&input_mm[1]); + prep00_15(P1, W1); + + __m128i W2 = _mm_loadu_si128(&input_mm[2]); + prep00_15(P2, W2); + + __m128i W3 = _mm_loadu_si128(&input_mm[3]); + prep00_15(P3, W3); + + /* + Using SSE4; slower on Core2 and Nehalem + #define GET_P_32(P, i) _mm_extract_epi32(P.u128, i) + + Much slower on all tested platforms + #define GET_P_32(P,i) _mm_cvtsi128_si32(_mm_srli_si128(P.u128, i*4)) + */ + +#define GET_P_32(P, i) P.u32[i] + + F1(A, B, C, D, E, GET_P_32(P0, 0)); + F1(E, A, B, C, D, GET_P_32(P0, 1)); + F1(D, E, A, B, C, GET_P_32(P0, 2)); + F1(C, D, E, A, B, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K00_19); + + F1(B, C, D, E, A, GET_P_32(P1, 0)); + F1(A, B, C, D, E, GET_P_32(P1, 1)); + F1(E, A, B, C, D, GET_P_32(P1, 2)); + F1(D, E, A, B, C, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K20_39); + + F1(C, D, E, A, B, GET_P_32(P2, 0)); + F1(B, C, D, E, A, GET_P_32(P2, 1)); + F1(A, B, C, D, E, GET_P_32(P2, 2)); + F1(E, A, B, C, D, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K20_39); + + F1(D, E, A, B, C, GET_P_32(P3, 0)); + F1(C, D, E, A, B, GET_P_32(P3, 1)); + F1(B, C, D, E, A, GET_P_32(P3, 2)); + F1(A, B, C, D, E, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K20_39); + + F1(E, A, B, C, D, GET_P_32(P0, 0)); + F1(D, E, A, B, C, GET_P_32(P0, 1)); + F1(C, D, E, A, B, GET_P_32(P0, 2)); + F1(B, C, D, E, A, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K20_39); + + F2(A, B, C, D, E, GET_P_32(P1, 0)); + F2(E, A, B, C, D, GET_P_32(P1, 1)); + F2(D, E, A, B, C, GET_P_32(P1, 2)); + F2(C, D, E, A, B, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K20_39); + + F2(B, C, D, E, A, GET_P_32(P2, 0)); + F2(A, B, C, D, E, GET_P_32(P2, 1)); + F2(E, A, B, C, D, GET_P_32(P2, 2)); + F2(D, E, A, B, C, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K40_59); + + F2(C, D, E, A, B, GET_P_32(P3, 0)); + F2(B, C, D, E, A, GET_P_32(P3, 1)); + F2(A, B, C, D, E, GET_P_32(P3, 2)); + F2(E, A, B, C, D, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K40_59); + + F2(D, E, A, B, C, GET_P_32(P0, 0)); + F2(C, D, E, A, B, GET_P_32(P0, 1)); + F2(B, C, D, E, A, GET_P_32(P0, 2)); + F2(A, B, C, D, E, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K40_59); + + F2(E, A, B, C, D, GET_P_32(P1, 0)); + F2(D, E, A, B, C, GET_P_32(P1, 1)); + F2(C, D, E, A, B, GET_P_32(P1, 2)); + F2(B, C, D, E, A, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K40_59); + + F3(A, B, C, D, E, GET_P_32(P2, 0)); + F3(E, A, B, C, D, GET_P_32(P2, 1)); + F3(D, E, A, B, C, GET_P_32(P2, 2)); + F3(C, D, E, A, B, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K40_59); + + F3(B, C, D, E, A, GET_P_32(P3, 0)); + F3(A, B, C, D, E, GET_P_32(P3, 1)); + F3(E, A, B, C, D, GET_P_32(P3, 2)); + F3(D, E, A, B, C, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K60_79); + + F3(C, D, E, A, B, GET_P_32(P0, 0)); + F3(B, C, D, E, A, GET_P_32(P0, 1)); + F3(A, B, C, D, E, GET_P_32(P0, 2)); + F3(E, A, B, C, D, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K60_79); + + F3(D, E, A, B, C, GET_P_32(P1, 0)); + F3(C, D, E, A, B, GET_P_32(P1, 1)); + F3(B, C, D, E, A, GET_P_32(P1, 2)); + F3(A, B, C, D, E, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K60_79); + + F3(E, A, B, C, D, GET_P_32(P2, 0)); + F3(D, E, A, B, C, GET_P_32(P2, 1)); + F3(C, D, E, A, B, GET_P_32(P2, 2)); + F3(B, C, D, E, A, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K60_79); + + F4(A, B, C, D, E, GET_P_32(P3, 0)); + F4(E, A, B, C, D, GET_P_32(P3, 1)); + F4(D, E, A, B, C, GET_P_32(P3, 2)); + F4(C, D, E, A, B, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K60_79); + + F4(B, C, D, E, A, GET_P_32(P0, 0)); + F4(A, B, C, D, E, GET_P_32(P0, 1)); + F4(E, A, B, C, D, GET_P_32(P0, 2)); + F4(D, E, A, B, C, GET_P_32(P0, 3)); + + F4(C, D, E, A, B, GET_P_32(P1, 0)); + F4(B, C, D, E, A, GET_P_32(P1, 1)); + F4(A, B, C, D, E, GET_P_32(P1, 2)); + F4(E, A, B, C, D, GET_P_32(P1, 3)); + + F4(D, E, A, B, C, GET_P_32(P2, 0)); + F4(C, D, E, A, B, GET_P_32(P2, 1)); + F4(B, C, D, E, A, GET_P_32(P2, 2)); + F4(A, B, C, D, E, GET_P_32(P2, 3)); + + F4(E, A, B, C, D, GET_P_32(P3, 0)); + F4(D, E, A, B, C, GET_P_32(P3, 1)); + F4(C, D, E, A, B, GET_P_32(P3, 2)); + F4(B, C, D, E, A, GET_P_32(P3, 3)); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input_mm += (64 / 16); + } + +#undef GET_P_32 + } + +#undef prep00_15 +#undef prep + +} diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha1_x86/info.txt b/comm/third_party/botan/src/lib/hash/sha1/sha1_x86/info.txt new file mode 100644 index 0000000000..0a46d980a0 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha1_x86/info.txt @@ -0,0 +1,16 @@ + +SHA1_X86_SHA_NI -> 20170518 + + + +sha +sse2 +ssse3 +sse41 + + + +clang:3.9 +gcc:5.0 +msvc:19.0 # MSVS 2015 + diff --git a/comm/third_party/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp b/comm/third_party/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp new file mode 100644 index 0000000000..76feebcea1 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp @@ -0,0 +1,216 @@ +/* +* SHA-1 using Intel SHA intrinsic +* +* Based on public domain code by Sean Gulley +* (https://github.com/mitls/hacl-star/tree/master/experimental/hash) +* Adapted to Botan by Jeffrey Walton. +* +* Further changes +* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +#if defined(BOTAN_HAS_SHA1_X86_SHA_NI) +BOTAN_FUNC_ISA("sha,ssse3,sse4.1") +void SHA_160::sha1_compress_x86(secure_vector& digest, + const uint8_t input[], + size_t blocks) + { + const __m128i MASK = _mm_set_epi64x(0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL); + const __m128i* input_mm = reinterpret_cast(input); + + uint32_t* state = digest.data(); + + // Load initial values + __m128i ABCD = _mm_loadu_si128(reinterpret_cast<__m128i*>(state)); + __m128i E0 = _mm_set_epi32(state[4], 0, 0, 0); + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + + while (blocks) + { + // Save current hash + const __m128i ABCD_SAVE = ABCD; + const __m128i E0_SAVE = E0; + + __m128i MSG0, MSG1, MSG2, MSG3; + __m128i E1; + + // Rounds 0-3 + MSG0 = _mm_loadu_si128(input_mm+0); + MSG0 = _mm_shuffle_epi8(MSG0, MASK); + E0 = _mm_add_epi32(E0, MSG0); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + + // Rounds 4-7 + MSG1 = _mm_loadu_si128(input_mm+1); + MSG1 = _mm_shuffle_epi8(MSG1, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + + // Rounds 8-11 + MSG2 = _mm_loadu_si128(input_mm+2); + MSG2 = _mm_shuffle_epi8(MSG2, MASK); + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 12-15 + MSG3 = _mm_loadu_si128(input_mm+3); + MSG3 = _mm_shuffle_epi8(MSG3, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 16-19 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 20-23 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 24-27 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 28-31 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 32-35 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 36-39 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 40-43 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 44-47 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 48-51 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 52-55 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 56-59 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 60-63 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 64-67 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 68-71 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 72-75 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + + // Rounds 76-79 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + + // Add values back to state + E0 = _mm_sha1nexte_epu32(E0, E0_SAVE); + ABCD = _mm_add_epi32(ABCD, ABCD_SAVE); + + input_mm += 4; + blocks--; + } + + // Save state + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + _mm_storeu_si128(reinterpret_cast<__m128i*>(state), ABCD); + state[4] = _mm_extract_epi32(E0, 3); + } +#endif + +} diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/info.txt b/comm/third_party/botan/src/lib/hash/sha2_32/info.txt new file mode 100644 index 0000000000..7992eff261 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/info.txt @@ -0,0 +1,7 @@ + +SHA2_32 -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.cpp b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.cpp new file mode 100644 index 0000000000..61e98d22f2 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.cpp @@ -0,0 +1,278 @@ +/* +* SHA-{224,256} +* (C) 1999-2010,2017 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string sha256_provider() + { +#if defined(BOTAN_HAS_SHA2_32_X86) + if(CPUID::has_intel_sha()) + { + return "shani"; + } +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86_BMI2) + if(CPUID::has_bmi2()) + { + return "bmi2"; + } +#endif + +#if defined(BOTAN_HAS_SHA2_32_ARMV8) + if(CPUID::has_arm_sha2()) + { + return "armv8"; + } +#endif + + return "base"; + } + +} + +std::unique_ptr SHA_224::copy_state() const + { + return std::unique_ptr(new SHA_224(*this)); + } + +std::unique_ptr SHA_256::copy_state() const + { + return std::unique_ptr(new SHA_256(*this)); + } + +/* +* SHA-256 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do { \ + uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); \ + uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); \ + uint32_t M2_sigma = rotr<17>(M2) ^ rotr<19>(M2) ^ (M2 >> 10); \ + uint32_t M4_sigma = rotr<7>(M4) ^ rotr<18>(M4) ^ (M4 >> 3); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +/* +* SHA-224 / SHA-256 compression function +*/ +void SHA_256::compress_digest(secure_vector& digest, + const uint8_t input[], size_t blocks) + { +#if defined(BOTAN_HAS_SHA2_32_X86) + if(CPUID::has_intel_sha()) + { + return SHA_256::compress_digest_x86(digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86_BMI2) + if(CPUID::has_bmi2()) + { + return SHA_256::compress_digest_x86_bmi2(digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA2_32_ARMV8) + if(CPUID::has_arm_sha2()) + { + return SHA_256::compress_digest_armv8(digest, input, blocks); + } +#endif + + uint32_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t W00 = load_be(input, 0); + uint32_t W01 = load_be(input, 1); + uint32_t W02 = load_be(input, 2); + uint32_t W03 = load_be(input, 3); + uint32_t W04 = load_be(input, 4); + uint32_t W05 = load_be(input, 5); + uint32_t W06 = load_be(input, 6); + uint32_t W07 = load_be(input, 7); + uint32_t W08 = load_be(input, 8); + uint32_t W09 = load_be(input, 9); + uint32_t W10 = load_be(input, 10); + uint32_t W11 = load_be(input, 11); + uint32_t W12 = load_be(input, 12); + uint32_t W13 = load_be(input, 13); + uint32_t W14 = load_be(input, 14); + uint32_t W15 = load_be(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 64; + } + } + +std::string SHA_224::provider() const + { + return sha256_provider(); + } + +std::string SHA_256::provider() const + { + return sha256_provider(); + } + +/* +* SHA-224 compression function +*/ +void SHA_224::compress_n(const uint8_t input[], size_t blocks) + { + SHA_256::compress_digest(m_digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_224::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_224::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0xC1059ED8; + m_digest[1] = 0x367CD507; + m_digest[2] = 0x3070DD17; + m_digest[3] = 0xF70E5939; + m_digest[4] = 0xFFC00B31; + m_digest[5] = 0x68581511; + m_digest[6] = 0x64F98FA7; + m_digest[7] = 0xBEFA4FA4; + } + +/* +* SHA-256 compression function +*/ +void SHA_256::compress_n(const uint8_t input[], size_t blocks) + { + SHA_256::compress_digest(m_digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_256::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_256::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x6A09E667; + m_digest[1] = 0xBB67AE85; + m_digest[2] = 0x3C6EF372; + m_digest[3] = 0xA54FF53A; + m_digest[4] = 0x510E527F; + m_digest[5] = 0x9B05688C; + m_digest[6] = 0x1F83D9AB; + m_digest[7] = 0x5BE0CD19; + } + +} diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.h b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.h new file mode 100644 index 0000000000..90a0597212 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32.h @@ -0,0 +1,95 @@ +/* +* SHA-{224,256} +* (C) 1999-2011 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA_224_256_H_ +#define BOTAN_SHA_224_256_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sha2_32.h) + +namespace Botan { + +/** +* SHA-224 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_224 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-224"; } + size_t output_length() const override { return 28; } + HashFunction* clone() const override { return new SHA_224; } + std::unique_ptr copy_state() const override; + + void clear() override; + + std::string provider() const override; + + SHA_224() : MDx_HashFunction(64, true, true), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector m_digest; + }; + +/** +* SHA-256 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_256 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-256"; } + size_t output_length() const override { return 32; } + HashFunction* clone() const override { return new SHA_256; } + std::unique_ptr copy_state() const override; + + void clear() override; + + std::string provider() const override; + + SHA_256() : MDx_HashFunction(64, true, true), m_digest(8) + { clear(); } + + /* + * Perform a SHA-256 compression. For internal use + */ + static void compress_digest(secure_vector& digest, + const uint8_t input[], + size_t blocks); + + private: + +#if defined(BOTAN_HAS_SHA2_32_ARMV8) + static void compress_digest_armv8(secure_vector& digest, + const uint8_t input[], + size_t blocks); +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86_BMI2) + static void compress_digest_x86_bmi2(secure_vector& digest, + const uint8_t input[], + size_t blocks); +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86) + static void compress_digest_x86(secure_vector& digest, + const uint8_t input[], + size_t blocks); +#endif + + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt new file mode 100644 index 0000000000..cd8813b74f --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt @@ -0,0 +1,12 @@ + +SHA2_32_ARMV8 -> 20170117 + + + +armv8crypto + + + +gcc:4.9 +clang:3.8 + diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp new file mode 100644 index 0000000000..1574a32738 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp @@ -0,0 +1,204 @@ +/* +* SHA-256 using CPU instructions in ARMv8 +* +* Contributed by Jeffrey Walton. Based on public domain code by +* Johannes Schneiders, Skip Hovsmith and Barry O'Rourke. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* SHA-256 using CPU instructions in ARMv8 +*/ +//static +#if defined(BOTAN_HAS_SHA2_32_ARMV8) +BOTAN_FUNC_ISA("+crypto") +void SHA_256::compress_digest_armv8(secure_vector& digest, const uint8_t input8[], size_t blocks) + { + static const uint32_t K[] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, + }; + + uint32x4_t STATE0, STATE1, ABEF_SAVE, CDGH_SAVE; + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP1, TMP2; + + // Load initial values + STATE0 = vld1q_u32(&digest[0]); + STATE1 = vld1q_u32(&digest[4]); + + // Intermediate void* cast due to https://llvm.org/bugs/show_bug.cgi?id=20670 + const uint32_t* input32 = reinterpret_cast(reinterpret_cast(input8)); + + while (blocks) + { + // Save current state + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + MSG0 = vld1q_u32(input32 + 0); + MSG1 = vld1q_u32(input32 + 4); + MSG2 = vld1q_u32(input32 + 8); + MSG3 = vld1q_u32(input32 + 12); + + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG1))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG2))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG3))); + + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x00])); + + // Rounds 0-3 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x04])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 4-7 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x08])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 8-11 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x0c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 12-15 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x10])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 16-19 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x14])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 20-23 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x18])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 24-27 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x1c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 28-31 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x20])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 32-35 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x24])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 36-39 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x28])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 40-43 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x2c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 44-47 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x30])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 48-51 + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x34])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 52-55 + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x38])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + + // Rounds 56-59 + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x3c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 60-63 + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + + // Add back to state + STATE0 = vaddq_u32(STATE0, ABEF_SAVE); + STATE1 = vaddq_u32(STATE1, CDGH_SAVE); + + input32 += 64/4; + blocks--; + } + + // Save state + vst1q_u32(&digest[0], STATE0); + vst1q_u32(&digest[4], STATE1); + } +#endif + +} diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt new file mode 100644 index 0000000000..6918f0a4a3 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt @@ -0,0 +1,12 @@ + +SHA2_32_X86_BMI2 -> 20180526 + + + +bmi2 + + + +gcc +clang + diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp new file mode 100644 index 0000000000..e3194e4afe --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp @@ -0,0 +1,140 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +Your eyes do not decieve you; this is currently just a copy of the +baseline SHA-256 implementation. Because we compile it with BMI2 +flags, GCC and Clang use the BMI2 instructions without further help. + +Likely instruction scheduling could be improved by using inline asm. +*/ + +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do { \ + uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); \ + uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); \ + uint32_t M2_sigma = rotr<17>(M2) ^ rotr<19>(M2) ^ (M2 >> 10); \ + uint32_t M4_sigma = rotr<7>(M4) ^ rotr<18>(M4) ^ (M4 >> 3); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +void SHA_256::compress_digest_x86_bmi2(secure_vector& digest, + const uint8_t input[], + size_t blocks) + { + uint32_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t W00 = load_be(input, 0); + uint32_t W01 = load_be(input, 1); + uint32_t W02 = load_be(input, 2); + uint32_t W03 = load_be(input, 3); + uint32_t W04 = load_be(input, 4); + uint32_t W05 = load_be(input, 5); + uint32_t W06 = load_be(input, 6); + uint32_t W07 = load_be(input, 7); + uint32_t W08 = load_be(input, 8); + uint32_t W09 = load_be(input, 9); + uint32_t W10 = load_be(input, 10); + uint32_t W11 = load_be(input, 11); + uint32_t W12 = load_be(input, 12); + uint32_t W13 = load_be(input, 13); + uint32_t W14 = load_be(input, 14); + uint32_t W15 = load_be(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 64; + } + } + +} diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt new file mode 100644 index 0000000000..8d9fb4149b --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt @@ -0,0 +1,16 @@ + +SHA2_32_X86 -> 20170518 + + + +sha +sse2 +ssse3 +sse41 + + + +gcc:5.0 +clang:3.9 +msvc:19.0 # MSVS 2015 + diff --git a/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp new file mode 100644 index 0000000000..a4bd9b72db --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp @@ -0,0 +1,215 @@ +/* +* Support for SHA-256 x86 instrinsic +* Based on public domain code by Sean Gulley +* (https://github.com/mitls/hacl-star/tree/master/experimental/hash) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +// called from sha2_32.cpp +#if defined(BOTAN_HAS_SHA2_32_X86) +BOTAN_FUNC_ISA("sha,sse4.1,ssse3") +void SHA_256::compress_digest_x86(secure_vector& digest, const uint8_t input[], size_t blocks) + { + __m128i STATE0, STATE1; + __m128i MSG, TMP, MASK; + __m128i TMSG0, TMSG1, TMSG2, TMSG3; + __m128i ABEF_SAVE, CDGH_SAVE; + + uint32_t* state = &digest[0]; + + const __m128i* input_mm = reinterpret_cast(input); + + // Load initial values + TMP = _mm_loadu_si128(reinterpret_cast<__m128i*>(&state[0])); + STATE1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(&state[4])); + MASK = _mm_set_epi64x(0x0c0d0e0f08090a0bULL, 0x0405060700010203ULL); + + TMP = _mm_shuffle_epi32(TMP, 0xB1); // CDAB + STATE1 = _mm_shuffle_epi32(STATE1, 0x1B); // EFGH + STATE0 = _mm_alignr_epi8(TMP, STATE1, 8); // ABEF + STATE1 = _mm_blend_epi16(STATE1, TMP, 0xF0); // CDGH + + while (blocks) + { + // Save current hash + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + // Rounds 0-3 + MSG = _mm_loadu_si128(input_mm); + TMSG0 = _mm_shuffle_epi8(MSG, MASK); + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCFULL, 0x71374491428A2F98ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 4-7 + TMSG1 = _mm_loadu_si128(input_mm + 1); + TMSG1 = _mm_shuffle_epi8(TMSG1, MASK); + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0xAB1C5ED5923F82A4ULL, 0x59F111F13956C25BULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 8-11 + TMSG2 = _mm_loadu_si128(input_mm + 2); + TMSG2 = _mm_shuffle_epi8(TMSG2, MASK); + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0x550C7DC3243185BEULL, 0x12835B01D807AA98ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 12-15 + TMSG3 = _mm_loadu_si128(input_mm + 3); + TMSG3 = _mm_shuffle_epi8(TMSG3, MASK); + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0xC19BF1749BDC06A7ULL, 0x80DEB1FE72BE5D74ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 16-19 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0x240CA1CC0FC19DC6ULL, 0xEFBE4786E49B69C1ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 20-23 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0x76F988DA5CB0A9DCULL, 0x4A7484AA2DE92C6FULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 24-27 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0xBF597FC7B00327C8ULL, 0xA831C66D983E5152ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 28-31 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0x1429296706CA6351ULL, 0xD5A79147C6E00BF3ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 32-35 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0x53380D134D2C6DFCULL, 0x2E1B213827B70A85ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 36-39 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0x92722C8581C2C92EULL, 0x766A0ABB650A7354ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 40-43 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0xC76C51A3C24B8B70ULL, 0xA81A664BA2BFE8A1ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 44-47 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0x106AA070F40E3585ULL, 0xD6990624D192E819ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 48-51 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0x34B0BCB52748774CULL, 0x1E376C0819A4C116ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 52-55 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0x682E6FF35B9CCA4FULL, 0x4ED8AA4A391C0CB3ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 56-59 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0x8CC7020884C87814ULL, 0x78A5636F748F82EEULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 60-63 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0xC67178F2BEF9A3F7ULL, 0xA4506CEB90BEFFFAULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Add values back to state + STATE0 = _mm_add_epi32(STATE0, ABEF_SAVE); + STATE1 = _mm_add_epi32(STATE1, CDGH_SAVE); + + input_mm += 4; + blocks--; + } + + TMP = _mm_shuffle_epi32(STATE0, 0x1B); // FEBA + STATE1 = _mm_shuffle_epi32(STATE1, 0xB1); // DCHG + STATE0 = _mm_blend_epi16(TMP, STATE1, 0xF0); // DCBA + STATE1 = _mm_alignr_epi8(STATE1, TMP, 8); // ABEF + + // Save state + _mm_storeu_si128(reinterpret_cast<__m128i*>(&state[0]), STATE0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(&state[4]), STATE1); + } +#endif + +} diff --git a/comm/third_party/botan/src/lib/hash/sha2_64/info.txt b/comm/third_party/botan/src/lib/hash/sha2_64/info.txt new file mode 100644 index 0000000000..6fb415a6bb --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_64/info.txt @@ -0,0 +1,7 @@ + +SHA2_64 -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.cpp b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.cpp new file mode 100644 index 0000000000..01abb4f00c --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.cpp @@ -0,0 +1,281 @@ +/* +* SHA-{384,512} +* (C) 1999-2011,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string sha512_provider() + { +#if defined(BOTAN_HAS_SHA2_64_BMI2) + if(CPUID::has_bmi2()) + { + return "bmi2"; + } +#endif + + return "base"; + } + +} + +std::unique_ptr SHA_384::copy_state() const + { + return std::unique_ptr(new SHA_384(*this)); + } + +std::unique_ptr SHA_512::copy_state() const + { + return std::unique_ptr(new SHA_512(*this)); + } + +std::unique_ptr SHA_512_256::copy_state() const + { + return std::unique_ptr(new SHA_512_256(*this)); + } + +/* +* SHA-512 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + const uint64_t E_rho = rotr<14>(E) ^ rotr<18>(E) ^ rotr<41>(E); \ + const uint64_t A_rho = rotr<28>(A) ^ rotr<34>(A) ^ rotr<39>(A); \ + const uint64_t M2_sigma = rotr<19>(M2) ^ rotr<61>(M2) ^ (M2 >> 6); \ + const uint64_t M4_sigma = rotr<1>(M4) ^ rotr<8>(M4) ^ (M4 >> 7); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +/* +* SHA-{384,512} Compression Function +*/ +//static +void SHA_512::compress_digest(secure_vector& digest, + const uint8_t input[], size_t blocks) + { +#if defined(BOTAN_HAS_SHA2_64_BMI2) + if(CPUID::has_bmi2()) + { + return compress_digest_bmi2(digest, input, blocks); + } +#endif + + uint64_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint64_t W00 = load_be(input, 0); + uint64_t W01 = load_be(input, 1); + uint64_t W02 = load_be(input, 2); + uint64_t W03 = load_be(input, 3); + uint64_t W04 = load_be(input, 4); + uint64_t W05 = load_be(input, 5); + uint64_t W06 = load_be(input, 6); + uint64_t W07 = load_be(input, 7); + uint64_t W08 = load_be(input, 8); + uint64_t W09 = load_be(input, 9); + uint64_t W10 = load_be(input, 10); + uint64_t W11 = load_be(input, 11); + uint64_t W12 = load_be(input, 12); + uint64_t W13 = load_be(input, 13); + uint64_t W14 = load_be(input, 14); + uint64_t W15 = load_be(input, 15); + + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CD); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2F); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBC); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9B); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBE); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28C); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896F); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFAB); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213F); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826F); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFC); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AED); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DF); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DE); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202A); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACB); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FC); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439EC); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532B); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619C); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1E); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBA); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAE); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBC); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4C); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2A); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAEC); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 128; + } + } + +#undef SHA2_64_F + +std::string SHA_512_256::provider() const + { + return sha512_provider(); + } + +std::string SHA_384::provider() const + { + return sha512_provider(); + } + +std::string SHA_512::provider() const + { + return sha512_provider(); + } + +void SHA_512_256::compress_n(const uint8_t input[], size_t blocks) + { + SHA_512::compress_digest(m_digest, input, blocks); + } + +void SHA_384::compress_n(const uint8_t input[], size_t blocks) + { + SHA_512::compress_digest(m_digest, input, blocks); + } + +void SHA_512::compress_n(const uint8_t input[], size_t blocks) + { + SHA_512::compress_digest(m_digest, input, blocks); + } + +void SHA_512_256::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +void SHA_384::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +void SHA_512::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +void SHA_512_256::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x22312194FC2BF72C; + m_digest[1] = 0x9F555FA3C84C64C2; + m_digest[2] = 0x2393B86B6F53B151; + m_digest[3] = 0x963877195940EABD; + m_digest[4] = 0x96283EE2A88EFFE3; + m_digest[5] = 0xBE5E1E2553863992; + m_digest[6] = 0x2B0199FC2C85B8AA; + m_digest[7] = 0x0EB72DDC81C52CA2; + } + +void SHA_384::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0xCBBB9D5DC1059ED8; + m_digest[1] = 0x629A292A367CD507; + m_digest[2] = 0x9159015A3070DD17; + m_digest[3] = 0x152FECD8F70E5939; + m_digest[4] = 0x67332667FFC00B31; + m_digest[5] = 0x8EB44A8768581511; + m_digest[6] = 0xDB0C2E0D64F98FA7; + m_digest[7] = 0x47B5481DBEFA4FA4; + } + +void SHA_512::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x6A09E667F3BCC908; + m_digest[1] = 0xBB67AE8584CAA73B; + m_digest[2] = 0x3C6EF372FE94F82B; + m_digest[3] = 0xA54FF53A5F1D36F1; + m_digest[4] = 0x510E527FADE682D1; + m_digest[5] = 0x9B05688C2B3E6C1F; + m_digest[6] = 0x1F83D9ABFB41BD6B; + m_digest[7] = 0x5BE0CD19137E2179; + } + +} diff --git a/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.h b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.h new file mode 100644 index 0000000000..dc5f0dd183 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64.h @@ -0,0 +1,102 @@ +/* +* SHA-{384,512} +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA_64BIT_H_ +#define BOTAN_SHA_64BIT_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sha2_64.h) + +namespace Botan { + +/** +* SHA-384 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_384 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-384"; } + size_t output_length() const override { return 48; } + HashFunction* clone() const override { return new SHA_384; } + std::unique_ptr copy_state() const override; + std::string provider() const override; + + void clear() override; + + SHA_384() : MDx_HashFunction(128, true, true, 16), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector m_digest; + }; + +/** +* SHA-512 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_512 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-512"; } + size_t output_length() const override { return 64; } + HashFunction* clone() const override { return new SHA_512; } + std::unique_ptr copy_state() const override; + std::string provider() const override; + + void clear() override; + + /* + * Perform a SHA-512 compression. For internal use + */ + static void compress_digest(secure_vector& digest, + const uint8_t input[], + size_t blocks); + + SHA_512() : MDx_HashFunction(128, true, true, 16), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + static const uint64_t K[80]; + +#if defined(BOTAN_HAS_SHA2_64_BMI2) + static void compress_digest_bmi2(secure_vector& digest, + const uint8_t input[], + size_t blocks); +#endif + + secure_vector m_digest; + }; + +/** +* SHA-512/256 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_512_256 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-512-256"; } + size_t output_length() const override { return 32; } + HashFunction* clone() const override { return new SHA_512_256; } + std::unique_ptr copy_state() const override; + std::string provider() const override; + + void clear() override; + + SHA_512_256() : MDx_HashFunction(128, true, true, 16), m_digest(8) { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/info.txt b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/info.txt new file mode 100644 index 0000000000..0a2ba10fb8 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/info.txt @@ -0,0 +1,17 @@ + +SHA2_64_BMI2 -> 20190117 + + + +bmi2 + + +# Needs 64-bit registers to be useful + +x86_64 + + + +gcc +clang + diff --git a/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/sha2_64_bmi2.cpp b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/sha2_64_bmi2.cpp new file mode 100644 index 0000000000..1ef0ecc56a --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha2_64/sha2_64_bmi2/sha2_64_bmi2.cpp @@ -0,0 +1,153 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* SHA-512 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + const uint64_t E_rho = rotr<14>(E) ^ rotr<18>(E) ^ rotr<41>(E); \ + const uint64_t A_rho = rotr<28>(A) ^ rotr<34>(A) ^ rotr<39>(A); \ + const uint64_t M2_sigma = rotr<19>(M2) ^ rotr<61>(M2) ^ (M2 >> 6); \ + const uint64_t M4_sigma = rotr<1>(M4) ^ rotr<8>(M4) ^ (M4 >> 7); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +void SHA_512::compress_digest_bmi2(secure_vector& digest, + const uint8_t input[], size_t blocks) + { + uint64_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint64_t W00 = load_be(input, 0); + uint64_t W01 = load_be(input, 1); + uint64_t W02 = load_be(input, 2); + uint64_t W03 = load_be(input, 3); + uint64_t W04 = load_be(input, 4); + uint64_t W05 = load_be(input, 5); + uint64_t W06 = load_be(input, 6); + uint64_t W07 = load_be(input, 7); + uint64_t W08 = load_be(input, 8); + uint64_t W09 = load_be(input, 9); + uint64_t W10 = load_be(input, 10); + uint64_t W11 = load_be(input, 11); + uint64_t W12 = load_be(input, 12); + uint64_t W13 = load_be(input, 13); + uint64_t W14 = load_be(input, 14); + uint64_t W15 = load_be(input, 15); + + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CD); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2F); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBC); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9B); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBE); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28C); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896F); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFAB); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213F); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826F); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFC); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AED); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DF); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DE); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202A); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACB); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FC); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439EC); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532B); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619C); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1E); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBA); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAE); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBC); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4C); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2A); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAEC); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 128; + } + } + +#undef SHA2_64_F + +} diff --git a/comm/third_party/botan/src/lib/hash/sha3/info.txt b/comm/third_party/botan/src/lib/hash/sha3/info.txt new file mode 100644 index 0000000000..76ae81bd8f --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha3/info.txt @@ -0,0 +1,3 @@ + +SHA3 -> 20161018 + diff --git a/comm/third_party/botan/src/lib/hash/sha3/sha3.cpp b/comm/third_party/botan/src/lib/hash/sha3/sha3.cpp new file mode 100644 index 0000000000..289e451ffa --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha3/sha3.cpp @@ -0,0 +1,293 @@ +/* +* SHA-3 +* (C) 2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +#include + +namespace Botan { + +namespace { + +// This is a workaround for a suspected bug in clang 12 (and XCode 13) +// that caused a miscompile of the SHA3 implementation for optimization +// level -O2 and higher. +// +// For details, see: https://github.com/randombit/botan/issues/2802 +#if defined(__clang__) && \ + (( defined(__apple_build_version__) && __clang_major__ == 13) || \ + (!defined(__apple_build_version__) && __clang_major__ == 12)) +#define BOTAN_WORKAROUND_MAYBE_INLINE __attribute__((noinline)) +#else +#define BOTAN_WORKAROUND_MAYBE_INLINE inline +#endif + +BOTAN_WORKAROUND_MAYBE_INLINE std::tuple + xor_CNs(const uint64_t A[25]) + { + return { + A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20], + A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21], + A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22], + A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23], + A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]}; + } + +#undef BOTAN_WORKAROUND_MAYBE_INLINE + +inline void SHA3_round(uint64_t T[25], const uint64_t A[25], uint64_t RC) + { + const auto Cs = xor_CNs(A); + + const uint64_t D0 = rotl<1>(std::get<0>(Cs)) ^ std::get<3>(Cs); + const uint64_t D1 = rotl<1>(std::get<1>(Cs)) ^ std::get<4>(Cs); + const uint64_t D2 = rotl<1>(std::get<2>(Cs)) ^ std::get<0>(Cs); + const uint64_t D3 = rotl<1>(std::get<3>(Cs)) ^ std::get<1>(Cs); + const uint64_t D4 = rotl<1>(std::get<4>(Cs)) ^ std::get<2>(Cs); + + const uint64_t B00 = A[ 0] ^ D1; + const uint64_t B01 = rotl<44>(A[ 6] ^ D2); + const uint64_t B02 = rotl<43>(A[12] ^ D3); + const uint64_t B03 = rotl<21>(A[18] ^ D4); + const uint64_t B04 = rotl<14>(A[24] ^ D0); + T[ 0] = B00 ^ (~B01 & B02) ^ RC; + T[ 1] = B01 ^ (~B02 & B03); + T[ 2] = B02 ^ (~B03 & B04); + T[ 3] = B03 ^ (~B04 & B00); + T[ 4] = B04 ^ (~B00 & B01); + + const uint64_t B05 = rotl<28>(A[ 3] ^ D4); + const uint64_t B06 = rotl<20>(A[ 9] ^ D0); + const uint64_t B07 = rotl< 3>(A[10] ^ D1); + const uint64_t B08 = rotl<45>(A[16] ^ D2); + const uint64_t B09 = rotl<61>(A[22] ^ D3); + T[ 5] = B05 ^ (~B06 & B07); + T[ 6] = B06 ^ (~B07 & B08); + T[ 7] = B07 ^ (~B08 & B09); + T[ 8] = B08 ^ (~B09 & B05); + T[ 9] = B09 ^ (~B05 & B06); + + const uint64_t B10 = rotl< 1>(A[ 1] ^ D2); + const uint64_t B11 = rotl< 6>(A[ 7] ^ D3); + const uint64_t B12 = rotl<25>(A[13] ^ D4); + const uint64_t B13 = rotl< 8>(A[19] ^ D0); + const uint64_t B14 = rotl<18>(A[20] ^ D1); + T[10] = B10 ^ (~B11 & B12); + T[11] = B11 ^ (~B12 & B13); + T[12] = B12 ^ (~B13 & B14); + T[13] = B13 ^ (~B14 & B10); + T[14] = B14 ^ (~B10 & B11); + + const uint64_t B15 = rotl<27>(A[ 4] ^ D0); + const uint64_t B16 = rotl<36>(A[ 5] ^ D1); + const uint64_t B17 = rotl<10>(A[11] ^ D2); + const uint64_t B18 = rotl<15>(A[17] ^ D3); + const uint64_t B19 = rotl<56>(A[23] ^ D4); + T[15] = B15 ^ (~B16 & B17); + T[16] = B16 ^ (~B17 & B18); + T[17] = B17 ^ (~B18 & B19); + T[18] = B18 ^ (~B19 & B15); + T[19] = B19 ^ (~B15 & B16); + + const uint64_t B20 = rotl<62>(A[ 2] ^ D3); + const uint64_t B21 = rotl<55>(A[ 8] ^ D4); + const uint64_t B22 = rotl<39>(A[14] ^ D0); + const uint64_t B23 = rotl<41>(A[15] ^ D1); + const uint64_t B24 = rotl< 2>(A[21] ^ D2); + T[20] = B20 ^ (~B21 & B22); + T[21] = B21 ^ (~B22 & B23); + T[22] = B22 ^ (~B23 & B24); + T[23] = B23 ^ (~B24 & B20); + T[24] = B24 ^ (~B20 & B21); + } + +} + +//static +void SHA_3::permute(uint64_t A[25]) + { +#if defined(BOTAN_HAS_SHA3_BMI2) + if(CPUID::has_bmi2()) + { + return permute_bmi2(A); + } +#endif + + static const uint64_t RC[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, + 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, + 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + + uint64_t T[25]; + + for(size_t i = 0; i != 24; i += 2) + { + SHA3_round(T, A, RC[i+0]); + SHA3_round(A, T, RC[i+1]); + } + } + +//static +size_t SHA_3::absorb(size_t bitrate, + secure_vector& S, size_t S_pos, + const uint8_t input[], size_t length) + { + while(length > 0) + { + size_t to_take = std::min(length, bitrate / 8 - S_pos); + + length -= to_take; + + while(to_take && S_pos % 8) + { + S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); + + ++S_pos; + ++input; + --to_take; + } + + while(to_take && to_take % 8 == 0) + { + S[S_pos / 8] ^= load_le(input, 0); + S_pos += 8; + input += 8; + to_take -= 8; + } + + while(to_take) + { + S[S_pos / 8] ^= static_cast(input[0]) << (8 * (S_pos % 8)); + + ++S_pos; + ++input; + --to_take; + } + + if(S_pos == bitrate / 8) + { + SHA_3::permute(S.data()); + S_pos = 0; + } + } + + return S_pos; + } + +//static +void SHA_3::finish(size_t bitrate, + secure_vector& S, size_t S_pos, + uint8_t init_pad, uint8_t fini_pad) + { + BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64"); + + S[S_pos / 8] ^= static_cast(init_pad) << (8 * (S_pos % 8)); + S[(bitrate / 64) - 1] ^= static_cast(fini_pad) << 56; + SHA_3::permute(S.data()); + } + +//static +void SHA_3::expand(size_t bitrate, + secure_vector& S, + uint8_t output[], size_t output_length) + { + BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64"); + + const size_t byterate = bitrate / 8; + + while(output_length > 0) + { + const size_t copying = std::min(byterate, output_length); + + copy_out_vec_le(output, copying, S); + + output += copying; + output_length -= copying; + + if(output_length > 0) + { + SHA_3::permute(S.data()); + } + } + } + +SHA_3::SHA_3(size_t output_bits) : + m_output_bits(output_bits), + m_bitrate(1600 - 2*output_bits), + m_S(25), + m_S_pos(0) + { + // We only support the parameters for SHA-3 in this constructor + + if(output_bits != 224 && output_bits != 256 && + output_bits != 384 && output_bits != 512) + throw Invalid_Argument("SHA_3: Invalid output length " + + std::to_string(output_bits)); + } + +std::string SHA_3::name() const + { + return "SHA-3(" + std::to_string(m_output_bits) + ")"; + } + +std::string SHA_3::provider() const + { +#if defined(BOTAN_HAS_SHA3_BMI2) + if(CPUID::has_bmi2()) + { + return "bmi2"; + } +#endif + + return "base"; + } + +std::unique_ptr SHA_3::copy_state() const + { + return std::unique_ptr(new SHA_3(*this)); + } + +HashFunction* SHA_3::clone() const + { + return new SHA_3(m_output_bits); + } + +void SHA_3::clear() + { + zeroise(m_S); + m_S_pos = 0; + } + +void SHA_3::add_data(const uint8_t input[], size_t length) + { + m_S_pos = SHA_3::absorb(m_bitrate, m_S, m_S_pos, input, length); + } + +void SHA_3::final_result(uint8_t output[]) + { + SHA_3::finish(m_bitrate, m_S, m_S_pos, 0x06, 0x80); + + /* + * We never have to run the permutation again because we only support + * limited output lengths + */ + copy_out_vec_le(output, m_output_bits/8, m_S); + + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/sha3/sha3.h b/comm/third_party/botan/src/lib/hash/sha3/sha3.h new file mode 100644 index 0000000000..e290e60a20 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha3/sha3.h @@ -0,0 +1,136 @@ +/* +* SHA-3 +* (C) 2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA3_H_ +#define BOTAN_SHA3_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sha3.h) + +namespace Botan { + +/** +* SHA-3 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_3 : public HashFunction + { + public: + + /** + * @param output_bits the size of the hash output; must be one of + * 224, 256, 384, or 512 + */ + explicit SHA_3(size_t output_bits); + + size_t hash_block_size() const override { return m_bitrate / 8; } + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override; + std::unique_ptr copy_state() const override; + std::string name() const override; + void clear() override; + std::string provider() const override; + + // Static functions for internal usage + + /** + * Absorb data into the provided state + * @param bitrate the bitrate to absorb into the sponge + * @param S the sponge state + * @param S_pos where to begin absorbing into S + * @param input the input data + * @param length size of input in bytes + */ + static size_t absorb(size_t bitrate, + secure_vector& S, size_t S_pos, + const uint8_t input[], size_t length); + + /** + * Add final padding and permute. The padding is assumed to be + * init_pad || 00... || fini_pad + * + * @param bitrate the bitrate to absorb into the sponge + * @param S the sponge state + * @param S_pos where to begin absorbing into S + * @param init_pad the leading pad bits + * @param fini_pad the final pad bits + */ + static void finish(size_t bitrate, + secure_vector& S, size_t S_pos, + uint8_t init_pad, uint8_t fini_pad); + + /** + * Expand from provided state + * @param bitrate sponge parameter + * @param S the state + * @param output the output buffer + * @param output_length the size of output in bytes + */ + static void expand(size_t bitrate, + secure_vector& S, + uint8_t output[], size_t output_length); + + /** + * The bare Keccak-1600 permutation + */ + static void permute(uint64_t A[25]); + + private: + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + +#if defined(BOTAN_HAS_SHA3_BMI2) + static void permute_bmi2(uint64_t A[25]); +#endif + + size_t m_output_bits, m_bitrate; + secure_vector m_S; + size_t m_S_pos; + }; + +/** +* SHA-3-224 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_3_224 final : public SHA_3 + { + public: + SHA_3_224() : SHA_3(224) {} + }; + +/** +* SHA-3-256 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_3_256 final : public SHA_3 + { + public: + SHA_3_256() : SHA_3(256) {} + }; + +/** +* SHA-3-384 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_3_384 final : public SHA_3 + { + public: + SHA_3_384() : SHA_3(384) {} + }; + +/** +* SHA-3-512 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_3_512 final : public SHA_3 + { + public: + SHA_3_512() : SHA_3(512) {} + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/info.txt b/comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/info.txt new file mode 100644 index 0000000000..5f0db560e5 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/info.txt @@ -0,0 +1,17 @@ + +SHA3_BMI2 -> 20190117 + + + +bmi2 + + +# Needs 64-bit registers to be useful + +x86_64 + + + +gcc +clang + diff --git a/comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp b/comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp new file mode 100644 index 0000000000..c7f1914a3b --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp @@ -0,0 +1,133 @@ +/* +* SHA-3 +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include + +namespace Botan { + +namespace { + +// This is a workaround for a suspected bug in clang 12 (and XCode 13) +// that caused a miscompile of the SHA3 implementation for optimization +// level -O2 and higher. +// +// For details, see: https://github.com/randombit/botan/issues/2802 +#if defined(__clang__) && \ + (( defined(__apple_build_version__) && __clang_major__ == 13) || \ + (!defined(__apple_build_version__) && __clang_major__ == 12)) +#define BOTAN_WORKAROUND_MAYBE_INLINE __attribute__((noinline)) +#else +#define BOTAN_WORKAROUND_MAYBE_INLINE inline +#endif + +BOTAN_WORKAROUND_MAYBE_INLINE std::tuple + xor_CNs(const uint64_t A[25]) + { + return { + A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20], + A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21], + A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22], + A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23], + A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]}; + } + +#undef BOTAN_WORKAROUND_MAYBE_INLINE + +inline void SHA3_BMI2_round(uint64_t T[25], const uint64_t A[25], uint64_t RC) + { + const auto Cs = xor_CNs(A); + + const uint64_t D0 = rotl<1>(std::get<0>(Cs)) ^ std::get<3>(Cs); + const uint64_t D1 = rotl<1>(std::get<1>(Cs)) ^ std::get<4>(Cs); + const uint64_t D2 = rotl<1>(std::get<2>(Cs)) ^ std::get<0>(Cs); + const uint64_t D3 = rotl<1>(std::get<3>(Cs)) ^ std::get<1>(Cs); + const uint64_t D4 = rotl<1>(std::get<4>(Cs)) ^ std::get<2>(Cs); + + const uint64_t B00 = A[ 0] ^ D1; + const uint64_t B01 = rotl<44>(A[ 6] ^ D2); + const uint64_t B02 = rotl<43>(A[12] ^ D3); + const uint64_t B03 = rotl<21>(A[18] ^ D4); + const uint64_t B04 = rotl<14>(A[24] ^ D0); + T[ 0] = B00 ^ (~B01 & B02) ^ RC; + T[ 1] = B01 ^ (~B02 & B03); + T[ 2] = B02 ^ (~B03 & B04); + T[ 3] = B03 ^ (~B04 & B00); + T[ 4] = B04 ^ (~B00 & B01); + + const uint64_t B05 = rotl<28>(A[ 3] ^ D4); + const uint64_t B06 = rotl<20>(A[ 9] ^ D0); + const uint64_t B07 = rotl< 3>(A[10] ^ D1); + const uint64_t B08 = rotl<45>(A[16] ^ D2); + const uint64_t B09 = rotl<61>(A[22] ^ D3); + T[ 5] = B05 ^ (~B06 & B07); + T[ 6] = B06 ^ (~B07 & B08); + T[ 7] = B07 ^ (~B08 & B09); + T[ 8] = B08 ^ (~B09 & B05); + T[ 9] = B09 ^ (~B05 & B06); + + const uint64_t B10 = rotl< 1>(A[ 1] ^ D2); + const uint64_t B11 = rotl< 6>(A[ 7] ^ D3); + const uint64_t B12 = rotl<25>(A[13] ^ D4); + const uint64_t B13 = rotl< 8>(A[19] ^ D0); + const uint64_t B14 = rotl<18>(A[20] ^ D1); + T[10] = B10 ^ (~B11 & B12); + T[11] = B11 ^ (~B12 & B13); + T[12] = B12 ^ (~B13 & B14); + T[13] = B13 ^ (~B14 & B10); + T[14] = B14 ^ (~B10 & B11); + + const uint64_t B15 = rotl<27>(A[ 4] ^ D0); + const uint64_t B16 = rotl<36>(A[ 5] ^ D1); + const uint64_t B17 = rotl<10>(A[11] ^ D2); + const uint64_t B18 = rotl<15>(A[17] ^ D3); + const uint64_t B19 = rotl<56>(A[23] ^ D4); + T[15] = B15 ^ (~B16 & B17); + T[16] = B16 ^ (~B17 & B18); + T[17] = B17 ^ (~B18 & B19); + T[18] = B18 ^ (~B19 & B15); + T[19] = B19 ^ (~B15 & B16); + + const uint64_t B20 = rotl<62>(A[ 2] ^ D3); + const uint64_t B21 = rotl<55>(A[ 8] ^ D4); + const uint64_t B22 = rotl<39>(A[14] ^ D0); + const uint64_t B23 = rotl<41>(A[15] ^ D1); + const uint64_t B24 = rotl< 2>(A[21] ^ D2); + T[20] = B20 ^ (~B21 & B22); + T[21] = B21 ^ (~B22 & B23); + T[22] = B22 ^ (~B23 & B24); + T[23] = B23 ^ (~B24 & B20); + T[24] = B24 ^ (~B20 & B21); + } + +} + +void SHA_3::permute_bmi2(uint64_t A[25]) + { + static const uint64_t RC[24] = { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, + 0x8000000080008000, 0x000000000000808B, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000A, + 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + + uint64_t T[25]; + + for(size_t i = 0; i != 24; i += 2) + { + SHA3_BMI2_round(T, A, RC[i+0]); + SHA3_BMI2_round(A, T, RC[i+1]); + } + } + +} diff --git a/comm/third_party/botan/src/lib/hash/shake/info.txt b/comm/third_party/botan/src/lib/hash/shake/info.txt new file mode 100644 index 0000000000..59a1a852a9 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/shake/info.txt @@ -0,0 +1,7 @@ + +SHAKE -> 20161009 + + + +sha3 + diff --git a/comm/third_party/botan/src/lib/hash/shake/shake.cpp b/comm/third_party/botan/src/lib/hash/shake/shake.cpp new file mode 100644 index 0000000000..76ed79a274 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/shake/shake.cpp @@ -0,0 +1,97 @@ +/* +* SHAKE-128/256 as a hash +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +SHAKE_128::SHAKE_128(size_t output_bits) : + m_output_bits(output_bits), m_S(25), m_S_pos(0) + { + if(output_bits % 8 != 0) + throw Invalid_Argument("SHAKE_128: Invalid output length " + + std::to_string(output_bits)); + } + +std::string SHAKE_128::name() const + { + return "SHAKE-128(" + std::to_string(m_output_bits) + ")"; + } + +HashFunction* SHAKE_128::clone() const + { + return new SHAKE_128(m_output_bits); + } + +std::unique_ptr SHAKE_128::copy_state() const + { + return std::unique_ptr(new SHAKE_128(*this)); + } + +void SHAKE_128::clear() + { + zeroise(m_S); + m_S_pos = 0; + } + +void SHAKE_128::add_data(const uint8_t input[], size_t length) + { + m_S_pos = SHA_3::absorb(SHAKE_128_BITRATE, m_S, m_S_pos, input, length); + } + +void SHAKE_128::final_result(uint8_t output[]) + { + SHA_3::finish(SHAKE_128_BITRATE, m_S, m_S_pos, 0x1F, 0x80); + SHA_3::expand(SHAKE_128_BITRATE, m_S, output, output_length()); + clear(); + } + +SHAKE_256::SHAKE_256(size_t output_bits) : + m_output_bits(output_bits), m_S(25), m_S_pos(0) + { + if(output_bits % 8 != 0) + throw Invalid_Argument("SHAKE_256: Invalid output length " + + std::to_string(output_bits)); + } + +std::string SHAKE_256::name() const + { + return "SHAKE-256(" + std::to_string(m_output_bits) + ")"; + } + +HashFunction* SHAKE_256::clone() const + { + return new SHAKE_256(m_output_bits); + } + +std::unique_ptr SHAKE_256::copy_state() const + { + return std::unique_ptr(new SHAKE_256(*this)); + } + +void SHAKE_256::clear() + { + zeroise(m_S); + m_S_pos = 0; + } + +void SHAKE_256::add_data(const uint8_t input[], size_t length) + { + m_S_pos = SHA_3::absorb(SHAKE_256_BITRATE, m_S, m_S_pos, input, length); + } + +void SHAKE_256::final_result(uint8_t output[]) + { + SHA_3::finish(SHAKE_256_BITRATE, m_S, m_S_pos, 0x1F, 0x80); + SHA_3::expand(SHAKE_256_BITRATE, m_S, output, output_length()); + + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/shake/shake.h b/comm/third_party/botan/src/lib/hash/shake/shake.h new file mode 100644 index 0000000000..c52df136b7 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/shake/shake.h @@ -0,0 +1,85 @@ +/* +* SHAKE hash functions +* (C) 2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHAKE_HASH_H_ +#define BOTAN_SHAKE_HASH_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(shake.h) + +namespace Botan { + +/** +* SHAKE-128 +*/ +class BOTAN_PUBLIC_API(2,0) SHAKE_128 final : public HashFunction + { + public: + + /** + * @param output_bits the desired output size in bits + * must be a multiple of 8 + */ + explicit SHAKE_128(size_t output_bits); + + size_t hash_block_size() const override { return SHAKE_128_BITRATE / 8; } + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override; + std::unique_ptr copy_state() const override; + std::string name() const override; + void clear() override; + + private: + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + static const size_t SHAKE_128_BITRATE = 1600 - 256; + + size_t m_output_bits; + secure_vector m_S; + size_t m_S_pos; + }; + +/** +* SHAKE-256 +*/ +class BOTAN_PUBLIC_API(2,0) SHAKE_256 final : public HashFunction + { + public: + + /** + * @param output_bits the desired output size in bits + * must be a multiple of 8 + */ + explicit SHAKE_256(size_t output_bits); + + size_t hash_block_size() const override { return SHAKE_256_BITRATE / 8; } + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override; + std::unique_ptr copy_state() const override; + std::string name() const override; + void clear() override; + + private: + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + static const size_t SHAKE_256_BITRATE = 1600 - 512; + + size_t m_output_bits; + secure_vector m_S; + size_t m_S_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/skein/info.txt b/comm/third_party/botan/src/lib/hash/skein/info.txt new file mode 100644 index 0000000000..3445c376fe --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/skein/info.txt @@ -0,0 +1,7 @@ + +SKEIN_512 -> 20131128 + + + +threefish_512 + diff --git a/comm/third_party/botan/src/lib/hash/skein/skein_512.cpp b/comm/third_party/botan/src/lib/hash/skein/skein_512.cpp new file mode 100644 index 0000000000..edf95d5961 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/skein/skein_512.cpp @@ -0,0 +1,178 @@ +/* +* The Skein-512 hash function +* (C) 2009,2010,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +Skein_512::Skein_512(size_t arg_output_bits, + const std::string& arg_personalization) : + m_personalization(arg_personalization), + m_output_bits(arg_output_bits), + m_threefish(new Threefish_512), + m_T(2), m_buffer(64), m_buf_pos(0) + { + if(m_output_bits == 0 || m_output_bits % 8 != 0 || m_output_bits > 512) + throw Invalid_Argument("Bad output bits size for Skein-512"); + + initial_block(); + } + +std::string Skein_512::name() const + { + if(m_personalization != "") + return "Skein-512(" + std::to_string(m_output_bits) + "," + + m_personalization + ")"; + return "Skein-512(" + std::to_string(m_output_bits) + ")"; + } + +HashFunction* Skein_512::clone() const + { + return new Skein_512(m_output_bits, m_personalization); + } + +std::unique_ptr Skein_512::copy_state() const + { + std::unique_ptr copy(new Skein_512(m_output_bits, m_personalization)); + + copy->m_threefish->m_K = this->m_threefish->m_K; + copy->m_T = this->m_T; + copy->m_buffer = this->m_buffer; + copy->m_buf_pos = this->m_buf_pos; + + // work around GCC 4.8 bug + return std::unique_ptr(copy.release()); + } + +void Skein_512::clear() + { + zeroise(m_buffer); + m_buf_pos = 0; + + initial_block(); + } + +void Skein_512::reset_tweak(type_code type, bool is_final) + { + m_T[0] = 0; + + m_T[1] = (static_cast(type) << 56) | + (static_cast(1) << 62) | + (static_cast(is_final) << 63); + } + +void Skein_512::initial_block() + { + const uint8_t zeros[64] = { 0 }; + + m_threefish->set_key(zeros, sizeof(zeros)); + + // ASCII("SHA3") followed by version (0x0001) code + uint8_t config_str[32] = { 0x53, 0x48, 0x41, 0x33, 0x01, 0x00, 0 }; + store_le(uint32_t(m_output_bits), config_str + 8); + + reset_tweak(SKEIN_CONFIG, true); + ubi_512(config_str, sizeof(config_str)); + + if(m_personalization != "") + { + /* + This is a limitation of this implementation, and not of the + algorithm specification. Could be fixed relatively easily, but + doesn't seem worth the trouble. + */ + if(m_personalization.length() > 64) + throw Invalid_Argument("Skein personalization must be less than 64 bytes"); + + const uint8_t* bits = cast_char_ptr_to_uint8(m_personalization.data()); + reset_tweak(SKEIN_PERSONALIZATION, true); + ubi_512(bits, m_personalization.length()); + } + + reset_tweak(SKEIN_MSG, false); + } + +void Skein_512::ubi_512(const uint8_t msg[], size_t msg_len) + { + secure_vector M(8); + + do + { + const size_t to_proc = std::min(msg_len, 64); + m_T[0] += to_proc; + + load_le(M.data(), msg, to_proc / 8); + + if(to_proc % 8) + { + for(size_t j = 0; j != to_proc % 8; ++j) + M[to_proc/8] |= static_cast(msg[8*(to_proc/8)+j]) << (8*j); + } + + m_threefish->skein_feedfwd(M, m_T); + + // clear first flag if set + m_T[1] &= ~(static_cast(1) << 62); + + msg_len -= to_proc; + msg += to_proc; + } while(msg_len); + } + +void Skein_512::add_data(const uint8_t input[], size_t length) + { + if(length == 0) + return; + + if(m_buf_pos) + { + buffer_insert(m_buffer, m_buf_pos, input, length); + if(m_buf_pos + length > 64) + { + ubi_512(m_buffer.data(), m_buffer.size()); + + input += (64 - m_buf_pos); + length -= (64 - m_buf_pos); + m_buf_pos = 0; + } + } + + const size_t full_blocks = (length - 1) / 64; + + if(full_blocks) + ubi_512(input, 64*full_blocks); + + length -= full_blocks * 64; + + buffer_insert(m_buffer, m_buf_pos, input + full_blocks * 64, length); + m_buf_pos += length; + } + +void Skein_512::final_result(uint8_t out[]) + { + m_T[1] |= (static_cast(1) << 63); // final block flag + + for(size_t i = m_buf_pos; i != m_buffer.size(); ++i) + m_buffer[i] = 0; + + ubi_512(m_buffer.data(), m_buf_pos); + + const uint8_t counter[8] = { 0 }; + + reset_tweak(SKEIN_OUTPUT, true); + ubi_512(counter, sizeof(counter)); + + copy_out_vec_le(out, m_output_bits / 8, m_threefish->m_K); + + m_buf_pos = 0; + initial_block(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/skein/skein_512.h b/comm/third_party/botan/src/lib/hash/skein/skein_512.h new file mode 100644 index 0000000000..0bf173cebd --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/skein/skein_512.h @@ -0,0 +1,72 @@ +/* +* The Skein-512 hash function +* (C) 2009,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SKEIN_512_H_ +#define BOTAN_SKEIN_512_H_ + +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(skin_512.h) + +namespace Botan { + +/** +* Skein-512, a SHA-3 candidate +*/ +class BOTAN_PUBLIC_API(2,0) Skein_512 final : public HashFunction + { + public: + /** + * @param output_bits the output size of Skein in bits + * @param personalization is a string that will parameterize the + * hash output + */ + Skein_512(size_t output_bits = 512, + const std::string& personalization = ""); + + size_t hash_block_size() const override { return 64; } + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override; + std::unique_ptr copy_state() const override; + std::string name() const override; + void clear() override; + private: + enum type_code { + SKEIN_KEY = 0, + SKEIN_CONFIG = 4, + SKEIN_PERSONALIZATION = 8, + SKEIN_PUBLIC_KEY = 12, + SKEIN_KEY_IDENTIFIER = 16, + SKEIN_NONCE = 20, + SKEIN_MSG = 48, + SKEIN_OUTPUT = 63 + }; + + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + void ubi_512(const uint8_t msg[], size_t msg_len); + + void initial_block(); + void reset_tweak(type_code type, bool is_final); + + std::string m_personalization; + size_t m_output_bits; + + std::unique_ptr m_threefish; + secure_vector m_T; + secure_vector m_buffer; + size_t m_buf_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/sm3/info.txt b/comm/third_party/botan/src/lib/hash/sm3/info.txt new file mode 100644 index 0000000000..e591a6ce00 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sm3/info.txt @@ -0,0 +1,7 @@ + +SM3 -> 20170402 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/sm3/sm3.cpp b/comm/third_party/botan/src/lib/hash/sm3/sm3.cpp new file mode 100644 index 0000000000..cfd1409cd1 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sm3/sm3.cpp @@ -0,0 +1,259 @@ +/* +* SM3 +* (C) 2017 Ribose Inc. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +std::unique_ptr SM3::copy_state() const + { + return std::unique_ptr(new SM3(*this)); + } + +namespace { + +const uint32_t SM3_IV[] = { + 0x7380166fUL, 0x4914b2b9UL, 0x172442d7UL, 0xda8a0600UL, + 0xa96f30bcUL, 0x163138aaUL, 0xe38dee4dUL, 0xb0fb0e4eUL +}; + +inline uint32_t P0(uint32_t X) + { + return X ^ rotl<9>(X) ^ rotl<17>(X); + } + +inline uint32_t FF1(uint32_t X, uint32_t Y, uint32_t Z) + { + return (X & Y) | ((X | Y) & Z); + //return (X & Y) | (X & Z) | (Y & Z); + } + +inline uint32_t GG1(uint32_t X, uint32_t Y, uint32_t Z) + { + //return (X & Y) | (~X & Z); + return ((Z ^ (X & (Y ^ Z)))); + } + +inline void R1(uint32_t A, uint32_t& B, uint32_t C, uint32_t& D, + uint32_t E, uint32_t& F, uint32_t G, uint32_t& H, + uint32_t TJ, uint32_t Wi, uint32_t Wj) + { + const uint32_t A12 = rotl<12>(A); + const uint32_t SS1 = rotl<7>(A12 + E + TJ); + const uint32_t TT1 = (A ^ B ^ C) + D + (SS1 ^ A12) + Wj; + const uint32_t TT2 = (E ^ F ^ G) + H + SS1 + Wi; + + B = rotl<9>(B); + D = TT1; + F = rotl<19>(F); + H = P0(TT2); + } + +inline void R2(uint32_t A, uint32_t& B, uint32_t C, uint32_t& D, + uint32_t E, uint32_t& F, uint32_t G, uint32_t& H, + uint32_t TJ, uint32_t Wi, uint32_t Wj) + { + const uint32_t A12 = rotl<12>(A); + const uint32_t SS1 = rotl<7>(A12 + E + TJ); + const uint32_t TT1 = FF1(A, B, C) + D + (SS1 ^ A12) + Wj; + const uint32_t TT2 = GG1(E, F, G) + H + SS1 + Wi; + + B = rotl<9>(B); + D = TT1; + F = rotl<19>(F); + H = P0(TT2); + } + +inline uint32_t P1(uint32_t X) + { + return X ^ rotl<15>(X) ^ rotl<23>(X); + } + +inline uint32_t SM3_E(uint32_t W0, uint32_t W7, uint32_t W13, uint32_t W3, uint32_t W10) + { + return P1(W0 ^ W7 ^ rotl<15>(W13)) ^ rotl<7>(W3) ^ W10; + } + +} + +/* +* SM3 Compression Function +*/ +void SM3::compress_n(const uint8_t input[], size_t blocks) + { + uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3], + E = m_digest[4], F = m_digest[5], G = m_digest[6], H = m_digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t W00 = load_be(input, 0); + uint32_t W01 = load_be(input, 1); + uint32_t W02 = load_be(input, 2); + uint32_t W03 = load_be(input, 3); + uint32_t W04 = load_be(input, 4); + uint32_t W05 = load_be(input, 5); + uint32_t W06 = load_be(input, 6); + uint32_t W07 = load_be(input, 7); + uint32_t W08 = load_be(input, 8); + uint32_t W09 = load_be(input, 9); + uint32_t W10 = load_be(input, 10); + uint32_t W11 = load_be(input, 11); + uint32_t W12 = load_be(input, 12); + uint32_t W13 = load_be(input, 13); + uint32_t W14 = load_be(input, 14); + uint32_t W15 = load_be(input, 15); + + R1(A, B, C, D, E, F, G, H, 0x79CC4519, W00, W00 ^ W04); + W00 = SM3_E(W00, W07, W13, W03, W10); + R1(D, A, B, C, H, E, F, G, 0xF3988A32, W01, W01 ^ W05); + W01 = SM3_E(W01, W08, W14, W04, W11); + R1(C, D, A, B, G, H, E, F, 0xE7311465, W02, W02 ^ W06); + W02 = SM3_E(W02, W09, W15, W05, W12); + R1(B, C, D, A, F, G, H, E, 0xCE6228CB, W03, W03 ^ W07); + W03 = SM3_E(W03, W10, W00, W06, W13); + R1(A, B, C, D, E, F, G, H, 0x9CC45197, W04, W04 ^ W08); + W04 = SM3_E(W04, W11, W01, W07, W14); + R1(D, A, B, C, H, E, F, G, 0x3988A32F, W05, W05 ^ W09); + W05 = SM3_E(W05, W12, W02, W08, W15); + R1(C, D, A, B, G, H, E, F, 0x7311465E, W06, W06 ^ W10); + W06 = SM3_E(W06, W13, W03, W09, W00); + R1(B, C, D, A, F, G, H, E, 0xE6228CBC, W07, W07 ^ W11); + W07 = SM3_E(W07, W14, W04, W10, W01); + R1(A, B, C, D, E, F, G, H, 0xCC451979, W08, W08 ^ W12); + W08 = SM3_E(W08, W15, W05, W11, W02); + R1(D, A, B, C, H, E, F, G, 0x988A32F3, W09, W09 ^ W13); + W09 = SM3_E(W09, W00, W06, W12, W03); + R1(C, D, A, B, G, H, E, F, 0x311465E7, W10, W10 ^ W14); + W10 = SM3_E(W10, W01, W07, W13, W04); + R1(B, C, D, A, F, G, H, E, 0x6228CBCE, W11, W11 ^ W15); + W11 = SM3_E(W11, W02, W08, W14, W05); + R1(A, B, C, D, E, F, G, H, 0xC451979C, W12, W12 ^ W00); + W12 = SM3_E(W12, W03, W09, W15, W06); + R1(D, A, B, C, H, E, F, G, 0x88A32F39, W13, W13 ^ W01); + W13 = SM3_E(W13, W04, W10, W00, W07); + R1(C, D, A, B, G, H, E, F, 0x11465E73, W14, W14 ^ W02); + W14 = SM3_E(W14, W05, W11, W01, W08); + R1(B, C, D, A, F, G, H, E, 0x228CBCE6, W15, W15 ^ W03); + W15 = SM3_E(W15, W06, W12, W02, W09); + R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); + W00 = SM3_E(W00, W07, W13, W03, W10); + R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); + W01 = SM3_E(W01, W08, W14, W04, W11); + R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); + W02 = SM3_E(W02, W09, W15, W05, W12); + R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); + W03 = SM3_E(W03, W10, W00, W06, W13); + R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); + W04 = SM3_E(W04, W11, W01, W07, W14); + R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); + W05 = SM3_E(W05, W12, W02, W08, W15); + R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); + W06 = SM3_E(W06, W13, W03, W09, W00); + R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); + W07 = SM3_E(W07, W14, W04, W10, W01); + R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); + W08 = SM3_E(W08, W15, W05, W11, W02); + R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); + W09 = SM3_E(W09, W00, W06, W12, W03); + R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); + W10 = SM3_E(W10, W01, W07, W13, W04); + R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); + W11 = SM3_E(W11, W02, W08, W14, W05); + R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); + W12 = SM3_E(W12, W03, W09, W15, W06); + R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); + W13 = SM3_E(W13, W04, W10, W00, W07); + R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); + W14 = SM3_E(W14, W05, W11, W01, W08); + R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); + W15 = SM3_E(W15, W06, W12, W02, W09); + R2(A, B, C, D, E, F, G, H, 0x7A879D8A, W00, W00 ^ W04); + W00 = SM3_E(W00, W07, W13, W03, W10); + R2(D, A, B, C, H, E, F, G, 0xF50F3B14, W01, W01 ^ W05); + W01 = SM3_E(W01, W08, W14, W04, W11); + R2(C, D, A, B, G, H, E, F, 0xEA1E7629, W02, W02 ^ W06); + W02 = SM3_E(W02, W09, W15, W05, W12); + R2(B, C, D, A, F, G, H, E, 0xD43CEC53, W03, W03 ^ W07); + W03 = SM3_E(W03, W10, W00, W06, W13); + R2(A, B, C, D, E, F, G, H, 0xA879D8A7, W04, W04 ^ W08); + W04 = SM3_E(W04, W11, W01, W07, W14); + R2(D, A, B, C, H, E, F, G, 0x50F3B14F, W05, W05 ^ W09); + W05 = SM3_E(W05, W12, W02, W08, W15); + R2(C, D, A, B, G, H, E, F, 0xA1E7629E, W06, W06 ^ W10); + W06 = SM3_E(W06, W13, W03, W09, W00); + R2(B, C, D, A, F, G, H, E, 0x43CEC53D, W07, W07 ^ W11); + W07 = SM3_E(W07, W14, W04, W10, W01); + R2(A, B, C, D, E, F, G, H, 0x879D8A7A, W08, W08 ^ W12); + W08 = SM3_E(W08, W15, W05, W11, W02); + R2(D, A, B, C, H, E, F, G, 0x0F3B14F5, W09, W09 ^ W13); + W09 = SM3_E(W09, W00, W06, W12, W03); + R2(C, D, A, B, G, H, E, F, 0x1E7629EA, W10, W10 ^ W14); + W10 = SM3_E(W10, W01, W07, W13, W04); + R2(B, C, D, A, F, G, H, E, 0x3CEC53D4, W11, W11 ^ W15); + W11 = SM3_E(W11, W02, W08, W14, W05); + R2(A, B, C, D, E, F, G, H, 0x79D8A7A8, W12, W12 ^ W00); + W12 = SM3_E(W12, W03, W09, W15, W06); + R2(D, A, B, C, H, E, F, G, 0xF3B14F50, W13, W13 ^ W01); + W13 = SM3_E(W13, W04, W10, W00, W07); + R2(C, D, A, B, G, H, E, F, 0xE7629EA1, W14, W14 ^ W02); + W14 = SM3_E(W14, W05, W11, W01, W08); + R2(B, C, D, A, F, G, H, E, 0xCEC53D43, W15, W15 ^ W03); + W15 = SM3_E(W15, W06, W12, W02, W09); + R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04); + W00 = SM3_E(W00, W07, W13, W03, W10); + R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05); + W01 = SM3_E(W01, W08, W14, W04, W11); + R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06); + W02 = SM3_E(W02, W09, W15, W05, W12); + R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07); + W03 = SM3_E(W03, W10, W00, W06, W13); + R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08); + R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09); + R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10); + R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11); + R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12); + R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13); + R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14); + R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15); + R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00); + R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01); + R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02); + R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03); + + A = (m_digest[0] ^= A); + B = (m_digest[1] ^= B); + C = (m_digest[2] ^= C); + D = (m_digest[3] ^= D); + E = (m_digest[4] ^= E); + F = (m_digest[5] ^= F); + G = (m_digest[6] ^= G); + H = (m_digest[7] ^= H); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void SM3::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SM3::clear() + { + MDx_HashFunction::clear(); + std::copy(std::begin(SM3_IV), std::end(SM3_IV), m_digest.begin()); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/sm3/sm3.h b/comm/third_party/botan/src/lib/hash/sm3/sm3.h new file mode 100644 index 0000000000..268bd87fb3 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/sm3/sm3.h @@ -0,0 +1,49 @@ +/* +* SM3 +* (C) 2017 Ribose Inc. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SM3_H_ +#define BOTAN_SM3_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sm3.h) + +namespace Botan { + +enum { + SM3_BLOCK_BYTES = 64, + SM3_DIGEST_BYTES = 32 +}; + +/** +* SM3 +*/ +class BOTAN_PUBLIC_API(2,2) SM3 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SM3"; } + size_t output_length() const override { return SM3_DIGEST_BYTES; } + HashFunction* clone() const override { return new SM3; } + std::unique_ptr copy_state() const override; + + void clear() override; + + SM3() : MDx_HashFunction(SM3_BLOCK_BYTES, true, true), m_digest(SM3_DIGEST_BYTES) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + /** + * The digest value + */ + secure_vector m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/streebog/info.txt b/comm/third_party/botan/src/lib/hash/streebog/info.txt new file mode 100644 index 0000000000..1a8bae57fa --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/streebog/info.txt @@ -0,0 +1,3 @@ + +STREEBOG -> 20170623 + diff --git a/comm/third_party/botan/src/lib/hash/streebog/streebog.cpp b/comm/third_party/botan/src/lib/hash/streebog/streebog.cpp new file mode 100644 index 0000000000..0134daded2 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/streebog/streebog.cpp @@ -0,0 +1,207 @@ +/* +* Streebog +* (C) 2017 Ribose Inc. +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +extern const uint64_t STREEBOG_Ax[8][256]; +extern const uint64_t STREEBOG_C[12][8]; + +std::unique_ptr Streebog::copy_state() const + { + return std::unique_ptr(new Streebog(*this)); + } + +Streebog::Streebog(size_t output_bits) : + m_output_bits(output_bits), + m_count(0), + m_position(0), + m_buffer(64), + m_h(8), + m_S(8) + { + if(output_bits != 256 && output_bits != 512) + throw Invalid_Argument("Streebog: Invalid output length " + + std::to_string(output_bits)); + + clear(); + } + +std::string Streebog::name() const + { + return "Streebog-" + std::to_string(m_output_bits); + } + +/* +* Clear memory of sensitive data +*/ +void Streebog::clear() + { + m_count = 0; + m_position = 0; + zeroise(m_buffer); + zeroise(m_S); + + const uint64_t fill = (m_output_bits == 512) ? 0 : 0x0101010101010101; + std::fill(m_h.begin(), m_h.end(), fill); + } + +/* +* Update the hash +*/ +void Streebog::add_data(const uint8_t input[], size_t length) + { + const size_t block_size = m_buffer.size(); + + if(m_position) + { + buffer_insert(m_buffer, m_position, input, length); + + if(m_position + length >= block_size) + { + compress(m_buffer.data()); + m_count += 512; + input += (block_size - m_position); + length -= (block_size - m_position); + m_position = 0; + } + } + + const size_t full_blocks = length / block_size; + const size_t remaining = length % block_size; + + for(size_t i = 0; i != full_blocks; ++i) + { + compress(input + block_size * i); + m_count += 512; + } + + buffer_insert(m_buffer, m_position, input + full_blocks * block_size, remaining); + m_position += remaining; + } + +/* +* Finalize a hash +*/ +void Streebog::final_result(uint8_t output[]) + { + m_buffer[m_position++] = 0x01; + + if(m_position != m_buffer.size()) + clear_mem(&m_buffer[m_position], m_buffer.size() - m_position); + + compress(m_buffer.data()); + m_count += (m_position - 1) * 8; + + zeroise(m_buffer); + store_le(m_count, m_buffer.data()); + compress(m_buffer.data(), true); + + compress_64(m_S.data(), true); + // FIXME + std::memcpy(output, &m_h[8 - output_length() / 8], output_length()); + clear(); + } + +namespace { + +inline uint64_t force_le(uint64_t x) + { +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + return x; +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + return reverse_bytes(x); +#else + store_le(x, reinterpret_cast(&x)); + return x; +#endif + } + +inline void lps(uint64_t block[8]) + { + uint8_t r[64]; + // FIXME + std::memcpy(r, block, 64); + + for(int i = 0; i < 8; ++i) + { + block[i] = force_le(STREEBOG_Ax[0][r[i + 0*8]]) ^ + force_le(STREEBOG_Ax[1][r[i + 1*8]]) ^ + force_le(STREEBOG_Ax[2][r[i + 2*8]]) ^ + force_le(STREEBOG_Ax[3][r[i + 3*8]]) ^ + force_le(STREEBOG_Ax[4][r[i + 4*8]]) ^ + force_le(STREEBOG_Ax[5][r[i + 5*8]]) ^ + force_le(STREEBOG_Ax[6][r[i + 6*8]]) ^ + force_le(STREEBOG_Ax[7][r[i + 7*8]]); + } + } + +} //namespace + +void Streebog::compress(const uint8_t input[], bool last_block) + { + uint64_t M[8]; + std::memcpy(M, input, 64); + + compress_64(M, last_block); + } + +void Streebog::compress_64(const uint64_t M[], bool last_block) + { + uint64_t N = force_le(last_block ? 0ULL : m_count); + + uint64_t hN[8]; + uint64_t A[8]; + + copy_mem(hN, m_h.data(), 8); + hN[0] ^= N; + lps(hN); + + copy_mem(A, hN, 8); + + for(size_t i = 0; i != 8; ++i) + { + hN[i] ^= M[i]; + } + + for(size_t i = 0; i < 12; ++i) + { + for(size_t j = 0; j != 8; ++j) + A[j] ^= force_le(STREEBOG_C[i][j]); + lps(A); + + lps(hN); + for(size_t j = 0; j != 8; ++j) + hN[j] ^= A[j]; + } + + for(size_t i = 0; i != 8; ++i) + { + m_h[i] ^= hN[i] ^ M[i]; + } + + if(!last_block) + { + uint64_t carry = 0; + for(int i = 0; i < 8; i++) + { + const uint64_t m = force_le(M[i]); + const uint64_t hi = force_le(m_S[i]); + const uint64_t t = hi + m + carry; + + m_S[i] = force_le(t); + if(t != m) + carry = (t < m); + } + } + } + +} diff --git a/comm/third_party/botan/src/lib/hash/streebog/streebog.h b/comm/third_party/botan/src/lib/hash/streebog/streebog.h new file mode 100644 index 0000000000..a573964d8e --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/streebog/streebog.h @@ -0,0 +1,72 @@ +/* +* Streebog +* (C) 2017 Ribose Inc. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREEBOG_H_ +#define BOTAN_STREEBOG_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(streebog.h) + +namespace Botan { + +/** +* Streebog (GOST R 34.11-2012) +* RFC 6986 +*/ +class BOTAN_PUBLIC_API(2,2) Streebog : public HashFunction + { + public: + size_t output_length() const override { return m_output_bits / 8; } + + HashFunction* clone() const override { return new Streebog(m_output_bits); } + void clear() override; + std::string name() const override; + size_t hash_block_size() const override { return 64; } + + std::unique_ptr copy_state() const override; + + explicit Streebog(size_t output_bits); + protected: + void add_data(const uint8_t input[], size_t length) override; + void final_result(uint8_t out[]) override; + + void compress(const uint8_t input[], bool lastblock = false); + + void compress_64(const uint64_t input[], bool lastblock = false); + + private: + const size_t m_output_bits; + uint64_t m_count; + size_t m_position; + secure_vector m_buffer; + secure_vector m_h; + secure_vector m_S; + }; + + +/** +* Streebog-256 +*/ +class BOTAN_PUBLIC_API(2,2) Streebog_256 final : public Streebog + { + public: + Streebog_256() : Streebog(256) {} + }; + +/** +* Streebog-512 +*/ +class BOTAN_PUBLIC_API(2,2) Streebog_512 final : public Streebog + { + public: + Streebog_512() : Streebog(512) {} + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/streebog/streebog_precalc.cpp b/comm/third_party/botan/src/lib/hash/streebog/streebog_precalc.cpp new file mode 100644 index 0000000000..cf28379327 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/streebog/streebog_precalc.cpp @@ -0,0 +1,866 @@ +/* + * Derived from: + * https://github.com/degtyarevalexey/streebog + * + * Copyright (c) 2013, Alexey Degtyarev . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +namespace Botan { + +extern const uint64_t STREEBOG_Ax[8][256] = + { + { + 0xd01f715b5c7ef8e6ULL, 0x16fa240980778325ULL, 0xa8a42e857ee049c8ULL, + 0x6ac1068fa186465bULL, 0x6e417bd7a2e9320bULL, 0x665c8167a437daabULL, + 0x7666681aa89617f6ULL, 0x4b959163700bdcf5ULL, 0xf14be6b78df36248ULL, + 0xc585bd689a625cffULL, 0x9557d7fca67d82cbULL, 0x89f0b969af6dd366ULL, + 0xb0833d48749f6c35ULL, 0xa1998c23b1ecbc7cULL, 0x8d70c431ac02a736ULL, + 0xd6dfbc2fd0a8b69eULL, 0x37aeb3e551fa198bULL, 0x0b7d128a40b5cf9cULL, + 0x5a8f2008b5780cbcULL, 0xedec882284e333e5ULL, 0xd25fc177d3c7c2ceULL, + 0x5e0f5d50b61778ecULL, 0x1d873683c0c24cb9ULL, 0xad040bcbb45d208cULL, + 0x2f89a0285b853c76ULL, 0x5732fff6791b8d58ULL, 0x3e9311439ef6ec3fULL, + 0xc9183a809fd3c00fULL, 0x83adf3f5260a01eeULL, 0xa6791941f4e8ef10ULL, + 0x103ae97d0ca1cd5dULL, 0x2ce948121dee1b4aULL, 0x39738421dbf2bf53ULL, + 0x093da2a6cf0cf5b4ULL, 0xcd9847d89cbcb45fULL, 0xf9561c078b2d8ae8ULL, + 0x9c6a755a6971777fULL, 0xbc1ebaa0712ef0c5ULL, 0x72e61542abf963a6ULL, + 0x78bb5fde229eb12eULL, 0x14ba94250fceb90dULL, 0x844d6697630e5282ULL, + 0x98ea08026a1e032fULL, 0xf06bbea144217f5cULL, 0xdb6263d11ccb377aULL, + 0x641c314b2b8ee083ULL, 0x320e96ab9b4770cfULL, 0x1ee7deb986a96b85ULL, + 0xe96cf57a878c47b5ULL, 0xfdd6615f8842feb8ULL, 0xc83862965601dd1bULL, + 0x2ea9f83e92572162ULL, 0xf876441142ff97fcULL, 0xeb2c455608357d9dULL, + 0x5612a7e0b0c9904cULL, 0x6c01cbfb2d500823ULL, 0x4548a6a7fa037a2dULL, + 0xabc4c6bf388b6ef4ULL, 0xbade77d4fdf8bebdULL, 0x799b07c8eb4cac3aULL, + 0x0c9d87e805b19cf0ULL, 0xcb588aac106afa27ULL, 0xea0c1d40c1e76089ULL, + 0x2869354a1e816f1aULL, 0xff96d17307fbc490ULL, 0x9f0a9d602f1a5043ULL, + 0x96373fc6e016a5f7ULL, 0x5292dab8b3a6e41cULL, 0x9b8ae0382c752413ULL, + 0x4f15ec3b7364a8a5ULL, 0x3fb349555724f12bULL, 0xc7c50d4415db66d7ULL, + 0x92b7429ee379d1a7ULL, 0xd37f99611a15dfdaULL, 0x231427c05e34a086ULL, + 0xa439a96d7b51d538ULL, 0xb403401077f01865ULL, 0xdda2aea5901d7902ULL, + 0x0a5d4a9c8967d288ULL, 0xc265280adf660f93ULL, 0x8bb0094520d4e94eULL, + 0x2a29856691385532ULL, 0x42a833c5bf072941ULL, 0x73c64d54622b7eb2ULL, + 0x07e095624504536cULL, 0x8a905153e906f45aULL, 0x6f6123c16b3b2f1fULL, + 0xc6e55552dc097bc3ULL, 0x4468feb133d16739ULL, 0xe211e7f0c7398829ULL, + 0xa2f96419f7879b40ULL, 0x19074bdbc3ad38e9ULL, 0xf4ebc3f9474e0b0cULL, + 0x43886bd376d53455ULL, 0xd8028beb5aa01046ULL, 0x51f23282f5cdc320ULL, + 0xe7b1c2be0d84e16dULL, 0x081dfab006dee8a0ULL, 0x3b33340d544b857bULL, + 0x7f5bcabc679ae242ULL, 0x0edd37c48a08a6d8ULL, 0x81ed43d9a9b33bc6ULL, + 0xb1a3655ebd4d7121ULL, 0x69a1eeb5e7ed6167ULL, 0xf6ab73d5c8f73124ULL, + 0x1a67a3e185c61fd5ULL, 0x2dc91004d43c065eULL, 0x0240b02c8fb93a28ULL, + 0x90f7f2b26cc0eb8fULL, 0x3cd3a16f114fd617ULL, 0xaae49ea9f15973e0ULL, + 0x06c0cd748cd64e78ULL, 0xda423bc7d5192a6eULL, 0xc345701c16b41287ULL, + 0x6d2193ede4821537ULL, 0xfcf639494190e3acULL, 0x7c3b228621f1c57eULL, + 0xfb16ac2b0494b0c0ULL, 0xbf7e529a3745d7f9ULL, 0x6881b6a32e3f7c73ULL, + 0xca78d2bad9b8e733ULL, 0xbbfe2fc2342aa3a9ULL, 0x0dbddffecc6381e4ULL, + 0x70a6a56e2440598eULL, 0xe4d12a844befc651ULL, 0x8c509c2765d0ba22ULL, + 0xee8c6018c28814d9ULL, 0x17da7c1f49a59e31ULL, 0x609c4c1328e194d3ULL, + 0xb3e3d57232f44b09ULL, 0x91d7aaa4a512f69bULL, 0x0ffd6fd243dabbccULL, + 0x50d26a943c1fde34ULL, 0x6be15e9968545b4fULL, 0x94778fea6faf9fdfULL, + 0x2b09dd7058ea4826ULL, 0x677cd9716de5c7bfULL, 0x49d5214fffb2e6ddULL, + 0x0360e83a466b273cULL, 0x1fc786af4f7b7691ULL, 0xa0b9d435783ea168ULL, + 0xd49f0c035f118cb6ULL, 0x01205816c9d21d14ULL, 0xac2453dd7d8f3d98ULL, + 0x545217cc3f70aa64ULL, 0x26b4028e9489c9c2ULL, 0xdec2469fd6765e3eULL, + 0x04807d58036f7450ULL, 0xe5f17292823ddb45ULL, 0xf30b569b024a5860ULL, + 0x62dcfc3fa758aefbULL, 0xe84cad6c4e5e5aa1ULL, 0xccb81fce556ea94bULL, + 0x53b282ae7a74f908ULL, 0x1b47fbf74c1402c1ULL, 0x368eebf39828049fULL, + 0x7afbeff2ad278b06ULL, 0xbe5e0a8cfe97caedULL, 0xcfd8f7f413058e77ULL, + 0xf78b2bc301252c30ULL, 0x4d555c17fcdd928dULL, 0x5f2f05467fc565f8ULL, + 0x24f4b2a21b30f3eaULL, 0x860dd6bbecb768aaULL, 0x4c750401350f8f99ULL, + 0x0000000000000000ULL, 0xecccd0344d312ef1ULL, 0xb5231806be220571ULL, + 0xc105c030990d28afULL, 0x653c695de25cfd97ULL, 0x159acc33c61ca419ULL, + 0xb89ec7f872418495ULL, 0xa9847693b73254dcULL, 0x58cf90243ac13694ULL, + 0x59efc832f3132b80ULL, 0x5c4fed7c39ae42c4ULL, 0x828dabe3efd81cfaULL, + 0xd13f294d95ace5f2ULL, 0x7d1b7a90e823d86aULL, 0xb643f03cf849224dULL, + 0x3df3f979d89dcb03ULL, 0x7426d836272f2ddeULL, 0xdfe21e891fa4432aULL, + 0x3a136c1b9d99986fULL, 0xfa36f43dcd46add4ULL, 0xc025982650df35bbULL, + 0x856d3e81aadc4f96ULL, 0xc4a5e57e53b041ebULL, 0x4708168b75ba4005ULL, + 0xaf44bbe73be41aa4ULL, 0x971767d029c4b8e3ULL, 0xb9be9feebb939981ULL, + 0x215497ecd18d9aaeULL, 0x316e7e91dd2c57f3ULL, 0xcef8afe2dad79363ULL, + 0x3853dc371220a247ULL, 0x35ee03c9de4323a3ULL, 0xe6919aa8c456fc79ULL, + 0xe05157dc4880b201ULL, 0x7bdbb7e464f59612ULL, 0x127a59518318f775ULL, + 0x332ecebd52956ddbULL, 0x8f30741d23bb9d1eULL, 0xd922d3fd93720d52ULL, + 0x7746300c61440ae2ULL, 0x25d4eab4d2e2eefeULL, 0x75068020eefd30caULL, + 0x135a01474acaea61ULL, 0x304e268714fe4ae7ULL, 0xa519f17bb283c82cULL, + 0xdc82f6b359cf6416ULL, 0x5baf781e7caa11a8ULL, 0xb2c38d64fb26561dULL, + 0x34ce5bdf17913eb7ULL, 0x5d6fb56af07c5fd0ULL, 0x182713cd0a7f25fdULL, + 0x9e2ac576e6c84d57ULL, 0x9aaab82ee5a73907ULL, 0xa3d93c0f3e558654ULL, + 0x7e7b92aaae48ff56ULL, 0x872d8ead256575beULL, 0x41c8dbfff96c0e7dULL, + 0x99ca5014a3cc1e3bULL, 0x40e883e930be1369ULL, 0x1ca76e95091051adULL, + 0x4e35b42dbab6b5b1ULL, 0x05a0254ecabd6944ULL, 0xe1710fca8152af15ULL, + 0xf22b0e8dcb984574ULL, 0xb763a82a319b3f59ULL, 0x63fca4296e8ab3efULL, + 0x9d4a2d4ca0a36a6bULL, 0xe331bfe60eeb953dULL, 0xd5bf541596c391a2ULL, + 0xf5cb9bef8e9c1618ULL, 0x46284e9dbc685d11ULL, 0x2074cffa185f87baULL, + 0xbd3ee2b6b8fcedd1ULL, 0xae64e3f1f23607b0ULL, 0xfeb68965ce29d984ULL, + 0x55724fdaf6a2b770ULL, 0x29496d5cd753720eULL, 0xa75941573d3af204ULL, + 0x8e102c0bea69800aULL, 0x111ab16bc573d049ULL, 0xd7ffe439197aab8aULL, + 0xefac380e0b5a09cdULL, 0x48f579593660fbc9ULL, 0x22347fd697e6bd92ULL, + 0x61bc1405e13389c7ULL, 0x4ab5c975b9d9c1e1ULL, 0x80cd1bcf606126d2ULL, + 0x7186fd78ed92449aULL, 0x93971a882aabccb3ULL, 0x88d0e17f66bfce72ULL, + 0x27945a985d5bd4d6ULL + }, + { + 0xde553f8c05a811c8ULL, 0x1906b59631b4f565ULL, 0x436e70d6b1964ff7ULL, + 0x36d343cb8b1e9d85ULL, 0x843dfacc858aab5aULL, 0xfdfc95c299bfc7f9ULL, + 0x0f634bdea1d51fa2ULL, 0x6d458b3b76efb3cdULL, 0x85c3f77cf8593f80ULL, + 0x3c91315fbe737cb2ULL, 0x2148b03366ace398ULL, 0x18f8b8264c6761bfULL, + 0xc830c1c495c9fb0fULL, 0x981a76102086a0aaULL, 0xaa16012142f35760ULL, + 0x35cc54060c763cf6ULL, 0x42907d66cc45db2dULL, 0x8203d44b965af4bcULL, + 0x3d6f3cefc3a0e868ULL, 0xbc73ff69d292bda7ULL, 0x8722ed0102e20a29ULL, + 0x8f8185e8cd34deb7ULL, 0x9b0561dda7ee01d9ULL, 0x5335a0193227fad6ULL, + 0xc9cecc74e81a6fd5ULL, 0x54f5832e5c2431eaULL, 0x99e47ba05d553470ULL, + 0xf7bee756acd226ceULL, 0x384e05a5571816fdULL, 0xd1367452a47d0e6aULL, + 0xf29fde1c386ad85bULL, 0x320c77316275f7caULL, 0xd0c879e2d9ae9ab0ULL, + 0xdb7406c69110ef5dULL, 0x45505e51a2461011ULL, 0xfc029872e46c5323ULL, + 0xfa3cb6f5f7bc0cc5ULL, 0x031f17cd8768a173ULL, 0xbd8df2d9af41297dULL, + 0x9d3b4f5ab43e5e3fULL, 0x4071671b36feee84ULL, 0x716207e7d3e3b83dULL, + 0x48d20ff2f9283a1aULL, 0x27769eb4757cbc7eULL, 0x5c56ebc793f2e574ULL, + 0xa48b474f9ef5dc18ULL, 0x52cbada94ff46e0cULL, 0x60c7da982d8199c6ULL, + 0x0e9d466edc068b78ULL, 0x4eec2175eaf865fcULL, 0x550b8e9e21f7a530ULL, + 0x6b7ba5bc653fec2bULL, 0x5eb7f1ba6949d0ddULL, 0x57ea94e3db4c9099ULL, + 0xf640eae6d101b214ULL, 0xdd4a284182c0b0bbULL, 0xff1d8fbf6304f250ULL, + 0xb8accb933bf9d7e8ULL, 0xe8867c478eb68c4dULL, 0x3f8e2692391bddc1ULL, + 0xcb2fd60912a15a7cULL, 0xaec935dbab983d2fULL, 0xf55ffd2b56691367ULL, + 0x80e2ce366ce1c115ULL, 0x179bf3f8edb27e1dULL, 0x01fe0db07dd394daULL, + 0xda8a0b76ecc37b87ULL, 0x44ae53e1df9584cbULL, 0xb310b4b77347a205ULL, + 0xdfab323c787b8512ULL, 0x3b511268d070b78eULL, 0x65e6e3d2b9396753ULL, + 0x6864b271e2574d58ULL, 0x259784c98fc789d7ULL, 0x02e11a7dfabb35a9ULL, + 0x8841a6dfa337158bULL, 0x7ade78c39b5dcdd0ULL, 0xb7cf804d9a2cc84aULL, + 0x20b6bd831b7f7742ULL, 0x75bd331d3a88d272ULL, 0x418f6aab4b2d7a5eULL, + 0xd9951cbb6babdaf4ULL, 0xb6318dfde7ff5c90ULL, 0x1f389b112264aa83ULL, + 0x492c024284fbaec0ULL, 0xe33a0363c608f9a0ULL, 0x2688930408af28a4ULL, + 0xc7538a1a341ce4adULL, 0x5da8e677ee2171aeULL, 0x8c9e92254a5c7fc4ULL, + 0x63d8cd55aae938b5ULL, 0x29ebd8daa97a3706ULL, 0x959827b37be88aa1ULL, + 0x1484e4356adadf6eULL, 0xa7945082199d7d6bULL, 0xbf6ce8a455fa1cd4ULL, + 0x9cc542eac9edcae5ULL, 0x79c16f0e1c356ca3ULL, 0x89bfab6fdee48151ULL, + 0xd4174d1830c5f0ffULL, 0x9258048415eb419dULL, 0x6139d72850520d1cULL, + 0x6a85a80c18ec78f1ULL, 0xcd11f88e0171059aULL, 0xcceff53e7ca29140ULL, + 0xd229639f2315af19ULL, 0x90b91ef9ef507434ULL, 0x5977d28d074a1be1ULL, + 0x311360fce51d56b9ULL, 0xc093a92d5a1f2f91ULL, 0x1a19a25bb6dc5416ULL, + 0xeb996b8a09de2d3eULL, 0xfee3820f1ed7668aULL, 0xd7085ad5b7ad518cULL, + 0x7fff41890fe53345ULL, 0xec5948bd67dde602ULL, 0x2fd5f65dbaaa68e0ULL, + 0xa5754affe32648c2ULL, 0xf8ddac880d07396cULL, 0x6fa491468c548664ULL, + 0x0c7c5c1326bdbed1ULL, 0x4a33158f03930fb3ULL, 0x699abfc19f84d982ULL, + 0xe4fa2054a80b329cULL, 0x6707f9af438252faULL, 0x08a368e9cfd6d49eULL, + 0x47b1442c58fd25b8ULL, 0xbbb3dc5ebc91769bULL, 0x1665fe489061eac7ULL, + 0x33f27a811fa66310ULL, 0x93a609346838d547ULL, 0x30ed6d4c98cec263ULL, + 0x1dd9816cd8df9f2aULL, 0x94662a03063b1e7bULL, 0x83fdd9fbeb896066ULL, + 0x7b207573e68e590aULL, 0x5f49fc0a149a4407ULL, 0x343259b671a5a82cULL, + 0xfbc2bb458a6f981fULL, 0xc272b350a0a41a38ULL, 0x3aaf1fd8ada32354ULL, + 0x6cbb868b0b3c2717ULL, 0xa2b569c88d2583feULL, 0xf180c9d1bf027928ULL, + 0xaf37386bd64ba9f5ULL, 0x12bacab2790a8088ULL, 0x4c0d3b0810435055ULL, + 0xb2eeb9070e9436dfULL, 0xc5b29067cea7d104ULL, 0xdcb425f1ff132461ULL, + 0x4f122cc5972bf126ULL, 0xac282fa651230886ULL, 0xe7e537992f6393efULL, + 0xe61b3a2952b00735ULL, 0x709c0a57ae302ce7ULL, 0xe02514ae416058d3ULL, + 0xc44c9dd7b37445deULL, 0x5a68c5408022ba92ULL, 0x1c278cdca50c0bf0ULL, + 0x6e5a9cf6f18712beULL, 0x86dce0b17f319ef3ULL, 0x2d34ec2040115d49ULL, + 0x4bcd183f7e409b69ULL, 0x2815d56ad4a9a3dcULL, 0x24698979f2141d0dULL, + 0x0000000000000000ULL, 0x1ec696a15fb73e59ULL, 0xd86b110b16784e2eULL, + 0x8e7f8858b0e74a6dULL, 0x063e2e8713d05fe6ULL, 0xe2c40ed3bbdb6d7aULL, + 0xb1f1aeca89fc97acULL, 0xe1db191e3cb3cc09ULL, 0x6418ee62c4eaf389ULL, + 0xc6ad87aa49cf7077ULL, 0xd6f65765ca7ec556ULL, 0x9afb6c6dda3d9503ULL, + 0x7ce05644888d9236ULL, 0x8d609f95378feb1eULL, 0x23a9aa4e9c17d631ULL, + 0x6226c0e5d73aac6fULL, 0x56149953a69f0443ULL, 0xeeb852c09d66d3abULL, + 0x2b0ac2a753c102afULL, 0x07c023376e03cb3cULL, 0x2ccae1903dc2c993ULL, + 0xd3d76e2f5ec63bc3ULL, 0x9e2458973356ff4cULL, 0xa66a5d32644ee9b1ULL, + 0x0a427294356de137ULL, 0x783f62be61e6f879ULL, 0x1344c70204d91452ULL, + 0x5b96c8f0fdf12e48ULL, 0xa90916ecc59bf613ULL, 0xbe92e5142829880eULL, + 0x727d102a548b194eULL, 0x1be7afebcb0fc0ccULL, 0x3e702b2244c8491bULL, + 0xd5e940a84d166425ULL, 0x66f9f41f3e51c620ULL, 0xabe80c913f20c3baULL, + 0xf07ec461c2d1edf2ULL, 0xf361d3ac45b94c81ULL, 0x0521394a94b8fe95ULL, + 0xadd622162cf09c5cULL, 0xe97871f7f3651897ULL, 0xf4a1f09b2bba87bdULL, + 0x095d6559b2054044ULL, 0x0bbc7f2448be75edULL, 0x2af4cf172e129675ULL, + 0x157ae98517094bb4ULL, 0x9fda55274e856b96ULL, 0x914713499283e0eeULL, + 0xb952c623462a4332ULL, 0x74433ead475b46a8ULL, 0x8b5eb112245fb4f8ULL, + 0xa34b6478f0f61724ULL, 0x11a5dd7ffe6221fbULL, 0xc16da49d27ccbb4bULL, + 0x76a224d0bde07301ULL, 0x8aa0bca2598c2022ULL, 0x4df336b86d90c48fULL, + 0xea67663a740db9e4ULL, 0xef465f70e0b54771ULL, 0x39b008152acb8227ULL, + 0x7d1e5bf4f55e06ecULL, 0x105bd0cf83b1b521ULL, 0x775c2960c033e7dbULL, + 0x7e014c397236a79fULL, 0x811cc386113255cfULL, 0xeda7450d1a0e72d8ULL, + 0x5889df3d7a998f3bULL, 0x2e2bfbedc779fc3aULL, 0xce0eef438619a4e9ULL, + 0x372d4e7bf6cd095fULL, 0x04df34fae96b6a4fULL, 0xf923a13870d4adb6ULL, + 0xa1aa7e050a4d228dULL, 0xa8f71b5cb84862c9ULL, 0xb52e9a306097fde3ULL, + 0x0d8251a35b6e2a0bULL, 0x2257a7fee1c442ebULL, 0x73831d9a29588d94ULL, + 0x51d4ba64c89ccf7fULL, 0x502ab7d4b54f5ba5ULL, 0x97793dce8153bf08ULL, + 0xe5042de4d5d8a646ULL, 0x9687307efc802bd2ULL, 0xa05473b5779eb657ULL, + 0xb4d097801d446939ULL, 0xcff0e2f3fbca3033ULL, 0xc38cbee0dd778ee2ULL, + 0x464f499c252eb162ULL, 0xcad1dbb96f72cea6ULL, 0xba4dd1eec142e241ULL, + 0xb00fa37af42f0376ULL + }, + { + 0xcce4cd3aa968b245ULL, 0x089d5484e80b7fafULL, 0x638246c1b3548304ULL, + 0xd2fe0ec8c2355492ULL, 0xa7fbdf7ff2374eeeULL, 0x4df1600c92337a16ULL, + 0x84e503ea523b12fbULL, 0x0790bbfd53ab0c4aULL, 0x198a780f38f6ea9dULL, + 0x2ab30c8f55ec48cbULL, 0xe0f7fed6b2c49db5ULL, 0xb6ecf3f422cadbdcULL, + 0x409c9a541358df11ULL, 0xd3ce8a56dfde3fe3ULL, 0xc3e9224312c8c1a0ULL, + 0x0d6dfa58816ba507ULL, 0xddf3e1b179952777ULL, 0x04c02a42748bb1d9ULL, + 0x94c2abff9f2decb8ULL, 0x4f91752da8f8acf4ULL, 0x78682befb169bf7bULL, + 0xe1c77a48af2ff6c4ULL, 0x0c5d7ec69c80ce76ULL, 0x4cc1e4928fd81167ULL, + 0xfeed3d24d9997b62ULL, 0x518bb6dfc3a54a23ULL, 0x6dbf2d26151f9b90ULL, + 0xb5bc624b05ea664fULL, 0xe86aaa525acfe21aULL, 0x4801ced0fb53a0beULL, + 0xc91463e6c00868edULL, 0x1027a815cd16fe43ULL, 0xf67069a0319204cdULL, + 0xb04ccc976c8abce7ULL, 0xc0b9b3fc35e87c33ULL, 0xf380c77c58f2de65ULL, + 0x50bb3241de4e2152ULL, 0xdf93f490435ef195ULL, 0xf1e0d25d62390887ULL, + 0xaf668bfb1a3c3141ULL, 0xbc11b251f00a7291ULL, 0x73a5eed47e427d47ULL, + 0x25bee3f6ee4c3b2eULL, 0x43cc0beb34786282ULL, 0xc824e778dde3039cULL, + 0xf97d86d98a327728ULL, 0xf2b043e24519b514ULL, 0xe297ebf7880f4b57ULL, + 0x3a94a49a98fab688ULL, 0x868516cb68f0c419ULL, 0xeffa11af0964ee50ULL, + 0xa4ab4ec0d517f37dULL, 0xa9c6b498547c567aULL, 0x8e18424f80fbbbb6ULL, + 0x0bcdc53bcf2bc23cULL, 0x137739aaea3643d0ULL, 0x2c1333ec1bac2ff0ULL, + 0x8d48d3f0a7db0625ULL, 0x1e1ac3f26b5de6d7ULL, 0xf520f81f16b2b95eULL, + 0x9f0f6ec450062e84ULL, 0x0130849e1deb6b71ULL, 0xd45e31ab8c7533a9ULL, + 0x652279a2fd14e43fULL, 0x3209f01e70f1c927ULL, 0xbe71a770cac1a473ULL, + 0x0e3d6be7a64b1894ULL, 0x7ec8148cff29d840ULL, 0xcb7476c7fac3be0fULL, + 0x72956a4a63a91636ULL, 0x37f95ec21991138fULL, 0x9e3fea5a4ded45f5ULL, + 0x7b38ba50964902e8ULL, 0x222e580bbde73764ULL, 0x61e253e0899f55e6ULL, + 0xfc8d2805e352ad80ULL, 0x35994be3235ac56dULL, 0x09add01af5e014deULL, + 0x5e8659a6780539c6ULL, 0xb17c48097161d796ULL, 0x026015213acbd6e2ULL, + 0xd1ae9f77e515e901ULL, 0xb7dc776a3f21b0adULL, 0xaba6a1b96eb78098ULL, + 0x9bcf4486248d9f5dULL, 0x582666c536455efdULL, 0xfdbdac9bfeb9c6f1ULL, + 0xc47999be4163cdeaULL, 0x765540081722a7efULL, 0x3e548ed8ec710751ULL, + 0x3d041f67cb51bac2ULL, 0x7958af71ac82d40aULL, 0x36c9da5c047a78feULL, + 0xed9a048e33af38b2ULL, 0x26ee7249c96c86bdULL, 0x900281bdeba65d61ULL, + 0x11172c8bd0fd9532ULL, 0xea0abf73600434f8ULL, 0x42fc8f75299309f3ULL, + 0x34a9cf7d3eb1ae1cULL, 0x2b838811480723baULL, 0x5ce64c8742ceef24ULL, + 0x1adae9b01fd6570eULL, 0x3c349bf9d6bad1b3ULL, 0x82453c891c7b75c0ULL, + 0x97923a40b80d512bULL, 0x4a61dbf1c198765cULL, 0xb48ce6d518010d3eULL, + 0xcfb45c858e480fd6ULL, 0xd933cbf30d1e96aeULL, 0xd70ea014ab558e3aULL, + 0xc189376228031742ULL, 0x9262949cd16d8b83ULL, 0xeb3a3bed7def5f89ULL, + 0x49314a4ee6b8cbcfULL, 0xdcc3652f647e4c06ULL, 0xda635a4c2a3e2b3dULL, + 0x470c21a940f3d35bULL, 0x315961a157d174b4ULL, 0x6672e81dda3459acULL, + 0x5b76f77a1165e36eULL, 0x445cb01667d36ec8ULL, 0xc5491d205c88a69bULL, + 0x456c34887a3805b9ULL, 0xffddb9bac4721013ULL, 0x99af51a71e4649bfULL, + 0xa15be01cbc7729d5ULL, 0x52db2760e485f7b0ULL, 0x8c78576eba306d54ULL, + 0xae560f6507d75a30ULL, 0x95f22f6182c687c9ULL, 0x71c5fbf54489aba5ULL, + 0xca44f259e728d57eULL, 0x88b87d2ccebbdc8dULL, 0xbab18d32be4a15aaULL, + 0x8be8ec93e99b611eULL, 0x17b713e89ebdf209ULL, 0xb31c5d284baa0174ULL, + 0xeeca9531148f8521ULL, 0xb8d198138481c348ULL, 0x8988f9b2d350b7fcULL, + 0xb9e11c8d996aa839ULL, 0x5a4673e40c8e881fULL, 0x1687977683569978ULL, + 0xbf4123eed72acf02ULL, 0x4ea1f1b3b513c785ULL, 0xe767452be16f91ffULL, + 0x7505d1b730021a7cULL, 0xa59bca5ec8fc980cULL, 0xad069eda20f7e7a3ULL, + 0x38f4b1bba231606aULL, 0x60d2d77e94743e97ULL, 0x9affc0183966f42cULL, + 0x248e6768f3a7505fULL, 0xcdd449a4b483d934ULL, 0x87b59255751baf68ULL, + 0x1bea6d2e023d3c7fULL, 0x6b1f12455b5ffcabULL, 0x743555292de9710dULL, + 0xd8034f6d10f5fddfULL, 0xc6198c9f7ba81b08ULL, 0xbb8109aca3a17edbULL, + 0xfa2d1766ad12cabbULL, 0xc729080166437079ULL, 0x9c5fff7b77269317ULL, + 0x0000000000000000ULL, 0x15d706c9a47624ebULL, 0x6fdf38072fd44d72ULL, + 0x5fb6dd3865ee52b7ULL, 0xa33bf53d86bcff37ULL, 0xe657c1b5fc84fa8eULL, + 0xaa962527735cebe9ULL, 0x39c43525bfda0b1bULL, 0x204e4d2a872ce186ULL, + 0x7a083ece8ba26999ULL, 0x554b9c9db72efbfaULL, 0xb22cd9b656416a05ULL, + 0x96a2bedea5e63a5aULL, 0x802529a826b0a322ULL, 0x8115ad363b5bc853ULL, + 0x8375b81701901eb1ULL, 0x3069e53f4a3a1fc5ULL, 0xbd2136cfede119e0ULL, + 0x18bafc91251d81ecULL, 0x1d4a524d4c7d5b44ULL, 0x05f0aedc6960daa8ULL, + 0x29e39d3072ccf558ULL, 0x70f57f6b5962c0d4ULL, 0x989fd53903ad22ceULL, + 0xf84d024797d91c59ULL, 0x547b1803aac5908bULL, 0xf0d056c37fd263f6ULL, + 0xd56eb535919e58d8ULL, 0x1c7ad6d351963035ULL, 0x2e7326cd2167f912ULL, + 0xac361a443d1c8cd2ULL, 0x697f076461942a49ULL, 0x4b515f6fdc731d2dULL, + 0x8ad8680df4700a6fULL, 0x41ac1eca0eb3b460ULL, 0x7d988533d80965d3ULL, + 0xa8f6300649973d0bULL, 0x7765c4960ac9cc9eULL, 0x7ca801adc5e20ea2ULL, + 0xdea3700e5eb59ae4ULL, 0xa06b6482a19c42a4ULL, 0x6a2f96db46b497daULL, + 0x27def6d7d487edccULL, 0x463ca5375d18b82aULL, 0xa6cb5be1efdc259fULL, + 0x53eba3fef96e9cc1ULL, 0xce84d81b93a364a7ULL, 0xf4107c810b59d22fULL, + 0x333974806d1aa256ULL, 0x0f0def79bba073e5ULL, 0x231edc95a00c5c15ULL, + 0xe437d494c64f2c6cULL, 0x91320523f64d3610ULL, 0x67426c83c7df32ddULL, + 0x6eefbc99323f2603ULL, 0x9d6f7be56acdf866ULL, 0x5916e25b2bae358cULL, + 0x7ff89012e2c2b331ULL, 0x035091bf2720bd93ULL, 0x561b0d22900e4669ULL, + 0x28d319ae6f279e29ULL, 0x2f43a2533c8c9263ULL, 0xd09e1be9f8fe8270ULL, + 0xf740ed3e2c796fbcULL, 0xdb53ded237d5404cULL, 0x62b2c25faebfe875ULL, + 0x0afd41a5d2c0a94dULL, 0x6412fd3ce0ff8f4eULL, 0xe3a76f6995e42026ULL, + 0x6c8fa9b808f4f0e1ULL, 0xc2d9a6dd0f23aad1ULL, 0x8f28c6d19d10d0c7ULL, + 0x85d587744fd0798aULL, 0xa20b71a39b579446ULL, 0x684f83fa7c7f4138ULL, + 0xe507500adba4471dULL, 0x3f640a46f19a6c20ULL, 0x1247bd34f7dd28a1ULL, + 0x2d23b77206474481ULL, 0x93521002cc86e0f2ULL, 0x572b89bc8de52d18ULL, + 0xfb1d93f8b0f9a1caULL, 0xe95a2ecc4724896bULL, 0x3ba420048511ddf9ULL, + 0xd63e248ab6bee54bULL, 0x5dd6c8195f258455ULL, 0x06a03f634e40673bULL, + 0x1f2a476c76b68da6ULL, 0x217ec9b49ac78af7ULL, 0xecaa80102e4453c3ULL, + 0x14e78257b99d4f9aULL + }, + { + 0x20329b2cc87bba05ULL, 0x4f5eb6f86546a531ULL, 0xd4f44775f751b6b1ULL, + 0x8266a47b850dfa8bULL, 0xbb986aa15a6ca985ULL, 0xc979eb08f9ae0f99ULL, + 0x2da6f447a2375ea1ULL, 0x1e74275dcd7d8576ULL, 0xbc20180a800bc5f8ULL, + 0xb4a2f701b2dc65beULL, 0xe726946f981b6d66ULL, 0x48e6c453bf21c94cULL, + 0x42cad9930f0a4195ULL, 0xefa47b64aacccd20ULL, 0x71180a8960409a42ULL, + 0x8bb3329bf6a44e0cULL, 0xd34c35de2d36daccULL, 0xa92f5b7cbc23dc96ULL, + 0xb31a85aa68bb09c3ULL, 0x13e04836a73161d2ULL, 0xb24dfc4129c51d02ULL, + 0x8ae44b70b7da5acdULL, 0xe671ed84d96579a7ULL, 0xa4bb3417d66f3832ULL, + 0x4572ab38d56d2de8ULL, 0xb1b47761ea47215cULL, 0xe81c09cf70aba15dULL, + 0xffbdb872ce7f90acULL, 0xa8782297fd5dc857ULL, 0x0d946f6b6a4ce4a4ULL, + 0xe4df1f4f5b995138ULL, 0x9ebc71edca8c5762ULL, 0x0a2c1dc0b02b88d9ULL, + 0x3b503c115d9d7b91ULL, 0xc64376a8111ec3a2ULL, 0xcec199a323c963e4ULL, + 0xdc76a87ec58616f7ULL, 0x09d596e073a9b487ULL, 0x14583a9d7d560dafULL, + 0xf4c6dc593f2a0cb4ULL, 0xdd21d19584f80236ULL, 0x4a4836983ddde1d3ULL, + 0xe58866a41ae745f9ULL, 0xf591a5b27e541875ULL, 0x891dc05074586693ULL, + 0x5b068c651810a89eULL, 0xa30346bc0c08544fULL, 0x3dbf3751c684032dULL, + 0x2a1e86ec785032dcULL, 0xf73f5779fca830eaULL, 0xb60c05ca30204d21ULL, + 0x0cc316802b32f065ULL, 0x8770241bdd96be69ULL, 0xb861e18199ee95dbULL, + 0xf805cad91418fcd1ULL, 0x29e70dccbbd20e82ULL, 0xc7140f435060d763ULL, + 0x0f3a9da0e8b0cc3bULL, 0xa2543f574d76408eULL, 0xbd7761e1c175d139ULL, + 0x4b1f4f737ca3f512ULL, 0x6dc2df1f2fc137abULL, 0xf1d05c3967b14856ULL, + 0xa742bf3715ed046cULL, 0x654030141d1697edULL, 0x07b872abda676c7dULL, + 0x3ce84eba87fa17ecULL, 0xc1fb0403cb79afdfULL, 0x3e46bc7105063f73ULL, + 0x278ae987121cd678ULL, 0xa1adb4778ef47cd0ULL, 0x26dd906c5362c2b9ULL, + 0x05168060589b44e2ULL, 0xfbfc41f9d79ac08fULL, 0x0e6de44ba9ced8faULL, + 0x9feb08068bf243a3ULL, 0x7b341749d06b129bULL, 0x229c69e74a87929aULL, + 0xe09ee6c4427c011bULL, 0x5692e30e725c4c3aULL, 0xda99a33e5e9f6e4bULL, + 0x353dd85af453a36bULL, 0x25241b4c90e0fee7ULL, 0x5de987258309d022ULL, + 0xe230140fc0802984ULL, 0x93281e86a0c0b3c6ULL, 0xf229d719a4337408ULL, + 0x6f6c2dd4ad3d1f34ULL, 0x8ea5b2fbae3f0aeeULL, 0x8331dd90c473ee4aULL, + 0x346aa1b1b52db7aaULL, 0xdf8f235e06042aa9ULL, 0xcc6f6b68a1354b7bULL, + 0x6c95a6f46ebf236aULL, 0x52d31a856bb91c19ULL, 0x1a35ded6d498d555ULL, + 0xf37eaef2e54d60c9ULL, 0x72e181a9a3c2a61cULL, 0x98537aad51952fdeULL, + 0x16f6c856ffaa2530ULL, 0xd960281e9d1d5215ULL, 0x3a0745fa1ce36f50ULL, + 0x0b7b642bf1559c18ULL, 0x59a87eae9aec8001ULL, 0x5e100c05408bec7cULL, + 0x0441f98b19e55023ULL, 0xd70dcc5534d38aefULL, 0x927f676de1bea707ULL, + 0x9769e70db925e3e5ULL, 0x7a636ea29115065aULL, 0x468b201816ef11b6ULL, + 0xab81a9b73edff409ULL, 0xc0ac7de88a07bb1eULL, 0x1f235eb68c0391b7ULL, + 0x6056b074458dd30fULL, 0xbe8eeac102f7ed67ULL, 0xcd381283e04b5fbaULL, + 0x5cbefecec277c4e3ULL, 0xd21b4c356c48ce0dULL, 0x1019c31664b35d8cULL, + 0x247362a7d19eea26ULL, 0xebe582efb3299d03ULL, 0x02aef2cb82fc289fULL, + 0x86275df09ce8aaa8ULL, 0x28b07427faac1a43ULL, 0x38a9b7319e1f47cfULL, + 0xc82e92e3b8d01b58ULL, 0x06ef0b409b1978bcULL, 0x62f842bfc771fb90ULL, + 0x9904034610eb3b1fULL, 0xded85ab5477a3e68ULL, 0x90d195a663428f98ULL, + 0x5384636e2ac708d8ULL, 0xcbd719c37b522706ULL, 0xae9729d76644b0ebULL, + 0x7c8c65e20a0c7ee6ULL, 0x80c856b007f1d214ULL, 0x8c0b40302cc32271ULL, + 0xdbcedad51fe17a8aULL, 0x740e8ae938dbdea0ULL, 0xa615c6dc549310adULL, + 0x19cc55f6171ae90bULL, 0x49b1bdb8fe5fdd8dULL, 0xed0a89af2830e5bfULL, + 0x6a7aadb4f5a65bd6ULL, 0x7e22972988f05679ULL, 0xf952b3325566e810ULL, + 0x39fecedadf61530eULL, 0x6101c99f04f3c7ceULL, 0x2e5f7f6761b562ffULL, + 0xf08725d226cf5c97ULL, 0x63af3b54860fef51ULL, 0x8ff2cb10ef411e2fULL, + 0x884ab9bb35267252ULL, 0x4df04433e7ba8daeULL, 0x9afd8866d3690741ULL, + 0x66b9bb34de94abb3ULL, 0x9baaf18d92171380ULL, 0x543c11c5f0a064a5ULL, + 0x17a1b1bdbed431f1ULL, 0xb5f58eeaf3a2717fULL, 0xc355f6c849858740ULL, + 0xec5df044694ef17eULL, 0xd83751f5dc6346d4ULL, 0xfc4433520dfdacf2ULL, + 0x0000000000000000ULL, 0x5a51f58e596ebc5fULL, 0x3285aaf12e34cf16ULL, + 0x8d5c39db6dbd36b0ULL, 0x12b731dde64f7513ULL, 0x94906c2d7aa7dfbbULL, + 0x302b583aacc8e789ULL, 0x9d45facd090e6b3cULL, 0x2165e2c78905aec4ULL, + 0x68d45f7f775a7349ULL, 0x189b2c1d5664fdcaULL, 0xe1c99f2f030215daULL, + 0x6983269436246788ULL, 0x8489af3b1e148237ULL, 0xe94b702431d5b59cULL, + 0x33d2d31a6f4adbd7ULL, 0xbfd9932a4389f9a6ULL, 0xb0e30e8aab39359dULL, + 0xd1e2c715afcaf253ULL, 0x150f43763c28196eULL, 0xc4ed846393e2eb3dULL, + 0x03f98b20c3823c5eULL, 0xfd134ab94c83b833ULL, 0x556b682eb1de7064ULL, + 0x36c4537a37d19f35ULL, 0x7559f30279a5ca61ULL, 0x799ae58252973a04ULL, + 0x9c12832648707ffdULL, 0x78cd9c6913e92ec5ULL, 0x1d8dac7d0effb928ULL, + 0x439da0784e745554ULL, 0x413352b3cc887dcbULL, 0xbacf134a1b12bd44ULL, + 0x114ebafd25cd494dULL, 0x2f08068c20cb763eULL, 0x76a07822ba27f63fULL, + 0xeab2fb04f25789c2ULL, 0xe3676de481fe3d45ULL, 0x1b62a73d95e6c194ULL, + 0x641749ff5c68832cULL, 0xa5ec4dfc97112cf3ULL, 0xf6682e92bdd6242bULL, + 0x3f11c59a44782bb2ULL, 0x317c21d1edb6f348ULL, 0xd65ab5be75ad9e2eULL, + 0x6b2dd45fb4d84f17ULL, 0xfaab381296e4d44eULL, 0xd0b5befeeeb4e692ULL, + 0x0882ef0b32d7a046ULL, 0x512a91a5a83b2047ULL, 0x963e9ee6f85bf724ULL, + 0x4e09cf132438b1f0ULL, 0x77f701c9fb59e2feULL, 0x7ddb1c094b726a27ULL, + 0x5f4775ee01f5f8bdULL, 0x9186ec4d223c9b59ULL, 0xfeeac1998f01846dULL, + 0xac39db1ce4b89874ULL, 0xb75b7c21715e59e0ULL, 0xafc0503c273aa42aULL, + 0x6e3b543fec430bf5ULL, 0x704f7362213e8e83ULL, 0x58ff0745db9294c0ULL, + 0x67eec2df9feabf72ULL, 0xa0facd9ccf8a6811ULL, 0xb936986ad890811aULL, + 0x95c715c63bd9cb7aULL, 0xca8060283a2c33c7ULL, 0x507de84ee9453486ULL, + 0x85ded6d05f6a96f6ULL, 0x1cdad5964f81ade9ULL, 0xd5a33e9eb62fa270ULL, + 0x40642b588df6690aULL, 0x7f75eec2c98e42b8ULL, 0x2cf18dace3494a60ULL, + 0x23cb100c0bf9865bULL, 0xeef3028febb2d9e1ULL, 0x4425d2d394133929ULL, + 0xaad6d05c7fa1e0c8ULL, 0xad6ea2f7a5c68cb5ULL, 0xc2028f2308fb9381ULL, + 0x819f2f5b468fc6d5ULL, 0xc5bafd88d29cfffcULL, 0x47dc59f357910577ULL, + 0x2b49ff07392e261dULL, 0x57c59ae5332258fbULL, 0x73b6f842e2bcb2ddULL, + 0xcf96e04862b77725ULL, 0x4ca73dd8a6c4996fULL, 0x015779eb417e14c1ULL, + 0x37932a9176af8bf4ULL + }, + { + 0x190a2c9b249df23eULL, 0x2f62f8b62263e1e9ULL, 0x7a7f754740993655ULL, + 0x330b7ba4d5564d9fULL, 0x4c17a16a46672582ULL, 0xb22f08eb7d05f5b8ULL, + 0x535f47f40bc148ccULL, 0x3aec5d27d4883037ULL, 0x10ed0a1825438f96ULL, + 0x516101f72c233d17ULL, 0x13cc6f949fd04eaeULL, 0x739853c441474bfdULL, + 0x653793d90d3f5b1bULL, 0x5240647b96b0fc2fULL, 0x0c84890ad27623e0ULL, + 0xd7189b32703aaea3ULL, 0x2685de3523bd9c41ULL, 0x99317c5b11bffefaULL, + 0x0d9baa854f079703ULL, 0x70b93648fbd48ac5ULL, 0xa80441fce30bc6beULL, + 0x7287704bdc36ff1eULL, 0xb65384ed33dc1f13ULL, 0xd36417343ee34408ULL, + 0x39cd38ab6e1bf10fULL, 0x5ab861770a1f3564ULL, 0x0ebacf09f594563bULL, + 0xd04572b884708530ULL, 0x3cae9722bdb3af47ULL, 0x4a556b6f2f5cbaf2ULL, + 0xe1704f1f76c4bd74ULL, 0x5ec4ed7144c6dfcfULL, 0x16afc01d4c7810e6ULL, + 0x283f113cd629ca7aULL, 0xaf59a8761741ed2dULL, 0xeed5a3991e215facULL, + 0x3bf37ea849f984d4ULL, 0xe413e096a56ce33cULL, 0x2c439d3a98f020d1ULL, + 0x637559dc6404c46bULL, 0x9e6c95d1e5f5d569ULL, 0x24bb9836045fe99aULL, + 0x44efa466dac8ecc9ULL, 0xc6eab2a5c80895d6ULL, 0x803b50c035220cc4ULL, + 0x0321658cba93c138ULL, 0x8f9ebc465dc7ee1cULL, 0xd15a5137190131d3ULL, + 0x0fa5ec8668e5e2d8ULL, 0x91c979578d1037b1ULL, 0x0642ca05693b9f70ULL, + 0xefca80168350eb4fULL, 0x38d21b24f36a45ecULL, 0xbeab81e1af73d658ULL, + 0x8cbfd9cae7542f24ULL, 0xfd19cc0d81f11102ULL, 0x0ac6430fbb4dbc90ULL, + 0x1d76a09d6a441895ULL, 0x2a01573ff1cbbfa1ULL, 0xb572e161894fde2bULL, + 0x8124734fa853b827ULL, 0x614b1fdf43e6b1b0ULL, 0x68ac395c4238cc18ULL, + 0x21d837bfd7f7b7d2ULL, 0x20c714304a860331ULL, 0x5cfaab726324aa14ULL, + 0x74c5ba4eb50d606eULL, 0xf3a3030474654739ULL, 0x23e671bcf015c209ULL, + 0x45f087e947b9582aULL, 0xd8bd77b418df4c7bULL, 0xe06f6c90ebb50997ULL, + 0x0bd96080263c0873ULL, 0x7e03f9410e40dcfeULL, 0xb8e94be4c6484928ULL, + 0xfb5b0608e8ca8e72ULL, 0x1a2b49179e0e3306ULL, 0x4e29e76961855059ULL, + 0x4f36c4e6fcf4e4baULL, 0x49740ee395cf7bcaULL, 0xc2963ea386d17f7dULL, + 0x90d65ad810618352ULL, 0x12d34c1b02a1fa4dULL, 0xfa44258775bb3a91ULL, + 0x18150f14b9ec46ddULL, 0x1491861e6b9a653dULL, 0x9a1019d7ab2c3fc2ULL, + 0x3668d42d06fe13d7ULL, 0xdcc1fbb25606a6d0ULL, 0x969490dd795a1c22ULL, + 0x3549b1a1bc6dd2efULL, 0xc94f5e23a0ed770eULL, 0xb9f6686b5b39fdcbULL, + 0xc4d4f4a6efeae00dULL, 0xe732851a1fff2204ULL, 0x94aad6de5eb869f9ULL, + 0x3f8ff2ae07206e7fULL, 0xfe38a9813b62d03aULL, 0xa7a1ad7a8bee2466ULL, + 0x7b6056c8dde882b6ULL, 0x302a1e286fc58ca7ULL, 0x8da0fa457a259bc7ULL, + 0xb3302b64e074415bULL, 0x5402ae7eff8b635fULL, 0x08f8050c9cafc94bULL, + 0xae468bf98a3059ceULL, 0x88c355cca98dc58fULL, 0xb10e6d67c7963480ULL, + 0xbad70de7e1aa3cf3ULL, 0xbfb4a26e320262bbULL, 0xcb711820870f02d5ULL, + 0xce12b7a954a75c9dULL, 0x563ce87dd8691684ULL, 0x9f73b65e7884618aULL, + 0x2b1e74b06cba0b42ULL, 0x47cec1ea605b2df1ULL, 0x1c698312f735ac76ULL, + 0x5fdbcefed9b76b2cULL, 0x831a354c8fb1cdfcULL, 0x820516c312c0791fULL, + 0xb74ca762aeadabf0ULL, 0xfc06ef821c80a5e1ULL, 0x5723cbf24518a267ULL, + 0x9d4df05d5f661451ULL, 0x588627742dfd40bfULL, 0xda8331b73f3d39a0ULL, + 0x17b0e392d109a405ULL, 0xf965400bcf28fba9ULL, 0x7c3dbf4229a2a925ULL, + 0x023e460327e275dbULL, 0x6cd0b55a0ce126b3ULL, 0xe62da695828e96e7ULL, + 0x42ad6e63b3f373b9ULL, 0xe50cc319381d57dfULL, 0xc5cbd729729b54eeULL, + 0x46d1e265fd2a9912ULL, 0x6428b056904eeff8ULL, 0x8be23040131e04b7ULL, + 0x6709d5da2add2ec0ULL, 0x075de98af44a2b93ULL, 0x8447dcc67bfbe66fULL, + 0x6616f655b7ac9a23ULL, 0xd607b8bded4b1a40ULL, 0x0563af89d3a85e48ULL, + 0x3db1b4ad20c21ba4ULL, 0x11f22997b8323b75ULL, 0x292032b34b587e99ULL, + 0x7f1cdace9331681dULL, 0x8e819fc9c0b65affULL, 0xa1e3677fe2d5bb16ULL, + 0xcd33d225ee349da5ULL, 0xd9a2543b85aef898ULL, 0x795e10cbfa0af76dULL, + 0x25a4bbb9992e5d79ULL, 0x78413344677b438eULL, 0xf0826688cef68601ULL, + 0xd27b34bba392f0ebULL, 0x551d8df162fad7bcULL, 0x1e57c511d0d7d9adULL, + 0xdeffbdb171e4d30bULL, 0xf4feea8e802f6caaULL, 0xa480c8f6317de55eULL, + 0xa0fc44f07fa40ff5ULL, 0x95b5f551c3c9dd1aULL, 0x22f952336d6476eaULL, + 0x0000000000000000ULL, 0xa6be8ef5169f9085ULL, 0xcc2cf1aa73452946ULL, + 0x2e7ddb39bf12550aULL, 0xd526dd3157d8db78ULL, 0x486b2d6c08becf29ULL, + 0x9b0f3a58365d8b21ULL, 0xac78cdfaadd22c15ULL, 0xbc95c7e28891a383ULL, + 0x6a927f5f65dab9c3ULL, 0xc3891d2c1ba0cb9eULL, 0xeaa92f9f50f8b507ULL, + 0xcf0d9426c9d6e87eULL, 0xca6e3baf1a7eb636ULL, 0xab25247059980786ULL, + 0x69b31ad3df4978fbULL, 0xe2512a93cc577c4cULL, 0xff278a0ea61364d9ULL, + 0x71a615c766a53e26ULL, 0x89dc764334fc716cULL, 0xf87a638452594f4aULL, + 0xf2bc208be914f3daULL, 0x8766b94ac1682757ULL, 0xbbc82e687cdb8810ULL, + 0x626a7a53f9757088ULL, 0xa2c202f358467a2eULL, 0x4d0882e5db169161ULL, + 0x09e7268301de7da8ULL, 0xe897699c771ac0dcULL, 0xc8507dac3d9cc3edULL, + 0xc0a878a0a1330aa6ULL, 0x978bb352e42ba8c1ULL, 0xe9884a13ea6b743fULL, + 0x279afdbabecc28a2ULL, 0x047c8c064ed9eaabULL, 0x507e2278b15289f4ULL, + 0x599904fbb08cf45cULL, 0xbd8ae46d15e01760ULL, 0x31353da7f2b43844ULL, + 0x8558ff49e68a528cULL, 0x76fbfc4d92ef15b5ULL, 0x3456922e211c660cULL, + 0x86799ac55c1993b4ULL, 0x3e90d1219a51da9cULL, 0x2d5cbeb505819432ULL, + 0x982e5fd48cce4a19ULL, 0xdb9c1238a24c8d43ULL, 0xd439febecaa96f9bULL, + 0x418c0bef0960b281ULL, 0x158ea591f6ebd1deULL, 0x1f48e69e4da66d4eULL, + 0x8afd13cf8e6fb054ULL, 0xf5e1c9011d5ed849ULL, 0xe34e091c5126c8afULL, + 0xad67ee7530a398f6ULL, 0x43b24dec2e82c75aULL, 0x75da99c1287cd48dULL, + 0x92e81cdb3783f689ULL, 0xa3dd217cc537cecdULL, 0x60543c50de970553ULL, + 0x93f73f54aaf2426aULL, 0xa91b62737e7a725dULL, 0xf19d4507538732e2ULL, + 0x77e4dfc20f9ea156ULL, 0x7d229ccdb4d31dc6ULL, 0x1b346a98037f87e5ULL, + 0xedf4c615a4b29e94ULL, 0x4093286094110662ULL, 0xb0114ee85ae78063ULL, + 0x6ff1d0d6b672e78bULL, 0x6dcf96d591909250ULL, 0xdfe09e3eec9567e8ULL, + 0x3214582b4827f97cULL, 0xb46dc2ee143e6ac8ULL, 0xf6c0ac8da7cd1971ULL, + 0xebb60c10cd8901e4ULL, 0xf7df8f023abcad92ULL, 0x9c52d3d2c217a0b2ULL, + 0x6b8d5cd0f8ab0d20ULL, 0x3777f7a29b8fa734ULL, 0x011f238f9d71b4e3ULL, + 0xc1b75b2f3c42be45ULL, 0x5de588fdfe551ef7ULL, 0x6eeef3592b035368ULL, + 0xaa3a07ffc4e9b365ULL, 0xecebe59a39c32a77ULL, 0x5ba742f8976e8187ULL, + 0x4b4a48e0b22d0e11ULL, 0xddded83dcb771233ULL, 0xa59feb79ac0c51bdULL, + 0xc7f5912a55792135ULL + }, + { + 0x6d6ae04668a9b08aULL, 0x3ab3f04b0be8c743ULL, 0xe51e166b54b3c908ULL, + 0xbe90a9eb35c2f139ULL, 0xb2c7066637f2bec1ULL, 0xaa6945613392202cULL, + 0x9a28c36f3b5201ebULL, 0xddce5a93ab536994ULL, 0x0e34133ef6382827ULL, + 0x52a02ba1ec55048bULL, 0xa2f88f97c4b2a177ULL, 0x8640e513ca2251a5ULL, + 0xcdf1d36258137622ULL, 0xfe6cb708dedf8ddbULL, 0x8a174a9ec8121e5dULL, + 0x679896036b81560eULL, 0x59ed033395795feeULL, 0x1dd778ab8b74edafULL, + 0xee533ef92d9f926dULL, 0x2a8c79baf8a8d8f5ULL, 0x6bcf398e69b119f6ULL, + 0xe20491742fafdd95ULL, 0x276488e0809c2aecULL, 0xea955b82d88f5cceULL, + 0x7102c63a99d9e0c4ULL, 0xf9763017a5c39946ULL, 0x429fa2501f151b3dULL, + 0x4659c72bea05d59eULL, 0x984b7fdccf5a6634ULL, 0xf742232953fbb161ULL, + 0x3041860e08c021c7ULL, 0x747bfd9616cd9386ULL, 0x4bb1367192312787ULL, + 0x1b72a1638a6c44d3ULL, 0x4a0e68a6e8359a66ULL, 0x169a5039f258b6caULL, + 0xb98a2ef44edee5a4ULL, 0xd9083fe85e43a737ULL, 0x967f6ce239624e13ULL, + 0x8874f62d3c1a7982ULL, 0x3c1629830af06e3fULL, 0x9165ebfd427e5a8eULL, + 0xb5dd81794ceeaa5cULL, 0x0de8f15a7834f219ULL, 0x70bd98ede3dd5d25ULL, + 0xaccc9ca9328a8950ULL, 0x56664eda1945ca28ULL, 0x221db34c0f8859aeULL, + 0x26dbd637fa98970dULL, 0x1acdffb4f068f932ULL, 0x4585254f64090fa0ULL, + 0x72de245e17d53afaULL, 0x1546b25d7c546cf4ULL, 0x207e0ffffb803e71ULL, + 0xfaaad2732bcf4378ULL, 0xb462dfae36ea17bdULL, 0xcf926fd1ac1b11fdULL, + 0xe0672dc7dba7ba4aULL, 0xd3fa49ad5d6b41b3ULL, 0x8ba81449b216a3bcULL, + 0x14f9ec8a0650d115ULL, 0x40fc1ee3eb1d7ce2ULL, 0x23a2ed9b758ce44fULL, + 0x782c521b14fddc7eULL, 0x1c68267cf170504eULL, 0xbcf31558c1ca96e6ULL, + 0xa781b43b4ba6d235ULL, 0xf6fd7dfe29ff0c80ULL, 0xb0a4bad5c3fad91eULL, + 0xd199f51ea963266cULL, 0x414340349119c103ULL, 0x5405f269ed4dadf7ULL, + 0xabd61bb649969dcdULL, 0x6813dbeae7bdc3c8ULL, 0x65fb2ab09f8931d1ULL, + 0xf1e7fae152e3181dULL, 0xc1a67cef5a2339daULL, 0x7a4feea8e0f5bba1ULL, + 0x1e0b9acf05783791ULL, 0x5b8ebf8061713831ULL, 0x80e53cdbcb3af8d9ULL, + 0x7e898bd315e57502ULL, 0xc6bcfbf0213f2d47ULL, 0x95a38e86b76e942dULL, + 0x092e94218d243cbaULL, 0x8339debf453622e7ULL, 0xb11be402b9fe64ffULL, + 0x57d9100d634177c9ULL, 0xcc4e8db52217cbc3ULL, 0x3b0cae9c71ec7aa2ULL, + 0xfb158ca451cbfe99ULL, 0x2b33276d82ac6514ULL, 0x01bf5ed77a04bde1ULL, + 0xc5601994af33f779ULL, 0x75c4a3416cc92e67ULL, 0xf3844652a6eb7fc2ULL, + 0x3487e375fdd0ef64ULL, 0x18ae430704609eedULL, 0x4d14efb993298efbULL, + 0x815a620cb13e4538ULL, 0x125c354207487869ULL, 0x9eeea614ce42cf48ULL, + 0xce2d3106d61fac1cULL, 0xbbe99247bad6827bULL, 0x071a871f7b1c149dULL, + 0x2e4a1cc10db81656ULL, 0x77a71ff298c149b8ULL, 0x06a5d9c80118a97cULL, + 0xad73c27e488e34b1ULL, 0x443a7b981e0db241ULL, 0xe3bbcfa355ab6074ULL, + 0x0af276450328e684ULL, 0x73617a896dd1871bULL, 0x58525de4ef7de20fULL, + 0xb7be3dcab8e6cd83ULL, 0x19111dd07e64230cULL, 0x842359a03e2a367aULL, + 0x103f89f1f3401fb6ULL, 0xdc710444d157d475ULL, 0xb835702334da5845ULL, + 0x4320fc876511a6dcULL, 0xd026abc9d3679b8dULL, 0x17250eee885c0b2bULL, + 0x90dab52a387ae76fULL, 0x31fed8d972c49c26ULL, 0x89cba8fa461ec463ULL, + 0x2ff5421677bcabb7ULL, 0x396f122f85e41d7dULL, 0xa09b332430bac6a8ULL, + 0xc888e8ced7070560ULL, 0xaeaf201ac682ee8fULL, 0x1180d7268944a257ULL, + 0xf058a43628e7a5fcULL, 0xbd4c4b8fbbce2b07ULL, 0xa1246df34abe7b49ULL, + 0x7d5569b79be9af3cULL, 0xa9b5a705bd9efa12ULL, 0xdb6b835baa4bc0e8ULL, + 0x05793bac8f147342ULL, 0x21c1512881848390ULL, 0xfdb0556c50d357e5ULL, + 0x613d4fcb6a99ff72ULL, 0x03dce2648e0cda3eULL, 0xe949b9e6568386f0ULL, + 0xfc0f0bbb2ad7ea04ULL, 0x6a70675913b5a417ULL, 0x7f36d5046fe1c8e3ULL, + 0x0c57af8d02304ff8ULL, 0x32223abdfcc84618ULL, 0x0891caf6f720815bULL, + 0xa63eeaec31a26fd4ULL, 0x2507345374944d33ULL, 0x49d28ac266394058ULL, + 0xf5219f9aa7f3d6beULL, 0x2d96fea583b4cc68ULL, 0x5a31e1571b7585d0ULL, + 0x8ed12fe53d02d0feULL, 0xdfade6205f5b0e4bULL, 0x4cabb16ee92d331aULL, + 0x04c6657bf510cea3ULL, 0xd73c2cd6a87b8f10ULL, 0xe1d87310a1a307abULL, + 0x6cd5be9112ad0d6bULL, 0x97c032354366f3f2ULL, 0xd4e0ceb22677552eULL, + 0x0000000000000000ULL, 0x29509bde76a402cbULL, 0xc27a9e8bd42fe3e4ULL, + 0x5ef7842cee654b73ULL, 0xaf107ecdbc86536eULL, 0x3fcacbe784fcb401ULL, + 0xd55f90655c73e8cfULL, 0xe6c2f40fdabf1336ULL, 0xe8f6e7312c873b11ULL, + 0xeb2a0555a28be12fULL, 0xe4a148bc2eb774e9ULL, 0x9b979db84156bc0aULL, + 0x6eb60222e6a56ab4ULL, 0x87ffbbc4b026ec44ULL, 0xc703a5275b3b90a6ULL, + 0x47e699fc9001687fULL, 0x9c8d1aa73a4aa897ULL, 0x7cea3760e1ed12ddULL, + 0x4ec80ddd1d2554c5ULL, 0x13e36b957d4cc588ULL, 0x5d2b66486069914dULL, + 0x92b90999cc7280b0ULL, 0x517cc9c56259deb5ULL, 0xc937b619ad03b881ULL, + 0xec30824ad997f5b2ULL, 0xa45d565fc5aa080bULL, 0xd6837201d27f32f1ULL, + 0x635ef3789e9198adULL, 0x531f75769651b96aULL, 0x4f77530a6721e924ULL, + 0x486dd4151c3dfdb9ULL, 0x5f48dafb9461f692ULL, 0x375b011173dc355aULL, + 0x3da9775470f4d3deULL, 0x8d0dcd81b30e0ac0ULL, 0x36e45fc609d888bbULL, + 0x55baacbe97491016ULL, 0x8cb29356c90ab721ULL, 0x76184125e2c5f459ULL, + 0x99f4210bb55edbd5ULL, 0x6f095cf59ca1d755ULL, 0x9f51f8c3b44672a9ULL, + 0x3538bda287d45285ULL, 0x50c39712185d6354ULL, 0xf23b1885dcefc223ULL, + 0x79930ccc6ef9619fULL, 0xed8fdc9da3934853ULL, 0xcb540aaa590bdf5eULL, + 0x5c94389f1a6d2cacULL, 0xe77daad8a0bbaed7ULL, 0x28efc5090ca0bf2aULL, + 0xbf2ff73c4fc64cd8ULL, 0xb37858b14df60320ULL, 0xf8c96ec0dfc724a7ULL, + 0x828680683f329f06ULL, 0x941cd051cd6a29ccULL, 0xc3c5c05cae2b5e05ULL, + 0xb601631dc2e27062ULL, 0xc01922382027843bULL, 0x24b86a840e90f0d2ULL, + 0xd245177a276ffc52ULL, 0x0f8b4de98c3c95c6ULL, 0x3e759530fef809e0ULL, + 0x0b4d2892792c5b65ULL, 0xc4df4743d5374a98ULL, 0xa5e20888bfaeb5eaULL, + 0xba56cc90c0d23f9aULL, 0x38d04cf8ffe0a09cULL, 0x62e1adafe495254cULL, + 0x0263bcb3f40867dfULL, 0xcaeb547d230f62bfULL, 0x6082111c109d4293ULL, + 0xdad4dd8cd04f7d09ULL, 0xefec602e579b2f8cULL, 0x1fb4c4187f7c8a70ULL, + 0xffd3e9dfa4db303aULL, 0x7bf0b07f9af10640ULL, 0xf49ec14dddf76b5fULL, + 0x8f6e713247066d1fULL, 0x339d646a86ccfbf9ULL, 0x64447467e58d8c30ULL, + 0x2c29a072f9b07189ULL, 0xd8b7613f24471ad6ULL, 0x6627c8d41185ebefULL, + 0xa347d140beb61c96ULL, 0xde12b8f7255fb3aaULL, 0x9d324470404e1576ULL, + 0x9306574eb6763d51ULL, 0xa80af9d2c79a47f3ULL, 0x859c0777442e8b9bULL, + 0x69ac853d9db97e29ULL + }, + { + 0xc3407dfc2de6377eULL, 0x5b9e93eea4256f77ULL, 0xadb58fdd50c845e0ULL, + 0x5219ff11a75bed86ULL, 0x356b61cfd90b1de9ULL, 0xfb8f406e25abe037ULL, + 0x7a5a0231c0f60796ULL, 0x9d3cd216e1f5020bULL, 0x0c6550fb6b48d8f3ULL, + 0xf57508c427ff1c62ULL, 0x4ad35ffa71cb407dULL, 0x6290a2da1666aa6dULL, + 0xe284ec2349355f9fULL, 0xb3c307c53d7c84ecULL, 0x05e23c0468365a02ULL, + 0x190bac4d6c9ebfa8ULL, 0x94bbbee9e28b80faULL, 0xa34fc777529cb9b5ULL, + 0xcc7b39f095bcd978ULL, 0x2426addb0ce532e3ULL, 0x7e79329312ce4fc7ULL, + 0xab09a72eebec2917ULL, 0xf8d15499f6b9d6c2ULL, 0x1a55b8babf8c895dULL, + 0xdb8add17fb769a85ULL, 0xb57f2f368658e81bULL, 0x8acd36f18f3f41f6ULL, + 0x5ce3b7bba50f11d3ULL, 0x114dcc14d5ee2f0aULL, 0xb91a7fcded1030e8ULL, + 0x81d5425fe55de7a1ULL, 0xb6213bc1554adeeeULL, 0x80144ef95f53f5f2ULL, + 0x1e7688186db4c10cULL, 0x3b912965db5fe1bcULL, 0xc281715a97e8252dULL, + 0x54a5d7e21c7f8171ULL, 0x4b12535ccbc5522eULL, 0x1d289cefbea6f7f9ULL, + 0x6ef5f2217d2e729eULL, 0xe6a7dc819b0d17ceULL, 0x1b94b41c05829b0eULL, + 0x33d7493c622f711eULL, 0xdcf7f942fa5ce421ULL, 0x600fba8b7f7a8ecbULL, + 0x46b60f011a83988eULL, 0x235b898e0dcf4c47ULL, 0x957ab24f588592a9ULL, + 0x4354330572b5c28cULL, 0xa5f3ef84e9b8d542ULL, 0x8c711e02341b2d01ULL, + 0x0b1874ae6a62a657ULL, 0x1213d8e306fc19ffULL, 0xfe6d7c6a4d9dba35ULL, + 0x65ed868f174cd4c9ULL, 0x88522ea0e6236550ULL, 0x899322065c2d7703ULL, + 0xc01e690bfef4018bULL, 0x915982ed8abddaf8ULL, 0xbe675b98ec3a4e4cULL, + 0xa996bf7f82f00db1ULL, 0xe1daf8d49a27696aULL, 0x2effd5d3dc8986e7ULL, + 0xd153a51f2b1a2e81ULL, 0x18caa0ebd690adfbULL, 0x390e3134b243c51aULL, + 0x2778b92cdff70416ULL, 0x029f1851691c24a6ULL, 0x5e7cafeacc133575ULL, + 0xfa4e4cc89fa5f264ULL, 0x5a5f9f481e2b7d24ULL, 0x484c47ab18d764dbULL, + 0x400a27f2a1a7f479ULL, 0xaeeb9b2a83da7315ULL, 0x721c626879869734ULL, + 0x042330a2d2384851ULL, 0x85f672fd3765aff0ULL, 0xba446b3a3e02061dULL, + 0x73dd6ecec3888567ULL, 0xffac70ccf793a866ULL, 0xdfa9edb5294ed2d4ULL, + 0x6c6aea7014325638ULL, 0x834a5a0e8c41c307ULL, 0xcdba35562fb2cb2bULL, + 0x0ad97808d06cb404ULL, 0x0f3b440cb85aee06ULL, 0xe5f9c876481f213bULL, + 0x98deee1289c35809ULL, 0x59018bbfcd394bd1ULL, 0xe01bf47220297b39ULL, + 0xde68e1139340c087ULL, 0x9fa3ca4788e926adULL, 0xbb85679c840c144eULL, + 0x53d8f3b71d55ffd5ULL, 0x0da45c5dd146caa0ULL, 0x6f34fe87c72060cdULL, + 0x57fbc315cf6db784ULL, 0xcee421a1fca0fddeULL, 0x3d2d0196607b8d4bULL, + 0x642c8a29ad42c69aULL, 0x14aff010bdd87508ULL, 0xac74837beac657b3ULL, + 0x3216459ad821634dULL, 0x3fb219c70967a9edULL, 0x06bc28f3bb246cf7ULL, + 0xf2082c9126d562c6ULL, 0x66b39278c45ee23cULL, 0xbd394f6f3f2878b9ULL, + 0xfd33689d9e8f8cc0ULL, 0x37f4799eb017394fULL, 0x108cc0b26fe03d59ULL, + 0xda4bd1b1417888d6ULL, 0xb09d1332ee6eb219ULL, 0x2f3ed975668794b4ULL, + 0x58c0871977375982ULL, 0x7561463d78ace990ULL, 0x09876cff037e82f1ULL, + 0x7fb83e35a8c05d94ULL, 0x26b9b58a65f91645ULL, 0xef20b07e9873953fULL, + 0x3148516d0b3355b8ULL, 0x41cb2b541ba9e62aULL, 0x790416c613e43163ULL, + 0xa011d380818e8f40ULL, 0x3a5025c36151f3efULL, 0xd57095bdf92266d0ULL, + 0x498d4b0da2d97688ULL, 0x8b0c3a57353153a5ULL, 0x21c491df64d368e1ULL, + 0x8f2f0af5e7091bf4ULL, 0x2da1c1240f9bb012ULL, 0xc43d59a92ccc49daULL, + 0xbfa6573e56345c1fULL, 0x828b56a8364fd154ULL, 0x9a41f643e0df7cafULL, + 0xbcf843c985266aeaULL, 0x2b1de9d7b4bfdce5ULL, 0x20059d79dedd7ab2ULL, + 0x6dabe6d6ae3c446bULL, 0x45e81bf6c991ae7bULL, 0x6351ae7cac68b83eULL, + 0xa432e32253b6c711ULL, 0xd092a9b991143cd2ULL, 0xcac711032e98b58fULL, + 0xd8d4c9e02864ac70ULL, 0xc5fc550f96c25b89ULL, 0xd7ef8dec903e4276ULL, + 0x67729ede7e50f06fULL, 0xeac28c7af045cf3dULL, 0xb15c1f945460a04aULL, + 0x9cfddeb05bfb1058ULL, 0x93c69abce3a1fe5eULL, 0xeb0380dc4a4bdd6eULL, + 0xd20db1e8f8081874ULL, 0x229a8528b7c15e14ULL, 0x44291750739fbc28ULL, + 0xd3ccbd4e42060a27ULL, 0xf62b1c33f4ed2a97ULL, 0x86a8660ae4779905ULL, + 0xd62e814a2a305025ULL, 0x477703a7a08d8addULL, 0x7b9b0e977af815c5ULL, + 0x78c51a60a9ea2330ULL, 0xa6adfb733aaae3b7ULL, 0x97e5aa1e3199b60fULL, + 0x0000000000000000ULL, 0xf4b404629df10e31ULL, 0x5564db44a6719322ULL, + 0x9207961a59afec0dULL, 0x9624a6b88b97a45cULL, 0x363575380a192b1cULL, + 0x2c60cd82b595a241ULL, 0x7d272664c1dc7932ULL, 0x7142769faa94a1c1ULL, + 0xa1d0df263b809d13ULL, 0x1630e841d4c451aeULL, 0xc1df65ad44fa13d8ULL, + 0x13d2d445bcf20bacULL, 0xd915c546926abe23ULL, 0x38cf3d92084dd749ULL, + 0xe766d0272103059dULL, 0xc7634d5effde7f2fULL, 0x077d2455012a7ea4ULL, + 0xedbfa82ff16fb199ULL, 0xaf2a978c39d46146ULL, 0x42953fa3c8bbd0dfULL, + 0xcb061da59496a7dcULL, 0x25e7a17db6eb20b0ULL, 0x34aa6d6963050fbaULL, + 0xa76cf7d580a4f1e4ULL, 0xf7ea10954ee338c4ULL, 0xfcf2643b24819e93ULL, + 0xcf252d0746aeef8dULL, 0x4ef06f58a3f3082cULL, 0x563acfb37563a5d7ULL, + 0x5086e740ce47c920ULL, 0x2982f186dda3f843ULL, 0x87696aac5e798b56ULL, + 0x5d22bb1d1f010380ULL, 0x035e14f7d31236f5ULL, 0x3cec0d30da759f18ULL, + 0xf3c920379cdb7095ULL, 0xb8db736b571e22bbULL, 0xdd36f5e44052f672ULL, + 0xaac8ab8851e23b44ULL, 0xa857b3d938fe1fe2ULL, 0x17f1e4e76eca43fdULL, + 0xec7ea4894b61a3caULL, 0x9e62c6e132e734feULL, 0xd4b1991b432c7483ULL, + 0x6ad6c283af163acfULL, 0x1ce9904904a8e5aaULL, 0x5fbda34c761d2726ULL, + 0xf910583f4cb7c491ULL, 0xc6a241f845d06d7cULL, 0x4f3163fe19fd1a7fULL, + 0xe99c988d2357f9c8ULL, 0x8eee06535d0709a7ULL, 0x0efa48aa0254fc55ULL, + 0xb4be23903c56fa48ULL, 0x763f52caabbedf65ULL, 0xeee1bcd8227d876cULL, + 0xe345e085f33b4dccULL, 0x3e731561b369bbbeULL, 0x2843fd2067adea10ULL, + 0x2adce5710eb1ceb6ULL, 0xb7e03767ef44ccbdULL, 0x8db012a48e153f52ULL, + 0x61ceb62dc5749c98ULL, 0xe85d942b9959eb9bULL, 0x4c6f7709caef2c8aULL, + 0x84377e5b8d6bbda3ULL, 0x30895dcbb13d47ebULL, 0x74a04a9bc2a2fbc3ULL, + 0x6b17ce251518289cULL, 0xe438c4d0f2113368ULL, 0x1fb784bed7bad35fULL, + 0x9b80fae55ad16efcULL, 0x77fe5e6c11b0cd36ULL, 0xc858095247849129ULL, + 0x08466059b97090a2ULL, 0x01c10ca6ba0e1253ULL, 0x6988d6747c040c3aULL, + 0x6849dad2c60a1e69ULL, 0x5147ebe67449db73ULL, 0xc99905f4fd8a837aULL, + 0x991fe2b433cd4a5aULL, 0xf09734c04fc94660ULL, 0xa28ecbd1e892abe6ULL, + 0xf1563866f5c75433ULL, 0x4dae7baf70e13ed9ULL, 0x7ce62ac27bd26b61ULL, + 0x70837a39109ab392ULL, 0x90988e4b30b3c8abULL, 0xb2020b63877296bfULL, + 0x156efcb607d6675bULL + }, + { + 0xe63f55ce97c331d0ULL, 0x25b506b0015bba16ULL, 0xc8706e29e6ad9ba8ULL, + 0x5b43d3775d521f6aULL, 0x0bfa3d577035106eULL, 0xab95fc172afb0e66ULL, + 0xf64b63979e7a3276ULL, 0xf58b4562649dad4bULL, 0x48f7c3dbae0c83f1ULL, + 0xff31916642f5c8c5ULL, 0xcbb048dc1c4a0495ULL, 0x66b8f83cdf622989ULL, + 0x35c130e908e2b9b0ULL, 0x7c761a61f0b34fa1ULL, 0x3601161cf205268dULL, + 0x9e54ccfe2219b7d6ULL, 0x8b7d90a538940837ULL, 0x9cd403588ea35d0bULL, + 0xbc3c6fea9ccc5b5aULL, 0xe5ff733b6d24aeedULL, 0xceed22de0f7eb8d2ULL, + 0xec8581cab1ab545eULL, 0xb96105e88ff8e71dULL, 0x8ca03501871a5eadULL, + 0x76ccce65d6db2a2fULL, 0x5883f582a7b58057ULL, 0x3f7be4ed2e8adc3eULL, + 0x0fe7be06355cd9c9ULL, 0xee054e6c1d11be83ULL, 0x1074365909b903a6ULL, + 0x5dde9f80b4813c10ULL, 0x4a770c7d02b6692cULL, 0x5379c8d5d7809039ULL, + 0xb4067448161ed409ULL, 0x5f5e5026183bd6cdULL, 0xe898029bf4c29df9ULL, + 0x7fb63c940a54d09cULL, 0xc5171f897f4ba8bcULL, 0xa6f28db7b31d3d72ULL, + 0x2e4f3be7716eaa78ULL, 0x0d6771a099e63314ULL, 0x82076254e41bf284ULL, + 0x2f0fd2b42733df98ULL, 0x5c9e76d3e2dc49f0ULL, 0x7aeb569619606cdbULL, + 0x83478b07b2468764ULL, 0xcfadcb8d5923cd32ULL, 0x85dac7f05b95a41eULL, + 0xb5469d1b4043a1e9ULL, 0xb821ecbbd9a592fdULL, 0x1b8e0b0e798c13c8ULL, + 0x62a57b6d9a0be02eULL, 0xfcf1b793b81257f8ULL, 0x9d94ea0bd8fe28ebULL, + 0x4cea408aeb654a56ULL, 0x23284a47e888996cULL, 0x2d8f1d128b893545ULL, + 0xf4cbac3132c0d8abULL, 0xbd7c86b9ca912ebaULL, 0x3a268eef3dbe6079ULL, + 0xf0d62f6077a9110cULL, 0x2735c916ade150cbULL, 0x89fd5f03942ee2eaULL, + 0x1acee25d2fd16628ULL, 0x90f39bab41181bffULL, 0x430dfe8cde39939fULL, + 0xf70b8ac4c8274796ULL, 0x1c53aeaac6024552ULL, 0x13b410acf35e9c9bULL, + 0xa532ab4249faa24fULL, 0x2b1251e5625a163fULL, 0xd7e3e676da4841c7ULL, + 0xa7b264e4e5404892ULL, 0xda8497d643ae72d3ULL, 0x861ae105a1723b23ULL, + 0x38a6414991048aa4ULL, 0x6578dec92585b6b4ULL, 0x0280cfa6acbaeaddULL, + 0x88bdb650c273970aULL, 0x9333bd5ebbff84c2ULL, 0x4e6a8f2c47dfa08bULL, + 0x321c954db76cef2aULL, 0x418d312a72837942ULL, 0xb29b38bfffcdf773ULL, + 0x6c022c38f90a4c07ULL, 0x5a033a240b0f6a8aULL, 0x1f93885f3ce5da6fULL, + 0xc38a537e96988bc6ULL, 0x39e6a81ac759ff44ULL, 0x29929e43cee0fce2ULL, + 0x40cdd87924de0ca2ULL, 0xe9d8ebc8a29fe819ULL, 0x0c2798f3cfbb46f4ULL, + 0x55e484223e53b343ULL, 0x4650948ecd0d2fd8ULL, 0x20e86cb2126f0651ULL, + 0x6d42c56baf5739e7ULL, 0xa06fc1405ace1e08ULL, 0x7babbfc54f3d193bULL, + 0x424d17df8864e67fULL, 0xd8045870ef14980eULL, 0xc6d7397c85ac3781ULL, + 0x21a885e1443273b1ULL, 0x67f8116f893f5c69ULL, 0x24f5efe35706cff6ULL, + 0xd56329d076f2ab1aULL, 0x5e1eb9754e66a32dULL, 0x28d2771098bd8902ULL, + 0x8f6013f47dfdc190ULL, 0x17a993fdb637553cULL, 0xe0a219397e1012aaULL, + 0x786b9930b5da8606ULL, 0x6e82e39e55b0a6daULL, 0x875a0856f72f4ec3ULL, + 0x3741ff4fa458536dULL, 0xac4859b3957558fcULL, 0x7ef6d5c75c09a57cULL, + 0xc04a758b6c7f14fbULL, 0xf9acdd91ab26ebbfULL, 0x7391a467c5ef9668ULL, + 0x335c7c1ee1319acaULL, 0xa91533b18641e4bbULL, 0xe4bf9a683b79db0dULL, + 0x8e20faa72ba0b470ULL, 0x51f907737b3a7ae4ULL, 0x2268a314bed5ec8cULL, + 0xd944b123b949edeeULL, 0x31dcb3b84d8b7017ULL, 0xd3fe65279f218860ULL, + 0x097af2f1dc8ffab3ULL, 0x9b09a6fc312d0b91ULL, 0xcc6ded78a3c4520fULL, + 0x3481d9ba5ebfcc50ULL, 0x4f2a667f1182d56bULL, 0xdfd9fdd4509ace94ULL, + 0x26752045fbbc252bULL, 0xbffc491f662bc467ULL, 0xdd593272fc202449ULL, + 0x3cbbc218d46d4303ULL, 0x91b372f817456e1fULL, 0x681faf69bc6385a0ULL, + 0xb686bbeebaa43ed4ULL, 0x1469b5084cd0ca01ULL, 0x98c98009cbca94acULL, + 0x6438379a73d8c354ULL, 0xc2caba2dc0c5fe26ULL, 0x3e3b0dbe78d7a9deULL, + 0x50b9ee202d670f04ULL, 0x4590b27b37eab0e5ULL, 0x6025b4cb36b10af3ULL, + 0xfb2c1237079c0162ULL, 0xa12f28130c936be8ULL, 0x4b37e52e54eb1cccULL, + 0x083a1ba28ad28f53ULL, 0xc10a9cd83a22611bULL, 0x9f1425ad7444c236ULL, + 0x069d4cf7e9d3237aULL, 0xedc56899e7f621beULL, 0x778c273680865fcfULL, + 0x309c5aeb1bd605f7ULL, 0x8de0dc52d1472b4dULL, 0xf8ec34c2fd7b9e5fULL, + 0xea18cd3d58787724ULL, 0xaad515447ca67b86ULL, 0x9989695a9d97e14cULL, + 0x0000000000000000ULL, 0xf196c63321f464ecULL, 0x71116bc169557cb5ULL, + 0xaf887f466f92c7c1ULL, 0x972e3e0ffe964d65ULL, 0x190ec4a8d536f915ULL, + 0x95aef1a9522ca7b8ULL, 0xdc19db21aa7d51a9ULL, 0x94ee18fa0471d258ULL, + 0x8087adf248a11859ULL, 0xc457f6da2916dd5cULL, 0xfa6cfb6451c17482ULL, + 0xf256e0c6db13fbd1ULL, 0x6a9f60cf10d96f7dULL, 0x4daaa9d9bd383fb6ULL, + 0x03c026f5fae79f3dULL, 0xde99148706c7bb74ULL, 0x2a52b8b6340763dfULL, + 0x6fc20acd03edd33aULL, 0xd423c08320afdefaULL, 0xbbe1ca4e23420dc0ULL, + 0x966ed75ca8cb3885ULL, 0xeb58246e0e2502c4ULL, 0x055d6a021334bc47ULL, + 0xa47242111fa7d7afULL, 0xe3623fcc84f78d97ULL, 0x81c744a11efc6db9ULL, + 0xaec8961539cfb221ULL, 0xf31609958d4e8e31ULL, 0x63e5923ecc5695ceULL, + 0x47107ddd9b505a38ULL, 0xa3afe7b5a0298135ULL, 0x792b7063e387f3e6ULL, + 0x0140e953565d75e0ULL, 0x12f4f9ffa503e97bULL, 0x750ce8902c3cb512ULL, + 0xdbc47e8515f30733ULL, 0x1ed3610c6ab8af8fULL, 0x5239218681dde5d9ULL, + 0xe222d69fd2aaf877ULL, 0xfe71783514a8bd25ULL, 0xcaf0a18f4a177175ULL, + 0x61655d9860ec7f13ULL, 0xe77fbc9dc19e4430ULL, 0x2ccff441ddd440a5ULL, + 0x16e97aaee06a20dcULL, 0xa855dae2d01c915bULL, 0x1d1347f9905f30b2ULL, + 0xb7c652bdecf94b34ULL, 0xd03e43d265c6175dULL, 0xfdb15ec0ee4f2218ULL, + 0x57644b8492e9599eULL, 0x07dda5a4bf8e569aULL, 0x54a46d71680ec6a3ULL, + 0x5624a2d7c4b42c7eULL, 0xbebca04c3076b187ULL, 0x7d36f332a6ee3a41ULL, + 0x3b6667bc6be31599ULL, 0x695f463aea3ef040ULL, 0xad08b0e0c3282d1cULL, + 0xb15b1e4a052a684eULL, 0x44d05b2861b7c505ULL, 0x15295c5b1a8dbfe1ULL, + 0x744c01c37a61c0f2ULL, 0x59c31cd1f1e8f5b7ULL, 0xef45a73f4b4ccb63ULL, + 0x6bdf899c46841a9dULL, 0x3dfb2b4b823036e3ULL, 0xa2ef0ee6f674f4d5ULL, + 0x184e2dfb836b8cf5ULL, 0x1134df0a5fe47646ULL, 0xbaa1231d751f7820ULL, + 0xd17eaa81339b62bdULL, 0xb01bf71953771daeULL, 0x849a2ea30dc8d1feULL, + 0x705182923f080955ULL, 0x0ea757556301ac29ULL, 0x041d83514569c9a7ULL, + 0x0abad4042668658eULL, 0x49b72a88f851f611ULL, 0x8a3d79f66ec97dd7ULL, + 0xcd2d042bf59927efULL, 0xc930877ab0f0ee48ULL, 0x9273540deda2f122ULL, + 0xc797d02fd3f14261ULL, 0xe1e2f06a284d674aULL, 0xd2be8c74c97cfd80ULL, + 0x9a494faf67707e71ULL, 0xb3dbd1eca9908293ULL, 0x72d14d3493b2e388ULL, + 0xd6a30f258c153427ULL + } + }; + +extern const uint64_t STREEBOG_C[12][8] = + { + { + 0xdd806559f2a64507ULL, + 0x05767436cc744d23ULL, + 0xa2422a08a460d315ULL, + 0x4b7ce09192676901ULL, + 0x714eb88d7585c4fcULL, + 0x2f6a76432e45d016ULL, + 0xebcb2f81c0657c1fULL, + 0xb1085bda1ecadae9ULL + }, + { + 0xe679047021b19bb7ULL, + 0x55dda21bd7cbcd56ULL, + 0x5cb561c2db0aa7caULL, + 0x9ab5176b12d69958ULL, + 0x61d55e0f16b50131ULL, + 0xf3feea720a232b98ULL, + 0x4fe39d460f70b5d7ULL, + 0x6fa3b58aa99d2f1aULL + }, + { + 0x991e96f50aba0ab2ULL, + 0xc2b6f443867adb31ULL, + 0xc1c93a376062db09ULL, + 0xd3e20fe490359eb1ULL, + 0xf2ea7514b1297b7bULL, + 0x06f15e5f529c1f8bULL, + 0x0a39fc286a3d8435ULL, + 0xf574dcac2bce2fc7ULL + }, + { + 0x220cbebc84e3d12eULL, + 0x3453eaa193e837f1ULL, + 0xd8b71333935203beULL, + 0xa9d72c82ed03d675ULL, + 0x9d721cad685e353fULL, + 0x488e857e335c3c7dULL, + 0xf948e1a05d71e4ddULL, + 0xef1fdfb3e81566d2ULL + }, + { + 0x601758fd7c6cfe57ULL, + 0x7a56a27ea9ea63f5ULL, + 0xdfff00b723271a16ULL, + 0xbfcd1747253af5a3ULL, + 0x359e35d7800fffbdULL, + 0x7f151c1f1686104aULL, + 0x9a3f410c6ca92363ULL, + 0x4bea6bacad474799ULL + }, + { + 0xfa68407a46647d6eULL, + 0xbf71c57236904f35ULL, + 0x0af21f66c2bec6b6ULL, + 0xcffaa6b71c9ab7b4ULL, + 0x187f9ab49af08ec6ULL, + 0x2d66c4f95142a46cULL, + 0x6fa4c33b7a3039c0ULL, + 0xae4faeae1d3ad3d9ULL + }, + { + 0x8886564d3a14d493ULL, + 0x3517454ca23c4af3ULL, + 0x06476983284a0504ULL, + 0x0992abc52d822c37ULL, + 0xd3473e33197a93c9ULL, + 0x399ec6c7e6bf87c9ULL, + 0x51ac86febf240954ULL, + 0xf4c70e16eeaac5ecULL + }, + { + 0xa47f0dd4bf02e71eULL, + 0x36acc2355951a8d9ULL, + 0x69d18d2bd1a5c42fULL, + 0xf4892bcb929b0690ULL, + 0x89b4443b4ddbc49aULL, + 0x4eb7f8719c36de1eULL, + 0x03e7aa020c6e4141ULL, + 0x9b1f5b424d93c9a7ULL + }, + { + 0x7261445183235adbULL, + 0x0e38dc92cb1f2a60ULL, + 0x7b2b8a9aa6079c54ULL, + 0x800a440bdbb2ceb1ULL, + 0x3cd955b7e00d0984ULL, + 0x3a7d3a1b25894224ULL, + 0x944c9ad8ec165fdeULL, + 0x378f5a541631229bULL + }, + { + 0x74b4c7fb98459cedULL, + 0x3698fad1153bb6c3ULL, + 0x7a1e6c303b7652f4ULL, + 0x9fe76702af69334bULL, + 0x1fffe18a1b336103ULL, + 0x8941e71cff8a78dbULL, + 0x382ae548b2e4f3f3ULL, + 0xabbedea680056f52ULL + }, + { + 0x6bcaa4cd81f32d1bULL, + 0xdea2594ac06fd85dULL, + 0xefbacd1d7d476e98ULL, + 0x8a1d71efea48b9caULL, + 0x2001802114846679ULL, + 0xd8fa6bbbebab0761ULL, + 0x3002c6cd635afe94ULL, + 0x7bcd9ed0efc889fbULL + }, + { + 0x48bc924af11bd720ULL, + 0xfaf417d5d9b21b99ULL, + 0xe71da4aa88e12852ULL, + 0x5d80ef9d1891cc86ULL, + 0xf82012d430219f9bULL, + 0xcda43c32bcdf1d77ULL, + 0xd21380b00449b17aULL, + 0x378ee767f11631baULL + } + }; + +} diff --git a/comm/third_party/botan/src/lib/hash/tiger/info.txt b/comm/third_party/botan/src/lib/hash/tiger/info.txt new file mode 100644 index 0000000000..a244b2f0b2 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/tiger/info.txt @@ -0,0 +1,7 @@ + +TIGER -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/tiger/tig_tab.cpp b/comm/third_party/botan/src/lib/hash/tiger/tig_tab.cpp new file mode 100644 index 0000000000..3d1dc1eeb1 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/tiger/tig_tab.cpp @@ -0,0 +1,364 @@ +/* +* S-Box Tables for Tiger +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +const uint64_t Tiger::SBOX1[256] = { + 0x02AAB17CF7E90C5E, 0xAC424B03E243A8EC, 0x72CD5BE30DD5FCD3, + 0x6D019B93F6F97F3A, 0xCD9978FFD21F9193, 0x7573A1C9708029E2, + 0xB164326B922A83C3, 0x46883EEE04915870, 0xEAACE3057103ECE6, + 0xC54169B808A3535C, 0x4CE754918DDEC47C, 0x0AA2F4DFDC0DF40C, + 0x10B76F18A74DBEFA, 0xC6CCB6235AD1AB6A, 0x13726121572FE2FF, + 0x1A488C6F199D921E, 0x4BC9F9F4DA0007CA, 0x26F5E6F6E85241C7, + 0x859079DBEA5947B6, 0x4F1885C5C99E8C92, 0xD78E761EA96F864B, + 0x8E36428C52B5C17D, 0x69CF6827373063C1, 0xB607C93D9BB4C56E, + 0x7D820E760E76B5EA, 0x645C9CC6F07FDC42, 0xBF38A078243342E0, + 0x5F6B343C9D2E7D04, 0xF2C28AEB600B0EC6, 0x6C0ED85F7254BCAC, + 0x71592281A4DB4FE5, 0x1967FA69CE0FED9F, 0xFD5293F8B96545DB, + 0xC879E9D7F2A7600B, 0x860248920193194E, 0xA4F9533B2D9CC0B3, + 0x9053836C15957613, 0xDB6DCF8AFC357BF1, 0x18BEEA7A7A370F57, + 0x037117CA50B99066, 0x6AB30A9774424A35, 0xF4E92F02E325249B, + 0x7739DB07061CCAE1, 0xD8F3B49CECA42A05, 0xBD56BE3F51382F73, + 0x45FAED5843B0BB28, 0x1C813D5C11BF1F83, 0x8AF0E4B6D75FA169, + 0x33EE18A487AD9999, 0x3C26E8EAB1C94410, 0xB510102BC0A822F9, + 0x141EEF310CE6123B, 0xFC65B90059DDB154, 0xE0158640C5E0E607, + 0x884E079826C3A3CF, 0x930D0D9523C535FD, 0x35638D754E9A2B00, + 0x4085FCCF40469DD5, 0xC4B17AD28BE23A4C, 0xCAB2F0FC6A3E6A2E, + 0x2860971A6B943FCD, 0x3DDE6EE212E30446, 0x6222F32AE01765AE, + 0x5D550BB5478308FE, 0xA9EFA98DA0EDA22A, 0xC351A71686C40DA7, + 0x1105586D9C867C84, 0xDCFFEE85FDA22853, 0xCCFBD0262C5EEF76, + 0xBAF294CB8990D201, 0xE69464F52AFAD975, 0x94B013AFDF133E14, + 0x06A7D1A32823C958, 0x6F95FE5130F61119, 0xD92AB34E462C06C0, + 0xED7BDE33887C71D2, 0x79746D6E6518393E, 0x5BA419385D713329, + 0x7C1BA6B948A97564, 0x31987C197BFDAC67, 0xDE6C23C44B053D02, + 0x581C49FED002D64D, 0xDD474D6338261571, 0xAA4546C3E473D062, + 0x928FCE349455F860, 0x48161BBACAAB94D9, 0x63912430770E6F68, + 0x6EC8A5E602C6641C, 0x87282515337DDD2B, 0x2CDA6B42034B701B, + 0xB03D37C181CB096D, 0xE108438266C71C6F, 0x2B3180C7EB51B255, + 0xDF92B82F96C08BBC, 0x5C68C8C0A632F3BA, 0x5504CC861C3D0556, + 0xABBFA4E55FB26B8F, 0x41848B0AB3BACEB4, 0xB334A273AA445D32, + 0xBCA696F0A85AD881, 0x24F6EC65B528D56C, 0x0CE1512E90F4524A, + 0x4E9DD79D5506D35A, 0x258905FAC6CE9779, 0x2019295B3E109B33, + 0xF8A9478B73A054CC, 0x2924F2F934417EB0, 0x3993357D536D1BC4, + 0x38A81AC21DB6FF8B, 0x47C4FBF17D6016BF, 0x1E0FAADD7667E3F5, + 0x7ABCFF62938BEB96, 0xA78DAD948FC179C9, 0x8F1F98B72911E50D, + 0x61E48EAE27121A91, 0x4D62F7AD31859808, 0xECEBA345EF5CEAEB, + 0xF5CEB25EBC9684CE, 0xF633E20CB7F76221, 0xA32CDF06AB8293E4, + 0x985A202CA5EE2CA4, 0xCF0B8447CC8A8FB1, 0x9F765244979859A3, + 0xA8D516B1A1240017, 0x0BD7BA3EBB5DC726, 0xE54BCA55B86ADB39, + 0x1D7A3AFD6C478063, 0x519EC608E7669EDD, 0x0E5715A2D149AA23, + 0x177D4571848FF194, 0xEEB55F3241014C22, 0x0F5E5CA13A6E2EC2, + 0x8029927B75F5C361, 0xAD139FABC3D6E436, 0x0D5DF1A94CCF402F, + 0x3E8BD948BEA5DFC8, 0xA5A0D357BD3FF77E, 0xA2D12E251F74F645, + 0x66FD9E525E81A082, 0x2E0C90CE7F687A49, 0xC2E8BCBEBA973BC5, + 0x000001BCE509745F, 0x423777BBE6DAB3D6, 0xD1661C7EAEF06EB5, + 0xA1781F354DAACFD8, 0x2D11284A2B16AFFC, 0xF1FC4F67FA891D1F, + 0x73ECC25DCB920ADA, 0xAE610C22C2A12651, 0x96E0A810D356B78A, + 0x5A9A381F2FE7870F, 0xD5AD62EDE94E5530, 0xD225E5E8368D1427, + 0x65977B70C7AF4631, 0x99F889B2DE39D74F, 0x233F30BF54E1D143, + 0x9A9675D3D9A63C97, 0x5470554FF334F9A8, 0x166ACB744A4F5688, + 0x70C74CAAB2E4AEAD, 0xF0D091646F294D12, 0x57B82A89684031D1, + 0xEFD95A5A61BE0B6B, 0x2FBD12E969F2F29A, 0x9BD37013FEFF9FE8, + 0x3F9B0404D6085A06, 0x4940C1F3166CFE15, 0x09542C4DCDF3DEFB, + 0xB4C5218385CD5CE3, 0xC935B7DC4462A641, 0x3417F8A68ED3B63F, + 0xB80959295B215B40, 0xF99CDAEF3B8C8572, 0x018C0614F8FCB95D, + 0x1B14ACCD1A3ACDF3, 0x84D471F200BB732D, 0xC1A3110E95E8DA16, + 0x430A7220BF1A82B8, 0xB77E090D39DF210E, 0x5EF4BD9F3CD05E9D, + 0x9D4FF6DA7E57A444, 0xDA1D60E183D4A5F8, 0xB287C38417998E47, + 0xFE3EDC121BB31886, 0xC7FE3CCC980CCBEF, 0xE46FB590189BFD03, + 0x3732FD469A4C57DC, 0x7EF700A07CF1AD65, 0x59C64468A31D8859, + 0x762FB0B4D45B61F6, 0x155BAED099047718, 0x68755E4C3D50BAA6, + 0xE9214E7F22D8B4DF, 0x2ADDBF532EAC95F4, 0x32AE3909B4BD0109, + 0x834DF537B08E3450, 0xFA209DA84220728D, 0x9E691D9B9EFE23F7, + 0x0446D288C4AE8D7F, 0x7B4CC524E169785B, 0x21D87F0135CA1385, + 0xCEBB400F137B8AA5, 0x272E2B66580796BE, 0x3612264125C2B0DE, + 0x057702BDAD1EFBB2, 0xD4BABB8EACF84BE9, 0x91583139641BC67B, + 0x8BDC2DE08036E024, 0x603C8156F49F68ED, 0xF7D236F7DBEF5111, + 0x9727C4598AD21E80, 0xA08A0896670A5FD7, 0xCB4A8F4309EBA9CB, + 0x81AF564B0F7036A1, 0xC0B99AA778199ABD, 0x959F1EC83FC8E952, + 0x8C505077794A81B9, 0x3ACAAF8F056338F0, 0x07B43F50627A6778, + 0x4A44AB49F5ECCC77, 0x3BC3D6E4B679EE98, 0x9CC0D4D1CF14108C, + 0x4406C00B206BC8A0, 0x82A18854C8D72D89, 0x67E366B35C3C432C, + 0xB923DD61102B37F2, 0x56AB2779D884271D, 0xBE83E1B0FF1525AF, + 0xFB7C65D4217E49A9, 0x6BDBE0E76D48E7D4, 0x08DF828745D9179E, + 0x22EA6A9ADD53BD34, 0xE36E141C5622200A, 0x7F805D1B8CB750EE, + 0xAFE5C7A59F58E837, 0xE27F996A4FB1C23C, 0xD3867DFB0775F0D0, + 0xD0E673DE6E88891A, 0x123AEB9EAFB86C25, 0x30F1D5D5C145B895, + 0xBB434A2DEE7269E7, 0x78CB67ECF931FA38, 0xF33B0372323BBF9C, + 0x52D66336FB279C74, 0x505F33AC0AFB4EAA, 0xE8A5CD99A2CCE187, + 0x534974801E2D30BB, 0x8D2D5711D5876D90, 0x1F1A412891BC038E, + 0xD6E2E71D82E56648, 0x74036C3A497732B7, 0x89B67ED96361F5AB, + 0xFFED95D8F1EA02A2, 0xE72B3BD61464D43D, 0xA6300F170BDC4820, + 0xEBC18760ED78A77A }; + +const uint64_t Tiger::SBOX2[256] = { + 0xE6A6BE5A05A12138, 0xB5A122A5B4F87C98, 0x563C6089140B6990, + 0x4C46CB2E391F5DD5, 0xD932ADDBC9B79434, 0x08EA70E42015AFF5, + 0xD765A6673E478CF1, 0xC4FB757EAB278D99, 0xDF11C6862D6E0692, + 0xDDEB84F10D7F3B16, 0x6F2EF604A665EA04, 0x4A8E0F0FF0E0DFB3, + 0xA5EDEEF83DBCBA51, 0xFC4F0A2A0EA4371E, 0xE83E1DA85CB38429, + 0xDC8FF882BA1B1CE2, 0xCD45505E8353E80D, 0x18D19A00D4DB0717, + 0x34A0CFEDA5F38101, 0x0BE77E518887CAF2, 0x1E341438B3C45136, + 0xE05797F49089CCF9, 0xFFD23F9DF2591D14, 0x543DDA228595C5CD, + 0x661F81FD99052A33, 0x8736E641DB0F7B76, 0x15227725418E5307, + 0xE25F7F46162EB2FA, 0x48A8B2126C13D9FE, 0xAFDC541792E76EEA, + 0x03D912BFC6D1898F, 0x31B1AAFA1B83F51B, 0xF1AC2796E42AB7D9, + 0x40A3A7D7FCD2EBAC, 0x1056136D0AFBBCC5, 0x7889E1DD9A6D0C85, + 0xD33525782A7974AA, 0xA7E25D09078AC09B, 0xBD4138B3EAC6EDD0, + 0x920ABFBE71EB9E70, 0xA2A5D0F54FC2625C, 0xC054E36B0B1290A3, + 0xF6DD59FF62FE932B, 0x3537354511A8AC7D, 0xCA845E9172FADCD4, + 0x84F82B60329D20DC, 0x79C62CE1CD672F18, 0x8B09A2ADD124642C, + 0xD0C1E96A19D9E726, 0x5A786A9B4BA9500C, 0x0E020336634C43F3, + 0xC17B474AEB66D822, 0x6A731AE3EC9BAAC2, 0x8226667AE0840258, + 0x67D4567691CAECA5, 0x1D94155C4875ADB5, 0x6D00FD985B813FDF, + 0x51286EFCB774CD06, 0x5E8834471FA744AF, 0xF72CA0AEE761AE2E, + 0xBE40E4CDAEE8E09A, 0xE9970BBB5118F665, 0x726E4BEB33DF1964, + 0x703B000729199762, 0x4631D816F5EF30A7, 0xB880B5B51504A6BE, + 0x641793C37ED84B6C, 0x7B21ED77F6E97D96, 0x776306312EF96B73, + 0xAE528948E86FF3F4, 0x53DBD7F286A3F8F8, 0x16CADCE74CFC1063, + 0x005C19BDFA52C6DD, 0x68868F5D64D46AD3, 0x3A9D512CCF1E186A, + 0x367E62C2385660AE, 0xE359E7EA77DCB1D7, 0x526C0773749ABE6E, + 0x735AE5F9D09F734B, 0x493FC7CC8A558BA8, 0xB0B9C1533041AB45, + 0x321958BA470A59BD, 0x852DB00B5F46C393, 0x91209B2BD336B0E5, + 0x6E604F7D659EF19F, 0xB99A8AE2782CCB24, 0xCCF52AB6C814C4C7, + 0x4727D9AFBE11727B, 0x7E950D0C0121B34D, 0x756F435670AD471F, + 0xF5ADD442615A6849, 0x4E87E09980B9957A, 0x2ACFA1DF50AEE355, + 0xD898263AFD2FD556, 0xC8F4924DD80C8FD6, 0xCF99CA3D754A173A, + 0xFE477BACAF91BF3C, 0xED5371F6D690C12D, 0x831A5C285E687094, + 0xC5D3C90A3708A0A4, 0x0F7F903717D06580, 0x19F9BB13B8FDF27F, + 0xB1BD6F1B4D502843, 0x1C761BA38FFF4012, 0x0D1530C4E2E21F3B, + 0x8943CE69A7372C8A, 0xE5184E11FEB5CE66, 0x618BDB80BD736621, + 0x7D29BAD68B574D0B, 0x81BB613E25E6FE5B, 0x071C9C10BC07913F, + 0xC7BEEB7909AC2D97, 0xC3E58D353BC5D757, 0xEB017892F38F61E8, + 0xD4EFFB9C9B1CC21A, 0x99727D26F494F7AB, 0xA3E063A2956B3E03, + 0x9D4A8B9A4AA09C30, 0x3F6AB7D500090FB4, 0x9CC0F2A057268AC0, + 0x3DEE9D2DEDBF42D1, 0x330F49C87960A972, 0xC6B2720287421B41, + 0x0AC59EC07C00369C, 0xEF4EAC49CB353425, 0xF450244EEF0129D8, + 0x8ACC46E5CAF4DEB6, 0x2FFEAB63989263F7, 0x8F7CB9FE5D7A4578, + 0x5BD8F7644E634635, 0x427A7315BF2DC900, 0x17D0C4AA2125261C, + 0x3992486C93518E50, 0xB4CBFEE0A2D7D4C3, 0x7C75D6202C5DDD8D, + 0xDBC295D8E35B6C61, 0x60B369D302032B19, 0xCE42685FDCE44132, + 0x06F3DDB9DDF65610, 0x8EA4D21DB5E148F0, 0x20B0FCE62FCD496F, + 0x2C1B912358B0EE31, 0xB28317B818F5A308, 0xA89C1E189CA6D2CF, + 0x0C6B18576AAADBC8, 0xB65DEAA91299FAE3, 0xFB2B794B7F1027E7, + 0x04E4317F443B5BEB, 0x4B852D325939D0A6, 0xD5AE6BEEFB207FFC, + 0x309682B281C7D374, 0xBAE309A194C3B475, 0x8CC3F97B13B49F05, + 0x98A9422FF8293967, 0x244B16B01076FF7C, 0xF8BF571C663D67EE, + 0x1F0D6758EEE30DA1, 0xC9B611D97ADEB9B7, 0xB7AFD5887B6C57A2, + 0x6290AE846B984FE1, 0x94DF4CDEACC1A5FD, 0x058A5BD1C5483AFF, + 0x63166CC142BA3C37, 0x8DB8526EB2F76F40, 0xE10880036F0D6D4E, + 0x9E0523C9971D311D, 0x45EC2824CC7CD691, 0x575B8359E62382C9, + 0xFA9E400DC4889995, 0xD1823ECB45721568, 0xDAFD983B8206082F, + 0xAA7D29082386A8CB, 0x269FCD4403B87588, 0x1B91F5F728BDD1E0, + 0xE4669F39040201F6, 0x7A1D7C218CF04ADE, 0x65623C29D79CE5CE, + 0x2368449096C00BB1, 0xAB9BF1879DA503BA, 0xBC23ECB1A458058E, + 0x9A58DF01BB401ECC, 0xA070E868A85F143D, 0x4FF188307DF2239E, + 0x14D565B41A641183, 0xEE13337452701602, 0x950E3DCF3F285E09, + 0x59930254B9C80953, 0x3BF299408930DA6D, 0xA955943F53691387, + 0xA15EDECAA9CB8784, 0x29142127352BE9A0, 0x76F0371FFF4E7AFB, + 0x0239F450274F2228, 0xBB073AF01D5E868B, 0xBFC80571C10E96C1, + 0xD267088568222E23, 0x9671A3D48E80B5B0, 0x55B5D38AE193BB81, + 0x693AE2D0A18B04B8, 0x5C48B4ECADD5335F, 0xFD743B194916A1CA, + 0x2577018134BE98C4, 0xE77987E83C54A4AD, 0x28E11014DA33E1B9, + 0x270CC59E226AA213, 0x71495F756D1A5F60, 0x9BE853FB60AFEF77, + 0xADC786A7F7443DBF, 0x0904456173B29A82, 0x58BC7A66C232BD5E, + 0xF306558C673AC8B2, 0x41F639C6B6C9772A, 0x216DEFE99FDA35DA, + 0x11640CC71C7BE615, 0x93C43694565C5527, 0xEA038E6246777839, + 0xF9ABF3CE5A3E2469, 0x741E768D0FD312D2, 0x0144B883CED652C6, + 0xC20B5A5BA33F8552, 0x1AE69633C3435A9D, 0x97A28CA4088CFDEC, + 0x8824A43C1E96F420, 0x37612FA66EEEA746, 0x6B4CB165F9CF0E5A, + 0x43AA1C06A0ABFB4A, 0x7F4DC26FF162796B, 0x6CBACC8E54ED9B0F, + 0xA6B7FFEFD2BB253E, 0x2E25BC95B0A29D4F, 0x86D6A58BDEF1388C, + 0xDED74AC576B6F054, 0x8030BDBC2B45805D, 0x3C81AF70E94D9289, + 0x3EFF6DDA9E3100DB, 0xB38DC39FDFCC8847, 0x123885528D17B87E, + 0xF2DA0ED240B1B642, 0x44CEFADCD54BF9A9, 0x1312200E433C7EE6, + 0x9FFCC84F3A78C748, 0xF0CD1F72248576BB, 0xEC6974053638CFE4, + 0x2BA7B67C0CEC4E4C, 0xAC2F4DF3E5CE32ED, 0xCB33D14326EA4C11, + 0xA4E9044CC77E58BC, 0x5F513293D934FCEF, 0x5DC9645506E55444, + 0x50DE418F317DE40A, 0x388CB31A69DDE259, 0x2DB4A83455820A86, + 0x9010A91E84711AE9, 0x4DF7F0B7B1498371, 0xD62A2EABC0977179, + 0x22FAC097AA8D5C0E }; + +const uint64_t Tiger::SBOX3[256] = { + 0xF49FCC2FF1DAF39B, 0x487FD5C66FF29281, 0xE8A30667FCDCA83F, + 0x2C9B4BE3D2FCCE63, 0xDA3FF74B93FBBBC2, 0x2FA165D2FE70BA66, + 0xA103E279970E93D4, 0xBECDEC77B0E45E71, 0xCFB41E723985E497, + 0xB70AAA025EF75017, 0xD42309F03840B8E0, 0x8EFC1AD035898579, + 0x96C6920BE2B2ABC5, 0x66AF4163375A9172, 0x2174ABDCCA7127FB, + 0xB33CCEA64A72FF41, 0xF04A4933083066A5, 0x8D970ACDD7289AF5, + 0x8F96E8E031C8C25E, 0xF3FEC02276875D47, 0xEC7BF310056190DD, + 0xF5ADB0AEBB0F1491, 0x9B50F8850FD58892, 0x4975488358B74DE8, + 0xA3354FF691531C61, 0x0702BBE481D2C6EE, 0x89FB24057DEDED98, + 0xAC3075138596E902, 0x1D2D3580172772ED, 0xEB738FC28E6BC30D, + 0x5854EF8F63044326, 0x9E5C52325ADD3BBE, 0x90AA53CF325C4623, + 0xC1D24D51349DD067, 0x2051CFEEA69EA624, 0x13220F0A862E7E4F, + 0xCE39399404E04864, 0xD9C42CA47086FCB7, 0x685AD2238A03E7CC, + 0x066484B2AB2FF1DB, 0xFE9D5D70EFBF79EC, 0x5B13B9DD9C481854, + 0x15F0D475ED1509AD, 0x0BEBCD060EC79851, 0xD58C6791183AB7F8, + 0xD1187C5052F3EEE4, 0xC95D1192E54E82FF, 0x86EEA14CB9AC6CA2, + 0x3485BEB153677D5D, 0xDD191D781F8C492A, 0xF60866BAA784EBF9, + 0x518F643BA2D08C74, 0x8852E956E1087C22, 0xA768CB8DC410AE8D, + 0x38047726BFEC8E1A, 0xA67738B4CD3B45AA, 0xAD16691CEC0DDE19, + 0xC6D4319380462E07, 0xC5A5876D0BA61938, 0x16B9FA1FA58FD840, + 0x188AB1173CA74F18, 0xABDA2F98C99C021F, 0x3E0580AB134AE816, + 0x5F3B05B773645ABB, 0x2501A2BE5575F2F6, 0x1B2F74004E7E8BA9, + 0x1CD7580371E8D953, 0x7F6ED89562764E30, 0xB15926FF596F003D, + 0x9F65293DA8C5D6B9, 0x6ECEF04DD690F84C, 0x4782275FFF33AF88, + 0xE41433083F820801, 0xFD0DFE409A1AF9B5, 0x4325A3342CDB396B, + 0x8AE77E62B301B252, 0xC36F9E9F6655615A, 0x85455A2D92D32C09, + 0xF2C7DEA949477485, 0x63CFB4C133A39EBA, 0x83B040CC6EBC5462, + 0x3B9454C8FDB326B0, 0x56F56A9E87FFD78C, 0x2DC2940D99F42BC6, + 0x98F7DF096B096E2D, 0x19A6E01E3AD852BF, 0x42A99CCBDBD4B40B, + 0xA59998AF45E9C559, 0x366295E807D93186, 0x6B48181BFAA1F773, + 0x1FEC57E2157A0A1D, 0x4667446AF6201AD5, 0xE615EBCACFB0F075, + 0xB8F31F4F68290778, 0x22713ED6CE22D11E, 0x3057C1A72EC3C93B, + 0xCB46ACC37C3F1F2F, 0xDBB893FD02AAF50E, 0x331FD92E600B9FCF, + 0xA498F96148EA3AD6, 0xA8D8426E8B6A83EA, 0xA089B274B7735CDC, + 0x87F6B3731E524A11, 0x118808E5CBC96749, 0x9906E4C7B19BD394, + 0xAFED7F7E9B24A20C, 0x6509EADEEB3644A7, 0x6C1EF1D3E8EF0EDE, + 0xB9C97D43E9798FB4, 0xA2F2D784740C28A3, 0x7B8496476197566F, + 0x7A5BE3E6B65F069D, 0xF96330ED78BE6F10, 0xEEE60DE77A076A15, + 0x2B4BEE4AA08B9BD0, 0x6A56A63EC7B8894E, 0x02121359BA34FEF4, + 0x4CBF99F8283703FC, 0x398071350CAF30C8, 0xD0A77A89F017687A, + 0xF1C1A9EB9E423569, 0x8C7976282DEE8199, 0x5D1737A5DD1F7ABD, + 0x4F53433C09A9FA80, 0xFA8B0C53DF7CA1D9, 0x3FD9DCBC886CCB77, + 0xC040917CA91B4720, 0x7DD00142F9D1DCDF, 0x8476FC1D4F387B58, + 0x23F8E7C5F3316503, 0x032A2244E7E37339, 0x5C87A5D750F5A74B, + 0x082B4CC43698992E, 0xDF917BECB858F63C, 0x3270B8FC5BF86DDA, + 0x10AE72BB29B5DD76, 0x576AC94E7700362B, 0x1AD112DAC61EFB8F, + 0x691BC30EC5FAA427, 0xFF246311CC327143, 0x3142368E30E53206, + 0x71380E31E02CA396, 0x958D5C960AAD76F1, 0xF8D6F430C16DA536, + 0xC8FFD13F1BE7E1D2, 0x7578AE66004DDBE1, 0x05833F01067BE646, + 0xBB34B5AD3BFE586D, 0x095F34C9A12B97F0, 0x247AB64525D60CA8, + 0xDCDBC6F3017477D1, 0x4A2E14D4DECAD24D, 0xBDB5E6D9BE0A1EEB, + 0x2A7E70F7794301AB, 0xDEF42D8A270540FD, 0x01078EC0A34C22C1, + 0xE5DE511AF4C16387, 0x7EBB3A52BD9A330A, 0x77697857AA7D6435, + 0x004E831603AE4C32, 0xE7A21020AD78E312, 0x9D41A70C6AB420F2, + 0x28E06C18EA1141E6, 0xD2B28CBD984F6B28, 0x26B75F6C446E9D83, + 0xBA47568C4D418D7F, 0xD80BADBFE6183D8E, 0x0E206D7F5F166044, + 0xE258A43911CBCA3E, 0x723A1746B21DC0BC, 0xC7CAA854F5D7CDD3, + 0x7CAC32883D261D9C, 0x7690C26423BA942C, 0x17E55524478042B8, + 0xE0BE477656A2389F, 0x4D289B5E67AB2DA0, 0x44862B9C8FBBFD31, + 0xB47CC8049D141365, 0x822C1B362B91C793, 0x4EB14655FB13DFD8, + 0x1ECBBA0714E2A97B, 0x6143459D5CDE5F14, 0x53A8FBF1D5F0AC89, + 0x97EA04D81C5E5B00, 0x622181A8D4FDB3F3, 0xE9BCD341572A1208, + 0x1411258643CCE58A, 0x9144C5FEA4C6E0A4, 0x0D33D06565CF620F, + 0x54A48D489F219CA1, 0xC43E5EAC6D63C821, 0xA9728B3A72770DAF, + 0xD7934E7B20DF87EF, 0xE35503B61A3E86E5, 0xCAE321FBC819D504, + 0x129A50B3AC60BFA6, 0xCD5E68EA7E9FB6C3, 0xB01C90199483B1C7, + 0x3DE93CD5C295376C, 0xAED52EDF2AB9AD13, 0x2E60F512C0A07884, + 0xBC3D86A3E36210C9, 0x35269D9B163951CE, 0x0C7D6E2AD0CDB5FA, + 0x59E86297D87F5733, 0x298EF221898DB0E7, 0x55000029D1A5AA7E, + 0x8BC08AE1B5061B45, 0xC2C31C2B6C92703A, 0x94CC596BAF25EF42, + 0x0A1D73DB22540456, 0x04B6A0F9D9C4179A, 0xEFFDAFA2AE3D3C60, + 0xF7C8075BB49496C4, 0x9CC5C7141D1CD4E3, 0x78BD1638218E5534, + 0xB2F11568F850246A, 0xEDFABCFA9502BC29, 0x796CE5F2DA23051B, + 0xAAE128B0DC93537C, 0x3A493DA0EE4B29AE, 0xB5DF6B2C416895D7, + 0xFCABBD25122D7F37, 0x70810B58105DC4B1, 0xE10FDD37F7882A90, + 0x524DCAB5518A3F5C, 0x3C9E85878451255B, 0x4029828119BD34E2, + 0x74A05B6F5D3CECCB, 0xB610021542E13ECA, 0x0FF979D12F59E2AC, + 0x6037DA27E4F9CC50, 0x5E92975A0DF1847D, 0xD66DE190D3E623FE, + 0x5032D6B87B568048, 0x9A36B7CE8235216E, 0x80272A7A24F64B4A, + 0x93EFED8B8C6916F7, 0x37DDBFF44CCE1555, 0x4B95DB5D4B99BD25, + 0x92D3FDA169812FC0, 0xFB1A4A9A90660BB6, 0x730C196946A4B9B2, + 0x81E289AA7F49DA68, 0x64669A0F83B1A05F, 0x27B3FF7D9644F48B, + 0xCC6B615C8DB675B3, 0x674F20B9BCEBBE95, 0x6F31238275655982, + 0x5AE488713E45CF05, 0xBF619F9954C21157, 0xEABAC46040A8EAE9, + 0x454C6FE9F2C0C1CD, 0x419CF6496412691C, 0xD3DC3BEF265B0F70, + 0x6D0E60F5C3578A9E }; + +const uint64_t Tiger::SBOX4[256] = { + 0x5B0E608526323C55, 0x1A46C1A9FA1B59F5, 0xA9E245A17C4C8FFA, + 0x65CA5159DB2955D7, 0x05DB0A76CE35AFC2, 0x81EAC77EA9113D45, + 0x528EF88AB6AC0A0D, 0xA09EA253597BE3FF, 0x430DDFB3AC48CD56, + 0xC4B3A67AF45CE46F, 0x4ECECFD8FBE2D05E, 0x3EF56F10B39935F0, + 0x0B22D6829CD619C6, 0x17FD460A74DF2069, 0x6CF8CC8E8510ED40, + 0xD6C824BF3A6ECAA7, 0x61243D581A817049, 0x048BACB6BBC163A2, + 0xD9A38AC27D44CC32, 0x7FDDFF5BAAF410AB, 0xAD6D495AA804824B, + 0xE1A6A74F2D8C9F94, 0xD4F7851235DEE8E3, 0xFD4B7F886540D893, + 0x247C20042AA4BFDA, 0x096EA1C517D1327C, 0xD56966B4361A6685, + 0x277DA5C31221057D, 0x94D59893A43ACFF7, 0x64F0C51CCDC02281, + 0x3D33BCC4FF6189DB, 0xE005CB184CE66AF1, 0xFF5CCD1D1DB99BEA, + 0xB0B854A7FE42980F, 0x7BD46A6A718D4B9F, 0xD10FA8CC22A5FD8C, + 0xD31484952BE4BD31, 0xC7FA975FCB243847, 0x4886ED1E5846C407, + 0x28CDDB791EB70B04, 0xC2B00BE2F573417F, 0x5C9590452180F877, + 0x7A6BDDFFF370EB00, 0xCE509E38D6D9D6A4, 0xEBEB0F00647FA702, + 0x1DCC06CF76606F06, 0xE4D9F28BA286FF0A, 0xD85A305DC918C262, + 0x475B1D8732225F54, 0x2D4FB51668CCB5FE, 0xA679B9D9D72BBA20, + 0x53841C0D912D43A5, 0x3B7EAA48BF12A4E8, 0x781E0E47F22F1DDF, + 0xEFF20CE60AB50973, 0x20D261D19DFFB742, 0x16A12B03062A2E39, + 0x1960EB2239650495, 0x251C16FED50EB8B8, 0x9AC0C330F826016E, + 0xED152665953E7671, 0x02D63194A6369570, 0x5074F08394B1C987, + 0x70BA598C90B25CE1, 0x794A15810B9742F6, 0x0D5925E9FCAF8C6C, + 0x3067716CD868744E, 0x910AB077E8D7731B, 0x6A61BBDB5AC42F61, + 0x93513EFBF0851567, 0xF494724B9E83E9D5, 0xE887E1985C09648D, + 0x34B1D3C675370CFD, 0xDC35E433BC0D255D, 0xD0AAB84234131BE0, + 0x08042A50B48B7EAF, 0x9997C4EE44A3AB35, 0x829A7B49201799D0, + 0x263B8307B7C54441, 0x752F95F4FD6A6CA6, 0x927217402C08C6E5, + 0x2A8AB754A795D9EE, 0xA442F7552F72943D, 0x2C31334E19781208, + 0x4FA98D7CEAEE6291, 0x55C3862F665DB309, 0xBD0610175D53B1F3, + 0x46FE6CB840413F27, 0x3FE03792DF0CFA59, 0xCFE700372EB85E8F, + 0xA7BE29E7ADBCE118, 0xE544EE5CDE8431DD, 0x8A781B1B41F1873E, + 0xA5C94C78A0D2F0E7, 0x39412E2877B60728, 0xA1265EF3AFC9A62C, + 0xBCC2770C6A2506C5, 0x3AB66DD5DCE1CE12, 0xE65499D04A675B37, + 0x7D8F523481BFD216, 0x0F6F64FCEC15F389, 0x74EFBE618B5B13C8, + 0xACDC82B714273E1D, 0xDD40BFE003199D17, 0x37E99257E7E061F8, + 0xFA52626904775AAA, 0x8BBBF63A463D56F9, 0xF0013F1543A26E64, + 0xA8307E9F879EC898, 0xCC4C27A4150177CC, 0x1B432F2CCA1D3348, + 0xDE1D1F8F9F6FA013, 0x606602A047A7DDD6, 0xD237AB64CC1CB2C7, + 0x9B938E7225FCD1D3, 0xEC4E03708E0FF476, 0xFEB2FBDA3D03C12D, + 0xAE0BCED2EE43889A, 0x22CB8923EBFB4F43, 0x69360D013CF7396D, + 0x855E3602D2D4E022, 0x073805BAD01F784C, 0x33E17A133852F546, + 0xDF4874058AC7B638, 0xBA92B29C678AA14A, 0x0CE89FC76CFAADCD, + 0x5F9D4E0908339E34, 0xF1AFE9291F5923B9, 0x6E3480F60F4A265F, + 0xEEBF3A2AB29B841C, 0xE21938A88F91B4AD, 0x57DFEFF845C6D3C3, + 0x2F006B0BF62CAAF2, 0x62F479EF6F75EE78, 0x11A55AD41C8916A9, + 0xF229D29084FED453, 0x42F1C27B16B000E6, 0x2B1F76749823C074, + 0x4B76ECA3C2745360, 0x8C98F463B91691BD, 0x14BCC93CF1ADE66A, + 0x8885213E6D458397, 0x8E177DF0274D4711, 0xB49B73B5503F2951, + 0x10168168C3F96B6B, 0x0E3D963B63CAB0AE, 0x8DFC4B5655A1DB14, + 0xF789F1356E14DE5C, 0x683E68AF4E51DAC1, 0xC9A84F9D8D4B0FD9, + 0x3691E03F52A0F9D1, 0x5ED86E46E1878E80, 0x3C711A0E99D07150, + 0x5A0865B20C4E9310, 0x56FBFC1FE4F0682E, 0xEA8D5DE3105EDF9B, + 0x71ABFDB12379187A, 0x2EB99DE1BEE77B9C, 0x21ECC0EA33CF4523, + 0x59A4D7521805C7A1, 0x3896F5EB56AE7C72, 0xAA638F3DB18F75DC, + 0x9F39358DABE9808E, 0xB7DEFA91C00B72AC, 0x6B5541FD62492D92, + 0x6DC6DEE8F92E4D5B, 0x353F57ABC4BEEA7E, 0x735769D6DA5690CE, + 0x0A234AA642391484, 0xF6F9508028F80D9D, 0xB8E319A27AB3F215, + 0x31AD9C1151341A4D, 0x773C22A57BEF5805, 0x45C7561A07968633, + 0xF913DA9E249DBE36, 0xDA652D9B78A64C68, 0x4C27A97F3BC334EF, + 0x76621220E66B17F4, 0x967743899ACD7D0B, 0xF3EE5BCAE0ED6782, + 0x409F753600C879FC, 0x06D09A39B5926DB6, 0x6F83AEB0317AC588, + 0x01E6CA4A86381F21, 0x66FF3462D19F3025, 0x72207C24DDFD3BFB, + 0x4AF6B6D3E2ECE2EB, 0x9C994DBEC7EA08DE, 0x49ACE597B09A8BC4, + 0xB38C4766CF0797BA, 0x131B9373C57C2A75, 0xB1822CCE61931E58, + 0x9D7555B909BA1C0C, 0x127FAFDD937D11D2, 0x29DA3BADC66D92E4, + 0xA2C1D57154C2ECBC, 0x58C5134D82F6FE24, 0x1C3AE3515B62274F, + 0xE907C82E01CB8126, 0xF8ED091913E37FCB, 0x3249D8F9C80046C9, + 0x80CF9BEDE388FB63, 0x1881539A116CF19E, 0x5103F3F76BD52457, + 0x15B7E6F5AE47F7A8, 0xDBD7C6DED47E9CCF, 0x44E55C410228BB1A, + 0xB647D4255EDB4E99, 0x5D11882BB8AAFC30, 0xF5098BBB29D3212A, + 0x8FB5EA14E90296B3, 0x677B942157DD025A, 0xFB58E7C0A390ACB5, + 0x89D3674C83BD4A01, 0x9E2DA4DF4BF3B93B, 0xFCC41E328CAB4829, + 0x03F38C96BA582C52, 0xCAD1BDBD7FD85DB2, 0xBBB442C16082AE83, + 0xB95FE86BA5DA9AB0, 0xB22E04673771A93F, 0x845358C9493152D8, + 0xBE2A488697B4541E, 0x95A2DC2DD38E6966, 0xC02C11AC923C852B, + 0x2388B1990DF2A87B, 0x7C8008FA1B4F37BE, 0x1F70D0C84D54E503, + 0x5490ADEC7ECE57D4, 0x002B3C27D9063A3A, 0x7EAEA3848030A2BF, + 0xC602326DED2003C0, 0x83A7287D69A94086, 0xC57A5FCB30F57A8A, + 0xB56844E479EBE779, 0xA373B40F05DCBCE9, 0xD71A786E88570EE2, + 0x879CBACDBDE8F6A0, 0x976AD1BCC164A32F, 0xAB21E25E9666D78B, + 0x901063AAE5E5C33C, 0x9818B34448698D90, 0xE36487AE3E1E8ABB, + 0xAFBDF931893BDCB4, 0x6345A0DC5FBBD519, 0x8628FE269B9465CA, + 0x1E5D01603F9C51EC, 0x4DE44006A15049B7, 0xBF6C70E5F776CBB1, + 0x411218F2EF552BED, 0xCB0C0708705A36A3, 0xE74D14754F986044, + 0xCD56D9430EA8280E, 0xC12591D7535F5065, 0xC83223F1720AEF96, + 0xC3A0396F7363A51F }; + +} diff --git a/comm/third_party/botan/src/lib/hash/tiger/tiger.cpp b/comm/third_party/botan/src/lib/hash/tiger/tiger.cpp new file mode 100644 index 0000000000..ac2038a0fd --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/tiger/tiger.cpp @@ -0,0 +1,190 @@ +/* +* Tiger +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +std::unique_ptr Tiger::copy_state() const + { + return std::unique_ptr(new Tiger(*this)); + } + +namespace { + +/* +* Tiger Mixing Function +*/ +inline void mix(secure_vector& X) + { + X[0] -= X[7] ^ 0xA5A5A5A5A5A5A5A5; + X[1] ^= X[0]; + X[2] += X[1]; + X[3] -= X[2] ^ ((~X[1]) << 19); + X[4] ^= X[3]; + X[5] += X[4]; + X[6] -= X[5] ^ ((~X[4]) >> 23); + X[7] ^= X[6]; + + X[0] += X[7]; + X[1] -= X[0] ^ ((~X[7]) << 19); + X[2] ^= X[1]; + X[3] += X[2]; + X[4] -= X[3] ^ ((~X[2]) >> 23); + X[5] ^= X[4]; + X[6] += X[5]; + X[7] -= X[6] ^ 0x0123456789ABCDEF; + } + +} + +/* +* Tiger Compression Function +*/ +void Tiger::compress_n(const uint8_t input[], size_t blocks) + { + uint64_t A = m_digest[0], B = m_digest[1], C = m_digest[2]; + + for(size_t i = 0; i != blocks; ++i) + { + load_le(m_X.data(), input, m_X.size()); + + pass(A, B, C, m_X, 5); mix(m_X); + pass(C, A, B, m_X, 7); mix(m_X); + pass(B, C, A, m_X, 9); + + for(size_t j = 3; j != m_passes; ++j) + { + mix(m_X); + pass(A, B, C, m_X, 9); + uint64_t T = A; A = C; C = B; B = T; + } + + A = (m_digest[0] ^= A); + B = m_digest[1] = B - m_digest[1]; + C = (m_digest[2] += C); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void Tiger::copy_out(uint8_t output[]) + { + copy_out_vec_le(output, output_length(), m_digest); + } + +/* +* Tiger Pass +*/ +void Tiger::pass(uint64_t& A, uint64_t& B, uint64_t& C, + const secure_vector& X, + uint8_t mul) + { + C ^= X[0]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[1]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + + B ^= X[2]; + C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ + SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; + A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ + SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; + A *= mul; + + C ^= X[3]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[4]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + + B ^= X[5]; + C -= SBOX1[get_byte(7, B)] ^ SBOX2[get_byte(5, B)] ^ + SBOX3[get_byte(3, B)] ^ SBOX4[get_byte(1, B)]; + A += SBOX1[get_byte(0, B)] ^ SBOX2[get_byte(2, B)] ^ + SBOX3[get_byte(4, B)] ^ SBOX4[get_byte(6, B)]; + A *= mul; + + C ^= X[6]; + A -= SBOX1[get_byte(7, C)] ^ SBOX2[get_byte(5, C)] ^ + SBOX3[get_byte(3, C)] ^ SBOX4[get_byte(1, C)]; + B += SBOX1[get_byte(0, C)] ^ SBOX2[get_byte(2, C)] ^ + SBOX3[get_byte(4, C)] ^ SBOX4[get_byte(6, C)]; + B *= mul; + + A ^= X[7]; + B -= SBOX1[get_byte(7, A)] ^ SBOX2[get_byte(5, A)] ^ + SBOX3[get_byte(3, A)] ^ SBOX4[get_byte(1, A)]; + C += SBOX1[get_byte(0, A)] ^ SBOX2[get_byte(2, A)] ^ + SBOX3[get_byte(4, A)] ^ SBOX4[get_byte(6, A)]; + C *= mul; + } + +/* +* Clear memory of sensitive data +*/ +void Tiger::clear() + { + MDx_HashFunction::clear(); + zeroise(m_X); + m_digest[0] = 0x0123456789ABCDEF; + m_digest[1] = 0xFEDCBA9876543210; + m_digest[2] = 0xF096A5B4C3B2E187; + } + +/* +* Return the name of this type +*/ +std::string Tiger::name() const + { + return "Tiger(" + std::to_string(output_length()) + "," + + std::to_string(m_passes) + ")"; + } + +/* +* Tiger Constructor +*/ +Tiger::Tiger(size_t hash_len, size_t passes) : + MDx_HashFunction(64, false, false), + m_X(8), + m_digest(3), + m_hash_len(hash_len), + m_passes(passes) + { + if(output_length() != 16 && output_length() != 20 && output_length() != 24) + throw Invalid_Argument("Tiger: Illegal hash output size: " + + std::to_string(output_length())); + + if(passes < 3) + throw Invalid_Argument("Tiger: Invalid number of passes: " + + std::to_string(passes)); + clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/tiger/tiger.h b/comm/third_party/botan/src/lib/hash/tiger/tiger.h new file mode 100644 index 0000000000..6e17ce83c9 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/tiger/tiger.h @@ -0,0 +1,59 @@ +/* +* Tiger +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TIGER_H_ +#define BOTAN_TIGER_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(tiger.h) + +namespace Botan { + +/** +* Tiger +*/ +class BOTAN_PUBLIC_API(2,0) Tiger final : public MDx_HashFunction + { + public: + std::string name() const override; + size_t output_length() const override { return m_hash_len; } + + HashFunction* clone() const override + { + return new Tiger(output_length(), m_passes); + } + + std::unique_ptr copy_state() const override; + + void clear() override; + + /** + * @param out_size specifies the output length; can be 16, 20, or 24 + * @param passes to make in the algorithm + */ + Tiger(size_t out_size = 24, size_t passes = 3); + private: + void compress_n(const uint8_t[], size_t block) override; + void copy_out(uint8_t[]) override; + + static void pass(uint64_t& A, uint64_t& B, uint64_t& C, + const secure_vector& M, + uint8_t mul); + + static const uint64_t SBOX1[256]; + static const uint64_t SBOX2[256]; + static const uint64_t SBOX3[256]; + static const uint64_t SBOX4[256]; + + secure_vector m_X, m_digest; + const size_t m_hash_len, m_passes; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/hash/whirlpool/info.txt b/comm/third_party/botan/src/lib/hash/whirlpool/info.txt new file mode 100644 index 0000000000..e1a8da77a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/whirlpool/info.txt @@ -0,0 +1,7 @@ + +WHIRLPOOL -> 20131128 + + + +mdx_hash + diff --git a/comm/third_party/botan/src/lib/hash/whirlpool/whirlpool.cpp b/comm/third_party/botan/src/lib/hash/whirlpool/whirlpool.cpp new file mode 100644 index 0000000000..e1ffa4f20c --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/whirlpool/whirlpool.cpp @@ -0,0 +1,150 @@ +/* +* Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::unique_ptr Whirlpool::copy_state() const + { + return std::unique_ptr(new Whirlpool(*this)); + } + +/* +* Whirlpool Compression Function +*/ +void Whirlpool::compress_n(const uint8_t in[], size_t blocks) + { + static const uint64_t RC[10] = { + 0x1823C6E887B8014F, 0x36A6D2F5796F9152, + 0x60BC9B8EA30C7B35, 0x1DE0D7C22E4BFE57, + 0x157737E59FF04ADA, 0x58C9290AB1A06B85, + 0xBD5D10F4CB3E0567, 0xE427418BA77D95D8, + 0xFBEE7C66DD17479E, 0xCA2DBF07AD5A8333 + }; + + for(size_t i = 0; i != blocks; ++i) + { + load_be(m_M.data(), in, m_M.size()); + + uint64_t K0, K1, K2, K3, K4, K5, K6, K7; + K0 = m_digest[0]; K1 = m_digest[1]; K2 = m_digest[2]; K3 = m_digest[3]; + K4 = m_digest[4]; K5 = m_digest[5]; K6 = m_digest[6]; K7 = m_digest[7]; + + uint64_t B0, B1, B2, B3, B4, B5, B6, B7; + B0 = K0 ^ m_M[0]; B1 = K1 ^ m_M[1]; B2 = K2 ^ m_M[2]; B3 = K3 ^ m_M[3]; + B4 = K4 ^ m_M[4]; B5 = K5 ^ m_M[5]; B6 = K6 ^ m_M[6]; B7 = K7 ^ m_M[7]; + + for(size_t j = 0; j != 10; ++j) + { + uint64_t T0, T1, T2, T3, T4, T5, T6, T7; + T0 = C0[get_byte(0, K0)] ^ C1[get_byte(1, K7)] ^ + C2[get_byte(2, K6)] ^ C3[get_byte(3, K5)] ^ + C4[get_byte(4, K4)] ^ C5[get_byte(5, K3)] ^ + C6[get_byte(6, K2)] ^ C7[get_byte(7, K1)] ^ RC[j]; + T1 = C0[get_byte(0, K1)] ^ C1[get_byte(1, K0)] ^ + C2[get_byte(2, K7)] ^ C3[get_byte(3, K6)] ^ + C4[get_byte(4, K5)] ^ C5[get_byte(5, K4)] ^ + C6[get_byte(6, K3)] ^ C7[get_byte(7, K2)]; + T2 = C0[get_byte(0, K2)] ^ C1[get_byte(1, K1)] ^ + C2[get_byte(2, K0)] ^ C3[get_byte(3, K7)] ^ + C4[get_byte(4, K6)] ^ C5[get_byte(5, K5)] ^ + C6[get_byte(6, K4)] ^ C7[get_byte(7, K3)]; + T3 = C0[get_byte(0, K3)] ^ C1[get_byte(1, K2)] ^ + C2[get_byte(2, K1)] ^ C3[get_byte(3, K0)] ^ + C4[get_byte(4, K7)] ^ C5[get_byte(5, K6)] ^ + C6[get_byte(6, K5)] ^ C7[get_byte(7, K4)]; + T4 = C0[get_byte(0, K4)] ^ C1[get_byte(1, K3)] ^ + C2[get_byte(2, K2)] ^ C3[get_byte(3, K1)] ^ + C4[get_byte(4, K0)] ^ C5[get_byte(5, K7)] ^ + C6[get_byte(6, K6)] ^ C7[get_byte(7, K5)]; + T5 = C0[get_byte(0, K5)] ^ C1[get_byte(1, K4)] ^ + C2[get_byte(2, K3)] ^ C3[get_byte(3, K2)] ^ + C4[get_byte(4, K1)] ^ C5[get_byte(5, K0)] ^ + C6[get_byte(6, K7)] ^ C7[get_byte(7, K6)]; + T6 = C0[get_byte(0, K6)] ^ C1[get_byte(1, K5)] ^ + C2[get_byte(2, K4)] ^ C3[get_byte(3, K3)] ^ + C4[get_byte(4, K2)] ^ C5[get_byte(5, K1)] ^ + C6[get_byte(6, K0)] ^ C7[get_byte(7, K7)]; + T7 = C0[get_byte(0, K7)] ^ C1[get_byte(1, K6)] ^ + C2[get_byte(2, K5)] ^ C3[get_byte(3, K4)] ^ + C4[get_byte(4, K3)] ^ C5[get_byte(5, K2)] ^ + C6[get_byte(6, K1)] ^ C7[get_byte(7, K0)]; + + K0 = T0; K1 = T1; K2 = T2; K3 = T3; + K4 = T4; K5 = T5; K6 = T6; K7 = T7; + + T0 = C0[get_byte(0, B0)] ^ C1[get_byte(1, B7)] ^ + C2[get_byte(2, B6)] ^ C3[get_byte(3, B5)] ^ + C4[get_byte(4, B4)] ^ C5[get_byte(5, B3)] ^ + C6[get_byte(6, B2)] ^ C7[get_byte(7, B1)] ^ K0; + T1 = C0[get_byte(0, B1)] ^ C1[get_byte(1, B0)] ^ + C2[get_byte(2, B7)] ^ C3[get_byte(3, B6)] ^ + C4[get_byte(4, B5)] ^ C5[get_byte(5, B4)] ^ + C6[get_byte(6, B3)] ^ C7[get_byte(7, B2)] ^ K1; + T2 = C0[get_byte(0, B2)] ^ C1[get_byte(1, B1)] ^ + C2[get_byte(2, B0)] ^ C3[get_byte(3, B7)] ^ + C4[get_byte(4, B6)] ^ C5[get_byte(5, B5)] ^ + C6[get_byte(6, B4)] ^ C7[get_byte(7, B3)] ^ K2; + T3 = C0[get_byte(0, B3)] ^ C1[get_byte(1, B2)] ^ + C2[get_byte(2, B1)] ^ C3[get_byte(3, B0)] ^ + C4[get_byte(4, B7)] ^ C5[get_byte(5, B6)] ^ + C6[get_byte(6, B5)] ^ C7[get_byte(7, B4)] ^ K3; + T4 = C0[get_byte(0, B4)] ^ C1[get_byte(1, B3)] ^ + C2[get_byte(2, B2)] ^ C3[get_byte(3, B1)] ^ + C4[get_byte(4, B0)] ^ C5[get_byte(5, B7)] ^ + C6[get_byte(6, B6)] ^ C7[get_byte(7, B5)] ^ K4; + T5 = C0[get_byte(0, B5)] ^ C1[get_byte(1, B4)] ^ + C2[get_byte(2, B3)] ^ C3[get_byte(3, B2)] ^ + C4[get_byte(4, B1)] ^ C5[get_byte(5, B0)] ^ + C6[get_byte(6, B7)] ^ C7[get_byte(7, B6)] ^ K5; + T6 = C0[get_byte(0, B6)] ^ C1[get_byte(1, B5)] ^ + C2[get_byte(2, B4)] ^ C3[get_byte(3, B3)] ^ + C4[get_byte(4, B2)] ^ C5[get_byte(5, B1)] ^ + C6[get_byte(6, B0)] ^ C7[get_byte(7, B7)] ^ K6; + T7 = C0[get_byte(0, B7)] ^ C1[get_byte(1, B6)] ^ + C2[get_byte(2, B5)] ^ C3[get_byte(3, B4)] ^ + C4[get_byte(4, B3)] ^ C5[get_byte(5, B2)] ^ + C6[get_byte(6, B1)] ^ C7[get_byte(7, B0)] ^ K7; + + B0 = T0; B1 = T1; B2 = T2; B3 = T3; + B4 = T4; B5 = T5; B6 = T6; B7 = T7; + } + + m_digest[0] ^= B0 ^ m_M[0]; + m_digest[1] ^= B1 ^ m_M[1]; + m_digest[2] ^= B2 ^ m_M[2]; + m_digest[3] ^= B3 ^ m_M[3]; + m_digest[4] ^= B4 ^ m_M[4]; + m_digest[5] ^= B5 ^ m_M[5]; + m_digest[6] ^= B6 ^ m_M[6]; + m_digest[7] ^= B7 ^ m_M[7]; + + in += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void Whirlpool::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void Whirlpool::clear() + { + MDx_HashFunction::clear(); + zeroise(m_M); + zeroise(m_digest); + } + +} diff --git a/comm/third_party/botan/src/lib/hash/whirlpool/whrl_tab.cpp b/comm/third_party/botan/src/lib/hash/whirlpool/whrl_tab.cpp new file mode 100644 index 0000000000..e4be36247e --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/whirlpool/whrl_tab.cpp @@ -0,0 +1,540 @@ +/* +* Diffusion Tables for Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +alignas(64) const uint64_t Whirlpool::C0[256] = { +0x18186018C07830D8, 0x23238C2305AF4626, 0xC6C63FC67EF991B8, 0xE8E887E8136FCDFB, +0x878726874CA113CB, 0xB8B8DAB8A9626D11, 0x0101040108050209, 0x4F4F214F426E9E0D, +0x3636D836ADEE6C9B, 0xA6A6A2A6590451FF, 0xD2D26FD2DEBDB90C, 0xF5F5F3F5FB06F70E, +0x7979F979EF80F296, 0x6F6FA16F5FCEDE30, 0x91917E91FCEF3F6D, 0x52525552AA07A4F8, +0x60609D6027FDC047, 0xBCBCCABC89766535, 0x9B9B569BACCD2B37, 0x8E8E028E048C018A, +0xA3A3B6A371155BD2, 0x0C0C300C603C186C, 0x7B7BF17BFF8AF684, 0x3535D435B5E16A80, +0x1D1D741DE8693AF5, 0xE0E0A7E05347DDB3, 0xD7D77BD7F6ACB321, 0xC2C22FC25EED999C, +0x2E2EB82E6D965C43, 0x4B4B314B627A9629, 0xFEFEDFFEA321E15D, 0x575741578216AED5, +0x15155415A8412ABD, 0x7777C1779FB6EEE8, 0x3737DC37A5EB6E92, 0xE5E5B3E57B56D79E, +0x9F9F469F8CD92313, 0xF0F0E7F0D317FD23, 0x4A4A354A6A7F9420, 0xDADA4FDA9E95A944, +0x58587D58FA25B0A2, 0xC9C903C906CA8FCF, 0x2929A429558D527C, 0x0A0A280A5022145A, +0xB1B1FEB1E14F7F50, 0xA0A0BAA0691A5DC9, 0x6B6BB16B7FDAD614, 0x85852E855CAB17D9, +0xBDBDCEBD8173673C, 0x5D5D695DD234BA8F, 0x1010401080502090, 0xF4F4F7F4F303F507, +0xCBCB0BCB16C08BDD, 0x3E3EF83EEDC67CD3, 0x0505140528110A2D, 0x676781671FE6CE78, +0xE4E4B7E47353D597, 0x27279C2725BB4E02, 0x4141194132588273, 0x8B8B168B2C9D0BA7, +0xA7A7A6A7510153F6, 0x7D7DE97DCF94FAB2, 0x95956E95DCFB3749, 0xD8D847D88E9FAD56, +0xFBFBCBFB8B30EB70, 0xEEEE9FEE2371C1CD, 0x7C7CED7CC791F8BB, 0x6666856617E3CC71, +0xDDDD53DDA68EA77B, 0x17175C17B84B2EAF, 0x4747014702468E45, 0x9E9E429E84DC211A, +0xCACA0FCA1EC589D4, 0x2D2DB42D75995A58, 0xBFBFC6BF9179632E, 0x07071C07381B0E3F, +0xADAD8EAD012347AC, 0x5A5A755AEA2FB4B0, 0x838336836CB51BEF, 0x3333CC3385FF66B6, +0x636391633FF2C65C, 0x02020802100A0412, 0xAAAA92AA39384993, 0x7171D971AFA8E2DE, +0xC8C807C80ECF8DC6, 0x19196419C87D32D1, 0x494939497270923B, 0xD9D943D9869AAF5F, +0xF2F2EFF2C31DF931, 0xE3E3ABE34B48DBA8, 0x5B5B715BE22AB6B9, 0x88881A8834920DBC, +0x9A9A529AA4C8293E, 0x262698262DBE4C0B, 0x3232C8328DFA64BF, 0xB0B0FAB0E94A7D59, +0xE9E983E91B6ACFF2, 0x0F0F3C0F78331E77, 0xD5D573D5E6A6B733, 0x80803A8074BA1DF4, +0xBEBEC2BE997C6127, 0xCDCD13CD26DE87EB, 0x3434D034BDE46889, 0x48483D487A759032, +0xFFFFDBFFAB24E354, 0x7A7AF57AF78FF48D, 0x90907A90F4EA3D64, 0x5F5F615FC23EBE9D, +0x202080201DA0403D, 0x6868BD6867D5D00F, 0x1A1A681AD07234CA, 0xAEAE82AE192C41B7, +0xB4B4EAB4C95E757D, 0x54544D549A19A8CE, 0x93937693ECE53B7F, 0x222288220DAA442F, +0x64648D6407E9C863, 0xF1F1E3F1DB12FF2A, 0x7373D173BFA2E6CC, 0x12124812905A2482, +0x40401D403A5D807A, 0x0808200840281048, 0xC3C32BC356E89B95, 0xECEC97EC337BC5DF, +0xDBDB4BDB9690AB4D, 0xA1A1BEA1611F5FC0, 0x8D8D0E8D1C830791, 0x3D3DF43DF5C97AC8, +0x97976697CCF1335B, 0x0000000000000000, 0xCFCF1BCF36D483F9, 0x2B2BAC2B4587566E, +0x7676C57697B3ECE1, 0x8282328264B019E6, 0xD6D67FD6FEA9B128, 0x1B1B6C1BD87736C3, +0xB5B5EEB5C15B7774, 0xAFAF86AF112943BE, 0x6A6AB56A77DFD41D, 0x50505D50BA0DA0EA, +0x45450945124C8A57, 0xF3F3EBF3CB18FB38, 0x3030C0309DF060AD, 0xEFEF9BEF2B74C3C4, +0x3F3FFC3FE5C37EDA, 0x55554955921CAAC7, 0xA2A2B2A2791059DB, 0xEAEA8FEA0365C9E9, +0x656589650FECCA6A, 0xBABAD2BAB9686903, 0x2F2FBC2F65935E4A, 0xC0C027C04EE79D8E, +0xDEDE5FDEBE81A160, 0x1C1C701CE06C38FC, 0xFDFDD3FDBB2EE746, 0x4D4D294D52649A1F, +0x92927292E4E03976, 0x7575C9758FBCEAFA, 0x06061806301E0C36, 0x8A8A128A249809AE, +0xB2B2F2B2F940794B, 0xE6E6BFE66359D185, 0x0E0E380E70361C7E, 0x1F1F7C1FF8633EE7, +0x6262956237F7C455, 0xD4D477D4EEA3B53A, 0xA8A89AA829324D81, 0x96966296C4F43152, +0xF9F9C3F99B3AEF62, 0xC5C533C566F697A3, 0x2525942535B14A10, 0x59597959F220B2AB, +0x84842A8454AE15D0, 0x7272D572B7A7E4C5, 0x3939E439D5DD72EC, 0x4C4C2D4C5A619816, +0x5E5E655ECA3BBC94, 0x7878FD78E785F09F, 0x3838E038DDD870E5, 0x8C8C0A8C14860598, +0xD1D163D1C6B2BF17, 0xA5A5AEA5410B57E4, 0xE2E2AFE2434DD9A1, 0x616199612FF8C24E, +0xB3B3F6B3F1457B42, 0x2121842115A54234, 0x9C9C4A9C94D62508, 0x1E1E781EF0663CEE, +0x4343114322528661, 0xC7C73BC776FC93B1, 0xFCFCD7FCB32BE54F, 0x0404100420140824, +0x51515951B208A2E3, 0x99995E99BCC72F25, 0x6D6DA96D4FC4DA22, 0x0D0D340D68391A65, +0xFAFACFFA8335E979, 0xDFDF5BDFB684A369, 0x7E7EE57ED79BFCA9, 0x242490243DB44819, +0x3B3BEC3BC5D776FE, 0xABAB96AB313D4B9A, 0xCECE1FCE3ED181F0, 0x1111441188552299, +0x8F8F068F0C890383, 0x4E4E254E4A6B9C04, 0xB7B7E6B7D1517366, 0xEBEB8BEB0B60CBE0, +0x3C3CF03CFDCC78C1, 0x81813E817CBF1FFD, 0x94946A94D4FE3540, 0xF7F7FBF7EB0CF31C, +0xB9B9DEB9A1676F18, 0x13134C13985F268B, 0x2C2CB02C7D9C5851, 0xD3D36BD3D6B8BB05, +0xE7E7BBE76B5CD38C, 0x6E6EA56E57CBDC39, 0xC4C437C46EF395AA, 0x03030C03180F061B, +0x565645568A13ACDC, 0x44440D441A49885E, 0x7F7FE17FDF9EFEA0, 0xA9A99EA921374F88, +0x2A2AA82A4D825467, 0xBBBBD6BBB16D6B0A, 0xC1C123C146E29F87, 0x53535153A202A6F1, +0xDCDC57DCAE8BA572, 0x0B0B2C0B58271653, 0x9D9D4E9D9CD32701, 0x6C6CAD6C47C1D82B, +0x3131C43195F562A4, 0x7474CD7487B9E8F3, 0xF6F6FFF6E309F115, 0x464605460A438C4C, +0xACAC8AAC092645A5, 0x89891E893C970FB5, 0x14145014A04428B4, 0xE1E1A3E15B42DFBA, +0x16165816B04E2CA6, 0x3A3AE83ACDD274F7, 0x6969B9696FD0D206, 0x09092409482D1241, +0x7070DD70A7ADE0D7, 0xB6B6E2B6D954716F, 0xD0D067D0CEB7BD1E, 0xEDED93ED3B7EC7D6, +0xCCCC17CC2EDB85E2, 0x424215422A578468, 0x98985A98B4C22D2C, 0xA4A4AAA4490E55ED, +0x2828A0285D885075, 0x5C5C6D5CDA31B886, 0xF8F8C7F8933FED6B, 0x8686228644A411C2 }; + +alignas(64) const uint64_t Whirlpool::C1[256] = { +0xD818186018C07830, 0x2623238C2305AF46, 0xB8C6C63FC67EF991, 0xFBE8E887E8136FCD, +0xCB878726874CA113, 0x11B8B8DAB8A9626D, 0x0901010401080502, 0x0D4F4F214F426E9E, +0x9B3636D836ADEE6C, 0xFFA6A6A2A6590451, 0x0CD2D26FD2DEBDB9, 0x0EF5F5F3F5FB06F7, +0x967979F979EF80F2, 0x306F6FA16F5FCEDE, 0x6D91917E91FCEF3F, 0xF852525552AA07A4, +0x4760609D6027FDC0, 0x35BCBCCABC897665, 0x379B9B569BACCD2B, 0x8A8E8E028E048C01, +0xD2A3A3B6A371155B, 0x6C0C0C300C603C18, 0x847B7BF17BFF8AF6, 0x803535D435B5E16A, +0xF51D1D741DE8693A, 0xB3E0E0A7E05347DD, 0x21D7D77BD7F6ACB3, 0x9CC2C22FC25EED99, +0x432E2EB82E6D965C, 0x294B4B314B627A96, 0x5DFEFEDFFEA321E1, 0xD5575741578216AE, +0xBD15155415A8412A, 0xE87777C1779FB6EE, 0x923737DC37A5EB6E, 0x9EE5E5B3E57B56D7, +0x139F9F469F8CD923, 0x23F0F0E7F0D317FD, 0x204A4A354A6A7F94, 0x44DADA4FDA9E95A9, +0xA258587D58FA25B0, 0xCFC9C903C906CA8F, 0x7C2929A429558D52, 0x5A0A0A280A502214, +0x50B1B1FEB1E14F7F, 0xC9A0A0BAA0691A5D, 0x146B6BB16B7FDAD6, 0xD985852E855CAB17, +0x3CBDBDCEBD817367, 0x8F5D5D695DD234BA, 0x9010104010805020, 0x07F4F4F7F4F303F5, +0xDDCBCB0BCB16C08B, 0xD33E3EF83EEDC67C, 0x2D0505140528110A, 0x78676781671FE6CE, +0x97E4E4B7E47353D5, 0x0227279C2725BB4E, 0x7341411941325882, 0xA78B8B168B2C9D0B, +0xF6A7A7A6A7510153, 0xB27D7DE97DCF94FA, 0x4995956E95DCFB37, 0x56D8D847D88E9FAD, +0x70FBFBCBFB8B30EB, 0xCDEEEE9FEE2371C1, 0xBB7C7CED7CC791F8, 0x716666856617E3CC, +0x7BDDDD53DDA68EA7, 0xAF17175C17B84B2E, 0x454747014702468E, 0x1A9E9E429E84DC21, +0xD4CACA0FCA1EC589, 0x582D2DB42D75995A, 0x2EBFBFC6BF917963, 0x3F07071C07381B0E, +0xACADAD8EAD012347, 0xB05A5A755AEA2FB4, 0xEF838336836CB51B, 0xB63333CC3385FF66, +0x5C636391633FF2C6, 0x1202020802100A04, 0x93AAAA92AA393849, 0xDE7171D971AFA8E2, +0xC6C8C807C80ECF8D, 0xD119196419C87D32, 0x3B49493949727092, 0x5FD9D943D9869AAF, +0x31F2F2EFF2C31DF9, 0xA8E3E3ABE34B48DB, 0xB95B5B715BE22AB6, 0xBC88881A8834920D, +0x3E9A9A529AA4C829, 0x0B262698262DBE4C, 0xBF3232C8328DFA64, 0x59B0B0FAB0E94A7D, +0xF2E9E983E91B6ACF, 0x770F0F3C0F78331E, 0x33D5D573D5E6A6B7, 0xF480803A8074BA1D, +0x27BEBEC2BE997C61, 0xEBCDCD13CD26DE87, 0x893434D034BDE468, 0x3248483D487A7590, +0x54FFFFDBFFAB24E3, 0x8D7A7AF57AF78FF4, 0x6490907A90F4EA3D, 0x9D5F5F615FC23EBE, +0x3D202080201DA040, 0x0F6868BD6867D5D0, 0xCA1A1A681AD07234, 0xB7AEAE82AE192C41, +0x7DB4B4EAB4C95E75, 0xCE54544D549A19A8, 0x7F93937693ECE53B, 0x2F222288220DAA44, +0x6364648D6407E9C8, 0x2AF1F1E3F1DB12FF, 0xCC7373D173BFA2E6, 0x8212124812905A24, +0x7A40401D403A5D80, 0x4808082008402810, 0x95C3C32BC356E89B, 0xDFECEC97EC337BC5, +0x4DDBDB4BDB9690AB, 0xC0A1A1BEA1611F5F, 0x918D8D0E8D1C8307, 0xC83D3DF43DF5C97A, +0x5B97976697CCF133, 0x0000000000000000, 0xF9CFCF1BCF36D483, 0x6E2B2BAC2B458756, +0xE17676C57697B3EC, 0xE68282328264B019, 0x28D6D67FD6FEA9B1, 0xC31B1B6C1BD87736, +0x74B5B5EEB5C15B77, 0xBEAFAF86AF112943, 0x1D6A6AB56A77DFD4, 0xEA50505D50BA0DA0, +0x5745450945124C8A, 0x38F3F3EBF3CB18FB, 0xAD3030C0309DF060, 0xC4EFEF9BEF2B74C3, +0xDA3F3FFC3FE5C37E, 0xC755554955921CAA, 0xDBA2A2B2A2791059, 0xE9EAEA8FEA0365C9, +0x6A656589650FECCA, 0x03BABAD2BAB96869, 0x4A2F2FBC2F65935E, 0x8EC0C027C04EE79D, +0x60DEDE5FDEBE81A1, 0xFC1C1C701CE06C38, 0x46FDFDD3FDBB2EE7, 0x1F4D4D294D52649A, +0x7692927292E4E039, 0xFA7575C9758FBCEA, 0x3606061806301E0C, 0xAE8A8A128A249809, +0x4BB2B2F2B2F94079, 0x85E6E6BFE66359D1, 0x7E0E0E380E70361C, 0xE71F1F7C1FF8633E, +0x556262956237F7C4, 0x3AD4D477D4EEA3B5, 0x81A8A89AA829324D, 0x5296966296C4F431, +0x62F9F9C3F99B3AEF, 0xA3C5C533C566F697, 0x102525942535B14A, 0xAB59597959F220B2, +0xD084842A8454AE15, 0xC57272D572B7A7E4, 0xEC3939E439D5DD72, 0x164C4C2D4C5A6198, +0x945E5E655ECA3BBC, 0x9F7878FD78E785F0, 0xE53838E038DDD870, 0x988C8C0A8C148605, +0x17D1D163D1C6B2BF, 0xE4A5A5AEA5410B57, 0xA1E2E2AFE2434DD9, 0x4E616199612FF8C2, +0x42B3B3F6B3F1457B, 0x342121842115A542, 0x089C9C4A9C94D625, 0xEE1E1E781EF0663C, +0x6143431143225286, 0xB1C7C73BC776FC93, 0x4FFCFCD7FCB32BE5, 0x2404041004201408, +0xE351515951B208A2, 0x2599995E99BCC72F, 0x226D6DA96D4FC4DA, 0x650D0D340D68391A, +0x79FAFACFFA8335E9, 0x69DFDF5BDFB684A3, 0xA97E7EE57ED79BFC, 0x19242490243DB448, +0xFE3B3BEC3BC5D776, 0x9AABAB96AB313D4B, 0xF0CECE1FCE3ED181, 0x9911114411885522, +0x838F8F068F0C8903, 0x044E4E254E4A6B9C, 0x66B7B7E6B7D15173, 0xE0EBEB8BEB0B60CB, +0xC13C3CF03CFDCC78, 0xFD81813E817CBF1F, 0x4094946A94D4FE35, 0x1CF7F7FBF7EB0CF3, +0x18B9B9DEB9A1676F, 0x8B13134C13985F26, 0x512C2CB02C7D9C58, 0x05D3D36BD3D6B8BB, +0x8CE7E7BBE76B5CD3, 0x396E6EA56E57CBDC, 0xAAC4C437C46EF395, 0x1B03030C03180F06, +0xDC565645568A13AC, 0x5E44440D441A4988, 0xA07F7FE17FDF9EFE, 0x88A9A99EA921374F, +0x672A2AA82A4D8254, 0x0ABBBBD6BBB16D6B, 0x87C1C123C146E29F, 0xF153535153A202A6, +0x72DCDC57DCAE8BA5, 0x530B0B2C0B582716, 0x019D9D4E9D9CD327, 0x2B6C6CAD6C47C1D8, +0xA43131C43195F562, 0xF37474CD7487B9E8, 0x15F6F6FFF6E309F1, 0x4C464605460A438C, +0xA5ACAC8AAC092645, 0xB589891E893C970F, 0xB414145014A04428, 0xBAE1E1A3E15B42DF, +0xA616165816B04E2C, 0xF73A3AE83ACDD274, 0x066969B9696FD0D2, 0x4109092409482D12, +0xD77070DD70A7ADE0, 0x6FB6B6E2B6D95471, 0x1ED0D067D0CEB7BD, 0xD6EDED93ED3B7EC7, +0xE2CCCC17CC2EDB85, 0x68424215422A5784, 0x2C98985A98B4C22D, 0xEDA4A4AAA4490E55, +0x752828A0285D8850, 0x865C5C6D5CDA31B8, 0x6BF8F8C7F8933FED, 0xC28686228644A411 }; + +alignas(64) const uint64_t Whirlpool::C2[256] = { +0x30D818186018C078, 0x462623238C2305AF, 0x91B8C6C63FC67EF9, 0xCDFBE8E887E8136F, +0x13CB878726874CA1, 0x6D11B8B8DAB8A962, 0x0209010104010805, 0x9E0D4F4F214F426E, +0x6C9B3636D836ADEE, 0x51FFA6A6A2A65904, 0xB90CD2D26FD2DEBD, 0xF70EF5F5F3F5FB06, +0xF2967979F979EF80, 0xDE306F6FA16F5FCE, 0x3F6D91917E91FCEF, 0xA4F852525552AA07, +0xC04760609D6027FD, 0x6535BCBCCABC8976, 0x2B379B9B569BACCD, 0x018A8E8E028E048C, +0x5BD2A3A3B6A37115, 0x186C0C0C300C603C, 0xF6847B7BF17BFF8A, 0x6A803535D435B5E1, +0x3AF51D1D741DE869, 0xDDB3E0E0A7E05347, 0xB321D7D77BD7F6AC, 0x999CC2C22FC25EED, +0x5C432E2EB82E6D96, 0x96294B4B314B627A, 0xE15DFEFEDFFEA321, 0xAED5575741578216, +0x2ABD15155415A841, 0xEEE87777C1779FB6, 0x6E923737DC37A5EB, 0xD79EE5E5B3E57B56, +0x23139F9F469F8CD9, 0xFD23F0F0E7F0D317, 0x94204A4A354A6A7F, 0xA944DADA4FDA9E95, +0xB0A258587D58FA25, 0x8FCFC9C903C906CA, 0x527C2929A429558D, 0x145A0A0A280A5022, +0x7F50B1B1FEB1E14F, 0x5DC9A0A0BAA0691A, 0xD6146B6BB16B7FDA, 0x17D985852E855CAB, +0x673CBDBDCEBD8173, 0xBA8F5D5D695DD234, 0x2090101040108050, 0xF507F4F4F7F4F303, +0x8BDDCBCB0BCB16C0, 0x7CD33E3EF83EEDC6, 0x0A2D050514052811, 0xCE78676781671FE6, +0xD597E4E4B7E47353, 0x4E0227279C2725BB, 0x8273414119413258, 0x0BA78B8B168B2C9D, +0x53F6A7A7A6A75101, 0xFAB27D7DE97DCF94, 0x374995956E95DCFB, 0xAD56D8D847D88E9F, +0xEB70FBFBCBFB8B30, 0xC1CDEEEE9FEE2371, 0xF8BB7C7CED7CC791, 0xCC716666856617E3, +0xA77BDDDD53DDA68E, 0x2EAF17175C17B84B, 0x8E45474701470246, 0x211A9E9E429E84DC, +0x89D4CACA0FCA1EC5, 0x5A582D2DB42D7599, 0x632EBFBFC6BF9179, 0x0E3F07071C07381B, +0x47ACADAD8EAD0123, 0xB4B05A5A755AEA2F, 0x1BEF838336836CB5, 0x66B63333CC3385FF, +0xC65C636391633FF2, 0x041202020802100A, 0x4993AAAA92AA3938, 0xE2DE7171D971AFA8, +0x8DC6C8C807C80ECF, 0x32D119196419C87D, 0x923B494939497270, 0xAF5FD9D943D9869A, +0xF931F2F2EFF2C31D, 0xDBA8E3E3ABE34B48, 0xB6B95B5B715BE22A, 0x0DBC88881A883492, +0x293E9A9A529AA4C8, 0x4C0B262698262DBE, 0x64BF3232C8328DFA, 0x7D59B0B0FAB0E94A, +0xCFF2E9E983E91B6A, 0x1E770F0F3C0F7833, 0xB733D5D573D5E6A6, 0x1DF480803A8074BA, +0x6127BEBEC2BE997C, 0x87EBCDCD13CD26DE, 0x68893434D034BDE4, 0x903248483D487A75, +0xE354FFFFDBFFAB24, 0xF48D7A7AF57AF78F, 0x3D6490907A90F4EA, 0xBE9D5F5F615FC23E, +0x403D202080201DA0, 0xD00F6868BD6867D5, 0x34CA1A1A681AD072, 0x41B7AEAE82AE192C, +0x757DB4B4EAB4C95E, 0xA8CE54544D549A19, 0x3B7F93937693ECE5, 0x442F222288220DAA, +0xC86364648D6407E9, 0xFF2AF1F1E3F1DB12, 0xE6CC7373D173BFA2, 0x248212124812905A, +0x807A40401D403A5D, 0x1048080820084028, 0x9B95C3C32BC356E8, 0xC5DFECEC97EC337B, +0xAB4DDBDB4BDB9690, 0x5FC0A1A1BEA1611F, 0x07918D8D0E8D1C83, 0x7AC83D3DF43DF5C9, +0x335B97976697CCF1, 0x0000000000000000, 0x83F9CFCF1BCF36D4, 0x566E2B2BAC2B4587, +0xECE17676C57697B3, 0x19E68282328264B0, 0xB128D6D67FD6FEA9, 0x36C31B1B6C1BD877, +0x7774B5B5EEB5C15B, 0x43BEAFAF86AF1129, 0xD41D6A6AB56A77DF, 0xA0EA50505D50BA0D, +0x8A5745450945124C, 0xFB38F3F3EBF3CB18, 0x60AD3030C0309DF0, 0xC3C4EFEF9BEF2B74, +0x7EDA3F3FFC3FE5C3, 0xAAC755554955921C, 0x59DBA2A2B2A27910, 0xC9E9EAEA8FEA0365, +0xCA6A656589650FEC, 0x6903BABAD2BAB968, 0x5E4A2F2FBC2F6593, 0x9D8EC0C027C04EE7, +0xA160DEDE5FDEBE81, 0x38FC1C1C701CE06C, 0xE746FDFDD3FDBB2E, 0x9A1F4D4D294D5264, +0x397692927292E4E0, 0xEAFA7575C9758FBC, 0x0C3606061806301E, 0x09AE8A8A128A2498, +0x794BB2B2F2B2F940, 0xD185E6E6BFE66359, 0x1C7E0E0E380E7036, 0x3EE71F1F7C1FF863, +0xC4556262956237F7, 0xB53AD4D477D4EEA3, 0x4D81A8A89AA82932, 0x315296966296C4F4, +0xEF62F9F9C3F99B3A, 0x97A3C5C533C566F6, 0x4A102525942535B1, 0xB2AB59597959F220, +0x15D084842A8454AE, 0xE4C57272D572B7A7, 0x72EC3939E439D5DD, 0x98164C4C2D4C5A61, +0xBC945E5E655ECA3B, 0xF09F7878FD78E785, 0x70E53838E038DDD8, 0x05988C8C0A8C1486, +0xBF17D1D163D1C6B2, 0x57E4A5A5AEA5410B, 0xD9A1E2E2AFE2434D, 0xC24E616199612FF8, +0x7B42B3B3F6B3F145, 0x42342121842115A5, 0x25089C9C4A9C94D6, 0x3CEE1E1E781EF066, +0x8661434311432252, 0x93B1C7C73BC776FC, 0xE54FFCFCD7FCB32B, 0x0824040410042014, +0xA2E351515951B208, 0x2F2599995E99BCC7, 0xDA226D6DA96D4FC4, 0x1A650D0D340D6839, +0xE979FAFACFFA8335, 0xA369DFDF5BDFB684, 0xFCA97E7EE57ED79B, 0x4819242490243DB4, +0x76FE3B3BEC3BC5D7, 0x4B9AABAB96AB313D, 0x81F0CECE1FCE3ED1, 0x2299111144118855, +0x03838F8F068F0C89, 0x9C044E4E254E4A6B, 0x7366B7B7E6B7D151, 0xCBE0EBEB8BEB0B60, +0x78C13C3CF03CFDCC, 0x1FFD81813E817CBF, 0x354094946A94D4FE, 0xF31CF7F7FBF7EB0C, +0x6F18B9B9DEB9A167, 0x268B13134C13985F, 0x58512C2CB02C7D9C, 0xBB05D3D36BD3D6B8, +0xD38CE7E7BBE76B5C, 0xDC396E6EA56E57CB, 0x95AAC4C437C46EF3, 0x061B03030C03180F, +0xACDC565645568A13, 0x885E44440D441A49, 0xFEA07F7FE17FDF9E, 0x4F88A9A99EA92137, +0x54672A2AA82A4D82, 0x6B0ABBBBD6BBB16D, 0x9F87C1C123C146E2, 0xA6F153535153A202, +0xA572DCDC57DCAE8B, 0x16530B0B2C0B5827, 0x27019D9D4E9D9CD3, 0xD82B6C6CAD6C47C1, +0x62A43131C43195F5, 0xE8F37474CD7487B9, 0xF115F6F6FFF6E309, 0x8C4C464605460A43, +0x45A5ACAC8AAC0926, 0x0FB589891E893C97, 0x28B414145014A044, 0xDFBAE1E1A3E15B42, +0x2CA616165816B04E, 0x74F73A3AE83ACDD2, 0xD2066969B9696FD0, 0x124109092409482D, +0xE0D77070DD70A7AD, 0x716FB6B6E2B6D954, 0xBD1ED0D067D0CEB7, 0xC7D6EDED93ED3B7E, +0x85E2CCCC17CC2EDB, 0x8468424215422A57, 0x2D2C98985A98B4C2, 0x55EDA4A4AAA4490E, +0x50752828A0285D88, 0xB8865C5C6D5CDA31, 0xED6BF8F8C7F8933F, 0x11C28686228644A4 }; + +alignas(64) const uint64_t Whirlpool::C3[256] = { +0x7830D818186018C0, 0xAF462623238C2305, 0xF991B8C6C63FC67E, 0x6FCDFBE8E887E813, +0xA113CB878726874C, 0x626D11B8B8DAB8A9, 0x0502090101040108, 0x6E9E0D4F4F214F42, +0xEE6C9B3636D836AD, 0x0451FFA6A6A2A659, 0xBDB90CD2D26FD2DE, 0x06F70EF5F5F3F5FB, +0x80F2967979F979EF, 0xCEDE306F6FA16F5F, 0xEF3F6D91917E91FC, 0x07A4F852525552AA, +0xFDC04760609D6027, 0x766535BCBCCABC89, 0xCD2B379B9B569BAC, 0x8C018A8E8E028E04, +0x155BD2A3A3B6A371, 0x3C186C0C0C300C60, 0x8AF6847B7BF17BFF, 0xE16A803535D435B5, +0x693AF51D1D741DE8, 0x47DDB3E0E0A7E053, 0xACB321D7D77BD7F6, 0xED999CC2C22FC25E, +0x965C432E2EB82E6D, 0x7A96294B4B314B62, 0x21E15DFEFEDFFEA3, 0x16AED55757415782, +0x412ABD15155415A8, 0xB6EEE87777C1779F, 0xEB6E923737DC37A5, 0x56D79EE5E5B3E57B, +0xD923139F9F469F8C, 0x17FD23F0F0E7F0D3, 0x7F94204A4A354A6A, 0x95A944DADA4FDA9E, +0x25B0A258587D58FA, 0xCA8FCFC9C903C906, 0x8D527C2929A42955, 0x22145A0A0A280A50, +0x4F7F50B1B1FEB1E1, 0x1A5DC9A0A0BAA069, 0xDAD6146B6BB16B7F, 0xAB17D985852E855C, +0x73673CBDBDCEBD81, 0x34BA8F5D5D695DD2, 0x5020901010401080, 0x03F507F4F4F7F4F3, +0xC08BDDCBCB0BCB16, 0xC67CD33E3EF83EED, 0x110A2D0505140528, 0xE6CE78676781671F, +0x53D597E4E4B7E473, 0xBB4E0227279C2725, 0x5882734141194132, 0x9D0BA78B8B168B2C, +0x0153F6A7A7A6A751, 0x94FAB27D7DE97DCF, 0xFB374995956E95DC, 0x9FAD56D8D847D88E, +0x30EB70FBFBCBFB8B, 0x71C1CDEEEE9FEE23, 0x91F8BB7C7CED7CC7, 0xE3CC716666856617, +0x8EA77BDDDD53DDA6, 0x4B2EAF17175C17B8, 0x468E454747014702, 0xDC211A9E9E429E84, +0xC589D4CACA0FCA1E, 0x995A582D2DB42D75, 0x79632EBFBFC6BF91, 0x1B0E3F07071C0738, +0x2347ACADAD8EAD01, 0x2FB4B05A5A755AEA, 0xB51BEF838336836C, 0xFF66B63333CC3385, +0xF2C65C636391633F, 0x0A04120202080210, 0x384993AAAA92AA39, 0xA8E2DE7171D971AF, +0xCF8DC6C8C807C80E, 0x7D32D119196419C8, 0x70923B4949394972, 0x9AAF5FD9D943D986, +0x1DF931F2F2EFF2C3, 0x48DBA8E3E3ABE34B, 0x2AB6B95B5B715BE2, 0x920DBC88881A8834, +0xC8293E9A9A529AA4, 0xBE4C0B262698262D, 0xFA64BF3232C8328D, 0x4A7D59B0B0FAB0E9, +0x6ACFF2E9E983E91B, 0x331E770F0F3C0F78, 0xA6B733D5D573D5E6, 0xBA1DF480803A8074, +0x7C6127BEBEC2BE99, 0xDE87EBCDCD13CD26, 0xE468893434D034BD, 0x75903248483D487A, +0x24E354FFFFDBFFAB, 0x8FF48D7A7AF57AF7, 0xEA3D6490907A90F4, 0x3EBE9D5F5F615FC2, +0xA0403D202080201D, 0xD5D00F6868BD6867, 0x7234CA1A1A681AD0, 0x2C41B7AEAE82AE19, +0x5E757DB4B4EAB4C9, 0x19A8CE54544D549A, 0xE53B7F93937693EC, 0xAA442F222288220D, +0xE9C86364648D6407, 0x12FF2AF1F1E3F1DB, 0xA2E6CC7373D173BF, 0x5A24821212481290, +0x5D807A40401D403A, 0x2810480808200840, 0xE89B95C3C32BC356, 0x7BC5DFECEC97EC33, +0x90AB4DDBDB4BDB96, 0x1F5FC0A1A1BEA161, 0x8307918D8D0E8D1C, 0xC97AC83D3DF43DF5, +0xF1335B97976697CC, 0x0000000000000000, 0xD483F9CFCF1BCF36, 0x87566E2B2BAC2B45, +0xB3ECE17676C57697, 0xB019E68282328264, 0xA9B128D6D67FD6FE, 0x7736C31B1B6C1BD8, +0x5B7774B5B5EEB5C1, 0x2943BEAFAF86AF11, 0xDFD41D6A6AB56A77, 0x0DA0EA50505D50BA, +0x4C8A574545094512, 0x18FB38F3F3EBF3CB, 0xF060AD3030C0309D, 0x74C3C4EFEF9BEF2B, +0xC37EDA3F3FFC3FE5, 0x1CAAC75555495592, 0x1059DBA2A2B2A279, 0x65C9E9EAEA8FEA03, +0xECCA6A656589650F, 0x686903BABAD2BAB9, 0x935E4A2F2FBC2F65, 0xE79D8EC0C027C04E, +0x81A160DEDE5FDEBE, 0x6C38FC1C1C701CE0, 0x2EE746FDFDD3FDBB, 0x649A1F4D4D294D52, +0xE0397692927292E4, 0xBCEAFA7575C9758F, 0x1E0C360606180630, 0x9809AE8A8A128A24, +0x40794BB2B2F2B2F9, 0x59D185E6E6BFE663, 0x361C7E0E0E380E70, 0x633EE71F1F7C1FF8, +0xF7C4556262956237, 0xA3B53AD4D477D4EE, 0x324D81A8A89AA829, 0xF4315296966296C4, +0x3AEF62F9F9C3F99B, 0xF697A3C5C533C566, 0xB14A102525942535, 0x20B2AB59597959F2, +0xAE15D084842A8454, 0xA7E4C57272D572B7, 0xDD72EC3939E439D5, 0x6198164C4C2D4C5A, +0x3BBC945E5E655ECA, 0x85F09F7878FD78E7, 0xD870E53838E038DD, 0x8605988C8C0A8C14, +0xB2BF17D1D163D1C6, 0x0B57E4A5A5AEA541, 0x4DD9A1E2E2AFE243, 0xF8C24E616199612F, +0x457B42B3B3F6B3F1, 0xA542342121842115, 0xD625089C9C4A9C94, 0x663CEE1E1E781EF0, +0x5286614343114322, 0xFC93B1C7C73BC776, 0x2BE54FFCFCD7FCB3, 0x1408240404100420, +0x08A2E351515951B2, 0xC72F2599995E99BC, 0xC4DA226D6DA96D4F, 0x391A650D0D340D68, +0x35E979FAFACFFA83, 0x84A369DFDF5BDFB6, 0x9BFCA97E7EE57ED7, 0xB44819242490243D, +0xD776FE3B3BEC3BC5, 0x3D4B9AABAB96AB31, 0xD181F0CECE1FCE3E, 0x5522991111441188, +0x8903838F8F068F0C, 0x6B9C044E4E254E4A, 0x517366B7B7E6B7D1, 0x60CBE0EBEB8BEB0B, +0xCC78C13C3CF03CFD, 0xBF1FFD81813E817C, 0xFE354094946A94D4, 0x0CF31CF7F7FBF7EB, +0x676F18B9B9DEB9A1, 0x5F268B13134C1398, 0x9C58512C2CB02C7D, 0xB8BB05D3D36BD3D6, +0x5CD38CE7E7BBE76B, 0xCBDC396E6EA56E57, 0xF395AAC4C437C46E, 0x0F061B03030C0318, +0x13ACDC565645568A, 0x49885E44440D441A, 0x9EFEA07F7FE17FDF, 0x374F88A9A99EA921, +0x8254672A2AA82A4D, 0x6D6B0ABBBBD6BBB1, 0xE29F87C1C123C146, 0x02A6F153535153A2, +0x8BA572DCDC57DCAE, 0x2716530B0B2C0B58, 0xD327019D9D4E9D9C, 0xC1D82B6C6CAD6C47, +0xF562A43131C43195, 0xB9E8F37474CD7487, 0x09F115F6F6FFF6E3, 0x438C4C464605460A, +0x2645A5ACAC8AAC09, 0x970FB589891E893C, 0x4428B414145014A0, 0x42DFBAE1E1A3E15B, +0x4E2CA616165816B0, 0xD274F73A3AE83ACD, 0xD0D2066969B9696F, 0x2D12410909240948, +0xADE0D77070DD70A7, 0x54716FB6B6E2B6D9, 0xB7BD1ED0D067D0CE, 0x7EC7D6EDED93ED3B, +0xDB85E2CCCC17CC2E, 0x578468424215422A, 0xC22D2C98985A98B4, 0x0E55EDA4A4AAA449, +0x8850752828A0285D, 0x31B8865C5C6D5CDA, 0x3FED6BF8F8C7F893, 0xA411C28686228644 }; + +alignas(64) const uint64_t Whirlpool::C4[256] = { +0xC07830D818186018, 0x05AF462623238C23, 0x7EF991B8C6C63FC6, 0x136FCDFBE8E887E8, +0x4CA113CB87872687, 0xA9626D11B8B8DAB8, 0x0805020901010401, 0x426E9E0D4F4F214F, +0xADEE6C9B3636D836, 0x590451FFA6A6A2A6, 0xDEBDB90CD2D26FD2, 0xFB06F70EF5F5F3F5, +0xEF80F2967979F979, 0x5FCEDE306F6FA16F, 0xFCEF3F6D91917E91, 0xAA07A4F852525552, +0x27FDC04760609D60, 0x89766535BCBCCABC, 0xACCD2B379B9B569B, 0x048C018A8E8E028E, +0x71155BD2A3A3B6A3, 0x603C186C0C0C300C, 0xFF8AF6847B7BF17B, 0xB5E16A803535D435, +0xE8693AF51D1D741D, 0x5347DDB3E0E0A7E0, 0xF6ACB321D7D77BD7, 0x5EED999CC2C22FC2, +0x6D965C432E2EB82E, 0x627A96294B4B314B, 0xA321E15DFEFEDFFE, 0x8216AED557574157, +0xA8412ABD15155415, 0x9FB6EEE87777C177, 0xA5EB6E923737DC37, 0x7B56D79EE5E5B3E5, +0x8CD923139F9F469F, 0xD317FD23F0F0E7F0, 0x6A7F94204A4A354A, 0x9E95A944DADA4FDA, +0xFA25B0A258587D58, 0x06CA8FCFC9C903C9, 0x558D527C2929A429, 0x5022145A0A0A280A, +0xE14F7F50B1B1FEB1, 0x691A5DC9A0A0BAA0, 0x7FDAD6146B6BB16B, 0x5CAB17D985852E85, +0x8173673CBDBDCEBD, 0xD234BA8F5D5D695D, 0x8050209010104010, 0xF303F507F4F4F7F4, +0x16C08BDDCBCB0BCB, 0xEDC67CD33E3EF83E, 0x28110A2D05051405, 0x1FE6CE7867678167, +0x7353D597E4E4B7E4, 0x25BB4E0227279C27, 0x3258827341411941, 0x2C9D0BA78B8B168B, +0x510153F6A7A7A6A7, 0xCF94FAB27D7DE97D, 0xDCFB374995956E95, 0x8E9FAD56D8D847D8, +0x8B30EB70FBFBCBFB, 0x2371C1CDEEEE9FEE, 0xC791F8BB7C7CED7C, 0x17E3CC7166668566, +0xA68EA77BDDDD53DD, 0xB84B2EAF17175C17, 0x02468E4547470147, 0x84DC211A9E9E429E, +0x1EC589D4CACA0FCA, 0x75995A582D2DB42D, 0x9179632EBFBFC6BF, 0x381B0E3F07071C07, +0x012347ACADAD8EAD, 0xEA2FB4B05A5A755A, 0x6CB51BEF83833683, 0x85FF66B63333CC33, +0x3FF2C65C63639163, 0x100A041202020802, 0x39384993AAAA92AA, 0xAFA8E2DE7171D971, +0x0ECF8DC6C8C807C8, 0xC87D32D119196419, 0x7270923B49493949, 0x869AAF5FD9D943D9, +0xC31DF931F2F2EFF2, 0x4B48DBA8E3E3ABE3, 0xE22AB6B95B5B715B, 0x34920DBC88881A88, +0xA4C8293E9A9A529A, 0x2DBE4C0B26269826, 0x8DFA64BF3232C832, 0xE94A7D59B0B0FAB0, +0x1B6ACFF2E9E983E9, 0x78331E770F0F3C0F, 0xE6A6B733D5D573D5, 0x74BA1DF480803A80, +0x997C6127BEBEC2BE, 0x26DE87EBCDCD13CD, 0xBDE468893434D034, 0x7A75903248483D48, +0xAB24E354FFFFDBFF, 0xF78FF48D7A7AF57A, 0xF4EA3D6490907A90, 0xC23EBE9D5F5F615F, +0x1DA0403D20208020, 0x67D5D00F6868BD68, 0xD07234CA1A1A681A, 0x192C41B7AEAE82AE, +0xC95E757DB4B4EAB4, 0x9A19A8CE54544D54, 0xECE53B7F93937693, 0x0DAA442F22228822, +0x07E9C86364648D64, 0xDB12FF2AF1F1E3F1, 0xBFA2E6CC7373D173, 0x905A248212124812, +0x3A5D807A40401D40, 0x4028104808082008, 0x56E89B95C3C32BC3, 0x337BC5DFECEC97EC, +0x9690AB4DDBDB4BDB, 0x611F5FC0A1A1BEA1, 0x1C8307918D8D0E8D, 0xF5C97AC83D3DF43D, +0xCCF1335B97976697, 0x0000000000000000, 0x36D483F9CFCF1BCF, 0x4587566E2B2BAC2B, +0x97B3ECE17676C576, 0x64B019E682823282, 0xFEA9B128D6D67FD6, 0xD87736C31B1B6C1B, +0xC15B7774B5B5EEB5, 0x112943BEAFAF86AF, 0x77DFD41D6A6AB56A, 0xBA0DA0EA50505D50, +0x124C8A5745450945, 0xCB18FB38F3F3EBF3, 0x9DF060AD3030C030, 0x2B74C3C4EFEF9BEF, +0xE5C37EDA3F3FFC3F, 0x921CAAC755554955, 0x791059DBA2A2B2A2, 0x0365C9E9EAEA8FEA, +0x0FECCA6A65658965, 0xB9686903BABAD2BA, 0x65935E4A2F2FBC2F, 0x4EE79D8EC0C027C0, +0xBE81A160DEDE5FDE, 0xE06C38FC1C1C701C, 0xBB2EE746FDFDD3FD, 0x52649A1F4D4D294D, +0xE4E0397692927292, 0x8FBCEAFA7575C975, 0x301E0C3606061806, 0x249809AE8A8A128A, +0xF940794BB2B2F2B2, 0x6359D185E6E6BFE6, 0x70361C7E0E0E380E, 0xF8633EE71F1F7C1F, +0x37F7C45562629562, 0xEEA3B53AD4D477D4, 0x29324D81A8A89AA8, 0xC4F4315296966296, +0x9B3AEF62F9F9C3F9, 0x66F697A3C5C533C5, 0x35B14A1025259425, 0xF220B2AB59597959, +0x54AE15D084842A84, 0xB7A7E4C57272D572, 0xD5DD72EC3939E439, 0x5A6198164C4C2D4C, +0xCA3BBC945E5E655E, 0xE785F09F7878FD78, 0xDDD870E53838E038, 0x148605988C8C0A8C, +0xC6B2BF17D1D163D1, 0x410B57E4A5A5AEA5, 0x434DD9A1E2E2AFE2, 0x2FF8C24E61619961, +0xF1457B42B3B3F6B3, 0x15A5423421218421, 0x94D625089C9C4A9C, 0xF0663CEE1E1E781E, +0x2252866143431143, 0x76FC93B1C7C73BC7, 0xB32BE54FFCFCD7FC, 0x2014082404041004, +0xB208A2E351515951, 0xBCC72F2599995E99, 0x4FC4DA226D6DA96D, 0x68391A650D0D340D, +0x8335E979FAFACFFA, 0xB684A369DFDF5BDF, 0xD79BFCA97E7EE57E, 0x3DB4481924249024, +0xC5D776FE3B3BEC3B, 0x313D4B9AABAB96AB, 0x3ED181F0CECE1FCE, 0x8855229911114411, +0x0C8903838F8F068F, 0x4A6B9C044E4E254E, 0xD1517366B7B7E6B7, 0x0B60CBE0EBEB8BEB, +0xFDCC78C13C3CF03C, 0x7CBF1FFD81813E81, 0xD4FE354094946A94, 0xEB0CF31CF7F7FBF7, +0xA1676F18B9B9DEB9, 0x985F268B13134C13, 0x7D9C58512C2CB02C, 0xD6B8BB05D3D36BD3, +0x6B5CD38CE7E7BBE7, 0x57CBDC396E6EA56E, 0x6EF395AAC4C437C4, 0x180F061B03030C03, +0x8A13ACDC56564556, 0x1A49885E44440D44, 0xDF9EFEA07F7FE17F, 0x21374F88A9A99EA9, +0x4D8254672A2AA82A, 0xB16D6B0ABBBBD6BB, 0x46E29F87C1C123C1, 0xA202A6F153535153, +0xAE8BA572DCDC57DC, 0x582716530B0B2C0B, 0x9CD327019D9D4E9D, 0x47C1D82B6C6CAD6C, +0x95F562A43131C431, 0x87B9E8F37474CD74, 0xE309F115F6F6FFF6, 0x0A438C4C46460546, +0x092645A5ACAC8AAC, 0x3C970FB589891E89, 0xA04428B414145014, 0x5B42DFBAE1E1A3E1, +0xB04E2CA616165816, 0xCDD274F73A3AE83A, 0x6FD0D2066969B969, 0x482D124109092409, +0xA7ADE0D77070DD70, 0xD954716FB6B6E2B6, 0xCEB7BD1ED0D067D0, 0x3B7EC7D6EDED93ED, +0x2EDB85E2CCCC17CC, 0x2A57846842421542, 0xB4C22D2C98985A98, 0x490E55EDA4A4AAA4, +0x5D8850752828A028, 0xDA31B8865C5C6D5C, 0x933FED6BF8F8C7F8, 0x44A411C286862286 }; + +alignas(64) const uint64_t Whirlpool::C5[256] = { +0x18C07830D8181860, 0x2305AF462623238C, 0xC67EF991B8C6C63F, 0xE8136FCDFBE8E887, +0x874CA113CB878726, 0xB8A9626D11B8B8DA, 0x0108050209010104, 0x4F426E9E0D4F4F21, +0x36ADEE6C9B3636D8, 0xA6590451FFA6A6A2, 0xD2DEBDB90CD2D26F, 0xF5FB06F70EF5F5F3, +0x79EF80F2967979F9, 0x6F5FCEDE306F6FA1, 0x91FCEF3F6D91917E, 0x52AA07A4F8525255, +0x6027FDC04760609D, 0xBC89766535BCBCCA, 0x9BACCD2B379B9B56, 0x8E048C018A8E8E02, +0xA371155BD2A3A3B6, 0x0C603C186C0C0C30, 0x7BFF8AF6847B7BF1, 0x35B5E16A803535D4, +0x1DE8693AF51D1D74, 0xE05347DDB3E0E0A7, 0xD7F6ACB321D7D77B, 0xC25EED999CC2C22F, +0x2E6D965C432E2EB8, 0x4B627A96294B4B31, 0xFEA321E15DFEFEDF, 0x578216AED5575741, +0x15A8412ABD151554, 0x779FB6EEE87777C1, 0x37A5EB6E923737DC, 0xE57B56D79EE5E5B3, +0x9F8CD923139F9F46, 0xF0D317FD23F0F0E7, 0x4A6A7F94204A4A35, 0xDA9E95A944DADA4F, +0x58FA25B0A258587D, 0xC906CA8FCFC9C903, 0x29558D527C2929A4, 0x0A5022145A0A0A28, +0xB1E14F7F50B1B1FE, 0xA0691A5DC9A0A0BA, 0x6B7FDAD6146B6BB1, 0x855CAB17D985852E, +0xBD8173673CBDBDCE, 0x5DD234BA8F5D5D69, 0x1080502090101040, 0xF4F303F507F4F4F7, +0xCB16C08BDDCBCB0B, 0x3EEDC67CD33E3EF8, 0x0528110A2D050514, 0x671FE6CE78676781, +0xE47353D597E4E4B7, 0x2725BB4E0227279C, 0x4132588273414119, 0x8B2C9D0BA78B8B16, +0xA7510153F6A7A7A6, 0x7DCF94FAB27D7DE9, 0x95DCFB374995956E, 0xD88E9FAD56D8D847, +0xFB8B30EB70FBFBCB, 0xEE2371C1CDEEEE9F, 0x7CC791F8BB7C7CED, 0x6617E3CC71666685, +0xDDA68EA77BDDDD53, 0x17B84B2EAF17175C, 0x4702468E45474701, 0x9E84DC211A9E9E42, +0xCA1EC589D4CACA0F, 0x2D75995A582D2DB4, 0xBF9179632EBFBFC6, 0x07381B0E3F07071C, +0xAD012347ACADAD8E, 0x5AEA2FB4B05A5A75, 0x836CB51BEF838336, 0x3385FF66B63333CC, +0x633FF2C65C636391, 0x02100A0412020208, 0xAA39384993AAAA92, 0x71AFA8E2DE7171D9, +0xC80ECF8DC6C8C807, 0x19C87D32D1191964, 0x497270923B494939, 0xD9869AAF5FD9D943, +0xF2C31DF931F2F2EF, 0xE34B48DBA8E3E3AB, 0x5BE22AB6B95B5B71, 0x8834920DBC88881A, +0x9AA4C8293E9A9A52, 0x262DBE4C0B262698, 0x328DFA64BF3232C8, 0xB0E94A7D59B0B0FA, +0xE91B6ACFF2E9E983, 0x0F78331E770F0F3C, 0xD5E6A6B733D5D573, 0x8074BA1DF480803A, +0xBE997C6127BEBEC2, 0xCD26DE87EBCDCD13, 0x34BDE468893434D0, 0x487A75903248483D, +0xFFAB24E354FFFFDB, 0x7AF78FF48D7A7AF5, 0x90F4EA3D6490907A, 0x5FC23EBE9D5F5F61, +0x201DA0403D202080, 0x6867D5D00F6868BD, 0x1AD07234CA1A1A68, 0xAE192C41B7AEAE82, +0xB4C95E757DB4B4EA, 0x549A19A8CE54544D, 0x93ECE53B7F939376, 0x220DAA442F222288, +0x6407E9C86364648D, 0xF1DB12FF2AF1F1E3, 0x73BFA2E6CC7373D1, 0x12905A2482121248, +0x403A5D807A40401D, 0x0840281048080820, 0xC356E89B95C3C32B, 0xEC337BC5DFECEC97, +0xDB9690AB4DDBDB4B, 0xA1611F5FC0A1A1BE, 0x8D1C8307918D8D0E, 0x3DF5C97AC83D3DF4, +0x97CCF1335B979766, 0x0000000000000000, 0xCF36D483F9CFCF1B, 0x2B4587566E2B2BAC, +0x7697B3ECE17676C5, 0x8264B019E6828232, 0xD6FEA9B128D6D67F, 0x1BD87736C31B1B6C, +0xB5C15B7774B5B5EE, 0xAF112943BEAFAF86, 0x6A77DFD41D6A6AB5, 0x50BA0DA0EA50505D, +0x45124C8A57454509, 0xF3CB18FB38F3F3EB, 0x309DF060AD3030C0, 0xEF2B74C3C4EFEF9B, +0x3FE5C37EDA3F3FFC, 0x55921CAAC7555549, 0xA2791059DBA2A2B2, 0xEA0365C9E9EAEA8F, +0x650FECCA6A656589, 0xBAB9686903BABAD2, 0x2F65935E4A2F2FBC, 0xC04EE79D8EC0C027, +0xDEBE81A160DEDE5F, 0x1CE06C38FC1C1C70, 0xFDBB2EE746FDFDD3, 0x4D52649A1F4D4D29, +0x92E4E03976929272, 0x758FBCEAFA7575C9, 0x06301E0C36060618, 0x8A249809AE8A8A12, +0xB2F940794BB2B2F2, 0xE66359D185E6E6BF, 0x0E70361C7E0E0E38, 0x1FF8633EE71F1F7C, +0x6237F7C455626295, 0xD4EEA3B53AD4D477, 0xA829324D81A8A89A, 0x96C4F43152969662, +0xF99B3AEF62F9F9C3, 0xC566F697A3C5C533, 0x2535B14A10252594, 0x59F220B2AB595979, +0x8454AE15D084842A, 0x72B7A7E4C57272D5, 0x39D5DD72EC3939E4, 0x4C5A6198164C4C2D, +0x5ECA3BBC945E5E65, 0x78E785F09F7878FD, 0x38DDD870E53838E0, 0x8C148605988C8C0A, +0xD1C6B2BF17D1D163, 0xA5410B57E4A5A5AE, 0xE2434DD9A1E2E2AF, 0x612FF8C24E616199, +0xB3F1457B42B3B3F6, 0x2115A54234212184, 0x9C94D625089C9C4A, 0x1EF0663CEE1E1E78, +0x4322528661434311, 0xC776FC93B1C7C73B, 0xFCB32BE54FFCFCD7, 0x0420140824040410, +0x51B208A2E3515159, 0x99BCC72F2599995E, 0x6D4FC4DA226D6DA9, 0x0D68391A650D0D34, +0xFA8335E979FAFACF, 0xDFB684A369DFDF5B, 0x7ED79BFCA97E7EE5, 0x243DB44819242490, +0x3BC5D776FE3B3BEC, 0xAB313D4B9AABAB96, 0xCE3ED181F0CECE1F, 0x1188552299111144, +0x8F0C8903838F8F06, 0x4E4A6B9C044E4E25, 0xB7D1517366B7B7E6, 0xEB0B60CBE0EBEB8B, +0x3CFDCC78C13C3CF0, 0x817CBF1FFD81813E, 0x94D4FE354094946A, 0xF7EB0CF31CF7F7FB, +0xB9A1676F18B9B9DE, 0x13985F268B13134C, 0x2C7D9C58512C2CB0, 0xD3D6B8BB05D3D36B, +0xE76B5CD38CE7E7BB, 0x6E57CBDC396E6EA5, 0xC46EF395AAC4C437, 0x03180F061B03030C, +0x568A13ACDC565645, 0x441A49885E44440D, 0x7FDF9EFEA07F7FE1, 0xA921374F88A9A99E, +0x2A4D8254672A2AA8, 0xBBB16D6B0ABBBBD6, 0xC146E29F87C1C123, 0x53A202A6F1535351, +0xDCAE8BA572DCDC57, 0x0B582716530B0B2C, 0x9D9CD327019D9D4E, 0x6C47C1D82B6C6CAD, +0x3195F562A43131C4, 0x7487B9E8F37474CD, 0xF6E309F115F6F6FF, 0x460A438C4C464605, +0xAC092645A5ACAC8A, 0x893C970FB589891E, 0x14A04428B4141450, 0xE15B42DFBAE1E1A3, +0x16B04E2CA6161658, 0x3ACDD274F73A3AE8, 0x696FD0D2066969B9, 0x09482D1241090924, +0x70A7ADE0D77070DD, 0xB6D954716FB6B6E2, 0xD0CEB7BD1ED0D067, 0xED3B7EC7D6EDED93, +0xCC2EDB85E2CCCC17, 0x422A578468424215, 0x98B4C22D2C98985A, 0xA4490E55EDA4A4AA, +0x285D8850752828A0, 0x5CDA31B8865C5C6D, 0xF8933FED6BF8F8C7, 0x8644A411C2868622 }; + +alignas(64) const uint64_t Whirlpool::C6[256] = { +0x6018C07830D81818, 0x8C2305AF46262323, 0x3FC67EF991B8C6C6, 0x87E8136FCDFBE8E8, +0x26874CA113CB8787, 0xDAB8A9626D11B8B8, 0x0401080502090101, 0x214F426E9E0D4F4F, +0xD836ADEE6C9B3636, 0xA2A6590451FFA6A6, 0x6FD2DEBDB90CD2D2, 0xF3F5FB06F70EF5F5, +0xF979EF80F2967979, 0xA16F5FCEDE306F6F, 0x7E91FCEF3F6D9191, 0x5552AA07A4F85252, +0x9D6027FDC0476060, 0xCABC89766535BCBC, 0x569BACCD2B379B9B, 0x028E048C018A8E8E, +0xB6A371155BD2A3A3, 0x300C603C186C0C0C, 0xF17BFF8AF6847B7B, 0xD435B5E16A803535, +0x741DE8693AF51D1D, 0xA7E05347DDB3E0E0, 0x7BD7F6ACB321D7D7, 0x2FC25EED999CC2C2, +0xB82E6D965C432E2E, 0x314B627A96294B4B, 0xDFFEA321E15DFEFE, 0x41578216AED55757, +0x5415A8412ABD1515, 0xC1779FB6EEE87777, 0xDC37A5EB6E923737, 0xB3E57B56D79EE5E5, +0x469F8CD923139F9F, 0xE7F0D317FD23F0F0, 0x354A6A7F94204A4A, 0x4FDA9E95A944DADA, +0x7D58FA25B0A25858, 0x03C906CA8FCFC9C9, 0xA429558D527C2929, 0x280A5022145A0A0A, +0xFEB1E14F7F50B1B1, 0xBAA0691A5DC9A0A0, 0xB16B7FDAD6146B6B, 0x2E855CAB17D98585, +0xCEBD8173673CBDBD, 0x695DD234BA8F5D5D, 0x4010805020901010, 0xF7F4F303F507F4F4, +0x0BCB16C08BDDCBCB, 0xF83EEDC67CD33E3E, 0x140528110A2D0505, 0x81671FE6CE786767, +0xB7E47353D597E4E4, 0x9C2725BB4E022727, 0x1941325882734141, 0x168B2C9D0BA78B8B, +0xA6A7510153F6A7A7, 0xE97DCF94FAB27D7D, 0x6E95DCFB37499595, 0x47D88E9FAD56D8D8, +0xCBFB8B30EB70FBFB, 0x9FEE2371C1CDEEEE, 0xED7CC791F8BB7C7C, 0x856617E3CC716666, +0x53DDA68EA77BDDDD, 0x5C17B84B2EAF1717, 0x014702468E454747, 0x429E84DC211A9E9E, +0x0FCA1EC589D4CACA, 0xB42D75995A582D2D, 0xC6BF9179632EBFBF, 0x1C07381B0E3F0707, +0x8EAD012347ACADAD, 0x755AEA2FB4B05A5A, 0x36836CB51BEF8383, 0xCC3385FF66B63333, +0x91633FF2C65C6363, 0x0802100A04120202, 0x92AA39384993AAAA, 0xD971AFA8E2DE7171, +0x07C80ECF8DC6C8C8, 0x6419C87D32D11919, 0x39497270923B4949, 0x43D9869AAF5FD9D9, +0xEFF2C31DF931F2F2, 0xABE34B48DBA8E3E3, 0x715BE22AB6B95B5B, 0x1A8834920DBC8888, +0x529AA4C8293E9A9A, 0x98262DBE4C0B2626, 0xC8328DFA64BF3232, 0xFAB0E94A7D59B0B0, +0x83E91B6ACFF2E9E9, 0x3C0F78331E770F0F, 0x73D5E6A6B733D5D5, 0x3A8074BA1DF48080, +0xC2BE997C6127BEBE, 0x13CD26DE87EBCDCD, 0xD034BDE468893434, 0x3D487A7590324848, +0xDBFFAB24E354FFFF, 0xF57AF78FF48D7A7A, 0x7A90F4EA3D649090, 0x615FC23EBE9D5F5F, +0x80201DA0403D2020, 0xBD6867D5D00F6868, 0x681AD07234CA1A1A, 0x82AE192C41B7AEAE, +0xEAB4C95E757DB4B4, 0x4D549A19A8CE5454, 0x7693ECE53B7F9393, 0x88220DAA442F2222, +0x8D6407E9C8636464, 0xE3F1DB12FF2AF1F1, 0xD173BFA2E6CC7373, 0x4812905A24821212, +0x1D403A5D807A4040, 0x2008402810480808, 0x2BC356E89B95C3C3, 0x97EC337BC5DFECEC, +0x4BDB9690AB4DDBDB, 0xBEA1611F5FC0A1A1, 0x0E8D1C8307918D8D, 0xF43DF5C97AC83D3D, +0x6697CCF1335B9797, 0x0000000000000000, 0x1BCF36D483F9CFCF, 0xAC2B4587566E2B2B, +0xC57697B3ECE17676, 0x328264B019E68282, 0x7FD6FEA9B128D6D6, 0x6C1BD87736C31B1B, +0xEEB5C15B7774B5B5, 0x86AF112943BEAFAF, 0xB56A77DFD41D6A6A, 0x5D50BA0DA0EA5050, +0x0945124C8A574545, 0xEBF3CB18FB38F3F3, 0xC0309DF060AD3030, 0x9BEF2B74C3C4EFEF, +0xFC3FE5C37EDA3F3F, 0x4955921CAAC75555, 0xB2A2791059DBA2A2, 0x8FEA0365C9E9EAEA, +0x89650FECCA6A6565, 0xD2BAB9686903BABA, 0xBC2F65935E4A2F2F, 0x27C04EE79D8EC0C0, +0x5FDEBE81A160DEDE, 0x701CE06C38FC1C1C, 0xD3FDBB2EE746FDFD, 0x294D52649A1F4D4D, +0x7292E4E039769292, 0xC9758FBCEAFA7575, 0x1806301E0C360606, 0x128A249809AE8A8A, +0xF2B2F940794BB2B2, 0xBFE66359D185E6E6, 0x380E70361C7E0E0E, 0x7C1FF8633EE71F1F, +0x956237F7C4556262, 0x77D4EEA3B53AD4D4, 0x9AA829324D81A8A8, 0x6296C4F431529696, +0xC3F99B3AEF62F9F9, 0x33C566F697A3C5C5, 0x942535B14A102525, 0x7959F220B2AB5959, +0x2A8454AE15D08484, 0xD572B7A7E4C57272, 0xE439D5DD72EC3939, 0x2D4C5A6198164C4C, +0x655ECA3BBC945E5E, 0xFD78E785F09F7878, 0xE038DDD870E53838, 0x0A8C148605988C8C, +0x63D1C6B2BF17D1D1, 0xAEA5410B57E4A5A5, 0xAFE2434DD9A1E2E2, 0x99612FF8C24E6161, +0xF6B3F1457B42B3B3, 0x842115A542342121, 0x4A9C94D625089C9C, 0x781EF0663CEE1E1E, +0x1143225286614343, 0x3BC776FC93B1C7C7, 0xD7FCB32BE54FFCFC, 0x1004201408240404, +0x5951B208A2E35151, 0x5E99BCC72F259999, 0xA96D4FC4DA226D6D, 0x340D68391A650D0D, +0xCFFA8335E979FAFA, 0x5BDFB684A369DFDF, 0xE57ED79BFCA97E7E, 0x90243DB448192424, +0xEC3BC5D776FE3B3B, 0x96AB313D4B9AABAB, 0x1FCE3ED181F0CECE, 0x4411885522991111, +0x068F0C8903838F8F, 0x254E4A6B9C044E4E, 0xE6B7D1517366B7B7, 0x8BEB0B60CBE0EBEB, +0xF03CFDCC78C13C3C, 0x3E817CBF1FFD8181, 0x6A94D4FE35409494, 0xFBF7EB0CF31CF7F7, +0xDEB9A1676F18B9B9, 0x4C13985F268B1313, 0xB02C7D9C58512C2C, 0x6BD3D6B8BB05D3D3, +0xBBE76B5CD38CE7E7, 0xA56E57CBDC396E6E, 0x37C46EF395AAC4C4, 0x0C03180F061B0303, +0x45568A13ACDC5656, 0x0D441A49885E4444, 0xE17FDF9EFEA07F7F, 0x9EA921374F88A9A9, +0xA82A4D8254672A2A, 0xD6BBB16D6B0ABBBB, 0x23C146E29F87C1C1, 0x5153A202A6F15353, +0x57DCAE8BA572DCDC, 0x2C0B582716530B0B, 0x4E9D9CD327019D9D, 0xAD6C47C1D82B6C6C, +0xC43195F562A43131, 0xCD7487B9E8F37474, 0xFFF6E309F115F6F6, 0x05460A438C4C4646, +0x8AAC092645A5ACAC, 0x1E893C970FB58989, 0x5014A04428B41414, 0xA3E15B42DFBAE1E1, +0x5816B04E2CA61616, 0xE83ACDD274F73A3A, 0xB9696FD0D2066969, 0x2409482D12410909, +0xDD70A7ADE0D77070, 0xE2B6D954716FB6B6, 0x67D0CEB7BD1ED0D0, 0x93ED3B7EC7D6EDED, +0x17CC2EDB85E2CCCC, 0x15422A5784684242, 0x5A98B4C22D2C9898, 0xAAA4490E55EDA4A4, +0xA0285D8850752828, 0x6D5CDA31B8865C5C, 0xC7F8933FED6BF8F8, 0x228644A411C28686 }; + +alignas(64) const uint64_t Whirlpool::C7[256] = { +0x186018C07830D818, 0x238C2305AF462623, 0xC63FC67EF991B8C6, 0xE887E8136FCDFBE8, +0x8726874CA113CB87, 0xB8DAB8A9626D11B8, 0x0104010805020901, 0x4F214F426E9E0D4F, +0x36D836ADEE6C9B36, 0xA6A2A6590451FFA6, 0xD26FD2DEBDB90CD2, 0xF5F3F5FB06F70EF5, +0x79F979EF80F29679, 0x6FA16F5FCEDE306F, 0x917E91FCEF3F6D91, 0x525552AA07A4F852, +0x609D6027FDC04760, 0xBCCABC89766535BC, 0x9B569BACCD2B379B, 0x8E028E048C018A8E, +0xA3B6A371155BD2A3, 0x0C300C603C186C0C, 0x7BF17BFF8AF6847B, 0x35D435B5E16A8035, +0x1D741DE8693AF51D, 0xE0A7E05347DDB3E0, 0xD77BD7F6ACB321D7, 0xC22FC25EED999CC2, +0x2EB82E6D965C432E, 0x4B314B627A96294B, 0xFEDFFEA321E15DFE, 0x5741578216AED557, +0x155415A8412ABD15, 0x77C1779FB6EEE877, 0x37DC37A5EB6E9237, 0xE5B3E57B56D79EE5, +0x9F469F8CD923139F, 0xF0E7F0D317FD23F0, 0x4A354A6A7F94204A, 0xDA4FDA9E95A944DA, +0x587D58FA25B0A258, 0xC903C906CA8FCFC9, 0x29A429558D527C29, 0x0A280A5022145A0A, +0xB1FEB1E14F7F50B1, 0xA0BAA0691A5DC9A0, 0x6BB16B7FDAD6146B, 0x852E855CAB17D985, +0xBDCEBD8173673CBD, 0x5D695DD234BA8F5D, 0x1040108050209010, 0xF4F7F4F303F507F4, +0xCB0BCB16C08BDDCB, 0x3EF83EEDC67CD33E, 0x05140528110A2D05, 0x6781671FE6CE7867, +0xE4B7E47353D597E4, 0x279C2725BB4E0227, 0x4119413258827341, 0x8B168B2C9D0BA78B, +0xA7A6A7510153F6A7, 0x7DE97DCF94FAB27D, 0x956E95DCFB374995, 0xD847D88E9FAD56D8, +0xFBCBFB8B30EB70FB, 0xEE9FEE2371C1CDEE, 0x7CED7CC791F8BB7C, 0x66856617E3CC7166, +0xDD53DDA68EA77BDD, 0x175C17B84B2EAF17, 0x47014702468E4547, 0x9E429E84DC211A9E, +0xCA0FCA1EC589D4CA, 0x2DB42D75995A582D, 0xBFC6BF9179632EBF, 0x071C07381B0E3F07, +0xAD8EAD012347ACAD, 0x5A755AEA2FB4B05A, 0x8336836CB51BEF83, 0x33CC3385FF66B633, +0x6391633FF2C65C63, 0x020802100A041202, 0xAA92AA39384993AA, 0x71D971AFA8E2DE71, +0xC807C80ECF8DC6C8, 0x196419C87D32D119, 0x4939497270923B49, 0xD943D9869AAF5FD9, +0xF2EFF2C31DF931F2, 0xE3ABE34B48DBA8E3, 0x5B715BE22AB6B95B, 0x881A8834920DBC88, +0x9A529AA4C8293E9A, 0x2698262DBE4C0B26, 0x32C8328DFA64BF32, 0xB0FAB0E94A7D59B0, +0xE983E91B6ACFF2E9, 0x0F3C0F78331E770F, 0xD573D5E6A6B733D5, 0x803A8074BA1DF480, +0xBEC2BE997C6127BE, 0xCD13CD26DE87EBCD, 0x34D034BDE4688934, 0x483D487A75903248, +0xFFDBFFAB24E354FF, 0x7AF57AF78FF48D7A, 0x907A90F4EA3D6490, 0x5F615FC23EBE9D5F, +0x2080201DA0403D20, 0x68BD6867D5D00F68, 0x1A681AD07234CA1A, 0xAE82AE192C41B7AE, +0xB4EAB4C95E757DB4, 0x544D549A19A8CE54, 0x937693ECE53B7F93, 0x2288220DAA442F22, +0x648D6407E9C86364, 0xF1E3F1DB12FF2AF1, 0x73D173BFA2E6CC73, 0x124812905A248212, +0x401D403A5D807A40, 0x0820084028104808, 0xC32BC356E89B95C3, 0xEC97EC337BC5DFEC, +0xDB4BDB9690AB4DDB, 0xA1BEA1611F5FC0A1, 0x8D0E8D1C8307918D, 0x3DF43DF5C97AC83D, +0x976697CCF1335B97, 0x0000000000000000, 0xCF1BCF36D483F9CF, 0x2BAC2B4587566E2B, +0x76C57697B3ECE176, 0x82328264B019E682, 0xD67FD6FEA9B128D6, 0x1B6C1BD87736C31B, +0xB5EEB5C15B7774B5, 0xAF86AF112943BEAF, 0x6AB56A77DFD41D6A, 0x505D50BA0DA0EA50, +0x450945124C8A5745, 0xF3EBF3CB18FB38F3, 0x30C0309DF060AD30, 0xEF9BEF2B74C3C4EF, +0x3FFC3FE5C37EDA3F, 0x554955921CAAC755, 0xA2B2A2791059DBA2, 0xEA8FEA0365C9E9EA, +0x6589650FECCA6A65, 0xBAD2BAB9686903BA, 0x2FBC2F65935E4A2F, 0xC027C04EE79D8EC0, +0xDE5FDEBE81A160DE, 0x1C701CE06C38FC1C, 0xFDD3FDBB2EE746FD, 0x4D294D52649A1F4D, +0x927292E4E0397692, 0x75C9758FBCEAFA75, 0x061806301E0C3606, 0x8A128A249809AE8A, +0xB2F2B2F940794BB2, 0xE6BFE66359D185E6, 0x0E380E70361C7E0E, 0x1F7C1FF8633EE71F, +0x62956237F7C45562, 0xD477D4EEA3B53AD4, 0xA89AA829324D81A8, 0x966296C4F4315296, +0xF9C3F99B3AEF62F9, 0xC533C566F697A3C5, 0x25942535B14A1025, 0x597959F220B2AB59, +0x842A8454AE15D084, 0x72D572B7A7E4C572, 0x39E439D5DD72EC39, 0x4C2D4C5A6198164C, +0x5E655ECA3BBC945E, 0x78FD78E785F09F78, 0x38E038DDD870E538, 0x8C0A8C148605988C, +0xD163D1C6B2BF17D1, 0xA5AEA5410B57E4A5, 0xE2AFE2434DD9A1E2, 0x6199612FF8C24E61, +0xB3F6B3F1457B42B3, 0x21842115A5423421, 0x9C4A9C94D625089C, 0x1E781EF0663CEE1E, +0x4311432252866143, 0xC73BC776FC93B1C7, 0xFCD7FCB32BE54FFC, 0x0410042014082404, +0x515951B208A2E351, 0x995E99BCC72F2599, 0x6DA96D4FC4DA226D, 0x0D340D68391A650D, +0xFACFFA8335E979FA, 0xDF5BDFB684A369DF, 0x7EE57ED79BFCA97E, 0x2490243DB4481924, +0x3BEC3BC5D776FE3B, 0xAB96AB313D4B9AAB, 0xCE1FCE3ED181F0CE, 0x1144118855229911, +0x8F068F0C8903838F, 0x4E254E4A6B9C044E, 0xB7E6B7D1517366B7, 0xEB8BEB0B60CBE0EB, +0x3CF03CFDCC78C13C, 0x813E817CBF1FFD81, 0x946A94D4FE354094, 0xF7FBF7EB0CF31CF7, +0xB9DEB9A1676F18B9, 0x134C13985F268B13, 0x2CB02C7D9C58512C, 0xD36BD3D6B8BB05D3, +0xE7BBE76B5CD38CE7, 0x6EA56E57CBDC396E, 0xC437C46EF395AAC4, 0x030C03180F061B03, +0x5645568A13ACDC56, 0x440D441A49885E44, 0x7FE17FDF9EFEA07F, 0xA99EA921374F88A9, +0x2AA82A4D8254672A, 0xBBD6BBB16D6B0ABB, 0xC123C146E29F87C1, 0x535153A202A6F153, +0xDC57DCAE8BA572DC, 0x0B2C0B582716530B, 0x9D4E9D9CD327019D, 0x6CAD6C47C1D82B6C, +0x31C43195F562A431, 0x74CD7487B9E8F374, 0xF6FFF6E309F115F6, 0x4605460A438C4C46, +0xAC8AAC092645A5AC, 0x891E893C970FB589, 0x145014A04428B414, 0xE1A3E15B42DFBAE1, +0x165816B04E2CA616, 0x3AE83ACDD274F73A, 0x69B9696FD0D20669, 0x092409482D124109, +0x70DD70A7ADE0D770, 0xB6E2B6D954716FB6, 0xD067D0CEB7BD1ED0, 0xED93ED3B7EC7D6ED, +0xCC17CC2EDB85E2CC, 0x4215422A57846842, 0x985A98B4C22D2C98, 0xA4AAA4490E55EDA4, +0x28A0285D88507528, 0x5C6D5CDA31B8865C, 0xF8C7F8933FED6BF8, 0x86228644A411C286 }; + +} diff --git a/comm/third_party/botan/src/lib/hash/whirlpool/whrlpool.h b/comm/third_party/botan/src/lib/hash/whirlpool/whrlpool.h new file mode 100644 index 0000000000..26ee7f775d --- /dev/null +++ b/comm/third_party/botan/src/lib/hash/whirlpool/whrlpool.h @@ -0,0 +1,50 @@ +/* +* Whirlpool +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_WHIRLPOOL_H_ +#define BOTAN_WHIRLPOOL_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(whrlpool.h) + +namespace Botan { + +/** +* Whirlpool +*/ +class BOTAN_PUBLIC_API(2,0) Whirlpool final : public MDx_HashFunction + { + public: + std::string name() const override { return "Whirlpool"; } + size_t output_length() const override { return 64; } + HashFunction* clone() const override { return new Whirlpool; } + std::unique_ptr copy_state() const override; + + void clear() override; + + Whirlpool() : MDx_HashFunction(64, true, true, 32), m_M(8), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + static const uint64_t C0[256]; + static const uint64_t C1[256]; + static const uint64_t C2[256]; + static const uint64_t C3[256]; + static const uint64_t C4[256]; + static const uint64_t C5[256]; + static const uint64_t C6[256]; + static const uint64_t C7[256]; + + secure_vector m_M, m_digest; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/hkdf/hkdf.cpp b/comm/third_party/botan/src/lib/kdf/hkdf/hkdf.cpp new file mode 100644 index 0000000000..0a62648fcd --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/hkdf/hkdf.cpp @@ -0,0 +1,122 @@ +/* +* HKDF +* (C) 2013,2015,2017 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +size_t HKDF::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + HKDF_Extract extract(m_prf->clone()); + HKDF_Expand expand(m_prf->clone()); + secure_vector prk(m_prf->output_length()); + + extract.kdf(prk.data(), prk.size(), secret, secret_len, salt, salt_len, nullptr, 0); + return expand.kdf(key, key_len, prk.data(), prk.size(), nullptr, 0, label, label_len); + } + +size_t HKDF_Extract::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t[], size_t) const + { + secure_vector prk; + if(salt_len == 0) + { + m_prf->set_key(std::vector(m_prf->output_length())); + } + else + { + m_prf->set_key(salt, salt_len); + } + + m_prf->update(secret, secret_len); + m_prf->final(prk); + + const size_t written = std::min(prk.size(), key_len); + copy_mem(&key[0], prk.data(), written); + // FIXME: returns truncated output + return written; + } + +size_t HKDF_Expand::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + m_prf->set_key(secret, secret_len); + + uint8_t counter = 1; + secure_vector h; + size_t offset = 0; + + while(offset != key_len && counter != 0) + { + m_prf->update(h); + m_prf->update(label, label_len); + m_prf->update(salt, salt_len); + m_prf->update(counter++); + m_prf->final(h); + + const size_t written = std::min(h.size(), key_len - offset); + copy_mem(&key[offset], h.data(), written); + offset += written; + } + + // FIXME: returns truncated output + return offset; + } + +secure_vector +hkdf_expand_label(const std::string& hash_fn, + const uint8_t secret[], size_t secret_len, + const std::string& label, + const uint8_t hash_val[], size_t hash_val_len, + size_t length) + { + BOTAN_ARG_CHECK(length <= 0xFFFF, "HKDF-Expand-Label requested output too large"); + BOTAN_ARG_CHECK(label.size() <= 0xFF, "HKDF-Expand-Label label too long"); + BOTAN_ARG_CHECK(hash_val_len <= 0xFF, "HKDF-Expand-Label hash too long"); + + const uint16_t length16 = static_cast(length); + + auto mac = MessageAuthenticationCode::create_or_throw("HMAC(" + hash_fn + ")"); + + HKDF_Expand hkdf(mac.release()); + + secure_vector output(length16); + std::vector prefix(3 + label.size() + 1); + + prefix[0] = get_byte(0, length16); + prefix[1] = get_byte(1, length16); + prefix[2] = static_cast(label.size()); + + copy_mem(prefix.data() + 3, + cast_char_ptr_to_uint8(label.data()), + label.size()); + + prefix[3 + label.size()] = static_cast(hash_val_len); + + /* + * We do something a little dirty here to avoid copying the hash_val, + * making use of the fact that Botan's KDF interface supports label+salt, + * and knowing that our HKDF hashes first param label then param salt. + */ + hkdf.kdf(output.data(), output.size(), + secret, secret_len, + hash_val, hash_val_len, + prefix.data(), prefix.size()); + + return output; + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/hkdf/hkdf.h b/comm/third_party/botan/src/lib/kdf/hkdf/hkdf.h new file mode 100644 index 0000000000..4b1ed2922c --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/hkdf/hkdf.h @@ -0,0 +1,117 @@ +/* +* HKDF +* (C) 2013,2015 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HKDF_H_ +#define BOTAN_HKDF_H_ + +#include +#include + +/* +* The definitions of HKDF, HKDF_Extract, HKDF_Expand will be made internal +* in the future. However the function hkdf_expand_label will still be defined. +*/ +//BOTAN_FUTURE_INTERNAL_HEADER(hkdf.h) + +namespace Botan { + +/** +* HKDF from RFC 5869. +*/ +class BOTAN_PUBLIC_API(2,0) HKDF final : public KDF + { + public: + /** + * @param prf MAC algorithm to use + */ + explicit HKDF(MessageAuthenticationCode* prf) : m_prf(prf) {} + + KDF* clone() const override { return new HKDF(m_prf->clone()); } + + std::string name() const override { return "HKDF(" + m_prf->name() + ")"; } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + private: + std::unique_ptr m_prf; + }; + +/** +* HKDF Extraction Step from RFC 5869. +*/ +class BOTAN_PUBLIC_API(2,0) HKDF_Extract final : public KDF + { + public: + /** + * @param prf MAC algorithm to use + */ + explicit HKDF_Extract(MessageAuthenticationCode* prf) : m_prf(prf) {} + + KDF* clone() const override { return new HKDF_Extract(m_prf->clone()); } + + std::string name() const override { return "HKDF-Extract(" + m_prf->name() + ")"; } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + private: + std::unique_ptr m_prf; + }; + +/** +* HKDF Expansion Step from RFC 5869. +*/ +class BOTAN_PUBLIC_API(2,0) HKDF_Expand final : public KDF + { + public: + /** + * @param prf MAC algorithm to use + */ + explicit HKDF_Expand(MessageAuthenticationCode* prf) : m_prf(prf) {} + + KDF* clone() const override { return new HKDF_Expand(m_prf->clone()); } + + std::string name() const override { return "HKDF-Expand(" + m_prf->name() + ")"; } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + private: + std::unique_ptr m_prf; + }; + +/** +* HKDF-Expand-Label from TLS 1.3/QUIC +* @param hash_fn the hash to use +* @param secret the secret bits +* @param secret_len the length of secret +* @param label the full label (no "TLS 1.3, " or "tls13 " prefix +* is applied) +* @param hash_val the previous hash value (used for chaining, may be empty) +* @param hash_val_len the length of hash_val +* @param length the desired output length +*/ +secure_vector +BOTAN_PUBLIC_API(2,3) hkdf_expand_label( + const std::string& hash_fn, + const uint8_t secret[], size_t secret_len, + const std::string& label, + const uint8_t hash_val[], size_t hash_val_len, + size_t length); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/hkdf/info.txt b/comm/third_party/botan/src/lib/kdf/hkdf/info.txt new file mode 100644 index 0000000000..9cbd420604 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/hkdf/info.txt @@ -0,0 +1,7 @@ + +HKDF -> 20170927 + + + +hmac + diff --git a/comm/third_party/botan/src/lib/kdf/info.txt b/comm/third_party/botan/src/lib/kdf/info.txt new file mode 100644 index 0000000000..81567300f5 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/info.txt @@ -0,0 +1,12 @@ + +KDF_BASE -> 20131128 + + + +mac +hash + + + +kdf.h + diff --git a/comm/third_party/botan/src/lib/kdf/kdf.cpp b/comm/third_party/botan/src/lib/kdf/kdf.cpp new file mode 100644 index 0000000000..7f7d352dbf --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf.cpp @@ -0,0 +1,255 @@ +/* +* KDF Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_HKDF) +#include +#endif + +#if defined(BOTAN_HAS_KDF1) +#include +#endif + +#if defined(BOTAN_HAS_KDF2) +#include +#endif + +#if defined(BOTAN_HAS_KDF1_18033) +#include +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) || defined(BOTAN_HAS_TLS_V12_PRF) +#include +#endif + +#if defined(BOTAN_HAS_X942_PRF) +#include +#endif + +#if defined(BOTAN_HAS_SP800_108) +#include +#endif + +#if defined(BOTAN_HAS_SP800_56A) +#include +#endif + +#if defined(BOTAN_HAS_SP800_56C) +#include +#endif + +namespace Botan { + +namespace { + +template +std::unique_ptr +kdf_create_mac_or_hash(const std::string& nm) + { + if(auto mac = MessageAuthenticationCode::create(nm)) + return std::unique_ptr(new KDF_Type(mac.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + nm + ")")) + return std::unique_ptr(new KDF_Type(mac.release())); + + return nullptr; + } + +} + +std::unique_ptr KDF::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_HKDF) + if(req.algo_name() == "HKDF" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } + + if(req.algo_name() == "HKDF-Extract" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } + + if(req.algo_name() == "HKDF-Expand" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } +#endif + +#if defined(BOTAN_HAS_KDF2) + if(req.algo_name() == "KDF2" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr(new KDF2(hash.release())); + } + } +#endif + +#if defined(BOTAN_HAS_KDF1_18033) + if(req.algo_name() == "KDF1-18033" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr(new KDF1_18033(hash.release())); + } + } +#endif + +#if defined(BOTAN_HAS_KDF1) + if(req.algo_name() == "KDF1" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr(new KDF1(hash.release())); + } + } +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) + if(req.algo_name() == "TLS-PRF" && req.arg_count() == 0) + { + if(provider.empty() || provider == "base") + { + auto hmac_md5 = MessageAuthenticationCode::create("HMAC(MD5)"); + auto hmac_sha1 = MessageAuthenticationCode::create("HMAC(SHA-1)"); + + if(hmac_md5 && hmac_sha1) + return std::unique_ptr(new TLS_PRF(std::move(hmac_md5), std::move(hmac_sha1))); + } + } +#endif + +#if defined(BOTAN_HAS_TLS_V12_PRF) + if(req.algo_name() == "TLS-12-PRF" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } +#endif + +#if defined(BOTAN_HAS_X942_PRF) + if(req.algo_name() == "X9.42-PRF" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr(new X942_PRF(req.arg(0))); + } + } +#endif + +#if defined(BOTAN_HAS_SP800_108) + if(req.algo_name() == "SP800-108-Counter" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } + + if(req.algo_name() == "SP800-108-Feedback" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } + + if(req.algo_name() == "SP800-108-Pipeline" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash(req.arg(0)); + } + } +#endif + +#if defined(BOTAN_HAS_SP800_56A) + if(req.algo_name() == "SP800-56A" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr(new SP800_56A_Hash(hash.release())); + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr(new SP800_56A_HMAC(mac.release())); + } +#endif + +#if defined(BOTAN_HAS_SP800_56C) + if(req.algo_name() == "SP800-56C" && req.arg_count() == 1) + { + std::unique_ptr exp(kdf_create_mac_or_hash(req.arg(0))); + if(exp) + { + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr(new SP800_56C(mac.release(), exp.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) + return std::unique_ptr(new SP800_56C(mac.release(), exp.release())); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr +KDF::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto kdf = KDF::create(algo, provider)) + { + return kdf; + } + throw Lookup_Error("KDF", algo, provider); + } + +std::vector KDF::providers(const std::string& algo_spec) + { + return probe_providers_of(algo_spec, { "base" }); + } + +KDF* get_kdf(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + if(request.algo_name() == "Raw") + return nullptr; // No KDF + + //return KDF::create_or_throw(algo_spec).release(); + auto kdf = KDF::create(algo_spec); + if(!kdf) + throw Algorithm_Not_Found(algo_spec); + return kdf.release(); + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/kdf.h b/comm/third_party/botan/src/lib/kdf/kdf.h new file mode 100644 index 0000000000..dd4cfedf6d --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf.h @@ -0,0 +1,196 @@ +/* +* Key Derivation Function interfaces +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KDF_BASE_H_ +#define BOTAN_KDF_BASE_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Key Derivation Function +*/ +class BOTAN_PUBLIC_API(2,0) KDF + { + public: + virtual ~KDF() = default; + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector providers(const std::string& algo_spec); + + /** + * @return KDF name + */ + virtual std::string name() const = 0; + + /** + * Derive a key + * @param key buffer holding the derived key, must be of length key_len + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + * @param label purpose for the derived keying material + * @param label_len size of label in bytes + * @return the derived key + */ + virtual size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const = 0; + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + * @param label purpose for the derived keying material + * @param label_len size of label in bytes + * @return the derived key + */ + secure_vector derive_key(size_t key_len, + const uint8_t secret[], + size_t secret_len, + const uint8_t salt[], + size_t salt_len, + const uint8_t label[] = nullptr, + size_t label_len = 0) const + { + secure_vector key(key_len); + key.resize(kdf(key.data(), key.size(), secret, secret_len, salt, salt_len, label, label_len)); + return key; + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param label purpose for the derived keying material + * @return the derived key + */ + secure_vector derive_key(size_t key_len, + const secure_vector& secret, + const std::string& salt = "", + const std::string& label = "") const + { + return derive_key(key_len, secret.data(), secret.size(), + cast_char_ptr_to_uint8(salt.data()), + salt.length(), + cast_char_ptr_to_uint8(label.data()), + label.length()); + + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param label purpose for the derived keying material + * @return the derived key + */ + template + secure_vector derive_key(size_t key_len, + const std::vector& secret, + const std::vector& salt, + const std::vector& label) const + { + return derive_key(key_len, + secret.data(), secret.size(), + salt.data(), salt.size(), + label.data(), label.size()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param salt_len size of salt in bytes + * @param label purpose for the derived keying material + * @return the derived key + */ + secure_vector derive_key(size_t key_len, + const secure_vector& secret, + const uint8_t salt[], + size_t salt_len, + const std::string& label = "") const + { + return derive_key(key_len, + secret.data(), secret.size(), + salt, salt_len, + cast_char_ptr_to_uint8(label.data()), + label.size()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param label purpose for the derived keying material + * @return the derived key + */ + secure_vector derive_key(size_t key_len, + const uint8_t secret[], + size_t secret_len, + const std::string& salt = "", + const std::string& label = "") const + { + return derive_key(key_len, secret, secret_len, + cast_char_ptr_to_uint8(salt.data()), + salt.length(), + cast_char_ptr_to_uint8(label.data()), + label.length()); + } + + /** + * @return new object representing the same algorithm as *this + */ + virtual KDF* clone() const = 0; + }; + +/** +* Factory method for KDF (key derivation function) +* @param algo_spec the name of the KDF to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_PUBLIC_API(2,0) KDF* get_kdf(const std::string& algo_spec); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/kdf1/info.txt b/comm/third_party/botan/src/lib/kdf/kdf1/info.txt new file mode 100644 index 0000000000..f88268f93e --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf1/info.txt @@ -0,0 +1,7 @@ + +KDF1 -> 20131128 + + + +hash + diff --git a/comm/third_party/botan/src/lib/kdf/kdf1/kdf1.cpp b/comm/third_party/botan/src/lib/kdf/kdf1/kdf1.cpp new file mode 100644 index 0000000000..3de261c55f --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf1/kdf1.cpp @@ -0,0 +1,33 @@ +/* +* KDF1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +size_t KDF1::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + m_hash->update(secret, secret_len); + m_hash->update(label, label_len); + m_hash->update(salt, salt_len); + + if(key_len < m_hash->output_length()) + { + secure_vector v = m_hash->final(); + copy_mem(key, v.data(), key_len); + return key_len; + } + + m_hash->final(key); + // FIXME: returns truncated output + return m_hash->output_length(); + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/kdf1/kdf1.h b/comm/third_party/botan/src/lib/kdf/kdf1/kdf1.h new file mode 100644 index 0000000000..388b552517 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf1/kdf1.h @@ -0,0 +1,43 @@ +/* +* KDF1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KDF1_H_ +#define BOTAN_KDF1_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(kdf1.h) + +namespace Botan { + +/** +* KDF1, from IEEE 1363 +*/ +class BOTAN_PUBLIC_API(2,0) KDF1 final : public KDF + { + public: + std::string name() const override { return "KDF1(" + m_hash->name() + ")"; } + + KDF* clone() const override { return new KDF1(m_hash->clone()); } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param h hash function to use + */ + explicit KDF1(HashFunction* h) : m_hash(h) {} + private: + std::unique_ptr m_hash; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/info.txt b/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/info.txt new file mode 100644 index 0000000000..494b8358b0 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/info.txt @@ -0,0 +1,7 @@ + +KDF1_18033 -> 20160128 + + + +hash + diff --git a/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp b/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp new file mode 100644 index 0000000000..c7699d2f25 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp @@ -0,0 +1,38 @@ +/* +* KDF1 from ISO 18033-2 +* (C) 2016 Philipp Weber +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +size_t KDF1_18033::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + uint32_t counter = 0; + secure_vector h; + + size_t offset = 0; + while(offset != key_len && counter != 0xFFFFFFFF) + { + m_hash->update(secret, secret_len); + m_hash->update_be(counter++); + m_hash->update(label, label_len); + m_hash->update(salt, salt_len); + m_hash->final(h); + + const size_t added = std::min(h.size(), key_len - offset); + copy_mem(&key[offset], h.data(), added); + offset += added; + } + + // FIXME: returns truncated output + return offset; + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h b/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h new file mode 100644 index 0000000000..5f913057e1 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h @@ -0,0 +1,43 @@ +/* +* KDF1 from ISO 18033-2 +* (C) 2016 Philipp Weber +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KDF1_18033_H_ +#define BOTAN_KDF1_18033_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(kdf1_iso18033.h) + +namespace Botan { + +/** +* KDF1, from ISO 18033-2 +*/ +class BOTAN_PUBLIC_API(2,0) KDF1_18033 final : public KDF + { + public: + std::string name() const override { return "KDF1-18033(" + m_hash->name() + ")"; } + + KDF* clone() const override { return new KDF1_18033(m_hash->clone()); } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param h hash function to use + */ + explicit KDF1_18033(HashFunction* h) : m_hash(h) {} + private: + std::unique_ptr m_hash; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/kdf2/info.txt b/comm/third_party/botan/src/lib/kdf/kdf2/info.txt new file mode 100644 index 0000000000..e222a4521f --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf2/info.txt @@ -0,0 +1,7 @@ + +KDF2 -> 20131128 + + + +hash + diff --git a/comm/third_party/botan/src/lib/kdf/kdf2/kdf2.cpp b/comm/third_party/botan/src/lib/kdf/kdf2/kdf2.cpp new file mode 100644 index 0000000000..4e3bb55832 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf2/kdf2.cpp @@ -0,0 +1,38 @@ +/* +* KDF2 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +size_t KDF2::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + uint32_t counter = 1; + secure_vector h; + + size_t offset = 0; + while(offset != key_len && counter != 0) + { + m_hash->update(secret, secret_len); + m_hash->update_be(counter++); + m_hash->update(label, label_len); + m_hash->update(salt, salt_len); + m_hash->final(h); + + const size_t added = std::min(h.size(), key_len - offset); + copy_mem(&key[offset], h.data(), added); + offset += added; + } + + // FIXME: returns truncated output + return offset; + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/kdf2/kdf2.h b/comm/third_party/botan/src/lib/kdf/kdf2/kdf2.h new file mode 100644 index 0000000000..43abbf087e --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/kdf2/kdf2.h @@ -0,0 +1,43 @@ +/* +* KDF2 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KDF2_H_ +#define BOTAN_KDF2_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(kdf2.h) + +namespace Botan { + +/** +* KDF2, from IEEE 1363 +*/ +class BOTAN_PUBLIC_API(2,0) KDF2 final : public KDF + { + public: + std::string name() const override { return "KDF2(" + m_hash->name() + ")"; } + + KDF* clone() const override { return new KDF2(m_hash->clone()); } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param h hash function to use + */ + explicit KDF2(HashFunction* h) : m_hash(h) {} + private: + std::unique_ptr m_hash; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/prf_tls/info.txt b/comm/third_party/botan/src/lib/kdf/prf_tls/info.txt new file mode 100644 index 0000000000..3d76e4b4cb --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/prf_tls/info.txt @@ -0,0 +1,8 @@ + +TLS_V10_PRF -> 20131128 +TLS_V12_PRF -> 20131128 + + + +hmac + diff --git a/comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.cpp b/comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.cpp new file mode 100644 index 0000000000..c98c7d3516 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.cpp @@ -0,0 +1,96 @@ +/* +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +TLS_PRF::TLS_PRF() : + TLS_PRF(MessageAuthenticationCode::create_or_throw("HMAC(MD5)"), + MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)")) + { + } + +namespace { + +/* +* TLS PRF P_hash function +*/ +void P_hash(uint8_t out[], size_t out_len, + MessageAuthenticationCode& mac, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len) + { + try + { + mac.set_key(secret, secret_len); + } + catch(Invalid_Key_Length&) + { + throw Internal_Error("The premaster secret of " + + std::to_string(secret_len) + + " bytes is too long for the PRF"); + } + + secure_vector A(salt, salt + salt_len); + secure_vector h; + + size_t offset = 0; + + while(offset != out_len) + { + A = mac.process(A); + + mac.update(A); + mac.update(salt, salt_len); + mac.final(h); + + const size_t writing = std::min(h.size(), out_len - offset); + xor_buf(&out[offset], h.data(), writing); + offset += writing; + } + } + +} + +size_t TLS_PRF::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + const size_t S1_len = (secret_len + 1) / 2, + S2_len = (secret_len + 1) / 2; + const uint8_t* S1 = secret; + const uint8_t* S2 = secret + (secret_len - S2_len); + secure_vector msg; + + msg.reserve(label_len + salt_len); + msg += std::make_pair(label, label_len); + msg += std::make_pair(salt, salt_len); + + P_hash(key, key_len, *m_hmac_md5, S1, S1_len, msg.data(), msg.size()); + P_hash(key, key_len, *m_hmac_sha1, S2, S2_len, msg.data(), msg.size()); + return key_len; + } + +size_t TLS_12_PRF::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + secure_vector msg; + + msg.reserve(label_len + salt_len); + msg += std::make_pair(label, label_len); + msg += std::make_pair(salt, salt_len); + + P_hash(key, key_len, *m_mac, secret, secret_len, msg.data(), msg.size()); + return key_len; + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.h b/comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.h new file mode 100644 index 0000000000..603086a7e9 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/prf_tls/prf_tls.h @@ -0,0 +1,70 @@ +/* +* TLS v1.0 and v1.2 PRFs +* (C) 2004-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_PRF_H_ +#define BOTAN_TLS_PRF_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(prf_tls.h) + +namespace Botan { + +/** +* PRF used in TLS 1.0/1.1 +*/ +class BOTAN_PUBLIC_API(2,0) TLS_PRF final : public KDF + { + public: + std::string name() const override { return "TLS-PRF"; } + + KDF* clone() const override { return new TLS_PRF; } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + TLS_PRF(std::unique_ptr hmac_md5, + std::unique_ptr hmac_sha1) : + m_hmac_md5(std::move(hmac_md5)), + m_hmac_sha1(std::move(hmac_sha1)) + {} + + TLS_PRF(); + private: + std::unique_ptr m_hmac_md5; + std::unique_ptr m_hmac_sha1; + }; + +/** +* PRF used in TLS 1.2 +*/ +class BOTAN_PUBLIC_API(2,0) TLS_12_PRF final : public KDF + { + public: + std::string name() const override { return "TLS-12-PRF(" + m_mac->name() + ")"; } + + KDF* clone() const override { return new TLS_12_PRF(m_mac->clone()); } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param mac MAC algorithm to use + */ + explicit TLS_12_PRF(MessageAuthenticationCode* mac) : m_mac(mac) {} + private: + std::unique_ptr m_mac; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/prf_x942/info.txt b/comm/third_party/botan/src/lib/kdf/prf_x942/info.txt new file mode 100644 index 0000000000..8226433654 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/prf_x942/info.txt @@ -0,0 +1,8 @@ + +X942_PRF -> 20131128 + + + +asn1 +sha1 + diff --git a/comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.cpp b/comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.cpp new file mode 100644 index 0000000000..4a4a3a7f09 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.cpp @@ -0,0 +1,92 @@ +/* +* X9.42 PRF +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Encode an integer as an OCTET STRING +*/ +std::vector encode_x942_int(uint32_t n) + { + uint8_t n_buf[4] = { 0 }; + store_be(n, n_buf); + + std::vector output; + DER_Encoder(output).encode(n_buf, 4, OCTET_STRING); + return output; + } + +} + +size_t X942_PRF::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + std::unique_ptr hash(HashFunction::create("SHA-160")); + + secure_vector h; + secure_vector in; + size_t offset = 0; + uint32_t counter = 1; + + in.reserve(salt_len + label_len); + in += std::make_pair(label,label_len); + in += std::make_pair(salt,salt_len); + + while(offset != key_len && counter) + { + hash->update(secret, secret_len); + + hash->update( + DER_Encoder().start_cons(SEQUENCE) + + .start_cons(SEQUENCE) + .encode(m_key_wrap_oid) + .raw_bytes(encode_x942_int(counter)) + .end_cons() + + .encode_if(salt_len != 0, + DER_Encoder() + .start_explicit(0) + .encode(in, OCTET_STRING) + .end_explicit() + ) + + .start_explicit(2) + .raw_bytes(encode_x942_int(static_cast(8 * key_len))) + .end_explicit() + + .end_cons().get_contents() + ); + + hash->final(h); + const size_t copied = std::min(h.size(), key_len - offset); + copy_mem(&key[offset], h.data(), copied); + offset += copied; + + ++counter; + } + + // FIXME: returns truncated output + return offset; + } + +std::string X942_PRF::name() const + { + return "X9.42-PRF(" + m_key_wrap_oid.to_formatted_string() + ")"; + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.h b/comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.h new file mode 100644 index 0000000000..98af7e069b --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/prf_x942/prf_x942.h @@ -0,0 +1,42 @@ +/* +* X9.42 PRF +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ANSI_X942_PRF_H_ +#define BOTAN_ANSI_X942_PRF_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(prf_x942.h) + +namespace Botan { + +/** +* PRF from ANSI X9.42 +*/ +class BOTAN_PUBLIC_API(2,0) X942_PRF final : public KDF + { + public: + std::string name() const override; + + KDF* clone() const override { return new X942_PRF(m_key_wrap_oid); } + + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + explicit X942_PRF(const std::string& oid) : m_key_wrap_oid(OID::from_string(oid)) {} + + explicit X942_PRF(const OID& oid) : m_key_wrap_oid(oid) {} + private: + OID m_key_wrap_oid; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/sp800_108/info.txt b/comm/third_party/botan/src/lib/kdf/sp800_108/info.txt new file mode 100644 index 0000000000..864a7fb9c3 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_108/info.txt @@ -0,0 +1,8 @@ + +SP800_108 -> 20160128 + + + +mac +hmac + diff --git a/comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.cpp b/comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.cpp new file mode 100644 index 0000000000..909e8d47d5 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.cpp @@ -0,0 +1,170 @@ +/* +* KDFs defined in NIST SP 800-108 +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +size_t SP800_108_Counter::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + const std::size_t prf_len = m_prf->output_length(); + + const uint64_t blocks_required = (key_len + prf_len - 1) / prf_len; + + if(blocks_required > 0xFFFFFFFF) + throw Invalid_Argument("SP800_108_Counter output size too large"); + + const uint8_t delim = 0; + const uint32_t length = static_cast(key_len * 8); + + uint8_t *p = key; + uint32_t counter = 1; + uint8_t be_len[4] = { 0 }; + secure_vector tmp; + + store_be(length, be_len); + m_prf->set_key(secret, secret_len); + + while(p < key + key_len) + { + const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); + uint8_t be_cnt[4] = { 0 }; + + store_be(counter, be_cnt); + + m_prf->update(be_cnt,4); + m_prf->update(label,label_len); + m_prf->update(delim); + m_prf->update(salt,salt_len); + m_prf->update(be_len,4); + m_prf->final(tmp); + + copy_mem(p, tmp.data(), to_copy); + p += to_copy; + + ++counter; + BOTAN_ASSERT(counter != 0, "No counter overflow"); + } + + return key_len; + } + +size_t SP800_108_Feedback::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + const uint32_t length = static_cast(key_len * 8); + const std::size_t prf_len = m_prf->output_length(); + const std::size_t iv_len = (salt_len >= prf_len ? prf_len : 0); + const uint8_t delim = 0; + + const uint64_t blocks_required = (key_len + prf_len - 1) / prf_len; + + if(blocks_required > 0xFFFFFFFF) + throw Invalid_Argument("SP800_108_Feedback output size too large"); + + uint8_t *p = key; + uint32_t counter = 1; + uint8_t be_len[4] = { 0 }; + secure_vector< uint8_t > prev(salt, salt + iv_len); + secure_vector< uint8_t > ctx(salt + iv_len, salt + salt_len); + + store_be(length, be_len); + m_prf->set_key(secret, secret_len); + + while(p < key + key_len) + { + const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); + uint8_t be_cnt[4] = { 0 }; + + store_be(counter, be_cnt); + + m_prf->update(prev); + m_prf->update(be_cnt,4); + m_prf->update(label,label_len); + m_prf->update(delim); + m_prf->update(ctx); + m_prf->update(be_len,4); + m_prf->final(prev); + + copy_mem(p, prev.data(), to_copy); + p += to_copy; + + ++counter; + + BOTAN_ASSERT(counter != 0, "No overflow"); + } + + return key_len; + } + +size_t SP800_108_Pipeline::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + const uint32_t length = static_cast(key_len * 8); + const std::size_t prf_len = m_prf->output_length(); + const uint8_t delim = 0; + + const uint64_t blocks_required = (key_len + prf_len - 1) / prf_len; + + if(blocks_required > 0xFFFFFFFF) + throw Invalid_Argument("SP800_108_Feedback output size too large"); + + uint8_t *p = key; + uint32_t counter = 1; + uint8_t be_len[4] = { 0 }; + secure_vector ai, ki; + + store_be(length, be_len); + m_prf->set_key(secret,secret_len); + + // A(0) + std::copy(label,label + label_len,std::back_inserter(ai)); + ai.emplace_back(delim); + std::copy(salt,salt + salt_len,std::back_inserter(ai)); + std::copy(be_len,be_len + 4,std::back_inserter(ai)); + + while(p < key + key_len) + { + // A(i) + m_prf->update(ai); + m_prf->final(ai); + + // K(i) + const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); + uint8_t be_cnt[4] = { 0 }; + + store_be(counter, be_cnt); + + m_prf->update(ai); + m_prf->update(be_cnt,4); + m_prf->update(label, label_len); + m_prf->update(delim); + m_prf->update(salt, salt_len); + m_prf->update(be_len,4); + m_prf->final(ki); + + copy_mem(p, ki.data(), to_copy); + p += to_copy; + + ++counter; + + BOTAN_ASSERT(counter != 0, "No overflow"); + } + + return key_len; + } +} diff --git a/comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.h b/comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.h new file mode 100644 index 0000000000..46f734e8ea --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_108/sp800_108.h @@ -0,0 +1,135 @@ +/* +* KDFs defined in NIST SP 800-108 +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SP800_108_H_ +#define BOTAN_SP800_108_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sp800_108.h) + +namespace Botan { + +/** + * NIST SP 800-108 KDF in Counter Mode (5.1) + */ +class BOTAN_PUBLIC_API(2,0) SP800_108_Counter final : public KDF + { + public: + std::string name() const override { return "SP800-108-Counter(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_108_Counter(m_prf->clone()); } + + /** + * Derive a key using the SP800-108 KDF in Counter mode. + * + * The implementation hard codes the length of [L]_2 + * and [i]_2 (the value r) to 32 bits. + * + * @param key resulting keying material + * @param key_len the desired output length in bytes + * @param secret K_I + * @param secret_len size of K_I in bytes + * @param salt Context + * @param salt_len size of Context in bytes + * @param label Label + * @param label_len size of Label in bytes + * + * @throws Invalid_Argument key_len > 2^32 + */ + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param mac MAC algorithm to use + */ + explicit SP800_108_Counter(MessageAuthenticationCode* mac) : m_prf(mac) {} + private: + std::unique_ptr m_prf; + }; + +/** + * NIST SP 800-108 KDF in Feedback Mode (5.2) + */ +class BOTAN_PUBLIC_API(2,0) SP800_108_Feedback final : public KDF + { + public: + std::string name() const override { return "SP800-108-Feedback(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_108_Feedback(m_prf->clone()); } + + /** + * Derive a key using the SP800-108 KDF in Feedback mode. + * + * The implementation uses the optional counter i and hard + * codes the length of [L]_2 and [i]_2 (the value r) to 32 bits. + * + * @param key resulting keying material + * @param key_len the desired output length in bytes + * @param secret K_I + * @param secret_len size of K_I in bytes + * @param salt IV || Context + * @param salt_len size of Context plus IV in bytes + * @param label Label + * @param label_len size of Label in bytes + * + * @throws Invalid_Argument key_len > 2^32 + */ + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + explicit SP800_108_Feedback(MessageAuthenticationCode* mac) : m_prf(mac) {} + private: + std::unique_ptr m_prf; + }; + +/** + * NIST SP 800-108 KDF in Double Pipeline Mode (5.3) + */ +class BOTAN_PUBLIC_API(2,0) SP800_108_Pipeline final : public KDF + { + public: + std::string name() const override { return "SP800-108-Pipeline(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_108_Pipeline(m_prf->clone()); } + + /** + * Derive a key using the SP800-108 KDF in Double Pipeline mode. + * + * The implementation uses the optional counter i and hard + * codes the length of [L]_2 and [i]_2 (the value r) to 32 bits. + * + * @param key resulting keying material + * @param key_len the desired output length in bytes + * @param secret K_I + * @param secret_len size of K_I in bytes + * @param salt Context + * @param salt_len size of Context in bytes + * @param label Label + * @param label_len size of Label in bytes + * + * @throws Invalid_Argument key_len > 2^32 + */ + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + explicit SP800_108_Pipeline(MessageAuthenticationCode* mac) : m_prf(mac) {} + + private: + std::unique_ptr m_prf; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/sp800_56a/info.txt b/comm/third_party/botan/src/lib/kdf/sp800_56a/info.txt new file mode 100644 index 0000000000..d8ef51673b --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_56a/info.txt @@ -0,0 +1,7 @@ + +SP800_56A -> 20170501 + + + +hmac + diff --git a/comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.cpp b/comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.cpp new file mode 100644 index 0000000000..8e9bcf8560 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.cpp @@ -0,0 +1,98 @@ +/* +* KDF defined in NIST SP 800-56a (Approved Alternative 1) +* +* (C) 2017 Ribose Inc. Written by Krzysztof Kwiatkowski. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +template +size_t SP800_56A_kdf( + AuxiliaryFunction_t& auxfunc, + uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t label[], size_t label_len) + { + const uint64_t kRepsUpperBound = (1ULL << 32); + + const size_t digest_len = auxfunc.output_length(); + + const size_t reps = key_len / digest_len + ((key_len % digest_len) ? 1 : 0); + + if (reps >= kRepsUpperBound) + { + // See SP-800-56A, point 5.8.1 + throw Invalid_Argument("SP800-56A KDF requested output too large"); + } + + uint32_t counter = 1; + secure_vector result; + for(size_t i = 0; i < reps; i++) + { + auxfunc.update_be(counter++); + auxfunc.update(secret, secret_len); + auxfunc.update(label, label_len); + auxfunc.final(result); + + const size_t offset = digest_len * i; + const size_t len = std::min(result.size(), key_len - offset); + copy_mem(&key[offset], result.data(), len); + } + + return key_len; + } + +} + +size_t SP800_56A_Hash::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + /* + * TODO: should we reject a non-empty salt with an exception? + * Ignoring the salt seems quite dangerous to applications which + * don't expect it. + */ + BOTAN_UNUSED(salt, salt_len); + + return SP800_56A_kdf(*m_hash, key, key_len, secret, secret_len, label, label_len); + } + +SP800_56A_HMAC::SP800_56A_HMAC(MessageAuthenticationCode* mac) : m_mac(mac) + { + // TODO: we need a MessageAuthenticationCode::is_hmac + const SCAN_Name req(m_mac->name()); + if(req.algo_name() != "HMAC") + { + throw Algorithm_Not_Found("Only HMAC can be used with KDF SP800-56A"); + } + } + +size_t SP800_56A_HMAC::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + /* + * SP 800-56A specifies if the salt is empty then a block of zeros + * equal to the hash's underlying block size are used. However this + * is equivalent to setting a zero-length key, so the same call + * works for either case. + */ + m_mac->set_key(salt, salt_len); + + return SP800_56A_kdf(*m_mac, key, key_len, secret, secret_len, label, label_len); + } + + + +} diff --git a/comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.h b/comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.h new file mode 100644 index 0000000000..e83f117e2e --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_56a/sp800_56a.h @@ -0,0 +1,103 @@ +/* +* KDF defined in NIST SP 800-56a revision 2 (Single-step key-derivation function) +* +* (C) 2017 Ribose Inc. Written by Krzysztof Kwiatkowski. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SP800_56A_H_ +#define BOTAN_SP800_56A_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sp800_56a.h) + +namespace Botan { + +/** + * NIST SP 800-56A KDF using hash function + * @warning This KDF ignores the provided salt value + */ +class BOTAN_PUBLIC_API(2,2) SP800_56A_Hash final : public KDF + { + public: + std::string name() const override { return "SP800-56A(" + m_hash->name() + ")"; } + + KDF* clone() const override { return new SP800_56A_Hash(m_hash->clone()); } + + /** + * Derive a key using the SP800-56A KDF. + * + * The implementation hard codes the context value for the + * expansion step to the empty string. + * + * @param key derived keying material K_M + * @param key_len the desired output length in bytes + * @param secret shared secret Z + * @param secret_len size of Z in bytes + * @param salt ignored + * @param salt_len ignored + * @param label label for the expansion step + * @param label_len size of label in bytes + * + * @throws Invalid_Argument key_len > 2^32 + */ + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param hash the hash function to use as the auxiliary function + */ + explicit SP800_56A_Hash(HashFunction* hash) : m_hash(hash) {} + private: + std::unique_ptr m_hash; + }; + +/** + * NIST SP 800-56A KDF using HMAC + */ +class BOTAN_PUBLIC_API(2,2) SP800_56A_HMAC final : public KDF + { + public: + std::string name() const override { return "SP800-56A(" + m_mac->name() + ")"; } + + KDF* clone() const override { return new SP800_56A_HMAC(m_mac->clone()); } + + /** + * Derive a key using the SP800-56A KDF. + * + * The implementation hard codes the context value for the + * expansion step to the empty string. + * + * @param key derived keying material K_M + * @param key_len the desired output length in bytes + * @param secret shared secret Z + * @param secret_len size of Z in bytes + * @param salt ignored + * @param salt_len ignored + * @param label label for the expansion step + * @param label_len size of label in bytes + * + * @throws Invalid_Argument key_len > 2^32 or MAC is not a HMAC + */ + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param mac the HMAC to use as the auxiliary function + */ + explicit SP800_56A_HMAC(MessageAuthenticationCode* mac); + private: + std::unique_ptr m_mac; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/kdf/sp800_56c/info.txt b/comm/third_party/botan/src/lib/kdf/sp800_56c/info.txt new file mode 100644 index 0000000000..e598e88454 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_56c/info.txt @@ -0,0 +1,8 @@ + +SP800_56C -> 20160211 + + + +sp800_108 +hmac + diff --git a/comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.cpp b/comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.cpp new file mode 100644 index 0000000000..c0a1a1f689 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.cpp @@ -0,0 +1,28 @@ +/* +* KDF defined in NIST SP 800-56c +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +size_t SP800_56C::kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const + { + // Randomness Extraction + secure_vector k_dk; + + m_prf->set_key(salt, salt_len); + m_prf->update(secret, secret_len); + m_prf->final(k_dk); + + // Key Expansion + return m_exp->kdf(key, key_len, k_dk.data(), k_dk.size(), nullptr, 0, label, label_len); + } + +} diff --git a/comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.h b/comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.h new file mode 100644 index 0000000000..bdbdfcd9e1 --- /dev/null +++ b/comm/third_party/botan/src/lib/kdf/sp800_56c/sp800_56c.h @@ -0,0 +1,61 @@ +/* +* KDF defined in NIST SP 800-56c +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SP800_56C_H_ +#define BOTAN_SP800_56C_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(sp800_56c.h) + +namespace Botan { + +/** + * NIST SP 800-56C KDF + */ +class BOTAN_PUBLIC_API(2,0) SP800_56C final : public KDF + { + public: + std::string name() const override { return "SP800-56C(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_56C(m_prf->clone(), m_exp->clone()); } + + /** + * Derive a key using the SP800-56C KDF. + * + * The implementation hard codes the context value for the + * expansion step to the empty string. + * + * @param key derived keying material K_M + * @param key_len the desired output length in bytes + * @param secret shared secret Z + * @param secret_len size of Z in bytes + * @param salt salt s of the extraction step + * @param salt_len size of s in bytes + * @param label label for the expansion step + * @param label_len size of label in bytes + * + * @throws Invalid_Argument key_len > 2^32 + */ + size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const override; + + /** + * @param mac MAC algorithm used for randomness extraction + * @param exp KDF used for key expansion + */ + SP800_56C(MessageAuthenticationCode* mac, KDF* exp) : m_prf(mac), m_exp(exp) {} + private: + std::unique_ptr m_prf; + std::unique_ptr m_exp; + }; +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp new file mode 100644 index 0000000000..ba403b564a --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.cpp @@ -0,0 +1,99 @@ +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +* Update an CBC-MAC Calculation +*/ +void CBC_MAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_state.empty() == false); + + size_t xored = std::min(output_length() - m_position, length); + xor_buf(&m_state[m_position], input, xored); + m_position += xored; + + if(m_position < output_length()) + return; + + m_cipher->encrypt(m_state); + input += xored; + length -= xored; + while(length >= output_length()) + { + xor_buf(m_state, input, output_length()); + m_cipher->encrypt(m_state); + input += output_length(); + length -= output_length(); + } + + xor_buf(m_state, input, length); + m_position = length; + } + +/* +* Finalize an CBC-MAC Calculation +*/ +void CBC_MAC::final_result(uint8_t mac[]) + { + verify_key_set(m_state.empty() == false); + + if(m_position) + m_cipher->encrypt(m_state); + + copy_mem(mac, m_state.data(), m_state.size()); + zeroise(m_state); + m_position = 0; + } + +/* +* CBC-MAC Key Schedule +*/ +void CBC_MAC::key_schedule(const uint8_t key[], size_t length) + { + m_state.resize(m_cipher->block_size()); + m_cipher->set_key(key, length); + } + +/* +* Clear memory of sensitive data +*/ +void CBC_MAC::clear() + { + m_cipher->clear(); + zap(m_state); + m_position = 0; + } + +/* +* Return the name of this type +*/ +std::string CBC_MAC::name() const + { + return "CBC-MAC(" + m_cipher->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CBC_MAC::clone() const + { + return new CBC_MAC(m_cipher->clone()); + } + +/* +* CBC-MAC Constructor +*/ +CBC_MAC::CBC_MAC(BlockCipher* cipher) : + m_cipher(cipher) + { + } + +} diff --git a/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h new file mode 100644 index 0000000000..ed4eb2bd18 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cbc_mac/cbc_mac.h @@ -0,0 +1,50 @@ +/* +* CBC-MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CBC_MAC_H_ +#define BOTAN_CBC_MAC_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cbc_mac.h) + +namespace Botan { + +/** +* CBC-MAC +*/ +class BOTAN_PUBLIC_API(2,0) CBC_MAC final : public MessageAuthenticationCode + { + public: + std::string name() const override; + MessageAuthenticationCode* clone() const override; + size_t output_length() const override { return m_cipher->block_size(); } + void clear() override; + + Key_Length_Specification key_spec() const override + { + return m_cipher->key_spec(); + } + + /** + * @param cipher the block cipher to use + */ + explicit CBC_MAC(BlockCipher* cipher); + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr m_cipher; + secure_vector m_state; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/cbc_mac/info.txt b/comm/third_party/botan/src/lib/mac/cbc_mac/info.txt new file mode 100644 index 0000000000..994a63872b --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cbc_mac/info.txt @@ -0,0 +1,7 @@ + +CBC_MAC -> 20131128 + + + +block + diff --git a/comm/third_party/botan/src/lib/mac/cmac/cmac.cpp b/comm/third_party/botan/src/lib/mac/cmac/cmac.cpp new file mode 100644 index 0000000000..38752471dd --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cmac/cmac.cpp @@ -0,0 +1,139 @@ +/* +* CMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Perform CMAC's multiplication in GF(2^n) +*/ +secure_vector CMAC::poly_double(const secure_vector& in) + { + secure_vector out(in.size()); + poly_double_n(out.data(), in.data(), out.size()); + return out; + } + +/* +* Update an CMAC Calculation +*/ +void CMAC::add_data(const uint8_t input[], size_t length) + { + const size_t bs = output_length(); + + buffer_insert(m_buffer, m_position, input, length); + if(m_position + length > bs) + { + xor_buf(m_state, m_buffer, bs); + m_cipher->encrypt(m_state); + input += (bs - m_position); + length -= (bs - m_position); + while(length > bs) + { + xor_buf(m_state, input, bs); + m_cipher->encrypt(m_state); + input += bs; + length -= bs; + } + copy_mem(m_buffer.data(), input, length); + m_position = 0; + } + m_position += length; + } + +/* +* Finalize an CMAC Calculation +*/ +void CMAC::final_result(uint8_t mac[]) + { + xor_buf(m_state, m_buffer, m_position); + + if(m_position == output_length()) + { + xor_buf(m_state, m_B, output_length()); + } + else + { + m_state[m_position] ^= 0x80; + xor_buf(m_state, m_P, output_length()); + } + + m_cipher->encrypt(m_state); + + copy_mem(mac, m_state.data(), output_length()); + + zeroise(m_state); + zeroise(m_buffer); + m_position = 0; + } + +/* +* CMAC Key Schedule +*/ +void CMAC::key_schedule(const uint8_t key[], size_t length) + { + clear(); + m_cipher->set_key(key, length); + m_cipher->encrypt(m_B); + poly_double_n(m_B.data(), m_B.size()); + poly_double_n(m_P.data(), m_B.data(), m_P.size()); + } + +/* +* Clear memory of sensitive data +*/ +void CMAC::clear() + { + m_cipher->clear(); + zeroise(m_state); + zeroise(m_buffer); + zeroise(m_B); + zeroise(m_P); + m_position = 0; + } + +/* +* Return the name of this type +*/ +std::string CMAC::name() const + { + return "CMAC(" + m_cipher->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* CMAC::clone() const + { + return new CMAC(m_cipher->clone()); + } + +/* +* CMAC Constructor +*/ +CMAC::CMAC(BlockCipher* cipher) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()) + { + if(poly_double_supported_size(m_block_size) == false) + { + throw Invalid_Argument("CMAC cannot use the " + + std::to_string(m_block_size * 8) + + " bit cipher " + m_cipher->name()); + } + + m_state.resize(output_length()); + m_buffer.resize(output_length()); + m_B.resize(output_length()); + m_P.resize(output_length()); + m_position = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/mac/cmac/cmac.h b/comm/third_party/botan/src/lib/mac/cmac/cmac.h new file mode 100644 index 0000000000..f73167590d --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cmac/cmac.h @@ -0,0 +1,67 @@ +/* +* CMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CMAC_H_ +#define BOTAN_CMAC_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cmac.h) + +namespace Botan { + +/** +* CMAC, also known as OMAC1 +*/ +class BOTAN_PUBLIC_API(2,0) CMAC final : public MessageAuthenticationCode + { + public: + std::string name() const override; + size_t output_length() const override { return m_block_size; } + MessageAuthenticationCode* clone() const override; + + void clear() override; + + Key_Length_Specification key_spec() const override + { + return m_cipher->key_spec(); + } + + /** + * CMAC's polynomial doubling operation + * + * This function was only exposed for use elsewhere in the library, but it is not + * longer used. This function will be removed in a future release. + * + * @param in the input + */ + static secure_vector + BOTAN_DEPRECATED("This was only for internal use and is no longer used") + poly_double(const secure_vector& in); + + /** + * @param cipher the block cipher to use + */ + explicit CMAC(BlockCipher* cipher); + + CMAC(const CMAC&) = delete; + CMAC& operator=(const CMAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr m_cipher; + secure_vector m_buffer, m_state, m_B, m_P; + const size_t m_block_size; + size_t m_position; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/cmac/info.txt b/comm/third_party/botan/src/lib/mac/cmac/info.txt new file mode 100644 index 0000000000..d78b3851ee --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/cmac/info.txt @@ -0,0 +1,8 @@ + +CMAC -> 20131128 + + + +block +poly_dbl + diff --git a/comm/third_party/botan/src/lib/mac/gmac/gmac.cpp b/comm/third_party/botan/src/lib/mac/gmac/gmac.cpp new file mode 100644 index 0000000000..6b162857f3 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/gmac/gmac.cpp @@ -0,0 +1,134 @@ +/* + * GMAC + * (C) 2016 Matthias Gierlings, René Korthaus + * (C) 2017 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include +#include +#include +#include + +namespace Botan { + +GMAC::GMAC(BlockCipher* cipher) : + m_cipher(cipher), + m_ghash(new GHASH), + m_aad_buf(GCM_BS), + m_aad_buf_pos(0), + m_initialized(false) + { + } + +void GMAC::clear() + { + m_cipher->clear(); + m_ghash->clear(); + zeroise(m_aad_buf); + m_aad_buf_pos = 0; + m_initialized = false; + } + +GMAC::~GMAC() { /* for unique_ptr */ } + +Key_Length_Specification GMAC::key_spec() const + { + return m_cipher->key_spec(); + } + +std::string GMAC::name() const + { + return "GMAC(" + m_cipher->name() + ")"; + } + +size_t GMAC::output_length() const + { + return GCM_BS; + } + +void GMAC::add_data(const uint8_t input[], size_t size) + { + if(m_aad_buf_pos > 0) + { + const size_t taking = std::min(GCM_BS - m_aad_buf_pos, size); + copy_mem(&m_aad_buf[m_aad_buf_pos], input, taking); + m_aad_buf_pos += taking; + input += taking; + size -= taking; + + if(m_aad_buf_pos == GCM_BS) + { + m_ghash->update_associated_data(m_aad_buf.data(), GCM_BS); + m_aad_buf_pos = 0; + } + } + + const size_t left_over = size % GCM_BS; + const size_t full_blocks = size - left_over; + m_ghash->update_associated_data(input, full_blocks); + input += full_blocks; + + if(left_over > 0) + { + copy_mem(&m_aad_buf[m_aad_buf_pos], input, left_over); + m_aad_buf_pos += left_over; + } + } + +void GMAC::key_schedule(const uint8_t key[], size_t size) + { + clear(); + m_cipher->set_key(key, size); + + secure_vector H(GCM_BS); + m_cipher->encrypt(H); + m_ghash->set_key(H); + } + +void GMAC::start_msg(const uint8_t nonce[], size_t nonce_len) + { + secure_vector y0(GCM_BS); + + if(nonce_len == 12) + { + copy_mem(y0.data(), nonce, nonce_len); + y0[GCM_BS - 1] = 1; + } + else + { + m_ghash->ghash_update(y0, nonce, nonce_len); + m_ghash->add_final_block(y0, 0, nonce_len); + } + + secure_vector m_enc_y0(GCM_BS); + m_cipher->encrypt(y0.data(), m_enc_y0.data()); + m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); + m_initialized = true; + } + +void GMAC::final_result(uint8_t mac[]) + { + // This ensures the GMAC computation has been initialized with a fresh + // nonce. The aim of this check is to prevent developers from re-using + // nonces (and potential nonce-reuse attacks). + if(m_initialized == false) + throw Invalid_State("GMAC was not used with a fresh nonce"); + + // process the rest of the aad buffer. Even if it is a partial block only + // ghash_update will process it properly. + if(m_aad_buf_pos > 0) + { + m_ghash->update_associated_data(m_aad_buf.data(), m_aad_buf_pos); + } + + m_ghash->final(mac, output_length()); + clear(); + } + +MessageAuthenticationCode* GMAC::clone() const + { + return new GMAC(m_cipher->clone()); + } +} diff --git a/comm/third_party/botan/src/lib/mac/gmac/gmac.h b/comm/third_party/botan/src/lib/mac/gmac/gmac.h new file mode 100644 index 0000000000..b78aeec6f1 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/gmac/gmac.h @@ -0,0 +1,64 @@ +/* + * GMAC + * (C) 2016 Matthias Gierlings, René Korthaus + * (C) 2017 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_GMAC_H_ +#define BOTAN_GMAC_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(gmac.h) + +namespace Botan { + +class BlockCipher; +class GHASH; + +/** +* GMAC +* +* GMAC requires a unique initialization vector be used for each message. +* This must be provided via the MessageAuthenticationCode::start() API +*/ +class BOTAN_PUBLIC_API(2,0) GMAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + size_t output_length() const override; + MessageAuthenticationCode* clone() const override; + + Key_Length_Specification key_spec() const override; + + /** + * Creates a new GMAC instance. + * + * @param cipher the underlying block cipher to use + */ + explicit GMAC(BlockCipher* cipher); + + GMAC(const GMAC&) = delete; + GMAC& operator=(const GMAC&) = delete; + + ~GMAC(); + + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + void key_schedule(const uint8_t key[], size_t size) override; + + static const size_t GCM_BS = 16; + std::unique_ptr m_cipher; + std::unique_ptr m_ghash; + secure_vector m_aad_buf; + size_t m_aad_buf_pos; + bool m_initialized; + }; + +} +#endif diff --git a/comm/third_party/botan/src/lib/mac/gmac/info.txt b/comm/third_party/botan/src/lib/mac/gmac/info.txt new file mode 100644 index 0000000000..cc473feb90 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/gmac/info.txt @@ -0,0 +1,8 @@ + +GMAC -> 20160207 + + + +ghash +block + diff --git a/comm/third_party/botan/src/lib/mac/hmac/hmac.cpp b/comm/third_party/botan/src/lib/mac/hmac/hmac.cpp new file mode 100644 index 0000000000..eada1e1bcf --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/hmac/hmac.cpp @@ -0,0 +1,150 @@ +/* +* HMAC +* (C) 1999-2007,2014,2020 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Update a HMAC Calculation +*/ +void HMAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_ikey.empty() == false); + m_hash->update(input, length); + } + +/* +* Finalize a HMAC Calculation +*/ +void HMAC::final_result(uint8_t mac[]) + { + verify_key_set(m_okey.empty() == false); + m_hash->final(mac); + m_hash->update(m_okey); + m_hash->update(mac, m_hash_output_length); + m_hash->final(mac); + m_hash->update(m_ikey); + } + +Key_Length_Specification HMAC::key_spec() const + { + // Support very long lengths for things like PBKDF2 and the TLS PRF + return Key_Length_Specification(0, 4096); + } + +size_t HMAC::output_length() const + { + return m_hash_output_length; + } + +/* +* HMAC Key Schedule +*/ +void HMAC::key_schedule(const uint8_t key[], size_t length) + { + const uint8_t ipad = 0x36; + const uint8_t opad = 0x5C; + + m_hash->clear(); + + m_ikey.resize(m_hash_block_size); + m_okey.resize(m_hash_block_size); + + clear_mem(m_ikey.data(), m_ikey.size()); + clear_mem(m_okey.data(), m_okey.size()); + + /* + * Sometimes the HMAC key length itself is sensitive, as with PBKDF2 where it + * reveals the length of the passphrase. Make some attempt to hide this to + * side channels. Clearly if the secret is longer than the block size then the + * branch to hash first reveals that. In addition, counting the number of + * compression functions executed reveals the size at the granularity of the + * hash function's block size. + * + * The greater concern is for smaller keys; being able to detect when a + * passphrase is say 4 bytes may assist choosing weaker targets. Even though + * the loop bounds are constant, we can only actually read key[0..length] so + * it doesn't seem possible to make this computation truly constant time. + * + * We don't mind leaking if the length is exactly zero since that's + * trivial to simply check. + */ + + if(length > m_hash_block_size) + { + m_hash->update(key, length); + m_hash->final(m_ikey.data()); + } + else if(length > 0) + { + for(size_t i = 0, i_mod_length = 0; i != m_hash_block_size; ++i) + { + /* + access key[i % length] but avoiding division due to variable + time computation on some processors. + */ + auto needs_reduction = CT::Mask::is_lte(length, i_mod_length); + i_mod_length = needs_reduction.select(0, i_mod_length); + const uint8_t kb = key[i_mod_length]; + + auto in_range = CT::Mask::is_lt(i, length); + m_ikey[i] = static_cast(in_range.if_set_return(kb)); + i_mod_length += 1; + } + } + + for(size_t i = 0; i != m_hash_block_size; ++i) + { + m_ikey[i] ^= ipad; + m_okey[i] = m_ikey[i] ^ ipad ^ opad; + } + + m_hash->update(m_ikey); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC::clear() + { + m_hash->clear(); + zap(m_ikey); + zap(m_okey); + } + +/* +* Return the name of this type +*/ +std::string HMAC::name() const + { + return "HMAC(" + m_hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* HMAC::clone() const + { + return new HMAC(m_hash->clone()); + } + +/* +* HMAC Constructor +*/ +HMAC::HMAC(HashFunction* hash) : + m_hash(hash), + m_hash_output_length(m_hash->output_length()), + m_hash_block_size(m_hash->hash_block_size()) + { + BOTAN_ARG_CHECK(m_hash_block_size >= m_hash_output_length, + "HMAC is not compatible with this hash function"); + } + +} diff --git a/comm/third_party/botan/src/lib/mac/hmac/hmac.h b/comm/third_party/botan/src/lib/mac/hmac/hmac.h new file mode 100644 index 0000000000..1f2f4227d4 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/hmac/hmac.h @@ -0,0 +1,52 @@ +/* +* HMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HMAC_H_ +#define BOTAN_HMAC_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(hmac.h) + +namespace Botan { + +/** +* HMAC +*/ +class BOTAN_PUBLIC_API(2,0) HMAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + MessageAuthenticationCode* clone() const override; + + size_t output_length() const override; + + Key_Length_Specification key_spec() const override; + + /** + * @param hash the hash to use for HMACing + */ + explicit HMAC(HashFunction* hash); + + HMAC(const HMAC&) = delete; + HMAC& operator=(const HMAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr m_hash; + secure_vector m_ikey, m_okey; + size_t m_hash_output_length; + size_t m_hash_block_size; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/hmac/info.txt b/comm/third_party/botan/src/lib/mac/hmac/info.txt new file mode 100644 index 0000000000..50dc665dc9 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/hmac/info.txt @@ -0,0 +1,7 @@ + +HMAC -> 20131128 + + + +hash + diff --git a/comm/third_party/botan/src/lib/mac/info.txt b/comm/third_party/botan/src/lib/mac/info.txt new file mode 100644 index 0000000000..7aef92b879 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/info.txt @@ -0,0 +1,7 @@ + +MAC -> 20150626 + + + +mac.h + diff --git a/comm/third_party/botan/src/lib/mac/mac.cpp b/comm/third_party/botan/src/lib/mac/mac.cpp new file mode 100644 index 0000000000..4c3fc5230e --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/mac.cpp @@ -0,0 +1,171 @@ +/* +* Message Authentication Code base class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_CBC_MAC) + #include +#endif + +#if defined(BOTAN_HAS_CMAC) + #include +#endif + +#if defined(BOTAN_HAS_GMAC) + #include + #include +#endif + +#if defined(BOTAN_HAS_HMAC) + #include + #include +#endif + +#if defined(BOTAN_HAS_POLY1305) + #include +#endif + +#if defined(BOTAN_HAS_SIPHASH) + #include +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + #include +#endif + +namespace Botan { + +std::unique_ptr +MessageAuthenticationCode::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_GMAC) + if(req.algo_name() == "GMAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr(new GMAC(bc.release())); + } + } +#endif + +#if defined(BOTAN_HAS_HMAC) + if(req.algo_name() == "HMAC" && req.arg_count() == 1) + { + // TODO OpenSSL + if(provider.empty() || provider == "base") + { + if(auto h = HashFunction::create(req.arg(0))) + return std::unique_ptr(new HMAC(h.release())); + } + } +#endif + +#if defined(BOTAN_HAS_POLY1305) + if(req.algo_name() == "Poly1305" && req.arg_count() == 0) + { + if(provider.empty() || provider == "base") + return std::unique_ptr(new Poly1305); + } +#endif + +#if defined(BOTAN_HAS_SIPHASH) + if(req.algo_name() == "SipHash") + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr( + new SipHash(req.arg_as_integer(0, 2), req.arg_as_integer(1, 4))); + } + } +#endif + +#if defined(BOTAN_HAS_CMAC) + if((req.algo_name() == "CMAC" || req.algo_name() == "OMAC") && req.arg_count() == 1) + { + // TODO: OpenSSL CMAC + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr(new CMAC(bc.release())); + } + } +#endif + + +#if defined(BOTAN_HAS_CBC_MAC) + if(req.algo_name() == "CBC-MAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr(new CBC_MAC(bc.release())); + } + } +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + if(req.algo_name() == "X9.19-MAC") + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr(new ANSI_X919_MAC); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +std::vector +MessageAuthenticationCode::providers(const std::string& algo_spec) + { + return probe_providers_of(algo_spec, {"base", "openssl"}); + } + +//static +std::unique_ptr +MessageAuthenticationCode::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto mac = MessageAuthenticationCode::create(algo, provider)) + { + return mac; + } + throw Lookup_Error("MAC", algo, provider); + } + +void MessageAuthenticationCode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + BOTAN_UNUSED(nonce); + if(nonce_len > 0) + throw Invalid_IV_Length(name(), nonce_len); + } + +/* +* Default (deterministic) MAC verification operation +*/ +bool MessageAuthenticationCode::verify_mac(const uint8_t mac[], size_t length) + { + secure_vector our_mac = final(); + + if(our_mac.size() != length) + return false; + + return constant_time_compare(our_mac.data(), mac, length); + } + +} diff --git a/comm/third_party/botan/src/lib/mac/mac.h b/comm/third_party/botan/src/lib/mac/mac.h new file mode 100644 index 0000000000..de30b7dbb2 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/mac.h @@ -0,0 +1,143 @@ +/* +* Base class for message authentiction codes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MESSAGE_AUTH_CODE_BASE_H_ +#define BOTAN_MESSAGE_AUTH_CODE_BASE_H_ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents Message Authentication Code (MAC) objects. +*/ +class BOTAN_PUBLIC_API(2,0) MessageAuthenticationCode : public Buffered_Computation, + public SymmetricAlgorithm + { + public: + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr + create(const std::string& algo_spec, + const std::string& provider = ""); + + /* + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws a Lookup_Error if algo/provider combination cannot be found + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector providers(const std::string& algo_spec); + + virtual ~MessageAuthenticationCode() = default; + + /** + * Prepare for processing a message under the specified nonce + * + * Most MACs neither require nor support a nonce; for these algorithms + * calling `start_msg` is optional and calling it with anything other than + * an empty string is an error. One MAC which *requires* a per-message + * nonce be specified is GMAC. + * + * @param nonce the message nonce bytes + * @param nonce_len the size of len in bytes + * Default implementation simply rejects all non-empty nonces + * since most hash/MAC algorithms do not support randomization + */ + virtual void start_msg(const uint8_t nonce[], size_t nonce_len); + + /** + * Begin processing a message with a nonce + * + * @param nonce the per message nonce + */ + template + void start(const std::vector& nonce) + { + start_msg(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + void start(const uint8_t nonce[], size_t nonce_len) + { + start_msg(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + void start() + { + return start_msg(nullptr, 0); + } + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @param length the length of param in + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const uint8_t in[], size_t length); + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const std::vector& in) + { + return verify_mac(in.data(), in.size()); + } + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const secure_vector& in) + { + return verify_mac(in.data(), in.size()); + } + + /** + * Get a new object representing the same algorithm as *this + */ + virtual MessageAuthenticationCode* clone() const = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + }; + +typedef MessageAuthenticationCode MAC; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/poly1305/info.txt b/comm/third_party/botan/src/lib/mac/poly1305/info.txt new file mode 100644 index 0000000000..868f97241d --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/poly1305/info.txt @@ -0,0 +1,7 @@ + +POLY1305 -> 20141227 + + + +poly1305.h + diff --git a/comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp new file mode 100644 index 0000000000..333a21a1a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.cpp @@ -0,0 +1,211 @@ +/* +* Derived from poly1305-donna-64.h by Andrew Moon +* in https://github.com/floodyberry/poly1305-donna +* +* (C) 2014 Andrew Moon +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void poly1305_init(secure_vector& X, const uint8_t key[32]) + { + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + const uint64_t t0 = load_le(key, 0); + const uint64_t t1 = load_le(key, 1); + + X[0] = ( t0 ) & 0xffc0fffffff; + X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + X[2] = ((t1 >> 24) ) & 0x00ffffffc0f; + + /* h = 0 */ + X[3] = 0; + X[4] = 0; + X[5] = 0; + + /* save pad for later */ + X[6] = load_le(key, 2); + X[7] = load_le(key, 3); + } + +void poly1305_blocks(secure_vector& X, const uint8_t *m, size_t blocks, bool is_final = false) + { +#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + typedef donna128 uint128_t; +#endif + + const uint64_t hibit = is_final ? 0 : (static_cast(1) << 40); /* 1 << 128 */ + + const uint64_t r0 = X[0]; + const uint64_t r1 = X[1]; + const uint64_t r2 = X[2]; + + const uint64_t M44 = 0xFFFFFFFFFFF; + const uint64_t M42 = 0x3FFFFFFFFFF; + + uint64_t h0 = X[3+0]; + uint64_t h1 = X[3+1]; + uint64_t h2 = X[3+2]; + + const uint64_t s1 = r1 * 20; + const uint64_t s2 = r2 * 20; + + for(size_t i = 0; i != blocks; ++i) + { + const uint64_t t0 = load_le(m, 0); + const uint64_t t1 = load_le(m, 1); + + h0 += (( t0 ) & M44); + h1 += (((t0 >> 44) | (t1 << 20)) & M44); + h2 += (((t1 >> 24) ) & M42) | hibit; + + const uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1; + const uint64_t c0 = carry_shift(d0, 44); + + const uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2 + c0; + const uint64_t c1 = carry_shift(d1, 44); + + const uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0 + c1; + const uint64_t c2 = carry_shift(d2, 42); + + h0 = d0 & M44; + h1 = d1 & M44; + h2 = d2 & M42; + + h0 += c2 * 5; + h1 += carry_shift(h0, 44); + h0 = h0 & M44; + + m += 16; + } + + X[3+0] = h0; + X[3+1] = h1; + X[3+2] = h2; + } + +void poly1305_finish(secure_vector& X, uint8_t mac[16]) + { + const uint64_t M44 = 0xFFFFFFFFFFF; + const uint64_t M42 = 0x3FFFFFFFFFF; + + /* fully carry h */ + uint64_t h0 = X[3+0]; + uint64_t h1 = X[3+1]; + uint64_t h2 = X[3+2]; + + uint64_t c; + c = (h1 >> 44); h1 &= M44; + h2 += c; c = (h2 >> 42); h2 &= M42; + h0 += c * 5; c = (h0 >> 44); h0 &= M44; + h1 += c; c = (h1 >> 44); h1 &= M44; + h2 += c; c = (h2 >> 42); h2 &= M42; + h0 += c * 5; c = (h0 >> 44); h0 &= M44; + h1 += c; + + /* compute h + -p */ + uint64_t g0 = h0 + 5; c = (g0 >> 44); g0 &= M44; + uint64_t g1 = h1 + c; c = (g1 >> 44); g1 &= M44; + uint64_t g2 = h2 + c - (static_cast(1) << 42); + + /* select h if h < p, or h + -p if h >= p */ + const auto c_mask = CT::Mask::expand(c); + h0 = c_mask.select(g0, h0); + h1 = c_mask.select(g1, h1); + h2 = c_mask.select(g2, h2); + + /* h = (h + pad) */ + const uint64_t t0 = X[6]; + const uint64_t t1 = X[7]; + + h0 += (( t0 ) & M44) ; c = (h0 >> 44); h0 &= M44; + h1 += (((t0 >> 44) | (t1 << 20)) & M44) + c; c = (h1 >> 44); h1 &= M44; + h2 += (((t1 >> 24) ) & M42) + c; h2 &= M42; + + /* mac = h % (2^128) */ + h0 = ((h0 ) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + store_le(mac, h0, h1); + + /* zero out the state */ + clear_mem(X.data(), X.size()); + } + +} + +void Poly1305::clear() + { + zap(m_poly); + zap(m_buf); + m_buf_pos = 0; + } + +void Poly1305::key_schedule(const uint8_t key[], size_t) + { + m_buf_pos = 0; + m_buf.resize(16); + m_poly.resize(8); + + poly1305_init(m_poly, key); + } + +void Poly1305::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_poly.size() == 8); + + if(m_buf_pos) + { + buffer_insert(m_buf, m_buf_pos, input, length); + + if(m_buf_pos + length >= m_buf.size()) + { + poly1305_blocks(m_poly, m_buf.data(), 1); + input += (m_buf.size() - m_buf_pos); + length -= (m_buf.size() - m_buf_pos); + m_buf_pos = 0; + } + } + + const size_t full_blocks = length / m_buf.size(); + const size_t remaining = length % m_buf.size(); + + if(full_blocks) + poly1305_blocks(m_poly, input, full_blocks); + + buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining); + m_buf_pos += remaining; + } + +void Poly1305::final_result(uint8_t out[]) + { + verify_key_set(m_poly.size() == 8); + + if(m_buf_pos != 0) + { + m_buf[m_buf_pos] = 1; + const size_t len = m_buf.size() - m_buf_pos - 1; + if (len > 0) + { + clear_mem(&m_buf[m_buf_pos+1], len); + } + poly1305_blocks(m_poly, m_buf.data(), 1, true); + } + + poly1305_finish(m_poly, out); + + m_poly.clear(); + m_buf_pos = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/mac/poly1305/poly1305.h b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.h new file mode 100644 index 0000000000..fdd01ecd1a --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/poly1305/poly1305.h @@ -0,0 +1,50 @@ +/* +* Poly1305 +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MAC_POLY1305_H_ +#define BOTAN_MAC_POLY1305_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(poly1305.h) + +namespace Botan { + +/** +* DJB's Poly1305 +* Important note: each key can only be used once +*/ +class BOTAN_PUBLIC_API(2,0) Poly1305 final : public MessageAuthenticationCode + { + public: + std::string name() const override { return "Poly1305"; } + + MessageAuthenticationCode* clone() const override { return new Poly1305; } + + void clear() override; + + size_t output_length() const override { return 16; } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(32); + } + + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + secure_vector m_poly; + secure_vector m_buf; + size_t m_buf_pos = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/siphash/info.txt b/comm/third_party/botan/src/lib/mac/siphash/info.txt new file mode 100644 index 0000000000..8d4c20d1a8 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/siphash/info.txt @@ -0,0 +1,3 @@ + +SIPHASH -> 20150110 + diff --git a/comm/third_party/botan/src/lib/mac/siphash/siphash.cpp b/comm/third_party/botan/src/lib/mac/siphash/siphash.cpp new file mode 100644 index 0000000000..566d5d5def --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/siphash/siphash.cpp @@ -0,0 +1,136 @@ +/* +* SipHash +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +void SipRounds(uint64_t M, secure_vector& V, size_t r) + { + uint64_t V0 = V[0], V1 = V[1], V2 = V[2], V3 = V[3]; + + V3 ^= M; + for(size_t i = 0; i != r; ++i) + { + V0 += V1; V2 += V3; + V1 = rotl<13>(V1); + V3 = rotl<16>(V3); + V1 ^= V0; V3 ^= V2; + V0 = rotl<32>(V0); + + V2 += V1; V0 += V3; + V1 = rotl<17>(V1); + V3 = rotl<21>(V3); + V1 ^= V2; V3 ^= V0; + V2 = rotl<32>(V2); + } + V0 ^= M; + + V[0] = V0; V[1] = V1; V[2] = V2; V[3] = V3; + } + +} + +void SipHash::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_V.empty() == false); + + // SipHash counts the message length mod 256 + m_words += static_cast(length); + + if(m_mbuf_pos) + { + while(length && m_mbuf_pos != 8) + { + m_mbuf = (m_mbuf >> 8) | (static_cast(input[0]) << 56); + ++m_mbuf_pos; + ++input; + length--; + } + + if(m_mbuf_pos == 8) + { + SipRounds(m_mbuf, m_V, m_C); + m_mbuf_pos = 0; + m_mbuf = 0; + } + } + + while(length >= 8) + { + SipRounds(load_le(input, 0), m_V, m_C); + input += 8; + length -= 8; + } + + for(size_t i = 0; i != length; ++i) + { + m_mbuf = (m_mbuf >> 8) | (static_cast(input[i]) << 56); + m_mbuf_pos++; + } + } + +void SipHash::final_result(uint8_t mac[]) + { + verify_key_set(m_V.empty() == false); + + if(m_mbuf_pos == 0) + { + m_mbuf = (static_cast(m_words) << 56); + } + else if(m_mbuf_pos < 8) + { + m_mbuf = (m_mbuf >> (64-m_mbuf_pos*8)) | (static_cast(m_words) << 56); + } + + SipRounds(m_mbuf, m_V, m_C); + + m_V[2] ^= 0xFF; + SipRounds(0, m_V, m_D); + + const uint64_t X = m_V[0] ^ m_V[1] ^ m_V[2] ^ m_V[3]; + + store_le(X, mac); + + clear(); + } + +void SipHash::key_schedule(const uint8_t key[], size_t) + { + const uint64_t K0 = load_le(key, 0); + const uint64_t K1 = load_le(key, 1); + + m_V.resize(4); + m_V[0] = K0 ^ 0x736F6D6570736575; + m_V[1] = K1 ^ 0x646F72616E646F6D; + m_V[2] = K0 ^ 0x6C7967656E657261; + m_V[3] = K1 ^ 0x7465646279746573; + } + +void SipHash::clear() + { + zap(m_V); + m_mbuf = 0; + m_mbuf_pos = 0; + m_words = 0; + } + +std::string SipHash::name() const + { + return "SipHash(" + std::to_string(m_C) + "," + std::to_string(m_D) + ")"; + } + +MessageAuthenticationCode* SipHash::clone() const + { + return new SipHash(m_C, m_D); + } + +} diff --git a/comm/third_party/botan/src/lib/mac/siphash/siphash.h b/comm/third_party/botan/src/lib/mac/siphash/siphash.h new file mode 100644 index 0000000000..d60df8dfce --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/siphash/siphash.h @@ -0,0 +1,47 @@ +/* +* SipHash +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SIPHASH_H_ +#define BOTAN_SIPHASH_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(siphash.h) + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) SipHash final : public MessageAuthenticationCode + { + public: + SipHash(size_t c = 2, size_t d = 4) : m_C(c), m_D(d) {} + + void clear() override; + std::string name() const override; + + MessageAuthenticationCode* clone() const override; + + size_t output_length() const override { return 8; } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(16); + } + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + const size_t m_C, m_D; + secure_vector m_V; + uint64_t m_mbuf = 0; + size_t m_mbuf_pos = 0; + uint8_t m_words = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/mac/x919_mac/info.txt b/comm/third_party/botan/src/lib/mac/x919_mac/info.txt new file mode 100644 index 0000000000..65d6cee645 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/x919_mac/info.txt @@ -0,0 +1,7 @@ + +ANSI_X919_MAC -> 20131128 + + + +des + diff --git a/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp new file mode 100644 index 0000000000..0cbf087959 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.cpp @@ -0,0 +1,99 @@ +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +* Update an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_state.empty() == false); + + size_t xored = std::min(8 - m_position, length); + xor_buf(&m_state[m_position], input, xored); + m_position += xored; + + if(m_position < 8) return; + + m_des1->encrypt(m_state); + input += xored; + length -= xored; + while(length >= 8) + { + xor_buf(m_state, input, 8); + m_des1->encrypt(m_state); + input += 8; + length -= 8; + } + + xor_buf(m_state, input, length); + m_position = length; + } + +/* +* Finalize an ANSI X9.19 MAC Calculation +*/ +void ANSI_X919_MAC::final_result(uint8_t mac[]) + { + if(m_position) + m_des1->encrypt(m_state); + m_des2->decrypt(m_state.data(), mac); + m_des1->encrypt(mac); + zeroise(m_state); + m_position = 0; + } + +/* +* ANSI X9.19 MAC Key Schedule +*/ +void ANSI_X919_MAC::key_schedule(const uint8_t key[], size_t length) + { + m_state.resize(8); + + m_des1->set_key(key, 8); + + if(length == 16) + key += 8; + + m_des2->set_key(key, 8); + } + +/* +* Clear memory of sensitive data +*/ +void ANSI_X919_MAC::clear() + { + m_des1->clear(); + m_des2->clear(); + zap(m_state); + m_position = 0; + } + +std::string ANSI_X919_MAC::name() const + { + return "X9.19-MAC"; + } + +MessageAuthenticationCode* ANSI_X919_MAC::clone() const + { + return new ANSI_X919_MAC; + } + +/* +* ANSI X9.19 MAC Constructor +*/ +ANSI_X919_MAC::ANSI_X919_MAC() : + m_des1(BlockCipher::create("DES")), + m_des2(m_des1->clone()), + m_position(0) + { + } + +} diff --git a/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h new file mode 100644 index 0000000000..3df38b9aa6 --- /dev/null +++ b/comm/third_party/botan/src/lib/mac/x919_mac/x919_mac.h @@ -0,0 +1,51 @@ +/* +* ANSI X9.19 MAC +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ANSI_X919_MAC_H_ +#define BOTAN_ANSI_X919_MAC_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(x919_mac.h) + +namespace Botan { + +/** +* DES/3DES-based MAC from ANSI X9.19 +*/ +class BOTAN_PUBLIC_API(2,0) ANSI_X919_MAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + size_t output_length() const override { return 8; } + + MessageAuthenticationCode* clone() const override; + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(8, 16, 8); + } + + ANSI_X919_MAC(); + + ANSI_X919_MAC(const ANSI_X919_MAC&) = delete; + ANSI_X919_MAC& operator=(const ANSI_X919_MAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr m_des1, m_des2; + secure_vector m_state; + size_t m_position; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/bigint/big_code.cpp b/comm/third_party/botan/src/lib/math/bigint/big_code.cpp new file mode 100644 index 0000000000..6eb27549e8 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/big_code.cpp @@ -0,0 +1,200 @@ +/* +* BigInt Encoding/Decoding +* (C) 1999-2010,2012,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +std::string BigInt::to_dec_string() const + { + BigInt copy = *this; + copy.set_sign(Positive); + + uint8_t remainder; + std::vector digits; + + while(copy > 0) + { + ct_divide_u8(copy, 10, copy, remainder); + digits.push_back(remainder); + } + + std::string s; + + for(auto i = digits.rbegin(); i != digits.rend(); ++i) + { + s.push_back(Charset::digit2char(*i)); + } + + if(s.empty()) + s += "0"; + + return s; + } + +std::string BigInt::to_hex_string() const + { + const std::vector bits = BigInt::encode(*this); + if(bits.empty()) + return "00"; + else + return hex_encode(bits); + } + +/* +* Encode a BigInt +*/ +void BigInt::encode(uint8_t output[], const BigInt& n, Base base) + { + secure_vector enc = n.encode_locked(base); + copy_mem(output, enc.data(), enc.size()); + } + +namespace { + +std::vector str_to_vector(const std::string& s) + { + std::vector v(s.size()); + std::memcpy(v.data(), s.data(), s.size()); + return v; + } + +secure_vector str_to_lvector(const std::string& s) + { + secure_vector v(s.size()); + std::memcpy(v.data(), s.data(), s.size()); + return v; + } + +} + +/* +* Encode a BigInt +*/ +std::vector BigInt::encode(const BigInt& n, Base base) + { + if(base == Binary) + return BigInt::encode(n); + else if(base == Hexadecimal) + return str_to_vector(n.to_hex_string()); + else if(base == Decimal) + return str_to_vector(n.to_dec_string()); + else + throw Invalid_Argument("Unknown BigInt encoding base"); + } + +/* +* Encode a BigInt +*/ +secure_vector BigInt::encode_locked(const BigInt& n, Base base) + { + if(base == Binary) + return BigInt::encode_locked(n); + else if(base == Hexadecimal) + return str_to_lvector(n.to_hex_string()); + else if(base == Decimal) + return str_to_lvector(n.to_dec_string()); + else + throw Invalid_Argument("Unknown BigInt encoding base"); + } + +/* +* Encode a BigInt, with leading 0s if needed +*/ +secure_vector BigInt::encode_1363(const BigInt& n, size_t bytes) + { + if(n.bytes() > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + secure_vector output(bytes); + n.binary_encode(output.data(), output.size()); + return output; + } + +//static +void BigInt::encode_1363(uint8_t output[], size_t bytes, const BigInt& n) + { + if(n.bytes() > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + n.binary_encode(output, bytes); + } + +/* +* Encode two BigInt, with leading 0s if needed, and concatenate +*/ +secure_vector BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) + { + if(n1.bytes() > bytes || n2.bytes() > bytes) + throw Encoding_Error("encode_fixed_length_int_pair: values too large to encode properly"); + secure_vector output(2 * bytes); + n1.binary_encode(output.data() , bytes); + n2.binary_encode(output.data() + bytes, bytes); + return output; + } + +/* +* Decode a BigInt +*/ +BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) + { + BigInt r; + if(base == Binary) + { + r.binary_decode(buf, length); + } + else if(base == Hexadecimal) + { + secure_vector binary; + + if(length % 2) + { + // Handle lack of leading 0 + const char buf0_with_leading_0[2] = + { '0', static_cast(buf[0]) }; + + binary = hex_decode_locked(buf0_with_leading_0, 2); + + binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), + length - 1, + false); + } + else + binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), + length, false); + + r.binary_decode(binary.data(), binary.size()); + } + else if(base == Decimal) + { + for(size_t i = 0; i != length; ++i) + { + if(Charset::is_space(buf[i])) + continue; + + if(!Charset::is_digit(buf[i])) + throw Invalid_Argument("BigInt::decode: " + "Invalid character in decimal input"); + + const uint8_t x = Charset::char2digit(buf[i]); + + if(x >= 10) + throw Invalid_Argument("BigInt: Invalid decimal string"); + + r *= 10; + r += x; + } + } + else + throw Invalid_Argument("Unknown BigInt decoding method"); + return r; + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/big_io.cpp b/comm/third_party/botan/src/lib/math/bigint/big_io.cpp new file mode 100644 index 0000000000..b31315eac4 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/big_io.cpp @@ -0,0 +1,62 @@ +/* +* BigInt Input/Output +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Write the BigInt into a stream +*/ +std::ostream& operator<<(std::ostream& stream, const BigInt& n) + { + size_t base = 10; + if(stream.flags() & std::ios::hex) + base = 16; + if(stream.flags() & std::ios::oct) + throw Invalid_Argument("Octal output of BigInt not supported"); + + if(n == 0) + stream.write("0", 1); + else + { + if(n < 0) + stream.write("-", 1); + + std::string enc; + + if(base == 10) + enc = n.to_dec_string(); + else + enc = n.to_hex_string(); + + size_t skip = 0; + while(skip < enc.size() && enc[skip] == '0') + ++skip; + stream.write(&enc[skip], enc.size() - skip); + } + if(!stream.good()) + throw Stream_IO_Error("BigInt output operator has failed"); + return stream; + } + +/* +* Read the BigInt from a stream +*/ +std::istream& operator>>(std::istream& stream, BigInt& n) + { + std::string str; + std::getline(stream, str); + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("BigInt input operator has failed"); + n = BigInt(str); + return stream; + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/big_ops2.cpp b/comm/third_party/botan/src/lib/math/bigint/big_ops2.cpp new file mode 100644 index 0000000000..cc85f5e96d --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/big_ops2.cpp @@ -0,0 +1,314 @@ +/* +* (C) 1999-2007,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +BigInt& BigInt::add(const word y[], size_t y_words, Sign y_sign) + { + const size_t x_sw = sig_words(); + + grow_to(std::max(x_sw, y_words) + 1); + + if(sign() == y_sign) + { + bigint_add2(mutable_data(), size() - 1, y, y_words); + } + else + { + const int32_t relative_size = bigint_cmp(data(), x_sw, y, y_words); + + if(relative_size >= 0) + { + // *this >= y + bigint_sub2(mutable_data(), x_sw, y, y_words); + } + else + { + // *this < y + bigint_sub2_rev(mutable_data(), y, y_words); + } + + //this->sign_fixup(relative_size, y_sign); + if(relative_size < 0) + set_sign(y_sign); + else if(relative_size == 0) + set_sign(Positive); + } + + return (*this); + } + +BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector& ws) + { + if(this->is_negative() || s.is_negative() || mod.is_negative()) + throw Invalid_Argument("BigInt::mod_add expects all arguments are positive"); + + BOTAN_DEBUG_ASSERT(*this < mod); + BOTAN_DEBUG_ASSERT(s < mod); + + /* + t + s or t + s - p == t - (p - s) + + So first compute ws = p - s + + Then compute t + s and t - ws + + If t - ws does not borrow, then that is the correct valued + */ + + const size_t mod_sw = mod.sig_words(); + BOTAN_ARG_CHECK(mod_sw > 0, "BigInt::mod_add modulus must be positive"); + + this->grow_to(mod_sw); + s.grow_to(mod_sw); + + // First mod_sw for p - s, 2*mod_sw for bigint_addsub workspace + if(ws.size() < 3*mod_sw) + ws.resize(3*mod_sw); + + word borrow = bigint_sub3(&ws[0], mod.data(), mod_sw, s.data(), mod_sw); + BOTAN_DEBUG_ASSERT(borrow == 0); + + // Compute t - ws + borrow = bigint_sub3(&ws[mod_sw], this->data(), mod_sw, &ws[0], mod_sw); + + // Compute t + s + bigint_add3_nc(&ws[mod_sw*2], this->data(), mod_sw, s.data(), mod_sw); + + CT::conditional_copy_mem(borrow, &ws[0], &ws[mod_sw*2], &ws[mod_sw], mod_sw); + set_words(&ws[0], mod_sw); + + return (*this); + } + +BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector& ws) + { + if(this->is_negative() || s.is_negative() || mod.is_negative()) + throw Invalid_Argument("BigInt::mod_sub expects all arguments are positive"); + + // We are assuming in this function that *this and s are no more than mod_sw words long + BOTAN_DEBUG_ASSERT(*this < mod); + BOTAN_DEBUG_ASSERT(s < mod); + + const size_t mod_sw = mod.sig_words(); + + this->grow_to(mod_sw); + s.grow_to(mod_sw); + + if(ws.size() < mod_sw) + ws.resize(mod_sw); + + if(mod_sw == 4) + bigint_mod_sub_n<4>(mutable_data(), s.data(), mod.data(), ws.data()); + else if(mod_sw == 6) + bigint_mod_sub_n<6>(mutable_data(), s.data(), mod.data(), ws.data()); + else + bigint_mod_sub(mutable_data(), s.data(), mod.data(), mod_sw, ws.data()); + + return (*this); + } + +BigInt& BigInt::mod_mul(uint8_t y, const BigInt& mod, secure_vector& ws) + { + BOTAN_ARG_CHECK(this->is_negative() == false, "*this must be positive"); + BOTAN_ARG_CHECK(y < 16, "y too large"); + + BOTAN_DEBUG_ASSERT(*this < mod); + + *this *= static_cast(y); + this->reduce_below(mod, ws); + return (*this); + } + +BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector& ws) + { + if(this->sign() != BigInt::Positive) + throw Invalid_State("BigInt::sub_rev requires this is positive"); + + const size_t x_sw = this->sig_words(); + + ws.resize(std::max(x_sw, y_sw)); + clear_mem(ws.data(), ws.size()); + + const int32_t relative_size = bigint_sub_abs(ws.data(), data(), x_sw, y, y_sw); + + this->cond_flip_sign(relative_size > 0); + this->swap_reg(ws); + + return (*this); + } + +/* +* Multiplication Operator +*/ +BigInt& BigInt::operator*=(const BigInt& y) + { + secure_vector ws; + return this->mul(y, ws); + } + +BigInt& BigInt::mul(const BigInt& y, secure_vector& ws) + { + const size_t x_sw = sig_words(); + const size_t y_sw = y.sig_words(); + set_sign((sign() == y.sign()) ? Positive : Negative); + + if(x_sw == 0 || y_sw == 0) + { + clear(); + set_sign(Positive); + } + else if(x_sw == 1 && y_sw) + { + grow_to(y_sw + 1); + bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0)); + } + else if(y_sw == 1 && x_sw) + { + word carry = bigint_linmul2(mutable_data(), x_sw, y.word_at(0)); + set_word_at(x_sw, carry); + } + else + { + const size_t new_size = x_sw + y_sw + 1; + ws.resize(new_size); + secure_vector z_reg(new_size); + + bigint_mul(z_reg.data(), z_reg.size(), + data(), size(), x_sw, + y.data(), y.size(), y_sw, + ws.data(), ws.size()); + + this->swap_reg(z_reg); + } + + return (*this); + } + +BigInt& BigInt::square(secure_vector& ws) + { + const size_t sw = sig_words(); + + secure_vector z(2*sw); + ws.resize(z.size()); + + bigint_sqr(z.data(), z.size(), + data(), size(), sw, + ws.data(), ws.size()); + + swap_reg(z); + set_sign(BigInt::Positive); + + return (*this); + } + +BigInt& BigInt::operator*=(word y) + { + if(y == 0) + { + clear(); + set_sign(Positive); + } + + const word carry = bigint_linmul2(mutable_data(), size(), y); + set_word_at(size(), carry); + + return (*this); + } + +/* +* Division Operator +*/ +BigInt& BigInt::operator/=(const BigInt& y) + { + if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) + (*this) >>= (y.bits() - 1); + else + (*this) = (*this) / y; + return (*this); + } + +/* +* Modulo Operator +*/ +BigInt& BigInt::operator%=(const BigInt& mod) + { + return (*this = (*this) % mod); + } + +/* +* Modulo Operator +*/ +word BigInt::operator%=(word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + + word remainder = 0; + + if(is_power_of_2(mod)) + { + remainder = (word_at(0) & (mod - 1)); + } + else + { + const size_t sw = sig_words(); + for(size_t i = sw; i > 0; --i) + remainder = bigint_modop(remainder, word_at(i-1), mod); + } + + if(remainder && sign() == BigInt::Negative) + remainder = mod - remainder; + + m_data.set_to_zero(); + m_data.set_word_at(0, remainder); + set_sign(BigInt::Positive); + return remainder; + } + +/* +* Left Shift Operator +*/ +BigInt& BigInt::operator<<=(size_t shift) + { + const size_t shift_words = shift / BOTAN_MP_WORD_BITS; + const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; + const size_t size = sig_words(); + + const size_t bits_free = top_bits_free(); + + const size_t new_size = size + shift_words + (bits_free < shift_bits); + + m_data.grow_to(new_size); + + bigint_shl1(m_data.mutable_data(), new_size, size, shift_words, shift_bits); + + return (*this); + } + +/* +* Right Shift Operator +*/ +BigInt& BigInt::operator>>=(size_t shift) + { + const size_t shift_words = shift / BOTAN_MP_WORD_BITS; + const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; + + bigint_shr1(m_data.mutable_data(), m_data.size(), shift_words, shift_bits); + + if(is_negative() && is_zero()) + set_sign(Positive); + + return (*this); + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/big_ops3.cpp b/comm/third_party/botan/src/lib/math/bigint/big_ops3.cpp new file mode 100644 index 0000000000..11804762b9 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/big_ops3.cpp @@ -0,0 +1,214 @@ +/* +* BigInt Binary Operators +* (C) 1999-2007,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +//static +BigInt BigInt::add2(const BigInt& x, const word y[], size_t y_words, BigInt::Sign y_sign) + { + const size_t x_sw = x.sig_words(); + + BigInt z(x.sign(), std::max(x_sw, y_words) + 1); + + if(x.sign() == y_sign) + { + bigint_add3(z.mutable_data(), x.data(), x_sw, y, y_words); + } + else + { + const int32_t relative_size = bigint_sub_abs(z.mutable_data(), x.data(), x_sw, y, y_words); + + //z.sign_fixup(relative_size, y_sign); + if(relative_size < 0) + z.set_sign(y_sign); + else if(relative_size == 0) + z.set_sign(BigInt::Positive); + } + + return z; + } + +/* +* Multiplication Operator +*/ +BigInt operator*(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(); + const size_t y_sw = y.sig_words(); + + BigInt z(BigInt::Positive, x.size() + y.size()); + + if(x_sw == 1 && y_sw) + bigint_linmul3(z.mutable_data(), y.data(), y_sw, x.word_at(0)); + else if(y_sw == 1 && x_sw) + bigint_linmul3(z.mutable_data(), x.data(), x_sw, y.word_at(0)); + else if(x_sw && y_sw) + { + secure_vector workspace(z.size()); + + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), x_sw, + y.data(), y.size(), y_sw, + workspace.data(), workspace.size()); + } + + z.cond_flip_sign(x_sw > 0 && y_sw > 0 && x.sign() != y.sign()); + + return z; + } + +/* +* Multiplication Operator +*/ +BigInt operator*(const BigInt& x, word y) + { + const size_t x_sw = x.sig_words(); + + BigInt z(BigInt::Positive, x_sw + 1); + + if(x_sw && y) + { + bigint_linmul3(z.mutable_data(), x.data(), x_sw, y); + z.set_sign(x.sign()); + } + + return z; + } + +/* +* Division Operator +*/ +BigInt operator/(const BigInt& x, const BigInt& y) + { + if(y.sig_words() == 1) + { + return x / y.word_at(0); + } + + BigInt q, r; + vartime_divide(x, y, q, r); + return q; + } + +/* +* Division Operator +*/ +BigInt operator/(const BigInt& x, word y) + { + if(y == 0) + throw BigInt::DivideByZero(); + else if(y == 1) + return x; + else if(y == 2) + return (x >> 1); + else if(y <= 255) + { + BigInt q; + uint8_t r; + ct_divide_u8(x, static_cast(y), q, r); + return q; + } + + BigInt q, r; + vartime_divide(x, y, q, r); + return q; + } + +/* +* Modulo Operator +*/ +BigInt operator%(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative()) + throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); + if(n.is_positive() && mod.is_positive() && n < mod) + return n; + + if(mod.sig_words() == 1) + { + return n % mod.word_at(0); + } + + BigInt q, r; + vartime_divide(n, mod, q, r); + return r; + } + +/* +* Modulo Operator +*/ +word operator%(const BigInt& n, word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + + if(mod == 1) + return 0; + + word remainder = 0; + + if(is_power_of_2(mod)) + { + remainder = (n.word_at(0) & (mod - 1)); + } + else + { + const size_t sw = n.sig_words(); + for(size_t i = sw; i > 0; --i) + { + remainder = bigint_modop(remainder, n.word_at(i-1), mod); + } + } + + if(remainder && n.sign() == BigInt::Negative) + return mod - remainder; + return remainder; + } + +/* +* Left Shift Operator +*/ +BigInt operator<<(const BigInt& x, size_t shift) + { + const size_t shift_words = shift / BOTAN_MP_WORD_BITS, + shift_bits = shift % BOTAN_MP_WORD_BITS; + + const size_t x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); + bigint_shl2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +/* +* Right Shift Operator +*/ +BigInt operator>>(const BigInt& x, size_t shift) + { + const size_t shift_words = shift / BOTAN_MP_WORD_BITS; + const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; + const size_t x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw - shift_words); + bigint_shr2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); + + if(x.is_negative() && y.is_zero()) + y.set_sign(BigInt::Positive); + + return y; + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/big_rand.cpp b/comm/third_party/botan/src/lib/math/bigint/big_rand.cpp new file mode 100644 index 0000000000..dd4cb5eaba --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/big_rand.cpp @@ -0,0 +1,64 @@ +/* +* BigInt Random Generation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Randomize this number +*/ +void BigInt::randomize(RandomNumberGenerator& rng, + size_t bitsize, bool set_high_bit) + { + set_sign(Positive); + + if(bitsize == 0) + { + clear(); + } + else + { + secure_vector array = rng.random_vec(round_up(bitsize, 8) / 8); + + // Always cut unwanted bits + if(bitsize % 8) + array[0] &= 0xFF >> (8 - (bitsize % 8)); + + // Set the highest bit if wanted + if (set_high_bit) + array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0); + + binary_decode(array); + } + } + +/* +* Generate a random integer within given range +*/ +BigInt BigInt::random_integer(RandomNumberGenerator& rng, + const BigInt& min, const BigInt& max) + { + if(min.is_negative() || max.is_negative() || max <= min) + throw Invalid_Argument("BigInt::random_integer invalid range"); + + BigInt r; + + const size_t bits = max.bits(); + + do + { + r.randomize(rng, bits, false); + } + while(r < min || r >= max); + + return r; + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/bigint.cpp b/comm/third_party/botan/src/lib/math/bigint/bigint.cpp new file mode 100644 index 0000000000..7bcbaf37f0 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/bigint.cpp @@ -0,0 +1,551 @@ +/* +* BigInt Base +* (C) 1999-2011,2012,2014,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +BigInt::BigInt(const word words[], size_t length) + { + m_data.set_words(words, length); + } + +/* +* Construct a BigInt from a regular number +*/ +BigInt::BigInt(uint64_t n) + { + if(n > 0) + { +#if BOTAN_MP_WORD_BITS == 32 + m_data.set_word_at(0, static_cast(n)); + m_data.set_word_at(1, static_cast(n >> 32)); +#else + m_data.set_word_at(0, n); +#endif + } + + } + +/* +* Construct a BigInt of the specified size +*/ +BigInt::BigInt(Sign s, size_t size) + { + m_data.set_size(size); + m_signedness = s; + } + +/* +* Construct a BigInt from a string +*/ +BigInt::BigInt(const std::string& str) + { + Base base = Decimal; + size_t markers = 0; + bool negative = false; + + if(str.length() > 0 && str[0] == '-') + { + markers += 1; + negative = true; + } + + if(str.length() > markers + 2 && str[markers ] == '0' && + str[markers + 1] == 'x') + { + markers += 2; + base = Hexadecimal; + } + + *this = decode(cast_char_ptr_to_uint8(str.data()) + markers, + str.length() - markers, base); + + if(negative) set_sign(Negative); + else set_sign(Positive); + } + +BigInt::BigInt(const uint8_t input[], size_t length) + { + binary_decode(input, length); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(const uint8_t input[], size_t length, Base base) + { + *this = decode(input, length, base); + } + +BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits) + { + if(8 * length > max_bits) + length = (max_bits + 7) / 8; + + binary_decode(buf, length); + + if(8 * length > max_bits) + *this >>= (8 - (max_bits % 8)); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit) + { + randomize(rng, bits, set_high_bit); + } + +uint8_t BigInt::byte_at(size_t n) const + { + return get_byte(sizeof(word) - (n % sizeof(word)) - 1, + word_at(n / sizeof(word))); + } + +int32_t BigInt::cmp_word(word other) const + { + if(is_negative()) + return -1; // other is positive ... + + const size_t sw = this->sig_words(); + if(sw > 1) + return 1; // must be larger since other is just one word ... + + return bigint_cmp(this->data(), sw, &other, 1); + } + +/* +* Comparison Function +*/ +int32_t BigInt::cmp(const BigInt& other, bool check_signs) const + { + if(check_signs) + { + if(other.is_positive() && this->is_negative()) + return -1; + + if(other.is_negative() && this->is_positive()) + return 1; + + if(other.is_negative() && this->is_negative()) + return (-bigint_cmp(this->data(), this->size(), + other.data(), other.size())); + } + + return bigint_cmp(this->data(), this->size(), + other.data(), other.size()); + } + +bool BigInt::is_equal(const BigInt& other) const + { + if(this->sign() != other.sign()) + return false; + + return bigint_ct_is_eq(this->data(), this->sig_words(), + other.data(), other.sig_words()).is_set(); + } + +bool BigInt::is_less_than(const BigInt& other) const + { + if(this->is_negative() && other.is_positive()) + return true; + + if(this->is_positive() && other.is_negative()) + return false; + + if(other.is_negative() && this->is_negative()) + { + return bigint_ct_is_lt(other.data(), other.sig_words(), + this->data(), this->sig_words()).is_set(); + } + + return bigint_ct_is_lt(this->data(), this->sig_words(), + other.data(), other.sig_words()).is_set(); + } + +void BigInt::encode_words(word out[], size_t size) const + { + const size_t words = sig_words(); + + if(words > size) + throw Encoding_Error("BigInt::encode_words value too large to encode"); + + clear_mem(out, size); + copy_mem(out, data(), words); + } + +size_t BigInt::Data::calc_sig_words() const + { + const size_t sz = m_reg.size(); + size_t sig = sz; + + word sub = 1; + + for(size_t i = 0; i != sz; ++i) + { + const word w = m_reg[sz - i - 1]; + sub &= ct_is_zero(w); + sig -= sub; + } + + /* + * This depends on the data so is poisoned, but unpoison it here as + * later conditionals are made on the size. + */ + CT::unpoison(sig); + + return sig; + } + +/* +* Return bits {offset...offset+length} +*/ +uint32_t BigInt::get_substring(size_t offset, size_t length) const + { + if(length == 0 || length > 32) + throw Invalid_Argument("BigInt::get_substring invalid substring length"); + + const uint32_t mask = 0xFFFFFFFF >> (32 - length); + + const size_t word_offset = offset / BOTAN_MP_WORD_BITS; + const size_t wshift = (offset % BOTAN_MP_WORD_BITS); + + /* + * The substring is contained within one or at most two words. The + * offset and length are not secret, so we can perform conditional + * operations on those values. + */ + const word w0 = word_at(word_offset); + + if(wshift == 0 || (offset + length) / BOTAN_MP_WORD_BITS == word_offset) + { + return static_cast(w0 >> wshift) & mask; + } + else + { + const word w1 = word_at(word_offset + 1); + return static_cast((w0 >> wshift) | (w1 << (BOTAN_MP_WORD_BITS - wshift))) & mask; + } + } + +/* +* Convert this number to a uint32_t, if possible +*/ +uint32_t BigInt::to_u32bit() const + { + if(is_negative()) + throw Encoding_Error("BigInt::to_u32bit: Number is negative"); + if(bits() > 32) + throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); + + uint32_t out = 0; + for(size_t i = 0; i != 4; ++i) + out = (out << 8) | byte_at(3-i); + return out; + } + +/* +* Set bit number n +*/ +void BigInt::conditionally_set_bit(size_t n, bool set_it) + { + const size_t which = n / BOTAN_MP_WORD_BITS; + const word mask = static_cast(set_it) << (n % BOTAN_MP_WORD_BITS); + m_data.set_word_at(which, word_at(which) | mask); + } + +/* +* Clear bit number n +*/ +void BigInt::clear_bit(size_t n) + { + const size_t which = n / BOTAN_MP_WORD_BITS; + + if(which < size()) + { + const word mask = ~(static_cast(1) << (n % BOTAN_MP_WORD_BITS)); + m_data.set_word_at(which, word_at(which) & mask); + } + } + +size_t BigInt::bytes() const + { + return round_up(bits(), 8) / 8; + } + +size_t BigInt::top_bits_free() const + { + const size_t words = sig_words(); + + const word top_word = word_at(words - 1); + const size_t bits_used = high_bit(top_word); + CT::unpoison(bits_used); + return BOTAN_MP_WORD_BITS - bits_used; + } + +size_t BigInt::bits() const + { + const size_t words = sig_words(); + + if(words == 0) + return 0; + + const size_t full_words = (words - 1) * BOTAN_MP_WORD_BITS; + const size_t top_bits = BOTAN_MP_WORD_BITS - top_bits_free(); + + return full_words + top_bits; + } + +/* +* Calcluate the size in a certain base +*/ +size_t BigInt::encoded_size(Base base) const + { + static const double LOG_2_BASE_10 = 0.30102999566; + + if(base == Binary) + return bytes(); + else if(base == Hexadecimal) + return 2*bytes(); + else if(base == Decimal) + return static_cast((bits() * LOG_2_BASE_10) + 1); + else + throw Invalid_Argument("Unknown base for BigInt encoding"); + } + +/* +* Return the negation of this number +*/ +BigInt BigInt::operator-() const + { + BigInt x = (*this); + x.flip_sign(); + return x; + } + +size_t BigInt::reduce_below(const BigInt& p, secure_vector& ws) + { + if(p.is_negative() || this->is_negative()) + throw Invalid_Argument("BigInt::reduce_below both values must be positive"); + + const size_t p_words = p.sig_words(); + + if(size() < p_words + 1) + grow_to(p_words + 1); + + if(ws.size() < p_words + 1) + ws.resize(p_words + 1); + + clear_mem(ws.data(), ws.size()); + + size_t reductions = 0; + + for(;;) + { + word borrow = bigint_sub3(ws.data(), data(), p_words + 1, p.data(), p_words); + if(borrow) + break; + + ++reductions; + swap_reg(ws); + } + + return reductions; + } + +void BigInt::ct_reduce_below(const BigInt& mod, secure_vector& ws, size_t bound) + { + if(mod.is_negative() || this->is_negative()) + throw Invalid_Argument("BigInt::ct_reduce_below both values must be positive"); + + const size_t mod_words = mod.sig_words(); + + grow_to(mod_words); + + const size_t sz = size(); + + ws.resize(sz); + + clear_mem(ws.data(), sz); + + for(size_t i = 0; i != bound; ++i) + { + word borrow = bigint_sub3(ws.data(), data(), sz, mod.data(), mod_words); + + CT::Mask::is_zero(borrow).select_n(mutable_data(), ws.data(), data(), sz); + } + } + +/* +* Return the absolute value of this number +*/ +BigInt BigInt::abs() const + { + BigInt x = (*this); + x.set_sign(Positive); + return x; + } + +void BigInt::binary_encode(uint8_t buf[]) const + { + this->binary_encode(buf, bytes()); + } + +/* +* Encode this number into bytes +*/ +void BigInt::binary_encode(uint8_t output[], size_t len) const + { + const size_t full_words = len / sizeof(word); + const size_t extra_bytes = len % sizeof(word); + + for(size_t i = 0; i != full_words; ++i) + { + const word w = word_at(i); + store_be(w, output + (len - (i+1)*sizeof(word))); + } + + if(extra_bytes > 0) + { + const word w = word_at(full_words); + + for(size_t i = 0; i != extra_bytes; ++i) + { + output[extra_bytes - i - 1] = get_byte(sizeof(word) - i - 1, w); + } + } + } + +/* +* Set this number to the value in buf +*/ +void BigInt::binary_decode(const uint8_t buf[], size_t length) + { + clear(); + + const size_t full_words = length / sizeof(word); + const size_t extra_bytes = length % sizeof(word); + + secure_vector reg((round_up(full_words + (extra_bytes > 0 ? 1 : 0), 8))); + + for(size_t i = 0; i != full_words; ++i) + { + reg[i] = load_be(buf + length - sizeof(word)*(i+1), 0); + } + + if(extra_bytes > 0) + { + for(size_t i = 0; i != extra_bytes; ++i) + reg[full_words] = (reg[full_words] << 8) | buf[i]; + } + + m_data.swap(reg); + } + +void BigInt::ct_cond_add(bool predicate, const BigInt& value) + { + if(this->is_negative() || value.is_negative()) + throw Invalid_Argument("BigInt::ct_cond_add requires both values to be positive"); + this->grow_to(1 + value.sig_words()); + + bigint_cnd_add(static_cast(predicate), + this->mutable_data(), this->size(), + value.data(), value.sig_words()); + } + +void BigInt::ct_cond_swap(bool predicate, BigInt& other) + { + const size_t max_words = std::max(size(), other.size()); + grow_to(max_words); + other.grow_to(max_words); + + bigint_cnd_swap(predicate, this->mutable_data(), other.mutable_data(), max_words); + } + +void BigInt::cond_flip_sign(bool predicate) + { + // This code is assuming Negative == 0, Positive == 1 + + const auto mask = CT::Mask::expand(predicate); + + const uint8_t current_sign = static_cast(sign()); + + const uint8_t new_sign = mask.select(current_sign ^ 1, current_sign); + + set_sign(static_cast(new_sign)); + } + +void BigInt::ct_cond_assign(bool predicate, const BigInt& other) + { + const size_t t_words = size(); + const size_t o_words = other.size(); + + if(o_words < t_words) + grow_to(o_words); + + const size_t r_words = std::max(t_words, o_words); + + const auto mask = CT::Mask::expand(predicate); + + for(size_t i = 0; i != r_words; ++i) + { + const word o_word = other.word_at(i); + const word t_word = this->word_at(i); + this->set_word_at(i, mask.select(o_word, t_word)); + } + + const bool different_sign = sign() != other.sign(); + cond_flip_sign(predicate && different_sign); + } + +#if defined(BOTAN_HAS_VALGRIND) +void BigInt::const_time_poison() const + { + CT::poison(m_data.const_data(), m_data.size()); + } + +void BigInt::const_time_unpoison() const + { + CT::unpoison(m_data.const_data(), m_data.size()); + } +#endif + +void BigInt::const_time_lookup(secure_vector& output, + const std::vector& vec, + size_t idx) + { + const size_t words = output.size(); + + clear_mem(output.data(), output.size()); + + CT::poison(&idx, sizeof(idx)); + + for(size_t i = 0; i != vec.size(); ++i) + { + BOTAN_ASSERT(vec[i].size() >= words, + "Word size as expected in const_time_lookup"); + + const auto mask = CT::Mask::is_equal(i, idx); + + for(size_t w = 0; w != words; ++w) + { + const word viw = vec[i].word_at(w); + output[w] = mask.if_set_return(viw); + } + } + + CT::unpoison(idx); + CT::unpoison(output.data(), output.size()); + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/bigint.h b/comm/third_party/botan/src/lib/math/bigint/bigint.h new file mode 100644 index 0000000000..33e79d0122 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/bigint.h @@ -0,0 +1,1153 @@ +/* +* BigInt +* (C) 1999-2008,2012,2018 Jack Lloyd +* 2007 FlexSecure +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BIGINT_H_ +#define BOTAN_BIGINT_H_ + +#include +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Arbitrary precision integer +*/ +class BOTAN_PUBLIC_API(2,0) BigInt final + { + public: + /** + * Base enumerator for encoding and decoding + */ + enum Base { Decimal = 10, Hexadecimal = 16, Binary = 256 }; + + /** + * Sign symbol definitions for positive and negative numbers + */ + enum Sign { Negative = 0, Positive = 1 }; + + /** + * DivideByZero Exception + * + * In a future release this exception will be removed and its usage + * replaced by Invalid_Argument + */ + class BOTAN_PUBLIC_API(2,0) DivideByZero final : public Invalid_Argument + { + public: + DivideByZero() : Invalid_Argument("BigInt divide by zero") {} + }; + + /** + * Create empty BigInt + */ + BigInt() = default; + + /** + * Create BigInt from 64 bit integer + * @param n initial value of this BigInt + */ + BigInt(uint64_t n); + + /** + * Copy Constructor + * @param other the BigInt to copy + */ + BigInt(const BigInt& other) = default; + + /** + * Create BigInt from a string. If the string starts with 0x the + * rest of the string will be interpreted as hexadecimal digits. + * Otherwise, it will be interpreted as a decimal number. + * + * @param str the string to parse for an integer value + */ + explicit BigInt(const std::string& str); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + */ + BigInt(const uint8_t buf[], size_t length); + + /** + * Create a BigInt from an integer in a byte array + * @param vec the byte vector holding the value + */ + template + explicit BigInt(const std::vector& vec) : BigInt(vec.data(), vec.size()) {} + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + * @param base is the number base of the integer in buf + */ + BigInt(const uint8_t buf[], size_t length, Base base); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + * @param max_bits if the resulting integer is more than max_bits, + * it will be shifted so it is at most max_bits in length. + */ + BigInt(const uint8_t buf[], size_t length, size_t max_bits); + + /** + * Create a BigInt from an array of words + * @param words the words + * @param length number of words + */ + BigInt(const word words[], size_t length); + + /** + * \brief Create a random BigInt of the specified size + * + * @param rng random number generator + * @param bits size in bits + * @param set_high_bit if true, the highest bit is always set + * + * @see randomize + */ + BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit = true); + + /** + * Create BigInt of specified size, all zeros + * @param sign the sign + * @param n size of the internal register in words + */ + BigInt(Sign sign, size_t n); + + /** + * Move constructor + */ + BigInt(BigInt&& other) + { + this->swap(other); + } + + ~BigInt() { const_time_unpoison(); } + + /** + * Move assignment + */ + BigInt& operator=(BigInt&& other) + { + if(this != &other) + this->swap(other); + + return (*this); + } + + /** + * Copy assignment + */ + BigInt& operator=(const BigInt&) = default; + + /** + * Swap this value with another + * @param other BigInt to swap values with + */ + void swap(BigInt& other) + { + m_data.swap(other.m_data); + std::swap(m_signedness, other.m_signedness); + } + + void swap_reg(secure_vector& reg) + { + m_data.swap(reg); + // sign left unchanged + } + + /** + * += operator + * @param y the BigInt to add to this + */ + BigInt& operator+=(const BigInt& y) + { + return add(y.data(), y.sig_words(), y.sign()); + } + + /** + * += operator + * @param y the word to add to this + */ + BigInt& operator+=(word y) + { + return add(&y, 1, Positive); + } + + /** + * -= operator + * @param y the BigInt to subtract from this + */ + BigInt& operator-=(const BigInt& y) + { + return sub(y.data(), y.sig_words(), y.sign()); + } + + /** + * -= operator + * @param y the word to subtract from this + */ + BigInt& operator-=(word y) + { + return sub(&y, 1, Positive); + } + + /** + * *= operator + * @param y the BigInt to multiply with this + */ + BigInt& operator*=(const BigInt& y); + + /** + * *= operator + * @param y the word to multiply with this + */ + BigInt& operator*=(word y); + + /** + * /= operator + * @param y the BigInt to divide this by + */ + BigInt& operator/=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus to reduce this by + */ + BigInt& operator%=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus (word) to reduce this by + */ + word operator%=(word y); + + /** + * Left shift operator + * @param shift the number of bits to shift this left by + */ + BigInt& operator<<=(size_t shift); + + /** + * Right shift operator + * @param shift the number of bits to shift this right by + */ + BigInt& operator>>=(size_t shift); + + /** + * Increment operator + */ + BigInt& operator++() { return (*this += 1); } + + /** + * Decrement operator + */ + BigInt& operator--() { return (*this -= 1); } + + /** + * Postfix increment operator + */ + BigInt operator++(int) { BigInt x = (*this); ++(*this); return x; } + + /** + * Postfix decrement operator + */ + BigInt operator--(int) { BigInt x = (*this); --(*this); return x; } + + /** + * Unary negation operator + * @return negative this + */ + BigInt operator-() const; + + /** + * ! operator + * @return true iff this is zero, otherwise false + */ + bool operator !() const { return (!is_nonzero()); } + + static BigInt add2(const BigInt& x, const word y[], size_t y_words, Sign y_sign); + + BigInt& add(const word y[], size_t y_words, Sign sign); + + BigInt& sub(const word y[], size_t y_words, Sign sign) + { + return add(y, y_words, sign == Positive ? Negative : Positive); + } + + /** + * Multiply this with y + * @param y the BigInt to multiply with this + * @param ws a temp workspace + */ + BigInt& mul(const BigInt& y, secure_vector& ws); + + /** + * Square value of *this + * @param ws a temp workspace + */ + BigInt& square(secure_vector& ws); + + /** + * Set *this to y - *this + * @param y the BigInt to subtract from as a sequence of words + * @param y_words length of y in words + * @param ws a temp workspace + */ + BigInt& rev_sub(const word y[], size_t y_words, secure_vector& ws); + + /** + * Set *this to (*this + y) % mod + * This function assumes *this is >= 0 && < mod + * @param y the BigInt to add - assumed y >= 0 and y < mod + * @param mod the positive modulus + * @param ws a temp workspace + */ + BigInt& mod_add(const BigInt& y, const BigInt& mod, secure_vector& ws); + + /** + * Set *this to (*this - y) % mod + * This function assumes *this is >= 0 && < mod + * @param y the BigInt to subtract - assumed y >= 0 and y < mod + * @param mod the positive modulus + * @param ws a temp workspace + */ + BigInt& mod_sub(const BigInt& y, const BigInt& mod, secure_vector& ws); + + /** + * Set *this to (*this * y) % mod + * This function assumes *this is >= 0 && < mod + * y should be small, less than 16 + * @param y the small integer to multiply by + * @param mod the positive modulus + * @param ws a temp workspace + */ + BigInt& mod_mul(uint8_t y, const BigInt& mod, secure_vector& ws); + + /** + * Return *this % mod + * + * Assumes that *this is (if anything) only slightly larger than + * mod and performs repeated subtractions. It should not be used if + * *this is much larger than mod, instead use modulo operator. + */ + size_t reduce_below(const BigInt& mod, secure_vector &ws); + + /** + * Return *this % mod + * + * Assumes that *this is (if anything) only slightly larger than mod and + * performs repeated subtractions. It should not be used if *this is much + * larger than mod, instead use modulo operator. + * + * Performs exactly bound subtractions, so if *this is >= bound*mod then the + * result will not be fully reduced. If bound is zero, nothing happens. + */ + void ct_reduce_below(const BigInt& mod, secure_vector &ws, size_t bound); + + /** + * Zeroize the BigInt. The size of the underlying register is not + * modified. + */ + void clear() { m_data.set_to_zero(); m_signedness = Positive; } + + /** + * Compare this to another BigInt + * @param n the BigInt value to compare with + * @param check_signs include sign in comparison? + * @result if (thisn) return 1, if both + * values are identical return 0 [like Perl's <=> operator] + */ + int32_t cmp(const BigInt& n, bool check_signs = true) const; + + /** + * Compare this to another BigInt + * @param n the BigInt value to compare with + * @result true if this == n or false otherwise + */ + bool is_equal(const BigInt& n) const; + + /** + * Compare this to another BigInt + * @param n the BigInt value to compare with + * @result true if this < n or false otherwise + */ + bool is_less_than(const BigInt& n) const; + + /** + * Compare this to an integer + * @param n the value to compare with + * @result if (thisn) return 1, if both + * values are identical return 0 [like Perl's <=> operator] + */ + int32_t cmp_word(word n) const; + + /** + * Test if the integer has an even value + * @result true if the integer is even, false otherwise + */ + bool is_even() const { return (get_bit(0) == 0); } + + /** + * Test if the integer has an odd value + * @result true if the integer is odd, false otherwise + */ + bool is_odd() const { return (get_bit(0) == 1); } + + /** + * Test if the integer is not zero + * @result true if the integer is non-zero, false otherwise + */ + bool is_nonzero() const { return (!is_zero()); } + + /** + * Test if the integer is zero + * @result true if the integer is zero, false otherwise + */ + bool is_zero() const + { + return (sig_words() == 0); + } + + /** + * Set bit at specified position + * @param n bit position to set + */ + void set_bit(size_t n) + { + conditionally_set_bit(n, true); + } + + /** + * Conditionally set bit at specified position. Note if set_it is + * false, nothing happens, and if the bit is already set, it + * remains set. + * + * @param n bit position to set + * @param set_it if the bit should be set + */ + void conditionally_set_bit(size_t n, bool set_it); + + /** + * Clear bit at specified position + * @param n bit position to clear + */ + void clear_bit(size_t n); + + /** + * Clear all but the lowest n bits + * @param n amount of bits to keep + */ + void mask_bits(size_t n) + { + m_data.mask_bits(n); + } + + /** + * Return bit value at specified position + * @param n the bit offset to test + * @result true, if the bit at position n is set, false otherwise + */ + bool get_bit(size_t n) const + { + return ((word_at(n / BOTAN_MP_WORD_BITS) >> (n % BOTAN_MP_WORD_BITS)) & 1); + } + + /** + * Return (a maximum of) 32 bits of the complete value + * @param offset the offset to start extracting + * @param length amount of bits to extract (starting at offset) + * @result the integer extracted from the register starting at + * offset with specified length + */ + uint32_t get_substring(size_t offset, size_t length) const; + + /** + * Convert this value into a uint32_t, if it is in the range + * [0 ... 2**32-1], or otherwise throw an exception. + * @result the value as a uint32_t if conversion is possible + */ + uint32_t to_u32bit() const; + + /** + * Convert this value to a decimal string. + * Warning: decimal conversions are relatively slow + */ + std::string to_dec_string() const; + + /** + * Convert this value to a hexadecimal string. + */ + std::string to_hex_string() const; + + /** + * @param n the offset to get a byte from + * @result byte at offset n + */ + uint8_t byte_at(size_t n) const; + + /** + * Return the word at a specified position of the internal register + * @param n position in the register + * @return value at position n + */ + word word_at(size_t n) const + { + return m_data.get_word_at(n); + } + + void set_word_at(size_t i, word w) + { + m_data.set_word_at(i, w); + } + + void set_words(const word w[], size_t len) + { + m_data.set_words(w, len); + } + + /** + * Tests if the sign of the integer is negative + * @result true, iff the integer has a negative sign + */ + bool is_negative() const { return (sign() == Negative); } + + /** + * Tests if the sign of the integer is positive + * @result true, iff the integer has a positive sign + */ + bool is_positive() const { return (sign() == Positive); } + + /** + * Return the sign of the integer + * @result the sign of the integer + */ + Sign sign() const { return (m_signedness); } + + /** + * @result the opposite sign of the represented integer value + */ + Sign reverse_sign() const + { + if(sign() == Positive) + return Negative; + return Positive; + } + + /** + * Flip the sign of this BigInt + */ + void flip_sign() + { + set_sign(reverse_sign()); + } + + /** + * Set sign of the integer + * @param sign new Sign to set + */ + void set_sign(Sign sign) + { + if(sign == Negative && is_zero()) + sign = Positive; + + m_signedness = sign; + } + + /** + * @result absolute (positive) value of this + */ + BigInt abs() const; + + /** + * Give size of internal register + * @result size of internal register in words + */ + size_t size() const { return m_data.size(); } + + /** + * Return how many words we need to hold this value + * @result significant words of the represented integer value + */ + size_t sig_words() const + { + return m_data.sig_words(); + } + + /** + * Give byte length of the integer + * @result byte length of the represented integer value + */ + size_t bytes() const; + + /** + * Get the bit length of the integer + * @result bit length of the represented integer value + */ + size_t bits() const; + + /** + * Get the number of high bits unset in the top (allocated) word + * of this integer. Returns BOTAN_MP_WORD_BITS only iff *this is + * zero. Ignores sign. + */ + size_t top_bits_free() const; + + /** + * Return a mutable pointer to the register + * @result a pointer to the start of the internal register + */ + word* mutable_data() { return m_data.mutable_data(); } + + /** + * Return a const pointer to the register + * @result a pointer to the start of the internal register + */ + const word* data() const { return m_data.const_data(); } + + /** + * Don't use this function in application code + */ + secure_vector& get_word_vector() { return m_data.mutable_vector(); } + + /** + * Don't use this function in application code + */ + const secure_vector& get_word_vector() const { return m_data.const_vector(); } + + /** + * Increase internal register buffer to at least n words + * @param n new size of register + */ + void grow_to(size_t n) const { m_data.grow_to(n); } + + /** + * Resize the vector to the minimum word size to hold the integer, or + * min_size words, whichever is larger + */ + void BOTAN_DEPRECATED("Use resize if required") shrink_to_fit(size_t min_size = 0) + { + m_data.shrink_to_fit(min_size); + } + + void resize(size_t s) { m_data.resize(s); } + + /** + * Fill BigInt with a random number with size of bitsize + * + * If \p set_high_bit is true, the highest bit will be set, which causes + * the entropy to be \a bits-1. Otherwise the highest bit is randomly chosen + * by the rng, causing the entropy to be \a bits. + * + * @param rng the random number generator to use + * @param bitsize number of bits the created random value should have + * @param set_high_bit if true, the highest bit is always set + */ + void randomize(RandomNumberGenerator& rng, size_t bitsize, bool set_high_bit = true); + + /** + * Store BigInt-value in a given byte array + * @param buf destination byte array for the integer value + */ + void binary_encode(uint8_t buf[]) const; + + /** + * Store BigInt-value in a given byte array. If len is less than + * the size of the value, then it will be truncated. If len is + * greater than the size of the value, it will be zero-padded. + * If len exactly equals this->bytes(), this function behaves identically + * to binary_encode. + * + * @param buf destination byte array for the integer value + * @param len how many bytes to write + */ + void binary_encode(uint8_t buf[], size_t len) const; + + /** + * Read integer value from a byte array with given size + * @param buf byte array buffer containing the integer + * @param length size of buf + */ + void binary_decode(const uint8_t buf[], size_t length); + + /** + * Read integer value from a byte vector + * @param buf the vector to load from + */ + template + void binary_decode(const std::vector& buf) + { + binary_decode(buf.data(), buf.size()); + } + + /** + * @param base the base to measure the size for + * @return size of this integer in base base + * + * Deprecated. This is only needed when using the `encode` and + * `encode_locked` functions, which are also deprecated. + */ + BOTAN_DEPRECATED("See comments on declaration") + size_t encoded_size(Base base = Binary) const; + + /** + * Place the value into out, zero-padding up to size words + * Throw if *this cannot be represented in size words + */ + void encode_words(word out[], size_t size) const; + + /** + * If predicate is true assign other to *this + * Uses a masked operation to avoid side channels + */ + void ct_cond_assign(bool predicate, const BigInt& other); + + /** + * If predicate is true swap *this and other + * Uses a masked operation to avoid side channels + */ + void ct_cond_swap(bool predicate, BigInt& other); + + /** + * If predicate is true add value to *this + */ + void ct_cond_add(bool predicate, const BigInt& value); + + /** + * If predicate is true flip the sign of *this + */ + void cond_flip_sign(bool predicate); + +#if defined(BOTAN_HAS_VALGRIND) + void const_time_poison() const; + void const_time_unpoison() const; +#else + void const_time_poison() const {} + void const_time_unpoison() const {} +#endif + + /** + * @param rng a random number generator + * @param min the minimum value (must be non-negative) + * @param max the maximum value (must be non-negative and > min) + * @return random integer in [min,max) + */ + static BigInt random_integer(RandomNumberGenerator& rng, + const BigInt& min, + const BigInt& max); + + /** + * Create a power of two + * @param n the power of two to create + * @return bigint representing 2^n + */ + static BigInt power_of_2(size_t n) + { + BigInt b; + b.set_bit(n); + return b; + } + + /** + * Encode the integer value from a BigInt to a std::vector of bytes + * @param n the BigInt to use as integer source + * @result secure_vector of bytes containing the bytes of the integer + */ + static std::vector encode(const BigInt& n) + { + std::vector output(n.bytes()); + n.binary_encode(output.data()); + return output; + } + + /** + * Encode the integer value from a BigInt to a secure_vector of bytes + * @param n the BigInt to use as integer source + * @result secure_vector of bytes containing the bytes of the integer + */ + static secure_vector encode_locked(const BigInt& n) + { + secure_vector output(n.bytes()); + n.binary_encode(output.data()); + return output; + } + + /** + * Encode the integer value from a BigInt to a byte array + * @param buf destination byte array for the encoded integer + * @param n the BigInt to use as integer source + */ + static BOTAN_DEPRECATED("Use n.binary_encode") void encode(uint8_t buf[], const BigInt& n) + { + n.binary_encode(buf); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param length size of buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const uint8_t buf[], size_t length) + { + return BigInt(buf, length); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @result BigInt representing the integer in the byte array + */ + template + static BigInt decode(const std::vector& buf) + { + return BigInt(buf); + } + + /** + * Encode the integer value from a BigInt to a std::vector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result secure_vector of bytes containing the integer with given base + * + * Deprecated. If you need Binary, call the version of encode that doesn't + * take a Base. If you need Hex or Decimal output, use to_hex_string or + * to_dec_string resp. + */ + BOTAN_DEPRECATED("See comments on declaration") + static std::vector encode(const BigInt& n, Base base); + + /** + * Encode the integer value from a BigInt to a secure_vector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result secure_vector of bytes containing the integer with given base + * + * Deprecated. If you need Binary, call the version of encode_locked that + * doesn't take a Base. If you need Hex or Decimal output, use to_hex_string + * or to_dec_string resp. + */ + BOTAN_DEPRECATED("See comments on declaration") + static secure_vector encode_locked(const BigInt& n, + Base base); + + /** + * Encode the integer value from a BigInt to a byte array + * @param buf destination byte array for the encoded integer + * value with given base + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * + * Deprecated. If you need Binary, call binary_encode. If you need + * Hex or Decimal output, use to_hex_string or to_dec_string resp. + */ + BOTAN_DEPRECATED("See comments on declaration") + static void encode(uint8_t buf[], const BigInt& n, Base base); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param length size of buf + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const uint8_t buf[], size_t length, + Base base); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + template + static BigInt decode(const std::vector& buf, Base base) + { + if(base == Binary) + return BigInt(buf); + return BigInt::decode(buf.data(), buf.size(), base); + } + + /** + * Encode a BigInt to a byte array according to IEEE 1363 + * @param n the BigInt to encode + * @param bytes the length of the resulting secure_vector + * @result a secure_vector containing the encoded BigInt + */ + static secure_vector encode_1363(const BigInt& n, size_t bytes); + + static void encode_1363(uint8_t out[], size_t bytes, const BigInt& n); + + /** + * Encode two BigInt to a byte array according to IEEE 1363 + * @param n1 the first BigInt to encode + * @param n2 the second BigInt to encode + * @param bytes the length of the encoding of each single BigInt + * @result a secure_vector containing the concatenation of the two encoded BigInt + */ + static secure_vector encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes); + + /** + * Set output = vec[idx].m_reg in constant time + * + * All elements of vec must have the same size, and output must be + * pre-allocated with the same size. + */ + static void BOTAN_DEPRECATED("No longer in use") const_time_lookup( + secure_vector& output, + const std::vector& vec, + size_t idx); + + private: + + class Data + { + public: + word* mutable_data() + { + invalidate_sig_words(); + return m_reg.data(); + } + + const word* const_data() const + { + return m_reg.data(); + } + + secure_vector& mutable_vector() + { + invalidate_sig_words(); + return m_reg; + } + + const secure_vector& const_vector() const + { + return m_reg; + } + + word get_word_at(size_t n) const + { + if(n < m_reg.size()) + return m_reg[n]; + return 0; + } + + void set_word_at(size_t i, word w) + { + invalidate_sig_words(); + if(i >= m_reg.size()) + { + if(w == 0) + return; + grow_to(i + 1); + } + m_reg[i] = w; + } + + void set_words(const word w[], size_t len) + { + invalidate_sig_words(); + m_reg.assign(w, w + len); + } + + void set_to_zero() + { + m_reg.resize(m_reg.capacity()); + clear_mem(m_reg.data(), m_reg.size()); + m_sig_words = 0; + } + + void set_size(size_t s) + { + invalidate_sig_words(); + clear_mem(m_reg.data(), m_reg.size()); + m_reg.resize(s + (8 - (s % 8))); + } + + void mask_bits(size_t n) + { + if(n == 0) { return set_to_zero(); } + + const size_t top_word = n / BOTAN_MP_WORD_BITS; + + // if(top_word < sig_words()) ? + if(top_word < size()) + { + const word mask = (static_cast(1) << (n % BOTAN_MP_WORD_BITS)) - 1; + const size_t len = size() - (top_word + 1); + if(len > 0) + { + clear_mem(&m_reg[top_word+1], len); + } + m_reg[top_word] &= mask; + invalidate_sig_words(); + } + } + + void grow_to(size_t n) const + { + if(n > size()) + { + if(n <= m_reg.capacity()) + m_reg.resize(n); + else + m_reg.resize(n + (8 - (n % 8))); + } + } + + size_t size() const { return m_reg.size(); } + + void shrink_to_fit(size_t min_size = 0) + { + const size_t words = std::max(min_size, sig_words()); + m_reg.resize(words); + } + + void resize(size_t s) + { + m_reg.resize(s); + } + + void swap(Data& other) + { + m_reg.swap(other.m_reg); + std::swap(m_sig_words, other.m_sig_words); + } + + void swap(secure_vector& reg) + { + m_reg.swap(reg); + invalidate_sig_words(); + } + + void invalidate_sig_words() const + { + m_sig_words = sig_words_npos; + } + + size_t sig_words() const + { + if(m_sig_words == sig_words_npos) + { + m_sig_words = calc_sig_words(); + } + else + { + BOTAN_DEBUG_ASSERT(m_sig_words == calc_sig_words()); + } + return m_sig_words; + } + private: + static const size_t sig_words_npos = static_cast(-1); + + size_t calc_sig_words() const; + + mutable secure_vector m_reg; + mutable size_t m_sig_words = sig_words_npos; + }; + + Data m_data; + Sign m_signedness = Positive; + }; + +/* +* Arithmetic Operators +*/ +inline BigInt operator+(const BigInt& x, const BigInt& y) + { + return BigInt::add2(x, y.data(), y.sig_words(), y.sign()); + } + +inline BigInt operator+(const BigInt& x, word y) + { + return BigInt::add2(x, &y, 1, BigInt::Positive); + } + +inline BigInt operator+(word x, const BigInt& y) + { + return y + x; + } + +inline BigInt operator-(const BigInt& x, const BigInt& y) + { + return BigInt::add2(x, y.data(), y.sig_words(), y.reverse_sign()); + } + +inline BigInt operator-(const BigInt& x, word y) + { + return BigInt::add2(x, &y, 1, BigInt::Negative); + } + +BigInt BOTAN_PUBLIC_API(2,0) operator*(const BigInt& x, const BigInt& y); +BigInt BOTAN_PUBLIC_API(2,8) operator*(const BigInt& x, word y); +inline BigInt operator*(word x, const BigInt& y) { return y*x; } + +BigInt BOTAN_PUBLIC_API(2,0) operator/(const BigInt& x, const BigInt& d); +BigInt BOTAN_PUBLIC_API(2,0) operator/(const BigInt& x, word m); +BigInt BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, const BigInt& m); +word BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, word m); +BigInt BOTAN_PUBLIC_API(2,0) operator<<(const BigInt& x, size_t n); +BigInt BOTAN_PUBLIC_API(2,0) operator>>(const BigInt& x, size_t n); + +/* +* Comparison Operators +*/ +inline bool operator==(const BigInt& a, const BigInt& b) + { return a.is_equal(b); } +inline bool operator!=(const BigInt& a, const BigInt& b) + { return !a.is_equal(b); } +inline bool operator<=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) <= 0); } +inline bool operator>=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) >= 0); } +inline bool operator<(const BigInt& a, const BigInt& b) + { return a.is_less_than(b); } +inline bool operator>(const BigInt& a, const BigInt& b) + { return b.is_less_than(a); } + +inline bool operator==(const BigInt& a, word b) + { return (a.cmp_word(b) == 0); } +inline bool operator!=(const BigInt& a, word b) + { return (a.cmp_word(b) != 0); } +inline bool operator<=(const BigInt& a, word b) + { return (a.cmp_word(b) <= 0); } +inline bool operator>=(const BigInt& a, word b) + { return (a.cmp_word(b) >= 0); } +inline bool operator<(const BigInt& a, word b) + { return (a.cmp_word(b) < 0); } +inline bool operator>(const BigInt& a, word b) + { return (a.cmp_word(b) > 0); } + +/* +* I/O Operators +*/ +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream&, const BigInt&); +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream&, BigInt&); + +} + +namespace std { + +template<> +inline void swap(Botan::BigInt& x, Botan::BigInt& y) + { + x.swap(y); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/bigint/divide.cpp b/comm/third_party/botan/src/lib/math/bigint/divide.cpp new file mode 100644 index 0000000000..0b23e2489e --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/divide.cpp @@ -0,0 +1,236 @@ +/* +* Division Algorithm +* (C) 1999-2007,2012,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Handle signed operands, if necessary +*/ +void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) + { + q.cond_flip_sign(x.sign() != y.sign()); + + if(x.is_negative() && r.is_nonzero()) + { + q -= 1; + r = y.abs() - r; + } + } + +inline bool division_check(word q, word y2, word y1, + word x3, word x2, word x1) + { + /* + Compute (y3,y2,y1) = (y2,y1) * q + and return true if (y3,y2,y1) > (x3,x2,x1) + */ + + word y3 = 0; + y1 = word_madd2(q, y1, &y3); + y2 = word_madd2(q, y2, &y3); + + const word x[3] = { x1, x2, x3 }; + const word y[3] = { y1, y2, y3 }; + + return bigint_ct_is_lt(x, 3, y, 3).is_set(); + } + +} + +void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out) + { + const size_t x_words = x.sig_words(); + const size_t y_words = y.sig_words(); + + const size_t x_bits = x.bits(); + + BigInt q(BigInt::Positive, x_words); + BigInt r(BigInt::Positive, y_words); + BigInt t(BigInt::Positive, y_words); // a temporary + + for(size_t i = 0; i != x_bits; ++i) + { + const size_t b = x_bits - 1 - i; + const bool x_b = x.get_bit(b); + + r *= 2; + r.conditionally_set_bit(0, x_b); + + const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0; + + q.conditionally_set_bit(b, r_gte_y); + r.ct_cond_swap(r_gte_y, t); + } + + sign_fixup(x, y, q, r); + r_out = r; + q_out = q; + } + +void ct_divide_u8(const BigInt& x, uint8_t y, BigInt& q_out, uint8_t& r_out) + { + const size_t x_words = x.sig_words(); + const size_t x_bits = x.bits(); + + BigInt q(BigInt::Positive, x_words); + uint32_t r = 0; + + for(size_t i = 0; i != x_bits; ++i) + { + const size_t b = x_bits - 1 - i; + const bool x_b = x.get_bit(b); + + r *= 2; + r += x_b; + + const auto r_gte_y = CT::Mask::is_gte(r, y); + + q.conditionally_set_bit(b, r_gte_y.is_set()); + r = r_gte_y.select(r - y, r); + } + + if(x.is_negative()) + { + q.flip_sign(); + if(r != 0) + { + --q; + r = y - r; + } + } + + r_out = static_cast(r); + q_out = q; + } + +BigInt ct_modulo(const BigInt& x, const BigInt& y) + { + if(y.is_negative() || y.is_zero()) + throw Invalid_Argument("ct_modulo requires y > 0"); + + const size_t y_words = y.sig_words(); + + const size_t x_bits = x.bits(); + + BigInt r(BigInt::Positive, y_words); + BigInt t(BigInt::Positive, y_words); + + for(size_t i = 0; i != x_bits; ++i) + { + const size_t b = x_bits - 1 - i; + const bool x_b = x.get_bit(b); + + r *= 2; + r.conditionally_set_bit(0, x_b); + + const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0; + + r.ct_cond_swap(r_gte_y, t); + } + + if(x.is_negative()) + { + if(r.is_nonzero()) + { + r = y - r; + } + } + + return r; + } + +/* +* Solve x = q * y + r +* +* See Handbook of Applied Cryptography section 14.2.5 +*/ +void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out) + { + if(y_arg.is_zero()) + throw BigInt::DivideByZero(); + + const size_t y_words = y_arg.sig_words(); + + BOTAN_ASSERT_NOMSG(y_words > 0); + + BigInt y = y_arg; + + BigInt r = x; + BigInt q = 0; + secure_vector ws; + + r.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + + // Calculate shifts needed to normalize y with high bit set + const size_t shifts = y.top_bits_free(); + + y <<= shifts; + r <<= shifts; + + // we know y has not changed size, since we only shifted up to set high bit + const size_t t = y_words - 1; + const size_t n = std::max(y_words, r.sig_words()) - 1; // r may have changed size however + + BOTAN_ASSERT_NOMSG(n >= t); + + q.grow_to(n - t + 1); + + word* q_words = q.mutable_data(); + + BigInt shifted_y = y << (BOTAN_MP_WORD_BITS * (n-t)); + + // Set q_{n-t} to number of times r > shifted_y + q_words[n-t] = r.reduce_below(shifted_y, ws); + + const word y_t0 = y.word_at(t); + const word y_t1 = y.word_at(t-1); + BOTAN_DEBUG_ASSERT((y_t0 >> (BOTAN_MP_WORD_BITS-1)) == 1); + + for(size_t j = n; j != t; --j) + { + const word x_j0 = r.word_at(j); + const word x_j1 = r.word_at(j-1); + const word x_j2 = r.word_at(j-2); + + word qjt = bigint_divop(x_j0, x_j1, y_t0); + + qjt = CT::Mask::is_equal(x_j0, y_t0).select(MP_WORD_MAX, qjt); + + // Per HAC 14.23, this operation is required at most twice + qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2); + qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2); + BOTAN_DEBUG_ASSERT(division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2) == false); + + shifted_y >>= BOTAN_MP_WORD_BITS; + // Now shifted_y == y << (BOTAN_MP_WORD_BITS * (j-t-1)) + + // TODO this sequence could be better + r -= qjt * shifted_y; + qjt -= r.is_negative(); + r += static_cast(r.is_negative()) * shifted_y; + + q_words[j-t-1] = qjt; + } + + r >>= shifts; + + sign_fixup(x, y_arg, q, r); + + r_out = r; + q_out = q; + } + +} diff --git a/comm/third_party/botan/src/lib/math/bigint/divide.h b/comm/third_party/botan/src/lib/math/bigint/divide.h new file mode 100644 index 0000000000..47141b3e7f --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/divide.h @@ -0,0 +1,101 @@ +/* +* Division +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DIVISON_ALGORITHM_H_ +#define BOTAN_DIVISON_ALGORITHM_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(divide.h) + +namespace Botan { + +/** +* BigInt Division +* @param x an integer +* @param y a non-zero integer +* @param q will be set to x / y +* @param r will be set to x % y +*/ +void BOTAN_UNSTABLE_API vartime_divide(const BigInt& x, + const BigInt& y, + BigInt& q, + BigInt& r); + +/** +* BigInt division, const time variant +* +* This runs with control flow independent of the values of x/y. +* Warning: the loop bounds still leak the sizes of x and y. +* +* @param x an integer +* @param y a non-zero integer +* @param q will be set to x / y +* @param r will be set to x % y +*/ +void BOTAN_PUBLIC_API(2,9) ct_divide(const BigInt& x, + const BigInt& y, + BigInt& q, + BigInt& r); + +inline void divide(const BigInt& x, + const BigInt& y, + BigInt& q, + BigInt& r) + { + ct_divide(x, y, q, r); + } + +/** +* BigInt division, const time variant +* +* This runs with control flow independent of the values of x/y. +* Warning: the loop bounds still leak the sizes of x and y. +* +* @param x an integer +* @param y a non-zero integer +* @return x/y with remainder discarded +*/ +inline BigInt ct_divide(const BigInt& x, const BigInt& y) + { + BigInt q, r; + ct_divide(x, y, q, r); + return q; + } + +/** +* BigInt division, const time variant +* +* This runs with control flow independent of the values of x/y. +* Warning: the loop bounds still leak the sizes of x and y. +* +* @param x an integer +* @param y a non-zero integer +* @param q will be set to x / y +* @param r will be set to x % y +*/ +void BOTAN_PUBLIC_API(2,9) ct_divide_u8(const BigInt& x, + uint8_t y, + BigInt& q, + uint8_t& r); + +/** +* BigInt modulo, const time variant +* +* Using this function is (slightly) cheaper than calling ct_divide and +* using only the remainder. +* +* @param x a non-negative integer +* @param modulo a positive integer +* @return result x % modulo +*/ +BigInt BOTAN_PUBLIC_API(2,9) ct_modulo(const BigInt& x, + const BigInt& modulo); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/bigint/info.txt b/comm/third_party/botan/src/lib/math/bigint/info.txt new file mode 100644 index 0000000000..974366b810 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/bigint/info.txt @@ -0,0 +1,14 @@ + +BIGINT -> 20131128 + + + +bigint.h +divide.h + + + +mp +hex +rng + diff --git a/comm/third_party/botan/src/lib/math/mp/info.txt b/comm/third_party/botan/src/lib/math/mp/info.txt new file mode 100644 index 0000000000..cee4325ed8 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/info.txt @@ -0,0 +1,10 @@ + +BIGINT_MP -> 20151225 + + + +mp_core.h +mp_madd.h +mp_asmi.h +mp_monty.h + diff --git a/comm/third_party/botan/src/lib/math/mp/mp_asmi.h b/comm/third_party/botan/src/lib/math/mp/mp_asmi.h new file mode 100644 index 0000000000..e1518d51c7 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_asmi.h @@ -0,0 +1,611 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H_ +#define BOTAN_MP_ASM_INTERNAL_H_ + +#include + +namespace Botan { + +#if defined(BOTAN_MP_USE_X86_32_ASM) + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \ + ASM("movl %[carry], 4*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("addl 4*" #INDEX "(%[z]),%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX " (%[z])") + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorl %[carry]") \ + CORE_CODE \ + ASM("sbbl %[carry],%[carry]") \ + ASM("negl %[carry]") + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movq 8*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 8*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 8*" #INDEX "(%[y]), %[carry]") \ + ASM("movq %[carry], 8*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]),%%rax") \ + ASM("mulq %[y]") \ + ASM("addq %[carry],%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("movq %%rdx,%[carry]") \ + ASM("movq %%rax, 8*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]),%%rax") \ + ASM("mulq %[y]") \ + ASM("addq %[carry],%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("addq 8*" #INDEX "(%[z]),%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("movq %%rdx,%[carry]") \ + ASM("movq %%rax, 8*" #INDEX " (%[z])") + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorq %[carry]") \ + CORE_CODE \ + ASM("sbbq %[carry],%[carry]") \ + ASM("negq %[carry]") + +#endif + +#if defined(ADD_OR_SUBTRACT) + +#define ASM(x) x "\n\t" + +#define DO_8_TIMES(MACRO, ARG) \ + MACRO(ARG, 0) \ + MACRO(ARG, 1) \ + MACRO(ARG, 2) \ + MACRO(ARG, 3) \ + MACRO(ARG, 4) \ + MACRO(ARG, 5) \ + MACRO(ARG, 6) \ + MACRO(ARG, 7) + +#endif + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#else + word z = x + y; + word c1 = (z < x); + z += *carry; + *carry = c1 | (z < *carry); + return z; +#endif + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#else + x[0] = word_add(x[0], y[0], &carry); + x[1] = word_add(x[1], y[1], &carry); + x[2] = word_add(x[2], y[2], &carry); + x[3] = word_add(x[3], y[3], &carry); + x[4] = word_add(x[4], y[4], &carry); + x[5] = word_add(x[5], y[5], &carry); + x[6] = word_add(x[6], y[6], &carry); + x[7] = word_add(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], + const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#else + z[0] = word_add(x[0], y[0], &carry); + z[1] = word_add(x[1], y[1], &carry); + z[2] = word_add(x[2], y[2], &carry); + z[3] = word_add(x[3], y[3], &carry); + z[4] = word_add(x[4], y[4], &carry); + z[5] = word_add(x[5], y[5], &carry); + z[6] = word_add(x[6], y[6], &carry); + z[7] = word_add(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#else + word t0 = x - y; + word c1 = (t0 > x); + word z = t0 - *carry; + *carry = c1 | (z > t0); + return z; +#endif + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#else + x[0] = word_sub(x[0], y[0], &carry); + x[1] = word_sub(x[1], y[1], &carry); + x[2] = word_sub(x[2], y[2], &carry); + x[3] = word_sub(x[3], y[3], &carry); + x[4] = word_sub(x[4], y[4], &carry); + x[5] = word_sub(x[5], y[5], &carry); + x[6] = word_sub(x[6], y[6], &carry); + x[7] = word_sub(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + +#else + x[0] = word_sub(y[0], x[0], &carry); + x[1] = word_sub(y[1], x[1], &carry); + x[2] = word_sub(y[2], x[2], &carry); + x[3] = word_sub(y[3], x[3], &carry); + x[4] = word_sub(y[4], x[4], &carry); + x[5] = word_sub(y[5], x[5], &carry); + x[6] = word_sub(y[6], x[6], &carry); + x[7] = word_sub(y[7], x[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], + const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#else + z[0] = word_sub(x[0], y[0], &carry); + z[1] = word_sub(x[1], y[1], &carry); + z[2] = word_sub(x[2], y[2], &carry); + z[3] = word_sub(x[3], y[3], &carry); + z[4] = word_sub(x[4], y[4], &carry); + z[5] = word_sub(x[5], y[5], &carry); + z[6] = word_sub(x[6], y[6], &carry); + z[7] = word_sub(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + +#else + x[0] = word_madd2(x[0], y, &carry); + x[1] = word_madd2(x[1], y, &carry); + x[2] = word_madd2(x[2], y, &carry); + x[3] = word_madd2(x[3], y, &carry); + x[4] = word_madd2(x[4], y, &carry); + x[5] = word_madd2(x[5], y, &carry); + x[6] = word_madd2(x[6], y, &carry); + x[7] = word_madd2(x[7], y, &carry); + return carry; +#endif + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + +#else + z[0] = word_madd2(x[0], y, &carry); + z[1] = word_madd2(x[1], y, &carry); + z[2] = word_madd2(x[2], y, &carry); + z[3] = word_madd2(x[3], y, &carry); + z[4] = word_madd2(x[4], y, &carry); + z[5] = word_madd2(x[5], y, &carry); + z[6] = word_madd2(x[6], y, &carry); + z[7] = word_madd2(x[7], y, &carry); + return carry; +#endif + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + +#else + z[0] = word_madd3(x[0], y, z[0], &carry); + z[1] = word_madd3(x[1], y, z[1], &carry); + z[2] = word_madd3(x[2], y, z[2], &carry); + z[3] = word_madd3(x[3], y, z[3], &carry); + z[4] = word_madd3(x[4], y, z[4], &carry); + z[5] = word_madd3(x[5], y, z[5], &carry); + z[6] = word_madd3(x[6], y, z[6], &carry); + z[7] = word_madd3(x[7], y, z[7], &carry); + return carry; +#endif + } + +/* +* Multiply-Add Accumulator +* (w2,w1,w0) += x * y +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + word z0 = 0, z1 = 0; + + asm("mull %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm(R"( + addl %[z0],%[w0] + adcl %[z1],%[w1] + adcl $0,%[w2] + )" + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + word z0 = 0, z1 = 0; + + asm("mulq %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm(R"( + addq %[z0],%[w0] + adcq %[z1],%[w1] + adcq $0,%[w2] + )" + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#else + word carry = *w0; + *w0 = word_madd2(x, y, &carry); + *w1 += carry; + *w2 += (*w1 < carry); +#endif + } + +/* +* 3-word addition +* (w2,w1,w0) += x +*/ +inline void word3_add(word* w2, word* w1, word* w0, word x) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm(R"( + addl %[x],%[w0] + adcl $0,%[w1] + adcl $0,%[w2] + )" + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"r"(x), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm(R"( + addq %[x],%[w0] + adcq $0,%[w1] + adcq $0,%[w2] + )" + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"r"(x), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#else + *w0 += x; + word c1 = (*w0 < x); + *w1 += c1; + word c2 = (*w1 < c1); + *w2 += c2; +#endif + } + +/* +* Multiply-Add Accumulator +* (w2,w1,w0) += 2 * x * y +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + + word z0 = 0, z1 = 0; + + asm("mull %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm(R"( + addl %[z0],%[w0] + adcl %[z1],%[w1] + adcl $0,%[w2] + + addl %[z0],%[w0] + adcl %[z1],%[w1] + adcl $0,%[w2] + )" + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + word z0 = 0, z1 = 0; + + asm("mulq %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm(R"( + addq %[z0],%[w0] + adcq %[z1],%[w1] + adcq $0,%[w2] + + addq %[z0],%[w0] + adcq %[z1],%[w1] + adcq $0,%[w2] + )" + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#else + word carry = 0; + x = word_madd2(x, y, &carry); + y = carry; + + word top = (y >> (BOTAN_MP_WORD_BITS-1)); + y <<= 1; + y |= (x >> (BOTAN_MP_WORD_BITS-1)); + x <<= 1; + + carry = 0; + *w0 = word_add(*w0, x, &carry); + *w1 = word_add(*w1, y, &carry); + *w2 = word_add(*w2, top, &carry); +#endif + } + +#if defined(ASM) + #undef ASM + #undef DO_8_TIMES + #undef ADD_OR_SUBTRACT + #undef ADDSUB2_OP + #undef ADDSUB3_OP + #undef LINMUL_OP + #undef MULADD_OP +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/mp/mp_comba.cpp b/comm/third_party/botan/src/lib/math/mp/mp_comba.cpp new file mode 100644 index 0000000000..ec527224c8 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_comba.cpp @@ -0,0 +1,2211 @@ +/* +* Comba Multiplication and Squaring +* +* This file was automatically generated by ./src/scripts/comba.py on 2018-05-08 +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Comba 4x4 Squaring +*/ +void bigint_comba_sqr4(word z[8], const word x[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 4x4 Multiplication +*/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 6x6 Squaring +*/ +void bigint_comba_sqr6(word z[12], const word x[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 6x6 Multiplication +*/ +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 8x8 Squaring +*/ +void bigint_comba_sqr8(word z[16], const word x[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 8x8 Multiplication +*/ +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 9x9 Squaring +*/ +void bigint_comba_sqr9(word z[18], const word x[9]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; + z[17] = w2; + } + +/* +* Comba 9x9 Multiplication +*/ +void bigint_comba_mul9(word z[18], const word x[9], const word y[9]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + z[16] = w1; + z[17] = w2; + } + +/* +* Comba 16x16 Squaring +*/ +void bigint_comba_sqr16(word z[32], const word x[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); + word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); + z[17] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); + word3_muladd (&w2, &w1, &w0, x[ 9], x[ 9]); + z[18] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); + z[19] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); + word3_muladd (&w1, &w0, &w2, x[10], x[10]); + z[20] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); + z[21] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); + word3_muladd (&w0, &w2, &w1, x[11], x[11]); + z[22] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); + z[23] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); + word3_muladd (&w2, &w1, &w0, x[12], x[12]); + z[24] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); + z[25] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); + word3_muladd (&w1, &w0, &w2, x[13], x[13]); + z[26] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); + z[27] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); + word3_muladd (&w0, &w2, &w1, x[14], x[14]); + z[28] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); + z[29] = w2; w2 = 0; + + word3_muladd (&w2, &w1, &w0, x[15], x[15]); + z[30] = w0; + z[31] = w1; + } + +/* +* Comba 16x16 Multiplication +*/ +void bigint_comba_mul16(word z[32], const word x[16], const word y[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); + z[16] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); + z[17] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); + z[18] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); + z[19] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); + word3_muladd(&w1, &w0, &w2, x[10], y[10]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); + z[20] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); + word3_muladd(&w2, &w1, &w0, x[10], y[11]); + word3_muladd(&w2, &w1, &w0, x[11], y[10]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); + z[21] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); + word3_muladd(&w0, &w2, &w1, x[10], y[12]); + word3_muladd(&w0, &w2, &w1, x[11], y[11]); + word3_muladd(&w0, &w2, &w1, x[12], y[10]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); + z[22] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); + word3_muladd(&w1, &w0, &w2, x[10], y[13]); + word3_muladd(&w1, &w0, &w2, x[11], y[12]); + word3_muladd(&w1, &w0, &w2, x[12], y[11]); + word3_muladd(&w1, &w0, &w2, x[13], y[10]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); + z[23] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); + word3_muladd(&w2, &w1, &w0, x[10], y[14]); + word3_muladd(&w2, &w1, &w0, x[11], y[13]); + word3_muladd(&w2, &w1, &w0, x[12], y[12]); + word3_muladd(&w2, &w1, &w0, x[13], y[11]); + word3_muladd(&w2, &w1, &w0, x[14], y[10]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); + z[24] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[10], y[15]); + word3_muladd(&w0, &w2, &w1, x[11], y[14]); + word3_muladd(&w0, &w2, &w1, x[12], y[13]); + word3_muladd(&w0, &w2, &w1, x[13], y[12]); + word3_muladd(&w0, &w2, &w1, x[14], y[11]); + word3_muladd(&w0, &w2, &w1, x[15], y[10]); + z[25] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[11], y[15]); + word3_muladd(&w1, &w0, &w2, x[12], y[14]); + word3_muladd(&w1, &w0, &w2, x[13], y[13]); + word3_muladd(&w1, &w0, &w2, x[14], y[12]); + word3_muladd(&w1, &w0, &w2, x[15], y[11]); + z[26] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[12], y[15]); + word3_muladd(&w2, &w1, &w0, x[13], y[14]); + word3_muladd(&w2, &w1, &w0, x[14], y[13]); + word3_muladd(&w2, &w1, &w0, x[15], y[12]); + z[27] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[13], y[15]); + word3_muladd(&w0, &w2, &w1, x[14], y[14]); + word3_muladd(&w0, &w2, &w1, x[15], y[13]); + z[28] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[14], y[15]); + word3_muladd(&w1, &w0, &w2, x[15], y[14]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[15], y[15]); + z[30] = w0; + z[31] = w1; + } + +/* +* Comba 24x24 Squaring +*/ +void bigint_comba_sqr24(word z[48], const word x[24]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); + word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); + z[17] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); + word3_muladd (&w2, &w1, &w0, x[ 9], x[ 9]); + z[18] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); + z[19] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); + word3_muladd (&w1, &w0, &w2, x[10], x[10]); + z[20] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); + z[21] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); + word3_muladd (&w0, &w2, &w1, x[11], x[11]); + z[22] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); + z[23] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); + word3_muladd (&w2, &w1, &w0, x[12], x[12]); + z[24] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); + z[25] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); + word3_muladd (&w1, &w0, &w2, x[13], x[13]); + z[26] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); + z[27] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); + word3_muladd (&w0, &w2, &w1, x[14], x[14]); + z[28] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[13], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); + z[29] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[12], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[14], x[16]); + word3_muladd (&w2, &w1, &w0, x[15], x[15]); + z[30] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[13], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[14], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[15], x[16]); + z[31] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[13], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[14], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[15], x[17]); + word3_muladd (&w1, &w0, &w2, x[16], x[16]); + z[32] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[10], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[12], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[14], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[15], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[16], x[17]); + z[33] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[11], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[13], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[14], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[15], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[16], x[18]); + word3_muladd (&w0, &w2, &w1, x[17], x[17]); + z[34] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[12], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[13], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[14], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[15], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[16], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[17], x[18]); + z[35] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[13], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[14], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[15], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[16], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[17], x[19]); + word3_muladd (&w2, &w1, &w0, x[18], x[18]); + z[36] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[14], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[15], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[16], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[17], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[18], x[19]); + z[37] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[15], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[16], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[17], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[18], x[20]); + word3_muladd (&w1, &w0, &w2, x[19], x[19]); + z[38] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[16], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[17], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[18], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[19], x[20]); + z[39] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[17], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[18], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[19], x[21]); + word3_muladd (&w0, &w2, &w1, x[20], x[20]); + z[40] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[18], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[19], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[20], x[21]); + z[41] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[19], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[20], x[22]); + word3_muladd (&w2, &w1, &w0, x[21], x[21]); + z[42] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[20], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[21], x[22]); + z[43] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[21], x[23]); + word3_muladd (&w1, &w0, &w2, x[22], x[22]); + z[44] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[22], x[23]); + z[45] = w0; w0 = 0; + + word3_muladd (&w0, &w2, &w1, x[23], x[23]); + z[46] = w1; + z[47] = w2; + } + +/* +* Comba 24x24 Multiplication +*/ +void bigint_comba_mul24(word z[48], const word x[24], const word y[24]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[16]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 0]); + z[16] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[17]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[16]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[16], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 0]); + z[17] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[18]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[17]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[16]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[16], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[17], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 0]); + z[18] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[19]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[18]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[17]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[16]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[17], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[18], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 0]); + z[19] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[20]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[19]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[18]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[17]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[16]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); + word3_muladd(&w1, &w0, &w2, x[10], y[10]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[16], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[18], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[19], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 0]); + z[20] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[21]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[20]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[19]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[18]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[17]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[16]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); + word3_muladd(&w2, &w1, &w0, x[10], y[11]); + word3_muladd(&w2, &w1, &w0, x[11], y[10]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[16], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[17], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[19], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[20], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 0]); + z[21] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[22]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[21]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[20]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[19]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[18]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[17]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[16]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); + word3_muladd(&w0, &w2, &w1, x[10], y[12]); + word3_muladd(&w0, &w2, &w1, x[11], y[11]); + word3_muladd(&w0, &w2, &w1, x[12], y[10]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[17], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[18], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[20], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[21], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 0]); + z[22] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[23]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[22]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[21]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[20]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[19]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[18]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[17]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[16]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); + word3_muladd(&w1, &w0, &w2, x[10], y[13]); + word3_muladd(&w1, &w0, &w2, x[11], y[12]); + word3_muladd(&w1, &w0, &w2, x[12], y[11]); + word3_muladd(&w1, &w0, &w2, x[13], y[10]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[16], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[18], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[19], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[21], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[22], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 0]); + z[23] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[23]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[22]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[21]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[20]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[19]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[18]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[17]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[16]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); + word3_muladd(&w2, &w1, &w0, x[10], y[14]); + word3_muladd(&w2, &w1, &w0, x[11], y[13]); + word3_muladd(&w2, &w1, &w0, x[12], y[12]); + word3_muladd(&w2, &w1, &w0, x[13], y[11]); + word3_muladd(&w2, &w1, &w0, x[14], y[10]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[16], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[17], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[19], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[20], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[22], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[23], y[ 1]); + z[24] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[23]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[22]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[21]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[20]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[19]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[18]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[17]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[16]); + word3_muladd(&w0, &w2, &w1, x[10], y[15]); + word3_muladd(&w0, &w2, &w1, x[11], y[14]); + word3_muladd(&w0, &w2, &w1, x[12], y[13]); + word3_muladd(&w0, &w2, &w1, x[13], y[12]); + word3_muladd(&w0, &w2, &w1, x[14], y[11]); + word3_muladd(&w0, &w2, &w1, x[15], y[10]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[17], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[18], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[20], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[21], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[23], y[ 2]); + z[25] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[23]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[22]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[21]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[20]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[19]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[18]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[17]); + word3_muladd(&w1, &w0, &w2, x[10], y[16]); + word3_muladd(&w1, &w0, &w2, x[11], y[15]); + word3_muladd(&w1, &w0, &w2, x[12], y[14]); + word3_muladd(&w1, &w0, &w2, x[13], y[13]); + word3_muladd(&w1, &w0, &w2, x[14], y[12]); + word3_muladd(&w1, &w0, &w2, x[15], y[11]); + word3_muladd(&w1, &w0, &w2, x[16], y[10]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[18], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[19], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[21], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[22], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 3]); + z[26] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[23]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[22]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[21]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[20]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[19]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[18]); + word3_muladd(&w2, &w1, &w0, x[10], y[17]); + word3_muladd(&w2, &w1, &w0, x[11], y[16]); + word3_muladd(&w2, &w1, &w0, x[12], y[15]); + word3_muladd(&w2, &w1, &w0, x[13], y[14]); + word3_muladd(&w2, &w1, &w0, x[14], y[13]); + word3_muladd(&w2, &w1, &w0, x[15], y[12]); + word3_muladd(&w2, &w1, &w0, x[16], y[11]); + word3_muladd(&w2, &w1, &w0, x[17], y[10]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[19], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[20], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[22], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[23], y[ 4]); + z[27] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[23]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[22]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[21]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[20]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[19]); + word3_muladd(&w0, &w2, &w1, x[10], y[18]); + word3_muladd(&w0, &w2, &w1, x[11], y[17]); + word3_muladd(&w0, &w2, &w1, x[12], y[16]); + word3_muladd(&w0, &w2, &w1, x[13], y[15]); + word3_muladd(&w0, &w2, &w1, x[14], y[14]); + word3_muladd(&w0, &w2, &w1, x[15], y[13]); + word3_muladd(&w0, &w2, &w1, x[16], y[12]); + word3_muladd(&w0, &w2, &w1, x[17], y[11]); + word3_muladd(&w0, &w2, &w1, x[18], y[10]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[20], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[21], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[23], y[ 5]); + z[28] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 6], y[23]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[22]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[21]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[20]); + word3_muladd(&w1, &w0, &w2, x[10], y[19]); + word3_muladd(&w1, &w0, &w2, x[11], y[18]); + word3_muladd(&w1, &w0, &w2, x[12], y[17]); + word3_muladd(&w1, &w0, &w2, x[13], y[16]); + word3_muladd(&w1, &w0, &w2, x[14], y[15]); + word3_muladd(&w1, &w0, &w2, x[15], y[14]); + word3_muladd(&w1, &w0, &w2, x[16], y[13]); + word3_muladd(&w1, &w0, &w2, x[17], y[12]); + word3_muladd(&w1, &w0, &w2, x[18], y[11]); + word3_muladd(&w1, &w0, &w2, x[19], y[10]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[21], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[22], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 6]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 7], y[23]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[22]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[21]); + word3_muladd(&w2, &w1, &w0, x[10], y[20]); + word3_muladd(&w2, &w1, &w0, x[11], y[19]); + word3_muladd(&w2, &w1, &w0, x[12], y[18]); + word3_muladd(&w2, &w1, &w0, x[13], y[17]); + word3_muladd(&w2, &w1, &w0, x[14], y[16]); + word3_muladd(&w2, &w1, &w0, x[15], y[15]); + word3_muladd(&w2, &w1, &w0, x[16], y[14]); + word3_muladd(&w2, &w1, &w0, x[17], y[13]); + word3_muladd(&w2, &w1, &w0, x[18], y[12]); + word3_muladd(&w2, &w1, &w0, x[19], y[11]); + word3_muladd(&w2, &w1, &w0, x[20], y[10]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[22], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[23], y[ 7]); + z[30] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 8], y[23]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[22]); + word3_muladd(&w0, &w2, &w1, x[10], y[21]); + word3_muladd(&w0, &w2, &w1, x[11], y[20]); + word3_muladd(&w0, &w2, &w1, x[12], y[19]); + word3_muladd(&w0, &w2, &w1, x[13], y[18]); + word3_muladd(&w0, &w2, &w1, x[14], y[17]); + word3_muladd(&w0, &w2, &w1, x[15], y[16]); + word3_muladd(&w0, &w2, &w1, x[16], y[15]); + word3_muladd(&w0, &w2, &w1, x[17], y[14]); + word3_muladd(&w0, &w2, &w1, x[18], y[13]); + word3_muladd(&w0, &w2, &w1, x[19], y[12]); + word3_muladd(&w0, &w2, &w1, x[20], y[11]); + word3_muladd(&w0, &w2, &w1, x[21], y[10]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[23], y[ 8]); + z[31] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 9], y[23]); + word3_muladd(&w1, &w0, &w2, x[10], y[22]); + word3_muladd(&w1, &w0, &w2, x[11], y[21]); + word3_muladd(&w1, &w0, &w2, x[12], y[20]); + word3_muladd(&w1, &w0, &w2, x[13], y[19]); + word3_muladd(&w1, &w0, &w2, x[14], y[18]); + word3_muladd(&w1, &w0, &w2, x[15], y[17]); + word3_muladd(&w1, &w0, &w2, x[16], y[16]); + word3_muladd(&w1, &w0, &w2, x[17], y[15]); + word3_muladd(&w1, &w0, &w2, x[18], y[14]); + word3_muladd(&w1, &w0, &w2, x[19], y[13]); + word3_muladd(&w1, &w0, &w2, x[20], y[12]); + word3_muladd(&w1, &w0, &w2, x[21], y[11]); + word3_muladd(&w1, &w0, &w2, x[22], y[10]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 9]); + z[32] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[10], y[23]); + word3_muladd(&w2, &w1, &w0, x[11], y[22]); + word3_muladd(&w2, &w1, &w0, x[12], y[21]); + word3_muladd(&w2, &w1, &w0, x[13], y[20]); + word3_muladd(&w2, &w1, &w0, x[14], y[19]); + word3_muladd(&w2, &w1, &w0, x[15], y[18]); + word3_muladd(&w2, &w1, &w0, x[16], y[17]); + word3_muladd(&w2, &w1, &w0, x[17], y[16]); + word3_muladd(&w2, &w1, &w0, x[18], y[15]); + word3_muladd(&w2, &w1, &w0, x[19], y[14]); + word3_muladd(&w2, &w1, &w0, x[20], y[13]); + word3_muladd(&w2, &w1, &w0, x[21], y[12]); + word3_muladd(&w2, &w1, &w0, x[22], y[11]); + word3_muladd(&w2, &w1, &w0, x[23], y[10]); + z[33] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[11], y[23]); + word3_muladd(&w0, &w2, &w1, x[12], y[22]); + word3_muladd(&w0, &w2, &w1, x[13], y[21]); + word3_muladd(&w0, &w2, &w1, x[14], y[20]); + word3_muladd(&w0, &w2, &w1, x[15], y[19]); + word3_muladd(&w0, &w2, &w1, x[16], y[18]); + word3_muladd(&w0, &w2, &w1, x[17], y[17]); + word3_muladd(&w0, &w2, &w1, x[18], y[16]); + word3_muladd(&w0, &w2, &w1, x[19], y[15]); + word3_muladd(&w0, &w2, &w1, x[20], y[14]); + word3_muladd(&w0, &w2, &w1, x[21], y[13]); + word3_muladd(&w0, &w2, &w1, x[22], y[12]); + word3_muladd(&w0, &w2, &w1, x[23], y[11]); + z[34] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[12], y[23]); + word3_muladd(&w1, &w0, &w2, x[13], y[22]); + word3_muladd(&w1, &w0, &w2, x[14], y[21]); + word3_muladd(&w1, &w0, &w2, x[15], y[20]); + word3_muladd(&w1, &w0, &w2, x[16], y[19]); + word3_muladd(&w1, &w0, &w2, x[17], y[18]); + word3_muladd(&w1, &w0, &w2, x[18], y[17]); + word3_muladd(&w1, &w0, &w2, x[19], y[16]); + word3_muladd(&w1, &w0, &w2, x[20], y[15]); + word3_muladd(&w1, &w0, &w2, x[21], y[14]); + word3_muladd(&w1, &w0, &w2, x[22], y[13]); + word3_muladd(&w1, &w0, &w2, x[23], y[12]); + z[35] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[13], y[23]); + word3_muladd(&w2, &w1, &w0, x[14], y[22]); + word3_muladd(&w2, &w1, &w0, x[15], y[21]); + word3_muladd(&w2, &w1, &w0, x[16], y[20]); + word3_muladd(&w2, &w1, &w0, x[17], y[19]); + word3_muladd(&w2, &w1, &w0, x[18], y[18]); + word3_muladd(&w2, &w1, &w0, x[19], y[17]); + word3_muladd(&w2, &w1, &w0, x[20], y[16]); + word3_muladd(&w2, &w1, &w0, x[21], y[15]); + word3_muladd(&w2, &w1, &w0, x[22], y[14]); + word3_muladd(&w2, &w1, &w0, x[23], y[13]); + z[36] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[14], y[23]); + word3_muladd(&w0, &w2, &w1, x[15], y[22]); + word3_muladd(&w0, &w2, &w1, x[16], y[21]); + word3_muladd(&w0, &w2, &w1, x[17], y[20]); + word3_muladd(&w0, &w2, &w1, x[18], y[19]); + word3_muladd(&w0, &w2, &w1, x[19], y[18]); + word3_muladd(&w0, &w2, &w1, x[20], y[17]); + word3_muladd(&w0, &w2, &w1, x[21], y[16]); + word3_muladd(&w0, &w2, &w1, x[22], y[15]); + word3_muladd(&w0, &w2, &w1, x[23], y[14]); + z[37] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[15], y[23]); + word3_muladd(&w1, &w0, &w2, x[16], y[22]); + word3_muladd(&w1, &w0, &w2, x[17], y[21]); + word3_muladd(&w1, &w0, &w2, x[18], y[20]); + word3_muladd(&w1, &w0, &w2, x[19], y[19]); + word3_muladd(&w1, &w0, &w2, x[20], y[18]); + word3_muladd(&w1, &w0, &w2, x[21], y[17]); + word3_muladd(&w1, &w0, &w2, x[22], y[16]); + word3_muladd(&w1, &w0, &w2, x[23], y[15]); + z[38] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[16], y[23]); + word3_muladd(&w2, &w1, &w0, x[17], y[22]); + word3_muladd(&w2, &w1, &w0, x[18], y[21]); + word3_muladd(&w2, &w1, &w0, x[19], y[20]); + word3_muladd(&w2, &w1, &w0, x[20], y[19]); + word3_muladd(&w2, &w1, &w0, x[21], y[18]); + word3_muladd(&w2, &w1, &w0, x[22], y[17]); + word3_muladd(&w2, &w1, &w0, x[23], y[16]); + z[39] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[17], y[23]); + word3_muladd(&w0, &w2, &w1, x[18], y[22]); + word3_muladd(&w0, &w2, &w1, x[19], y[21]); + word3_muladd(&w0, &w2, &w1, x[20], y[20]); + word3_muladd(&w0, &w2, &w1, x[21], y[19]); + word3_muladd(&w0, &w2, &w1, x[22], y[18]); + word3_muladd(&w0, &w2, &w1, x[23], y[17]); + z[40] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[18], y[23]); + word3_muladd(&w1, &w0, &w2, x[19], y[22]); + word3_muladd(&w1, &w0, &w2, x[20], y[21]); + word3_muladd(&w1, &w0, &w2, x[21], y[20]); + word3_muladd(&w1, &w0, &w2, x[22], y[19]); + word3_muladd(&w1, &w0, &w2, x[23], y[18]); + z[41] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[19], y[23]); + word3_muladd(&w2, &w1, &w0, x[20], y[22]); + word3_muladd(&w2, &w1, &w0, x[21], y[21]); + word3_muladd(&w2, &w1, &w0, x[22], y[20]); + word3_muladd(&w2, &w1, &w0, x[23], y[19]); + z[42] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[20], y[23]); + word3_muladd(&w0, &w2, &w1, x[21], y[22]); + word3_muladd(&w0, &w2, &w1, x[22], y[21]); + word3_muladd(&w0, &w2, &w1, x[23], y[20]); + z[43] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[21], y[23]); + word3_muladd(&w1, &w0, &w2, x[22], y[22]); + word3_muladd(&w1, &w0, &w2, x[23], y[21]); + z[44] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[22], y[23]); + word3_muladd(&w2, &w1, &w0, x[23], y[22]); + z[45] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[23], y[23]); + z[46] = w1; + z[47] = w2; + } + +} diff --git a/comm/third_party/botan/src/lib/math/mp/mp_core.h b/comm/third_party/botan/src/lib/math/mp/mp_core.h new file mode 100644 index 0000000000..c4bf8e8815 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_core.h @@ -0,0 +1,819 @@ +/* +* MPI Algorithms +* (C) 1999-2010,2018 Jack Lloyd +* 2006 Luca Piccarreta +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_CORE_OPS_H_ +#define BOTAN_MP_CORE_OPS_H_ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +const word MP_WORD_MAX = ~static_cast(0); + +/* +* If cond == 0, does nothing. +* If cond > 0, swaps x[0:size] with y[0:size] +* Runs in constant time +*/ +inline void bigint_cnd_swap(word cnd, word x[], word y[], size_t size) + { + const auto mask = CT::Mask::expand(cnd); + + for(size_t i = 0; i != size; ++i) + { + const word a = x[i]; + const word b = y[i]; + x[i] = mask.select(b, a); + y[i] = mask.select(a, b); + } + } + +inline word bigint_cnd_add(word cnd, word x[], word x_size, + const word y[], size_t y_size) + { + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const auto mask = CT::Mask::expand(cnd); + + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + word z[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_add3(z, x + i, y + i, carry); + mask.select_n(x + i, z, x + i, 8); + } + + for(size_t i = blocks; i != y_size; ++i) + { + z[0] = word_add(x[i], y[i], &carry); + x[i] = mask.select(z[0], x[i]); + } + + for(size_t i = y_size; i != x_size; ++i) + { + z[0] = word_add(x[i], 0, &carry); + x[i] = mask.select(z[0], x[i]); + } + + return mask.if_set_return(carry); + } + +/* +* If cond > 0 adds x[0:size] and y[0:size] and returns carry +* Runs in constant time +*/ +inline word bigint_cnd_add(word cnd, word x[], const word y[], size_t size) + { + return bigint_cnd_add(cnd, x, size, y, size); + } + +/* +* If cond > 0 subtracts x[0:size] and y[0:size] and returns borrow +* Runs in constant time +*/ +inline word bigint_cnd_sub(word cnd, + word x[], size_t x_size, + const word y[], size_t y_size) + { + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const auto mask = CT::Mask::expand(cnd); + + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + word z[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_sub3(z, x + i, y + i, carry); + mask.select_n(x + i, z, x + i, 8); + } + + for(size_t i = blocks; i != y_size; ++i) + { + z[0] = word_sub(x[i], y[i], &carry); + x[i] = mask.select(z[0], x[i]); + } + + for(size_t i = y_size; i != x_size; ++i) + { + z[0] = word_sub(x[i], 0, &carry); + x[i] = mask.select(z[0], x[i]); + } + + return mask.if_set_return(carry); + } + +/* +* If cond > 0 adds x[0:size] and y[0:size] and returns carry +* Runs in constant time +*/ +inline word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size) + { + return bigint_cnd_sub(cnd, x, size, y, size); + } + + +/* +* Equivalent to +* bigint_cnd_add( mask, x, y, size); +* bigint_cnd_sub(~mask, x, y, size); +* +* Mask must be either 0 or all 1 bits +*/ +inline void bigint_cnd_add_or_sub(CT::Mask mask, word x[], const word y[], size_t size) + { + const size_t blocks = size - (size % 8); + + word carry = 0; + word borrow = 0; + + word t0[8] = { 0 }; + word t1[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_add3(t0, x + i, y + i, carry); + borrow = word8_sub3(t1, x + i, y + i, borrow); + + for(size_t j = 0; j != 8; ++j) + x[i+j] = mask.select(t0[j], t1[j]); + } + + for(size_t i = blocks; i != size; ++i) + { + const word a = word_add(x[i], y[i], &carry); + const word s = word_sub(x[i], y[i], &borrow); + + x[i] = mask.select(a, s); + } + } + +/* +* Equivalent to +* bigint_cnd_add( mask, x, size, y, size); +* bigint_cnd_sub(~mask, x, size, z, size); +* +* Mask must be either 0 or all 1 bits +* +* Returns the carry or borrow resp +*/ +inline word bigint_cnd_addsub(CT::Mask mask, word x[], + const word y[], const word z[], + size_t size) + { + const size_t blocks = size - (size % 8); + + word carry = 0; + word borrow = 0; + + word t0[8] = { 0 }; + word t1[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_add3(t0, x + i, y + i, carry); + borrow = word8_sub3(t1, x + i, z + i, borrow); + + for(size_t j = 0; j != 8; ++j) + x[i+j] = mask.select(t0[j], t1[j]); + } + + for(size_t i = blocks; i != size; ++i) + { + t0[0] = word_add(x[i], y[i], &carry); + t1[0] = word_sub(x[i], z[i], &borrow); + x[i] = mask.select(t0[0], t1[0]); + } + + return mask.select(carry, borrow); + } + +/* +* 2s complement absolute value +* If cond > 0 sets x to ~x + 1 +* Runs in constant time +*/ +inline void bigint_cnd_abs(word cnd, word x[], size_t size) + { + const auto mask = CT::Mask::expand(cnd); + + word carry = mask.if_set_return(1); + for(size_t i = 0; i != size; ++i) + { + const word z = word_add(~x[i], 0, &carry); + x[i] = mask.select(z, x[i]); + } + } + +/** +* Two operand addition with carry out +*/ +inline word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) + { + word carry = 0; + + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add2(x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/** +* Three operand addition with carry out +*/ +inline word bigint_add3_nc(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) + { return bigint_add3_nc(z, y, y_size, x, x_size); } + + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add3(z + i, x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/** +* Two operand addition +* @param x the first operand (and output) +* @param x_size size of x +* @param y the second operand +* @param y_size size of y (must be >= x_size) +*/ +inline void bigint_add2(word x[], size_t x_size, + const word y[], size_t y_size) + { + x[x_size] += bigint_add2_nc(x, x_size, y, y_size); + } + +/** +* Three operand addition +*/ +inline void bigint_add3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size) + { + z[x_size > y_size ? x_size : y_size] += + bigint_add3_nc(z, x, x_size, y, y_size); + } + +/** +* Two operand subtraction +*/ +inline word bigint_sub2(word x[], size_t x_size, + const word y[], size_t y_size) + { + word borrow = 0; + + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/** +* Two operand subtraction, x = y - x; assumes y >= x +*/ +inline void bigint_sub2_rev(word x[], const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2_rev(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(y[i], x[i], &borrow); + + BOTAN_ASSERT(borrow == 0, "y must be greater than x"); + } + +/** +* Three operand subtraction +*/ +inline word bigint_sub3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size) + { + word borrow = 0; + + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub3(z + i, x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/** +* Return abs(x-y), ie if x >= y, then compute z = x - y +* Otherwise compute z = y - x +* No borrow is possible since the result is always >= 0 +* +* Returns ~0 if x >= y or 0 if x < y +* @param z output array of at least N words +* @param x input array of N words +* @param y input array of N words +* @param N length of x and y +* @param ws array of at least 2*N words +*/ +inline CT::Mask +bigint_sub_abs(word z[], + const word x[], const word y[], size_t N, + word ws[]) + { + // Subtract in both direction then conditional copy out the result + + word* ws0 = ws; + word* ws1 = ws + N; + + word borrow0 = 0; + word borrow1 = 0; + + const size_t blocks = N - (N % 8); + + for(size_t i = 0; i != blocks; i += 8) + { + borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0); + borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1); + } + + for(size_t i = blocks; i != N; ++i) + { + ws0[i] = word_sub(x[i], y[i], &borrow0); + ws1[i] = word_sub(y[i], x[i], &borrow1); + } + + return CT::conditional_copy_mem(borrow0, z, ws1, ws0, N); + } + +/* +* Shift Operations +*/ +inline void bigint_shl1(word x[], size_t x_size, size_t x_words, + size_t word_shift, size_t bit_shift) + { + copy_mem(x + word_shift, x, x_words); + clear_mem(x, word_shift); + + const auto carry_mask = CT::Mask::expand(bit_shift); + const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); + + word carry = 0; + for(size_t i = word_shift; i != x_size; ++i) + { + const word w = x[i]; + x[i] = (w << bit_shift) | carry; + carry = carry_mask.if_set_return(w >> carry_shift); + } + } + +inline void bigint_shr1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + const size_t top = x_size >= word_shift ? (x_size - word_shift) : 0; + + if(top > 0) + copy_mem(x, x + word_shift, top); + clear_mem(x + top, std::min(word_shift, x_size)); + + const auto carry_mask = CT::Mask::expand(bit_shift); + const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); + + word carry = 0; + + for(size_t i = 0; i != top; ++i) + { + const word w = x[top - i - 1]; + x[top-i-1] = (w >> bit_shift) | carry; + carry = carry_mask.if_set_return(w << carry_shift); + } + } + +inline void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + copy_mem(y + word_shift, x, x_size); + + const auto carry_mask = CT::Mask::expand(bit_shift); + const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); + + word carry = 0; + for(size_t i = word_shift; i != x_size + word_shift + 1; ++i) + { + const word w = y[i]; + y[i] = (w << bit_shift) | carry; + carry = carry_mask.if_set_return(w >> carry_shift); + } + } + +inline void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + const size_t new_size = x_size < word_shift ? 0 : (x_size - word_shift); + + if(new_size > 0) + copy_mem(y, x + word_shift, new_size); + + const auto carry_mask = CT::Mask::expand(bit_shift); + const size_t carry_shift = carry_mask.if_set_return(BOTAN_MP_WORD_BITS - bit_shift); + + word carry = 0; + for(size_t i = new_size; i > 0; --i) + { + word w = y[i-1]; + y[i-1] = (w >> bit_shift) | carry; + carry = carry_mask.if_set_return(w << carry_shift); + } + } + +/* +* Linear Multiply - returns the carry +*/ +inline word BOTAN_WARN_UNUSED_RESULT bigint_linmul2(word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul2(x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + x[i] = word_madd2(x[i], y, &carry); + + return carry; + } + +inline void bigint_linmul3(word z[], const word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul3(z + i, x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + z[i] = word_madd2(x[i], y, &carry); + + z[x_size] = carry; + } + +/** +* Compare x and y +* Return -1 if x < y +* Return 0 if x == y +* Return 1 if x > y +*/ +inline int32_t bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size) + { + static_assert(sizeof(word) >= sizeof(uint32_t), "Size assumption"); + + const word LT = static_cast(-1); + const word EQ = 0; + const word GT = 1; + + const size_t common_elems = std::min(x_size, y_size); + + word result = EQ; // until found otherwise + + for(size_t i = 0; i != common_elems; i++) + { + const auto is_eq = CT::Mask::is_equal(x[i], y[i]); + const auto is_lt = CT::Mask::is_lt(x[i], y[i]); + + result = is_eq.select(result, is_lt.select(LT, GT)); + } + + if(x_size < y_size) + { + word mask = 0; + for(size_t i = x_size; i != y_size; i++) + mask |= y[i]; + + // If any bits were set in high part of y, then x < y + result = CT::Mask::is_zero(mask).select(result, LT); + } + else if(y_size < x_size) + { + word mask = 0; + for(size_t i = y_size; i != x_size; i++) + mask |= x[i]; + + // If any bits were set in high part of x, then x > y + result = CT::Mask::is_zero(mask).select(result, GT); + } + + CT::unpoison(result); + BOTAN_DEBUG_ASSERT(result == LT || result == GT || result == EQ); + return static_cast(result); + } + +/** +* Compare x and y +* Return ~0 if x[0:x_size] < y[0:y_size] or 0 otherwise +* If lt_or_equal is true, returns ~0 also for x == y +*/ +inline CT::Mask +bigint_ct_is_lt(const word x[], size_t x_size, + const word y[], size_t y_size, + bool lt_or_equal = false) + { + const size_t common_elems = std::min(x_size, y_size); + + auto is_lt = CT::Mask::expand(lt_or_equal); + + for(size_t i = 0; i != common_elems; i++) + { + const auto eq = CT::Mask::is_equal(x[i], y[i]); + const auto lt = CT::Mask::is_lt(x[i], y[i]); + is_lt = eq.select_mask(is_lt, lt); + } + + if(x_size < y_size) + { + word mask = 0; + for(size_t i = x_size; i != y_size; i++) + mask |= y[i]; + // If any bits were set in high part of y, then is_lt should be forced true + is_lt |= CT::Mask::expand(mask); + } + else if(y_size < x_size) + { + word mask = 0; + for(size_t i = y_size; i != x_size; i++) + mask |= x[i]; + + // If any bits were set in high part of x, then is_lt should be false + is_lt &= CT::Mask::is_zero(mask); + } + + return is_lt; + } + +inline CT::Mask +bigint_ct_is_eq(const word x[], size_t x_size, + const word y[], size_t y_size) + { + const size_t common_elems = std::min(x_size, y_size); + + word diff = 0; + + for(size_t i = 0; i != common_elems; i++) + { + diff |= (x[i] ^ y[i]); + } + + // If any bits were set in high part of x/y, then they are not equal + if(x_size < y_size) + { + for(size_t i = x_size; i != y_size; i++) + diff |= y[i]; + } + else if(y_size < x_size) + { + for(size_t i = y_size; i != x_size; i++) + diff |= x[i]; + } + + return CT::Mask::is_zero(diff); + } + +/** +* Set z to abs(x-y), ie if x >= y, then compute z = x - y +* Otherwise compute z = y - x +* No borrow is possible since the result is always >= 0 +* +* Return the relative size of x vs y (-1, 0, 1) +* +* @param z output array of max(x_size,y_size) words +* @param x input param +* @param x_size length of x +* @param y input param +* @param y_size length of y +*/ +inline int32_t +bigint_sub_abs(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size) + { + const int32_t relative_size = bigint_cmp(x, x_size, y, y_size); + + // Swap if relative_size == -1 + const bool need_swap = relative_size < 0; + CT::conditional_swap_ptr(need_swap, x, y); + CT::conditional_swap(need_swap, x_size, y_size); + + /* + * We know at this point that x >= y so if y_size is larger than + * x_size, we are guaranteed they are just leading zeros which can + * be ignored + */ + y_size = std::min(x_size, y_size); + + bigint_sub3(z, x, x_size, y, y_size); + + return relative_size; + } + +/** +* Set t to t-s modulo mod +* +* @param t first integer +* @param s second integer +* @param mod the modulus +* @param mod_sw size of t, s, and mod +* @param ws workspace of size mod_sw +*/ +inline void +bigint_mod_sub(word t[], const word s[], const word mod[], size_t mod_sw, word ws[]) + { + // is t < s or not? + const auto is_lt = bigint_ct_is_lt(t, mod_sw, s, mod_sw); + + // ws = p - s + const word borrow = bigint_sub3(ws, mod, mod_sw, s, mod_sw); + + // Compute either (t - s) or (t + (p - s)) depending on mask + const word carry = bigint_cnd_addsub(is_lt, t, ws, s, mod_sw); + + BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); + BOTAN_UNUSED(carry, borrow); + } + +template +inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[]) + { + // is t < s or not? + const auto is_lt = bigint_ct_is_lt(t, N, s, N); + + // ws = p - s + const word borrow = bigint_sub3(ws, mod, N, s, N); + + // Compute either (t - s) or (t + (p - s)) depending on mask + const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N); + + BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); + BOTAN_UNUSED(carry, borrow); + } + +/** +* Compute ((n1<(n1) << BOTAN_MP_WORD_BITS) | n0) / d; +#else + + word high = n1 % d; + word quotient = 0; + + for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i) + { + const word high_top_bit = high >> (BOTAN_MP_WORD_BITS-1); + + high <<= 1; + high |= (n0 >> (BOTAN_MP_WORD_BITS-1-i)) & 1; + quotient <<= 1; + + if(high_top_bit || high >= d) + { + high -= d; + quotient |= 1; + } + } + + return quotient; +#endif + } + +/** +* Compute ((n1<(n1) << BOTAN_MP_WORD_BITS) | n0) % d; +#else + word z = bigint_divop(n1, n0, d); + word dummy = 0; + z = word_madd2(z, d, &dummy); + return (n0-z); +#endif + } + +/* +* Comba Multiplication / Squaring +*/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]); +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]); +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]); +void bigint_comba_mul9(word z[18], const word x[9], const word y[9]); +void bigint_comba_mul16(word z[32], const word x[16], const word y[16]); +void bigint_comba_mul24(word z[48], const word x[24], const word y[24]); + +void bigint_comba_sqr4(word out[8], const word in[4]); +void bigint_comba_sqr6(word out[12], const word in[6]); +void bigint_comba_sqr8(word out[16], const word in[8]); +void bigint_comba_sqr9(word out[18], const word in[9]); +void bigint_comba_sqr16(word out[32], const word in[16]); +void bigint_comba_sqr24(word out[48], const word in[24]); + +/** +* Montgomery Reduction +* @param z integer to reduce, of size exactly 2*(p_size+1). + Output is in the first p_size+1 words, higher + words are set to zero. +* @param p modulus +* @param p_size size of p +* @param p_dash Montgomery value +* @param workspace array of at least 2*(p_size+1) words +* @param ws_size size of workspace in words +*/ +void bigint_monty_redc(word z[], + const word p[], size_t p_size, + word p_dash, + word workspace[], + size_t ws_size); + +/* +* High Level Multiplication/Squaring Interfaces +*/ + +void bigint_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + word workspace[], size_t ws_size); + +void bigint_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + word workspace[], size_t ws_size); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/mp/mp_karat.cpp b/comm/third_party/botan/src/lib/math/mp/mp_karat.cpp new file mode 100644 index 0000000000..15fcafa5be --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_karat.cpp @@ -0,0 +1,408 @@ +/* +* Multiplication and Squaring +* (C) 1999-2010,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32; +const size_t KARATSUBA_SQUARE_THRESHOLD = 32; + +/* +* Simple O(N^2) Multiplication +*/ +void basecase_mul(word z[], size_t z_size, + const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(z_size < x_size + y_size) + throw Invalid_Argument("basecase_mul z_size too small"); + + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, z_size); + + for(size_t i = 0; i != y_size; ++i) + { + const word y_i = y[i]; + + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, y_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +void basecase_sqr(word z[], size_t z_size, + const word x[], size_t x_size) + { + if(z_size < 2*x_size) + throw Invalid_Argument("basecase_sqr z_size too small"); + + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, z_size); + + for(size_t i = 0; i != x_size; ++i) + { + const word x_i = x[i]; + + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, x_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +/* +* Karatsuba Multiplication Operation +*/ +void karatsuba_mul(word z[], const word x[], const word y[], size_t N, + word workspace[]) + { + if(N < KARATSUBA_MULTIPLY_THRESHOLD || N % 2) + { + switch(N) + { + case 6: + return bigint_comba_mul6(z, x, y); + case 8: + return bigint_comba_mul8(z, x, y); + case 9: + return bigint_comba_mul9(z, x, y); + case 16: + return bigint_comba_mul16(z, x, y); + case 24: + return bigint_comba_mul24(z, x, y); + default: + return basecase_mul(z, 2*N, x, N, y, N); + } + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + const word* y0 = y; + const word* y1 = y + N2; + word* z0 = z; + word* z1 = z + N; + + word* ws0 = workspace; + word* ws1 = workspace + N; + + clear_mem(workspace, 2*N); + + /* + * If either of cmp0 or cmp1 is zero then z0 or z1 resp is zero here, + * resulting in a no-op - z0*z1 will be equal to zero so we don't need to do + * anything, clear_mem above already set the correct result. + * + * However we ignore the result of the comparisons and always perform the + * subtractions and recursively multiply to avoid the timing channel. + */ + + // First compute (X_lo - X_hi)*(Y_hi - Y_lo) + const auto cmp0 = bigint_sub_abs(z0, x0, x1, N2, workspace); + const auto cmp1 = bigint_sub_abs(z1, y1, y0, N2, workspace); + const auto neg_mask = ~(cmp0 ^ cmp1); + + karatsuba_mul(ws0, z0, z1, N2, ws1); + + // Compute X_lo * Y_lo + karatsuba_mul(z0, x0, y0, N2, ws1); + + // Compute X_hi * Y_hi + karatsuba_mul(z1, x1, y1, N2, ws1); + + const word ws_carry = bigint_add3_nc(ws1, z0, N, z1, N); + word z_carry = bigint_add2_nc(z + N2, N, ws1, N); + + z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); + bigint_add2_nc(z + N + N2, N2, &z_carry, 1); + + clear_mem(workspace + N, N2); + + bigint_cnd_add_or_sub(neg_mask, z + N2, workspace, 2*N-N2); + } + +/* +* Karatsuba Squaring Operation +*/ +void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[]) + { + if(N < KARATSUBA_SQUARE_THRESHOLD || N % 2) + { + switch(N) + { + case 6: + return bigint_comba_sqr6(z, x); + case 8: + return bigint_comba_sqr8(z, x); + case 9: + return bigint_comba_sqr9(z, x); + case 16: + return bigint_comba_sqr16(z, x); + case 24: + return bigint_comba_sqr24(z, x); + default: + return basecase_sqr(z, 2*N, x, N); + } + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + word* z0 = z; + word* z1 = z + N; + + word* ws0 = workspace; + word* ws1 = workspace + N; + + clear_mem(workspace, 2*N); + + // See comment in karatsuba_mul + bigint_sub_abs(z0, x0, x1, N2, workspace); + karatsuba_sqr(ws0, z0, N2, ws1); + + karatsuba_sqr(z0, x0, N2, ws1); + karatsuba_sqr(z1, x1, N2, ws1); + + const word ws_carry = bigint_add3_nc(ws1, z0, N, z1, N); + word z_carry = bigint_add2_nc(z + N2, N, ws1, N); + + z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); + bigint_add2_nc(z + N + N2, N2, &z_carry, 1); + + /* + * This is only actually required if cmp (result of bigint_sub_abs) is != 0, + * however if cmp==0 then ws0[0:N] == 0 and avoiding the jump hides a + * timing channel. + */ + bigint_sub2(z + N2, 2*N-N2, ws0, N); + } + +/* +* Pick a good size for the Karatsuba multiply +*/ +size_t karatsuba_size(size_t z_size, + size_t x_size, size_t x_sw, + size_t y_size, size_t y_sw) + { + if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) + return 0; + + if(((x_size == x_sw) && (x_size % 2)) || + ((y_size == y_sw) && (y_size % 2))) + return 0; + + const size_t start = (x_sw > y_sw) ? x_sw : y_sw; + const size_t end = (x_size < y_size) ? x_size : y_size; + + if(start == end) + { + if(start % 2) + return 0; + return start; + } + + for(size_t j = start; j <= end; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) + { + if(j % 4 == 2 && + (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + } + + return 0; + } + +/* +* Pick a good size for the Karatsuba squaring +*/ +size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw) + { + if(x_sw == x_size) + { + if(x_sw % 2) + return 0; + return x_sw; + } + + for(size_t j = x_sw; j <= x_size; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + + return 0; + } + +template +inline bool sized_for_comba_mul(size_t x_sw, size_t x_size, + size_t y_sw, size_t y_size, + size_t z_size) + { + return (x_sw <= SZ && x_size >= SZ && + y_sw <= SZ && y_size >= SZ && + z_size >= 2*SZ); + } + +template +inline bool sized_for_comba_sqr(size_t x_sw, size_t x_size, + size_t z_size) + { + return (x_sw <= SZ && x_size >= SZ && z_size >= 2*SZ); + } + +} + +void bigint_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + word workspace[], size_t ws_size) + { + clear_mem(z, z_size); + + if(x_sw == 1) + { + bigint_linmul3(z, y, y_sw, x[0]); + } + else if(y_sw == 1) + { + bigint_linmul3(z, x, x_sw, y[0]); + } + else if(sized_for_comba_mul<4>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul4(z, x, y); + } + else if(sized_for_comba_mul<6>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul6(z, x, y); + } + else if(sized_for_comba_mul<8>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul8(z, x, y); + } + else if(sized_for_comba_mul<9>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul9(z, x, y); + } + else if(sized_for_comba_mul<16>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul16(z, x, y); + } + else if(sized_for_comba_mul<24>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul24(z, x, y); + } + else if(x_sw < KARATSUBA_MULTIPLY_THRESHOLD || + y_sw < KARATSUBA_MULTIPLY_THRESHOLD || + !workspace) + { + basecase_mul(z, z_size, x, x_sw, y, y_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); + + if(N && z_size >= 2*N && ws_size >= 2*N) + karatsuba_mul(z, x, y, N, workspace); + else + basecase_mul(z, z_size, x, x_sw, y, y_sw); + } + } + +/* +* Squaring Algorithm Dispatcher +*/ +void bigint_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + word workspace[], size_t ws_size) + { + clear_mem(z, z_size); + + BOTAN_ASSERT(z_size/2 >= x_sw, "Output size is sufficient"); + + if(x_sw == 1) + { + bigint_linmul3(z, x, x_sw, x[0]); + } + else if(sized_for_comba_sqr<4>(x_sw, x_size, z_size)) + { + bigint_comba_sqr4(z, x); + } + else if(sized_for_comba_sqr<6>(x_sw, x_size, z_size)) + { + bigint_comba_sqr6(z, x); + } + else if(sized_for_comba_sqr<8>(x_sw, x_size, z_size)) + { + bigint_comba_sqr8(z, x); + } + else if(sized_for_comba_sqr<9>(x_sw, x_size, z_size)) + { + bigint_comba_sqr9(z, x); + } + else if(sized_for_comba_sqr<16>(x_sw, x_size, z_size)) + { + bigint_comba_sqr16(z, x); + } + else if(sized_for_comba_sqr<24>(x_sw, x_size, z_size)) + { + bigint_comba_sqr24(z, x); + } + else if(x_size < KARATSUBA_SQUARE_THRESHOLD || !workspace) + { + basecase_sqr(z, z_size, x, x_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw); + + if(N && z_size >= 2*N && ws_size >= 2*N) + karatsuba_sqr(z, x, N, workspace); + else + basecase_sqr(z, z_size, x, x_sw); + } + } + +} diff --git a/comm/third_party/botan/src/lib/math/mp/mp_madd.h b/comm/third_party/botan/src/lib/math/mp/mp_madd.h new file mode 100644 index 0000000000..531d6e6634 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_madd.h @@ -0,0 +1,146 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2008,2013 Jack Lloyd +* 2006 Luca Piccarreta +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_WORD_MULADD_H_ +#define BOTAN_MP_WORD_MULADD_H_ + +#include +#include + +namespace Botan { + +#if (BOTAN_MP_WORD_BITS == 32) + typedef uint64_t dword; + #define BOTAN_HAS_MP_DWORD + +#elif (BOTAN_MP_WORD_BITS == 64) + #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + typedef uint128_t dword; + #define BOTAN_HAS_MP_DWORD + #else + // No native 128 bit integer type; use mul64x64_128 instead + #endif + +#else + #error BOTAN_MP_WORD_BITS must be 32 or 64 +#endif + +#if defined(BOTAN_USE_GCC_INLINE_ASM) + + #if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32) + #define BOTAN_MP_USE_X86_32_ASM + #elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) + #define BOTAN_MP_USE_X86_64_ASM + #endif + +#endif + +/* +* Word Multiply/Add +*/ +inline word word_madd2(word a, word b, word* c) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm(R"( + mull %[b] + addl %[c],%[a] + adcl $0,%[carry] + )" + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + asm(R"( + mulq %[b] + addq %[c],%[a] + adcq $0,%[carry] + )" + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + +#elif defined(BOTAN_HAS_MP_DWORD) + const dword s = static_cast(a) * b + *c; + *c = static_cast(s >> BOTAN_MP_WORD_BITS); + return static_cast(s); +#else + static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); + + word hi = 0, lo = 0; + + mul64x64_128(a, b, &lo, &hi); + + lo += *c; + hi += (lo < *c); // carry? + + *c = hi; + return lo; +#endif + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm(R"( + mull %[b] + + addl %[c],%[a] + adcl $0,%[carry] + + addl %[d],%[a] + adcl $0,%[carry] + )" + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + asm(R"( + mulq %[b] + addq %[c],%[a] + adcq $0,%[carry] + addq %[d],%[a] + adcq $0,%[carry] + )" + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + +#elif defined(BOTAN_HAS_MP_DWORD) + const dword s = static_cast(a) * b + c + *d; + *d = static_cast(s >> BOTAN_MP_WORD_BITS); + return static_cast(s); +#else + static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); + + word hi = 0, lo = 0; + + mul64x64_128(a, b, &lo, &hi); + + lo += c; + hi += (lo < c); // carry? + + lo += *d; + hi += (lo < *d); // carry? + + *d = hi; + return lo; +#endif + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/mp/mp_monty.cpp b/comm/third_party/botan/src/lib/math/mp/mp_monty.cpp new file mode 100644 index 0000000000..433d3ff358 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_monty.cpp @@ -0,0 +1,133 @@ +/* +* Montgomery Reduction +* (C) 1999-2011 Jack Lloyd +* 2006 Luca Piccarreta +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Montgomery reduction - product scanning form +* +* https://www.iacr.org/archive/ches2005/006.pdf +* https://eprint.iacr.org/2013/882.pdf +* https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/j37acmon.pdf +*/ +void bigint_monty_redc_generic(word z[], size_t z_size, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + + w0 = z[0]; + + ws[0] = w0 * p_dash; + + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + + w0 = w1; + w1 = w2; + w2 = 0; + + for(size_t i = 1; i != p_size; ++i) + { + for(size_t j = 0; j < i; ++j) + { + word3_muladd(&w2, &w1, &w0, ws[j], p[i-j]); + } + + word3_add(&w2, &w1, &w0, z[i]); + + ws[i] = w0 * p_dash; + + word3_muladd(&w2, &w1, &w0, ws[i], p[0]); + + w0 = w1; + w1 = w2; + w2 = 0; + } + + for(size_t i = 0; i != p_size; ++i) + { + for(size_t j = i + 1; j != p_size; ++j) + { + word3_muladd(&w2, &w1, &w0, ws[j], p[p_size + i-j]); + } + + word3_add(&w2, &w1, &w0, z[p_size+i]); + + ws[i] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + } + + word3_add(&w2, &w1, &w0, z[z_size-1]); + + ws[p_size] = w0; + ws[p_size+1] = w1; + + /* + * The result might need to be reduced mod p. To avoid a timing + * channel, always perform the subtraction. If in the compution + * of x - p a borrow is required then x was already < p. + * + * x starts at ws[0] and is p_size+1 bytes long. + * x - p starts at ws[p_size+1] and is also p_size+1 bytes log + * + * Select which address to copy from indexing off of the final + * borrow. + */ + + // word borrow = bigint_sub3(ws + p_size + 1, ws, p_size + 1, p, p_size); + word borrow = 0; + for(size_t i = 0; i != p_size; ++i) + ws[p_size + 1 + i] = word_sub(ws[i], p[i], &borrow); + ws[2*p_size+1] = word_sub(ws[p_size], 0, &borrow); + + BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); + + CT::conditional_copy_mem(borrow, z, ws, ws + (p_size + 1), (p_size + 1)); + clear_mem(z + p_size, z_size - p_size - 2); + } + +} + +void bigint_monty_redc(word z[], + const word p[], size_t p_size, word p_dash, + word ws[], size_t ws_size) + { + const size_t z_size = 2*(p_size+1); + + BOTAN_ARG_CHECK(ws_size >= z_size, "workspace too small"); + + if(p_size == 4) + bigint_monty_redc_4(z, p, p_dash, ws); + else if(p_size == 6) + bigint_monty_redc_6(z, p, p_dash, ws); + else if(p_size == 8) + bigint_monty_redc_8(z, p, p_dash, ws); + else if(p_size == 16) + bigint_monty_redc_16(z, p, p_dash, ws); + else if(p_size == 24) + bigint_monty_redc_24(z, p, p_dash, ws); + else if(p_size == 32) + bigint_monty_redc_32(z, p, p_dash, ws); + else + bigint_monty_redc_generic(z, z_size, p, p_size, p_dash, ws); + } + +} diff --git a/comm/third_party/botan/src/lib/math/mp/mp_monty.h b/comm/third_party/botan/src/lib/math/mp/mp_monty.h new file mode 100644 index 0000000000..7462272d5c --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_monty.h @@ -0,0 +1,31 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_MONTY_H_ +#define BOTAN_MP_MONTY_H_ + +#include + +namespace Botan { + +/* +* Each of these functions makes the following assumptions: +* +* z_size >= 2*(p_size + 1) +* ws_size >= z_size +*/ + +void bigint_monty_redc_4(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_6(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_8(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_16(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_24(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_32(word z[], const word p[], word p_dash, word ws[]); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/mp/mp_monty_n.cpp b/comm/third_party/botan/src/lib/math/mp/mp_monty_n.cpp new file mode 100644 index 0000000000..0331d4a073 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/mp/mp_monty_n.cpp @@ -0,0 +1,2614 @@ +/* +* This file was automatically generated by ./src/scripts/monty.py on 2018-06-11 +* All manual changes will be lost. Edit the script instead. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +void bigint_monty_redc_4(word z[], const word p[4], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_add(&w2, &w1, &w0, z[5]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_add(&w2, &w1, &w0, z[6]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[7]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[9]); + ws[4] = w0; + ws[5] = w1; + word borrow = 0; + ws[5] = word_sub(ws[0], p[0], &borrow); + ws[6] = word_sub(ws[1], p[1], &borrow); + ws[7] = word_sub(ws[2], p[2], &borrow); + ws[8] = word_sub(ws[3], p[3], &borrow); + ws[9] = word_sub(ws[4], 0, &borrow); + CT::conditional_copy_mem(borrow, z, ws, ws + 5, 5); + clear_mem(z + 4, 2*(4+1) - 4); + } + +void bigint_monty_redc_6(word z[], const word p[6], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_add(&w2, &w1, &w0, z[7]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_add(&w2, &w1, &w0, z[8]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_add(&w2, &w1, &w0, z[9]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_add(&w2, &w1, &w0, z[10]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[11]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[13]); + ws[6] = w0; + ws[7] = w1; + word borrow = 0; + ws[7] = word_sub(ws[0], p[0], &borrow); + ws[8] = word_sub(ws[1], p[1], &borrow); + ws[9] = word_sub(ws[2], p[2], &borrow); + ws[10] = word_sub(ws[3], p[3], &borrow); + ws[11] = word_sub(ws[4], p[4], &borrow); + ws[12] = word_sub(ws[5], p[5], &borrow); + ws[13] = word_sub(ws[6], 0, &borrow); + CT::conditional_copy_mem(borrow, z, ws, ws + 7, 7); + clear_mem(z + 6, 2*(6+1) - 6); + } + +void bigint_monty_redc_8(word z[], const word p[8], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_add(&w2, &w1, &w0, z[9]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_add(&w2, &w1, &w0, z[10]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_add(&w2, &w1, &w0, z[11]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_add(&w2, &w1, &w0, z[12]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_add(&w2, &w1, &w0, z[13]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_add(&w2, &w1, &w0, z[14]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[15]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[17]); + ws[8] = w0; + ws[9] = w1; + word borrow = 0; + ws[9] = word_sub(ws[0], p[0], &borrow); + ws[10] = word_sub(ws[1], p[1], &borrow); + ws[11] = word_sub(ws[2], p[2], &borrow); + ws[12] = word_sub(ws[3], p[3], &borrow); + ws[13] = word_sub(ws[4], p[4], &borrow); + ws[14] = word_sub(ws[5], p[5], &borrow); + ws[15] = word_sub(ws[6], p[6], &borrow); + ws[16] = word_sub(ws[7], p[7], &borrow); + ws[17] = word_sub(ws[8], 0, &borrow); + CT::conditional_copy_mem(borrow, z, ws, ws + 9, 9); + clear_mem(z + 8, 2*(8+1) - 8); + } + +void bigint_monty_redc_16(word z[], const word p[16], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[8]); + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[8] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[8], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[9]); + word3_muladd(&w2, &w1, &w0, ws[1], p[8]); + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_muladd(&w2, &w1, &w0, ws[8], p[1]); + word3_add(&w2, &w1, &w0, z[9]); + ws[9] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[9], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[10]); + word3_muladd(&w2, &w1, &w0, ws[1], p[9]); + word3_muladd(&w2, &w1, &w0, ws[2], p[8]); + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_muladd(&w2, &w1, &w0, ws[8], p[2]); + word3_muladd(&w2, &w1, &w0, ws[9], p[1]); + word3_add(&w2, &w1, &w0, z[10]); + ws[10] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[10], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[11]); + word3_muladd(&w2, &w1, &w0, ws[1], p[10]); + word3_muladd(&w2, &w1, &w0, ws[2], p[9]); + word3_muladd(&w2, &w1, &w0, ws[3], p[8]); + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_muladd(&w2, &w1, &w0, ws[8], p[3]); + word3_muladd(&w2, &w1, &w0, ws[9], p[2]); + word3_muladd(&w2, &w1, &w0, ws[10], p[1]); + word3_add(&w2, &w1, &w0, z[11]); + ws[11] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[11], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[12]); + word3_muladd(&w2, &w1, &w0, ws[1], p[11]); + word3_muladd(&w2, &w1, &w0, ws[2], p[10]); + word3_muladd(&w2, &w1, &w0, ws[3], p[9]); + word3_muladd(&w2, &w1, &w0, ws[4], p[8]); + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_muladd(&w2, &w1, &w0, ws[8], p[4]); + word3_muladd(&w2, &w1, &w0, ws[9], p[3]); + word3_muladd(&w2, &w1, &w0, ws[10], p[2]); + word3_muladd(&w2, &w1, &w0, ws[11], p[1]); + word3_add(&w2, &w1, &w0, z[12]); + ws[12] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[12], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[13]); + word3_muladd(&w2, &w1, &w0, ws[1], p[12]); + word3_muladd(&w2, &w1, &w0, ws[2], p[11]); + word3_muladd(&w2, &w1, &w0, ws[3], p[10]); + word3_muladd(&w2, &w1, &w0, ws[4], p[9]); + word3_muladd(&w2, &w1, &w0, ws[5], p[8]); + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_muladd(&w2, &w1, &w0, ws[8], p[5]); + word3_muladd(&w2, &w1, &w0, ws[9], p[4]); + word3_muladd(&w2, &w1, &w0, ws[10], p[3]); + word3_muladd(&w2, &w1, &w0, ws[11], p[2]); + word3_muladd(&w2, &w1, &w0, ws[12], p[1]); + word3_add(&w2, &w1, &w0, z[13]); + ws[13] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[13], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[14]); + word3_muladd(&w2, &w1, &w0, ws[1], p[13]); + word3_muladd(&w2, &w1, &w0, ws[2], p[12]); + word3_muladd(&w2, &w1, &w0, ws[3], p[11]); + word3_muladd(&w2, &w1, &w0, ws[4], p[10]); + word3_muladd(&w2, &w1, &w0, ws[5], p[9]); + word3_muladd(&w2, &w1, &w0, ws[6], p[8]); + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_muladd(&w2, &w1, &w0, ws[8], p[6]); + word3_muladd(&w2, &w1, &w0, ws[9], p[5]); + word3_muladd(&w2, &w1, &w0, ws[10], p[4]); + word3_muladd(&w2, &w1, &w0, ws[11], p[3]); + word3_muladd(&w2, &w1, &w0, ws[12], p[2]); + word3_muladd(&w2, &w1, &w0, ws[13], p[1]); + word3_add(&w2, &w1, &w0, z[14]); + ws[14] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[14], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[15]); + word3_muladd(&w2, &w1, &w0, ws[1], p[14]); + word3_muladd(&w2, &w1, &w0, ws[2], p[13]); + word3_muladd(&w2, &w1, &w0, ws[3], p[12]); + word3_muladd(&w2, &w1, &w0, ws[4], p[11]); + word3_muladd(&w2, &w1, &w0, ws[5], p[10]); + word3_muladd(&w2, &w1, &w0, ws[6], p[9]); + word3_muladd(&w2, &w1, &w0, ws[7], p[8]); + word3_muladd(&w2, &w1, &w0, ws[8], p[7]); + word3_muladd(&w2, &w1, &w0, ws[9], p[6]); + word3_muladd(&w2, &w1, &w0, ws[10], p[5]); + word3_muladd(&w2, &w1, &w0, ws[11], p[4]); + word3_muladd(&w2, &w1, &w0, ws[12], p[3]); + word3_muladd(&w2, &w1, &w0, ws[13], p[2]); + word3_muladd(&w2, &w1, &w0, ws[14], p[1]); + word3_add(&w2, &w1, &w0, z[15]); + ws[15] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[15], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[15]); + word3_muladd(&w2, &w1, &w0, ws[2], p[14]); + word3_muladd(&w2, &w1, &w0, ws[3], p[13]); + word3_muladd(&w2, &w1, &w0, ws[4], p[12]); + word3_muladd(&w2, &w1, &w0, ws[5], p[11]); + word3_muladd(&w2, &w1, &w0, ws[6], p[10]); + word3_muladd(&w2, &w1, &w0, ws[7], p[9]); + word3_muladd(&w2, &w1, &w0, ws[8], p[8]); + word3_muladd(&w2, &w1, &w0, ws[9], p[7]); + word3_muladd(&w2, &w1, &w0, ws[10], p[6]); + word3_muladd(&w2, &w1, &w0, ws[11], p[5]); + word3_muladd(&w2, &w1, &w0, ws[12], p[4]); + word3_muladd(&w2, &w1, &w0, ws[13], p[3]); + word3_muladd(&w2, &w1, &w0, ws[14], p[2]); + word3_muladd(&w2, &w1, &w0, ws[15], p[1]); + word3_add(&w2, &w1, &w0, z[16]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[15]); + word3_muladd(&w2, &w1, &w0, ws[3], p[14]); + word3_muladd(&w2, &w1, &w0, ws[4], p[13]); + word3_muladd(&w2, &w1, &w0, ws[5], p[12]); + word3_muladd(&w2, &w1, &w0, ws[6], p[11]); + word3_muladd(&w2, &w1, &w0, ws[7], p[10]); + word3_muladd(&w2, &w1, &w0, ws[8], p[9]); + word3_muladd(&w2, &w1, &w0, ws[9], p[8]); + word3_muladd(&w2, &w1, &w0, ws[10], p[7]); + word3_muladd(&w2, &w1, &w0, ws[11], p[6]); + word3_muladd(&w2, &w1, &w0, ws[12], p[5]); + word3_muladd(&w2, &w1, &w0, ws[13], p[4]); + word3_muladd(&w2, &w1, &w0, ws[14], p[3]); + word3_muladd(&w2, &w1, &w0, ws[15], p[2]); + word3_add(&w2, &w1, &w0, z[17]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[15]); + word3_muladd(&w2, &w1, &w0, ws[4], p[14]); + word3_muladd(&w2, &w1, &w0, ws[5], p[13]); + word3_muladd(&w2, &w1, &w0, ws[6], p[12]); + word3_muladd(&w2, &w1, &w0, ws[7], p[11]); + word3_muladd(&w2, &w1, &w0, ws[8], p[10]); + word3_muladd(&w2, &w1, &w0, ws[9], p[9]); + word3_muladd(&w2, &w1, &w0, ws[10], p[8]); + word3_muladd(&w2, &w1, &w0, ws[11], p[7]); + word3_muladd(&w2, &w1, &w0, ws[12], p[6]); + word3_muladd(&w2, &w1, &w0, ws[13], p[5]); + word3_muladd(&w2, &w1, &w0, ws[14], p[4]); + word3_muladd(&w2, &w1, &w0, ws[15], p[3]); + word3_add(&w2, &w1, &w0, z[18]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[15]); + word3_muladd(&w2, &w1, &w0, ws[5], p[14]); + word3_muladd(&w2, &w1, &w0, ws[6], p[13]); + word3_muladd(&w2, &w1, &w0, ws[7], p[12]); + word3_muladd(&w2, &w1, &w0, ws[8], p[11]); + word3_muladd(&w2, &w1, &w0, ws[9], p[10]); + word3_muladd(&w2, &w1, &w0, ws[10], p[9]); + word3_muladd(&w2, &w1, &w0, ws[11], p[8]); + word3_muladd(&w2, &w1, &w0, ws[12], p[7]); + word3_muladd(&w2, &w1, &w0, ws[13], p[6]); + word3_muladd(&w2, &w1, &w0, ws[14], p[5]); + word3_muladd(&w2, &w1, &w0, ws[15], p[4]); + word3_add(&w2, &w1, &w0, z[19]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[15]); + word3_muladd(&w2, &w1, &w0, ws[6], p[14]); + word3_muladd(&w2, &w1, &w0, ws[7], p[13]); + word3_muladd(&w2, &w1, &w0, ws[8], p[12]); + word3_muladd(&w2, &w1, &w0, ws[9], p[11]); + word3_muladd(&w2, &w1, &w0, ws[10], p[10]); + word3_muladd(&w2, &w1, &w0, ws[11], p[9]); + word3_muladd(&w2, &w1, &w0, ws[12], p[8]); + word3_muladd(&w2, &w1, &w0, ws[13], p[7]); + word3_muladd(&w2, &w1, &w0, ws[14], p[6]); + word3_muladd(&w2, &w1, &w0, ws[15], p[5]); + word3_add(&w2, &w1, &w0, z[20]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[15]); + word3_muladd(&w2, &w1, &w0, ws[7], p[14]); + word3_muladd(&w2, &w1, &w0, ws[8], p[13]); + word3_muladd(&w2, &w1, &w0, ws[9], p[12]); + word3_muladd(&w2, &w1, &w0, ws[10], p[11]); + word3_muladd(&w2, &w1, &w0, ws[11], p[10]); + word3_muladd(&w2, &w1, &w0, ws[12], p[9]); + word3_muladd(&w2, &w1, &w0, ws[13], p[8]); + word3_muladd(&w2, &w1, &w0, ws[14], p[7]); + word3_muladd(&w2, &w1, &w0, ws[15], p[6]); + word3_add(&w2, &w1, &w0, z[21]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[15]); + word3_muladd(&w2, &w1, &w0, ws[8], p[14]); + word3_muladd(&w2, &w1, &w0, ws[9], p[13]); + word3_muladd(&w2, &w1, &w0, ws[10], p[12]); + word3_muladd(&w2, &w1, &w0, ws[11], p[11]); + word3_muladd(&w2, &w1, &w0, ws[12], p[10]); + word3_muladd(&w2, &w1, &w0, ws[13], p[9]); + word3_muladd(&w2, &w1, &w0, ws[14], p[8]); + word3_muladd(&w2, &w1, &w0, ws[15], p[7]); + word3_add(&w2, &w1, &w0, z[22]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[8], p[15]); + word3_muladd(&w2, &w1, &w0, ws[9], p[14]); + word3_muladd(&w2, &w1, &w0, ws[10], p[13]); + word3_muladd(&w2, &w1, &w0, ws[11], p[12]); + word3_muladd(&w2, &w1, &w0, ws[12], p[11]); + word3_muladd(&w2, &w1, &w0, ws[13], p[10]); + word3_muladd(&w2, &w1, &w0, ws[14], p[9]); + word3_muladd(&w2, &w1, &w0, ws[15], p[8]); + word3_add(&w2, &w1, &w0, z[23]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[9], p[15]); + word3_muladd(&w2, &w1, &w0, ws[10], p[14]); + word3_muladd(&w2, &w1, &w0, ws[11], p[13]); + word3_muladd(&w2, &w1, &w0, ws[12], p[12]); + word3_muladd(&w2, &w1, &w0, ws[13], p[11]); + word3_muladd(&w2, &w1, &w0, ws[14], p[10]); + word3_muladd(&w2, &w1, &w0, ws[15], p[9]); + word3_add(&w2, &w1, &w0, z[24]); + ws[8] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[10], p[15]); + word3_muladd(&w2, &w1, &w0, ws[11], p[14]); + word3_muladd(&w2, &w1, &w0, ws[12], p[13]); + word3_muladd(&w2, &w1, &w0, ws[13], p[12]); + word3_muladd(&w2, &w1, &w0, ws[14], p[11]); + word3_muladd(&w2, &w1, &w0, ws[15], p[10]); + word3_add(&w2, &w1, &w0, z[25]); + ws[9] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[11], p[15]); + word3_muladd(&w2, &w1, &w0, ws[12], p[14]); + word3_muladd(&w2, &w1, &w0, ws[13], p[13]); + word3_muladd(&w2, &w1, &w0, ws[14], p[12]); + word3_muladd(&w2, &w1, &w0, ws[15], p[11]); + word3_add(&w2, &w1, &w0, z[26]); + ws[10] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[12], p[15]); + word3_muladd(&w2, &w1, &w0, ws[13], p[14]); + word3_muladd(&w2, &w1, &w0, ws[14], p[13]); + word3_muladd(&w2, &w1, &w0, ws[15], p[12]); + word3_add(&w2, &w1, &w0, z[27]); + ws[11] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[13], p[15]); + word3_muladd(&w2, &w1, &w0, ws[14], p[14]); + word3_muladd(&w2, &w1, &w0, ws[15], p[13]); + word3_add(&w2, &w1, &w0, z[28]); + ws[12] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[14], p[15]); + word3_muladd(&w2, &w1, &w0, ws[15], p[14]); + word3_add(&w2, &w1, &w0, z[29]); + ws[13] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[15], p[15]); + word3_add(&w2, &w1, &w0, z[30]); + ws[14] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[31]); + ws[15] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[33]); + ws[16] = w0; + ws[17] = w1; + word borrow = bigint_sub3(ws + 16 + 1, ws, 16 + 1, p, 16); + CT::conditional_copy_mem(borrow, z, ws, ws + 17, 17); + clear_mem(z + 16, 2*(16+1) - 16); + } + +void bigint_monty_redc_24(word z[], const word p[24], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[8]); + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[8] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[8], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[9]); + word3_muladd(&w2, &w1, &w0, ws[1], p[8]); + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_muladd(&w2, &w1, &w0, ws[8], p[1]); + word3_add(&w2, &w1, &w0, z[9]); + ws[9] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[9], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[10]); + word3_muladd(&w2, &w1, &w0, ws[1], p[9]); + word3_muladd(&w2, &w1, &w0, ws[2], p[8]); + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_muladd(&w2, &w1, &w0, ws[8], p[2]); + word3_muladd(&w2, &w1, &w0, ws[9], p[1]); + word3_add(&w2, &w1, &w0, z[10]); + ws[10] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[10], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[11]); + word3_muladd(&w2, &w1, &w0, ws[1], p[10]); + word3_muladd(&w2, &w1, &w0, ws[2], p[9]); + word3_muladd(&w2, &w1, &w0, ws[3], p[8]); + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_muladd(&w2, &w1, &w0, ws[8], p[3]); + word3_muladd(&w2, &w1, &w0, ws[9], p[2]); + word3_muladd(&w2, &w1, &w0, ws[10], p[1]); + word3_add(&w2, &w1, &w0, z[11]); + ws[11] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[11], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[12]); + word3_muladd(&w2, &w1, &w0, ws[1], p[11]); + word3_muladd(&w2, &w1, &w0, ws[2], p[10]); + word3_muladd(&w2, &w1, &w0, ws[3], p[9]); + word3_muladd(&w2, &w1, &w0, ws[4], p[8]); + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_muladd(&w2, &w1, &w0, ws[8], p[4]); + word3_muladd(&w2, &w1, &w0, ws[9], p[3]); + word3_muladd(&w2, &w1, &w0, ws[10], p[2]); + word3_muladd(&w2, &w1, &w0, ws[11], p[1]); + word3_add(&w2, &w1, &w0, z[12]); + ws[12] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[12], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[13]); + word3_muladd(&w2, &w1, &w0, ws[1], p[12]); + word3_muladd(&w2, &w1, &w0, ws[2], p[11]); + word3_muladd(&w2, &w1, &w0, ws[3], p[10]); + word3_muladd(&w2, &w1, &w0, ws[4], p[9]); + word3_muladd(&w2, &w1, &w0, ws[5], p[8]); + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_muladd(&w2, &w1, &w0, ws[8], p[5]); + word3_muladd(&w2, &w1, &w0, ws[9], p[4]); + word3_muladd(&w2, &w1, &w0, ws[10], p[3]); + word3_muladd(&w2, &w1, &w0, ws[11], p[2]); + word3_muladd(&w2, &w1, &w0, ws[12], p[1]); + word3_add(&w2, &w1, &w0, z[13]); + ws[13] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[13], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[14]); + word3_muladd(&w2, &w1, &w0, ws[1], p[13]); + word3_muladd(&w2, &w1, &w0, ws[2], p[12]); + word3_muladd(&w2, &w1, &w0, ws[3], p[11]); + word3_muladd(&w2, &w1, &w0, ws[4], p[10]); + word3_muladd(&w2, &w1, &w0, ws[5], p[9]); + word3_muladd(&w2, &w1, &w0, ws[6], p[8]); + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_muladd(&w2, &w1, &w0, ws[8], p[6]); + word3_muladd(&w2, &w1, &w0, ws[9], p[5]); + word3_muladd(&w2, &w1, &w0, ws[10], p[4]); + word3_muladd(&w2, &w1, &w0, ws[11], p[3]); + word3_muladd(&w2, &w1, &w0, ws[12], p[2]); + word3_muladd(&w2, &w1, &w0, ws[13], p[1]); + word3_add(&w2, &w1, &w0, z[14]); + ws[14] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[14], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[15]); + word3_muladd(&w2, &w1, &w0, ws[1], p[14]); + word3_muladd(&w2, &w1, &w0, ws[2], p[13]); + word3_muladd(&w2, &w1, &w0, ws[3], p[12]); + word3_muladd(&w2, &w1, &w0, ws[4], p[11]); + word3_muladd(&w2, &w1, &w0, ws[5], p[10]); + word3_muladd(&w2, &w1, &w0, ws[6], p[9]); + word3_muladd(&w2, &w1, &w0, ws[7], p[8]); + word3_muladd(&w2, &w1, &w0, ws[8], p[7]); + word3_muladd(&w2, &w1, &w0, ws[9], p[6]); + word3_muladd(&w2, &w1, &w0, ws[10], p[5]); + word3_muladd(&w2, &w1, &w0, ws[11], p[4]); + word3_muladd(&w2, &w1, &w0, ws[12], p[3]); + word3_muladd(&w2, &w1, &w0, ws[13], p[2]); + word3_muladd(&w2, &w1, &w0, ws[14], p[1]); + word3_add(&w2, &w1, &w0, z[15]); + ws[15] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[15], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[16]); + word3_muladd(&w2, &w1, &w0, ws[1], p[15]); + word3_muladd(&w2, &w1, &w0, ws[2], p[14]); + word3_muladd(&w2, &w1, &w0, ws[3], p[13]); + word3_muladd(&w2, &w1, &w0, ws[4], p[12]); + word3_muladd(&w2, &w1, &w0, ws[5], p[11]); + word3_muladd(&w2, &w1, &w0, ws[6], p[10]); + word3_muladd(&w2, &w1, &w0, ws[7], p[9]); + word3_muladd(&w2, &w1, &w0, ws[8], p[8]); + word3_muladd(&w2, &w1, &w0, ws[9], p[7]); + word3_muladd(&w2, &w1, &w0, ws[10], p[6]); + word3_muladd(&w2, &w1, &w0, ws[11], p[5]); + word3_muladd(&w2, &w1, &w0, ws[12], p[4]); + word3_muladd(&w2, &w1, &w0, ws[13], p[3]); + word3_muladd(&w2, &w1, &w0, ws[14], p[2]); + word3_muladd(&w2, &w1, &w0, ws[15], p[1]); + word3_add(&w2, &w1, &w0, z[16]); + ws[16] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[16], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[17]); + word3_muladd(&w2, &w1, &w0, ws[1], p[16]); + word3_muladd(&w2, &w1, &w0, ws[2], p[15]); + word3_muladd(&w2, &w1, &w0, ws[3], p[14]); + word3_muladd(&w2, &w1, &w0, ws[4], p[13]); + word3_muladd(&w2, &w1, &w0, ws[5], p[12]); + word3_muladd(&w2, &w1, &w0, ws[6], p[11]); + word3_muladd(&w2, &w1, &w0, ws[7], p[10]); + word3_muladd(&w2, &w1, &w0, ws[8], p[9]); + word3_muladd(&w2, &w1, &w0, ws[9], p[8]); + word3_muladd(&w2, &w1, &w0, ws[10], p[7]); + word3_muladd(&w2, &w1, &w0, ws[11], p[6]); + word3_muladd(&w2, &w1, &w0, ws[12], p[5]); + word3_muladd(&w2, &w1, &w0, ws[13], p[4]); + word3_muladd(&w2, &w1, &w0, ws[14], p[3]); + word3_muladd(&w2, &w1, &w0, ws[15], p[2]); + word3_muladd(&w2, &w1, &w0, ws[16], p[1]); + word3_add(&w2, &w1, &w0, z[17]); + ws[17] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[17], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[18]); + word3_muladd(&w2, &w1, &w0, ws[1], p[17]); + word3_muladd(&w2, &w1, &w0, ws[2], p[16]); + word3_muladd(&w2, &w1, &w0, ws[3], p[15]); + word3_muladd(&w2, &w1, &w0, ws[4], p[14]); + word3_muladd(&w2, &w1, &w0, ws[5], p[13]); + word3_muladd(&w2, &w1, &w0, ws[6], p[12]); + word3_muladd(&w2, &w1, &w0, ws[7], p[11]); + word3_muladd(&w2, &w1, &w0, ws[8], p[10]); + word3_muladd(&w2, &w1, &w0, ws[9], p[9]); + word3_muladd(&w2, &w1, &w0, ws[10], p[8]); + word3_muladd(&w2, &w1, &w0, ws[11], p[7]); + word3_muladd(&w2, &w1, &w0, ws[12], p[6]); + word3_muladd(&w2, &w1, &w0, ws[13], p[5]); + word3_muladd(&w2, &w1, &w0, ws[14], p[4]); + word3_muladd(&w2, &w1, &w0, ws[15], p[3]); + word3_muladd(&w2, &w1, &w0, ws[16], p[2]); + word3_muladd(&w2, &w1, &w0, ws[17], p[1]); + word3_add(&w2, &w1, &w0, z[18]); + ws[18] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[18], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[19]); + word3_muladd(&w2, &w1, &w0, ws[1], p[18]); + word3_muladd(&w2, &w1, &w0, ws[2], p[17]); + word3_muladd(&w2, &w1, &w0, ws[3], p[16]); + word3_muladd(&w2, &w1, &w0, ws[4], p[15]); + word3_muladd(&w2, &w1, &w0, ws[5], p[14]); + word3_muladd(&w2, &w1, &w0, ws[6], p[13]); + word3_muladd(&w2, &w1, &w0, ws[7], p[12]); + word3_muladd(&w2, &w1, &w0, ws[8], p[11]); + word3_muladd(&w2, &w1, &w0, ws[9], p[10]); + word3_muladd(&w2, &w1, &w0, ws[10], p[9]); + word3_muladd(&w2, &w1, &w0, ws[11], p[8]); + word3_muladd(&w2, &w1, &w0, ws[12], p[7]); + word3_muladd(&w2, &w1, &w0, ws[13], p[6]); + word3_muladd(&w2, &w1, &w0, ws[14], p[5]); + word3_muladd(&w2, &w1, &w0, ws[15], p[4]); + word3_muladd(&w2, &w1, &w0, ws[16], p[3]); + word3_muladd(&w2, &w1, &w0, ws[17], p[2]); + word3_muladd(&w2, &w1, &w0, ws[18], p[1]); + word3_add(&w2, &w1, &w0, z[19]); + ws[19] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[19], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[20]); + word3_muladd(&w2, &w1, &w0, ws[1], p[19]); + word3_muladd(&w2, &w1, &w0, ws[2], p[18]); + word3_muladd(&w2, &w1, &w0, ws[3], p[17]); + word3_muladd(&w2, &w1, &w0, ws[4], p[16]); + word3_muladd(&w2, &w1, &w0, ws[5], p[15]); + word3_muladd(&w2, &w1, &w0, ws[6], p[14]); + word3_muladd(&w2, &w1, &w0, ws[7], p[13]); + word3_muladd(&w2, &w1, &w0, ws[8], p[12]); + word3_muladd(&w2, &w1, &w0, ws[9], p[11]); + word3_muladd(&w2, &w1, &w0, ws[10], p[10]); + word3_muladd(&w2, &w1, &w0, ws[11], p[9]); + word3_muladd(&w2, &w1, &w0, ws[12], p[8]); + word3_muladd(&w2, &w1, &w0, ws[13], p[7]); + word3_muladd(&w2, &w1, &w0, ws[14], p[6]); + word3_muladd(&w2, &w1, &w0, ws[15], p[5]); + word3_muladd(&w2, &w1, &w0, ws[16], p[4]); + word3_muladd(&w2, &w1, &w0, ws[17], p[3]); + word3_muladd(&w2, &w1, &w0, ws[18], p[2]); + word3_muladd(&w2, &w1, &w0, ws[19], p[1]); + word3_add(&w2, &w1, &w0, z[20]); + ws[20] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[20], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[21]); + word3_muladd(&w2, &w1, &w0, ws[1], p[20]); + word3_muladd(&w2, &w1, &w0, ws[2], p[19]); + word3_muladd(&w2, &w1, &w0, ws[3], p[18]); + word3_muladd(&w2, &w1, &w0, ws[4], p[17]); + word3_muladd(&w2, &w1, &w0, ws[5], p[16]); + word3_muladd(&w2, &w1, &w0, ws[6], p[15]); + word3_muladd(&w2, &w1, &w0, ws[7], p[14]); + word3_muladd(&w2, &w1, &w0, ws[8], p[13]); + word3_muladd(&w2, &w1, &w0, ws[9], p[12]); + word3_muladd(&w2, &w1, &w0, ws[10], p[11]); + word3_muladd(&w2, &w1, &w0, ws[11], p[10]); + word3_muladd(&w2, &w1, &w0, ws[12], p[9]); + word3_muladd(&w2, &w1, &w0, ws[13], p[8]); + word3_muladd(&w2, &w1, &w0, ws[14], p[7]); + word3_muladd(&w2, &w1, &w0, ws[15], p[6]); + word3_muladd(&w2, &w1, &w0, ws[16], p[5]); + word3_muladd(&w2, &w1, &w0, ws[17], p[4]); + word3_muladd(&w2, &w1, &w0, ws[18], p[3]); + word3_muladd(&w2, &w1, &w0, ws[19], p[2]); + word3_muladd(&w2, &w1, &w0, ws[20], p[1]); + word3_add(&w2, &w1, &w0, z[21]); + ws[21] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[21], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[22]); + word3_muladd(&w2, &w1, &w0, ws[1], p[21]); + word3_muladd(&w2, &w1, &w0, ws[2], p[20]); + word3_muladd(&w2, &w1, &w0, ws[3], p[19]); + word3_muladd(&w2, &w1, &w0, ws[4], p[18]); + word3_muladd(&w2, &w1, &w0, ws[5], p[17]); + word3_muladd(&w2, &w1, &w0, ws[6], p[16]); + word3_muladd(&w2, &w1, &w0, ws[7], p[15]); + word3_muladd(&w2, &w1, &w0, ws[8], p[14]); + word3_muladd(&w2, &w1, &w0, ws[9], p[13]); + word3_muladd(&w2, &w1, &w0, ws[10], p[12]); + word3_muladd(&w2, &w1, &w0, ws[11], p[11]); + word3_muladd(&w2, &w1, &w0, ws[12], p[10]); + word3_muladd(&w2, &w1, &w0, ws[13], p[9]); + word3_muladd(&w2, &w1, &w0, ws[14], p[8]); + word3_muladd(&w2, &w1, &w0, ws[15], p[7]); + word3_muladd(&w2, &w1, &w0, ws[16], p[6]); + word3_muladd(&w2, &w1, &w0, ws[17], p[5]); + word3_muladd(&w2, &w1, &w0, ws[18], p[4]); + word3_muladd(&w2, &w1, &w0, ws[19], p[3]); + word3_muladd(&w2, &w1, &w0, ws[20], p[2]); + word3_muladd(&w2, &w1, &w0, ws[21], p[1]); + word3_add(&w2, &w1, &w0, z[22]); + ws[22] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[22], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[23]); + word3_muladd(&w2, &w1, &w0, ws[1], p[22]); + word3_muladd(&w2, &w1, &w0, ws[2], p[21]); + word3_muladd(&w2, &w1, &w0, ws[3], p[20]); + word3_muladd(&w2, &w1, &w0, ws[4], p[19]); + word3_muladd(&w2, &w1, &w0, ws[5], p[18]); + word3_muladd(&w2, &w1, &w0, ws[6], p[17]); + word3_muladd(&w2, &w1, &w0, ws[7], p[16]); + word3_muladd(&w2, &w1, &w0, ws[8], p[15]); + word3_muladd(&w2, &w1, &w0, ws[9], p[14]); + word3_muladd(&w2, &w1, &w0, ws[10], p[13]); + word3_muladd(&w2, &w1, &w0, ws[11], p[12]); + word3_muladd(&w2, &w1, &w0, ws[12], p[11]); + word3_muladd(&w2, &w1, &w0, ws[13], p[10]); + word3_muladd(&w2, &w1, &w0, ws[14], p[9]); + word3_muladd(&w2, &w1, &w0, ws[15], p[8]); + word3_muladd(&w2, &w1, &w0, ws[16], p[7]); + word3_muladd(&w2, &w1, &w0, ws[17], p[6]); + word3_muladd(&w2, &w1, &w0, ws[18], p[5]); + word3_muladd(&w2, &w1, &w0, ws[19], p[4]); + word3_muladd(&w2, &w1, &w0, ws[20], p[3]); + word3_muladd(&w2, &w1, &w0, ws[21], p[2]); + word3_muladd(&w2, &w1, &w0, ws[22], p[1]); + word3_add(&w2, &w1, &w0, z[23]); + ws[23] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[23], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[23]); + word3_muladd(&w2, &w1, &w0, ws[2], p[22]); + word3_muladd(&w2, &w1, &w0, ws[3], p[21]); + word3_muladd(&w2, &w1, &w0, ws[4], p[20]); + word3_muladd(&w2, &w1, &w0, ws[5], p[19]); + word3_muladd(&w2, &w1, &w0, ws[6], p[18]); + word3_muladd(&w2, &w1, &w0, ws[7], p[17]); + word3_muladd(&w2, &w1, &w0, ws[8], p[16]); + word3_muladd(&w2, &w1, &w0, ws[9], p[15]); + word3_muladd(&w2, &w1, &w0, ws[10], p[14]); + word3_muladd(&w2, &w1, &w0, ws[11], p[13]); + word3_muladd(&w2, &w1, &w0, ws[12], p[12]); + word3_muladd(&w2, &w1, &w0, ws[13], p[11]); + word3_muladd(&w2, &w1, &w0, ws[14], p[10]); + word3_muladd(&w2, &w1, &w0, ws[15], p[9]); + word3_muladd(&w2, &w1, &w0, ws[16], p[8]); + word3_muladd(&w2, &w1, &w0, ws[17], p[7]); + word3_muladd(&w2, &w1, &w0, ws[18], p[6]); + word3_muladd(&w2, &w1, &w0, ws[19], p[5]); + word3_muladd(&w2, &w1, &w0, ws[20], p[4]); + word3_muladd(&w2, &w1, &w0, ws[21], p[3]); + word3_muladd(&w2, &w1, &w0, ws[22], p[2]); + word3_muladd(&w2, &w1, &w0, ws[23], p[1]); + word3_add(&w2, &w1, &w0, z[24]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[23]); + word3_muladd(&w2, &w1, &w0, ws[3], p[22]); + word3_muladd(&w2, &w1, &w0, ws[4], p[21]); + word3_muladd(&w2, &w1, &w0, ws[5], p[20]); + word3_muladd(&w2, &w1, &w0, ws[6], p[19]); + word3_muladd(&w2, &w1, &w0, ws[7], p[18]); + word3_muladd(&w2, &w1, &w0, ws[8], p[17]); + word3_muladd(&w2, &w1, &w0, ws[9], p[16]); + word3_muladd(&w2, &w1, &w0, ws[10], p[15]); + word3_muladd(&w2, &w1, &w0, ws[11], p[14]); + word3_muladd(&w2, &w1, &w0, ws[12], p[13]); + word3_muladd(&w2, &w1, &w0, ws[13], p[12]); + word3_muladd(&w2, &w1, &w0, ws[14], p[11]); + word3_muladd(&w2, &w1, &w0, ws[15], p[10]); + word3_muladd(&w2, &w1, &w0, ws[16], p[9]); + word3_muladd(&w2, &w1, &w0, ws[17], p[8]); + word3_muladd(&w2, &w1, &w0, ws[18], p[7]); + word3_muladd(&w2, &w1, &w0, ws[19], p[6]); + word3_muladd(&w2, &w1, &w0, ws[20], p[5]); + word3_muladd(&w2, &w1, &w0, ws[21], p[4]); + word3_muladd(&w2, &w1, &w0, ws[22], p[3]); + word3_muladd(&w2, &w1, &w0, ws[23], p[2]); + word3_add(&w2, &w1, &w0, z[25]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[23]); + word3_muladd(&w2, &w1, &w0, ws[4], p[22]); + word3_muladd(&w2, &w1, &w0, ws[5], p[21]); + word3_muladd(&w2, &w1, &w0, ws[6], p[20]); + word3_muladd(&w2, &w1, &w0, ws[7], p[19]); + word3_muladd(&w2, &w1, &w0, ws[8], p[18]); + word3_muladd(&w2, &w1, &w0, ws[9], p[17]); + word3_muladd(&w2, &w1, &w0, ws[10], p[16]); + word3_muladd(&w2, &w1, &w0, ws[11], p[15]); + word3_muladd(&w2, &w1, &w0, ws[12], p[14]); + word3_muladd(&w2, &w1, &w0, ws[13], p[13]); + word3_muladd(&w2, &w1, &w0, ws[14], p[12]); + word3_muladd(&w2, &w1, &w0, ws[15], p[11]); + word3_muladd(&w2, &w1, &w0, ws[16], p[10]); + word3_muladd(&w2, &w1, &w0, ws[17], p[9]); + word3_muladd(&w2, &w1, &w0, ws[18], p[8]); + word3_muladd(&w2, &w1, &w0, ws[19], p[7]); + word3_muladd(&w2, &w1, &w0, ws[20], p[6]); + word3_muladd(&w2, &w1, &w0, ws[21], p[5]); + word3_muladd(&w2, &w1, &w0, ws[22], p[4]); + word3_muladd(&w2, &w1, &w0, ws[23], p[3]); + word3_add(&w2, &w1, &w0, z[26]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[23]); + word3_muladd(&w2, &w1, &w0, ws[5], p[22]); + word3_muladd(&w2, &w1, &w0, ws[6], p[21]); + word3_muladd(&w2, &w1, &w0, ws[7], p[20]); + word3_muladd(&w2, &w1, &w0, ws[8], p[19]); + word3_muladd(&w2, &w1, &w0, ws[9], p[18]); + word3_muladd(&w2, &w1, &w0, ws[10], p[17]); + word3_muladd(&w2, &w1, &w0, ws[11], p[16]); + word3_muladd(&w2, &w1, &w0, ws[12], p[15]); + word3_muladd(&w2, &w1, &w0, ws[13], p[14]); + word3_muladd(&w2, &w1, &w0, ws[14], p[13]); + word3_muladd(&w2, &w1, &w0, ws[15], p[12]); + word3_muladd(&w2, &w1, &w0, ws[16], p[11]); + word3_muladd(&w2, &w1, &w0, ws[17], p[10]); + word3_muladd(&w2, &w1, &w0, ws[18], p[9]); + word3_muladd(&w2, &w1, &w0, ws[19], p[8]); + word3_muladd(&w2, &w1, &w0, ws[20], p[7]); + word3_muladd(&w2, &w1, &w0, ws[21], p[6]); + word3_muladd(&w2, &w1, &w0, ws[22], p[5]); + word3_muladd(&w2, &w1, &w0, ws[23], p[4]); + word3_add(&w2, &w1, &w0, z[27]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[23]); + word3_muladd(&w2, &w1, &w0, ws[6], p[22]); + word3_muladd(&w2, &w1, &w0, ws[7], p[21]); + word3_muladd(&w2, &w1, &w0, ws[8], p[20]); + word3_muladd(&w2, &w1, &w0, ws[9], p[19]); + word3_muladd(&w2, &w1, &w0, ws[10], p[18]); + word3_muladd(&w2, &w1, &w0, ws[11], p[17]); + word3_muladd(&w2, &w1, &w0, ws[12], p[16]); + word3_muladd(&w2, &w1, &w0, ws[13], p[15]); + word3_muladd(&w2, &w1, &w0, ws[14], p[14]); + word3_muladd(&w2, &w1, &w0, ws[15], p[13]); + word3_muladd(&w2, &w1, &w0, ws[16], p[12]); + word3_muladd(&w2, &w1, &w0, ws[17], p[11]); + word3_muladd(&w2, &w1, &w0, ws[18], p[10]); + word3_muladd(&w2, &w1, &w0, ws[19], p[9]); + word3_muladd(&w2, &w1, &w0, ws[20], p[8]); + word3_muladd(&w2, &w1, &w0, ws[21], p[7]); + word3_muladd(&w2, &w1, &w0, ws[22], p[6]); + word3_muladd(&w2, &w1, &w0, ws[23], p[5]); + word3_add(&w2, &w1, &w0, z[28]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[23]); + word3_muladd(&w2, &w1, &w0, ws[7], p[22]); + word3_muladd(&w2, &w1, &w0, ws[8], p[21]); + word3_muladd(&w2, &w1, &w0, ws[9], p[20]); + word3_muladd(&w2, &w1, &w0, ws[10], p[19]); + word3_muladd(&w2, &w1, &w0, ws[11], p[18]); + word3_muladd(&w2, &w1, &w0, ws[12], p[17]); + word3_muladd(&w2, &w1, &w0, ws[13], p[16]); + word3_muladd(&w2, &w1, &w0, ws[14], p[15]); + word3_muladd(&w2, &w1, &w0, ws[15], p[14]); + word3_muladd(&w2, &w1, &w0, ws[16], p[13]); + word3_muladd(&w2, &w1, &w0, ws[17], p[12]); + word3_muladd(&w2, &w1, &w0, ws[18], p[11]); + word3_muladd(&w2, &w1, &w0, ws[19], p[10]); + word3_muladd(&w2, &w1, &w0, ws[20], p[9]); + word3_muladd(&w2, &w1, &w0, ws[21], p[8]); + word3_muladd(&w2, &w1, &w0, ws[22], p[7]); + word3_muladd(&w2, &w1, &w0, ws[23], p[6]); + word3_add(&w2, &w1, &w0, z[29]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[23]); + word3_muladd(&w2, &w1, &w0, ws[8], p[22]); + word3_muladd(&w2, &w1, &w0, ws[9], p[21]); + word3_muladd(&w2, &w1, &w0, ws[10], p[20]); + word3_muladd(&w2, &w1, &w0, ws[11], p[19]); + word3_muladd(&w2, &w1, &w0, ws[12], p[18]); + word3_muladd(&w2, &w1, &w0, ws[13], p[17]); + word3_muladd(&w2, &w1, &w0, ws[14], p[16]); + word3_muladd(&w2, &w1, &w0, ws[15], p[15]); + word3_muladd(&w2, &w1, &w0, ws[16], p[14]); + word3_muladd(&w2, &w1, &w0, ws[17], p[13]); + word3_muladd(&w2, &w1, &w0, ws[18], p[12]); + word3_muladd(&w2, &w1, &w0, ws[19], p[11]); + word3_muladd(&w2, &w1, &w0, ws[20], p[10]); + word3_muladd(&w2, &w1, &w0, ws[21], p[9]); + word3_muladd(&w2, &w1, &w0, ws[22], p[8]); + word3_muladd(&w2, &w1, &w0, ws[23], p[7]); + word3_add(&w2, &w1, &w0, z[30]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[8], p[23]); + word3_muladd(&w2, &w1, &w0, ws[9], p[22]); + word3_muladd(&w2, &w1, &w0, ws[10], p[21]); + word3_muladd(&w2, &w1, &w0, ws[11], p[20]); + word3_muladd(&w2, &w1, &w0, ws[12], p[19]); + word3_muladd(&w2, &w1, &w0, ws[13], p[18]); + word3_muladd(&w2, &w1, &w0, ws[14], p[17]); + word3_muladd(&w2, &w1, &w0, ws[15], p[16]); + word3_muladd(&w2, &w1, &w0, ws[16], p[15]); + word3_muladd(&w2, &w1, &w0, ws[17], p[14]); + word3_muladd(&w2, &w1, &w0, ws[18], p[13]); + word3_muladd(&w2, &w1, &w0, ws[19], p[12]); + word3_muladd(&w2, &w1, &w0, ws[20], p[11]); + word3_muladd(&w2, &w1, &w0, ws[21], p[10]); + word3_muladd(&w2, &w1, &w0, ws[22], p[9]); + word3_muladd(&w2, &w1, &w0, ws[23], p[8]); + word3_add(&w2, &w1, &w0, z[31]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[9], p[23]); + word3_muladd(&w2, &w1, &w0, ws[10], p[22]); + word3_muladd(&w2, &w1, &w0, ws[11], p[21]); + word3_muladd(&w2, &w1, &w0, ws[12], p[20]); + word3_muladd(&w2, &w1, &w0, ws[13], p[19]); + word3_muladd(&w2, &w1, &w0, ws[14], p[18]); + word3_muladd(&w2, &w1, &w0, ws[15], p[17]); + word3_muladd(&w2, &w1, &w0, ws[16], p[16]); + word3_muladd(&w2, &w1, &w0, ws[17], p[15]); + word3_muladd(&w2, &w1, &w0, ws[18], p[14]); + word3_muladd(&w2, &w1, &w0, ws[19], p[13]); + word3_muladd(&w2, &w1, &w0, ws[20], p[12]); + word3_muladd(&w2, &w1, &w0, ws[21], p[11]); + word3_muladd(&w2, &w1, &w0, ws[22], p[10]); + word3_muladd(&w2, &w1, &w0, ws[23], p[9]); + word3_add(&w2, &w1, &w0, z[32]); + ws[8] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[10], p[23]); + word3_muladd(&w2, &w1, &w0, ws[11], p[22]); + word3_muladd(&w2, &w1, &w0, ws[12], p[21]); + word3_muladd(&w2, &w1, &w0, ws[13], p[20]); + word3_muladd(&w2, &w1, &w0, ws[14], p[19]); + word3_muladd(&w2, &w1, &w0, ws[15], p[18]); + word3_muladd(&w2, &w1, &w0, ws[16], p[17]); + word3_muladd(&w2, &w1, &w0, ws[17], p[16]); + word3_muladd(&w2, &w1, &w0, ws[18], p[15]); + word3_muladd(&w2, &w1, &w0, ws[19], p[14]); + word3_muladd(&w2, &w1, &w0, ws[20], p[13]); + word3_muladd(&w2, &w1, &w0, ws[21], p[12]); + word3_muladd(&w2, &w1, &w0, ws[22], p[11]); + word3_muladd(&w2, &w1, &w0, ws[23], p[10]); + word3_add(&w2, &w1, &w0, z[33]); + ws[9] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[11], p[23]); + word3_muladd(&w2, &w1, &w0, ws[12], p[22]); + word3_muladd(&w2, &w1, &w0, ws[13], p[21]); + word3_muladd(&w2, &w1, &w0, ws[14], p[20]); + word3_muladd(&w2, &w1, &w0, ws[15], p[19]); + word3_muladd(&w2, &w1, &w0, ws[16], p[18]); + word3_muladd(&w2, &w1, &w0, ws[17], p[17]); + word3_muladd(&w2, &w1, &w0, ws[18], p[16]); + word3_muladd(&w2, &w1, &w0, ws[19], p[15]); + word3_muladd(&w2, &w1, &w0, ws[20], p[14]); + word3_muladd(&w2, &w1, &w0, ws[21], p[13]); + word3_muladd(&w2, &w1, &w0, ws[22], p[12]); + word3_muladd(&w2, &w1, &w0, ws[23], p[11]); + word3_add(&w2, &w1, &w0, z[34]); + ws[10] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[12], p[23]); + word3_muladd(&w2, &w1, &w0, ws[13], p[22]); + word3_muladd(&w2, &w1, &w0, ws[14], p[21]); + word3_muladd(&w2, &w1, &w0, ws[15], p[20]); + word3_muladd(&w2, &w1, &w0, ws[16], p[19]); + word3_muladd(&w2, &w1, &w0, ws[17], p[18]); + word3_muladd(&w2, &w1, &w0, ws[18], p[17]); + word3_muladd(&w2, &w1, &w0, ws[19], p[16]); + word3_muladd(&w2, &w1, &w0, ws[20], p[15]); + word3_muladd(&w2, &w1, &w0, ws[21], p[14]); + word3_muladd(&w2, &w1, &w0, ws[22], p[13]); + word3_muladd(&w2, &w1, &w0, ws[23], p[12]); + word3_add(&w2, &w1, &w0, z[35]); + ws[11] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[13], p[23]); + word3_muladd(&w2, &w1, &w0, ws[14], p[22]); + word3_muladd(&w2, &w1, &w0, ws[15], p[21]); + word3_muladd(&w2, &w1, &w0, ws[16], p[20]); + word3_muladd(&w2, &w1, &w0, ws[17], p[19]); + word3_muladd(&w2, &w1, &w0, ws[18], p[18]); + word3_muladd(&w2, &w1, &w0, ws[19], p[17]); + word3_muladd(&w2, &w1, &w0, ws[20], p[16]); + word3_muladd(&w2, &w1, &w0, ws[21], p[15]); + word3_muladd(&w2, &w1, &w0, ws[22], p[14]); + word3_muladd(&w2, &w1, &w0, ws[23], p[13]); + word3_add(&w2, &w1, &w0, z[36]); + ws[12] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[14], p[23]); + word3_muladd(&w2, &w1, &w0, ws[15], p[22]); + word3_muladd(&w2, &w1, &w0, ws[16], p[21]); + word3_muladd(&w2, &w1, &w0, ws[17], p[20]); + word3_muladd(&w2, &w1, &w0, ws[18], p[19]); + word3_muladd(&w2, &w1, &w0, ws[19], p[18]); + word3_muladd(&w2, &w1, &w0, ws[20], p[17]); + word3_muladd(&w2, &w1, &w0, ws[21], p[16]); + word3_muladd(&w2, &w1, &w0, ws[22], p[15]); + word3_muladd(&w2, &w1, &w0, ws[23], p[14]); + word3_add(&w2, &w1, &w0, z[37]); + ws[13] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[15], p[23]); + word3_muladd(&w2, &w1, &w0, ws[16], p[22]); + word3_muladd(&w2, &w1, &w0, ws[17], p[21]); + word3_muladd(&w2, &w1, &w0, ws[18], p[20]); + word3_muladd(&w2, &w1, &w0, ws[19], p[19]); + word3_muladd(&w2, &w1, &w0, ws[20], p[18]); + word3_muladd(&w2, &w1, &w0, ws[21], p[17]); + word3_muladd(&w2, &w1, &w0, ws[22], p[16]); + word3_muladd(&w2, &w1, &w0, ws[23], p[15]); + word3_add(&w2, &w1, &w0, z[38]); + ws[14] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[16], p[23]); + word3_muladd(&w2, &w1, &w0, ws[17], p[22]); + word3_muladd(&w2, &w1, &w0, ws[18], p[21]); + word3_muladd(&w2, &w1, &w0, ws[19], p[20]); + word3_muladd(&w2, &w1, &w0, ws[20], p[19]); + word3_muladd(&w2, &w1, &w0, ws[21], p[18]); + word3_muladd(&w2, &w1, &w0, ws[22], p[17]); + word3_muladd(&w2, &w1, &w0, ws[23], p[16]); + word3_add(&w2, &w1, &w0, z[39]); + ws[15] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[17], p[23]); + word3_muladd(&w2, &w1, &w0, ws[18], p[22]); + word3_muladd(&w2, &w1, &w0, ws[19], p[21]); + word3_muladd(&w2, &w1, &w0, ws[20], p[20]); + word3_muladd(&w2, &w1, &w0, ws[21], p[19]); + word3_muladd(&w2, &w1, &w0, ws[22], p[18]); + word3_muladd(&w2, &w1, &w0, ws[23], p[17]); + word3_add(&w2, &w1, &w0, z[40]); + ws[16] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[18], p[23]); + word3_muladd(&w2, &w1, &w0, ws[19], p[22]); + word3_muladd(&w2, &w1, &w0, ws[20], p[21]); + word3_muladd(&w2, &w1, &w0, ws[21], p[20]); + word3_muladd(&w2, &w1, &w0, ws[22], p[19]); + word3_muladd(&w2, &w1, &w0, ws[23], p[18]); + word3_add(&w2, &w1, &w0, z[41]); + ws[17] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[19], p[23]); + word3_muladd(&w2, &w1, &w0, ws[20], p[22]); + word3_muladd(&w2, &w1, &w0, ws[21], p[21]); + word3_muladd(&w2, &w1, &w0, ws[22], p[20]); + word3_muladd(&w2, &w1, &w0, ws[23], p[19]); + word3_add(&w2, &w1, &w0, z[42]); + ws[18] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[20], p[23]); + word3_muladd(&w2, &w1, &w0, ws[21], p[22]); + word3_muladd(&w2, &w1, &w0, ws[22], p[21]); + word3_muladd(&w2, &w1, &w0, ws[23], p[20]); + word3_add(&w2, &w1, &w0, z[43]); + ws[19] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[21], p[23]); + word3_muladd(&w2, &w1, &w0, ws[22], p[22]); + word3_muladd(&w2, &w1, &w0, ws[23], p[21]); + word3_add(&w2, &w1, &w0, z[44]); + ws[20] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[22], p[23]); + word3_muladd(&w2, &w1, &w0, ws[23], p[22]); + word3_add(&w2, &w1, &w0, z[45]); + ws[21] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[23], p[23]); + word3_add(&w2, &w1, &w0, z[46]); + ws[22] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[47]); + ws[23] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[49]); + ws[24] = w0; + ws[25] = w1; + word borrow = bigint_sub3(ws + 24 + 1, ws, 24 + 1, p, 24); + CT::conditional_copy_mem(borrow, z, ws, ws + 25, 25); + clear_mem(z + 24, 2*(24+1) - 24); + } + +void bigint_monty_redc_32(word z[], const word p[32], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[8]); + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[8] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[8], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[9]); + word3_muladd(&w2, &w1, &w0, ws[1], p[8]); + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_muladd(&w2, &w1, &w0, ws[8], p[1]); + word3_add(&w2, &w1, &w0, z[9]); + ws[9] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[9], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[10]); + word3_muladd(&w2, &w1, &w0, ws[1], p[9]); + word3_muladd(&w2, &w1, &w0, ws[2], p[8]); + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_muladd(&w2, &w1, &w0, ws[8], p[2]); + word3_muladd(&w2, &w1, &w0, ws[9], p[1]); + word3_add(&w2, &w1, &w0, z[10]); + ws[10] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[10], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[11]); + word3_muladd(&w2, &w1, &w0, ws[1], p[10]); + word3_muladd(&w2, &w1, &w0, ws[2], p[9]); + word3_muladd(&w2, &w1, &w0, ws[3], p[8]); + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_muladd(&w2, &w1, &w0, ws[8], p[3]); + word3_muladd(&w2, &w1, &w0, ws[9], p[2]); + word3_muladd(&w2, &w1, &w0, ws[10], p[1]); + word3_add(&w2, &w1, &w0, z[11]); + ws[11] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[11], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[12]); + word3_muladd(&w2, &w1, &w0, ws[1], p[11]); + word3_muladd(&w2, &w1, &w0, ws[2], p[10]); + word3_muladd(&w2, &w1, &w0, ws[3], p[9]); + word3_muladd(&w2, &w1, &w0, ws[4], p[8]); + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_muladd(&w2, &w1, &w0, ws[8], p[4]); + word3_muladd(&w2, &w1, &w0, ws[9], p[3]); + word3_muladd(&w2, &w1, &w0, ws[10], p[2]); + word3_muladd(&w2, &w1, &w0, ws[11], p[1]); + word3_add(&w2, &w1, &w0, z[12]); + ws[12] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[12], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[13]); + word3_muladd(&w2, &w1, &w0, ws[1], p[12]); + word3_muladd(&w2, &w1, &w0, ws[2], p[11]); + word3_muladd(&w2, &w1, &w0, ws[3], p[10]); + word3_muladd(&w2, &w1, &w0, ws[4], p[9]); + word3_muladd(&w2, &w1, &w0, ws[5], p[8]); + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_muladd(&w2, &w1, &w0, ws[8], p[5]); + word3_muladd(&w2, &w1, &w0, ws[9], p[4]); + word3_muladd(&w2, &w1, &w0, ws[10], p[3]); + word3_muladd(&w2, &w1, &w0, ws[11], p[2]); + word3_muladd(&w2, &w1, &w0, ws[12], p[1]); + word3_add(&w2, &w1, &w0, z[13]); + ws[13] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[13], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[14]); + word3_muladd(&w2, &w1, &w0, ws[1], p[13]); + word3_muladd(&w2, &w1, &w0, ws[2], p[12]); + word3_muladd(&w2, &w1, &w0, ws[3], p[11]); + word3_muladd(&w2, &w1, &w0, ws[4], p[10]); + word3_muladd(&w2, &w1, &w0, ws[5], p[9]); + word3_muladd(&w2, &w1, &w0, ws[6], p[8]); + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_muladd(&w2, &w1, &w0, ws[8], p[6]); + word3_muladd(&w2, &w1, &w0, ws[9], p[5]); + word3_muladd(&w2, &w1, &w0, ws[10], p[4]); + word3_muladd(&w2, &w1, &w0, ws[11], p[3]); + word3_muladd(&w2, &w1, &w0, ws[12], p[2]); + word3_muladd(&w2, &w1, &w0, ws[13], p[1]); + word3_add(&w2, &w1, &w0, z[14]); + ws[14] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[14], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[15]); + word3_muladd(&w2, &w1, &w0, ws[1], p[14]); + word3_muladd(&w2, &w1, &w0, ws[2], p[13]); + word3_muladd(&w2, &w1, &w0, ws[3], p[12]); + word3_muladd(&w2, &w1, &w0, ws[4], p[11]); + word3_muladd(&w2, &w1, &w0, ws[5], p[10]); + word3_muladd(&w2, &w1, &w0, ws[6], p[9]); + word3_muladd(&w2, &w1, &w0, ws[7], p[8]); + word3_muladd(&w2, &w1, &w0, ws[8], p[7]); + word3_muladd(&w2, &w1, &w0, ws[9], p[6]); + word3_muladd(&w2, &w1, &w0, ws[10], p[5]); + word3_muladd(&w2, &w1, &w0, ws[11], p[4]); + word3_muladd(&w2, &w1, &w0, ws[12], p[3]); + word3_muladd(&w2, &w1, &w0, ws[13], p[2]); + word3_muladd(&w2, &w1, &w0, ws[14], p[1]); + word3_add(&w2, &w1, &w0, z[15]); + ws[15] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[15], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[16]); + word3_muladd(&w2, &w1, &w0, ws[1], p[15]); + word3_muladd(&w2, &w1, &w0, ws[2], p[14]); + word3_muladd(&w2, &w1, &w0, ws[3], p[13]); + word3_muladd(&w2, &w1, &w0, ws[4], p[12]); + word3_muladd(&w2, &w1, &w0, ws[5], p[11]); + word3_muladd(&w2, &w1, &w0, ws[6], p[10]); + word3_muladd(&w2, &w1, &w0, ws[7], p[9]); + word3_muladd(&w2, &w1, &w0, ws[8], p[8]); + word3_muladd(&w2, &w1, &w0, ws[9], p[7]); + word3_muladd(&w2, &w1, &w0, ws[10], p[6]); + word3_muladd(&w2, &w1, &w0, ws[11], p[5]); + word3_muladd(&w2, &w1, &w0, ws[12], p[4]); + word3_muladd(&w2, &w1, &w0, ws[13], p[3]); + word3_muladd(&w2, &w1, &w0, ws[14], p[2]); + word3_muladd(&w2, &w1, &w0, ws[15], p[1]); + word3_add(&w2, &w1, &w0, z[16]); + ws[16] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[16], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[17]); + word3_muladd(&w2, &w1, &w0, ws[1], p[16]); + word3_muladd(&w2, &w1, &w0, ws[2], p[15]); + word3_muladd(&w2, &w1, &w0, ws[3], p[14]); + word3_muladd(&w2, &w1, &w0, ws[4], p[13]); + word3_muladd(&w2, &w1, &w0, ws[5], p[12]); + word3_muladd(&w2, &w1, &w0, ws[6], p[11]); + word3_muladd(&w2, &w1, &w0, ws[7], p[10]); + word3_muladd(&w2, &w1, &w0, ws[8], p[9]); + word3_muladd(&w2, &w1, &w0, ws[9], p[8]); + word3_muladd(&w2, &w1, &w0, ws[10], p[7]); + word3_muladd(&w2, &w1, &w0, ws[11], p[6]); + word3_muladd(&w2, &w1, &w0, ws[12], p[5]); + word3_muladd(&w2, &w1, &w0, ws[13], p[4]); + word3_muladd(&w2, &w1, &w0, ws[14], p[3]); + word3_muladd(&w2, &w1, &w0, ws[15], p[2]); + word3_muladd(&w2, &w1, &w0, ws[16], p[1]); + word3_add(&w2, &w1, &w0, z[17]); + ws[17] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[17], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[18]); + word3_muladd(&w2, &w1, &w0, ws[1], p[17]); + word3_muladd(&w2, &w1, &w0, ws[2], p[16]); + word3_muladd(&w2, &w1, &w0, ws[3], p[15]); + word3_muladd(&w2, &w1, &w0, ws[4], p[14]); + word3_muladd(&w2, &w1, &w0, ws[5], p[13]); + word3_muladd(&w2, &w1, &w0, ws[6], p[12]); + word3_muladd(&w2, &w1, &w0, ws[7], p[11]); + word3_muladd(&w2, &w1, &w0, ws[8], p[10]); + word3_muladd(&w2, &w1, &w0, ws[9], p[9]); + word3_muladd(&w2, &w1, &w0, ws[10], p[8]); + word3_muladd(&w2, &w1, &w0, ws[11], p[7]); + word3_muladd(&w2, &w1, &w0, ws[12], p[6]); + word3_muladd(&w2, &w1, &w0, ws[13], p[5]); + word3_muladd(&w2, &w1, &w0, ws[14], p[4]); + word3_muladd(&w2, &w1, &w0, ws[15], p[3]); + word3_muladd(&w2, &w1, &w0, ws[16], p[2]); + word3_muladd(&w2, &w1, &w0, ws[17], p[1]); + word3_add(&w2, &w1, &w0, z[18]); + ws[18] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[18], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[19]); + word3_muladd(&w2, &w1, &w0, ws[1], p[18]); + word3_muladd(&w2, &w1, &w0, ws[2], p[17]); + word3_muladd(&w2, &w1, &w0, ws[3], p[16]); + word3_muladd(&w2, &w1, &w0, ws[4], p[15]); + word3_muladd(&w2, &w1, &w0, ws[5], p[14]); + word3_muladd(&w2, &w1, &w0, ws[6], p[13]); + word3_muladd(&w2, &w1, &w0, ws[7], p[12]); + word3_muladd(&w2, &w1, &w0, ws[8], p[11]); + word3_muladd(&w2, &w1, &w0, ws[9], p[10]); + word3_muladd(&w2, &w1, &w0, ws[10], p[9]); + word3_muladd(&w2, &w1, &w0, ws[11], p[8]); + word3_muladd(&w2, &w1, &w0, ws[12], p[7]); + word3_muladd(&w2, &w1, &w0, ws[13], p[6]); + word3_muladd(&w2, &w1, &w0, ws[14], p[5]); + word3_muladd(&w2, &w1, &w0, ws[15], p[4]); + word3_muladd(&w2, &w1, &w0, ws[16], p[3]); + word3_muladd(&w2, &w1, &w0, ws[17], p[2]); + word3_muladd(&w2, &w1, &w0, ws[18], p[1]); + word3_add(&w2, &w1, &w0, z[19]); + ws[19] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[19], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[20]); + word3_muladd(&w2, &w1, &w0, ws[1], p[19]); + word3_muladd(&w2, &w1, &w0, ws[2], p[18]); + word3_muladd(&w2, &w1, &w0, ws[3], p[17]); + word3_muladd(&w2, &w1, &w0, ws[4], p[16]); + word3_muladd(&w2, &w1, &w0, ws[5], p[15]); + word3_muladd(&w2, &w1, &w0, ws[6], p[14]); + word3_muladd(&w2, &w1, &w0, ws[7], p[13]); + word3_muladd(&w2, &w1, &w0, ws[8], p[12]); + word3_muladd(&w2, &w1, &w0, ws[9], p[11]); + word3_muladd(&w2, &w1, &w0, ws[10], p[10]); + word3_muladd(&w2, &w1, &w0, ws[11], p[9]); + word3_muladd(&w2, &w1, &w0, ws[12], p[8]); + word3_muladd(&w2, &w1, &w0, ws[13], p[7]); + word3_muladd(&w2, &w1, &w0, ws[14], p[6]); + word3_muladd(&w2, &w1, &w0, ws[15], p[5]); + word3_muladd(&w2, &w1, &w0, ws[16], p[4]); + word3_muladd(&w2, &w1, &w0, ws[17], p[3]); + word3_muladd(&w2, &w1, &w0, ws[18], p[2]); + word3_muladd(&w2, &w1, &w0, ws[19], p[1]); + word3_add(&w2, &w1, &w0, z[20]); + ws[20] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[20], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[21]); + word3_muladd(&w2, &w1, &w0, ws[1], p[20]); + word3_muladd(&w2, &w1, &w0, ws[2], p[19]); + word3_muladd(&w2, &w1, &w0, ws[3], p[18]); + word3_muladd(&w2, &w1, &w0, ws[4], p[17]); + word3_muladd(&w2, &w1, &w0, ws[5], p[16]); + word3_muladd(&w2, &w1, &w0, ws[6], p[15]); + word3_muladd(&w2, &w1, &w0, ws[7], p[14]); + word3_muladd(&w2, &w1, &w0, ws[8], p[13]); + word3_muladd(&w2, &w1, &w0, ws[9], p[12]); + word3_muladd(&w2, &w1, &w0, ws[10], p[11]); + word3_muladd(&w2, &w1, &w0, ws[11], p[10]); + word3_muladd(&w2, &w1, &w0, ws[12], p[9]); + word3_muladd(&w2, &w1, &w0, ws[13], p[8]); + word3_muladd(&w2, &w1, &w0, ws[14], p[7]); + word3_muladd(&w2, &w1, &w0, ws[15], p[6]); + word3_muladd(&w2, &w1, &w0, ws[16], p[5]); + word3_muladd(&w2, &w1, &w0, ws[17], p[4]); + word3_muladd(&w2, &w1, &w0, ws[18], p[3]); + word3_muladd(&w2, &w1, &w0, ws[19], p[2]); + word3_muladd(&w2, &w1, &w0, ws[20], p[1]); + word3_add(&w2, &w1, &w0, z[21]); + ws[21] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[21], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[22]); + word3_muladd(&w2, &w1, &w0, ws[1], p[21]); + word3_muladd(&w2, &w1, &w0, ws[2], p[20]); + word3_muladd(&w2, &w1, &w0, ws[3], p[19]); + word3_muladd(&w2, &w1, &w0, ws[4], p[18]); + word3_muladd(&w2, &w1, &w0, ws[5], p[17]); + word3_muladd(&w2, &w1, &w0, ws[6], p[16]); + word3_muladd(&w2, &w1, &w0, ws[7], p[15]); + word3_muladd(&w2, &w1, &w0, ws[8], p[14]); + word3_muladd(&w2, &w1, &w0, ws[9], p[13]); + word3_muladd(&w2, &w1, &w0, ws[10], p[12]); + word3_muladd(&w2, &w1, &w0, ws[11], p[11]); + word3_muladd(&w2, &w1, &w0, ws[12], p[10]); + word3_muladd(&w2, &w1, &w0, ws[13], p[9]); + word3_muladd(&w2, &w1, &w0, ws[14], p[8]); + word3_muladd(&w2, &w1, &w0, ws[15], p[7]); + word3_muladd(&w2, &w1, &w0, ws[16], p[6]); + word3_muladd(&w2, &w1, &w0, ws[17], p[5]); + word3_muladd(&w2, &w1, &w0, ws[18], p[4]); + word3_muladd(&w2, &w1, &w0, ws[19], p[3]); + word3_muladd(&w2, &w1, &w0, ws[20], p[2]); + word3_muladd(&w2, &w1, &w0, ws[21], p[1]); + word3_add(&w2, &w1, &w0, z[22]); + ws[22] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[22], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[23]); + word3_muladd(&w2, &w1, &w0, ws[1], p[22]); + word3_muladd(&w2, &w1, &w0, ws[2], p[21]); + word3_muladd(&w2, &w1, &w0, ws[3], p[20]); + word3_muladd(&w2, &w1, &w0, ws[4], p[19]); + word3_muladd(&w2, &w1, &w0, ws[5], p[18]); + word3_muladd(&w2, &w1, &w0, ws[6], p[17]); + word3_muladd(&w2, &w1, &w0, ws[7], p[16]); + word3_muladd(&w2, &w1, &w0, ws[8], p[15]); + word3_muladd(&w2, &w1, &w0, ws[9], p[14]); + word3_muladd(&w2, &w1, &w0, ws[10], p[13]); + word3_muladd(&w2, &w1, &w0, ws[11], p[12]); + word3_muladd(&w2, &w1, &w0, ws[12], p[11]); + word3_muladd(&w2, &w1, &w0, ws[13], p[10]); + word3_muladd(&w2, &w1, &w0, ws[14], p[9]); + word3_muladd(&w2, &w1, &w0, ws[15], p[8]); + word3_muladd(&w2, &w1, &w0, ws[16], p[7]); + word3_muladd(&w2, &w1, &w0, ws[17], p[6]); + word3_muladd(&w2, &w1, &w0, ws[18], p[5]); + word3_muladd(&w2, &w1, &w0, ws[19], p[4]); + word3_muladd(&w2, &w1, &w0, ws[20], p[3]); + word3_muladd(&w2, &w1, &w0, ws[21], p[2]); + word3_muladd(&w2, &w1, &w0, ws[22], p[1]); + word3_add(&w2, &w1, &w0, z[23]); + ws[23] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[23], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[24]); + word3_muladd(&w2, &w1, &w0, ws[1], p[23]); + word3_muladd(&w2, &w1, &w0, ws[2], p[22]); + word3_muladd(&w2, &w1, &w0, ws[3], p[21]); + word3_muladd(&w2, &w1, &w0, ws[4], p[20]); + word3_muladd(&w2, &w1, &w0, ws[5], p[19]); + word3_muladd(&w2, &w1, &w0, ws[6], p[18]); + word3_muladd(&w2, &w1, &w0, ws[7], p[17]); + word3_muladd(&w2, &w1, &w0, ws[8], p[16]); + word3_muladd(&w2, &w1, &w0, ws[9], p[15]); + word3_muladd(&w2, &w1, &w0, ws[10], p[14]); + word3_muladd(&w2, &w1, &w0, ws[11], p[13]); + word3_muladd(&w2, &w1, &w0, ws[12], p[12]); + word3_muladd(&w2, &w1, &w0, ws[13], p[11]); + word3_muladd(&w2, &w1, &w0, ws[14], p[10]); + word3_muladd(&w2, &w1, &w0, ws[15], p[9]); + word3_muladd(&w2, &w1, &w0, ws[16], p[8]); + word3_muladd(&w2, &w1, &w0, ws[17], p[7]); + word3_muladd(&w2, &w1, &w0, ws[18], p[6]); + word3_muladd(&w2, &w1, &w0, ws[19], p[5]); + word3_muladd(&w2, &w1, &w0, ws[20], p[4]); + word3_muladd(&w2, &w1, &w0, ws[21], p[3]); + word3_muladd(&w2, &w1, &w0, ws[22], p[2]); + word3_muladd(&w2, &w1, &w0, ws[23], p[1]); + word3_add(&w2, &w1, &w0, z[24]); + ws[24] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[24], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[25]); + word3_muladd(&w2, &w1, &w0, ws[1], p[24]); + word3_muladd(&w2, &w1, &w0, ws[2], p[23]); + word3_muladd(&w2, &w1, &w0, ws[3], p[22]); + word3_muladd(&w2, &w1, &w0, ws[4], p[21]); + word3_muladd(&w2, &w1, &w0, ws[5], p[20]); + word3_muladd(&w2, &w1, &w0, ws[6], p[19]); + word3_muladd(&w2, &w1, &w0, ws[7], p[18]); + word3_muladd(&w2, &w1, &w0, ws[8], p[17]); + word3_muladd(&w2, &w1, &w0, ws[9], p[16]); + word3_muladd(&w2, &w1, &w0, ws[10], p[15]); + word3_muladd(&w2, &w1, &w0, ws[11], p[14]); + word3_muladd(&w2, &w1, &w0, ws[12], p[13]); + word3_muladd(&w2, &w1, &w0, ws[13], p[12]); + word3_muladd(&w2, &w1, &w0, ws[14], p[11]); + word3_muladd(&w2, &w1, &w0, ws[15], p[10]); + word3_muladd(&w2, &w1, &w0, ws[16], p[9]); + word3_muladd(&w2, &w1, &w0, ws[17], p[8]); + word3_muladd(&w2, &w1, &w0, ws[18], p[7]); + word3_muladd(&w2, &w1, &w0, ws[19], p[6]); + word3_muladd(&w2, &w1, &w0, ws[20], p[5]); + word3_muladd(&w2, &w1, &w0, ws[21], p[4]); + word3_muladd(&w2, &w1, &w0, ws[22], p[3]); + word3_muladd(&w2, &w1, &w0, ws[23], p[2]); + word3_muladd(&w2, &w1, &w0, ws[24], p[1]); + word3_add(&w2, &w1, &w0, z[25]); + ws[25] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[25], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[26]); + word3_muladd(&w2, &w1, &w0, ws[1], p[25]); + word3_muladd(&w2, &w1, &w0, ws[2], p[24]); + word3_muladd(&w2, &w1, &w0, ws[3], p[23]); + word3_muladd(&w2, &w1, &w0, ws[4], p[22]); + word3_muladd(&w2, &w1, &w0, ws[5], p[21]); + word3_muladd(&w2, &w1, &w0, ws[6], p[20]); + word3_muladd(&w2, &w1, &w0, ws[7], p[19]); + word3_muladd(&w2, &w1, &w0, ws[8], p[18]); + word3_muladd(&w2, &w1, &w0, ws[9], p[17]); + word3_muladd(&w2, &w1, &w0, ws[10], p[16]); + word3_muladd(&w2, &w1, &w0, ws[11], p[15]); + word3_muladd(&w2, &w1, &w0, ws[12], p[14]); + word3_muladd(&w2, &w1, &w0, ws[13], p[13]); + word3_muladd(&w2, &w1, &w0, ws[14], p[12]); + word3_muladd(&w2, &w1, &w0, ws[15], p[11]); + word3_muladd(&w2, &w1, &w0, ws[16], p[10]); + word3_muladd(&w2, &w1, &w0, ws[17], p[9]); + word3_muladd(&w2, &w1, &w0, ws[18], p[8]); + word3_muladd(&w2, &w1, &w0, ws[19], p[7]); + word3_muladd(&w2, &w1, &w0, ws[20], p[6]); + word3_muladd(&w2, &w1, &w0, ws[21], p[5]); + word3_muladd(&w2, &w1, &w0, ws[22], p[4]); + word3_muladd(&w2, &w1, &w0, ws[23], p[3]); + word3_muladd(&w2, &w1, &w0, ws[24], p[2]); + word3_muladd(&w2, &w1, &w0, ws[25], p[1]); + word3_add(&w2, &w1, &w0, z[26]); + ws[26] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[26], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[27]); + word3_muladd(&w2, &w1, &w0, ws[1], p[26]); + word3_muladd(&w2, &w1, &w0, ws[2], p[25]); + word3_muladd(&w2, &w1, &w0, ws[3], p[24]); + word3_muladd(&w2, &w1, &w0, ws[4], p[23]); + word3_muladd(&w2, &w1, &w0, ws[5], p[22]); + word3_muladd(&w2, &w1, &w0, ws[6], p[21]); + word3_muladd(&w2, &w1, &w0, ws[7], p[20]); + word3_muladd(&w2, &w1, &w0, ws[8], p[19]); + word3_muladd(&w2, &w1, &w0, ws[9], p[18]); + word3_muladd(&w2, &w1, &w0, ws[10], p[17]); + word3_muladd(&w2, &w1, &w0, ws[11], p[16]); + word3_muladd(&w2, &w1, &w0, ws[12], p[15]); + word3_muladd(&w2, &w1, &w0, ws[13], p[14]); + word3_muladd(&w2, &w1, &w0, ws[14], p[13]); + word3_muladd(&w2, &w1, &w0, ws[15], p[12]); + word3_muladd(&w2, &w1, &w0, ws[16], p[11]); + word3_muladd(&w2, &w1, &w0, ws[17], p[10]); + word3_muladd(&w2, &w1, &w0, ws[18], p[9]); + word3_muladd(&w2, &w1, &w0, ws[19], p[8]); + word3_muladd(&w2, &w1, &w0, ws[20], p[7]); + word3_muladd(&w2, &w1, &w0, ws[21], p[6]); + word3_muladd(&w2, &w1, &w0, ws[22], p[5]); + word3_muladd(&w2, &w1, &w0, ws[23], p[4]); + word3_muladd(&w2, &w1, &w0, ws[24], p[3]); + word3_muladd(&w2, &w1, &w0, ws[25], p[2]); + word3_muladd(&w2, &w1, &w0, ws[26], p[1]); + word3_add(&w2, &w1, &w0, z[27]); + ws[27] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[27], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[28]); + word3_muladd(&w2, &w1, &w0, ws[1], p[27]); + word3_muladd(&w2, &w1, &w0, ws[2], p[26]); + word3_muladd(&w2, &w1, &w0, ws[3], p[25]); + word3_muladd(&w2, &w1, &w0, ws[4], p[24]); + word3_muladd(&w2, &w1, &w0, ws[5], p[23]); + word3_muladd(&w2, &w1, &w0, ws[6], p[22]); + word3_muladd(&w2, &w1, &w0, ws[7], p[21]); + word3_muladd(&w2, &w1, &w0, ws[8], p[20]); + word3_muladd(&w2, &w1, &w0, ws[9], p[19]); + word3_muladd(&w2, &w1, &w0, ws[10], p[18]); + word3_muladd(&w2, &w1, &w0, ws[11], p[17]); + word3_muladd(&w2, &w1, &w0, ws[12], p[16]); + word3_muladd(&w2, &w1, &w0, ws[13], p[15]); + word3_muladd(&w2, &w1, &w0, ws[14], p[14]); + word3_muladd(&w2, &w1, &w0, ws[15], p[13]); + word3_muladd(&w2, &w1, &w0, ws[16], p[12]); + word3_muladd(&w2, &w1, &w0, ws[17], p[11]); + word3_muladd(&w2, &w1, &w0, ws[18], p[10]); + word3_muladd(&w2, &w1, &w0, ws[19], p[9]); + word3_muladd(&w2, &w1, &w0, ws[20], p[8]); + word3_muladd(&w2, &w1, &w0, ws[21], p[7]); + word3_muladd(&w2, &w1, &w0, ws[22], p[6]); + word3_muladd(&w2, &w1, &w0, ws[23], p[5]); + word3_muladd(&w2, &w1, &w0, ws[24], p[4]); + word3_muladd(&w2, &w1, &w0, ws[25], p[3]); + word3_muladd(&w2, &w1, &w0, ws[26], p[2]); + word3_muladd(&w2, &w1, &w0, ws[27], p[1]); + word3_add(&w2, &w1, &w0, z[28]); + ws[28] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[28], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[29]); + word3_muladd(&w2, &w1, &w0, ws[1], p[28]); + word3_muladd(&w2, &w1, &w0, ws[2], p[27]); + word3_muladd(&w2, &w1, &w0, ws[3], p[26]); + word3_muladd(&w2, &w1, &w0, ws[4], p[25]); + word3_muladd(&w2, &w1, &w0, ws[5], p[24]); + word3_muladd(&w2, &w1, &w0, ws[6], p[23]); + word3_muladd(&w2, &w1, &w0, ws[7], p[22]); + word3_muladd(&w2, &w1, &w0, ws[8], p[21]); + word3_muladd(&w2, &w1, &w0, ws[9], p[20]); + word3_muladd(&w2, &w1, &w0, ws[10], p[19]); + word3_muladd(&w2, &w1, &w0, ws[11], p[18]); + word3_muladd(&w2, &w1, &w0, ws[12], p[17]); + word3_muladd(&w2, &w1, &w0, ws[13], p[16]); + word3_muladd(&w2, &w1, &w0, ws[14], p[15]); + word3_muladd(&w2, &w1, &w0, ws[15], p[14]); + word3_muladd(&w2, &w1, &w0, ws[16], p[13]); + word3_muladd(&w2, &w1, &w0, ws[17], p[12]); + word3_muladd(&w2, &w1, &w0, ws[18], p[11]); + word3_muladd(&w2, &w1, &w0, ws[19], p[10]); + word3_muladd(&w2, &w1, &w0, ws[20], p[9]); + word3_muladd(&w2, &w1, &w0, ws[21], p[8]); + word3_muladd(&w2, &w1, &w0, ws[22], p[7]); + word3_muladd(&w2, &w1, &w0, ws[23], p[6]); + word3_muladd(&w2, &w1, &w0, ws[24], p[5]); + word3_muladd(&w2, &w1, &w0, ws[25], p[4]); + word3_muladd(&w2, &w1, &w0, ws[26], p[3]); + word3_muladd(&w2, &w1, &w0, ws[27], p[2]); + word3_muladd(&w2, &w1, &w0, ws[28], p[1]); + word3_add(&w2, &w1, &w0, z[29]); + ws[29] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[29], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[30]); + word3_muladd(&w2, &w1, &w0, ws[1], p[29]); + word3_muladd(&w2, &w1, &w0, ws[2], p[28]); + word3_muladd(&w2, &w1, &w0, ws[3], p[27]); + word3_muladd(&w2, &w1, &w0, ws[4], p[26]); + word3_muladd(&w2, &w1, &w0, ws[5], p[25]); + word3_muladd(&w2, &w1, &w0, ws[6], p[24]); + word3_muladd(&w2, &w1, &w0, ws[7], p[23]); + word3_muladd(&w2, &w1, &w0, ws[8], p[22]); + word3_muladd(&w2, &w1, &w0, ws[9], p[21]); + word3_muladd(&w2, &w1, &w0, ws[10], p[20]); + word3_muladd(&w2, &w1, &w0, ws[11], p[19]); + word3_muladd(&w2, &w1, &w0, ws[12], p[18]); + word3_muladd(&w2, &w1, &w0, ws[13], p[17]); + word3_muladd(&w2, &w1, &w0, ws[14], p[16]); + word3_muladd(&w2, &w1, &w0, ws[15], p[15]); + word3_muladd(&w2, &w1, &w0, ws[16], p[14]); + word3_muladd(&w2, &w1, &w0, ws[17], p[13]); + word3_muladd(&w2, &w1, &w0, ws[18], p[12]); + word3_muladd(&w2, &w1, &w0, ws[19], p[11]); + word3_muladd(&w2, &w1, &w0, ws[20], p[10]); + word3_muladd(&w2, &w1, &w0, ws[21], p[9]); + word3_muladd(&w2, &w1, &w0, ws[22], p[8]); + word3_muladd(&w2, &w1, &w0, ws[23], p[7]); + word3_muladd(&w2, &w1, &w0, ws[24], p[6]); + word3_muladd(&w2, &w1, &w0, ws[25], p[5]); + word3_muladd(&w2, &w1, &w0, ws[26], p[4]); + word3_muladd(&w2, &w1, &w0, ws[27], p[3]); + word3_muladd(&w2, &w1, &w0, ws[28], p[2]); + word3_muladd(&w2, &w1, &w0, ws[29], p[1]); + word3_add(&w2, &w1, &w0, z[30]); + ws[30] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[30], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[31]); + word3_muladd(&w2, &w1, &w0, ws[1], p[30]); + word3_muladd(&w2, &w1, &w0, ws[2], p[29]); + word3_muladd(&w2, &w1, &w0, ws[3], p[28]); + word3_muladd(&w2, &w1, &w0, ws[4], p[27]); + word3_muladd(&w2, &w1, &w0, ws[5], p[26]); + word3_muladd(&w2, &w1, &w0, ws[6], p[25]); + word3_muladd(&w2, &w1, &w0, ws[7], p[24]); + word3_muladd(&w2, &w1, &w0, ws[8], p[23]); + word3_muladd(&w2, &w1, &w0, ws[9], p[22]); + word3_muladd(&w2, &w1, &w0, ws[10], p[21]); + word3_muladd(&w2, &w1, &w0, ws[11], p[20]); + word3_muladd(&w2, &w1, &w0, ws[12], p[19]); + word3_muladd(&w2, &w1, &w0, ws[13], p[18]); + word3_muladd(&w2, &w1, &w0, ws[14], p[17]); + word3_muladd(&w2, &w1, &w0, ws[15], p[16]); + word3_muladd(&w2, &w1, &w0, ws[16], p[15]); + word3_muladd(&w2, &w1, &w0, ws[17], p[14]); + word3_muladd(&w2, &w1, &w0, ws[18], p[13]); + word3_muladd(&w2, &w1, &w0, ws[19], p[12]); + word3_muladd(&w2, &w1, &w0, ws[20], p[11]); + word3_muladd(&w2, &w1, &w0, ws[21], p[10]); + word3_muladd(&w2, &w1, &w0, ws[22], p[9]); + word3_muladd(&w2, &w1, &w0, ws[23], p[8]); + word3_muladd(&w2, &w1, &w0, ws[24], p[7]); + word3_muladd(&w2, &w1, &w0, ws[25], p[6]); + word3_muladd(&w2, &w1, &w0, ws[26], p[5]); + word3_muladd(&w2, &w1, &w0, ws[27], p[4]); + word3_muladd(&w2, &w1, &w0, ws[28], p[3]); + word3_muladd(&w2, &w1, &w0, ws[29], p[2]); + word3_muladd(&w2, &w1, &w0, ws[30], p[1]); + word3_add(&w2, &w1, &w0, z[31]); + ws[31] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[31], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[31]); + word3_muladd(&w2, &w1, &w0, ws[2], p[30]); + word3_muladd(&w2, &w1, &w0, ws[3], p[29]); + word3_muladd(&w2, &w1, &w0, ws[4], p[28]); + word3_muladd(&w2, &w1, &w0, ws[5], p[27]); + word3_muladd(&w2, &w1, &w0, ws[6], p[26]); + word3_muladd(&w2, &w1, &w0, ws[7], p[25]); + word3_muladd(&w2, &w1, &w0, ws[8], p[24]); + word3_muladd(&w2, &w1, &w0, ws[9], p[23]); + word3_muladd(&w2, &w1, &w0, ws[10], p[22]); + word3_muladd(&w2, &w1, &w0, ws[11], p[21]); + word3_muladd(&w2, &w1, &w0, ws[12], p[20]); + word3_muladd(&w2, &w1, &w0, ws[13], p[19]); + word3_muladd(&w2, &w1, &w0, ws[14], p[18]); + word3_muladd(&w2, &w1, &w0, ws[15], p[17]); + word3_muladd(&w2, &w1, &w0, ws[16], p[16]); + word3_muladd(&w2, &w1, &w0, ws[17], p[15]); + word3_muladd(&w2, &w1, &w0, ws[18], p[14]); + word3_muladd(&w2, &w1, &w0, ws[19], p[13]); + word3_muladd(&w2, &w1, &w0, ws[20], p[12]); + word3_muladd(&w2, &w1, &w0, ws[21], p[11]); + word3_muladd(&w2, &w1, &w0, ws[22], p[10]); + word3_muladd(&w2, &w1, &w0, ws[23], p[9]); + word3_muladd(&w2, &w1, &w0, ws[24], p[8]); + word3_muladd(&w2, &w1, &w0, ws[25], p[7]); + word3_muladd(&w2, &w1, &w0, ws[26], p[6]); + word3_muladd(&w2, &w1, &w0, ws[27], p[5]); + word3_muladd(&w2, &w1, &w0, ws[28], p[4]); + word3_muladd(&w2, &w1, &w0, ws[29], p[3]); + word3_muladd(&w2, &w1, &w0, ws[30], p[2]); + word3_muladd(&w2, &w1, &w0, ws[31], p[1]); + word3_add(&w2, &w1, &w0, z[32]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[31]); + word3_muladd(&w2, &w1, &w0, ws[3], p[30]); + word3_muladd(&w2, &w1, &w0, ws[4], p[29]); + word3_muladd(&w2, &w1, &w0, ws[5], p[28]); + word3_muladd(&w2, &w1, &w0, ws[6], p[27]); + word3_muladd(&w2, &w1, &w0, ws[7], p[26]); + word3_muladd(&w2, &w1, &w0, ws[8], p[25]); + word3_muladd(&w2, &w1, &w0, ws[9], p[24]); + word3_muladd(&w2, &w1, &w0, ws[10], p[23]); + word3_muladd(&w2, &w1, &w0, ws[11], p[22]); + word3_muladd(&w2, &w1, &w0, ws[12], p[21]); + word3_muladd(&w2, &w1, &w0, ws[13], p[20]); + word3_muladd(&w2, &w1, &w0, ws[14], p[19]); + word3_muladd(&w2, &w1, &w0, ws[15], p[18]); + word3_muladd(&w2, &w1, &w0, ws[16], p[17]); + word3_muladd(&w2, &w1, &w0, ws[17], p[16]); + word3_muladd(&w2, &w1, &w0, ws[18], p[15]); + word3_muladd(&w2, &w1, &w0, ws[19], p[14]); + word3_muladd(&w2, &w1, &w0, ws[20], p[13]); + word3_muladd(&w2, &w1, &w0, ws[21], p[12]); + word3_muladd(&w2, &w1, &w0, ws[22], p[11]); + word3_muladd(&w2, &w1, &w0, ws[23], p[10]); + word3_muladd(&w2, &w1, &w0, ws[24], p[9]); + word3_muladd(&w2, &w1, &w0, ws[25], p[8]); + word3_muladd(&w2, &w1, &w0, ws[26], p[7]); + word3_muladd(&w2, &w1, &w0, ws[27], p[6]); + word3_muladd(&w2, &w1, &w0, ws[28], p[5]); + word3_muladd(&w2, &w1, &w0, ws[29], p[4]); + word3_muladd(&w2, &w1, &w0, ws[30], p[3]); + word3_muladd(&w2, &w1, &w0, ws[31], p[2]); + word3_add(&w2, &w1, &w0, z[33]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[31]); + word3_muladd(&w2, &w1, &w0, ws[4], p[30]); + word3_muladd(&w2, &w1, &w0, ws[5], p[29]); + word3_muladd(&w2, &w1, &w0, ws[6], p[28]); + word3_muladd(&w2, &w1, &w0, ws[7], p[27]); + word3_muladd(&w2, &w1, &w0, ws[8], p[26]); + word3_muladd(&w2, &w1, &w0, ws[9], p[25]); + word3_muladd(&w2, &w1, &w0, ws[10], p[24]); + word3_muladd(&w2, &w1, &w0, ws[11], p[23]); + word3_muladd(&w2, &w1, &w0, ws[12], p[22]); + word3_muladd(&w2, &w1, &w0, ws[13], p[21]); + word3_muladd(&w2, &w1, &w0, ws[14], p[20]); + word3_muladd(&w2, &w1, &w0, ws[15], p[19]); + word3_muladd(&w2, &w1, &w0, ws[16], p[18]); + word3_muladd(&w2, &w1, &w0, ws[17], p[17]); + word3_muladd(&w2, &w1, &w0, ws[18], p[16]); + word3_muladd(&w2, &w1, &w0, ws[19], p[15]); + word3_muladd(&w2, &w1, &w0, ws[20], p[14]); + word3_muladd(&w2, &w1, &w0, ws[21], p[13]); + word3_muladd(&w2, &w1, &w0, ws[22], p[12]); + word3_muladd(&w2, &w1, &w0, ws[23], p[11]); + word3_muladd(&w2, &w1, &w0, ws[24], p[10]); + word3_muladd(&w2, &w1, &w0, ws[25], p[9]); + word3_muladd(&w2, &w1, &w0, ws[26], p[8]); + word3_muladd(&w2, &w1, &w0, ws[27], p[7]); + word3_muladd(&w2, &w1, &w0, ws[28], p[6]); + word3_muladd(&w2, &w1, &w0, ws[29], p[5]); + word3_muladd(&w2, &w1, &w0, ws[30], p[4]); + word3_muladd(&w2, &w1, &w0, ws[31], p[3]); + word3_add(&w2, &w1, &w0, z[34]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[31]); + word3_muladd(&w2, &w1, &w0, ws[5], p[30]); + word3_muladd(&w2, &w1, &w0, ws[6], p[29]); + word3_muladd(&w2, &w1, &w0, ws[7], p[28]); + word3_muladd(&w2, &w1, &w0, ws[8], p[27]); + word3_muladd(&w2, &w1, &w0, ws[9], p[26]); + word3_muladd(&w2, &w1, &w0, ws[10], p[25]); + word3_muladd(&w2, &w1, &w0, ws[11], p[24]); + word3_muladd(&w2, &w1, &w0, ws[12], p[23]); + word3_muladd(&w2, &w1, &w0, ws[13], p[22]); + word3_muladd(&w2, &w1, &w0, ws[14], p[21]); + word3_muladd(&w2, &w1, &w0, ws[15], p[20]); + word3_muladd(&w2, &w1, &w0, ws[16], p[19]); + word3_muladd(&w2, &w1, &w0, ws[17], p[18]); + word3_muladd(&w2, &w1, &w0, ws[18], p[17]); + word3_muladd(&w2, &w1, &w0, ws[19], p[16]); + word3_muladd(&w2, &w1, &w0, ws[20], p[15]); + word3_muladd(&w2, &w1, &w0, ws[21], p[14]); + word3_muladd(&w2, &w1, &w0, ws[22], p[13]); + word3_muladd(&w2, &w1, &w0, ws[23], p[12]); + word3_muladd(&w2, &w1, &w0, ws[24], p[11]); + word3_muladd(&w2, &w1, &w0, ws[25], p[10]); + word3_muladd(&w2, &w1, &w0, ws[26], p[9]); + word3_muladd(&w2, &w1, &w0, ws[27], p[8]); + word3_muladd(&w2, &w1, &w0, ws[28], p[7]); + word3_muladd(&w2, &w1, &w0, ws[29], p[6]); + word3_muladd(&w2, &w1, &w0, ws[30], p[5]); + word3_muladd(&w2, &w1, &w0, ws[31], p[4]); + word3_add(&w2, &w1, &w0, z[35]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[31]); + word3_muladd(&w2, &w1, &w0, ws[6], p[30]); + word3_muladd(&w2, &w1, &w0, ws[7], p[29]); + word3_muladd(&w2, &w1, &w0, ws[8], p[28]); + word3_muladd(&w2, &w1, &w0, ws[9], p[27]); + word3_muladd(&w2, &w1, &w0, ws[10], p[26]); + word3_muladd(&w2, &w1, &w0, ws[11], p[25]); + word3_muladd(&w2, &w1, &w0, ws[12], p[24]); + word3_muladd(&w2, &w1, &w0, ws[13], p[23]); + word3_muladd(&w2, &w1, &w0, ws[14], p[22]); + word3_muladd(&w2, &w1, &w0, ws[15], p[21]); + word3_muladd(&w2, &w1, &w0, ws[16], p[20]); + word3_muladd(&w2, &w1, &w0, ws[17], p[19]); + word3_muladd(&w2, &w1, &w0, ws[18], p[18]); + word3_muladd(&w2, &w1, &w0, ws[19], p[17]); + word3_muladd(&w2, &w1, &w0, ws[20], p[16]); + word3_muladd(&w2, &w1, &w0, ws[21], p[15]); + word3_muladd(&w2, &w1, &w0, ws[22], p[14]); + word3_muladd(&w2, &w1, &w0, ws[23], p[13]); + word3_muladd(&w2, &w1, &w0, ws[24], p[12]); + word3_muladd(&w2, &w1, &w0, ws[25], p[11]); + word3_muladd(&w2, &w1, &w0, ws[26], p[10]); + word3_muladd(&w2, &w1, &w0, ws[27], p[9]); + word3_muladd(&w2, &w1, &w0, ws[28], p[8]); + word3_muladd(&w2, &w1, &w0, ws[29], p[7]); + word3_muladd(&w2, &w1, &w0, ws[30], p[6]); + word3_muladd(&w2, &w1, &w0, ws[31], p[5]); + word3_add(&w2, &w1, &w0, z[36]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[31]); + word3_muladd(&w2, &w1, &w0, ws[7], p[30]); + word3_muladd(&w2, &w1, &w0, ws[8], p[29]); + word3_muladd(&w2, &w1, &w0, ws[9], p[28]); + word3_muladd(&w2, &w1, &w0, ws[10], p[27]); + word3_muladd(&w2, &w1, &w0, ws[11], p[26]); + word3_muladd(&w2, &w1, &w0, ws[12], p[25]); + word3_muladd(&w2, &w1, &w0, ws[13], p[24]); + word3_muladd(&w2, &w1, &w0, ws[14], p[23]); + word3_muladd(&w2, &w1, &w0, ws[15], p[22]); + word3_muladd(&w2, &w1, &w0, ws[16], p[21]); + word3_muladd(&w2, &w1, &w0, ws[17], p[20]); + word3_muladd(&w2, &w1, &w0, ws[18], p[19]); + word3_muladd(&w2, &w1, &w0, ws[19], p[18]); + word3_muladd(&w2, &w1, &w0, ws[20], p[17]); + word3_muladd(&w2, &w1, &w0, ws[21], p[16]); + word3_muladd(&w2, &w1, &w0, ws[22], p[15]); + word3_muladd(&w2, &w1, &w0, ws[23], p[14]); + word3_muladd(&w2, &w1, &w0, ws[24], p[13]); + word3_muladd(&w2, &w1, &w0, ws[25], p[12]); + word3_muladd(&w2, &w1, &w0, ws[26], p[11]); + word3_muladd(&w2, &w1, &w0, ws[27], p[10]); + word3_muladd(&w2, &w1, &w0, ws[28], p[9]); + word3_muladd(&w2, &w1, &w0, ws[29], p[8]); + word3_muladd(&w2, &w1, &w0, ws[30], p[7]); + word3_muladd(&w2, &w1, &w0, ws[31], p[6]); + word3_add(&w2, &w1, &w0, z[37]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[31]); + word3_muladd(&w2, &w1, &w0, ws[8], p[30]); + word3_muladd(&w2, &w1, &w0, ws[9], p[29]); + word3_muladd(&w2, &w1, &w0, ws[10], p[28]); + word3_muladd(&w2, &w1, &w0, ws[11], p[27]); + word3_muladd(&w2, &w1, &w0, ws[12], p[26]); + word3_muladd(&w2, &w1, &w0, ws[13], p[25]); + word3_muladd(&w2, &w1, &w0, ws[14], p[24]); + word3_muladd(&w2, &w1, &w0, ws[15], p[23]); + word3_muladd(&w2, &w1, &w0, ws[16], p[22]); + word3_muladd(&w2, &w1, &w0, ws[17], p[21]); + word3_muladd(&w2, &w1, &w0, ws[18], p[20]); + word3_muladd(&w2, &w1, &w0, ws[19], p[19]); + word3_muladd(&w2, &w1, &w0, ws[20], p[18]); + word3_muladd(&w2, &w1, &w0, ws[21], p[17]); + word3_muladd(&w2, &w1, &w0, ws[22], p[16]); + word3_muladd(&w2, &w1, &w0, ws[23], p[15]); + word3_muladd(&w2, &w1, &w0, ws[24], p[14]); + word3_muladd(&w2, &w1, &w0, ws[25], p[13]); + word3_muladd(&w2, &w1, &w0, ws[26], p[12]); + word3_muladd(&w2, &w1, &w0, ws[27], p[11]); + word3_muladd(&w2, &w1, &w0, ws[28], p[10]); + word3_muladd(&w2, &w1, &w0, ws[29], p[9]); + word3_muladd(&w2, &w1, &w0, ws[30], p[8]); + word3_muladd(&w2, &w1, &w0, ws[31], p[7]); + word3_add(&w2, &w1, &w0, z[38]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[8], p[31]); + word3_muladd(&w2, &w1, &w0, ws[9], p[30]); + word3_muladd(&w2, &w1, &w0, ws[10], p[29]); + word3_muladd(&w2, &w1, &w0, ws[11], p[28]); + word3_muladd(&w2, &w1, &w0, ws[12], p[27]); + word3_muladd(&w2, &w1, &w0, ws[13], p[26]); + word3_muladd(&w2, &w1, &w0, ws[14], p[25]); + word3_muladd(&w2, &w1, &w0, ws[15], p[24]); + word3_muladd(&w2, &w1, &w0, ws[16], p[23]); + word3_muladd(&w2, &w1, &w0, ws[17], p[22]); + word3_muladd(&w2, &w1, &w0, ws[18], p[21]); + word3_muladd(&w2, &w1, &w0, ws[19], p[20]); + word3_muladd(&w2, &w1, &w0, ws[20], p[19]); + word3_muladd(&w2, &w1, &w0, ws[21], p[18]); + word3_muladd(&w2, &w1, &w0, ws[22], p[17]); + word3_muladd(&w2, &w1, &w0, ws[23], p[16]); + word3_muladd(&w2, &w1, &w0, ws[24], p[15]); + word3_muladd(&w2, &w1, &w0, ws[25], p[14]); + word3_muladd(&w2, &w1, &w0, ws[26], p[13]); + word3_muladd(&w2, &w1, &w0, ws[27], p[12]); + word3_muladd(&w2, &w1, &w0, ws[28], p[11]); + word3_muladd(&w2, &w1, &w0, ws[29], p[10]); + word3_muladd(&w2, &w1, &w0, ws[30], p[9]); + word3_muladd(&w2, &w1, &w0, ws[31], p[8]); + word3_add(&w2, &w1, &w0, z[39]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[9], p[31]); + word3_muladd(&w2, &w1, &w0, ws[10], p[30]); + word3_muladd(&w2, &w1, &w0, ws[11], p[29]); + word3_muladd(&w2, &w1, &w0, ws[12], p[28]); + word3_muladd(&w2, &w1, &w0, ws[13], p[27]); + word3_muladd(&w2, &w1, &w0, ws[14], p[26]); + word3_muladd(&w2, &w1, &w0, ws[15], p[25]); + word3_muladd(&w2, &w1, &w0, ws[16], p[24]); + word3_muladd(&w2, &w1, &w0, ws[17], p[23]); + word3_muladd(&w2, &w1, &w0, ws[18], p[22]); + word3_muladd(&w2, &w1, &w0, ws[19], p[21]); + word3_muladd(&w2, &w1, &w0, ws[20], p[20]); + word3_muladd(&w2, &w1, &w0, ws[21], p[19]); + word3_muladd(&w2, &w1, &w0, ws[22], p[18]); + word3_muladd(&w2, &w1, &w0, ws[23], p[17]); + word3_muladd(&w2, &w1, &w0, ws[24], p[16]); + word3_muladd(&w2, &w1, &w0, ws[25], p[15]); + word3_muladd(&w2, &w1, &w0, ws[26], p[14]); + word3_muladd(&w2, &w1, &w0, ws[27], p[13]); + word3_muladd(&w2, &w1, &w0, ws[28], p[12]); + word3_muladd(&w2, &w1, &w0, ws[29], p[11]); + word3_muladd(&w2, &w1, &w0, ws[30], p[10]); + word3_muladd(&w2, &w1, &w0, ws[31], p[9]); + word3_add(&w2, &w1, &w0, z[40]); + ws[8] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[10], p[31]); + word3_muladd(&w2, &w1, &w0, ws[11], p[30]); + word3_muladd(&w2, &w1, &w0, ws[12], p[29]); + word3_muladd(&w2, &w1, &w0, ws[13], p[28]); + word3_muladd(&w2, &w1, &w0, ws[14], p[27]); + word3_muladd(&w2, &w1, &w0, ws[15], p[26]); + word3_muladd(&w2, &w1, &w0, ws[16], p[25]); + word3_muladd(&w2, &w1, &w0, ws[17], p[24]); + word3_muladd(&w2, &w1, &w0, ws[18], p[23]); + word3_muladd(&w2, &w1, &w0, ws[19], p[22]); + word3_muladd(&w2, &w1, &w0, ws[20], p[21]); + word3_muladd(&w2, &w1, &w0, ws[21], p[20]); + word3_muladd(&w2, &w1, &w0, ws[22], p[19]); + word3_muladd(&w2, &w1, &w0, ws[23], p[18]); + word3_muladd(&w2, &w1, &w0, ws[24], p[17]); + word3_muladd(&w2, &w1, &w0, ws[25], p[16]); + word3_muladd(&w2, &w1, &w0, ws[26], p[15]); + word3_muladd(&w2, &w1, &w0, ws[27], p[14]); + word3_muladd(&w2, &w1, &w0, ws[28], p[13]); + word3_muladd(&w2, &w1, &w0, ws[29], p[12]); + word3_muladd(&w2, &w1, &w0, ws[30], p[11]); + word3_muladd(&w2, &w1, &w0, ws[31], p[10]); + word3_add(&w2, &w1, &w0, z[41]); + ws[9] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[11], p[31]); + word3_muladd(&w2, &w1, &w0, ws[12], p[30]); + word3_muladd(&w2, &w1, &w0, ws[13], p[29]); + word3_muladd(&w2, &w1, &w0, ws[14], p[28]); + word3_muladd(&w2, &w1, &w0, ws[15], p[27]); + word3_muladd(&w2, &w1, &w0, ws[16], p[26]); + word3_muladd(&w2, &w1, &w0, ws[17], p[25]); + word3_muladd(&w2, &w1, &w0, ws[18], p[24]); + word3_muladd(&w2, &w1, &w0, ws[19], p[23]); + word3_muladd(&w2, &w1, &w0, ws[20], p[22]); + word3_muladd(&w2, &w1, &w0, ws[21], p[21]); + word3_muladd(&w2, &w1, &w0, ws[22], p[20]); + word3_muladd(&w2, &w1, &w0, ws[23], p[19]); + word3_muladd(&w2, &w1, &w0, ws[24], p[18]); + word3_muladd(&w2, &w1, &w0, ws[25], p[17]); + word3_muladd(&w2, &w1, &w0, ws[26], p[16]); + word3_muladd(&w2, &w1, &w0, ws[27], p[15]); + word3_muladd(&w2, &w1, &w0, ws[28], p[14]); + word3_muladd(&w2, &w1, &w0, ws[29], p[13]); + word3_muladd(&w2, &w1, &w0, ws[30], p[12]); + word3_muladd(&w2, &w1, &w0, ws[31], p[11]); + word3_add(&w2, &w1, &w0, z[42]); + ws[10] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[12], p[31]); + word3_muladd(&w2, &w1, &w0, ws[13], p[30]); + word3_muladd(&w2, &w1, &w0, ws[14], p[29]); + word3_muladd(&w2, &w1, &w0, ws[15], p[28]); + word3_muladd(&w2, &w1, &w0, ws[16], p[27]); + word3_muladd(&w2, &w1, &w0, ws[17], p[26]); + word3_muladd(&w2, &w1, &w0, ws[18], p[25]); + word3_muladd(&w2, &w1, &w0, ws[19], p[24]); + word3_muladd(&w2, &w1, &w0, ws[20], p[23]); + word3_muladd(&w2, &w1, &w0, ws[21], p[22]); + word3_muladd(&w2, &w1, &w0, ws[22], p[21]); + word3_muladd(&w2, &w1, &w0, ws[23], p[20]); + word3_muladd(&w2, &w1, &w0, ws[24], p[19]); + word3_muladd(&w2, &w1, &w0, ws[25], p[18]); + word3_muladd(&w2, &w1, &w0, ws[26], p[17]); + word3_muladd(&w2, &w1, &w0, ws[27], p[16]); + word3_muladd(&w2, &w1, &w0, ws[28], p[15]); + word3_muladd(&w2, &w1, &w0, ws[29], p[14]); + word3_muladd(&w2, &w1, &w0, ws[30], p[13]); + word3_muladd(&w2, &w1, &w0, ws[31], p[12]); + word3_add(&w2, &w1, &w0, z[43]); + ws[11] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[13], p[31]); + word3_muladd(&w2, &w1, &w0, ws[14], p[30]); + word3_muladd(&w2, &w1, &w0, ws[15], p[29]); + word3_muladd(&w2, &w1, &w0, ws[16], p[28]); + word3_muladd(&w2, &w1, &w0, ws[17], p[27]); + word3_muladd(&w2, &w1, &w0, ws[18], p[26]); + word3_muladd(&w2, &w1, &w0, ws[19], p[25]); + word3_muladd(&w2, &w1, &w0, ws[20], p[24]); + word3_muladd(&w2, &w1, &w0, ws[21], p[23]); + word3_muladd(&w2, &w1, &w0, ws[22], p[22]); + word3_muladd(&w2, &w1, &w0, ws[23], p[21]); + word3_muladd(&w2, &w1, &w0, ws[24], p[20]); + word3_muladd(&w2, &w1, &w0, ws[25], p[19]); + word3_muladd(&w2, &w1, &w0, ws[26], p[18]); + word3_muladd(&w2, &w1, &w0, ws[27], p[17]); + word3_muladd(&w2, &w1, &w0, ws[28], p[16]); + word3_muladd(&w2, &w1, &w0, ws[29], p[15]); + word3_muladd(&w2, &w1, &w0, ws[30], p[14]); + word3_muladd(&w2, &w1, &w0, ws[31], p[13]); + word3_add(&w2, &w1, &w0, z[44]); + ws[12] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[14], p[31]); + word3_muladd(&w2, &w1, &w0, ws[15], p[30]); + word3_muladd(&w2, &w1, &w0, ws[16], p[29]); + word3_muladd(&w2, &w1, &w0, ws[17], p[28]); + word3_muladd(&w2, &w1, &w0, ws[18], p[27]); + word3_muladd(&w2, &w1, &w0, ws[19], p[26]); + word3_muladd(&w2, &w1, &w0, ws[20], p[25]); + word3_muladd(&w2, &w1, &w0, ws[21], p[24]); + word3_muladd(&w2, &w1, &w0, ws[22], p[23]); + word3_muladd(&w2, &w1, &w0, ws[23], p[22]); + word3_muladd(&w2, &w1, &w0, ws[24], p[21]); + word3_muladd(&w2, &w1, &w0, ws[25], p[20]); + word3_muladd(&w2, &w1, &w0, ws[26], p[19]); + word3_muladd(&w2, &w1, &w0, ws[27], p[18]); + word3_muladd(&w2, &w1, &w0, ws[28], p[17]); + word3_muladd(&w2, &w1, &w0, ws[29], p[16]); + word3_muladd(&w2, &w1, &w0, ws[30], p[15]); + word3_muladd(&w2, &w1, &w0, ws[31], p[14]); + word3_add(&w2, &w1, &w0, z[45]); + ws[13] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[15], p[31]); + word3_muladd(&w2, &w1, &w0, ws[16], p[30]); + word3_muladd(&w2, &w1, &w0, ws[17], p[29]); + word3_muladd(&w2, &w1, &w0, ws[18], p[28]); + word3_muladd(&w2, &w1, &w0, ws[19], p[27]); + word3_muladd(&w2, &w1, &w0, ws[20], p[26]); + word3_muladd(&w2, &w1, &w0, ws[21], p[25]); + word3_muladd(&w2, &w1, &w0, ws[22], p[24]); + word3_muladd(&w2, &w1, &w0, ws[23], p[23]); + word3_muladd(&w2, &w1, &w0, ws[24], p[22]); + word3_muladd(&w2, &w1, &w0, ws[25], p[21]); + word3_muladd(&w2, &w1, &w0, ws[26], p[20]); + word3_muladd(&w2, &w1, &w0, ws[27], p[19]); + word3_muladd(&w2, &w1, &w0, ws[28], p[18]); + word3_muladd(&w2, &w1, &w0, ws[29], p[17]); + word3_muladd(&w2, &w1, &w0, ws[30], p[16]); + word3_muladd(&w2, &w1, &w0, ws[31], p[15]); + word3_add(&w2, &w1, &w0, z[46]); + ws[14] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[16], p[31]); + word3_muladd(&w2, &w1, &w0, ws[17], p[30]); + word3_muladd(&w2, &w1, &w0, ws[18], p[29]); + word3_muladd(&w2, &w1, &w0, ws[19], p[28]); + word3_muladd(&w2, &w1, &w0, ws[20], p[27]); + word3_muladd(&w2, &w1, &w0, ws[21], p[26]); + word3_muladd(&w2, &w1, &w0, ws[22], p[25]); + word3_muladd(&w2, &w1, &w0, ws[23], p[24]); + word3_muladd(&w2, &w1, &w0, ws[24], p[23]); + word3_muladd(&w2, &w1, &w0, ws[25], p[22]); + word3_muladd(&w2, &w1, &w0, ws[26], p[21]); + word3_muladd(&w2, &w1, &w0, ws[27], p[20]); + word3_muladd(&w2, &w1, &w0, ws[28], p[19]); + word3_muladd(&w2, &w1, &w0, ws[29], p[18]); + word3_muladd(&w2, &w1, &w0, ws[30], p[17]); + word3_muladd(&w2, &w1, &w0, ws[31], p[16]); + word3_add(&w2, &w1, &w0, z[47]); + ws[15] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[17], p[31]); + word3_muladd(&w2, &w1, &w0, ws[18], p[30]); + word3_muladd(&w2, &w1, &w0, ws[19], p[29]); + word3_muladd(&w2, &w1, &w0, ws[20], p[28]); + word3_muladd(&w2, &w1, &w0, ws[21], p[27]); + word3_muladd(&w2, &w1, &w0, ws[22], p[26]); + word3_muladd(&w2, &w1, &w0, ws[23], p[25]); + word3_muladd(&w2, &w1, &w0, ws[24], p[24]); + word3_muladd(&w2, &w1, &w0, ws[25], p[23]); + word3_muladd(&w2, &w1, &w0, ws[26], p[22]); + word3_muladd(&w2, &w1, &w0, ws[27], p[21]); + word3_muladd(&w2, &w1, &w0, ws[28], p[20]); + word3_muladd(&w2, &w1, &w0, ws[29], p[19]); + word3_muladd(&w2, &w1, &w0, ws[30], p[18]); + word3_muladd(&w2, &w1, &w0, ws[31], p[17]); + word3_add(&w2, &w1, &w0, z[48]); + ws[16] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[18], p[31]); + word3_muladd(&w2, &w1, &w0, ws[19], p[30]); + word3_muladd(&w2, &w1, &w0, ws[20], p[29]); + word3_muladd(&w2, &w1, &w0, ws[21], p[28]); + word3_muladd(&w2, &w1, &w0, ws[22], p[27]); + word3_muladd(&w2, &w1, &w0, ws[23], p[26]); + word3_muladd(&w2, &w1, &w0, ws[24], p[25]); + word3_muladd(&w2, &w1, &w0, ws[25], p[24]); + word3_muladd(&w2, &w1, &w0, ws[26], p[23]); + word3_muladd(&w2, &w1, &w0, ws[27], p[22]); + word3_muladd(&w2, &w1, &w0, ws[28], p[21]); + word3_muladd(&w2, &w1, &w0, ws[29], p[20]); + word3_muladd(&w2, &w1, &w0, ws[30], p[19]); + word3_muladd(&w2, &w1, &w0, ws[31], p[18]); + word3_add(&w2, &w1, &w0, z[49]); + ws[17] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[19], p[31]); + word3_muladd(&w2, &w1, &w0, ws[20], p[30]); + word3_muladd(&w2, &w1, &w0, ws[21], p[29]); + word3_muladd(&w2, &w1, &w0, ws[22], p[28]); + word3_muladd(&w2, &w1, &w0, ws[23], p[27]); + word3_muladd(&w2, &w1, &w0, ws[24], p[26]); + word3_muladd(&w2, &w1, &w0, ws[25], p[25]); + word3_muladd(&w2, &w1, &w0, ws[26], p[24]); + word3_muladd(&w2, &w1, &w0, ws[27], p[23]); + word3_muladd(&w2, &w1, &w0, ws[28], p[22]); + word3_muladd(&w2, &w1, &w0, ws[29], p[21]); + word3_muladd(&w2, &w1, &w0, ws[30], p[20]); + word3_muladd(&w2, &w1, &w0, ws[31], p[19]); + word3_add(&w2, &w1, &w0, z[50]); + ws[18] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[20], p[31]); + word3_muladd(&w2, &w1, &w0, ws[21], p[30]); + word3_muladd(&w2, &w1, &w0, ws[22], p[29]); + word3_muladd(&w2, &w1, &w0, ws[23], p[28]); + word3_muladd(&w2, &w1, &w0, ws[24], p[27]); + word3_muladd(&w2, &w1, &w0, ws[25], p[26]); + word3_muladd(&w2, &w1, &w0, ws[26], p[25]); + word3_muladd(&w2, &w1, &w0, ws[27], p[24]); + word3_muladd(&w2, &w1, &w0, ws[28], p[23]); + word3_muladd(&w2, &w1, &w0, ws[29], p[22]); + word3_muladd(&w2, &w1, &w0, ws[30], p[21]); + word3_muladd(&w2, &w1, &w0, ws[31], p[20]); + word3_add(&w2, &w1, &w0, z[51]); + ws[19] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[21], p[31]); + word3_muladd(&w2, &w1, &w0, ws[22], p[30]); + word3_muladd(&w2, &w1, &w0, ws[23], p[29]); + word3_muladd(&w2, &w1, &w0, ws[24], p[28]); + word3_muladd(&w2, &w1, &w0, ws[25], p[27]); + word3_muladd(&w2, &w1, &w0, ws[26], p[26]); + word3_muladd(&w2, &w1, &w0, ws[27], p[25]); + word3_muladd(&w2, &w1, &w0, ws[28], p[24]); + word3_muladd(&w2, &w1, &w0, ws[29], p[23]); + word3_muladd(&w2, &w1, &w0, ws[30], p[22]); + word3_muladd(&w2, &w1, &w0, ws[31], p[21]); + word3_add(&w2, &w1, &w0, z[52]); + ws[20] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[22], p[31]); + word3_muladd(&w2, &w1, &w0, ws[23], p[30]); + word3_muladd(&w2, &w1, &w0, ws[24], p[29]); + word3_muladd(&w2, &w1, &w0, ws[25], p[28]); + word3_muladd(&w2, &w1, &w0, ws[26], p[27]); + word3_muladd(&w2, &w1, &w0, ws[27], p[26]); + word3_muladd(&w2, &w1, &w0, ws[28], p[25]); + word3_muladd(&w2, &w1, &w0, ws[29], p[24]); + word3_muladd(&w2, &w1, &w0, ws[30], p[23]); + word3_muladd(&w2, &w1, &w0, ws[31], p[22]); + word3_add(&w2, &w1, &w0, z[53]); + ws[21] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[23], p[31]); + word3_muladd(&w2, &w1, &w0, ws[24], p[30]); + word3_muladd(&w2, &w1, &w0, ws[25], p[29]); + word3_muladd(&w2, &w1, &w0, ws[26], p[28]); + word3_muladd(&w2, &w1, &w0, ws[27], p[27]); + word3_muladd(&w2, &w1, &w0, ws[28], p[26]); + word3_muladd(&w2, &w1, &w0, ws[29], p[25]); + word3_muladd(&w2, &w1, &w0, ws[30], p[24]); + word3_muladd(&w2, &w1, &w0, ws[31], p[23]); + word3_add(&w2, &w1, &w0, z[54]); + ws[22] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[24], p[31]); + word3_muladd(&w2, &w1, &w0, ws[25], p[30]); + word3_muladd(&w2, &w1, &w0, ws[26], p[29]); + word3_muladd(&w2, &w1, &w0, ws[27], p[28]); + word3_muladd(&w2, &w1, &w0, ws[28], p[27]); + word3_muladd(&w2, &w1, &w0, ws[29], p[26]); + word3_muladd(&w2, &w1, &w0, ws[30], p[25]); + word3_muladd(&w2, &w1, &w0, ws[31], p[24]); + word3_add(&w2, &w1, &w0, z[55]); + ws[23] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[25], p[31]); + word3_muladd(&w2, &w1, &w0, ws[26], p[30]); + word3_muladd(&w2, &w1, &w0, ws[27], p[29]); + word3_muladd(&w2, &w1, &w0, ws[28], p[28]); + word3_muladd(&w2, &w1, &w0, ws[29], p[27]); + word3_muladd(&w2, &w1, &w0, ws[30], p[26]); + word3_muladd(&w2, &w1, &w0, ws[31], p[25]); + word3_add(&w2, &w1, &w0, z[56]); + ws[24] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[26], p[31]); + word3_muladd(&w2, &w1, &w0, ws[27], p[30]); + word3_muladd(&w2, &w1, &w0, ws[28], p[29]); + word3_muladd(&w2, &w1, &w0, ws[29], p[28]); + word3_muladd(&w2, &w1, &w0, ws[30], p[27]); + word3_muladd(&w2, &w1, &w0, ws[31], p[26]); + word3_add(&w2, &w1, &w0, z[57]); + ws[25] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[27], p[31]); + word3_muladd(&w2, &w1, &w0, ws[28], p[30]); + word3_muladd(&w2, &w1, &w0, ws[29], p[29]); + word3_muladd(&w2, &w1, &w0, ws[30], p[28]); + word3_muladd(&w2, &w1, &w0, ws[31], p[27]); + word3_add(&w2, &w1, &w0, z[58]); + ws[26] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[28], p[31]); + word3_muladd(&w2, &w1, &w0, ws[29], p[30]); + word3_muladd(&w2, &w1, &w0, ws[30], p[29]); + word3_muladd(&w2, &w1, &w0, ws[31], p[28]); + word3_add(&w2, &w1, &w0, z[59]); + ws[27] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[29], p[31]); + word3_muladd(&w2, &w1, &w0, ws[30], p[30]); + word3_muladd(&w2, &w1, &w0, ws[31], p[29]); + word3_add(&w2, &w1, &w0, z[60]); + ws[28] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[30], p[31]); + word3_muladd(&w2, &w1, &w0, ws[31], p[30]); + word3_add(&w2, &w1, &w0, z[61]); + ws[29] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[31], p[31]); + word3_add(&w2, &w1, &w0, z[62]); + ws[30] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[63]); + ws[31] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[65]); + ws[32] = w0; + ws[33] = w1; + word borrow = bigint_sub3(ws + 32 + 1, ws, 32 + 1, p, 32); + CT::conditional_copy_mem(borrow, z, ws, ws + 33, 33); + clear_mem(z + 32, 2*(32+1) - 32); + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/curve_nistp.h b/comm/third_party/botan/src/lib/math/numbertheory/curve_nistp.h new file mode 100644 index 0000000000..19d1bd2566 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/curve_nistp.h @@ -0,0 +1,49 @@ +/* +* Arithmetic operations specialized for NIST ECC primes +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NIST_PRIMES_H_ +#define BOTAN_NIST_PRIMES_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(curve_nistp.h) + +namespace Botan { + +/** +* NIST Prime reduction functions. +* +* Reduces the value in place +* +* ws is a workspace function which is used as a temporary, +* and will be resized as needed. +*/ +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p521(); +BOTAN_PUBLIC_API(2,0) void redc_p521(BigInt& x, secure_vector& ws); + +/* +Previously this macro indicated if the P-{192,224,256,384} reducers +were available. Now they are always enabled and this macro has no meaning. +The define will be removed in a future major release. +*/ +#define BOTAN_HAS_NIST_PRIME_REDUCERS_W32 + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p384(); +BOTAN_PUBLIC_API(2,0) void redc_p384(BigInt& x, secure_vector& ws); + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p256(); +BOTAN_PUBLIC_API(2,0) void redc_p256(BigInt& x, secure_vector& ws); + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p224(); +BOTAN_PUBLIC_API(2,0) void redc_p224(BigInt& x, secure_vector& ws); + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p192(); +BOTAN_PUBLIC_API(2,0) void redc_p192(BigInt& x, secure_vector& ws); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/dsa_gen.cpp b/comm/third_party/botan/src/lib/math/numbertheory/dsa_gen.cpp new file mode 100644 index 0000000000..a5efbc2662 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/dsa_gen.cpp @@ -0,0 +1,136 @@ +/* +* DSA Parameter Generation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Check if this size is allowed by FIPS 186-3 +*/ +bool fips186_3_valid_size(size_t pbits, size_t qbits) + { + if(qbits == 160) + return (pbits == 1024); + + if(qbits == 224) + return (pbits == 2048); + + if(qbits == 256) + return (pbits == 2048 || pbits == 3072); + + return false; + } + +} + +/* +* Attempt DSA prime generation with given seed +*/ +bool generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits, + const std::vector& seed_c, + size_t offset) + { + if(!fips186_3_valid_size(pbits, qbits)) + throw Invalid_Argument( + "FIPS 186-3 does not allow DSA domain parameters of " + + std::to_string(pbits) + "/" + std::to_string(qbits) + " bits long"); + + if(seed_c.size() * 8 < qbits) + throw Invalid_Argument( + "Generating a DSA parameter set with a " + std::to_string(qbits) + + " bit long q requires a seed at least as many bits long"); + + const std::string hash_name = "SHA-" + std::to_string(qbits); + std::unique_ptr hash(HashFunction::create_or_throw(hash_name)); + + const size_t HASH_SIZE = hash->output_length(); + + class Seed final + { + public: + explicit Seed(const std::vector& s) : m_seed(s) {} + + const std::vector& value() const { return m_seed; } + + Seed& operator++() + { + for(size_t j = m_seed.size(); j > 0; --j) + if(++m_seed[j-1]) + break; + return (*this); + } + private: + std::vector m_seed; + }; + + Seed seed(seed_c); + + q.binary_decode(hash->process(seed.value())); + q.set_bit(qbits-1); + q.set_bit(0); + + if(!is_prime(q, rng, 128, true)) + return false; + + const size_t n = (pbits-1) / (HASH_SIZE * 8), + b = (pbits-1) % (HASH_SIZE * 8); + + BigInt X; + std::vector V(HASH_SIZE * (n+1)); + + Modular_Reducer mod_2q(2*q); + + for(size_t j = 0; j != 4*pbits; ++j) + { + for(size_t k = 0; k <= n; ++k) + { + ++seed; + hash->update(seed.value()); + hash->final(&V[HASH_SIZE * (n-k)]); + } + + if(j >= offset) + { + X.binary_decode(&V[HASH_SIZE - 1 - b/8], + V.size() - (HASH_SIZE - 1 - b/8)); + X.set_bit(pbits-1); + + p = X - (mod_2q.reduce(X) - 1); + + if(p.bits() == pbits && is_prime(p, rng, 128, true)) + return true; + } + } + return false; + } + +/* +* Generate DSA Primes +*/ +std::vector generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits) + { + while(true) + { + std::vector seed(qbits / 8); + rng.randomize(seed.data(), seed.size()); + + if(generate_dsa_primes(rng, p, q, pbits, qbits, seed)) + return seed; + } + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/info.txt b/comm/third_party/botan/src/lib/math/numbertheory/info.txt new file mode 100644 index 0000000000..4b241c1208 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/info.txt @@ -0,0 +1,22 @@ + +NUMBERTHEORY -> 20131128 + + + +curve_nistp.h +numthry.h +pow_mod.h +reducer.h +monty.h + + + +primality.h +monty_exp.h + + + +bigint +hash +rng + diff --git a/comm/third_party/botan/src/lib/math/numbertheory/jacobi.cpp b/comm/third_party/botan/src/lib/math/numbertheory/jacobi.cpp new file mode 100644 index 0000000000..284fc2b204 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/jacobi.cpp @@ -0,0 +1,52 @@ +/* +* Jacobi Function +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +* Calculate the Jacobi symbol +*/ +int32_t jacobi(const BigInt& a, const BigInt& n) + { + if(n.is_even() || n < 2) + throw Invalid_Argument("jacobi: second argument must be odd and > 1"); + + BigInt x = a % n; + BigInt y = n; + int32_t J = 1; + + while(y > 1) + { + x %= y; + if(x > y / 2) + { + x = y - x; + if(y % 4 == 3) + J = -J; + } + if(x.is_zero()) + return 0; + + size_t shifts = low_zero_bits(x); + x >>= shifts; + if(shifts % 2) + { + word y_mod_8 = y % 8; + if(y_mod_8 == 3 || y_mod_8 == 5) + J = -J; + } + + if(x % 4 == 3 && y % 4 == 3) + J = -J; + std::swap(x, y); + } + return J; + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/make_prm.cpp b/comm/third_party/botan/src/lib/math/numbertheory/make_prm.cpp new file mode 100644 index 0000000000..404e301046 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/make_prm.cpp @@ -0,0 +1,293 @@ +/* +* Prime Generation +* (C) 1999-2007,2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class Prime_Sieve final + { + public: + Prime_Sieve(const BigInt& init_value, size_t sieve_size) : + m_sieve(std::min(sieve_size, PRIME_TABLE_SIZE)) + { + for(size_t i = 0; i != m_sieve.size(); ++i) + m_sieve[i] = static_cast(init_value % PRIMES[i]); + } + + void step(word increment) + { + for(size_t i = 0; i != m_sieve.size(); ++i) + { + m_sieve[i] = (m_sieve[i] + increment) % PRIMES[i]; + } + } + + bool passes(bool check_2p1 = false) const + { + for(size_t i = 0; i != m_sieve.size(); ++i) + { + /* + In this case, p is a multiple of PRIMES[i] + */ + if(m_sieve[i] == 0) + return false; + + if(check_2p1) + { + /* + In this case, 2*p+1 will be a multiple of PRIMES[i] + + So if potentially generating a safe prime, we want to + avoid this value because 2*p+1 will certainly not be prime. + + See "Safe Prime Generation with a Combined Sieve" M. Wiener + https://eprint.iacr.org/2003/186.pdf + */ + if(m_sieve[i] == (PRIMES[i] - 1) / 2) + return false; + } + } + + return true; + } + + private: + std::vector m_sieve; + }; + +} + + +/* +* Generate a random prime +*/ +BigInt random_prime(RandomNumberGenerator& rng, + size_t bits, const BigInt& coprime, + size_t equiv, size_t modulo, + size_t prob) + { + if(bits <= 1) + { + throw Invalid_Argument("random_prime: Can't make a prime of " + + std::to_string(bits) + " bits"); + } + if(coprime.is_negative() || (!coprime.is_zero() && coprime.is_even()) || coprime.bits() >= bits) + { + throw Invalid_Argument("random_prime: invalid coprime"); + } + if(modulo == 0) + { + throw Invalid_Argument("random_prime: Invalid modulo value"); + } + + equiv %= modulo; + + if(equiv == 0) + throw Invalid_Argument("random_prime Invalid value for equiv/modulo"); + + // Handle small values: + + if(bits <= 16) + { + if(equiv != 1 || modulo != 2 || coprime != 0) + throw Not_Implemented("random_prime equiv/modulo/coprime options not usable for small primes"); + + if(bits == 2) + { + return ((rng.next_byte() % 2) ? 2 : 3); + } + else if(bits == 3) + { + return ((rng.next_byte() % 2) ? 5 : 7); + } + else if(bits == 4) + { + return ((rng.next_byte() % 2) ? 11 : 13); + } + else + { + for(;;) + { + // This is slightly biased, but for small primes it does not seem to matter + uint8_t b[4]; + rng.randomize(b, 4); + const size_t idx = load_le(b, 0) % PRIME_TABLE_SIZE; + const uint16_t small_prime = PRIMES[idx]; + + if(high_bit(small_prime) == bits) + return small_prime; + } + } + } + + const size_t MAX_ATTEMPTS = 32*1024; + + const size_t mr_trials = miller_rabin_test_iterations(bits, prob, true); + + while(true) + { + BigInt p(rng, bits); + + // Force lowest and two top bits on + p.set_bit(bits - 1); + p.set_bit(bits - 2); + p.set_bit(0); + + // Force p to be equal to equiv mod modulo + p += (modulo - (p % modulo)) + equiv; + + Prime_Sieve sieve(p, bits); + + for(size_t attempt = 0; attempt <= MAX_ATTEMPTS; ++attempt) + { + p += modulo; + + sieve.step(modulo); + + // p can be even if modulo is odd, continue on in that case + if(p.is_even() || sieve.passes(true) == false) + continue; + + Modular_Reducer mod_p(p); + + if(coprime > 1) + { + /* + First do a single M-R iteration to quickly elimate most non-primes, + before doing the coprimality check which is expensive + */ + if(is_miller_rabin_probable_prime(p, mod_p, rng, 1) == false) + continue; + + /* + * Check if p - 1 and coprime are relatively prime, using gcd. + * The gcd computation is const-time + */ + if(gcd(p - 1, coprime) > 1) + continue; + } + + if(p.bits() > bits) + break; + + if(is_miller_rabin_probable_prime(p, mod_p, rng, mr_trials) == false) + continue; + + if(prob > 32 && !is_lucas_probable_prime(p, mod_p)) + continue; + + return p; + } + } + } + +BigInt generate_rsa_prime(RandomNumberGenerator& keygen_rng, + RandomNumberGenerator& prime_test_rng, + size_t bits, + const BigInt& coprime, + size_t prob) + { + if(bits < 512) + throw Invalid_Argument("generate_rsa_prime bits too small"); + + /* + * The restriction on coprime <= 64 bits is arbitrary but generally speaking + * very large RSA public exponents are a bad idea both for performance and due + * to attacks on small d. + */ + if(coprime <= 1 || coprime.is_even() || coprime.bits() > 64) + throw Invalid_Argument("generate_rsa_prime coprime must be small odd positive integer"); + + const size_t MAX_ATTEMPTS = 32*1024; + + const size_t mr_trials = miller_rabin_test_iterations(bits, prob, true); + + while(true) + { + BigInt p(keygen_rng, bits); + + // Force high two bits so multiplication always results in expected n bit integer + p.set_bit(bits - 1); + p.set_bit(bits - 2); + p.set_bit(0); + + const word step = 2; + + Prime_Sieve sieve(p, bits); + + for(size_t attempt = 0; attempt <= MAX_ATTEMPTS; ++attempt) + { + p += step; + + sieve.step(step); + + if(sieve.passes() == false) + continue; + + Modular_Reducer mod_p(p); + + /* + * Do a single primality test first before checking coprimality, since + * currently a single Miller-Rabin test is faster than computing gcd, + * and this eliminates almost all wasted gcd computations. + */ + if(is_miller_rabin_probable_prime(p, mod_p, prime_test_rng, 1) == false) + continue; + + /* + * Check if p - 1 and coprime are relatively prime. + */ + if(gcd(p - 1, coprime) > 1) + continue; + + if(p.bits() > bits) + break; + + if(is_miller_rabin_probable_prime(p, mod_p, prime_test_rng, mr_trials) == true) + return p; + } + } + } + +/* +* Generate a random safe prime +*/ +BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) + { + if(bits <= 64) + throw Invalid_Argument("random_safe_prime: Can't make a prime of " + + std::to_string(bits) + " bits"); + + const size_t error_bound = 128; + + BigInt q, p; + for(;;) + { + /* + Generate q == 2 (mod 3), since otherwise [in the case of q == 1 (mod 3)], + 2*q+1 == 3 (mod 3) and so certainly not prime. + */ + q = random_prime(rng, bits - 1, 0, 2, 3, error_bound); + p = (q << 1) + 1; + + if(is_prime(p, rng, error_bound, true)) + { + return p; + } + } + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/mod_inv.cpp b/comm/third_party/botan/src/lib/math/numbertheory/mod_inv.cpp new file mode 100644 index 0000000000..ec3bb33f00 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/mod_inv.cpp @@ -0,0 +1,356 @@ +/* +* (C) 1999-2011,2016,2018,2019,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +Sets result to a^-1 * 2^k mod a +with n <= k <= 2n +Returns k + +"The Montgomery Modular Inverse - Revisited" Çetin Koç, E. Savas +https://citeseerx.ist.psu.edu/viewdoc/citations?doi=10.1.1.75.8377 + +A const time implementation of this algorithm is described in +"Constant Time Modular Inversion" Joppe W. Bos +http://www.joppebos.com/files/CTInversion.pdf +*/ +size_t almost_montgomery_inverse(BigInt& result, + const BigInt& a, + const BigInt& p) + { + size_t k = 0; + + BigInt u = p, v = a, r = 0, s = 1; + + while(v > 0) + { + if(u.is_even()) + { + u >>= 1; + s <<= 1; + } + else if(v.is_even()) + { + v >>= 1; + r <<= 1; + } + else if(u > v) + { + u -= v; + u >>= 1; + r += s; + s <<= 1; + } + else + { + v -= u; + v >>= 1; + s += r; + r <<= 1; + } + + ++k; + } + + if(r >= p) + { + r -= p; + } + + result = p - r; + + return k; + } + +BigInt normalized_montgomery_inverse(const BigInt& a, const BigInt& p) + { + BigInt r; + size_t k = almost_montgomery_inverse(r, a, p); + + for(size_t i = 0; i != k; ++i) + { + if(r.is_odd()) + r += p; + r >>= 1; + } + + return r; + } + +namespace { + +BigInt inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) + { + // Caller should assure these preconditions: + BOTAN_DEBUG_ASSERT(n.is_positive()); + BOTAN_DEBUG_ASSERT(mod.is_positive()); + BOTAN_DEBUG_ASSERT(n < mod); + BOTAN_DEBUG_ASSERT(mod >= 3 && mod.is_odd()); + + /* + This uses a modular inversion algorithm designed by Niels Möller + and implemented in Nettle. The same algorithm was later also + adapted to GMP in mpn_sec_invert. + + It can be easily implemented in a way that does not depend on + secret branches or memory lookups, providing resistance against + some forms of side channel attack. + + There is also a description of the algorithm in Appendix 5 of "Fast + Software Polynomial Multiplication on ARM Processors using the NEON Engine" + by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo + Dahab in LNCS 8182 + https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf + + Thanks to Niels for creating the algorithm, explaining some things + about it, and the reference to the paper. + */ + + const size_t mod_words = mod.sig_words(); + BOTAN_ASSERT(mod_words > 0, "Not empty"); + + secure_vector tmp_mem(5*mod_words); + + word* v_w = &tmp_mem[0]; + word* u_w = &tmp_mem[1*mod_words]; + word* b_w = &tmp_mem[2*mod_words]; + word* a_w = &tmp_mem[3*mod_words]; + word* mp1o2 = &tmp_mem[4*mod_words]; + + CT::poison(tmp_mem.data(), tmp_mem.size()); + + copy_mem(a_w, n.data(), std::min(n.size(), mod_words)); + copy_mem(b_w, mod.data(), std::min(mod.size(), mod_words)); + u_w[0] = 1; + // v_w = 0 + + // compute (mod + 1) / 2 which [because mod is odd] is equal to + // (mod / 2) + 1 + copy_mem(mp1o2, mod.data(), std::min(mod.size(), mod_words)); + bigint_shr1(mp1o2, mod_words, 0, 1); + word carry = bigint_add2_nc(mp1o2, mod_words, u_w, 1); + BOTAN_ASSERT_NOMSG(carry == 0); + + // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n + const size_t execs = 2 * mod.bits(); + + for(size_t i = 0; i != execs; ++i) + { + const word odd_a = a_w[0] & 1; + + //if(odd_a) a -= b + word underflow = bigint_cnd_sub(odd_a, a_w, b_w, mod_words); + + //if(underflow) { b -= a; a = abs(a); swap(u, v); } + bigint_cnd_add(underflow, b_w, a_w, mod_words); + bigint_cnd_abs(underflow, a_w, mod_words); + bigint_cnd_swap(underflow, u_w, v_w, mod_words); + + // a >>= 1 + bigint_shr1(a_w, mod_words, 0, 1); + + //if(odd_a) u -= v; + word borrow = bigint_cnd_sub(odd_a, u_w, v_w, mod_words); + + // if(borrow) u += p + bigint_cnd_add(borrow, u_w, mod.data(), mod_words); + + const word odd_u = u_w[0] & 1; + + // u >>= 1 + bigint_shr1(u_w, mod_words, 0, 1); + + //if(odd_u) u += mp1o2; + bigint_cnd_add(odd_u, u_w, mp1o2, mod_words); + } + + auto a_is_0 = CT::Mask::set(); + for(size_t i = 0; i != mod_words; ++i) + a_is_0 &= CT::Mask::is_zero(a_w[i]); + + auto b_is_1 = CT::Mask::is_equal(b_w[0], 1); + for(size_t i = 1; i != mod_words; ++i) + b_is_1 &= CT::Mask::is_zero(b_w[i]); + + BOTAN_ASSERT(a_is_0.is_set(), "A is zero"); + + // if b != 1 then gcd(n,mod) > 1 and inverse does not exist + // in which case zero out the result to indicate this + (~b_is_1).if_set_zero_out(v_w, mod_words); + + /* + * We've placed the result in the lowest words of the temp buffer. + * So just clear out the other values and then give that buffer to a + * BigInt. + */ + clear_mem(&tmp_mem[mod_words], 4*mod_words); + + CT::unpoison(tmp_mem.data(), tmp_mem.size()); + + BigInt r; + r.swap_reg(tmp_mem); + return r; + } + +BigInt inverse_mod_pow2(const BigInt& a1, size_t k) + { + /* + * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç + * https://eprint.iacr.org/2017/411.pdf sections 5 and 7. + */ + + if(a1.is_even()) + return 0; + + BigInt a = a1; + a.mask_bits(k); + + BigInt b = 1; + BigInt X = 0; + BigInt newb; + + const size_t a_words = a.sig_words(); + + X.grow_to(round_up(k, BOTAN_MP_WORD_BITS) / BOTAN_MP_WORD_BITS); + b.grow_to(a_words); + + /* + Hide the exact value of k. k is anyway known to word length + granularity because of the length of a, so no point in doing more + than this. + */ + const size_t iter = round_up(k, BOTAN_MP_WORD_BITS); + + for(size_t i = 0; i != iter; ++i) + { + const bool b0 = b.get_bit(0); + X.conditionally_set_bit(i, b0); + newb = b - a; + b.ct_cond_assign(b0, newb); + b >>= 1; + } + + X.mask_bits(k); + X.const_time_unpoison(); + return X; + } + +} + +BigInt inverse_mod(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative() || n.is_negative()) + throw Invalid_Argument("inverse_mod: arguments must be non-negative"); + if(n.is_zero() || (n.is_even() && mod.is_even())) + return 0; + + if(mod.is_odd()) + { + /* + Fastpath for common case. This leaks information if n > mod + but we don't guarantee const time behavior in that case. + */ + if(n < mod) + return inverse_mod_odd_modulus(n, mod); + else + return inverse_mod_odd_modulus(ct_modulo(n, mod), mod); + } + + const size_t mod_lz = low_zero_bits(mod); + BOTAN_ASSERT_NOMSG(mod_lz > 0); + const size_t mod_bits = mod.bits(); + BOTAN_ASSERT_NOMSG(mod_bits > mod_lz); + + if(mod_lz == mod_bits - 1) + { + // In this case we are performing an inversion modulo 2^k + return inverse_mod_pow2(n, mod_lz); + } + + /* + * In this case we are performing an inversion modulo 2^k*o for + * some k > 1 and some odd (not necessarily prime) integer. + * Compute the inversions modulo 2^k and modulo o, then combine them + * using CRT, which is possible because 2^k and o are relatively prime. + */ + + const BigInt o = mod >> mod_lz; + const BigInt n_redc = ct_modulo(n, o); + const BigInt inv_o = inverse_mod_odd_modulus(n_redc, o); + const BigInt inv_2k = inverse_mod_pow2(n, mod_lz); + + // No modular inverse in this case: + if(inv_o == 0 || inv_2k == 0) + return 0; + + const BigInt m2k = BigInt::power_of_2(mod_lz); + // Compute the CRT parameter + const BigInt c = inverse_mod_pow2(o, mod_lz); + + // Compute h = c*(inv_2k-inv_o) mod 2^k + BigInt h = c * (inv_2k - inv_o); + const bool h_neg = h.is_negative(); + h.set_sign(BigInt::Positive); + h.mask_bits(mod_lz); + const bool h_nonzero = h.is_nonzero(); + h.ct_cond_assign(h_nonzero && h_neg, m2k - h); + + // Return result inv_o + h * o + h *= o; + h += inv_o; + return h; + } + +// Deprecated forwarding functions: +BigInt inverse_euclid(const BigInt& x, const BigInt& modulus) + { + return inverse_mod(x, modulus); + } + +BigInt ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) + { + return inverse_mod_odd_modulus(n, mod); + } + +word monty_inverse(word a) + { + if(a % 2 == 0) + throw Invalid_Argument("monty_inverse only valid for odd integers"); + + /* + * From "A New Algorithm for Inversion mod p^k" by Çetin Kaya Koç + * https://eprint.iacr.org/2017/411.pdf sections 5 and 7. + */ + + word b = 1; + word r = 0; + + for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i) + { + const word bi = b % 2; + r >>= 1; + r += bi << (BOTAN_MP_WORD_BITS - 1); + + b -= a * bi; + b >>= 1; + } + + // Now invert in addition space + r = (MP_WORD_MAX - r) + 1; + + return r; + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/monty.cpp b/comm/third_party/botan/src/lib/math/numbertheory/monty.cpp new file mode 100644 index 0000000000..ca5eb73dfd --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/monty.cpp @@ -0,0 +1,444 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +Montgomery_Params::Montgomery_Params(const BigInt& p, + const Modular_Reducer& mod_p) + { + if(p.is_even() || p < 3) + throw Invalid_Argument("Montgomery_Params invalid modulus"); + + m_p = p; + m_p_words = m_p.sig_words(); + m_p_dash = monty_inverse(m_p.word_at(0)); + + const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); + + m_r1 = mod_p.reduce(r); + m_r2 = mod_p.square(m_r1); + m_r3 = mod_p.multiply(m_r1, m_r2); + } + +Montgomery_Params::Montgomery_Params(const BigInt& p) + { + + if(p.is_negative() || p.is_even()) + throw Invalid_Argument("Montgomery_Params invalid modulus"); + + m_p = p; + m_p_words = m_p.sig_words(); + m_p_dash = monty_inverse(m_p.word_at(0)); + + const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); + + // It might be faster to use ct_modulo here vs setting up Barrett reduction? + Modular_Reducer mod_p(p); + + m_r1 = mod_p.reduce(r); + m_r2 = mod_p.square(m_r1); + m_r3 = mod_p.multiply(m_r1, m_r2); + } + +BigInt Montgomery_Params::inv_mod_p(const BigInt& x) const + { + // TODO use Montgomery inverse here? + return inverse_mod(x, p()); + } + +BigInt Montgomery_Params::redc(const BigInt& x, secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < output_size) + ws.resize(output_size); + + BigInt z = x; + z.grow_to(output_size); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y, + secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < output_size) + ws.resize(output_size); + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); + + BigInt z(BigInt::Positive, output_size); + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +BigInt Montgomery_Params::mul(const BigInt& x, + const secure_vector& y, + secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + if(ws.size() < output_size) + ws.resize(output_size); + BigInt z(BigInt::Positive, output_size); + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +void Montgomery_Params::mul_by(BigInt& x, + const secure_vector& y, + secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < 2*output_size) + ws.resize(2*output_size); + + word* z_data = &ws[0]; + word* ws_data = &ws[output_size]; + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_mul(z_data, output_size, + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws_data, output_size); + + bigint_monty_redc(z_data, + m_p.data(), m_p_words, m_p_dash, + ws_data, output_size); + + if(x.size() < output_size) + x.grow_to(output_size); + copy_mem(x.mutable_data(), z_data, output_size); + } + +void Montgomery_Params::mul_by(BigInt& x, + const BigInt& y, + secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < 2*output_size) + ws.resize(2*output_size); + + word* z_data = &ws[0]; + word* ws_data = &ws[output_size]; + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_mul(z_data, output_size, + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws_data, output_size); + + bigint_monty_redc(z_data, + m_p.data(), m_p_words, m_p_dash, + ws_data, output_size); + + if(x.size() < output_size) + x.grow_to(output_size); + copy_mem(x.mutable_data(), z_data, output_size); + } + +BigInt Montgomery_Params::sqr(const BigInt& x, secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < output_size) + ws.resize(output_size); + + BigInt z(BigInt::Positive, output_size); + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_sqr(z.mutable_data(), z.size(), + x.data(), x.size(), std::min(m_p_words, x.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +void Montgomery_Params::square_this(BigInt& x, + secure_vector& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < 2*output_size) + ws.resize(2*output_size); + + word* z_data = &ws[0]; + word* ws_data = &ws[output_size]; + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_sqr(z_data, output_size, + x.data(), x.size(), std::min(m_p_words, x.size()), + ws_data, output_size); + + bigint_monty_redc(z_data, + m_p.data(), m_p_words, m_p_dash, + ws_data, output_size); + + if(x.size() < output_size) + x.grow_to(output_size); + copy_mem(x.mutable_data(), z_data, output_size); + } + +Montgomery_Int::Montgomery_Int(const std::shared_ptr params, + const BigInt& v, + bool redc_needed) : + m_params(params) + { + if(redc_needed == false) + { + m_v = v; + } + else + { + BOTAN_ASSERT_NOMSG(m_v < m_params->p()); + secure_vector ws; + m_v = m_params->mul(v, m_params->R2(), ws); + } + } + +Montgomery_Int::Montgomery_Int(std::shared_ptr params, + const uint8_t bits[], size_t len, + bool redc_needed) : + m_params(params), + m_v(bits, len) + { + if(redc_needed) + { + BOTAN_ASSERT_NOMSG(m_v < m_params->p()); + secure_vector ws; + m_v = m_params->mul(m_v, m_params->R2(), ws); + } + } + +Montgomery_Int::Montgomery_Int(std::shared_ptr params, + const word words[], size_t len, + bool redc_needed) : + m_params(params), + m_v(words, len) + { + if(redc_needed) + { + BOTAN_ASSERT_NOMSG(m_v < m_params->p()); + secure_vector ws; + m_v = m_params->mul(m_v, m_params->R2(), ws); + } + } + +void Montgomery_Int::fix_size() + { + const size_t p_words = m_params->p_words(); + + if(m_v.sig_words() > p_words) + throw Internal_Error("Montgomery_Int::fix_size v too large"); + + m_v.grow_to(p_words); + } + +bool Montgomery_Int::operator==(const Montgomery_Int& other) const + { + return m_v == other.m_v && m_params->p() == other.m_params->p(); + } + +std::vector Montgomery_Int::serialize() const + { + std::vector v(size()); + BigInt::encode_1363(v.data(), v.size(), value()); + return v; + } + +size_t Montgomery_Int::size() const + { + return m_params->p().bytes(); + } + +bool Montgomery_Int::is_one() const + { + return m_v == m_params->R1(); + } + +bool Montgomery_Int::is_zero() const + { + return m_v.is_zero(); + } + +BigInt Montgomery_Int::value() const + { + secure_vector ws; + return m_params->redc(m_v, ws); + } + +Montgomery_Int Montgomery_Int::operator+(const Montgomery_Int& other) const + { + secure_vector ws; + BigInt z = m_v; + z.mod_add(other.m_v, m_params->p(), ws); + return Montgomery_Int(m_params, z, false); + } + +Montgomery_Int Montgomery_Int::operator-(const Montgomery_Int& other) const + { + secure_vector ws; + BigInt z = m_v; + z.mod_sub(other.m_v, m_params->p(), ws); + return Montgomery_Int(m_params, z, false); + } + +Montgomery_Int& Montgomery_Int::operator+=(const Montgomery_Int& other) + { + secure_vector ws; + return this->add(other, ws); + } + +Montgomery_Int& Montgomery_Int::add(const Montgomery_Int& other, secure_vector& ws) + { + m_v.mod_add(other.m_v, m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::operator-=(const Montgomery_Int& other) + { + secure_vector ws; + return this->sub(other, ws); + } + +Montgomery_Int& Montgomery_Int::sub(const Montgomery_Int& other, secure_vector& ws) + { + m_v.mod_sub(other.m_v, m_params->p(), ws); + return (*this); + } + +Montgomery_Int Montgomery_Int::operator*(const Montgomery_Int& other) const + { + secure_vector ws; + return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false); + } + +Montgomery_Int Montgomery_Int::mul(const Montgomery_Int& other, + secure_vector& ws) const + { + return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false); + } + +Montgomery_Int& Montgomery_Int::mul_by(const Montgomery_Int& other, + secure_vector& ws) + { + m_params->mul_by(m_v, other.m_v, ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by(const secure_vector& other, + secure_vector& ws) + { + m_params->mul_by(m_v, other, ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::operator*=(const Montgomery_Int& other) + { + secure_vector ws; + return mul_by(other, ws); + } + +Montgomery_Int& Montgomery_Int::operator*=(const secure_vector& other) + { + secure_vector ws; + return mul_by(other, ws); + } + +Montgomery_Int& Montgomery_Int::square_this_n_times(secure_vector& ws, size_t n) + { + for(size_t i = 0; i != n; ++i) + m_params->square_this(m_v, ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::square_this(secure_vector& ws) + { + m_params->square_this(m_v, ws); + return (*this); + } + +Montgomery_Int Montgomery_Int::square(secure_vector& ws) const + { + return Montgomery_Int(m_params, m_params->sqr(m_v, ws), false); + } + +Montgomery_Int Montgomery_Int::multiplicative_inverse() const + { + secure_vector ws; + const BigInt iv = m_params->mul(m_params->inv_mod_p(m_v), m_params->R3(), ws); + return Montgomery_Int(m_params, iv, false); + } + +Montgomery_Int Montgomery_Int::additive_inverse() const + { + return Montgomery_Int(m_params, m_params->p()) - (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_2(secure_vector& ws) + { + m_v.mod_mul(2, m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_3(secure_vector& ws) + { + m_v.mod_mul(3, m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_4(secure_vector& ws) + { + m_v.mod_mul(4, m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_8(secure_vector& ws) + { + m_v.mod_mul(8, m_params->p(), ws); + return (*this); + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/monty.h b/comm/third_party/botan/src/lib/math/numbertheory/monty.h new file mode 100644 index 0000000000..8e0cd342fb --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/monty.h @@ -0,0 +1,191 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MONTY_INT_H_ +#define BOTAN_MONTY_INT_H_ + +#include +BOTAN_FUTURE_INTERNAL_HEADER(monty.h) + +namespace Botan { + +class Modular_Reducer; + +class Montgomery_Params; + +/** +* The Montgomery representation of an integer +*/ +class BOTAN_UNSTABLE_API Montgomery_Int final + { + public: + /** + * Create a zero-initialized Montgomery_Int + */ + Montgomery_Int(std::shared_ptr params) : m_params(params) {} + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr params, + const BigInt& v, + bool redc_needed = true); + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr params, + const uint8_t bits[], size_t len, + bool redc_needed = true); + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr params, + const word words[], size_t len, + bool redc_needed = true); + + bool operator==(const Montgomery_Int& other) const; + bool operator!=(const Montgomery_Int& other) const { return (m_v != other.m_v); } + + std::vector serialize() const; + + size_t size() const; + bool is_one() const; + bool is_zero() const; + + void fix_size(); + + /** + * Return the value to normal mod-p space + */ + BigInt value() const; + + /** + * Return the Montgomery representation + */ + const BigInt& repr() const { return m_v; } + + Montgomery_Int operator+(const Montgomery_Int& other) const; + + Montgomery_Int operator-(const Montgomery_Int& other) const; + + Montgomery_Int& operator+=(const Montgomery_Int& other); + + Montgomery_Int& operator-=(const Montgomery_Int& other); + + Montgomery_Int operator*(const Montgomery_Int& other) const; + + Montgomery_Int& operator*=(const Montgomery_Int& other); + + Montgomery_Int& operator*=(const secure_vector& other); + + Montgomery_Int& add(const Montgomery_Int& other, + secure_vector& ws); + + Montgomery_Int& sub(const Montgomery_Int& other, + secure_vector& ws); + + Montgomery_Int mul(const Montgomery_Int& other, + secure_vector& ws) const; + + Montgomery_Int& mul_by(const Montgomery_Int& other, + secure_vector& ws); + + Montgomery_Int& mul_by(const secure_vector& other, + secure_vector& ws); + + Montgomery_Int square(secure_vector& ws) const; + + Montgomery_Int& square_this(secure_vector& ws); + + Montgomery_Int& square_this_n_times(secure_vector& ws, size_t n); + + Montgomery_Int multiplicative_inverse() const; + + Montgomery_Int additive_inverse() const; + + Montgomery_Int& mul_by_2(secure_vector& ws); + + Montgomery_Int& mul_by_3(secure_vector& ws); + + Montgomery_Int& mul_by_4(secure_vector& ws); + + Montgomery_Int& mul_by_8(secure_vector& ws); + + void const_time_poison() const { m_v.const_time_poison(); } + void const_time_unpoison() const { return m_v.const_time_unpoison(); } + + private: + std::shared_ptr m_params; + BigInt m_v; + }; + +/** +* Parameters for Montgomery Reduction +*/ +class BOTAN_UNSTABLE_API Montgomery_Params final + { + public: + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + Montgomery_Params(const BigInt& p, const Modular_Reducer& mod_p); + + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + Montgomery_Params(const BigInt& p); + + const BigInt& p() const { return m_p; } + const BigInt& R1() const { return m_r1; } + const BigInt& R2() const { return m_r2; } + const BigInt& R3() const { return m_r3; } + + word p_dash() const { return m_p_dash; } + + size_t p_words() const { return m_p_words; } + + BigInt redc(const BigInt& x, + secure_vector& ws) const; + + BigInt mul(const BigInt& x, + const BigInt& y, + secure_vector& ws) const; + + BigInt mul(const BigInt& x, + const secure_vector& y, + secure_vector& ws) const; + + void mul_by(BigInt& x, + const secure_vector& y, + secure_vector& ws) const; + + void mul_by(BigInt& x, const BigInt& y, + secure_vector& ws) const; + + BigInt sqr(const BigInt& x, + secure_vector& ws) const; + + void square_this(BigInt& x, + secure_vector& ws) const; + + BigInt inv_mod_p(const BigInt& x) const; + + private: + BigInt m_p; + BigInt m_r1; + BigInt m_r2; + BigInt m_r3; + word m_p_dash; + size_t m_p_words; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/monty_exp.cpp b/comm/third_party/botan/src/lib/math/numbertheory/monty_exp.cpp new file mode 100644 index 0000000000..02ae795cd9 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/monty_exp.cpp @@ -0,0 +1,254 @@ +/* +* Montgomery Exponentiation +* (C) 1999-2010,2012,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class Montgomery_Exponentation_State + { + public: + Montgomery_Exponentation_State(std::shared_ptr params, + const BigInt& g, + size_t window_bits, + bool const_time); + + BigInt exponentiation(const BigInt& k, size_t max_k_bits) const; + + BigInt exponentiation_vartime(const BigInt& k) const; + private: + std::shared_ptr m_params; + std::vector m_g; + size_t m_window_bits; + bool m_const_time; + }; + +Montgomery_Exponentation_State::Montgomery_Exponentation_State(std::shared_ptr params, + const BigInt& g, + size_t window_bits, + bool const_time) : + m_params(params), + m_window_bits(window_bits == 0 ? 4 : window_bits), + m_const_time(const_time) + { + BOTAN_ARG_CHECK(g < m_params->p(), "Montgomery base too big"); + + if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ... + throw Invalid_Argument("Invalid window bits for Montgomery exponentiation"); + + const size_t window_size = (static_cast(1) << m_window_bits); + + m_g.reserve(window_size); + + m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false)); + + m_g.push_back(Montgomery_Int(m_params, g)); + + for(size_t i = 2; i != window_size; ++i) + { + m_g.push_back(m_g[1] * m_g[i - 1]); + } + + // Resize each element to exactly p words + for(size_t i = 0; i != window_size; ++i) + { + m_g[i].fix_size(); + if(const_time) + m_g[i].const_time_poison(); + } + } + +namespace { + +void const_time_lookup(secure_vector& output, + const std::vector& g, + size_t nibble) + { + BOTAN_ASSERT_NOMSG(g.size() % 2 == 0); // actually a power of 2 + + const size_t words = output.size(); + + clear_mem(output.data(), output.size()); + + for(size_t i = 0; i != g.size(); i += 2) + { + const secure_vector& vec_0 = g[i ].repr().get_word_vector(); + const secure_vector& vec_1 = g[i+1].repr().get_word_vector(); + + BOTAN_ASSERT_NOMSG(vec_0.size() >= words && vec_1.size() >= words); + + const auto mask_0 = CT::Mask::is_equal(nibble, i); + const auto mask_1 = CT::Mask::is_equal(nibble, i+1); + + for(size_t w = 0; w != words; ++w) + { + output[w] |= mask_0.if_set_return(vec_0[w]); + output[w] |= mask_1.if_set_return(vec_1[w]); + } + } + } + +} + +BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const + { + BOTAN_DEBUG_ASSERT(scalar.bits() <= max_k_bits); + // TODO add a const-time implementation of above assert and use it in release builds + + const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits; + + if(exp_nibbles == 0) + return 1; + + secure_vector e_bits(m_params->p_words()); + secure_vector ws; + + const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)); + Montgomery_Int x(m_params, e_bits.data(), e_bits.size(), false); + + for(size_t i = exp_nibbles - 1; i > 0; --i) + { + x.square_this_n_times(ws, m_window_bits); + const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(i-1), m_window_bits)); + x.mul_by(e_bits, ws); + } + + x.const_time_unpoison(); + return x.value(); + } + +BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const + { + BOTAN_ASSERT_NOMSG(m_const_time == false); + + const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits; + + secure_vector ws; + + if(exp_nibbles == 0) + return 1; + + Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)]; + + for(size_t i = exp_nibbles - 1; i > 0; --i) + { + x.square_this_n_times(ws, m_window_bits); + + const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits); + if(nibble > 0) + x.mul_by(m_g[nibble], ws); + } + + x.const_time_unpoison(); + return x.value(); + } + +std::shared_ptr +monty_precompute(std::shared_ptr params, + const BigInt& g, + size_t window_bits, + bool const_time) + { + return std::make_shared(params, g, window_bits, const_time); + } + +BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k, size_t max_k_bits) + { + return precomputed_state.exponentiation(k, max_k_bits); + } + +BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k) + { + return precomputed_state.exponentiation_vartime(k); + } + +BigInt monty_multi_exp(std::shared_ptr params_p, + const BigInt& x_bn, + const BigInt& z1, + const BigInt& y_bn, + const BigInt& z2) + { + if(z1.is_negative() || z2.is_negative()) + throw Invalid_Argument("multi_exponentiate exponents must be positive"); + + const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); + + secure_vector ws; + + const Montgomery_Int one(params_p, params_p->R1(), false); + //const Montgomery_Int one(params_p, 1); + + const Montgomery_Int x1(params_p, x_bn); + const Montgomery_Int x2 = x1.square(ws); + const Montgomery_Int x3 = x2.mul(x1, ws); + + const Montgomery_Int y1(params_p, y_bn); + const Montgomery_Int y2 = y1.square(ws); + const Montgomery_Int y3 = y2.mul(y1, ws); + + const Montgomery_Int y1x1 = y1.mul(x1, ws); + const Montgomery_Int y1x2 = y1.mul(x2, ws); + const Montgomery_Int y1x3 = y1.mul(x3, ws); + + const Montgomery_Int y2x1 = y2.mul(x1, ws); + const Montgomery_Int y2x2 = y2.mul(x2, ws); + const Montgomery_Int y2x3 = y2.mul(x3, ws); + + const Montgomery_Int y3x1 = y3.mul(x1, ws); + const Montgomery_Int y3x2 = y3.mul(x2, ws); + const Montgomery_Int y3x3 = y3.mul(x3, ws); + + const Montgomery_Int* M[16] = { + &one, + &x1, // 0001 + &x2, // 0010 + &x3, // 0011 + &y1, // 0100 + &y1x1, + &y1x2, + &y1x3, + &y2, // 1000 + &y2x1, + &y2x2, + &y2x3, + &y3, // 1100 + &y3x1, + &y3x2, + &y3x3 + }; + + Montgomery_Int H = one; + + for(size_t i = 0; i != z_bits; i += 2) + { + if(i > 0) + { + H.square_this(ws); + H.square_this(ws); + } + + const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2); + const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2); + + const uint32_t z12 = (4*z2_b) + z1_b; + + H.mul_by(*M[z12], ws); + } + + return H.value(); + } + +} + diff --git a/comm/third_party/botan/src/lib/math/numbertheory/monty_exp.h b/comm/third_party/botan/src/lib/math/numbertheory/monty_exp.h new file mode 100644 index 0000000000..632d7f7d6e --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/monty_exp.h @@ -0,0 +1,54 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MONTY_EXP_H_ +#define BOTAN_MONTY_EXP_H_ + +#include + +namespace Botan { + +class BigInt; +class Modular_Reducer; + +class Montgomery_Params; + +class Montgomery_Exponentation_State; + +/* +* Precompute for calculating values g^x mod p +*/ +std::shared_ptr +monty_precompute(std::shared_ptr params_p, + const BigInt& g, + size_t window_bits, + bool const_time = true); + +/* +* Return g^k mod p +*/ +BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k, size_t max_k_bits); + +/* +* Return g^k mod p taking variable time depending on k +* @warning only use this if k is public +*/ +BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k); + +/** +* Return (x^z1 * y^z2) % p +*/ +BigInt monty_multi_exp(std::shared_ptr params_p, + const BigInt& x, + const BigInt& z1, + const BigInt& y, + const BigInt& z2); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/mp_numth.cpp b/comm/third_party/botan/src/lib/math/numbertheory/mp_numth.cpp new file mode 100644 index 0000000000..eef6419965 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/mp_numth.cpp @@ -0,0 +1,84 @@ +/* +* Fused and Important MP Algorithms +* (C) 1999-2007 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Square a BigInt +*/ +BigInt square(const BigInt& x) + { + BigInt z = x; + secure_vector ws; + z.square(ws); + return z; + } + +/* +* Multiply-Add Operation +*/ +BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative()) + throw Invalid_Argument("mul_add: Third argument must be > 0"); + + BigInt::Sign sign = BigInt::Positive; + if(a.sign() != b.sign()) + sign = BigInt::Negative; + + const size_t a_sw = a.sig_words(); + const size_t b_sw = b.sig_words(); + const size_t c_sw = c.sig_words(); + + BigInt r(sign, std::max(a_sw + b_sw, c_sw) + 1); + secure_vector workspace(r.size()); + + bigint_mul(r.mutable_data(), r.size(), + a.data(), a.size(), a_sw, + b.data(), b.size(), b_sw, + workspace.data(), workspace.size()); + + const size_t r_size = std::max(r.sig_words(), c_sw); + bigint_add2(r.mutable_data(), r_size, c.data(), c_sw); + return r; + } + +/* +* Subtract-Multiply Operation +*/ +BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(a.is_negative() || b.is_negative()) + throw Invalid_Argument("sub_mul: First two arguments must be >= 0"); + + BigInt r = a; + r -= b; + r *= c; + return r; + } + +/* +* Multiply-Subtract Operation +*/ +BigInt mul_sub(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative() || c.is_zero()) + throw Invalid_Argument("mul_sub: Third argument must be > 0"); + + BigInt r = a; + r *= b; + r -= c; + return r; + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/nistp_redc.cpp b/comm/third_party/botan/src/lib/math/numbertheory/nistp_redc.cpp new file mode 100644 index 0000000000..7f5ff18b95 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/nistp_redc.cpp @@ -0,0 +1,583 @@ +/* +* NIST prime reductions +* (C) 2014,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +const BigInt& prime_p521() + { + static const BigInt p521("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + return p521; + } + +void redc_p521(BigInt& x, secure_vector& ws) + { + const size_t p_full_words = 521 / BOTAN_MP_WORD_BITS; + const size_t p_top_bits = 521 % BOTAN_MP_WORD_BITS; + const size_t p_words = p_full_words + 1; + +#if (BOTAN_MP_WORD_BITS == 64) + static const word p521_words[p_words] = { + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0x1FF }; +#else + static const word p521_words[p_words] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x1FF }; +#endif + + if(ws.size() < p_words + 1) + ws.resize(p_words + 1); + + clear_mem(ws.data(), ws.size()); + bigint_shr2(ws.data(), x.data(), std::min(x.size(), 2*p_words), p_full_words, p_top_bits); + + x.mask_bits(521); + x.grow_to(p_words); + + // Word-level carry will be zero + word carry = bigint_add3_nc(x.mutable_data(), x.data(), p_words, ws.data(), p_words); + BOTAN_ASSERT_EQUAL(carry, 0, "Final carry in P-521 reduction"); + + const word top_word = x.word_at(p_full_words); + + /* + * Check if we need to reduce modulo P + * There are two possible cases: + * - The result overflowed past 521 bits, in which case bit 522 will be set + * - The result is exactly 2**521 - 1 + */ + const auto bit_522_set = CT::Mask::expand(top_word >> p_top_bits); + + word and_512 = MP_WORD_MAX; + for(size_t i = 0; i != p_full_words; ++i) + and_512 &= x.word_at(i); + const auto all_512_low_bits_set = CT::Mask::is_equal(and_512, MP_WORD_MAX); + const auto has_p521_top_word = CT::Mask::is_equal(top_word, 0x1FF); + const auto is_p521 = all_512_low_bits_set & has_p521_top_word; + + const auto needs_reduction = is_p521 | bit_522_set; + + bigint_cnd_sub(needs_reduction.value(), x.mutable_data(), p521_words, p_words); + } + +namespace { + +/** +* Treating this MPI as a sequence of 32-bit words in big-endian +* order, return word i. The array is assumed to be large enough. +*/ +inline uint32_t get_uint32(const word xw[], size_t i) + { +#if (BOTAN_MP_WORD_BITS == 32) + return xw[i]; +#else + return static_cast(xw[i/2] >> ((i % 2)*32)); +#endif + } + +inline void set_words(word x[], size_t i, uint32_t R0, uint32_t R1) + { +#if (BOTAN_MP_WORD_BITS == 32) + x[i] = R0; + x[i+1] = R1; +#else + x[i/2] = (static_cast(R1) << 32) | R0; +#endif + } + +} + +const BigInt& prime_p192() + { + static const BigInt p192("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); + return p192; + } + +void redc_p192(BigInt& x, secure_vector& ws) + { + BOTAN_UNUSED(ws); + + static const size_t p192_limbs = 192 / BOTAN_MP_WORD_BITS; + + x.grow_to(2*p192_limbs); + word* xw = x.mutable_data(); + + const uint64_t X00 = get_uint32(xw, 0); + const uint64_t X01 = get_uint32(xw, 1); + const uint64_t X02 = get_uint32(xw, 2); + const uint64_t X03 = get_uint32(xw, 3); + const uint64_t X04 = get_uint32(xw, 4); + const uint64_t X05 = get_uint32(xw, 5); + const uint64_t X06 = get_uint32(xw, 6); + const uint64_t X07 = get_uint32(xw, 7); + const uint64_t X08 = get_uint32(xw, 8); + const uint64_t X09 = get_uint32(xw, 9); + const uint64_t X10 = get_uint32(xw, 10); + const uint64_t X11 = get_uint32(xw, 11); + + const uint64_t S0 = X00 + X06 + X10; + const uint64_t S1 = X01 + X07 + X11; + const uint64_t S2 = X02 + X06 + X08 + X10; + const uint64_t S3 = X03 + X07 + X09 + X11; + const uint64_t S4 = X04 + X08 + X10; + const uint64_t S5 = X05 + X09 + X11; + + uint64_t S = 0; + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast(S); + S >>= 32; + + S += S1; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 0, R0, R1); + + S += S2; + R0 = static_cast(S); + S >>= 32; + + S += S3; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 2, R0, R1); + + S += S4; + R0 = static_cast(S); + S >>= 32; + + S += S5; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 4, R0, R1); + + // No underflow possible + + /* + This is a table of (i*P-192) % 2**192 for i in 1...3 + */ + static const word p192_mults[3][p192_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF}, + {0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFF}, + {0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFF}, +#else + {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, +#endif + }; + + CT::unpoison(S); + BOTAN_ASSERT(S <= 2, "Expected overflow"); + + BOTAN_ASSERT_NOMSG(x.size() >= p192_limbs + 1); + x.mask_bits(192); + word borrow = bigint_sub2(x.mutable_data(), p192_limbs + 1, p192_mults[S], p192_limbs); + BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); + bigint_cnd_add(borrow, x.mutable_data(), p192_limbs + 1, p192_mults[0], p192_limbs); + } + +const BigInt& prime_p224() + { + static const BigInt p224("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); + return p224; + } + +void redc_p224(BigInt& x, secure_vector& ws) + { + static const size_t p224_limbs = (BOTAN_MP_WORD_BITS == 32) ? 7 : 4; + + BOTAN_UNUSED(ws); + + x.grow_to(2*p224_limbs); + word* xw = x.mutable_data(); + + const int64_t X00 = get_uint32(xw, 0); + const int64_t X01 = get_uint32(xw, 1); + const int64_t X02 = get_uint32(xw, 2); + const int64_t X03 = get_uint32(xw, 3); + const int64_t X04 = get_uint32(xw, 4); + const int64_t X05 = get_uint32(xw, 5); + const int64_t X06 = get_uint32(xw, 6); + const int64_t X07 = get_uint32(xw, 7); + const int64_t X08 = get_uint32(xw, 8); + const int64_t X09 = get_uint32(xw, 9); + const int64_t X10 = get_uint32(xw, 10); + const int64_t X11 = get_uint32(xw, 11); + const int64_t X12 = get_uint32(xw, 12); + const int64_t X13 = get_uint32(xw, 13); + + // One full copy of P224 is added, so the result is always positive + + const int64_t S0 = 0x00000001 + X00 - X07 - X11; + const int64_t S1 = 0x00000000 + X01 - X08 - X12; + const int64_t S2 = 0x00000000 + X02 - X09 - X13; + const int64_t S3 = 0xFFFFFFFF + X03 + X07 + X11 - X10; + const int64_t S4 = 0xFFFFFFFF + X04 + X08 + X12 - X11; + const int64_t S5 = 0xFFFFFFFF + X05 + X09 + X13 - X12; + const int64_t S6 = 0xFFFFFFFF + X06 + X10 - X13; + + int64_t S = 0; + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast(S); + S >>= 32; + + S += S1; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 0, R0, R1); + + S += S2; + R0 = static_cast(S); + S >>= 32; + + S += S3; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 2, R0, R1); + + S += S4; + R0 = static_cast(S); + S >>= 32; + + S += S5; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 4, R0, R1); + + S += S6; + R0 = static_cast(S); + S >>= 32; + + set_words(xw, 6, R0, 0); + + static const word p224_mults[3][p224_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0x0000000000000001, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, + {0x0000000000000002, 0xFFFFFFFE00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, + {0x0000000000000003, 0xFFFFFFFD00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, +#else + {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0x00000003, 0x00000000, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#endif + + }; + + CT::unpoison(S); + BOTAN_ASSERT(S >= 0 && S <= 2, "Expected overflow"); + + BOTAN_ASSERT_NOMSG(x.size() >= p224_limbs + 1); + x.mask_bits(224); + word borrow = bigint_sub2(x.mutable_data(), p224_limbs + 1, p224_mults[S], p224_limbs); + BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); + bigint_cnd_add(borrow, x.mutable_data(), p224_limbs + 1, p224_mults[0], p224_limbs); + } + +const BigInt& prime_p256() + { + static const BigInt p256("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + return p256; + } + +void redc_p256(BigInt& x, secure_vector& ws) + { + static const size_t p256_limbs = (BOTAN_MP_WORD_BITS == 32) ? 8 : 4; + + BOTAN_UNUSED(ws); + + x.grow_to(2*p256_limbs); + word* xw = x.mutable_data(); + + const int64_t X00 = get_uint32(xw, 0); + const int64_t X01 = get_uint32(xw, 1); + const int64_t X02 = get_uint32(xw, 2); + const int64_t X03 = get_uint32(xw, 3); + const int64_t X04 = get_uint32(xw, 4); + const int64_t X05 = get_uint32(xw, 5); + const int64_t X06 = get_uint32(xw, 6); + const int64_t X07 = get_uint32(xw, 7); + const int64_t X08 = get_uint32(xw, 8); + const int64_t X09 = get_uint32(xw, 9); + const int64_t X10 = get_uint32(xw, 10); + const int64_t X11 = get_uint32(xw, 11); + const int64_t X12 = get_uint32(xw, 12); + const int64_t X13 = get_uint32(xw, 13); + const int64_t X14 = get_uint32(xw, 14); + const int64_t X15 = get_uint32(xw, 15); + + // Adds 6 * P-256 to prevent underflow + const int64_t S0 = 0xFFFFFFFA + X00 + X08 + X09 - (X11 + X12 + X13) - X14; + const int64_t S1 = 0xFFFFFFFF + X01 + X09 + X10 - X12 - (X13 + X14 + X15); + const int64_t S2 = 0xFFFFFFFF + X02 + X10 + X11 - (X13 + X14 + X15); + const int64_t S3 = 0x00000005 + X03 + (X11 + X12)*2 + X13 - X15 - X08 - X09; + const int64_t S4 = 0x00000000 + X04 + (X12 + X13)*2 + X14 - X09 - X10; + const int64_t S5 = 0x00000000 + X05 + (X13 + X14)*2 + X15 - X10 - X11; + const int64_t S6 = 0x00000006 + X06 + X13 + X14*3 + X15*2 - X08 - X09; + const int64_t S7 = 0xFFFFFFFA + X07 + X15*3 + X08 - X10 - (X11 + X12 + X13); + + int64_t S = 0; + + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast(S); + S >>= 32; + + S += S1; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 0, R0, R1); + + S += S2; + R0 = static_cast(S); + S >>= 32; + + S += S3; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 2, R0, R1); + + S += S4; + R0 = static_cast(S); + S >>= 32; + + S += S5; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 4, R0, R1); + + S += S6; + R0 = static_cast(S); + S >>= 32; + + S += S7; + R1 = static_cast(S); + S >>= 32; + set_words(xw, 6, R0, R1); + + S += 5; // the top digits of 6*P-256 + + /* + This is a table of (i*P-256) % 2**256 for i in 1...10 + */ + static const word p256_mults[11][p256_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF, 0x0000000000000000, 0xFFFFFFFF00000001}, + {0xFFFFFFFFFFFFFFFE, 0x00000001FFFFFFFF, 0x0000000000000000, 0xFFFFFFFE00000002}, + {0xFFFFFFFFFFFFFFFD, 0x00000002FFFFFFFF, 0x0000000000000000, 0xFFFFFFFD00000003}, + {0xFFFFFFFFFFFFFFFC, 0x00000003FFFFFFFF, 0x0000000000000000, 0xFFFFFFFC00000004}, + {0xFFFFFFFFFFFFFFFB, 0x00000004FFFFFFFF, 0x0000000000000000, 0xFFFFFFFB00000005}, + {0xFFFFFFFFFFFFFFFA, 0x00000005FFFFFFFF, 0x0000000000000000, 0xFFFFFFFA00000006}, + {0xFFFFFFFFFFFFFFF9, 0x00000006FFFFFFFF, 0x0000000000000000, 0xFFFFFFF900000007}, + {0xFFFFFFFFFFFFFFF8, 0x00000007FFFFFFFF, 0x0000000000000000, 0xFFFFFFF800000008}, + {0xFFFFFFFFFFFFFFF7, 0x00000008FFFFFFFF, 0x0000000000000000, 0xFFFFFFF700000009}, + {0xFFFFFFFFFFFFFFF6, 0x00000009FFFFFFFF, 0x0000000000000000, 0xFFFFFFF60000000A}, + {0xFFFFFFFFFFFFFFF5, 0x0000000AFFFFFFFF, 0x0000000000000000, 0xFFFFFFF50000000B}, +#else + {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}, + {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000000, 0x00000002, 0xFFFFFFFE}, + {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000002, 0x00000000, 0x00000000, 0x00000003, 0xFFFFFFFD}, + {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFC}, + {0xFFFFFFFB, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000004, 0x00000000, 0x00000000, 0x00000005, 0xFFFFFFFB}, + {0xFFFFFFFA, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000005, 0x00000000, 0x00000000, 0x00000006, 0xFFFFFFFA}, + {0xFFFFFFF9, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000006, 0x00000000, 0x00000000, 0x00000007, 0xFFFFFFF9}, + {0xFFFFFFF8, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000, 0x00000000, 0x00000008, 0xFFFFFFF8}, + {0xFFFFFFF7, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000008, 0x00000000, 0x00000000, 0x00000009, 0xFFFFFFF7}, + {0xFFFFFFF6, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000009, 0x00000000, 0x00000000, 0x0000000A, 0xFFFFFFF6}, + {0xFFFFFFF5, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000A, 0x00000000, 0x00000000, 0x0000000B, 0xFFFFFFF5}, +#endif + }; + + CT::unpoison(S); + BOTAN_ASSERT(S >= 0 && S <= 10, "Expected overflow"); + + BOTAN_ASSERT_NOMSG(x.size() >= p256_limbs + 1); + x.mask_bits(256); + word borrow = bigint_sub2(x.mutable_data(), p256_limbs + 1, p256_mults[S], p256_limbs); + BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); + bigint_cnd_add(borrow, x.mutable_data(), p256_limbs + 1, p256_mults[0], p256_limbs); + } + +const BigInt& prime_p384() + { + static const BigInt p384("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); + return p384; + } + +void redc_p384(BigInt& x, secure_vector& ws) + { + BOTAN_UNUSED(ws); + + static const size_t p384_limbs = (BOTAN_MP_WORD_BITS == 32) ? 12 : 6; + + x.grow_to(2*p384_limbs); + word* xw = x.mutable_data(); + + const int64_t X00 = get_uint32(xw, 0); + const int64_t X01 = get_uint32(xw, 1); + const int64_t X02 = get_uint32(xw, 2); + const int64_t X03 = get_uint32(xw, 3); + const int64_t X04 = get_uint32(xw, 4); + const int64_t X05 = get_uint32(xw, 5); + const int64_t X06 = get_uint32(xw, 6); + const int64_t X07 = get_uint32(xw, 7); + const int64_t X08 = get_uint32(xw, 8); + const int64_t X09 = get_uint32(xw, 9); + const int64_t X10 = get_uint32(xw, 10); + const int64_t X11 = get_uint32(xw, 11); + const int64_t X12 = get_uint32(xw, 12); + const int64_t X13 = get_uint32(xw, 13); + const int64_t X14 = get_uint32(xw, 14); + const int64_t X15 = get_uint32(xw, 15); + const int64_t X16 = get_uint32(xw, 16); + const int64_t X17 = get_uint32(xw, 17); + const int64_t X18 = get_uint32(xw, 18); + const int64_t X19 = get_uint32(xw, 19); + const int64_t X20 = get_uint32(xw, 20); + const int64_t X21 = get_uint32(xw, 21); + const int64_t X22 = get_uint32(xw, 22); + const int64_t X23 = get_uint32(xw, 23); + + // One copy of P-384 is added to prevent underflow + const int64_t S0 = 0xFFFFFFFF + X00 + X12 + X20 + X21 - X23; + const int64_t S1 = 0x00000000 + X01 + X13 + X22 + X23 - X12 - X20; + const int64_t S2 = 0x00000000 + X02 + X14 + X23 - X13 - X21; + const int64_t S3 = 0xFFFFFFFF + X03 + X12 + X15 + X20 + X21 - X14 - X22 - X23; + const int64_t S4 = 0xFFFFFFFE + X04 + X12 + X13 + X16 + X20 + X21*2 + X22 - X15 - X23*2; + const int64_t S5 = 0xFFFFFFFF + X05 + X13 + X14 + X17 + X21 + X22*2 + X23 - X16; + const int64_t S6 = 0xFFFFFFFF + X06 + X14 + X15 + X18 + X22 + X23*2 - X17; + const int64_t S7 = 0xFFFFFFFF + X07 + X15 + X16 + X19 + X23 - X18; + const int64_t S8 = 0xFFFFFFFF + X08 + X16 + X17 + X20 - X19; + const int64_t S9 = 0xFFFFFFFF + X09 + X17 + X18 + X21 - X20; + const int64_t SA = 0xFFFFFFFF + X10 + X18 + X19 + X22 - X21; + const int64_t SB = 0xFFFFFFFF + X11 + X19 + X20 + X23 - X22; + + int64_t S = 0; + + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast(S); + S >>= 32; + + S += S1; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 0, R0, R1); + + S += S2; + R0 = static_cast(S); + S >>= 32; + + S += S3; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 2, R0, R1); + + S += S4; + R0 = static_cast(S); + S >>= 32; + + S += S5; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 4, R0, R1); + + S += S6; + R0 = static_cast(S); + S >>= 32; + + S += S7; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 6, R0, R1); + + S += S8; + R0 = static_cast(S); + S >>= 32; + + S += S9; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 8, R0, R1); + + S += SA; + R0 = static_cast(S); + S >>= 32; + + S += SB; + R1 = static_cast(S); + S >>= 32; + + set_words(xw, 10, R0, R1); + + /* + This is a table of (i*P-384) % 2**384 for i in 1...4 + */ + static const word p384_mults[5][p384_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000001FFFFFFFE, 0xFFFFFFFE00000000, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000002FFFFFFFD, 0xFFFFFFFD00000000, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000003FFFFFFFC, 0xFFFFFFFC00000000, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000004FFFFFFFB, 0xFFFFFFFB00000000, 0xFFFFFFFFFFFFFFFA, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + +#else + {0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFE, 0x00000001, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFD, 0x00000002, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFC, 0x00000003, 0x00000000, 0xFFFFFFFC, 0xFFFFFFFB, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFB, 0x00000004, 0x00000000, 0xFFFFFFFB, 0xFFFFFFFA, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, +#endif + }; + + CT::unpoison(S); + BOTAN_ASSERT(S >= 0 && S <= 4, "Expected overflow"); + + BOTAN_ASSERT_NOMSG(x.size() >= p384_limbs + 1); + x.mask_bits(384); + word borrow = bigint_sub2(x.mutable_data(), p384_limbs + 1, p384_mults[S], p384_limbs); + BOTAN_DEBUG_ASSERT(borrow == 0 || borrow == 1); + bigint_cnd_add(borrow, x.mutable_data(), p384_limbs + 1, p384_mults[0], p384_limbs); + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/numthry.cpp b/comm/third_party/botan/src/lib/math/numbertheory/numthry.cpp new file mode 100644 index 0000000000..51afa94c64 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/numthry.cpp @@ -0,0 +1,268 @@ +/* +* Number Theory Functions +* (C) 1999-2011,2016,2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void sub_abs(BigInt& z, const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(); + const size_t y_sw = y.sig_words(); + z.resize(std::max(x_sw, y_sw)); + + bigint_sub_abs(z.mutable_data(), + x.data(), x_sw, + y.data(), y_sw); + } + +} + +/* +* Return the number of 0 bits at the end of n +*/ +size_t low_zero_bits(const BigInt& n) + { + size_t low_zero = 0; + + auto seen_nonempty_word = CT::Mask::cleared(); + + for(size_t i = 0; i != n.size(); ++i) + { + const word x = n.word_at(i); + + // ctz(0) will return sizeof(word) + const size_t tz_x = ctz(x); + + // if x > 0 we want to count tz_x in total but not any + // further words, so set the mask after the addition + low_zero += seen_nonempty_word.if_not_set_return(tz_x); + + seen_nonempty_word |= CT::Mask::expand(x); + } + + // if we saw no words with x > 0 then n == 0 and the value we have + // computed is meaningless. Instead return 0 in that case. + return seen_nonempty_word.if_set_return(low_zero); + } + +namespace { + +size_t safegcd_loop_bound(size_t f_bits, size_t g_bits) + { + const size_t d = std::max(f_bits, g_bits); + + if(d < 46) + return (49*d + 80) / 17; + else + return (49*d + 57) / 17; + } + +} + +/* +* Calculate the GCD +*/ +BigInt gcd(const BigInt& a, const BigInt& b) + { + if(a.is_zero()) + return abs(b); + if(b.is_zero()) + return abs(a); + if(a == 1 || b == 1) + return 1; + + // See https://gcd.cr.yp.to/safegcd-20190413.pdf fig 1.2 + + BigInt f = a; + BigInt g = b; + f.const_time_poison(); + g.const_time_poison(); + + f.set_sign(BigInt::Positive); + g.set_sign(BigInt::Positive); + + const size_t common2s = std::min(low_zero_bits(f), low_zero_bits(g)); + CT::unpoison(common2s); + + f >>= common2s; + g >>= common2s; + + f.ct_cond_swap(f.is_even(), g); + + int32_t delta = 1; + + const size_t loop_cnt = safegcd_loop_bound(f.bits(), g.bits()); + + BigInt newg, t; + for(size_t i = 0; i != loop_cnt; ++i) + { + sub_abs(newg, f, g); + + const bool need_swap = (g.is_odd() && delta > 0); + + // if(need_swap) { delta *= -1 } else { delta *= 1 } + delta *= CT::Mask::expand(need_swap).if_not_set_return(2) - 1; + f.ct_cond_swap(need_swap, g); + g.ct_cond_swap(need_swap, newg); + + delta += 1; + + g.ct_cond_add(g.is_odd(), f); + g >>= 1; + } + + f <<= common2s; + + f.const_time_unpoison(); + g.const_time_unpoison(); + + BOTAN_ASSERT_NOMSG(g.is_zero()); + + return f; + } + +/* +* Calculate the LCM +*/ +BigInt lcm(const BigInt& a, const BigInt& b) + { + return ct_divide(a * b, gcd(a, b)); + } + +/* +* Modular Exponentiation +*/ +BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) + { + if(mod.is_negative() || mod == 1) + { + return 0; + } + + if(base.is_zero() || mod.is_zero()) + { + if(exp.is_zero()) + return 1; + return 0; + } + + Modular_Reducer reduce_mod(mod); + + const size_t exp_bits = exp.bits(); + + if(mod.is_odd()) + { + const size_t powm_window = 4; + + auto monty_mod = std::make_shared(mod, reduce_mod); + auto powm_base_mod = monty_precompute(monty_mod, reduce_mod.reduce(base), powm_window); + return monty_execute(*powm_base_mod, exp, exp_bits); + } + + /* + Support for even modulus is just a convenience and not considered + cryptographically important, so this implementation is slow ... + */ + BigInt accum = 1; + BigInt g = reduce_mod.reduce(base); + BigInt t; + + for(size_t i = 0; i != exp_bits; ++i) + { + t = reduce_mod.multiply(g, accum); + g = reduce_mod.square(g); + accum.ct_cond_assign(exp.get_bit(i), t); + } + return accum; + } + + +BigInt is_perfect_square(const BigInt& C) + { + if(C < 1) + throw Invalid_Argument("is_perfect_square requires C >= 1"); + if(C == 1) + return 1; + + const size_t n = C.bits(); + const size_t m = (n + 1) / 2; + const BigInt B = C + BigInt::power_of_2(m); + + BigInt X = BigInt::power_of_2(m) - 1; + BigInt X2 = (X*X); + + for(;;) + { + X = (X2 + C) / (2*X); + X2 = (X*X); + + if(X2 < B) + break; + } + + if(X2 == C) + return X; + else + return 0; + } + +/* +* Test for primality using Miller-Rabin +*/ +bool is_prime(const BigInt& n, + RandomNumberGenerator& rng, + size_t prob, + bool is_random) + { + if(n == 2) + return true; + if(n <= 1 || n.is_even()) + return false; + + const size_t n_bits = n.bits(); + + // Fast path testing for small numbers (<= 65521) + if(n_bits <= 16) + { + const uint16_t num = static_cast(n.word_at(0)); + + return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num); + } + + Modular_Reducer mod_n(n); + + if(rng.is_seeded()) + { + const size_t t = miller_rabin_test_iterations(n_bits, prob, is_random); + + if(is_miller_rabin_probable_prime(n, mod_n, rng, t) == false) + return false; + + if(is_random) + return true; + else + return is_lucas_probable_prime(n, mod_n); + } + else + { + return is_bailie_psw_probable_prime(n, mod_n); + } + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/numthry.h b/comm/third_party/botan/src/lib/math/numbertheory/numthry.h new file mode 100644 index 0000000000..be9cd985ea --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/numthry.h @@ -0,0 +1,296 @@ +/* +* Number Theory Functions +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NUMBER_THEORY_H_ +#define BOTAN_NUMBER_THEORY_H_ + +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Fused multiply-add +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)+c +*/ +BigInt BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Just use (a*b)+c") + mul_add(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Fused subtract-multiply +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a-b)*c +*/ +BigInt BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Just use (a-b)*c") + sub_mul(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Fused multiply-subtract +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)-c +*/ +BigInt BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Just use (a*b)-c") + mul_sub(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Return the absolute value +* @param n an integer +* @return absolute value of n +*/ +inline BigInt abs(const BigInt& n) { return n.abs(); } + +/** +* Compute the greatest common divisor +* @param x a positive integer +* @param y a positive integer +* @return gcd(x,y) +*/ +BigInt BOTAN_PUBLIC_API(2,0) gcd(const BigInt& x, const BigInt& y); + +/** +* Least common multiple +* @param x a positive integer +* @param y a positive integer +* @return z, smallest integer such that z % x == 0 and z % y == 0 +*/ +BigInt BOTAN_PUBLIC_API(2,0) lcm(const BigInt& x, const BigInt& y); + +/** +* @param x an integer +* @return (x*x) +*/ +BigInt BOTAN_PUBLIC_API(2,0) square(const BigInt& x); + +/** +* Modular inversion. This algorithm is const time with respect to x, +* as long as x is less than modulus. It also avoids leaking +* information about the modulus, except that it does leak which of 3 +* categories the modulus is in: an odd integer, a power of 2, or some +* other even number, and if the modulus is even, leaks the power of 2 +* which divides the modulus. +* +* @param x a positive integer +* @param modulus a positive integer +* @return y st (x*y) % modulus == 1 or 0 if no such value +*/ +BigInt BOTAN_PUBLIC_API(2,0) inverse_mod(const BigInt& x, + const BigInt& modulus); + +/** +* Deprecated modular inversion function. Use inverse_mod instead. +* @param x a positive integer +* @param modulus a positive integer +* @return y st (x*y) % modulus == 1 or 0 if no such value +*/ +BigInt BOTAN_DEPRECATED_API("Use inverse_mod") inverse_euclid(const BigInt& x, const BigInt& modulus); + +/** +* Deprecated modular inversion function. Use inverse_mod instead. +*/ +BigInt BOTAN_DEPRECATED_API("Use inverse_mod") ct_inverse_mod_odd_modulus(const BigInt& x, const BigInt& modulus); + +/** +* Return a^-1 * 2^k mod b +* Returns k, between n and 2n +* Not const time +*/ +size_t BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use inverse_mod") + almost_montgomery_inverse(BigInt& result, + const BigInt& a, + const BigInt& b); + +/** +* Call almost_montgomery_inverse and correct the result to a^-1 mod b +*/ +BigInt BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use inverse_mod") + normalized_montgomery_inverse(const BigInt& a, const BigInt& b); + + +/** +* Compute the Jacobi symbol. If n is prime, this is equivalent +* to the Legendre symbol. +* @see http://mathworld.wolfram.com/JacobiSymbol.html +* +* @param a is a non-negative integer +* @param n is an odd integer > 1 +* @return (n / m) +*/ +int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a, const BigInt& n); + +/** +* Modular exponentation +* @param b an integer base +* @param x a positive exponent +* @param m a positive modulus +* @return (b^x) % m +*/ +BigInt BOTAN_PUBLIC_API(2,0) power_mod(const BigInt& b, + const BigInt& x, + const BigInt& m); + +/** +* Compute the square root of x modulo a prime using the +* Tonelli-Shanks algorithm +* +* @param x the input +* @param p the prime +* @return y such that (y*y)%p == x, or -1 if no such integer +*/ +BigInt BOTAN_PUBLIC_API(2,0) ressol(const BigInt& x, const BigInt& p); + +/* +* Compute -input^-1 mod 2^MP_WORD_BITS. Throws an exception if input +* is even. If input is odd, then input and 2^n are relatively prime +* and an inverse exists. +*/ +word BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use inverse_mod") + monty_inverse(word input); + +/** +* @param x an integer +* @return count of the low zero bits in x, or, equivalently, the +* largest value of n such that 2^n divides x evenly. Returns +* zero if x is equal to zero. +*/ +size_t BOTAN_PUBLIC_API(2,0) low_zero_bits(const BigInt& x); + +/** +* Check for primality +* @param n a positive integer to test for primality +* @param rng a random number generator +* @param prob chance of false positive is bounded by 1/2**prob +* @param is_random true if n was randomly chosen by us +* @return true if all primality tests passed, otherwise false +*/ +bool BOTAN_PUBLIC_API(2,0) is_prime(const BigInt& n, + RandomNumberGenerator& rng, + size_t prob = 64, + bool is_random = false); + +/** +* Test if the positive integer x is a perfect square ie if there +* exists some positive integer y st y*y == x +* See FIPS 186-4 sec C.4 +* @return 0 if the integer is not a perfect square, otherwise +* returns the positive y st y*y == x +*/ +BigInt BOTAN_PUBLIC_API(2,8) is_perfect_square(const BigInt& x); + +inline bool BOTAN_DEPRECATED("Use is_prime") + quick_check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return is_prime(n, rng, 32); } + +inline bool BOTAN_DEPRECATED("Use is_prime") + check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return is_prime(n, rng, 56); } + +inline bool BOTAN_DEPRECATED("Use is_prime") + verify_prime(const BigInt& n, RandomNumberGenerator& rng) + { return is_prime(n, rng, 80); } + +/** +* Randomly generate a prime suitable for discrete logarithm parameters +* @param rng a random number generator +* @param bits how large the resulting prime should be in bits +* @param coprime a positive integer that (prime - 1) should be coprime to +* @param equiv a non-negative number that the result should be + equivalent to modulo equiv_mod +* @param equiv_mod the modulus equiv should be checked against +* @param prob use test so false positive is bounded by 1/2**prob +* @return random prime with the specified criteria +*/ +BigInt BOTAN_PUBLIC_API(2,0) random_prime(RandomNumberGenerator& rng, + size_t bits, + const BigInt& coprime = 0, + size_t equiv = 1, + size_t equiv_mod = 2, + size_t prob = 128); + +/** +* Generate a prime suitable for RSA p/q +* @param keygen_rng a random number generator +* @param prime_test_rng a random number generator +* @param bits how large the resulting prime should be in bits (must be >= 512) +* @param coprime a positive integer that (prime - 1) should be coprime to +* @param prob use test so false positive is bounded by 1/2**prob +* @return random prime with the specified criteria +*/ +BigInt BOTAN_PUBLIC_API(2,7) generate_rsa_prime(RandomNumberGenerator& keygen_rng, + RandomNumberGenerator& prime_test_rng, + size_t bits, + const BigInt& coprime, + size_t prob = 128); + +/** +* Return a 'safe' prime, of the form p=2*q+1 with q prime +* @param rng a random number generator +* @param bits is how long the resulting prime should be +* @return prime randomly chosen from safe primes of length bits +*/ +BigInt BOTAN_PUBLIC_API(2,0) random_safe_prime(RandomNumberGenerator& rng, + size_t bits); + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @return random seed used to generate this parameter set +*/ +std::vector BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use DL_Group") +generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits); + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @param seed the seed used to generate the parameters +* @param offset optional offset from seed to start searching at +* @return true if seed generated a valid DSA parameter set, otherwise + false. p_out and q_out are only valid if true was returned. +*/ +bool BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use DL_Group") +generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits, + const std::vector& seed, + size_t offset = 0); + +/** +* The size of the PRIMES[] array +*/ +const size_t PRIME_TABLE_SIZE = 6541; + +/** +* A const array of all odd primes less than 65535 +*/ +extern const uint16_t BOTAN_PUBLIC_API(2,0) PRIMES[]; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/pow_mod.cpp b/comm/third_party/botan/src/lib/math/numbertheory/pow_mod.cpp new file mode 100644 index 0000000000..7b38fad1d8 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/pow_mod.cpp @@ -0,0 +1,328 @@ +/* +* Modular Exponentiation Proxy +* (C) 1999-2007,2012,2018,2019 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class Modular_Exponentiator + { + public: + virtual void set_base(const BigInt&) = 0; + virtual void set_exponent(const BigInt&) = 0; + virtual BigInt execute() const = 0; + virtual Modular_Exponentiator* copy() const = 0; + + Modular_Exponentiator() = default; + Modular_Exponentiator(const Modular_Exponentiator&) = default; + Modular_Exponentiator & operator=(const Modular_Exponentiator&) = default; + virtual ~Modular_Exponentiator() = default; + }; + +namespace { + +/** +* Fixed Window Exponentiator +*/ +class Fixed_Window_Exponentiator final : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt& e) override { m_exp = e; } + void set_base(const BigInt&) override; + BigInt execute() const override; + + Modular_Exponentiator* copy() const override + { return new Fixed_Window_Exponentiator(*this); } + + Fixed_Window_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + Modular_Reducer m_reducer; + BigInt m_exp; + size_t m_window_bits; + std::vector m_g; + Power_Mod::Usage_Hints m_hints; + }; + +void Fixed_Window_Exponentiator::set_base(const BigInt& base) + { + m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints); + + m_g.resize(static_cast(1) << m_window_bits); + m_g[0] = 1; + m_g[1] = m_reducer.reduce(base); + + for(size_t i = 2; i != m_g.size(); ++i) + m_g[i] = m_reducer.multiply(m_g[i-1], m_g[1]); + } + +BigInt Fixed_Window_Exponentiator::execute() const + { + const size_t exp_nibbles = (m_exp.bits() + m_window_bits - 1) / m_window_bits; + + BigInt x = 1; + + for(size_t i = exp_nibbles; i > 0; --i) + { + for(size_t j = 0; j != m_window_bits; ++j) + x = m_reducer.square(x); + + const uint32_t nibble = m_exp.get_substring(m_window_bits*(i-1), m_window_bits); + + // not const time: + x = m_reducer.multiply(x, m_g[nibble]); + } + return x; + } + +/* +* Fixed_Window_Exponentiator Constructor +*/ +Fixed_Window_Exponentiator::Fixed_Window_Exponentiator(const BigInt& n, + Power_Mod::Usage_Hints hints) + : m_reducer{Modular_Reducer(n)}, m_exp{}, m_window_bits{}, m_g{}, m_hints{hints} + {} + +class Montgomery_Exponentiator final : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt& e) override { m_e = e; } + void set_base(const BigInt&) override; + BigInt execute() const override; + + Modular_Exponentiator* copy() const override + { return new Montgomery_Exponentiator(*this); } + + Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + BigInt m_p; + Modular_Reducer m_mod_p; + std::shared_ptr m_monty_params; + std::shared_ptr m_monty; + + BigInt m_e; + Power_Mod::Usage_Hints m_hints; + }; + +void Montgomery_Exponentiator::set_base(const BigInt& base) + { + size_t window_bits = Power_Mod::window_bits(m_e.bits(), base.bits(), m_hints); + m_monty = monty_precompute(m_monty_params, m_mod_p.reduce(base), window_bits); + } + +BigInt Montgomery_Exponentiator::execute() const + { + /* + This leaks size of e via loop iterations, not possible to fix without + breaking this API. Round up to avoid leaking fine details. + */ + return monty_execute(*m_monty, m_e, round_up(m_e.bits(), 8)); + } + +Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, + Power_Mod::Usage_Hints hints) : + m_p(mod), + m_mod_p(mod), + m_monty_params(std::make_shared(m_p, m_mod_p)), + m_hints(hints) + { + } + +} + +/* +* Power_Mod Constructor +*/ +Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints, bool disable_monty) + { + set_modulus(n, hints, disable_monty); + } + +Power_Mod::~Power_Mod() { /* for ~unique_ptr */ } + +/* +* Power_Mod Copy Constructor +*/ +Power_Mod::Power_Mod(const Power_Mod& other) + { + if(other.m_core.get()) + m_core.reset(other.m_core->copy()); + } + +/* +* Power_Mod Assignment Operator +*/ +Power_Mod& Power_Mod::operator=(const Power_Mod& other) + { + if(this != &other) + { + if(other.m_core) + m_core.reset(other.m_core->copy()); + else + m_core.reset(); + } + return (*this); + } + +/* +* Set the modulus +*/ +void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints, bool disable_monty) const + { + // Allow set_modulus(0) to mean "drop old state" + + m_core.reset(); + + if(n != 0) + { + if(n.is_odd() && disable_monty == false) + m_core.reset(new Montgomery_Exponentiator(n, hints)); + else + m_core.reset(new Fixed_Window_Exponentiator(n, hints)); + } + } + +/* +* Set the base +*/ +void Power_Mod::set_base(const BigInt& b) const + { + if(b.is_negative()) + throw Invalid_Argument("Power_Mod::set_base: arg must be non-negative"); + + if(!m_core) + throw Internal_Error("Power_Mod::set_base: m_core was NULL"); + m_core->set_base(b); + } + +/* +* Set the exponent +*/ +void Power_Mod::set_exponent(const BigInt& e) const + { + if(e.is_negative()) + throw Invalid_Argument("Power_Mod::set_exponent: arg must be > 0"); + + if(!m_core) + throw Internal_Error("Power_Mod::set_exponent: m_core was NULL"); + m_core->set_exponent(e); + } + +/* +* Compute the result +*/ +BigInt Power_Mod::execute() const + { + if(!m_core) + throw Internal_Error("Power_Mod::execute: m_core was NULL"); + return m_core->execute(); + } + +/* +* Try to choose a good window size +*/ +size_t Power_Mod::window_bits(size_t exp_bits, size_t, + Power_Mod::Usage_Hints hints) + { + static const size_t wsize[][2] = { + { 1434, 7 }, + { 539, 6 }, + { 197, 4 }, + { 70, 3 }, + { 17, 2 }, + { 0, 0 } + }; + + size_t window_bits = 1; + + if(exp_bits) + { + for(size_t j = 0; wsize[j][0]; ++j) + { + if(exp_bits >= wsize[j][0]) + { + window_bits += wsize[j][1]; + break; + } + } + } + + if(hints & Power_Mod::BASE_IS_FIXED) + window_bits += 2; + if(hints & Power_Mod::EXP_IS_LARGE) + ++window_bits; + + return window_bits; + } + +namespace { + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_base_hints(const BigInt& b, const BigInt& n) + { + if(b == 2) + return Power_Mod::Usage_Hints(Power_Mod::BASE_IS_2 | + Power_Mod::BASE_IS_SMALL); + + const size_t b_bits = b.bits(); + const size_t n_bits = n.bits(); + + if(b_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(b_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + + return Power_Mod::NO_HINTS; + } + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_exp_hints(const BigInt& e, const BigInt& n) + { + const size_t e_bits = e.bits(); + const size_t n_bits = n.bits(); + + if(e_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(e_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + return Power_Mod::NO_HINTS; + } + +} + +/* +* Fixed_Exponent_Power_Mod Constructor +*/ +Fixed_Exponent_Power_Mod::Fixed_Exponent_Power_Mod(const BigInt& e, + const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | EXP_IS_FIXED | choose_exp_hints(e, n))) + { + set_exponent(e); + } + +/* +* Fixed_Base_Power_Mod Constructor +*/ +Fixed_Base_Power_Mod::Fixed_Base_Power_Mod(const BigInt& b, const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | BASE_IS_FIXED | choose_base_hints(b, n))) + { + set_base(b); + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/pow_mod.h b/comm/third_party/botan/src/lib/math/numbertheory/pow_mod.h new file mode 100644 index 0000000000..b465013e55 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/pow_mod.h @@ -0,0 +1,122 @@ +/* +* Modular Exponentiator +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POWER_MOD_H_ +#define BOTAN_POWER_MOD_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(pow_mod.h) + +namespace Botan { + +class Modular_Exponentiator; + +/** +* Modular Exponentiator Proxy +*/ +class BOTAN_PUBLIC_API(2,0) Power_Mod + { + public: + + enum Usage_Hints { + NO_HINTS = 0x0000, + + BASE_IS_FIXED = 0x0001, + BASE_IS_SMALL = 0x0002, + BASE_IS_LARGE = 0x0004, + BASE_IS_2 = 0x0008, + + EXP_IS_FIXED = 0x0100, + EXP_IS_SMALL = 0x0200, + EXP_IS_LARGE = 0x0400 + }; + + /* + * Try to choose a good window size + */ + static size_t window_bits(size_t exp_bits, size_t base_bits, + Power_Mod::Usage_Hints hints); + + /** + * @param modulus the modulus + * @param hints Passed to set_modulus if modulus > 0 + * @param disable_montgomery_arith Disables use of Montgomery + * representation. Likely only useful for testing. + */ + void set_modulus(const BigInt& modulus, + Usage_Hints hints = NO_HINTS, + bool disable_montgomery_arith = false) const; + + /** + * Set the base + */ + void set_base(const BigInt& base) const; + + /** + * Set the exponent + */ + void set_exponent(const BigInt& exponent) const; + + /** + * All three of the above functions must have already been called. + * @return result of g^x%p + */ + BigInt execute() const; + + Power_Mod& operator=(const Power_Mod&); + + /** + * @param modulus Optionally call set_modulus + * @param hints Passed to set_modulus if modulus > 0 + * @param disable_montgomery_arith Disables use of Montgomery + * representation. Likely only useful for testing. + */ + Power_Mod(const BigInt& modulus = 0, + Usage_Hints hints = NO_HINTS, + bool disable_montgomery_arith = false); + Power_Mod(const Power_Mod&); + virtual ~Power_Mod(); + private: + mutable std::unique_ptr m_core; + }; + +/** +* Fixed Exponent Modular Exponentiator Proxy +*/ +class BOTAN_PUBLIC_API(2,0) Fixed_Exponent_Power_Mod final : public Power_Mod + { + public: + BigInt operator()(const BigInt& b) const + { set_base(b); return execute(); } + + Fixed_Exponent_Power_Mod() = default; + + Fixed_Exponent_Power_Mod(const BigInt& exponent, + const BigInt& modulus, + Usage_Hints hints = NO_HINTS); + }; + +/** +* Fixed Base Modular Exponentiator Proxy +*/ +class BOTAN_PUBLIC_API(2,0) Fixed_Base_Power_Mod final : public Power_Mod + { + public: + BigInt operator()(const BigInt& e) const + { set_exponent(e); return execute(); } + + Fixed_Base_Power_Mod() = default; + + Fixed_Base_Power_Mod(const BigInt& base, + const BigInt& modulus, + Usage_Hints hints = NO_HINTS); + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/primality.cpp b/comm/third_party/botan/src/lib/math/numbertheory/primality.cpp new file mode 100644 index 0000000000..eb2be42b13 --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/primality.cpp @@ -0,0 +1,203 @@ +/* +* (C) 2016,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +bool is_lucas_probable_prime(const BigInt& C, const Modular_Reducer& mod_C) + { + if(C <= 1) + return false; + else if(C == 2) + return true; + else if(C.is_even()) + return false; + else if(C == 3 || C == 5 || C == 7 || C == 11 || C == 13) + return true; + + BigInt D = 5; + + for(;;) + { + int32_t j = jacobi(D, C); + if(j == 0) + return false; + + if(j == -1) + break; + + // Check 5, -7, 9, -11, 13, -15, 17, ... + if(D.is_negative()) + { + D.flip_sign(); + D += 2; + } + else + { + D += 2; + D.flip_sign(); + } + + if(D == 17 && is_perfect_square(C).is_nonzero()) + return false; + } + + const BigInt K = C + 1; + const size_t K_bits = K.bits() - 1; + + BigInt U = 1; + BigInt V = 1; + + BigInt Ut, Vt, U2, V2; + + for(size_t i = 0; i != K_bits; ++i) + { + const bool k_bit = K.get_bit(K_bits - 1 - i); + + Ut = mod_C.multiply(U, V); + + Vt = mod_C.reduce(mod_C.square(V) + mod_C.multiply(D, mod_C.square(U))); + Vt.ct_cond_add(Vt.is_odd(), C); + Vt >>= 1; + Vt = mod_C.reduce(Vt); + + U = Ut; + V = Vt; + + U2 = mod_C.reduce(Ut + Vt); + U2.ct_cond_add(U2.is_odd(), C); + U2 >>= 1; + + V2 = mod_C.reduce(Vt + Ut*D); + V2.ct_cond_add(V2.is_odd(), C); + V2 >>= 1; + + U.ct_cond_assign(k_bit, U2); + V.ct_cond_assign(k_bit, V2); + } + + return (U == 0); + } + +bool is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n) + { + auto monty_n = std::make_shared(n, mod_n); + return passes_miller_rabin_test(n, mod_n, monty_n, 2) && is_lucas_probable_prime(n, mod_n); + } + +bool is_bailie_psw_probable_prime(const BigInt& n) + { + Modular_Reducer mod_n(n); + return is_bailie_psw_probable_prime(n, mod_n); + } + +bool passes_miller_rabin_test(const BigInt& n, + const Modular_Reducer& mod_n, + const std::shared_ptr& monty_n, + const BigInt& a) + { + BOTAN_ASSERT_NOMSG(n > 1); + + const BigInt n_minus_1 = n - 1; + const size_t s = low_zero_bits(n_minus_1); + const BigInt nm1_s = n_minus_1 >> s; + const size_t n_bits = n.bits(); + + const size_t powm_window = 4; + + auto powm_a_n = monty_precompute(monty_n, a, powm_window); + + BigInt y = monty_execute(*powm_a_n, nm1_s, n_bits); + + if(y == 1 || y == n_minus_1) + return true; + + for(size_t i = 1; i != s; ++i) + { + y = mod_n.square(y); + + if(y == 1) // found a non-trivial square root + return false; + + /* + -1 is the trivial square root of unity, so ``a`` is not a + witness for this number - give up + */ + if(y == n_minus_1) + return true; + } + + return false; + } + +bool is_miller_rabin_probable_prime(const BigInt& n, + const Modular_Reducer& mod_n, + RandomNumberGenerator& rng, + size_t test_iterations) + { + BOTAN_ASSERT_NOMSG(n > 1); + + auto monty_n = std::make_shared(n, mod_n); + + for(size_t i = 0; i != test_iterations; ++i) + { + const BigInt a = BigInt::random_integer(rng, 2, n); + + if(!passes_miller_rabin_test(n, mod_n, monty_n, a)) + return false; + } + + // Failed to find a counterexample + return true; + } + + +size_t miller_rabin_test_iterations(size_t n_bits, size_t prob, bool random) + { + const size_t base = (prob + 2) / 2; // worst case 4^-t error rate + + /* + * If the candidate prime was maliciously constructed, we can't rely + * on arguments based on p being random. + */ + if(random == false) + return base; + + /* + * For randomly chosen numbers we can use the estimates from + * http://www.math.dartmouth.edu/~carlp/PDF/paper88.pdf + * + * These values are derived from the inequality for p(k,t) given on + * the second page. + */ + if(prob <= 128) + { + if(n_bits >= 1536) + return 4; // < 2^-133 + if(n_bits >= 1024) + return 6; // < 2^-133 + if(n_bits >= 512) + return 12; // < 2^-129 + if(n_bits >= 256) + return 29; // < 2^-128 + } + + /* + If the user desires a smaller error probability than we have + precomputed error estimates for, just fall back to using the worst + case error rate. + */ + return base; + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/primality.h b/comm/third_party/botan/src/lib/math/numbertheory/primality.h new file mode 100644 index 0000000000..db7a76a74d --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/primality.h @@ -0,0 +1,100 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PRIMALITY_TEST_H_ +#define BOTAN_PRIMALITY_TEST_H_ + +#include +#include + +namespace Botan { + +class BigInt; +class Modular_Reducer; +class Montgomery_Params; +class RandomNumberGenerator; + +/** +* Perform Lucas primality test +* @see FIPS 186-4 C.3.3 +* +* @warning it is possible to construct composite integers which pass +* this test alone. +* +* @param n the positive integer to test +* @param mod_n a pre-created Modular_Reducer for n +* @return true if n seems probably prime, false if n is composite +*/ +bool BOTAN_TEST_API is_lucas_probable_prime(const BigInt& n, const Modular_Reducer& mod_n); + +/** +* Perform Bailie-PSW primality test +* +* This is a combination of Miller-Rabin with base 2 and a Lucas test. No known +* composite integer passes both tests, though it is conjectured that infinitely +* many composite counterexamples exist. +* +* @param n the positive integer to test +* @param mod_n a pre-created Modular_Reducer for n +* @return true if n seems probably prime, false if n is composite +*/ +bool BOTAN_TEST_API is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n); + +/** +* Perform Bailie-PSW primality test +* +* This is a combination of Miller-Rabin with base 2 and a Lucas test. No known +* composite integer passes both tests, though it is conjectured that infinitely +* many composite counterexamples exist. +* +* @param n the positive integer to test +* @return true if n seems probably prime, false if n is composite +*/ +bool is_bailie_psw_probable_prime(const BigInt& n); + +/** +* Return required number of Miller-Rabin tests in order to +* reach the specified probability of error. +* +* @param n_bits the bit-length of the integer being tested +* @param prob chance of false positive is bounded by 1/2**prob +* @param random is set if (and only if) the integer was randomly generated by us +* and thus cannot have been maliciously constructed. +*/ +size_t miller_rabin_test_iterations(size_t n_bits, size_t prob, bool random); + +/** +* Perform a single Miller-Rabin test with specified base +* +* @param n the positive integer to test +* @param mod_n a pre-created Modular_Reducer for n +* @param monty_n Montgomery parameters for n +* @param a the base to check +* @return result of primality test +*/ +bool passes_miller_rabin_test(const BigInt& n, + const Modular_Reducer& mod_n, + const std::shared_ptr& monty_n, + const BigInt& a); + +/** +* Perform t iterations of a Miller-Rabin primality test with random bases +* +* @param n the positive integer to test +* @param mod_n a pre-created Modular_Reducer for n +* @param rng a random number generator +* @param t number of tests to perform +* +* @return result of primality test +*/ +bool BOTAN_TEST_API is_miller_rabin_probable_prime(const BigInt& n, + const Modular_Reducer& mod_n, + RandomNumberGenerator& rng, + size_t t); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/primes.cpp b/comm/third_party/botan/src/lib/math/numbertheory/primes.cpp new file mode 100644 index 0000000000..4a3eb46f2c --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/primes.cpp @@ -0,0 +1,609 @@ +/* +* Small Primes Table +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +const uint16_t PRIMES[PRIME_TABLE_SIZE+1] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, + 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, + 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, + 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, + 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, + 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, + 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, + 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, + 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, + 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, + 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, + 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, + 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, + 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, + 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, + 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, + 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, + 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, + 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, + 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, + 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, + 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, + 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, + 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, + 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, + 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, + 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, + 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, + 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, + 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, + 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, + 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, + 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, + 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, + 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, + 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, + 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, + 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, + 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, + 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, + 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, + 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, + 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, + 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, + 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, + 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, + 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, + 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, + 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, + 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, + 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, + 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, + 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, + 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, + 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, + 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, + 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, + 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, + 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, + 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, + 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, + 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, + 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, + 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, + 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, + 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, + 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, + 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, + 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, + 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, + 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, + 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, + 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, + 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, + 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, + 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, + 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, + 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, + 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, + 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, + 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, + 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, + 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, +10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, +10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, +10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, +10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, +10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, +10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, +10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, +10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, +10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, +10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, +11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, +11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, +11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, +11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, +11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, +11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, +11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, +11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, +11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, +12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, +12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, +12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, +12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, +12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, +12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, +12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, +12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, +12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, +12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, +13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, +13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, +13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, +13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, +13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, +13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, +13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, +13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, +13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, +13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, +14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, +14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, +14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, +14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, +14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, +14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, +14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, +14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, +14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, +15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, +15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, +15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, +15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, +15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, +15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, +15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, +15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, +15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, +15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, +16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, +16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, +16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, +16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, +16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, +16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, +16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, +16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, +16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, +17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, +17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, +17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, +17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, +17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, +17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, +17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, +17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, +17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, +18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, +18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, +18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, +18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, +18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, +18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, +18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, +18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, +18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, +19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, +19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, +19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, +19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, +19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, +19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, +19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, +19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, +19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, +20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, +20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, +20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, +20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, +20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, +20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, +20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, +20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, +20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, +21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, +21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, +21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, +21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, +21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, +21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, +21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, +21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, +21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, +22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, +22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, +22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, +22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, +22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, +22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, +22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, +22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, +22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, +23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, +23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, +23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, +23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, +23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, +23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, +23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, +23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, +23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, +23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, +24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, +24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, +24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, +24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, +24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, +24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, +24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, +24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, +25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, +25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, +25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, +25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, +25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, +25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, +25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, +25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, +25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, +26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, +26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, +26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, +26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, +26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, +26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, +26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, +26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, +26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, +26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, +27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, +27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, +27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, +27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, +27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, +27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, +27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, +27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, +28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, +28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, +28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, +28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, +28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, +28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, +28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, +28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, +28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, +29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, +29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, +29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, +29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, +29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, +29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, +29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, +29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, +30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, +30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, +30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, +30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, +30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, +30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, +30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, +30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, +30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, +31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, +31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, +31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, +31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, +31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, +31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, +31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, +31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, +32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, +32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, +32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, +32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, +32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, +32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, +32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, +32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, +32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, +32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, +33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, +33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, +33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, +33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, +33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, +33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, +33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, +33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, +33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, +34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, +34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, +34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, +34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, +34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, +34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, +34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, +34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, +34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, +35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, +35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, +35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, +35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, +35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, +35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, +35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, +35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, +36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, +36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, +36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, +36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, +36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, +36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, +36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, +36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, +36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, +37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, +37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, +37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, +37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, +37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, +37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, +37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, +37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, +37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, +38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, +38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, +38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, +38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, +38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, +38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, +38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, +38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, +39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, +39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, +39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, +39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, +39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, +39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, +39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, +39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, +40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, +40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, +40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, +40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, +40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, +40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, +40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, +40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, +41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, +41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, +41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, +41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, +41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, +41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, +41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, +41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, +41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, +41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, +42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, +42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, +42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, +42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, +42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, +42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, +42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, +42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, +42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, +43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, +43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, +43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, +43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, +43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, +43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, +43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, +43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, +44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, +44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, +44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, +44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, +44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, +44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, +44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, +44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, +45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, +45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, +45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, +45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, +45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, +45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, +45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, +45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, +46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, +46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, +46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, +46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, +46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, +46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, +46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, +46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, +47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, +47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, +47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, +47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, +47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, +47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, +47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, +47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, +47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, +48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, +48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, +48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, +48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, +48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, +48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, +48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, +48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, +49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, +49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, +49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, +49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, +49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, +49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, +49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, +49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, +49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, +50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, +50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, +50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, +50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, +50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, +50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, +50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, +50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, +51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, +51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, +51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, +51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, +51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, +51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, +51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, +51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, +51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, +52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, +52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, +52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, +52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, +52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, +52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, +52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, +52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, +53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, +53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, +53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, +53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, +53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, +53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, +53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, +53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, +54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, +54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, +54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, +54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, +54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, +54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, +54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, +54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, +54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, +55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, +55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, +55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, +55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, +55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, +55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, +55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, +55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, +56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, +56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, +56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, +56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, +56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, +56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, +56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, +56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, +56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, +57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, +57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, +57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, +57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, +57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, +57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, +57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, +57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, +58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, +58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, +58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, +58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, +58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, +58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, +58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, +58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, +59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, +59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, +59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, +59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, +59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, +59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, +59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, +59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, +59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, +60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, +60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, +60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, +60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, +60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, +60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, +60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, +60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, +61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, +61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, +61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, +61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, +61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, +61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, +61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, +61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, +62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, +62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, +62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, +62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, +62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, +62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, +62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, +62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, +63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, +63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, +63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, +63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, +63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, +63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, +63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, +63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, +64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, +64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, +64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, +64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, +64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, +64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, +64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, +64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, +65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, +65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, +65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, +65437, 65447, 65449, 65479, 65497, 65519, 65521, 0 }; + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/reducer.cpp b/comm/third_party/botan/src/lib/math/numbertheory/reducer.cpp new file mode 100644 index 0000000000..deb3874d3e --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/reducer.cpp @@ -0,0 +1,119 @@ +/* +* Modular Reducer +* (C) 1999-2011,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Modular_Reducer Constructor +*/ +Modular_Reducer::Modular_Reducer(const BigInt& mod) + { + if(mod < 0) + throw Invalid_Argument("Modular_Reducer: modulus must be positive"); + + // Left uninitialized if mod == 0 + m_mod_words = 0; + + if(mod > 0) + { + m_modulus = mod; + m_mod_words = m_modulus.sig_words(); + + // Compute mu = floor(2^{2k} / m) + m_mu.set_bit(2 * BOTAN_MP_WORD_BITS * m_mod_words); + m_mu = ct_divide(m_mu, m_modulus); + } + } + +BigInt Modular_Reducer::reduce(const BigInt& x) const + { + BigInt r; + secure_vector ws; + reduce(r, x, ws); + return r; + } + +namespace { + +/* +* Like if(cnd) x.rev_sub(...) but in const time +*/ +void cnd_rev_sub(bool cnd, BigInt& x, const word y[], size_t y_sw, secure_vector& ws) + { + if(x.sign() != BigInt::Positive) + throw Invalid_State("BigInt::sub_rev requires this is positive"); + + const size_t x_sw = x.sig_words(); + + const size_t max_words = std::max(x_sw, y_sw); + ws.resize(std::max(x_sw, y_sw)); + clear_mem(ws.data(), ws.size()); + x.grow_to(max_words); + + const int32_t relative_size = bigint_sub_abs(ws.data(), x.data(), x_sw, y, y_sw); + + x.cond_flip_sign((relative_size > 0) && cnd); + bigint_cnd_swap(cnd, x.mutable_data(), ws.data(), max_words); + } + +} + +void Modular_Reducer::reduce(BigInt& t1, const BigInt& x, secure_vector& ws) const + { + if(&t1 == &x) + throw Invalid_State("Modular_Reducer arguments cannot alias"); + if(m_mod_words == 0) + throw Invalid_State("Modular_Reducer: Never initalized"); + + const size_t x_sw = x.sig_words(); + + if(x_sw > 2*m_mod_words) + { + // too big, fall back to slow boat division + t1 = ct_modulo(x, m_modulus); + return; + } + + t1 = x; + t1.set_sign(BigInt::Positive); + t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words - 1)); + + t1.mul(m_mu, ws); + t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words + 1)); + + // TODO add masked mul to avoid computing high bits + t1.mul(m_modulus, ws); + t1.mask_bits(BOTAN_MP_WORD_BITS * (m_mod_words + 1)); + + t1.rev_sub(x.data(), std::min(x_sw, m_mod_words + 1), ws); + + /* + * If t1 < 0 then we must add b^(k+1) where b = 2^w. To avoid a + * side channel perform the addition unconditionally, with ws set + * to either b^(k+1) or else 0. + */ + const word t1_neg = t1.is_negative(); + + if(ws.size() < m_mod_words + 2) + ws.resize(m_mod_words + 2); + clear_mem(ws.data(), ws.size()); + ws[m_mod_words + 1] = t1_neg; + + t1.add(ws.data(), m_mod_words + 2, BigInt::Positive); + + // Per HAC this step requires at most 2 subtractions + t1.ct_reduce_below(m_modulus, ws, 2); + + cnd_rev_sub(t1.is_nonzero() && x.is_negative(), t1, m_modulus.data(), m_modulus.size(), ws); + } + +} diff --git a/comm/third_party/botan/src/lib/math/numbertheory/reducer.h b/comm/third_party/botan/src/lib/math/numbertheory/reducer.h new file mode 100644 index 0000000000..b1c2c87a9f --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/reducer.h @@ -0,0 +1,69 @@ +/* +* Modular Reducer +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODULAR_REDUCER_H_ +#define BOTAN_MODULAR_REDUCER_H_ + +#include + +namespace Botan { + +/** +* Modular Reducer (using Barrett's technique) +*/ +class BOTAN_PUBLIC_API(2,0) Modular_Reducer + { + public: + const BigInt& get_modulus() const { return m_modulus; } + + BigInt reduce(const BigInt& x) const; + + /** + * Multiply mod p + * @param x the first operand + * @param y the second operand + * @return (x * y) % p + */ + BigInt multiply(const BigInt& x, const BigInt& y) const + { return reduce(x * y); } + + /** + * Square mod p + * @param x the value to square + * @return (x * x) % p + */ + BigInt square(const BigInt& x) const + { return reduce(Botan::square(x)); } + + /** + * Cube mod p + * @param x the value to cube + * @return (x * x * x) % p + */ + BigInt cube(const BigInt& x) const + { return multiply(x, this->square(x)); } + + /** + * Low level reduction function. Mostly for internal use. + * Sometimes useful for performance by reducing temporaries + * Reduce x mod p and place the output in out. ** X and out must not reference each other ** + * ws is a temporary workspace. + */ + void reduce(BigInt& out, const BigInt& x, secure_vector& ws) const; + + bool initialized() const { return (m_mod_words != 0); } + + Modular_Reducer() { m_mod_words = 0; } + explicit Modular_Reducer(const BigInt& mod); + private: + BigInt m_modulus, m_mu; + size_t m_mod_words; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/math/numbertheory/ressol.cpp b/comm/third_party/botan/src/lib/math/numbertheory/ressol.cpp new file mode 100644 index 0000000000..f9e7e3eb1d --- /dev/null +++ b/comm/third_party/botan/src/lib/math/numbertheory/ressol.cpp @@ -0,0 +1,100 @@ +/* +* (C) 2007,2008 Falko Strenzke, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Tonelli-Shanks algorithm +*/ +BigInt ressol(const BigInt& a, const BigInt& p) + { + if(p <= 1 || p.is_even()) + throw Invalid_Argument("ressol: invalid prime"); + + if(a == 0) + return 0; + else if(a < 0) + throw Invalid_Argument("ressol: value to solve for must be positive"); + else if(a >= p) + throw Invalid_Argument("ressol: value to solve for must be less than p"); + + if(p == 2) + return a; + + if(jacobi(a, p) != 1) // not a quadratic residue + return -BigInt(1); + + if(p % 4 == 3) // The easy case + { + return power_mod(a, ((p+1) >> 2), p); + } + + size_t s = low_zero_bits(p - 1); + BigInt q = p >> s; + + q -= 1; + q >>= 1; + + Modular_Reducer mod_p(p); + + BigInt r = power_mod(a, q, p); + BigInt n = mod_p.multiply(a, mod_p.square(r)); + r = mod_p.multiply(r, a); + + if(n == 1) + return r; + + // find random quadratic nonresidue z + word z = 2; + for(;;) + { + if(jacobi(z, p) == -1) // found one + break; + + z += 1; // try next z + + /* + * The expected number of tests to find a non-residue modulo a + * prime is 2. If we have not found one after 256 then almost + * certainly we have been given a non-prime p. + */ + if(z >= 256) + return -BigInt(1); + } + + BigInt c = power_mod(z, (q << 1) + 1, p); + + while(n > 1) + { + q = n; + + size_t i = 0; + while(q != 1) + { + q = mod_p.square(q); + ++i; + + if(i >= s) + { + return -BigInt(1); + } + } + + c = power_mod(c, BigInt::power_of_2(s-i-1), p); + r = mod_p.multiply(r, c); + c = mod_p.square(c); + n = mod_p.multiply(n, c); + s = i; + } + + return r; + } + +} diff --git a/comm/third_party/botan/src/lib/misc/aont/info.txt b/comm/third_party/botan/src/lib/misc/aont/info.txt new file mode 100644 index 0000000000..bbd6449f7e --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/aont/info.txt @@ -0,0 +1,9 @@ + +PACKAGE_TRANSFORM -> 20131128 + + + +ctr +rng +filters + diff --git a/comm/third_party/botan/src/lib/misc/aont/package.cpp b/comm/third_party/botan/src/lib/misc/aont/package.cpp new file mode 100644 index 0000000000..7cadc62f48 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/aont/package.cpp @@ -0,0 +1,125 @@ +/* +* Rivest's Package Tranform +* +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +void aont_package(RandomNumberGenerator& rng, + BlockCipher* cipher, + const uint8_t input[], size_t input_len, + uint8_t output[]) + { + if(input_len <= 1) + throw Encoding_Error("Package transform cannot encode small inputs"); + + const size_t BLOCK_SIZE = cipher->block_size(); + + if(!cipher->valid_keylength(BLOCK_SIZE)) + throw Invalid_Argument("AONT::package: Invalid cipher"); + + // The all-zero string which is used both as the CTR IV and as K0 + const std::string all_zeros(BLOCK_SIZE*2, '0'); + + SymmetricKey package_key(rng, BLOCK_SIZE); + + Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); + + pipe.process_msg(input, input_len); + const size_t remaining = pipe.remaining(); + BOTAN_ASSERT_EQUAL(remaining, pipe.read(output, remaining), "Expected read size"); + + // Set K0 (the all zero key) + cipher->set_key(SymmetricKey(all_zeros)); + + secure_vector buf(BLOCK_SIZE); + + const size_t blocks = + (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE; + + uint8_t* final_block = output + input_len; + clear_mem(final_block, BLOCK_SIZE); + + // XOR the hash blocks into the final block + for(size_t i = 0; i != blocks; ++i) + { + const size_t left = std::min(BLOCK_SIZE, + input_len - BLOCK_SIZE * i); + + zeroise(buf); + copy_mem(buf.data(), output + (BLOCK_SIZE * i), left); + + for(size_t j = 0; j != sizeof(i); ++j) + buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); + + cipher->encrypt(buf.data()); + + xor_buf(final_block, buf.data(), BLOCK_SIZE); + } + + // XOR the random package key into the final block + xor_buf(final_block, package_key.begin(), BLOCK_SIZE); + } + +void aont_unpackage(BlockCipher* cipher, + const uint8_t input[], size_t input_len, + uint8_t output[]) + { + const size_t BLOCK_SIZE = cipher->block_size(); + + if(!cipher->valid_keylength(BLOCK_SIZE)) + throw Invalid_Argument("AONT::unpackage: Invalid cipher"); + + if(input_len < BLOCK_SIZE) + throw Invalid_Argument("AONT::unpackage: Input too short"); + + // The all-zero string which is used both as the CTR IV and as K0 + const std::string all_zeros(BLOCK_SIZE*2, '0'); + + cipher->set_key(SymmetricKey(all_zeros)); + + secure_vector package_key(BLOCK_SIZE); + secure_vector buf(BLOCK_SIZE); + + // Copy the package key (masked with the block hashes) + copy_mem(package_key.data(), + input + (input_len - BLOCK_SIZE), + BLOCK_SIZE); + + const size_t blocks = ((input_len - 1) / BLOCK_SIZE); + + // XOR the blocks into the package key bits + for(size_t i = 0; i != blocks; ++i) + { + const size_t left = std::min(BLOCK_SIZE, + input_len - BLOCK_SIZE * (i+1)); + + zeroise(buf); + copy_mem(buf.data(), input + (BLOCK_SIZE * i), left); + + for(size_t j = 0; j != sizeof(i); ++j) + buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); + + cipher->encrypt(buf.data()); + + xor_buf(package_key.data(), buf.data(), BLOCK_SIZE); + } + + Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); + + pipe.process_msg(input, input_len - BLOCK_SIZE); + + const size_t remaining = pipe.remaining(); + BOTAN_ASSERT_EQUAL(remaining, pipe.read(output, remaining), "Expected read size"); + } + +} diff --git a/comm/third_party/botan/src/lib/misc/aont/package.h b/comm/third_party/botan/src/lib/misc/aont/package.h new file mode 100644 index 0000000000..38e04e4708 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/aont/package.h @@ -0,0 +1,49 @@ +/* +* Rivest's Package Tranform +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AONT_PACKAGE_TRANSFORM_H_ +#define BOTAN_AONT_PACKAGE_TRANSFORM_H_ + +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Rivest's Package Tranform +* @param rng the random number generator to use +* @param cipher the block cipher to use (aont_package takes ownership) +* @param input the input data buffer +* @param input_len the length of the input data in bytes +* @param output the output data buffer (must be at least +* input_len + cipher->BLOCK_SIZE bytes long) +*/ +BOTAN_DEPRECATED("Possibly broken, avoid") +void BOTAN_PUBLIC_API(2,0) +aont_package(RandomNumberGenerator& rng, + BlockCipher* cipher, + const uint8_t input[], size_t input_len, + uint8_t output[]); + +/** +* Rivest's Package Tranform (Inversion) +* @param cipher the block cipher to use (aont_package takes ownership) +* @param input the input data buffer +* @param input_len the length of the input data in bytes +* @param output the output data buffer (must be at least +* input_len - cipher->BLOCK_SIZE bytes long) +*/ +BOTAN_DEPRECATED("Possibly broken, avoid") +void BOTAN_PUBLIC_API(2,0) +aont_unpackage(BlockCipher* cipher, + const uint8_t input[], size_t input_len, + uint8_t output[]); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.cpp b/comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.cpp new file mode 100644 index 0000000000..452d953088 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.cpp @@ -0,0 +1,180 @@ +/* +* Cryptobox Message Routines +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace CryptoBox { + +namespace { + +/* +First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits +for later use as flags, etc if needed +*/ +const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400; + +const size_t VERSION_CODE_LEN = 4; +const size_t CIPHER_KEY_LEN = 32; +const size_t CIPHER_IV_LEN = 16; +const size_t MAC_KEY_LEN = 32; +const size_t MAC_OUTPUT_LEN = 20; +const size_t PBKDF_SALT_LEN = 10; +const size_t PBKDF_ITERATIONS = 8 * 1024; + +const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN; +const size_t CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN; + +} + +std::string encrypt(const uint8_t input[], size_t input_len, + const std::string& passphrase, + RandomNumberGenerator& rng) + { + /* + Output format is: + version # (4 bytes) + salt (10 bytes) + mac (20 bytes) + ciphertext + */ + secure_vector out_buf(CRYPTOBOX_HEADER_LEN + input_len); + for(size_t i = 0; i != VERSION_CODE_LEN; ++i) + out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE); + rng.randomize(&out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN); + // space left for MAC here + if(input_len > 0) + copy_mem(&out_buf[CRYPTOBOX_HEADER_LEN], input, input_len); + + // Generate the keys and IV + + std::unique_ptr pbkdf(PBKDF::create_or_throw("PBKDF2(HMAC(SHA-512))")); + + OctetString master_key = pbkdf->derive_key( + CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN, + passphrase, + &out_buf[VERSION_CODE_LEN], + PBKDF_SALT_LEN, + PBKDF_ITERATIONS); + + const uint8_t* mk = master_key.begin(); + const uint8_t* cipher_key = mk; + const uint8_t* mac_key = mk + CIPHER_KEY_LEN; + const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN; + + // Now encrypt and authenticate + std::unique_ptr ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", ENCRYPTION); + ctr->set_key(cipher_key, CIPHER_KEY_LEN); + ctr->start(iv, CIPHER_IV_LEN); + ctr->finish(out_buf, CRYPTOBOX_HEADER_LEN); + + std::unique_ptr hmac = + MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); + hmac->set_key(mac_key, MAC_KEY_LEN); + if(input_len > 0) + hmac->update(&out_buf[CRYPTOBOX_HEADER_LEN], input_len); + + // Can't write directly because of MAC truncation + secure_vector mac = hmac->final(); + copy_mem(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], mac.data(), MAC_OUTPUT_LEN); + + return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE"); + } + +secure_vector +decrypt_bin(const uint8_t input[], size_t input_len, + const std::string& passphrase) + { + DataSource_Memory input_src(input, input_len); + secure_vector ciphertext = + PEM_Code::decode_check_label(input_src, + "BOTAN CRYPTOBOX MESSAGE"); + + if(ciphertext.size() < CRYPTOBOX_HEADER_LEN) + throw Decoding_Error("Invalid CryptoBox input"); + + for(size_t i = 0; i != VERSION_CODE_LEN; ++i) + if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE)) + throw Decoding_Error("Bad CryptoBox version"); + + const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN]; + const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN]; + + std::unique_ptr pbkdf(PBKDF::create_or_throw("PBKDF2(HMAC(SHA-512))")); + + OctetString master_key = pbkdf->derive_key( + PBKDF_OUTPUT_LEN, + passphrase, + pbkdf_salt, + PBKDF_SALT_LEN, + PBKDF_ITERATIONS); + + const uint8_t* mk = master_key.begin(); + const uint8_t* cipher_key = mk; + const uint8_t* mac_key = mk + CIPHER_KEY_LEN; + const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN; + + // Now authenticate and decrypt + std::unique_ptr hmac = + MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); + hmac->set_key(mac_key, MAC_KEY_LEN); + + if(ciphertext.size() > CRYPTOBOX_HEADER_LEN) + { + hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN], + ciphertext.size() - CRYPTOBOX_HEADER_LEN); + } + secure_vector computed_mac = hmac->final(); + + if(!constant_time_compare(computed_mac.data(), box_mac, MAC_OUTPUT_LEN)) + throw Decoding_Error("CryptoBox integrity failure"); + + std::unique_ptr ctr(Cipher_Mode::create_or_throw("Serpent/CTR-BE", DECRYPTION)); + ctr->set_key(cipher_key, CIPHER_KEY_LEN); + ctr->start(iv, CIPHER_IV_LEN); + ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN); + + ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN); + return ciphertext; + } + +secure_vector decrypt_bin(const std::string& input, + const std::string& passphrase) + { + return decrypt_bin(cast_char_ptr_to_uint8(input.data()), + input.size(), + passphrase); + } + +std::string decrypt(const uint8_t input[], size_t input_len, + const std::string& passphrase) + { + const secure_vector bin = decrypt_bin(input, input_len, passphrase); + + return std::string(cast_uint8_ptr_to_char(&bin[0]), + bin.size()); + } + +std::string decrypt(const std::string& input, + const std::string& passphrase) + { + return decrypt(cast_char_ptr_to_uint8(input.data()), + input.size(), passphrase); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.h b/comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.h new file mode 100644 index 0000000000..977ef37d65 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/cryptobox/cryptobox.h @@ -0,0 +1,79 @@ +/* +* Cryptobox Message Routines +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CRYPTOBOX_H_ +#define BOTAN_CRYPTOBOX_H_ + +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* This namespace holds various high-level crypto functions +*/ +namespace CryptoBox { + +/** +* Encrypt a message using a passphrase +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +* @param rng a ref to a random number generator, such as AutoSeeded_RNG +*/ +BOTAN_PUBLIC_API(2,0) std::string encrypt(const uint8_t input[], size_t input_len, + const std::string& passphrase, + RandomNumberGenerator& rng); + + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_PUBLIC_API(2,3) +secure_vector +decrypt_bin(const uint8_t input[], size_t input_len, + const std::string& passphrase); + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_PUBLIC_API(2,3) +secure_vector +decrypt_bin(const std::string& input, + const std::string& passphrase); + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param input_len the length of input in bytes +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_PUBLIC_API(2,0) +std::string decrypt(const uint8_t input[], size_t input_len, + const std::string& passphrase); + +/** +* Decrypt a message encrypted with CryptoBox::encrypt +* @param input the input data +* @param passphrase the passphrase used to encrypt the message +*/ +BOTAN_PUBLIC_API(2,0) +std::string decrypt(const std::string& input, + const std::string& passphrase); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/cryptobox/info.txt b/comm/third_party/botan/src/lib/misc/cryptobox/info.txt new file mode 100644 index 0000000000..770076a402 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/cryptobox/info.txt @@ -0,0 +1,14 @@ + +CRYPTO_BOX -> 20131128 + + + +base64 +ctr +hmac +modes +pbkdf2 +pem +serpent +sha2_64 + diff --git a/comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.cpp b/comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.cpp new file mode 100644 index 0000000000..7e3dac5028 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.cpp @@ -0,0 +1,218 @@ +/* +* Format Preserving Encryption (FE1 scheme) +* (C) 2009,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +// Normally FPE is for SSNs, CC#s, etc, nothing too big +const size_t MAX_N_BYTES = 128/8; + +/* +* Factor n into a and b which are as close together as possible. +* Assumes n is composed mostly of small factors which is the case for +* typical uses of FPE (typically, n is a power of 10) +*/ +void factor(BigInt n, BigInt& a, BigInt& b) + { + a = 1; + b = 1; + + size_t n_low_zero = low_zero_bits(n); + + a <<= (n_low_zero / 2); + b <<= n_low_zero - (n_low_zero / 2); + n >>= n_low_zero; + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + while(n % PRIMES[i] == 0) + { + a *= PRIMES[i]; + if(a > b) + std::swap(a, b); + n /= PRIMES[i]; + } + } + + if(a > b) + std::swap(a, b); + a *= n; + + if(a <= 1 || b <= 1) + throw Internal_Error("Could not factor n for use in FPE"); + } + +} + +FPE_FE1::FPE_FE1(const BigInt& n, + size_t rounds, + bool compat_mode, + const std::string& mac_algo) : + m_rounds(rounds) + { + if(m_rounds < 3) + throw Invalid_Argument("FPE_FE1 rounds too small"); + + m_mac = MessageAuthenticationCode::create_or_throw(mac_algo); + + m_n_bytes = BigInt::encode(n); + + if(m_n_bytes.size() > MAX_N_BYTES) + throw Invalid_Argument("N is too large for FPE encryption"); + + factor(n, m_a, m_b); + + if(compat_mode) + { + if(m_a < m_b) + std::swap(m_a, m_b); + } + else + { + if(m_a > m_b) + std::swap(m_a, m_b); + } + + mod_a.reset(new Modular_Reducer(m_a)); + } + +FPE_FE1::~FPE_FE1() + { + // for ~unique_ptr + } + +void FPE_FE1::clear() + { + m_mac->clear(); + } + +std::string FPE_FE1::name() const + { + return "FPE_FE1(" + m_mac->name() + "," + std::to_string(m_rounds) + ")"; + } + +Key_Length_Specification FPE_FE1::key_spec() const + { + return m_mac->key_spec(); + } + +void FPE_FE1::key_schedule(const uint8_t key[], size_t length) + { + m_mac->set_key(key, length); + } + +BigInt FPE_FE1::F(const BigInt& R, size_t round, + const secure_vector& tweak_mac, + secure_vector& tmp) const + { + tmp = BigInt::encode_locked(R); + + m_mac->update(tweak_mac); + m_mac->update_be(static_cast(round)); + + m_mac->update_be(static_cast(tmp.size())); + m_mac->update(tmp.data(), tmp.size()); + + tmp = m_mac->final(); + return BigInt(tmp.data(), tmp.size()); + } + +secure_vector FPE_FE1::compute_tweak_mac(const uint8_t tweak[], size_t tweak_len) const + { + m_mac->update_be(static_cast(m_n_bytes.size())); + m_mac->update(m_n_bytes.data(), m_n_bytes.size()); + + m_mac->update_be(static_cast(tweak_len)); + if(tweak_len > 0) + m_mac->update(tweak, tweak_len); + + return m_mac->final(); + } + +BigInt FPE_FE1::encrypt(const BigInt& input, const uint8_t tweak[], size_t tweak_len) const + { + const secure_vector tweak_mac = compute_tweak_mac(tweak, tweak_len); + + BigInt X = input; + + secure_vector tmp; + + BigInt L, R, Fi; + for(size_t i = 0; i != m_rounds; ++i) + { + ct_divide(X, m_b, L, R); + Fi = F(R, i, tweak_mac, tmp); + X = m_a * R + mod_a->reduce(L + Fi); + } + + return X; + } + +BigInt FPE_FE1::decrypt(const BigInt& input, const uint8_t tweak[], size_t tweak_len) const + { + const secure_vector tweak_mac = compute_tweak_mac(tweak, tweak_len); + + BigInt X = input; + secure_vector tmp; + + BigInt W, R, Fi; + for(size_t i = 0; i != m_rounds; ++i) + { + ct_divide(X, m_a, R, W); + + Fi = F(R, m_rounds-i-1, tweak_mac, tmp); + X = m_b * mod_a->reduce(W - Fi) + R; + } + + return X; + } + +BigInt FPE_FE1::encrypt(const BigInt& x, uint64_t tweak) const + { + uint8_t tweak8[8]; + store_be(tweak, tweak8); + return encrypt(x, tweak8, sizeof(tweak8)); + } + +BigInt FPE_FE1::decrypt(const BigInt& x, uint64_t tweak) const + { + uint8_t tweak8[8]; + store_be(tweak, tweak8); + return decrypt(x, tweak8, sizeof(tweak8)); + } + +namespace FPE { + +BigInt fe1_encrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const std::vector& tweak) + { + FPE_FE1 fpe(n, 3, true, "HMAC(SHA-256)"); + fpe.set_key(key); + return fpe.encrypt(X, tweak.data(), tweak.size()); + } + +BigInt fe1_decrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const std::vector& tweak) + { + FPE_FE1 fpe(n, 3, true, "HMAC(SHA-256)"); + fpe.set_key(key); + return fpe.decrypt(X, tweak.data(), tweak.size()); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.h b/comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.h new file mode 100644 index 0000000000..d9f760f0da --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/fpe_fe1/fpe_fe1.h @@ -0,0 +1,123 @@ +/* +* Format Preserving Encryption (FE1 scheme) +* (C) 2009,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FPE_FE1_H_ +#define BOTAN_FPE_FE1_H_ + +#include +#include + +namespace Botan { + +class Modular_Reducer; +class MessageAuthenticationCode; + +/** +* Format Preserving Encryption using the scheme FE1 from the paper +* "Format-Preserving Encryption" by Bellare, Rogaway, et al +* (https://eprint.iacr.org/2009/251) +*/ +class BOTAN_PUBLIC_API(2,5) FPE_FE1 final : public SymmetricAlgorithm + { + public: + + /** + * @param n the modulus. All plaintext and ciphertext values must be + * less than this. + * @param rounds the number of rounds to use. Must be at least 3. + * @param compat_mode An error in versions before 2.5.0 chose incorrect + * values for a and b. Set compat_mode to true to select this version. + * @param mac_algo the PRF to use as the encryption function + */ + FPE_FE1(const BigInt& n, + size_t rounds = 5, + bool compat_mode = false, + const std::string& mac_algo = "HMAC(SHA-256)"); + + ~FPE_FE1(); + + Key_Length_Specification key_spec() const override; + + std::string name() const override; + + void clear() override; + + /** + * Encrypt X from and onto the group Z_n using key and tweak + * @param x the plaintext to encrypt <= n + * @param tweak will modify the ciphertext + * @param tweak_len length of tweak + */ + BigInt encrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const; + + /** + * Decrypt X from and onto the group Z_n using key and tweak + * @param x the ciphertext to encrypt <= n + * @param tweak must match the value used to encrypt + * @param tweak_len length of tweak + */ + BigInt decrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const; + + BigInt encrypt(const BigInt& x, uint64_t tweak) const; + + BigInt decrypt(const BigInt& x, uint64_t tweak) const; + private: + void key_schedule(const uint8_t key[], size_t length) override; + + BigInt F(const BigInt& R, size_t round, + const secure_vector& tweak, + secure_vector& tmp) const; + + secure_vector compute_tweak_mac(const uint8_t tweak[], size_t tweak_len) const; + + std::unique_ptr m_mac; + std::unique_ptr mod_a; + std::vector m_n_bytes; + BigInt m_a; + BigInt m_b; + size_t m_rounds; + }; + +namespace FPE { + +/** +* Format Preserving Encryption using the scheme FE1 from the paper +* "Format-Preserving Encryption" by Bellare, Rogaway, et al +* (https://eprint.iacr.org/2009/251) +* +* Encrypt X from and onto the group Z_n using key and tweak +* @param n the modulus +* @param X the plaintext as a BigInt +* @param key a random key +* @param tweak will modify the ciphertext (think of as an IV) +* +* @warning This function is hardcoded to use only 3 rounds which +* may be insecure for some values of n. Prefer FPE_FE1 class +*/ +BigInt BOTAN_PUBLIC_API(2,0) fe1_encrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const std::vector& tweak); + +/** +* Decrypt X from and onto the group Z_n using key and tweak +* @param n the modulus +* @param X the ciphertext as a BigInt +* @param key is the key used for encryption +* @param tweak the same tweak used for encryption +* +* @warning This function is hardcoded to use only 3 rounds which +* may be insecure for some values of n. Prefer FPE_FE1 class +*/ +BigInt BOTAN_PUBLIC_API(2,0) fe1_decrypt(const BigInt& n, const BigInt& X, + const SymmetricKey& key, + const std::vector& tweak); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/fpe_fe1/info.txt b/comm/third_party/botan/src/lib/misc/fpe_fe1/info.txt new file mode 100644 index 0000000000..1902fa9662 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/fpe_fe1/info.txt @@ -0,0 +1,10 @@ + +FPE_FE1 -> 20131128 + + + +bigint +hmac +numbertheory +sha2_32 + diff --git a/comm/third_party/botan/src/lib/misc/hotp/hotp.cpp b/comm/third_party/botan/src/lib/misc/hotp/hotp.cpp new file mode 100644 index 0000000000..b9791bc9b0 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/hotp/hotp.cpp @@ -0,0 +1,63 @@ +/* +* HOTP +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +HOTP::HOTP(const uint8_t key[], size_t key_len, + const std::string& hash_algo, size_t digits) + { + BOTAN_ARG_CHECK(digits == 6 || digits == 7 || digits == 8, "Invalid HOTP digits"); + + if(digits == 6) + m_digit_mod = 1000000; + else if(digits == 7) + m_digit_mod = 10000000; + else if(digits == 8) + m_digit_mod = 100000000; + + /* + RFC 4228 only supports SHA-1 but TOTP allows SHA-256 and SHA-512 + and some HOTP libs support one or both as extensions + */ + if(hash_algo == "SHA-1") + m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)"); + else if(hash_algo == "SHA-256") + m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + else if(hash_algo == "SHA-512") + m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)"); + else + throw Invalid_Argument("Unsupported HOTP hash function"); + + m_mac->set_key(key, key_len); + } + +uint32_t HOTP::generate_hotp(uint64_t counter) + { + m_mac->update_be(counter); + const secure_vector mac = m_mac->final(); + + const size_t offset = mac[mac.size()-1] & 0x0F; + const uint32_t code = load_be(mac.data() + offset, 0) & 0x7FFFFFFF; + return code % m_digit_mod; + } + +std::pair HOTP::verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range) + { + for(size_t i = 0; i <= resync_range; ++i) + { + if(generate_hotp(starting_counter + i) == otp) + return std::make_pair(true, starting_counter + i + 1); + } + return std::make_pair(false, starting_counter); + } + +} + diff --git a/comm/third_party/botan/src/lib/misc/hotp/hotp.h b/comm/third_party/botan/src/lib/misc/hotp/hotp.h new file mode 100644 index 0000000000..d8c545557e --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/hotp/hotp.h @@ -0,0 +1,14 @@ +/* +* HOTP +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HOTP_H_ +#define BOTAN_HOTP_H_ + +#include +BOTAN_DEPRECATED_HEADER(hotp.h) + +#endif diff --git a/comm/third_party/botan/src/lib/misc/hotp/info.txt b/comm/third_party/botan/src/lib/misc/hotp/info.txt new file mode 100644 index 0000000000..880940c59a --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/hotp/info.txt @@ -0,0 +1,9 @@ + +HOTP -> 20180816 +TOTP -> 20180816 + + + +hmac +utils + diff --git a/comm/third_party/botan/src/lib/misc/hotp/otp.h b/comm/third_party/botan/src/lib/misc/hotp/otp.h new file mode 100644 index 0000000000..664f181f11 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/hotp/otp.h @@ -0,0 +1,117 @@ +/* +* HOTP/TOTP +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ONE_TIME_PASSWORDS_H_ +#define BOTAN_ONE_TIME_PASSWORDS_H_ + +#include +#include + +namespace Botan { + +/** +* HOTP one time passwords (RFC 4226) +*/ +class BOTAN_PUBLIC_API(2,2) HOTP final + { + public: + /** + * @param key the secret key shared between client and server + * @param hash_algo the hash algorithm to use, should be SHA-1 or SHA-256 + * @param digits the number of digits in the OTP (must be 6, 7, or 8) + */ + HOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", size_t digits = 6) : + HOTP(key.begin(), key.size(), hash_algo, digits) {} + + /** + * @param key the secret key shared between client and server + * @param key_len length of key param + * @param hash_algo the hash algorithm to use, should be SHA-1 or SHA-256 + * @param digits the number of digits in the OTP (must be 6, 7, or 8) + */ + HOTP(const uint8_t key[], size_t key_len, + const std::string& hash_algo = "SHA-1", + size_t digits = 6); + + /** + * Generate the HOTP for a particular counter value + * @warning if the counter value is repeated the OTP ceases to be one-time + */ + uint32_t generate_hotp(uint64_t counter); + + /** + * Check an OTP value using a starting counter and a resync range + * @param otp the client provided OTP + * @param starting_counter the server's guess as to the current counter state + * @param resync_range if 0 then only HOTP(starting_counter) is accepted + * If larger than 0, up to resync_range values after HOTP are also checked. + * @return (valid,next_counter). If the OTP does not validate, always + * returns (false,starting_counter). Otherwise returns (true,next_counter) + * where next_counter is at most starting_counter + resync_range + 1 + */ + std::pair verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range = 0); + private: + std::unique_ptr m_mac; + uint32_t m_digit_mod; + }; + +/** +* TOTP (time based) one time passwords (RFC 6238) +*/ +class BOTAN_PUBLIC_API(2,2) TOTP final + { + public: + /** + * @param key the secret key shared between client and server + * @param hash_algo the hash algorithm to use, should be SHA-1, SHA-256 or SHA-512 + * @param digits the number of digits in the OTP (must be 6, 7, or 8) + * @param time_step granularity of OTP in seconds + */ + TOTP(const SymmetricKey& key, + const std::string& hash_algo = "SHA-1", + size_t digits = 6, size_t time_step = 30) : + TOTP(key.begin(), key.size(), hash_algo, digits, time_step) {} + + /** + * @param key the secret key shared between client and server + * @param key_len length of key + * @param hash_algo the hash algorithm to use, should be SHA-1, SHA-256 or SHA-512 + * @param digits the number of digits in the OTP (must be 6, 7, or 8) + * @param time_step granularity of OTP in seconds + */ + TOTP(const uint8_t key[], size_t key_len, + const std::string& hash_algo = "SHA-1", + size_t digits = 6, + size_t time_step = 30); + + /** + * Convert the provided time_point to a Unix timestamp and call generate_totp + */ + uint32_t generate_totp(std::chrono::system_clock::time_point time_point); + + /** + * Generate the OTP corresponding the the provided "Unix timestamp" (ie + * number of seconds since midnight Jan 1, 1970) + */ + uint32_t generate_totp(uint64_t unix_time); + + bool verify_totp(uint32_t otp, + std::chrono::system_clock::time_point time, + size_t clock_drift_accepted = 0); + + bool verify_totp(uint32_t otp, uint64_t unix_time, + size_t clock_drift_accepted = 0); + + private: + HOTP m_hotp; + size_t m_time_step; + std::chrono::system_clock::time_point m_unix_epoch; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/hotp/totp.cpp b/comm/third_party/botan/src/lib/misc/hotp/totp.cpp new file mode 100644 index 0000000000..5e1c23f61e --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/hotp/totp.cpp @@ -0,0 +1,63 @@ +/* +* TOTP +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +TOTP::TOTP(const uint8_t key[], size_t key_len, + const std::string& hash_algo, + size_t digits, size_t time_step) + : m_hotp(key, key_len, hash_algo, digits) + , m_time_step(time_step) + , m_unix_epoch(calendar_point(1970, 1, 1, 0, 0, 0).to_std_timepoint()) + { + /* + * Technically any time step except 0 is valid, but 30 is typical + * and over 5 minutes seems unlikely. + */ + BOTAN_ARG_CHECK(m_time_step > 0 && m_time_step < 300, "Invalid TOTP time step"); + } + +uint32_t TOTP::generate_totp(std::chrono::system_clock::time_point current_time) + { + const uint64_t unix_time = + std::chrono::duration_cast(current_time - m_unix_epoch).count(); + return this->generate_totp(unix_time); + } + +uint32_t TOTP::generate_totp(uint64_t unix_time) + { + return m_hotp.generate_hotp(unix_time / m_time_step); + } + +bool TOTP::verify_totp(uint32_t otp, std::chrono::system_clock::time_point current_time, + size_t clock_drift_accepted) + { + const uint64_t unix_time = + std::chrono::duration_cast(current_time - m_unix_epoch).count(); + return verify_totp(otp, unix_time, clock_drift_accepted); + } + +bool TOTP::verify_totp(uint32_t otp, uint64_t unix_time, + size_t clock_drift_accepted) + { + uint64_t t = unix_time / m_time_step; + + for(size_t i = 0; i <= clock_drift_accepted; ++i) + { + if(m_hotp.generate_hotp(t-i) == otp) + { + return true; + } + } + + return false; + } + +} diff --git a/comm/third_party/botan/src/lib/misc/hotp/totp.h b/comm/third_party/botan/src/lib/misc/hotp/totp.h new file mode 100644 index 0000000000..a5a0831927 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/hotp/totp.h @@ -0,0 +1,13 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TOTP_H_ +#define BOTAN_TOTP_H_ + +#include +BOTAN_DEPRECATED_HEADER(totp.h) + +#endif diff --git a/comm/third_party/botan/src/lib/misc/nist_keywrap/info.txt b/comm/third_party/botan/src/lib/misc/nist_keywrap/info.txt new file mode 100644 index 0000000000..b48e84c118 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/nist_keywrap/info.txt @@ -0,0 +1,7 @@ + +NIST_KEYWRAP -> 20171119 + + + +block + diff --git a/comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.cpp b/comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.cpp new file mode 100644 index 0000000000..671d31ea4d --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.cpp @@ -0,0 +1,209 @@ +/* +* (C) 2011,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::vector +raw_nist_key_wrap(const uint8_t input[], + size_t input_len, + const BlockCipher& bc, + uint64_t ICV) + { + const size_t n = (input_len + 7) / 8; + + secure_vector R((n + 1) * 8); + secure_vector A(16); + + store_be(ICV, A.data()); + + copy_mem(&R[8], input, input_len); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = 1; i <= n; ++i) + { + const uint32_t t = static_cast((n * j) + i); + + copy_mem(&A[8], &R[8*i], 8); + + bc.encrypt(A.data()); + copy_mem(&R[8*i], &A[8], 8); + + uint8_t t_buf[4] = { 0 }; + store_be(t, t_buf); + xor_buf(&A[4], t_buf, 4); + } + } + + copy_mem(R.data(), A.data(), 8); + + return std::vector(R.begin(), R.end()); + } + +secure_vector +raw_nist_key_unwrap(const uint8_t input[], + size_t input_len, + const BlockCipher& bc, + uint64_t& ICV_out) + { + if(input_len < 16 || input_len % 8 != 0) + throw Invalid_Argument("Bad input size for NIST key unwrap"); + + const size_t n = (input_len - 8) / 8; + + secure_vector R(n * 8); + secure_vector A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = input[i]; + + copy_mem(R.data(), input + 8, input_len - 8); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = n; i != 0; --i) + { + const uint32_t t = static_cast((5 - j) * n + i); + + uint8_t t_buf[4] = { 0 }; + store_be(t, t_buf); + + xor_buf(&A[4], t_buf, 4); + + copy_mem(&A[8], &R[8*(i-1)], 8); + + bc.decrypt(A.data()); + + copy_mem(&R[8*(i-1)], &A[8], 8); + } + } + + ICV_out = load_be(A.data(), 0); + + return R; + } + +} + +std::vector +nist_key_wrap(const uint8_t input[], + size_t input_len, + const BlockCipher& bc) + { + if(bc.block_size() != 16) + throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); + + if(input_len % 8 != 0) + throw Invalid_Argument("Bad input size for NIST key wrap"); + + return raw_nist_key_wrap(input, input_len, bc, 0xA6A6A6A6A6A6A6A6); + } + +secure_vector +nist_key_unwrap(const uint8_t input[], + size_t input_len, + const BlockCipher& bc) + { + if(bc.block_size() != 16) + throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); + + if(input_len < 16 || input_len % 8 != 0) + throw Invalid_Argument("Bad input size for NIST key unwrap"); + + uint64_t ICV_out = 0; + + secure_vector R = raw_nist_key_unwrap(input, input_len, bc, ICV_out); + + if(ICV_out != 0xA6A6A6A6A6A6A6A6) + throw Invalid_Authentication_Tag("NIST key unwrap failed"); + + return R; + } + +std::vector +nist_key_wrap_padded(const uint8_t input[], + size_t input_len, + const BlockCipher& bc) + { + if(bc.block_size() != 16) + throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); + + const uint64_t ICV = 0xA65959A600000000 | static_cast(input_len); + + if(input_len <= 8) + { + /* + * Special case for small inputs: if input <= 8 bytes just use ECB + */ + std::vector block(16); + store_be(ICV, block.data()); + copy_mem(block.data() + 8, input, input_len); + bc.encrypt(block); + return block; + } + else + { + return raw_nist_key_wrap(input, input_len, bc, ICV); + } + } + +secure_vector +nist_key_unwrap_padded(const uint8_t input[], + size_t input_len, + const BlockCipher& bc) + { + if(bc.block_size() != 16) + throw Invalid_Argument("NIST key wrap algorithm requires a 128-bit cipher"); + + if(input_len < 16 || input_len % 8 != 0) + throw Invalid_Argument("Bad input size for NIST key unwrap"); + + uint64_t ICV_out = 0; + secure_vector R; + + if(input_len == 16) + { + secure_vector block(input, input + input_len); + bc.decrypt(block); + + ICV_out = load_be(block.data(), 0); + R.resize(8); + copy_mem(R.data(), block.data() + 8, 8); + } + else + { + R = raw_nist_key_unwrap(input, input_len, bc, ICV_out); + } + + if((ICV_out >> 32) != 0xA65959A6) + throw Invalid_Authentication_Tag("NIST key unwrap failed"); + + const size_t len = (ICV_out & 0xFFFFFFFF); + + if(R.size() < 8 || len > R.size() || len < R.size() - 8) + throw Invalid_Authentication_Tag("NIST key unwrap failed"); + + const size_t padding = R.size() - len; + + for(size_t i = 0; i != padding; ++i) + { + if(R[R.size() - i - 1] != 0) + throw Invalid_Authentication_Tag("NIST key unwrap failed"); + } + + R.resize(R.size() - padding); + + return R; + } + +} diff --git a/comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.h b/comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.h new file mode 100644 index 0000000000..022b4016f5 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/nist_keywrap/nist_keywrap.h @@ -0,0 +1,67 @@ +/* +* (C) 2011,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NIST_KEY_WRAP_H_ +#define BOTAN_NIST_KEY_WRAP_H_ + +#include + +namespace Botan { + +class BlockCipher; + +/** +* Key wrap. See RFC 3394 and NIST SP800-38F +* @param input the value to be encrypted +* @param input_len length of input, must be a multiple of 8 +* @param bc a keyed 128-bit block cipher that will be used to encrypt input +* @return input encrypted under NIST key wrap algorithm +*/ +std::vector BOTAN_PUBLIC_API(2,4) +nist_key_wrap(const uint8_t input[], + size_t input_len, + const BlockCipher& bc); + +/** +* @param input the value to be decrypted, output of nist_key_wrap +* @param input_len length of input +* @param bc a keyed 128-bit block cipher that will be used to decrypt input +* @return input decrypted under NIST key wrap algorithm +* Throws an exception if decryption fails. +*/ +secure_vector BOTAN_PUBLIC_API(2,4) +nist_key_unwrap(const uint8_t input[], + size_t input_len, + const BlockCipher& bc); + +/** +* KWP (key wrap with padding). See RFC 5649 and NIST SP800-38F +* @param input the value to be encrypted +* @param input_len length of input +* @param bc a keyed 128-bit block cipher that will be used to encrypt input +* @return input encrypted under NIST key wrap algorithm +*/ +std::vector BOTAN_PUBLIC_API(2,4) +nist_key_wrap_padded(const uint8_t input[], + size_t input_len, + const BlockCipher& bc); + +/** +* @param input the value to be decrypted, output of nist_key_wrap +* @param input_len length of input +* @param bc a keyed 128-bit block cipher that will be used to decrypt input +* @return input decrypted under NIST key wrap algorithm +* Throws an exception if decryption fails. +*/ +secure_vector BOTAN_PUBLIC_API(2,4) +nist_key_unwrap_padded(const uint8_t input[], + size_t input_len, + const BlockCipher& bc); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/rfc3394/info.txt b/comm/third_party/botan/src/lib/misc/rfc3394/info.txt new file mode 100644 index 0000000000..075834219a --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/rfc3394/info.txt @@ -0,0 +1,8 @@ + +RFC3394_KEYWRAP -> 20131128 + + + +aes +nist_keywrap + diff --git a/comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.cpp b/comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.cpp new file mode 100644 index 0000000000..cb24809984 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.cpp @@ -0,0 +1,44 @@ +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +secure_vector rfc3394_keywrap(const secure_vector& key, + const SymmetricKey& kek) + { + BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32, + "Invalid KEK length for NIST key wrap"); + + const std::string cipher_name = "AES-" + std::to_string(8*kek.size()); + std::unique_ptr aes(BlockCipher::create_or_throw(cipher_name)); + aes->set_key(kek); + + std::vector wrapped = nist_key_wrap(key.data(), key.size(), *aes); + return secure_vector(wrapped.begin(), wrapped.end()); + } + +secure_vector rfc3394_keyunwrap(const secure_vector& key, + const SymmetricKey& kek) + { + BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32, + "Invalid KEK length for NIST key wrap"); + + BOTAN_ARG_CHECK(key.size() >= 16 && key.size() % 8 == 0, + "Bad input key size for NIST key unwrap"); + + const std::string cipher_name = "AES-" + std::to_string(8*kek.size()); + std::unique_ptr aes(BlockCipher::create_or_throw(cipher_name)); + aes->set_key(kek); + + return nist_key_unwrap(key.data(), key.size(), *aes); + } + +} diff --git a/comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.h b/comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.h new file mode 100644 index 0000000000..9cfcfaaf6d --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/rfc3394/rfc3394.h @@ -0,0 +1,39 @@ +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RFC3394_H_ +#define BOTAN_RFC3394_H_ + +#include + +namespace Botan { + +/** +* Encrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the plaintext key to encrypt +* @param kek the key encryption key +* @return key encrypted under kek +*/ +secure_vector BOTAN_PUBLIC_API(2,0) rfc3394_keywrap(const secure_vector& key, + const SymmetricKey& kek); + +/** +* Decrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the encrypted key to decrypt +* @param kek the key encryption key +* @return key decrypted under kek +*/ +secure_vector BOTAN_PUBLIC_API(2,0) rfc3394_keyunwrap(const secure_vector& key, + const SymmetricKey& kek); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/roughtime/info.txt b/comm/third_party/botan/src/lib/misc/roughtime/info.txt new file mode 100644 index 0000000000..560f526660 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/roughtime/info.txt @@ -0,0 +1,10 @@ + +ROUGHTIME -> 20190220 + + + +ed25519 +rng +sha2_64 +socket + diff --git a/comm/third_party/botan/src/lib/misc/roughtime/roughtime.cpp b/comm/third_party/botan/src/lib/misc/roughtime/roughtime.cpp new file mode 100644 index 0000000000..384d40626e --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/roughtime/roughtime.cpp @@ -0,0 +1,466 @@ +/* +* Roughtime +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace Botan { + +namespace { + +// This exists to work around a LGTM false positive +static_assert(Roughtime::request_min_size == 1024, "Expected minimum size"); + +template< bool B, class T = void > +using enable_if_t = typename std::enable_if::type; + +template +struct is_array : std::false_type {}; + +template +struct is_array>:std::true_type{}; + +template +T impl_from_little_endian(const uint8_t* t, const size_t i) + { + static_assert(sizeof(T) <= sizeof(int64_t), ""); + return T(static_cast(t[i]) << i * 8) + (i == 0 ? T(0) : impl_from_little_endian(t, i - 1)); + } + +template +T from_little_endian(const uint8_t* t) + { + return impl_from_little_endian(t, sizeof(T) - 1); + } + +template::value>* = nullptr> +T copy(const uint8_t* t) + { + return typecast_copy(t); //arrays are endianess indepedent, so we do a memcpy + } + +template::value>* = nullptr> +T copy(const uint8_t* t) + { + return from_little_endian(t); //other types are arithmetic, so we account that roughtime serializes as little endian + } + +template +std::map> unpack_roughtime_packet(T bytes) + { + if(bytes.size() < 8) + { throw Roughtime::Roughtime_Error("Map length is under minimum of 8 bytes"); } + const auto buf = bytes.data(); + const uint32_t num_tags = buf[0]; + const uint32_t start_content = num_tags * 8; + if(start_content > bytes.size()) + { throw Roughtime::Roughtime_Error("Map length too small to contain all tags"); } + uint32_t start = start_content; + std::map> tags; + for(uint32_t i=0; i(buf + 4 + i*4); + if(end > bytes.size()) + { throw Roughtime::Roughtime_Error("Tag end index out of bounds"); } + if(end < start) + { throw Roughtime::Roughtime_Error("Tag offset must be more than previous tag offset"); } + const char* label_ptr = cast_uint8_ptr_to_char(buf) + (num_tags+i)*4; + const char label[] = {label_ptr[0], label_ptr[1], label_ptr[2], label_ptr[3], 0}; + auto ret = tags.emplace(label, std::vector(buf+start, buf+end)); + if(!ret.second) + { throw Roughtime::Roughtime_Error(std::string("Map has duplicated tag: ") + label); } + start = static_cast(end); + } + return tags; + } + +template +T get(const std::map>& map, const std::string& label) + { + const auto& tag = map.find(label); + if(tag == map.end()) + { throw Roughtime::Roughtime_Error("Tag " + label + " not found"); } + if(tag->second.size() != sizeof(T)) + { throw Roughtime::Roughtime_Error("Tag " + label + " has unexpected size"); } + return copy(tag->second.data()); + } + +const std::vector& get_v(const std::map>& map, const std::string& label) + { + const auto& tag = map.find(label); + if(tag == map.end()) + { throw Roughtime::Roughtime_Error("Tag " + label + " not found"); } + return tag->second; + } + +bool verify_signature(const std::array& pk, const std::vector& payload, + const std::array& signature) + { + const char context[] = "RoughTime v1 response signature"; + Ed25519_PublicKey key(std::vector(pk.data(), pk.data()+pk.size())); + PK_Verifier verifier(key, "Pure"); + verifier.update(cast_char_ptr_to_uint8(context), sizeof(context)); //add context including \0 + verifier.update(payload); + return verifier.check_signature(signature.data(), signature.size()); + } + +std::array hashLeaf(const std::array& leaf) + { + std::array ret; + std::unique_ptr hash(HashFunction::create_or_throw("SHA-512")); + hash->update(0); + hash->update(leaf.data(), leaf.size()); + hash->final(ret.data()); + return ret; + } + +void hashNode(std::array& hash, const std::array& node, bool reverse) + { + std::unique_ptr h(HashFunction::create_or_throw("SHA-512")); + h->update(1); + if(reverse) + { + h->update(node.data(), node.size()); + h->update(hash.data(), hash.size()); + } + else + { + h->update(hash.data(), hash.size()); + h->update(node.data(), node.size()); + } + h->final(hash.data()); + } + +template +std::array vector_to_array(std::vector vec) + { + if(vec.size() != N) + { throw std::logic_error("Invalid vector size"); } + return typecast_copy>(vec.data()); + } +} + +namespace Roughtime { + +Nonce::Nonce(const std::vector& nonce) + { + if(nonce.size() != 64) + { throw Invalid_Argument("Nonce lenght must be 64"); } + m_nonce = typecast_copy>(nonce.data()); + } +Nonce::Nonce(RandomNumberGenerator& rng) + { + rng.randomize(m_nonce.data(), m_nonce.size()); + } + +std::array encode_request(const Nonce& nonce) + { + std::array buf = {{2, 0, 0, 0, 64, 0, 0, 0, 'N', 'O', 'N', 'C', 'P', 'A', 'D', 0xff}}; + std::memcpy(buf.data() + 16, nonce.get_nonce().data(), nonce.get_nonce().size()); + std::memset(buf.data() + 16 + nonce.get_nonce().size(), 0, buf.size() - 16 - nonce.get_nonce().size()); + return buf; + } + +Response Response::from_bits(const std::vector& response, + const Nonce& nonce) + { + const auto response_v = unpack_roughtime_packet(response); + const auto cert = unpack_roughtime_packet(get_v(response_v, "CERT")); + const auto cert_dele = get>(cert, "DELE"); + const auto cert_sig = get>(cert, "SIG"); + const auto cert_dele_v = unpack_roughtime_packet(cert_dele); + const auto srep = get_v(response_v, "SREP"); + const auto srep_v = unpack_roughtime_packet(srep); + + const auto cert_dele_pubk = get>(cert_dele_v, "PUBK"); + const auto sig = get>(response_v, "SIG"); + if(!verify_signature(cert_dele_pubk, srep, sig)) + { throw Roughtime_Error("Response signature invalid"); } + + const auto indx = get(response_v, "INDX"); + const auto path = get_v(response_v, "PATH"); + const auto srep_root = get>(srep_v, "ROOT"); + const auto size = path.size(); + const auto levels = size/64; + + if(size % 64) + { throw Roughtime_Error("Merkle tree path size must be multiple of 64 bytes"); } + if(indx >= (1u << levels)) + { throw Roughtime_Error("Merkle tree path is too short"); } + + auto hash = hashLeaf(nonce.get_nonce()); + auto index = indx; + auto level = 0u; + while(level < levels) + { + hashNode(hash, typecast_copy>(path.data() + level*64), index&1); + ++level; + index>>=1; + } + + if(srep_root != hash) + { throw Roughtime_Error("Nonce verification failed"); } + + const auto cert_dele_maxt = sys_microseconds64(get(cert_dele_v, "MAXT")); + const auto cert_dele_mint = sys_microseconds64(get(cert_dele_v, "MINT")); + const auto srep_midp = sys_microseconds64(get(srep_v, "MIDP")); + const auto srep_radi = get(srep_v, "RADI"); + if(srep_midp < cert_dele_mint) + { throw Roughtime_Error("Midpoint earlier than delegation start"); } + if(srep_midp > cert_dele_maxt) + { throw Roughtime_Error("Midpoint later than delegation end"); } + return {cert_dele, cert_sig, srep_midp, srep_radi}; + } + +bool Response::validate(const Ed25519_PublicKey& pk) const + { + const char context[] = "RoughTime v1 delegation signature--"; + PK_Verifier verifier(pk, "Pure"); + verifier.update(cast_char_ptr_to_uint8(context), sizeof(context)); //add context including \0 + verifier.update(m_cert_dele.data(), m_cert_dele.size()); + return verifier.check_signature(m_cert_sig.data(), m_cert_sig.size()); + } + +Nonce nonce_from_blind(const std::vector& previous_response, + const Nonce& blind) + { + std::array ret; + const auto blind_arr = blind.get_nonce(); + std::unique_ptr hash(Botan::HashFunction::create_or_throw("SHA-512")); + hash->update(previous_response); + hash->update(hash->final()); + hash->update(blind_arr.data(), blind_arr.size()); + hash->final(ret.data()); + + return ret; + } + +Chain::Chain(const std::string& str) + { + std::stringstream ss(str); + const std::string ERROR_MESSAGE = "Line does not have 4 space separated fields"; + for(std::string s; std::getline(ss, s);) + { + size_t start = 0, end = 0; + end = s.find(' ', start); + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto publicKeyType = s.substr(start, end-start); + if(publicKeyType != "ed25519") + { throw Not_Implemented("Only ed25519 publicKeyType is implemented"); } + + start = end + 1; + end = s.find(' ', start); + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto serverPublicKey = Botan::Ed25519_PublicKey(Botan::base64_decode(s.substr(start, end-start))); + + start = end + 1; + end = s.find(' ', start); + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + if((end - start) != 88) + { + throw Decoding_Error("Nonce has invalid length"); + } + const auto vec = Botan::base64_decode(s.substr(start, end-start)); + const auto nonceOrBlind = Nonce(vector_to_array<64>(Botan::base64_decode(s.substr(start, end-start)))); + + start = end + 1; + end = s.find(' ', start); + if(end != std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto response = Botan::unlock(Botan::base64_decode(s.substr(start))); + + m_links.push_back({response, serverPublicKey, nonceOrBlind}); + } + } +std::vector Chain::responses() const + { + std::vector responses; + for(unsigned i = 0; i < m_links.size(); ++i) + { + const auto& l = m_links[i]; + const auto nonce = i ? nonce_from_blind(m_links[i-1].response(), l.nonce_or_blind()) : l.nonce_or_blind(); + const auto response = Response::from_bits(l.response(), nonce); + if(!response.validate(l.public_key())) + { throw Roughtime_Error("Invalid signature or public key"); } + responses.push_back(response); + } + return responses; + } +Nonce Chain::next_nonce(const Nonce& blind) const + { + return m_links.empty() + ? blind + : nonce_from_blind(m_links.back().response(), blind); + } +void Chain::append(const Link& new_link, size_t max_chain_size) + { + if(max_chain_size <= 0) + { throw Invalid_Argument("Max chain size must be positive"); } + + while(m_links.size() >= max_chain_size) + { + if(m_links.size() == 1) + { + auto new_link_updated = new_link; + new_link_updated.nonce_or_blind() = + nonce_from_blind(m_links[0].response(), new_link.nonce_or_blind()); //we need to convert blind to nonce + m_links.clear(); + m_links.push_back(new_link_updated); + return; + } + if(m_links.size() >= 2) + { + m_links[1].nonce_or_blind() = + nonce_from_blind(m_links[0].response(), m_links[1].nonce_or_blind()); //we need to convert blind to nonce + } + m_links.erase(m_links.begin()); + } + m_links.push_back(new_link); + } + +std::string Chain::to_string() const + { + std::string s; + s.reserve((7+1 + 88+1 + 44+1 + 480)*m_links.size()); + for(const auto& link : m_links) + { + s += "ed25519"; + s += ' '; + s += Botan::base64_encode(link.public_key().get_public_key()); + s += ' '; + s += Botan::base64_encode(link.nonce_or_blind().get_nonce().data(), link.nonce_or_blind().get_nonce().size()); + s += ' '; + s += Botan::base64_encode(link.response()); + s += '\n'; + } + return s; + } + +std::vector online_request(const std::string& uri, + const Nonce& nonce, + std::chrono::milliseconds timeout) + { + const std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now(); + auto socket = OS::open_socket_udp(uri, timeout); + if(!socket) + { throw Not_Implemented("No socket support enabled in build"); } + + const auto encoded = encode_request(nonce); + socket->write(encoded.data(), encoded.size()); + + if(std::chrono::system_clock::now() - start_time > timeout) + { throw System_Error("Timeout during socket write"); } + + std::vector buffer; + buffer.resize(360+64*10+1); //response basic size is 360 bytes + 64 bytes for each level of merkle tree + //add one additional byte to be able to differentiate if datagram got truncated + const auto n = socket->read(buffer.data(), buffer.size()); + + if(!n || std::chrono::system_clock::now() - start_time > timeout) + { throw System_Error("Timeout waiting for response"); } + + if(n == buffer.size()) + { throw System_Error("Buffer too small"); } + + buffer.resize(n); + return buffer; + } + +std::vector servers_from_str(const std::string& str) + { + std::vector servers; + std::stringstream ss(str); + const std::string ERROR_MESSAGE = "Line does not have at least 5 space separated fields"; + for(std::string s; std::getline(ss, s);) + { + size_t start = 0, end = 0; + end = s.find(' ', start); + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto name = s.substr(start, end-start); + + start = end + 1; + end = s.find(' ', start); + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto publicKeyType = s.substr(start, end-start); + if(publicKeyType != "ed25519") + { throw Not_Implemented("Only ed25519 publicKeyType is implemented"); } + + start = end + 1; + end = s.find(' ', start); + + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto publicKeyBase64 = s.substr(start, end-start); + const auto publicKey = Botan::Ed25519_PublicKey(Botan::base64_decode(publicKeyBase64)); + + start = end + 1; + end = s.find(' ', start); + if(end == std::string::npos) + { + throw Decoding_Error(ERROR_MESSAGE); + } + const auto protocol = s.substr(start, end-start); + if(protocol != "udp") + { throw Not_Implemented("Only UDP protocol is implemented"); } + + const auto addresses = [&]() + { + std::vector addr; + for(;;) + { + start = end + 1; + end = s.find(' ', start); + const auto address = s.substr(start, (end == std::string::npos) ? std::string::npos : end-start); + if(address.empty()) + { return addr; } + addr.push_back(address); + if(end == std::string::npos) + { return addr; } + } + } + (); + if(addresses.size() == 0) + { + throw Decoding_Error(ERROR_MESSAGE); + } + + servers.push_back({name, publicKey, std::move(addresses)}); + } + return servers; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/misc/roughtime/roughtime.h b/comm/third_party/botan/src/lib/misc/roughtime/roughtime.h new file mode 100644 index 0000000000..e52be25a16 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/roughtime/roughtime.h @@ -0,0 +1,167 @@ +/* +* Roughtime +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ROUGHTIME_H_ +#define BOTAN_ROUGHTIME_H_ + +#include +#include +#include + +#include + +namespace Botan { + +class RandomNumberGenerator; + +namespace Roughtime { + +const unsigned request_min_size = 1024; + +class BOTAN_PUBLIC_API(2, 13) Roughtime_Error final : public Decoding_Error + { + public: + explicit Roughtime_Error(const std::string& s) : Decoding_Error("Roughtime " + s) {} + ErrorType error_type() const noexcept override { return ErrorType::RoughtimeError; } + }; + +class BOTAN_PUBLIC_API(2, 13) Nonce final + { + public: + Nonce() = default; + Nonce(const std::vector& nonce); + Nonce(RandomNumberGenerator& rng); + Nonce(const std::array& nonce) + { + m_nonce = nonce; + } + bool operator==(const Nonce& rhs) const { return m_nonce == rhs.m_nonce; } + const std::array& get_nonce() const { return m_nonce; } + private: + std::array m_nonce; + }; + + +/** +* An Roughtime request. +*/ +BOTAN_PUBLIC_API(2, 13) +std::array encode_request(const Nonce& nonce); + +/** +* An Roughtime response. +*/ +class BOTAN_PUBLIC_API(2, 13) Response final + { + public: + using microseconds32 = std::chrono::duration; + using microseconds64 = std::chrono::duration; + using sys_microseconds64 = std::chrono::time_point; + + static Response from_bits(const std::vector& response, const Nonce& nonce); + + bool validate(const Ed25519_PublicKey& pk) const; + + sys_microseconds64 utc_midpoint() const { return m_utc_midpoint; } + + microseconds32 utc_radius() const { return m_utc_radius; } + private: + Response(const std::array& dele, + const std::array& sig, + sys_microseconds64 utc_midp, + microseconds32 utc_radius) + : m_cert_dele(dele) + , m_cert_sig(sig) + , m_utc_midpoint {utc_midp} + , m_utc_radius {utc_radius} + {} + const std::array m_cert_dele; + const std::array m_cert_sig; + const sys_microseconds64 m_utc_midpoint; + const microseconds32 m_utc_radius; + }; + +class BOTAN_PUBLIC_API(2, 13) Link final + { + public: + Link(const std::vector& response, + const Ed25519_PublicKey& public_key, + const Nonce& nonce_or_blind) + : m_response{response} + , m_public_key{public_key} + , m_nonce_or_blind{nonce_or_blind} + {} + const std::vector& response() const { return m_response; } + const Ed25519_PublicKey& public_key() const { return m_public_key; } + const Nonce& nonce_or_blind() const { return m_nonce_or_blind; } + Nonce& nonce_or_blind() { return m_nonce_or_blind; } + + private: + std::vector m_response; + Ed25519_PublicKey m_public_key; + Nonce m_nonce_or_blind; + }; + +class BOTAN_PUBLIC_API(2, 13) Chain final + { + public: + Chain() = default; //empty + Chain(const std::string& str); + const std::vector& links() const { return m_links; } + std::vector responses() const; + Nonce next_nonce(const Nonce& blind) const; + void append(const Link& new_link, size_t max_chain_size); + std::string to_string() const; + private: + std::vector m_links; + }; + +/** +*/ +BOTAN_PUBLIC_API(2, 13) +Nonce nonce_from_blind(const std::vector& previous_response, + const Nonce& blind); + +/** +* Makes an online Roughtime request via UDP and returns the Roughtime response. +* @param url Roughtime server UDP endpoint (host:port) +* @param nonce the nonce to send to the server +* @param timeout a timeout on the UDP request +* @return Roughtime response +*/ +BOTAN_PUBLIC_API(2, 13) +std::vector online_request(const std::string& url, + const Nonce& nonce, + std::chrono::milliseconds timeout = std::chrono::seconds(3)); + +struct BOTAN_PUBLIC_API(2, 13) Server_Information final + { +public: + Server_Information(const std::string& name, + const Botan::Ed25519_PublicKey& public_key, + const std::vector& addresses) + : m_name { name } + , m_public_key { public_key } + , m_addresses { addresses } + {} + const std::string& name() const {return m_name;} + const Botan::Ed25519_PublicKey& public_key() const {return m_public_key;} + const std::vector& addresses() const {return m_addresses;} + +private: + std::string m_name; + Botan::Ed25519_PublicKey m_public_key; + std::vector m_addresses; + }; + +BOTAN_PUBLIC_API(2, 13) +std::vector servers_from_str(const std::string& str); + +} +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/srp6/info.txt b/comm/third_party/botan/src/lib/misc/srp6/info.txt new file mode 100644 index 0000000000..27b7848f5b --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/srp6/info.txt @@ -0,0 +1,8 @@ + +SRP6 -> 20161017 + + + +bigint +dl_group + diff --git a/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp b/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp new file mode 100644 index 0000000000..0bd9b192ae --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp @@ -0,0 +1,193 @@ +/* +* SRP-6a (RFC 5054 compatatible) +* (C) 2011,2012,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +BigInt hash_seq(const std::string& hash_id, + size_t pad_to, + const BigInt& in1, + const BigInt& in2) + { + std::unique_ptr hash_fn(HashFunction::create_or_throw(hash_id)); + + hash_fn->update(BigInt::encode_1363(in1, pad_to)); + hash_fn->update(BigInt::encode_1363(in2, pad_to)); + + return BigInt::decode(hash_fn->final()); + } + +BigInt compute_x(const std::string& hash_id, + const std::string& identifier, + const std::string& password, + const std::vector& salt) + { + std::unique_ptr hash_fn(HashFunction::create_or_throw(hash_id)); + + hash_fn->update(identifier); + hash_fn->update(":"); + hash_fn->update(password); + + secure_vector inner_h = hash_fn->final(); + + hash_fn->update(salt); + hash_fn->update(inner_h); + + secure_vector outer_h = hash_fn->final(); + + return BigInt::decode(outer_h); + } + +} + +std::string srp6_group_identifier(const BigInt& N, const BigInt& g) + { + /* + This function assumes that only one 'standard' SRP parameter set has + been defined for a particular bitsize. As of this writing that is the case. + */ + try + { + const std::string group_name = "modp/srp/" + std::to_string(N.bits()); + + DL_Group group(group_name); + + if(group.get_p() == N && group.get_g() == g) + return group_name; + } + catch(...) + { + } + + // If we didn't return, the group was unknown or did not match + throw Invalid_Argument("Invalid or unknown SRP group parameters"); + } + +std::pair +srp6_client_agree(const std::string& identifier, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const std::vector& salt, + const BigInt& B, + RandomNumberGenerator& rng) + { + DL_Group group(group_id); + const size_t a_bits = group.exponent_bits(); + + return srp6_client_agree(identifier, password, group, hash_id, salt, B, a_bits, rng); + } + +std::pair +srp6_client_agree(const std::string& identifier, + const std::string& password, + const DL_Group& group, + const std::string& hash_id, + const std::vector& salt, + const BigInt& B, + const size_t a_bits, + RandomNumberGenerator& rng) + { + const BigInt& g = group.get_g(); + const BigInt& p = group.get_p(); + + const size_t p_bytes = group.p_bytes(); + + if(B <= 0 || B >= p) + throw Decoding_Error("Invalid SRP parameter from server"); + + const BigInt k = hash_seq(hash_id, p_bytes, p, g); + + const BigInt a(rng, a_bits); + + const BigInt A = group.power_g_p(a, a_bits); + + const BigInt u = hash_seq(hash_id, p_bytes, A, B); + + const BigInt x = compute_x(hash_id, identifier, password, salt); + + const BigInt S = power_mod(group.mod_p(B - (k * power_mod(g, x, p))), + group.mod_p(a + (u * x)), p); + + const SymmetricKey Sk(BigInt::encode_1363(S, p_bytes)); + + return std::make_pair(A, Sk); + } + +BigInt generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const std::vector& salt, + const std::string& group_id, + const std::string& hash_id) + { + DL_Group group(group_id); + return generate_srp6_verifier(identifier, password, salt, group, hash_id); + } + +BigInt generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const std::vector& salt, + const DL_Group& group, + const std::string& hash_id) + { + const BigInt x = compute_x(hash_id, identifier, password, salt); + // FIXME: x should be size of hash fn so avoid computing x.bits() here + return group.power_g_p(x, x.bits()); + } + +BigInt SRP6_Server_Session::step1(const BigInt& v, + const std::string& group_id, + const std::string& hash_id, + RandomNumberGenerator& rng) + { + DL_Group group(group_id); + const size_t b_bits = group.exponent_bits(); + + return this->step1(v, group, hash_id, b_bits, rng); + } + +BigInt SRP6_Server_Session::step1(const BigInt& v, + const DL_Group& group, + const std::string& hash_id, + size_t b_bits, + RandomNumberGenerator& rng) + { + const BigInt& g = group.get_g(); + const BigInt& p = group.get_p(); + + m_p_bytes = p.bytes(); + m_v = v; + m_b = BigInt(rng, b_bits); + m_p = p; + m_hash_id = hash_id; + + const BigInt k = hash_seq(hash_id, m_p_bytes, p, g); + + m_B = group.mod_p(v*k + group.power_g_p(m_b, b_bits)); + + return m_B; + } + +SymmetricKey SRP6_Server_Session::step2(const BigInt& A) + { + if(A <= 0 || A >= m_p) + throw Decoding_Error("Invalid SRP parameter from client"); + + const BigInt u = hash_seq(m_hash_id, m_p_bytes, A, m_B); + + const BigInt S = power_mod(A * power_mod(m_v, u, m_p), m_b, m_p); + + return BigInt::encode_1363(S, m_p_bytes); + } + +} diff --git a/comm/third_party/botan/src/lib/misc/srp6/srp6.h b/comm/third_party/botan/src/lib/misc/srp6/srp6.h new file mode 100644 index 0000000000..6bb4b7e7c5 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/srp6/srp6.h @@ -0,0 +1,155 @@ +/* +* SRP-6a (RFC 5054 compatatible) +* (C) 2011,2012,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RFC5054_SRP6_H_ +#define BOTAN_RFC5054_SRP6_H_ + +#include +#include +#include + +namespace Botan { + +class DL_Group; +class RandomNumberGenerator; + +/** +* SRP6a Client side +* @param username the username we are attempting login for +* @param password the password we are attempting to use +* @param group_id specifies the shared SRP group +* @param hash_id specifies a secure hash function +* @param salt is the salt value sent by the server +* @param B is the server's public value +* @param rng is a random number generator +* +* @return (A,K) the client public key and the shared secret key +*/ +std::pair +BOTAN_PUBLIC_API(2,0) srp6_client_agree(const std::string& username, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const std::vector& salt, + const BigInt& B, + RandomNumberGenerator& rng); + + +/** +* SRP6a Client side +* @param username the username we are attempting login for +* @param password the password we are attempting to use +* @param group specifies the shared SRP group +* @param hash_id specifies a secure hash function +* @param salt is the salt value sent by the server +* @param B is the server's public value +* @param a_bits size of secret exponent in bits +* @param rng is a random number generator +* +* @return (A,K) the client public key and the shared secret key +*/ +std::pair BOTAN_PUBLIC_API(2,11) + srp6_client_agree(const std::string& username, + const std::string& password, + const DL_Group& group, + const std::string& hash_id, + const std::vector& salt, + const BigInt& B, + size_t a_bits, + RandomNumberGenerator& rng); + +/** +* Generate a new SRP-6 verifier +* @param identifier a username or other client identifier +* @param password the secret used to authenticate user +* @param salt a randomly chosen value, at least 128 bits long +* @param group_id specifies the shared SRP group +* @param hash_id specifies a secure hash function +*/ +BigInt BOTAN_PUBLIC_API(2,0) + generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const std::vector& salt, + const std::string& group_id, + const std::string& hash_id); + +/** +* Generate a new SRP-6 verifier +* @param identifier a username or other client identifier +* @param password the secret used to authenticate user +* @param salt a randomly chosen value, at least 128 bits long +* @param group specifies the shared SRP group +* @param hash_id specifies a secure hash function +*/ +BigInt BOTAN_PUBLIC_API(2,11) + generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const std::vector& salt, + const DL_Group& group, + const std::string& hash_id); + +/** +* Return the group id for this SRP param set, or else thrown an +* exception +* @param N the group modulus +* @param g the group generator +* @return group identifier +*/ +std::string BOTAN_PUBLIC_API(2,0) srp6_group_identifier(const BigInt& N, const BigInt& g); + +/** +* Represents a SRP-6a server session +*/ +class BOTAN_PUBLIC_API(2,0) SRP6_Server_Session final + { + public: + /** + * Server side step 1 + * @param v the verification value saved from client registration + * @param group_id the SRP group id + * @param hash_id the SRP hash in use + * @param rng a random number generator + * @return SRP-6 B value + */ + BigInt step1(const BigInt& v, + const std::string& group_id, + const std::string& hash_id, + RandomNumberGenerator& rng); + + /** + * Server side step 1 + * This version of step1 added in 2.11 + * + * @param v the verification value saved from client registration + * @param group the SRP group + * @param hash_id the SRP hash in use + * @param rng a random number generator + * @param b_bits size of secret exponent in bits + * @return SRP-6 B value + */ + BigInt step1(const BigInt& v, + const DL_Group& group, + const std::string& hash_id, + const size_t b_bits, + RandomNumberGenerator& rng); + + /** + * Server side step 2 + * @param A the client's value + * @return shared symmetric key + */ + SymmetricKey step2(const BigInt& A); + + private: + std::string m_hash_id; + BigInt m_B, m_b, m_v, m_S, m_p; + size_t m_p_bytes = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/misc/tss/info.txt b/comm/third_party/botan/src/lib/misc/tss/info.txt new file mode 100644 index 0000000000..513be70bc5 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/tss/info.txt @@ -0,0 +1,10 @@ + +THRESHOLD_SECRET_SHARING -> 20131128 + + + +rng +hex +sha1 +sha2_32 + diff --git a/comm/third_party/botan/src/lib/misc/tss/tss.cpp b/comm/third_party/botan/src/lib/misc/tss/tss.cpp new file mode 100644 index 0000000000..dd3a294f8a --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/tss/tss.cpp @@ -0,0 +1,333 @@ +/* +* RTSS (threshold secret sharing) +* (C) 2009,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const size_t RTSS_HEADER_SIZE = 20; + +/** +Table for GF(2^8) arithmetic (exponentials) +*/ +const uint8_t RTSS_EXP[256] = { +0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, +0x96, 0xA1, 0xF8, 0x13, 0x35, 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, +0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA, 0xE5, +0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, +0x90, 0xAB, 0xE6, 0x31, 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, +0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD, 0x4C, 0xD4, +0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, +0x28, 0x78, 0x88, 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, +0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A, 0xB5, 0xC4, 0x57, +0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, +0x61, 0xA3, 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, +0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0, 0xFB, 0x16, 0x3A, 0x4E, +0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, +0x41, 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, +0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75, 0x9F, 0xBA, 0xD5, 0x64, 0xAC, +0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80, +0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, +0xB1, 0xC8, 0x43, 0xC5, 0x54, 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, +0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA, 0x45, +0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, +0xC6, 0x51, 0xF3, 0x0E, 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, +0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17, 0x39, 0x4B, +0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, +0x52, 0xF6, 0x01 }; + +/** +Table for GF(2^8) arithmetic (logarithms) +*/ +const uint8_t RTSS_LOG[] = { +0x90, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, +0x68, 0x33, 0xEE, 0xDF, 0x03, 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, +0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1, 0x7D, +0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, +0x9A, 0xC9, 0x09, 0x78, 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, +0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E, 0x96, 0x8F, +0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, +0x46, 0x83, 0x38, 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, +0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10, 0x7E, 0x6E, 0x48, +0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, +0x3D, 0xBA, 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, +0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57, 0xAF, 0x58, 0xA8, 0x50, +0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, +0xE8, 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, +0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0, 0x7F, 0x0C, 0xF6, 0x6F, 0x17, +0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7, +0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, +0x6C, 0xAA, 0x55, 0x29, 0x9D, 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, +0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1, 0x53, +0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, +0x56, 0xF2, 0xD3, 0xAB, 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, +0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5, 0x67, 0x4A, +0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, +0xF7, 0x70, 0x07 }; + +uint8_t gfp_mul(uint8_t x, uint8_t y) + { + if(x == 0 || y == 0) + return 0; + return RTSS_EXP[(RTSS_LOG[x] + RTSS_LOG[y]) % 255]; + } + +uint8_t rtss_hash_id(const std::string& hash_name) + { + if(hash_name == "None") + return 0; + else if(hash_name == "SHA-160" || hash_name == "SHA-1" || hash_name == "SHA1") + return 1; + else if(hash_name == "SHA-256") + return 2; + else + throw Invalid_Argument("RTSS only supports SHA-1 and SHA-256"); + } + +std::unique_ptr get_rtss_hash_by_id(uint8_t id) + { + if(id == 0) + return std::unique_ptr(); + if(id == 1) + return HashFunction::create_or_throw("SHA-1"); + else if(id == 2) + return HashFunction::create_or_throw("SHA-256"); + else + throw Decoding_Error("Unknown RTSS hash identifier"); + } + +} + +RTSS_Share::RTSS_Share(const std::string& hex_input) + { + m_contents = hex_decode_locked(hex_input); + } + +RTSS_Share::RTSS_Share(const uint8_t bin[], size_t len) + { + m_contents.assign(bin, bin + len); + } + +uint8_t RTSS_Share::share_id() const + { + if(!initialized()) + throw Invalid_State("RTSS_Share::share_id not initialized"); + + if(m_contents.size() < RTSS_HEADER_SIZE + 1) + throw Decoding_Error("RTSS_Share::share_id invalid share data"); + + return m_contents[20]; + } + +std::string RTSS_Share::to_string() const + { + return hex_encode(m_contents.data(), m_contents.size()); + } + +std::vector +RTSS_Share::split(uint8_t M, uint8_t N, + const uint8_t S[], uint16_t S_len, + const uint8_t identifier[16], + RandomNumberGenerator& rng) + { + return RTSS_Share::split(M, N, S, S_len, + std::vector(identifier, identifier + 16), + "SHA-256", + rng); + } + +std::vector +RTSS_Share::split(uint8_t M, uint8_t N, + const uint8_t S[], uint16_t S_len, + const std::vector& identifier, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + if(M <= 1 || N <= 1 || M > N || N >= 255) + throw Invalid_Argument("RTSS_Share::split: Invalid N or M"); + + if(identifier.size() > 16) + throw Invalid_Argument("RTSS_Share::split Invalid identifier size"); + + const uint8_t hash_id = rtss_hash_id(hash_fn); + + std::unique_ptr hash; + if(hash_id > 0) + hash = HashFunction::create_or_throw(hash_fn); + + // secret = S || H(S) + secure_vector secret(S, S + S_len); + if(hash) + secret += hash->process(S, S_len); + + if(secret.size() >= 0xFFFE) + throw Encoding_Error("RTSS_Share::split secret too large for TSS format"); + + // +1 byte for the share ID + const uint16_t share_len = static_cast(secret.size() + 1); + + secure_vector share_header(RTSS_HEADER_SIZE); + copy_mem(&share_header[0], identifier.data(), identifier.size()); + share_header[16] = hash_id; + share_header[17] = M; + share_header[18] = get_byte(0, share_len); + share_header[19] = get_byte(1, share_len); + + // Create RTSS header in each share + std::vector shares(N); + + for(uint8_t i = 0; i != N; ++i) + { + shares[i].m_contents.reserve(share_header.size() + share_len); + shares[i].m_contents = share_header; + } + + // Choose sequential values for X starting from 1 + for(uint8_t i = 0; i != N; ++i) + shares[i].m_contents.push_back(i+1); + + for(size_t i = 0; i != secret.size(); ++i) + { + std::vector coefficients(M-1); + rng.randomize(coefficients.data(), coefficients.size()); + + for(uint8_t j = 0; j != N; ++j) + { + const uint8_t X = j + 1; + + uint8_t sum = secret[i]; + uint8_t X_i = X; + + for(size_t k = 0; k != coefficients.size(); ++k) + { + sum ^= gfp_mul(X_i, coefficients[k]); + X_i = gfp_mul(X_i, X); + } + + shares[j].m_contents.push_back(sum); + } + } + + return shares; + } + +secure_vector +RTSS_Share::reconstruct(const std::vector& shares) + { + if(shares.size() <= 1) + throw Decoding_Error("Insufficient shares to do TSS reconstruction"); + + for(size_t i = 0; i != shares.size(); ++i) + { + if(shares[i].size() < RTSS_HEADER_SIZE + 1) + throw Decoding_Error("Missing or malformed RTSS header"); + + if(shares[i].share_id() == 0) + throw Decoding_Error("Invalid (id = 0) RTSS share detected"); + + if(i > 0) + { + if(shares[i].size() != shares[0].size()) + throw Decoding_Error("Different sized RTSS shares detected"); + + if(!same_mem(&shares[0].m_contents[0], + &shares[i].m_contents[0], RTSS_HEADER_SIZE)) + throw Decoding_Error("Different RTSS headers detected"); + } + } + + const uint8_t N = shares[0].m_contents[17]; + + if(shares.size() < N) + throw Decoding_Error("Insufficient shares to do TSS reconstruction"); + + const uint16_t share_len = make_uint16(shares[0].m_contents[18], + shares[0].m_contents[19]); + + const uint8_t hash_id = shares[0].m_contents[16]; + std::unique_ptr hash(get_rtss_hash_by_id(hash_id)); + const size_t hash_len = (hash ? hash->output_length() : 0); + + if(shares[0].size() != RTSS_HEADER_SIZE + share_len) + { + /* + * This second (laxer) check accomodates a bug in TSS that was + * fixed in 2.9.0 - previous versions used the length of the + * *secret* here, instead of the length of the *share*, which is + * precisely 1 + hash_len longer. + */ + if(shares[0].size() <= RTSS_HEADER_SIZE + 1 + hash_len) + throw Decoding_Error("Bad RTSS length field in header"); + } + + std::vector V(shares.size()); + secure_vector recovered; + + for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i) + { + for(size_t j = 0; j != V.size(); ++j) + V[j] = shares[j].m_contents[i]; + + uint8_t r = 0; + for(size_t k = 0; k != shares.size(); ++k) + { + // L_i function: + uint8_t r2 = 1; + for(size_t l = 0; l != shares.size(); ++l) + { + if(k == l) + continue; + + uint8_t share_k = shares[k].share_id(); + uint8_t share_l = shares[l].share_id(); + + if(share_k == share_l) + throw Decoding_Error("Duplicate shares found in RTSS recovery"); + + uint8_t div = RTSS_EXP[(255 + + RTSS_LOG[share_l] - + RTSS_LOG[share_k ^ share_l]) % 255]; + + r2 = gfp_mul(r2, div); + } + + r ^= gfp_mul(V[k], r2); + } + recovered.push_back(r); + } + + if(hash) + { + if(recovered.size() < hash->output_length()) + throw Decoding_Error("RTSS recovered value too short to be valid"); + + const size_t secret_len = recovered.size() - hash->output_length(); + + hash->update(recovered.data(), secret_len); + secure_vector hash_check = hash->final(); + + if(!constant_time_compare(hash_check.data(), + &recovered[secret_len], + hash->output_length())) + { + throw Decoding_Error("RTSS hash check failed"); + } + + // remove the trailing hash value + recovered.resize(secret_len); + } + + return recovered; + } + +} diff --git a/comm/third_party/botan/src/lib/misc/tss/tss.h b/comm/third_party/botan/src/lib/misc/tss/tss.h new file mode 100644 index 0000000000..89848c43e6 --- /dev/null +++ b/comm/third_party/botan/src/lib/misc/tss/tss.h @@ -0,0 +1,104 @@ +/* +* RTSS (threshold secret sharing) +* (C) 2009,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RTSS_H_ +#define BOTAN_RTSS_H_ + +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* A split secret, using the format from draft-mcgrew-tss-03 +*/ +class BOTAN_PUBLIC_API(2,0) RTSS_Share final + { + public: + /** + * @param M the number of shares needed to reconstruct + * @param N the number of shares generated + * @param secret the secret to split + * @param secret_len the length of the secret + * @param identifier the 16 byte share identifier + * @param rng the random number generator to use + */ + static std::vector + split(uint8_t M, uint8_t N, + const uint8_t secret[], uint16_t secret_len, + const uint8_t identifier[16], + RandomNumberGenerator& rng); + + /** + * @param M the number of shares needed to reconstruct + * @param N the number of shares generated + * @param secret the secret to split + * @param secret_len the length of the secret + * @param identifier the share identifier + * @param hash_fn the hash function to use for a checksum ("None", "SHA-1", "SHA-256") + * @param rng the random number generator to use + */ + static std::vector + split(uint8_t M, uint8_t N, + const uint8_t secret[], uint16_t secret_len, + const std::vector& identifier, + const std::string& hash_fn, + RandomNumberGenerator& rng); + + /** + * @param shares the list of shares + */ + static secure_vector + reconstruct(const std::vector& shares); + + RTSS_Share() = default; + + /** + * @param hex_input the share encoded in hexadecimal + */ + explicit RTSS_Share(const std::string& hex_input); + + /** + * @param data the shared data + * @param len the length of data + */ + RTSS_Share(const uint8_t data[], size_t len); + + /** + * @return binary representation + */ + const secure_vector& data() const { return m_contents; } + + /** + * @return hex representation + */ + std::string to_string() const; + + /** + * @return share identifier + */ + uint8_t share_id() const; + + /** + * @return size of this share in bytes + */ + size_t size() const { return m_contents.size(); } + + /** + * @return if this TSS share was initialized or not + */ + bool initialized() const { return (m_contents.size() > 0); } + private: + secure_vector m_contents; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/aead.cpp b/comm/third_party/botan/src/lib/modes/aead/aead.cpp new file mode 100644 index 0000000000..9ad550ffd7 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/aead.cpp @@ -0,0 +1,176 @@ +/* +* (C) 2013,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_CCM) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_SIV) + #include +#endif + +namespace Botan { + +void AEAD_Mode::set_associated_data_n(size_t i, const uint8_t ad[], size_t ad_len) + { + if(i == 0) + this->set_associated_data(ad, ad_len); + else + throw Invalid_Argument("AEAD '" + name() + "' does not support multiple associated data"); + } + +std::unique_ptr AEAD_Mode::create_or_throw(const std::string& algo, + Cipher_Dir dir, + const std::string& provider) + { + if(auto aead = AEAD_Mode::create(algo, dir, provider)) + return aead; + + throw Lookup_Error("AEAD", algo, provider); + } + +std::unique_ptr AEAD_Mode::create(const std::string& algo, + Cipher_Dir dir, + const std::string& provider) + { + BOTAN_UNUSED(provider); +#if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) + if(algo == "ChaCha20Poly1305") + { + if(dir == ENCRYPTION) + return std::unique_ptr(new ChaCha20Poly1305_Encryption); + else + return std::unique_ptr(new ChaCha20Poly1305_Decryption); + + } +#endif + + if(algo.find('/') != std::string::npos) + { + const std::vector algo_parts = split_on(algo, '/'); + const std::string cipher_name = algo_parts[0]; + const std::vector mode_info = parse_algorithm_name(algo_parts[1]); + + if(mode_info.empty()) + return std::unique_ptr(); + + std::ostringstream alg_args; + + alg_args << '(' << cipher_name; + for(size_t i = 1; i < mode_info.size(); ++i) + alg_args << ',' << mode_info[i]; + for(size_t i = 2; i < algo_parts.size(); ++i) + alg_args << ',' << algo_parts[i]; + alg_args << ')'; + + const std::string mode_name = mode_info[0] + alg_args.str(); + return AEAD_Mode::create(mode_name, dir); + } + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + + SCAN_Name req(algo); + + if(req.arg_count() == 0) + { + return std::unique_ptr(); + } + + std::unique_ptr bc(BlockCipher::create(req.arg(0), provider)); + + if(!bc) + { + return std::unique_ptr(); + } + +#if defined(BOTAN_HAS_AEAD_CCM) + if(req.algo_name() == "CCM") + { + size_t tag_len = req.arg_as_integer(1, 16); + size_t L_len = req.arg_as_integer(2, 3); + if(dir == ENCRYPTION) + return std::unique_ptr(new CCM_Encryption(bc.release(), tag_len, L_len)); + else + return std::unique_ptr(new CCM_Decryption(bc.release(), tag_len, L_len)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + if(req.algo_name() == "GCM") + { + size_t tag_len = req.arg_as_integer(1, 16); + if(dir == ENCRYPTION) + return std::unique_ptr(new GCM_Encryption(bc.release(), tag_len)); + else + return std::unique_ptr(new GCM_Decryption(bc.release(), tag_len)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + if(req.algo_name() == "OCB") + { + size_t tag_len = req.arg_as_integer(1, 16); + if(dir == ENCRYPTION) + return std::unique_ptr(new OCB_Encryption(bc.release(), tag_len)); + else + return std::unique_ptr(new OCB_Decryption(bc.release(), tag_len)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + if(req.algo_name() == "EAX") + { + size_t tag_len = req.arg_as_integer(1, bc->block_size()); + if(dir == ENCRYPTION) + return std::unique_ptr(new EAX_Encryption(bc.release(), tag_len)); + else + return std::unique_ptr(new EAX_Decryption(bc.release(), tag_len)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_SIV) + if(req.algo_name() == "SIV") + { + if(dir == ENCRYPTION) + return std::unique_ptr(new SIV_Encryption(bc.release())); + else + return std::unique_ptr(new SIV_Decryption(bc.release())); + } +#endif + +#endif + + return std::unique_ptr(); + } + + + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/aead.h b/comm/third_party/botan/src/lib/modes/aead/aead.h new file mode 100644 index 0000000000..442eb8ed7f --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/aead.h @@ -0,0 +1,147 @@ +/* +* Interface for AEAD modes +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_MODE_H_ +#define BOTAN_AEAD_MODE_H_ + +#include + +namespace Botan { + +/** +* Interface for AEAD (Authenticated Encryption with Associated Data) +* modes. These modes provide both encryption and message +* authentication, and can authenticate additional per-message data +* which is not included in the ciphertext (for instance a sequence +* number). +*/ +class BOTAN_PUBLIC_API(2,0) AEAD_Mode : public Cipher_Mode + { + public: + /** + * Create an AEAD mode + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode or a null pointer if not available + */ + static std::unique_ptr create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /** + * Create an AEAD mode, or throw + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode, or throw an exception + */ + static std::unique_ptr create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + bool authenticated() const override { return true; } + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key and + * before start. + * + * Unless reset by another call, the associated data is kept + * between messages. Thus, if the AD does not change, calling + * once (after set_key) is the optimum. + * + * @param ad the associated data + * @param ad_len length of add in bytes + */ + virtual void set_associated_data(const uint8_t ad[], size_t ad_len) = 0; + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key and + * before start. + * + * Unless reset by another call, the associated data is kept + * between messages. Thus, if the AD does not change, calling + * once (after set_key) is the optimum. + * + * Some AEADs (namely SIV) support multiple AD inputs. For + * all other modes only nominal AD input 0 is supported; all + * other values of i will cause an exception. + * + * @param ad the associated data + * @param ad_len length of add in bytes + */ + virtual void set_associated_data_n(size_t i, const uint8_t ad[], size_t ad_len); + + /** + * Returns the maximum supported number of associated data inputs which + * can be provided to set_associated_data_n + * + * If returns 0, then no associated data is supported. + */ + virtual size_t maximum_associated_data_inputs() const { return 1; } + + /** + * Most AEADs require the key to be set prior to setting the AD + * A few allow the AD to be set even before the cipher is keyed. + * Such ciphers would return false from this function. + */ + virtual bool associated_data_requires_key() const { return true; } + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key and + * before start. + * + * See @ref set_associated_data(). + * + * @param ad the associated data + */ + template + void set_associated_data_vec(const std::vector& ad) + { + set_associated_data(ad.data(), ad.size()); + } + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key and + * before start. + * + * See @ref set_associated_data(). + * + * @param ad the associated data + */ + template + void set_ad(const std::vector& ad) + { + set_associated_data(ad.data(), ad.size()); + } + + /** + * @return default AEAD nonce size (a commonly supported value among AEAD + * modes, and large enough that random collisions are unlikely) + */ + size_t default_nonce_length() const override { return 12; } + + virtual ~AEAD_Mode() = default; + }; + +/** +* Get an AEAD mode by name (eg "AES-128/GCM" or "Serpent/EAX") +* @param name AEAD name +* @param direction ENCRYPTION or DECRYPTION +*/ +inline AEAD_Mode* get_aead(const std::string& name, Cipher_Dir direction) + { + return AEAD_Mode::create(name, direction, "").release(); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/ccm/ccm.cpp b/comm/third_party/botan/src/lib/modes/aead/ccm/ccm.cpp new file mode 100644 index 0000000000..ab2cfcb950 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/ccm/ccm.cpp @@ -0,0 +1,279 @@ +/* +* CCM Mode Encryption +* (C) 2013,2018 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +// 128-bit cipher is intrinsic to CCM definition +static const size_t CCM_BS = 16; + +/* +* CCM_Mode Constructor +*/ +CCM_Mode::CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L) : + m_tag_size(tag_size), + m_L(L), + m_cipher(cipher) + { + if(m_cipher->block_size() != CCM_BS) + throw Invalid_Argument(m_cipher->name() + " cannot be used with CCM mode"); + + if(L < 2 || L > 8) + throw Invalid_Argument("Invalid CCM L value " + std::to_string(L)); + + if(tag_size < 4 || tag_size > 16 || tag_size % 2 != 0) + throw Invalid_Argument("invalid CCM tag length " + std::to_string(tag_size)); + } + +void CCM_Mode::clear() + { + m_cipher->clear(); + reset(); + } + +void CCM_Mode::reset() + { + m_nonce.clear(); + m_msg_buf.clear(); + m_ad_buf.clear(); + } + +std::string CCM_Mode::name() const + { + return (m_cipher->name() + "/CCM(" + std::to_string(tag_size()) + "," + std::to_string(L())) + ")"; + } + +bool CCM_Mode::valid_nonce_length(size_t n) const + { + return (n == (15-L())); + } + +size_t CCM_Mode::default_nonce_length() const + { + return (15-L()); + } + +size_t CCM_Mode::update_granularity() const + { + /* + This value does not particularly matter as regardless CCM_Mode::update + buffers all input, so in theory this could be 1. However as for instance + Transform_Filter creates update_granularity() uint8_t buffers, use a + somewhat large size to avoid bouncing on a tiny buffer. + */ + return m_cipher->parallel_bytes(); + } + +Key_Length_Specification CCM_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +void CCM_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + } + +void CCM_Mode::set_associated_data(const uint8_t ad[], size_t length) + { + m_ad_buf.clear(); + + if(length) + { + // FIXME: support larger AD using length encoding rules + BOTAN_ARG_CHECK(length < (0xFFFF - 0xFF), "Supported CCM AD length"); + + m_ad_buf.push_back(get_byte(0, static_cast(length))); + m_ad_buf.push_back(get_byte(1, static_cast(length))); + m_ad_buf += std::make_pair(ad, length); + while(m_ad_buf.size() % CCM_BS) + m_ad_buf.push_back(0); // pad with zeros to full block size + } + } + +void CCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_nonce.assign(nonce, nonce + nonce_len); + m_msg_buf.clear(); + } + +size_t CCM_Mode::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(m_nonce.size() > 0); + m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz); + return 0; // no output until finished + } + +void CCM_Mode::encode_length(uint64_t len, uint8_t out[]) + { + const size_t len_bytes = L(); + + BOTAN_ASSERT_NOMSG(len_bytes >= 2 && len_bytes <= 8); + + for(size_t i = 0; i != len_bytes; ++i) + out[len_bytes-1-i] = get_byte(sizeof(uint64_t)-1-i, len); + + if(len_bytes < 8 && (len >> (len_bytes*8)) > 0) + throw Encoding_Error("CCM message length too long to encode in L field"); + } + +void CCM_Mode::inc(secure_vector& C) + { + for(size_t i = 0; i != C.size(); ++i) + if(++C[C.size()-i-1]) + break; + } + +secure_vector CCM_Mode::format_b0(size_t sz) + { + if(m_nonce.size() != 15-L()) + throw Invalid_State("CCM mode must set nonce"); + secure_vector B0(CCM_BS); + + const uint8_t b_flags = + static_cast((m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1)); + + B0[0] = b_flags; + copy_mem(&B0[1], m_nonce.data(), m_nonce.size()); + encode_length(sz, &B0[m_nonce.size()+1]); + + return B0; + } + +secure_vector CCM_Mode::format_c0() + { + if(m_nonce.size() != 15-L()) + throw Invalid_State("CCM mode must set nonce"); + secure_vector C(CCM_BS); + + const uint8_t a_flags = static_cast(L() - 1); + + C[0] = a_flags; + copy_mem(&C[1], m_nonce.data(), m_nonce.size()); + + return C; + } + +void CCM_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + const secure_vector& ad = ad_buf(); + BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple"); + + const BlockCipher& E = cipher(); + + secure_vector T(CCM_BS); + E.encrypt(format_b0(sz), T); + + for(size_t i = 0; i != ad.size(); i += CCM_BS) + { + xor_buf(T.data(), &ad[i], CCM_BS); + E.encrypt(T); + } + + secure_vector C = format_c0(); + secure_vector S0(CCM_BS); + E.encrypt(C, S0); + inc(C); + + secure_vector X(CCM_BS); + + const uint8_t* buf_end = &buf[sz]; + + while(buf != buf_end) + { + const size_t to_proc = std::min(CCM_BS, buf_end - buf); + + xor_buf(T.data(), buf, to_proc); + E.encrypt(T); + + E.encrypt(C, X); + xor_buf(buf, X.data(), to_proc); + inc(C); + + buf += to_proc; + } + + T ^= S0; + + buffer += std::make_pair(T.data(), tag_size()); + + reset(); + } + +void CCM_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); + + const secure_vector& ad = ad_buf(); + BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple"); + + const BlockCipher& E = cipher(); + + secure_vector T(CCM_BS); + E.encrypt(format_b0(sz - tag_size()), T); + + for(size_t i = 0; i != ad.size(); i += CCM_BS) + { + xor_buf(T.data(), &ad[i], CCM_BS); + E.encrypt(T); + } + + secure_vector C = format_c0(); + + secure_vector S0(CCM_BS); + E.encrypt(C, S0); + inc(C); + + secure_vector X(CCM_BS); + + const uint8_t* buf_end = &buf[sz - tag_size()]; + + while(buf != buf_end) + { + const size_t to_proc = std::min(CCM_BS, buf_end - buf); + + E.encrypt(C, X); + xor_buf(buf, X.data(), to_proc); + inc(C); + + xor_buf(T.data(), buf, to_proc); + E.encrypt(T); + + buf += to_proc; + } + + T ^= S0; + + if(!constant_time_compare(T.data(), buf_end, tag_size())) + throw Invalid_Authentication_Tag("CCM tag check failed"); + + buffer.resize(buffer.size() - tag_size()); + + reset(); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/ccm/ccm.h b/comm/third_party/botan/src/lib/modes/aead/ccm/ccm.h new file mode 100644 index 0000000000..9b4bcecbf2 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/ccm/ccm.h @@ -0,0 +1,130 @@ +/* +* CCM Mode +* (C) 2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_CCM_H_ +#define BOTAN_AEAD_CCM_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(ccm.h) + +namespace Botan { + +/** +* Base class for CCM encryption and decryption +* @see RFC 3610 +*/ +class BOTAN_PUBLIC_API(2,0) CCM_Mode : public AEAD_Mode + { + public: + size_t process(uint8_t buf[], size_t sz) override; + + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + bool associated_data_requires_key() const override { return false; } + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t) const override; + + size_t default_nonce_length() const override; + + void clear() override; + + void reset() override; + + size_t tag_size() const override { return m_tag_size; } + + protected: + CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L); + + size_t L() const { return m_L; } + + const BlockCipher& cipher() const { return *m_cipher; } + + void encode_length(uint64_t len, uint8_t out[]); + + void inc(secure_vector& C); + + const secure_vector& ad_buf() const { return m_ad_buf; } + + secure_vector& msg_buf() { return m_msg_buf; } + + secure_vector format_b0(size_t msg_size); + secure_vector format_c0(); + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + + const size_t m_tag_size; + const size_t m_L; + + std::unique_ptr m_cipher; + secure_vector m_nonce, m_msg_buf, m_ad_buf; + }; + +/** +* CCM Encryption +*/ +class BOTAN_PUBLIC_API(2,0) CCM_Encryption final : public CCM_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be (even values + * between 4 and 16 are accepted) + * @param L length of L parameter. The total message length + * must be less than 2**L bytes, and the nonce is 15-L bytes. + */ + CCM_Encryption(BlockCipher* cipher, size_t tag_size = 16, size_t L = 3) : + CCM_Mode(cipher, tag_size, L) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + }; + +/** +* CCM Decryption +*/ +class BOTAN_PUBLIC_API(2,0) CCM_Decryption final : public CCM_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be (even values + * between 4 and 16 are accepted) + * @param L length of L parameter. The total message length + * must be less than 2**L bytes, and the nonce is 15-L bytes. + */ + CCM_Decryption(BlockCipher* cipher, size_t tag_size = 16, size_t L = 3) : + CCM_Mode(cipher, tag_size, L) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/ccm/info.txt b/comm/third_party/botan/src/lib/modes/aead/ccm/info.txt new file mode 100644 index 0000000000..9341cea7fc --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/ccm/info.txt @@ -0,0 +1,7 @@ + +AEAD_CCM -> 20131128 + + + +block + diff --git a/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp b/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp new file mode 100644 index 0000000000..ca02ca5048 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp @@ -0,0 +1,171 @@ +/* +* ChaCha20Poly1305 AEAD +* (C) 2014,2016,2018 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +ChaCha20Poly1305_Mode::ChaCha20Poly1305_Mode() : + m_chacha(StreamCipher::create("ChaCha")), + m_poly1305(MessageAuthenticationCode::create("Poly1305")) + { + if(!m_chacha || !m_poly1305) + throw Algorithm_Not_Found("ChaCha20Poly1305"); + } + +bool ChaCha20Poly1305_Mode::valid_nonce_length(size_t n) const + { + return (n == 8 || n == 12 || n == 24); + } + +void ChaCha20Poly1305_Mode::clear() + { + m_chacha->clear(); + m_poly1305->clear(); + reset(); + } + +void ChaCha20Poly1305_Mode::reset() + { + m_ad.clear(); + m_ctext_len = 0; + m_nonce_len = 0; + } + +void ChaCha20Poly1305_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_chacha->set_key(key, length); + } + +void ChaCha20Poly1305_Mode::set_associated_data(const uint8_t ad[], size_t length) + { + if(m_ctext_len > 0 || m_nonce_len > 0) + throw Invalid_State("Cannot set AD for ChaCha20Poly1305 while processing a message"); + m_ad.assign(ad, ad + length); + } + +void ChaCha20Poly1305_Mode::update_len(size_t len) + { + uint8_t len8[8] = { 0 }; + store_le(static_cast(len), len8); + m_poly1305->update(len8, 8); + } + +void ChaCha20Poly1305_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_ctext_len = 0; + m_nonce_len = nonce_len; + + m_chacha->set_iv(nonce, nonce_len); + + uint8_t first_block[64]; + m_chacha->write_keystream(first_block, sizeof(first_block)); + + m_poly1305->set_key(first_block, 32); + // Remainder of first block is discarded + secure_scrub_memory(first_block, sizeof(first_block)); + + m_poly1305->update(m_ad); + + if(cfrg_version()) + { + if(m_ad.size() % 16) + { + const uint8_t zeros[16] = { 0 }; + m_poly1305->update(zeros, 16 - m_ad.size() % 16); + } + } + else + { + update_len(m_ad.size()); + } + } + +size_t ChaCha20Poly1305_Encryption::process(uint8_t buf[], size_t sz) + { + m_chacha->cipher1(buf, sz); + m_poly1305->update(buf, sz); // poly1305 of ciphertext + m_ctext_len += sz; + return sz; + } + +void ChaCha20Poly1305_Encryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + if(cfrg_version()) + { + if(m_ctext_len % 16) + { + const uint8_t zeros[16] = { 0 }; + m_poly1305->update(zeros, 16 - m_ctext_len % 16); + } + update_len(m_ad.size()); + } + update_len(m_ctext_len); + + buffer.resize(buffer.size() + tag_size()); + m_poly1305->final(&buffer[buffer.size() - tag_size()]); + m_ctext_len = 0; + m_nonce_len = 0; + } + +size_t ChaCha20Poly1305_Decryption::process(uint8_t buf[], size_t sz) + { + m_poly1305->update(buf, sz); // poly1305 of ciphertext + m_chacha->cipher1(buf, sz); + m_ctext_len += sz; + return sz; + } + +void ChaCha20Poly1305_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); + + const size_t remaining = sz - tag_size(); + + if(remaining) + { + m_poly1305->update(buf, remaining); // poly1305 of ciphertext + m_chacha->cipher1(buf, remaining); + m_ctext_len += remaining; + } + + if(cfrg_version()) + { + if(m_ctext_len % 16) + { + const uint8_t zeros[16] = { 0 }; + m_poly1305->update(zeros, 16 - m_ctext_len % 16); + } + update_len(m_ad.size()); + } + + update_len(m_ctext_len); + + uint8_t mac[16]; + m_poly1305->final(mac); + + const uint8_t* included_tag = &buf[remaining]; + + m_ctext_len = 0; + m_nonce_len = 0; + + if(!constant_time_compare(mac, included_tag, tag_size())) + throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed"); + buffer.resize(offset + remaining); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h b/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h new file mode 100644 index 0000000000..dbba58cc93 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h @@ -0,0 +1,104 @@ +/* +* ChaCha20Poly1305 AEAD +* (C) 2014 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_CHACHA20_POLY1305_H_ +#define BOTAN_AEAD_CHACHA20_POLY1305_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(chacha20poly1305.h) + +namespace Botan { + +/** +* Base class +* See draft-irtf-cfrg-chacha20-poly1305-03 for specification +* If a nonce of 64 bits is used the older version described in +* draft-agl-tls-chacha20poly1305-04 is used instead. +* If a nonce of 192 bits is used, XChaCha20Poly1305 is selected. +*/ +class BOTAN_PUBLIC_API(2,0) ChaCha20Poly1305_Mode : public AEAD_Mode + { + public: + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + bool associated_data_requires_key() const override { return false; } + + std::string name() const override { return "ChaCha20Poly1305"; } + + size_t update_granularity() const override { return 64; } + + Key_Length_Specification key_spec() const override + { return Key_Length_Specification(32); } + + bool valid_nonce_length(size_t n) const override; + + size_t tag_size() const override { return 16; } + + void clear() override; + + void reset() override; + + protected: + std::unique_ptr m_chacha; + std::unique_ptr m_poly1305; + + ChaCha20Poly1305_Mode(); + + secure_vector m_ad; + size_t m_nonce_len = 0; + size_t m_ctext_len = 0; + + bool cfrg_version() const { return m_nonce_len == 12 || m_nonce_len == 24; } + void update_len(size_t len); + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + }; + +/** +* ChaCha20Poly1305 Encryption +*/ +class BOTAN_PUBLIC_API(2,0) ChaCha20Poly1305_Encryption final : public ChaCha20Poly1305_Mode + { + public: + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* ChaCha20Poly1305 Decryption +*/ +class BOTAN_PUBLIC_API(2,0) ChaCha20Poly1305_Decryption final : public ChaCha20Poly1305_Mode + { + public: + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/info.txt b/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/info.txt new file mode 100644 index 0000000000..c3ea53db09 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/chacha20poly1305/info.txt @@ -0,0 +1,8 @@ + +AEAD_CHACHA20_POLY1305 -> 20180807 + + + +chacha +poly1305 + diff --git a/comm/third_party/botan/src/lib/modes/aead/eax/eax.cpp b/comm/third_party/botan/src/lib/modes/aead/eax/eax.cpp new file mode 100644 index 0000000000..4f6b540ffb --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/eax/eax.cpp @@ -0,0 +1,194 @@ +/* +* EAX Mode Encryption +* (C) 1999-2007 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* EAX MAC-based PRF +*/ +secure_vector eax_prf(uint8_t tag, size_t block_size, + MessageAuthenticationCode& mac, + const uint8_t in[], size_t length) + { + for(size_t i = 0; i != block_size - 1; ++i) + { + mac.update(0); + } + mac.update(tag); + mac.update(in, length); + return mac.final(); + } + +} + +/* +* EAX_Mode Constructor +*/ +EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) : + m_tag_size(tag_size), + m_cipher(cipher), + m_ctr(new CTR_BE(m_cipher->clone())), + m_cmac(new CMAC(m_cipher->clone())) + { + if(m_tag_size < 8 || m_tag_size > m_cmac->output_length()) + throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size)); + } + +void EAX_Mode::clear() + { + m_cipher->clear(); + m_ctr->clear(); + m_cmac->clear(); + reset(); + } + +void EAX_Mode::reset() + { + m_ad_mac.clear(); + m_nonce_mac.clear(); + + // Clear out any data added to the CMAC calculation + try { + m_cmac->final(); + } + catch(Key_Not_Set&) {} + } + +std::string EAX_Mode::name() const + { + return (m_cipher->name() + "/EAX"); + } + +size_t EAX_Mode::update_granularity() const + { + /* + * For EAX this actually can be as low as 1 but that causes problems + * for applications which use update_granularity as the buffer size. + */ + return m_cipher->parallel_bytes(); + } + +Key_Length_Specification EAX_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +/* +* Set the EAX key +*/ +void EAX_Mode::key_schedule(const uint8_t key[], size_t length) + { + /* + * These could share the key schedule, which is one nice part of EAX, + * but it's much easier to ignore that here... + */ + m_ctr->set_key(key, length); + m_cmac->set_key(key, length); + } + +/* +* Set the EAX associated data +*/ +void EAX_Mode::set_associated_data(const uint8_t ad[], size_t length) + { + if(m_nonce_mac.empty() == false) + throw Invalid_State("Cannot set AD for EAX while processing a message"); + m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length); + } + +void EAX_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len); + + m_ctr->set_iv(m_nonce_mac.data(), m_nonce_mac.size()); + + for(size_t i = 0; i != block_size() - 1; ++i) + m_cmac->update(0); + m_cmac->update(2); + } + +size_t EAX_Encryption::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(m_nonce_mac.size() > 0); + m_ctr->cipher(buf, buf, sz); + m_cmac->update(buf, sz); + return sz; + } + +void EAX_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT_NOMSG(m_nonce_mac.empty() == false); + update(buffer, offset); + + secure_vector data_mac = m_cmac->final(); + xor_buf(data_mac, m_nonce_mac, data_mac.size()); + + if(m_ad_mac.empty()) + { + m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); + } + + xor_buf(data_mac, m_ad_mac, data_mac.size()); + + buffer += std::make_pair(data_mac.data(), tag_size()); + } + +size_t EAX_Decryption::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(m_nonce_mac.size() > 0); + m_cmac->update(buf, sz); + m_ctr->cipher(buf, buf, sz); + return sz; + } + +void EAX_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); + + const size_t remaining = sz - tag_size(); + + if(remaining) + { + m_cmac->update(buf, remaining); + m_ctr->cipher(buf, buf, remaining); + } + + const uint8_t* included_tag = &buf[remaining]; + + secure_vector mac = m_cmac->final(); + mac ^= m_nonce_mac; + + if(m_ad_mac.empty()) + { + m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); + } + + mac ^= m_ad_mac; + + if(!constant_time_compare(mac.data(), included_tag, tag_size())) + throw Invalid_Authentication_Tag("EAX tag check failed"); + + buffer.resize(offset + remaining); + + m_nonce_mac.clear(); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/eax/eax.h b/comm/third_party/botan/src/lib/modes/aead/eax/eax.h new file mode 100644 index 0000000000..b9b02c192b --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/eax/eax.h @@ -0,0 +1,119 @@ +/* +* EAX Mode +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_EAX_H_ +#define BOTAN_AEAD_EAX_H_ + +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(eax.h) + +namespace Botan { + +/** +* EAX base class +*/ +class BOTAN_PUBLIC_API(2,0) EAX_Mode : public AEAD_Mode + { + public: + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + // EAX supports arbitrary nonce lengths + bool valid_nonce_length(size_t) const override { return true; } + + size_t tag_size() const override { return m_tag_size; } + + void clear() override; + + void reset() override; + + protected: + /** + * @param cipher the cipher to use + * @param tag_size is how big the auth tag will be + */ + EAX_Mode(BlockCipher* cipher, size_t tag_size); + + size_t block_size() const { return m_cipher->block_size(); } + + size_t m_tag_size; + + std::unique_ptr m_cipher; + std::unique_ptr m_ctr; + std::unique_ptr m_cmac; + + secure_vector m_ad_mac; + + secure_vector m_nonce_mac; + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + }; + +/** +* EAX Encryption +*/ +class BOTAN_PUBLIC_API(2,0) EAX_Encryption final : public EAX_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be + */ + EAX_Encryption(BlockCipher* cipher, size_t tag_size = 0) : + EAX_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* EAX Decryption +*/ +class BOTAN_PUBLIC_API(2,0) EAX_Decryption final : public EAX_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be + */ + EAX_Decryption(BlockCipher* cipher, size_t tag_size = 0) : + EAX_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/eax/info.txt b/comm/third_party/botan/src/lib/modes/aead/eax/info.txt new file mode 100644 index 0000000000..6bc01ff704 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/eax/info.txt @@ -0,0 +1,8 @@ + +AEAD_EAX -> 20131128 + + + +cmac +ctr + diff --git a/comm/third_party/botan/src/lib/modes/aead/gcm/gcm.cpp b/comm/third_party/botan/src/lib/modes/aead/gcm/gcm.cpp new file mode 100644 index 0000000000..4b9c5b7204 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/gcm/gcm.cpp @@ -0,0 +1,179 @@ +/* +* GCM Mode Encryption +* (C) 2013,2015 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* GCM_Mode Constructor +*/ +GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) : + m_tag_size(tag_size), + m_cipher_name(cipher->name()), + m_ctr(new CTR_BE(cipher, 4)), + m_ghash(new GHASH) + { + if(cipher->block_size() != GCM_BS) + throw Invalid_Argument("Invalid block cipher for GCM"); + + /* We allow any of the values 128, 120, 112, 104, or 96 bits as a tag size */ + /* 64 bit tag is still supported but deprecated and will be removed in the future */ + if(m_tag_size != 8 && (m_tag_size < 12 || m_tag_size > 16)) + throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size)); + } + +GCM_Mode::~GCM_Mode() { /* for unique_ptr */ } + +void GCM_Mode::clear() + { + m_ctr->clear(); + m_ghash->clear(); + reset(); + } + +void GCM_Mode::reset() + { + m_ghash->reset(); + } + +std::string GCM_Mode::name() const + { + return (m_cipher_name + "/GCM(" + std::to_string(tag_size()) + ")"); + } + +std::string GCM_Mode::provider() const + { + return m_ghash->provider(); + } + +size_t GCM_Mode::update_granularity() const + { + return GCM_BS * std::max(2, BOTAN_BLOCK_CIPHER_PAR_MULT); + } + +bool GCM_Mode::valid_nonce_length(size_t len) const + { + // GCM does not support empty nonces + return (len > 0); + } + +Key_Length_Specification GCM_Mode::key_spec() const + { + return m_ctr->key_spec(); + } + +void GCM_Mode::key_schedule(const uint8_t key[], size_t keylen) + { + m_ctr->set_key(key, keylen); + + const std::vector zeros(GCM_BS); + m_ctr->set_iv(zeros.data(), zeros.size()); + + secure_vector H(GCM_BS); + m_ctr->encipher(H); + m_ghash->set_key(H); + } + +void GCM_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) + { + m_ghash->set_associated_data(ad, ad_len); + } + +void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + if(m_y0.size() != GCM_BS) + m_y0.resize(GCM_BS); + + clear_mem(m_y0.data(), m_y0.size()); + + if(nonce_len == 12) + { + copy_mem(m_y0.data(), nonce, nonce_len); + m_y0[15] = 1; + } + else + { + m_ghash->nonce_hash(m_y0, nonce, nonce_len); + } + + m_ctr->set_iv(m_y0.data(), m_y0.size()); + + clear_mem(m_y0.data(), m_y0.size()); + m_ctr->encipher(m_y0); + + m_ghash->start(m_y0.data(), m_y0.size()); + clear_mem(m_y0.data(), m_y0.size()); + } + +size_t GCM_Encryption::process(uint8_t buf[], size_t sz) + { + BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size"); + m_ctr->cipher(buf, buf, sz); + m_ghash->update(buf, sz); + return sz; + } + +void GCM_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + m_ctr->cipher(buf, buf, sz); + m_ghash->update(buf, sz); + + uint8_t mac[16] = { 0 }; + m_ghash->final(mac, tag_size()); + buffer += std::make_pair(mac, tag_size()); + } + +size_t GCM_Decryption::process(uint8_t buf[], size_t sz) + { + BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size"); + m_ghash->update(buf, sz); + m_ctr->cipher(buf, buf, sz); + return sz; + } + +void GCM_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + if(sz < tag_size()) + throw Decoding_Error("Insufficient input for GCM decryption, tag missing"); + + const size_t remaining = sz - tag_size(); + + // handle any final input before the tag + if(remaining) + { + m_ghash->update(buf, remaining); + m_ctr->cipher(buf, buf, remaining); + } + + uint8_t mac[16] = { 0 }; + m_ghash->final(mac, tag_size()); + + const uint8_t* included_tag = &buffer[remaining+offset]; + + if(!constant_time_compare(mac, included_tag, tag_size())) + throw Invalid_Authentication_Tag("GCM tag check failed"); + + buffer.resize(offset + remaining); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/gcm/gcm.h b/comm/third_party/botan/src/lib/modes/aead/gcm/gcm.h new file mode 100644 index 0000000000..fe3c405721 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/gcm/gcm.h @@ -0,0 +1,117 @@ +/* +* GCM Mode +* (C) 2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_GCM_H_ +#define BOTAN_AEAD_GCM_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(gcm.h) + +namespace Botan { + +class BlockCipher; +class StreamCipher; +class GHASH; + +/** +* GCM Mode +*/ +class BOTAN_PUBLIC_API(2,0) GCM_Mode : public AEAD_Mode + { + public: + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t len) const override; + + size_t tag_size() const override { return m_tag_size; } + + void clear() override; + + void reset() override; + + std::string provider() const override; + protected: + GCM_Mode(BlockCipher* cipher, size_t tag_size); + + ~GCM_Mode(); + + static const size_t GCM_BS = 16; + + const size_t m_tag_size; + const std::string m_cipher_name; + + std::unique_ptr m_ctr; + std::unique_ptr m_ghash; + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector m_y0; + }; + +/** +* GCM Encryption +*/ +class BOTAN_PUBLIC_API(2,0) GCM_Encryption final : public GCM_Mode + { + public: + /** + * @param cipher the 128 bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + GCM_Encryption(BlockCipher* cipher, size_t tag_size = 16) : + GCM_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* GCM Decryption +*/ +class BOTAN_PUBLIC_API(2,0) GCM_Decryption final : public GCM_Mode + { + public: + /** + * @param cipher the 128 bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + GCM_Decryption(BlockCipher* cipher, size_t tag_size = 16) : + GCM_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/gcm/info.txt b/comm/third_party/botan/src/lib/modes/aead/gcm/info.txt new file mode 100644 index 0000000000..94eb09ab64 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/gcm/info.txt @@ -0,0 +1,9 @@ + +AEAD_GCM -> 20131128 + + + +block +ctr +ghash + diff --git a/comm/third_party/botan/src/lib/modes/aead/info.txt b/comm/third_party/botan/src/lib/modes/aead/info.txt new file mode 100644 index 0000000000..15106e46ab --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/info.txt @@ -0,0 +1,3 @@ + +AEAD_MODES -> 20131128 + diff --git a/comm/third_party/botan/src/lib/modes/aead/ocb/info.txt b/comm/third_party/botan/src/lib/modes/aead/ocb/info.txt new file mode 100644 index 0000000000..4e16e23624 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/ocb/info.txt @@ -0,0 +1,8 @@ + +AEAD_OCB -> 20131128 + + + +block +poly_dbl + diff --git a/comm/third_party/botan/src/lib/modes/aead/ocb/ocb.cpp b/comm/third_party/botan/src/lib/modes/aead/ocb/ocb.cpp new file mode 100644 index 0000000000..6c16203296 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/ocb/ocb.cpp @@ -0,0 +1,533 @@ +/* +* OCB Mode +* (C) 2013,2017 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +// Has to be in Botan namespace so unique_ptr can reference it +class L_computer final + { + public: + explicit L_computer(const BlockCipher& cipher) : + m_BS(cipher.block_size()), + m_max_blocks(cipher.parallel_bytes() / m_BS) + { + m_L_star.resize(m_BS); + cipher.encrypt(m_L_star); + m_L_dollar = poly_double(star()); + m_L.push_back(poly_double(dollar())); + + while(m_L.size() < 8) + m_L.push_back(poly_double(m_L.back())); + + m_offset_buf.resize(m_BS * m_max_blocks); + } + + void init(const secure_vector& offset) + { + m_offset = offset; + } + + bool initialized() const { return m_offset.empty() == false; } + + const secure_vector& star() const { return m_L_star; } + const secure_vector& dollar() const { return m_L_dollar; } + const secure_vector& offset() const { return m_offset; } + + const secure_vector& get(size_t i) const + { + while(m_L.size() <= i) + m_L.push_back(poly_double(m_L.back())); + + return m_L[i]; + } + + const uint8_t* + compute_offsets(size_t block_index, size_t blocks) + { + BOTAN_ASSERT(blocks <= m_max_blocks, "OCB offsets"); + + uint8_t* offsets = m_offset_buf.data(); + + if(block_index % 4 == 0) + { + const secure_vector& L0 = get(0); + const secure_vector& L1 = get(1); + + while(blocks >= 4) + { + // ntz(4*i+1) == 0 + // ntz(4*i+2) == 1 + // ntz(4*i+3) == 0 + block_index += 4; + const size_t ntz4 = var_ctz32(static_cast(block_index)); + + xor_buf(offsets, m_offset.data(), L0.data(), m_BS); + offsets += m_BS; + + xor_buf(offsets, offsets - m_BS, L1.data(), m_BS); + offsets += m_BS; + + xor_buf(m_offset.data(), L1.data(), m_BS); + copy_mem(offsets, m_offset.data(), m_BS); + offsets += m_BS; + + xor_buf(m_offset.data(), get(ntz4).data(), m_BS); + copy_mem(offsets, m_offset.data(), m_BS); + offsets += m_BS; + + blocks -= 4; + } + } + + for(size_t i = 0; i != blocks; ++i) + { // could be done in parallel + const size_t ntz = var_ctz32(static_cast(block_index + i + 1)); + xor_buf(m_offset.data(), get(ntz).data(), m_BS); + copy_mem(offsets, m_offset.data(), m_BS); + offsets += m_BS; + } + + return m_offset_buf.data(); + } + + private: + secure_vector poly_double(const secure_vector& in) const + { + secure_vector out(in.size()); + poly_double_n(out.data(), in.data(), out.size()); + return out; + } + + const size_t m_BS, m_max_blocks; + secure_vector m_L_dollar, m_L_star; + secure_vector m_offset; + mutable std::vector> m_L; + secure_vector m_offset_buf; + }; + +namespace { + +/* +* OCB's HASH +*/ +secure_vector ocb_hash(const L_computer& L, + const BlockCipher& cipher, + const uint8_t ad[], size_t ad_len) + { + const size_t BS = cipher.block_size(); + secure_vector sum(BS); + secure_vector offset(BS); + + secure_vector buf(BS); + + const size_t ad_blocks = (ad_len / BS); + const size_t ad_remainder = (ad_len % BS); + + for(size_t i = 0; i != ad_blocks; ++i) + { + // this loop could run in parallel + offset ^= L.get(var_ctz32(static_cast(i+1))); + buf = offset; + xor_buf(buf.data(), &ad[BS*i], BS); + cipher.encrypt(buf); + sum ^= buf; + } + + if(ad_remainder) + { + offset ^= L.star(); + buf = offset; + xor_buf(buf.data(), &ad[BS*ad_blocks], ad_remainder); + buf[ad_remainder] ^= 0x80; + cipher.encrypt(buf); + sum ^= buf; + } + + return sum; + } + +} + +OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) : + m_cipher(cipher), + m_checksum(m_cipher->parallel_bytes()), + m_ad_hash(m_cipher->block_size()), + m_tag_size(tag_size), + m_block_size(m_cipher->block_size()), + m_par_blocks(m_cipher->parallel_bytes() / m_block_size) + { + const size_t BS = block_size(); + + /* + * draft-krovetz-ocb-wide-d1 specifies OCB for several other block + * sizes but only 128, 192, 256 and 512 bit are currently supported + * by this implementation. + */ + BOTAN_ARG_CHECK(BS == 16 || BS == 24 || BS == 32 || BS == 64, + "Invalid block size for OCB"); + + BOTAN_ARG_CHECK(m_tag_size % 4 == 0 && + m_tag_size >= 8 && m_tag_size <= BS && + m_tag_size <= 32, + "Invalid OCB tag length"); + } + +OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ } + +void OCB_Mode::clear() + { + m_cipher->clear(); + m_L.reset(); // add clear here? + reset(); + } + +void OCB_Mode::reset() + { + m_block_index = 0; + zeroise(m_ad_hash); + zeroise(m_checksum); + m_last_nonce.clear(); + m_stretch.clear(); + } + +bool OCB_Mode::valid_nonce_length(size_t length) const + { + if(length == 0) + return false; + if(block_size() == 16) + return length < 16; + else + return length < (block_size() - 1); + } + +std::string OCB_Mode::name() const + { + return m_cipher->name() + "/OCB"; // include tag size? + } + +size_t OCB_Mode::update_granularity() const + { + return (m_par_blocks * block_size()); + } + +Key_Length_Specification OCB_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +void OCB_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + m_L.reset(new L_computer(*m_cipher)); + } + +void OCB_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) + { + verify_key_set(m_L != nullptr); + m_ad_hash = ocb_hash(*m_L, *m_cipher, ad, ad_len); + } + +const secure_vector& +OCB_Mode::update_nonce(const uint8_t nonce[], size_t nonce_len) + { + const size_t BS = block_size(); + + BOTAN_ASSERT(BS == 16 || BS == 24 || BS == 32 || BS == 64, + "OCB block size is supported"); + + const size_t MASKLEN = (BS == 16 ? 6 : ((BS == 24) ? 7 : 8)); + + const uint8_t BOTTOM_MASK = + static_cast((static_cast(1) << MASKLEN) - 1); + + m_nonce_buf.resize(BS); + clear_mem(&m_nonce_buf[0], m_nonce_buf.size()); + + copy_mem(&m_nonce_buf[BS - nonce_len], nonce, nonce_len); + m_nonce_buf[0] = static_cast(((tag_size()*8) % (BS*8)) << (BS <= 16 ? 1 : 0)); + + m_nonce_buf[BS - nonce_len - 1] ^= 1; + + const uint8_t bottom = m_nonce_buf[BS-1] & BOTTOM_MASK; + m_nonce_buf[BS-1] &= ~BOTTOM_MASK; + + const bool need_new_stretch = (m_last_nonce != m_nonce_buf); + + if(need_new_stretch) + { + m_last_nonce = m_nonce_buf; + + m_cipher->encrypt(m_nonce_buf); + + /* + The loop bounds (BS vs BS/2) are derived from the relation + between the block size and the MASKLEN. Using the terminology + of draft-krovetz-ocb-wide, we have to derive enough bits in + ShiftedKtop to read up to BLOCKLEN+bottom bits from Stretch. + + +----------+---------+-------+---------+ + | BLOCKLEN | RESIDUE | SHIFT | MASKLEN | + +----------+---------+-------+---------+ + | 32 | 141 | 17 | 4 | + | 64 | 27 | 25 | 5 | + | 96 | 1601 | 33 | 6 | + | 128 | 135 | 8 | 6 | + | 192 | 135 | 40 | 7 | + | 256 | 1061 | 1 | 8 | + | 384 | 4109 | 80 | 8 | + | 512 | 293 | 176 | 8 | + | 1024 | 524355 | 352 | 9 | + +----------+---------+-------+---------+ + */ + if(BS == 16) + { + for(size_t i = 0; i != BS / 2; ++i) + m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+1]); + } + else if(BS == 24) + { + for(size_t i = 0; i != 16; ++i) + m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+5]); + } + else if(BS == 32) + { + for(size_t i = 0; i != BS; ++i) + m_nonce_buf.push_back(m_nonce_buf[i] ^ (m_nonce_buf[i] << 1) ^ (m_nonce_buf[i+1] >> 7)); + } + else if(BS == 64) + { + for(size_t i = 0; i != BS / 2; ++i) + m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+22]); + } + + m_stretch = m_nonce_buf; + } + + // now set the offset from stretch and bottom + const size_t shift_bytes = bottom / 8; + const size_t shift_bits = bottom % 8; + + BOTAN_ASSERT(m_stretch.size() >= BS + shift_bytes + 1, "Size ok"); + + m_offset.resize(BS); + for(size_t i = 0; i != BS; ++i) + { + m_offset[i] = (m_stretch[i+shift_bytes] << shift_bits); + m_offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits)); + } + + return m_offset; + } + +void OCB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + verify_key_set(m_L != nullptr); + + m_L->init(update_nonce(nonce, nonce_len)); + zeroise(m_checksum); + m_block_index = 0; + } + +void OCB_Encryption::encrypt(uint8_t buffer[], size_t blocks) + { + verify_key_set(m_L != nullptr); + BOTAN_STATE_CHECK(m_L->initialized()); + + const size_t BS = block_size(); + + while(blocks) + { + const size_t proc_blocks = std::min(blocks, par_blocks()); + const size_t proc_bytes = proc_blocks * BS; + + const uint8_t* offsets = m_L->compute_offsets(m_block_index, proc_blocks); + + xor_buf(m_checksum.data(), buffer, proc_bytes); + + m_cipher->encrypt_n_xex(buffer, offsets, proc_blocks); + + buffer += proc_bytes; + blocks -= proc_blocks; + m_block_index += proc_blocks; + } + } + +size_t OCB_Encryption::process(uint8_t buf[], size_t sz) + { + BOTAN_ASSERT(sz % update_granularity() == 0, "Invalid OCB input size"); + encrypt(buf, sz / block_size()); + return sz; + } + +void OCB_Encryption::finish(secure_vector& buffer, size_t offset) + { + verify_key_set(m_L != nullptr); + + const size_t BS = block_size(); + + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + secure_vector mac(BS); + + if(sz) + { + const size_t final_full_blocks = sz / BS; + const size_t remainder_bytes = sz - (final_full_blocks * BS); + + encrypt(buf, final_full_blocks); + mac = m_L->offset(); + + if(remainder_bytes) + { + BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left"); + uint8_t* remainder = &buf[sz - remainder_bytes]; + + xor_buf(m_checksum.data(), remainder, remainder_bytes); + m_checksum[remainder_bytes] ^= 0x80; + + // Offset_* + mac ^= m_L->star(); + + secure_vector pad(BS); + m_cipher->encrypt(mac, pad); + xor_buf(remainder, pad.data(), remainder_bytes); + } + } + else + { + mac = m_L->offset(); + } + + // now compute the tag + + // fold checksum + for(size_t i = 0; i != m_checksum.size(); i += BS) + { + xor_buf(mac.data(), m_checksum.data() + i, BS); + } + + xor_buf(mac.data(), m_L->dollar().data(), BS); + m_cipher->encrypt(mac); + xor_buf(mac.data(), m_ad_hash.data(), BS); + + buffer += std::make_pair(mac.data(), tag_size()); + + zeroise(m_checksum); + m_block_index = 0; + } + +void OCB_Decryption::decrypt(uint8_t buffer[], size_t blocks) + { + verify_key_set(m_L != nullptr); + BOTAN_STATE_CHECK(m_L->initialized()); + + const size_t BS = block_size(); + + while(blocks) + { + const size_t proc_blocks = std::min(blocks, par_blocks()); + const size_t proc_bytes = proc_blocks * BS; + + const uint8_t* offsets = m_L->compute_offsets(m_block_index, proc_blocks); + + m_cipher->decrypt_n_xex(buffer, offsets, proc_blocks); + + xor_buf(m_checksum.data(), buffer, proc_bytes); + + buffer += proc_bytes; + blocks -= proc_blocks; + m_block_index += proc_blocks; + } + } + +size_t OCB_Decryption::process(uint8_t buf[], size_t sz) + { + BOTAN_ASSERT(sz % update_granularity() == 0, "Invalid OCB input size"); + decrypt(buf, sz / block_size()); + return sz; + } + +void OCB_Decryption::finish(secure_vector& buffer, size_t offset) + { + verify_key_set(m_L != nullptr); + + const size_t BS = block_size(); + + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); + + const size_t remaining = sz - tag_size(); + + secure_vector mac(BS); + + if(remaining) + { + const size_t final_full_blocks = remaining / BS; + const size_t final_bytes = remaining - (final_full_blocks * BS); + + decrypt(buf, final_full_blocks); + mac ^= m_L->offset(); + + if(final_bytes) + { + BOTAN_ASSERT(final_bytes < BS, "Only a partial block left"); + + uint8_t* remainder = &buf[remaining - final_bytes]; + + mac ^= m_L->star(); + secure_vector pad(BS); + m_cipher->encrypt(mac, pad); // P_* + xor_buf(remainder, pad.data(), final_bytes); + + xor_buf(m_checksum.data(), remainder, final_bytes); + m_checksum[final_bytes] ^= 0x80; + } + } + else + mac = m_L->offset(); + + // compute the mac + + // fold checksum + for(size_t i = 0; i != m_checksum.size(); i += BS) + { + xor_buf(mac.data(), m_checksum.data() + i, BS); + } + + mac ^= m_L->dollar(); + m_cipher->encrypt(mac); + mac ^= m_ad_hash; + + // reset state + zeroise(m_checksum); + m_block_index = 0; + + // compare mac + const uint8_t* included_tag = &buf[remaining]; + + if(!constant_time_compare(mac.data(), included_tag, tag_size())) + throw Invalid_Authentication_Tag("OCB tag check failed"); + + // remove tag from end of message + buffer.resize(remaining + offset); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/ocb/ocb.h b/comm/third_party/botan/src/lib/modes/aead/ocb/ocb.h new file mode 100644 index 0000000000..4029fcda25 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/ocb/ocb.h @@ -0,0 +1,137 @@ +/* +* OCB Mode +* (C) 2013,2014 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_OCB_H_ +#define BOTAN_AEAD_OCB_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(ocb.h) + +namespace Botan { + +class BlockCipher; +class L_computer; + +/** +* OCB Mode (base class for OCB_Encryption and OCB_Decryption). Note +* that OCB is patented, but is freely licensed in some circumstances. +* +* @see "The OCB Authenticated-Encryption Algorithm" RFC 7253 +* https://tools.ietf.org/html/rfc7253 +* @see "OCB For Block Ciphers Without 128-Bit Blocks" +* (draft-krovetz-ocb-wide-d3) for the extension of OCB to +* block ciphers with larger block sizes. +* @see Free Licenses http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm +* @see OCB home page http://www.cs.ucdavis.edu/~rogaway/ocb +*/ +class BOTAN_PUBLIC_API(2,0) OCB_Mode : public AEAD_Mode + { + public: + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t) const override; + + size_t tag_size() const override { return m_tag_size; } + + void clear() override; + + void reset() override; + + ~OCB_Mode(); + protected: + /** + * @param cipher the block cipher to use + * @param tag_size is how big the auth tag will be + */ + OCB_Mode(BlockCipher* cipher, size_t tag_size); + + size_t block_size() const { return m_block_size; } + size_t par_blocks() const { return m_par_blocks; } + size_t par_bytes() const { return m_checksum.size(); } + + // fixme make these private + std::unique_ptr m_cipher; + std::unique_ptr m_L; + + size_t m_block_index = 0; + + secure_vector m_checksum; + secure_vector m_ad_hash; + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + + const secure_vector& update_nonce(const uint8_t nonce[], size_t nonce_len); + + const size_t m_tag_size; + const size_t m_block_size; + const size_t m_par_blocks; + secure_vector m_last_nonce; + secure_vector m_stretch; + secure_vector m_nonce_buf; + secure_vector m_offset; + }; + +class BOTAN_PUBLIC_API(2,0) OCB_Encryption final : public OCB_Mode + { + public: + /** + * @param cipher the block cipher to use + * @param tag_size is how big the auth tag will be + */ + OCB_Encryption(BlockCipher* cipher, size_t tag_size = 16) : + OCB_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + private: + void encrypt(uint8_t input[], size_t blocks); + }; + +class BOTAN_PUBLIC_API(2,0) OCB_Decryption final : public OCB_Mode + { + public: + /** + * @param cipher the block cipher to use + * @param tag_size is how big the auth tag will be + */ + OCB_Decryption(BlockCipher* cipher, size_t tag_size = 16) : + OCB_Mode(cipher, tag_size) {} + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + private: + void decrypt(uint8_t input[], size_t blocks); + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/aead/siv/info.txt b/comm/third_party/botan/src/lib/modes/aead/siv/info.txt new file mode 100644 index 0000000000..4894896665 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/siv/info.txt @@ -0,0 +1,9 @@ + +AEAD_SIV -> 20131202 + + + +cmac +ctr +poly_dbl + diff --git a/comm/third_party/botan/src/lib/modes/aead/siv/siv.cpp b/comm/third_party/botan/src/lib/modes/aead/siv/siv.cpp new file mode 100644 index 0000000000..8bd82a4684 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/siv/siv.cpp @@ -0,0 +1,211 @@ +/* +* SIV Mode Encryption +* (C) 2013,2017 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +SIV_Mode::SIV_Mode(BlockCipher* cipher) : + m_name(cipher->name() + "/SIV"), + m_ctr(new CTR_BE(cipher->clone(), 8)), + m_mac(new CMAC(cipher)), + m_bs(cipher->block_size()) + { + // Not really true but only 128 bit allowed at the moment + if(m_bs != 16) + throw Invalid_Argument("SIV requires a 128 bit block cipher"); + } + +SIV_Mode::~SIV_Mode() + { + // for ~unique_ptr + } + +void SIV_Mode::clear() + { + m_ctr->clear(); + m_mac->clear(); + reset(); + } + +void SIV_Mode::reset() + { + m_nonce.clear(); + m_msg_buf.clear(); + m_ad_macs.clear(); + } + +std::string SIV_Mode::name() const + { + return m_name; + } + +bool SIV_Mode::valid_nonce_length(size_t) const + { + return true; + } + +size_t SIV_Mode::update_granularity() const + { + /* + This value does not particularly matter as regardless SIV_Mode::update + buffers all input, so in theory this could be 1. However as for instance + Transform_Filter creates update_granularity() uint8_t buffers, use a + somewhat large size to avoid bouncing on a tiny buffer. + */ + return 128; + } + +Key_Length_Specification SIV_Mode::key_spec() const + { + return m_mac->key_spec().multiple(2); + } + +void SIV_Mode::key_schedule(const uint8_t key[], size_t length) + { + const size_t keylen = length / 2; + m_mac->set_key(key, keylen); + m_ctr->set_key(key + keylen, keylen); + m_ad_macs.clear(); + } + +size_t SIV_Mode::maximum_associated_data_inputs() const + { + return block_size() * 8 - 2; + } + +void SIV_Mode::set_associated_data_n(size_t n, const uint8_t ad[], size_t length) + { + const size_t max_ads = maximum_associated_data_inputs(); + if(n > max_ads) + throw Invalid_Argument(name() + " allows no more than " + std::to_string(max_ads) + " ADs"); + + if(n >= m_ad_macs.size()) + m_ad_macs.resize(n+1); + + m_ad_macs[n] = m_mac->process(ad, length); + } + +void SIV_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + if(nonce_len) + m_nonce = m_mac->process(nonce, nonce_len); + else + m_nonce.clear(); + + m_msg_buf.clear(); + } + +size_t SIV_Mode::process(uint8_t buf[], size_t sz) + { + // all output is saved for processing in finish + m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz); + return 0; + } + +secure_vector SIV_Mode::S2V(const uint8_t* text, size_t text_len) + { + const std::vector zeros(block_size()); + + secure_vector V = m_mac->process(zeros.data(), zeros.size()); + + for(size_t i = 0; i != m_ad_macs.size(); ++i) + { + poly_double_n(V.data(), V.size()); + V ^= m_ad_macs[i]; + } + + if(m_nonce.size()) + { + poly_double_n(V.data(), V.size()); + V ^= m_nonce; + } + + if(text_len < block_size()) + { + poly_double_n(V.data(), V.size()); + xor_buf(V.data(), text, text_len); + V[text_len] ^= 0x80; + return m_mac->process(V); + } + + m_mac->update(text, text_len - block_size()); + xor_buf(V.data(), &text[text_len - block_size()], block_size()); + m_mac->update(V); + + return m_mac->final(); + } + +void SIV_Mode::set_ctr_iv(secure_vector V) + { + V[m_bs-8] &= 0x7F; + V[m_bs-4] &= 0x7F; + + ctr().set_iv(V.data(), V.size()); + } + +void SIV_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + msg_buf().clear(); + + const secure_vector V = S2V(buffer.data() + offset, buffer.size() - offset); + + buffer.insert(buffer.begin() + offset, V.begin(), V.end()); + + if(buffer.size() != offset + V.size()) + { + set_ctr_iv(V); + ctr().cipher1(&buffer[offset + V.size()], buffer.size() - offset - V.size()); + } + } + +void SIV_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + if(msg_buf().size() > 0) + { + buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); + msg_buf().clear(); + } + + const size_t sz = buffer.size() - offset; + + BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); + + secure_vector V(buffer.data() + offset, + buffer.data() + offset + block_size()); + + if(buffer.size() != offset + V.size()) + { + set_ctr_iv(V); + + ctr().cipher(buffer.data() + offset + V.size(), + buffer.data() + offset, + buffer.size() - offset - V.size()); + } + + const secure_vector T = S2V(buffer.data() + offset, buffer.size() - offset - V.size()); + + if(!constant_time_compare(T.data(), V.data(), T.size())) + throw Invalid_Authentication_Tag("SIV tag check failed"); + + buffer.resize(buffer.size() - tag_size()); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/aead/siv/siv.h b/comm/third_party/botan/src/lib/modes/aead/siv/siv.h new file mode 100644 index 0000000000..c76fd32296 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/aead/siv/siv.h @@ -0,0 +1,129 @@ +/* +* SIV Mode +* (C) 2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_SIV_H_ +#define BOTAN_AEAD_SIV_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(siv.h) + +namespace Botan { + +class BlockCipher; +class MessageAuthenticationCode; + +/** +* Base class for SIV encryption and decryption (@see RFC 5297) +*/ +class BOTAN_PUBLIC_API(2,0) SIV_Mode : public AEAD_Mode + { + public: + size_t process(uint8_t buf[], size_t size) override; + + /** + * Sets the nth element of the vector of associated data + * @param n index into the AD vector + * @param ad associated data + * @param ad_len length of associated data in bytes + */ + void set_associated_data_n(size_t n, const uint8_t ad[], size_t ad_len) override; + + size_t maximum_associated_data_inputs() const override; + + void set_associated_data(const uint8_t ad[], size_t ad_len) override + { + set_associated_data_n(0, ad, ad_len); + } + + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + bool valid_nonce_length(size_t) const override; + + void clear() override; + + void reset() override; + + size_t tag_size() const override { return 16; } + + ~SIV_Mode(); + + protected: + explicit SIV_Mode(BlockCipher* cipher); + + size_t block_size() const { return m_bs; } + + StreamCipher& ctr() { return *m_ctr; } + + void set_ctr_iv(secure_vector V); + + secure_vector& msg_buf() { return m_msg_buf; } + + secure_vector S2V(const uint8_t text[], size_t text_len); + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + + const std::string m_name; + std::unique_ptr m_ctr; + std::unique_ptr m_mac; + secure_vector m_nonce, m_msg_buf; + std::vector> m_ad_macs; + const size_t m_bs; + }; + +/** +* SIV Encryption +*/ +class BOTAN_PUBLIC_API(2,0) SIV_Encryption final : public SIV_Mode + { + public: + /** + * @param cipher a block cipher + */ + explicit SIV_Encryption(BlockCipher* cipher) : SIV_Mode(cipher) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { return input_length + tag_size(); } + + size_t minimum_final_size() const override { return 0; } + }; + +/** +* SIV Decryption +*/ +class BOTAN_PUBLIC_API(2,0) SIV_Decryption final : public SIV_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + */ + explicit SIV_Decryption(BlockCipher* cipher) : SIV_Mode(cipher) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override + { + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); + return input_length - tag_size(); + } + + size_t minimum_final_size() const override { return tag_size(); } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/cbc/cbc.cpp b/comm/third_party/botan/src/lib/modes/cbc/cbc.cpp new file mode 100644 index 0000000000..cde08f64a9 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cbc/cbc.cpp @@ -0,0 +1,323 @@ +/* +* CBC Mode +* (C) 1999-2007,2013,2017 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + m_cipher(cipher), + m_padding(padding), + m_block_size(cipher->block_size()) + { + if(m_padding && !m_padding->valid_blocksize(m_block_size)) + throw Invalid_Argument("Padding " + m_padding->name() + + " cannot be used with " + + cipher->name() + "/CBC"); + } + +void CBC_Mode::clear() + { + m_cipher->clear(); + reset(); + } + +void CBC_Mode::reset() + { + m_state.clear(); + } + +std::string CBC_Mode::name() const + { + if(m_padding) + return cipher().name() + "/CBC/" + padding().name(); + else + return cipher().name() + "/CBC/CTS"; + } + +size_t CBC_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +Key_Length_Specification CBC_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CBC_Mode::default_nonce_length() const + { + return block_size(); + } + +bool CBC_Mode::valid_nonce_length(size_t n) const + { + return (n == 0 || n == block_size()); + } + +void CBC_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + m_state.clear(); + } + +void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + /* + * A nonce of zero length means carry the last ciphertext value over + * as the new IV, as unfortunately some protocols require this. If + * this is the first message then we use an IV of all zeros. + */ + if(nonce_len) + m_state.assign(nonce, nonce + nonce_len); + else if(m_state.empty()) + m_state.resize(m_cipher->block_size()); + // else leave the state alone + } + +size_t CBC_Encryption::minimum_final_size() const + { + return 0; + } + +size_t CBC_Encryption::output_length(size_t input_length) const + { + if(input_length == 0) + return block_size(); + else + return round_up(input_length, block_size()); + } + +size_t CBC_Encryption::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(state().empty() == false); + const size_t BS = block_size(); + + BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks"); + const size_t blocks = sz / BS; + + if(blocks > 0) + { + xor_buf(&buf[0], state_ptr(), BS); + cipher().encrypt(&buf[0]); + + for(size_t i = 1; i != blocks; ++i) + { + xor_buf(&buf[BS*i], &buf[BS*(i-1)], BS); + cipher().encrypt(&buf[BS*i]); + } + + state().assign(&buf[BS*(blocks-1)], &buf[BS*blocks]); + } + + return sz; + } + +void CBC_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_STATE_CHECK(state().empty() == false); + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + const size_t BS = block_size(); + + const size_t bytes_in_final_block = (buffer.size()-offset) % BS; + + padding().add_padding(buffer, bytes_in_final_block, BS); + + BOTAN_ASSERT_EQUAL(buffer.size() % BS, offset % BS, "Padded to block boundary"); + + update(buffer, offset); + } + +bool CTS_Encryption::valid_nonce_length(size_t n) const + { + return (n == block_size()); + } + +size_t CTS_Encryption::minimum_final_size() const + { + return block_size() + 1; + } + +size_t CTS_Encryption::output_length(size_t input_length) const + { + return input_length; // no ciphertext expansion in CTS + } + +void CTS_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_STATE_CHECK(state().empty() == false); + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + uint8_t* buf = buffer.data() + offset; + const size_t sz = buffer.size() - offset; + + const size_t BS = block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to encrypt"); + + if(sz % BS == 0) + { + update(buffer, offset); + + // swap last two blocks + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + } + else + { + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last.data(), state_ptr(), BS); + cipher().encrypt(last.data()); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + last[i] ^= last[i + BS]; + last[i + BS] ^= last[i]; + } + + cipher().encrypt(last.data()); + + buffer += last; + } + } + +size_t CBC_Decryption::output_length(size_t input_length) const + { + return input_length; // precise for CTS, worst case otherwise + } + +size_t CBC_Decryption::minimum_final_size() const + { + return block_size(); + } + +size_t CBC_Decryption::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(state().empty() == false); + + const size_t BS = block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + while(blocks) + { + const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); + + cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS); + + xor_buf(m_tempbuf.data(), state_ptr(), BS); + xor_buf(&m_tempbuf[BS], buf, to_proc - BS); + copy_mem(state_ptr(), buf + (to_proc - BS), BS); + + copy_mem(buf, m_tempbuf.data(), to_proc); + + buf += to_proc; + blocks -= to_proc / BS; + } + + return sz; + } + +void CBC_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_STATE_CHECK(state().empty() == false); + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + + const size_t BS = block_size(); + + if(sz == 0 || sz % BS) + throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); + + update(buffer, offset); + + const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); + buffer.resize(buffer.size() - pad_bytes); // remove padding + if(pad_bytes == 0 && padding().name() != "NoPadding") + { + throw Decoding_Error("Invalid CBC padding"); + } + } + +void CBC_Decryption::reset() + { + CBC_Mode::reset(); + zeroise(m_tempbuf); + } + +bool CTS_Decryption::valid_nonce_length(size_t n) const + { + return (n == block_size()); + } + +size_t CTS_Decryption::minimum_final_size() const + { + return block_size() + 1; + } + +void CTS_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_STATE_CHECK(state().empty() == false); + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + const size_t BS = block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to decrypt"); + + if(sz % BS == 0) + { + // swap last two blocks + + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + + update(buffer, offset); + } + else + { + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + cipher().decrypt(last.data()); + + xor_buf(last.data(), &last[BS], final_bytes - BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + cipher().decrypt(last.data()); + xor_buf(last.data(), state_ptr(), BS); + + buffer += last; + } + } + +} diff --git a/comm/third_party/botan/src/lib/modes/cbc/cbc.h b/comm/third_party/botan/src/lib/modes/cbc/cbc.h new file mode 100644 index 0000000000..7a488dbd50 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cbc/cbc.h @@ -0,0 +1,157 @@ +/* +* CBC mode +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_CBC_H_ +#define BOTAN_MODE_CBC_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cbc.h) + +namespace Botan { + +/** +* CBC Mode +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Mode : public Cipher_Mode + { + public: + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear() override; + + void reset() override; + + protected: + CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding); + + const BlockCipher& cipher() const { return *m_cipher; } + + const BlockCipherModePaddingMethod& padding() const + { + BOTAN_ASSERT_NONNULL(m_padding); + return *m_padding; + } + + size_t block_size() const { return m_block_size; } + + secure_vector& state() { return m_state; } + + uint8_t* state_ptr() { return m_state.data(); } + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + + std::unique_ptr m_cipher; + std::unique_ptr m_padding; + secure_vector m_state; + size_t m_block_size; + }; + +/** +* CBC Encryption +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Encryption : public CBC_Mode + { + public: + /** + * @param cipher block cipher to use + * @param padding padding method to use + */ + CBC_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + }; + +/** +* CBC Encryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_PUBLIC_API(2,0) CTS_Encryption final : public CBC_Encryption + { + public: + /** + * @param cipher block cipher to use + */ + explicit CTS_Encryption(BlockCipher* cipher) : CBC_Encryption(cipher, nullptr) {} + + size_t output_length(size_t input_length) const override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const override; + }; + +/** +* CBC Decryption +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Decryption : public CBC_Mode + { + public: + /** + * @param cipher block cipher to use + * @param padding padding method to use + */ + CBC_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding), m_tempbuf(update_granularity()) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + + void reset() override; + + private: + secure_vector m_tempbuf; + }; + +/** +* CBC Decryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_PUBLIC_API(2,0) CTS_Decryption final : public CBC_Decryption + { + public: + /** + * @param cipher block cipher to use + */ + explicit CTS_Decryption(BlockCipher* cipher) : CBC_Decryption(cipher, nullptr) {} + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/cbc/info.txt b/comm/third_party/botan/src/lib/modes/cbc/info.txt new file mode 100644 index 0000000000..778ba1e252 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cbc/info.txt @@ -0,0 +1,8 @@ + +MODE_CBC -> 20131128 + + + +block +mode_pad + diff --git a/comm/third_party/botan/src/lib/modes/cfb/cfb.cpp b/comm/third_party/botan/src/lib/modes/cfb/cfb.cpp new file mode 100644 index 0000000000..0c619e322c --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cfb/cfb.cpp @@ -0,0 +1,229 @@ +/* +* CFB Mode +* (C) 1999-2007,2013,2017 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +CFB_Mode::CFB_Mode(BlockCipher* cipher, size_t feedback_bits) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()), + m_feedback_bytes(feedback_bits ? feedback_bits / 8 : m_block_size) + { + if(feedback_bits % 8 || feedback() > cipher->block_size()) + throw Invalid_Argument(name() + ": feedback bits " + + std::to_string(feedback_bits) + " not supported"); + } + +void CFB_Mode::clear() + { + m_cipher->clear(); + m_keystream.clear(); + reset(); + } + +void CFB_Mode::reset() + { + m_state.clear(); + zeroise(m_keystream); + } + +std::string CFB_Mode::name() const + { + if(feedback() == cipher().block_size()) + return cipher().name() + "/CFB"; + else + return cipher().name() + "/CFB(" + std::to_string(feedback()*8) + ")"; + } + +size_t CFB_Mode::output_length(size_t input_length) const + { + return input_length; + } + +size_t CFB_Mode::update_granularity() const + { + return feedback(); + } + +size_t CFB_Mode::minimum_final_size() const + { + return 0; + } + +Key_Length_Specification CFB_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CFB_Mode::default_nonce_length() const + { + return block_size(); + } + +bool CFB_Mode::valid_nonce_length(size_t n) const + { + return (n == 0 || n == block_size()); + } + +void CFB_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + m_keystream.resize(m_cipher->block_size()); + } + +void CFB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + verify_key_set(!m_keystream.empty()); + + if(nonce_len == 0) + { + if(m_state.empty()) + { + throw Invalid_State("CFB requires a non-empty initial nonce"); + } + // No reason to encrypt state->keystream_buf, because no change + } + else + { + m_state.assign(nonce, nonce + nonce_len); + cipher().encrypt(m_state, m_keystream); + m_keystream_pos = 0; + } + } + +void CFB_Mode::shift_register() + { + const size_t shift = feedback(); + const size_t carryover = block_size() - shift; + + if(carryover > 0) + { + copy_mem(m_state.data(), &m_state[shift], carryover); + } + copy_mem(&m_state[carryover], m_keystream.data(), shift); + cipher().encrypt(m_state, m_keystream); + m_keystream_pos = 0; + } + +size_t CFB_Encryption::process(uint8_t buf[], size_t sz) + { + verify_key_set(!m_keystream.empty()); + BOTAN_STATE_CHECK(m_state.empty() == false); + + const size_t shift = feedback(); + + size_t left = sz; + + if(m_keystream_pos != 0) + { + const size_t take = std::min(left, shift - m_keystream_pos); + + xor_buf(m_keystream.data() + m_keystream_pos, buf, take); + copy_mem(buf, m_keystream.data() + m_keystream_pos, take); + + m_keystream_pos += take; + left -= take; + buf += take; + + if(m_keystream_pos == shift) + { + shift_register(); + } + } + + while(left >= shift) + { + xor_buf(m_keystream.data(), buf, shift); + copy_mem(buf, m_keystream.data(), shift); + + left -= shift; + buf += shift; + shift_register(); + } + + if(left > 0) + { + xor_buf(m_keystream.data(), buf, left); + copy_mem(buf, m_keystream.data(), left); + m_keystream_pos += left; + } + + return sz; + } + +void CFB_Encryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + } + +namespace { + +inline void xor_copy(uint8_t buf[], uint8_t key_buf[], size_t len) + { + for(size_t i = 0; i != len; ++i) + { + uint8_t k = key_buf[i]; + key_buf[i] = buf[i]; + buf[i] ^= k; + } + } + +} + +size_t CFB_Decryption::process(uint8_t buf[], size_t sz) + { + verify_key_set(!m_keystream.empty()); + BOTAN_STATE_CHECK(m_state.empty() == false); + + const size_t shift = feedback(); + + size_t left = sz; + + if(m_keystream_pos != 0) + { + const size_t take = std::min(left, shift - m_keystream_pos); + + xor_copy(buf, m_keystream.data() + m_keystream_pos, take); + + m_keystream_pos += take; + left -= take; + buf += take; + + if(m_keystream_pos == shift) + { + shift_register(); + } + } + + while(left >= shift) + { + xor_copy(buf, m_keystream.data(), shift); + left -= shift; + buf += shift; + shift_register(); + } + + if(left > 0) + { + xor_copy(buf, m_keystream.data(), left); + m_keystream_pos += left; + } + + return sz; + } + +void CFB_Decryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/cfb/cfb.h b/comm/third_party/botan/src/lib/modes/cfb/cfb.h new file mode 100644 index 0000000000..1f9e554872 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cfb/cfb.h @@ -0,0 +1,106 @@ +/* +* CFB mode +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_CFB_H_ +#define BOTAN_MODE_CFB_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cfb.h) + +namespace Botan { + +/** +* CFB Mode +*/ +class BOTAN_PUBLIC_API(2,0) CFB_Mode : public Cipher_Mode + { + public: + std::string name() const override final; + + size_t update_granularity() const override final; + + size_t minimum_final_size() const override final; + + Key_Length_Specification key_spec() const override final; + + size_t output_length(size_t input_length) const override final; + + size_t default_nonce_length() const override final; + + bool valid_nonce_length(size_t n) const override final; + + void clear() override final; + + void reset() override final; + protected: + CFB_Mode(BlockCipher* cipher, size_t feedback_bits); + + void shift_register(); + + size_t feedback() const { return m_feedback_bytes; } + const BlockCipher& cipher() const { return *m_cipher; } + size_t block_size() const { return m_block_size; } + + secure_vector m_state; + secure_vector m_keystream; + size_t m_keystream_pos = 0; + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + void key_schedule(const uint8_t key[], size_t length) override; + + std::unique_ptr m_cipher; + const size_t m_block_size; + const size_t m_feedback_bytes; + }; + +/** +* CFB Encryption +*/ +class BOTAN_PUBLIC_API(2,0) CFB_Encryption final : public CFB_Mode + { + public: + /** + * If feedback_bits is zero, cipher->block_size() bytes will be used. + * @param cipher block cipher to use + * @param feedback_bits number of bits fed back into the shift register, + * must be a multiple of 8 + */ + CFB_Encryption(BlockCipher* cipher, size_t feedback_bits) : + CFB_Mode(cipher, feedback_bits) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +/** +* CFB Decryption +*/ +class BOTAN_PUBLIC_API(2,0) CFB_Decryption final : public CFB_Mode + { + public: + /** + * If feedback_bits is zero, cipher->block_size() bytes will be used. + * @param cipher block cipher to use + * @param feedback_bits number of bits fed back into the shift register, + * must be a multiple of 8 + */ + CFB_Decryption(BlockCipher* cipher, size_t feedback_bits) : + CFB_Mode(cipher, feedback_bits) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/cfb/info.txt b/comm/third_party/botan/src/lib/modes/cfb/info.txt new file mode 100644 index 0000000000..77a6af448e --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cfb/info.txt @@ -0,0 +1,7 @@ + +MODE_CFB -> 20131128 + + + +block + diff --git a/comm/third_party/botan/src/lib/modes/cipher_mode.cpp b/comm/third_party/botan/src/lib/modes/cipher_mode.cpp new file mode 100644 index 0000000000..710f16ba22 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cipher_mode.cpp @@ -0,0 +1,205 @@ +/* +* Cipher Modes +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_AEAD_MODES) + #include +#endif + +#if defined(BOTAN_HAS_MODE_CBC) + #include +#endif + +#if defined(BOTAN_HAS_MODE_CFB) + #include +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + #include +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +#if defined(BOTAN_HAS_COMMONCRYPTO) + #include +#endif + +namespace Botan { + +std::unique_ptr Cipher_Mode::create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider) + { + if(auto mode = Cipher_Mode::create(algo, direction, provider)) + return mode; + + throw Lookup_Error("Cipher mode", algo, provider); + } + +std::unique_ptr Cipher_Mode::create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider) + { +#if defined(BOTAN_HAS_COMMONCRYPTO) + if(provider.empty() || provider == "commoncrypto") + { + std::unique_ptr commoncrypto_cipher(make_commoncrypto_cipher_mode(algo, direction)); + + if(commoncrypto_cipher) + return commoncrypto_cipher; + + if(!provider.empty()) + return std::unique_ptr(); + } +#endif + +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + std::unique_ptr openssl_cipher(make_openssl_cipher_mode(algo, direction)); + + if(openssl_cipher) + return openssl_cipher; + + if(!provider.empty()) + return std::unique_ptr(); + } +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + if(auto sc = StreamCipher::create(algo)) + { + return std::unique_ptr(new Stream_Cipher_Mode(sc.release())); + } +#endif + +#if defined(BOTAN_HAS_AEAD_MODES) + if(auto aead = AEAD_Mode::create(algo, direction)) + { + return std::unique_ptr(aead.release()); + } +#endif + + if(algo.find('/') != std::string::npos) + { + const std::vector algo_parts = split_on(algo, '/'); + const std::string cipher_name = algo_parts[0]; + const std::vector mode_info = parse_algorithm_name(algo_parts[1]); + + if(mode_info.empty()) + return std::unique_ptr(); + + std::ostringstream alg_args; + + alg_args << '(' << cipher_name; + for(size_t i = 1; i < mode_info.size(); ++i) + alg_args << ',' << mode_info[i]; + for(size_t i = 2; i < algo_parts.size(); ++i) + alg_args << ',' << algo_parts[i]; + alg_args << ')'; + + const std::string mode_name = mode_info[0] + alg_args.str(); + return Cipher_Mode::create(mode_name, direction, provider); + } + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + + SCAN_Name spec(algo); + + if(spec.arg_count() == 0) + { + return std::unique_ptr(); + } + + std::unique_ptr bc(BlockCipher::create(spec.arg(0), provider)); + + if(!bc) + { + return std::unique_ptr(); + } + +#if defined(BOTAN_HAS_MODE_CBC) + if(spec.algo_name() == "CBC") + { + const std::string padding = spec.arg(1, "PKCS7"); + + if(padding == "CTS") + { + if(direction == ENCRYPTION) + return std::unique_ptr(new CTS_Encryption(bc.release())); + else + return std::unique_ptr(new CTS_Decryption(bc.release())); + } + else + { + std::unique_ptr pad(get_bc_pad(padding)); + + if(pad) + { + if(direction == ENCRYPTION) + return std::unique_ptr(new CBC_Encryption(bc.release(), pad.release())); + else + return std::unique_ptr(new CBC_Decryption(bc.release(), pad.release())); + } + } + } +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + if(spec.algo_name() == "XTS") + { + if(direction == ENCRYPTION) + return std::unique_ptr(new XTS_Encryption(bc.release())); + else + return std::unique_ptr(new XTS_Decryption(bc.release())); + } +#endif + +#if defined(BOTAN_HAS_MODE_CFB) + if(spec.algo_name() == "CFB") + { + const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size()); + if(direction == ENCRYPTION) + return std::unique_ptr(new CFB_Encryption(bc.release(), feedback_bits)); + else + return std::unique_ptr(new CFB_Decryption(bc.release(), feedback_bits)); + } +#endif + +#endif + + return std::unique_ptr(); + } + +//static +std::vector Cipher_Mode::providers(const std::string& algo_spec) + { + const std::vector& possible = { "base", "openssl", "commoncrypto" }; + std::vector providers; + for(auto&& prov : possible) + { + std::unique_ptr mode = Cipher_Mode::create(algo_spec, ENCRYPTION, prov); + if(mode) + { + providers.push_back(prov); // available + } + } + return providers; + } + +} diff --git a/comm/third_party/botan/src/lib/modes/cipher_mode.h b/comm/third_party/botan/src/lib/modes/cipher_mode.h new file mode 100644 index 0000000000..9bf0b6811e --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cipher_mode.h @@ -0,0 +1,198 @@ +/* +* Cipher Modes +* (C) 2013,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CIPHER_MODE_H_ +#define BOTAN_CIPHER_MODE_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* The two possible directions for cipher filters, determining whether they +* actually perform encryption or decryption. +*/ +enum Cipher_Dir : int { ENCRYPTION, DECRYPTION }; + +/** +* Interface for cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Cipher_Mode : public SymmetricAlgorithm + { + public: + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector providers(const std::string& algo_spec); + + /** + * Create an AEAD mode + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode or a null pointer if not available + */ + static std::unique_ptr create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /** + * Create an AEAD mode, or throw + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode, or throw an exception + */ + static std::unique_ptr create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /* + * Prepare for processing a message under the specified nonce + */ + virtual void start_msg(const uint8_t nonce[], size_t nonce_len) = 0; + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template + void start(const std::vector& nonce) + { + start_msg(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + void start(const uint8_t nonce[], size_t nonce_len) + { + start_msg(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + void start() + { + return start_msg(nullptr, 0); + } + + /** + * Process message blocks + * + * Input must be a multiple of update_granularity + * + * Processes msg in place and returns bytes written. Normally + * this will be either msg_len (indicating the entire message was + * processed) or for certain AEAD modes zero (indicating that the + * mode requires the entire message be processed in one pass). + * + * @param msg the message to be processed + * @param msg_len length of the message in bytes + */ + virtual size_t process(uint8_t msg[], size_t msg_len) = 0; + + /** + * Process some data. Input must be in size update_granularity() uint8_t blocks. + * @param buffer in/out parameter which will possibly be resized + * @param offset an offset into blocks to begin processing + */ + void update(secure_vector& buffer, size_t offset = 0) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset ok"); + uint8_t* buf = buffer.data() + offset; + const size_t buf_size = buffer.size() - offset; + + const size_t written = process(buf, buf_size); + buffer.resize(offset + written); + } + + /** + * Complete processing of a message. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector& final_block, size_t offset = 0) = 0; + + /** + * Returns the size of the output if this transform is used to process a + * message with input_length bytes. In most cases the answer is precise. + * If it is not possible to precise (namely for CBC decryption) instead a + * lower bound is returned. + */ + virtual size_t output_length(size_t input_length) const = 0; + + /** + * @return size of required blocks to update + */ + virtual size_t update_granularity() const = 0; + + /** + * @return required minimium size to finalize() - may be any + * length larger than this. + */ + virtual size_t minimum_final_size() const = 0; + + /** + * @return the default size for a nonce + */ + virtual size_t default_nonce_length() const = 0; + + /** + * @return true iff nonce_len is a valid length for the nonce + */ + virtual bool valid_nonce_length(size_t nonce_len) const = 0; + + /** + * Resets just the message specific state and allows encrypting again under the existing key + */ + virtual void reset() = 0; + + /** + * @return true iff this mode provides authentication as well as + * confidentiality. + */ + virtual bool authenticated() const { return false; } + + /** + * @return the size of the authentication tag used (in bytes) + */ + virtual size_t tag_size() const { return 0; } + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + }; + +/** +* Get a cipher mode by name (eg "AES-128/CBC" or "Serpent/XTS") +* @param algo_spec cipher name +* @param direction ENCRYPTION or DECRYPTION +* @param provider provider implementation to choose +*/ +inline Cipher_Mode* get_cipher_mode(const std::string& algo_spec, + Cipher_Dir direction, + const std::string& provider = "") + { + return Cipher_Mode::create(algo_spec, direction, provider).release(); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/info.txt b/comm/third_party/botan/src/lib/modes/info.txt new file mode 100644 index 0000000000..4c19db04ca --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/info.txt @@ -0,0 +1,9 @@ + +MODES -> 20150626 +CIPHER_MODES -> 20180124 + + + +cipher_mode.h +stream_mode.h + diff --git a/comm/third_party/botan/src/lib/modes/mode_pad/info.txt b/comm/third_party/botan/src/lib/modes/mode_pad/info.txt new file mode 100644 index 0000000000..12b6e5b3a9 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/mode_pad/info.txt @@ -0,0 +1,3 @@ + +CIPHER_MODE_PADDING -> 20131128 + diff --git a/comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.cpp b/comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.cpp new file mode 100644 index 0000000000..18bb71af5d --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.cpp @@ -0,0 +1,333 @@ +/* +* CBC Padding Methods +* (C) 1999-2007,2013,2018,2020 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/** +* Get a block cipher padding method by name +*/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec) + { + if(algo_spec == "NoPadding") + return new Null_Padding; + + if(algo_spec == "PKCS7") + return new PKCS7_Padding; + + if(algo_spec == "OneAndZeros") + return new OneAndZeros_Padding; + + if(algo_spec == "X9.23") + return new ANSI_X923_Padding; + + if(algo_spec == "ESP") + return new ESP_Padding; + + return nullptr; + } + +/* +* Pad with PKCS #7 Method +*/ +void PKCS7_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t BS) const + { + /* + Padding format is + 01 + 0202 + 030303 + ... + */ + BOTAN_DEBUG_ASSERT(last_byte_pos < BS); + + const uint8_t padding_len = static_cast(BS - last_byte_pos); + + buffer.resize(buffer.size() + padding_len); + + CT::poison(&last_byte_pos, 1); + CT::poison(buffer.data(), buffer.size()); + + BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); + BOTAN_DEBUG_ASSERT(buffer.size() >= BS); + + const size_t start_of_last_block = buffer.size() - BS; + const size_t end_of_last_block = buffer.size(); + const size_t start_of_padding = buffer.size() - padding_len; + + for(size_t i = start_of_last_block; i != end_of_last_block; ++i) + { + auto needs_padding = CT::Mask(CT::Mask::is_gte(i, start_of_padding)); + buffer[i] = needs_padding.select(padding_len, buffer[i]); + } + + CT::unpoison(buffer.data(), buffer.size()); + CT::unpoison(last_byte_pos); + } + +/* +* Unpad with PKCS #7 Method +*/ +size_t PKCS7_Padding::unpad(const uint8_t input[], size_t input_length) const + { + if(!valid_blocksize(input_length)) + return input_length; + + CT::poison(input, input_length); + + const uint8_t last_byte = input[input_length-1]; + + /* + The input should == the block size so if the last byte exceeds + that then the padding is certainly invalid + */ + auto bad_input = CT::Mask::is_gt(last_byte, input_length); + + const size_t pad_pos = input_length - last_byte; + + for(size_t i = 0; i != input_length - 1; ++i) + { + // Does this byte equal the expected pad byte? + const auto pad_eq = CT::Mask::is_equal(input[i], last_byte); + + // Ignore values that are not part of the padding + const auto in_range = CT::Mask::is_gte(i, pad_pos); + bad_input |= in_range & (~pad_eq); + } + + CT::unpoison(input, input_length); + + return bad_input.select_and_unpoison(input_length, pad_pos); + } + +/* +* Pad with ANSI X9.23 Method +*/ +void ANSI_X923_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t BS) const + { + /* + Padding format is + 01 + 0002 + 000003 + ... + */ + BOTAN_DEBUG_ASSERT(last_byte_pos < BS); + + const uint8_t padding_len = static_cast(BS - last_byte_pos); + + buffer.resize(buffer.size() + padding_len); + + CT::poison(&last_byte_pos, 1); + CT::poison(buffer.data(), buffer.size()); + + BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); + BOTAN_DEBUG_ASSERT(buffer.size() >= BS); + + const size_t start_of_last_block = buffer.size() - BS; + const size_t end_of_zero_padding = buffer.size() - 1; + const size_t start_of_padding = buffer.size() - padding_len; + + for(size_t i = start_of_last_block; i != end_of_zero_padding; ++i) + { + auto needs_padding = CT::Mask(CT::Mask::is_gte(i, start_of_padding)); + buffer[i] = needs_padding.select(0, buffer[i]); + } + + buffer[buffer.size()-1] = padding_len; + CT::unpoison(buffer.data(), buffer.size()); + CT::unpoison(last_byte_pos); + } + +/* +* Unpad with ANSI X9.23 Method +*/ +size_t ANSI_X923_Padding::unpad(const uint8_t input[], size_t input_length) const + { + if(!valid_blocksize(input_length)) + return input_length; + + CT::poison(input, input_length); + + const size_t last_byte = input[input_length-1]; + + auto bad_input = CT::Mask::is_gt(last_byte, input_length); + + const size_t pad_pos = input_length - last_byte; + + for(size_t i = 0; i != input_length - 1; ++i) + { + // Ignore values that are not part of the padding + const auto in_range = CT::Mask::is_gte(i, pad_pos); + const auto pad_is_nonzero = CT::Mask::expand(input[i]); + bad_input |= pad_is_nonzero & in_range; + } + + CT::unpoison(input, input_length); + + return bad_input.select_and_unpoison(input_length, pad_pos); + } + +/* +* Pad with One and Zeros Method +*/ +void OneAndZeros_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t BS) const + { + /* + Padding format is + 80 + 8000 + 800000 + ... + */ + + BOTAN_DEBUG_ASSERT(last_byte_pos < BS); + + const uint8_t padding_len = static_cast(BS - last_byte_pos); + + buffer.resize(buffer.size() + padding_len); + + CT::poison(&last_byte_pos, 1); + CT::poison(buffer.data(), buffer.size()); + + BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); + BOTAN_DEBUG_ASSERT(buffer.size() >= BS); + + const size_t start_of_last_block = buffer.size() - BS; + const size_t end_of_last_block = buffer.size(); + const size_t start_of_padding = buffer.size() - padding_len; + + for(size_t i = start_of_last_block; i != end_of_last_block; ++i) + { + auto needs_80 = CT::Mask(CT::Mask::is_equal(i, start_of_padding)); + auto needs_00 = CT::Mask(CT::Mask::is_gt(i, start_of_padding)); + buffer[i] = needs_00.select(0x00, needs_80.select(0x80, buffer[i])); + } + + CT::unpoison(buffer.data(), buffer.size()); + CT::unpoison(last_byte_pos); + } + +/* +* Unpad with One and Zeros Method +*/ +size_t OneAndZeros_Padding::unpad(const uint8_t input[], size_t input_length) const + { + if(!valid_blocksize(input_length)) + return input_length; + + CT::poison(input, input_length); + + auto bad_input = CT::Mask::cleared(); + auto seen_0x80 = CT::Mask::cleared(); + + size_t pad_pos = input_length - 1; + size_t i = input_length; + + while(i) + { + const auto is_0x80 = CT::Mask::is_equal(input[i-1], 0x80); + const auto is_zero = CT::Mask::is_zero(input[i-1]); + + seen_0x80 |= is_0x80; + pad_pos -= seen_0x80.if_not_set_return(1); + bad_input |= ~seen_0x80 & ~is_zero; + i--; + } + bad_input |= ~seen_0x80; + + CT::unpoison(input, input_length); + + return CT::Mask::expand(bad_input).select_and_unpoison(input_length, pad_pos); + } + +/* +* Pad with ESP Padding Method +*/ +void ESP_Padding::add_padding(secure_vector& buffer, + size_t last_byte_pos, + size_t BS) const + { + /* + Padding format is + 01 + 0102 + 010203 + ... + */ + BOTAN_DEBUG_ASSERT(last_byte_pos < BS); + + const uint8_t padding_len = static_cast(BS - last_byte_pos); + + buffer.resize(buffer.size() + padding_len); + + CT::poison(&last_byte_pos, 1); + CT::poison(buffer.data(), buffer.size()); + + BOTAN_DEBUG_ASSERT(buffer.size() % BS == 0); + BOTAN_DEBUG_ASSERT(buffer.size() >= BS); + + const size_t start_of_last_block = buffer.size() - BS; + const size_t end_of_last_block = buffer.size(); + const size_t start_of_padding = buffer.size() - padding_len; + + uint8_t pad_ctr = 0x01; + + for(size_t i = start_of_last_block; i != end_of_last_block; ++i) + { + auto needs_padding = CT::Mask(CT::Mask::is_gte(i, start_of_padding)); + buffer[i] = needs_padding.select(pad_ctr, buffer[i]); + pad_ctr = needs_padding.select(pad_ctr + 1, pad_ctr); + } + + CT::unpoison(buffer.data(), buffer.size()); + CT::unpoison(last_byte_pos); + } + +/* +* Unpad with ESP Padding Method +*/ +size_t ESP_Padding::unpad(const uint8_t input[], size_t input_length) const + { + if(!valid_blocksize(input_length)) + return input_length; + + CT::poison(input, input_length); + + const uint8_t input_length_8 = static_cast(input_length); + const uint8_t last_byte = input[input_length-1]; + + auto bad_input = CT::Mask::is_zero(last_byte) | + CT::Mask::is_gt(last_byte, input_length_8); + + const uint8_t pad_pos = input_length_8 - last_byte; + size_t i = input_length_8 - 1; + while(i) + { + const auto in_range = CT::Mask::is_gt(i, pad_pos); + const auto incrementing = CT::Mask::is_equal(input[i-1], input[i]-1); + + bad_input |= CT::Mask(in_range) & ~incrementing; + --i; + } + + CT::unpoison(input, input_length); + return bad_input.select_and_unpoison(input_length_8, pad_pos); + } + + +} diff --git a/comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.h b/comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.h new file mode 100644 index 0000000000..b0e4a3cfae --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/mode_pad/mode_pad.h @@ -0,0 +1,160 @@ +/* +* CBC Padding Methods +* (C) 1999-2008,2013 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_PADDING_H_ +#define BOTAN_MODE_PADDING_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(mode_pad.h) + +namespace Botan { + +/** +* Block Cipher Mode Padding Method +* This class is pretty limited, it cannot deal well with +* randomized padding methods, or any padding method that +* wants to add more than one block. For instance, it should +* be possible to define cipher text stealing mode as simply +* a padding mode for CBC, which happens to consume the last +* two block (and requires use of the block cipher). +*/ +class BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod + { + public: + /** + * Add padding bytes to buffer. + * @param buffer data to pad + * @param final_block_bytes size of the final block in bytes + * @param block_size size of each block in bytes + */ + virtual void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const = 0; + + /** + * Remove padding bytes from block + * @param block the last block + * @param len the size of the block in bytes + * @return number of data bytes, or if the padding is invalid returns len + */ + virtual size_t unpad(const uint8_t block[], size_t len) const = 0; + + /** + * @param block_size of the cipher + * @return valid block size for this padding mode + */ + virtual bool valid_blocksize(size_t block_size) const = 0; + + /** + * @return name of the mode + */ + virtual std::string name() const = 0; + + /** + * virtual destructor + */ + virtual ~BlockCipherModePaddingMethod() = default; + }; + +/** +* PKCS#7 Padding +*/ +class BOTAN_PUBLIC_API(2,0) PKCS7_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 2 && bs < 256); } + + std::string name() const override { return "PKCS7"; } + }; + +/** +* ANSI X9.23 Padding +*/ +class BOTAN_PUBLIC_API(2,0) ANSI_X923_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 2 && bs < 256); } + + std::string name() const override { return "X9.23"; } + }; + +/** +* One And Zeros Padding (ISO/IEC 9797-1, padding method 2) +*/ +class BOTAN_PUBLIC_API(2,0) OneAndZeros_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 2); } + + std::string name() const override { return "OneAndZeros"; } + }; + +/** +* ESP Padding (RFC 4304) +*/ +class BOTAN_PUBLIC_API(2,0) ESP_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 2 && bs < 256); } + + std::string name() const override { return "ESP"; } + }; + +/** +* Null Padding +*/ +class BOTAN_PUBLIC_API(2,0) Null_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector&, size_t, size_t) const override + { + /* no padding */ + } + + size_t unpad(const uint8_t[], size_t size) const override { return size; } + + bool valid_blocksize(size_t) const override { return true; } + + std::string name() const override { return "NoPadding"; } + }; + +/** +* Get a block cipher padding mode by name (eg "NoPadding" or "PKCS7") +* @param algo_spec block cipher padding mode name +*/ +BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/stream_mode.h b/comm/third_party/botan/src/lib/modes/stream_mode.h new file mode 100644 index 0000000000..da3fc38cf0 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/stream_mode.h @@ -0,0 +1,84 @@ +/* +* (C) 2015 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREAM_MODE_H_ +#define BOTAN_STREAM_MODE_H_ + +#include + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include +#endif + +BOTAN_FUTURE_INTERNAL_HEADER(stream_mode.h) + +namespace Botan { + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +class BOTAN_PUBLIC_API(2,0) Stream_Cipher_Mode final : public Cipher_Mode + { + public: + /** + * @param cipher underyling stream cipher + */ + explicit Stream_Cipher_Mode(StreamCipher* cipher) : m_cipher(cipher) {} + + size_t process(uint8_t buf[], size_t sz) override + { + m_cipher->cipher1(buf, sz); + return sz; + } + + void finish(secure_vector& buf, size_t offset) override + { return update(buf, offset); } + + size_t output_length(size_t input_length) const override { return input_length; } + + size_t update_granularity() const override { return 1; } + + size_t minimum_final_size() const override { return 0; } + + size_t default_nonce_length() const override { return 0; } + + bool valid_nonce_length(size_t nonce_len) const override + { return m_cipher->valid_iv_length(nonce_len); } + + Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); } + + std::string name() const override { return m_cipher->name(); } + + void clear() override + { + m_cipher->clear(); + reset(); + } + + void reset() override { /* no msg state */ } + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override + { + if(nonce_len > 0) + { + m_cipher->set_iv(nonce, nonce_len); + } + } + + void key_schedule(const uint8_t key[], size_t length) override + { + m_cipher->set_key(key, length); + } + + std::unique_ptr m_cipher; + }; + +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/xts/info.txt b/comm/third_party/botan/src/lib/modes/xts/info.txt new file mode 100644 index 0000000000..cee850be78 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/xts/info.txt @@ -0,0 +1,8 @@ + +MODE_XTS -> 20131128 + + + +block +poly_dbl + diff --git a/comm/third_party/botan/src/lib/modes/xts/xts.cpp b/comm/third_party/botan/src/lib/modes/xts/xts.cpp new file mode 100644 index 0000000000..559584b082 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/xts/xts.cpp @@ -0,0 +1,248 @@ +/* +* XTS Mode +* (C) 2009,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +XTS_Mode::XTS_Mode(BlockCipher* cipher) : + m_cipher(cipher), + m_cipher_block_size(m_cipher->block_size()), + m_cipher_parallelism(m_cipher->parallel_bytes()) + { + if(poly_double_supported_size(m_cipher_block_size) == false) + { + throw Invalid_Argument("Cannot use " + cipher->name() + " with XTS"); + } + + m_tweak_cipher.reset(m_cipher->clone()); + } + +void XTS_Mode::clear() + { + m_cipher->clear(); + m_tweak_cipher->clear(); + reset(); + } + +void XTS_Mode::reset() + { + m_tweak.clear(); + } + +std::string XTS_Mode::name() const + { + return cipher().name() + "/XTS"; + } + +size_t XTS_Mode::minimum_final_size() const + { + return cipher_block_size(); + } + +Key_Length_Specification XTS_Mode::key_spec() const + { + return cipher().key_spec().multiple(2); + } + +size_t XTS_Mode::default_nonce_length() const + { + return cipher_block_size(); + } + +bool XTS_Mode::valid_nonce_length(size_t n) const + { + return cipher_block_size() == n; + } + +void XTS_Mode::key_schedule(const uint8_t key[], size_t length) + { + const size_t key_half = length / 2; + + if(length % 2 == 1 || !m_cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), length); + + m_cipher->set_key(key, key_half); + m_tweak_cipher->set_key(&key[key_half], key_half); + } + +void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + m_tweak.resize(update_granularity()); + copy_mem(m_tweak.data(), nonce, nonce_len); + m_tweak_cipher->encrypt(m_tweak.data()); + + update_tweak(0); + } + +void XTS_Mode::update_tweak(size_t which) + { + const size_t BS = m_tweak_cipher->block_size(); + + if(which > 0) + poly_double_n_le(m_tweak.data(), &m_tweak[(which-1)*BS], BS); + + const size_t blocks_in_tweak = update_granularity() / BS; + + for(size_t i = 1; i < blocks_in_tweak; ++i) + poly_double_n_le(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); + } + +size_t XTS_Encryption::output_length(size_t input_length) const + { + return input_length; + } + +size_t XTS_Encryption::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(tweak_set()); + const size_t BS = cipher_block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + const size_t blocks_in_tweak = update_granularity() / BS; + + while(blocks) + { + const size_t to_proc = std::min(blocks, blocks_in_tweak); + + cipher().encrypt_n_xex(buf, tweak(), to_proc); + + buf += to_proc * BS; + blocks -= to_proc; + + update_tweak(to_proc); + } + + return sz; + } + +void XTS_Encryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS encrypt"); + + const size_t BS = cipher_block_size(); + + if(sz % BS == 0) + { + update(buffer, offset); + } + else + { + // steal ciphertext + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last, tweak(), BS); + cipher().encrypt(last); + xor_buf(last, tweak(), BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + last[i] ^= last[i + BS]; + last[i + BS] ^= last[i]; + last[i] ^= last[i + BS]; + } + + xor_buf(last, tweak() + BS, BS); + cipher().encrypt(last); + xor_buf(last, tweak() + BS, BS); + + buffer += last; + } + } + +size_t XTS_Decryption::output_length(size_t input_length) const + { + return input_length; + } + +size_t XTS_Decryption::process(uint8_t buf[], size_t sz) + { + BOTAN_STATE_CHECK(tweak_set()); + const size_t BS = cipher_block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + const size_t blocks_in_tweak = update_granularity() / BS; + + while(blocks) + { + const size_t to_proc = std::min(blocks, blocks_in_tweak); + + cipher().decrypt_n_xex(buf, tweak(), to_proc); + + buf += to_proc * BS; + blocks -= to_proc; + + update_tweak(to_proc); + } + + return sz; + } + +void XTS_Decryption::finish(secure_vector& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS decrypt"); + + const size_t BS = cipher_block_size(); + + if(sz % BS == 0) + { + update(buffer, offset); + } + else + { + // steal ciphertext + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last, tweak() + BS, BS); + cipher().decrypt(last); + xor_buf(last, tweak() + BS, BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + last[i] ^= last[i + BS]; + last[i + BS] ^= last[i]; + last[i] ^= last[i + BS]; + } + + xor_buf(last, tweak(), BS); + cipher().decrypt(last); + xor_buf(last, tweak(), BS); + + buffer += last; + } + } + +} diff --git a/comm/third_party/botan/src/lib/modes/xts/xts.h b/comm/third_party/botan/src/lib/modes/xts/xts.h new file mode 100644 index 0000000000..75de93c088 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/xts/xts.h @@ -0,0 +1,103 @@ +/* +* XTS mode, from IEEE P1619 +* (C) 2009,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_XTS_H_ +#define BOTAN_MODE_XTS_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(xts.h) + +namespace Botan { + +/** +* IEEE P1619 XTS Mode +*/ +class BOTAN_PUBLIC_API(2,0) XTS_Mode : public Cipher_Mode + { + public: + std::string name() const override; + + size_t update_granularity() const override { return m_cipher_parallelism; } + + size_t minimum_final_size() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear() override; + + void reset() override; + + protected: + explicit XTS_Mode(BlockCipher* cipher); + + const uint8_t* tweak() const { return m_tweak.data(); } + + bool tweak_set() const { return m_tweak.empty() == false; } + + const BlockCipher& cipher() const { return *m_cipher; } + + void update_tweak(size_t last_used); + + size_t cipher_block_size() const { return m_cipher_block_size; } + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + void key_schedule(const uint8_t key[], size_t length) override; + + std::unique_ptr m_cipher; + std::unique_ptr m_tweak_cipher; + secure_vector m_tweak; + const size_t m_cipher_block_size; + const size_t m_cipher_parallelism; + }; + +/** +* IEEE P1619 XTS Encryption +*/ +class BOTAN_PUBLIC_API(2,0) XTS_Encryption final : public XTS_Mode + { + public: + /** + * @param cipher underlying block cipher + */ + explicit XTS_Encryption(BlockCipher* cipher) : XTS_Mode(cipher) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + }; + +/** +* IEEE P1619 XTS Decryption +*/ +class BOTAN_PUBLIC_API(2,0) XTS_Decryption final : public XTS_Mode + { + public: + /** + * @param cipher underlying block cipher + */ + explicit XTS_Decryption(BlockCipher* cipher) : XTS_Mode(cipher) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp new file mode 100644 index 0000000000..1d28ddfb4d --- /dev/null +++ b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.cpp @@ -0,0 +1,181 @@ +/* +* Bcrypt Password Hashing +* (C) 2010,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string bcrypt_base64_encode(const uint8_t input[], size_t length) + { + // Bcrypt uses a non-standard base64 alphabet + const uint8_t OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39, + 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + std::string b64 = base64_encode(input, length); + + while(b64.size() && b64[b64.size()-1] == '=') + b64 = b64.substr(0, b64.size() - 1); + + for(size_t i = 0; i != b64.size(); ++i) + b64[i] = OPENBSD_BASE64_SUB[static_cast(b64[i])]; + + return b64; + } + +std::vector bcrypt_base64_decode(std::string input) + { + const uint8_t OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + for(size_t i = 0; i != input.size(); ++i) + input[i] = OPENBSD_BASE64_SUB[static_cast(input[i])]; + + return unlock(base64_decode(input)); + } + +std::string make_bcrypt(const std::string& pass, + const std::vector& salt, + uint16_t work_factor, + char version) + { + /* + * On a 4 GHz Skylake, workfactor == 18 takes about 15 seconds to + * hash a password. This seems like a reasonable upper bound for the + * time being. + * Bcrypt allows up to work factor 31 (2^31 iterations) + */ + BOTAN_ARG_CHECK(work_factor >= 4 && work_factor <= 18, + "Invalid bcrypt work factor"); + + static const uint8_t BCRYPT_MAGIC[8*3] = { + 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, + 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74 + }; + + Blowfish blowfish; + + // Include the trailing NULL byte, so we need c_str() not data() + blowfish.salted_set_key(cast_char_ptr_to_uint8(pass.c_str()), + pass.length() + 1, + salt.data(), + salt.size(), + work_factor); + + std::vector ctext(BCRYPT_MAGIC, BCRYPT_MAGIC + 8*3); + + for(size_t i = 0; i != 64; ++i) + blowfish.encrypt_n(ctext.data(), ctext.data(), 3); + + std::string salt_b64 = bcrypt_base64_encode(salt.data(), salt.size()); + + std::string work_factor_str = std::to_string(work_factor); + if(work_factor_str.length() == 1) + work_factor_str = "0" + work_factor_str; + + return "$2" + std::string(1, version) + "$" + work_factor_str + + "$" + salt_b64.substr(0, 22) + + bcrypt_base64_encode(ctext.data(), ctext.size() - 1); + } + +} + +std::string generate_bcrypt(const std::string& pass, + RandomNumberGenerator& rng, + uint16_t work_factor, + char version) + { + /* + 2a, 2b and 2y are identical for our purposes because our implementation of 2a + never had the truncation or signed char bugs in the first place. + */ + + if(version != 'a' && version != 'b' && version != 'y') + throw Invalid_Argument("Unknown bcrypt version '" + std::string(1, version) + "'"); + + std::vector salt; + rng.random_vec(salt, 16); + return make_bcrypt(pass, salt, work_factor, version); + } + +bool check_bcrypt(const std::string& pass, const std::string& hash) + { + if(hash.size() != 60 || + hash[0] != '$' || hash[1] != '2' || hash[3] != '$' || hash[6] != '$') + { + return false; + } + + const char bcrypt_version = hash[2]; + + if(bcrypt_version != 'a' && bcrypt_version != 'b' && bcrypt_version != 'y') + { + return false; + } + + const uint16_t workfactor = to_uint16(hash.substr(4, 2)); + + const std::vector salt = bcrypt_base64_decode(hash.substr(7, 22)); + if(salt.size() != 16) + return false; + + const std::string compare = make_bcrypt(pass, salt, workfactor, bcrypt_version); + + return same_mem(hash.data(), compare.data(), compare.size()); + } + +} diff --git a/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h new file mode 100644 index 0000000000..cdf9cf3d19 --- /dev/null +++ b/comm/third_party/botan/src/lib/passhash/bcrypt/bcrypt.h @@ -0,0 +1,49 @@ +/* +* Bcrypt Password Hashing +* (C) 2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BCRYPT_H_ +#define BOTAN_BCRYPT_H_ + +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Create a password hash using Bcrypt +* +* @warning The password is truncated at at most 72 characters; characters after +* that do not have any effect on the resulting hash. To support longer +* passwords, consider pre-hashing the password, for example by using +* the hex encoding of SHA-256 of the password as the input to bcrypt. +* +* @param password the password. +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* @param version which version to emit (may be 'a', 'b', or 'y' all of which +* have identical behavior in this implementation). +* +* @see https://www.usenix.org/events/usenix99/provos/provos_html/ +*/ +std::string BOTAN_PUBLIC_API(2,0) generate_bcrypt(const std::string& password, + RandomNumberGenerator& rng, + uint16_t work_factor = 12, + char version = 'a'); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_PUBLIC_API(2,0) check_bcrypt(const std::string& password, + const std::string& hash); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/passhash/bcrypt/info.txt b/comm/third_party/botan/src/lib/passhash/bcrypt/info.txt new file mode 100644 index 0000000000..6be060ea0f --- /dev/null +++ b/comm/third_party/botan/src/lib/passhash/bcrypt/info.txt @@ -0,0 +1,9 @@ + +BCRYPT -> 20131128 + + + +blowfish +rng +base64 + diff --git a/comm/third_party/botan/src/lib/passhash/passhash9/info.txt b/comm/third_party/botan/src/lib/passhash/passhash9/info.txt new file mode 100644 index 0000000000..525427b45d --- /dev/null +++ b/comm/third_party/botan/src/lib/passhash/passhash9/info.txt @@ -0,0 +1,9 @@ + +PASSHASH9 -> 20131128 + + + +pbkdf2 +rng +base64 + diff --git a/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp new file mode 100644 index 0000000000..98f5a54d51 --- /dev/null +++ b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.cpp @@ -0,0 +1,142 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const std::string MAGIC_PREFIX = "$9$"; + +const size_t WORKFACTOR_BYTES = 2; +const size_t ALGID_BYTES = 1; +const size_t SALT_BYTES = 12; // 96 bits of salt +const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output + +const size_t WORK_FACTOR_SCALE = 10000; + +std::unique_ptr get_pbkdf_prf(uint8_t alg_id) + { + if(alg_id == 0) + return MessageAuthenticationCode::create("HMAC(SHA-1)"); + else if(alg_id == 1) + return MessageAuthenticationCode::create("HMAC(SHA-256)"); + else if(alg_id == 2) + return MessageAuthenticationCode::create("CMAC(Blowfish)"); + else if(alg_id == 3) + return MessageAuthenticationCode::create("HMAC(SHA-384)"); + else if(alg_id == 4) + return MessageAuthenticationCode::create("HMAC(SHA-512)"); + return nullptr; + } + +} + +std::string generate_passhash9(const std::string& pass, + RandomNumberGenerator& rng, + uint16_t work_factor, + uint8_t alg_id) + { + BOTAN_ARG_CHECK(work_factor > 0 && work_factor < 512, "Invalid Passhash9 work factor"); + + std::unique_ptr prf = get_pbkdf_prf(alg_id); + + if(!prf) + throw Invalid_Argument("Passhash9: Algorithm id " + + std::to_string(alg_id) + + " is not defined"); + + PKCS5_PBKDF2 kdf(prf.release()); // takes ownership of pointer + + secure_vector salt(SALT_BYTES); + rng.randomize(salt.data(), salt.size()); + + const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + secure_vector blob; + blob.push_back(alg_id); + blob.push_back(get_byte(0, work_factor)); + blob.push_back(get_byte(1, work_factor)); + blob += salt; + blob += kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN, + pass, + salt.data(), salt.size(), + kdf_iterations).bits_of(); + + return MAGIC_PREFIX + base64_encode(blob); + } + +bool check_passhash9(const std::string& pass, const std::string& hash) + { + const size_t BINARY_LENGTH = + ALGID_BYTES + + WORKFACTOR_BYTES + + PASSHASH9_PBKDF_OUTPUT_LEN + + SALT_BYTES; + + const size_t BASE64_LENGTH = + MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6; + + if(hash.size() != BASE64_LENGTH) + return false; + + for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) + if(hash[i] != MAGIC_PREFIX[i]) + return false; + + secure_vector bin = base64_decode(hash.c_str() + MAGIC_PREFIX.size()); + + if(bin.size() != BINARY_LENGTH) + return false; + + uint8_t alg_id = bin[0]; + + const size_t work_factor = load_be(&bin[ALGID_BYTES], 0); + + // Bug in the format, bad states shouldn't be representable, but are... + if(work_factor == 0) + return false; + + if(work_factor > 512) + throw Invalid_Argument("Requested passhash9 work factor " + + std::to_string(work_factor) + " is too large"); + + const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + std::unique_ptr pbkdf_prf = get_pbkdf_prf(alg_id); + + if(!pbkdf_prf) + return false; // unknown algorithm, reject + + PKCS5_PBKDF2 kdf(pbkdf_prf.release()); // takes ownership of pointer + + secure_vector cmp = kdf.derive_key( + PASSHASH9_PBKDF_OUTPUT_LEN, + pass, + &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES, + kdf_iterations).bits_of(); + + return constant_time_compare(cmp.data(), + &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES], + PASSHASH9_PBKDF_OUTPUT_LEN); + } + +bool is_passhash9_alg_supported(uint8_t alg_id) + { + if (get_pbkdf_prf(alg_id)) + { + return true; + } + return false; + } + +} diff --git a/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h new file mode 100644 index 0000000000..b312cb1bf9 --- /dev/null +++ b/comm/third_party/botan/src/lib/passhash/passhash9/passhash9.h @@ -0,0 +1,52 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PASSHASH9_H_ +#define BOTAN_PASSHASH9_H_ + +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Create a password hash using PBKDF2 +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* @param alg_id specifies which PRF to use with PBKDF2 +* 0 is HMAC(SHA-1) +* 1 is HMAC(SHA-256) +* 2 is CMAC(Blowfish) +* 3 is HMAC(SHA-384) +* 4 is HMAC(SHA-512) +* all other values are currently undefined +*/ +std::string BOTAN_PUBLIC_API(2,0) generate_passhash9(const std::string& password, + RandomNumberGenerator& rng, + uint16_t work_factor = 15, + uint8_t alg_id = 4); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_PUBLIC_API(2,0) check_passhash9(const std::string& password, + const std::string& hash); + +/** +* Check if the PRF used with PBKDF2 is supported +* @param alg_id alg_id used in generate_passhash9() +*/ +bool BOTAN_PUBLIC_API(2,3) is_passhash9_alg_supported(uint8_t alg_id); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/argon2/argon2.cpp b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2.cpp new file mode 100644 index 0000000000..0d767e04e7 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2.cpp @@ -0,0 +1,443 @@ +/** +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +static const size_t SYNC_POINTS = 4; + +secure_vector argon2_H0(HashFunction& blake2b, + size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t key[], size_t key_len, + const uint8_t ad[], size_t ad_len, + size_t y, size_t p, size_t M, size_t t) + { + const uint8_t v = 19; // Argon2 version code + + blake2b.update_le(static_cast(p)); + blake2b.update_le(static_cast(output_len)); + blake2b.update_le(static_cast(M)); + blake2b.update_le(static_cast(t)); + blake2b.update_le(static_cast(v)); + blake2b.update_le(static_cast(y)); + + blake2b.update_le(static_cast(password_len)); + blake2b.update(cast_char_ptr_to_uint8(password), password_len); + + blake2b.update_le(static_cast(salt_len)); + blake2b.update(salt, salt_len); + + blake2b.update_le(static_cast(key_len)); + blake2b.update(key, key_len); + + blake2b.update_le(static_cast(ad_len)); + blake2b.update(ad, ad_len); + + return blake2b.final(); + } + +void Htick(secure_vector& T, + uint8_t output[], + size_t output_len, + HashFunction& blake2b, + const secure_vector& H0, + size_t p0, size_t p1) + { + BOTAN_ASSERT_NOMSG(output_len % 64 == 0); + + blake2b.update_le(static_cast(output_len)); + blake2b.update(H0); + blake2b.update_le(static_cast(p0)); + blake2b.update_le(static_cast(p1)); + + blake2b.final(&T[0]); + + while(output_len > 64) + { + copy_mem(output, &T[0], 32); + output_len -= 32; + output += 32; + + blake2b.update(T); + blake2b.final(&T[0]); + } + + if(output_len > 0) + copy_mem(output, &T[0], output_len); + } + +void extract_key(uint8_t output[], size_t output_len, + const secure_vector& B, + size_t memory, size_t threads) + { + const size_t lanes = memory / threads; + + secure_vector sum(128); + + for(size_t lane = 0; lane != threads; ++lane) + { + size_t start = 128*(lane * lanes + lanes - 1); + size_t end = 128*(lane * lanes + lanes); + + for(size_t j = start; j != end; ++j) + { + sum[j % 128] ^= B[j]; + } + } + + secure_vector sum8(1024); + copy_out_le(sum8.data(), 1024, sum.data()); + + if(output_len <= 64) + { + std::unique_ptr blake2b = HashFunction::create_or_throw("BLAKE2b(" + std::to_string(output_len*8) + ")"); + blake2b->update_le(static_cast(output_len)); + blake2b->update(sum8.data(), sum8.size()); + blake2b->final(output); + } + else + { + secure_vector T(64); + + std::unique_ptr blake2b = HashFunction::create_or_throw("BLAKE2b(512)"); + blake2b->update_le(static_cast(output_len)); + blake2b->update(sum8.data(), sum8.size()); + blake2b->final(&T[0]); + + while(output_len > 64) + { + copy_mem(output, &T[0], 32); + output_len -= 32; + output += 32; + + if(output_len > 64) + { + blake2b->update(T); + blake2b->final(&T[0]); + } + } + + if(output_len == 64) + { + blake2b->update(T); + blake2b->final(output); + } + else + { + std::unique_ptr blake2b_f = HashFunction::create_or_throw("BLAKE2b(" + std::to_string(output_len*8) + ")"); + blake2b_f->update(T); + blake2b_f->final(output); + } + } + } + +void init_blocks(secure_vector& B, + HashFunction& blake2b, + const secure_vector& H0, + size_t memory, + size_t threads) + { + BOTAN_ASSERT_NOMSG(B.size() >= threads*256); + + secure_vector H(1024); + secure_vector T(blake2b.output_length()); + + for(size_t i = 0; i != threads; ++i) + { + const size_t B_off = i * (memory / threads); + + BOTAN_ASSERT_NOMSG(B.size() >= 128*(B_off+2)); + + Htick(T, &H[0], H.size(), blake2b, H0, 0, i); + + for(size_t j = 0; j != 128; ++j) + { + B[128*B_off+j] = load_le(H.data(), j); + } + + Htick(T, &H[0], H.size(), blake2b, H0, 1, i); + + for(size_t j = 0; j != 128; ++j) + { + B[128*(B_off+1)+j] = load_le(H.data(), j); + } + } + } + +inline void blamka_G(uint64_t& A, uint64_t& B, uint64_t& C, uint64_t& D) + { + A += B + (static_cast(2) * static_cast(A)) * static_cast(B); + D = rotr<32>(A ^ D); + + C += D + (static_cast(2) * static_cast(C)) * static_cast(D); + B = rotr<24>(B ^ C); + + A += B + (static_cast(2) * static_cast(A)) * static_cast(B); + D = rotr<16>(A ^ D); + + C += D + (static_cast(2) * static_cast(C)) * static_cast(D); + B = rotr<63>(B ^ C); + } + +inline void blamka(uint64_t& V0, uint64_t& V1, uint64_t& V2, uint64_t& V3, + uint64_t& V4, uint64_t& V5, uint64_t& V6, uint64_t& V7, + uint64_t& V8, uint64_t& V9, uint64_t& VA, uint64_t& VB, + uint64_t& VC, uint64_t& VD, uint64_t& VE, uint64_t& VF) + { + blamka_G(V0, V4, V8, VC); + blamka_G(V1, V5, V9, VD); + blamka_G(V2, V6, VA, VE); + blamka_G(V3, V7, VB, VF); + + blamka_G(V0, V5, VA, VF); + blamka_G(V1, V6, VB, VC); + blamka_G(V2, V7, V8, VD); + blamka_G(V3, V4, V9, VE); + } + +void process_block_xor(secure_vector& T, + secure_vector& B, + size_t offset, + size_t prev, + size_t new_offset) + { + for(size_t i = 0; i != 128; ++i) + T[i] = B[128*prev+i] ^ B[128*new_offset+i]; + + for(size_t i = 0; i != 128; i += 16) + { + blamka(T[i+ 0], T[i+ 1], T[i+ 2], T[i+ 3], + T[i+ 4], T[i+ 5], T[i+ 6], T[i+ 7], + T[i+ 8], T[i+ 9], T[i+10], T[i+11], + T[i+12], T[i+13], T[i+14], T[i+15]); + } + + for(size_t i = 0; i != 128 / 8; i += 2) + { + blamka(T[ i], T[ i+1], T[ 16+i], T[ 16+i+1], + T[ 32+i], T[ 32+i+1], T[ 48+i], T[ 48+i+1], + T[ 64+i], T[ 64+i+1], T[ 80+i], T[ 80+i+1], + T[ 96+i], T[ 96+i+1], T[112+i], T[112+i+1]); + } + + for(size_t i = 0; i != 128; ++i) + B[128*offset + i] ^= T[i] ^ B[128*prev+i] ^ B[128*new_offset+i]; + } + +void gen_2i_addresses(secure_vector& T, secure_vector& B, + size_t n, size_t lane, size_t slice, size_t memory, + size_t time, size_t mode, size_t cnt) + { + BOTAN_ASSERT_NOMSG(B.size() == 128); + BOTAN_ASSERT_NOMSG(T.size() == 128); + + clear_mem(B.data(), B.size()); + B[0] = n; + B[1] = lane; + B[2] = slice; + B[3] = memory; + B[4] = time; + B[5] = mode; + B[6] = cnt; + + for(size_t r = 0; r != 2; ++r) + { + copy_mem(T.data(), B.data(), B.size()); + + for(size_t i = 0; i != 128; i += 16) + { + blamka(T[i+ 0], T[i+ 1], T[i+ 2], T[i+ 3], + T[i+ 4], T[i+ 5], T[i+ 6], T[i+ 7], + T[i+ 8], T[i+ 9], T[i+10], T[i+11], + T[i+12], T[i+13], T[i+14], T[i+15]); + } + for(size_t i = 0; i != 128 / 8; i += 2) + { + blamka(T[ i], T[ i+1], T[ 16+i], T[ 16+i+1], + T[ 32+i], T[ 32+i+1], T[ 48+i], T[ 48+i+1], + T[ 64+i], T[ 64+i+1], T[ 80+i], T[ 80+i+1], + T[ 96+i], T[ 96+i+1], T[112+i], T[112+i+1]); + } + + for(size_t i = 0; i != 128; ++i) + B[i] ^= T[i]; + } + } + +uint32_t index_alpha(uint64_t random, + size_t lanes, + size_t segments, + size_t threads, + size_t n, + size_t slice, + size_t lane, + size_t index) + { + size_t ref_lane = static_cast(random >> 32) % threads; + + if(n == 0 && slice == 0) + ref_lane = lane; + + size_t m = 3*segments; + size_t s = ((slice+1) % 4)*segments; + + if(lane == ref_lane) + m += index; + + if(n == 0) { + m = slice*segments; + s = 0; + if(slice == 0 || lane == ref_lane) + m += index; + } + + if(index == 0 || lane == ref_lane) + m -= 1; + + uint64_t p = static_cast(random); + p = (p * p) >> 32; + p = (p * m) >> 32; + + return static_cast(ref_lane*lanes + (s + m - (p+1)) % lanes); + } + +void process_block_argon2d(secure_vector& T, + secure_vector& B, + size_t n, size_t slice, size_t lane, + size_t lanes, size_t segments, size_t threads) + { + size_t index = 0; + if(n == 0 && slice == 0) + index = 2; + + while(index < segments) + { + const size_t offset = lane*lanes + slice*segments + index; + + size_t prev = offset - 1; + if(index == 0 && slice == 0) + prev += lanes; + + const uint64_t random = B.at(128*prev); + const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index); + + process_block_xor(T, B, offset, prev, new_offset); + + index += 1; + } + } + +void process_block_argon2i(secure_vector& T, + secure_vector& B, + size_t n, size_t slice, size_t lane, + size_t lanes, size_t segments, size_t threads, uint8_t mode, + size_t memory, size_t time) + { + size_t index = 0; + if(n == 0 && slice == 0) + index = 2; + + secure_vector addresses(128); + size_t address_counter = 1; + + gen_2i_addresses(T, addresses, n, lane, slice, memory, time, mode, address_counter); + + while(index < segments) + { + const size_t offset = lane*lanes + slice*segments + index; + + size_t prev = offset - 1; + if(index == 0 && slice == 0) + prev += lanes; + + if(index > 0 && index % 128 == 0) + { + address_counter += 1; + gen_2i_addresses(T, addresses, n, lane, slice, memory, time, mode, address_counter); + } + + const uint64_t random = addresses[index % 128]; + const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index); + + process_block_xor(T, B, offset, prev, new_offset); + + index += 1; + } + } + +void process_blocks(secure_vector& B, + size_t t, + size_t memory, + size_t threads, + uint8_t mode) + { + const size_t lanes = memory / threads; + const size_t segments = lanes / SYNC_POINTS; + + secure_vector T(128); + for(size_t n = 0; n != t; ++n) + { + for(size_t slice = 0; slice != SYNC_POINTS; ++slice) + { + // TODO can run this in Thread_Pool + for(size_t lane = 0; lane != threads; ++lane) + { + if(mode == 1 || (mode == 2 && n == 0 && slice < SYNC_POINTS/2)) + process_block_argon2i(T, B, n, slice, lane, lanes, segments, threads, mode, memory, t); + else + process_block_argon2d(T, B, n, slice, lane, lanes, segments, threads); + } + } + } + + } + +} + +void argon2(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t key[], size_t key_len, + const uint8_t ad[], size_t ad_len, + uint8_t mode, size_t threads, size_t M, size_t t) + { + BOTAN_ARG_CHECK(mode == 0 || mode == 1 || mode == 2, "Unknown Argon2 mode parameter"); + BOTAN_ARG_CHECK(output_len >= 4, "Invalid Argon2 output length"); + BOTAN_ARG_CHECK(threads >= 1 && threads <= 128, "Invalid Argon2 threads parameter"); + BOTAN_ARG_CHECK(M >= 8*threads && M <= 8192*1024, "Invalid Argon2 M parameter"); + BOTAN_ARG_CHECK(t >= 1, "Invalid Argon2 t parameter"); + + std::unique_ptr blake2 = HashFunction::create_or_throw("BLAKE2b"); + + const auto H0 = argon2_H0(*blake2, output_len, + password, password_len, + salt, salt_len, + key, key_len, + ad, ad_len, + mode, threads, M, t); + + const size_t memory = (M / (SYNC_POINTS*threads)) * (SYNC_POINTS*threads); + + secure_vector B(memory * 1024/8); + + init_blocks(B, *blake2, H0, memory, threads); + process_blocks(B, t, memory, threads, mode); + + clear_mem(output, output_len); + extract_key(output, output_len, B, memory, threads); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/argon2/argon2.h b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2.h new file mode 100644 index 0000000000..3a1b859f0c --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2.h @@ -0,0 +1,118 @@ +/** +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ARGON2_H_ +#define BOTAN_ARGON2_H_ + +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(argon2.h) + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Argon2 key derivation function +*/ +class BOTAN_PUBLIC_API(2,11) Argon2 final : public PasswordHash + { + public: + Argon2(uint8_t family, size_t M, size_t t, size_t p); + + Argon2(const Argon2& other) = default; + Argon2& operator=(const Argon2&) = default; + + /** + * Derive a new key under the current Argon2 parameter set + */ + void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const override; + + std::string to_string() const override; + + size_t M() const { return m_M; } + size_t t() const { return m_t; } + size_t p() const { return m_p; } + + size_t iterations() const override { return t(); } + + size_t parallelism() const override { return p(); } + + size_t memory_param() const override { return M(); } + + size_t total_memory_usage() const override { return M() * 1024; } + + private: + uint8_t m_family; + size_t m_M, m_t, m_p; + }; + +class BOTAN_PUBLIC_API(2,11) Argon2_Family final : public PasswordHashFamily + { + public: + Argon2_Family(uint8_t family); + + std::string name() const override; + + std::unique_ptr tune(size_t output_length, + std::chrono::milliseconds msec, + size_t max_memory) const override; + + std::unique_ptr default_params() const override; + + std::unique_ptr from_iterations(size_t iter) const override; + + std::unique_ptr from_params( + size_t M, size_t t, size_t p) const override; + private: + const uint8_t m_family; + }; + +/** +* Argon2 key derivation function +* +* @param output the output will be placed here +* @param output_len length of output +* @param password the user password +* @param password_len the length of password +* @param salt the salt +* @param salt_len length of salt +* @param key an optional secret key +* @param key_len the length of key +* @param ad an optional additional input +* @param ad_len the length of ad +* @param y the Argon2 variant (0 = Argon2d, 1 = Argon2i, 2 = Argon2id) +* @param p the parallelization parameter +* @param M the amount of memory to use in Kb +* @param t the number of iterations to use +*/ +void BOTAN_PUBLIC_API(2,11) argon2(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t key[], size_t key_len, + const uint8_t ad[], size_t ad_len, + uint8_t y, size_t p, size_t M, size_t t); + +std::string BOTAN_PUBLIC_API(2,11) + argon2_generate_pwhash(const char* password, size_t password_len, + RandomNumberGenerator& rng, + size_t p, size_t M, size_t t, + uint8_t y = 2, size_t salt_len = 16, size_t output_len = 32); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param password_len the length of password +* @param hash the stored hash to check against +*/ +bool BOTAN_PUBLIC_API(2,11) argon2_check_pwhash(const char* password, size_t password_len, + const std::string& hash); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/argon2/argon2fmt.cpp b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2fmt.cpp new file mode 100644 index 0000000000..480be5fa36 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2fmt.cpp @@ -0,0 +1,125 @@ +/** +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::string strip_padding(std::string s) + { + while(s.size() > 0 && s[s.size()-1] == '=') + s.resize(s.size() - 1); + return s; + } + +} + +std::string argon2_generate_pwhash(const char* password, size_t password_len, + RandomNumberGenerator& rng, + size_t p, size_t M, size_t t, + uint8_t y, size_t salt_len, size_t output_len) + { + std::vector salt(salt_len); + rng.randomize(salt.data(), salt.size()); + + std::vector output(output_len); + argon2(output.data(), output.size(), + password, password_len, + salt.data(), salt.size(), + nullptr, 0, + nullptr, 0, + y, p, M, t); + + std::ostringstream oss; + + if(y == 0) + oss << "$argon2d$"; + else if(y == 1) + oss << "$argon2i$"; + else + oss << "$argon2id$"; + + oss << "v=19$m=" << M << ",t=" << t << ",p=" << p << "$"; + oss << strip_padding(base64_encode(salt)) << "$" << strip_padding(base64_encode(output)); + + return oss.str(); + } + +bool argon2_check_pwhash(const char* password, size_t password_len, + const std::string& input_hash) + { + const std::vector parts = split_on(input_hash, '$'); + + if(parts.size() != 5) + return false; + + uint8_t family = 0; + + if(parts[0] == "argon2d") + family = 0; + else if(parts[0] == "argon2i") + family = 1; + else if(parts[0] == "argon2id") + family = 2; + else + return false; + + if(parts[1] != "v=19") + return false; + + const std::vector params = split_on(parts[2], ','); + + if(params.size() != 3) + return false; + + size_t M = 0, t = 0, p = 0; + + for(auto param_str : params) + { + const std::vector param = split_on(param_str, '='); + + if(param.size() != 2) + return false; + + const std::string key = param[0]; + const size_t val = to_u32bit(param[1]); + if(key == "m") + M = val; + else if(key == "t") + t = val; + else if(key == "p") + p = val; + else + return false; + } + + std::vector salt(base64_decode_max_output(parts[3].size())); + salt.resize(base64_decode(salt.data(), parts[3], false)); + + std::vector hash(base64_decode_max_output(parts[4].size())); + hash.resize(base64_decode(hash.data(), parts[4], false)); + + if(hash.size() < 4) + return false; + + std::vector generated(hash.size()); + argon2(generated.data(), generated.size(), + password, password_len, + salt.data(), salt.size(), + nullptr, 0, + nullptr, 0, + family, p, M, t); + + return constant_time_compare(generated.data(), hash.data(), generated.size()); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/argon2/argon2pwhash.cpp b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2pwhash.cpp new file mode 100644 index 0000000000..96f7f74fee --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/argon2/argon2pwhash.cpp @@ -0,0 +1,154 @@ +/** +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +Argon2::Argon2(uint8_t family, size_t M, size_t t, size_t p) : + m_family(family), + m_M(M), + m_t(t), + m_p(p) + {} + +void Argon2::derive_key(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const + { + argon2(output, output_len, + password, password_len, + salt, salt_len, + nullptr, 0, + nullptr, 0, + m_family, m_p, m_M, m_t); + } + +namespace { + +std::string argon2_family_name(uint8_t f) + { + switch(f) + { + case 0: + return "Argon2d"; + case 1: + return "Argon2i"; + case 2: + return "Argon2id"; + default: + throw Invalid_Argument("Unknown Argon2 parameter"); + } + } + +} + +std::string Argon2::to_string() const + { + return argon2_family_name(m_family) + "(" + + std::to_string(m_M) + "," + + std::to_string(m_t) + "," + + std::to_string(m_p) + ")"; + } + +Argon2_Family::Argon2_Family(uint8_t family) : m_family(family) + { + if(m_family != 0 && m_family != 1 && m_family != 2) + throw Invalid_Argument("Unknown Argon2 family identifier"); + } + +std::string Argon2_Family::name() const + { + return argon2_family_name(m_family); + } + +std::unique_ptr Argon2_Family::tune(size_t /*output_length*/, + std::chrono::milliseconds msec, + size_t max_memory) const + { + const size_t max_kib = (max_memory == 0) ? 256*1024 : max_memory*1024; + + // Tune with a large memory otherwise we measure cache vs RAM speeds and underestimate + // costs for larger params. Default is 36 MiB, or use 128 for long times. + const size_t tune_M = (msec >= std::chrono::milliseconds(500) ? 128 : 36) * 1024; + const size_t p = 1; + size_t t = 1; + + Timer timer("Argon2"); + const auto tune_time = BOTAN_PBKDF_TUNING_TIME; + + timer.run_until_elapsed(tune_time, [&]() { + uint8_t output[64] = { 0 }; + argon2(output, sizeof(output), "test", 4, nullptr, 0, nullptr, 0, nullptr, 0, m_family, p, tune_M, t); + }); + + if(timer.events() == 0 || timer.value() == 0) + return default_params(); + + size_t M = 4*1024; + + const uint64_t measured_time = timer.value() / (timer.events() * (tune_M / M)); + + const uint64_t target_nsec = msec.count() * static_cast(1000000); + + /* + * Argon2 scaling rules: + * k*M, k*t, k*p all increase cost by about k + * + * Since we don't even take advantage of p > 1, we prefer increasing + * t or M instead. + * + * If possible to increase M, prefer that. + */ + + uint64_t est_nsec = measured_time; + + if(est_nsec < target_nsec && M < max_kib) + { + const uint64_t desired_cost_increase = (target_nsec + est_nsec - 1) / est_nsec; + const uint64_t mem_headroom = max_kib / M; + + const uint64_t M_mult = std::min(desired_cost_increase, mem_headroom); + M *= static_cast(M_mult); + est_nsec *= M_mult; + } + + if(est_nsec < target_nsec) + { + const uint64_t desired_cost_increase = (target_nsec + est_nsec - 1) / est_nsec; + t *= static_cast(desired_cost_increase); + } + + return this->from_params(M, t, p); + } + +std::unique_ptr Argon2_Family::default_params() const + { + return this->from_params(128*1024, 1, 1); + } + +std::unique_ptr Argon2_Family::from_iterations(size_t iter) const + { + /* + These choices are arbitrary, but should not change in future + releases since they will break applications expecting deterministic + mapping from iteration count to params + */ + const size_t M = iter; + const size_t t = 1; + const size_t p = 1; + return this->from_params(M, t, p); + } + +std::unique_ptr Argon2_Family::from_params(size_t M, size_t t, size_t p) const + { + return std::unique_ptr(new Argon2(m_family, M, t, p)); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/argon2/info.txt b/comm/third_party/botan/src/lib/pbkdf/argon2/info.txt new file mode 100644 index 0000000000..91e85d0c47 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/argon2/info.txt @@ -0,0 +1,9 @@ + +ARGON2 -> 20190824 + + + +blake2 +base64 + + diff --git a/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.cpp b/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.cpp new file mode 100644 index 0000000000..2f2c770256 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.cpp @@ -0,0 +1,183 @@ +/* +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +void Bcrypt_PBKDF::derive_key(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const + { + bcrypt_pbkdf(output, output_len, + password, password_len, + salt, salt_len, + m_iterations); + } + +std::string Bcrypt_PBKDF::to_string() const + { + return "Bcrypt-PBKDF(" + std::to_string(m_iterations) + ")"; + } + +std::string Bcrypt_PBKDF_Family::name() const + { + return "Bcrypt-PBKDF"; + } + +std::unique_ptr Bcrypt_PBKDF_Family::tune(size_t output_length, + std::chrono::milliseconds msec, + size_t /*max_memory*/) const + { + Timer timer("Bcrypt_PBKDF"); + const auto tune_time = BOTAN_PBKDF_TUNING_TIME; + + const size_t blocks = (output_length + 32 - 1) / 32; + + if(blocks == 0) + return default_params(); + + const size_t starting_iter = 2; + + timer.run_until_elapsed(tune_time, [&]() { + uint8_t output[32] = { 0 }; + bcrypt_pbkdf(output, sizeof(output), "test", 4, nullptr, 0, starting_iter); + }); + + if(timer.events() < blocks || timer.value() == 0) + return default_params(); + + const uint64_t measured_time = timer.value() / (timer.events() / blocks); + + const uint64_t target_nsec = msec.count() * static_cast(1000000); + + const uint64_t desired_increase = target_nsec / measured_time; + + if(desired_increase == 0) + return this->from_iterations(starting_iter); + + return this->from_iterations(static_cast(desired_increase * starting_iter)); + } + +std::unique_ptr Bcrypt_PBKDF_Family::default_params() const + { + return this->from_iterations(32); // About 100 ms on fast machine + } + +std::unique_ptr Bcrypt_PBKDF_Family::from_iterations(size_t iter) const + { + return std::unique_ptr(new Bcrypt_PBKDF(iter)); + } + +std::unique_ptr Bcrypt_PBKDF_Family::from_params(size_t iter, size_t /*t*/, size_t /*p*/) const + { + return this->from_iterations(iter); + } + +namespace { + +void bcrypt_round(Blowfish& blowfish, + const secure_vector& pass_hash, + const secure_vector& salt_hash, + secure_vector& out, + secure_vector& tmp) + { + const size_t BCRYPT_PBKDF_OUTPUT = 32; + + // "OxychromaticBlowfishSwatDynamite" + static const uint8_t BCRYPT_PBKDF_MAGIC[BCRYPT_PBKDF_OUTPUT] = { + 0x4F, 0x78, 0x79, 0x63, 0x68, 0x72, 0x6F, 0x6D, + 0x61, 0x74, 0x69, 0x63, 0x42, 0x6C, 0x6F, 0x77, + 0x66, 0x69, 0x73, 0x68, 0x53, 0x77, 0x61, 0x74, + 0x44, 0x79, 0x6E, 0x61, 0x6D, 0x69, 0x74, 0x65 + }; + + const size_t BCRYPT_PBKDF_WORKFACTOR = 6; + const size_t BCRYPT_PBKDF_ROUNDS = 64; + + blowfish.salted_set_key(pass_hash.data(), pass_hash.size(), + salt_hash.data(), salt_hash.size(), + BCRYPT_PBKDF_WORKFACTOR, true); + + copy_mem(tmp.data(), BCRYPT_PBKDF_MAGIC, BCRYPT_PBKDF_OUTPUT); + for(size_t i = 0; i != BCRYPT_PBKDF_ROUNDS; ++i) + blowfish.encrypt(tmp); + + /* + Bcrypt PBKDF loads the Blowfish output as big endian for no reason + in particular. We can't just swap everything once at the end + because the (big-endian) values are fed into SHA-512 to generate + the salt for the next round + */ + for(size_t i = 0; i != 32/4; ++i) + { + const uint32_t w = load_le(tmp.data(), i); + store_be(w, &tmp[sizeof(uint32_t)*i]); + } + + xor_buf(out.data(), tmp.data(), BCRYPT_PBKDF_OUTPUT); + } + +} + +void bcrypt_pbkdf(uint8_t output[], size_t output_len, + const char* pass, size_t pass_len, + const uint8_t salt[], size_t salt_len, + size_t rounds) + { + BOTAN_ARG_CHECK(rounds >= 1, "Invalid rounds for Bcrypt PBKDF"); + + // No output desired, so we are all done already... + if(output_len == 0) + return; + + BOTAN_ARG_CHECK(output_len <= 10*1024*1024, "Too much output for Bcrypt PBKDF"); + + const size_t BCRYPT_BLOCK_SIZE = 32; + const size_t blocks = (output_len + BCRYPT_BLOCK_SIZE - 1) / BCRYPT_BLOCK_SIZE; + + std::unique_ptr sha512 = HashFunction::create_or_throw("SHA-512"); + const secure_vector pass_hash = sha512->process(reinterpret_cast(pass), pass_len); + + secure_vector salt_hash(sha512->output_length()); + + Blowfish blowfish; + secure_vector out(BCRYPT_BLOCK_SIZE); + secure_vector tmp(BCRYPT_BLOCK_SIZE); + + for(size_t block = 0; block != blocks; ++block) + { + clear_mem(out.data(), out.size()); + + sha512->update(salt, salt_len); + sha512->update_be(static_cast(block + 1)); + sha512->final(salt_hash.data()); + + bcrypt_round(blowfish, pass_hash, salt_hash, out, tmp); + + for(size_t r = 1; r != rounds; ++r) + { + // Next salt is H(prev_output) + sha512->update(tmp); + sha512->final(salt_hash.data()); + + bcrypt_round(blowfish, pass_hash, salt_hash, out, tmp); + } + + for(size_t i = 0; i != BCRYPT_BLOCK_SIZE; ++i) + { + const size_t dest = i * blocks + block; + if(dest < output_len) + output[dest] = out[i]; + } + } + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.h b/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.h new file mode 100644 index 0000000000..0d459e8dbc --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/bcrypt_pbkdf.h @@ -0,0 +1,77 @@ +/* +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBKDF_BCRYPT_H_ +#define BOTAN_PBKDF_BCRYPT_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(bcrypt_pbkdf.h) + +namespace Botan { + +/** +* Bcrypt-PBKDF key derivation function +*/ +class BOTAN_PUBLIC_API(2,11) Bcrypt_PBKDF final : public PasswordHash + { + public: + Bcrypt_PBKDF(size_t iterations) : m_iterations(iterations) {} + + Bcrypt_PBKDF(const Bcrypt_PBKDF& other) = default; + Bcrypt_PBKDF& operator=(const Bcrypt_PBKDF&) = default; + + /** + * Derive a new key under the current Bcrypt-PBKDF parameter set + */ + void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const override; + + std::string to_string() const override; + + size_t iterations() const override { return m_iterations; } + + size_t parallelism() const override { return 0; } + + size_t memory_param() const override { return 0; } + + size_t total_memory_usage() const override { return 4096; } + + private: + size_t m_iterations; + }; + +class BOTAN_PUBLIC_API(2,11) Bcrypt_PBKDF_Family final : public PasswordHashFamily + { + public: + Bcrypt_PBKDF_Family() {} + + std::string name() const override; + + std::unique_ptr tune(size_t output_length, + std::chrono::milliseconds msec, + size_t max_memory) const override; + + std::unique_ptr default_params() const override; + + std::unique_ptr from_iterations(size_t iter) const override; + + std::unique_ptr from_params( + size_t i, size_t, size_t) const override; + }; + +/** +* Bcrypt PBKDF compatible with OpenBSD bcrypt_pbkdf +*/ +void BOTAN_UNSTABLE_API bcrypt_pbkdf(uint8_t output[], size_t output_len, + const char* pass, size_t pass_len, + const uint8_t salt[], size_t salt_len, + size_t rounds); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/info.txt b/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/info.txt new file mode 100644 index 0000000000..0e2b10178e --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/bcrypt_pbkdf/info.txt @@ -0,0 +1,8 @@ + +PBKDF_BCRYPT -> 20190531 + + + +blowfish +sha2_64 + diff --git a/comm/third_party/botan/src/lib/pbkdf/info.txt b/comm/third_party/botan/src/lib/pbkdf/info.txt new file mode 100644 index 0000000000..650414f41b --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/info.txt @@ -0,0 +1,13 @@ + +PBKDF -> 20180902 + + + +mac +hash + + + +pwdhash.h +pbkdf.h + diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf.cpp b/comm/third_party/botan/src/lib/pbkdf/pbkdf.cpp new file mode 100644 index 0000000000..73b482725c --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf.cpp @@ -0,0 +1,133 @@ +/* +* PBKDF +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_PBKDF1) +#include +#endif + +#if defined(BOTAN_HAS_PBKDF2) +#include +#endif + +#if defined(BOTAN_HAS_PGP_S2K) +#include +#endif + +namespace Botan { + +std::unique_ptr PBKDF::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_PBKDF2) + if(req.algo_name() == "PBKDF2") + { + // TODO OpenSSL + + if(provider.empty() || provider == "base") + { + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr(new PKCS5_PBKDF2(mac.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) + return std::unique_ptr(new PKCS5_PBKDF2(mac.release())); + } + + return nullptr; + } +#endif + +#if defined(BOTAN_HAS_PBKDF1) + if(req.algo_name() == "PBKDF1" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr(new PKCS5_PBKDF1(hash.release())); + + } +#endif + +#if defined(BOTAN_HAS_PGP_S2K) + if(req.algo_name() == "OpenPGP-S2K" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr(new OpenPGP_S2K(hash.release())); + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr +PBKDF::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto pbkdf = PBKDF::create(algo, provider)) + { + return pbkdf; + } + throw Lookup_Error("PBKDF", algo, provider); + } + +std::vector PBKDF::providers(const std::string& algo_spec) + { + return probe_providers_of(algo_spec, { "base", "openssl" }); + } + +void PBKDF::pbkdf_timed(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + iterations = pbkdf(out, out_len, passphrase, salt, salt_len, 0, msec); + } + +void PBKDF::pbkdf_iterations(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const + { + if(iterations == 0) + throw Invalid_Argument(name() + ": Invalid iteration count"); + + const size_t iterations_run = pbkdf(out, out_len, passphrase, + salt, salt_len, iterations, + std::chrono::milliseconds(0)); + BOTAN_ASSERT_EQUAL(iterations, iterations_run, "Expected PBKDF iterations"); + } + +secure_vector PBKDF::pbkdf_iterations(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const + { + secure_vector out(out_len); + pbkdf_iterations(out.data(), out_len, passphrase, salt, salt_len, iterations); + return out; + } + +secure_vector PBKDF::pbkdf_timed(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + secure_vector out(out_len); + pbkdf_timed(out.data(), out_len, passphrase, salt, salt_len, msec, iterations); + return out; + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf.h b/comm/third_party/botan/src/lib/pbkdf/pbkdf.h new file mode 100644 index 0000000000..e7f0a84eec --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf.h @@ -0,0 +1,246 @@ +/* +* PBKDF +* (C) 1999-2007,2012,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBKDF_H_ +#define BOTAN_PBKDF_H_ + +#include +#include + +namespace Botan { + +/** +* Base class for PBKDF (password based key derivation function) +* implementations. Converts a password into a key using a salt +* and iterated hashing to make brute force attacks harder. +* +* Starting in 2.8 this functionality is also offered by PasswordHash. +* The PBKDF interface may be removed in a future release. +*/ +class BOTAN_PUBLIC_API(2,0) PBKDF + { + public: + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector providers(const std::string& algo_spec); + + /** + * @return new instance of this same algorithm + */ + virtual PBKDF* clone() const = 0; + + /** + * @return name of this PBKDF + */ + virtual std::string name() const = 0; + + virtual ~PBKDF() = default; + + /** + * Derive a key from a passphrase for a number of iterations + * specified by either iterations or if iterations == 0 then + * running until msec time has elapsed. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @return the number of iterations performed + */ + virtual size_t pbkdf(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const = 0; + + /** + * Derive a key from a passphrase for a number of iterations. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + */ + void pbkdf_iterations(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const; + + /** + * Derive a key from a passphrase, running until msec time has elapsed. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @param iterations set to the number iterations executed + */ + void pbkdf_timed(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + /** + * Derive a key from a passphrase for a number of iterations. + * + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + * @return the derived key + */ + secure_vector pbkdf_iterations(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const; + + /** + * Derive a key from a passphrase, running until msec time has elapsed. + * + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @param iterations set to the number iterations executed + * @return the derived key + */ + secure_vector pbkdf_timed(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + // Following kept for compat with 1.10: + + /** + * Derive a key from a passphrase + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + */ + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const + { + return pbkdf_iterations(out_len, passphrase, salt, salt_len, iterations); + } + + /** + * Derive a key from a passphrase + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param iterations the number of iterations to use (use 10K or more) + */ + template + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const std::vector& salt, + size_t iterations) const + { + return pbkdf_iterations(out_len, passphrase, salt.data(), salt.size(), iterations); + } + + /** + * Derive a key from a passphrase + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec is how long to run the PBKDF + * @param iterations is set to the number of iterations used + */ + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + return pbkdf_timed(out_len, passphrase, salt, salt_len, msec, iterations); + } + + /** + * Derive a key from a passphrase using a certain amount of time + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param msec is how long to run the PBKDF + * @param iterations is set to the number of iterations used + */ + template + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const std::vector& salt, + std::chrono::milliseconds msec, + size_t& iterations) const + { + return pbkdf_timed(out_len, passphrase, salt.data(), salt.size(), msec, iterations); + } + }; + +/* +* Compatibility typedef +*/ +typedef PBKDF S2K; + +/** +* Password based key derivation function factory method +* @param algo_spec the name of the desired PBKDF algorithm +* @param provider the provider to use +* @return pointer to newly allocated object of that type +*/ +inline PBKDF* get_pbkdf(const std::string& algo_spec, + const std::string& provider = "") + { + return PBKDF::create_or_throw(algo_spec, provider).release(); + } + +inline PBKDF* get_s2k(const std::string& algo_spec) + { + return get_pbkdf(algo_spec); + } + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf1/info.txt b/comm/third_party/botan/src/lib/pbkdf/pbkdf1/info.txt new file mode 100644 index 0000000000..e4b972e4b6 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf1/info.txt @@ -0,0 +1,7 @@ + +PBKDF1 -> 20131128 + + + +hash + diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.cpp b/comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.cpp new file mode 100644 index 0000000000..ad922ce9c6 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.cpp @@ -0,0 +1,54 @@ +/* +* PBKDF1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +size_t PKCS5_PBKDF1::pbkdf(uint8_t output_buf[], size_t output_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + if(output_len > m_hash->output_length()) + throw Invalid_Argument("PKCS5_PBKDF1: Requested output length too long"); + + m_hash->update(passphrase); + m_hash->update(salt, salt_len); + secure_vector key = m_hash->final(); + + const auto start = std::chrono::high_resolution_clock::now(); + size_t iterations_performed = 1; + + while(true) + { + if(iterations == 0) + { + if(iterations_performed % 10000 == 0) + { + auto time_taken = std::chrono::high_resolution_clock::now() - start; + auto msec_taken = std::chrono::duration_cast(time_taken); + if(msec_taken > msec) + break; + } + } + else if(iterations_performed == iterations) + break; + + m_hash->update(key); + m_hash->final(key.data()); + + ++iterations_performed; + } + + copy_mem(output_buf, key.data(), output_len); + return iterations_performed; + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.h b/comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.h new file mode 100644 index 0000000000..f5e95b8368 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf1/pbkdf1.h @@ -0,0 +1,53 @@ +/* +* PBKDF1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBKDF1_H_ +#define BOTAN_PBKDF1_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(pbkdf1.h) + +namespace Botan { + +/** +* PKCS #5 v1 PBKDF, aka PBKDF1 +* Can only generate a key up to the size of the hash output. +* Unless needed for backwards compatibility, use PKCS5_PBKDF2 +*/ +class BOTAN_PUBLIC_API(2,0) PKCS5_PBKDF1 final : public PBKDF + { + public: + /** + * Create a PKCS #5 instance using the specified hash function. + * @param hash pointer to a hash function object to use + */ + explicit PKCS5_PBKDF1(HashFunction* hash) : m_hash(hash) {} + + std::string name() const override + { + return "PBKDF1(" + m_hash->name() + ")"; + } + + PBKDF* clone() const override + { + return new PKCS5_PBKDF1(m_hash->clone()); + } + + size_t pbkdf(uint8_t output_buf[], size_t output_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const override; + private: + std::unique_ptr m_hash; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf2/info.txt b/comm/third_party/botan/src/lib/pbkdf/pbkdf2/info.txt new file mode 100644 index 0000000000..b6c6fb4e65 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf2/info.txt @@ -0,0 +1,7 @@ + +PBKDF2 -> 20180902 + + + +hmac + diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp new file mode 100644 index 0000000000..122d0fae3e --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp @@ -0,0 +1,228 @@ +/* +* PBKDF2 +* (C) 1999-2007 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void pbkdf2_set_key(MessageAuthenticationCode& prf, + const char* password, + size_t password_len) + { + try + { + prf.set_key(cast_char_ptr_to_uint8(password), password_len); + } + catch(Invalid_Key_Length&) + { + throw Invalid_Argument("PBKDF2 cannot accept passphrase of the given size"); + } + } + +} + +size_t +pbkdf2(MessageAuthenticationCode& prf, + uint8_t out[], + size_t out_len, + const std::string& password, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) + { + if(iterations == 0) + { + iterations = PBKDF2(prf, out_len, msec).iterations(); + } + + PBKDF2 pbkdf2(prf, iterations); + + pbkdf2.derive_key(out, out_len, + password.c_str(), password.size(), + salt, salt_len); + + return iterations; + } + +namespace { + +size_t tune_pbkdf2(MessageAuthenticationCode& prf, + size_t output_length, + uint32_t msec) + { + if(output_length == 0) + output_length = 1; + + const size_t prf_sz = prf.output_length(); + BOTAN_ASSERT_NOMSG(prf_sz > 0); + secure_vector U(prf_sz); + + const size_t trial_iterations = 2000; + + // Short output ensures we only need a single PBKDF2 block + + Timer timer("PBKDF2"); + + const auto tune_time = BOTAN_PBKDF_TUNING_TIME; + + prf.set_key(nullptr, 0); + + timer.run_until_elapsed(tune_time, [&]() { + uint8_t out[12] = { 0 }; + uint8_t salt[12] = { 0 }; + pbkdf2(prf, out, sizeof(out), salt, sizeof(salt), trial_iterations); + }); + + if(timer.events() == 0) + return trial_iterations; + + const uint64_t duration_nsec = timer.value() / timer.events(); + + const uint64_t desired_nsec = static_cast(msec) * 1000000; + + if(duration_nsec > desired_nsec) + return trial_iterations; + + const size_t blocks_needed = (output_length + prf_sz - 1) / prf_sz; + + const size_t multiplier = static_cast(desired_nsec / duration_nsec / blocks_needed); + + if(multiplier == 0) + return trial_iterations; + else + return trial_iterations * multiplier; + } + +} + +void pbkdf2(MessageAuthenticationCode& prf, + uint8_t out[], + size_t out_len, + const uint8_t salt[], + size_t salt_len, + size_t iterations) + { + if(iterations == 0) + throw Invalid_Argument("PBKDF2: Invalid iteration count"); + + clear_mem(out, out_len); + + if(out_len == 0) + return; + + const size_t prf_sz = prf.output_length(); + BOTAN_ASSERT_NOMSG(prf_sz > 0); + + secure_vector U(prf_sz); + + uint32_t counter = 1; + while(out_len) + { + const size_t prf_output = std::min(prf_sz, out_len); + + prf.update(salt, salt_len); + prf.update_be(counter++); + prf.final(U.data()); + + xor_buf(out, U.data(), prf_output); + + for(size_t i = 1; i != iterations; ++i) + { + prf.update(U); + prf.final(U.data()); + xor_buf(out, U.data(), prf_output); + } + + out_len -= prf_output; + out += prf_output; + } + } + +// PBKDF interface +size_t +PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len, + const std::string& password, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + if(iterations == 0) + { + iterations = PBKDF2(*m_mac, key_len, msec).iterations(); + } + + PBKDF2 pbkdf2(*m_mac, iterations); + + pbkdf2.derive_key(key, key_len, + password.c_str(), password.size(), + salt, salt_len); + + return iterations; + } + +std::string PKCS5_PBKDF2::name() const + { + return "PBKDF2(" + m_mac->name() + ")"; + } + +PBKDF* PKCS5_PBKDF2::clone() const + { + return new PKCS5_PBKDF2(m_mac->clone()); + } + +// PasswordHash interface + +PBKDF2::PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec) : + m_prf(prf.clone()), + m_iterations(tune_pbkdf2(*m_prf, olen, static_cast(msec.count()))) + {} + +std::string PBKDF2::to_string() const + { + return "PBKDF2(" + m_prf->name() + "," + std::to_string(m_iterations) + ")"; + } + +void PBKDF2::derive_key(uint8_t out[], size_t out_len, + const char* password, const size_t password_len, + const uint8_t salt[], size_t salt_len) const + { + pbkdf2_set_key(*m_prf, password, password_len); + pbkdf2(*m_prf, out, out_len, salt, salt_len, m_iterations); + } + +std::string PBKDF2_Family::name() const + { + return "PBKDF2(" + m_prf->name() + ")"; + } + +std::unique_ptr PBKDF2_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const + { + return std::unique_ptr(new PBKDF2(*m_prf, output_len, msec)); + } + +std::unique_ptr PBKDF2_Family::default_params() const + { + return std::unique_ptr(new PBKDF2(*m_prf, 150000)); + } + +std::unique_ptr PBKDF2_Family::from_params(size_t iter, size_t, size_t) const + { + return std::unique_ptr(new PBKDF2(*m_prf, iter)); + } + +std::unique_ptr PBKDF2_Family::from_iterations(size_t iter) const + { + return std::unique_ptr(new PBKDF2(*m_prf, iter)); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h b/comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h new file mode 100644 index 0000000000..9f90799c40 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h @@ -0,0 +1,117 @@ +/* +* PBKDF2 +* (C) 1999-2007,2012 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBKDF2_H_ +#define BOTAN_PBKDF2_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(pbkdf2.h) + +namespace Botan { + +BOTAN_PUBLIC_API(2,0) size_t pbkdf2(MessageAuthenticationCode& prf, + uint8_t out[], + size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec); + +/** +* Perform PBKDF2. The prf is assumed to be keyed already. +*/ +BOTAN_PUBLIC_API(2,8) void pbkdf2(MessageAuthenticationCode& prf, + uint8_t out[], size_t out_len, + const uint8_t salt[], size_t salt_len, + size_t iterations); + +/** +* PBKDF2 +*/ +class BOTAN_PUBLIC_API(2,8) PBKDF2 final : public PasswordHash + { + public: + PBKDF2(const MessageAuthenticationCode& prf, size_t iter) : + m_prf(prf.clone()), + m_iterations(iter) + {} + + PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec); + + size_t iterations() const override { return m_iterations; } + + std::string to_string() const override; + + void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const override; + private: + std::unique_ptr m_prf; + size_t m_iterations; + }; + +/** +* Family of PKCS #5 PBKDF2 operations +*/ +class BOTAN_PUBLIC_API(2,8) PBKDF2_Family final : public PasswordHashFamily + { + public: + PBKDF2_Family(MessageAuthenticationCode* prf) : m_prf(prf) {} + + std::string name() const override; + + std::unique_ptr tune(size_t output_len, + std::chrono::milliseconds msec, + size_t max_memory) const override; + + /** + * Return some default parameter set for this PBKDF that should be good + * enough for most users. The value returned may change over time as + * processing power and attacks improve. + */ + std::unique_ptr default_params() const override; + + std::unique_ptr from_iterations(size_t iter) const override; + + std::unique_ptr from_params( + size_t iter, size_t, size_t) const override; + private: + std::unique_ptr m_prf; + }; + +/** +* PKCS #5 PBKDF2 (old interface) +*/ +class BOTAN_PUBLIC_API(2,0) PKCS5_PBKDF2 final : public PBKDF + { + public: + std::string name() const override; + + PBKDF* clone() const override; + + size_t pbkdf(uint8_t output_buf[], size_t output_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const override; + + /** + * Create a PKCS #5 instance using the specified message auth code + * @param mac_fn the MAC object to use as PRF + */ + explicit PKCS5_PBKDF2(MessageAuthenticationCode* mac_fn) : m_mac(mac_fn) {} + private: + std::unique_ptr m_mac; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/info.txt b/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/info.txt new file mode 100644 index 0000000000..5aabc09195 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/info.txt @@ -0,0 +1,7 @@ + +PGP_S2K -> 20170527 + + + +hash + diff --git a/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp b/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp new file mode 100644 index 0000000000..8bcf9239fc --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp @@ -0,0 +1,219 @@ +/* +* OpenPGP S2K +* (C) 1999-2007,2017 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +PGP stores the iteration count as a single byte +Thus it can only actually take on one of 256 values, based on the +formula in RFC 4880 section 3.6.1.3 +*/ +static const uint32_t OPENPGP_S2K_ITERS[256] = { + 1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, + 1664, 1728, 1792, 1856, 1920, 1984, 2048, 2176, 2304, 2432, + 2560, 2688, 2816, 2944, 3072, 3200, 3328, 3456, 3584, 3712, + 3840, 3968, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, + 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936, 8192, 8704, + 9216, 9728, 10240, 10752, 11264, 11776, 12288, 12800, 13312, + 13824, 14336, 14848, 15360, 15872, 16384, 17408, 18432, 19456, + 20480, 21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, + 29696, 30720, 31744, 32768, 34816, 36864, 38912, 40960, 43008, + 45056, 47104, 49152, 51200, 53248, 55296, 57344, 59392, 61440, + 63488, 65536, 69632, 73728, 77824, 81920, 86016, 90112, 94208, + 98304, 102400, 106496, 110592, 114688, 118784, 122880, 126976, + 131072, 139264, 147456, 155648, 163840, 172032, 180224, 188416, + 196608, 204800, 212992, 221184, 229376, 237568, 245760, 253952, + 262144, 278528, 294912, 311296, 327680, 344064, 360448, 376832, + 393216, 409600, 425984, 442368, 458752, 475136, 491520, 507904, + 524288, 557056, 589824, 622592, 655360, 688128, 720896, 753664, + 786432, 819200, 851968, 884736, 917504, 950272, 983040, 1015808, + 1048576, 1114112, 1179648, 1245184, 1310720, 1376256, 1441792, + 1507328, 1572864, 1638400, 1703936, 1769472, 1835008, 1900544, + 1966080, 2031616, 2097152, 2228224, 2359296, 2490368, 2621440, + 2752512, 2883584, 3014656, 3145728, 3276800, 3407872, 3538944, + 3670016, 3801088, 3932160, 4063232, 4194304, 4456448, 4718592, + 4980736, 5242880, 5505024, 5767168, 6029312, 6291456, 6553600, + 6815744, 7077888, 7340032, 7602176, 7864320, 8126464, 8388608, + 8912896, 9437184, 9961472, 10485760, 11010048, 11534336, + 12058624, 12582912, 13107200, 13631488, 14155776, 14680064, + 15204352, 15728640, 16252928, 16777216, 17825792, 18874368, + 19922944, 20971520, 22020096, 23068672, 24117248, 25165824, + 26214400, 27262976, 28311552, 29360128, 30408704, 31457280, + 32505856, 33554432, 35651584, 37748736, 39845888, 41943040, + 44040192, 46137344, 48234496, 50331648, 52428800, 54525952, + 56623104, 58720256, 60817408, 62914560, 65011712 }; + +uint8_t RFC4880_encode_count(size_t desired_iterations) + { + if(desired_iterations <= OPENPGP_S2K_ITERS[0]) + return 0; + + if(desired_iterations >= OPENPGP_S2K_ITERS[255]) + return 255; + + auto i = std::lower_bound(OPENPGP_S2K_ITERS, OPENPGP_S2K_ITERS + 256, desired_iterations); + + return static_cast(i - OPENPGP_S2K_ITERS); + } + +size_t RFC4880_decode_count(uint8_t iter) + { + return OPENPGP_S2K_ITERS[iter]; + } + +namespace { + +void pgp_s2k(HashFunction& hash, + uint8_t output_buf[], size_t output_len, + const char* password, const size_t password_size, + const uint8_t salt[], size_t salt_len, + size_t iterations) + { + if(iterations > 1 && salt_len == 0) + throw Invalid_Argument("OpenPGP S2K requires a salt in iterated mode"); + + secure_vector input_buf(salt_len + password_size); + if(salt_len > 0) + { + copy_mem(&input_buf[0], salt, salt_len); + } + if(password_size > 0) + { + copy_mem(&input_buf[salt_len], + cast_char_ptr_to_uint8(password), + password_size); + } + + secure_vector hash_buf(hash.output_length()); + + size_t pass = 0; + size_t generated = 0; + + while(generated != output_len) + { + const size_t output_this_pass = + std::min(hash_buf.size(), output_len - generated); + + // Preload some number of zero bytes (empty first iteration) + std::vector zero_padding(pass); + hash.update(zero_padding); + + // The input is always fully processed even if iterations is very small + if(input_buf.empty() == false) + { + size_t left = std::max(iterations, input_buf.size()); + while(left > 0) + { + const size_t input_to_take = std::min(left, input_buf.size()); + hash.update(input_buf.data(), input_to_take); + left -= input_to_take; + } + } + + hash.final(hash_buf.data()); + copy_mem(output_buf + generated, hash_buf.data(), output_this_pass); + generated += output_this_pass; + ++pass; + } + } + +} + +size_t OpenPGP_S2K::pbkdf(uint8_t output_buf[], size_t output_len, + const std::string& password, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + std::unique_ptr pwdhash; + + if(iterations == 0) + { + RFC4880_S2K_Family s2k_params(m_hash->clone()); + iterations = s2k_params.tune(output_len, msec, 0)->iterations(); + } + + pgp_s2k(*m_hash, output_buf, output_len, + password.c_str(), password.size(), + salt, salt_len, + iterations); + + return iterations; + } + +std::string RFC4880_S2K_Family::name() const + { + return "OpenPGP-S2K(" + m_hash->name() + ")"; + } + +std::unique_ptr RFC4880_S2K_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const + { + const auto tune_time = BOTAN_PBKDF_TUNING_TIME; + + const size_t buf_size = 1024; + std::vector buffer(buf_size); + + Timer timer("RFC4880_S2K", buf_size); + timer.run_until_elapsed(tune_time, [&]() { + m_hash->update(buffer); + }); + + const double hash_bytes_per_second = timer.bytes_per_second(); + const uint64_t desired_nsec = msec.count() * 1000000; + + const size_t hash_size = m_hash->output_length(); + const size_t blocks_required = (output_len <= hash_size ? 1 : (output_len + hash_size - 1) / hash_size); + + const double bytes_to_be_hashed = (hash_bytes_per_second * (desired_nsec / 1000000000.0)) / blocks_required; + const size_t iterations = RFC4880_round_iterations(static_cast(bytes_to_be_hashed)); + + return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), iterations)); + } + +std::unique_ptr RFC4880_S2K_Family::from_params(size_t iter, size_t, size_t) const + { + return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), iter)); + } + +std::unique_ptr RFC4880_S2K_Family::default_params() const + { + return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), 50331648)); + } + +std::unique_ptr RFC4880_S2K_Family::from_iterations(size_t iter) const + { + return std::unique_ptr(new RFC4880_S2K(m_hash->clone(), iter)); + } + +RFC4880_S2K::RFC4880_S2K(HashFunction* hash, size_t iterations) : + m_hash(hash), + m_iterations(iterations) + { + } + +std::string RFC4880_S2K::to_string() const + { + return "OpenPGP-S2K(" + m_hash->name() + "," + std::to_string(m_iterations) + ")"; + } + +void RFC4880_S2K::derive_key(uint8_t out[], size_t out_len, + const char* password, const size_t password_len, + const uint8_t salt[], size_t salt_len) const + { + pgp_s2k(*m_hash, out, out_len, + password, password_len, + salt, salt_len, + m_iterations); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.h b/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.h new file mode 100644 index 0000000000..7fda724c2a --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pgp_s2k/pgp_s2k.h @@ -0,0 +1,164 @@ +/* +* OpenPGP PBKDF +* (C) 1999-2007,2017 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OPENPGP_S2K_H_ +#define BOTAN_OPENPGP_S2K_H_ + +#include +#include +#include + +/* +This header will not be fully internal - the RFC4880 count +encoding functions will remain here. But the definition of +OpenPGP_S2K will be made internal +*/ + +//BOTAN_FUTURE_INTERNAL_HEADER(pgp_s2k.h) + +namespace Botan { + +/** +* RFC 4880 encodes the iteration count to a single-byte value +*/ +uint8_t BOTAN_PUBLIC_API(2,8) RFC4880_encode_count(size_t iterations); + +/** +* Decode the iteration count from RFC 4880 encoding +*/ +size_t BOTAN_PUBLIC_API(2,8) RFC4880_decode_count(uint8_t encoded_iter); + +/** +* Round an arbitrary iteration count to next largest iteration count +* supported by RFC4880 encoding. +*/ +inline size_t RFC4880_round_iterations(size_t iterations) + { + return RFC4880_decode_count(RFC4880_encode_count(iterations)); + } + +/** +* OpenPGP's S2K +* +* See RFC 4880 sections 3.7.1.1, 3.7.1.2, and 3.7.1.3 +* If the salt is empty and iterations == 1, "simple" S2K is used +* If the salt is non-empty and iterations == 1, "salted" S2K is used +* If the salt is non-empty and iterations > 1, "iterated" S2K is used +* +* Due to complexities of the PGP S2K algorithm, time-based derivation +* is not supported. So if iterations == 0 and msec.count() > 0, an +* exception is thrown. In the future this may be supported, in which +* case "iterated" S2K will be used and the number of iterations +* performed is returned. +* +* Note that unlike PBKDF2, OpenPGP S2K's "iterations" are defined as +* the number of bytes hashed. +*/ +class BOTAN_PUBLIC_API(2,2) OpenPGP_S2K final : public PBKDF + { + public: + /** + * @param hash the hash function to use + */ + explicit OpenPGP_S2K(HashFunction* hash) : m_hash(hash) {} + + std::string name() const override + { + return "OpenPGP-S2K(" + m_hash->name() + ")"; + } + + PBKDF* clone() const override + { + return new OpenPGP_S2K(m_hash->clone()); + } + + size_t pbkdf(uint8_t output_buf[], size_t output_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const override; + + /** + * RFC 4880 encodes the iteration count to a single-byte value + */ + static uint8_t encode_count(size_t iterations) + { + return RFC4880_encode_count(iterations); + } + + static size_t decode_count(uint8_t encoded_iter) + { + return RFC4880_decode_count(encoded_iter); + } + + private: + std::unique_ptr m_hash; + }; + +/** +* OpenPGP's S2K +* +* See RFC 4880 sections 3.7.1.1, 3.7.1.2, and 3.7.1.3 +* If the salt is empty and iterations == 1, "simple" S2K is used +* If the salt is non-empty and iterations == 1, "salted" S2K is used +* If the salt is non-empty and iterations > 1, "iterated" S2K is used +* +* Note that unlike PBKDF2, OpenPGP S2K's "iterations" are defined as +* the number of bytes hashed. +*/ +class BOTAN_PUBLIC_API(2,8) RFC4880_S2K final : public PasswordHash + { + public: + /** + * @param hash the hash function to use + * @param iterations is rounded due to PGP formatting + */ + RFC4880_S2K(HashFunction* hash, size_t iterations); + + std::string to_string() const override; + + size_t iterations() const override { return m_iterations; } + + void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const override; + + private: + std::unique_ptr m_hash; + size_t m_iterations; + }; + +class BOTAN_PUBLIC_API(2,8) RFC4880_S2K_Family final : public PasswordHashFamily + { + public: + RFC4880_S2K_Family(HashFunction* hash) : m_hash(hash) {} + + std::string name() const override; + + std::unique_ptr tune(size_t output_len, + std::chrono::milliseconds msec, + size_t max_mem) const override; + + /** + * Return some default parameter set for this PBKDF that should be good + * enough for most users. The value returned may change over time as + * processing power and attacks improve. + */ + std::unique_ptr default_params() const override; + + std::unique_ptr from_iterations(size_t iter) const override; + + std::unique_ptr from_params( + size_t iter, size_t, size_t) const override; + private: + std::unique_ptr m_hash; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/pwdhash.cpp b/comm/third_party/botan/src/lib/pbkdf/pwdhash.cpp new file mode 100644 index 0000000000..718024a227 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pwdhash.cpp @@ -0,0 +1,118 @@ +/* +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_PBKDF2) + #include +#endif + +#if defined(BOTAN_HAS_PGP_S2K) + #include +#endif + +#if defined(BOTAN_HAS_SCRYPT) + #include +#endif + +#if defined(BOTAN_HAS_ARGON2) + #include +#endif + +#if defined(BOTAN_HAS_PBKDF_BCRYPT) + #include +#endif + +namespace Botan { + +std::unique_ptr PasswordHashFamily::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_PBKDF2) + if(req.algo_name() == "PBKDF2") + { + // TODO OpenSSL + + if(provider.empty() || provider == "base") + { + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr(new PBKDF2_Family(mac.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) + return std::unique_ptr(new PBKDF2_Family(mac.release())); + } + + return nullptr; + } +#endif + +#if defined(BOTAN_HAS_SCRYPT) + if(req.algo_name() == "Scrypt") + { + return std::unique_ptr(new Scrypt_Family); + } +#endif + +#if defined(BOTAN_HAS_ARGON2) + if(req.algo_name() == "Argon2d") + { + return std::unique_ptr(new Argon2_Family(0)); + } + else if(req.algo_name() == "Argon2i") + { + return std::unique_ptr(new Argon2_Family(1)); + } + else if(req.algo_name() == "Argon2id") + { + return std::unique_ptr(new Argon2_Family(2)); + } +#endif + +#if defined(BOTAN_HAS_PBKDF_BCRYPT) + if(req.algo_name() == "Bcrypt-PBKDF") + { + return std::unique_ptr(new Bcrypt_PBKDF_Family); + } +#endif + +#if defined(BOTAN_HAS_PGP_S2K) + if(req.algo_name() == "OpenPGP-S2K" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + { + return std::unique_ptr(new RFC4880_S2K_Family(hash.release())); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr +PasswordHashFamily::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto pbkdf = PasswordHashFamily::create(algo, provider)) + { + return pbkdf; + } + throw Lookup_Error("PasswordHashFamily", algo, provider); + } + +std::vector PasswordHashFamily::providers(const std::string& algo_spec) + { + return probe_providers_of(algo_spec, { "base", "openssl" }); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/pwdhash.h b/comm/third_party/botan/src/lib/pbkdf/pwdhash.h new file mode 100644 index 0000000000..ba64a73fd5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/pwdhash.h @@ -0,0 +1,162 @@ +/* +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PWDHASH_H_ +#define BOTAN_PWDHASH_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Base class for password based key derivation functions. +* +* Converts a password into a key using a salt and iterated hashing to +* make brute force attacks harder. +*/ +class BOTAN_PUBLIC_API(2,8) PasswordHash + { + public: + virtual ~PasswordHash() = default; + + virtual std::string to_string() const = 0; + + /** + * Most password hashes have some notion of iterations. + */ + virtual size_t iterations() const = 0; + + /** + * Some password hashing algorithms have a parameter which controls how + * much memory is used. If not supported by some algorithm, returns 0. + */ + virtual size_t memory_param() const { return 0; } + + /** + * Some password hashing algorithms have a parallelism parameter. + * If the algorithm does not support this notion, then the + * function returns zero. This allows distinguishing between a + * password hash which just does not support parallel operation, + * vs one that does support parallel operation but which has been + * configured to use a single lane. + */ + virtual size_t parallelism() const { return 0; } + + /** + * Returns an estimate of the total memory usage required to perform this + * key derivation. + * + * If this algorithm uses a small and constant amount of memory, with no + * effort made towards being memory hard, this function returns 0. + */ + virtual size_t total_memory_usage() const { return 0; } + + /** + * Derive a key from a password + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param password the password to derive the key from + * @param password_len the length of password in bytes + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * + * This function is const, but is not thread safe. Different threads should + * either use unique objects, or serialize all access. + */ + virtual void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const = 0; + }; + +class BOTAN_PUBLIC_API(2,8) PasswordHashFamily + { + public: + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector providers(const std::string& algo_spec); + + virtual ~PasswordHashFamily() = default; + + /** + * @return name of this PasswordHash + */ + virtual std::string name() const = 0; + + /** + * Return a new parameter set tuned for this machine + * @param output_length how long the output length will be + * @param msec the desired execution time in milliseconds + * + * @param max_memory_usage_mb some password hash functions can use a tunable + * amount of memory, in this case max_memory_usage limits the amount of RAM + * the returned parameters will require, in mebibytes (2**20 bytes). It may + * require some small amount above the request. Set to zero to place no + * limit at all. + */ + virtual std::unique_ptr tune(size_t output_length, + std::chrono::milliseconds msec, + size_t max_memory_usage_mb = 0) const = 0; + + /** + * Return some default parameter set for this PBKDF that should be good + * enough for most users. The value returned may change over time as + * processing power and attacks improve. + */ + virtual std::unique_ptr default_params() const = 0; + + /** + * Return a parameter chosen based on a rough approximation with the + * specified iteration count. The exact value this returns for a particular + * algorithm may change from over time. Think of it as an alternative to + * tune, where time is expressed in terms of PBKDF2 iterations rather than + * milliseconds. + */ + virtual std::unique_ptr from_iterations(size_t iterations) const = 0; + + /** + * Create a password hash using some scheme specific format. + * Eg PBKDF2 and PGP-S2K set iterations in i1 + * Scrypt uses N,r,p in i{1-3} + * Bcrypt-PBKDF just has iterations + * Argon2{i,d,id} would use iterations, memory, parallelism for i{1-3}, + * and Argon2 type is part of the family. + * + * Values not needed should be set to 0 + */ + virtual std::unique_ptr from_params( + size_t i1, + size_t i2 = 0, + size_t i3 = 0) const = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pbkdf/scrypt/info.txt b/comm/third_party/botan/src/lib/pbkdf/scrypt/info.txt new file mode 100644 index 0000000000..3ba48fd726 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/scrypt/info.txt @@ -0,0 +1,10 @@ + +SCRYPT -> 20180902 + + + +salsa20 +pbkdf2 +hmac +sha2_32 + diff --git a/comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.cpp b/comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.cpp new file mode 100644 index 0000000000..8275ac9567 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.cpp @@ -0,0 +1,249 @@ +/** +* (C) 2018 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +std::string Scrypt_Family::name() const + { + return "Scrypt"; + } + +std::unique_ptr Scrypt_Family::default_params() const + { + return std::unique_ptr(new Scrypt(32768, 8, 1)); + } + +std::unique_ptr Scrypt_Family::tune(size_t output_length, + std::chrono::milliseconds msec, + size_t max_memory_usage_mb) const + { + BOTAN_UNUSED(output_length); + + /* + * Some rough relations between scrypt parameters and runtime. + * Denote here by stime(N,r,p) the msec it takes to run scrypt. + * + * Emperically for smaller sizes: + * stime(N,8*r,p) / stime(N,r,p) is ~ 6-7 + * stime(N,r,8*p) / stime(N,r,8*p) is ~ 7 + * stime(2*N,r,p) / stime(N,r,p) is ~ 2 + * + * Compute stime(8192,1,1) as baseline and extrapolate + */ + + const size_t max_memory_usage = max_memory_usage_mb * 1024 * 1024; + // Starting parameters + size_t N = 8192; + size_t r = 1; + size_t p = 1; + + Timer timer("Scrypt"); + const auto tune_time = BOTAN_PBKDF_TUNING_TIME; + + timer.run_until_elapsed(tune_time, [&]() { + uint8_t output[32] = { 0 }; + scrypt(output, sizeof(output), "test", 4, nullptr, 0, N, r, p); + }); + + // No timer events seems strange, perhaps something is wrong - give + // up on this and just return default params + if(timer.events() == 0) + return default_params(); + + // nsec per eval of scrypt with initial params + const uint64_t measured_time = timer.value() / timer.events(); + + const uint64_t target_nsec = msec.count() * static_cast(1000000); + + uint64_t est_nsec = measured_time; + + // First move increase r by 8x if possible + + if(max_memory_usage == 0 || scrypt_memory_usage(N, r, p)*8 < max_memory_usage) + { + if(target_nsec / est_nsec >= 5) + { + r *= 8; + est_nsec *= 5; + } + } + + // Now double N as many times as we can + + while(max_memory_usage == 0 || scrypt_memory_usage(N, r, p)*2 < max_memory_usage) + { + if(target_nsec / est_nsec >= 2) + { + N *= 2; + est_nsec *= 2; + } + else + break; + } + + // If we have extra runtime budget, increment p + + if(target_nsec / est_nsec > 2) + p *= std::min(1024, static_cast(target_nsec / est_nsec)); + + return std::unique_ptr(new Scrypt(N, r, p)); + } + +std::unique_ptr Scrypt_Family::from_params(size_t N, size_t r, size_t p) const + { + return std::unique_ptr(new Scrypt(N, r, p)); + } + +std::unique_ptr Scrypt_Family::from_iterations(size_t iter) const + { + const size_t r = 8; + const size_t p = 1; + + size_t N = 8192; + + if(iter > 50000) + N = 16384; + if(iter > 100000) + N = 32768; + if(iter > 150000) + N = 65536; + + return std::unique_ptr(new Scrypt(N, r, p)); + } + +Scrypt::Scrypt(size_t N, size_t r, size_t p) : + m_N(N), m_r(r), m_p(p) + { + if(!is_power_of_2(N)) + throw Invalid_Argument("Scrypt N parameter must be a power of 2"); + + if(p == 0 || p > 1024) + throw Invalid_Argument("Invalid or unsupported scrypt p"); + if(r == 0 || r > 256) + throw Invalid_Argument("Invalid or unsupported scrypt r"); + if(N < 1 || N > 4194304) + throw Invalid_Argument("Invalid or unsupported scrypt N"); + } + +std::string Scrypt::to_string() const + { + std::ostringstream oss; + oss << "Scrypt(" << m_N << "," << m_r << "," << m_p << ")"; + return oss.str(); + } + +size_t Scrypt::total_memory_usage() const + { + return scrypt_memory_usage(m_N, m_r, m_p); + } + +void Scrypt::derive_key(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const + { + scrypt(output, output_len, + password, password_len, + salt, salt_len, + N(), r(), p()); + } + +namespace { + +void scryptBlockMix(size_t r, uint8_t* B, uint8_t* Y) + { + uint32_t B32[16]; + secure_vector X(64); + copy_mem(X.data(), &B[(2*r-1)*64], 64); + + for(size_t i = 0; i != 2*r; i++) + { + xor_buf(X.data(), &B[64*i], 64); + load_le(B32, X.data(), 16); + Salsa20::salsa_core(X.data(), B32, 8); + copy_mem(&Y[64*i], X.data(), 64); + } + + for(size_t i = 0; i < r; ++i) + { + copy_mem(&B[i*64], &Y[(i * 2) * 64], 64); + } + + for(size_t i = 0; i < r; ++i) + { + copy_mem(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64); + } + } + +void scryptROMmix(size_t r, size_t N, uint8_t* B, secure_vector& V) + { + const size_t S = 128 * r; + + for(size_t i = 0; i != N; ++i) + { + copy_mem(&V[S*i], B, S); + scryptBlockMix(r, B, &V[N*S]); + } + + for(size_t i = 0; i != N; ++i) + { + // compiler doesn't know here that N is power of 2 + const size_t j = load_le(&B[(2*r-1)*64], 0) & (N - 1); + xor_buf(B, &V[j*S], S); + scryptBlockMix(r, B, &V[N*S]); + } + } + +} + +void scrypt(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + size_t N, size_t r, size_t p) + { + const size_t S = 128 * r; + secure_vector B(p * S); + // temp space + secure_vector V((N+1) * S); + + auto hmac_sha256 = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + + try + { + hmac_sha256->set_key(cast_char_ptr_to_uint8(password), password_len); + } + catch(Invalid_Key_Length&) + { + throw Invalid_Argument("Scrypt cannot accept passphrases of the provided length"); + } + + pbkdf2(*hmac_sha256.get(), + B.data(), B.size(), + salt, salt_len, + 1); + + // these can be parallel + for(size_t i = 0; i != p; ++i) + { + scryptROMmix(r, N, &B[128*r*i], V); + } + + pbkdf2(*hmac_sha256.get(), + output, output_len, + B.data(), B.size(), + 1); + } + +} diff --git a/comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.h b/comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.h new file mode 100644 index 0000000000..60cdbd0460 --- /dev/null +++ b/comm/third_party/botan/src/lib/pbkdf/scrypt/scrypt.h @@ -0,0 +1,127 @@ +/** +* (C) 2018 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SCRYPT_H_ +#define BOTAN_SCRYPT_H_ + +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(scrypt.h) + +namespace Botan { + +/** +* Scrypt key derivation function (RFC 7914) +*/ +class BOTAN_PUBLIC_API(2,8) Scrypt final : public PasswordHash + { + public: + Scrypt(size_t N, size_t r, size_t p); + + Scrypt(const Scrypt& other) = default; + Scrypt& operator=(const Scrypt&) = default; + + /** + * Derive a new key under the current Scrypt parameter set + */ + void derive_key(uint8_t out[], size_t out_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len) const override; + + std::string to_string() const override; + + size_t N() const { return m_N; } + size_t r() const { return m_r; } + size_t p() const { return m_p; } + + size_t iterations() const override { return r(); } + + size_t parallelism() const override { return p(); } + + size_t memory_param() const override { return N(); } + + size_t total_memory_usage() const override; + + private: + size_t m_N, m_r, m_p; + }; + +class BOTAN_PUBLIC_API(2,8) Scrypt_Family final : public PasswordHashFamily + { + public: + std::string name() const override; + + std::unique_ptr tune(size_t output_length, + std::chrono::milliseconds msec, + size_t max_memory) const override; + + std::unique_ptr default_params() const override; + + std::unique_ptr from_iterations(size_t iter) const override; + + std::unique_ptr from_params( + size_t N, size_t r, size_t p) const override; + }; + +/** +* Scrypt key derivation function (RFC 7914) +* +* @param output the output will be placed here +* @param output_len length of output +* @param password the user password +* @param password_len length of password +* @param salt the salt +* @param salt_len length of salt +* @param N the CPU/Memory cost parameter, must be power of 2 +* @param r the block size parameter +* @param p the parallelization parameter +* +* Suitable parameters for most uses would be N = 32768, r = 8, p = 1 +* +* Scrypt uses approximately (p + N + 1) * 128 * r bytes of memory +*/ +void BOTAN_PUBLIC_API(2,8) scrypt(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + size_t N, size_t r, size_t p); + +/** +* Scrypt key derivation function (RFC 7914) +* Before 2.8 this function was the primary interface for scrypt +* +* @param output the output will be placed here +* @param output_len length of output +* @param password the user password +* @param salt the salt +* @param salt_len length of salt +* @param N the CPU/Memory cost parameter, must be power of 2 +* @param r the block size parameter +* @param p the parallelization parameter +* +* Suitable parameters for most uses would be N = 32768, r = 8, p = 1 +* +* Scrypt uses approximately (p + N + 1) * 128 * r bytes of memory +*/ +inline void scrypt(uint8_t output[], size_t output_len, + const std::string& password, + const uint8_t salt[], size_t salt_len, + size_t N, size_t r, size_t p) + { + return scrypt(output, output_len, + password.c_str(), password.size(), + salt, salt_len, + N, r, p); + } + +inline size_t scrypt_memory_usage(size_t N, size_t r, size_t p) + { + return 128 * r * (N + p); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/eme.cpp b/comm/third_party/botan/src/lib/pk_pad/eme.cpp new file mode 100644 index 0000000000..ffedac923d --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme.cpp @@ -0,0 +1,94 @@ +/* +* EME Base Class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_EME_OAEP) +#include +#endif + +#if defined(BOTAN_HAS_EME_PKCS1) +#include +#endif + +#if defined(BOTAN_HAS_EME_RAW) +#include +#endif + +namespace Botan { + +EME* get_eme(const std::string& algo_spec) + { +#if defined(BOTAN_HAS_EME_RAW) + if(algo_spec == "Raw") + return new EME_Raw; +#endif + +#if defined(BOTAN_HAS_EME_PKCS1) + if(algo_spec == "PKCS1v15" || algo_spec == "EME-PKCS1-v1_5") + return new EME_PKCS1v15; +#endif + +#if defined(BOTAN_HAS_EME_OAEP) + SCAN_Name req(algo_spec); + + if(req.algo_name() == "OAEP" || + req.algo_name() == "EME-OAEP" || + req.algo_name() == "EME1") + { + if(req.arg_count() == 1 || + ((req.arg_count() == 2 || req.arg_count() == 3) && req.arg(1) == "MGF1")) + { + if(auto hash = HashFunction::create(req.arg(0))) + return new OAEP(hash.release(), req.arg(2, "")); + } + else if(req.arg_count() == 2 || req.arg_count() == 3) + { + auto mgf_params = parse_algorithm_name(req.arg(1)); + + if(mgf_params.size() == 2 && mgf_params[0] == "MGF1") + { + auto hash = HashFunction::create(req.arg(0)); + auto mgf1_hash = HashFunction::create(mgf_params[1]); + + if(hash && mgf1_hash) + { + return new OAEP(hash.release(), mgf1_hash.release(), req.arg(2, "")); + } + } + } + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Encode a message +*/ +secure_vector EME::encode(const uint8_t msg[], size_t msg_len, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(msg, msg_len, key_bits, rng); + } + +/* +* Encode a message +*/ +secure_vector EME::encode(const secure_vector& msg, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(msg.data(), msg.size(), key_bits, rng); + } + + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/eme.h b/comm/third_party/botan/src/lib/pk_pad/eme.h new file mode 100644 index 0000000000..38cce4b093 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme.h @@ -0,0 +1,94 @@ +/* +* EME Classes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PUBKEY_EME_ENCRYPTION_PAD_H_ +#define BOTAN_PUBKEY_EME_ENCRYPTION_PAD_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(eme.h) + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Encoding Method for Encryption +*/ +class BOTAN_PUBLIC_API(2,0) EME + { + public: + virtual ~EME() = default; + + /** + * Return the maximum input size in bytes we can support + * @param keybits the size of the key in bits + * @return upper bound of input in bytes + */ + virtual size_t maximum_input_size(size_t keybits) const = 0; + + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + secure_vector encode(const uint8_t in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Encode an input + * @param in the plaintext + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + secure_vector encode(const secure_vector& in, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Decode an input + * @param valid_mask written to specifies if output is valid + * @param in the encoded plaintext + * @param in_len length of encoded plaintext in bytes + * @return bytes of out[] written to along with + * validity mask (0xFF if valid, else 0x00) + */ + virtual secure_vector unpad(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const = 0; + + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + virtual secure_vector pad(const uint8_t in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const = 0; + }; + +/** +* Factory method for EME (message-encoding methods for encryption) objects +* @param algo_spec the name of the EME to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_PUBLIC_API(2,0) EME* get_eme(const std::string& algo_spec); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_oaep/info.txt b/comm/third_party/botan/src/lib/pk_pad/eme_oaep/info.txt new file mode 100644 index 0000000000..cabe23fb85 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_oaep/info.txt @@ -0,0 +1,7 @@ + +EME_OAEP -> 20180305 + + + +mgf1 + diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.cpp b/comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.cpp new file mode 100644 index 0000000000..428b6ac3bf --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.cpp @@ -0,0 +1,168 @@ +/* +* OAEP +* (C) 1999-2010,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* OAEP Pad Operation +*/ +secure_vector OAEP::pad(const uint8_t in[], size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const + { + key_length /= 8; + + if(in_length > maximum_input_size(key_length * 8)) + { + throw Invalid_Argument("OAEP: Input is too large"); + } + + secure_vector out(key_length); + + rng.randomize(out.data(), m_Phash.size()); + + buffer_insert(out, m_Phash.size(), m_Phash.data(), m_Phash.size()); + out[out.size() - in_length - 1] = 0x01; + buffer_insert(out, out.size() - in_length, in, in_length); + + mgf1_mask(*m_mgf1_hash, + out.data(), m_Phash.size(), + &out[m_Phash.size()], out.size() - m_Phash.size()); + + mgf1_mask(*m_mgf1_hash, + &out[m_Phash.size()], out.size() - m_Phash.size(), + out.data(), m_Phash.size()); + + return out; + } + +/* +* OAEP Unpad Operation +*/ +secure_vector OAEP::unpad(uint8_t& valid_mask, + const uint8_t in[], size_t in_length) const + { + /* + Must be careful about error messages here; if an attacker can + distinguish them, it is easy to use the differences as an oracle to + find the secret key, as described in "A Chosen Ciphertext Attack on + RSA Optimal Asymmetric Encryption Padding (OAEP) as Standardized in + PKCS #1 v2.0", James Manger, Crypto 2001 + + Also have to be careful about timing attacks! Pointed out by Falko + Strenzke. + + According to the standard (Section 7.1.1), the encryptor always + creates a message as follows: + i. Concatenate a single octet with hexadecimal value 0x00, + maskedSeed, and maskedDB to form an encoded message EM of + length k octets as + EM = 0x00 || maskedSeed || maskedDB. + where k is the length of the modulus N. + Therefore, the first byte can always be skipped safely. + */ + + const auto leading_0 = CT::Mask::is_zero(in[0]); + + secure_vector input(in + 1, in + in_length); + + const size_t hlen = m_Phash.size(); + + mgf1_mask(*m_mgf1_hash, + &input[hlen], input.size() - hlen, + input.data(), hlen); + + mgf1_mask(*m_mgf1_hash, + input.data(), hlen, + &input[hlen], input.size() - hlen); + + auto unpadded = oaep_find_delim(valid_mask, input.data(), input.size(), m_Phash); + valid_mask &= leading_0.unpoisoned_value(); + return unpadded; + } + +secure_vector +oaep_find_delim(uint8_t& valid_mask, + const uint8_t input[], size_t input_len, + const secure_vector& Phash) + { + const size_t hlen = Phash.size(); + + // Too short to be valid, reject immediately + if(input_len < 1 + 2*hlen) + { + return secure_vector(); + } + + CT::poison(input, input_len); + + size_t delim_idx = 2 * hlen; + CT::Mask waiting_for_delim = CT::Mask::set(); + CT::Mask bad_input_m = CT::Mask::cleared(); + + for(size_t i = delim_idx; i < input_len; ++i) + { + const auto zero_m = CT::Mask::is_zero(input[i]); + const auto one_m = CT::Mask::is_equal(input[i], 1); + + const auto add_m = waiting_for_delim & zero_m; + + bad_input_m |= waiting_for_delim & ~(zero_m | one_m); + + delim_idx += add_m.if_set_return(1); + + waiting_for_delim &= zero_m; + } + + // If we never saw any non-zero byte, then it's not valid input + bad_input_m |= waiting_for_delim; + bad_input_m |= CT::Mask::is_zero(ct_compare_u8(&input[hlen], Phash.data(), hlen)); + + delim_idx += 1; + + valid_mask = (~bad_input_m).unpoisoned_value(); + const secure_vector output = CT::copy_output(bad_input_m, input, input_len, delim_idx); + + CT::unpoison(input, input_len); + + return output; + } + +/* +* Return the max input size for a given key size +*/ +size_t OAEP::maximum_input_size(size_t keybits) const + { + if(keybits / 8 > 2*m_Phash.size() + 1) + return ((keybits / 8) - 2*m_Phash.size() - 1); + else + return 0; + } + +/* +* OAEP Constructor +*/ +OAEP::OAEP(HashFunction* hash, const std::string& P) : m_mgf1_hash(hash) + { + m_Phash = m_mgf1_hash->process(P); + } + +OAEP::OAEP(HashFunction* hash, + HashFunction* mgf1_hash, + const std::string& P) : m_mgf1_hash(mgf1_hash) + { + std::unique_ptr phash(hash); // takes ownership + m_Phash = phash->process(P); + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.h b/comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.h new file mode 100644 index 0000000000..383617b82c --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_oaep/oaep.h @@ -0,0 +1,62 @@ +/* +* OAEP +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OAEP_H_ +#define BOTAN_OAEP_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(oaep.h) + +namespace Botan { + +/** +* OAEP (called EME1 in IEEE 1363 and in earlier versions of the library) +* as specified in PKCS#1 v2.0 (RFC 2437) +*/ +class BOTAN_PUBLIC_API(2,0) OAEP final : public EME + { + public: + size_t maximum_input_size(size_t) const override; + + /** + * @param hash function to use for hashing (takes ownership) + * @param P an optional label. Normally empty. + */ + OAEP(HashFunction* hash, const std::string& P = ""); + + /** + * @param hash function to use for hashing (takes ownership) + * @param mgf1_hash function to use for MGF1 (takes ownership) + * @param P an optional label. Normally empty. + */ + OAEP(HashFunction* hash, + HashFunction* mgf1_hash, + const std::string& P = ""); + private: + secure_vector pad(const uint8_t in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const override; + + secure_vector unpad(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const override; + + secure_vector m_Phash; + std::unique_ptr m_mgf1_hash; + }; + +secure_vector +BOTAN_TEST_API oaep_find_delim(uint8_t& valid_mask, + const uint8_t input[], size_t input_len, + const secure_vector& Phash); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp b/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp new file mode 100644 index 0000000000..eac3da5d9a --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp @@ -0,0 +1,109 @@ +/* +* PKCS #1 v1.5 Type 2 (encryption) padding +* (C) 1999-2007,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* PKCS1 Pad Operation +*/ +secure_vector EME_PKCS1v15::pad(const uint8_t in[], size_t inlen, + size_t key_length, + RandomNumberGenerator& rng) const + { + key_length /= 8; + + if(inlen > maximum_input_size(key_length * 8)) + { + throw Invalid_Argument("PKCS1: Input is too large"); + } + + secure_vector out(key_length); + + out[0] = 0x02; + rng.randomize(out.data() + 1, (key_length - inlen - 2)); + + for(size_t j = 1; j != key_length - inlen - 1; ++j) + { + if(out[j] == 0) + { + out[j] = rng.next_nonzero_byte(); + } + } + + buffer_insert(out, key_length - inlen, in, inlen); + + return out; + } + +/* +* PKCS1 Unpad Operation +*/ +secure_vector EME_PKCS1v15::unpad(uint8_t& valid_mask, + const uint8_t in[], size_t inlen) const + { + /* + * RSA decryption pads the ciphertext up to the modulus size, so this only + * occurs with very (!) small keys, or when fuzzing. + * + * 11 bytes == 00,02 + 8 bytes mandatory padding + 00 + */ + if(inlen < 11) + { + valid_mask = false; + return secure_vector(); + } + + CT::poison(in, inlen); + + CT::Mask bad_input_m = CT::Mask::cleared(); + CT::Mask seen_zero_m = CT::Mask::cleared(); + size_t delim_idx = 2; // initial 0002 + + bad_input_m |= ~CT::Mask::is_equal(in[0], 0); + bad_input_m |= ~CT::Mask::is_equal(in[1], 2); + + for(size_t i = 2; i < inlen; ++i) + { + const auto is_zero_m = CT::Mask::is_zero(in[i]); + delim_idx += seen_zero_m.if_not_set_return(1); + seen_zero_m |= is_zero_m; + } + + // no zero delim -> bad padding + bad_input_m |= ~seen_zero_m; + /* + delim indicates < 8 bytes padding -> bad padding + + We require 11 here because we are counting also the 00 delim byte + */ + bad_input_m |= CT::Mask(CT::Mask::is_lt(delim_idx, 11)); + + valid_mask = (~bad_input_m).unpoisoned_value(); + const secure_vector output = CT::copy_output(bad_input_m, in, inlen, delim_idx); + + CT::unpoison(in, inlen); + + return output; + } + +/* +* Return the max input size for a given key size +*/ +size_t EME_PKCS1v15::maximum_input_size(size_t keybits) const + { + if(keybits / 8 > 10) + return ((keybits / 8) - 10); + else + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.h b/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.h new file mode 100644 index 0000000000..fb7cf14197 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/eme_pkcs.h @@ -0,0 +1,35 @@ +/* +* EME PKCS#1 v1.5 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EME_PKCS1_H_ +#define BOTAN_EME_PKCS1_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(eme_pkcs.h) + +namespace Botan { + +/** +* EME from PKCS #1 v1.5 +*/ +class BOTAN_PUBLIC_API(2,0) EME_PKCS1v15 final : public EME + { + public: + size_t maximum_input_size(size_t) const override; + + secure_vector pad(const uint8_t[], size_t, size_t, + RandomNumberGenerator&) const override; + + secure_vector unpad(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/info.txt b/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/info.txt new file mode 100644 index 0000000000..772806e429 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_pkcs1/info.txt @@ -0,0 +1,4 @@ + +EME_PKCS1v15 -> 20131128 +EME_PKCS1 -> 20190426 + diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.cpp b/comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.cpp new file mode 100644 index 0000000000..066e7afd8c --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.cpp @@ -0,0 +1,31 @@ +/* +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +secure_vector EME_Raw::pad(const uint8_t in[], size_t in_length, + size_t, + RandomNumberGenerator&) const + { + return secure_vector(in, in + in_length); + } + +secure_vector EME_Raw::unpad(uint8_t& valid_mask, + const uint8_t in[], size_t in_length) const + { + valid_mask = 0xFF; + return CT::strip_leading_zeros(in, in_length); + } + +size_t EME_Raw::maximum_input_size(size_t keybits) const + { + return keybits / 8; + } +} diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.h b/comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.h new file mode 100644 index 0000000000..840448c559 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_raw/eme_raw.h @@ -0,0 +1,33 @@ +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EME_RAW_H_ +#define BOTAN_EME_RAW_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(eme_raw.h) + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) EME_Raw final : public EME + { + public: + size_t maximum_input_size(size_t i) const override; + + EME_Raw() = default; + private: + secure_vector pad(const uint8_t[], size_t, size_t, + RandomNumberGenerator&) const override; + + secure_vector unpad(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/eme_raw/info.txt b/comm/third_party/botan/src/lib/pk_pad/eme_raw/info.txt new file mode 100644 index 0000000000..c42365e98a --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/eme_raw/info.txt @@ -0,0 +1,3 @@ + +EME_RAW -> 20150313 + diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa.cpp b/comm/third_party/botan/src/lib/pk_pad/emsa.cpp new file mode 100644 index 0000000000..a3e4486862 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa.cpp @@ -0,0 +1,207 @@ +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_EMSA1) + #include +#endif + +#if defined(BOTAN_HAS_EMSA_X931) + #include +#endif + +#if defined(BOTAN_HAS_EMSA_PKCS1) + #include +#endif + +#if defined(BOTAN_HAS_EMSA_PSSR) + #include +#endif + +#if defined(BOTAN_HAS_EMSA_RAW) + #include +#endif + +#if defined(BOTAN_HAS_ISO_9796) + #include +#endif + +namespace Botan { + +AlgorithmIdentifier EMSA::config_for_x509(const Private_Key&, + const std::string&) const + { + throw Not_Implemented("Encoding " + name() + " not supported for signing X509 objects"); + } + +EMSA* get_emsa(const std::string& algo_spec) + { + SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_EMSA1) + if(req.algo_name() == "EMSA1" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return new EMSA1(hash.release()); + } +#endif + +#if defined(BOTAN_HAS_EMSA_PKCS1) + if(req.algo_name() == "EMSA_PKCS1" || + req.algo_name() == "PKCS1v15" || + req.algo_name() == "EMSA-PKCS1-v1_5" || + req.algo_name() == "EMSA3") + { + if(req.arg_count() == 2 && req.arg(0) == "Raw") + { + return new EMSA_PKCS1v15_Raw(req.arg(1)); + } + else if(req.arg_count() == 1) + { + if(req.arg(0) == "Raw") + { + return new EMSA_PKCS1v15_Raw; + } + else + { + if(auto hash = HashFunction::create(req.arg(0))) + { + return new EMSA_PKCS1v15(hash.release()); + } + } + } + } +#endif + +#if defined(BOTAN_HAS_EMSA_PSSR) + if(req.algo_name() == "PSS_Raw" || + req.algo_name() == "PSSR_Raw") + { + if(req.arg_count_between(1, 3) && req.arg(1, "MGF1") == "MGF1") + { + if(auto h = HashFunction::create(req.arg(0))) + { + if(req.arg_count() == 3) + { + const size_t salt_size = req.arg_as_integer(2, 0); + return new PSSR_Raw(h.release(), salt_size); + } + else + { + return new PSSR_Raw(h.release()); + } + } + } + } + + if(req.algo_name() == "PSS" || + req.algo_name() == "PSSR" || + req.algo_name() == "EMSA-PSS" || + req.algo_name() == "PSS-MGF1" || + req.algo_name() == "EMSA4") + { + if(req.arg_count_between(1, 3) && req.arg(1, "MGF1") == "MGF1") + { + if(auto h = HashFunction::create(req.arg(0))) + { + if(req.arg_count() == 3) + { + const size_t salt_size = req.arg_as_integer(2, 0); + return new PSSR(h.release(), salt_size); + } + else + { + return new PSSR(h.release()); + } + } + } + } +#endif + +#if defined(BOTAN_HAS_ISO_9796) + if(req.algo_name() == "ISO_9796_DS2") + { + if(req.arg_count_between(1, 3)) + { + if(auto h = HashFunction::create(req.arg(0))) + { + const size_t salt_size = req.arg_as_integer(2, h->output_length()); + const bool implicit = req.arg(1, "exp") == "imp"; + return new ISO_9796_DS2(h.release(), implicit, salt_size); + } + } + } + //ISO-9796-2 DS 3 is deterministic and DS2 without a salt + if(req.algo_name() == "ISO_9796_DS3") + { + if(req.arg_count_between(1, 2)) + { + if(auto h = HashFunction::create(req.arg(0))) + { + const bool implicit = req.arg(1, "exp") == "imp"; + return new ISO_9796_DS3(h.release(), implicit); + } + } + } +#endif + +#if defined(BOTAN_HAS_EMSA_X931) + if(req.algo_name() == "EMSA_X931" || + req.algo_name() == "EMSA2" || + req.algo_name() == "X9.31") + { + if(req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + { + return new EMSA_X931(hash.release()); + } + } + } +#endif + +#if defined(BOTAN_HAS_EMSA_RAW) + if(req.algo_name() == "Raw") + { + if(req.arg_count() == 0) + { + return new EMSA_Raw; + } + else + { + auto hash = HashFunction::create(req.arg(0)); + if(hash) + return new EMSA_Raw(hash->output_length()); + } + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +std::string hash_for_emsa(const std::string& algo_spec) + { + SCAN_Name emsa_name(algo_spec); + + if(emsa_name.arg_count() > 0) + { + const std::string pos_hash = emsa_name.arg(0); + return pos_hash; + } + + // If we don't understand what this is return a safe default +#if defined(BOTAN_HAS_SHA2_64) + return "SHA-512"; +#else + return "SHA-256"; +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa.h b/comm/third_party/botan/src/lib/pk_pad/emsa.h new file mode 100644 index 0000000000..7178eae237 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa.h @@ -0,0 +1,107 @@ +/* +* EMSA Classes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PUBKEY_EMSA_H_ +#define BOTAN_PUBKEY_EMSA_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(emsa.h) + +namespace Botan { + +class Private_Key; +class RandomNumberGenerator; + +/** +* EMSA, from IEEE 1363s Encoding Method for Signatures, Appendix +* +* Any way of encoding/padding signatures +*/ +class BOTAN_PUBLIC_API(2,0) EMSA + { + public: + virtual ~EMSA() = default; + + /** + * Add more data to the signature computation + * @param input some data + * @param length length of input in bytes + */ + virtual void update(const uint8_t input[], size_t length) = 0; + + /** + * @return raw hash + */ + virtual secure_vector raw_data() = 0; + + /** + * Return the encoding of a message + * @param msg the result of raw_data() + * @param output_bits the desired output bit size + * @param rng a random number generator + * @return encoded signature + */ + virtual secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) = 0; + + /** + * Verify the encoding + * @param coded the received (coded) message representative + * @param raw the computed (local, uncoded) message representative + * @param key_bits the size of the key in bits + * @return true if coded is a valid encoding of raw, otherwise false + */ + virtual bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) = 0; + + /** + * Prepare sig_algo for use in choose_sig_format for x509 certs + * + * @param key used for checking compatibility with the encoding scheme + * @param cert_hash_name is checked to equal the hash for the encoding + * @return algorithm identifier to signatures created using this key, + * padding method and hash. + */ + virtual AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const; + + /** + * @return a new object representing the same encoding method as *this + */ + virtual EMSA* clone() = 0; + + /** + * @return the SCAN name of the encoding/padding scheme + */ + virtual std::string name() const = 0; + }; + +/** +* Factory method for EMSA (message-encoding methods for signatures +* with appendix) objects +* @param algo_spec the name of the EMSA to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_PUBLIC_API(2,0) EMSA* get_emsa(const std::string& algo_spec); + +/** +* Returns the hash function used in the given EMSA scheme +* If the hash function is not specified or not understood, +* returns "SHA-512" +* @param algo_spec the name of the EMSA +* @return hash function used in the given EMSA scheme +*/ +BOTAN_PUBLIC_API(2,0) std::string hash_for_emsa(const std::string& algo_spec); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.cpp b/comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.cpp new file mode 100644 index 0000000000..f7293db270 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.cpp @@ -0,0 +1,133 @@ +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector emsa1_encoding(const secure_vector& msg, + size_t output_bits) + { + if(8*msg.size() <= output_bits) + return msg; + + size_t shift = 8*msg.size() - output_bits; + + size_t byte_shift = shift / 8, bit_shift = shift % 8; + secure_vector digest(msg.size() - byte_shift); + + for(size_t j = 0; j != msg.size() - byte_shift; ++j) + digest[j] = msg[j]; + + if(bit_shift) + { + uint8_t carry = 0; + for(size_t j = 0; j != digest.size(); ++j) + { + uint8_t temp = digest[j]; + digest[j] = (temp >> bit_shift) | carry; + carry = (temp << (8 - bit_shift)); + } + } + return digest; + } + +} + +std::string EMSA1::name() const + { + return "EMSA1(" + m_hash->name() + ")"; + } + +EMSA* EMSA1::clone() + { + return new EMSA1(m_hash->clone()); + } + +void EMSA1::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +secure_vector EMSA1::raw_data() + { + return m_hash->final(); + } + +secure_vector EMSA1::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash_output_length()) + throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); + return emsa1_encoding(msg, output_bits); + } + +bool EMSA1::verify(const secure_vector& input, + const secure_vector& raw, + size_t key_bits) + { + if(raw.size() != m_hash->output_length()) + return false; + + // Call emsa1_encoding to handle any required bit shifting + const secure_vector our_coding = emsa1_encoding(raw, key_bits); + + if(our_coding.size() < input.size()) + return false; + + const size_t offset = our_coding.size() - input.size(); // must be >= 0 per check above + + // If our encoding is longer, all the bytes in it must be zero + for(size_t i = 0; i != offset; ++i) + if(our_coding[i] != 0) + return false; + + return constant_time_compare(input.data(), &our_coding[offset], input.size()); + } + +AlgorithmIdentifier EMSA1::config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const + { + if(cert_hash_name != m_hash->name()) + throw Invalid_Argument("Hash function from opts and hash_fn argument" + " need to be identical"); + // check that the signature algorithm and the padding scheme fit + if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA1")) + { + throw Invalid_Argument("Encoding scheme with canonical name EMSA1" + " not supported for signature algorithm " + key.algo_name()); + } + + const OID oid = OID::from_string(key.algo_name() + "/" + name()); + + const std::string algo_name = key.algo_name(); + std::vector parameters; + if(algo_name == "DSA" || + algo_name == "ECDSA" || + algo_name == "ECGDSA" || + algo_name == "ECKCDSA" || + algo_name == "GOST-34.10" || + algo_name == "GOST-34.10-2012-256" || + algo_name == "GOST-34.10-2012-512") + { + // for DSA, ECDSA, GOST parameters "SHALL" be empty + } + else + { + parameters = key.algorithm_identifier().get_parameters(); + } + + return AlgorithmIdentifier(oid, parameters); + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.h b/comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.h new file mode 100644 index 0000000000..76736bc276 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa1/emsa1.h @@ -0,0 +1,55 @@ +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EMSA1_H_ +#define BOTAN_EMSA1_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(emsa1.h) + +namespace Botan { + +/** +* EMSA1 from IEEE 1363 +* Essentially, sign the hash directly +*/ +class BOTAN_PUBLIC_API(2,0) EMSA1 final : public EMSA + { + public: + /** + * @param hash the hash function to use + */ + explicit EMSA1(HashFunction* hash) : m_hash(hash) {} + + EMSA* clone() override; + + std::string name() const override; + + AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const override; + private: + size_t hash_output_length() const { return m_hash->output_length(); } + + void update(const uint8_t[], size_t) override; + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) override; + + std::unique_ptr m_hash; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa1/info.txt b/comm/third_party/botan/src/lib/pk_pad/emsa1/info.txt new file mode 100644 index 0000000000..5b5bf1f6b0 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa1/info.txt @@ -0,0 +1,3 @@ + +EMSA1 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp b/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp new file mode 100644 index 0000000000..85556a39ed --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp @@ -0,0 +1,166 @@ +/* +* PKCS #1 v1.5 signature padding +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector emsa3_encoding(const secure_vector& msg, + size_t output_bits, + const uint8_t hash_id[], + size_t hash_id_length) + { + size_t output_length = output_bits / 8; + if(output_length < hash_id_length + msg.size() + 10) + throw Encoding_Error("emsa3_encoding: Output length is too small"); + + secure_vector T(output_length); + const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2; + + T[0] = 0x01; + set_mem(&T[1], P_LENGTH, 0xFF); + T[P_LENGTH+1] = 0x00; + + if(hash_id_length > 0) + { + BOTAN_ASSERT_NONNULL(hash_id); + buffer_insert(T, P_LENGTH+2, hash_id, hash_id_length); + } + + buffer_insert(T, output_length-msg.size(), msg.data(), msg.size()); + return T; + } + +} + +void EMSA_PKCS1v15::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +secure_vector EMSA_PKCS1v15::raw_data() + { + return m_hash->final(); + } + +secure_vector +EMSA_PKCS1v15::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != m_hash->output_length()) + throw Encoding_Error("EMSA_PKCS1v15::encoding_of: Bad input length"); + + return emsa3_encoding(msg, output_bits, + m_hash_id.data(), m_hash_id.size()); + } + +bool EMSA_PKCS1v15::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + if(raw.size() != m_hash->output_length()) + return false; + + try + { + return (coded == emsa3_encoding(raw, key_bits, + m_hash_id.data(), m_hash_id.size())); + } + catch(...) + { + return false; + } + } + +AlgorithmIdentifier EMSA_PKCS1v15::config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const + { + if(cert_hash_name != m_hash->name()) + throw Invalid_Argument("Hash function from opts and hash_fn argument" + " need to be identical"); + // check that the signature algorithm and the padding scheme fit + if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA3")) + { + throw Invalid_Argument("Encoding scheme with canonical name EMSA3" + " not supported for signature algorithm " + key.algo_name()); + } + + // for RSA PKCSv1.5 parameters "SHALL" be NULL + + const OID oid = OID::from_string(key.algo_name() + "/" + name()); + return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_NULL_PARAM); + } + +EMSA_PKCS1v15::EMSA_PKCS1v15(HashFunction* hash) : m_hash(hash) + { + m_hash_id = pkcs_hash_id(m_hash->name()); + } + +EMSA_PKCS1v15_Raw::EMSA_PKCS1v15_Raw(const std::string& hash_algo) + { + if(!hash_algo.empty()) + { + m_hash_id = pkcs_hash_id(hash_algo); + std::unique_ptr hash(HashFunction::create_or_throw(hash_algo)); + m_hash_name = hash->name(); + m_hash_output_len = hash->output_length(); + } + else + { + m_hash_output_len = 0; + } + } + +void EMSA_PKCS1v15_Raw::update(const uint8_t input[], size_t length) + { + m_message += std::make_pair(input, length); + } + +secure_vector EMSA_PKCS1v15_Raw::raw_data() + { + secure_vector ret; + std::swap(ret, m_message); + + if(m_hash_output_len > 0 && ret.size() != m_hash_output_len) + throw Encoding_Error("EMSA_PKCS1v15_Raw::encoding_of: Bad input length"); + + return ret; + } + +secure_vector +EMSA_PKCS1v15_Raw::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa3_encoding(msg, output_bits, m_hash_id.data(), m_hash_id.size()); + } + +bool EMSA_PKCS1v15_Raw::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + if(m_hash_output_len > 0 && raw.size() != m_hash_output_len) + return false; + + try + { + return (coded == emsa3_encoding(raw, key_bits, m_hash_id.data(), m_hash_id.size())); + } + catch(...) + { + return false; + } + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h b/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h new file mode 100644 index 0000000000..5b9cf7aea7 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h @@ -0,0 +1,94 @@ +/* +* PKCS #1 v1.5 signature padding +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EMSA_PKCS1_H_ +#define BOTAN_EMSA_PKCS1_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(emsa_pkcs1.h) + +namespace Botan { + +/** +* PKCS #1 v1.5 signature padding +* aka PKCS #1 block type 1 +* aka EMSA3 from IEEE 1363 +*/ +class BOTAN_PUBLIC_API(2,0) EMSA_PKCS1v15 final : public EMSA + { + public: + /** + * @param hash the hash function to use + */ + explicit EMSA_PKCS1v15(HashFunction* hash); + + EMSA* clone() override { return new EMSA_PKCS1v15(m_hash->clone()); } + + void update(const uint8_t[], size_t) override; + + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector&, const secure_vector&, + size_t) override; + + std::string name() const override + { return "EMSA3(" + m_hash->name() + ")"; } + + AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const override; + private: + std::unique_ptr m_hash; + std::vector m_hash_id; + }; + +/** +* EMSA_PKCS1v15_Raw which is EMSA_PKCS1v15 without a hash or digest id +* (which according to QCA docs is "identical to PKCS#11's CKM_RSA_PKCS +* mechanism", something I have not confirmed) +*/ +class BOTAN_PUBLIC_API(2,0) EMSA_PKCS1v15_Raw final : public EMSA + { + public: + EMSA* clone() override { return new EMSA_PKCS1v15_Raw(); } + + void update(const uint8_t[], size_t) override; + + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector&, const secure_vector&, + size_t) override; + + /** + * @param hash_algo if non-empty, the digest id for that hash is + * included in the signature. + */ + EMSA_PKCS1v15_Raw(const std::string& hash_algo = ""); + + std::string name() const override + { + if(m_hash_name.empty()) return "EMSA3(Raw)"; + else return "EMSA3(Raw," + m_hash_name + ")"; + } + + private: + size_t m_hash_output_len = 0; + std::string m_hash_name; + std::vector m_hash_id; + secure_vector m_message; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/info.txt b/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/info.txt new file mode 100644 index 0000000000..b70f4e2445 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_pkcs1/info.txt @@ -0,0 +1,7 @@ + +EMSA_PKCS1 -> 20140118 + + + +hash_id + diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/info.txt b/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/info.txt new file mode 100644 index 0000000000..f514936c37 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/info.txt @@ -0,0 +1,7 @@ + +EMSA_PSSR -> 20131128 + + + +mgf1 + diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp b/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp new file mode 100644 index 0000000000..652a7628ba --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp @@ -0,0 +1,291 @@ +/* +* PSSR +* (C) 1999-2007,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* PSSR Encode Operation +*/ +secure_vector pss_encode(HashFunction& hash, + const secure_vector& msg, + const secure_vector& salt, + size_t output_bits) + { + const size_t HASH_SIZE = hash.output_length(); + const size_t SALT_SIZE = salt.size(); + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("Cannot encode PSS string, input length invalid for hash"); + if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9) + throw Encoding_Error("Cannot encode PSS string, output length too small"); + + const size_t output_length = (output_bits + 7) / 8; + + for(size_t i = 0; i != 8; ++i) + hash.update(0); + hash.update(msg); + hash.update(salt); + secure_vector H = hash.final(); + + secure_vector EM(output_length); + + EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01; + buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt); + mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1); + EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); + buffer_insert(EM, output_length - 1 - HASH_SIZE, H); + EM[output_length-1] = 0xBC; + return EM; + } + +bool pss_verify(HashFunction& hash, + const secure_vector& pss_repr, + const secure_vector& message_hash, + size_t key_bits, + size_t* out_salt_size) + { + const size_t HASH_SIZE = hash.output_length(); + const size_t KEY_BYTES = (key_bits + 7) / 8; + + if(key_bits < 8*HASH_SIZE + 9) + return false; + + if(message_hash.size() != HASH_SIZE) + return false; + + if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1) + return false; + + if(pss_repr[pss_repr.size()-1] != 0xBC) + return false; + + secure_vector coded = pss_repr; + if(coded.size() < KEY_BYTES) + { + secure_vector temp(KEY_BYTES); + buffer_insert(temp, KEY_BYTES - coded.size(), coded); + coded = temp; + } + + const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; + if(TOP_BITS > 8 - high_bit(coded[0])) + return false; + + uint8_t* DB = coded.data(); + const size_t DB_size = coded.size() - HASH_SIZE - 1; + + const uint8_t* H = &coded[DB_size]; + const size_t H_size = HASH_SIZE; + + mgf1_mask(hash, H, H_size, DB, DB_size); + DB[0] &= 0xFF >> TOP_BITS; + + size_t salt_offset = 0; + for(size_t j = 0; j != DB_size; ++j) + { + if(DB[j] == 0x01) + { salt_offset = j + 1; break; } + if(DB[j]) + return false; + } + if(salt_offset == 0) + return false; + + const size_t salt_size = DB_size - salt_offset; + + for(size_t j = 0; j != 8; ++j) + hash.update(0); + hash.update(message_hash); + hash.update(&DB[salt_offset], salt_size); + + const secure_vector H2 = hash.final(); + + const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE); + + if(out_salt_size && ok) + *out_salt_size = salt_size; + + return ok; + } + +} + +PSSR::PSSR(HashFunction* h) : + m_hash(h), + m_salt_size(m_hash->output_length()), + m_required_salt_len(false) + { + } + +PSSR::PSSR(HashFunction* h, size_t salt_size) : + m_hash(h), + m_salt_size(salt_size), + m_required_salt_len(true) + { + } + +/* +* PSSR Update Operation +*/ +void PSSR::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector PSSR::raw_data() + { + return m_hash->final(); + } + +secure_vector PSSR::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + const secure_vector salt = rng.random_vec(m_salt_size); + return pss_encode(*m_hash, msg, salt, output_bits); + } + +/* +* PSSR Decode/Verify Operation +*/ +bool PSSR::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + size_t salt_size = 0; + const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size); + + if(m_required_salt_len && salt_size != m_salt_size) + return false; + + return ok; + } + +EMSA* PSSR::clone() + { + return new PSSR(m_hash->clone(), m_salt_size); + } + +std::string PSSR::name() const + { + return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")"; + } + +AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const + { + if(cert_hash_name != m_hash->name()) + throw Invalid_Argument("Hash function from opts and hash_fn argument" + " need to be identical"); + // check that the signature algorithm and the padding scheme fit + if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4")) + { + throw Invalid_Argument("Encoding scheme with canonical name EMSA4" + " not supported for signature algorithm " + key.algo_name()); + } + + const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM); + const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode()); + + std::vector parameters; + DER_Encoder(parameters) + .start_cons(SEQUENCE) + .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).encode(hash_id).end_cons() + .start_cons(ASN1_Tag(1), CONTEXT_SPECIFIC).encode(mgf_id).end_cons() + .start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_salt_size).end_cons() + .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field + .end_cons(); + + // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment + return AlgorithmIdentifier("RSA/EMSA4", parameters); + } + +PSSR_Raw::PSSR_Raw(HashFunction* h) : + m_hash(h), + m_salt_size(m_hash->output_length()), + m_required_salt_len(false) + { + } + +PSSR_Raw::PSSR_Raw(HashFunction* h, size_t salt_size) : + m_hash(h), + m_salt_size(salt_size), + m_required_salt_len(true) + { + } + +/* +* PSSR_Raw Update Operation +*/ +void PSSR_Raw::update(const uint8_t input[], size_t length) + { + m_msg.insert(m_msg.end(), input, input + length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector PSSR_Raw::raw_data() + { + secure_vector ret; + std::swap(ret, m_msg); + + if(ret.size() != m_hash->output_length()) + throw Encoding_Error("PSSR_Raw Bad input length, did not match hash"); + + return ret; + } + +secure_vector PSSR_Raw::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + secure_vector salt = rng.random_vec(m_salt_size); + return pss_encode(*m_hash, msg, salt, output_bits); + } + +/* +* PSSR_Raw Decode/Verify Operation +*/ +bool PSSR_Raw::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + size_t salt_size = 0; + const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size); + + if(m_required_salt_len && salt_size != m_salt_size) + return false; + + return ok; + } + +EMSA* PSSR_Raw::clone() + { + return new PSSR_Raw(m_hash->clone(), m_salt_size); + } + +std::string PSSR_Raw::name() const + { + return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")"; + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.h b/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.h new file mode 100644 index 0000000000..47efacb518 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_pssr/pssr.h @@ -0,0 +1,103 @@ +/* +* PSSR +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PSSR_H_ +#define BOTAN_PSSR_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(pssr.h) + +namespace Botan { + +/** +* PSSR (called EMSA4 in IEEE 1363 and in old versions of the library) +*/ +class BOTAN_PUBLIC_API(2,0) PSSR final : public EMSA + { + public: + + /** + * @param hash the hash function to use + */ + explicit PSSR(HashFunction* hash); + + /** + * @param hash the hash function to use + * @param salt_size the size of the salt to use in bytes + */ + PSSR(HashFunction* hash, size_t salt_size); + + EMSA* clone() override; + + std::string name() const override; + + AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const override; + private: + void update(const uint8_t input[], size_t length) override; + + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) override; + + std::unique_ptr m_hash; + size_t m_salt_size; + bool m_required_salt_len; + }; + +/** +* PSSR_Raw +* This accepts a pre-hashed buffer +*/ +class BOTAN_PUBLIC_API(2,3) PSSR_Raw final : public EMSA + { + public: + + /** + * @param hash the hash function to use + */ + explicit PSSR_Raw(HashFunction* hash); + + /** + * @param hash the hash function to use + * @param salt_size the size of the salt to use in bytes + */ + PSSR_Raw(HashFunction* hash, size_t salt_size); + + EMSA* clone() override; + + std::string name() const override; + private: + void update(const uint8_t input[], size_t length) override; + + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) override; + + std::unique_ptr m_hash; + secure_vector m_msg; + size_t m_salt_size; + bool m_required_salt_len; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.cpp b/comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.cpp new file mode 100644 index 0000000000..0ac11dc5ad --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.cpp @@ -0,0 +1,92 @@ +/* +* EMSA-Raw +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::string EMSA_Raw::name() const + { + if(m_expected_size > 0) + return "Raw(" + std::to_string(m_expected_size) + ")"; + return "Raw"; + } + +/* +* EMSA-Raw Encode Operation +*/ +void EMSA_Raw::update(const uint8_t input[], size_t length) + { + m_message += std::make_pair(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector EMSA_Raw::raw_data() + { + if(m_expected_size && m_message.size() != m_expected_size) + throw Invalid_Argument("EMSA_Raw was configured to use a " + + std::to_string(m_expected_size) + + " byte hash but instead was used for a " + + std::to_string(m_message.size()) + " hash"); + + secure_vector output; + std::swap(m_message, output); + return output; + } + +/* +* EMSA-Raw Encode Operation +*/ +secure_vector +EMSA_Raw::encoding_of(const secure_vector& msg, + size_t, + RandomNumberGenerator&) + { + if(m_expected_size && msg.size() != m_expected_size) + throw Invalid_Argument("EMSA_Raw was configured to use a " + + std::to_string(m_expected_size) + + " byte hash but instead was used for a " + + std::to_string(msg.size()) + " hash"); + + return msg; + } + +/* +* EMSA-Raw Verify Operation +*/ +bool EMSA_Raw::verify(const secure_vector& coded, + const secure_vector& raw, + size_t) + { + if(m_expected_size && raw.size() != m_expected_size) + return false; + + if(coded.size() == raw.size()) + return (coded == raw); + + if(coded.size() > raw.size()) + return false; + + // handle zero padding differences + const size_t leading_zeros_expected = raw.size() - coded.size(); + + bool same_modulo_leading_zeros = true; + + for(size_t i = 0; i != leading_zeros_expected; ++i) + if(raw[i]) + same_modulo_leading_zeros = false; + + if(!constant_time_compare(coded.data(), raw.data() + leading_zeros_expected, coded.size())) + same_modulo_leading_zeros = false; + + return same_modulo_leading_zeros; + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.h b/comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.h new file mode 100644 index 0000000000..dc01b94a2d --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_raw/emsa_raw.h @@ -0,0 +1,47 @@ +/* +* EMSA-Raw +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EMSA_RAW_H_ +#define BOTAN_EMSA_RAW_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(emsa_raw.h) + +namespace Botan { + +/** +* EMSA-Raw - sign inputs directly +* Don't use this unless you know what you are doing. +*/ +class BOTAN_PUBLIC_API(2,0) EMSA_Raw final : public EMSA + { + public: + EMSA* clone() override { return new EMSA_Raw(); } + + explicit EMSA_Raw(size_t expected_hash_size = 0) : + m_expected_size(expected_hash_size) {} + + std::string name() const override; + private: + void update(const uint8_t[], size_t) override; + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator&) override; + + bool verify(const secure_vector&, + const secure_vector&, + size_t) override; + + const size_t m_expected_size; + secure_vector m_message; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_raw/info.txt b/comm/third_party/botan/src/lib/pk_pad/emsa_raw/info.txt new file mode 100644 index 0000000000..ffd3cbe3b3 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_raw/info.txt @@ -0,0 +1,3 @@ + +EMSA_RAW -> 20131128 + diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.cpp b/comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.cpp new file mode 100644 index 0000000000..b1f698f86d --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.cpp @@ -0,0 +1,102 @@ +/* +* EMSA_X931 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector emsa2_encoding(const secure_vector& msg, + size_t output_bits, + const secure_vector& empty_hash, + uint8_t hash_id) + { + const size_t HASH_SIZE = empty_hash.size(); + + size_t output_length = (output_bits + 1) / 8; + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("EMSA_X931::encoding_of: Bad input length"); + if(output_length < HASH_SIZE + 4) + throw Encoding_Error("EMSA_X931::encoding_of: Output length is too small"); + + const bool empty_input = (msg == empty_hash); + + secure_vector output(output_length); + + output[0] = (empty_input ? 0x4B : 0x6B); + output[output_length - 3 - HASH_SIZE] = 0xBA; + set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB); + buffer_insert(output, output_length - (HASH_SIZE + 2), msg.data(), msg.size()); + output[output_length-2] = hash_id; + output[output_length-1] = 0xCC; + + return output; + } + +} + +std::string EMSA_X931::name() const + { + return "EMSA2(" + m_hash->name() + ")"; + } + +void EMSA_X931::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +secure_vector EMSA_X931::raw_data() + { + return m_hash->final(); + } + +/* +* EMSA_X931 Encode Operation +*/ +secure_vector EMSA_X931::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa2_encoding(msg, output_bits, m_empty_hash, m_hash_id); + } + +/* +* EMSA_X931 Verify Operation +*/ +bool EMSA_X931::verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) + { + try + { + return (coded == emsa2_encoding(raw, key_bits, + m_empty_hash, m_hash_id)); + } + catch(...) + { + return false; + } + } + +/* +* EMSA_X931 Constructor +*/ +EMSA_X931::EMSA_X931(HashFunction* hash) : m_hash(hash) + { + m_empty_hash = m_hash->final(); + + m_hash_id = ieee1363_hash_id(hash->name()); + + if(!m_hash_id) + throw Encoding_Error("EMSA_X931 no hash identifier for " + hash->name()); + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.h b/comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.h new file mode 100644 index 0000000000..a2fef0468a --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_x931/emsa_x931.h @@ -0,0 +1,52 @@ +/* +* X9.31 EMSA +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EMSA_X931_H_ +#define BOTAN_EMSA_X931_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(emsa_x931.h) + +namespace Botan { + +/** +* EMSA from X9.31 (EMSA2 in IEEE 1363) +* Useful for Rabin-Williams, also sometimes used with RSA in +* odd protocols. +*/ +class BOTAN_PUBLIC_API(2,0) EMSA_X931 final : public EMSA + { + public: + /** + * @param hash the hash function to use + */ + explicit EMSA_X931(HashFunction* hash); + + EMSA* clone() override { return new EMSA_X931(m_hash->clone()); } + + std::string name() const override; + + private: + void update(const uint8_t[], size_t) override; + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector&, size_t, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector&, const secure_vector&, + size_t) override; + + secure_vector m_empty_hash; + std::unique_ptr m_hash; + uint8_t m_hash_id; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/emsa_x931/info.txt b/comm/third_party/botan/src/lib/pk_pad/emsa_x931/info.txt new file mode 100644 index 0000000000..d3c5ca76ea --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/emsa_x931/info.txt @@ -0,0 +1,7 @@ + +EMSA_X931 -> 20140118 + + + +hash_id + diff --git a/comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.cpp b/comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.cpp new file mode 100644 index 0000000000..ec317f9692 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.cpp @@ -0,0 +1,163 @@ +/* +* Hash Function Identification +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +const uint8_t MD5_PKCS_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + +const uint8_t RIPEMD_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x01, 0x05, 0x00, 0x04, 0x14 }; + +const uint8_t SHA_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, +0x1A, 0x05, 0x00, 0x04, 0x14 }; + +const uint8_t SHA_224_PKCS_ID[] = { +0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C }; + +const uint8_t SHA_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; + +const uint8_t SHA_384_PKCS_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; + +const uint8_t SHA_512_PKCS_ID[] = { +0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; + +const uint8_t SHA_512_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20 }; + +const uint8_t SHA3_224_PKCS_ID[] = { +0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x07, 0x05, 0x00, 0x04, 0x1C }; + +const uint8_t SHA3_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20 }; + +const uint8_t SHA3_384_PKCS_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, 0x30 }; + +const uint8_t SHA3_512_PKCS_ID[] = { +0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x0A, 0x05, 0x00, 0x04, 0x40 }; + +const uint8_t SM3_PKCS_ID[] = { +0x30, 0x30, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x81, 0x1C, 0xCF, +0x55, 0x01, 0x83, 0x11, 0x05, 0x00, 0x04, 0x20, +}; + +const uint8_t TIGER_PKCS_ID[] = { +0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, +0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 }; + +} + +/* +* HashID as specified by PKCS +*/ +std::vector pkcs_hash_id(const std::string& name) + { + // Special case for SSL/TLS RSA signatures + if(name == "Parallel(MD5,SHA-160)") + return std::vector(); + + // If you add a value to this function, also update test_hash_id.cpp + + if(name == "MD5") + return std::vector(MD5_PKCS_ID, + MD5_PKCS_ID + sizeof(MD5_PKCS_ID)); + + if(name == "RIPEMD-160") + return std::vector(RIPEMD_160_PKCS_ID, + RIPEMD_160_PKCS_ID + sizeof(RIPEMD_160_PKCS_ID)); + + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return std::vector(SHA_160_PKCS_ID, + SHA_160_PKCS_ID + sizeof(SHA_160_PKCS_ID)); + + if(name == "SHA-224") + return std::vector(SHA_224_PKCS_ID, + SHA_224_PKCS_ID + sizeof(SHA_224_PKCS_ID)); + + if(name == "SHA-256") + return std::vector(SHA_256_PKCS_ID, + SHA_256_PKCS_ID + sizeof(SHA_256_PKCS_ID)); + + if(name == "SHA-384") + return std::vector(SHA_384_PKCS_ID, + SHA_384_PKCS_ID + sizeof(SHA_384_PKCS_ID)); + + if(name == "SHA-512") + return std::vector(SHA_512_PKCS_ID, + SHA_512_PKCS_ID + sizeof(SHA_512_PKCS_ID)); + + if(name == "SHA-512-256") + return std::vector(SHA_512_256_PKCS_ID, + SHA_512_256_PKCS_ID + sizeof(SHA_512_256_PKCS_ID)); + + if(name == "SHA-3(224)") + return std::vector(SHA3_224_PKCS_ID, + SHA3_224_PKCS_ID + sizeof(SHA3_224_PKCS_ID)); + + if(name == "SHA-3(256)") + return std::vector(SHA3_256_PKCS_ID, + SHA3_256_PKCS_ID + sizeof(SHA3_256_PKCS_ID)); + + if(name == "SHA-3(384)") + return std::vector(SHA3_384_PKCS_ID, + SHA3_384_PKCS_ID + sizeof(SHA3_384_PKCS_ID)); + + if(name == "SHA-3(512)") + return std::vector(SHA3_512_PKCS_ID, + SHA3_512_PKCS_ID + sizeof(SHA3_512_PKCS_ID)); + + if(name == "SM3") + return std::vector(SM3_PKCS_ID, SM3_PKCS_ID + sizeof(SM3_PKCS_ID)); + + if(name == "Tiger(24,3)") + return std::vector(TIGER_PKCS_ID, + TIGER_PKCS_ID + sizeof(TIGER_PKCS_ID)); + + throw Invalid_Argument("No PKCS #1 identifier for " + name); + } + +/* +* HashID as specified by IEEE 1363/X9.31 +*/ +uint8_t ieee1363_hash_id(const std::string& name) + { + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return 0x33; + + if(name == "SHA-224") return 0x38; + if(name == "SHA-256") return 0x34; + if(name == "SHA-384") return 0x36; + if(name == "SHA-512") return 0x35; + + if(name == "RIPEMD-160") return 0x31; + + if(name == "Whirlpool") return 0x37; + + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.h b/comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.h new file mode 100644 index 0000000000..75c86c0c65 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/hash_id/hash_id.h @@ -0,0 +1,34 @@ +/* +* Hash Function Identification +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HASHID_H_ +#define BOTAN_HASHID_H_ + +#include +#include + +namespace Botan { + +/** +* Return the PKCS #1 hash identifier +* @see RFC 3447 section 9.2 +* @param hash_name the name of the hash function +* @return uint8_t sequence identifying the hash +* @throw Invalid_Argument if the hash has no known PKCS #1 hash id +*/ +BOTAN_PUBLIC_API(2,0) std::vector pkcs_hash_id(const std::string& hash_name); + +/** +* Return the IEEE 1363 hash identifier +* @param hash_name the name of the hash function +* @return uint8_t code identifying the hash, or 0 if not known +*/ +BOTAN_PUBLIC_API(2,0) uint8_t ieee1363_hash_id(const std::string& hash_name); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/hash_id/info.txt b/comm/third_party/botan/src/lib/pk_pad/hash_id/info.txt new file mode 100644 index 0000000000..8cd930a9fe --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/hash_id/info.txt @@ -0,0 +1,3 @@ + +HASH_ID -> 20131128 + diff --git a/comm/third_party/botan/src/lib/pk_pad/info.txt b/comm/third_party/botan/src/lib/pk_pad/info.txt new file mode 100644 index 0000000000..e8fb00c8e3 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/info.txt @@ -0,0 +1,18 @@ + +PK_PADDING -> 20131128 + + + +asn1 +rng +pubkey + + + +padding.h + + + +eme.h +emsa.h + diff --git a/comm/third_party/botan/src/lib/pk_pad/iso9796/info.txt b/comm/third_party/botan/src/lib/pk_pad/iso9796/info.txt new file mode 100644 index 0000000000..92bdb3c7d2 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/iso9796/info.txt @@ -0,0 +1,9 @@ + +ISO_9796 -> 20161121 + + + +mgf1 +hash_id + + diff --git a/comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.cpp b/comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.cpp new file mode 100644 index 0000000000..9fdb87e3b5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.cpp @@ -0,0 +1,322 @@ +/* + * ISO-9796-2 - Digital signature schemes giving message recovery schemes 2 and 3 + * (C) 2016 Tobias Niemann, Hackmanit GmbH + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector iso9796_encoding(const secure_vector& msg, + size_t output_bits, + std::unique_ptr& hash, + size_t SALT_SIZE, + bool implicit, + RandomNumberGenerator& rng) + { + const size_t output_length = (output_bits + 7) / 8; + + //set trailer length + size_t tLength = 1; + if(!implicit) + { + tLength = 2; + } + const size_t HASH_SIZE = hash->output_length(); + + if(output_length <= HASH_SIZE + SALT_SIZE + tLength) + { + throw Encoding_Error("ISO9796-2::encoding_of: Output length is too small"); + } + + //calculate message capacity + const size_t capacity = output_length - HASH_SIZE - SALT_SIZE - tLength - 1; + + //msg1 is the recoverable and msg2 the unrecoverable message part. + secure_vector msg1; + secure_vector msg2; + if(msg.size() > capacity) + { + msg1 = secure_vector(msg.begin(), msg.begin() + capacity); + msg2 = secure_vector(msg.begin() + capacity, msg.end()); + hash->update(msg2); + } + else + { + msg1 = msg; + } + msg2 = hash->final(); + + //compute H(C||msg1 ||H(msg2)||S) + const size_t msgLength = msg1.size(); + secure_vector salt = rng.random_vec(SALT_SIZE); + hash->update_be(static_cast(msgLength) * 8); + hash->update(msg1); + hash->update(msg2); + hash->update(salt); + secure_vector H = hash->final(); + + secure_vector EM(output_length); + + //compute message offset. + const size_t offset = output_length - HASH_SIZE - SALT_SIZE - tLength - msgLength - 1; + + //insert message border (0x01), msg1 and salt into the output buffer + EM[offset] = 0x01; + buffer_insert(EM, offset + 1, msg1); + buffer_insert(EM, offset + 1 + msgLength, salt); + + //apply mask + mgf1_mask(*hash, H.data(), HASH_SIZE, EM.data(), + output_length - HASH_SIZE - tLength); + buffer_insert(EM, output_length - HASH_SIZE - tLength, H); + //set implicit/ISO trailer + if(!implicit) + { + uint8_t hash_id = ieee1363_hash_id(hash->name()); + if(!hash_id) + { + throw Encoding_Error("ISO9796-2::encoding_of: no hash identifier for " + hash->name()); + } + EM[output_length - 1] = 0xCC; + EM[output_length - 2] = hash_id; + + } + else + { + EM[output_length - 1] = 0xBC; + } + //clear the leftmost bit (confer bouncy castle) + EM[0] &= 0x7F; + + return EM; + } + +bool iso9796_verification(const secure_vector& const_coded, + const secure_vector& raw, size_t key_bits, std::unique_ptr& hash, size_t SALT_SIZE) + { + const size_t HASH_SIZE = hash->output_length(); + const size_t KEY_BYTES = (key_bits + 7) / 8; + + if(const_coded.size() != KEY_BYTES) + { + return false; + } + //get trailer length + size_t tLength; + if(const_coded[const_coded.size() - 1] == 0xBC) + { + tLength = 1; + } + else + { + uint8_t hash_id = ieee1363_hash_id(hash->name()); + if((!const_coded[const_coded.size() - 2]) || (const_coded[const_coded.size() - 2] != hash_id) || + (const_coded[const_coded.size() - 1] != 0xCC)) + { + return false; //in case of wrong ISO trailer. + } + tLength = 2; + } + + secure_vector coded = const_coded; + + CT::poison(coded.data(), coded.size()); + //remove mask + uint8_t* DB = coded.data(); + const size_t DB_size = coded.size() - HASH_SIZE - tLength; + + const uint8_t* H = &coded[DB_size]; + + mgf1_mask(*hash, H, HASH_SIZE, DB, DB_size); + //clear the leftmost bit (confer bouncy castle) + DB[0] &= 0x7F; + + //recover msg1 and salt + size_t msg1_offset = 1; + + auto waiting_for_delim = CT::Mask::set(); + auto bad_input = CT::Mask::cleared(); + + for(size_t j = 0; j < DB_size; ++j) + { + const auto is_zero = CT::Mask::is_zero(DB[j]); + const auto is_one = CT::Mask::is_equal(DB[j], 0x01); + + const auto add_m = waiting_for_delim & is_zero; + + bad_input |= waiting_for_delim & ~(is_zero | is_one); + msg1_offset += add_m.if_set_return(1); + + waiting_for_delim &= is_zero; + } + + //invalid, if delimiter 0x01 was not found or msg1_offset is too big + bad_input |= waiting_for_delim; + bad_input |= CT::Mask::is_lt(coded.size(), tLength + HASH_SIZE + msg1_offset + SALT_SIZE); + + //in case that msg1_offset is too big, just continue with offset = 0. + msg1_offset = CT::Mask::expand(bad_input.value()).if_not_set_return(msg1_offset); + + CT::unpoison(coded.data(), coded.size()); + CT::unpoison(msg1_offset); + + secure_vector msg1(coded.begin() + msg1_offset, + coded.end() - tLength - HASH_SIZE - SALT_SIZE); + secure_vector salt(coded.begin() + msg1_offset + msg1.size(), + coded.end() - tLength - HASH_SIZE); + + //compute H2(C||msg1||H(msg2)||S*). * indicates a recovered value + const size_t capacity = (key_bits - 2 + 7) / 8 - HASH_SIZE - SALT_SIZE - tLength - 1; + secure_vector msg1raw; + secure_vector msg2; + if(raw.size() > capacity) + { + msg1raw = secure_vector (raw.begin(), raw.begin() + capacity); + msg2 = secure_vector (raw.begin() + capacity, raw.end()); + hash->update(msg2); + } + else + { + msg1raw = raw; + } + msg2 = hash->final(); + + const uint64_t msg1rawLength = msg1raw.size(); + hash->update_be(msg1rawLength * 8); + hash->update(msg1raw); + hash->update(msg2); + hash->update(salt); + secure_vector H3 = hash->final(); + + //compute H3(C*||msg1*||H(msg2)||S*) * indicates a recovered value + const uint64_t msgLength = msg1.size(); + hash->update_be(msgLength * 8); + hash->update(msg1); + hash->update(msg2); + hash->update(salt); + secure_vector H2 = hash->final(); + + //check if H3 == H2 + bad_input |= CT::Mask::is_zero(ct_compare_u8(H3.data(), H2.data(), HASH_SIZE)); + + CT::unpoison(bad_input); + return (bad_input.is_set() == false); + } + +} + +EMSA* ISO_9796_DS2::clone() + { + return new ISO_9796_DS2(m_hash->clone(), m_implicit, m_SALT_SIZE); + } + +/* + * ISO-9796-2 signature scheme 2 + * DS 2 is probabilistic + */ +void ISO_9796_DS2::update(const uint8_t input[], size_t length) + { + //need to buffer message completely, before digest + m_msg_buffer.insert(m_msg_buffer.end(), input, input+length); + } + +/* + * Return the raw (unencoded) data + */ +secure_vector ISO_9796_DS2::raw_data() + { + secure_vector retbuffer = m_msg_buffer; + m_msg_buffer.clear(); + return retbuffer; + } + +/* + * ISO-9796-2 scheme 2 encode operation + */ +secure_vector ISO_9796_DS2::encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + return iso9796_encoding(msg, output_bits, m_hash, m_SALT_SIZE, m_implicit, rng); + } + +/* + * ISO-9796-2 scheme 2 verify operation + */ +bool ISO_9796_DS2::verify(const secure_vector& const_coded, + const secure_vector& raw, size_t key_bits) + { + return iso9796_verification(const_coded, raw, key_bits, m_hash, m_SALT_SIZE); + } + +/* + * Return the SCAN name + */ +std::string ISO_9796_DS2::name() const + { + return "ISO_9796_DS2(" + m_hash->name() + "," + + (m_implicit ? "imp" : "exp") + "," + std::to_string(m_SALT_SIZE) + ")"; + } + +EMSA* ISO_9796_DS3::clone() + { + return new ISO_9796_DS3(m_hash->clone(), m_implicit); + } + +/* + * ISO-9796-2 signature scheme 3 + * DS 3 is deterministic and equals DS2 without salt + */ +void ISO_9796_DS3::update(const uint8_t input[], size_t length) + { + //need to buffer message completely, before digest + m_msg_buffer.insert(m_msg_buffer.end(), input, input+length); + } + +/* + * Return the raw (unencoded) data + */ +secure_vector ISO_9796_DS3::raw_data() + { + secure_vector retbuffer = m_msg_buffer; + m_msg_buffer.clear(); + return retbuffer; + } + +/* + * ISO-9796-2 scheme 3 encode operation + */ +secure_vector ISO_9796_DS3::encoding_of(const secure_vector& msg, + size_t output_bits, RandomNumberGenerator& rng) + { + return iso9796_encoding(msg, output_bits, m_hash, 0, m_implicit, rng); + } + +/* + * ISO-9796-2 scheme 3 verify operation + */ +bool ISO_9796_DS3::verify(const secure_vector& const_coded, + const secure_vector& raw, size_t key_bits) + { + return iso9796_verification(const_coded, raw, key_bits, m_hash, 0); + } +/* + * Return the SCAN name + */ +std::string ISO_9796_DS3::name() const + { + return "ISO_9796_DS3(" + m_hash->name() + "," + + (m_implicit ? "imp" : "exp") + ")"; + } +} diff --git a/comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.h b/comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.h new file mode 100644 index 0000000000..9782e53b23 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/iso9796/iso9796.h @@ -0,0 +1,98 @@ +/* + * ISO-9796-2 - Digital signature schemes giving message recovery schemes 2 and 3 + * (C) 2016 Tobias Niemann, Hackmanit GmbH + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_ISO9796_H_ +#define BOTAN_ISO9796_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(iso9796.h) + +namespace Botan { + +/** +* ISO-9796-2 - Digital signature scheme 2 (probabilistic) +*/ +class BOTAN_PUBLIC_API(2,0) ISO_9796_DS2 final : public EMSA + { + public: + /** + * @param hash function to use + * @param implicit whether or not the trailer is implicit + */ + explicit ISO_9796_DS2(HashFunction* hash, bool implicit = false) : m_hash(hash), m_implicit(implicit), + m_SALT_SIZE(hash->output_length()) {} + + /** + * @param hash function to use + * @param implicit whether or not the trailer is implicit + * @param salt_size size of the salt to use in bytes + */ + ISO_9796_DS2(HashFunction* hash, bool implicit, size_t salt_size) : m_hash(hash), m_implicit(implicit), + m_SALT_SIZE(salt_size) {} + + EMSA* clone() override; + + std::string name() const override; + private: + void update(const uint8_t input[], size_t length) override; + + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) override; + + std::unique_ptr m_hash; + bool m_implicit; + size_t m_SALT_SIZE; + secure_vector m_msg_buffer; + }; + +/** +* ISO-9796-2 - Digital signature scheme 3 (deterministic) +*/ +class BOTAN_PUBLIC_API(2,0) ISO_9796_DS3 final : public EMSA + { + public: + /** + * @param hash function to use + * @param implicit whether or not the trailer is implicit + */ + ISO_9796_DS3(HashFunction* hash, bool implicit = false) : m_hash(hash), m_implicit(implicit) + {} + + EMSA* clone() override; + + std::string name() const override; + private: + void update(const uint8_t input[], size_t length) override; + + secure_vector raw_data() override; + + secure_vector encoding_of(const secure_vector& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector& coded, + const secure_vector& raw, + size_t key_bits) override; + + std::unique_ptr m_hash; + bool m_implicit; + secure_vector m_msg_buffer; + }; + +} + +#endif + diff --git a/comm/third_party/botan/src/lib/pk_pad/mgf1/info.txt b/comm/third_party/botan/src/lib/pk_pad/mgf1/info.txt new file mode 100644 index 0000000000..f17c72fda4 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/mgf1/info.txt @@ -0,0 +1,3 @@ + +MGF1 -> 20140118 + diff --git a/comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.cpp b/comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.cpp new file mode 100644 index 0000000000..2e7ef99734 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.cpp @@ -0,0 +1,36 @@ +/* +* MGF1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +void mgf1_mask(HashFunction& hash, + const uint8_t in[], size_t in_len, + uint8_t out[], size_t out_len) + { + uint32_t counter = 0; + + secure_vector buffer(hash.output_length()); + while(out_len) + { + hash.update(in, in_len); + hash.update_be(counter); + hash.final(buffer.data()); + + const size_t xored = std::min(buffer.size(), out_len); + xor_buf(out, buffer.data(), xored); + out += xored; + out_len -= xored; + + ++counter; + } + } + +} diff --git a/comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.h b/comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.h new file mode 100644 index 0000000000..9eb652a825 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/mgf1/mgf1.h @@ -0,0 +1,31 @@ +/* +* MGF1 +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MGF1_H_ +#define BOTAN_MGF1_H_ + +#include + +namespace Botan { + +class HashFunction; + +/** +* MGF1 from PKCS #1 v2.0 +* @param hash hash function to use +* @param in input buffer +* @param in_len size of the input buffer in bytes +* @param out output buffer +* @param out_len size of the output buffer in bytes +*/ +void BOTAN_PUBLIC_API(2,0) mgf1_mask(HashFunction& hash, + const uint8_t in[], size_t in_len, + uint8_t out[], size_t out_len); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pk_pad/padding.cpp b/comm/third_party/botan/src/lib/pk_pad/padding.cpp new file mode 100644 index 0000000000..bac3fcd7eb --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/padding.cpp @@ -0,0 +1,44 @@ +/* +* Sets of allowed padding schemes for public key types +* +* This file was automatically generated by ./src/scripts/oids.py on 2017-12-20 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +const std::map> allowed_signature_paddings = + { + { "DSA", {"EMSA1"} }, + { "ECDSA", {"EMSA1"} }, + { "ECGDSA", {"EMSA1"} }, + { "ECKCDSA", {"EMSA1"} }, + { "GOST-34.10", {"EMSA1"} }, + { "GOST-34.10-2012-256", {"EMSA1"} }, + { "GOST-34.10-2012-512", {"EMSA1"} }, + { "RSA", {"EMSA4", "EMSA3"} }, + }; + +const std::vector get_sig_paddings(const std::string algo) + { + if(allowed_signature_paddings.count(algo) > 0) + return allowed_signature_paddings.at(algo); + return {}; + } + +bool sig_algo_and_pad_ok(const std::string algo, const std::string padding) + { + std::vector pads = get_sig_paddings(algo); + return std::find(pads.begin(), pads.end(), padding) != pads.end(); + } +} diff --git a/comm/third_party/botan/src/lib/pk_pad/padding.h b/comm/third_party/botan/src/lib/pk_pad/padding.h new file mode 100644 index 0000000000..ed05ec3819 --- /dev/null +++ b/comm/third_party/botan/src/lib/pk_pad/padding.h @@ -0,0 +1,36 @@ +/* +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PADDING_H_ +#define BOTAN_PADDING_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Returns the allowed padding schemes when using the given +* algorithm (key type) for creating digital signatures. +* +* @param algo the algorithm for which to look up supported padding schemes +* @return a vector of supported padding schemes +*/ +BOTAN_TEST_API const std::vector get_sig_paddings(const std::string algo); + +/** +* Returns true iff the given padding scheme is valid for the given +* signature algorithm (key type). +* +* @param algo the signature algorithm to be used +* @param padding the padding scheme to be used +*/ +bool sig_algo_and_pad_ok(const std::string algo, const std::string padding); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto.h b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto.h new file mode 100644 index 0000000000..31fa110fc3 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto.h @@ -0,0 +1,62 @@ +/* +* Utils for calling CommonCrypto +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_INTERNAL_COMMONCRYPTO_H_ +#define BOTAN_INTERNAL_COMMONCRYPTO_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class Cipher_Mode; +class BlockCipher; +class HashFunction; +enum Cipher_Dir : int; +typedef int32_t CCCryptorStatus; + +class BOTAN_PUBLIC_API(2, 0) CommonCrypto_Error final : public Exception + { + public: + CommonCrypto_Error(const std::string& what) : + Exception(what + " failed."), + m_rc(0) {} + + CommonCrypto_Error(const std::string& what, int32_t status) : + Exception(what + std::string(" failed. Status: ") + ccryptorstatus_to_string(status)), + m_rc(status) {} + + ErrorType error_type() const noexcept override { return ErrorType::CommonCryptoError; } + + int error_code() const noexcept override { return m_rc; } + + private: + std::string ccryptorstatus_to_string(CCCryptorStatus status); + + int32_t m_rc; + }; + +/* Cipher Modes */ + +Cipher_Mode* +make_commoncrypto_cipher_mode(const std::string& name, Cipher_Dir direction); + +/* Block Ciphers */ + +std::unique_ptr +make_commoncrypto_block_cipher(const std::string& name); + +/* Hash */ + +std::unique_ptr make_commoncrypto_hash(const std::string& name); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_block.cpp b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_block.cpp new file mode 100644 index 0000000000..417e765bd6 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_block.cpp @@ -0,0 +1,164 @@ +/* +* Block Ciphers via CommonCrypto +* (C) 2018 Jose Luis Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#include + +namespace Botan { + +namespace { + +class CommonCrypto_BlockCipher final : public BlockCipher + { + public: + CommonCrypto_BlockCipher(const std::string& name, const CommonCryptor_Opts& opts); + + ~CommonCrypto_BlockCipher(); + + void clear() override; + std::string provider() const override { return "commoncrypto"; } + std::string name() const override { return m_cipher_name; } + BlockCipher* clone() const override; + + size_t block_size() const override { return m_opts.block_size; } + + Key_Length_Specification key_spec() const override { return m_opts.key_spec; } + + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override + { + verify_key_set(m_key_set); + size_t total_len = blocks * m_opts.block_size; + size_t out_len = 0; + + CCCryptorStatus status = CCCryptorUpdate(m_encrypt, in, total_len, + out, total_len, &out_len); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorUpdate encrypt", status); + } + } + + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override + { + verify_key_set(m_key_set); + size_t total_len = blocks * m_opts.block_size; + size_t out_len = 0; + + CCCryptorStatus status = CCCryptorUpdate(m_decrypt, in, total_len, + out, total_len, &out_len); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorUpdate decrypt", status); + } + } + + void key_schedule(const uint8_t key[], size_t key_len) override; + + std::string m_cipher_name; + CommonCryptor_Opts m_opts; + + CCCryptorRef m_encrypt = nullptr; + CCCryptorRef m_decrypt = nullptr; + bool m_key_set; + }; + +CommonCrypto_BlockCipher::CommonCrypto_BlockCipher(const std::string& algo_name, + const CommonCryptor_Opts& opts) : + m_cipher_name(algo_name), + m_opts(opts), + m_key_set(false) + { + } + +CommonCrypto_BlockCipher::~CommonCrypto_BlockCipher() + { + if(m_encrypt) + { + CCCryptorRelease(m_encrypt); + } + if(m_decrypt) + { + CCCryptorRelease(m_decrypt); + } + } + +/* +* Set the key +*/ +void CommonCrypto_BlockCipher::key_schedule(const uint8_t key[], size_t length) + { + secure_vector full_key(key, key + length); + + clear(); + commoncrypto_adjust_key_size(key, length, m_opts, full_key); + + CCCryptorStatus status; + status = CCCryptorCreate(kCCEncrypt, m_opts.algo, kCCOptionECBMode, + full_key.data(), full_key.size(), nullptr, &m_encrypt); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorCreate encrypt", status); + } + status = CCCryptorCreate(kCCDecrypt, m_opts.algo, kCCOptionECBMode, + full_key.data(), full_key.size(), nullptr, &m_decrypt); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorCreate decrypt", status); + } + + m_key_set = true; + } + +/* +* Return a clone of this object +*/ +BlockCipher* CommonCrypto_BlockCipher::clone() const + { + return new CommonCrypto_BlockCipher(m_cipher_name, m_opts); + } + +/* +* Clear memory of sensitive data +*/ +void CommonCrypto_BlockCipher::clear() + { + m_key_set = false; + + if(m_encrypt) + { + CCCryptorRelease(m_encrypt); + m_encrypt = nullptr; + } + + if(m_decrypt) + { + CCCryptorRelease(m_decrypt); + m_decrypt = nullptr; + } + } +} + +std::unique_ptr +make_commoncrypto_block_cipher(const std::string& name) + { + + try + { + CommonCryptor_Opts opts = commoncrypto_opts_from_algo_name(name); + return std::unique_ptr(new CommonCrypto_BlockCipher(name, opts)); + } + catch(CommonCrypto_Error& e) + { + return nullptr; + } + } +} + diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_hash.cpp b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_hash.cpp new file mode 100644 index 0000000000..f6203fb417 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_hash.cpp @@ -0,0 +1,146 @@ +/* +* CommonCrypto Hash Functions +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#include + +namespace Botan { + +namespace { + +template +class CommonCrypto_HashFunction final : public HashFunction + { + public: + + struct digest_config_t { + std::string name; + size_t digestLength; + size_t blockSize; + int (*init)(CTX *); + int (*update)(CTX *, const void *, CC_LONG len); + int (*final)(unsigned char *, CTX*); + }; + + void clear() override + { + if(m_info.init(&m_ctx) != 1) + throw CommonCrypto_Error("CC_" + m_info.name + "_Init"); + } + + std::string provider() const override { return "commoncrypto"; } + std::string name() const override { return m_info.name; } + + HashFunction* clone() const override + { + return new CommonCrypto_HashFunction(m_info); + } + + std::unique_ptr copy_state() const override + { + return std::unique_ptr( + new CommonCrypto_HashFunction(m_info, m_ctx)); + } + + size_t output_length() const override + { + return m_info.digestLength; + } + + size_t hash_block_size() const override + { + return m_info.blockSize; + } + + CommonCrypto_HashFunction(const digest_config_t& info) : + m_info(info) + { + clear(); + } + + CommonCrypto_HashFunction(const digest_config_t& info, const CTX &ctx) : + m_ctx(ctx), m_info(info) {} + + private: + void add_data(const uint8_t input[], size_t length) override + { + /* update len parameter is 32 bit unsigned integer, feed input in parts */ + while (length > 0) + { + CC_LONG update_len = (length > 0xFFFFFFFFUL) ? 0xFFFFFFFFUL : static_cast(length); + m_info.update(&m_ctx, input, update_len); + input += update_len; + length -= update_len; + } + } + + void final_result(uint8_t output[]) override + { + if(m_info.final(output, &m_ctx) != 1) + throw CommonCrypto_Error("CC_" + m_info.name + "_Final"); + clear(); + } + + CTX m_ctx; + digest_config_t m_info; + }; +} + +std::unique_ptr +make_commoncrypto_hash(const std::string& name) + { +#define MAKE_COMMONCRYPTO_HASH_3(name, hash, ctx) \ + std::unique_ptr( \ + new CommonCrypto_HashFunction({ \ + name, \ + CC_ ## hash ## _DIGEST_LENGTH, \ + CC_ ## hash ## _BLOCK_BYTES, \ + CC_ ## hash ## _Init, \ + CC_ ## hash ## _Update, \ + CC_ ## hash ## _Final \ + })); + +#define MAKE_COMMONCRYPTO_HASH_2(name, id) \ + MAKE_COMMONCRYPTO_HASH_3(name, id, id) + +#define MAKE_COMMONCRYPTO_HASH_1(id) \ + MAKE_COMMONCRYPTO_HASH_2(#id, id) + +#if defined(BOTAN_HAS_SHA2_32) + if(name == "SHA-224") + return MAKE_COMMONCRYPTO_HASH_3(name, SHA224, SHA256); + if(name == "SHA-256") + return MAKE_COMMONCRYPTO_HASH_2(name, SHA256); +#endif +#if defined(BOTAN_HAS_SHA2_64) + if(name == "SHA-384") + return MAKE_COMMONCRYPTO_HASH_3(name, SHA384, SHA512); + if(name == "SHA-512") + return MAKE_COMMONCRYPTO_HASH_2(name, SHA512); +#endif + +#if defined(BOTAN_HAS_SHA1) + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return MAKE_COMMONCRYPTO_HASH_2(name, SHA1); +#endif + +#if defined(BOTAN_HAS_MD5) + if(name == "MD5") + return MAKE_COMMONCRYPTO_HASH_1(MD5); +#endif + +#if defined(BOTAN_HAS_MD4) + if(name == "MD4") + return MAKE_COMMONCRYPTO_HASH_1(MD4); +#endif + return nullptr; + } + +} diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_mode.cpp b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_mode.cpp new file mode 100644 index 0000000000..82d4bd5526 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_mode.cpp @@ -0,0 +1,247 @@ +/* +* Cipher Modes via CommonCrypto +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#include + +namespace Botan { + +namespace { + +class CommonCrypto_Cipher_Mode final : public Cipher_Mode + { + public: + CommonCrypto_Cipher_Mode(const std::string& name, + Cipher_Dir direction, + const CommonCryptor_Opts& opts); + + ~CommonCrypto_Cipher_Mode(); + + std::string provider() const override { return "commoncrypto"; } + std::string name() const override { return m_mode_name; } + + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + size_t process(uint8_t msg[], size_t msg_len) override; + void finish(secure_vector& final_block, size_t offset0) override; + size_t output_length(size_t input_length) const override; + size_t update_granularity() const override; + size_t minimum_final_size() const override; + size_t default_nonce_length() const override; + bool valid_nonce_length(size_t nonce_len) const override; + void clear() override; + void reset() override; + Key_Length_Specification key_spec() const override; + + private: + void key_schedule(const uint8_t key[], size_t length) override; + + const std::string m_mode_name; + Cipher_Dir m_direction; + CommonCryptor_Opts m_opts; + CCCryptorRef m_cipher = nullptr; + bool m_key_set; + bool m_nonce_set; + }; + +CommonCrypto_Cipher_Mode::CommonCrypto_Cipher_Mode(const std::string& name, + Cipher_Dir direction, const CommonCryptor_Opts& opts) : + m_mode_name(name), + m_direction(direction), + m_opts(opts), + m_key_set(false), + m_nonce_set(false) + { + } + +CommonCrypto_Cipher_Mode::~CommonCrypto_Cipher_Mode() + { + if(m_cipher) + { + CCCryptorRelease(m_cipher); + } + } + +void CommonCrypto_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + verify_key_set(m_key_set); + + if(!valid_nonce_length(nonce_len)) + { throw Invalid_IV_Length(name(), nonce_len); } + if(nonce_len) + { + CCCryptorStatus status = CCCryptorReset(m_cipher, nonce); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorReset on start_msg", status); + } + } + m_nonce_set = true; + } + +size_t CommonCrypto_Cipher_Mode::process(uint8_t msg[], size_t msg_len) + { + verify_key_set(m_key_set); + BOTAN_STATE_CHECK(m_nonce_set); + + if(msg_len == 0) + { return 0; } + if(msg_len > INT_MAX) + { throw Internal_Error("msg_len overflow"); } + size_t outl = CCCryptorGetOutputLength(m_cipher, msg_len, false); + + secure_vector out(outl); + + if(m_opts.padding == ccNoPadding && msg_len % m_opts.block_size) + { + msg_len = outl; + } + + CCCryptorStatus status = CCCryptorUpdate(m_cipher, msg, msg_len, + out.data(), outl, &outl); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorUpdate", status); + } + copy_mem(msg, out.data(), outl); + + return outl; + } + +void CommonCrypto_Cipher_Mode::finish(secure_vector& buffer, + size_t offset) + { + verify_key_set(m_key_set); + BOTAN_STATE_CHECK(m_nonce_set); + + BOTAN_ASSERT(buffer.size() >= offset, "Offset ok"); + uint8_t* buf = buffer.data() + offset; + const size_t buf_size = buffer.size() - offset; + + size_t written = process(buf, buf_size); + + size_t outl = CCCryptorGetOutputLength(m_cipher, buf_size - written, true); + secure_vector out(outl); + + CCCryptorStatus status = CCCryptorFinal( + m_cipher, out.data(), outl, &outl); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorFinal", status); + } + + size_t new_len = offset + written + outl; + if(m_opts.padding != ccNoPadding || buffer.size() < new_len) + { + buffer.resize(new_len); + } + copy_mem(buffer.data() - offset + written, out.data(), outl); + written += outl; + } + +size_t CommonCrypto_Cipher_Mode::update_granularity() const + { + return m_opts.block_size * BOTAN_BLOCK_CIPHER_PAR_MULT; + } + +size_t CommonCrypto_Cipher_Mode::minimum_final_size() const + { + if(m_direction == ENCRYPTION) + return 0; + else + return m_opts.block_size; + } + +size_t CommonCrypto_Cipher_Mode::default_nonce_length() const + { + return m_opts.block_size; + } + +bool CommonCrypto_Cipher_Mode::valid_nonce_length(size_t nonce_len) const + { + return (nonce_len == 0 || nonce_len == m_opts.block_size); + } + +size_t CommonCrypto_Cipher_Mode::output_length(size_t input_length) const + { + if(input_length == 0) + { return m_opts.block_size; } + else + { return round_up(input_length, m_opts.block_size); } + } + +void CommonCrypto_Cipher_Mode::clear() + { + m_key_set = false; + + if(m_cipher == nullptr) + { + return; + } + + if(m_cipher) + { + CCCryptorRelease(m_cipher); + m_cipher = nullptr; + } + } + +void CommonCrypto_Cipher_Mode::reset() + { + if(m_cipher == nullptr) + { + return; + } + + m_nonce_set = false; + + CCCryptorStatus status = CCCryptorReset(m_cipher, nullptr); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorReset", status); + } + } + +Key_Length_Specification CommonCrypto_Cipher_Mode::key_spec() const + { + return m_opts.key_spec; + } + +void CommonCrypto_Cipher_Mode::key_schedule(const uint8_t key[], size_t length) + { + CCCryptorStatus status; + CCOperation op = m_direction == ENCRYPTION ? kCCEncrypt : kCCDecrypt; + status = CCCryptorCreateWithMode(op, m_opts.mode, m_opts.algo, m_opts.padding, + nullptr, key, length, nullptr, 0, 0, 0, &m_cipher); + if(status != kCCSuccess) + { + throw CommonCrypto_Error("CCCryptorCreate", status); + } + + m_key_set = true; + m_nonce_set = false; + } +} + +Cipher_Mode* +make_commoncrypto_cipher_mode(const std::string& name, Cipher_Dir direction) + { + + try + { + CommonCryptor_Opts opts = commoncrypto_opts_from_algo(name); + return new CommonCrypto_Cipher_Mode(name, direction, opts); + } + catch(CommonCrypto_Error& e) + { + return nullptr; + } + } +} diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.cpp b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.cpp new file mode 100644 index 0000000000..59e501dd7e --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.cpp @@ -0,0 +1,196 @@ +/* +* Cipher Modes via CommonCrypto +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +std::string CommonCrypto_Error::ccryptorstatus_to_string(CCCryptorStatus status) + { + switch(status) + { + case kCCSuccess: + return "Success"; + case kCCParamError: + return "ParamError"; + case kCCBufferTooSmall: + return "BufferTooSmall"; + case kCCMemoryFailure: + return "MemoryFailure"; + case kCCAlignmentError: + return "AlignmentError"; + case kCCDecodeError: + return "DecodeError"; + case kCCUnimplemented: + return "Unimplemented"; + case kCCOverflow: + return "Overflow"; + case kCCRNGFailure: + return "RNGFailure"; + case kCCUnspecifiedError: + return "UnspecifiedError"; + case kCCCallSequenceError: + return "CallSequenceError"; + case kCCKeySizeError: + return "KeySizeError"; + default: + return "Unknown"; + } + }; + + +CommonCryptor_Opts commoncrypto_opts_from_algo_name(const std::string& algo_name) + { + CommonCryptor_Opts opts; + + if(algo_name.compare(0, 3, "AES") == 0) + { + opts.algo = kCCAlgorithmAES; + opts.block_size = kCCBlockSizeAES128; + if(algo_name == "AES-128") + { + opts.key_spec = Key_Length_Specification(kCCKeySizeAES128); + } + else if(algo_name == "AES-192") + { + opts.key_spec = Key_Length_Specification(kCCKeySizeAES192); + } + else if(algo_name == "AES-256") + { + opts.key_spec = Key_Length_Specification(kCCKeySizeAES256); + } + else + { + throw CommonCrypto_Error("Unknown AES algorithm"); + } + } + else if(algo_name == "DES") + { + opts.algo = kCCAlgorithmDES; + opts.block_size = kCCBlockSizeDES; + opts.key_spec = Key_Length_Specification(kCCKeySizeDES); + } + else if(algo_name == "TripleDES") + { + opts.algo = kCCAlgorithm3DES; + opts.block_size = kCCBlockSize3DES; + opts.key_spec = Key_Length_Specification(16, kCCKeySize3DES, 8); + } + else if(algo_name == "Blowfish") + { + opts.algo = kCCAlgorithmBlowfish; + opts.block_size = kCCBlockSizeBlowfish; + opts.key_spec = Key_Length_Specification(1, kCCKeySizeMaxBlowfish, 1); + } + else if(algo_name == "CAST-128") + { + opts.algo = kCCAlgorithmCAST; + opts.block_size = kCCBlockSizeCAST; + // Botan's base implementation of CAST does not support shorter keys + // so we limit its minimum key size to 11 here. + opts.key_spec = Key_Length_Specification(11, kCCKeySizeMaxCAST, 1); + } + else + { + throw CommonCrypto_Error("Unsupported cipher"); + } + + return opts; + } + + +CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo) + { + SCAN_Name spec(algo); + + std::string algo_name = spec.algo_name(); + std::string cipher_mode = spec.cipher_mode(); + std::string cipher_mode_padding = spec.cipher_mode_pad(); + + CommonCryptor_Opts opts = commoncrypto_opts_from_algo_name(algo_name); + + //TODO add CFB and XTS support + if(cipher_mode.empty() || cipher_mode == "ECB") + { + opts.mode = kCCModeECB; + } + else if(cipher_mode == "CBC") + { + opts.mode = kCCModeCBC; + } + else if(cipher_mode == "CTR") + { + opts.mode = kCCModeCTR; + } + else if(cipher_mode == "OFB") + { + opts.mode = kCCModeOFB; + } + else + { + throw CommonCrypto_Error("Unsupported cipher mode!"); + } + + if(cipher_mode_padding == "NoPadding") + { + opts.padding = ccNoPadding; + } + /* + else if(cipher_mode_padding.empty() || cipher_mode_padding == "PKCS7") + { + opts.padding = ccPKCS7Padding; + } + */ + else + { + throw CommonCrypto_Error("Unsupported cipher mode padding!"); + } + + return opts; + } + + +void commoncrypto_adjust_key_size(const uint8_t key[], size_t length, + const CommonCryptor_Opts& opts, secure_vector& full_key) + { + + if(opts.algo == kCCAlgorithmBlowfish && length < 8) + { + size_t repeat; + switch(length) + { + case 1: + repeat = 8; + break; + case 2: + repeat = 4; + break; + case 3: + repeat = 3; + break; + default: + repeat = 2; + break; + } + + full_key.resize(length * repeat); + for(size_t i = 0; i < repeat; i++) + { + copy_mem(full_key.data() + i * length, key, length); + } + } + else if(opts.algo == kCCAlgorithm3DES && length == 16) + { + full_key += std::make_pair(key, 8); + } + } +} diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.h b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.h new file mode 100644 index 0000000000..c20f0d81d7 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/commoncrypto_utils.h @@ -0,0 +1,35 @@ +/* +* Utils for calling CommonCrypto +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_INTERNAL_COMMONCRYPTO_UTILS_H_ +#define BOTAN_INTERNAL_COMMONCRYPTO_UTILS_H_ + +#include + +#include + +namespace Botan { + +struct CommonCryptor_Opts + { + CCAlgorithm algo; + CCMode mode; + CCPadding padding; + size_t block_size; + Key_Length_Specification key_spec{0}; + }; + +CommonCryptor_Opts commoncrypto_opts_from_algo_name(const std::string& algo_name); +CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo); + +void commoncrypto_adjust_key_size(const uint8_t key[], size_t length, + const CommonCryptor_Opts& opts, secure_vector& full_key); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/commoncrypto/info.txt b/comm/third_party/botan/src/lib/prov/commoncrypto/info.txt new file mode 100644 index 0000000000..b95d4547ec --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/commoncrypto/info.txt @@ -0,0 +1,19 @@ + +COMMONCRYPTO -> 20180903 + + +load_on vendor + + +commoncrypto.h +commoncrypto_utils.h + + + +commoncrypto + + + +modes +block + diff --git a/comm/third_party/botan/src/lib/prov/openssl/info.txt b/comm/third_party/botan/src/lib/prov/openssl/info.txt new file mode 100644 index 0000000000..32e71a8481 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/info.txt @@ -0,0 +1,21 @@ + +OPENSSL -> 20151219 + + +load_on vendor + + +openssl.h + + + +all!windows -> crypto +windows -> libeay32 + + + +block +stream +modes +pubkey + diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl.h b/comm/third_party/botan/src/lib/prov/openssl/openssl.h new file mode 100644 index 0000000000..a68dda5af0 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl.h @@ -0,0 +1,118 @@ +/* +* Utils for calling OpenSSL +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_INTERNAL_OPENSSL_H_ +#define BOTAN_INTERNAL_OPENSSL_H_ + +#include +#include +#include +#include +#include + +#include +#include + +#if defined(BOTAN_HAS_RC4) +#include +#endif + +namespace Botan { + +class BlockCipher; +class Cipher_Mode; +class StreamCipher; +class HashFunction; +class RandomNumberGenerator; +enum Cipher_Dir : int; + +class BOTAN_PUBLIC_API(2,0) OpenSSL_Error final : public Exception + { + public: + OpenSSL_Error(const std::string& what, int err) : + Exception(what + " failed: " + ERR_error_string(err, nullptr)), + m_err(err) {} + + ErrorType error_type() const noexcept override { return ErrorType::OpenSSLError; } + + int error_code() const noexcept override { return m_err; } + + private: + int m_err; + }; + +/* Block Ciphers */ + +std::unique_ptr +make_openssl_block_cipher(const std::string& name); + +/* Cipher Modes */ + +Cipher_Mode* +make_openssl_cipher_mode(const std::string& name, Cipher_Dir direction); + +/* Hash */ + +std::unique_ptr +make_openssl_hash(const std::string& name); + +/* RSA */ + +#if defined(BOTAN_HAS_RSA) + +class RSA_PublicKey; +class RSA_PrivateKey; + +std::unique_ptr +make_openssl_rsa_enc_op(const RSA_PublicKey& key, const std::string& params); +std::unique_ptr +make_openssl_rsa_dec_op(const RSA_PrivateKey& key, const std::string& params); + +std::unique_ptr +make_openssl_rsa_ver_op(const RSA_PublicKey& key, const std::string& params); +std::unique_ptr +make_openssl_rsa_sig_op(const RSA_PrivateKey& key, const std::string& params); +std::unique_ptr +make_openssl_rsa_private_key(RandomNumberGenerator& rng, size_t rsa_bits); + +#endif + +/* ECDSA */ + +#if defined(BOTAN_HAS_ECDSA) + +class ECDSA_PublicKey; +class ECDSA_PrivateKey; + +std::unique_ptr +make_openssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params); +std::unique_ptr +make_openssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params); + +#endif + +/* ECDH */ + +#if defined(BOTAN_HAS_ECDH) + +class ECDH_PrivateKey; + +std::unique_ptr +make_openssl_ecdh_ka_op(const ECDH_PrivateKey& key, const std::string& params); + +#endif + +#if defined(BOTAN_HAS_RC4) + +std::unique_ptr +make_openssl_rc4(size_t skip); + +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp new file mode 100644 index 0000000000..7f9bdcf6c5 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp @@ -0,0 +1,234 @@ +/* +* Block Ciphers via OpenSSL +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +class OpenSSL_BlockCipher final : public BlockCipher + { + public: + OpenSSL_BlockCipher(const std::string& name, + const EVP_CIPHER* cipher); + + OpenSSL_BlockCipher(const std::string& name, + const EVP_CIPHER* cipher, + size_t kl_min, size_t kl_max, size_t kl_mod); + + ~OpenSSL_BlockCipher(); + + void clear() override; + std::string provider() const override { return "openssl"; } + std::string name() const override { return m_cipher_name; } + BlockCipher* clone() const override; + + size_t block_size() const override { return m_block_sz; } + + Key_Length_Specification key_spec() const override { return m_cipher_key_spec; } + + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override + { + verify_key_set(m_key_set); + int out_len = 0; + if(!EVP_EncryptUpdate(m_encrypt, out, &out_len, in, blocks * m_block_sz)) + throw OpenSSL_Error("EVP_EncryptUpdate", ERR_get_error()); + } + + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override + { + verify_key_set(m_key_set); + int out_len = 0; + if(!EVP_DecryptUpdate(m_decrypt, out, &out_len, in, blocks * m_block_sz)) + throw OpenSSL_Error("EVP_DecryptUpdate", ERR_get_error()); + } + + void key_schedule(const uint8_t key[], size_t key_len) override; + + size_t m_block_sz; + Key_Length_Specification m_cipher_key_spec; + std::string m_cipher_name; + EVP_CIPHER_CTX *m_encrypt; + EVP_CIPHER_CTX *m_decrypt; + bool m_key_set; + }; + +OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, + const EVP_CIPHER* algo) : + m_block_sz(EVP_CIPHER_block_size(algo)), + m_cipher_key_spec(EVP_CIPHER_key_length(algo)), + m_cipher_name(algo_name), + m_key_set(false) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in"); + + m_encrypt = EVP_CIPHER_CTX_new(); + m_decrypt = EVP_CIPHER_CTX_new(); + if (m_encrypt == nullptr || m_decrypt == nullptr) + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); + + EVP_CIPHER_CTX_init(m_encrypt); + EVP_CIPHER_CTX_init(m_decrypt); + + if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr)) + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); + if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr)) + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); + + if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error()); + if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error()); + } + +OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, + const EVP_CIPHER* algo, + size_t key_min, + size_t key_max, + size_t key_mod) : + m_block_sz(EVP_CIPHER_block_size(algo)), + m_cipher_key_spec(key_min, key_max, key_mod), + m_cipher_name(algo_name), + m_key_set(false) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in"); + + m_encrypt = EVP_CIPHER_CTX_new(); + m_decrypt = EVP_CIPHER_CTX_new(); + if (m_encrypt == nullptr || m_decrypt == nullptr) + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); + + EVP_CIPHER_CTX_init(m_encrypt); + EVP_CIPHER_CTX_init(m_decrypt); + + if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr)) + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); + if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr)) + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); + + if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error()); + if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error()); + } + +OpenSSL_BlockCipher::~OpenSSL_BlockCipher() + { + EVP_CIPHER_CTX_cleanup(m_encrypt); + EVP_CIPHER_CTX_cleanup(m_decrypt); + + EVP_CIPHER_CTX_free(m_encrypt); + EVP_CIPHER_CTX_free(m_decrypt); + } + +/* +* Set the key +*/ +void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length) + { + secure_vector full_key(key, key + length); + + if(m_cipher_name == "TripleDES" && length == 16) + { + full_key += std::make_pair(key, 8); + } + else + { + if(EVP_CIPHER_CTX_set_key_length(m_encrypt, length) == 0 || + EVP_CIPHER_CTX_set_key_length(m_decrypt, length) == 0) + throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " + + m_cipher_name); + } + + if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr)) + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); + if(!EVP_DecryptInit_ex(m_decrypt, nullptr, nullptr, full_key.data(), nullptr)) + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); + + m_key_set = true; + } + +/* +* Return a clone of this object +*/ +BlockCipher* OpenSSL_BlockCipher::clone() const + { + return new OpenSSL_BlockCipher(m_cipher_name, + EVP_CIPHER_CTX_cipher(m_encrypt), + m_cipher_key_spec.minimum_keylength(), + m_cipher_key_spec.maximum_keylength(), + m_cipher_key_spec.keylength_multiple()); + } + +/* +* Clear memory of sensitive data +*/ +void OpenSSL_BlockCipher::clear() + { + const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_encrypt); + + m_key_set = false; + + if(!EVP_CIPHER_CTX_cleanup(m_encrypt)) + throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt", ERR_get_error()); + if(!EVP_CIPHER_CTX_cleanup(m_decrypt)) + throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup decrypt", ERR_get_error()); + EVP_CIPHER_CTX_init(m_encrypt); + EVP_CIPHER_CTX_init(m_decrypt); + if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr)) + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); + if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr)) + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); + if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error()); + if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error()); + } + +} + +std::unique_ptr +make_openssl_block_cipher(const std::string& name) + { +#define MAKE_OPENSSL_BLOCK(evp_fn) \ + std::unique_ptr(new OpenSSL_BlockCipher(name, evp_fn())) +#define MAKE_OPENSSL_BLOCK_KEYLEN(evp_fn, kl_min, kl_max, kl_mod) \ + std::unique_ptr(new OpenSSL_BlockCipher(name, evp_fn(), kl_min, kl_max, kl_mod)) + +#if defined(BOTAN_HAS_AES) && !defined(OPENSSL_NO_AES) + if(name == "AES-128") + return MAKE_OPENSSL_BLOCK(EVP_aes_128_ecb); + if(name == "AES-192") + return MAKE_OPENSSL_BLOCK(EVP_aes_192_ecb); + if(name == "AES-256") + return MAKE_OPENSSL_BLOCK(EVP_aes_256_ecb); +#endif + +#if defined(BOTAN_HAS_CAMELLIA) && !defined(OPENSSL_NO_CAMELLIA) + if(name == "Camellia-128") + return MAKE_OPENSSL_BLOCK(EVP_camellia_128_ecb); + if(name == "Camellia-192") + return MAKE_OPENSSL_BLOCK(EVP_camellia_192_ecb); + if(name == "Camellia-256") + return MAKE_OPENSSL_BLOCK(EVP_camellia_256_ecb); +#endif + +#if defined(BOTAN_HAS_DES) && !defined(OPENSSL_NO_DES) + if(name == "TripleDES") + return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8); +#endif + + return nullptr; + } + +} + diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp new file mode 100644 index 0000000000..3f691f68ac --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp @@ -0,0 +1,383 @@ +/* +* ECDSA and ECDH via OpenSSL +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + #include + #include + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include +#endif + +#if defined(BOTAN_HAS_ECDH) + #include +#endif + +#include +#include + +#if !defined(OPENSSL_NO_EC) + #include +#endif + +#if !defined(OPENSSL_NO_ECDSA) + #include +#endif + +#if !defined(OPENSSL_NO_ECDH) + #include +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + +namespace { + +secure_vector PKCS8_for_openssl(const EC_PrivateKey& ec) + { + const PointGFp& pub_key = ec.public_point(); + const BigInt& priv_key = ec.private_value(); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(1)) + .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), OCTET_STRING) + .start_cons(ASN1_Tag(0), PRIVATE) + .raw_bytes(ec.domain().DER_encode(EC_DOMPAR_ENC_OID)) + .end_cons() + .start_cons(ASN1_Tag(1), PRIVATE) + .encode(pub_key.encode(PointGFp::UNCOMPRESSED), BIT_STRING) + .end_cons() + .end_cons() + .get_contents(); + } + +int OpenSSL_EC_curve_builtin(int nid) + { + // the NID macro is still defined even though the curve may not be + // supported, so we need to check the list of builtin curves at runtime + EC_builtin_curve builtin_curves[100]; + size_t num = 0; + + if (!(num = EC_get_builtin_curves(builtin_curves, sizeof(builtin_curves)))) + { + return -1; + } + + for(size_t i = 0; i < num; ++i) + { + if(builtin_curves[i].nid == nid) + { + return nid; + } + } + + return -1; + } + +int OpenSSL_EC_nid_for(const OID& oid) + { + if(oid.empty()) + return -1; + + const std::string name = oid.to_formatted_string(); + + if(name == "secp192r1") + return OpenSSL_EC_curve_builtin(NID_X9_62_prime192v1); + if(name == "secp224r1") + return OpenSSL_EC_curve_builtin(NID_secp224r1); + if(name == "secp256r1") + return OpenSSL_EC_curve_builtin(NID_X9_62_prime256v1); + if(name == "secp384r1") + return OpenSSL_EC_curve_builtin(NID_secp384r1); + if(name == "secp521r1") + return OpenSSL_EC_curve_builtin(NID_secp521r1); + + // OpenSSL 1.0.2 added brainpool curves +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + if(name == "brainpool160r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP160r1); + if(name == "brainpool192r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP192r1); + if(name == "brainpool224r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP224r1); + if(name == "brainpool256r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP256r1); + if(name == "brainpool320r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP320r1); + if(name == "brainpool384r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP384r1); + if(name == "brainpool512r1") + return OpenSSL_EC_curve_builtin(NID_brainpoolP512r1); +#endif + + return -1; + } + +} + +#endif + +#if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA) + +namespace { + +class OpenSSL_ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + OpenSSL_ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa, int nid) : + PK_Ops::Verification_with_EMSA(emsa), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free) + { + std::unique_ptr<::EC_GROUP, std::function> grp(::EC_GROUP_new_by_curve_name(nid), + ::EC_GROUP_free); + + if(!grp) + throw OpenSSL_Error("EC_GROUP_new_by_curve_name", ERR_get_error()); + + if(!::EC_KEY_set_group(m_ossl_ec.get(), grp.get())) + throw OpenSSL_Error("EC_KEY_set_group", ERR_get_error()); + + const std::vector enc = ecdsa.public_point().encode(PointGFp::UNCOMPRESSED); + const uint8_t* enc_ptr = enc.data(); + EC_KEY* key_ptr = m_ossl_ec.get(); + if(!::o2i_ECPublicKey(&key_ptr, &enc_ptr, enc.size())) + throw OpenSSL_Error("o2i_ECPublicKey", ERR_get_error()); + + const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get()); + m_order_bits = ::EC_GROUP_get_degree(group); + } + + size_t max_input_bits() const override { return m_order_bits; } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig_bytes[], size_t sig_len) override + { + const size_t order_bytes = (m_order_bits + 7) / 8; + if(sig_len != 2 * order_bytes) + return false; + + std::unique_ptr> sig(nullptr, ECDSA_SIG_free); + sig.reset(::ECDSA_SIG_new()); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + sig->r = BN_bin2bn(sig_bytes , sig_len / 2, sig->r); + sig->s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, sig->s); +#else + BIGNUM* r = BN_bin2bn(sig_bytes , sig_len / 2, nullptr); + BIGNUM* s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, nullptr); + if(r == nullptr || s == nullptr) + throw OpenSSL_Error("BN_bin2bn sig s", ERR_get_error()); + + ECDSA_SIG_set0(sig.get(), r, s); +#endif + + const int res = ECDSA_do_verify(msg, msg_len, sig.get(), m_ossl_ec.get()); + if(res < 0) + { + int err = ERR_get_error(); + + bool hard_error = true; + +#if defined(EC_R_BAD_SIGNATURE) + if(ERR_GET_REASON(err) == EC_R_BAD_SIGNATURE) + hard_error = false; +#endif +#if defined(EC_R_POINT_AT_INFINITY) + if(ERR_GET_REASON(err) == EC_R_POINT_AT_INFINITY) + hard_error = false; +#endif +#if defined(ECDSA_R_BAD_SIGNATURE) + if(ERR_GET_REASON(err) == ECDSA_R_BAD_SIGNATURE) + hard_error = false; +#endif + + if(hard_error) + throw OpenSSL_Error("ECDSA_do_verify", err); + } + return (res == 1); + } + + private: + std::unique_ptr> m_ossl_ec; + size_t m_order_bits = 0; + }; + +class OpenSSL_ECDSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + OpenSSL_ECDSA_Signing_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), + m_ossl_ec(nullptr, ::EC_KEY_free) + { + const secure_vector der = PKCS8_for_openssl(ecdsa); + const uint8_t* der_ptr = der.data(); + m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size())); + if(!m_ossl_ec) + throw OpenSSL_Error("d2i_ECPrivateKey", ERR_get_error()); + + const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get()); + m_order_bits = ::EC_GROUP_get_degree(group); + m_order_bytes = (m_order_bits + 7) / 8; + } + + size_t signature_length() const override { return 2*m_order_bytes; } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator&) override + { + std::unique_ptr> sig(nullptr, ECDSA_SIG_free); + sig.reset(::ECDSA_do_sign(msg, msg_len, m_ossl_ec.get())); + + if(!sig) + throw OpenSSL_Error("ECDSA_do_sign", ERR_get_error()); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + const BIGNUM* r = sig->r; + const BIGNUM* s = sig->s; +#else + const BIGNUM* r; + const BIGNUM* s; + ECDSA_SIG_get0(sig.get(), &r, &s); +#endif + + const size_t r_bytes = BN_num_bytes(r); + const size_t s_bytes = BN_num_bytes(s); + secure_vector sigval(2*m_order_bytes); + BN_bn2bin(r, &sigval[m_order_bytes - r_bytes]); + BN_bn2bin(s, &sigval[2*m_order_bytes - s_bytes]); + return sigval; + } + + size_t max_input_bits() const override { return m_order_bits; } + + private: + std::unique_ptr> m_ossl_ec; + size_t m_order_bits; + size_t m_order_bytes; + }; + +} + +std::unique_ptr +make_openssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params) + { + const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid()); + if(nid < 0) + { + throw Lookup_Error("OpenSSL ECDSA does not support this curve"); + } + + try + { + return std::unique_ptr(new OpenSSL_ECDSA_Verification_Operation(key, params, nid)); + } + catch(OpenSSL_Error&) + { + throw Lookup_Error("OpenSSL ECDSA does not support this key"); + } + } + +std::unique_ptr +make_openssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params) + { + const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid()); + if(nid < 0) + { + throw Lookup_Error("OpenSSL ECDSA does not support this curve"); + } + return std::unique_ptr(new OpenSSL_ECDSA_Signing_Operation(key, params)); + } + +#endif + +#if defined(BOTAN_HAS_ECDH) && !defined(OPENSSL_NO_ECDH) + +namespace { + +class OpenSSL_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + + OpenSSL_ECDH_KA_Operation(const ECDH_PrivateKey& ecdh, const std::string& kdf) : + PK_Ops::Key_Agreement_with_KDF(kdf), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free) + { + m_value_size = ecdh.domain().get_p_bytes(); + const secure_vector der = PKCS8_for_openssl(ecdh); + const uint8_t* der_ptr = der.data(); + m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size())); + if(!m_ossl_ec) + throw OpenSSL_Error("d2i_ECPrivateKey", ERR_get_error()); + } + + size_t agreed_value_size() const override { return m_value_size; } + + secure_vector raw_agree(const uint8_t w[], size_t w_len) override + { + const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get()); + const size_t out_len = (::EC_GROUP_get_degree(group) + 7) / 8; + secure_vector out(out_len); + + std::unique_ptr> pub_key( + ::EC_POINT_new(group), ::EC_POINT_free); + + if(!pub_key) + throw OpenSSL_Error("EC_POINT_new", ERR_get_error()); + + const int os2ecp_rc = + ::EC_POINT_oct2point(group, pub_key.get(), w, w_len, nullptr); + + if(os2ecp_rc != 1) + throw OpenSSL_Error("EC_POINT_oct2point", ERR_get_error()); + + const int ecdh_rc = ::ECDH_compute_key(out.data(), + out.size(), + pub_key.get(), + m_ossl_ec.get(), + /*KDF*/nullptr); + + if(ecdh_rc <= 0) + throw OpenSSL_Error("ECDH_compute_key", ERR_get_error()); + + const size_t ecdh_sz = static_cast(ecdh_rc); + + if(ecdh_sz > out.size()) + throw Internal_Error("OpenSSL ECDH returned more than requested"); + + out.resize(ecdh_sz); + return out; + } + + private: + std::unique_ptr> m_ossl_ec; + size_t m_value_size; + }; + +} + +std::unique_ptr +make_openssl_ecdh_ka_op(const ECDH_PrivateKey& key, const std::string& params) + { + const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid()); + if(nid < 0) + { + throw Lookup_Error("OpenSSL ECDH does not support this curve"); + } + + return std::unique_ptr(new OpenSSL_ECDH_KA_Operation(key, params)); + } + +#endif + +} + diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp new file mode 100644 index 0000000000..9a56228c7b --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp @@ -0,0 +1,136 @@ +/* +* OpenSSL Hash Functions +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class OpenSSL_HashFunction final : public HashFunction + { + public: + void clear() override + { + const EVP_MD* algo = EVP_MD_CTX_md(m_md); + if(!EVP_DigestInit_ex(m_md, algo, nullptr)) + throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error()); + } + + std::string provider() const override { return "openssl"; } + std::string name() const override { return m_name; } + + HashFunction* clone() const override + { + const EVP_MD* algo = EVP_MD_CTX_md(m_md); + return new OpenSSL_HashFunction(name(), algo); + } + + std::unique_ptr copy_state() const override + { + std::unique_ptr copy(new OpenSSL_HashFunction(m_name, nullptr)); + EVP_MD_CTX_copy(copy->m_md, m_md); + return std::unique_ptr(copy.release()); + } + + size_t output_length() const override + { + return EVP_MD_size(EVP_MD_CTX_md(m_md)); + } + + size_t hash_block_size() const override + { + return EVP_MD_block_size(EVP_MD_CTX_md(m_md)); + } + + OpenSSL_HashFunction(const std::string& name, const EVP_MD* md) : m_name(name) + { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + m_md = EVP_MD_CTX_create(); +#else + m_md = EVP_MD_CTX_new(); +#endif + + if(m_md == nullptr) + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); + EVP_MD_CTX_init(m_md); + if(md && !EVP_DigestInit_ex(m_md, md, nullptr)) + throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error()); + } + + OpenSSL_HashFunction(EVP_MD_CTX* ctx) : m_md(ctx) + { + } + + ~OpenSSL_HashFunction() + { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_destroy(m_md); +#else + EVP_MD_CTX_free(m_md); +#endif + } + + private: + void add_data(const uint8_t input[], size_t length) override + { + if(!EVP_DigestUpdate(m_md, input, length)) + throw OpenSSL_Error("EVP_DigestUpdate", ERR_get_error()); + } + + void final_result(uint8_t output[]) override + { + if(!EVP_DigestFinal_ex(m_md, output, nullptr)) + throw OpenSSL_Error("EVP_DigestFinal_ex", ERR_get_error()); + const EVP_MD* algo = EVP_MD_CTX_md(m_md); + if(!EVP_DigestInit_ex(m_md, algo, nullptr)) + throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error()); + } + + std::string m_name; + EVP_MD_CTX* m_md; + }; + +} + +std::unique_ptr +make_openssl_hash(const std::string& name) + { +#define MAKE_OPENSSL_HASH(fn) \ + std::unique_ptr(new OpenSSL_HashFunction(name, fn ())) + +#if defined(BOTAN_HAS_SHA2_32) && !defined(OPENSSL_NO_SHA256) + if(name == "SHA-224") + return MAKE_OPENSSL_HASH(EVP_sha224); + if(name == "SHA-256") + return MAKE_OPENSSL_HASH(EVP_sha256); +#endif + +#if defined(BOTAN_HAS_SHA2_64) && !defined(OPENSSL_NO_SHA512) + if(name == "SHA-384") + return MAKE_OPENSSL_HASH(EVP_sha384); + if(name == "SHA-512") + return MAKE_OPENSSL_HASH(EVP_sha512); +#endif + +#if defined(BOTAN_HAS_SHA1) && !defined(OPENSSL_NO_SHA) + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return MAKE_OPENSSL_HASH(EVP_sha1); +#endif + +#if defined(BOTAN_HAS_MD5) && !defined(OPENSSL_NO_MD5) + if(name == "MD5") + return MAKE_OPENSSL_HASH(EVP_md5); + #endif + + return nullptr; + } + +} diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp new file mode 100644 index 0000000000..81f8413a2a --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp @@ -0,0 +1,233 @@ +/* +* Cipher Modes via OpenSSL +* (C) 1999-2010,2015 Jack Lloyd +* (C) 2017 Alexander Bluhm (genua GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class OpenSSL_Cipher_Mode final : public Cipher_Mode + { + public: + OpenSSL_Cipher_Mode(const std::string& name, + const EVP_CIPHER* cipher, + Cipher_Dir direction); + ~OpenSSL_Cipher_Mode(); + + std::string provider() const override { return "openssl"; } + std::string name() const override { return m_mode_name; } + + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + size_t process(uint8_t msg[], size_t msg_len) override; + void finish(secure_vector& final_block, size_t offset0) override; + size_t output_length(size_t input_length) const override; + size_t update_granularity() const override; + size_t minimum_final_size() const override; + size_t default_nonce_length() const override; + bool valid_nonce_length(size_t nonce_len) const override; + void clear() override; + void reset() override; + Key_Length_Specification key_spec() const override; + + private: + void key_schedule(const uint8_t key[], size_t length) override; + + const std::string m_mode_name; + const Cipher_Dir m_direction; + size_t m_block_size; + EVP_CIPHER_CTX* m_cipher; + bool m_key_set; + bool m_nonce_set; + }; + +OpenSSL_Cipher_Mode::OpenSSL_Cipher_Mode(const std::string& name, + const EVP_CIPHER* algo, + Cipher_Dir direction) : + m_mode_name(name), + m_direction(direction), + m_key_set(false), + m_nonce_set(false) + { + m_block_size = EVP_CIPHER_block_size(algo); + + if(EVP_CIPHER_mode(algo) != EVP_CIPH_CBC_MODE) + throw Invalid_Argument("OpenSSL_BlockCipher: Non-CBC EVP was passed in"); + + m_cipher = EVP_CIPHER_CTX_new(); + if (m_cipher == nullptr) + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); + + EVP_CIPHER_CTX_init(m_cipher); + if(!EVP_CipherInit_ex(m_cipher, algo, nullptr, nullptr, nullptr, + m_direction == ENCRYPTION ? 1 : 0)) + throw OpenSSL_Error("EVP_CipherInit_ex", ERR_get_error()); + if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding", ERR_get_error()); + } + +OpenSSL_Cipher_Mode::~OpenSSL_Cipher_Mode() + { + EVP_CIPHER_CTX_free(m_cipher); + } + +void OpenSSL_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + verify_key_set(m_key_set); + + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + if(nonce_len) + { + if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nonce, -1)) + throw OpenSSL_Error("EVP_CipherInit_ex nonce", ERR_get_error()); + } + else if(m_nonce_set == false) + { + const std::vector zeros(m_block_size); + if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, zeros.data(), -1)) + throw OpenSSL_Error("EVP_CipherInit_ex nonce", ERR_get_error()); + } + // otherwise existing CBC state left unchanged + + m_nonce_set = true; + } + +size_t OpenSSL_Cipher_Mode::process(uint8_t msg[], size_t msg_len) + { + verify_key_set(m_key_set); + BOTAN_STATE_CHECK(m_nonce_set); + + if(msg_len == 0) + return 0; + if(msg_len > INT_MAX) + throw Internal_Error("msg_len overflow"); + int outl = msg_len; + secure_vector out(outl); + + if(!EVP_CipherUpdate(m_cipher, out.data(), &outl, msg, msg_len)) + throw OpenSSL_Error("EVP_CipherUpdate", ERR_get_error()); + copy_mem(msg, out.data(), outl); + return outl; + } + +void OpenSSL_Cipher_Mode::finish(secure_vector& buffer, + size_t offset) + { + verify_key_set(m_key_set); + BOTAN_STATE_CHECK(m_nonce_set); + + BOTAN_ASSERT(buffer.size() >= offset, "Offset ok"); + uint8_t* buf = buffer.data() + offset; + const size_t buf_size = buffer.size() - offset; + + size_t written = process(buf, buf_size); + int outl = buf_size - written; + secure_vector out(outl); + + if(!EVP_CipherFinal_ex(m_cipher, out.data(), &outl)) + throw OpenSSL_Error("EVP_CipherFinal_ex", ERR_get_error()); + copy_mem(buf + written, out.data(), outl); + written += outl; + buffer.resize(offset + written); + } + +size_t OpenSSL_Cipher_Mode::update_granularity() const + { + return m_block_size * BOTAN_BLOCK_CIPHER_PAR_MULT; + } + +size_t OpenSSL_Cipher_Mode::minimum_final_size() const + { + return 0; // no padding + } + +size_t OpenSSL_Cipher_Mode::default_nonce_length() const + { + return m_block_size; + } + +bool OpenSSL_Cipher_Mode::valid_nonce_length(size_t nonce_len) const + { + return (nonce_len == 0 || nonce_len == m_block_size); + } + +size_t OpenSSL_Cipher_Mode::output_length(size_t input_length) const + { + if(input_length == 0) + return m_block_size; + else + return round_up(input_length, m_block_size); + } + +void OpenSSL_Cipher_Mode::clear() + { + m_key_set = false; + m_nonce_set = false; + + const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_cipher); + + if(!EVP_CIPHER_CTX_cleanup(m_cipher)) + throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup", ERR_get_error()); + EVP_CIPHER_CTX_init(m_cipher); + if(!EVP_CipherInit_ex(m_cipher, algo, nullptr, nullptr, nullptr, + m_direction == ENCRYPTION ? 1 : 0)) + throw OpenSSL_Error("EVP_CipherInit_ex clear", ERR_get_error()); + if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding clear", ERR_get_error()); + } + +void OpenSSL_Cipher_Mode::reset() + { + if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nullptr, -1)) + throw OpenSSL_Error("EVP_CipherInit_ex clear", ERR_get_error()); + m_nonce_set = false; + } + +Key_Length_Specification OpenSSL_Cipher_Mode::key_spec() const + { + return Key_Length_Specification(EVP_CIPHER_CTX_key_length(m_cipher)); + } + +void OpenSSL_Cipher_Mode::key_schedule(const uint8_t key[], size_t length) + { + if(!EVP_CIPHER_CTX_set_key_length(m_cipher, length)) + throw OpenSSL_Error("EVP_CIPHER_CTX_set_key_length", ERR_get_error()); + if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, key, nullptr, -1)) + throw OpenSSL_Error("EVP_CipherInit_ex key", ERR_get_error()); + m_key_set = true; + m_nonce_set = false; + } + +} + +Cipher_Mode* +make_openssl_cipher_mode(const std::string& name, Cipher_Dir direction) + { +#define MAKE_OPENSSL_MODE(evp_fn) \ + new OpenSSL_Cipher_Mode(name, (evp_fn)(), direction) + +#if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_MODE_CBC) && !defined(OPENSSL_NO_AES) + if(name == "AES-128/CBC/NoPadding") + return MAKE_OPENSSL_MODE(EVP_aes_128_cbc); + if(name == "AES-192/CBC/NoPadding") + return MAKE_OPENSSL_MODE(EVP_aes_192_cbc); + if(name == "AES-256/CBC/NoPadding") + return MAKE_OPENSSL_MODE(EVP_aes_256_cbc); +#endif + +#undef MAKE_OPENSSL_MODE + return nullptr; + } + +} diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp new file mode 100644 index 0000000000..dbda890f82 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp @@ -0,0 +1,93 @@ +/* +* OpenSSL RC4 +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_OPENSSL) && defined(BOTAN_HAS_RC4) + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class OpenSSL_RC4 final : public StreamCipher + { + public: + void clear() override { clear_mem(&m_rc4, 1); m_key_set = false; } + + std::string provider() const override { return "openssl"; } + + std::string name() const override + { + switch(m_skip) + { + case 0: + return "RC4"; + case 256: + return "MARK-4"; + default: + return "RC4(" + std::to_string(m_skip) + ")"; + } + } + + StreamCipher* clone() const override { return new OpenSSL_RC4(m_skip); } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(1, 32); + } + + explicit OpenSSL_RC4(size_t skip = 0) : m_skip(skip) { clear(); } + ~OpenSSL_RC4() { clear(); } + + void set_iv(const uint8_t*, size_t len) override + { + if(len > 0) + throw Invalid_IV_Length("RC4", len); + } + + void seek(uint64_t) override + { + throw Not_Implemented("RC4 does not support seeking"); + } + private: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override + { + verify_key_set(m_key_set); + ::RC4(&m_rc4, length, in, out); + } + + void key_schedule(const uint8_t key[], size_t length) override + { + ::RC4_set_key(&m_rc4, length, key); + uint8_t d = 0; + for(size_t i = 0; i != m_skip; ++i) + ::RC4(&m_rc4, 1, &d, &d); + m_key_set = true; + } + + size_t m_skip; + RC4_KEY m_rc4; + bool m_key_set; + }; + +} + +std::unique_ptr +make_openssl_rc4(size_t skip) + { + return std::unique_ptr(new OpenSSL_RC4(skip)); + } + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp new file mode 100644 index 0000000000..6744b35b2c --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp @@ -0,0 +1,312 @@ +/* +* RSA operations provided by OpenSSL +* (C) 2015 Jack Lloyd +* (C) 2017 Alexander Bluhm +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_RSA) + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::pair get_openssl_enc_pad(const std::string& eme) + { + if(eme == "Raw") + return std::make_pair(RSA_NO_PADDING, 0); + else if(eme == "EME-PKCS1-v1_5") + return std::make_pair(RSA_PKCS1_PADDING, 11); + else if(eme == "OAEP(SHA-1)" || eme == "EME1(SHA-1)") + return std::make_pair(RSA_PKCS1_OAEP_PADDING, 41); + else + throw Lookup_Error("OpenSSL RSA does not support EME " + eme); + } + +class OpenSSL_RSA_Encryption_Operation final : public PK_Ops::Encryption + { + public: + + OpenSSL_RSA_Encryption_Operation(const RSA_PublicKey& rsa, int pad, size_t pad_overhead) : + m_openssl_rsa(nullptr, ::RSA_free), m_padding(pad) + { + const std::vector der = rsa.public_key_bits(); + const uint8_t* der_ptr = der.data(); + m_openssl_rsa.reset(::d2i_RSAPublicKey(nullptr, &der_ptr, der.size())); + if(!m_openssl_rsa) + throw OpenSSL_Error("d2i_RSAPublicKey", ERR_get_error()); + + m_bits = 8 * (n_size() - pad_overhead) - 1; + } + + size_t ciphertext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); } + + size_t max_input_bits() const override { return m_bits; }; + + secure_vector encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator&) override + { + const size_t mod_sz = n_size(); + + if(msg_len > mod_sz) + throw Invalid_Argument("Input too large for RSA key"); + + secure_vector outbuf(mod_sz); + + secure_vector inbuf; + + if(m_padding == RSA_NO_PADDING) + { + inbuf.resize(mod_sz); + copy_mem(&inbuf[mod_sz - msg_len], msg, msg_len); + } + else + { + inbuf.assign(msg, msg + msg_len); + } + + int rc = ::RSA_public_encrypt(inbuf.size(), inbuf.data(), outbuf.data(), + m_openssl_rsa.get(), m_padding); + if(rc < 0) + throw OpenSSL_Error("RSA_public_encrypt", ERR_get_error()); + + return outbuf; + } + + private: + size_t n_size() const { return ::RSA_size(m_openssl_rsa.get()); } + std::unique_ptr> m_openssl_rsa; + size_t m_bits = 0; + int m_padding = 0; + }; + +class OpenSSL_RSA_Decryption_Operation final : public PK_Ops::Decryption + { + public: + + OpenSSL_RSA_Decryption_Operation(const RSA_PrivateKey& rsa, int pad) : + m_openssl_rsa(nullptr, ::RSA_free), m_padding(pad) + { + const secure_vector der = rsa.private_key_bits(); + const uint8_t* der_ptr = der.data(); + m_openssl_rsa.reset(d2i_RSAPrivateKey(nullptr, &der_ptr, der.size())); + if(!m_openssl_rsa) + throw OpenSSL_Error("d2i_RSAPrivateKey", ERR_get_error()); + } + + size_t plaintext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); } + + secure_vector decrypt(uint8_t& valid_mask, + const uint8_t msg[], size_t msg_len) override + { + secure_vector buf(::RSA_size(m_openssl_rsa.get())); + int rc = ::RSA_private_decrypt(msg_len, msg, buf.data(), m_openssl_rsa.get(), m_padding); + if(rc < 0 || static_cast(rc) > buf.size()) + { + valid_mask = 0; + buf.resize(0); + } + else + { + valid_mask = 0xFF; + buf.resize(rc); + } + + if(m_padding == RSA_NO_PADDING) + { + return CT::strip_leading_zeros(buf); + } + + return buf; + } + + private: + std::unique_ptr> m_openssl_rsa; + int m_padding = 0; + }; + +class OpenSSL_RSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + + OpenSSL_RSA_Verification_Operation(const RSA_PublicKey& rsa, const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_openssl_rsa(nullptr, ::RSA_free) + { + const std::vector der = rsa.public_key_bits(); + const uint8_t* der_ptr = der.data(); + m_openssl_rsa.reset(::d2i_RSAPublicKey(nullptr, &der_ptr, der.size())); + if(!m_openssl_rsa) + throw OpenSSL_Error("d2i_RSAPublicKey", ERR_get_error()); + } + + size_t max_input_bits() const override + { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return ::BN_num_bits(m_openssl_rsa->n) - 1; +#else + return ::RSA_bits(m_openssl_rsa.get()) - 1; +#endif + } + + bool with_recovery() const override { return true; } + + secure_vector verify_mr(const uint8_t msg[], size_t msg_len) override + { + const size_t mod_sz = ::RSA_size(m_openssl_rsa.get()); + + if(msg_len > mod_sz) + throw Invalid_Argument("OpenSSL RSA verify input too large"); + + secure_vector inbuf(mod_sz); + + if(msg_len > 0) + copy_mem(&inbuf[mod_sz - msg_len], msg, msg_len); + + secure_vector outbuf(mod_sz); + + int rc = ::RSA_public_decrypt(inbuf.size(), inbuf.data(), outbuf.data(), + m_openssl_rsa.get(), RSA_NO_PADDING); + if(rc < 0) + throw Invalid_Argument("RSA_public_decrypt"); + + return CT::strip_leading_zeros(outbuf); + } + private: + std::unique_ptr> m_openssl_rsa; + }; + +class OpenSSL_RSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + + OpenSSL_RSA_Signing_Operation(const RSA_PrivateKey& rsa, const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), + m_openssl_rsa(nullptr, ::RSA_free) + { + const secure_vector der = rsa.private_key_bits(); + const uint8_t* der_ptr = der.data(); + m_openssl_rsa.reset(d2i_RSAPrivateKey(nullptr, &der_ptr, der.size())); + if(!m_openssl_rsa) + throw OpenSSL_Error("d2i_RSAPrivateKey", ERR_get_error()); + } + + size_t signature_length() const override { return ::RSA_size(m_openssl_rsa.get()); } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator&) override + { + const size_t mod_sz = ::RSA_size(m_openssl_rsa.get()); + + if(msg_len > mod_sz) + throw Invalid_Argument("OpenSSL RSA sign input too large"); + + secure_vector inbuf(mod_sz); + copy_mem(&inbuf[mod_sz - msg_len], msg, msg_len); + + secure_vector outbuf(mod_sz); + + int rc = ::RSA_private_encrypt(inbuf.size(), inbuf.data(), outbuf.data(), + m_openssl_rsa.get(), RSA_NO_PADDING); + if(rc < 0) + throw OpenSSL_Error("RSA_private_encrypt", ERR_get_error()); + + return outbuf; + } + + size_t max_input_bits() const override + { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return ::BN_num_bits(m_openssl_rsa->n) - 1; +#else + return ::RSA_bits(m_openssl_rsa.get()) - 1; +#endif + } + + private: + std::unique_ptr> m_openssl_rsa; + }; + +} + +std::unique_ptr +make_openssl_rsa_enc_op(const RSA_PublicKey& key, const std::string& params) + { + auto pad_info = get_openssl_enc_pad(params); + return std::unique_ptr( + new OpenSSL_RSA_Encryption_Operation(key, pad_info.first, pad_info.second)); + } + +std::unique_ptr +make_openssl_rsa_dec_op(const RSA_PrivateKey& key, const std::string& params) + { + auto pad_info = get_openssl_enc_pad(params); + return std::unique_ptr(new OpenSSL_RSA_Decryption_Operation(key, pad_info.first)); + } + +std::unique_ptr +make_openssl_rsa_ver_op(const RSA_PublicKey& key, const std::string& params) + { + return std::unique_ptr(new OpenSSL_RSA_Verification_Operation(key, params)); + } + +std::unique_ptr +make_openssl_rsa_sig_op(const RSA_PrivateKey& key, const std::string& params) + { + return std::unique_ptr(new OpenSSL_RSA_Signing_Operation(key, params)); + } + +std::unique_ptr +make_openssl_rsa_private_key(RandomNumberGenerator& rng, size_t rsa_bits) + { + if (rsa_bits > INT_MAX) + throw Internal_Error("rsa_bits overflow"); + + secure_vector seed(BOTAN_SYSTEM_RNG_POLL_REQUEST); + rng.randomize(seed.data(), seed.size()); + RAND_seed(seed.data(), seed.size()); + + std::unique_ptr> bn(BN_new(), BN_free); + if(!bn) + throw OpenSSL_Error("BN_new", ERR_get_error()); + if(!BN_set_word(bn.get(), RSA_F4)) + throw OpenSSL_Error("BN_set_word", ERR_get_error()); + + std::unique_ptr> rsa(RSA_new(), RSA_free); + if(!rsa) + throw OpenSSL_Error("RSA_new", ERR_get_error()); + if(!RSA_generate_key_ex(rsa.get(), rsa_bits, bn.get(), nullptr)) + throw OpenSSL_Error("RSA_generate_key_ex", ERR_get_error()); + + uint8_t* der = nullptr; + int bytes = i2d_RSAPrivateKey(rsa.get(), &der); + if(bytes < 0) + throw OpenSSL_Error("i2d_RSAPrivateKey", ERR_get_error()); + + const secure_vector keydata(der, der + bytes); + secure_scrub_memory(der, bytes); + std::free(der); + return std::unique_ptr + (new RSA_PrivateKey(AlgorithmIdentifier(), keydata)); + } +} + +#endif // BOTAN_HAS_RSA diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/info.txt b/comm/third_party/botan/src/lib/prov/pkcs11/info.txt new file mode 100644 index 0000000000..0f8aab8e09 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/info.txt @@ -0,0 +1,36 @@ + +PKCS11 -> 20160219 + + + +dyn_load +rng +pubkey +pk_pad + + + +p11_mechanism.h + + + +pkcs11.h +pkcs11f.h +pkcs11t.h + + + +p11.h +p11_ecc_key.h +p11_ecdh.h +p11_ecdsa.h +p11_object.h +p11_randomgenerator.h +p11_rsa.h +p11_types.h +p11_x509.h + +p11_module.h +p11_slot.h +p11_session.h + diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11.cpp new file mode 100644 index 0000000000..334a75caaf --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11.cpp @@ -0,0 +1,767 @@ +/* +* PKCS#11 +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#include +#include +#include + +namespace Botan { +namespace PKCS11 { + +ReturnValue* ThrowException = reinterpret_cast< ReturnValue* >(-1); + +namespace { +/// @param function_result Return value of the PKCS11 module function +/// @param return_value if (`ThrowException`) is passed the function throws an exception, otherwise if a non-NULL pointer is passed: +/// return_value receives the return value of the PKCS#11 function and no exception is thrown. +/// @return true if function call was successful, false otherwise +bool handle_return_value(const CK_RV function_result, ReturnValue* return_value) + { + if(return_value == ThrowException) + { + if(static_cast< ReturnValue >(function_result) != ReturnValue::OK) + { + // caller wants exception + throw PKCS11_ReturnError(static_cast< ReturnValue >(function_result)); + } + } + else if(return_value != nullptr) + { + // caller wants return value + *return_value = static_cast< ReturnValue >(function_result); + } + + return static_cast< ReturnValue >(function_result) == ReturnValue::OK; + } +} + +void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin) + { + slot.initialize(label, so_pin); + set_pin(slot, so_pin, pin); + } + +void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin) + { + Session session(slot, false); + session.login(UserType::User, old_pin); + session.set_pin(old_pin, new_pin); + } + +void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin) + { + Session session(slot, false); + session.login(UserType::SO, old_so_pin); + session.set_pin(old_so_pin, new_so_pin); + } + +void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin) + { + Session session(slot, false); + session.login(UserType::SO, so_pin); + session.init_pin(pin); + } + +LowLevel::LowLevel(FunctionListPtr ptr) : + m_func_list_ptr(ptr) + { + if(m_func_list_ptr == nullptr) + { + throw Invalid_Argument("Invalid PKCS#11 function list ptr"); + } + } + +/****************************** General purpose functions ******************************/ + +bool LowLevel::C_Initialize(VoidPtr init_args, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Initialize(init_args), return_value); + } + +bool LowLevel::C_Finalize(VoidPtr reserved, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Finalize(reserved), return_value); + } + +bool LowLevel::C_GetInfo(Info* info_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetInfo(info_ptr), return_value); + } + +bool LowLevel::C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr, + ReturnValue* return_value) + { + using get_function_list = CK_RV(*)(FunctionListPtr*); + + get_function_list get_function_list_ptr = pkcs11_module.resolve("C_GetFunctionList"); + + return handle_return_value(get_function_list_ptr(function_list_ptr_ptr), return_value); + } + +/****************************** Slot and token management functions ******************************/ + +bool LowLevel::C_GetSlotList(Bbool token_present, + SlotId* slot_list_ptr, + Ulong* count_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetSlotList(token_present, slot_list_ptr, count_ptr), return_value); + } + +bool LowLevel::C_GetSlotList(bool token_present, + std::vector& slot_ids, + ReturnValue* return_value) const + { + slot_ids.clear(); + + // first get available slots + Ulong number_slots = 0; + + bool success = C_GetSlotList(token_present, nullptr, &number_slots, return_value); + + if(!success || !number_slots) + { + return success; + } + + // get actual slot ids + slot_ids.resize(number_slots); + return C_GetSlotList(token_present, slot_ids.data(), &number_slots, return_value); + } + +bool LowLevel::C_GetSlotInfo(SlotId slot_id, + SlotInfo* info_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetSlotInfo(slot_id, info_ptr), return_value); + } + +bool LowLevel::C_GetTokenInfo(SlotId slot_id, + TokenInfo* info_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetTokenInfo(slot_id, info_ptr), return_value); + } + +bool LowLevel::C_WaitForSlotEvent(Flags flags, + SlotId* slot_ptr, + VoidPtr reserved, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_WaitForSlotEvent(flags, slot_ptr, reserved), return_value); + } + +bool LowLevel::C_GetMechanismList(SlotId slot_id, + MechanismType* mechanism_list_ptr, + Ulong* count_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetMechanismList(slot_id, + reinterpret_cast< CK_MECHANISM_TYPE_PTR >(mechanism_list_ptr), count_ptr), return_value); + } + +bool LowLevel::C_GetMechanismList(SlotId slot_id, + std::vector& mechanisms, + ReturnValue* return_value) const + { + mechanisms.clear(); + + // first get number of mechanisms + Ulong number_mechanisms = 0; + + bool success = C_GetMechanismList(slot_id, nullptr, &number_mechanisms, return_value); + + if(!success || !number_mechanisms) + { + return success; + } + + // get actual mechanisms + mechanisms.resize(number_mechanisms); + return C_GetMechanismList(slot_id, reinterpret_cast< MechanismType* >(mechanisms.data()), &number_mechanisms, + return_value); + } + +bool LowLevel::C_GetMechanismInfo(SlotId slot_id, + MechanismType type, + MechanismInfo* info_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetMechanismInfo(slot_id, static_cast< CK_MECHANISM_TYPE >(type), + info_ptr), return_value); + } + +bool LowLevel::C_InitToken(SlotId slot_id, + Utf8Char* so_pin_ptr, + Ulong so_pin_len, + Utf8Char* label_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_InitToken(slot_id, so_pin_ptr, so_pin_len, label_ptr), return_value); + } + +bool LowLevel::C_InitPIN(SessionHandle session, + Utf8Char* pin_ptr, + Ulong pin_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_InitPIN(session, pin_ptr, pin_len), return_value); + } + +bool LowLevel::C_SetPIN(SessionHandle session, + Utf8Char* old_pin_ptr, + Ulong old_len, + Utf8Char* new_pin_ptr, + Ulong new_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SetPIN(session, old_pin_ptr, old_len, new_pin_ptr, new_len), + return_value); + } + +/****************************** Session management ******************************/ + +bool LowLevel::C_OpenSession(SlotId slot_id, + Flags flags, + VoidPtr application, + Notify notify, + SessionHandle* session_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_OpenSession(slot_id, flags, application, notify, session_ptr), + return_value); + } + +bool LowLevel::C_CloseSession(SessionHandle session, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_CloseSession(session), return_value); + } + +bool LowLevel::C_CloseAllSessions(SlotId slot_id, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_CloseAllSessions(slot_id), return_value); + } + +bool LowLevel::C_GetSessionInfo(SessionHandle session, + SessionInfo* info_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetSessionInfo(session, info_ptr), return_value); + } + +bool LowLevel::C_GetOperationState(SessionHandle session, + Byte* operation_state_ptr, + Ulong* operation_state_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetOperationState(session, operation_state_ptr, operation_state_len_ptr), + return_value); + } + +bool LowLevel::C_SetOperationState(SessionHandle session, + Byte* operation_state_ptr, + Ulong operation_state_len, + ObjectHandle encryption_key, + ObjectHandle authentication_key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SetOperationState(session, operation_state_ptr, operation_state_len, + encryption_key, authentication_key), return_value); + } + +bool LowLevel::C_Login(SessionHandle session, + UserType user_type, + Utf8Char* pin_ptr, + Ulong pin_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Login(session, static_cast< CK_USER_TYPE >(user_type), pin_ptr, pin_len), + return_value); + } + +bool LowLevel::C_Logout(SessionHandle session, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Logout(session), return_value); + } + +/****************************** Object management functions ******************************/ + +bool LowLevel::C_CreateObject(SessionHandle session, + Attribute* attribute_template_ptr, + Ulong count, + ObjectHandle* object_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_CreateObject(session, attribute_template_ptr, count, object_ptr), + return_value); + } + +bool LowLevel::C_CopyObject(SessionHandle session, + ObjectHandle object, + Attribute* attribute_template_ptr, + Ulong count, + ObjectHandle* new_object_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_CopyObject(session, object, attribute_template_ptr, count, + new_object_ptr), return_value); + } + +bool LowLevel::C_DestroyObject(SessionHandle session, + ObjectHandle object, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DestroyObject(session, object), return_value); + } + +bool LowLevel::C_GetObjectSize(SessionHandle session, + ObjectHandle object, + Ulong* size_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetObjectSize(session, object, size_ptr), return_value); + } + +bool LowLevel::C_GetAttributeValue(SessionHandle session, + ObjectHandle object, + Attribute* attribute_template_ptr, + Ulong count, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetAttributeValue(session, object, attribute_template_ptr, count), + return_value); + } + +bool LowLevel::C_SetAttributeValue(SessionHandle session, + ObjectHandle object, + Attribute* attribute_template_ptr, + Ulong count, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SetAttributeValue(session, object, attribute_template_ptr, count), + return_value); + } + +bool LowLevel::C_FindObjectsInit(SessionHandle session, + Attribute* attribute_template_ptr, + Ulong count, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_FindObjectsInit(session, attribute_template_ptr, count), return_value); + } + +bool LowLevel::C_FindObjects(SessionHandle session, + ObjectHandle* object_ptr, + Ulong max_object_count, + Ulong* object_count_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_FindObjects(session, object_ptr, max_object_count, object_count_ptr), + return_value); + } + +bool LowLevel::C_FindObjectsFinal(SessionHandle session, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_FindObjectsFinal(session), return_value); + } + +/****************************** Encryption functions ******************************/ + +bool LowLevel::C_EncryptInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_EncryptInit(session, mechanism_ptr, key), return_value); + } + +bool LowLevel::C_Encrypt(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* encrypted_data_ptr, + Ulong* encrypted_data_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Encrypt(session, data_ptr, data_len, encrypted_data_ptr, + encrypted_data_len_ptr), return_value); + } + +bool LowLevel::C_EncryptUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + Byte* encrypted_part_ptr, + Ulong* encrypted_part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_EncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr, + encrypted_part_len_ptr), return_value); + } + +bool LowLevel::C_EncryptFinal(SessionHandle session, + Byte* last_encrypted_part_ptr, + Ulong* last_encrypted_part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_EncryptFinal(session, last_encrypted_part_ptr, + last_encrypted_part_len_ptr), return_value); + } + +/****************************** Decryption functions ******************************/ + +bool LowLevel::C_DecryptInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DecryptInit(session, mechanism_ptr, key), return_value); + } + +bool LowLevel::C_Decrypt(SessionHandle session, + Byte* encrypted_data_ptr, + Ulong encrypted_data_len, + Byte* data_ptr, + Ulong* data_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Decrypt(session, encrypted_data_ptr, encrypted_data_len, data_ptr, + data_len_ptr), return_value); + } + +bool LowLevel::C_DecryptUpdate(SessionHandle session, + Byte* encrypted_part_ptr, + Ulong encrypted_part_len, + Byte* part_ptr, + Ulong* part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DecryptUpdate(session, encrypted_part_ptr, encrypted_part_len, part_ptr, + part_len_ptr), return_value); + } + +bool LowLevel::C_DecryptFinal(SessionHandle session, + Byte* last_part_ptr, + Ulong* last_part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DecryptFinal(session, last_part_ptr, last_part_len_ptr), return_value); + } + +/****************************** Message digesting functions ******************************/ + +bool LowLevel::C_DigestInit(SessionHandle session, + Mechanism* mechanism, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DigestInit(session, mechanism), return_value); + } + +bool LowLevel::C_Digest(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* digest_ptr, + Ulong* digest_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Digest(session, data_ptr, data_len, digest_ptr, digest_len_ptr), + return_value); + } + +bool LowLevel::C_DigestUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DigestUpdate(session, part_ptr, part_len), return_value); + } + +bool LowLevel::C_DigestKey(SessionHandle session, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DigestKey(session, key), return_value); + } + +bool LowLevel::C_DigestFinal(SessionHandle session, + Byte* digest_ptr, + Ulong* digest_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DigestFinal(session, digest_ptr, digest_len_ptr), return_value); + } + +/****************************** Signing and MACing functions ******************************/ + +bool LowLevel::C_SignInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SignInit(session, mechanism_ptr, key), return_value); + } + +bool LowLevel::C_Sign(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* signature_ptr, + Ulong* signature_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Sign(session, data_ptr, data_len, signature_ptr, signature_len_ptr), + return_value); + } + +bool LowLevel::C_SignUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SignUpdate(session, part_ptr, part_len), return_value); + } + +bool LowLevel::C_SignFinal(SessionHandle session, + Byte* signature_ptr, + Ulong* signature_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SignFinal(session, signature_ptr, signature_len_ptr), return_value); + } + +bool LowLevel::C_SignRecoverInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SignRecoverInit(session, mechanism_ptr, key), return_value); + } + +bool LowLevel::C_SignRecover(SessionHandle session, + Byte* data, + Ulong data_len, + Byte* signature, + Ulong* signature_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SignRecover(session, data, data_len, signature, signature_len), + return_value); + } + +/****************************** Functions for verifying signatures and MACs ******************************/ + +bool LowLevel::C_VerifyInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_VerifyInit(session, mechanism_ptr, key), return_value); + } + +bool LowLevel::C_Verify(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* signature_ptr, + Ulong signature_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_Verify(session, data_ptr, data_len, signature_ptr, signature_len), + return_value); + } + +bool LowLevel::C_VerifyUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_VerifyUpdate(session, part_ptr, part_len), return_value); + } + +bool LowLevel::C_VerifyFinal(SessionHandle session, + Byte* signature_ptr, + Ulong signature_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_VerifyFinal(session, signature_ptr, signature_len), return_value); + } + +bool LowLevel::C_VerifyRecoverInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_VerifyRecoverInit(session, mechanism_ptr, key), return_value); + } + +bool LowLevel::C_VerifyRecover(SessionHandle session, + Byte* signature_ptr, + Ulong signature_len, + Byte* data_ptr, + Ulong* data_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_VerifyRecover(session, signature_ptr, signature_len, data_ptr, + data_len_ptr), return_value); + } + +/****************************** Dual-purpose cryptographic functions ******************************/ + +bool LowLevel::C_DigestEncryptUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + Byte* encrypted_part_ptr, + Ulong* encrypted_part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DigestEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr, + encrypted_part_len_ptr), return_value); + } + +bool LowLevel::C_DecryptDigestUpdate(SessionHandle session, + Byte* encrypted_part_ptr, + Ulong encrypted_part_len, + Byte* part_ptr, + Ulong* part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DecryptDigestUpdate(session, encrypted_part_ptr, encrypted_part_len, + part_ptr, part_len_ptr), return_value); + } + +bool LowLevel::C_SignEncryptUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + Byte* encrypted_part_ptr, + Ulong* encrypted_part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SignEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr, + encrypted_part_len_ptr), return_value); + } + +bool LowLevel::C_DecryptVerifyUpdate(SessionHandle session, + Byte* encrypted_part_ptr, + Ulong encrypted_part_len, + Byte* part_ptr, + Ulong* part_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DecryptVerifyUpdate(session, encrypted_part_ptr, encrypted_part_len, + part_ptr, part_len_ptr), return_value); + } + +/****************************** Key management functions ******************************/ + +bool LowLevel::C_GenerateKey(SessionHandle session, + Mechanism* mechanism_ptr, + Attribute* attribute_template_ptr, + Ulong count, + ObjectHandle* key_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GenerateKey(session, mechanism_ptr, attribute_template_ptr, count, + key_ptr), return_value); + } + +bool LowLevel::C_GenerateKeyPair(SessionHandle session, + Mechanism* mechanism_ptr, + Attribute* public_key_template_ptr, + Ulong public_key_attribute_count, + Attribute* private_key_template_ptr, + Ulong private_key_attribute_count, + ObjectHandle* public_key_ptr, + ObjectHandle* private_key_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GenerateKeyPair(session, mechanism_ptr, public_key_template_ptr, + public_key_attribute_count, private_key_template_ptr, + private_key_attribute_count, public_key_ptr, private_key_ptr), return_value); + } + +bool LowLevel::C_WrapKey(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle wrapping_key, + ObjectHandle key, + Byte* wrapped_key_ptr, + Ulong* wrapped_key_len_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_WrapKey(session, mechanism_ptr, wrapping_key, key, wrapped_key_ptr, + wrapped_key_len_ptr), return_value); + } + +bool LowLevel::C_UnwrapKey(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle unwrapping_key, + Byte* wrapped_key_ptr, + Ulong wrapped_key_len, + Attribute* attribute_template_ptr, + Ulong attribute_count, + ObjectHandle* key_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_UnwrapKey(session, mechanism_ptr, unwrapping_key, wrapped_key_ptr, + wrapped_key_len, attribute_template_ptr, + attribute_count, key_ptr), return_value); + } + +bool LowLevel::C_DeriveKey(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle base_key, + Attribute* attribute_template_ptr, + Ulong attribute_count, + ObjectHandle* key_ptr, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_DeriveKey(session, mechanism_ptr, base_key, attribute_template_ptr, + attribute_count, key_ptr), return_value); + } + +/****************************** Random number generation functions ******************************/ + +bool LowLevel::C_SeedRandom(SessionHandle session, + Byte* seed_ptr, + Ulong seed_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_SeedRandom(session, seed_ptr, seed_len), return_value); + } + +bool LowLevel::C_GenerateRandom(SessionHandle session, + Byte* random_data_ptr, + Ulong random_len, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GenerateRandom(session, random_data_ptr, random_len), return_value); + } + +/****************************** Parallel function management functions ******************************/ + +bool LowLevel::C_GetFunctionStatus(SessionHandle session, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_GetFunctionStatus(session), return_value); + } + +bool LowLevel::C_CancelFunction(SessionHandle session, + ReturnValue* return_value) const + { + return handle_return_value(m_func_list_ptr->C_CancelFunction(session), return_value); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11.h new file mode 100644 index 0000000000..0fae1c2c58 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11.h @@ -0,0 +1,2930 @@ +/* +* PKCS#11 +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_H_ +#define BOTAN_P11_H_ + +#include +#include + +#include +#include +#include + +#define CK_PTR * + +#if defined(_MSC_VER) +#define CK_DECLARE_FUNCTION(returnType, name) \ + returnType __declspec(dllimport) name +#else +#define CK_DECLARE_FUNCTION(returnType, name) \ + returnType name +#endif + +#if defined(_MSC_VER) +#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + returnType __declspec(dllimport) (* name) +#else +#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + returnType (* name) +#endif + +#define CK_CALLBACK_FUNCTION(returnType, name) \ + returnType (* name) + +#ifndef NULL_PTR + #define NULL_PTR nullptr +#endif + +#if defined(_MSC_VER) + #pragma pack(push, cryptoki, 1) +#endif + +#include "pkcs11.h" + +#if defined(_MSC_VER) + #pragma pack(pop, cryptoki) +#endif + +static_assert(CRYPTOKI_VERSION_MAJOR == 2 && CRYPTOKI_VERSION_MINOR == 40, + "The Botan PKCS#11 module was implemented against PKCS#11 v2.40. Please use the correct PKCS#11 headers."); + +namespace Botan { + +class Dynamically_Loaded_Library; + +namespace PKCS11 { + +using secure_string = secure_vector; + +enum class AttributeType : CK_ATTRIBUTE_TYPE + { + Class = CKA_CLASS, + Token = CKA_TOKEN, + Private = CKA_PRIVATE, + Label = CKA_LABEL, + Application = CKA_APPLICATION, + Value = CKA_VALUE, + ObjectId = CKA_OBJECT_ID, + CertificateType = CKA_CERTIFICATE_TYPE, + Issuer = CKA_ISSUER, + SerialNumber = CKA_SERIAL_NUMBER, + AcIssuer = CKA_AC_ISSUER, + Owner = CKA_OWNER, + AttrTypes = CKA_ATTR_TYPES, + Trusted = CKA_TRUSTED, + CertificateCategory = CKA_CERTIFICATE_CATEGORY, + JavaMidpSecurityDomain = CKA_JAVA_MIDP_SECURITY_DOMAIN, + Url = CKA_URL, + HashOfSubjectPublicKey = CKA_HASH_OF_SUBJECT_PUBLIC_KEY, + HashOfIssuerPublicKey = CKA_HASH_OF_ISSUER_PUBLIC_KEY, + NameHashAlgorithm = CKA_NAME_HASH_ALGORITHM, + CheckValue = CKA_CHECK_VALUE, + KeyType = CKA_KEY_TYPE, + Subject = CKA_SUBJECT, + Id = CKA_ID, + Sensitive = CKA_SENSITIVE, + Encrypt = CKA_ENCRYPT, + Decrypt = CKA_DECRYPT, + Wrap = CKA_WRAP, + Unwrap = CKA_UNWRAP, + Sign = CKA_SIGN, + SignRecover = CKA_SIGN_RECOVER, + Verify = CKA_VERIFY, + VerifyRecover = CKA_VERIFY_RECOVER, + Derive = CKA_DERIVE, + StartDate = CKA_START_DATE, + EndDate = CKA_END_DATE, + Modulus = CKA_MODULUS, + ModulusBits = CKA_MODULUS_BITS, + PublicExponent = CKA_PUBLIC_EXPONENT, + PrivateExponent = CKA_PRIVATE_EXPONENT, + Prime1 = CKA_PRIME_1, + Prime2 = CKA_PRIME_2, + Exponent1 = CKA_EXPONENT_1, + Exponent2 = CKA_EXPONENT_2, + Coefficient = CKA_COEFFICIENT, + PublicKeyInfo = CKA_PUBLIC_KEY_INFO, + Prime = CKA_PRIME, + Subprime = CKA_SUBPRIME, + Base = CKA_BASE, + PrimeBits = CKA_PRIME_BITS, + SubprimeBits = CKA_SUBPRIME_BITS, + SubPrimeBits = CKA_SUB_PRIME_BITS, + ValueBits = CKA_VALUE_BITS, + ValueLen = CKA_VALUE_LEN, + Extractable = CKA_EXTRACTABLE, + Local = CKA_LOCAL, + NeverExtractable = CKA_NEVER_EXTRACTABLE, + AlwaysSensitive = CKA_ALWAYS_SENSITIVE, + KeyGenMechanism = CKA_KEY_GEN_MECHANISM, + Modifiable = CKA_MODIFIABLE, + Copyable = CKA_COPYABLE, + Destroyable = CKA_DESTROYABLE, + EcdsaParams = CKA_ECDSA_PARAMS, + EcParams = CKA_EC_PARAMS, + EcPoint = CKA_EC_POINT, + SecondaryAuth = CKA_SECONDARY_AUTH, + AuthPinFlags = CKA_AUTH_PIN_FLAGS, + AlwaysAuthenticate = CKA_ALWAYS_AUTHENTICATE, + WrapWithTrusted = CKA_WRAP_WITH_TRUSTED, + WrapTemplate = CKA_WRAP_TEMPLATE, + UnwrapTemplate = CKA_UNWRAP_TEMPLATE, + DeriveTemplate = CKA_DERIVE_TEMPLATE, + OtpFormat = CKA_OTP_FORMAT, + OtpLength = CKA_OTP_LENGTH, + OtpTimeInterval = CKA_OTP_TIME_INTERVAL, + OtpUserFriendlyMode = CKA_OTP_USER_FRIENDLY_MODE, + OtpChallengeRequirement = CKA_OTP_CHALLENGE_REQUIREMENT, + OtpTimeRequirement = CKA_OTP_TIME_REQUIREMENT, + OtpCounterRequirement = CKA_OTP_COUNTER_REQUIREMENT, + OtpPinRequirement = CKA_OTP_PIN_REQUIREMENT, + OtpCounter = CKA_OTP_COUNTER, + OtpTime = CKA_OTP_TIME, + OtpUserIdentifier = CKA_OTP_USER_IDENTIFIER, + OtpServiceIdentifier = CKA_OTP_SERVICE_IDENTIFIER, + OtpServiceLogo = CKA_OTP_SERVICE_LOGO, + OtpServiceLogoType = CKA_OTP_SERVICE_LOGO_TYPE, + Gostr3410Params = CKA_GOSTR3410_PARAMS, + Gostr3411Params = CKA_GOSTR3411_PARAMS, + Gost28147Params = CKA_GOST28147_PARAMS, + HwFeatureType = CKA_HW_FEATURE_TYPE, + ResetOnInit = CKA_RESET_ON_INIT, + HasReset = CKA_HAS_RESET, + PixelX = CKA_PIXEL_X, + PixelY = CKA_PIXEL_Y, + Resolution = CKA_RESOLUTION, + CharRows = CKA_CHAR_ROWS, + CharColumns = CKA_CHAR_COLUMNS, + Color = CKA_COLOR, + BitsPerPixel = CKA_BITS_PER_PIXEL, + CharSets = CKA_CHAR_SETS, + EncodingMethods = CKA_ENCODING_METHODS, + MimeTypes = CKA_MIME_TYPES, + MechanismType = CKA_MECHANISM_TYPE, + RequiredCmsAttributes = CKA_REQUIRED_CMS_ATTRIBUTES, + DefaultCmsAttributes = CKA_DEFAULT_CMS_ATTRIBUTES, + SupportedCmsAttributes = CKA_SUPPORTED_CMS_ATTRIBUTES, + AllowedMechanisms = CKA_ALLOWED_MECHANISMS, + VendorDefined = CKA_VENDOR_DEFINED, + }; + +enum class CertificateType : CK_CERTIFICATE_TYPE + { + X509 = CKC_X_509, + X509AttrCert = CKC_X_509_ATTR_CERT, + Wtls = CKC_WTLS, + VendorDefined = CKC_VENDOR_DEFINED, + }; + +/// Indicates if a stored certificate is a user certificate for which the corresponding private key is available +/// on the token ("token user"), a CA certificate ("authority"), or another end-entity certificate ("other entity"). +enum class CertificateCategory : CK_ULONG + { + Unspecified = CK_CERTIFICATE_CATEGORY_UNSPECIFIED, + TokenUser = CK_CERTIFICATE_CATEGORY_TOKEN_USER, + Authority = CK_CERTIFICATE_CATEGORY_AUTHORITY, + OtherEntity = CK_CERTIFICATE_CATEGORY_OTHER_ENTITY + }; + +enum class KeyDerivation : CK_ULONG + { + Null = CKD_NULL, + Sha1Kdf = CKD_SHA1_KDF, + Sha1KdfAsn1 = CKD_SHA1_KDF_ASN1, + Sha1KdfConcatenate = CKD_SHA1_KDF_CONCATENATE, + Sha224Kdf = CKD_SHA224_KDF, + Sha256Kdf = CKD_SHA256_KDF, + Sha384Kdf = CKD_SHA384_KDF, + Sha512Kdf = CKD_SHA512_KDF, + CpdiversifyKdf = CKD_CPDIVERSIFY_KDF, + }; + +enum class Flag : CK_FLAGS + { + None = 0, + TokenPresent = CKF_TOKEN_PRESENT, + RemovableDevice = CKF_REMOVABLE_DEVICE, + HwSlot = CKF_HW_SLOT, + Rng = CKF_RNG, + WriteProtected = CKF_WRITE_PROTECTED, + LoginRequired = CKF_LOGIN_REQUIRED, + UserPinInitialized = CKF_USER_PIN_INITIALIZED, + RestoreKeyNotNeeded = CKF_RESTORE_KEY_NOT_NEEDED, + ClockOnToken = CKF_CLOCK_ON_TOKEN, + ProtectedAuthenticationPath = CKF_PROTECTED_AUTHENTICATION_PATH, + DualCryptoOperations = CKF_DUAL_CRYPTO_OPERATIONS, + TokenInitialized = CKF_TOKEN_INITIALIZED, + SecondaryAuthentication = CKF_SECONDARY_AUTHENTICATION, + UserPinCountLow = CKF_USER_PIN_COUNT_LOW, + UserPinFinalTry = CKF_USER_PIN_FINAL_TRY, + UserPinLocked = CKF_USER_PIN_LOCKED, + UserPinToBeChanged = CKF_USER_PIN_TO_BE_CHANGED, + SoPinCountLow = CKF_SO_PIN_COUNT_LOW, + SoPinFinalTry = CKF_SO_PIN_FINAL_TRY, + SoPinLocked = CKF_SO_PIN_LOCKED, + SoPinToBeChanged = CKF_SO_PIN_TO_BE_CHANGED, + ErrorState = CKF_ERROR_STATE, + RwSession = CKF_RW_SESSION, + SerialSession = CKF_SERIAL_SESSION, + ArrayAttribute = CKF_ARRAY_ATTRIBUTE, + Hw = CKF_HW, + Encrypt = CKF_ENCRYPT, + Decrypt = CKF_DECRYPT, + Digest = CKF_DIGEST, + Sign = CKF_SIGN, + SignRecover = CKF_SIGN_RECOVER, + Verify = CKF_VERIFY, + VerifyRecover = CKF_VERIFY_RECOVER, + Generate = CKF_GENERATE, + GenerateKeyPair = CKF_GENERATE_KEY_PAIR, + Wrap = CKF_WRAP, + Unwrap = CKF_UNWRAP, + Derive = CKF_DERIVE, + EcFP = CKF_EC_F_P, + EcF2m = CKF_EC_F_2M, + EcEcparameters = CKF_EC_ECPARAMETERS, + EcNamedcurve = CKF_EC_NAMEDCURVE, + EcUncompress = CKF_EC_UNCOMPRESS, + EcCompress = CKF_EC_COMPRESS, + Extension = CKF_EXTENSION, + LibraryCantCreateOsThreads = CKF_LIBRARY_CANT_CREATE_OS_THREADS, + OsLockingOk = CKF_OS_LOCKING_OK, + DontBlock = CKF_DONT_BLOCK, + NextOtp = CKF_NEXT_OTP, + ExcludeTime = CKF_EXCLUDE_TIME, + ExcludeCounter = CKF_EXCLUDE_COUNTER, + ExcludeChallenge = CKF_EXCLUDE_CHALLENGE, + ExcludePin = CKF_EXCLUDE_PIN, + UserFriendlyOtp = CKF_USER_FRIENDLY_OTP, + }; + +inline Flag operator | (Flag a, Flag b) + { + return static_cast< Flag >(static_cast< CK_FLAGS >(a) | static_cast< CK_FLAGS >(b)); + } + +enum class MGF : CK_RSA_PKCS_MGF_TYPE + { + Mgf1Sha1 = CKG_MGF1_SHA1, + Mgf1Sha256 = CKG_MGF1_SHA256, + Mgf1Sha384 = CKG_MGF1_SHA384, + Mgf1Sha512 = CKG_MGF1_SHA512, + Mgf1Sha224 = CKG_MGF1_SHA224, + }; + +enum class HardwareType : CK_HW_FEATURE_TYPE + { + MonotonicCounter = CKH_MONOTONIC_COUNTER, + Clock = CKH_CLOCK, + UserInterface = CKH_USER_INTERFACE, + VendorDefined = CKH_VENDOR_DEFINED, + }; + +enum class KeyType : CK_KEY_TYPE + { + Rsa = CKK_RSA, + Dsa = CKK_DSA, + Dh = CKK_DH, + Ecdsa = CKK_ECDSA, + Ec = CKK_EC, + X942Dh = CKK_X9_42_DH, + Kea = CKK_KEA, + GenericSecret = CKK_GENERIC_SECRET, + Rc2 = CKK_RC2, + Rc4 = CKK_RC4, + Des = CKK_DES, + Des2 = CKK_DES2, + Des3 = CKK_DES3, + Cast = CKK_CAST, + Cast3 = CKK_CAST3, + Cast5 = CKK_CAST5, + Cast128 = CKK_CAST128, + Rc5 = CKK_RC5, + Idea = CKK_IDEA, + Skipjack = CKK_SKIPJACK, + Baton = CKK_BATON, + Juniper = CKK_JUNIPER, + Cdmf = CKK_CDMF, + Aes = CKK_AES, + Blowfish = CKK_BLOWFISH, + Twofish = CKK_TWOFISH, + Securid = CKK_SECURID, + Hotp = CKK_HOTP, + Acti = CKK_ACTI, + Camellia = CKK_CAMELLIA, + Aria = CKK_ARIA, + Md5Hmac = CKK_MD5_HMAC, + Sha1Hmac = CKK_SHA_1_HMAC, + Ripemd128Hmac = CKK_RIPEMD128_HMAC, + Ripemd160Hmac = CKK_RIPEMD160_HMAC, + Sha256Hmac = CKK_SHA256_HMAC, + Sha384Hmac = CKK_SHA384_HMAC, + Sha512Hmac = CKK_SHA512_HMAC, + Sha224Hmac = CKK_SHA224_HMAC, + Seed = CKK_SEED, + Gostr3410 = CKK_GOSTR3410, + Gostr3411 = CKK_GOSTR3411, + Gost28147 = CKK_GOST28147, + VendorDefined = CKK_VENDOR_DEFINED, + }; + +enum class MechanismType : CK_MECHANISM_TYPE + { + RsaPkcsKeyPairGen = CKM_RSA_PKCS_KEY_PAIR_GEN, + RsaPkcs = CKM_RSA_PKCS, + Rsa9796 = CKM_RSA_9796, + RsaX509 = CKM_RSA_X_509, + Md2RsaPkcs = CKM_MD2_RSA_PKCS, + Md5RsaPkcs = CKM_MD5_RSA_PKCS, + Sha1RsaPkcs = CKM_SHA1_RSA_PKCS, + Ripemd128RsaPkcs = CKM_RIPEMD128_RSA_PKCS, + Ripemd160RsaPkcs = CKM_RIPEMD160_RSA_PKCS, + RsaPkcsOaep = CKM_RSA_PKCS_OAEP, + RsaX931KeyPairGen = CKM_RSA_X9_31_KEY_PAIR_GEN, + RsaX931 = CKM_RSA_X9_31, + Sha1RsaX931 = CKM_SHA1_RSA_X9_31, + RsaPkcsPss = CKM_RSA_PKCS_PSS, + Sha1RsaPkcsPss = CKM_SHA1_RSA_PKCS_PSS, + DsaKeyPairGen = CKM_DSA_KEY_PAIR_GEN, + Dsa = CKM_DSA, + DsaSha1 = CKM_DSA_SHA1, + DsaSha224 = CKM_DSA_SHA224, + DsaSha256 = CKM_DSA_SHA256, + DsaSha384 = CKM_DSA_SHA384, + DsaSha512 = CKM_DSA_SHA512, + DhPkcsKeyPairGen = CKM_DH_PKCS_KEY_PAIR_GEN, + DhPkcsDerive = CKM_DH_PKCS_DERIVE, + X942DhKeyPairGen = CKM_X9_42_DH_KEY_PAIR_GEN, + X942DhDerive = CKM_X9_42_DH_DERIVE, + X942DhHybridDerive = CKM_X9_42_DH_HYBRID_DERIVE, + X942MqvDerive = CKM_X9_42_MQV_DERIVE, + Sha256RsaPkcs = CKM_SHA256_RSA_PKCS, + Sha384RsaPkcs = CKM_SHA384_RSA_PKCS, + Sha512RsaPkcs = CKM_SHA512_RSA_PKCS, + Sha256RsaPkcsPss = CKM_SHA256_RSA_PKCS_PSS, + Sha384RsaPkcsPss = CKM_SHA384_RSA_PKCS_PSS, + Sha512RsaPkcsPss = CKM_SHA512_RSA_PKCS_PSS, + Sha224RsaPkcs = CKM_SHA224_RSA_PKCS, + Sha224RsaPkcsPss = CKM_SHA224_RSA_PKCS_PSS, + Sha512224 = CKM_SHA512_224, + Sha512224Hmac = CKM_SHA512_224_HMAC, + Sha512224HmacGeneral = CKM_SHA512_224_HMAC_GENERAL, + Sha512224KeyDerivation = CKM_SHA512_224_KEY_DERIVATION, + Sha512256 = CKM_SHA512_256, + Sha512256Hmac = CKM_SHA512_256_HMAC, + Sha512256HmacGeneral = CKM_SHA512_256_HMAC_GENERAL, + Sha512256KeyDerivation = CKM_SHA512_256_KEY_DERIVATION, + Sha512T = CKM_SHA512_T, + Sha512THmac = CKM_SHA512_T_HMAC, + Sha512THmacGeneral = CKM_SHA512_T_HMAC_GENERAL, + Sha512TKeyDerivation = CKM_SHA512_T_KEY_DERIVATION, + Rc2KeyGen = CKM_RC2_KEY_GEN, + Rc2Ecb = CKM_RC2_ECB, + Rc2Cbc = CKM_RC2_CBC, + Rc2Mac = CKM_RC2_MAC, + Rc2MacGeneral = CKM_RC2_MAC_GENERAL, + Rc2CbcPad = CKM_RC2_CBC_PAD, + Rc4KeyGen = CKM_RC4_KEY_GEN, + Rc4 = CKM_RC4, + DesKeyGen = CKM_DES_KEY_GEN, + DesEcb = CKM_DES_ECB, + DesCbc = CKM_DES_CBC, + DesMac = CKM_DES_MAC, + DesMacGeneral = CKM_DES_MAC_GENERAL, + DesCbcPad = CKM_DES_CBC_PAD, + Des2KeyGen = CKM_DES2_KEY_GEN, + Des3KeyGen = CKM_DES3_KEY_GEN, + Des3Ecb = CKM_DES3_ECB, + Des3Cbc = CKM_DES3_CBC, + Des3Mac = CKM_DES3_MAC, + Des3MacGeneral = CKM_DES3_MAC_GENERAL, + Des3CbcPad = CKM_DES3_CBC_PAD, + Des3CmacGeneral = CKM_DES3_CMAC_GENERAL, + Des3Cmac = CKM_DES3_CMAC, + CdmfKeyGen = CKM_CDMF_KEY_GEN, + CdmfEcb = CKM_CDMF_ECB, + CdmfCbc = CKM_CDMF_CBC, + CdmfMac = CKM_CDMF_MAC, + CdmfMacGeneral = CKM_CDMF_MAC_GENERAL, + CdmfCbcPad = CKM_CDMF_CBC_PAD, + DesOfb64 = CKM_DES_OFB64, + DesOfb8 = CKM_DES_OFB8, + DesCfb64 = CKM_DES_CFB64, + DesCfb8 = CKM_DES_CFB8, + Md2 = CKM_MD2, + Md2Hmac = CKM_MD2_HMAC, + Md2HmacGeneral = CKM_MD2_HMAC_GENERAL, + Md5 = CKM_MD5, + Md5Hmac = CKM_MD5_HMAC, + Md5HmacGeneral = CKM_MD5_HMAC_GENERAL, + Sha1 = CKM_SHA_1, + Sha1Hmac = CKM_SHA_1_HMAC, + Sha1HmacGeneral = CKM_SHA_1_HMAC_GENERAL, + Ripemd128 = CKM_RIPEMD128, + Ripemd128Hmac = CKM_RIPEMD128_HMAC, + Ripemd128HmacGeneral = CKM_RIPEMD128_HMAC_GENERAL, + Ripemd160 = CKM_RIPEMD160, + Ripemd160Hmac = CKM_RIPEMD160_HMAC, + Ripemd160HmacGeneral = CKM_RIPEMD160_HMAC_GENERAL, + Sha256 = CKM_SHA256, + Sha256Hmac = CKM_SHA256_HMAC, + Sha256HmacGeneral = CKM_SHA256_HMAC_GENERAL, + Sha224 = CKM_SHA224, + Sha224Hmac = CKM_SHA224_HMAC, + Sha224HmacGeneral = CKM_SHA224_HMAC_GENERAL, + Sha384 = CKM_SHA384, + Sha384Hmac = CKM_SHA384_HMAC, + Sha384HmacGeneral = CKM_SHA384_HMAC_GENERAL, + Sha512 = CKM_SHA512, + Sha512Hmac = CKM_SHA512_HMAC, + Sha512HmacGeneral = CKM_SHA512_HMAC_GENERAL, + SecuridKeyGen = CKM_SECURID_KEY_GEN, + Securid = CKM_SECURID, + HotpKeyGen = CKM_HOTP_KEY_GEN, + Hotp = CKM_HOTP, + Acti = CKM_ACTI, + ActiKeyGen = CKM_ACTI_KEY_GEN, + CastKeyGen = CKM_CAST_KEY_GEN, + CastEcb = CKM_CAST_ECB, + CastCbc = CKM_CAST_CBC, + CastMac = CKM_CAST_MAC, + CastMacGeneral = CKM_CAST_MAC_GENERAL, + CastCbcPad = CKM_CAST_CBC_PAD, + Cast3KeyGen = CKM_CAST3_KEY_GEN, + Cast3Ecb = CKM_CAST3_ECB, + Cast3Cbc = CKM_CAST3_CBC, + Cast3Mac = CKM_CAST3_MAC, + Cast3MacGeneral = CKM_CAST3_MAC_GENERAL, + Cast3CbcPad = CKM_CAST3_CBC_PAD, + Cast5KeyGen = CKM_CAST5_KEY_GEN, + Cast128KeyGen = CKM_CAST128_KEY_GEN, + Cast5Ecb = CKM_CAST5_ECB, + Cast128Ecb = CKM_CAST128_ECB, + Cast5Cbc = CKM_CAST5_CBC, + Cast128Cbc = CKM_CAST128_CBC, + Cast5Mac = CKM_CAST5_MAC, + Cast128Mac = CKM_CAST128_MAC, + Cast5MacGeneral = CKM_CAST5_MAC_GENERAL, + Cast128MacGeneral = CKM_CAST128_MAC_GENERAL, + Cast5CbcPad = CKM_CAST5_CBC_PAD, + Cast128CbcPad = CKM_CAST128_CBC_PAD, + Rc5KeyGen = CKM_RC5_KEY_GEN, + Rc5Ecb = CKM_RC5_ECB, + Rc5Cbc = CKM_RC5_CBC, + Rc5Mac = CKM_RC5_MAC, + Rc5MacGeneral = CKM_RC5_MAC_GENERAL, + Rc5CbcPad = CKM_RC5_CBC_PAD, + IdeaKeyGen = CKM_IDEA_KEY_GEN, + IdeaEcb = CKM_IDEA_ECB, + IdeaCbc = CKM_IDEA_CBC, + IdeaMac = CKM_IDEA_MAC, + IdeaMacGeneral = CKM_IDEA_MAC_GENERAL, + IdeaCbcPad = CKM_IDEA_CBC_PAD, + GenericSecretKeyGen = CKM_GENERIC_SECRET_KEY_GEN, + ConcatenateBaseAndKey = CKM_CONCATENATE_BASE_AND_KEY, + ConcatenateBaseAndData = CKM_CONCATENATE_BASE_AND_DATA, + ConcatenateDataAndBase = CKM_CONCATENATE_DATA_AND_BASE, + XorBaseAndData = CKM_XOR_BASE_AND_DATA, + ExtractKeyFromKey = CKM_EXTRACT_KEY_FROM_KEY, + Ssl3PreMasterKeyGen = CKM_SSL3_PRE_MASTER_KEY_GEN, + Ssl3MasterKeyDerive = CKM_SSL3_MASTER_KEY_DERIVE, + Ssl3KeyAndMacDerive = CKM_SSL3_KEY_AND_MAC_DERIVE, + Ssl3MasterKeyDeriveDh = CKM_SSL3_MASTER_KEY_DERIVE_DH, + TlsPreMasterKeyGen = CKM_TLS_PRE_MASTER_KEY_GEN, + TlsMasterKeyDerive = CKM_TLS_MASTER_KEY_DERIVE, + TlsKeyAndMacDerive = CKM_TLS_KEY_AND_MAC_DERIVE, + TlsMasterKeyDeriveDh = CKM_TLS_MASTER_KEY_DERIVE_DH, + TlsPrf = CKM_TLS_PRF, + Ssl3Md5Mac = CKM_SSL3_MD5_MAC, + Ssl3Sha1Mac = CKM_SSL3_SHA1_MAC, + Md5KeyDerivation = CKM_MD5_KEY_DERIVATION, + Md2KeyDerivation = CKM_MD2_KEY_DERIVATION, + Sha1KeyDerivation = CKM_SHA1_KEY_DERIVATION, + Sha256KeyDerivation = CKM_SHA256_KEY_DERIVATION, + Sha384KeyDerivation = CKM_SHA384_KEY_DERIVATION, + Sha512KeyDerivation = CKM_SHA512_KEY_DERIVATION, + Sha224KeyDerivation = CKM_SHA224_KEY_DERIVATION, + PbeMd2DesCbc = CKM_PBE_MD2_DES_CBC, + PbeMd5DesCbc = CKM_PBE_MD5_DES_CBC, + PbeMd5CastCbc = CKM_PBE_MD5_CAST_CBC, + PbeMd5Cast3Cbc = CKM_PBE_MD5_CAST3_CBC, + PbeMd5Cast5Cbc = CKM_PBE_MD5_CAST5_CBC, + PbeMd5Cast128Cbc = CKM_PBE_MD5_CAST128_CBC, + PbeSha1Cast5Cbc = CKM_PBE_SHA1_CAST5_CBC, + PbeSha1Cast128Cbc = CKM_PBE_SHA1_CAST128_CBC, + PbeSha1Rc4128 = CKM_PBE_SHA1_RC4_128, + PbeSha1Rc440 = CKM_PBE_SHA1_RC4_40, + PbeSha1Des3EdeCbc = CKM_PBE_SHA1_DES3_EDE_CBC, + PbeSha1Des2EdeCbc = CKM_PBE_SHA1_DES2_EDE_CBC, + PbeSha1Rc2128Cbc = CKM_PBE_SHA1_RC2_128_CBC, + PbeSha1Rc240Cbc = CKM_PBE_SHA1_RC2_40_CBC, + Pkcs5Pbkd2 = CKM_PKCS5_PBKD2, + PbaSha1WithSha1Hmac = CKM_PBA_SHA1_WITH_SHA1_HMAC, + WtlsPreMasterKeyGen = CKM_WTLS_PRE_MASTER_KEY_GEN, + WtlsMasterKeyDerive = CKM_WTLS_MASTER_KEY_DERIVE, + WtlsMasterKeyDeriveDhEcc = CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC, + WtlsPrf = CKM_WTLS_PRF, + WtlsServerKeyAndMacDerive = CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE, + WtlsClientKeyAndMacDerive = CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE, + Tls10MacServer = CKM_TLS10_MAC_SERVER, + Tls10MacClient = CKM_TLS10_MAC_CLIENT, + Tls12Mac = CKM_TLS12_MAC, + Tls12Kdf = CKM_TLS12_KDF, + Tls12MasterKeyDerive = CKM_TLS12_MASTER_KEY_DERIVE, + Tls12KeyAndMacDerive = CKM_TLS12_KEY_AND_MAC_DERIVE, + Tls12MasterKeyDeriveDh = CKM_TLS12_MASTER_KEY_DERIVE_DH, + Tls12KeySafeDerive = CKM_TLS12_KEY_SAFE_DERIVE, + TlsMac = CKM_TLS_MAC, + TlsKdf = CKM_TLS_KDF, + KeyWrapLynks = CKM_KEY_WRAP_LYNKS, + KeyWrapSetOaep = CKM_KEY_WRAP_SET_OAEP, + CmsSig = CKM_CMS_SIG, + KipDerive = CKM_KIP_DERIVE, + KipWrap = CKM_KIP_WRAP, + KipMac = CKM_KIP_MAC, + CamelliaKeyGen = CKM_CAMELLIA_KEY_GEN, + CamelliaEcb = CKM_CAMELLIA_ECB, + CamelliaCbc = CKM_CAMELLIA_CBC, + CamelliaMac = CKM_CAMELLIA_MAC, + CamelliaMacGeneral = CKM_CAMELLIA_MAC_GENERAL, + CamelliaCbcPad = CKM_CAMELLIA_CBC_PAD, + CamelliaEcbEncryptData = CKM_CAMELLIA_ECB_ENCRYPT_DATA, + CamelliaCbcEncryptData = CKM_CAMELLIA_CBC_ENCRYPT_DATA, + CamelliaCtr = CKM_CAMELLIA_CTR, + AriaKeyGen = CKM_ARIA_KEY_GEN, + AriaEcb = CKM_ARIA_ECB, + AriaCbc = CKM_ARIA_CBC, + AriaMac = CKM_ARIA_MAC, + AriaMacGeneral = CKM_ARIA_MAC_GENERAL, + AriaCbcPad = CKM_ARIA_CBC_PAD, + AriaEcbEncryptData = CKM_ARIA_ECB_ENCRYPT_DATA, + AriaCbcEncryptData = CKM_ARIA_CBC_ENCRYPT_DATA, + SeedKeyGen = CKM_SEED_KEY_GEN, + SeedEcb = CKM_SEED_ECB, + SeedCbc = CKM_SEED_CBC, + SeedMac = CKM_SEED_MAC, + SeedMacGeneral = CKM_SEED_MAC_GENERAL, + SeedCbcPad = CKM_SEED_CBC_PAD, + SeedEcbEncryptData = CKM_SEED_ECB_ENCRYPT_DATA, + SeedCbcEncryptData = CKM_SEED_CBC_ENCRYPT_DATA, + SkipjackKeyGen = CKM_SKIPJACK_KEY_GEN, + SkipjackEcb64 = CKM_SKIPJACK_ECB64, + SkipjackCbc64 = CKM_SKIPJACK_CBC64, + SkipjackOfb64 = CKM_SKIPJACK_OFB64, + SkipjackCfb64 = CKM_SKIPJACK_CFB64, + SkipjackCfb32 = CKM_SKIPJACK_CFB32, + SkipjackCfb16 = CKM_SKIPJACK_CFB16, + SkipjackCfb8 = CKM_SKIPJACK_CFB8, + SkipjackWrap = CKM_SKIPJACK_WRAP, + SkipjackPrivateWrap = CKM_SKIPJACK_PRIVATE_WRAP, + SkipjackRelayx = CKM_SKIPJACK_RELAYX, + KeaKeyPairGen = CKM_KEA_KEY_PAIR_GEN, + KeaKeyDerive = CKM_KEA_KEY_DERIVE, + KeaDerive = CKM_KEA_DERIVE, + FortezzaTimestamp = CKM_FORTEZZA_TIMESTAMP, + BatonKeyGen = CKM_BATON_KEY_GEN, + BatonEcb128 = CKM_BATON_ECB128, + BatonEcb96 = CKM_BATON_ECB96, + BatonCbc128 = CKM_BATON_CBC128, + BatonCounter = CKM_BATON_COUNTER, + BatonShuffle = CKM_BATON_SHUFFLE, + BatonWrap = CKM_BATON_WRAP, + EcdsaKeyPairGen = CKM_ECDSA_KEY_PAIR_GEN, + EcKeyPairGen = CKM_EC_KEY_PAIR_GEN, + Ecdsa = CKM_ECDSA, + EcdsaSha1 = CKM_ECDSA_SHA1, + EcdsaSha224 = CKM_ECDSA_SHA224, + EcdsaSha256 = CKM_ECDSA_SHA256, + EcdsaSha384 = CKM_ECDSA_SHA384, + EcdsaSha512 = CKM_ECDSA_SHA512, + Ecdh1Derive = CKM_ECDH1_DERIVE, + Ecdh1CofactorDerive = CKM_ECDH1_COFACTOR_DERIVE, + EcmqvDerive = CKM_ECMQV_DERIVE, + EcdhAesKeyWrap = CKM_ECDH_AES_KEY_WRAP, + RsaAesKeyWrap = CKM_RSA_AES_KEY_WRAP, + JuniperKeyGen = CKM_JUNIPER_KEY_GEN, + JuniperEcb128 = CKM_JUNIPER_ECB128, + JuniperCbc128 = CKM_JUNIPER_CBC128, + JuniperCounter = CKM_JUNIPER_COUNTER, + JuniperShuffle = CKM_JUNIPER_SHUFFLE, + JuniperWrap = CKM_JUNIPER_WRAP, + Fasthash = CKM_FASTHASH, + AesKeyGen = CKM_AES_KEY_GEN, + AesEcb = CKM_AES_ECB, + AesCbc = CKM_AES_CBC, + AesMac = CKM_AES_MAC, + AesMacGeneral = CKM_AES_MAC_GENERAL, + AesCbcPad = CKM_AES_CBC_PAD, + AesCtr = CKM_AES_CTR, + AesGcm = CKM_AES_GCM, + AesCcm = CKM_AES_CCM, + AesCts = CKM_AES_CTS, + AesCmac = CKM_AES_CMAC, + AesCmacGeneral = CKM_AES_CMAC_GENERAL, + AesXcbcMac = CKM_AES_XCBC_MAC, + AesXcbcMac96 = CKM_AES_XCBC_MAC_96, + AesGmac = CKM_AES_GMAC, + BlowfishKeyGen = CKM_BLOWFISH_KEY_GEN, + BlowfishCbc = CKM_BLOWFISH_CBC, + TwofishKeyGen = CKM_TWOFISH_KEY_GEN, + TwofishCbc = CKM_TWOFISH_CBC, + BlowfishCbcPad = CKM_BLOWFISH_CBC_PAD, + TwofishCbcPad = CKM_TWOFISH_CBC_PAD, + DesEcbEncryptData = CKM_DES_ECB_ENCRYPT_DATA, + DesCbcEncryptData = CKM_DES_CBC_ENCRYPT_DATA, + Des3EcbEncryptData = CKM_DES3_ECB_ENCRYPT_DATA, + Des3CbcEncryptData = CKM_DES3_CBC_ENCRYPT_DATA, + AesEcbEncryptData = CKM_AES_ECB_ENCRYPT_DATA, + AesCbcEncryptData = CKM_AES_CBC_ENCRYPT_DATA, + Gostr3410KeyPairGen = CKM_GOSTR3410_KEY_PAIR_GEN, + Gostr3410 = CKM_GOSTR3410, + Gostr3410WithGostr3411 = CKM_GOSTR3410_WITH_GOSTR3411, + Gostr3410KeyWrap = CKM_GOSTR3410_KEY_WRAP, + Gostr3410Derive = CKM_GOSTR3410_DERIVE, + Gostr3411 = CKM_GOSTR3411, + Gostr3411Hmac = CKM_GOSTR3411_HMAC, + Gost28147KeyGen = CKM_GOST28147_KEY_GEN, + Gost28147Ecb = CKM_GOST28147_ECB, + Gost28147 = CKM_GOST28147, + Gost28147Mac = CKM_GOST28147_MAC, + Gost28147KeyWrap = CKM_GOST28147_KEY_WRAP, + DsaParameterGen = CKM_DSA_PARAMETER_GEN, + DhPkcsParameterGen = CKM_DH_PKCS_PARAMETER_GEN, + X942DhParameterGen = CKM_X9_42_DH_PARAMETER_GEN, + DsaProbablisticParameterGen = CKM_DSA_PROBABLISTIC_PARAMETER_GEN, + DsaShaweTaylorParameterGen = CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN, + AesOfb = CKM_AES_OFB, + AesCfb64 = CKM_AES_CFB64, + AesCfb8 = CKM_AES_CFB8, + AesCfb128 = CKM_AES_CFB128, + AesCfb1 = CKM_AES_CFB1, + AesKeyWrap = CKM_AES_KEY_WRAP, + AesKeyWrapPad = CKM_AES_KEY_WRAP_PAD, + RsaPkcsTpm11 = CKM_RSA_PKCS_TPM_1_1, + RsaPkcsOaepTpm11 = CKM_RSA_PKCS_OAEP_TPM_1_1, + VendorDefined = CKM_VENDOR_DEFINED, + }; + +enum class Notification : CK_NOTIFICATION + { + Surrender = CKN_SURRENDER, + OtpChanged = CKN_OTP_CHANGED, + }; + +enum class ObjectClass : CK_OBJECT_CLASS + { + Data = CKO_DATA, + Certificate = CKO_CERTIFICATE, + PublicKey = CKO_PUBLIC_KEY, + PrivateKey = CKO_PRIVATE_KEY, + SecretKey = CKO_SECRET_KEY, + HwFeature = CKO_HW_FEATURE, + DomainParameters = CKO_DOMAIN_PARAMETERS, + Mechanism = CKO_MECHANISM, + OtpKey = CKO_OTP_KEY, + VendorDefined = CKO_VENDOR_DEFINED, + }; + +enum class PseudoRandom : CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE + { + Pkcs5Pbkd2HmacSha1 = CKP_PKCS5_PBKD2_HMAC_SHA1, + Pkcs5Pbkd2HmacGostr3411 = CKP_PKCS5_PBKD2_HMAC_GOSTR3411, + Pkcs5Pbkd2HmacSha224 = CKP_PKCS5_PBKD2_HMAC_SHA224, + Pkcs5Pbkd2HmacSha256 = CKP_PKCS5_PBKD2_HMAC_SHA256, + Pkcs5Pbkd2HmacSha384 = CKP_PKCS5_PBKD2_HMAC_SHA384, + Pkcs5Pbkd2HmacSha512 = CKP_PKCS5_PBKD2_HMAC_SHA512, + Pkcs5Pbkd2HmacSha512224 = CKP_PKCS5_PBKD2_HMAC_SHA512_224, + Pkcs5Pbkd2HmacSha512256 = CKP_PKCS5_PBKD2_HMAC_SHA512_256, + }; + +enum class SessionState : CK_STATE + { + RoPublicSession = CKS_RO_PUBLIC_SESSION, + RoUserFunctions = CKS_RO_USER_FUNCTIONS, + RwPublicSession = CKS_RW_PUBLIC_SESSION, + RwUserFunctions = CKS_RW_USER_FUNCTIONS, + RwSoFunctions = CKS_RW_SO_FUNCTIONS, + }; + +enum class ReturnValue : CK_RV + { + OK = CKR_OK, + Cancel = CKR_CANCEL, + HostMemory = CKR_HOST_MEMORY, + SlotIdInvalid = CKR_SLOT_ID_INVALID, + GeneralError = CKR_GENERAL_ERROR, + FunctionFailed = CKR_FUNCTION_FAILED, + ArgumentsBad = CKR_ARGUMENTS_BAD, + NoEvent = CKR_NO_EVENT, + NeedToCreateThreads = CKR_NEED_TO_CREATE_THREADS, + CantLock = CKR_CANT_LOCK, + AttributeReadOnly = CKR_ATTRIBUTE_READ_ONLY, + AttributeSensitive = CKR_ATTRIBUTE_SENSITIVE, + AttributeTypeInvalid = CKR_ATTRIBUTE_TYPE_INVALID, + AttributeValueInvalid = CKR_ATTRIBUTE_VALUE_INVALID, + ActionProhibited = CKR_ACTION_PROHIBITED, + DataInvalid = CKR_DATA_INVALID, + DataLenRange = CKR_DATA_LEN_RANGE, + DeviceError = CKR_DEVICE_ERROR, + DeviceMemory = CKR_DEVICE_MEMORY, + DeviceRemoved = CKR_DEVICE_REMOVED, + EncryptedDataInvalid = CKR_ENCRYPTED_DATA_INVALID, + EncryptedDataLenRange = CKR_ENCRYPTED_DATA_LEN_RANGE, + FunctionCanceled = CKR_FUNCTION_CANCELED, + FunctionNotParallel = CKR_FUNCTION_NOT_PARALLEL, + FunctionNotSupported = CKR_FUNCTION_NOT_SUPPORTED, + KeyHandleInvalid = CKR_KEY_HANDLE_INVALID, + KeySizeRange = CKR_KEY_SIZE_RANGE, + KeyTypeInconsistent = CKR_KEY_TYPE_INCONSISTENT, + KeyNotNeeded = CKR_KEY_NOT_NEEDED, + KeyChanged = CKR_KEY_CHANGED, + KeyNeeded = CKR_KEY_NEEDED, + KeyIndigestible = CKR_KEY_INDIGESTIBLE, + KeyFunctionNotPermitted = CKR_KEY_FUNCTION_NOT_PERMITTED, + KeyNotWrappable = CKR_KEY_NOT_WRAPPABLE, + KeyUnextractable = CKR_KEY_UNEXTRACTABLE, + MechanismInvalid = CKR_MECHANISM_INVALID, + MechanismParamInvalid = CKR_MECHANISM_PARAM_INVALID, + ObjectHandleInvalid = CKR_OBJECT_HANDLE_INVALID, + OperationActive = CKR_OPERATION_ACTIVE, + OperationNotInitialized = CKR_OPERATION_NOT_INITIALIZED, + PinIncorrect = CKR_PIN_INCORRECT, + PinInvalid = CKR_PIN_INVALID, + PinLenRange = CKR_PIN_LEN_RANGE, + PinExpired = CKR_PIN_EXPIRED, + PinLocked = CKR_PIN_LOCKED, + SessionClosed = CKR_SESSION_CLOSED, + SessionCount = CKR_SESSION_COUNT, + SessionHandleInvalid = CKR_SESSION_HANDLE_INVALID, + SessionParallelNotSupported = CKR_SESSION_PARALLEL_NOT_SUPPORTED, + SessionReadOnly = CKR_SESSION_READ_ONLY, + SessionExists = CKR_SESSION_EXISTS, + SessionReadOnlyExists = CKR_SESSION_READ_ONLY_EXISTS, + SessionReadWriteSoExists = CKR_SESSION_READ_WRITE_SO_EXISTS, + SignatureInvalid = CKR_SIGNATURE_INVALID, + SignatureLenRange = CKR_SIGNATURE_LEN_RANGE, + TemplateIncomplete = CKR_TEMPLATE_INCOMPLETE, + TemplateInconsistent = CKR_TEMPLATE_INCONSISTENT, + TokenNotPresent = CKR_TOKEN_NOT_PRESENT, + TokenNotRecognized = CKR_TOKEN_NOT_RECOGNIZED, + TokenWriteProtected = CKR_TOKEN_WRITE_PROTECTED, + UnwrappingKeyHandleInvalid = CKR_UNWRAPPING_KEY_HANDLE_INVALID, + UnwrappingKeySizeRange = CKR_UNWRAPPING_KEY_SIZE_RANGE, + UnwrappingKeyTypeInconsistent = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, + UserAlreadyLoggedIn = CKR_USER_ALREADY_LOGGED_IN, + UserNotLoggedIn = CKR_USER_NOT_LOGGED_IN, + UserPinNotInitialized = CKR_USER_PIN_NOT_INITIALIZED, + UserTypeInvalid = CKR_USER_TYPE_INVALID, + UserAnotherAlreadyLoggedIn = CKR_USER_ANOTHER_ALREADY_LOGGED_IN, + UserTooManyTypes = CKR_USER_TOO_MANY_TYPES, + WrappedKeyInvalid = CKR_WRAPPED_KEY_INVALID, + WrappedKeyLenRange = CKR_WRAPPED_KEY_LEN_RANGE, + WrappingKeyHandleInvalid = CKR_WRAPPING_KEY_HANDLE_INVALID, + WrappingKeySizeRange = CKR_WRAPPING_KEY_SIZE_RANGE, + WrappingKeyTypeInconsistent = CKR_WRAPPING_KEY_TYPE_INCONSISTENT, + RandomSeedNotSupported = CKR_RANDOM_SEED_NOT_SUPPORTED, + RandomNoRng = CKR_RANDOM_NO_RNG, + DomainParamsInvalid = CKR_DOMAIN_PARAMS_INVALID, + CurveNotSupported = CKR_CURVE_NOT_SUPPORTED, + BufferTooSmall = CKR_BUFFER_TOO_SMALL, + SavedStateInvalid = CKR_SAVED_STATE_INVALID, + InformationSensitive = CKR_INFORMATION_SENSITIVE, + StateUnsaveable = CKR_STATE_UNSAVEABLE, + CryptokiNotInitialized = CKR_CRYPTOKI_NOT_INITIALIZED, + CryptokiAlreadyInitialized = CKR_CRYPTOKI_ALREADY_INITIALIZED, + MutexBad = CKR_MUTEX_BAD, + MutexNotLocked = CKR_MUTEX_NOT_LOCKED, + NewPinMode = CKR_NEW_PIN_MODE, + NextOtp = CKR_NEXT_OTP, + ExceededMaxIterations = CKR_EXCEEDED_MAX_ITERATIONS, + FipsSelfTestFailed = CKR_FIPS_SELF_TEST_FAILED, + LibraryLoadFailed = CKR_LIBRARY_LOAD_FAILED, + PinTooWeak = CKR_PIN_TOO_WEAK, + PublicKeyInvalid = CKR_PUBLIC_KEY_INVALID, + FunctionRejected = CKR_FUNCTION_REJECTED, + VendorDefined = CKR_VENDOR_DEFINED, + }; + +enum class UserType : CK_USER_TYPE + { + SO = CKU_SO, + User = CKU_USER, + ContextSpecific = CKU_CONTEXT_SPECIFIC, + }; + +enum class PublicPointEncoding : uint32_t + { + Raw, + Der + }; + +using FunctionListPtr = CK_FUNCTION_LIST_PTR; +using VoidPtr = CK_VOID_PTR; +using C_InitializeArgs = CK_C_INITIALIZE_ARGS; +using CreateMutex = CK_CREATEMUTEX; +using DestroyMutex = CK_DESTROYMUTEX; +using LockMutex = CK_LOCKMUTEX; +using UnlockMutex = CK_UNLOCKMUTEX; +using Flags = CK_FLAGS; +using Info = CK_INFO; +using Bbool = CK_BBOOL; +using SlotId = CK_SLOT_ID; +using Ulong = CK_ULONG; +using SlotInfo = CK_SLOT_INFO; +using TokenInfo = CK_TOKEN_INFO; +using Mechanism = CK_MECHANISM; +using MechanismInfo = CK_MECHANISM_INFO; +using Utf8Char = CK_UTF8CHAR; +using Notify = CK_NOTIFY; +using SessionHandle = CK_SESSION_HANDLE; +using SessionInfo = CK_SESSION_INFO; +using Attribute = CK_ATTRIBUTE; +using ObjectHandle = CK_OBJECT_HANDLE; +using Byte = CK_BYTE; +using RsaPkcsOaepParams = CK_RSA_PKCS_OAEP_PARAMS; +using RsaPkcsPssParams = CK_RSA_PKCS_PSS_PARAMS; +using Ecdh1DeriveParams = CK_ECDH1_DERIVE_PARAMS; +using Date = CK_DATE; + +BOTAN_PUBLIC_API(2,0) extern ReturnValue* ThrowException; + +const Bbool True = CK_TRUE; +const Bbool False = CK_FALSE; + +inline Flags flags(Flag flags) + { + return static_cast(flags); + } + +class Slot; + +/** +* Initializes a token +* @param slot The slot with the attached token that should be initialized +* @param label The token label +* @param so_pin PIN of the security officer. Will be set if the token is uninitialized other this has to be the current SO_PIN +* @param pin The user PIN that will be set +*/ +BOTAN_PUBLIC_API(2,0) void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, + const secure_string& pin); + +/** +* Change PIN with old PIN to new PIN +* @param slot The slot with the attached token +* @param old_pin The old user PIN +* @param new_pin The new user PIN +*/ + +BOTAN_PUBLIC_API(2,0) void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin); + +/** +* Change SO_PIN with old SO_PIN to new SO_PIN +* @param slot The slot with the attached token +* @param old_so_pin The old SO_PIN +* @param new_so_pin The new SO_PIN +*/ +BOTAN_PUBLIC_API(2,0) void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin); + +/** +* Sets user PIN with SO_PIN +* @param slot The slot with the attached token +* @param so_pin PIN of the security officer +* @param pin The user PIN that should be set +*/ +BOTAN_PUBLIC_API(2,0) void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin); + +/// Provides access to all PKCS#11 functions +class BOTAN_PUBLIC_API(2,0) LowLevel + { + public: + /// @param ptr the functon list pointer to use. Can be retrieved via `LowLevel::C_GetFunctionList` + explicit LowLevel(FunctionListPtr ptr); + + /****************************** General purpose functions ******************************/ + + /** + * C_Initialize initializes the Cryptoki library. + * @param init_args if this is not nullptr, it gets cast to (`C_InitializeArgs`) and dereferenced + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CantLock \li CryptokiAlreadyInitialized + * \li FunctionFailed \li GeneralError \li HostMemory + * \li NeedToCreateThreads \li OK + * @return true on success, false otherwise + */ + bool C_Initialize(VoidPtr init_args, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Finalize indicates that an application is done with the Cryptoki library. + * @param reserved reserved. Should be nullptr + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * @return true on success, false otherwise + */ + bool C_Finalize(VoidPtr reserved, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetInfo returns general information about Cryptoki. + * @param info_ptr location that receives information + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * @return true on success, false otherwise + */ + bool C_GetInfo(Info* info_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetFunctionList returns the function list. + * @param pkcs11_module The PKCS#11 module + * @param function_list_ptr_ptr receives pointer to function list + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li FunctionFailed \li GeneralError + * \li HostMemory \li OK + * @return true on success, false otherwise + */ + static bool C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr, + ReturnValue* return_value = ThrowException); + + /****************************** Slot and token management functions ******************************/ + + /** + * C_GetSlotList obtains a list of slots in the system. + * @param token_present only slots with tokens + * @param slot_list_ptr receives array of slot IDs + * @param count_ptr receives number of slots + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK + * @return true on success, false otherwise + */ + bool C_GetSlotList(Bbool token_present, + SlotId* slot_list_ptr, + Ulong* count_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetSlotList obtains a list of slots in the system. + * @param token_present only slots with tokens + * @param slot_ids receives vector of slot IDs + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK + * @return true on success, false otherwise + */ + bool C_GetSlotList(bool token_present, + std::vector& slot_ids, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetSlotInfo obtains information about a particular slot in the system. + * @param slot_id the ID of the slot + * @param info_ptr receives the slot information + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li SlotIdInvalid + * @return true on success, false otherwise + */ + bool C_GetSlotInfo(SlotId slot_id, + SlotInfo* info_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetTokenInfo obtains information about a particular token in the system. + * @param slot_id ID of the token's slot + * @param info_ptr receives the token information + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li SlotIdInvalid + * \li TokenNotPresent \li TokenNotRecognized \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_GetTokenInfo(SlotId slot_id, + TokenInfo* info_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_WaitForSlotEvent waits for a slot event (token insertion, removal, etc.) to occur. + * @param flags blocking/nonblocking flag + * @param slot_ptr location that receives the slot ID + * @param reserved reserved. Should be NULL_PTR + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed + * \li GeneralError \li HostMemory \li NoEvent + * \li OK + * @return true on success, false otherwise + */ + bool C_WaitForSlotEvent(Flags flags, + SlotId* slot_ptr, + VoidPtr reserved, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetMechanismList obtains a list of mechanism types supported by a token. + * @param slot_id ID of token's slot + * @param mechanism_list_ptr gets mech. array + * @param count_ptr gets # of mechs. + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized + * \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_GetMechanismList(SlotId slot_id, + MechanismType* mechanism_list_ptr, + Ulong* count_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetMechanismList obtains a list of mechanism types supported by a token. + * @param slot_id ID of token's slot + * @param mechanisms receives vector of supported mechanisms + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized + * \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_GetMechanismList(SlotId slot_id, + std::vector& mechanisms, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetMechanismInfo obtains information about a particular mechanism possibly supported by a token. + * @param slot_id ID of the token's slot + * @param type type of mechanism + * @param info_ptr receives mechanism info + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li MechanismInvalid \li OK + * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized + * \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_GetMechanismInfo(SlotId slot_id, + MechanismType type, + MechanismInfo* info_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_InitToken initializes a token. + * @param slot_id ID of the token's slot + * @param so_pin_ptr the SO's initial PIN + * @param so_pin_len length in bytes of the SO_PIN + * @param label_ptr 32-byte token label (blank padded) + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li PinIncorrect \li PinLocked \li SessionExists + * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized + * \li TokenWriteProtected \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_InitToken(SlotId slot_id, + Utf8Char* so_pin_ptr, + Ulong so_pin_len, + Utf8Char* label_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_InitToken initializes a token. + * @param slot_id ID of the token's slot + * @param so_pin the SO's initial PIN + * @param label token label (at max 32 bytes long) + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li PinIncorrect \li PinLocked \li SessionExists + * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized + * \li TokenWriteProtected \li ArgumentsBad + * @return true on success, false otherwise + */ + template + bool C_InitToken(SlotId slot_id, + const std::vector& so_pin, + const std::string& label, + ReturnValue* return_value = ThrowException) const + { + std::string padded_label = label; + if(label.size() < 32) + { + padded_label.insert(padded_label.end(), 32 - label.size(), ' '); + } + + return C_InitToken(slot_id, + reinterpret_cast< Utf8Char* >(const_cast< uint8_t* >(so_pin.data())), + static_cast(so_pin.size()), + reinterpret_cast< Utf8Char* >(const_cast< char* >(padded_label.c_str())), + return_value); + } + + /** + * C_InitPIN initializes the normal user's PIN. + * @param session the session's handle + * @param pin_ptr the normal user's PIN + * @param pin_len length in bytes of the PIN + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li PinInvalid \li PinLenRange \li SessionClosed + * \li SessionReadOnly \li SessionHandleInvalid \li TokenWriteProtected + * \li UserNotLoggedIn \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_InitPIN(SessionHandle session, + Utf8Char* pin_ptr, + Ulong pin_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_InitPIN initializes the normal user's PIN. + * @param session the session's handle + * @param pin the normal user's PIN + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li PinInvalid \li PinLenRange \li SessionClosed + * \li SessionReadOnly \li SessionHandleInvalid \li TokenWriteProtected + * \li UserNotLoggedIn \li ArgumentsBad + * @return true on success, false otherwise + */ + template + bool C_InitPIN(SessionHandle session, + const std::vector& pin, + ReturnValue* return_value = ThrowException) const + { + return C_InitPIN(session, + reinterpret_cast< Utf8Char* >(const_cast< uint8_t* >(pin.data())), + static_cast(pin.size()), + return_value); + } + + /** + * C_SetPIN modifies the PIN of the user who is logged in. + * @param session the session's handle + * @param old_pin_ptr the old PIN + * @param old_len length of the old PIN + * @param new_pin_ptr the new PIN + * @param new_len length of the new PIN + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li PinIncorrect \li PinInvalid \li PinLenRange + * \li PinLocked \li SessionClosed \li SessionHandleInvalid + * \li SessionReadOnly \li TokenWriteProtected \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_SetPIN(SessionHandle session, + Utf8Char* old_pin_ptr, + Ulong old_len, + Utf8Char* new_pin_ptr, + Ulong new_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SetPIN modifies the PIN of the user who is logged in. + * @param session the session's handle + * @param old_pin the old PIN + * @param new_pin the new PIN + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li PinIncorrect \li PinInvalid \li PinLenRange + * \li PinLocked \li SessionClosed \li SessionHandleInvalid + * \li SessionReadOnly \li TokenWriteProtected \li ArgumentsBad + * @return true on success, false otherwise + */ + template + bool C_SetPIN(SessionHandle session, + const std::vector& old_pin, + const std::vector& new_pin, + ReturnValue* return_value = ThrowException) const + { + return C_SetPIN(session, + reinterpret_cast< Utf8Char* >(const_cast< uint8_t* >(old_pin.data())), + static_cast(old_pin.size()), + reinterpret_cast< Utf8Char* >(const_cast< uint8_t* >(new_pin.data())), + static_cast(new_pin.size()), + return_value); + } + + + /****************************** Session management ******************************/ + + /** + * C_OpenSession opens a session between an application and a token. + * @param slot_id the slot's ID + * @param flags from CK_SESSION_INFO + * @param application passed to callback + * @param notify callback function + * @param session_ptr gets session handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li SessionCount + * \li SessionParallelNotSupported \li SessionReadWriteSoExists \li SlotIdInvalid + * \li TokenNotPresent \li TokenNotRecognized \li TokenWriteProtected + * \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_OpenSession(SlotId slot_id, + Flags flags, + VoidPtr application, + Notify notify, + SessionHandle* session_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_CloseSession closes a session between an application and a token. + * @param session the session's handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li SessionClosed + * \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_CloseSession(SessionHandle session, + ReturnValue* return_value = ThrowException) const; + + /** + * C_CloseAllSessions closes all sessions with a token. + * @param slot_id the token's slot + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li SlotIdInvalid + * \li TokenNotPresent + * @return true on success, false otherwise + */ + bool C_CloseAllSessions(SlotId slot_id, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetSessionInfo obtains information about the session. + * @param session the session's handle + * @param info_ptr receives session info + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li SessionClosed + * \li SessionHandleInvalid \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_GetSessionInfo(SessionHandle session, + SessionInfo* info_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetOperationState obtains the state of the cryptographic operation in a session. + * @param session session's handle + * @param operation_state_ptr gets state + * @param operation_state_len_ptr gets state length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * \li StateUnsaveable \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_GetOperationState(SessionHandle session, + Byte* operation_state_ptr, + Ulong* operation_state_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SetOperationState restores the state of the cryptographic operation in a session. + * @param session session's handle + * @param operation_state_ptr holds state + * @param operation_state_len holds state length + * @param encryption_key en/decryption key + * @param authentication_key sign/verify key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li KeyChanged \li KeyNeeded + * \li KeyNotNeeded \li OK \li SavedStateInvalid + * \li SessionClosed \li SessionHandleInvalid \li ArgumentsBad + * @return true on success, false otherwise + */ + bool C_SetOperationState(SessionHandle session, + Byte* operation_state_ptr, + Ulong operation_state_len, + ObjectHandle encryption_key, + ObjectHandle authentication_key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Login logs a user into a token. + * @param session the session's handle + * @param user_type the user type + * @param pin_ptr the user's PIN + * @param pin_len the length of the PIN + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li PinIncorrect + * \li PinLocked \li SessionClosed \li SessionHandleInvalid + * \li SessionReadOnlyExists \li UserAlreadyLoggedIn \li UserAnotherAlreadyLoggedIn + * \li UserPinNotInitialized \li UserTooManyTypes \li UserTypeInvalid + * @return true on success, false otherwise + */ + bool C_Login(SessionHandle session, + UserType user_type, + Utf8Char* pin_ptr, + Ulong pin_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Login logs a user into a token. + * @param session the session's handle + * @param user_type the user type + * @param pin the user or security officer's PIN + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li PinIncorrect + * \li PinLocked \li SessionClosed \li SessionHandleInvalid + * \li SessionReadOnlyExists \li UserAlreadyLoggedIn \li UserAnotherAlreadyLoggedIn + * \li UserPinNotInitialized \li UserTooManyTypes \li UserTypeInvalid + * @return true on success, false otherwise + */ + template + bool C_Login(SessionHandle session, + UserType user_type, + const std::vector& pin, + ReturnValue* return_value = ThrowException) const + { + return C_Login(session, user_type, + reinterpret_cast< Utf8Char* >(const_cast< uint8_t* >(pin.data())), + static_cast(pin.size()), + return_value); + } + + /** + * C_Logout logs a user out from a token. + * @param session the session's handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_Logout(SessionHandle session, + ReturnValue* return_value = ThrowException) const; + + /****************************** Object management functions ******************************/ + + /** + * C_CreateObject creates a new object. + * @param session the session's handle + * @param attribute_template_ptr the object's template + * @param count attributes in template + * @param object_ptr gets new object's handle. + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid + * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li DomainParamsInvalid \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly + * \li TemplateIncomplete \li TemplateInconsistent \li TokenWriteProtected + * \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_CreateObject(SessionHandle session, + Attribute* attribute_template_ptr, + Ulong count, + ObjectHandle* object_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_CopyObject copies an object, creating a new object for the copy. + * @param session the session's handle + * @param object the object's handle + * @param attribute_template_ptr template for new object + * @param count attributes in template + * @param new_object_ptr receives handle of copy + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly + * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionFailed \li GeneralError \li HostMemory + * \li ObjectHandleInvalid \li OK \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly + * \li TemplateInconsistent \li TokenWriteProtected \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_CopyObject(SessionHandle session, + ObjectHandle object, + Attribute* attribute_template_ptr, + Ulong count, + ObjectHandle* new_object_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DestroyObject destroys an object. + * @param session the session's handle + * @param object the object's handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ActionProhibited \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li ObjectHandleInvalid + * \li OK \li PinExpired \li SessionClosed + * \li SessionHandleInvalid \li SessionReadOnly \li TokenWriteProtected + * @return true on success, false otherwise + */ + bool C_DestroyObject(SessionHandle session, + ObjectHandle object, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetObjectSize gets the size of an object in bytes. + * @param session the session's handle + * @param object the object's handle + * @param size_ptr receives size of object + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li InformationSensitive + * \li ObjectHandleInvalid \li OK \li SessionClosed + * \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_GetObjectSize(SessionHandle session, + ObjectHandle object, + Ulong* size_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetAttributeValue obtains the value of one or more object attributes. + * @param session the session's handle + * @param object the object's handle + * @param attribute_template_ptr specifies attrs; gets vals + * @param count attributes in template + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeSensitive \li AttributeTypeInvalid + * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li ObjectHandleInvalid + * \li OK \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_GetAttributeValue(SessionHandle session, + ObjectHandle object, + Attribute* attribute_template_ptr, + Ulong count, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GetAttributeValue obtains the value of one or more object attributes. + * @param session the session's handle + * @param object the object's handle + * @param attribute_values specifies attrs; gets vals + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeSensitive \li AttributeTypeInvalid + * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li ObjectHandleInvalid + * \li OK \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + template + bool C_GetAttributeValue(SessionHandle session, + ObjectHandle object, + std::map>& attribute_values, + ReturnValue* return_value = ThrowException) const + { + std::vector getter_template; + + for(const auto& entry : attribute_values) + { + getter_template.emplace_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(entry.first), nullptr, 0 }); + } + + bool success = C_GetAttributeValue(session, + object, + const_cast< Attribute* >(getter_template.data()), + static_cast(getter_template.size()), + return_value); + + if(!success) + { + return success; + } + + size_t i = 0; + for(auto& entry : attribute_values) + { + entry.second.clear(); + entry.second.resize(getter_template.at(i).ulValueLen); + getter_template.at(i).pValue = const_cast< uint8_t* >(entry.second.data()); + i++; + } + + return C_GetAttributeValue(session, object, + const_cast< Attribute* >(getter_template.data()), + static_cast(getter_template.size()), + return_value); + } + + /** + * C_SetAttributeValue modifies the value of one or more object attributes. + * @param session the session's handle + * @param object the object's handle + * @param attribute_template_ptr specifies attrs and values + * @param count attributes in template + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly + * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionFailed \li GeneralError \li HostMemory + * \li ObjectHandleInvalid \li OK \li SessionClosed + * \li SessionHandleInvalid \li SessionReadOnly \li TemplateInconsistent + * \li TokenWriteProtected \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SetAttributeValue(SessionHandle session, + ObjectHandle object, + Attribute* attribute_template_ptr, + Ulong count, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SetAttributeValue modifies the value of one or more object attributes. + * @param session the session's handle + * @param object the object's handle + * @param attribute_values specifies attrs and values + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly + * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionFailed \li GeneralError \li HostMemory + * \li ObjectHandleInvalid \li OK \li SessionClosed + * \li SessionHandleInvalid \li SessionReadOnly \li TemplateInconsistent + * \li TokenWriteProtected \li UserNotLoggedIn + * @return true on success, false otherwise + */ + template + bool C_SetAttributeValue(SessionHandle session, + ObjectHandle object, + std::map>& attribute_values, + ReturnValue* return_value = ThrowException) const + { + std::vector setter_template; + + for(auto& entry : attribute_values) + { + setter_template.emplace_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(entry.first), entry.second.data(), static_cast(entry.second.size()) }); + } + + return C_SetAttributeValue(session, object, + const_cast< Attribute* >(setter_template.data()), + static_cast(setter_template.size()), + return_value); + } + + /** + * C_FindObjectsInit initializes a search for token and session objects that match a template. + * @param session the session's handle + * @param attribute_template_ptr attribute values to match + * @param count attrs in search template + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeTypeInvalid \li AttributeValueInvalid + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationActive + * \li PinExpired \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_FindObjectsInit(SessionHandle session, + Attribute* attribute_template_ptr, + Ulong count, + ReturnValue* return_value = ThrowException) const; + + /** + * C_FindObjects continues a search for token and session objects that match a template, obtaining additional object handles. + * @param session session's handle + * @param object_ptr gets obj. handles + * @param max_object_count max handles to get + * @param object_count_ptr actual # returned + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_FindObjects(SessionHandle session, + ObjectHandle* object_ptr, + Ulong max_object_count, + Ulong* object_count_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_FindObjectsFinal finishes a search for token and session objects. + * @param session the session's handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_FindObjectsFinal(SessionHandle session, + ReturnValue* return_value = ThrowException) const; + + /****************************** Encryption functions ******************************/ + + /** + * C_EncryptInit initializes an encryption operation. + * @param session the session's handle + * @param mechanism_ptr the encryption mechanism + * @param key handle of encryption key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li KeyFunctionNotPermitted + * \li KeyHandleInvalid \li KeySizeRange \li KeyTypeInconsistent + * \li MechanismInvalid \li MechanismParamInvalid \li OK + * \li OperationActive \li PinExpired \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_EncryptInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Encrypt encrypts single-part data. + * @param session session's handle + * @param data_ptr the plaintext data + * @param data_len size of plaintext data in bytes + * @param encrypted_data gets ciphertext + * @param encrypted_data_len_ptr gets c-text size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataInvalid \li DataLenRange \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_Encrypt(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* encrypted_data, + Ulong* encrypted_data_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Encrypt encrypts single-part data. + * @param session session's handle + * @param plaintext_data the plaintext data + * @param encrypted_data gets ciphertext + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataInvalid \li DataLenRange \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid + * @return true on success, false otherwise + */ + template + bool C_Encrypt(SessionHandle session, + const std::vector& plaintext_data, + std::vector& encrypted_data, + ReturnValue* return_value = ThrowException) const + { + Ulong encrypted_size = 0; + if(!C_Encrypt(session, + const_cast((plaintext_data.data())), + static_cast(plaintext_data.size()), + nullptr, &encrypted_size, + return_value)) + { + return false; + } + + encrypted_data.resize(encrypted_size); + if (!C_Encrypt(session, + const_cast(plaintext_data.data()), + static_cast(plaintext_data.size()), + encrypted_data.data(), + &encrypted_size, return_value)) + { + return false; + } + encrypted_data.resize(encrypted_size); + return true; + } + + /** + * C_EncryptUpdate continues a multiple-part encryption operation. + * @param session session's handle + * @param part_ptr the plaintext data + * @param part_len plaintext data len + * @param encrypted_part_ptr gets ciphertext + * @param encrypted_part_len_ptr gets c-text size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_EncryptUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + Byte* encrypted_part_ptr, + Ulong* encrypted_part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_EncryptFinal finishes a multiple-part encryption operation. + * @param session session handle + * @param last_encrypted_part_ptr last c-text + * @param last_encrypted_part_len_ptr gets last size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_EncryptFinal(SessionHandle session, + Byte* last_encrypted_part_ptr, + Ulong* last_encrypted_part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Decryption functions ******************************/ + + /** + * C_DecryptInit initializes a decryption operation. + * @param session the session's handle + * @param mechanism_ptr the decryption mechanism + * @param key handle of decryption key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange + * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid + * \li OK \li OperationActive \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_DecryptInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Decrypt decrypts encrypted data in a single part. + * @param session session's handle + * @param encrypted_data_ptr ciphertext + * @param encrypted_data_len ciphertext length + * @param data_ptr gets plaintext + * @param data_len_ptr gets p-text size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_Decrypt(SessionHandle session, + Byte* encrypted_data_ptr, + Ulong encrypted_data_len, + Byte* data_ptr, + Ulong* data_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Decrypt decrypts encrypted data in a single part. + * @param session session's handle + * @param encrypted_data ciphertext + * @param decrypted_data gets plaintext + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + template + bool C_Decrypt(SessionHandle session, + const std::vector& encrypted_data, + std::vector& decrypted_data, + ReturnValue* return_value = ThrowException) const + { + Ulong decrypted_size = 0; + if(!C_Decrypt(session, + const_cast((encrypted_data.data())), + static_cast(encrypted_data.size()), + nullptr, &decrypted_size, + return_value)) + { + return false; + } + + decrypted_data.resize(decrypted_size); + if(!C_Decrypt(session, + const_cast(encrypted_data.data()), + static_cast(encrypted_data.size()), + decrypted_data.data(), + &decrypted_size, return_value)) + { + return false; + } + decrypted_data.resize(decrypted_size); + return true; + } + + /** + * C_DecryptUpdate continues a multiple-part decryption operation. + * @param session session's handle + * @param encrypted_part_ptr encrypted data + * @param encrypted_part_len input length + * @param part_ptr gets plaintext + * @param part_len_ptr p-text size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_DecryptUpdate(SessionHandle session, + Byte* encrypted_part_ptr, + Ulong encrypted_part_len, + Byte* part_ptr, + Ulong* part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DecryptFinal finishes a multiple-part decryption operation. + * @param session the session's handle + * @param last_part_ptr gets plaintext + * @param last_part_len_ptr p-text size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_DecryptFinal(SessionHandle session, + Byte* last_part_ptr, + Ulong* last_part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Message digesting functions ******************************/ + + /** + * C_DigestInit initializes a message-digesting operation. + * @param session the session's handle + * @param mechanism_ptr the digesting mechanism + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li MechanismInvalid \li MechanismParamInvalid \li OK + * \li OperationActive \li PinExpired \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_DigestInit(SessionHandle session, + Mechanism* mechanism_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Digest digests data in a single part. + * @param session the session's handle + * @param data_ptr data to be digested + * @param data_len bytes of data to digest + * @param digest_ptr gets the message digest + * @param digest_len_ptr gets digest length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_Digest(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* digest_ptr, + Ulong* digest_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DigestUpdate continues a multiple-part message-digesting operation. + * @param session the session's handle + * @param part_ptr data to be digested + * @param part_len bytes of data to be digested + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_DigestUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DigestKey continues a multi-part message-digesting operation, by digesting the value of a secret key as part of the data already digested. + * @param session the session's handle + * @param key secret key to digest + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li KeyHandleInvalid + * \li KeyIndigestible \li KeySizeRange \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_DigestKey(SessionHandle session, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DigestFinal finishes a multiple-part message-digesting operation. + * @param session the session's handle + * @param digest_ptr gets the message digest + * @param digest_len_ptr gets uint8_t count of digest + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_DigestFinal(SessionHandle session, + Byte* digest_ptr, + Ulong* digest_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Signing and MACing functions ******************************/ + + /** + * C_SignInit initializes a signature (private key encryption) operation, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param mechanism_ptr the signature mechanism + * @param key handle of signature key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange + * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid + * \li OK \li OperationActive \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SignInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Sign signs (encrypts with private key) data in a single part, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param data_ptr the data to sign + * @param data_len count of bytes to sign + * @param signature_ptr gets the signature + * @param signature_len_ptr gets signature length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataInvalid \li DataLenRange \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn \li FunctionRejected + * @return true on success, false otherwise + */ + bool C_Sign(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* signature_ptr, + Ulong* signature_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Sign signs (encrypts with private key) data in a single part, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param data the data to sign + * @param signature gets the signature + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataInvalid \li DataLenRange \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn \li FunctionRejected + * @return true on success, false otherwise + */ + template + bool C_Sign(SessionHandle session, + const std::vector& data, + std::vector& signature, + ReturnValue* return_value = ThrowException) const + { + Ulong signature_size = 0; + if(!C_Sign(session, + const_cast((data.data())), + static_cast(data.size()), + nullptr, + &signature_size, + return_value)) + { + return false; + } + + signature.resize(signature_size); + if (!C_Sign(session, + const_cast(data.data()), + static_cast(data.size()), + signature.data(), + &signature_size, + return_value)) + { + return false; + } + signature.resize(signature_size); + return true; + } + + /** + * C_SignUpdate continues a multiple-part signature operation, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param part_ptr the data to sign + * @param part_len count of bytes to sign + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SignUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SignUpdate continues a multiple-part signature operation, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param part the data to sign + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + template + bool C_SignUpdate(SessionHandle session, + const std::vector& part, + ReturnValue* return_value = ThrowException) const + { + return C_SignUpdate(session, + const_cast(part.data()), + static_cast(part.size()), + return_value); + } + + /** + * C_SignFinal finishes a multiple-part signature operation, returning the signature. + * @param session the session's handle + * @param signature_ptr gets the signature + * @param signature_len_ptr gets signature length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * \li UserNotLoggedIn \li FunctionRejected + * @return true on success, false otherwise + */ + bool C_SignFinal(SessionHandle session, + Byte* signature_ptr, + Ulong* signature_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SignFinal finishes a multiple-part signature operation, returning the signature. + * @param session the session's handle + * @param signature gets the signature + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * \li UserNotLoggedIn \li FunctionRejected + * @return true on success, false otherwise + */ + template + bool C_SignFinal(SessionHandle session, + std::vector& signature, + ReturnValue* return_value = ThrowException) const + { + Ulong signature_size = 0; + if(!C_SignFinal(session, nullptr, &signature_size, return_value)) + { + return false; + } + + signature.resize(signature_size); + if (!C_SignFinal(session, signature.data(), &signature_size, return_value)) + { + return false; + } + signature.resize(signature_size); + return true; + } + + /** + * C_SignRecoverInit initializes a signature operation, where the data can be recovered from the signature. + * @param session the session's handle + * @param mechanism_ptr the signature mechanism + * @param key handle of the signature key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange + * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid + * \li OK \li OperationActive \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SignRecoverInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SignRecover signs data in a single operation, where the data can be recovered from the signature. + * @param session the session's handle + * @param data_ptr the data to sign + * @param data_len count of bytes to sign + * @param signature_ptr gets the signature + * @param signature_len_ptr gets signature length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataInvalid \li DataLenRange \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SignRecover(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* signature_ptr, + Ulong* signature_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Functions for verifying signatures and MACs ******************************/ + + /** + * C_VerifyInit initializes a verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature (e.g. DSA). + * @param session the session's handle + * @param mechanism_ptr the verification mechanism + * @param key verification key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange + * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid + * \li OK \li OperationActive \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_VerifyInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Verify verifies a signature in a single-part operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param data_ptr signed data + * @param data_len length of signed data + * @param signature_ptr signature + * @param signature_len signature length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataInvalid + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * \li SignatureInvalid \li SignatureLenRange + * @return true on success, false otherwise + */ + bool C_Verify(SessionHandle session, + Byte* data_ptr, + Ulong data_len, + Byte* signature_ptr, + Ulong signature_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_Verify verifies a signature in a single-part operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param data signed data + * @param signature signature + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataInvalid + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * \li SignatureInvalid \li SignatureLenRange + * @return true on success, false otherwise + */ + template + bool C_Verify(SessionHandle session, + const std::vector& data, + std::vector& signature, + ReturnValue* return_value = ThrowException) const + { + return C_Verify(session, + const_cast(data.data()), + static_cast(data.size()), + signature.data(), + static_cast(signature.size()), + return_value); + } + + /** + * C_VerifyUpdate continues a multiple-part verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param part_ptr signed data + * @param part_len length of signed data + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_VerifyUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_VerifyUpdate continues a multiple-part verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature. + * @param session the session's handle + * @param part signed data + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + template + bool C_VerifyUpdate(SessionHandle session, + std::vector part, + ReturnValue* return_value = ThrowException) const + { + return C_VerifyUpdate(session, part.data(), static_cast(part.size()), return_value); + } + + /** + * C_VerifyFinal finishes a multiple-part verification operation, checking the signature. + * @param session the session's handle + * @param signature_ptr signature to verify + * @param signature_len signature length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid \li SignatureInvalid + * \li SignatureLenRange + * @return true on success, false otherwise + */ + bool C_VerifyFinal(SessionHandle session, + Byte* signature_ptr, + Ulong signature_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_VerifyRecoverInit initializes a signature verification operation, where the data is recovered from the signature. + * @param session the session's handle + * @param mechanism_ptr the verification mechanism + * @param key verification key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange + * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid + * \li OK \li OperationActive \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_VerifyRecoverInit(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle key, + ReturnValue* return_value = ThrowException) const; + + /** + * C_VerifyRecover verifies a signature in a single-part operation, where the data is recovered from the signature. + * @param session the session's handle + * @param signature_ptr signature to verify + * @param signature_len signature length + * @param data_ptr gets signed data + * @param data_len_ptr gets signed data len + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataInvalid \li DataLenRange \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid \li SignatureLenRange \li SignatureInvalid + * @return true on success, false otherwise + */ + bool C_VerifyRecover(SessionHandle session, + Byte* signature_ptr, + Ulong signature_len, + Byte* data_ptr, + Ulong* data_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Dual-purpose cryptographic functions ******************************/ + + /** + * C_DigestEncryptUpdate continues a multiple-part digesting and encryption operation. + * @param session session's handle + * @param part_ptr the plaintext data + * @param part_len plaintext length + * @param encrypted_part_ptr gets ciphertext + * @param encrypted_part_len_ptr gets c-text length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_DigestEncryptUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + Byte* encrypted_part_ptr, + Ulong* encrypted_part_len_ptr, + ReturnValue* return_value = ThrowException) const ; + + /** + * C_DecryptDigestUpdate continues a multiple-part decryption and digesting operation. + * @param session session's handle + * @param encrypted_part_ptr ciphertext + * @param encrypted_part_len ciphertext length + * @param part_ptr gets plaintext + * @param part_len_ptr gets plaintext len + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationNotInitialized \li SessionClosed + * \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_DecryptDigestUpdate(SessionHandle session, + Byte* encrypted_part_ptr, + Ulong encrypted_part_len, + Byte* part_ptr, + Ulong* part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_SignEncryptUpdate continues a multiple-part signing and encryption operation. + * @param session session's handle + * @param part_ptr the plaintext data + * @param part_len plaintext length + * @param encrypted_part_ptr gets ciphertext + * @param encrypted_part_len_ptr gets c-text length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li OK + * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid + * \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SignEncryptUpdate(SessionHandle session, + Byte* part_ptr, + Ulong part_len, + Byte* encrypted_part_ptr, + Ulong* encrypted_part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DecryptVerifyUpdate continues a multiple-part decryption and verify operation. + * @param session session's handle + * @param encrypted_part_ptr ciphertext + * @param encrypted_part_len ciphertext length + * @param part_ptr gets plaintext + * @param part_len_ptr gets p-text length + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DataLenRange \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li EncryptedDataInvalid \li EncryptedDataLenRange + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li OK \li OperationNotInitialized + * \li SessionClosed \li SessionHandleInvalid + * @return true on success, false otherwise + */ + bool C_DecryptVerifyUpdate(SessionHandle session, + Byte* encrypted_part_ptr, + Ulong encrypted_part_len, + Byte* part_ptr, + Ulong* part_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Key management functions ******************************/ + + /** + * C_GenerateKey generates a secret key, creating a new key object. + * @param session the session's handle + * @param mechanism_ptr key generation mech. + * @param attribute_template_ptr template for new key + * @param count # of attrs in template + * @param key_ptr gets handle of new key + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid + * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li MechanismInvalid \li MechanismParamInvalid + * \li OK \li OperationActive \li PinExpired + * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly + * \li TemplateIncomplete \li TemplateInconsistent \li TokenWriteProtected + * \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_GenerateKey(SessionHandle session, + Mechanism* mechanism_ptr, + Attribute* attribute_template_ptr, + Ulong count, + ObjectHandle* key_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GenerateKeyPair generates a public-key/private-key pair, creating new key objects. + * @param session session handle + * @param mechanism_ptr key-gen mech. + * @param public_key_template_ptr template for pub. key + * @param public_key_attribute_count # pub. attrs. + * @param private_key_template_ptr template for priv. key + * @param private_key_attribute_count # priv. attrs. + * @param public_key_ptr gets pub. key handle + * @param private_key_ptr gets priv. key handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid + * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li DomainParamsInvalid \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li MechanismInvalid + * \li MechanismParamInvalid \li OK \li OperationActive + * \li PinExpired \li SessionClosed \li SessionHandleInvalid + * \li SessionReadOnly \li TemplateIncomplete \li TemplateInconsistent + * \li TokenWriteProtected \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_GenerateKeyPair(SessionHandle session, + Mechanism* mechanism_ptr, + Attribute* public_key_template_ptr, + Ulong public_key_attribute_count, + Attribute* private_key_template_ptr, + Ulong private_key_attribute_count, + ObjectHandle* public_key_ptr, + ObjectHandle* private_key_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_WrapKey wraps (i.e., encrypts) a key. + * @param session the session's handle + * @param mechanism_ptr the wrapping mechanism + * @param wrapping_key wrapping key + * @param key key to be wrapped + * @param wrapped_key_ptr gets wrapped key + * @param wrapped_key_len_ptr gets wrapped key size + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li FunctionCanceled \li FunctionFailed \li GeneralError + * \li HostMemory \li KeyHandleInvalid \li KeyNotWrappable + * \li KeySizeRange \li KeyUnextractable \li MechanismInvalid + * \li MechanismParamInvalid \li OK \li OperationActive + * \li PinExpired \li SessionClosed \li SessionHandleInvalid + * \li UserNotLoggedIn \li WrappingKeyHandleInvalid \li WrappingKeySizeRange + * \li WrappingKeyTypeInconsistent + * @return true on success, false otherwise + */ + bool C_WrapKey(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle wrapping_key, + ObjectHandle key, + Byte* wrapped_key_ptr, + Ulong* wrapped_key_len_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. + * @param session session's handle + * @param mechanism_ptr unwrapping mech. + * @param unwrapping_key unwrapping key + * @param wrapped_key_ptr the wrapped key + * @param wrapped_key_len wrapped key len + * @param attribute_template_ptr new key template + * @param attribute_count template length + * @param key_ptr gets new handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid + * \li AttributeValueInvalid \li BufferTooSmall \li CryptokiNotInitialized + * \li CurveNotSupported \li DeviceError \li DeviceMemory + * \li DeviceRemoved \li DomainParamsInvalid \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li MechanismInvalid \li MechanismParamInvalid \li OK + * \li OperationActive \li PinExpired \li SessionClosed + * \li SessionHandleInvalid \li SessionReadOnly \li TemplateIncomplete + * \li TemplateInconsistent \li TokenWriteProtected \li UnwrappingKeyHandleInvalid + * \li UnwrappingKeySizeRange \li UnwrappingKeyTypeInconsistent \li UserNotLoggedIn + * \li WrappedKeyInvalid \li WrappedKeyLenRange + * @return true on success, false otherwise + */ + bool C_UnwrapKey(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle unwrapping_key, + Byte* wrapped_key_ptr, + Ulong wrapped_key_len, + Attribute* attribute_template_ptr, + Ulong attribute_count, + ObjectHandle* key_ptr, + ReturnValue* return_value = ThrowException) const; + + /** + * C_DeriveKey derives a key from a base key, creating a new key object. + * @param session session's handle + * @param mechanism_ptr key deriv. mech. + * @param base_key base key + * @param attribute_template_ptr new key template + * @param attribute_count template length + * @param key_ptr gets new handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid + * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported + * \li DeviceError \li DeviceMemory \li DeviceRemoved + * \li DomainParamsInvalid \li FunctionCanceled \li FunctionFailed + * \li GeneralError \li HostMemory \li KeyHandleInvalid + * \li KeySizeRange \li KeyTypeInconsistent \li MechanismInvalid + * \li MechanismParamInvalid \li OK \li OperationActive + * \li PinExpired \li SessionClosed \li SessionHandleInvalid + * \li SessionReadOnly \li TemplateIncomplete \li TemplateInconsistent + * \li TokenWriteProtected \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_DeriveKey(SessionHandle session, + Mechanism* mechanism_ptr, + ObjectHandle base_key, + Attribute* attribute_template_ptr, + Ulong attribute_count, + ObjectHandle* key_ptr, + ReturnValue* return_value = ThrowException) const; + + /****************************** Random number generation functions ******************************/ + + /** + * C_SeedRandom mixes additional seed material into the token's random number generator. + * @param session the session's handle + * @param seed_ptr the seed material + * @param seed_len length of seed material + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationActive \li RandomSeedNotSupported + * \li RandomNoRng \li SessionClosed \li SessionHandleInvalid + * \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_SeedRandom(SessionHandle session, + Byte* seed_ptr, + Ulong seed_len, + ReturnValue* return_value = ThrowException) const; + + /** + * C_GenerateRandom generates random data. + * @param session the session's handle + * @param random_data_ptr receives the random data + * @param random_len # of bytes to generate + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError + * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled + * \li FunctionFailed \li GeneralError \li HostMemory + * \li OK \li OperationActive \li RandomNoRng + * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn + * @return true on success, false otherwise + */ + bool C_GenerateRandom(SessionHandle session, + Byte* random_data_ptr, + Ulong random_len, + ReturnValue* return_value = ThrowException) const; + + /****************************** Parallel function management functions ******************************/ + + /** + * C_GetFunctionStatus is a legacy function; it obtains an updated status of a function running in parallel with an application. + * @param session the session's handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li FunctionFailed \li FunctionNotParallel + * \li GeneralError \li HostMemory \li SessionHandleInvalid + * \li SessionClosed + * @return true on success, false otherwise + */ + bool C_GetFunctionStatus(SessionHandle session, + ReturnValue* return_value = ThrowException) const; + + /** + * C_CancelFunction is a legacy function; it cancels a function running in parallel. + * @param session the session's handle + * @param return_value default value (`ThrowException`): throw exception on error. + * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown. + * At least the following PKCS#11 return values may be returned: + * \li CryptokiNotInitialized \li FunctionFailed \li FunctionNotParallel + * \li GeneralError \li HostMemory \li SessionHandleInvalid + * \li SessionClosed + * @return true on success, false otherwise + */ + bool C_CancelFunction(SessionHandle session, + ReturnValue* return_value = ThrowException) const; + + private: + const FunctionListPtr m_func_list_ptr; + }; + +class BOTAN_PUBLIC_API(2,0) PKCS11_Error : public Exception + { + public: + explicit PKCS11_Error(const std::string& what) : + Exception("PKCS11 error", what) + { + } + + ErrorType error_type() const noexcept override { return ErrorType::Pkcs11Error; } + }; + +class BOTAN_PUBLIC_API(2,0) PKCS11_ReturnError final : public PKCS11_Error + { + public: + explicit PKCS11_ReturnError(ReturnValue return_val) : + PKCS11_Error(std::to_string(static_cast< uint32_t >(return_val))), + m_return_val(return_val) + {} + + inline ReturnValue get_return_value() const + { + return m_return_val; + } + + int error_code() const noexcept override + { + return static_cast(m_return_val); + } + + private: + const ReturnValue m_return_val; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.cpp new file mode 100644 index 0000000000..874621b780 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.cpp @@ -0,0 +1,136 @@ +/* +* PKCS#11 ECC +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + +#include +#include + +namespace Botan { +namespace PKCS11 { +namespace { +/// Converts a DER-encoded ANSI X9.62 ECPoint to PointGFp +PointGFp decode_public_point(const secure_vector& ec_point_data, const EC_Group& group) + { + secure_vector ec_point; + BER_Decoder(ec_point_data).decode(ec_point, OCTET_STRING); + return group.OS2ECP(ec_point); + } +} + +EC_PublicKeyGenerationProperties::EC_PublicKeyGenerationProperties(const std::vector& ec_params) + : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params) + { + add_binary(AttributeType::EcParams, m_ec_params); + } + +EC_PublicKeyImportProperties::EC_PublicKeyImportProperties(const std::vector& ec_params, + const std::vector& ec_point) + : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_ec_point(ec_point) + { + add_binary(AttributeType::EcParams, m_ec_params); + add_binary(AttributeType::EcPoint, m_ec_point); + } + +PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, ObjectHandle handle) + : Object(session, handle) + { + secure_vector ec_parameters = get_attribute_value(AttributeType::EcParams); + m_domain_params = EC_Group(unlock(ec_parameters)); + m_public_key = decode_public_point(get_attribute_value(AttributeType::EcPoint), m_domain_params); + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + } + +PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + : Object(session, props) + { + m_domain_params = EC_Group(props.ec_params()); + + secure_vector ec_point; + BER_Decoder(props.ec_point()).decode(ec_point, OCTET_STRING); + m_public_key = m_domain_params.OS2ECP(ec_point); + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + } + +EC_PrivateKeyImportProperties::EC_PrivateKeyImportProperties(const std::vector& ec_params, const BigInt& value) + : PrivateKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_value(value) + { + add_binary(AttributeType::EcParams, m_ec_params); + add_binary(AttributeType::Value, BigInt::encode(m_value)); + } + +PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle) + : Object(session, handle), m_domain_params(), m_public_key() + { + secure_vector ec_parameters = get_attribute_value(AttributeType::EcParams); + m_domain_params = EC_Group(unlock(ec_parameters)); + } + +PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + : Object(session, props) + { + m_domain_params = EC_Group(props.ec_params()); + } + +PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const std::vector& ec_params, + const EC_PrivateKeyGenerationProperties& props) + : Object(session) + { + m_domain_params = EC_Group(ec_params); + + EC_PublicKeyGenerationProperties pub_key_props(ec_params); + pub_key_props.set_verify(true); + pub_key_props.set_private(false); + pub_key_props.set_token(false); // don't create a persistent public key object + + ObjectHandle pub_key_handle = CK_INVALID_HANDLE; + ObjectHandle priv_key_handle = CK_INVALID_HANDLE; + Mechanism mechanism = { CKM_EC_KEY_PAIR_GEN, nullptr, 0 }; + session.module()->C_GenerateKeyPair(session.handle(), &mechanism, + pub_key_props.data(), static_cast(pub_key_props.count()), + props.data(), static_cast(props.count()), + &pub_key_handle, &priv_key_handle); + + this->reset_handle(priv_key_handle); + + Object public_key(session, pub_key_handle); + m_public_key = decode_public_point(public_key.get_attribute_value(AttributeType::EcPoint), m_domain_params); + } + +size_t PKCS11_EC_PrivateKey::key_length() const + { + return m_domain_params.get_order().bits(); + } + +std::vector PKCS11_EC_PrivateKey::public_key_bits() const + { + return public_point().encode(PointGFp::COMPRESSED); + } + +size_t PKCS11_EC_PrivateKey::estimated_strength() const + { + return ecp_work_factor(key_length()); + } + +bool PKCS11_EC_PrivateKey::check_key(RandomNumberGenerator&, bool) const + { + return m_public_key.on_the_curve(); + } + +AlgorithmIdentifier PKCS11_EC_PrivateKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), domain().DER_encode(EC_DOMPAR_ENC_EXPLICIT)); + } +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.h new file mode 100644 index 0000000000..e2fd35b1a3 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecc_key.h @@ -0,0 +1,223 @@ +/* +* PKCS#11 ECC +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_ECC_H_ +#define BOTAN_P11_ECC_H_ + +#include +#include + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) +#include +#include +#include +#include + +namespace Botan { +namespace PKCS11 { + +class Session; + +/// Properties for generating a PKCS#11 EC public key +class BOTAN_PUBLIC_API(2,0) EC_PublicKeyGenerationProperties final : public PublicKeyProperties + { + public: + /// @param ec_params DER-encoding of an ANSI X9.62 Parameters value + EC_PublicKeyGenerationProperties(const std::vector& ec_params); + + /// @return the DER-encoding of the ec parameters according to ANSI X9.62 + inline const std::vector& ec_params() const + { + return m_ec_params; + } + + private: + const std::vector m_ec_params; + }; + +/// Properties for importing a PKCS#11 EC public key +class BOTAN_PUBLIC_API(2,0) EC_PublicKeyImportProperties final : public PublicKeyProperties + { + public: + /** + * @param ec_params DER-encoding of an ANSI X9.62 Parameters value + * @param ec_point DER-encoding of ANSI X9.62 ECPoint value Q + */ + EC_PublicKeyImportProperties(const std::vector& ec_params, const std::vector& ec_point); + + /// @return the DER-encoding of the ec parameters according to ANSI X9.62 + inline const std::vector& ec_params() const + { + return m_ec_params; + } + + /// @return the DER-encoding of the ec public point according to ANSI X9.62 + inline const std::vector& ec_point() const + { + return m_ec_point; + } + + private: + const std::vector m_ec_params; + const std::vector m_ec_point; + }; + +/// Represents a PKCS#11 EC public key +class BOTAN_PUBLIC_API(2,0) PKCS11_EC_PublicKey : public virtual EC_PublicKey, + public Object + { + public: + static const ObjectClass Class = ObjectClass::PublicKey; + + /** + * Creates a PKCS11_EC_PublicKey object from an existing PKCS#11 EC public key + * @param session the session to use + * @param handle the handle of the ecc public key + */ + PKCS11_EC_PublicKey(Session& session, ObjectHandle handle); + + /** + * Imports an EC public key + * @param session the session to use + * @param props the attributes of the public key + */ + PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props); + }; + +/// Properties for generating a PKCS#11 EC private key +class BOTAN_PUBLIC_API(2,0) EC_PrivateKeyGenerationProperties final : public PrivateKeyProperties + { + public: + EC_PrivateKeyGenerationProperties() + : PrivateKeyProperties(KeyType::Ec) + {} + }; + +/// Properties for importing a PKCS#11 EC private key +class BOTAN_PUBLIC_API(2,0) EC_PrivateKeyImportProperties final : public PrivateKeyProperties + { + public: + /** + * @param ec_params DER-encoding of an ANSI X9.62 Parameters value + * @param value ANSI X9.62 private value d + */ + EC_PrivateKeyImportProperties(const std::vector& ec_params, const BigInt& value); + + /// @return the DER-encoding of the ec parameters according to ANSI X9.62 + inline const std::vector& ec_params() const + { + return m_ec_params; + } + + /// @return the value of the ec private key + inline const BigInt& value() const + { + return m_value; + } + + private: + const std::vector m_ec_params; + const BigInt m_value; + }; + +// note: don't inherit from PKCS11_EC_PublicKey: a private key object IS NOT A public key object on a smartcard (-> two different objects) +// note: don't inherit from EC_PublicKey: the public key can not be extracted from a PKCS11-EC-PrivateKey (its only attributes are CKA_EC_PARAMS and CKA_VALUE) +/// Represents a PKCS#11 EC private key +class BOTAN_PUBLIC_API(2,0) PKCS11_EC_PrivateKey : public virtual Private_Key, + public Object + { + public: + static const ObjectClass Class = ObjectClass::PrivateKey; + + /** + * Creates a PKCS11_EC_PrivateKey object from an existing PKCS#11 EC private key + * @param session the session to use + * @param handle the handle of the EC private key + */ + PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle); + + /** + * Imports an EC private key + * @param session the session to use + * @param props the attributes of the private key + */ + PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props); + + /** + * Generates a PKCS#11 EC private key + * @param session the session to use + * @param ec_params DER-encoding of an ANSI X9.62 Parameters value + * @param props the attributes of the private key + * @note no persistent public key object will be created + */ + PKCS11_EC_PrivateKey(Session& session, const std::vector& ec_params, + const EC_PrivateKeyGenerationProperties& props); + + /// @returns the domain of the EC private key + inline const EC_Group& domain() const + { + return m_domain_params; + } + + /** + * Sets the associated public point of this private key + * @param point the public point + * @param point_encoding encoding of the point (default DER-encoded) + */ + void set_public_point(const PointGFp& point, PublicPointEncoding point_encoding = PublicPointEncoding::Der) + { + m_public_key = point; + m_point_encoding = point_encoding; + } + + /** + * Gets the public_point + * @note the public key must be set using `set_public_point` + * because it is not possible to infer the public key from a PKCS#11 EC private key + * @return the public point of the private key + * @throws Exception if the public point was not set using set_public_point() + */ + const PointGFp& public_point() const + { + if(m_public_key.is_zero()) + { + throw Invalid_State("Public point not set. Inferring the public key from a PKCS#11 ec private key is not possible."); + } + return m_public_key; + } + + /// @return the encoding format for the public point when it is passed to cryptoki functions as an argument + PublicPointEncoding point_encoding() const + { + return m_point_encoding; + } + + // Private_Key methods + + std::vector public_key_bits() const override; + + std::size_t key_length() const override; + + std::size_t estimated_strength() const override; + + bool check_key(RandomNumberGenerator&, bool) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + private: + EC_Group m_domain_params; + PointGFp m_public_key; + PublicPointEncoding m_point_encoding = PublicPointEncoding::Der; + }; +} + +} + +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.cpp new file mode 100644 index 0000000000..4110fd486e --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.cpp @@ -0,0 +1,125 @@ +/* +* PKCS#11 ECDH +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_ECDH) + +#include +#include +#include +#include + +namespace Botan { + +namespace PKCS11 { + +ECDH_PublicKey PKCS11_ECDH_PublicKey::export_key() const + { + return ECDH_PublicKey(domain(), public_point()); + } + +ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const + { + auto priv_key = get_attribute_value(AttributeType::Value); + + Null_RNG rng; + return ECDH_PrivateKey(rng, domain(), BigInt::decode(priv_key)); + } + +secure_vector PKCS11_ECDH_PrivateKey::private_key_bits() const + { + return export_key().private_key_bits(); + } + +namespace { +class PKCS11_ECDH_KA_Operation final : public PK_Ops::Key_Agreement + { + public: + PKCS11_ECDH_KA_Operation(const PKCS11_EC_PrivateKey& key, const std::string& params) + : PK_Ops::Key_Agreement(), m_key(key), m_mechanism(MechanismWrapper::create_ecdh_mechanism(params)) + {} + + size_t agreed_value_size() const override { return m_key.domain().get_p_bytes(); } + + /// The encoding in V2.20 was not specified and resulted in different implementations choosing different encodings. + /// Applications relying only on a V2.20 encoding (e.g. the DER variant) other than the one specified now (raw) may not work with all V2.30 compliant tokens. + secure_vector agree(size_t key_len, const uint8_t other_key[], size_t other_key_len, const uint8_t salt[], + size_t salt_len) override + { + std::vector der_encoded_other_key; + if(m_key.point_encoding() == PublicPointEncoding::Der) + { + DER_Encoder(der_encoded_other_key).encode(other_key, other_key_len, OCTET_STRING); + m_mechanism.set_ecdh_other_key(der_encoded_other_key.data(), der_encoded_other_key.size()); + } + else + { + m_mechanism.set_ecdh_other_key(other_key, other_key_len); + } + + if(salt != nullptr && salt_len > 0) + { + m_mechanism.set_ecdh_salt(salt, salt_len); + } + + ObjectHandle secret_handle = 0; + AttributeContainer attributes; + attributes.add_bool(AttributeType::Sensitive, false); + attributes.add_bool(AttributeType::Extractable, true); + attributes.add_numeric(AttributeType::Class, static_cast< CK_OBJECT_CLASS >(ObjectClass::SecretKey)); + attributes.add_numeric(AttributeType::KeyType, static_cast< CK_KEY_TYPE >(KeyType::GenericSecret)); + attributes.add_numeric(AttributeType::ValueLen, static_cast< CK_ULONG >(key_len)); + m_key.module()->C_DeriveKey(m_key.session().handle(), m_mechanism.data(), m_key.handle(), attributes.data(), + static_cast(attributes.count()), &secret_handle); + + Object secret_object(m_key.session(), secret_handle); + secure_vector secret = secret_object.get_attribute_value(AttributeType::Value); + if(secret.size() < key_len) + { + throw PKCS11_Error("ECDH key derivation secret length is too short"); + } + secret.resize(key_len); + return secret; + } + + private: + const PKCS11_EC_PrivateKey& m_key; + MechanismWrapper m_mechanism; + }; + +} + +std::unique_ptr +PKCS11_ECDH_PrivateKey::create_key_agreement_op(RandomNumberGenerator&, + const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_ECDH_KA_Operation(*this, params)); + } + +PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, + const EC_PrivateKeyGenerationProperties& priv_props) + { + ObjectHandle pub_key_handle = 0; + ObjectHandle priv_key_handle = 0; + + Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::EcKeyPairGen), nullptr, 0 }; + + session.module()->C_GenerateKeyPair(session.handle(), &mechanism, + pub_props.data(), static_cast(pub_props.count()), + priv_props.data(), static_cast(priv_props.count()), + &pub_key_handle, &priv_key_handle); + + return std::make_pair(PKCS11_ECDH_PublicKey(session, pub_key_handle), PKCS11_ECDH_PrivateKey(session, priv_key_handle)); + } + +} +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.h new file mode 100644 index 0000000000..bbef9a3e5b --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdh.h @@ -0,0 +1,127 @@ +/* +* PKCS#11 ECDH +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_ECDH_H_ +#define BOTAN_P11_ECDH_H_ + +#include + +#if defined(BOTAN_HAS_ECDH) + +#include +#include + +#include +#include + +namespace Botan { +namespace PKCS11 { +class Session; + +/// Represents a PKCS#11 ECDH public key +class BOTAN_PUBLIC_API(2,0) PKCS11_ECDH_PublicKey : public PKCS11_EC_PublicKey + { + public: + /** + * Create a PKCS11_ECDH_PublicKey object from an existing PKCS#11 ECDH public key + * @param session the session to use + * @param handle the handle of the ECDH public key + */ + PKCS11_ECDH_PublicKey(Session& session, ObjectHandle handle) + : EC_PublicKey(), PKCS11_EC_PublicKey(session, handle) + {} + + /** + * Imports a ECDH public key + * @param session the session to use + * @param props the attributes of the public key + */ + PKCS11_ECDH_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + : EC_PublicKey(), PKCS11_EC_PublicKey(session, props) + {} + + inline std::string algo_name() const override + { + return "ECDH"; + } + + /// @return the exported ECDH public key + ECDH_PublicKey export_key() const; + }; + +/// Represents a PKCS#11 ECDH private key +class BOTAN_PUBLIC_API(2,0) PKCS11_ECDH_PrivateKey final : public virtual PKCS11_EC_PrivateKey, public virtual PK_Key_Agreement_Key + { + public: + /** + * Creates a PKCS11_ECDH_PrivateKey object from an existing PKCS#11 ECDH private key + * @param session the session to use + * @param handle the handle of the ECDH private key + */ + PKCS11_ECDH_PrivateKey(Session& session, ObjectHandle handle) + : PKCS11_EC_PrivateKey(session, handle) + {} + + /** + * Imports an ECDH private key + * @param session the session to use + * @param props the attributes of the private key + */ + PKCS11_ECDH_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + : PKCS11_EC_PrivateKey(session, props) + {} + + /** + * Generates a PKCS#11 ECDH private key + * @param session the session to use + * @param ec_params DER-encoding of an ANSI X9.62 Parameters value + * @param props the attributes of the private key + * @note no persistent public key object will be created + */ + PKCS11_ECDH_PrivateKey(Session& session, const std::vector& ec_params, + const EC_PrivateKeyGenerationProperties& props) + : PKCS11_EC_PrivateKey(session, ec_params, props) + {} + + inline std::string algo_name() const override + { + return "ECDH"; + } + + inline std::vector public_value() const override + { + return public_point().encode(PointGFp::UNCOMPRESSED); + } + + /// @return the exported ECDH private key + ECDH_PrivateKey export_key() const; + + secure_vector private_key_bits() const override; + + std::unique_ptr + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +using PKCS11_ECDH_KeyPair = std::pair; + +/** +* PKCS#11 ECDH key pair generation +* @param session the session that should be used for the key generation +* @param pub_props the properties of the public key +* @param priv_props the properties of the private key +*/ +BOTAN_PUBLIC_API(2,0) PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, + const EC_PrivateKeyGenerationProperties& priv_props); +} + +} + +#endif +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.cpp new file mode 100644 index 0000000000..a990933da1 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.cpp @@ -0,0 +1,213 @@ +/* +* PKCS#11 ECDSA +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_ECDSA) + +#include +#include +#include +#include + +namespace Botan { +namespace PKCS11 { + +ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const + { + return ECDSA_PublicKey(domain(), public_point()); + } + +bool PKCS11_ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!public_point().on_the_curve()) + { + return false; + } + + if(!strong) + { + return true; + } + + ECDSA_PublicKey pubkey(domain(), public_point()); + return KeyPair::signature_consistency_check(rng, *this, pubkey, "EMSA1(SHA-256)"); + } + +ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const + { + auto priv_key = get_attribute_value(AttributeType::Value); + + Null_RNG rng; + return ECDSA_PrivateKey(rng, domain(), BigInt::decode(priv_key)); + } + +secure_vector PKCS11_ECDSA_PrivateKey::private_key_bits() const + { + return export_key().private_key_bits(); + } + +namespace { + +class PKCS11_ECDSA_Signature_Operation final : public PK_Ops::Signature + { + public: + PKCS11_ECDSA_Signature_Operation(const PKCS11_EC_PrivateKey& key, const std::string& emsa) + : PK_Ops::Signature(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa)) + {} + + void update(const uint8_t msg[], size_t msg_len) override + { + if(!m_initialized) + { + // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed + m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); + m_initialized = true; + m_first_message = secure_vector(msg, msg + msg_len); + return; + } + + if(!m_first_message.empty()) + { + // second call to update: start multiple-part operation + m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message); + m_first_message.clear(); + } + + m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast(msg), static_cast(msg_len)); + } + + secure_vector sign(RandomNumberGenerator&) override + { + secure_vector signature; + if(!m_first_message.empty()) + { + // single call to update: perform single-part operation + m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature); + m_first_message.clear(); + } + else + { + // multiple calls to update (or none): finish multiple-part operation + m_key.module()->C_SignFinal(m_key.session().handle(), signature); + } + m_initialized = false; + return signature; + } + + size_t signature_length() const override { return 2*m_order.bytes(); } + + private: + const PKCS11_EC_PrivateKey& m_key; + const BigInt& m_order; + MechanismWrapper m_mechanism; + secure_vector m_first_message; + bool m_initialized = false; + }; + + +class PKCS11_ECDSA_Verification_Operation final : public PK_Ops::Verification + { + public: + PKCS11_ECDSA_Verification_Operation(const PKCS11_EC_PublicKey& key, const std::string& emsa) + : PK_Ops::Verification(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa)) + {} + + void update(const uint8_t msg[], size_t msg_len) override + { + if(!m_initialized) + { + // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed + m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); + m_initialized = true; + m_first_message = secure_vector(msg, msg + msg_len); + return; + } + + if(!m_first_message.empty()) + { + // second call to update: start multiple-part operation + m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message); + m_first_message.clear(); + } + + m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast(msg), static_cast(msg_len)); + } + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override + { + ReturnValue return_value = ReturnValue::SignatureInvalid; + if(!m_first_message.empty()) + { + // single call to update: perform single-part operation + m_key.module()->C_Verify(m_key.session().handle(), + m_first_message.data(), static_cast(m_first_message.size()), + const_cast(sig), static_cast(sig_len), + &return_value); + m_first_message.clear(); + } + else + { + // multiple calls to update (or none): finish multiple-part operation + m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast(sig), static_cast(sig_len), &return_value); + } + m_initialized = false; + if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid) + { + throw PKCS11_ReturnError(return_value); + } + return return_value == ReturnValue::OK; + } + + private: + const PKCS11_EC_PublicKey& m_key; + const BigInt& m_order; + MechanismWrapper m_mechanism; + secure_vector m_first_message; + bool m_initialized = false; + }; + +} + +std::unique_ptr +PKCS11_ECDSA_PublicKey::create_verification_op(const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_ECDSA_Verification_Operation(*this, params)); + } + +std::unique_ptr +PKCS11_ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_ECDSA_Signature_Operation(*this, params)); + } + +PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, + const EC_PrivateKeyGenerationProperties& priv_props) + { + ObjectHandle pub_key_handle = 0; + ObjectHandle priv_key_handle = 0; + + Mechanism mechanism = { static_cast(MechanismType::EcKeyPairGen), nullptr, 0 }; + + session.module()->C_GenerateKeyPair(session.handle(), &mechanism, + pub_props.data(), static_cast(pub_props.count()), + priv_props.data(), static_cast(priv_props.count()), + &pub_key_handle, &priv_key_handle); + + return std::make_pair(PKCS11_ECDSA_PublicKey(session, pub_key_handle), PKCS11_ECDSA_PrivateKey(session, + priv_key_handle)); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.h new file mode 100644 index 0000000000..82721a4666 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_ecdsa.h @@ -0,0 +1,133 @@ +/* +* PKCS#11 ECDSA +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_ECDSA_H_ +#define BOTAN_P11_ECDSA_H_ + +#include +#include + +#if defined(BOTAN_HAS_ECDSA) + +#include +#include + +#include + +namespace Botan { +namespace PKCS11 { +class Session; + +/// Represents a PKCS#11 ECDSA public key +class BOTAN_PUBLIC_API(2,0) PKCS11_ECDSA_PublicKey final : public PKCS11_EC_PublicKey, public virtual ECDSA_PublicKey + { + public: + /** + * Creates a PKCS11_ECDSA_PublicKey object from an existing PKCS#11 ECDSA public key + * @param session the session to use + * @param handle the handle of the ECDSA public key + */ + PKCS11_ECDSA_PublicKey(Session& session, ObjectHandle handle) + : EC_PublicKey(), PKCS11_EC_PublicKey(session, handle) + {} + + /** + * Imports an ECDSA public key + * @param session the session to use + * @param props the attributes of the public key + */ + PKCS11_ECDSA_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + : EC_PublicKey(), PKCS11_EC_PublicKey(session, props) + {} + + inline std::string algo_name() const override + { + return "ECDSA"; + } + + /// @return the exported ECDSA public key + ECDSA_PublicKey export_key() const; + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + }; + +/// Represents a PKCS#11 ECDSA private key +class BOTAN_PUBLIC_API(2,0) PKCS11_ECDSA_PrivateKey final : public PKCS11_EC_PrivateKey + { + public: + /** + * Creates a PKCS11_ECDSA_PrivateKey object from an existing PKCS#11 ECDSA private key + * @param session the session to use + * @param handle the handle of the ECDSA private key + */ + PKCS11_ECDSA_PrivateKey(Session& session, ObjectHandle handle) + : PKCS11_EC_PrivateKey(session, handle) + {} + + /** + * Imports a ECDSA private key + * @param session the session to use + * @param props the attributes of the private key + */ + PKCS11_ECDSA_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + : PKCS11_EC_PrivateKey(session, props) + {} + + /** + * Generates a PKCS#11 ECDSA private key + * @param session the session to use + * @param ec_params DER-encoding of an ANSI X9.62 Parameters value + * @param props the attributes of the private key + * @note no persistent public key object will be created + */ + PKCS11_ECDSA_PrivateKey(Session& session, const std::vector& ec_params, + const EC_PrivateKeyGenerationProperties& props) + : PKCS11_EC_PrivateKey(session, ec_params, props) + {} + + inline std::string algo_name() const override + { + return "ECDSA"; + } + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + /// @return the exported ECDSA private key + ECDSA_PrivateKey export_key() const; + + secure_vector private_key_bits() const override; + + bool check_key(RandomNumberGenerator&, bool) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +using PKCS11_ECDSA_KeyPair = std::pair; + +/** +* ECDSA key pair generation +* @param session the session that should be used for the key generation +* @param pub_props the properties of the public key +* @param priv_props the properties of the private key +*/ +BOTAN_PUBLIC_API(2,0) PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session, + const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props); +} + +} + +#endif +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.cpp new file mode 100644 index 0000000000..e06dcfc1f4 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.cpp @@ -0,0 +1,278 @@ +/* +* PKCS#11 Mechanism +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#include + +namespace Botan { +namespace PKCS11 { + +namespace { +using PSS_Params = std::tuple; + +// maps a PSS mechanism type to the number of bytes used for the salt, the mechanism type of the underlying hash algorithm and the MGF +static const std::map PssOptions = + { + { MechanismType::RsaPkcsPss, PSS_Params(0, MechanismType::Sha1, MGF::Mgf1Sha1) }, + { MechanismType::Sha1RsaPkcsPss, PSS_Params(20, MechanismType::Sha1, MGF::Mgf1Sha1) }, + { MechanismType::Sha224RsaPkcsPss, PSS_Params(28, MechanismType::Sha224, MGF::Mgf1Sha224) }, + { MechanismType::Sha256RsaPkcsPss, PSS_Params(32, MechanismType::Sha256, MGF::Mgf1Sha256) }, + { MechanismType::Sha384RsaPkcsPss, PSS_Params(48, MechanismType::Sha384, MGF::Mgf1Sha384) }, + { MechanismType::Sha512RsaPkcsPss, PSS_Params(64, MechanismType::Sha512, MGF::Mgf1Sha512) } + }; + +struct MechanismData + { + explicit MechanismData(MechanismType _type) + : type(_type) + {} + + MechanismData(MechanismData const&) = default; + MechanismData& operator=(MechanismData const&) = default; + virtual ~MechanismData() = default; + + // the mechanism to perform + MechanismType type; + }; + +struct RSA_SignMechanism final : public MechanismData + { + explicit RSA_SignMechanism(MechanismType _type) + : MechanismData(_type), hash(static_cast(0)), mgf(static_cast(0)), salt_size(0) + { + auto pss_option = PssOptions.find(type); + if(pss_option != PssOptions.end()) + { + hash = std::get<1>(pss_option->second); + mgf = std::get<2>(pss_option->second); + salt_size = std::get<0>(pss_option->second); + } + } + + // hash algorithm used in the PSS encoding; if the signature mechanism does not include message hashing, + // then this value must be the mechanism used by the application to generate the message hash; + // if the signature mechanism includes hashing, then this value must match the hash algorithm indicated by the signature mechanism + MechanismType hash; + + // mask generation function to use on the encoded block + MGF mgf; + + // length, in bytes, of the salt value used in the PSS encoding; typical values are the length of the message hash and zero + size_t salt_size; + }; + +// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_sign_mechanism` +static std::map SignMechanisms = + { + { "Raw", RSA_SignMechanism(MechanismType::RsaX509) }, + + { "EMSA2(Raw)", RSA_SignMechanism(MechanismType::RsaX931) }, + { "EMSA2(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaX931) }, + + // RSASSA PKCS#1 v1.5 + { "EMSA3(Raw)", RSA_SignMechanism(MechanismType::RsaPkcs) }, + { "EMSA3(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) }, + { "EMSA3(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) }, + { "EMSA3(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) }, + { "EMSA3(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) }, + { "EMSA3(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) }, + + { "EMSA_PKCS1(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) }, + { "EMSA_PKCS1(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) }, + { "EMSA_PKCS1(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) }, + { "EMSA_PKCS1(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) }, + { "EMSA_PKCS1(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) }, + + // RSASSA PKCS#1 PSS + { "EMSA4(Raw)", RSA_SignMechanism(MechanismType::RsaPkcsPss) }, + { "EMSA4(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcsPss) }, + { "EMSA4(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcsPss) }, + + { "EMSA4(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) }, + { "EMSA4(SHA-256,MGF1,32)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) }, + { "PSSR(SHA-256,MGF1,32)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) }, + + { "EMSA4(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) }, + { "EMSA4(SHA-384,MGF1,48)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) }, + { "PSSR(SHA-384,MGF1,48)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) }, + + { "EMSA4(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) }, + { "EMSA4(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) }, + { "PSSR(SHA-512,MGF1,64)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) }, + + { "ISO9796", RSA_SignMechanism(MechanismType::Rsa9796) } + }; + +struct RSA_CryptMechanism final : public MechanismData + { + RSA_CryptMechanism(MechanismType _type, size_t _padding_size, MechanismType _hash, MGF _mgf) + : MechanismData(_type), hash(_hash), mgf(_mgf), padding_size(_padding_size) + {} + + RSA_CryptMechanism(MechanismType _type, size_t _padding_size) + : RSA_CryptMechanism(_type, _padding_size, static_cast(0), static_cast(0)) + {} + + // mechanism ID of the message digest algorithm used to calculate the digest of the encoding parameter + MechanismType hash; + + // mask generation function to use on the encoded block + MGF mgf; + + // number of bytes required for the padding + size_t padding_size; + }; + +// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_crypt_mechanism` +static const std::map CryptMechanisms = + { + { "Raw", RSA_CryptMechanism(MechanismType::RsaX509, 0) }, + { "EME-PKCS1-v1_5", RSA_CryptMechanism(MechanismType::RsaPkcs, 11) }, + { "OAEP(SHA-1)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 20, MechanismType::Sha1, MGF::Mgf1Sha1) }, + { "OAEP(SHA-224)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 28, MechanismType::Sha224, MGF::Mgf1Sha224) }, + { "OAEP(SHA-256)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 32, MechanismType::Sha256, MGF::Mgf1Sha256) }, + { "OAEP(SHA-384)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 48, MechanismType::Sha384, MGF::Mgf1Sha384) }, + { "OAEP(SHA-512)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 64, MechanismType::Sha512, MGF::Mgf1Sha512) } + }; + +// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdsa_mechanism` +static std::map EcdsaHash = + { + { "Raw", MechanismType::Ecdsa }, + { "SHA-160", MechanismType::EcdsaSha1 }, + { "SHA-224", MechanismType::EcdsaSha224 }, + { "SHA-256", MechanismType::EcdsaSha256 }, + { "SHA-384", MechanismType::EcdsaSha384 }, + { "SHA-512", MechanismType::EcdsaSha512 } + }; + +// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdh_mechanism` +static std::map EcdhHash = + { + { "Raw", KeyDerivation::Null }, + { "SHA-160", KeyDerivation::Sha1Kdf }, + { "SHA-224", KeyDerivation::Sha224Kdf }, + { "SHA-256", KeyDerivation::Sha256Kdf }, + { "SHA-384", KeyDerivation::Sha384Kdf }, + { "SHA-512", KeyDerivation::Sha512Kdf } + }; +} + +MechanismWrapper::MechanismWrapper(MechanismType mechanism_type) + : m_mechanism( { static_cast(mechanism_type), nullptr, 0 }), m_parameters(nullptr) + {} + +MechanismWrapper MechanismWrapper::create_rsa_crypt_mechanism(const std::string& padding) + { + auto mechanism_info_it = CryptMechanisms.find(padding); + if(mechanism_info_it == CryptMechanisms.end()) + { + // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding` + throw Lookup_Error("PKCS#11 RSA encrypt/decrypt does not support EME " + padding); + } + RSA_CryptMechanism mechanism_info = mechanism_info_it->second; + + MechanismWrapper mech(mechanism_info.type); + if(mechanism_info.type == MechanismType::RsaPkcsOaep) + { + mech.m_parameters = std::make_shared(); + mech.m_parameters->oaep_params.hashAlg = static_cast(mechanism_info.hash); + mech.m_parameters->oaep_params.mgf = static_cast(mechanism_info.mgf); + mech.m_parameters->oaep_params.source = CKZ_DATA_SPECIFIED; + mech.m_parameters->oaep_params.pSourceData = nullptr; + mech.m_parameters->oaep_params.ulSourceDataLen = 0; + mech.m_mechanism.pParameter = mech.m_parameters.get(); + mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsOaepParams); + } + mech.m_padding_size = mechanism_info.padding_size; + return mech; + } + +MechanismWrapper MechanismWrapper::create_rsa_sign_mechanism(const std::string& padding) + { + auto mechanism_info_it = SignMechanisms.find(padding); + if(mechanism_info_it == SignMechanisms.end()) + { + // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding` + throw Lookup_Error("PKCS#11 RSA sign/verify does not support EMSA " + padding); + } + RSA_SignMechanism mechanism_info = mechanism_info_it->second; + + MechanismWrapper mech(mechanism_info.type); + if(PssOptions.find(mechanism_info.type) != PssOptions.end()) + { + mech.m_parameters = std::make_shared(); + mech.m_parameters->pss_params.hashAlg = static_cast(mechanism_info.hash); + mech.m_parameters->pss_params.mgf = static_cast(mechanism_info.mgf); + mech.m_parameters->pss_params.sLen = static_cast(mechanism_info.salt_size); + mech.m_mechanism.pParameter = mech.m_parameters.get(); + mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsPssParams); + } + return mech; + } + +MechanismWrapper MechanismWrapper::create_ecdsa_mechanism(const std::string& hash) + { + std::string hash_name = hash; + + if(hash_name != "Raw") + { + hash_name = hash_for_emsa(hash); + } + + auto mechanism_type = EcdsaHash.find(hash_name); + if(mechanism_type == EcdsaHash.end()) + { + throw Lookup_Error("PKCS#11 ECDSA sign/verify does not support " + hash); + } + return MechanismWrapper(mechanism_type->second); + } + +MechanismWrapper MechanismWrapper::create_ecdh_mechanism(const std::string& params) + { + std::vector param_parts = split_on(params, ','); + + if(param_parts.empty() || param_parts.size() > 2) + throw Invalid_Argument("PKCS #11 ECDH key derivation bad params " + params); + + const bool use_cofactor = + (param_parts[0] == "Cofactor") || + (param_parts.size() == 2 && param_parts[1] == "Cofactor"); + + std::string kdf_name = (param_parts[0] == "Cofactor" ? param_parts[1] : param_parts[0]); + std::string hash = kdf_name; + + if(kdf_name != "Raw") + { + SCAN_Name kdf_hash(kdf_name); + + if(kdf_hash.arg_count() > 0) + { + hash = kdf_hash.arg(0); + } + } + + auto kdf = EcdhHash.find(hash); + if(kdf == EcdhHash.end()) + { + throw Lookup_Error("PKCS#11 ECDH key derivation does not support KDF " + kdf_name); + } + MechanismWrapper mech(use_cofactor ? MechanismType::Ecdh1CofactorDerive : MechanismType::Ecdh1Derive); + mech.m_parameters = std::make_shared(); + mech.m_parameters->ecdh_params.kdf = static_cast(kdf->second); + mech.m_mechanism.pParameter = mech.m_parameters.get(); + mech.m_mechanism.ulParameterLen = sizeof(Ecdh1DeriveParams); + return mech; + } + +} +} diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.h new file mode 100644 index 0000000000..8947372fda --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_mechanism.h @@ -0,0 +1,118 @@ +/* +* PKCS#11 Mechanism +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_MECHANISM_H_ +#define BOTAN_P11_MECHANISM_H_ + +#include + +#include +#include +#include + +namespace Botan { +namespace PKCS11 { + +/** +* Simple class to build and hold the data for a CK_MECHANISM struct +* for RSA (encryption/decryption, signature/verification) +* and EC (ECDSA signature/verification, ECDH key derivation). +*/ +class MechanismWrapper final + { + public: + /// @param mechanism_type the CK_MECHANISM_TYPE for the `mechanism` field of the CK_MECHANISM struct + explicit MechanismWrapper(MechanismType mechanism_type); + + /** + * Creates the CK_MECHANISM data for RSA encryption/decryption + * @param padding supported paddings are Raw (X.509), EME-PKCS1-v1_5 (PKCS#1 v1.5) and OAEP (PKCS#1 OAEP) + */ + static MechanismWrapper create_rsa_crypt_mechanism(const std::string& padding); + + /** + * Creates the CK_MECHANISM data for RSA signature/verification + * @param padding supported paddings are Raw (X.509), EMSA3 (PKCS#1 v1.5), EMSA4 (PKCS#1 PSS), + * EMSA2 (ANSI X9.31) and ISO9796 (ISO/IEC 9796) + */ + static MechanismWrapper create_rsa_sign_mechanism(const std::string& padding); + + /** + * Creates the CK_MECHANISM data for ECDSA signature/verification + * @param hash the hash algorithm used to hash the data to sign. + * supported hash functions are Raw and SHA-160 to SHA-512 + */ + static MechanismWrapper create_ecdsa_mechanism(const std::string& hash); + + /** + * Creates the CK_MECHANISM data for ECDH key derivation (CKM_ECDH1_DERIVE or CKM_ECDH1_COFACTOR_DERIVE) + * @param params specifies the key derivation function to use. + * Supported KDFs are Raw and SHA-160 to SHA-512. + * Params can also include the string "Cofactor" if the cofactor + * key derivation mechanism should be used, for example "SHA-512,Cofactor" + */ + static MechanismWrapper create_ecdh_mechanism(const std::string& params); + + /** + * Sets the salt for the ECDH mechanism parameters. + * @param salt the salt + * @param salt_len size of the salt in bytes + */ + inline void set_ecdh_salt(const uint8_t salt[], size_t salt_len) + { + m_parameters->ecdh_params.pSharedData = const_cast(salt); + m_parameters->ecdh_params.ulSharedDataLen = static_cast(salt_len); + } + + /** + * Sets the public key of the other party for the ECDH mechanism parameters. + * @param other_key key of the other party + * @param other_key_len size of the key of the other party in bytes + */ + inline void set_ecdh_other_key(const uint8_t other_key[], size_t other_key_len) + { + m_parameters->ecdh_params.pPublicData = const_cast(other_key); + m_parameters->ecdh_params.ulPublicDataLen = static_cast(other_key_len); + } + + /// @return a pointer to the CK_MECHANISM struct that can be passed to the cryptoki functions + inline Mechanism* data() const + { + return const_cast(&m_mechanism); + } + + /// @return the size of the padding in bytes (for encryption/decryption) + inline size_t padding_size() const + { + return m_padding_size; + } + + /// Holds the mechanism parameters for OAEP, PSS and ECDH + union MechanismParameters + { + MechanismParameters() + { + clear_mem(this, 1); + } + + RsaPkcsOaepParams oaep_params; + RsaPkcsPssParams pss_params; + Ecdh1DeriveParams ecdh_params; + }; + + private: + Mechanism m_mechanism; + std::shared_ptr m_parameters; + size_t m_padding_size = 0; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_module.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_module.cpp new file mode 100644 index 0000000000..1c84d415cb --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_module.cpp @@ -0,0 +1,53 @@ +/* +* PKCS#11 Module +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace PKCS11 { + +Module::Module(Module&&) = default; + +Module::Module(const std::string& file_path, C_InitializeArgs init_args) + : m_file_path(file_path) + { + if(file_path.empty()) + throw Invalid_Argument("PKCS11 no module path specified"); + reload(init_args); + } + +Module::~Module() noexcept + { + try + { + m_low_level->C_Finalize(nullptr, nullptr); + } + catch(...) + { + // we are noexcept and must swallow any exception here + } + } + +void Module::reload(C_InitializeArgs init_args) + { + if(m_low_level) + { + m_low_level->C_Finalize(nullptr); + } + + m_library.reset(new Dynamically_Loaded_Library(m_file_path)); + LowLevel::C_GetFunctionList(*m_library, &m_func_list); + m_low_level.reset(new LowLevel(m_func_list)); + + m_low_level->C_Initialize(&init_args); + } + +} +} diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_module.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_module.h new file mode 100644 index 0000000000..0c8a6a6db4 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_module.h @@ -0,0 +1,15 @@ +/* +* PKCS#11 Module +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_MODULE_H_ +#define BOTAN_P11_MODULE_H_ + +#include +BOTAN_DEPRECATED_HEADER(p11_module.h) + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_object.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_object.cpp new file mode 100644 index 0000000000..4dd191efe2 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_object.cpp @@ -0,0 +1,227 @@ +/* +* PKCS#11 Object +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace PKCS11 { + +AttributeContainer::AttributeContainer(ObjectClass object_class) + { + add_class(object_class); + } + +void AttributeContainer::add_class(ObjectClass object_class) + { + m_numerics.emplace_back(static_cast< uint64_t >(object_class)); + add_attribute(AttributeType::Class, + reinterpret_cast< uint8_t* >(&m_numerics.back()), + static_cast(sizeof(ObjectClass))); + } + +void AttributeContainer::add_string(AttributeType attribute, const std::string& value) + { + m_strings.push_back(value); + add_attribute(attribute, reinterpret_cast(m_strings.back().data()), static_cast(value.size())); + } + +void AttributeContainer::add_binary(AttributeType attribute, const uint8_t* value, size_t length) + { + m_vectors.push_back(secure_vector(value, value + length)); + add_attribute(attribute, reinterpret_cast< const uint8_t* >(m_vectors.back().data()), static_cast(length)); + } + +void AttributeContainer::add_bool(AttributeType attribute, bool value) + { + m_numerics.push_back(value ? True : False); + add_attribute(attribute, reinterpret_cast< uint8_t* >(&m_numerics.back()), sizeof(Bbool)); + } + +void AttributeContainer::add_attribute(AttributeType attribute, const uint8_t* value, uint32_t size) + { + bool exists = false; + // check if the attribute has been added already + for(auto& existing_attribute : m_attributes) + { + if(existing_attribute.type == static_cast< CK_ATTRIBUTE_TYPE >(attribute)) + { + // remove old entries + m_strings.erase(std::remove_if(m_strings.begin(), m_strings.end(), [ &existing_attribute ](const std::string& data) + { + return data.data() == existing_attribute.pValue; + }), m_strings.end()); + + m_numerics.erase(std::remove_if(m_numerics.begin(), m_numerics.end(), [ &existing_attribute ](const uint64_t& data) + { + return &data == existing_attribute.pValue; + }), m_numerics.end()); + + m_vectors.erase(std::remove_if(m_vectors.begin(), + m_vectors.end(), [ &existing_attribute ](const secure_vector& data) + { + return data.data() == existing_attribute.pValue; + }), m_vectors.end()); + + existing_attribute.pValue = const_cast< uint8_t* >(value); + existing_attribute.ulValueLen = size; + exists = true; + break; + } + } + + if(!exists) + { + m_attributes.push_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(attribute), const_cast< uint8_t* >(value), size }); + } + } + +// ==================================================================================================== + +ObjectFinder::ObjectFinder(Session& session, const std::vector& search_template) + : m_session(session), m_search_terminated(false) + { + module()->C_FindObjectsInit(m_session.get().handle(), + const_cast< Attribute* >(search_template.data()), + static_cast(search_template.size())); + } + +ObjectFinder::~ObjectFinder() noexcept + { + try + { + if(m_search_terminated == false) + { + module()->C_FindObjectsFinal(m_session.get().handle(), nullptr); + } + } + catch(...) + { + // ignore error during noexcept function + } + } + +std::vector ObjectFinder::find(uint32_t max_count) const + { + std::vector result(max_count); + Ulong objectCount = 0; + module()->C_FindObjects(m_session.get().handle(), result.data(), max_count, &objectCount); + if(objectCount < max_count) + { + result.resize(objectCount); + } + return result; + } + +void ObjectFinder::finish() + { + module()->C_FindObjectsFinal(m_session.get().handle()); + m_search_terminated = true; + } + +// ==================================================================================================== + +ObjectProperties::ObjectProperties(ObjectClass object_class) + : AttributeContainer(object_class), m_object_class(object_class) + {} + +// ==================================================================================================== + +StorageObjectProperties::StorageObjectProperties(ObjectClass object_class) + : ObjectProperties(object_class) + {} + +// ==================================================================================================== + +DataObjectProperties::DataObjectProperties() + : StorageObjectProperties(ObjectClass::Data) + {} + +// ==================================================================================================== + +CertificateProperties::CertificateProperties(CertificateType cert_type) + : StorageObjectProperties(ObjectClass::Certificate), m_cert_type(cert_type) + { + add_numeric(AttributeType::CertificateType, static_cast< CK_CERTIFICATE_TYPE >(m_cert_type)); + } + +// ==================================================================================================== + +KeyProperties::KeyProperties(ObjectClass object_class, KeyType key_type) + : StorageObjectProperties(object_class), m_key_type(key_type) + { + add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type)); + } + +// ==================================================================================================== + +PublicKeyProperties::PublicKeyProperties(KeyType key_type) + : KeyProperties(ObjectClass::PublicKey, key_type) + {} + +// ==================================================================================================== + +PrivateKeyProperties::PrivateKeyProperties(KeyType key_type) + : KeyProperties(ObjectClass::PrivateKey, key_type) + {} + +// ==================================================================================================== + +SecretKeyProperties::SecretKeyProperties(KeyType key_type) + : KeyProperties(ObjectClass::SecretKey, key_type) + {} + +// ==================================================================================================== + +DomainParameterProperties::DomainParameterProperties(KeyType key_type) + : StorageObjectProperties(ObjectClass::DomainParameters), m_key_type(key_type) + { + add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type)); + } + +// ==================================================================================================== + +Object::Object(Session& session, ObjectHandle handle) + : m_session(session), m_handle(handle) + {} + +Object::Object(Session& session, const ObjectProperties& obj_props) + : m_session(session), m_handle(0) + { + m_session.get().module()->C_CreateObject(m_session.get().handle(), obj_props.data(), static_cast(obj_props.count()), &m_handle); + } + +secure_vector Object::get_attribute_value(AttributeType attribute) const + { + std::map> attribute_map = { { attribute, secure_vector() } }; + module()->C_GetAttributeValue(m_session.get().handle(), m_handle, attribute_map); + return attribute_map.at(attribute); + } + +void Object::set_attribute_value(AttributeType attribute, const secure_vector& value) const + { + std::map> attribute_map = { { attribute, value } }; + module()->C_SetAttributeValue(m_session.get().handle(), m_handle, attribute_map); + } + +void Object::destroy() const + { + module()->C_DestroyObject(m_session.get().handle(), m_handle); + } + +ObjectHandle Object::copy(const AttributeContainer& modified_attributes) const + { + ObjectHandle copied_handle; + module()->C_CopyObject(m_session.get().handle(), m_handle, + modified_attributes.data(), static_cast(modified_attributes.count()), + &copied_handle); + return copied_handle; + } +} +} diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_object.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_object.h new file mode 100644 index 0000000000..a0da1b5cac --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_object.h @@ -0,0 +1,773 @@ +/* +* PKCS#11 Object +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_OBJECT_H_ +#define BOTAN_P11_OBJECT_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Botan { +namespace PKCS11 { + +class Module; + +/// Helper class to build the Attribute / CK_ATTRIBUTE structures +class BOTAN_PUBLIC_API(2,0) AttributeContainer + { + public: + AttributeContainer() = default; + + /// @param object_class the class type of this container + AttributeContainer(ObjectClass object_class); + + virtual ~AttributeContainer() = default; + + AttributeContainer(AttributeContainer&& other) = default; + AttributeContainer& operator=(AttributeContainer&& other) = default; + + // Warning when implementing copy/assignment: m_attributes contains pointers to the other members which must be updated after a copy + AttributeContainer(const AttributeContainer& other) = delete; + AttributeContainer& operator=(const AttributeContainer& other) = delete; + + /// @return the attributes this container contains + inline const std::vector& attributes() const + { + return m_attributes; + } + + /// @return raw attribute data + inline Attribute* data() const + { + return const_cast< Attribute* >(m_attributes.data()); + } + + /// @return the number of attributes in this container + inline size_t count() const + { + return m_attributes.size(); + } + + /** + * Add a class attribute (CKA_CLASS / AttributeType::Class). + * @param object_class class attribute to add + */ + void add_class(ObjectClass object_class); + + /** + * Add a string attribute (e.g. CKA_LABEL / AttributeType::Label). + * @param attribute attribute type + * @param value string value to add + */ + void add_string(AttributeType attribute, const std::string& value); + + /** + * Add a binary attribute (e.g. CKA_ID / AttributeType::Id). + * @param attribute attribute type + * @param value binary attribute value to add + * @param length size of the binary attribute value in bytes + */ + void add_binary(AttributeType attribute, const uint8_t* value, size_t length); + + /** + * Add a binary attribute (e.g. CKA_ID / AttributeType::Id). + * @param attribute attribute type + * @param binary binary attribute value to add + */ + template + void add_binary(AttributeType attribute, const std::vector& binary) + { + add_binary(attribute, binary.data(), binary.size()); + } + + /** + * Add a bool attribute (e.g. CKA_SENSITIVE / AttributeType::Sensitive). + * @param attribute attribute type + * @param value boolean value to add + */ + void add_bool(AttributeType attribute, bool value); + + /** + * Add a numeric attribute (e.g. CKA_MODULUS_BITS / AttributeType::ModulusBits). + * @param attribute attribute type + * @param value numeric value to add + */ + template + void add_numeric(AttributeType attribute, T value) + { + static_assert(std::is_integral::value, "Numeric value required."); + m_numerics.push_back(static_cast< uint64_t >(value)); + add_attribute(attribute, reinterpret_cast< uint8_t* >(&m_numerics.back()), sizeof(T)); + } + + protected: + /// Add an attribute with the given value and size to the attribute collection `m_attributes` + void add_attribute(AttributeType attribute, const uint8_t* value, uint32_t size); + + private: + std::vector m_attributes; + std::list m_numerics; + std::list m_strings; + std::list> m_vectors; + }; + +/// Manages calls to C_FindObjects* functions (C_FindObjectsInit -> C_FindObjects -> C_FindObjectsFinal) +class BOTAN_PUBLIC_API(2,0) ObjectFinder final + { + public: + /** + * Initializes a search for token and session objects that match a template (calls C_FindObjectsInit) + * @param session the session to use for the search + * @param search_template the search_template as a vector of `Attribute` + */ + ObjectFinder(Session& session, const std::vector& search_template); + + ObjectFinder(const ObjectFinder& other) = default; + ObjectFinder& operator=(const ObjectFinder& other) = delete; + + ObjectFinder(ObjectFinder&& other) = default; + ObjectFinder& operator=(ObjectFinder&& other) = delete; + + /// Terminates a search for token and session objects (calls C_FindObjectsFinal) + ~ObjectFinder() noexcept; + + /** + * Starts or continues a search for token and session objects that match a template, obtaining additional object handles (calls C_FindObjects) + * @param max_count maximum amount of object handles to retrieve. Default = 100 + * @return the result of the search as a vector of `ObjectHandle` + */ + std::vector find(std::uint32_t max_count = 100) const; + + /// Finishes the search operation manually to allow a new ObjectFinder to exist + void finish(); + + /// @return the module this `ObjectFinder` belongs to + inline Module& module() const + { + return m_session.get().module(); + } + + private: + const std::reference_wrapper m_session; + bool m_search_terminated; + }; + +/// Common attributes of all objects +class BOTAN_PUBLIC_API(2,0) ObjectProperties : public AttributeContainer + { + public: + /// @param object_class the object class of the object + ObjectProperties(ObjectClass object_class); + + /// @return the object class of this object + inline ObjectClass object_class() const + { + return m_object_class; + } + + private: + const ObjectClass m_object_class; + }; + +/// Common attributes of all storage objects +class BOTAN_PUBLIC_API(2,0) StorageObjectProperties : public ObjectProperties + { + public: + /// @param object_class the CK_OBJECT_CLASS this storage object belongs to + StorageObjectProperties(ObjectClass object_class); + + /// @param label description of the object (RFC2279 string) + inline void set_label(const std::string& label) + { + add_string(AttributeType::Label, label); + } + + /// @param value if true the object is a token object; otherwise the object is a session object + inline void set_token(bool value) + { + add_bool(AttributeType::Token, value); + } + + /** + * @param value if true the object is a private object; otherwise the object is a public object + * When private, a user may not access the object until the user has been authenticated to the token + */ + inline void set_private(bool value) + { + add_bool(AttributeType::Private, value); + } + + /// @param value if true the object can be modified, otherwise it is read-only + void set_modifiable(bool value) + { + add_bool(AttributeType::Modifiable, value); + } + + /// @param value if true the object can be copied using C_CopyObject + void set_copyable(bool value) + { + add_bool(AttributeType::Copyable, value); + } + + /// @param value if true the object can be destroyed using C_DestroyObject + void set_destroyable(bool value) + { + add_bool(AttributeType::Destroyable, value); + } + }; + +/// Common attributes of all data objects +class BOTAN_PUBLIC_API(2,0) DataObjectProperties final : public StorageObjectProperties + { + public: + DataObjectProperties(); + + /// @param value description of the application that manages the object (RFC2279 string) + inline void set_application(const std::string& value) + { + add_string(AttributeType::Application, value); + } + + /// @param object_id DER-encoding of the object identifier indicating the data object type + inline void set_object_id(const std::vector& object_id) + { + add_binary(AttributeType::ObjectId, object_id); + } + + /// @param value value of the object + inline void set_value(const secure_vector& value) + { + add_binary(AttributeType::Value, value); + } + }; + +/// Common attributes of all certificate objects +class BOTAN_PUBLIC_API(2,0) CertificateProperties : public StorageObjectProperties + { + public: + /// @param cert_type type of certificate + CertificateProperties(CertificateType cert_type); + + /// @param value the certificate can be trusted for the application that it was created (can only be set to true by SO user) + inline void set_trusted(bool value) + { + add_bool(AttributeType::Trusted, value); + } + + /// @param category one of `CertificateCategory` + inline void set_category(CertificateCategory category) + { + add_numeric(AttributeType::CertificateCategory, static_cast< CK_CERTIFICATE_CATEGORY >(category)); + } + + /** + * @param checksum the value of this attribute is derived from the certificate by taking the + * first three bytes of the SHA - 1 hash of the certificate object's `CKA_VALUE` attribute + */ + inline void set_check_value(const std::vector& checksum) + { + add_binary(AttributeType::CheckValue, checksum); + } + + /// @param date start date for the certificate + inline void set_start_date(Date date) + { + add_binary(AttributeType::StartDate, reinterpret_cast(&date), sizeof(Date)); + } + + /// @param date end date for the certificate + inline void set_end_date(Date date) + { + add_binary(AttributeType::EndDate, reinterpret_cast(&date), sizeof(Date)); + } + + /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for the public key contained in this certificate + inline void set_public_key_info(const std::vector& pubkey_info) + { + add_binary(AttributeType::PublicKeyInfo, pubkey_info); + } + + /// @return the certificate type of this certificate object + inline CertificateType cert_type() const + { + return m_cert_type; + } + + private: + const CertificateType m_cert_type; + }; + +/// Common attributes of all key objects +class BOTAN_PUBLIC_API(2,0) KeyProperties : public StorageObjectProperties + { + public: + /** + * @param object_class the `CK_OBJECT_CLASS` this key object belongs to + * @param key_type type of key + */ + KeyProperties(ObjectClass object_class, KeyType key_type); + + /// @param id key identifier for key + inline void set_id(const std::vector& id) + { + add_binary(AttributeType::Id, id); + } + + /// @param date start date for the key + inline void set_start_date(Date date) + { + add_binary(AttributeType::StartDate, reinterpret_cast(&date), sizeof(Date)); + } + + /// @param date end date for the key + inline void set_end_date(Date date) + { + add_binary(AttributeType::EndDate, reinterpret_cast(&date), sizeof(Date)); + } + + /// @param value true if key supports key derivation (i.e., if other keys can be derived from this one) + inline void set_derive(bool value) + { + add_bool(AttributeType::Derive, value); + } + + /** + * Sets a list of mechanisms allowed to be used with this key + * Not implemented + */ + inline void set_allowed_mechanisms(const std::vector&) + { + throw Not_Implemented("KeyProperties::set_allowed_mechanisms"); + } + + /// @return the key type of this key object + inline KeyType key_type() const + { + return m_key_type; + } + + private: + const KeyType m_key_type; + }; + +/// Common attributes of all public key objects +class BOTAN_PUBLIC_API(2,0) PublicKeyProperties : public KeyProperties + { + public: + /// @param key_type type of key + PublicKeyProperties(KeyType key_type); + + /// @param subject DER-encoding of the key subject name + inline void set_subject(const std::vector& subject) + { + add_binary(AttributeType::Subject, subject); + } + + /// @param value true if the key supports encryption + inline void set_encrypt(bool value) + { + add_bool(AttributeType::Encrypt, value); + } + + /// @param value true if the key supports verification where the signature is an appendix to the data + inline void set_verify(bool value) + { + add_bool(AttributeType::Verify, value); + } + + /// @param value true if the key supports verification where the data is recovered from the signature + inline void set_verify_recover(bool value) + { + add_bool(AttributeType::VerifyRecover, value); + } + + /// @param value true if the key supports wrapping (i.e., can be used to wrap other keys) + inline void set_wrap(bool value) + { + add_bool(AttributeType::Wrap, value); + } + + /** + * @param value true if the key can be trusted for the application that it was created. + * The wrapping key can be used to wrap keys with `CKA_WRAP_WITH_TRUSTED` set to `CK_TRUE` + */ + inline void set_trusted(bool value) + { + add_bool(AttributeType::Trusted, value); + } + + /** + * For wrapping keys + * The attribute template to match against any keys wrapped using this wrapping key. + * Keys that do not match cannot be wrapped + * Not implemented + */ + inline void set_wrap_template(const AttributeContainer&) + { + throw Not_Implemented("PublicKeyProperties::set_wrap_template"); + } + + /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key + inline void set_public_key_info(const std::vector& pubkey_info) + { + add_binary(AttributeType::PublicKeyInfo, pubkey_info); + } + }; + +/// Common attributes of all private keys +class BOTAN_PUBLIC_API(2,0) PrivateKeyProperties : public KeyProperties + { + public: + /// @param key_type type of key + PrivateKeyProperties(KeyType key_type); + + /// @param subject DER-encoding of the key subject name + inline void set_subject(const std::vector& subject) + { + add_binary(AttributeType::Subject, subject); + } + + /// @param value true if the key is sensitive + inline void set_sensitive(bool value) + { + add_bool(AttributeType::Sensitive, value); + } + + /// @param value true if the key supports decryption + inline void set_decrypt(bool value) + { + add_bool(AttributeType::Decrypt, value); + } + + /// @param value true if the key supports signatures where the signature is an appendix to the data + inline void set_sign(bool value) + { + add_bool(AttributeType::Sign, value); + } + + /// @param value true if the key supports signatures where the data can be recovered from the signature + inline void set_sign_recover(bool value) + { + add_bool(AttributeType::SignRecover, value); + } + + /// @param value true if the key supports unwrapping (i.e., can be used to unwrap other keys) + inline void set_unwrap(bool value) + { + add_bool(AttributeType::Unwrap, value); + } + + /// @param value true if the key is extractable and can be wrapped + inline void set_extractable(bool value) + { + add_bool(AttributeType::Extractable, value); + } + + /// @param value true if the key can only be wrapped with a wrapping key that has `CKA_TRUSTED` set to `CK_TRUE` + inline void set_wrap_with_trusted(bool value) + { + add_bool(AttributeType::WrapWithTrusted, value); + } + + /// @param value If true, the user has to supply the PIN for each use (sign or decrypt) with the key + inline void set_always_authenticate(bool value) + { + add_bool(AttributeType::AlwaysAuthenticate, value); + } + + /** + * For wrapping keys + * The attribute template to apply to any keys unwrapped using this wrapping key. + * Any user supplied template is applied after this template as if the object has already been created + * Not implemented + */ + inline void set_unwrap_template(const AttributeContainer&) + { + throw Not_Implemented("PrivateKeyProperties::set_unwrap_template"); + } + + /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key + inline void set_public_key_info(const std::vector& pubkey_info) + { + add_binary(AttributeType::PublicKeyInfo, pubkey_info); + } + }; + +/// Common attributes of all secret (symmetric) keys +class BOTAN_PUBLIC_API(2,0) SecretKeyProperties final : public KeyProperties + { + public: + /// @param key_type type of key + SecretKeyProperties(KeyType key_type); + + /// @param value true if the key is sensitive + inline void set_sensitive(bool value) + { + add_bool(AttributeType::Sensitive, value); + } + + /// @param value true if the key supports encryption + inline void set_encrypt(bool value) + { + add_bool(AttributeType::Encrypt, value); + } + + /// @param value true if the key supports decryption + inline void set_decrypt(bool value) + { + add_bool(AttributeType::Decrypt, value); + } + + /// @param value true if the key supports signatures where the signature is an appendix to the data + inline void set_sign(bool value) + { + add_bool(AttributeType::Sign, value); + } + + /// @param value true if the key supports verification where the signature is an appendix to the data + inline void set_verify(bool value) + { + add_bool(AttributeType::Verify, value); + } + + /// @param value true if the key supports unwrapping (i.e., can be used to unwrap other keys) + inline void set_unwrap(bool value) + { + add_bool(AttributeType::Unwrap, value); + } + + /// @param value true if the key is extractable and can be wrapped + inline void set_extractable(bool value) + { + add_bool(AttributeType::Extractable, value); + } + + /// @param value true if the key can only be wrapped with a wrapping key that has `CKA_TRUSTED` set to `CK_TRUE` + inline void set_wrap_with_trusted(bool value) + { + add_bool(AttributeType::WrapWithTrusted, value); + } + + /// @param value if true, the user has to supply the PIN for each use (sign or decrypt) with the key + inline void set_always_authenticate(bool value) + { + add_bool(AttributeType::AlwaysAuthenticate, value); + } + + /// @param value true if the key supports wrapping (i.e., can be used to wrap other keys) + inline void set_wrap(bool value) + { + add_bool(AttributeType::Wrap, value); + } + + /** + * @param value the key can be trusted for the application that it was created. + * The wrapping key can be used to wrap keys with `CKA_WRAP_WITH_TRUSTED` set to `CK_TRUE` + */ + inline void set_trusted(bool value) + { + add_bool(AttributeType::Trusted, value); + } + + /// @param checksum the key check value of this key + inline void set_check_value(const std::vector& checksum) + { + add_binary(AttributeType::CheckValue, checksum); + } + + /** + * For wrapping keys + * The attribute template to match against any keys wrapped using this wrapping key. + * Keys that do not match cannot be wrapped + * Not implemented + */ + inline void set_wrap_template(const AttributeContainer&) + { + throw Not_Implemented("SecretKeyProperties::set_wrap_template"); + } + + /** + * For wrapping keys + * The attribute template to apply to any keys unwrapped using this wrapping key + * Any user supplied template is applied after this template as if the object has already been created + * Not Implemented + */ + inline void set_unwrap_template(const AttributeContainer&) + { + throw Not_Implemented("SecretKeyProperties::set_unwrap_template"); + } + }; + +/// Common attributes of domain parameter +class BOTAN_PUBLIC_API(2,0) DomainParameterProperties final : public StorageObjectProperties + { + public: + /// @param key_type type of key the domain parameters can be used to generate + DomainParameterProperties(KeyType key_type); + + /// @return the key type + inline KeyType key_type() const + { + return m_key_type; + } + + private: + const KeyType m_key_type; + }; + +/** +* Represents a PKCS#11 object. +*/ +class BOTAN_PUBLIC_API(2,0) Object + { + public: + /** + * Creates an `Object` from an existing PKCS#11 object + * @param session the session the object belongs to + * @param handle handle of the object + */ + + Object(Session& session, ObjectHandle handle); + + /** + * Creates the object + * @param session the session in which the object should be created + * @param obj_props properties of this object + */ + Object(Session& session, const ObjectProperties& obj_props); + + Object(const Object&) = default; + Object& operator=(const Object&) = delete; + virtual ~Object() = default; + + /// Searches for all objects of the given type that match `search_template` + template + static std::vector search(Session& session, const std::vector& search_template); + + /// Searches for all objects of the given type using the label (`CKA_LABEL`) + template + static std::vector search(Session& session, const std::string& label); + + /// Searches for all objects of the given type using the id (`CKA_ID`) + template + static std::vector search(Session& session, const std::vector& id); + + /// Searches for all objects of the given type using the label (`CKA_LABEL`) and id (`CKA_ID`) + template + static std::vector search(Session& session, const std::string& label, const std::vector& id); + + /// Searches for all objects of the given type + template + static std::vector search(Session& session); + + /// @returns the value of the given attribute (using `C_GetAttributeValue`) + secure_vector get_attribute_value(AttributeType attribute) const; + + /// Sets the given value for the attribute (using `C_SetAttributeValue`) + void set_attribute_value(AttributeType attribute, const secure_vector& value) const; + + /// Destroys the object + void destroy() const; + + /** + * Copies the object + * @param modified_attributes the attributes of the copied object + */ + ObjectHandle copy(const AttributeContainer& modified_attributes) const; + + /// @return the handle of this object. + inline ObjectHandle handle() const + { + return m_handle; + } + + /// @return the session this objects belongs to + inline Session& session() const + { + return m_session; + } + + /// @return the module this object belongs to + inline Module& module() const + { + return m_session.get().module(); + } + protected: + Object(Session& session) + : m_session(session) + {} + + void reset_handle(ObjectHandle handle) + { + if(m_handle != CK_INVALID_HANDLE) + throw Invalid_Argument("Cannot reset handle on already valid PKCS11 object"); + m_handle = handle; + } + + private: + const std::reference_wrapper m_session; + ObjectHandle m_handle = CK_INVALID_HANDLE; + }; + +template +std::vector Object::search(Session& session, const std::vector& search_template) + { + ObjectFinder finder(session, search_template); + std::vector handles = finder.find(); + std::vector result; + result.reserve(handles.size()); + for(const auto& handle : handles) + { + result.emplace_back(T(session, handle)); + } + return result; + } + +template +std::vector Object::search(Session& session, const std::string& label) + { + AttributeContainer search_template(T::Class); + search_template.add_string(AttributeType::Label, label); + return search(session, search_template.attributes()); + } + +template +std::vector Object::search(Session& session, const std::vector& id) + { + AttributeContainer search_template(T::Class); + search_template.add_binary(AttributeType::Id, id); + return search(session, search_template.attributes()); + } + +template +std::vector Object::search(Session& session, const std::string& label, const std::vector& id) + { + AttributeContainer search_template(T::Class); + search_template.add_string(AttributeType::Label, label); + search_template.add_binary(AttributeType::Id, id); + return search(session, search_template.attributes()); + } + +template +std::vector Object::search(Session& session) + { + return search(session, AttributeContainer(T::Class).attributes()); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.cpp new file mode 100644 index 0000000000..2f4e4c2ec9 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.cpp @@ -0,0 +1,31 @@ +/* +* PKCS#11 Random Generator +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +namespace PKCS11 { + +PKCS11_RNG::PKCS11_RNG(Session& session) + : m_session(session) + {} + +void PKCS11_RNG::randomize(uint8_t output[], std::size_t length) + { + module()->C_GenerateRandom(m_session.get().handle(), output, Ulong(length)); + } + +void PKCS11_RNG::add_entropy(const uint8_t in[], std::size_t length) + { + module()->C_SeedRandom(m_session.get().handle(), const_cast(in), Ulong(length)); + } + +} +} + diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.h new file mode 100644 index 0000000000..339cb95a5c --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_randomgenerator.h @@ -0,0 +1,70 @@ +/* +* PKCS#11 Random Generator +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_RNG_H_ +#define BOTAN_P11_RNG_H_ + +#include +#include +#include + +#include +#include + +namespace Botan { +namespace PKCS11 { + +class Module; + +/// A random generator that only fetches random from the PKCS#11 RNG +class BOTAN_PUBLIC_API(2,0) PKCS11_RNG final : public Hardware_RNG + { + public: + /// Initialize the RNG with the PKCS#11 session that provides access to the cryptoki functions + explicit PKCS11_RNG(Session& session); + + std::string name() const override + { + return "PKCS11_RNG"; + } + + /// Always returns true + bool is_seeded() const override + { + return true; + } + + /// No operation - always returns 0 + size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override + { + return 0; + } + + /// @return the module used by this RNG + inline Module& module() const + { + return m_session.get().module(); + } + + /// Calls `C_GenerateRandom` to generate random data + void randomize(uint8_t output[], std::size_t length) override; + + /// Calls `C_SeedRandom` to add entropy to the random generation function of the token/middleware + void add_entropy(const uint8_t in[], std::size_t length) override; + + // C_SeedRandom may suceed + bool accepts_input() const override { return true; } + + private: + const std::reference_wrapper m_session; + }; +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.cpp new file mode 100644 index 0000000000..0e434c5b34 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.cpp @@ -0,0 +1,373 @@ +/* +* PKCS#11 RSA +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_RSA) + +#include +#include +#include +#include + +namespace Botan { + +namespace PKCS11 { + +RSA_PublicKeyImportProperties::RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent) + : PublicKeyProperties(KeyType::Rsa), m_modulus(modulus), m_pub_exponent(pub_exponent) + { + add_binary(AttributeType::Modulus, BigInt::encode(m_modulus)); + add_binary(AttributeType::PublicExponent, BigInt::encode(m_pub_exponent)); + } + +RSA_PublicKeyGenerationProperties::RSA_PublicKeyGenerationProperties(Ulong bits) + : PublicKeyProperties(KeyType::Rsa) + { + add_numeric(AttributeType::ModulusBits, bits); + } + +PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle) + : Object(session, handle), + RSA_PublicKey(BigInt::decode(get_attribute_value(AttributeType::Modulus)), + BigInt::decode(get_attribute_value(AttributeType::PublicExponent))) + { + } + +PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props) + : Object(session, pubkey_props), RSA_PublicKey(pubkey_props.modulus(), pubkey_props.pub_exponent()) + {} + + +RSA_PrivateKeyImportProperties::RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent) + : PrivateKeyProperties(KeyType::Rsa), m_modulus(modulus), m_priv_exponent(priv_exponent) + { + add_binary(AttributeType::Modulus, BigInt::encode(m_modulus)); + add_binary(AttributeType::PrivateExponent, BigInt::encode(m_priv_exponent)); + } + + +PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle) + : Object(session, handle), + RSA_PublicKey(BigInt::decode(get_attribute_value(AttributeType::Modulus)), + BigInt::decode(get_attribute_value(AttributeType::PublicExponent))) + { + } + +PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props) + : Object(session, priv_key_props), + RSA_PublicKey(priv_key_props.modulus(), + BigInt::decode(get_attribute_value(AttributeType::PublicExponent))) + { + } + +PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, + const RSA_PrivateKeyGenerationProperties& priv_key_props) + : Object(session), RSA_PublicKey() + { + RSA_PublicKeyGenerationProperties pub_key_props(bits); + pub_key_props.set_encrypt(true); + pub_key_props.set_verify(true); + pub_key_props.set_token(false); // don't create a persistent public key object + + ObjectHandle pub_key_handle = CK_INVALID_HANDLE; + ObjectHandle priv_key_handle = CK_INVALID_HANDLE; + Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 }; + session.module()->C_GenerateKeyPair(session.handle(), &mechanism, + pub_key_props.data(), static_cast(pub_key_props.count()), + priv_key_props.data(), static_cast(priv_key_props.count()), + &pub_key_handle, &priv_key_handle); + + this->reset_handle(priv_key_handle); + + BigInt n = BigInt::decode(get_attribute_value(AttributeType::Modulus)); + BigInt e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent)); + RSA_PublicKey::init(std::move(n), std::move(e)); + } + +RSA_PrivateKey PKCS11_RSA_PrivateKey::export_key() const + { + auto p = get_attribute_value(AttributeType::Prime1); + auto q = get_attribute_value(AttributeType::Prime2); + auto e = get_attribute_value(AttributeType::PublicExponent); + auto d = get_attribute_value(AttributeType::PrivateExponent); + auto n = get_attribute_value(AttributeType::Modulus); + + return RSA_PrivateKey( BigInt::decode(p) + , BigInt::decode(q) + , BigInt::decode(e) + , BigInt::decode(d) + , BigInt::decode(n)); + } + +secure_vector PKCS11_RSA_PrivateKey::private_key_bits() const + { + return export_key().private_key_bits(); + } + + +namespace { +// note: multiple-part decryption operations (with C_DecryptUpdate/C_DecryptFinal) +// are not supported (PK_Ops::Decryption does not provide an `update` method) +class PKCS11_RSA_Decryption_Operation final : public PK_Ops::Decryption + { + public: + + PKCS11_RSA_Decryption_Operation(const PKCS11_RSA_PrivateKey& key, + const std::string& padding, + RandomNumberGenerator& rng) + : m_key(key), + m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)), + m_blinder(m_key.get_n(), rng, + [ this ](const BigInt& k) { return power_mod(k, m_key.get_e(), m_key.get_n()); }, + [ this ](const BigInt& k) { return inverse_mod(k, m_key.get_n()); }) + { + m_bits = m_key.get_n().bits() - 1; + } + + size_t plaintext_length(size_t) const override { return m_key.get_n().bytes(); } + + secure_vector decrypt(uint8_t& valid_mask, const uint8_t ciphertext[], size_t ciphertext_len) override + { + valid_mask = 0; + m_key.module()->C_DecryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); + + std::vector encrypted_data(ciphertext, ciphertext + ciphertext_len); + + // blind for RSA/RAW decryption + if(! m_mechanism.padding_size()) + { + encrypted_data = BigInt::encode(m_blinder.blind(BigInt::decode(encrypted_data))); + } + + secure_vector decrypted_data; + m_key.module()->C_Decrypt(m_key.session().handle(), encrypted_data, decrypted_data); + + // Unblind for RSA/RAW decryption + if(!m_mechanism.padding_size()) + { + decrypted_data = BigInt::encode_1363(m_blinder.unblind(BigInt::decode(decrypted_data)), m_key.get_n().bits() / 8 ); + } + + valid_mask = 0xFF; + return decrypted_data; + } + + private: + const PKCS11_RSA_PrivateKey& m_key; + MechanismWrapper m_mechanism; + size_t m_bits = 0; + Blinder m_blinder; + }; + +// note: multiple-part encryption operations (with C_EncryptUpdate/C_EncryptFinal) +// are not supported (PK_Ops::Encryption does not provide an `update` method) +class PKCS11_RSA_Encryption_Operation final : public PK_Ops::Encryption + { + public: + + PKCS11_RSA_Encryption_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding) + : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)) + { + m_bits = 8 * (key.get_n().bytes() - m_mechanism.padding_size()) - 1; + } + + size_t ciphertext_length(size_t) const override { return m_key.get_n().bytes(); } + + size_t max_input_bits() const override + { + return m_bits; + } + + secure_vector encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator&) override + { + m_key.module()->C_EncryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); + + secure_vector encrytped_data; + m_key.module()->C_Encrypt(m_key.session().handle(), secure_vector(msg, msg + msg_len), encrytped_data); + return encrytped_data; + } + + private: + const PKCS11_RSA_PublicKey& m_key; + MechanismWrapper m_mechanism; + size_t m_bits = 0; + }; + + +class PKCS11_RSA_Signature_Operation final : public PK_Ops::Signature + { + public: + + PKCS11_RSA_Signature_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding) + : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding)) + {} + + size_t signature_length() const override { return m_key.get_n().bytes(); } + + void update(const uint8_t msg[], size_t msg_len) override + { + if(!m_initialized) + { + // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed + m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); + m_initialized = true; + m_first_message = secure_vector(msg, msg + msg_len); + return; + } + + if(!m_first_message.empty()) + { + // second call to update: start multiple-part operation + m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message); + m_first_message.clear(); + } + + m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast< Byte* >(msg), static_cast(msg_len)); + } + + secure_vector sign(RandomNumberGenerator&) override + { + secure_vector signature; + if(!m_first_message.empty()) + { + // single call to update: perform single-part operation + m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature); + m_first_message.clear(); + } + else + { + // multiple calls to update (or none): finish multiple-part operation + m_key.module()->C_SignFinal(m_key.session().handle(), signature); + } + m_initialized = false; + return signature; + } + + private: + const PKCS11_RSA_PrivateKey& m_key; + bool m_initialized = false; + secure_vector m_first_message; + MechanismWrapper m_mechanism; + }; + + +class PKCS11_RSA_Verification_Operation final : public PK_Ops::Verification + { + public: + + PKCS11_RSA_Verification_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding) + : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding)) + {} + + void update(const uint8_t msg[], size_t msg_len) override + { + if(!m_initialized) + { + // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed + m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle()); + m_initialized = true; + m_first_message = secure_vector(msg, msg + msg_len); + return; + } + + if(!m_first_message.empty()) + { + // second call to update: start multiple-part operation + m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message); + m_first_message.clear(); + } + + m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast< Byte* >(msg), static_cast(msg_len)); + } + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override + { + ReturnValue return_value = ReturnValue::SignatureInvalid; + if(!m_first_message.empty()) + { + // single call to update: perform single-part operation + m_key.module()->C_Verify(m_key.session().handle(), + m_first_message.data(), static_cast(m_first_message.size()), + const_cast< Byte* >(sig), static_cast(sig_len), &return_value); + m_first_message.clear(); + } + else + { + // multiple calls to update (or none): finish multiple-part operation + m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast< Byte* >(sig), static_cast(sig_len), &return_value); + } + m_initialized = false; + if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid) + { + throw PKCS11_ReturnError(return_value); + } + return return_value == ReturnValue::OK; + } + + private: + const PKCS11_RSA_PublicKey& m_key; + bool m_initialized = false; + secure_vector m_first_message; + MechanismWrapper m_mechanism; + }; + +} + +std::unique_ptr +PKCS11_RSA_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_RSA_Encryption_Operation(*this, params)); + } + +std::unique_ptr +PKCS11_RSA_PublicKey::create_verification_op(const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_RSA_Verification_Operation(*this, params)); + } + +std::unique_ptr +PKCS11_RSA_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_RSA_Decryption_Operation(*this, params, rng)); + } + +std::unique_ptr +PKCS11_RSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new PKCS11_RSA_Signature_Operation(*this, params)); + } + +PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props, + const RSA_PrivateKeyGenerationProperties& priv_props) + { + ObjectHandle pub_key_handle = 0; + ObjectHandle priv_key_handle = 0; + + Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 }; + + session.module()->C_GenerateKeyPair(session.handle(), &mechanism, + pub_props.data(), static_cast(pub_props.count()), + priv_props.data(), static_cast(priv_props.count()), + &pub_key_handle, &priv_key_handle); + + return std::make_pair(PKCS11_RSA_PublicKey(session, pub_key_handle), PKCS11_RSA_PrivateKey(session, priv_key_handle)); + } + +} +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.h new file mode 100644 index 0000000000..41d9bc1348 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_rsa.h @@ -0,0 +1,229 @@ +/* +* PKCS#11 RSA +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_RSA_H_ +#define BOTAN_P11_RSA_H_ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_RSA) +#include +#include + +namespace Botan { +namespace PKCS11 { + +/// Properties for generating a PKCS#11 RSA public key +class BOTAN_PUBLIC_API(2,0) RSA_PublicKeyGenerationProperties final : public PublicKeyProperties + { + public: + /// @param bits length in bits of modulus n + explicit RSA_PublicKeyGenerationProperties(Ulong bits); + + /// @param pub_exponent public exponent e + inline void set_pub_exponent(const BigInt& pub_exponent = BigInt(0x10001)) + { + add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent)); + } + + virtual ~RSA_PublicKeyGenerationProperties() = default; + }; + +/// Properties for importing a PKCS#11 RSA public key +class BOTAN_PUBLIC_API(2,0) RSA_PublicKeyImportProperties final : public PublicKeyProperties + { + public: + /// @param modulus modulus n + /// @param pub_exponent public exponent e + RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent); + + /// @return the modulus + inline const BigInt& modulus() const + { + return m_modulus; + } + + /// @return the public exponent + inline const BigInt& pub_exponent() const + { + return m_pub_exponent; + } + + virtual ~RSA_PublicKeyImportProperties() = default; + private: + const BigInt m_modulus; + const BigInt m_pub_exponent; + }; + +/// Represents a PKCS#11 RSA public key +class BOTAN_PUBLIC_API(2,0) PKCS11_RSA_PublicKey : public Object, public RSA_PublicKey + { + public: + static const ObjectClass Class = ObjectClass::PublicKey; + + /** + * Creates a PKCS11_RSA_PublicKey object from an existing PKCS#11 RSA public key + * @param session the session to use + * @param handle the handle of the RSA public key + */ + PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle); + + /** + * Imports a RSA public key + * @param session the session to use + * @param pubkey_props the attributes of the public key + */ + PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props); + + std::unique_ptr + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + }; + +/// Properties for importing a PKCS#11 RSA private key +class BOTAN_PUBLIC_API(2,0) RSA_PrivateKeyImportProperties final : public PrivateKeyProperties + { + public: + /** + * @param modulus modulus n + * @param priv_exponent private exponent d + */ + RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent); + + /// @param pub_exponent public exponent e + inline void set_pub_exponent(const BigInt& pub_exponent) + { + add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent)); + } + + /// @param prime1 prime p + inline void set_prime_1(const BigInt& prime1) + { + add_binary(AttributeType::Prime1, BigInt::encode(prime1)); + } + + /// @param prime2 prime q + inline void set_prime_2(const BigInt& prime2) + { + add_binary(AttributeType::Prime2, BigInt::encode(prime2)); + } + + /// @param exp1 private exponent d modulo p-1 + inline void set_exponent_1(const BigInt& exp1) + { + add_binary(AttributeType::Exponent1, BigInt::encode(exp1)); + } + + /// @param exp2 private exponent d modulo q-1 + inline void set_exponent_2(const BigInt& exp2) + { + add_binary(AttributeType::Exponent2, BigInt::encode(exp2)); + } + + /// @param coeff CRT coefficient q^-1 mod p + inline void set_coefficient(const BigInt& coeff) + { + add_binary(AttributeType::Coefficient, BigInt::encode(coeff)); + } + + /// @return the modulus + inline const BigInt& modulus() const + { + return m_modulus; + } + + /// @return the private exponent + inline const BigInt& priv_exponent() const + { + return m_priv_exponent; + } + + virtual ~RSA_PrivateKeyImportProperties() = default; + + private: + const BigInt m_modulus; + const BigInt m_priv_exponent; + }; + +/// Properties for generating a PKCS#11 RSA private key +class BOTAN_PUBLIC_API(2,0) RSA_PrivateKeyGenerationProperties final : public PrivateKeyProperties + { + public: + RSA_PrivateKeyGenerationProperties() + : PrivateKeyProperties(KeyType::Rsa) + {} + + virtual ~RSA_PrivateKeyGenerationProperties() = default; + }; + +/// Represents a PKCS#11 RSA private key +class BOTAN_PUBLIC_API(2,0) PKCS11_RSA_PrivateKey final : + public Object, public Private_Key, public RSA_PublicKey + { + public: + static const ObjectClass Class = ObjectClass::PrivateKey; + + /// Creates a PKCS11_RSA_PrivateKey object from an existing PKCS#11 RSA private key + PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle); + + /** + * Imports a RSA private key + * @param session the session to use + * @param priv_key_props the properties of the RSA private key + */ + PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props); + + /** + * Generates a PKCS#11 RSA private key + * @param session the session to use + * @param bits length in bits of modulus n + * @param priv_key_props the properties of the RSA private key + * @note no persistent public key object will be created + */ + PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props); + + /// @return the exported RSA private key + RSA_PrivateKey export_key() const; + + secure_vector private_key_bits() const override; + + std::unique_ptr + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +using PKCS11_RSA_KeyPair = std::pair; + +/** +* RSA key pair generation +* @param session the session that should be used for the key generation +* @param pub_props properties of the public key +* @param priv_props properties of the private key +*/ +BOTAN_PUBLIC_API(2,0) PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props, + const RSA_PrivateKeyGenerationProperties& priv_props); +} + +} +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_session.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_session.cpp new file mode 100644 index 0000000000..3f5bfc001e --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_session.cpp @@ -0,0 +1,96 @@ +/* +* PKCS#11 Session +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { +namespace PKCS11 { + +Session::Session(Slot& slot, bool read_only) + : Session(slot, PKCS11::flags(Flag::SerialSession | (read_only ? Flag::None : Flag::RwSession)), nullptr, nullptr) + {} + +Session::Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback) + : m_slot(slot), m_handle(0), m_logged_in(false) + { + module()->C_OpenSession(m_slot.slot_id(), flags, callback_data, notify_callback, &m_handle); + } + +Session::Session(Slot& slot, SessionHandle handle) + : m_slot(slot), m_handle(handle) + { + SessionInfo info = get_info(); + if(info.state == static_cast(SessionState::RoPublicSession) + || info.state == static_cast(SessionState::RwPublicSession)) + { + m_logged_in = false; + } + else + { + m_logged_in = true; + } + } + +Session::~Session() noexcept + { + try + { + if(m_handle) + { + if(m_logged_in) + { + module()->C_Logout(m_handle, nullptr); + } + module()->C_CloseSession(m_handle, nullptr); + m_handle = 0; + } + } + catch(...) + { + // exception during noexcept destructor is ignored + } + } + +SessionHandle Session::release() + { + SessionHandle handle = 0; + std::swap(handle, m_handle); + return handle; + } + +void Session::login(UserType user_type, const secure_string& pin) + { + module()->C_Login(m_handle, user_type, pin); + m_logged_in = true; + } + +void Session::logoff() + { + module()->C_Logout(m_handle); + m_logged_in = false; + } + +SessionInfo Session::get_info() const + { + SessionInfo info; + module()->C_GetSessionInfo(m_handle, &info); + return info; + } + +void Session::set_pin(const secure_string& old_pin, const secure_string& new_pin) const + { + module()->C_SetPIN(m_handle, old_pin, new_pin); + } + +void Session::init_pin(const secure_string& new_pin) + { + module()->C_InitPIN(m_handle, new_pin); + } + +} +} diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_session.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_session.h new file mode 100644 index 0000000000..39b7877cbf --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_session.h @@ -0,0 +1,15 @@ +/* +* PKCS#11 Session +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_SESSION_H_ +#define BOTAN_P11_SESSION_H_ + +#include +BOTAN_DEPRECATED_HEADER(p11_session.h) + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.cpp new file mode 100644 index 0000000000..5c6ce91ad4 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.cpp @@ -0,0 +1,60 @@ +/* +* PKCS#11 Slot +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +namespace PKCS11 { + +Slot::Slot(Module& module, SlotId slot_id) + : m_module(module), m_slot_id(slot_id) + {} + +SlotInfo Slot::get_slot_info() const + { + SlotInfo slot_info = {}; + m_module.get()->C_GetSlotInfo(m_slot_id, &slot_info); + return slot_info; + } + +std::vector Slot::get_mechanism_list() const + { + std::vector mechanism_list; + m_module.get()->C_GetMechanismList(m_slot_id, mechanism_list); + return mechanism_list; + } + +MechanismInfo Slot::get_mechanism_info(MechanismType mechanism_type) const + { + MechanismInfo mechanism_info = {}; + m_module.get()->C_GetMechanismInfo(m_slot_id, mechanism_type, &mechanism_info); + return mechanism_info; + } + +std::vector Slot::get_available_slots(Module& module, bool token_present) + { + std::vector slot_vec; + module->C_GetSlotList(token_present, slot_vec); + return slot_vec; + } + +TokenInfo Slot::get_token_info() const + { + TokenInfo token_info; + m_module.get()->C_GetTokenInfo(m_slot_id, &token_info); + return token_info; + } + +void Slot::initialize(const std::string& label, const secure_string& so_pin) const + { + m_module.get()->C_InitToken(m_slot_id, so_pin, label); + } +} + +} diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.h new file mode 100644 index 0000000000..0a33ed5f41 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_slot.h @@ -0,0 +1,15 @@ +/* +* PKCS#11 Slot +* (C) 2016 Daniel Neus +* (C) 2016 Philipp Weber +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_SLOT_H_ +#define BOTAN_P11_SLOT_H_ + +#include +BOTAN_DEPRECATED_HEADER(p11_slot.h) + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_types.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_types.h new file mode 100644 index 0000000000..bd445da3ca --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_types.h @@ -0,0 +1,209 @@ +/* +* PKCS#11 Module/Slot/Session +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_TYPES_H_ +#define BOTAN_P11_TYPES_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class Dynamically_Loaded_Library; + +namespace PKCS11 { + +/** +* Loads the PKCS#11 shared library +* Calls C_Initialize on load and C_Finalize on destruction +*/ +class BOTAN_PUBLIC_API(2,0) Module final + { + public: + /** + * Loads the shared library and calls C_Initialize + * @param file_path the path to the PKCS#11 shared library + * @param init_args flags to use for `C_Initialize` + */ + Module(const std::string& file_path, C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr }); + + Module(Module&& other); + Module& operator=(Module&& other) = delete; + + // Dtor calls C_Finalize(). A copy could be deleted while the origin still exists + // Furthermore std::unique_ptr member -> not copyable + Module(const Module& other) = delete; + Module& operator=(const Module& other) = delete; + + /// Calls C_Finalize() + ~Module() noexcept; + + /** + * Reloads the module and reinitializes it + * @param init_args flags to use for `C_Initialize` + */ + void reload(C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr }); + + inline LowLevel* operator->() const + { + return m_low_level.get(); + } + + /// @return general information about Cryptoki + inline Info get_info() const + { + Info info; + m_low_level->C_GetInfo(&info); + return info; + } + + private: + const std::string m_file_path; + FunctionListPtr m_func_list = nullptr; + std::unique_ptr m_library; + std::unique_ptr m_low_level = nullptr; + }; + +/// Represents a PKCS#11 Slot, i.e., a card reader +class BOTAN_PUBLIC_API(2,0) Slot final + { + public: + /** + * @param module the PKCS#11 module to use + * @param slot_id the slot id to use + */ + Slot(Module& module, SlotId slot_id); + + /// @return a reference to the module that is used + inline Module& module() const + { + return m_module; + } + + /// @return the slot id + inline SlotId slot_id() const + { + return m_slot_id; + } + + /** + * Get available slots + * @param module the module to use + * @param token_present true if only slots with attached tokens should be returned, false for all slots + * @return a list of available slots (calls C_GetSlotList) + */ + static std::vector get_available_slots(Module& module, bool token_present); + + /// @return information about the slot (`C_GetSlotInfo`) + SlotInfo get_slot_info() const; + + /// Obtains a list of mechanism types supported by the slot (`C_GetMechanismList`) + std::vector get_mechanism_list() const; + + /// Obtains information about a particular mechanism possibly supported by a slot (`C_GetMechanismInfo`) + MechanismInfo get_mechanism_info(MechanismType mechanism_type) const; + + /// Obtains information about a particular token in the system (`C_GetTokenInfo`) + TokenInfo get_token_info() const; + + /** + * Calls `C_InitToken` to initialize the token + * @param label the label for the token (must not exceed 32 bytes according to PKCS#11) + * @param so_pin the PIN of the security officer + */ + void initialize(const std::string& label, const secure_string& so_pin) const; + + private: + const std::reference_wrapper m_module; + const SlotId m_slot_id; + }; + +/// Represents a PKCS#11 session +class BOTAN_PUBLIC_API(2,0) Session final + { + public: + /** + * @param slot the slot to use + * @param read_only true if the session should be read only, false to create a read-write session + */ + Session(Slot& slot, bool read_only); + + /** + * @param slot the slot to use + * @param flags the flags to use for the session. Remark: Flag::SerialSession is mandatory + * @param callback_data application-defined pointer to be passed to the notification callback + * @param notify_callback address of the notification callback function + */ + Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback); + + /// Takes ownership of a session + Session(Slot& slot, SessionHandle handle); + + Session(Session&& other) = default; + Session& operator=(Session&& other) = delete; + + // Dtor calls C_CloseSession() and eventually C_Logout. A copy could close the session while the origin still exists + Session(const Session& other) = delete; + Session& operator=(const Session& other) = delete; + + /// Logout user and close the session on destruction + ~Session() noexcept; + + /// @return a reference to the slot + inline const Slot& slot() const + { + return m_slot; + } + + /// @return the session handle of this session + inline SessionHandle handle() const + { + return m_handle; + } + + /// @return a reference to the used module + inline Module& module() const + { + return m_slot.module(); + } + + /// @return the released session handle + SessionHandle release(); + + /** + * Login to this session + * @param userType the user type to use for the login + * @param pin the PIN of the user + */ + void login(UserType userType, const secure_string& pin); + + /// Logout from this session + void logoff(); + + /// @return information about this session + SessionInfo get_info() const; + + /// Calls `C_SetPIN` to change the PIN using the old PIN (requires a logged in session) + void set_pin(const secure_string& old_pin, const secure_string& new_pin) const; + + /// Calls `C_InitPIN` to change or initialize the PIN using the SO_PIN (requires a logged in session) + void init_pin(const secure_string& new_pin); + + private: + const Slot& m_slot; + SessionHandle m_handle; + bool m_logged_in; + }; + +} +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.cpp b/comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.cpp new file mode 100644 index 0000000000..5c6accdf08 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.cpp @@ -0,0 +1,37 @@ +/* +* PKCS#11 X.509 +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + +namespace Botan { +namespace PKCS11 { + +X509_CertificateProperties::X509_CertificateProperties(const std::vector& subject, const std::vector& value) + : CertificateProperties(CertificateType::X509), m_subject(subject), m_value(value) + { + add_binary(AttributeType::Subject, m_subject); + add_binary(AttributeType::Value, m_value); + } + +PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, ObjectHandle handle) + : Object(session, handle), X509_Certificate(unlock(get_attribute_value(AttributeType::Value))) + { + } + +PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props) + : Object(session, props), X509_Certificate(props.value()) + { + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.h b/comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.h new file mode 100644 index 0000000000..d3eafbe352 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/p11_x509.h @@ -0,0 +1,117 @@ +/* +* PKCS#11 X.509 +* (C) 2016 Daniel Neus, Sirrix AG +* (C) 2016 Philipp Weber, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_P11_X509_H_ +#define BOTAN_P11_X509_H_ + +#include + +#if defined(BOTAN_HAS_X509_CERTIFICATES) + +#include +#include + +namespace Botan { +namespace PKCS11 { + +class Session; + +/// Common attributes of all PKCS#11 X509 certificates +class BOTAN_PUBLIC_API(2,0) X509_CertificateProperties final : public CertificateProperties + { + public: + /** + * @param subject DER-encoding of the certificate subject name + * @param value BER-encoding of the certificate + */ + X509_CertificateProperties(const std::vector& subject, const std::vector& value); + + X509_CertificateProperties(const X509_Certificate& cert) : + X509_CertificateProperties(cert.raw_subject_dn(), cert.BER_encode()) + {} + + /// @param id key identifier for public/private key pair + inline void set_id(const std::vector& id) + { + add_binary(AttributeType::Id, id); + } + + /// @param issuer DER-encoding of the certificate issuer name + inline void set_issuer(const std::vector& issuer) + { + add_binary(AttributeType::Issuer, issuer); + } + + /// @param serial DER-encoding of the certificate serial number + inline void set_serial(const std::vector& serial) + { + add_binary(AttributeType::SerialNumber, serial); + } + + /// @param hash hash value of the subject public key + inline void set_subject_pubkey_hash(const std::vector& hash) + { + add_binary(AttributeType::HashOfSubjectPublicKey, hash); + } + + /// @param hash hash value of the issuer public key + inline void set_issuer_pubkey_hash(const std::vector& hash) + { + add_binary(AttributeType::HashOfIssuerPublicKey, hash); + } + + /// @param alg defines the mechanism used to calculate `CKA_HASH_OF_SUBJECT_PUBLIC_KEY` and `CKA_HASH_OF_ISSUER_PUBLIC_KEY` + inline void set_hash_alg(MechanismType alg) + { + add_numeric(AttributeType::NameHashAlgorithm, static_cast(alg)); + } + + /// @return the subject + inline const std::vector& subject() const + { + return m_subject; + } + + /// @return the BER-encoding of the certificate + inline const std::vector& value() const + { + return m_value; + } + + private: + const std::vector m_subject; + const std::vector m_value; + }; + +/// Represents a PKCS#11 X509 certificate +class BOTAN_PUBLIC_API(2,0) PKCS11_X509_Certificate final : public Object, public X509_Certificate + { + public: + static const ObjectClass Class = ObjectClass::Certificate; + + /** + * Create a PKCS11_X509_Certificate object from an existing PKCS#11 X509 cert + * @param session the session to use + * @param handle the handle of the X.509 certificate + */ + PKCS11_X509_Certificate(Session& session, ObjectHandle handle); + + /** + * Imports a X.509 certificate + * @param session the session to use + * @param props the attributes of the X.509 certificate + */ + PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props); + }; + +} +} + +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11.h b/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11.h new file mode 100644 index 0000000000..c66b0bca98 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11.h @@ -0,0 +1,264 @@ +/* + * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01 + * Committee Specification Draft 01 / Public Review Draft 01 + * 09 December 2015 + * Copyright (c) OASIS Open 2015. All Rights Reserved. + * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/ + * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html + * https://www.oasis-open.org/policies-guidelines/ipr + */ + +#ifndef _PKCS11_H_ +#define _PKCS11_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Before including this file (pkcs11.h) (or pkcs11t.h by + * itself), 5 platform-specific macros must be defined. These + * macros are described below, and typical definitions for them + * are also given. Be advised that these definitions can depend + * on both the platform and the compiler used (and possibly also + * on whether a Cryptoki library is linked statically or + * dynamically). + * + * In addition to defining these 5 macros, the packing convention + * for Cryptoki structures should be set. The Cryptoki + * convention on packing is that structures should be 1-byte + * aligned. + * + * If you're using Microsoft Developer Studio 5.0 to produce + * Win32 stuff, this might be done by using the following + * preprocessor directive before including pkcs11.h or pkcs11t.h: + * + * #pragma pack(push, cryptoki, 1) + * + * and using the following preprocessor directive after including + * pkcs11.h or pkcs11t.h: + * + * #pragma pack(pop, cryptoki) + * + * If you're using an earlier version of Microsoft Developer + * Studio to produce Win16 stuff, this might be done by using + * the following preprocessor directive before including + * pkcs11.h or pkcs11t.h: + * + * #pragma pack(1) + * + * In a UNIX environment, you're on your own for this. You might + * not need to do (or be able to do!) anything. + * + * + * Now for the macros: + * + * + * 1. CK_PTR: The indirection string for making a pointer to an + * object. It can be used like this: + * + * typedef CK_BYTE CK_PTR CK_BYTE_PTR; + * + * If you're using Microsoft Developer Studio 5.0 to produce + * Win32 stuff, it might be defined by: + * + * #define CK_PTR * + * + * If you're using an earlier version of Microsoft Developer + * Studio to produce Win16 stuff, it might be defined by: + * + * #define CK_PTR far * + * + * In a typical UNIX environment, it might be defined by: + * + * #define CK_PTR * + * + * + * 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes + * an importable Cryptoki library function declaration out of a + * return type and a function name. It should be used in the + * following fashion: + * + * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( + * CK_VOID_PTR pReserved + * ); + * + * If you're using Microsoft Developer Studio 5.0 to declare a + * function in a Win32 Cryptoki .dll, it might be defined by: + * + * #define CK_DECLARE_FUNCTION(returnType, name) \ + * returnType __declspec(dllimport) name + * + * If you're using an earlier version of Microsoft Developer + * Studio to declare a function in a Win16 Cryptoki .dll, it + * might be defined by: + * + * #define CK_DECLARE_FUNCTION(returnType, name) \ + * returnType __export _far _pascal name + * + * In a UNIX environment, it might be defined by: + * + * #define CK_DECLARE_FUNCTION(returnType, name) \ + * returnType name + * + * + * 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro + * which makes a Cryptoki API function pointer declaration or + * function pointer type declaration out of a return type and a + * function name. It should be used in the following fashion: + * + * // Define funcPtr to be a pointer to a Cryptoki API function + * // taking arguments args and returning CK_RV. + * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); + * + * or + * + * // Define funcPtrType to be the type of a pointer to a + * // Cryptoki API function taking arguments args and returning + * // CK_RV, and then define funcPtr to be a variable of type + * // funcPtrType. + * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); + * funcPtrType funcPtr; + * + * If you're using Microsoft Developer Studio 5.0 to access + * functions in a Win32 Cryptoki .dll, in might be defined by: + * + * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + * returnType __declspec(dllimport) (* name) + * + * If you're using an earlier version of Microsoft Developer + * Studio to access functions in a Win16 Cryptoki .dll, it might + * be defined by: + * + * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + * returnType __export _far _pascal (* name) + * + * In a UNIX environment, it might be defined by: + * + * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ + * returnType (* name) + * + * + * 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes + * a function pointer type for an application callback out of + * a return type for the callback and a name for the callback. + * It should be used in the following fashion: + * + * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); + * + * to declare a function pointer, myCallback, to a callback + * which takes arguments args and returns a CK_RV. It can also + * be used like this: + * + * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); + * myCallbackType myCallback; + * + * If you're using Microsoft Developer Studio 5.0 to do Win32 + * Cryptoki development, it might be defined by: + * + * #define CK_CALLBACK_FUNCTION(returnType, name) \ + * returnType (* name) + * + * If you're using an earlier version of Microsoft Developer + * Studio to do Win16 development, it might be defined by: + * + * #define CK_CALLBACK_FUNCTION(returnType, name) \ + * returnType _far _pascal (* name) + * + * In a UNIX environment, it might be defined by: + * + * #define CK_CALLBACK_FUNCTION(returnType, name) \ + * returnType (* name) + * + * + * 5. NULL_PTR: This macro is the value of a NULL pointer. + * + * In any ANSI/ISO C environment (and in many others as well), + * this should best be defined by + * + * #ifndef NULL_PTR + * #define NULL_PTR 0 + * #endif + */ + + +/* All the various Cryptoki types and #define'd values are in the + * file pkcs11t.h. + */ +#include "pkcs11t.h" + +#define __PASTE(x,y) x##y + + +/* ============================================================== + * Define the "extern" form of all the entry points. + * ============================================================== + */ + +#define CK_NEED_ARG_LIST 1 +#define CK_PKCS11_FUNCTION_INFO(name) \ + extern CK_DECLARE_FUNCTION(CK_RV, name) + +/* pkcs11f.h has all the information about the Cryptoki + * function prototypes. + */ +#include "pkcs11f.h" + +#undef CK_NEED_ARG_LIST +#undef CK_PKCS11_FUNCTION_INFO + + +/* ============================================================== + * Define the typedef form of all the entry points. That is, for + * each Cryptoki function C_XXX, define a type CK_C_XXX which is + * a pointer to that kind of function. + * ============================================================== + */ + +#define CK_NEED_ARG_LIST 1 +#define CK_PKCS11_FUNCTION_INFO(name) \ + typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name)) + +/* pkcs11f.h has all the information about the Cryptoki + * function prototypes. + */ +#include "pkcs11f.h" + +#undef CK_NEED_ARG_LIST +#undef CK_PKCS11_FUNCTION_INFO + + +/* ============================================================== + * Define structed vector of entry points. A CK_FUNCTION_LIST + * contains a CK_VERSION indicating a library's Cryptoki version + * and then a whole slew of function pointers to the routines in + * the library. This type was declared, but not defined, in + * pkcs11t.h. + * ============================================================== + */ + +#define CK_PKCS11_FUNCTION_INFO(name) \ + __PASTE(CK_,name) name; + +struct CK_FUNCTION_LIST { + + CK_VERSION version; /* Cryptoki version */ + +/* Pile all the function pointers into the CK_FUNCTION_LIST. */ +/* pkcs11f.h has all the information about the Cryptoki + * function prototypes. + */ +#include "pkcs11f.h" + +}; + +#undef CK_PKCS11_FUNCTION_INFO + + +#undef __PASTE + +#ifdef __cplusplus +} +#endif + +#endif /* _PKCS11_H_ */ + diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11f.h b/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11f.h new file mode 100644 index 0000000000..48ba5726f0 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11f.h @@ -0,0 +1,938 @@ +/* + * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01 + * Committee Specification Draft 01 / Public Review Draft 01 + * 09 December 2015 + * Copyright (c) OASIS Open 2015. All Rights Reserved. + * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/ + * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html + * https://www.oasis-open.org/policies-guidelines/ipr + */ + +/* This header file contains pretty much everything about all the + * Cryptoki function prototypes. Because this information is + * used for more than just declaring function prototypes, the + * order of the functions appearing herein is important, and + * should not be altered. + */ + +/* General-purpose */ + +/* C_Initialize initializes the Cryptoki library. */ +CK_PKCS11_FUNCTION_INFO(C_Initialize) +#ifdef CK_NEED_ARG_LIST +( + CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets + * cast to CK_C_INITIALIZE_ARGS_PTR + * and dereferenced + */ +); +#endif + + +/* C_Finalize indicates that an application is done with the + * Cryptoki library. + */ +CK_PKCS11_FUNCTION_INFO(C_Finalize) +#ifdef CK_NEED_ARG_LIST +( + CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */ +); +#endif + + +/* C_GetInfo returns general information about Cryptoki. */ +CK_PKCS11_FUNCTION_INFO(C_GetInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_INFO_PTR pInfo /* location that receives information */ +); +#endif + + +/* C_GetFunctionList returns the function list. */ +CK_PKCS11_FUNCTION_INFO(C_GetFunctionList) +#ifdef CK_NEED_ARG_LIST +( + CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to + * function list + */ +); +#endif + + + +/* Slot and token management */ + +/* C_GetSlotList obtains a list of slots in the system. */ +CK_PKCS11_FUNCTION_INFO(C_GetSlotList) +#ifdef CK_NEED_ARG_LIST +( + CK_BBOOL tokenPresent, /* only slots with tokens */ + CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */ + CK_ULONG_PTR pulCount /* receives number of slots */ +); +#endif + + +/* C_GetSlotInfo obtains information about a particular slot in + * the system. + */ +CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* the ID of the slot */ + CK_SLOT_INFO_PTR pInfo /* receives the slot information */ +); +#endif + + +/* C_GetTokenInfo obtains information about a particular token + * in the system. + */ +CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of the token's slot */ + CK_TOKEN_INFO_PTR pInfo /* receives the token information */ +); +#endif + + +/* C_GetMechanismList obtains a list of mechanism types + * supported by a token. + */ +CK_PKCS11_FUNCTION_INFO(C_GetMechanismList) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of token's slot */ + CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */ + CK_ULONG_PTR pulCount /* gets # of mechs. */ +); +#endif + + +/* C_GetMechanismInfo obtains information about a particular + * mechanism possibly supported by a token. + */ +CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of the token's slot */ + CK_MECHANISM_TYPE type, /* type of mechanism */ + CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */ +); +#endif + + +/* C_InitToken initializes a token. */ +CK_PKCS11_FUNCTION_INFO(C_InitToken) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* ID of the token's slot */ + CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */ + CK_ULONG ulPinLen, /* length in bytes of the PIN */ + CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */ +); +#endif + + +/* C_InitPIN initializes the normal user's PIN. */ +CK_PKCS11_FUNCTION_INFO(C_InitPIN) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */ + CK_ULONG ulPinLen /* length in bytes of the PIN */ +); +#endif + + +/* C_SetPIN modifies the PIN of the user who is logged in. */ +CK_PKCS11_FUNCTION_INFO(C_SetPIN) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_UTF8CHAR_PTR pOldPin, /* the old PIN */ + CK_ULONG ulOldLen, /* length of the old PIN */ + CK_UTF8CHAR_PTR pNewPin, /* the new PIN */ + CK_ULONG ulNewLen /* length of the new PIN */ +); +#endif + + + +/* Session management */ + +/* C_OpenSession opens a session between an application and a + * token. + */ +CK_PKCS11_FUNCTION_INFO(C_OpenSession) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID, /* the slot's ID */ + CK_FLAGS flags, /* from CK_SESSION_INFO */ + CK_VOID_PTR pApplication, /* passed to callback */ + CK_NOTIFY Notify, /* callback function */ + CK_SESSION_HANDLE_PTR phSession /* gets session handle */ +); +#endif + + +/* C_CloseSession closes a session between an application and a + * token. + */ +CK_PKCS11_FUNCTION_INFO(C_CloseSession) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + +/* C_CloseAllSessions closes all sessions with a token. */ +CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions) +#ifdef CK_NEED_ARG_LIST +( + CK_SLOT_ID slotID /* the token's slot */ +); +#endif + + +/* C_GetSessionInfo obtains information about the session. */ +CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_SESSION_INFO_PTR pInfo /* receives session info */ +); +#endif + + +/* C_GetOperationState obtains the state of the cryptographic operation + * in a session. + */ +CK_PKCS11_FUNCTION_INFO(C_GetOperationState) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pOperationState, /* gets state */ + CK_ULONG_PTR pulOperationStateLen /* gets state length */ +); +#endif + + +/* C_SetOperationState restores the state of the cryptographic + * operation in a session. + */ +CK_PKCS11_FUNCTION_INFO(C_SetOperationState) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pOperationState, /* holds state */ + CK_ULONG ulOperationStateLen, /* holds state length */ + CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */ + CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */ +); +#endif + + +/* C_Login logs a user into a token. */ +CK_PKCS11_FUNCTION_INFO(C_Login) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_USER_TYPE userType, /* the user type */ + CK_UTF8CHAR_PTR pPin, /* the user's PIN */ + CK_ULONG ulPinLen /* the length of the PIN */ +); +#endif + + +/* C_Logout logs a user out from a token. */ +CK_PKCS11_FUNCTION_INFO(C_Logout) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + + +/* Object management */ + +/* C_CreateObject creates a new object. */ +CK_PKCS11_FUNCTION_INFO(C_CreateObject) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* the object's template */ + CK_ULONG ulCount, /* attributes in template */ + CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */ +); +#endif + + +/* C_CopyObject copies an object, creating a new object for the + * copy. + */ +CK_PKCS11_FUNCTION_INFO(C_CopyObject) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* template for new object */ + CK_ULONG ulCount, /* attributes in template */ + CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */ +); +#endif + + +/* C_DestroyObject destroys an object. */ +CK_PKCS11_FUNCTION_INFO(C_DestroyObject) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject /* the object's handle */ +); +#endif + + +/* C_GetObjectSize gets the size of an object in bytes. */ +CK_PKCS11_FUNCTION_INFO(C_GetObjectSize) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ULONG_PTR pulSize /* receives size of object */ +); +#endif + + +/* C_GetAttributeValue obtains the value of one or more object + * attributes. + */ +CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */ + CK_ULONG ulCount /* attributes in template */ +); +#endif + + +/* C_SetAttributeValue modifies the value of one or more object + * attributes. + */ +CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hObject, /* the object's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */ + CK_ULONG ulCount /* attributes in template */ +); +#endif + + +/* C_FindObjectsInit initializes a search for token and session + * objects that match a template. + */ +CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */ + CK_ULONG ulCount /* attrs in search template */ +); +#endif + + +/* C_FindObjects continues a search for token and session + * objects that match a template, obtaining additional object + * handles. + */ +CK_PKCS11_FUNCTION_INFO(C_FindObjects) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */ + CK_ULONG ulMaxObjectCount, /* max handles to get */ + CK_ULONG_PTR pulObjectCount /* actual # returned */ +); +#endif + + +/* C_FindObjectsFinal finishes a search for token and session + * objects. + */ +CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + + +/* Encryption and decryption */ + +/* C_EncryptInit initializes an encryption operation. */ +CK_PKCS11_FUNCTION_INFO(C_EncryptInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ + CK_OBJECT_HANDLE hKey /* handle of encryption key */ +); +#endif + + +/* C_Encrypt encrypts single-part data. */ +CK_PKCS11_FUNCTION_INFO(C_Encrypt) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pData, /* the plaintext data */ + CK_ULONG ulDataLen, /* bytes of plaintext */ + CK_BYTE_PTR pEncryptedData, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */ +); +#endif + + +/* C_EncryptUpdate continues a multiple-part encryption + * operation. + */ +CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pPart, /* the plaintext data */ + CK_ULONG ulPartLen, /* plaintext data len */ + CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */ +); +#endif + + +/* C_EncryptFinal finishes a multiple-part encryption + * operation. + */ +CK_PKCS11_FUNCTION_INFO(C_EncryptFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session handle */ + CK_BYTE_PTR pLastEncryptedPart, /* last c-text */ + CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */ +); +#endif + + +/* C_DecryptInit initializes a decryption operation. */ +CK_PKCS11_FUNCTION_INFO(C_DecryptInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ + CK_OBJECT_HANDLE hKey /* handle of decryption key */ +); +#endif + + +/* C_Decrypt decrypts encrypted data in a single part. */ +CK_PKCS11_FUNCTION_INFO(C_Decrypt) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedData, /* ciphertext */ + CK_ULONG ulEncryptedDataLen, /* ciphertext length */ + CK_BYTE_PTR pData, /* gets plaintext */ + CK_ULONG_PTR pulDataLen /* gets p-text size */ +); +#endif + + +/* C_DecryptUpdate continues a multiple-part decryption + * operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedPart, /* encrypted data */ + CK_ULONG ulEncryptedPartLen, /* input length */ + CK_BYTE_PTR pPart, /* gets plaintext */ + CK_ULONG_PTR pulPartLen /* p-text size */ +); +#endif + + +/* C_DecryptFinal finishes a multiple-part decryption + * operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DecryptFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pLastPart, /* gets plaintext */ + CK_ULONG_PTR pulLastPartLen /* p-text size */ +); +#endif + + + +/* Message digesting */ + +/* C_DigestInit initializes a message-digesting operation. */ +CK_PKCS11_FUNCTION_INFO(C_DigestInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism /* the digesting mechanism */ +); +#endif + + +/* C_Digest digests data in a single part. */ +CK_PKCS11_FUNCTION_INFO(C_Digest) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* data to be digested */ + CK_ULONG ulDataLen, /* bytes of data to digest */ + CK_BYTE_PTR pDigest, /* gets the message digest */ + CK_ULONG_PTR pulDigestLen /* gets digest length */ +); +#endif + + +/* C_DigestUpdate continues a multiple-part message-digesting + * operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DigestUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pPart, /* data to be digested */ + CK_ULONG ulPartLen /* bytes of data to be digested */ +); +#endif + + +/* C_DigestKey continues a multi-part message-digesting + * operation, by digesting the value of a secret key as part of + * the data already digested. + */ +CK_PKCS11_FUNCTION_INFO(C_DigestKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_OBJECT_HANDLE hKey /* secret key to digest */ +); +#endif + + +/* C_DigestFinal finishes a multiple-part message-digesting + * operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DigestFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pDigest, /* gets the message digest */ + CK_ULONG_PTR pulDigestLen /* gets byte count of digest */ +); +#endif + + + +/* Signing and MACing */ + +/* C_SignInit initializes a signature (private key encryption) + * operation, where the signature is (will be) an appendix to + * the data, and plaintext cannot be recovered from the + * signature. + */ +CK_PKCS11_FUNCTION_INFO(C_SignInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ + CK_OBJECT_HANDLE hKey /* handle of signature key */ +); +#endif + + +/* C_Sign signs (encrypts with private key) data in a single + * part, where the signature is (will be) an appendix to the + * data, and plaintext cannot be recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_Sign) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* the data to sign */ + CK_ULONG ulDataLen, /* count of bytes to sign */ + CK_BYTE_PTR pSignature, /* gets the signature */ + CK_ULONG_PTR pulSignatureLen /* gets signature length */ +); +#endif + + +/* C_SignUpdate continues a multiple-part signature operation, + * where the signature is (will be) an appendix to the data, + * and plaintext cannot be recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_SignUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pPart, /* the data to sign */ + CK_ULONG ulPartLen /* count of bytes to sign */ +); +#endif + + +/* C_SignFinal finishes a multiple-part signature operation, + * returning the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_SignFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSignature, /* gets the signature */ + CK_ULONG_PTR pulSignatureLen /* gets signature length */ +); +#endif + + +/* C_SignRecoverInit initializes a signature operation, where + * the data can be recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ + CK_OBJECT_HANDLE hKey /* handle of the signature key */ +); +#endif + + +/* C_SignRecover signs data in a single operation, where the + * data can be recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_SignRecover) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* the data to sign */ + CK_ULONG ulDataLen, /* count of bytes to sign */ + CK_BYTE_PTR pSignature, /* gets the signature */ + CK_ULONG_PTR pulSignatureLen /* gets signature length */ +); +#endif + + + +/* Verifying signatures and MACs */ + +/* C_VerifyInit initializes a verification operation, where the + * signature is an appendix to the data, and plaintext cannot + * cannot be recovered from the signature (e.g. DSA). + */ +CK_PKCS11_FUNCTION_INFO(C_VerifyInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ + CK_OBJECT_HANDLE hKey /* verification key */ +); +#endif + + +/* C_Verify verifies a signature in a single-part operation, + * where the signature is an appendix to the data, and plaintext + * cannot be recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_Verify) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pData, /* signed data */ + CK_ULONG ulDataLen, /* length of signed data */ + CK_BYTE_PTR pSignature, /* signature */ + CK_ULONG ulSignatureLen /* signature length*/ +); +#endif + + +/* C_VerifyUpdate continues a multiple-part verification + * operation, where the signature is an appendix to the data, + * and plaintext cannot be recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pPart, /* signed data */ + CK_ULONG ulPartLen /* length of signed data */ +); +#endif + + +/* C_VerifyFinal finishes a multiple-part verification + * operation, checking the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_VerifyFinal) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSignature, /* signature to verify */ + CK_ULONG ulSignatureLen /* signature length */ +); +#endif + + +/* C_VerifyRecoverInit initializes a signature verification + * operation, where the data is recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ + CK_OBJECT_HANDLE hKey /* verification key */ +); +#endif + + +/* C_VerifyRecover verifies a signature in a single-part + * operation, where the data is recovered from the signature. + */ +CK_PKCS11_FUNCTION_INFO(C_VerifyRecover) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSignature, /* signature to verify */ + CK_ULONG ulSignatureLen, /* signature length */ + CK_BYTE_PTR pData, /* gets signed data */ + CK_ULONG_PTR pulDataLen /* gets signed data len */ +); +#endif + + + +/* Dual-function cryptographic operations */ + +/* C_DigestEncryptUpdate continues a multiple-part digesting + * and encryption operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pPart, /* the plaintext data */ + CK_ULONG ulPartLen, /* plaintext length */ + CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ +); +#endif + + +/* C_DecryptDigestUpdate continues a multiple-part decryption and + * digesting operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedPart, /* ciphertext */ + CK_ULONG ulEncryptedPartLen, /* ciphertext length */ + CK_BYTE_PTR pPart, /* gets plaintext */ + CK_ULONG_PTR pulPartLen /* gets plaintext len */ +); +#endif + + +/* C_SignEncryptUpdate continues a multiple-part signing and + * encryption operation. + */ +CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pPart, /* the plaintext data */ + CK_ULONG ulPartLen, /* plaintext length */ + CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ + CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ +); +#endif + + +/* C_DecryptVerifyUpdate continues a multiple-part decryption and + * verify operation. + */ +CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_BYTE_PTR pEncryptedPart, /* ciphertext */ + CK_ULONG ulEncryptedPartLen, /* ciphertext length */ + CK_BYTE_PTR pPart, /* gets plaintext */ + CK_ULONG_PTR pulPartLen /* gets p-text length */ +); +#endif + + + +/* Key management */ + +/* C_GenerateKey generates a secret key, creating a new key + * object. + */ +CK_PKCS11_FUNCTION_INFO(C_GenerateKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* key generation mech. */ + CK_ATTRIBUTE_PTR pTemplate, /* template for new key */ + CK_ULONG ulCount, /* # of attrs in template */ + CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */ +); +#endif + + +/* C_GenerateKeyPair generates a public-key/private-key pair, + * creating new key objects. + */ +CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session handle */ + CK_MECHANISM_PTR pMechanism, /* key-gen mech. */ + CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template for pub. key */ + CK_ULONG ulPublicKeyAttributeCount, /* # pub. attrs. */ + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template for priv. key */ + CK_ULONG ulPrivateKeyAttributeCount, /* # priv. attrs. */ + CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */ + CK_OBJECT_HANDLE_PTR phPrivateKey /* gets priv. key handle */ +); +#endif + + +/* C_WrapKey wraps (i.e., encrypts) a key. */ +CK_PKCS11_FUNCTION_INFO(C_WrapKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */ + CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */ + CK_OBJECT_HANDLE hKey, /* key to be wrapped */ + CK_BYTE_PTR pWrappedKey, /* gets wrapped key */ + CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */ +); +#endif + + +/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new + * key object. + */ +CK_PKCS11_FUNCTION_INFO(C_UnwrapKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */ + CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */ + CK_BYTE_PTR pWrappedKey, /* the wrapped key */ + CK_ULONG ulWrappedKeyLen, /* wrapped key len */ + CK_ATTRIBUTE_PTR pTemplate, /* new key template */ + CK_ULONG ulAttributeCount, /* template length */ + CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ +); +#endif + + +/* C_DeriveKey derives a key from a base key, creating a new key + * object. + */ +CK_PKCS11_FUNCTION_INFO(C_DeriveKey) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* session's handle */ + CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */ + CK_OBJECT_HANDLE hBaseKey, /* base key */ + CK_ATTRIBUTE_PTR pTemplate, /* new key template */ + CK_ULONG ulAttributeCount, /* template length */ + CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ +); +#endif + + + +/* Random number generation */ + +/* C_SeedRandom mixes additional seed material into the token's + * random number generator. + */ +CK_PKCS11_FUNCTION_INFO(C_SeedRandom) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR pSeed, /* the seed material */ + CK_ULONG ulSeedLen /* length of seed material */ +); +#endif + + +/* C_GenerateRandom generates random data. */ +CK_PKCS11_FUNCTION_INFO(C_GenerateRandom) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_BYTE_PTR RandomData, /* receives the random data */ + CK_ULONG ulRandomLen /* # of bytes to generate */ +); +#endif + + + +/* Parallel function management */ + +/* C_GetFunctionStatus is a legacy function; it obtains an + * updated status of a function running in parallel with an + * application. + */ +CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + +/* C_CancelFunction is a legacy function; it cancels a function + * running in parallel. + */ +CK_PKCS11_FUNCTION_INFO(C_CancelFunction) +#ifdef CK_NEED_ARG_LIST +( + CK_SESSION_HANDLE hSession /* the session's handle */ +); +#endif + + +/* C_WaitForSlotEvent waits for a slot event (token insertion, + * removal, etc.) to occur. + */ +CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent) +#ifdef CK_NEED_ARG_LIST +( + CK_FLAGS flags, /* blocking/nonblocking flag */ + CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ + CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */ +); +#endif + diff --git a/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11t.h b/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11t.h new file mode 100644 index 0000000000..c183ea9741 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/pkcs11/pkcs11t.h @@ -0,0 +1,2002 @@ +/* + * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01 + * Committee Specification Draft 01 / Public Review Draft 01 + * 09 December 2015 + * Copyright (c) OASIS Open 2015. All Rights Reserved. + * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/ + * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html + * https://www.oasis-open.org/policies-guidelines/ipr + */ + +/* See top of pkcs11.h for information about the macros that + * must be defined and the structure-packing conventions that + * must be set before including this file. + */ + +#ifndef _PKCS11T_H_ +#define _PKCS11T_H_ 1 + +#define CRYPTOKI_VERSION_MAJOR 2 +#define CRYPTOKI_VERSION_MINOR 40 +#define CRYPTOKI_VERSION_AMENDMENT 0 + +#define CK_TRUE 1 +#define CK_FALSE 0 + +#ifndef CK_DISABLE_TRUE_FALSE +#ifndef FALSE +#define FALSE CK_FALSE +#endif +#ifndef TRUE +#define TRUE CK_TRUE +#endif +#endif + +/* an unsigned 8-bit value */ +typedef unsigned char CK_BYTE; + +/* an unsigned 8-bit character */ +typedef CK_BYTE CK_CHAR; + +/* an 8-bit UTF-8 character */ +typedef CK_BYTE CK_UTF8CHAR; + +/* a BYTE-sized Boolean flag */ +typedef CK_BYTE CK_BBOOL; + +/* an unsigned value, at least 32 bits long */ +typedef unsigned long int CK_ULONG; + +/* a signed value, the same size as a CK_ULONG */ +typedef long int CK_LONG; + +/* at least 32 bits; each bit is a Boolean flag */ +typedef CK_ULONG CK_FLAGS; + + +/* some special values for certain CK_ULONG variables */ +#define CK_UNAVAILABLE_INFORMATION (~0UL) +#define CK_EFFECTIVELY_INFINITE 0UL + + +typedef CK_BYTE CK_PTR CK_BYTE_PTR; +typedef CK_CHAR CK_PTR CK_CHAR_PTR; +typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR; +typedef CK_ULONG CK_PTR CK_ULONG_PTR; +typedef void CK_PTR CK_VOID_PTR; + +/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */ +typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; + + +/* The following value is always invalid if used as a session + * handle or object handle + */ +#define CK_INVALID_HANDLE 0UL + + +typedef struct CK_VERSION { + CK_BYTE major; /* integer portion of version number */ + CK_BYTE minor; /* 1/100ths portion of version number */ +} CK_VERSION; + +typedef CK_VERSION CK_PTR CK_VERSION_PTR; + + +typedef struct CK_INFO { + CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS flags; /* must be zero */ + CK_UTF8CHAR libraryDescription[32]; /* blank padded */ + CK_VERSION libraryVersion; /* version of library */ +} CK_INFO; + +typedef CK_INFO CK_PTR CK_INFO_PTR; + + +/* CK_NOTIFICATION enumerates the types of notifications that + * Cryptoki provides to an application + */ +typedef CK_ULONG CK_NOTIFICATION; +#define CKN_SURRENDER 0UL +#define CKN_OTP_CHANGED 1UL + +typedef CK_ULONG CK_SLOT_ID; + +typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR; + + +/* CK_SLOT_INFO provides information about a slot */ +typedef struct CK_SLOT_INFO { + CK_UTF8CHAR slotDescription[64]; /* blank padded */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_FLAGS flags; + + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ +} CK_SLOT_INFO; + +/* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ +#define CKF_TOKEN_PRESENT 0x00000001UL /* a token is there */ +#define CKF_REMOVABLE_DEVICE 0x00000002UL /* removable devices*/ +#define CKF_HW_SLOT 0x00000004UL /* hardware slot */ + +typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR; + + +/* CK_TOKEN_INFO provides information about a token */ +typedef struct CK_TOKEN_INFO { + CK_UTF8CHAR label[32]; /* blank padded */ + CK_UTF8CHAR manufacturerID[32]; /* blank padded */ + CK_UTF8CHAR model[16]; /* blank padded */ + CK_CHAR serialNumber[16]; /* blank padded */ + CK_FLAGS flags; /* see below */ + + CK_ULONG ulMaxSessionCount; /* max open sessions */ + CK_ULONG ulSessionCount; /* sess. now open */ + CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */ + CK_ULONG ulRwSessionCount; /* R/W sess. now open */ + CK_ULONG ulMaxPinLen; /* in bytes */ + CK_ULONG ulMinPinLen; /* in bytes */ + CK_ULONG ulTotalPublicMemory; /* in bytes */ + CK_ULONG ulFreePublicMemory; /* in bytes */ + CK_ULONG ulTotalPrivateMemory; /* in bytes */ + CK_ULONG ulFreePrivateMemory; /* in bytes */ + CK_VERSION hardwareVersion; /* version of hardware */ + CK_VERSION firmwareVersion; /* version of firmware */ + CK_CHAR utcTime[16]; /* time */ +} CK_TOKEN_INFO; + +/* The flags parameter is defined as follows: + * Bit Flag Mask Meaning + */ +#define CKF_RNG 0x00000001UL /* has random # generator */ +#define CKF_WRITE_PROTECTED 0x00000002UL /* token is write-protected */ +#define CKF_LOGIN_REQUIRED 0x00000004UL /* user must login */ +#define CKF_USER_PIN_INITIALIZED 0x00000008UL /* normal user's PIN is set */ + +/* CKF_RESTORE_KEY_NOT_NEEDED. If it is set, + * that means that *every* time the state of cryptographic + * operations of a session is successfully saved, all keys + * needed to continue those operations are stored in the state + */ +#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020UL + +/* CKF_CLOCK_ON_TOKEN. If it is set, that means + * that the token has some sort of clock. The time on that + * clock is returned in the token info structure + */ +#define CKF_CLOCK_ON_TOKEN 0x00000040UL + +/* CKF_PROTECTED_AUTHENTICATION_PATH. If it is + * set, that means that there is some way for the user to login + * without sending a PIN through the Cryptoki library itself + */ +#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100UL + +/* CKF_DUAL_CRYPTO_OPERATIONS. If it is true, + * that means that a single session with the token can perform + * dual simultaneous cryptographic operations (digest and + * encrypt; decrypt and digest; sign and encrypt; and decrypt + * and sign) + */ +#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200UL + +/* CKF_TOKEN_INITIALIZED. If it is true, the + * token has been initialized using C_InitializeToken or an + * equivalent mechanism outside the scope of PKCS #11. + * Calling C_InitializeToken when this flag is set will cause + * the token to be reinitialized. + */ +#define CKF_TOKEN_INITIALIZED 0x00000400UL + +/* CKF_SECONDARY_AUTHENTICATION. If it is + * true, the token supports secondary authentication for + * private key objects. + */ +#define CKF_SECONDARY_AUTHENTICATION 0x00000800UL + +/* CKF_USER_PIN_COUNT_LOW. If it is true, an + * incorrect user login PIN has been entered at least once + * since the last successful authentication. + */ +#define CKF_USER_PIN_COUNT_LOW 0x00010000UL + +/* CKF_USER_PIN_FINAL_TRY. If it is true, + * supplying an incorrect user PIN will it to become locked. + */ +#define CKF_USER_PIN_FINAL_TRY 0x00020000UL + +/* CKF_USER_PIN_LOCKED. If it is true, the + * user PIN has been locked. User login to the token is not + * possible. + */ +#define CKF_USER_PIN_LOCKED 0x00040000UL + +/* CKF_USER_PIN_TO_BE_CHANGED. If it is true, + * the user PIN value is the default value set by token + * initialization or manufacturing, or the PIN has been + * expired by the card. + */ +#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000UL + +/* CKF_SO_PIN_COUNT_LOW. If it is true, an + * incorrect SO login PIN has been entered at least once since + * the last successful authentication. + */ +#define CKF_SO_PIN_COUNT_LOW 0x00100000UL + +/* CKF_SO_PIN_FINAL_TRY. If it is true, + * supplying an incorrect SO PIN will it to become locked. + */ +#define CKF_SO_PIN_FINAL_TRY 0x00200000UL + +/* CKF_SO_PIN_LOCKED. If it is true, the SO + * PIN has been locked. SO login to the token is not possible. + */ +#define CKF_SO_PIN_LOCKED 0x00400000UL + +/* CKF_SO_PIN_TO_BE_CHANGED. If it is true, + * the SO PIN value is the default value set by token + * initialization or manufacturing, or the PIN has been + * expired by the card. + */ +#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000UL + +#define CKF_ERROR_STATE 0x01000000UL + +typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR; + + +/* CK_SESSION_HANDLE is a Cryptoki-assigned value that + * identifies a session + */ +typedef CK_ULONG CK_SESSION_HANDLE; + +typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; + + +/* CK_USER_TYPE enumerates the types of Cryptoki users */ +typedef CK_ULONG CK_USER_TYPE; +/* Security Officer */ +#define CKU_SO 0UL +/* Normal user */ +#define CKU_USER 1UL +/* Context specific */ +#define CKU_CONTEXT_SPECIFIC 2UL + +/* CK_STATE enumerates the session states */ +typedef CK_ULONG CK_STATE; +#define CKS_RO_PUBLIC_SESSION 0UL +#define CKS_RO_USER_FUNCTIONS 1UL +#define CKS_RW_PUBLIC_SESSION 2UL +#define CKS_RW_USER_FUNCTIONS 3UL +#define CKS_RW_SO_FUNCTIONS 4UL + +/* CK_SESSION_INFO provides information about a session */ +typedef struct CK_SESSION_INFO { + CK_SLOT_ID slotID; + CK_STATE state; + CK_FLAGS flags; /* see below */ + CK_ULONG ulDeviceError; /* device-dependent error code */ +} CK_SESSION_INFO; + +/* The flags are defined in the following table: + * Bit Flag Mask Meaning + */ +#define CKF_RW_SESSION 0x00000002UL /* session is r/w */ +#define CKF_SERIAL_SESSION 0x00000004UL /* no parallel */ + +typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR; + + +/* CK_OBJECT_HANDLE is a token-specific identifier for an + * object + */ +typedef CK_ULONG CK_OBJECT_HANDLE; + +typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR; + + +/* CK_OBJECT_CLASS is a value that identifies the classes (or + * types) of objects that Cryptoki recognizes. It is defined + * as follows: + */ +typedef CK_ULONG CK_OBJECT_CLASS; + +/* The following classes of objects are defined: */ +#define CKO_DATA 0x00000000UL +#define CKO_CERTIFICATE 0x00000001UL +#define CKO_PUBLIC_KEY 0x00000002UL +#define CKO_PRIVATE_KEY 0x00000003UL +#define CKO_SECRET_KEY 0x00000004UL +#define CKO_HW_FEATURE 0x00000005UL +#define CKO_DOMAIN_PARAMETERS 0x00000006UL +#define CKO_MECHANISM 0x00000007UL +#define CKO_OTP_KEY 0x00000008UL + +#define CKO_VENDOR_DEFINED 0x80000000UL + +typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; + +/* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type + * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. + */ +typedef CK_ULONG CK_HW_FEATURE_TYPE; + +/* The following hardware feature types are defined */ +#define CKH_MONOTONIC_COUNTER 0x00000001UL +#define CKH_CLOCK 0x00000002UL +#define CKH_USER_INTERFACE 0x00000003UL +#define CKH_VENDOR_DEFINED 0x80000000UL + +/* CK_KEY_TYPE is a value that identifies a key type */ +typedef CK_ULONG CK_KEY_TYPE; + +/* the following key types are defined: */ +#define CKK_RSA 0x00000000UL +#define CKK_DSA 0x00000001UL +#define CKK_DH 0x00000002UL +#define CKK_ECDSA 0x00000003UL /* Deprecated */ +#define CKK_EC 0x00000003UL +#define CKK_X9_42_DH 0x00000004UL +#define CKK_KEA 0x00000005UL +#define CKK_GENERIC_SECRET 0x00000010UL +#define CKK_RC2 0x00000011UL +#define CKK_RC4 0x00000012UL +#define CKK_DES 0x00000013UL +#define CKK_DES2 0x00000014UL +#define CKK_DES3 0x00000015UL +#define CKK_CAST 0x00000016UL +#define CKK_CAST3 0x00000017UL +#define CKK_CAST5 0x00000018UL /* Deprecated */ +#define CKK_CAST128 0x00000018UL +#define CKK_RC5 0x00000019UL +#define CKK_IDEA 0x0000001AUL +#define CKK_SKIPJACK 0x0000001BUL +#define CKK_BATON 0x0000001CUL +#define CKK_JUNIPER 0x0000001DUL +#define CKK_CDMF 0x0000001EUL +#define CKK_AES 0x0000001FUL +#define CKK_BLOWFISH 0x00000020UL +#define CKK_TWOFISH 0x00000021UL +#define CKK_SECURID 0x00000022UL +#define CKK_HOTP 0x00000023UL +#define CKK_ACTI 0x00000024UL +#define CKK_CAMELLIA 0x00000025UL +#define CKK_ARIA 0x00000026UL + +#define CKK_MD5_HMAC 0x00000027UL +#define CKK_SHA_1_HMAC 0x00000028UL +#define CKK_RIPEMD128_HMAC 0x00000029UL +#define CKK_RIPEMD160_HMAC 0x0000002AUL +#define CKK_SHA256_HMAC 0x0000002BUL +#define CKK_SHA384_HMAC 0x0000002CUL +#define CKK_SHA512_HMAC 0x0000002DUL +#define CKK_SHA224_HMAC 0x0000002EUL + +#define CKK_SEED 0x0000002FUL +#define CKK_GOSTR3410 0x00000030UL +#define CKK_GOSTR3411 0x00000031UL +#define CKK_GOST28147 0x00000032UL + + + +#define CKK_VENDOR_DEFINED 0x80000000UL + + +/* CK_CERTIFICATE_TYPE is a value that identifies a certificate + * type + */ +typedef CK_ULONG CK_CERTIFICATE_TYPE; + +#define CK_CERTIFICATE_CATEGORY_UNSPECIFIED 0UL +#define CK_CERTIFICATE_CATEGORY_TOKEN_USER 1UL +#define CK_CERTIFICATE_CATEGORY_AUTHORITY 2UL +#define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY 3UL + +#define CK_SECURITY_DOMAIN_UNSPECIFIED 0UL +#define CK_SECURITY_DOMAIN_MANUFACTURER 1UL +#define CK_SECURITY_DOMAIN_OPERATOR 2UL +#define CK_SECURITY_DOMAIN_THIRD_PARTY 3UL + + +/* The following certificate types are defined: */ +#define CKC_X_509 0x00000000UL +#define CKC_X_509_ATTR_CERT 0x00000001UL +#define CKC_WTLS 0x00000002UL +#define CKC_VENDOR_DEFINED 0x80000000UL + + +/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute + * type + */ +typedef CK_ULONG CK_ATTRIBUTE_TYPE; + +/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which + * consists of an array of values. + */ +#define CKF_ARRAY_ATTRIBUTE 0x40000000UL + +/* The following OTP-related defines relate to the CKA_OTP_FORMAT attribute */ +#define CK_OTP_FORMAT_DECIMAL 0UL +#define CK_OTP_FORMAT_HEXADECIMAL 1UL +#define CK_OTP_FORMAT_ALPHANUMERIC 2UL +#define CK_OTP_FORMAT_BINARY 3UL + +/* The following OTP-related defines relate to the CKA_OTP_..._REQUIREMENT + * attributes + */ +#define CK_OTP_PARAM_IGNORED 0UL +#define CK_OTP_PARAM_OPTIONAL 1UL +#define CK_OTP_PARAM_MANDATORY 2UL + +/* The following attribute types are defined: */ +#define CKA_CLASS 0x00000000UL +#define CKA_TOKEN 0x00000001UL +#define CKA_PRIVATE 0x00000002UL +#define CKA_LABEL 0x00000003UL +#define CKA_APPLICATION 0x00000010UL +#define CKA_VALUE 0x00000011UL +#define CKA_OBJECT_ID 0x00000012UL +#define CKA_CERTIFICATE_TYPE 0x00000080UL +#define CKA_ISSUER 0x00000081UL +#define CKA_SERIAL_NUMBER 0x00000082UL +#define CKA_AC_ISSUER 0x00000083UL +#define CKA_OWNER 0x00000084UL +#define CKA_ATTR_TYPES 0x00000085UL +#define CKA_TRUSTED 0x00000086UL +#define CKA_CERTIFICATE_CATEGORY 0x00000087UL +#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088UL +#define CKA_URL 0x00000089UL +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008AUL +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008BUL +#define CKA_NAME_HASH_ALGORITHM 0x0000008CUL +#define CKA_CHECK_VALUE 0x00000090UL + +#define CKA_KEY_TYPE 0x00000100UL +#define CKA_SUBJECT 0x00000101UL +#define CKA_ID 0x00000102UL +#define CKA_SENSITIVE 0x00000103UL +#define CKA_ENCRYPT 0x00000104UL +#define CKA_DECRYPT 0x00000105UL +#define CKA_WRAP 0x00000106UL +#define CKA_UNWRAP 0x00000107UL +#define CKA_SIGN 0x00000108UL +#define CKA_SIGN_RECOVER 0x00000109UL +#define CKA_VERIFY 0x0000010AUL +#define CKA_VERIFY_RECOVER 0x0000010BUL +#define CKA_DERIVE 0x0000010CUL +#define CKA_START_DATE 0x00000110UL +#define CKA_END_DATE 0x00000111UL +#define CKA_MODULUS 0x00000120UL +#define CKA_MODULUS_BITS 0x00000121UL +#define CKA_PUBLIC_EXPONENT 0x00000122UL +#define CKA_PRIVATE_EXPONENT 0x00000123UL +#define CKA_PRIME_1 0x00000124UL +#define CKA_PRIME_2 0x00000125UL +#define CKA_EXPONENT_1 0x00000126UL +#define CKA_EXPONENT_2 0x00000127UL +#define CKA_COEFFICIENT 0x00000128UL +#define CKA_PUBLIC_KEY_INFO 0x00000129UL +#define CKA_PRIME 0x00000130UL +#define CKA_SUBPRIME 0x00000131UL +#define CKA_BASE 0x00000132UL + +#define CKA_PRIME_BITS 0x00000133UL +#define CKA_SUBPRIME_BITS 0x00000134UL +#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS + +#define CKA_VALUE_BITS 0x00000160UL +#define CKA_VALUE_LEN 0x00000161UL +#define CKA_EXTRACTABLE 0x00000162UL +#define CKA_LOCAL 0x00000163UL +#define CKA_NEVER_EXTRACTABLE 0x00000164UL +#define CKA_ALWAYS_SENSITIVE 0x00000165UL +#define CKA_KEY_GEN_MECHANISM 0x00000166UL + +#define CKA_MODIFIABLE 0x00000170UL +#define CKA_COPYABLE 0x00000171UL + +#define CKA_DESTROYABLE 0x00000172UL + +#define CKA_ECDSA_PARAMS 0x00000180UL /* Deprecated */ +#define CKA_EC_PARAMS 0x00000180UL + +#define CKA_EC_POINT 0x00000181UL + +#define CKA_SECONDARY_AUTH 0x00000200UL /* Deprecated */ +#define CKA_AUTH_PIN_FLAGS 0x00000201UL /* Deprecated */ + +#define CKA_ALWAYS_AUTHENTICATE 0x00000202UL + +#define CKA_WRAP_WITH_TRUSTED 0x00000210UL +#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211UL) +#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212UL) +#define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000213UL) + +#define CKA_OTP_FORMAT 0x00000220UL +#define CKA_OTP_LENGTH 0x00000221UL +#define CKA_OTP_TIME_INTERVAL 0x00000222UL +#define CKA_OTP_USER_FRIENDLY_MODE 0x00000223UL +#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224UL +#define CKA_OTP_TIME_REQUIREMENT 0x00000225UL +#define CKA_OTP_COUNTER_REQUIREMENT 0x00000226UL +#define CKA_OTP_PIN_REQUIREMENT 0x00000227UL +#define CKA_OTP_COUNTER 0x0000022EUL +#define CKA_OTP_TIME 0x0000022FUL +#define CKA_OTP_USER_IDENTIFIER 0x0000022AUL +#define CKA_OTP_SERVICE_IDENTIFIER 0x0000022BUL +#define CKA_OTP_SERVICE_LOGO 0x0000022CUL +#define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022DUL + +#define CKA_GOSTR3410_PARAMS 0x00000250UL +#define CKA_GOSTR3411_PARAMS 0x00000251UL +#define CKA_GOST28147_PARAMS 0x00000252UL + +#define CKA_HW_FEATURE_TYPE 0x00000300UL +#define CKA_RESET_ON_INIT 0x00000301UL +#define CKA_HAS_RESET 0x00000302UL + +#define CKA_PIXEL_X 0x00000400UL +#define CKA_PIXEL_Y 0x00000401UL +#define CKA_RESOLUTION 0x00000402UL +#define CKA_CHAR_ROWS 0x00000403UL +#define CKA_CHAR_COLUMNS 0x00000404UL +#define CKA_COLOR 0x00000405UL +#define CKA_BITS_PER_PIXEL 0x00000406UL +#define CKA_CHAR_SETS 0x00000480UL +#define CKA_ENCODING_METHODS 0x00000481UL +#define CKA_MIME_TYPES 0x00000482UL +#define CKA_MECHANISM_TYPE 0x00000500UL +#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501UL +#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502UL +#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503UL +#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600UL) + +#define CKA_VENDOR_DEFINED 0x80000000UL + +/* CK_ATTRIBUTE is a structure that includes the type, length + * and value of an attribute + */ +typedef struct CK_ATTRIBUTE { + CK_ATTRIBUTE_TYPE type; + CK_VOID_PTR pValue; + CK_ULONG ulValueLen; /* in bytes */ +} CK_ATTRIBUTE; + +typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR; + +/* CK_DATE is a structure that defines a date */ +typedef struct CK_DATE{ + CK_CHAR year[4]; /* the year ("1900" - "9999") */ + CK_CHAR month[2]; /* the month ("01" - "12") */ + CK_CHAR day[2]; /* the day ("01" - "31") */ +} CK_DATE; + + +/* CK_MECHANISM_TYPE is a value that identifies a mechanism + * type + */ +typedef CK_ULONG CK_MECHANISM_TYPE; + +/* the following mechanism types are defined: */ +#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL +#define CKM_RSA_PKCS 0x00000001UL +#define CKM_RSA_9796 0x00000002UL +#define CKM_RSA_X_509 0x00000003UL + +#define CKM_MD2_RSA_PKCS 0x00000004UL +#define CKM_MD5_RSA_PKCS 0x00000005UL +#define CKM_SHA1_RSA_PKCS 0x00000006UL + +#define CKM_RIPEMD128_RSA_PKCS 0x00000007UL +#define CKM_RIPEMD160_RSA_PKCS 0x00000008UL +#define CKM_RSA_PKCS_OAEP 0x00000009UL + +#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000AUL +#define CKM_RSA_X9_31 0x0000000BUL +#define CKM_SHA1_RSA_X9_31 0x0000000CUL +#define CKM_RSA_PKCS_PSS 0x0000000DUL +#define CKM_SHA1_RSA_PKCS_PSS 0x0000000EUL + +#define CKM_DSA_KEY_PAIR_GEN 0x00000010UL +#define CKM_DSA 0x00000011UL +#define CKM_DSA_SHA1 0x00000012UL +#define CKM_DSA_SHA224 0x00000013UL +#define CKM_DSA_SHA256 0x00000014UL +#define CKM_DSA_SHA384 0x00000015UL +#define CKM_DSA_SHA512 0x00000016UL + +#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL +#define CKM_DH_PKCS_DERIVE 0x00000021UL + +#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030UL +#define CKM_X9_42_DH_DERIVE 0x00000031UL +#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032UL +#define CKM_X9_42_MQV_DERIVE 0x00000033UL + +#define CKM_SHA256_RSA_PKCS 0x00000040UL +#define CKM_SHA384_RSA_PKCS 0x00000041UL +#define CKM_SHA512_RSA_PKCS 0x00000042UL +#define CKM_SHA256_RSA_PKCS_PSS 0x00000043UL +#define CKM_SHA384_RSA_PKCS_PSS 0x00000044UL +#define CKM_SHA512_RSA_PKCS_PSS 0x00000045UL + +#define CKM_SHA224_RSA_PKCS 0x00000046UL +#define CKM_SHA224_RSA_PKCS_PSS 0x00000047UL + +#define CKM_SHA512_224 0x00000048UL +#define CKM_SHA512_224_HMAC 0x00000049UL +#define CKM_SHA512_224_HMAC_GENERAL 0x0000004AUL +#define CKM_SHA512_224_KEY_DERIVATION 0x0000004BUL +#define CKM_SHA512_256 0x0000004CUL +#define CKM_SHA512_256_HMAC 0x0000004DUL +#define CKM_SHA512_256_HMAC_GENERAL 0x0000004EUL +#define CKM_SHA512_256_KEY_DERIVATION 0x0000004FUL + +#define CKM_SHA512_T 0x00000050UL +#define CKM_SHA512_T_HMAC 0x00000051UL +#define CKM_SHA512_T_HMAC_GENERAL 0x00000052UL +#define CKM_SHA512_T_KEY_DERIVATION 0x00000053UL + +#define CKM_RC2_KEY_GEN 0x00000100UL +#define CKM_RC2_ECB 0x00000101UL +#define CKM_RC2_CBC 0x00000102UL +#define CKM_RC2_MAC 0x00000103UL + +#define CKM_RC2_MAC_GENERAL 0x00000104UL +#define CKM_RC2_CBC_PAD 0x00000105UL + +#define CKM_RC4_KEY_GEN 0x00000110UL +#define CKM_RC4 0x00000111UL +#define CKM_DES_KEY_GEN 0x00000120UL +#define CKM_DES_ECB 0x00000121UL +#define CKM_DES_CBC 0x00000122UL +#define CKM_DES_MAC 0x00000123UL + +#define CKM_DES_MAC_GENERAL 0x00000124UL +#define CKM_DES_CBC_PAD 0x00000125UL + +#define CKM_DES2_KEY_GEN 0x00000130UL +#define CKM_DES3_KEY_GEN 0x00000131UL +#define CKM_DES3_ECB 0x00000132UL +#define CKM_DES3_CBC 0x00000133UL +#define CKM_DES3_MAC 0x00000134UL + +#define CKM_DES3_MAC_GENERAL 0x00000135UL +#define CKM_DES3_CBC_PAD 0x00000136UL +#define CKM_DES3_CMAC_GENERAL 0x00000137UL +#define CKM_DES3_CMAC 0x00000138UL +#define CKM_CDMF_KEY_GEN 0x00000140UL +#define CKM_CDMF_ECB 0x00000141UL +#define CKM_CDMF_CBC 0x00000142UL +#define CKM_CDMF_MAC 0x00000143UL +#define CKM_CDMF_MAC_GENERAL 0x00000144UL +#define CKM_CDMF_CBC_PAD 0x00000145UL + +#define CKM_DES_OFB64 0x00000150UL +#define CKM_DES_OFB8 0x00000151UL +#define CKM_DES_CFB64 0x00000152UL +#define CKM_DES_CFB8 0x00000153UL + +#define CKM_MD2 0x00000200UL + +#define CKM_MD2_HMAC 0x00000201UL +#define CKM_MD2_HMAC_GENERAL 0x00000202UL + +#define CKM_MD5 0x00000210UL + +#define CKM_MD5_HMAC 0x00000211UL +#define CKM_MD5_HMAC_GENERAL 0x00000212UL + +#define CKM_SHA_1 0x00000220UL + +#define CKM_SHA_1_HMAC 0x00000221UL +#define CKM_SHA_1_HMAC_GENERAL 0x00000222UL + +#define CKM_RIPEMD128 0x00000230UL +#define CKM_RIPEMD128_HMAC 0x00000231UL +#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232UL +#define CKM_RIPEMD160 0x00000240UL +#define CKM_RIPEMD160_HMAC 0x00000241UL +#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242UL + +#define CKM_SHA256 0x00000250UL +#define CKM_SHA256_HMAC 0x00000251UL +#define CKM_SHA256_HMAC_GENERAL 0x00000252UL +#define CKM_SHA224 0x00000255UL +#define CKM_SHA224_HMAC 0x00000256UL +#define CKM_SHA224_HMAC_GENERAL 0x00000257UL +#define CKM_SHA384 0x00000260UL +#define CKM_SHA384_HMAC 0x00000261UL +#define CKM_SHA384_HMAC_GENERAL 0x00000262UL +#define CKM_SHA512 0x00000270UL +#define CKM_SHA512_HMAC 0x00000271UL +#define CKM_SHA512_HMAC_GENERAL 0x00000272UL +#define CKM_SECURID_KEY_GEN 0x00000280UL +#define CKM_SECURID 0x00000282UL +#define CKM_HOTP_KEY_GEN 0x00000290UL +#define CKM_HOTP 0x00000291UL +#define CKM_ACTI 0x000002A0UL +#define CKM_ACTI_KEY_GEN 0x000002A1UL + +#define CKM_CAST_KEY_GEN 0x00000300UL +#define CKM_CAST_ECB 0x00000301UL +#define CKM_CAST_CBC 0x00000302UL +#define CKM_CAST_MAC 0x00000303UL +#define CKM_CAST_MAC_GENERAL 0x00000304UL +#define CKM_CAST_CBC_PAD 0x00000305UL +#define CKM_CAST3_KEY_GEN 0x00000310UL +#define CKM_CAST3_ECB 0x00000311UL +#define CKM_CAST3_CBC 0x00000312UL +#define CKM_CAST3_MAC 0x00000313UL +#define CKM_CAST3_MAC_GENERAL 0x00000314UL +#define CKM_CAST3_CBC_PAD 0x00000315UL +/* Note that CAST128 and CAST5 are the same algorithm */ +#define CKM_CAST5_KEY_GEN 0x00000320UL +#define CKM_CAST128_KEY_GEN 0x00000320UL +#define CKM_CAST5_ECB 0x00000321UL +#define CKM_CAST128_ECB 0x00000321UL +#define CKM_CAST5_CBC 0x00000322UL /* Deprecated */ +#define CKM_CAST128_CBC 0x00000322UL +#define CKM_CAST5_MAC 0x00000323UL /* Deprecated */ +#define CKM_CAST128_MAC 0x00000323UL +#define CKM_CAST5_MAC_GENERAL 0x00000324UL /* Deprecated */ +#define CKM_CAST128_MAC_GENERAL 0x00000324UL +#define CKM_CAST5_CBC_PAD 0x00000325UL /* Deprecated */ +#define CKM_CAST128_CBC_PAD 0x00000325UL +#define CKM_RC5_KEY_GEN 0x00000330UL +#define CKM_RC5_ECB 0x00000331UL +#define CKM_RC5_CBC 0x00000332UL +#define CKM_RC5_MAC 0x00000333UL +#define CKM_RC5_MAC_GENERAL 0x00000334UL +#define CKM_RC5_CBC_PAD 0x00000335UL +#define CKM_IDEA_KEY_GEN 0x00000340UL +#define CKM_IDEA_ECB 0x00000341UL +#define CKM_IDEA_CBC 0x00000342UL +#define CKM_IDEA_MAC 0x00000343UL +#define CKM_IDEA_MAC_GENERAL 0x00000344UL +#define CKM_IDEA_CBC_PAD 0x00000345UL +#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350UL +#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360UL +#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362UL +#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363UL +#define CKM_XOR_BASE_AND_DATA 0x00000364UL +#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365UL +#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370UL +#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371UL +#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372UL + +#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373UL +#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374UL +#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375UL +#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376UL +#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377UL + +#define CKM_TLS_PRF 0x00000378UL + +#define CKM_SSL3_MD5_MAC 0x00000380UL +#define CKM_SSL3_SHA1_MAC 0x00000381UL +#define CKM_MD5_KEY_DERIVATION 0x00000390UL +#define CKM_MD2_KEY_DERIVATION 0x00000391UL +#define CKM_SHA1_KEY_DERIVATION 0x00000392UL + +#define CKM_SHA256_KEY_DERIVATION 0x00000393UL +#define CKM_SHA384_KEY_DERIVATION 0x00000394UL +#define CKM_SHA512_KEY_DERIVATION 0x00000395UL +#define CKM_SHA224_KEY_DERIVATION 0x00000396UL + +#define CKM_PBE_MD2_DES_CBC 0x000003A0UL +#define CKM_PBE_MD5_DES_CBC 0x000003A1UL +#define CKM_PBE_MD5_CAST_CBC 0x000003A2UL +#define CKM_PBE_MD5_CAST3_CBC 0x000003A3UL +#define CKM_PBE_MD5_CAST5_CBC 0x000003A4UL /* Deprecated */ +#define CKM_PBE_MD5_CAST128_CBC 0x000003A4UL +#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5UL /* Deprecated */ +#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5UL +#define CKM_PBE_SHA1_RC4_128 0x000003A6UL +#define CKM_PBE_SHA1_RC4_40 0x000003A7UL +#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8UL +#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9UL +#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AAUL +#define CKM_PBE_SHA1_RC2_40_CBC 0x000003ABUL + +#define CKM_PKCS5_PBKD2 0x000003B0UL + +#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0UL + +#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0UL +#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1UL +#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2UL +#define CKM_WTLS_PRF 0x000003D3UL +#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4UL +#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5UL + +#define CKM_TLS10_MAC_SERVER 0x000003D6UL +#define CKM_TLS10_MAC_CLIENT 0x000003D7UL +#define CKM_TLS12_MAC 0x000003D8UL +#define CKM_TLS12_KDF 0x000003D9UL +#define CKM_TLS12_MASTER_KEY_DERIVE 0x000003E0UL +#define CKM_TLS12_KEY_AND_MAC_DERIVE 0x000003E1UL +#define CKM_TLS12_MASTER_KEY_DERIVE_DH 0x000003E2UL +#define CKM_TLS12_KEY_SAFE_DERIVE 0x000003E3UL +#define CKM_TLS_MAC 0x000003E4UL +#define CKM_TLS_KDF 0x000003E5UL + +#define CKM_KEY_WRAP_LYNKS 0x00000400UL +#define CKM_KEY_WRAP_SET_OAEP 0x00000401UL + +#define CKM_CMS_SIG 0x00000500UL +#define CKM_KIP_DERIVE 0x00000510UL +#define CKM_KIP_WRAP 0x00000511UL +#define CKM_KIP_MAC 0x00000512UL + +#define CKM_CAMELLIA_KEY_GEN 0x00000550UL +#define CKM_CAMELLIA_ECB 0x00000551UL +#define CKM_CAMELLIA_CBC 0x00000552UL +#define CKM_CAMELLIA_MAC 0x00000553UL +#define CKM_CAMELLIA_MAC_GENERAL 0x00000554UL +#define CKM_CAMELLIA_CBC_PAD 0x00000555UL +#define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556UL +#define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557UL +#define CKM_CAMELLIA_CTR 0x00000558UL + +#define CKM_ARIA_KEY_GEN 0x00000560UL +#define CKM_ARIA_ECB 0x00000561UL +#define CKM_ARIA_CBC 0x00000562UL +#define CKM_ARIA_MAC 0x00000563UL +#define CKM_ARIA_MAC_GENERAL 0x00000564UL +#define CKM_ARIA_CBC_PAD 0x00000565UL +#define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566UL +#define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567UL + +#define CKM_SEED_KEY_GEN 0x00000650UL +#define CKM_SEED_ECB 0x00000651UL +#define CKM_SEED_CBC 0x00000652UL +#define CKM_SEED_MAC 0x00000653UL +#define CKM_SEED_MAC_GENERAL 0x00000654UL +#define CKM_SEED_CBC_PAD 0x00000655UL +#define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656UL +#define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657UL + +#define CKM_SKIPJACK_KEY_GEN 0x00001000UL +#define CKM_SKIPJACK_ECB64 0x00001001UL +#define CKM_SKIPJACK_CBC64 0x00001002UL +#define CKM_SKIPJACK_OFB64 0x00001003UL +#define CKM_SKIPJACK_CFB64 0x00001004UL +#define CKM_SKIPJACK_CFB32 0x00001005UL +#define CKM_SKIPJACK_CFB16 0x00001006UL +#define CKM_SKIPJACK_CFB8 0x00001007UL +#define CKM_SKIPJACK_WRAP 0x00001008UL +#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009UL +#define CKM_SKIPJACK_RELAYX 0x0000100aUL +#define CKM_KEA_KEY_PAIR_GEN 0x00001010UL +#define CKM_KEA_KEY_DERIVE 0x00001011UL +#define CKM_KEA_DERIVE 0x00001012UL +#define CKM_FORTEZZA_TIMESTAMP 0x00001020UL +#define CKM_BATON_KEY_GEN 0x00001030UL +#define CKM_BATON_ECB128 0x00001031UL +#define CKM_BATON_ECB96 0x00001032UL +#define CKM_BATON_CBC128 0x00001033UL +#define CKM_BATON_COUNTER 0x00001034UL +#define CKM_BATON_SHUFFLE 0x00001035UL +#define CKM_BATON_WRAP 0x00001036UL + +#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040UL /* Deprecated */ +#define CKM_EC_KEY_PAIR_GEN 0x00001040UL + +#define CKM_ECDSA 0x00001041UL +#define CKM_ECDSA_SHA1 0x00001042UL +#define CKM_ECDSA_SHA224 0x00001043UL +#define CKM_ECDSA_SHA256 0x00001044UL +#define CKM_ECDSA_SHA384 0x00001045UL +#define CKM_ECDSA_SHA512 0x00001046UL + +#define CKM_ECDH1_DERIVE 0x00001050UL +#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051UL +#define CKM_ECMQV_DERIVE 0x00001052UL + +#define CKM_ECDH_AES_KEY_WRAP 0x00001053UL +#define CKM_RSA_AES_KEY_WRAP 0x00001054UL + +#define CKM_JUNIPER_KEY_GEN 0x00001060UL +#define CKM_JUNIPER_ECB128 0x00001061UL +#define CKM_JUNIPER_CBC128 0x00001062UL +#define CKM_JUNIPER_COUNTER 0x00001063UL +#define CKM_JUNIPER_SHUFFLE 0x00001064UL +#define CKM_JUNIPER_WRAP 0x00001065UL +#define CKM_FASTHASH 0x00001070UL + +#define CKM_AES_KEY_GEN 0x00001080UL +#define CKM_AES_ECB 0x00001081UL +#define CKM_AES_CBC 0x00001082UL +#define CKM_AES_MAC 0x00001083UL +#define CKM_AES_MAC_GENERAL 0x00001084UL +#define CKM_AES_CBC_PAD 0x00001085UL +#define CKM_AES_CTR 0x00001086UL +#define CKM_AES_GCM 0x00001087UL +#define CKM_AES_CCM 0x00001088UL +#define CKM_AES_CTS 0x00001089UL +#define CKM_AES_CMAC 0x0000108AUL +#define CKM_AES_CMAC_GENERAL 0x0000108BUL + +#define CKM_AES_XCBC_MAC 0x0000108CUL +#define CKM_AES_XCBC_MAC_96 0x0000108DUL +#define CKM_AES_GMAC 0x0000108EUL + +#define CKM_BLOWFISH_KEY_GEN 0x00001090UL +#define CKM_BLOWFISH_CBC 0x00001091UL +#define CKM_TWOFISH_KEY_GEN 0x00001092UL +#define CKM_TWOFISH_CBC 0x00001093UL +#define CKM_BLOWFISH_CBC_PAD 0x00001094UL +#define CKM_TWOFISH_CBC_PAD 0x00001095UL + +#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100UL +#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101UL +#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102UL +#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103UL +#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104UL +#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105UL + +#define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200UL +#define CKM_GOSTR3410 0x00001201UL +#define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202UL +#define CKM_GOSTR3410_KEY_WRAP 0x00001203UL +#define CKM_GOSTR3410_DERIVE 0x00001204UL +#define CKM_GOSTR3411 0x00001210UL +#define CKM_GOSTR3411_HMAC 0x00001211UL +#define CKM_GOST28147_KEY_GEN 0x00001220UL +#define CKM_GOST28147_ECB 0x00001221UL +#define CKM_GOST28147 0x00001222UL +#define CKM_GOST28147_MAC 0x00001223UL +#define CKM_GOST28147_KEY_WRAP 0x00001224UL + +#define CKM_DSA_PARAMETER_GEN 0x00002000UL +#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001UL +#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002UL +#define CKM_DSA_PROBABLISTIC_PARAMETER_GEN 0x00002003UL +#define CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN 0x00002004UL + +#define CKM_AES_OFB 0x00002104UL +#define CKM_AES_CFB64 0x00002105UL +#define CKM_AES_CFB8 0x00002106UL +#define CKM_AES_CFB128 0x00002107UL + +#define CKM_AES_CFB1 0x00002108UL +#define CKM_AES_KEY_WRAP 0x00002109UL /* WAS: 0x00001090 */ +#define CKM_AES_KEY_WRAP_PAD 0x0000210AUL /* WAS: 0x00001091 */ + +#define CKM_RSA_PKCS_TPM_1_1 0x00004001UL +#define CKM_RSA_PKCS_OAEP_TPM_1_1 0x00004002UL + +#define CKM_VENDOR_DEFINED 0x80000000UL + +typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR; + + +/* CK_MECHANISM is a structure that specifies a particular + * mechanism + */ +typedef struct CK_MECHANISM { + CK_MECHANISM_TYPE mechanism; + CK_VOID_PTR pParameter; + CK_ULONG ulParameterLen; /* in bytes */ +} CK_MECHANISM; + +typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; + + +/* CK_MECHANISM_INFO provides information about a particular + * mechanism + */ +typedef struct CK_MECHANISM_INFO { + CK_ULONG ulMinKeySize; + CK_ULONG ulMaxKeySize; + CK_FLAGS flags; +} CK_MECHANISM_INFO; + +/* The flags are defined as follows: + * Bit Flag Mask Meaning */ +#define CKF_HW 0x00000001UL /* performed by HW */ + +/* Specify whether or not a mechanism can be used for a particular task */ +#define CKF_ENCRYPT 0x00000100UL +#define CKF_DECRYPT 0x00000200UL +#define CKF_DIGEST 0x00000400UL +#define CKF_SIGN 0x00000800UL +#define CKF_SIGN_RECOVER 0x00001000UL +#define CKF_VERIFY 0x00002000UL +#define CKF_VERIFY_RECOVER 0x00004000UL +#define CKF_GENERATE 0x00008000UL +#define CKF_GENERATE_KEY_PAIR 0x00010000UL +#define CKF_WRAP 0x00020000UL +#define CKF_UNWRAP 0x00040000UL +#define CKF_DERIVE 0x00080000UL + +/* Describe a token's EC capabilities not available in mechanism + * information. + */ +#define CKF_EC_F_P 0x00100000UL +#define CKF_EC_F_2M 0x00200000UL +#define CKF_EC_ECPARAMETERS 0x00400000UL +#define CKF_EC_NAMEDCURVE 0x00800000UL +#define CKF_EC_UNCOMPRESS 0x01000000UL +#define CKF_EC_COMPRESS 0x02000000UL + +#define CKF_EXTENSION 0x80000000UL + +typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; + +/* CK_RV is a value that identifies the return value of a + * Cryptoki function + */ +typedef CK_ULONG CK_RV; + +#define CKR_OK 0x00000000UL +#define CKR_CANCEL 0x00000001UL +#define CKR_HOST_MEMORY 0x00000002UL +#define CKR_SLOT_ID_INVALID 0x00000003UL + +#define CKR_GENERAL_ERROR 0x00000005UL +#define CKR_FUNCTION_FAILED 0x00000006UL + +#define CKR_ARGUMENTS_BAD 0x00000007UL +#define CKR_NO_EVENT 0x00000008UL +#define CKR_NEED_TO_CREATE_THREADS 0x00000009UL +#define CKR_CANT_LOCK 0x0000000AUL + +#define CKR_ATTRIBUTE_READ_ONLY 0x00000010UL +#define CKR_ATTRIBUTE_SENSITIVE 0x00000011UL +#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012UL +#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013UL + +#define CKR_ACTION_PROHIBITED 0x0000001BUL + +#define CKR_DATA_INVALID 0x00000020UL +#define CKR_DATA_LEN_RANGE 0x00000021UL +#define CKR_DEVICE_ERROR 0x00000030UL +#define CKR_DEVICE_MEMORY 0x00000031UL +#define CKR_DEVICE_REMOVED 0x00000032UL +#define CKR_ENCRYPTED_DATA_INVALID 0x00000040UL +#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041UL +#define CKR_FUNCTION_CANCELED 0x00000050UL +#define CKR_FUNCTION_NOT_PARALLEL 0x00000051UL + +#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054UL + +#define CKR_KEY_HANDLE_INVALID 0x00000060UL + +#define CKR_KEY_SIZE_RANGE 0x00000062UL +#define CKR_KEY_TYPE_INCONSISTENT 0x00000063UL + +#define CKR_KEY_NOT_NEEDED 0x00000064UL +#define CKR_KEY_CHANGED 0x00000065UL +#define CKR_KEY_NEEDED 0x00000066UL +#define CKR_KEY_INDIGESTIBLE 0x00000067UL +#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068UL +#define CKR_KEY_NOT_WRAPPABLE 0x00000069UL +#define CKR_KEY_UNEXTRACTABLE 0x0000006AUL + +#define CKR_MECHANISM_INVALID 0x00000070UL +#define CKR_MECHANISM_PARAM_INVALID 0x00000071UL + +#define CKR_OBJECT_HANDLE_INVALID 0x00000082UL +#define CKR_OPERATION_ACTIVE 0x00000090UL +#define CKR_OPERATION_NOT_INITIALIZED 0x00000091UL +#define CKR_PIN_INCORRECT 0x000000A0UL +#define CKR_PIN_INVALID 0x000000A1UL +#define CKR_PIN_LEN_RANGE 0x000000A2UL + +#define CKR_PIN_EXPIRED 0x000000A3UL +#define CKR_PIN_LOCKED 0x000000A4UL + +#define CKR_SESSION_CLOSED 0x000000B0UL +#define CKR_SESSION_COUNT 0x000000B1UL +#define CKR_SESSION_HANDLE_INVALID 0x000000B3UL +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4UL +#define CKR_SESSION_READ_ONLY 0x000000B5UL +#define CKR_SESSION_EXISTS 0x000000B6UL + +#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7UL +#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8UL + +#define CKR_SIGNATURE_INVALID 0x000000C0UL +#define CKR_SIGNATURE_LEN_RANGE 0x000000C1UL +#define CKR_TEMPLATE_INCOMPLETE 0x000000D0UL +#define CKR_TEMPLATE_INCONSISTENT 0x000000D1UL +#define CKR_TOKEN_NOT_PRESENT 0x000000E0UL +#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1UL +#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2UL +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0UL +#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1UL +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2UL +#define CKR_USER_ALREADY_LOGGED_IN 0x00000100UL +#define CKR_USER_NOT_LOGGED_IN 0x00000101UL +#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102UL +#define CKR_USER_TYPE_INVALID 0x00000103UL + +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104UL +#define CKR_USER_TOO_MANY_TYPES 0x00000105UL + +#define CKR_WRAPPED_KEY_INVALID 0x00000110UL +#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112UL +#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113UL +#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114UL +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115UL +#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120UL + +#define CKR_RANDOM_NO_RNG 0x00000121UL + +#define CKR_DOMAIN_PARAMS_INVALID 0x00000130UL + +#define CKR_CURVE_NOT_SUPPORTED 0x00000140UL + +#define CKR_BUFFER_TOO_SMALL 0x00000150UL +#define CKR_SAVED_STATE_INVALID 0x00000160UL +#define CKR_INFORMATION_SENSITIVE 0x00000170UL +#define CKR_STATE_UNSAVEABLE 0x00000180UL + +#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190UL +#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191UL +#define CKR_MUTEX_BAD 0x000001A0UL +#define CKR_MUTEX_NOT_LOCKED 0x000001A1UL + +#define CKR_NEW_PIN_MODE 0x000001B0UL +#define CKR_NEXT_OTP 0x000001B1UL + +#define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5UL +#define CKR_FIPS_SELF_TEST_FAILED 0x000001B6UL +#define CKR_LIBRARY_LOAD_FAILED 0x000001B7UL +#define CKR_PIN_TOO_WEAK 0x000001B8UL +#define CKR_PUBLIC_KEY_INVALID 0x000001B9UL + +#define CKR_FUNCTION_REJECTED 0x00000200UL + +#define CKR_VENDOR_DEFINED 0x80000000UL + + +/* CK_NOTIFY is an application callback that processes events */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( + CK_SESSION_HANDLE hSession, /* the session's handle */ + CK_NOTIFICATION event, + CK_VOID_PTR pApplication /* passed to C_OpenSession */ +); + + +/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec + * version and pointers of appropriate types to all the + * Cryptoki functions + */ +typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; + +typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; + +typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; + + +/* CK_CREATEMUTEX is an application callback for creating a + * mutex object + */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( + CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */ +); + + +/* CK_DESTROYMUTEX is an application callback for destroying a + * mutex object + */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ +); + + +/* CK_LOCKMUTEX is an application callback for locking a mutex */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ +); + + +/* CK_UNLOCKMUTEX is an application callback for unlocking a + * mutex + */ +typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( + CK_VOID_PTR pMutex /* pointer to mutex */ +); + + +/* CK_C_INITIALIZE_ARGS provides the optional arguments to + * C_Initialize + */ +typedef struct CK_C_INITIALIZE_ARGS { + CK_CREATEMUTEX CreateMutex; + CK_DESTROYMUTEX DestroyMutex; + CK_LOCKMUTEX LockMutex; + CK_UNLOCKMUTEX UnlockMutex; + CK_FLAGS flags; + CK_VOID_PTR pReserved; +} CK_C_INITIALIZE_ARGS; + +/* flags: bit flags that provide capabilities of the slot + * Bit Flag Mask Meaning + */ +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL +#define CKF_OS_LOCKING_OK 0x00000002UL + +typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR; + + +/* additional flags for parameters to functions */ + +/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ +#define CKF_DONT_BLOCK 1 + +/* CK_RSA_PKCS_MGF_TYPE is used to indicate the Message + * Generation Function (MGF) applied to a message block when + * formatting a message block for the PKCS #1 OAEP encryption + * scheme. + */ +typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; + +typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR; + +/* The following MGFs are defined */ +#define CKG_MGF1_SHA1 0x00000001UL +#define CKG_MGF1_SHA256 0x00000002UL +#define CKG_MGF1_SHA384 0x00000003UL +#define CKG_MGF1_SHA512 0x00000004UL +#define CKG_MGF1_SHA224 0x00000005UL + +/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source + * of the encoding parameter when formatting a message block + * for the PKCS #1 OAEP encryption scheme. + */ +typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; + +typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR; + +/* The following encoding parameter sources are defined */ +#define CKZ_DATA_SPECIFIED 0x00000001UL + +/* CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the + * CKM_RSA_PKCS_OAEP mechanism. + */ +typedef struct CK_RSA_PKCS_OAEP_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_RSA_PKCS_OAEP_SOURCE_TYPE source; + CK_VOID_PTR pSourceData; + CK_ULONG ulSourceDataLen; +} CK_RSA_PKCS_OAEP_PARAMS; + +typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR; + +/* CK_RSA_PKCS_PSS_PARAMS provides the parameters to the + * CKM_RSA_PKCS_PSS mechanism(s). + */ +typedef struct CK_RSA_PKCS_PSS_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_ULONG sLen; +} CK_RSA_PKCS_PSS_PARAMS; + +typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR; + +typedef CK_ULONG CK_EC_KDF_TYPE; + +/* The following EC Key Derivation Functions are defined */ +#define CKD_NULL 0x00000001UL +#define CKD_SHA1_KDF 0x00000002UL + +/* The following X9.42 DH key derivation functions are defined */ +#define CKD_SHA1_KDF_ASN1 0x00000003UL +#define CKD_SHA1_KDF_CONCATENATE 0x00000004UL +#define CKD_SHA224_KDF 0x00000005UL +#define CKD_SHA256_KDF 0x00000006UL +#define CKD_SHA384_KDF 0x00000007UL +#define CKD_SHA512_KDF 0x00000008UL +#define CKD_CPDIVERSIFY_KDF 0x00000009UL + + +/* CK_ECDH1_DERIVE_PARAMS provides the parameters to the + * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms, + * where each party contributes one key pair. + */ +typedef struct CK_ECDH1_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_ECDH1_DERIVE_PARAMS; + +typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR; + +/* + * CK_ECDH2_DERIVE_PARAMS provides the parameters to the + * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. + */ +typedef struct CK_ECDH2_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + CK_ULONG ulPublicDataLen2; + CK_BYTE_PTR pPublicData2; +} CK_ECDH2_DERIVE_PARAMS; + +typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR; + +typedef struct CK_ECMQV_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + CK_ULONG ulPublicDataLen2; + CK_BYTE_PTR pPublicData2; + CK_OBJECT_HANDLE publicKey; +} CK_ECMQV_DERIVE_PARAMS; + +typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR; + +/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the + * CKM_X9_42_DH_PARAMETER_GEN mechanisms + */ +typedef CK_ULONG CK_X9_42_DH_KDF_TYPE; +typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR; + +/* CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the + * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party + * contributes one key pair + */ +typedef struct CK_X9_42_DH1_DERIVE_PARAMS { + CK_X9_42_DH_KDF_TYPE kdf; + CK_ULONG ulOtherInfoLen; + CK_BYTE_PTR pOtherInfo; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_X9_42_DH1_DERIVE_PARAMS; + +typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR; + +/* CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the + * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation + * mechanisms, where each party contributes two key pairs + */ +typedef struct CK_X9_42_DH2_DERIVE_PARAMS { + CK_X9_42_DH_KDF_TYPE kdf; + CK_ULONG ulOtherInfoLen; + CK_BYTE_PTR pOtherInfo; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + CK_ULONG ulPublicDataLen2; + CK_BYTE_PTR pPublicData2; +} CK_X9_42_DH2_DERIVE_PARAMS; + +typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR; + +typedef struct CK_X9_42_MQV_DERIVE_PARAMS { + CK_X9_42_DH_KDF_TYPE kdf; + CK_ULONG ulOtherInfoLen; + CK_BYTE_PTR pOtherInfo; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + CK_ULONG ulPublicDataLen2; + CK_BYTE_PTR pPublicData2; + CK_OBJECT_HANDLE publicKey; +} CK_X9_42_MQV_DERIVE_PARAMS; + +typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR; + +/* CK_KEA_DERIVE_PARAMS provides the parameters to the + * CKM_KEA_DERIVE mechanism + */ +typedef struct CK_KEA_DERIVE_PARAMS { + CK_BBOOL isSender; + CK_ULONG ulRandomLen; + CK_BYTE_PTR pRandomA; + CK_BYTE_PTR pRandomB; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_KEA_DERIVE_PARAMS; + +typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR; + + +/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and + * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just + * holds the effective keysize + */ +typedef CK_ULONG CK_RC2_PARAMS; + +typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR; + + +/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC + * mechanism + */ +typedef struct CK_RC2_CBC_PARAMS { + CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ + CK_BYTE iv[8]; /* IV for CBC mode */ +} CK_RC2_CBC_PARAMS; + +typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR; + + +/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the + * CKM_RC2_MAC_GENERAL mechanism + */ +typedef struct CK_RC2_MAC_GENERAL_PARAMS { + CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ + CK_ULONG ulMacLength; /* Length of MAC in bytes */ +} CK_RC2_MAC_GENERAL_PARAMS; + +typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \ + CK_RC2_MAC_GENERAL_PARAMS_PTR; + + +/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and + * CKM_RC5_MAC mechanisms + */ +typedef struct CK_RC5_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ +} CK_RC5_PARAMS; + +typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR; + + +/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC + * mechanism + */ +typedef struct CK_RC5_CBC_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ + CK_BYTE_PTR pIv; /* pointer to IV */ + CK_ULONG ulIvLen; /* length of IV in bytes */ +} CK_RC5_CBC_PARAMS; + +typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR; + + +/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the + * CKM_RC5_MAC_GENERAL mechanism + */ +typedef struct CK_RC5_MAC_GENERAL_PARAMS { + CK_ULONG ulWordsize; /* wordsize in bits */ + CK_ULONG ulRounds; /* number of rounds */ + CK_ULONG ulMacLength; /* Length of MAC in bytes */ +} CK_RC5_MAC_GENERAL_PARAMS; + +typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \ + CK_RC5_MAC_GENERAL_PARAMS_PTR; + +/* CK_MAC_GENERAL_PARAMS provides the parameters to most block + * ciphers' MAC_GENERAL mechanisms. Its value is the length of + * the MAC + */ +typedef CK_ULONG CK_MAC_GENERAL_PARAMS; + +typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR; + +typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS { + CK_BYTE iv[8]; + CK_BYTE_PTR pData; + CK_ULONG length; +} CK_DES_CBC_ENCRYPT_DATA_PARAMS; + +typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR; + +typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS { + CK_BYTE iv[16]; + CK_BYTE_PTR pData; + CK_ULONG length; +} CK_AES_CBC_ENCRYPT_DATA_PARAMS; + +typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR; + +/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the + * CKM_SKIPJACK_PRIVATE_WRAP mechanism + */ +typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { + CK_ULONG ulPasswordLen; + CK_BYTE_PTR pPassword; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPAndGLen; + CK_ULONG ulQLen; + CK_ULONG ulRandomLen; + CK_BYTE_PTR pRandomA; + CK_BYTE_PTR pPrimeP; + CK_BYTE_PTR pBaseG; + CK_BYTE_PTR pSubprimeQ; +} CK_SKIPJACK_PRIVATE_WRAP_PARAMS; + +typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \ + CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR; + + +/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the + * CKM_SKIPJACK_RELAYX mechanism + */ +typedef struct CK_SKIPJACK_RELAYX_PARAMS { + CK_ULONG ulOldWrappedXLen; + CK_BYTE_PTR pOldWrappedX; + CK_ULONG ulOldPasswordLen; + CK_BYTE_PTR pOldPassword; + CK_ULONG ulOldPublicDataLen; + CK_BYTE_PTR pOldPublicData; + CK_ULONG ulOldRandomLen; + CK_BYTE_PTR pOldRandomA; + CK_ULONG ulNewPasswordLen; + CK_BYTE_PTR pNewPassword; + CK_ULONG ulNewPublicDataLen; + CK_BYTE_PTR pNewPublicData; + CK_ULONG ulNewRandomLen; + CK_BYTE_PTR pNewRandomA; +} CK_SKIPJACK_RELAYX_PARAMS; + +typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \ + CK_SKIPJACK_RELAYX_PARAMS_PTR; + + +typedef struct CK_PBE_PARAMS { + CK_BYTE_PTR pInitVector; + CK_UTF8CHAR_PTR pPassword; + CK_ULONG ulPasswordLen; + CK_BYTE_PTR pSalt; + CK_ULONG ulSaltLen; + CK_ULONG ulIteration; +} CK_PBE_PARAMS; + +typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR; + + +/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the + * CKM_KEY_WRAP_SET_OAEP mechanism + */ +typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { + CK_BYTE bBC; /* block contents byte */ + CK_BYTE_PTR pX; /* extra data */ + CK_ULONG ulXLen; /* length of extra data in bytes */ +} CK_KEY_WRAP_SET_OAEP_PARAMS; + +typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR CK_KEY_WRAP_SET_OAEP_PARAMS_PTR; + +typedef struct CK_SSL3_RANDOM_DATA { + CK_BYTE_PTR pClientRandom; + CK_ULONG ulClientRandomLen; + CK_BYTE_PTR pServerRandom; + CK_ULONG ulServerRandomLen; +} CK_SSL3_RANDOM_DATA; + + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { + CK_SSL3_RANDOM_DATA RandomInfo; + CK_VERSION_PTR pVersion; +} CK_SSL3_MASTER_KEY_DERIVE_PARAMS; + +typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \ + CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR; + +typedef struct CK_SSL3_KEY_MAT_OUT { + CK_OBJECT_HANDLE hClientMacSecret; + CK_OBJECT_HANDLE hServerMacSecret; + CK_OBJECT_HANDLE hClientKey; + CK_OBJECT_HANDLE hServerKey; + CK_BYTE_PTR pIVClient; + CK_BYTE_PTR pIVServer; +} CK_SSL3_KEY_MAT_OUT; + +typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR; + + +typedef struct CK_SSL3_KEY_MAT_PARAMS { + CK_ULONG ulMacSizeInBits; + CK_ULONG ulKeySizeInBits; + CK_ULONG ulIVSizeInBits; + CK_BBOOL bIsExport; + CK_SSL3_RANDOM_DATA RandomInfo; + CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; +} CK_SSL3_KEY_MAT_PARAMS; + +typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR; + +typedef struct CK_TLS_PRF_PARAMS { + CK_BYTE_PTR pSeed; + CK_ULONG ulSeedLen; + CK_BYTE_PTR pLabel; + CK_ULONG ulLabelLen; + CK_BYTE_PTR pOutput; + CK_ULONG_PTR pulOutputLen; +} CK_TLS_PRF_PARAMS; + +typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR; + +typedef struct CK_WTLS_RANDOM_DATA { + CK_BYTE_PTR pClientRandom; + CK_ULONG ulClientRandomLen; + CK_BYTE_PTR pServerRandom; + CK_ULONG ulServerRandomLen; +} CK_WTLS_RANDOM_DATA; + +typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR; + +typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS { + CK_MECHANISM_TYPE DigestMechanism; + CK_WTLS_RANDOM_DATA RandomInfo; + CK_BYTE_PTR pVersion; +} CK_WTLS_MASTER_KEY_DERIVE_PARAMS; + +typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \ + CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR; + +typedef struct CK_WTLS_PRF_PARAMS { + CK_MECHANISM_TYPE DigestMechanism; + CK_BYTE_PTR pSeed; + CK_ULONG ulSeedLen; + CK_BYTE_PTR pLabel; + CK_ULONG ulLabelLen; + CK_BYTE_PTR pOutput; + CK_ULONG_PTR pulOutputLen; +} CK_WTLS_PRF_PARAMS; + +typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR; + +typedef struct CK_WTLS_KEY_MAT_OUT { + CK_OBJECT_HANDLE hMacSecret; + CK_OBJECT_HANDLE hKey; + CK_BYTE_PTR pIV; +} CK_WTLS_KEY_MAT_OUT; + +typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR; + +typedef struct CK_WTLS_KEY_MAT_PARAMS { + CK_MECHANISM_TYPE DigestMechanism; + CK_ULONG ulMacSizeInBits; + CK_ULONG ulKeySizeInBits; + CK_ULONG ulIVSizeInBits; + CK_ULONG ulSequenceNumber; + CK_BBOOL bIsExport; + CK_WTLS_RANDOM_DATA RandomInfo; + CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial; +} CK_WTLS_KEY_MAT_PARAMS; + +typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR; + +typedef struct CK_CMS_SIG_PARAMS { + CK_OBJECT_HANDLE certificateHandle; + CK_MECHANISM_PTR pSigningMechanism; + CK_MECHANISM_PTR pDigestMechanism; + CK_UTF8CHAR_PTR pContentType; + CK_BYTE_PTR pRequestedAttributes; + CK_ULONG ulRequestedAttributesLen; + CK_BYTE_PTR pRequiredAttributes; + CK_ULONG ulRequiredAttributesLen; +} CK_CMS_SIG_PARAMS; + +typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR; + +typedef struct CK_KEY_DERIVATION_STRING_DATA { + CK_BYTE_PTR pData; + CK_ULONG ulLen; +} CK_KEY_DERIVATION_STRING_DATA; + +typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \ + CK_KEY_DERIVATION_STRING_DATA_PTR; + + +/* The CK_EXTRACT_PARAMS is used for the + * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit + * of the base key should be used as the first bit of the + * derived key + */ +typedef CK_ULONG CK_EXTRACT_PARAMS; + +typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; + +/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to + * indicate the Pseudo-Random Function (PRF) used to generate + * key bits using PKCS #5 PBKDF2. + */ +typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; + +typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR \ + CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR; + +#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001UL +#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411 0x00000002UL +#define CKP_PKCS5_PBKD2_HMAC_SHA224 0x00000003UL +#define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004UL +#define CKP_PKCS5_PBKD2_HMAC_SHA384 0x00000005UL +#define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006UL +#define CKP_PKCS5_PBKD2_HMAC_SHA512_224 0x00000007UL +#define CKP_PKCS5_PBKD2_HMAC_SHA512_256 0x00000008UL + +/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the + * source of the salt value when deriving a key using PKCS #5 + * PBKDF2. + */ +typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; + +typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR \ + CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR; + +/* The following salt value sources are defined in PKCS #5 v2.0. */ +#define CKZ_SALT_SPECIFIED 0x00000001UL + +/* CK_PKCS5_PBKD2_PARAMS is a structure that provides the + * parameters to the CKM_PKCS5_PBKD2 mechanism. + */ +typedef struct CK_PKCS5_PBKD2_PARAMS { + CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; + CK_VOID_PTR pSaltSourceData; + CK_ULONG ulSaltSourceDataLen; + CK_ULONG iterations; + CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; + CK_VOID_PTR pPrfData; + CK_ULONG ulPrfDataLen; + CK_UTF8CHAR_PTR pPassword; + CK_ULONG_PTR ulPasswordLen; +} CK_PKCS5_PBKD2_PARAMS; + +typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR; + +/* CK_PKCS5_PBKD2_PARAMS2 is a corrected version of the CK_PKCS5_PBKD2_PARAMS + * structure that provides the parameters to the CKM_PKCS5_PBKD2 mechanism + * noting that the ulPasswordLen field is a CK_ULONG and not a CK_ULONG_PTR. + */ +typedef struct CK_PKCS5_PBKD2_PARAMS2 { + CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; + CK_VOID_PTR pSaltSourceData; + CK_ULONG ulSaltSourceDataLen; + CK_ULONG iterations; + CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; + CK_VOID_PTR pPrfData; + CK_ULONG ulPrfDataLen; + CK_UTF8CHAR_PTR pPassword; + CK_ULONG ulPasswordLen; +} CK_PKCS5_PBKD2_PARAMS2; + +typedef CK_PKCS5_PBKD2_PARAMS2 CK_PTR CK_PKCS5_PBKD2_PARAMS2_PTR; + +typedef CK_ULONG CK_OTP_PARAM_TYPE; +typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* backward compatibility */ + +typedef struct CK_OTP_PARAM { + CK_OTP_PARAM_TYPE type; + CK_VOID_PTR pValue; + CK_ULONG ulValueLen; +} CK_OTP_PARAM; + +typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR; + +typedef struct CK_OTP_PARAMS { + CK_OTP_PARAM_PTR pParams; + CK_ULONG ulCount; +} CK_OTP_PARAMS; + +typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR; + +typedef struct CK_OTP_SIGNATURE_INFO { + CK_OTP_PARAM_PTR pParams; + CK_ULONG ulCount; +} CK_OTP_SIGNATURE_INFO; + +typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR; + +#define CK_OTP_VALUE 0UL +#define CK_OTP_PIN 1UL +#define CK_OTP_CHALLENGE 2UL +#define CK_OTP_TIME 3UL +#define CK_OTP_COUNTER 4UL +#define CK_OTP_FLAGS 5UL +#define CK_OTP_OUTPUT_LENGTH 6UL +#define CK_OTP_OUTPUT_FORMAT 7UL + +#define CKF_NEXT_OTP 0x00000001UL +#define CKF_EXCLUDE_TIME 0x00000002UL +#define CKF_EXCLUDE_COUNTER 0x00000004UL +#define CKF_EXCLUDE_CHALLENGE 0x00000008UL +#define CKF_EXCLUDE_PIN 0x00000010UL +#define CKF_USER_FRIENDLY_OTP 0x00000020UL + +typedef struct CK_KIP_PARAMS { + CK_MECHANISM_PTR pMechanism; + CK_OBJECT_HANDLE hKey; + CK_BYTE_PTR pSeed; + CK_ULONG ulSeedLen; +} CK_KIP_PARAMS; + +typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR; + +typedef struct CK_AES_CTR_PARAMS { + CK_ULONG ulCounterBits; + CK_BYTE cb[16]; +} CK_AES_CTR_PARAMS; + +typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR; + +typedef struct CK_GCM_PARAMS { + CK_BYTE_PTR pIv; + CK_ULONG ulIvLen; + CK_ULONG ulIvBits; + CK_BYTE_PTR pAAD; + CK_ULONG ulAADLen; + CK_ULONG ulTagBits; +} CK_GCM_PARAMS; + +typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR; + +typedef struct CK_CCM_PARAMS { + CK_ULONG ulDataLen; + CK_BYTE_PTR pNonce; + CK_ULONG ulNonceLen; + CK_BYTE_PTR pAAD; + CK_ULONG ulAADLen; + CK_ULONG ulMACLen; +} CK_CCM_PARAMS; + +typedef CK_CCM_PARAMS CK_PTR CK_CCM_PARAMS_PTR; + +/* Deprecated. Use CK_GCM_PARAMS */ +typedef struct CK_AES_GCM_PARAMS { + CK_BYTE_PTR pIv; + CK_ULONG ulIvLen; + CK_ULONG ulIvBits; + CK_BYTE_PTR pAAD; + CK_ULONG ulAADLen; + CK_ULONG ulTagBits; +} CK_AES_GCM_PARAMS; + +typedef CK_AES_GCM_PARAMS CK_PTR CK_AES_GCM_PARAMS_PTR; + +/* Deprecated. Use CK_CCM_PARAMS */ +typedef struct CK_AES_CCM_PARAMS { + CK_ULONG ulDataLen; + CK_BYTE_PTR pNonce; + CK_ULONG ulNonceLen; + CK_BYTE_PTR pAAD; + CK_ULONG ulAADLen; + CK_ULONG ulMACLen; +} CK_AES_CCM_PARAMS; + +typedef CK_AES_CCM_PARAMS CK_PTR CK_AES_CCM_PARAMS_PTR; + +typedef struct CK_CAMELLIA_CTR_PARAMS { + CK_ULONG ulCounterBits; + CK_BYTE cb[16]; +} CK_CAMELLIA_CTR_PARAMS; + +typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR; + +typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS { + CK_BYTE iv[16]; + CK_BYTE_PTR pData; + CK_ULONG length; +} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS; + +typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \ + CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR; + +typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS { + CK_BYTE iv[16]; + CK_BYTE_PTR pData; + CK_ULONG length; +} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS; + +typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \ + CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR; + +typedef struct CK_DSA_PARAMETER_GEN_PARAM { + CK_MECHANISM_TYPE hash; + CK_BYTE_PTR pSeed; + CK_ULONG ulSeedLen; + CK_ULONG ulIndex; +} CK_DSA_PARAMETER_GEN_PARAM; + +typedef CK_DSA_PARAMETER_GEN_PARAM CK_PTR CK_DSA_PARAMETER_GEN_PARAM_PTR; + +typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS { + CK_ULONG ulAESKeyBits; + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; +} CK_ECDH_AES_KEY_WRAP_PARAMS; + +typedef CK_ECDH_AES_KEY_WRAP_PARAMS CK_PTR CK_ECDH_AES_KEY_WRAP_PARAMS_PTR; + +typedef CK_ULONG CK_JAVA_MIDP_SECURITY_DOMAIN; + +typedef CK_ULONG CK_CERTIFICATE_CATEGORY; + +typedef struct CK_RSA_AES_KEY_WRAP_PARAMS { + CK_ULONG ulAESKeyBits; + CK_RSA_PKCS_OAEP_PARAMS_PTR pOAEPParams; +} CK_RSA_AES_KEY_WRAP_PARAMS; + +typedef CK_RSA_AES_KEY_WRAP_PARAMS CK_PTR CK_RSA_AES_KEY_WRAP_PARAMS_PTR; + +typedef struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS { + CK_SSL3_RANDOM_DATA RandomInfo; + CK_VERSION_PTR pVersion; + CK_MECHANISM_TYPE prfHashMechanism; +} CK_TLS12_MASTER_KEY_DERIVE_PARAMS; + +typedef CK_TLS12_MASTER_KEY_DERIVE_PARAMS CK_PTR \ + CK_TLS12_MASTER_KEY_DERIVE_PARAMS_PTR; + +typedef struct CK_TLS12_KEY_MAT_PARAMS { + CK_ULONG ulMacSizeInBits; + CK_ULONG ulKeySizeInBits; + CK_ULONG ulIVSizeInBits; + CK_BBOOL bIsExport; + CK_SSL3_RANDOM_DATA RandomInfo; + CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; + CK_MECHANISM_TYPE prfHashMechanism; +} CK_TLS12_KEY_MAT_PARAMS; + +typedef CK_TLS12_KEY_MAT_PARAMS CK_PTR CK_TLS12_KEY_MAT_PARAMS_PTR; + +typedef struct CK_TLS_KDF_PARAMS { + CK_MECHANISM_TYPE prfMechanism; + CK_BYTE_PTR pLabel; + CK_ULONG ulLabelLength; + CK_SSL3_RANDOM_DATA RandomInfo; + CK_BYTE_PTR pContextData; + CK_ULONG ulContextDataLength; +} CK_TLS_KDF_PARAMS; + +typedef CK_TLS_KDF_PARAMS CK_PTR CK_TLS_KDF_PARAMS_PTR; + +typedef struct CK_TLS_MAC_PARAMS { + CK_MECHANISM_TYPE prfHashMechanism; + CK_ULONG ulMacLength; + CK_ULONG ulServerOrClient; +} CK_TLS_MAC_PARAMS; + +typedef CK_TLS_MAC_PARAMS CK_PTR CK_TLS_MAC_PARAMS_PTR; + +typedef struct CK_GOSTR3410_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_BYTE_PTR pPublicData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pUKM; + CK_ULONG ulUKMLen; +} CK_GOSTR3410_DERIVE_PARAMS; + +typedef CK_GOSTR3410_DERIVE_PARAMS CK_PTR CK_GOSTR3410_DERIVE_PARAMS_PTR; + +typedef struct CK_GOSTR3410_KEY_WRAP_PARAMS { + CK_BYTE_PTR pWrapOID; + CK_ULONG ulWrapOIDLen; + CK_BYTE_PTR pUKM; + CK_ULONG ulUKMLen; + CK_OBJECT_HANDLE hKey; +} CK_GOSTR3410_KEY_WRAP_PARAMS; + +typedef CK_GOSTR3410_KEY_WRAP_PARAMS CK_PTR CK_GOSTR3410_KEY_WRAP_PARAMS_PTR; + +typedef struct CK_SEED_CBC_ENCRYPT_DATA_PARAMS { + CK_BYTE iv[16]; + CK_BYTE_PTR pData; + CK_ULONG length; +} CK_SEED_CBC_ENCRYPT_DATA_PARAMS; + +typedef CK_SEED_CBC_ENCRYPT_DATA_PARAMS CK_PTR \ + CK_SEED_CBC_ENCRYPT_DATA_PARAMS_PTR; + +#endif /* _PKCS11T_H_ */ + diff --git a/comm/third_party/botan/src/lib/prov/tpm/info.txt b/comm/third_party/botan/src/lib/prov/tpm/info.txt new file mode 100644 index 0000000000..3993efc530 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/tpm/info.txt @@ -0,0 +1,16 @@ + +TPM -> 20151126 + + +load_on vendor + + +all -> tspi + + + +uuid +hash_id +rsa +rng + diff --git a/comm/third_party/botan/src/lib/prov/tpm/tpm.cpp b/comm/third_party/botan/src/lib/prov/tpm/tpm.cpp new file mode 100644 index 0000000000..dec2316b10 --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/tpm/tpm.cpp @@ -0,0 +1,460 @@ +/* +* TPM 1.2 interface +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// TODO: dynamically load the TPM libraries? + +namespace Botan { + +namespace { + +void tss_error(TSS_RESULT res, const char* expr, const char* file, int line) + { + std::ostringstream err; + err << "TPM error " << Trspi_Error_String(res) + << " layer " << Trspi_Error_Layer(res) + << " in " << expr << " at " << file << ":" << line; + + throw TPM_Error(err.str()); + } + +TSS_FLAG bit_flag(size_t bits) + { + switch(bits) + { + // 512 supported, but ignored and rejected here + case 1024: + return TSS_KEY_SIZE_1024; + case 2048: + return TSS_KEY_SIZE_2048; + + // Most? v1.2 TPMs only support 1024 and 2048 bit keys ... + case 4096: + return TSS_KEY_SIZE_4096; + case 8192: + return TSS_KEY_SIZE_8192; + case 16384: + return TSS_KEY_SIZE_16384; + default: + throw Invalid_Argument("Unsupported TPM key size " + std::to_string(bits)); + } + } + +#if 0 +bool is_srk_uuid(const UUID& uuid) + { + static const uint8_t srk[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + const std::vector& b = uuid.binary_value(); + return (b.size() == 16 && same_mem(b.data(), srk, 16)); + } +#endif + +#define TSPI_CHECK_SUCCESS(expr) do { \ + TSS_RESULT res = expr; \ + if(res != TSS_SUCCESS) \ + tss_error(res, #expr, __FILE__, __LINE__); \ + } while(0) + +std::vector get_obj_attr(TSS_HCONTEXT ctx, + TSS_HOBJECT obj, + TSS_FLAG flag, + TSS_FLAG sub_flag) + { + BYTE *data = nullptr; + UINT32 data_len = 0; + TSPI_CHECK_SUCCESS(::Tspi_GetAttribData(obj, flag, sub_flag, &data_len, &data)); + + std::vector r(data, data + data_len); + + TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(ctx, data)); + + return r; + } + +void set_policy_secret(TSS_HPOLICY policy, const char* secret) + { + if(secret) + { + BYTE* as_b = const_cast(reinterpret_cast(secret)); + TSPI_CHECK_SUCCESS(::Tspi_Policy_SetSecret(policy, + TSS_SECRET_MODE_PLAIN, + std::strlen(secret), + as_b)); + } + else + { + static const uint8_t nullpass[20] = { 0 }; + + TSPI_CHECK_SUCCESS(::Tspi_Policy_SetSecret(policy, + TSS_SECRET_MODE_SHA1, + sizeof(nullpass), + const_cast(nullpass))); + } + } + +TSS_UUID to_tss_uuid(const UUID& uuid) + { + static_assert(sizeof(TSS_UUID) == 16, "Expected size of packed UUID"); + + TSS_UUID tss_uuid; + typecast_copy(tss_uuid, uuid.binary_value().data()); + return tss_uuid; + } + +UUID from_tss_uuid(const TSS_UUID& tss_uuid) + { + static_assert(sizeof(TSS_UUID) == 16, "Expected size of packed UUID"); + + std::vector mem(16); + typecast_copy(mem.data(), tss_uuid); + UUID uuid(std::move(mem)); + return uuid; + } + +TPM_Storage_Type storage_type_from_tss_flag(TSS_FLAG flag) + { + if(flag == TSS_PS_TYPE_USER) + return TPM_Storage_Type::User; + else if(flag == TSS_PS_TYPE_SYSTEM) + return TPM_Storage_Type::System; + else + throw TPM_Error("Invalid storage flag " + std::to_string(flag)); + } + +std::string format_url(const UUID& uuid, TPM_Storage_Type storage) + { + std::string storage_str = (storage == TPM_Storage_Type::User) ? "user" : "system"; + return "tpmkey:uuid=" + uuid.to_string() + ";storage=" + storage_str; + } + +std::string format_url(const TSS_UUID& tss_uuid, TSS_FLAG store_type) + { + UUID uuid = from_tss_uuid(tss_uuid); + + return format_url(from_tss_uuid(tss_uuid), + storage_type_from_tss_flag(store_type)); + } + +} + +TPM_Context::TPM_Context(pin_cb cb, const char* srk_password) : + m_pin_cb(cb), + m_srk_policy(0) + { + TSPI_CHECK_SUCCESS(::Tspi_Context_Create(&m_ctx)); + TSPI_CHECK_SUCCESS(::Tspi_Context_Connect(m_ctx, nullptr)); + + TSPI_CHECK_SUCCESS(::Tspi_Context_GetTpmObject(m_ctx, &m_tpm)); + + const TSS_UUID SRK_UUID = TSS_UUID_SRK; + + TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByUUID(m_ctx, TSS_PS_TYPE_SYSTEM, SRK_UUID, &m_srk)); + + TSPI_CHECK_SUCCESS(::Tspi_GetPolicyObject(m_srk, TSS_POLICY_USAGE, &m_srk_policy)); + set_policy_secret(m_srk_policy, srk_password); + + // TODO: do we have to cache it? + // TODO: try to use SRK with null, if it fails call the pin cb? + } + +TPM_Context::~TPM_Context() + { + TSPI_CHECK_SUCCESS(::Tspi_Context_CloseObject(m_ctx, m_srk)); + //TSPI_CHECK_SUCCESS(::Tspi_Context_CloseObject(m_ctx, m_tpm)); + TSPI_CHECK_SUCCESS(::Tspi_Context_Close(m_srk_policy)); + TSPI_CHECK_SUCCESS(::Tspi_Context_Close(m_ctx)); + } + +uint32_t TPM_Context::current_counter() + { + uint32_t r = 0; + TSPI_CHECK_SUCCESS(::Tspi_TPM_ReadCounter(m_tpm, &r)); + return r; + } + +void TPM_Context::gen_random(uint8_t out[], size_t out_len) + { + BYTE* mem; + TSPI_CHECK_SUCCESS(::Tspi_TPM_GetRandom(m_tpm, out_len, &mem)); + copy_mem(out, reinterpret_cast(mem), out_len); + TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(m_ctx, mem)); + } + +void TPM_Context::stir_random(const uint8_t in[], size_t in_len) + { + TSPI_CHECK_SUCCESS(::Tspi_TPM_StirRandom(m_tpm, in_len, const_cast(in))); + } + +TPM_PrivateKey::TPM_PrivateKey(TPM_Context& ctx, size_t bits, + const char* key_password) : m_ctx(ctx) + { + // TODO: can also do OAEP decryption via binding keys + // TODO: offer signing, binding (decrypt), or legacy (sign + decrypt) keys? + + TSS_FLAG key_flags = bit_flag(bits) | TSS_KEY_VOLATILE | TSS_KEY_TYPE_SIGNING; + + TSS_HKEY key; + TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(m_ctx.handle(), TSS_OBJECT_TYPE_RSAKEY, key_flags, &key)); + + TSPI_CHECK_SUCCESS(::Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO, + TSS_TSPATTRIB_KEYINFO_SIGSCHEME, + TSS_SS_RSASSAPKCS1V15_DER)); + + TSS_HPOLICY policy; + TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(m_ctx.handle(), TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &policy)); + set_policy_secret(policy, key_password); + TSPI_CHECK_SUCCESS(::Tspi_Policy_AssignToObject(policy, key)); + + TSPI_CHECK_SUCCESS(::Tspi_Key_CreateKey(key, ctx.srk(), 0)); + m_key = key; + } + +// reference a registered TPM key +TPM_PrivateKey::TPM_PrivateKey(TPM_Context& ctx, const std::string& uuid_str, + TPM_Storage_Type storage_type) : + m_ctx(ctx), + m_uuid(uuid_str), + m_storage(storage_type) + { + const TSS_FLAG key_ps_type = + (m_storage == TPM_Storage_Type::User) ? TSS_PS_TYPE_USER : TSS_PS_TYPE_SYSTEM; + + TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByUUID(m_ctx.handle(), + key_ps_type, + to_tss_uuid(m_uuid), + &m_key)); + } + +TPM_PrivateKey::TPM_PrivateKey(TPM_Context& ctx, + const std::vector& blob) : m_ctx(ctx) + { + TSPI_CHECK_SUCCESS(::Tspi_Context_LoadKeyByBlob(m_ctx.handle(), m_ctx.srk(), blob.size(), + const_cast(blob.data()), + &m_key)); + + //TSPI_CHECK_SUCCESS(::Tspi_Key_LoadKey(m_key, m_ctx.srk())); + } + +std::string TPM_PrivateKey::register_key(TPM_Storage_Type storage_type) + { + if(!m_uuid.is_valid()) + { + TPM_RNG rng(ctx()); // use system_rng or arg RNG& instead? + m_uuid = UUID(rng); + m_storage = storage_type; + + const TSS_UUID key_uuid = to_tss_uuid(m_uuid); + const TSS_FLAG key_ps_type = + (storage_type == TPM_Storage_Type::User) ? TSS_PS_TYPE_USER : TSS_PS_TYPE_SYSTEM; + + const TSS_UUID srk_uuid = TSS_UUID_SRK; + + TSPI_CHECK_SUCCESS(::Tspi_Context_RegisterKey(m_ctx.handle(), + m_key, + key_ps_type, + key_uuid, + TSS_PS_TYPE_SYSTEM, + srk_uuid)); + + } + + // Presumably we could re-register in the other store and same UUID + // Doesn't seem like what is desired most of the time here + if(storage_type != m_storage) + { + throw TPM_Error("TPM key " + m_uuid.to_string() + + " already registered with different storage type"); + } + + return format_url(m_uuid, m_storage); + } + +std::vector TPM_PrivateKey::registered_keys(TPM_Context& ctx) + { + TSS_KM_KEYINFO2* key_info; + UINT32 key_info_size; + + // TODO: does the PS type matter here at all? + TSPI_CHECK_SUCCESS(::Tspi_Context_GetRegisteredKeysByUUID2(ctx.handle(), + TSS_PS_TYPE_SYSTEM, + nullptr, + &key_info_size, + &key_info)); + + std::vector r(key_info_size); + + for(size_t i = 0; i != key_info_size; ++i) + { + r[i] = format_url(key_info[i].keyUUID, key_info[i].persistentStorageType); + } + + // TODO: are we supposed to free this memory and if so how? + //TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(ctx.handle(), key_info)); + + return r; + } + +BigInt TPM_PrivateKey::get_n() const + { + if(m_n == 0) + { + m_n = BigInt::decode(get_obj_attr(m_ctx.handle(), m_key, + TSS_TSPATTRIB_RSAKEY_INFO, + TSS_TSPATTRIB_KEYINFO_RSA_MODULUS)); + } + + return m_n; + } + +BigInt TPM_PrivateKey::get_e() const + { + if(m_e == 0) + { + m_e = BigInt::decode(get_obj_attr(m_ctx.handle(), m_key, + TSS_TSPATTRIB_RSAKEY_INFO, + TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT)); + } + + return m_e; + } + +size_t TPM_PrivateKey::estimated_strength() const + { + return if_work_factor(key_length()); + } + +size_t TPM_PrivateKey::key_length() const + { + return get_n().bits(); + } + +AlgorithmIdentifier TPM_PrivateKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + AlgorithmIdentifier::USE_NULL_PARAM); + } + +std::vector TPM_PrivateKey::public_key_bits() const + { + std::vector bits; + DER_Encoder(bits) + .start_cons(SEQUENCE) + .encode(get_n()) + .encode(get_e()) + .end_cons(); + return bits; + } + +secure_vector TPM_PrivateKey::private_key_bits() const + { + throw TPM_Error("Private key export not supported for TPM keys"); + } + +std::vector TPM_PrivateKey::export_blob() const + { + return get_obj_attr(m_ctx.handle(), m_key, + TSS_TSPATTRIB_KEY_BLOB, + TSS_TSPATTRIB_KEYBLOB_BLOB); + } + +std::unique_ptr TPM_PrivateKey::public_key() const + { + return std::unique_ptr(new RSA_PublicKey(get_n(), get_e())); + } + +bool TPM_PrivateKey::check_key(RandomNumberGenerator&, bool) const + { + return true; // TODO do a kat or pairwise check + } + +namespace { + +class TPM_Signing_Operation final : public PK_Ops::Signature + { + public: + TPM_Signing_Operation(const TPM_PrivateKey& key, + const std::string& hash_name) : + m_key(key), + m_hash(HashFunction::create(hash_name)), + m_hash_id(pkcs_hash_id(hash_name)) + { + } + + size_t signature_length() const override + { + return m_key.get_n().bytes(); + } + + void update(const uint8_t msg[], size_t msg_len) override + { + m_hash->update(msg, msg_len); + } + + secure_vector sign(RandomNumberGenerator&) override + { + /* + * v1.2 TPMs will only sign with PKCS #1 v1.5 padding. SHA-1 is built + * in, all other hash inputs (TSS_HASH_OTHER) are treated as the + * concatenation of the hash OID and hash value and signed with just the + * 01FFFF... prefix. Even when using SHA-1 we compute the hash locally + * since it is going to be much faster than pushing data over the LPC bus. + */ + secure_vector msg_hash = m_hash->final(); + + std::vector id_and_msg; + id_and_msg.reserve(m_hash_id.size() + msg_hash.size()); + id_and_msg.insert(id_and_msg.end(), m_hash_id.begin(), m_hash_id.end()); + id_and_msg.insert(id_and_msg.end(), msg_hash.begin(), msg_hash.end()); + + TSS_HCONTEXT ctx = m_key.ctx().handle(); + TSS_HHASH tpm_hash; + TSPI_CHECK_SUCCESS(::Tspi_Context_CreateObject(ctx, TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &tpm_hash)); + TSPI_CHECK_SUCCESS(::Tspi_Hash_SetHashValue(tpm_hash, id_and_msg.size(), id_and_msg.data())); + + BYTE* sig_bytes = nullptr; + UINT32 sig_len = 0; + TSPI_CHECK_SUCCESS(::Tspi_Hash_Sign(tpm_hash, m_key.handle(), &sig_len, &sig_bytes)); + secure_vector sig(sig_bytes, sig_bytes + sig_len); + + // TODO: RAII for Context_FreeMemory + TSPI_CHECK_SUCCESS(::Tspi_Context_FreeMemory(ctx, sig_bytes)); + + // TODO: RAII for Context_CloseObject + TSPI_CHECK_SUCCESS(::Tspi_Context_CloseObject(ctx, tpm_hash)); + + return sig; + } + + private: + const TPM_PrivateKey& m_key; + std::unique_ptr m_hash; + std::vector m_hash_id; + }; + +} + +std::unique_ptr +TPM_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& /*provider*/) const + { + return std::unique_ptr(new TPM_Signing_Operation(*this, params)); + } + +} diff --git a/comm/third_party/botan/src/lib/prov/tpm/tpm.h b/comm/third_party/botan/src/lib/prov/tpm/tpm.h new file mode 100644 index 0000000000..8a25458b7c --- /dev/null +++ b/comm/third_party/botan/src/lib/prov/tpm/tpm.h @@ -0,0 +1,194 @@ + +/* +* TPM 1.2 interface +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TPM_H_ +#define BOTAN_TPM_H_ + +#include +#include +#include +#include +#include +#include + +//TODO remove this +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) TPM_Error final : public Exception + { + public: + TPM_Error(const std::string& err) : Exception(err) {} + ErrorType error_type() const noexcept override { return ErrorType::TPMError; } + }; + +/** +* Creates a connection to the TPM. All other TPM types take and hold +* a TPM_Context reference, so all other objects must be deallocated +* before ~TPM_Context runs. +* +* Use nullptr for the srk_password to indicate the well known secret +* (ie, an unencrypted SRK). This is usually what you want. +* +* TODO: handling owner password? +*/ +class BOTAN_PUBLIC_API(2,0) TPM_Context final + { + public: + /** + * User callback for getting the PIN. Will be passed the best available + * description of what we are attempting to load. + */ + typedef std::function pin_cb; + + TPM_Context(pin_cb cb, const char* srk_password); + + ~TPM_Context(); + + // Get data from the TPM's RNG, whatever that is + void gen_random(uint8_t out[], size_t out_len); + + // Uses Tspi_TPM_StirRandom to add data to TPM's internal pool + void stir_random(const uint8_t in[], size_t in_len); + + std::string get_user_pin(const std::string& who) + { + return m_pin_cb(who); + } + + uint32_t current_counter(); + + TSS_HCONTEXT handle() const { return m_ctx; } + TSS_HKEY srk() const { return m_srk; } + + private: + std::function m_pin_cb; + TSS_HCONTEXT m_ctx; + TSS_HKEY m_srk; + TSS_HTPM m_tpm; + TSS_HPOLICY m_srk_policy; + }; + +class BOTAN_PUBLIC_API(2,0) TPM_RNG final : public Hardware_RNG + { + public: + TPM_RNG(TPM_Context& ctx) : m_ctx(ctx) {} + + bool accepts_input() const override { return true; } + + void add_entropy(const uint8_t in[], size_t in_len) override + { + m_ctx.stir_random(in, in_len); + } + + void randomize(uint8_t out[], size_t out_len) override + { + m_ctx.gen_random(out, out_len); + } + + std::string name() const override { return "TPM_RNG"; } + + bool is_seeded() const override { return true; } + + private: + TPM_Context& m_ctx; +}; + +enum class TPM_Storage_Type { User, System }; + +/* +* Also implements the public interface, but does not have usable +* TODO: derive from RSA_PublicKey??? +*/ +class BOTAN_PUBLIC_API(2,0) TPM_PrivateKey final : public Private_Key + { + public: + // TODO: key import? + + /* + * Create a new key on the TPM parented to the SRK + * @param bits must be 1024 or 2048 + */ + TPM_PrivateKey(TPM_Context& ctx, size_t bits, const char* key_password); + + // reference an existing TPM key using URL syntax from GnuTLS + // "tpmkey:uuid=79f07ca9-73ac-478a-9093-11ca6702e774;storage=user" + //TPM_PrivateKey(TPM_Context& ctx, const std::string& tpm_url); + + TPM_PrivateKey(TPM_Context& ctx, + const std::string& uuid, + TPM_Storage_Type storage_type); + + TPM_PrivateKey(TPM_Context& ctx, + const std::vector& blob); + + /** + * If the key is not currently registered under a known UUID, + * generates a new random UUID and registers the key. + * Returns the access URL. + */ + std::string register_key(TPM_Storage_Type storage_type); + + /** + * Returns a copy of the public key + */ + std::unique_ptr public_key() const; + + std::vector export_blob() const; + + TPM_Context& ctx() const { return m_ctx; } + + TSS_HKEY handle() const { return m_key; } + + /* + * Returns the list of all keys (in URL format) registered with the system + */ + static std::vector registered_keys(TPM_Context& ctx); + + size_t estimated_strength() const override; + + size_t key_length() const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + secure_vector private_key_bits() const override; + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + BigInt get_n() const; + + BigInt get_e() const; + + std::string algo_name() const override { return "RSA"; } // ??? + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + private: + TPM_Context& m_ctx; + TSS_HKEY m_key; + + // Only set for registered keys + UUID m_uuid; + TPM_Storage_Type m_storage; + + // Lazily computed in get_n, get_e + mutable BigInt m_n, m_e; + }; + +// TODO: NVRAM interface +// TODO: PCR measurement, writing, key locking + +} + +#endif diff --git a/comm/third_party/botan/src/lib/psk_db/info.txt b/comm/third_party/botan/src/lib/psk_db/info.txt new file mode 100644 index 0000000000..4b1d0747ed --- /dev/null +++ b/comm/third_party/botan/src/lib/psk_db/info.txt @@ -0,0 +1,11 @@ + +PSK_DB -> 20171119 + + + +aes +hmac +base64 +sha2_32 +nist_keywrap + diff --git a/comm/third_party/botan/src/lib/psk_db/psk_db.cpp b/comm/third_party/botan/src/lib/psk_db/psk_db.cpp new file mode 100644 index 0000000000..59fa768934 --- /dev/null +++ b/comm/third_party/botan/src/lib/psk_db/psk_db.cpp @@ -0,0 +1,105 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +Encrypted_PSK_Database::Encrypted_PSK_Database(const secure_vector& master_key) + { + m_cipher = BlockCipher::create_or_throw("AES-256"); + m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + m_hmac->set_key(master_key); + + m_cipher->set_key(m_hmac->process("wrap")); + m_hmac->set_key(m_hmac->process("hmac")); + } + +Encrypted_PSK_Database::~Encrypted_PSK_Database() + { + // for ~unique_ptr + } + +std::set Encrypted_PSK_Database::list_names() const + { + const std::set encrypted_names = kv_get_all(); + + std::set names; + + for(std::string enc_name : encrypted_names) + { + try + { + const secure_vector raw_name = base64_decode(enc_name); + const secure_vector name_bits = + nist_key_unwrap_padded(raw_name.data(), raw_name.size(), *m_cipher); + + std::string pt_name(cast_uint8_ptr_to_char(name_bits.data()), name_bits.size()); + names.insert(pt_name); + } + catch(Invalid_Authentication_Tag&) + { + } + } + + return names; + } + +void Encrypted_PSK_Database::remove(const std::string& name) + { + const std::vector wrapped_name = + nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), + name.size(), + *m_cipher); + + this->kv_del(base64_encode(wrapped_name)); + } + +secure_vector Encrypted_PSK_Database::get(const std::string& name) const + { + const std::vector wrapped_name = + nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), + name.size(), + *m_cipher); + + const std::string val_base64 = kv_get(base64_encode(wrapped_name)); + + if(val_base64.empty()) + throw Invalid_Argument("Named PSK not located"); + + const secure_vector val = base64_decode(val_base64); + + std::unique_ptr wrap_cipher(m_cipher->clone()); + wrap_cipher->set_key(m_hmac->process(wrapped_name)); + + return nist_key_unwrap_padded(val.data(), val.size(), *wrap_cipher); + } + +void Encrypted_PSK_Database::set(const std::string& name, const uint8_t val[], size_t len) + { + /* + * Both as a basic precaution wrt key seperation, and specifically to prevent + * cut-and-paste attacks against the database, each PSK is encrypted with a + * distinct key which is derived by hashing the wrapped key name with HMAC. + */ + const std::vector wrapped_name = + nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), + name.size(), + *m_cipher); + + std::unique_ptr wrap_cipher(m_cipher->clone()); + wrap_cipher->set_key(m_hmac->process(wrapped_name)); + const std::vector wrapped_key = nist_key_wrap_padded(val, len, *wrap_cipher); + + this->kv_set(base64_encode(wrapped_name), base64_encode(wrapped_key)); + } + +} diff --git a/comm/third_party/botan/src/lib/psk_db/psk_db.h b/comm/third_party/botan/src/lib/psk_db/psk_db.h new file mode 100644 index 0000000000..06358935c1 --- /dev/null +++ b/comm/third_party/botan/src/lib/psk_db/psk_db.h @@ -0,0 +1,166 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PSK_DB_H_ +#define BOTAN_PSK_DB_H_ + +#include +#include +#include +#include + +namespace Botan { + +class BlockCipher; +class MessageAuthenticationCode; + +/** +* This is an interface to a generic PSK (pre-shared key) database. +* It might be implemented as a plaintext storage or via some mechanism +* that encrypts the keys and/or values. +*/ +class BOTAN_PUBLIC_API(2,4) PSK_Database + { + public: + /** + * Return the set of names for which get() will return a value. + */ + virtual std::set list_names() const = 0; + + /** + * Return the value associated with the specified @param name or otherwise + * throw an exception. + */ + virtual secure_vector get(const std::string& name) const = 0; + + /** + * Set a value that can later be accessed with get(). + * If name already exists in the database, the old value will be overwritten. + */ + virtual void set(const std::string& name, const uint8_t psk[], size_t psk_len) = 0; + + /** + * Remove a PSK from the database + */ + virtual void remove(const std::string& name) = 0; + + /** + * Returns if the values in the PSK database are encrypted. If + * false, saved values are being stored in plaintext. + */ + virtual bool is_encrypted() const = 0; + + /** + * Get a PSK in the form of a string (eg if the PSK is a password) + */ + std::string get_str(const std::string& name) const + { + secure_vector psk = get(name); + return std::string(cast_uint8_ptr_to_char(psk.data()), psk.size()); + } + + void set_str(const std::string& name, const std::string& psk) + { + set(name, cast_char_ptr_to_uint8(psk.data()), psk.size()); + } + + template + void set_vec(const std::string& name, + const std::vector& psk) + + { + set(name, psk.data(), psk.size()); + } + + virtual ~PSK_Database() = default; + }; + +/** +* A mixin for an encrypted PSK database. +* Both keys and values are encrypted with NIST AES-256 key wrapping. +* Values are padded to obscure their length before encryption, allowing +* it to be used as a password vault. +* +* Subclasses must implement the virtual calls to handle storing and +* getting raw (base64 encoded) values. +*/ +class BOTAN_PUBLIC_API(2,4) Encrypted_PSK_Database : public PSK_Database + { + public: + /** + * @param master_key specifies the master key used to encrypt all + * keys and value. It can be of any length, but should be at least 256 bits. + * + * Subkeys for the cryptographic algorithms used are derived from this + * master key. No key stretching is performed; if encrypting a PSK database + * using a password, it is recommended to use PBKDF2 to derive the database + * master key. + */ + Encrypted_PSK_Database(const secure_vector& master_key); + + ~Encrypted_PSK_Database(); + + std::set list_names() const override; + + secure_vector get(const std::string& name) const override; + + void set(const std::string& name, const uint8_t psk[], size_t psk_len) override; + + void remove(const std::string& name) override; + + bool is_encrypted() const override { return true; } + + protected: + /** + * Save a encrypted (name.value) pair to the database. Both will be base64 encoded strings. + */ + virtual void kv_set(const std::string& index, const std::string& value) = 0; + + /** + * Get a value previously saved with set_raw_value. Should return an empty + * string if index is not found. + */ + virtual std::string kv_get(const std::string& index) const = 0; + + /** + * Remove an index + */ + virtual void kv_del(const std::string& index) = 0; + + /** + * Return all indexes in the table. + */ + virtual std::set kv_get_all() const = 0; + + private: + std::unique_ptr m_cipher; + std::unique_ptr m_hmac; + secure_vector m_wrap_key; + }; + +class SQL_Database; + +class BOTAN_PUBLIC_API(2,4) Encrypted_PSK_Database_SQL : public Encrypted_PSK_Database + { + public: + Encrypted_PSK_Database_SQL(const secure_vector& master_key, + std::shared_ptr db, + const std::string& table_name); + + ~Encrypted_PSK_Database_SQL(); + private: + void kv_set(const std::string& index, const std::string& value) override; + std::string kv_get(const std::string& index) const override; + void kv_del(const std::string& index) override; + std::set kv_get_all() const override; + + std::shared_ptr m_db; + const std::string m_table_name; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/psk_db/psk_db_sql.cpp b/comm/third_party/botan/src/lib/psk_db/psk_db_sql.cpp new file mode 100644 index 0000000000..92dcb5f1dc --- /dev/null +++ b/comm/third_party/botan/src/lib/psk_db/psk_db_sql.cpp @@ -0,0 +1,75 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +Encrypted_PSK_Database_SQL::Encrypted_PSK_Database_SQL(const secure_vector& master_key, + std::shared_ptr db, + const std::string& table_name) : + Encrypted_PSK_Database(master_key), + m_db(db), + m_table_name(table_name) + { + m_db->create_table( + "create table if not exists " + m_table_name + + "(psk_name TEXT PRIMARY KEY, psk_value TEXT)"); + } + +Encrypted_PSK_Database_SQL::~Encrypted_PSK_Database_SQL() + { + /* for ~unique_ptr */ + } + +void Encrypted_PSK_Database_SQL::kv_del(const std::string& name) + { + auto stmt = m_db->new_statement("delete from " + m_table_name + " where psk_name=?1"); + stmt->bind(1, name); + stmt->spin(); + } + +void Encrypted_PSK_Database_SQL::kv_set(const std::string& name, const std::string& value) + { + auto stmt = m_db->new_statement("insert or replace into " + m_table_name + " values(?1, ?2)"); + + stmt->bind(1, name); + stmt->bind(2, value); + + stmt->spin(); + } + +std::string Encrypted_PSK_Database_SQL::kv_get(const std::string& name) const + { + auto stmt = m_db->new_statement("select psk_value from " + m_table_name + + " where psk_name = ?1"); + + stmt->bind(1, name); + + while(stmt->step()) + { + return stmt->get_str(0); + } + return ""; + } + +std::set Encrypted_PSK_Database_SQL::kv_get_all() const + { + std::set names; + + auto stmt = m_db->new_statement("select psk_name from " + m_table_name); + + while(stmt->step()) + { + names.insert(stmt->get_str(0)); + } + + return names; + } + +} + diff --git a/comm/third_party/botan/src/lib/psk_db/psk_db_sql.h b/comm/third_party/botan/src/lib/psk_db/psk_db_sql.h new file mode 100644 index 0000000000..170ca674c5 --- /dev/null +++ b/comm/third_party/botan/src/lib/psk_db/psk_db_sql.h @@ -0,0 +1,13 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PSK_DB_SQL_H_ +#define BOTAN_PSK_DB_SQL_H_ + +#include +BOTAN_DEPRECATED_HEADER(psk_db_sql.h) + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/blinding.cpp b/comm/third_party/botan/src/lib/pubkey/blinding.cpp new file mode 100644 index 0000000000..d1f299229a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/blinding.cpp @@ -0,0 +1,66 @@ +/* +* Blinding for public key operations +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +Blinder::Blinder(const BigInt& modulus, + RandomNumberGenerator& rng, + std::function fwd, + std::function inv) : + m_reducer(modulus), + m_rng(rng), + m_fwd_fn(fwd), + m_inv_fn(inv), + m_modulus_bits(modulus.bits()), + m_e{}, + m_d{}, + m_counter{} + { + const BigInt k = blinding_nonce(); + m_e = m_fwd_fn(k); + m_d = m_inv_fn(k); + } + +BigInt Blinder::blinding_nonce() const + { + return BigInt(m_rng, m_modulus_bits - 1); + } + +BigInt Blinder::blind(const BigInt& i) const + { + if(!m_reducer.initialized()) + throw Invalid_State("Blinder not initialized, cannot blind"); + + ++m_counter; + + if((BOTAN_BLINDING_REINIT_INTERVAL > 0) && (m_counter > BOTAN_BLINDING_REINIT_INTERVAL)) + { + const BigInt k = blinding_nonce(); + m_e = m_fwd_fn(k); + m_d = m_inv_fn(k); + m_counter = 0; + } + else + { + m_e = m_reducer.square(m_e); + m_d = m_reducer.square(m_d); + } + + return m_reducer.multiply(i, m_e); + } + +BigInt Blinder::unblind(const BigInt& i) const + { + if(!m_reducer.initialized()) + throw Invalid_State("Blinder not initialized, cannot unblind"); + + return m_reducer.multiply(i, m_d); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/blinding.h b/comm/third_party/botan/src/lib/pubkey/blinding.h new file mode 100644 index 0000000000..988a41a357 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/blinding.h @@ -0,0 +1,80 @@ +/* +* Blinding for public key operations +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BLINDER_H_ +#define BOTAN_BLINDER_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(blinding.h) + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Blinding Function Object. +*/ +class BOTAN_PUBLIC_API(2,0) Blinder final + { + public: + /** + * Blind a value. + * The blinding nonce k is freshly generated after + * BOTAN_BLINDING_REINIT_INTERVAL calls to blind(). + * BOTAN_BLINDING_REINIT_INTERVAL = 0 means a fresh + * nonce is only generated once. On every other call, + * an updated nonce is used for blinding: k' = k*k mod n. + * @param x value to blind + * @return blinded value + */ + BigInt blind(const BigInt& x) const; + + /** + * Unblind a value. + * @param x value to unblind + * @return unblinded value + */ + BigInt unblind(const BigInt& x) const; + + /** + * @param modulus the modulus + * @param rng the RNG to use for generating the nonce + * @param fwd_func a function that calculates the modular + * exponentiation of the public exponent and the given value (the nonce) + * @param inv_func a function that calculates the modular inverse + * of the given value (the nonce) + */ + Blinder(const BigInt& modulus, + RandomNumberGenerator& rng, + std::function fwd_func, + std::function inv_func); + + Blinder(const Blinder&) = delete; + + Blinder& operator=(const Blinder&) = delete; + + RandomNumberGenerator& rng() const { return m_rng; } + + private: + BigInt blinding_nonce() const; + + Modular_Reducer m_reducer; + RandomNumberGenerator& m_rng; + std::function m_fwd_fn; + std::function m_inv_fn; + size_t m_modulus_bits = 0; + + mutable BigInt m_e, m_d; + mutable size_t m_counter = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.cpp b/comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.cpp new file mode 100644 index 0000000000..e11a1e0839 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.cpp @@ -0,0 +1,51 @@ +/* +* CECPQ1 (x25519 + NewHope) +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +void CECPQ1_offer(uint8_t send[CECPQ1_OFFER_BYTES], + CECPQ1_key* offer_key_output, + RandomNumberGenerator& rng) + { + offer_key_output->m_x25519 = rng.random_vec(32); + curve25519_basepoint(send, offer_key_output->m_x25519.data()); + + newhope_keygen(send + 32, &offer_key_output->m_newhope, + rng, Newhope_Mode::BoringSSL); + } + +void CECPQ1_accept(uint8_t shared_key[CECPQ1_SHARED_KEY_BYTES], + uint8_t send[CECPQ1_ACCEPT_BYTES], + const uint8_t received[CECPQ1_OFFER_BYTES], + RandomNumberGenerator& rng) + { + secure_vector x25519_key = rng.random_vec(32); + + curve25519_basepoint(send, x25519_key.data()); + + curve25519_donna(shared_key, x25519_key.data(), received); + + newhope_sharedb(shared_key + 32, send + 32, received + 32, + rng, Newhope_Mode::BoringSSL); + } + +void CECPQ1_finish(uint8_t shared_key[CECPQ1_SHARED_KEY_BYTES], + const CECPQ1_key& offer_key, + const uint8_t received[CECPQ1_ACCEPT_BYTES]) + { + curve25519_donna(shared_key, offer_key.m_x25519.data(), received); + + newhope_shareda(shared_key + 32, &offer_key.m_newhope, received + 32, + Newhope_Mode::BoringSSL); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.h b/comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.h new file mode 100644 index 0000000000..a722899c67 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/cecpq1/cecpq1.h @@ -0,0 +1,38 @@ +/* +* CECPQ1 (x25519 + NewHope) +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CECPQ1_H_ +#define BOTAN_CECPQ1_H_ + +#include +#include + +namespace Botan { + +class CECPQ1_key final + { + public: + secure_vector m_x25519; + newhope_poly m_newhope; + }; + +void BOTAN_PUBLIC_API(2,0) CECPQ1_offer(uint8_t* offer_message, + CECPQ1_key* offer_key_output, + RandomNumberGenerator& rng); + +void BOTAN_PUBLIC_API(2,0) CECPQ1_accept(uint8_t* shared_key, + uint8_t* accept_message, + const uint8_t* offer_message, + RandomNumberGenerator& rng); + +void BOTAN_PUBLIC_API(2,0) CECPQ1_finish(uint8_t* shared_key, + const CECPQ1_key& offer_key, + const uint8_t* accept_message); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/cecpq1/info.txt b/comm/third_party/botan/src/lib/pubkey/cecpq1/info.txt new file mode 100644 index 0000000000..1e50f4c880 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/cecpq1/info.txt @@ -0,0 +1,9 @@ + +CECPQ1 -> 20161116 + + + +newhope +curve25519 + + diff --git a/comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.cpp b/comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.cpp new file mode 100644 index 0000000000..515fdc5e68 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.cpp @@ -0,0 +1,143 @@ +/* +* Curve25519 +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +void curve25519_basepoint(uint8_t mypublic[32], const uint8_t secret[32]) + { + const uint8_t basepoint[32] = { 9 }; + curve25519_donna(mypublic, secret, basepoint); + } + +namespace { + +void size_check(size_t size, const char* thing) + { + if(size != 32) + throw Decoding_Error("Invalid size " + std::to_string(size) + " for Curve25519 " + thing); + } + +secure_vector curve25519(const secure_vector& secret, + const uint8_t pubval[32]) + { + secure_vector out(32); + curve25519_donna(out.data(), secret.data(), pubval); + return out; + } + +} + +AlgorithmIdentifier Curve25519_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); + } + +bool Curve25519_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + return true; // no tests possible? + } + +Curve25519_PublicKey::Curve25519_PublicKey(const AlgorithmIdentifier&, + const std::vector& key_bits) + { + m_public = key_bits; + + size_check(m_public.size(), "public key"); + } + +std::vector Curve25519_PublicKey::public_key_bits() const + { + return m_public; + } + +Curve25519_PrivateKey::Curve25519_PrivateKey(const secure_vector& secret_key) + { + if(secret_key.size() != 32) + throw Decoding_Error("Invalid size for Curve25519 private key"); + + m_public.resize(32); + m_private = secret_key; + curve25519_basepoint(m_public.data(), m_private.data()); + } + +Curve25519_PrivateKey::Curve25519_PrivateKey(RandomNumberGenerator& rng) + { + m_private = rng.random_vec(32); + m_public.resize(32); + curve25519_basepoint(m_public.data(), m_private.data()); + } + +Curve25519_PrivateKey::Curve25519_PrivateKey(const AlgorithmIdentifier&, + const secure_vector& key_bits) + { + BER_Decoder(key_bits).decode(m_private, OCTET_STRING).discard_remaining(); + + size_check(m_private.size(), "private key"); + m_public.resize(32); + curve25519_basepoint(m_public.data(), m_private.data()); + } + +secure_vector Curve25519_PrivateKey::private_key_bits() const + { + return DER_Encoder().encode(m_private, OCTET_STRING).get_contents(); + } + +bool Curve25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const + { + std::vector public_point(32); + curve25519_basepoint(public_point.data(), m_private.data()); + return public_point == m_public; + } + +secure_vector Curve25519_PrivateKey::agree(const uint8_t w[], size_t w_len) const + { + size_check(w_len, "public value"); + return curve25519(m_private, w); + } + +namespace { + +/** +* Curve25519 operation +*/ +class Curve25519_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + + Curve25519_KA_Operation(const Curve25519_PrivateKey& key, const std::string& kdf) : + PK_Ops::Key_Agreement_with_KDF(kdf), + m_key(key) {} + + size_t agreed_value_size() const override { return 32; } + + secure_vector raw_agree(const uint8_t w[], size_t w_len) override + { + return m_key.agree(w, w_len); + } + private: + const Curve25519_PrivateKey& m_key; + }; + +} + +std::unique_ptr +Curve25519_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new Curve25519_KA_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.h b/comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.h new file mode 100644 index 0000000000..c2f8f42b33 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/curve25519/curve25519.h @@ -0,0 +1,123 @@ +/* +* Curve25519 +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CURVE_25519_H_ +#define BOTAN_CURVE_25519_H_ + +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) Curve25519_PublicKey : public virtual Public_Key + { + public: + std::string algo_name() const override { return "Curve25519"; } + + size_t estimated_strength() const override { return 128; } + + size_t key_length() const override { return 255; } + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + std::vector public_value() const { return m_public; } + + /** + * Create a Curve25519 Public Key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + Curve25519_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits); + + /** + * Create a Curve25519 Public Key. + * @param pub 32-byte raw public key + */ + explicit Curve25519_PublicKey(const std::vector& pub) : m_public(pub) {} + + /** + * Create a Curve25519 Public Key. + * @param pub 32-byte raw public key + */ + explicit Curve25519_PublicKey(const secure_vector& pub) : + m_public(pub.begin(), pub.end()) {} + + protected: + Curve25519_PublicKey() = default; + std::vector m_public; + }; + +class BOTAN_PUBLIC_API(2,0) Curve25519_PrivateKey final : public Curve25519_PublicKey, + public virtual Private_Key, + public virtual PK_Key_Agreement_Key + { + public: + /** + * Construct a private key from the specified parameters. + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + Curve25519_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Generate a private key. + * @param rng the RNG to use + */ + explicit Curve25519_PrivateKey(RandomNumberGenerator& rng); + + /** + * Construct a private key from the specified parameters. + * @param secret_key the private key + */ + explicit Curve25519_PrivateKey(const secure_vector& secret_key); + + std::vector public_value() const override { return Curve25519_PublicKey::public_value(); } + + secure_vector agree(const uint8_t w[], size_t w_len) const; + + const secure_vector& get_x() const { return m_private; } + + secure_vector private_key_bits() const override; + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + std::unique_ptr + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + private: + secure_vector m_private; + }; + +typedef Curve25519_PublicKey X25519_PublicKey; +typedef Curve25519_PrivateKey X25519_PrivateKey; + +/* +* The types above are just wrappers for curve25519_donna, plus defining +* encodings for public and private keys. +*/ +void BOTAN_PUBLIC_API(2,0) curve25519_donna(uint8_t mypublic[32], + const uint8_t secret[32], + const uint8_t basepoint[32]); + +/** +* Exponentiate by the x25519 base point +* @param mypublic output value +* @param secret random scalar +*/ +void BOTAN_PUBLIC_API(2,0) curve25519_basepoint(uint8_t mypublic[32], + const uint8_t secret[32]); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/curve25519/donna.cpp b/comm/third_party/botan/src/lib/pubkey/curve25519/donna.cpp new file mode 100644 index 0000000000..352e081dcd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/curve25519/donna.cpp @@ -0,0 +1,464 @@ +/* +* Based on curve25519-donna-c64.c from github.com/agl/curve25519-donna +* revision 80ad9b9930c9baef5829dd2a235b6b7646d32a8e +* +* Further changes +* (C) 2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +/* Copyright 2008, Google Inc. +* All rights reserved. +* +* Code released into the public domain. +* +* curve25519-donna: Curve25519 elliptic curve, public key function +* +* https://code.google.com/p/curve25519-donna/ +* +* Adam Langley +* +* Derived from public domain C code by Daniel J. Bernstein +* +* More information about curve25519 can be found here +* https://cr.yp.to/ecdh.html +* +* djb's sample implementation of curve25519 is written in a special assembly +* language called qhasm and uses the floating point registers. +* +* This is, almost, a clean room reimplementation from the curve25519 paper. It +* uses many of the tricks described therein. Only the crecip function is taken +* from the sample implementation. +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) +typedef donna128 uint128_t; +#endif + +/* Sum two numbers: output += in */ +inline void fsum(uint64_t out[5], const uint64_t in[5]) + { + out[0] += in[0]; + out[1] += in[1]; + out[2] += in[2]; + out[3] += in[3]; + out[4] += in[4]; + } + +/* Find the difference of two numbers: out = in - out +* (note the order of the arguments!) +* +* Assumes that out[i] < 2**52 +* On return, out[i] < 2**55 +*/ +inline void fdifference_backwards(uint64_t out[5], const uint64_t in[5]) + { + /* 152 is 19 << 3 */ + const uint64_t two54m152 = (static_cast(1) << 54) - 152; + const uint64_t two54m8 = (static_cast(1) << 54) - 8; + + out[0] = in[0] + two54m152 - out[0]; + out[1] = in[1] + two54m8 - out[1]; + out[2] = in[2] + two54m8 - out[2]; + out[3] = in[3] + two54m8 - out[3]; + out[4] = in[4] + two54m8 - out[4]; + } + +inline void fadd_sub(uint64_t x[5], + uint64_t y[5]) + { + // TODO merge these and avoid the tmp array + uint64_t tmp[5]; + copy_mem(tmp, y, 5); + fsum(y, x); + fdifference_backwards(x, tmp); // does x - z + } + +/* Multiply a number by a scalar: out = in * scalar */ +inline void fscalar_product(uint64_t out[5], const uint64_t in[5], const uint64_t scalar) + { + uint128_t a = uint128_t(in[0]) * scalar; + out[0] = a & 0x7ffffffffffff; + + a = uint128_t(in[1]) * scalar + carry_shift(a, 51); + out[1] = a & 0x7ffffffffffff; + + a = uint128_t(in[2]) * scalar + carry_shift(a, 51); + out[2] = a & 0x7ffffffffffff; + + a = uint128_t(in[3]) * scalar + carry_shift(a, 51); + out[3] = a & 0x7ffffffffffff; + + a = uint128_t(in[4]) * scalar + carry_shift(a, 51); + out[4] = a & 0x7ffffffffffff; + + out[0] += carry_shift(a, 51) * 19; + } + +/* Multiply two numbers: out = in2 * in +* +* out must be distinct to both inputs. The inputs are reduced coefficient +* form, the output is not. +* +* Assumes that in[i] < 2**55 and likewise for in2. +* On return, out[i] < 2**52 +*/ +inline void fmul(uint64_t out[5], const uint64_t in[5], const uint64_t in2[5]) + { + const uint128_t s0 = in2[0]; + const uint128_t s1 = in2[1]; + const uint128_t s2 = in2[2]; + const uint128_t s3 = in2[3]; + const uint128_t s4 = in2[4]; + + uint64_t r0 = in[0]; + uint64_t r1 = in[1]; + uint64_t r2 = in[2]; + uint64_t r3 = in[3]; + uint64_t r4 = in[4]; + + uint128_t t0 = r0 * s0; + uint128_t t1 = r0 * s1 + r1 * s0; + uint128_t t2 = r0 * s2 + r2 * s0 + r1 * s1; + uint128_t t3 = r0 * s3 + r3 * s0 + r1 * s2 + r2 * s1; + uint128_t t4 = r0 * s4 + r4 * s0 + r3 * s1 + r1 * s3 + r2 * s2; + + r4 *= 19; + r1 *= 19; + r2 *= 19; + r3 *= 19; + + t0 += r4 * s1 + r1 * s4 + r2 * s3 + r3 * s2; + t1 += r4 * s2 + r2 * s4 + r3 * s3; + t2 += r4 * s3 + r3 * s4; + t3 += r4 * s4; + + r0 = t0 & 0x7ffffffffffff; t1 += carry_shift(t0, 51); + r1 = t1 & 0x7ffffffffffff; t2 += carry_shift(t1, 51); + r2 = t2 & 0x7ffffffffffff; t3 += carry_shift(t2, 51); + r3 = t3 & 0x7ffffffffffff; t4 += carry_shift(t3, 51); + r4 = t4 & 0x7ffffffffffff; uint64_t c = carry_shift(t4, 51); + + r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; + r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; + r2 += c; + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + } + +inline void fsquare(uint64_t out[5], const uint64_t in[5], size_t count = 1) + { + uint64_t r0 = in[0]; + uint64_t r1 = in[1]; + uint64_t r2 = in[2]; + uint64_t r3 = in[3]; + uint64_t r4 = in[4]; + + for(size_t i = 0; i != count; ++i) + { + const uint64_t d0 = r0 * 2; + const uint64_t d1 = r1 * 2; + const uint64_t d2 = r2 * 2 * 19; + const uint64_t d419 = r4 * 19; + const uint64_t d4 = d419 * 2; + + uint128_t t0 = uint128_t(r0) * r0 + uint128_t(d4) * r1 + uint128_t(d2) * (r3 ); + uint128_t t1 = uint128_t(d0) * r1 + uint128_t(d4) * r2 + uint128_t(r3) * (r3 * 19); + uint128_t t2 = uint128_t(d0) * r2 + uint128_t(r1) * r1 + uint128_t(d4) * (r3 ); + uint128_t t3 = uint128_t(d0) * r3 + uint128_t(d1) * r2 + uint128_t(r4) * (d419 ); + uint128_t t4 = uint128_t(d0) * r4 + uint128_t(d1) * r3 + uint128_t(r2) * (r2 ); + + r0 = t0 & 0x7ffffffffffff; t1 += carry_shift(t0, 51); + r1 = t1 & 0x7ffffffffffff; t2 += carry_shift(t1, 51); + r2 = t2 & 0x7ffffffffffff; t3 += carry_shift(t2, 51); + r3 = t3 & 0x7ffffffffffff; t4 += carry_shift(t3, 51); + r4 = t4 & 0x7ffffffffffff; uint64_t c = carry_shift(t4, 51); + + r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; + r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; + r2 += c; + } + + out[0] = r0; + out[1] = r1; + out[2] = r2; + out[3] = r3; + out[4] = r4; + } + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +inline void fexpand(uint64_t *out, const uint8_t *in) + { + out[0] = load_le(in, 0) & 0x7ffffffffffff; + out[1] = (load_le(in+6, 0) >> 3) & 0x7ffffffffffff; + out[2] = (load_le(in+12, 0) >> 6) & 0x7ffffffffffff; + out[3] = (load_le(in+19, 0) >> 1) & 0x7ffffffffffff; + out[4] = (load_le(in+24, 0) >> 12) & 0x7ffffffffffff; + } + +/* Take a fully reduced polynomial form number and contract it into a +* little-endian, 32-byte array +*/ +inline void fcontract(uint8_t *out, const uint64_t input[5]) + { + uint128_t t0 = input[0]; + uint128_t t1 = input[1]; + uint128_t t2 = input[2]; + uint128_t t3 = input[3]; + uint128_t t4 = input[4]; + + for(size_t i = 0; i != 2; ++i) + { + t1 += t0 >> 51; t0 &= 0x7ffffffffffff; + t2 += t1 >> 51; t1 &= 0x7ffffffffffff; + t3 += t2 >> 51; t2 &= 0x7ffffffffffff; + t4 += t3 >> 51; t3 &= 0x7ffffffffffff; + t0 += (t4 >> 51) * 19; t4 &= 0x7ffffffffffff; + } + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + + t0 += 19; + + t1 += t0 >> 51; t0 &= 0x7ffffffffffff; + t2 += t1 >> 51; t1 &= 0x7ffffffffffff; + t3 += t2 >> 51; t2 &= 0x7ffffffffffff; + t4 += t3 >> 51; t3 &= 0x7ffffffffffff; + t0 += (t4 >> 51) * 19; t4 &= 0x7ffffffffffff; + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + + t0 += 0x8000000000000 - 19; + t1 += 0x8000000000000 - 1; + t2 += 0x8000000000000 - 1; + t3 += 0x8000000000000 - 1; + t4 += 0x8000000000000 - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + + t1 += t0 >> 51; t0 &= 0x7ffffffffffff; + t2 += t1 >> 51; t1 &= 0x7ffffffffffff; + t3 += t2 >> 51; t2 &= 0x7ffffffffffff; + t4 += t3 >> 51; t3 &= 0x7ffffffffffff; + t4 &= 0x7ffffffffffff; + + store_le(out, + combine_lower(t0, 0, t1, 51), + combine_lower(t1, 13, t2, 38), + combine_lower(t2, 26, t3, 25), + combine_lower(t3, 39, t4, 12)); + } + +/* Input: Q, Q', Q-Q' +* Out: 2Q, Q+Q' +* +* result.two_q (2*Q): long form +* result.q_plus_q_dash (Q + Q): long form +* in_q: short form, destroyed +* in_q_dash: short form, destroyed +* in_q_minus_q_dash: short form, preserved +*/ +void fmonty(uint64_t result_two_q_x[5], + uint64_t result_two_q_z[5], + uint64_t result_q_plus_q_dash_x[5], + uint64_t result_q_plus_q_dash_z[5], + uint64_t in_q_x[5], + uint64_t in_q_z[5], + uint64_t in_q_dash_x[5], + uint64_t in_q_dash_z[5], + const uint64_t q_minus_q_dash[5]) + { + uint64_t zzz[5]; + uint64_t xx[5]; + uint64_t zz[5]; + uint64_t xxprime[5]; + uint64_t zzprime[5]; + uint64_t zzzprime[5]; + + fadd_sub(in_q_z, in_q_x); + fadd_sub(in_q_dash_z, in_q_dash_x); + + fmul(xxprime, in_q_dash_x, in_q_z); + fmul(zzprime, in_q_dash_z, in_q_x); + + fadd_sub(zzprime, xxprime); + + fsquare(result_q_plus_q_dash_x, xxprime); + fsquare(zzzprime, zzprime); + fmul(result_q_plus_q_dash_z, zzzprime, q_minus_q_dash); + + fsquare(xx, in_q_x); + fsquare(zz, in_q_z); + fmul(result_two_q_x, xx, zz); + + fdifference_backwards(zz, xx); // does zz = xx - zz + fscalar_product(zzz, zz, 121665); + fsum(zzz, xx); + + fmul(result_two_q_z, zz, zzz); + } + +/* +* Maybe swap the contents of two uint64_t arrays (@a and @b), +* Param @iswap is assumed to be either 0 or 1 +* +* This function performs the swap without leaking any side-channel +* information. +*/ +inline void swap_conditional(uint64_t a[5], uint64_t b[5], + uint64_t c[5], uint64_t d[5], + uint64_t iswap) + { + const uint64_t swap = 0 - iswap; + + for(size_t i = 0; i < 5; ++i) + { + const uint64_t x0 = swap & (a[i] ^ b[i]); + const uint64_t x1 = swap & (c[i] ^ d[i]); + a[i] ^= x0; + b[i] ^= x0; + c[i] ^= x1; + d[i] ^= x1; + } + } + +/* Calculates nQ where Q is the x-coordinate of a point on the curve +* +* resultx/resultz: the x/z coordinate of the resulting curve point (short form) +* n: a little endian, 32-byte number +* q: a point of the curve (short form) +*/ +void cmult(uint64_t resultx[5], uint64_t resultz[5], const uint8_t n[32], const uint64_t q[5]) + { + uint64_t a[5] = {0}; // nqpqx + uint64_t b[5] = {1}; // npqpz + uint64_t c[5] = {1}; // nqx + uint64_t d[5] = {0}; // nqz + uint64_t e[5] = {0}; // npqqx2 + uint64_t f[5] = {1}; // npqqz2 + uint64_t g[5] = {0}; // nqx2 + uint64_t h[5] = {1}; // nqz2 + + copy_mem(a, q, 5); + + for(size_t i = 0; i < 32; ++i) + { + const uint64_t bit0 = (n[31 - i] >> 7) & 1; + const uint64_t bit1 = (n[31 - i] >> 6) & 1; + const uint64_t bit2 = (n[31 - i] >> 5) & 1; + const uint64_t bit3 = (n[31 - i] >> 4) & 1; + const uint64_t bit4 = (n[31 - i] >> 3) & 1; + const uint64_t bit5 = (n[31 - i] >> 2) & 1; + const uint64_t bit6 = (n[31 - i] >> 1) & 1; + const uint64_t bit7 = (n[31 - i] >> 0) & 1; + + swap_conditional(c, a, d, b, bit0); + fmonty(g, h, e, f, c, d, a, b, q); + + swap_conditional(g, e, h, f, bit0 ^ bit1); + fmonty(c, d, a, b, g, h, e, f, q); + + swap_conditional(c, a, d, b, bit1 ^ bit2); + fmonty(g, h, e, f, c, d, a, b, q); + + swap_conditional(g, e, h, f, bit2 ^ bit3); + fmonty(c, d, a, b, g, h, e, f, q); + + swap_conditional(c, a, d, b, bit3 ^ bit4); + fmonty(g, h, e, f, c, d, a, b, q); + + swap_conditional(g, e, h, f, bit4 ^ bit5); + fmonty(c, d, a, b, g, h, e, f, q); + + swap_conditional(c, a, d, b, bit5 ^ bit6); + fmonty(g, h, e, f, c, d, a, b, q); + + swap_conditional(g, e, h, f, bit6 ^ bit7); + fmonty(c, d, a, b, g, h, e, f, q); + + swap_conditional(c, a, d, b, bit7); + } + + copy_mem(resultx, c, 5); + copy_mem(resultz, d, 5); + } + + +// ----------------------------------------------------------------------------- +// Shamelessly copied from djb's code, tightened a little +// ----------------------------------------------------------------------------- +void crecip(uint64_t out[5], const uint64_t z[5]) + { + uint64_t a[5]; + uint64_t b[5]; + uint64_t c[5]; + uint64_t t0[5]; + + fsquare(a, z); // 2 + fsquare(t0, a, 2); // 8 + fmul(b, t0, z); // 9 + fmul(a, b, a); // 11 + fsquare(t0, a); // 22 + fmul(b, t0, b); // 2^5 - 2^0 = 31 + fsquare(t0, b, 5); // 2^10 - 2^5 + fmul(b, t0, b); // 2^10 - 2^0 + fsquare(t0, b, 10); // 2^20 - 2^10 + fmul(c, t0, b); // 2^20 - 2^0 + fsquare(t0, c, 20); // 2^40 - 2^20 + fmul(t0, t0, c); // 2^40 - 2^0 + fsquare(t0, t0, 10); // 2^50 - 2^10 + fmul(b, t0, b); // 2^50 - 2^0 + fsquare(t0, b, 50); // 2^100 - 2^50 + fmul(c, t0, b); // 2^100 - 2^0 + fsquare(t0, c, 100); // 2^200 - 2^100 + fmul(t0, t0, c); // 2^200 - 2^0 + fsquare(t0, t0, 50); // 2^250 - 2^50 + fmul(t0, t0, b); // 2^250 - 2^0 + fsquare(t0, t0, 5); // 2^255 - 2^5 + fmul(out, t0, a); // 2^255 - 21 + } + +} + +void +curve25519_donna(uint8_t mypublic[32], const uint8_t secret[32], const uint8_t basepoint[32]) + { + CT::poison(secret, 32); + CT::poison(basepoint, 32); + + uint64_t bp[5], x[5], z[5], zmone[5]; + uint8_t e[32]; + + copy_mem(e, secret, 32); + e[ 0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + fcontract(mypublic, z); + + CT::unpoison(secret, 32); + CT::unpoison(basepoint, 32); + CT::unpoison(mypublic, 32); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/curve25519/info.txt b/comm/third_party/botan/src/lib/pubkey/curve25519/info.txt new file mode 100644 index 0000000000..3818b0606b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/curve25519/info.txt @@ -0,0 +1,8 @@ + +CURVE_25519 -> 20170621 +X25519 -> 20180910 + + + +curve25519.h + diff --git a/comm/third_party/botan/src/lib/pubkey/dh/dh.cpp b/comm/third_party/botan/src/lib/pubkey/dh/dh.cpp new file mode 100644 index 0000000000..687032a696 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dh/dh.cpp @@ -0,0 +1,142 @@ +/* +* Diffie-Hellman +* (C) 1999-2007,2016,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* DH_PublicKey Constructor +*/ +DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) + { + m_group = grp; + m_y = y1; + } + +/* +* Return the public value for key agreement +*/ +std::vector DH_PublicKey::public_value() const + { + return unlock(BigInt::encode_1363(m_y, group_p().bytes())); + } + +/* +* Create a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + m_group = grp; + + if(x_arg == 0) + { + const size_t exp_bits = grp.exponent_bits(); + m_x.randomize(rng, exp_bits); + m_y = m_group.power_g_p(m_x, exp_bits); + } + else + { + m_x = x_arg; + + if(m_y == 0) + m_y = m_group.power_g_p(m_x, grp.p_bits()); + } + } + +/* +* Load a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + if(m_y.is_zero()) + { + m_y = m_group.power_g_p(m_x, m_group.p_bits()); + } + } + +/* +* Return the public value for key agreement +*/ +std::vector DH_PrivateKey::public_value() const + { + return DH_PublicKey::public_value(); + } + +namespace { + +/** +* DH operation +*/ +class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + + DH_KA_Operation(const DH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : + PK_Ops::Key_Agreement_with_KDF(kdf), + m_p(key.group_p()), + m_x(key.get_x()), + m_x_bits(m_x.bits()), + m_monty_p(key.get_group().monty_params_p()), + m_blinder(m_p, + rng, + [](const BigInt& k) { return k; }, + [this](const BigInt& k) { return powermod_x_p(inverse_mod(k, m_p)); }) + {} + + size_t agreed_value_size() const override { return m_p.bytes(); } + + secure_vector raw_agree(const uint8_t w[], size_t w_len) override; + private: + BigInt powermod_x_p(const BigInt& v) const + { + const size_t powm_window = 4; + auto powm_v_p = monty_precompute(m_monty_p, v, powm_window); + return monty_execute(*powm_v_p, m_x, m_x_bits); + } + + const BigInt& m_p; + const BigInt& m_x; + const size_t m_x_bits; + std::shared_ptr m_monty_p; + Blinder m_blinder; + }; + +secure_vector DH_KA_Operation::raw_agree(const uint8_t w[], size_t w_len) + { + BigInt v = BigInt::decode(w, w_len); + + if(v <= 1 || v >= m_p - 1) + throw Invalid_Argument("DH agreement - invalid key provided"); + + v = m_blinder.blind(v); + v = powermod_x_p(v); + v = m_blinder.unblind(v); + + return BigInt::encode_1363(v, m_p.bytes()); + } + +} + +std::unique_ptr +DH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new DH_KA_Operation(*this, params, rng)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/dh/dh.h b/comm/third_party/botan/src/lib/pubkey/dh/dh.h new file mode 100644 index 0000000000..e3aa0d2c5b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dh/dh.h @@ -0,0 +1,81 @@ +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DIFFIE_HELLMAN_H_ +#define BOTAN_DIFFIE_HELLMAN_H_ + +#include + +namespace Botan { + +/** +* This class represents Diffie-Hellman public keys. +*/ +class BOTAN_PUBLIC_API(2,0) DH_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const override { return "DH"; } + + std::vector public_value() const; + + DL_Group::Format group_format() const override { return DL_Group::ANSI_X9_42; } + + /** + * Create a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + DH_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) {} + + /** + * Construct a public key with the specified parameters. + * @param grp the DL group to use in the key + * @param y the public value y + */ + DH_PublicKey(const DL_Group& grp, const BigInt& y); + protected: + DH_PublicKey() = default; + }; + +/** +* This class represents Diffie-Hellman private keys. +*/ +class BOTAN_PUBLIC_API(2,0) DH_PrivateKey final : public DH_PublicKey, + public PK_Key_Agreement_Key, + public virtual DL_Scheme_PrivateKey + { + public: + std::vector public_value() const override; + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Create a private key. + * @param rng random number generator to use + * @param grp the group to be used in the key + * @param x the key's secret value (or if zero, generate a new key) + */ + DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, + const BigInt& x = 0); + + std::unique_ptr + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/dh/info.txt b/comm/third_party/botan/src/lib/pubkey/dh/info.txt new file mode 100644 index 0000000000..1b9ba24948 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dh/info.txt @@ -0,0 +1,13 @@ + +DIFFIE_HELLMAN -> 20131128 + + + +dh.h + + + +dl_algo +dl_group +numbertheory + diff --git a/comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.cpp b/comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.cpp new file mode 100644 index 0000000000..15b0b175e4 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.cpp @@ -0,0 +1,84 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +size_t DL_Scheme_PublicKey::key_length() const + { + return m_group.p_bits(); + } + +size_t DL_Scheme_PublicKey::estimated_strength() const + { + return m_group.estimated_strength(); + } + +AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + m_group.DER_encode(group_format())); + } + +std::vector DL_Scheme_PublicKey::public_key_bits() const + { + std::vector output; + DER_Encoder(output).encode(m_y); + return output; + } + +DL_Scheme_PublicKey::DL_Scheme_PublicKey(const DL_Group& group, const BigInt& y) : + m_y(y), + m_group(group) + { + } + +DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits, + DL_Group::Format format) : + m_group(alg_id.get_parameters(), format) + { + BER_Decoder(key_bits).decode(m_y); + } + +secure_vector DL_Scheme_PrivateKey::private_key_bits() const + { + return DER_Encoder().encode(m_x).get_contents(); + } + +DL_Scheme_PrivateKey::DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + DL_Group::Format format) + { + m_group.BER_decode(alg_id.get_parameters(), format); + + BER_Decoder(key_bits).decode(m_x); + } + +/* +* Check Public DL Parameters +*/ +bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + return m_group.verify_group(rng, strong) && m_group.verify_public_element(m_y); + } + +/* +* Check DL Scheme Private Parameters +*/ +bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + return m_group.verify_group(rng, strong) && m_group.verify_element_pair(m_y, m_x); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.h b/comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.h new file mode 100644 index 0000000000..af01bc217a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_algo/dl_algo.h @@ -0,0 +1,140 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DL_ALGO_H_ +#define BOTAN_DL_ALGO_H_ + +#include +#include + +namespace Botan { + +/** +* This class represents discrete logarithm (DL) public keys. +*/ +class BOTAN_PUBLIC_API(2,0) DL_Scheme_PublicKey : public virtual Public_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + /** + * Get the DL domain parameters of this key. + * @return DL domain parameters of this key + */ + const DL_Group& get_domain() const { return m_group; } + + /** + * Get the DL domain parameters of this key. + * @return DL domain parameters of this key + */ + const DL_Group& get_group() const { return m_group; } + + /** + * Get the public value y with y = g^x mod p where x is the secret key. + */ + const BigInt& get_y() const { return m_y; } + + /** + * Get the prime p of the underlying DL group. + * @return prime p + */ + const BigInt& group_p() const { return m_group.get_p(); } + + /** + * Get the prime q of the underlying DL group. + * @return prime q + */ + const BigInt& group_q() const { return m_group.get_q(); } + + /** + * Get the generator g of the underlying DL group. + * @return generator g + */ + const BigInt& group_g() const { return m_group.get_g(); } + + /** + * Get the underlying groups encoding format. + * @return encoding format + */ + virtual DL_Group::Format group_format() const = 0; + + size_t key_length() const override; + size_t estimated_strength() const override; + + DL_Scheme_PublicKey& operator=(const DL_Scheme_PublicKey& other) = default; + + protected: + DL_Scheme_PublicKey() = default; + + /** + * Create a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + * @param group_format the underlying groups encoding format + */ + DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits, + DL_Group::Format group_format); + + DL_Scheme_PublicKey(const DL_Group& group, const BigInt& y); + + /** + * The DL public key + */ + BigInt m_y; + + /** + * The DL group + */ + DL_Group m_group; + }; + +/** +* This class represents discrete logarithm (DL) private keys. +*/ +class BOTAN_PUBLIC_API(2,0) DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, + public virtual Private_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const override; + + /** + * Get the secret key x. + * @return secret key + */ + const BigInt& get_x() const { return m_x; } + + secure_vector private_key_bits() const override; + + DL_Scheme_PrivateKey& operator=(const DL_Scheme_PrivateKey& other) = default; + + protected: + /** + * Create a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded private key bits + * @param group_format the underlying groups encoding format + */ + DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + DL_Group::Format group_format); + + DL_Scheme_PrivateKey() = default; + + /** + * The DL private key + */ + BigInt m_x; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/dl_algo/info.txt b/comm/third_party/botan/src/lib/pubkey/dl_algo/info.txt new file mode 100644 index 0000000000..44e649cd67 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_algo/info.txt @@ -0,0 +1,10 @@ + +DL_PUBLIC_KEY_FAMILY -> 20131128 + + + +asn1 +dl_group +numbertheory +rng + diff --git a/comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.cpp b/comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.cpp new file mode 100644 index 0000000000..05f9640e30 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.cpp @@ -0,0 +1,646 @@ +/* +* Discrete Logarithm Parameters +* (C) 1999-2008,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class DL_Group_Data final + { + public: + DL_Group_Data(const BigInt& p, const BigInt& q, const BigInt& g, DL_Group_Source source) : + m_p(p), m_q(q), m_g(g), + m_mod_p(p), + m_mod_q(q), + m_monty_params(std::make_shared(m_p, m_mod_p)), + m_monty(monty_precompute(m_monty_params, m_g, /*window bits=*/4)), + m_p_bits(p.bits()), + m_q_bits(q.bits()), + m_estimated_strength(dl_work_factor(m_p_bits)), + m_exponent_bits(dl_exponent_size(m_p_bits)), + m_source(source) + { + } + + ~DL_Group_Data() = default; + + DL_Group_Data(const DL_Group_Data& other) = delete; + DL_Group_Data& operator=(const DL_Group_Data& other) = delete; + + const BigInt& p() const { return m_p; } + const BigInt& q() const { return m_q; } + const BigInt& g() const { return m_g; } + + BigInt mod_p(const BigInt& x) const { return m_mod_p.reduce(x); } + + BigInt multiply_mod_p(const BigInt& x, const BigInt& y) const + { + return m_mod_p.multiply(x, y); + } + + BigInt mod_q(const BigInt& x) const { return m_mod_q.reduce(x); } + + BigInt multiply_mod_q(const BigInt& x, const BigInt& y) const + { + return m_mod_q.multiply(x, y); + } + + BigInt square_mod_q(const BigInt& x) const + { + return m_mod_q.square(x); + } + + std::shared_ptr monty_params_p() const + { return m_monty_params; } + + size_t p_bits() const { return m_p_bits; } + size_t q_bits() const { return m_q_bits; } + size_t p_bytes() const { return (m_p_bits + 7) / 8; } + size_t q_bytes() const { return (m_q_bits + 7) / 8; } + + size_t estimated_strength() const { return m_estimated_strength; } + + size_t exponent_bits() const { return m_exponent_bits; } + + BigInt power_g_p(const BigInt& k, size_t max_k_bits) const + { + return monty_execute(*m_monty, k, max_k_bits); + } + + bool q_is_set() const { return m_q_bits > 0; } + + void assert_q_is_set(const std::string& function) const + { + if(q_is_set() == false) + throw Invalid_State("DL_Group::" + function + " q is not set for this group"); + } + + DL_Group_Source source() const { return m_source; } + + private: + BigInt m_p; + BigInt m_q; + BigInt m_g; + Modular_Reducer m_mod_p; + Modular_Reducer m_mod_q; + std::shared_ptr m_monty_params; + std::shared_ptr m_monty; + size_t m_p_bits; + size_t m_q_bits; + size_t m_estimated_strength; + size_t m_exponent_bits; + DL_Group_Source m_source; + }; + +//static +std::shared_ptr DL_Group::BER_decode_DL_group(const uint8_t data[], size_t data_len, + DL_Group::Format format, + DL_Group_Source source) + { + BigInt p, q, g; + + BER_Decoder decoder(data, data_len); + BER_Decoder ber = decoder.start_cons(SEQUENCE); + + if(format == DL_Group::ANSI_X9_57) + { + ber.decode(p) + .decode(q) + .decode(g) + .verify_end(); + } + else if(format == DL_Group::ANSI_X9_42) + { + ber.decode(p) + .decode(g) + .decode(q) + .discard_remaining(); + } + else if(format == DL_Group::PKCS_3) + { + // q is left as zero + ber.decode(p) + .decode(g) + .discard_remaining(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + + return std::make_shared(p, q, g, source); + } + +//static +std::shared_ptr +DL_Group::load_DL_group_info(const char* p_str, + const char* q_str, + const char* g_str) + { + const BigInt p(p_str); + const BigInt q(q_str); + const BigInt g(g_str); + + return std::make_shared(p, q, g, DL_Group_Source::Builtin); + } + +//static +std::shared_ptr +DL_Group::load_DL_group_info(const char* p_str, + const char* g_str) + { + const BigInt p(p_str); + const BigInt q = (p - 1) / 2; + const BigInt g(g_str); + + return std::make_shared(p, q, g, DL_Group_Source::Builtin); + } + +namespace { + +DL_Group::Format pem_label_to_dl_format(const std::string& label) + { + if(label == "DH PARAMETERS") + return DL_Group::PKCS_3; + else if(label == "DSA PARAMETERS") + return DL_Group::ANSI_X9_57; + else if(label == "X942 DH PARAMETERS" || label == "X9.42 DH PARAMETERS") + return DL_Group::ANSI_X9_42; + else + throw Decoding_Error("DL_Group: Invalid PEM label " + label); + } + +} + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const std::string& str) + { + // Either a name or a PEM block, try name first + m_data = DL_group_info(str); + + if(m_data == nullptr) + { + try + { + std::string label; + const std::vector ber = unlock(PEM_Code::decode(str, label)); + Format format = pem_label_to_dl_format(label); + + m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource); + } + catch(...) {} + } + + if(m_data == nullptr) + throw Invalid_Argument("DL_Group: Unknown group " + str); + } + +namespace { + +/* +* Create generator of the q-sized subgroup (DSA style generator) +*/ +BigInt make_dsa_generator(const BigInt& p, const BigInt& q) + { + BigInt e, r; + vartime_divide(p - 1, q, e, r); + + if(e == 0 || r > 0) + throw Invalid_Argument("make_dsa_generator q does not divide p-1"); + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + // TODO precompute! + BigInt g = power_mod(PRIMES[i], e, p); + if(g > 1) + return g; + } + + throw Internal_Error("DL_Group: Couldn't create a suitable generator"); + } + +} + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + PrimeType type, size_t pbits, size_t qbits) + { + if(pbits < 1024) + throw Invalid_Argument("DL_Group: prime size " + std::to_string(pbits) + " is too small"); + + if(type == Strong) + { + if(qbits != 0 && qbits != pbits - 1) + throw Invalid_Argument("Cannot create strong-prime DL_Group with specified q bits"); + + const BigInt p = random_safe_prime(rng, pbits); + const BigInt q = (p - 1) / 2; + + /* + Always choose a generator that is quadratic reside mod p, + this forces g to be a generator of the subgroup of size q. + */ + BigInt g = 2; + if(jacobi(g, p) != 1) + { + // prime table does not contain 2 + for(size_t i = 0; i < PRIME_TABLE_SIZE; ++i) + { + g = PRIMES[i]; + if(jacobi(g, p) == 1) + break; + } + } + + m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); + } + else if(type == Prime_Subgroup) + { + if(qbits == 0) + qbits = dl_exponent_size(pbits); + + const BigInt q = random_prime(rng, qbits); + Modular_Reducer mod_2q(2*q); + BigInt X; + BigInt p; + while(p.bits() != pbits || !is_prime(p, rng, 128, true)) + { + X.randomize(rng, pbits); + p = X - mod_2q.reduce(X) + 1; + } + + const BigInt g = make_dsa_generator(p, q); + m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); + } + else if(type == DSA_Kosherizer) + { + if(qbits == 0) + qbits = ((pbits <= 1024) ? 160 : 256); + + BigInt p, q; + generate_dsa_primes(rng, p, q, pbits, qbits); + const BigInt g = make_dsa_generator(p, q); + m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); + } + else + { + throw Invalid_Argument("DL_Group unknown PrimeType"); + } + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + const std::vector& seed, + size_t pbits, size_t qbits) + { + BigInt p, q; + + if(!generate_dsa_primes(rng, p, q, pbits, qbits, seed)) + throw Invalid_Argument("DL_Group: The seed given does not generate a DSA group"); + + BigInt g = make_dsa_generator(p, q); + + m_data = std::make_shared(p, q, g, DL_Group_Source::RandomlyGenerated); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p, const BigInt& g) + { + m_data = std::make_shared(p, 0, g, DL_Group_Source::ExternalSource); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p, const BigInt& q, const BigInt& g) + { + m_data = std::make_shared(p, q, g, DL_Group_Source::ExternalSource); + } + +const DL_Group_Data& DL_Group::data() const + { + if(m_data) + return *m_data; + + throw Invalid_State("DL_Group uninitialized"); + } + +bool DL_Group::verify_public_element(const BigInt& y) const + { + const BigInt& p = get_p(); + const BigInt& q = get_q(); + + if(y <= 1 || y >= p) + return false; + + if(q.is_zero() == false) + { + if(power_mod(y, q, p) != 1) + return false; + } + + return true; + } + +bool DL_Group::verify_element_pair(const BigInt& y, const BigInt& x) const + { + const BigInt& p = get_p(); + + if(y <= 1 || y >= p || x <= 1 || x >= p) + return false; + + if(y != power_g_p(x)) + return false; + + return true; + } + +/* +* Verify the parameters +*/ +bool DL_Group::verify_group(RandomNumberGenerator& rng, + bool strong) const + { + const bool from_builtin = (source() == DL_Group_Source::Builtin); + + if(!strong && from_builtin) + return true; + + const BigInt& p = get_p(); + const BigInt& q = get_q(); + const BigInt& g = get_g(); + + if(g < 2 || p < 3 || q < 0) + return false; + + const size_t test_prob = 128; + const bool is_randomly_generated = (source() != DL_Group_Source::ExternalSource); + + if(q != 0) + { + if((p - 1) % q != 0) + { + return false; + } + if(this->power_g_p(q) != 1) + { + return false; + } + if(!is_prime(q, rng, test_prob, is_randomly_generated)) + { + return false; + } + } + + if(!is_prime(p, rng, test_prob, is_randomly_generated)) + { + return false; + } + + return true; + } + +/* +* Return the prime +*/ +const BigInt& DL_Group::get_p() const + { + return data().p(); + } + +/* +* Return the generator +*/ +const BigInt& DL_Group::get_g() const + { + return data().g(); + } + +/* +* Return the subgroup +*/ +const BigInt& DL_Group::get_q() const + { + return data().q(); + } + +std::shared_ptr DL_Group::monty_params_p() const + { + return data().monty_params_p(); + } + +size_t DL_Group::p_bits() const + { + return data().p_bits(); + } + +size_t DL_Group::p_bytes() const + { + return data().p_bytes(); + } + +size_t DL_Group::q_bits() const + { + data().assert_q_is_set("q_bits"); + return data().q_bits(); + } + +size_t DL_Group::q_bytes() const + { + data().assert_q_is_set("q_bytes"); + return data().q_bytes(); + } + +size_t DL_Group::estimated_strength() const + { + return data().estimated_strength(); + } + +size_t DL_Group::exponent_bits() const + { + return data().exponent_bits(); + } + +BigInt DL_Group::inverse_mod_p(const BigInt& x) const + { + // precompute?? + return inverse_mod(x, get_p()); + } + +BigInt DL_Group::mod_p(const BigInt& x) const + { + return data().mod_p(x); + } + +BigInt DL_Group::multiply_mod_p(const BigInt& x, const BigInt& y) const + { + return data().multiply_mod_p(x, y); + } + +BigInt DL_Group::inverse_mod_q(const BigInt& x) const + { + data().assert_q_is_set("inverse_mod_q"); + // precompute?? + return inverse_mod(x, get_q()); + } + +BigInt DL_Group::mod_q(const BigInt& x) const + { + data().assert_q_is_set("mod_q"); + return data().mod_q(x); + } + +BigInt DL_Group::multiply_mod_q(const BigInt& x, const BigInt& y) const + { + data().assert_q_is_set("multiply_mod_q"); + return data().multiply_mod_q(x, y); + } + +BigInt DL_Group::multiply_mod_q(const BigInt& x, const BigInt& y, const BigInt& z) const + { + data().assert_q_is_set("multiply_mod_q"); + return data().multiply_mod_q(data().multiply_mod_q(x, y), z); + } + +BigInt DL_Group::square_mod_q(const BigInt& x) const + { + data().assert_q_is_set("square_mod_q"); + return data().square_mod_q(x); + } + +BigInt DL_Group::multi_exponentiate(const BigInt& x, const BigInt& y, const BigInt& z) const + { + return monty_multi_exp(data().monty_params_p(), get_g(), x, y, z); + } + +BigInt DL_Group::power_g_p(const BigInt& x) const + { + return data().power_g_p(x, x.bits()); + } + +BigInt DL_Group::power_g_p(const BigInt& x, size_t max_x_bits) const + { + return data().power_g_p(x, max_x_bits); + } + +DL_Group_Source DL_Group::source() const + { + return data().source(); + } + +/* +* DER encode the parameters +*/ +std::vector DL_Group::DER_encode(Format format) const + { + if(get_q().is_zero() && (format == ANSI_X9_57 || format == ANSI_X9_42)) + throw Encoding_Error("Cannot encode DL_Group in ANSI formats when q param is missing"); + + std::vector output; + DER_Encoder der(output); + + if(format == ANSI_X9_57) + { + der.start_cons(SEQUENCE) + .encode(get_p()) + .encode(get_q()) + .encode(get_g()) + .end_cons(); + } + else if(format == ANSI_X9_42) + { + der.start_cons(SEQUENCE) + .encode(get_p()) + .encode(get_g()) + .encode(get_q()) + .end_cons(); + } + else if(format == PKCS_3) + { + der.start_cons(SEQUENCE) + .encode(get_p()) + .encode(get_g()) + .end_cons(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + + return output; + } + +/* +* PEM encode the parameters +*/ +std::string DL_Group::PEM_encode(Format format) const + { + const std::vector encoding = DER_encode(format); + + if(format == PKCS_3) + return PEM_Code::encode(encoding, "DH PARAMETERS"); + else if(format == ANSI_X9_57) + return PEM_Code::encode(encoding, "DSA PARAMETERS"); + else if(format == ANSI_X9_42) + return PEM_Code::encode(encoding, "X9.42 DH PARAMETERS"); + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + } + +DL_Group::DL_Group(const uint8_t ber[], size_t ber_len, Format format) + { + m_data = BER_decode_DL_group(ber, ber_len, format, DL_Group_Source::ExternalSource); + } + +void DL_Group::BER_decode(const std::vector& ber, Format format) + { + m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource); + } + +//static +DL_Group DL_Group::DL_Group_from_PEM(const std::string& pem) + { + std::string label; + const std::vector ber = unlock(PEM_Code::decode(pem, label)); + Format format = pem_label_to_dl_format(label); + return DL_Group(ber, format); + } + +/* +* Decode PEM encoded parameters +*/ +void DL_Group::PEM_decode(const std::string& pem) + { + std::string label; + const std::vector ber = unlock(PEM_Code::decode(pem, label)); + Format format = pem_label_to_dl_format(label); + + m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource); + } + +//static +std::string DL_Group::PEM_for_named_group(const std::string& name) + { + DL_Group group(name); + DL_Group::Format format = group.get_q().is_zero() ? DL_Group::PKCS_3 : DL_Group::ANSI_X9_42; + return group.PEM_encode(format); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.h b/comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.h new file mode 100644 index 0000000000..98ce7a7ad7 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_group/dl_group.h @@ -0,0 +1,357 @@ +/* +* Discrete Logarithm Group +* (C) 1999-2008,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DL_PARAM_H_ +#define BOTAN_DL_PARAM_H_ + +#include + +namespace Botan { + +class Montgomery_Params; +class DL_Group_Data; + +enum class DL_Group_Source { + Builtin, + RandomlyGenerated, + ExternalSource, +}; + +/** +* This class represents discrete logarithm groups. It holds a prime +* modulus p, a generator g, and (optionally) a prime q which is a +* factor of (p-1). In most cases g generates the order-q subgroup. +*/ +class BOTAN_PUBLIC_API(2,0) DL_Group final + { + public: + /** + * Determine the prime creation for DL groups. + */ + enum PrimeType { Strong, Prime_Subgroup, DSA_Kosherizer }; + + /** + * The DL group encoding format variants. + */ + enum Format { + ANSI_X9_42, + ANSI_X9_57, + PKCS_3, + + DSA_PARAMETERS = ANSI_X9_57, + DH_PARAMETERS = ANSI_X9_42, + ANSI_X9_42_DH_PARAMETERS = ANSI_X9_42, + PKCS3_DH_PARAMETERS = PKCS_3 + }; + + /** + * Construct a DL group with uninitialized internal value. + * Use this constructor is you wish to set the groups values + * from a DER or PEM encoded group. + */ + DL_Group() = default; + + /** + * Construct a DL group that is registered in the configuration. + * @param name the name of the group, for example "modp/ietf/3072" + * + * @warning This constructor also accepts PEM inputs. This behavior is + * deprecated and will be removed in a future major release. Instead + * use DL_Group_from_PEM function + */ + explicit DL_Group(const std::string& name); + + /* + * Read a PEM representation + */ + static DL_Group DL_Group_from_PEM(const std::string& pem); + + /** + * Create a new group randomly. + * @param rng the random number generator to use + * @param type specifies how the creation of primes p and q shall + * be performed. If type=Strong, then p will be determined as a + * safe prime, and q will be chosen as (p-1)/2. If + * type=Prime_Subgroup and qbits = 0, then the size of q will be + * determined according to the estimated difficulty of the DL + * problem. If type=DSA_Kosherizer, DSA primes will be created. + * @param pbits the number of bits of p + * @param qbits the number of bits of q. Leave it as 0 to have + * the value determined according to pbits. + */ + DL_Group(RandomNumberGenerator& rng, PrimeType type, + size_t pbits, size_t qbits = 0); + + /** + * Create a DSA group with a given seed. + * @param rng the random number generator to use + * @param seed the seed to use to create the random primes + * @param pbits the desired bit size of the prime p + * @param qbits the desired bit size of the prime q. + */ + DL_Group(RandomNumberGenerator& rng, + const std::vector& seed, + size_t pbits = 1024, size_t qbits = 0); + + /** + * Create a DL group. + * @param p the prime p + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& g); + + /** + * Create a DL group. + * @param p the prime p + * @param q the prime q + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& q, const BigInt& g); + + /** + * Decode a BER-encoded DL group param + */ + DL_Group(const uint8_t ber[], size_t ber_len, Format format); + + /** + * Decode a BER-encoded DL group param + */ + template + DL_Group(const std::vector& ber, Format format) : + DL_Group(ber.data(), ber.size(), format) {} + + /** + * Get the prime p. + * @return prime p + */ + const BigInt& get_p() const; + + /** + * Get the prime q, returns zero if q is not used + * @return prime q + */ + const BigInt& get_q() const; + + /** + * Get the base g. + * @return base g + */ + const BigInt& get_g() const; + + /** + * Perform validity checks on the group. + * @param rng the rng to use + * @param strong whether to perform stronger by lengthier tests + * @return true if the object is consistent, false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, bool strong = true) const; + + /** + * Verify a public element, ie check if y = g^x for some x. + * + * This is not a perfect test. It verifies that 1 < y < p and (if q is set) + * that y is in the subgroup of size q. + */ + bool verify_public_element(const BigInt& y) const; + + /** + * Verify a pair of elements y = g^x + * + * This verifies that 1 < x,y < p and that y=g^x mod p + */ + bool verify_element_pair(const BigInt& y, const BigInt& x) const; + + /** + * Encode this group into a string using PEM encoding. + * @param format the encoding format + * @return string holding the PEM encoded group + */ + std::string PEM_encode(Format format) const; + + /** + * Encode this group into a string using DER encoding. + * @param format the encoding format + * @return string holding the DER encoded group + */ + std::vector DER_encode(Format format) const; + + /** + * Reduce an integer modulo p + * @return x % p + */ + BigInt mod_p(const BigInt& x) const; + + /** + * Multiply and reduce an integer modulo p + * @return (x*y) % p + */ + BigInt multiply_mod_p(const BigInt& x, const BigInt& y) const; + + /** + * Return the inverse of x mod p + */ + BigInt inverse_mod_p(const BigInt& x) const; + + /** + * Reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return x % q + */ + BigInt mod_q(const BigInt& x) const; + + /** + * Multiply and reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return (x*y) % q + */ + BigInt multiply_mod_q(const BigInt& x, const BigInt& y) const; + + /** + * Multiply and reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return (x*y*z) % q + */ + BigInt multiply_mod_q(const BigInt& x, const BigInt& y, const BigInt& z) const; + + /** + * Square and reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return (x*x) % q + */ + BigInt square_mod_q(const BigInt& x) const; + + /** + * Return the inverse of x mod q + * Throws if q is unset on this DL_Group + */ + BigInt inverse_mod_q(const BigInt& x) const; + + /** + * Modular exponentiation + * + * @warning this function leaks the size of x via the number of + * loop iterations. Use the version taking the maximum size to + * avoid this. + * + * @return (g^x) % p + */ + BigInt power_g_p(const BigInt& x) const; + + /** + * Modular exponentiation + * @param x the exponent + * @param max_x_bits x is assumed to be at most this many bits long. + * + * @return (g^x) % p + */ + BigInt power_g_p(const BigInt& x, size_t max_x_bits) const; + + /** + * Multi-exponentiate + * Return (g^x * y^z) % p + */ + BigInt multi_exponentiate(const BigInt& x, const BigInt& y, const BigInt& z) const; + + /** + * Return parameters for Montgomery reduction/exponentiation mod p + */ + std::shared_ptr monty_params_p() const; + + /** + * Return the size of p in bits + * Same as get_p().bits() + */ + size_t p_bits() const; + + /** + * Return the size of p in bytes + * Same as get_p().bytes() + */ + size_t p_bytes() const; + + /** + * Return the size of q in bits + * Same as get_q().bits() + * Throws if q is unset + */ + size_t q_bits() const; + + /** + * Return the size of q in bytes + * Same as get_q().bytes() + * Throws if q is unset + */ + size_t q_bytes() const; + + /** + * Return size in bits of a secret exponent + * + * This attempts to balance between the attack costs of NFS + * (which depends on the size of the modulus) and Pollard's rho + * (which depends on the size of the exponent). + * + * It may vary over time for a particular group, if the attack + * costs change. + */ + size_t exponent_bits() const; + + /** + * Return an estimate of the strength of this group against + * discrete logarithm attacks (eg NFS). Warning: since this only + * takes into account known attacks it is by necessity an + * overestimate of the actual strength. + */ + size_t estimated_strength() const; + + /** + * Decode a DER/BER encoded group into this instance. + * @param ber a vector containing the DER/BER encoded group + * @param format the format of the encoded group + * + * @warning avoid this. Instead use the DL_Group constructor + */ + void BER_decode(const std::vector& ber, Format format); + + /** + * Decode a PEM encoded group into this instance. + * @param pem the PEM encoding of the group + */ + void BOTAN_DEPRECATED("Use DL_Group_from_PEM") PEM_decode(const std::string& pem); + + DL_Group_Source source() const; + + /** + * Return PEM representation of named DL group + */ + static std::string BOTAN_DEPRECATED("Use DL_Group(name).PEM_encode()") + PEM_for_named_group(const std::string& name); + + /* + * For internal use only + */ + static std::shared_ptr DL_group_info(const std::string& name); + + private: + static std::shared_ptr load_DL_group_info(const char* p_str, + const char* q_str, + const char* g_str); + + static std::shared_ptr load_DL_group_info(const char* p_str, + const char* g_str); + + static std::shared_ptr + BER_decode_DL_group(const uint8_t data[], size_t data_len, + DL_Group::Format format, + DL_Group_Source source); + + const DL_Group_Data& data() const; + std::shared_ptr m_data; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/dl_group/dl_named.cpp b/comm/third_party/botan/src/lib/pubkey/dl_group/dl_named.cpp new file mode 100644 index 0000000000..4d7b71bc1d --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_group/dl_named.cpp @@ -0,0 +1,175 @@ +/* +* List of discrete log groups +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +//static +std::shared_ptr DL_Group::DL_group_info(const std::string& name) + { + /* TLS FFDHE groups */ + + if(name == "ffdhe/ietf/2048") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/3072") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/4096") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6AFFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/6144") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/8192") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C8381E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665CB2C0F1CC01BD70229388839D2AF05E454504AC78B7582822846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA4571EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88CD68C8BB7C5C6424CFFFFFFFFFFFFFFFF", + "0x2"); + } + + /* IETF IPsec groups */ + + if(name == "modp/ietf/1024") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/1536") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/2048") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/3072") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/4096") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/6144") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/8192") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "0x2"); + } + + /* SRP groups + + SRP groups have a p st (p-1)/2 is prime, but g is not a generator + of subgroup of size q, so set q == 0 to bypass generator check + + Missing q doesn't matter for SRP, and nothing but SRP should be + using these parameters. + */ + + if(name == "modp/srp/1024") + { + return load_DL_group_info("0xEEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", + "0", + "0x2"); + } + + if(name == "modp/srp/1536") + { + return load_DL_group_info("0x9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", + "0", + "0x2"); + } + + if(name == "modp/srp/2048") + { + return load_DL_group_info("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", + "0", + "0x2"); + } + + if(name == "modp/srp/3072") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", + "0", + "0x5"); + } + + if(name == "modp/srp/4096") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", + "0", + "0x5"); + } + + if(name == "modp/srp/6144") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", + "0", + "0x5"); + } + + if(name == "modp/srp/8192") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "0", + "0x13"); + } + + /* DSA groups */ + + if(name == "dsa/jce/1024") + { + return load_DL_group_info("0xFD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB593D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC3023554135A169132F675F3AE2B61D72AEFF22203199DD14801C7", + "0x9760508F15230BCCB292B982A2EB840BF0581CF5", + "0x469603512E30278CD3947595DB22EEC9826A6322ADC97344F41D740C325724C8F9EFBAA7D4D803FF8C609DCD100EBC5BDFCFAD7C6A425FAEA786EA2050EBE98351EA1FDA1FDF24D6947AA6B9AA23766953802F4D7D4A8ECBA06D19768A2491FFB16D0EF9C43A99B5F71672FF6F0A24B444D0736D04D38A1A1322DAF6CDD88C9D"); + } + + if(name == "dsa/botan/2048") + { + return load_DL_group_info("0x91C48A4FDFBCF7C02AE95E7DA126122B5DD2864F559B87E8E74A286D52F59BD1DE68DFD645D0E00C60C080031891980374EEB594A532BFD67B9A09EAC4B8663A07910E68F39465FB7040D25DF13932EBAC4347A530ECBA61C854F9B880D3C0C3660080587C45566DADE26BD5A394BE093B4C0F24B5AFFEF8EC6C5B3E57FB89025A9BC16769932131E16D3C94EFCAB18D0DF061203CC53E6103BC72D5594BFD40CA65380F44A9A851DCB075495FC033A8A58071A1BD78FE052F66555648EB4B719D2AFE8B4880F8DAD6F15818BA178F89274C870BE9B96EB08C46C40040CC2EFE1DFB1B1868DD319DE3C34A32A63AB6EB1224209A419680CC7902D1728D4DF9E1", + "0x8CD7D450F86F0AD94EEE4CE469A8756D1EBD1058241943EAFFB0B354585E924D", + "0xD9F5E0761B4DBD1833D6AB1A961A0996C5F22303F72D84C140F67C431D94AB5715BEA81A0C98D39CE4BCF78D6B9EBC895D34FE89D94091D5848615EF15F5E86F11D96F6C969E203DDFA58356420A49CB444B595B901A933CFE0767B594F18A07B7F91DECDBA446B88990F78F2FF91F2FE7CD43FD2E46D18EADA1F7BB6602C617F6EF3A4B284F2FD9BA10A36042DE8FA87A2CA36597FEC81157A1485E44041DF02830111CB880BBE6ED494814886F965CDC3135F5CCF1383728BF65B806F9692C0B10D6C4C09C75A6CA3B4013CB16AB2C105F6BE23AEA9000EAB2178985F972C98057E1C86E44E7218688EA4AE0F3636DCCA745C9DCD4E6AFFB67CCBC13D6131"); + } + + if(name == "dsa/botan/3072") + { + return load_DL_group_info("0xE4B50880759663585E142460CA2D9DFF132F8AE4C840DDA3A2666889124FE5638B84E8A29B7AF3FA1209BE6BFC4B5072ED3B2B7387BAF3F857F478A80228EF3600B76B3DCFB61D20D34465B2506D2CAF87DF6E7DC0CE91BD2D167A46F6ADCC31C531E4F9C7ABBDB92ADDF35B0A806C66292A5F5E17E964DD099903733AC428AB35D80EA6F685BFBA8BE4068E5418AE5ECAD9E8FF073DE2B63E4E7EAD35C8A9B70B5BD47CFB88D373B66F37931939B0AB71BD5595809086DA0155337D185A0E4FB36A519B1B6202B8591E6002449CF1CD3A66384F6D2073B1CD73BECA93BAF1E1A6117D0238F222AE1ED7FED185A890E7F67FAB8FEB9753CC134A5183DFE87AE2595F7B5C2D9FBB42249FDD59513E1D3396B3EB2FD86684F285A8448FE757A029881C40760B94EF919BDF9740C38389599EC51A6E9BB519A8E068491E9CE0A2FCFE3CB60D66CF0DFAD20A8EC684048684A61444575BD1724D7352B44A760077B3BD6BD385CE5B0A7250CC0BF768DA82923806EB9CFBB138843731B618208C759B", + "0xB3EBD364EC69EF8CF3BAF643B75734B16339B2E49E5CDE1B59C1E9FB40EE0C5B", + "0x2BED21EEF83964A230AE89BBA71D9F7C39C52FC8229B4E3BC7E5944D329DA10F010EAC9E7BAF6C009FC4EB2960723E2B56DF4663E4C3AC800E9258DE2F7649D206782893F865EFCA498D2EEF30074EA5E8A7AB262712A4D94A2F3B0B9A92EE400FB38A3CC59A5DC7E436D5C004B22E35028381B51C93407EB32D4AE0FD42CB45E12D0ECEE8A26238EDE2082A7B1522113C66CEF8D745C6CF3CB945F84D2F4DE16D44A71DE198270E13F03553C88B8D323AD0B948A1BF2103A949979B6ED16FB5F3C953D95B7C8E88CA67DCF5A636FB9CA39D924215F7A884ED6C7EE3C96D8D9715427974B7C4351282E13D3773F7D28B452F10892A13C7587328DEA4827B6B369B2A8DC172ADC583F51F2A6598C5483E5BC467B02F91D059C402D18E2C2680F776AA06F49280A2C72C17CC42D5B6E740C5C4B1AB3C51C2ED092BE2A2D8B053AE5773D1425ED2B08F06E2DD50592DF1A478C15591CDFD11564FF88FF38B721D42392FDA473212DCFD8D2D88A976A00AFFE6FFFB430A359E64CA2B351CA2412394"); + } + + return std::shared_ptr(); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/dl_group/info.txt b/comm/third_party/botan/src/lib/pubkey/dl_group/info.txt new file mode 100644 index 0000000000..a73edb18c1 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dl_group/info.txt @@ -0,0 +1,10 @@ + +DL_GROUP -> 20131128 + + + +asn1 +bigint +numbertheory +pem + diff --git a/comm/third_party/botan/src/lib/pubkey/dlies/dlies.cpp b/comm/third_party/botan/src/lib/pubkey/dlies/dlies.cpp new file mode 100644 index 0000000000..4aee3ffb34 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dlies/dlies.cpp @@ -0,0 +1,219 @@ +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_length) : + DLIES_Encryptor(own_priv_key, rng, kdf, nullptr, 0, mac, mac_key_length) + { + } + +DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + Cipher_Mode* cipher, + size_t cipher_key_len, + MessageAuthenticationCode* mac, + size_t mac_key_length) : + m_other_pub_key(), + m_own_pub_key(own_priv_key.public_value()), + m_ka(own_priv_key, rng, "Raw"), + m_kdf(kdf), + m_cipher(cipher), + m_cipher_key_len(cipher_key_len), + m_mac(mac), + m_mac_keylen(mac_key_length), + m_iv() + { + BOTAN_ASSERT_NONNULL(kdf); + BOTAN_ASSERT_NONNULL(mac); + } + +std::vector DLIES_Encryptor::enc(const uint8_t in[], size_t length, + RandomNumberGenerator&) const + { + if(m_other_pub_key.empty()) + { + throw Invalid_State("DLIES: The other key was never set"); + } + + // calculate secret value + const SymmetricKey secret_value = m_ka.derive_key(0, m_other_pub_key); + + // derive secret key from secret value + const size_t required_key_length = m_cipher ? m_cipher_key_len + m_mac_keylen : length + m_mac_keylen; + const secure_vector secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of()); + + if(secret_keys.size() != required_key_length) + { + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + } + + secure_vector ciphertext(in, in + length); + const size_t cipher_key_len = m_cipher ? m_cipher_key_len : length; + + if(m_cipher) + { + SymmetricKey enc_key(secret_keys.data(), cipher_key_len); + m_cipher->set_key(enc_key); + + if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) + throw Invalid_Argument("DLIES with " + m_cipher->name() + " requires an IV be set"); + m_cipher->start(m_iv.bits_of()); + m_cipher->finish(ciphertext); + } + else + { + xor_buf(ciphertext, secret_keys, cipher_key_len); + } + + // calculate MAC + m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen); + secure_vector tag = m_mac->process(ciphertext); + + // out = (ephemeral) public key + ciphertext + tag + secure_vector out(m_own_pub_key.size() + ciphertext.size() + tag.size()); + buffer_insert(out, 0, m_own_pub_key); + buffer_insert(out, 0 + m_own_pub_key.size(), ciphertext); + buffer_insert(out, 0 + m_own_pub_key.size() + ciphertext.size(), tag); + + return unlock(out); + } + +/** +* Return the max size, in bytes, of a message +* We assume DLIES is only used for key transport and limit the maximum size +* to 512 bits +*/ +size_t DLIES_Encryptor::maximum_input_size() const + { + return 64; + } + +size_t DLIES_Encryptor::ciphertext_length(size_t ptext_len) const + { + return m_own_pub_key.size() + m_mac->output_length() + m_cipher->output_length(ptext_len); + } + +DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + Cipher_Mode* cipher, + size_t cipher_key_len, + MessageAuthenticationCode* mac, + size_t mac_key_length) : + m_pub_key_size(own_priv_key.public_value().size()), + m_ka(own_priv_key, rng, "Raw"), + m_kdf(kdf), + m_cipher(cipher), + m_cipher_key_len(cipher_key_len), + m_mac(mac), + m_mac_keylen(mac_key_length), + m_iv() + { + BOTAN_ASSERT_NONNULL(kdf); + BOTAN_ASSERT_NONNULL(mac); + } + +DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_length) : + DLIES_Decryptor(own_priv_key, rng, kdf, nullptr, 0, mac, mac_key_length) + {} + +size_t DLIES_Decryptor::plaintext_length(size_t ctext_len) const + { + if(ctext_len < m_pub_key_size + m_mac->output_length()) + return 0; // will throw if attempted + + return ctext_len - (m_pub_key_size + m_mac->output_length()); + } + +secure_vector DLIES_Decryptor::do_decrypt(uint8_t& valid_mask, + const uint8_t msg[], size_t length) const + { + if(length < m_pub_key_size + m_mac->output_length()) + { + throw Decoding_Error("DLIES decryption: ciphertext is too short"); + } + + // calculate secret value + std::vector other_pub_key(msg, msg + m_pub_key_size); + const SymmetricKey secret_value = m_ka.derive_key(0, other_pub_key); + + const size_t ciphertext_len = length - m_pub_key_size - m_mac->output_length(); + size_t cipher_key_len = m_cipher ? m_cipher_key_len : ciphertext_len; + + // derive secret key from secret value + const size_t required_key_length = cipher_key_len + m_mac_keylen; + secure_vector secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of()); + + if(secret_keys.size() != required_key_length) + { + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + } + + secure_vector ciphertext(msg + m_pub_key_size, msg + m_pub_key_size + ciphertext_len); + + // calculate MAC + m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen); + secure_vector calculated_tag = m_mac->process(ciphertext); + + // calculated tag == received tag ? + secure_vector tag(msg + m_pub_key_size + ciphertext_len, + msg + m_pub_key_size + ciphertext_len + m_mac->output_length()); + + valid_mask = ct_compare_u8(tag.data(), calculated_tag.data(), tag.size()); + + // decrypt + if(m_cipher) + { + if(valid_mask) + { + SymmetricKey dec_key(secret_keys.data(), cipher_key_len); + m_cipher->set_key(dec_key); + + try + { + // the decryption can fail: + // e.g. Invalid_Authentication_Tag is thrown if GCM is used and the message does not have a valid tag + + if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) + throw Invalid_Argument("DLIES with " + m_cipher->name() + " requires an IV be set"); + m_cipher->start(m_iv.bits_of()); + m_cipher->finish(ciphertext); + } + catch(...) + { + valid_mask = 0; + } + + } + else + { + return secure_vector(); + } + } + else + { + xor_buf(ciphertext, secret_keys.data(), cipher_key_len); + } + + return ciphertext; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/dlies/dlies.h b/comm/third_party/botan/src/lib/pubkey/dlies/dlies.h new file mode 100644 index 0000000000..640a8655eb --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dlies/dlies.h @@ -0,0 +1,163 @@ +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DLIES_H_ +#define BOTAN_DLIES_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* DLIES Encryption +*/ +class BOTAN_PUBLIC_API(2,0) DLIES_Encryptor final : public PK_Encryptor + { + public: + /** + * Stream mode: use KDF to provide a stream of bytes to xor with the message + * + * @param own_priv_key own (ephemeral) DH private key + * @param rng the RNG to use + * @param kdf the KDF that should be used + * @param mac the MAC function that should be used + * @param mac_key_len key length of the MAC function. Default = 20 bytes + * + * output = (ephemeral) public key + ciphertext + tag + */ + DLIES_Encryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + /** + * Block cipher mode + * + * @param own_priv_key own (ephemeral) DH private key + * @param rng the RNG to use + * @param kdf the KDF that should be used + * @param cipher the block cipher that should be used + * @param cipher_key_len the key length of the block cipher + * @param mac the MAC function that should be used + * @param mac_key_len key length of the MAC function. Default = 20 bytes + * + * output = (ephemeral) public key + ciphertext + tag + */ + DLIES_Encryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + Cipher_Mode* cipher, + size_t cipher_key_len, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + // Set the other parties public key + inline void set_other_key(const std::vector& other_pub_key) + { + m_other_pub_key = other_pub_key; + } + + /// Set the initialization vector for the data encryption method + inline void set_initialization_vector(const InitializationVector& iv) + { + m_iv = iv; + } + + private: + std::vector enc(const uint8_t[], size_t, + RandomNumberGenerator&) const override; + + size_t maximum_input_size() const override; + + size_t ciphertext_length(size_t ptext_len) const override; + + std::vector m_other_pub_key; + std::vector m_own_pub_key; + PK_Key_Agreement m_ka; + std::unique_ptr m_kdf; + std::unique_ptr m_cipher; + const size_t m_cipher_key_len; + std::unique_ptr m_mac; + const size_t m_mac_keylen; + InitializationVector m_iv; + }; + +/** +* DLIES Decryption +*/ +class BOTAN_PUBLIC_API(2,0) DLIES_Decryptor final : public PK_Decryptor + { + public: + /** + * Stream mode: use KDF to provide a stream of bytes to xor with the message + * + * @param own_priv_key own (ephemeral) DH private key + * @param rng the RNG to use + * @param kdf the KDF that should be used + * @param mac the MAC function that should be used + * @param mac_key_len key length of the MAC function. Default = 20 bytes + * + * input = (ephemeral) public key + ciphertext + tag + */ + DLIES_Decryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + /** + * Block cipher mode + * + * @param own_priv_key own (ephemeral) DH private key + * @param rng the RNG to use + * @param kdf the KDF that should be used + * @param cipher the block cipher that should be used + * @param cipher_key_len the key length of the block cipher + * @param mac the MAC function that should be used + * @param mac_key_len key length of the MAC function. Default = 20 bytes + * + * input = (ephemeral) public key + ciphertext + tag + */ + DLIES_Decryptor(const DH_PrivateKey& own_priv_key, + RandomNumberGenerator& rng, + KDF* kdf, + Cipher_Mode* cipher, + size_t cipher_key_len, + MessageAuthenticationCode* mac, + size_t mac_key_len = 20); + + /// Set the initialization vector for the data decryption method + inline void set_initialization_vector(const InitializationVector& iv) + { + m_iv = iv; + } + + private: + secure_vector do_decrypt(uint8_t& valid_mask, + const uint8_t in[], size_t in_len) const override; + + size_t plaintext_length(size_t ctext_len) const override; + + const size_t m_pub_key_size; + PK_Key_Agreement m_ka; + std::unique_ptr m_kdf; + std::unique_ptr m_cipher; + const size_t m_cipher_key_len; + std::unique_ptr m_mac; + const size_t m_mac_keylen; + InitializationVector m_iv; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/dlies/info.txt b/comm/third_party/botan/src/lib/pubkey/dlies/info.txt new file mode 100644 index 0000000000..80c0466f46 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dlies/info.txt @@ -0,0 +1,10 @@ + +DLIES -> 20160713 + + + +dh +kdf +mac +modes + diff --git a/comm/third_party/botan/src/lib/pubkey/dsa/dsa.cpp b/comm/third_party/botan/src/lib/pubkey/dsa/dsa.cpp new file mode 100644 index 0000000000..4da347c5e3 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dsa/dsa.cpp @@ -0,0 +1,230 @@ +/* +* DSA +* (C) 1999-2010,2014,2016 Jack Lloyd +* (C) 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + #include + #include +#endif + +namespace Botan { + +/* +* DSA_PublicKey Constructor +*/ +DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) + { + m_group = grp; + m_y = y1; + } + +/* +* Create a DSA private key +*/ +DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + m_group = grp; + + if(x_arg == 0) + m_x = BigInt::random_integer(rng, 2, group_q()); + else + m_x = x_arg; + + m_y = m_group.power_g_p(m_x, m_group.q_bits()); + } + +DSA_PrivateKey::DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + m_y = m_group.power_g_p(m_x, m_group.q_bits()); + } + +/* +* Check Private DSA Parameters +*/ +bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || m_x >= group_q()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); + } + +namespace { + +/** +* Object that can create a DSA signature +*/ +class DSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + DSA_Signature_Operation(const DSA_PrivateKey& dsa, + const std::string& emsa, + RandomNumberGenerator& rng) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(dsa.get_group()), + m_x(dsa.get_x()) + { +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + m_rfc6979_hash = hash_for_emsa(emsa); +#endif + + m_b = BigInt::random_integer(rng, 2, dsa.group_q()); + m_b_inv = m_group.inverse_mod_q(m_b); + } + + size_t signature_length() const override { return 2*m_group.q_bytes(); } + size_t max_input_bits() const override { return m_group.q_bits(); } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + private: + const DL_Group m_group; + const BigInt& m_x; +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + std::string m_rfc6979_hash; +#endif + + BigInt m_b, m_b_inv; + }; + +secure_vector +DSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt& q = m_group.get_q(); + + BigInt m(msg, msg_len, m_group.q_bits()); + + while(m >= q) + m -= q; + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + BOTAN_UNUSED(rng); + const BigInt k = generate_rfc6979_nonce(m_x, q, m, m_rfc6979_hash); +#else + const BigInt k = BigInt::random_integer(rng, 1, q); +#endif + + const BigInt k_inv = m_group.inverse_mod_q(k); + + /* + * It may not be strictly necessary for the reduction (g^k mod p) mod q to be + * const time, since r is published as part of the signature, and deriving + * anything useful about k from g^k mod p would seem to require computing a + * discrete logarithm. + * + * However it only increases the cost of signatures by about 7-10%, and DSA is + * only for legacy use anyway so we don't care about the performance so much. + */ + const BigInt r = ct_modulo(m_group.power_g_p(k, m_group.q_bits()), m_group.get_q()); + + /* + * Blind the input message and compute x*r+m as (x*r*b + m*b)/b + */ + m_b = m_group.square_mod_q(m_b); + m_b_inv = m_group.square_mod_q(m_b_inv); + + m = m_group.multiply_mod_q(m_b, m); + const BigInt xr = m_group.multiply_mod_q(m_b, m_x, r); + + const BigInt s = m_group.multiply_mod_q(m_b_inv, k_inv, m_group.mod_q(xr+m)); + + // With overwhelming probability, a bug rather than actual zero r/s + if(r.is_zero() || s.is_zero()) + throw Internal_Error("Computed zero r/s during DSA signature"); + + return BigInt::encode_fixed_length_int_pair(r, s, q.bytes()); + } + +/** +* Object that can verify a DSA signature +*/ +class DSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + DSA_Verification_Operation(const DSA_PublicKey& dsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(dsa.get_group()), + m_y(dsa.get_y()) + { + } + + size_t max_input_bits() const override { return m_group.q_bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const DL_Group m_group; + const BigInt& m_y; + }; + +bool DSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) + { + const BigInt& q = m_group.get_q(); + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + BigInt r(sig, q_bytes); + BigInt s(sig + q_bytes, q_bytes); + BigInt i(msg, msg_len, q.bits()); + + if(r <= 0 || r >= q || s <= 0 || s >= q) + return false; + + s = inverse_mod(s, q); + + const BigInt sr = m_group.multiply_mod_q(s, r); + const BigInt si = m_group.multiply_mod_q(s, i); + + s = m_group.multi_exponentiate(si, m_y, sr); + + // s is too big for Barrett, and verification doesn't need to be const-time + return (s % m_group.get_q() == r); + } + +} + +std::unique_ptr +DSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new DSA_Verification_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +DSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new DSA_Signature_Operation(*this, params, rng)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/dsa/dsa.h b/comm/third_party/botan/src/lib/pubkey/dsa/dsa.h new file mode 100644 index 0000000000..b219a1cf37 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dsa/dsa.h @@ -0,0 +1,87 @@ +/* +* DSA +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DSA_H_ +#define BOTAN_DSA_H_ + +#include + +namespace Botan { + +/** +* DSA Public Key +*/ +class BOTAN_PUBLIC_API(2,0) DSA_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const override { return "DSA"; } + + DL_Group::Format group_format() const override { return DL_Group::ANSI_X9_57; } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return group_q().bytes(); } + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + DSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + } + + /** + * Create a public key. + * @param group the underlying DL group + * @param y the public value y = g^x mod p + */ + DSA_PublicKey(const DL_Group& group, const BigInt& y); + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + protected: + DSA_PublicKey() = default; + }; + +/** +* DSA Private Key +*/ +class BOTAN_PUBLIC_API(2,0) DSA_PrivateKey final : public DSA_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded key bits in ANSI X9.57 format + */ + DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Create a private key. + * @param rng the RNG to use + * @param group the underlying DL group + * @param private_key the private key (if zero, a new random key is generated) + */ + DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& private_key = 0); + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/dsa/info.txt b/comm/third_party/botan/src/lib/pubkey/dsa/info.txt new file mode 100644 index 0000000000..a9f288edea --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/dsa/info.txt @@ -0,0 +1,12 @@ + +DSA -> 20131128 + + + +dl_algo +dl_group +keypair +numbertheory +emsa1 +sha2_32 + diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.cpp b/comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.cpp new file mode 100644 index 0000000000..9957bb0853 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.cpp @@ -0,0 +1,568 @@ +/* +* Elliptic curves over GF(p) Montgomery Representation +* (C) 2014,2015,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class CurveGFp_Montgomery final : public CurveGFp_Repr + { + public: + CurveGFp_Montgomery(const BigInt& p, const BigInt& a, const BigInt& b) : + m_p(p), m_a(a), m_b(b), + m_p_words(m_p.sig_words()), + m_p_dash(monty_inverse(m_p.word_at(0))) + { + Modular_Reducer mod_p(m_p); + + m_r.set_bit(m_p_words * BOTAN_MP_WORD_BITS); + m_r = mod_p.reduce(m_r); + + m_r2 = mod_p.square(m_r); + m_r3 = mod_p.multiply(m_r, m_r2); + m_a_r = mod_p.multiply(m_r, m_a); + m_b_r = mod_p.multiply(m_r, m_b); + + m_a_is_zero = m_a.is_zero(); + m_a_is_minus_3 = (m_a + 3 == m_p); + } + + bool a_is_zero() const override { return m_a_is_zero; } + bool a_is_minus_3() const override { return m_a_is_minus_3; } + + const BigInt& get_a() const override { return m_a; } + + const BigInt& get_b() const override { return m_b; } + + const BigInt& get_p() const override { return m_p; } + + const BigInt& get_a_rep() const override { return m_a_r; } + + const BigInt& get_b_rep() const override { return m_b_r; } + + const BigInt& get_1_rep() const override { return m_r; } + + bool is_one(const BigInt& x) const override { return x == m_r; } + + size_t get_p_words() const override { return m_p_words; } + + size_t get_ws_size() const override { return 2*m_p_words + 4; } + + BigInt invert_element(const BigInt& x, secure_vector& ws) const override; + + void to_curve_rep(BigInt& x, secure_vector& ws) const override; + + void from_curve_rep(BigInt& x, secure_vector& ws) const override; + + void curve_mul_words(BigInt& z, + const word x_words[], + const size_t x_size, + const BigInt& y, + secure_vector& ws) const override; + + void curve_sqr_words(BigInt& z, + const word x_words[], + size_t x_size, + secure_vector& ws) const override; + + private: + BigInt m_p; + BigInt m_a, m_b; + BigInt m_a_r, m_b_r; + size_t m_p_words; // cache of m_p.sig_words() + + // Montgomery parameters + BigInt m_r, m_r2, m_r3; + word m_p_dash; + + bool m_a_is_zero; + bool m_a_is_minus_3; + }; + +BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector& ws) const + { + // Should we use Montgomery inverse instead? + const BigInt inv = inverse_mod(x, m_p); + BigInt res; + curve_mul(res, inv, m_r3, ws); + return res; + } + +void CurveGFp_Montgomery::to_curve_rep(BigInt& x, secure_vector& ws) const + { + const BigInt tx = x; + curve_mul(x, tx, m_r2, ws); + } + +void CurveGFp_Montgomery::from_curve_rep(BigInt& z, secure_vector& ws) const + { + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + } + +void CurveGFp_Montgomery::curve_mul_words(BigInt& z, + const word x_w[], + size_t x_size, + const BigInt& y, + secure_vector& ws) const + { + BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); + + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_mul(z.mutable_data(), z.size(), + x_w, x_size, std::min(m_p_words, x_size), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + } + +void CurveGFp_Montgomery::curve_sqr_words(BigInt& z, + const word x[], + size_t x_size, + secure_vector& ws) const + { + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_sqr(z.mutable_data(), z.size(), + x, x_size, std::min(m_p_words, x_size), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + } + +class CurveGFp_NIST : public CurveGFp_Repr + { + public: + CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) : + m_1(1), m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS) + { + // All Solinas prime curves are assumed a == -3 + } + + bool a_is_zero() const override { return false; } + bool a_is_minus_3() const override { return true; } + + const BigInt& get_a() const override { return m_a; } + + const BigInt& get_b() const override { return m_b; } + + const BigInt& get_1_rep() const override { return m_1; } + + size_t get_p_words() const override { return m_p_words; } + + size_t get_ws_size() const override { return 2*m_p_words + 4; } + + const BigInt& get_a_rep() const override { return m_a; } + + const BigInt& get_b_rep() const override { return m_b; } + + bool is_one(const BigInt& x) const override { return x == 1; } + + void to_curve_rep(BigInt& x, secure_vector& ws) const override + { redc_mod_p(x, ws); } + + void from_curve_rep(BigInt& x, secure_vector& ws) const override + { redc_mod_p(x, ws); } + + virtual void redc_mod_p(BigInt& z, secure_vector& ws) const = 0; + + BigInt invert_element(const BigInt& x, secure_vector& ws) const override; + + void curve_mul_words(BigInt& z, + const word x_words[], + const size_t x_size, + const BigInt& y, + secure_vector& ws) const override; + + void curve_mul_tmp(BigInt& x, const BigInt& y, BigInt& tmp, secure_vector& ws) const + { + curve_mul(tmp, x, y, ws); + x.swap(tmp); + } + + void curve_sqr_tmp(BigInt& x, BigInt& tmp, secure_vector& ws) const + { + curve_sqr(tmp, x, ws); + x.swap(tmp); + } + + void curve_sqr_words(BigInt& z, + const word x_words[], + size_t x_size, + secure_vector& ws) const override; + private: + // Curve parameters + BigInt m_1; + BigInt m_a, m_b; + size_t m_p_words; // cache of m_p.sig_words() + }; + +BigInt CurveGFp_NIST::invert_element(const BigInt& x, secure_vector& ws) const + { + BOTAN_UNUSED(ws); + return inverse_mod(x, get_p()); + } + +void CurveGFp_NIST::curve_mul_words(BigInt& z, + const word x_w[], + size_t x_size, + const BigInt& y, + secure_vector& ws) const + { + BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); + + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_mul(z.mutable_data(), z.size(), + x_w, x_size, std::min(m_p_words, x_size), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + this->redc_mod_p(z, ws); + } + +void CurveGFp_NIST::curve_sqr_words(BigInt& z, const word x[], size_t x_size, + secure_vector& ws) const + { + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_sqr(z.mutable_data(), output_size, + x, x_size, std::min(m_p_words, x_size), + ws.data(), ws.size()); + + this->redc_mod_p(z, ws); + } + +/** +* The NIST P-192 curve +*/ +class CurveGFp_P192 final : public CurveGFp_NIST + { + public: + CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {} + const BigInt& get_p() const override { return prime_p192(); } + private: + void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p192(x, ws); } + }; + +/** +* The NIST P-224 curve +*/ +class CurveGFp_P224 final : public CurveGFp_NIST + { + public: + CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {} + const BigInt& get_p() const override { return prime_p224(); } + private: + void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p224(x, ws); } + }; + +/** +* The NIST P-256 curve +*/ +class CurveGFp_P256 final : public CurveGFp_NIST + { + public: + CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {} + const BigInt& get_p() const override { return prime_p256(); } + private: + void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p256(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector& ws) const override; + }; + +BigInt CurveGFp_P256::invert_element(const BigInt& x, secure_vector& ws) const + { + BigInt r, p2, p4, p8, p16, p32, tmp; + + curve_sqr(r, x, ws); + + curve_mul(p2, r, x, ws); + curve_sqr(r, p2, ws); + curve_sqr_tmp(r, tmp, ws); + + curve_mul(p4, r, p2, ws); + + curve_sqr(r, p4, ws); + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul(p8, r, p4, ws); + + curve_sqr(r, p8, ws); + for(size_t i = 0; i != 7; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul(p16, r, p8, ws); + + curve_sqr(r, p16, ws); + for(size_t i = 0; i != 15; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul(p32, r, p16, ws); + + curve_sqr(r, p32, ws); + for(size_t i = 0; i != 31; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + for(size_t i = 0; i != 32*4; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p32, tmp, ws); + + for(size_t i = 0; i != 32; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p32, tmp, ws); + + for(size_t i = 0; i != 16; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p16, tmp, ws); + for(size_t i = 0; i != 8; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p8, tmp, ws); + + for(size_t i = 0; i != 4; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p4, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p2, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + return r; + } + +/** +* The NIST P-384 curve +*/ +class CurveGFp_P384 final : public CurveGFp_NIST + { + public: + CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {} + const BigInt& get_p() const override { return prime_p384(); } + private: + void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p384(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector& ws) const override; + }; + +BigInt CurveGFp_P384::invert_element(const BigInt& x, secure_vector& ws) const + { + // From https://briansmith.org/ecc-inversion-addition-chains-01 + + BigInt r, x2, x3, x15, x30, tmp, rl; + + r = x; + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + x2 = r; + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + x3 = r; + + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x3, tmp, ws); + + rl = r; + for(size_t i = 0; i != 6; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x3, tmp, ws); + + x15 = r; + for(size_t i = 0; i != 15; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x15, tmp, ws); + + x30 = r; + for(size_t i = 0; i != 30; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x30, tmp, ws); + + rl = r; + for(size_t i = 0; i != 60; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 120; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + for(size_t i = 0; i != 15; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x15, tmp, ws); + + for(size_t i = 0; i != 31; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x30, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x2, tmp, ws); + + for(size_t i = 0; i != 94; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x30, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + + curve_mul_tmp(r, x, tmp, ws); + + return r; + } + +/** +* The NIST P-521 curve +*/ +class CurveGFp_P521 final : public CurveGFp_NIST + { + public: + CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {} + const BigInt& get_p() const override { return prime_p521(); } + private: + void redc_mod_p(BigInt& x, secure_vector& ws) const override { redc_p521(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector& ws) const override; + }; + +BigInt CurveGFp_P521::invert_element(const BigInt& x, secure_vector& ws) const + { + // Addition chain from https://eprint.iacr.org/2014/852.pdf section + + BigInt r; + BigInt rl; + BigInt a7; + BigInt tmp; + + curve_sqr(r, x, ws); + curve_mul_tmp(r, x, tmp, ws); + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + rl = r; + + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + a7 = r; // need this value later + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + rl = r; + for(size_t i = 0; i != 8; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 16; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 32; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 64; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 128; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 256; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + for(size_t i = 0; i != 7; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, a7, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + return r; + } + +} + +std::shared_ptr +CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b) + { + if(p == prime_p192()) + return std::shared_ptr(new CurveGFp_P192(a, b)); + if(p == prime_p224()) + return std::shared_ptr(new CurveGFp_P224(a, b)); + if(p == prime_p256()) + return std::shared_ptr(new CurveGFp_P256(a, b)); + if(p == prime_p384()) + return std::shared_ptr(new CurveGFp_P384(a, b)); + if(p == prime_p521()) + return std::shared_ptr(new CurveGFp_P521(a, b)); + + return std::shared_ptr(new CurveGFp_Montgomery(p, a, b)); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.h b/comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.h new file mode 100644 index 0000000000..77c04ebf36 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/curve_gfp.h @@ -0,0 +1,265 @@ +/* +* Elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2010-2011,2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_GFP_CURVE_H_ +#define BOTAN_GFP_CURVE_H_ + +#include +#include + +// Currently exposed in PointGFp +//BOTAN_FUTURE_INTERNAL_HEADER(curve_gfp.h) + +namespace Botan { + +class BOTAN_UNSTABLE_API CurveGFp_Repr + { + public: + virtual ~CurveGFp_Repr() = default; + + virtual const BigInt& get_p() const = 0; + virtual const BigInt& get_a() const = 0; + virtual const BigInt& get_b() const = 0; + + virtual size_t get_p_words() const = 0; + + virtual size_t get_ws_size() const = 0; + + virtual bool is_one(const BigInt& x) const = 0; + + virtual bool a_is_zero() const = 0; + + virtual bool a_is_minus_3() const = 0; + + /* + * Returns to_curve_rep(get_a()) + */ + virtual const BigInt& get_a_rep() const = 0; + + /* + * Returns to_curve_rep(get_b()) + */ + virtual const BigInt& get_b_rep() const = 0; + + /* + * Returns to_curve_rep(1) + */ + virtual const BigInt& get_1_rep() const = 0; + + virtual BigInt invert_element(const BigInt& x, secure_vector& ws) const = 0; + + virtual void to_curve_rep(BigInt& x, secure_vector& ws) const = 0; + + virtual void from_curve_rep(BigInt& x, secure_vector& ws) const = 0; + + void curve_mul(BigInt& z, const BigInt& x, const BigInt& y, + secure_vector& ws) const + { + BOTAN_DEBUG_ASSERT(x.sig_words() <= get_p_words()); + curve_mul_words(z, x.data(), x.size(), y, ws); + } + + virtual void curve_mul_words(BigInt& z, + const word x_words[], + const size_t x_size, + const BigInt& y, + secure_vector& ws) const = 0; + + void curve_sqr(BigInt& z, const BigInt& x, + secure_vector& ws) const + { + BOTAN_DEBUG_ASSERT(x.sig_words() <= get_p_words()); + curve_sqr_words(z, x.data(), x.size(), ws); + } + + virtual void curve_sqr_words(BigInt& z, + const word x_words[], + size_t x_size, + secure_vector& ws) const = 0; + }; + +/** +* This class represents an elliptic curve over GF(p) +* +* There should not be any reason for applications to use this type. +* If you need EC primitives use the interfaces EC_Group and PointGFp +* +* It is likely this class will be removed entirely in a future major +* release. +*/ +class BOTAN_UNSTABLE_API CurveGFp final + { + public: + + /** + * Create an uninitialized CurveGFp + */ + CurveGFp() = default; + + /** + * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) + * @param p prime number of the field + * @param a first coefficient + * @param b second coefficient + */ + CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) : + m_repr(choose_repr(p, a, b)) + { + } + + CurveGFp(const CurveGFp&) = default; + + CurveGFp& operator=(const CurveGFp&) = default; + + /** + * @return curve coefficient a + */ + const BigInt& get_a() const { return m_repr->get_a(); } + + /** + * @return curve coefficient b + */ + const BigInt& get_b() const { return m_repr->get_b(); } + + /** + * Get prime modulus of the field of the curve + * @return prime modulus of the field of the curve + */ + const BigInt& get_p() const { return m_repr->get_p(); } + + size_t get_p_words() const { return m_repr->get_p_words(); } + + size_t get_ws_size() const { return m_repr->get_ws_size(); } + + const BigInt& get_a_rep() const { return m_repr->get_a_rep(); } + + const BigInt& get_b_rep() const { return m_repr->get_b_rep(); } + + const BigInt& get_1_rep() const { return m_repr->get_1_rep(); } + + bool a_is_minus_3() const { return m_repr->a_is_minus_3(); } + bool a_is_zero() const { return m_repr->a_is_zero(); } + + bool is_one(const BigInt& x) const { return m_repr->is_one(x); } + + BigInt invert_element(const BigInt& x, secure_vector& ws) const + { + return m_repr->invert_element(x, ws); + } + + void to_rep(BigInt& x, secure_vector& ws) const + { + m_repr->to_curve_rep(x, ws); + } + + void from_rep(BigInt& x, secure_vector& ws) const + { + m_repr->from_curve_rep(x, ws); + } + + BigInt from_rep_to_tmp(const BigInt& x, secure_vector& ws) const + { + BigInt xt(x); + m_repr->from_curve_rep(xt, ws); + return xt; + } + + // TODO: from_rep taking && ref + + void mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector& ws) const + { + m_repr->curve_mul(z, x, y, ws); + } + + void mul(BigInt& z, const word x_w[], size_t x_size, + const BigInt& y, secure_vector& ws) const + { + m_repr->curve_mul_words(z, x_w, x_size, y, ws); + } + + void sqr(BigInt& z, const BigInt& x, secure_vector& ws) const + { + m_repr->curve_sqr(z, x, ws); + } + + void sqr(BigInt& z, const word x_w[], size_t x_size, secure_vector& ws) const + { + m_repr->curve_sqr_words(z, x_w, x_size, ws); + } + + BigInt mul(const BigInt& x, const BigInt& y, secure_vector& ws) const + { + return mul_to_tmp(x, y, ws); + } + + BigInt sqr(const BigInt& x, secure_vector& ws) const + { + return sqr_to_tmp(x, ws); + } + + BigInt mul_to_tmp(const BigInt& x, const BigInt& y, secure_vector& ws) const + { + BigInt z; + m_repr->curve_mul(z, x, y, ws); + return z; + } + + BigInt sqr_to_tmp(const BigInt& x, secure_vector& ws) const + { + BigInt z; + m_repr->curve_sqr(z, x, ws); + return z; + } + + void swap(CurveGFp& other) + { + std::swap(m_repr, other.m_repr); + } + + /** + * Equality operator + * @param other a curve + * @return true iff *this is the same as other + */ + inline bool operator==(const CurveGFp& other) const + { + if(m_repr.get() == other.m_repr.get()) + return true; + + return (get_p() == other.get_p()) && + (get_a() == other.get_a()) && + (get_b() == other.get_b()); + } + + private: + static std::shared_ptr + choose_repr(const BigInt& p, const BigInt& a, const BigInt& b); + + std::shared_ptr m_repr; + }; + +inline bool operator!=(const CurveGFp& lhs, const CurveGFp& rhs) + { + return !(lhs == rhs); + } + +} + +namespace std { + +template<> inline +void swap(Botan::CurveGFp& curve1, + Botan::CurveGFp& curve2) noexcept + { + curve1.swap(curve2); + } + +} // namespace std + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.cpp b/comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.cpp new file mode 100644 index 0000000000..bb60bacf7b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.cpp @@ -0,0 +1,796 @@ +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* (C) 2008,2018 Jack Lloyd +* (C) 2018 Tobias Niemann +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class EC_Group_Data final + { + public: + + EC_Group_Data(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& g_x, + const BigInt& g_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid, + EC_Group_Source source) : + m_curve(p, a, b), + m_base_point(m_curve, g_x, g_y), + m_g_x(g_x), + m_g_y(g_y), + m_order(order), + m_cofactor(cofactor), + m_mod_order(order), + m_base_mult(m_base_point, m_mod_order), + m_oid(oid), + m_p_bits(p.bits()), + m_order_bits(order.bits()), + m_a_is_minus_3(a == p - 3), + m_a_is_zero(a.is_zero()), + m_source(source) + { + } + + bool match(const BigInt& p, const BigInt& a, const BigInt& b, + const BigInt& g_x, const BigInt& g_y, + const BigInt& order, const BigInt& cofactor) const + { + return (this->p() == p && + this->a() == a && + this->b() == b && + this->order() == order && + this->cofactor() == cofactor && + this->g_x() == g_x && + this->g_y() == g_y); + } + + void set_oid(const OID& oid) + { + BOTAN_STATE_CHECK(m_oid.empty()); + m_oid = oid; + } + + const OID& oid() const { return m_oid; } + const BigInt& p() const { return m_curve.get_p(); } + const BigInt& a() const { return m_curve.get_a(); } + const BigInt& b() const { return m_curve.get_b(); } + const BigInt& order() const { return m_order; } + const BigInt& cofactor() const { return m_cofactor; } + const BigInt& g_x() const { return m_g_x; } + const BigInt& g_y() const { return m_g_y; } + + size_t p_bits() const { return m_p_bits; } + size_t p_bytes() const { return (m_p_bits + 7) / 8; } + + size_t order_bits() const { return m_order_bits; } + size_t order_bytes() const { return (m_order_bits + 7) / 8; } + + const CurveGFp& curve() const { return m_curve; } + const PointGFp& base_point() const { return m_base_point; } + + bool a_is_minus_3() const { return m_a_is_minus_3; } + bool a_is_zero() const { return m_a_is_zero; } + + BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); } + + BigInt square_mod_order(const BigInt& x) const + { + return m_mod_order.square(x); + } + + BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const + { + return m_mod_order.multiply(x, y); + } + + BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const + { + return m_mod_order.multiply(m_mod_order.multiply(x, y), z); + } + + BigInt inverse_mod_order(const BigInt& x) const + { + return inverse_mod(x, m_order); + } + + PointGFp blinded_base_point_multiply(const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const + { + return m_base_mult.mul(k, rng, m_order, ws); + } + + EC_Group_Source source() const { return m_source; } + + private: + CurveGFp m_curve; + PointGFp m_base_point; + + BigInt m_g_x; + BigInt m_g_y; + BigInt m_order; + BigInt m_cofactor; + Modular_Reducer m_mod_order; + PointGFp_Base_Point_Precompute m_base_mult; + OID m_oid; + size_t m_p_bits; + size_t m_order_bits; + bool m_a_is_minus_3; + bool m_a_is_zero; + EC_Group_Source m_source; + }; + +class EC_Group_Data_Map final + { + public: + EC_Group_Data_Map() {} + + size_t clear() + { + lock_guard_type lock(m_mutex); + size_t count = m_registered_curves.size(); + m_registered_curves.clear(); + return count; + } + + std::shared_ptr lookup(const OID& oid) + { + lock_guard_type lock(m_mutex); + + for(auto i : m_registered_curves) + { + if(i->oid() == oid) + return i; + } + + // Not found, check hardcoded data + std::shared_ptr data = EC_Group::EC_group_info(oid); + + if(data) + { + m_registered_curves.push_back(data); + return data; + } + + // Nope, unknown curve + return std::shared_ptr(); + } + + std::shared_ptr lookup_or_create(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& g_x, + const BigInt& g_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid, + EC_Group_Source source) + { + lock_guard_type lock(m_mutex); + + for(auto i : m_registered_curves) + { + if(!oid.empty()) + { + if(i->oid() == oid) + { + if(!i->match(p, a, b, g_x, g_y, order, cofactor)) + throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() + + " but another curve is already registered using that OID"); + return i; + } + else if(i->oid().has_value()) + continue; // distinct OIDs so not a match + } + + if(i->match(p, a, b, g_x, g_y, order, cofactor)) + { + /* + * If the same curve was previously created without an OID + * but has been registered again using an OID, save that OID. + */ + if(oid.empty() == false) + { + if(i->oid().empty() == true) + { + i->set_oid(oid); + } + else + { + throw Invalid_Argument("Cannot register ECC group with OID " + oid.to_string() + + " already registered using " + i->oid().to_string()); + } + } + return i; + } + } + + // Not found - if OID is set try looking up that way + + if(oid.has_value()) + { + // Not located in existing store - try hardcoded data set + std::shared_ptr data = EC_Group::EC_group_info(oid); + + if(data) + { + m_registered_curves.push_back(data); + return data; + } + } + + // Not found or no OID, add data and return + std::shared_ptr d = + std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, source); + + m_registered_curves.push_back(d); + return d; + } + + private: + mutex_type m_mutex; + std::vector> m_registered_curves; + }; + +//static +EC_Group_Data_Map& EC_Group::ec_group_data() + { + /* + * This exists purely to ensure the allocator is constructed before g_ec_data, + * which ensures that its destructor runs after ~g_ec_data is complete. + */ + + static Allocator_Initializer g_init_allocator; + static EC_Group_Data_Map g_ec_data; + return g_ec_data; + } + +//static +size_t EC_Group::clear_registered_curve_data() + { + return ec_group_data().clear(); + } + +//static +std::shared_ptr +EC_Group::load_EC_group_info(const char* p_str, + const char* a_str, + const char* b_str, + const char* g_x_str, + const char* g_y_str, + const char* order_str, + const OID& oid) + { + const BigInt p(p_str); + const BigInt a(a_str); + const BigInt b(b_str); + const BigInt g_x(g_x_str); + const BigInt g_y(g_y_str); + const BigInt order(order_str); + const BigInt cofactor(1); // implicit + + return std::make_shared(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin); + } + +//static +std::shared_ptr EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len, + EC_Group_Source source) + { + BER_Decoder ber(bits, len); + BER_Object obj = ber.get_next_object(); + + if(obj.type() == NULL_TAG) + { + throw Decoding_Error("Cannot handle ImplicitCA ECC parameters"); + } + else if(obj.type() == OBJECT_ID) + { + OID dom_par_oid; + BER_Decoder(bits, len).decode(dom_par_oid); + return ec_group_data().lookup(dom_par_oid); + } + else if(obj.type() == SEQUENCE) + { + BigInt p, a, b, order, cofactor; + std::vector base_pt; + std::vector seed; + + BER_Decoder(bits, len) + .start_cons(SEQUENCE) + .decode_and_check(1, "Unknown ECC param version code") + .start_cons(SEQUENCE) + .decode_and_check(OID("1.2.840.10045.1.1"), + "Only prime ECC fields supported") + .decode(p) + .end_cons() + .start_cons(SEQUENCE) + .decode_octet_string_bigint(a) + .decode_octet_string_bigint(b) + .decode_optional_string(seed, BIT_STRING, BIT_STRING) + .end_cons() + .decode(base_pt, OCTET_STRING) + .decode(order) + .decode(cofactor) + .end_cons() + .verify_end(); + + if(p.bits() < 64 || p.is_negative() || !is_bailie_psw_probable_prime(p)) + throw Decoding_Error("Invalid ECC p parameter"); + + if(a.is_negative() || a >= p) + throw Decoding_Error("Invalid ECC a parameter"); + + if(b <= 0 || b >= p) + throw Decoding_Error("Invalid ECC b parameter"); + + if(order <= 0 || !is_bailie_psw_probable_prime(order)) + throw Decoding_Error("Invalid ECC order parameter"); + + if(cofactor <= 0 || cofactor >= 16) + throw Decoding_Error("Invalid ECC cofactor parameter"); + + std::pair base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b); + + return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, + order, cofactor, OID(), source); + } + else + { + throw Decoding_Error("Unexpected tag while decoding ECC domain params"); + } + } + +EC_Group::EC_Group() + { + } + +EC_Group::~EC_Group() + { + // shared_ptr possibly freed here + } + +EC_Group::EC_Group(const OID& domain_oid) + { + this->m_data = ec_group_data().lookup(domain_oid); + if(!this->m_data) + throw Invalid_Argument("Unknown EC_Group " + domain_oid.to_string()); + } + +EC_Group::EC_Group(const std::string& str) + { + if(str == "") + return; // no initialization / uninitialized + + try + { + const OID oid = OID::from_string(str); + if(oid.has_value()) + m_data = ec_group_data().lookup(oid); + } + catch(...) + { + } + + if(m_data == nullptr) + { + if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") + { + // OK try it as PEM ... + secure_vector ber = PEM_Code::decode_check_label(str, "EC PARAMETERS"); + this->m_data = BER_decode_EC_group(ber.data(), ber.size(), EC_Group_Source::ExternalSource); + } + } + + if(m_data == nullptr) + throw Invalid_Argument("Unknown ECC group '" + str + "'"); + } + +//static +EC_Group EC_Group::EC_Group_from_PEM(const std::string& pem) + { + const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS"); + return EC_Group(ber.data(), ber.size()); + } + +//static +std::string EC_Group::PEM_for_named_group(const std::string& name) + { + try + { + EC_Group group(name); + return group.PEM_encode(); + } + catch(...) + { + return ""; + } + } + +EC_Group::EC_Group(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& base_x, + const BigInt& base_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid) + { + m_data = ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid, + EC_Group_Source::ExternalSource); + } + +EC_Group::EC_Group(const uint8_t ber[], size_t ber_len) + { + m_data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource); + } + +const EC_Group_Data& EC_Group::data() const + { + if(m_data == nullptr) + throw Invalid_State("EC_Group uninitialized"); + return *m_data; + } + +const CurveGFp& EC_Group::get_curve() const + { + return data().curve(); + } + +bool EC_Group::a_is_minus_3() const + { + return data().a_is_minus_3(); + } + +bool EC_Group::a_is_zero() const + { + return data().a_is_zero(); + } + +size_t EC_Group::get_p_bits() const + { + return data().p_bits(); + } + +size_t EC_Group::get_p_bytes() const + { + return data().p_bytes(); + } + +size_t EC_Group::get_order_bits() const + { + return data().order_bits(); + } + +size_t EC_Group::get_order_bytes() const + { + return data().order_bytes(); + } + +const BigInt& EC_Group::get_p() const + { + return data().p(); + } + +const BigInt& EC_Group::get_a() const + { + return data().a(); + } + +const BigInt& EC_Group::get_b() const + { + return data().b(); + } + +const PointGFp& EC_Group::get_base_point() const + { + return data().base_point(); + } + +const BigInt& EC_Group::get_order() const + { + return data().order(); + } + +const BigInt& EC_Group::get_g_x() const + { + return data().g_x(); + } + +const BigInt& EC_Group::get_g_y() const + { + return data().g_y(); + } + +const BigInt& EC_Group::get_cofactor() const + { + return data().cofactor(); + } + +BigInt EC_Group::mod_order(const BigInt& k) const + { + return data().mod_order(k); + } + +BigInt EC_Group::square_mod_order(const BigInt& x) const + { + return data().square_mod_order(x); + } + +BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const + { + return data().multiply_mod_order(x, y); + } + +BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const + { + return data().multiply_mod_order(x, y, z); + } + +BigInt EC_Group::inverse_mod_order(const BigInt& x) const + { + return data().inverse_mod_order(x); + } + +const OID& EC_Group::get_curve_oid() const + { + return data().oid(); + } + +EC_Group_Source EC_Group::source() const + { + return data().source(); + } + +size_t EC_Group::point_size(PointGFp::Compression_Type format) const + { + // Hybrid and standard format are (x,y), compressed is y, +1 format byte + if(format == PointGFp::COMPRESSED) + return (1 + get_p_bytes()); + else + return (1 + 2*get_p_bytes()); + } + +PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const + { + return Botan::OS2ECP(bits, len, data().curve()); + } + +PointGFp EC_Group::point(const BigInt& x, const BigInt& y) const + { + // TODO: randomize the representation? + return PointGFp(data().curve(), x, y); + } + +PointGFp EC_Group::point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const + { + PointGFp_Multi_Point_Precompute xy_mul(get_base_point(), pt); + return xy_mul.multi_exp(x, y); + } + +PointGFp EC_Group::blinded_base_point_multiply(const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const + { + return data().blinded_base_point_multiply(k, rng, ws); + } + +BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const + { + const PointGFp pt = data().blinded_base_point_multiply(k, rng, ws); + + if(pt.is_zero()) + return 0; + return pt.get_affine_x(); + } + +BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const + { + return BigInt::random_integer(rng, 1, get_order()); + } + +PointGFp EC_Group::blinded_var_point_multiply(const PointGFp& point, + const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const + { + PointGFp_Var_Point_Precompute mul(point, rng, ws); + return mul.mul(k, rng, get_order(), ws); + } + +PointGFp EC_Group::zero_point() const + { + return PointGFp(data().curve()); + } + +std::vector +EC_Group::DER_encode(EC_Group_Encoding form) const + { + std::vector output; + + DER_Encoder der(output); + + if(form == EC_DOMPAR_ENC_EXPLICIT) + { + const size_t ecpVers1 = 1; + const OID curve_type("1.2.840.10045.1.1"); // prime field + + const size_t p_bytes = get_p_bytes(); + + der.start_cons(SEQUENCE) + .encode(ecpVers1) + .start_cons(SEQUENCE) + .encode(curve_type) + .encode(get_p()) + .end_cons() + .start_cons(SEQUENCE) + .encode(BigInt::encode_1363(get_a(), p_bytes), + OCTET_STRING) + .encode(BigInt::encode_1363(get_b(), p_bytes), + OCTET_STRING) + .end_cons() + .encode(get_base_point().encode(PointGFp::UNCOMPRESSED), OCTET_STRING) + .encode(get_order()) + .encode(get_cofactor()) + .end_cons(); + } + else if(form == EC_DOMPAR_ENC_OID) + { + const OID oid = get_curve_oid(); + if(oid.empty()) + { + throw Encoding_Error("Cannot encode EC_Group as OID because OID not set"); + } + der.encode(oid); + } + else if(form == EC_DOMPAR_ENC_IMPLICITCA) + { + der.encode_null(); + } + else + { + throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); + } + + return output; + } + +std::string EC_Group::PEM_encode() const + { + const std::vector der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); + return PEM_Code::encode(der, "EC PARAMETERS"); + } + +bool EC_Group::operator==(const EC_Group& other) const + { + if(m_data == other.m_data) + return true; // same shared rep + + /* + * No point comparing order/cofactor as they are uniquely determined + * by the curve equation (p,a,b) and the base point. + */ + return (get_p() == other.get_p() && + get_a() == other.get_a() && + get_b() == other.get_b() && + get_g_x() == other.get_g_x() && + get_g_y() == other.get_g_y()); + } + +bool EC_Group::verify_public_element(const PointGFp& point) const + { + //check that public point is not at infinity + if(point.is_zero()) + return false; + + //check that public point is on the curve + if(point.on_the_curve() == false) + return false; + + //check that public point has order q + if((point * get_order()).is_zero() == false) + return false; + + if(get_cofactor() > 1) + { + if((point * get_cofactor()).is_zero()) + return false; + } + + return true; + } + +bool EC_Group::verify_group(RandomNumberGenerator& rng, + bool strong) const + { + const bool is_builtin = source() == EC_Group_Source::Builtin; + + if(is_builtin && !strong) + return true; + + const BigInt& p = get_p(); + const BigInt& a = get_a(); + const BigInt& b = get_b(); + const BigInt& order = get_order(); + const PointGFp& base_point = get_base_point(); + + if(p <= 3 || order <= 0) + return false; + if(a < 0 || a >= p) + return false; + if(b <= 0 || b >= p) + return false; + + const size_t test_prob = 128; + const bool is_randomly_generated = is_builtin; + + //check if field modulus is prime + if(!is_prime(p, rng, test_prob, is_randomly_generated)) + { + return false; + } + + //check if order is prime + if(!is_prime(order, rng, test_prob, is_randomly_generated)) + { + return false; + } + + //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero + const Modular_Reducer mod_p(p); + + const BigInt discriminant = mod_p.reduce( + mod_p.multiply(4, mod_p.cube(a)) + + mod_p.multiply(27, mod_p.square(b))); + + if(discriminant == 0) + { + return false; + } + + //check for valid cofactor + if(get_cofactor() < 1) + { + return false; + } + + //check if the base point is on the curve + if(!base_point.on_the_curve()) + { + return false; + } + if((base_point * get_cofactor()).is_zero()) + { + return false; + } + //check if order of the base point is correct + if(!(base_point * order).is_zero()) + { + return false; + } + + return true; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.h b/comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.h new file mode 100644 index 0000000000..8f583a3092 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/ec_group.h @@ -0,0 +1,398 @@ +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECC_DOMAIN_PARAMETERS_H_ +#define BOTAN_ECC_DOMAIN_PARAMETERS_H_ + +#include +#include +#include +#include + +namespace Botan { + +/** +* This class represents elliptic curce domain parameters +*/ +enum EC_Group_Encoding { + EC_DOMPAR_ENC_EXPLICIT = 0, + EC_DOMPAR_ENC_IMPLICITCA = 1, + EC_DOMPAR_ENC_OID = 2 +}; + +enum class EC_Group_Source { + Builtin, + ExternalSource, +}; + +class CurveGFp; + +class EC_Group_Data; +class EC_Group_Data_Map; + +/** +* Class representing an elliptic curve +* +* The internal representation is stored in a shared_ptr, so copying an +* EC_Group is inexpensive. +*/ +class BOTAN_PUBLIC_API(2,0) EC_Group final + { + public: + + /** + * Construct Domain paramers from specified parameters + * @param curve elliptic curve + * @param base_point a base point + * @param order the order of the base point + * @param cofactor the cofactor + */ + BOTAN_DEPRECATED("Use version taking all BigInts") + EC_Group(const CurveGFp& curve, + const PointGFp& base_point, + const BigInt& order, + const BigInt& cofactor) : + EC_Group(curve.get_p(), + curve.get_a(), + curve.get_b(), + base_point.get_affine_x(), + base_point.get_affine_y(), + order, + cofactor) {} + + /** + * Construct Domain paramers from specified parameters + * @param p the elliptic curve p + * @param a the elliptic curve a param + * @param b the elliptic curve b param + * @param base_x the x coordinate of the base point + * @param base_y the y coordinate of the base point + * @param order the order of the base point + * @param cofactor the cofactor + * @param oid an optional OID used to identify this curve + */ + EC_Group(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& base_x, + const BigInt& base_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid = OID()); + + /** + * Decode a BER encoded ECC domain parameter set + * @param ber the bytes of the BER encoding + * @param ber_len the length of ber + */ + explicit EC_Group(const uint8_t ber[], size_t ber_len); + + template + EC_Group(const std::vector& ber) : + EC_Group(ber.data(), ber.size()) {} + + /** + * Create an EC domain by OID (or throw if unknown) + * @param oid the OID of the EC domain to create + */ + explicit EC_Group(const OID& oid); + + /** + * Create an EC domain from PEM encoding (as from PEM_encode), or + * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7") + * @param pem_or_oid PEM-encoded data, or an OID + + * @warning Support for PEM in this function is deprecated. Use + * EC_Group_from_PEM + */ + explicit EC_Group(const std::string& pem_or_oid); + + static EC_Group EC_Group_from_PEM(const std::string& pem); + + /** + * Create an uninitialized EC_Group + */ + EC_Group(); + + ~EC_Group(); + + EC_Group(const EC_Group&) = default; + EC_Group(EC_Group&&) = default; + + EC_Group& operator=(const EC_Group&) = default; + EC_Group& operator=(EC_Group&&) = default; + + /** + * Create the DER encoding of this domain + * @param form of encoding to use + * @returns bytes encododed as DER + */ + std::vector DER_encode(EC_Group_Encoding form) const; + + /** + * Return the PEM encoding (always in explicit form) + * @return string containing PEM data + */ + std::string PEM_encode() const; + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + BOTAN_DEPRECATED("Avoid CurveGFp") const CurveGFp& get_curve() const; + + /** + * Return if a == -3 mod p + */ + bool a_is_minus_3() const; + + /** + * Return if a == 0 mod p + */ + bool a_is_zero() const; + + /** + * Return the size of p in bits (same as get_p().bits()) + */ + size_t get_p_bits() const; + + /** + * Return the size of p in bits (same as get_p().bytes()) + */ + size_t get_p_bytes() const; + + /** + * Return the size of group order in bits (same as get_order().bits()) + */ + size_t get_order_bits() const; + + /** + * Return the size of p in bytes (same as get_order().bytes()) + */ + size_t get_order_bytes() const; + + /** + * Return the prime modulus of the field + */ + const BigInt& get_p() const; + + /** + * Return the a parameter of the elliptic curve equation + */ + const BigInt& get_a() const; + + /** + * Return the b parameter of the elliptic curve equation + */ + const BigInt& get_b() const; + + /** + * Return group base point + * @result base point + */ + const PointGFp& get_base_point() const; + + /** + * Return the x coordinate of the base point + */ + const BigInt& get_g_x() const; + + /** + * Return the y coordinate of the base point + */ + const BigInt& get_g_y() const; + + /** + * Return the order of the base point + * @result order of the base point + */ + const BigInt& get_order() const; + + /* + * Reduce x modulo the order + */ + BigInt mod_order(const BigInt& x) const; + + /* + * Return inverse of x modulo the order + */ + BigInt inverse_mod_order(const BigInt& x) const; + + /* + * Reduce (x*x) modulo the order + */ + BigInt square_mod_order(const BigInt& x) const; + + /* + * Reduce (x*y) modulo the order + */ + BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const; + + /* + * Reduce (x*y*z) modulo the order + */ + BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const; + + /** + * Return the cofactor + * @result the cofactor + */ + const BigInt& get_cofactor() const; + + /** + * Check if y is a plausible point on the curve + * + * In particular, checks that it is a point on the curve, not infinity, + * and that it has order matching the group. + */ + bool verify_public_element(const PointGFp& y) const; + + /** + * Return the OID of these domain parameters + * @result the OID as a string + */ + std::string BOTAN_DEPRECATED("Use get_curve_oid") get_oid() const { return get_curve_oid().to_string(); } + + /** + * Return the OID of these domain parameters + * @result the OID + */ + const OID& get_curve_oid() const; + + /** + * Return a point on this curve with the affine values x, y + */ + PointGFp point(const BigInt& x, const BigInt& y) const; + + /** + * Multi exponentiate. Not constant time. + * @return base_point*x + pt*y + */ + PointGFp point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const; + + /** + * Blinded point multiplication, attempts resistance to side channels + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return base_point*k + */ + PointGFp blinded_base_point_multiply(const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const; + + /** + * Blinded point multiplication, attempts resistance to side channels + * Returns just the x coordinate of the point + * + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return x coordinate of base_point*k + */ + BigInt blinded_base_point_multiply_x(const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const; + + /** + * Blinded point multiplication, attempts resistance to side channels + * @param point input point + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return point*k + */ + PointGFp blinded_var_point_multiply(const PointGFp& point, + const BigInt& k, + RandomNumberGenerator& rng, + std::vector& ws) const; + + /** + * Return a random scalar ie an integer in [1,order) + */ + BigInt random_scalar(RandomNumberGenerator& rng) const; + + /** + * Return the zero (or infinite) point on this curve + */ + PointGFp zero_point() const; + + size_t point_size(PointGFp::Compression_Type format) const; + + PointGFp OS2ECP(const uint8_t bits[], size_t len) const; + + template + PointGFp OS2ECP(const std::vector& vec) const + { + return this->OS2ECP(vec.data(), vec.size()); + } + + bool initialized() const { return (m_data != nullptr); } + + /** + * Verify EC_Group domain + * @returns true if group is valid. false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, + bool strong = false) const; + + bool operator==(const EC_Group& other) const; + + EC_Group_Source source() const; + + /** + * Return PEM representation of named EC group + * Deprecated: Use EC_Group(name).PEM_encode() if this is needed + */ + static std::string BOTAN_DEPRECATED("See header comment") PEM_for_named_group(const std::string& name); + + /** + * Return a set of known named EC groups + */ + static const std::set& known_named_groups(); + + /* + * For internal use only + */ + static std::shared_ptr EC_group_info(const OID& oid); + + static size_t clear_registered_curve_data(); + + private: + static EC_Group_Data_Map& ec_group_data(); + + static std::shared_ptr BER_decode_EC_group(const uint8_t bits[], size_t len, + EC_Group_Source source); + + static std::shared_ptr + load_EC_group_info(const char* p, + const char* a, + const char* b, + const char* g_x, + const char* g_y, + const char* order, + const OID& oid); + + // Member data + const EC_Group_Data& data() const; + std::shared_ptr m_data; + }; + +inline bool operator!=(const EC_Group& lhs, + const EC_Group& rhs) + { + return !(lhs == rhs); + } + +// For compatibility with 1.8 +typedef EC_Group EC_Domain_Params; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/ec_named.cpp b/comm/third_party/botan/src/lib/pubkey/ec_group/ec_named.cpp new file mode 100644 index 0000000000..7fe1517e44 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/ec_named.cpp @@ -0,0 +1,301 @@ +/* +* List of ECC groups +* (C) 2013,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +//static +std::shared_ptr EC_Group::EC_group_info(const OID& oid) + { + // P-256 + if(oid == OID{1,2,840,10045,3,1,7}) + return load_EC_group_info("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + "0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + oid); + + // P-384 + if(oid == OID{1,3,132,0,34}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", + "0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + "0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + "0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + oid); + // P-521 + if(oid == OID{1,3,132,0,35}) + return load_EC_group_info("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", + "0x51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "0xC6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", + "0x11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", + "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + oid); + + // brainpool160r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,1}) + return load_EC_group_info("0xE95E4A5F737059DC60DFC7AD95B3D8139515620F", + "0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300", + "0x1E589A8595423412134FAA2DBDEC95C8D8675E58", + "0xBED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", + "0x1667CB477A1A8EC338F94741669C976316DA6321", + "0xE95E4A5F737059DC60DF5991D45029409E60FC09", + oid); + // brainpool192r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,3}) + return load_EC_group_info("0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", + "0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", + "0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", + "0xC0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6", + "0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", + "0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", + oid); + // brainpool224r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,5}) + return load_EC_group_info("0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", + "0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", + "0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", + "0xD9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D", + "0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", + "0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", + oid); + // brainpool256r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,7}) + return load_EC_group_info("0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", + "0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", + "0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", + "0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", + "0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", + "0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", + oid); + // brainpool320r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,9}) + return load_EC_group_info("0xD35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", + "0x3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", + "0x520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", + "0x43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", + "0x14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", + "0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", + oid); + // brainpool384r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,11}) + return load_EC_group_info("0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", + "0x7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", + "0x4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", + "0x1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", + "0x8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", + "0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", + oid); + // brainpool512r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,13}) + return load_EC_group_info("0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", + "0x7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", + "0x3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", + "0x81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", + "0x7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", + "0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", + oid); + // frp256v1 + if(oid == OID{1,2,250,1,223,101,256,1}) + return load_EC_group_info("0xF1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C03", + "0xF1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C00", + "0xEE353FCA5428A9300D4ABA754A44C00FDFEC0C9AE4B1A1803075ED967B7BB73F", + "0xB6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF", + "0x6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB", + "0xF1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1", + oid); + // gost_256A + if(oid == OID{1,2,643,2,2,35,1} || oid == OID{1,2,643,2,2,36,0} || oid == OID{1,2,643,7,1,2,1,1,1}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", + "0xA6", + "0x1", + "0x8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", + OID{1,2,643,7,1,2,1,1,1}); + + // gost_512A + if(oid == OID{1,2,643,7,1,2,1,2,1}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4", + "0xE8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760", + "3", + "0x7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275", + oid); + + // secp160k1 + if(oid == OID{1,3,132,0,9}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0x0", + "0x7", + "0x3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", + "0x938CF935318FDCED6BC28286531733C3F03C4FEE", + "0x100000000000000000001B8FA16DFAB9ACA16B6B3", + oid); + // secp160r1 + if(oid == OID{1,3,132,0,8}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "0x1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "0x4A96B5688EF573284664698968C38BB913CBFC82", + "0x23A628553168947D59DCC912042351377AC5FB32", + "0x100000000000000000001F4C8F927AED3CA752257", + oid); + // secp160r2 + if(oid == OID{1,3,132,0,30}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", + "0xB4E134D3FB59EB8BAB57274904664D5AF50388BA", + "0x52DCB034293A117E1F4FF11B30F7199D3144CE6D", + "0xFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", + "0x100000000000000000000351EE786A818F3A1A16B", + oid); + // secp192k1 + if(oid == OID{1,3,132,0,31}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", + "0x0", + "0x3", + "0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", + "0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", + "0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", + oid); + // secp192r1 + if(oid == OID{1,2,840,10045,3,1,1}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "0x7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", + oid); + // secp224k1 + if(oid == OID{1,3,132,0,32}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", + "0x0", + "0x5", + "0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", + "0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", + "0x10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", + oid); + // secp224r1 + if(oid == OID{1,3,132,0,33}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", + "0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", + "0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", + "0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", + oid); + // secp256k1 + if(oid == OID{1,3,132,0,10}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0x0", + "0x7", + "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + oid); + + // sm2p256v1 + if(oid == OID{1,2,156,10197,1,301}) + return load_EC_group_info("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", + "0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", + "0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", + "0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", + oid); + // x962_p192v2 + if(oid == OID{1,2,840,10045,3,1,2}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "0xCC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", + "0xEEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", + "0x6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", + "0xFFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", + oid); + // x962_p192v3 + if(oid == OID{1,2,840,10045,3,1,3}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "0x22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", + "0x7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", + "0x38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", + "0xFFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", + oid); + // x962_p239v1 + if(oid == OID{1,2,840,10045,3,1,4}) + return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "0x6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", + "0xFFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", + "0x7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", + oid); + // x962_p239v2 + if(oid == OID{1,2,840,10045,3,1,5}) + return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "0x617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", + "0x38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", + "0x5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", + "0x7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", + oid); + // x962_p239v3 + if(oid == OID{1,2,840,10045,3,1,6}) + return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "0x255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", + "0x6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", + "0x1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", + oid); + + return std::shared_ptr(); + } + +//static +const std::set& EC_Group::known_named_groups() + { + static const std::set named_groups = { + "secp160k1", + "secp160r1", + "secp160r2", + "secp192k1", + "secp192r1", + "secp224k1", + "secp224r1", + "secp256k1", + "secp256r1", + "secp384r1", + "secp521r1", + "brainpool160r1", + "brainpool192r1", + "brainpool224r1", + "brainpool256r1", + "brainpool320r1", + "brainpool384r1", + "brainpool512r1", + "x962_p192v2", + "x962_p192v3", + "x962_p239v1", + "x962_p239v2", + "x962_p239v3", + "gost_256A", + "gost_512A", + "frp256v1", + "sm2p256v1" + }; + return named_groups; + } +} diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/info.txt b/comm/third_party/botan/src/lib/pubkey/ec_group/info.txt new file mode 100644 index 0000000000..e382e25a5e --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/info.txt @@ -0,0 +1,20 @@ + +ECC_GROUP -> 20170225 +EC_CURVE_GFP -> 20131128 + + + +asn1 +numbertheory +pem + + + +point_mul.h + + + +curve_gfp.h +ec_group.h +point_gfp.h + diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.cpp b/comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.cpp new file mode 100644 index 0000000000..6c2302bd66 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.cpp @@ -0,0 +1,731 @@ +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2008-2011,2012,2014,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +PointGFp::PointGFp(const CurveGFp& curve) : + m_curve(curve), + m_coord_x(0), + m_coord_y(curve.get_1_rep()), + m_coord_z(0) + { + // Assumes Montgomery rep of zero is zero + } + +PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) : + m_curve(curve), + m_coord_x(x), + m_coord_y(y), + m_coord_z(m_curve.get_1_rep()) + { + if(x < 0 || x >= curve.get_p()) + throw Invalid_Argument("Invalid PointGFp affine x"); + if(y < 0 || y >= curve.get_p()) + throw Invalid_Argument("Invalid PointGFp affine y"); + + secure_vector monty_ws(m_curve.get_ws_size()); + m_curve.to_rep(m_coord_x, monty_ws); + m_curve.to_rep(m_coord_y, monty_ws); + } + +void PointGFp::randomize_repr(RandomNumberGenerator& rng) + { + secure_vector ws(m_curve.get_ws_size()); + randomize_repr(rng, ws); + } + +void PointGFp::randomize_repr(RandomNumberGenerator& rng, secure_vector& ws) + { + const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p()); + + /* + * No reason to convert this to Montgomery representation first, + * just pretend the random mask was chosen as Redc(mask) and the + * random mask we generated above is in the Montgomery + * representation. + * //m_curve.to_rep(mask, ws); + */ + const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws); + const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws); + + m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws); + m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws); + m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws); + } + +namespace { + +inline void resize_ws(std::vector& ws_bn, size_t cap_size) + { + BOTAN_ASSERT(ws_bn.size() >= PointGFp::WORKSPACE_SIZE, + "Expected size for PointGFp workspace"); + + for(size_t i = 0; i != ws_bn.size(); ++i) + if(ws_bn[i].size() < cap_size) + ws_bn[i].get_word_vector().resize(cap_size); + } + +inline word all_zeros(const word x[], size_t len) + { + word z = 0; + for(size_t i = 0; i != len; ++i) + z |= x[i]; + return CT::Mask::is_zero(z).value(); + } + +} + +void PointGFp::add_affine(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + std::vector& ws_bn) + { + if(all_zeros(x_words, x_size) & all_zeros(y_words, y_size)) + { + return; + } + + if(is_zero()) + { + m_coord_x.set_words(x_words, x_size); + m_coord_y.set_words(y_words, y_size); + m_coord_z = m_curve.get_1_rep(); + return; + } + + resize_ws(ws_bn, m_curve.get_ws_size()); + + secure_vector& ws = ws_bn[0].get_word_vector(); + secure_vector& sub_ws = ws_bn[1].get_word_vector(); + + BigInt& T0 = ws_bn[2]; + BigInt& T1 = ws_bn[3]; + BigInt& T2 = ws_bn[4]; + BigInt& T3 = ws_bn[5]; + BigInt& T4 = ws_bn[6]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + simplified with Z2 = 1 + */ + + const BigInt& p = m_curve.get_p(); + + m_curve.sqr(T3, m_coord_z, ws); // z1^2 + m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 + + m_curve.mul(T2, m_coord_z, T3, ws); // z1^3 + m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3 + + T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2 + + T0.mod_sub(m_coord_y, p, sub_ws); + + if(T4.is_zero()) + { + if(T0.is_zero()) + { + mult2(ws_bn); + return; + } + + // setting to zero: + m_coord_x.clear(); + m_coord_y = m_curve.get_1_rep(); + m_coord_z.clear(); + return; + } + + m_curve.sqr(T2, T4, ws); + + m_curve.mul(T3, m_coord_x, T2, ws); + + m_curve.mul(T1, T2, T4, ws); + + m_curve.sqr(m_coord_x, T0, ws); + m_coord_x.mod_sub(T1, p, sub_ws); + + m_coord_x.mod_sub(T3, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + + T3.mod_sub(m_coord_x, p, sub_ws); + + m_curve.mul(T2, T0, T3, ws); + m_curve.mul(T0, m_coord_y, T1, ws); + T2.mod_sub(T0, p, sub_ws); + m_coord_y.swap(T2); + + m_curve.mul(T0, m_coord_z, T4, ws); + m_coord_z.swap(T0); + } + +void PointGFp::add(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + const word z_words[], size_t z_size, + std::vector& ws_bn) + { + if(all_zeros(x_words, x_size) & all_zeros(z_words, z_size)) + return; + + if(is_zero()) + { + m_coord_x.set_words(x_words, x_size); + m_coord_y.set_words(y_words, y_size); + m_coord_z.set_words(z_words, z_size); + return; + } + + resize_ws(ws_bn, m_curve.get_ws_size()); + + secure_vector& ws = ws_bn[0].get_word_vector(); + secure_vector& sub_ws = ws_bn[1].get_word_vector(); + + BigInt& T0 = ws_bn[2]; + BigInt& T1 = ws_bn[3]; + BigInt& T2 = ws_bn[4]; + BigInt& T3 = ws_bn[5]; + BigInt& T4 = ws_bn[6]; + BigInt& T5 = ws_bn[7]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + */ + + const BigInt& p = m_curve.get_p(); + + m_curve.sqr(T0, z_words, z_size, ws); // z2^2 + m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2 + m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3 + m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3 + + m_curve.sqr(T3, m_coord_z, ws); // z1^2 + m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 + + m_curve.mul(T5, m_coord_z, T3, ws); // z1^3 + m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3 + + T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2 + + T0.mod_sub(T2, p, sub_ws); + + if(T4.is_zero()) + { + if(T0.is_zero()) + { + mult2(ws_bn); + return; + } + + // setting to zero: + m_coord_x.clear(); + m_coord_y = m_curve.get_1_rep(); + m_coord_z.clear(); + return; + } + + m_curve.sqr(T5, T4, ws); + + m_curve.mul(T3, T1, T5, ws); + + m_curve.mul(T1, T5, T4, ws); + + m_curve.sqr(m_coord_x, T0, ws); + m_coord_x.mod_sub(T1, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + + T3.mod_sub(m_coord_x, p, sub_ws); + + m_curve.mul(m_coord_y, T0, T3, ws); + m_curve.mul(T3, T2, T1, ws); + + m_coord_y.mod_sub(T3, p, sub_ws); + + m_curve.mul(T3, z_words, z_size, m_coord_z, ws); + m_curve.mul(m_coord_z, T3, T4, ws); + } + +void PointGFp::mult2i(size_t iterations, std::vector& ws_bn) + { + if(iterations == 0) + return; + + if(m_coord_y.is_zero()) + { + *this = PointGFp(m_curve); // setting myself to zero + return; + } + + /* + TODO we can save 2 squarings per iteration by computing + a*Z^4 using values cached from previous iteration + */ + for(size_t i = 0; i != iterations; ++i) + mult2(ws_bn); + } + +// *this *= 2 +void PointGFp::mult2(std::vector& ws_bn) + { + if(is_zero()) + return; + + if(m_coord_y.is_zero()) + { + *this = PointGFp(m_curve); // setting myself to zero + return; + } + + resize_ws(ws_bn, m_curve.get_ws_size()); + + secure_vector& ws = ws_bn[0].get_word_vector(); + secure_vector& sub_ws = ws_bn[1].get_word_vector(); + + BigInt& T0 = ws_bn[2]; + BigInt& T1 = ws_bn[3]; + BigInt& T2 = ws_bn[4]; + BigInt& T3 = ws_bn[5]; + BigInt& T4 = ws_bn[6]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc + */ + const BigInt& p = m_curve.get_p(); + + m_curve.sqr(T0, m_coord_y, ws); + + m_curve.mul(T1, m_coord_x, T0, ws); + T1.mod_mul(4, p, sub_ws); + + if(m_curve.a_is_zero()) + { + // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2 + m_curve.sqr(T4, m_coord_x, ws); // x^2 + T4.mod_mul(3, p, sub_ws); // 3*x^2 + } + else if(m_curve.a_is_minus_3()) + { + /* + if a == -3 then + 3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2) + */ + m_curve.sqr(T3, m_coord_z, ws); // z^2 + + // (x-z^2) + T2 = m_coord_x; + T2.mod_sub(T3, p, sub_ws); + + // (x+z^2) + T3.mod_add(m_coord_x, p, sub_ws); + + m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2) + + T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2) + } + else + { + m_curve.sqr(T3, m_coord_z, ws); // z^2 + m_curve.sqr(T4, T3, ws); // z^4 + m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4 + + m_curve.sqr(T4, m_coord_x, ws); // x^2 + T4.mod_mul(3, p, sub_ws); + T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4 + } + + m_curve.sqr(T2, T4, ws); + T2.mod_sub(T1, p, sub_ws); + T2.mod_sub(T1, p, sub_ws); + + m_curve.sqr(T3, T0, ws); + T3.mod_mul(8, p, sub_ws); + + T1.mod_sub(T2, p, sub_ws); + + m_curve.mul(T0, T4, T1, ws); + T0.mod_sub(T3, p, sub_ws); + + m_coord_x.swap(T2); + + m_curve.mul(T2, m_coord_y, m_coord_z, ws); + T2.mod_mul(2, p, sub_ws); + + m_coord_y.swap(T0); + m_coord_z.swap(T2); + } + +// arithmetic operators +PointGFp& PointGFp::operator+=(const PointGFp& rhs) + { + std::vector ws(PointGFp::WORKSPACE_SIZE); + add(rhs, ws); + return *this; + } + +PointGFp& PointGFp::operator-=(const PointGFp& rhs) + { + PointGFp minus_rhs = PointGFp(rhs).negate(); + + if(is_zero()) + *this = minus_rhs; + else + *this += minus_rhs; + + return *this; + } + +PointGFp& PointGFp::operator*=(const BigInt& scalar) + { + *this = scalar * *this; + return *this; + } + +PointGFp operator*(const BigInt& scalar, const PointGFp& point) + { + BOTAN_DEBUG_ASSERT(point.on_the_curve()); + + const size_t scalar_bits = scalar.bits(); + + std::vector ws(PointGFp::WORKSPACE_SIZE); + + PointGFp R[2] = { point.zero(), point }; + + for(size_t i = scalar_bits; i > 0; i--) + { + const size_t b = scalar.get_bit(i - 1); + R[b ^ 1].add(R[b], ws); + R[b].mult2(ws); + } + + if(scalar.is_negative()) + R[0].negate(); + + BOTAN_DEBUG_ASSERT(R[0].on_the_curve()); + + return R[0]; + } + +//static +void PointGFp::force_all_affine(std::vector& points, + secure_vector& ws) + { + if(points.size() <= 1) + { + for(size_t i = 0; i != points.size(); ++i) + points[i].force_affine(); + return; + } + + for(size_t i = 0; i != points.size(); ++i) + { + if(points[i].is_zero()) + throw Invalid_State("Cannot convert zero ECC point to affine"); + } + + /* + For >= 2 points use Montgomery's trick + + See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography" + (Hankerson, Menezes, Vanstone) + + TODO is it really necessary to save all k points in c? + */ + + const CurveGFp& curve = points[0].m_curve; + const BigInt& rep_1 = curve.get_1_rep(); + + if(ws.size() < curve.get_ws_size()) + ws.resize(curve.get_ws_size()); + + std::vector c(points.size()); + c[0] = points[0].m_coord_z; + + for(size_t i = 1; i != points.size(); ++i) + { + curve.mul(c[i], c[i-1], points[i].m_coord_z, ws); + } + + BigInt s_inv = curve.invert_element(c[c.size()-1], ws); + + BigInt z_inv, z2_inv, z3_inv; + + for(size_t i = points.size() - 1; i != 0; i--) + { + PointGFp& point = points[i]; + + curve.mul(z_inv, s_inv, c[i-1], ws); + + s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws); + + curve.sqr(z2_inv, z_inv, ws); + curve.mul(z3_inv, z2_inv, z_inv, ws); + point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws); + point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws); + point.m_coord_z = rep_1; + } + + curve.sqr(z2_inv, s_inv, ws); + curve.mul(z3_inv, z2_inv, s_inv, ws); + points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws); + points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws); + points[0].m_coord_z = rep_1; + } + +void PointGFp::force_affine() + { + if(is_zero()) + throw Invalid_State("Cannot convert zero ECC point to affine"); + + secure_vector ws; + + const BigInt z_inv = m_curve.invert_element(m_coord_z, ws); + const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws); + const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws); + m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws); + m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws); + m_coord_z = m_curve.get_1_rep(); + } + +bool PointGFp::is_affine() const + { + return m_curve.is_one(m_coord_z); + } + +BigInt PointGFp::get_affine_x() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + secure_vector monty_ws; + + if(is_affine()) + return m_curve.from_rep_to_tmp(m_coord_x, monty_ws); + + BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + z2 = m_curve.invert_element(z2, monty_ws); + + BigInt r; + m_curve.mul(r, m_coord_x, z2, monty_ws); + m_curve.from_rep(r, monty_ws); + return r; + } + +BigInt PointGFp::get_affine_y() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + secure_vector monty_ws; + + if(is_affine()) + return m_curve.from_rep_to_tmp(m_coord_y, monty_ws); + + const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); + const BigInt z3_inv = m_curve.invert_element(z3, monty_ws); + + BigInt r; + m_curve.mul(r, m_coord_y, z3_inv, monty_ws); + m_curve.from_rep(r, monty_ws); + return r; + } + +bool PointGFp::on_the_curve() const + { + /* + Is the point still on the curve?? (If everything is correct, the + point is always on its curve; then the function will return true. + If somehow the state is corrupted, which suggests a fault attack + (or internal computational error), then return false. + */ + if(is_zero()) + return true; + + secure_vector monty_ws; + + const BigInt y2 = m_curve.from_rep_to_tmp(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws); + const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws); + const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws); + const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + + if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)? + { + if(y2 != m_curve.from_rep_to_tmp(x3 + ax + m_curve.get_b_rep(), monty_ws)) + return false; + } + + const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); + const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws); + const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws); + + if(y2 != m_curve.from_rep_to_tmp(x3 + ax_z4 + b_z6, monty_ws)) + return false; + + return true; + } + +// swaps the states of *this and other, does not throw! +void PointGFp::swap(PointGFp& other) + { + m_curve.swap(other.m_curve); + m_coord_x.swap(other.m_coord_x); + m_coord_y.swap(other.m_coord_y); + m_coord_z.swap(other.m_coord_z); + } + +bool PointGFp::operator==(const PointGFp& other) const + { + if(m_curve != other.m_curve) + return false; + + // If this is zero, only equal if other is also zero + if(is_zero()) + return other.is_zero(); + + return (get_affine_x() == other.get_affine_x() && + get_affine_y() == other.get_affine_y()); + } + +// encoding and decoding +std::vector PointGFp::encode(PointGFp::Compression_Type format) const + { + if(is_zero()) + return std::vector(1); // single 0 byte + + const size_t p_bytes = m_curve.get_p().bytes(); + + const BigInt x = get_affine_x(); + const BigInt y = get_affine_y(); + + std::vector result; + + if(format == PointGFp::UNCOMPRESSED) + { + result.resize(1 + 2*p_bytes); + result[0] = 0x04; + BigInt::encode_1363(&result[1], p_bytes, x); + BigInt::encode_1363(&result[1+p_bytes], p_bytes, y); + } + else if(format == PointGFp::COMPRESSED) + { + result.resize(1 + p_bytes); + result[0] = 0x02 | static_cast(y.get_bit(0)); + BigInt::encode_1363(&result[1], p_bytes, x); + } + else if(format == PointGFp::HYBRID) + { + result.resize(1 + 2*p_bytes); + result[0] = 0x06 | static_cast(y.get_bit(0)); + BigInt::encode_1363(&result[1], p_bytes, x); + BigInt::encode_1363(&result[1+p_bytes], p_bytes, y); + } + else + throw Invalid_Argument("EC2OSP illegal point encoding"); + + return result; + } + +namespace { + +BigInt decompress_point(bool yMod2, + const BigInt& x, + const BigInt& curve_p, + const BigInt& curve_a, + const BigInt& curve_b) + { + BigInt xpow3 = x * x * x; + + BigInt g = curve_a * x; + g += xpow3; + g += curve_b; + g = g % curve_p; + + BigInt z = ressol(g, curve_p); + + if(z < 0) + throw Illegal_Point("error during EC point decompression"); + + if(z.get_bit(0) != yMod2) + z = curve_p - z; + + return z; + } + +} + +PointGFp OS2ECP(const uint8_t data[], size_t data_len, + const CurveGFp& curve) + { + // Should we really be doing this? + if(data_len <= 1) + return PointGFp(curve); // return zero + + std::pair xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b()); + + PointGFp point(curve, xy.first, xy.second); + + if(!point.on_the_curve()) + throw Illegal_Point("OS2ECP: Decoded point was not on the curve"); + + return point; + } + +std::pair OS2ECP(const uint8_t data[], size_t data_len, + const BigInt& curve_p, + const BigInt& curve_a, + const BigInt& curve_b) + { + if(data_len <= 1) + throw Decoding_Error("OS2ECP invalid point"); + + const uint8_t pc = data[0]; + + BigInt x, y; + + if(pc == 2 || pc == 3) + { + //compressed form + x = BigInt::decode(&data[1], data_len - 1); + + const bool y_mod_2 = ((pc & 0x01) == 1); + y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b); + } + else if(pc == 4) + { + const size_t l = (data_len - 1) / 2; + + // uncompressed form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + } + else if(pc == 6 || pc == 7) + { + const size_t l = (data_len - 1) / 2; + + // hybrid form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + + const bool y_mod_2 = ((pc & 0x01) == 1); + + if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y) + throw Illegal_Point("OS2ECP: Decoding error in hybrid format"); + } + else + throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc)); + + return std::make_pair(x, y); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.h b/comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.h new file mode 100644 index 0000000000..13752c4a48 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/point_gfp.h @@ -0,0 +1,447 @@ +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2008-2011,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POINT_GFP_H_ +#define BOTAN_POINT_GFP_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Exception thrown if you try to convert a zero point to an affine +* coordinate +* +* In a future major release this exception type will be removed and its +* usage replaced by Invalid_State +*/ +class BOTAN_PUBLIC_API(2,0) Illegal_Transformation final : public Invalid_State + { + public: + explicit Illegal_Transformation(const std::string& err) : Invalid_State(err) {} + }; + +/** +* Exception thrown if some form of illegal point is decoded +* +* In a future major release this exception type will be removed and its +* usage replaced by Decoding_Error +*/ +class BOTAN_PUBLIC_API(2,0) Illegal_Point final : public Decoding_Error + { + public: + explicit Illegal_Point(const std::string& err) : Decoding_Error(err) {} + }; + +/** +* This class represents one point on a curve of GF(p) +*/ +class BOTAN_PUBLIC_API(2,0) PointGFp final + { + public: + enum Compression_Type { + UNCOMPRESSED = 0, + COMPRESSED = 1, + HYBRID = 2 + }; + + enum { WORKSPACE_SIZE = 8 }; + + /** + * Construct an uninitialized PointGFp + */ + PointGFp() = default; + + /** + * Construct the zero point + * @param curve The base curve + */ + explicit PointGFp(const CurveGFp& curve); + + /** + * Copy constructor + */ + PointGFp(const PointGFp&) = default; + + /** + * Move Constructor + */ + PointGFp(PointGFp&& other) + { + this->swap(other); + } + + /** + * Standard Assignment + */ + PointGFp& operator=(const PointGFp&) = default; + + /** + * Move Assignment + */ + PointGFp& operator=(PointGFp&& other) + { + if(this != &other) + this->swap(other); + return (*this); + } + + /** + * Construct a point from its affine coordinates + * Prefer EC_Group::point(x,y) for this operation. + * @param curve the base curve + * @param x affine x coordinate + * @param y affine y coordinate + */ + PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y); + + /** + * EC2OSP - elliptic curve to octet string primitive + * @param format which format to encode using + */ + std::vector encode(PointGFp::Compression_Type format) const; + + /** + * += Operator + * @param rhs the PointGFp to add to the local value + * @result resulting PointGFp + */ + PointGFp& operator+=(const PointGFp& rhs); + + /** + * -= Operator + * @param rhs the PointGFp to subtract from the local value + * @result resulting PointGFp + */ + PointGFp& operator-=(const PointGFp& rhs); + + /** + * *= Operator + * @param scalar the PointGFp to multiply with *this + * @result resulting PointGFp + */ + PointGFp& operator*=(const BigInt& scalar); + + /** + * Negate this point + * @return *this + */ + PointGFp& negate() + { + if(!is_zero()) + m_coord_y = m_curve.get_p() - m_coord_y; + return *this; + } + + /** + * get affine x coordinate + * @result affine x coordinate + */ + BigInt get_affine_x() const; + + /** + * get affine y coordinate + * @result affine y coordinate + */ + BigInt get_affine_y() const; + + const BigInt& get_x() const { return m_coord_x; } + const BigInt& get_y() const { return m_coord_y; } + const BigInt& get_z() const { return m_coord_z; } + + void swap_coords(BigInt& new_x, BigInt& new_y, BigInt& new_z) + { + m_coord_x.swap(new_x); + m_coord_y.swap(new_y); + m_coord_z.swap(new_z); + } + + /** + * Force this point to affine coordinates + */ + void force_affine(); + + /** + * Force all points on the list to affine coordinates + */ + static void force_all_affine(std::vector& points, + secure_vector& ws); + + bool is_affine() const; + + /** + * Is this the point at infinity? + * @result true, if this point is at infinity, false otherwise. + */ + bool is_zero() const { return m_coord_z.is_zero(); } + + /** + * Checks whether the point is to be found on the underlying + * curve; used to prevent fault attacks. + * @return if the point is on the curve + */ + bool on_the_curve() const; + + /** + * swaps the states of *this and other, does not throw! + * @param other the object to swap values with + */ + void swap(PointGFp& other); + + /** + * Randomize the point representation + * The actual value (get_affine_x, get_affine_y) does not change + */ + void randomize_repr(RandomNumberGenerator& rng); + + /** + * Randomize the point representation + * The actual value (get_affine_x, get_affine_y) does not change + */ + void randomize_repr(RandomNumberGenerator& rng, secure_vector& ws); + + /** + * Equality operator + */ + bool operator==(const PointGFp& other) const; + + /** + * Point addition + * @param other the point to add to *this + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add(const PointGFp& other, std::vector& workspace) + { + BOTAN_ASSERT_NOMSG(m_curve == other.m_curve); + + const size_t p_words = m_curve.get_p_words(); + + add(other.m_coord_x.data(), std::min(p_words, other.m_coord_x.size()), + other.m_coord_y.data(), std::min(p_words, other.m_coord_y.size()), + other.m_coord_z.data(), std::min(p_words, other.m_coord_z.size()), + workspace); + } + + /** + * Point addition. Array version. + * + * @param x_words the words of the x coordinate of the other point + * @param x_size size of x_words + * @param y_words the words of the y coordinate of the other point + * @param y_size size of y_words + * @param z_words the words of the z coordinate of the other point + * @param z_size size of z_words + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + const word z_words[], size_t z_size, + std::vector& workspace); + + /** + * Point addition - mixed J+A + * @param other affine point to add - assumed to be affine! + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add_affine(const PointGFp& other, std::vector& workspace) + { + BOTAN_ASSERT_NOMSG(m_curve == other.m_curve); + BOTAN_DEBUG_ASSERT(other.is_affine()); + + const size_t p_words = m_curve.get_p_words(); + add_affine(other.m_coord_x.data(), std::min(p_words, other.m_coord_x.size()), + other.m_coord_y.data(), std::min(p_words, other.m_coord_y.size()), + workspace); + } + + /** + * Point addition - mixed J+A. Array version. + * + * @param x_words the words of the x coordinate of the other point + * @param x_size size of x_words + * @param y_words the words of the y coordinate of the other point + * @param y_size size of y_words + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add_affine(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + std::vector& workspace); + + /** + * Point doubling + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void mult2(std::vector& workspace); + + /** + * Repeated point doubling + * @param i number of doublings to perform + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void mult2i(size_t i, std::vector& workspace); + + /** + * Point addition + * @param other the point to add to *this + * @param workspace temp space, at least WORKSPACE_SIZE elements + * @return other plus *this + */ + PointGFp plus(const PointGFp& other, std::vector& workspace) const + { + PointGFp x = (*this); + x.add(other, workspace); + return x; + } + + /** + * Point doubling + * @param workspace temp space, at least WORKSPACE_SIZE elements + * @return *this doubled + */ + PointGFp double_of(std::vector& workspace) const + { + PointGFp x = (*this); + x.mult2(workspace); + return x; + } + + /** + * Return the zero (aka infinite) point associated with this curve + */ + PointGFp zero() const { return PointGFp(m_curve); } + + /** + * Return base curve of this point + * @result the curve over GF(p) of this point + * + * You should not need to use this + */ + const CurveGFp& get_curve() const { return m_curve; } + + private: + CurveGFp m_curve; + BigInt m_coord_x, m_coord_y, m_coord_z; + }; + +/** +* Point multiplication operator +* @param scalar the scalar value +* @param point the point value +* @return scalar*point on the curve +*/ +BOTAN_PUBLIC_API(2,0) PointGFp operator*(const BigInt& scalar, const PointGFp& point); + +/** +* ECC point multiexponentiation - not constant time! +* @param p1 a point +* @param z1 a scalar +* @param p2 a point +* @param z2 a scalar +* @result (p1 * z1 + p2 * z2) +*/ +BOTAN_PUBLIC_API(2,0) PointGFp multi_exponentiate( + const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2); + +// relational operators +inline bool operator!=(const PointGFp& lhs, const PointGFp& rhs) + { + return !(rhs == lhs); + } + +// arithmetic operators +inline PointGFp operator-(const PointGFp& lhs) + { + return PointGFp(lhs).negate(); + } + +inline PointGFp operator+(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp += rhs; + } + +inline PointGFp operator-(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp -= rhs; + } + +inline PointGFp operator*(const PointGFp& point, const BigInt& scalar) + { + return scalar * point; + } + +// encoding and decoding +inline secure_vector BOTAN_DEPRECATED("Use PointGFp::encode") + EC2OSP(const PointGFp& point, uint8_t format) + { + std::vector enc = point.encode(static_cast(format)); + return secure_vector(enc.begin(), enc.end()); + } + +/** +* Perform point decoding +* Use EC_Group::OS2ECP instead +*/ +PointGFp BOTAN_PUBLIC_API(2,0) OS2ECP(const uint8_t data[], size_t data_len, + const CurveGFp& curve); + +/** +* Perform point decoding +* Use EC_Group::OS2ECP instead +* +* @param data the encoded point +* @param data_len length of data in bytes +* @param curve_p the curve equation prime +* @param curve_a the curve equation a parameter +* @param curve_b the curve equation b parameter +*/ +std::pair BOTAN_UNSTABLE_API OS2ECP(const uint8_t data[], size_t data_len, + const BigInt& curve_p, + const BigInt& curve_a, + const BigInt& curve_b); + +template +PointGFp OS2ECP(const std::vector& data, const CurveGFp& curve) + { return OS2ECP(data.data(), data.size(), curve); } + +class PointGFp_Var_Point_Precompute; + +/** +* Deprecated API for point multiplication +* Use EC_Group::blinded_base_point_multiply or EC_Group::blinded_var_point_multiply +*/ +class BOTAN_PUBLIC_API(2,0) Blinded_Point_Multiply final + { + public: + Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h = 0); + + ~Blinded_Point_Multiply(); + + PointGFp BOTAN_DEPRECATED("Use alternative APIs") blinded_multiply(const BigInt& scalar, RandomNumberGenerator& rng); + private: + std::vector m_ws; + const BigInt& m_order; + std::unique_ptr m_point_mul; + }; + +} + +namespace std { + +template<> +inline void swap(Botan::PointGFp& x, Botan::PointGFp& y) + { x.swap(y); } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.cpp b/comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.cpp new file mode 100644 index 0000000000..2dff959d7c --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.cpp @@ -0,0 +1,431 @@ +/* +* (C) 2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +size_t blinding_size(const BigInt& group_order) + { + return (group_order.bits() + 1) / 2; + } + +} + +PointGFp multi_exponentiate(const PointGFp& x, const BigInt& z1, + const PointGFp& y, const BigInt& z2) + { + PointGFp_Multi_Point_Precompute xy_mul(x, y); + return xy_mul.multi_exp(z1, z2); + } + +Blinded_Point_Multiply::Blinded_Point_Multiply(const PointGFp& base, + const BigInt& order, + size_t h) : + m_ws(PointGFp::WORKSPACE_SIZE), + m_order(order) + { + BOTAN_UNUSED(h); + Null_RNG null_rng; + m_point_mul.reset(new PointGFp_Var_Point_Precompute(base, null_rng, m_ws)); + } + +Blinded_Point_Multiply::~Blinded_Point_Multiply() + { + /* for ~unique_ptr */ + } + +PointGFp Blinded_Point_Multiply::blinded_multiply(const BigInt& scalar, + RandomNumberGenerator& rng) + { + return m_point_mul->mul(scalar, rng, m_order, m_ws); + } + +PointGFp_Base_Point_Precompute::PointGFp_Base_Point_Precompute(const PointGFp& base, + const Modular_Reducer& mod_order) : + m_base_point(base), + m_mod_order(mod_order), + m_p_words(base.get_curve().get_p().sig_words()) + { + std::vector ws(PointGFp::WORKSPACE_SIZE); + + const size_t p_bits = base.get_curve().get_p().bits(); + + /* + * Some of the curves (eg secp160k1) have an order slightly larger than + * the size of the prime modulus. In all cases they are at most 1 bit + * longer. The +1 compensates for this. + */ + const size_t T_bits = round_up(p_bits + blinding_size(mod_order.get_modulus()) + 1, WINDOW_BITS) / WINDOW_BITS; + + std::vector T(WINDOW_SIZE*T_bits); + + PointGFp g = base; + PointGFp g2, g4; + + for(size_t i = 0; i != T_bits; i++) + { + g2 = g; + g2.mult2(ws); + g4 = g2; + g4.mult2(ws); + + T[7*i+0] = g; + T[7*i+1] = std::move(g2); + T[7*i+2] = T[7*i+1].plus(T[7*i+0], ws); // g2+g + T[7*i+3] = g4; + T[7*i+4] = T[7*i+3].plus(T[7*i+0], ws); // g4+g + T[7*i+5] = T[7*i+3].plus(T[7*i+1], ws); // g4+g2 + T[7*i+6] = T[7*i+3].plus(T[7*i+2], ws); // g4+g2+g + + g.swap(g4); + g.mult2(ws); + } + + PointGFp::force_all_affine(T, ws[0].get_word_vector()); + + m_W.resize(T.size() * 2 * m_p_words); + + word* p = &m_W[0]; + for(size_t i = 0; i != T.size(); ++i) + { + T[i].get_x().encode_words(p, m_p_words); + p += m_p_words; + T[i].get_y().encode_words(p, m_p_words); + p += m_p_words; + } + } + +PointGFp PointGFp_Base_Point_Precompute::mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector& ws) const + { + if(k.is_negative()) + throw Invalid_Argument("PointGFp_Base_Point_Precompute scalar must be positive"); + + // Instead of reducing k mod group order should we alter the mask size?? + BigInt scalar = m_mod_order.reduce(k); + + if(rng.is_seeded()) + { + // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) + const BigInt mask(rng, blinding_size(group_order)); + scalar += group_order * mask; + } + else + { + /* + When we don't have an RNG we cannot do scalar blinding. Instead use the + same trick as OpenSSL and add one or two copies of the order to normalize + the length of the scalar at order.bits()+1. This at least ensures the loop + bound does not leak information about the high bits of the scalar. + */ + scalar += group_order; + if(scalar.bits() == group_order.bits()) + scalar += group_order; + BOTAN_DEBUG_ASSERT(scalar.bits() == group_order.bits() + 1); + } + + const size_t windows = round_up(scalar.bits(), WINDOW_BITS) / WINDOW_BITS; + + const size_t elem_size = 2*m_p_words; + + BOTAN_ASSERT(windows <= m_W.size() / (3*elem_size), + "Precomputed sufficient values for scalar mult"); + + PointGFp R = m_base_point.zero(); + + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); + + // the precomputed multiples are not secret so use std::vector + std::vector Wt(elem_size); + + for(size_t i = 0; i != windows; ++i) + { + const size_t window = windows - i - 1; + const size_t base_addr = (WINDOW_SIZE*window)*elem_size; + + const word w = scalar.get_substring(WINDOW_BITS*window, WINDOW_BITS); + + const auto w_is_1 = CT::Mask::is_equal(w, 1); + const auto w_is_2 = CT::Mask::is_equal(w, 2); + const auto w_is_3 = CT::Mask::is_equal(w, 3); + const auto w_is_4 = CT::Mask::is_equal(w, 4); + const auto w_is_5 = CT::Mask::is_equal(w, 5); + const auto w_is_6 = CT::Mask::is_equal(w, 6); + const auto w_is_7 = CT::Mask::is_equal(w, 7); + + for(size_t j = 0; j != elem_size; ++j) + { + const word w1 = w_is_1.if_set_return(m_W[base_addr + 0*elem_size + j]); + const word w2 = w_is_2.if_set_return(m_W[base_addr + 1*elem_size + j]); + const word w3 = w_is_3.if_set_return(m_W[base_addr + 2*elem_size + j]); + const word w4 = w_is_4.if_set_return(m_W[base_addr + 3*elem_size + j]); + const word w5 = w_is_5.if_set_return(m_W[base_addr + 4*elem_size + j]); + const word w6 = w_is_6.if_set_return(m_W[base_addr + 5*elem_size + j]); + const word w7 = w_is_7.if_set_return(m_W[base_addr + 6*elem_size + j]); + + Wt[j] = w1 | w2 | w3 | w4 | w5 | w6 | w7; + } + + R.add_affine(&Wt[0], m_p_words, &Wt[m_p_words], m_p_words, ws); + + if(i == 0 && rng.is_seeded()) + { + /* + * Since we start with the top bit of the exponent we know the + * first window must have a non-zero element, and thus R is + * now a point other than the point at infinity. + */ + BOTAN_DEBUG_ASSERT(w != 0); + R.randomize_repr(rng, ws[0].get_word_vector()); + } + } + + BOTAN_DEBUG_ASSERT(R.on_the_curve()); + + return R; + } + +PointGFp_Var_Point_Precompute::PointGFp_Var_Point_Precompute(const PointGFp& point, + RandomNumberGenerator& rng, + std::vector& ws) : + m_curve(point.get_curve()), + m_p_words(m_curve.get_p().sig_words()), + m_window_bits(4) + { + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); + + std::vector U(static_cast(1) << m_window_bits); + U[0] = point.zero(); + U[1] = point; + + for(size_t i = 2; i < U.size(); i += 2) + { + U[i] = U[i/2].double_of(ws); + U[i+1] = U[i].plus(point, ws); + } + + // Hack to handle Blinded_Point_Multiply + if(rng.is_seeded()) + { + BigInt& mask = ws[0]; + BigInt& mask2 = ws[1]; + BigInt& mask3 = ws[2]; + BigInt& new_x = ws[3]; + BigInt& new_y = ws[4]; + BigInt& new_z = ws[5]; + secure_vector& tmp = ws[6].get_word_vector(); + + const CurveGFp& curve = U[0].get_curve(); + + const size_t p_bits = curve.get_p().bits(); + + // Skipping zero point since it can't be randomized + for(size_t i = 1; i != U.size(); ++i) + { + mask.randomize(rng, p_bits - 1, false); + // Easy way of ensuring mask != 0 + mask.set_bit(0); + + curve.sqr(mask2, mask, tmp); + curve.mul(mask3, mask, mask2, tmp); + + curve.mul(new_x, U[i].get_x(), mask2, tmp); + curve.mul(new_y, U[i].get_y(), mask3, tmp); + curve.mul(new_z, U[i].get_z(), mask, tmp); + + U[i].swap_coords(new_x, new_y, new_z); + } + } + + m_T.resize(U.size() * 3 * m_p_words); + + word* p = &m_T[0]; + for(size_t i = 0; i != U.size(); ++i) + { + U[i].get_x().encode_words(p , m_p_words); + U[i].get_y().encode_words(p + m_p_words, m_p_words); + U[i].get_z().encode_words(p + 2*m_p_words, m_p_words); + p += 3*m_p_words; + } + } + +PointGFp PointGFp_Var_Point_Precompute::mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector& ws) const + { + if(k.is_negative()) + throw Invalid_Argument("PointGFp_Var_Point_Precompute scalar must be positive"); + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); + + // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) + const BigInt mask(rng, blinding_size(group_order), false); + const BigInt scalar = k + group_order * mask; + + const size_t elem_size = 3*m_p_words; + const size_t window_elems = (1ULL << m_window_bits); + + size_t windows = round_up(scalar.bits(), m_window_bits) / m_window_bits; + PointGFp R(m_curve); + secure_vector e(elem_size); + + if(windows > 0) + { + windows--; + + const uint32_t w = scalar.get_substring(windows*m_window_bits, m_window_bits); + + clear_mem(e.data(), e.size()); + for(size_t i = 1; i != window_elems; ++i) + { + const auto wmask = CT::Mask::is_equal(w, i); + + for(size_t j = 0; j != elem_size; ++j) + { + e[j] |= wmask.if_set_return(m_T[i * elem_size + j]); + } + } + + R.add(&e[0], m_p_words, &e[m_p_words], m_p_words, &e[2*m_p_words], m_p_words, ws); + + /* + Randomize after adding the first nibble as before the addition R + is zero, and we cannot effectively randomize the point + representation of the zero point. + */ + R.randomize_repr(rng, ws[0].get_word_vector()); + } + + while(windows) + { + R.mult2i(m_window_bits, ws); + + const uint32_t w = scalar.get_substring((windows-1)*m_window_bits, m_window_bits); + + clear_mem(e.data(), e.size()); + for(size_t i = 1; i != window_elems; ++i) + { + const auto wmask = CT::Mask::is_equal(w, i); + + for(size_t j = 0; j != elem_size; ++j) + { + e[j] |= wmask.if_set_return(m_T[i * elem_size + j]); + } + } + + R.add(&e[0], m_p_words, &e[m_p_words], m_p_words, &e[2*m_p_words], m_p_words, ws); + + windows--; + } + + BOTAN_DEBUG_ASSERT(R.on_the_curve()); + + return R; + } + + +PointGFp_Multi_Point_Precompute::PointGFp_Multi_Point_Precompute(const PointGFp& x, + const PointGFp& y) + { + std::vector ws(PointGFp::WORKSPACE_SIZE); + + PointGFp x2 = x; + x2.mult2(ws); + + const PointGFp x3(x2.plus(x, ws)); + + PointGFp y2 = y; + y2.mult2(ws); + + const PointGFp y3(y2.plus(y, ws)); + + m_M.reserve(15); + + m_M.push_back(x); + m_M.push_back(x2); + m_M.push_back(x3); + + m_M.push_back(y); + m_M.push_back(y.plus(x, ws)); + m_M.push_back(y.plus(x2, ws)); + m_M.push_back(y.plus(x3, ws)); + + m_M.push_back(y2); + m_M.push_back(y2.plus(x, ws)); + m_M.push_back(y2.plus(x2, ws)); + m_M.push_back(y2.plus(x3, ws)); + + m_M.push_back(y3); + m_M.push_back(y3.plus(x, ws)); + m_M.push_back(y3.plus(x2, ws)); + m_M.push_back(y3.plus(x3, ws)); + + bool no_infinity = true; + for(auto& pt : m_M) + { + if(pt.is_zero()) + no_infinity = false; + } + + if(no_infinity) + { + PointGFp::force_all_affine(m_M, ws[0].get_word_vector()); + } + + m_no_infinity = no_infinity; + } + +PointGFp PointGFp_Multi_Point_Precompute::multi_exp(const BigInt& z1, + const BigInt& z2) const + { + std::vector ws(PointGFp::WORKSPACE_SIZE); + + const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); + + PointGFp H = m_M[0].zero(); + + for(size_t i = 0; i != z_bits; i += 2) + { + if(i > 0) + { + H.mult2i(2, ws); + } + + const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2); + const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2); + + const uint32_t z12 = (4*z2_b) + z1_b; + + // This function is not intended to be const time + if(z12) + { + if(m_no_infinity) + H.add_affine(m_M[z12-1], ws); + else + H.add(m_M[z12-1], ws); + } + } + + if(z1.is_negative() != z2.is_negative()) + H.negate(); + + return H; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.h b/comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.h new file mode 100644 index 0000000000..0956204289 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ec_group/point_mul.h @@ -0,0 +1,85 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POINT_MUL_H_ +#define BOTAN_POINT_MUL_H_ + +#include + +namespace Botan { + +class Modular_Reducer; + +class PointGFp_Base_Point_Precompute final + { + public: + PointGFp_Base_Point_Precompute(const PointGFp& base_point, + const Modular_Reducer& mod_order); + + PointGFp mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector& ws) const; + private: + const PointGFp& m_base_point; + const Modular_Reducer& m_mod_order; + + enum { WINDOW_BITS = 3 }; + enum { WINDOW_SIZE = (1 << WINDOW_BITS) - 1 }; + + const size_t m_p_words; + + /* + * This is a table of T_size * 3*p_word words + */ + std::vector m_W; + }; + +class PointGFp_Var_Point_Precompute final + { + public: + PointGFp_Var_Point_Precompute(const PointGFp& point, + RandomNumberGenerator& rng, + std::vector& ws); + + PointGFp mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector& ws) const; + private: + const CurveGFp m_curve; + const size_t m_p_words; + const size_t m_window_bits; + + /* + * Table of 2^window_bits * 3*2*p_word words + * Kept in locked vector since the base point might be sensitive + * (normally isn't in most protocols but hard to say anything + * categorically.) + */ + secure_vector m_T; + }; + +class PointGFp_Multi_Point_Precompute final + { + public: + PointGFp_Multi_Point_Precompute(const PointGFp& g1, + const PointGFp& g2); + + /* + * Return (g1*k1 + g2*k2) + * Not constant time, intended to use with public inputs + */ + PointGFp multi_exp(const BigInt& k1, + const BigInt& k2) const; + private: + std::vector m_M; + bool m_no_infinity; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.cpp b/comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.cpp new file mode 100644 index 0000000000..5a97e7a501 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.cpp @@ -0,0 +1,205 @@ +/* +* ECC Key implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +size_t EC_PublicKey::key_length() const + { + return domain().get_p_bits(); + } + +size_t EC_PublicKey::estimated_strength() const + { + return ecp_work_factor(key_length()); + } + +EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point) : + m_domain_params(dom_par), m_public_key(pub_point) + { + if (!dom_par.get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + +#if 0 + if(domain().get_curve() != public_point().get_curve()) + throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); +#endif + } + +EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + m_domain_params{EC_Group(alg_id.get_parameters())}, + m_public_key{domain().OS2ECP(key_bits)} + { + if (!domain().get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + } + +bool EC_PublicKey::check_key(RandomNumberGenerator& rng, + bool) const + { + return m_domain_params.verify_group(rng) && + m_domain_params.verify_public_element(public_point()); + } + + +AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), DER_domain()); + } + +std::vector EC_PublicKey::public_key_bits() const + { + return public_point().encode(point_encoding()); + } + +void EC_PublicKey::set_point_encoding(PointGFp::Compression_Type enc) + { + if(enc != PointGFp::COMPRESSED && + enc != PointGFp::UNCOMPRESSED && + enc != PointGFp::HYBRID) + throw Invalid_Argument("Invalid point encoding for EC_PublicKey"); + + m_point_encoding = enc; + } + +void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) + { + if(form != EC_DOMPAR_ENC_EXPLICIT && + form != EC_DOMPAR_ENC_IMPLICITCA && + form != EC_DOMPAR_ENC_OID) + throw Invalid_Argument("Invalid encoding form for EC-key object specified"); + + if((form == EC_DOMPAR_ENC_OID) && (m_domain_params.get_curve_oid().empty())) + throw Invalid_Argument("Invalid encoding form OID specified for " + "EC-key object whose corresponding domain " + "parameters are without oid"); + + m_domain_encoding = form; + } + +const BigInt& EC_PrivateKey::private_value() const + { + if(m_private_key == 0) + throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); + + return m_private_key; + } + +/** +* EC_PrivateKey constructor +*/ +EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& ec_group, + const BigInt& x, + bool with_modular_inverse) + { + m_domain_params = ec_group; + if (!ec_group.get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + if(x == 0) + { + m_private_key = ec_group.random_scalar(rng); + } + else + { + m_private_key = x; + } + + std::vector ws; + + if(with_modular_inverse) + { + // ECKCDSA + m_public_key = domain().blinded_base_point_multiply( + m_domain_params.inverse_mod_order(m_private_key), rng, ws); + } + else + { + m_public_key = domain().blinded_base_point_multiply(m_private_key, rng, ws); + } + + BOTAN_ASSERT(m_public_key.on_the_curve(), + "Generated public key point was on the curve"); + } + +secure_vector EC_PrivateKey::private_key_bits() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(1)) + .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), OCTET_STRING) + .start_cons(ASN1_Tag(1), PRIVATE) + .encode(m_public_key.encode(PointGFp::Compression_Type::UNCOMPRESSED), BIT_STRING) + .end_cons() + .end_cons() + .get_contents(); + } + +EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + bool with_modular_inverse) + { + m_domain_params = EC_Group(alg_id.get_parameters()); + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + if (!domain().get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + OID key_parameters; + secure_vector public_key_bits; + + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check(1, "Unknown version code for ECC key") + .decode_octet_string_bigint(m_private_key) + .decode_optional(key_parameters, ASN1_Tag(0), PRIVATE) + .decode_optional_string(public_key_bits, BIT_STRING, 1, PRIVATE) + .end_cons(); + + if(public_key_bits.empty()) + { + if(with_modular_inverse) + { + // ECKCDSA + m_public_key = domain().get_base_point() * m_domain_params.inverse_mod_order(m_private_key); + } + else + { + m_public_key = domain().get_base_point() * m_private_key; + } + + BOTAN_ASSERT(m_public_key.on_the_curve(), + "Public point derived from loaded key was on the curve"); + } + else + { + m_public_key = domain().OS2ECP(public_key_bits); + // OS2ECP verifies that the point is on the curve + } + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.h b/comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.h new file mode 100644 index 0000000000..ec2b5f9be3 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecc_key/ecc_key.h @@ -0,0 +1,172 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECC_PUBLIC_KEY_BASE_H_ +#define BOTAN_ECC_PUBLIC_KEY_BASE_H_ + +#include +#include + +namespace Botan { + +/** +* This class represents abstract ECC public keys. When encoding a key +* via an encoder that can be accessed via the corresponding member +* functions, the key will decide upon its internally stored encoding +* information whether to encode itself with or without domain +* parameters, or using the domain parameter oid. Furthermore, a public +* key without domain parameters can be decoded. In that case, it +* cannot be used for verification until its domain parameters are set +* by calling the corresponding member function. +*/ +class BOTAN_PUBLIC_API(2,0) EC_PublicKey : public virtual Public_Key + { + public: + /** + * Create a public key. + * @param dom_par EC domain parameters + * @param pub_point public point on the curve + */ + EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point); + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + EC_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits); + + EC_PublicKey(const EC_PublicKey& other) = default; + EC_PublicKey& operator=(const EC_PublicKey& other) = default; + virtual ~EC_PublicKey() = default; + + /** + * Get the public point of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the public point of this key + */ + const PointGFp& public_point() const { return m_public_key; } + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + bool check_key(RandomNumberGenerator& rng, + bool strong) const override; + + /** + * Get the domain parameters of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the domain parameters of this key + */ + const EC_Group& domain() const { return m_domain_params; } + + /** + * Set the domain parameter encoding to be used when encoding this key. + * @param enc the encoding to use + */ + void set_parameter_encoding(EC_Group_Encoding enc); + + /** + * Set the point encoding method to be used when encoding this key. + * @param enc the encoding to use + */ + void set_point_encoding(PointGFp::Compression_Type enc); + + /** + * Return the DER encoding of this keys domain in whatever format + * is preset for this particular key + */ + std::vector DER_domain() const + { return domain().DER_encode(domain_format()); } + + /** + * Get the domain parameter encoding to be used when encoding this key. + * @result the encoding to use + */ + EC_Group_Encoding domain_format() const + { return m_domain_encoding; } + + /** + * Get the point encoding method to be used when encoding this key. + * @result the encoding to use + */ + PointGFp::Compression_Type point_encoding() const + { return m_point_encoding; } + + size_t key_length() const override; + size_t estimated_strength() const override; + + protected: + EC_PublicKey() : m_domain_params{}, m_public_key{}, m_domain_encoding(EC_DOMPAR_ENC_EXPLICIT) + {} + + EC_Group m_domain_params; + PointGFp m_public_key; + EC_Group_Encoding m_domain_encoding; + PointGFp::Compression_Type m_point_encoding = PointGFp::UNCOMPRESSED; + }; + +/** +* This abstract class represents ECC private keys +*/ +class BOTAN_PUBLIC_API(2,0) EC_PrivateKey : public virtual EC_PublicKey, + public virtual Private_Key + { + public: + /* + * If x=0, creates a new private key in the domain + * using the given rng. If with_modular_inverse is set, + * the public key will be calculated by multiplying + * the base point with the modular inverse of + * x (as in ECGDSA and ECKCDSA), otherwise by + * multiplying directly with x (as in ECDSA). + */ + EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x, + bool with_modular_inverse=false); + + /* + * Creates a new private key object from the + * ECPrivateKey structure given in key_bits. + * If with_modular_inverse is set, + * the public key will be calculated by multiplying + * the base point with the modular inverse of + * x (as in ECGDSA and ECKCDSA), otherwise by + * multiplying directly with x (as in ECDSA). + */ + EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits, + bool with_modular_inverse=false); + + secure_vector private_key_bits() const override; + + /** + * Get the private key value of this key object. + * @result the private key value of this key object + */ + const BigInt& private_value() const; + + EC_PrivateKey(const EC_PrivateKey& other) = default; + EC_PrivateKey& operator=(const EC_PrivateKey& other) = default; + ~EC_PrivateKey() = default; + protected: + EC_PrivateKey() = default; + + BigInt m_private_key; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ecc_key/info.txt b/comm/third_party/botan/src/lib/pubkey/ecc_key/info.txt new file mode 100644 index 0000000000..32d05f2f90 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecc_key/info.txt @@ -0,0 +1,11 @@ + +ECC_PUBLIC_KEY_CRYPTO -> 20131128 +ECC_KEY -> 20190801 + + + +asn1 +bigint +ec_group +numbertheory + diff --git a/comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.cpp b/comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.cpp new file mode 100644 index 0000000000..e7e49a74fd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.cpp @@ -0,0 +1,87 @@ +/* +* ECDH implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +namespace Botan { + +namespace { + +/** +* ECDH operation +*/ +class ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + + ECDH_KA_Operation(const ECDH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : + PK_Ops::Key_Agreement_with_KDF(kdf), + m_group(key.domain()), + m_rng(rng) + { + m_l_times_priv = m_group.inverse_mod_order(m_group.get_cofactor()) * key.private_value(); + } + + size_t agreed_value_size() const override { return m_group.get_p_bytes(); } + + secure_vector raw_agree(const uint8_t w[], size_t w_len) override + { + PointGFp input_point = m_group.get_cofactor() * m_group.OS2ECP(w, w_len); + input_point.randomize_repr(m_rng); + + const PointGFp S = m_group.blinded_var_point_multiply( + input_point, m_l_times_priv, m_rng, m_ws); + + if(S.on_the_curve() == false) + throw Internal_Error("ECDH agreed value was not on the curve"); + return BigInt::encode_1363(S.get_affine_x(), m_group.get_p_bytes()); + } + private: + const EC_Group m_group; + BigInt m_l_times_priv; + RandomNumberGenerator& m_rng; + std::vector m_ws; + }; + +} + +std::unique_ptr +ECDH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_ecdh_ka_op(*this, params); + } + catch(Lookup_Error&) + { + if(provider == "openssl") + throw; + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECDH_KA_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.h b/comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.h new file mode 100644 index 0000000000..f88955ac40 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecdh/ecdh.h @@ -0,0 +1,106 @@ +/* +* ECDH +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECDH_KEY_H_ +#define BOTAN_ECDH_KEY_H_ + +#include + +namespace Botan { + +/** +* This class represents ECDH Public Keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECDH_PublicKey : public virtual EC_PublicKey + { + public: + /** + * Create an ECDH public key. + * @param alg_id algorithm identifier + * @param key_bits DER encoded public key bits + */ + ECDH_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDH_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Get this keys algorithm name. + * @return this keys algorithm name + */ + std::string algo_name() const override { return "ECDH"; } + + /** + * @return public point value + */ + std::vector public_value() const + { return public_point().encode(PointGFp::UNCOMPRESSED); } + + /** + * @return public point value + */ + std::vector public_value(PointGFp::Compression_Type format) const + { return public_point().encode(format); } + + protected: + ECDH_PublicKey() = default; + }; + +/** +* This class represents ECDH Private Keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECDH_PrivateKey final : public ECDH_PublicKey, + public EC_PrivateKey, + public PK_Key_Agreement_Key + { + public: + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + ECDH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + ECDH_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + std::vector public_value() const override + { return ECDH_PublicKey::public_value(PointGFp::UNCOMPRESSED); } + + std::vector public_value(PointGFp::Compression_Type type) const + { return ECDH_PublicKey::public_value(type); } + + std::unique_ptr + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ecdh/info.txt b/comm/third_party/botan/src/lib/pubkey/ecdh/info.txt new file mode 100644 index 0000000000..11ca921dab --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecdh/info.txt @@ -0,0 +1,10 @@ + +ECDH -> 20131128 + + + +asn1 +ec_group +ecc_key +numbertheory + diff --git a/comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.cpp b/comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.cpp new file mode 100644 index 0000000000..ebe9268cc9 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.cpp @@ -0,0 +1,308 @@ +/* +* ECDSA implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010,2015,2016,2018 Jack Lloyd +* 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + #include +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +namespace Botan { + +namespace { + +PointGFp recover_ecdsa_public_key(const EC_Group& group, + const std::vector& msg, + const BigInt& r, + const BigInt& s, + uint8_t v) + { + if(group.get_cofactor() != 1) + throw Invalid_Argument("ECDSA public key recovery only supported for prime order groups"); + + if(v > 4) + throw Invalid_Argument("Unexpected v param for ECDSA public key recovery"); + + const uint8_t y_odd = v % 2; + const uint8_t add_order = v >> 1; + + const BigInt& group_order = group.get_order(); + const size_t p_bytes = group.get_p_bytes(); + + try + { + const BigInt e(msg.data(), msg.size(), group.get_order_bits()); + const BigInt r_inv = group.inverse_mod_order(r); + + BigInt x = r + add_order*group_order; + + std::vector X(p_bytes + 1); + + X[0] = 0x02 | y_odd; + BigInt::encode_1363(&X[1], p_bytes, x); + + const PointGFp R = group.OS2ECP(X); + + if((R*group_order).is_zero() == false) + throw Decoding_Error("Unable to recover ECDSA public key"); + + // Compute r_inv * (s*R - eG) + PointGFp_Multi_Point_Precompute RG_mul(R, group.get_base_point()); + const BigInt ne = group.mod_order(group_order - e); + return r_inv * RG_mul.multi_exp(s, ne); + } + catch(...) + { + // continue on and throw + } + + throw Decoding_Error("Failed to recover ECDSA public key from signature/msg pair"); + } + +} + +ECDSA_PublicKey::ECDSA_PublicKey(const EC_Group& group, + const std::vector& msg, + const BigInt& r, + const BigInt& s, + uint8_t v) : + EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {} + + +uint8_t ECDSA_PublicKey::recovery_param(const std::vector& msg, + const BigInt& r, + const BigInt& s) const + { + for(uint8_t v = 0; v != 4; ++v) + { + try + { + PointGFp R = recover_ecdsa_public_key(this->domain(), msg, r, s, v); + + if(R == this->public_point()) + { + return v; + } + } + catch(Decoding_Error&) + { + // try the next v + } + } + + throw Internal_Error("Could not determine ECDSA recovery parameter"); + } + +bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); + } + +namespace { + +/** +* ECDSA signature operation +*/ +class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + + ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, + const std::string& emsa, + RandomNumberGenerator& rng) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(ecdsa.domain()), + m_x(ecdsa.private_value()) + { +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + m_rfc6979.reset(new RFC6979_Nonce_Generator(hash_for_emsa(emsa), m_group.get_order(), m_x)); +#endif + + m_b = m_group.random_scalar(rng); + m_b_inv = m_group.inverse_mod_order(m_b); + } + + size_t signature_length() const override { return 2*m_group.get_order_bytes(); } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + private: + const EC_Group m_group; + const BigInt& m_x; + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + std::unique_ptr m_rfc6979; +#endif + + std::vector m_ws; + + BigInt m_b, m_b_inv; + }; + +secure_vector +ECDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + BigInt m(msg, msg_len, m_group.get_order_bits()); + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + const BigInt k = m_rfc6979->nonce_for(m); +#else + const BigInt k = m_group.random_scalar(rng); +#endif + + const BigInt r = m_group.mod_order( + m_group.blinded_base_point_multiply_x(k, rng, m_ws)); + + const BigInt k_inv = m_group.inverse_mod_order(k); + + /* + * Blind the input message and compute x*r+m as (x*r*b + m*b)/b + */ + m_b = m_group.square_mod_order(m_b); + m_b_inv = m_group.square_mod_order(m_b_inv); + + m = m_group.multiply_mod_order(m_b, m_group.mod_order(m)); + const BigInt xr_m = m_group.mod_order(m_group.multiply_mod_order(m_x, m_b, r) + m); + + const BigInt s = m_group.multiply_mod_order(k_inv, xr_m, m_b_inv); + + // With overwhelming probability, a bug rather than actual zero r/s + if(r.is_zero() || s.is_zero()) + throw Internal_Error("During ECDSA signature generated zero r/s"); + + return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); + } + +/** +* ECDSA verification operation +*/ +class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(ecdsa.domain()), + m_gy_mul(m_group.get_base_point(), ecdsa.public_point()) + { + } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const EC_Group m_group; + const PointGFp_Multi_Point_Precompute m_gy_mul; + }; + +bool ECDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) + { + if(sig_len != m_group.get_order_bytes() * 2) + return false; + + const BigInt e(msg, msg_len, m_group.get_order_bits()); + + const BigInt r(sig, sig_len / 2); + const BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) + return false; + + const BigInt w = m_group.inverse_mod_order(s); + + const BigInt u1 = m_group.multiply_mod_order(m_group.mod_order(e), w); + const BigInt u2 = m_group.multiply_mod_order(r, w); + const PointGFp R = m_gy_mul.multi_exp(u1, u2); + + if(R.is_zero()) + return false; + + const BigInt v = m_group.mod_order(R.get_affine_x()); + return (v == r); + } + +} + +std::unique_ptr +ECDSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_ecdsa_ver_op(*this, params); + } + catch(Lookup_Error& e) + { + if(provider == "openssl") + throw; + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECDSA_Verification_Operation(*this, params)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_ecdsa_sig_op(*this, params); + } + catch(Lookup_Error& e) + { + if(provider == "openssl") + throw; + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECDSA_Signature_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.h b/comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.h new file mode 100644 index 0000000000..8423a9c205 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecdsa/ecdsa.h @@ -0,0 +1,117 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECDSA_KEY_H_ +#define BOTAN_ECDSA_KEY_H_ + +#include + +namespace Botan { + +/** +* This class represents ECDSA Public Keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Create a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + ECDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Recover a public key from a signature/msg pair + * See SEC section 4.6.1 + * @param group the elliptic curve group + * @param msg the message + * @param r the r paramter of the signature + * @param s the s paramter of the signature + * @param v the recovery ID + */ + ECDSA_PublicKey(const EC_Group& group, + const std::vector& msg, + const BigInt& r, + const BigInt& s, + uint8_t v); + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECDSA") + */ + std::string algo_name() const override { return "ECDSA"; } + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + uint8_t recovery_param(const std::vector& msg, + const BigInt& r, + const BigInt& s) const; + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + protected: + ECDSA_PublicKey() = default; + }; + +/** +* This class represents ECDSA Private Keys +*/ +class BOTAN_PUBLIC_API(2,0) ECDSA_PrivateKey final : public ECDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + ECDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Create a private key. + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a new random key) + */ + ECDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ecdsa/info.txt b/comm/third_party/botan/src/lib/pubkey/ecdsa/info.txt new file mode 100644 index 0000000000..6bd32ca175 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecdsa/info.txt @@ -0,0 +1,14 @@ + +ECDSA -> 20131128 + + + +asn1 +ec_group +ecc_key +keypair +numbertheory +rng +emsa1 +sha2_32 + diff --git a/comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp new file mode 100644 index 0000000000..7ed8763158 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp @@ -0,0 +1,155 @@ +/* +* ECGDSA (BSI-TR-03111, version 2.0) +* (C) 2016 René Korthaus +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); + } + +namespace { + +/** +* ECGDSA signature operation +*/ +class ECGDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + + ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, + const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(ecgdsa.domain()), + m_x(ecgdsa.private_value()) + { + } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + size_t signature_length() const override { return 2*m_group.get_order_bytes(); } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + private: + const EC_Group m_group; + const BigInt& m_x; + std::vector m_ws; + }; + +secure_vector +ECGDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt m(msg, msg_len, m_group.get_order_bits()); + + const BigInt k = m_group.random_scalar(rng); + + const BigInt r = m_group.mod_order( + m_group.blinded_base_point_multiply_x(k, rng, m_ws)); + + const BigInt kr = m_group.multiply_mod_order(k, r); + + const BigInt s = m_group.multiply_mod_order(m_x, kr - m); + + // With overwhelming probability, a bug rather than actual zero r/s + if(r.is_zero() || s.is_zero()) + throw Internal_Error("During ECGDSA signature generated zero r/s"); + + return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); + } + +/** +* ECGDSA verification operation +*/ +class ECGDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + + ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(ecgdsa.domain()), + m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) + { + } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const EC_Group m_group; + const PointGFp_Multi_Point_Precompute m_gy_mul; + }; + +bool ECGDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) + { + if(sig_len != m_group.get_order_bytes() * 2) + return false; + + const BigInt e(msg, msg_len, m_group.get_order_bits()); + + const BigInt r(sig, sig_len / 2); + const BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) + return false; + + const BigInt w = m_group.inverse_mod_order(r); + + const BigInt u1 = m_group.multiply_mod_order(e, w); + const BigInt u2 = m_group.multiply_mod_order(s, w); + const PointGFp R = m_gy_mul.multi_exp(u1, u2); + + if(R.is_zero()) + return false; + + const BigInt v = m_group.mod_order(R.get_affine_x()); + return (v == r); + } + +} + +std::unique_ptr +ECGDSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECGDSA_Verification_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +ECGDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECGDSA_Signature_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.h b/comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.h new file mode 100644 index 0000000000..31d0e2be55 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecgdsa/ecgdsa.h @@ -0,0 +1,96 @@ +/* +* ECGDSA (BSI-TR-03111, version 2.0) +* (C) 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECGDSA_KEY_H_ +#define BOTAN_ECGDSA_KEY_H_ + +#include + +namespace Botan { + +/** +* This class represents ECGDSA public keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECGDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECGDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + ECGDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECGDSA") + */ + std::string algo_name() const override { return "ECGDSA"; } + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + protected: + ECGDSA_PublicKey() = default; + }; + +/** +* This class represents ECGDSA private keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECGDSA_PrivateKey final : public ECGDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + ECGDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits, true) {} + + /** + * Generate a new private key. + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a new random key) + */ + ECGDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x, true) {} + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ecgdsa/info.txt b/comm/third_party/botan/src/lib/pubkey/ecgdsa/info.txt new file mode 100644 index 0000000000..3f967cfcf9 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecgdsa/info.txt @@ -0,0 +1,15 @@ + +ECGDSA -> 20160301 + + + +asn1 +bigint +ec_group +ecc_key +keypair +numbertheory +rng +emsa1 +sha2_32 + diff --git a/comm/third_party/botan/src/lib/pubkey/ecies/ecies.cpp b/comm/third_party/botan/src/lib/pubkey/ecies/ecies.cpp new file mode 100644 index 0000000000..a8c277b3aa --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecies/ecies.cpp @@ -0,0 +1,415 @@ +/* +* ECIES +* (C) 2016 Philipp Weber +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/** +* Private key type for ECIES_ECDH_KA_Operation +*/ +class ECIES_PrivateKey final : public EC_PrivateKey, public PK_Key_Agreement_Key + { + public: + explicit ECIES_PrivateKey(const ECDH_PrivateKey& private_key) : + EC_PublicKey(private_key), + EC_PrivateKey(private_key), + PK_Key_Agreement_Key(), + m_key(private_key) + { + } + + std::vector public_value() const override + { + return m_key.public_value(); + } + + std::string algo_name() const override + { + return "ECIES"; + } + + std::unique_ptr + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + private: + ECDH_PrivateKey m_key; + }; + +/** +* Implements ECDH key agreement without using the cofactor mode +*/ +class ECIES_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + ECIES_ECDH_KA_Operation(const ECIES_PrivateKey& private_key, RandomNumberGenerator& rng) : + PK_Ops::Key_Agreement_with_KDF("Raw"), + m_key(private_key), + m_rng(rng) + { + } + + size_t agreed_value_size() const override { return m_key.domain().get_p_bytes(); } + + secure_vector raw_agree(const uint8_t w[], size_t w_len) override + { + const EC_Group& group = m_key.domain(); + + PointGFp input_point = group.OS2ECP(w, w_len); + input_point.randomize_repr(m_rng); + + const PointGFp S = group.blinded_var_point_multiply( + input_point, m_key.private_value(), m_rng, m_ws); + + if(S.on_the_curve() == false) + throw Internal_Error("ECDH agreed value was not on the curve"); + return BigInt::encode_1363(S.get_affine_x(), group.get_p_bytes()); + } + + private: + ECIES_PrivateKey m_key; + RandomNumberGenerator& m_rng; + std::vector m_ws; + }; + +std::unique_ptr +ECIES_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + return std::unique_ptr(new ECIES_ECDH_KA_Operation(*this, rng)); + } + +/** +* Creates a PK_Key_Agreement instance for the given key and ecies_params +* Returns either ECIES_ECDH_KA_Operation or the default implementation for the given key, +* depending on the key and ecies_params +* @param private_key the private key used for the key agreement +* @param ecies_params settings for ecies +* @param for_encryption disable cofactor mode if the secret will be used for encryption +* (according to ISO 18033 cofactor mode is only used during decryption) +*/ +PK_Key_Agreement create_key_agreement(const PK_Key_Agreement_Key& private_key, + const ECIES_KA_Params& ecies_params, + bool for_encryption, + RandomNumberGenerator& rng) + { + const ECDH_PrivateKey* ecdh_key = dynamic_cast(&private_key); + + if(ecdh_key == nullptr && (ecies_params.cofactor_mode() || ecies_params.old_cofactor_mode() + || ecies_params.check_mode())) + { + // assume we have a private key from an external provider (e.g. pkcs#11): + // there is no way to determine or control whether the provider uses cofactor mode or not. + // ISO 18033 does not allow cofactor mode in combination with old cofactor mode or check mode + // => disable cofactor mode, old cofactor mode and check mode for unknown keys/providers (as a precaution). + throw Invalid_Argument("ECIES: cofactor, old cofactor and check mode are only supported for ECDH_PrivateKey"); + } + + if(ecdh_key && (for_encryption || !ecies_params.cofactor_mode())) + { + // ECDH_KA_Operation uses cofactor mode: use own key agreement method if cofactor should not be used. + return PK_Key_Agreement(ECIES_PrivateKey(*ecdh_key), rng, "Raw"); + } + + return PK_Key_Agreement(private_key, rng, "Raw"); // use default implementation + } +} + +ECIES_KA_Operation::ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, + const ECIES_KA_Params& ecies_params, + bool for_encryption, + RandomNumberGenerator& rng) : + m_ka(create_key_agreement(private_key, ecies_params, for_encryption, rng)), + m_params(ecies_params) + { + } + +/** +* ECIES secret derivation according to ISO 18033-2 +*/ +SymmetricKey ECIES_KA_Operation::derive_secret(const std::vector& eph_public_key_bin, + const PointGFp& other_public_key_point) const + { + if(other_public_key_point.is_zero()) + { + throw Invalid_Argument("ECIES: other public key point is zero"); + } + + std::unique_ptr kdf = Botan::KDF::create_or_throw(m_params.kdf_spec()); + + PointGFp other_point = other_public_key_point; + + // ISO 18033: step b + if(m_params.old_cofactor_mode()) + { + other_point *= m_params.domain().get_cofactor(); + } + + secure_vector derivation_input; + + // ISO 18033: encryption step e / decryption step g + if(!m_params.single_hash_mode()) + { + derivation_input += eph_public_key_bin; + } + + // ISO 18033: encryption step f / decryption step h + std::vector other_public_key_bin = other_point.encode(m_params.compression_type()); + // Note: the argument `m_params.secret_length()` passed for `key_len` will only be used by providers because + // "Raw" is passed to the `PK_Key_Agreement` if the implementation of botan is used. + const SymmetricKey peh = m_ka.derive_key(m_params.domain().get_order().bytes(), other_public_key_bin.data(), other_public_key_bin.size()); + derivation_input.insert(derivation_input.end(), peh.begin(), peh.end()); + + // ISO 18033: encryption step g / decryption step i + return kdf->derive_key(m_params.secret_length(), derivation_input); + } + + +ECIES_KA_Params::ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length, + PointGFp::Compression_Type compression_type, ECIES_Flags flags) : + m_domain(domain), + m_kdf_spec(kdf_spec), + m_length(length), + m_compression_mode(compression_type), + m_flags(flags) + { + } + +ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, + const std::string& dem_algo_spec, size_t dem_key_len, + const std::string& mac_spec, size_t mac_key_len, + PointGFp::Compression_Type compression_type, ECIES_Flags flags) : + ECIES_KA_Params(domain, kdf_spec, dem_key_len + mac_key_len, compression_type, flags), + m_dem_spec(dem_algo_spec), + m_dem_keylen(dem_key_len), + m_mac_spec(mac_spec), + m_mac_keylen(mac_key_len) + { + // ISO 18033: "At most one of CofactorMode, OldCofactorMode, and CheckMode may be 1." + if(size_t(cofactor_mode()) + size_t(old_cofactor_mode()) + size_t(check_mode()) > 1) + { + throw Invalid_Argument("ECIES: only one of cofactor_mode, old_cofactor_mode and check_mode can be set"); + } + } + +ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, + const std::string& dem_algo_spec, size_t dem_key_len, + const std::string& mac_spec, size_t mac_key_len) : + ECIES_System_Params(domain, kdf_spec, dem_algo_spec, dem_key_len, mac_spec, mac_key_len, PointGFp::UNCOMPRESSED, + ECIES_Flags::NONE) + { + } + +std::unique_ptr ECIES_System_Params::create_mac() const + { + return Botan::MessageAuthenticationCode::create_or_throw(m_mac_spec); + } + +std::unique_ptr ECIES_System_Params::create_cipher(Botan::Cipher_Dir direction) const + { + return Cipher_Mode::create_or_throw(m_dem_spec, direction); + } + + +/* +* ECIES_Encryptor Constructor +*/ +ECIES_Encryptor::ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, + const ECIES_System_Params& ecies_params, + RandomNumberGenerator& rng) : + m_ka(private_key, ecies_params, true, rng), + m_params(ecies_params), + m_eph_public_key_bin(private_key.public_value()), // returns the uncompressed public key, see conversion below + m_iv(), + m_other_point(), + m_label() + { + if(ecies_params.compression_type() != PointGFp::UNCOMPRESSED) + { + // ISO 18033: step d + // convert only if necessary; m_eph_public_key_bin has been initialized with the uncompressed format + m_eph_public_key_bin = m_params.domain().OS2ECP(m_eph_public_key_bin).encode(ecies_params.compression_type()); + } + m_mac = m_params.create_mac(); + m_cipher = m_params.create_cipher(ENCRYPTION); + } + +/* +* ECIES_Encryptor Constructor +*/ +ECIES_Encryptor::ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params) : + ECIES_Encryptor(ECDH_PrivateKey(rng, ecies_params.domain()), ecies_params, rng) + { + } + +size_t ECIES_Encryptor::maximum_input_size() const + { + /* + ECIES should just be used for key transport so this (arbitrary) limit + seems sufficient + */ + return 64; + } + +size_t ECIES_Encryptor::ciphertext_length(size_t ptext_len) const + { + return m_eph_public_key_bin.size() + + m_mac->output_length() + + m_cipher->output_length(ptext_len); + } + +/* +* ECIES Encryption according to ISO 18033-2 +*/ +std::vector ECIES_Encryptor::enc(const uint8_t data[], size_t length, RandomNumberGenerator&) const + { + if(m_other_point.is_zero()) + { + throw Invalid_State("ECIES: the other key is zero"); + } + + const SymmetricKey secret_key = m_ka.derive_secret(m_eph_public_key_bin, m_other_point); + + // encryption + + m_cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen())); + if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) + throw Invalid_Argument("ECIES with " + m_cipher->name() + " requires an IV be set"); + + m_cipher->start(m_iv.bits_of()); + + secure_vector encrypted_data(data, data + length); + m_cipher->finish(encrypted_data); + + // concat elements + + std::vector out(m_eph_public_key_bin.size() + encrypted_data.size() + m_mac->output_length()); + buffer_insert(out, 0, m_eph_public_key_bin); + buffer_insert(out, m_eph_public_key_bin.size(), encrypted_data); + + // mac + m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen()); + m_mac->update(encrypted_data); + if(!m_label.empty()) + { + m_mac->update(m_label); + } + m_mac->final(out.data() + m_eph_public_key_bin.size() + encrypted_data.size()); + + return out; + } + + +ECIES_Decryptor::ECIES_Decryptor(const PK_Key_Agreement_Key& key, + const ECIES_System_Params& ecies_params, + RandomNumberGenerator& rng) : + m_ka(key, ecies_params, false, rng), + m_params(ecies_params), + m_iv(), + m_label() + { + // ISO 18033: "If v > 1 and CheckMode = 0, then we must have gcd(u, v) = 1." (v = index, u= order) + if(!ecies_params.check_mode()) + { + const Botan::BigInt& cofactor = m_params.domain().get_cofactor(); + if(cofactor > 1 && Botan::gcd(cofactor, m_params.domain().get_order()) != 1) + { + throw Invalid_Argument("ECIES: gcd of cofactor and order must be 1 if check_mode is 0"); + } + } + + m_mac = m_params.create_mac(); + m_cipher = m_params.create_cipher(DECRYPTION); + } + +size_t ECIES_Decryptor::plaintext_length(size_t ctext_len) const + { + const size_t point_size = m_params.domain().point_size(m_params.compression_type()); + const size_t overhead = point_size + m_mac->output_length(); + + if(ctext_len < overhead) + return 0; + + return m_cipher->output_length(ctext_len - overhead); + } + +/** +* ECIES Decryption according to ISO 18033-2 +*/ +secure_vector ECIES_Decryptor::do_decrypt(uint8_t& valid_mask, const uint8_t in[], size_t in_len) const + { + const size_t point_size = m_params.domain().point_size(m_params.compression_type()); + + if(in_len < point_size + m_mac->output_length()) + { + throw Decoding_Error("ECIES decryption: ciphertext is too short"); + } + + // extract data + const std::vector other_public_key_bin(in, in + point_size); // the received (ephemeral) public key + const std::vector encrypted_data(in + point_size, in + in_len - m_mac->output_length()); + const std::vector mac_data(in + in_len - m_mac->output_length(), in + in_len); + + // ISO 18033: step a + PointGFp other_public_key = m_params.domain().OS2ECP(other_public_key_bin); + + // ISO 18033: step b + if(m_params.check_mode() && !other_public_key.on_the_curve()) + { + throw Decoding_Error("ECIES decryption: received public key is not on the curve"); + } + + // ISO 18033: step e (and step f because get_affine_x (called by ECDH_KA_Operation::raw_agree) + // throws Illegal_Transformation if the point is zero) + const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key); + + // validate mac + m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen()); + m_mac->update(encrypted_data); + if(!m_label.empty()) + { + m_mac->update(m_label); + } + const secure_vector calculated_mac = m_mac->final(); + valid_mask = ct_compare_u8(mac_data.data(), calculated_mac.data(), mac_data.size()); + + if(valid_mask) + { + // decrypt data + + m_cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen())); + if(m_iv.size() == 0 && !m_cipher->valid_nonce_length(m_iv.size())) + throw Invalid_Argument("ECIES with " + m_cipher->name() + " requires an IV be set"); + m_cipher->start(m_iv.bits_of()); + + try + { + // the decryption can fail: + // e.g. Invalid_Authentication_Tag is thrown if GCM is used and the message does not have a valid tag + secure_vector decrypted_data(encrypted_data.begin(), encrypted_data.end()); + m_cipher->finish(decrypted_data); + return decrypted_data; + } + catch(...) + { + valid_mask = 0; + } + } + return secure_vector(); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ecies/ecies.h b/comm/third_party/botan/src/lib/pubkey/ecies/ecies.h new file mode 100644 index 0000000000..1b35c8cc79 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecies/ecies.h @@ -0,0 +1,314 @@ +/* +* ECIES +* (C) 2016 Philipp Weber +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECIES_H_ +#define BOTAN_ECIES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +enum class ECIES_Flags : uint32_t + { + NONE = 0, + + /// if set: prefix the input of the (ecdh) key agreement with the encoded (ephemeral) public key + SINGLE_HASH_MODE = 1, + + /// (decryption only) if set: use cofactor multiplication during (ecdh) key agreement + COFACTOR_MODE = 2, + + /// if set: use ecdhc instead of ecdh + OLD_COFACTOR_MODE = 4, + + /// (decryption only) if set: test if the (ephemeral) public key is on the curve + CHECK_MODE = 8 + }; + +inline ECIES_Flags operator |(ECIES_Flags a, ECIES_Flags b) + { + return static_cast(static_cast(a) | static_cast(b)); + } + +inline ECIES_Flags operator &(ECIES_Flags a, ECIES_Flags b) + { + return static_cast(static_cast(a) & static_cast(b)); + } + +/** +* Parameters for ECIES secret derivation +*/ +class BOTAN_PUBLIC_API(2,0) ECIES_KA_Params + { + public: + /** + * @param domain ec domain parameters of the involved ec keys + * @param kdf_spec name of the key derivation function + * @param length length of the secret to be derived + * @param compression_type format of encoded keys (affects the secret derivation if single_hash_mode is used) + * @param flags options, see documentation of ECIES_Flags + */ + ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length, + PointGFp::Compression_Type compression_type, ECIES_Flags flags); + + ECIES_KA_Params(const ECIES_KA_Params&) = default; + ECIES_KA_Params& operator=(const ECIES_KA_Params&) = delete; + + virtual ~ECIES_KA_Params() = default; + + inline const EC_Group& domain() const + { + return m_domain; + } + + inline size_t secret_length() const + { + return m_length; + } + + inline bool single_hash_mode() const + { + return (m_flags & ECIES_Flags::SINGLE_HASH_MODE) == ECIES_Flags::SINGLE_HASH_MODE; + } + + inline bool cofactor_mode() const + { + return (m_flags & ECIES_Flags::COFACTOR_MODE) == ECIES_Flags::COFACTOR_MODE; + } + + inline bool old_cofactor_mode() const + { + return (m_flags & ECIES_Flags::OLD_COFACTOR_MODE) == ECIES_Flags::OLD_COFACTOR_MODE; + } + + inline bool check_mode() const + { + return (m_flags & ECIES_Flags::CHECK_MODE) == ECIES_Flags::CHECK_MODE; + } + + inline PointGFp::Compression_Type compression_type() const + { + return m_compression_mode; + } + + const std::string& kdf_spec() const + { + return m_kdf_spec; + } + + private: + const EC_Group m_domain; + const std::string m_kdf_spec; + const size_t m_length; + const PointGFp::Compression_Type m_compression_mode; + const ECIES_Flags m_flags; + }; + + +class BOTAN_PUBLIC_API(2,0) ECIES_System_Params final : public ECIES_KA_Params + { + public: + /** + * @param domain ec domain parameters of the involved ec keys + * @param kdf_spec name of the key derivation function + * @param dem_algo_spec name of the data encryption method + * @param dem_key_len length of the key used for the data encryption method + * @param mac_spec name of the message authentication code + * @param mac_key_len length of the key used for the message authentication code + */ + ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec, + size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len); + + /** + * @param domain ec domain parameters of the involved ec keys + * @param kdf_spec name of the key derivation function + * @param dem_algo_spec name of the data encryption method + * @param dem_key_len length of the key used for the data encryption method + * @param mac_spec name of the message authentication code + * @param mac_key_len length of the key used for the message authentication code + * @param compression_type format of encoded keys (affects the secret derivation if single_hash_mode is used) + * @param flags options, see documentation of ECIES_Flags + */ + ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec, + size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len, + PointGFp::Compression_Type compression_type, ECIES_Flags flags); + + ECIES_System_Params(const ECIES_System_Params&) = default; + ECIES_System_Params& operator=(const ECIES_System_Params&) = delete; + virtual ~ECIES_System_Params() = default; + + /// creates an instance of the message authentication code + std::unique_ptr create_mac() const; + + /// creates an instance of the data encryption method + std::unique_ptr create_cipher(Botan::Cipher_Dir direction) const; + + /// returns the length of the key used by the data encryption method + inline size_t dem_keylen() const + { + return m_dem_keylen; + } + + /// returns the length of the key used by the message authentication code + inline size_t mac_keylen() const + { + return m_mac_keylen; + } + + private: + const std::string m_dem_spec; + const size_t m_dem_keylen; + const std::string m_mac_spec; + const size_t m_mac_keylen; + }; + + +/** +* ECIES secret derivation according to ISO 18033-2 +*/ +class BOTAN_PUBLIC_API(2,0) ECIES_KA_Operation + { + public: + /** + * @param private_key the (ephemeral) private key which is used to derive the secret + * @param ecies_params settings for ecies + * @param for_encryption disable cofactor mode if the secret will be used for encryption + * (according to ISO 18033 cofactor mode is only used during decryption) + * @param rng the RNG to use + */ + ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, + const ECIES_KA_Params& ecies_params, + bool for_encryption, + RandomNumberGenerator& rng); + + /** + * Performs a key agreement with the provided keys and derives the secret from the result + * @param eph_public_key_bin the encoded (ephemeral) public key which belongs to the used (ephemeral) private key + * @param other_public_key_point public key point of the other party + */ + SymmetricKey derive_secret(const std::vector& eph_public_key_bin, + const PointGFp& other_public_key_point) const; + + private: + const PK_Key_Agreement m_ka; + const ECIES_KA_Params m_params; + }; + + +/** +* ECIES Encryption according to ISO 18033-2 +*/ +class BOTAN_PUBLIC_API(2,0) ECIES_Encryptor final : public PK_Encryptor + { + public: + /** + * @param private_key the (ephemeral) private key which is used for the key agreement + * @param ecies_params settings for ecies + * @param rng random generator to use + */ + ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, + const ECIES_System_Params& ecies_params, + RandomNumberGenerator& rng); + + /** + * Creates an ephemeral private key which is used for the key agreement + * @param rng random generator used during private key generation + * @param ecies_params settings for ecies + */ + ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params); + + /// Set the public key of the other party + inline void set_other_key(const Botan::PointGFp& public_point) + { + m_other_point = public_point; + } + + /// Set the initialization vector for the data encryption method + inline void set_initialization_vector(const InitializationVector& iv) + { + m_iv = iv; + } + + /// Set the label which is appended to the input for the message authentication code + inline void set_label(const std::string& label) + { + m_label = std::vector(label.begin(), label.end()); + } + + private: + std::vector enc(const uint8_t data[], size_t length, RandomNumberGenerator&) const override; + + size_t maximum_input_size() const override; + + size_t ciphertext_length(size_t ptext_len) const override; + + const ECIES_KA_Operation m_ka; + const ECIES_System_Params m_params; + std::unique_ptr m_mac; + std::unique_ptr m_cipher; + std::vector m_eph_public_key_bin; + InitializationVector m_iv; + PointGFp m_other_point; + std::vector m_label; + }; + + +/** +* ECIES Decryption according to ISO 18033-2 +*/ +class BOTAN_PUBLIC_API(2,0) ECIES_Decryptor final : public PK_Decryptor + { + public: + /** + * @param private_key the private key which is used for the key agreement + * @param ecies_params settings for ecies + * @param rng the random generator to use + */ + ECIES_Decryptor(const PK_Key_Agreement_Key& private_key, + const ECIES_System_Params& ecies_params, + RandomNumberGenerator& rng); + + /// Set the initialization vector for the data encryption method + inline void set_initialization_vector(const InitializationVector& iv) + { + m_iv = iv; + } + + /// Set the label which is appended to the input for the message authentication code + inline void set_label(const std::string& label) + { + m_label = std::vector(label.begin(), label.end()); + } + + private: + secure_vector do_decrypt(uint8_t& valid_mask, const uint8_t in[], size_t in_len) const override; + + size_t plaintext_length(size_t ctext_len) const override; + + const ECIES_KA_Operation m_ka; + const ECIES_System_Params m_params; + std::unique_ptr m_mac; + std::unique_ptr m_cipher; + InitializationVector m_iv; + std::vector m_label; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ecies/info.txt b/comm/third_party/botan/src/lib/pubkey/ecies/info.txt new file mode 100644 index 0000000000..530cc3970f --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ecies/info.txt @@ -0,0 +1,10 @@ + +ECIES -> 20160128 + + + +kdf +mac +ecdh +modes + diff --git a/comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp b/comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp new file mode 100644 index 0000000000..40d9425143 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp @@ -0,0 +1,208 @@ +/* +* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009) +* (C) 2016 René Korthaus, Sirrix AG +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + { + return false; + } + + if(!strong) + { + return true; + } + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); + } + +namespace { + +/** +* ECKCDSA signature operation +*/ +class ECKCDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + + ECKCDSA_Signature_Operation(const ECKCDSA_PrivateKey& eckcdsa, + const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(eckcdsa.domain()), + m_x(eckcdsa.private_value()), + m_prefix() + { + const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); + const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); + + m_prefix.resize(public_point_x.bytes() + public_point_y.bytes()); + public_point_x.binary_encode(m_prefix.data()); + public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]); + m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits + } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + size_t signature_length() const override { return 2*m_group.get_order_bytes(); } + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + bool has_prefix() override { return true; } + secure_vector message_prefix() const override { return m_prefix; } + + private: + const EC_Group m_group; + const BigInt& m_x; + secure_vector m_prefix; + std::vector m_ws; + }; + +secure_vector +ECKCDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t, + RandomNumberGenerator& rng) + { + const BigInt k = m_group.random_scalar(rng); + const BigInt k_times_P_x = m_group.blinded_base_point_multiply_x(k, rng, m_ws); + + secure_vector to_be_hashed(k_times_P_x.bytes()); + k_times_P_x.binary_encode(to_be_hashed.data()); + + std::unique_ptr emsa = this->clone_emsa(); + emsa->update(to_be_hashed.data(), to_be_hashed.size()); + secure_vector c = emsa->raw_data(); + c = emsa->encoding_of(c, max_input_bits(), rng); + + const BigInt r(c.data(), c.size()); + + xor_buf(c, msg, c.size()); + BigInt w(c.data(), c.size()); + w = m_group.mod_order(w); + + const BigInt s = m_group.multiply_mod_order(m_x, k - w); + if(s.is_zero()) + throw Internal_Error("During ECKCDSA signature generation created zero s"); + + secure_vector output = BigInt::encode_1363(r, c.size()); + output += BigInt::encode_1363(s, m_group.get_order_bytes()); + return output; + } + +/** +* ECKCDSA verification operation +*/ +class ECKCDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + + ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(eckcdsa.domain()), + m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()), + m_prefix() + { + const BigInt public_point_x = eckcdsa.public_point().get_affine_x(); + const BigInt public_point_y = eckcdsa.public_point().get_affine_y(); + + m_prefix.resize(public_point_x.bytes() + public_point_y.bytes()); + public_point_x.binary_encode(&m_prefix[0]); + public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]); + m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits + } + + bool has_prefix() override { return true; } + secure_vector message_prefix() const override { return m_prefix; } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const EC_Group m_group; + const PointGFp_Multi_Point_Precompute m_gy_mul; + secure_vector m_prefix; + }; + +bool ECKCDSA_Verification_Operation::verify(const uint8_t msg[], size_t, + const uint8_t sig[], size_t sig_len) + { + const std::unique_ptr hash = HashFunction::create(hash_for_signature()); + //calculate size of r + + const size_t order_bytes = m_group.get_order_bytes(); + + const size_t size_r = std::min(hash -> output_length(), order_bytes); + if(sig_len != size_r + order_bytes) + { + return false; + } + + secure_vector r(sig, sig + size_r); + + // check that 0 < s < q + const BigInt s(sig + size_r, order_bytes); + + if(s <= 0 || s >= m_group.get_order()) + { + return false; + } + + secure_vector r_xor_e(r); + xor_buf(r_xor_e, msg, r.size()); + BigInt w(r_xor_e.data(), r_xor_e.size()); + w = m_group.mod_order(w); + + const PointGFp q = m_gy_mul.multi_exp(w, s); + const BigInt q_x = q.get_affine_x(); + secure_vector c(q_x.bytes()); + q_x.binary_encode(c.data()); + std::unique_ptr emsa = this->clone_emsa(); + emsa->update(c.data(), c.size()); + secure_vector v = emsa->raw_data(); + Null_RNG rng; + v = emsa->encoding_of(v, max_input_bits(), rng); + + return (v == r); + } + +} + +std::unique_ptr +ECKCDSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECKCDSA_Verification_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +ECKCDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ECKCDSA_Signature_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.h b/comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.h new file mode 100644 index 0000000000..aa04cb146d --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/eckcdsa/eckcdsa.h @@ -0,0 +1,96 @@ +/* +* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009) +* (C) 2016 René Korthaus, Sirrix AG +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECKCDSA_KEY_H_ +#define BOTAN_ECKCDSA_KEY_H_ + +#include + +namespace Botan { + +/** +* This class represents ECKCDSA public keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECKCDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECKCDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + ECKCDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECGDSA") + */ + std::string algo_name() const override { return "ECKCDSA"; } + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + protected: + ECKCDSA_PublicKey() = default; + }; + +/** +* This class represents ECKCDSA private keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECKCDSA_PrivateKey final : public ECKCDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + ECKCDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits, true) {} + + /** + * Create a private key. + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a new random key) + */ + ECKCDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x, true) {} + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/eckcdsa/info.txt b/comm/third_party/botan/src/lib/pubkey/eckcdsa/info.txt new file mode 100644 index 0000000000..2bce4aa79b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/eckcdsa/info.txt @@ -0,0 +1,17 @@ + +ECKCDSA -> 20160413 + + + +asn1 +bigint +ec_group +ecc_key +emsa1 +hash +keypair +numbertheory +pk_pad +rng +sha2_32 + diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.cpp b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.cpp new file mode 100644 index 0000000000..624f82657a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.cpp @@ -0,0 +1,102 @@ +/* +* Ed25519 +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +void ed25519_gen_keypair(uint8_t* pk, uint8_t* sk, const uint8_t seed[32]) + { + uint8_t az[64]; + + SHA_512 sha; + sha.update(seed, 32); + sha.final(az); + az[0] &= 248; + az[31] &= 63; + az[31] |= 64; + + ge_scalarmult_base(pk, az); + + // todo copy_mem + copy_mem(sk, seed, 32); + copy_mem(sk + 32, pk, 32); + } + +void ed25519_sign(uint8_t sig[64], + const uint8_t m[], size_t mlen, + const uint8_t sk[64], + const uint8_t domain_sep[], size_t domain_sep_len) + { + uint8_t az[64]; + uint8_t nonce[64]; + uint8_t hram[64]; + + SHA_512 sha; + + sha.update(sk, 32); + sha.final(az); + az[0] &= 248; + az[31] &= 63; + az[31] |= 64; + + sha.update(domain_sep, domain_sep_len); + sha.update(az + 32, 32); + sha.update(m, mlen); + sha.final(nonce); + + sc_reduce(nonce); + ge_scalarmult_base(sig, nonce); + + sha.update(domain_sep, domain_sep_len); + sha.update(sig, 32); + sha.update(sk + 32, 32); + sha.update(m, mlen); + sha.final(hram); + + sc_reduce(hram); + sc_muladd(sig + 32, hram, az, nonce); + } + +bool ed25519_verify(const uint8_t* m, size_t mlen, + const uint8_t sig[64], + const uint8_t* pk, + const uint8_t domain_sep[], size_t domain_sep_len) + { + uint8_t h[64]; + uint8_t rcheck[32]; + ge_p3 A; + SHA_512 sha; + + if(sig[63] & 224) + { + return false; + } + if(ge_frombytes_negate_vartime(&A, pk) != 0) + { + return false; + } + + sha.update(domain_sep, domain_sep_len); + sha.update(sig, 32); + sha.update(pk, 32); + sha.update(m, mlen); + sha.final(h); + sc_reduce(h); + + ge_double_scalarmult_vartime(rcheck, h, &A, sig + 32); + + return constant_time_compare(rcheck, sig, 32); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.h b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.h new file mode 100644 index 0000000000..97ed023f27 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519.h @@ -0,0 +1,113 @@ +/* +* Ed25519 +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ED25519_H_ +#define BOTAN_ED25519_H_ + +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,2) Ed25519_PublicKey : public virtual Public_Key + { + public: + std::string algo_name() const override { return "Ed25519"; } + + size_t estimated_strength() const override { return 128; } + + size_t key_length() const override { return 255; } + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + /** + * Create a Ed25519 Public Key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + Ed25519_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits); + + template + Ed25519_PublicKey(const std::vector& pub) : + Ed25519_PublicKey(pub.data(), pub.size()) {} + + Ed25519_PublicKey(const uint8_t pub_key[], size_t len); + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + + const std::vector& get_public_key() const { return m_public; } + + protected: + Ed25519_PublicKey() = default; + std::vector m_public; + }; + +class BOTAN_PUBLIC_API(2,2) Ed25519_PrivateKey final : public Ed25519_PublicKey, + public virtual Private_Key + { + public: + /** + * Construct a private key from the specified parameters. + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + Ed25519_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Generate a private key. + * @param rng the RNG to use + */ + explicit Ed25519_PrivateKey(RandomNumberGenerator& rng); + + /** + * Construct a private key from the specified parameters. + * @param secret_key the private key + */ + explicit Ed25519_PrivateKey(const secure_vector& secret_key); + + const secure_vector& get_private_key() const { return m_private; } + + secure_vector private_key_bits() const override; + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + private: + secure_vector m_private; + }; + +void ed25519_gen_keypair(uint8_t pk[32], uint8_t sk[64], const uint8_t seed[32]); + +void ed25519_sign(uint8_t sig[64], + const uint8_t msg[], + size_t msg_len, + const uint8_t sk[64], + const uint8_t domain_sep[], size_t domain_sep_len); + +bool ed25519_verify(const uint8_t msg[], + size_t msg_len, + const uint8_t sig[64], + const uint8_t pk[32], + const uint8_t domain_sep[], size_t domain_sep_len); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.cpp b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.cpp new file mode 100644 index 0000000000..135813d393 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.cpp @@ -0,0 +1,754 @@ +/* +* Ed25519 field element +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +//static +FE_25519 FE_25519::invert(const FE_25519& z) + { + fe t0; + fe t1; + fe t2; + fe t3; + + fe_sq(t0, z); + fe_sq_iter(t1, t0, 2); + fe_mul(t1, z, t1); + fe_mul(t0, t0, t1); + fe_sq(t2, t0); + fe_mul(t1, t1, t2); + fe_sq_iter(t2, t1, 5); + fe_mul(t1, t2, t1); + fe_sq_iter(t2, t1, 10); + fe_mul(t2, t2, t1); + fe_sq_iter(t3, t2, 20); + fe_mul(t2, t3, t2); + fe_sq_iter(t2, t2, 10); + fe_mul(t1, t2, t1); + fe_sq_iter(t2, t1, 50); + fe_mul(t2, t2, t1); + fe_sq_iter(t3, t2, 100); + fe_mul(t2, t3, t2); + fe_sq_iter(t2, t2, 50); + fe_mul(t1, t2, t1); + fe_sq_iter(t1, t1, 5); + + fe_mul(t0, t1, t0); + return t0; + } + +FE_25519 FE_25519::pow_22523(const fe& z) + { + fe t0; + fe t1; + fe t2; + + fe_sq(t0, z); + fe_sq_iter(t1, t0, 2); + fe_mul(t1, z, t1); + fe_mul(t0, t0, t1); + fe_sq(t0, t0); + fe_mul(t0, t1, t0); + fe_sq_iter(t1, t0, 5); + fe_mul(t0, t1, t0); + fe_sq_iter(t1, t0, 10); + fe_mul(t1, t1, t0); + fe_sq_iter(t2, t1, 20); + fe_mul(t1, t2, t1); + fe_sq_iter(t1, t1, 10); + fe_mul(t0, t1, t0); + fe_sq_iter(t1, t0, 50); + fe_mul(t1, t1, t0); + fe_sq_iter(t2, t1, 100); + fe_mul(t1, t2, t1); + fe_sq_iter(t1, t1, 50); + fe_mul(t0, t1, t0); + fe_sq_iter(t0, t0, 2); + + fe_mul(t0, t0, z); + return t0; + } + +/* +h = f * g +Can overlap h with f or g. + +Preconditions: +|f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. +|g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: +|h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +Notes on implementation strategy: + +Using schoolbook multiplication. +Karatsuba would save a little in some cost models. + +Most multiplications by 2 and 19 are 32-bit precomputations; +cheaper than 64-bit postcomputations. + +There is one remaining multiplication by 19 in the carry chain; +one *19 precomputation can be merged into this, +but the resulting data flow is considerably less clean. + +There are 12 carries below. +10 of them are 2-way parallelizable and vectorizable. +Can get away with 11 carries, but then data flow is much deeper. + +With tighter constraints on inputs can squeeze carries into int32. +*/ + +//static +FE_25519 FE_25519::mul(const FE_25519& f, const FE_25519& g) + { + const int32_t f0 = f[0]; + const int32_t f1 = f[1]; + const int32_t f2 = f[2]; + const int32_t f3 = f[3]; + const int32_t f4 = f[4]; + const int32_t f5 = f[5]; + const int32_t f6 = f[6]; + const int32_t f7 = f[7]; + const int32_t f8 = f[8]; + const int32_t f9 = f[9]; + + const int32_t g0 = g[0]; + const int32_t g1 = g[1]; + const int32_t g2 = g[2]; + const int32_t g3 = g[3]; + const int32_t g4 = g[4]; + const int32_t g5 = g[5]; + const int32_t g6 = g[6]; + const int32_t g7 = g[7]; + const int32_t g8 = g[8]; + const int32_t g9 = g[9]; + + const int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ + const int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + const int32_t g3_19 = 19 * g3; + const int32_t g4_19 = 19 * g4; + const int32_t g5_19 = 19 * g5; + const int32_t g6_19 = 19 * g6; + const int32_t g7_19 = 19 * g7; + const int32_t g8_19 = 19 * g8; + const int32_t g9_19 = 19 * g9; + const int32_t f1_2 = 2 * f1; + const int32_t f3_2 = 2 * f3; + const int32_t f5_2 = 2 * f5; + const int32_t f7_2 = 2 * f7; + const int32_t f9_2 = 2 * f9; + + const int64_t f0g0 = f0 * static_cast(g0); + const int64_t f0g1 = f0 * static_cast(g1); + const int64_t f0g2 = f0 * static_cast(g2); + const int64_t f0g3 = f0 * static_cast(g3); + const int64_t f0g4 = f0 * static_cast(g4); + const int64_t f0g5 = f0 * static_cast(g5); + const int64_t f0g6 = f0 * static_cast(g6); + const int64_t f0g7 = f0 * static_cast(g7); + const int64_t f0g8 = f0 * static_cast(g8); + const int64_t f0g9 = f0 * static_cast(g9); + const int64_t f1g0 = f1 * static_cast(g0); + const int64_t f1g1_2 = f1_2 * static_cast(g1); + const int64_t f1g2 = f1 * static_cast(g2); + const int64_t f1g3_2 = f1_2 * static_cast(g3); + const int64_t f1g4 = f1 * static_cast(g4); + const int64_t f1g5_2 = f1_2 * static_cast(g5); + const int64_t f1g6 = f1 * static_cast(g6); + const int64_t f1g7_2 = f1_2 * static_cast(g7); + const int64_t f1g8 = f1 * static_cast(g8); + const int64_t f1g9_38 = f1_2 * static_cast(g9_19); + const int64_t f2g0 = f2 * static_cast(g0); + const int64_t f2g1 = f2 * static_cast(g1); + const int64_t f2g2 = f2 * static_cast(g2); + const int64_t f2g3 = f2 * static_cast(g3); + const int64_t f2g4 = f2 * static_cast(g4); + const int64_t f2g5 = f2 * static_cast(g5); + const int64_t f2g6 = f2 * static_cast(g6); + const int64_t f2g7 = f2 * static_cast(g7); + const int64_t f2g8_19 = f2 * static_cast(g8_19); + const int64_t f2g9_19 = f2 * static_cast(g9_19); + const int64_t f3g0 = f3 * static_cast(g0); + const int64_t f3g1_2 = f3_2 * static_cast(g1); + const int64_t f3g2 = f3 * static_cast(g2); + const int64_t f3g3_2 = f3_2 * static_cast(g3); + const int64_t f3g4 = f3 * static_cast(g4); + const int64_t f3g5_2 = f3_2 * static_cast(g5); + const int64_t f3g6 = f3 * static_cast(g6); + const int64_t f3g7_38 = f3_2 * static_cast(g7_19); + const int64_t f3g8_19 = f3 * static_cast(g8_19); + const int64_t f3g9_38 = f3_2 * static_cast(g9_19); + const int64_t f4g0 = f4 * static_cast(g0); + const int64_t f4g1 = f4 * static_cast(g1); + const int64_t f4g2 = f4 * static_cast(g2); + const int64_t f4g3 = f4 * static_cast(g3); + const int64_t f4g4 = f4 * static_cast(g4); + const int64_t f4g5 = f4 * static_cast(g5); + const int64_t f4g6_19 = f4 * static_cast(g6_19); + const int64_t f4g7_19 = f4 * static_cast(g7_19); + const int64_t f4g8_19 = f4 * static_cast(g8_19); + const int64_t f4g9_19 = f4 * static_cast(g9_19); + const int64_t f5g0 = f5 * static_cast(g0); + const int64_t f5g1_2 = f5_2 * static_cast(g1); + const int64_t f5g2 = f5 * static_cast(g2); + const int64_t f5g3_2 = f5_2 * static_cast(g3); + const int64_t f5g4 = f5 * static_cast(g4); + const int64_t f5g5_38 = f5_2 * static_cast(g5_19); + const int64_t f5g6_19 = f5 * static_cast(g6_19); + const int64_t f5g7_38 = f5_2 * static_cast(g7_19); + const int64_t f5g8_19 = f5 * static_cast(g8_19); + const int64_t f5g9_38 = f5_2 * static_cast(g9_19); + const int64_t f6g0 = f6 * static_cast(g0); + const int64_t f6g1 = f6 * static_cast(g1); + const int64_t f6g2 = f6 * static_cast(g2); + const int64_t f6g3 = f6 * static_cast(g3); + const int64_t f6g4_19 = f6 * static_cast(g4_19); + const int64_t f6g5_19 = f6 * static_cast(g5_19); + const int64_t f6g6_19 = f6 * static_cast(g6_19); + const int64_t f6g7_19 = f6 * static_cast(g7_19); + const int64_t f6g8_19 = f6 * static_cast(g8_19); + const int64_t f6g9_19 = f6 * static_cast(g9_19); + const int64_t f7g0 = f7 * static_cast(g0); + const int64_t f7g1_2 = f7_2 * static_cast(g1); + const int64_t f7g2 = f7 * static_cast(g2); + const int64_t f7g3_38 = f7_2 * static_cast(g3_19); + const int64_t f7g4_19 = f7 * static_cast(g4_19); + const int64_t f7g5_38 = f7_2 * static_cast(g5_19); + const int64_t f7g6_19 = f7 * static_cast(g6_19); + const int64_t f7g7_38 = f7_2 * static_cast(g7_19); + const int64_t f7g8_19 = f7 * static_cast(g8_19); + const int64_t f7g9_38 = f7_2 * static_cast(g9_19); + const int64_t f8g0 = f8 * static_cast(g0); + const int64_t f8g1 = f8 * static_cast(g1); + const int64_t f8g2_19 = f8 * static_cast(g2_19); + const int64_t f8g3_19 = f8 * static_cast(g3_19); + const int64_t f8g4_19 = f8 * static_cast(g4_19); + const int64_t f8g5_19 = f8 * static_cast(g5_19); + const int64_t f8g6_19 = f8 * static_cast(g6_19); + const int64_t f8g7_19 = f8 * static_cast(g7_19); + const int64_t f8g8_19 = f8 * static_cast(g8_19); + const int64_t f8g9_19 = f8 * static_cast(g9_19); + const int64_t f9g0 = f9 * static_cast(g0); + const int64_t f9g1_38 = f9_2 * static_cast(g1_19); + const int64_t f9g2_19 = f9 * static_cast(g2_19); + const int64_t f9g3_38 = f9_2 * static_cast(g3_19); + const int64_t f9g4_19 = f9 * static_cast(g4_19); + const int64_t f9g5_38 = f9_2 * static_cast(g5_19); + const int64_t f9g6_19 = f9 * static_cast(g6_19); + const int64_t f9g7_38 = f9_2 * static_cast(g7_19); + const int64_t f9g8_19 = f9 * static_cast(g8_19); + const int64_t f9g9_38 = f9_2 * static_cast(g9_19); + + int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; + int64_t h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; + int64_t h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; + int64_t h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; + int64_t h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; + int64_t h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; + int64_t h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; + int64_t h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; + int64_t h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; + int64_t h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + carry<26>(h0, h1); + carry<26>(h4, h5); + + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry<25>(h1, h2); + carry<25>(h5, h6); + + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry<26>(h2, h3); + carry<26>(h6, h7); + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry<25>(h3, h4); + carry<25>(h7, h8); + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry<26>(h4, h5); + carry<26>(h8, h9); + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry<25, 19>(h9, h0); + + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry<26>(h0, h1); + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + return FE_25519(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9); + } + +/* +h = f * f +Can overlap h with f. + +Preconditions: +|f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: +|h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +//static +FE_25519 FE_25519::sqr_iter(const FE_25519& f, size_t iter) + { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + for(size_t i = 0; i != iter; ++i) + { + const int32_t f0_2 = 2 * f0; + const int32_t f1_2 = 2 * f1; + const int32_t f2_2 = 2 * f2; + const int32_t f3_2 = 2 * f3; + const int32_t f4_2 = 2 * f4; + const int32_t f5_2 = 2 * f5; + const int32_t f6_2 = 2 * f6; + const int32_t f7_2 = 2 * f7; + const int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + const int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + const int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + const int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + const int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + + const int64_t f0f0 = f0 * static_cast(f0); + const int64_t f0f1_2 = f0_2 * static_cast(f1); + const int64_t f0f2_2 = f0_2 * static_cast(f2); + const int64_t f0f3_2 = f0_2 * static_cast(f3); + const int64_t f0f4_2 = f0_2 * static_cast(f4); + const int64_t f0f5_2 = f0_2 * static_cast(f5); + const int64_t f0f6_2 = f0_2 * static_cast(f6); + const int64_t f0f7_2 = f0_2 * static_cast(f7); + const int64_t f0f8_2 = f0_2 * static_cast(f8); + const int64_t f0f9_2 = f0_2 * static_cast(f9); + const int64_t f1f1_2 = f1_2 * static_cast(f1); + const int64_t f1f2_2 = f1_2 * static_cast(f2); + const int64_t f1f3_4 = f1_2 * static_cast(f3_2); + const int64_t f1f4_2 = f1_2 * static_cast(f4); + const int64_t f1f5_4 = f1_2 * static_cast(f5_2); + const int64_t f1f6_2 = f1_2 * static_cast(f6); + const int64_t f1f7_4 = f1_2 * static_cast(f7_2); + const int64_t f1f8_2 = f1_2 * static_cast(f8); + const int64_t f1f9_76 = f1_2 * static_cast(f9_38); + const int64_t f2f2 = f2 * static_cast(f2); + const int64_t f2f3_2 = f2_2 * static_cast(f3); + const int64_t f2f4_2 = f2_2 * static_cast(f4); + const int64_t f2f5_2 = f2_2 * static_cast(f5); + const int64_t f2f6_2 = f2_2 * static_cast(f6); + const int64_t f2f7_2 = f2_2 * static_cast(f7); + const int64_t f2f8_38 = f2_2 * static_cast(f8_19); + const int64_t f2f9_38 = f2 * static_cast(f9_38); + const int64_t f3f3_2 = f3_2 * static_cast(f3); + const int64_t f3f4_2 = f3_2 * static_cast(f4); + const int64_t f3f5_4 = f3_2 * static_cast(f5_2); + const int64_t f3f6_2 = f3_2 * static_cast(f6); + const int64_t f3f7_76 = f3_2 * static_cast(f7_38); + const int64_t f3f8_38 = f3_2 * static_cast(f8_19); + const int64_t f3f9_76 = f3_2 * static_cast(f9_38); + const int64_t f4f4 = f4 * static_cast(f4); + const int64_t f4f5_2 = f4_2 * static_cast(f5); + const int64_t f4f6_38 = f4_2 * static_cast(f6_19); + const int64_t f4f7_38 = f4 * static_cast(f7_38); + const int64_t f4f8_38 = f4_2 * static_cast(f8_19); + const int64_t f4f9_38 = f4 * static_cast(f9_38); + const int64_t f5f5_38 = f5 * static_cast(f5_38); + const int64_t f5f6_38 = f5_2 * static_cast(f6_19); + const int64_t f5f7_76 = f5_2 * static_cast(f7_38); + const int64_t f5f8_38 = f5_2 * static_cast(f8_19); + const int64_t f5f9_76 = f5_2 * static_cast(f9_38); + const int64_t f6f6_19 = f6 * static_cast(f6_19); + const int64_t f6f7_38 = f6 * static_cast(f7_38); + const int64_t f6f8_38 = f6_2 * static_cast(f8_19); + const int64_t f6f9_38 = f6 * static_cast(f9_38); + const int64_t f7f7_38 = f7 * static_cast(f7_38); + const int64_t f7f8_38 = f7_2 * static_cast(f8_19); + const int64_t f7f9_76 = f7_2 * static_cast(f9_38); + const int64_t f8f8_19 = f8 * static_cast(f8_19); + const int64_t f8f9_38 = f8 * static_cast(f9_38); + const int64_t f9f9_38 = f9 * static_cast(f9_38); + + int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + + carry<26>(h0, h1); + carry<26>(h4, h5); + carry<25>(h1, h2); + carry<25>(h5, h6); + carry<26>(h2, h3); + carry<26>(h6, h7); + + carry<25>(h3, h4); + carry<25>(h7, h8); + + carry<26>(h4, h5); + carry<26>(h8, h9); + carry<25,19>(h9, h0); + carry<26>(h0, h1); + + f0 = static_cast(h0); + f1 = static_cast(h1); + f2 = static_cast(h2); + f3 = static_cast(h3); + f4 = static_cast(h4); + f5 = static_cast(h5); + f6 = static_cast(h6); + f7 = static_cast(h7); + f8 = static_cast(h8); + f9 = static_cast(h9); + } + + return FE_25519(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); + } + +/* +h = 2 * f * f +Can overlap h with f. + +Preconditions: +|f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: +|h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +//static +FE_25519 FE_25519::sqr2(const FE_25519& f) + { + const int32_t f0 = f[0]; + const int32_t f1 = f[1]; + const int32_t f2 = f[2]; + const int32_t f3 = f[3]; + const int32_t f4 = f[4]; + const int32_t f5 = f[5]; + const int32_t f6 = f[6]; + const int32_t f7 = f[7]; + const int32_t f8 = f[8]; + const int32_t f9 = f[9]; + const int32_t f0_2 = 2 * f0; + const int32_t f1_2 = 2 * f1; + const int32_t f2_2 = 2 * f2; + const int32_t f3_2 = 2 * f3; + const int32_t f4_2 = 2 * f4; + const int32_t f5_2 = 2 * f5; + const int32_t f6_2 = 2 * f6; + const int32_t f7_2 = 2 * f7; + const int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + const int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + const int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + const int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + const int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + const int64_t f0f0 = f0 * static_cast(f0); + const int64_t f0f1_2 = f0_2 * static_cast(f1); + const int64_t f0f2_2 = f0_2 * static_cast(f2); + const int64_t f0f3_2 = f0_2 * static_cast(f3); + const int64_t f0f4_2 = f0_2 * static_cast(f4); + const int64_t f0f5_2 = f0_2 * static_cast(f5); + const int64_t f0f6_2 = f0_2 * static_cast(f6); + const int64_t f0f7_2 = f0_2 * static_cast(f7); + const int64_t f0f8_2 = f0_2 * static_cast(f8); + const int64_t f0f9_2 = f0_2 * static_cast(f9); + const int64_t f1f1_2 = f1_2 * static_cast(f1); + const int64_t f1f2_2 = f1_2 * static_cast(f2); + const int64_t f1f3_4 = f1_2 * static_cast(f3_2); + const int64_t f1f4_2 = f1_2 * static_cast(f4); + const int64_t f1f5_4 = f1_2 * static_cast(f5_2); + const int64_t f1f6_2 = f1_2 * static_cast(f6); + const int64_t f1f7_4 = f1_2 * static_cast(f7_2); + const int64_t f1f8_2 = f1_2 * static_cast(f8); + const int64_t f1f9_76 = f1_2 * static_cast(f9_38); + const int64_t f2f2 = f2 * static_cast(f2); + const int64_t f2f3_2 = f2_2 * static_cast(f3); + const int64_t f2f4_2 = f2_2 * static_cast(f4); + const int64_t f2f5_2 = f2_2 * static_cast(f5); + const int64_t f2f6_2 = f2_2 * static_cast(f6); + const int64_t f2f7_2 = f2_2 * static_cast(f7); + const int64_t f2f8_38 = f2_2 * static_cast(f8_19); + const int64_t f2f9_38 = f2 * static_cast(f9_38); + const int64_t f3f3_2 = f3_2 * static_cast(f3); + const int64_t f3f4_2 = f3_2 * static_cast(f4); + const int64_t f3f5_4 = f3_2 * static_cast(f5_2); + const int64_t f3f6_2 = f3_2 * static_cast(f6); + const int64_t f3f7_76 = f3_2 * static_cast(f7_38); + const int64_t f3f8_38 = f3_2 * static_cast(f8_19); + const int64_t f3f9_76 = f3_2 * static_cast(f9_38); + const int64_t f4f4 = f4 * static_cast(f4); + const int64_t f4f5_2 = f4_2 * static_cast(f5); + const int64_t f4f6_38 = f4_2 * static_cast(f6_19); + const int64_t f4f7_38 = f4 * static_cast(f7_38); + const int64_t f4f8_38 = f4_2 * static_cast(f8_19); + const int64_t f4f9_38 = f4 * static_cast(f9_38); + const int64_t f5f5_38 = f5 * static_cast(f5_38); + const int64_t f5f6_38 = f5_2 * static_cast(f6_19); + const int64_t f5f7_76 = f5_2 * static_cast(f7_38); + const int64_t f5f8_38 = f5_2 * static_cast(f8_19); + const int64_t f5f9_76 = f5_2 * static_cast(f9_38); + const int64_t f6f6_19 = f6 * static_cast(f6_19); + const int64_t f6f7_38 = f6 * static_cast(f7_38); + const int64_t f6f8_38 = f6_2 * static_cast(f8_19); + const int64_t f6f9_38 = f6 * static_cast(f9_38); + const int64_t f7f7_38 = f7 * static_cast(f7_38); + const int64_t f7f8_38 = f7_2 * static_cast(f8_19); + const int64_t f7f9_76 = f7_2 * static_cast(f9_38); + const int64_t f8f8_19 = f8 * static_cast(f8_19); + const int64_t f8f9_38 = f8 * static_cast(f9_38); + const int64_t f9f9_38 = f9 * static_cast(f9_38); + + int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry<26>(h0, h1); + carry<26>(h4, h5); + + carry<25>(h1, h2); + carry<25>(h5, h6); + + carry<26>(h2, h3); + carry<26>(h6, h7); + + carry<25>(h3, h4); + carry<25>(h7, h8); + carry<26>(h4, h5); + carry<26>(h8, h9); + carry<25,19>(h9, h0); + carry<26>(h0, h1); + + return FE_25519(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9); + } + +/* +Ignores top bit of h. +*/ + +void FE_25519::from_bytes(const uint8_t s[32]) + { + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 0x7fffff) << 2; + + carry<25,19>(h9, h0); + carry<25>(h1, h2); + carry<25>(h3, h4); + carry<25>(h5, h6); + carry<25>(h7, h8); + + carry<26>(h0, h1); + carry<26>(h2, h3); + carry<26>(h4, h5); + carry<26>(h6, h7); + carry<26>(h8, h9); + + m_fe[0] = static_cast(h0); + m_fe[1] = static_cast(h1); + m_fe[2] = static_cast(h2); + m_fe[3] = static_cast(h3); + m_fe[4] = static_cast(h4); + m_fe[5] = static_cast(h5); + m_fe[6] = static_cast(h6); + m_fe[7] = static_cast(h7); + m_fe[8] = static_cast(h8); + m_fe[9] = static_cast(h9); + } + +/* +Preconditions: +|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + +Write p=2^255-19; q=floor(h/p). +Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + +Proof: +Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. +Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + +Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). +Then 0(1) << 24))) >> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0<26>(h0, h1); + carry0<25>(h1, h2); + carry0<26>(h2, h3); + carry0<25>(h3, h4); + carry0<26>(h4, h5); + carry0<25>(h5, h6); + carry0<26>(h6, h7); + carry0<25>(h7, h8); + carry0<26>(h8, h9); + + int32_t carry9 = h9 >> 25; + h9 -= carry9 * X25; + /* h10 = carry9 */ + + /* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + Goal: Output h0+...+2^230 h9. + */ + + s[0] = static_cast(h0 >> 0); + s[1] = static_cast(h0 >> 8); + s[2] = static_cast(h0 >> 16); + s[3] = static_cast((h0 >> 24) | (h1 << 2)); + s[4] = static_cast(h1 >> 6); + s[5] = static_cast(h1 >> 14); + s[6] = static_cast((h1 >> 22) | (h2 << 3)); + s[7] = static_cast(h2 >> 5); + s[8] = static_cast(h2 >> 13); + s[9] = static_cast((h2 >> 21) | (h3 << 5)); + s[10] = static_cast(h3 >> 3); + s[11] = static_cast(h3 >> 11); + s[12] = static_cast((h3 >> 19) | (h4 << 6)); + s[13] = static_cast(h4 >> 2); + s[14] = static_cast(h4 >> 10); + s[15] = static_cast(h4 >> 18); + s[16] = static_cast(h5 >> 0); + s[17] = static_cast(h5 >> 8); + s[18] = static_cast(h5 >> 16); + s[19] = static_cast((h5 >> 24) | (h6 << 1)); + s[20] = static_cast(h6 >> 7); + s[21] = static_cast(h6 >> 15); + s[22] = static_cast((h6 >> 23) | (h7 << 3)); + s[23] = static_cast(h7 >> 5); + s[24] = static_cast(h7 >> 13); + s[25] = static_cast((h7 >> 21) | (h8 << 4)); + s[26] = static_cast(h8 >> 4); + s[27] = static_cast(h8 >> 12); + s[28] = static_cast((h8 >> 20) | (h9 << 6)); + s[29] = static_cast(h9 >> 2); + s[30] = static_cast(h9 >> 10); + s[31] = static_cast(h9 >> 18); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.h b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.h new file mode 100644 index 0000000000..bcdc36a5e2 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_fe.h @@ -0,0 +1,227 @@ +/* +* Ed25519 field element +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ED25519_FE_H_ +#define BOTAN_ED25519_FE_H_ + +#include +#include + +namespace Botan { + +/** +* An element of the field \\Z/(2^255-19) +*/ +class FE_25519 + { + public: + ~FE_25519() { secure_scrub_memory(m_fe, sizeof(m_fe)); } + + /** + * Zero element + */ + FE_25519(int init = 0) + { + if(init != 0 && init != 1) + throw Invalid_Argument("Invalid FE_25519 initial value"); + clear_mem(m_fe, 10); + m_fe[0] = init; + } + + FE_25519(std::initializer_list x) + { + if(x.size() != 10) + throw Invalid_Argument("Invalid FE_25519 initializer list"); + copy_mem(m_fe, x.begin(), 10); + } + + FE_25519(int64_t h0, int64_t h1, int64_t h2, int64_t h3, int64_t h4, + int64_t h5, int64_t h6, int64_t h7, int64_t h8, int64_t h9) + { + m_fe[0] = static_cast(h0); + m_fe[1] = static_cast(h1); + m_fe[2] = static_cast(h2); + m_fe[3] = static_cast(h3); + m_fe[4] = static_cast(h4); + m_fe[5] = static_cast(h5); + m_fe[6] = static_cast(h6); + m_fe[7] = static_cast(h7); + m_fe[8] = static_cast(h8); + m_fe[9] = static_cast(h9); + } + + FE_25519(const FE_25519& other) = default; + FE_25519& operator=(const FE_25519& other) = default; + + FE_25519(FE_25519&& other) = default; + FE_25519& operator=(FE_25519&& other) = default; + + void from_bytes(const uint8_t b[32]); + void to_bytes(uint8_t b[32]) const; + + bool is_zero() const + { + uint8_t s[32]; + to_bytes(s); + + uint8_t sum = 0; + for(size_t i = 0; i != 32; ++i) + { sum |= s[i]; } + + // TODO avoid ternary here + return (sum == 0) ? 1 : 0; + } + + /* + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + */ + bool is_negative() const + { + // TODO could avoid most of the to_bytes computation here + uint8_t s[32]; + to_bytes(s); + return s[0] & 1; + } + + static FE_25519 add(const FE_25519& a, const FE_25519& b) + { + FE_25519 z; + for(size_t i = 0; i != 10; ++i) + { z[i] = a[i] + b[i]; } + return z; + } + + static FE_25519 sub(const FE_25519& a, const FE_25519& b) + { + FE_25519 z; + for(size_t i = 0; i != 10; ++i) + { z[i] = a[i] - b[i]; } + return z; + } + + static FE_25519 negate(const FE_25519& a) + { + FE_25519 z; + for(size_t i = 0; i != 10; ++i) + { z[i] = -a[i]; } + return z; + } + + static FE_25519 mul(const FE_25519& a, const FE_25519& b); + static FE_25519 sqr_iter(const FE_25519& a, size_t iter); + static FE_25519 sqr(const FE_25519& a) { return sqr_iter(a, 1); } + static FE_25519 sqr2(const FE_25519& a); + static FE_25519 pow_22523(const FE_25519& a); + static FE_25519 invert(const FE_25519& a); + + // TODO remove + int32_t operator[](size_t i) const { return m_fe[i]; } + int32_t& operator[](size_t i) { return m_fe[i]; } + + private: + + int32_t m_fe[10]; + }; + +typedef FE_25519 fe; + +/* +fe means field element. +Here the field is +An element t, entries t[0]...t[9], represents the integer +t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. +Bounds on each t[i] vary depending on context. +*/ + +inline void fe_frombytes(fe& x, const uint8_t* b) + { + x.from_bytes(b); + } + +inline void fe_tobytes(uint8_t* b, const fe& x) + { + x.to_bytes(b); + } + +inline void fe_copy(fe& a, const fe& b) + { + a = b; + } + +inline int fe_isnonzero(const fe& x) + { + return x.is_zero() ? 0 : 1; + } + +inline int fe_isnegative(const fe& x) + { + return x.is_negative(); + } + + +inline void fe_0(fe& x) + { + x = FE_25519(); + } + +inline void fe_1(fe& x) + { + x = FE_25519(1); + } + +inline void fe_add(fe& x, const fe& a, const fe& b) + { + x = FE_25519::add(a, b); + } + +inline void fe_sub(fe& x, const fe& a, const fe& b) + { + x = FE_25519::sub(a, b); + } + +inline void fe_neg(fe& x, const fe& z) + { + x = FE_25519::negate(z); + } + +inline void fe_mul(fe& x, const fe& a, const fe& b) + { + x = FE_25519::mul(a, b); + } + +inline void fe_sq(fe& x, const fe& z) + { + x = FE_25519::sqr(z); + } + +inline void fe_sq_iter(fe& x, const fe& z, size_t iter) + { + x = FE_25519::sqr_iter(z, iter); + } + +inline void fe_sq2(fe& x, const fe& z) + { + x = FE_25519::sqr2(z); + } + +inline void fe_invert(fe& x, const fe& z) + { + x = FE_25519::invert(z); + } + +inline void fe_pow22523(fe& x, const fe& y) + { + x = FE_25519::pow_22523(y); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_internal.h b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_internal.h new file mode 100644 index 0000000000..cb67a43fd2 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_internal.h @@ -0,0 +1,119 @@ +/* +* Ed25519 +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ED25519_INT_H_ +#define BOTAN_ED25519_INT_H_ + +#include +#include + +namespace Botan { + +inline uint64_t load_3(const uint8_t in[3]) + { + return static_cast(in[0]) | + (static_cast(in[1]) << 8) | + (static_cast(in[2]) << 16); + } + +inline uint64_t load_4(const uint8_t* in) + { + return load_le(in, 0); + } + +template +inline void carry(int64_t& h0, int64_t& h1) + { + static_assert(S > 0 && S < 64, "Shift in range"); + + const int64_t X1 = (static_cast(1) << S); + const int64_t X2 = (static_cast(1) << (S - 1)); + int64_t c = (h0 + X2) >> S; + h1 += c * MUL; + h0 -= c * X1; + } + +template +inline void carry0(int64_t& h0, int64_t& h1) + { + static_assert(S > 0 && S < 64, "Shift in range"); + + const int64_t X1 = (static_cast(1) << S); + int64_t c = h0 >> S; + h1 += c; + h0 -= c * X1; + } + +template +inline void carry0(int32_t& h0, int32_t& h1) + { + static_assert(S > 0 && S < 32, "Shift in range"); + + const int32_t X1 = (static_cast(1) << S); + int32_t c = h0 >> S; + h1 += c; + h0 -= c * X1; + } + +inline void redc_mul(int64_t& s1, + int64_t& s2, + int64_t& s3, + int64_t& s4, + int64_t& s5, + int64_t& s6, + int64_t& X) + { + s1 += X * 666643; + s2 += X * 470296; + s3 += X * 654183; + s4 -= X * 997805; + s5 += X * 136657; + s6 -= X * 683901; + X = 0; + } + +/* +ge means group element. + +Here the group is the set of pairs (x,y) of field elements (see fe.h) +satisfying -x^2 + y^2 = 1 + d x^2y^2 +where d = -121665/121666. + +Representations: + ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT +*/ + +typedef struct + { + fe X; + fe Y; + fe Z; + fe T; + } ge_p3; + +int ge_frombytes_negate_vartime(ge_p3*, const uint8_t*); +void ge_scalarmult_base(uint8_t out[32], const uint8_t in[32]); + +void ge_double_scalarmult_vartime(uint8_t out[32], + const uint8_t a[], + const ge_p3* A, + const uint8_t b[]); + +/* +The set of scalars is \Z/l +where l = 2^252 + 27742317777372353535851937790883648493. +*/ + +void sc_reduce(uint8_t*); +void sc_muladd(uint8_t*, const uint8_t*, const uint8_t*, const uint8_t*); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_key.cpp b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_key.cpp new file mode 100644 index 0000000000..c4b260c4cc --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ed25519_key.cpp @@ -0,0 +1,288 @@ +/* +* Ed25519 +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +AlgorithmIdentifier Ed25519_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); + } + +bool Ed25519_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + return true; // no tests possible? + // TODO could check cofactor + } + +Ed25519_PublicKey::Ed25519_PublicKey(const uint8_t pub_key[], size_t pub_len) + { + if(pub_len != 32) + throw Decoding_Error("Invalid length for Ed25519 key"); + m_public.assign(pub_key, pub_key + pub_len); + } + +Ed25519_PublicKey::Ed25519_PublicKey(const AlgorithmIdentifier&, + const std::vector& key_bits) + { + m_public = key_bits; + + if(m_public.size() != 32) + throw Decoding_Error("Invalid size for Ed25519 public key"); + } + +std::vector Ed25519_PublicKey::public_key_bits() const + { + return m_public; + } + +Ed25519_PrivateKey::Ed25519_PrivateKey(const secure_vector& secret_key) + { + if(secret_key.size() == 64) + { + m_private = secret_key; + m_public.assign(m_private.begin() + 32, m_private.end()); + } + else if(secret_key.size() == 32) + { + m_public.resize(32); + m_private.resize(64); + ed25519_gen_keypair(m_public.data(), m_private.data(), secret_key.data()); + } + else + throw Decoding_Error("Invalid size for Ed25519 private key"); + } + +Ed25519_PrivateKey::Ed25519_PrivateKey(RandomNumberGenerator& rng) + { + const secure_vector seed = rng.random_vec(32); + m_public.resize(32); + m_private.resize(64); + ed25519_gen_keypair(m_public.data(), m_private.data(), seed.data()); + } + +Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier&, + const secure_vector& key_bits) + { + secure_vector bits; + BER_Decoder(key_bits).decode(bits, OCTET_STRING).discard_remaining(); + + if(bits.size() != 32) + throw Decoding_Error("Invalid size for Ed25519 private key"); + m_public.resize(32); + m_private.resize(64); + ed25519_gen_keypair(m_public.data(), m_private.data(), bits.data()); + } + +secure_vector Ed25519_PrivateKey::private_key_bits() const + { + secure_vector bits(&m_private[0], &m_private[32]); + return DER_Encoder().encode(bits, OCTET_STRING).get_contents(); + } + +bool Ed25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const + { + return true; // ??? + } + +namespace { + +/** +* Ed25519 verifying operation +*/ +class Ed25519_Pure_Verify_Operation final : public PK_Ops::Verification + { + public: + Ed25519_Pure_Verify_Operation(const Ed25519_PublicKey& key) : m_key(key) + { + } + + void update(const uint8_t msg[], size_t msg_len) override + { + m_msg.insert(m_msg.end(), msg, msg + msg_len); + } + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override + { + if(sig_len != 64) + return false; + + const std::vector& pub_key = m_key.get_public_key(); + BOTAN_ASSERT_EQUAL(pub_key.size(), 32, "Expected size"); + const bool ok = ed25519_verify(m_msg.data(), m_msg.size(), sig, pub_key.data(), nullptr, 0); + m_msg.clear(); + return ok; + } + + private: + std::vector m_msg; + const Ed25519_PublicKey& m_key; + }; + +/** +* Ed25519 verifying operation with pre-hash +*/ +class Ed25519_Hashed_Verify_Operation final : public PK_Ops::Verification + { + public: + Ed25519_Hashed_Verify_Operation(const Ed25519_PublicKey& key, const std::string& hash, bool rfc8032) : + m_key(key) + { + m_hash = HashFunction::create_or_throw(hash); + + if(rfc8032) + { + m_domain_sep = { + 0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E, 0x6F, 0x20, 0x45, 0x64, + 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F, 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, + 0x01, 0x00 }; + } + } + + void update(const uint8_t msg[], size_t msg_len) override + { + m_hash->update(msg, msg_len); + } + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override + { + if(sig_len != 64) + return false; + std::vector msg_hash(m_hash->output_length()); + m_hash->final(msg_hash.data()); + + const std::vector& pub_key = m_key.get_public_key(); + BOTAN_ASSERT_EQUAL(pub_key.size(), 32, "Expected size"); + return ed25519_verify(msg_hash.data(), msg_hash.size(), sig, pub_key.data(), m_domain_sep.data(), m_domain_sep.size()); + } + + private: + std::unique_ptr m_hash; + const Ed25519_PublicKey& m_key; + std::vector m_domain_sep; + }; + +/** +* Ed25519 signing operation ('pure' - signs message directly) +*/ +class Ed25519_Pure_Sign_Operation final : public PK_Ops::Signature + { + public: + Ed25519_Pure_Sign_Operation(const Ed25519_PrivateKey& key) : m_key(key) + { + } + + void update(const uint8_t msg[], size_t msg_len) override + { + m_msg.insert(m_msg.end(), msg, msg + msg_len); + } + + secure_vector sign(RandomNumberGenerator&) override + { + secure_vector sig(64); + ed25519_sign(sig.data(), m_msg.data(), m_msg.size(), m_key.get_private_key().data(), nullptr, 0); + m_msg.clear(); + return sig; + } + + size_t signature_length() const override { return 64; } + + private: + std::vector m_msg; + const Ed25519_PrivateKey& m_key; + }; + +/** +* Ed25519 signing operation with pre-hash +*/ +class Ed25519_Hashed_Sign_Operation final : public PK_Ops::Signature + { + public: + Ed25519_Hashed_Sign_Operation(const Ed25519_PrivateKey& key, const std::string& hash, bool rfc8032) : + m_key(key) + { + m_hash = HashFunction::create_or_throw(hash); + + if(rfc8032) + { + m_domain_sep = std::vector{ + 0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E, 0x6F, 0x20, 0x45, 0x64, + 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F, 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, + 0x01, 0x00 }; + } + } + + size_t signature_length() const override { return 64; } + + void update(const uint8_t msg[], size_t msg_len) override + { + m_hash->update(msg, msg_len); + } + + secure_vector sign(RandomNumberGenerator&) override + { + secure_vector sig(64); + std::vector msg_hash(m_hash->output_length()); + m_hash->final(msg_hash.data()); + ed25519_sign(sig.data(), + msg_hash.data(), msg_hash.size(), + m_key.get_private_key().data(), + m_domain_sep.data(), m_domain_sep.size()); + return sig; + } + + private: + std::unique_ptr m_hash; + const Ed25519_PrivateKey& m_key; + std::vector m_domain_sep; + }; + +} + +std::unique_ptr +Ed25519_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + if(params == "" || params == "Identity" || params == "Pure") + return std::unique_ptr(new Ed25519_Pure_Verify_Operation(*this)); + else if(params == "Ed25519ph") + return std::unique_ptr(new Ed25519_Hashed_Verify_Operation(*this, "SHA-512", true)); + else + return std::unique_ptr(new Ed25519_Hashed_Verify_Operation(*this, params, false)); + } + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +Ed25519_PrivateKey::create_signature_op(RandomNumberGenerator&, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + if(params == "" || params == "Identity" || params == "Pure") + return std::unique_ptr(new Ed25519_Pure_Sign_Operation(*this)); + else if(params == "Ed25519ph") + return std::unique_ptr(new Ed25519_Hashed_Sign_Operation(*this, "SHA-512", true)); + else + return std::unique_ptr(new Ed25519_Hashed_Sign_Operation(*this, params, false)); + } + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/ge.cpp b/comm/third_party/botan/src/lib/pubkey/ed25519/ge.cpp new file mode 100644 index 0000000000..7d3fae2fbc --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/ge.cpp @@ -0,0 +1,2174 @@ +/* +* Ed25519 group operations +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +/* +Representations: + ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + ge_precomp (Duif): (y+x,y-x,2dxy) +*/ +typedef struct + { + fe X; + fe Y; + fe Z; + } ge_p2; + +typedef struct + { + fe X; + fe Y; + fe Z; + fe T; + } ge_p1p1; + +typedef struct + { + fe yplusx; + fe yminusx; + fe xy2d; + } ge_precomp; + +typedef struct + { + fe YplusX; + fe YminusX; + fe Z; + fe T2d; + } ge_cached; + +/* +r = p + q +*/ + +void ge_add(ge_p1p1* r, const ge_p3* p, const ge_cached* q) + { + fe t0; + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ + fe_add(r->X, p->Y, p->X); + + /* qhasm: YmX1 = Y1-X1 */ + /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ + fe_sub(r->Y, p->Y, p->X); + + /* qhasm: A = YpX1*YpX2 */ + /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YplusX); */ + fe_mul(r->Z, r->X, q->YplusX); + + /* qhasm: B = YmX1*YmX2 */ + /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YminusX); */ + fe_mul(r->Y, r->Y, q->YminusX); + + /* qhasm: C = T2d2*T1 */ + /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ + fe_mul(r->T, q->T2d, p->T); + + /* qhasm: ZZ = Z1*Z2 */ + /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ + fe_mul(r->X, p->Z, q->Z); + + /* qhasm: D = 2*ZZ */ + /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ + fe_add(t0, r->X, r->X); + + /* qhasm: X3 = A-B */ + /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ + fe_sub(r->X, r->Z, r->Y); + + /* qhasm: Y3 = A+B */ + /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ + fe_add(r->Y, r->Z, r->Y); + + /* qhasm: Z3 = D+C */ + /* asm 1: fe_add(>Z3=fe#3,Z3=r->Z,T); */ + fe_add(r->Z, t0, r->T); + + /* qhasm: T3 = D-C */ + /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T); */ + fe_sub(r->T, t0, r->T); + } + +/* +r = p + q +*/ + +void ge_madd(ge_p1p1* r, const ge_p3* p, const ge_precomp* q) + { + fe t0; + /* qhasm: YpX1 = Y1+X1 */ + fe_add(r->X, p->Y, p->X); + + /* qhasm: YmX1 = Y1-X1 */ + fe_sub(r->Y, p->Y, p->X); + + /* qhasm: A = YpX1*ypx2 */ + fe_mul(r->Z, r->X, q->yplusx); + + /* qhasm: B = YmX1*ymx2 */ + fe_mul(r->Y, r->Y, q->yminusx); + + /* qhasm: C = xy2d2*T1 */ + fe_mul(r->T, q->xy2d, p->T); + + /* qhasm: D = 2*Z1 */ + fe_add(t0, p->Z, p->Z); + + /* qhasm: X3 = A-B */ + fe_sub(r->X, r->Z, r->Y); + + /* qhasm: Y3 = A+B */ + fe_add(r->Y, r->Z, r->Y); + + /* qhasm: Z3 = D+C */ + fe_add(r->Z, t0, r->T); + + /* qhasm: T3 = D-C */ + fe_sub(r->T, t0, r->T); + } + +/* +r = p - q +*/ + +void ge_msub(ge_p1p1* r, const ge_p3* p, const ge_precomp* q) + { + fe t0; + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ + fe_add(r->X, p->Y, p->X); + + /* qhasm: YmX1 = Y1-X1 */ + /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ + fe_sub(r->Y, p->Y, p->X); + + /* qhasm: A = YpX1*ymx2 */ + /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,yminusx); */ + fe_mul(r->Z, r->X, q->yminusx); + + /* qhasm: B = YmX1*ypx2 */ + /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,yplusx); */ + fe_mul(r->Y, r->Y, q->yplusx); + + /* qhasm: C = xy2d2*T1 */ + /* asm 1: fe_mul(>C=fe#4,C=r->T,xy2d,T); */ + fe_mul(r->T, q->xy2d, p->T); + + /* qhasm: D = 2*Z1 */ + /* asm 1: fe_add(>D=fe#5,D=t0,Z,Z); */ + fe_add(t0, p->Z, p->Z); + + /* qhasm: X3 = A-B */ + /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ + fe_sub(r->X, r->Z, r->Y); + + /* qhasm: Y3 = A+B */ + /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ + fe_add(r->Y, r->Z, r->Y); + + /* qhasm: Z3 = D-C */ + /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ + fe_sub(r->Z, t0, r->T); + + /* qhasm: T3 = D+C */ + /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ + fe_add(r->T, t0, r->T); + + } + +/* +r = p +*/ + +void ge_p1p1_to_p2(ge_p2* r, const ge_p1p1* p) + { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); + } + +/* +r = p +*/ + +void ge_p1p1_to_p3(ge_p3* r, const ge_p1p1* p) + { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); + fe_mul(r->T, p->X, p->Y); + } + +/* +r = 2 * p +*/ + +void ge_p2_dbl(ge_p1p1* r, const ge_p2* p) + { + fe t0; + /* qhasm: XX=X1^2 */ + /* asm 1: fe_sq(>XX=fe#1,XX=r->X,X); */ + fe_sq(r->X, p->X); + + /* qhasm: YY=Y1^2 */ + /* asm 1: fe_sq(>YY=fe#3,YY=r->Z,Y); */ + fe_sq(r->Z, p->Y); + + /* qhasm: B=2*Z1^2 */ + /* asm 1: fe_sq2(>B=fe#4,B=r->T,Z); */ + fe_sq2(r->T, p->Z); + + /* qhasm: A=X1+Y1 */ + /* asm 1: fe_add(>A=fe#2,A=r->Y,X,Y); */ + fe_add(r->Y, p->X, p->Y); + + /* qhasm: AA=A^2 */ + /* asm 1: fe_sq(>AA=fe#5,AA=t0,Y); */ + fe_sq(t0, r->Y); + + /* qhasm: Y3=YY+XX */ + /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,X); */ + fe_add(r->Y, r->Z, r->X); + + /* qhasm: Z3=YY-XX */ + /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,Z,X); */ + fe_sub(r->Z, r->Z, r->X); + + /* qhasm: X3=AA-Y3 */ + /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Y); */ + fe_sub(r->X, t0, r->Y); + + /* qhasm: T3=B-Z3 */ + /* asm 1: fe_sub(>T3=fe#4,T3=r->T,T,Z); */ + fe_sub(r->T, r->T, r->Z); + } + +void ge_p3_0(ge_p3* h) + { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); + fe_0(h->T); + } + +/* +r = 2 * p +*/ + +void ge_p3_dbl(ge_p1p1* r, const ge_p3* p) + { + ge_p2 q; + // Convert to p2 rep + q.X = p->X; + q.Y = p->Y; + q.Z = p->Z; + ge_p2_dbl(r, &q); + } + +/* +r = p +*/ + + +void ge_p3_to_cached(ge_cached* r, const ge_p3* p) + { + static const fe d2 = + { + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 + } ; + fe_add(r->YplusX, p->Y, p->X); + fe_sub(r->YminusX, p->Y, p->X); + fe_copy(r->Z, p->Z); + fe_mul(r->T2d, p->T, d2); + } + +/* +r = p - q +*/ + +void ge_sub(ge_p1p1* r, const ge_p3* p, const ge_cached* q) + { + fe t0; + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r->X,Y,X); */ + fe_add(r->X, p->Y, p->X); + + /* qhasm: YmX1 = Y1-X1 */ + /* asm 1: fe_sub(>YmX1=fe#2,YmX1=r->Y,Y,X); */ + fe_sub(r->Y, p->Y, p->X); + + /* qhasm: A = YpX1*YmX2 */ + /* asm 1: fe_mul(>A=fe#3,A=r->Z,X,YminusX); */ + fe_mul(r->Z, r->X, q->YminusX); + + /* qhasm: B = YmX1*YpX2 */ + /* asm 1: fe_mul(>B=fe#2,B=r->Y,Y,YplusX); */ + fe_mul(r->Y, r->Y, q->YplusX); + + /* qhasm: C = T2d2*T1 */ + /* asm 1: fe_mul(>C=fe#4,C=r->T,T2d,T); */ + fe_mul(r->T, q->T2d, p->T); + + /* qhasm: ZZ = Z1*Z2 */ + /* asm 1: fe_mul(>ZZ=fe#1,ZZ=r->X,Z,Z); */ + fe_mul(r->X, p->Z, q->Z); + + /* qhasm: D = 2*ZZ */ + /* asm 1: fe_add(>D=fe#5,D=t0,X,X); */ + fe_add(t0, r->X, r->X); + + /* qhasm: X3 = A-B */ + /* asm 1: fe_sub(>X3=fe#1,X3=r->X,Z,Y); */ + fe_sub(r->X, r->Z, r->Y); + + /* qhasm: Y3 = A+B */ + /* asm 1: fe_add(>Y3=fe#2,Y3=r->Y,Z,Y); */ + fe_add(r->Y, r->Z, r->Y); + + /* qhasm: Z3 = D-C */ + /* asm 1: fe_sub(>Z3=fe#3,Z3=r->Z,T); */ + fe_sub(r->Z, t0, r->T); + + /* qhasm: T3 = D+C */ + /* asm 1: fe_add(>T3=fe#4,T3=r->T,T); */ + fe_add(r->T, t0, r->T); + + } + +void slide(int8_t* r, const uint8_t* a) + { + for(size_t i = 0; i < 256; ++i) + { + r[i] = 1 & (a[i >> 3] >> (i & 7)); + } + + for(size_t i = 0; i < 256; ++i) + { + if(r[i]) + { + for(size_t b = 1; b <= 6 && i + b < 256; ++b) + { + if(r[i + b]) + { + if(r[i] + (r[i + b] << b) <= 15) + { + r[i] += r[i + b] << b; + r[i + b] = 0; + } + else if(r[i] - (r[i + b] << b) >= -15) + { + r[i] -= r[i + b] << b; + for(size_t k = i + b; k < 256; ++k) + { + if(!r[k]) + { + r[k] = 1; + break; + } + r[k] = 0; + } + } + else + { break; } + } + } + } + } + } + +void ge_tobytes(uint8_t* s, const ge_p2* h) + { + fe recip; + fe x; + fe y; + + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; + } + +void ge_p2_0(ge_p2* h) + { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); + } + +} + +int ge_frombytes_negate_vartime(ge_p3* h, const uint8_t* s) + { + static const fe d = + { + -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 + } ; + static const fe sqrtm1 = + { + -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 + } ; + + fe u; + fe v; + fe v3; + fe vxx; + fe check; + + fe_frombytes(h->Y, s); + fe_1(h->Z); + fe_sq(u, h->Y); + fe_mul(v, u, d); + fe_sub(u, u, h->Z); /* u = y^2-1 */ + fe_add(v, v, h->Z); /* v = dy^2+1 */ + + fe_sq(v3, v); + fe_mul(v3, v3, v); /* v3 = v^3 */ + fe_sq(h->X, v3); + fe_mul(h->X, h->X, v); + fe_mul(h->X, h->X, u); /* x = uv^7 */ + + fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ + fe_mul(h->X, h->X, v3); + fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe_sq(vxx, h->X); + fe_mul(vxx, vxx, v); + fe_sub(check, vxx, u); /* vx^2-u */ + if(fe_isnonzero(check)) + { + fe_add(check, vxx, u); /* vx^2+u */ + if(fe_isnonzero(check)) + { + return -1; + } + fe_mul(h->X, h->X, sqrtm1); + } + + if(fe_isnegative(h->X) == (s[31] >> 7)) + { fe_neg(h->X, h->X); } + + fe_mul(h->T, h->X, h->Y); + return 0; + } + +/* +r = a * A + b * B +where a = a[0]+256*a[1]+...+256^31 a[31]. +and b = b[0]+256*b[1]+...+256^31 b[31]. +B is the Ed25519 base point (x,4/5) with x positive. +*/ + +void ge_double_scalarmult_vartime( + uint8_t out[32], + const uint8_t* a, const ge_p3* A, const uint8_t* b) + { + static const ge_precomp Bi[8] = + { + { + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 }, + }, + { + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 }, + }, + { + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 }, + }, + { + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 }, + }, + { + { -22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877 }, + { -6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951 }, + { 4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784 }, + }, + { + { -25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436 }, + { 25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918 }, + { 23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877 }, + }, + { + { -33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800 }, + { -25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305 }, + { -13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300 }, + }, + { + { -3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876 }, + { -24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619 }, + { -3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683 }, + }, + } ; + + int8_t aslide[256]; + int8_t bslide[256]; + ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ + ge_p1p1 t; + ge_p3 u; + ge_p3 A2; + ge_p2 r; + int i; + + slide(aslide, a); + slide(bslide, b); + + ge_p3_to_cached(&Ai[0], A); + ge_p3_dbl(&t, A); + ge_p1p1_to_p3(&A2, &t); + ge_add(&t, &A2, &Ai[0]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[1], &u); + ge_add(&t, &A2, &Ai[1]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[2], &u); + ge_add(&t, &A2, &Ai[2]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[3], &u); + ge_add(&t, &A2, &Ai[3]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[4], &u); + ge_add(&t, &A2, &Ai[4]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[5], &u); + ge_add(&t, &A2, &Ai[5]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[6], &u); + ge_add(&t, &A2, &Ai[6]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[7], &u); + + ge_p2_0(&r); + + for(i = 255; i >= 0; --i) + { + if(aslide[i] || bslide[i]) + { + break; + } + } + + for(; i >= 0; --i) + { + ge_p2_dbl(&t, &r); + + if(aslide[i] > 0) + { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i] >> 1]); + } + else if(aslide[i] < 0) + { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i]) >> 1]); + } + + if(bslide[i] > 0) + { + ge_p1p1_to_p3(&u, &t); + ge_madd(&t, &u, &Bi[bslide[i] >> 1]); + } + else if(bslide[i] < 0) + { + ge_p1p1_to_p3(&u, &t); + ge_msub(&t, &u, &Bi[(-bslide[i]) >> 1]); + } + + ge_p1p1_to_p2(&r, &t); + } + + ge_tobytes(out, &r); + } + +/* base[i][j] = (j+1)*256^i*B */ +static const ge_precomp B_precomp[32][8] = + { + { + { + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 }, + }, + { + { -12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303 }, + { -21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081 }, + { 26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697 }, + }, + { + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 }, + }, + { + { -17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540 }, + { 23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397 }, + { 7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325 }, + }, + { + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 }, + }, + { + { -15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777 }, + { -8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737 }, + { -18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652 }, + }, + { + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 }, + }, + { + { 14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726 }, + { -7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955 }, + { 27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425 }, + }, + }, + { + { + { -13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171 }, + { 27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510 }, + { 17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660 }, + }, + { + { -10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639 }, + { 29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963 }, + { 5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950 }, + }, + { + { -27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568 }, + { 12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335 }, + { 25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628 }, + }, + { + { -26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007 }, + { -2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772 }, + { -22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653 }, + }, + { + { 2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567 }, + { 13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686 }, + { 21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372 }, + }, + { + { -13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887 }, + { -23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954 }, + { -29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953 }, + }, + { + { 24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833 }, + { -16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532 }, + { -22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876 }, + }, + { + { 2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268 }, + { 33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214 }, + { 1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038 }, + }, + }, + { + { + { 6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800 }, + { 4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645 }, + { -4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664 }, + }, + { + { 1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933 }, + { -25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182 }, + { -17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222 }, + }, + { + { -18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991 }, + { 20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880 }, + { 9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092 }, + }, + { + { -16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295 }, + { 19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788 }, + { 8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553 }, + }, + { + { -15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026 }, + { 11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347 }, + { -18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033 }, + }, + { + { -23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395 }, + { -27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278 }, + { 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890 }, + }, + { + { 32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995 }, + { -30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596 }, + { -11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891 }, + }, + { + { 31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060 }, + { 11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608 }, + { -20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606 }, + }, + }, + { + { + { 7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389 }, + { -19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016 }, + { -11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341 }, + }, + { + { -22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505 }, + { 14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553 }, + { -28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655 }, + }, + { + { 15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220 }, + { 12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631 }, + { -4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099 }, + }, + { + { 26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556 }, + { 14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749 }, + { 236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930 }, + }, + { + { 1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391 }, + { 5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253 }, + { 20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066 }, + }, + { + { 24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958 }, + { -11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082 }, + { -28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383 }, + }, + { + { -30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521 }, + { -11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807 }, + { 23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948 }, + }, + { + { 9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134 }, + { -32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455 }, + { 27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629 }, + }, + }, + { + { + { -8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069 }, + { -32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746 }, + { 24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919 }, + }, + { + { 11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837 }, + { 8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906 }, + { -28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771 }, + }, + { + { -25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817 }, + { 10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098 }, + { 10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409 }, + }, + { + { -12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504 }, + { -26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727 }, + { 28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420 }, + }, + { + { -32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003 }, + { -1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605 }, + { -30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384 }, + }, + { + { -26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701 }, + { -23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683 }, + { 29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708 }, + }, + { + { -3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563 }, + { -19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260 }, + { -5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387 }, + }, + { + { -19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672 }, + { 23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686 }, + { -24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665 }, + }, + }, + { + { + { 11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182 }, + { -31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277 }, + { 14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628 }, + }, + { + { -4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474 }, + { -26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539 }, + { -25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822 }, + }, + { + { -10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970 }, + { 19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756 }, + { -24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508 }, + }, + { + { -26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683 }, + { -10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655 }, + { -20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158 }, + }, + { + { -4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125 }, + { -15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839 }, + { -20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664 }, + }, + { + { 27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294 }, + { -18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899 }, + { -11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070 }, + }, + { + { 3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294 }, + { -15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949 }, + { -21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083 }, + }, + { + { 31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420 }, + { -5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940 }, + { 29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396 }, + }, + }, + { + { + { -12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567 }, + { 20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127 }, + { -16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294 }, + }, + { + { -12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887 }, + { 22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964 }, + { 16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195 }, + }, + { + { 9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244 }, + { 24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999 }, + { -1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762 }, + }, + { + { -18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274 }, + { -33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236 }, + { -16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605 }, + }, + { + { -13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761 }, + { -22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884 }, + { -6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482 }, + }, + { + { -24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638 }, + { -11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490 }, + { -32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170 }, + }, + { + { 5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736 }, + { 10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124 }, + { -17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392 }, + }, + { + { 8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029 }, + { 6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048 }, + { 28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958 }, + }, + }, + { + { + { 24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593 }, + { 26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071 }, + { -11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692 }, + }, + { + { 11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687 }, + { -160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441 }, + { -20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001 }, + }, + { + { -938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460 }, + { -19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007 }, + { -21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762 }, + }, + { + { 15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005 }, + { -9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674 }, + { 4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035 }, + }, + { + { 7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590 }, + { -2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957 }, + { -30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812 }, + }, + { + { 33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740 }, + { -18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122 }, + { -27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158 }, + }, + { + { 8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885 }, + { 26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140 }, + { 19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857 }, + }, + { + { 801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155 }, + { 19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260 }, + { 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483 }, + }, + }, + { + { + { -3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677 }, + { 32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815 }, + { 22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751 }, + }, + { + { -16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203 }, + { -11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208 }, + { 1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230 }, + }, + { + { 16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850 }, + { -21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389 }, + { -9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968 }, + }, + { + { -11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689 }, + { 14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880 }, + { 5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304 }, + }, + { + { 30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632 }, + { -3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412 }, + { 20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566 }, + }, + { + { -20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038 }, + { -26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232 }, + { -1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943 }, + }, + { + { 17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856 }, + { 23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738 }, + { 15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971 }, + }, + { + { -27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718 }, + { -13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697 }, + { -11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883 }, + }, + }, + { + { + { 5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912 }, + { -26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358 }, + { 3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849 }, + }, + { + { 29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307 }, + { -14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977 }, + { -6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335 }, + }, + { + { -29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644 }, + { -22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616 }, + { -27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735 }, + }, + { + { -21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099 }, + { 29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341 }, + { -936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336 }, + }, + { + { -23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646 }, + { 31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425 }, + { -17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388 }, + }, + { + { -31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743 }, + { -16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822 }, + { -8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462 }, + }, + { + { 18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985 }, + { 9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702 }, + { -22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797 }, + }, + { + { 21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293 }, + { 27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100 }, + { 19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688 }, + }, + }, + { + { + { 12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186 }, + { 2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610 }, + { -2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707 }, + }, + { + { 7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220 }, + { 915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025 }, + { 32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044 }, + }, + { + { 32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992 }, + { -4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027 }, + { 21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197 }, + }, + { + { 8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901 }, + { 31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952 }, + { 19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878 }, + }, + { + { -28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390 }, + { 32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730 }, + { 2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730 }, + }, + { + { -19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180 }, + { -30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272 }, + { -15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715 }, + }, + { + { -22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970 }, + { -31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772 }, + { -17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865 }, + }, + { + { 15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750 }, + { 20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373 }, + { 32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348 }, + }, + }, + { + { + { 9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144 }, + { -22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195 }, + { 5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086 }, + }, + { + { -13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684 }, + { -8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518 }, + { -2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233 }, + }, + { + { -5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793 }, + { -2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794 }, + { 580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435 }, + }, + { + { 23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921 }, + { 13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518 }, + { 2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563 }, + }, + { + { 14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278 }, + { -27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024 }, + { 4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030 }, + }, + { + { 10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783 }, + { 27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717 }, + { 6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844 }, + }, + { + { 14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333 }, + { 16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048 }, + { 22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760 }, + }, + { + { -4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760 }, + { -15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757 }, + { -2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112 }, + }, + }, + { + { + { -19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468 }, + { 3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184 }, + { 10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289 }, + }, + { + { 15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066 }, + { 24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882 }, + { 13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226 }, + }, + { + { 16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101 }, + { 29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279 }, + { -6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811 }, + }, + { + { 27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709 }, + { 20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714 }, + { -2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121 }, + }, + { + { 9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464 }, + { 12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847 }, + { 13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400 }, + }, + { + { 4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414 }, + { -15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158 }, + { 17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045 }, + }, + { + { -461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415 }, + { -5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459 }, + { -31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079 }, + }, + { + { 21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412 }, + { -20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743 }, + { -14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836 }, + }, + }, + { + { + { 12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022 }, + { 18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429 }, + { -6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065 }, + }, + { + { 30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861 }, + { 10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000 }, + { -33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101 }, + }, + { + { 32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815 }, + { 29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642 }, + { 10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966 }, + }, + { + { 25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574 }, + { -21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742 }, + { -18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689 }, + }, + { + { 12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020 }, + { -10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772 }, + { 3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982 }, + }, + { + { -14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953 }, + { -16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218 }, + { -17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265 }, + }, + { + { 29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073 }, + { -3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325 }, + { -11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798 }, + }, + { + { -4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870 }, + { -7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863 }, + { -13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927 }, + }, + }, + { + { + { -2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267 }, + { -9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663 }, + { 22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862 }, + }, + { + { -25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673 }, + { 15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943 }, + { 15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020 }, + }, + { + { -4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238 }, + { 11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064 }, + { 14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795 }, + }, + { + { 15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052 }, + { -10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904 }, + { 29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531 }, + }, + { + { -13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979 }, + { -5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841 }, + { 10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431 }, + }, + { + { 10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324 }, + { -31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940 }, + { 10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320 }, + }, + { + { -15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184 }, + { 14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114 }, + { 30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878 }, + }, + { + { 12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784 }, + { -2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091 }, + { -16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585 }, + }, + }, + { + { + { -8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208 }, + { 10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864 }, + { 17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661 }, + }, + { + { 7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233 }, + { 26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212 }, + { -12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525 }, + }, + { + { -24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068 }, + { 9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397 }, + { -8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988 }, + }, + { + { 5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889 }, + { 32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038 }, + { 14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697 }, + }, + { + { 20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875 }, + { -25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905 }, + { -25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656 }, + }, + { + { 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818 }, + { 27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714 }, + { 10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203 }, + }, + { + { 20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931 }, + { -30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024 }, + { -23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084 }, + }, + { + { -1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204 }, + { 20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817 }, + { 27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667 }, + }, + }, + { + { + { 11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504 }, + { -12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768 }, + { -19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255 }, + }, + { + { 6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790 }, + { 1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438 }, + { -22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333 }, + }, + { + { 17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971 }, + { 31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905 }, + { 29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409 }, + }, + { + { 12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409 }, + { 6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499 }, + { -8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363 }, + }, + { + { 28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664 }, + { -11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324 }, + { -21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940 }, + }, + { + { 13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990 }, + { -17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914 }, + { -25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290 }, + }, + { + { 24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257 }, + { -6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433 }, + { -16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236 }, + }, + { + { -12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045 }, + { 11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093 }, + { -1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347 }, + }, + }, + { + { + { -28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191 }, + { -15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507 }, + { -12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906 }, + }, + { + { 3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018 }, + { -16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109 }, + { -23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926 }, + }, + { + { -24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528 }, + { 8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625 }, + { -32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286 }, + }, + { + { 2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033 }, + { 27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866 }, + { 21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896 }, + }, + { + { 30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075 }, + { 26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347 }, + { -22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437 }, + }, + { + { -5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165 }, + { -18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588 }, + { -32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193 }, + }, + { + { -19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017 }, + { -28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883 }, + { 21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961 }, + }, + { + { 8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043 }, + { 29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663 }, + { -20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362 }, + }, + }, + { + { + { -33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860 }, + { 2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466 }, + { -24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063 }, + }, + { + { -26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997 }, + { -1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295 }, + { -13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369 }, + }, + { + { 9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385 }, + { 18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109 }, + { 2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906 }, + }, + { + { 4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424 }, + { -19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185 }, + { 7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962 }, + }, + { + { -7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325 }, + { 10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593 }, + { 696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404 }, + }, + { + { -11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644 }, + { 17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801 }, + { 26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804 }, + }, + { + { -31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884 }, + { -586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577 }, + { -9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849 }, + }, + { + { 32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473 }, + { -8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644 }, + { -2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319 }, + }, + }, + { + { + { -11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599 }, + { -9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768 }, + { -27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084 }, + }, + { + { -27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328 }, + { -15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369 }, + { 20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920 }, + }, + { + { 12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815 }, + { -32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025 }, + { -21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397 }, + }, + { + { -20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448 }, + { 6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981 }, + { 30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165 }, + }, + { + { 32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501 }, + { 17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073 }, + { -1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861 }, + }, + { + { 14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845 }, + { -1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211 }, + { 18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870 }, + }, + { + { 10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096 }, + { 33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803 }, + { -32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168 }, + }, + { + { 30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965 }, + { -14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505 }, + { 18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598 }, + }, + }, + { + { + { 5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782 }, + { 5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900 }, + { -31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479 }, + }, + { + { -12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208 }, + { 8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232 }, + { 17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719 }, + }, + { + { 16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271 }, + { -4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326 }, + { -8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132 }, + }, + { + { 14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300 }, + { 8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570 }, + { 15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670 }, + }, + { + { -2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994 }, + { -12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913 }, + { 31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317 }, + }, + { + { -25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730 }, + { 842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096 }, + { -4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078 }, + }, + { + { -15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411 }, + { -19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905 }, + { -9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654 }, + }, + { + { -28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870 }, + { -23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498 }, + { 12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579 }, + }, + }, + { + { + { 14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677 }, + { 10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647 }, + { -2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743 }, + }, + { + { -25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468 }, + { 21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375 }, + { -25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155 }, + }, + { + { 6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725 }, + { -12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612 }, + { -10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943 }, + }, + { + { -30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944 }, + { 30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928 }, + { 9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406 }, + }, + { + { 22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139 }, + { -8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963 }, + { -31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693 }, + }, + { + { 1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734 }, + { -448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680 }, + { -24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410 }, + }, + { + { -9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931 }, + { -16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654 }, + { 22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710 }, + }, + { + { 29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180 }, + { -26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684 }, + { -10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895 }, + }, + }, + { + { + { 22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501 }, + { -11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413 }, + { 6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880 }, + }, + { + { -8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874 }, + { 22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962 }, + { -7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899 }, + }, + { + { 21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152 }, + { 9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063 }, + { 7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080 }, + }, + { + { -9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146 }, + { -17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183 }, + { -19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133 }, + }, + { + { -32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421 }, + { -3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622 }, + { -4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197 }, + }, + { + { 2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663 }, + { 31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753 }, + { 4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755 }, + }, + { + { -9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862 }, + { -26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118 }, + { 26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171 }, + }, + { + { 15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380 }, + { 16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824 }, + { 28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270 }, + }, + }, + { + { + { -817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438 }, + { -31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584 }, + { -594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562 }, + }, + { + { 30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471 }, + { 18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610 }, + { 19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269 }, + }, + { + { -30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650 }, + { 14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369 }, + { 19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461 }, + }, + { + { 30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462 }, + { -5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793 }, + { -2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218 }, + }, + { + { -24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226 }, + { 18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019 }, + { -15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037 }, + }, + { + { 31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171 }, + { -17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132 }, + { -28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841 }, + }, + { + { 21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181 }, + { -33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210 }, + { -1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040 }, + }, + { + { 3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935 }, + { 24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105 }, + { -28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814 }, + }, + }, + { + { + { 793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852 }, + { 5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581 }, + { -4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646 }, + }, + { + { 10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844 }, + { 10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025 }, + { 27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453 }, + }, + { + { -23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068 }, + { 4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192 }, + { -17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921 }, + }, + { + { -9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259 }, + { -12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426 }, + { -5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072 }, + }, + { + { -17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305 }, + { 13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832 }, + { 28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943 }, + }, + { + { -16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011 }, + { 24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447 }, + { 17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494 }, + }, + { + { -28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245 }, + { -20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859 }, + { 28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915 }, + }, + { + { 16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707 }, + { 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848 }, + { -11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224 }, + }, + }, + { + { + { -25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391 }, + { 15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215 }, + { -23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101 }, + }, + { + { 23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713 }, + { 21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849 }, + { -7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930 }, + }, + { + { -29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940 }, + { -21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031 }, + { -17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404 }, + }, + { + { -25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243 }, + { -23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116 }, + { -24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525 }, + }, + { + { -23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509 }, + { -10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883 }, + { 15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865 }, + }, + { + { -3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660 }, + { 4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273 }, + { -28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138 }, + }, + { + { -25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560 }, + { -10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135 }, + { 2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941 }, + }, + { + { -4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739 }, + { 18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756 }, + { -30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819 }, + }, + }, + { + { + { -6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347 }, + { -27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028 }, + { 21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075 }, + }, + { + { 16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799 }, + { -2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609 }, + { -25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817 }, + }, + { + { -23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989 }, + { -30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523 }, + { 4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278 }, + }, + { + { 31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045 }, + { 19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377 }, + { 24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480 }, + }, + { + { 17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016 }, + { 510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426 }, + { 18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525 }, + }, + { + { 13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396 }, + { 9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080 }, + { 12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892 }, + }, + { + { 15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275 }, + { 11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074 }, + { 20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140 }, + }, + { + { -16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717 }, + { -1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101 }, + { 24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127 }, + }, + }, + { + { + { -12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632 }, + { -26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415 }, + { -31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160 }, + }, + { + { 31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876 }, + { 22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625 }, + { -15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478 }, + }, + { + { 27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164 }, + { 26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595 }, + { -7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248 }, + }, + { + { -16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858 }, + { 15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193 }, + { 8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184 }, + }, + { + { -18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942 }, + { -1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635 }, + { 21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948 }, + }, + { + { 11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935 }, + { -25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415 }, + { -15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416 }, + }, + { + { -7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018 }, + { 4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778 }, + { 366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659 }, + }, + { + { -24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385 }, + { 18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503 }, + { 476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329 }, + }, + }, + { + { + { 20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056 }, + { -13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838 }, + { 24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948 }, + }, + { + { -3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691 }, + { -15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118 }, + { -23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517 }, + }, + { + { -20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269 }, + { -6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904 }, + { -23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589 }, + }, + { + { -28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193 }, + { -7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910 }, + { -30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930 }, + }, + { + { -7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667 }, + { 25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481 }, + { -9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876 }, + }, + { + { 22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640 }, + { -8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278 }, + { -21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112 }, + }, + { + { 26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272 }, + { 17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012 }, + { -10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221 }, + }, + { + { 30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046 }, + { 13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345 }, + { -19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310 }, + }, + }, + { + { + { 19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937 }, + { 31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636 }, + { -9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008 }, + }, + { + { -2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429 }, + { -15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576 }, + { 31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066 }, + }, + { + { -9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490 }, + { -12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104 }, + { 33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053 }, + }, + { + { 31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275 }, + { -20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511 }, + { 22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095 }, + }, + { + { -28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439 }, + { 23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939 }, + { -23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424 }, + }, + { + { 2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310 }, + { 3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608 }, + { -32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079 }, + }, + { + { -23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101 }, + { 21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418 }, + { 18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576 }, + }, + { + { 30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356 }, + { 9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996 }, + { -26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099 }, + }, + }, + { + { + { -26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728 }, + { -13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658 }, + { -10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242 }, + }, + { + { -21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001 }, + { -4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766 }, + { 18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373 }, + }, + { + { 26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458 }, + { -17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628 }, + { -13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657 }, + }, + { + { -23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062 }, + { 25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616 }, + { 31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014 }, + }, + { + { 24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383 }, + { -25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814 }, + { -20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718 }, + }, + { + { 30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417 }, + { 2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222 }, + { 33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444 }, + }, + { + { -20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597 }, + { 23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970 }, + { 1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799 }, + }, + { + { -5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647 }, + { 13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511 }, + { -29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032 }, + }, + }, + { + { + { 9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834 }, + { -23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461 }, + { 29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062 }, + }, + { + { -25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516 }, + { -20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547 }, + { -24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240 }, + }, + { + { -17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038 }, + { -33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741 }, + { 16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103 }, + }, + { + { -19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747 }, + { -1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323 }, + { 31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016 }, + }, + { + { -14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373 }, + { 15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228 }, + { -2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141 }, + }, + { + { 16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399 }, + { 11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831 }, + { -185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376 }, + }, + { + { -32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313 }, + { -18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958 }, + { -6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577 }, + }, + { + { -22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743 }, + { 29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684 }, + { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 }, + }, + }, + } ; + +namespace { + +inline uint8_t equal(int8_t b, int8_t c) + { + uint8_t ub = b; + uint8_t uc = c; + uint8_t x = ub ^ uc; /* 0: yes; 1..255: no */ + uint32_t y = x; /* 0: yes; 1..255: no */ + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + return static_cast(y); + } + +inline int32_t equal32(int8_t b, int8_t c) + { + return -static_cast(equal(b, c)); + } + +inline uint8_t negative(int8_t b) + { + uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return static_cast(x); + } + +inline void ge_precomp_0(ge_precomp* h) + { + fe_1(h->yplusx); + fe_1(h->yminusx); + fe_0(h->xy2d); + } + +inline void select(ge_precomp* t, + const ge_precomp* base, + int8_t b) + { + const uint8_t bnegative = negative(b); + const uint8_t babs = b - ((-static_cast(bnegative) & b) * 2); + const int32_t neg_mask = equal32(bnegative, 1); + + const int32_t mask1 = equal32(babs, 1); + const int32_t mask2 = equal32(babs, 2); + const int32_t mask3 = equal32(babs, 3); + const int32_t mask4 = equal32(babs, 4); + const int32_t mask5 = equal32(babs, 5); + const int32_t mask6 = equal32(babs, 6); + const int32_t mask7 = equal32(babs, 7); + const int32_t mask8 = equal32(babs, 8); + + ge_precomp_0(t); + + for(size_t i = 0; i != 10; ++i) + { + t->yplusx[i] = t->yplusx[i] ^ + ((t->yplusx[i] ^ base[0].yplusx[i]) & mask1) ^ + ((t->yplusx[i] ^ base[1].yplusx[i]) & mask2) ^ + ((t->yplusx[i] ^ base[2].yplusx[i]) & mask3) ^ + ((t->yplusx[i] ^ base[3].yplusx[i]) & mask4) ^ + ((t->yplusx[i] ^ base[4].yplusx[i]) & mask5) ^ + ((t->yplusx[i] ^ base[5].yplusx[i]) & mask6) ^ + ((t->yplusx[i] ^ base[6].yplusx[i]) & mask7) ^ + ((t->yplusx[i] ^ base[7].yplusx[i]) & mask8); + + t->yminusx[i] = t->yminusx[i] ^ + ((t->yminusx[i] ^ base[0].yminusx[i]) & mask1) ^ + ((t->yminusx[i] ^ base[1].yminusx[i]) & mask2) ^ + ((t->yminusx[i] ^ base[2].yminusx[i]) & mask3) ^ + ((t->yminusx[i] ^ base[3].yminusx[i]) & mask4) ^ + ((t->yminusx[i] ^ base[4].yminusx[i]) & mask5) ^ + ((t->yminusx[i] ^ base[5].yminusx[i]) & mask6) ^ + ((t->yminusx[i] ^ base[6].yminusx[i]) & mask7) ^ + ((t->yminusx[i] ^ base[7].yminusx[i]) & mask8); + + t->xy2d[i] = t->xy2d[i] ^ + ((t->xy2d[i] ^ base[0].xy2d[i]) & mask1) ^ + ((t->xy2d[i] ^ base[1].xy2d[i]) & mask2) ^ + ((t->xy2d[i] ^ base[2].xy2d[i]) & mask3) ^ + ((t->xy2d[i] ^ base[3].xy2d[i]) & mask4) ^ + ((t->xy2d[i] ^ base[4].xy2d[i]) & mask5) ^ + ((t->xy2d[i] ^ base[5].xy2d[i]) & mask6) ^ + ((t->xy2d[i] ^ base[6].xy2d[i]) & mask7) ^ + ((t->xy2d[i] ^ base[7].xy2d[i]) & mask8); + } + + fe minus_xy2d; + fe_neg(minus_xy2d, t->xy2d); + + // If negative have to swap yminusx and yplusx + for(size_t i = 0; i != 10; ++i) + { + int32_t t_yplusx = t->yplusx[i] ^ ((t->yplusx[i] ^ t->yminusx[i]) & neg_mask); + int32_t t_yminusx = t->yminusx[i] ^ ((t->yminusx[i] ^ t->yplusx[i]) & neg_mask); + + t->yplusx[i] = t_yplusx; + t->yminusx[i] = t_yminusx; + t->xy2d[i] = t->xy2d[i] ^ ((t->xy2d[i] ^ minus_xy2d[i]) & neg_mask); + } + } + +void ge_p3_tobytes(uint8_t* s, const ge_p3* h) + { + fe recip; + fe x; + fe y; + + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; + } + +} + +/* +h = a * B +where a = a[0]+256*a[1]+...+256^31 a[31] +B is the Ed25519 base point (x,4/5) with x positive. + +Preconditions: + a[31] <= 127 +*/ + +void ge_scalarmult_base(uint8_t out[32], const uint8_t a[32]) + { + int8_t e[64]; + int8_t carry; + ge_p1p1 r; + ge_p2 s; + ge_p3 h; + ge_precomp t; + int i; + + for(i = 0; i < 32; ++i) + { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for(i = 0; i < 63; ++i) + { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(&h); + for(i = 1; i < 64; i += 2) + { + select(&t, B_precomp[i / 2], e[i]); + ge_madd(&r, &h, &t); + ge_p1p1_to_p3(&h, &r); + } + + ge_p3_dbl(&r, &h); + ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + ge_p1p1_to_p3(&h, &r); + + for(i = 0; i < 64; i += 2) + { + select(&t, B_precomp[i / 2], e[i]); + ge_madd(&r, &h, &t); + ge_p1p1_to_p3(&h, &r); + } + + ge_p3_tobytes(out, &h); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/info.txt b/comm/third_party/botan/src/lib/pubkey/ed25519/info.txt new file mode 100644 index 0000000000..f17b86cbf8 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/info.txt @@ -0,0 +1,17 @@ + +ED25519 -> 20170607 + + + +sha2_64 + + + +ed25519.h + + + +ed25519_fe.h +ed25519_internal.h + + diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/sc_muladd.cpp b/comm/third_party/botan/src/lib/pubkey/ed25519/sc_muladd.cpp new file mode 100644 index 0000000000..4a88be22de --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/sc_muladd.cpp @@ -0,0 +1,221 @@ +/* +* Ed25519 +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + +Output: + s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l + where l = 2^252 + 27742317777372353535851937790883648493. +*/ + +void sc_muladd(uint8_t* s, const uint8_t* a, const uint8_t* b, const uint8_t* c) + { + const int32_t MASK = 0x1fffff; + + const int64_t a0 = MASK & load_3(a); + const int64_t a1 = MASK & (load_4(a + 2) >> 5); + const int64_t a2 = MASK & (load_3(a + 5) >> 2); + const int64_t a3 = MASK & (load_4(a + 7) >> 7); + const int64_t a4 = MASK & (load_4(a + 10) >> 4); + const int64_t a5 = MASK & (load_3(a + 13) >> 1); + const int64_t a6 = MASK & (load_4(a + 15) >> 6); + const int64_t a7 = MASK & (load_3(a + 18) >> 3); + const int64_t a8 = MASK & load_3(a + 21); + const int64_t a9 = MASK & (load_4(a + 23) >> 5); + const int64_t a10 = MASK & (load_3(a + 26) >> 2); + const int64_t a11 = (load_4(a + 28) >> 7); + const int64_t b0 = MASK & load_3(b); + const int64_t b1 = MASK & (load_4(b + 2) >> 5); + const int64_t b2 = MASK & (load_3(b + 5) >> 2); + const int64_t b3 = MASK & (load_4(b + 7) >> 7); + const int64_t b4 = MASK & (load_4(b + 10) >> 4); + const int64_t b5 = MASK & (load_3(b + 13) >> 1); + const int64_t b6 = MASK & (load_4(b + 15) >> 6); + const int64_t b7 = MASK & (load_3(b + 18) >> 3); + const int64_t b8 = MASK & load_3(b + 21); + const int64_t b9 = MASK & (load_4(b + 23) >> 5); + const int64_t b10 = MASK & (load_3(b + 26) >> 2); + const int64_t b11 = (load_4(b + 28) >> 7); + const int64_t c0 = MASK & load_3(c); + const int64_t c1 = MASK & (load_4(c + 2) >> 5); + const int64_t c2 = MASK & (load_3(c + 5) >> 2); + const int64_t c3 = MASK & (load_4(c + 7) >> 7); + const int64_t c4 = MASK & (load_4(c + 10) >> 4); + const int64_t c5 = MASK & (load_3(c + 13) >> 1); + const int64_t c6 = MASK & (load_4(c + 15) >> 6); + const int64_t c7 = MASK & (load_3(c + 18) >> 3); + const int64_t c8 = MASK & load_3(c + 21); + const int64_t c9 = MASK & (load_4(c + 23) >> 5); + const int64_t c10 = MASK & (load_3(c + 26) >> 2); + const int64_t c11 = (load_4(c + 28) >> 7); + + int64_t s0 = c0 + a0*b0; + int64_t s1 = c1 + a0*b1 + a1*b0; + int64_t s2 = c2 + a0*b2 + a1*b1 + a2*b0; + int64_t s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0; + int64_t s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0; + int64_t s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0; + int64_t s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0; + int64_t s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0; + int64_t s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0; + int64_t s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0; + int64_t s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0; + int64_t s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0; + int64_t s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1; + int64_t s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2; + int64_t s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3; + int64_t s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4; + int64_t s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5; + int64_t s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6; + int64_t s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7; + int64_t s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8; + int64_t s20 = a9*b11 + a10*b10 + a11*b9; + int64_t s21 = a10*b11 + a11*b10; + int64_t s22 = a11*b11; + int64_t s23 = 0; + + carry<21>(s0, s1); + carry<21>(s2, s3); + carry<21>(s4, s5); + carry<21>(s6, s7); + carry<21>(s8, s9); + carry<21>(s10, s11); + carry<21>(s12, s13); + carry<21>(s14, s15); + carry<21>(s16, s17); + carry<21>(s18, s19); + carry<21>(s20, s21); + carry<21>(s22, s23); + + carry<21>(s1, s2); + carry<21>(s3, s4); + carry<21>(s5, s6); + carry<21>(s7, s8); + carry<21>(s9, s10); + carry<21>(s11, s12); + carry<21>(s13, s14); + carry<21>(s15, s16); + carry<21>(s17, s18); + carry<21>(s19, s20); + carry<21>(s21, s22); + + redc_mul(s11, s12, s13, s14, s15, s16, s23); + redc_mul(s10, s11, s12, s13, s14, s15, s22); + redc_mul( s9, s10, s11, s12, s13, s14, s21); + redc_mul( s8, s9, s10, s11, s12, s13, s20); + redc_mul( s7, s8, s9, s10, s11, s12, s19); + redc_mul( s6, s7, s8, s9, s10, s11, s18); + + carry<21>(s6, s7); + carry<21>(s8, s9); + carry<21>(s10, s11); + carry<21>(s12, s13); + carry<21>(s14, s15); + carry<21>(s16, s17); + + carry<21>(s7, s8); + carry<21>(s9, s10); + carry<21>(s11, s12); + carry<21>(s13, s14); + carry<21>(s15, s16); + + redc_mul(s5, s6, s7, s8, s9, s10, s17); + redc_mul(s4, s5, s6, s7, s8, s9, s16); + redc_mul(s3, s4, s5, s6, s7, s8, s15); + redc_mul(s2, s3, s4, s5, s6, s7, s14); + redc_mul(s1, s2, s3, s4, s5, s6, s13); + redc_mul(s0, s1, s2, s3, s4, s5, s12); + + carry<21>(s0, s1); + carry<21>(s2, s3); + carry<21>(s4, s5); + carry<21>(s6, s7); + carry<21>(s8, s9); + carry<21>(s10, s11); + + carry<21>(s1, s2); + carry<21>(s3, s4); + carry<21>(s5, s6); + carry<21>(s7, s8); + carry<21>(s9, s10); + carry<21>(s11, s12); + + redc_mul(s0, s1, s2, s3, s4, s5, s12); + + carry0<21>(s0, s1); + carry0<21>(s1, s2); + carry0<21>(s2, s3); + carry0<21>(s3, s4); + carry0<21>(s4, s5); + carry0<21>(s5, s6); + carry0<21>(s6, s7); + carry0<21>(s7, s8); + carry0<21>(s8, s9); + carry0<21>(s9, s10); + carry0<21>(s10, s11); + carry0<21>(s11, s12); + + redc_mul(s0, s1, s2, s3, s4, s5, s12); + + carry0<21>(s0, s1); + carry0<21>(s1, s2); + carry0<21>(s2, s3); + carry0<21>(s3, s4); + carry0<21>(s4, s5); + carry0<21>(s5, s6); + carry0<21>(s6, s7); + carry0<21>(s7, s8); + carry0<21>(s8, s9); + carry0<21>(s9, s10); + carry0<21>(s10, s11); + + s[0] = static_cast(s0 >> 0); + s[1] = static_cast(s0 >> 8); + s[2] = static_cast((s0 >> 16) | (s1 << 5)); + s[3] = static_cast(s1 >> 3); + s[4] = static_cast(s1 >> 11); + s[5] = static_cast((s1 >> 19) | (s2 << 2)); + s[6] = static_cast(s2 >> 6); + s[7] = static_cast((s2 >> 14) | (s3 << 7)); + s[8] = static_cast(s3 >> 1); + s[9] = static_cast(s3 >> 9); + s[10] = static_cast((s3 >> 17) | (s4 << 4)); + s[11] = static_cast(s4 >> 4); + s[12] = static_cast(s4 >> 12); + s[13] = static_cast((s4 >> 20) | (s5 << 1)); + s[14] = static_cast(s5 >> 7); + s[15] = static_cast((s5 >> 15) | (s6 << 6)); + s[16] = static_cast(s6 >> 2); + s[17] = static_cast(s6 >> 10); + s[18] = static_cast((s6 >> 18) | (s7 << 3)); + s[19] = static_cast(s7 >> 5); + s[20] = static_cast(s7 >> 13); + s[21] = static_cast(s8 >> 0); + s[22] = static_cast(s8 >> 8); + s[23] = static_cast((s8 >> 16) | (s9 << 5)); + s[24] = static_cast(s9 >> 3); + s[25] = static_cast(s9 >> 11); + s[26] = static_cast((s9 >> 19) | (s10 << 2)); + s[27] = static_cast(s10 >> 6); + s[28] = static_cast((s10 >> 14) | (s11 << 7)); + s[29] = static_cast(s11 >> 1); + s[30] = static_cast(s11 >> 9); + s[31] = static_cast(s11 >> 17); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/ed25519/sc_reduce.cpp b/comm/third_party/botan/src/lib/pubkey/ed25519/sc_reduce.cpp new file mode 100644 index 0000000000..c69dd5eccd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/ed25519/sc_reduce.cpp @@ -0,0 +1,159 @@ +/* +* Ed25519 +* (C) 2017 Ribose Inc +* +* Based on the public domain code from SUPERCOP ref10 by +* Peter Schwabe, Daniel J. Bernstein, Niels Duif, Tanja Lange, Bo-Yin Yang +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +/* +Input: + s[0]+256*s[1]+...+256^63*s[63] = s + +Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. +*/ + +void sc_reduce(uint8_t* s) + { + const uint32_t MASK = 0x1fffff; + + int64_t s0 = MASK & load_3(s); + int64_t s1 = MASK & (load_4(s + 2) >> 5); + int64_t s2 = MASK & (load_3(s + 5) >> 2); + int64_t s3 = MASK & (load_4(s + 7) >> 7); + int64_t s4 = MASK & (load_4(s + 10) >> 4); + int64_t s5 = MASK & (load_3(s + 13) >> 1); + int64_t s6 = MASK & (load_4(s + 15) >> 6); + int64_t s7 = MASK & (load_3(s + 18) >> 3); + int64_t s8 = MASK & load_3(s + 21); + int64_t s9 = MASK & (load_4(s + 23) >> 5); + int64_t s10 = MASK & (load_3(s + 26) >> 2); + int64_t s11 = MASK & (load_4(s + 28) >> 7); + int64_t s12 = MASK & (load_4(s + 31) >> 4); + int64_t s13 = MASK & (load_3(s + 34) >> 1); + int64_t s14 = MASK & (load_4(s + 36) >> 6); + int64_t s15 = MASK & (load_3(s + 39) >> 3); + int64_t s16 = MASK & load_3(s + 42); + int64_t s17 = MASK & (load_4(s + 44) >> 5); + int64_t s18 = MASK & (load_3(s + 47) >> 2); + int64_t s19 = MASK & (load_4(s + 49) >> 7); + int64_t s20 = MASK & (load_4(s + 52) >> 4); + int64_t s21 = MASK & (load_3(s + 55) >> 1); + int64_t s22 = MASK & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + + redc_mul(s11, s12, s13, s14, s15, s16, s23); + redc_mul(s10, s11, s12, s13, s14, s15, s22); + redc_mul( s9, s10, s11, s12, s13, s14, s21); + redc_mul( s8, s9, s10, s11, s12, s13, s20); + redc_mul( s7, s8, s9, s10, s11, s12, s19); + redc_mul( s6, s7, s8, s9, s10, s11, s18); + + carry<21>(s6, s7); + carry<21>(s8, s9); + carry<21>(s10, s11); + carry<21>(s12, s13); + carry<21>(s14, s15); + carry<21>(s16, s17); + + carry<21>(s7, s8); + carry<21>(s9, s10); + carry<21>(s11, s12); + carry<21>(s13, s14); + carry<21>(s15, s16); + + redc_mul(s5, s6, s7, s8, s9, s10, s17); + redc_mul(s4, s5, s6, s7, s8, s9, s16); + redc_mul(s3, s4, s5, s6, s7, s8, s15); + redc_mul(s2, s3, s4, s5, s6, s7, s14); + redc_mul(s1, s2, s3, s4, s5, s6, s13); + redc_mul(s0, s1, s2, s3, s4, s5, s12); + + carry<21>(s0, s1); + carry<21>(s2, s3); + carry<21>(s4, s5); + carry<21>(s6, s7); + carry<21>(s8, s9); + carry<21>(s10, s11); + + carry<21>(s1, s2); + carry<21>(s3, s4); + carry<21>(s5, s6); + carry<21>(s7, s8); + carry<21>(s9, s10); + carry<21>(s11, s12); + + redc_mul(s0, s1, s2, s3, s4, s5, s12); + + carry0<21>(s0, s1); + carry0<21>(s1, s2); + carry0<21>(s2, s3); + carry0<21>(s3, s4); + carry0<21>(s4, s5); + carry0<21>(s5, s6); + carry0<21>(s6, s7); + carry0<21>(s7, s8); + carry0<21>(s8, s9); + carry0<21>(s9, s10); + carry0<21>(s10, s11); + carry0<21>(s11, s12); + + redc_mul(s0, s1, s2, s3, s4, s5, s12); + + carry0<21>(s0, s1); + carry0<21>(s1, s2); + carry0<21>(s2, s3); + carry0<21>(s3, s4); + carry0<21>(s4, s5); + carry0<21>(s5, s6); + carry0<21>(s6, s7); + carry0<21>(s7, s8); + carry0<21>(s8, s9); + carry0<21>(s9, s10); + carry0<21>(s10, s11); + carry0<21>(s11, s12); + + s[0] = static_cast(s0 >> 0); + s[1] = static_cast(s0 >> 8); + s[2] = static_cast((s0 >> 16) | (s1 << 5)); + s[3] = static_cast(s1 >> 3); + s[4] = static_cast(s1 >> 11); + s[5] = static_cast((s1 >> 19) | (s2 << 2)); + s[6] = static_cast(s2 >> 6); + s[7] = static_cast((s2 >> 14) | (s3 << 7)); + s[8] = static_cast(s3 >> 1); + s[9] = static_cast(s3 >> 9); + s[10] = static_cast((s3 >> 17) | (s4 << 4)); + s[11] = static_cast(s4 >> 4); + s[12] = static_cast(s4 >> 12); + s[13] = static_cast((s4 >> 20) | (s5 << 1)); + s[14] = static_cast(s5 >> 7); + s[15] = static_cast((s5 >> 15) | (s6 << 6)); + s[16] = static_cast(s6 >> 2); + s[17] = static_cast(s6 >> 10); + s[18] = static_cast((s6 >> 18) | (s7 << 3)); + s[19] = static_cast(s7 >> 5); + s[20] = static_cast(s7 >> 13); + s[21] = static_cast(s8 >> 0); + s[22] = static_cast(s8 >> 8); + s[23] = static_cast((s8 >> 16) | (s9 << 5)); + s[24] = static_cast(s9 >> 3); + s[25] = static_cast(s9 >> 11); + s[26] = static_cast((s9 >> 19) | (s10 << 2)); + s[27] = static_cast(s10 >> 6); + s[28] = static_cast((s10 >> 14) | (s11 << 7)); + s[29] = static_cast(s11 >> 1); + s[30] = static_cast(s11 >> 9); + s[31] = static_cast(s11 >> 17); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.cpp b/comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.cpp new file mode 100644 index 0000000000..21e126031a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.cpp @@ -0,0 +1,213 @@ +/* +* ElGamal +* (C) 1999-2007,2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* ElGamal_PublicKey Constructor +*/ +ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& group, const BigInt& y) : + DL_Scheme_PublicKey(group, y) + { + } + +/* +* ElGamal_PrivateKey Constructor +*/ +ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& x) + { + m_x = x; + m_group = group; + + if(m_x.is_zero()) + { + const size_t exp_bits = m_group.exponent_bits(); + m_x.randomize(rng, exp_bits); + m_y = m_group.power_g_p(m_x, exp_bits); + } + else + { + m_y = m_group.power_g_p(m_x, m_group.p_bits()); + } + } + +ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + m_y = m_group.power_g_p(m_x, m_group.p_bits()); + } + +/* +* Check Private ElGamal Parameters +*/ +bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + return KeyPair::encryption_consistency_check(rng, *this, "OAEP(SHA-256)"); + } + +namespace { + +/** +* ElGamal encryption operation +*/ +class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME + { + public: + + size_t ciphertext_length(size_t) const override { return 2*m_group.p_bytes(); } + + size_t max_raw_input_bits() const override { return m_group.p_bits() - 1; } + + ElGamal_Encryption_Operation(const ElGamal_PublicKey& key, const std::string& eme); + + secure_vector raw_encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + private: + const DL_Group m_group; + std::shared_ptr m_monty_y_p; + }; + +ElGamal_Encryption_Operation::ElGamal_Encryption_Operation(const ElGamal_PublicKey& key, + const std::string& eme) : + PK_Ops::Encryption_with_EME(eme), + m_group(key.get_group()) + { + const size_t powm_window = 4; + m_monty_y_p = monty_precompute(key.get_group().monty_params_p(), + key.get_y(), + powm_window); + } + +secure_vector +ElGamal_Encryption_Operation::raw_encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + BigInt m(msg, msg_len); + + if(m >= m_group.get_p()) + throw Invalid_Argument("ElGamal encryption: Input is too large"); + + /* + Some ElGamal implementations generate keys where using short exponents + is unsafe. Always use full length exponents to avoid this. + + See https://eprint.iacr.org/2021/923 for details. + */ + const size_t k_bits = m_group.p_bits() - 1; + const BigInt k(rng, k_bits, false); + + const BigInt a = m_group.power_g_p(k, k_bits); + const BigInt b = m_group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits)); + + return BigInt::encode_fixed_length_int_pair(a, b, m_group.p_bytes()); + } + +/** +* ElGamal decryption operation +*/ +class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME + { + public: + + ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, + const std::string& eme, + RandomNumberGenerator& rng); + + size_t plaintext_length(size_t) const override { return m_group.p_bytes(); } + + secure_vector raw_decrypt(const uint8_t msg[], size_t msg_len) override; + private: + BigInt powermod_x_p(const BigInt& v) const + { + const size_t powm_window = 4; + auto powm_v_p = monty_precompute(m_monty_p, v, powm_window); + return monty_execute(*powm_v_p, m_x, m_x_bits); + } + + const DL_Group m_group; + const BigInt& m_x; + const size_t m_x_bits; + std::shared_ptr m_monty_p; + Blinder m_blinder; + }; + +ElGamal_Decryption_Operation::ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, + const std::string& eme, + RandomNumberGenerator& rng) : + PK_Ops::Decryption_with_EME(eme), + m_group(key.get_group()), + m_x(key.get_x()), + m_x_bits(m_x.bits()), + m_monty_p(key.get_group().monty_params_p()), + m_blinder(m_group.get_p(), + rng, + [](const BigInt& k) { return k; }, + [this](const BigInt& k) { return powermod_x_p(k); }) + { + } + +secure_vector +ElGamal_Decryption_Operation::raw_decrypt(const uint8_t msg[], size_t msg_len) + { + const size_t p_bytes = m_group.p_bytes(); + + if(msg_len != 2 * p_bytes) + throw Invalid_Argument("ElGamal decryption: Invalid message"); + + BigInt a(msg, p_bytes); + const BigInt b(msg + p_bytes, p_bytes); + + if(a >= m_group.get_p() || b >= m_group.get_p()) + throw Invalid_Argument("ElGamal decryption: Invalid message"); + + a = m_blinder.blind(a); + + const BigInt r = m_group.multiply_mod_p(m_group.inverse_mod_p(powermod_x_p(a)), b); + + return BigInt::encode_1363(m_blinder.unblind(r), p_bytes); + } + +} + +std::unique_ptr +ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ElGamal_Encryption_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +ElGamal_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new ElGamal_Decryption_Operation(*this, params, rng)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.h b/comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.h new file mode 100644 index 0000000000..e4d932f6aa --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/elgamal/elgamal.h @@ -0,0 +1,85 @@ +/* +* ElGamal +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ELGAMAL_H_ +#define BOTAN_ELGAMAL_H_ + +#include + +namespace Botan { + +/** +* ElGamal Public Key +*/ +class BOTAN_PUBLIC_API(2,0) ElGamal_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const override { return "ElGamal"; } + DL_Group::Format group_format() const override { return DL_Group::ANSI_X9_42; } + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + ElGamal_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + {} + + /** + * Create a public key. + * @param group the underlying DL group + * @param y the public value y = g^x mod p + */ + ElGamal_PublicKey(const DL_Group& group, const BigInt& y); + + std::unique_ptr + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + protected: + ElGamal_PublicKey() = default; + }; + +/** +* ElGamal Private Key +*/ +class BOTAN_PUBLIC_API(2,0) ElGamal_PrivateKey final : public ElGamal_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const override; + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded key bits in ANSI X9.42 format + */ + ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Create a private key. + * @param rng random number generator to use + * @param group the group to be used in the key + * @param priv_key the key's secret value (or if zero, generate a new key) + */ + ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& priv_key = 0); + + std::unique_ptr + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/elgamal/info.txt b/comm/third_party/botan/src/lib/pubkey/elgamal/info.txt new file mode 100644 index 0000000000..0b36658bcd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/elgamal/info.txt @@ -0,0 +1,10 @@ + +ELGAMAL -> 20131128 + + + +dl_algo +dl_group +keypair +numbertheory + diff --git a/comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.cpp b/comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.cpp new file mode 100644 index 0000000000..d1f8fc7867 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.cpp @@ -0,0 +1,253 @@ +/* +* GOST 34.10-2012 +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +std::vector GOST_3410_PublicKey::public_key_bits() const + { + const BigInt x = public_point().get_affine_x(); + const BigInt y = public_point().get_affine_y(); + + size_t part_size = std::max(x.bytes(), y.bytes()); + + std::vector bits(2*part_size); + + x.binary_encode(&bits[part_size - x.bytes()]); + y.binary_encode(&bits[2*part_size - y.bytes()]); + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + std::vector output; + DER_Encoder(output).encode(bits, OCTET_STRING); + return output; + } + +std::string GOST_3410_PublicKey::algo_name() const + { + const size_t p_bits = domain().get_p_bits(); + + if(p_bits == 256 || p_bits == 512) + return "GOST-34.10-2012-" + std::to_string(p_bits); + else + throw Encoding_Error("GOST-34.10-2012 is not defined for parameters of this size"); + } + +AlgorithmIdentifier GOST_3410_PublicKey::algorithm_identifier() const + { + std::vector params; + + const OID gost_oid = get_oid(); + const OID domain_oid = domain().get_curve_oid(); + + DER_Encoder(params).start_cons(SEQUENCE).encode(domain_oid).end_cons(); + + return AlgorithmIdentifier(gost_oid, params); + } + +GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) + { + OID ecc_param_id; + + // The parameters also includes hash and cipher OIDs + BER_Decoder(alg_id.get_parameters()).start_cons(SEQUENCE).decode(ecc_param_id); + + m_domain_params = EC_Group(ecc_param_id); + + const size_t p_bits = m_domain_params.get_p_bits(); + if(p_bits != 256 && p_bits != 512) + throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + + std::to_string(p_bits)); + + secure_vector bits; + BER_Decoder(key_bits).decode(bits, OCTET_STRING); + + const size_t part_size = bits.size() / 2; + + // Keys are stored in little endian format (WTF) + for(size_t i = 0; i != part_size / 2; ++i) + { + std::swap(bits[i], bits[part_size-1-i]); + std::swap(bits[part_size+i], bits[2*part_size-1-i]); + } + + BigInt x(bits.data(), part_size); + BigInt y(&bits[part_size], part_size); + + m_public_key = domain().point(x, y); + + BOTAN_ASSERT(m_public_key.on_the_curve(), + "Loaded GOST 34.10 public key is on the curve"); + } + +GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x) : + EC_PrivateKey(rng, domain, x) + { + const size_t p_bits = m_domain_params.get_p_bits(); + if(p_bits != 256 && p_bits != 512) + throw Decoding_Error("GOST-34.10-2012 is not defined for parameters of size " + + std::to_string(p_bits)); + } + +namespace { + +BigInt decode_le(const uint8_t msg[], size_t msg_len) + { + secure_vector msg_le(msg, msg + msg_len); + + for(size_t i = 0; i != msg_le.size() / 2; ++i) + std::swap(msg_le[i], msg_le[msg_le.size()-1-i]); + + return BigInt(msg_le.data(), msg_le.size()); + } + +/** +* GOST-34.10 signature operation +*/ +class GOST_3410_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410, + const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(gost_3410.domain()), + m_x(gost_3410.private_value()) + {} + + size_t signature_length() const override { return 2*m_group.get_order_bytes(); } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + private: + const EC_Group m_group; + const BigInt& m_x; + std::vector m_ws; + }; + +secure_vector +GOST_3410_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt k = m_group.random_scalar(rng); + + BigInt e = decode_le(msg, msg_len); + + e = m_group.mod_order(e); + if(e == 0) + e = 1; + + const BigInt r = m_group.mod_order( + m_group.blinded_base_point_multiply_x(k, rng, m_ws)); + + const BigInt s = m_group.mod_order( + m_group.multiply_mod_order(r, m_x) + + m_group.multiply_mod_order(k, e)); + + if(r == 0 || s == 0) + throw Internal_Error("GOST 34.10 signature generation failed, r/s equal to zero"); + + return BigInt::encode_fixed_length_int_pair(s, r, m_group.get_order_bytes()); + } + +/** +* GOST-34.10 verification operation +*/ +class GOST_3410_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + + GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(gost.domain()), + m_gy_mul(m_group.get_base_point(), gost.public_point()) + {} + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const EC_Group m_group; + const PointGFp_Multi_Point_Precompute m_gy_mul; + }; + +bool GOST_3410_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) + { + if(sig_len != m_group.get_order_bytes() * 2) + return false; + + const BigInt s(sig, sig_len / 2); + const BigInt r(sig + sig_len / 2, sig_len / 2); + + const BigInt& order = m_group.get_order(); + + if(r <= 0 || r >= order || s <= 0 || s >= order) + return false; + + BigInt e = decode_le(msg, msg_len); + e = m_group.mod_order(e); + if(e == 0) + e = 1; + + const BigInt v = m_group.inverse_mod_order(e); + + const BigInt z1 = m_group.multiply_mod_order(s, v); + const BigInt z2 = m_group.multiply_mod_order(-r, v); + + const PointGFp R = m_gy_mul.multi_exp(z1, z2); + + if(R.is_zero()) + return false; + + return (R.get_affine_x() == r); + } + +} + +std::unique_ptr +GOST_3410_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new GOST_3410_Verification_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +GOST_3410_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new GOST_3410_Signature_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.h b/comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.h new file mode 100644 index 0000000000..9eedaf1224 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/gost_3410/gost_3410.h @@ -0,0 +1,104 @@ +/* +* GOST 34.10-2001 +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_GOST_3410_KEY_H_ +#define BOTAN_GOST_3410_KEY_H_ + +#include + +namespace Botan { + +/** +* GOST-34.10 Public Key +*/ +class BOTAN_PUBLIC_API(2,0) GOST_3410_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + GOST_3410_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits); + + /** + * Get this keys algorithm name. + * @result this keys algorithm name + */ + std::string algo_name() const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + Signature_Format default_x509_signature_format() const override + { return IEEE_1363; } + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + + protected: + GOST_3410_PublicKey() = default; + }; + +/** +* GOST-34.10 Private Key +*/ +class BOTAN_PUBLIC_API(2,0) GOST_3410_PrivateKey final : + public GOST_3410_PublicKey, public EC_PrivateKey + { + public: + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + GOST_3410_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + GOST_3410_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0); + + AlgorithmIdentifier pkcs8_algorithm_identifier() const override + { return EC_PublicKey::algorithm_identifier(); } + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/gost_3410/info.txt b/comm/third_party/botan/src/lib/pubkey/gost_3410/info.txt new file mode 100644 index 0000000000..805e31485a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/gost_3410/info.txt @@ -0,0 +1,12 @@ + +GOST_34_10_2001 -> 20131128 +GOST_34_10_2012 -> 20190801 + + + +asn1 +ec_group +ecc_key +numbertheory +rng + diff --git a/comm/third_party/botan/src/lib/pubkey/info.txt b/comm/third_party/botan/src/lib/pubkey/info.txt new file mode 100644 index 0000000000..c6e8036e59 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/info.txt @@ -0,0 +1,31 @@ + +PUBLIC_KEY_CRYPTO -> 20131128 + + + +blinding.h +pk_algs.h +pk_keys.h +pk_ops.h +pk_ops_fwd.h +pkcs8.h +pubkey.h +workfactor.h +x509_key.h + + + +pk_ops_impl.h + + + +asn1 +bigint +kdf +pem +pk_pad +numbertheory +rng +hash +hex + diff --git a/comm/third_party/botan/src/lib/pubkey/keypair/info.txt b/comm/third_party/botan/src/lib/pubkey/keypair/info.txt new file mode 100644 index 0000000000..ed85abf691 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/keypair/info.txt @@ -0,0 +1,6 @@ + +KEYPAIR_TESTING -> 20131128 + + + + diff --git a/comm/third_party/botan/src/lib/pubkey/keypair/keypair.cpp b/comm/third_party/botan/src/lib/pubkey/keypair/keypair.cpp new file mode 100644 index 0000000000..d5cd001720 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/keypair/keypair.cpp @@ -0,0 +1,85 @@ +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace KeyPair { + +/* +* Check an encryption key pair for consistency +*/ +bool encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding) + { + PK_Encryptor_EME encryptor(public_key, rng, padding); + PK_Decryptor_EME decryptor(private_key, rng, padding); + + /* + Weird corner case, if the key is too small to encrypt anything at + all. This can happen with very small RSA keys with PSS + */ + if(encryptor.maximum_input_size() == 0) + return true; + + std::vector plaintext; + rng.random_vec(plaintext, encryptor.maximum_input_size() - 1); + + std::vector ciphertext = encryptor.encrypt(plaintext, rng); + if(ciphertext == plaintext) + return false; + + std::vector decrypted = unlock(decryptor.decrypt(ciphertext)); + + return (plaintext == decrypted); + } + +/* +* Check a signature key pair for consistency +*/ +bool signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding) + { + PK_Signer signer(private_key, rng, padding); + PK_Verifier verifier(public_key, padding); + + std::vector message(32); + rng.randomize(message.data(), message.size()); + + std::vector signature; + + try + { + signature = signer.sign_message(message, rng); + } + catch(Encoding_Error&) + { + return false; + } + + if(!verifier.verify_message(message, signature)) + return false; + + // Now try to check a corrupt signature, ensure it does not succeed + ++signature[0]; + + if(verifier.verify_message(message, signature)) + return false; + + return true; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/pubkey/keypair/keypair.h b/comm/third_party/botan/src/lib/pubkey/keypair/keypair.h new file mode 100644 index 0000000000..6900faa359 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/keypair/keypair.h @@ -0,0 +1,85 @@ +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEYPAIR_CHECKS_H_ +#define BOTAN_KEYPAIR_CHECKS_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(keypair.h) + +namespace Botan { + +namespace KeyPair { + +/** +* Tests whether the key is consistent for encryption; whether +* encrypting and then decrypting gives to the original plaintext. +* @param rng the rng to use +* @param private_key the key to test +* @param public_key the key to test +* @param padding the encryption padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_PUBLIC_API(2,0) bool +encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding); + +/** +* Tests whether the key is consistent for signatures; whether a +* signature can be created and then verified +* @param rng the rng to use +* @param private_key the key to test +* @param public_key the key to test +* @param padding the signature padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_PUBLIC_API(2,0) bool +signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding); + +/** +* Tests whether the key is consistent for encryption; whether +* encrypting and then decrypting gives to the original plaintext. +* @param rng the rng to use +* @param key the key to test +* @param padding the encryption padding method to use +* @return true if consistent otherwise false +*/ +inline bool +encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + return encryption_consistency_check(rng, key, key, padding); + } + +/** +* Tests whether the key is consistent for signatures; whether a +* signature can be created and then verified +* @param rng the rng to use +* @param key the key to test +* @param padding the signature padding method to use +* @return true if consistent otherwise false +*/ +inline bool +signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + return signature_consistency_check(rng, key, key, padding); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/mce/code_based_key_gen.cpp b/comm/third_party/botan/src/lib/pubkey/mce/code_based_key_gen.cpp new file mode 100644 index 0000000000..8dc3a3178b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/code_based_key_gen.cpp @@ -0,0 +1,298 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * (C) 2015 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class binary_matrix final + { + public: + binary_matrix(size_t m_rown, size_t m_coln); + + void row_xor(size_t a, size_t b); + secure_vector row_reduced_echelon_form(); + + /** + * return the coefficient out of F_2 + */ + uint32_t coef(size_t i, size_t j) + { + return (m_elem[(i) * m_rwdcnt + (j) / 32] >> (j % 32)) & 1; + } + + void set_coef_to_one(size_t i, size_t j) + { + m_elem[(i) * m_rwdcnt + (j) / 32] |= (static_cast(1) << ((j) % 32)) ; + } + + void toggle_coeff(size_t i, size_t j) + { + m_elem[(i) * m_rwdcnt + (j) / 32] ^= (static_cast(1) << ((j) % 32)) ; + } + + size_t rows() const { return m_rown; } + + size_t columns() const { return m_coln; } + + private: + size_t m_rown; // number of rows. + size_t m_coln; // number of columns. + size_t m_rwdcnt; // number of words in a row + public: + // TODO this should be private + std::vector m_elem; + }; + +binary_matrix::binary_matrix(size_t rown, size_t coln) + { + m_coln = coln; + m_rown = rown; + m_rwdcnt = 1 + ((m_coln - 1) / 32); + m_elem = std::vector(m_rown * m_rwdcnt); + } + +void binary_matrix::row_xor(size_t a, size_t b) + { + for(size_t i = 0; i != m_rwdcnt; i++) + { + m_elem[a*m_rwdcnt+i] ^= m_elem[b*m_rwdcnt+i]; + } + } + +//the matrix is reduced from LSB...(from right) +secure_vector binary_matrix::row_reduced_echelon_form() + { + secure_vector perm(m_coln); + for(size_t i = 0; i != m_coln; i++) + { + perm[i] = i; // initialize permutation. + } + + uint32_t failcnt = 0; + + size_t max = m_coln - 1; + for(size_t i = 0; i != m_rown; i++, max--) + { + bool found_row = false; + + for(size_t j = i; !found_row && j != m_rown; j++) + { + if(coef(j, max)) + { + if(i != j) //not needed as ith row is 0 and jth row is 1. + { + row_xor(i, j);//xor to the row.(swap)? + } + + found_row = true; + } + } + + //if no row with a 1 found then swap last column and the column with no 1 down. + if(!found_row) + { + perm[m_coln - m_rown - 1 - failcnt] = static_cast(max); + failcnt++; + if(!max) + { + perm.resize(0); + } + i--; + } + else + { + perm[i+m_coln - m_rown] = max; + for(size_t j=i+1;j& L, RandomNumberGenerator& rng) + { + for(size_t i = 0; i != L.size(); ++i) + { + gf2m rnd = random_gf2m(rng); + + // no rejection sampling, but for useful code-based parameters with n <= 13 this seem tolerable + std::swap(L[i], L[rnd % L.size()]); + } + } + +std::unique_ptr generate_R(std::vector &L, polyn_gf2m* g, std::shared_ptr sp_field, size_t code_length, size_t t) + { + //L- Support + //t- Number of errors + //n- Length of the Goppa code + //m- The extension degree of the GF + //g- The generator polynomial. + + const size_t r = t * sp_field->get_extension_degree(); + + binary_matrix H(r, code_length); + + for(size_t i = 0; i != code_length; i++) + { + gf2m x = g->eval(lex_to_gray(L[i]));//evaluate the polynomial at the point L[i]. + x = sp_field->gf_inv(x); + gf2m y = x; + for(size_t j=0;jget_extension_degree();k++) + { + if(y & (1<get_extension_degree()+ k,i); + } + } + y = sp_field->gf_mul(y,lex_to_gray(L[i])); + } + }//The H matrix is fed. + + secure_vector perm = H.row_reduced_echelon_form(); + if(perm.size() == 0) + { + throw Invalid_State("McEliece keygen failed - could not bring matrix to row reduced echelon form"); + } + + std::unique_ptr result(new binary_matrix(code_length-r, r)) ; + for(size_t i = 0; i < result->rows(); ++i) + { + for(size_t j = 0; j < result->columns(); ++j) + { + if(H.coef(j, perm[i])) + { + result->toggle_coeff(i,j); + } + } + } + + std::vector Laux(code_length); + for(size_t i = 0; i < code_length; ++i) + { + Laux[i] = L[perm[i]]; + } + + for(size_t i = 0; i < code_length; ++i) + { + L[i] = Laux[i]; + } + return result; + } +} + +McEliece_PrivateKey generate_mceliece_key(RandomNumberGenerator & rng, size_t ext_deg, size_t code_length, size_t t) + { + const size_t codimension = t * ext_deg; + + if(code_length <= codimension) + { + throw Invalid_Argument("invalid McEliece parameters"); + } + + std::shared_ptr sp_field(new GF2m_Field(ext_deg)); + + //pick the support......... + std::vector L(code_length); + + for(size_t i = 0; i != L.size(); i++) + { + L[i] = static_cast(i); + } + randomize_support(L, rng); + polyn_gf2m g(sp_field); // create as zero + + bool success = false; + std::unique_ptr R; + + do + { + // create a random irreducible polynomial + g = polyn_gf2m(t, rng, sp_field); + + try + { + R = generate_R(L, &g, sp_field, code_length, t); + success = true; + } + catch(const Invalid_State &) + { + } + } while (!success); + + std::vector sqrtmod = polyn_gf2m::sqrt_mod_init( g); + std::vector F = syndrome_init(g, L, static_cast(code_length)); + + // Each F[i] is the (precomputed) syndrome of the error vector with + // a single '1' in i-th position. + // We do not store the F[i] as polynomials of degree t , but + // as binary vectors of length ext_deg * t (this will + // speed up the syndrome computation) + // + std::vector H(bit_size_to_32bit_size(codimension) * code_length); + uint32_t* sk = H.data(); + for(size_t i = 0; i < code_length; ++i) + { + for(size_t l = 0; l < t; ++l) + { + const size_t k = (l * ext_deg) / 32; + const uint8_t j = (l * ext_deg) % 32; + sk[k] ^= static_cast(F[i].get_coef(l)) << j; + if(j + ext_deg > 32) + { + sk[k + 1] ^= F[i].get_coef(l) >> (32 - j); + } + } + sk += bit_size_to_32bit_size(codimension); + } + + // We need the support L for decoding (decryption). In fact the + // inverse is needed + + std::vector Linv(code_length) ; + for(size_t i = 0; i != Linv.size(); ++i) + { + Linv[L[i]] = static_cast(i); + } + std::vector pubmat(R->m_elem.size() * 4); + for(size_t i = 0; i < R->m_elem.size(); i++) + { + store_le(R->m_elem[i], &pubmat[i*4]); + } + + return McEliece_PrivateKey(g, H, sqrtmod, Linv, pubmat); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mce/code_based_util.h b/comm/third_party/botan/src/lib/pubkey/mce/code_based_util.h new file mode 100644 index 0000000000..5b0a9195a0 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/code_based_util.h @@ -0,0 +1,57 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#ifndef BOTAN_CODE_BASED_UTIL_H_ +#define BOTAN_CODE_BASED_UTIL_H_ + +#include + +namespace Botan { + +/** +* Expand an input to a bit mask depending on it being being zero or non-zero +* @param tst the input +* @return the mask 0xFFFF if tst is non-zero and 0 otherwise +*/ +template +uint16_t expand_mask_16bit(T tst) + { + const uint16_t result = (tst != 0); + return ~(result - 1); + } + +inline gf2m gray_to_lex(gf2m gray) + { + gf2m result = gray ^ (gray >> 8); + result ^= (result >> 4); + result ^= (result >> 2); + result ^= (result >> 1); + return result; + } + +inline gf2m lex_to_gray(gf2m lex) + { + return (lex >> 1) ^ lex; + } + +inline size_t bit_size_to_byte_size(size_t bit_size) + { + return (bit_size - 1) / 8 + 1; + } + +inline size_t bit_size_to_32bit_size(size_t bit_size) + { + return (bit_size - 1) / 32 + 1; + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp b/comm/third_party/botan/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp new file mode 100644 index 0000000000..5fd88f3d71 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/gf2m_rootfind_dcmp.cpp @@ -0,0 +1,314 @@ +/* + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void patch_root_array(gf2m res_root_arr[], + size_t res_root_arr_len, + size_t root_pos) + { + volatile gf2m patch_elem = 0x01; + volatile gf2m cond_mask = (root_pos == res_root_arr_len); + cond_mask = expand_mask_16bit(cond_mask); + cond_mask = ~cond_mask; /* now cond = 1 if not enough roots */ + patch_elem &= cond_mask; + for(size_t i = 0; i < res_root_arr_len; i++) + { + gf2m masked_patch_elem = (patch_elem++) & cond_mask; + res_root_arr[i] ^= masked_patch_elem++; + } + } + +class gf2m_decomp_rootfind_state + { + public: + gf2m_decomp_rootfind_state(const polyn_gf2m & p_polyn, size_t code_length); + + void calc_LiK(const polyn_gf2m & sigma); + gf2m calc_Fxj_j_neq_0( const polyn_gf2m & sigma, gf2m j_gray); + void calc_next_Aij(); + void calc_Ai_zero(const polyn_gf2m & sigma); + secure_vector find_roots(const polyn_gf2m & sigma); + + private: + size_t m_code_length; + secure_vector m_Lik; // size is outer_summands * m + secure_vector m_Aij; // ... + uint32_t m_outer_summands; + gf2m m_j; + gf2m m_j_gray; + gf2m m_sigma_3_l; + gf2m m_sigma_3_neq_0_mask; + }; + +/* +* !! Attention: assumes gf2m is 16bit !! +*/ +#if 0 +gf2m brootf_decomp_gray_to_lex(gf2m gray) + { + static_assert(sizeof(gf2m) == 2, "Expected size"); + gf2m result = gray ^ (gray>>8); + result ^= (result >> 4); + result ^= (result >> 2); + result ^= (result >> 1); + return result; + } +#endif + +/** +* calculates ceil((t-4)/5) = outer_summands - 1 +*/ +uint32_t brootf_decomp_calc_sum_limit(uint32_t t) + { + uint32_t result; + if(t < 4) + { + return 0; + } + result = t - 4; + result += 4; + result /= 5; + return result; + } + +gf2m_decomp_rootfind_state::gf2m_decomp_rootfind_state(const polyn_gf2m & polyn, size_t code_length) : + m_code_length(code_length), m_j(0), m_j_gray(0) + { + gf2m coeff_3; + gf2m coeff_head; + std::shared_ptr sp_field = polyn.get_sp_field(); + int deg_sigma = polyn.get_degree(); + if(deg_sigma <= 3) + { + throw Internal_Error("Unexpected degree in gf2m_decomp_rootfind_state"); + } + + coeff_3 = polyn.get_coef( 3); + coeff_head = polyn.get_coef( deg_sigma); /* dummy value for SCA CM */ + if(coeff_3 != 0) + { + this->m_sigma_3_l = sp_field->gf_l_from_n(coeff_3); + this->m_sigma_3_neq_0_mask = 0xFFFF; + } + else + { + // dummy value needed for timing countermeasure + this->m_sigma_3_l = sp_field->gf_l_from_n(coeff_head); + this->m_sigma_3_neq_0_mask = 0 ; + } + + this->m_outer_summands = 1 + brootf_decomp_calc_sum_limit(deg_sigma); + this->m_Lik.resize(this->m_outer_summands * sp_field->get_extension_degree()); + this->m_Aij.resize(this->m_outer_summands); + } + +void gf2m_decomp_rootfind_state::calc_Ai_zero(const polyn_gf2m & sigma) + { + uint32_t i; + /* + * this function assumes this the first gray code element is zero + */ + for(i = 0; i < this->m_outer_summands; i++) + { + this->m_Aij[i] = sigma.get_coef(5*i); + } + this->m_j = 0; + this->m_j_gray = 0; + } + +void gf2m_decomp_rootfind_state::calc_next_Aij() + { + /* + * upon function entry, we have in the state j, Aij. + * first thing, we declare Aij Aij_minusone and increase j. + * Case j=0 upon function entry also included, then Aij contains A_{i,j=0}. + */ + uint32_t i; + gf2m diff, new_j_gray; + uint32_t Lik_pos_base; + + this->m_j++; + + new_j_gray = lex_to_gray(this->m_j); + + if(this->m_j & 1) /* half of the times */ + { + Lik_pos_base = 0; + } + else if(this->m_j & 2) /* one quarter of the times */ + { + Lik_pos_base = this->m_outer_summands; + } + else if( this->m_j & 4) /* one eighth of the times */ + { + Lik_pos_base = this->m_outer_summands * 2; + } + else if( this->m_j & 8) /* one sixteenth of the times */ + { + Lik_pos_base = this->m_outer_summands * 3; + } + else if( this->m_j & 16) /* ... */ + { + Lik_pos_base = this->m_outer_summands * 4; + } + else + { + gf2m delta_offs = 5; + diff = this->m_j_gray ^ new_j_gray; + while(((static_cast(1) << delta_offs) & diff) == 0) + { + delta_offs++; + + } + Lik_pos_base = delta_offs * this->m_outer_summands; + } + this->m_j_gray = new_j_gray; + + i = 0; + for(; i < this->m_outer_summands; i++) + { + this->m_Aij[i] ^= this->m_Lik[Lik_pos_base + i]; + } + + } + +void gf2m_decomp_rootfind_state::calc_LiK(const polyn_gf2m & sigma) + { + std::shared_ptr sp_field = sigma.get_sp_field(); + uint32_t i, k, d; + d = sigma.get_degree(); + for(k = 0; k < sp_field->get_extension_degree(); k++) + { + uint32_t Lik_pos_base = k * this->m_outer_summands; + gf2m alpha_l_k_tt2_ttj[4]; + alpha_l_k_tt2_ttj[0] = sp_field->gf_l_from_n(static_cast(1) << k); + alpha_l_k_tt2_ttj[1] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[0], alpha_l_k_tt2_ttj[0]); + alpha_l_k_tt2_ttj[2] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[1],alpha_l_k_tt2_ttj[1] ); + + alpha_l_k_tt2_ttj[3] = sp_field->gf_mul_rrr(alpha_l_k_tt2_ttj[2], alpha_l_k_tt2_ttj[2]); + for(i = 0; i < this->m_outer_summands; i++) + { + uint32_t j; + uint32_t five_i = 5*i; + uint32_t Lik_pos = Lik_pos_base + i; + this->m_Lik[Lik_pos] = 0; + for(j = 0; j <= 3; j++) + { + gf2m f, x; + uint32_t f_ind = five_i + (static_cast(1) << j); + if(f_ind > d) + { + break; + } + f = sigma.get_coef( f_ind); + + x = sp_field->gf_mul_zrz(alpha_l_k_tt2_ttj[j], f); + this->m_Lik[Lik_pos] ^= x; + } + } + } + } + +gf2m gf2m_decomp_rootfind_state::calc_Fxj_j_neq_0( const polyn_gf2m & sigma, gf2m j_gray) + { + //needs the A_{ij} to compute F(x)_j + gf2m sum = 0; + uint32_t i; + std::shared_ptr sp_field = sigma.get_sp_field(); + const gf2m jl_gray = sp_field->gf_l_from_n(j_gray); + gf2m xl_j_tt_5 = sp_field->gf_square_rr(jl_gray); + gf2m xl_gray_tt_3 = sp_field->gf_mul_rrr(xl_j_tt_5, jl_gray); + xl_j_tt_5 = sp_field->gf_mul_rrr(xl_j_tt_5, xl_gray_tt_3); + + + sum = sp_field->gf_mul_nrr(xl_gray_tt_3, this->m_sigma_3_l); + sum &= this->m_sigma_3_neq_0_mask; + /* here, we rely on compiler to be unable to optimize + * for the state->sigma_3_neq_0_mask value + */ + /* treat i = 0 special: */ + sum ^= this->m_Aij[0]; + /* treat i = 1 special also */ + + if(this->m_outer_summands > 1) + { + gf2m x; + x = sp_field->gf_mul_zrz(xl_j_tt_5, this->m_Aij[1]); /* x_j^{5i} A_i^j */ + sum ^= x; + } + + gf2m xl_j_tt_5i = xl_j_tt_5; + + for(i = 2; i < this->m_outer_summands; i++) + { + gf2m x; + xl_j_tt_5i = sp_field->gf_mul_rrr(xl_j_tt_5i, xl_j_tt_5); + // now x_j_tt_5i lives up to its name + x = sp_field->gf_mul_zrz(xl_j_tt_5i, this->m_Aij[i]); /* x_j^{5i} A_i^(j) */ + sum ^= x; + } + return sum; + } + +secure_vector gf2m_decomp_rootfind_state::find_roots(const polyn_gf2m & sigma) + { + const int sigma_degree = sigma.get_degree(); + BOTAN_ASSERT(sigma_degree > 0, "Valid sigma"); + secure_vector result(sigma_degree); + uint32_t root_pos = 0; + + this->calc_Ai_zero(sigma); + this->calc_LiK(sigma); + for(;;) + { + gf2m eval_result; + + if(this->m_j_gray == 0) + { + eval_result = sigma.get_coef(0); + } + else + { + eval_result = this->calc_Fxj_j_neq_0(sigma, this->m_j_gray); + } + + if(eval_result == 0) + { + result[root_pos] = this->m_j_gray; + root_pos++; + } + + if(this->m_j + static_cast(1) == m_code_length) + { + break; + } + this->calc_next_Aij(); + } + + // side channel / fault attack countermeasure: + patch_root_array(result.data(), result.size(), root_pos); + return result; + } + +} // end anonymous namespace + +secure_vector find_roots_gf2m_decomp(const polyn_gf2m & polyn, size_t code_length) + { + gf2m_decomp_rootfind_state state(polyn, code_length); + return state.find_roots(polyn); + } + +} // end namespace Botan diff --git a/comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.cpp b/comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.cpp new file mode 100644 index 0000000000..341b45d034 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.cpp @@ -0,0 +1,126 @@ +/* +* (C) Copyright Projet SECRET, INRIA, Rocquencourt +* (C) Bhaskar Biswas and Nicolas Sendrier +* +* (C) 2014 cryptosource GmbH +* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +#define MAX_EXT_DEG 16 + +namespace { + +gf2m prim_poly[MAX_EXT_DEG + 1] = { + 01, /* extension degree 0 (!) never used */ + 03, /* extension degree 1 (!) never used */ + 07, /* extension degree 2 */ + 013, /* extension degree 3 */ + 023, /* extension degree 4 */ + 045, /* extension degree 5 */ + 0103, /* extension degree 6 */ + 0203, /* extension degree 7 */ + 0435, /* extension degree 8 */ + 01041, /* extension degree 9 */ + 02011, /* extension degree 10 */ + 04005, /* extension degree 11 */ + 010123, /* extension degree 12 */ + 020033, /* extension degree 13 */ + 042103, /* extension degree 14 */ + 0100003, /* extension degree 15 */ +}; + +std::vector gf_exp_table(size_t deg, gf2m prime_poly) + { + // construct the table gf_exp[i]=alpha^i + + std::vector tab((static_cast(1) << deg) + 1); + + tab[0] = 1; + for(size_t i = 1; i < tab.size(); ++i) + { + const gf2m overflow = tab[i-1] >> (deg - 1); + tab[i] = (tab[i-1] << 1) ^ (overflow * prime_poly); + } + + return tab; + } + +const std::vector& exp_table(size_t deg) + { + static std::vector tabs[MAX_EXT_DEG + 1]; + + if(deg < 2 || deg > MAX_EXT_DEG) + throw Invalid_Argument("GF2m_Field does not support degree " + std::to_string(deg)); + + if(tabs[deg].empty()) + tabs[deg] = gf_exp_table(deg, prim_poly[deg]); + + return tabs[deg]; + } + +std::vector gf_log_table(size_t deg, const std::vector& exp) + { + std::vector tab(static_cast(1) << deg); + + tab[0] = static_cast((static_cast(1) << deg) - 1); // log of 0 is the order by convention + for(size_t i = 0; i < tab.size(); ++i) + { + tab[exp[i]] = static_cast(i); + } + return tab; + } + +const std::vector& log_table(size_t deg) + { + static std::vector tabs[MAX_EXT_DEG + 1]; + + if(deg < 2 || deg > MAX_EXT_DEG) + throw Invalid_Argument("GF2m_Field does not support degree " + std::to_string(deg)); + + if(tabs[deg].empty()) + tabs[deg] = gf_log_table(deg, exp_table(deg)); + + return tabs[deg]; + } + +} + +uint32_t encode_gf2m(gf2m to_enc, uint8_t* mem) + { + mem[0] = to_enc >> 8; + mem[1] = to_enc & 0xFF; + return sizeof(to_enc); + } + +gf2m decode_gf2m(const uint8_t* mem) + { + gf2m result; + result = mem[0] << 8; + result |= mem[1]; + return result; + } + +GF2m_Field::GF2m_Field(size_t extdeg) : m_gf_extension_degree(extdeg), + m_gf_multiplicative_order((1 << extdeg) - 1), + m_gf_log_table(log_table(m_gf_extension_degree)), + m_gf_exp_table(exp_table(m_gf_extension_degree)) + { + } + +gf2m GF2m_Field::gf_div(gf2m x, gf2m y) const + { + const int32_t sub_res = static_cast(gf_log(x) - static_cast(gf_log(y))); + const gf2m modq_res = _gf_modq_1(sub_res); + const int32_t div_res = static_cast(x) ? static_cast(gf_exp(modq_res)) : 0; + return static_cast(div_res); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.h b/comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.h new file mode 100644 index 0000000000..ae3eab2264 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/gf2m_small_m.h @@ -0,0 +1,221 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#ifndef BOTAN_GF2M_SMALL_M_H_ +#define BOTAN_GF2M_SMALL_M_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(gf2m_small_m.h) + +namespace Botan { + +typedef uint16_t gf2m; + +/** +* GF(2^m) field for m = [2...16] +*/ +class BOTAN_PUBLIC_API(2,0) GF2m_Field + { + public: + explicit GF2m_Field(size_t extdeg); + + gf2m gf_mul(gf2m x, gf2m y) const + { + return ((x) ? gf_mul_fast(x, y) : 0); + } + + gf2m gf_square(gf2m x) const + { + return ((x) ? gf_exp(_gf_modq_1(gf_log(x) << 1)) : 0); + } + + gf2m square_rr(gf2m x) const + { + return _gf_modq_1(x << 1); + } + + gf2m gf_mul_fast(gf2m x, gf2m y) const + { + return ((y) ? gf_exp(_gf_modq_1(gf_log(x) + gf_log(y))) : 0); + } + + /* + naming convention of GF(2^m) field operations: + l logarithmic, unreduced + r logarithmic, reduced + n normal, non-zero + z normal, might be zero + */ + + gf2m gf_mul_lll(gf2m a, gf2m b) const + { + return (a + b); + } + + gf2m gf_mul_rrr(gf2m a, gf2m b) const + { + return (_gf_modq_1(gf_mul_lll(a, b))); + } + + gf2m gf_mul_nrr(gf2m a, gf2m b) const + { + return (gf_exp(gf_mul_rrr(a, b))); + } + + gf2m gf_mul_rrn(gf2m a, gf2m y) const + { + return _gf_modq_1(gf_mul_lll(a, gf_log(y))); + } + + gf2m gf_mul_rnr(gf2m y, gf2m a) const + { + return gf_mul_rrn(a, y); + } + + gf2m gf_mul_lnn(gf2m x, gf2m y) const + { + return (gf_log(x) + gf_log(y)); + } + + gf2m gf_mul_rnn(gf2m x, gf2m y) const + { + return _gf_modq_1(gf_mul_lnn(x, y)); + } + + gf2m gf_mul_nrn(gf2m a, gf2m y) const + { + return gf_exp(_gf_modq_1((a) + gf_log(y))); + } + + /** + * zero operand allowed + */ + gf2m gf_mul_zrz(gf2m a, gf2m y) const + { + return ( (y == 0) ? 0 : gf_mul_nrn(a, y) ); + } + + gf2m gf_mul_zzr(gf2m a, gf2m y) const + { + return gf_mul_zrz(y, a); + } + + /** + * non-zero operand + */ + gf2m gf_mul_nnr(gf2m y, gf2m a) const + { + return gf_mul_nrn(a, y); + } + + gf2m gf_sqrt(gf2m x) const + { + return ((x) ? gf_exp(_gf_modq_1(gf_log(x) << (get_extension_degree()-1))) : 0); + } + + gf2m gf_div_rnn(gf2m x, gf2m y) const + { + return _gf_modq_1(gf_log(x) - gf_log(y)); + } + + gf2m gf_div_rnr(gf2m x, gf2m b) const + { + return _gf_modq_1(gf_log(x) - b); + } + + gf2m gf_div_nrr(gf2m a, gf2m b) const + { + return gf_exp(_gf_modq_1(a - b)); + } + + gf2m gf_div_zzr(gf2m x, gf2m b) const + { + return ((x) ? gf_exp(_gf_modq_1(gf_log(x) - b)) : 0); + } + + gf2m gf_inv(gf2m x) const + { + return gf_exp(gf_ord() - gf_log(x)); + } + + gf2m gf_inv_rn(gf2m x) const + { + return (gf_ord() - gf_log(x)); + } + + gf2m gf_square_ln(gf2m x) const + { + return gf_log(x) << 1; + } + + gf2m gf_square_rr(gf2m a) const + { + return a << 1; + } + + gf2m gf_l_from_n(gf2m x) const + { + return gf_log(x); + } + + gf2m gf_div(gf2m x, gf2m y) const; + + gf2m gf_exp(gf2m i) const + { + return m_gf_exp_table.at(i); /* alpha^i */ + } + + gf2m gf_log(gf2m i) const + { + return m_gf_log_table.at(i); /* return i when x=alpha^i */ + } + + gf2m gf_ord() const + { + return m_gf_multiplicative_order; + } + + size_t get_extension_degree() const + { + return m_gf_extension_degree; + } + + gf2m get_cardinality() const + { + return static_cast(1 << get_extension_degree()); + } + + private: + gf2m _gf_modq_1(int32_t d) const + { + /* residual modulo q-1 + when -q < d < 0, we get (q-1+d) + when 0 <= d < q, we get (d) + when q <= d < 2q-1, we get (d-q+1) + */ + return static_cast(((d) & gf_ord()) + ((d) >> get_extension_degree())); + } + + const size_t m_gf_extension_degree; + const gf2m m_gf_multiplicative_order; + const std::vector& m_gf_log_table; + const std::vector& m_gf_exp_table; + }; + +uint32_t encode_gf2m(gf2m to_enc, uint8_t* mem); + +gf2m decode_gf2m(const uint8_t* mem); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/mce/goppa_code.cpp b/comm/third_party/botan/src/lib/pubkey/mce/goppa_code.cpp new file mode 100644 index 0000000000..f26716fabd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/goppa_code.cpp @@ -0,0 +1,234 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include + +namespace Botan { + +namespace { + +void matrix_arr_mul(std::vector matrix, + size_t numo_rows, + size_t words_per_row, + const uint8_t input_vec[], + uint32_t output_vec[], + size_t output_vec_len) + { + for(size_t j = 0; j < numo_rows; j++) + { + if((input_vec[j / 8] >> (j % 8)) & 1) + { + for(size_t i = 0; i < output_vec_len; i++) + { + output_vec[i] ^= matrix[j * (words_per_row) + i]; + } + } + } + } + +/** +* returns the error vector to the syndrome +*/ +secure_vector goppa_decode(const polyn_gf2m & syndrom_polyn, + const polyn_gf2m & g, + const std::vector & sqrtmod, + const std::vector & Linv) + { + const size_t code_length = Linv.size(); + gf2m a; + uint32_t t = g.get_degree(); + + std::shared_ptr sp_field = g.get_sp_field(); + + std::pair h_aux = polyn_gf2m::eea_with_coefficients( syndrom_polyn, g, 1); + polyn_gf2m & h = h_aux.first; + polyn_gf2m & aux = h_aux.second; + a = sp_field->gf_inv(aux.get_coef(0)); + gf2m log_a = sp_field->gf_log(a); + for(int i = 0; i <= h.get_degree(); ++i) + { + h.set_coef(i,sp_field->gf_mul_zrz(log_a,h.get_coef(i))); + } + + // compute h(z) += z + h.add_to_coef( 1, 1); + // compute S square root of h (using sqrtmod) + polyn_gf2m S(t - 1, g.get_sp_field()); + + for(uint32_t i=0;igf_sqrt(h.get_coef(i)); + + if(i & 1) + { + for(uint32_t j=0;jgf_mul(a, sqrtmod[i/2].get_coef(j))); + } + } + else + { + S.add_to_coef( i/2, a); + } + } /* end for loop (i) */ + + + S.get_degree(); + + std::pair v_u = polyn_gf2m::eea_with_coefficients(S, g, t/2+1); + polyn_gf2m & u = v_u.second; + polyn_gf2m & v = v_u.first; + + // sigma = u^2+z*v^2 + polyn_gf2m sigma ( t , g.get_sp_field()); + + const int u_deg = u.get_degree(); + BOTAN_ASSERT(u_deg >= 0, "Valid degree"); + for(int i = 0; i <= u_deg; ++i) + { + sigma.set_coef(2*i, sp_field->gf_square(u.get_coef(i))); + } + + const int v_deg = v.get_degree(); + BOTAN_ASSERT(v_deg >= 0, "Valid degree"); + for(int i = 0; i <= v_deg; ++i) + { + sigma.set_coef(2*i+1, sp_field->gf_square(v.get_coef(i))); + } + + secure_vector res = find_roots_gf2m_decomp(sigma, code_length); + size_t d = res.size(); + + secure_vector result(d); + for(uint32_t i = 0; i < d; ++i) + { + gf2m current = res[i]; + + gf2m tmp; + tmp = gray_to_lex(current); + /// XXX double assignment, possible bug? + if(tmp >= code_length) /* invalid root */ + { + result[i] = static_cast(i); + } + result[i] = Linv[tmp]; + } + + return result; + } +} + +void mceliece_decrypt(secure_vector& plaintext_out, + secure_vector& error_mask_out, + const secure_vector& ciphertext, + const McEliece_PrivateKey& key) + { + mceliece_decrypt(plaintext_out, error_mask_out, ciphertext.data(), ciphertext.size(), key); + } + +void mceliece_decrypt( + secure_vector& plaintext, + secure_vector & error_mask, + const uint8_t ciphertext[], + size_t ciphertext_len, + const McEliece_PrivateKey & key) + { + secure_vector error_pos; + plaintext = mceliece_decrypt(error_pos, ciphertext, ciphertext_len, key); + + const size_t code_length = key.get_code_length(); + secure_vector result((code_length+7)/8); + for(auto&& pos : error_pos) + { + if(pos > code_length) + { + throw Invalid_Argument("error position larger than code size"); + } + result[pos / 8] |= (1 << (pos % 8)); + } + + error_mask = result; + } + +/** +* @p p_err_pos_len must point to the available length of @p error_pos on input, the +* function will set it to the actual number of errors returned in the @p error_pos +* array */ +secure_vector mceliece_decrypt( + secure_vector & error_pos, + const uint8_t *ciphertext, size_t ciphertext_len, + const McEliece_PrivateKey & key) + { + + const size_t dimension = key.get_dimension(); + const size_t codimension = key.get_codimension(); + const uint32_t t = key.get_goppa_polyn().get_degree(); + polyn_gf2m syndrome_polyn(key.get_goppa_polyn().get_sp_field()); // init as zero polyn + const unsigned unused_pt_bits = dimension % 8; + const uint8_t unused_pt_bits_mask = (1 << unused_pt_bits) - 1; + + if(ciphertext_len != (key.get_code_length()+7)/8) + { + throw Invalid_Argument("wrong size of McEliece ciphertext"); + } + const size_t cleartext_len = (key.get_message_word_bit_length()+7)/8; + + if(cleartext_len != bit_size_to_byte_size(dimension)) + { + throw Invalid_Argument("mce-decryption: wrong length of cleartext buffer"); + } + + secure_vector syndrome_vec(bit_size_to_32bit_size(codimension)); + matrix_arr_mul(key.get_H_coeffs(), + key.get_code_length(), + bit_size_to_32bit_size(codimension), + ciphertext, + syndrome_vec.data(), syndrome_vec.size()); + + secure_vector syndrome_byte_vec(bit_size_to_byte_size(codimension)); + const size_t syndrome_byte_vec_size = syndrome_byte_vec.size(); + for(size_t i = 0; i < syndrome_byte_vec_size; i++) + { + syndrome_byte_vec[i] = static_cast(syndrome_vec[i/4] >> (8 * (i % 4))); + } + + syndrome_polyn = polyn_gf2m(t-1, syndrome_byte_vec.data(), bit_size_to_byte_size(codimension), key.get_goppa_polyn().get_sp_field()); + + syndrome_polyn.get_degree(); + error_pos = goppa_decode(syndrome_polyn, key.get_goppa_polyn(), key.get_sqrtmod(), key.get_Linv()); + + const size_t nb_err = error_pos.size(); + + secure_vector cleartext(cleartext_len); + copy_mem(cleartext.data(), ciphertext, cleartext_len); + + for(size_t i = 0; i < nb_err; i++) + { + gf2m current = error_pos[i]; + + if(current >= cleartext_len * 8) + { + // an invalid position, this shouldn't happen + continue; + } + cleartext[current / 8] ^= (1 << (current % 8)); + } + + if(unused_pt_bits) + { + cleartext[cleartext_len - 1] &= unused_pt_bits_mask; + } + + return cleartext; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mce/info.txt b/comm/third_party/botan/src/lib/pubkey/mce/info.txt new file mode 100644 index 0000000000..becf616b3e --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/info.txt @@ -0,0 +1,18 @@ + +MCELIECE -> 20150922 + + + +mceliece.h +polyn_gf2m.h +gf2m_small_m.h + + + +code_based_util.h +mce_internal.h + + + +sha2_64 + diff --git a/comm/third_party/botan/src/lib/pubkey/mce/mce_internal.h b/comm/third_party/botan/src/lib/pubkey/mce/mce_internal.h new file mode 100644 index 0000000000..7059f4e2ec --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/mce_internal.h @@ -0,0 +1,53 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#ifndef BOTAN_MCELIECE_INTERNAL_H_ +#define BOTAN_MCELIECE_INTERNAL_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +void mceliece_decrypt(secure_vector& plaintext_out, + secure_vector& error_mask_out, + const uint8_t ciphertext[], + size_t ciphertext_len, + const McEliece_PrivateKey& key); + +void mceliece_decrypt(secure_vector& plaintext_out, + secure_vector& error_mask_out, + const secure_vector& ciphertext, + const McEliece_PrivateKey& key); + +secure_vector mceliece_decrypt( + secure_vector & error_pos, + const uint8_t *ciphertext, size_t ciphertext_len, + const McEliece_PrivateKey & key); + +void mceliece_encrypt(secure_vector& ciphertext_out, + secure_vector& error_mask_out, + const secure_vector& plaintext, + const McEliece_PublicKey& key, + RandomNumberGenerator& rng); + +McEliece_PrivateKey generate_mceliece_key(RandomNumberGenerator &rng, + size_t ext_deg, + size_t code_length, + size_t t); + +} + + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/mce/mce_workfactor.cpp b/comm/third_party/botan/src/lib/pubkey/mce/mce_workfactor.cpp new file mode 100644 index 0000000000..ce38781c8b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/mce_workfactor.cpp @@ -0,0 +1,112 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * (C) 2014 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include +#include + +namespace Botan { + +namespace { + +double binomial(size_t n, size_t k) + { + double x = 1; + + for(size_t i = 0; i != k; ++i) + { + x *= n - i; + x /= k -i; + } + + return x; + } + +double log_binomial(size_t n, size_t k) + { + double x = 0; + + for(size_t i = 0; i != k; ++i) + { + x += std::log(n - i); + x -= std::log(k - i); + } + + return x / std::log(2); + } + +double nb_iter(size_t n, size_t k, size_t w, size_t p, size_t l) + { + double x = 2 * log_binomial(k / 2, p); + x += log_binomial(n - k - l, w - 2 * p); + x = log_binomial(n, w) - x; + return x; + } + +double cout_iter(size_t n, size_t k, size_t p, size_t l) + { + double x = binomial(k / 2, p); + const size_t i = static_cast(std::log(x) / std::log(2)); + double res = 2 * p * (n - k - l) * std::ldexp(x * x, -static_cast(l)); + + // x <- binomial(k/2,p)*2*(2*l+log[2](binomial(k/2,p))) + x *= 2 * (2 * l + i); + + // res <- k*(n-k)/2 + + // binomial(k/2,p)*2*(2*l+log[2](binomial(k/2,p))) + + // 2*p*(n-k-l)*binomial(k/2,p)^2/2^l + res += x + k * ((n - k) / 2.0); + + return std::log(res) / std::log(2); // convert to bits + } + +double cout_total(size_t n, size_t k, size_t w, size_t p, size_t l) + { + return nb_iter(n, k, w, p, l) + cout_iter(n, k, p, l); + } + +double best_wf(size_t n, size_t k, size_t w, size_t p) + { + if(p >= k / 2) + return -1; + + double min = cout_total(n, k, w, p, 0); + + for(size_t l = 1; l < n - k; ++l) + { + const double lwf = cout_total(n, k, w, p, l); + if(lwf < min) + min = lwf; + else + break; + } + + return min; + } + +} + +size_t mceliece_work_factor(size_t n, size_t t) + { + const size_t k = n - ceil_log2(n) * t; + + double min = cout_total(n, k, t, 0, 0); // correspond a p=1 + for(size_t p = 0; p != t / 2; ++p) + { + double lwf = best_wf(n, k + 1, t, p); + if(lwf < 0) + break; + + min = std::min(min, lwf); + } + + return static_cast(min); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mce/mceliece.cpp b/comm/third_party/botan/src/lib/pubkey/mce/mceliece.cpp new file mode 100644 index 0000000000..c5fe74b058 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/mceliece.cpp @@ -0,0 +1,139 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector concat_vectors(const secure_vector& a, + const secure_vector& b, + size_t dimension, + size_t codimension) + { + secure_vector x(bit_size_to_byte_size(dimension) + bit_size_to_byte_size(codimension)); + + const size_t final_bits = dimension % 8; + + if(final_bits == 0) + { + const size_t dim_bytes = bit_size_to_byte_size(dimension); + copy_mem(&x[0], a.data(), dim_bytes); + copy_mem(&x[dim_bytes], b.data(), bit_size_to_byte_size(codimension)); + } + else + { + copy_mem(&x[0], a.data(), (dimension / 8)); + size_t l = dimension / 8; + x[l] = static_cast(a[l] & ((1 << final_bits) - 1)); + + for(size_t k = 0; k < codimension / 8; ++k) + { + x[l] ^= static_cast(b[k] << final_bits); + ++l; + x[l] = static_cast(b[k] >> (8 - final_bits)); + } + x[l] ^= static_cast(b[codimension/8] << final_bits); + } + + return x; + } + +secure_vector mult_by_pubkey(const secure_vector& cleartext, + std::vector const& public_matrix, + size_t code_length, size_t t) + { + const size_t ext_deg = ceil_log2(code_length); + const size_t codimension = ext_deg * t; + const size_t dimension = code_length - codimension; + secure_vector cR(bit_size_to_32bit_size(codimension) * sizeof(uint32_t)); + + const uint8_t* pt = public_matrix.data(); + + for(size_t i = 0; i < dimension / 8; ++i) + { + for(size_t j = 0; j < 8; ++j) + { + if(cleartext[i] & (1 << j)) + { + xor_buf(cR.data(), pt, cR.size()); + } + pt += cR.size(); + } + } + + for(size_t i = 0; i < dimension % 8 ; ++i) + { + if(cleartext[dimension/8] & (1 << i)) + { + xor_buf(cR.data(), pt, cR.size()); + } + pt += cR.size(); + } + + secure_vector ciphertext = concat_vectors(cleartext, cR, dimension, codimension); + ciphertext.resize((code_length+7)/8); + return ciphertext; + } + +secure_vector create_random_error_vector(size_t code_length, + size_t error_weight, + RandomNumberGenerator& rng) + { + secure_vector result((code_length+7)/8); + + size_t bits_set = 0; + + while(bits_set < error_weight) + { + gf2m x = random_code_element(static_cast(code_length), rng); + + const size_t byte_pos = x / 8; + const size_t bit_pos = x % 8; + + const uint8_t mask = (1 << bit_pos); + + if(result[byte_pos] & mask) + continue; // already set this bit + + result[byte_pos] |= mask; + bits_set++; + } + + return result; + } + +} + +void mceliece_encrypt(secure_vector& ciphertext_out, + secure_vector& error_mask_out, + const secure_vector& plaintext, + const McEliece_PublicKey& key, + RandomNumberGenerator& rng) + { + const uint16_t code_length = static_cast(key.get_code_length()); + + secure_vector error_mask = create_random_error_vector(code_length, key.get_t(), rng); + + secure_vector ciphertext = mult_by_pubkey(plaintext, key.get_public_matrix(), + key.get_code_length(), key.get_t()); + + ciphertext ^= error_mask; + + ciphertext_out.swap(ciphertext); + error_mask_out.swap(error_mask); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mce/mceliece.h b/comm/third_party/botan/src/lib/pubkey/mce/mceliece.h new file mode 100644 index 0000000000..ba044ef7dc --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/mceliece.h @@ -0,0 +1,141 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#ifndef BOTAN_MCELIECE_KEY_H_ +#define BOTAN_MCELIECE_KEY_H_ + +#include +#include + +namespace Botan { + +typedef uint16_t gf2m; + +class polyn_gf2m; + +class BOTAN_PUBLIC_API(2,0) McEliece_PublicKey : public virtual Public_Key + { + public: + explicit McEliece_PublicKey(const std::vector& key_bits); + + McEliece_PublicKey(const std::vector& pub_matrix, size_t t, size_t the_code_length) : + m_public_matrix(pub_matrix), + m_t(t), + m_code_length(the_code_length){} + + McEliece_PublicKey(const McEliece_PublicKey& other) = default; + McEliece_PublicKey& operator=(const McEliece_PublicKey& other) = default; + virtual ~McEliece_PublicKey()= default; + + secure_vector random_plaintext_element(RandomNumberGenerator& rng) const; + + std::string algo_name() const override { return "McEliece"; } + + AlgorithmIdentifier algorithm_identifier() const override; + + size_t key_length() const override; + size_t estimated_strength() const override; + + std::vector public_key_bits() const override; + + bool check_key(RandomNumberGenerator&, bool) const override + { return true; } + + size_t get_t() const { return m_t; } + size_t get_code_length() const { return m_code_length; } + size_t get_message_word_bit_length() const; + const std::vector& get_public_matrix() const { return m_public_matrix; } + + bool operator==(const McEliece_PublicKey& other) const; + bool operator!=(const McEliece_PublicKey& other) const { return !(*this == other); } + + std::unique_ptr + create_kem_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + protected: + McEliece_PublicKey() : m_t(0), m_code_length(0) {} + + std::vector m_public_matrix; + size_t m_t; + size_t m_code_length; + }; + +class BOTAN_PUBLIC_API(2,0) McEliece_PrivateKey final : public virtual McEliece_PublicKey, + public virtual Private_Key + { + public: + + /** + Generate a McEliece key pair + + Suggested parameters for a given security level (SL) + + SL=80 n=1632 t=33 - 59 KB pubkey 140 KB privkey + SL=107 n=2480 t=45 - 128 KB pubkey 300 KB privkey + SL=128 n=2960 t=57 - 195 KB pubkey 459 KB privkey + SL=147 n=3408 t=67 - 265 KB pubkey 622 KB privkey + SL=191 n=4624 t=95 - 516 KB pubkey 1234 KB privkey + SL=256 n=6624 t=115 - 942 KB pubkey 2184 KB privkey + */ + McEliece_PrivateKey(RandomNumberGenerator& rng, size_t code_length, size_t t); + + explicit McEliece_PrivateKey(const secure_vector& key_bits); + + McEliece_PrivateKey(polyn_gf2m const& goppa_polyn, + std::vector const& parity_check_matrix_coeffs, + std::vector const& square_root_matrix, + std::vector const& inverse_support, + std::vector const& public_matrix ); + + ~McEliece_PrivateKey(); + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + polyn_gf2m const& get_goppa_polyn() const; + std::vector const& get_H_coeffs() const { return m_coeffs; } + std::vector const& get_Linv() const { return m_Linv; } + std::vector const& get_sqrtmod() const { return m_sqrtmod; } + + inline size_t get_dimension() const { return m_dimension; } + + inline size_t get_codimension() const { return m_codimension; } + + secure_vector private_key_bits() const override; + + bool operator==(const McEliece_PrivateKey & other) const; + + bool operator!=(const McEliece_PrivateKey& other) const { return !(*this == other); } + + std::unique_ptr + create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + private: + std::vector m_g; // single element + std::vector m_sqrtmod; + std::vector m_Linv; + std::vector m_coeffs; + + size_t m_codimension; + size_t m_dimension; + }; + +/** +* Estimate work factor for McEliece +* @return estimated security level for these key parameters +*/ +BOTAN_PUBLIC_API(2,0) size_t mceliece_work_factor(size_t code_size, size_t t); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/mce/mceliece_key.cpp b/comm/third_party/botan/src/lib/pubkey/mce/mceliece_key.cpp new file mode 100644 index 0000000000..283421be40 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/mceliece_key.cpp @@ -0,0 +1,386 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * (C) 2015 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +McEliece_PrivateKey::McEliece_PrivateKey(polyn_gf2m const& goppa_polyn, + std::vector const& parity_check_matrix_coeffs, + std::vector const& square_root_matrix, + std::vector const& inverse_support, + std::vector const& public_matrix) : + McEliece_PublicKey(public_matrix, goppa_polyn.get_degree(), inverse_support.size()), + m_g{goppa_polyn}, + m_sqrtmod(square_root_matrix), + m_Linv(inverse_support), + m_coeffs(parity_check_matrix_coeffs), + m_codimension(static_cast(ceil_log2(inverse_support.size())) * goppa_polyn.get_degree()), + m_dimension(inverse_support.size() - m_codimension) + { + } + +McEliece_PrivateKey::McEliece_PrivateKey(RandomNumberGenerator& rng, size_t code_length, size_t t) + { + uint32_t ext_deg = ceil_log2(code_length); + *this = generate_mceliece_key(rng, ext_deg, code_length, t); + } + +McEliece_PrivateKey::~McEliece_PrivateKey() = default; + +const polyn_gf2m& McEliece_PrivateKey::get_goppa_polyn() const + { + return m_g[0]; + } + +size_t McEliece_PublicKey::get_message_word_bit_length() const + { + size_t codimension = ceil_log2(m_code_length) * m_t; + return m_code_length - codimension; + } + +secure_vector McEliece_PublicKey::random_plaintext_element(RandomNumberGenerator& rng) const + { + const size_t bits = get_message_word_bit_length(); + + secure_vector plaintext((bits+7)/8); + rng.randomize(plaintext.data(), plaintext.size()); + + // unset unused bits in the last plaintext byte + if(uint32_t used = bits % 8) + { + const uint8_t mask = (1 << used) - 1; + plaintext[plaintext.size() - 1] &= mask; + } + + return plaintext; + } + +AlgorithmIdentifier McEliece_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); + } + +std::vector McEliece_PublicKey::public_key_bits() const + { + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(static_cast(get_code_length())) + .encode(static_cast(get_t())) + .end_cons() + .encode(m_public_matrix, OCTET_STRING) + .end_cons(); + return output; + } + +size_t McEliece_PublicKey::key_length() const + { + return m_code_length; + } + +size_t McEliece_PublicKey::estimated_strength() const + { + return mceliece_work_factor(m_code_length, m_t); + } + +McEliece_PublicKey::McEliece_PublicKey(const std::vector& key_bits) + { + BER_Decoder dec(key_bits); + size_t n; + size_t t; + dec.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .decode(n) + .decode(t) + .end_cons() + .decode(m_public_matrix, OCTET_STRING) + .end_cons(); + m_t = t; + m_code_length = n; + } + +secure_vector McEliece_PrivateKey::private_key_bits() const + { + DER_Encoder enc; + enc.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(static_cast(get_code_length())) + .encode(static_cast(get_t())) + .end_cons() + .encode(m_public_matrix, OCTET_STRING) + .encode(m_g[0].encode(), OCTET_STRING); // g as octet string + enc.start_cons(SEQUENCE); + for(size_t i = 0; i < m_sqrtmod.size(); i++) + { + enc.encode(m_sqrtmod[i].encode(), OCTET_STRING); + } + enc.end_cons(); + secure_vector enc_support; + + for(uint16_t Linv : m_Linv) + { + enc_support.push_back(get_byte(0, Linv)); + enc_support.push_back(get_byte(1, Linv)); + } + enc.encode(enc_support, OCTET_STRING); + secure_vector enc_H; + for(uint32_t coef : m_coeffs) + { + enc_H.push_back(get_byte(0, coef)); + enc_H.push_back(get_byte(1, coef)); + enc_H.push_back(get_byte(2, coef)); + enc_H.push_back(get_byte(3, coef)); + } + enc.encode(enc_H, OCTET_STRING); + enc.end_cons(); + return enc.get_contents(); + } + +bool McEliece_PrivateKey::check_key(RandomNumberGenerator& rng, bool) const + { + const secure_vector plaintext = this->random_plaintext_element(rng); + + secure_vector ciphertext; + secure_vector errors; + mceliece_encrypt(ciphertext, errors, plaintext, *this, rng); + + secure_vector plaintext_out; + secure_vector errors_out; + mceliece_decrypt(plaintext_out, errors_out, ciphertext, *this); + + if(errors != errors_out || plaintext != plaintext_out) + return false; + + return true; + } + +McEliece_PrivateKey::McEliece_PrivateKey(const secure_vector& key_bits) + { + size_t n, t; + secure_vector enc_g; + BER_Decoder dec_base(key_bits); + BER_Decoder dec = dec_base.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .decode(n) + .decode(t) + .end_cons() + .decode(m_public_matrix, OCTET_STRING) + .decode(enc_g, OCTET_STRING); + + if(t == 0 || n == 0) + throw Decoding_Error("invalid McEliece parameters"); + + uint32_t ext_deg = ceil_log2(n); + m_code_length = n; + m_t = t; + m_codimension = (ext_deg * t); + m_dimension = (n - m_codimension); + + std::shared_ptr sp_field(new GF2m_Field(ext_deg)); + m_g = { polyn_gf2m(enc_g, sp_field) }; + if(m_g[0].get_degree() != static_cast(t)) + { + throw Decoding_Error("degree of decoded Goppa polynomial is incorrect"); + } + BER_Decoder dec2 = dec.start_cons(SEQUENCE); + for(uint32_t i = 0; i < t/2; i++) + { + secure_vector sqrt_enc; + dec2.decode(sqrt_enc, OCTET_STRING); + while(sqrt_enc.size() < (t*2)) + { + // ensure that the length is always t + sqrt_enc.push_back(0); + sqrt_enc.push_back(0); + } + if(sqrt_enc.size() != t*2) + { + throw Decoding_Error("length of square root polynomial entry is too large"); + } + m_sqrtmod.push_back(polyn_gf2m(sqrt_enc, sp_field)); + } + secure_vector enc_support; + BER_Decoder dec3 = dec2.end_cons() + .decode(enc_support, OCTET_STRING); + if(enc_support.size() % 2) + { + throw Decoding_Error("encoded support has odd length"); + } + if(enc_support.size() / 2 != n) + { + throw Decoding_Error("encoded support has length different from code length"); + } + for(uint32_t i = 0; i < n*2; i+=2) + { + gf2m el = (enc_support[i] << 8) | enc_support[i+1]; + m_Linv.push_back(el); + } + secure_vector enc_H; + dec3.decode(enc_H, OCTET_STRING) + .end_cons(); + if(enc_H.size() % 4) + { + throw Decoding_Error("encoded parity check matrix has length which is not a multiple of four"); + } + if(enc_H.size() / 4 != bit_size_to_32bit_size(m_codimension) * m_code_length) + { + throw Decoding_Error("encoded parity check matrix has wrong length"); + } + + for(uint32_t i = 0; i < enc_H.size(); i+=4) + { + uint32_t coeff = (enc_H[i] << 24) | (enc_H[i+1] << 16) | (enc_H[i+2] << 8) | enc_H[i+3]; + m_coeffs.push_back(coeff); + } + + } + +bool McEliece_PrivateKey::operator==(const McEliece_PrivateKey & other) const + { + if(*static_cast(this) != *static_cast(&other)) + { + return false; + } + if(m_g != other.m_g) + { + return false; + } + + if( m_sqrtmod != other.m_sqrtmod) + { + return false; + } + if( m_Linv != other.m_Linv) + { + return false; + } + if( m_coeffs != other.m_coeffs) + { + return false; + } + + if(m_codimension != other.m_codimension || m_dimension != other.m_dimension) + { + return false; + } + + return true; + } + +bool McEliece_PublicKey::operator==(const McEliece_PublicKey& other) const + { + if(m_public_matrix != other.m_public_matrix) + { + return false; + } + if(m_t != other.m_t) + { + return false; + } + if( m_code_length != other.m_code_length) + { + return false; + } + return true; + } + +namespace { + +class MCE_KEM_Encryptor final : public PK_Ops::KEM_Encryption_with_KDF + { + public: + + MCE_KEM_Encryptor(const McEliece_PublicKey& key, + const std::string& kdf) : + KEM_Encryption_with_KDF(kdf), m_key(key) {} + + private: + void raw_kem_encrypt(secure_vector& out_encapsulated_key, + secure_vector& raw_shared_key, + Botan::RandomNumberGenerator& rng) override + { + secure_vector plaintext = m_key.random_plaintext_element(rng); + + secure_vector ciphertext, error_mask; + mceliece_encrypt(ciphertext, error_mask, plaintext, m_key, rng); + + raw_shared_key.clear(); + raw_shared_key += plaintext; + raw_shared_key += error_mask; + + out_encapsulated_key.swap(ciphertext); + } + + const McEliece_PublicKey& m_key; + }; + +class MCE_KEM_Decryptor final : public PK_Ops::KEM_Decryption_with_KDF + { + public: + + MCE_KEM_Decryptor(const McEliece_PrivateKey& key, + const std::string& kdf) : + KEM_Decryption_with_KDF(kdf), m_key(key) {} + + private: + secure_vector + raw_kem_decrypt(const uint8_t encap_key[], size_t len) override + { + secure_vector plaintext, error_mask; + mceliece_decrypt(plaintext, error_mask, encap_key, len, m_key); + + secure_vector output; + output.reserve(plaintext.size() + error_mask.size()); + output.insert(output.end(), plaintext.begin(), plaintext.end()); + output.insert(output.end(), error_mask.begin(), error_mask.end()); + return output; + } + + const McEliece_PrivateKey& m_key; + }; + +} + +std::unique_ptr +McEliece_PublicKey::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new MCE_KEM_Encryptor(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +McEliece_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new MCE_KEM_Decryptor(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +} + + diff --git a/comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.cpp b/comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.cpp new file mode 100644 index 0000000000..592ab72625 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.cpp @@ -0,0 +1,806 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * (C) 2015 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +gf2m generate_gf2m_mask(gf2m a) + { + gf2m result = (a != 0); + return ~(result - 1); + } + +/** +* number of leading zeros +*/ +unsigned nlz_16bit(uint16_t x) + { + unsigned n; + if(x == 0) return 16; + n = 0; + if(x <= 0x00FF) {n = n + 8; x = x << 8;} + if(x <= 0x0FFF) {n = n + 4; x = x << 4;} + if(x <= 0x3FFF) {n = n + 2; x = x << 2;} + if(x <= 0x7FFF) {n = n + 1;} + return n; + } +} + +int polyn_gf2m::calc_degree_secure() const + { + int i = static_cast(this->coeff.size()) - 1; + int result = 0; + uint32_t found_mask = 0; + uint32_t tracker_mask = 0xffff; + for( ; i >= 0; i--) + { + found_mask = expand_mask_16bit(this->coeff[i]); + result |= i & found_mask & tracker_mask; + // tracker mask shall become zero once found mask is set + // it shall remain zero from then on + tracker_mask = tracker_mask & ~found_mask; + } + const_cast(this)->m_deg = result; + return result; + } + +gf2m random_gf2m(RandomNumberGenerator& rng) + { + uint8_t b[2]; + rng.randomize(b, sizeof(b)); + return make_uint16(b[1], b[0]); + } + +gf2m random_code_element(uint16_t code_length, RandomNumberGenerator& rng) + { + if(code_length == 0) + { + throw Invalid_Argument("random_code_element() was supplied a code length of zero"); + } + const unsigned nlz = nlz_16bit(code_length-1); + const gf2m mask = (1 << (16-nlz)) - 1; + + gf2m result; + + do + { + result = random_gf2m(rng); + result &= mask; + } while(result >= code_length); // rejection sampling + + return result; + } + +polyn_gf2m::polyn_gf2m(polyn_gf2m const& other) + :m_deg(other.m_deg), + coeff(other.coeff), + m_sp_field(other.m_sp_field) + { } + +polyn_gf2m::polyn_gf2m(int d, std::shared_ptr sp_field) + :m_deg(-1), + coeff(d+1), + m_sp_field(sp_field) + { + } + +std::string polyn_gf2m::to_string() const + { + int d = get_degree(); + std::string result; + for(int i = 0; i <= d; i ++) + { + result += std::to_string(this->coeff[i]); + if(i != d) + { + result += ", "; + } + } + return result; + } +/** +* doesn't save coefficients: +*/ +void polyn_gf2m::realloc(uint32_t new_size) + { + this->coeff = secure_vector(new_size); + } + +polyn_gf2m::polyn_gf2m(const uint8_t* mem, uint32_t mem_len, std::shared_ptr sp_field) : + m_deg(-1), m_sp_field(sp_field) + { + if(mem_len % sizeof(gf2m)) + { + throw Decoding_Error("illegal length of memory to decode "); + } + + uint32_t size = (mem_len / sizeof(this->coeff[0])) ; + this->coeff = secure_vector(size); + this->m_deg = -1; + for(uint32_t i = 0; i < size; i++) + { + this->coeff[i] = decode_gf2m(mem); + mem += sizeof(this->coeff[0]); + } + for(uint32_t i = 0; i < size; i++) + { + if(this->coeff[i] >= (1 << sp_field->get_extension_degree())) + { + throw Decoding_Error("error decoding polynomial"); + } + } + this->get_degree(); + } + + +polyn_gf2m::polyn_gf2m( std::shared_ptr sp_field) : + m_deg(-1), coeff(1), m_sp_field(sp_field) + {} + +polyn_gf2m::polyn_gf2m(int degree, const uint8_t* mem, size_t mem_byte_len, std::shared_ptr sp_field) + :m_sp_field(sp_field) + { + uint32_t j, k, l; + gf2m a; + uint32_t polyn_size; + polyn_size = degree + 1; + if(polyn_size * sp_field->get_extension_degree() > 8 * mem_byte_len) + { + throw Decoding_Error("memory vector for polynomial has wrong size"); + } + this->coeff = secure_vector(degree+1); + gf2m ext_deg = static_cast(this->m_sp_field->get_extension_degree()); + for (l = 0; l < polyn_size; l++) + { + k = (l * ext_deg) / 8; + + j = (l * ext_deg) % 8; + a = mem[k] >> j; + if (j + ext_deg > 8) + { + a ^= mem[k + 1] << (8- j); + } + if(j + ext_deg > 16) + { + a ^= mem[k + 2] << (16- j); + } + a &= ((1 << ext_deg) - 1); + (*this).set_coef( l, a); + } + + this->get_degree(); + } + +#if 0 +void polyn_gf2m::encode(uint32_t min_numo_coeffs, uint8_t* mem, uint32_t mem_len) const + { + uint32_t i; + uint32_t numo_coeffs, needed_size; + this->get_degree(); + numo_coeffs = (min_numo_coeffs > static_cast(this->m_deg+1)) ? min_numo_coeffs : this->m_deg+1; + needed_size = sizeof(this->coeff[0]) * numo_coeffs; + if(mem_len < needed_size) + { + Invalid_Argument("provided memory too small to encode polynomial"); + } + + for(i = 0; i < numo_coeffs; i++) + { + gf2m to_enc; + if(i >= static_cast(this->m_deg+1)) + { + /* encode a zero */ + to_enc = 0; + } + else + { + to_enc = this->coeff[i]; + } + mem += encode_gf2m(to_enc, mem); + } + } +#endif + + +void polyn_gf2m::set_to_zero() + { + clear_mem(&this->coeff[0], this->coeff.size()); + this->m_deg = -1; + } + +int polyn_gf2m::get_degree() const + { + int d = static_cast(this->coeff.size()) - 1; + while ((d >= 0) && (this->coeff[d] == 0)) + --d; + const_cast(this)->m_deg = d; + return d; + } + + +static gf2m eval_aux(const gf2m * /*restrict*/ coeff, gf2m a, int d, std::shared_ptr sp_field) + { + gf2m b; + b = coeff[d--]; + for (; d >= 0; --d) + if (b != 0) + { + b = sp_field->gf_mul(b, a) ^ coeff[d]; + } + else + { + b = coeff[d]; + } + return b; + } + +gf2m polyn_gf2m::eval(gf2m a) + { + return eval_aux(&this->coeff[0], a, this->m_deg, this->m_sp_field); + } + + +// p will contain it's remainder modulo g +void polyn_gf2m::remainder(polyn_gf2m &p, const polyn_gf2m & g) + { + int i, j, d; + std::shared_ptr m_sp_field = g.m_sp_field; + d = p.get_degree() - g.get_degree(); + if (d >= 0) { + gf2m la = m_sp_field->gf_inv_rn(g.get_lead_coef()); + + const int p_degree = p.get_degree(); + + BOTAN_ASSERT(p_degree > 0, "Valid polynomial"); + + for (i = p_degree; d >= 0; --i, --d) { + if (p[i] != 0) { + gf2m lb = m_sp_field->gf_mul_rrn(la, p[i]); + for (j = 0; j < g.get_degree(); ++j) + { + p[j+d] ^= m_sp_field->gf_mul_zrz(lb, g[j]); + } + (*&p).set_coef( i, 0); + } + } + p.set_degree( g.get_degree() - 1); + while ((p.get_degree() >= 0) && (p[p.get_degree()] == 0)) + p.set_degree( p.get_degree() - 1); + } + } + +std::vector polyn_gf2m::sqmod_init(const polyn_gf2m & g) + { + std::vector sq; + const int signed_deg = g.get_degree(); + if(signed_deg <= 0) + throw Invalid_Argument("cannot compute sqmod for such low degree"); + + const uint32_t d = static_cast(signed_deg); + uint32_t t = g.m_deg; + // create t zero polynomials + uint32_t i; + for (i = 0; i < t; ++i) + { + sq.push_back(polyn_gf2m(t+1, g.get_sp_field())); + } + for (i = 0; i < d / 2; ++i) + { + sq[i].set_degree( 2 * i); + (*&sq[i]).set_coef( 2 * i, 1); + } + + for (; i < d; ++i) + { + clear_mem(&sq[i].coeff[0], 2); + copy_mem(&sq[i].coeff[0] + 2, &sq[i - 1].coeff[0], d); + sq[i].set_degree( sq[i - 1].get_degree() + 2); + polyn_gf2m::remainder(sq[i], g); + } + return sq; + } + +/*Modulo p square of a certain polynomial g, sq[] contains the square +Modulo g of the base canonical polynomials of degree < d, where d is +the degree of G. The table sq[] will be calculated by polyn_gf2m_sqmod_init*/ +polyn_gf2m polyn_gf2m::sqmod( const std::vector & sq, int d) + { + int i, j; + gf2m la; + std::shared_ptr sp_field = this->m_sp_field; + + polyn_gf2m result(d - 1, sp_field); + // terms of low degree + for (i = 0; i < d / 2; ++i) + { + (*&result).set_coef( i * 2, sp_field->gf_square((*this)[i])); + } + + // terms of high degree + for (; i < d; ++i) + { + gf2m lpi = (*this)[i]; + if (lpi != 0) + { + lpi = sp_field->gf_log(lpi); + la = sp_field->gf_mul_rrr(lpi, lpi); + for (j = 0; j < d; ++j) + { + result[j] ^= sp_field->gf_mul_zrz(la, sq[i][j]); + } + } + } + + // Update degre + result.set_degree( d - 1); + while ((result.get_degree() >= 0) && (result[result.get_degree()] == 0)) + result.set_degree( result.get_degree() - 1); + return result; + } + + +// destructive +polyn_gf2m polyn_gf2m::gcd_aux(polyn_gf2m& p1, polyn_gf2m& p2) + { + if (p2.get_degree() == -1) + return p1; + else { + polyn_gf2m::remainder(p1, p2); + return polyn_gf2m::gcd_aux(p2, p1); + } + } + + +polyn_gf2m polyn_gf2m::gcd(polyn_gf2m const& p1, polyn_gf2m const& p2) + { + polyn_gf2m a(p1); + polyn_gf2m b(p2); + if (a.get_degree() < b.get_degree()) + { + return polyn_gf2m(polyn_gf2m::gcd_aux(b, a)); + } + else + { + return polyn_gf2m(polyn_gf2m::gcd_aux(a, b)); + } + } + + + + + +// Returns the degree of the smallest factor +size_t polyn_gf2m::degppf(const polyn_gf2m& g) + { + polyn_gf2m s(g.get_sp_field()); + + const size_t ext_deg = g.m_sp_field->get_extension_degree(); + const int d = g.get_degree(); + std::vector u = polyn_gf2m::sqmod_init(g); + + polyn_gf2m p(d - 1, g.m_sp_field); + + p.set_degree(1); + (*&p).set_coef(1, 1); + size_t result = static_cast(d); + for(size_t i = 1; i <= (d / 2) * ext_deg; ++i) + { + polyn_gf2m r = p.sqmod(u, d); + if ((i % ext_deg) == 0) + { + r[1] ^= 1; + r.get_degree(); // The degree may change + s = polyn_gf2m::gcd( g, r); + + if(s.get_degree() > 0) + { + result = i / ext_deg; + break; + } + r[1] ^= 1; + r.get_degree(); // The degree may change + } + // No need for the exchange s + s = p; + p = r; + r = s; + } + + return result; + } + +void polyn_gf2m::patchup_deg_secure( uint32_t trgt_deg, volatile gf2m patch_elem) + { + uint32_t i; + if(this->coeff.size() < trgt_deg) + { + return; + } + for(i = 0; i < this->coeff.size(); i++) + { + uint32_t equal, equal_mask; + this->coeff[i] |= patch_elem; + equal = (i == trgt_deg); + equal_mask = expand_mask_16bit(equal); + patch_elem &= ~equal_mask; + } + this->calc_degree_secure(); + } +// We suppose m_deg(g) >= m_deg(p) +// v is the problem +std::pair polyn_gf2m::eea_with_coefficients( const polyn_gf2m & p, const polyn_gf2m & g, int break_deg) + { + + std::shared_ptr m_sp_field = g.m_sp_field; + int i, j, dr, du, delta; + gf2m a; + polyn_gf2m aux; + + // initialisation of the local variables + // r0 <- g, r1 <- p, u0 <- 0, u1 <- 1 + dr = g.get_degree(); + + BOTAN_ASSERT(dr > 3, "Valid polynomial"); + + polyn_gf2m r0(dr, g.m_sp_field); + polyn_gf2m r1(dr - 1, g.m_sp_field); + polyn_gf2m u0(dr - 1, g.m_sp_field); + polyn_gf2m u1(dr - 1, g.m_sp_field); + + r0 = g; + r1 = p; + u0.set_to_zero(); + u1.set_to_zero(); + (*&u1).set_coef( 0, 1); + u1.set_degree( 0); + + + // invariants: + // r1 = u1 * p + v1 * g + // r0 = u0 * p + v0 * g + // and m_deg(u1) = m_deg(g) - m_deg(r0) + // It stops when m_deg (r1) = t) + // And therefore m_deg (u1) = m_deg (g) - m_deg (r0) = break_deg) + { + + for (j = delta; j >= 0; --j) + { + a = m_sp_field->gf_div(r0[dr + j], r1[dr]); + if (a != 0) + { + gf2m la = m_sp_field->gf_log(a); + // u0(z) <- u0(z) + a * u1(z) * z^j + for (i = 0; i <= du; ++i) + { + u0[i + j] ^= m_sp_field->gf_mul_zrz(la, u1[i]); + } + // r0(z) <- r0(z) + a * r1(z) * z^j + for (i = 0; i <= dr; ++i) + { + r0[i + j] ^= m_sp_field->gf_mul_zrz(la, r1[i]); + } + } + } // end loop over j + + if(break_deg != 1) /* key eq. solving */ + { + /* [ssms_icisc09] Countermeasure + * d_break from paper equals break_deg - 1 + * */ + + volatile gf2m fake_elem = 0x01; + volatile gf2m cond1, cond2; + int trgt_deg = r1.get_degree() - 1; + r0.calc_degree_secure(); + u0.calc_degree_secure(); + if(!(g.get_degree() % 2)) + { + /* t even */ + cond1 = r0.get_degree() < break_deg - 1; + } + else + { + /* t odd */ + cond1 = r0.get_degree() < break_deg; + cond2 = u0.get_degree() < break_deg - 1; + cond1 &= cond2; + } + /* expand cond1 to a full mask */ + gf2m mask = generate_gf2m_mask(cond1); + fake_elem &= mask; + r0.patchup_deg_secure(trgt_deg, fake_elem); + } + if(break_deg == 1) /* syndrome inversion */ + { + volatile gf2m fake_elem = 0x00; + volatile uint32_t trgt_deg = 0; + r0.calc_degree_secure(); + u0.calc_degree_secure(); + /** + * countermeasure against the low weight attacks for w=4, w=6 and w=8. + * Higher values are not covered since for w=8 we already have a + * probability for a positive of 1/n^3 from random ciphertexts with the + * given weight. For w = 10 it would be 1/n^4 and so on. Thus attacks + * based on such high values of w are considered impractical. + * + * The outer test for the degree of u ( Omega in the paper ) needs not to + * be disguised. Each of the three is performed at most once per EEA + * (syndrome inversion) execution, the attacker knows this already when + * preparing the ciphertext with the given weight. Inside these three + * cases however, we must use timing neutral (branch free) operations to + * implement the condition detection and the counteractions. + * + */ + if(u0.get_degree() == 4) + { + uint32_t mask = 0; + /** + * Condition that the EEA would break now + */ + int cond_r = r0.get_degree() == 0; + /** + * Now come the conditions for all odd coefficients of this sigma + * candiate. If they are all fulfilled, then we know that we have a low + * weight error vector, since the key-equation solving EEA is skipped if + * the degree of tau^2 is low (=m_deg(u0)) and all its odd cofficients are + * zero (they would cause "full-length" contributions from the square + * root computation). + */ + // Condition for the coefficient to Y to be cancelled out by the + // addition of Y before the square root computation: + int cond_u1 = m_sp_field->gf_mul(u0.coeff[1], m_sp_field->gf_inv(r0.coeff[0])) == 1; + + // Condition sigma_3 = 0: + int cond_u3 = u0.coeff[3] == 0; + // combine the conditions: + cond_r &= (cond_u1 & cond_u3); + // mask generation: + mask = expand_mask_16bit(cond_r); + trgt_deg = 2 & mask; + fake_elem = 1 & mask; + } + else if(u0.get_degree() == 6) + { + uint32_t mask = 0; + int cond_r= r0.get_degree() == 0; + int cond_u1 = m_sp_field->gf_mul(u0.coeff[1], m_sp_field->gf_inv(r0.coeff[0])) == 1; + int cond_u3 = u0.coeff[3] == 0; + + int cond_u5 = u0.coeff[5] == 0; + + cond_r &= (cond_u1 & cond_u3 & cond_u5); + mask = expand_mask_16bit(cond_r); + trgt_deg = 4 & mask; + fake_elem = 1 & mask; + } + else if(u0.get_degree() == 8) + { + uint32_t mask = 0; + int cond_r= r0.get_degree() == 0; + int cond_u1 = m_sp_field->gf_mul(u0[1], m_sp_field->gf_inv(r0[0])) == 1; + int cond_u3 = u0.coeff[3] == 0; + + int cond_u5 = u0.coeff[5] == 0; + + int cond_u7 = u0.coeff[7] == 0; + + cond_r &= (cond_u1 & cond_u3 & cond_u5 & cond_u7); + mask = expand_mask_16bit(cond_r); + trgt_deg = 6 & mask; + fake_elem = 1 & mask; + } + r0.patchup_deg_secure(trgt_deg, fake_elem); + } + // exchange + aux = r0; r0 = r1; r1 = aux; + aux = u0; u0 = u1; u1 = aux; + + du = du + delta; + delta = 1; + while (r1[dr - delta] == 0) + { + delta++; + } + + + dr -= delta; + } /* end while loop (dr >= break_deg) */ + + + u1.set_degree( du); + r1.set_degree( dr); + //return u1 and r1; + return std::make_pair(u1,r1); // coefficients u,v + } + +polyn_gf2m::polyn_gf2m(size_t t, RandomNumberGenerator& rng, std::shared_ptr sp_field) + :m_deg(static_cast(t)), + coeff(t+1), + m_sp_field(sp_field) + { + this->set_coef(t, 1); + for(;;) + { + for(size_t i = 0; i < t; ++i) + { + this->set_coef(i, random_code_element(sp_field->get_cardinality(), rng)); + } + + const size_t degree = polyn_gf2m::degppf(*this); + + if(degree >= t) + break; + } + } + +void polyn_gf2m::poly_shiftmod( const polyn_gf2m & g) + { + if(g.get_degree() <= 1) + { + throw Invalid_Argument("shiftmod cannot be called on polynomials of degree 1 or less"); + } + std::shared_ptr field = g.m_sp_field; + + int t = g.get_degree(); + gf2m a = field->gf_div(this->coeff[t-1], g.coeff[t]); + for (int i = t - 1; i > 0; --i) + { + this->coeff[i] = this->coeff[i - 1] ^ this->m_sp_field->gf_mul(a, g.coeff[i]); + } + this->coeff[0] = field->gf_mul(a, g.coeff[0]); + } + +std::vector polyn_gf2m::sqrt_mod_init(const polyn_gf2m & g) + { + uint32_t i, t; + uint32_t nb_polyn_sqrt_mat; + std::shared_ptr m_sp_field = g.m_sp_field; + std::vector result; + t = g.get_degree(); + nb_polyn_sqrt_mat = t/2; + + std::vector sq_aux = polyn_gf2m::sqmod_init(g); + + + polyn_gf2m p( t - 1, g.get_sp_field()); + p.set_degree( 1); + + (*&p).set_coef( 1, 1); + // q(z) = 0, p(z) = z + for (i = 0; i < t * m_sp_field->get_extension_degree() - 1; ++i) + { + // q(z) <- p(z)^2 mod g(z) + polyn_gf2m q = p.sqmod(sq_aux, t); + // q(z) <-> p(z) + polyn_gf2m aux = q; + q = p; + p = aux; + } + // p(z) = z^(2^(tm-1)) mod g(z) = sqrt(z) mod g(z) + + for (i = 0; i < nb_polyn_sqrt_mat; ++i) + { + result.push_back(polyn_gf2m(t - 1, g.get_sp_field())); + } + + result[0] = p; + result[0].get_degree(); + for(i = 1; i < nb_polyn_sqrt_mat; i++) + { + result[i] = result[i - 1]; + result[i].poly_shiftmod(g), + result[i].get_degree(); + } + + return result; + } + +std::vector syndrome_init(polyn_gf2m const& generator, std::vector const& support, int n) + { + int i,j,t; + gf2m a; + + + std::shared_ptr m_sp_field = generator.m_sp_field; + + std::vector result; + t = generator.get_degree(); + + //g(z)=g_t+g_(t-1).z^(t-1)+......+g_1.z+g_0 + //f(z)=f_(t-1).z^(t-1)+......+f_1.z+f_0 + + for(j=0;j=0;i--) + { + (*&result[j]).set_coef(i, (generator)[i+1] ^ + m_sp_field->gf_mul(lex_to_gray(support[j]),result[j][i+1])); + } + a = ((generator)[0] ^ m_sp_field->gf_mul(lex_to_gray(support[j]),result[j][0])); + for(i=0;igf_div(result[j][i],a)); + } + } + return result; + } + +polyn_gf2m::polyn_gf2m(const secure_vector& encoded, std::shared_ptr sp_field ) + :m_sp_field(sp_field) + { + if(encoded.size() % 2) + { + throw Decoding_Error("encoded polynomial has odd length"); + } + for(uint32_t i = 0; i < encoded.size(); i += 2) + { + gf2m el = (encoded[i] << 8) | encoded[i + 1]; + coeff.push_back(el); + } + get_degree(); + + } +secure_vector polyn_gf2m::encode() const + { + secure_vector result; + + if(m_deg < 1) + { + result.push_back(0); + result.push_back(0); + return result; + } + + uint32_t len = m_deg+1; + for(unsigned i = 0; i < len; i++) + { + // "big endian" encoding of the GF(2^m) elements + result.push_back(get_byte(0, coeff[i])); + result.push_back(get_byte(1, coeff[i])); + } + return result; + } + +void polyn_gf2m::swap(polyn_gf2m& other) + { + std::swap(this->m_deg, other.m_deg); + std::swap(this->m_sp_field, other.m_sp_field); + std::swap(this->coeff, other.coeff); + } + +bool polyn_gf2m::operator==(const polyn_gf2m & other) const + { + if(m_deg != other.m_deg || coeff != other.coeff) + { + return false; + } + return true; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.h b/comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.h new file mode 100644 index 0000000000..0f9bf07f9a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mce/polyn_gf2m.h @@ -0,0 +1,174 @@ +/* + * (C) Copyright Projet SECRET, INRIA, Rocquencourt + * (C) Bhaskar Biswas and Nicolas Sendrier + * + * (C) 2014 cryptosource GmbH + * (C) 2014 Falko Strenzke fstrenzke@cryptosource.de + * + * Botan is released under the Simplified BSD License (see license.txt) + * + */ + +#ifndef BOTAN_POLYN_GF2M_H_ +#define BOTAN_POLYN_GF2M_H_ + +#include +#include +#include + +// Currently must be visible for MSVC +//BOTAN_FUTURE_INTERNAL_HEADER(polyn_gf2m.h) + +namespace Botan { + +typedef uint16_t gf2m; + +class GF2m_Field; + +class RandomNumberGenerator; + +class polyn_gf2m + { + public: + /** + * create a zero polynomial: + */ + explicit polyn_gf2m(std::shared_ptr sp_field); + + polyn_gf2m() : m_deg(-1) {} + + polyn_gf2m(const secure_vector& encoded, std::shared_ptr sp_field); + + polyn_gf2m& operator=(const polyn_gf2m&) = default; + + /** + * create zero polynomial with reservation of space for a degree d polynomial + */ + polyn_gf2m(int d, std::shared_ptr sp_field); + + polyn_gf2m(polyn_gf2m const& other); + + /** + * random irreducible polynomial of degree t + */ + polyn_gf2m(size_t t, RandomNumberGenerator& rng, std::shared_ptr sp_field); + + /** decode a polynomial from memory: **/ + polyn_gf2m(const uint8_t* mem, uint32_t mem_len, std::shared_ptr sp_field); + + /** + * create a polynomial from memory area (encoded) + */ + polyn_gf2m(int degree, const uint8_t* mem, size_t mem_byte_len, std::shared_ptr sp_field); + + bool operator==(const polyn_gf2m & other) const ; + + bool operator!=(const polyn_gf2m & other) const { return !(*this == other); } + + polyn_gf2m(polyn_gf2m&& other) + { + this->swap(other); + } + + polyn_gf2m & operator=(polyn_gf2m&& other) + { + if(this != &other) + { + this->swap(other); + } + return *this; + } + + void swap(polyn_gf2m& other); + + secure_vector encode() const; + + std::shared_ptr get_sp_field() const + { return m_sp_field; } + + gf2m& operator[](size_t i) { return coeff[i]; } + + gf2m operator[](size_t i) const { return coeff[i]; } + + gf2m get_lead_coef() const { return coeff[m_deg]; } + + gf2m get_coef(size_t i) const { return coeff[i]; } + + inline void set_coef(size_t i, gf2m v) + { + coeff[i] = v; + } + + inline void add_to_coef(size_t i, gf2m v) + { + coeff[i] ^= v; + } + + std::string to_string() const; + + void encode(uint32_t min_numo_coeffs, uint8_t* mem, uint32_t mem_len) const; + + int get_degree() const; + + /** + * determine the degree in a timing secure manner. the timing of this function + * only depends on the number of allocated coefficients, not on the actual + * degree + */ + int calc_degree_secure() const; + + size_t degppf(const polyn_gf2m& g); + + static std::vector sqmod_init(const polyn_gf2m & g); + + static std::vector sqrt_mod_init(const polyn_gf2m & g); + + + polyn_gf2m sqmod(const std::vector & sq, int d); + void set_to_zero(); + gf2m eval(gf2m a); + + static std::pair eea_with_coefficients(const polyn_gf2m & p, + const polyn_gf2m & g, + int break_deg); + + void patchup_deg_secure( uint32_t trgt_deg, volatile gf2m patch_elem); + + private: + + void set_degree(int d) { m_deg = d; } + + void poly_shiftmod( const polyn_gf2m & g); + void realloc(uint32_t new_size); + static polyn_gf2m gcd(polyn_gf2m const& p1, polyn_gf2m const& p2); + + /** + * destructive: + */ + static void remainder(polyn_gf2m & p, const polyn_gf2m & g); + + static polyn_gf2m gcd_aux(polyn_gf2m& p1, polyn_gf2m& p2); + public: + // public member variable: + int m_deg; + + // public member variable: + secure_vector coeff; + + // public member variable: + std::shared_ptr m_sp_field; + }; + +gf2m random_gf2m(RandomNumberGenerator& rng); +gf2m random_code_element(uint16_t code_length, RandomNumberGenerator& rng); + +std::vector syndrome_init(polyn_gf2m const& generator, std::vector const& support, int n); + +/** +* Find the roots of a polynomial over GF(2^m) using the method by Federenko et al. +*/ +secure_vector find_roots_gf2m_decomp(const polyn_gf2m & polyn, size_t code_length); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/mceies/info.txt b/comm/third_party/botan/src/lib/pubkey/mceies/info.txt new file mode 100644 index 0000000000..cf5e011540 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mceies/info.txt @@ -0,0 +1,10 @@ + +MCEIES -> 20150706 + + + +aes +mce +ocb +kdf1 + diff --git a/comm/third_party/botan/src/lib/pubkey/mceies/mceies.cpp b/comm/third_party/botan/src/lib/pubkey/mceies/mceies.cpp new file mode 100644 index 0000000000..4d62889fee --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mceies/mceies.cpp @@ -0,0 +1,110 @@ +/* +* McEliece Integrated Encryption System +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector aead_key(const secure_vector& mk, + const AEAD_Mode& aead) + { + // Fold the key as required for the AEAD mode in use + if(aead.valid_keylength(mk.size())) + return mk; + + secure_vector r(aead.key_spec().maximum_keylength()); + BOTAN_ASSERT_NOMSG(r.size() > 0); + for(size_t i = 0; i != mk.size(); ++i) + r[i % r.size()] ^= mk[i]; + return r; + } + +} + +secure_vector +mceies_encrypt(const McEliece_PublicKey& pubkey, + const uint8_t pt[], size_t pt_len, + const uint8_t ad[], size_t ad_len, + RandomNumberGenerator& rng, + const std::string& algo) + { + PK_KEM_Encryptor kem_op(pubkey, rng, "KDF1(SHA-512)"); + + secure_vector mce_ciphertext, mce_key; + kem_op.encrypt(mce_ciphertext, mce_key, 64, rng); + + const size_t mce_code_bytes = (pubkey.get_code_length() + 7) / 8; + + BOTAN_ASSERT(mce_ciphertext.size() == mce_code_bytes, "Unexpected size"); + + std::unique_ptr aead = AEAD_Mode::create_or_throw(algo, ENCRYPTION); + + const size_t nonce_len = aead->default_nonce_length(); + + aead->set_key(aead_key(mce_key, *aead)); + aead->set_associated_data(ad, ad_len); + + const secure_vector nonce = rng.random_vec(nonce_len); + + secure_vector msg(mce_ciphertext.size() + nonce.size() + pt_len); + copy_mem(msg.data(), mce_ciphertext.data(), mce_ciphertext.size()); + copy_mem(msg.data() + mce_ciphertext.size(), nonce.data(), nonce.size()); + copy_mem(msg.data() + mce_ciphertext.size() + nonce.size(), pt, pt_len); + + aead->start(nonce); + aead->finish(msg, mce_ciphertext.size() + nonce.size()); + return msg; + } + +secure_vector +mceies_decrypt(const McEliece_PrivateKey& privkey, + const uint8_t ct[], size_t ct_len, + const uint8_t ad[], size_t ad_len, + const std::string& algo) + { + try + { + Null_RNG null_rng; + PK_KEM_Decryptor kem_op(privkey, null_rng, "KDF1(SHA-512)"); + + const size_t mce_code_bytes = (privkey.get_code_length() + 7) / 8; + + std::unique_ptr aead = AEAD_Mode::create_or_throw(algo, DECRYPTION); + + const size_t nonce_len = aead->default_nonce_length(); + + if(ct_len < mce_code_bytes + nonce_len + aead->tag_size()) + throw Decoding_Error("Input message too small to be valid"); + + const secure_vector mce_key = kem_op.decrypt(ct, mce_code_bytes, 64); + + aead->set_key(aead_key(mce_key, *aead)); + aead->set_associated_data(ad, ad_len); + + secure_vector pt(ct + mce_code_bytes + nonce_len, ct + ct_len); + + aead->start(&ct[mce_code_bytes], nonce_len); + aead->finish(pt, 0); + return pt; + } + catch(Invalid_Authentication_Tag&) + { + throw; + } + catch(std::exception& e) + { + throw Decoding_Error("mce_decrypt failed: " + std::string(e.what())); + } + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/mceies/mceies.h b/comm/third_party/botan/src/lib/pubkey/mceies/mceies.h new file mode 100644 index 0000000000..c9b3f7efd5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/mceies/mceies.h @@ -0,0 +1,46 @@ +/* +* McEliece Integrated Encryption System +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MCEIES_H_ +#define BOTAN_MCEIES_H_ + +#include +#include + +namespace Botan { + +class RandomNumberGenerator; +class McEliece_PublicKey; +class McEliece_PrivateKey; + +/** +* McEliece Integrated Encryption System +* Derive a shared key using MCE KEM and encrypt/authenticate the +* plaintext and AD using AES-256 in OCB mode. +*/ +secure_vector +BOTAN_PUBLIC_API(2,0) mceies_encrypt(const McEliece_PublicKey& pubkey, + const uint8_t pt[], size_t pt_len, + const uint8_t ad[], size_t ad_len, + RandomNumberGenerator& rng, + const std::string& aead = "AES-256/OCB"); + +/** +* McEliece Integrated Encryption System +* Derive a shared key using MCE KEM and decrypt/authenticate the +* ciphertext and AD using AES-256 in OCB mode. +*/ +secure_vector +BOTAN_PUBLIC_API(2,0) mceies_decrypt(const McEliece_PrivateKey& privkey, + const uint8_t ct[], size_t ct_len, + const uint8_t ad[], size_t ad_len, + const std::string& aead = "AES-256/OCB"); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/newhope/info.txt b/comm/third_party/botan/src/lib/pubkey/newhope/info.txt new file mode 100644 index 0000000000..4877a138bb --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/newhope/info.txt @@ -0,0 +1,12 @@ + +NEWHOPE -> 20161018 + + + +sha3 +shake_cipher + +sha2_32 +ctr +aes + diff --git a/comm/third_party/botan/src/lib/pubkey/newhope/newhope.cpp b/comm/third_party/botan/src/lib/pubkey/newhope/newhope.cpp new file mode 100644 index 0000000000..6a0440139e --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/newhope/newhope.cpp @@ -0,0 +1,800 @@ +/* +* NEWHOPE Ring-LWE scheme +* Based on the public domain reference implementation by the +* designers (https://github.com/tpoeppelmann/newhope) +* +* Further changes +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +newhope_poly::~newhope_poly() + { + secure_scrub_memory(coeffs, sizeof(coeffs)); + } + +typedef newhope_poly poly; + +namespace { + +static const uint16_t PARAM_Q = 12289; +static const size_t PARAM_N = 1024; + +/* Incomplete-reduction routines; for details on allowed input ranges + * and produced output ranges, see the description in the paper: + * https://cryptojedi.org/papers/#newhope */ + +inline uint16_t montgomery_reduce(uint32_t a) + { + const uint32_t qinv = 12287; // -inverse_mod(p,2^18) + const uint32_t rlog = 18; + const uint32_t rlog_mask = ((1 << rlog) - 1); + + uint32_t u = (a * qinv); + u &= rlog_mask; + u *= PARAM_Q; + u += a; + return (u >> rlog); + } + +inline uint16_t barrett_reduce(uint16_t a) + { + uint32_t u = (static_cast(a) * 5) >> 16; + u *= PARAM_Q; + a = static_cast(a - u); + return a; + } + +inline void mul_coefficients(uint16_t* poly, const uint16_t* factors) + { + for(size_t i = 0; i < PARAM_N; i++) + { + poly[i] = montgomery_reduce(poly[i] * factors[i]); + } + } + +/* GS_bo_to_no; omegas need to be in Montgomery domain */ +inline void ntt(uint16_t* a, const uint16_t* omega) + { + for(size_t i = 0; i < 10; i+=2) + { + // Even level + size_t distance = (1ULL << i); + for(size_t start = 0; start < distance; start++) + { + size_t jTwiddle = 0; + for(size_t j = start; j < PARAM_N-1; j += 2*distance) + { + uint16_t W = omega[jTwiddle++]; + uint16_t temp = a[j]; + a[j] = (temp + a[j + distance]); // Omit reduction (be lazy) + a[j + distance] = montgomery_reduce((W * (static_cast(temp) + 3*PARAM_Q - a[j + distance]))); + } + } + + // Odd level + distance <<= 1; + for(size_t start = 0; start < distance; start++) + { + size_t jTwiddle = 0; + for(size_t j = start; j < PARAM_N-1; j += 2*distance) + { + uint16_t W = omega[jTwiddle++]; + uint16_t temp = a[j]; + a[j] = barrett_reduce((temp + a[j + distance])); + a[j + distance] = montgomery_reduce((W * (static_cast(temp) + 3*PARAM_Q - a[j + distance]))); + } + } + } + } + +inline void poly_frombytes(poly* r, const uint8_t* a) + { + for(size_t i = 0; i < PARAM_N/4; i++) + { + r->coeffs[4*i+0] = a[7*i+0] | ((static_cast(a[7*i+1]) & 0x3f) << 8); + r->coeffs[4*i+1] = (a[7*i+1] >> 6) | (static_cast(a[7*i+2]) << 2) | (static_cast + (a[7*i+3] & 0x0f) << 10); + r->coeffs[4*i+2] = (a[7*i+3] >> 4) | (static_cast(a[7*i+4]) << 4) | (static_cast + (a[7*i+5] & 0x03) << 12); + r->coeffs[4*i+3] = (a[7*i+5] >> 2) | (static_cast(a[7*i+6]) << 6); + } + } + +inline void poly_tobytes(uint8_t* r, const poly* p) + { + for(size_t i = 0; i < PARAM_N/4; i++) + { + uint16_t t0 = barrett_reduce(p->coeffs[4*i+0]); //Make sure that coefficients have only 14 bits + uint16_t t1 = barrett_reduce(p->coeffs[4*i+1]); + uint16_t t2 = barrett_reduce(p->coeffs[4*i+2]); + uint16_t t3 = barrett_reduce(p->coeffs[4*i+3]); + + uint16_t m; + int16_t c; + + m = t0 - PARAM_Q; + c = m; + c >>= 15; + t0 = m ^ ((t0^m)&c); // >= 15; + t1 = m ^ ((t1^m)&c); // >= 15; + t2 = m ^ ((t2^m)&c); // >= 15; + t3 = m ^ ((t3^m)&c); // ((t0 >> 8) | (t1 << 6)); + r[7*i+2] = static_cast((t1 >> 2)); + r[7*i+3] = static_cast((t1 >> 10) | (t2 << 4)); + r[7*i+4] = static_cast((t2 >> 4)); + r[7*i+5] = static_cast((t2 >> 12) | (t3 << 2)); + r[7*i+6] = static_cast((t3 >> 6)); + } + } + +inline void poly_getnoise(Botan::RandomNumberGenerator& rng, poly* r) + { + uint8_t buf[4*PARAM_N]; + + rng.randomize(buf, 4*PARAM_N); + + for(size_t i = 0; i < PARAM_N; i++) + { + const uint32_t t = load_le(buf, i); + uint32_t d = 0; + for(size_t j = 0; j < 8; j++) + { + d += (t >> j) & 0x01010101; + } + const uint32_t a = ((d >> 8) & 0xff) + (d & 0xff); + const uint32_t b = (d >> 24) + ((d >> 16) & 0xff); + r->coeffs[i] = static_cast(a + PARAM_Q - b); + } + } + +inline void poly_pointwise(poly* r, const poly* a, const poly* b) + { + for(size_t i = 0; i < PARAM_N; i++) + { + const uint16_t t = montgomery_reduce(3186*b->coeffs[i]); /* t is now in Montgomery domain */ + r->coeffs[i] = montgomery_reduce(a->coeffs[i] * t); /* r->coeffs[i] is back in normal domain */ + } + } + +inline void poly_add(poly* r, const poly* a, const poly* b) + { + for(size_t i = 0; i < PARAM_N; i++) + { + r->coeffs[i] = barrett_reduce(a->coeffs[i] + b->coeffs[i]); + } + } + +inline void poly_ntt(poly* r) + { + static const uint16_t omegas_montgomery[PARAM_N/2] = + { + 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775, 2344, + 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, + 7822, 7540, 6752, 5456, 4449, 3789, 12142, 11973, 382, 3988, 468, 6843, 5339, + 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879, 11889, 1728, + 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, + 3199, 9987, 605, 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, + 4080, 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681, 3477, 1105, 142, 241, + 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968, 12097, 7591, + 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, 12138, + 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874, 677, 3336, 6234, 2766, 1323, + 9115, 12237, 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, + 4774, 5429, 11871, 3772, 453, 5908, 2882, 1805, 2051, 1954, 11713, 3963, + 2447, 6142, 8174, 3030, 1843, 2361, 12071, 2908, 3529, 3434, 3202, 7796, + 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, + 5942, 10706, 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, + 9634, 6554, 10596, 9280, 11566, 174, 2948, 2503, 6507, 10723, 11606, 2459, + 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065, 835, 3570, + 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, + 1112, 3728, 4049, 11130, 5990, 1404, 325, 948, 11143, 6190, 295, 11637, 5766, + 8212, 8273, 2919, 8527, 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105, 7991, + 3329, 9597, 12121, 5106, 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, + 3091, 1000, 7969, 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, 1062, + 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088, + 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, + 7143, 11567, 10984, 4134, 5736, 4978, 10938, 5777, 8961, 4591, 5728, 6461, + 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283, 10092, 5067, 12171, + 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, + 4452, 10908, 2525, 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, + 1022, 11950, 9821, 11745, 5791, 5092, 2089, 9005, 2881, 3289, 2013, 9048, + 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, + 9558, 8830, 3637, 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, + 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952, + 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, + 1002, 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045, 2481, 5012, 7428, 354, + 6591, 9377, 11847, 2401, 1067, 7188, 11516, 390, 8511, 8456, 7270, 545, 8585, + 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, + 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, + 11869, 6730, 10745, 10111, 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, + 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777, 4654, 10863, + 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, + 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, + 4414, 9442, 7917, 2174 + }; + + static const uint16_t psis_bitrev_montgomery[PARAM_N] = + { + 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041, 8775, 2344, + 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118, 2683, 1190, 4789, + 7822, 7540, 6752, 5456, 4449, 3789, 12142, 11973, 382, 3988, 468, 6843, 5339, + 6196, 3710, 11316, 1254, 5435, 10930, 3998, 10256, 10367, 3879, 11889, 1728, + 6137, 4948, 5862, 6136, 3643, 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, + 3199, 9987, 605, 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, + 4080, 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681, 3477, 1105, 142, 241, + 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968, 12097, 7591, + 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821, 11502, 8807, 12138, + 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874, 677, 3336, 6234, 2766, 1323, + 9115, 12237, 2031, 6956, 6413, 2281, 3969, 3991, 12133, 9522, 4737, 10996, + 4774, 5429, 11871, 3772, 453, 5908, 2882, 1805, 2051, 1954, 11713, 3963, + 2447, 6142, 8174, 3030, 1843, 2361, 12071, 2908, 3529, 3434, 3202, 7796, + 2057, 5369, 11939, 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, + 5942, 10706, 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, + 9634, 6554, 10596, 9280, 11566, 174, 2948, 2503, 6507, 10723, 11606, 2459, + 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065, 835, 3570, + 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922, 7967, 1958, 10211, + 1112, 3728, 4049, 11130, 5990, 1404, 325, 948, 11143, 6190, 295, 11637, 5766, + 8212, 8273, 2919, 8527, 6119, 6992, 8333, 1360, 2555, 6167, 1200, 7105, 7991, + 3329, 9597, 12121, 5106, 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, + 3091, 1000, 7969, 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, 1062, + 2294, 3553, 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088, + 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479, 1, 8246, + 7143, 11567, 10984, 4134, 5736, 4978, 10938, 5777, 8961, 4591, 5728, 6461, + 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744, 9283, 10092, 5067, 12171, + 2476, 3748, 11336, 6522, 827, 9452, 5374, 12159, 7935, 3296, 3949, 9893, + 4452, 10908, 2525, 3584, 8112, 8011, 10616, 4989, 6958, 11809, 9447, 12280, + 1022, 11950, 9821, 11745, 5791, 5092, 2089, 9005, 2881, 3289, 2013, 9048, + 729, 7901, 1260, 5755, 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, + 9558, 8830, 3637, 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, + 1207, 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952, + 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302, 6022, 7278, + 1002, 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045, 2481, 5012, 7428, 354, + 6591, 9377, 11847, 2401, 1067, 7188, 11516, 390, 8511, 8456, 7270, 545, 8585, + 9611, 12047, 1537, 4143, 4714, 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, + 9273, 12046, 11618, 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, + 11869, 6730, 10745, 10111, 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, + 2686, 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777, 4654, 10863, + 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852, 12286, + 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364, 3271, 4057, + 4414, 9442, 7917, 2174, 3947, 11951, 2455, 6599, 10545, 10975, 3654, 2894, + 7681, 7126, 7287, 12269, 4119, 3343, 2151, 1522, 7174, 7350, 11041, 2442, + 2148, 5959, 6492, 8330, 8945, 5598, 3624, 10397, 1325, 6565, 1945, 11260, + 10077, 2674, 3338, 3276, 11034, 506, 6505, 1392, 5478, 8778, 1178, 2776, + 3408, 10347, 11124, 2575, 9489, 12096, 6092, 10058, 4167, 6085, 923, 11251, + 11912, 4578, 10669, 11914, 425, 10453, 392, 10104, 8464, 4235, 8761, 7376, + 2291, 3375, 7954, 8896, 6617, 7790, 1737, 11667, 3982, 9342, 6680, 636, 6825, + 7383, 512, 4670, 2900, 12050, 7735, 994, 1687, 11883, 7021, 146, 10485, 1403, + 5189, 6094, 2483, 2054, 3042, 10945, 3981, 10821, 11826, 8882, 8151, 180, + 9600, 7684, 5219, 10880, 6780, 204, 11232, 2600, 7584, 3121, 3017, 11053, + 7814, 7043, 4251, 4739, 11063, 6771, 7073, 9261, 2360, 11925, 1928, 11825, + 8024, 3678, 3205, 3359, 11197, 5209, 8581, 3238, 8840, 1136, 9363, 1826, + 3171, 4489, 7885, 346, 2068, 1389, 8257, 3163, 4840, 6127, 8062, 8921, 612, + 4238, 10763, 8067, 125, 11749, 10125, 5416, 2110, 716, 9839, 10584, 11475, + 11873, 3448, 343, 1908, 4538, 10423, 7078, 4727, 1208, 11572, 3589, 2982, + 1373, 1721, 10753, 4103, 2429, 4209, 5412, 5993, 9011, 438, 3515, 7228, 1218, + 8347, 5232, 8682, 1327, 7508, 4924, 448, 1014, 10029, 12221, 4566, 5836, + 12229, 2717, 1535, 3200, 5588, 5845, 412, 5102, 7326, 3744, 3056, 2528, 7406, + 8314, 9202, 6454, 6613, 1417, 10032, 7784, 1518, 3765, 4176, 5063, 9828, + 2275, 6636, 4267, 6463, 2065, 7725, 3495, 8328, 8755, 8144, 10533, 5966, + 12077, 9175, 9520, 5596, 6302, 8400, 579, 6781, 11014, 5734, 11113, 11164, + 4860, 1131, 10844, 9068, 8016, 9694, 3837, 567, 9348, 7000, 6627, 7699, 5082, + 682, 11309, 5207, 4050, 7087, 844, 7434, 3769, 293, 9057, 6940, 9344, 10883, + 2633, 8190, 3944, 5530, 5604, 3480, 2171, 9282, 11024, 2213, 8136, 3805, 767, + 12239, 216, 11520, 6763, 10353, 7, 8566, 845, 7235, 3154, 4360, 3285, 10268, + 2832, 3572, 1282, 7559, 3229, 8360, 10583, 6105, 3120, 6643, 6203, 8536, + 8348, 6919, 3536, 9199, 10891, 11463, 5043, 1658, 5618, 8787, 5789, 4719, + 751, 11379, 6389, 10783, 3065, 7806, 6586, 2622, 5386, 510, 7628, 6921, 578, + 10345, 11839, 8929, 4684, 12226, 7154, 9916, 7302, 8481, 3670, 11066, 2334, + 1590, 7878, 10734, 1802, 1891, 5103, 6151, 8820, 3418, 7846, 9951, 4693, 417, + 9996, 9652, 4510, 2946, 5461, 365, 881, 1927, 1015, 11675, 11009, 1371, + 12265, 2485, 11385, 5039, 6742, 8449, 1842, 12217, 8176, 9577, 4834, 7937, + 9461, 2643, 11194, 3045, 6508, 4094, 3451, 7911, 11048, 5406, 4665, 3020, + 6616, 11345, 7519, 3669, 5287, 1790, 7014, 5410, 11038, 11249, 2035, 6125, + 10407, 4565, 7315, 5078, 10506, 2840, 2478, 9270, 4194, 9195, 4518, 7469, + 1160, 6878, 2730, 10421, 10036, 1734, 3815, 10939, 5832, 10595, 10759, 4423, + 8420, 9617, 7119, 11010, 11424, 9173, 189, 10080, 10526, 3466, 10588, 7592, + 3578, 11511, 7785, 9663, 530, 12150, 8957, 2532, 3317, 9349, 10243, 1481, + 9332, 3454, 3758, 7899, 4218, 2593, 11410, 2276, 982, 6513, 1849, 8494, 9021, + 4523, 7988, 8, 457, 648, 150, 8000, 2307, 2301, 874, 5650, 170, 9462, 2873, + 9855, 11498, 2535, 11169, 5808, 12268, 9687, 1901, 7171, 11787, 3846, 1573, + 6063, 3793, 466, 11259, 10608, 3821, 6320, 4649, 6263, 2929 + }; + + mul_coefficients(r->coeffs, psis_bitrev_montgomery); + ntt(r->coeffs, omegas_montgomery); + } + +inline void bitrev_vector(uint16_t* poly) + { + static const uint16_t bitrev_table[1024] = + { + 0, 512, 256, 768, 128, 640, 384, 896, 64, 576, 320, 832, 192, 704, 448, 960, 32, 544, 288, 800, 160, 672, 416, 928, 96, 608, 352, 864, 224, 736, 480, 992, + 16, 528, 272, 784, 144, 656, 400, 912, 80, 592, 336, 848, 208, 720, 464, 976, 48, 560, 304, 816, 176, 688, 432, 944, 112, 624, 368, 880, 240, 752, 496, 1008, + 8, 520, 264, 776, 136, 648, 392, 904, 72, 584, 328, 840, 200, 712, 456, 968, 40, 552, 296, 808, 168, 680, 424, 936, 104, 616, 360, 872, 232, 744, 488, 1000, + 24, 536, 280, 792, 152, 664, 408, 920, 88, 600, 344, 856, 216, 728, 472, 984, 56, 568, 312, 824, 184, 696, 440, 952, 120, 632, 376, 888, 248, 760, 504, 1016, + 4, 516, 260, 772, 132, 644, 388, 900, 68, 580, 324, 836, 196, 708, 452, 964, 36, 548, 292, 804, 164, 676, 420, 932, 100, 612, 356, 868, 228, 740, 484, 996, + 20, 532, 276, 788, 148, 660, 404, 916, 84, 596, 340, 852, 212, 724, 468, 980, 52, 564, 308, 820, 180, 692, 436, 948, 116, 628, 372, 884, 244, 756, 500, 1012, + 12, 524, 268, 780, 140, 652, 396, 908, 76, 588, 332, 844, 204, 716, 460, 972, 44, 556, 300, 812, 172, 684, 428, 940, 108, 620, 364, 876, 236, 748, 492, 1004, + 28, 540, 284, 796, 156, 668, 412, 924, 92, 604, 348, 860, 220, 732, 476, 988, 60, 572, 316, 828, 188, 700, 444, 956, 124, 636, 380, 892, 252, 764, 508, 1020, + 2, 514, 258, 770, 130, 642, 386, 898, 66, 578, 322, 834, 194, 706, 450, 962, 34, 546, 290, 802, 162, 674, 418, 930, 98, 610, 354, 866, 226, 738, 482, 994, + 18, 530, 274, 786, 146, 658, 402, 914, 82, 594, 338, 850, 210, 722, 466, 978, 50, 562, 306, 818, 178, 690, 434, 946, 114, 626, 370, 882, 242, 754, 498, 1010, + 10, 522, 266, 778, 138, 650, 394, 906, 74, 586, 330, 842, 202, 714, 458, 970, 42, 554, 298, 810, 170, 682, 426, 938, 106, 618, 362, 874, 234, 746, 490, 1002, + 26, 538, 282, 794, 154, 666, 410, 922, 90, 602, 346, 858, 218, 730, 474, 986, 58, 570, 314, 826, 186, 698, 442, 954, 122, 634, 378, 890, 250, 762, 506, 1018, + 6, 518, 262, 774, 134, 646, 390, 902, 70, 582, 326, 838, 198, 710, 454, 966, 38, 550, 294, 806, 166, 678, 422, 934, 102, 614, 358, 870, 230, 742, 486, 998, + 22, 534, 278, 790, 150, 662, 406, 918, 86, 598, 342, 854, 214, 726, 470, 982, 54, 566, 310, 822, 182, 694, 438, 950, 118, 630, 374, 886, 246, 758, 502, 1014, + 14, 526, 270, 782, 142, 654, 398, 910, 78, 590, 334, 846, 206, 718, 462, 974, 46, 558, 302, 814, 174, 686, 430, 942, 110, 622, 366, 878, 238, 750, 494, 1006, + 30, 542, 286, 798, 158, 670, 414, 926, 94, 606, 350, 862, 222, 734, 478, 990, 62, 574, 318, 830, 190, 702, 446, 958, 126, 638, 382, 894, 254, 766, 510, 1022, + 1, 513, 257, 769, 129, 641, 385, 897, 65, 577, 321, 833, 193, 705, 449, 961, 33, 545, 289, 801, 161, 673, 417, 929, 97, 609, 353, 865, 225, 737, 481, 993, + 17, 529, 273, 785, 145, 657, 401, 913, 81, 593, 337, 849, 209, 721, 465, 977, 49, 561, 305, 817, 177, 689, 433, 945, 113, 625, 369, 881, 241, 753, 497, 1009, + 9, 521, 265, 777, 137, 649, 393, 905, 73, 585, 329, 841, 201, 713, 457, 969, 41, 553, 297, 809, 169, 681, 425, 937, 105, 617, 361, 873, 233, 745, 489, 1001, + 25, 537, 281, 793, 153, 665, 409, 921, 89, 601, 345, 857, 217, 729, 473, 985, 57, 569, 313, 825, 185, 697, 441, 953, 121, 633, 377, 889, 249, 761, 505, 1017, + 5, 517, 261, 773, 133, 645, 389, 901, 69, 581, 325, 837, 197, 709, 453, 965, 37, 549, 293, 805, 165, 677, 421, 933, 101, 613, 357, 869, 229, 741, 485, 997, + 21, 533, 277, 789, 149, 661, 405, 917, 85, 597, 341, 853, 213, 725, 469, 981, 53, 565, 309, 821, 181, 693, 437, 949, 117, 629, 373, 885, 245, 757, 501, 1013, + 13, 525, 269, 781, 141, 653, 397, 909, 77, 589, 333, 845, 205, 717, 461, 973, 45, 557, 301, 813, 173, 685, 429, 941, 109, 621, 365, 877, 237, 749, 493, 1005, + 29, 541, 285, 797, 157, 669, 413, 925, 93, 605, 349, 861, 221, 733, 477, 989, 61, 573, 317, 829, 189, 701, 445, 957, 125, 637, 381, 893, 253, 765, 509, 1021, + 3, 515, 259, 771, 131, 643, 387, 899, 67, 579, 323, 835, 195, 707, 451, 963, 35, 547, 291, 803, 163, 675, 419, 931, 99, 611, 355, 867, 227, 739, 483, 995, + 19, 531, 275, 787, 147, 659, 403, 915, 83, 595, 339, 851, 211, 723, 467, 979, 51, 563, 307, 819, 179, 691, 435, 947, 115, 627, 371, 883, 243, 755, 499, 1011, + 11, 523, 267, 779, 139, 651, 395, 907, 75, 587, 331, 843, 203, 715, 459, 971, 43, 555, 299, 811, 171, 683, 427, 939, 107, 619, 363, 875, 235, 747, 491, 1003, + 27, 539, 283, 795, 155, 667, 411, 923, 91, 603, 347, 859, 219, 731, 475, 987, 59, 571, 315, 827, 187, 699, 443, 955, 123, 635, 379, 891, 251, 763, 507, 1019, + 7, 519, 263, 775, 135, 647, 391, 903, 71, 583, 327, 839, 199, 711, 455, 967, 39, 551, 295, 807, 167, 679, 423, 935, 103, 615, 359, 871, 231, 743, 487, 999, + 23, 535, 279, 791, 151, 663, 407, 919, 87, 599, 343, 855, 215, 727, 471, 983, 55, 567, 311, 823, 183, 695, 439, 951, 119, 631, 375, 887, 247, 759, 503, 1015, + 15, 527, 271, 783, 143, 655, 399, 911, 79, 591, 335, 847, 207, 719, 463, 975, 47, 559, 303, 815, 175, 687, 431, 943, 111, 623, 367, 879, 239, 751, 495, 1007, + 31, 543, 287, 799, 159, 671, 415, 927, 95, 607, 351, 863, 223, 735, 479, 991, 63, 575, 319, 831, 191, 703, 447, 959, 127, 639, 383, 895, 255, 767, 511, 1023 + }; + + for(size_t i = 0; i < PARAM_N; i++) + { + const uint16_t r = bitrev_table[i]; + if(i < r) + { + const uint16_t tmp = poly[i]; + poly[i] = poly[r]; + poly[r] = tmp; + } + } + } + +inline void poly_invntt(poly* r) + { + static const uint16_t omegas_inv_montgomery[PARAM_N/2] = + { + 4075, 5315, 4324, 4916, 10120, 11767, 7210, 9027, 10316, 6715, 1278, 9945, + 3514, 11248, 11271, 5925, 147, 8500, 7840, 6833, 5537, 4749, 4467, 7500, + 11099, 9606, 6171, 8471, 8429, 5445, 11239, 7753, 9090, 12233, 5529, 5206, + 10587, 1987, 11635, 3565, 5415, 8646, 6153, 6427, 7341, 6152, 10561, 400, + 8410, 1922, 2033, 8291, 1359, 6854, 11035, 973, 8579, 6093, 6950, 5446, + 11821, 8301, 11907, 316, 52, 3174, 10966, 9523, 6055, 8953, 11612, 6415, + 2505, 5906, 10710, 11858, 8332, 9450, 10162, 151, 3482, 787, 5468, 1010, + 4169, 9162, 5241, 9369, 7509, 8844, 7232, 4698, 192, 1321, 10240, 4912, 885, + 6281, 10333, 7280, 8757, 11286, 58, 12048, 12147, 11184, 8812, 6608, 2844, + 3438, 4212, 11314, 8687, 6068, 421, 8209, 3600, 3263, 7665, 6077, 7507, 5886, + 3029, 6695, 4213, 504, 11684, 2302, 1962, 1594, 6328, 7183, 168, 2692, 8960, + 4298, 5184, 11089, 6122, 9734, 10929, 3956, 5297, 6170, 3762, 9370, 4016, + 4077, 6523, 652, 11994, 6099, 1146, 11341, 11964, 10885, 6299, 1159, 8240, + 8561, 11177, 2078, 10331, 4322, 11367, 441, 4079, 11231, 3150, 1319, 8243, + 709, 8049, 8719, 11454, 6224, 3054, 6803, 3123, 10542, 4433, 6370, 7032, + 3834, 8633, 12225, 9830, 683, 1566, 5782, 9786, 9341, 12115, 723, 3009, 1693, + 5735, 2655, 2738, 6421, 11942, 2925, 1975, 8532, 3315, 11863, 4754, 1858, + 1583, 6347, 2500, 10800, 6374, 1483, 12240, 1263, 1815, 5383, 10777, 350, + 6920, 10232, 4493, 9087, 8855, 8760, 9381, 218, 9928, 10446, 9259, 4115, + 6147, 9842, 8326, 576, 10335, 10238, 10484, 9407, 6381, 11836, 8517, 418, + 6860, 7515, 1293, 7552, 2767, 156, 8298, 8320, 10008, 5876, 5333, 10258, + 10115, 4372, 2847, 7875, 8232, 9018, 8925, 1689, 8236, 2645, 5042, 9984, + 7094, 9509, 1484, 7394, 3, 4437, 160, 3149, 113, 7370, 10123, 3915, 6998, + 2704, 8653, 4938, 1426, 7635, 10512, 1663, 6957, 3510, 2370, 2865, 3978, + 9320, 3247, 9603, 6882, 3186, 10659, 10163, 1153, 9405, 8241, 10040, 2178, + 1544, 5559, 420, 8304, 4905, 476, 3531, 5191, 9153, 2399, 8889, 3000, 671, + 243, 3016, 3763, 10849, 12262, 9223, 10657, 7205, 11272, 7404, 7575, 8146, + 10752, 242, 2678, 3704, 11744, 5019, 3833, 3778, 11899, 773, 5101, 11222, + 9888, 442, 2912, 5698, 11935, 4861, 7277, 9808, 11244, 2859, 3780, 11414, + 4976, 10682, 7201, 8005, 11287, 5011, 6267, 2987, 2437, 3646, 2566, 10102, + 9867, 6250, 5444, 2381, 11796, 8193, 4337, 11854, 1912, 1378, 404, 7644, + 1065, 2143, 11121, 5277, 3248, 11082, 2548, 8058, 8907, 11934, 1759, 8582, + 3694, 7110, 12144, 6747, 8652, 3459, 2731, 8357, 6378, 7399, 10861, 1696, + 9863, 334, 7657, 6534, 11029, 4388, 11560, 3241, 10276, 9000, 9408, 3284, + 10200, 7197, 6498, 544, 2468, 339, 11267, 9, 2842, 480, 5331, 7300, 1673, + 4278, 4177, 8705, 9764, 1381, 7837, 2396, 8340, 8993, 4354, 130, 6915, 2837, + 11462, 5767, 953, 8541, 9813, 118, 7222, 2197, 3006, 9545, 563, 9314, 2625, + 11340, 4821, 2639, 7266, 5828, 6561, 7698, 3328, 6512, 1351, 7311, 6553, + 8155, 1305, 722, 5146, 4043, 12288, 10810, 2545, 3621, 8747, 8785, 1646, + 1212, 5860, 3195, 7203, 10963, 3201, 3014, 955, 11499, 9970, 11119, 3135, + 3712, 7443, 9542, 7484, 8736, 9995, 11227, 1635, 9521, 1177, 8034, 140, + 10436, 11563, 7678, 4320, 11289, 9198, 12208, 2963, 7393, 2366, 9238 + }; + + static const uint16_t psis_inv_montgomery[PARAM_N] = + { + 256, 10570, 1510, 7238, 1034, 7170, 6291, 7921, 11665, 3422, 4000, 2327, + 2088, 5565, 795, 10647, 1521, 5484, 2539, 7385, 1055, 7173, 8047, 11683, + 1669, 1994, 3796, 5809, 4341, 9398, 11876, 12230, 10525, 12037, 12253, 3506, + 4012, 9351, 4847, 2448, 7372, 9831, 3160, 2207, 5582, 2553, 7387, 6322, 9681, + 1383, 10731, 1533, 219, 5298, 4268, 7632, 6357, 9686, 8406, 4712, 9451, + 10128, 4958, 5975, 11387, 8649, 11769, 6948, 11526, 12180, 1740, 10782, 6807, + 2728, 7412, 4570, 4164, 4106, 11120, 12122, 8754, 11784, 3439, 5758, 11356, + 6889, 9762, 11928, 1704, 1999, 10819, 12079, 12259, 7018, 11536, 1648, 1991, + 2040, 2047, 2048, 10826, 12080, 8748, 8272, 8204, 1172, 1923, 7297, 2798, + 7422, 6327, 4415, 7653, 6360, 11442, 12168, 7005, 8023, 9924, 8440, 8228, + 2931, 7441, 1063, 3663, 5790, 9605, 10150, 1450, 8985, 11817, 10466, 10273, + 12001, 3470, 7518, 1074, 1909, 7295, 9820, 4914, 702, 5367, 7789, 8135, 9940, + 1420, 3714, 11064, 12114, 12264, 1752, 5517, 9566, 11900, 1700, 3754, 5803, + 829, 1874, 7290, 2797, 10933, 5073, 7747, 8129, 6428, 6185, 11417, 1631, 233, + 5300, 9535, 10140, 11982, 8734, 8270, 2937, 10953, 8587, 8249, 2934, 9197, + 4825, 5956, 4362, 9401, 1343, 3703, 529, 10609, 12049, 6988, 6265, 895, 3639, + 4031, 4087, 4095, 585, 10617, 8539, 4731, 4187, 9376, 3095, 9220, 10095, + 10220, 1460, 10742, 12068, 1724, 5513, 11321, 6884, 2739, 5658, 6075, 4379, + 11159, 10372, 8504, 4726, 9453, 3106, 7466, 11600, 10435, 8513, 9994, 8450, + 9985, 3182, 10988, 8592, 2983, 9204, 4826, 2445, 5616, 6069, 867, 3635, 5786, + 11360, 5134, 2489, 10889, 12089, 1727, 7269, 2794, 9177, 1311, 5454, 9557, + 6632, 2703, 9164, 10087, 1441, 3717, 531, 3587, 2268, 324, 5313, 759, 1864, + 5533, 2546, 7386, 9833, 8427, 4715, 11207, 1601, 7251, 4547, 11183, 12131, + 1733, 10781, 10318, 1474, 10744, 5046, 4232, 11138, 10369, 6748, 964, 7160, + 4534, 7670, 8118, 8182, 4680, 11202, 6867, 981, 8918, 1274, 182, 26, 7026, + 8026, 11680, 12202, 10521, 1503, 7237, 4545, 5916, 9623, 8397, 11733, 10454, + 3249, 9242, 6587, 941, 1890, 270, 10572, 6777, 9746, 6659, 6218, 6155, 6146, + 878, 1881, 7291, 11575, 12187, 1741, 7271, 8061, 11685, 6936, 4502, 9421, + 4857, 4205, 7623, 1089, 10689, 1527, 8996, 10063, 11971, 10488, 6765, 2722, + 3900, 9335, 11867, 6962, 11528, 5158, 4248, 4118, 5855, 2592, 5637, 6072, + 2623, 7397, 8079, 9932, 4930, 5971, 853, 3633, 519, 8852, 11798, 3441, 11025, + 1575, 225, 8810, 11792, 12218, 3501, 9278, 3081, 9218, 4828, 7712, 8124, + 11694, 12204, 3499, 4011, 573, 3593, 5780, 7848, 9899, 10192, 1456, 208, + 7052, 2763, 7417, 11593, 10434, 12024, 8740, 11782, 10461, 3250, 5731, 7841, + 9898, 1414, 202, 3540, 7528, 2831, 2160, 10842, 5060, 4234, 4116, 588, 84, + 12, 7024, 2759, 9172, 6577, 11473, 1639, 9012, 3043, 7457, 6332, 11438, 1634, + 1989, 9062, 11828, 8712, 11778, 12216, 10523, 6770, 9745, 10170, 4964, 9487, + 6622, 946, 8913, 6540, 6201, 4397, 9406, 8366, 9973, 8447, 8229, 11709, 8695, + 10020, 3187, 5722, 2573, 10901, 6824, 4486, 4152, 9371, 8361, 2950, 2177, + 311, 1800, 9035, 8313, 11721, 3430, 490, 70, 10, 1757, 251, 3547, 7529, + 11609, 3414, 7510, 4584, 4166, 9373, 1339, 5458, 7802, 11648, 1664, 7260, + 9815, 10180, 6721, 9738, 10169, 8475, 8233, 9954, 1422, 8981, 1283, 5450, + 11312, 1616, 3742, 11068, 10359, 4991, 713, 3613, 9294, 8350, 4704, 672, 96, + 7036, 9783, 11931, 3460, 5761, 823, 10651, 12055, 10500, 1500, 5481, 783, + 3623, 11051, 8601, 8251, 8201, 11705, 10450, 5004, 4226, 7626, 2845, 2162, + 3820, 7568, 9859, 3164, 452, 10598, 1514, 5483, 6050, 6131, 4387, 7649, 8115, + 6426, 918, 8909, 8295, 1185, 5436, 11310, 8638, 1234, 5443, 11311, 5127, + 2488, 2111, 10835, 5059, 7745, 2862, 3920, 560, 80, 1767, 2008, 3798, 11076, + 6849, 2734, 10924, 12094, 8750, 1250, 10712, 6797, 971, 7161, 1023, 8924, + 4786, 7706, 4612, 4170, 7618, 6355, 4419, 5898, 11376, 10403, 10264, 6733, + 4473, 639, 5358, 2521, 9138, 3061, 5704, 4326, 618, 5355, 765, 5376, 768, + 7132, 4530, 9425, 3102, 9221, 6584, 11474, 10417, 10266, 12000, 6981, 6264, + 4406, 2385, 7363, 4563, 4163, 7617, 9866, 3165, 9230, 11852, 10471, 5007, + 5982, 11388, 5138, 734, 3616, 11050, 12112, 6997, 11533, 12181, 10518, 12036, + 3475, 2252, 7344, 9827, 4915, 9480, 6621, 4457, 7659, 9872, 6677, 4465, 4149, + 7615, 4599, 657, 3605, 515, 10607, 6782, 4480, 640, 1847, 3775, 5806, 2585, + 5636, 9583, 1369, 10729, 8555, 10000, 11962, 5220, 7768, 8132, 8184, 9947, + 1421, 203, 29, 8782, 11788, 1684, 10774, 10317, 4985, 9490, 8378, 4708, + 11206, 5112, 5997, 7879, 11659, 12199, 8765, 10030, 4944, 5973, 6120, 6141, + 6144, 7900, 11662, 1666, 238, 34, 3516, 5769, 9602, 8394, 9977, 6692, 956, + 10670, 6791, 9748, 11926, 8726, 11780, 5194, 742, 106, 8793, 10034, 3189, + 10989, 5081, 4237, 5872, 4350, 2377, 10873, 6820, 6241, 11425, 10410, 10265, + 3222, 5727, 9596, 4882, 2453, 2106, 3812, 11078, 12116, 5242, 4260, 11142, + 8614, 11764, 12214, 5256, 4262, 4120, 11122, 5100, 11262, 5120, 2487, 5622, + 9581, 8391, 8221, 2930, 10952, 12098, 6995, 6266, 9673, 4893, 699, 3611, + 4027, 5842, 11368, 1624, 232, 8811, 8281, 1183, 169, 8802, 3013, 2186, 5579, + 797, 3625, 4029, 11109, 1587, 7249, 11569, 8675, 6506, 2685, 10917, 12093, + 12261, 12285, 1755, 7273, 1039, 1904, 272, 3550, 9285, 3082, 5707, 6082, + 4380, 7648, 11626, 5172, 4250, 9385, 8363, 8217, 4685, 5936, 848, 8899, 6538, + 934, 1889, 3781, 9318, 10109, 10222, 6727, 961, 5404, 772, 5377, 9546, 8386, + 1198, 8949, 3034, 2189, 7335, 4559, 5918, 2601, 10905, 5069, 9502, 3113, + 7467, 8089, 11689, 5181, 9518, 8382, 2953, 3933, 4073, 4093, 7607, 8109, + 2914, 5683, 4323, 11151, 1593, 10761, 6804, 972, 3650, 2277, 5592, 4310, + 7638, 9869, 4921, 703, 1856, 9043, 4803, 9464, 1352, 8971, 11815, 5199, 7765, + 6376, 4422, 7654, 2849, 407, 8836, 6529, 7955, 2892, 9191, 1313, 10721, + 12065, 12257, 1751, 9028, 8312, 2943, 2176, 3822, 546, 78, 8789, 11789, + 10462, 12028, 6985, 4509, 9422, 1346, 5459, 4291, 613, 10621, 6784, 9747, + 3148, 7472, 2823, 5670, 810, 7138, 8042, 4660, 7688, 6365, 6176, 6149, 2634, + 5643, 9584, 10147, 11983, 5223, 9524, 11894, 10477, 8519, 1217, 3685, 2282, + 326, 10580, 3267, 7489, 4581, 2410, 5611, 11335, 6886, 8006, 8166, 11700, + 3427, 11023, 8597, 10006, 3185, 455, 65, 5276, 7776, 4622, 5927, 7869, 9902, + 11948, 5218, 2501, 5624, 2559, 10899, 1557, 1978, 10816, 10323, 8497, 4725, + 675, 1852, 10798, 12076, 10503, 3256, 9243, 3076, 2195, 10847, 12083, 10504, + 12034, 10497 + }; + + bitrev_vector(r->coeffs); + ntt(r->coeffs, omegas_inv_montgomery); + mul_coefficients(r->coeffs, psis_inv_montgomery); + } + +inline void encode_a(uint8_t* r, const poly* pk, const uint8_t* seed) + { + poly_tobytes(r, pk); + for(size_t i = 0; i < NEWHOPE_SEED_BYTES; i++) + { + r[NEWHOPE_POLY_BYTES+i] = seed[i]; + } + } + +inline void decode_a(poly* pk, uint8_t* seed, const uint8_t* r) + { + poly_frombytes(pk, r); + for(size_t i = 0; i < NEWHOPE_SEED_BYTES; i++) + { + seed[i] = r[NEWHOPE_POLY_BYTES+i]; + } + } + +inline void encode_b(uint8_t* r, const poly* b, const poly* c) + { + poly_tobytes(r, b); + for(size_t i = 0; i < PARAM_N/4; i++) + { + r[NEWHOPE_POLY_BYTES+i] = static_cast(c->coeffs[4*i] | + (c->coeffs[4*i+1] << 2) | + (c->coeffs[4*i+2] << 4) | + (c->coeffs[4*i+3] << 6)); + } + } + +inline void decode_b(poly* b, poly* c, const uint8_t* r) + { + poly_frombytes(b, r); + for(size_t i = 0; i < PARAM_N/4; i++) + { + c->coeffs[4*i+0] = r[NEWHOPE_POLY_BYTES+i] & 0x03; + c->coeffs[4*i+1] = (r[NEWHOPE_POLY_BYTES+i] >> 2) & 0x03; + c->coeffs[4*i+2] = (r[NEWHOPE_POLY_BYTES+i] >> 4) & 0x03; + c->coeffs[4*i+3] = (r[NEWHOPE_POLY_BYTES+i] >> 6); + } + } + +inline int32_t ct_abs(int32_t v) + { + int32_t mask = v >> 31; + return (v ^ mask) - mask; + } + +inline int32_t f(int32_t* v0, int32_t* v1, int32_t x) + { + int32_t xit, t, r, b; + + // Next 6 lines compute t = x/PARAM_Q; + b = x*2730; + t = b >> 25; + b = x - t*12289; + b = 12288 - b; + b >>= 31; + t -= b; + + r = t & 1; + xit = (t>>1); + *v0 = xit+r; // v0 = round(x/(2*PARAM_Q)) + + t -= 1; + r = t & 1; + *v1 = (t>>1)+r; + + return ct_abs(x-((*v0)*2*PARAM_Q)); + } + +inline void helprec(poly* c, const poly* v, RandomNumberGenerator& rng) + { + uint8_t rand[32]; + + rng.randomize(rand, 32); + + for(size_t i = 0; i < 256; i++) + { + int32_t v0[4], v1[4]; + uint8_t rbit = (rand[i>>3] >> (i&7)) & 1; + int32_t k; + + k = f(v0+0, v1+0, 8*v->coeffs[ 0+i] + 4*rbit); + k += f(v0+1, v1+1, 8*v->coeffs[256+i] + 4*rbit); + k += f(v0+2, v1+2, 8*v->coeffs[512+i] + 4*rbit); + k += f(v0+3, v1+3, 8*v->coeffs[768+i] + 4*rbit); + + k = (2*PARAM_Q-1-k) >> 31; + + int32_t v_tmp[4]; + v_tmp[0] = ((~k) & v0[0]) ^ (k & v1[0]); + v_tmp[1] = ((~k) & v0[1]) ^ (k & v1[1]); + v_tmp[2] = ((~k) & v0[2]) ^ (k & v1[2]); + v_tmp[3] = ((~k) & v0[3]) ^ (k & v1[3]); + + c->coeffs[ 0+i] = (v_tmp[0] - v_tmp[3]) & 3; + c->coeffs[256+i] = (v_tmp[1] - v_tmp[3]) & 3; + c->coeffs[512+i] = (v_tmp[2] - v_tmp[3]) & 3; + c->coeffs[768+i] = (- k + 2*v_tmp[3]) & 3; + } + } + +inline int32_t g(int32_t x) + { + int32_t t, c, b; + + // Next 6 lines compute t = x/(4*PARAM_Q); + b = x*2730; + t = b >> 27; + b = x - t*49156; + b = 49155 - b; + b >>= 31; + t -= b; + + c = t & 1; + t = (t >> 1) + c; // t = round(x/(8*PARAM_Q)) + + t *= 8*PARAM_Q; + + return ct_abs(t - x); + } + +inline int16_t LDDecode(int32_t xi0, int32_t xi1, int32_t xi2, int32_t xi3) + { + int32_t t; + + t = g(xi0); + t += g(xi1); + t += g(xi2); + t += g(xi3); + + t -= 8*PARAM_Q; + t >>= 31; + return t&1; + } + +inline void rec(uint8_t* key, const poly* v, const poly* c) + { + clear_mem(key, 32); + + for(size_t i = 0; i < 256; i++) + { + const int32_t tmp0 = 16*PARAM_Q + 8*static_cast(v->coeffs[ 0+i]) - PARAM_Q * (2*c->coeffs[ 0+i]+c->coeffs[768+i]); + const int32_t tmp1 = 16*PARAM_Q + 8*static_cast(v->coeffs[256+i]) - PARAM_Q * (2*c->coeffs[256+i]+c->coeffs[768+i]); + const int32_t tmp2 = 16*PARAM_Q + 8*static_cast(v->coeffs[512+i]) - PARAM_Q * (2*c->coeffs[512+i]+c->coeffs[768+i]); + const int32_t tmp3 = 16*PARAM_Q + 8*static_cast(v->coeffs[768+i]) - PARAM_Q * (c->coeffs[768+i]); + + key[i>>3] |= LDDecode(tmp0, tmp1, tmp2, tmp3) << (i & 7); + } + } + +void gen_a(poly* a, const uint8_t* seed, Newhope_Mode mode) + { + std::vector buf(168*16); + + std::unique_ptr xof; + + if(mode == Newhope_Mode::BoringSSL) + { + xof = StreamCipher::create_or_throw("CTR-BE(AES-128)"); + xof->set_key(seed, 16); + xof->set_iv(seed + 16, 16); + } + else + { + xof = StreamCipher::create_or_throw("SHAKE-128"); + xof->set_key(seed, NEWHOPE_SEED_BYTES); + } + + zeroise(buf); + xof->encrypt(buf); + + size_t pos = 0, ctr = 0; + + while(ctr < PARAM_N) + { + // Specialized for q = 12889 + const uint16_t val = (buf[pos] | (static_cast(buf[pos+1]) << 8)) & 0x3fff; + + if(val < PARAM_Q) + { + a->coeffs[ctr++] = val; + } + pos += 2; + if(pos >= buf.size()) + { + zeroise(buf); + xof->encrypt(buf); + pos = 0; + } + } + } + +} + +// API FUNCTIONS + +void newhope_keygen(uint8_t* send, poly* sk, RandomNumberGenerator& rng, + Newhope_Mode mode) + { + poly a, e, r, pk; + uint8_t seed[NEWHOPE_SEED_BYTES]; + + rng.randomize(seed, NEWHOPE_SEED_BYTES); + + gen_a(&a, seed, mode); + + poly_getnoise(rng, sk); + poly_ntt(sk); + + poly_getnoise(rng, &e); + poly_ntt(&e); + + poly_pointwise(&r, sk, &a); + poly_add(&pk, &e, &r); + + encode_a(send, &pk, seed); + } + +void newhope_sharedb(uint8_t* sharedkey, uint8_t* send, const uint8_t* received, + RandomNumberGenerator& rng, + Newhope_Mode mode) + { + poly sp, ep, v, a, pka, c, epp, bp; + uint8_t seed[NEWHOPE_SEED_BYTES]; + + decode_a(&pka, seed, received); + gen_a(&a, seed, mode); + + poly_getnoise(rng, &sp); + poly_ntt(&sp); + poly_getnoise(rng, &ep); + poly_ntt(&ep); + + poly_pointwise(&bp, &a, &sp); + poly_add(&bp, &bp, &ep); + + poly_pointwise(&v, &pka, &sp); + poly_invntt(&v); + + poly_getnoise(rng, &epp); + poly_add(&v, &v, &epp); + + helprec(&c, &v, rng); + + encode_b(send, &bp, &c); + + rec(sharedkey, &v, &c); + + const std::string kdf_hash = (mode == Newhope_Mode::SHA3) ? "SHA-3(256)" : "SHA-256"; + std::unique_ptr hash = HashFunction::create_or_throw(kdf_hash); + + hash->update(sharedkey, 32); + hash->final(sharedkey); + } + +void newhope_shareda(uint8_t sharedkey[], + const poly* sk, + const uint8_t received[], + Newhope_Mode mode) + { + poly v, bp, c; + + decode_b(&bp, &c, received); + + poly_pointwise(&v, sk, &bp); + poly_invntt(&v); + + rec(sharedkey, &v, &c); + + const std::string kdf_hash = (mode == Newhope_Mode::SHA3) ? "SHA-3(256)" : "SHA-256"; + std::unique_ptr hash = HashFunction::create_or_throw(kdf_hash); + + hash->update(sharedkey, 32); + hash->final(sharedkey); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/newhope/newhope.h b/comm/third_party/botan/src/lib/pubkey/newhope/newhope.h new file mode 100644 index 0000000000..8840ef5603 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/newhope/newhope.h @@ -0,0 +1,85 @@ +/* +* NEWHOPE Ring-LWE scheme +* Based on the public domain reference implementation by the +* designers (https://github.com/tpoeppelmann/newhope) +* +* Further changes +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NEWHOPE_H_ +#define BOTAN_NEWHOPE_H_ + +#include + +namespace Botan { + +class RandomNumberGenerator; + +/* +* WARNING: This API is preliminary and will change +* Currently pubkey.h does not support a 2-phase KEM scheme of +* the sort NEWHOPE exports. +*/ + +// TODO: change to just a secure_vector +class BOTAN_UNSTABLE_API newhope_poly final + { + public: + uint16_t coeffs[1024]; + ~newhope_poly(); + }; + +enum Newhope_Params + { + NEWHOPE_SENDABYTES = 1824, + NEWHOPE_SENDBBYTES = 2048, + + NEWHOPE_OFFER_BYTES = 1824, + NEWHOPE_ACCEPT_BYTES = 2048, + NEWHOPE_SHARED_KEY_BYTES = 32, + + NEWHOPE_SEED_BYTES = 32, + NEWHOPE_POLY_BYTES = 1792, + + CECPQ1_OFFER_BYTES = NEWHOPE_OFFER_BYTES + 32, + CECPQ1_ACCEPT_BYTES = NEWHOPE_ACCEPT_BYTES + 32, + CECPQ1_SHARED_KEY_BYTES = NEWHOPE_SHARED_KEY_BYTES + 32 + }; + +/** +* This chooses the XOF + hash for NewHope +* The official NewHope specification and reference implementation use +* SHA-3 and SHAKE-128. BoringSSL instead uses SHA-256 and AES-128 in +* CTR mode. CECPQ1 (x25519+NewHope) always uses BoringSSL's mode +*/ +enum class Newhope_Mode + { + SHA3, + BoringSSL + }; + +// offer +void BOTAN_PUBLIC_API(2,0) newhope_keygen(uint8_t send[NEWHOPE_SENDABYTES], + newhope_poly* sk, + RandomNumberGenerator& rng, + Newhope_Mode = Newhope_Mode::SHA3); + +// accept +void BOTAN_PUBLIC_API(2,0) newhope_sharedb(uint8_t sharedkey[NEWHOPE_SHARED_KEY_BYTES], + uint8_t send[], + const uint8_t* received, + RandomNumberGenerator& rng, + Newhope_Mode mode = Newhope_Mode::SHA3); + +// finish +void BOTAN_PUBLIC_API(2,0) newhope_shareda(uint8_t sharedkey[NEWHOPE_SHARED_KEY_BYTES], + const newhope_poly* ska, + const uint8_t* received, + Newhope_Mode mode = Newhope_Mode::SHA3); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pbes2/info.txt b/comm/third_party/botan/src/lib/pubkey/pbes2/info.txt new file mode 100644 index 0000000000..f8c6d37196 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pbes2/info.txt @@ -0,0 +1,10 @@ + +PKCS5_PBES2 -> 20141119 + + + +asn1 +cbc +hmac +pbkdf2 + diff --git a/comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.cpp b/comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.cpp new file mode 100644 index 0000000000..1360de67c5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.cpp @@ -0,0 +1,339 @@ +/* +* PKCS #5 PBES2 +* (C) 1999-2008,2014 Jack Lloyd +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_SCRYPT) + #include +#endif + +namespace Botan { + +namespace { + +bool known_pbes_cipher_mode(const std::string& mode) + { + return (mode == "CBC" || mode == "GCM" || mode == "SIV"); + } + +SymmetricKey derive_key(const std::string& passphrase, + const AlgorithmIdentifier& kdf_algo, + size_t default_key_size) + { + if(kdf_algo.get_oid() == OID::from_string("PKCS5.PBKDF2")) + { + secure_vector salt; + size_t iterations = 0, key_length = 0; + + AlgorithmIdentifier prf_algo; + BER_Decoder(kdf_algo.get_parameters()) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(iterations) + .decode_optional(key_length, INTEGER, UNIVERSAL) + .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED, + AlgorithmIdentifier("HMAC(SHA-160)", + AlgorithmIdentifier::USE_NULL_PARAM)) + .end_cons(); + + if(salt.size() < 8) + throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); + + if(key_length == 0) + key_length = default_key_size; + + const std::string prf = OIDS::oid2str_or_throw(prf_algo.get_oid()); + std::unique_ptr pbkdf(get_pbkdf("PBKDF2(" + prf + ")")); + return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations); + } +#if defined(BOTAN_HAS_SCRYPT) + else if(kdf_algo.get_oid() == OID::from_string("Scrypt")) + { + secure_vector salt; + size_t N = 0, r = 0, p = 0; + size_t key_length = 0; + + AlgorithmIdentifier prf_algo; + BER_Decoder(kdf_algo.get_parameters()) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(N) + .decode(r) + .decode(p) + .decode_optional(key_length, INTEGER, UNIVERSAL) + .end_cons(); + + if(key_length == 0) + key_length = default_key_size; + + secure_vector output(key_length); + scrypt(output.data(), output.size(), passphrase, + salt.data(), salt.size(), N, r, p); + + return SymmetricKey(output); + } +#endif + else + throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + + kdf_algo.get_oid().to_string()); + } + +secure_vector derive_key(const std::string& passphrase, + const std::string& digest, + RandomNumberGenerator& rng, + size_t* msec_in_iterations_out, + size_t iterations_if_msec_null, + size_t key_length, + AlgorithmIdentifier& kdf_algo) + { + const secure_vector salt = rng.random_vec(12); + + if(digest == "Scrypt") + { +#if defined(BOTAN_HAS_SCRYPT) + + std::unique_ptr pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt"); + + std::unique_ptr pwhash; + + if(msec_in_iterations_out) + { + const std::chrono::milliseconds msec(*msec_in_iterations_out); + pwhash = pwhash_fam->tune(key_length, msec); + } + else + { + pwhash = pwhash_fam->from_iterations(iterations_if_msec_null); + } + + secure_vector key(key_length); + pwhash->derive_key(key.data(), key.size(), + passphrase.c_str(), passphrase.size(), + salt.data(), salt.size()); + + const size_t N = pwhash->memory_param(); + const size_t r = pwhash->iterations(); + const size_t p = pwhash->parallelism(); + + if(msec_in_iterations_out) + *msec_in_iterations_out = 0; + + std::vector scrypt_params; + DER_Encoder(scrypt_params) + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(N) + .encode(r) + .encode(p) + .encode(key_length) + .end_cons(); + + kdf_algo = AlgorithmIdentifier(OID::from_string("Scrypt"), scrypt_params); + return key; +#else + throw Not_Implemented("Scrypt is not available in this build"); +#endif + } + else + { + const std::string prf = "HMAC(" + digest + ")"; + const std::string pbkdf_name = "PBKDF2(" + prf + ")"; + + std::unique_ptr pwhash_fam = PasswordHashFamily::create(pbkdf_name); + if(!pwhash_fam) + throw Invalid_Argument("Unknown password hash digest " + digest); + + std::unique_ptr pwhash; + + if(msec_in_iterations_out) + { + const std::chrono::milliseconds msec(*msec_in_iterations_out); + pwhash = pwhash_fam->tune(key_length, msec); + } + else + { + pwhash = pwhash_fam->from_iterations(iterations_if_msec_null); + } + + secure_vector key(key_length); + pwhash->derive_key(key.data(), key.size(), + passphrase.c_str(), passphrase.size(), + salt.data(), salt.size()); + + std::vector pbkdf2_params; + + const size_t iterations = pwhash->iterations(); + + if(msec_in_iterations_out) + *msec_in_iterations_out = iterations; + + DER_Encoder(pbkdf2_params) + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(iterations) + .encode(key_length) + .encode_if(prf != "HMAC(SHA-160)", + AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM)) + .end_cons(); + + kdf_algo = AlgorithmIdentifier("PKCS5.PBKDF2", pbkdf2_params); + return key; + } + } + +/* +* PKCS#5 v2.0 PBE Encryption +*/ +std::pair> +pbes2_encrypt_shared(const secure_vector& key_bits, + const std::string& passphrase, + size_t* msec_in_iterations_out, + size_t iterations_if_msec_null, + const std::string& cipher, + const std::string& prf, + RandomNumberGenerator& rng) + { + const std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Encoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + + if(!known_pbes_cipher_mode(cipher_spec[1])) + throw Encoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); + + const OID cipher_oid = OIDS::str2oid_or_empty(cipher); + if(cipher_oid.empty()) + throw Encoding_Error("PBE-PKCS5 v2.0: No OID assigned for " + cipher); + + std::unique_ptr enc = Cipher_Mode::create(cipher, ENCRYPTION); + + if(!enc) + throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher); + + const size_t key_length = enc->key_spec().maximum_keylength(); + + const secure_vector iv = rng.random_vec(enc->default_nonce_length()); + + AlgorithmIdentifier kdf_algo; + + const secure_vector derived_key = + derive_key(passphrase, prf, rng, + msec_in_iterations_out, iterations_if_msec_null, + key_length, kdf_algo); + + enc->set_key(derived_key); + enc->start(iv); + secure_vector ctext = key_bits; + enc->finish(ctext); + + std::vector encoded_iv; + DER_Encoder(encoded_iv).encode(iv, OCTET_STRING); + + std::vector pbes2_params; + DER_Encoder(pbes2_params) + .start_cons(SEQUENCE) + .encode(kdf_algo) + .encode(AlgorithmIdentifier(cipher, encoded_iv)) + .end_cons(); + + AlgorithmIdentifier id(OID::from_string("PBE-PKCS5v20"), pbes2_params); + + return std::make_pair(id, unlock(ctext)); + } + +} + +std::pair> +pbes2_encrypt(const secure_vector& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng) + { + size_t msec_in_iterations_out = static_cast(msec.count()); + return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng); + // return value msec_in_iterations_out discarded + } + +std::pair> +pbes2_encrypt_msec(const secure_vector& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + size_t* out_iterations_if_nonnull, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng) + { + size_t msec_in_iterations_out = static_cast(msec.count()); + + auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng); + + if(out_iterations_if_nonnull) + *out_iterations_if_nonnull = msec_in_iterations_out; + + return ret; + } + +std::pair> +pbes2_encrypt_iter(const secure_vector& key_bits, + const std::string& passphrase, + size_t pbkdf_iter, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng) + { + return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng); + } + +secure_vector +pbes2_decrypt(const secure_vector& key_bits, + const std::string& passphrase, + const std::vector& params) + { + AlgorithmIdentifier kdf_algo, enc_algo; + + BER_Decoder(params) + .start_cons(SEQUENCE) + .decode(kdf_algo) + .decode(enc_algo) + .end_cons(); + + const std::string cipher = OIDS::oid2str_or_throw(enc_algo.get_oid()); + const std::vector cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + if(!known_pbes_cipher_mode(cipher_spec[1])) + throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); + + secure_vector iv; + BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end(); + + std::unique_ptr dec = Cipher_Mode::create(cipher, DECRYPTION); + if(!dec) + throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher); + + dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength())); + + dec->start(iv); + + secure_vector buf = key_bits; + dec->finish(buf); + + return buf; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.h b/comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.h new file mode 100644 index 0000000000..a5051a8fd9 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pbes2/pbes2.h @@ -0,0 +1,87 @@ +/* +* PKCS #5 v2.0 PBE +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBE_PKCS_v20_H_ +#define BOTAN_PBE_PKCS_v20_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(pbes2.h) + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Encrypt with PBES2 from PKCS #5 v2.0 +* @param key_bits the input +* @param passphrase the passphrase to use for encryption +* @param msec how many milliseconds to run PBKDF2 +* @param cipher specifies the block cipher to use to encrypt +* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)") +* @param rng a random number generator +*/ +std::pair> +BOTAN_PUBLIC_API(2,0) pbes2_encrypt(const secure_vector& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng); + +/** +* Encrypt with PBES2 from PKCS #5 v2.0 +* @param key_bits the input +* @param passphrase the passphrase to use for encryption +* @param msec how many milliseconds to run PBKDF2 +* @param out_iterations_if_nonnull if not null, set to the number +* of PBKDF iterations used +* @param cipher specifies the block cipher to use to encrypt +* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)") +* @param rng a random number generator +*/ +std::pair> +BOTAN_PUBLIC_API(2,1) pbes2_encrypt_msec(const secure_vector& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + size_t* out_iterations_if_nonnull, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng); + +/** +* Encrypt with PBES2 from PKCS #5 v2.0 +* @param key_bits the input +* @param passphrase the passphrase to use for encryption +* @param iterations how many iterations to run PBKDF2 +* @param cipher specifies the block cipher to use to encrypt +* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)") +* @param rng a random number generator +*/ +std::pair> +BOTAN_PUBLIC_API(2,1) pbes2_encrypt_iter(const secure_vector& key_bits, + const std::string& passphrase, + size_t iterations, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng); + +/** +* Decrypt a PKCS #5 v2.0 encrypted stream +* @param key_bits the input +* @param passphrase the passphrase to use for decryption +* @param params the PBES2 parameters +*/ +secure_vector +BOTAN_PUBLIC_API(2,0) pbes2_decrypt(const secure_vector& key_bits, + const std::string& passphrase, + const std::vector& params); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pem/info.txt b/comm/third_party/botan/src/lib/pubkey/pem/info.txt new file mode 100644 index 0000000000..471d9abd63 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pem/info.txt @@ -0,0 +1,7 @@ + +PEM_CODEC -> 20131128 + + + +base64 + diff --git a/comm/third_party/botan/src/lib/pubkey/pem/pem.cpp b/comm/third_party/botan/src/lib/pubkey/pem/pem.cpp new file mode 100644 index 0000000000..d2433860dd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pem/pem.cpp @@ -0,0 +1,169 @@ +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace PEM_Code { + +namespace { + +std::string linewrap(size_t width, const std::string& in) + { + std::string out; + for(size_t i = 0; i != in.size(); ++i) + { + if(i > 0 && i % width == 0) + { + out.push_back('\n'); + } + out.push_back(in[i]); + } + if(out.size() > 0 && out[out.size()-1] != '\n') + { + out.push_back('\n'); + } + + return out; + } + +} + +/* +* PEM encode BER/DER-encoded objects +*/ +std::string encode(const uint8_t der[], size_t length, const std::string& label, size_t width) + { + const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; + const std::string PEM_TRAILER = "-----END " + label + "-----\n"; + + return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER); + } + +/* +* Decode PEM down to raw BER/DER +*/ +secure_vector decode_check_label(DataSource& source, + const std::string& label_want) + { + std::string label_got; + secure_vector ber = decode(source, label_got); + if(label_got != label_want) + throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + + ", got " + label_got); + return ber; + } + +/* +* Decode PEM down to raw BER/DER +*/ +secure_vector decode(DataSource& source, std::string& label) + { + const size_t RANDOM_CHAR_LIMIT = 8; + + label.clear(); + + const std::string PEM_HEADER1 = "-----BEGIN "; + const std::string PEM_HEADER2 = "-----"; + size_t position = 0; + + while(position != PEM_HEADER1.length()) + { + uint8_t b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PEM: Malformed PEM header"); + else + position = 0; + } + position = 0; + while(position != PEM_HEADER2.length()) + { + uint8_t b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM header"); + + if(position == 0) + label += static_cast(b); + } + + std::vector b64; + + const std::string PEM_TRAILER = "-----END " + label + "-----"; + position = 0; + while(position != PEM_TRAILER.length()) + { + uint8_t b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM trailer found"); + if(b == PEM_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM trailer"); + + if(position == 0) + b64.push_back(b); + } + + return base64_decode(b64.data(), b64.size()); + } + +secure_vector decode_check_label(const std::string& pem, + const std::string& label_want) + { + DataSource_Memory src(pem); + return decode_check_label(src, label_want); + } + +secure_vector decode(const std::string& pem, std::string& label) + { + DataSource_Memory src(pem); + return decode(src, label); + } + +/* +* Search for a PEM signature +*/ +bool matches(DataSource& source, const std::string& extra, + size_t search_range) + { + const std::string PEM_HEADER = "-----BEGIN " + extra; + + secure_vector search_buf(search_range); + size_t got = source.peek(search_buf.data(), search_buf.size(), 0); + + if(got < PEM_HEADER.length()) + return false; + + size_t index = 0; + + for(size_t j = 0; j != got; ++j) + { + if(search_buf[j] == PEM_HEADER[index]) + ++index; + else + index = 0; + if(index == PEM_HEADER.size()) + return true; + } + return false; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/pubkey/pem/pem.h b/comm/third_party/botan/src/lib/pubkey/pem/pem.h new file mode 100644 index 0000000000..c02294dce5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pem/pem.h @@ -0,0 +1,91 @@ +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PEM_H_ +#define BOTAN_PEM_H_ + +#include +#include + +namespace Botan { + +class DataSource; + +namespace PEM_Code { + +/** +* Encode some binary data in PEM format +* @param data binary data to encode +* @param data_len length of binary data in bytes +* @param label PEM label put after BEGIN and END +* @param line_width after this many characters, a new line is inserted +*/ +BOTAN_PUBLIC_API(2,0) std::string encode(const uint8_t data[], + size_t data_len, + const std::string& label, + size_t line_width = 64); + +/** +* Encode some binary data in PEM format +* @param data binary data to encode +* @param label PEM label +* @param line_width after this many characters, a new line is inserted +*/ +template +std::string encode(const std::vector& data, + const std::string& label, + size_t line_width = 64) + { + return encode(data.data(), data.size(), label, line_width); + } + +/** +* Decode PEM data +* @param pem a datasource containing PEM encoded data +* @param label is set to the PEM label found for later inspection +*/ +BOTAN_PUBLIC_API(2,0) secure_vector decode(DataSource& pem, + std::string& label); + +/** +* Decode PEM data +* @param pem a string containing PEM encoded data +* @param label is set to the PEM label found for later inspection +*/ +BOTAN_PUBLIC_API(2,0) secure_vector decode(const std::string& pem, + std::string& label); + +/** +* Decode PEM data +* @param pem a datasource containing PEM encoded data +* @param label is what we expect the label to be +*/ +BOTAN_PUBLIC_API(2,0) +secure_vector decode_check_label(DataSource& pem, + const std::string& label); + +/** +* Decode PEM data +* @param pem a string containing PEM encoded data +* @param label is what we expect the label to be +*/ +BOTAN_PUBLIC_API(2,0) +secure_vector decode_check_label(const std::string& pem, + const std::string& label); + +/** +* Heuristic test for PEM data. +*/ +BOTAN_PUBLIC_API(2,0) bool matches(DataSource& source, + const std::string& extra = "", + size_t search_range = 4096); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pk_algs.cpp b/comm/third_party/botan/src/lib/pubkey/pk_algs.cpp new file mode 100644 index 0000000000..fc86975852 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_algs.cpp @@ -0,0 +1,426 @@ +/* +* PK Key +* (C) 1999-2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_HAS_RSA) + #include +#endif + +#if defined(BOTAN_HAS_DSA) + #include +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + #include +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include +#endif + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + #include +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include +#endif + +#if defined(BOTAN_HAS_ECGDSA) + #include +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + #include +#endif + +#if defined(BOTAN_HAS_ED25519) + #include +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + #include +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include +#endif + +#if defined(BOTAN_HAS_ECDH) + #include +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + #include +#endif + +#if defined(BOTAN_HAS_MCELIECE) + #include +#endif + +#if defined(BOTAN_HAS_XMSS_RFC8391) + #include +#endif + +#if defined(BOTAN_HAS_SM2) + #include +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +namespace Botan { + +std::unique_ptr +load_public_key(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) + { + const std::string oid_str = alg_id.get_oid().to_formatted_string(); + const std::vector alg_info = split_on(oid_str, '/'); + const std::string alg_name = alg_info[0]; + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return std::unique_ptr(new RSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return std::unique_ptr(new Curve25519_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_MCELIECE) + if(alg_name == "McEliece") + return std::unique_ptr(new McEliece_PublicKey(key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return std::unique_ptr(new ECDSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return std::unique_ptr(new ECDH_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return std::unique_ptr(new DH_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return std::unique_ptr(new DSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return std::unique_ptr(new ElGamal_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return std::unique_ptr(new ECGDSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + if(alg_name == "ECKCDSA") + return std::unique_ptr(new ECKCDSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ED25519) + if(alg_name == "Ed25519") + return std::unique_ptr(new Ed25519_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") + return std::unique_ptr(new GOST_3410_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_SM2) + if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") + return std::unique_ptr(new SM2_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_XMSS_RFC8391) + if(alg_name == "XMSS") + return std::unique_ptr(new XMSS_PublicKey(key_bits)); +#endif + + throw Decoding_Error("Unknown or unavailable public key algorithm " + alg_name); + } + +std::unique_ptr +load_private_key(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) + { + const std::string alg_name = alg_id.get_oid().to_formatted_string(); + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return std::unique_ptr(new RSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return std::unique_ptr(new Curve25519_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return std::unique_ptr(new ECDSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return std::unique_ptr(new ECDH_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return std::unique_ptr(new DH_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return std::unique_ptr(new DSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_MCELIECE) + if(alg_name == "McEliece") + return std::unique_ptr(new McEliece_PrivateKey(key_bits)); +#endif + +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return std::unique_ptr(new ECGDSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + if(alg_name == "ECKCDSA") + return std::unique_ptr(new ECKCDSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ED25519) + if(alg_name == "Ed25519") + return std::unique_ptr(new Ed25519_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") + return std::unique_ptr(new GOST_3410_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_SM2) + if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") + return std::unique_ptr(new SM2_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return std::unique_ptr(new ElGamal_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_XMSS_RFC8391) + if(alg_name == "XMSS") + return std::unique_ptr(new XMSS_PrivateKey(key_bits)); +#endif + + throw Decoding_Error("Unknown or unavailable public key algorithm " + alg_name); + } + +#if defined(BOTAN_HAS_ECC_GROUP) + +namespace { + +std::string default_ec_group_for(const std::string& alg_name) + { + if(alg_name == "SM2" || alg_name == "SM2_Enc" || alg_name == "SM2_Sig") + return "sm2p256v1"; + if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256") + return "gost_256A"; + if(alg_name == "GOST-34.10-2012-512") + return "gost_512A"; + if(alg_name == "ECGDSA") + return "brainpool256r1"; + return "secp256r1"; + + } + +} + +#endif + +std::unique_ptr +create_private_key(const std::string& alg_name, + RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) + { + /* + * Default paramaters are chosen for work factor > 2**128 where possible + */ + +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return std::unique_ptr(new Curve25519_PrivateKey(rng)); +#endif + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + { + const size_t rsa_bits = (params.empty() ? 3072 : to_u32bit(params)); +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + std::unique_ptr pk; + if((pk = make_openssl_rsa_private_key(rng, rsa_bits))) + return pk; + + if(!provider.empty()) + return nullptr; + } +#endif + return std::unique_ptr(new RSA_PrivateKey(rng, rsa_bits)); + } +#endif + +#if defined(BOTAN_HAS_MCELIECE) + if(alg_name == "McEliece") + { + std::vector mce_param = + Botan::split_on(params.empty() ? "2960,57" : params, ','); + + if(mce_param.size() != 2) + throw Invalid_Argument("create_private_key bad McEliece parameters " + params); + + size_t mce_n = Botan::to_u32bit(mce_param[0]); + size_t mce_t = Botan::to_u32bit(mce_param[1]); + + return std::unique_ptr(new Botan::McEliece_PrivateKey(rng, mce_n, mce_t)); + } +#endif + +#if defined(BOTAN_HAS_XMSS_RFC8391) + if(alg_name == "XMSS") + { + return std::unique_ptr( + new XMSS_PrivateKey(XMSS_Parameters(params.empty() ? "XMSS-SHA2_10_512" : params).oid(), rng)); + } +#endif + +#if defined(BOTAN_HAS_ED25519) + if(alg_name == "Ed25519") + { + return std::unique_ptr(new Ed25519_PrivateKey(rng)); + } +#endif + + // ECC crypto +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + + if(alg_name == "ECDSA" || + alg_name == "ECDH" || + alg_name == "ECKCDSA" || + alg_name == "ECGDSA" || + alg_name == "SM2" || + alg_name == "SM2_Sig" || + alg_name == "SM2_Enc" || + alg_name == "GOST-34.10" || + alg_name == "GOST-34.10-2012-256" || + alg_name == "GOST-34.10-2012-512") + { + const EC_Group ec_group(params.empty() ? default_ec_group_for(alg_name) : params); + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return std::unique_ptr(new ECDSA_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return std::unique_ptr(new ECDH_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + if(alg_name == "ECKCDSA") + return std::unique_ptr(new ECKCDSA_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10" || alg_name == "GOST-34.10-2012-256" || alg_name == "GOST-34.10-2012-512") + return std::unique_ptr(new GOST_3410_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_SM2) + if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") + return std::unique_ptr(new SM2_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return std::unique_ptr(new ECGDSA_PrivateKey(rng, ec_group)); +#endif + } +#endif + + // DL crypto +#if defined(BOTAN_HAS_DL_GROUP) + if(alg_name == "DH" || alg_name == "DSA" || alg_name == "ElGamal") + { + std::string default_group = (alg_name == "DSA") ? "dsa/botan/2048" : "modp/ietf/2048"; + DL_Group modp_group(params.empty() ? default_group : params); + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return std::unique_ptr(new DH_PrivateKey(rng, modp_group)); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return std::unique_ptr(new DSA_PrivateKey(rng, modp_group)); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return std::unique_ptr(new ElGamal_PrivateKey(rng, modp_group)); +#endif + } +#endif + + BOTAN_UNUSED(alg_name, rng, params, provider); + + return std::unique_ptr(); + } + +std::vector +probe_provider_private_key(const std::string& alg_name, + const std::vector possible) + { + std::vector providers; + for(auto&& prov : possible) + { + if(prov == "base" || +#if defined(BOTAN_HAS_OPENSSL) + (prov == "openssl" && alg_name == "RSA") || +#endif + 0) + { + providers.push_back(prov); // available + } + } + + BOTAN_UNUSED(alg_name); + + return providers; + } +} diff --git a/comm/third_party/botan/src/lib/pubkey/pk_algs.h b/comm/third_party/botan/src/lib/pubkey/pk_algs.h new file mode 100644 index 0000000000..12514908ec --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_algs.h @@ -0,0 +1,46 @@ +/* +* PK Key Factory +* (C) 1999-2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_KEY_FACTORY_H_ +#define BOTAN_PK_KEY_FACTORY_H_ + +#include +#include +#include + +namespace Botan { + +BOTAN_PUBLIC_API(2,0) std::unique_ptr +load_public_key(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits); + +BOTAN_PUBLIC_API(2,0) std::unique_ptr +load_private_key(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + +/** +* Create a new key +* For ECC keys, algo_params specifies EC group (eg, "secp256r1") +* For DH/DSA/ElGamal keys, algo_params is DL group (eg, "modp/ietf/2048") +* For RSA, algo_params is integer keylength +* For McEliece, algo_params is n,t +* If algo_params is left empty, suitable default parameters are chosen. +*/ +BOTAN_PUBLIC_API(2,0) std::unique_ptr +create_private_key(const std::string& algo_name, + RandomNumberGenerator& rng, + const std::string& algo_params = "", + const std::string& provider = ""); + +BOTAN_PUBLIC_API(2,2) +std::vector +probe_provider_private_key(const std::string& algo_name, + const std::vector possible); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pk_keys.cpp b/comm/third_party/botan/src/lib/pubkey/pk_keys.cpp new file mode 100644 index 0000000000..c5a98d72fe --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_keys.cpp @@ -0,0 +1,145 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +std::string create_hex_fingerprint(const uint8_t bits[], + size_t bits_len, + const std::string& hash_name) + { + std::unique_ptr hash_fn(HashFunction::create_or_throw(hash_name)); + const std::string hex_hash = hex_encode(hash_fn->process(bits, bits_len)); + + std::string fprint; + + for(size_t i = 0; i != hex_hash.size(); i += 2) + { + if(i != 0) + fprint.push_back(':'); + + fprint.push_back(hex_hash[i]); + fprint.push_back(hex_hash[i+1]); + } + + return fprint; + } + +std::vector Public_Key::subject_public_key() const + { + std::vector output; + + DER_Encoder(output).start_cons(SEQUENCE) + .encode(algorithm_identifier()) + .encode(public_key_bits(), BIT_STRING) + .end_cons(); + + return output; + } + +/* +* Default OID access +*/ +OID Public_Key::get_oid() const + { + const OID o = OIDS::str2oid_or_empty(algo_name()); + if(o.empty()) + throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs"); + return o; + } + +secure_vector Private_Key::private_key_info() const + { + const size_t PKCS8_VERSION = 0; + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(PKCS8_VERSION) + .encode(pkcs8_algorithm_identifier()) + .encode(private_key_bits(), OCTET_STRING) + .end_cons() + .get_contents(); + } + +/* +* Hash of the X.509 subjectPublicKey encoding +*/ +std::string Public_Key::fingerprint_public(const std::string& hash_algo) const + { + return create_hex_fingerprint(subject_public_key(), hash_algo); + } + +/* +* Hash of the PKCS #8 encoding for this key object +*/ +std::string Private_Key::fingerprint_private(const std::string& hash_algo) const + { + return create_hex_fingerprint(private_key_bits(), hash_algo); + } + +std::unique_ptr +Public_Key::create_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support encryption"); + } + +std::unique_ptr +Public_Key::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support KEM encryption"); + } + +std::unique_ptr +Public_Key::create_verification_op(const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support verification"); + } + +std::unique_ptr +Private_Key::create_decryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support decryption"); + } + +std::unique_ptr +Private_Key::create_kem_decryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support KEM decryption"); + } + +std::unique_ptr +Private_Key::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support signatures"); + } + +std::unique_ptr +Private_Key::create_key_agreement_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support key agreement"); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/pk_keys.h b/comm/third_party/botan/src/lib/pubkey/pk_keys.h new file mode 100644 index 0000000000..bf2be6bbd2 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_keys.h @@ -0,0 +1,329 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_KEYS_H_ +#define BOTAN_PK_KEYS_H_ + +#include +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +/** +* The two types of signature format supported by Botan. +*/ +enum Signature_Format { IEEE_1363, DER_SEQUENCE }; + +/** +* Public Key Base Class. +*/ +class BOTAN_PUBLIC_API(2,0) Public_Key + { + public: + Public_Key() =default; + Public_Key(const Public_Key& other) = default; + Public_Key& operator=(const Public_Key& other) = default; + virtual ~Public_Key() = default; + + /** + * Get the name of the underlying public key scheme. + * @return name of the public key scheme + */ + virtual std::string algo_name() const = 0; + + /** + * Return the estimated strength of the underlying key against + * the best currently known attack. Note that this ignores anything + * but pure attacks against the key itself and do not take into + * account padding schemes, usage mistakes, etc which might reduce + * the strength. However it does suffice to provide an upper bound. + * + * @return estimated strength in bits + */ + virtual size_t estimated_strength() const = 0; + + /** + * Return an integer value best approximating the length of the + * primary security parameter. For example for RSA this will be + * the size of the modulus, for ECDSA the size of the ECC group, + * and for McEliece the size of the code will be returned. + */ + virtual size_t key_length() const = 0; + + /** + * Get the OID of the underlying public key scheme. + * @return OID of the public key scheme + */ + virtual OID get_oid() const; + + /** + * Test the key values for consistency. + * @param rng rng to use + * @param strong whether to perform strong and lengthy version + * of the test + * @return true if the test is passed + */ + virtual bool check_key(RandomNumberGenerator& rng, + bool strong) const = 0; + + + /** + * @return X.509 AlgorithmIdentifier for this key + */ + virtual AlgorithmIdentifier algorithm_identifier() const = 0; + + /** + * @return BER encoded public key bits + */ + virtual std::vector public_key_bits() const = 0; + + /** + * @return X.509 subject key encoding for this key object + */ + std::vector subject_public_key() const; + + /** + * @return Hash of the subject public key + */ + std::string fingerprint_public(const std::string& alg = "SHA-256") const; + + // Internal or non-public declarations follow + + /** + * Returns more than 1 if the output of this algorithm + * (ciphertext, signature) should be treated as more than one + * value. This is used for algorithms like DSA and ECDSA, where + * the (r,s) output pair can be encoded as either a plain binary + * list or a TLV tagged DER encoding depending on the protocol. + * + * This function is public but applications should have few + * reasons to ever call this. + * + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Returns how large each of the message parts refered to + * by message_parts() is + * + * This function is public but applications should have few + * reasons to ever call this. + * + * @return size of the message parts in bits + */ + virtual size_t message_part_size() const { return 0; } + + virtual Signature_Format default_x509_signature_format() const + { + return (this->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + } + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return an encryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a KEM encryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr + create_kem_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a verification operation for this key/params or throw + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const; + }; + +/** +* Private Key Base Class +*/ +class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key + { + public: + Private_Key() = default; + Private_Key(const Private_Key& other) = default; + Private_Key& operator=(const Private_Key& other) = default; + virtual ~Private_Key() = default; + + virtual bool stateful_operation() const { return false; } + + /** + * @return BER encoded private key bits + */ + virtual secure_vector private_key_bits() const = 0; + + /** + * @return PKCS #8 private key encoding for this key object + */ + secure_vector private_key_info() const; + + /** + * @return PKCS #8 AlgorithmIdentifier for this key + * Might be different from the X.509 identifier, but normally is not + */ + virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const + { return algorithm_identifier(); } + + // Internal or non-public declarations follow + + /** + * @return Hash of the PKCS #8 encoding for this key object + */ + std::string fingerprint_private(const std::string& alg) const; + + BOTAN_DEPRECATED("Use fingerprint_private or fingerprint_public") + inline std::string fingerprint(const std::string& alg) const + { + return fingerprint_private(alg); // match behavior in previous versions + } + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return an decryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + * + */ + virtual std::unique_ptr + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a KEM decryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr + create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a signature operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a key agreement operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + }; + +/** +* PK Secret Value Derivation Key +*/ +class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement_Key : public virtual Private_Key + { + public: + /* + * @return public component of this key + */ + virtual std::vector public_value() const = 0; + + PK_Key_Agreement_Key() = default; + PK_Key_Agreement_Key(const PK_Key_Agreement_Key&) = default; + PK_Key_Agreement_Key& operator=(const PK_Key_Agreement_Key&) = default; + virtual ~PK_Key_Agreement_Key() = default; + }; + +/* +* Old compat typedefs +* TODO: remove these? +*/ +typedef PK_Key_Agreement_Key PK_KA_Key; +typedef Public_Key X509_PublicKey; +typedef Private_Key PKCS8_PrivateKey; + +std::string BOTAN_PUBLIC_API(2,4) + create_hex_fingerprint(const uint8_t bits[], size_t len, + const std::string& hash_name); + +template +std::string create_hex_fingerprint(const std::vector& vec, + const std::string& hash_name) + { + return create_hex_fingerprint(vec.data(), vec.size(), hash_name); + } + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pk_ops.cpp b/comm/third_party/botan/src/lib/pubkey/pk_ops.cpp new file mode 100644 index 0000000000..025836878b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_ops.cpp @@ -0,0 +1,173 @@ +/* +* PK Operation Types +* (C) 2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +PK_Ops::Encryption_with_EME::Encryption_with_EME(const std::string& eme) + { + m_eme.reset(get_eme(eme)); + if(!m_eme.get()) + throw Algorithm_Not_Found(eme); + } + +size_t PK_Ops::Encryption_with_EME::max_input_bits() const + { + return 8 * m_eme->maximum_input_size(max_raw_input_bits()); + } + +secure_vector PK_Ops::Encryption_with_EME::encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t max_raw = max_raw_input_bits(); + const std::vector encoded = unlock(m_eme->encode(msg, msg_len, max_raw, rng)); + return raw_encrypt(encoded.data(), encoded.size(), rng); + } + +PK_Ops::Decryption_with_EME::Decryption_with_EME(const std::string& eme) + { + m_eme.reset(get_eme(eme)); + if(!m_eme.get()) + throw Algorithm_Not_Found(eme); + } + +secure_vector +PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, + const uint8_t ciphertext[], + size_t ciphertext_len) + { + const secure_vector raw = raw_decrypt(ciphertext, ciphertext_len); + return m_eme->unpad(valid_mask, raw.data(), raw.size()); + } + +PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(const std::string& kdf) + { + if(kdf != "Raw") + m_kdf.reset(get_kdf(kdf)); + } + +secure_vector PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len, + const uint8_t w[], size_t w_len, + const uint8_t salt[], size_t salt_len) + { + secure_vector z = raw_agree(w, w_len); + if(m_kdf) + return m_kdf->derive_key(key_len, z, salt, salt_len); + return z; + } + +PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa) : + Signature(), + m_emsa(get_emsa(emsa)), + m_hash(hash_for_emsa(emsa)), + m_prefix_used(false) + { + if(!m_emsa) + throw Algorithm_Not_Found(emsa); + } + +void PK_Ops::Signature_with_EMSA::update(const uint8_t msg[], size_t msg_len) + { + if(has_prefix() && !m_prefix_used) + { + m_prefix_used = true; + secure_vector prefix = message_prefix(); + m_emsa->update(prefix.data(), prefix.size()); + } + m_emsa->update(msg, msg_len); + } + +secure_vector PK_Ops::Signature_with_EMSA::sign(RandomNumberGenerator& rng) + { + m_prefix_used = false; + const secure_vector msg = m_emsa->raw_data(); + const auto padded = m_emsa->encoding_of(msg, this->max_input_bits(), rng); + return raw_sign(padded.data(), padded.size(), rng); + } + +PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa) : + Verification(), + m_emsa(get_emsa(emsa)), + m_hash(hash_for_emsa(emsa)), + m_prefix_used(false) + { + if(!m_emsa) + throw Algorithm_Not_Found(emsa); + } + +void PK_Ops::Verification_with_EMSA::update(const uint8_t msg[], size_t msg_len) + { + if(has_prefix() && !m_prefix_used) + { + m_prefix_used = true; + secure_vector prefix = message_prefix(); + m_emsa->update(prefix.data(), prefix.size()); + } + m_emsa->update(msg, msg_len); + } + +bool PK_Ops::Verification_with_EMSA::is_valid_signature(const uint8_t sig[], size_t sig_len) + { + m_prefix_used = false; + const secure_vector msg = m_emsa->raw_data(); + + if(with_recovery()) + { + secure_vector output_of_key = verify_mr(sig, sig_len); + return m_emsa->verify(output_of_key, msg, max_input_bits()); + } + else + { + Null_RNG rng; + secure_vector encoded = m_emsa->encoding_of(msg, max_input_bits(), rng); + return verify(encoded.data(), encoded.size(), sig, sig_len); + } + } + +void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) + { + secure_vector raw_shared; + this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng); + + out_shared_key = m_kdf->derive_key(desired_shared_key_len, + raw_shared.data(), raw_shared.size(), + salt, salt_len); + } + +PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(const std::string& kdf) + { + m_kdf.reset(get_kdf(kdf)); + } + +secure_vector +PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(const uint8_t encap_key[], + size_t len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) + { + secure_vector raw_shared = this->raw_kem_decrypt(encap_key, len); + + return m_kdf->derive_key(desired_shared_key_len, + raw_shared.data(), raw_shared.size(), + salt, salt_len); + } + +PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(const std::string& kdf) + { + m_kdf.reset(get_kdf(kdf)); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/pk_ops.h b/comm/third_party/botan/src/lib/pubkey/pk_ops.h new file mode 100644 index 0000000000..63ef9fa9bd --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_ops.h @@ -0,0 +1,161 @@ +/* +* (C) 2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_OPERATIONS_H_ +#define BOTAN_PK_OPERATIONS_H_ + +/** +* Ordinary applications should never need to include or use this +* header. It is exposed only for specialized applications which want +* to implement new versions of public key crypto without merging them +* as changes to the library. One actual example of such usage is an +* application which creates RSA signatures using a custom TPM library. +* Unless you're doing something like that, you don't need anything +* here. Instead use pubkey.h which wraps these types safely and +* provides a stable application-oriented API. +*/ + +#include +#include + +namespace Botan { + +class RandomNumberGenerator; +class EME; +class KDF; +class EMSA; + +namespace PK_Ops { + +/** +* Public key encryption interface +*/ +class BOTAN_PUBLIC_API(2,0) Encryption + { + public: + virtual secure_vector encrypt(const uint8_t msg[], + size_t msg_len, + RandomNumberGenerator& rng) = 0; + + virtual size_t max_input_bits() const = 0; + + virtual size_t ciphertext_length(size_t ptext_len) const = 0; + + virtual ~Encryption() = default; + }; + +/** +* Public key decryption interface +*/ +class BOTAN_PUBLIC_API(2,0) Decryption + { + public: + virtual secure_vector decrypt(uint8_t& valid_mask, + const uint8_t ciphertext[], + size_t ciphertext_len) = 0; + + virtual size_t plaintext_length(size_t ctext_len) const = 0; + + virtual ~Decryption() = default; + }; + +/** +* Public key signature verification interface +*/ +class BOTAN_PUBLIC_API(2,0) Verification + { + public: + /* + * Add more data to the message currently being signed + * @param msg the message + * @param msg_len the length of msg in bytes + */ + virtual void update(const uint8_t msg[], size_t msg_len) = 0; + + /* + * Perform a verification operation + * @param rng a random number generator + */ + virtual bool is_valid_signature(const uint8_t sig[], size_t sig_len) = 0; + + virtual ~Verification() = default; + }; + +/** +* Public key signature creation interface +*/ +class BOTAN_PUBLIC_API(2,0) Signature + { + public: + /* + * Add more data to the message currently being signed + * @param msg the message + * @param msg_len the length of msg in bytes + */ + virtual void update(const uint8_t msg[], size_t msg_len) = 0; + + /* + * Perform a signature operation + * @param rng a random number generator + */ + virtual secure_vector sign(RandomNumberGenerator& rng) = 0; + + /* + * Return an upper bound on the length of the output signature + */ + virtual size_t signature_length() const = 0; + + virtual ~Signature() = default; + }; + +/** +* A generic key agreement operation (eg DH or ECDH) +*/ +class BOTAN_PUBLIC_API(2,0) Key_Agreement + { + public: + virtual secure_vector agree(size_t key_len, + const uint8_t other_key[], size_t other_key_len, + const uint8_t salt[], size_t salt_len) = 0; + + virtual size_t agreed_value_size() const = 0; + + virtual ~Key_Agreement() = default; + }; + +/** +* KEM (key encapsulation) +*/ +class BOTAN_PUBLIC_API(2,0) KEM_Encryption + { + public: + virtual void kem_encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) = 0; + + virtual ~KEM_Encryption() = default; + }; + +class BOTAN_PUBLIC_API(2,0) KEM_Decryption + { + public: + virtual secure_vector kem_decrypt(const uint8_t encap_key[], + size_t len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) = 0; + + virtual ~KEM_Decryption() = default; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pk_ops_fwd.h b/comm/third_party/botan/src/lib/pubkey/pk_ops_fwd.h new file mode 100644 index 0000000000..92a3c2a969 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_ops_fwd.h @@ -0,0 +1,27 @@ +/* +* PK Operation Types Forward Decls +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_OPERATIONS_FWD_H_ +#define BOTAN_PK_OPERATIONS_FWD_H_ + +namespace Botan { + +namespace PK_Ops { + +class Encryption; +class Decryption; +class Verification; +class Signature; +class Key_Agreement; +class KEM_Encryption; +class KEM_Decryption; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pk_ops_impl.h b/comm/third_party/botan/src/lib/pubkey/pk_ops_impl.h new file mode 100644 index 0000000000..6bab2143e1 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pk_ops_impl.h @@ -0,0 +1,231 @@ + +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_OPERATION_IMPL_H_ +#define BOTAN_PK_OPERATION_IMPL_H_ + +#include +#include +#include +#include + +namespace Botan { + +namespace PK_Ops { + +class Encryption_with_EME : public Encryption + { + public: + size_t max_input_bits() const override; + + secure_vector encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + ~Encryption_with_EME() = default; + protected: + explicit Encryption_with_EME(const std::string& eme); + private: + virtual size_t max_raw_input_bits() const = 0; + + virtual secure_vector raw_encrypt(const uint8_t msg[], size_t len, + RandomNumberGenerator& rng) = 0; + std::unique_ptr m_eme; + }; + +class Decryption_with_EME : public Decryption + { + public: + secure_vector decrypt(uint8_t& valid_mask, + const uint8_t msg[], size_t msg_len) override; + + ~Decryption_with_EME() = default; + protected: + explicit Decryption_with_EME(const std::string& eme); + private: + virtual secure_vector raw_decrypt(const uint8_t msg[], size_t len) = 0; + std::unique_ptr m_eme; + }; + +class Verification_with_EMSA : public Verification + { + public: + ~Verification_with_EMSA() = default; + + void update(const uint8_t msg[], size_t msg_len) override; + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; + + bool do_check(const secure_vector& msg, + const uint8_t sig[], size_t sig_len); + + std::string hash_for_signature() { return m_hash; } + + protected: + explicit Verification_with_EMSA(const std::string& emsa); + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + /** + * @return boolean specifying if this signature scheme uses + * a message prefix returned by message_prefix() + */ + virtual bool has_prefix() { return false; } + + /** + * @return the message prefix if this signature scheme uses + * a message prefix, signaled via has_prefix() + */ + virtual secure_vector message_prefix() const { throw Invalid_State("No prefix"); } + + /** + * @return boolean specifying if this key type supports message + * recovery and thus if you need to call verify() or verify_mr() + */ + virtual bool with_recovery() const = 0; + + /* + * Perform a signature check operation + * @param msg the message + * @param msg_len the length of msg in bytes + * @param sig the signature + * @param sig_len the length of sig in bytes + * @returns if signature is a valid one for message + */ + virtual bool verify(const uint8_t[], size_t, + const uint8_t[], size_t) + { + throw Invalid_State("Message recovery required"); + } + + /* + * Perform a signature operation (with message recovery) + * Only call this if with_recovery() returns true + * @param msg the message + * @param msg_len the length of msg in bytes + * @returns recovered message + */ + virtual secure_vector verify_mr(const uint8_t[], size_t) + { + throw Invalid_State("Message recovery not supported"); + } + + std::unique_ptr clone_emsa() const { return std::unique_ptr(m_emsa->clone()); } + + private: + std::unique_ptr m_emsa; + const std::string m_hash; + bool m_prefix_used; + }; + +class Signature_with_EMSA : public Signature + { + public: + void update(const uint8_t msg[], size_t msg_len) override; + + secure_vector sign(RandomNumberGenerator& rng) override; + protected: + explicit Signature_with_EMSA(const std::string& emsa); + ~Signature_with_EMSA() = default; + + std::string hash_for_signature() { return m_hash; } + + /** + * @return boolean specifying if this signature scheme uses + * a message prefix returned by message_prefix() + */ + virtual bool has_prefix() { return false; } + + /** + * @return the message prefix if this signature scheme uses + * a message prefix, signaled via has_prefix() + */ + virtual secure_vector message_prefix() const { throw Invalid_State("No prefix"); } + + std::unique_ptr clone_emsa() const { return std::unique_ptr(m_emsa->clone()); } + + private: + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + bool self_test_signature(const std::vector& msg, + const std::vector& sig) const; + + virtual secure_vector raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + std::unique_ptr m_emsa; + const std::string m_hash; + bool m_prefix_used; + }; + +class Key_Agreement_with_KDF : public Key_Agreement + { + public: + secure_vector agree(size_t key_len, + const uint8_t other_key[], size_t other_key_len, + const uint8_t salt[], size_t salt_len) override; + + protected: + explicit Key_Agreement_with_KDF(const std::string& kdf); + ~Key_Agreement_with_KDF() = default; + private: + virtual secure_vector raw_agree(const uint8_t w[], size_t w_len) = 0; + std::unique_ptr m_kdf; + }; + +class KEM_Encryption_with_KDF : public KEM_Encryption + { + public: + void kem_encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) override; + + protected: + virtual void raw_kem_encrypt(secure_vector& out_encapsulated_key, + secure_vector& raw_shared_key, + Botan::RandomNumberGenerator& rng) = 0; + + explicit KEM_Encryption_with_KDF(const std::string& kdf); + ~KEM_Encryption_with_KDF() = default; + private: + std::unique_ptr m_kdf; + }; + +class KEM_Decryption_with_KDF : public KEM_Decryption + { + public: + secure_vector kem_decrypt(const uint8_t encap_key[], + size_t len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) override; + + protected: + virtual secure_vector + raw_kem_decrypt(const uint8_t encap_key[], size_t len) = 0; + + explicit KEM_Decryption_with_KDF(const std::string& kdf); + ~KEM_Decryption_with_KDF() = default; + private: + std::unique_ptr m_kdf; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pkcs8.cpp b/comm/third_party/botan/src/lib/pubkey/pkcs8.cpp new file mode 100644 index 0000000000..2989e20aa0 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pkcs8.cpp @@ -0,0 +1,490 @@ +/* +* PKCS #8 +* (C) 1999-2010,2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_PKCS5_PBES2) + #include +#endif + +namespace Botan { + +namespace PKCS8 { + +namespace { + +/* +* Get info from an EncryptedPrivateKeyInfo +*/ +secure_vector PKCS8_extract(DataSource& source, + AlgorithmIdentifier& pbe_alg_id) + { + secure_vector key_data; + + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(pbe_alg_id) + .decode(key_data, OCTET_STRING) + .verify_end(); + + return key_data; + } + +/* +* PEM decode and/or decrypt a private key +*/ +secure_vector PKCS8_decode( + DataSource& source, + std::function get_passphrase, + AlgorithmIdentifier& pk_alg_id, + bool is_encrypted) + { + AlgorithmIdentifier pbe_alg_id; + secure_vector key_data, key; + + try { + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + if(is_encrypted) + { + key_data = PKCS8_extract(source, pbe_alg_id); + } + else + { + // todo read more efficiently + while(!source.end_of_data()) + { + uint8_t b; + size_t read = source.read_byte(b); + if(read) + { + key_data.push_back(b); + } + } + } + } + else + { + std::string label; + key_data = PEM_Code::decode(source, label); + + // todo remove autodetect for pem as well? + if(label == "PRIVATE KEY") + is_encrypted = false; + else if(label == "ENCRYPTED PRIVATE KEY") + { + DataSource_Memory key_source(key_data); + key_data = PKCS8_extract(key_source, pbe_alg_id); + } + else + throw PKCS8_Exception("Unknown PEM label " + label); + } + + if(key_data.empty()) + throw PKCS8_Exception("No key data found"); + } + catch(Decoding_Error& e) + { + throw Decoding_Error("PKCS #8 private key decoding", e); + } + + try + { + if(is_encrypted) + { + if(OIDS::oid2str_or_throw(pbe_alg_id.get_oid()) != "PBE-PKCS5v20") + throw PKCS8_Exception("Unknown PBE type " + pbe_alg_id.get_oid().to_string()); +#if defined(BOTAN_HAS_PKCS5_PBES2) + key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.get_parameters()); +#else + BOTAN_UNUSED(get_passphrase); + throw Decoding_Error("Private key is encrypted but PBES2 was disabled in build"); +#endif + } + else + key = key_data; + + BER_Decoder(key) + .start_cons(SEQUENCE) + .decode_and_check(0, "Unknown PKCS #8 version number") + .decode(pk_alg_id) + .decode(key, OCTET_STRING) + .discard_remaining() + .end_cons(); + } + catch(std::exception& e) + { + throw Decoding_Error("PKCS #8 private key decoding", e); + } + return key; + } + +} + +/* +* BER encode a PKCS #8 private key, unencrypted +*/ +secure_vector BER_encode(const Private_Key& key) + { + // keeping around for compat + return key.private_key_info(); + } + +/* +* PEM encode a PKCS #8 private key, unencrypted +*/ +std::string PEM_encode(const Private_Key& key) + { + return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY"); + } + +#if defined(BOTAN_HAS_PKCS5_PBES2) + +namespace { + +std::pair +choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo) + { + if(pbe_algo.empty()) + { + /* + * For algorithms where we are using a non-RFC format anyway, default to + * SIV or GCM. For others (RSA, ECDSA, ...) default to something widely + * compatible. + */ + const bool nonstandard_pk = (key_algo == "McEliece" || key_algo == "XMSS"); + + if(nonstandard_pk) + { +#if defined(BOTAN_HAS_AEAD_SIV) && defined(BOTAN_HAS_SHA2_64) + return std::make_pair("AES-256/SIV", "SHA-512"); +#elif defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_SHA2_64) + return std::make_pair("AES-256/GCM", "SHA-512"); +#endif + } + + // Default is something compatible with everyone else + return std::make_pair("AES-256/CBC", "SHA-256"); + } + + SCAN_Name request(pbe_algo); + + if(request.arg_count() != 2 || + (request.algo_name() != "PBE-PKCS5v20" && request.algo_name() != "PBES2")) + { + throw Invalid_Argument("Unsupported PBE " + pbe_algo); + } + + return std::make_pair(request.arg(0), request.arg(1)); + } + +} + +#endif + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec, + const std::string& pbe_algo) + { +#if defined(BOTAN_HAS_PKCS5_PBES2) + const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name()); + + const std::pair> pbe_info = + pbes2_encrypt_msec(PKCS8::BER_encode(key), pass, msec, nullptr, + pbe_params.first, pbe_params.second, rng); + + std::vector output; + DER_Encoder der(output); + der.start_cons(SEQUENCE) + .encode(pbe_info.first) + .encode(pbe_info.second, OCTET_STRING) + .end_cons(); + + return output; +#else + BOTAN_UNUSED(key, rng, pass, msec, pbe_algo); + throw Encoding_Error("PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build"); +#endif + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec, + const std::string& pbe_algo) + { + if(pass.empty()) + return PEM_encode(key); + + return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo), + "ENCRYPTED PRIVATE KEY"); + } + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector BER_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { +#if defined(BOTAN_HAS_PKCS5_PBES2) + const std::pair> pbe_info = + pbes2_encrypt_iter(key.private_key_info(), + pass, pbkdf_iterations, + cipher.empty() ? "AES-256/CBC" : cipher, + pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash, + rng); + + std::vector output; + DER_Encoder der(output); + der.start_cons(SEQUENCE) + .encode(pbe_info.first) + .encode(pbe_info.second, OCTET_STRING) + .end_cons(); + + return output; + +#else + BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash); + throw Encoding_Error("PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build"); +#endif + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { + return PEM_Code::encode( + PKCS8::BER_encode_encrypted_pbkdf_iter(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash), + "ENCRYPTED PRIVATE KEY"); + } + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector BER_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { +#if defined(BOTAN_HAS_PKCS5_PBES2) + const std::pair> pbe_info = + pbes2_encrypt_msec(key.private_key_info(), pass, + pbkdf_msec, pbkdf_iterations, + cipher.empty() ? "AES-256/CBC" : cipher, + pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash, + rng); + + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode(pbe_info.first) + .encode(pbe_info.second, OCTET_STRING) + .end_cons(); + + return output; +#else + BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash); + throw Encoding_Error("BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build"); +#endif + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { + return PEM_Code::encode( + PKCS8::BER_encode_encrypted_pbkdf_msec(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash), + "ENCRYPTED PRIVATE KEY"); + } + +namespace { + +/* +* Extract a private key (encrypted/unencrypted) and return it +*/ +std::unique_ptr +load_key(DataSource& source, + std::function get_pass, + bool is_encrypted) + { + AlgorithmIdentifier alg_id; + secure_vector pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted); + + const std::string alg_name = OIDS::oid2str_or_empty(alg_id.get_oid()); + if(alg_name.empty()) + throw PKCS8_Exception("Unknown algorithm OID: " + + alg_id.get_oid().to_string()); + + return load_private_key(alg_id, pkcs8_key); + } + +} + +/* +* Extract an encrypted private key and return it +*/ +std::unique_ptr load_key(DataSource& source, + std::function get_pass) + { + return load_key(source, get_pass, true); + } + +/* +* Extract an encrypted private key and return it +*/ +std::unique_ptr load_key(DataSource& source, + const std::string& pass) + { + // We need to use bind rather than a lambda capturing `pass` here in order to avoid a Clang 8 bug. + // See https://github.com/randombit/botan/issues/2255. + return load_key(source, std::bind([](const std::string p) { return p; }, pass), true); + } + +/* +* Extract an unencrypted private key and return it +*/ +std::unique_ptr load_key(DataSource& source) + { + auto fail_fn = []() -> std::string { + throw PKCS8_Exception("Internal error: Attempt to read password for unencrypted key"); + }; + + return load_key(source, fail_fn, false); + } + +/* +* Make a copy of this private key +*/ +std::unique_ptr copy_key(const Private_Key& key) + { + DataSource_Memory source(PEM_encode(key)); + return PKCS8::load_key(source); + } + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + std::function get_pass) + { + BOTAN_UNUSED(rng); + return PKCS8::load_key(source, get_pass).release(); + } + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass) + { + BOTAN_UNUSED(rng); + return PKCS8::load_key(source, pass).release(); + } + +/* +* Extract an unencrypted private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng) + { + BOTAN_UNUSED(rng); + return PKCS8::load_key(source).release(); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + std::function get_pass) + { + BOTAN_UNUSED(rng); + DataSource_Stream in(fsname); + return PKCS8::load_key(in, get_pass).release(); + } + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const std::string& pass) + { + BOTAN_UNUSED(rng); + DataSource_Stream in(fsname); + // We need to use bind rather than a lambda capturing `pass` here in order to avoid a Clang 8 bug. + // See https://github.com/randombit/botan/issues/2255. + return PKCS8::load_key(in, std::bind([](const std::string p) { return p; }, pass)).release(); + } + +/* +* Extract an unencrypted private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng) + { + BOTAN_UNUSED(rng); + DataSource_Stream in(fsname); + return PKCS8::load_key(in).release(); + } +#endif + +/* +* Make a copy of this private key +*/ +Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng) + { + BOTAN_UNUSED(rng); + return PKCS8::copy_key(key).release(); + } + + + +} + +} diff --git a/comm/third_party/botan/src/lib/pubkey/pkcs8.h b/comm/third_party/botan/src/lib/pubkey/pkcs8.h new file mode 100644 index 0000000000..a243c4fda4 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pkcs8.h @@ -0,0 +1,288 @@ +/* +* PKCS #8 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PKCS8_H_ +#define BOTAN_PKCS8_H_ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class DataSource; +class RandomNumberGenerator; + +/** +* PKCS #8 General Exception +*/ +class BOTAN_PUBLIC_API(2,0) PKCS8_Exception final : public Decoding_Error + { + public: + explicit PKCS8_Exception(const std::string& error) : + Decoding_Error("PKCS #8: " + error) {} + }; + +/** +* This namespace contains functions for handling PKCS #8 private keys +*/ +namespace PKCS8 { + +/** +* BER encode a private key +* @param key the private key to encode +* @return BER encoded key +*/ +BOTAN_PUBLIC_API(2,0) secure_vector BER_encode(const Private_Key& key); + +/** +* Get a string containing a PEM encoded private key. +* @param key the key to encode +* @return encoded key +*/ +BOTAN_PUBLIC_API(2,0) std::string PEM_encode(const Private_Key& key); + +/** +* Encrypt a key using PKCS #8 encryption +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param msec number of milliseconds to run the password derivation +* @param pbe_algo the name of the desired password-based encryption +* algorithm; if empty ("") a reasonable (portable/secure) +* default will be chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_PUBLIC_API(2,0) std::vector +BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec = std::chrono::milliseconds(300), + const std::string& pbe_algo = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param msec number of milliseconds to run the password derivation +* @param pbe_algo the name of the desired password-based encryption +* algorithm; if empty ("") a reasonable (portable/secure) +* default will be chosen. +* @return encrypted key in PEM form +*/ +BOTAN_PUBLIC_API(2,0) std::string +PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec = std::chrono::milliseconds(300), + const std::string& pbe_algo = ""); + +/** +* Encrypt a key using PKCS #8 encryption and a fixed iteration count +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_iter number of interations to run PBKDF2 +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_PUBLIC_API(2,1) std::vector +BER_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iter, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_iter number of iterations to run PBKDF +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in PEM form +*/ +BOTAN_PUBLIC_API(2,1) std::string +PEM_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iter, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Encrypt a key using PKCS #8 encryption and a variable iteration count +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_msec how long to run PBKDF2 +* @param pbkdf_iterations if non-null, set to the number of iterations used +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_PUBLIC_API(2,1) std::vector +BER_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_msec how long in milliseconds to run PBKDF2 +* @param pbkdf_iterations (output argument) number of iterations of PBKDF +* that ended up being used +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in PEM form +*/ +BOTAN_PUBLIC_API(2,1) std::string +PEM_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param rng ignored for compatibility +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + std::function get_passphrase); + +/** Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param rng ignored for compatibility +* @param pass the passphrase to decrypt the key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass); + +/** Load an unencrypted key from a data source. +* @param source the data source providing the encoded key +* @param rng ignored for compatibility +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +/** +* Load an encrypted key from a file. +* @param filename the path to the file containing the encoded key +* @param rng ignored for compatibility +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + std::function get_passphrase); + +/** Load an encrypted key from a file. +* @param filename the path to the file containing the encoded key +* @param rng ignored for compatibility +* @param pass the passphrase to decrypt the key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const std::string& pass); + +/** Load an unencrypted key from a file. +* @param filename the path to the file containing the encoded key +* @param rng ignored for compatibility +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng); +#endif + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @param rng ignored for compatibility +* @return new copy of the key +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng); + + +/** +* Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr load_key(DataSource& source, + std::function get_passphrase); + +/** Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param pass the passphrase to decrypt the key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr load_key(DataSource& source, + const std::string& pass); + +/** Load an unencrypted key from a data source. +* @param source the data source providing the encoded key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr load_key(DataSource& source); + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @return new copy of the key +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr copy_key(const Private_Key& key); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/pubkey.cpp b/comm/third_party/botan/src/lib/pubkey/pubkey.cpp new file mode 100644 index 0000000000..3834489ef8 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pubkey.cpp @@ -0,0 +1,388 @@ +/* +* (C) 1999-2010,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +secure_vector PK_Decryptor::decrypt(const uint8_t in[], size_t length) const + { + uint8_t valid_mask = 0; + + secure_vector decoded = do_decrypt(valid_mask, in, length); + + if(valid_mask == 0) + throw Decoding_Error("Invalid public key ciphertext, cannot decrypt"); + + return decoded; + } + +secure_vector +PK_Decryptor::decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng, + const uint8_t required_content_bytes[], + const uint8_t required_content_offsets[], + size_t required_contents_length) const + { + const secure_vector fake_pms = rng.random_vec(expected_pt_len); + + uint8_t decrypt_valid = 0; + secure_vector decoded = do_decrypt(decrypt_valid, in, length); + + auto valid_mask = CT::Mask::is_equal(decrypt_valid, 0xFF); + valid_mask &= CT::Mask(CT::Mask::is_zero(decoded.size() ^ expected_pt_len)); + + decoded.resize(expected_pt_len); + + for(size_t i = 0; i != required_contents_length; ++i) + { + /* + These values are chosen by the application and for TLS are constants, + so this early failure via assert is fine since we know 0,1 < 48 + + If there is a protocol that has content checks on the key where + the expected offsets are controllable by the attacker this could + still leak. + + Alternately could always reduce the offset modulo the length? + */ + + const uint8_t exp = required_content_bytes[i]; + const uint8_t off = required_content_offsets[i]; + + BOTAN_ASSERT(off < expected_pt_len, "Offset in range of plaintext"); + + auto eq = CT::Mask::is_equal(decoded[off], exp); + + valid_mask &= eq; + } + + // If valid_mask is false, assign fake pre master instead + valid_mask.select_n(decoded.data(), decoded.data(), fake_pms.data(), expected_pt_len); + + return decoded; + } + +secure_vector +PK_Decryptor::decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng) const + { + return decrypt_or_random(in, length, expected_pt_len, rng, + nullptr, nullptr, 0); + } + +PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& padding, + const std::string& provider) + { + m_op = key.create_encryption_op(rng, padding, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support encryption"); + } + +PK_Encryptor_EME::~PK_Encryptor_EME() { /* for unique_ptr */ } + +size_t PK_Encryptor_EME::ciphertext_length(size_t ptext_len) const + { + return m_op->ciphertext_length(ptext_len); + } + +std::vector +PK_Encryptor_EME::enc(const uint8_t in[], size_t length, RandomNumberGenerator& rng) const + { + return unlock(m_op->encrypt(in, length, rng)); + } + +size_t PK_Encryptor_EME::maximum_input_size() const + { + return m_op->max_input_bits() / 8; + } + +PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& padding, + const std::string& provider) + { + m_op = key.create_decryption_op(rng, padding, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support decryption"); + } + +PK_Decryptor_EME::~PK_Decryptor_EME() { /* for unique_ptr */ } + +size_t PK_Decryptor_EME::plaintext_length(size_t ctext_len) const + { + return m_op->plaintext_length(ctext_len); + } + +secure_vector PK_Decryptor_EME::do_decrypt(uint8_t& valid_mask, + const uint8_t in[], size_t in_len) const + { + return m_op->decrypt(valid_mask, in, in_len); + } + +PK_KEM_Encryptor::PK_KEM_Encryptor(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& param, + const std::string& provider) + { + m_op = key.create_kem_encryption_op(rng, param, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support KEM encryption"); + } + +PK_KEM_Encryptor::~PK_KEM_Encryptor() { /* for unique_ptr */ } + +void PK_KEM_Encryptor::encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) + { + m_op->kem_encrypt(out_encapsulated_key, + out_shared_key, + desired_shared_key_len, + rng, + salt, + salt_len); + } + +PK_KEM_Decryptor::PK_KEM_Decryptor(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& param, + const std::string& provider) + { + m_op = key.create_kem_decryption_op(rng, param, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support KEM decryption"); + } + +PK_KEM_Decryptor::~PK_KEM_Decryptor() { /* for unique_ptr */ } + +secure_vector PK_KEM_Decryptor::decrypt(const uint8_t encap_key[], + size_t encap_key_len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) + { + return m_op->kem_decrypt(encap_key, encap_key_len, + desired_shared_key_len, + salt, salt_len); + } + +PK_Key_Agreement::PK_Key_Agreement(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& kdf, + const std::string& provider) + { + m_op = key.create_key_agreement_op(rng, kdf, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support key agreement"); + } + +PK_Key_Agreement::~PK_Key_Agreement() { /* for unique_ptr */ } + +PK_Key_Agreement& PK_Key_Agreement::operator=(PK_Key_Agreement&& other) + { + if(this != &other) + { + m_op = std::move(other.m_op); + } + return (*this); + } + +PK_Key_Agreement::PK_Key_Agreement(PK_Key_Agreement&& other) : + m_op(std::move(other.m_op)) + {} + +size_t PK_Key_Agreement::agreed_value_size() const + { + return m_op->agreed_value_size(); + } + +SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, + const uint8_t in[], size_t in_len, + const uint8_t salt[], + size_t salt_len) const + { + return m_op->agree(key_len, in, in_len, salt, salt_len); + } + +static void check_der_format_supported(Signature_Format format, size_t parts) + { + if(format != IEEE_1363 && parts == 1) + throw Invalid_Argument("PK: This algorithm does not support DER encoding"); + } + +PK_Signer::PK_Signer(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format, + const std::string& provider) + { + m_op = key.create_signature_op(rng, emsa, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support signature generation"); + m_sig_format = format; + m_parts = key.message_parts(); + m_part_size = key.message_part_size(); + check_der_format_supported(format, m_parts); + } + +PK_Signer::~PK_Signer() { /* for unique_ptr */ } + +void PK_Signer::update(const uint8_t in[], size_t length) + { + m_op->update(in, length); + } + +namespace { + +std::vector der_encode_signature(const std::vector& sig, + size_t parts, + size_t part_size) + { + if(sig.size() % parts != 0 || sig.size() != parts * part_size) + throw Encoding_Error("Unexpected size for DER signature"); + + std::vector sig_parts(parts); + for(size_t i = 0; i != sig_parts.size(); ++i) + sig_parts[i].binary_decode(&sig[part_size*i], part_size); + + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_list(sig_parts) + .end_cons(); + return output; + } + +} + +size_t PK_Signer::signature_length() const + { + if(m_sig_format == IEEE_1363) + { + return m_op->signature_length(); + } + else if(m_sig_format == DER_SEQUENCE) + { + // This is a large over-estimate but its easier than computing + // the exact value + return m_op->signature_length() + (8 + 4*m_parts); + } + else + throw Internal_Error("PK_Signer: Invalid signature format enum"); + } + +std::vector PK_Signer::signature(RandomNumberGenerator& rng) + { + const std::vector sig = unlock(m_op->sign(rng)); + + if(m_sig_format == IEEE_1363) + { + return sig; + } + else if(m_sig_format == DER_SEQUENCE) + { + return der_encode_signature(sig, m_parts, m_part_size); + } + else + throw Internal_Error("PK_Signer: Invalid signature format enum"); + } + +PK_Verifier::PK_Verifier(const Public_Key& key, + const std::string& emsa, + Signature_Format format, + const std::string& provider) + { + m_op = key.create_verification_op(emsa, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support signature verification"); + m_sig_format = format; + m_parts = key.message_parts(); + m_part_size = key.message_part_size(); + check_der_format_supported(format, m_parts); + } + +PK_Verifier::~PK_Verifier() { /* for unique_ptr */ } + +void PK_Verifier::set_input_format(Signature_Format format) + { + check_der_format_supported(format, m_parts); + m_sig_format = format; + } + +bool PK_Verifier::verify_message(const uint8_t msg[], size_t msg_length, + const uint8_t sig[], size_t sig_length) + { + update(msg, msg_length); + return check_signature(sig, sig_length); + } + +void PK_Verifier::update(const uint8_t in[], size_t length) + { + m_op->update(in, length); + } + +bool PK_Verifier::check_signature(const uint8_t sig[], size_t length) + { + try { + if(m_sig_format == IEEE_1363) + { + return m_op->is_valid_signature(sig, length); + } + else if(m_sig_format == DER_SEQUENCE) + { + std::vector real_sig; + BER_Decoder decoder(sig, length); + BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); + + BOTAN_ASSERT_NOMSG(m_parts != 0 && m_part_size != 0); + + size_t count = 0; + + while(ber_sig.more_items()) + { + BigInt sig_part; + ber_sig.decode(sig_part); + real_sig += BigInt::encode_1363(sig_part, m_part_size); + ++count; + } + + if(count != m_parts) + throw Decoding_Error("PK_Verifier: signature size invalid"); + + const std::vector reencoded = + der_encode_signature(real_sig, m_parts, m_part_size); + + if(reencoded.size() != length || + same_mem(reencoded.data(), sig, reencoded.size()) == false) + { + throw Decoding_Error("PK_Verifier: signature is not the canonical DER encoding"); + } + + return m_op->is_valid_signature(real_sig.data(), real_sig.size()); + } + else + throw Internal_Error("PK_Verifier: Invalid signature format enum"); + } + catch(Invalid_Argument&) { return false; } + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/pubkey.h b/comm/third_party/botan/src/lib/pubkey/pubkey.h new file mode 100644 index 0000000000..2aa8ea9164 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/pubkey.h @@ -0,0 +1,800 @@ +/* +* Public Key Interface +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PUBKEY_H_ +#define BOTAN_PUBKEY_H_ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include + #define BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS +#endif + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Public Key Encryptor +* This is the primary interface for public key encryption +*/ +class BOTAN_PUBLIC_API(2,0) PK_Encryptor + { + public: + + /** + * Encrypt a message. + * @param in the message as a byte array + * @param length the length of the above byte array + * @param rng the random number source to use + * @return encrypted message + */ + std::vector encrypt(const uint8_t in[], size_t length, + RandomNumberGenerator& rng) const + { + return enc(in, length, rng); + } + + /** + * Encrypt a message. + * @param in the message + * @param rng the random number source to use + * @return encrypted message + */ + template + std::vector encrypt(const std::vector& in, + RandomNumberGenerator& rng) const + { + return enc(in.data(), in.size(), rng); + } + + /** + * Return the maximum allowed message size in bytes. + * @return maximum message size in bytes + */ + virtual size_t maximum_input_size() const = 0; + + /** + * Return an upper bound on the ciphertext length + */ + virtual size_t ciphertext_length(size_t ctext_len) const = 0; + + PK_Encryptor() = default; + virtual ~PK_Encryptor() = default; + + PK_Encryptor(const PK_Encryptor&) = delete; + PK_Encryptor& operator=(const PK_Encryptor&) = delete; + + private: + virtual std::vector enc(const uint8_t[], size_t, + RandomNumberGenerator&) const = 0; + }; + +/** +* Public Key Decryptor +*/ +class BOTAN_PUBLIC_API(2,0) PK_Decryptor + { + public: + /** + * Decrypt a ciphertext, throwing an exception if the input + * seems to be invalid (eg due to an accidental or malicious + * error in the ciphertext). + * + * @param in the ciphertext as a byte array + * @param length the length of the above byte array + * @return decrypted message + */ + secure_vector decrypt(const uint8_t in[], size_t length) const; + + /** + * Same as above, but taking a vector + * @param in the ciphertext + * @return decrypted message + */ + template + secure_vector decrypt(const std::vector& in) const + { + return decrypt(in.data(), in.size()); + } + + /** + * Decrypt a ciphertext. If the ciphertext is invalid (eg due to + * invalid padding) or is not the expected length, instead + * returns a random string of the expected length. Use to avoid + * oracle attacks, especially against PKCS #1 v1.5 decryption. + */ + secure_vector + decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng) const; + + /** + * Decrypt a ciphertext. If the ciphertext is invalid (eg due to + * invalid padding) or is not the expected length, instead + * returns a random string of the expected length. Use to avoid + * oracle attacks, especially against PKCS #1 v1.5 decryption. + * + * Additionally checks (also in const time) that: + * contents[required_content_offsets[i]] == required_content_bytes[i] + * for 0 <= i < required_contents + * + * Used for example in TLS, which encodes the client version in + * the content bytes: if there is any timing variation the version + * check can be used as an oracle to recover the key. + */ + secure_vector + decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng, + const uint8_t required_content_bytes[], + const uint8_t required_content_offsets[], + size_t required_contents) const; + + /** + * Return an upper bound on the plaintext length for a particular + * ciphertext input length + */ + virtual size_t plaintext_length(size_t ctext_len) const = 0; + + PK_Decryptor() = default; + virtual ~PK_Decryptor() = default; + + PK_Decryptor(const PK_Decryptor&) = delete; + PK_Decryptor& operator=(const PK_Decryptor&) = delete; + + private: + virtual secure_vector do_decrypt(uint8_t& valid_mask, + const uint8_t in[], size_t in_len) const = 0; + }; + +/** +* Public Key Signer. Use the sign_message() functions for small +* messages. Use multiple calls update() to process large messages and +* generate the signature by finally calling signature(). +*/ +class BOTAN_PUBLIC_API(2,0) PK_Signer final + { + public: + + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param rng the random generator to use + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + * @param format the signature format to use + * @param provider the provider to use + */ + PK_Signer(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format = IEEE_1363, + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + * @param format the signature format to use + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Signer(const Private_Key& key, + const std::string& emsa, + Signature_Format format = IEEE_1363, + const std::string& provider = "") : + PK_Signer(key, system_rng(), emsa, format, provider) + {} +#endif + + ~PK_Signer(); + + PK_Signer(const PK_Signer&) = delete; + PK_Signer& operator=(const PK_Signer&) = delete; + + /** + * Sign a message all in one go + * @param in the message to sign as a byte array + * @param length the length of the above byte array + * @param rng the rng to use + * @return signature + */ + std::vector sign_message(const uint8_t in[], size_t length, + RandomNumberGenerator& rng) + { + this->update(in, length); + return this->signature(rng); + } + + /** + * Sign a message. + * @param in the message to sign + * @param rng the rng to use + * @return signature + */ + template + std::vector sign_message(const std::vector& in, + RandomNumberGenerator& rng) + { + return sign_message(in.data(), in.size(), rng); + } + + /** + * Add a message part (single byte). + * @param in the byte to add + */ + void update(uint8_t in) { update(&in, 1); } + + /** + * Add a message part. + * @param in the message part to add as a byte array + * @param length the length of the above byte array + */ + void update(const uint8_t in[], size_t length); + + /** + * Add a message part. + * @param in the message part to add + */ + template + void update(const std::vector& in) + { + update(in.data(), in.size()); + } + + /** + * Add a message part. + * @param in the message part to add + */ + void update(const std::string& in) + { + update(cast_char_ptr_to_uint8(in.data()), in.size()); + } + + /** + * Get the signature of the so far processed message (provided by the + * calls to update()). + * @param rng the rng to use + * @return signature of the total message + */ + std::vector signature(RandomNumberGenerator& rng); + + + /** + * Set the output format of the signature. + * @param format the signature format to use + */ + void set_output_format(Signature_Format format) { m_sig_format = format; } + + /** + * Return an upper bound on the length of the signatures this + * PK_Signer will produce + */ + size_t signature_length() const; + + private: + std::unique_ptr m_op; + Signature_Format m_sig_format; + size_t m_parts, m_part_size; + }; + +/** +* Public Key Verifier. Use the verify_message() functions for small +* messages. Use multiple calls update() to process large messages and +* verify the signature by finally calling check_signature(). +*/ +class BOTAN_PUBLIC_API(2,0) PK_Verifier final + { + public: + /** + * Construct a PK Verifier. + * @param pub_key the public key to verify against + * @param emsa the EMSA to use (eg "EMSA3(SHA-1)") + * @param format the signature format to use + * @param provider the provider to use + */ + PK_Verifier(const Public_Key& pub_key, + const std::string& emsa, + Signature_Format format = IEEE_1363, + const std::string& provider = ""); + + ~PK_Verifier(); + + PK_Verifier& operator=(const PK_Verifier&) = delete; + PK_Verifier(const PK_Verifier&) = delete; + + /** + * Verify a signature. + * @param msg the message that the signature belongs to, as a byte array + * @param msg_length the length of the above byte array msg + * @param sig the signature as a byte array + * @param sig_length the length of the above byte array sig + * @return true if the signature is valid + */ + bool verify_message(const uint8_t msg[], size_t msg_length, + const uint8_t sig[], size_t sig_length); + /** + * Verify a signature. + * @param msg the message that the signature belongs to + * @param sig the signature + * @return true if the signature is valid + */ + template + bool verify_message(const std::vector& msg, + const std::vector& sig) + { + return verify_message(msg.data(), msg.size(), + sig.data(), sig.size()); + } + + /** + * Add a message part (single byte) of the message corresponding to the + * signature to be verified. + * @param in the byte to add + */ + void update(uint8_t in) { update(&in, 1); } + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param msg_part the new message part as a byte array + * @param length the length of the above byte array + */ + void update(const uint8_t msg_part[], size_t length); + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param in the new message part + */ + template + void update(const std::vector& in) + { + update(in.data(), in.size()); + } + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + */ + void update(const std::string& in) + { + update(cast_char_ptr_to_uint8(in.data()), in.size()); + } + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified as a byte array + * @param length the length of the above byte array + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const uint8_t sig[], size_t length); + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified + * @return true if the signature is valid, false otherwise + */ + template + bool check_signature(const std::vector& sig) + { + return check_signature(sig.data(), sig.size()); + } + + /** + * Set the format of the signatures fed to this verifier. + * @param format the signature format to use + */ + void set_input_format(Signature_Format format); + + private: + std::unique_ptr m_op; + Signature_Format m_sig_format; + size_t m_parts, m_part_size; + }; + +/** +* Object used for key agreement +*/ +class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final + { + public: + + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param rng the random generator to use + * @param kdf name of the KDF to use (or 'Raw' for no KDF) + * @param provider the algo provider to use (or empty for default) + */ + PK_Key_Agreement(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& kdf, + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param kdf name of the KDF to use (or 'Raw' for no KDF) + * @param provider the algo provider to use (or empty for default) + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Key_Agreement(const Private_Key& key, + const std::string& kdf, + const std::string& provider = "") : + PK_Key_Agreement(key, system_rng(), kdf, provider) + {} +#endif + + ~PK_Key_Agreement(); + + // For ECIES + PK_Key_Agreement& operator=(PK_Key_Agreement&&); + PK_Key_Agreement(PK_Key_Agreement&&); + + PK_Key_Agreement& operator=(const PK_Key_Agreement&) = delete; + PK_Key_Agreement(const PK_Key_Agreement&) = delete; + + /** + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const uint8_t in[], + size_t in_len, + const uint8_t params[], + size_t params_len) const; + + /** + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const std::vector& in, + const uint8_t params[], + size_t params_len) const + { + return derive_key(key_len, in.data(), in.size(), + params, params_len); + } + + /** + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const uint8_t in[], size_t in_len, + const std::string& params = "") const + { + return derive_key(key_len, in, in_len, + cast_char_ptr_to_uint8(params.data()), + params.length()); + } + + /** + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const std::vector& in, + const std::string& params = "") const + { + return derive_key(key_len, in.data(), in.size(), + cast_char_ptr_to_uint8(params.data()), + params.length()); + } + + /** + * Return the underlying size of the value that is agreed. + * If derive_key is called with a length of 0 with a "Raw" + * KDF, it will return a value of this size. + */ + size_t agreed_value_size() const; + + private: + std::unique_ptr m_op; + }; + +/** +* Encryption using a standard message recovery algorithm like RSA or +* ElGamal, paired with an encoding scheme like OAEP. +*/ +class BOTAN_PUBLIC_API(2,0) PK_Encryptor_EME final : public PK_Encryptor + { + public: + size_t maximum_input_size() const override; + + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param rng the RNG to use + * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") + * @param provider the provider to use + */ + PK_Encryptor_EME(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& padding, + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Encryptor_EME(const Public_Key& key, + const std::string& padding, + const std::string& provider = "") : + PK_Encryptor_EME(key, system_rng(), padding, provider) {} +#endif + + ~PK_Encryptor_EME(); + + PK_Encryptor_EME& operator=(const PK_Encryptor_EME&) = delete; + PK_Encryptor_EME(const PK_Encryptor_EME&) = delete; + + /** + * Return an upper bound on the ciphertext length for a particular + * plaintext input length + */ + size_t ciphertext_length(size_t ptext_len) const override; + private: + std::vector enc(const uint8_t[], size_t, + RandomNumberGenerator& rng) const override; + + std::unique_ptr m_op; + }; + +/** +* Decryption with an MR algorithm and an EME. +*/ +class BOTAN_PUBLIC_API(2,0) PK_Decryptor_EME final : public PK_Decryptor + { + public: + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param rng the random generator to use + * @param eme the EME to use + * @param provider the provider to use + */ + PK_Decryptor_EME(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& eme, + const std::string& provider = ""); + + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param eme the message encoding scheme to use (eg "OAEP(SHA-256)") + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Decryptor_EME(const Private_Key& key, + const std::string& eme, + const std::string& provider = "") : + PK_Decryptor_EME(key, system_rng(), eme, provider) {} +#endif + + size_t plaintext_length(size_t ptext_len) const override; + + ~PK_Decryptor_EME(); + PK_Decryptor_EME& operator=(const PK_Decryptor_EME&) = delete; + PK_Decryptor_EME(const PK_Decryptor_EME&) = delete; + private: + secure_vector do_decrypt(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const override; + + std::unique_ptr m_op; + }; + +/** +* Public Key Key Encapsulation Mechanism Encryption. +*/ +class BOTAN_PUBLIC_API(2,0) PK_KEM_Encryptor final + { + public: + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param rng the RNG to use + * @param kem_param additional KEM parameters + * @param provider the provider to use + */ + PK_KEM_Encryptor(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& kem_param = "", + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_KEM_Encryptor(const Public_Key& key, + const std::string& kem_param = "", + const std::string& provider = "") : + PK_KEM_Encryptor(key, system_rng(), kem_param, provider) {} +#endif + + ~PK_KEM_Encryptor(); + + PK_KEM_Encryptor& operator=(const PK_KEM_Encryptor&) = delete; + PK_KEM_Encryptor(const PK_KEM_Encryptor&) = delete; + + /** + * Generate a shared key for data encryption. + * @param out_encapsulated_key the generated encapsulated key + * @param out_shared_key the generated shared key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param rng the RNG to use + * @param salt a salt value used in the KDF + * @param salt_len size of the salt value in bytes + */ + void encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len); + + /** + * Generate a shared key for data encryption. + * @param out_encapsulated_key the generated encapsulated key + * @param out_shared_key the generated shared key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param rng the RNG to use + * @param salt a salt value used in the KDF + */ + template + void encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const std::vector& salt) + { + this->encrypt(out_encapsulated_key, + out_shared_key, + desired_shared_key_len, + rng, + salt.data(), salt.size()); + } + + + /** + * Generate a shared key for data encryption. + * @param out_encapsulated_key the generated encapsulated key + * @param out_shared_key the generated shared key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param rng the RNG to use + */ + void encrypt(secure_vector& out_encapsulated_key, + secure_vector& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng) + { + this->encrypt(out_encapsulated_key, + out_shared_key, + desired_shared_key_len, + rng, + nullptr, + 0); + } + + private: + std::unique_ptr m_op; + }; + +/** +* Public Key Key Encapsulation Mechanism Decryption. +*/ +class BOTAN_PUBLIC_API(2,0) PK_KEM_Decryptor final + { + public: + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param rng the RNG to use + * @param kem_param additional KEM parameters + * @param provider the provider to use + */ + PK_KEM_Decryptor(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& kem_param = "", + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_KEM_Decryptor(const Private_Key& key, + const std::string& kem_param = "", + const std::string& provider = "") : + PK_KEM_Decryptor(key, system_rng(), kem_param, provider) + {} +#endif + + ~PK_KEM_Decryptor(); + PK_KEM_Decryptor& operator=(const PK_KEM_Decryptor&) = delete; + PK_KEM_Decryptor(const PK_KEM_Decryptor&) = delete; + + /** + * Decrypts the shared key for data encryption. + * @param encap_key the encapsulated key + * @param encap_key_len size of the encapsulated key in bytes + * @param desired_shared_key_len desired size of the shared key in bytes + * @param salt a salt value used in the KDF + * @param salt_len size of the salt value in bytes + * @return the shared data encryption key + */ + secure_vector decrypt(const uint8_t encap_key[], + size_t encap_key_len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len); + + /** + * Decrypts the shared key for data encryption. + * @param encap_key the encapsulated key + * @param encap_key_len size of the encapsulated key in bytes + * @param desired_shared_key_len desired size of the shared key in bytes + * @return the shared data encryption key + */ + secure_vector decrypt(const uint8_t encap_key[], + size_t encap_key_len, + size_t desired_shared_key_len) + { + return this->decrypt(encap_key, encap_key_len, + desired_shared_key_len, + nullptr, 0); + } + + /** + * Decrypts the shared key for data encryption. + * @param encap_key the encapsulated key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param salt a salt value used in the KDF + * @return the shared data encryption key + */ + template + secure_vector decrypt(const std::vector& encap_key, + size_t desired_shared_key_len, + const std::vector& salt) + { + return this->decrypt(encap_key.data(), encap_key.size(), + desired_shared_key_len, + salt.data(), salt.size()); + } + + private: + std::unique_ptr m_op; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/rfc6979/info.txt b/comm/third_party/botan/src/lib/pubkey/rfc6979/info.txt new file mode 100644 index 0000000000..72a61301c5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/rfc6979/info.txt @@ -0,0 +1,8 @@ + +RFC6979_GENERATOR -> 20140321 + + + +bigint +hmac_drbg + diff --git a/comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.cpp b/comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.cpp new file mode 100644 index 0000000000..94b313c3a2 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.cpp @@ -0,0 +1,59 @@ +/* +* RFC 6979 Deterministic Nonce Generator +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +RFC6979_Nonce_Generator::RFC6979_Nonce_Generator(const std::string& hash, + const BigInt& order, + const BigInt& x) : + m_order(order), + m_qlen(m_order.bits()), + m_rlen(m_qlen / 8 + (m_qlen % 8 ? 1 : 0)), + m_rng_in(m_rlen * 2), + m_rng_out(m_rlen) + { + m_hmac_drbg.reset(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")"))); + BigInt::encode_1363(m_rng_in.data(), m_rlen, x); + } + +RFC6979_Nonce_Generator::~RFC6979_Nonce_Generator() + { + // for ~unique_ptr + } + +const BigInt& RFC6979_Nonce_Generator::nonce_for(const BigInt& m) + { + BigInt::encode_1363(&m_rng_in[m_rlen], m_rlen, m); + m_hmac_drbg->clear(); + m_hmac_drbg->initialize_with(m_rng_in.data(), m_rng_in.size()); + + do + { + m_hmac_drbg->randomize(m_rng_out.data(), m_rng_out.size()); + m_k.binary_decode(m_rng_out.data(), m_rng_out.size()); + m_k >>= (8*m_rlen - m_qlen); + } + while(m_k == 0 || m_k >= m_order); + + return m_k; + } + +BigInt generate_rfc6979_nonce(const BigInt& x, + const BigInt& q, + const BigInt& h, + const std::string& hash) + { + RFC6979_Nonce_Generator gen(hash, q, x); + BigInt k = gen.nonce_for(h); + return k; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.h b/comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.h new file mode 100644 index 0000000000..54134a682f --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/rfc6979/rfc6979.h @@ -0,0 +1,55 @@ +/* +* RFC 6979 Deterministic Nonce Generator +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RFC6979_GENERATOR_H_ +#define BOTAN_RFC6979_GENERATOR_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(rfc6979.h) + +namespace Botan { + +class HMAC_DRBG; + +class BOTAN_PUBLIC_API(2,0) RFC6979_Nonce_Generator final + { + public: + /** + * Note: keeps persistent reference to order + */ + RFC6979_Nonce_Generator(const std::string& hash, + const BigInt& order, + const BigInt& x); + + ~RFC6979_Nonce_Generator(); + + const BigInt& nonce_for(const BigInt& m); + private: + const BigInt& m_order; + BigInt m_k; + size_t m_qlen, m_rlen; + std::unique_ptr m_hmac_drbg; + secure_vector m_rng_in, m_rng_out; + }; + +/** +* @param x the secret (EC)DSA key +* @param q the group order +* @param h the message hash already reduced mod q +* @param hash the hash function used to generate h +*/ +BigInt BOTAN_PUBLIC_API(2,0) generate_rfc6979_nonce(const BigInt& x, + const BigInt& q, + const BigInt& h, + const std::string& hash); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/rsa/info.txt b/comm/third_party/botan/src/lib/pubkey/rsa/info.txt new file mode 100644 index 0000000000..9fc9354b83 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/rsa/info.txt @@ -0,0 +1,10 @@ + +RSA -> 20160730 + + + +keypair +numbertheory +emsa_pssr +sha2_32 + diff --git a/comm/third_party/botan/src/lib/pubkey/rsa/rsa.cpp b/comm/third_party/botan/src/lib/pubkey/rsa/rsa.cpp new file mode 100644 index 0000000000..96f405892a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/rsa/rsa.cpp @@ -0,0 +1,753 @@ +/* +* RSA +* (C) 1999-2010,2015,2016,2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +#if defined(BOTAN_HAS_THREAD_UTILS) + #include +#endif + +namespace Botan { + +class RSA_Public_Data final + { + public: + RSA_Public_Data(BigInt&& n, BigInt&& e) : + m_n(n), + m_e(e), + m_monty_n(std::make_shared(m_n)), + m_public_modulus_bits(m_n.bits()), + m_public_modulus_bytes(m_n.bytes()) + {} + + BigInt public_op(const BigInt& m) const + { + const size_t powm_window = 1; + auto powm_m_n = monty_precompute(m_monty_n, m, powm_window, false); + return monty_execute_vartime(*powm_m_n, m_e); + } + + const BigInt& get_n() const { return m_n; } + const BigInt& get_e() const { return m_e; } + size_t public_modulus_bits() const { return m_public_modulus_bits; } + size_t public_modulus_bytes() const { return m_public_modulus_bytes; } + + private: + BigInt m_n; + BigInt m_e; + std::shared_ptr m_monty_n; + size_t m_public_modulus_bits; + size_t m_public_modulus_bytes; + }; + +class RSA_Private_Data final + { + public: + RSA_Private_Data(BigInt&& d, BigInt&& p, BigInt&& q, + BigInt&& d1, BigInt&& d2, BigInt&& c) : + m_d(d), + m_p(p), + m_q(q), + m_d1(d1), + m_d2(d2), + m_c(c), + m_mod_p(m_p), + m_mod_q(m_q), + m_monty_p(std::make_shared(m_p, m_mod_p)), + m_monty_q(std::make_shared(m_q, m_mod_q)), + m_p_bits(m_p.bits()), + m_q_bits(m_q.bits()) + {} + + const BigInt& get_d() const { return m_d; } + const BigInt& get_p() const { return m_p; } + const BigInt& get_q() const { return m_q; } + const BigInt& get_d1() const { return m_d1; } + const BigInt& get_d2() const { return m_d2; } + const BigInt& get_c() const { return m_c; } + + //private: + BigInt m_d; + BigInt m_p; + BigInt m_q; + BigInt m_d1; + BigInt m_d2; + BigInt m_c; + + Modular_Reducer m_mod_p; + Modular_Reducer m_mod_q; + std::shared_ptr m_monty_p; + std::shared_ptr m_monty_q; + size_t m_p_bits; + size_t m_q_bits; + }; + +std::shared_ptr RSA_PublicKey::public_data() const + { + return m_public; + } + +const BigInt& RSA_PublicKey::get_n() const { return m_public->get_n(); } +const BigInt& RSA_PublicKey::get_e() const { return m_public->get_e(); } + +void RSA_PublicKey::init(BigInt&& n, BigInt&& e) + { + if(n.is_negative() || n.is_even() || e.is_negative() || e.is_even()) + throw Decoding_Error("Invalid RSA public key parameters"); + m_public = std::make_shared(std::move(n), std::move(e)); + } + +RSA_PublicKey::RSA_PublicKey(const AlgorithmIdentifier&, + const std::vector& key_bits) + { + BigInt n, e; + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode(n) + .decode(e) + .end_cons(); + + init(std::move(n), std::move(e)); + } + +RSA_PublicKey::RSA_PublicKey(const BigInt& modulus, const BigInt& exponent) + { + BigInt n = modulus; + BigInt e = exponent; + init(std::move(n), std::move(e)); + } + +size_t RSA_PublicKey::key_length() const + { + return m_public->public_modulus_bits(); + } + +size_t RSA_PublicKey::estimated_strength() const + { + return if_work_factor(key_length()); + } + +AlgorithmIdentifier RSA_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_NULL_PARAM); + } + +std::vector RSA_PublicKey::public_key_bits() const + { + std::vector output; + DER_Encoder der(output); + der.start_cons(SEQUENCE) + .encode(get_n()) + .encode(get_e()) + .end_cons(); + + return output; + } + +/* +* Check RSA Public Parameters +*/ +bool RSA_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + if(get_n() < 35 || get_n().is_even() || get_e() < 3 || get_e().is_even()) + return false; + return true; + } + +std::shared_ptr RSA_PrivateKey::private_data() const + { + return m_private; + } + +secure_vector RSA_PrivateKey::private_key_bits() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(0)) + .encode(get_n()) + .encode(get_e()) + .encode(get_d()) + .encode(get_p()) + .encode(get_q()) + .encode(get_d1()) + .encode(get_d2()) + .encode(get_c()) + .end_cons() + .get_contents(); + } + +const BigInt& RSA_PrivateKey::get_p() const { return m_private->get_p(); } +const BigInt& RSA_PrivateKey::get_q() const { return m_private->get_q(); } +const BigInt& RSA_PrivateKey::get_d() const { return m_private->get_d(); } +const BigInt& RSA_PrivateKey::get_c() const { return m_private->get_c(); } +const BigInt& RSA_PrivateKey::get_d1() const { return m_private->get_d1(); } +const BigInt& RSA_PrivateKey::get_d2() const { return m_private->get_d2(); } + +void RSA_PrivateKey::init(BigInt&& d, BigInt&& p, BigInt&& q, + BigInt&& d1, BigInt&& d2, BigInt&& c) + { + m_private = std::make_shared( + std::move(d), std::move(p), std::move(q), std::move(d1), std::move(d2), std::move(c)); + } + +RSA_PrivateKey::RSA_PrivateKey(const AlgorithmIdentifier&, + const secure_vector& key_bits) + { + BigInt n, e, d, p, q, d1, d2, c; + + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check(0, "Unknown PKCS #1 key format version") + .decode(n) + .decode(e) + .decode(d) + .decode(p) + .decode(q) + .decode(d1) + .decode(d2) + .decode(c) + .end_cons(); + + RSA_PublicKey::init(std::move(n), std::move(e)); + + RSA_PrivateKey::init(std::move(d), std::move(p), std::move(q), + std::move(d1), std::move(d2), std::move(c)); + } + +RSA_PrivateKey::RSA_PrivateKey(const BigInt& prime1, + const BigInt& prime2, + const BigInt& exp, + const BigInt& d_exp, + const BigInt& mod) + { + BigInt p = prime1; + BigInt q = prime2; + BigInt n = mod; + if(n.is_zero()) + n = p * q; + + BigInt e = exp; + + BigInt d = d_exp; + + const BigInt p_minus_1 = p - 1; + const BigInt q_minus_1 = q - 1; + + if(d.is_zero()) + { + const BigInt phi_n = lcm(p_minus_1, q_minus_1); + d = inverse_mod(e, phi_n); + } + + BigInt d1 = ct_modulo(d, p_minus_1); + BigInt d2 = ct_modulo(d, q_minus_1); + BigInt c = inverse_mod(q, p); + + RSA_PublicKey::init(std::move(n), std::move(e)); + + RSA_PrivateKey::init(std::move(d), std::move(p), std::move(q), + std::move(d1), std::move(d2), std::move(c)); + } + +/* +* Create a RSA private key +*/ +RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp) + { + if(bits < 1024) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + std::to_string(bits) + " bits long"); + if(exp < 3 || exp % 2 == 0) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + BigInt n, e, d, p, q, d1, d2, c; + + e = exp; + + const size_t p_bits = (bits + 1) / 2; + const size_t q_bits = bits - p_bits; + + do + { + // TODO could generate primes in thread pool + p = generate_rsa_prime(rng, rng, p_bits, e); + q = generate_rsa_prime(rng, rng, q_bits, e); + + if(p == q) + throw Internal_Error("RNG failure during RSA key generation"); + + n = p * q; + } while(n.bits() != bits); + + const BigInt p_minus_1 = p - 1; + const BigInt q_minus_1 = q - 1; + + const BigInt phi_n = lcm(p_minus_1, q_minus_1); + d = inverse_mod(e, phi_n); + d1 = ct_modulo(d, p_minus_1); + d2 = ct_modulo(d, q_minus_1); + c = inverse_mod(q, p); + + RSA_PublicKey::init(std::move(n), std::move(e)); + + RSA_PrivateKey::init(std::move(d), std::move(p), std::move(q), + std::move(d1), std::move(d2), std::move(c)); + } + +/* +* Check Private RSA Parameters +*/ +bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(get_n() < 35 || get_n().is_even() || get_e() < 3 || get_e().is_even()) + return false; + + if(get_d() < 2 || get_p() < 3 || get_q() < 3) + return false; + + if(get_p() * get_q() != get_n()) + return false; + + if(get_p() == get_q()) + return false; + + if(get_d1() != ct_modulo(get_d(), get_p() - 1)) + return false; + if(get_d2() != ct_modulo(get_d(), get_q() - 1)) + return false; + if(get_c() != inverse_mod(get_q(), get_p())) + return false; + + const size_t prob = (strong) ? 128 : 12; + + if(!is_prime(get_p(), rng, prob)) + return false; + if(!is_prime(get_q(), rng, prob)) + return false; + + if(strong) + { + if(ct_modulo(get_e() * get_d(), lcm(get_p() - 1, get_q() - 1)) != 1) + return false; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-256)"); + } + + return true; + } + +namespace { + +/** +* RSA private (decrypt/sign) operation +*/ +class RSA_Private_Operation + { + protected: + size_t public_modulus_bits() const { return m_public->public_modulus_bits(); } + size_t public_modulus_bytes() const { return m_public->public_modulus_bytes(); } + + explicit RSA_Private_Operation(const RSA_PrivateKey& rsa, RandomNumberGenerator& rng) : + m_public(rsa.public_data()), + m_private(rsa.private_data()), + m_blinder(m_public->get_n(), rng, + [this](const BigInt& k) { return m_public->public_op(k); }, + [this](const BigInt& k) { return inverse_mod(k, m_public->get_n()); }), + m_blinding_bits(64), + m_max_d1_bits(m_private->m_p_bits + m_blinding_bits), + m_max_d2_bits(m_private->m_q_bits + m_blinding_bits) + { + } + + secure_vector raw_op(const uint8_t input[], size_t input_len) + { + const BigInt input_bn(input, input_len); + if(input_bn >= m_public->get_n()) + throw Invalid_Argument("RSA private op - input is too large"); + + // TODO: This should be a function on blinder + // BigInt Blinder::run_blinded_function(std::function fn, const BigInt& input); + + const BigInt recovered = m_blinder.unblind(rsa_private_op(m_blinder.blind(input_bn))); + BOTAN_ASSERT(input_bn == m_public->public_op(recovered), "RSA consistency check"); + return BigInt::encode_1363(recovered, m_public->public_modulus_bytes()); + } + + private: + + BigInt rsa_private_op(const BigInt& m) const + { + /* + TODO + Consider using Montgomery reduction instead of Barrett, using + the "Smooth RSA-CRT" method. https://eprint.iacr.org/2007/039.pdf + */ + + static constexpr size_t powm_window = 4; + + // Compute this in main thread to avoid racing on the rng + const BigInt d1_mask(m_blinder.rng(), m_blinding_bits); + +#if defined(BOTAN_HAS_THREAD_UTILS) && !defined(BOTAN_HAS_VALGRIND) + #define BOTAN_RSA_USE_ASYNC +#endif + +#if defined(BOTAN_RSA_USE_ASYNC) + /* + * Precompute m.sig_words in the main thread before calling async. Otherwise + * the two threads race (during Modular_Reducer::reduce) and while the output + * is correct in both threads, helgrind warns. + */ + m.sig_words(); + + auto future_j1 = Thread_Pool::global_instance().run([this, &m, &d1_mask]() { +#endif + const BigInt masked_d1 = m_private->get_d1() + (d1_mask * (m_private->get_p() - 1)); + auto powm_d1_p = monty_precompute(m_private->m_monty_p, m_private->m_mod_p.reduce(m), powm_window); + BigInt j1 = monty_execute(*powm_d1_p, masked_d1, m_max_d1_bits); + +#if defined(BOTAN_RSA_USE_ASYNC) + return j1; + }); +#endif + + const BigInt d2_mask(m_blinder.rng(), m_blinding_bits); + const BigInt masked_d2 = m_private->get_d2() + (d2_mask * (m_private->get_q() - 1)); + auto powm_d2_q = monty_precompute(m_private->m_monty_q, m_private->m_mod_q.reduce(m), powm_window); + const BigInt j2 = monty_execute(*powm_d2_q, masked_d2, m_max_d2_bits); + +#if defined(BOTAN_RSA_USE_ASYNC) + BigInt j1 = future_j1.get(); +#endif + + /* + * To recover the final value from the CRT representation (j1,j2) + * we use Garner's algorithm: + * c = q^-1 mod p (this is precomputed) + * h = c*(j1-j2) mod p + * m = j2 + h*q + * + * We must avoid leaking if j1 >= j2 or not, as doing so allows deriving + * information about the secret prime. Do this by first adding p to j1, + * which should ensure the subtraction of j2 does not underflow. But + * this may still underflow if p and q are imbalanced in size. + */ + + j1 = m_private->m_mod_p.multiply(m_private->m_mod_p.reduce((m_private->get_p() + j1) - j2), m_private->get_c()); + return mul_add(j1, m_private->get_q(), j2); + } + + std::shared_ptr m_public; + std::shared_ptr m_private; + + // XXX could the blinder starting pair be shared? + Blinder m_blinder; + const size_t m_blinding_bits; + const size_t m_max_d1_bits; + const size_t m_max_d2_bits; + }; + +class RSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA, + private RSA_Private_Operation + { + public: + size_t max_input_bits() const override { return public_modulus_bits() - 1; } + + size_t signature_length() const override { return public_modulus_bytes(); } + + RSA_Signature_Operation(const RSA_PrivateKey& rsa, const std::string& emsa, RandomNumberGenerator& rng) : + PK_Ops::Signature_with_EMSA(emsa), + RSA_Private_Operation(rsa, rng) + { + } + + secure_vector raw_sign(const uint8_t input[], size_t input_len, + RandomNumberGenerator&) override + { + return raw_op(input, input_len); + } + }; + +class RSA_Decryption_Operation final : public PK_Ops::Decryption_with_EME, + private RSA_Private_Operation + { + public: + + RSA_Decryption_Operation(const RSA_PrivateKey& rsa, const std::string& eme, RandomNumberGenerator& rng) : + PK_Ops::Decryption_with_EME(eme), + RSA_Private_Operation(rsa, rng) + { + } + + size_t plaintext_length(size_t) const override { return public_modulus_bytes(); } + + secure_vector raw_decrypt(const uint8_t input[], size_t input_len) override + { + return raw_op(input, input_len); + } + }; + +class RSA_KEM_Decryption_Operation final : public PK_Ops::KEM_Decryption_with_KDF, + private RSA_Private_Operation + { + public: + + RSA_KEM_Decryption_Operation(const RSA_PrivateKey& key, + const std::string& kdf, + RandomNumberGenerator& rng) : + PK_Ops::KEM_Decryption_with_KDF(kdf), + RSA_Private_Operation(key, rng) + {} + + secure_vector + raw_kem_decrypt(const uint8_t encap_key[], size_t len) override + { + return raw_op(encap_key, len); + } + }; + +/** +* RSA public (encrypt/verify) operation +*/ +class RSA_Public_Operation + { + public: + explicit RSA_Public_Operation(const RSA_PublicKey& rsa) : + m_public(rsa.public_data()) + {} + + size_t get_max_input_bits() const + { + const size_t n_bits = m_public->public_modulus_bits(); + + /* + Make Coverity happy that n_bits - 1 won't underflow + + 5 bit minimum: smallest possible RSA key is 3*5 + */ + BOTAN_ASSERT_NOMSG(n_bits >= 5); + return n_bits - 1; + } + + protected: + BigInt public_op(const BigInt& m) const + { + if(m >= m_public->get_n()) + throw Invalid_Argument("RSA public op - input is too large"); + + return m_public->public_op(m); + } + + size_t public_modulus_bytes() const { return m_public->public_modulus_bytes(); } + + const BigInt& get_n() const { return m_public->get_n(); } + + std::shared_ptr m_public; + }; + +class RSA_Encryption_Operation final : public PK_Ops::Encryption_with_EME, + private RSA_Public_Operation + { + public: + + RSA_Encryption_Operation(const RSA_PublicKey& rsa, const std::string& eme) : + PK_Ops::Encryption_with_EME(eme), + RSA_Public_Operation(rsa) + { + } + + size_t ciphertext_length(size_t) const override { return public_modulus_bytes(); } + + size_t max_raw_input_bits() const override { return get_max_input_bits(); } + + secure_vector raw_encrypt(const uint8_t input[], size_t input_len, + RandomNumberGenerator&) override + { + BigInt input_bn(input, input_len); + return BigInt::encode_1363(public_op(input_bn), public_modulus_bytes()); + } + }; + +class RSA_Verify_Operation final : public PK_Ops::Verification_with_EMSA, + private RSA_Public_Operation + { + public: + + size_t max_input_bits() const override { return get_max_input_bits(); } + + RSA_Verify_Operation(const RSA_PublicKey& rsa, const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + RSA_Public_Operation(rsa) + { + } + + bool with_recovery() const override { return true; } + + secure_vector verify_mr(const uint8_t input[], size_t input_len) override + { + BigInt input_bn(input, input_len); + return BigInt::encode_locked(public_op(input_bn)); + } + }; + +class RSA_KEM_Encryption_Operation final : public PK_Ops::KEM_Encryption_with_KDF, + private RSA_Public_Operation + { + public: + + RSA_KEM_Encryption_Operation(const RSA_PublicKey& key, + const std::string& kdf) : + PK_Ops::KEM_Encryption_with_KDF(kdf), + RSA_Public_Operation(key) {} + + private: + void raw_kem_encrypt(secure_vector& out_encapsulated_key, + secure_vector& raw_shared_key, + Botan::RandomNumberGenerator& rng) override + { + const BigInt r = BigInt::random_integer(rng, 1, get_n()); + const BigInt c = public_op(r); + + out_encapsulated_key = BigInt::encode_locked(c); + raw_shared_key = BigInt::encode_locked(r); + } + }; + +} + +std::unique_ptr +RSA_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_rsa_enc_op(*this, params); + } + catch(Exception& e) + { + /* + * If OpenSSL for some reason could not handle this (eg due to OAEP params), + * throw if openssl was specifically requested but otherwise just fall back + * to the normal version. + */ + if(provider == "openssl") + throw Lookup_Error("OpenSSL RSA provider rejected key:" + std::string(e.what())); + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new RSA_Encryption_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +RSA_PublicKey::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new RSA_KEM_Encryption_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +RSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + std::unique_ptr res = make_openssl_rsa_ver_op(*this, params); + if(res) + return res; + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new RSA_Verify_Operation(*this, params)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +RSA_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_rsa_dec_op(*this, params); + } + catch(Exception& e) + { + if(provider == "openssl") + throw Lookup_Error("OpenSSL RSA provider rejected key:" + std::string(e.what())); + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new RSA_Decryption_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +RSA_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr(new RSA_KEM_Decryption_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +RSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + std::unique_ptr res = make_openssl_rsa_sig_op(*this, params); + if(res) + return res; + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr(new RSA_Signature_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/rsa/rsa.h b/comm/third_party/botan/src/lib/pubkey/rsa/rsa.h new file mode 100644 index 0000000000..2a02c89d56 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/rsa/rsa.h @@ -0,0 +1,180 @@ +/* +* RSA +* (C) 1999-2008,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RSA_H_ +#define BOTAN_RSA_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class RSA_Public_Data; +class RSA_Private_Data; + +/** +* RSA Public Key +*/ +class BOTAN_PUBLIC_API(2,0) RSA_PublicKey : public virtual Public_Key + { + public: + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + RSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits); + + /** + * Create a public key. + * @arg n the modulus + * @arg e the exponent + */ + RSA_PublicKey(const BigInt& n, const BigInt& e); + + std::string algo_name() const override { return "RSA"; } + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector public_key_bits() const override; + + /** + * @return public modulus + */ + const BigInt& get_n() const; + + /** + * @return public exponent + */ + const BigInt& get_e() const; + + size_t key_length() const override; + size_t estimated_strength() const override; + + // internal functions: + std::shared_ptr public_data() const; + + std::unique_ptr + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_kem_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + + protected: + RSA_PublicKey() = default; + + void init(BigInt&& n, BigInt&& e); + + std::shared_ptr m_public; + }; + +/** +* RSA Private Key +*/ +class BOTAN_PUBLIC_API(2,0) RSA_PrivateKey final : public Private_Key, public RSA_PublicKey + { + public: + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS#1 RSAPrivateKey bits + */ + RSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Construct a private key from the specified parameters. + * @param p the first prime + * @param q the second prime + * @param e the exponent + * @param d if specified, this has to be d with + * exp * d = 1 mod (p - 1, q - 1). Leave it as 0 if you wish to + * the constructor to calculate it. + * @param n if specified, this must be n = p * q. Leave it as 0 + * if you wish to the constructor to calculate it. + */ + RSA_PrivateKey(const BigInt& p, const BigInt& q, + const BigInt& e, const BigInt& d = 0, + const BigInt& n = 0); + + /** + * Create a new private key with the specified bit length + * @param rng the random number generator to use + * @param bits the desired bit length of the private key + * @param exp the public exponent to be used + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp = 65537); + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + /** + * Get the first prime p. + * @return prime p + */ + const BigInt& get_p() const; + + /** + * Get the second prime q. + * @return prime q + */ + const BigInt& get_q() const; + + /** + * Get d with exp * d = 1 mod (p - 1, q - 1). + * @return d + */ + const BigInt& get_d() const; + + const BigInt& get_c() const; + const BigInt& get_d1() const; + const BigInt& get_d2() const; + + secure_vector private_key_bits() const override; + + // internal functions: + std::shared_ptr private_data() const; + + std::unique_ptr + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + private: + + void init(BigInt&& d, BigInt&& p, BigInt&& q, BigInt&& d1, BigInt&& d2, BigInt&& c); + + std::shared_ptr m_private; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/sm2/info.txt b/comm/third_party/botan/src/lib/pubkey/sm2/info.txt new file mode 100644 index 0000000000..a3f756820a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/sm2/info.txt @@ -0,0 +1,14 @@ + +SM2 -> 20180801 + + + +asn1 +ec_group +ecc_key +keypair +numbertheory +rng +sm3 +kdf2 + diff --git a/comm/third_party/botan/src/lib/pubkey/sm2/sm2.cpp b/comm/third_party/botan/src/lib/pubkey/sm2/sm2.cpp new file mode 100644 index 0000000000..a976c097b3 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/sm2/sm2.cpp @@ -0,0 +1,306 @@ +/* +* SM2 Signatures +* (C) 2017,2018 Ribose Inc +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +std::string SM2_PublicKey::algo_name() const + { + return "SM2"; + } + +bool SM2_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "user@example.com,SM3"); + } + +SM2_PrivateKey::SM2_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits) : + EC_PrivateKey(alg_id, key_bits) + { + m_da_inv = domain().inverse_mod_order(m_private_key + 1); + } + +SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x) : + EC_PrivateKey(rng, domain, x) + { + m_da_inv = domain.inverse_mod_order(m_private_key + 1); + } + +std::vector sm2_compute_za(HashFunction& hash, + const std::string& user_id, + const EC_Group& domain, + const PointGFp& pubkey) + { + if(user_id.size() >= 8192) + throw Invalid_Argument("SM2 user id too long to represent"); + + const uint16_t uid_len = static_cast(8 * user_id.size()); + + hash.update(get_byte(0, uid_len)); + hash.update(get_byte(1, uid_len)); + hash.update(user_id); + + const size_t p_bytes = domain.get_p_bytes(); + + hash.update(BigInt::encode_1363(domain.get_a(), p_bytes)); + hash.update(BigInt::encode_1363(domain.get_b(), p_bytes)); + hash.update(BigInt::encode_1363(domain.get_g_x(), p_bytes)); + hash.update(BigInt::encode_1363(domain.get_g_y(), p_bytes)); + hash.update(BigInt::encode_1363(pubkey.get_affine_x(), p_bytes)); + hash.update(BigInt::encode_1363(pubkey.get_affine_y(), p_bytes)); + + std::vector za(hash.output_length()); + hash.final(za.data()); + + return za; + } + +namespace { + +/** +* SM2 signature operation +*/ +class SM2_Signature_Operation final : public PK_Ops::Signature + { + public: + + SM2_Signature_Operation(const SM2_PrivateKey& sm2, + const std::string& ident, + const std::string& hash) : + m_group(sm2.domain()), + m_x(sm2.private_value()), + m_da_inv(sm2.get_da_inv()) + { + if(hash == "Raw") + { + // m_hash is null, m_za is empty + } + else + { + m_hash = HashFunction::create_or_throw(hash); + // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA) + m_za = sm2_compute_za(*m_hash, ident, m_group, sm2.public_point()); + m_hash->update(m_za); + } + } + + size_t signature_length() const override { return 2*m_group.get_order_bytes(); } + + void update(const uint8_t msg[], size_t msg_len) override + { + if(m_hash) + { + m_hash->update(msg, msg_len); + } + else + { + m_digest.insert(m_digest.end(), msg, msg + msg_len); + } + } + + secure_vector sign(RandomNumberGenerator& rng) override; + + private: + const EC_Group m_group; + const BigInt& m_x; + const BigInt& m_da_inv; + + std::vector m_za; + secure_vector m_digest; + std::unique_ptr m_hash; + std::vector m_ws; + }; + +secure_vector +SM2_Signature_Operation::sign(RandomNumberGenerator& rng) + { + BigInt e; + if(m_hash) + { + e = BigInt::decode(m_hash->final()); + // prepend ZA for next signature if any + m_hash->update(m_za); + } + else + { + e = BigInt::decode(m_digest); + m_digest.clear(); + } + + const BigInt k = m_group.random_scalar(rng); + + const BigInt r = m_group.mod_order( + m_group.blinded_base_point_multiply_x(k, rng, m_ws) + e); + const BigInt s = m_group.multiply_mod_order(m_da_inv, m_group.mod_order(k - r*m_x)); + + return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order().bytes()); + } + +/** +* SM2 verification operation +*/ +class SM2_Verification_Operation final : public PK_Ops::Verification + { + public: + SM2_Verification_Operation(const SM2_PublicKey& sm2, + const std::string& ident, + const std::string& hash) : + m_group(sm2.domain()), + m_gy_mul(m_group.get_base_point(), sm2.public_point()) + { + if(hash == "Raw") + { + // m_hash is null, m_za is empty + } + else + { + m_hash = HashFunction::create_or_throw(hash); + // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA) + m_za = sm2_compute_za(*m_hash, ident, m_group, sm2.public_point()); + m_hash->update(m_za); + } + } + + void update(const uint8_t msg[], size_t msg_len) override + { + if(m_hash) + { + m_hash->update(msg, msg_len); + } + else + { + m_digest.insert(m_digest.end(), msg, msg + msg_len); + } + } + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; + private: + const EC_Group m_group; + const PointGFp_Multi_Point_Precompute m_gy_mul; + secure_vector m_digest; + std::vector m_za; + std::unique_ptr m_hash; + }; + +bool SM2_Verification_Operation::is_valid_signature(const uint8_t sig[], size_t sig_len) + { + BigInt e; + if(m_hash) + { + e = BigInt::decode(m_hash->final()); + // prepend ZA for next signature if any + m_hash->update(m_za); + } + else + { + e = BigInt::decode(m_digest); + m_digest.clear(); + } + + if(sig_len != m_group.get_order().bytes()*2) + return false; + + const BigInt r(sig, sig_len / 2); + const BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) + return false; + + const BigInt t = m_group.mod_order(r + s); + + if(t == 0) + return false; + + const PointGFp R = m_gy_mul.multi_exp(s, t); + + // ??? + if(R.is_zero()) + return false; + + return (m_group.mod_order(R.get_affine_x() + e) == r); + } + +void parse_sm2_param_string(const std::string& params, + std::string& userid, + std::string& hash) + { + // GM/T 0009-2012 specifies this as the default userid + const std::string default_userid = "1234567812345678"; + + // defaults: + userid = default_userid; + hash = "SM3"; + + /* + * SM2 parameters have the following possible formats: + * Ident [since 2.2.0] + * Ident,Hash [since 2.3.0] + */ + + auto comma = params.find(','); + if(comma == std::string::npos) + { + userid = params; + } + else + { + userid = params.substr(0, comma); + hash = params.substr(comma+1, std::string::npos); + } + } + +} + +std::unique_ptr +SM2_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + std::string userid, hash; + parse_sm2_param_string(params, userid, hash); + return std::unique_ptr(new SM2_Verification_Operation(*this, userid, hash)); + } + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +SM2_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + std::string userid, hash; + parse_sm2_param_string(params, userid, hash); + return std::unique_ptr(new SM2_Signature_Operation(*this, userid, hash)); + } + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/sm2/sm2.h b/comm/third_party/botan/src/lib/pubkey/sm2/sm2.h new file mode 100644 index 0000000000..7b5f38858b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/sm2/sm2.h @@ -0,0 +1,124 @@ +/* +* SM2 +* (C) 2017 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SM2_KEY_H_ +#define BOTAN_SM2_KEY_H_ + +#include + +namespace Botan { + +/** +* This class represents SM2 public keys +*/ +class BOTAN_PUBLIC_API(2,2) SM2_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Create a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + SM2_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + SM2_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name + */ + std::string algo_name() const override; + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + protected: + SM2_PublicKey() = default; + }; + +/** +* This class represents SM2 private keys +*/ +class BOTAN_PUBLIC_API(2,2) SM2_PrivateKey final : + public SM2_PublicKey, public EC_PrivateKey + { + public: + + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + SM2_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector& key_bits); + + /** + * Create a private key. + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a new random key) + */ + SM2_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0); + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + const BigInt& get_da_inv() const { return m_da_inv; } + private: + BigInt m_da_inv; + }; + +class HashFunction; + +std::vector +BOTAN_PUBLIC_API(2,5) sm2_compute_za(HashFunction& hash, + const std::string& user_id, + const EC_Group& domain, + const PointGFp& pubkey); + +// For compat with versions 2.2 - 2.7 +typedef SM2_PublicKey SM2_Signature_PublicKey; +typedef SM2_PublicKey SM2_Encryption_PublicKey; + +typedef SM2_PrivateKey SM2_Signature_PrivateKey; +typedef SM2_PrivateKey SM2_Encryption_PrivateKey; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.cpp b/comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.cpp new file mode 100644 index 0000000000..55549afe30 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.cpp @@ -0,0 +1,267 @@ +/* +* SM2 Encryption +* (C) 2017 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +class SM2_Encryption_Operation final : public PK_Ops::Encryption + { + public: + SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key, + RandomNumberGenerator& rng, + const std::string& kdf_hash) : + m_group(key.domain()), + m_kdf_hash(kdf_hash), + m_ws(PointGFp::WORKSPACE_SIZE), + m_mul_public_point(key.public_point(), rng, m_ws) + { + std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); + m_hash_size = hash->output_length(); + } + + size_t max_input_bits() const override + { + // This is arbitrary, but assumes SM2 is used for key encapsulation + return 512; + } + + size_t ciphertext_length(size_t ptext_len) const override + { + const size_t elem_size = m_group.get_order_bytes(); + const size_t der_overhead = 16; + + return der_overhead + 2*elem_size + m_hash_size + ptext_len; + } + + secure_vector encrypt(const uint8_t msg[], + size_t msg_len, + RandomNumberGenerator& rng) override + { + std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); + std::unique_ptr kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")"); + + const size_t p_bytes = m_group.get_p_bytes(); + + const BigInt k = m_group.random_scalar(rng); + + const PointGFp C1 = m_group.blinded_base_point_multiply(k, rng, m_ws); + const BigInt x1 = C1.get_affine_x(); + const BigInt y1 = C1.get_affine_y(); + std::vector x1_bytes(p_bytes); + std::vector y1_bytes(p_bytes); + BigInt::encode_1363(x1_bytes.data(), x1_bytes.size(), x1); + BigInt::encode_1363(y1_bytes.data(), y1_bytes.size(), y1); + + const PointGFp kPB = m_mul_public_point.mul(k, rng, m_group.get_order(), m_ws); + + const BigInt x2 = kPB.get_affine_x(); + const BigInt y2 = kPB.get_affine_y(); + std::vector x2_bytes(p_bytes); + std::vector y2_bytes(p_bytes); + BigInt::encode_1363(x2_bytes.data(), x2_bytes.size(), x2); + BigInt::encode_1363(y2_bytes.data(), y2_bytes.size(), y2); + + secure_vector kdf_input; + kdf_input += x2_bytes; + kdf_input += y2_bytes; + + const secure_vector kdf_output = + kdf->derive_key(msg_len, kdf_input.data(), kdf_input.size()); + + secure_vector masked_msg(msg_len); + xor_buf(masked_msg.data(), msg, kdf_output.data(), msg_len); + + hash->update(x2_bytes); + hash->update(msg, msg_len); + hash->update(y2_bytes); + std::vector C3(hash->output_length()); + hash->final(C3.data()); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(x1) + .encode(y1) + .encode(C3, OCTET_STRING) + .encode(masked_msg, OCTET_STRING) + .end_cons() + .get_contents(); + } + + private: + const EC_Group m_group; + const std::string m_kdf_hash; + + std::vector m_ws; + PointGFp_Var_Point_Precompute m_mul_public_point; + size_t m_hash_size; + }; + +class SM2_Decryption_Operation final : public PK_Ops::Decryption + { + public: + SM2_Decryption_Operation(const SM2_Encryption_PrivateKey& key, + RandomNumberGenerator& rng, + const std::string& kdf_hash) : + m_key(key), + m_rng(rng), + m_kdf_hash(kdf_hash) + { + std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); + m_hash_size = hash->output_length(); + } + + size_t plaintext_length(size_t ptext_len) const override + { + /* + * This ignores the DER encoding and so overestimates the + * plaintext length by 12 bytes or so + */ + const size_t elem_size = m_key.domain().get_order_bytes(); + + if(ptext_len < 2*elem_size + m_hash_size) + return 0; + + return ptext_len - (2*elem_size + m_hash_size); + } + + secure_vector decrypt(uint8_t& valid_mask, + const uint8_t ciphertext[], + size_t ciphertext_len) override + { + const EC_Group& group = m_key.domain(); + const BigInt& cofactor = group.get_cofactor(); + const size_t p_bytes = group.get_p_bytes(); + + valid_mask = 0x00; + + std::unique_ptr hash = HashFunction::create_or_throw(m_kdf_hash); + std::unique_ptr kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")"); + + // Too short to be valid - no timing problem from early return + if(ciphertext_len < 1 + p_bytes*2 + hash->output_length()) + { + return secure_vector(); + } + + BigInt x1, y1; + secure_vector C3, masked_msg; + + BER_Decoder(ciphertext, ciphertext_len) + .start_cons(SEQUENCE) + .decode(x1) + .decode(y1) + .decode(C3, OCTET_STRING) + .decode(masked_msg, OCTET_STRING) + .end_cons() + .verify_end(); + + std::vector recode_ctext; + DER_Encoder(recode_ctext) + .start_cons(SEQUENCE) + .encode(x1) + .encode(y1) + .encode(C3, OCTET_STRING) + .encode(masked_msg, OCTET_STRING) + .end_cons(); + + if(recode_ctext.size() != ciphertext_len) + return secure_vector(); + + if(same_mem(recode_ctext.data(), ciphertext, ciphertext_len) == false) + return secure_vector(); + + PointGFp C1 = group.point(x1, y1); + C1.randomize_repr(m_rng); + + // Here C1 is publically invalid, so no problem with early return: + if(!C1.on_the_curve()) + return secure_vector(); + + if(cofactor > 1 && (C1 * cofactor).is_zero()) + { + return secure_vector(); + } + + const PointGFp dbC1 = group.blinded_var_point_multiply( + C1, m_key.private_value(), m_rng, m_ws); + + const BigInt x2 = dbC1.get_affine_x(); + const BigInt y2 = dbC1.get_affine_y(); + + secure_vector x2_bytes(p_bytes); + secure_vector y2_bytes(p_bytes); + BigInt::encode_1363(x2_bytes.data(), x2_bytes.size(), x2); + BigInt::encode_1363(y2_bytes.data(), y2_bytes.size(), y2); + + secure_vector kdf_input; + kdf_input += x2_bytes; + kdf_input += y2_bytes; + + const secure_vector kdf_output = + kdf->derive_key(masked_msg.size(), kdf_input.data(), kdf_input.size()); + + xor_buf(masked_msg.data(), kdf_output.data(), kdf_output.size()); + + hash->update(x2_bytes); + hash->update(masked_msg); + hash->update(y2_bytes); + secure_vector u = hash->final(); + + if(constant_time_compare(u.data(), C3.data(), hash->output_length()) == false) + return secure_vector(); + + valid_mask = 0xFF; + return masked_msg; + } + private: + const SM2_Encryption_PrivateKey& m_key; + RandomNumberGenerator& m_rng; + const std::string m_kdf_hash; + std::vector m_ws; + size_t m_hash_size; + }; + +} + +std::unique_ptr +SM2_PublicKey::create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + const std::string kdf_hash = (params.empty() ? "SM3" : params); + return std::unique_ptr(new SM2_Encryption_Operation(*this, rng, kdf_hash)); + } + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr +SM2_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + const std::string kdf_hash = (params.empty() ? "SM3" : params); + return std::unique_ptr(new SM2_Decryption_Operation(*this, rng, kdf_hash)); + } + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.h b/comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.h new file mode 100644 index 0000000000..ea8c43d9d5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/sm2/sm2_enc.h @@ -0,0 +1,15 @@ +/* +* SM2 Encryption +* (C) 2017 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SM2_ENC_KEY_H_ +#define BOTAN_SM2_ENC_KEY_H_ + +#include + +BOTAN_DEPRECATED_HEADER(sm2_enc.h) + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/workfactor.cpp b/comm/third_party/botan/src/lib/pubkey/workfactor.cpp new file mode 100644 index 0000000000..bb4fd56ca5 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/workfactor.cpp @@ -0,0 +1,66 @@ +/* +* Public Key Work Factor Functions +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +size_t ecp_work_factor(size_t bits) + { + return bits / 2; + } + +namespace { + +size_t nfs_workfactor(size_t bits, double log2_k) + { + // approximates natural logarithm of an integer of given bitsize + const double log2_e = 1.44269504088896340736; + const double log_p = bits / log2_e; + + const double log_log_p = std::log(log_p); + + // RFC 3766: k * e^((1.92 + o(1)) * cubrt(ln(n) * (ln(ln(n)))^2)) + const double est = 1.92 * std::pow(log_p * log_log_p * log_log_p, 1.0/3.0); + + // return log2 of the workfactor + return static_cast(log2_k + log2_e * est); + } + +} + +size_t if_work_factor(size_t bits) + { + // RFC 3766 estimates k at .02 and o(1) to be effectively zero for sizes of interest + + const double log2_k = -5.6438; // log2(.02) + return nfs_workfactor(bits, log2_k); + } + +size_t dl_work_factor(size_t bits) + { + // Lacking better estimates... + return if_work_factor(bits); + } + +size_t dl_exponent_size(size_t bits) + { + /* + This uses a slightly tweaked version of the standard work factor + function above. It assumes k is 1 (thus overestimating the strength + of the prime group by 5-6 bits), and always returns at least 128 bits + (this only matters for very small primes). + */ + const size_t min_workfactor = 64; + const double log2_k = 0; + + return 2 * std::max(min_workfactor, nfs_workfactor(bits, log2_k)); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/workfactor.h b/comm/third_party/botan/src/lib/pubkey/workfactor.h new file mode 100644 index 0000000000..2c8c876420 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/workfactor.h @@ -0,0 +1,51 @@ +/* +* Public Key Work Factor Functions +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_WORKFACTOR_H_ +#define BOTAN_WORKFACTOR_H_ + +#include +BOTAN_FUTURE_INTERNAL_HEADER(workfactor.h) + +namespace Botan { + +/** +* Estimate work factor for discrete logarithm +* @param prime_group_size size of the group in bits +* @return estimated security level for this group +*/ +BOTAN_PUBLIC_API(2,0) size_t dl_work_factor(size_t prime_group_size); + +/** +* Return the appropriate exponent size to use for a particular prime +* group. This is twice the size of the estimated cost of breaking the +* key using an index calculus attack; the assumption is that if an +* arbitrary discrete log on a group of size bits would take about 2^n +* effort, and thus using an exponent of size 2^(2*n) implies that all +* available attacks are about as easy (as e.g Pollard's kangaroo +* algorithm can compute the DL in sqrt(x) operations) while minimizing +* the exponent size for performance reasons. +*/ +BOTAN_PUBLIC_API(2,0) size_t dl_exponent_size(size_t prime_group_size); + +/** +* Estimate work factor for integer factorization +* @param n_bits size of modulus in bits +* @return estimated security level for this modulus +*/ +BOTAN_PUBLIC_API(2,0) size_t if_work_factor(size_t n_bits); + +/** +* Estimate work factor for EC discrete logarithm +* @param prime_group_size size of the group in bits +* @return estimated security level for this group +*/ +BOTAN_PUBLIC_API(2,0) size_t ecp_work_factor(size_t prime_group_size); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/x509_key.cpp b/comm/third_party/botan/src/lib/pubkey/x509_key.cpp new file mode 100644 index 0000000000..716cb1ba4b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/x509_key.cpp @@ -0,0 +1,106 @@ +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace X509 { + +std::vector BER_encode(const Public_Key& key) + { + // keeping it around for compat + return key.subject_public_key(); + } + +/* +* PEM encode a X.509 public key +*/ +std::string PEM_encode(const Public_Key& key) + { + return PEM_Code::encode(key.subject_public_key(), + "PUBLIC KEY"); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(DataSource& source) + { + try { + AlgorithmIdentifier alg_id; + std::vector key_bits; + + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .end_cons(); + } + else + { + DataSource_Memory ber( + PEM_Code::decode_check_label(source, "PUBLIC KEY") + ); + + BER_Decoder(ber) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .end_cons(); + } + + if(key_bits.empty()) + throw Decoding_Error("X.509 public key decoding"); + + return load_public_key(alg_id, key_bits).release(); + } + catch(Decoding_Error& e) + { + throw Decoding_Error("X.509 public key decoding", e); + } + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::string& fsname) + { + DataSource_Stream source(fsname, true); + return X509::load_key(source); + } +#endif + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::vector& mem) + { + DataSource_Memory source(mem); + return X509::load_key(source); + } + +/* +* Make a copy of this public key +*/ +Public_Key* copy_key(const Public_Key& key) + { + DataSource_Memory source(PEM_encode(key)); + return X509::load_key(source); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/pubkey/x509_key.h b/comm/third_party/botan/src/lib/pubkey/x509_key.h new file mode 100644 index 0000000000..58d537bbe7 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/x509_key.h @@ -0,0 +1,80 @@ +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_PUBLIC_KEY_H_ +#define BOTAN_X509_PUBLIC_KEY_H_ + +#include +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; +class DataSource; + +/** +* The two types of X509 encoding supported by Botan. +* This enum is not used anymore, and will be removed in a future major release. +*/ +enum X509_Encoding { RAW_BER, PEM }; + +/** +* This namespace contains functions for handling X.509 public keys +*/ +namespace X509 { + +/** +* BER encode a key +* @param key the public key to encode +* @return BER encoding of this key +*/ +BOTAN_PUBLIC_API(2,0) std::vector BER_encode(const Public_Key& key); + +/** +* PEM encode a public key into a string. +* @param key the key to encode +* @return PEM encoded key +*/ +BOTAN_PUBLIC_API(2,0) std::string PEM_encode(const Public_Key& key); + +/** +* Create a public key from a data source. +* @param source the source providing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* load_key(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +/** +* Create a public key from a file +* @param filename pathname to the file to load +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* load_key(const std::string& filename); +#endif + +/** +* Create a public key from a memory region. +* @param enc the memory region containing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* load_key(const std::vector& enc); + +/** +* Copy a key. +* @param key the public key to copy +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* copy_key(const Public_Key& key); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/atomic.h b/comm/third_party/botan/src/lib/pubkey/xmss/atomic.h new file mode 100644 index 0000000000..a542d4c005 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/atomic.h @@ -0,0 +1,55 @@ +/* + * Atomic + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_ATOMIC_H_ +#define BOTAN_ATOMIC_H_ + +#include +#include +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(atomic.h) + +namespace Botan { + +template +/** + * Simple helper class to expand std::atomic with copy constructor and copy + * assignment operator, i.e. for use as element in a container like + * std::vector. The construction of instances of this wrapper is NOT atomic + * and needs to be properly guarded. + **/ +class Atomic final + { + public: + Atomic() = default; + Atomic(const Atomic& data) : m_data(data.m_data.load()) {} + Atomic(const std::atomic& data) : m_data(data.load()) {} + ~Atomic() = default; + + Atomic& operator=(const Atomic& a) + { + m_data.store(a.m_data.load()); + return *this; + } + + Atomic& operator=(const std::atomic& a) + { + m_data.store(a.load()); + return *this; + } + + operator std::atomic& () { return m_data; } + operator T() { return m_data.load(); } + + private: + std::atomic m_data; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/info.txt b/comm/third_party/botan/src/lib/pubkey/xmss/info.txt new file mode 100644 index 0000000000..ae290f5fc9 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/info.txt @@ -0,0 +1,40 @@ + +XMSS_RFC8391 -> 20201101 + + + +xmss.h +xmss_hash.h +xmss_wots.h +xmss_parameters.h +xmss_key_pair.h +xmss_privatekey.h +xmss_publickey.h +xmss_wots_parameters.h +xmss_wots_privatekey.h +xmss_wots_publickey.h + + + +atomic.h +xmss_address.h +xmss_common_ops.h +xmss_index_registry.h +xmss_signature.h +xmss_signature_operation.h +xmss_tools.h +xmss_verification_operation.h +xmss_wots_addressed_privatekey.h +xmss_wots_addressed_publickey.h + + + +asn1 +rng +hash +sha2_32 + + + +atomics + diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss.h new file mode 100644 index 0000000000..af8e8a41e8 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss.h @@ -0,0 +1,459 @@ +/* + * XMSS Keys + * (C) 2016,2017 Matthias Gierlings + * (C) 2019 René Korthaus, Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_H_ +#define BOTAN_XMSS_H_ + +#include +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; +class XMSS_Verification_Operation; + +/** + * An XMSS: Extended Hash-Based Signature public key. + * + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + **/ +class BOTAN_PUBLIC_API(2,0) XMSS_PublicKey : public virtual Public_Key + { + public: + /** + * Creates a new XMSS public key for the chosen XMSS signature method. + * New public and prf seeds are generated using rng. The appropriate WOTS + * signature method will be automatically set based on the chosen XMSS + * signature method. + * + * @param xmss_oid Identifier for the selected XMSS signature method. + * @param rng A random number generator to use for key generation. + **/ + XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, + RandomNumberGenerator& rng); + + /** + * Loads a public key. + * + * Public key must be encoded as in RFC + * draft-vangeest-x509-hash-sigs-03. + * + * @param key_bits DER encoded public key bits + */ + XMSS_PublicKey(const std::vector& key_bits); + + /** + * Creates a new XMSS public key for a chosen XMSS signature method as + * well as pre-computed root node and public_seed values. + * + * @param xmss_oid Identifier for the selected XMSS signature method. + * @param root Root node value. + * @param public_seed Public seed value. + **/ + XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, + const secure_vector& root, + const secure_vector& public_seed) + : m_xmss_params(xmss_oid), m_wots_params(m_xmss_params.ots_oid()), + m_root(root), m_public_seed(public_seed) {} + + /** + * Creates a new XMSS public key for a chosen XMSS signature method as + * well as pre-computed root node and public_seed values. + * + * @param xmss_oid Identifier for the selected XMSS signature method. + * @param root Root node value. + * @param public_seed Public seed value. + **/ + XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, + secure_vector&& root, + secure_vector&& public_seed) + : m_xmss_params(xmss_oid), m_wots_params(m_xmss_params.ots_oid()), + m_root(std::move(root)), m_public_seed(std::move(public_seed)) {} + + /** + * Retrieves the chosen XMSS signature method. + * + * @return XMSS signature method identifier. + **/ + XMSS_Parameters::xmss_algorithm_t xmss_oid() const + { + return m_xmss_params.oid(); + } + + /** + * Sets the chosen XMSS signature method + **/ + void set_xmss_oid(XMSS_Parameters::xmss_algorithm_t xmss_oid) + { + m_xmss_params = XMSS_Parameters(xmss_oid); + m_wots_params = XMSS_WOTS_Parameters(m_xmss_params.ots_oid()); + } + + /** + * Retrieves the XMSS parameters determined by the chosen XMSS Signature + * method. + * + * @return XMSS parameters. + **/ + const XMSS_Parameters& xmss_parameters() const + { + return m_xmss_params; + } + + /** + * Retrieves the XMSS parameters determined by the chosen XMSS Signature + * method. + * + * @return XMSS parameters. + **/ + std::string xmss_hash_function() const + { + return m_xmss_params.hash_function_name(); + } + + /** + * Retrieves the Winternitz One Time Signature (WOTS) method, + * corresponding to the chosen XMSS signature method. + * + * @return XMSS WOTS signature method identifier. + **/ + XMSS_WOTS_Parameters::ots_algorithm_t wots_oid() const + { + return m_wots_params.oid(); + } + + /** + * Retrieves the Winternitz One Time Signature (WOTS) parameters + * corresponding to the chosen XMSS signature method. + * + * @return XMSS WOTS signature method parameters. + **/ + const XMSS_WOTS_Parameters& wots_parameters() const + { + return m_wots_params; + } + + secure_vector& root() + { + return m_root; + } + + void set_root(const secure_vector& root) + { + m_root = root; + } + + void set_root(secure_vector&& root) + { + m_root = std::move(root); + } + + const secure_vector& root() const + { + return m_root; + } + + virtual secure_vector& public_seed() + { + return m_public_seed; + } + + virtual void set_public_seed(const secure_vector& public_seed) + { + m_public_seed = public_seed; + } + + virtual void set_public_seed(secure_vector&& public_seed) + { + m_public_seed = std::move(public_seed); + } + + virtual const secure_vector& public_seed() const + { + return m_public_seed; + } + + std::string algo_name() const override + { + return "XMSS"; + } + + AlgorithmIdentifier algorithm_identifier() const override + { + return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_EMPTY_PARAM); + } + + bool check_key(RandomNumberGenerator&, bool) const override + { + return true; + } + + std::unique_ptr + create_verification_op(const std::string&, + const std::string& provider) const override; + + size_t estimated_strength() const override + { + return m_xmss_params.estimated_strength(); + } + + size_t key_length() const override + { + return m_xmss_params.estimated_strength(); + } + + /** + * Returns the encoded public key as defined in RFC + * draft-vangeest-x509-hash-sigs-03. + * + * @return encoded public key bits + **/ + std::vector public_key_bits() const override; + + /** + * Size in bytes of the serialized XMSS public key produced by + * raw_public_key(). + * + * @return size in bytes of serialized Public Key. + **/ + virtual size_t size() const + { + return sizeof(uint32_t) + 2 * m_xmss_params.element_size(); + } + + /** + * Generates a byte sequence representing the XMSS + * public key, as defined in [1] (p. 23, "XMSS Public Key") + * + * @return 4-byte OID, followed by n-byte root node, followed by + * public seed. + **/ + virtual std::vector raw_public_key() const; + + protected: + std::vector m_raw_key; + XMSS_Parameters m_xmss_params; + XMSS_WOTS_Parameters m_wots_params; + secure_vector m_root; + secure_vector m_public_seed; + + private: + XMSS_Parameters::xmss_algorithm_t deserialize_xmss_oid( + const std::vector& raw_key); + }; + +template class Atomic; + +class XMSS_Index_Registry; + +/** + * An XMSS: Extended Hash-Based Signature private key. + * The XMSS private key does not support the X509 and PKCS7 standard. Instead + * the raw format described in [1] is used. + * + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + **/ +class BOTAN_PUBLIC_API(2,0) XMSS_PrivateKey final : public virtual XMSS_PublicKey, + public virtual Private_Key + { + public: + /** + * Creates a new XMSS private key for the chosen XMSS signature method. + * New seeds for public/private key and pseudo random function input are + * generated using the provided RNG. The appropriate WOTS signature method + * will be automatically set based on the chosen XMSS signature method. + * + * @param xmss_algo_id Identifier for the selected XMSS signature method. + * @param rng A random number generator to use for key generation. + **/ + XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, + RandomNumberGenerator& rng); + + /** + * Creates an XMSS_PrivateKey from a byte sequence produced by + * raw_private_key(). + * + * @param raw_key An XMSS private key serialized using raw_private_key(). + **/ + XMSS_PrivateKey(const secure_vector& raw_key); + + /** + * Creates a new XMSS private key for the chosen XMSS signature method + * using precomputed seeds for public/private keys and pseudo random + * function input. The appropriate WOTS signature method will be + * automatically set, based on the chosen XMSS signature method. + * + * @param xmss_algo_id Identifier for the selected XMSS signature method. + * @param idx_leaf Index of the next unused leaf. + * @param wots_priv_seed A seed to generate a Winternitz-One-Time- + * Signature private key from. + * @param prf a secret n-byte key sourced from a secure source + * of uniformly random data. + * @param root Root node of the binary hash tree. + * @param public_seed The public seed. + **/ + XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, + size_t idx_leaf, + const secure_vector& wots_priv_seed, + const secure_vector& prf, + const secure_vector& root, + const secure_vector& public_seed); + + bool stateful_operation() const override { return true; } + + /** + * Retrieves the last unused leaf index of the private key. Reusing a leaf + * by utilizing leaf indices lower than the last unused leaf index will + * compromise security. + * + * @return Index of the last unused leaf. + **/ + size_t unused_leaf_index() const; + + /** + * Sets the last unused leaf index of the private key. The leaf index + * will be updated automatically during every signing operation, and + * should not be set manually. + * + * @param idx Index of the last unused leaf. + **/ + void set_unused_leaf_index(size_t idx); + + size_t reserve_unused_leaf_index(); + + /** + * Winternitz One Time Signature Scheme key utilized for signing + * operations. + * + * @return WOTS+ private key. + **/ + const XMSS_WOTS_PrivateKey& wots_private_key() const + { + return m_wots_priv_key; + } + + /** + * Winternitz One Time Signature Scheme key utilized for signing + * operations. + * + * @return WOTS+ private key. + **/ + XMSS_WOTS_PrivateKey& wots_private_key() + { + return m_wots_priv_key; + } + + const secure_vector& prf() const + { + return m_prf; + } + + secure_vector& prf() + { + return m_prf; + } + + void set_public_seed( + const secure_vector& public_seed) override + { + m_public_seed = public_seed; + m_wots_priv_key.set_public_seed(public_seed); + } + + void set_public_seed(secure_vector&& public_seed) override + { + m_public_seed = std::move(public_seed); + m_wots_priv_key.set_public_seed(m_public_seed); + } + + const secure_vector& public_seed() const override + { + return m_public_seed; + } + + std::unique_ptr + create_signature_op(RandomNumberGenerator&, + const std::string&, + const std::string& provider) const override; + + secure_vector private_key_bits() const override; + + size_t size() const override + { + return XMSS_PublicKey::size() + + sizeof(uint32_t) + + 2 * XMSS_PublicKey::m_xmss_params.element_size(); + } + + /** + * Generates a non standartized byte sequence representing the XMSS + * private key. + * + * @return byte sequence consisting of the following elements in order: + * 4-byte OID, n-byte root node, n-byte public seed, + * 8-byte unused leaf index, n-byte prf seed, n-byte private seed. + **/ + secure_vector raw_private_key() const; + /** + * Algorithm 9: "treeHash" + * Computes the internal n-byte nodes of a Merkle tree. + * + * @param start_idx The start index. + * @param target_node_height Height of the target node. + * @param adrs Address of the tree containing the target node. + * + * @return The root node of a tree of height target_node height with the + * leftmost leaf being the hash of the WOTS+ pk with index + * start_idx. + **/ + secure_vector tree_hash( + size_t start_idx, + size_t target_node_height, + XMSS_Address& adrs); + + private: + /** + * Fetches shared unused leaf index from the index registry + **/ + std::shared_ptr> recover_global_leaf_index() const; + + inline void tree_hash_subtree(secure_vector& result, + size_t start_idx, + size_t target_node_height, + XMSS_Address& adrs) + { + return tree_hash_subtree(result, start_idx, target_node_height, adrs, m_hash); + } + + + /** + * Helper for multithreaded tree hashing. + */ + void tree_hash_subtree(secure_vector& result, + size_t start_idx, + size_t target_node_height, + XMSS_Address& adrs, + XMSS_Hash& hash); + + XMSS_WOTS_PrivateKey m_wots_priv_key; + XMSS_Hash m_hash; + secure_vector m_prf; + XMSS_Index_Registry& m_index_reg; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_address.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_address.h new file mode 100644 index 0000000000..05a78f3b88 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_address.h @@ -0,0 +1,405 @@ +/* + * XMSS Address + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_ADDRESS_H_ +#define BOTAN_XMSS_ADDRESS_H_ + +#include + +namespace Botan { + +/** + * Generic XMSS Address type holding 256 Bits of data. Properties + * of all three address formats L-Tree-Address, Hash-Tree-Address, + * OTS-Hash-Address can be called depending on the type currently + * assigned to the XMSS address using set_type(). + **/ +class XMSS_Address final + { + public: + /** + * Distinct types an XMSS_Address can represent. The available types + * are specified in [1] - 2.5 Hash Function Address Scheme. + **/ + enum class Type : uint8_t + { + None = 255, + OTS_Hash_Address = 0, + LTree_Address = 1, + Hash_Tree_Address = 2 + }; + + /** + * The available modes for an XMSS Address: + * - Key_Mode: Used to generate the key. + * - Mask_Mode: Sets the n-byte bitmask (OTS-Hash-Address) + * - Mask_MSB_Mode: Used to generate the b most significant bytes of + * the 2n-byte bitmask (LTree Address and Hash Tree Address). + * - Mask_LSB_Mode: Used to generated the b least significant bytes + * of the 2n-byte bitmask. (LTree Address and Hash Tree Address). + **/ + enum class Key_Mask : uint8_t + { + Key_Mode = 0, + Mask_Mode = 1, + Mask_MSB_Mode = 1, + Mask_LSB_Mode = 2 + }; + + /** + * Layer Address for XMSS is constantly zero and can not be changed this + * property is only of relevance to XMSS_MT. + * + * @return Layer address, which is constant 0 for XMSS. + **/ + uint8_t get_layer_addr() const { return 0; } + + /** + * Layer Address for XMSS is constantly zero and can not be changed this + * property is only of relevance to XMSS_MT. Calling this method for + * XMSS will result in an error. + **/ + void set_layer_addr() + { + BOTAN_ASSERT(false, "Only available in XMSS_MT."); + } + + /** + * Tree Address for XMSS is constantly zero and can not be changed this + * property is only of relevance to XMSS_MT. + * + * @return Tree address, which is constant 0 for XMSS. + **/ + uint64_t get_tree_addr() const { return 0; } + + /** + * Tree Address for XMSS is constantly zero and can not be changed this + * property is only of relevance to XMSS_MT. Calling this method for + * XMSS will result in an error. + **/ + void set_tree_addr() + { + BOTAN_ASSERT(false, "Only available in XMSS_MT."); + } + + /** + * retrieves the logical type currently assigned to the XMSS Address + * instance. + * + * @return Type of the address (OTS_Hash_Address, LTree_Address or + * Hash_Tree_Address) + **/ + Type get_type() const + { + return static_cast(m_data[15]); + } + + /** + * Changes the logical type currently assigned to the XMSS Address + * instance. Please note that changing the type will automatically + * reset the 128 LSBs of the Address to zero. This affects the + * key_mask_mode property as well as all properties identified by + * XMSS_Address::Property. + * + * @param type Type that shall be assigned to the address + * (OTS_Hash_Address, LTree_Address or Hash_Tree_Address) + **/ + void set_type(Type type) + { + m_data[15] = static_cast(type); + std::fill(m_data.begin() + 16, m_data.end(), static_cast(0)); + } + + /** + * Retrieves the mode the address os currently set to. (See + * XMSS_Address::Key_Mask for details.) + * + * @return currently active mode + **/ + Key_Mask get_key_mask_mode() const + { + return Key_Mask(m_data[31]); + } + + /** + * Changes the mode the address currently used address mode. + * (XMSS_Address::Key_Mask for details.) + * + * @param value Target mode. + **/ + void set_key_mask_mode(Key_Mask value) + { + BOTAN_ASSERT(value != Key_Mask::Mask_LSB_Mode || + get_type() != Type::OTS_Hash_Address, + "Invalid Key_Mask for current XMSS_Address::Type."); + m_data[31] = static_cast(value); + } + + /** + * Retrieve the index of the OTS key pair within the tree. A call to + * this method is only valid, if the address type is set to + * Type::OTS_Hash_Address. + * + * @return index of OTS key pair. + **/ + uint32_t get_ots_address() const + { + BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, + "get_ots_address() requires XMSS_Address::Type::" + "OTS_Hash_Address."); + return get_hi32(2); + } + + /** + * Sets the index of the OTS key pair within the tree. A call to this + * method is only valid, if the address type is set to + * Type::OTS_Hash_Address. + * + * @param value index of OTS key pair. + **/ + void set_ots_address(uint32_t value) + { + BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, + "set_ots_address() requires XMSS_Address::Type::" + "OTS_Hash_Address."); + set_hi32(2, value); + } + + /** + * Retrieves the index of the leaf computed with this LTree. A call to + * this method is only valid, if the address type is set to + * Type::LTree_Address. + * + * @return index of the leaf. + **/ + uint32_t get_ltree_address() const + { + BOTAN_ASSERT(get_type() == Type::LTree_Address, + "set_ltree_address() requires XMSS_Address::Type::" + "LTree_Address."); + return get_hi32(2); + } + + /** + * Sets the index of the leaf computed with this LTree. A call to this + * method is only valid, if the address type is set to + * Type::LTree_Address. + * + * @param value index of the leaf. + **/ + void set_ltree_address(uint32_t value) + { + BOTAN_ASSERT(get_type() == Type::LTree_Address, + "set_ltree_address() requires XMSS_Address::Type::" + "LTree_Address."); + set_hi32(2, value); + } + + /** + * Retrieve the chain address. A call to this method is only valid, if + * the address type is set to Type::OTS_Hash_Address. + * + * @return chain address. + **/ + uint32_t get_chain_address() const + { + BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, + "get_chain_address() requires XMSS_Address::Type::" + "OTS_Hash_Address."); + return get_lo32(2); + } + + /** + * Set the chain address. A call to this method is only valid, if + * the address type is set to Type::OTS_Hash_Address. + **/ + void set_chain_address(uint32_t value) + { + BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, + "set_chain_address() requires XMSS_Address::Type::" + "OTS_Hash_Address."); + set_lo32(2, value); + } + + /** + * Retrieves the height of the tree node to be computed within the + * tree. A call to this method is only valid, if the address type is + * set to Type::LTree_Address or Type::Hash_Tree_Address. + * + * @return height of the tree node. + **/ + uint32_t get_tree_height() const + { + BOTAN_ASSERT(get_type() == Type::LTree_Address || + get_type() == Type::Hash_Tree_Address, + "get_tree_height() requires XMSS_Address::Type::" + "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); + return get_lo32(2); + } + + /** + * Sets the height of the tree node to be computed within the + * tree. A call to this method is only valid, if the address type is + * set to Type::LTree_Address or Type::Hash_Tree_Address. + * + * @param value height of the tree node. + **/ + void set_tree_height(uint32_t value) + { + BOTAN_ASSERT(get_type() == Type::LTree_Address || + get_type() == Type::Hash_Tree_Address, + "set_tree_height() requires XMSS_Address::Type::" + "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); + set_lo32(2, value); + } + + /** + * Retrieves the address of the hash function call within the chain. + * A call to this method is only valid, if the address type is + * set to Type::OTS_Hash_Address. + * + * @return address of the hash function call within chain. + **/ + uint32_t get_hash_address() const + { + BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, + "get_hash_address() requires XMSS_Address::Type::" + "OTS_Hash_Address."); + return get_hi32(3); + } + + /** + * Sets the address of the hash function call within the chain. + * A call to this method is only valid, if the address type is + * set to Type::OTS_Hash_Address. + * + * @param value address of the hash function call within chain. + **/ + void set_hash_address(uint32_t value) + { + BOTAN_ASSERT(get_type() == Type::OTS_Hash_Address, + "set_hash_address() requires XMSS_Address::Type::" + "OTS_Hash_Address."); + set_hi32(3, value); + } + + /** + * Retrieves the index of the tree node at current tree height in the + * tree. A call to this method is only valid, if the address type is + * set to Type::LTree_Address or Type::Hash_Tree_Address. + * + * @return index of the tree node at current height. + **/ + uint32_t get_tree_index() const + { + BOTAN_ASSERT(get_type() == Type::LTree_Address || + get_type() == Type::Hash_Tree_Address, + "get_tree_index() requires XMSS_Address::Type::" + "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); + return get_hi32(3); + } + + /** + * Sets the index of the tree node at current tree height in the + * tree. A call to this method is only valid, if the address type is + * set to Type::LTree_Address or Type::Hash_Tree_Address. + * + * @param value index of the tree node at current height. + **/ + void set_tree_index(uint32_t value) + { + BOTAN_ASSERT(get_type() == Type::LTree_Address || + get_type() == Type::Hash_Tree_Address, + "set_tree_index() requires XMSS_Address::Type::" + "LTree_Address or XMSS_Address::Type::Hash_Tree_Address."); + set_hi32(3, value); + } + + const secure_vector& bytes() const + { + return m_data; + } + + secure_vector& bytes() + { + return m_data; + } + + /** + * @return the size of an XMSS_Address + **/ + size_t size() const + { + return m_data.size(); + } + + XMSS_Address() + : m_data(m_address_size) + { + set_type(Type::None); + } + + XMSS_Address(Type type) + : m_data(m_address_size) + { + set_type(type); + } + + XMSS_Address(const secure_vector& data) : m_data(data) + { + BOTAN_ASSERT(m_data.size() == m_address_size, + "XMSS_Address must be of 256 bits size."); + } + + XMSS_Address(secure_vector&& data) : m_data(std::move(data)) + { + BOTAN_ASSERT(m_data.size() == m_address_size, + "XMSS_Address must be of 256 bits size."); + } + + protected: + secure_vector m_data; + + private: + static const size_t m_address_size = 32; + + inline uint32_t get_hi32(size_t offset) const + { + return ((0x000000FF & m_data[8 * offset + 3]) | + (0x000000FF & m_data[8 * offset + 2]) << 8 | + (0x000000FF & m_data[8 * offset + 1]) << 16 | + (0x000000FF & m_data[8 * offset ]) << 24); + } + + inline void set_hi32(size_t offset, uint32_t value) + { + m_data[offset * 8 ] = ((value >> 24) & 0xFF); + m_data[offset * 8 + 1] = ((value >> 16) & 0xFF); + m_data[offset * 8 + 2] = ((value >> 8) & 0xFF); + m_data[offset * 8 + 3] = ((value ) & 0xFF); + } + + inline uint32_t get_lo32(size_t offset) const + { + return ((0x000000FF & m_data[8 * offset + 7]) | + (0x000000FF & m_data[8 * offset + 6]) << 8 | + (0x000000FF & m_data[8 * offset + 5]) << 16 | + (0x000000FF & m_data[8 * offset + 4]) << 24); + } + + inline void set_lo32(size_t offset, uint32_t value) + { + m_data[offset * 8 + 4] = ((value >> 24) & 0xFF); + m_data[offset * 8 + 5] = ((value >> 16) & 0xFF); + m_data[offset * 8 + 6] = ((value >> 8) & 0xFF); + m_data[offset * 8 + 7] = ((value ) & 0xFF); + } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.cpp new file mode 100644 index 0000000000..9a3fe085ab --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.cpp @@ -0,0 +1,74 @@ +/* + * XMSS Common Ops + * Operations shared by XMSS signature generation and verification operations. + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include + +namespace Botan { + +void +XMSS_Common_Ops::randomize_tree_hash(secure_vector& result, + const secure_vector& left, + const secure_vector& right, + XMSS_Address& adrs, + const secure_vector& seed, + XMSS_Hash& hash, + const XMSS_Parameters& params) + { + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode); + secure_vector key { hash.prf(seed, adrs.bytes()) }; + + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_MSB_Mode); + secure_vector bitmask_l { hash.prf(seed, adrs.bytes()) }; + + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_LSB_Mode); + secure_vector bitmask_r { hash.prf(seed, adrs.bytes()) }; + + BOTAN_ASSERT(bitmask_l.size() == left.size() && + bitmask_r.size() == right.size(), + "Bitmask size doesn't match node size."); + + secure_vector concat_xor(params.element_size() * 2); + for(size_t i = 0; i < left.size(); i++) + { + concat_xor[i] = left[i] ^ bitmask_l[i]; + concat_xor[i + left.size()] = right[i] ^ bitmask_r[i]; + } + + hash.h(result, key, concat_xor); + } + + +void +XMSS_Common_Ops::create_l_tree(secure_vector& result, + wots_keysig_t pk, + XMSS_Address& adrs, + const secure_vector& seed, + XMSS_Hash& hash, + const XMSS_Parameters& params) + { + size_t l = params.len(); + adrs.set_tree_height(0); + + while(l > 1) + { + for(size_t i = 0; i < l >> 1; i++) + { + adrs.set_tree_index(static_cast(i)); + randomize_tree_hash(pk[i], pk[2 * i], pk[2 * i + 1], adrs, seed, hash, params); + } + if(l & 0x01) + { + pk[l >> 1] = pk[l - 1]; + } + l = (l >> 1) + (l & 0x01); + adrs.set_tree_height(adrs.get_tree_height() + 1); + } + result = pk[0]; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.h new file mode 100644 index 0000000000..77fdc9dc1e --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_common_ops.h @@ -0,0 +1,83 @@ +/* + * XMSS Common Ops + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_COMMON_OPS_H_ +#define BOTAN_XMSS_COMMON_OPS_H_ + +#include +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(xmss_common_ops.h) + +namespace Botan { + +typedef std::vector> wots_keysig_t; + +/** + * Operations shared by XMSS signature generation and verification operations. + **/ +class XMSS_Common_Ops + { + public: + /** + * Algorithm 7: "RAND_HASH" + * + * Generates a randomized hash. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each + * thread. + * + * @param[out] result The resulting randomized hash. + * @param[in] left Left half of the hash function input. + * @param[in] right Right half of the hash function input. + * @param[in] adrs Adress of the hash function call. + * @param[in] seed The seed for G. + * @param[in] hash Instance of XMSS_Hash, that may only by the thead + * executing generate_public_key. + * @param[in] params + **/ + static void randomize_tree_hash( + secure_vector& result, + const secure_vector& left, + const secure_vector& right, + XMSS_Address& adrs, + const secure_vector& seed, + XMSS_Hash& hash, + const XMSS_Parameters& params); + + /** + * Algorithm 8: "ltree" + * Create an L-tree used to compute the leaves of the binary hash tree. + * Takes a WOTS+ public key and compresses it to a single n-byte value. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each thread. + * + * @param[out] result Public key compressed to a single n-byte value + * pk[0]. + * @param[in] pk Winternitz One Time Signatures+ public key. + * @param[in] adrs Address encoding the address of the L-Tree + * @param[in] seed The seed generated during the public key generation. + * @param[in] hash Instance of XMSS_Hash, that may only be used by the + * thead executing create_l_tree. + * @param[in] params + **/ + static void create_l_tree(secure_vector& result, + wots_keysig_t pk, + XMSS_Address& adrs, + const secure_vector& seed, + XMSS_Hash& hash, + const XMSS_Parameters& params); + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.cpp new file mode 100644 index 0000000000..cd714873ca --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.cpp @@ -0,0 +1,80 @@ +/* + * XMSS Hash + * A collection of pseudorandom hash functions required for XMSS and WOTS + * computations. + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include + +namespace Botan { + +XMSS_Hash::XMSS_Hash(const XMSS_Hash& hash) + : XMSS_Hash(hash.m_hash_func_name) + { + } + +XMSS_Hash::XMSS_Hash(const std::string& h_func_name) : + m_hash(HashFunction::create(h_func_name)), + m_hash_func_name(h_func_name) + { + if(!m_hash) + throw Lookup_Error("XMSS cannot use hash " + h_func_name + + " because it is unavailable"); + + m_output_length = m_hash->output_length(); + BOTAN_ASSERT(m_output_length > 0, "Hash output length of zero is invalid."); + + m_zero_padding.resize(m_output_length - 1); + m_msg_hash.reset(m_hash->clone()); + } + +void +XMSS_Hash::h(secure_vector& result, + const secure_vector& key, + const secure_vector& data) + { + m_hash->update(m_zero_padding); + m_hash->update(m_id_h); + m_hash->update(key); + m_hash->update(data); + m_hash->final(result); + } + +void XMSS_Hash::h_msg_init(const secure_vector& randomness, + const secure_vector& root, + const secure_vector& index_bytes) + { + m_msg_hash->clear(); + m_msg_hash->update(m_zero_padding); + m_msg_hash->update(m_id_hmsg); + m_msg_hash->update(randomness); + m_msg_hash->update(root); + m_msg_hash->update(index_bytes); + } + +void XMSS_Hash::h_msg_update(const uint8_t data[], size_t size) + { + m_msg_hash->update(data, size); + } + +secure_vector XMSS_Hash::h_msg_final() + { + return m_msg_hash->final(); + } + +secure_vector +XMSS_Hash::h_msg(const secure_vector& randomness, + const secure_vector& root, + const secure_vector& index_bytes, + const secure_vector& data) + { + h_msg_init(randomness, root, index_bytes); + m_msg_hash->update(data); + return m_msg_hash->final(); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.h new file mode 100644 index 0000000000..5d8cbab538 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_hash.h @@ -0,0 +1,156 @@ +/* + * XMSS Hash + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_HASH_H_ +#define BOTAN_XMSS_HASH_H_ + +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(xmss_hash.h) + +namespace Botan { + +/** + * A collection of pseudorandom hash functions required for XMSS and WOTS + * computations. + **/ +class XMSS_Hash final + { + public: + XMSS_Hash(const std::string& h_func_name); + XMSS_Hash(const XMSS_Hash& hash); + + /** + * Pseudoranom function creating a hash out of a key and data using + * a cryptographic hash function. + * + * @param[out] result The hash calculated using key and data. + * @param[in] key An n-byte key value. + * @param[in] data A 32-byte XMSS_Address data value + **/ + inline void prf(secure_vector& result, + const secure_vector& key, + const secure_vector& data) + { + m_hash->update(m_zero_padding); + m_hash->update(m_id_prf); + m_hash->update(key); + m_hash->update(data); + m_hash->final(result); + } + + /** + * Pseudoranom function creating a hash out of a key and data using + * a cryptographic hash function. + * + * @param[in] key An n-byte key value. + * @param[in] data A 32-byte XMSS_Address data value + * @return result The hash calculated using key and data. + **/ + inline secure_vector prf(const secure_vector& key, + const secure_vector& data) + { + m_hash->update(m_zero_padding); + m_hash->update(m_id_prf); + m_hash->update(key); + m_hash->update(data); + return m_hash->final(); + } + + /** + * F is a keyed cryptographic hash function used by the WOTS+ algorithm. + * + * @param[out] result The hash calculated using key and data. + * @param[in] key key of length n bytes. + * @param[in] data string of arbitrary length. + **/ + void f(secure_vector& result, + const secure_vector& key, + const secure_vector& data) + { + m_hash->update(m_zero_padding); + m_hash->update(m_id_f); + m_hash->update(key); + m_hash->update(data); + m_hash->final(result); + } + + /** + * Cryptographic hash function h accepting n byte keys and 2n byte + * strings of data. + * + * @param[out] result The hash calculated using key and data. + * @param[in] key key of length n bytes. + * @param[in] data string of 2n bytes length. + **/ + void h(secure_vector& result, + const secure_vector& key, + const secure_vector& data); + + /** + * Cryptographic hash function h accepting 3n byte keys and data + * strings of arbitrary length. + * + * @param randomness n-byte value. + * @param root n-byte root node. + * @param index_bytes Index value padded with leading zeros. + * @param data string of arbitrary length. + * + * @return hash value of n-bytes length. + **/ + secure_vector h_msg(const secure_vector& randomness, + const secure_vector& root, + const secure_vector& index_bytes, + const secure_vector& data); + + /** + * Initializes buffered h_msg computation with prefix data. + * + * @param randomness random n-byte value. + * @param root n-byte root node. + * @param index_bytes Index value padded with leading zeros. + **/ + void h_msg_init(const secure_vector& randomness, + const secure_vector& root, + const secure_vector& index_bytes); + + /** + * Adds a message block to buffered h_msg computation. + * + * @param data A message block + * @param size Length of the message block in bytes. + **/ + void h_msg_update(const uint8_t data[], size_t size); + + /** + * Finalizes buffered h_msg computation and retrieves the result. + * + * @return Hash calculated using the prefix set by h_msg_init() and + * message blocks provided through calls to h_msg_update(). + **/ + secure_vector h_msg_final(); + + size_t output_length() const { return m_output_length; } + + private: + static const uint8_t m_id_f = 0x00; + static const uint8_t m_id_h = 0x01; + static const uint8_t m_id_hmsg = 0x02; + static const uint8_t m_id_prf = 0x03; + + std::unique_ptr m_hash; + std::unique_ptr m_msg_hash; + //32 byte id prefixes prepended to the hash input. + std::vector m_zero_padding; + size_t m_output_length; + const std::string m_hash_func_name; + + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.cpp new file mode 100644 index 0000000000..8709d8026f --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.cpp @@ -0,0 +1,84 @@ +/* + * XMSS Index Registry + * A registry for XMSS private keys, keeps track of the leaf index for + * independend copies of the same key. + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include + +namespace Botan { + +const std::string XMSS_Index_Registry::m_index_hash_function = "SHA-256"; + +uint64_t XMSS_Index_Registry::make_key_id( + const secure_vector& private_seed, + const secure_vector& prf) const + { + std::unique_ptr hash = + HashFunction::create(m_index_hash_function); + BOTAN_ASSERT(hash != nullptr, "XMSS_Index_Registry requires SHA-256"); + hash->update(private_seed); + hash->update(prf); + secure_vector result = hash->final(); + uint64_t key_id = 0; + for(size_t i = 0; i < sizeof(key_id); i++) + { + key_id = ((key_id << 8) | result[i]); + } + + return key_id; + } + +std::shared_ptr> +XMSS_Index_Registry::get(const secure_vector& private_seed, + const secure_vector& prf) + { + size_t pos = get(make_key_id(private_seed, prf)); + + if(pos < std::numeric_limits::max()) + { + return m_leaf_indices[pos]; + } + else + { + return m_leaf_indices[add(make_key_id(private_seed, prf))]; + } + } + +size_t XMSS_Index_Registry::get(uint64_t id) const + { + for(size_t i = 0; i < m_key_ids.size(); i++) + { + if(m_key_ids[i] == id) + { + return i; + } + } + + return std::numeric_limits::max(); + } + +size_t XMSS_Index_Registry::add(uint64_t id, size_t last_unused) + { + lock_guard_type lock(m_mutex); + size_t pos = get(id); + if(pos < m_key_ids.size()) + { + if(last_unused > *(m_leaf_indices[pos])) + { + m_leaf_indices[pos] = std::make_shared>(last_unused); + } + return pos; + } + + m_key_ids.push_back(id); + m_leaf_indices.push_back(std::make_shared>(last_unused)); + return m_key_ids.size() - 1; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.h new file mode 100644 index 0000000000..91166db4ba --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_index_registry.h @@ -0,0 +1,105 @@ +/* + * XMSS Index Registry + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_INDEX_REGISTRY_H_ +#define BOTAN_XMSS_INDEX_REGISTRY_H_ + +#include + +#include +#include +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(xmss_index_registry.h) + +namespace Botan { + +/** + * A registry for XMSS private keys, keeps track of the leaf index for + * independend copies of the same key. + **/ +class XMSS_Index_Registry final + { + public: + XMSS_Index_Registry(const XMSS_Index_Registry&) = delete; + XMSS_Index_Registry& operator=(const XMSS_Index_Registry&) = delete; + + /** + * Retrieves a handle to the process-wide unique XMSS index registry. + * + * @return Reference to unique XMSS index registry. + **/ + static XMSS_Index_Registry& get_instance() + { + static XMSS_Index_Registry self; + return self; + } + + /** + * Retrieves the last unused leaf index for the private key identified + * by private_seed and prf. The leaf index will be updated properly + * across independent copies of private_key. + * + * @param private_seed Part of the unique identifier for an + * XMSS_PrivateKey. + * @param prf Part of the unique identifier for an XMSS_PrivateKey. + * + * @return last unused leaf index for private_key. + **/ + std::shared_ptr> + get(const secure_vector& private_seed, + const secure_vector& prf); + + private: + XMSS_Index_Registry() = default; + + static const std::string m_index_hash_function; + + /** + * Creates a unique 64-bit id for an XMSS_Private key, by interpreting + * the first 64-bit of HASH(PRIVATE_SEED || PRF) as 64 bit integer + * value. + * + * @return unique integral identifier for an XMSS private key. + **/ + uint64_t make_key_id(const secure_vector& private_seed, + const secure_vector& prf) const; + + /** + * Retrieves the index position of a key within the registry or + * max(size_t) if key has not been found. + * + * @param id unique id of the XMSS private key (see make_key_id()). + * + * @return index position of key or max(size_t) if key not found. + **/ + size_t get(uint64_t id) const; + + /** + * If XMSS_PrivateKey identified by id is already registered, the + * position of the according registry entry is returned. If last_unused + * is bigger than the last unused index stored for the key identified by + * id the unused leaf index for this key is set to last_unused. If no key + * matching id is registed yet, an entry of id is added, with the last + * unused leaf index initialized to the value of last_unused. + * + * @last_unused Initial value for the last unused leaf index of the + * registered key. + * + * @return positon of leaf index registry entry for key identified + * by id. + **/ + size_t add(uint64_t id, size_t last_unused = 0); + + std::vector m_key_ids; + std::vector>> m_leaf_indices; + mutex_type m_mutex; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_key_pair.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_key_pair.h new file mode 100644 index 0000000000..19e23c7776 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_key_pair.h @@ -0,0 +1,49 @@ +/* + * XMSS Key Pair + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_KEY_PAIR_H_ +#define BOTAN_XMSS_KEY_PAIR_H_ + +#include + +BOTAN_DEPRECATED_HEADER(xmss_key_pair.h) + +namespace Botan { + +/** + * A pair of XMSS public and private key. + **/ +class BOTAN_PUBLIC_API(2,0) XMSS_Key_Pair + { + public: + XMSS_Key_Pair(XMSS_Parameters::xmss_algorithm_t xmss_oid, + RandomNumberGenerator& rng) + : m_priv_key(xmss_oid, rng), m_pub_key(m_priv_key) {} + + XMSS_Key_Pair(const XMSS_PublicKey& pub_key, + const XMSS_PrivateKey& priv_key) + : m_priv_key(priv_key), m_pub_key(pub_key) + {} + + XMSS_Key_Pair(XMSS_PublicKey&& pub_key, + XMSS_PrivateKey&& priv_key) + : m_priv_key(std::move(priv_key)), m_pub_key(std::move(pub_key)) {} + + const XMSS_PublicKey& public_key() const { return m_pub_key; } + XMSS_PublicKey& public_key() { return m_pub_key; } + + const XMSS_PrivateKey& private_key() const { return m_priv_key; } + XMSS_PrivateKey& private_key() { return m_priv_key; } + + private: + XMSS_PrivateKey m_priv_key; + XMSS_PublicKey m_pub_key; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.cpp new file mode 100644 index 0000000000..55084c8b92 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.cpp @@ -0,0 +1,184 @@ +/* + * XMSS Parameters + * Descibes a signature method for XMSS, as defined in: + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + * + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include + +namespace Botan { + +XMSS_Parameters::xmss_algorithm_t XMSS_Parameters::xmss_id_from_string(const std::string& param_set) + { + if(param_set == "XMSS-SHA2_10_256") + { return XMSS_SHA2_10_256; } + if(param_set == "XMSS-SHA2_16_256") + { return XMSS_SHA2_16_256; } + if(param_set == "XMSS-SHA2_20_256") + { return XMSS_SHA2_20_256; } + if(param_set == "XMSS-SHA2_10_512") + { return XMSS_SHA2_10_512; } + if(param_set == "XMSS-SHA2_16_512") + { return XMSS_SHA2_16_512; } + if(param_set == "XMSS-SHA2_20_512") + { return XMSS_SHA2_20_512; } + if(param_set == "XMSS-SHAKE_10_256") + { return XMSS_SHAKE_10_256; } + if(param_set == "XMSS-SHAKE_16_256") + { return XMSS_SHAKE_16_256; } + if(param_set == "XMSS-SHAKE_20_256") + { return XMSS_SHAKE_20_256; } + if(param_set == "XMSS-SHAKE_10_512") + { return XMSS_SHAKE_10_512; } + if(param_set == "XMSS-SHAKE_16_512") + { return XMSS_SHAKE_16_512; } + if(param_set == "XMSS-SHAKE_20_512") + { return XMSS_SHAKE_20_512; } + throw Lookup_Error("Unknown XMSS algorithm param '" + param_set + "'"); + } + +XMSS_Parameters::XMSS_Parameters(const std::string& param_set) + : XMSS_Parameters(XMSS_Parameters::xmss_id_from_string(param_set)) + { + } + +XMSS_Parameters::XMSS_Parameters(xmss_algorithm_t oid) + : m_oid(oid) + { + switch(oid) + { + case XMSS_SHA2_10_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 10; + m_name = "XMSS-SHA2_10_256"; + m_hash_name = "SHA-256"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_256; + break; + case XMSS_SHA2_16_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 16; + m_name = "XMSS-SHA2_16_256"; + m_hash_name = "SHA-256"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_256; + break; + case XMSS_SHA2_20_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 20; + m_name = "XMSS-SHA2_20_256"; + m_hash_name = "SHA-256"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_256; + break; + case XMSS_SHA2_10_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 10; + m_name = "XMSS-SHA2_10_512"; + m_hash_name = "SHA-512"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512; + break; + case XMSS_SHA2_16_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 16; + m_name = "XMSS-SHA2_16_512"; + m_hash_name = "SHA-512"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512; + break; + case XMSS_SHA2_20_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 20; + m_name = "XMSS-SHA2_20_512"; + m_hash_name = "SHA-512"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHA2_512; + break; + case XMSS_SHAKE_10_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 10; + m_name = "XMSS-SHAKE_10_256"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_256; + break; + case XMSS_SHAKE_16_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 16; + m_name = "XMSS-SHAKE_16_256"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_256; + break; + case XMSS_SHAKE_20_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_tree_height = 20; + m_name = "XMSS-SHAKE_20_256"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_256; + break; + case XMSS_SHAKE_10_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 10; + m_name = "XMSS-SHAKE_10_512"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_512; + break; + case XMSS_SHAKE_16_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 16; + m_name = "XMSS-SHAKE_16_512"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_512; + break; + case XMSS_SHAKE_20_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_tree_height = 20; + m_name = "XMSS-SHAKE_20_512"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE_512; + break; + default: + throw Not_Implemented("Algorithm id does not match any known XMSS algorithm id:" + std::to_string(oid)); + break; + } + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.h new file mode 100644 index 0000000000..2f186ac53b --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_parameters.h @@ -0,0 +1,119 @@ +/* + * XMSS Parameters + * (C) 2016,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_PARAMETERS_H_ +#define BOTAN_XMSS_PARAMETERS_H_ + +#include +#include + +namespace Botan { + +/** + * Descibes a signature method for XMSS, as defined in: + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + **/ +class BOTAN_PUBLIC_API(2,0) XMSS_Parameters + { + public: + enum xmss_algorithm_t + { + XMSS_SHA2_10_256 = 0x00000001, + XMSS_SHA2_16_256 = 0x00000002, + XMSS_SHA2_20_256 = 0x00000003, + XMSS_SHA2_10_512 = 0x00000004, + XMSS_SHA2_16_512 = 0x00000005, + XMSS_SHA2_20_512 = 0x00000006, + XMSS_SHAKE_10_256 = 0x00000007, + XMSS_SHAKE_16_256 = 0x00000008, + XMSS_SHAKE_20_256 = 0x00000009, + XMSS_SHAKE_10_512 = 0x0000000a, + XMSS_SHAKE_16_512 = 0x0000000b, + XMSS_SHAKE_20_512 = 0x0000000c + }; + + static xmss_algorithm_t xmss_id_from_string(const std::string& algo_name); + + XMSS_Parameters(const std::string& algo_name); + XMSS_Parameters(xmss_algorithm_t oid); + + /** + * @return XMSS registry name for the chosen parameter set. + **/ + const std::string& name() const + { + return m_name; + } + + const std::string& hash_function_name() const + { + return m_hash_name; + } + + /** + * Retrieves the uniform length of a message, and the size of + * each node. This correlates to XMSS parameter "n" defined + * in [1]. + * + * @return element length in bytes. + **/ + size_t element_size() const { return m_element_size; } + + /** + * @returns The height (number of levels - 1) of the tree + **/ + size_t tree_height() const { return m_tree_height; } + + /** + * The Winternitz parameter. + * + * @return numeric base used for internal representation of + * data. + **/ + size_t wots_parameter() const { return m_w; } + + size_t len() const { return m_len; } + + xmss_algorithm_t oid() const { return m_oid; } + + XMSS_WOTS_Parameters::ots_algorithm_t ots_oid() const + { + return m_wots_oid; + } + + /** + * Returns the estimated pre-quantum security level of + * the chosen algorithm. + **/ + size_t estimated_strength() const + { + return m_strength; + } + + bool operator==(const XMSS_Parameters& p) const + { + return m_oid == p.m_oid; + } + + private: + xmss_algorithm_t m_oid; + XMSS_WOTS_Parameters::ots_algorithm_t m_wots_oid; + std::string m_name; + std::string m_hash_name; + size_t m_element_size; + size_t m_tree_height; + size_t m_w; + size_t m_len; + size_t m_strength; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.cpp new file mode 100644 index 0000000000..c497be003a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.cpp @@ -0,0 +1,405 @@ +/* + * XMSS Private Key + * An XMSS: Extended Hash-Based Siganture private key. + * The XMSS private key does not support the X509 and PKCS7 standard. Instead + * the raw format described in [1] is used. + * + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + * + * (C) 2016,2017,2018 Matthias Gierlings + * (C) 2019 Jack Lloyd + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_THREAD_UTILS) + #include +#endif + +namespace Botan { + +namespace { + +// fall back to raw decoding for previous versions, which did not encode an OCTET STRING +secure_vector extract_raw_key(const secure_vector& key_bits) + { + secure_vector raw_key; + try + { + BER_Decoder(key_bits).decode(raw_key, OCTET_STRING); + } + catch(Decoding_Error&) + { + raw_key = key_bits; + } + return raw_key; + } + +} + +XMSS_PrivateKey::XMSS_PrivateKey(const secure_vector& key_bits) + : XMSS_PublicKey(unlock(key_bits)), + m_wots_priv_key(m_wots_params.oid(), m_public_seed), + m_hash(xmss_hash_function()), + m_index_reg(XMSS_Index_Registry::get_instance()) + { + /* + The code requires sizeof(size_t) >= ceil(tree_height / 8) + + Maximum supported tree height is 20, ceil(20/8) == 3, so 4 byte + size_t is sufficient for all defined parameters, or even a + (hypothetical) tree height 32, which would be extremely slow to + compute. + */ + static_assert(sizeof(size_t) >= 4, "size_t is big enough to support leaf index"); + + secure_vector raw_key = extract_raw_key(key_bits); + + if(raw_key.size() != XMSS_PrivateKey::size()) + { + throw Decoding_Error("Invalid XMSS private key size"); + } + + // extract & copy unused leaf index from raw_key + uint64_t unused_leaf = 0; + auto begin = (raw_key.begin() + XMSS_PublicKey::size()); + auto end = raw_key.begin() + XMSS_PublicKey::size() + sizeof(uint32_t); + + for(auto& i = begin; i != end; i++) + { + unused_leaf = ((unused_leaf << 8) | *i); + } + + if(unused_leaf >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) + { + throw Decoding_Error("XMSS private key leaf index out of bounds"); + } + + begin = end; + end = begin + XMSS_PublicKey::m_xmss_params.element_size(); + m_prf.clear(); + m_prf.reserve(XMSS_PublicKey::m_xmss_params.element_size()); + std::copy(begin, end, std::back_inserter(m_prf)); + + begin = end; + end = begin + m_wots_params.element_size(); + m_wots_priv_key.set_private_seed(secure_vector(begin, end)); + set_unused_leaf_index(static_cast(unused_leaf)); + } + +XMSS_PrivateKey::XMSS_PrivateKey( + XMSS_Parameters::xmss_algorithm_t xmss_algo_id, + RandomNumberGenerator& rng) + : XMSS_PublicKey(xmss_algo_id, rng), + m_wots_priv_key(XMSS_PublicKey::m_xmss_params.ots_oid(), + public_seed(), + rng), + m_hash(xmss_hash_function()), + m_prf(rng.random_vec(XMSS_PublicKey::m_xmss_params.element_size())), + m_index_reg(XMSS_Index_Registry::get_instance()) + { + XMSS_Address adrs; + set_root(tree_hash(0, + XMSS_PublicKey::m_xmss_params.tree_height(), + adrs)); + } + + +XMSS_PrivateKey::XMSS_PrivateKey(XMSS_Parameters::xmss_algorithm_t xmss_algo_id, + size_t idx_leaf, + const secure_vector& wots_priv_seed, + const secure_vector& prf, + const secure_vector& root, + const secure_vector& public_seed) + : XMSS_PublicKey(xmss_algo_id, root, public_seed), + m_wots_priv_key(XMSS_PublicKey::m_xmss_params.ots_oid(), + public_seed, + wots_priv_seed), + m_hash(XMSS_PublicKey::m_xmss_params.hash_function_name()), + m_prf(prf), + m_index_reg(XMSS_Index_Registry::get_instance()) + { + set_unused_leaf_index(idx_leaf); + } + +secure_vector +XMSS_PrivateKey::tree_hash(size_t start_idx, + size_t target_node_height, + XMSS_Address& adrs) + { + BOTAN_ASSERT_NOMSG(target_node_height <= 30); + BOTAN_ASSERT((start_idx % (static_cast(1) << target_node_height)) == 0, + "Start index must be divisible by 2^{target node height}."); + +#if defined(BOTAN_HAS_THREAD_UTILS) + // dertermine number of parallel tasks to split the tree_hashing into. + + Thread_Pool& thread_pool = Thread_Pool::global_instance(); + + const size_t split_level = std::min(target_node_height, thread_pool.worker_count()); + + // skip parallelization overhead for leaf nodes. + if(split_level == 0) + { + secure_vector result; + tree_hash_subtree(result, start_idx, target_node_height, adrs); + return result; + } + + const size_t subtrees = static_cast(1) << split_level; + const size_t last_idx = (static_cast(1) << (target_node_height)) + start_idx; + const size_t offs = (last_idx - start_idx) / subtrees; + // this cast cannot overflow because target_node_height is limited + uint8_t level = static_cast(split_level); // current level in the tree + + BOTAN_ASSERT((last_idx - start_idx) % subtrees == 0, + "Number of worker threads in tree_hash need to divide range " + "of calculated nodes."); + + std::vector> nodes( + subtrees, + secure_vector(XMSS_PublicKey::m_xmss_params.element_size())); + std::vector node_addresses(subtrees, adrs); + std::vector xmss_hash(subtrees, m_hash); + std::vector> work; + + // Calculate multiple subtrees in parallel. + for(size_t i = 0; i < subtrees; i++) + { + using tree_hash_subtree_fn_t = + void (XMSS_PrivateKey::*)(secure_vector&, + size_t, + size_t, + XMSS_Address&, + XMSS_Hash&); + + tree_hash_subtree_fn_t work_fn = &XMSS_PrivateKey::tree_hash_subtree; + + work.push_back(thread_pool.run( + work_fn, + this, + std::ref(nodes[i]), + start_idx + i * offs, + target_node_height - split_level, + std::ref(node_addresses[i]), + std::ref(xmss_hash[i]))); + } + + for(auto& w : work) + { + w.get(); + } + work.clear(); + + // Parallelize the top tree levels horizontally + while(level-- > 1) + { + std::vector> ro_nodes( + nodes.begin(), nodes.begin() + (static_cast(1) << (level+1))); + + for(size_t i = 0; i < (static_cast(1) << level); i++) + { + BOTAN_ASSERT_NOMSG(xmss_hash.size() > i); + + node_addresses[i].set_tree_height(static_cast(target_node_height - (level + 1))); + node_addresses[i].set_tree_index( + (node_addresses[2 * i + 1].get_tree_index() - 1) >> 1); + + work.push_back(thread_pool.run( + &XMSS_Common_Ops::randomize_tree_hash, + std::ref(nodes[i]), + std::cref(ro_nodes[2 * i]), + std::cref(ro_nodes[2 * i + 1]), + std::ref(node_addresses[i]), + std::cref(this->public_seed()), + std::ref(xmss_hash[i]), + std::cref(m_xmss_params))); + } + + for(auto &w : work) + { + w.get(); + } + work.clear(); + } + + // Avoid creation an extra thread to calculate root node. + node_addresses[0].set_tree_height(static_cast(target_node_height - 1)); + node_addresses[0].set_tree_index( + (node_addresses[1].get_tree_index() - 1) >> 1); + XMSS_Common_Ops::randomize_tree_hash(nodes[0], + nodes[0], + nodes[1], + node_addresses[0], + this->public_seed(), + m_hash, + m_xmss_params); + return nodes[0]; +#else + secure_vector result; + tree_hash_subtree(result, start_idx, target_node_height, adrs, m_hash); + return result; +#endif + } + +void +XMSS_PrivateKey::tree_hash_subtree(secure_vector& result, + size_t start_idx, + size_t target_node_height, + XMSS_Address& adrs, + XMSS_Hash& hash) + { + const secure_vector& seed = this->public_seed(); + + std::vector> nodes( + target_node_height + 1, + secure_vector(XMSS_PublicKey::m_xmss_params.element_size())); + + // node stack, holds all nodes on stack and one extra "pending" node. This + // temporary node referred to as "node" in the XMSS standard document stays + // a pending element, meaning it is not regarded as element on the stack + // until level is increased. + std::vector node_levels(target_node_height + 1); + + uint8_t level = 0; // current level on the node stack. + XMSS_WOTS_PublicKey pk(m_wots_priv_key.wots_parameters().oid(), seed); + const size_t last_idx = (static_cast(1) << target_node_height) + start_idx; + + for(size_t i = start_idx; i < last_idx; i++) + { + adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); + adrs.set_ots_address(static_cast(i)); + this->wots_private_key().generate_public_key( + pk, + // getWOTS_SK(SK, s + i), reference implementation uses adrs + // instead of zero padded index s + i. + this->wots_private_key().at(adrs, hash), + adrs, + hash); + adrs.set_type(XMSS_Address::Type::LTree_Address); + adrs.set_ltree_address(static_cast(i)); + XMSS_Common_Ops::create_l_tree(nodes[level], pk, adrs, seed, hash, m_xmss_params); + node_levels[level] = 0; + + adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); + adrs.set_tree_height(0); + adrs.set_tree_index(static_cast(i)); + + while(level > 0 && node_levels[level] == + node_levels[level - 1]) + { + adrs.set_tree_index(((adrs.get_tree_index() - 1) >> 1)); + XMSS_Common_Ops::randomize_tree_hash(nodes[level - 1], + nodes[level - 1], + nodes[level], + adrs, + seed, + hash, + m_xmss_params); + node_levels[level - 1]++; + level--; //Pop stack top element + adrs.set_tree_height(adrs.get_tree_height() + 1); + } + level++; //push temporary node to stack + } + result = nodes[level - 1]; + } + +secure_vector XMSS_PrivateKey::private_key_bits() const + { + return DER_Encoder().encode(raw_private_key(), OCTET_STRING).get_contents(); + } + +std::shared_ptr> +XMSS_PrivateKey::recover_global_leaf_index() const + { + BOTAN_ASSERT(m_wots_priv_key.private_seed().size() == + XMSS_PublicKey::m_xmss_params.element_size() && + m_prf.size() == XMSS_PublicKey::m_xmss_params.element_size(), + "Trying to retrieve index for partially initialized key"); + return m_index_reg.get(m_wots_priv_key.private_seed(), m_prf); + } + +void XMSS_PrivateKey::set_unused_leaf_index(size_t idx) + { + if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) + { + throw Decoding_Error("XMSS private key leaf index out of bounds"); + } + else + { + std::atomic& index = + static_cast&>(*recover_global_leaf_index()); + size_t current = 0; + + do + { + current = index.load(); + if(current > idx) + { return; } + } + while(!index.compare_exchange_strong(current, idx)); + } + } + +size_t XMSS_PrivateKey::reserve_unused_leaf_index() + { + size_t idx = (static_cast&>( + *recover_global_leaf_index())).fetch_add(1); + if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) + { + throw Decoding_Error("XMSS private key, one time signatures exhaused"); + } + return idx; + } + +size_t XMSS_PrivateKey::unused_leaf_index() const + { + return *recover_global_leaf_index(); + } + +secure_vector XMSS_PrivateKey::raw_private_key() const + { + std::vector pk { raw_public_key() }; + secure_vector result(pk.begin(), pk.end()); + result.reserve(size()); + + for(int i = 3; i >= 0; i--) + { + result.push_back( + static_cast( + static_cast(unused_leaf_index()) >> 8 * i)); + } + + std::copy(m_prf.begin(), m_prf.end(), std::back_inserter(result)); + std::copy(m_wots_priv_key.private_seed().begin(), + m_wots_priv_key.private_seed().end(), + std::back_inserter(result)); + + return result; + } + +std::unique_ptr +XMSS_PrivateKey::create_signature_op(RandomNumberGenerator&, + const std::string&, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr( + new XMSS_Signature_Operation(*this)); + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.h new file mode 100644 index 0000000000..dc040e4437 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_privatekey.h @@ -0,0 +1,13 @@ +/* + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_PRIVATEKEY_H_ +#define BOTAN_XMSS_PRIVATEKEY_H_ + +#include +BOTAN_DEPRECATED_HEADER(xmss_privatekey.h) + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.cpp new file mode 100644 index 0000000000..f6db6d5026 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.cpp @@ -0,0 +1,129 @@ +/* + * XMSS Public Key + * An XMSS: Extended Hash-Based Siganture public key. + * The XMSS public key does not support the X509 standard. Instead the + * raw format described in [1] is used. + * + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + * + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +// fall back to raw decoding for previous versions, which did not encode an OCTET STRING +std::vector extract_raw_key(const std::vector& key_bits) + { + std::vector raw_key; + try + { + BER_Decoder(key_bits).decode(raw_key, OCTET_STRING); + } + catch(Decoding_Error&) + { + raw_key = key_bits; + } + return raw_key; + } + +} + +XMSS_PublicKey::XMSS_PublicKey(XMSS_Parameters::xmss_algorithm_t xmss_oid, + RandomNumberGenerator& rng) + : m_xmss_params(xmss_oid), m_wots_params(m_xmss_params.ots_oid()), + m_root(m_xmss_params.element_size()), + m_public_seed(rng.random_vec(m_xmss_params.element_size())) + {} + +XMSS_PublicKey::XMSS_PublicKey(const std::vector& key_bits) + : m_raw_key(extract_raw_key(key_bits)), + m_xmss_params(XMSS_PublicKey::deserialize_xmss_oid(m_raw_key)), + m_wots_params(m_xmss_params.ots_oid()) + { + if(m_raw_key.size() < XMSS_PublicKey::size()) + { + throw Decoding_Error("Invalid XMSS public key size detected"); + } + + // extract & copy root from raw key + m_root.clear(); + m_root.reserve(m_xmss_params.element_size()); + auto begin = m_raw_key.begin() + sizeof(uint32_t); + auto end = begin + m_xmss_params.element_size(); + std::copy(begin, end, std::back_inserter(m_root)); + + // extract & copy public seed from raw key + begin = end; + end = begin + m_xmss_params.element_size(); + m_public_seed.clear(); + m_public_seed.reserve(m_xmss_params.element_size()); + std::copy(begin, end, std::back_inserter(m_public_seed)); + } + +XMSS_Parameters::xmss_algorithm_t +XMSS_PublicKey::deserialize_xmss_oid(const std::vector& raw_key) + { + if(raw_key.size() < 4) + { + throw Decoding_Error("XMSS signature OID missing."); + } + + // extract and convert algorithm id to enum type + uint32_t raw_id = 0; + for(size_t i = 0; i < 4; i++) + { raw_id = ((raw_id << 8) | raw_key[i]); } + + return static_cast(raw_id); + } + +std::unique_ptr +XMSS_PublicKey::create_verification_op(const std::string&, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + { + return std::unique_ptr( + new XMSS_Verification_Operation(*this)); + } + throw Provider_Not_Found(algo_name(), provider); + } + +std::vector XMSS_PublicKey::raw_public_key() const + { + std::vector result + { + static_cast(m_xmss_params.oid() >> 24), + static_cast(m_xmss_params.oid() >> 16), + static_cast(m_xmss_params.oid() >> 8), + static_cast(m_xmss_params.oid()) + }; + + std::copy(m_root.begin(), m_root.end(), std::back_inserter(result)); + std::copy(m_public_seed.begin(), + m_public_seed.end(), + std::back_inserter(result)); + + return result; + } + +std::vector XMSS_PublicKey::public_key_bits() const + { + std::vector output; + DER_Encoder(output).encode(raw_public_key(), OCTET_STRING); + return output; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.h new file mode 100644 index 0000000000..eba27fc95f --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_publickey.h @@ -0,0 +1,14 @@ +/* + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_PUBLICKEY_H_ +#define BOTAN_XMSS_PUBLICKEY_H_ + +#include +BOTAN_DEPRECATED_HEADER(xmss_publickey.h) + +#endif + diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.cpp new file mode 100644 index 0000000000..98fadff358 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.cpp @@ -0,0 +1,92 @@ +/* + * XMSS Signature + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include + +namespace Botan { + +XMSS_Signature::XMSS_Signature(XMSS_Parameters::xmss_algorithm_t oid, + const secure_vector& raw_sig) + : m_leaf_idx(0), m_randomness(0, 0x00), m_tree_sig() + { + XMSS_Parameters xmss_params(oid); + + if(raw_sig.size() != (xmss_params.len() + xmss_params.tree_height() + 1) + * xmss_params.element_size() + sizeof(uint32_t)) + { + throw Decoding_Error("XMSS signature size invalid."); + } + + for(size_t i = 0; i < 4; i++) + { m_leaf_idx = ((m_leaf_idx << 8) | raw_sig[i]); } + + if(m_leaf_idx >= (1ull << xmss_params.tree_height())) + { + throw Decoding_Error("XMSS signature leaf index out of bounds."); + } + + auto begin = raw_sig.begin() + sizeof(uint32_t); + auto end = begin + xmss_params.element_size(); + std::copy(begin, end, std::back_inserter(m_randomness)); + + for(size_t i = 0; i < xmss_params.len(); i++) + { + begin = end; + end = begin + xmss_params.element_size(); + m_tree_sig.ots_signature().push_back(secure_vector(0)); + m_tree_sig.ots_signature().back().reserve( + xmss_params.element_size()); + std::copy(begin, + end, + std::back_inserter(m_tree_sig.ots_signature().back())); + } + + for(size_t i = 0; i < xmss_params.tree_height(); i++) + { + begin = end; + end = begin + xmss_params.element_size(); + m_tree_sig.authentication_path().push_back(secure_vector(0)); + m_tree_sig.authentication_path().back().reserve( + xmss_params.element_size()); + std::copy(begin, + end, + std::back_inserter(m_tree_sig.authentication_path().back())); + } + } + +secure_vector XMSS_Signature::bytes() const + { + secure_vector result + { + static_cast(m_leaf_idx >> 24U), + static_cast(m_leaf_idx >> 16U), + static_cast(m_leaf_idx >> 8U), + static_cast(m_leaf_idx) + }; + + std::copy(m_randomness.begin(), + m_randomness.end(), + std::back_inserter(result)); + + for(const auto& sig : tree().ots_signature()) + { + std::copy(sig.begin(), + sig.end(), + std::back_inserter(result)); + } + + for(const auto& auth : tree().authentication_path()) + { + std::copy(auth.begin(), + auth.end(), + std::back_inserter(result)); + } + return result; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.h new file mode 100644 index 0000000000..d791dbedb8 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature.h @@ -0,0 +1,127 @@ +/* + * XMSS Signature + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_SIGNATURE_H_ +#define BOTAN_XMSS_SIGNATURE_H_ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class XMSS_Signature final + { + public: + /** + * Creates a signature from an XMSS signature method and a uint8_t sequence + * representing a raw signature. + * + * @param oid XMSS signature method + * @param raw_sig An XMSS signature serialized using + * XMSS_Signature::bytes(). + **/ + XMSS_Signature(XMSS_Parameters::xmss_algorithm_t oid, + const secure_vector& raw_sig); + + /** + * Creates an XMSS Signature from a leaf index used for signature + * generation, a random value and a tree signature. + * + * @param leaf_idx Leaf index used to generate the signature. + * @param randomness A random value. + * @param tree_sig A tree signature. + **/ + XMSS_Signature(size_t leaf_idx, + const secure_vector& randomness, + const XMSS_WOTS_PublicKey::TreeSignature& tree_sig) + : m_leaf_idx(leaf_idx), m_randomness(randomness), + m_tree_sig(tree_sig) {} + + /** + * Creates an XMSS Signature from a leaf index used for signature + * generation, a random value and a tree signature. + * + * @param leaf_idx Leaf index used to generate the signature. + * @param randomness A random value. + * @param tree_sig A tree signature. + **/ + XMSS_Signature(size_t leaf_idx, + secure_vector&& randomness, + XMSS_WOTS_PublicKey::TreeSignature&& tree_sig) + : m_leaf_idx(leaf_idx), m_randomness(std::move(randomness)), + m_tree_sig(std::move(tree_sig)) {} + + size_t unused_leaf_index() const { return m_leaf_idx; } + void set_unused_leaf_idx(size_t idx) { m_leaf_idx = idx; } + + const secure_vector randomness() const + { + return m_randomness; + } + + secure_vector& randomness() + { + return m_randomness; + } + + void set_randomness(const secure_vector& randomness) + { + m_randomness = randomness; + } + + void set_randomness(secure_vector&& randomness) + { + m_randomness = std::move(randomness); + } + + const XMSS_WOTS_PublicKey::TreeSignature& tree() const + { + return m_tree_sig; + } + + XMSS_WOTS_PublicKey::TreeSignature& tree() + { + return m_tree_sig; + } + + void set_tree(const XMSS_WOTS_PublicKey::TreeSignature& tree_sig) + { + m_tree_sig = tree_sig; + } + + void set_tree(XMSS_WOTS_PublicKey::TreeSignature&& tree_sig) + { + m_tree_sig = std::move(tree_sig); + } + + /** + * Generates a serialized representation of XMSS Signature by + * concatenating the following elements in order: + * 4-byte leaf index, n-bytes randomness, ots_signature, + * authentication path. + * + * n is the element_size(), len equal to len(), h the tree height + * defined by the chosen XMSS signature method. + * + * @return serialized signature, a sequence of + * 4+(len + h + 1)n bytes. + **/ + secure_vector bytes() const; + + private: + size_t m_leaf_idx; + secure_vector m_randomness; + XMSS_WOTS_PublicKey::TreeSignature m_tree_sig; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.cpp new file mode 100644 index 0000000000..49f1041d90 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.cpp @@ -0,0 +1,120 @@ +/* + * XMSS Signature Operation + * Signature generation operation for Extended Hash-Based Signatures (XMSS) as + * defined in: + * + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + * + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include + +namespace Botan { + +XMSS_Signature_Operation::XMSS_Signature_Operation( + const XMSS_PrivateKey& private_key) : + m_priv_key(private_key), + m_xmss_params(private_key.xmss_oid()), + m_hash(private_key.xmss_hash_function()), + m_randomness(0), + m_leaf_idx(0), + m_is_initialized(false) + {} + +XMSS_WOTS_PublicKey::TreeSignature +XMSS_Signature_Operation::generate_tree_signature(const secure_vector& msg, + XMSS_PrivateKey& xmss_priv_key, + XMSS_Address& adrs) + { + + wots_keysig_t auth_path = build_auth_path(xmss_priv_key, adrs); + adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); + adrs.set_ots_address(m_leaf_idx); + + wots_keysig_t sig_ots = xmss_priv_key.wots_private_key().sign(msg, adrs); + return XMSS_WOTS_PublicKey::TreeSignature(sig_ots, auth_path); + } + +XMSS_Signature +XMSS_Signature_Operation::sign(const secure_vector& msg_hash, + XMSS_PrivateKey& xmss_priv_key) + { + XMSS_Address adrs; + XMSS_Signature sig(m_leaf_idx, + m_randomness, + generate_tree_signature(msg_hash, xmss_priv_key,adrs)); + return sig; + } + +size_t XMSS_Signature_Operation::signature_length() const + { + return sizeof(uint64_t) + // size of leaf index + m_xmss_params.element_size() + + m_xmss_params.len() * m_xmss_params.element_size() + + m_xmss_params.tree_height() * m_xmss_params.element_size(); + } + +wots_keysig_t +XMSS_Signature_Operation::build_auth_path(XMSS_PrivateKey& priv_key, + XMSS_Address& adrs) + { + wots_keysig_t auth_path(m_xmss_params.tree_height()); + adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); + + for(size_t j = 0; j < m_xmss_params.tree_height(); j++) + { + size_t k = (m_leaf_idx / (1ULL << j)) ^ 0x01; + auth_path[j] = priv_key.tree_hash(k * (1ULL << j), j, adrs); + } + + return auth_path; + } + +void XMSS_Signature_Operation::update(const uint8_t msg[], size_t msg_len) + { + initialize(); + m_hash.h_msg_update(msg, msg_len); + } + +secure_vector +XMSS_Signature_Operation::sign(RandomNumberGenerator&) + { + initialize(); + secure_vector signature(sign(m_hash.h_msg_final(), + m_priv_key).bytes()); + m_is_initialized = false; + return signature; + } + +void XMSS_Signature_Operation::initialize() + { + // return if we already initialized and reserved a leaf index for signing. + if(m_is_initialized) + { return; } + + secure_vector index_bytes; + // reserve leaf index so it can not be reused in by another signature + // operation using the same private key. + m_leaf_idx = static_cast(m_priv_key.reserve_unused_leaf_index()); + + // write prefix for message hashing into buffer. + XMSS_Tools::concat(index_bytes, m_leaf_idx, 32); + m_randomness = m_hash.prf(m_priv_key.prf(), index_bytes); + index_bytes.clear(); + XMSS_Tools::concat(index_bytes, m_leaf_idx, + m_priv_key.xmss_parameters().element_size()); + m_hash.h_msg_init(m_randomness, + m_priv_key.root(), + index_bytes); + m_is_initialized = true; + } + +} + diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.h new file mode 100644 index 0000000000..e6fb2c7114 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_signature_operation.h @@ -0,0 +1,89 @@ +/* + * XMSS Signature Operation + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_SIGNATURE_OPERATION_H_ +#define BOTAN_XMSS_SIGNATURE_OPERATION_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** + * Signature generation operation for Extended Hash-Based Signatures (XMSS) as + * defined in: + * + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + **/ +class XMSS_Signature_Operation final : public virtual PK_Ops::Signature + { + public: + XMSS_Signature_Operation(const XMSS_PrivateKey& private_key); + + /** + * Creates an XMSS signature for the message provided through call to + * update(). + * + * @return serialized XMSS signature. + **/ + secure_vector sign(RandomNumberGenerator&) override; + + void update(const uint8_t msg[], size_t msg_len) override; + + size_t signature_length() const override; + + private: + /** + * Algorithm 11: "treeSig" + * Generate a WOTS+ signature on a message with corresponding auth path. + * + * @param msg A message. + * @param xmss_priv_key A XMSS private key. + * @param adrs A XMSS Address. + **/ + XMSS_WOTS_PublicKey::TreeSignature generate_tree_signature( + const secure_vector& msg, + XMSS_PrivateKey& xmss_priv_key, + XMSS_Address& adrs); + + /** + * Algorithm 12: "XMSS_sign" + * Generate an XMSS signature and update the XMSS secret key + * + * @param msg A message to sign of arbitrary length. + * @param [out] xmss_priv_key A XMSS private key. The private key will be + * updated during the signing process. + * + * @return The signature of msg signed using xmss_priv_key. + **/ + XMSS_Signature sign( + const secure_vector& msg, + XMSS_PrivateKey& xmss_priv_key); + + wots_keysig_t build_auth_path(XMSS_PrivateKey& priv_key, + XMSS_Address& adrs); + + void initialize(); + + XMSS_PrivateKey m_priv_key; + const XMSS_Parameters m_xmss_params; + XMSS_Hash m_hash; + secure_vector m_randomness; + uint32_t m_leaf_idx; + bool m_is_initialized; + }; + +} + +#endif + diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_tools.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_tools.h new file mode 100644 index 0000000000..81d17f5bfe --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_tools.h @@ -0,0 +1,108 @@ +/* + * XMSS Tools + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_TOOLS_H_ +#define BOTAN_XMSS_TOOLS_H_ + +#include +#include +#include +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(xmss_tools.h) + +namespace Botan { + +/** + * Helper tools for low level byte operations required + * for the XMSS implementation. + **/ +class XMSS_Tools final + { + public: + XMSS_Tools(const XMSS_Tools&) = delete; + void operator=(const XMSS_Tools&) = delete; + + /** + * Concatenates the byte representation in big-endian order of any + * integral value to a secure_vector. + * + * @param target Vector to concatenate the byte representation of the + * integral value to. + * @param src integral value to concatenate. + **/ + template::value, + void>::type> + static void concat(secure_vector& target, const T& src); + + /** + * Concatenates the last n bytes of the byte representation in big-endian + * order of any integral value to a to a secure_vector. + * + * @param target Vector to concatenate the byte representation of the + * integral value to. + * @param src Integral value to concatenate. + * @param len number of bytes to concatenate. This value must be smaller + * or equal to the size of type T. + **/ + template ::value, + void>::type> + static void concat(secure_vector& target, const T& src, size_t len); + + private: + XMSS_Tools(); + }; + +template +void XMSS_Tools::concat(secure_vector& target, const T& src) + { + const uint8_t* src_bytes = reinterpret_cast(&src); + if(CPUID::is_little_endian()) + { + std::reverse_copy(src_bytes, + src_bytes + sizeof(src), + std::back_inserter(target)); + } + else + { + std::copy(src_bytes, + src_bytes + sizeof(src), + std::back_inserter(target)); + } + } + + +template +void XMSS_Tools::concat(secure_vector& target, + const T& src, + size_t len) + { + size_t c = static_cast(std::min(len, sizeof(src))); + if(len > sizeof(src)) + { + target.resize(target.size() + len - sizeof(src), 0); + } + + const uint8_t* src_bytes = reinterpret_cast(&src); + if(CPUID::is_little_endian()) + { + std::reverse_copy(src_bytes, + src_bytes + c, + std::back_inserter(target)); + } + else + { + std::copy(src_bytes + sizeof(src) - c, + src_bytes + sizeof(src), + std::back_inserter(target)); + } + } +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.cpp new file mode 100644 index 0000000000..b9442aa03d --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.cpp @@ -0,0 +1,138 @@ +/* + * XMSS Verification Operation + * Provides signature verification capabilities for Extended Hash-Based + * Signatures (XMSS). + * + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include +#include + +namespace Botan { + +XMSS_Verification_Operation::XMSS_Verification_Operation( + const XMSS_PublicKey& public_key) : + m_pub_key(public_key), + m_hash(public_key.xmss_hash_function()), + m_msg_buf(0) + { + } + +secure_vector +XMSS_Verification_Operation::root_from_signature(const XMSS_Signature& sig, + const secure_vector& msg, + XMSS_Address& adrs, + const secure_vector& seed) + { + const auto params = m_pub_key.xmss_parameters(); + + const uint32_t next_index = static_cast(sig.unused_leaf_index()); + adrs.set_type(XMSS_Address::Type::OTS_Hash_Address); + adrs.set_ots_address(next_index); + + XMSS_WOTS_PublicKey pub_key_ots(m_pub_key.wots_parameters().oid(), + msg, + sig.tree().ots_signature(), + adrs, + seed); + + adrs.set_type(XMSS_Address::Type::LTree_Address); + adrs.set_ltree_address(next_index); + + std::array, 2> node; + XMSS_Common_Ops::create_l_tree(node[0], pub_key_ots, adrs, seed, m_hash, params); + + adrs.set_type(XMSS_Address::Type::Hash_Tree_Address); + adrs.set_tree_index(next_index); + + for(size_t k = 0; k < params.tree_height(); k++) + { + adrs.set_tree_height(static_cast(k)); + if(((next_index / (static_cast(1) << k)) & 0x01) == 0) + { + adrs.set_tree_index(adrs.get_tree_index() >> 1); + XMSS_Common_Ops::randomize_tree_hash(node[1], + node[0], + sig.tree().authentication_path()[k], + adrs, + seed, + m_hash, + params); + } + else + { + adrs.set_tree_index((adrs.get_tree_index() - 1) >> 1); + XMSS_Common_Ops::randomize_tree_hash(node[1], + sig.tree().authentication_path()[k], + node[0], + adrs, + seed, + m_hash, + params); + } + node[0] = node[1]; + } + return node[0]; + } + +bool +XMSS_Verification_Operation::verify(const XMSS_Signature& sig, + const secure_vector& msg, + const XMSS_PublicKey& public_key) + { + XMSS_Address adrs; + secure_vector index_bytes; + XMSS_Tools::concat(index_bytes, + sig.unused_leaf_index(), + m_pub_key.xmss_parameters().element_size()); + secure_vector msg_digest = + m_hash.h_msg(sig.randomness(), + public_key.root(), + index_bytes, + msg); + + secure_vector node = root_from_signature(sig, + msg_digest, + adrs, + public_key.public_seed()); + + return (node == public_key.root()); + } + +// FIXME: XMSS signature verification requires the "randomness" parameter out +// of the XMSS signature, which is part of the prefix that is hashed before +// msg. Since the signature is unknown till sign() is called all message +// content has to be buffered. For large messages this can be inconvenient or +// impossible. +// Possible solution: Change PK_Ops::Verification interface to take the +// signature as constructor argument, make sign a parameterless member call. +void XMSS_Verification_Operation::update(const uint8_t msg[], size_t msg_len) + { + std::copy(msg, msg + msg_len, std::back_inserter(m_msg_buf)); + } + +bool XMSS_Verification_Operation::is_valid_signature(const uint8_t sig[], + size_t sig_len) + { + try + { + XMSS_Signature signature(m_pub_key.xmss_parameters().oid(), + secure_vector(sig, sig + sig_len)); + bool result = verify(signature, m_msg_buf, m_pub_key); + m_msg_buf.clear(); + return result; + } + catch(...) + { + m_msg_buf.clear(); + return false; + } + } + +} + diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.h new file mode 100644 index 0000000000..f96b3803bc --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_verification_operation.h @@ -0,0 +1,71 @@ +/* + * XMSS Verification Operation + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_VERIFICATION_OPERATION_H_ +#define BOTAN_XMSS_VERIFICATION_OPERATION_H_ + +#include +#include +#include + +namespace Botan { + +/** + * Provides signature verification capabilities for Extended Hash-Based + * Signatures (XMSS). + **/ + class XMSS_Verification_Operation final : public virtual PK_Ops::Verification + { + public: + XMSS_Verification_Operation( + const XMSS_PublicKey& public_key); + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; + + void update(const uint8_t msg[], size_t msg_len) override; + + private: + /** + * Algorithm 13: "XMSS_rootFromSig" + * Computes a root node using an XMSS signature, a message and a seed. + * + * @param msg A message. + * @param sig The XMSS signature for msg. + * @param ards A XMSS tree address. + * @param seed A seed. + * + * @return An n-byte string holding the value of the root of a tree + * defined by the input parameters. + **/ + secure_vector root_from_signature( + const XMSS_Signature& sig, + const secure_vector& msg, + XMSS_Address& ards, + const secure_vector& seed); + + /** + * Algorithm 14: "XMSS_verify" + * Verifies a XMSS signature using the corresponding XMSS public key. + * + * @param sig A XMSS signature. + * @param msg The message signed with sig. + * @param pub_key the public key + * + * @return true if signature sig is valid for msg, false otherwise. + **/ + bool verify(const XMSS_Signature& sig, + const secure_vector& msg, + const XMSS_PublicKey& pub_key); + + const XMSS_PublicKey& m_pub_key; + XMSS_Hash m_hash; + secure_vector m_msg_buf; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots.h new file mode 100644 index 0000000000..d85e889bfb --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots.h @@ -0,0 +1,752 @@ +/* + * XMSS WOTS + * (C) 2016,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_H_ +#define BOTAN_XMSS_WOTS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** + * Descibes a signature method for XMSS Winternitz One Time Signatures, + * as defined in: + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + **/ +class XMSS_WOTS_Parameters final + { + public: + enum ots_algorithm_t + { + WOTSP_SHA2_256 = 0x00000001, + WOTSP_SHA2_512 = 0x00000002, + WOTSP_SHAKE_256 = 0x00000003, + WOTSP_SHAKE_512 = 0x00000004 + }; + + XMSS_WOTS_Parameters(const std::string& algo_name); + XMSS_WOTS_Parameters(ots_algorithm_t ots_spec); + + static ots_algorithm_t xmss_wots_id_from_string(const std::string& param_set); + + /** + * Algorithm 1: convert input string to base. + * + * @param msg Input string (referred to as X in [1]). + * @param out_size size of message in base w. + * + * @return Input string converted to the given base. + **/ + secure_vector base_w(const secure_vector& msg, size_t out_size) const; + + secure_vector base_w(size_t value) const; + + void append_checksum(secure_vector& data); + + /** + * @return XMSS WOTS registry name for the chosen parameter set. + **/ + const std::string& name() const + { + return m_name; + } + + /** + * @return Botan name for the hash function used. + **/ + const std::string& hash_function_name() const + { + return m_hash_name; + } + + /** + * Retrieves the uniform length of a message, and the size of + * each node. This correlates to XMSS parameter "n" defined + * in [1]. + * + * @return element length in bytes. + **/ + size_t element_size() const { return m_element_size; } + + /** + * The Winternitz parameter. + * + * @return numeric base used for internal representation of + * data. + **/ + size_t wots_parameter() const { return m_w; } + + size_t len() const { return m_len; } + + size_t len_1() const { return m_len_1; } + + size_t len_2() const { return m_len_2; } + + size_t lg_w() const { return m_lg_w; } + + ots_algorithm_t oid() const { return m_oid; } + + size_t estimated_strength() const { return m_strength; } + + bool operator==(const XMSS_WOTS_Parameters& p) const + { + return m_oid == p.m_oid; + } + + private: + static const std::map m_oid_name_lut; + ots_algorithm_t m_oid; + std::string m_name; + std::string m_hash_name; + size_t m_element_size; + size_t m_w; + size_t m_len_1; + size_t m_len_2; + size_t m_len; + size_t m_strength; + uint8_t m_lg_w; + }; + +class XMSS_Address; + +typedef std::vector> wots_keysig_t; + +/** + * A Winternitz One Time Signature public key for use with Extended Hash-Based + * Signatures. + **/ +class XMSS_WOTS_PublicKey : virtual public Public_Key + { + public: + class TreeSignature final + { + public: + TreeSignature() = default; + + TreeSignature(const wots_keysig_t& ots_sig, + const wots_keysig_t& auth_path) + : m_ots_sig(ots_sig), m_auth_path(auth_path) + {} + + TreeSignature(wots_keysig_t&& ots_sig, + wots_keysig_t&& auth_path) + : m_ots_sig(std::move(ots_sig)), + m_auth_path(std::move(auth_path)) + {} + + const wots_keysig_t& ots_signature() const + { + return m_ots_sig; + } + + wots_keysig_t& ots_signature() + { + return m_ots_sig; + } + + const wots_keysig_t& authentication_path() const + { + return m_auth_path; + } + + wots_keysig_t& authentication_path() + { + return m_auth_path; + } + + private: + wots_keysig_t m_ots_sig; + wots_keysig_t m_auth_path; + }; + + /** + * Creates a XMSS_WOTS_PublicKey for the signature method identified by + * oid. The public seed for this key will be initialized with a + * uniformly random n-byte value, where "n" is the element size of the + * selected signature method. + * + * @param oid Identifier for the selected signature method. + **/ + XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters::ots_algorithm_t oid) + : m_wots_params(oid), + m_hash(m_wots_params.hash_function_name()) {} + + /** + * Creates a XMSS_WOTS_PublicKey for the signature method identified by + * oid. The public seed for this key will be initialized with a + * uniformly random n-byte value, where "n" is the element size of the + * selected signature method. + * + * @param oid Identifier for the selected signature method. + * @param rng A random number generate used to generate the public seed. + **/ + XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + RandomNumberGenerator& rng) + : m_wots_params(oid), + m_hash(m_wots_params.hash_function_name()), + m_public_seed(rng.random_vec(m_wots_params.element_size())) {} + + /** + * Creates a XMSS_WOTS_PrivateKey for the signature method identified by + * oid, with a precomputed public seed. + * + * @param oid Identifier for the selected signature method. + * @param public_seed A precomputed public seed of n-bytes length. + **/ + XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + secure_vector public_seed) + : m_wots_params(oid), + m_hash(m_wots_params.hash_function_name()), + m_public_seed(public_seed) {} + + /** + * Creates a XMSS_WOTS_PublicKey for the signature method identified by + * oid. The public seed will be initialized with a precomputed seed and + * and precomputed key data which should be derived from a + * XMSS_WOTS_PrivateKey. + * + * @param oid Ident:s/ifier for the selected signature methods. + * @param public_seed A precomputed public seed of n-bytes length. + * @param key Precomputed raw key data of the XMSS_WOTS_PublicKey. + **/ + XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + secure_vector&& public_seed, + wots_keysig_t&& key) + : m_wots_params(oid), + m_hash(m_wots_params.hash_function_name()), + m_key(std::move(key)), + m_public_seed(std::move(public_seed)) + {} + + /** + * Creates a XMSS_WOTS_PublicKey for the signature method identified by + * oid. The public seed will be initialized with a precomputed seed and + * and precomputed key data which should be derived from a + * XMSS_WOTS_PrivateKey. + * + * @param oid Identifier for the selected signature methods. + * @param public_seed A precomputed public seed of n-bytes length. + * @param key Precomputed raw key data of the XMSS_WOTS_PublicKey. + **/ + XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + const secure_vector& public_seed, + const wots_keysig_t& key) + : m_wots_params(oid), + m_hash(m_wots_params.hash_function_name()), + m_key(key), + m_public_seed(public_seed) + {} + + /** + * Creates a XMSS_WOTS_PublicKey form a message and signature using + * Algorithm 6 WOTS_pkFromSig defined in the XMSS standard. This + * overload is used to verify a message using a public key. + * + * @param oid WOTSP algorithm identifier. + * @param msg A message. + * @param sig A WOTS signature for msg. + * @param adrs An XMSS_Address. + * @param public_seed The public public_seed. + **/ + XMSS_WOTS_PublicKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + const secure_vector& msg, + const wots_keysig_t& sig, + XMSS_Address& adrs, + const secure_vector& public_seed) + : m_wots_params(oid), + m_hash(m_wots_params.hash_function_name()), + m_key(pub_key_from_signature(msg, + sig, + adrs, + public_seed)), + m_public_seed(public_seed) + {} + + /** + * Retrieves the i-th element out of the length len chain of + * n-byte elements contained in the public key. + * + * @param i index of the element. + * @returns n-byte element addressed by i. + **/ + const secure_vector& operator[](size_t i) const { return m_key[i]; } + secure_vector& operator[](size_t i) { return m_key[i]; } + + /** + * Convert the key into the raw key data. The key becomes a length + * len vector of n-byte elements. + **/ + operator const wots_keysig_t& () const { return m_key; } + + /** + * Convert the key into the raw key data. The key becomes a length + * len vector of n-byte elements. + **/ + operator wots_keysig_t& () { return m_key; } + + const secure_vector& public_seed() const { return m_public_seed; } + + secure_vector& public_seed() { return m_public_seed; } + + void set_public_seed(const secure_vector& public_seed) + { + m_public_seed = public_seed; + } + + void set_public_seed(secure_vector&& public_seed) + { + m_public_seed = std::move(public_seed); + } + + const wots_keysig_t& key_data() const { return m_key; } + + wots_keysig_t& key_data() { return m_key; } + + void set_key_data(const wots_keysig_t& key_data) + { + m_key = key_data; + } + + void set_key_data(wots_keysig_t&& key_data) + { + m_key = std::move(key_data); + } + + const XMSS_WOTS_Parameters& wots_parameters() const + { + return m_wots_params; + } + + std::string algo_name() const override + { + return m_wots_params.name(); + } + + AlgorithmIdentifier algorithm_identifier() const override + { + throw Not_Implemented("No AlgorithmIdentifier available for XMSS-WOTS."); + } + + bool check_key(RandomNumberGenerator&, bool) const override + { + return true; + } + + size_t estimated_strength() const override + { + return m_wots_params.estimated_strength(); + } + + size_t key_length() const override + { + return m_wots_params.estimated_strength(); + } + + std::vector public_key_bits() const override + { + throw Not_Implemented("No key format defined for XMSS-WOTS"); + } + + bool operator==(const XMSS_WOTS_PublicKey& key) + { + return m_key == key.m_key; + } + + bool operator!=(const XMSS_WOTS_PublicKey& key) + { + return !(*this == key); + } + + protected: + /** + * Algorithm 2: Chaining Function. + * + * Takes an n-byte input string and transforms it into a the function + * result iterating the cryptographic hash function "F" steps times on + * the input x using the outputs of the PRNG "G". + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each + * thread. + * + * @param[out] x An n-byte input string, that will be transformed into + * the chaining function result. + * @param start_idx The start index. + * @param steps A number of steps. + * @param adrs An OTS Hash Address. + * @param public_seed A public seed. + * @param hash Instance of XMSS_Hash, that may only by the thead + * executing chain. + **/ + void chain(secure_vector& x, + size_t start_idx, + size_t steps, + XMSS_Address& adrs, + const secure_vector& public_seed, + XMSS_Hash& hash); + + /** + * Algorithm 2: Chaining Function. + * + * Takes an n-byte input string and transforms it into a the function + * result iterating the cryptographic hash function "F" steps times on + * the input x using the outputs of the PRNG "G". + * + * @param[out] x An n-byte input string, that will be transformed into + * the chaining function result. + * @param start_idx The start index. + * @param steps A number of steps. + * @param adrs An OTS Hash Address. + * @param public_seed A public seed. + **/ + inline void chain(secure_vector& x, + size_t start_idx, + size_t steps, + XMSS_Address& adrs, + const secure_vector& public_seed) + { + chain(x, start_idx, steps, adrs, public_seed, m_hash); + } + + XMSS_WOTS_Parameters m_wots_params; + XMSS_Hash m_hash; + wots_keysig_t m_key; + secure_vector m_public_seed; + + private: + /** + * Algorithm 6: "WOTS_pkFromSig" + * Computes a Winternitz One Time Signature+ public key from a message and + * its signature. + * + * @param msg A message. + * @param sig The signature for msg. + * @param adrs An address. + * @param public_seed A public_seed. + * + * @return Temporary WOTS+ public key. + **/ + wots_keysig_t pub_key_from_signature( + const secure_vector& msg, + const wots_keysig_t& sig, + XMSS_Address& adrs, + const secure_vector& public_seed); + }; + +/** A Winternitz One Time Signature private key for use with Extended Hash-Based + * Signatures. + **/ +class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey, + public virtual Private_Key + { + public: + /** + * Creates a WOTS private key for the chosen XMSS WOTS signature method. + * Members need to be initialized manually. + * + * @param oid Identifier for the selected signature method. + **/ + XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters::ots_algorithm_t oid) + : XMSS_WOTS_PublicKey(oid) + {} + + /** + * Creates a WOTS private key for the chosen XMSS WOTS signature method. + * + * @param oid Identifier for the selected signature method. + * @param rng A random number generator to use for key generation. + **/ + XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + RandomNumberGenerator& rng) + : XMSS_WOTS_PublicKey(oid, rng), + m_private_seed(rng.random_vec(m_wots_params.element_size())) + { + set_key_data(generate(m_private_seed)); + } + + /** + * Constructs a WOTS private key. Chains will be generated on demand + * applying a hash function to a unique value generated from a secret + * seed and a counter. The secret seed of length n, will be + * automatically generated using AutoSeeded_RNG(). "n" equals + * the element size of the chosen WOTS security parameter set. + * + * @param oid Identifier for the selected signature method. + * @param public_seed A public seed used for the pseudo random generation + * of public keys derived from this private key. + * @param rng A random number generator to use for key generation. + **/ + XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + const secure_vector& public_seed, + RandomNumberGenerator& rng) + : XMSS_WOTS_PublicKey(oid, public_seed), + m_private_seed(rng.random_vec(m_wots_params.element_size())) + { + set_key_data(generate(m_private_seed)); + } + + /** + * Constructs a WOTS private key. Chains will be generated on demand + * applying a hash function to a unique value generated from a secret + * seed and a counter. The secret seed of length n, will be + * automatically generated using AutoSeeded_RNG(). "n" equals + * the element size of the chosen WOTS security parameter set. + * + * @param oid Identifier for the selected signature method. + * @param public_seed A public seed used for the pseudo random generation + * of public keys derived from this private key. + **/ + XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + const secure_vector& public_seed) + : XMSS_WOTS_PublicKey(oid, public_seed) + {} + + /** + * Constructs a WOTS private key. Chains will be generated on demand + * applying a hash function to a unique value generated from the + * secret seed and a counter. + * + * @param oid Identifier for the selected signature method. + * @param public_seed A public seed used for the pseudo random generation + * of public keys derived from this private key. + * @param private_seed A secret uniformly random n-byte value. + **/ + XMSS_WOTS_PrivateKey(XMSS_WOTS_Parameters::ots_algorithm_t oid, + const secure_vector& public_seed, + const secure_vector& private_seed) + : XMSS_WOTS_PublicKey(oid, public_seed), + m_private_seed(private_seed) + { + set_key_data(generate(private_seed)); + } + + /** + * Retrieves the i-th WOTS private key using pseudo random key + * (re-)generation. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each + * thread. + * + * @param i Index of the key to retrieve. + * @param hash Instance of XMSS_Hash, that may only be used by the + * thead executing at. + * + * @return WOTS secret key. + **/ + wots_keysig_t at(size_t i, XMSS_Hash& hash); + + /** + * Retrieves the i-th WOTS private key using pseudo random key + * (re-)generation. + * + * @param i Index of the key to retrieve. + * + * @return WOTS secret key. + **/ + inline wots_keysig_t operator[](size_t i) + { + return this->at(i, m_hash); + } + + /** + * Retrieves the i-th WOTS private key using pseudo random key + * (re-)generation. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each + * thread. + * + * @param adrs The address of the key to retrieve. + * @param hash Instance of XMSS_Hash, that may only be used by the + * thead executing at. + * + * @return WOTS secret key. + **/ + wots_keysig_t at(const XMSS_Address& adrs, XMSS_Hash& hash); + + inline wots_keysig_t operator[](const XMSS_Address& adrs) + { + return this->at(adrs, m_hash); + } + + wots_keysig_t generate_private_key(const secure_vector& priv_seed); + + /** + * Algorithm 4: "WOTS_genPK" + * Generates a Winternitz One Time Signature+ (WOTS+) Public Key from a + * given private key. + * + * @param adrs Hash function address encoding the address of the WOTS+ + * key pair within a greater structure. + * + * @return A XMSS_WOTS_PublicKey. + **/ + XMSS_WOTS_PublicKey generate_public_key(XMSS_Address& adrs); + + /** + * Algorithm 4: "WOTS_genPK" + * Initializes a Winternitz One Time Signature+ (WOTS+) Public Key's + * key_data() member, with data derived from in_key_data using the + * WOTS chaining function. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each + * thread. + * + * @param[out] pub_key Public key to initialize key_data() member on. + * @param in_key_data Input key material from private key used for + * public key generation. + * @param adrs Hash function address encoding the address of + * the WOTS+ key pair within a greater structure. + * @param hash Instance of XMSS_Hash, that may only by the thead + * executing generate_public_key. + **/ + void generate_public_key(XMSS_WOTS_PublicKey& pub_key, + wots_keysig_t&& in_key_data, + XMSS_Address& adrs, + XMSS_Hash& hash); + /** + * Algorithm 4: "WOTS_genPK" + * Initializes a Winternitz One Time Signature+ (WOTS+) Public Key's + * key_data() member, with data derived from in_key_data using the + * WOTS chaining function. + * + * @param[out] pub_key Public key to initialize key_data() member on. + * @param in_key_data Input key material from private key used for + * public key generation. + * @param adrs Hash function address encoding the address of + * the WOTS+ key pair within a greater structure. + **/ + inline void generate_public_key(XMSS_WOTS_PublicKey& pub_key, + wots_keysig_t&& in_key_data, + XMSS_Address& adrs) + { + generate_public_key(pub_key, std::forward(in_key_data), adrs, m_hash); + } + + /** + * Algorithm 5: "WOTS_sign" + * Generates a signature from a private key and a message. + * + * @param msg A message to sign. + * @param adrs An OTS hash address identifying the WOTS+ key pair + * used for signing. + * + * @return signature for msg. + **/ + inline wots_keysig_t sign(const secure_vector& msg, + XMSS_Address& adrs) + { + return sign(msg, adrs, m_hash); + } + + /** + * Algorithm 5: "WOTS_sign" + * Generates a signature from a private key and a message. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each + * thread. + * + * @param msg A message to sign. + * @param adrs An OTS hash address identifying the WOTS+ key pair + * used for signing. + * @param hash Instance of XMSS_Hash, that may only be used by the + * thead executing sign. + * + * @return signature for msg. + **/ + wots_keysig_t sign(const secure_vector& msg, + XMSS_Address& adrs, + XMSS_Hash& hash); + + /** + * Retrieves the secret seed used to generate WOTS+ chains. The seed + * should be a uniformly random n-byte value. + * + * @return secret seed. + **/ + const secure_vector& private_seed() const + { + return m_private_seed; + } + + /** + * Sets the secret seed used to generate WOTS+ chains. The seed + * should be a uniformly random n-byte value. + * + * @param private_seed Uniformly random n-byte value. + **/ + void set_private_seed(const secure_vector& private_seed) + { + m_private_seed = private_seed; + } + + /** + * Sets the secret seed used to generate WOTS+ chains. The seed + * should be a uniformly random n-byte value. + * + * @param private_seed Uniformly random n-byte value. + **/ + void set_private_seed(secure_vector&& private_seed) + { + m_private_seed = std::move(private_seed); + } + + AlgorithmIdentifier + pkcs8_algorithm_identifier() const override + { + throw Not_Implemented("No AlgorithmIdentifier available for XMSS-WOTS."); + } + + secure_vector private_key_bits() const override + { + throw Not_Implemented("No PKCS8 key format defined for XMSS-WOTS."); + } + + private: + /** + * Algorithm 3: "Generating a WOTS+ Private Key". + * Generates a private key. + * + * This overload is used in multithreaded scenarios, where it is + * required to provide seperate instances of XMSS_Hash to each thread. + * + * @param private_seed Uniformly random n-byte value. + * @param[in] hash Instance of XMSS_Hash, that may only be used by the + * thead executing generate. + * + * @returns a vector of length key_size() of vectors of n bytes length + * containing uniformly random data. + **/ + wots_keysig_t generate(const secure_vector& private_seed, + XMSS_Hash& hash); + + inline wots_keysig_t generate(const secure_vector& private_seed) + { + return generate(private_seed, m_hash); + } + + secure_vector m_private_seed; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h new file mode 100644 index 0000000000..debd00ff18 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_privatekey.h @@ -0,0 +1,68 @@ +/** + * XMSS WOTS Addressed Private Key + * (C) 2016 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_ADDRESSED_PRIVATEKEY_H_ +#define BOTAN_XMSS_WOTS_ADDRESSED_PRIVATEKEY_H_ + +#include +#include +#include + +namespace Botan { + +/** + * Wrapper class to pair an XMSS_WOTS_PrivateKey with an XMSS Address. Since + * the PK_Ops::Signature interface does not allow an extra address + * parameter to be passed to the sign(RandomNumberGenerator&), the address + * needs to be stored together with the key and passed to the + * XMSS_WOTS_Signature_Operation() on creation. + **/ +class XMSS_WOTS_Addressed_PrivateKey final : + public virtual XMSS_WOTS_Addressed_PublicKey, + public virtual Private_Key + { + public: + XMSS_WOTS_Addressed_PrivateKey(const XMSS_WOTS_PrivateKey& private_key) + : XMSS_WOTS_Addressed_PublicKey(private_key), + m_priv_key(private_key) {} + + XMSS_WOTS_Addressed_PrivateKey(const XMSS_WOTS_PrivateKey& private_key, + const XMSS_Address& adrs) + : XMSS_WOTS_Addressed_PublicKey(private_key, adrs), + m_priv_key(private_key) {} + + XMSS_WOTS_Addressed_PrivateKey(XMSS_WOTS_PrivateKey&& private_key) + : XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey(private_key)), + m_priv_key(std::move(private_key)) {} + + XMSS_WOTS_Addressed_PrivateKey(XMSS_WOTS_PrivateKey&& private_key, + XMSS_Address&& adrs) + : XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey(private_key), + std::move(adrs)), + m_priv_key(std::move(private_key)) {} + + const XMSS_WOTS_PrivateKey& private_key() const { return m_priv_key; } + XMSS_WOTS_PrivateKey& private_key() { return m_priv_key; } + + AlgorithmIdentifier + pkcs8_algorithm_identifier() const override + { + return m_priv_key.pkcs8_algorithm_identifier(); + } + + secure_vector private_key_bits() const override + { + return m_priv_key.private_key_bits(); + } + + private: + XMSS_WOTS_PrivateKey m_priv_key; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h new file mode 100644 index 0000000000..78d150d214 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_addressed_publickey.h @@ -0,0 +1,96 @@ +/** + * XMSS WOTS Addressed Public Key + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + + +#ifndef BOTAN_XMSS_WOTS_ADDRESSED_PUBLICKEY_H_ +#define BOTAN_XMSS_WOTS_ADDRESSED_PUBLICKEY_H_ + +#include +#include + +namespace Botan { + +/** + * Wrapper class to pair a XMSS_WOTS_PublicKey with an XMSS Address. Since + * the PK_Ops::Verification interface does not allow an extra address + * parameter to be passed to the sign(RandomNumberGenerator&), the address + * needs to be stored together with the key and passed to the + * XMSS_WOTS_Verification_Operation() on creation. + **/ +class XMSS_WOTS_Addressed_PublicKey : public virtual Public_Key + { + public: + XMSS_WOTS_Addressed_PublicKey(const XMSS_WOTS_PublicKey& public_key) + : m_pub_key(public_key), m_adrs() {} + + XMSS_WOTS_Addressed_PublicKey(const XMSS_WOTS_PublicKey& public_key, + const XMSS_Address& adrs) + : m_pub_key(public_key), m_adrs(adrs) {} + + XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey&& public_key) + : m_pub_key(std::move(public_key)), m_adrs() {} + + XMSS_WOTS_Addressed_PublicKey(XMSS_WOTS_PublicKey&& public_key, + XMSS_Address&& adrs) + : m_pub_key(std::move(public_key)), m_adrs(std::move(adrs)) {} + + const XMSS_WOTS_PublicKey& public_key() const { return m_pub_key; } + XMSS_WOTS_PublicKey& public_key() { return m_pub_key; } + + const XMSS_Address& address() const { return m_adrs; } + XMSS_Address& address() { return m_adrs; } + + std::string algo_name() const override + { + return m_pub_key.algo_name(); + } + + AlgorithmIdentifier algorithm_identifier() const override + { + return m_pub_key.algorithm_identifier(); + } + + bool check_key(RandomNumberGenerator& rng, bool strong) const override + { + return m_pub_key.check_key(rng, strong); + } + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override + { + return m_pub_key.create_verification_op(params, provider); + } + + OID get_oid() const override + { + return m_pub_key.get_oid(); + } + + size_t estimated_strength() const override + { + return m_pub_key.estimated_strength(); + } + + size_t key_length() const override + { + return m_pub_key.estimated_strength(); + } + + std::vector public_key_bits() const override + { + return m_pub_key.public_key_bits(); + } + + protected: + XMSS_WOTS_PublicKey m_pub_key; + XMSS_Address m_adrs; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.cpp new file mode 100644 index 0000000000..ef89c081c0 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.cpp @@ -0,0 +1,137 @@ +/* + * XMSS WOTS Parameters + * Descibes a signature method for XMSS Winternitz One Time Signatures, + * as defined in: + * [1] XMSS: Extended Hash-Based Signatures, + * Request for Comments: 8391 + * Release: May 2018. + * https://datatracker.ietf.org/doc/rfc8391/ + * + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include +#include + +namespace Botan { + +XMSS_WOTS_Parameters::ots_algorithm_t +XMSS_WOTS_Parameters::xmss_wots_id_from_string(const std::string& param_set) + { + if(param_set == "WOTSP-SHA2_256") + { return WOTSP_SHA2_256; } + if(param_set == "WOTSP-SHA2_512") + { return WOTSP_SHA2_512; } + if(param_set == "WOTSP-SHAKE_256") + { return WOTSP_SHAKE_256; } + if(param_set == "WOTSP-SHAKE_512") + { return WOTSP_SHAKE_512; } + throw Invalid_Argument("Unknown XMSS-WOTS algorithm param '" + param_set + "'"); + } + +XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(const std::string& param_set) + : XMSS_WOTS_Parameters(xmss_wots_id_from_string(param_set)) + {} + +XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(ots_algorithm_t oid) + : m_oid(oid) + { + switch(oid) + { + case WOTSP_SHA2_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_name = "WOTSP-SHA2_256"; + m_hash_name = "SHA-256"; + m_strength = 256; + break; + case WOTSP_SHA2_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_name = "WOTSP-SHA2_512"; + m_hash_name = "SHA-512"; + m_strength = 512; + break; + case WOTSP_SHAKE_256: + m_element_size = 32; + m_w = 16; + m_len = 67; + m_name = "WOTSP-SHAKE_256"; + m_hash_name = "SHAKE-128(256)"; + m_strength = 256; + break; + case WOTSP_SHAKE_512: + m_element_size = 64; + m_w = 16; + m_len = 131; + m_name = "WOTSP-SHAKE_512"; + m_hash_name = "SHAKE-256(512)"; + m_strength = 512; + break; + default: + throw Not_Implemented("Algorithm id does not match any known XMSS WOTS algorithm id."); + break; + } + + m_lg_w = (m_w == 16) ? 4 : 2; + m_len_1 = static_cast(std::ceil((8 * element_size()) / m_lg_w)); + m_len_2 = static_cast( + floor(log2(m_len_1 * (wots_parameter() - 1)) / m_lg_w) + 1); + BOTAN_ASSERT(m_len == m_len_1 + m_len_2, "Invalid XMSS WOTS parameter " + "\"len\" detedted."); + } + +secure_vector +XMSS_WOTS_Parameters::base_w(const secure_vector& msg, size_t out_size) const + { + secure_vector result; + size_t in = 0; + size_t total = 0; + size_t bits = 0; + + for(size_t i = 0; i < out_size; i++) + { + if(bits == 0) + { + total = msg[in]; + in++; + bits += 8; + } + bits -= m_lg_w; + result.push_back(static_cast((total >> bits) & (m_w - 1))); + } + return result; + } + +secure_vector +XMSS_WOTS_Parameters::base_w(size_t value) const + { + value <<= (8 - ((m_len_2 * m_lg_w) % 8)); + size_t len_2_bytes = static_cast( + std::ceil(static_cast(m_len_2 * m_lg_w) / 8.f)); + secure_vector result; + XMSS_Tools::concat(result, value, len_2_bytes); + return base_w(result, m_len_2); + } + +void +XMSS_WOTS_Parameters::append_checksum(secure_vector& data) + { + size_t csum = 0; + + for(size_t i = 0; i < data.size(); i++) + { + csum += wots_parameter() - 1 - data[i]; + } + + secure_vector csum_bytes = base_w(csum); + std::move(csum_bytes.begin(), csum_bytes.end(), std::back_inserter(data)); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.h new file mode 100644 index 0000000000..e8c3e2b4a3 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_parameters.h @@ -0,0 +1,14 @@ +/* + * XMSS WOTS Parameters + * (C) 2016,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_PARAMETERS_H_ +#define BOTAN_XMSS_WOTS_PARAMETERS_H_ + +#include +BOTAN_DEPRECATED_HEADER(xmss_wots_parameters.h) + +#endif diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp new file mode 100644 index 0000000000..7293f2538a --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.cpp @@ -0,0 +1,99 @@ +/* + * XMSS WOTS Private Key + * A Winternitz One Time Signature private key for use with Extended Hash-Based + * Signatures. + * + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include +#include + +namespace Botan { + +wots_keysig_t +XMSS_WOTS_PrivateKey::generate(const secure_vector& priv_seed, + XMSS_Hash& hash) + { + wots_keysig_t priv_key(m_wots_params.len(), + secure_vector(0)); + + for(size_t i = 0; i < m_wots_params.len(); i++) + { + XMSS_Tools::concat(priv_key[i], i, 32); + hash.prf(priv_key[i], priv_seed, priv_key[i]); + } + return priv_key; + } + + +XMSS_WOTS_PublicKey +XMSS_WOTS_PrivateKey::generate_public_key(XMSS_Address& adrs) + { + XMSS_WOTS_PublicKey pub_key(m_wots_params.oid(), + public_seed()); + generate_public_key(pub_key, wots_keysig_t((*this)[adrs]), adrs); + return pub_key; + } + +void +XMSS_WOTS_PrivateKey::generate_public_key(XMSS_WOTS_PublicKey& pub_key, + wots_keysig_t&& in_key_data, + XMSS_Address& adrs, + XMSS_Hash& hash) + { + BOTAN_ASSERT(wots_parameters() == pub_key.wots_parameters() && + public_seed() == pub_key.public_seed(), + "Conflicting public key data."); + + pub_key.set_key_data(std::move(in_key_data)); + for(size_t i = 0; i < m_wots_params.len(); i++) + { + adrs.set_chain_address(static_cast(i)); + chain(pub_key[i], 0, m_wots_params.wots_parameter() - 1, adrs, + public_seed(), hash); + } + } + +wots_keysig_t +XMSS_WOTS_PrivateKey::sign(const secure_vector& msg, + XMSS_Address& adrs, + XMSS_Hash& hash) + + { + secure_vector msg_digest + { + m_wots_params.base_w(msg, m_wots_params.len_1()) + }; + + m_wots_params.append_checksum(msg_digest); + wots_keysig_t sig(this->at(adrs, hash)); + + for(size_t i = 0; i < m_wots_params.len(); i++) + { + adrs.set_chain_address(static_cast(i)); + chain(sig[i], 0 , msg_digest[i], adrs, m_public_seed, hash); + } + + return sig; + } + +wots_keysig_t XMSS_WOTS_PrivateKey::at(const XMSS_Address& adrs, XMSS_Hash& hash) + { + secure_vector result; + hash.prf(result, m_private_seed, adrs.bytes()); + return generate(result, hash); + } + +wots_keysig_t XMSS_WOTS_PrivateKey::at(size_t i, XMSS_Hash& hash) + { + secure_vector idx_bytes; + XMSS_Tools::concat(idx_bytes, i, m_wots_params.element_size()); + hash.h(idx_bytes, m_private_seed, idx_bytes); + return generate(idx_bytes, hash); + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.h new file mode 100644 index 0000000000..2d631598bb --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_privatekey.h @@ -0,0 +1,15 @@ +/* + * XMSS WOTS Private Key + * (C) 2016,2017 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_PRIVATEKEY_H_ +#define BOTAN_XMSS_WOTS_PRIVATEKEY_H_ + +#include +BOTAN_DEPRECATED_HEADER(xmss_wots_privatekey.h) + +#endif + diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.cpp b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.cpp new file mode 100644 index 0000000000..70ff1b7bad --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.cpp @@ -0,0 +1,72 @@ +/* + * XMSS WOTS Public Key + * A Winternitz One Time Signature public key for use with Extended Hash-Based + * Signatures. + * + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#include +#include + +namespace Botan { + +void +XMSS_WOTS_PublicKey::chain(secure_vector& result, + size_t start_idx, + size_t steps, + XMSS_Address& adrs, + const secure_vector& seed, + XMSS_Hash& hash) + { + secure_vector prf_output(hash.output_length()); + + for(size_t i = start_idx; + i < (start_idx + steps) && i < m_wots_params.wots_parameter(); + i++) + { + adrs.set_hash_address(static_cast(i)); + + //Calculate tmp XOR bitmask + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_Mode); + hash.prf(prf_output, seed, adrs.bytes()); + xor_buf(result, prf_output, result.size()); + + // Calculate key + adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode); + + //Calculate f(key, tmp XOR bitmask) + hash.prf(prf_output, seed, adrs.bytes()); + hash.f(result, prf_output, result); + } + } + +wots_keysig_t +XMSS_WOTS_PublicKey::pub_key_from_signature(const secure_vector& msg, + const wots_keysig_t& sig, + XMSS_Address& adrs, + const secure_vector& seed) + { + secure_vector msg_digest + { + m_wots_params.base_w(msg, m_wots_params.len_1()) + }; + + m_wots_params.append_checksum(msg_digest); + wots_keysig_t result(sig); + + for(size_t i = 0; i < m_wots_params.len(); i++) + { + adrs.set_chain_address(static_cast(i)); + chain(result[i], + msg_digest[i], + m_wots_params.wots_parameter() - 1 - msg_digest[i], + adrs, + seed); + } + return result; + } + +} diff --git a/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.h b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.h new file mode 100644 index 0000000000..796bf4c308 --- /dev/null +++ b/comm/third_party/botan/src/lib/pubkey/xmss/xmss_wots_publickey.h @@ -0,0 +1,14 @@ +/* + * XMSS WOTS Public Key + * (C) 2016,2017,2018 Matthias Gierlings + * + * Botan is released under the Simplified BSD License (see license.txt) + **/ + +#ifndef BOTAN_XMSS_WOTS_PUBLICKEY_H_ +#define BOTAN_XMSS_WOTS_PUBLICKEY_H_ + +#include +BOTAN_DEPRECATED_HEADER(xmss_wots_publickey.h) + +#endif diff --git a/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp new file mode 100644 index 0000000000..a13429e9b5 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp @@ -0,0 +1,112 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include +#endif + +#if !defined(BOTAN_AUTO_RNG_HMAC) +#error "No hash function defined for AutoSeeded_RNG in build.h (try enabling sha2_32)" +#endif + +namespace Botan { + +AutoSeeded_RNG::~AutoSeeded_RNG() + { + // for unique_ptr + } + +AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + size_t reseed_interval) + { + m_rng.reset(new HMAC_DRBG(MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), + underlying_rng, + reseed_interval)); + force_reseed(); + } + +AutoSeeded_RNG::AutoSeeded_RNG(Entropy_Sources& entropy_sources, + size_t reseed_interval) + { + m_rng.reset(new HMAC_DRBG(MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), + entropy_sources, + reseed_interval)); + force_reseed(); + } + +AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval) + { + m_rng.reset(new HMAC_DRBG( + MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), + underlying_rng, entropy_sources, reseed_interval)); + force_reseed(); + } + +AutoSeeded_RNG::AutoSeeded_RNG(size_t reseed_interval) : +#if defined(BOTAN_HAS_SYSTEM_RNG) + AutoSeeded_RNG(system_rng(), reseed_interval) +#else + AutoSeeded_RNG(Entropy_Sources::global_sources(), reseed_interval) +#endif + { + } + +void AutoSeeded_RNG::force_reseed() + { + m_rng->force_reseed(); + m_rng->next_byte(); + + if(!m_rng->is_seeded()) + { + throw Internal_Error("AutoSeeded_RNG reseeding failed"); + } + } + +bool AutoSeeded_RNG::is_seeded() const + { + return m_rng->is_seeded(); + } + +void AutoSeeded_RNG::clear() + { + m_rng->clear(); + } + +std::string AutoSeeded_RNG::name() const + { + return m_rng->name(); + } + +void AutoSeeded_RNG::add_entropy(const uint8_t in[], size_t len) + { + m_rng->add_entropy(in, len); + } + +size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) + { + return m_rng->reseed(srcs, poll_bits, poll_timeout); + } + +void AutoSeeded_RNG::randomize(uint8_t output[], size_t output_len) + { + m_rng->randomize_with_ts_input(output, output_len); + } + +void AutoSeeded_RNG::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t ad[], size_t ad_len) + { + m_rng->randomize_with_input(output, output_len, ad, ad_len); + } + +} diff --git a/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h new file mode 100644 index 0000000000..8cb2c4a127 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h @@ -0,0 +1,102 @@ +/* +* Auto Seeded RNG +* (C) 2008,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AUTO_SEEDING_RNG_H_ +#define BOTAN_AUTO_SEEDING_RNG_H_ + +#include + +namespace Botan { + +class Stateful_RNG; + +/** +* A userspace PRNG +*/ +class BOTAN_PUBLIC_API(2,0) AutoSeeded_RNG final : public RandomNumberGenerator + { + public: + void randomize(uint8_t out[], size_t len) override; + + void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override; + + bool is_seeded() const override; + + bool accepts_input() const override { return true; } + + /** + * Mark state as requiring a reseed on next use + */ + void force_reseed(); + + size_t reseed(Entropy_Sources& srcs, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override; + + void add_entropy(const uint8_t in[], size_t len) override; + + std::string name() const override; + + void clear() override; + + /** + * Uses the system RNG (if available) or else a default group of + * entropy sources (all other systems) to gather seed material. + * + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Create an AutoSeeded_RNG which will get seed material from some other + * RNG instance. For example you could provide a reference to the system + * RNG or a hardware RNG. + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Create an AutoSeeded_RNG which will get seed material from a set of + * entropy sources. + * + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Create an AutoSeeded_RNG which will get seed material from both an + * underlying RNG and a set of entropy sources. + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + ~AutoSeeded_RNG(); + + private: + std::unique_ptr m_rng; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/auto_rng/info.txt b/comm/third_party/botan/src/lib/rng/auto_rng/info.txt new file mode 100644 index 0000000000..f1adcc8001 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/auto_rng/info.txt @@ -0,0 +1,8 @@ + +AUTO_SEEDING_RNG -> 20160821 +AUTO_RNG -> 20161126 + + + +hmac_drbg + diff --git a/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp new file mode 100644 index 0000000000..3dc69ec1b8 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp @@ -0,0 +1,87 @@ +/* +* ChaCha_RNG +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +ChaCha_RNG::ChaCha_RNG() : Stateful_RNG() + { + m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); + clear(); + } + +ChaCha_RNG::ChaCha_RNG(const secure_vector& seed) : Stateful_RNG() + { + m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); + clear(); + add_entropy(seed.data(), seed.size()); + } + +ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng, + size_t reseed_interval) : + Stateful_RNG(underlying_rng, reseed_interval) + { + m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); + clear(); + } + +ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval) : + Stateful_RNG(underlying_rng, entropy_sources, reseed_interval) + { + m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); + clear(); + } + +ChaCha_RNG::ChaCha_RNG(Entropy_Sources& entropy_sources, + size_t reseed_interval) : + Stateful_RNG(entropy_sources, reseed_interval) + { + m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + m_chacha = StreamCipher::create_or_throw("ChaCha(20)"); + clear(); + } + +void ChaCha_RNG::clear_state() + { + m_hmac->set_key(std::vector(m_hmac->output_length(), 0x00)); + m_chacha->set_key(m_hmac->final()); + } + +void ChaCha_RNG::generate_output(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + if(input_len > 0) + { + update(input, input_len); + } + + m_chacha->write_keystream(output, output_len); + } + +void ChaCha_RNG::update(const uint8_t input[], size_t input_len) + { + m_hmac->update(input, input_len); + m_chacha->set_key(m_hmac->final()); + + secure_vector mac_key(m_hmac->output_length()); + m_chacha->write_keystream(mac_key.data(), mac_key.size()); + m_hmac->set_key(mac_key); + } + +size_t ChaCha_RNG::security_level() const + { + return 256; + } + +} diff --git a/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h new file mode 100644 index 0000000000..c50c2d0c25 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h @@ -0,0 +1,125 @@ +/* +* ChaCha_RNG +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CHACHA_RNG_H_ +#define BOTAN_CHACHA_RNG_H_ + +#include +#include +#include + +namespace Botan { + +class Entropy_Sources; + +/** +* ChaCha_RNG is a very fast but completely ad-hoc RNG created by +* creating a 256-bit random value and using it as a key for ChaCha20. +* +* The RNG maintains two 256-bit keys, one for HMAC_SHA256 (HK) and the +* other for ChaCha20 (CK). To compute a new key in response to +* reseeding request or add_entropy calls, ChaCha_RNG computes +* CK' = HMAC_SHA256(HK, input_material) +* Then a new HK' is computed by running ChaCha20 with the new key to +* output 32 bytes: +* HK' = ChaCha20(CK') +* +* Now output can be produced by continuing to produce output with ChaCha20 +* under CK' +* +* The first HK (before seeding occurs) is taken as the all zero value. +* +* @warning This RNG construction is probably fine but is non-standard. +* The primary reason to use it is in cases where the other RNGs are +* not fast enough. +*/ +class BOTAN_PUBLIC_API(2,3) ChaCha_RNG final : public Stateful_RNG + { + public: + /** + * Automatic reseeding is disabled completely, as it has no access to + * any source for seed material. + * + * If a fork is detected, the RNG will be unable to reseed itself + * in response. In this case, an exception will be thrown rather + * than generating duplicated output. + */ + ChaCha_RNG(); + + /** + * Provide an initial seed to the RNG, without providing an + * underlying RNG or entropy source. Automatic reseeding is + * disabled completely, as it has no access to any source for + * seed material. + * + * If a fork is detected, the RNG will be unable to reseed itself + * in response. In this case, an exception will be thrown rather + * than generating duplicated output. + * + * @param seed the seed material, should be at least 256 bits + */ + ChaCha_RNG(const secure_vector& seed); + + /** + * Automatic reseeding from @p underlying_rng will take place after + * @p reseed_interval many requests or after a fork was detected. + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + ChaCha_RNG(RandomNumberGenerator& underlying_rng, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Automatic reseeding from @p entropy_sources will take place after + * @p reseed_interval many requests or after a fork was detected. + * + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. + */ + ChaCha_RNG(Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Automatic reseeding from @p underlying_rng and @p entropy_sources + * will take place after @p reseed_interval many requests or after + * a fork was detected. + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. + */ + ChaCha_RNG(RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + std::string name() const override { return "ChaCha_RNG"; } + + size_t security_level() const override; + + size_t max_number_of_bytes_per_request() const override { return 0; } + + private: + void update(const uint8_t input[], size_t input_len) override; + + void generate_output(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override; + + void clear_state() override; + + std::unique_ptr m_hmac; + std::unique_ptr m_chacha; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/chacha_rng/info.txt b/comm/third_party/botan/src/lib/rng/chacha_rng/info.txt new file mode 100644 index 0000000000..3f51bf4d0e --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/chacha_rng/info.txt @@ -0,0 +1,10 @@ + +CHACHA_RNG -> 20170728 + + + +hmac +sha2_32 +chacha +stateful_rng + diff --git a/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp new file mode 100644 index 0000000000..2b66a839c3 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp @@ -0,0 +1,197 @@ +/* +* HMAC_DRBG +* (C) 2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace { + +size_t hmac_drbg_security_level(size_t mac_output_length) + { + // security strength of the hash function + // for pre-image resistance (see NIST SP 800-57) + // SHA-160: 128 bits + // SHA-224, SHA-512/224: 192 bits, + // SHA-256, SHA-512/256, SHA-384, SHA-512: >= 256 bits + // NIST SP 800-90A only supports up to 256 bits though + + if(mac_output_length < 32) + { + return (mac_output_length - 4) * 8; + } + else + { + return 32 * 8; + } + } + +void check_limits(size_t reseed_interval, + size_t max_number_of_bytes_per_request) + { + // SP800-90A permits up to 2^48, but it is not usable on 32 bit + // platforms, so we only allow up to 2^24, which is still reasonably high + if(reseed_interval == 0 || reseed_interval > static_cast(1) << 24) + { + throw Invalid_Argument("Invalid value for reseed_interval"); + } + + if(max_number_of_bytes_per_request == 0 || max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request"); + } + } + +} + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf, + RandomNumberGenerator& underlying_rng, + size_t reseed_interval, + size_t max_number_of_bytes_per_request) : + Stateful_RNG(underlying_rng, reseed_interval), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(max_number_of_bytes_per_request), + m_security_level(hmac_drbg_security_level(m_mac->output_length())) + { + BOTAN_ASSERT_NONNULL(m_mac); + + check_limits(reseed_interval, max_number_of_bytes_per_request); + + clear(); + } + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf, + RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval, + size_t max_number_of_bytes_per_request) : + Stateful_RNG(underlying_rng, entropy_sources, reseed_interval), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(max_number_of_bytes_per_request), + m_security_level(hmac_drbg_security_level(m_mac->output_length())) + { + BOTAN_ASSERT_NONNULL(m_mac); + + check_limits(reseed_interval, max_number_of_bytes_per_request); + + clear(); + } + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf, + Entropy_Sources& entropy_sources, + size_t reseed_interval, + size_t max_number_of_bytes_per_request) : + Stateful_RNG(entropy_sources, reseed_interval), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(max_number_of_bytes_per_request), + m_security_level(hmac_drbg_security_level(m_mac->output_length())) + { + BOTAN_ASSERT_NONNULL(m_mac); + + check_limits(reseed_interval, max_number_of_bytes_per_request); + + clear(); + } + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr prf) : + Stateful_RNG(), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(64*1024), + m_security_level(hmac_drbg_security_level(m_mac->output_length())) + { + BOTAN_ASSERT_NONNULL(m_mac); + clear(); + } + +HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash) : + Stateful_RNG(), + m_mac(MessageAuthenticationCode::create_or_throw("HMAC(" + hmac_hash + ")")), + m_max_number_of_bytes_per_request(64 * 1024), + m_security_level(hmac_drbg_security_level(m_mac->output_length())) + { + clear(); + } + +void HMAC_DRBG::clear_state() + { + if(m_V.size() == 0) + { + const size_t output_length = m_mac->output_length(); + m_V.resize(output_length); + } + + for(size_t i = 0; i != m_V.size(); ++i) + m_V[i] = 0x01; + m_mac->set_key(std::vector(m_V.size(), 0x00)); + } + +std::string HMAC_DRBG::name() const + { + return "HMAC_DRBG(" + m_mac->name() + ")"; + } + +/* +* HMAC_DRBG generation +* See NIST SP800-90A section 10.1.2.5 +*/ +void HMAC_DRBG::generate_output(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + if(input_len > 0) + { + update(input, input_len); + } + + while(output_len > 0) + { + const size_t to_copy = std::min(output_len, m_V.size()); + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + copy_mem(output, m_V.data(), to_copy); + + output += to_copy; + output_len -= to_copy; + } + + update(input, input_len); + } + +/* +* Reset V and the mac key with new values +* See NIST SP800-90A section 10.1.2.2 +*/ +void HMAC_DRBG::update(const uint8_t input[], size_t input_len) + { + secure_vector T(m_V.size()); + m_mac->update(m_V); + m_mac->update(0x00); + m_mac->update(input, input_len); + m_mac->final(T.data()); + m_mac->set_key(T); + + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + + if(input_len > 0) + { + m_mac->update(m_V); + m_mac->update(0x01); + m_mac->update(input, input_len); + m_mac->final(T.data()); + m_mac->set_key(T); + + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + } + } + +size_t HMAC_DRBG::security_level() const + { + return m_security_level; + } +} diff --git a/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h new file mode 100644 index 0000000000..a4c288c74b --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h @@ -0,0 +1,150 @@ +/* +* HMAC_DRBG (SP800-90A) +* (C) 2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HMAC_DRBG_H_ +#define BOTAN_HMAC_DRBG_H_ + +#include +#include + +namespace Botan { + +class Entropy_Sources; + +/** +* HMAC_DRBG from NIST SP800-90A +*/ +class BOTAN_PUBLIC_API(2,0) HMAC_DRBG final : public Stateful_RNG + { + public: + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding is disabled completely, as it has no access to + * any source for seed material. + * + * If a fork is detected, the RNG will be unable to reseed itself + * in response. In this case, an exception will be thrown rather + * than generating duplicated output. + */ + explicit HMAC_DRBG(std::unique_ptr prf); + + /** + * Constructor taking a string for the hash + */ + explicit HMAC_DRBG(const std::string& hmac_hash); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding from @p underlying_rng will take place after + * @p reseed_interval many requests or after a fork was detected. + * + * @param prf MAC to use as a PRF + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed (max. 2^24) + * @param max_number_of_bytes_per_request requests that are in size higher + * than max_number_of_bytes_per_request are treated as if multiple single + * requests of max_number_of_bytes_per_request size had been made. + * In theory SP 800-90A requires that we reject any request for a DRBG + * output longer than max_number_of_bytes_per_request. To avoid inconveniencing + * the caller who wants an output larger than max_number_of_bytes_per_request, + * instead treat these requests as if multiple requests of + * max_number_of_bytes_per_request size had been made. NIST requires for + * HMAC_DRBG that every implementation set a value no more than 2**19 bits + * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for + * example every 512 bit automatic reseeding occurs. + */ + HMAC_DRBG(std::unique_ptr prf, + RandomNumberGenerator& underlying_rng, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, + size_t max_number_of_bytes_per_request = 64 * 1024); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding from @p entropy_sources will take place after + * @p reseed_interval many requests or after a fork was detected. + * + * @param prf MAC to use as a PRF + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed (max. 2^24) + * @param max_number_of_bytes_per_request requests that are in size higher + * than max_number_of_bytes_per_request are treated as if multiple single + * requests of max_number_of_bytes_per_request size had been made. + * In theory SP 800-90A requires that we reject any request for a DRBG + * output longer than max_number_of_bytes_per_request. To avoid inconveniencing + * the caller who wants an output larger than max_number_of_bytes_per_request, + * instead treat these requests as if multiple requests of + * max_number_of_bytes_per_request size had been made. NIST requires for + * HMAC_DRBG that every implementation set a value no more than 2**19 bits + * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for + * example every 512 bit automatic reseeding occurs. + */ + HMAC_DRBG(std::unique_ptr prf, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, + size_t max_number_of_bytes_per_request = 64 * 1024); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding from @p underlying_rng and @p entropy_sources + * will take place after @p reseed_interval many requests or after + * a fork was detected. + * + * @param prf MAC to use as a PRF + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed (max. 2^24) + * @param max_number_of_bytes_per_request requests that are in size higher + * than max_number_of_bytes_per_request are treated as if multiple single + * requests of max_number_of_bytes_per_request size had been made. + * In theory SP 800-90A requires that we reject any request for a DRBG + * output longer than max_number_of_bytes_per_request. To avoid inconveniencing + * the caller who wants an output larger than max_number_of_bytes_per_request, + * instead treat these requests as if multiple requests of + * max_number_of_bytes_per_request size had been made. NIST requires for + * HMAC_DRBG that every implementation set a value no more than 2**19 bits + * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for + * example every 512 bit automatic reseeding occurs. + */ + HMAC_DRBG(std::unique_ptr prf, + RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, + size_t max_number_of_bytes_per_request = 64 * 1024); + + std::string name() const override; + + size_t security_level() const override; + + size_t max_number_of_bytes_per_request() const override + { return m_max_number_of_bytes_per_request; } + + private: + void update(const uint8_t input[], size_t input_len) override; + + void generate_output(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override; + + void clear_state() override; + + std::unique_ptr m_mac; + secure_vector m_V; + const size_t m_max_number_of_bytes_per_request; + const size_t m_security_level; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt b/comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt new file mode 100644 index 0000000000..a8922bdf0e --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt @@ -0,0 +1,8 @@ + +HMAC_DRBG -> 20140319 + + + +hmac +stateful_rng + diff --git a/comm/third_party/botan/src/lib/rng/info.txt b/comm/third_party/botan/src/lib/rng/info.txt new file mode 100644 index 0000000000..4c88ba3826 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/info.txt @@ -0,0 +1,3 @@ + +entropy + diff --git a/comm/third_party/botan/src/lib/rng/processor_rng/info.txt b/comm/third_party/botan/src/lib/rng/processor_rng/info.txt new file mode 100644 index 0000000000..61d10f11b4 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/processor_rng/info.txt @@ -0,0 +1,20 @@ + +PROCESSOR_RNG -> 20200508 + + + +gcc +clang +icc +msvc + + + +x86_32 +x86_64 +ppc64 + + + +ppc64:power9 + diff --git a/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp new file mode 100644 index 0000000000..ca52d05e67 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp @@ -0,0 +1,157 @@ +/* +* (C) 2016,2019,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) && !defined(BOTAN_USE_GCC_INLINE_ASM) + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + /* + * According to Intel, RDRAND is guaranteed to generate a random + * number within 10 retries on a working CPU + */ + const size_t HWRNG_RETRIES = 10; + +#else + /* + * Lacking specific guidance we give the CPU quite a bit of leeway + */ + const size_t HWRNG_RETRIES = 512; +#endif + +#if defined(BOTAN_TARGET_ARCH_IS_X86_32) + typedef uint32_t hwrng_output; +#else + typedef uint64_t hwrng_output; +#endif + +hwrng_output read_hwrng(bool& success) + { + hwrng_output output = 0; + success = false; + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + int cf = 0; +#if defined(BOTAN_USE_GCC_INLINE_ASM) + // same asm seq works for 32 and 64 bit + asm volatile("rdrand %0; adcl $0,%1" : + "=r" (output), "=r" (cf) : "0" (output), "1" (cf) : "cc"); +#elif defined(BOTAN_TARGET_ARCH_IS_X86_32) + cf = _rdrand32_step(&output); +#else + cf = _rdrand64_step(&output); +#endif + success = (1 == cf); + +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + + /* + DARN indicates error by returning 0xFF..FF, ie is biased. Which is crazy. + Avoid the bias by invoking it twice and, assuming both succeed, returning the + XOR of the two results, which should unbias the output. + */ + uint64_t output2 = 0; + // DARN codes are 0: 32-bit conditioned, 1: 64-bit conditioned, 2: 64-bit raw (ala RDSEED) + asm volatile("darn %0, 1" : "=r" (output)); + asm volatile("darn %0, 1" : "=r" (output2)); + + if((~output) != 0 && (~output2) != 0) + { + output ^= output2; + success = true; + } + +#endif + + if(success) + return output; + + return 0; + } + +hwrng_output read_hwrng() + { + for(size_t i = 0; i < HWRNG_RETRIES; ++i) + { + bool success = false; + hwrng_output output = read_hwrng(success); + + if(success) + return output; + } + + throw PRNG_Unseeded("Processor RNG instruction failed to produce output within expected iterations"); + } + +} + +//static +bool Processor_RNG::available() + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + return CPUID::has_rdrand(); +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + return CPUID::has_darn_rng(); +#else + return false; +#endif + } + +std::string Processor_RNG::name() const + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + return "rdrand"; +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + return "darn"; +#else + return "hwrng"; +#endif + } + +void Processor_RNG::randomize(uint8_t out[], size_t out_len) + { + while(out_len >= sizeof(hwrng_output)) + { + const hwrng_output r = read_hwrng(); + store_le(r, out); + out += sizeof(hwrng_output); + out_len -= sizeof(hwrng_output); + } + + if(out_len > 0) // at most sizeof(hwrng_output)-1 + { + const hwrng_output r = read_hwrng(); + for(size_t i = 0; i != out_len; ++i) + out[i] = get_byte(i, r); + } + } + +Processor_RNG::Processor_RNG() + { + if(!Processor_RNG::available()) + throw Invalid_State("Current CPU does not support RNG instruction"); + } + +void Processor_RNG::add_entropy(const uint8_t[], size_t) + { + /* no way to add entropy */ + } + +size_t Processor_RNG::reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) + { + /* no way to add entropy */ + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h new file mode 100644 index 0000000000..5900e386e0 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h @@ -0,0 +1,52 @@ +/* +* (C) 2016,2019,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RNG_PROCESSOR_RNG_H_ +#define BOTAN_RNG_PROCESSOR_RNG_H_ + +#include + +namespace Botan { + +/** +* Directly invokes a CPU specific instruction to generate random numbers. +* On x86, the RDRAND instruction is used. +* on POWER, the DARN instruction is used. +*/ +class BOTAN_PUBLIC_API(2,15) Processor_RNG final : public Hardware_RNG + { + public: + /** + * Constructor will throw if CPU does not have RDRAND bit set + */ + Processor_RNG(); + + /** + * Return true if RNG instruction is available on the current processor + */ + static bool available(); + + bool accepts_input() const override { return false; } + bool is_seeded() const override { return true; } + + void randomize(uint8_t out[], size_t out_len) override; + + /* + * No way to provide entropy to RDRAND generator, so add_entropy is ignored + */ + void add_entropy(const uint8_t[], size_t) override; + + /* + * No way to reseed processor provided generator, so reseed is ignored + */ + size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override; + + std::string name() const override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt b/comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt new file mode 100644 index 0000000000..5cc616deae --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt @@ -0,0 +1,13 @@ + +RDRAND_RNG -> 20160619 + + + +processor_rng + + +# Avoid building RDRAND_RNG on non-x86 since that would be confusing + +x86_32 +x86_64 + diff --git a/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp new file mode 100644 index 0000000000..fade5a1992 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp @@ -0,0 +1,67 @@ +/* +* RDRAND RNG +* (C) 2016,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +void RDRAND_RNG::randomize(uint8_t out[], size_t out_len) + { + Processor_RNG rng; + rng.randomize(out, out_len); + } + +RDRAND_RNG::RDRAND_RNG() + { + // Will throw if instruction is not available + Processor_RNG rng; + } + +//static +bool RDRAND_RNG::available() + { + return Processor_RNG::available(); + } + +//static +uint32_t RDRAND_RNG::rdrand() + { + Processor_RNG rng; + + for(;;) + { + try + { + uint8_t out[4]; + rng.randomize(out, 4); + return load_le(out, 0); + } + catch(PRNG_Unseeded&) {} + } + } + +//static +uint32_t RDRAND_RNG::rdrand_status(bool& ok) + { + ok = false; + Processor_RNG rng; + + try + { + uint8_t out[4]; + rng.randomize(out, 4); + ok = true; + return load_le(out, 0); + } + catch(PRNG_Unseeded&) {} + + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h new file mode 100644 index 0000000000..1b6977eac3 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h @@ -0,0 +1,68 @@ +/* +* RDRAND RNG +* (C) 2016,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RNG_RDRAND_H_ +#define BOTAN_RNG_RDRAND_H_ + +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) RDRAND_RNG final : public Hardware_RNG + { + public: + /** + * Constructor will throw if CPU does not have RDRAND bit set + */ + BOTAN_DEPRECATED("Use Processor_RNG instead") RDRAND_RNG(); + + /** + * Return true if RDRAND is available on the current processor + */ + static bool available(); + + bool accepts_input() const override { return false; } + + /** + * Uses RDRAND to produce output + */ + void randomize(uint8_t out[], size_t out_len) override; + + /* + * No way to provide entropy to RDRAND generator, so add_entropy is ignored + */ + void add_entropy(const uint8_t[], size_t) override + { /* no op */ } + + /* + * No way to reseed RDRAND generator, so reseed is ignored + */ + size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override + { return 0; /* no op */ } + + std::string name() const override { return "RDRAND"; } + + bool is_seeded() const override { return true; } + + /** + * On correctly working hardware, RDRAND is always supposed to + * succeed within a set number of retries. If after that many + * retries RDRAND has still not suceeded, sets ok = false and + * returns 0. + */ + static uint32_t BOTAN_DEPRECATED("Use Processor_RNG::randomize") rdrand_status(bool& ok); + + /* + * Calls RDRAND until it succeeds, this could hypothetically + * loop forever on broken hardware. + */ + static uint32_t BOTAN_DEPRECATED("Use Processor_RNG::randomize") rdrand(); + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/rng.cpp b/comm/third_party/botan/src/lib/rng/rng.cpp new file mode 100644 index 0000000000..743f7c7aa2 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/rng.cpp @@ -0,0 +1,91 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include +#endif + +namespace Botan { + +void RandomNumberGenerator::randomize_with_ts_input(uint8_t output[], size_t output_len) + { + if(this->accepts_input()) + { + /* + Form additional input which is provided to the PRNG implementation + to paramaterize the KDF output. + */ + uint8_t additional_input[16] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_high_resolution_clock(), additional_input + 8); + + this->randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } + else + { + this->randomize(output, output_len); + } + } + +void RandomNumberGenerator::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + this->add_entropy(input, input_len); + this->randomize(output, output_len); + } + +size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) + { + if(this->accepts_input()) + { + return srcs.poll(*this, poll_bits, poll_timeout); + } + else + { + return 0; + } + } + +void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) + { + if(this->accepts_input()) + { + secure_vector buf(poll_bits / 8); + rng.randomize(buf.data(), buf.size()); + this->add_entropy(buf.data(), buf.size()); + } + } + +RandomNumberGenerator* RandomNumberGenerator::make_rng() + { +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + return new AutoSeeded_RNG; +#else + throw Not_Implemented("make_rng failed, no AutoSeeded_RNG in this build"); +#endif + } + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) +Serialized_RNG::Serialized_RNG() : m_rng(new AutoSeeded_RNG) {} +#else +Serialized_RNG::Serialized_RNG() + { + throw Not_Implemented("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build"); + } +#endif + +#endif + +} diff --git a/comm/third_party/botan/src/lib/rng/rng.h b/comm/third_party/botan/src/lib/rng/rng.h new file mode 100644 index 0000000000..54a8ea8319 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/rng.h @@ -0,0 +1,297 @@ +/* +* Random Number Generator base classes +* (C) 1999-2009,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H_ +#define BOTAN_RANDOM_NUMBER_GENERATOR_H_ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class Entropy_Sources; + +/** +* An interface to a cryptographic random number generator +*/ +class BOTAN_PUBLIC_API(2,0) RandomNumberGenerator + { + public: + virtual ~RandomNumberGenerator() = default; + + RandomNumberGenerator() = default; + + /* + * Never copy a RNG, create a new one + */ + RandomNumberGenerator(const RandomNumberGenerator& rng) = delete; + RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete; + + /** + * Randomize a byte array. + * @param output the byte array to hold the random output. + * @param length the length of the byte array output in bytes. + */ + virtual void randomize(uint8_t output[], size_t length) = 0; + + /** + * Returns false if it is known that this RNG object is not able to accept + * externally provided inputs (via add_entropy, randomize_with_input, etc). + * In this case, any such provided inputs are ignored. + * + * If this function returns true, then inputs may or may not be accepted. + */ + virtual bool accepts_input() const = 0; + + /** + * Incorporate some additional data into the RNG state. For + * example adding nonces or timestamps from a peer's protocol + * message can help hedge against VM state rollback attacks. + * A few RNG types do not accept any externally provided input, + * in which case this function is a no-op. + * + * @param input a byte array containg the entropy to be added + * @param length the length of the byte array in + */ + virtual void add_entropy(const uint8_t input[], size_t length) = 0; + + /** + * Incorporate some additional data into the RNG state. + */ + template void add_entropy_T(const T& t) + { + static_assert(std::is_standard_layout::value && std::is_trivial::value, "add_entropy_T data must be POD"); + this->add_entropy(reinterpret_cast(&t), sizeof(T)); + } + + /** + * Incorporate entropy into the RNG state then produce output. + * Some RNG types implement this using a single operation, default + * calls add_entropy + randomize in sequence. + * + * Use this to further bind the outputs to your current + * process/protocol state. For instance if generating a new key + * for use in a session, include a session ID or other such + * value. See NIST SP 800-90 A, B, C series for more ideas. + * + * @param output buffer to hold the random output + * @param output_len size of the output buffer in bytes + * @param input entropy buffer to incorporate + * @param input_len size of the input buffer in bytes + */ + virtual void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len); + + /** + * This calls `randomize_with_input` using some timestamps as extra input. + * + * For a stateful RNG using non-random but potentially unique data the + * extra input can help protect against problems with fork, VM state + * rollback, or other cases where somehow an RNG state is duplicated. If + * both of the duplicated RNG states later incorporate a timestamp (and the + * timestamps don't themselves repeat), their outputs will diverge. + */ + virtual void randomize_with_ts_input(uint8_t output[], size_t output_len); + + /** + * @return the name of this RNG type + */ + virtual std::string name() const = 0; + + /** + * Clear all internally held values of this RNG + * @post is_seeded() == false + */ + virtual void clear() = 0; + + /** + * Check whether this RNG is seeded. + * @return true if this RNG was already seeded, false otherwise. + */ + virtual bool is_seeded() const = 0; + + /** + * Poll provided sources for up to poll_bits bits of entropy + * or until the timeout expires. Returns estimate of the number + * of bits collected. + */ + virtual size_t reseed(Entropy_Sources& srcs, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT); + + /** + * Reseed by reading specified bits from the RNG + */ + virtual void reseed_from_rng(RandomNumberGenerator& rng, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS); + + // Some utility functions built on the interface above: + + /** + * Return a random vector + * @param bytes number of bytes in the result + * @return randomized vector of length bytes + */ + secure_vector random_vec(size_t bytes) + { + secure_vector output; + random_vec(output, bytes); + return output; + } + + template + void random_vec(std::vector& v, size_t bytes) + { + v.resize(bytes); + this->randomize(v.data(), v.size()); + } + + /** + * Return a random byte + * @return random byte + */ + uint8_t next_byte() + { + uint8_t b; + this->randomize(&b, 1); + return b; + } + + /** + * @return a random byte that is greater than zero + */ + uint8_t next_nonzero_byte() + { + uint8_t b = this->next_byte(); + while(b == 0) + b = this->next_byte(); + return b; + } + + /** + * Create a seeded and active RNG object for general application use + * Added in 1.8.0 + * Use AutoSeeded_RNG instead + */ + BOTAN_DEPRECATED("Use AutoSeeded_RNG") + static RandomNumberGenerator* make_rng(); + }; + +/** +* Convenience typedef +*/ +typedef RandomNumberGenerator RNG; + +/** +* Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG) +*/ +class BOTAN_PUBLIC_API(2,0) Hardware_RNG : public RandomNumberGenerator + { + public: + virtual void clear() final override { /* no way to clear state of hardware RNG */ } + }; + +/** +* Null/stub RNG - fails if you try to use it for anything +* This is not generally useful except for in certain tests +*/ +class BOTAN_PUBLIC_API(2,0) Null_RNG final : public RandomNumberGenerator + { + public: + bool is_seeded() const override { return false; } + + bool accepts_input() const override { return false; } + + void clear() override {} + + void randomize(uint8_t[], size_t) override + { + throw PRNG_Unseeded("Null_RNG called"); + } + + void add_entropy(const uint8_t[], size_t) override {} + + std::string name() const override { return "Null_RNG"; } + }; + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) +/** +* Wraps access to a RNG in a mutex +* Note that most of the time it's much better to use a RNG per thread +* otherwise the RNG will act as an unnecessary contention point +* +* Since 2.16.0 all Stateful_RNG instances have an internal lock, so +* this class is no longer needed. It will be removed in a future major +* release. +*/ +class BOTAN_PUBLIC_API(2,0) Serialized_RNG final : public RandomNumberGenerator + { + public: + void randomize(uint8_t out[], size_t len) override + { + lock_guard_type lock(m_mutex); + m_rng->randomize(out, len); + } + + bool accepts_input() const override + { + lock_guard_type lock(m_mutex); + return m_rng->accepts_input(); + } + + bool is_seeded() const override + { + lock_guard_type lock(m_mutex); + return m_rng->is_seeded(); + } + + void clear() override + { + lock_guard_type lock(m_mutex); + m_rng->clear(); + } + + std::string name() const override + { + lock_guard_type lock(m_mutex); + return m_rng->name(); + } + + size_t reseed(Entropy_Sources& src, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override + { + lock_guard_type lock(m_mutex); + return m_rng->reseed(src, poll_bits, poll_timeout); + } + + void add_entropy(const uint8_t in[], size_t len) override + { + lock_guard_type lock(m_mutex); + m_rng->add_entropy(in, len); + } + + BOTAN_DEPRECATED("Use Serialized_RNG(new AutoSeeded_RNG) instead") Serialized_RNG(); + + /* + * Since 2.16.0 this is no longer needed for any RNG type. This + * class will be removed in a future major release. + */ + explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {} + private: + mutable mutex_type m_mutex; + std::unique_ptr m_rng; + }; +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/stateful_rng/info.txt b/comm/third_party/botan/src/lib/rng/stateful_rng/info.txt new file mode 100644 index 0000000000..edc2d91694 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/stateful_rng/info.txt @@ -0,0 +1,3 @@ + +STATEFUL_RNG -> 20160819 + diff --git a/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp new file mode 100644 index 0000000000..c7b3484ee0 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp @@ -0,0 +1,190 @@ +/* +* (C) 2016,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include +#endif + +namespace Botan { + +void Stateful_RNG::clear() + { + lock_guard_type lock(m_mutex); + m_reseed_counter = 0; + m_last_pid = 0; + clear_state(); + } + +void Stateful_RNG::force_reseed() + { + lock_guard_type lock(m_mutex); + m_reseed_counter = 0; + } + +bool Stateful_RNG::is_seeded() const + { + lock_guard_type lock(m_mutex); + return m_reseed_counter > 0; + } + +void Stateful_RNG::add_entropy(const uint8_t input[], size_t input_len) + { + lock_guard_type lock(m_mutex); + + update(input, input_len); + + if(8*input_len >= security_level()) + { + reset_reseed_counter(); + } + } + +void Stateful_RNG::initialize_with(const uint8_t input[], size_t len) + { + lock_guard_type lock(m_mutex); + + clear(); + add_entropy(input, len); + } + +void Stateful_RNG::randomize(uint8_t output[], size_t output_len) + { + randomize_with_input(output, output_len, nullptr, 0); + } + +void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len) + { + uint8_t additional_input[20] = { 0 }; + + store_le(OS::get_high_resolution_clock(), additional_input); + +#if defined(BOTAN_HAS_SYSTEM_RNG) + System_RNG system_rng; + system_rng.randomize(additional_input + 8, sizeof(additional_input) - 8); +#else + store_le(OS::get_system_timestamp_ns(), additional_input + 8); + store_le(OS::get_process_id(), additional_input + 16); +#endif + + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } + +void Stateful_RNG::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + if(output_len == 0) + return; + + lock_guard_type lock(m_mutex); + + const size_t max_per_request = max_number_of_bytes_per_request(); + + if(max_per_request == 0) // no limit + { + reseed_check(); + this->generate_output(output, output_len, input, input_len); + } + else + { + while(output_len > 0) + { + const size_t this_req = std::min(max_per_request, output_len); + + /* + * We split the request into several requests to the underlying DRBG but + * pass the input to each invocation. It might be more sensible to only + * provide it for the first invocation, however between 2.0 and 2.15 + * HMAC_DRBG always provided it for all requests so retain that here. + */ + + reseed_check(); + this->generate_output(output, this_req, input, input_len); + + output += this_req; + output_len -= this_req; + } + } + } + +size_t Stateful_RNG::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) + { + lock_guard_type lock(m_mutex); + + const size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout); + + if(bits_collected >= security_level()) + { + reset_reseed_counter(); + } + + return bits_collected; + } + +void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) + { + lock_guard_type lock(m_mutex); + + RandomNumberGenerator::reseed_from_rng(rng, poll_bits); + + if(poll_bits >= security_level()) + { + reset_reseed_counter(); + } + } + +void Stateful_RNG::reset_reseed_counter() + { + // Lock is held whenever this function is called + m_reseed_counter = 1; + } + +void Stateful_RNG::reseed_check() + { + // Lock is held whenever this function is called + + const uint32_t cur_pid = OS::get_process_id(); + + const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid); + + if(is_seeded() == false || + fork_detected || + (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval)) + { + m_reseed_counter = 0; + m_last_pid = cur_pid; + + if(m_underlying_rng) + { + reseed_from_rng(*m_underlying_rng, security_level()); + } + + if(m_entropy_sources) + { + reseed(*m_entropy_sources, security_level()); + } + + if(!is_seeded()) + { + if(fork_detected) + throw Invalid_State("Detected use of fork but cannot reseed DRBG"); + else + throw PRNG_Unseeded(name()); + } + } + else + { + BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded"); + m_reseed_counter += 1; + } + } + +} diff --git a/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h new file mode 100644 index 0000000000..e1311fcc9f --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h @@ -0,0 +1,166 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STATEFUL_RNG_H_ +#define BOTAN_STATEFUL_RNG_H_ + +#include +#include + +namespace Botan { + +/** +* Inherited by RNGs which maintain in-process state, like HMAC_DRBG. +* On Unix these RNGs are vulnerable to problems with fork, where the +* RNG state is duplicated, and the parent and child process RNGs will +* produce identical output until one of them reseeds. Stateful_RNG +* reseeds itself whenever a fork is detected, or after a set number of +* bytes have been output. +* +* Not implemented by RNGs which access an external RNG, such as the +* system PRNG or a hardware RNG. +*/ +class BOTAN_PUBLIC_API(2,0) Stateful_RNG : public RandomNumberGenerator + { + public: + /** + * @param rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + Stateful_RNG(RandomNumberGenerator& rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval) : + m_underlying_rng(&rng), + m_entropy_sources(&entropy_sources), + m_reseed_interval(reseed_interval) + {} + + /** + * @param rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + Stateful_RNG(RandomNumberGenerator& rng, size_t reseed_interval) : + m_underlying_rng(&rng), + m_reseed_interval(reseed_interval) + {} + + /** + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + Stateful_RNG(Entropy_Sources& entropy_sources, size_t reseed_interval) : + m_entropy_sources(&entropy_sources), + m_reseed_interval(reseed_interval) + {} + + /** + * In this case, automatic reseeding is impossible + */ + Stateful_RNG() : m_reseed_interval(0) {} + + /** + * Consume this input and mark the RNG as initialized regardless + * of the length of the input or the current seeded state of + * the RNG. + */ + void initialize_with(const uint8_t input[], size_t length); + + bool is_seeded() const override final; + + bool accepts_input() const override final { return true; } + + /** + * Mark state as requiring a reseed on next use + */ + void force_reseed(); + + void reseed_from_rng(RandomNumberGenerator& rng, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS) override final; + + void add_entropy(const uint8_t input[], size_t input_len) override final; + + void randomize(uint8_t output[], size_t output_len) override final; + + void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override final; + + /** + * Overrides default implementation and also includes the current + * process ID and the reseed counter. + */ + void randomize_with_ts_input(uint8_t output[], size_t output_len) override final; + + /** + * Poll provided sources for up to poll_bits bits of entropy + * or until the timeout expires. Returns estimate of the number + * of bits collected. + */ + size_t reseed(Entropy_Sources& srcs, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override; + + /** + * @return intended security level of this DRBG + */ + virtual size_t security_level() const = 0; + + /** + * Some DRBGs have a notion of the maximum number of bytes per + * request. Longer requests (to randomize) will be treated as + * multiple requests, and may initiate reseeding multiple times, + * depending on the values of max_number_of_bytes_per_request and + * reseed_interval(). This function returns zero if the RNG in + * question does not have such a notion. + * + * @return max number of bytes per request (or zero) + */ + virtual size_t max_number_of_bytes_per_request() const = 0; + + size_t reseed_interval() const { return m_reseed_interval; } + + void clear() override final; + + protected: + void reseed_check(); + + virtual void generate_output(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) = 0; + + virtual void update(const uint8_t input[], size_t input_len) = 0; + + virtual void clear_state() = 0; + + private: + void reset_reseed_counter(); + + mutable recursive_mutex_type m_mutex; + + // A non-owned and possibly null pointer to shared RNG + RandomNumberGenerator* m_underlying_rng = nullptr; + + // A non-owned and possibly null pointer to a shared Entropy_Source + Entropy_Sources* m_entropy_sources = nullptr; + + const size_t m_reseed_interval; + uint32_t m_last_pid = 0; + + /* + * Set to 1 after a successful seeding, then incremented. Reset + * to 0 by clear() or a fork. This logic is used even if + * automatic reseeding is disabled (via m_reseed_interval = 0) + */ + size_t m_reseed_counter = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/rng/system_rng/info.txt b/comm/third_party/botan/src/lib/rng/system_rng/info.txt new file mode 100644 index 0000000000..e77328b820 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/system_rng/info.txt @@ -0,0 +1,18 @@ + +SYSTEM_RNG -> 20141202 + + + +dev_random,posix1 +arc4random +rtlgenrandom +crypto_ng + + + +uwp -> bcrypt + + + +rtlgenrandom?dyn_load + diff --git a/comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp new file mode 100644 index 0000000000..0c5641e60d --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp @@ -0,0 +1,289 @@ +/* +* System RNG +* (C) 2014,2015,2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM) + #include + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include + +#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG) + #include + +#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM) + #include + +#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM) + #include + #include + +#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM) + #include + #include + #include + #include + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + System_RNG_Impl() : m_advapi("advapi32.dll") + { + // This throws if the function is not found + m_rtlgenrandom = m_advapi.resolve("SystemFunction036"); + } + + void randomize(uint8_t buf[], size_t len) override + { + bool success = m_rtlgenrandom(buf, ULONG(len)) == TRUE; + if(!success) + throw System_Error("RtlGenRandom failed"); + } + + void add_entropy(const uint8_t[], size_t) override { /* ignored */ } + bool is_seeded() const override { return true; } + bool accepts_input() const override { return false; } + void clear() override { /* not possible */ } + std::string name() const override { return "RtlGenRandom"; } + private: + // Use type BYTE instead of BOOLEAN because of a naming conflict + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx + using RtlGenRandom_fptr = BYTE (NTAPI *)(PVOID, ULONG); + + Dynamically_Loaded_Library m_advapi; + RtlGenRandom_fptr m_rtlgenrandom; + }; + +#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + System_RNG_Impl() + { + NTSTATUS ret = ::BCryptOpenAlgorithmProvider(&m_prov, + BCRYPT_RNG_ALGORITHM, + MS_PRIMITIVE_PROVIDER, 0); + if(ret != STATUS_SUCCESS) + throw System_Error("System_RNG failed to acquire crypto provider", ret); + } + + ~System_RNG_Impl() + { + ::BCryptCloseAlgorithmProvider(m_prov, 0); + } + + void randomize(uint8_t buf[], size_t len) override + { + NTSTATUS ret = ::BCryptGenRandom(m_prov, static_cast(buf), static_cast(len), 0); + if(ret != STATUS_SUCCESS) + throw System_Error("System_RNG call to BCryptGenRandom failed", ret); + } + + void add_entropy(const uint8_t in[], size_t length) override + { + /* + There is a flag BCRYPT_RNG_USE_ENTROPY_IN_BUFFER to provide + entropy inputs, but it is ignored in Windows 8 and later. + */ + } + + bool is_seeded() const override { return true; } + bool accepts_input() const override { return false; } + void clear() override { /* not possible */ } + std::string name() const override { return "crypto_ng"; } + private: + BCRYPT_ALG_HANDLE m_prov; + }; + +#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + // No constructor or destructor needed as no userland state maintained + + void randomize(uint8_t buf[], size_t len) override + { + // macOS 10.15 arc4random crashes if called with buf == nullptr && len == 0 + if(len > 0) + { + ::arc4random_buf(buf, len); + } + } + + bool accepts_input() const override { return false; } + void add_entropy(const uint8_t[], size_t) override { /* ignored */ } + bool is_seeded() const override { return true; } + void clear() override { /* not possible */ } + std::string name() const override { return "arc4random"; } + }; + +#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + // No constructor or destructor needed as no userland state maintained + + void randomize(uint8_t buf[], size_t len) override + { + const unsigned int flags = 0; + + while(len > 0) + { + const ssize_t got = ::getrandom(buf, len, flags); + + if(got < 0) + { + if(errno == EINTR) + continue; + throw System_Error("System_RNG getrandom failed", errno); + } + + buf += got; + len -= got; + } + } + + bool accepts_input() const override { return false; } + void add_entropy(const uint8_t[], size_t) override { /* ignored */ } + bool is_seeded() const override { return true; } + void clear() override { /* not possible */ } + std::string name() const override { return "getrandom"; } + }; + + +#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM) + +// Read a random device + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + System_RNG_Impl() + { +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + + m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY); + + if(m_fd >= 0) + { + m_writable = true; + } + else + { + /* + Cannot open in read-write mode. Fall back to read-only, + calls to add_entropy will fail, but randomize will work + */ + m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY); + m_writable = false; + } + + if(m_fd < 0) + throw System_Error("System_RNG failed to open RNG device", errno); + } + + ~System_RNG_Impl() + { + ::close(m_fd); + m_fd = -1; + } + + void randomize(uint8_t buf[], size_t len) override; + void add_entropy(const uint8_t in[], size_t length) override; + bool is_seeded() const override { return true; } + bool accepts_input() const override { return m_writable; } + void clear() override { /* not possible */ } + std::string name() const override { return BOTAN_SYSTEM_RNG_DEVICE; } + private: + int m_fd; + bool m_writable; + }; + +void System_RNG_Impl::randomize(uint8_t buf[], size_t len) + { + while(len) + { + ssize_t got = ::read(m_fd, buf, len); + + if(got < 0) + { + if(errno == EINTR) + continue; + throw System_Error("System_RNG read failed", errno); + } + if(got == 0) + throw System_Error("System_RNG EOF on device"); // ?!? + + buf += got; + len -= got; + } + } + +void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len) + { + if(!m_writable) + return; + + while(len) + { + ssize_t got = ::write(m_fd, input, len); + + if(got < 0) + { + if(errno == EINTR) + continue; + + /* + * This is seen on OS X CI, despite the fact that the man page + * for macOS urandom explicitly states that writing to it is + * supported, and write(2) does not document EPERM at all. + * But in any case EPERM seems indicative of a policy decision + * by the OS or sysadmin that additional entropy is not wanted + * in the system pool, so we accept that and return here, + * since there is no corrective action possible. + * + * In Linux EBADF or EPERM is returned if m_fd is not opened for + * writing. + */ + if(errno == EPERM || errno == EBADF) + return; + + // maybe just ignore any failure here and return? + throw System_Error("System_RNG write failed", errno); + } + + input += got; + len -= got; + } + } + +#endif + +} + +RandomNumberGenerator& system_rng() + { + static System_RNG_Impl g_system_rng; + return g_system_rng; + } + +} diff --git a/comm/third_party/botan/src/lib/rng/system_rng/system_rng.h b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.h new file mode 100644 index 0000000000..e0f0181ca1 --- /dev/null +++ b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.h @@ -0,0 +1,43 @@ +/* +* System RNG interface +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYSTEM_RNG_H_ +#define BOTAN_SYSTEM_RNG_H_ + +#include + +namespace Botan { + +/** +* Return a shared reference to a global PRNG instance provided by the +* operating system. For instance might be instantiated by /dev/urandom +* or CryptGenRandom. +*/ +BOTAN_PUBLIC_API(2,0) RandomNumberGenerator& system_rng(); + +/* +* Instantiable reference to the system RNG. +*/ +class BOTAN_PUBLIC_API(2,0) System_RNG final : public RandomNumberGenerator + { + public: + std::string name() const override { return system_rng().name(); } + + void randomize(uint8_t out[], size_t len) override { system_rng().randomize(out, len); } + + void add_entropy(const uint8_t in[], size_t length) override { system_rng().add_entropy(in, length); } + + bool is_seeded() const override { return system_rng().is_seeded(); } + + bool accepts_input() const override { return system_rng().accepts_input(); } + + void clear() override { system_rng().clear(); } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha.cpp b/comm/third_party/botan/src/lib/stream/chacha/chacha.cpp new file mode 100644 index 0000000000..c8d567e5e0 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha.cpp @@ -0,0 +1,384 @@ +/* +* ChaCha +* (C) 2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +#define CHACHA_QUARTER_ROUND(a, b, c, d) \ + do { \ + a += b; d ^= a; d = rotl<16>(d); \ + c += d; b ^= c; b = rotl<12>(b); \ + a += b; d ^= a; d = rotl<8>(d); \ + c += d; b ^= c; b = rotl<7>(b); \ + } while(0) + +/* +* Generate HChaCha cipher stream (for XChaCha IV setup) +*/ +void hchacha(uint32_t output[8], const uint32_t input[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != rounds / 2; ++i) + { + CHACHA_QUARTER_ROUND(x00, x04, x08, x12); + CHACHA_QUARTER_ROUND(x01, x05, x09, x13); + CHACHA_QUARTER_ROUND(x02, x06, x10, x14); + CHACHA_QUARTER_ROUND(x03, x07, x11, x15); + + CHACHA_QUARTER_ROUND(x00, x05, x10, x15); + CHACHA_QUARTER_ROUND(x01, x06, x11, x12); + CHACHA_QUARTER_ROUND(x02, x07, x08, x13); + CHACHA_QUARTER_ROUND(x03, x04, x09, x14); + } + + output[0] = x00; + output[1] = x01; + output[2] = x02; + output[3] = x03; + output[4] = x12; + output[5] = x13; + output[6] = x14; + output[7] = x15; + } + +} + +ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) + { + BOTAN_ARG_CHECK(m_rounds == 8 || m_rounds == 12 || m_rounds == 20, + "ChaCha only supports 8, 12 or 20 rounds"); + } + +std::string ChaCha::provider() const + { +#if defined(BOTAN_HAS_CHACHA_AVX2) + if(CPUID::has_avx2()) + { + return "avx2"; + } +#endif + +#if defined(BOTAN_HAS_CHACHA_SIMD32) + if(CPUID::has_simd_32()) + { + return "simd32"; + } +#endif + + return "base"; + } + +//static +void ChaCha::chacha_x8(uint8_t output[64*8], uint32_t input[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + +#if defined(BOTAN_HAS_CHACHA_AVX2) + if(CPUID::has_avx2()) + { + return ChaCha::chacha_avx2_x8(output, input, rounds); + } +#endif + +#if defined(BOTAN_HAS_CHACHA_SIMD32) + if(CPUID::has_simd_32()) + { + ChaCha::chacha_simd32_x4(output, input, rounds); + ChaCha::chacha_simd32_x4(output + 4*64, input, rounds); + return; + } +#endif + + // TODO interleave rounds + for(size_t i = 0; i != 8; ++i) + { + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t r = 0; r != rounds / 2; ++r) + { + CHACHA_QUARTER_ROUND(x00, x04, x08, x12); + CHACHA_QUARTER_ROUND(x01, x05, x09, x13); + CHACHA_QUARTER_ROUND(x02, x06, x10, x14); + CHACHA_QUARTER_ROUND(x03, x07, x11, x15); + + CHACHA_QUARTER_ROUND(x00, x05, x10, x15); + CHACHA_QUARTER_ROUND(x01, x06, x11, x12); + CHACHA_QUARTER_ROUND(x02, x07, x08, x13); + CHACHA_QUARTER_ROUND(x03, x04, x09, x14); + } + + x00 += input[0]; + x01 += input[1]; + x02 += input[2]; + x03 += input[3]; + x04 += input[4]; + x05 += input[5]; + x06 += input[6]; + x07 += input[7]; + x08 += input[8]; + x09 += input[9]; + x10 += input[10]; + x11 += input[11]; + x12 += input[12]; + x13 += input[13]; + x14 += input[14]; + x15 += input[15]; + + store_le(x00, output + 64 * i + 4 * 0); + store_le(x01, output + 64 * i + 4 * 1); + store_le(x02, output + 64 * i + 4 * 2); + store_le(x03, output + 64 * i + 4 * 3); + store_le(x04, output + 64 * i + 4 * 4); + store_le(x05, output + 64 * i + 4 * 5); + store_le(x06, output + 64 * i + 4 * 6); + store_le(x07, output + 64 * i + 4 * 7); + store_le(x08, output + 64 * i + 4 * 8); + store_le(x09, output + 64 * i + 4 * 9); + store_le(x10, output + 64 * i + 4 * 10); + store_le(x11, output + 64 * i + 4 * 11); + store_le(x12, output + 64 * i + 4 * 12); + store_le(x13, output + 64 * i + 4 * 13); + store_le(x14, output + 64 * i + 4 * 14); + store_le(x15, output + 64 * i + 4 * 15); + + input[12]++; + input[13] += (input[12] == 0); + } + } + +#undef CHACHA_QUARTER_ROUND + +/* +* Combine cipher stream with message +*/ +void ChaCha::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + const size_t available = m_buffer.size() - m_position; + + xor_buf(out, in, &m_buffer[m_position], available); + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + + length -= available; + in += available; + out += available; + m_position = 0; + } + + xor_buf(out, in, &m_buffer[m_position], length); + + m_position += length; + } + +void ChaCha::write_keystream(uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + const size_t available = m_buffer.size() - m_position; + + copy_mem(out, &m_buffer[m_position], available); + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + + length -= available; + out += available; + m_position = 0; + } + + copy_mem(out, &m_buffer[m_position], length); + + m_position += length; + } + +void ChaCha::initialize_state() + { + static const uint32_t TAU[] = + { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; + + static const uint32_t SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + m_state[4] = m_key[0]; + m_state[5] = m_key[1]; + m_state[6] = m_key[2]; + m_state[7] = m_key[3]; + + if(m_key.size() == 4) + { + m_state[0] = TAU[0]; + m_state[1] = TAU[1]; + m_state[2] = TAU[2]; + m_state[3] = TAU[3]; + + m_state[8] = m_key[0]; + m_state[9] = m_key[1]; + m_state[10] = m_key[2]; + m_state[11] = m_key[3]; + } + else + { + m_state[0] = SIGMA[0]; + m_state[1] = SIGMA[1]; + m_state[2] = SIGMA[2]; + m_state[3] = SIGMA[3]; + + m_state[8] = m_key[4]; + m_state[9] = m_key[5]; + m_state[10] = m_key[6]; + m_state[11] = m_key[7]; + } + + m_state[12] = 0; + m_state[13] = 0; + m_state[14] = 0; + m_state[15] = 0; + + m_position = 0; + } + +/* +* ChaCha Key Schedule +*/ +void ChaCha::key_schedule(const uint8_t key[], size_t length) + { + m_key.resize(length / 4); + load_le(m_key.data(), key, m_key.size()); + + m_state.resize(16); + + const size_t chacha_parallelism = 8; // chacha_x8 + const size_t chacha_block = 64; + m_buffer.resize(chacha_parallelism * chacha_block); + + set_iv(nullptr, 0); + } + +size_t ChaCha::default_iv_length() const + { + return 24; + } + +Key_Length_Specification ChaCha::key_spec() const + { + return Key_Length_Specification(16, 32, 16); + } + +StreamCipher* ChaCha::clone() const + { + return new ChaCha(m_rounds); + } + +bool ChaCha::valid_iv_length(size_t iv_len) const + { + return (iv_len == 0 || iv_len == 8 || iv_len == 12 || iv_len == 24); + } + +void ChaCha::set_iv(const uint8_t iv[], size_t length) + { + verify_key_set(m_state.empty() == false); + + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + initialize_state(); + + if(length == 0) + { + // Treat zero length IV same as an all-zero IV + m_state[14] = 0; + m_state[15] = 0; + } + else if(length == 8) + { + m_state[14] = load_le(iv, 0); + m_state[15] = load_le(iv, 1); + } + else if(length == 12) + { + m_state[13] = load_le(iv, 0); + m_state[14] = load_le(iv, 1); + m_state[15] = load_le(iv, 2); + } + else if(length == 24) + { + m_state[12] = load_le(iv, 0); + m_state[13] = load_le(iv, 1); + m_state[14] = load_le(iv, 2); + m_state[15] = load_le(iv, 3); + + secure_vector hc(8); + hchacha(hc.data(), m_state.data(), m_rounds); + + m_state[ 4] = hc[0]; + m_state[ 5] = hc[1]; + m_state[ 6] = hc[2]; + m_state[ 7] = hc[3]; + m_state[ 8] = hc[4]; + m_state[ 9] = hc[5]; + m_state[10] = hc[6]; + m_state[11] = hc[7]; + m_state[12] = 0; + m_state[13] = 0; + m_state[14] = load_le(iv, 4); + m_state[15] = load_le(iv, 5); + } + + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + m_position = 0; + } + +void ChaCha::clear() + { + zap(m_key); + zap(m_state); + zap(m_buffer); + m_position = 0; + } + +std::string ChaCha::name() const + { + return "ChaCha(" + std::to_string(m_rounds) + ")"; + } + +void ChaCha::seek(uint64_t offset) + { + verify_key_set(m_state.empty() == false); + + // Find the block offset + const uint64_t counter = offset / 64; + + uint8_t out[8]; + + store_le(counter, out); + + m_state[12] = load_le(out, 0); + m_state[13] += load_le(out, 1); + + chacha_x8(m_buffer.data(), m_state.data(), m_rounds); + m_position = offset % 64; + } +} diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha.h b/comm/third_party/botan/src/lib/stream/chacha/chacha.h new file mode 100644 index 0000000000..1749127f28 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha.h @@ -0,0 +1,82 @@ +/* +* ChaCha20 +* (C) 2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CHACHA_H_ +#define BOTAN_CHACHA_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(chacha.h) + +namespace Botan { + +/** +* DJB's ChaCha (https://cr.yp.to/chacha.html) +*/ +class BOTAN_PUBLIC_API(2,0) ChaCha final : public StreamCipher + { + public: + /** + * @param rounds number of rounds + * @note Currently only 8, 12 or 20 rounds are supported, all others + * will throw an exception + */ + explicit ChaCha(size_t rounds = 20); + + std::string provider() const override; + + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void write_keystream(uint8_t out[], size_t len) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + /* + * ChaCha accepts 0, 8, 12 or 24 byte IVs. + * The default IV is a 8 zero bytes. + * An IV of length 0 is treated the same as the default zero IV. + * An IV of length 24 selects XChaCha mode + */ + bool valid_iv_length(size_t iv_len) const override; + + size_t default_iv_length() const override; + + Key_Length_Specification key_spec() const override; + + void clear() override; + + StreamCipher* clone() const override; + + std::string name() const override; + + void seek(uint64_t offset) override; + + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + void initialize_state(); + + void chacha_x8(uint8_t output[64*8], uint32_t state[16], size_t rounds); + +#if defined(BOTAN_HAS_CHACHA_SIMD32) + void chacha_simd32_x4(uint8_t output[64*4], uint32_t state[16], size_t rounds); +#endif + +#if defined(BOTAN_HAS_CHACHA_AVX2) + void chacha_avx2_x8(uint8_t output[64*8], uint32_t state[16], size_t rounds); +#endif + + size_t m_rounds; + secure_vector m_key; + secure_vector m_state; + secure_vector m_buffer; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp new file mode 100644 index 0000000000..78d2365214 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/chacha_avx2.cpp @@ -0,0 +1,207 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +//static +BOTAN_FUNC_ISA("avx2") +void ChaCha::chacha_avx2_x8(uint8_t output[64*8], uint32_t state[16], size_t rounds) + { + SIMD_8x32::reset_registers(); + + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + const SIMD_8x32 CTR0 = SIMD_8x32(0, 1, 2, 3, 4, 5, 6, 7); + + const uint32_t C = 0xFFFFFFFF - state[12]; + const SIMD_8x32 CTR1 = SIMD_8x32(0, C < 1, C < 2, C < 3, C < 4, C < 5, C < 6, C < 7); + + SIMD_8x32 R00 = SIMD_8x32::splat(state[ 0]); + SIMD_8x32 R01 = SIMD_8x32::splat(state[ 1]); + SIMD_8x32 R02 = SIMD_8x32::splat(state[ 2]); + SIMD_8x32 R03 = SIMD_8x32::splat(state[ 3]); + SIMD_8x32 R04 = SIMD_8x32::splat(state[ 4]); + SIMD_8x32 R05 = SIMD_8x32::splat(state[ 5]); + SIMD_8x32 R06 = SIMD_8x32::splat(state[ 6]); + SIMD_8x32 R07 = SIMD_8x32::splat(state[ 7]); + SIMD_8x32 R08 = SIMD_8x32::splat(state[ 8]); + SIMD_8x32 R09 = SIMD_8x32::splat(state[ 9]); + SIMD_8x32 R10 = SIMD_8x32::splat(state[10]); + SIMD_8x32 R11 = SIMD_8x32::splat(state[11]); + SIMD_8x32 R12 = SIMD_8x32::splat(state[12]) + CTR0; + SIMD_8x32 R13 = SIMD_8x32::splat(state[13]) + CTR1; + SIMD_8x32 R14 = SIMD_8x32::splat(state[14]); + SIMD_8x32 R15 = SIMD_8x32::splat(state[15]); + + for(size_t r = 0; r != rounds / 2; ++r) + { + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + R15 = R15.rotl<16>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<12>(); + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + R15 = R15.rotl<8>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<7>(); + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<16>(); + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + R04 = R04.rotl<12>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<8>(); + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + R04 = R04.rotl<7>(); + } + + R00 += SIMD_8x32::splat(state[0]); + R01 += SIMD_8x32::splat(state[1]); + R02 += SIMD_8x32::splat(state[2]); + R03 += SIMD_8x32::splat(state[3]); + R04 += SIMD_8x32::splat(state[4]); + R05 += SIMD_8x32::splat(state[5]); + R06 += SIMD_8x32::splat(state[6]); + R07 += SIMD_8x32::splat(state[7]); + R08 += SIMD_8x32::splat(state[8]); + R09 += SIMD_8x32::splat(state[9]); + R10 += SIMD_8x32::splat(state[10]); + R11 += SIMD_8x32::splat(state[11]); + R12 += SIMD_8x32::splat(state[12]) + CTR0; + R13 += SIMD_8x32::splat(state[13]) + CTR1; + R14 += SIMD_8x32::splat(state[14]); + R15 += SIMD_8x32::splat(state[15]); + + SIMD_8x32::transpose(R00, R01, R02, R03, R04, R05, R06, R07); + SIMD_8x32::transpose(R08, R09, R10, R11, R12, R13, R14, R15); + + R00.store_le(output); + R08.store_le(output + 32*1); + R01.store_le(output + 32*2); + R09.store_le(output + 32*3); + R02.store_le(output + 32*4); + R10.store_le(output + 32*5); + R03.store_le(output + 32*6); + R11.store_le(output + 32*7); + R04.store_le(output + 32*8); + R12.store_le(output + 32*9); + R05.store_le(output + 32*10); + R13.store_le(output + 32*11); + R06.store_le(output + 32*12); + R14.store_le(output + 32*13); + R07.store_le(output + 32*14); + R15.store_le(output + 32*15); + + SIMD_8x32::zero_registers(); + + state[12] += 8; + if(state[12] < 8) + state[13]++; + } +} diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt new file mode 100644 index 0000000000..64f102cc58 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_avx2/info.txt @@ -0,0 +1,11 @@ + +CHACHA_AVX2 -> 20180418 + + + +avx2 + + + +simd_avx2 + diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp new file mode 100644 index 0000000000..6cd6acd0d8 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/chacha_simd32.cpp @@ -0,0 +1,205 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +//static +void ChaCha::chacha_simd32_x4(uint8_t output[64*4], uint32_t state[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + const SIMD_4x32 CTR0 = SIMD_4x32(0, 1, 2, 3); + + const uint32_t C = 0xFFFFFFFF - state[12]; + const SIMD_4x32 CTR1 = SIMD_4x32(0, C < 1, C < 2, C < 3); + + SIMD_4x32 R00 = SIMD_4x32::splat(state[ 0]); + SIMD_4x32 R01 = SIMD_4x32::splat(state[ 1]); + SIMD_4x32 R02 = SIMD_4x32::splat(state[ 2]); + SIMD_4x32 R03 = SIMD_4x32::splat(state[ 3]); + SIMD_4x32 R04 = SIMD_4x32::splat(state[ 4]); + SIMD_4x32 R05 = SIMD_4x32::splat(state[ 5]); + SIMD_4x32 R06 = SIMD_4x32::splat(state[ 6]); + SIMD_4x32 R07 = SIMD_4x32::splat(state[ 7]); + SIMD_4x32 R08 = SIMD_4x32::splat(state[ 8]); + SIMD_4x32 R09 = SIMD_4x32::splat(state[ 9]); + SIMD_4x32 R10 = SIMD_4x32::splat(state[10]); + SIMD_4x32 R11 = SIMD_4x32::splat(state[11]); + SIMD_4x32 R12 = SIMD_4x32::splat(state[12]) + CTR0; + SIMD_4x32 R13 = SIMD_4x32::splat(state[13]) + CTR1; + SIMD_4x32 R14 = SIMD_4x32::splat(state[14]); + SIMD_4x32 R15 = SIMD_4x32::splat(state[15]); + + for(size_t r = 0; r != rounds / 2; ++r) + { + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + R15 = R15.rotl<16>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<12>(); + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + + R00 += R04; + R01 += R05; + R02 += R06; + R03 += R07; + + R12 ^= R00; + R13 ^= R01; + R14 ^= R02; + R15 ^= R03; + + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + R15 = R15.rotl<8>(); + + R08 += R12; + R09 += R13; + R10 += R14; + R11 += R15; + + R04 ^= R08; + R05 ^= R09; + R06 ^= R10; + R07 ^= R11; + + R04 = R04.rotl<7>(); + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<16>(); + R12 = R12.rotl<16>(); + R13 = R13.rotl<16>(); + R14 = R14.rotl<16>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<12>(); + R06 = R06.rotl<12>(); + R07 = R07.rotl<12>(); + R04 = R04.rotl<12>(); + + R00 += R05; + R01 += R06; + R02 += R07; + R03 += R04; + + R15 ^= R00; + R12 ^= R01; + R13 ^= R02; + R14 ^= R03; + + R15 = R15.rotl<8>(); + R12 = R12.rotl<8>(); + R13 = R13.rotl<8>(); + R14 = R14.rotl<8>(); + + R10 += R15; + R11 += R12; + R08 += R13; + R09 += R14; + + R05 ^= R10; + R06 ^= R11; + R07 ^= R08; + R04 ^= R09; + + R05 = R05.rotl<7>(); + R06 = R06.rotl<7>(); + R07 = R07.rotl<7>(); + R04 = R04.rotl<7>(); + } + + R00 += SIMD_4x32::splat(state[0]); + R01 += SIMD_4x32::splat(state[1]); + R02 += SIMD_4x32::splat(state[2]); + R03 += SIMD_4x32::splat(state[3]); + R04 += SIMD_4x32::splat(state[4]); + R05 += SIMD_4x32::splat(state[5]); + R06 += SIMD_4x32::splat(state[6]); + R07 += SIMD_4x32::splat(state[7]); + R08 += SIMD_4x32::splat(state[8]); + R09 += SIMD_4x32::splat(state[9]); + R10 += SIMD_4x32::splat(state[10]); + R11 += SIMD_4x32::splat(state[11]); + R12 += SIMD_4x32::splat(state[12]) + CTR0; + R13 += SIMD_4x32::splat(state[13]) + CTR1; + R14 += SIMD_4x32::splat(state[14]); + R15 += SIMD_4x32::splat(state[15]); + + SIMD_4x32::transpose(R00, R01, R02, R03); + SIMD_4x32::transpose(R04, R05, R06, R07); + SIMD_4x32::transpose(R08, R09, R10, R11); + SIMD_4x32::transpose(R12, R13, R14, R15); + + R00.store_le(output + 0*16); + R04.store_le(output + 1*16); + R08.store_le(output + 2*16); + R12.store_le(output + 3*16); + R01.store_le(output + 4*16); + R05.store_le(output + 5*16); + R09.store_le(output + 6*16); + R13.store_le(output + 7*16); + R02.store_le(output + 8*16); + R06.store_le(output + 9*16); + R10.store_le(output + 10*16); + R14.store_le(output + 11*16); + R03.store_le(output + 12*16); + R07.store_le(output + 13*16); + R11.store_le(output + 14*16); + R15.store_le(output + 15*16); + + state[12] += 4; + if(state[12] < 4) + state[13]++; + } + +} diff --git a/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt new file mode 100644 index 0000000000..1ec932f811 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/chacha_simd32/info.txt @@ -0,0 +1,7 @@ + +CHACHA_SIMD32 -> 20181104 + + + +simd + diff --git a/comm/third_party/botan/src/lib/stream/chacha/info.txt b/comm/third_party/botan/src/lib/stream/chacha/info.txt new file mode 100644 index 0000000000..ba9c3da341 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/chacha/info.txt @@ -0,0 +1,3 @@ + +CHACHA -> 20180807 + diff --git a/comm/third_party/botan/src/lib/stream/ctr/ctr.cpp b/comm/third_party/botan/src/lib/stream/ctr/ctr.cpp new file mode 100644 index 0000000000..e2ed0e7126 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ctr/ctr.cpp @@ -0,0 +1,256 @@ +/* +* Counter mode +* (C) 1999-2011,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +CTR_BE::CTR_BE(BlockCipher* ciph) : + m_cipher(ciph), + m_block_size(m_cipher->block_size()), + m_ctr_size(m_block_size), + m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), + m_counter(m_cipher->parallel_bytes()), + m_pad(m_counter.size()), + m_pad_pos(0) + { + } + +CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()), + m_ctr_size(ctr_size), + m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), + m_counter(m_cipher->parallel_bytes()), + m_pad(m_counter.size()), + m_pad_pos(0) + { + BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size, + "Invalid CTR-BE counter size"); + } + +void CTR_BE::clear() + { + m_cipher->clear(); + zeroise(m_pad); + zeroise(m_counter); + zap(m_iv); + m_pad_pos = 0; + } + +size_t CTR_BE::default_iv_length() const + { + return m_block_size; + } + +bool CTR_BE::valid_iv_length(size_t iv_len) const + { + return (iv_len <= m_block_size); + } + +Key_Length_Specification CTR_BE::key_spec() const + { + return m_cipher->key_spec(); + } + +CTR_BE* CTR_BE::clone() const + { + return new CTR_BE(m_cipher->clone(), m_ctr_size); + } + +void CTR_BE::key_schedule(const uint8_t key[], size_t key_len) + { + m_cipher->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +std::string CTR_BE::name() const + { + if(m_ctr_size == m_block_size) + return ("CTR-BE(" + m_cipher->name() + ")"); + else + return ("CTR-BE(" + m_cipher->name() + "," + std::to_string(m_ctr_size) + ")"); + + } + +void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_iv.empty() == false); + + const uint8_t* pad_bits = &m_pad[0]; + const size_t pad_size = m_pad.size(); + + if(m_pad_pos > 0) + { + const size_t avail = pad_size - m_pad_pos; + const size_t take = std::min(length, avail); + xor_buf(out, in, pad_bits + m_pad_pos, take); + length -= take; + in += take; + out += take; + m_pad_pos += take; + + if(take == avail) + { + add_counter(m_ctr_blocks); + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + m_pad_pos = 0; + } + } + + while(length >= pad_size) + { + xor_buf(out, in, pad_bits, pad_size); + length -= pad_size; + in += pad_size; + out += pad_size; + + add_counter(m_ctr_blocks); + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + } + + xor_buf(out, in, pad_bits, length); + m_pad_pos += length; + } + +void CTR_BE::set_iv(const uint8_t iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + m_iv.resize(m_block_size); + zeroise(m_iv); + buffer_insert(m_iv, 0, iv, iv_len); + + seek(0); + } + +void CTR_BE::add_counter(const uint64_t counter) + { + const size_t ctr_size = m_ctr_size; + const size_t ctr_blocks = m_ctr_blocks; + const size_t BS = m_block_size; + + if(ctr_size == 4) + { + const size_t off = (BS - 4); + const uint32_t low32 = static_cast(counter + load_be(&m_counter[off], 0)); + + for(size_t i = 0; i != ctr_blocks; ++i) + { + store_be(uint32_t(low32 + i), &m_counter[i*BS+off]); + } + } + else if(ctr_size == 8) + { + const size_t off = (BS - 8); + const uint64_t low64 = counter + load_be(&m_counter[off], 0); + + for(size_t i = 0; i != ctr_blocks; ++i) + { + store_be(uint64_t(low64 + i), &m_counter[i*BS+off]); + } + } + else if(ctr_size == 16) + { + const size_t off = (BS - 16); + uint64_t b0 = load_be(&m_counter[off], 0); + uint64_t b1 = load_be(&m_counter[off], 1); + b1 += counter; + b0 += (b1 < counter) ? 1 : 0; // carry + + for(size_t i = 0; i != ctr_blocks; ++i) + { + store_be(b0, &m_counter[i*BS+off]); + store_be(b1, &m_counter[i*BS+off+8]); + b1 += 1; + b0 += (b1 == 0); // carry + } + } + else + { + for(size_t i = 0; i != ctr_blocks; ++i) + { + uint64_t local_counter = counter; + uint16_t carry = static_cast(local_counter); + for(size_t j = 0; (carry || local_counter) && j != ctr_size; ++j) + { + const size_t off = i*BS + (BS-1-j); + const uint16_t cnt = static_cast(m_counter[off]) + carry; + m_counter[off] = static_cast(cnt); + local_counter = (local_counter >> 8); + carry = (cnt >> 8) + static_cast(local_counter); + } + } + } + } + +void CTR_BE::seek(uint64_t offset) + { + verify_key_set(m_iv.empty() == false); + + const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size()); + + zeroise(m_counter); + buffer_insert(m_counter, 0, m_iv); + + const size_t BS = m_block_size; + + // Set m_counter blocks to IV, IV + 1, ... IV + n + + if(m_ctr_size == 4 && BS >= 8) + { + const uint32_t low32 = load_be(&m_counter[BS-4], 0); + + if(m_ctr_blocks >= 4 && is_power_of_2(m_ctr_blocks)) + { + size_t written = 1; + while(written < m_ctr_blocks) + { + copy_mem(&m_counter[written*BS], &m_counter[0], BS*written); + written *= 2; + } + } + else + { + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + copy_mem(&m_counter[i*BS], &m_counter[0], BS - 4); + } + } + + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + const uint32_t c = static_cast(low32 + i); + store_be(c, &m_counter[(BS-4)+i*BS]); + } + } + else + { + // do everything sequentially: + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + buffer_insert(m_counter, i*BS, &m_counter[(i-1)*BS], BS); + + for(size_t j = 0; j != m_ctr_size; ++j) + if(++m_counter[i*BS + (BS - 1 - j)]) + break; + } + } + + if(base_counter > 0) + add_counter(base_counter); + + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + m_pad_pos = offset % m_counter.size(); + } +} diff --git a/comm/third_party/botan/src/lib/stream/ctr/ctr.h b/comm/third_party/botan/src/lib/stream/ctr/ctr.h new file mode 100644 index 0000000000..0687c606e1 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ctr/ctr.h @@ -0,0 +1,65 @@ +/* +* CTR-BE Mode +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CTR_BE_H_ +#define BOTAN_CTR_BE_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(ctr.h) + +namespace Botan { + +/** +* CTR-BE (Counter mode, big-endian) +*/ +class BOTAN_PUBLIC_API(2,0) CTR_BE final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + size_t default_iv_length() const override; + + bool valid_iv_length(size_t iv_len) const override; + + Key_Length_Specification key_spec() const override; + + std::string name() const override; + + CTR_BE* clone() const override; + + void clear() override; + + /** + * @param cipher the block cipher to use + */ + explicit CTR_BE(BlockCipher* cipher); + + CTR_BE(BlockCipher* cipher, size_t ctr_size); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + void add_counter(const uint64_t counter); + + std::unique_ptr m_cipher; + + const size_t m_block_size; + const size_t m_ctr_size; + const size_t m_ctr_blocks; + + secure_vector m_counter, m_pad; + std::vector m_iv; + size_t m_pad_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/ctr/info.txt b/comm/third_party/botan/src/lib/stream/ctr/info.txt new file mode 100644 index 0000000000..270ceecf8b --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ctr/info.txt @@ -0,0 +1,7 @@ + +CTR_BE -> 20131128 + + + +block + diff --git a/comm/third_party/botan/src/lib/stream/info.txt b/comm/third_party/botan/src/lib/stream/info.txt new file mode 100644 index 0000000000..4f62c5a7c1 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/info.txt @@ -0,0 +1,7 @@ + +STREAM_CIPHER -> 20131128 + + + +stream_cipher.h + diff --git a/comm/third_party/botan/src/lib/stream/ofb/info.txt b/comm/third_party/botan/src/lib/stream/ofb/info.txt new file mode 100644 index 0000000000..2675e78573 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ofb/info.txt @@ -0,0 +1,7 @@ + +OFB -> 20131128 + + + +block + diff --git a/comm/third_party/botan/src/lib/stream/ofb/ofb.cpp b/comm/third_party/botan/src/lib/stream/ofb/ofb.cpp new file mode 100644 index 0000000000..dde4681171 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ofb/ofb.cpp @@ -0,0 +1,92 @@ +/* +* OFB Mode +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +OFB::OFB(BlockCipher* cipher) : + m_cipher(cipher), + m_buffer(m_cipher->block_size()), + m_buf_pos(0) + { + } + +void OFB::clear() + { + m_cipher->clear(); + zeroise(m_buffer); + m_buf_pos = 0; + } + +void OFB::key_schedule(const uint8_t key[], size_t key_len) + { + m_cipher->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +std::string OFB::name() const + { + return "OFB(" + m_cipher->name() + ")"; + } + +size_t OFB::default_iv_length() const + { + return m_cipher->block_size(); + } + +bool OFB::valid_iv_length(size_t iv_len) const + { + return (iv_len <= m_cipher->block_size()); + } + +Key_Length_Specification OFB::key_spec() const + { + return m_cipher->key_spec(); + } + +OFB* OFB::clone() const + { + return new OFB(m_cipher->clone()); + } + +void OFB::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + while(length >= m_buffer.size() - m_buf_pos) + { + xor_buf(out, in, &m_buffer[m_buf_pos], m_buffer.size() - m_buf_pos); + length -= (m_buffer.size() - m_buf_pos); + in += (m_buffer.size() - m_buf_pos); + out += (m_buffer.size() - m_buf_pos); + m_cipher->encrypt(m_buffer); + m_buf_pos = 0; + } + xor_buf(out, in, &m_buffer[m_buf_pos], length); + m_buf_pos += length; + } + +void OFB::set_iv(const uint8_t iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + zeroise(m_buffer); + buffer_insert(m_buffer, 0, iv, iv_len); + + m_cipher->encrypt(m_buffer); + m_buf_pos = 0; + } + + +void OFB::seek(uint64_t) + { + throw Not_Implemented("OFB does not support seeking"); + } +} diff --git a/comm/third_party/botan/src/lib/stream/ofb/ofb.h b/comm/third_party/botan/src/lib/stream/ofb/ofb.h new file mode 100644 index 0000000000..994d3d198d --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/ofb/ofb.h @@ -0,0 +1,56 @@ +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OUTPUT_FEEDBACK_MODE_H_ +#define BOTAN_OUTPUT_FEEDBACK_MODE_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(ofb.h) + +namespace Botan { + +/** +* Output Feedback Mode +*/ +class BOTAN_PUBLIC_API(2,0) OFB final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + size_t default_iv_length() const override; + + bool valid_iv_length(size_t iv_len) const override; + + Key_Length_Specification key_spec() const override; + + std::string name() const override; + + OFB* clone() const override; + + void clear() override; + + /** + * @param cipher the block cipher to use + */ + explicit OFB(BlockCipher* cipher); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + std::unique_ptr m_cipher; + secure_vector m_buffer; + size_t m_buf_pos; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/rc4/info.txt b/comm/third_party/botan/src/lib/stream/rc4/info.txt new file mode 100644 index 0000000000..97cc227602 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/rc4/info.txt @@ -0,0 +1,3 @@ + +RC4 -> 20131128 + diff --git a/comm/third_party/botan/src/lib/stream/rc4/rc4.cpp b/comm/third_party/botan/src/lib/stream/rc4/rc4.cpp new file mode 100644 index 0000000000..8bb01a2387 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/rc4/rc4.cpp @@ -0,0 +1,133 @@ +/* +* RC4 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* +* Combine cipher stream with message +*/ +void RC4::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); + length -= (m_buffer.size() - m_position); + in += (m_buffer.size() - m_position); + out += (m_buffer.size() - m_position); + generate(); + } + xor_buf(out, in, &m_buffer[m_position], length); + m_position += length; + } + +StreamCipher* RC4::clone() const + { + return new RC4(m_SKIP); + } + +Key_Length_Specification RC4::key_spec() const + { + return Key_Length_Specification(1, 256); + } + +void RC4::set_iv(const uint8_t*, size_t length) + { + if(length > 0) + throw Invalid_IV_Length("RC4", length); + } + +/* +* Generate cipher stream +*/ +void RC4::generate() + { + uint8_t SX, SY; + for(size_t i = 0; i != m_buffer.size(); i += 4) + { + SX = m_state[m_X+1]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X+1] = SY; m_state[m_Y] = SX; + m_buffer[i] = m_state[(SX + SY) % 256]; + + SX = m_state[m_X+2]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X+2] = SY; m_state[m_Y] = SX; + m_buffer[i+1] = m_state[(SX + SY) % 256]; + + SX = m_state[m_X+3]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X+3] = SY; m_state[m_Y] = SX; + m_buffer[i+2] = m_state[(SX + SY) % 256]; + + m_X = (m_X + 4) % 256; + SX = m_state[m_X]; m_Y = (m_Y + SX) % 256; SY = m_state[m_Y]; + m_state[m_X] = SY; m_state[m_Y] = SX; + m_buffer[i+3] = m_state[(SX + SY) % 256]; + } + m_position = 0; + } + +/* +* RC4 Key Schedule +*/ +void RC4::key_schedule(const uint8_t key[], size_t length) + { + m_state.resize(256); + m_buffer.resize(256); + + m_position = m_X = m_Y = 0; + + for(size_t i = 0; i != 256; ++i) + m_state[i] = static_cast(i); + + for(size_t i = 0, state_index = 0; i != 256; ++i) + { + state_index = (state_index + key[i % length] + m_state[i]) % 256; + std::swap(m_state[i], m_state[state_index]); + } + + for(size_t i = 0; i <= m_SKIP; i += m_buffer.size()) + generate(); + + m_position += (m_SKIP % m_buffer.size()); + } + +/* +* Return the name of this type +*/ +std::string RC4::name() const + { + if(m_SKIP == 0) + return "RC4"; + else if(m_SKIP == 256) + return "MARK-4"; + else + return "RC4(" + std::to_string(m_SKIP) + ")"; + } + +/* +* Clear memory of sensitive data +*/ +void RC4::clear() + { + zap(m_state); + zap(m_buffer); + m_position = m_X = m_Y = 0; + } + +/* +* RC4 Constructor +*/ +RC4::RC4(size_t s) : m_SKIP(s) {} + +void RC4::seek(uint64_t) + { + throw Not_Implemented("RC4 does not support seeking"); + } +} diff --git a/comm/third_party/botan/src/lib/stream/rc4/rc4.h b/comm/third_party/botan/src/lib/stream/rc4/rc4.h new file mode 100644 index 0000000000..eff3c568db --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/rc4/rc4.h @@ -0,0 +1,57 @@ +/* +* RC4 +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RC4_H_ +#define BOTAN_RC4_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(rc4.h) + +namespace Botan { + +/** +* RC4 stream cipher +*/ +class BOTAN_PUBLIC_API(2,0) RC4 final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + void clear() override; + std::string name() const override; + + StreamCipher* clone() const override; + + Key_Length_Specification key_spec() const override; + + /** + * @param skip skip this many initial bytes in the keystream + */ + explicit RC4(size_t skip = 0); + + ~RC4() { clear(); } + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t[], size_t) override; + void generate(); + + const size_t m_SKIP; + uint8_t m_X = 0; + uint8_t m_Y = 0; + secure_vector m_state; + secure_vector m_buffer; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/salsa20/info.txt b/comm/third_party/botan/src/lib/stream/salsa20/info.txt new file mode 100644 index 0000000000..8e9bfa5683 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/salsa20/info.txt @@ -0,0 +1,3 @@ + +SALSA20 -> 20171114 + diff --git a/comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp new file mode 100644 index 0000000000..1e30391d21 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.cpp @@ -0,0 +1,302 @@ +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4) \ + do { \ + x2 ^= rotl<7>(x1 + x4); \ + x3 ^= rotl<9>(x2 + x1); \ + x4 ^= rotl<13>(x3 + x2); \ + x1 ^= rotl<18>(x4 + x3); \ + } while(0) + +/* +* Generate HSalsa20 cipher stream (for XSalsa20 IV setup) +*/ +//static +void Salsa20::hsalsa20(uint32_t output[8], const uint32_t input[16]) + { + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != 10; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + output[0] = x00; + output[1] = x05; + output[2] = x10; + output[3] = x15; + output[4] = x06; + output[5] = x07; + output[6] = x08; + output[7] = x09; + } + +/* +* Generate Salsa20 cipher stream +*/ +//static +void Salsa20::salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds) + { + BOTAN_ASSERT_NOMSG(rounds % 2 == 0); + + uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], + x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], + x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], + x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15]; + + for(size_t i = 0; i != rounds / 2; ++i) + { + SALSA20_QUARTER_ROUND(x00, x04, x08, x12); + SALSA20_QUARTER_ROUND(x05, x09, x13, x01); + SALSA20_QUARTER_ROUND(x10, x14, x02, x06); + SALSA20_QUARTER_ROUND(x15, x03, x07, x11); + + SALSA20_QUARTER_ROUND(x00, x01, x02, x03); + SALSA20_QUARTER_ROUND(x05, x06, x07, x04); + SALSA20_QUARTER_ROUND(x10, x11, x08, x09); + SALSA20_QUARTER_ROUND(x15, x12, x13, x14); + } + + store_le(x00 + input[ 0], output + 4 * 0); + store_le(x01 + input[ 1], output + 4 * 1); + store_le(x02 + input[ 2], output + 4 * 2); + store_le(x03 + input[ 3], output + 4 * 3); + store_le(x04 + input[ 4], output + 4 * 4); + store_le(x05 + input[ 5], output + 4 * 5); + store_le(x06 + input[ 6], output + 4 * 6); + store_le(x07 + input[ 7], output + 4 * 7); + store_le(x08 + input[ 8], output + 4 * 8); + store_le(x09 + input[ 9], output + 4 * 9); + store_le(x10 + input[10], output + 4 * 10); + store_le(x11 + input[11], output + 4 * 11); + store_le(x12 + input[12], output + 4 * 12); + store_le(x13 + input[13], output + 4 * 13); + store_le(x14 + input[14], output + 4 * 14); + store_le(x15 + input[15], output + 4 * 15); + } + +#undef SALSA20_QUARTER_ROUND + +/* +* Combine cipher stream with message +*/ +void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_state.empty() == false); + + while(length >= m_buffer.size() - m_position) + { + const size_t available = m_buffer.size() - m_position; + + xor_buf(out, in, &m_buffer[m_position], available); + salsa_core(m_buffer.data(), m_state.data(), 20); + + ++m_state[8]; + m_state[9] += (m_state[8] == 0); + + length -= available; + in += available; + out += available; + + m_position = 0; + } + + xor_buf(out, in, &m_buffer[m_position], length); + + m_position += length; + } + +void Salsa20::initialize_state() + { + static const uint32_t TAU[] = + { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 }; + + static const uint32_t SIGMA[] = + { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; + + m_state[1] = m_key[0]; + m_state[2] = m_key[1]; + m_state[3] = m_key[2]; + m_state[4] = m_key[3]; + + if(m_key.size() == 4) + { + m_state[0] = TAU[0]; + m_state[5] = TAU[1]; + m_state[10] = TAU[2]; + m_state[15] = TAU[3]; + m_state[11] = m_key[0]; + m_state[12] = m_key[1]; + m_state[13] = m_key[2]; + m_state[14] = m_key[3]; + } + else + { + m_state[0] = SIGMA[0]; + m_state[5] = SIGMA[1]; + m_state[10] = SIGMA[2]; + m_state[15] = SIGMA[3]; + m_state[11] = m_key[4]; + m_state[12] = m_key[5]; + m_state[13] = m_key[6]; + m_state[14] = m_key[7]; + } + + m_state[6] = 0; + m_state[7] = 0; + m_state[8] = 0; + m_state[9] = 0; + + m_position = 0; + } + +/* +* Salsa20 Key Schedule +*/ +void Salsa20::key_schedule(const uint8_t key[], size_t length) + { + m_key.resize(length / 4); + load_le(m_key.data(), key, m_key.size()); + + m_state.resize(16); + m_buffer.resize(64); + + set_iv(nullptr, 0); + } + +/* +* Set the Salsa IV +*/ +void Salsa20::set_iv(const uint8_t iv[], size_t length) + { + verify_key_set(m_state.empty() == false); + + if(!valid_iv_length(length)) + throw Invalid_IV_Length(name(), length); + + initialize_state(); + + if(length == 0) + { + // Salsa20 null IV + m_state[6] = 0; + m_state[7] = 0; + } + else if(length == 8) + { + // Salsa20 + m_state[6] = load_le(iv, 0); + m_state[7] = load_le(iv, 1); + } + else + { + // XSalsa20 + m_state[6] = load_le(iv, 0); + m_state[7] = load_le(iv, 1); + m_state[8] = load_le(iv, 2); + m_state[9] = load_le(iv, 3); + + secure_vector hsalsa(8); + hsalsa20(hsalsa.data(), m_state.data()); + + m_state[ 1] = hsalsa[0]; + m_state[ 2] = hsalsa[1]; + m_state[ 3] = hsalsa[2]; + m_state[ 4] = hsalsa[3]; + m_state[ 6] = load_le(iv, 4); + m_state[ 7] = load_le(iv, 5); + m_state[11] = hsalsa[4]; + m_state[12] = hsalsa[5]; + m_state[13] = hsalsa[6]; + m_state[14] = hsalsa[7]; + } + + m_state[8] = 0; + m_state[9] = 0; + + salsa_core(m_buffer.data(), m_state.data(), 20); + ++m_state[8]; + m_state[9] += (m_state[8] == 0); + + m_position = 0; + } + +bool Salsa20::valid_iv_length(size_t iv_len) const + { + return (iv_len == 0 || iv_len == 8 || iv_len == 24); + } + +size_t Salsa20::default_iv_length() const + { + return 24; + } + +Key_Length_Specification Salsa20::key_spec() const + { + return Key_Length_Specification(16, 32, 16); + } + +StreamCipher* Salsa20::clone() const + { + return new Salsa20; + } + +std::string Salsa20::name() const + { + return "Salsa20"; + } + +/* +* Clear memory of sensitive data +*/ +void Salsa20::clear() + { + zap(m_key); + zap(m_state); + zap(m_buffer); + m_position = 0; + } + +void Salsa20::seek(uint64_t offset) + { + verify_key_set(m_state.empty() == false); + + // Find the block offset + const uint64_t counter = offset / 64; + uint8_t counter8[8]; + store_le(counter, counter8); + + m_state[8] = load_le(counter8, 0); + m_state[9] += load_le(counter8, 1); + + salsa_core(m_buffer.data(), m_state.data(), 20); + + ++m_state[8]; + m_state[9] += (m_state[8] == 0); + + m_position = offset % 64; + } +} diff --git a/comm/third_party/botan/src/lib/stream/salsa20/salsa20.h b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.h new file mode 100644 index 0000000000..6ad0da7709 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/salsa20/salsa20.h @@ -0,0 +1,54 @@ +/* +* Salsa20 / XSalsa20 +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SALSA20_H_ +#define BOTAN_SALSA20_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(salsa20.h) + +namespace Botan { + +/** +* DJB's Salsa20 (and XSalsa20) +*/ +class BOTAN_PUBLIC_API(2,0) Salsa20 final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + bool valid_iv_length(size_t iv_len) const override; + + size_t default_iv_length() const override; + + Key_Length_Specification key_spec() const override; + + void clear() override; + std::string name() const override; + StreamCipher* clone() const override; + + static void salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds); + static void hsalsa20(uint32_t output[8], const uint32_t input[16]); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + void initialize_state(); + + secure_vector m_key; + secure_vector m_state; + secure_vector m_buffer; + size_t m_position = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/shake_cipher/info.txt b/comm/third_party/botan/src/lib/stream/shake_cipher/info.txt new file mode 100644 index 0000000000..ca2a0c079c --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/shake_cipher/info.txt @@ -0,0 +1,7 @@ + +SHAKE_CIPHER -> 20161018 + + + +sha3 + diff --git a/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp new file mode 100644 index 0000000000..f1920959e3 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.cpp @@ -0,0 +1,90 @@ +/* +* SHAKE-128 +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +SHAKE_128_Cipher::SHAKE_128_Cipher() : + m_buf_pos(0) + {} + +void SHAKE_128_Cipher::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + const size_t SHAKE_128_BYTERATE = (1600-256)/8; + + verify_key_set(m_state.empty() == false); + + while(length >= SHAKE_128_BYTERATE - m_buf_pos) + { + xor_buf(out, in, &m_buffer[m_buf_pos], SHAKE_128_BYTERATE - m_buf_pos); + length -= (SHAKE_128_BYTERATE - m_buf_pos); + in += (SHAKE_128_BYTERATE - m_buf_pos); + out += (SHAKE_128_BYTERATE - m_buf_pos); + + SHA_3::permute(m_state.data()); + copy_out_le(m_buffer.data(), SHAKE_128_BYTERATE, m_state.data()); + + m_buf_pos = 0; + } + xor_buf(out, in, &m_buffer[m_buf_pos], length); + m_buf_pos += length; + } + +void SHAKE_128_Cipher::key_schedule(const uint8_t key[], size_t length) + { + const size_t SHAKE_128_BITRATE = (1600-256); + m_state.resize(25); + m_buffer.resize(SHAKE_128_BITRATE/8); + zeroise(m_state); + + const size_t S_pos = SHA_3::absorb(SHAKE_128_BITRATE, m_state, 0, key, length); + SHA_3::finish(SHAKE_128_BITRATE, m_state, S_pos, 0x1F, 0x80); + copy_out_le(m_buffer.data(), m_buffer.size(), m_state.data()); + } + +void SHAKE_128_Cipher::clear() + { + zap(m_state); + zap(m_buffer); + m_buf_pos = 0; + } + +void SHAKE_128_Cipher::set_iv(const uint8_t[], size_t length) + { + /* + * This could be supported in some way (say, by treating iv as + * a prefix or suffix of the key). + */ + if(length != 0) + throw Invalid_IV_Length(name(), length); + } + +void SHAKE_128_Cipher::seek(uint64_t) + { + throw Not_Implemented("SHAKE_128_Cipher::seek"); + } + +Key_Length_Specification SHAKE_128_Cipher::key_spec() const + { + return Key_Length_Specification(1, 160); + } + +std::string SHAKE_128_Cipher::name() const + { + return "SHAKE-128"; + } + +StreamCipher* SHAKE_128_Cipher::clone() const + { + return new SHAKE_128_Cipher; + } + +} diff --git a/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h new file mode 100644 index 0000000000..85eaec2a85 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/shake_cipher/shake_cipher.h @@ -0,0 +1,57 @@ +/* +* SHAKE-128 as a stream cipher +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHAKE128_CIPHER_H_ +#define BOTAN_SHAKE128_CIPHER_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(shake_cipher.h) + +namespace Botan { + +/** +* SHAKE-128 XOF presented as a stream cipher +*/ +class BOTAN_PUBLIC_API(2,0) SHAKE_128_Cipher final : public StreamCipher + { + public: + SHAKE_128_Cipher(); + + /** + * Produce more XOF output + */ + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + /** + * Seeking is not supported, this function will throw + */ + void seek(uint64_t offset) override; + + /** + * IV not supported, this function will throw unless iv_len == 0 + */ + void set_iv(const uint8_t iv[], size_t iv_len) override; + + Key_Length_Specification key_spec() const override; + + void clear() override; + std::string name() const override; + StreamCipher* clone() const override; + + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + + secure_vector m_state; // internal state + secure_vector m_buffer; // ciphertext buffer + size_t m_buf_pos; // position in m_buffer + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/stream/stream_cipher.cpp b/comm/third_party/botan/src/lib/stream/stream_cipher.cpp new file mode 100644 index 0000000000..340682ce25 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/stream_cipher.cpp @@ -0,0 +1,149 @@ +/* +* Stream Ciphers +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_CHACHA) + #include +#endif + +#if defined(BOTAN_HAS_SALSA20) + #include +#endif + +#if defined(BOTAN_HAS_SHAKE_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_CTR_BE) + #include +#endif + +#if defined(BOTAN_HAS_OFB) + #include +#endif + +#if defined(BOTAN_HAS_RC4) + #include +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include +#endif + +namespace Botan { + +std::unique_ptr StreamCipher::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_CTR_BE) + if((req.algo_name() == "CTR-BE" || req.algo_name() == "CTR") && req.arg_count_between(1,2)) + { + if(provider.empty() || provider == "base") + { + auto cipher = BlockCipher::create(req.arg(0)); + if(cipher) + { + size_t ctr_size = req.arg_as_integer(1, cipher->block_size()); + return std::unique_ptr(new CTR_BE(cipher.release(), ctr_size)); + } + } + } +#endif + +#if defined(BOTAN_HAS_CHACHA) + if(req.algo_name() == "ChaCha") + { + if(provider.empty() || provider == "base") + return std::unique_ptr(new ChaCha(req.arg_as_integer(0, 20))); + } + + if(req.algo_name() == "ChaCha20") + { + if(provider.empty() || provider == "base") + return std::unique_ptr(new ChaCha(20)); + } +#endif + +#if defined(BOTAN_HAS_SALSA20) + if(req.algo_name() == "Salsa20") + { + if(provider.empty() || provider == "base") + return std::unique_ptr(new Salsa20); + } +#endif + +#if defined(BOTAN_HAS_SHAKE_CIPHER) + if(req.algo_name() == "SHAKE-128" || req.algo_name() == "SHAKE-128-XOF") + { + if(provider.empty() || provider == "base") + return std::unique_ptr(new SHAKE_128_Cipher); + } +#endif + +#if defined(BOTAN_HAS_OFB) + if(req.algo_name() == "OFB" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto c = BlockCipher::create(req.arg(0))) + return std::unique_ptr(new OFB(c.release())); + } + } +#endif + +#if defined(BOTAN_HAS_RC4) + + if(req.algo_name() == "RC4" || + req.algo_name() == "ARC4" || + req.algo_name() == "MARK-4") + { + const size_t skip = (req.algo_name() == "MARK-4") ? 256 : req.arg_as_integer(0, 0); + +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + return std::unique_ptr(make_openssl_rc4(skip)); + } +#endif + + if(provider.empty() || provider == "base") + { + return std::unique_ptr(new RC4(skip)); + } + } + +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr +StreamCipher::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto sc = StreamCipher::create(algo, provider)) + { + return sc; + } + throw Lookup_Error("Stream cipher", algo, provider); + } + +std::vector StreamCipher::providers(const std::string& algo_spec) + { + return probe_providers_of(algo_spec, {"base", "openssl"}); + } + +} diff --git a/comm/third_party/botan/src/lib/stream/stream_cipher.h b/comm/third_party/botan/src/lib/stream/stream_cipher.h new file mode 100644 index 0000000000..a07f210413 --- /dev/null +++ b/comm/third_party/botan/src/lib/stream/stream_cipher.h @@ -0,0 +1,147 @@ +/* +* Stream Cipher +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREAM_CIPHER_H_ +#define BOTAN_STREAM_CIPHER_H_ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Base class for all stream ciphers +*/ +class BOTAN_PUBLIC_API(2,0) StreamCipher : public SymmetricAlgorithm + { + public: + virtual ~StreamCipher() = default; + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws a Lookup_Error if the algo/provider combination cannot be found + */ + static std::unique_ptr + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector providers(const std::string& algo_spec); + + /** + * Encrypt or decrypt a message + * @param in the plaintext + * @param out the byte array to hold the output, i.e. the ciphertext + * @param len the length of both in and out in bytes + */ + virtual void cipher(const uint8_t in[], uint8_t out[], size_t len) = 0; + + /** + * Write keystream bytes to a buffer + * @param out the byte array to hold the keystream + * @param len the length of out in bytes + */ + virtual void write_keystream(uint8_t out[], size_t len) + { + clear_mem(out, len); + cipher1(out, len); + } + + /** + * Encrypt or decrypt a message + * The message is encrypted/decrypted in place. + * @param buf the plaintext / ciphertext + * @param len the length of buf in bytes + */ + void cipher1(uint8_t buf[], size_t len) + { cipher(buf, buf, len); } + + /** + * Encrypt a message + * The message is encrypted/decrypted in place. + * @param inout the plaintext / ciphertext + */ + template + void encipher(std::vector& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Encrypt a message + * The message is encrypted in place. + * @param inout the plaintext / ciphertext + */ + template + void encrypt(std::vector& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Decrypt a message in place + * The message is decrypted in place. + * @param inout the plaintext / ciphertext + */ + template + void decrypt(std::vector& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Resync the cipher using the IV + * @param iv the initialization vector + * @param iv_len the length of the IV in bytes + */ + virtual void set_iv(const uint8_t iv[], size_t iv_len) = 0; + + /** + * Return the default (preferred) nonce length + * If this function returns 0, then this cipher does not support nonces + */ + virtual size_t default_iv_length() const { return 0; } + + /** + * @param iv_len the length of the IV in bytes + * @return if the length is valid for this algorithm + */ + virtual bool valid_iv_length(size_t iv_len) const { return (iv_len == 0); } + + /** + * @return a new object representing the same algorithm as *this + */ + virtual StreamCipher* clone() const = 0; + + /** + * Set the offset and the state used later to generate the keystream + * @param offset the offset where we begin to generate the keystream + */ + virtual void seek(uint64_t offset) = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/asio/asio_async_ops.h b/comm/third_party/botan/src/lib/tls/asio/asio_async_ops.h new file mode 100644 index 0000000000..47267a569d --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/asio/asio_async_ops.h @@ -0,0 +1,355 @@ +/* +* Helpers for TLS ASIO Stream +* (C) 2018-2020 Jack Lloyd +* 2018-2020 Hannes Rantzsch, Tim Oesterreich, Rene Meusel +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASIO_ASYNC_OPS_H_ +#define BOTAN_ASIO_ASYNC_OPS_H_ + +#include + +#include +#if BOOST_VERSION >= 106600 + +#include + +// We need to define BOOST_ASIO_DISABLE_SERIAL_PORT before any asio imports. Otherwise asio will include , +// which interferes with Botan's amalgamation by defining macros like 'B0' and 'FF1'. +#define BOOST_ASIO_DISABLE_SERIAL_PORT +#include +#include + +namespace Botan { +namespace TLS { +namespace detail { + +/** + * Base class for asynchronous stream operations. + * + * Asynchronous operations, used for example to implement an interface for boost::asio::async_read_some and + * boost::asio::async_write_some, are based on boost::asio::coroutines. + * Derived operations should implement a call operator and invoke it with the correct parameters upon construction. The + * call operator needs to make sure that the user-provided handler is not called directly. Typically, yield / reenter is + * used for this in the following fashion: + * + * ``` + * void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true) + * { + * reenter(this) + * { + * // operation specific logic, repeatedly interacting with the stream_core and the next_layer (socket) + * + * // make sure intermediate initiating function is called + * if(!isContinuation) + * { + * yield next_layer.async_operation(empty_buffer, this); + * } + * + * // call the completion handler + * complete_now(error_code, bytes_transferred); + * } + * } + * ``` + * + * Once the operation is completed and ready to call the completion handler it checks if an intermediate initiating + * function has been called using the `isContinuation` parameter. If not, it will call an asynchronous operation, such + * as `async_read_some`, with and empty buffer, set the object itself as the handler, and `yield`. As a result, the call + * operator will be invoked again, this time as a continuation, and will jump to the location where it yielded before + * using `reenter`. It is now safe to call the handler function via `complete_now`. + * + * \tparam Handler Type of the completion handler + * \tparam Executor1 Type of the asio executor (usually derived from the lower layer) + * \tparam Allocator Type of the allocator to be used + */ +template +class AsyncBase : public boost::asio::coroutine + { + public: + using allocator_type = boost::asio::associated_allocator_t; + using executor_type = boost::asio::associated_executor_t; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator(m_handler); + } + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor(m_handler, m_work_guard_1.get_executor()); + } + + protected: + template + AsyncBase(HandlerT&& handler, const Executor1& executor) + : m_handler(std::forward(handler)) + , m_work_guard_1(executor) + { + } + + /** + * Call the completion handler. + * + * This function should only be called after an intermediate initiating function has been called. + * + * @param args Arguments forwarded to the completion handler function. + */ + template + void complete_now(Args&& ... args) + { + m_work_guard_1.reset(); + m_handler(std::forward(args)...); + } + + Handler m_handler; + boost::asio::executor_work_guard m_work_guard_1; + }; + +template > +class AsyncReadOperation : public AsyncBase + { + public: + /** + * Construct and invoke an AsyncReadOperation. + * + * @param handler Handler function to be called upon completion. + * @param stream The stream from which the data will be read + * @param buffers The buffers into which the data will be read. + * @param ec Optional error code; used to report an error to the handler function. + */ + template + AsyncReadOperation(HandlerT&& handler, + Stream& stream, + const MutableBufferSequence& buffers, + const boost::system::error_code& ec = {}) + : AsyncBase( + std::forward(handler), + stream.get_executor()) + , m_stream(stream) + , m_buffers(buffers) + , m_decodedBytes(0) + { + this->operator()(ec, std::size_t(0), false); + } + + AsyncReadOperation(AsyncReadOperation&&) = default; + + void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true) + { + reenter(this) + { + if(bytes_transferred > 0 && !ec) + { + // We have received encrypted data from the network, now hand it to TLS::Channel for decryption. + boost::asio::const_buffer read_buffer{m_stream.input_buffer().data(), bytes_transferred}; + m_stream.process_encrypted_data(read_buffer, ec); + } + + if (m_stream.shutdown_received()) + { + // we just received a 'close_notify' from the peer and don't expect any more data + ec = boost::asio::error::eof; + } + else if (ec == boost::asio::error::eof) + { + // we did not expect this disconnection from the peer + ec = StreamError::StreamTruncated; + } + + if(!m_stream.has_received_data() && !ec && boost::asio::buffer_size(m_buffers) > 0) + { + // The channel did not decrypt a complete record yet, we need more data from the socket. + m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this)); + return; + } + + if(m_stream.has_received_data() && !ec) + { + // The channel has decrypted a TLS record, now copy it to the output buffers. + m_decodedBytes = m_stream.copy_received_data(m_buffers); + } + + if(!isContinuation) + { + // Make sure the handler is not called without an intermediate initiating function. + // "Reading" into a zero-byte buffer will complete immediately. + m_ec = ec; + yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this)); + ec = m_ec; + } + + this->complete_now(ec, m_decodedBytes); + } + } + + private: + Stream& m_stream; + MutableBufferSequence m_buffers; + std::size_t m_decodedBytes; + boost::system::error_code m_ec; + }; + +template > +class AsyncWriteOperation : public AsyncBase + { + public: + /** + * Construct and invoke an AsyncWriteOperation. + * + * @param handler Handler function to be called upon completion. + * @param stream The stream from which the data will be read + * @param plainBytesTransferred Number of bytes to be reported to the user-provided handler function as + * bytes_transferred. This needs to be provided since the amount of plaintext data + * consumed from the input buffer can differ from the amount of encrypted data written + * to the next layer. + * @param ec Optional error code; used to report an error to the handler function. + */ + template + AsyncWriteOperation(HandlerT&& handler, + Stream& stream, + std::size_t plainBytesTransferred, + const boost::system::error_code& ec = {}) + : AsyncBase( + std::forward(handler), + stream.get_executor()) + , m_stream(stream) + , m_plainBytesTransferred(plainBytesTransferred) + { + this->operator()(ec, std::size_t(0), false); + } + + AsyncWriteOperation(AsyncWriteOperation&&) = default; + + void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true) + { + reenter(this) + { + // mark the number of encrypted bytes sent to the network as "consumed" + // Note: bytes_transferred will be zero on first call + m_stream.consume_send_buffer(bytes_transferred); + + if(m_stream.has_data_to_send() && !ec) + { + m_stream.next_layer().async_write_some(m_stream.send_buffer(), std::move(*this)); + return; + } + + if (ec == boost::asio::error::eof && !m_stream.shutdown_received()) + { + // transport layer was closed by peer without receiving 'close_notify' + ec = StreamError::StreamTruncated; + } + + if(!isContinuation) + { + // Make sure the handler is not called without an intermediate initiating function. + // "Writing" to a zero-byte buffer will complete immediately. + m_ec = ec; + yield m_stream.next_layer().async_write_some(boost::asio::const_buffer(), std::move(*this)); + ec = m_ec; + } + + // The size of the sent TLS record can differ from the size of the payload due to TLS encryption. We need to + // tell the handler how many bytes of the original data we already processed. + this->complete_now(ec, m_plainBytesTransferred); + } + } + + private: + Stream& m_stream; + std::size_t m_plainBytesTransferred; + boost::system::error_code m_ec; + }; + +template > +class AsyncHandshakeOperation : public AsyncBase + { + public: + /** + * Construct and invoke an AsyncHandshakeOperation. + * + * @param handler Handler function to be called upon completion. + * @param stream The stream from which the data will be read + * @param ec Optional error code; used to report an error to the handler function. + */ + template + AsyncHandshakeOperation( + HandlerT&& handler, + Stream& stream, + const boost::system::error_code& ec = {}) + : AsyncBase( + std::forward(handler), + stream.get_executor()) + , m_stream(stream) + { + this->operator()(ec, std::size_t(0), false); + } + + AsyncHandshakeOperation(AsyncHandshakeOperation&&) = default; + + void operator()(boost::system::error_code ec, std::size_t bytesTransferred, bool isContinuation = true) + { + reenter(this) + { + if(ec == boost::asio::error::eof) + { + ec = StreamError::StreamTruncated; + } + + if(bytesTransferred > 0 && !ec) + { + // Provide encrypted TLS data received from the network to TLS::Channel for decryption + boost::asio::const_buffer read_buffer {m_stream.input_buffer().data(), bytesTransferred}; + m_stream.process_encrypted_data(read_buffer, ec); + } + + if(m_stream.has_data_to_send() && !ec) + { + // Write encrypted TLS data provided by the TLS::Channel on the wire + + // Note: we construct `AsyncWriteOperation` with 0 as its last parameter (`plainBytesTransferred`). This + // operation will eventually call `*this` as its own handler, passing the 0 back to this call operator. + // This is necessary because the check of `bytesTransferred > 0` assumes that `bytesTransferred` bytes + // were just read and are available in input_buffer for further processing. + AsyncWriteOperation::type, Stream, Allocator>, + Stream, + Allocator> + op{std::move(*this), m_stream, 0}; + return; + } + + if(!m_stream.native_handle()->is_active() && !ec) + { + // Read more encrypted TLS data from the network + m_stream.next_layer().async_read_some(m_stream.input_buffer(), std::move(*this)); + return; + } + + if(!isContinuation) + { + // Make sure the handler is not called without an intermediate initiating function. + // "Reading" into a zero-byte buffer will complete immediately. + m_ec = ec; + yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this)); + ec = m_ec; + } + + this->complete_now(ec); + } + } + + private: + Stream& m_stream; + boost::system::error_code m_ec; + }; + +} // namespace detail +} // namespace TLS +} // namespace Botan + +#include + +#endif // BOOST_VERSION +#endif // BOTAN_ASIO_ASYNC_OPS_H_ diff --git a/comm/third_party/botan/src/lib/tls/asio/asio_context.h b/comm/third_party/botan/src/lib/tls/asio/asio_context.h new file mode 100644 index 0000000000..e225fde6a2 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/asio/asio_context.h @@ -0,0 +1,120 @@ +/* + * TLS Context + * (C) 2018-2020 Jack Lloyd + * 2018-2020 Hannes Rantzsch, Tim Oesterreich, Rene Meusel + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_ASIO_TLS_CONTEXT_H_ +#define BOTAN_ASIO_TLS_CONTEXT_H_ + +#include + +#include +#if BOOST_VERSION >= 106600 + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { +namespace TLS { + +namespace detail { +template +struct fn_signature_helper : public std::false_type {}; + +template +struct fn_signature_helper + { + using type = std::function; + }; +} // namespace detail + +/** + * A helper class to initialize and configure Botan::TLS::Stream + */ +class Context + { + public: + // statically extract the function signature type from Callbacks::tls_verify_cert_chain + // and reuse it as an std::function<> for the verify callback signature + /** + * The signature of the callback function should correspond to the signature of + * Callbacks::tls_verify_cert_chain + */ + using Verify_Callback = + detail::fn_signature_helper::type; + + Context(Credentials_Manager& credentials_manager, + RandomNumberGenerator& rng, + Session_Manager& session_manager, + Policy& policy, + Server_Information server_info = Server_Information()) : + m_credentials_manager(credentials_manager), + m_rng(rng), + m_session_manager(session_manager), + m_policy(policy), + m_server_info(server_info) + {} + + virtual ~Context() = default; + + Context(Context&&) = default; + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + Context& operator=(Context&&) = delete; + + /** + * @brief Override the tls_verify_cert_chain callback + * + * This changes the verify_callback in the stream's TLS::Context, and hence the tls_verify_cert_chain callback + * used in the handshake. + * Using this function is equivalent to setting the callback via @see Botan::TLS::Stream::set_verify_callback + * + * @note This function should only be called before initiating the TLS handshake + */ + void set_verify_callback(Verify_Callback callback) + { + m_verify_callback = std::move(callback); + } + + bool has_verify_callback() const + { + return static_cast(m_verify_callback); + } + + const Verify_Callback& get_verify_callback() const + { + return m_verify_callback; + } + + void set_server_info(const Server_Information& server_info) + { + m_server_info = server_info; + } + + protected: + template friend class Stream; + + Credentials_Manager& m_credentials_manager; + RandomNumberGenerator& m_rng; + Session_Manager& m_session_manager; + Policy& m_policy; + + Server_Information m_server_info; + Verify_Callback m_verify_callback; + }; + +} // namespace TLS +} // namespace Botan + +#endif // BOOST_VERSION +#endif // BOTAN_ASIO_TLS_CONTEXT_H_ diff --git a/comm/third_party/botan/src/lib/tls/asio/asio_error.h b/comm/third_party/botan/src/lib/tls/asio/asio_error.h new file mode 100644 index 0000000000..bdaf8473f9 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/asio/asio_error.h @@ -0,0 +1,151 @@ +/* +* TLS Stream Errors +* (C) 2018-2020 Jack Lloyd +* 2018-2020 Hannes Rantzsch, Tim Oesterreich, Rene Meusel +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASIO_ERROR_H_ +#define BOTAN_ASIO_ERROR_H_ + +#include + +#include +#if BOOST_VERSION >= 106600 + +#include + +#include +#include +#include + +/* + * This file defines Botan-specific subclasses of boost::system::error_category. + * In addition to the class definition, each category class is accompanied by function `make_error_code` used to create + * a `boost::system::error_code` of the category from some other kind of error in Botan (for example, a TLS alert). + * Since error_category instances should be singletons, there's also a method to get/create the instance for each class. + */ + +namespace Botan { +namespace TLS { + +enum StreamError + { + StreamTruncated = 1 + }; + +//! @brief An error category for errors from the TLS::Stream +struct StreamCategory : public boost::system::error_category + { + public: + const char* name() const noexcept override + { + return "Botan TLS Stream"; + } + + std::string message(int value) const override + { + switch(value) + { + case StreamTruncated: + return "stream truncated"; + default: + return "generic error"; + } + } + }; + +inline const StreamCategory& botan_stream_category() + { + static StreamCategory category; + return category; + } + +inline boost::system::error_code make_error_code(Botan::TLS::StreamError e) + { + return boost::system::error_code(static_cast(e), Botan::TLS::botan_stream_category()); + } + +//! @brief An error category for TLS alerts +struct BotanAlertCategory : boost::system::error_category + { + const char* name() const noexcept override + { + return "Botan TLS Alert"; + } + + std::string message(int ev) const override + { + Botan::TLS::Alert alert(static_cast(ev)); + return alert.type_string(); + } + }; + +inline const BotanAlertCategory& botan_alert_category() noexcept + { + static BotanAlertCategory category; + return category; + } + +inline boost::system::error_code make_error_code(Botan::TLS::Alert::Type c) + { + return boost::system::error_code(static_cast(c), Botan::TLS::botan_alert_category()); + } + +} // namespace TLS + +//! @brief An error category for errors from Botan (other than TLS alerts) +struct BotanErrorCategory : boost::system::error_category + { + const char* name() const noexcept override + { + return "Botan"; + } + + std::string message(int ev) const override + { + return Botan::to_string(static_cast(ev)); + } + }; + +inline const BotanErrorCategory& botan_category() noexcept + { + static BotanErrorCategory category; + return category; + } + +inline boost::system::error_code make_error_code(Botan::ErrorType e) + { + return boost::system::error_code(static_cast(e), Botan::botan_category()); + } + +} // namespace Botan + + /* + * Add a template specialization of `is_error_code_enum` for each kind of error to allow automatic conversion to an + * error code. + */ +namespace boost { +namespace system { + +template<> struct is_error_code_enum + { + static const bool value = true; + }; + +template<> struct is_error_code_enum + { + static const bool value = true; + }; + +template<> struct is_error_code_enum + { + static const bool value = true; + }; + +} // namespace system +} // namespace boost + +#endif // BOOST_VERSION +#endif // BOTAN_ASIO_ERROR_H_ diff --git a/comm/third_party/botan/src/lib/tls/asio/asio_stream.h b/comm/third_party/botan/src/lib/tls/asio/asio_stream.h new file mode 100644 index 0000000000..bef95e44a0 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/asio/asio_stream.h @@ -0,0 +1,835 @@ +/* +* TLS ASIO Stream +* (C) 2018-2020 Jack Lloyd +* 2018-2020 Hannes Rantzsch, Tim Oesterreich, Rene Meusel +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASIO_STREAM_H_ +#define BOTAN_ASIO_STREAM_H_ + +#include + +// first version to be compatible with Networking TS (N4656) and boost::beast +#include +#if BOOST_VERSION >= 106600 + +#include +#include +#include + +#include +#include +#include +#include +#include + +// We need to define BOOST_ASIO_DISABLE_SERIAL_PORT before any asio imports. Otherwise asio will include , +// which interferes with Botan's amalgamation by defining macros like 'B0' and 'FF1'. +#define BOOST_ASIO_DISABLE_SERIAL_PORT +#include +#include + +#include +#include +#include + +namespace Botan { +namespace TLS { + +/** + * @brief boost::asio compatible SSL/TLS stream + * + * @tparam StreamLayer type of the next layer, usually a network socket + * @tparam ChannelT type of the native_handle, defaults to Botan::TLS::Channel, only needed for testing purposes + */ +template +class Stream + { + public: + //! \name construction + //! @{ + + /** + * @brief Construct a new Stream + * + * @param context The context parameter is used to set up the underlying native handle. Using code is + * responsible for lifetime management of the context and must ensure that it is available for the + * lifetime of the stream. + * @param args Arguments to be forwarded to the construction of the next layer. + */ + template + explicit Stream(Context& context, Args&& ... args) + : m_context(context) + , m_nextLayer(std::forward(args)...) + , m_core(*this) + , m_shutdown_received(false) + , m_input_buffer_space(MAX_CIPHERTEXT_SIZE, '\0') + , m_input_buffer(m_input_buffer_space.data(), m_input_buffer_space.size()) + {} + + /** + * @brief Construct a new Stream + * + * Convenience overload for boost::asio::ssl::stream compatibility. + * + * @param arg This argument is forwarded to the construction of the next layer. + * @param context The context parameter is used to set up the underlying native handle. Using code is + * responsible for lifetime management of the context and must ensure that is available for the + * lifetime of the stream. + */ + template + explicit Stream(Arg&& arg, Context& context) + : m_context(context) + , m_nextLayer(std::forward(arg)) + , m_core(*this) + , m_shutdown_received(false) + , m_input_buffer_space(MAX_CIPHERTEXT_SIZE, '\0') + , m_input_buffer(m_input_buffer_space.data(), m_input_buffer_space.size()) + {} + + virtual ~Stream() = default; + + Stream(Stream&& other) = default; + Stream& operator=(Stream&& other) = default; + + Stream(const Stream& other) = delete; + Stream& operator=(const Stream& other) = delete; + + //! @} + //! \name boost::asio accessor methods + //! @{ + + using next_layer_type = typename std::remove_reference::type; + + const next_layer_type& next_layer() const { return m_nextLayer; } + next_layer_type& next_layer() { return m_nextLayer; } + +#if BOOST_VERSION >= 107000 + /* + * From Boost 1.70 onwards Beast types no longer provide public access to the member function `lowest_layer()`. + * Instead, the new free-standing functions in Beast need to be used. + * See also: https://github.com/boostorg/beast/commit/6a658b5c3a36f8d58334f8b6582c01c3e87768ae + */ + using lowest_layer_type = typename boost::beast::lowest_layer_type; + + lowest_layer_type& lowest_layer() { return boost::beast::get_lowest_layer(m_nextLayer); } + const lowest_layer_type& lowest_layer() const { return boost::beast::get_lowest_layer(m_nextLayer); } +#else + using lowest_layer_type = typename next_layer_type::lowest_layer_type; + + lowest_layer_type& lowest_layer() { return m_nextLayer.lowest_layer(); } + const lowest_layer_type& lowest_layer() const { return m_nextLayer.lowest_layer(); } +#endif + + using executor_type = typename next_layer_type::executor_type; + executor_type get_executor() noexcept { return m_nextLayer.get_executor(); } + + using native_handle_type = typename std::add_pointer::type; + native_handle_type native_handle() + { + if(m_native_handle == nullptr) + { throw Invalid_State("Invalid handshake state"); } + return m_native_handle.get(); + } + + //! @} + //! \name configuration and callback setters + //! @{ + + /** + * @brief Override the tls_verify_cert_chain callback + * + * This changes the verify_callback in the stream's TLS::Context, and hence the tls_verify_cert_chain callback + * used in the handshake. + * Using this function is equivalent to setting the callback via @see Botan::TLS::Context::set_verify_callback + * + * @note This function should only be called before initiating the TLS handshake + */ + void set_verify_callback(Context::Verify_Callback callback) + { + m_context.set_verify_callback(std::move(callback)); + } + + /** + * @brief Compatibility overload of @ref set_verify_callback + * + * @param callback the callback implementation + * @param ec This parameter is unused. + */ + void set_verify_callback(Context::Verify_Callback callback, boost::system::error_code& ec) + { + BOTAN_UNUSED(ec); + m_context.set_verify_callback(std::move(callback)); + } + + //! @throws Not_Implemented + void set_verify_depth(int depth) + { + BOTAN_UNUSED(depth); + throw Not_Implemented("set_verify_depth is not implemented"); + } + + /** + * Not Implemented. + * @param depth the desired verification depth + * @param ec Will be set to `Botan::ErrorType::NotImplemented` + */ + void set_verify_depth(int depth, boost::system::error_code& ec) + { + BOTAN_UNUSED(depth); + ec = Botan::ErrorType::NotImplemented; + } + + //! @throws Not_Implemented + template + void set_verify_mode(verify_mode v) + { + BOTAN_UNUSED(v); + throw Not_Implemented("set_verify_mode is not implemented"); + } + + /** + * Not Implemented. + * @param v the desired verify mode + * @param ec Will be set to `Botan::ErrorType::NotImplemented` + */ + template + void set_verify_mode(verify_mode v, boost::system::error_code& ec) + { + BOTAN_UNUSED(v); + ec = Botan::ErrorType::NotImplemented; + } + + //! @} + //! \name handshake methods + //! @{ + + /** + * @brief Performs SSL handshaking. + * + * The function call will block until handshaking is complete or an error occurs. + * + * @param side The type of handshaking to be performed, i.e. as a client or as a server. + * @throws boost::system::system_error if error occured + */ + void handshake(Connection_Side side) + { + boost::system::error_code ec; + handshake(side, ec); + boost::asio::detail::throw_error(ec, "handshake"); + } + + /** + * @brief Performs SSL handshaking. + * + * The function call will block until handshaking is complete or an error occurs. + * + * @param side The type of handshaking to be performed, i.e. as a client or as a server. + * @param ec Set to indicate what error occurred, if any. + */ + void handshake(Connection_Side side, boost::system::error_code& ec) + { + setup_native_handle(side, ec); + + if(side == CLIENT) + { + // send client hello, which was written to the send buffer on client instantiation + send_pending_encrypted_data(ec); + } + + while(!native_handle()->is_active() && !ec) + { + boost::asio::const_buffer read_buffer{input_buffer().data(), m_nextLayer.read_some(input_buffer(), ec)}; + if(ec) + { return; } + + process_encrypted_data(read_buffer, ec); + + send_pending_encrypted_data(ec); + } + } + + /** + * @brief Starts an asynchronous SSL handshake. + * + * This function call always returns immediately. + * + * @param side The type of handshaking to be performed, i.e. as a client or as a server. + * @param handler The handler to be called when the handshake operation completes. + * The equivalent function signature of the handler must be: void(boost::system::error_code) + */ + template + auto async_handshake(Connection_Side side, HandshakeHandler&& handler) -> + BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void(boost::system::error_code)) + { + BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check; + + boost::system::error_code ec; + setup_native_handle(side, ec); + // If ec is set by setup_native_handle, the AsyncHandshakeOperation created below will do nothing but call the + // handler with the error_code set appropriately - no need to early return here. + + boost::asio::async_completion init(handler); + + detail::AsyncHandshakeOperation::type, Stream> + op{std::move(init.completion_handler), *this, ec}; + + return init.result.get(); + } + + //! @throws Not_Implemented + template + BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, + void(boost::system::error_code, std::size_t)) + async_handshake(Connection_Side side, const ConstBufferSequence& buffers, + BufferedHandshakeHandler&& handler) + { + BOTAN_UNUSED(side, buffers, handler); + BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(BufferedHandshakeHandler, handler) type_check; + throw Not_Implemented("buffered async handshake is not implemented"); + } + + //! @} + //! \name shutdown methods + //! @{ + + /** + * @brief Shut down SSL on the stream. + * + * This function is used to shut down SSL on the stream. The function call will block until SSL has been shut down + * or an error occurs. Note that this will not close the lowest layer. + * + * Note that this can be used in reaction of a received shutdown alert from the peer. + * + * @param ec Set to indicate what error occured, if any. + */ + void shutdown(boost::system::error_code& ec) + { + try_with_error_code([&] + { + native_handle()->close(); + }, ec); + + send_pending_encrypted_data(ec); + } + + /** + * @brief Shut down SSL on the stream. + * + * This function is used to shut down SSL on the stream. The function call will block until SSL has been shut down + * or an error occurs. Note that this will not close the lowest layer. + * + * Note that this can be used in reaction of a received shutdown alert from the peer. + * + * @throws boost::system::system_error if error occured + */ + void shutdown() + { + boost::system::error_code ec; + shutdown(ec); + boost::asio::detail::throw_error(ec, "shutdown"); + } + + private: + /** + * @brief Internal wrapper type to adapt the expected signature of `async_shutdown` to the completion handler + * signature of `AsyncWriteOperation`. + * + * This is boilerplate to ignore the `size_t` parameter that is passed to the completion handler of + * `AsyncWriteOperation`. Note that it needs to retain the wrapped handler's executor. + */ + template + struct Wrapper + { + void operator()(boost::system::error_code ec, std::size_t) + { + handler(ec); + } + + using executor_type = boost::asio::associated_executor_t; + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor(handler, io_executor); + } + + using allocator_type = boost::asio::associated_allocator_t; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator(handler); + } + + Handler handler; + Executor io_executor; + }; + + public: + /** + * @brief Asynchronously shut down SSL on the stream. + * + * This function call always returns immediately. + * + * Note that this can be used in reaction of a received shutdown alert from the peer. + * + * @param handler The handler to be called when the shutdown operation completes. + * The equivalent function signature of the handler must be: void(boost::system::error_code) + */ + template + void async_shutdown(ShutdownHandler&& handler) + { + boost::system::error_code ec; + try_with_error_code([&] + { + native_handle()->close(); + }, ec); + // If ec is set by native_handle->close(), the AsyncWriteOperation created below will do nothing but call the + // handler with the error_code set appropriately - no need to early return here. + + using ShutdownHandlerWrapper = Wrapper; + + ShutdownHandlerWrapper w{std::forward(handler), get_executor()}; + BOOST_ASIO_SHUTDOWN_HANDLER_CHECK(ShutdownHandler, w) type_check; + + boost::asio::async_completion + init(w); + + detail::AsyncWriteOperation::type, Stream> + op{std::move(init.completion_handler), *this, boost::asio::buffer_size(send_buffer())}; + + return init.result.get(); + } + + //! @} + //! \name I/O methods + //! @{ + + /** + * @brief Read some data from the stream. + * + * The function call will block until one or more bytes of data has been read successfully, or until an error + * occurs. + * + * @param buffers The buffers into which the data will be read. + * @param ec Set to indicate what error occurred, if any. Specifically, StreamTruncated will be set if the peer + * has closed the connection but did not properly shut down the SSL connection. + * @return The number of bytes read. Returns 0 if an error occurred. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + if(has_received_data()) + { return copy_received_data(buffers); } + + boost::asio::const_buffer read_buffer{input_buffer().data(), m_nextLayer.read_some(input_buffer(), ec)}; + if(ec) + { return 0; } + + process_encrypted_data(read_buffer, ec); + + if(ec) // something went wrong in process_encrypted_data() + { return 0; } + + if(shutdown_received()) + { + // we just received a 'close_notify' from the peer and don't expect any more data + ec = boost::asio::error::eof; + } + else if(ec == boost::asio::error::eof) + { + // we did not expect this disconnection from the peer + ec = StreamError::StreamTruncated; + } + + return !ec ? copy_received_data(buffers) : 0; + } + + /** + * @brief Read some data from the stream. + * + * The function call will block until one or more bytes of data has been read successfully, or until an error + * occurs. + * + * @param buffers The buffers into which the data will be read. + * @return The number of bytes read. Returns 0 if an error occurred. + * @throws boost::system::system_error if error occured + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + auto const n = read_some(buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return n; + } + + /** + * @brief Write some data to the stream. + * + * The function call will block until one or more bytes of data has been written successfully, or until an error + * occurs. + * + * @param buffers The data to be written. + * @param ec Set to indicate what error occurred, if any. + * @return The number of bytes processed from the input buffers. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + tls_encrypt(buffers, ec); + send_pending_encrypted_data(ec); + return !ec ? boost::asio::buffer_size(buffers) : 0; + } + + /** + * @brief Write some data to the stream. + * + * The function call will block until one or more bytes of data has been written successfully, or until an error + * occurs. + * + * @param buffers The data to be written. + * @return The number of bytes written. + * @throws boost::system::system_error if error occured + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + auto const n = write_some(buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return n; + } + + /** + * @brief Start an asynchronous write. The function call always returns immediately. + * + * @param buffers The data to be written. + * @param handler The handler to be called when the write operation completes. Copies will be made of the handler + * as required. The equivalent function signature of the handler must be: + * void(boost::system::error_code, std::size_t) + */ + template + auto async_write_some(const ConstBufferSequence& buffers, WriteHandler&& handler) -> + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void(boost::system::error_code, std::size_t)) + { + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + boost::asio::async_completion init(handler); + + boost::system::error_code ec; + tls_encrypt(buffers, ec); + if(ec) + { + // we cannot be sure how many bytes were committed here so clear the send_buffer and let the + // AsyncWriteOperation call the handler with the error_code set + consume_send_buffer(m_send_buffer.size()); + detail::AsyncWriteOperation::type, Stream> + op{std::move(init.completion_handler), *this, std::size_t(0), ec}; + return init.result.get(); + } + + detail::AsyncWriteOperation::type, Stream> + op{std::move(init.completion_handler), *this, boost::asio::buffer_size(buffers)}; + + return init.result.get(); + } + + /** + * @brief Start an asynchronous read. The function call always returns immediately. + * + * @param buffers The buffers into which the data will be read. Although the buffers object may be copied as + * necessary, ownership of the underlying buffers is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * @param handler The handler to be called when the read operation completes. The equivalent function signature of + * the handler must be: + * void(boost::system::error_code, std::size_t) + */ + template + auto async_read_some(const MutableBufferSequence& buffers, ReadHandler&& handler) -> + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void(boost::system::error_code, std::size_t)) + { + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + boost::asio::async_completion init(handler); + + detail::AsyncReadOperation::type, Stream, MutableBufferSequence> + op{std::move(init.completion_handler), *this, buffers}; + return init.result.get(); + } + + //! @} + + //! @brief Indicates whether a close_notify alert has been received from the peer. + bool shutdown_received() const + { + return m_shutdown_received; + } + + protected: + template friend class detail::AsyncReadOperation; + template friend class detail::AsyncWriteOperation; + template friend class detail::AsyncHandshakeOperation; + + /** + * @brief Helper class that implements Botan::TLS::Callbacks + * + * This class is provided to the stream's native_handle (Botan::TLS::Channel) and implements the callback + * functions triggered by the native_handle. + * + * @param receive_buffer reference to the buffer where decrypted data should be placed + * @param send_buffer reference to the buffer where encrypted data should be placed + */ + class StreamCore : public Botan::TLS::Callbacks + { + public: + StreamCore(Stream& stream) : m_stream(stream) {} + + virtual ~StreamCore() = default; + + void tls_emit_data(const uint8_t data[], std::size_t size) override + { + m_stream.m_send_buffer.commit( + boost::asio::buffer_copy(m_stream.m_send_buffer.prepare(size), boost::asio::buffer(data, size)) + ); + } + + void tls_record_received(uint64_t, const uint8_t data[], std::size_t size) override + { + m_stream.m_receive_buffer.commit( + boost::asio::buffer_copy(m_stream.m_receive_buffer.prepare(size), boost::asio::const_buffer(data, size)) + ); + } + + void tls_alert(Botan::TLS::Alert alert) override + { + if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY) + { + m_stream.set_shutdown_received(); + // Channel::process_alert will automatically write the corresponding close_notify response to the + // send_buffer and close the native_handle after this function returns. + } + } + + std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override + { + return std::chrono::milliseconds(1000); + } + + bool tls_session_established(const Botan::TLS::Session&) override + { + // TODO: it should be possible to configure this in the using application (via callback?) + return true; + } + + void tls_verify_cert_chain( + const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Usage_Type usage, + const std::string& hostname, + const TLS::Policy& policy) override + { + if(m_stream.m_context.has_verify_callback()) + { + m_stream.m_context.get_verify_callback()(cert_chain, ocsp_responses, trusted_roots, usage, hostname, policy); + } + else + { + Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, trusted_roots, usage, hostname, policy); + } + } + + private: + Stream& m_stream; + }; + + const boost::asio::mutable_buffer& input_buffer() { return m_input_buffer; } + boost::asio::const_buffer send_buffer() const { return m_send_buffer.data(); } + + //! @brief Check if decrypted data is available in the receive buffer + bool has_received_data() const { return m_receive_buffer.size() > 0; } + + //! @brief Copy decrypted data into the user-provided buffer + template + std::size_t copy_received_data(MutableBufferSequence buffers) + { + // Note: It would be nice to avoid this buffer copy. This could be achieved by equipping the StreamCore with + // the user's desired target buffer once a read is started, and reading directly into that buffer in tls_record + // received. However, we need to deal with the case that the receive buffer provided by the caller is smaller + // than the decrypted record, so this optimization might not be worth the additional complexity. + const auto copiedBytes = boost::asio::buffer_copy(buffers, m_receive_buffer.data()); + m_receive_buffer.consume(copiedBytes); + return copiedBytes; + } + + //! @brief Check if encrypted data is available in the send buffer + bool has_data_to_send() const { return m_send_buffer.size() > 0; } + + //! @brief Mark bytes in the send buffer as consumed, removing them from the buffer + void consume_send_buffer(std::size_t bytesConsumed) { m_send_buffer.consume(bytesConsumed); } + + // This is a helper construct to allow mocking the native_handle in test code. It is activated by explicitly + // specifying a (mocked) channel type template parameter when constructing the stream and does not attempt to + // instantiate the native_handle. + // Note: once we have C++17 we can achieve this much more elegantly using constexpr if. + template + typename std::enable_if::value>::type + setup_native_handle(Connection_Side, boost::system::error_code&) {} + + /** + * @brief Create the native handle. + * + * Depending on the desired connection side, this function will create a Botan::TLS::Client or a + * Botan::TLS::Server. + * + * @param side The desired connection side (client or server) + * @param ec Set to indicate what error occurred, if any. + */ + template + typename std::enable_if::value>::type + setup_native_handle(Connection_Side side, boost::system::error_code& ec) + { + try_with_error_code([&] + { + if(side == CLIENT) + { + m_native_handle = std::unique_ptr( + new Client(m_core, + m_context.m_session_manager, + m_context.m_credentials_manager, + m_context.m_policy, + m_context.m_rng, + m_context.m_server_info, + Protocol_Version::latest_tls_version())); + } + else + { + m_native_handle = std::unique_ptr( + new Server(m_core, + m_context.m_session_manager, + m_context.m_credentials_manager, + m_context.m_policy, + m_context.m_rng, + false /* no DTLS */)); + } + }, ec); + } + + /** @brief Synchronously write encrypted data from the send buffer to the next layer. + * + * If this function is called with an error code other than 'Success', it will do nothing and return 0. + * + * @param ec Set to indicate what error occurred, if any. Specifically, StreamTruncated will be set if the peer + * has closed the connection but did not properly shut down the SSL connection. + * @return The number of bytes written. + */ + size_t send_pending_encrypted_data(boost::system::error_code& ec) + { + if(ec) + { return 0; } + + auto writtenBytes = boost::asio::write(m_nextLayer, send_buffer(), ec); + consume_send_buffer(writtenBytes); + + if(ec == boost::asio::error::eof && !shutdown_received()) + { + // transport layer was closed by peer without receiving 'close_notify' + ec = StreamError::StreamTruncated; + } + + return writtenBytes; + } + + /** + * @brief Pass plaintext data to the native handle for processing. + * + * The native handle will then create TLS records and hand them back to the Stream via the tls_emit_data callback. + */ + template + void tls_encrypt(const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + // NOTE: This is not asynchronous: it encrypts the data synchronously. + // The data encrypted by native_handle()->send() is synchronously stored in the send_buffer of m_core, + // but is not actually written to the wire, yet. + for(auto it = boost::asio::buffer_sequence_begin(buffers); + !ec && it != boost::asio::buffer_sequence_end(buffers); + it++) + { + const boost::asio::const_buffer buffer = *it; + try_with_error_code([&] + { + native_handle()->send(static_cast(buffer.data()), buffer.size()); + }, ec); + } + } + + /** + * @brief Pass encrypted data to the native handle for processing. + * + * If an exception occurs while processing the data, an error code will be set. + * + * @param read_buffer Input buffer containing the encrypted data. + * @param ec Set to indicate what error occurred, if any. + */ + void process_encrypted_data(const boost::asio::const_buffer& read_buffer, boost::system::error_code& ec) + { + try_with_error_code([&] + { + native_handle()->received_data(static_cast(read_buffer.data()), read_buffer.size()); + }, ec); + } + + //! @brief Catch exceptions and set an error_code + template + void try_with_error_code(Fun f, boost::system::error_code& ec) + { + try + { + f(); + } + catch(const TLS_Exception& e) + { + ec = e.type(); + } + catch(const Botan::Exception& e) + { + ec = e.error_type(); + } + catch(const std::exception&) + { + ec = Botan::ErrorType::Unknown; + } + } + + void set_shutdown_received() + { + m_shutdown_received = true; + } + + Context& m_context; + StreamLayer m_nextLayer; + + boost::beast::flat_buffer m_receive_buffer; + boost::beast::flat_buffer m_send_buffer; + + StreamCore m_core; + std::unique_ptr m_native_handle; + + bool m_shutdown_received; + + // Buffer space used to read input intended for the core + std::vector m_input_buffer_space; + const boost::asio::mutable_buffer m_input_buffer; + }; + +} // namespace TLS +} // namespace Botan + +#endif // BOOST_VERSION +#endif // BOTAN_ASIO_STREAM_H_ diff --git a/comm/third_party/botan/src/lib/tls/asio/info.txt b/comm/third_party/botan/src/lib/tls/asio/info.txt new file mode 100644 index 0000000000..7862a1c284 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/asio/info.txt @@ -0,0 +1,15 @@ + +TLS_ASIO_STREAM -> 20181218 + + + +asio_context.h +asio_stream.h +asio_error.h +asio_async_ops.h + + + +boost +tls + diff --git a/comm/third_party/botan/src/lib/tls/credentials_manager.cpp b/comm/third_party/botan/src/lib/tls/credentials_manager.cpp new file mode 100644 index 0000000000..0c5ae9718f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/credentials_manager.cpp @@ -0,0 +1,105 @@ +/* +* Credentials Manager +* (C) 2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::string Credentials_Manager::psk_identity_hint(const std::string&, + const std::string&) + { + return ""; + } + +std::string Credentials_Manager::psk_identity(const std::string&, + const std::string&, + const std::string&) + { + return ""; + } + +SymmetricKey Credentials_Manager::psk(const std::string&, + const std::string&, + const std::string& identity) + { + throw Internal_Error("No PSK set for identity " + identity); + } + +bool Credentials_Manager::attempt_srp(const std::string&, + const std::string&) + { + return false; + } + +std::string Credentials_Manager::srp_identifier(const std::string&, + const std::string&) + { + return ""; + } + +std::string Credentials_Manager::srp_password(const std::string&, + const std::string&, + const std::string&) + { + return ""; + } + +bool Credentials_Manager::srp_verifier(const std::string&, + const std::string&, + const std::string&, + std::string&, + BigInt&, + std::vector&, + bool) + { + return false; + } + +std::vector Credentials_Manager::find_cert_chain( + const std::vector& key_types, + const std::vector&, + const std::string& type, + const std::string& context) + { + return cert_chain(key_types, type, context); + } + +std::vector Credentials_Manager::cert_chain( + const std::vector&, + const std::string&, + const std::string&) + { + return std::vector(); + } + +std::vector Credentials_Manager::cert_chain_single_type( + const std::string& cert_key_type, + const std::string& type, + const std::string& context) + { + std::vector cert_types; + cert_types.push_back(cert_key_type); + return find_cert_chain(cert_types, std::vector(), type, context); + } + +Private_Key* Credentials_Manager::private_key_for(const X509_Certificate&, + const std::string&, + const std::string&) + { + return nullptr; + } + +std::vector +Credentials_Manager::trusted_certificate_authorities( + const std::string&, + const std::string&) + { + return std::vector(); + } + +} diff --git a/comm/third_party/botan/src/lib/tls/credentials_manager.h b/comm/third_party/botan/src/lib/tls/credentials_manager.h new file mode 100644 index 0000000000..627894a87f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/credentials_manager.h @@ -0,0 +1,196 @@ +/* +* Credentials Manager +* (C) 2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CREDENTIALS_MANAGER_H_ +#define BOTAN_CREDENTIALS_MANAGER_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class X509_DN; +class BigInt; + +/** +* Interface for a credentials manager. +* +* A type is a fairly static value that represents the general nature +* of the transaction occurring. Currently used values are "tls-client" +* and "tls-server". Context represents a hostname, email address, +* username, or other identifier. +*/ +class BOTAN_PUBLIC_API(2,0) Credentials_Manager + { + public: + virtual ~Credentials_Manager() = default; + + /** + * Return a list of the certificates of CAs that we trust in this + * type/context. + * + * @param type specifies the type of operation occurring + * + * @param context specifies a context relative to type. For instance + * for type "tls-client", context specifies the servers name. + */ + virtual std::vector trusted_certificate_authorities( + const std::string& type, + const std::string& context); + + /** + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. + * + * It is assumed that the caller can get the private key of the + * leaf with private_key_for + * + * @param cert_key_types specifies the key types desired ("RSA", + * "DSA", "ECDSA", etc), or empty if there + * is no preference by the caller. + * + * @param acceptable_CAs the CAs the requestor will accept (possibly empty) + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + */ + virtual std::vector find_cert_chain( + const std::vector& cert_key_types, + const std::vector& acceptable_CAs, + const std::string& type, + const std::string& context); + + /** + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. + * + * This virtual function is deprecated, and will be removed in a + * future release. Use (and override) find_cert_chain instead. + * + * It is assumed that the caller can get the private key of the + * leaf with private_key_for + * + * @param cert_key_types specifies the key types desired ("RSA", + * "DSA", "ECDSA", etc), or empty if there + * is no preference by the caller. + * + * @param type specifies the type of operation occurring + * + * @param context specifies a context relative to type. + */ + virtual std::vector cert_chain( + const std::vector& cert_key_types, + const std::string& type, + const std::string& context); + + /** + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. + * + * It is assumed that the caller can get the private key of the + * leaf with private_key_for + * + * @param cert_key_type specifies the type of key requested + * ("RSA", "DSA", "ECDSA", etc) + * + * @param type specifies the type of operation occurring + * + * @param context specifies a context relative to type. + */ + std::vector cert_chain_single_type( + const std::string& cert_key_type, + const std::string& type, + const std::string& context); + + /** + * @return private key associated with this certificate if we should + * use it with this context. cert was returned by cert_chain + * @note this object should retain ownership of the returned key; + * it should not be deleted by the caller. + */ + virtual Private_Key* private_key_for(const X509_Certificate& cert, + const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + * @return true if we should attempt SRP authentication + */ + virtual bool attempt_srp(const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + * @return identifier for client-side SRP auth, if available + for this type/context. Should return empty string + if password auth not desired/available. + */ + virtual std::string srp_identifier(const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + * @param identifier specifies what identifier we want the + * password for. This will be a value previously returned + * by srp_identifier. + * @return password for client-side SRP auth, if available + for this identifier/type/context. + */ + virtual std::string srp_password(const std::string& type, + const std::string& context, + const std::string& identifier); + + /** + * Retrieve SRP verifier parameters + */ + virtual bool srp_verifier(const std::string& type, + const std::string& context, + const std::string& identifier, + std::string& group_name, + BigInt& verifier, + std::vector& salt, + bool generate_fake_on_unknown); + + /** + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + * @return the PSK identity hint for this type/context + */ + virtual std::string psk_identity_hint(const std::string& type, + const std::string& context); + + /** + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + * @param identity_hint was passed by the server (but may be empty) + * @return the PSK identity we want to use + */ + virtual std::string psk_identity(const std::string& type, + const std::string& context, + const std::string& identity_hint); + + /** + * @param type specifies the type of operation occurring + * @param context specifies a context relative to type. + * @param identity is a PSK identity previously returned by + psk_identity for the same type and context. + * @return the PSK used for identity, or throw an exception if no + * key exists + */ + virtual SymmetricKey psk(const std::string& type, + const std::string& context, + const std::string& identity); + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/info.txt b/comm/third_party/botan/src/lib/tls/info.txt new file mode 100644 index 0000000000..690bd41501 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/info.txt @@ -0,0 +1,54 @@ + +TLS -> 20191210 + + + +credentials_manager.h +tls_alert.h +tls_algos.h +tls_blocking.h +tls_callbacks.h +tls_channel.h +tls_ciphersuite.h +tls_client.h +tls_exceptn.h +tls_extensions.h +tls_handshake_msg.h +tls_magic.h +tls_messages.h +tls_server_info.h +tls_policy.h +tls_server.h +tls_session.h +tls_session_manager.h +tls_version.h + + + +tls_handshake_hash.h +tls_handshake_io.h +tls_handshake_state.h +tls_reader.h +tls_record.h +tls_seq_numbers.h +tls_session_key.h + + + +aead +aes +asn1 +dh +ecdh +ecdsa +eme_pkcs1 +emsa_pkcs1 +gcm +hmac +prf_tls +rng +rsa +sha2_32 +sha2_64 +x509 + diff --git a/comm/third_party/botan/src/lib/tls/msg_cert_req.cpp b/comm/third_party/botan/src/lib/tls/msg_cert_req.cpp new file mode 100644 index 0000000000..9e8a4d803c --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_cert_req.cpp @@ -0,0 +1,156 @@ +/* +* Certificate Request Message +* (C) 2004-2006,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +std::string cert_type_code_to_name(uint8_t code) + { + switch(code) + { + case 1: + return "RSA"; + case 2: + return "DSA"; + case 64: + return "ECDSA"; + default: + return ""; // DH or something else + } + } + +uint8_t cert_type_name_to_code(const std::string& name) + { + if(name == "RSA") + return 1; + if(name == "DSA") + return 2; + if(name == "ECDSA") + return 64; + + throw Invalid_Argument("Unknown cert type " + name); + } + +} + +/** +* Create a new Certificate Request message +*/ +Certificate_Req::Certificate_Req(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + const std::vector& ca_certs, + Protocol_Version version) : + m_names(ca_certs), + m_cert_key_types({ "RSA", "ECDSA", "DSA" }) + { + if(version.supports_negotiable_signature_algorithms()) + { + m_schemes = policy.allowed_signature_schemes(); + } + + hash.update(io.send(*this)); + } + +/** +* Deserialize a Certificate Request message +*/ +Certificate_Req::Certificate_Req(const std::vector& buf, + Protocol_Version version) + { + if(buf.size() < 4) + throw Decoding_Error("Certificate_Req: Bad certificate request"); + + TLS_Data_Reader reader("CertificateRequest", buf); + + std::vector cert_type_codes = reader.get_range_vector(1, 1, 255); + + for(size_t i = 0; i != cert_type_codes.size(); ++i) + { + const std::string cert_type_name = cert_type_code_to_name(cert_type_codes[i]); + + if(cert_type_name.empty()) // something we don't know + continue; + + m_cert_key_types.emplace_back(cert_type_name); + } + + if(version.supports_negotiable_signature_algorithms()) + { + const std::vector algs = reader.get_range_vector(2, 2, 65534); + + if(algs.size() % 2 != 0) + throw Decoding_Error("Bad length for signature IDs in certificate request"); + + for(size_t i = 0; i != algs.size(); i += 2) + { + m_schemes.push_back(static_cast(make_uint16(algs[i], algs[i+1]))); + } + } + + const uint16_t purported_size = reader.get_uint16_t(); + + if(reader.remaining_bytes() != purported_size) + throw Decoding_Error("Inconsistent length in certificate request"); + + while(reader.has_remaining()) + { + std::vector name_bits = reader.get_range_vector(2, 0, 65535); + + BER_Decoder decoder(name_bits.data(), name_bits.size()); + X509_DN name; + decoder.decode(name); + m_names.emplace_back(name); + } + } + +/** +* Serialize a Certificate Request message +*/ +std::vector Certificate_Req::serialize() const + { + std::vector buf; + + std::vector cert_types; + + for(size_t i = 0; i != m_cert_key_types.size(); ++i) + cert_types.push_back(cert_type_name_to_code(m_cert_key_types[i])); + + append_tls_length_value(buf, cert_types, 1); + + if(m_schemes.size() > 0) + buf += Signature_Algorithms(m_schemes).serialize(Connection_Side::SERVER); + + std::vector encoded_names; + + for(size_t i = 0; i != m_names.size(); ++i) + { + DER_Encoder encoder; + encoder.encode(m_names[i]); + + append_tls_length_value(encoded_names, encoder.get_contents(), 2); + } + + append_tls_length_value(buf, encoded_names, 2); + + return buf; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_cert_status.cpp b/comm/third_party/botan/src/lib/tls/msg_cert_status.cpp new file mode 100644 index 0000000000..ecc649a13c --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_cert_status.cpp @@ -0,0 +1,71 @@ +/* +* Certificate Status +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Certificate_Status::Certificate_Status(const std::vector& buf) + { + if(buf.size() < 5) + throw Decoding_Error("Invalid Certificate_Status message: too small"); + + if(buf[0] != 1) // not OCSP + throw Decoding_Error("Unexpected Certificate_Status message: unexpected response type"); + + size_t len = make_uint32(0, buf[1], buf[2], buf[3]); + + // Verify the redundant length field... + if(buf.size() != len + 4) + throw Decoding_Error("Invalid Certificate_Status: invalid length field"); + + m_response.assign(buf.begin() + 4, buf.end()); + } + +Certificate_Status::Certificate_Status(Handshake_IO& io, + Handshake_Hash& hash, + std::shared_ptr ocsp) : + m_response(ocsp->raw_bits()) + { + hash.update(io.send(*this)); + } + +Certificate_Status::Certificate_Status(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& raw_response_bytes) : + m_response(raw_response_bytes) + { + hash.update(io.send(*this)); + } + +std::vector Certificate_Status::serialize() const + { + if(m_response.size() > 0xFFFFFF) // unlikely + throw Encoding_Error("OCSP response too long to encode in TLS"); + + const uint32_t response_len = static_cast(m_response.size()); + + std::vector buf; + buf.push_back(1); // type OCSP + for(size_t i = 1; i < 4; ++i) + buf.push_back(get_byte(i, response_len)); + + buf += m_response; + return buf; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_cert_verify.cpp b/comm/third_party/botan/src/lib/tls/msg_cert_verify.cpp new file mode 100644 index 0000000000..711566bd08 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_cert_verify.cpp @@ -0,0 +1,110 @@ +/* +* Certificate Verify Message +* (C) 2004,2006,2011,2012 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/* +* Create a new Certificate Verify message +*/ +Certificate_Verify::Certificate_Verify(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + RandomNumberGenerator& rng, + const Private_Key* priv_key) + { + BOTAN_ASSERT_NONNULL(priv_key); + + std::pair format = + state.choose_sig_format(*priv_key, m_scheme, true, policy); + + m_signature = + state.callbacks().tls_sign_message(*priv_key, rng, format.first, format.second, + state.hash().get_contents()); + + state.hash().update(io.send(*this)); + } + +/* +* Deserialize a Certificate Verify message +*/ +Certificate_Verify::Certificate_Verify(const std::vector& buf, + Protocol_Version version) + { + TLS_Data_Reader reader("CertificateVerify", buf); + + if(version.supports_negotiable_signature_algorithms()) + { + m_scheme = static_cast(reader.get_uint16_t()); + } + + m_signature = reader.get_range(2, 0, 65535); + reader.assert_done(); + } + +/* +* Serialize a Certificate Verify message +*/ +std::vector Certificate_Verify::serialize() const + { + std::vector buf; + + if(m_scheme != Signature_Scheme::NONE) + { + const uint16_t scheme_code = static_cast(m_scheme); + buf.push_back(get_byte(0, scheme_code)); + buf.push_back(get_byte(1, scheme_code)); + } + + if(m_signature.size() > 0xFFFF) + throw Encoding_Error("Certificate_Verify signature too long to encode"); + + const uint16_t sig_len = static_cast(m_signature.size()); + buf.push_back(get_byte(0, sig_len)); + buf.push_back(get_byte(1, sig_len)); + buf += m_signature; + + return buf; + } + +/* +* Verify a Certificate Verify message +*/ +bool Certificate_Verify::verify(const X509_Certificate& cert, + const Handshake_State& state, + const Policy& policy) const + { + std::unique_ptr key(cert.subject_public_key()); + + policy.check_peer_key_acceptable(*key); + + std::pair format = + state.parse_sig_format(*key.get(), m_scheme, true, policy); + + const bool signature_valid = + state.callbacks().tls_verify_message(*key, format.first, format.second, + state.hash().get_contents(), m_signature); + +#if defined(BOTAN_UNSAFE_FUZZER_MODE) + BOTAN_UNUSED(signature_valid); + return true; +#else + return signature_valid; +#endif + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_certificate.cpp b/comm/third_party/botan/src/lib/tls/msg_certificate.cpp new file mode 100644 index 0000000000..25aeeefd27 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_certificate.cpp @@ -0,0 +1,109 @@ +/* +* Certificate Message +* (C) 2004-2006,2012,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Create a new Certificate message +*/ +Certificate::Certificate(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& cert_list) : + m_certs(cert_list) + { + hash.update(io.send(*this)); + } + +/** +* Deserialize a Certificate message +*/ +Certificate::Certificate(const std::vector& buf, const Policy& policy) + { + if(buf.size() < 3) + throw Decoding_Error("Certificate: Message malformed"); + + const size_t total_size = make_uint32(0, buf[0], buf[1], buf[2]); + + if(total_size != buf.size() - 3) + throw Decoding_Error("Certificate: Message malformed"); + + const size_t max_size = policy.maximum_certificate_chain_size(); + if(max_size > 0 && total_size > max_size) + throw Decoding_Error("Certificate chain exceeds policy specified maximum size"); + + const uint8_t* certs = buf.data() + 3; + + while(size_t remaining_bytes = buf.data() + buf.size() - certs) + { + if(remaining_bytes < 3) + throw Decoding_Error("Certificate: Message malformed"); + + const size_t cert_size = make_uint32(0, certs[0], certs[1], certs[2]); + + if(remaining_bytes < (3 + cert_size)) + throw Decoding_Error("Certificate: Message malformed"); + + DataSource_Memory cert_buf(&certs[3], cert_size); + m_certs.push_back(X509_Certificate(cert_buf)); + + certs += cert_size + 3; + } + + /* + * TLS 1.0 through 1.2 all seem to require that the certificate be + * precisely a v3 certificate. In fact the strict wording would seem + * to require that every certificate in the chain be v3. But often + * the intermediates are outside of the control of the server. + * But, require that the leaf certificate be v3 + */ + if(m_certs.size() > 0 && m_certs[0].x509_version() != 3) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, + "The leaf certificate must be v3"); + } + } + +/** +* Serialize a Certificate message +*/ +std::vector Certificate::serialize() const + { + std::vector buf(3); + + for(size_t i = 0; i != m_certs.size(); ++i) + { + std::vector raw_cert = m_certs[i].BER_encode(); + const size_t cert_size = raw_cert.size(); + for(size_t j = 0; j != 3; ++j) + { + buf.push_back(get_byte(j+1, static_cast(cert_size))); + } + buf += raw_cert; + } + + const size_t buf_size = buf.size() - 3; + for(size_t i = 0; i != 3; ++i) + buf[i] = get_byte(i+1, static_cast(buf_size)); + + return buf; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_client_hello.cpp b/comm/third_party/botan/src/lib/tls/msg_client_hello.cpp new file mode 100644 index 0000000000..149f3f0d4b --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_client_hello.cpp @@ -0,0 +1,465 @@ +/* +* TLS Hello Request and Client Hello Messages +* (C) 2004-2011,2015,2016 Jack Lloyd +* 2016 Matthias Gierlings +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +enum { + TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, + TLS_FALLBACK_SCSV = 0x5600 +}; + +std::vector make_hello_random(RandomNumberGenerator& rng, + const Policy& policy) + { + std::vector buf(32); + rng.randomize(buf.data(), buf.size()); + + std::unique_ptr sha256 = HashFunction::create_or_throw("SHA-256"); + sha256->update(buf); + sha256->final(buf); + + if(policy.include_time_in_hello_random()) + { + const uint32_t time32 = static_cast( + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); + + store_be(time32, buf.data()); + } + + return buf; + } + +/* +* Create a new Hello Request message +*/ +Hello_Request::Hello_Request(Handshake_IO& io) + { + io.send(*this); + } + +/* +* Deserialize a Hello Request message +*/ +Hello_Request::Hello_Request(const std::vector& buf) + { + if(buf.size()) + throw Decoding_Error("Bad Hello_Request, has non-zero size"); + } + +/* +* Serialize a Hello Request message +*/ +std::vector Hello_Request::serialize() const + { + return std::vector(); + } + +/* +* Create a new Client Hello message +*/ +Client_Hello::Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Client_Hello::Settings& client_settings, + const std::vector& next_protocols) : + m_version(client_settings.protocol_version()), + m_random(make_hello_random(rng, policy)), + m_suites(policy.ciphersuite_list(m_version, !client_settings.srp_identifier().empty())), + m_comp_methods(1) + { + if(!policy.acceptable_protocol_version(m_version)) + throw Internal_Error("Offering " + m_version.to_string() + + " but our own policy does not accept it"); + + /* + * Place all empty extensions in front to avoid a bug in some systems + * which reject hellos when the last extension in the list is empty. + */ + m_extensions.add(new Extended_Master_Secret); + m_extensions.add(new Session_Ticket()); + + if(policy.negotiate_encrypt_then_mac()) + m_extensions.add(new Encrypt_then_MAC); + + m_extensions.add(new Renegotiation_Extension(reneg_info)); + + m_extensions.add(new Supported_Versions(m_version, policy)); + + if(client_settings.hostname() != "") + m_extensions.add(new Server_Name_Indicator(client_settings.hostname())); + + if(policy.support_cert_status_message()) + m_extensions.add(new Certificate_Status_Request({}, {})); + + if(reneg_info.empty() && !next_protocols.empty()) + m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); + + if(m_version.supports_negotiable_signature_algorithms()) + m_extensions.add(new Signature_Algorithms(policy.allowed_signature_schemes())); + + if(m_version.is_datagram_protocol()) + m_extensions.add(new SRTP_Protection_Profiles(policy.srtp_profiles())); + +#if defined(BOTAN_HAS_SRP6) + m_extensions.add(new SRP_Identifier(client_settings.srp_identifier())); +#else + if(!client_settings.srp_identifier().empty()) + { + throw Invalid_State("Attempting to initiate SRP session but TLS-SRP support disabled"); + } +#endif + + std::unique_ptr supported_groups(new Supported_Groups(policy.key_exchange_groups())); + + if(supported_groups->ec_groups().size() > 0) + { + m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); + } + + m_extensions.add(supported_groups.release()); + + cb.tls_modify_extensions(m_extensions, CLIENT); + + if(policy.send_fallback_scsv(client_settings.protocol_version())) + m_suites.push_back(TLS_FALLBACK_SCSV); + + hash.update(io.send(*this)); + } + +/* +* Create a new Client Hello message (session resumption case) +*/ +Client_Hello::Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Session& session, + const std::vector& next_protocols) : + m_version(session.version()), + m_session_id(session.session_id()), + m_random(make_hello_random(rng, policy)), + m_suites(policy.ciphersuite_list(m_version, (session.srp_identifier() != ""))), + m_comp_methods(1) + { + if(!policy.acceptable_protocol_version(m_version)) + throw Internal_Error("Offering " + m_version.to_string() + + " but our own policy does not accept it"); + + if(!value_exists(m_suites, session.ciphersuite_code())) + m_suites.push_back(session.ciphersuite_code()); + + /* + We always add the EMS extension, even if not used in the original session. + If the server understands it and follows the RFC it should reject our resume + attempt and upgrade us to a new session with the EMS protection. + */ + m_extensions.add(new Extended_Master_Secret); + + m_extensions.add(new Renegotiation_Extension(reneg_info)); + m_extensions.add(new Server_Name_Indicator(session.server_info().hostname())); + m_extensions.add(new Session_Ticket(session.session_ticket())); + + if(policy.support_cert_status_message()) + m_extensions.add(new Certificate_Status_Request({}, {})); + + std::unique_ptr supported_groups(new Supported_Groups(policy.key_exchange_groups())); + + if(supported_groups->ec_groups().size() > 0) + { + m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); + } + + m_extensions.add(supported_groups.release()); + + if(session.supports_encrypt_then_mac()) + m_extensions.add(new Encrypt_then_MAC); + +#if defined(BOTAN_HAS_SRP6) + m_extensions.add(new SRP_Identifier(session.srp_identifier())); +#else + if(!session.srp_identifier().empty()) + { + throw Invalid_State("Attempting to resume SRP session but TLS-SRP support disabled"); + } +#endif + + if(m_version.supports_negotiable_signature_algorithms()) + m_extensions.add(new Signature_Algorithms(policy.allowed_signature_schemes())); + + if(reneg_info.empty() && !next_protocols.empty()) + m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); + + cb.tls_modify_extensions(m_extensions, CLIENT); + + hash.update(io.send(*this)); + } + +void Client_Hello::update_hello_cookie(const Hello_Verify_Request& hello_verify) + { + if(!m_version.is_datagram_protocol()) + throw Invalid_State("Cannot use hello cookie with stream protocol"); + + m_hello_cookie = hello_verify.cookie(); + } + +/* +* Serialize a Client Hello message +*/ +std::vector Client_Hello::serialize() const + { + std::vector buf; + + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; + + append_tls_length_value(buf, m_session_id, 1); + + if(m_version.is_datagram_protocol()) + append_tls_length_value(buf, m_hello_cookie, 1); + + append_tls_length_value(buf, m_suites, 2); + append_tls_length_value(buf, m_comp_methods, 1); + + /* + * May not want to send extensions at all in some cases. If so, + * should include SCSV value (if reneg info is empty, if not we are + * renegotiating with a modern server) + */ + + buf += m_extensions.serialize(Connection_Side::CLIENT); + + return buf; + } + +std::vector Client_Hello::cookie_input_data() const + { + std::vector buf; + + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; + + append_tls_length_value(buf, m_session_id, 1); + + append_tls_length_value(buf, m_suites, 2); + append_tls_length_value(buf, m_comp_methods, 1); + + // Here we don't serialize the extensions since the client extensions + // may contain values we don't know how to serialize back. + + return buf; + } + +/* +* Read a counterparty client hello +*/ +Client_Hello::Client_Hello(const std::vector& buf) + { + if(buf.size() < 41) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + TLS_Data_Reader reader("ClientHello", buf); + + const uint8_t major_version = reader.get_byte(); + const uint8_t minor_version = reader.get_byte(); + + m_version = Protocol_Version(major_version, minor_version); + + m_random = reader.get_fixed(32); + + m_session_id = reader.get_range(1, 0, 32); + + if(m_version.is_datagram_protocol()) + m_hello_cookie = reader.get_range(1, 0, 255); + + m_suites = reader.get_range_vector(2, 1, 32767); + + m_comp_methods = reader.get_range_vector(1, 1, 255); + + m_extensions.deserialize(reader, Connection_Side::CLIENT); + + if(offered_suite(static_cast(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) + { + if(Renegotiation_Extension* reneg = m_extensions.get()) + { + if(!reneg->renegotiation_info().empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client sent renegotiation SCSV and non-empty extension"); + } + else + { + // add fake extension + m_extensions.add(new Renegotiation_Extension()); + } + } + } + +bool Client_Hello::sent_fallback_scsv() const + { + return offered_suite(static_cast(TLS_FALLBACK_SCSV)); + } + +/* +* Check if we offered this ciphersuite +*/ +bool Client_Hello::offered_suite(uint16_t ciphersuite) const + { + for(size_t i = 0; i != m_suites.size(); ++i) + if(m_suites[i] == ciphersuite) + return true; + return false; + } + +std::vector Client_Hello::signature_schemes() const + { + std::vector schemes; + + if(Signature_Algorithms* sigs = m_extensions.get()) + { + schemes = sigs->supported_schemes(); + } + + return schemes; + } + +std::vector Client_Hello::supported_ecc_curves() const + { + if(Supported_Groups* groups = m_extensions.get()) + return groups->ec_groups(); + return std::vector(); + } + +std::vector Client_Hello::supported_dh_groups() const + { + if(Supported_Groups* groups = m_extensions.get()) + return groups->dh_groups(); + return std::vector(); + } + +bool Client_Hello::prefers_compressed_ec_points() const + { + if(Supported_Point_Formats* ecc_formats = m_extensions.get()) + { + return ecc_formats->prefers_compressed(); + } + return false; + } + +std::string Client_Hello::sni_hostname() const + { + if(Server_Name_Indicator* sni = m_extensions.get()) + return sni->host_name(); + return ""; + } + +#if defined(BOTAN_HAS_SRP6) +std::string Client_Hello::srp_identifier() const + { + if(SRP_Identifier* srp = m_extensions.get()) + return srp->identifier(); + return ""; + } +#endif + +bool Client_Hello::secure_renegotiation() const + { + return m_extensions.has(); + } + +std::vector Client_Hello::renegotiation_info() const + { + if(Renegotiation_Extension* reneg = m_extensions.get()) + return reneg->renegotiation_info(); + return std::vector(); + } + +std::vector Client_Hello::supported_versions() const + { + if(Supported_Versions* versions = m_extensions.get()) + return versions->versions(); + return {}; + } + +bool Client_Hello::supports_session_ticket() const + { + return m_extensions.has(); + } + +std::vector Client_Hello::session_ticket() const + { + if(Session_Ticket* ticket = m_extensions.get()) + return ticket->contents(); + return std::vector(); + } + +bool Client_Hello::supports_alpn() const + { + return m_extensions.has(); + } + +bool Client_Hello::supports_extended_master_secret() const + { + return m_extensions.has(); + } + +bool Client_Hello::supports_cert_status_message() const + { + return m_extensions.has(); + } + +bool Client_Hello::supports_encrypt_then_mac() const + { + return m_extensions.has(); + } + +bool Client_Hello::sent_signature_algorithms() const + { + return m_extensions.has(); + } + +std::vector Client_Hello::next_protocols() const + { + if(auto alpn = m_extensions.get()) + return alpn->protocols(); + return std::vector(); + } + +std::vector Client_Hello::srtp_profiles() const + { + if(SRTP_Protection_Profiles* srtp = m_extensions.get()) + return srtp->profiles(); + return std::vector(); + } + + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_client_kex.cpp b/comm/third_party/botan/src/lib/tls/msg_client_kex.cpp new file mode 100644 index 0000000000..39266962b5 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_client_kex.cpp @@ -0,0 +1,404 @@ +/* +* Client Key Exchange Message +* (C) 2004-2010,2016 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BOTAN_HAS_CECPQ1) + #include +#endif + +#if defined(BOTAN_HAS_SRP6) + #include +#endif + +namespace Botan { + +namespace TLS { + +/* +* Create a new Client Key Exchange message +*/ +Client_Key_Exchange::Client_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + const Public_Key* server_public_key, + const std::string& hostname, + RandomNumberGenerator& rng) + { + const Kex_Algo kex_algo = state.ciphersuite().kex_method(); + + if(kex_algo == Kex_Algo::PSK) + { + std::string identity_hint = ""; + + if(state.server_kex()) + { + TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); + identity_hint = reader.get_string(2, 0, 65535); + } + + const std::string psk_identity = + creds.psk_identity("tls-client", hostname, identity_hint); + + append_tls_length_value(m_key_material, psk_identity, 2); + + SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity); + + std::vector zeros(psk.length()); + + append_tls_length_value(m_pre_master, zeros, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + else if(state.server_kex()) + { + TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params()); + + SymmetricKey psk; + + if(kex_algo == Kex_Algo::DHE_PSK || + kex_algo == Kex_Algo::ECDHE_PSK) + { + std::string identity_hint = reader.get_string(2, 0, 65535); + + const std::string psk_identity = + creds.psk_identity("tls-client", hostname, identity_hint); + + append_tls_length_value(m_key_material, psk_identity, 2); + + psk = creds.psk("tls-client", hostname, psk_identity); + } + + if(kex_algo == Kex_Algo::DH || + kex_algo == Kex_Algo::DHE_PSK) + { + const std::vector modulus = reader.get_range(2, 1, 65535); + const std::vector generator = reader.get_range(2, 1, 65535); + const std::vector peer_public_value = reader.get_range(2, 1, 65535); + + if(reader.remaining_bytes()) + throw Decoding_Error("Bad params size for DH key exchange"); + + const std::pair, std::vector> dh_result = + state.callbacks().tls_dh_agree(modulus, generator, peer_public_value, policy, rng); + + if(kex_algo == Kex_Algo::DH) + m_pre_master = dh_result.first; + else + { + append_tls_length_value(m_pre_master, dh_result.first, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + + append_tls_length_value(m_key_material, dh_result.second, 2); + } + else if(kex_algo == Kex_Algo::ECDH || + kex_algo == Kex_Algo::ECDHE_PSK) + { + const uint8_t curve_type = reader.get_byte(); + if(curve_type != 3) + throw Decoding_Error("Server sent non-named ECC curve"); + + const Group_Params curve_id = static_cast(reader.get_uint16_t()); + const std::vector peer_public_value = reader.get_range(1, 1, 255); + + if(policy.choose_key_exchange_group({curve_id}) != curve_id) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent ECC curve prohibited by policy"); + } + + const std::string curve_name = state.callbacks().tls_decode_group_param(curve_id); + + if(curve_name == "") + throw Decoding_Error("Server sent unknown named curve " + + std::to_string(static_cast(curve_id))); + + const std::pair, std::vector> ecdh_result = + state.callbacks().tls_ecdh_agree(curve_name, peer_public_value, policy, rng, + state.server_hello()->prefers_compressed_ec_points()); + + if(kex_algo == Kex_Algo::ECDH) + { + m_pre_master = ecdh_result.first; + } + else + { + append_tls_length_value(m_pre_master, ecdh_result.first, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + + append_tls_length_value(m_key_material, ecdh_result.second, 1); + } +#if defined(BOTAN_HAS_SRP6) + else if(kex_algo == Kex_Algo::SRP_SHA) + { + const BigInt N = BigInt::decode(reader.get_range(2, 1, 65535)); + const BigInt g = BigInt::decode(reader.get_range(2, 1, 65535)); + std::vector salt = reader.get_range(1, 1, 255); + const BigInt B = BigInt::decode(reader.get_range(2, 1, 65535)); + + const std::string srp_group = srp6_group_identifier(N, g); + + const std::string srp_identifier = + creds.srp_identifier("tls-client", hostname); + + const std::string srp_password = + creds.srp_password("tls-client", hostname, srp_identifier); + + std::pair srp_vals = + srp6_client_agree(srp_identifier, + srp_password, + srp_group, + "SHA-1", + salt, + B, + rng); + + append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2); + m_pre_master = srp_vals.second.bits_of(); + } +#endif + +#if defined(BOTAN_HAS_CECPQ1) + else if(kex_algo == Kex_Algo::CECPQ1) + { + const std::vector cecpq1_offer = reader.get_range(2, 1, 65535); + + if(cecpq1_offer.size() != CECPQ1_OFFER_BYTES) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid CECPQ1 key size"); + + std::vector newhope_accept(CECPQ1_ACCEPT_BYTES); + secure_vector shared_secret(CECPQ1_SHARED_KEY_BYTES); + CECPQ1_accept(shared_secret.data(), newhope_accept.data(), cecpq1_offer.data(), rng); + append_tls_length_value(m_key_material, newhope_accept, 2); + m_pre_master = shared_secret; + } +#endif + else + { + throw Internal_Error("Client_Key_Exchange: Unknown key exchange method was negotiated"); + } + + reader.assert_done(); + } + else + { + // No server key exchange msg better mean RSA kex + RSA key in cert + + if(kex_algo != Kex_Algo::STATIC_RSA) + throw Unexpected_Message("No server kex message, but negotiated a key exchange that required it"); + + if(!server_public_key) + throw Internal_Error("No server public key for RSA exchange"); + + if(auto rsa_pub = dynamic_cast(server_public_key)) + { + const Protocol_Version offered_version = state.client_hello()->version(); + + rng.random_vec(m_pre_master, 48); + m_pre_master[0] = offered_version.major_version(); + m_pre_master[1] = offered_version.minor_version(); + + PK_Encryptor_EME encryptor(*rsa_pub, rng, "PKCS1v15"); + + const std::vector encrypted_key = encryptor.encrypt(m_pre_master, rng); + + append_tls_length_value(m_key_material, encrypted_key, 2); + } + else + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Expected a RSA key in server cert but got " + + server_public_key->algo_name()); + } + + state.hash().update(io.send(*this)); + } + +/* +* Read a Client Key Exchange message +*/ +Client_Key_Exchange::Client_Key_Exchange(const std::vector& contents, + const Handshake_State& state, + const Private_Key* server_rsa_kex_key, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng) + { + const Kex_Algo kex_algo = state.ciphersuite().kex_method(); + + if(kex_algo == Kex_Algo::STATIC_RSA) + { + BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(), + "RSA key exchange negotiated so server sent a certificate"); + + if(!server_rsa_kex_key) + throw Internal_Error("Expected RSA kex but no server kex key set"); + + if(!dynamic_cast(server_rsa_kex_key)) + throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name()); + + TLS_Data_Reader reader("ClientKeyExchange", contents); + const std::vector encrypted_pre_master = reader.get_range(2, 0, 65535); + reader.assert_done(); + + PK_Decryptor_EME decryptor(*server_rsa_kex_key, rng, "PKCS1v15"); + + const uint8_t client_major = state.client_hello()->version().major_version(); + const uint8_t client_minor = state.client_hello()->version().minor_version(); + + /* + * PK_Decryptor::decrypt_or_random will return a random value if + * either the length does not match the expected value or if the + * version number embedded in the PMS does not match the one sent + * in the client hello. + */ + const size_t expected_plaintext_size = 48; + const size_t expected_content_size = 2; + const uint8_t expected_content_bytes[expected_content_size] = { client_major, client_minor }; + const uint8_t expected_content_pos[expected_content_size] = { 0, 1 }; + + m_pre_master = + decryptor.decrypt_or_random(encrypted_pre_master.data(), + encrypted_pre_master.size(), + expected_plaintext_size, + rng, + expected_content_bytes, + expected_content_pos, + expected_content_size); + } + else + { + TLS_Data_Reader reader("ClientKeyExchange", contents); + + SymmetricKey psk; + + if(key_exchange_is_psk(kex_algo)) + { + const std::string psk_identity = reader.get_string(2, 0, 65535); + + psk = creds.psk("tls-server", + state.client_hello()->sni_hostname(), + psk_identity); + + if(psk.length() == 0) + { + if(policy.hide_unknown_users()) + psk = SymmetricKey(rng, 16); + else + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "No PSK for identifier " + psk_identity); + } + } + + if(kex_algo == Kex_Algo::PSK) + { + std::vector zeros(psk.length()); + append_tls_length_value(m_pre_master, zeros, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } +#if defined(BOTAN_HAS_SRP6) + else if(kex_algo == Kex_Algo::SRP_SHA) + { + SRP6_Server_Session& srp = state.server_kex()->server_srp_params(); + + m_pre_master = srp.step2(BigInt::decode(reader.get_range(2, 0, 65535))).bits_of(); + } +#endif +#if defined(BOTAN_HAS_CECPQ1) + else if(kex_algo == Kex_Algo::CECPQ1) + { + const CECPQ1_key& cecpq1_offer = state.server_kex()->cecpq1_key(); + + const std::vector cecpq1_accept = reader.get_range(2, 0, 65535); + if(cecpq1_accept.size() != CECPQ1_ACCEPT_BYTES) + throw Decoding_Error("Invalid size for CECPQ1 accept message"); + + m_pre_master.resize(CECPQ1_SHARED_KEY_BYTES); + CECPQ1_finish(m_pre_master.data(), cecpq1_offer, cecpq1_accept.data()); + } +#endif + else if(kex_algo == Kex_Algo::DH || + kex_algo == Kex_Algo::DHE_PSK || + kex_algo == Kex_Algo::ECDH || + kex_algo == Kex_Algo::ECDHE_PSK) + { + const Private_Key& private_key = state.server_kex()->server_kex_key(); + + const PK_Key_Agreement_Key* ka_key = + dynamic_cast(&private_key); + + if(!ka_key) + throw Internal_Error("Expected key agreement key type but got " + + private_key.algo_name()); + + std::vector client_pubkey; + + if(ka_key->algo_name() == "DH") + { + client_pubkey = reader.get_range(2, 0, 65535); + } + else + { + client_pubkey = reader.get_range(1, 1, 255); + } + + try + { + PK_Key_Agreement ka(*ka_key, rng, "Raw"); + + secure_vector shared_secret = ka.derive_key(0, client_pubkey).bits_of(); + + if(ka_key->algo_name() == "DH") + shared_secret = CT::strip_leading_zeros(shared_secret); + + if(kex_algo == Kex_Algo::DHE_PSK || + kex_algo == Kex_Algo::ECDHE_PSK) + { + append_tls_length_value(m_pre_master, shared_secret, 2); + append_tls_length_value(m_pre_master, psk.bits_of(), 2); + } + else + m_pre_master = shared_secret; + } + catch(Invalid_Argument& e) + { + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, e.what()); + } + catch(std::exception&) + { + /* + * Something failed in the DH/ECDH computation. To avoid possible + * attacks which are based on triggering and detecting some edge + * failure condition, randomize the pre-master output and carry on, + * allowing the protocol to fail later in the finished checks. + */ + rng.random_vec(m_pre_master, ka_key->public_value().size()); + } + + reader.assert_done(); + } + else + throw Internal_Error("Client_Key_Exchange: Unknown key exchange negotiated"); + } + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_finished.cpp b/comm/third_party/botan/src/lib/tls/msg_finished.cpp new file mode 100644 index 0000000000..47c875a518 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_finished.cpp @@ -0,0 +1,91 @@ +/* +* Finished Message +* (C) 2004-2006,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +/* +* Compute the verify_data +*/ +std::vector finished_compute_verify(const Handshake_State& state, + Connection_Side side) + { + const uint8_t TLS_CLIENT_LABEL[] = { + 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64 }; + + const uint8_t TLS_SERVER_LABEL[] = { + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64 }; + + std::unique_ptr prf(state.protocol_specific_prf()); + + std::vector input; + std::vector label; + if(side == CLIENT) + label += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL)); + else + label += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL)); + + input += state.hash().final(state.version(), state.ciphersuite().prf_algo()); + + return unlock(prf->derive_key(12, state.session_keys().master_secret(), input, label)); + } + +} + +/* +* Create a new Finished message +*/ +Finished::Finished(Handshake_IO& io, + Handshake_State& state, + Connection_Side side) : m_verification_data(finished_compute_verify( state, side )) + { + state.hash().update(io.send(*this)); + } + +/* +* Serialize a Finished message +*/ +std::vector Finished::serialize() const + { + return m_verification_data; + } + +/* +* Deserialize a Finished message +*/ +Finished::Finished(const std::vector& buf) : m_verification_data(buf) + {} + +/* +* Verify a Finished message +*/ +bool Finished::verify(const Handshake_State& state, + Connection_Side side) const + { + std::vector computed_verify = finished_compute_verify(state, side); + +#if defined(BOTAN_UNSAFE_FUZZER_MODE) + return true; +#else + return (m_verification_data.size() == computed_verify.size()) && + constant_time_compare(m_verification_data.data(), computed_verify.data(), computed_verify.size()); +#endif + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_hello_verify.cpp b/comm/third_party/botan/src/lib/tls/msg_hello_verify.cpp new file mode 100644 index 0000000000..bc93af9d62 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_hello_verify.cpp @@ -0,0 +1,69 @@ +/* +* DTLS Hello Verify Request +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +Hello_Verify_Request::Hello_Verify_Request(const std::vector& buf) + { + if(buf.size() < 3) + throw Decoding_Error("Hello verify request too small"); + + Protocol_Version version(buf[0], buf[1]); + + if(version != Protocol_Version::DTLS_V10 && + version != Protocol_Version::DTLS_V12) + { + throw Decoding_Error("Unknown version from server in hello verify request"); + } + + if(static_cast(buf[2]) + 3 != buf.size()) + throw Decoding_Error("Bad length in hello verify request"); + + m_cookie.assign(buf.begin() + 3, buf.end()); + } + +Hello_Verify_Request::Hello_Verify_Request(const std::vector& client_hello_bits, + const std::string& client_identity, + const SymmetricKey& secret_key) + { + std::unique_ptr hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + hmac->set_key(secret_key); + + hmac->update_be(static_cast(client_hello_bits.size())); + hmac->update(client_hello_bits); + hmac->update_be(static_cast(client_identity.size())); + hmac->update(client_identity); + + m_cookie.resize(hmac->output_length()); + hmac->final(m_cookie.data()); + } + +std::vector Hello_Verify_Request::serialize() const + { + /* DTLS 1.2 server implementations SHOULD use DTLS version 1.0 + regardless of the version of TLS that is expected to be + negotiated (RFC 6347, section 4.2.1) + */ + + Protocol_Version format_version(Protocol_Version::DTLS_V10); + + std::vector bits; + bits.push_back(format_version.major_version()); + bits.push_back(format_version.minor_version()); + bits.push_back(static_cast(m_cookie.size())); + bits += m_cookie; + return bits; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_server_hello.cpp b/comm/third_party/botan/src/lib/tls/msg_server_hello.cpp new file mode 100644 index 0000000000..651fd14f89 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_server_hello.cpp @@ -0,0 +1,251 @@ +/* +* TLS Server Hello and Server Hello Done +* (C) 2004-2011,2015,2016,2019 Jack Lloyd +* 2016 Matthias Gierlings +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +const uint64_t DOWNGRADE_TLS11 = 0x444F574E47524400; +//const uint64_t DOWNGRADE_TLS12 = 0x444F574E47524401; + +std::vector +make_server_hello_random(RandomNumberGenerator& rng, + Protocol_Version offered_version, + const Policy& policy) + { + auto random = make_hello_random(rng, policy); + + if((offered_version == Protocol_Version::TLS_V10 || + offered_version == Protocol_Version::TLS_V11) && + policy.allow_tls12()) + { + store_be(DOWNGRADE_TLS11, &random[24]); + } + + if(offered_version == Protocol_Version::DTLS_V10 && policy.allow_dtls12()) + { + store_be(DOWNGRADE_TLS11, &random[24]); + } + + return random; + } + +} + +// New session case +Server_Hello::Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Client_Hello& client_hello, + const Server_Hello::Settings& server_settings, + const std::string next_protocol) : + m_version(server_settings.protocol_version()), + m_session_id(server_settings.session_id()), + m_random(make_server_hello_random(rng, m_version, policy)), + m_ciphersuite(server_settings.ciphersuite()), + m_comp_method(0) + { + if(client_hello.supports_extended_master_secret()) + m_extensions.add(new Extended_Master_Secret); + + // Sending the extension back does not commit us to sending a stapled response + if(client_hello.supports_cert_status_message() && policy.support_cert_status_message()) + m_extensions.add(new Certificate_Status_Request); + + Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); + + if(c.cbc_ciphersuite() && client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) + { + m_extensions.add(new Encrypt_then_MAC); + } + + if(c.ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) + { + m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); + } + + if(client_hello.secure_renegotiation()) + m_extensions.add(new Renegotiation_Extension(reneg_info)); + + if(client_hello.supports_session_ticket() && server_settings.offer_session_ticket()) + m_extensions.add(new Session_Ticket()); + + if(!next_protocol.empty() && client_hello.supports_alpn()) + m_extensions.add(new Application_Layer_Protocol_Notification(next_protocol)); + + if(m_version.is_datagram_protocol()) + { + const std::vector server_srtp = policy.srtp_profiles(); + const std::vector client_srtp = client_hello.srtp_profiles(); + + if(!server_srtp.empty() && !client_srtp.empty()) + { + uint16_t shared = 0; + // always using server preferences for now + for(auto s_srtp : server_srtp) + for(auto c_srtp : client_srtp) + { + if(shared == 0 && s_srtp == c_srtp) + shared = s_srtp; + } + + if(shared) + m_extensions.add(new SRTP_Protection_Profiles(shared)); + } + } + + cb.tls_modify_extensions(m_extensions, SERVER); + + hash.update(io.send(*this)); + } + +// Resuming +Server_Hello::Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Client_Hello& client_hello, + Session& resumed_session, + bool offer_session_ticket, + const std::string& next_protocol) : + m_version(resumed_session.version()), + m_session_id(client_hello.session_id()), + m_random(make_hello_random(rng, policy)), + m_ciphersuite(resumed_session.ciphersuite_code()), + m_comp_method(0) + { + if(client_hello.supports_extended_master_secret()) + m_extensions.add(new Extended_Master_Secret); + + if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) + { + Ciphersuite c = resumed_session.ciphersuite(); + if(c.cbc_ciphersuite()) + m_extensions.add(new Encrypt_then_MAC); + } + + if(resumed_session.ciphersuite().ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) + { + m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); + } + + if(client_hello.secure_renegotiation()) + m_extensions.add(new Renegotiation_Extension(reneg_info)); + + if(client_hello.supports_session_ticket() && offer_session_ticket) + m_extensions.add(new Session_Ticket()); + + if(!next_protocol.empty() && client_hello.supports_alpn()) + m_extensions.add(new Application_Layer_Protocol_Notification(next_protocol)); + + cb.tls_modify_extensions(m_extensions, SERVER); + + hash.update(io.send(*this)); + } + +/* +* Deserialize a Server Hello message +*/ +Server_Hello::Server_Hello(const std::vector& buf) + { + if(buf.size() < 38) + throw Decoding_Error("Server_Hello: Packet corrupted"); + + TLS_Data_Reader reader("ServerHello", buf); + + const uint8_t major_version = reader.get_byte(); + const uint8_t minor_version = reader.get_byte(); + + m_version = Protocol_Version(major_version, minor_version); + + m_random = reader.get_fixed(32); + + m_session_id = reader.get_range(1, 0, 32); + + m_ciphersuite = reader.get_uint16_t(); + + m_comp_method = reader.get_byte(); + + m_extensions.deserialize(reader, Connection_Side::SERVER); + } + +/* +* Serialize a Server Hello message +*/ +std::vector Server_Hello::serialize() const + { + std::vector buf; + + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; + + append_tls_length_value(buf, m_session_id, 1); + + buf.push_back(get_byte(0, m_ciphersuite)); + buf.push_back(get_byte(1, m_ciphersuite)); + + buf.push_back(m_comp_method); + + buf += m_extensions.serialize(Connection_Side::SERVER); + + return buf; + } + +bool Server_Hello::random_signals_downgrade() const + { + const uint64_t last8 = load_be(m_random.data(), 3); + return (last8 == DOWNGRADE_TLS11); + } + +/* +* Create a new Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(Handshake_IO& io, + Handshake_Hash& hash) + { + hash.update(io.send(*this)); + } + +/* +* Deserialize a Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(const std::vector& buf) + { + if(buf.size()) + throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); + } + +/* +* Serialize a Server Hello Done message +*/ +std::vector Server_Hello_Done::serialize() const + { + return std::vector(); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_server_kex.cpp b/comm/third_party/botan/src/lib/tls/msg_server_kex.cpp new file mode 100644 index 0000000000..797907ed82 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_server_kex.cpp @@ -0,0 +1,334 @@ +/* +* Server Key Exchange Message +* (C) 2004-2010,2012,2015,2016 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(BOTAN_HAS_CURVE_25519) + #include +#endif + +#if defined(BOTAN_HAS_CECPQ1) + #include +#endif + +#if defined(BOTAN_HAS_SRP6) + #include +#endif + +namespace Botan { + +namespace TLS { + +/** +* Create a new Server Key Exchange message +*/ +Server_Key_Exchange::Server_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + RandomNumberGenerator& rng, + const Private_Key* signing_key) + { + const std::string hostname = state.client_hello()->sni_hostname(); + const Kex_Algo kex_algo = state.ciphersuite().kex_method(); + + if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) + { + std::string identity_hint = + creds.psk_identity_hint("tls-server", hostname); + + append_tls_length_value(m_params, identity_hint, 2); + } + + if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) + { + const std::vector dh_groups = state.client_hello()->supported_dh_groups(); + + Group_Params shared_group = Group_Params::NONE; + + /* + If the client does not send any DH groups in the supported groups + extension, but does offer DH ciphersuites, we select a group arbitrarily + */ + + if(dh_groups.empty()) + { + shared_group = policy.default_dh_group(); + } + else + { + shared_group = policy.choose_key_exchange_group(dh_groups); + } + + if(shared_group == Group_Params::NONE) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Could not agree on a DH group with the client"); + + BOTAN_ASSERT(group_param_is_dh(shared_group), "DH groups for the DH ciphersuites god"); + + const std::string group_name = state.callbacks().tls_decode_group_param(shared_group); + std::unique_ptr dh(new DH_PrivateKey(rng, DL_Group(group_name))); + + append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); + append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); + append_tls_length_value(m_params, dh->public_value(), 2); + m_kex_key.reset(dh.release()); + } + else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) + { + const std::vector ec_groups = state.client_hello()->supported_ecc_curves(); + + if(ec_groups.empty()) + throw Internal_Error("Client sent no ECC extension but we negotiated ECDH"); + + Group_Params shared_group = policy.choose_key_exchange_group(ec_groups); + + if(shared_group == Group_Params::NONE) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "No shared ECC group with client"); + + std::vector ecdh_public_val; + + if(shared_group == Group_Params::X25519) + { +#if defined(BOTAN_HAS_CURVE_25519) + std::unique_ptr x25519(new Curve25519_PrivateKey(rng)); + ecdh_public_val = x25519->public_value(); + m_kex_key.reset(x25519.release()); +#else + throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); +#endif + } + else + { + Group_Params curve = policy.choose_key_exchange_group(ec_groups); + + const std::string curve_name = state.callbacks().tls_decode_group_param(curve); + + EC_Group ec_group(curve_name); + std::unique_ptr ecdh(new ECDH_PrivateKey(rng, ec_group)); + + // follow client's preference for point compression + ecdh_public_val = ecdh->public_value( + state.client_hello()->prefers_compressed_ec_points() ? + PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED); + + m_kex_key.reset(ecdh.release()); + } + + const uint16_t named_curve_id = static_cast(shared_group); + m_params.push_back(3); // named curve + m_params.push_back(get_byte(0, named_curve_id)); + m_params.push_back(get_byte(1, named_curve_id)); + + append_tls_length_value(m_params, ecdh_public_val, 1); + } +#if defined(BOTAN_HAS_SRP6) + else if(kex_algo == Kex_Algo::SRP_SHA) + { + const std::string srp_identifier = state.client_hello()->srp_identifier(); + + std::string group_id; + BigInt v; + std::vector salt; + + const bool found = creds.srp_verifier("tls-server", hostname, + srp_identifier, + group_id, v, salt, + policy.hide_unknown_users()); + + if(!found) + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "Unknown SRP user " + srp_identifier); + + m_srp_params.reset(new SRP6_Server_Session); + + BigInt B = m_srp_params->step1(v, group_id, + "SHA-1", rng); + + DL_Group group(group_id); + + append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2); + append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2); + append_tls_length_value(m_params, salt, 1); + append_tls_length_value(m_params, BigInt::encode(B), 2); + } +#endif +#if defined(BOTAN_HAS_CECPQ1) + else if(kex_algo == Kex_Algo::CECPQ1) + { + std::vector cecpq1_offer(CECPQ1_OFFER_BYTES); + m_cecpq1_key.reset(new CECPQ1_key); + CECPQ1_offer(cecpq1_offer.data(), m_cecpq1_key.get(), rng); + append_tls_length_value(m_params, cecpq1_offer, 2); + } +#endif + else if(kex_algo != Kex_Algo::PSK) + { + throw Internal_Error("Server_Key_Exchange: Unknown kex type " + + kex_method_to_string(kex_algo)); + } + + if(state.ciphersuite().signature_used()) + { + BOTAN_ASSERT(signing_key, "Signing key was set"); + + std::pair format = + state.choose_sig_format(*signing_key, m_scheme, false, policy); + + std::vector buf = state.client_hello()->random(); + + buf += state.server_hello()->random(); + buf += params(); + + m_signature = + state.callbacks().tls_sign_message(*signing_key, rng, + format.first, format.second, buf); + } + + state.hash().update(io.send(*this)); + } + +/** +* Deserialize a Server Key Exchange message +*/ +Server_Key_Exchange::Server_Key_Exchange(const std::vector& buf, + const Kex_Algo kex_algo, + const Auth_Method auth_method, + Protocol_Version version) + { + TLS_Data_Reader reader("ServerKeyExchange", buf); + + /* + * Here we are deserializing enough to find out what offset the + * signature is at. All processing is done when the Client Key Exchange + * is prepared. + */ + + if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::DHE_PSK || kex_algo == Kex_Algo::ECDHE_PSK) + { + reader.get_string(2, 0, 65535); // identity hint + } + + if(kex_algo == Kex_Algo::DH || kex_algo == Kex_Algo::DHE_PSK) + { + // 3 bigints, DH p, g, Y + + for(size_t i = 0; i != 3; ++i) + { + reader.get_range(2, 1, 65535); + } + } + else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) + { + reader.get_byte(); // curve type + reader.get_uint16_t(); // curve id + reader.get_range(1, 1, 255); // public key + } + else if(kex_algo == Kex_Algo::SRP_SHA) + { + // 2 bigints (N,g) then salt, then server B + + reader.get_range(2, 1, 65535); + reader.get_range(2, 1, 65535); + reader.get_range(1, 1, 255); + reader.get_range(2, 1, 65535); + } + else if(kex_algo == Kex_Algo::CECPQ1) + { + // u16 blob + reader.get_range(2, 1, 65535); + } + else if(kex_algo != Kex_Algo::PSK) + throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + + kex_method_to_string(kex_algo)); + + m_params.assign(buf.data(), buf.data() + reader.read_so_far()); + + if(auth_method != Auth_Method::ANONYMOUS && auth_method != Auth_Method::IMPLICIT) + { + if(version.supports_negotiable_signature_algorithms()) + { + m_scheme = static_cast(reader.get_uint16_t()); + } + + m_signature = reader.get_range(2, 0, 65535); + } + + reader.assert_done(); + } + +/** +* Serialize a Server Key Exchange message +*/ +std::vector Server_Key_Exchange::serialize() const + { + std::vector buf = params(); + + if(m_signature.size()) + { + if(m_scheme != Signature_Scheme::NONE) + { + const uint16_t scheme_code = static_cast(m_scheme); + buf.push_back(get_byte(0, scheme_code)); + buf.push_back(get_byte(1, scheme_code)); + } + + append_tls_length_value(buf, m_signature, 2); + } + + return buf; + } + +/** +* Verify a Server Key Exchange message +*/ +bool Server_Key_Exchange::verify(const Public_Key& server_key, + const Handshake_State& state, + const Policy& policy) const + { + policy.check_peer_key_acceptable(server_key); + + std::pair format = + state.parse_sig_format(server_key, m_scheme, false, policy); + + std::vector buf = state.client_hello()->random(); + + buf += state.server_hello()->random(); + buf += params(); + + const bool signature_valid = + state.callbacks().tls_verify_message(server_key, format.first, format.second, + buf, m_signature); + +#if defined(BOTAN_UNSAFE_FUZZER_MODE) + BOTAN_UNUSED(signature_valid); + return true; +#else + return signature_valid; +#endif + } + +const Private_Key& Server_Key_Exchange::server_kex_key() const + { + BOTAN_ASSERT_NONNULL(m_kex_key); + return *m_kex_key; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/msg_session_ticket.cpp b/comm/third_party/botan/src/lib/tls/msg_session_ticket.cpp new file mode 100644 index 0000000000..bd0d74ceb2 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_session_ticket.cpp @@ -0,0 +1,56 @@ +/* +* Session Tickets +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& ticket, + uint32_t lifetime) : + m_ticket_lifetime_hint(lifetime), + m_ticket(ticket) + { + hash.update(io.send(*this)); + } + +New_Session_Ticket::New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash) + { + hash.update(io.send(*this)); + } + +New_Session_Ticket::New_Session_Ticket(const std::vector& buf) + { + if(buf.size() < 6) + throw Decoding_Error("Session ticket message too short to be valid"); + + TLS_Data_Reader reader("SessionTicket", buf); + + m_ticket_lifetime_hint = reader.get_uint32_t(); + m_ticket = reader.get_range(2, 0, 65535); + reader.assert_done(); + } + +std::vector New_Session_Ticket::serialize() const + { + std::vector buf(4); + store_be(m_ticket_lifetime_hint, buf.data()); + append_tls_length_value(buf, m_ticket, 2); + return buf; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/sessions_sql/info.txt b/comm/third_party/botan/src/lib/tls/sessions_sql/info.txt new file mode 100644 index 0000000000..58392bd0c4 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/sessions_sql/info.txt @@ -0,0 +1,7 @@ + +TLS_SESSION_MANAGER_SQL_DB -> 20141219 + + + +pbkdf2 + diff --git a/comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp b/comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp new file mode 100644 index 0000000000..09cfbc4e99 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp @@ -0,0 +1,213 @@ +/* +* SQL TLS Session Manager +* (C) 2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Session_Manager_SQL::Session_Manager_SQL(std::shared_ptr db, + const std::string& passphrase, + RandomNumberGenerator& rng, + size_t max_sessions, + std::chrono::seconds session_lifetime) : + m_db(db), + m_rng(rng), + m_max_sessions(max_sessions), + m_session_lifetime(session_lifetime) + { + m_db->create_table( + "create table if not exists tls_sessions " + "(" + "session_id TEXT PRIMARY KEY, " + "session_start INTEGER, " + "hostname TEXT, " + "hostport INTEGER, " + "session BLOB" + ")"); + + m_db->create_table( + "create table if not exists tls_sessions_metadata " + "(" + "passphrase_salt BLOB, " + "passphrase_iterations INTEGER, " + "passphrase_check INTEGER " + ")"); + + const size_t salts = m_db->row_count("tls_sessions_metadata"); + + std::unique_ptr pbkdf(get_pbkdf("PBKDF2(SHA-512)")); + + if(salts == 1) + { + // existing db + auto stmt = m_db->new_statement("select * from tls_sessions_metadata"); + + if(stmt->step()) + { + std::pair salt = stmt->get_blob(0); + const size_t iterations = stmt->get_size_t(1); + const size_t check_val_db = stmt->get_size_t(2); + + secure_vector x = pbkdf->pbkdf_iterations(32 + 2, + passphrase, + salt.first, salt.second, + iterations); + + const size_t check_val_created = make_uint16(x[0], x[1]); + m_session_key.assign(x.begin() + 2, x.end()); + + if(check_val_created != check_val_db) + throw Invalid_Argument("Session database password not valid"); + } + } + else + { + // maybe just zap the salts + sessions tables in this case? + if(salts != 0) + throw Internal_Error("Seemingly corrupted TLS session db, multiple salts found"); + + // new database case + + std::vector salt; + rng.random_vec(salt, 16); + size_t iterations = 0; + + secure_vector x = pbkdf->pbkdf_timed(32 + 2, + passphrase, + salt.data(), salt.size(), + std::chrono::milliseconds(100), + iterations); + + size_t check_val = make_uint16(x[0], x[1]); + m_session_key.assign(x.begin() + 2, x.end()); + + auto stmt = m_db->new_statement("insert into tls_sessions_metadata values(?1, ?2, ?3)"); + + stmt->bind(1, salt); + stmt->bind(2, iterations); + stmt->bind(3, check_val); + + stmt->spin(); + } + } + +bool Session_Manager_SQL::load_from_session_id(const std::vector& session_id, + Session& session) + { + auto stmt = m_db->new_statement("select session from tls_sessions where session_id = ?1"); + + stmt->bind(1, hex_encode(session_id)); + + while(stmt->step()) + { + std::pair blob = stmt->get_blob(0); + + try + { + session = Session::decrypt(blob.first, blob.second, m_session_key); + return true; + } + catch(...) + { + } + } + + return false; + } + +bool Session_Manager_SQL::load_from_server_info(const Server_Information& server, + Session& session) + { + auto stmt = m_db->new_statement("select session from tls_sessions" + " where hostname = ?1 and hostport = ?2" + " order by session_start desc"); + + stmt->bind(1, server.hostname()); + stmt->bind(2, server.port()); + + while(stmt->step()) + { + std::pair blob = stmt->get_blob(0); + + try + { + session = Session::decrypt(blob.first, blob.second, m_session_key); + return true; + } + catch(...) + { + } + } + + return false; + } + +void Session_Manager_SQL::remove_entry(const std::vector& session_id) + { + auto stmt = m_db->new_statement("delete from tls_sessions where session_id = ?1"); + + stmt->bind(1, hex_encode(session_id)); + + stmt->spin(); + } + +size_t Session_Manager_SQL::remove_all() + { + auto stmt = m_db->new_statement("delete from tls_sessions"); + return stmt->spin(); + } + +void Session_Manager_SQL::save(const Session& session) + { + if(session.server_info().hostname().empty()) + return; + + auto stmt = m_db->new_statement("insert or replace into tls_sessions" + " values(?1, ?2, ?3, ?4, ?5)"); + + stmt->bind(1, hex_encode(session.session_id())); + stmt->bind(2, session.start_time()); + stmt->bind(3, session.server_info().hostname()); + stmt->bind(4, session.server_info().port()); + stmt->bind(5, session.encrypt(m_session_key, m_rng)); + + stmt->spin(); + + prune_session_cache(); + } + +void Session_Manager_SQL::prune_session_cache() + { + // First expire old sessions + auto remove_expired = m_db->new_statement("delete from tls_sessions where session_start <= ?1"); + remove_expired->bind(1, std::chrono::system_clock::now() - m_session_lifetime); + remove_expired->spin(); + + const size_t sessions = m_db->row_count("tls_sessions"); + + // Then if needed expire some more sessions at random + if(sessions > m_max_sessions) + { + auto remove_some = m_db->new_statement("delete from tls_sessions where session_id in " + "(select session_id from tls_sessions limit ?1)"); + + remove_some->bind(1, sessions - m_max_sessions); + remove_some->spin(); + } + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.h b/comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.h new file mode 100644 index 0000000000..d96a8b5bba --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/sessions_sql/tls_session_manager_sql.h @@ -0,0 +1,81 @@ +/* +* TLS Session Manager storing to encrypted SQL db table +* (C) 2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SQL_SESSION_MANAGER_H_ +#define BOTAN_TLS_SQL_SESSION_MANAGER_H_ + +#include +#include + +namespace Botan { + +class RandomNumberGenerator; + +namespace TLS { + +/** +* An implementation of Session_Manager that saves values in a SQL +* database file, with the session data encrypted using a passphrase. +* +* @warning For clients, the hostnames associated with the saved +* sessions are stored in the database in plaintext. This may be a +* serious privacy risk in some situations. +*/ +class BOTAN_PUBLIC_API(2,0) Session_Manager_SQL : public Session_Manager + { + public: + /** + * @param db A connection to the database to use + The table names botan_tls_sessions and + botan_tls_sessions_metadata will be used + * @param passphrase used to encrypt the session data + * @param rng a random number generator + * @param max_sessions a hint on the maximum number of sessions + * to keep in memory at any one time. (If zero, don't cap) + * @param session_lifetime sessions are expired after this many + * seconds have elapsed from initial handshake. + */ + Session_Manager_SQL(std::shared_ptr db, + const std::string& passphrase, + RandomNumberGenerator& rng, + size_t max_sessions = 1000, + std::chrono::seconds session_lifetime = std::chrono::seconds(7200)); + + Session_Manager_SQL(const Session_Manager_SQL&) = delete; + + Session_Manager_SQL& operator=(const Session_Manager_SQL&) = delete; + + bool load_from_session_id(const std::vector& session_id, + Session& session) override; + + bool load_from_server_info(const Server_Information& info, + Session& session) override; + + void remove_entry(const std::vector& session_id) override; + + size_t remove_all() override; + + void save(const Session& session_data) override; + + std::chrono::seconds session_lifetime() const override + { return m_session_lifetime; } + + private: + void prune_session_cache(); + + std::shared_ptr m_db; + secure_vector m_session_key; + RandomNumberGenerator& m_rng; + size_t m_max_sessions; + std::chrono::seconds m_session_lifetime; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/sessions_sqlite3/info.txt b/comm/third_party/botan/src/lib/tls/sessions_sqlite3/info.txt new file mode 100644 index 0000000000..612142c094 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/sessions_sqlite3/info.txt @@ -0,0 +1,8 @@ + +TLS_SQLITE3_SESSION_MANAGER -> 20131128 + + + +sessions_sql +sqlite3 + diff --git a/comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.cpp b/comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.cpp new file mode 100644 index 0000000000..aa163be8a7 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.cpp @@ -0,0 +1,29 @@ +/* +* SQLite TLS Session Manager +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +Session_Manager_SQLite::Session_Manager_SQLite(const std::string& passphrase, + RandomNumberGenerator& rng, + const std::string& db_filename, + size_t max_sessions, + std::chrono::seconds session_lifetime) : + Session_Manager_SQL(std::make_shared(db_filename), + passphrase, + rng, + max_sessions, + session_lifetime) + {} + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.h b/comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.h new file mode 100644 index 0000000000..f906ae585e --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/sessions_sqlite3/tls_session_manager_sqlite.h @@ -0,0 +1,53 @@ +/* +* SQLite3 TLS Session Manager +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SQLITE3_SESSION_MANAGER_H_ +#define BOTAN_TLS_SQLITE3_SESSION_MANAGER_H_ + +#include + +namespace Botan { + +class RandomNumberGenerator; + +namespace TLS { + +/** +* An implementation of Session_Manager that saves values in a SQLite3 +* database file, with the session data encrypted using a passphrase. +* +* @warning For clients, the hostnames associated with the saved +* sessions are stored in the database in plaintext. This may be a +* serious privacy risk in some situations. +*/ +class BOTAN_PUBLIC_API(2,0) +Session_Manager_SQLite final : public Session_Manager_SQL + { + public: + /** + * @param passphrase used to encrypt the session data + * @param rng a random number generator + * @param db_filename filename of the SQLite database file. + The table names tls_sessions and tls_sessions_metadata + will be used + * @param max_sessions a hint on the maximum number of sessions + * to keep in memory at any one time. (If zero, don't cap) + * @param session_lifetime sessions are expired after this many + * seconds have elapsed from initial handshake. + */ + Session_Manager_SQLite(const std::string& passphrase, + RandomNumberGenerator& rng, + const std::string& db_filename, + size_t max_sessions = 1000, + std::chrono::seconds session_lifetime = std::chrono::seconds(7200)); +}; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_10/info.txt b/comm/third_party/botan/src/lib/tls/tls_10/info.txt new file mode 100644 index 0000000000..f85a199921 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_10/info.txt @@ -0,0 +1,10 @@ + +TLS_V10 -> 20191109 + + + +md5 +sha1 +par_hash +tls_cbc + diff --git a/comm/third_party/botan/src/lib/tls/tls_alert.cpp b/comm/third_party/botan/src/lib/tls/tls_alert.cpp new file mode 100644 index 0000000000..60c9c4b981 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_alert.cpp @@ -0,0 +1,126 @@ +/* +* Alert Message +* (C) 2004-2006,2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +Alert::Alert(const secure_vector& buf) + { + if(buf.size() != 2) + throw Decoding_Error("Bad size (" + std::to_string(buf.size()) + + ") for TLS alert message"); + + if(buf[0] == 1) m_fatal = false; + else if(buf[0] == 2) m_fatal = true; + else + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Bad code for TLS alert level"); + + const uint8_t dc = buf[1]; + + m_type_code = static_cast(dc); + } + +std::vector Alert::serialize() const + { + return std::vector({ + static_cast(is_fatal() ? 2 : 1), + static_cast(type()) + }); + } + +std::string Alert::type_string() const + { + switch(type()) + { + case CLOSE_NOTIFY: + return "close_notify"; + case UNEXPECTED_MESSAGE: + return "unexpected_message"; + case BAD_RECORD_MAC: + return "bad_record_mac"; + case DECRYPTION_FAILED: + return "decryption_failed"; + case RECORD_OVERFLOW: + return "record_overflow"; + case DECOMPRESSION_FAILURE: + return "decompression_failure"; + case HANDSHAKE_FAILURE: + return "handshake_failure"; + case NO_CERTIFICATE: + return "no_certificate"; + case BAD_CERTIFICATE: + return "bad_certificate"; + case UNSUPPORTED_CERTIFICATE: + return "unsupported_certificate"; + case CERTIFICATE_REVOKED: + return "certificate_revoked"; + case CERTIFICATE_EXPIRED: + return "certificate_expired"; + case CERTIFICATE_UNKNOWN: + return "certificate_unknown"; + case ILLEGAL_PARAMETER: + return "illegal_parameter"; + case UNKNOWN_CA: + return "unknown_ca"; + case ACCESS_DENIED: + return "access_denied"; + case DECODE_ERROR: + return "decode_error"; + case DECRYPT_ERROR: + return "decrypt_error"; + case EXPORT_RESTRICTION: + return "export_restriction"; + case PROTOCOL_VERSION: + return "protocol_version"; + case INSUFFICIENT_SECURITY: + return "insufficient_security"; + case INTERNAL_ERROR: + return "internal_error"; + case INAPPROPRIATE_FALLBACK: + return "inappropriate_fallback"; + case USER_CANCELED: + return "user_canceled"; + case NO_RENEGOTIATION: + return "no_renegotiation"; + + case UNSUPPORTED_EXTENSION: + return "unsupported_extension"; + case CERTIFICATE_UNOBTAINABLE: + return "certificate_unobtainable"; + case UNRECOGNIZED_NAME: + return "unrecognized_name"; + case BAD_CERTIFICATE_STATUS_RESPONSE: + return "bad_certificate_status_response"; + case BAD_CERTIFICATE_HASH_VALUE: + return "bad_certificate_hash_value"; + case UNKNOWN_PSK_IDENTITY: + return "unknown_psk_identity"; + case CERTIFICATE_REQUIRED: + return "certificate_required"; + case NO_APPLICATION_PROTOCOL: + return "no_application_protocol"; + + case NULL_ALERT: + return "none"; + } + + /* + * This is effectively the default case for the switch above, but we + * leave it out so that when an alert type is added to the enum the + * compiler can warn us that it is not included in the switch + * statement. + */ + return "unrecognized_alert_" + std::to_string(type()); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_alert.h b/comm/third_party/botan/src/lib/tls/tls_alert.h new file mode 100644 index 0000000000..d9d3fe3136 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_alert.h @@ -0,0 +1,116 @@ +/* +* Alert Message +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_ALERT_H_ +#define BOTAN_TLS_ALERT_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* SSL/TLS Alert Message +*/ +class BOTAN_PUBLIC_API(2,0) Alert final + { + public: + /** + * Type codes for TLS alerts + */ + enum Type { + CLOSE_NOTIFY = 0, + UNEXPECTED_MESSAGE = 10, + BAD_RECORD_MAC = 20, + DECRYPTION_FAILED = 21, + RECORD_OVERFLOW = 22, + DECOMPRESSION_FAILURE = 30, + HANDSHAKE_FAILURE = 40, + NO_CERTIFICATE = 41, // SSLv3 only + BAD_CERTIFICATE = 42, + UNSUPPORTED_CERTIFICATE = 43, + CERTIFICATE_REVOKED = 44, + CERTIFICATE_EXPIRED = 45, + CERTIFICATE_UNKNOWN = 46, + ILLEGAL_PARAMETER = 47, + UNKNOWN_CA = 48, + ACCESS_DENIED = 49, + DECODE_ERROR = 50, + DECRYPT_ERROR = 51, + EXPORT_RESTRICTION = 60, + PROTOCOL_VERSION = 70, + INSUFFICIENT_SECURITY = 71, + INTERNAL_ERROR = 80, + INAPPROPRIATE_FALLBACK = 86, + USER_CANCELED = 90, + NO_RENEGOTIATION = 100, + UNSUPPORTED_EXTENSION = 110, + CERTIFICATE_UNOBTAINABLE = 111, + UNRECOGNIZED_NAME = 112, + BAD_CERTIFICATE_STATUS_RESPONSE = 113, + BAD_CERTIFICATE_HASH_VALUE = 114, + UNKNOWN_PSK_IDENTITY = 115, + CERTIFICATE_REQUIRED = 116, // RFC 8446 + + NO_APPLICATION_PROTOCOL = 120, // RFC 7301 + + // pseudo alert values + NULL_ALERT = 256 + }; + + /** + * @return true iff this alert is non-empty + */ + bool is_valid() const { return (m_type_code != NULL_ALERT); } + + /** + * @return if this alert is a fatal one or not + */ + bool is_fatal() const { return m_fatal; } + + /** + * @return type of alert + */ + Type type() const { return m_type_code; } + + /** + * @return type of alert + */ + std::string type_string() const; + + /** + * Serialize an alert + */ + std::vector serialize() const; + + /** + * Deserialize an Alert message + * @param buf the serialized alert + */ + explicit Alert(const secure_vector& buf); + + /** + * Create a new Alert + * @param type_code the type of alert + * @param fatal specifies if this is a fatal alert + */ + Alert(Type type_code, bool fatal = false) : + m_fatal(fatal), m_type_code(type_code) {} + + Alert() : m_fatal(false), m_type_code(NULL_ALERT) {} + private: + bool m_fatal; + Type m_type_code; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_algos.cpp b/comm/third_party/botan/src/lib/tls/tls_algos.cpp new file mode 100644 index 0000000000..9501cfdfb7 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_algos.cpp @@ -0,0 +1,426 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +std::string kdf_algo_to_string(KDF_Algo algo) + { + switch(algo) + { + case KDF_Algo::SHA_1: + return "SHA-1"; + case KDF_Algo::SHA_256: + return "SHA-256"; + case KDF_Algo::SHA_384: + return "SHA-384"; + } + + throw Invalid_State("kdf_algo_to_string unknown enum value"); + } + +std::string kex_method_to_string(Kex_Algo method) + { + switch(method) + { + case Kex_Algo::STATIC_RSA: + return "RSA"; + case Kex_Algo::DH: + return "DH"; + case Kex_Algo::ECDH: + return "ECDH"; + case Kex_Algo::CECPQ1: + return "CECPQ1"; + case Kex_Algo::SRP_SHA: + return "SRP_SHA"; + case Kex_Algo::PSK: + return "PSK"; + case Kex_Algo::DHE_PSK: + return "DHE_PSK"; + case Kex_Algo::ECDHE_PSK: + return "ECDHE_PSK"; + } + + throw Invalid_State("kex_method_to_string unknown enum value"); + } + +Kex_Algo kex_method_from_string(const std::string& str) + { + if(str == "RSA") + return Kex_Algo::STATIC_RSA; + + if(str == "DH") + return Kex_Algo::DH; + + if(str == "ECDH") + return Kex_Algo::ECDH; + + if(str == "CECPQ1") + return Kex_Algo::CECPQ1; + + if(str == "SRP_SHA") + return Kex_Algo::SRP_SHA; + + if(str == "PSK") + return Kex_Algo::PSK; + + if(str == "DHE_PSK") + return Kex_Algo::DHE_PSK; + + if(str == "ECDHE_PSK") + return Kex_Algo::ECDHE_PSK; + + throw Invalid_Argument("Unknown kex method " + str); + } + +std::string auth_method_to_string(Auth_Method method) + { + switch(method) + { + case Auth_Method::RSA: + return "RSA"; + case Auth_Method::DSA: + return "DSA"; + case Auth_Method::ECDSA: + return "ECDSA"; + case Auth_Method::IMPLICIT: + return "IMPLICIT"; + case Auth_Method::ANONYMOUS: + return "ANONYMOUS"; + } + + throw Invalid_State("auth_method_to_string unknown enum value"); + } + +Auth_Method auth_method_from_string(const std::string& str) + { + if(str == "RSA") + return Auth_Method::RSA; + if(str == "DSA") + return Auth_Method::DSA; + if(str == "ECDSA") + return Auth_Method::ECDSA; + if(str == "IMPLICIT") + return Auth_Method::IMPLICIT; + if(str == "ANONYMOUS" || str == "") + return Auth_Method::ANONYMOUS; + + throw Invalid_Argument("Bad signature method " + str); + } + +bool group_param_is_dh(Group_Params group) + { + uint16_t group_id = static_cast(group); + return (group_id >= 256 && group_id < 512); + } + +Group_Params group_param_from_string(const std::string& group_name) + { + if(group_name == "secp256r1") + return Group_Params::SECP256R1; + if(group_name == "secp384r1") + return Group_Params::SECP384R1; + if(group_name == "secp521r1") + return Group_Params::SECP521R1; + if(group_name == "brainpool256r1") + return Group_Params::BRAINPOOL256R1; + if(group_name == "brainpool384r1") + return Group_Params::BRAINPOOL384R1; + if(group_name == "brainpool512r1") + return Group_Params::BRAINPOOL512R1; + if(group_name == "x25519") + return Group_Params::X25519; + + if(group_name == "ffdhe/ietf/2048") + return Group_Params::FFDHE_2048; + if(group_name == "ffdhe/ietf/3072") + return Group_Params::FFDHE_3072; + if(group_name == "ffdhe/ietf/4096") + return Group_Params::FFDHE_4096; + if(group_name == "ffdhe/ietf/6144") + return Group_Params::FFDHE_6144; + if(group_name == "ffdhe/ietf/8192") + return Group_Params::FFDHE_8192; + + return Group_Params::NONE; // unknown + } + +std::string group_param_to_string(Group_Params group) + { + switch(group) + { + case Group_Params::SECP256R1: + return "secp256r1"; + case Group_Params::SECP384R1: + return "secp384r1"; + case Group_Params::SECP521R1: + return "secp521r1"; + case Group_Params::BRAINPOOL256R1: + return "brainpool256r1"; + case Group_Params::BRAINPOOL384R1: + return "brainpool384r1"; + case Group_Params::BRAINPOOL512R1: + return "brainpool512r1"; + case Group_Params::X25519: + return "x25519"; + + case Group_Params::FFDHE_2048: + return "ffdhe/ietf/2048"; + case Group_Params::FFDHE_3072: + return "ffdhe/ietf/3072"; + case Group_Params::FFDHE_4096: + return "ffdhe/ietf/4096"; + case Group_Params::FFDHE_6144: + return "ffdhe/ietf/6144"; + case Group_Params::FFDHE_8192: + return "ffdhe/ietf/8192"; + + default: + return ""; + } + } + + +std::string hash_function_of_scheme(Signature_Scheme scheme) + { + switch(scheme) + { + case Signature_Scheme::DSA_SHA1: + case Signature_Scheme::ECDSA_SHA1: + case Signature_Scheme::RSA_PKCS1_SHA1: + return "SHA-1"; + + case Signature_Scheme::DSA_SHA256: + case Signature_Scheme::ECDSA_SHA256: + case Signature_Scheme::RSA_PKCS1_SHA256: + case Signature_Scheme::RSA_PSS_SHA256: + return "SHA-256"; + + case Signature_Scheme::DSA_SHA384: + case Signature_Scheme::ECDSA_SHA384: + case Signature_Scheme::RSA_PKCS1_SHA384: + case Signature_Scheme::RSA_PSS_SHA384: + return "SHA-384"; + + case Signature_Scheme::DSA_SHA512: + case Signature_Scheme::ECDSA_SHA512: + case Signature_Scheme::RSA_PKCS1_SHA512: + case Signature_Scheme::RSA_PSS_SHA512: + return "SHA-512"; + + case Signature_Scheme::EDDSA_25519: + case Signature_Scheme::EDDSA_448: + return "Pure"; + + case Signature_Scheme::NONE: + return ""; + } + + throw Invalid_State("hash_function_of_scheme: Unknown signature algorithm enum"); + } + +const std::vector& all_signature_schemes() + { + /* + * This is ordered in some approximate order of preference + */ + static const std::vector all_schemes = { + //Signature_Scheme::EDDSA_448, + //Signature_Scheme::EDDSA_25519, + + Signature_Scheme::RSA_PSS_SHA384, + Signature_Scheme::RSA_PSS_SHA256, + Signature_Scheme::RSA_PSS_SHA512, + + Signature_Scheme::RSA_PKCS1_SHA384, + Signature_Scheme::RSA_PKCS1_SHA512, + Signature_Scheme::RSA_PKCS1_SHA256, + + Signature_Scheme::ECDSA_SHA384, + Signature_Scheme::ECDSA_SHA512, + Signature_Scheme::ECDSA_SHA256, + + Signature_Scheme::DSA_SHA384, + Signature_Scheme::DSA_SHA512, + Signature_Scheme::DSA_SHA256, + + Signature_Scheme::RSA_PKCS1_SHA1, + Signature_Scheme::ECDSA_SHA1, + Signature_Scheme::DSA_SHA1, + }; + + return all_schemes; + } + +bool signature_scheme_is_known(Signature_Scheme scheme) + { + switch(scheme) + { + case Signature_Scheme::RSA_PKCS1_SHA1: + case Signature_Scheme::RSA_PKCS1_SHA256: + case Signature_Scheme::RSA_PKCS1_SHA384: + case Signature_Scheme::RSA_PKCS1_SHA512: + case Signature_Scheme::RSA_PSS_SHA256: + case Signature_Scheme::RSA_PSS_SHA384: + case Signature_Scheme::RSA_PSS_SHA512: + + case Signature_Scheme::DSA_SHA1: + case Signature_Scheme::DSA_SHA256: + case Signature_Scheme::DSA_SHA384: + case Signature_Scheme::DSA_SHA512: + + case Signature_Scheme::ECDSA_SHA1: + case Signature_Scheme::ECDSA_SHA256: + case Signature_Scheme::ECDSA_SHA384: + case Signature_Scheme::ECDSA_SHA512: + return true; + + default: + return false; + } + + } + +std::string signature_algorithm_of_scheme(Signature_Scheme scheme) + { + switch(scheme) + { + case Signature_Scheme::RSA_PKCS1_SHA1: + case Signature_Scheme::RSA_PKCS1_SHA256: + case Signature_Scheme::RSA_PKCS1_SHA384: + case Signature_Scheme::RSA_PKCS1_SHA512: + case Signature_Scheme::RSA_PSS_SHA256: + case Signature_Scheme::RSA_PSS_SHA384: + case Signature_Scheme::RSA_PSS_SHA512: + return "RSA"; + + case Signature_Scheme::DSA_SHA1: + case Signature_Scheme::DSA_SHA256: + case Signature_Scheme::DSA_SHA384: + case Signature_Scheme::DSA_SHA512: + return "DSA"; + + case Signature_Scheme::ECDSA_SHA1: + case Signature_Scheme::ECDSA_SHA256: + case Signature_Scheme::ECDSA_SHA384: + case Signature_Scheme::ECDSA_SHA512: + return "ECDSA"; + + case Signature_Scheme::EDDSA_25519: + return "Ed25519"; + + case Signature_Scheme::EDDSA_448: + return "Ed448"; + + case Signature_Scheme::NONE: + return ""; + } + + throw Invalid_State("signature_algorithm_of_scheme: Unknown signature algorithm enum"); + } + +std::string sig_scheme_to_string(Signature_Scheme scheme) + { + switch(scheme) + { + case Signature_Scheme::RSA_PKCS1_SHA1: + return "RSA_PKCS1_SHA1"; + case Signature_Scheme::RSA_PKCS1_SHA256: + return "RSA_PKCS1_SHA256"; + case Signature_Scheme::RSA_PKCS1_SHA384: + return "RSA_PKCS1_SHA384"; + case Signature_Scheme::RSA_PKCS1_SHA512: + return "RSA_PKCS1_SHA512"; + + case Signature_Scheme::DSA_SHA1: + return "DSA_SHA1"; + case Signature_Scheme::DSA_SHA256: + return "DSA_SHA256"; + case Signature_Scheme::DSA_SHA384: + return "DSA_SHA384"; + case Signature_Scheme::DSA_SHA512: + return "DSA_SHA512"; + + case Signature_Scheme::ECDSA_SHA1: + return "ECDSA_SHA1"; + case Signature_Scheme::ECDSA_SHA256: + return "ECDSA_SHA256"; + case Signature_Scheme::ECDSA_SHA384: + return "ECDSA_SHA384"; + case Signature_Scheme::ECDSA_SHA512: + return "ECDSA_SHA512"; + + case Signature_Scheme::RSA_PSS_SHA256: + return "RSA_PSS_SHA256"; + case Signature_Scheme::RSA_PSS_SHA384: + return "RSA_PSS_SHA384"; + case Signature_Scheme::RSA_PSS_SHA512: + return "RSA_PSS_SHA512"; + + case Signature_Scheme::EDDSA_25519: + return "EDDSA_25519"; + case Signature_Scheme::EDDSA_448: + return "EDDSA_448"; + + case Signature_Scheme::NONE: + return ""; + } + + throw Invalid_State("sig_scheme_to_string: Unknown signature algorithm enum"); + } + +std::string padding_string_for_scheme(Signature_Scheme scheme) + { + switch(scheme) + { + case Signature_Scheme::RSA_PKCS1_SHA1: + return "EMSA_PKCS1(SHA-1)"; + case Signature_Scheme::RSA_PKCS1_SHA256: + return "EMSA_PKCS1(SHA-256)"; + case Signature_Scheme::RSA_PKCS1_SHA384: + return "EMSA_PKCS1(SHA-384)"; + case Signature_Scheme::RSA_PKCS1_SHA512: + return "EMSA_PKCS1(SHA-512)"; + + case Signature_Scheme::DSA_SHA1: + case Signature_Scheme::ECDSA_SHA1: + return "EMSA1(SHA-1)"; + case Signature_Scheme::DSA_SHA256: + case Signature_Scheme::ECDSA_SHA256: + return "EMSA1(SHA-256)"; + case Signature_Scheme::DSA_SHA384: + case Signature_Scheme::ECDSA_SHA384: + return "EMSA1(SHA-384)"; + case Signature_Scheme::DSA_SHA512: + case Signature_Scheme::ECDSA_SHA512: + return "EMSA1(SHA-512)"; + + case Signature_Scheme::RSA_PSS_SHA256: + return "PSSR(SHA-256,MGF1,32)"; + case Signature_Scheme::RSA_PSS_SHA384: + return "PSSR(SHA-384,MGF1,48)"; + case Signature_Scheme::RSA_PSS_SHA512: + return "PSSR(SHA-512,MGF1,64)"; + + case Signature_Scheme::EDDSA_25519: + return "Pure"; + case Signature_Scheme::EDDSA_448: + return "Pure"; + + case Signature_Scheme::NONE: + return ""; + } + + throw Invalid_State("padding_string_for_scheme: Unknown signature algorithm enum"); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_algos.h b/comm/third_party/botan/src/lib/tls/tls_algos.h new file mode 100644 index 0000000000..3b0be81286 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_algos.h @@ -0,0 +1,171 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_ALGO_IDS_H_ +#define BOTAN_TLS_ALGO_IDS_H_ + +#include +#include +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(tls_algos.h) + +namespace Botan { + +namespace TLS { + +enum class Cipher_Algo { + CHACHA20_POLY1305, + + AES_128_CBC_HMAC_SHA1 = 100, + AES_128_CBC_HMAC_SHA256, + AES_128_CCM, + AES_128_CCM_8, + AES_128_GCM, + AES_128_OCB, + + AES_256_CBC_HMAC_SHA1 = 200, + AES_256_CBC_HMAC_SHA256, + AES_256_CBC_HMAC_SHA384, + AES_256_CCM, + AES_256_CCM_8, + AES_256_GCM, + AES_256_OCB, + + CAMELLIA_128_CBC_HMAC_SHA1 = 300, + CAMELLIA_128_CBC_HMAC_SHA256, + CAMELLIA_128_GCM, + + CAMELLIA_256_CBC_HMAC_SHA1 = 400, + CAMELLIA_256_CBC_HMAC_SHA256, + CAMELLIA_256_CBC_HMAC_SHA384, + CAMELLIA_256_GCM, + + ARIA_128_GCM = 500, + ARIA_256_GCM, + + DES_EDE_CBC_HMAC_SHA1 = 1000, + SEED_CBC_HMAC_SHA1, +}; + +enum class KDF_Algo { + SHA_1, + SHA_256, + SHA_384, +}; + +std::string BOTAN_DLL kdf_algo_to_string(KDF_Algo algo); + +enum class Nonce_Format { + CBC_MODE, + AEAD_IMPLICIT_4, + AEAD_XOR_12, +}; + +// TODO encoding should match signature_algorithms extension +// TODO this should include hash etc as in TLS v1.3 +enum class Auth_Method { + RSA, + DSA, + ECDSA, + + // These are placed outside the encodable range + IMPLICIT = 0x10000, + ANONYMOUS +}; + +std::string BOTAN_TEST_API auth_method_to_string(Auth_Method method); +Auth_Method BOTAN_TEST_API auth_method_from_string(const std::string& str); + +/* +* This matches the wire encoding +*/ +enum class Signature_Scheme : uint16_t { + NONE = 0x0000, + + RSA_PKCS1_SHA1 = 0x0201, + RSA_PKCS1_SHA256 = 0x0401, + RSA_PKCS1_SHA384 = 0x0501, + RSA_PKCS1_SHA512 = 0x0601, + + DSA_SHA1 = 0x0202, + DSA_SHA256 = 0x0402, + DSA_SHA384 = 0x0502, + DSA_SHA512 = 0x0602, + + ECDSA_SHA1 = 0x0203, + ECDSA_SHA256 = 0x0403, + ECDSA_SHA384 = 0x0503, + ECDSA_SHA512 = 0x0603, + + RSA_PSS_SHA256 = 0x0804, + RSA_PSS_SHA384 = 0x0805, + RSA_PSS_SHA512 = 0x0806, + + EDDSA_25519 = 0x0807, + EDDSA_448 = 0x0808, +}; + +BOTAN_UNSTABLE_API const std::vector& all_signature_schemes(); + +bool BOTAN_UNSTABLE_API signature_scheme_is_known(Signature_Scheme scheme); +std::string BOTAN_UNSTABLE_API sig_scheme_to_string(Signature_Scheme scheme); +std::string BOTAN_UNSTABLE_API hash_function_of_scheme(Signature_Scheme scheme); +std::string BOTAN_UNSTABLE_API padding_string_for_scheme(Signature_Scheme scheme); +std::string signature_algorithm_of_scheme(Signature_Scheme scheme); + +/* +* Matches with wire encoding +*/ +enum class Group_Params : uint16_t { + NONE = 0, + + SECP256R1 = 23, + SECP384R1 = 24, + SECP521R1 = 25, + BRAINPOOL256R1 = 26, + BRAINPOOL384R1 = 27, + BRAINPOOL512R1 = 28, + + X25519 = 29, + + FFDHE_2048 = 256, + FFDHE_3072 = 257, + FFDHE_4096 = 258, + FFDHE_6144 = 259, + FFDHE_8192 = 260, +}; + +std::string group_param_to_string(Group_Params group); +Group_Params group_param_from_string(const std::string& group_name); +bool group_param_is_dh(Group_Params group); + +enum class Kex_Algo { + STATIC_RSA, + DH, + ECDH, + CECPQ1, + SRP_SHA, + PSK, + DHE_PSK, + ECDHE_PSK, +}; + +std::string BOTAN_TEST_API kex_method_to_string(Kex_Algo method); +Kex_Algo BOTAN_TEST_API kex_method_from_string(const std::string& str); + +inline bool key_exchange_is_psk(Kex_Algo m) + { + return (m == Kex_Algo::PSK || + m == Kex_Algo::DHE_PSK || + m == Kex_Algo::ECDHE_PSK); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_blocking.cpp b/comm/third_party/botan/src/lib/tls/tls_blocking.cpp new file mode 100644 index 0000000000..b9c699dc03 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_blocking.cpp @@ -0,0 +1,97 @@ +/* +* TLS Blocking API +* (C) 2013 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +namespace TLS { + +Blocking_Client::Blocking_Client(read_fn reader, + write_fn writer, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info, + const Protocol_Version& offer_version, + const std::vector& next) : + m_read(reader), + m_callbacks(new TLS::Compat_Callbacks( + /* + we are ok using deprecated features here because the whole Blocking_Client class + is also deprecated, so just silence the warning. + */ + TLS::Compat_Callbacks::SILENCE_DEPRECATION_WARNING::PLEASE, + writer, + std::bind(&Blocking_Client::data_cb, this, std::placeholders::_1, std::placeholders::_2), + std::function(std::bind(&Blocking_Client::alert_cb, this, std::placeholders::_1)), + std::bind(&Blocking_Client::handshake_cb, this, std::placeholders::_1) + )), + m_channel(*m_callbacks.get(), + session_manager, + creds, + policy, + rng, + server_info, + offer_version, + next) + { + } + +bool Blocking_Client::handshake_cb(const Session& session) + { + return this->handshake_complete(session); + } + +void Blocking_Client::alert_cb(const Alert& alert) + { + this->alert_notification(alert); + } + +void Blocking_Client::data_cb(const uint8_t data[], size_t data_len) + { + m_plaintext.insert(m_plaintext.end(), data, data + data_len); + } + +void Blocking_Client::do_handshake() + { + std::vector readbuf(4096); + + while(!m_channel.is_closed() && !m_channel.is_active()) + { + const size_t from_socket = m_read(readbuf.data(), readbuf.size()); + m_channel.received_data(readbuf.data(), from_socket); + } + } + +size_t Blocking_Client::read(uint8_t buf[], size_t buf_len) + { + std::vector readbuf(4096); + + while(m_plaintext.empty() && !m_channel.is_closed()) + { + const size_t from_socket = m_read(readbuf.data(), readbuf.size()); + m_channel.received_data(readbuf.data(), from_socket); + } + + const size_t returned = std::min(buf_len, m_plaintext.size()); + + for(size_t i = 0; i != returned; ++i) + buf[i] = m_plaintext[i]; + m_plaintext.erase(m_plaintext.begin(), m_plaintext.begin() + returned); + + BOTAN_ASSERT_IMPLICATION(returned == 0, m_channel.is_closed(), + "Only return zero if channel is closed"); + + return returned; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_blocking.h b/comm/third_party/botan/src/lib/tls/tls_blocking.h new file mode 100644 index 0000000000..01620c652c --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_blocking.h @@ -0,0 +1,103 @@ +/* +* TLS Blocking API +* (C) 2013 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_BLOCKING_CHANNELS_H_ +#define BOTAN_TLS_BLOCKING_CHANNELS_H_ + +#include + +namespace Botan { + +namespace TLS { + +/** +* Blocking TLS Client +* Can be used directly, or subclass to get handshake and alert notifications +*/ +class BOTAN_PUBLIC_API(2,0) Blocking_Client + { + public: + /* + * These functions are expected to block until completing entirely, or + * fail by throwing an exception. + */ + typedef std::function read_fn; + typedef std::function write_fn; + + BOTAN_DEPRECATED("Use the regular TLS::Client interface") + Blocking_Client(read_fn reader, + write_fn writer, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protos = {}); + + /** + * Completes full handshake then returns + */ + void do_handshake(); + + /** + * Number of bytes pending read in the plaintext buffer (bytes + * readable without blocking) + */ + size_t pending() const { return m_plaintext.size(); } + + /** + * Blocking read, will return at least 1 byte (eventually) or else 0 if the connection + * is closed. + */ + size_t read(uint8_t buf[], size_t buf_len); + + void write(const uint8_t buf[], size_t buf_len) { m_channel.send(buf, buf_len); } + + const TLS::Channel& underlying_channel() const { return m_channel; } + TLS::Channel& underlying_channel() { return m_channel; } + + void close() { m_channel.close(); } + + bool is_closed() const { return m_channel.is_closed(); } + + std::vector peer_cert_chain() const + { return m_channel.peer_cert_chain(); } + + virtual ~Blocking_Client() = default; + + protected: + /** + * Application can override to get the handshake complete notification + */ + virtual bool handshake_complete(const Session&) { return true; } + + /** + * Application can override to get notification of alerts + */ + virtual void alert_notification(const Alert&) {} + + private: + + bool handshake_cb(const Session&); + + void data_cb(const uint8_t data[], size_t data_len); + + void alert_cb(const Alert& alert); + + read_fn m_read; + std::unique_ptr m_callbacks; + TLS::Client m_channel; + secure_vector m_plaintext; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_callbacks.cpp b/comm/third_party/botan/src/lib/tls/tls_callbacks.cpp new file mode 100644 index 0000000000..0dd758b757 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_callbacks.cpp @@ -0,0 +1,191 @@ +/* +* TLS Callbacks +* (C) 2016 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_CURVE_25519) + #include +#endif + +namespace Botan { + +void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message&) + { + // default is no op + } + +std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector&) + { + return ""; + } + +std::string TLS::Callbacks::tls_peer_network_identity() + { + return ""; + } + +void TLS::Callbacks::tls_modify_extensions(Extensions&, Connection_Side) + { + } + +void TLS::Callbacks::tls_examine_extensions(const Extensions&, Connection_Side) + { + } + +std::string TLS::Callbacks::tls_decode_group_param(Group_Params group_param) + { + return group_param_to_string(group_param); + } + +void TLS::Callbacks::tls_verify_cert_chain( + const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Usage_Type usage, + const std::string& hostname, + const TLS::Policy& policy) + { + if(cert_chain.empty()) + throw Invalid_Argument("Certificate chain was empty"); + + Path_Validation_Restrictions restrictions(policy.require_cert_revocation_info(), + policy.minimum_signature_strength()); + + Path_Validation_Result result = + x509_path_validate(cert_chain, + restrictions, + trusted_roots, + (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""), + usage, + std::chrono::system_clock::now(), + tls_verify_cert_chain_ocsp_timeout(), + ocsp_responses); + + if(!result.successful_validation()) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, + "Certificate validation failure: " + result.result_string()); + } + } + +std::vector TLS::Callbacks::tls_sign_message( + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format, + const std::vector& msg) + { + PK_Signer signer(key, rng, emsa, format); + + return signer.sign_message(msg, rng); + } + +bool TLS::Callbacks::tls_verify_message( + const Public_Key& key, + const std::string& emsa, + Signature_Format format, + const std::vector& msg, + const std::vector& sig) + { + PK_Verifier verifier(key, emsa, format); + + return verifier.verify_message(msg, sig); + } + +std::pair, std::vector> TLS::Callbacks::tls_dh_agree( + const std::vector& modulus, + const std::vector& generator, + const std::vector& peer_public_value, + const Policy& policy, + RandomNumberGenerator& rng) + { + BigInt p = BigInt::decode(modulus); + BigInt g = BigInt::decode(generator); + BigInt Y = BigInt::decode(peer_public_value); + + /* + * A basic check for key validity. As we do not know q here we + * cannot check that Y is in the right subgroup. However since + * our key is ephemeral there does not seem to be any + * advantage to bogus keys anyway. + */ + if(Y <= 1 || Y >= p - 1) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Server sent bad DH key for DHE exchange"); + + DL_Group group(p, g); + + if(!group.verify_group(rng, false)) + throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, + "DH group validation failed"); + + DH_PublicKey peer_key(group, Y); + + policy.check_peer_key_acceptable(peer_key); + + DH_PrivateKey priv_key(rng, group); + PK_Key_Agreement ka(priv_key, rng, "Raw"); + secure_vector dh_secret = CT::strip_leading_zeros( + ka.derive_key(0, peer_key.public_value()).bits_of()); + + return std::make_pair(dh_secret, priv_key.public_value()); + } + +std::pair, std::vector> TLS::Callbacks::tls_ecdh_agree( + const std::string& curve_name, + const std::vector& peer_public_value, + const Policy& policy, + RandomNumberGenerator& rng, + bool compressed) + { + secure_vector ecdh_secret; + std::vector our_public_value; + + if(curve_name == "x25519") + { +#if defined(BOTAN_HAS_CURVE_25519) + if(peer_public_value.size() != 32) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid X25519 key size"); + } + + Curve25519_PublicKey peer_key(peer_public_value); + policy.check_peer_key_acceptable(peer_key); + Curve25519_PrivateKey priv_key(rng); + PK_Key_Agreement ka(priv_key, rng, "Raw"); + ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of(); + + // X25519 is always compressed but sent as "uncompressed" in TLS + our_public_value = priv_key.public_value(); +#else + throw Internal_Error("Negotiated X25519 somehow, but it is disabled"); +#endif + } + else + { + EC_Group group(OID::from_string(curve_name)); + ECDH_PublicKey peer_key(group, group.OS2ECP(peer_public_value)); + policy.check_peer_key_acceptable(peer_key); + ECDH_PrivateKey priv_key(rng, group); + PK_Key_Agreement ka(priv_key, rng, "Raw"); + ecdh_secret = ka.derive_key(0, peer_key.public_value()).bits_of(); + our_public_value = priv_key.public_value(compressed ? PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED); + } + + return std::make_pair(ecdh_secret, our_public_value); + } + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_callbacks.h b/comm/third_party/botan/src/lib/tls/tls_callbacks.h new file mode 100644 index 0000000000..995c02e2d4 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_callbacks.h @@ -0,0 +1,484 @@ +/* +* TLS Callbacks +* (C) 2016 Matthias Gierlings +* 2016 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_CALLBACKS_H_ +#define BOTAN_TLS_CALLBACKS_H_ + +#include +#include +#include +#include + +namespace Botan { + +class Certificate_Store; +class X509_Certificate; + +namespace OCSP { + +class Response; + +} + +namespace TLS { + +class Handshake_Message; +class Policy; +class Extensions; +class Certificate_Status_Request; + +/** +* Encapsulates the callbacks that a TLS channel will make which are due to +* channel specific operations. +*/ +class BOTAN_PUBLIC_API(2,0) Callbacks + { + public: + virtual ~Callbacks() = default; + + /** + * Mandatory callback: output function + * The channel will call this with data which needs to be sent to the peer + * (eg, over a socket or some other form of IPC). The array will be overwritten + * when the function returns so a copy must be made if the data cannot be + * sent immediately. + * + * @param data the vector of data to send + * + * @param size the number of bytes to send + */ + virtual void tls_emit_data(const uint8_t data[], size_t size) = 0; + + /** + * Mandatory callback: process application data + * Called when application data record is received from the peer. + * Again the array is overwritten immediately after the function returns. + * + * @param seq_no the underlying TLS/DTLS record sequence number + * + * @param data the vector containing the received record + * + * @param size the length of the received record, in bytes + */ + virtual void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) = 0; + + /** + * Mandatory callback: alert received + * Called when an alert is received from the peer + * If fatal, the connection is closing. If not fatal, the connection may + * still be closing (depending on the error and the peer). + * + * @param alert the source of the alert + */ + virtual void tls_alert(Alert alert) = 0; + + /** + * Mandatory callback: session established + * Called when a session is established. Throw an exception to abort + * the connection. + * + * @param session the session descriptor + * + * @return return false to prevent the session from being cached, + * return true to cache the session in the configured session manager + */ + virtual bool tls_session_established(const Session& session) = 0; + + /** + * Optional callback: session activated + * Called when a session is active and can be written to + */ + virtual void tls_session_activated() {} + + /** + * Optional callback with default impl: verify cert chain + * + * Default implementation performs a standard PKIX validation + * and initiates network OCSP request for end-entity cert. + * Override to provide different behavior. + * + * Check the certificate chain is valid up to a trusted root, and + * optionally (if hostname != "") that the hostname given is + * consistent with the leaf certificate. + * + * This function should throw an exception derived from + * std::exception with an informative what() result if the + * certificate chain cannot be verified. + * + * @param cert_chain specifies a certificate chain leading to a + * trusted root CA certificate. + * @param ocsp_responses the server may have provided some + * @param trusted_roots the list of trusted certificates + * @param usage what this cert chain is being used for + * Usage_Type::TLS_SERVER_AUTH for server chains, + * Usage_Type::TLS_CLIENT_AUTH for client chains, + * Usage_Type::UNSPECIFIED for other uses + * @param hostname when authenticating a server, this is the hostname + * the client requested (eg via SNI). When authenticating a client, + * this is the server name the client is authenticating *to*. + * Empty in other cases or if no hostname was used. + * @param policy the TLS policy associated with the session being authenticated + * using the certificate chain + */ + virtual void tls_verify_cert_chain( + const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Usage_Type usage, + const std::string& hostname, + const TLS::Policy& policy); + + /** + * Called by default `tls_verify_cert_chain` to get the timeout to use for OCSP + * requests. Return 0 to disable online OCSP checks. + * + * This function should not be "const" since the implementation might need + * to perform some side effecting operation to compute the result. + */ + virtual std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const + { + return std::chrono::milliseconds(0); + } + + /** + * Called by the TLS server whenever the client included the + * status_request extension (see RFC 6066, a.k.a OCSP stapling) + * in the ClientHello. + * + * @return the encoded OCSP response to be sent to the client which + * indicates the revocation status of the server certificate. Return an + * empty vector to indicate that no response is available, and thus + * suppress the Certificate_Status message. + */ + virtual std::vector tls_provide_cert_status(const std::vector& chain, + const Certificate_Status_Request& csr) + { + BOTAN_UNUSED(chain); + BOTAN_UNUSED(csr); + return std::vector(); + } + + /** + * Optional callback with default impl: sign a message + * + * Default implementation uses PK_Signer::sign_message(). + * Override to provide a different approach, e.g. using an external device. + * + * @param key the private key of the signer + * @param rng a random number generator + * @param emsa the encoding method to be applied to the message + * @param format the signature format + * @param msg the input data for the signature + * + * @return the signature + */ + virtual std::vector tls_sign_message( + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format, + const std::vector& msg); + + /** + * Optional callback with default impl: verify a message signature + * + * Default implementation uses PK_Verifier::verify_message(). + * Override to provide a different approach, e.g. using an external device. + * + * @param key the public key of the signer + * @param emsa the encoding method to be applied to the message + * @param format the signature format + * @param msg the input data for the signature + * @param sig the signature to be checked + * + * @return true if the signature is valid, false otherwise + */ + virtual bool tls_verify_message( + const Public_Key& key, + const std::string& emsa, + Signature_Format format, + const std::vector& msg, + const std::vector& sig); + + /** + * Optional callback with default impl: client side DH agreement + * + * Default implementation uses PK_Key_Agreement::derive_key(). + * Override to provide a different approach, e.g. using an external device. + * + * @param modulus the modulus p of the discrete logarithm group + * @param generator the generator of the DH subgroup + * @param peer_public_value the public value of the peer + * @param policy the TLS policy associated with the session being established + * @param rng a random number generator + * + * @return a pair consisting of the agreed raw secret and our public value + */ + virtual std::pair, std::vector> tls_dh_agree( + const std::vector& modulus, + const std::vector& generator, + const std::vector& peer_public_value, + const Policy& policy, + RandomNumberGenerator& rng); + + /** + * Optional callback with default impl: client side ECDH agreement + * + * Default implementation uses PK_Key_Agreement::derive_key(). + * Override to provide a different approach, e.g. using an external device. + * + * @param curve_name the name of the elliptic curve + * @param peer_public_value the public value of the peer + * @param policy the TLS policy associated with the session being established + * @param rng a random number generator + * @param compressed the compression preference for our public value + * + * @return a pair consisting of the agreed raw secret and our public value + */ + virtual std::pair, std::vector> tls_ecdh_agree( + const std::string& curve_name, + const std::vector& peer_public_value, + const Policy& policy, + RandomNumberGenerator& rng, + bool compressed); + + /** + * Optional callback: inspect handshake message + * Throw an exception to abort the handshake. + * Default simply ignores the message. + * + * @param message the handshake message + */ + virtual void tls_inspect_handshake_msg(const Handshake_Message& message); + + /** + * Optional callback for server: choose ALPN protocol + * ALPN (RFC 7301) works by the client sending a list of application + * protocols it is willing to negotiate. The server then selects which + * protocol to use, which is not necessarily even on the list that + * the client sent. + * + * @param client_protos the vector of protocols the client is willing to negotiate + * + * @return the protocol selected by the server, which need not be on the + * list that the client sent; if this is the empty string, the server ignores the + * client ALPN extension. Default return value is empty string. + */ + virtual std::string tls_server_choose_app_protocol(const std::vector& client_protos); + + /** + * Optional callback: examine/modify Extensions before sending. + * + * Both client and server will call this callback on the Extensions object + * before serializing it in the client/server hellos. This allows an + * application to modify which extensions are sent during the + * handshake. + * + * Default implementation does nothing. + * + * @param extn the extensions + * @param which_side will be CLIENT or SERVER which is the current + * applications role in the exchange. + */ + virtual void tls_modify_extensions(Extensions& extn, Connection_Side which_side); + + /** + * Optional callback: examine peer extensions. + * + * Both client and server will call this callback with the Extensions + * object after receiving it from the peer. This allows examining the + * Extensions, for example to implement a custom extension. It also allows + * an application to require that a particular extension be implemented; + * throw an exception from this function to abort the handshake. + * + * Default implementation does nothing. + * + * @param extn the extensions + * @param which_side will be CLIENT if these are are the clients extensions (ie we are + * the server) or SERVER if these are the server extensions (we are the client). + */ + virtual void tls_examine_extensions(const Extensions& extn, Connection_Side which_side); + + /** + * Optional callback: decode TLS group ID + * + * TLS uses a 16-bit field to identify ECC and DH groups. This callback + * handles the decoding. You only need to implement this if you are using + * a custom ECC or DH group (this is extremely uncommon). + * + * Default implementation uses the standard (IETF-defined) mappings. + */ + virtual std::string tls_decode_group_param(Group_Params group_param); + + /** + * Optional callback: return peer network identity + * + * There is no expected or specified format. The only expectation is this + * function will return a unique value. For example returning the peer + * host IP and port. + * + * This is used to bind the DTLS cookie to a particular network identity. + * It is only called if the dtls-cookie-secret PSK is also defined. + */ + virtual std::string tls_peer_network_identity(); + + /** + * Optional callback: error logging. (not currently called) + * @param err An error message related to this connection. + */ + virtual void tls_log_error(const char* err) + { + BOTAN_UNUSED(err); + } + + /** + * Optional callback: debug logging. (not currently called) + * @param what Some hopefully informative string + */ + virtual void tls_log_debug(const char* what) + { + BOTAN_UNUSED(what); + } + + /** + * Optional callback: debug logging taking a buffer. (not currently called) + * @param descr What this buffer is + * @param val the bytes + * @param val_len length of val + */ + virtual void tls_log_debug_bin(const char* descr, const uint8_t val[], size_t val_len) + { + BOTAN_UNUSED(descr, val, val_len); + } + }; + +/** +* TLS::Callbacks using std::function for compatability with the old API signatures. +* This type is only provided for backward compatibility. +* New implementations should derive from TLS::Callbacks instead. +*/ +class BOTAN_PUBLIC_API(2,0) Compat_Callbacks final : public Callbacks + { + public: + typedef std::function output_fn; + typedef std::function data_cb; + typedef std::function alert_cb; + typedef std::function handshake_cb; + typedef std::function handshake_msg_cb; + typedef std::function)> next_protocol_fn; + + /** + * @param data_output_fn is called with data for the outbound socket + * + * @param app_data_cb is called when new application data is received + * + * @param recv_alert_cb is called when a TLS alert is received + * + * @param hs_cb is called when a handshake is completed + * + * @param hs_msg_cb is called for each handshake message received + * + * @param next_proto is called with ALPN protocol data sent by the client + */ + BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).") + Compat_Callbacks(output_fn data_output_fn, data_cb app_data_cb, alert_cb recv_alert_cb, + handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr, + next_protocol_fn next_proto = nullptr) + : m_output_function(data_output_fn), m_app_data_cb(app_data_cb), + m_alert_cb(std::bind(recv_alert_cb, std::placeholders::_1, nullptr, 0)), + m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {} + + BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).") + Compat_Callbacks(output_fn data_output_fn, data_cb app_data_cb, + std::function recv_alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb = nullptr, + next_protocol_fn next_proto = nullptr) + : m_output_function(data_output_fn), m_app_data_cb(app_data_cb), + m_alert_cb(recv_alert_cb), + m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {} + + enum class SILENCE_DEPRECATION_WARNING { PLEASE = 0 }; + Compat_Callbacks(SILENCE_DEPRECATION_WARNING, + output_fn data_output_fn, data_cb app_data_cb, + std::function recv_alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb = nullptr, + next_protocol_fn next_proto = nullptr) + : m_output_function(data_output_fn), + m_app_data_cb(app_data_cb), + m_alert_cb(recv_alert_cb), + m_hs_cb(hs_cb), + m_hs_msg_cb(hs_msg_cb), + m_next_proto(next_proto) {} + + Compat_Callbacks(SILENCE_DEPRECATION_WARNING, + output_fn data_output_fn, data_cb app_data_cb, alert_cb recv_alert_cb, + handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr, + next_protocol_fn next_proto = nullptr) + : m_output_function(data_output_fn), m_app_data_cb(app_data_cb), + m_alert_cb(std::bind(recv_alert_cb, std::placeholders::_1, nullptr, 0)), + m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {} + + + void tls_emit_data(const uint8_t data[], size_t size) override + { + BOTAN_ASSERT(m_output_function != nullptr, + "Invalid TLS output function callback."); + m_output_function(data, size); + } + + void tls_record_received(uint64_t /*seq_no*/, const uint8_t data[], size_t size) override + { + BOTAN_ASSERT(m_app_data_cb != nullptr, + "Invalid TLS app data callback."); + m_app_data_cb(data, size); + } + + void tls_alert(Alert alert) override + { + BOTAN_ASSERT(m_alert_cb != nullptr, + "Invalid TLS alert callback."); + m_alert_cb(alert); + } + + bool tls_session_established(const Session& session) override + { + BOTAN_ASSERT(m_hs_cb != nullptr, + "Invalid TLS handshake callback."); + return m_hs_cb(session); + } + + std::string tls_server_choose_app_protocol(const std::vector& client_protos) override + { + if(m_next_proto != nullptr) { return m_next_proto(client_protos); } + return ""; + } + + void tls_inspect_handshake_msg(const Handshake_Message& hmsg) override + { + // The handshake message callback is optional so we can + // not assume it has been set. + if(m_hs_msg_cb != nullptr) { m_hs_msg_cb(hmsg); } + } + + private: + const output_fn m_output_function; + const data_cb m_app_data_cb; + const std::function m_alert_cb; + const handshake_cb m_hs_cb; + const handshake_msg_cb m_hs_msg_cb; + const next_protocol_fn m_next_proto; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_cbc/info.txt b/comm/third_party/botan/src/lib/tls/tls_cbc/info.txt new file mode 100644 index 0000000000..a1d2b18cce --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_cbc/info.txt @@ -0,0 +1,12 @@ + +TLS_CBC -> 20161008 + + + +tls_cbc.h + + + +cbc +hmac + diff --git a/comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.cpp b/comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.cpp new file mode 100644 index 0000000000..3e3e4c2df0 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.cpp @@ -0,0 +1,499 @@ +/* +* TLS CBC Record Handling +* (C) 2012,2013,2014,2015,2016,2020 Jack Lloyd +* (C) 2016 Juraj Somorovsky +* (C) 2016 Matthias Gierlings +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/* +* TLS_CBC_HMAC_AEAD_Mode Constructor +*/ +TLS_CBC_HMAC_AEAD_Mode::TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir dir, + std::unique_ptr cipher, + std::unique_ptr mac, + size_t cipher_keylen, + size_t mac_keylen, + Protocol_Version version, + bool use_encrypt_then_mac) : + m_cipher_name(cipher->name()), + m_mac_name(mac->name()), + m_cipher_keylen(cipher_keylen), + m_mac_keylen(mac_keylen), + m_use_encrypt_then_mac(use_encrypt_then_mac) + { + m_tag_size = mac->output_length(); + m_block_size = cipher->block_size(); + + m_iv_size = version.supports_explicit_cbc_ivs() ? m_block_size : 0; + + m_is_datagram = version.is_datagram_protocol(); + + m_mac = std::move(mac); + + if(dir == ENCRYPTION) + m_cbc.reset(new CBC_Encryption(cipher.release(), new Null_Padding)); + else + m_cbc.reset(new CBC_Decryption(cipher.release(), new Null_Padding)); + } + +void TLS_CBC_HMAC_AEAD_Mode::clear() + { + cbc().clear(); + mac().clear(); + reset(); + } + +void TLS_CBC_HMAC_AEAD_Mode::reset() + { + cbc_state().clear(); + m_ad.clear(); + m_msg.clear(); + } + +std::string TLS_CBC_HMAC_AEAD_Mode::name() const + { + return "TLS_CBC(" + m_cipher_name + "," + m_mac_name + ")"; + } + +size_t TLS_CBC_HMAC_AEAD_Mode::update_granularity() const + { + return 1; // just buffers anyway + } + +bool TLS_CBC_HMAC_AEAD_Mode::valid_nonce_length(size_t nl) const + { + if(m_cbc_state.empty()) + return nl == block_size(); + return nl == iv_size(); + } + +Key_Length_Specification TLS_CBC_HMAC_AEAD_Mode::key_spec() const + { + return Key_Length_Specification(m_cipher_keylen + m_mac_keylen); + } + +void TLS_CBC_HMAC_AEAD_Mode::key_schedule(const uint8_t key[], size_t keylen) + { + // Both keys are of fixed length specified by the ciphersuite + + if(keylen != m_cipher_keylen + m_mac_keylen) + throw Invalid_Key_Length(name(), keylen); + + mac().set_key(&key[0], m_mac_keylen); + cbc().set_key(&key[m_mac_keylen], m_cipher_keylen); + } + +void TLS_CBC_HMAC_AEAD_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + { + throw Invalid_IV_Length(name(), nonce_len); + } + + m_msg.clear(); + + if(nonce_len > 0) + { + m_cbc_state.assign(nonce, nonce + nonce_len); + } + } + +size_t TLS_CBC_HMAC_AEAD_Mode::process(uint8_t buf[], size_t sz) + { + m_msg.insert(m_msg.end(), buf, buf + sz); + return 0; + } + +std::vector TLS_CBC_HMAC_AEAD_Mode::assoc_data_with_len(uint16_t len) + { + std::vector ad = m_ad; + BOTAN_ASSERT(ad.size() == 13, "Expected AAD size"); + ad[11] = get_byte(0, len); + ad[12] = get_byte(1, len); + return ad; + } + +void TLS_CBC_HMAC_AEAD_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) + { + if(ad_len != 13) + throw Invalid_Argument("Invalid TLS AEAD associated data length"); + m_ad.assign(ad, ad + ad_len); + } + +void TLS_CBC_HMAC_AEAD_Encryption::set_associated_data(const uint8_t ad[], size_t ad_len) + { + TLS_CBC_HMAC_AEAD_Mode::set_associated_data(ad, ad_len); + + if(use_encrypt_then_mac()) + { + // AAD hack for EtM + // EtM uses ciphertext size instead of plaintext size for AEAD input + const uint16_t pt_size = make_uint16(assoc_data()[11], assoc_data()[12]); + const uint16_t enc_size = static_cast(round_up(iv_size() + pt_size + 1, block_size())); + assoc_data()[11] = get_byte(0, enc_size); + assoc_data()[12] = get_byte(1, enc_size); + } + } + +void TLS_CBC_HMAC_AEAD_Encryption::cbc_encrypt_record( + secure_vector& buffer, size_t offset, size_t padding_length) + { + // We always do short padding: + BOTAN_ASSERT_NOMSG(padding_length <= 16); + + buffer.resize(buffer.size() + padding_length); + + const uint8_t padding_val = static_cast(padding_length - 1); + + CT::poison(&padding_val, 1); + CT::poison(&padding_length, 1); + CT::poison(buffer.data(), buffer.size()); + + const size_t last_block_starts = buffer.size() - block_size(); + const size_t padding_starts = buffer.size() - padding_length; + for(size_t i = last_block_starts; i != buffer.size(); ++i) + { + auto add_padding = CT::Mask(CT::Mask::is_gte(i, padding_starts)); + buffer[i] = add_padding.select(padding_val, buffer[i]); + } + + CT::unpoison(padding_val); + CT::unpoison(padding_length); + CT::unpoison(buffer.data(), buffer.size()); + + cbc().start(cbc_state()); + cbc().process(&buffer[offset], buffer.size() - offset); + + cbc_state().assign(buffer.data() + (buffer.size() - block_size()), buffer.data() + buffer.size()); + } + +size_t TLS_CBC_HMAC_AEAD_Encryption::output_length(size_t input_length) const + { + return round_up(input_length + 1 + (use_encrypt_then_mac() ? 0 : tag_size()), block_size()) + + (use_encrypt_then_mac() ? tag_size() : 0); + } + +void TLS_CBC_HMAC_AEAD_Encryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + + const size_t msg_size = msg().size(); + + const size_t input_size = msg_size + 1 + (use_encrypt_then_mac() ? 0 : tag_size()); + const size_t enc_size = round_up(input_size, block_size()); + BOTAN_DEBUG_ASSERT(enc_size % block_size() == 0); + + const uint8_t padding_val = static_cast(enc_size - input_size); + const size_t padding_length = static_cast(padding_val) + 1; + + buffer.reserve(offset + msg_size + padding_length + tag_size()); + buffer.resize(offset + msg_size); + copy_mem(&buffer[offset], msg().data(), msg_size); + + mac().update(assoc_data()); + + if(use_encrypt_then_mac()) + { + if(iv_size() > 0) + { + mac().update(cbc_state()); + } + + cbc_encrypt_record(buffer, offset, padding_length); + mac().update(&buffer[offset], enc_size); + buffer.resize(buffer.size() + tag_size()); + mac().final(&buffer[buffer.size() - tag_size()]); + } + else + { + mac().update(&buffer[offset], msg_size); + buffer.resize(buffer.size() + tag_size()); + mac().final(&buffer[buffer.size() - tag_size()]); + cbc_encrypt_record(buffer, offset, padding_length); + } + } + +/* +* Checks the TLS padding. Returns 0 if the padding is invalid (we +* count the padding_length field as part of the padding size so a +* valid padding will always be at least one byte long), or the length +* of the padding otherwise. This is actually padding_length + 1 +* because both the padding and padding_length fields are padding from +* our perspective. +* +* Returning 0 in the error case should ensure the MAC check will fail. +* This approach is suggested in section 6.2.3.2 of RFC 5246. +*/ +uint16_t check_tls_cbc_padding(const uint8_t record[], size_t record_len) + { + if(record_len == 0 || record_len > 0xFFFF) + return 0; + + const uint16_t rec16 = static_cast(record_len); + + /* + * TLS v1.0 and up require all the padding bytes be the same value + * and allows up to 255 bytes. + */ + + const uint16_t to_check = std::min(256, static_cast(record_len)); + const uint8_t pad_byte = record[record_len-1]; + const uint16_t pad_bytes = 1 + pad_byte; + + auto pad_invalid = CT::Mask::is_lt(rec16, pad_bytes); + + for(uint16_t i = rec16 - to_check; i != rec16; ++i) + { + const uint16_t offset = rec16 - i; + const auto in_pad_range = CT::Mask::is_lte(offset, pad_bytes); + const auto pad_correct = CT::Mask::is_equal(record[i], pad_byte); + pad_invalid |= in_pad_range & ~pad_correct; + } + + return pad_invalid.if_not_set_return(pad_bytes); + } + +void TLS_CBC_HMAC_AEAD_Decryption::cbc_decrypt_record(uint8_t record_contents[], size_t record_len) + { + if(record_len == 0 || record_len % block_size() != 0) + throw Decoding_Error("Received TLS CBC ciphertext with invalid length"); + + cbc().start(cbc_state()); + cbc_state().assign(record_contents + record_len - block_size(), + record_contents + record_len); + + cbc().process(record_contents, record_len); + } + +size_t TLS_CBC_HMAC_AEAD_Decryption::output_length(size_t) const + { + /* + * We don't know this because the padding is arbitrary + */ + return 0; + } + +/* +* This function performs additional compression calls in order +* to protect from the Lucky 13 attack. It adds new compression +* function calls over dummy data, by computing additional HMAC updates. +* +* The countermeasure was described (in a similar way) in the Lucky 13 paper. +* +* Background: +* - One SHA-1/SHA-256 compression is performed with 64 bytes of data. +* - HMAC adds 8 byte length field and padding (at least 1 byte) so that we have: +* - 0 - 55 bytes: 1 compression +* - 56 - 55+64 bytes: 2 compressions +* - 56+64 - 55+2*64 bytes: 3 compressions ... +* - For SHA-384, this works similarly, but we have 128 byte blocks and 16 byte +* long length field. This results in: +* - 0 - 111 bytes: 1 compression +* - 112 - 111+128 bytes: 2 compressions ... +* +* The implemented countermeasure works as follows: +* 1) It computes max_compressions: number of maximum compressions performed on +* the decrypted data +* 2) It computes current_compressions: number of compressions performed on the +* decrypted data, after padding has been removed +* 3) If current_compressions != max_compressions: It invokes an HMAC update +* over dummy data so that (max_compressions - current_compressions) +* compressions are performed. Otherwise, it invokes an HMAC update so that +* no compressions are performed. +* +* Note that the padding validation in Botan is always performed over +* min(plen,256) bytes, see the function check_tls_cbc_padding. This differs +* from the countermeasure described in the paper. +* +* Note that the padding length padlen does also count the last byte +* of the decrypted plaintext. This is different from the Lucky 13 paper. +* +* This countermeasure leaves a difference of about 100 clock cycles (in +* comparison to >1000 clock cycles observed without it). +* +* plen represents the length of the decrypted plaintext message P +* padlen represents the padding length +* +*/ +void TLS_CBC_HMAC_AEAD_Decryption::perform_additional_compressions(size_t plen, size_t padlen) + { + uint16_t block_size; + uint16_t max_bytes_in_first_block; + if(mac().name() == "HMAC(SHA-384)") + { + block_size = 128; + max_bytes_in_first_block = 111; + } + else + { + block_size = 64; + max_bytes_in_first_block = 55; + } + // number of maximum MACed bytes + const uint16_t L1 = static_cast(13 + plen - tag_size()); + // number of current MACed bytes (L1 - padlen) + // Here the Lucky 13 paper is different because the padlen length in the paper + // does not count the last message byte. + const uint16_t L2 = static_cast(13 + plen - padlen - tag_size()); + // From the paper, for SHA-256/SHA-1 compute: ceil((L1-55)/64) and ceil((L2-55)/64) + // ceil((L1-55)/64) = floor((L1+64-1-55)/64) + // Here we compute number of compressions for SHA-* in general + const uint16_t max_compresssions = ( (L1 + block_size - 1 - max_bytes_in_first_block) / block_size); + const uint16_t current_compressions = ((L2 + block_size - 1 - max_bytes_in_first_block) / block_size); + // number of additional compressions we have to perform + const uint16_t add_compressions = max_compresssions - current_compressions; + const uint16_t equal = CT::Mask::is_equal(max_compresssions, current_compressions).if_set_return(1); + // We compute the data length we need to achieve the number of compressions. + // If there are no compressions, we just add 55/111 dummy bytes so that no + // compression is performed. + const uint16_t data_len = block_size * add_compressions + equal * max_bytes_in_first_block; + std::vector data(data_len); + mac().update(data); + // we do not need to clear the MAC since the connection is broken anyway + } + +void TLS_CBC_HMAC_AEAD_Decryption::finish(secure_vector& buffer, size_t offset) + { + update(buffer, offset); + buffer.resize(offset); + + const size_t record_len = msg().size(); + uint8_t* record_contents = msg().data(); + + // This early exit does not leak info because all the values compared are public + if(record_len < tag_size() || + (record_len - (use_encrypt_then_mac() ? tag_size() : 0)) % block_size() != 0) + { + throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); + } + + if(use_encrypt_then_mac()) + { + const size_t enc_size = record_len - tag_size(); + const size_t enc_iv_size = enc_size + iv_size(); + + BOTAN_ASSERT_NOMSG(enc_iv_size <= 0xFFFF); + + mac().update(assoc_data_with_len(static_cast(enc_iv_size))); + if(iv_size() > 0) + { + mac().update(cbc_state()); + } + mac().update(record_contents, enc_size); + + std::vector mac_buf(tag_size()); + mac().final(mac_buf.data()); + + const size_t mac_offset = enc_size; + + const bool mac_ok = constant_time_compare(&record_contents[mac_offset], mac_buf.data(), tag_size()); + + if(!mac_ok) + { + throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); + } + + cbc_decrypt_record(record_contents, enc_size); + + // 0 if padding was invalid, otherwise 1 + padding_bytes + const uint16_t pad_size = check_tls_cbc_padding(record_contents, enc_size); + + // No oracle here, whoever sent us this had the key since MAC check passed + if(pad_size == 0) + { + throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); + } + + const uint8_t* plaintext_block = &record_contents[0]; + const size_t plaintext_length = enc_size - pad_size; + + buffer.insert(buffer.end(), plaintext_block, plaintext_block + plaintext_length); + } + else + { + cbc_decrypt_record(record_contents, record_len); + + CT::poison(record_contents, record_len); + + // 0 if padding was invalid, otherwise 1 + padding_bytes + uint16_t pad_size = check_tls_cbc_padding(record_contents, record_len); + + /* + This mask is zero if there is not enough room in the packet to get a valid MAC. + + We have to accept empty packets, since otherwise we are not compatible + with how OpenSSL's countermeasure for fixing BEAST in TLS 1.0 CBC works + (sending empty records, instead of 1/(n-1) splitting) + */ + + // We know the cast cannot overflow as pad_size <= 256 && tag_size <= 32 + const auto size_ok_mask = CT::Mask::is_lte( + static_cast(tag_size() + pad_size), + static_cast(record_len)); + + pad_size = size_ok_mask.if_set_return(pad_size); + + CT::unpoison(record_contents, record_len); + + /* + This is unpoisoned sooner than it should. The pad_size leaks to plaintext_length and + then to the timing channel in the MAC computation described in the Lucky 13 paper. + */ + CT::unpoison(pad_size); + + const uint8_t* plaintext_block = &record_contents[0]; + const uint16_t plaintext_length = static_cast(record_len - tag_size() - pad_size); + + mac().update(assoc_data_with_len(plaintext_length)); + mac().update(plaintext_block, plaintext_length); + + std::vector mac_buf(tag_size()); + mac().final(mac_buf.data()); + + const size_t mac_offset = record_len - (tag_size() + pad_size); + + const bool mac_ok = constant_time_compare(&record_contents[mac_offset], mac_buf.data(), tag_size()); + + const auto ok_mask = size_ok_mask & CT::Mask::expand(mac_ok) & CT::Mask::expand(pad_size); + + CT::unpoison(ok_mask); + + if(ok_mask.is_set()) + { + buffer.insert(buffer.end(), plaintext_block, plaintext_block + plaintext_length); + } + else + { + perform_additional_compressions(record_len, pad_size); + + /* + * In DTLS case we have to finish computing the MAC since we require the + * MAC state be reset for future packets. This extra timing channel may + * be exploitable in a Lucky13 variant. + */ + if(is_datagram_protocol()) + mac().final(mac_buf); + throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); + } + } + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.h b/comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.h new file mode 100644 index 0000000000..9387142184 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_cbc/tls_cbc.h @@ -0,0 +1,186 @@ +/* +* TLS CBC+HMAC AEAD +* (C) 2016 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_CBC_HMAC_AEAD_H_ +#define BOTAN_TLS_CBC_HMAC_AEAD_H_ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS CBC+HMAC AEAD base class (GenericBlockCipher in TLS spec) +* This is the weird TLS-specific mode, not for general consumption. +*/ +class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Mode : public AEAD_Mode + { + public: + size_t process(uint8_t buf[], size_t sz) override final; + + std::string name() const override final; + + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + size_t update_granularity() const override final; + + Key_Length_Specification key_spec() const override final; + + bool valid_nonce_length(size_t nl) const override final; + + size_t tag_size() const override final { return m_tag_size; } + + size_t default_nonce_length() const override final { return m_iv_size; } + + void clear() override final; + + void reset() override final; + + protected: + TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir direction, + std::unique_ptr cipher, + std::unique_ptr mac, + size_t cipher_keylen, + size_t mac_keylen, + Protocol_Version version, + bool use_encrypt_then_mac); + + size_t cipher_keylen() const { return m_cipher_keylen; } + size_t mac_keylen() const { return m_mac_keylen; } + size_t iv_size() const { return m_iv_size; } + size_t block_size() const { return m_block_size; } + + bool use_encrypt_then_mac() const { return m_use_encrypt_then_mac; } + + bool is_datagram_protocol() const { return m_is_datagram; } + + Cipher_Mode& cbc() const { return *m_cbc; } + + MessageAuthenticationCode& mac() const + { + BOTAN_ASSERT_NONNULL(m_mac); + return *m_mac; + } + + secure_vector& cbc_state() { return m_cbc_state; } + std::vector& assoc_data() { return m_ad; } + secure_vector& msg() { return m_msg; } + + std::vector assoc_data_with_len(uint16_t len); + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override final; + + void key_schedule(const uint8_t key[], size_t length) override final; + + const std::string m_cipher_name; + const std::string m_mac_name; + size_t m_cipher_keylen; + size_t m_mac_keylen; + size_t m_iv_size; + size_t m_tag_size; + size_t m_block_size; + bool m_use_encrypt_then_mac; + bool m_is_datagram; + + std::unique_ptr m_cbc; + std::unique_ptr m_mac; + + secure_vector m_cbc_state; + std::vector m_ad; + secure_vector m_msg; + }; + +/** +* TLS_CBC_HMAC_AEAD Encryption +*/ +class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Encryption final : public TLS_CBC_HMAC_AEAD_Mode + { + public: + /** + */ + TLS_CBC_HMAC_AEAD_Encryption( + std::unique_ptr cipher, + std::unique_ptr mac, + const size_t cipher_keylen, + const size_t mac_keylen, + const Protocol_Version version, + bool use_encrypt_then_mac) : + TLS_CBC_HMAC_AEAD_Mode(ENCRYPTION, + std::move(cipher), + std::move(mac), + cipher_keylen, + mac_keylen, + version, + use_encrypt_then_mac) + {} + + void set_associated_data(const uint8_t ad[], size_t ad_len) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override { return 0; } + + void finish(secure_vector& final_block, size_t offset = 0) override; + private: + void cbc_encrypt_record(secure_vector& buffer, size_t offset, + size_t padding_length); + }; + +/** +* TLS_CBC_HMAC_AEAD Decryption +*/ +class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Decryption final : public TLS_CBC_HMAC_AEAD_Mode + { + public: + /** + */ + TLS_CBC_HMAC_AEAD_Decryption(std::unique_ptr cipher, + std::unique_ptr mac, + const size_t cipher_keylen, + const size_t mac_keylen, + const Protocol_Version version, + bool use_encrypt_then_mac) : + TLS_CBC_HMAC_AEAD_Mode(DECRYPTION, + std::move(cipher), + std::move(mac), + cipher_keylen, + mac_keylen, + version, + use_encrypt_then_mac) + {} + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override { return tag_size(); } + + void finish(secure_vector& final_block, size_t offset = 0) override; + + private: + void cbc_decrypt_record(uint8_t record_contents[], size_t record_len); + + void perform_additional_compressions(size_t plen, size_t padlen); + }; + +/** +* Check the TLS padding of a record +* @param record the record bits +* @param record_len length of record +* @return 0 if padding is invalid, otherwise padding_bytes + 1 +*/ +BOTAN_TEST_API uint16_t check_tls_cbc_padding(const uint8_t record[], size_t record_len); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_channel.cpp b/comm/third_party/botan/src/lib/tls/tls_channel.cpp new file mode 100644 index 0000000000..897fed97c6 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_channel.cpp @@ -0,0 +1,795 @@ +/* +* TLS Channels +* (C) 2011,2012,2014,2015,2016 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024; + +Channel::Channel(Callbacks& callbacks, + Session_Manager& session_manager, + RandomNumberGenerator& rng, + const Policy& policy, + bool is_server, + bool is_datagram, + size_t reserved_io_buffer_size) : + m_is_server(is_server), + m_is_datagram(is_datagram), + m_callbacks(callbacks), + m_session_manager(session_manager), + m_policy(policy), + m_rng(rng), + m_has_been_closed(false) + { + init(reserved_io_buffer_size); + } + +Channel::Channel(output_fn out, + data_cb app_data_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb, + Session_Manager& session_manager, + RandomNumberGenerator& rng, + const Policy& policy, + bool is_server, + bool is_datagram, + size_t io_buf_sz) : + m_is_server(is_server), + m_is_datagram(is_datagram), + m_compat_callbacks(new Compat_Callbacks( + /* + this Channel constructor is also deprecated so its ok that it + relies on a deprecated API + */ + Compat_Callbacks::SILENCE_DEPRECATION_WARNING::PLEASE, + out, app_data_cb, recv_alert_cb, hs_cb, hs_msg_cb)), + m_callbacks(*m_compat_callbacks.get()), + m_session_manager(session_manager), + m_policy(policy), + m_rng(rng), + m_has_been_closed(false) + { + init(io_buf_sz); + } + +void Channel::init(size_t io_buf_sz) + { + /* epoch 0 is plaintext, thus null cipher state */ + m_write_cipher_states[0] = nullptr; + m_read_cipher_states[0] = nullptr; + + m_writebuf.reserve(io_buf_sz); + m_readbuf.reserve(io_buf_sz); + } + +void Channel::reset_state() + { + m_active_state.reset(); + m_pending_state.reset(); + m_readbuf.clear(); + m_write_cipher_states.clear(); + m_read_cipher_states.clear(); + } + +void Channel::reset_active_association_state() + { + // This operation only makes sense for DTLS + BOTAN_ASSERT_NOMSG(m_is_datagram); + m_active_state.reset(); + m_read_cipher_states.clear(); + m_write_cipher_states.clear(); + + m_write_cipher_states[0] = nullptr; + m_read_cipher_states[0] = nullptr; + + if(m_sequence_numbers) + m_sequence_numbers->reset(); + } + +Channel::~Channel() + { + // So unique_ptr destructors run correctly + } + +Connection_Sequence_Numbers& Channel::sequence_numbers() const + { + BOTAN_ASSERT(m_sequence_numbers, "Have a sequence numbers object"); + return *m_sequence_numbers; + } + +std::shared_ptr Channel::read_cipher_state_epoch(uint16_t epoch) const + { + auto i = m_read_cipher_states.find(epoch); + if(i == m_read_cipher_states.end()) + throw Internal_Error("TLS::Channel No read cipherstate for epoch " + std::to_string(epoch)); + return i->second; + } + +std::shared_ptr Channel::write_cipher_state_epoch(uint16_t epoch) const + { + auto i = m_write_cipher_states.find(epoch); + if(i == m_write_cipher_states.end()) + throw Internal_Error("TLS::Channel No write cipherstate for epoch " + std::to_string(epoch)); + return i->second; + } + +std::vector Channel::peer_cert_chain() const + { + if(auto active = active_state()) + return get_peer_cert_chain(*active); + return std::vector(); + } + +bool Channel::save_session(const Session& session) + { + return callbacks().tls_session_established(session); + } + +Handshake_State& Channel::create_handshake_state(Protocol_Version version) + { + if(pending_state()) + throw Internal_Error("create_handshake_state called during handshake"); + + if(auto active = active_state()) + { + Protocol_Version active_version = active->version(); + + if(active_version.is_datagram_protocol() != version.is_datagram_protocol()) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Active state using version " + active_version.to_string() + + " cannot change to " + version.to_string() + " in pending"); + } + } + + if(!m_sequence_numbers) + { + if(version.is_datagram_protocol()) + m_sequence_numbers.reset(new Datagram_Sequence_Numbers); + else + m_sequence_numbers.reset(new Stream_Sequence_Numbers); + } + + using namespace std::placeholders; + + std::unique_ptr io; + if(version.is_datagram_protocol()) + { + io.reset(new Datagram_Handshake_IO( + std::bind(&Channel::send_record_under_epoch, this, _1, _2, _3), + sequence_numbers(), + static_cast(m_policy.dtls_default_mtu()), + m_policy.dtls_initial_timeout(), + m_policy.dtls_maximum_timeout())); + } + else + { + io.reset(new Stream_Handshake_IO(std::bind(&Channel::send_record, this, _1, _2))); + } + + m_pending_state.reset(new_handshake_state(io.release())); + + if(auto active = active_state()) + m_pending_state->set_version(active->version()); + + return *m_pending_state.get(); + } + +bool Channel::timeout_check() + { + if(m_pending_state) + return m_pending_state->handshake_io().timeout_check(); + + //FIXME: scan cipher suites and remove epochs older than 2*MSL + return false; + } + +void Channel::renegotiate(bool force_full_renegotiation) + { + if(pending_state()) // currently in handshake? + return; + + if(auto active = active_state()) + { + if(force_full_renegotiation == false) + force_full_renegotiation = !policy().allow_resumption_for_renegotiation(); + + initiate_handshake(create_handshake_state(active->version()), + force_full_renegotiation); + } + else + throw Invalid_State("Cannot renegotiate on inactive connection"); + } + +void Channel::change_cipher_spec_reader(Connection_Side side) + { + auto pending = pending_state(); + + BOTAN_ASSERT(pending && pending->server_hello(), + "Have received server hello"); + + if(pending->server_hello()->compression_method() != 0) + throw Internal_Error("Negotiated unknown compression algorithm"); + + sequence_numbers().new_read_cipher_state(); + + const uint16_t epoch = sequence_numbers().current_read_epoch(); + + BOTAN_ASSERT(m_read_cipher_states.count(epoch) == 0, + "No read cipher state currently set for next epoch"); + + // flip side as we are reading + std::shared_ptr read_state( + new Connection_Cipher_State(pending->version(), + (side == CLIENT) ? SERVER : CLIENT, + false, + pending->ciphersuite(), + pending->session_keys(), + pending->server_hello()->supports_encrypt_then_mac())); + + m_read_cipher_states[epoch] = read_state; + } + +void Channel::change_cipher_spec_writer(Connection_Side side) + { + auto pending = pending_state(); + + BOTAN_ASSERT(pending && pending->server_hello(), + "Have received server hello"); + + if(pending->server_hello()->compression_method() != 0) + throw Internal_Error("Negotiated unknown compression algorithm"); + + sequence_numbers().new_write_cipher_state(); + + const uint16_t epoch = sequence_numbers().current_write_epoch(); + + BOTAN_ASSERT(m_write_cipher_states.count(epoch) == 0, + "No write cipher state currently set for next epoch"); + + std::shared_ptr write_state( + new Connection_Cipher_State(pending->version(), + side, + true, + pending->ciphersuite(), + pending->session_keys(), + pending->server_hello()->supports_encrypt_then_mac())); + + m_write_cipher_states[epoch] = write_state; + } + +bool Channel::is_active() const + { + if(is_closed()) + return false; + return (active_state() != nullptr); + } + +bool Channel::is_closed() const + { + return m_has_been_closed; + } + +void Channel::activate_session() + { + std::swap(m_active_state, m_pending_state); + m_pending_state.reset(); + + if(!m_active_state->version().is_datagram_protocol()) + { + // TLS is easy just remove all but the current state + const uint16_t current_epoch = sequence_numbers().current_write_epoch(); + + const auto not_current_epoch = + [current_epoch](uint16_t epoch) { return (epoch != current_epoch); }; + + map_remove_if(not_current_epoch, m_write_cipher_states); + map_remove_if(not_current_epoch, m_read_cipher_states); + } + + callbacks().tls_session_activated(); + } + +size_t Channel::received_data(const std::vector& buf) + { + return this->received_data(buf.data(), buf.size()); + } + +size_t Channel::received_data(const uint8_t input[], size_t input_size) + { + const bool allow_epoch0_restart = m_is_datagram && m_is_server && policy().allow_dtls_epoch0_restart(); + + try + { + while(input_size) + { + size_t consumed = 0; + + auto get_epoch = [this](uint16_t epoch) { return read_cipher_state_epoch(epoch); }; + + const Record_Header record = + read_record(m_is_datagram, + m_readbuf, + input, + input_size, + consumed, + m_record_buf, + m_sequence_numbers.get(), + get_epoch, + allow_epoch0_restart); + + const size_t needed = record.needed(); + + BOTAN_ASSERT(consumed > 0, "Got to eat something"); + + BOTAN_ASSERT(consumed <= input_size, + "Record reader consumed sane amount"); + + input += consumed; + input_size -= consumed; + + BOTAN_ASSERT(input_size == 0 || needed == 0, + "Got a full record or consumed all input"); + + if(input_size == 0 && needed != 0) + return needed; // need more data to complete record + + // Ignore invalid records in DTLS + if(m_is_datagram && record.type() == NO_RECORD) + { + return 0; + } + + if(m_record_buf.size() > MAX_PLAINTEXT_SIZE) + throw TLS_Exception(Alert::RECORD_OVERFLOW, + "TLS plaintext record is larger than allowed maximum"); + + + const bool epoch0_restart = m_is_datagram && record.epoch() == 0 && active_state(); + BOTAN_ASSERT_IMPLICATION(epoch0_restart, allow_epoch0_restart, "Allowed state"); + + const bool initial_record = epoch0_restart || (!pending_state() && !active_state()); + + if(record.type() != ALERT) + { + if(initial_record) + { + // For initial records just check for basic sanity + if(record.version().major_version() != 3 && + record.version().major_version() != 0xFE) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Received unexpected record version in initial record"); + } + } + else if(auto pending = pending_state()) + { + if(pending->server_hello() != nullptr && record.version() != pending->version()) + { + if(record.version() != pending->version()) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Received unexpected record version"); + } + } + } + else if(auto active = active_state()) + { + if(record.version() != active->version()) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Received unexpected record version"); + } + } + } + + if(record.type() == HANDSHAKE || record.type() == CHANGE_CIPHER_SPEC) + { + if(m_has_been_closed) + throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Received handshake data after connection closure"); + process_handshake_ccs(m_record_buf, record.sequence(), record.type(), record.version(), epoch0_restart); + } + else if(record.type() == APPLICATION_DATA) + { + if(m_has_been_closed) + throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Received application data after connection closure"); + if(pending_state() != nullptr) + throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, "Can't interleave application and handshake data"); + process_application_data(record.sequence(), m_record_buf); + } + else if(record.type() == ALERT) + { + process_alert(m_record_buf); + } + else if(record.type() != NO_RECORD) + throw Unexpected_Message("Unexpected record type " + + std::to_string(record.type()) + + " from counterparty"); + } + + return 0; // on a record boundary + } + catch(TLS_Exception& e) + { + send_fatal_alert(e.type()); + throw; + } + catch(Invalid_Authentication_Tag&) + { + send_fatal_alert(Alert::BAD_RECORD_MAC); + throw; + } + catch(Decoding_Error&) + { + send_fatal_alert(Alert::DECODE_ERROR); + throw; + } + catch(...) + { + send_fatal_alert(Alert::INTERNAL_ERROR); + throw; + } + } + +void Channel::process_handshake_ccs(const secure_vector& record, + uint64_t record_sequence, + Record_Type record_type, + Protocol_Version record_version, + bool epoch0_restart) + { + if(!m_pending_state) + { + // No pending handshake, possibly new: + if(record_version.is_datagram_protocol() && !epoch0_restart) + { + if(m_sequence_numbers) + { + /* + * Might be a peer retransmit under epoch - 1 in which + * case we must retransmit last flight + */ + sequence_numbers().read_accept(record_sequence); + + const uint16_t epoch = record_sequence >> 48; + + if(epoch == sequence_numbers().current_read_epoch()) + { + create_handshake_state(record_version); + } + else if(epoch == sequence_numbers().current_read_epoch() - 1) + { + BOTAN_ASSERT(m_active_state, "Have active state here"); + m_active_state->handshake_io().add_record(record.data(), + record.size(), + record_type, + record_sequence); + } + } + else + { + create_handshake_state(record_version); + } + } + else + { + create_handshake_state(record_version); + } + } + + // May have been created in above conditional + if(m_pending_state) + { + m_pending_state->handshake_io().add_record(record.data(), + record.size(), + record_type, + record_sequence); + + while(auto pending = m_pending_state.get()) + { + auto msg = pending->get_next_handshake_msg(); + + if(msg.first == HANDSHAKE_NONE) // no full handshake yet + break; + + process_handshake_msg(active_state(), *pending, + msg.first, msg.second, epoch0_restart); + + if(!m_pending_state) + break; + } + } + } + +void Channel::process_application_data(uint64_t seq_no, const secure_vector& record) + { + if(!active_state()) + throw Unexpected_Message("Application data before handshake done"); + + callbacks().tls_record_received(seq_no, record.data(), record.size()); + } + +void Channel::process_alert(const secure_vector& record) + { + Alert alert_msg(record); + + if(alert_msg.type() == Alert::NO_RENEGOTIATION) + m_pending_state.reset(); + + callbacks().tls_alert(alert_msg); + + if(alert_msg.is_fatal()) + { + if(auto active = active_state()) + m_session_manager.remove_entry(active->server_hello()->session_id()); + } + + if(alert_msg.type() == Alert::CLOSE_NOTIFY) + send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind + + if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal()) + { + m_has_been_closed = true; + } + } + +void Channel::write_record(Connection_Cipher_State* cipher_state, uint16_t epoch, + uint8_t record_type, const uint8_t input[], size_t length) + { + BOTAN_ASSERT(m_pending_state || m_active_state, "Some connection state exists"); + + const Protocol_Version record_version = + (m_pending_state) ? (m_pending_state->version()) : (m_active_state->version()); + + const uint64_t next_seq = sequence_numbers().next_write_sequence(epoch); + + if(cipher_state == nullptr) + { + TLS::write_unencrypted_record(m_writebuf, record_type, record_version, next_seq, + input, length); + } + else + { + TLS::write_record(m_writebuf, record_type, record_version, next_seq, + input, length, *cipher_state, m_rng); + } + + callbacks().tls_emit_data(m_writebuf.data(), m_writebuf.size()); + } + +void Channel::send_record_array(uint16_t epoch, uint8_t type, const uint8_t input[], size_t length) + { + if(length == 0) + return; + + /* + * In versions without an explicit IV field (only TLS v1.0 now that + * SSLv3 has been removed) send a single byte record first to randomize + * the following (implicit) IV of the following record. + * + * This isn't needed in TLS v1.1 or higher. + * + * An empty record also works but apparently some implementations do + * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814) + * + * See https://www.openssl.org/~bodo/tls-cbc.txt for background. + */ + + auto cipher_state = write_cipher_state_epoch(epoch); + + if(type == APPLICATION_DATA && m_active_state->version().supports_explicit_cbc_ivs() == false) + { + while(length) + { + write_record(cipher_state.get(), epoch, type, input, 1); + input += 1; + length -= 1; + + const size_t sending = std::min(length, MAX_PLAINTEXT_SIZE); + write_record(cipher_state.get(), epoch, type, input, sending); + + input += sending; + length -= sending; + } + } + else + { + while(length) + { + const size_t sending = std::min(length, MAX_PLAINTEXT_SIZE); + write_record(cipher_state.get(), epoch, type, input, sending); + + input += sending; + length -= sending; + } + } + } + +void Channel::send_record(uint8_t record_type, const std::vector& record) + { + send_record_array(sequence_numbers().current_write_epoch(), + record_type, record.data(), record.size()); + } + +void Channel::send_record_under_epoch(uint16_t epoch, uint8_t record_type, + const std::vector& record) + { + send_record_array(epoch, record_type, record.data(), record.size()); + } + +void Channel::send(const uint8_t buf[], size_t buf_size) + { + if(!is_active()) + throw Invalid_State("Data cannot be sent on inactive TLS connection"); + + send_record_array(sequence_numbers().current_write_epoch(), + APPLICATION_DATA, buf, buf_size); + } + +void Channel::send(const std::string& string) + { + this->send(cast_char_ptr_to_uint8(string.data()), string.size()); + } + +void Channel::send_alert(const Alert& alert) + { + if(alert.is_valid() && !is_closed()) + { + try + { + send_record(ALERT, alert.serialize()); + } + catch(...) { /* swallow it */ } + } + + if(alert.type() == Alert::NO_RENEGOTIATION) + m_pending_state.reset(); + + if(alert.is_fatal()) + { + if(auto active = active_state()) + { + m_session_manager.remove_entry(active->server_hello()->session_id()); + } + reset_state(); + } + + if(alert.type() == Alert::CLOSE_NOTIFY || alert.is_fatal()) + { + m_has_been_closed = true; + } + } + +void Channel::secure_renegotiation_check(const Client_Hello* client_hello) + { + const bool secure_renegotiation = client_hello->secure_renegotiation(); + + if(auto active = active_state()) + { + const bool active_sr = active->client_hello()->secure_renegotiation(); + + if(active_sr != secure_renegotiation) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client changed its mind about secure renegotiation"); + } + + if(secure_renegotiation) + { + const std::vector& data = client_hello->renegotiation_info(); + + if(data != secure_renegotiation_data_for_client_hello()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client sent bad values for secure renegotiation"); + } + } + +void Channel::secure_renegotiation_check(const Server_Hello* server_hello) + { + const bool secure_renegotiation = server_hello->secure_renegotiation(); + + if(auto active = active_state()) + { + const bool active_sr = active->server_hello()->secure_renegotiation(); + + if(active_sr != secure_renegotiation) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server changed its mind about secure renegotiation"); + } + + if(secure_renegotiation) + { + const std::vector& data = server_hello->renegotiation_info(); + + if(data != secure_renegotiation_data_for_server_hello()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent bad values for secure renegotiation"); + } + } + +std::vector Channel::secure_renegotiation_data_for_client_hello() const + { + if(auto active = active_state()) + return active->client_finished()->verify_data(); + return std::vector(); + } + +std::vector Channel::secure_renegotiation_data_for_server_hello() const + { + if(auto active = active_state()) + { + std::vector buf = active->client_finished()->verify_data(); + buf += active->server_finished()->verify_data(); + return buf; + } + + return std::vector(); + } + +bool Channel::secure_renegotiation_supported() const + { + if(auto active = active_state()) + return active->server_hello()->secure_renegotiation(); + + if(auto pending = pending_state()) + if(auto hello = pending->server_hello()) + return hello->secure_renegotiation(); + + return false; + } + +SymmetricKey Channel::key_material_export(const std::string& label, + const std::string& context, + size_t length) const + { + if(auto active = active_state()) + { + if(pending_state() != nullptr) + throw Invalid_State("Channel::key_material_export cannot export during renegotiation"); + + std::unique_ptr prf(active->protocol_specific_prf()); + + const secure_vector& master_secret = + active->session_keys().master_secret(); + + std::vector salt; + salt += active->client_hello()->random(); + salt += active->server_hello()->random(); + + if(context != "") + { + size_t context_size = context.length(); + if(context_size > 0xFFFF) + throw Invalid_Argument("key_material_export context is too long"); + salt.push_back(get_byte(0, static_cast(context_size))); + salt.push_back(get_byte(1, static_cast(context_size))); + salt += to_byte_vector(context); + } + + return prf->derive_key(length, master_secret, salt, to_byte_vector(label)); + } + else + { + throw Invalid_State("Channel::key_material_export connection not active"); + } + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_channel.h b/comm/third_party/botan/src/lib/tls/tls_channel.h new file mode 100644 index 0000000000..046560e228 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_channel.h @@ -0,0 +1,318 @@ +/* +* TLS Channel +* (C) 2011,2012,2014,2015 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_CHANNEL_H_ +#define BOTAN_TLS_CHANNEL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Connection_Cipher_State; +class Connection_Sequence_Numbers; +class Handshake_State; +class Handshake_Message; +class Client_Hello; +class Server_Hello; +class Policy; + +/** +* Generic interface for TLS endpoint +*/ +class BOTAN_PUBLIC_API(2,0) Channel + { + public: + typedef std::function output_fn; + typedef std::function data_cb; + typedef std::function alert_cb; + typedef std::function handshake_cb; + typedef std::function handshake_msg_cb; + static size_t IO_BUF_DEFAULT_SIZE; + + /** + * Set up a new TLS session + * + * @param callbacks contains a set of callback function references + * required by the TLS endpoint. + * @param session_manager manages session state + * @param rng a random number generator + * @param policy specifies other connection policy information + * @param is_server whether this is a server session or not + * @param is_datagram whether this is a DTLS session + * @param io_buf_sz This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. + */ + Channel(Callbacks& callbacks, + Session_Manager& session_manager, + RandomNumberGenerator& rng, + const Policy& policy, + bool is_server, + bool is_datagram, + size_t io_buf_sz = IO_BUF_DEFAULT_SIZE); + + /** + * DEPRECATED. This constructor is only provided for backward + * compatibility and should not be used in new implementations. + * (Not marked deprecated since it is only called internally, by + * other deprecated constructors) + */ + Channel(output_fn out, + data_cb app_data_cb, + alert_cb alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb, + Session_Manager& session_manager, + RandomNumberGenerator& rng, + const Policy& policy, + bool is_server, + bool is_datagram, + size_t io_buf_sz = IO_BUF_DEFAULT_SIZE); + + Channel(const Channel&) = delete; + + Channel& operator=(const Channel&) = delete; + + virtual ~Channel(); + + /** + * Inject TLS traffic received from counterparty + * @return a hint as the how many more bytes we need to process the + * current record (this may be 0 if on a record boundary) + */ + size_t received_data(const uint8_t buf[], size_t buf_size); + + /** + * Inject TLS traffic received from counterparty + * @return a hint as the how many more bytes we need to process the + * current record (this may be 0 if on a record boundary) + */ + size_t received_data(const std::vector& buf); + + /** + * Inject plaintext intended for counterparty + * Throws an exception if is_active() is false + */ + void send(const uint8_t buf[], size_t buf_size); + + /** + * Inject plaintext intended for counterparty + * Throws an exception if is_active() is false + */ + void send(const std::string& val); + + /** + * Inject plaintext intended for counterparty + * Throws an exception if is_active() is false + */ + template + void send(const std::vector& val) + { + send(val.data(), val.size()); + } + + /** + * Send a TLS alert message. If the alert is fatal, the internal + * state (keys, etc) will be reset. + * @param alert the Alert to send + */ + void send_alert(const Alert& alert); + + /** + * Send a warning alert + */ + void send_warning_alert(Alert::Type type) { send_alert(Alert(type, false)); } + + /** + * Send a fatal alert + */ + void send_fatal_alert(Alert::Type type) { send_alert(Alert(type, true)); } + + /** + * Send a close notification alert + */ + void close() { send_warning_alert(Alert::CLOSE_NOTIFY); } + + /** + * @return true iff the connection is active for sending application data + */ + bool is_active() const; + + /** + * @return true iff the connection has been definitely closed + */ + bool is_closed() const; + + /** + * @return certificate chain of the peer (may be empty) + */ + std::vector peer_cert_chain() const; + + /** + * Key material export (RFC 5705) + * @param label a disambiguating label string + * @param context a per-association context value + * @param length the length of the desired key in bytes + * @return key of length bytes + */ + SymmetricKey key_material_export(const std::string& label, + const std::string& context, + size_t length) const; + + /** + * Attempt to renegotiate the session + * @param force_full_renegotiation if true, require a full renegotiation, + * otherwise allow session resumption + */ + void renegotiate(bool force_full_renegotiation = false); + + /** + * @return true iff the counterparty supports the secure + * renegotiation extensions. + */ + bool secure_renegotiation_supported() const; + + /** + * Perform a handshake timeout check. This does nothing unless + * this is a DTLS channel with a pending handshake state, in + * which case we check for timeout and potentially retransmit + * handshake packets. + */ + bool timeout_check(); + + virtual std::string application_protocol() const = 0; + + protected: + + virtual void process_handshake_msg(const Handshake_State* active_state, + Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents, + bool epoch0_restart) = 0; + + virtual void initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) = 0; + + virtual std::vector + get_peer_cert_chain(const Handshake_State& state) const = 0; + + virtual Handshake_State* new_handshake_state(class Handshake_IO* io) = 0; + + Handshake_State& create_handshake_state(Protocol_Version version); + + void inspect_handshake_message(const Handshake_Message& msg); + + void activate_session(); + + void change_cipher_spec_reader(Connection_Side side); + + void change_cipher_spec_writer(Connection_Side side); + + /* secure renegotiation handling */ + + void secure_renegotiation_check(const Client_Hello* client_hello); + void secure_renegotiation_check(const Server_Hello* server_hello); + + std::vector secure_renegotiation_data_for_client_hello() const; + std::vector secure_renegotiation_data_for_server_hello() const; + + RandomNumberGenerator& rng() { return m_rng; } + + Session_Manager& session_manager() { return m_session_manager; } + + const Policy& policy() const { return m_policy; } + + bool save_session(const Session& session); + + Callbacks& callbacks() const { return m_callbacks; } + + void reset_active_association_state(); + + private: + void init(size_t io_buf_sze); + + void send_record(uint8_t record_type, const std::vector& record); + + void send_record_under_epoch(uint16_t epoch, uint8_t record_type, + const std::vector& record); + + void send_record_array(uint16_t epoch, uint8_t record_type, + const uint8_t input[], size_t length); + + void write_record(Connection_Cipher_State* cipher_state, + uint16_t epoch, uint8_t type, const uint8_t input[], size_t length); + + void reset_state(); + + Connection_Sequence_Numbers& sequence_numbers() const; + + std::shared_ptr read_cipher_state_epoch(uint16_t epoch) const; + + std::shared_ptr write_cipher_state_epoch(uint16_t epoch) const; + + const Handshake_State* active_state() const { return m_active_state.get(); } + + const Handshake_State* pending_state() const { return m_pending_state.get(); } + + /* methods to handle incoming traffic through Channel::receive_data. */ + void process_handshake_ccs(const secure_vector& record, + uint64_t record_sequence, + Record_Type record_type, + Protocol_Version record_version, + bool epoch0_restart); + + void process_application_data(uint64_t req_no, const secure_vector& record); + + void process_alert(const secure_vector& record); + + const bool m_is_server; + const bool m_is_datagram; + + /* callbacks */ + std::unique_ptr m_compat_callbacks; + Callbacks& m_callbacks; + + /* external state */ + Session_Manager& m_session_manager; + const Policy& m_policy; + RandomNumberGenerator& m_rng; + + /* sequence number state */ + std::unique_ptr m_sequence_numbers; + + /* pending and active connection states */ + std::unique_ptr m_active_state; + std::unique_ptr m_pending_state; + + /* cipher states for each epoch */ + std::map> m_write_cipher_states; + std::map> m_read_cipher_states; + + /* I/O buffers */ + secure_vector m_writebuf; + secure_vector m_readbuf; + secure_vector m_record_buf; + + bool m_has_been_closed; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp b/comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp new file mode 100644 index 0000000000..cf284e5650 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp @@ -0,0 +1,253 @@ +/* +* TLS Cipher Suite +* (C) 2004-2010,2012,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +size_t Ciphersuite::nonce_bytes_from_handshake() const + { + switch(m_nonce_format) + { + case Nonce_Format::CBC_MODE: + { + if(cipher_algo() == "3DES") + return 8; + else + return 16; + } + case Nonce_Format::AEAD_IMPLICIT_4: + return 4; + case Nonce_Format::AEAD_XOR_12: + return 12; + } + + throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); + } + +size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const + { + switch(m_nonce_format) + { + case Nonce_Format::CBC_MODE: + { + if(version.supports_explicit_cbc_ivs()) + { + return cipher_algo() == "3DES" ? 8 : 16; + } + else + { + return 0; + } + } + case Nonce_Format::AEAD_IMPLICIT_4: + return 8; + case Nonce_Format::AEAD_XOR_12: + return 0; + } + + throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); + } + +bool Ciphersuite::is_scsv(uint16_t suite) + { + // TODO: derive from IANA file in script + return (suite == 0x00FF || suite == 0x5600); + } + +bool Ciphersuite::psk_ciphersuite() const + { + return kex_method() == Kex_Algo::PSK || + kex_method() == Kex_Algo::DHE_PSK || + kex_method() == Kex_Algo::ECDHE_PSK; + } + +bool Ciphersuite::ecc_ciphersuite() const + { + return kex_method() == Kex_Algo::ECDH || + kex_method() == Kex_Algo::ECDHE_PSK || + auth_method() == Auth_Method::ECDSA; + } + +bool Ciphersuite::usable_in_version(Protocol_Version version) const + { + if(!version.supports_aead_modes()) + { + // Old versions do not support AEAD, or any MAC but SHA-1 + if(mac_algo() != "SHA-1") + return false; + } + + return true; + } + +bool Ciphersuite::cbc_ciphersuite() const + { + return (mac_algo() != "AEAD"); + } + +bool Ciphersuite::signature_used() const + { + return auth_method() != Auth_Method::ANONYMOUS && + auth_method() != Auth_Method::IMPLICIT; + } + +Ciphersuite Ciphersuite::by_id(uint16_t suite) + { + const std::vector& all_suites = all_known_ciphersuites(); + auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite); + + if(s != all_suites.end() && s->ciphersuite_code() == suite) + { + return *s; + } + + return Ciphersuite(); // some unknown ciphersuite + } + +Ciphersuite Ciphersuite::from_name(const std::string& name) + { + const std::vector& all_suites = all_known_ciphersuites(); + + for(auto suite : all_suites) + { + if(suite.to_string() == name) + return suite; + } + + return Ciphersuite(); // some unknown ciphersuite + } + +namespace { + +bool have_hash(const std::string& prf) + { + return (HashFunction::providers(prf).size() > 0); + } + +bool have_cipher(const std::string& cipher) + { + return (BlockCipher::providers(cipher).size() > 0) || + (StreamCipher::providers(cipher).size() > 0); + } + +} + +bool Ciphersuite::is_usable() const + { + if(!m_cipher_keylen) // uninitialized object + return false; + + if(!have_hash(prf_algo())) + return false; + +#if !defined(BOTAN_HAS_TLS_CBC) + if(cbc_ciphersuite()) + return false; +#endif + + if(mac_algo() == "AEAD") + { + if(cipher_algo() == "ChaCha20Poly1305") + { +#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) + return false; +#endif + } + else + { + auto cipher_and_mode = split_on(cipher_algo(), '/'); + BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); + if(!have_cipher(cipher_and_mode[0])) + return false; + + const auto mode = cipher_and_mode[1]; + +#if !defined(BOTAN_HAS_AEAD_CCM) + if(mode == "CCM" || mode == "CCM-8") + return false; +#endif + +#if !defined(BOTAN_HAS_AEAD_GCM) + if(mode == "GCM") + return false; +#endif + +#if !defined(BOTAN_HAS_AEAD_OCB) + if(mode == "OCB(12)" || mode == "OCB") + return false; +#endif + } + } + else + { + // Old non-AEAD schemes + if(!have_cipher(cipher_algo())) + return false; + if(!have_hash(mac_algo())) // HMAC + return false; + } + + if(kex_method() == Kex_Algo::SRP_SHA) + { +#if !defined(BOTAN_HAS_SRP6) + return false; +#endif + } + else if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK) + { +#if !defined(BOTAN_HAS_ECDH) + return false; +#endif + } + else if(kex_method() == Kex_Algo::DH || kex_method() == Kex_Algo::DHE_PSK) + { +#if !defined(BOTAN_HAS_DIFFIE_HELLMAN) + return false; +#endif + } + else if(kex_method() == Kex_Algo::CECPQ1) + { +#if !defined(BOTAN_HAS_CECPQ1) + return false; +#endif + } + + if(auth_method() == Auth_Method::DSA) + { +#if !defined(BOTAN_HAS_DSA) + return false; +#endif + } + else if(auth_method() == Auth_Method::ECDSA) + { +#if !defined(BOTAN_HAS_ECDSA) + return false; +#endif + } + else if(auth_method() == Auth_Method::RSA) + { +#if !defined(BOTAN_HAS_RSA) + return false; +#endif + } + + return true; + } + +} + +} + diff --git a/comm/third_party/botan/src/lib/tls/tls_ciphersuite.h b/comm/third_party/botan/src/lib/tls/tls_ciphersuite.h new file mode 100644 index 0000000000..1d23a6c4a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_ciphersuite.h @@ -0,0 +1,189 @@ +/* +* TLS Cipher Suites +* (C) 2004-2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_CIPHER_SUITES_H_ +#define BOTAN_TLS_CIPHER_SUITES_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Ciphersuite Information +*/ +class BOTAN_PUBLIC_API(2,0) Ciphersuite final + { + public: + /** + * Convert an SSL/TLS ciphersuite to algorithm fields + * @param suite the ciphersuite code number + * @return ciphersuite object + */ + static Ciphersuite by_id(uint16_t suite); + + /** + * Convert an SSL/TLS ciphersuite name to algorithm fields + * @param name the IANA name for the desired ciphersuite + * @return ciphersuite object + */ + static Ciphersuite from_name(const std::string& name); + + /** + * Returns true iff this suite is a known SCSV + */ + static bool is_scsv(uint16_t suite); + + /** + * Generate a static list of all known ciphersuites and return it. + * + * @return list of all known ciphersuites + */ + static const std::vector& all_known_ciphersuites(); + + /** + * Formats the ciphersuite back to an RFC-style ciphersuite string + * @return RFC ciphersuite string identifier + */ + std::string to_string() const { return m_iana_id; } + + /** + * @return ciphersuite number + */ + uint16_t ciphersuite_code() const { return m_ciphersuite_code; } + + /** + * @return true if this is a PSK ciphersuite + */ + bool psk_ciphersuite() const; + + /** + * @return true if this is an ECC ciphersuite + */ + bool ecc_ciphersuite() const; + + /** + * @return true if this suite uses a CBC cipher + */ + bool cbc_ciphersuite() const; + + bool signature_used() const; + + /** + * @return key exchange algorithm used by this ciphersuite + */ + std::string kex_algo() const { return kex_method_to_string(kex_method()); } + + Kex_Algo kex_method() const { return m_kex_algo; } + + /** + * @return signature algorithm used by this ciphersuite + */ + std::string sig_algo() const { return auth_method_to_string(auth_method()); } + + Auth_Method auth_method() const { return m_auth_method; } + + /** + * @return symmetric cipher algorithm used by this ciphersuite + */ + std::string cipher_algo() const { return m_cipher_algo; } + + /** + * @return message authentication algorithm used by this ciphersuite + */ + std::string mac_algo() const { return m_mac_algo; } + + std::string prf_algo() const + { + return kdf_algo_to_string(m_prf_algo); + } + + /** + * @return cipher key length used by this ciphersuite + */ + size_t cipher_keylen() const { return m_cipher_keylen; } + + size_t nonce_bytes_from_handshake() const; + + size_t nonce_bytes_from_record(Protocol_Version version) const; + + Nonce_Format nonce_format() const { return m_nonce_format; } + + size_t mac_keylen() const { return m_mac_keylen; } + + /** + * @return true if this is a valid/known ciphersuite + */ + bool valid() const { return m_usable; } + + bool usable_in_version(Protocol_Version version) const; + + bool operator<(const Ciphersuite& o) const { return ciphersuite_code() < o.ciphersuite_code(); } + bool operator<(const uint16_t c) const { return ciphersuite_code() < c; } + + Ciphersuite() = default; + + private: + + bool is_usable() const; + + Ciphersuite(uint16_t ciphersuite_code, + const char* iana_id, + Auth_Method auth_method, + Kex_Algo kex_algo, + const char* cipher_algo, + size_t cipher_keylen, + const char* mac_algo, + size_t mac_keylen, + KDF_Algo prf_algo, + Nonce_Format nonce_format) : + m_ciphersuite_code(ciphersuite_code), + m_iana_id(iana_id), + m_auth_method(auth_method), + m_kex_algo(kex_algo), + m_prf_algo(prf_algo), + m_nonce_format(nonce_format), + m_cipher_algo(cipher_algo), + m_mac_algo(mac_algo), + m_cipher_keylen(cipher_keylen), + m_mac_keylen(mac_keylen) + { + m_usable = is_usable(); + } + + uint16_t m_ciphersuite_code = 0; + + /* + All of these const char* strings are references to compile time + constants in tls_suite_info.cpp + */ + const char* m_iana_id = nullptr; + + Auth_Method m_auth_method = Auth_Method::ANONYMOUS; + Kex_Algo m_kex_algo = Kex_Algo::STATIC_RSA; + KDF_Algo m_prf_algo = KDF_Algo::SHA_1; + Nonce_Format m_nonce_format = Nonce_Format::CBC_MODE; + + const char* m_cipher_algo = nullptr; + const char* m_mac_algo = nullptr; + + size_t m_cipher_keylen = 0; + size_t m_mac_keylen = 0; + + bool m_usable = false; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_client.cpp b/comm/third_party/botan/src/lib/tls/tls_client.cpp new file mode 100644 index 0000000000..e5d90c9503 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_client.cpp @@ -0,0 +1,780 @@ +/* +* TLS Client +* (C) 2004-2011,2012,2015,2016 Jack Lloyd +* 2016 Matthias Gierlings +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +class Client_Handshake_State final : public Handshake_State + { + public: + Client_Handshake_State(Handshake_IO* io, Callbacks& cb) : + Handshake_State(io, cb), + m_is_reneg(false) + {} + + const Public_Key& get_server_public_key() const + { + BOTAN_ASSERT(server_public_key, "Server sent us a certificate"); + return *server_public_key.get(); + } + + bool is_a_resumption() const { return (resumed_session != nullptr); } + + bool is_a_renegotiation() const { return m_is_reneg; } + + const secure_vector& resume_master_secret() const + { + BOTAN_STATE_CHECK(is_a_resumption()); + return resumed_session->master_secret(); + } + + const std::vector& resume_peer_certs() const + { + BOTAN_STATE_CHECK(is_a_resumption()); + return resumed_session->peer_certs(); + } + + std::unique_ptr server_public_key; + // Used during session resumption + std::unique_ptr resumed_session; + bool m_is_reneg = false; + }; + +} + +/* +* TLS Client Constructor +*/ +Client::Client(Callbacks& callbacks, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& info, + const Protocol_Version& offer_version, + const std::vector& next_protos, + size_t io_buf_sz) : + Channel(callbacks, session_manager, rng, policy, + false, offer_version.is_datagram_protocol(), io_buf_sz), + m_creds(creds), + m_info(info) + { + init(offer_version, next_protos); + } + +Client::Client(output_fn data_output_fn, + data_cb proc_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& info, + const Protocol_Version& offer_version, + const std::vector& next_protos, + size_t io_buf_sz) : + Channel(data_output_fn, proc_cb, recv_alert_cb, hs_cb, Channel::handshake_msg_cb(), + session_manager, rng, policy, false, offer_version.is_datagram_protocol(), io_buf_sz), + m_creds(creds), + m_info(info) + { + init(offer_version, next_protos); + } + +Client::Client(output_fn data_output_fn, + data_cb proc_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& info, + const Protocol_Version& offer_version, + const std::vector& next_protos) : + Channel(data_output_fn, proc_cb, recv_alert_cb, hs_cb, hs_msg_cb, + session_manager, rng, policy, false, offer_version.is_datagram_protocol()), + m_creds(creds), + m_info(info) + { + init(offer_version, next_protos); + } + +void Client::init(const Protocol_Version& protocol_version, + const std::vector& next_protocols) + { + const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname()); + + Handshake_State& state = create_handshake_state(protocol_version); + send_client_hello(state, false, protocol_version, + srp_identifier, next_protocols); + } + +Handshake_State* Client::new_handshake_state(Handshake_IO* io) + { + return new Client_Handshake_State(io, callbacks()); + } + +std::vector +Client::get_peer_cert_chain(const Handshake_State& state) const + { + const Client_Handshake_State& cstate = dynamic_cast(state); + + if(cstate.is_a_resumption()) + return cstate.resume_peer_certs(); + + if(state.server_certs()) + return state.server_certs()->cert_chain(); + return std::vector(); + } + +/* +* Send a new client hello to renegotiate +*/ +void Client::initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) + { + send_client_hello(state, force_full_renegotiation, + policy().latest_supported_version(state.version().is_datagram_protocol())); + } + +void Client::send_client_hello(Handshake_State& state_base, + bool force_full_renegotiation, + Protocol_Version version, + const std::string& srp_identifier, + const std::vector& next_protocols) + { + Client_Handshake_State& state = dynamic_cast(state_base); + + if(state.version().is_datagram_protocol()) + state.set_expected_next(HELLO_VERIFY_REQUEST); // optional + state.set_expected_next(SERVER_HELLO); + + if(!force_full_renegotiation && !m_info.empty()) + { + std::unique_ptr session_info(new Session);; + if(session_manager().load_from_server_info(m_info, *session_info)) + { + /* + Ensure that the session protocol cipher and version are acceptable + If not skip the resume and establish a new session + */ + const bool exact_version = session_info->version() == version; + const bool ok_version = + (session_info->version().is_datagram_protocol() == version.is_datagram_protocol()) && + policy().acceptable_protocol_version(session_info->version()); + + const bool session_version_ok = policy().only_resume_with_exact_version() ? exact_version : ok_version; + + if(policy().acceptable_ciphersuite(session_info->ciphersuite()) && session_version_ok) + { + if(srp_identifier == "" || session_info->srp_identifier() == srp_identifier) + { + state.client_hello( + new Client_Hello(state.handshake_io(), + state.hash(), + policy(), + callbacks(), + rng(), + secure_renegotiation_data_for_client_hello(), + *session_info, + next_protocols)); + + state.resumed_session = std::move(session_info); + } + } + } + } + + if(!state.client_hello()) // not resuming + { + Client_Hello::Settings client_settings(version, m_info.hostname(), srp_identifier); + state.client_hello(new Client_Hello( + state.handshake_io(), + state.hash(), + policy(), + callbacks(), + rng(), + secure_renegotiation_data_for_client_hello(), + client_settings, + next_protocols)); + } + + secure_renegotiation_check(state.client_hello()); + } + +namespace { + +bool key_usage_matches_ciphersuite(Key_Constraints usage, + const Ciphersuite& suite) + { + if(usage == NO_CONSTRAINTS) + return true; // anything goes ... + + if(suite.kex_method() == Kex_Algo::STATIC_RSA) + { + return (usage & KEY_ENCIPHERMENT) | (usage & DATA_ENCIPHERMENT); + } + else + { + return (usage & DIGITAL_SIGNATURE) | (usage & NON_REPUDIATION); + } + } + +} + +/* +* Process a handshake message +*/ +void Client::process_handshake_msg(const Handshake_State* active_state, + Handshake_State& state_base, + Handshake_Type type, + const std::vector& contents, + bool epoch0_restart) + { + BOTAN_ASSERT_NOMSG(epoch0_restart == false); // only happens on server side + + Client_Handshake_State& state = dynamic_cast(state_base); + + if(type == HELLO_REQUEST && active_state) + { + Hello_Request hello_request(contents); + + if(state.client_hello()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Cannot renegotiate during a handshake"); + } + + if(policy().allow_server_initiated_renegotiation()) + { + if(secure_renegotiation_supported() || policy().allow_insecure_renegotiation()) + { + state.m_is_reneg = true; + this->initiate_handshake(state, true); + } + else + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Client policy prohibits insecure renegotiation"); + } + } + else + { + if(policy().abort_connection_on_undesired_renegotiation()) + { + throw TLS_Exception(Alert::NO_RENEGOTIATION, "Client policy prohibits renegotiation"); + } + else + { + // RFC 5746 section 4.2 + send_warning_alert(Alert::NO_RENEGOTIATION); + } + } + + return; + } + + state.confirm_transition_to(type); + + if(type != HANDSHAKE_CCS && type != FINISHED && type != HELLO_VERIFY_REQUEST) + state.hash().update(state.handshake_io().format(contents, type)); + + if(type == HELLO_VERIFY_REQUEST) + { + state.set_expected_next(SERVER_HELLO); + state.set_expected_next(HELLO_VERIFY_REQUEST); // might get it again + + Hello_Verify_Request hello_verify_request(contents); + state.hello_verify_request(hello_verify_request); + } + else if(type == SERVER_HELLO) + { + state.server_hello(new Server_Hello(contents)); + + if(!state.client_hello()->offered_suite(state.server_hello()->ciphersuite())) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with ciphersuite we didn't send"); + } + + if(!Ciphersuite::by_id(state.server_hello()->ciphersuite()).usable_in_version(state.server_hello()->version())) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied using a ciphersuite not allowed in version it offered"); + } + + if(Ciphersuite::is_scsv(state.server_hello()->ciphersuite())) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with a signaling ciphersuite"); + } + + if(state.server_hello()->compression_method() != 0) + { + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Server replied with non-null compression method"); + } + + if(state.client_hello()->version() > state.server_hello()->version()) + { + if(state.server_hello()->random_signals_downgrade()) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Downgrade attack detected"); + } + + auto client_extn = state.client_hello()->extension_types(); + auto server_extn = state.server_hello()->extension_types(); + + std::vector diff; + + std::set_difference(server_extn.begin(), server_extn.end(), + client_extn.begin(), client_extn.end(), + std::back_inserter(diff)); + + if(!diff.empty()) + { + // Server sent us back an extension we did not send! + + std::ostringstream msg; + msg << "Server replied with unsupported extensions:"; + for(auto&& d : diff) + msg << " " << static_cast(d); + throw TLS_Exception(Alert::UNSUPPORTED_EXTENSION, msg.str()); + } + + if(uint16_t srtp = state.server_hello()->srtp_profile()) + { + if(!value_exists(state.client_hello()->srtp_profiles(), srtp)) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with DTLS-SRTP alg we did not send"); + } + + callbacks().tls_examine_extensions(state.server_hello()->extensions(), SERVER); + + state.set_version(state.server_hello()->version()); + m_application_protocol = state.server_hello()->next_protocol(); + + secure_renegotiation_check(state.server_hello()); + + const bool server_returned_same_session_id = + !state.server_hello()->session_id().empty() && + (state.server_hello()->session_id() == state.client_hello()->session_id()); + + if(server_returned_same_session_id) + { + // successful resumption + + /* + * In this case, we offered the version used in the original + * session, and the server must resume with the same version. + */ + if(state.server_hello()->version() != state.client_hello()->version()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server resumed session but with wrong version"); + + if(state.server_hello()->supports_extended_master_secret() && + !state.resumed_session->supports_extended_master_secret()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server resumed session but added extended master secret"); + } + + if(!state.server_hello()->supports_extended_master_secret() && + state.resumed_session->supports_extended_master_secret()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server resumed session and removed extended master secret"); + } + + state.compute_session_keys(state.resume_master_secret()); + + if(state.server_hello()->supports_session_ticket()) + { + state.set_expected_next(NEW_SESSION_TICKET); + } + else + { + state.set_expected_next(HANDSHAKE_CCS); + } + } + else + { + // new session + + if(active_state) + { + // Here we are testing things that should not change during a renegotation, + // even if the server creates a new session. Howerver they might change + // in a resumption scenario. + + if(active_state->version() != state.server_hello()->version()) + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Server changed version after renegotiation"); + + if(state.server_hello()->supports_extended_master_secret() != + active_state->server_hello()->supports_extended_master_secret()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server changed its mind about extended master secret"); + } + } + + state.resumed_session.reset(); // non-null if we were attempting a resumption + + if(state.client_hello()->version().is_datagram_protocol() != + state.server_hello()->version().is_datagram_protocol()) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Server replied with different protocol type than we offered"); + } + + if(state.version() > state.client_hello()->version()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server replied with later version than client offered"); + } + + if(state.version().major_version() == 3 && state.version().minor_version() == 0) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Server attempting to negotiate SSLv3 which is not supported"); + } + + if(!policy().acceptable_protocol_version(state.version())) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Server version " + state.version().to_string() + + " is unacceptable by policy"); + } + + if(state.ciphersuite().signature_used() || state.ciphersuite().kex_method() == Kex_Algo::STATIC_RSA) + { + state.set_expected_next(CERTIFICATE); + } + else if(state.ciphersuite().kex_method() == Kex_Algo::PSK) + { + /* PSK is anonymous so no certificate/cert req message is + ever sent. The server may or may not send a server kex, + depending on if it has an identity hint for us. + + (EC)DHE_PSK always sends a server key exchange for the + DH exchange portion, and is covered by block below + */ + + state.set_expected_next(SERVER_KEX); + state.set_expected_next(SERVER_HELLO_DONE); + } + else if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } + } + } + else if(type == CERTIFICATE) + { + state.server_certs(new Certificate(contents, policy())); + + const std::vector& server_certs = + state.server_certs()->cert_chain(); + + if(server_certs.empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client: No certificates sent by server"); + + /* + If the server supports certificate status messages, + certificate verification happens after we receive the server hello done, + in case an OCSP response was also available + */ + + X509_Certificate server_cert = server_certs[0]; + + if(active_state && active_state->server_certs()) + { + X509_Certificate current_cert = active_state->server_certs()->cert_chain().at(0); + + if(current_cert != server_cert) + throw TLS_Exception(Alert::BAD_CERTIFICATE, "Server certificate changed during renegotiation"); + } + + std::unique_ptr peer_key(server_cert.subject_public_key()); + + const std::string expected_key_type = + state.ciphersuite().signature_used() ? state.ciphersuite().sig_algo() : "RSA"; + + if(peer_key->algo_name() != expected_key_type) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Certificate key type did not match ciphersuite"); + + if(!key_usage_matches_ciphersuite(server_cert.constraints(), state.ciphersuite())) + throw TLS_Exception(Alert::BAD_CERTIFICATE, + "Certificate usage constraints do not allow this ciphersuite"); + + state.server_public_key.reset(peer_key.release()); + + if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } + + if(state.server_hello()->supports_certificate_status_message()) + { + state.set_expected_next(CERTIFICATE_STATUS); // optional + } + else + { + try + { + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); + + callbacks().tls_verify_cert_chain(server_certs, + {}, + trusted_CAs, + Usage_Type::TLS_SERVER_AUTH, + m_info.hostname(), + policy()); + } + catch(TLS_Exception&) + { + throw; + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::INTERNAL_ERROR, e.what()); + } + } + } + else if(type == CERTIFICATE_STATUS) + { + state.server_cert_status(new Certificate_Status(contents)); + + if(state.ciphersuite().kex_method() != Kex_Algo::STATIC_RSA) + { + state.set_expected_next(SERVER_KEX); + } + else + { + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + } + } + else if(type == SERVER_KEX) + { + if(state.ciphersuite().psk_ciphersuite() == false) + state.set_expected_next(CERTIFICATE_REQUEST); // optional + state.set_expected_next(SERVER_HELLO_DONE); + + state.server_kex( + new Server_Key_Exchange(contents, + state.ciphersuite().kex_method(), + state.ciphersuite().auth_method(), + state.version()) + ); + + if(state.ciphersuite().signature_used()) + { + const Public_Key& server_key = state.get_server_public_key(); + + if(!state.server_kex()->verify(server_key, state, policy())) + { + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Bad signature on server key exchange"); + } + } + } + else if(type == CERTIFICATE_REQUEST) + { + state.set_expected_next(SERVER_HELLO_DONE); + state.cert_req(new Certificate_Req(contents, state.version())); + } + else if(type == SERVER_HELLO_DONE) + { + state.server_hello_done(new Server_Hello_Done(contents)); + + if(state.server_certs() != nullptr && + state.server_hello()->supports_certificate_status_message()) + { + try + { + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); + + std::vector> ocsp; + if(state.server_cert_status() != nullptr) + { + try { + ocsp.push_back(std::make_shared(state.server_cert_status()->response())); + } + catch(Decoding_Error&) + { + // ignore it here because it might be our fault + } + } + + callbacks().tls_verify_cert_chain(state.server_certs()->cert_chain(), + ocsp, + trusted_CAs, + Usage_Type::TLS_SERVER_AUTH, + m_info.hostname(), + policy()); + } + catch(TLS_Exception&) + { + throw; + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::INTERNAL_ERROR, e.what()); + } + } + + if(state.received_handshake_msg(CERTIFICATE_REQUEST)) + { + const auto& types = state.cert_req()->acceptable_cert_types(); + + std::vector client_certs = + m_creds.find_cert_chain(types, + state.cert_req()->acceptable_CAs(), + "tls-client", + m_info.hostname()); + + state.client_certs(new Certificate(state.handshake_io(), + state.hash(), + client_certs)); + } + + state.client_kex( + new Client_Key_Exchange(state.handshake_io(), + state, + policy(), + m_creds, + state.server_public_key.get(), + m_info.hostname(), + rng()) + ); + + state.compute_session_keys(); + + if(state.received_handshake_msg(CERTIFICATE_REQUEST) && + !state.client_certs()->empty()) + { + Private_Key* private_key = + m_creds.private_key_for(state.client_certs()->cert_chain()[0], + "tls-client", + m_info.hostname()); + + state.client_verify( + new Certificate_Verify(state.handshake_io(), + state, + policy(), + rng(), + private_key) + ); + } + + state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(CLIENT); + + state.client_finished(new Finished(state.handshake_io(), state, CLIENT)); + + if(state.server_hello()->supports_session_ticket()) + state.set_expected_next(NEW_SESSION_TICKET); + else + state.set_expected_next(HANDSHAKE_CCS); + } + else if(type == NEW_SESSION_TICKET) + { + state.new_session_ticket(new New_Session_Ticket(contents)); + + state.set_expected_next(HANDSHAKE_CCS); + } + else if(type == HANDSHAKE_CCS) + { + state.set_expected_next(FINISHED); + + change_cipher_spec_reader(CLIENT); + } + else if(type == FINISHED) + { + state.server_finished(new Finished(contents)); + + if(!state.server_finished()->verify(state, SERVER)) + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Finished message didn't verify"); + + state.hash().update(state.handshake_io().format(contents, type)); + + if(!state.client_finished()) // session resume case + { + state.handshake_io().send(Change_Cipher_Spec()); + change_cipher_spec_writer(CLIENT); + state.client_finished(new Finished(state.handshake_io(), state, CLIENT)); + } + + std::vector session_id = state.server_hello()->session_id(); + + const std::vector& session_ticket = state.session_ticket(); + + if(session_id.empty() && !session_ticket.empty()) + session_id = make_hello_random(rng(), policy()); + + Session session_info( + session_id, + state.session_keys().master_secret(), + state.server_hello()->version(), + state.server_hello()->ciphersuite(), + CLIENT, + state.server_hello()->supports_extended_master_secret(), + state.server_hello()->supports_encrypt_then_mac(), + get_peer_cert_chain(state), + session_ticket, + m_info, + "", + state.server_hello()->srtp_profile() + ); + + const bool should_save = save_session(session_info); + + if(session_id.size() > 0 && state.is_a_resumption() == false) + { + if(should_save) + session_manager().save(session_info); + else + session_manager().remove_entry(session_info.session_id()); + } + + activate_session(); + } + else + throw Unexpected_Message("Unknown handshake message received"); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_client.h b/comm/third_party/botan/src/lib/tls/tls_client.h new file mode 100644 index 0000000000..0e08b45953 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_client.h @@ -0,0 +1,169 @@ +/* +* TLS Client +* (C) 2004-2011 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_CLIENT_H_ +#define BOTAN_TLS_CLIENT_H_ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* SSL/TLS Client +*/ +class BOTAN_PUBLIC_API(2,0) Client final : public Channel + { + public: + + /** + * Set up a new TLS client session + * + * @param callbacks contains a set of callback function references + * required by the TLS client. + * + * @param session_manager manages session state + * + * @param creds manages application/user credentials + * + * @param policy specifies other connection policy information + * + * @param rng a random number generator + * + * @param server_info is identifying information about the TLS server + * + * @param offer_version specifies which version we will offer + * to the TLS server. + * + * @param next_protocols specifies protocols to advertise with ALPN + * + * @param reserved_io_buffer_size This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. + */ + Client(Callbacks& callbacks, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protocols = {}, + size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE + ); + + /** + * DEPRECATED. This constructor is only provided for backward + * compatibility and should not be used in new code. It will be + * removed in a future release. + * + * Set up a new TLS client session + * + * @param data_output_fn is called with data for the outbound socket + * + * @param app_data_cb is called when new application data is received + * + * @param recv_alert_cb is called when a TLS alert is received + * + * @param hs_cb is called when a handshake is completed + * + * @param session_manager manages session state + * + * @param creds manages application/user credentials + * + * @param policy specifies other connection policy information + * + * @param rng a random number generator + * + * @param server_info is identifying information about the TLS server + * + * @param offer_version specifies which version we will offer + * to the TLS server. + * + * @param next_protocols specifies protocols to advertise with ALPN + * + * @param reserved_io_buffer_size This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. + */ + BOTAN_DEPRECATED("Use TLS::Client(TLS::Callbacks ...)") + Client(output_fn data_output_fn, + data_cb app_data_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protocols = {}, + size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE + ); + + /** + * DEPRECATED. This constructor is only provided for backward + * compatibility and should not be used in new implementations. + */ + BOTAN_DEPRECATED("Use TLS::Client(TLS::Callbacks ...)") + Client(output_fn out, + data_cb app_data_cb, + alert_cb alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protocols = {} + ); + + /** + * @return network protocol as advertised by the TLS server, if server sent the ALPN extension + */ + std::string application_protocol() const override { return m_application_protocol; } + private: + void init(const Protocol_Version& protocol_version, + const std::vector& next_protocols); + + std::vector + get_peer_cert_chain(const Handshake_State& state) const override; + + void initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) override; + + void send_client_hello(Handshake_State& state, + bool force_full_renegotiation, + Protocol_Version version, + const std::string& srp_identifier = "", + const std::vector& next_protocols = {}); + + void process_handshake_msg(const Handshake_State* active_state, + Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents, + bool epoch0_restart) override; + + Handshake_State* new_handshake_state(Handshake_IO* io) override; + + Credentials_Manager& m_creds; + const Server_Information m_info; + std::string m_application_protocol; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_exceptn.h b/comm/third_party/botan/src/lib/tls/tls_exceptn.h new file mode 100644 index 0000000000..e7d8c19635 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_exceptn.h @@ -0,0 +1,52 @@ +/* +* Exceptions +* (C) 2004-2006 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_EXCEPTION_H_ +#define BOTAN_TLS_EXCEPTION_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Exception Base Class +*/ +class BOTAN_PUBLIC_API(2,0) TLS_Exception : public Exception + { + public: + Alert::Type type() const { return m_alert_type; } + + TLS_Exception(Alert::Type type, + const std::string& err_msg = "Unknown error") : + Exception(err_msg), m_alert_type(type) {} + + int error_code() const noexcept override { return static_cast(m_alert_type); } + + ErrorType error_type() const noexcept override { return ErrorType::TLSError; } + + private: + Alert::Type m_alert_type; + }; + +/** +* Unexpected_Message Exception +*/ +class BOTAN_PUBLIC_API(2,0) Unexpected_Message final : public TLS_Exception + { + public: + explicit Unexpected_Message(const std::string& err) : + TLS_Exception(Alert::UNEXPECTED_MESSAGE, err) {} + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_extensions.cpp b/comm/third_party/botan/src/lib/tls/tls_extensions.cpp new file mode 100644 index 0000000000..631868703f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_extensions.cpp @@ -0,0 +1,660 @@ +/* +* TLS Extensions +* (C) 2011,2012,2015,2016 Jack Lloyd +* 2016 Juraj Somorovsky +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +Extension* make_extension(TLS_Data_Reader& reader, uint16_t code, uint16_t size, Connection_Side from) + { + switch(code) + { + case TLSEXT_SERVER_NAME_INDICATION: + return new Server_Name_Indicator(reader, size); + +#if defined(BOTAN_HAS_SRP6) + case TLSEXT_SRP_IDENTIFIER: + return new SRP_Identifier(reader, size); +#endif + + case TLSEXT_SUPPORTED_GROUPS: + return new Supported_Groups(reader, size); + + case TLSEXT_CERT_STATUS_REQUEST: + return new Certificate_Status_Request(reader, size, from); + + case TLSEXT_EC_POINT_FORMATS: + return new Supported_Point_Formats(reader, size); + + case TLSEXT_SAFE_RENEGOTIATION: + return new Renegotiation_Extension(reader, size); + + case TLSEXT_SIGNATURE_ALGORITHMS: + return new Signature_Algorithms(reader, size); + + case TLSEXT_USE_SRTP: + return new SRTP_Protection_Profiles(reader, size); + + case TLSEXT_ALPN: + return new Application_Layer_Protocol_Notification(reader, size); + + case TLSEXT_EXTENDED_MASTER_SECRET: + return new Extended_Master_Secret(reader, size); + + case TLSEXT_ENCRYPT_THEN_MAC: + return new Encrypt_then_MAC(reader, size); + + case TLSEXT_SESSION_TICKET: + return new Session_Ticket(reader, size); + + case TLSEXT_SUPPORTED_VERSIONS: + return new Supported_Versions(reader, size, from); + } + + return new Unknown_Extension(static_cast(code), + reader, size); + } + +} + +void Extensions::deserialize(TLS_Data_Reader& reader, Connection_Side from) + { + if(reader.has_remaining()) + { + const uint16_t all_extn_size = reader.get_uint16_t(); + + if(reader.remaining_bytes() != all_extn_size) + throw Decoding_Error("Bad extension size"); + + while(reader.has_remaining()) + { + const uint16_t extension_code = reader.get_uint16_t(); + const uint16_t extension_size = reader.get_uint16_t(); + + const auto type = static_cast(extension_code); + + if(m_extensions.find(type) != m_extensions.end()) + throw TLS_Exception(TLS::Alert::DECODE_ERROR, + "Peer sent duplicated extensions"); + + Extension* extn = make_extension( + reader, extension_code, extension_size, from); + + this->add(extn); + } + } + } + +std::vector Extensions::serialize(Connection_Side whoami) const + { + std::vector buf(2); // 2 bytes for length field + + for(auto& extn : m_extensions) + { + if(extn.second->empty()) + continue; + + const uint16_t extn_code = static_cast(extn.second->type()); + + const std::vector extn_val = extn.second->serialize(whoami); + + buf.push_back(get_byte(0, extn_code)); + buf.push_back(get_byte(1, extn_code)); + + buf.push_back(get_byte(0, static_cast(extn_val.size()))); + buf.push_back(get_byte(1, static_cast(extn_val.size()))); + + buf += extn_val; + } + + const uint16_t extn_size = static_cast(buf.size() - 2); + + buf[0] = get_byte(0, extn_size); + buf[1] = get_byte(1, extn_size); + + // avoid sending a completely empty extensions block + if(buf.size() == 2) + return std::vector(); + + return buf; + } + +bool Extensions::remove_extension(Handshake_Extension_Type typ) + { + auto i = m_extensions.find(typ); + if(i == m_extensions.end()) + return false; + m_extensions.erase(i); + return true; + } + +std::set Extensions::extension_types() const + { + std::set offers; + for(auto i = m_extensions.begin(); i != m_extensions.end(); ++i) + offers.insert(i->first); + return offers; + } + +Unknown_Extension::Unknown_Extension(Handshake_Extension_Type type, + TLS_Data_Reader& reader, + uint16_t extension_size) : + m_type(type), + m_value(reader.get_fixed(extension_size)) + { + } + +std::vector Unknown_Extension::serialize(Connection_Side /*whoami*/) const + { + throw Invalid_State("Cannot encode an unknown TLS extension"); + } + +Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader, + uint16_t extension_size) + { + /* + * This is used by the server to confirm that it knew the name + */ + if(extension_size == 0) + return; + + uint16_t name_bytes = reader.get_uint16_t(); + + if(name_bytes + 2 != extension_size) + throw Decoding_Error("Bad encoding of SNI extension"); + + while(name_bytes) + { + uint8_t name_type = reader.get_byte(); + name_bytes--; + + if(name_type == 0) // DNS + { + m_sni_host_name = reader.get_string(2, 1, 65535); + name_bytes -= static_cast(2 + m_sni_host_name.size()); + } + else // some other unknown name type + { + reader.discard_next(name_bytes); + name_bytes = 0; + } + } + } + +std::vector Server_Name_Indicator::serialize(Connection_Side /*whoami*/) const + { + std::vector buf; + + size_t name_len = m_sni_host_name.size(); + + buf.push_back(get_byte(0, static_cast(name_len+3))); + buf.push_back(get_byte(1, static_cast(name_len+3))); + buf.push_back(0); // DNS + + buf.push_back(get_byte(0, static_cast(name_len))); + buf.push_back(get_byte(1, static_cast(name_len))); + + buf += std::make_pair( + cast_char_ptr_to_uint8(m_sni_host_name.data()), + m_sni_host_name.size()); + + return buf; + } + +#if defined(BOTAN_HAS_SRP6) + +SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader, + uint16_t extension_size) : m_srp_identifier(reader.get_string(1, 1, 255)) + { + if(m_srp_identifier.size() + 1 != extension_size) + throw Decoding_Error("Bad encoding for SRP identifier extension"); + } + +std::vector SRP_Identifier::serialize(Connection_Side /*whoami*/) const + { + std::vector buf; + + const uint8_t* srp_bytes = cast_char_ptr_to_uint8(m_srp_identifier.data()); + append_tls_length_value(buf, srp_bytes, m_srp_identifier.size(), 1); + + return buf; + } + +#endif + +Renegotiation_Extension::Renegotiation_Extension(TLS_Data_Reader& reader, + uint16_t extension_size) : m_reneg_data(reader.get_range(1, 0, 255)) + { + if(m_reneg_data.size() + 1 != extension_size) + throw Decoding_Error("Bad encoding for secure renegotiation extn"); + } + +std::vector Renegotiation_Extension::serialize(Connection_Side /*whoami*/) const + { + std::vector buf; + append_tls_length_value(buf, m_reneg_data, 1); + return buf; + } + +Application_Layer_Protocol_Notification::Application_Layer_Protocol_Notification(TLS_Data_Reader& reader, + uint16_t extension_size) + { + if(extension_size == 0) + return; // empty extension + + const uint16_t name_bytes = reader.get_uint16_t(); + + size_t bytes_remaining = extension_size - 2; + + if(name_bytes != bytes_remaining) + throw Decoding_Error("Bad encoding of ALPN extension, bad length field"); + + while(bytes_remaining) + { + const std::string p = reader.get_string(1, 0, 255); + + if(bytes_remaining < p.size() + 1) + throw Decoding_Error("Bad encoding of ALPN, length field too long"); + + if(p.empty()) + throw Decoding_Error("Empty ALPN protocol not allowed"); + + bytes_remaining -= (p.size() + 1); + + m_protocols.push_back(p); + } + } + +const std::string& Application_Layer_Protocol_Notification::single_protocol() const + { + if(m_protocols.size() != 1) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Server sent " + std::to_string(m_protocols.size()) + + " protocols in ALPN extension response"); + return m_protocols[0]; + } + +std::vector Application_Layer_Protocol_Notification::serialize(Connection_Side /*whoami*/) const + { + std::vector buf(2); + + for(auto&& p: m_protocols) + { + if(p.length() >= 256) + throw TLS_Exception(Alert::INTERNAL_ERROR, "ALPN name too long"); + if(p != "") + append_tls_length_value(buf, + cast_char_ptr_to_uint8(p.data()), + p.size(), + 1); + } + + buf[0] = get_byte(0, static_cast(buf.size()-2)); + buf[1] = get_byte(1, static_cast(buf.size()-2)); + + return buf; + } + +Supported_Groups::Supported_Groups(const std::vector& groups) : m_groups(groups) + { + } + +std::vector Supported_Groups::ec_groups() const + { + std::vector ec; + for(auto g : m_groups) + { + if(group_param_is_dh(g) == false) + ec.push_back(g); + } + return ec; + } + +std::vector Supported_Groups::dh_groups() const + { + std::vector dh; + for(auto g : m_groups) + { + if(group_param_is_dh(g) == true) + dh.push_back(g); + } + return dh; + } + +std::vector Supported_Groups::serialize(Connection_Side /*whoami*/) const + { + std::vector buf(2); + + for(auto g : m_groups) + { + const uint16_t id = static_cast(g); + + if(id > 0) + { + buf.push_back(get_byte(0, id)); + buf.push_back(get_byte(1, id)); + } + } + + buf[0] = get_byte(0, static_cast(buf.size()-2)); + buf[1] = get_byte(1, static_cast(buf.size()-2)); + + return buf; + } + +Supported_Groups::Supported_Groups(TLS_Data_Reader& reader, + uint16_t extension_size) + { + const uint16_t len = reader.get_uint16_t(); + + if(len + 2 != extension_size) + throw Decoding_Error("Inconsistent length field in supported groups list"); + + if(len % 2 == 1) + throw Decoding_Error("Supported groups list of strange size"); + + const size_t elems = len / 2; + + for(size_t i = 0; i != elems; ++i) + { + const uint16_t id = reader.get_uint16_t(); + m_groups.push_back(static_cast(id)); + } + } + +std::vector Supported_Point_Formats::serialize(Connection_Side /*whoami*/) const + { + // if this extension is sent, it MUST include uncompressed (RFC 4492, section 5.1) + if(m_prefers_compressed) + { + return std::vector{2, ANSIX962_COMPRESSED_PRIME, UNCOMPRESSED}; + } + else + { + return std::vector{1, UNCOMPRESSED}; + } + } + +Supported_Point_Formats::Supported_Point_Formats(TLS_Data_Reader& reader, + uint16_t extension_size) + { + uint8_t len = reader.get_byte(); + + if(len + 1 != extension_size) + throw Decoding_Error("Inconsistent length field in supported point formats list"); + + for(size_t i = 0; i != len; ++i) + { + uint8_t format = reader.get_byte(); + + if(static_cast(format) == UNCOMPRESSED) + { + m_prefers_compressed = false; + reader.discard_next(len-i-1); + return; + } + else if(static_cast(format) == ANSIX962_COMPRESSED_PRIME) + { + m_prefers_compressed = true; + reader.discard_next(len-i-1); + return; + } + + // ignore ANSIX962_COMPRESSED_CHAR2, we don't support these curves + } + } + +std::vector Signature_Algorithms::serialize(Connection_Side /*whoami*/) const + { + BOTAN_ASSERT(m_schemes.size() < 256, "Too many signature schemes"); + + std::vector buf; + + const uint16_t len = static_cast(m_schemes.size() * 2); + + buf.push_back(get_byte(0, len)); + buf.push_back(get_byte(1, len)); + + for(Signature_Scheme scheme : m_schemes) + { + const uint16_t scheme_code = static_cast(scheme); + + buf.push_back(get_byte(0, scheme_code)); + buf.push_back(get_byte(1, scheme_code)); + } + + return buf; + } + +Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader, + uint16_t extension_size) + { + uint16_t len = reader.get_uint16_t(); + + if(len + 2 != extension_size || len % 2 == 1 || len == 0) + { + throw Decoding_Error("Bad encoding on signature algorithms extension"); + } + + while(len) + { + const uint16_t scheme_code = reader.get_uint16_t(); + m_schemes.push_back(static_cast(scheme_code)); + len -= 2; + } + } + +Session_Ticket::Session_Ticket(TLS_Data_Reader& reader, + uint16_t extension_size) : m_ticket(reader.get_elem>(extension_size)) + {} + +SRTP_Protection_Profiles::SRTP_Protection_Profiles(TLS_Data_Reader& reader, + uint16_t extension_size) : m_pp(reader.get_range(2, 0, 65535)) + { + const std::vector mki = reader.get_range(1, 0, 255); + + if(m_pp.size() * 2 + mki.size() + 3 != extension_size) + throw Decoding_Error("Bad encoding for SRTP protection extension"); + + if(!mki.empty()) + throw Decoding_Error("Unhandled non-empty MKI for SRTP protection extension"); + } + +std::vector SRTP_Protection_Profiles::serialize(Connection_Side /*whoami*/) const + { + std::vector buf; + + const uint16_t pp_len = static_cast(m_pp.size() * 2); + buf.push_back(get_byte(0, pp_len)); + buf.push_back(get_byte(1, pp_len)); + + for(uint16_t pp : m_pp) + { + buf.push_back(get_byte(0, pp)); + buf.push_back(get_byte(1, pp)); + } + + buf.push_back(0); // srtp_mki, always empty here + + return buf; + } + +Extended_Master_Secret::Extended_Master_Secret(TLS_Data_Reader&, + uint16_t extension_size) + { + if(extension_size != 0) + throw Decoding_Error("Invalid extended_master_secret extension"); + } + +std::vector Extended_Master_Secret::serialize(Connection_Side /*whoami*/) const + { + return std::vector(); + } + +Encrypt_then_MAC::Encrypt_then_MAC(TLS_Data_Reader&, + uint16_t extension_size) + { + if(extension_size != 0) + throw Decoding_Error("Invalid encrypt_then_mac extension"); + } + +std::vector Encrypt_then_MAC::serialize(Connection_Side /*whoami*/) const + { + return std::vector(); + } + +std::vector Certificate_Status_Request::serialize(Connection_Side whoami) const + { + std::vector buf; + + if(whoami == Connection_Side::SERVER) + return buf; // server reply is empty + + /* + opaque ResponderID<1..2^16-1>; + opaque Extensions<0..2^16-1>; + + CertificateStatusType status_type = ocsp(1) + ResponderID responder_id_list<0..2^16-1> + Extensions request_extensions; + */ + + buf.push_back(1); // CertificateStatusType ocsp + + buf.push_back(0); + buf.push_back(0); + buf.push_back(0); + buf.push_back(0); + + return buf; + } + +Certificate_Status_Request::Certificate_Status_Request(TLS_Data_Reader& reader, + uint16_t extension_size, + Connection_Side from) + { + if(from == Connection_Side::SERVER) + { + if(extension_size != 0) + throw Decoding_Error("Server sent non-empty Certificate_Status_Request extension"); + } + else if(extension_size > 0) + { + const uint8_t type = reader.get_byte(); + if(type == 1) + { + const size_t len_resp_id_list = reader.get_uint16_t(); + m_ocsp_names = reader.get_fixed(len_resp_id_list); + const size_t len_requ_ext = reader.get_uint16_t(); + m_extension_bytes = reader.get_fixed(len_requ_ext); + } + else + { + reader.discard_next(extension_size - 1); + } + } + } + +Certificate_Status_Request::Certificate_Status_Request(const std::vector& ocsp_responder_ids, + const std::vector>& ocsp_key_ids) : + m_ocsp_names(ocsp_responder_ids), + m_ocsp_keys(ocsp_key_ids) + { + } + +std::vector Supported_Versions::serialize(Connection_Side whoami) const + { + std::vector buf; + + if(whoami == Connection_Side::SERVER) + { + BOTAN_ASSERT_NOMSG(m_versions.size() == 1); + buf.push_back(m_versions[0].major_version()); + buf.push_back(m_versions[0].minor_version()); + } + else + { + BOTAN_ASSERT_NOMSG(m_versions.size() >= 1); + const uint8_t len = static_cast(m_versions.size() * 2); + + buf.push_back(len); + + for(Protocol_Version version : m_versions) + { + buf.push_back(get_byte(0, version.major_version())); + buf.push_back(get_byte(1, version.minor_version())); + } + } + + return buf; + } + +Supported_Versions::Supported_Versions(Protocol_Version offer, const Policy& policy) + { + if(offer.is_datagram_protocol()) + { + if(offer >= Protocol_Version::DTLS_V12 && policy.allow_dtls12()) + m_versions.push_back(Protocol_Version::DTLS_V12); +#if defined(BOTAN_HAS_TLS_V10) + if(offer >= Protocol_Version::DTLS_V10 && policy.allow_dtls10()) + m_versions.push_back(Protocol_Version::DTLS_V10); +#endif + } + else + { + if(offer >= Protocol_Version::TLS_V12 && policy.allow_tls12()) + m_versions.push_back(Protocol_Version::TLS_V12); +#if defined(BOTAN_HAS_TLS_V10) + if(offer >= Protocol_Version::TLS_V11 && policy.allow_tls11()) + m_versions.push_back(Protocol_Version::TLS_V11); + if(offer >= Protocol_Version::TLS_V10 && policy.allow_tls10()) + m_versions.push_back(Protocol_Version::TLS_V10); +#endif + } + } + +Supported_Versions::Supported_Versions(TLS_Data_Reader& reader, + uint16_t extension_size, + Connection_Side from) + { + if(from == Connection_Side::SERVER) + { + if(extension_size != 2) + throw Decoding_Error("Server sent invalid supported_versions extension"); + m_versions.push_back(Protocol_Version(reader.get_uint16_t())); + } + else + { + auto versions = reader.get_range(1, 1, 127); + + for(auto v : versions) + m_versions.push_back(Protocol_Version(v)); + + if(extension_size != 1+2*versions.size()) + throw Decoding_Error("Client sent invalid supported_versions extension"); + } + } + +bool Supported_Versions::supports(Protocol_Version version) const + { + for(auto v : m_versions) + if(version == v) + return true; + return false; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_extensions.h b/comm/third_party/botan/src/lib/tls/tls_extensions.h new file mode 100644 index 0000000000..a426c8e56f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_extensions.h @@ -0,0 +1,551 @@ +/* +* TLS Extensions +* (C) 2011,2012,2016,2018,2019 Jack Lloyd +* (C) 2016 Juraj Somorovsky +* (C) 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_EXTENSIONS_H_ +#define BOTAN_TLS_EXTENSIONS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Policy; + +class TLS_Data_Reader; + +// This will become an enum class in a future major release +enum Handshake_Extension_Type { + TLSEXT_SERVER_NAME_INDICATION = 0, + TLSEXT_CERT_STATUS_REQUEST = 5, + + TLSEXT_CERTIFICATE_TYPES = 9, + TLSEXT_SUPPORTED_GROUPS = 10, + TLSEXT_EC_POINT_FORMATS = 11, + TLSEXT_SRP_IDENTIFIER = 12, + TLSEXT_SIGNATURE_ALGORITHMS = 13, + TLSEXT_USE_SRTP = 14, + TLSEXT_ALPN = 16, + + TLSEXT_ENCRYPT_THEN_MAC = 22, + TLSEXT_EXTENDED_MASTER_SECRET = 23, + + TLSEXT_SESSION_TICKET = 35, + + TLSEXT_SUPPORTED_VERSIONS = 43, + + TLSEXT_SAFE_RENEGOTIATION = 65281, +}; + +/** +* Base class representing a TLS extension of some kind +*/ +class BOTAN_UNSTABLE_API Extension + { + public: + /** + * @return code number of the extension + */ + virtual Handshake_Extension_Type type() const = 0; + + /** + * @return serialized binary for the extension + */ + virtual std::vector serialize(Connection_Side whoami) const = 0; + + /** + * @return if we should encode this extension or not + */ + virtual bool empty() const = 0; + + virtual ~Extension() = default; + }; + +/** +* Server Name Indicator extension (RFC 3546) +*/ +class BOTAN_UNSTABLE_API Server_Name_Indicator final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SERVER_NAME_INDICATION; } + + Handshake_Extension_Type type() const override { return static_type(); } + + explicit Server_Name_Indicator(const std::string& host_name) : + m_sni_host_name(host_name) {} + + Server_Name_Indicator(TLS_Data_Reader& reader, + uint16_t extension_size); + + std::string host_name() const { return m_sni_host_name; } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return m_sni_host_name.empty(); } + private: + std::string m_sni_host_name; + }; + +#if defined(BOTAN_HAS_SRP6) +/** +* SRP identifier extension (RFC 5054) +*/ +class BOTAN_UNSTABLE_API SRP_Identifier final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SRP_IDENTIFIER; } + + Handshake_Extension_Type type() const override { return static_type(); } + + explicit SRP_Identifier(const std::string& identifier) : + m_srp_identifier(identifier) {} + + SRP_Identifier(TLS_Data_Reader& reader, + uint16_t extension_size); + + std::string identifier() const { return m_srp_identifier; } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return m_srp_identifier.empty(); } + private: + std::string m_srp_identifier; + }; +#endif + +/** +* Renegotiation Indication Extension (RFC 5746) +*/ +class BOTAN_UNSTABLE_API Renegotiation_Extension final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SAFE_RENEGOTIATION; } + + Handshake_Extension_Type type() const override { return static_type(); } + + Renegotiation_Extension() = default; + + explicit Renegotiation_Extension(const std::vector& bits) : + m_reneg_data(bits) {} + + Renegotiation_Extension(TLS_Data_Reader& reader, + uint16_t extension_size); + + const std::vector& renegotiation_info() const + { return m_reneg_data; } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return false; } // always send this + private: + std::vector m_reneg_data; + }; + +/** +* ALPN (RFC 7301) +*/ +class BOTAN_UNSTABLE_API Application_Layer_Protocol_Notification final : public Extension + { + public: + static Handshake_Extension_Type static_type() { return TLSEXT_ALPN; } + + Handshake_Extension_Type type() const override { return static_type(); } + + const std::vector& protocols() const { return m_protocols; } + + const std::string& single_protocol() const; + + /** + * Single protocol, used by server + */ + explicit Application_Layer_Protocol_Notification(const std::string& protocol) : + m_protocols(1, protocol) {} + + /** + * List of protocols, used by client + */ + explicit Application_Layer_Protocol_Notification(const std::vector& protocols) : + m_protocols(protocols) {} + + Application_Layer_Protocol_Notification(TLS_Data_Reader& reader, + uint16_t extension_size); + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return m_protocols.empty(); } + private: + std::vector m_protocols; + }; + +/** +* Session Ticket Extension (RFC 5077) +*/ +class BOTAN_UNSTABLE_API Session_Ticket final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SESSION_TICKET; } + + Handshake_Extension_Type type() const override { return static_type(); } + + /** + * @return contents of the session ticket + */ + const std::vector& contents() const { return m_ticket; } + + /** + * Create empty extension, used by both client and server + */ + Session_Ticket() = default; + + /** + * Extension with ticket, used by client + */ + explicit Session_Ticket(const std::vector& session_ticket) : + m_ticket(session_ticket) {} + + /** + * Deserialize a session ticket + */ + Session_Ticket(TLS_Data_Reader& reader, uint16_t extension_size); + + std::vector serialize(Connection_Side) const override { return m_ticket; } + + bool empty() const override { return false; } + private: + std::vector m_ticket; + }; + + +/** +* Supported Groups Extension (RFC 7919) +*/ +class BOTAN_UNSTABLE_API Supported_Groups final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SUPPORTED_GROUPS; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector ec_groups() const; + std::vector dh_groups() const; + + std::vector serialize(Connection_Side whoami) const override; + + explicit Supported_Groups(const std::vector& groups); + + Supported_Groups(TLS_Data_Reader& reader, + uint16_t extension_size); + + bool empty() const override { return m_groups.empty(); } + private: + std::vector m_groups; + }; + +// previously Supported Elliptic Curves Extension (RFC 4492) +//using Supported_Elliptic_Curves = Supported_Groups; + +/** +* Supported Point Formats Extension (RFC 4492) +*/ +class BOTAN_UNSTABLE_API Supported_Point_Formats final : public Extension + { + public: + enum ECPointFormat : uint8_t { + UNCOMPRESSED = 0, + ANSIX962_COMPRESSED_PRIME = 1, + ANSIX962_COMPRESSED_CHAR2 = 2, // don't support these curves + }; + + static Handshake_Extension_Type static_type() + { return TLSEXT_EC_POINT_FORMATS; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector serialize(Connection_Side whoami) const override; + + explicit Supported_Point_Formats(bool prefer_compressed) : + m_prefers_compressed(prefer_compressed) {} + + Supported_Point_Formats(TLS_Data_Reader& reader, + uint16_t extension_size); + + bool empty() const override { return false; } + + bool prefers_compressed() { return m_prefers_compressed; } + + private: + bool m_prefers_compressed = false; + }; + +/** +* Signature Algorithms Extension for TLS 1.2 (RFC 5246) +*/ +class BOTAN_UNSTABLE_API Signature_Algorithms final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SIGNATURE_ALGORITHMS; } + + Handshake_Extension_Type type() const override { return static_type(); } + + const std::vector& supported_schemes() const { return m_schemes; } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return m_schemes.empty(); } + + explicit Signature_Algorithms(const std::vector& schemes) : + m_schemes(schemes) {} + + Signature_Algorithms(TLS_Data_Reader& reader, + uint16_t extension_size); + private: + std::vector m_schemes; + }; + +/** +* Used to indicate SRTP algorithms for DTLS (RFC 5764) +*/ +class BOTAN_UNSTABLE_API SRTP_Protection_Profiles final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_USE_SRTP; } + + Handshake_Extension_Type type() const override { return static_type(); } + + const std::vector& profiles() const { return m_pp; } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return m_pp.empty(); } + + explicit SRTP_Protection_Profiles(const std::vector& pp) : m_pp(pp) {} + + explicit SRTP_Protection_Profiles(uint16_t pp) : m_pp(1, pp) {} + + SRTP_Protection_Profiles(TLS_Data_Reader& reader, uint16_t extension_size); + private: + std::vector m_pp; + }; + +/** +* Extended Master Secret Extension (RFC 7627) +*/ +class BOTAN_UNSTABLE_API Extended_Master_Secret final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_EXTENDED_MASTER_SECRET; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return false; } + + Extended_Master_Secret() = default; + + Extended_Master_Secret(TLS_Data_Reader& reader, uint16_t extension_size); + }; + +/** +* Encrypt-then-MAC Extension (RFC 7366) +*/ +class BOTAN_UNSTABLE_API Encrypt_then_MAC final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_ENCRYPT_THEN_MAC; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return false; } + + Encrypt_then_MAC() = default; + + Encrypt_then_MAC(TLS_Data_Reader& reader, uint16_t extension_size); + }; + +/** +* Certificate Status Request (RFC 6066) +*/ +class BOTAN_UNSTABLE_API Certificate_Status_Request final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_CERT_STATUS_REQUEST; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return false; } + + const std::vector& get_responder_id_list() const + { + return m_ocsp_names; + } + + const std::vector& get_request_extensions() const + { + return m_extension_bytes; + } + + // Server generated version: empty + Certificate_Status_Request() {} + + // Client version, both lists can be empty + Certificate_Status_Request(const std::vector& ocsp_responder_ids, + const std::vector>& ocsp_key_ids); + + Certificate_Status_Request(TLS_Data_Reader& reader, + uint16_t extension_size, + Connection_Side side); + private: + std::vector m_ocsp_names; + std::vector> m_ocsp_keys; // is this field really needed + std::vector m_extension_bytes; + }; + +/** +* Supported Versions from RFC 8446 +*/ +class BOTAN_UNSTABLE_API Supported_Versions final : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_SUPPORTED_VERSIONS; } + + Handshake_Extension_Type type() const override { return static_type(); } + + std::vector serialize(Connection_Side whoami) const override; + + bool empty() const override { return m_versions.empty(); } + + Supported_Versions(Protocol_Version version, const Policy& policy); + + Supported_Versions(Protocol_Version version) + { + m_versions.push_back(version); + } + + Supported_Versions(TLS_Data_Reader& reader, + uint16_t extension_size, + Connection_Side from); + + bool supports(Protocol_Version version) const; + + const std::vector versions() const { return m_versions; } + private: + std::vector m_versions; + }; + +/** +* Unknown extensions are deserialized as this type +*/ +class BOTAN_UNSTABLE_API Unknown_Extension final : public Extension + { + public: + Unknown_Extension(Handshake_Extension_Type type, + TLS_Data_Reader& reader, + uint16_t extension_size); + + std::vector serialize(Connection_Side whoami) const override; // always fails + + const std::vector& value() { return m_value; } + + bool empty() const override { return false; } + + Handshake_Extension_Type type() const override { return m_type; } + + private: + Handshake_Extension_Type m_type; + std::vector m_value; + }; + +/** +* Represents a block of extensions in a hello message +*/ +class BOTAN_UNSTABLE_API Extensions final + { + public: + std::set extension_types() const; + + template + T* get() const + { + return dynamic_cast(get(T::static_type())); + } + + template + bool has() const + { + return get() != nullptr; + } + + void add(Extension* extn) + { + m_extensions[extn->type()].reset(extn); + } + + Extension* get(Handshake_Extension_Type type) const + { + auto i = m_extensions.find(type); + + if(i != m_extensions.end()) + return i->second.get(); + return nullptr; + } + + std::vector serialize(Connection_Side whoami) const; + + void deserialize(TLS_Data_Reader& reader, Connection_Side from); + + /** + * Remvoe an extension from this extensions object, if it exists. + * Returns true if the extension existed (and thus is now removed), + * otherwise false (the extension wasn't set in the first place). + */ + bool remove_extension(Handshake_Extension_Type typ); + + Extensions() = default; + + Extensions(TLS_Data_Reader& reader, Connection_Side side) + { + deserialize(reader, side); + } + + private: + Extensions(const Extensions&) = delete; + Extensions& operator=(const Extensions&) = delete; + + std::map> m_extensions; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_hash.cpp b/comm/third_party/botan/src/lib/tls/tls_handshake_hash.cpp new file mode 100644 index 0000000000..a48251d06d --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_hash.cpp @@ -0,0 +1,34 @@ +/* +* TLS Handshake Hash +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Return a TLS Handshake Hash +*/ +secure_vector Handshake_Hash::final(Protocol_Version version, + const std::string& mac_algo) const + { + std::string hash_algo = mac_algo; + if(!version.supports_ciphersuite_specific_prf()) + hash_algo = "Parallel(MD5,SHA-160)"; + else if(mac_algo == "MD5" || mac_algo == "SHA-1") + hash_algo = "SHA-256"; + + std::unique_ptr hash(HashFunction::create_or_throw(hash_algo)); + hash->update(m_data); + return hash->final(); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_hash.h b/comm/third_party/botan/src/lib/tls/tls_handshake_hash.h new file mode 100644 index 0000000000..bb38015c8c --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_hash.h @@ -0,0 +1,44 @@ +/* +* TLS Handshake Hash +* (C) 2004-2006,2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_HASH_H_ +#define BOTAN_TLS_HANDSHAKE_HASH_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Handshake Hash +*/ +class Handshake_Hash final + { + public: + void update(const uint8_t in[], size_t length) + { m_data += std::make_pair(in, length); } + + void update(const std::vector& in) + { m_data += in; } + + secure_vector final(Protocol_Version version, + const std::string& mac_algo) const; + + const std::vector& get_contents() const { return m_data; } + + void reset() { m_data.clear(); } + private: + std::vector m_data; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_io.cpp b/comm/third_party/botan/src/lib/tls/tls_handshake_io.cpp new file mode 100644 index 0000000000..7f9e2c86c5 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_io.cpp @@ -0,0 +1,480 @@ +/* +* TLS Handshake IO +* (C) 2012,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +namespace { + +inline size_t load_be24(const uint8_t q[3]) + { + return make_uint32(0, + q[0], + q[1], + q[2]); + } + +void store_be24(uint8_t out[3], size_t val) + { + out[0] = get_byte(1, static_cast(val)); + out[1] = get_byte(2, static_cast(val)); + out[2] = get_byte(3, static_cast(val)); + } + +uint64_t steady_clock_ms() + { + return std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count(); + } + +} + +Protocol_Version Stream_Handshake_IO::initial_record_version() const + { + return Protocol_Version::TLS_V10; + } + +void Stream_Handshake_IO::add_record(const uint8_t record[], + size_t record_len, + Record_Type record_type, uint64_t) + { + if(record_type == HANDSHAKE) + { + m_queue.insert(m_queue.end(), record, record + record_len); + } + else if(record_type == CHANGE_CIPHER_SPEC) + { + if(record_len != 1 || record[0] != 1) + throw Decoding_Error("Invalid ChangeCipherSpec"); + + // Pretend it's a regular handshake message of zero length + const uint8_t ccs_hs[] = { HANDSHAKE_CCS, 0, 0, 0 }; + m_queue.insert(m_queue.end(), ccs_hs, ccs_hs + sizeof(ccs_hs)); + } + else + throw Decoding_Error("Unknown message type " + std::to_string(record_type) + " in handshake processing"); + } + +std::pair> +Stream_Handshake_IO::get_next_record(bool) + { + if(m_queue.size() >= 4) + { + const size_t length = 4 + make_uint32(0, m_queue[1], m_queue[2], m_queue[3]); + + if(m_queue.size() >= length) + { + Handshake_Type type = static_cast(m_queue[0]); + + if(type == HANDSHAKE_NONE) + throw Decoding_Error("Invalid handshake message type"); + + std::vector contents(m_queue.begin() + 4, + m_queue.begin() + length); + + m_queue.erase(m_queue.begin(), m_queue.begin() + length); + + return std::make_pair(type, contents); + } + } + + return std::make_pair(HANDSHAKE_NONE, std::vector()); + } + +std::vector +Stream_Handshake_IO::format(const std::vector& msg, + Handshake_Type type) const + { + std::vector send_buf(4 + msg.size()); + + const size_t buf_size = msg.size(); + + send_buf[0] = static_cast(type); + + store_be24(&send_buf[1], buf_size); + + if (msg.size() > 0) + { + copy_mem(&send_buf[4], msg.data(), msg.size()); + } + + return send_buf; + } + +std::vector Stream_Handshake_IO::send_under_epoch(const Handshake_Message& /*msg*/, uint16_t /*epoch*/) + { + throw Invalid_State("Not possible to send under arbitrary epoch with stream based TLS"); + } + +std::vector Stream_Handshake_IO::send(const Handshake_Message& msg) + { + const std::vector msg_bits = msg.serialize(); + + if(msg.type() == HANDSHAKE_CCS) + { + m_send_hs(CHANGE_CIPHER_SPEC, msg_bits); + return std::vector(); // not included in handshake hashes + } + + const std::vector buf = format(msg_bits, msg.type()); + m_send_hs(HANDSHAKE, buf); + return buf; + } + +Protocol_Version Datagram_Handshake_IO::initial_record_version() const + { + return Protocol_Version::DTLS_V10; + } + +void Datagram_Handshake_IO::retransmit_last_flight() + { + const size_t flight_idx = (m_flights.size() == 1) ? 0 : (m_flights.size() - 2); + retransmit_flight(flight_idx); + } + +void Datagram_Handshake_IO::retransmit_flight(size_t flight_idx) + { + const std::vector& flight = m_flights.at(flight_idx); + + BOTAN_ASSERT(flight.size() > 0, "Nonempty flight to retransmit"); + + uint16_t epoch = m_flight_data[flight[0]].epoch; + + for(auto msg_seq : flight) + { + auto& msg = m_flight_data[msg_seq]; + + if(msg.epoch != epoch) + { + // Epoch gap: insert the CCS + std::vector ccs(1, 1); + m_send_hs(epoch, CHANGE_CIPHER_SPEC, ccs); + } + + send_message(msg_seq, msg.epoch, msg.msg_type, msg.msg_bits); + epoch = msg.epoch; + } + } + +bool Datagram_Handshake_IO::timeout_check() + { + if(m_last_write == 0 || (m_flights.size() > 1 && !m_flights.rbegin()->empty())) + { + /* + If we haven't written anything yet obviously no timeout. + Also no timeout possible if we are mid-flight, + */ + return false; + } + + const uint64_t ms_since_write = steady_clock_ms() - m_last_write; + + if(ms_since_write < m_next_timeout) + return false; + + retransmit_last_flight(); + + m_next_timeout = std::min(2 * m_next_timeout, m_max_timeout); + return true; + } + +void Datagram_Handshake_IO::add_record(const uint8_t record[], + size_t record_len, + Record_Type record_type, + uint64_t record_sequence) + { + const uint16_t epoch = static_cast(record_sequence >> 48); + + if(record_type == CHANGE_CIPHER_SPEC) + { + if(record_len != 1 || record[0] != 1) + throw Decoding_Error("Invalid ChangeCipherSpec"); + + // TODO: check this is otherwise empty + m_ccs_epochs.insert(epoch); + return; + } + + const size_t DTLS_HANDSHAKE_HEADER_LEN = 12; + + while(record_len) + { + if(record_len < DTLS_HANDSHAKE_HEADER_LEN) + return; // completely bogus? at least degenerate/weird + + const uint8_t msg_type = record[0]; + const size_t msg_len = load_be24(&record[1]); + const uint16_t message_seq = load_be(&record[4], 0); + const size_t fragment_offset = load_be24(&record[6]); + const size_t fragment_length = load_be24(&record[9]); + + const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length; + + if(record_len < total_size) + throw Decoding_Error("Bad lengths in DTLS header"); + + if(message_seq >= m_in_message_seq) + { + m_messages[message_seq].add_fragment(&record[DTLS_HANDSHAKE_HEADER_LEN], + fragment_length, + fragment_offset, + epoch, + msg_type, + msg_len); + } + else + { + // TODO: detect retransmitted flight + } + + record += total_size; + record_len -= total_size; + } + } + +std::pair> +Datagram_Handshake_IO::get_next_record(bool expecting_ccs) + { + // Expecting a message means the last flight is concluded + if(!m_flights.rbegin()->empty()) + m_flights.push_back(std::vector()); + + if(expecting_ccs) + { + if(!m_messages.empty()) + { + const uint16_t current_epoch = m_messages.begin()->second.epoch(); + + if(m_ccs_epochs.count(current_epoch)) + return std::make_pair(HANDSHAKE_CCS, std::vector()); + } + return std::make_pair(HANDSHAKE_NONE, std::vector()); + } + + auto i = m_messages.find(m_in_message_seq); + + if(i == m_messages.end() || !i->second.complete()) + { + return std::make_pair(HANDSHAKE_NONE, std::vector()); + } + + m_in_message_seq += 1; + + return i->second.message(); + } + +void Datagram_Handshake_IO::Handshake_Reassembly::add_fragment( + const uint8_t fragment[], + size_t fragment_length, + size_t fragment_offset, + uint16_t epoch, + uint8_t msg_type, + size_t msg_length) + { + if(complete()) + return; // already have entire message, ignore this + + if(m_msg_type == HANDSHAKE_NONE) + { + m_epoch = epoch; + m_msg_type = msg_type; + m_msg_length = msg_length; + } + + if(msg_type != m_msg_type || msg_length != m_msg_length || epoch != m_epoch) + throw Decoding_Error("Inconsistent values in fragmented DTLS handshake header"); + + if(fragment_offset > m_msg_length) + throw Decoding_Error("Fragment offset past end of message"); + + if(fragment_offset + fragment_length > m_msg_length) + throw Decoding_Error("Fragment overlaps past end of message"); + + if(fragment_offset == 0 && fragment_length == m_msg_length) + { + m_fragments.clear(); + m_message.assign(fragment, fragment+fragment_length); + } + else + { + /* + * FIXME. This is a pretty lame way to do defragmentation, huge + * overhead with a tree node per byte. + * + * Also should confirm that all overlaps have no changes, + * otherwise we expose ourselves to the classic fingerprinting + * and IDS evasion attacks on IP fragmentation. + */ + for(size_t i = 0; i != fragment_length; ++i) + m_fragments[fragment_offset+i] = fragment[i]; + + if(m_fragments.size() == m_msg_length) + { + m_message.resize(m_msg_length); + for(size_t i = 0; i != m_msg_length; ++i) + m_message[i] = m_fragments[i]; + m_fragments.clear(); + } + } + } + +bool Datagram_Handshake_IO::Handshake_Reassembly::complete() const + { + return (m_msg_type != HANDSHAKE_NONE && m_message.size() == m_msg_length); + } + +std::pair> +Datagram_Handshake_IO::Handshake_Reassembly::message() const + { + if(!complete()) + throw Internal_Error("Datagram_Handshake_IO - message not complete"); + + return std::make_pair(static_cast(m_msg_type), m_message); + } + +std::vector +Datagram_Handshake_IO::format_fragment(const uint8_t fragment[], + size_t frag_len, + uint16_t frag_offset, + uint16_t msg_len, + Handshake_Type type, + uint16_t msg_sequence) const + { + std::vector send_buf(12 + frag_len); + + send_buf[0] = static_cast(type); + + store_be24(&send_buf[1], msg_len); + + store_be(msg_sequence, &send_buf[4]); + + store_be24(&send_buf[6], frag_offset); + store_be24(&send_buf[9], frag_len); + + if (frag_len > 0) + { + copy_mem(&send_buf[12], fragment, frag_len); + } + + return send_buf; + } + +std::vector +Datagram_Handshake_IO::format_w_seq(const std::vector& msg, + Handshake_Type type, + uint16_t msg_sequence) const + { + return format_fragment(msg.data(), msg.size(), 0, static_cast(msg.size()), type, msg_sequence); + } + +std::vector +Datagram_Handshake_IO::format(const std::vector& msg, + Handshake_Type type) const + { + return format_w_seq(msg, type, m_in_message_seq - 1); + } + +std::vector Datagram_Handshake_IO::send(const Handshake_Message& msg) + { + return this->send_under_epoch(msg, m_seqs.current_write_epoch()); + } + +std::vector +Datagram_Handshake_IO::send_under_epoch(const Handshake_Message& msg, uint16_t epoch) + { + const std::vector msg_bits = msg.serialize(); + const Handshake_Type msg_type = msg.type(); + + if(msg_type == HANDSHAKE_CCS) + { + m_send_hs(epoch, CHANGE_CIPHER_SPEC, msg_bits); + return std::vector(); // not included in handshake hashes + } + else if(msg_type == HELLO_VERIFY_REQUEST) + { + // This message is not included in the handshake hashes + send_message(m_out_message_seq, epoch, msg_type, msg_bits); + m_out_message_seq += 1; + return std::vector(); + } + + // Note: not saving CCS, instead we know it was there due to change in epoch + m_flights.rbegin()->push_back(m_out_message_seq); + m_flight_data[m_out_message_seq] = Message_Info(epoch, msg_type, msg_bits); + + m_out_message_seq += 1; + m_last_write = steady_clock_ms(); + m_next_timeout = m_initial_timeout; + + return send_message(m_out_message_seq - 1, epoch, msg_type, msg_bits); + } + +std::vector Datagram_Handshake_IO::send_message(uint16_t msg_seq, + uint16_t epoch, + Handshake_Type msg_type, + const std::vector& msg_bits) + { + const size_t DTLS_HANDSHAKE_HEADER_LEN = 12; + + const std::vector no_fragment = + format_w_seq(msg_bits, msg_type, msg_seq); + + if(no_fragment.size() + DTLS_HEADER_SIZE <= m_mtu) + { + m_send_hs(epoch, HANDSHAKE, no_fragment); + } + else + { + size_t frag_offset = 0; + + /** + * Largest possible overhead is for SHA-384 CBC ciphers, with 16 byte IV, + * 16+ for padding and 48 bytes for MAC. 128 is probably a strict + * over-estimate here. When CBC ciphers are removed this can be reduced + * since AEAD modes have no padding, at most 16 byte mac, and smaller + * per-record nonce. + */ + const size_t ciphersuite_overhead = (epoch > 0) ? 128 : 0; + const size_t header_overhead = DTLS_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_LEN; + + if(m_mtu <= (header_overhead + ciphersuite_overhead)) + throw Invalid_Argument("DTLS MTU is too small to send headers"); + + const size_t max_rec_size = m_mtu - (header_overhead + ciphersuite_overhead); + + while(frag_offset != msg_bits.size()) + { + const size_t frag_len = std::min(msg_bits.size() - frag_offset, max_rec_size); + + const std::vector frag = + format_fragment(&msg_bits[frag_offset], + frag_len, + static_cast(frag_offset), + static_cast(msg_bits.size()), + msg_type, + msg_seq); + + m_send_hs(epoch, HANDSHAKE, frag); + + frag_offset += frag_len; + } + } + + return no_fragment; + } + +} +} diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_io.h b/comm/third_party/botan/src/lib/tls/tls_handshake_io.h new file mode 100644 index 0000000000..1c128726d6 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_io.h @@ -0,0 +1,218 @@ +/* +* TLS Handshake Serialization +* (C) 2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_IO_H_ +#define BOTAN_TLS_HANDSHAKE_IO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Handshake_Message; + +/** +* Handshake IO Interface +*/ +class Handshake_IO + { + public: + virtual Protocol_Version initial_record_version() const = 0; + + virtual std::vector send(const Handshake_Message& msg) = 0; + + virtual std::vector send_under_epoch(const Handshake_Message& msg, uint16_t epoch) = 0; + + virtual bool timeout_check() = 0; + + virtual std::vector format( + const std::vector& handshake_msg, + Handshake_Type handshake_type) const = 0; + + virtual void add_record(const uint8_t record[], + size_t record_len, + Record_Type type, + uint64_t sequence_number) = 0; + + /** + * Returns (HANDSHAKE_NONE, std::vector<>()) if no message currently available + */ + virtual std::pair> + get_next_record(bool expecting_ccs) = 0; + + Handshake_IO() = default; + + Handshake_IO(const Handshake_IO&) = delete; + + Handshake_IO& operator=(const Handshake_IO&) = delete; + + virtual ~Handshake_IO() = default; + }; + +/** +* Handshake IO for stream-based handshakes +*/ +class Stream_Handshake_IO final : public Handshake_IO + { + public: + typedef std::function&)> writer_fn; + + explicit Stream_Handshake_IO(writer_fn writer) : m_send_hs(writer) {} + + Protocol_Version initial_record_version() const override; + + bool timeout_check() override { return false; } + + std::vector send(const Handshake_Message& msg) override; + + std::vector send_under_epoch(const Handshake_Message& msg, uint16_t epoch) override; + + std::vector format( + const std::vector& handshake_msg, + Handshake_Type handshake_type) const override; + + void add_record(const uint8_t record[], + size_t record_len, + Record_Type type, + uint64_t sequence_number) override; + + std::pair> + get_next_record(bool expecting_ccs) override; + private: + std::deque m_queue; + writer_fn m_send_hs; + }; + +/** +* Handshake IO for datagram-based handshakes +*/ +class Datagram_Handshake_IO final : public Handshake_IO + { + public: + typedef std::function&)> writer_fn; + + Datagram_Handshake_IO(writer_fn writer, + class Connection_Sequence_Numbers& seq, + uint16_t mtu, uint64_t initial_timeout_ms, uint64_t max_timeout_ms) : + m_seqs(seq), + m_flights(1), + m_initial_timeout(initial_timeout_ms), + m_max_timeout(max_timeout_ms), + m_send_hs(writer), + m_mtu(mtu) + {} + + Protocol_Version initial_record_version() const override; + + bool timeout_check() override; + + std::vector send(const Handshake_Message& msg) override; + + std::vector send_under_epoch(const Handshake_Message& msg, uint16_t epoch) override; + + std::vector format( + const std::vector& handshake_msg, + Handshake_Type handshake_type) const override; + + void add_record(const uint8_t record[], + size_t record_len, + Record_Type type, + uint64_t sequence_number) override; + + std::pair> + get_next_record(bool expecting_ccs) override; + private: + void retransmit_flight(size_t flight); + void retransmit_last_flight(); + + std::vector format_fragment( + const uint8_t fragment[], + size_t fragment_len, + uint16_t frag_offset, + uint16_t msg_len, + Handshake_Type type, + uint16_t msg_sequence) const; + + std::vector format_w_seq( + const std::vector& handshake_msg, + Handshake_Type handshake_type, + uint16_t msg_sequence) const; + + std::vector send_message(uint16_t msg_seq, uint16_t epoch, + Handshake_Type msg_type, + const std::vector& msg); + + class Handshake_Reassembly final + { + public: + void add_fragment(const uint8_t fragment[], + size_t fragment_length, + size_t fragment_offset, + uint16_t epoch, + uint8_t msg_type, + size_t msg_length); + + bool complete() const; + + uint16_t epoch() const { return m_epoch; } + + std::pair> message() const; + private: + uint8_t m_msg_type = HANDSHAKE_NONE; + size_t m_msg_length = 0; + uint16_t m_epoch = 0; + + // vector m_seen; + // vector m_fragments + std::map m_fragments; + std::vector m_message; + }; + + struct Message_Info final + { + Message_Info(uint16_t e, Handshake_Type mt, const std::vector& msg) : + epoch(e), msg_type(mt), msg_bits(msg) {} + + Message_Info() : epoch(0xFFFF), msg_type(HANDSHAKE_NONE) {} + + uint16_t epoch; + Handshake_Type msg_type; + std::vector msg_bits; + }; + + class Connection_Sequence_Numbers& m_seqs; + std::map m_messages; + std::set m_ccs_epochs; + std::vector> m_flights; + std::map m_flight_data; + + uint64_t m_initial_timeout = 0; + uint64_t m_max_timeout = 0; + + uint64_t m_last_write = 0; + uint64_t m_next_timeout = 0; + + uint16_t m_in_message_seq = 0; + uint16_t m_out_message_seq = 0; + + writer_fn m_send_hs; + uint16_t m_mtu; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_msg.h b/comm/third_party/botan/src/lib/tls/tls_handshake_msg.h new file mode 100644 index 0000000000..a0d9346fba --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_msg.h @@ -0,0 +1,51 @@ +/* +* TLS Handshake Message +* (C) 2012 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_MSG_H_ +#define BOTAN_TLS_HANDSHAKE_MSG_H_ + +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Handshake_IO; +class Handshake_Hash; + +/** +* TLS Handshake Message Base Class +*/ +class BOTAN_PUBLIC_API(2,0) Handshake_Message + { + public: + /** + * @return string representation of this message type + */ + std::string type_string() const; + + /** + * @return the message type + */ + virtual Handshake_Type type() const = 0; + + /** + * @return DER representation of this message + */ + virtual std::vector serialize() const = 0; + + virtual ~Handshake_Message() = default; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_state.cpp b/comm/third_party/botan/src/lib/tls/tls_handshake_state.cpp new file mode 100644 index 0000000000..9c9390a221 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_state.cpp @@ -0,0 +1,580 @@ +/* +* TLS Handshaking +* (C) 2004-2006,2011,2012,2015,2016 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +std::string Handshake_Message::type_string() const + { + return handshake_type_to_string(type()); + } + +const char* handshake_type_to_string(Handshake_Type type) + { + switch(type) + { + case HELLO_VERIFY_REQUEST: + return "hello_verify_request"; + + case HELLO_REQUEST: + return "hello_request"; + + case CLIENT_HELLO: + return "client_hello"; + + case SERVER_HELLO: + return "server_hello"; + + case CERTIFICATE: + return "certificate"; + + case CERTIFICATE_URL: + return "certificate_url"; + + case CERTIFICATE_STATUS: + return "certificate_status"; + + case SERVER_KEX: + return "server_key_exchange"; + + case CERTIFICATE_REQUEST: + return "certificate_request"; + + case SERVER_HELLO_DONE: + return "server_hello_done"; + + case CERTIFICATE_VERIFY: + return "certificate_verify"; + + case CLIENT_KEX: + return "client_key_exchange"; + + case NEW_SESSION_TICKET: + return "new_session_ticket"; + + case HANDSHAKE_CCS: + return "change_cipher_spec"; + + case FINISHED: + return "finished"; + + case HANDSHAKE_NONE: + return "invalid"; + } + + throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, + "Unknown TLS handshake message type " + std::to_string(type)); + } + +namespace { + +uint32_t bitmask_for_handshake_type(Handshake_Type type) + { + switch(type) + { + case HELLO_VERIFY_REQUEST: + return (1 << 0); + + case HELLO_REQUEST: + return (1 << 1); + + case CLIENT_HELLO: + return (1 << 2); + + case SERVER_HELLO: + return (1 << 3); + + case CERTIFICATE: + return (1 << 4); + + case CERTIFICATE_URL: + return (1 << 5); + + case CERTIFICATE_STATUS: + return (1 << 6); + + case SERVER_KEX: + return (1 << 7); + + case CERTIFICATE_REQUEST: + return (1 << 8); + + case SERVER_HELLO_DONE: + return (1 << 9); + + case CERTIFICATE_VERIFY: + return (1 << 10); + + case CLIENT_KEX: + return (1 << 11); + + case NEW_SESSION_TICKET: + return (1 << 12); + + case HANDSHAKE_CCS: + return (1 << 13); + + case FINISHED: + return (1 << 14); + + // allow explicitly disabling new handshakes + case HANDSHAKE_NONE: + return 0; + } + + throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, + "Unknown TLS handshake message type " + std::to_string(type)); + } + +std::string handshake_mask_to_string(uint32_t mask, char combiner) + { + const Handshake_Type types[] = { + HELLO_VERIFY_REQUEST, + HELLO_REQUEST, + CLIENT_HELLO, + SERVER_HELLO, + CERTIFICATE, + CERTIFICATE_URL, + CERTIFICATE_STATUS, + SERVER_KEX, + CERTIFICATE_REQUEST, + SERVER_HELLO_DONE, + CERTIFICATE_VERIFY, + CLIENT_KEX, + NEW_SESSION_TICKET, + HANDSHAKE_CCS, + FINISHED + }; + + std::ostringstream o; + bool empty = true; + + for(auto&& t : types) + { + if(mask & bitmask_for_handshake_type(t)) + { + if(!empty) + o << combiner; + o << handshake_type_to_string(t); + empty = false; + } + } + + return o.str(); + } + +} + +/* +* Initialize the SSL/TLS Handshake State +*/ +Handshake_State::Handshake_State(Handshake_IO* io, Callbacks& cb) : + m_callbacks(cb), + m_handshake_io(io), + m_version(m_handshake_io->initial_record_version()) + { + } + +void Handshake_State::note_message(const Handshake_Message& msg) + { + m_callbacks.tls_inspect_handshake_msg(msg); + } + +void Handshake_State::hello_verify_request(const Hello_Verify_Request& hello_verify) + { + note_message(hello_verify); + + m_client_hello->update_hello_cookie(hello_verify); + hash().reset(); + hash().update(handshake_io().send(*m_client_hello)); + note_message(*m_client_hello); + } + +void Handshake_State::client_hello(Client_Hello* client_hello) + { + if(client_hello == nullptr) + { + m_client_hello.reset(); + hash().reset(); + } + else + { + m_client_hello.reset(client_hello); + note_message(*m_client_hello); + } + } + +void Handshake_State::server_hello(Server_Hello* server_hello) + { + m_server_hello.reset(server_hello); + m_ciphersuite = Ciphersuite::by_id(m_server_hello->ciphersuite()); + note_message(*m_server_hello); + } + +void Handshake_State::server_certs(Certificate* server_certs) + { + m_server_certs.reset(server_certs); + note_message(*m_server_certs); + } + +void Handshake_State::server_cert_status(Certificate_Status* server_cert_status) + { + m_server_cert_status.reset(server_cert_status); + note_message(*m_server_cert_status); + } + +void Handshake_State::server_kex(Server_Key_Exchange* server_kex) + { + m_server_kex.reset(server_kex); + note_message(*m_server_kex); + } + +void Handshake_State::cert_req(Certificate_Req* cert_req) + { + m_cert_req.reset(cert_req); + note_message(*m_cert_req); + } + +void Handshake_State::server_hello_done(Server_Hello_Done* server_hello_done) + { + m_server_hello_done.reset(server_hello_done); + note_message(*m_server_hello_done); + } + +void Handshake_State::client_certs(Certificate* client_certs) + { + m_client_certs.reset(client_certs); + note_message(*m_client_certs); + } + +void Handshake_State::client_kex(Client_Key_Exchange* client_kex) + { + m_client_kex.reset(client_kex); + note_message(*m_client_kex); + } + +void Handshake_State::client_verify(Certificate_Verify* client_verify) + { + m_client_verify.reset(client_verify); + note_message(*m_client_verify); + } + +void Handshake_State::new_session_ticket(New_Session_Ticket* new_session_ticket) + { + m_new_session_ticket.reset(new_session_ticket); + note_message(*m_new_session_ticket); + } + +void Handshake_State::server_finished(Finished* server_finished) + { + m_server_finished.reset(server_finished); + note_message(*m_server_finished); + } + +void Handshake_State::client_finished(Finished* client_finished) + { + m_client_finished.reset(client_finished); + note_message(*m_client_finished); + } + +void Handshake_State::set_version(const Protocol_Version& version) + { + m_version = version; + } + +void Handshake_State::compute_session_keys() + { + m_session_keys = Session_Keys(this, client_kex()->pre_master_secret(), false); + } + +void Handshake_State::compute_session_keys(const secure_vector& resume_master_secret) + { + m_session_keys = Session_Keys(this, resume_master_secret, true); + } + +void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg) + { + const uint32_t mask = bitmask_for_handshake_type(handshake_msg); + + m_hand_received_mask |= mask; + + const bool ok = (m_hand_expecting_mask & mask) != 0; // overlap? + + if(!ok) + { + const uint32_t seen_so_far = m_hand_received_mask & ~mask; + + std::ostringstream msg; + + msg << "Unexpected state transition in handshake got a " << handshake_type_to_string(handshake_msg); + + if(m_hand_expecting_mask == 0) + msg << " not expecting messages"; + else + msg << " expected " << handshake_mask_to_string(m_hand_expecting_mask, '|'); + + if(seen_so_far != 0) + msg << " seen " << handshake_mask_to_string(seen_so_far, '+'); + + throw Unexpected_Message(msg.str()); + } + + /* We don't know what to expect next, so force a call to + set_expected_next; if it doesn't happen, the next transition + check will always fail which is what we want. + */ + m_hand_expecting_mask = 0; + } + +void Handshake_State::set_expected_next(Handshake_Type handshake_msg) + { + m_hand_expecting_mask |= bitmask_for_handshake_type(handshake_msg); + } + +bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const + { + const uint32_t mask = bitmask_for_handshake_type(handshake_msg); + + return (m_hand_received_mask & mask) != 0; + } + +std::pair> +Handshake_State::get_next_handshake_msg() + { + const bool expecting_ccs = + (bitmask_for_handshake_type(HANDSHAKE_CCS) & m_hand_expecting_mask) != 0; + + return m_handshake_io->get_next_record(expecting_ccs); + } + +std::string Handshake_State::srp_identifier() const + { +#if defined(BOTAN_HAS_SRP6) + // Authenticated via the successful key exchange + if(ciphersuite().valid() && ciphersuite().kex_method() == Kex_Algo::SRP_SHA) + return client_hello()->srp_identifier(); +#endif + + return ""; + } + + +std::vector Handshake_State::session_ticket() const + { + if(new_session_ticket() && !new_session_ticket()->ticket().empty()) + return new_session_ticket()->ticket(); + + return client_hello()->session_ticket(); + } + +KDF* Handshake_State::protocol_specific_prf() const + { + if(version().supports_ciphersuite_specific_prf()) + { + const std::string prf_algo = ciphersuite().prf_algo(); + + if(prf_algo == "MD5" || prf_algo == "SHA-1") + return get_kdf("TLS-12-PRF(SHA-256)"); + + return get_kdf("TLS-12-PRF(" + prf_algo + ")"); + } + + // Old PRF used in TLS v1.0, v1.1 and DTLS v1.0 + return get_kdf("TLS-PRF"); + } + +std::pair +Handshake_State::choose_sig_format(const Private_Key& key, + Signature_Scheme& chosen_scheme, + bool for_client_auth, + const Policy& policy) const + { + const std::string sig_algo = key.algo_name(); + + if(this->version().supports_negotiable_signature_algorithms()) + { + const std::vector allowed = policy.allowed_signature_schemes(); + + std::vector requested = + (for_client_auth) ? cert_req()->signature_schemes() : client_hello()->signature_schemes(); + + if(requested.empty()) + { + // Implicit SHA-1 + requested.push_back(Signature_Scheme::RSA_PKCS1_SHA1); + requested.push_back(Signature_Scheme::ECDSA_SHA1); + requested.push_back(Signature_Scheme::DSA_SHA1); + } + + for(Signature_Scheme scheme : allowed) + { + if(signature_scheme_is_known(scheme) == false) + { + continue; + } + + if(signature_algorithm_of_scheme(scheme) == sig_algo) + { + if(std::find(requested.begin(), requested.end(), scheme) != requested.end()) + { + chosen_scheme = scheme; + break; + } + } + } + + const std::string hash = hash_function_of_scheme(chosen_scheme); + + if(!policy.allowed_signature_hash(hash)) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Policy refuses to accept signing with any hash supported by peer"); + } + + if(sig_algo == "RSA") + { + return std::make_pair(padding_string_for_scheme(chosen_scheme), IEEE_1363); + } + else if(sig_algo == "DSA" || sig_algo == "ECDSA") + { + return std::make_pair(padding_string_for_scheme(chosen_scheme), DER_SEQUENCE); + } + } + else + { + if(sig_algo == "RSA") + { + const std::string padding = "PKCS1v15(Parallel(MD5,SHA-160))"; + return std::make_pair(padding, IEEE_1363); + } + else if(sig_algo == "DSA" || sig_algo == "ECDSA") + { + const std::string padding = "EMSA1(SHA-1)"; + return std::make_pair(padding, DER_SEQUENCE); + } + } + + throw Invalid_Argument(sig_algo + " is invalid/unknown for TLS signatures"); + } + +namespace { + +bool supported_algos_include( + const std::vector& schemes, + const std::string& key_type, + const std::string& hash_type) + { + for(Signature_Scheme scheme : schemes) + { + if(signature_scheme_is_known(scheme) && + hash_function_of_scheme(scheme) == hash_type && + signature_algorithm_of_scheme(scheme) == key_type) + { + return true; + } + } + + return false; + } + +} + +std::pair +Handshake_State::parse_sig_format(const Public_Key& key, + Signature_Scheme scheme, + bool for_client_auth, + const Policy& policy) const + { + const std::string key_type = key.algo_name(); + + if(!policy.allowed_signature_method(key_type)) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Rejecting " + key_type + " signature"); + } + + if(this->version().supports_negotiable_signature_algorithms() == false) + { + if(scheme != Signature_Scheme::NONE) + throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); + + /* + There is no check on the acceptability of a v1.0/v1.1 hash type, + since it's implicit with use of the protocol + */ + + if(key_type == "RSA") + { + const std::string padding = "PKCS1v15(Parallel(MD5,SHA-160))"; + return std::make_pair(padding, IEEE_1363); + } + else if(key_type == "DSA" || key_type == "ECDSA") + { + const std::string padding = "EMSA1(SHA-1)"; + return std::make_pair(padding, DER_SEQUENCE); + } + else + throw Invalid_Argument(key_type + " is invalid/unknown for TLS signatures"); + } + + if(scheme == Signature_Scheme::NONE) + throw Decoding_Error("Counterparty did not send hash/sig IDS"); + + if(key_type != signature_algorithm_of_scheme(scheme)) + throw Decoding_Error("Counterparty sent inconsistent key and sig types"); + + if(for_client_auth && !cert_req()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "No certificate verify set"); + } + + /* + Confirm the signature type we just received against the + supported_algos list that we sent; it better be there. + */ + + const std::vector supported_algos = + for_client_auth ? cert_req()->signature_schemes() : + client_hello()->signature_schemes(); + + if(!signature_scheme_is_known(scheme)) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Peer sent unknown signature scheme"); + + const std::string hash_algo = hash_function_of_scheme(scheme); + + if(!supported_algos_include(supported_algos, key_type, hash_algo)) + { + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "TLS signature extension did not allow for " + + key_type + "/" + hash_algo + " signature"); + } + + if(key_type == "RSA") + { + return std::make_pair(padding_string_for_scheme(scheme), IEEE_1363); + } + else if(key_type == "DSA" || key_type == "ECDSA") + { + return std::make_pair(padding_string_for_scheme(scheme), DER_SEQUENCE); + } + + throw Invalid_Argument(key_type + " is invalid/unknown for TLS signatures"); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_handshake_state.h b/comm/third_party/botan/src/lib/tls/tls_handshake_state.h new file mode 100644 index 0000000000..3321a6210e --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_handshake_state.h @@ -0,0 +1,206 @@ +/* +* TLS Handshake State +* (C) 2004-2006,2011,2012 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_STATE_H_ +#define BOTAN_TLS_HANDSHAKE_STATE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class KDF; + +namespace TLS { + +class Callbacks; +class Policy; + +class Hello_Verify_Request; +class Client_Hello; +class Server_Hello; +class Certificate; +class Certificate_Status; +class Server_Key_Exchange; +class Certificate_Req; +class Server_Hello_Done; +class Certificate; +class Client_Key_Exchange; +class Certificate_Verify; +class New_Session_Ticket; +class Finished; + +/** +* SSL/TLS Handshake State +*/ +class Handshake_State + { + public: + Handshake_State(Handshake_IO* io, Callbacks& callbacks); + + virtual ~Handshake_State() = default; + + Handshake_State(const Handshake_State&) = delete; + Handshake_State& operator=(const Handshake_State&) = delete; + + Handshake_IO& handshake_io() { return *m_handshake_io; } + + /** + * Return true iff we have received a particular message already + * @param msg_type the message type + */ + bool received_handshake_msg(Handshake_Type msg_type) const; + + /** + * Confirm that we were expecting this message type + * @param msg_type the message type + */ + void confirm_transition_to(Handshake_Type msg_type); + + /** + * Record that we are expecting a particular message type next + * @param msg_type the message type + */ + void set_expected_next(Handshake_Type msg_type); + + std::pair> + get_next_handshake_msg(); + + std::vector session_ticket() const; + + std::pair + parse_sig_format(const Public_Key& key, + Signature_Scheme scheme, + bool for_client_auth, + const Policy& policy) const; + + std::pair + choose_sig_format(const Private_Key& key, + Signature_Scheme& scheme, + bool for_client_auth, + const Policy& policy) const; + + std::string srp_identifier() const; + + KDF* protocol_specific_prf() const; + + Protocol_Version version() const { return m_version; } + + void set_version(const Protocol_Version& version); + + void hello_verify_request(const Hello_Verify_Request& hello_verify); + + void client_hello(Client_Hello* client_hello); + void server_hello(Server_Hello* server_hello); + void server_certs(Certificate* server_certs); + void server_cert_status(Certificate_Status* server_cert_status); + void server_kex(Server_Key_Exchange* server_kex); + void cert_req(Certificate_Req* cert_req); + void server_hello_done(Server_Hello_Done* server_hello_done); + void client_certs(Certificate* client_certs); + void client_kex(Client_Key_Exchange* client_kex); + void client_verify(Certificate_Verify* client_verify); + void new_session_ticket(New_Session_Ticket* new_session_ticket); + void server_finished(Finished* server_finished); + void client_finished(Finished* client_finished); + + const Client_Hello* client_hello() const + { return m_client_hello.get(); } + + const Server_Hello* server_hello() const + { return m_server_hello.get(); } + + const Certificate* server_certs() const + { return m_server_certs.get(); } + + const Server_Key_Exchange* server_kex() const + { return m_server_kex.get(); } + + const Certificate_Req* cert_req() const + { return m_cert_req.get(); } + + const Server_Hello_Done* server_hello_done() const + { return m_server_hello_done.get(); } + + const Certificate* client_certs() const + { return m_client_certs.get(); } + + const Client_Key_Exchange* client_kex() const + { return m_client_kex.get(); } + + const Certificate_Verify* client_verify() const + { return m_client_verify.get(); } + + const Certificate_Status* server_cert_status() const + { return m_server_cert_status.get(); } + + const New_Session_Ticket* new_session_ticket() const + { return m_new_session_ticket.get(); } + + const Finished* server_finished() const + { return m_server_finished.get(); } + + const Finished* client_finished() const + { return m_client_finished.get(); } + + const Ciphersuite& ciphersuite() const { return m_ciphersuite; } + + const Session_Keys& session_keys() const { return m_session_keys; } + + Callbacks& callbacks() const { return m_callbacks; } + + void compute_session_keys(); + + void compute_session_keys(const secure_vector& resume_master_secret); + + Handshake_Hash& hash() { return m_handshake_hash; } + + const Handshake_Hash& hash() const { return m_handshake_hash; } + + void note_message(const Handshake_Message& msg); + private: + + Callbacks& m_callbacks; + + std::unique_ptr m_handshake_io; + + uint32_t m_hand_expecting_mask = 0; + uint32_t m_hand_received_mask = 0; + Protocol_Version m_version; + Ciphersuite m_ciphersuite; + Session_Keys m_session_keys; + Handshake_Hash m_handshake_hash; + + std::unique_ptr m_client_hello; + std::unique_ptr m_server_hello; + std::unique_ptr m_server_certs; + std::unique_ptr m_server_cert_status; + std::unique_ptr m_server_kex; + std::unique_ptr m_cert_req; + std::unique_ptr m_server_hello_done; + std::unique_ptr m_client_certs; + std::unique_ptr m_client_kex; + std::unique_ptr m_client_verify; + std::unique_ptr m_new_session_ticket; + std::unique_ptr m_server_finished; + std::unique_ptr m_client_finished; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_magic.h b/comm/third_party/botan/src/lib/tls/tls_magic.h new file mode 100644 index 0000000000..49d69c7d89 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_magic.h @@ -0,0 +1,72 @@ +/* +* SSL/TLS Protocol Constants +* (C) 2004-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H_ +#define BOTAN_TLS_PROTOCOL_MAGIC_H_ + +#include + +//BOTAN_FUTURE_INTERNAL_HEADER(tls_magic.h) + +namespace Botan { + +namespace TLS { + +/** +* Protocol Constants for SSL/TLS +*/ +enum Size_Limits { + TLS_HEADER_SIZE = 5, + DTLS_HEADER_SIZE = TLS_HEADER_SIZE + 8, + + MAX_PLAINTEXT_SIZE = 16*1024, + MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024, + MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024, +}; + +// This will become an enum class in a future major release +enum Connection_Side { CLIENT = 1, SERVER = 2 }; + +// This will become an enum class in a future major release +enum Record_Type { + CHANGE_CIPHER_SPEC = 20, + ALERT = 21, + HANDSHAKE = 22, + APPLICATION_DATA = 23, + + NO_RECORD = 256 +}; + +// This will become an enum class in a future major release +enum Handshake_Type { + HELLO_REQUEST = 0, + CLIENT_HELLO = 1, + SERVER_HELLO = 2, + HELLO_VERIFY_REQUEST = 3, + NEW_SESSION_TICKET = 4, // RFC 5077 + CERTIFICATE = 11, + SERVER_KEX = 12, + CERTIFICATE_REQUEST = 13, + SERVER_HELLO_DONE = 14, + CERTIFICATE_VERIFY = 15, + CLIENT_KEX = 16, + FINISHED = 20, + + CERTIFICATE_URL = 21, + CERTIFICATE_STATUS = 22, + + HANDSHAKE_CCS = 254, // Not a wire value + HANDSHAKE_NONE = 255 // Null value +}; + +const char* handshake_type_to_string(Handshake_Type t); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_messages.h b/comm/third_party/botan/src/lib/tls/tls_messages.h new file mode 100644 index 0000000000..fc95a1c020 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_messages.h @@ -0,0 +1,653 @@ +/* +* TLS Messages +* (C) 2004-2011,2015 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_MESSAGES_H_ +#define BOTAN_TLS_MESSAGES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_CECPQ1) + #include +#endif + +#if defined(BOTAN_HAS_SRP6) + #include +#endif + +namespace Botan { + +class Public_Key; +class Credentials_Manager; + +namespace TLS { + +class Session; +class Handshake_IO; +class Handshake_State; +class Callbacks; + +std::vector make_hello_random(RandomNumberGenerator& rng, + const Policy& policy); + +/** +* DTLS Hello Verify Request +*/ +class BOTAN_UNSTABLE_API Hello_Verify_Request final : public Handshake_Message + { + public: + std::vector serialize() const override; + Handshake_Type type() const override { return HELLO_VERIFY_REQUEST; } + + const std::vector& cookie() const { return m_cookie; } + + explicit Hello_Verify_Request(const std::vector& buf); + + Hello_Verify_Request(const std::vector& client_hello_bits, + const std::string& client_identity, + const SymmetricKey& secret_key); + private: + std::vector m_cookie; + }; + +/** +* Client Hello Message +*/ +class BOTAN_UNSTABLE_API Client_Hello final : public Handshake_Message + { + public: + class Settings final + { + public: + Settings(const Protocol_Version version, + const std::string& hostname = "", + const std::string& srp_identifier = "") : + m_new_session_version(version), + m_hostname(hostname), + m_srp_identifier(srp_identifier) {} + + const Protocol_Version protocol_version() const { return m_new_session_version; } + const std::string& hostname() const { return m_hostname; } + const std::string& srp_identifier() const { return m_srp_identifier; } + + private: + const Protocol_Version m_new_session_version; + const std::string m_hostname; + const std::string m_srp_identifier; + }; + + Handshake_Type type() const override { return CLIENT_HELLO; } + + Protocol_Version version() const { return m_version; } + + std::vector supported_versions() const; + + const std::vector& random() const { return m_random; } + + const std::vector& session_id() const { return m_session_id; } + + const std::vector& compression_methods() const { return m_comp_methods; } + + const std::vector& ciphersuites() const { return m_suites; } + + bool offered_suite(uint16_t ciphersuite) const; + + bool sent_fallback_scsv() const; + + std::vector signature_schemes() const; + + std::vector supported_ecc_curves() const; + + std::vector supported_dh_groups() const; + + bool prefers_compressed_ec_points() const; + + std::string sni_hostname() const; + +#if defined(BOTAN_HAS_SRP6) + std::string srp_identifier() const; +#endif + + bool secure_renegotiation() const; + + std::vector renegotiation_info() const; + + bool supports_session_ticket() const; + + std::vector session_ticket() const; + + bool supports_alpn() const; + + bool supports_extended_master_secret() const; + + bool supports_cert_status_message() const; + + bool supports_encrypt_then_mac() const; + + bool sent_signature_algorithms() const; + + std::vector next_protocols() const; + + std::vector srtp_profiles() const; + + void update_hello_cookie(const Hello_Verify_Request& hello_verify); + + const std::vector& cookie() const { return m_hello_cookie; } + + std::vector cookie_input_data() const; + + std::set extension_types() const + { return m_extensions.extension_types(); } + + const Extensions& extensions() const { return m_extensions; } + + Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Client_Hello::Settings& client_settings, + const std::vector& next_protocols); + + Client_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& reneg_info, + const Session& resumed_session, + const std::vector& next_protocols); + + explicit Client_Hello(const std::vector& buf); + + private: + std::vector serialize() const override; + + Protocol_Version m_version; + std::vector m_session_id; + std::vector m_random; + std::vector m_suites; + std::vector m_comp_methods; + std::vector m_hello_cookie; // DTLS only + + Extensions m_extensions; + }; + +/** +* Server Hello Message +*/ +class BOTAN_UNSTABLE_API Server_Hello final : public Handshake_Message + { + public: + class Settings final + { + public: + Settings(const std::vector new_session_id, + Protocol_Version new_session_version, + uint16_t ciphersuite, + bool offer_session_ticket) : + m_new_session_id(new_session_id), + m_new_session_version(new_session_version), + m_ciphersuite(ciphersuite), + m_offer_session_ticket(offer_session_ticket) {} + + const std::vector& session_id() const { return m_new_session_id; } + Protocol_Version protocol_version() const { return m_new_session_version; } + uint16_t ciphersuite() const { return m_ciphersuite; } + bool offer_session_ticket() const { return m_offer_session_ticket; } + + private: + const std::vector m_new_session_id; + Protocol_Version m_new_session_version; + uint16_t m_ciphersuite; + bool m_offer_session_ticket; + }; + + + Handshake_Type type() const override { return SERVER_HELLO; } + + Protocol_Version version() const { return m_version; } + + const std::vector& random() const { return m_random; } + + const std::vector& session_id() const { return m_session_id; } + + uint16_t ciphersuite() const { return m_ciphersuite; } + + uint8_t compression_method() const { return m_comp_method; } + + bool secure_renegotiation() const + { + return m_extensions.has(); + } + + std::vector renegotiation_info() const + { + if(Renegotiation_Extension* reneg = m_extensions.get()) + return reneg->renegotiation_info(); + return std::vector(); + } + + bool supports_extended_master_secret() const + { + return m_extensions.has(); + } + + bool supports_encrypt_then_mac() const + { + return m_extensions.has(); + } + + bool supports_certificate_status_message() const + { + return m_extensions.has(); + } + + bool supports_session_ticket() const + { + return m_extensions.has(); + } + + uint16_t srtp_profile() const + { + if(auto srtp = m_extensions.get()) + { + auto prof = srtp->profiles(); + if(prof.size() != 1 || prof[0] == 0) + throw Decoding_Error("Server sent malformed DTLS-SRTP extension"); + return prof[0]; + } + + return 0; + } + + std::string next_protocol() const + { + if(auto alpn = m_extensions.get()) + return alpn->single_protocol(); + return ""; + } + + std::set extension_types() const + { return m_extensions.extension_types(); } + + const Extensions& extensions() const { return m_extensions; } + + bool prefers_compressed_ec_points() const + { + if(auto ecc_formats = m_extensions.get()) + { + return ecc_formats->prefers_compressed(); + } + return false; + } + + bool random_signals_downgrade() const; + + Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& secure_reneg_info, + const Client_Hello& client_hello, + const Server_Hello::Settings& settings, + const std::string next_protocol); + + Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector& secure_reneg_info, + const Client_Hello& client_hello, + Session& resumed_session, + bool offer_session_ticket, + const std::string& next_protocol); + + explicit Server_Hello(const std::vector& buf); + private: + std::vector serialize() const override; + + Protocol_Version m_version; + std::vector m_session_id, m_random; + uint16_t m_ciphersuite; + uint8_t m_comp_method; + + Extensions m_extensions; + }; + +/** +* Client Key Exchange Message +*/ +class BOTAN_UNSTABLE_API Client_Key_Exchange final : public Handshake_Message + { + public: + Handshake_Type type() const override { return CLIENT_KEX; } + + const secure_vector& pre_master_secret() const + { return m_pre_master; } + + Client_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + const Public_Key* server_public_key, + const std::string& hostname, + RandomNumberGenerator& rng); + + Client_Key_Exchange(const std::vector& buf, + const Handshake_State& state, + const Private_Key* server_rsa_kex_key, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng); + + private: + std::vector serialize() const override + { return m_key_material; } + + std::vector m_key_material; + secure_vector m_pre_master; + }; + +/** +* Certificate Message +*/ +class BOTAN_UNSTABLE_API Certificate final : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE; } + const std::vector& cert_chain() const { return m_certs; } + + size_t count() const { return m_certs.size(); } + bool empty() const { return m_certs.empty(); } + + Certificate(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& certs); + + explicit Certificate(const std::vector& buf, const Policy &policy); + private: + std::vector serialize() const override; + + std::vector m_certs; + }; + +/** +* Certificate Status (RFC 6066) +*/ +class BOTAN_UNSTABLE_API Certificate_Status final : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE_STATUS; } + + //std::shared_ptr response() const { return m_response; } + + const std::vector& response() const { return m_response; } + + Certificate_Status(const std::vector& buf); + + Certificate_Status(Handshake_IO& io, + Handshake_Hash& hash, + std::shared_ptr response); + + /* + * Create a Certificate_Status message using an already DER encoded OCSP response. + */ + Certificate_Status(Handshake_IO& io, + Handshake_Hash& hash, + std::vector const& raw_response_bytes ); + + private: + std::vector serialize() const override; + std::vector m_response; + }; + +/** +* Certificate Request Message +*/ +class BOTAN_UNSTABLE_API Certificate_Req final : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE_REQUEST; } + + const std::vector& acceptable_cert_types() const + { return m_cert_key_types; } + + const std::vector& acceptable_CAs() const { return m_names; } + + const std::vector& signature_schemes() const + { + return m_schemes; + } + + Certificate_Req(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + const std::vector& allowed_cas, + Protocol_Version version); + + Certificate_Req(const std::vector& buf, + Protocol_Version version); + private: + std::vector serialize() const override; + + std::vector m_names; + std::vector m_cert_key_types; + + std::vector m_schemes; + }; + +/** +* Certificate Verify Message +*/ +class BOTAN_UNSTABLE_API Certificate_Verify final : public Handshake_Message + { + public: + Handshake_Type type() const override { return CERTIFICATE_VERIFY; } + + /** + * Check the signature on a certificate verify message + * @param cert the purported certificate + * @param state the handshake state + * @param policy the TLS policy + */ + bool verify(const X509_Certificate& cert, + const Handshake_State& state, + const Policy& policy) const; + + Certificate_Verify(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + RandomNumberGenerator& rng, + const Private_Key* key); + + Certificate_Verify(const std::vector& buf, + Protocol_Version version); + private: + std::vector serialize() const override; + + std::vector m_signature; + Signature_Scheme m_scheme = Signature_Scheme::NONE; + }; + +/** +* Finished Message +*/ +class BOTAN_UNSTABLE_API Finished final : public Handshake_Message + { + public: + Handshake_Type type() const override { return FINISHED; } + + std::vector verify_data() const + { return m_verification_data; } + + bool verify(const Handshake_State& state, + Connection_Side side) const; + + Finished(Handshake_IO& io, + Handshake_State& state, + Connection_Side side); + + explicit Finished(const std::vector& buf); + private: + std::vector serialize() const override; + + std::vector m_verification_data; + }; + +/** +* Hello Request Message +*/ +class BOTAN_UNSTABLE_API Hello_Request final : public Handshake_Message + { + public: + Handshake_Type type() const override { return HELLO_REQUEST; } + + explicit Hello_Request(Handshake_IO& io); + explicit Hello_Request(const std::vector& buf); + private: + std::vector serialize() const override; + }; + +/** +* Server Key Exchange Message +*/ +class BOTAN_UNSTABLE_API Server_Key_Exchange final : public Handshake_Message + { + public: + Handshake_Type type() const override { return SERVER_KEX; } + + const std::vector& params() const { return m_params; } + + bool verify(const Public_Key& server_key, + const Handshake_State& state, + const Policy& policy) const; + + // Only valid for certain kex types + const Private_Key& server_kex_key() const; + +#if defined(BOTAN_HAS_SRP6) + // Only valid for SRP negotiation + SRP6_Server_Session& server_srp_params() const + { + BOTAN_ASSERT_NONNULL(m_srp_params); + return *m_srp_params; + } +#endif + +#if defined(BOTAN_HAS_CECPQ1) + // Only valid for CECPQ1 negotiation + const CECPQ1_key& cecpq1_key() const + { + BOTAN_ASSERT_NONNULL(m_cecpq1_key); + return *m_cecpq1_key; + } +#endif + + Server_Key_Exchange(Handshake_IO& io, + Handshake_State& state, + const Policy& policy, + Credentials_Manager& creds, + RandomNumberGenerator& rng, + const Private_Key* signing_key = nullptr); + + Server_Key_Exchange(const std::vector& buf, + Kex_Algo kex_alg, + Auth_Method sig_alg, + Protocol_Version version); + + ~Server_Key_Exchange() = default; + private: + std::vector serialize() const override; + +#if defined(BOTAN_HAS_SRP6) + std::unique_ptr m_srp_params; +#endif + +#if defined(BOTAN_HAS_CECPQ1) + std::unique_ptr m_cecpq1_key; +#endif + + std::unique_ptr m_kex_key; + + std::vector m_params; + + std::vector m_signature; + Signature_Scheme m_scheme = Signature_Scheme::NONE; + }; + +/** +* Server Hello Done Message +*/ +class BOTAN_UNSTABLE_API Server_Hello_Done final : public Handshake_Message + { + public: + Handshake_Type type() const override { return SERVER_HELLO_DONE; } + + Server_Hello_Done(Handshake_IO& io, Handshake_Hash& hash); + explicit Server_Hello_Done(const std::vector& buf); + private: + std::vector serialize() const override; + }; + +/** +* New Session Ticket Message +*/ +class BOTAN_UNSTABLE_API New_Session_Ticket final : public Handshake_Message + { + public: + Handshake_Type type() const override { return NEW_SESSION_TICKET; } + + uint32_t ticket_lifetime_hint() const { return m_ticket_lifetime_hint; } + const std::vector& ticket() const { return m_ticket; } + + New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash, + const std::vector& ticket, + uint32_t lifetime); + + New_Session_Ticket(Handshake_IO& io, + Handshake_Hash& hash); + + explicit New_Session_Ticket(const std::vector& buf); + private: + std::vector serialize() const override; + + uint32_t m_ticket_lifetime_hint = 0; + std::vector m_ticket; + }; + +/** +* Change Cipher Spec +*/ +class BOTAN_UNSTABLE_API Change_Cipher_Spec final : public Handshake_Message + { + public: + Handshake_Type type() const override { return HANDSHAKE_CCS; } + + std::vector serialize() const override + { return std::vector(1, 1); } + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_policy.cpp b/comm/third_party/botan/src/lib/tls/tls_policy.cpp new file mode 100644 index 0000000000..17fe288f19 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_policy.cpp @@ -0,0 +1,616 @@ +/* +* Policies for TLS +* (C) 2004-2010,2012,2015,2016 Jack Lloyd +* 2016 Christian Mainka +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +std::vector Policy::allowed_signature_schemes() const + { + std::vector schemes; + + for(Signature_Scheme scheme : all_signature_schemes()) + { + if(signature_scheme_is_known(scheme) == false) + continue; + const bool sig_allowed = allowed_signature_method(signature_algorithm_of_scheme(scheme)); + const bool hash_allowed = allowed_signature_hash(hash_function_of_scheme(scheme)); + + if(sig_allowed && hash_allowed) + { + schemes.push_back(scheme); + } + } + + return schemes; + } + +std::vector Policy::allowed_ciphers() const + { + return { + //"AES-256/OCB(12)", + //"AES-128/OCB(12)", + "ChaCha20Poly1305", + "AES-256/GCM", + "AES-128/GCM", + //"AES-256/CCM", + //"AES-128/CCM", + //"AES-256/CCM(8)", + //"AES-128/CCM(8)", + //"Camellia-256/GCM", + //"Camellia-128/GCM", + //"ARIA-256/GCM", + //"ARIA-128/GCM", + //"AES-256", + //"AES-128", + //"Camellia-256", + //"Camellia-128", + //"SEED", + //"3DES", + }; + } + +std::vector Policy::allowed_signature_hashes() const + { + return { + "SHA-512", + "SHA-384", + "SHA-256", + //"SHA-1", + }; + } + +std::vector Policy::allowed_macs() const + { + /* + SHA-256 is preferred because the Lucky13 countermeasure works + somewhat better for SHA-256 vs SHA-384: + https://github.com/randombit/botan/pull/675 + */ + return { + "AEAD", + "SHA-256", + "SHA-384", + "SHA-1", + }; + } + +std::vector Policy::allowed_key_exchange_methods() const + { + return { + //"SRP_SHA", + //"ECDHE_PSK", + //"DHE_PSK", + //"PSK", + "CECPQ1", + "ECDH", + "DH", + //"RSA", + }; + } + +std::vector Policy::allowed_signature_methods() const + { + return { + "ECDSA", + "RSA", + //"DSA", + //"IMPLICIT", + //"ANONYMOUS" (anon) + }; + } + +bool Policy::allowed_signature_method(const std::string& sig_method) const + { + return value_exists(allowed_signature_methods(), sig_method); + } + +bool Policy::allowed_signature_hash(const std::string& sig_hash) const + { + return value_exists(allowed_signature_hashes(), sig_hash); + } + +bool Policy::use_ecc_point_compression() const + { + return false; + } + +Group_Params Policy::choose_key_exchange_group(const std::vector& peer_groups) const + { + if(peer_groups.empty()) + return Group_Params::NONE; + + const std::vector our_groups = key_exchange_groups(); + + for(auto g : our_groups) + { + if(value_exists(peer_groups, g)) + return g; + } + + return Group_Params::NONE; + } + +Group_Params Policy::default_dh_group() const + { + /* + * Return the first listed or just default to 2048 + */ + for(auto g : key_exchange_groups()) + { + if(group_param_is_dh(g)) + return g; + } + + return Group_Params::FFDHE_2048; + } + +std::vector Policy::key_exchange_groups() const + { + // Default list is ordered by performance + return { + +#if defined(BOTAN_HAS_CURVE_25519) + Group_Params::X25519, +#endif + + Group_Params::SECP256R1, + Group_Params::BRAINPOOL256R1, + Group_Params::SECP384R1, + Group_Params::BRAINPOOL384R1, + Group_Params::SECP521R1, + Group_Params::BRAINPOOL512R1, + + Group_Params::FFDHE_2048, + Group_Params::FFDHE_3072, + Group_Params::FFDHE_4096, + Group_Params::FFDHE_6144, + Group_Params::FFDHE_8192, + }; + } + +size_t Policy::minimum_dh_group_size() const + { + return 2048; + } + +size_t Policy::minimum_ecdsa_group_size() const + { + // Here we are at the mercy of whatever the CA signed, but most certs should be 256 bit by now + return 256; + } + +size_t Policy::minimum_ecdh_group_size() const + { + // x25519 is smallest curve currently supported for TLS key exchange + return 255; + } + +size_t Policy::minimum_signature_strength() const + { + return 110; + } + +bool Policy::require_cert_revocation_info() const + { + return true; + } + +size_t Policy::minimum_rsa_bits() const + { + /* Default assumption is all end-entity certificates should + be at least 2048 bits these days. + + If you are connecting to arbitrary servers on the Internet + (ie as a web browser or SMTP client) you'll probably have to reduce this + to 1024 bits, or perhaps even lower. + */ + return 2048; + } + +size_t Policy::minimum_dsa_group_size() const + { + // FIPS 186-3 + return 2048; + } + +void Policy::check_peer_key_acceptable(const Public_Key& public_key) const + { + const std::string algo_name = public_key.algo_name(); + + const size_t keylength = public_key.key_length(); + size_t expected_keylength = 0; + + if(algo_name == "RSA") + { + expected_keylength = minimum_rsa_bits(); + } + else if(algo_name == "DH") + { + expected_keylength = minimum_dh_group_size(); + } + else if(algo_name == "DSA") + { + expected_keylength = minimum_dsa_group_size(); + } + else if(algo_name == "ECDH" || algo_name == "Curve25519") + { + expected_keylength = minimum_ecdh_group_size(); + } + else if(algo_name == "ECDSA") + { + expected_keylength = minimum_ecdsa_group_size(); + } + // else some other algo, so leave expected_keylength as zero and the check is a no-op + + if(keylength < expected_keylength) + throw TLS_Exception(Alert::INSUFFICIENT_SECURITY, + "Peer sent " + + std::to_string(keylength) + " bit " + algo_name + " key" + ", policy requires at least " + + std::to_string(expected_keylength)); + } + +uint32_t Policy::session_ticket_lifetime() const + { + return 86400; // ~1 day + } + +bool Policy::send_fallback_scsv(Protocol_Version version) const + { + return version != latest_supported_version(version.is_datagram_protocol()); + } + +bool Policy::acceptable_protocol_version(Protocol_Version version) const + { + if(version == Protocol_Version::TLS_V12 && allow_tls12()) + return true; + + if(version == Protocol_Version::DTLS_V12 && allow_dtls12()) + return true; + +#if defined(BOTAN_HAS_TLS_V10) + + if(version == Protocol_Version::TLS_V11 && allow_tls11()) + return true; + if(version == Protocol_Version::TLS_V10 && allow_tls10()) + return true; + if(version == Protocol_Version::DTLS_V10 && allow_dtls10()) + return true; + +#endif + + return false; + } + +Protocol_Version Policy::latest_supported_version(bool datagram) const + { + if(datagram) + { + if(acceptable_protocol_version(Protocol_Version::DTLS_V12)) + return Protocol_Version::DTLS_V12; +#if defined(BOTAN_HAS_TLS_V10) + if(acceptable_protocol_version(Protocol_Version::DTLS_V10)) + return Protocol_Version::DTLS_V10; +#endif + throw Invalid_State("Policy forbids all available DTLS version"); + } + else + { + if(acceptable_protocol_version(Protocol_Version::TLS_V12)) + return Protocol_Version::TLS_V12; +#if defined(BOTAN_HAS_TLS_V10) + if(acceptable_protocol_version(Protocol_Version::TLS_V11)) + return Protocol_Version::TLS_V11; + if(acceptable_protocol_version(Protocol_Version::TLS_V10)) + return Protocol_Version::TLS_V10; +#endif + throw Invalid_State("Policy forbids all available TLS version"); + } + } + +bool Policy::acceptable_ciphersuite(const Ciphersuite& ciphersuite) const + { + return value_exists(allowed_ciphers(), ciphersuite.cipher_algo()) && + value_exists(allowed_macs(), ciphersuite.mac_algo()); + } + +bool Policy::allow_client_initiated_renegotiation() const { return false; } +bool Policy::allow_server_initiated_renegotiation() const { return false; } +bool Policy::allow_insecure_renegotiation() const { return false; } +bool Policy::allow_tls10() const { return false; } +bool Policy::allow_tls11() const { return false; } +bool Policy::allow_tls12() const { return true; } +bool Policy::allow_dtls10() const { return false; } +bool Policy::allow_dtls12() const { return true; } +bool Policy::include_time_in_hello_random() const { return true; } +bool Policy::hide_unknown_users() const { return false; } +bool Policy::server_uses_own_ciphersuite_preferences() const { return true; } +bool Policy::negotiate_encrypt_then_mac() const { return true; } +bool Policy::support_cert_status_message() const { return true; } +bool Policy::allow_resumption_for_renegotiation() const { return true; } +bool Policy::only_resume_with_exact_version() const { return true; } +bool Policy::require_client_certificate_authentication() const { return false; } +bool Policy::request_client_certificate_authentication() const { return require_client_certificate_authentication(); } +bool Policy::abort_connection_on_undesired_renegotiation() const { return false; } +bool Policy::allow_dtls_epoch0_restart() const { return false; } + +size_t Policy::maximum_certificate_chain_size() const { return 0; } + +// 1 second initial timeout, 60 second max - see RFC 6347 sec 4.2.4.1 +size_t Policy::dtls_initial_timeout() const { return 1*1000; } +size_t Policy::dtls_maximum_timeout() const { return 60*1000; } + +size_t Policy::dtls_default_mtu() const + { + // default MTU is IPv6 min MTU minus UDP/IP headers + return 1280 - 40 - 8; + } + +std::vector Policy::srtp_profiles() const + { + return std::vector(); + } + +namespace { + +class Ciphersuite_Preference_Ordering final + { + public: + Ciphersuite_Preference_Ordering(const std::vector& ciphers, + const std::vector& macs, + const std::vector& kex, + const std::vector& sigs) : + m_ciphers(ciphers), m_macs(macs), m_kex(kex), m_sigs(sigs) {} + + bool operator()(const Ciphersuite& a, const Ciphersuite& b) const + { + if(a.kex_method() != b.kex_method()) + { + for(size_t i = 0; i != m_kex.size(); ++i) + { + if(a.kex_algo() == m_kex[i]) + return true; + if(b.kex_algo() == m_kex[i]) + return false; + } + } + + if(a.cipher_algo() != b.cipher_algo()) + { + for(size_t i = 0; i != m_ciphers.size(); ++i) + { + if(a.cipher_algo() == m_ciphers[i]) + return true; + if(b.cipher_algo() == m_ciphers[i]) + return false; + } + } + + if(a.cipher_keylen() != b.cipher_keylen()) + { + if(a.cipher_keylen() < b.cipher_keylen()) + return false; + if(a.cipher_keylen() > b.cipher_keylen()) + return true; + } + + if(a.auth_method() != b.auth_method()) + { + for(size_t i = 0; i != m_sigs.size(); ++i) + { + if(a.sig_algo() == m_sigs[i]) + return true; + if(b.sig_algo() == m_sigs[i]) + return false; + } + } + + if(a.mac_algo() != b.mac_algo()) + { + for(size_t i = 0; i != m_macs.size(); ++i) + { + if(a.mac_algo() == m_macs[i]) + return true; + if(b.mac_algo() == m_macs[i]) + return false; + } + } + + return false; // equal (?!?) + } + private: + std::vector m_ciphers, m_macs, m_kex, m_sigs; + }; + +} + +std::vector Policy::ciphersuite_list(Protocol_Version version, + bool have_srp) const + { + const std::vector ciphers = allowed_ciphers(); + const std::vector macs = allowed_macs(); + const std::vector kex = allowed_key_exchange_methods(); + const std::vector sigs = allowed_signature_methods(); + + std::vector ciphersuites; + + for(auto&& suite : Ciphersuite::all_known_ciphersuites()) + { + // Can we use it? + if(!suite.valid()) + continue; + + // Can we use it in this version? + if(!suite.usable_in_version(version)) + continue; + + // Is it acceptable to the policy? + if(!this->acceptable_ciphersuite(suite)) + continue; + + // Are we doing SRP? + if(!have_srp && suite.kex_method() == Kex_Algo::SRP_SHA) + continue; + + if(!value_exists(kex, suite.kex_algo())) + continue; // unsupported key exchange + + if(!value_exists(ciphers, suite.cipher_algo())) + continue; // unsupported cipher + + if(!value_exists(macs, suite.mac_algo())) + continue; // unsupported MAC algo + + if(!value_exists(sigs, suite.sig_algo())) + { + // allow if it's an empty sig algo and we want to use PSK + if(suite.auth_method() != Auth_Method::IMPLICIT || !suite.psk_ciphersuite()) + continue; + } + + /* + CECPQ1 always uses x25519 for ECDH, so treat the applications + removal of x25519 from the ECC curve list as equivalent to + saying they do not trust CECPQ1 + */ + if(suite.kex_method() == Kex_Algo::CECPQ1) + { + if(value_exists(key_exchange_groups(), Group_Params::X25519) == false) + continue; + } + + // OK, consider it + ciphersuites.push_back(suite); + } + + if(ciphersuites.empty()) + { + throw Invalid_State("Policy does not allow any available cipher suite"); + } + + Ciphersuite_Preference_Ordering order(ciphers, macs, kex, sigs); + std::sort(ciphersuites.begin(), ciphersuites.end(), order); + + std::vector ciphersuite_codes; + for(auto i : ciphersuites) + ciphersuite_codes.push_back(i.ciphersuite_code()); + return ciphersuite_codes; + } + +namespace { + +void print_vec(std::ostream& o, + const char* key, + const std::vector& v) + { + o << key << " = "; + for(size_t i = 0; i != v.size(); ++i) + { + o << v[i]; + if(i != v.size() - 1) + o << ' '; + } + o << '\n'; + } + +void print_vec(std::ostream& o, + const char* key, + const std::vector& v) + { + o << key << " = "; + for(size_t i = 0; i != v.size(); ++i) + { + o << group_param_to_string(v[i]); + if(i != v.size() - 1) + o << ' '; + } + o << '\n'; + } + +void print_bool(std::ostream& o, + const char* key, bool b) + { + o << key << " = " << (b ? "true" : "false") << '\n'; + } + +} + +void Policy::print(std::ostream& o) const + { + print_bool(o, "allow_tls10", allow_tls10()); + print_bool(o, "allow_tls11", allow_tls11()); + print_bool(o, "allow_tls12", allow_tls12()); + print_bool(o, "allow_dtls10", allow_dtls10()); + print_bool(o, "allow_dtls12", allow_dtls12()); + print_vec(o, "ciphers", allowed_ciphers()); + print_vec(o, "macs", allowed_macs()); + print_vec(o, "signature_hashes", allowed_signature_hashes()); + print_vec(o, "signature_methods", allowed_signature_methods()); + print_vec(o, "key_exchange_methods", allowed_key_exchange_methods()); + print_vec(o, "key_exchange_groups", key_exchange_groups()); + + print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation()); + print_bool(o, "include_time_in_hello_random", include_time_in_hello_random()); + print_bool(o, "allow_server_initiated_renegotiation", allow_server_initiated_renegotiation()); + print_bool(o, "hide_unknown_users", hide_unknown_users()); + print_bool(o, "server_uses_own_ciphersuite_preferences", server_uses_own_ciphersuite_preferences()); + print_bool(o, "negotiate_encrypt_then_mac", negotiate_encrypt_then_mac()); + print_bool(o, "support_cert_status_message", support_cert_status_message()); + o << "session_ticket_lifetime = " << session_ticket_lifetime() << '\n'; + o << "minimum_dh_group_size = " << minimum_dh_group_size() << '\n'; + o << "minimum_ecdh_group_size = " << minimum_ecdh_group_size() << '\n'; + o << "minimum_rsa_bits = " << minimum_rsa_bits() << '\n'; + o << "minimum_signature_strength = " << minimum_signature_strength() << '\n'; + } + +std::string Policy::to_string() const + { + std::ostringstream oss; + this->print(oss); + return oss.str(); + } + +std::vector Strict_Policy::allowed_ciphers() const + { + return { "ChaCha20Poly1305", "AES-256/GCM", "AES-128/GCM" }; + } + +std::vector Strict_Policy::allowed_signature_hashes() const + { + return { "SHA-512", "SHA-384"}; + } + +std::vector Strict_Policy::allowed_macs() const + { + return { "AEAD" }; + } + +std::vector Strict_Policy::allowed_key_exchange_methods() const + { + return { "CECPQ1", "ECDH" }; + } + +bool Strict_Policy::allow_tls10() const { return false; } +bool Strict_Policy::allow_tls11() const { return false; } +bool Strict_Policy::allow_tls12() const { return true; } +bool Strict_Policy::allow_dtls10() const { return false; } +bool Strict_Policy::allow_dtls12() const { return true; } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_policy.h b/comm/third_party/botan/src/lib/tls/tls_policy.h new file mode 100644 index 0000000000..4fbbd75453 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_policy.h @@ -0,0 +1,616 @@ +/* +* Hooks for application level policies on TLS connections +* (C) 2004-2006,2013 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_POLICY_H_ +#define BOTAN_TLS_POLICY_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class Public_Key; + +namespace TLS { + +/** +* TLS Policy Base Class +* Inherit and overload as desired to suit local policy concerns +*/ +class BOTAN_PUBLIC_API(2,0) Policy + { + public: + + /** + * Returns a list of ciphers we are willing to negotiate, in + * order of preference. + */ + virtual std::vector allowed_ciphers() const; + + /** + * Returns a list of hash algorithms we are willing to use for + * signatures, in order of preference. + */ + virtual std::vector allowed_signature_hashes() const; + + /** + * Returns a list of MAC algorithms we are willing to use. + */ + virtual std::vector allowed_macs() const; + + /** + * Returns a list of key exchange algorithms we are willing to + * use, in order of preference. Allowed values: DH, empty string + * (representing RSA using server certificate key) + */ + virtual std::vector allowed_key_exchange_methods() const; + + /** + * Returns a list of signature algorithms we are willing to + * use, in order of preference. Allowed values RSA and DSA. + */ + virtual std::vector allowed_signature_methods() const; + + virtual std::vector allowed_signature_schemes() const; + + /** + * The minimum signature strength we will accept + * Returning 80 allows RSA 1024 and SHA-1. Values larger than 80 disable SHA-1 support. + * Returning 110 allows RSA 2048. + * Return 128 to force ECC (P-256) or large (~3000 bit) RSA keys. + * Default is 110 + */ + virtual size_t minimum_signature_strength() const; + + /** + * Return if cert revocation info (CRL/OCSP) is required + * If true, validation will fail unless a valid CRL or OCSP response + * was examined. + */ + virtual bool require_cert_revocation_info() const; + + bool allowed_signature_method(const std::string& sig_method) const; + bool allowed_signature_hash(const std::string& hash) const; + + /** + * Return list of ECC curves and FFDHE groups we are willing to + * use in order of preference. + */ + virtual std::vector key_exchange_groups() const; + + /** + * Request that ECC curve points are sent compressed + */ + virtual bool use_ecc_point_compression() const; + + /** + * Select a key exchange group to use, from the list of groups sent by the + * peer. If none are acceptable, return Group_Params::NONE + */ + virtual Group_Params choose_key_exchange_group(const std::vector& peer_groups) const; + + /** + * Allow renegotiation even if the counterparty doesn't + * support the secure renegotiation extension. + * + * @warning Changing this to true exposes you to injected + * plaintext attacks. Read RFC 5746 for background. + */ + virtual bool allow_insecure_renegotiation() const; + + /** + * The protocol dictates that the first 32 bits of the random + * field are the current time in seconds. However this allows + * client fingerprinting attacks. Set to false to disable, in + * which case random bytes will be used instead. + */ + virtual bool include_time_in_hello_random() const; + + /** + * Consulted by server side. If true, allows clients to initiate a new handshake + */ + virtual bool allow_client_initiated_renegotiation() const; + + /** + * Consulted by client side. If true, allows servers to initiate a new handshake + */ + virtual bool allow_server_initiated_renegotiation() const; + + /** + * If true, a request to renegotiate will close the connection with + * a fatal alert. Otherwise, a warning alert is sent. + */ + virtual bool abort_connection_on_undesired_renegotiation() const; + + virtual bool only_resume_with_exact_version() const; + + /** + * Allow TLS v1.0 + */ + virtual bool allow_tls10() const; + + /** + * Allow TLS v1.1 + */ + virtual bool allow_tls11() const; + + /** + * Allow TLS v1.2 + */ + virtual bool allow_tls12() const; + + /** + * Allow DTLS v1.0 + */ + virtual bool allow_dtls10() const; + + /** + * Allow DTLS v1.2 + */ + virtual bool allow_dtls12() const; + + virtual Group_Params default_dh_group() const; + + /** + * Return the minimum DH group size we're willing to use + * Default is currently 1024 (insecure), should be 2048 + */ + virtual size_t minimum_dh_group_size() const; + + /** + * For ECDSA authenticated ciphersuites, the smallest key size the + * client will accept. + * This policy is currently only enforced on the server by the client. + */ + virtual size_t minimum_ecdsa_group_size() const; + + /** + * Return the minimum ECDH group size we're willing to use + * for key exchange + * + * Default 255, allowing x25519 and larger + * x25519 is the smallest curve we will negotiate + * P-521 is the largest + */ + virtual size_t minimum_ecdh_group_size() const; + + /** + * Return the minimum bit size we're willing to accept for RSA + * key exchange or server signatures. + * + * It does not place any requirements on the size of any RSA signature(s) + * which were used to check the server certificate. This is only + * concerned with the server's public key. + * + * Default is 2048 which is smallest RSA key size still secure + * for medium term security. + */ + virtual size_t minimum_rsa_bits() const; + + /** + * Minimum DSA group size, default 2048 bits + */ + virtual size_t minimum_dsa_group_size() const; + + /** + * Throw an exception if you don't like the peer's key. + * Default impl checks the key size against minimum_rsa_bits, minimum_ecdsa_group_size, + * or minimum_ecdh_group_size depending on the key's type. + * Override if you'd like to perform some other kind of test on + * (or logging of) the peer's keys. + */ + virtual void check_peer_key_acceptable(const Public_Key& public_key) const; + + /** + * If this function returns false, unknown SRP/PSK identifiers + * will be rejected with an unknown_psk_identifier alert as soon + * as the non-existence is identified. Otherwise, a false + * identifier value will be used and the protocol allowed to + * proceed, causing the handshake to eventually fail without + * revealing that the username does not exist on this system. + */ + virtual bool hide_unknown_users() const; + + /** + * Return the allowed lifetime of a session ticket. If 0, session + * tickets do not expire until the session ticket key rolls over. + * Expired session tickets cannot be used to resume a session. + */ + virtual uint32_t session_ticket_lifetime() const; + + /** + * If this returns a non-empty vector, and DTLS is negotiated, + * then we will also attempt to negotiate the SRTP extension from + * RFC 5764 using the returned values as the profile ids. + */ + virtual std::vector srtp_profiles() const; + + /** + * @return true if and only if we are willing to accept this version + * Default accepts TLS v1.0 and later or DTLS v1.2 or later. + */ + virtual bool acceptable_protocol_version(Protocol_Version version) const; + + /** + * Returns the more recent protocol version we are willing to + * use, for either TLS or DTLS depending on datagram param. + * Shouldn't ever need to override this unless you want to allow + * a user to disable use of TLS v1.2 (which is *not recommended*) + */ + virtual Protocol_Version latest_supported_version(bool datagram) const; + + /** + * When offering this version, should we send a fallback SCSV? + * Default returns true iff version is not the latest version the + * policy allows, exists to allow override in case of interop problems. + */ + virtual bool send_fallback_scsv(Protocol_Version version) const; + + /** + * Allows policy to reject any ciphersuites which are undesirable + * for whatever reason without having to reimplement ciphersuite_list + */ + virtual bool acceptable_ciphersuite(const Ciphersuite& suite) const; + + /** + * @return true if servers should choose the ciphersuite matching + * their highest preference, rather than the clients. + * Has no effect on client side. + */ + virtual bool server_uses_own_ciphersuite_preferences() const; + + /** + * Indicates whether the encrypt-then-MAC extension should be negotiated + * (RFC 7366) + */ + virtual bool negotiate_encrypt_then_mac() const; + + /** + * Indicates whether certificate status messages should be supported + */ + virtual bool support_cert_status_message() const; + + /** + * Indicate if client certificate authentication is required. + * If true, then a cert will be requested and if the client does + * not send a certificate the connection will be closed. + */ + virtual bool require_client_certificate_authentication() const; + + /** + * Indicate if client certificate authentication is requested. + * If true, then a cert will be requested. + */ + virtual bool request_client_certificate_authentication() const; + + /** + * If true, then allow a DTLS client to restart a connection to the + * same server association as described in section 4.2.8 of the DTLS RFC + */ + virtual bool allow_dtls_epoch0_restart() const; + + /** + * Return allowed ciphersuites, in order of preference + */ + virtual std::vector ciphersuite_list(Protocol_Version version, + bool have_srp) const; + + /** + * @return the default MTU for DTLS + */ + virtual size_t dtls_default_mtu() const; + + /** + * @return the initial timeout for DTLS + */ + virtual size_t dtls_initial_timeout() const; + + /** + * @return the maximum timeout for DTLS + */ + virtual size_t dtls_maximum_timeout() const; + + /** + * @return the maximum size of the certificate chain, in bytes. + * Return 0 to disable this and accept any size. + */ + virtual size_t maximum_certificate_chain_size() const; + + virtual bool allow_resumption_for_renegotiation() const; + + /** + * Convert this policy to a printable format. + * @param o stream to be printed to + */ + virtual void print(std::ostream& o) const; + + /** + * Convert this policy to a printable format. + * Same as calling `print` on a ostringstream and reading o.str() + */ + std::string to_string() const; + + virtual ~Policy() = default; + }; + +typedef Policy Default_Policy; + +/** +* NSA Suite B 128-bit security level (RFC 6460) +* +* @warning As of August 2015 NSA indicated only the 192-bit Suite B +* should be used for all classification levels. +*/ +class BOTAN_PUBLIC_API(2,0) NSA_Suite_B_128 : public Policy + { + public: + std::vector allowed_ciphers() const override + { return std::vector({"AES-128/GCM"}); } + + std::vector allowed_signature_hashes() const override + { return std::vector({"SHA-256"}); } + + std::vector allowed_macs() const override + { return std::vector({"AEAD"}); } + + std::vector allowed_key_exchange_methods() const override + { return std::vector({"ECDH"}); } + + std::vector allowed_signature_methods() const override + { return std::vector({"ECDSA"}); } + + std::vector key_exchange_groups() const override + { return {Group_Params::SECP256R1}; } + + size_t minimum_signature_strength() const override { return 128; } + + bool allow_tls10() const override { return false; } + bool allow_tls11() const override { return false; } + bool allow_tls12() const override { return true; } + bool allow_dtls10() const override { return false; } + bool allow_dtls12() const override { return false; } + }; + +/** +* NSA Suite B 192-bit security level (RFC 6460) +*/ +class BOTAN_PUBLIC_API(2,7) NSA_Suite_B_192 : public Policy + { + public: + std::vector allowed_ciphers() const override + { return std::vector({"AES-256/GCM"}); } + + std::vector allowed_signature_hashes() const override + { return std::vector({"SHA-384"}); } + + std::vector allowed_macs() const override + { return std::vector({"AEAD"}); } + + std::vector allowed_key_exchange_methods() const override + { return std::vector({"ECDH"}); } + + std::vector allowed_signature_methods() const override + { return std::vector({"ECDSA"}); } + + std::vector key_exchange_groups() const override + { return {Group_Params::SECP384R1}; } + + size_t minimum_signature_strength() const override { return 192; } + + bool allow_tls10() const override { return false; } + bool allow_tls11() const override { return false; } + bool allow_tls12() const override { return true; } + bool allow_dtls10() const override { return false; } + bool allow_dtls12() const override { return false; } + }; + +/** +* BSI TR-02102-2 Policy +*/ +class BOTAN_PUBLIC_API(2,0) BSI_TR_02102_2 : public Policy + { + public: + std::vector allowed_ciphers() const override + { + return std::vector({"AES-256/GCM", "AES-128/GCM", "AES-256/CCM", "AES-128/CCM", "AES-256", "AES-128"}); + } + + std::vector allowed_signature_hashes() const override + { + return std::vector({"SHA-512", "SHA-384", "SHA-256"}); + } + + std::vector allowed_macs() const override + { + return std::vector({"AEAD", "SHA-384", "SHA-256"}); + } + + std::vector allowed_key_exchange_methods() const override + { + return std::vector({"ECDH", "DH", "ECDHE_PSK", "DHE_PSK"}); + } + + std::vector allowed_signature_methods() const override + { + return std::vector({"ECDSA", "RSA", "DSA"}); + } + + std::vector key_exchange_groups() const override + { + return std::vector({ + Group_Params::BRAINPOOL512R1, + Group_Params::BRAINPOOL384R1, + Group_Params::BRAINPOOL256R1, + Group_Params::SECP384R1, + Group_Params::SECP256R1, + Group_Params::FFDHE_4096, + Group_Params::FFDHE_3072, + Group_Params::FFDHE_2048 + }); + } + + bool allow_insecure_renegotiation() const override { return false; } + bool allow_server_initiated_renegotiation() const override { return true; } + bool server_uses_own_ciphersuite_preferences() const override { return true; } + bool negotiate_encrypt_then_mac() const override { return true; } + + size_t minimum_rsa_bits() const override { return 2000; } + size_t minimum_dh_group_size() const override { return 2000; } + size_t minimum_dsa_group_size() const override { return 2000; } + + size_t minimum_ecdh_group_size() const override { return 250; } + size_t minimum_ecdsa_group_size() const override { return 250; } + + bool allow_tls10() const override { return false; } + bool allow_tls11() const override { return false; } + bool allow_tls12() const override { return true; } + bool allow_dtls10() const override { return false; } + bool allow_dtls12() const override { return false; } + }; + +/** +* Policy for DTLS. We require DTLS v1.2 and an AEAD mode. +*/ +class BOTAN_PUBLIC_API(2,0) Datagram_Policy : public Policy + { + public: + std::vector allowed_macs() const override + { return std::vector({"AEAD"}); } + + bool allow_tls10() const override { return false; } + bool allow_tls11() const override { return false; } + bool allow_tls12() const override { return false; } + bool allow_dtls10() const override { return false; } + bool allow_dtls12() const override { return true; } + }; + +/* +* This policy requires a secure version of TLS and disables all insecure +* algorithms. It is compatible with other botan TLSes (including those using the +* default policy) and with many other recent implementations. It is a great idea +* to use if you control both sides of the protocol and don't have to worry +* about ancient and/or bizarre TLS implementations. +*/ +class BOTAN_PUBLIC_API(2,0) Strict_Policy : public Policy + { + public: + std::vector allowed_ciphers() const override; + + std::vector allowed_signature_hashes() const override; + + std::vector allowed_macs() const override; + + std::vector allowed_key_exchange_methods() const override; + + bool allow_tls10() const override; + bool allow_tls11() const override; + bool allow_tls12() const override; + bool allow_dtls10() const override; + bool allow_dtls12() const override; + }; + +class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy + { + public: + + std::vector allowed_ciphers() const override; + + std::vector allowed_signature_hashes() const override; + + std::vector allowed_macs() const override; + + std::vector allowed_key_exchange_methods() const override; + + std::vector allowed_signature_methods() const override; + + std::vector key_exchange_groups() const override; + + bool use_ecc_point_compression() const override; + + bool allow_tls10() const override; + + bool allow_tls11() const override; + + bool allow_tls12() const override; + + bool allow_dtls10() const override; + + bool allow_dtls12() const override; + + bool allow_insecure_renegotiation() const override; + + bool include_time_in_hello_random() const override; + + bool allow_client_initiated_renegotiation() const override; + bool allow_server_initiated_renegotiation() const override; + + bool server_uses_own_ciphersuite_preferences() const override; + + bool negotiate_encrypt_then_mac() const override; + + bool support_cert_status_message() const override; + + bool require_client_certificate_authentication() const override; + + size_t minimum_ecdh_group_size() const override; + + size_t minimum_ecdsa_group_size() const override; + + size_t minimum_dh_group_size() const override; + + size_t minimum_rsa_bits() const override; + + size_t minimum_signature_strength() const override; + + size_t dtls_default_mtu() const override; + + size_t dtls_initial_timeout() const override; + + size_t dtls_maximum_timeout() const override; + + bool require_cert_revocation_info() const override; + + bool hide_unknown_users() const override; + + uint32_t session_ticket_lifetime() const override; + + bool send_fallback_scsv(Protocol_Version version) const override; + + std::vector srtp_profiles() const override; + + void set(const std::string& k, const std::string& v); + + explicit Text_Policy(const std::string& s); + + explicit Text_Policy(std::istream& in); + + protected: + + std::vector get_list(const std::string& key, + const std::vector& def) const; + + size_t get_len(const std::string& key, size_t def) const; + + bool get_bool(const std::string& key, bool def) const; + + std::string get_str(const std::string& key, const std::string& def = "") const; + + bool set_value(const std::string& key, const std::string& val, bool overwrite); + + private: + std::map m_kv; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_reader.h b/comm/third_party/botan/src/lib/tls/tls_reader.h new file mode 100644 index 0000000000..c6cffed320 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_reader.h @@ -0,0 +1,231 @@ +/* +* TLS Data Reader +* (C) 2010-2011,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_READER_H_ +#define BOTAN_TLS_READER_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Helper class for decoding TLS protocol messages +*/ +class TLS_Data_Reader final + { + public: + TLS_Data_Reader(const char* type, const std::vector& buf_in) : + m_typename(type), m_buf(buf_in), m_offset(0) {} + + void assert_done() const + { + if(has_remaining()) + throw decode_error("Extra bytes at end of message"); + } + + size_t read_so_far() const { return m_offset; } + + size_t remaining_bytes() const { return m_buf.size() - m_offset; } + + bool has_remaining() const { return (remaining_bytes() > 0); } + + std::vector get_remaining() + { + return std::vector(m_buf.begin() + m_offset, m_buf.end()); + } + + void discard_next(size_t bytes) + { + assert_at_least(bytes); + m_offset += bytes; + } + + uint32_t get_uint32_t() + { + assert_at_least(4); + uint32_t result = make_uint32(m_buf[m_offset ], m_buf[m_offset+1], + m_buf[m_offset+2], m_buf[m_offset+3]); + m_offset += 4; + return result; + } + + uint16_t get_uint16_t() + { + assert_at_least(2); + uint16_t result = make_uint16(m_buf[m_offset], m_buf[m_offset+1]); + m_offset += 2; + return result; + } + + uint8_t get_byte() + { + assert_at_least(1); + uint8_t result = m_buf[m_offset]; + m_offset += 1; + return result; + } + + template + Container get_elem(size_t num_elems) + { + assert_at_least(num_elems * sizeof(T)); + + Container result(num_elems); + + for(size_t i = 0; i != num_elems; ++i) + result[i] = load_be(&m_buf[m_offset], i); + + m_offset += num_elems * sizeof(T); + + return result; + } + + template + std::vector get_range(size_t len_bytes, + size_t min_elems, + size_t max_elems) + { + const size_t num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem>(num_elems); + } + + template + std::vector get_range_vector(size_t len_bytes, + size_t min_elems, + size_t max_elems) + { + const size_t num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem>(num_elems); + } + + std::string get_string(size_t len_bytes, + size_t min_bytes, + size_t max_bytes) + { + std::vector v = + get_range_vector(len_bytes, min_bytes, max_bytes); + + return std::string(cast_uint8_ptr_to_char(v.data()), v.size()); + } + + template + std::vector get_fixed(size_t size) + { + return get_elem>(size); + } + + private: + size_t get_length_field(size_t len_bytes) + { + assert_at_least(len_bytes); + + if(len_bytes == 1) + return get_byte(); + else if(len_bytes == 2) + return get_uint16_t(); + + throw decode_error("Bad length size"); + } + + size_t get_num_elems(size_t len_bytes, + size_t T_size, + size_t min_elems, + size_t max_elems) + { + const size_t byte_length = get_length_field(len_bytes); + + if(byte_length % T_size != 0) + throw decode_error("Size isn't multiple of T"); + + const size_t num_elems = byte_length / T_size; + + if(num_elems < min_elems || num_elems > max_elems) + throw decode_error("Length field outside parameters"); + + return num_elems; + } + + void assert_at_least(size_t n) const + { + if(m_buf.size() - m_offset < n) + throw decode_error("Expected " + std::to_string(n) + + " bytes remaining, only " + + std::to_string(m_buf.size()-m_offset) + + " left"); + } + + Decoding_Error decode_error(const std::string& why) const + { + return Decoding_Error("Invalid " + std::string(m_typename) + ": " + why); + } + + const char* m_typename; + const std::vector& m_buf; + size_t m_offset; + }; + +/** +* Helper function for encoding length-tagged vectors +*/ +template +void append_tls_length_value(std::vector& buf, + const T* vals, + size_t vals_size, + size_t tag_size) + { + const size_t T_size = sizeof(T); + const size_t val_bytes = T_size * vals_size; + + if(tag_size != 1 && tag_size != 2) + throw Invalid_Argument("append_tls_length_value: invalid tag size"); + + if((tag_size == 1 && val_bytes > 255) || + (tag_size == 2 && val_bytes > 65535)) + throw Invalid_Argument("append_tls_length_value: value too large"); + + for(size_t i = 0; i != tag_size; ++i) + buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); + + for(size_t i = 0; i != vals_size; ++i) + for(size_t j = 0; j != T_size; ++j) + buf.push_back(get_byte(j, vals[i])); + } + +template +void append_tls_length_value(std::vector& buf, + const std::vector& vals, + size_t tag_size) + { + append_tls_length_value(buf, vals.data(), vals.size(), tag_size); + } + +template +void append_tls_length_value(std::vector& buf, + const std::string& str, + size_t tag_size) + { + append_tls_length_value(buf, + cast_char_ptr_to_uint8(str.data()), + str.size(), + tag_size); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_record.cpp b/comm/third_party/botan/src/lib/tls/tls_record.cpp new file mode 100644 index 0000000000..7a4044e69f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_record.cpp @@ -0,0 +1,534 @@ +/* +* TLS Record Handling +* (C) 2012,2013,2014,2015,2016,2019 Jack Lloyd +* 2016 Juraj Somorovsky +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_TLS_CBC) + #include +#endif + +namespace Botan { + +namespace TLS { + +Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, + Connection_Side side, + bool our_side, + const Ciphersuite& suite, + const Session_Keys& keys, + bool uses_encrypt_then_mac) : + m_start_time(std::chrono::system_clock::now()) + { + m_nonce_format = suite.nonce_format(); + m_nonce_bytes_from_record = suite.nonce_bytes_from_record(version); + m_nonce_bytes_from_handshake = suite.nonce_bytes_from_handshake(); + + const secure_vector& aead_key = keys.aead_key(side); + m_nonce = keys.nonce(side); + + BOTAN_ASSERT_NOMSG(m_nonce.size() == m_nonce_bytes_from_handshake); + + if(nonce_format() == Nonce_Format::CBC_MODE) + { +#if defined(BOTAN_HAS_TLS_CBC) + // legacy CBC+HMAC mode + auto mac = MessageAuthenticationCode::create_or_throw("HMAC(" + suite.mac_algo() + ")"); + auto cipher = BlockCipher::create_or_throw(suite.cipher_algo()); + + if(our_side) + { + m_aead.reset(new TLS_CBC_HMAC_AEAD_Encryption( + std::move(cipher), + std::move(mac), + suite.cipher_keylen(), + suite.mac_keylen(), + version, + uses_encrypt_then_mac)); + } + else + { + m_aead.reset(new TLS_CBC_HMAC_AEAD_Decryption( + std::move(cipher), + std::move(mac), + suite.cipher_keylen(), + suite.mac_keylen(), + version, + uses_encrypt_then_mac)); + } + +#else + BOTAN_UNUSED(uses_encrypt_then_mac); + throw Internal_Error("Negotiated disabled TLS CBC+HMAC ciphersuite"); +#endif + } + else + { + m_aead = AEAD_Mode::create_or_throw(suite.cipher_algo(), our_side ? ENCRYPTION : DECRYPTION); + } + + m_aead->set_key(aead_key); + } + +std::vector Connection_Cipher_State::aead_nonce(uint64_t seq, RandomNumberGenerator& rng) + { + switch(m_nonce_format) + { + case Nonce_Format::CBC_MODE: + { + if(m_nonce.size()) + { + std::vector nonce; + nonce.swap(m_nonce); + return nonce; + } + std::vector nonce(nonce_bytes_from_record()); + rng.randomize(nonce.data(), nonce.size()); + return nonce; + } + case Nonce_Format::AEAD_XOR_12: + { + std::vector nonce(12); + store_be(seq, nonce.data() + 4); + xor_buf(nonce, m_nonce.data(), m_nonce.size()); + return nonce; + } + case Nonce_Format::AEAD_IMPLICIT_4: + { + BOTAN_ASSERT_NOMSG(m_nonce.size() == 4); + std::vector nonce(12); + copy_mem(&nonce[0], m_nonce.data(), 4); + store_be(seq, &nonce[nonce_bytes_from_handshake()]); + return nonce; + } + } + + throw Invalid_State("Unknown nonce format specified"); + } + +std::vector +Connection_Cipher_State::aead_nonce(const uint8_t record[], size_t record_len, uint64_t seq) + { + switch(m_nonce_format) + { + case Nonce_Format::CBC_MODE: + { + if(nonce_bytes_from_record() == 0 && m_nonce.size()) + { + std::vector nonce; + nonce.swap(m_nonce); + return nonce; + } + if(record_len < nonce_bytes_from_record()) + throw Decoding_Error("Invalid CBC packet too short to be valid"); + std::vector nonce(record, record + nonce_bytes_from_record()); + return nonce; + } + case Nonce_Format::AEAD_XOR_12: + { + std::vector nonce(12); + store_be(seq, nonce.data() + 4); + xor_buf(nonce, m_nonce.data(), m_nonce.size()); + return nonce; + } + case Nonce_Format::AEAD_IMPLICIT_4: + { + BOTAN_ASSERT_NOMSG(m_nonce.size() == 4); + if(record_len < nonce_bytes_from_record()) + throw Decoding_Error("Invalid AEAD packet too short to be valid"); + std::vector nonce(12); + copy_mem(&nonce[0], m_nonce.data(), 4); + copy_mem(&nonce[nonce_bytes_from_handshake()], record, nonce_bytes_from_record()); + return nonce; + } + } + + throw Invalid_State("Unknown nonce format specified"); + } + +std::vector +Connection_Cipher_State::format_ad(uint64_t msg_sequence, + uint8_t msg_type, + Protocol_Version version, + uint16_t msg_length) + { + std::vector ad(13); + + store_be(msg_sequence, &ad[0]); + ad[8] = msg_type; + ad[9] = version.major_version(); + ad[10] = version.minor_version(); + ad[11] = get_byte(0, msg_length); + ad[12] = get_byte(1, msg_length); + + return ad; + } + +namespace { + +inline void append_u16_len(secure_vector& output, size_t len_field) + { + const uint16_t len16 = static_cast(len_field); + BOTAN_ASSERT_EQUAL(len_field, len16, "No truncation"); + output.push_back(get_byte(0, len16)); + output.push_back(get_byte(1, len16)); + } + +void write_record_header(secure_vector& output, + uint8_t record_type, + Protocol_Version version, + uint64_t record_sequence) + { + output.clear(); + + output.push_back(record_type); + output.push_back(version.major_version()); + output.push_back(version.minor_version()); + + if(version.is_datagram_protocol()) + { + for(size_t i = 0; i != 8; ++i) + output.push_back(get_byte(i, record_sequence)); + } + } + +} + +void write_unencrypted_record(secure_vector& output, + uint8_t record_type, + Protocol_Version version, + uint64_t record_sequence, + const uint8_t* message, + size_t message_len) + { + if(record_type == APPLICATION_DATA) + throw Internal_Error("Writing an unencrypted TLS application data record"); + write_record_header(output, record_type, version, record_sequence); + append_u16_len(output, message_len); + output.insert(output.end(), message, message + message_len); + } + +void write_record(secure_vector& output, + uint8_t record_type, + Protocol_Version version, + uint64_t record_sequence, + const uint8_t* message, + size_t message_len, + Connection_Cipher_State& cs, + RandomNumberGenerator& rng) + { + write_record_header(output, record_type, version, record_sequence); + + AEAD_Mode& aead = cs.aead(); + std::vector aad = cs.format_ad(record_sequence, record_type, version, static_cast(message_len)); + + const size_t ctext_size = aead.output_length(message_len); + + const size_t rec_size = ctext_size + cs.nonce_bytes_from_record(); + + aead.set_ad(aad); + + const std::vector nonce = cs.aead_nonce(record_sequence, rng); + + append_u16_len(output, rec_size); + + if(cs.nonce_bytes_from_record() > 0) + { + if(cs.nonce_format() == Nonce_Format::CBC_MODE) + output += nonce; + else + output += std::make_pair(&nonce[cs.nonce_bytes_from_handshake()], cs.nonce_bytes_from_record()); + } + + const size_t header_size = output.size(); + output += std::make_pair(message, message_len); + + aead.start(nonce); + aead.finish(output, header_size); + + BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE, + "Produced ciphertext larger than protocol allows"); + } + +namespace { + +size_t fill_buffer_to(secure_vector& readbuf, + const uint8_t*& input, + size_t& input_size, + size_t& input_consumed, + size_t desired) + { + if(readbuf.size() >= desired) + return 0; // already have it + + const size_t taken = std::min(input_size, desired - readbuf.size()); + + readbuf.insert(readbuf.end(), input, input + taken); + input_consumed += taken; + input_size -= taken; + input += taken; + + return (desired - readbuf.size()); // how many bytes do we still need? + } + +void decrypt_record(secure_vector& output, + uint8_t record_contents[], size_t record_len, + uint64_t record_sequence, + Protocol_Version record_version, + Record_Type record_type, + Connection_Cipher_State& cs) + { + AEAD_Mode& aead = cs.aead(); + + const std::vector nonce = cs.aead_nonce(record_contents, record_len, record_sequence); + const uint8_t* msg = &record_contents[cs.nonce_bytes_from_record()]; + const size_t msg_length = record_len - cs.nonce_bytes_from_record(); + + /* + * This early rejection is based just on public information (length of the + * encrypted packet) and so does not leak any information. We used to use + * decode_error here which really is more appropriate, but that confuses some + * tools which are attempting automated detection of padding oracles, + * including older versions of TLS-Attacker. + */ + if(msg_length < aead.minimum_final_size()) + throw TLS_Exception(Alert::BAD_RECORD_MAC, "AEAD packet is shorter than the tag"); + + const size_t ptext_size = aead.output_length(msg_length); + + aead.set_associated_data_vec( + cs.format_ad(record_sequence, + static_cast(record_type), + record_version, + static_cast(ptext_size)) + ); + + aead.start(nonce); + + output.assign(msg, msg + msg_length); + aead.finish(output, 0); + } + +Record_Header read_tls_record(secure_vector& readbuf, + const uint8_t input[], + size_t input_len, + size_t& consumed, + secure_vector& recbuf, + Connection_Sequence_Numbers* sequence_numbers, + get_cipherstate_fn get_cipherstate) + { + if(readbuf.size() < TLS_HEADER_SIZE) // header incomplete? + { + if(size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE)) + { + return Record_Header(needed); + } + + BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header"); + } + + if(readbuf[1] != 3) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Got unexpected TLS record version"); + } + + const Protocol_Version version(readbuf[1], readbuf[2]); + + const size_t record_size = make_uint16(readbuf[TLS_HEADER_SIZE-2], + readbuf[TLS_HEADER_SIZE-1]); + + if(record_size > MAX_CIPHERTEXT_SIZE) + throw TLS_Exception(Alert::RECORD_OVERFLOW, + "Received a record that exceeds maximum size"); + + if(record_size == 0) + throw TLS_Exception(Alert::DECODE_ERROR, + "Received a completely empty record"); + + if(size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE + record_size)) + { + return Record_Header(needed); + } + + BOTAN_ASSERT_EQUAL(static_cast(TLS_HEADER_SIZE) + record_size, + readbuf.size(), + "Have the full record"); + + const Record_Type type = static_cast(readbuf[0]); + + uint16_t epoch = 0; + + uint64_t sequence = 0; + if(sequence_numbers) + { + sequence = sequence_numbers->next_read_sequence(); + epoch = sequence_numbers->current_read_epoch(); + } + else + { + // server initial handshake case + epoch = 0; + } + + if(epoch == 0) // Unencrypted initial handshake + { + recbuf.assign(readbuf.begin() + TLS_HEADER_SIZE, readbuf.begin() + TLS_HEADER_SIZE + record_size); + readbuf.clear(); + return Record_Header(sequence, version, type); + } + + // Otherwise, decrypt, check MAC, return plaintext + auto cs = get_cipherstate(epoch); + + BOTAN_ASSERT(cs, "Have cipherstate for this epoch"); + + decrypt_record(recbuf, + &readbuf[TLS_HEADER_SIZE], + record_size, + sequence, + version, + type, + *cs); + + if(sequence_numbers) + sequence_numbers->read_accept(sequence); + + readbuf.clear(); + return Record_Header(sequence, version, type); + } + +Record_Header read_dtls_record(secure_vector& readbuf, + const uint8_t input[], + size_t input_len, + size_t& consumed, + secure_vector& recbuf, + Connection_Sequence_Numbers* sequence_numbers, + get_cipherstate_fn get_cipherstate, + bool allow_epoch0_restart) + { + if(readbuf.size() < DTLS_HEADER_SIZE) // header incomplete? + { + if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE)) + { + readbuf.clear(); + return Record_Header(0); + } + + BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, "Have an entire header"); + } + + const Protocol_Version version(readbuf[1], readbuf[2]); + + if(version.is_datagram_protocol() == false) + { + readbuf.clear(); + return Record_Header(0); + } + + const size_t record_size = make_uint16(readbuf[DTLS_HEADER_SIZE-2], + readbuf[DTLS_HEADER_SIZE-1]); + + if(record_size > MAX_CIPHERTEXT_SIZE) + { + // Too large to be valid, ignore it + readbuf.clear(); + return Record_Header(0); + } + + if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE + record_size)) + { + // Truncated packet? + readbuf.clear(); + return Record_Header(0); + } + + BOTAN_ASSERT_EQUAL(static_cast(DTLS_HEADER_SIZE) + record_size, readbuf.size(), + "Have the full record"); + + const Record_Type type = static_cast(readbuf[0]); + + const uint64_t sequence = load_be(&readbuf[3], 0); + const uint16_t epoch = (sequence >> 48); + + const bool already_seen = sequence_numbers && sequence_numbers->already_seen(sequence); + + if(already_seen && !(epoch == 0 && allow_epoch0_restart)) + { + readbuf.clear(); + return Record_Header(0); + } + + if(epoch == 0) // Unencrypted initial handshake + { + recbuf.assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_size); + readbuf.clear(); + if(sequence_numbers) + sequence_numbers->read_accept(sequence); + return Record_Header(sequence, version, type); + } + + try + { + // Otherwise, decrypt, check MAC, return plaintext + auto cs = get_cipherstate(epoch); + + BOTAN_ASSERT(cs, "Have cipherstate for this epoch"); + + decrypt_record(recbuf, + &readbuf[DTLS_HEADER_SIZE], + record_size, + sequence, + version, + type, + *cs); + } + catch(std::exception&) + { + readbuf.clear(); + return Record_Header(0); + } + + if(sequence_numbers) + sequence_numbers->read_accept(sequence); + + readbuf.clear(); + return Record_Header(sequence, version, type); + } + +} + +Record_Header read_record(bool is_datagram, + secure_vector& readbuf, + const uint8_t input[], + size_t input_len, + size_t& consumed, + secure_vector& recbuf, + Connection_Sequence_Numbers* sequence_numbers, + get_cipherstate_fn get_cipherstate, + bool allow_epoch0_restart) + { + if(is_datagram) + return read_dtls_record(readbuf, input, input_len, consumed, + recbuf, sequence_numbers, get_cipherstate, allow_epoch0_restart); + else + return read_tls_record(readbuf, input, input_len, consumed, + recbuf, sequence_numbers, get_cipherstate); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_record.h b/comm/third_party/botan/src/lib/tls/tls_record.h new file mode 100644 index 0000000000..8af4e5c050 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_record.h @@ -0,0 +1,188 @@ +/* +* TLS Record Handling +* (C) 2004-2012 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_RECORDS_H_ +#define BOTAN_TLS_RECORDS_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Ciphersuite; +class Session_Keys; + +class Connection_Sequence_Numbers; + +/** +* TLS Cipher State +*/ +class Connection_Cipher_State final + { + public: + /** + * Initialize a new cipher state + */ + Connection_Cipher_State(Protocol_Version version, + Connection_Side which_side, + bool is_our_side, + const Ciphersuite& suite, + const Session_Keys& keys, + bool uses_encrypt_then_mac); + + AEAD_Mode& aead() + { + BOTAN_ASSERT_NONNULL(m_aead.get()); + return *m_aead.get(); + } + + std::vector aead_nonce(uint64_t seq, RandomNumberGenerator& rng); + + std::vector aead_nonce(const uint8_t record[], size_t record_len, uint64_t seq); + + std::vector format_ad(uint64_t seq, uint8_t type, + Protocol_Version version, + uint16_t ptext_length); + + size_t nonce_bytes_from_handshake() const { return m_nonce_bytes_from_handshake; } + size_t nonce_bytes_from_record() const { return m_nonce_bytes_from_record; } + + Nonce_Format nonce_format() const { return m_nonce_format; } + + std::chrono::seconds age() const + { + return std::chrono::duration_cast( + std::chrono::system_clock::now() - m_start_time); + } + + private: + std::chrono::system_clock::time_point m_start_time; + std::unique_ptr m_aead; + + std::vector m_nonce; + Nonce_Format m_nonce_format; + size_t m_nonce_bytes_from_handshake; + size_t m_nonce_bytes_from_record; + }; + +class Record_Header final + { + public: + Record_Header(uint64_t sequence, + Protocol_Version version, + Record_Type type) : + m_needed(0), + m_sequence(sequence), + m_version(version), + m_type(type) + {} + + Record_Header(size_t needed) : + m_needed(needed), + m_sequence(0), + m_version(Protocol_Version()), + m_type(NO_RECORD) + {} + + size_t needed() const { return m_needed; } + + Protocol_Version version() const + { + BOTAN_ASSERT_NOMSG(m_needed == 0); + return m_version; + } + + uint64_t sequence() const + { + BOTAN_ASSERT_NOMSG(m_needed == 0); + return m_sequence; + } + + uint16_t epoch() const + { + return static_cast(sequence() >> 48); + } + + Record_Type type() const + { + BOTAN_ASSERT_NOMSG(m_needed == 0); + return m_type; + } + + private: + size_t m_needed; + uint64_t m_sequence; + Protocol_Version m_version; + Record_Type m_type; + }; + +/** +* Create an initial (unencrypted) TLS handshake record +* @param write_buffer the output record is placed here +* @param record_type the record layer type +* @param record_version the record layer version +* @param record_sequence the record layer sequence number +* @param message the record contents +* @param message_len is size of message +*/ +void write_unencrypted_record(secure_vector& write_buffer, + uint8_t record_type, + Protocol_Version record_version, + uint64_t record_sequence, + const uint8_t* message, + size_t message_len); + +/** +* Create a TLS record +* @param write_buffer the output record is placed here +* @param record_type the record layer type +* @param record_version the record layer version +* @param record_sequence the record layer sequence number +* @param message the record contents +* @param message_len is size of message +* @param cipherstate is the writing cipher state +* @param rng is a random number generator +*/ +void write_record(secure_vector& write_buffer, + uint8_t record_type, + Protocol_Version record_version, + uint64_t record_sequence, + const uint8_t* message, + size_t message_len, + Connection_Cipher_State& cipherstate, + RandomNumberGenerator& rng); + +// epoch -> cipher state +typedef std::function (uint16_t)> get_cipherstate_fn; + +/** +* Decode a TLS record +* @return zero if full message, else number of bytes still needed +*/ +Record_Header read_record(bool is_datagram, + secure_vector& read_buffer, + const uint8_t input[], + size_t input_len, + size_t& consumed, + secure_vector& record_buf, + Connection_Sequence_Numbers* sequence_numbers, + get_cipherstate_fn get_cipherstate, + bool allow_epoch0_restart); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_seq_numbers.h b/comm/third_party/botan/src/lib/tls/tls_seq_numbers.h new file mode 100644 index 0000000000..0a0a416f8f --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_seq_numbers.h @@ -0,0 +1,174 @@ +/* +* TLS Sequence Number Handling +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SEQ_NUMBERS_H_ +#define BOTAN_TLS_SEQ_NUMBERS_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +class Connection_Sequence_Numbers + { + public: + virtual ~Connection_Sequence_Numbers() = default; + + virtual void new_read_cipher_state() = 0; + virtual void new_write_cipher_state() = 0; + + virtual uint16_t current_read_epoch() const = 0; + virtual uint16_t current_write_epoch() const = 0; + + virtual uint64_t next_write_sequence(uint16_t) = 0; + virtual uint64_t next_read_sequence() = 0; + + virtual bool already_seen(uint64_t seq) const = 0; + virtual void read_accept(uint64_t seq) = 0; + + virtual void reset() = 0; + }; + +class Stream_Sequence_Numbers final : public Connection_Sequence_Numbers + { + public: + Stream_Sequence_Numbers() { Stream_Sequence_Numbers::reset(); } + + void reset() override + { + m_write_seq_no = 0; + m_read_seq_no = 0; + m_read_epoch = 0; + m_write_epoch = 0; + } + + void new_read_cipher_state() override { m_read_seq_no = 0; m_read_epoch++; } + void new_write_cipher_state() override { m_write_seq_no = 0; m_write_epoch++; } + + uint16_t current_read_epoch() const override { return m_read_epoch; } + uint16_t current_write_epoch() const override { return m_write_epoch; } + + uint64_t next_write_sequence(uint16_t) override { return m_write_seq_no++; } + uint64_t next_read_sequence() override { return m_read_seq_no; } + + bool already_seen(uint64_t) const override { return false; } + void read_accept(uint64_t) override { m_read_seq_no++; } + + private: + uint64_t m_write_seq_no; + uint64_t m_read_seq_no; + uint16_t m_read_epoch; + uint16_t m_write_epoch; + }; + +class Datagram_Sequence_Numbers final : public Connection_Sequence_Numbers + { + public: + Datagram_Sequence_Numbers() { Datagram_Sequence_Numbers::reset(); } + + void reset() override + { + m_write_seqs.clear(); + m_write_seqs[0] = 0; + m_write_epoch = 0; + m_read_epoch = 0; + m_window_highest = 0; + m_window_bits = 0; + } + + void new_read_cipher_state() override { m_read_epoch++; } + + void new_write_cipher_state() override + { + m_write_epoch++; + m_write_seqs[m_write_epoch] = 0; + } + + uint16_t current_read_epoch() const override { return m_read_epoch; } + uint16_t current_write_epoch() const override { return m_write_epoch; } + + uint64_t next_write_sequence(uint16_t epoch) override + { + auto i = m_write_seqs.find(epoch); + BOTAN_ASSERT(i != m_write_seqs.end(), "Found epoch"); + return (static_cast(epoch) << 48) | i->second++; + } + + uint64_t next_read_sequence() override + { + throw Invalid_State("DTLS uses explicit sequence numbers"); + } + + bool already_seen(uint64_t sequence) const override + { + const size_t window_size = sizeof(m_window_bits) * 8; + + if(sequence > m_window_highest) + { + return false; + } + + const uint64_t offset = m_window_highest - sequence; + + if(offset >= window_size) + { + return true; // really old? + } + + return (((m_window_bits >> offset) & 1) == 1); + } + + void read_accept(uint64_t sequence) override + { + const size_t window_size = sizeof(m_window_bits) * 8; + + if(sequence > m_window_highest) + { + // We've received a later sequence which advances our window + const uint64_t offset = sequence - m_window_highest; + m_window_highest += offset; + + if(offset >= window_size) + m_window_bits = 0; + else + m_window_bits <<= offset; + + m_window_bits |= 0x01; + } + else + { + const uint64_t offset = m_window_highest - sequence; + + if(offset < window_size) + { + // We've received an old sequence but still within our window + m_window_bits |= (static_cast(1) << offset); + } + else + { + // This occurs only if we have reset state (DTLS reconnection case) + m_window_highest = sequence; + m_window_bits = 0; + } + } + } + + private: + std::map m_write_seqs; + uint16_t m_write_epoch = 0; + uint16_t m_read_epoch = 0; + uint64_t m_window_highest = 0; + uint64_t m_window_bits = 0; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_server.cpp b/comm/third_party/botan/src/lib/tls/tls_server.cpp new file mode 100644 index 0000000000..e2a0bf2428 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_server.cpp @@ -0,0 +1,1025 @@ +/* +* TLS Server +* (C) 2004-2011,2012,2016 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Server_Handshake_State final : public Handshake_State + { + public: + Server_Handshake_State(Handshake_IO* io, Callbacks& cb) + : Handshake_State(io, cb) {} + + Private_Key* server_rsa_kex_key() { return m_server_rsa_kex_key; } + void set_server_rsa_kex_key(Private_Key* key) + { m_server_rsa_kex_key = key; } + + bool allow_session_resumption() const + { return m_allow_session_resumption; } + void set_allow_session_resumption(bool allow_session_resumption) + { m_allow_session_resumption = allow_session_resumption; } + + const std::vector& resume_peer_certs() const + { return m_resume_peer_certs; } + + void set_resume_certs(const std::vector& certs) + { m_resume_peer_certs = certs; } + + void mark_as_resumption() { m_is_a_resumption = true; } + + bool is_a_resumption() const { return m_is_a_resumption; } + + private: + // Used by the server only, in case of RSA key exchange. Not owned + Private_Key* m_server_rsa_kex_key = nullptr; + + /* + * Used by the server to know if resumption should be allowed on + * a server-initiated renegotiation + */ + bool m_allow_session_resumption = true; + + bool m_is_a_resumption = false; + + std::vector m_resume_peer_certs; + }; + +namespace { + +bool check_for_resume(Session& session_info, + Session_Manager& session_manager, + Credentials_Manager& credentials, + const Client_Hello* client_hello, + std::chrono::seconds session_ticket_lifetime) + { + const std::vector& client_session_id = client_hello->session_id(); + const std::vector& session_ticket = client_hello->session_ticket(); + + if(session_ticket.empty()) + { + if(client_session_id.empty()) // not resuming + return false; + + // not found + if(!session_manager.load_from_session_id(client_session_id, session_info)) + return false; + } + else + { + // If a session ticket was sent, ignore client session ID + try + { + session_info = Session::decrypt( + session_ticket, + credentials.psk("tls-server", "session-ticket", "")); + + if(session_ticket_lifetime != std::chrono::seconds(0) && + session_info.session_age() > session_ticket_lifetime) + return false; // ticket has expired + } + catch(...) + { + return false; + } + } + + // wrong version + if(client_hello->version() != session_info.version()) + return false; + + // client didn't send original ciphersuite + if(!value_exists(client_hello->ciphersuites(), + session_info.ciphersuite_code())) + return false; + +#if defined(BOTAN_HAS_SRP6) + // client sent a different SRP identity + if(client_hello->srp_identifier() != "") + { + if(client_hello->srp_identifier() != session_info.srp_identifier()) + return false; + } +#endif + + // client sent a different SNI hostname + if(client_hello->sni_hostname() != "") + { + if(client_hello->sni_hostname() != session_info.server_info().hostname()) + return false; + } + + // Checking extended_master_secret on resume (RFC 7627 section 5.3) + if(client_hello->supports_extended_master_secret() != session_info.supports_extended_master_secret()) + { + if(!session_info.supports_extended_master_secret()) + { + return false; // force new handshake with extended master secret + } + else + { + /* + Client previously negotiated session with extended master secret, + but has now attempted to resume without the extension: abort + */ + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client resumed extended ms session without sending extension"); + } + } + + // Checking encrypt_then_mac on resume (RFC 7366 section 3.1) + if(!client_hello->supports_encrypt_then_mac() && session_info.supports_encrypt_then_mac()) + { + /* + Client previously negotiated session with Encrypt-then-MAC, + but has now attempted to resume without the extension: abort + */ + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client resumed Encrypt-then-MAC session without sending extension"); + } + + return true; + } + +/* +* Choose which ciphersuite to use +*/ +uint16_t choose_ciphersuite( + const Policy& policy, + Protocol_Version version, + Credentials_Manager& creds, + const std::map>& cert_chains, + const Client_Hello& client_hello) + { + const bool our_choice = policy.server_uses_own_ciphersuite_preferences(); + const bool have_srp = creds.attempt_srp("tls-server", client_hello.sni_hostname()); + const std::vector client_suites = client_hello.ciphersuites(); + const std::vector server_suites = policy.ciphersuite_list(version, have_srp); + + if(server_suites.empty()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Policy forbids us from negotiating any ciphersuite"); + + const bool have_shared_ecc_curve = + (policy.choose_key_exchange_group(client_hello.supported_ecc_curves()) != Group_Params::NONE); + + /* + Walk down one list in preference order + */ + std::vector pref_list = server_suites; + std::vector other_list = client_suites; + + if(!our_choice) + std::swap(pref_list, other_list); + + for(auto suite_id : pref_list) + { + if(!value_exists(other_list, suite_id)) + continue; + + const Ciphersuite suite = Ciphersuite::by_id(suite_id); + + if(suite.valid() == false) + { + continue; + } + + if(have_shared_ecc_curve == false && suite.ecc_ciphersuite()) + { + continue; + } + + // For non-anon ciphersuites + if(suite.signature_used()) + { + const std::string sig_algo = suite.sig_algo(); + + // Do we have any certificates for this sig? + if(cert_chains.count(sig_algo) == 0) + { + continue; + } + + if(version.supports_negotiable_signature_algorithms()) + { + const std::vector allowed = + policy.allowed_signature_schemes(); + + std::vector client_sig_methods = + client_hello.signature_schemes(); + + if(client_sig_methods.empty()) + { + // If empty, then implicit SHA-1 (TLS v1.2 rules) + client_sig_methods.push_back(Signature_Scheme::RSA_PKCS1_SHA1); + client_sig_methods.push_back(Signature_Scheme::ECDSA_SHA1); + client_sig_methods.push_back(Signature_Scheme::DSA_SHA1); + } + + bool we_support_some_hash_by_client = false; + + for(Signature_Scheme scheme : client_sig_methods) + { + if(signature_scheme_is_known(scheme) == false) + continue; + + if(signature_algorithm_of_scheme(scheme) == suite.sig_algo() && + policy.allowed_signature_hash(hash_function_of_scheme(scheme))) + { + we_support_some_hash_by_client = true; + } + } + + if(we_support_some_hash_by_client == false) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Policy does not accept any hash function supported by client"); + } + } + } + +#if defined(BOTAN_HAS_SRP6) + /* + The client may offer SRP cipher suites in the hello message but + omit the SRP extension. If the server would like to select an + SRP cipher suite in this case, the server SHOULD return a fatal + "unknown_psk_identity" alert immediately after processing the + client hello message. + - RFC 5054 section 2.5.1.2 + */ + if(suite.kex_method() == Kex_Algo::SRP_SHA && client_hello.srp_identifier() == "") + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "Client wanted SRP but did not send username"); +#endif + + return suite_id; + } + + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Can't agree on a ciphersuite with client"); + } + +std::map> +get_server_certs(const std::string& hostname, + Credentials_Manager& creds) + { + const char* cert_types[] = { "RSA", "ECDSA", "DSA", nullptr }; + + std::map> cert_chains; + + for(size_t i = 0; cert_types[i]; ++i) + { + const std::vector certs = + creds.cert_chain_single_type(cert_types[i], "tls-server", hostname); + + if(!certs.empty()) + cert_chains[cert_types[i]] = certs; + } + + return cert_chains; + } + +} + +/* +* TLS Server Constructor +*/ +Server::Server(Callbacks& callbacks, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + bool is_datagram, + size_t io_buf_sz) : + Channel(callbacks, session_manager, rng, policy, + true, is_datagram, io_buf_sz), + m_creds(creds) + { + } + +Server::Server(output_fn output, + data_cb got_data_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + next_protocol_fn next_proto, + bool is_datagram, + size_t io_buf_sz) : + Channel(output, got_data_cb, recv_alert_cb, hs_cb, + Channel::handshake_msg_cb(), session_manager, + rng, policy, true, is_datagram, io_buf_sz), + m_creds(creds), + m_choose_next_protocol(next_proto) + { + } + +Server::Server(output_fn output, + data_cb got_data_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + next_protocol_fn next_proto, + bool is_datagram) : + Channel(output, got_data_cb, recv_alert_cb, hs_cb, hs_msg_cb, + session_manager, rng, policy, true, is_datagram), + m_creds(creds), + m_choose_next_protocol(next_proto) + { + } + +Handshake_State* Server::new_handshake_state(Handshake_IO* io) + { + std::unique_ptr state(new Server_Handshake_State(io, callbacks())); + + state->set_expected_next(CLIENT_HELLO); + return state.release(); + } + +std::vector +Server::get_peer_cert_chain(const Handshake_State& state_base) const + { + const Server_Handshake_State& state = dynamic_cast(state_base); + if(state.resume_peer_certs().size() > 0) + return state.resume_peer_certs(); + + if(state.client_certs()) + return state.client_certs()->cert_chain(); + return std::vector(); + } + +/* +* Send a hello request to the client +*/ +void Server::initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) + { + dynamic_cast(state). + set_allow_session_resumption(!force_full_renegotiation); + + Hello_Request hello_req(state.handshake_io()); + } + +namespace { + +Protocol_Version select_version(const Botan::TLS::Policy& policy, + Protocol_Version client_offer, + Protocol_Version active_version, + bool is_fallback, + const std::vector& supported_versions) + { + const bool is_datagram = client_offer.is_datagram_protocol(); + const bool initial_handshake = (active_version.valid() == false); + + const Protocol_Version latest_supported = policy.latest_supported_version(is_datagram); + + if(is_fallback) + { + if(latest_supported > client_offer) + throw TLS_Exception(Alert::INAPPROPRIATE_FALLBACK, + "Client signalled fallback SCSV, possible attack"); + } + + if(supported_versions.size() > 0) + { + if(is_datagram) + { + if(policy.allow_dtls12() && value_exists(supported_versions, Protocol_Version(Protocol_Version::DTLS_V12))) + return Protocol_Version::DTLS_V12; +#if defined(BOTAN_HAS_TLS_V10) + if(policy.allow_dtls10() && value_exists(supported_versions, Protocol_Version(Protocol_Version::DTLS_V10))) + return Protocol_Version::DTLS_V10; +#endif + throw TLS_Exception(Alert::PROTOCOL_VERSION, "No shared DTLS version"); + } + else + { + if(policy.allow_tls12() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V12))) + return Protocol_Version::TLS_V12; +#if defined(BOTAN_HAS_TLS_V10) + if(policy.allow_tls11() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V11))) + return Protocol_Version::TLS_V11; + if(policy.allow_tls10() && value_exists(supported_versions, Protocol_Version(Protocol_Version::TLS_V10))) + return Protocol_Version::TLS_V10; +#endif + throw TLS_Exception(Alert::PROTOCOL_VERSION, "No shared TLS version"); + } + } + + const bool client_offer_acceptable = + client_offer.known_version() && policy.acceptable_protocol_version(client_offer); + + if(!initial_handshake) + { + /* + * If this is a renegotiation, and the client has offered a + * later version than what it initially negotiated, negotiate + * the old version. This matches OpenSSL's behavior. If the + * client is offering a version earlier than what it initially + * negotiated, reject as a probable attack. + */ + if(active_version > client_offer) + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Client negotiated " + + active_version.to_string() + + " then renegotiated with " + + client_offer.to_string()); + } + else + { + return active_version; + } + } + else if(client_offer_acceptable) + { + return client_offer; + } + else if(!client_offer.known_version() || client_offer > latest_supported) + { + /* + The client offered some version newer than the latest we + support. Offer them the best we know. + */ + return latest_supported; + } + else + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Client version " + client_offer.to_string() + + " is unacceptable by policy"); + } + } + +} + +/* +* Process a CLIENT HELLO Message +*/ +void Server::process_client_hello_msg(const Handshake_State* active_state, + Server_Handshake_State& pending_state, + const std::vector& contents, + bool epoch0_restart) + { + BOTAN_ASSERT_IMPLICATION(epoch0_restart, active_state != nullptr, "Can't restart with a dead connection"); + + const bool initial_handshake = epoch0_restart || !active_state; + + if(initial_handshake == false && policy().allow_client_initiated_renegotiation() == false) + { + if(policy().abort_connection_on_undesired_renegotiation()) + throw TLS_Exception(Alert::NO_RENEGOTIATION, "Server policy prohibits renegotiation"); + else + send_warning_alert(Alert::NO_RENEGOTIATION); + return; + } + + if(!policy().allow_insecure_renegotiation() && + !(initial_handshake || secure_renegotiation_supported())) + { + send_warning_alert(Alert::NO_RENEGOTIATION); + return; + } + + pending_state.client_hello(new Client_Hello(contents)); + const Protocol_Version client_offer = pending_state.client_hello()->version(); + const bool datagram = client_offer.is_datagram_protocol(); + + if(datagram) + { + if(client_offer.major_version() == 0xFF) + throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered DTLS version with major version 0xFF"); + } + else + { + if(client_offer.major_version() < 3) + throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client offered TLS version with major version under 3"); + if(client_offer.major_version() == 3 && client_offer.minor_version() == 0) + throw TLS_Exception(Alert::PROTOCOL_VERSION, "SSLv3 is not supported"); + } + + /* + * BoGo test suite expects that we will send the hello verify with a record + * version matching the version that is eventually negotiated. This is wrong + * but harmless, so go with it. Also doing the version negotiation step first + * allows to immediately close the connection with an alert if the client has + * offered a version that we are not going to negotiate anyway, instead of + * making them first do the cookie exchange and then telling them no. + * + * There is no issue with amplification here, since the alert is just 2 bytes. + */ + const Protocol_Version negotiated_version = + select_version(policy(), client_offer, + active_state ? active_state->version() : Protocol_Version(), + pending_state.client_hello()->sent_fallback_scsv(), + pending_state.client_hello()->supported_versions()); + + pending_state.set_version(negotiated_version); + + const auto compression_methods = pending_state.client_hello()->compression_methods(); + if(!value_exists(compression_methods, uint8_t(0))) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, "Client did not offer NULL compression"); + + if(initial_handshake && datagram) + { + SymmetricKey cookie_secret; + + try + { + cookie_secret = m_creds.psk("tls-server", "dtls-cookie-secret", ""); + } + catch(...) {} + + if(cookie_secret.size() > 0) + { + const std::string client_identity = callbacks().tls_peer_network_identity(); + Hello_Verify_Request verify(pending_state.client_hello()->cookie_input_data(), client_identity, cookie_secret); + + if(pending_state.client_hello()->cookie() != verify.cookie()) + { + if(epoch0_restart) + pending_state.handshake_io().send_under_epoch(verify, 0); + else + pending_state.handshake_io().send(verify); + + pending_state.client_hello(nullptr); + pending_state.set_expected_next(CLIENT_HELLO); + return; + } + } + else if(epoch0_restart) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Reuse of DTLS association requires DTLS cookie secret be set"); + } + } + + if(epoch0_restart) + { + // If we reached here then we were able to verify the cookie + reset_active_association_state(); + } + + secure_renegotiation_check(pending_state.client_hello()); + + callbacks().tls_examine_extensions(pending_state.client_hello()->extensions(), CLIENT); + + Session session_info; + const bool resuming = + pending_state.allow_session_resumption() && + check_for_resume(session_info, + session_manager(), + m_creds, + pending_state.client_hello(), + std::chrono::seconds(policy().session_ticket_lifetime())); + + bool have_session_ticket_key = false; + + try + { + have_session_ticket_key = + m_creds.psk("tls-server", "session-ticket", "").length() > 0; + } + catch(...) {} + + m_next_protocol = ""; + if(pending_state.client_hello()->supports_alpn()) + { + m_next_protocol = callbacks().tls_server_choose_app_protocol(pending_state.client_hello()->next_protocols()); + + // if the callback return was empty, fall back to the (deprecated) std::function + if(m_next_protocol.empty() && m_choose_next_protocol) + { + m_next_protocol = m_choose_next_protocol(pending_state.client_hello()->next_protocols()); + } + } + + if(resuming) + { + this->session_resume(pending_state, have_session_ticket_key, session_info); + } + else // new session + { + this->session_create(pending_state, have_session_ticket_key); + } + } + +void Server::process_certificate_msg(Server_Handshake_State& pending_state, + const std::vector& contents) + { + pending_state.client_certs(new Certificate(contents, policy())); + + // CERTIFICATE_REQUIRED would make more sense but BoGo expects handshake failure alert + if(pending_state.client_certs()->empty() && policy().require_client_certificate_authentication()) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy requires client send a certificate, but it did not"); + + pending_state.set_expected_next(CLIENT_KEX); + } + +void Server::process_client_key_exchange_msg(Server_Handshake_State& pending_state, + const std::vector& contents) + { + if(pending_state.received_handshake_msg(CERTIFICATE) && !pending_state.client_certs()->empty()) + pending_state.set_expected_next(CERTIFICATE_VERIFY); + else + pending_state.set_expected_next(HANDSHAKE_CCS); + + pending_state.client_kex(new Client_Key_Exchange(contents, pending_state, + pending_state.server_rsa_kex_key(), + m_creds, policy(), rng())); + + pending_state.compute_session_keys(); + } + +void Server::process_change_cipher_spec_msg(Server_Handshake_State& pending_state) + { + pending_state.set_expected_next(FINISHED); + change_cipher_spec_reader(SERVER); + } + +void Server::process_certificate_verify_msg(Server_Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents) + { + pending_state.client_verify(new Certificate_Verify(contents, pending_state.version())); + + const std::vector& client_certs = + pending_state.client_certs()->cert_chain(); + + const bool sig_valid = + pending_state.client_verify()->verify(client_certs[0], pending_state, policy()); + + pending_state.hash().update(pending_state.handshake_io().format(contents, type)); + + /* + * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for + * "A handshake cryptographic operation failed, including being + * unable to correctly verify a signature, ..." + */ + if(!sig_valid) + throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed"); + + try + { + const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); + + callbacks().tls_verify_cert_chain(client_certs, + {}, // ocsp + trusted_CAs, + Usage_Type::TLS_CLIENT_AUTH, + sni_hostname, + policy()); + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); + } + + pending_state.set_expected_next(HANDSHAKE_CCS); + } + +void Server::process_finished_msg(Server_Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents) + { + pending_state.set_expected_next(HANDSHAKE_NONE); + + pending_state.client_finished(new Finished(contents)); + + if(!pending_state.client_finished()->verify(pending_state, CLIENT)) + throw TLS_Exception(Alert::DECRYPT_ERROR, + "Finished message didn't verify"); + + if(!pending_state.server_finished()) + { + // already sent finished if resuming, so this is a new session + + pending_state.hash().update(pending_state.handshake_io().format(contents, type)); + + Session session_info( + pending_state.server_hello()->session_id(), + pending_state.session_keys().master_secret(), + pending_state.server_hello()->version(), + pending_state.server_hello()->ciphersuite(), + SERVER, + pending_state.server_hello()->supports_extended_master_secret(), + pending_state.server_hello()->supports_encrypt_then_mac(), + get_peer_cert_chain(pending_state), + std::vector(), + Server_Information(pending_state.client_hello()->sni_hostname()), + pending_state.srp_identifier(), + pending_state.server_hello()->srtp_profile()); + + if(save_session(session_info)) + { + if(pending_state.server_hello()->supports_session_ticket()) + { + try + { + const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); + + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), + pending_state.hash(), + session_info.encrypt(ticket_key, rng()), + policy().session_ticket_lifetime())); + } + catch(...) {} + } + else + session_manager().save(session_info); + } + + if(!pending_state.new_session_ticket() && + pending_state.server_hello()->supports_session_ticket()) + { + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); + } + + pending_state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(SERVER); + + pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); + } + + activate_session(); + } + +/* +* Process a handshake message +*/ +void Server::process_handshake_msg(const Handshake_State* active_state, + Handshake_State& state_base, + Handshake_Type type, + const std::vector& contents, + bool epoch0_restart) + { + Server_Handshake_State& state = dynamic_cast(state_base); + state.confirm_transition_to(type); + + /* + * The change cipher spec message isn't technically a handshake + * message so it's not included in the hash. The finished and + * certificate verify messages are verified based on the current + * state of the hash *before* this message so we delay adding them + * to the hash computation until we've processed them below. + */ + if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY) + { + state.hash().update(state.handshake_io().format(contents, type)); + } + + switch(type) + { + case CLIENT_HELLO: + return this->process_client_hello_msg(active_state, state, contents, epoch0_restart); + + case CERTIFICATE: + return this->process_certificate_msg(state, contents); + + case CLIENT_KEX: + return this->process_client_key_exchange_msg(state, contents); + + case CERTIFICATE_VERIFY: + return this->process_certificate_verify_msg(state, type, contents); + + case HANDSHAKE_CCS: + return this->process_change_cipher_spec_msg(state); + + case FINISHED: + return this->process_finished_msg(state, type, contents); + + default: + throw Unexpected_Message("Unknown handshake message received"); + } + } + +void Server::session_resume(Server_Handshake_State& pending_state, + bool have_session_ticket_key, + Session& session_info) + { + // Only offer a resuming client a new ticket if they didn't send one this time, + // ie, resumed via server-side resumption. TODO: also send one if expiring soon? + + const bool offer_new_session_ticket = + (pending_state.client_hello()->supports_session_ticket() && + pending_state.client_hello()->session_ticket().empty() && + have_session_ticket_key); + + pending_state.server_hello(new Server_Hello( + pending_state.handshake_io(), + pending_state.hash(), + policy(), + callbacks(), + rng(), + secure_renegotiation_data_for_server_hello(), + *pending_state.client_hello(), + session_info, + offer_new_session_ticket, + m_next_protocol)); + + secure_renegotiation_check(pending_state.server_hello()); + + pending_state.mark_as_resumption(); + pending_state.compute_session_keys(session_info.master_secret()); + pending_state.set_resume_certs(session_info.peer_certs()); + + if(!save_session(session_info)) + { + session_manager().remove_entry(session_info.session_id()); + + if(pending_state.server_hello()->supports_session_ticket()) // send an empty ticket + { + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), + pending_state.hash())); + } + } + + if(pending_state.server_hello()->supports_session_ticket() && !pending_state.new_session_ticket()) + { + try + { + const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); + + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), + pending_state.hash(), + session_info.encrypt(ticket_key, rng()), + policy().session_ticket_lifetime())); + } + catch(...) {} + + if(!pending_state.new_session_ticket()) + { + pending_state.new_session_ticket( + new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())); + } + } + + pending_state.handshake_io().send(Change_Cipher_Spec()); + + change_cipher_spec_writer(SERVER); + + pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER)); + pending_state.set_expected_next(HANDSHAKE_CCS); + } + +void Server::session_create(Server_Handshake_State& pending_state, + bool have_session_ticket_key) + { + std::map> cert_chains; + + const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); + + cert_chains = get_server_certs(sni_hostname, m_creds); + + if(sni_hostname != "" && cert_chains.empty()) + { + cert_chains = get_server_certs("", m_creds); + + /* + * Only send the unrecognized_name alert if we couldn't + * find any certs for the requested name but did find at + * least one cert to use in general. That avoids sending an + * unrecognized_name when a server is configured for purely + * anonymous/PSK operation. + */ + if(!cert_chains.empty()) + send_warning_alert(Alert::UNRECOGNIZED_NAME); + } + + const uint16_t ciphersuite = choose_ciphersuite(policy(), pending_state.version(), + m_creds, cert_chains, + *pending_state.client_hello()); + + Server_Hello::Settings srv_settings( + make_hello_random(rng(), policy()), // new session ID + pending_state.version(), + ciphersuite, + have_session_ticket_key); + + pending_state.server_hello(new Server_Hello( + pending_state.handshake_io(), + pending_state.hash(), + policy(), + callbacks(), + rng(), + secure_renegotiation_data_for_server_hello(), + *pending_state.client_hello(), + srv_settings, + m_next_protocol)); + + secure_renegotiation_check(pending_state.server_hello()); + + const Ciphersuite& pending_suite = pending_state.ciphersuite(); + + Private_Key* private_key = nullptr; + + if(pending_suite.signature_used() || pending_suite.kex_method() == Kex_Algo::STATIC_RSA) + { + const std::string algo_used = + pending_suite.signature_used() ? pending_suite.sig_algo() : "RSA"; + + BOTAN_ASSERT(!cert_chains[algo_used].empty(), + "Attempting to send empty certificate chain"); + + pending_state.server_certs(new Certificate(pending_state.handshake_io(), + pending_state.hash(), + cert_chains[algo_used])); + + if(pending_state.client_hello()->supports_cert_status_message() && pending_state.is_a_resumption() == false) + { + auto csr = pending_state.client_hello()->extensions().get(); + // csr is non-null if client_hello()->supports_cert_status_message() + BOTAN_ASSERT_NOMSG(csr != nullptr); + const auto resp_bytes = callbacks().tls_provide_cert_status(cert_chains[algo_used], *csr); + if(resp_bytes.size() > 0) + { + pending_state.server_cert_status(new Certificate_Status( + pending_state.handshake_io(), + pending_state.hash(), + resp_bytes + )); + } + } + + private_key = m_creds.private_key_for( + pending_state.server_certs()->cert_chain()[0], + "tls-server", + sni_hostname); + + if(!private_key) + throw Internal_Error("No private key located for associated server cert"); + } + + if(pending_suite.kex_method() == Kex_Algo::STATIC_RSA) + { + pending_state.set_server_rsa_kex_key(private_key); + } + else + { + pending_state.server_kex(new Server_Key_Exchange(pending_state.handshake_io(), + pending_state, policy(), + m_creds, rng(), private_key)); + } + + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); + + std::vector client_auth_CAs; + + for(auto store : trusted_CAs) + { + auto subjects = store->all_subjects(); + client_auth_CAs.insert(client_auth_CAs.end(), subjects.begin(), subjects.end()); + } + + const bool request_cert = + (client_auth_CAs.empty() == false) || + policy().request_client_certificate_authentication(); + + if(request_cert && pending_state.ciphersuite().signature_used()) + { + pending_state.cert_req( + new Certificate_Req(pending_state.handshake_io(), + pending_state.hash(), + policy(), + client_auth_CAs, + pending_state.version())); + + /* + SSLv3 allowed clients to skip the Certificate message entirely + if they wanted. In TLS v1.0 and later clients must send a + (possibly empty) Certificate message + */ + pending_state.set_expected_next(CERTIFICATE); + } + else + { + pending_state.set_expected_next(CLIENT_KEX); + } + + pending_state.server_hello_done(new Server_Hello_Done(pending_state.handshake_io(), pending_state.hash())); + } +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_server.h b/comm/third_party/botan/src/lib/tls/tls_server.h new file mode 100644 index 0000000000..c601e8c6e3 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_server.h @@ -0,0 +1,169 @@ +/* +* TLS Server +* (C) 2004-2011 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SERVER_H_ +#define BOTAN_TLS_SERVER_H_ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +class Server_Handshake_State; + +/** +* TLS Server +*/ +class BOTAN_PUBLIC_API(2,0) Server final : public Channel + { + public: + typedef std::function)> next_protocol_fn; + + /** + * Server initialization + * + * @param callbacks contains a set of callback function references + * required by the TLS client. + * + * @param session_manager manages session state + * + * @param creds manages application/user credentials + * + * @param policy specifies other connection policy information + * + * @param rng a random number generator + * + * @param is_datagram set to true if this server should expect DTLS + * connections. Otherwise TLS connections are expected. + * + * @param reserved_io_buffer_size This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. + */ + Server(Callbacks& callbacks, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + bool is_datagram = false, + size_t reserved_io_buffer_size = TLS::Server::IO_BUF_DEFAULT_SIZE + ); + + /** + * DEPRECATED. This constructor is only provided for backward + * compatibility and should not be used in new implementations. + * It will be removed in a future release. + */ + BOTAN_DEPRECATED("Use TLS::Server(TLS::Callbacks ...)") + Server(output_fn output, + data_cb data_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + next_protocol_fn next_proto = next_protocol_fn(), + bool is_datagram = false, + size_t reserved_io_buffer_size = TLS::Server::IO_BUF_DEFAULT_SIZE + ); + + /** + * DEPRECATED. This constructor is only provided for backward + * compatibility and should not be used in new implementations. + * It will be removed in a future release. + */ + BOTAN_DEPRECATED("Use TLS::Server(TLS::Callbacks ...)") + Server(output_fn output, + data_cb data_cb, + alert_cb recv_alert_cb, + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + next_protocol_fn next_proto = next_protocol_fn(), + bool is_datagram = false + ); + + /** + * Return the protocol notification set by the client (using the + * ALPN extension) for this connection, if any. This value is not + * tied to the session and a later renegotiation of the same + * session can choose a new protocol. + */ + std::string next_protocol() const { return m_next_protocol; } + + /** + * Return the protocol notification set by the client (using the + * ALPN extension) for this connection, if any. This value is not + * tied to the session and a later renegotiation of the same + * session can choose a new protocol. + */ + std::string application_protocol() const override { return m_next_protocol; } + + private: + std::vector + get_peer_cert_chain(const Handshake_State& state) const override; + + void initiate_handshake(Handshake_State& state, + bool force_full_renegotiation) override; + + void process_handshake_msg(const Handshake_State* active_state, + Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents, + bool epoch0_restart) override; + + void process_client_hello_msg(const Handshake_State* active_state, + Server_Handshake_State& pending_state, + const std::vector& contents, + bool epoch0_restart); + + void process_certificate_msg(Server_Handshake_State& pending_state, + const std::vector& contents); + + void process_client_key_exchange_msg(Server_Handshake_State& pending_state, + const std::vector& contents); + + void process_change_cipher_spec_msg(Server_Handshake_State& pending_state); + + void process_certificate_verify_msg(Server_Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents); + + void process_finished_msg(Server_Handshake_State& pending_state, + Handshake_Type type, + const std::vector& contents); + + void session_resume(Server_Handshake_State& pending_state, + bool have_session_ticket_key, + Session& session_info); + + void session_create(Server_Handshake_State& pending_state, + bool have_session_ticket_key); + + Handshake_State* new_handshake_state(Handshake_IO* io) override; + + Credentials_Manager& m_creds; + std::string m_next_protocol; + + // Set by deprecated constructor, Server calls both this fn and Callbacks version + next_protocol_fn m_choose_next_protocol; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_server_info.h b/comm/third_party/botan/src/lib/tls/tls_server_info.h new file mode 100644 index 0000000000..d05af6acca --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_server_info.h @@ -0,0 +1,104 @@ +/* +* TLS Server Information +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SERVER_INFO_H_ +#define BOTAN_TLS_SERVER_INFO_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Represents information known about a TLS server. +*/ +class BOTAN_PUBLIC_API(2,0) Server_Information final + { + public: + /** + * An empty server info - nothing known + */ + Server_Information() : m_hostname(""), m_service(""), m_port(0) {} + + /** + * @param hostname the host's DNS name, if known + * @param port specifies the protocol port of the server (eg for + * TCP/UDP). Zero represents unknown. + */ + Server_Information(const std::string& hostname, + uint16_t port = 0) : + m_hostname(hostname), m_service(""), m_port(port) {} + + /** + * @param hostname the host's DNS name, if known + * @param service is a text string of the service type + * (eg "https", "tor", or "git") + * @param port specifies the protocol port of the server (eg for + * TCP/UDP). Zero represents unknown. + */ + Server_Information(const std::string& hostname, + const std::string& service, + uint16_t port = 0) : + m_hostname(hostname), m_service(service), m_port(port) {} + + /** + * @return the host's DNS name, if known + */ + std::string hostname() const { return m_hostname; } + + /** + * @return text string of the service type, e.g., + * "https", "tor", or "git" + */ + std::string service() const { return m_service; } + + /** + * @return the protocol port of the server, or zero if unknown + */ + uint16_t port() const { return m_port; } + + /** + * @return whether the hostname is known + */ + bool empty() const { return m_hostname.empty(); } + + private: + std::string m_hostname, m_service; + uint16_t m_port; + }; + +inline bool operator==(const Server_Information& a, const Server_Information& b) + { + return (a.hostname() == b.hostname()) && + (a.service() == b.service()) && + (a.port() == b.port()); + + } + +inline bool operator!=(const Server_Information& a, const Server_Information& b) + { + return !(a == b); + } + +inline bool operator<(const Server_Information& a, const Server_Information& b) + { + if(a.hostname() != b.hostname()) + return (a.hostname() < b.hostname()); + if(a.service() != b.service()) + return (a.service() < b.service()); + if(a.port() != b.port()) + return (a.port() < b.port()); + return false; // equal + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_session.cpp b/comm/third_party/botan/src/lib/tls/tls_session.cpp new file mode 100644 index 0000000000..0fd73c9fc5 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_session.cpp @@ -0,0 +1,299 @@ +/* +* TLS Session State +* (C) 2011-2012,2015,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Session::Session(const std::vector& session_identifier, + const secure_vector& master_secret, + Protocol_Version version, + uint16_t ciphersuite, + Connection_Side side, + bool extended_master_secret, + bool encrypt_then_mac, + const std::vector& certs, + const std::vector& ticket, + const Server_Information& server_info, + const std::string& srp_identifier, + uint16_t srtp_profile) : + m_start_time(std::chrono::system_clock::now()), + m_identifier(session_identifier), + m_session_ticket(ticket), + m_master_secret(master_secret), + m_version(version), + m_ciphersuite(ciphersuite), + m_connection_side(side), + m_srtp_profile(srtp_profile), + m_extended_master_secret(extended_master_secret), + m_encrypt_then_mac(encrypt_then_mac), + m_peer_certs(certs), + m_server_info(server_info), + m_srp_identifier(srp_identifier) + { + } + +Session::Session(const std::string& pem) + { + secure_vector der = PEM_Code::decode_check_label(pem, "TLS SESSION"); + + *this = Session(der.data(), der.size()); + } + +Session::Session(const uint8_t ber[], size_t ber_len) + { + uint8_t side_code = 0; + + ASN1_String server_hostname; + ASN1_String server_service; + size_t server_port; + + ASN1_String srp_identifier_str; + + uint8_t major_version = 0, minor_version = 0; + std::vector peer_cert_bits; + + size_t start_time = 0; + size_t srtp_profile = 0; + size_t fragment_size = 0; + size_t compression_method = 0; + + BER_Decoder(ber, ber_len) + .start_cons(SEQUENCE) + .decode_and_check(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION), + "Unknown version in serialized TLS session") + .decode_integer_type(start_time) + .decode_integer_type(major_version) + .decode_integer_type(minor_version) + .decode(m_identifier, OCTET_STRING) + .decode(m_session_ticket, OCTET_STRING) + .decode_integer_type(m_ciphersuite) + .decode_integer_type(compression_method) + .decode_integer_type(side_code) + .decode_integer_type(fragment_size) + .decode(m_extended_master_secret) + .decode(m_encrypt_then_mac) + .decode(m_master_secret, OCTET_STRING) + .decode(peer_cert_bits, OCTET_STRING) + .decode(server_hostname) + .decode(server_service) + .decode(server_port) + .decode(srp_identifier_str) + .decode(srtp_profile) + .end_cons() + .verify_end(); + + /* + * Compression is not supported and must be zero + */ + if(compression_method != 0) + { + throw Decoding_Error("Serialized TLS session contains non-null compression method"); + } + + /* + Fragment size is not supported anymore, but the field is still + set in the session object. + */ + if(fragment_size != 0) + { + throw Decoding_Error("Serialized TLS session used maximum fragment length which is " + " no longer supported"); + } + + m_version = Protocol_Version(major_version, minor_version); + m_start_time = std::chrono::system_clock::from_time_t(start_time); + m_connection_side = static_cast(side_code); + m_srtp_profile = static_cast(srtp_profile); + + m_server_info = Server_Information(server_hostname.value(), + server_service.value(), + static_cast(server_port)); + + m_srp_identifier = srp_identifier_str.value(); + + if(!peer_cert_bits.empty()) + { + DataSource_Memory certs(peer_cert_bits.data(), peer_cert_bits.size()); + + while(!certs.end_of_data()) + m_peer_certs.push_back(X509_Certificate(certs)); + } + } + +secure_vector Session::DER_encode() const + { + std::vector peer_cert_bits; + for(size_t i = 0; i != m_peer_certs.size(); ++i) + peer_cert_bits += m_peer_certs[i].BER_encode(); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION)) + .encode(static_cast(std::chrono::system_clock::to_time_t(m_start_time))) + .encode(static_cast(m_version.major_version())) + .encode(static_cast(m_version.minor_version())) + .encode(m_identifier, OCTET_STRING) + .encode(m_session_ticket, OCTET_STRING) + .encode(static_cast(m_ciphersuite)) + .encode(static_cast(/*old compression method*/0)) + .encode(static_cast(m_connection_side)) + .encode(static_cast(/*old fragment size*/0)) + .encode(m_extended_master_secret) + .encode(m_encrypt_then_mac) + .encode(m_master_secret, OCTET_STRING) + .encode(peer_cert_bits, OCTET_STRING) + .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING)) + .encode(ASN1_String(m_server_info.service(), UTF8_STRING)) + .encode(static_cast(m_server_info.port())) + .encode(ASN1_String(m_srp_identifier, UTF8_STRING)) + .encode(static_cast(m_srtp_profile)) + .end_cons() + .get_contents(); + } + +std::string Session::PEM_encode() const + { + return PEM_Code::encode(this->DER_encode(), "TLS SESSION"); + } + +std::chrono::seconds Session::session_age() const + { + return std::chrono::duration_cast( + std::chrono::system_clock::now() - m_start_time); + } + +namespace { + +// The output length of the HMAC must be a valid keylength for the AEAD +const char* TLS_SESSION_CRYPT_HMAC = "HMAC(SHA-512-256)"; +// SIV would be better, but we can't assume it is available +const char* TLS_SESSION_CRYPT_AEAD = "AES-256/GCM"; +const char* TLS_SESSION_CRYPT_KEY_NAME = "BOTAN TLS SESSION KEY NAME"; +const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000; +const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8; +const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4; +const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12; +const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16; +const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16; + +const size_t TLS_SESSION_CRYPT_HDR_LEN = + TLS_SESSION_CRYPT_MAGIC_LEN + + TLS_SESSION_CRYPT_KEY_NAME_LEN + + TLS_SESSION_CRYPT_AEAD_NONCE_LEN + + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN; + +const size_t TLS_SESSION_CRYPT_OVERHEAD = + TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE; + +} + +std::vector +Session::encrypt(const SymmetricKey& key, RandomNumberGenerator& rng) const + { + auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC); + hmac->set_key(key); + + // First derive the "key name" + std::vector key_name(hmac->output_length()); + hmac->update(TLS_SESSION_CRYPT_KEY_NAME); + hmac->final(key_name.data()); + key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN); + + std::vector aead_nonce; + std::vector key_seed; + + rng.random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN); + rng.random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN); + + hmac->update(key_seed); + const secure_vector aead_key = hmac->final(); + + secure_vector bits = this->DER_encode(); + + // create the header + std::vector buf; + buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size()); + buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN); + store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]); + buf += key_name; + buf += key_seed; + buf += aead_nonce; + + std::unique_ptr aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, ENCRYPTION); + BOTAN_ASSERT_NOMSG(aead->valid_nonce_length(TLS_SESSION_CRYPT_AEAD_NONCE_LEN)); + BOTAN_ASSERT_NOMSG(aead->tag_size() == TLS_SESSION_CRYPT_AEAD_TAG_SIZE); + aead->set_key(aead_key); + aead->set_associated_data_vec(buf); + aead->start(aead_nonce); + aead->finish(bits, 0); + + // append the ciphertext + buf += bits; + return buf; + } + +Session Session::decrypt(const uint8_t in[], size_t in_len, const SymmetricKey& key) + { + try + { + const size_t min_session_size = 48 + 4; // serious under-estimate + if(in_len < TLS_SESSION_CRYPT_OVERHEAD + min_session_size) + throw Decoding_Error("Encrypted session too short to be valid"); + + const uint8_t* magic = &in[0]; + const uint8_t* key_name = magic + TLS_SESSION_CRYPT_MAGIC_LEN; + const uint8_t* key_seed = key_name + TLS_SESSION_CRYPT_KEY_NAME_LEN; + const uint8_t* aead_nonce = key_seed + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN; + const uint8_t* ctext = aead_nonce + TLS_SESSION_CRYPT_AEAD_NONCE_LEN; + const size_t ctext_len = in_len - TLS_SESSION_CRYPT_HDR_LEN; // includes the tag + + if(load_be(magic, 0) != TLS_SESSION_CRYPT_MAGIC) + throw Decoding_Error("Missing expected magic numbers"); + + auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC); + hmac->set_key(key); + + // First derive and check the "key name" + std::vector cmp_key_name(hmac->output_length()); + hmac->update(TLS_SESSION_CRYPT_KEY_NAME); + hmac->final(cmp_key_name.data()); + + if(same_mem(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN) == false) + throw Decoding_Error("Wrong key name for encrypted session"); + + hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN); + const secure_vector aead_key = hmac->final(); + + auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, DECRYPTION); + aead->set_key(aead_key); + aead->set_associated_data(in, TLS_SESSION_CRYPT_HDR_LEN); + aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN); + secure_vector buf(ctext, ctext + ctext_len); + aead->finish(buf, 0); + return Session(buf.data(), buf.size()); + } + catch(std::exception& e) + { + throw Decoding_Error("Failed to decrypt serialized TLS session: " + + std::string(e.what())); + } + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_session.h b/comm/third_party/botan/src/lib/tls/tls_session.h new file mode 100644 index 0000000000..5a75e6a32b --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_session.h @@ -0,0 +1,210 @@ +/* +* TLS Session +* (C) 2011-2012,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SESSION_STATE_H_ +#define BOTAN_TLS_SESSION_STATE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Class representing a TLS session state +*/ +class BOTAN_PUBLIC_API(2,0) Session final + { + public: + + /** + * Uninitialized session + */ + Session() : + m_start_time(std::chrono::system_clock::time_point::min()), + m_version(), + m_ciphersuite(0), + m_connection_side(static_cast(0)), + m_srtp_profile(0), + m_extended_master_secret(false), + m_encrypt_then_mac(false) + {} + + /** + * New session (sets session start time) + */ + Session(const std::vector& session_id, + const secure_vector& master_secret, + Protocol_Version version, + uint16_t ciphersuite, + Connection_Side side, + bool supports_extended_master_secret, + bool supports_encrypt_then_mac, + const std::vector& peer_certs, + const std::vector& session_ticket, + const Server_Information& server_info, + const std::string& srp_identifier, + uint16_t srtp_profile); + + /** + * Load a session from DER representation (created by DER_encode) + * @param ber DER representation buffer + * @param ber_len size of buffer in bytes + */ + Session(const uint8_t ber[], size_t ber_len); + + /** + * Load a session from PEM representation (created by PEM_encode) + * @param pem PEM representation + */ + explicit Session(const std::string& pem); + + /** + * Encode this session data for storage + * @warning if the master secret is compromised so is the + * session traffic + */ + secure_vector DER_encode() const; + + /** + * Encrypt a session (useful for serialization or session tickets) + */ + std::vector encrypt(const SymmetricKey& key, + RandomNumberGenerator& rng) const; + + + /** + * Decrypt a session created by encrypt + * @param ctext the ciphertext returned by encrypt + * @param ctext_size the size of ctext in bytes + * @param key the same key used by the encrypting side + */ + static Session decrypt(const uint8_t ctext[], + size_t ctext_size, + const SymmetricKey& key); + + /** + * Decrypt a session created by encrypt + * @param ctext the ciphertext returned by encrypt + * @param key the same key used by the encrypting side + */ + static inline Session decrypt(const std::vector& ctext, + const SymmetricKey& key) + { + return Session::decrypt(ctext.data(), ctext.size(), key); + } + + /** + * Encode this session data for storage + * @warning if the master secret is compromised so is the + * session traffic + */ + std::string PEM_encode() const; + + /** + * Get the version of the saved session + */ + Protocol_Version version() const { return m_version; } + + /** + * Get the ciphersuite code of the saved session + */ + uint16_t ciphersuite_code() const { return m_ciphersuite; } + + /** + * Get the ciphersuite info of the saved session + */ + Ciphersuite ciphersuite() const { return Ciphersuite::by_id(m_ciphersuite); } + + /** + * Get which side of the connection the resumed session we are/were + * acting as. + */ + Connection_Side side() const { return m_connection_side; } + + /** + * Get the SRP identity (if sent by the client in the initial handshake) + */ + const std::string& srp_identifier() const { return m_srp_identifier; } + + /** + * Get the saved master secret + */ + const secure_vector& master_secret() const { return m_master_secret; } + + /** + * Get the session identifier + */ + const std::vector& session_id() const { return m_identifier; } + + /** + * Get the negotiated DTLS-SRTP algorithm (RFC 5764) + */ + uint16_t dtls_srtp_profile() const { return m_srtp_profile; } + + bool supports_extended_master_secret() const { return m_extended_master_secret; } + + bool supports_encrypt_then_mac() const { return m_encrypt_then_mac; } + + /** + * Return the certificate chain of the peer (possibly empty) + */ + const std::vector& peer_certs() const { return m_peer_certs; } + + /** + * Get the wall clock time this session began + */ + std::chrono::system_clock::time_point start_time() const { return m_start_time; } + + /** + * Return how long this session has existed (in seconds) + */ + std::chrono::seconds session_age() const; + + /** + * Return the session ticket the server gave us + */ + const std::vector& session_ticket() const { return m_session_ticket; } + + /** + * @return information about the TLS server + */ + const Server_Information& server_info() const { return m_server_info; } + + private: + enum { TLS_SESSION_PARAM_STRUCT_VERSION = 20160812 }; + + std::chrono::system_clock::time_point m_start_time; + + std::vector m_identifier; + std::vector m_session_ticket; // only used by client side + secure_vector m_master_secret; + + Protocol_Version m_version; + uint16_t m_ciphersuite; + Connection_Side m_connection_side; + uint16_t m_srtp_profile; + bool m_extended_master_secret; + bool m_encrypt_then_mac; + + std::vector m_peer_certs; + Server_Information m_server_info; // optional + std::string m_srp_identifier; // optional + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_session_key.cpp b/comm/third_party/botan/src/lib/tls/tls_session_key.cpp new file mode 100644 index 0000000000..2066810413 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_session_key.cpp @@ -0,0 +1,101 @@ +/* +* TLS Session Key +* (C) 2004-2006,2011,2016,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Session_Keys Constructor +*/ +Session_Keys::Session_Keys(const Handshake_State* state, + const secure_vector& pre_master_secret, + bool resuming) + { + const size_t cipher_keylen = state->ciphersuite().cipher_keylen(); + const size_t mac_keylen = state->ciphersuite().mac_keylen(); + const size_t cipher_nonce_bytes = state->ciphersuite().nonce_bytes_from_handshake(); + + const bool extended_master_secret = state->server_hello()->supports_extended_master_secret(); + + const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_nonce_bytes); + + const uint8_t MASTER_SECRET_MAGIC[] = { + 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 }; + + const uint8_t EXT_MASTER_SECRET_MAGIC[] = { + 0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, + 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 }; + + const uint8_t KEY_GEN_MAGIC[] = { + 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, 0x6E }; + + std::unique_ptr prf(state->protocol_specific_prf()); + + if(resuming) + { + // This is actually the master secret saved as part of the session + m_master_sec = pre_master_secret; + } + else + { + std::vector salt; + std::vector label; + if(extended_master_secret) + { + label.assign(EXT_MASTER_SECRET_MAGIC, EXT_MASTER_SECRET_MAGIC + sizeof(EXT_MASTER_SECRET_MAGIC)); + salt += state->hash().final(state->version(), + state->ciphersuite().prf_algo()); + } + else + { + label.assign(MASTER_SECRET_MAGIC, MASTER_SECRET_MAGIC + sizeof(MASTER_SECRET_MAGIC)); + salt += state->client_hello()->random(); + salt += state->server_hello()->random(); + } + + m_master_sec = prf->derive_key(48, pre_master_secret, salt, label); + } + + std::vector salt; + std::vector label; + label.assign(KEY_GEN_MAGIC, KEY_GEN_MAGIC + sizeof(KEY_GEN_MAGIC)); + salt += state->server_hello()->random(); + salt += state->client_hello()->random(); + + const secure_vector prf_output = prf->derive_key( + prf_gen, + m_master_sec.data(), m_master_sec.size(), + salt.data(), salt.size(), + label.data(), label.size()); + + const uint8_t* key_data = prf_output.data(); + + m_c_aead.resize(mac_keylen + cipher_keylen); + m_s_aead.resize(mac_keylen + cipher_keylen); + + copy_mem(&m_c_aead[0], key_data, mac_keylen); + copy_mem(&m_s_aead[0], key_data + mac_keylen, mac_keylen); + + copy_mem(&m_c_aead[mac_keylen], key_data + 2*mac_keylen, cipher_keylen); + copy_mem(&m_s_aead[mac_keylen], key_data + 2*mac_keylen + cipher_keylen, cipher_keylen); + + m_c_nonce.resize(cipher_nonce_bytes); + m_s_nonce.resize(cipher_nonce_bytes); + + copy_mem(&m_c_nonce[0], key_data + 2*(mac_keylen + cipher_keylen), cipher_nonce_bytes); + copy_mem(&m_s_nonce[0], key_data + 2*(mac_keylen + cipher_keylen) + cipher_nonce_bytes, cipher_nonce_bytes); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_session_key.h b/comm/third_party/botan/src/lib/tls/tls_session_key.h new file mode 100644 index 0000000000..0ea6d81cd5 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_session_key.h @@ -0,0 +1,82 @@ +/* +* TLS Session Key +* (C) 2004-2006,2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SESSION_KEYS_H_ +#define BOTAN_TLS_SESSION_KEYS_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +class Handshake_State; + +/** +* TLS Session Keys +*/ +class Session_Keys final + { + public: + /** + * @return client AEAD key + */ + const secure_vector& client_aead_key() const { return m_c_aead; } + + /** + * @return server AEAD key + */ + const secure_vector& server_aead_key() const { return m_s_aead; } + + /** + * @return client nonce + */ + const std::vector& client_nonce() const { return m_c_nonce; } + + /** + * @return server nonce + */ + const std::vector& server_nonce() const { return m_s_nonce; } + + /** + * @return TLS master secret + */ + const secure_vector& master_secret() const { return m_master_sec; } + + const secure_vector& aead_key(Connection_Side side) const + { + return (side == Connection_Side::CLIENT) ? client_aead_key() : server_aead_key(); + } + + const std::vector& nonce(Connection_Side side) const + { + return (side == Connection_Side::CLIENT) ? client_nonce() : server_nonce(); + } + + Session_Keys() = default; + + /** + * @param state state the handshake state + * @param pre_master_secret the pre-master secret + * @param resuming whether this TLS session is resumed + */ + Session_Keys(const Handshake_State* state, + const secure_vector& pre_master_secret, + bool resuming); + + private: + secure_vector m_master_sec; + secure_vector m_c_aead, m_s_aead; + std::vector m_c_nonce, m_s_nonce; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_session_manager.h b/comm/third_party/botan/src/lib/tls/tls_session_manager.h new file mode 100644 index 0000000000..40ca48f719 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_session_manager.h @@ -0,0 +1,160 @@ +/* +* TLS Session Manager +* (C) 2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_SESSION_MANAGER_H_ +#define BOTAN_TLS_SESSION_MANAGER_H_ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* Session_Manager is an interface to systems which can save +* session parameters for supporting session resumption. +* +* Saving sessions is done on a best-effort basis; an implementation is +* allowed to drop sessions due to space constraints. +* +* Implementations should strive to be thread safe +*/ +class BOTAN_PUBLIC_API(2,0) Session_Manager + { + public: + /** + * Try to load a saved session (using session ID) + * @param session_id the session identifier we are trying to resume + * @param session will be set to the saved session data (if found), + or not modified if not found + * @return true if session was modified + */ + virtual bool load_from_session_id(const std::vector& session_id, + Session& session) = 0; + + /** + * Try to load a saved session (using info about server) + * @param info the information about the server + * @param session will be set to the saved session data (if found), + or not modified if not found + * @return true if session was modified + */ + virtual bool load_from_server_info(const Server_Information& info, + Session& session) = 0; + + /** + * Remove this session id from the cache, if it exists + */ + virtual void remove_entry(const std::vector& session_id) = 0; + + /** + * Remove all sessions from the cache, return number of sessions deleted + */ + virtual size_t remove_all() = 0; + + /** + * Save a session on a best effort basis; the manager may not in + * fact be able to save the session for whatever reason; this is + * not an error. Caller cannot assume that calling save followed + * immediately by load_from_* will result in a successful lookup. + * + * @param session to save + */ + virtual void save(const Session& session) = 0; + + /** + * Return the allowed lifetime of a session; beyond this time, + * sessions are not resumed. Returns 0 if unknown/no explicit + * expiration policy. + */ + virtual std::chrono::seconds session_lifetime() const = 0; + + virtual ~Session_Manager() = default; + }; + +/** +* An implementation of Session_Manager that does not save sessions at +* all, preventing session resumption. +*/ +class BOTAN_PUBLIC_API(2,0) Session_Manager_Noop final : public Session_Manager + { + public: + bool load_from_session_id(const std::vector&, Session&) override + { return false; } + + bool load_from_server_info(const Server_Information&, Session&) override + { return false; } + + void remove_entry(const std::vector&) override {} + + size_t remove_all() override { return 0; } + + void save(const Session&) override {} + + std::chrono::seconds session_lifetime() const override + { return std::chrono::seconds(0); } + }; + +/** +* An implementation of Session_Manager that saves values in memory. +*/ +class BOTAN_PUBLIC_API(2,0) Session_Manager_In_Memory final : public Session_Manager + { + public: + /** + * @param rng a RNG used for generating session key and for + * session encryption + * @param max_sessions a hint on the maximum number of sessions + * to keep in memory at any one time. (If zero, don't cap) + * @param session_lifetime sessions are expired after this many + * seconds have elapsed from initial handshake. + */ + Session_Manager_In_Memory(RandomNumberGenerator& rng, + size_t max_sessions = 1000, + std::chrono::seconds session_lifetime = + std::chrono::seconds(7200)); + + bool load_from_session_id(const std::vector& session_id, + Session& session) override; + + bool load_from_server_info(const Server_Information& info, + Session& session) override; + + void remove_entry(const std::vector& session_id) override; + + size_t remove_all() override; + + void save(const Session& session_data) override; + + std::chrono::seconds session_lifetime() const override + { return m_session_lifetime; } + + private: + bool load_from_session_str(const std::string& session_str, + Session& session); + + mutex_type m_mutex; + + size_t m_max_sessions; + + std::chrono::seconds m_session_lifetime; + + RandomNumberGenerator& m_rng; + secure_vector m_session_key; + + std::map> m_sessions; // hex(session_id) -> session + std::map m_info_sessions; + }; + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/tls/tls_session_manager_memory.cpp b/comm/third_party/botan/src/lib/tls/tls_session_manager_memory.cpp new file mode 100644 index 0000000000..600eb440a9 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_session_manager_memory.cpp @@ -0,0 +1,132 @@ +/* +* TLS Session Management +* (C) 2011,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +Session_Manager_In_Memory::Session_Manager_In_Memory( + RandomNumberGenerator& rng, + size_t max_sessions, + std::chrono::seconds session_lifetime) : + m_max_sessions(max_sessions), + m_session_lifetime(session_lifetime), + m_rng(rng), + m_session_key(m_rng.random_vec(32)) + {} + +bool Session_Manager_In_Memory::load_from_session_str( + const std::string& session_str, Session& session) + { + // assert(lock is held) + + auto i = m_sessions.find(session_str); + + if(i == m_sessions.end()) + return false; + + try + { + session = Session::decrypt(i->second, m_session_key); + } + catch(...) + { + return false; + } + + // if session has expired, remove it + const auto now = std::chrono::system_clock::now(); + + if(session.start_time() + session_lifetime() < now) + { + m_sessions.erase(i); + return false; + } + + return true; + } + +bool Session_Manager_In_Memory::load_from_session_id( + const std::vector& session_id, Session& session) + { + lock_guard_type lock(m_mutex); + + return load_from_session_str(hex_encode(session_id), session); + } + +bool Session_Manager_In_Memory::load_from_server_info( + const Server_Information& info, Session& session) + { + lock_guard_type lock(m_mutex); + + auto i = m_info_sessions.find(info); + + if(i == m_info_sessions.end()) + return false; + + if(load_from_session_str(i->second, session)) + return true; + + /* + * It existed at one point but was removed from the sessions map, + * remove m_info_sessions entry as well + */ + m_info_sessions.erase(i); + + return false; + } + +void Session_Manager_In_Memory::remove_entry( + const std::vector& session_id) + { + lock_guard_type lock(m_mutex); + + auto i = m_sessions.find(hex_encode(session_id)); + + if(i != m_sessions.end()) + m_sessions.erase(i); + } + +size_t Session_Manager_In_Memory::remove_all() + { + const size_t removed = m_sessions.size(); + m_info_sessions.clear(); + m_sessions.clear(); + m_rng.random_vec(m_session_key, 32); + return removed; + } + +void Session_Manager_In_Memory::save(const Session& session) + { + lock_guard_type lock(m_mutex); + + if(m_max_sessions != 0) + { + /* + We generate new session IDs with the first 4 bytes being a + timestamp, so this actually removes the oldest sessions first. + */ + while(m_sessions.size() >= m_max_sessions) + m_sessions.erase(m_sessions.begin()); + } + + const std::string session_id_str = hex_encode(session.session_id()); + + m_sessions[session_id_str] = session.encrypt(m_session_key, m_rng); + + if(session.side() == CLIENT && !session.server_info().empty()) + m_info_sessions[session.server_info()] = session_id_str; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_suite_info.cpp b/comm/third_party/botan/src/lib/tls/tls_suite_info.cpp new file mode 100644 index 0000000000..f55b7cce16 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_suite_info.cpp @@ -0,0 +1,212 @@ +/* +* TLS cipher suite information +* +* This file was automatically generated from the IANA assignments +* (tls-parameters.txt hash fe1ef8f3492b0708f3b14c9e8f8de55188c1b3c0) +* by ./src/scripts/tls_suite_info.py on 2019-05-24 +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +namespace TLS { + +//static +const std::vector& Ciphersuite::all_known_ciphersuites() + { + // Note that this list of ciphersuites is ordered by id! + static const std::vector g_ciphersuite_list = { + Ciphersuite(0x000A, "RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0013, "DHE_DSS_WITH_3DES_EDE_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0016, "DHE_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x001B, "DH_anon_WITH_3DES_EDE_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x002F, "RSA_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0032, "DHE_DSS_WITH_AES_128_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0033, "DHE_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0034, "DH_anon_WITH_AES_128_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0035, "RSA_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0038, "DHE_DSS_WITH_AES_256_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0039, "DHE_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x003A, "DH_anon_WITH_AES_256_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x003C, "RSA_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x003D, "RSA_WITH_AES_256_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x0040, "DHE_DSS_WITH_AES_128_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x0041, "RSA_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0044, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0045, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0046, "DH_anon_WITH_CAMELLIA_128_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0067, "DHE_RSA_WITH_AES_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x006A, "DHE_DSS_WITH_AES_256_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x006B, "DHE_RSA_WITH_AES_256_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x006C, "DH_anon_WITH_AES_128_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x006D, "DH_anon_WITH_AES_256_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x0084, "RSA_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0087, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0088, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0089, "DH_anon_WITH_CAMELLIA_256_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x008B, "PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x008C, "PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x008D, "PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x008F, "DHE_PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0090, "DHE_PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0091, "DHE_PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0096, "RSA_WITH_SEED_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x0099, "DHE_DSS_WITH_SEED_CBC_SHA", Auth_Method::DSA, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x009A, "DHE_RSA_WITH_SEED_CBC_SHA", Auth_Method::RSA, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x009B, "DH_anon_WITH_SEED_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::DH, "SEED", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0x009C, "RSA_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x009D, "RSA_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x009E, "DHE_RSA_WITH_AES_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x009F, "DHE_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::DH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00A2, "DHE_DSS_WITH_AES_128_GCM_SHA256", Auth_Method::DSA, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00A3, "DHE_DSS_WITH_AES_256_GCM_SHA384", Auth_Method::DSA, Kex_Algo::DH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00A6, "DH_anon_WITH_AES_128_GCM_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00A7, "DH_anon_WITH_AES_256_GCM_SHA384", Auth_Method::ANONYMOUS, Kex_Algo::DH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00A8, "PSK_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00A9, "PSK_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00AA, "DHE_PSK_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00AB, "DHE_PSK_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x00AE, "PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00AF, "PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0x00B2, "DHE_PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00B3, "DHE_PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0x00BA, "RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00BD, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00BE, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00BF, "DH_anon_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00C0, "RSA_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00C3, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::DSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00C4, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x00C5, "DH_anon_WITH_CAMELLIA_256_CBC_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-256", 32, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0x16B7, "CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::CECPQ1, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0x16B8, "CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0x16B9, "CECPQ1_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::CECPQ1, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0x16BA, "CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC008, "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::ECDSA, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC009, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC00A, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC012, "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC013, "ECDHE_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC014, "ECDHE_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC017, "ECDH_anon_WITH_3DES_EDE_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::ECDH, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC018, "ECDH_anon_WITH_AES_128_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::ECDH, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC019, "ECDH_anon_WITH_AES_256_CBC_SHA", Auth_Method::ANONYMOUS, Kex_Algo::ECDH, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC01A, "SRP_SHA_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC01B, "SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC01C, "SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", Auth_Method::DSA, Kex_Algo::SRP_SHA, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC01D, "SRP_SHA_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC01E, "SRP_SHA_RSA_WITH_AES_128_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC01F, "SRP_SHA_DSS_WITH_AES_128_CBC_SHA", Auth_Method::DSA, Kex_Algo::SRP_SHA, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC020, "SRP_SHA_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC021, "SRP_SHA_RSA_WITH_AES_256_CBC_SHA", Auth_Method::RSA, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC022, "SRP_SHA_DSS_WITH_AES_256_CBC_SHA", Auth_Method::DSA, Kex_Algo::SRP_SHA, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC023, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC024, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC027, "ECDHE_RSA_WITH_AES_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC028, "ECDHE_RSA_WITH_AES_256_CBC_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC02B, "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC02C, "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC02F, "ECDHE_RSA_WITH_AES_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC030, "ECDHE_RSA_WITH_AES_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC034, "ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "3DES", 24, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC035, "ECDHE_PSK_WITH_AES_128_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128", 16, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC036, "ECDHE_PSK_WITH_AES_256_CBC_SHA", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256", 32, "SHA-1", 20, KDF_Algo::SHA_1, Nonce_Format::CBC_MODE), + Ciphersuite(0xC037, "ECDHE_PSK_WITH_AES_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC038, "ECDHE_PSK_WITH_AES_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC050, "RSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC051, "RSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC052, "DHE_RSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC053, "DHE_RSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::DH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC056, "DHE_DSS_WITH_ARIA_128_GCM_SHA256", Auth_Method::DSA, Kex_Algo::DH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC057, "DHE_DSS_WITH_ARIA_256_GCM_SHA384", Auth_Method::DSA, Kex_Algo::DH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC05A, "DH_anon_WITH_ARIA_128_GCM_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC05B, "DH_anon_WITH_ARIA_256_GCM_SHA384", Auth_Method::ANONYMOUS, Kex_Algo::DH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC05C, "ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC05D, "ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC060, "ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC061, "ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC06A, "PSK_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC06B, "PSK_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC06C, "DHE_PSK_WITH_ARIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ARIA-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC06D, "DHE_PSK_WITH_ARIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ARIA-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC072, "ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC073, "ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC076, "ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC077, "ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC07A, "RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC07B, "RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC07C, "DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC07D, "DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::DH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC080, "DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::DSA, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC081, "DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::DSA, Kex_Algo::DH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC084, "DH_anon_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC085, "DH_anon_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::ANONYMOUS, Kex_Algo::DH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC086, "ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC087, "ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::ECDSA, Kex_Algo::ECDH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC08A, "ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC08B, "ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::RSA, Kex_Algo::ECDH, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC08E, "PSK_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC08F, "PSK_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC090, "DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC091, "DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC094, "PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC095, "PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC096, "DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC097, "DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC09A, "ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "Camellia-128", 16, "SHA-256", 32, KDF_Algo::SHA_256, Nonce_Format::CBC_MODE), + Ciphersuite(0xC09B, "ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "Camellia-256", 32, "SHA-384", 48, KDF_Algo::SHA_384, Nonce_Format::CBC_MODE), + Ciphersuite(0xC09C, "RSA_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC09D, "RSA_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC09E, "DHE_RSA_WITH_AES_128_CCM", Auth_Method::RSA, Kex_Algo::DH, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC09F, "DHE_RSA_WITH_AES_256_CCM", Auth_Method::RSA, Kex_Algo::DH, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A0, "RSA_WITH_AES_128_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A1, "RSA_WITH_AES_256_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::STATIC_RSA, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A2, "DHE_RSA_WITH_AES_128_CCM_8", Auth_Method::RSA, Kex_Algo::DH, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A3, "DHE_RSA_WITH_AES_256_CCM_8", Auth_Method::RSA, Kex_Algo::DH, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A4, "PSK_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A5, "PSK_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A6, "DHE_PSK_WITH_AES_128_CCM", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A7, "DHE_PSK_WITH_AES_256_CCM", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A8, "PSK_WITH_AES_128_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0A9, "PSK_WITH_AES_256_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0AA, "PSK_DHE_WITH_AES_128_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0AB, "PSK_DHE_WITH_AES_256_CCM_8", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0AC, "ECDHE_ECDSA_WITH_AES_128_CCM", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0AD, "ECDHE_ECDSA_WITH_AES_256_CCM", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/CCM", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0AE, "ECDHE_ECDSA_WITH_AES_128_CCM_8", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xC0AF, "ECDHE_ECDSA_WITH_AES_256_CCM_8", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/CCM(8)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xCCA8, "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xCCA9, "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xCCAA, "DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::RSA, Kex_Algo::DH, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xCCAB, "PSK_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xCCAC, "ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xCCAD, "DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "ChaCha20Poly1305", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xD001, "ECDHE_PSK_WITH_AES_128_GCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/GCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xD002, "ECDHE_PSK_WITH_AES_256_GCM_SHA384", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256/GCM", 32, "AEAD", 0, KDF_Algo::SHA_384, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xD003, "ECDHE_PSK_WITH_AES_128_CCM_8_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/CCM(8)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xD005, "ECDHE_PSK_WITH_AES_128_CCM_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/CCM", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_IMPLICIT_4), + Ciphersuite(0xFFC0, "DHE_RSA_WITH_AES_128_OCB_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC1, "DHE_RSA_WITH_AES_256_OCB_SHA256", Auth_Method::RSA, Kex_Algo::DH, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC2, "ECDHE_RSA_WITH_AES_128_OCB_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC3, "ECDHE_RSA_WITH_AES_256_OCB_SHA256", Auth_Method::RSA, Kex_Algo::ECDH, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC4, "ECDHE_ECDSA_WITH_AES_128_OCB_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC5, "ECDHE_ECDSA_WITH_AES_256_OCB_SHA256", Auth_Method::ECDSA, Kex_Algo::ECDH, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC6, "PSK_WITH_AES_128_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC7, "PSK_WITH_AES_256_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::PSK, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC8, "DHE_PSK_WITH_AES_128_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFC9, "DHE_PSK_WITH_AES_256_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::DHE_PSK, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFCA, "ECDHE_PSK_WITH_AES_128_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-128/OCB(12)", 16, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFCB, "ECDHE_PSK_WITH_AES_256_OCB_SHA256", Auth_Method::IMPLICIT, Kex_Algo::ECDHE_PSK, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFCC, "CECPQ1_RSA_WITH_AES_256_OCB_SHA256", Auth_Method::RSA, Kex_Algo::CECPQ1, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + Ciphersuite(0xFFCD, "CECPQ1_ECDSA_WITH_AES_256_OCB_SHA256", Auth_Method::ECDSA, Kex_Algo::CECPQ1, "AES-256/OCB(12)", 32, "AEAD", 0, KDF_Algo::SHA_256, Nonce_Format::AEAD_XOR_12), + }; + + return g_ciphersuite_list; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_text_policy.cpp b/comm/third_party/botan/src/lib/tls/tls_text_policy.cpp new file mode 100644 index 0000000000..1b83f0dbde --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_text_policy.cpp @@ -0,0 +1,319 @@ +/* +* Text-Based TLS Policy +* (C) 2016,2017 Jack Lloyd +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace TLS { + +std::vector Text_Policy::allowed_ciphers() const + { + return get_list("ciphers", Policy::allowed_ciphers()); + } + +std::vector Text_Policy::allowed_signature_hashes() const + { + return get_list("signature_hashes", Policy::allowed_signature_hashes()); + } + +std::vector Text_Policy::allowed_macs() const + { + return get_list("macs", Policy::allowed_macs()); + } + +std::vector Text_Policy::allowed_key_exchange_methods() const + { + return get_list("key_exchange_methods", Policy::allowed_key_exchange_methods()); + } + +std::vector Text_Policy::allowed_signature_methods() const + { + return get_list("signature_methods", Policy::allowed_signature_methods()); + } + +bool Text_Policy::use_ecc_point_compression() const + { + return get_bool("use_ecc_point_compression", Policy::use_ecc_point_compression()); + } + +bool Text_Policy::allow_tls10() const + { + return get_bool("allow_tls10", Policy::allow_tls10()); + } + +bool Text_Policy::allow_tls11() const + { + return get_bool("allow_tls11", Policy::allow_tls11()); + } + +bool Text_Policy::allow_tls12() const + { + return get_bool("allow_tls12", Policy::allow_tls12()); + } + +bool Text_Policy::allow_dtls10() const + { + return get_bool("allow_dtls10", Policy::allow_dtls10()); + } + +bool Text_Policy::allow_dtls12() const + { + return get_bool("allow_dtls12", Policy::allow_dtls12()); + } + +bool Text_Policy::allow_insecure_renegotiation() const + { + return get_bool("allow_insecure_renegotiation", Policy::allow_insecure_renegotiation()); + } + +bool Text_Policy::include_time_in_hello_random() const + { + return get_bool("include_time_in_hello_random", Policy::include_time_in_hello_random()); + } + +bool Text_Policy::require_client_certificate_authentication() const + { + return get_bool("require_client_certificate_authentication", Policy::require_client_certificate_authentication()); + } + +bool Text_Policy::allow_client_initiated_renegotiation() const + { + return get_bool("allow_client_initiated_renegotiation", Policy::allow_client_initiated_renegotiation()); + } + +bool Text_Policy::allow_server_initiated_renegotiation() const + { + return get_bool("allow_server_initiated_renegotiation", Policy::allow_server_initiated_renegotiation()); + } + +bool Text_Policy::server_uses_own_ciphersuite_preferences() const + { + return get_bool("server_uses_own_ciphersuite_preferences", Policy::server_uses_own_ciphersuite_preferences()); + } + +bool Text_Policy::negotiate_encrypt_then_mac() const + { + return get_bool("negotiate_encrypt_then_mac", Policy::negotiate_encrypt_then_mac()); + } + +bool Text_Policy::support_cert_status_message() const + { + return get_bool("support_cert_status_message", Policy::support_cert_status_message()); + } + +std::vector Text_Policy::key_exchange_groups() const + { + std::string group_str = get_str("key_exchange_groups"); + + if(group_str.empty()) + { + // fall back to previously used name + group_str = get_str("groups"); + } + + if(group_str.empty()) + { + return Policy::key_exchange_groups(); + } + + std::vector groups; + for(std::string group_name : split_on(group_str, ' ')) + { + Group_Params group_id = group_param_from_string(group_name); + + if(group_id == Group_Params::NONE) + { + try + { + size_t consumed = 0; + unsigned long ll_id = std::stoul(group_name, &consumed, 0); + if(consumed != group_name.size()) + continue; // some other cruft + + const uint16_t id = static_cast(ll_id); + + if(id != ll_id) + continue; // integer too large + + group_id = static_cast(id); + } + catch(...) + { + continue; + } + } + + if(group_id != Group_Params::NONE) + groups.push_back(group_id); + } + + return groups; + } + +size_t Text_Policy::minimum_ecdh_group_size() const + { + return get_len("minimum_ecdh_group_size", Policy::minimum_ecdh_group_size()); + } + +size_t Text_Policy::minimum_ecdsa_group_size() const + { + return get_len("minimum_ecdsa_group_size", Policy::minimum_ecdsa_group_size()); + } + +size_t Text_Policy::minimum_dh_group_size() const + { + return get_len("minimum_dh_group_size", Policy::minimum_dh_group_size()); + } + +size_t Text_Policy::minimum_rsa_bits() const + { + return get_len("minimum_rsa_bits", Policy::minimum_rsa_bits()); + } + +size_t Text_Policy::minimum_signature_strength() const + { + return get_len("minimum_signature_strength", Policy::minimum_signature_strength()); + } + +size_t Text_Policy::dtls_default_mtu() const + { + return get_len("dtls_default_mtu", Policy::dtls_default_mtu()); + } + +size_t Text_Policy::dtls_initial_timeout() const + { + return get_len("dtls_initial_timeout", Policy::dtls_initial_timeout()); + } + +size_t Text_Policy::dtls_maximum_timeout() const + { + return get_len("dtls_maximum_timeout", Policy::dtls_maximum_timeout()); + } + +bool Text_Policy::require_cert_revocation_info() const + { + return get_bool("require_cert_revocation_info", Policy::require_cert_revocation_info()); + } + +bool Text_Policy::hide_unknown_users() const + { + return get_bool("hide_unknown_users", Policy::hide_unknown_users()); + } + +uint32_t Text_Policy::session_ticket_lifetime() const + { + return static_cast(get_len("session_ticket_lifetime", Policy::session_ticket_lifetime())); + } + +bool Text_Policy::send_fallback_scsv(Protocol_Version version) const + { + return get_bool("send_fallback_scsv", false) ? Policy::send_fallback_scsv(version) : false; + } + +std::vector Text_Policy::srtp_profiles() const + { + std::vector r; + for(std::string p : get_list("srtp_profiles", std::vector())) + { + r.push_back(to_uint16(p)); + } + return r; + } + +void Text_Policy::set(const std::string& k, const std::string& v) + { + m_kv[k] = v; + } + +Text_Policy::Text_Policy(const std::string& s) + { + std::istringstream iss(s); + m_kv = read_cfg(iss); + } + +Text_Policy::Text_Policy(std::istream& in) : m_kv(read_cfg(in)) + {} + +std::vector +Text_Policy::get_list(const std::string& key, + const std::vector& def) const + { + const std::string v = get_str(key); + + if(v.empty()) + { + return def; + } + + return split_on(v, ' '); + } + +size_t Text_Policy::get_len(const std::string& key, size_t def) const + { + const std::string v = get_str(key); + + if(v.empty()) + { + return def; + } + + return to_u32bit(v); + } + +bool Text_Policy::get_bool(const std::string& key, bool def) const + { + const std::string v = get_str(key); + + if(v.empty()) + { + return def; + } + + if(v == "true" || v == "True") + { + return true; + } + else if(v == "false" || v == "False") + { + return false; + } + else + { + throw Decoding_Error("Invalid boolean '" + v + "'"); + } + } + +std::string Text_Policy::get_str(const std::string& key, const std::string& def) const + { + auto i = m_kv.find(key); + if(i == m_kv.end()) + { + return def; + } + + return i->second; + } + +bool Text_Policy::set_value(const std::string& key, const std::string& val, bool overwrite) + { + auto i = m_kv.find(key); + + if(overwrite == false && i != m_kv.end()) + return false; + + m_kv.insert(i, std::make_pair(key, val)); + return true; + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_version.cpp b/comm/third_party/botan/src/lib/tls/tls_version.cpp new file mode 100644 index 0000000000..ecbe94897a --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_version.cpp @@ -0,0 +1,88 @@ +/* +* TLS Protocol Version Management +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +namespace TLS { + +std::string Protocol_Version::to_string() const + { + const uint8_t maj = major_version(); + const uint8_t min = minor_version(); + + if(maj == 3 && min == 0) + return "SSL v3"; + + if(maj == 3 && min >= 1) // TLS v1.x + return "TLS v1." + std::to_string(min-1); + + if(maj == 254) // DTLS 1.x + return "DTLS v1." + std::to_string(255 - min); + + // Some very new or very old protocol (or bogus data) + return "Unknown " + std::to_string(maj) + "." + std::to_string(min); + } + +bool Protocol_Version::is_datagram_protocol() const + { + return major_version() > 250; + } + +bool Protocol_Version::operator>(const Protocol_Version& other) const + { + if(this->is_datagram_protocol() != other.is_datagram_protocol()) + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Version comparing " + to_string() + + " with " + other.to_string()); + + if(this->is_datagram_protocol()) + return m_version < other.m_version; // goes backwards + + return m_version > other.m_version; + } + +bool Protocol_Version::known_version() const + { + return (m_version == Protocol_Version::TLS_V10 || + m_version == Protocol_Version::TLS_V11 || + m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V10 || + m_version == Protocol_Version::DTLS_V12); + } + +bool Protocol_Version::supports_negotiable_signature_algorithms() const + { + return (m_version != Protocol_Version::TLS_V10 && + m_version != Protocol_Version::TLS_V11 && + m_version != Protocol_Version::DTLS_V10); + } + +bool Protocol_Version::supports_explicit_cbc_ivs() const + { + return (m_version != Protocol_Version::TLS_V10); + } + +bool Protocol_Version::supports_ciphersuite_specific_prf() const + { + return (m_version != Protocol_Version::TLS_V10 && + m_version != Protocol_Version::TLS_V11 && + m_version != Protocol_Version::DTLS_V10); + } + +bool Protocol_Version::supports_aead_modes() const + { + return (m_version != Protocol_Version::TLS_V10 && + m_version != Protocol_Version::TLS_V11 && + m_version != Protocol_Version::DTLS_V10); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/tls/tls_version.h b/comm/third_party/botan/src/lib/tls/tls_version.h new file mode 100644 index 0000000000..18e2c0f65c --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_version.h @@ -0,0 +1,156 @@ +/* +* TLS Protocol Version Management +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_PROTOCOL_VERSION_H_ +#define BOTAN_TLS_PROTOCOL_VERSION_H_ + +#include +#include + +namespace Botan { + +namespace TLS { + +/** +* TLS Protocol Version +*/ +class BOTAN_PUBLIC_API(2,0) Protocol_Version final + { + public: + enum Version_Code { + TLS_V10 = 0x0301, + TLS_V11 = 0x0302, + TLS_V12 = 0x0303, + + DTLS_V10 = 0xFEFF, + DTLS_V12 = 0xFEFD + }; + + /** + * @return latest known TLS version + */ + static Protocol_Version latest_tls_version() + { + return Protocol_Version(TLS_V12); + } + + /** + * @return latest known DTLS version + */ + static Protocol_Version latest_dtls_version() + { + return Protocol_Version(DTLS_V12); + } + + Protocol_Version() : m_version(0) {} + + explicit Protocol_Version(uint16_t code) : m_version(code) {} + + /** + * @param named_version a specific named version of the protocol + */ + Protocol_Version(Version_Code named_version) : + Protocol_Version(static_cast(named_version)) {} + + /** + * @param major the major version + * @param minor the minor version + */ + Protocol_Version(uint8_t major, uint8_t minor) : + Protocol_Version(static_cast((static_cast(major) << 8) | minor)) {} + + /** + * @return true if this is a valid protocol version + */ + bool valid() const { return (m_version != 0); } + + /** + * @return true if this is a protocol version we know about + */ + bool known_version() const; + + /** + * @return major version of the protocol version + */ + uint8_t major_version() const { return static_cast(m_version >> 8); } + + /** + * @return minor version of the protocol version + */ + uint8_t minor_version() const { return static_cast(m_version & 0xFF); } + + /** + * @return the version code + */ + uint16_t version_code() const { return m_version; } + + /** + * @return human-readable description of this version + */ + std::string to_string() const; + + /** + * @return true iff this is a DTLS version + */ + bool is_datagram_protocol() const; + + /** + * @return true if this version supports negotiable signature algorithms + */ + bool supports_negotiable_signature_algorithms() const; + + /** + * @return true if this version uses explicit IVs for block ciphers + */ + bool supports_explicit_cbc_ivs() const; + + /** + * @return true if this version uses a ciphersuite specific PRF + */ + bool supports_ciphersuite_specific_prf() const; + + bool supports_aead_modes() const; + + /** + * @return if this version is equal to other + */ + bool operator==(const Protocol_Version& other) const + { + return (m_version == other.m_version); + } + + /** + * @return if this version is not equal to other + */ + bool operator!=(const Protocol_Version& other) const + { + return (m_version != other.m_version); + } + + /** + * @return if this version is later than other + */ + bool operator>(const Protocol_Version& other) const; + + /** + * @return if this version is later than or equal to other + */ + bool operator>=(const Protocol_Version& other) const + { + return (*this == other || *this > other); + } + + private: + uint16_t m_version; + }; + +} + +} + +#endif + diff --git a/comm/third_party/botan/src/lib/utils/assert.cpp b/comm/third_party/botan/src/lib/utils/assert.cpp new file mode 100644 index 0000000000..b251a469e9 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/assert.cpp @@ -0,0 +1,54 @@ +/* +* Runtime assertion checking +* (C) 2010,2012,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +void throw_invalid_argument(const char* message, + const char* func, + const char* file) + { + std::ostringstream format; + format << message << " in " << func << ":" << file; + throw Invalid_Argument(format.str()); + } + +void throw_invalid_state(const char* expr, + const char* func, + const char* file) + { + std::ostringstream format; + format << "Invalid state: " << expr << " was false in " << func << ":" << file; + throw Invalid_State(format.str()); + } + +void assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line) + { + std::ostringstream format; + + format << "False assertion "; + + if(assertion_made && assertion_made[0] != 0) + format << "'" << assertion_made << "' (expression " << expr_str << ") "; + else + format << expr_str << " "; + + if(func) + format << "in " << func << " "; + + format << "@" << file << ":" << line; + + throw Internal_Error(format.str()); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/assert.h b/comm/third_party/botan/src/lib/utils/assert.h new file mode 100644 index 0000000000..14cc442609 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/assert.h @@ -0,0 +1,157 @@ +/* +* Runtime assertion checking +* (C) 2010,2018 Jack Lloyd +* 2017 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASSERTION_CHECKING_H_ +#define BOTAN_ASSERTION_CHECKING_H_ + +#include +#include + +namespace Botan { + +/** +* Called when an assertion fails +* Throws an Exception object +*/ +BOTAN_NORETURN void BOTAN_PUBLIC_API(2,0) + assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line); + +/** +* Called when an invalid argument is used +* Throws Invalid_Argument +*/ +BOTAN_NORETURN void BOTAN_UNSTABLE_API throw_invalid_argument(const char* message, + const char* func, + const char* file); + + +#define BOTAN_ARG_CHECK(expr, msg) \ + do { if(!(expr)) Botan::throw_invalid_argument(msg, __func__, __FILE__); } while(0) + +/** +* Called when an invalid state is encountered +* Throws Invalid_State +*/ +BOTAN_NORETURN void BOTAN_UNSTABLE_API throw_invalid_state(const char* message, + const char* func, + const char* file); + + +#define BOTAN_STATE_CHECK(expr) \ + do { if(!(expr)) Botan::throw_invalid_state(#expr, __func__, __FILE__); } while(0) + +/** +* Make an assertion +*/ +#define BOTAN_ASSERT(expr, assertion_made) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + assertion_made, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Make an assertion +*/ +#define BOTAN_ASSERT_NOMSG(expr) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + "", \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that value1 == value2 +*/ +#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made) \ + do { \ + if((expr1) != (expr2)) \ + Botan::assertion_failure(#expr1 " == " #expr2, \ + assertion_made, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that expr1 (if true) implies expr2 is also true +*/ +#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg) \ + do { \ + if((expr1) && !(expr2)) \ + Botan::assertion_failure(#expr1 " implies " #expr2, \ + msg, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that a pointer is not null +*/ +#define BOTAN_ASSERT_NONNULL(ptr) \ + do { \ + if((ptr) == nullptr) \ + Botan::assertion_failure(#ptr " is not null", \ + "", \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +#if defined(BOTAN_ENABLE_DEBUG_ASSERTS) + +#define BOTAN_DEBUG_ASSERT(expr) BOTAN_ASSERT_NOMSG(expr) + +#else + +#define BOTAN_DEBUG_ASSERT(expr) do {} while(0) + +#endif + +/** +* Mark variable as unused. Takes between 1 and 9 arguments and marks all as unused, +* e.g. BOTAN_UNUSED(a); or BOTAN_UNUSED(x, y, z); +*/ +#define _BOTAN_UNUSED_IMPL1(a) static_cast(a) +#define _BOTAN_UNUSED_IMPL2(a, b) static_cast(a); _BOTAN_UNUSED_IMPL1(b) +#define _BOTAN_UNUSED_IMPL3(a, b, c) static_cast(a); _BOTAN_UNUSED_IMPL2(b, c) +#define _BOTAN_UNUSED_IMPL4(a, b, c, d) static_cast(a); _BOTAN_UNUSED_IMPL3(b, c, d) +#define _BOTAN_UNUSED_IMPL5(a, b, c, d, e) static_cast(a); _BOTAN_UNUSED_IMPL4(b, c, d, e) +#define _BOTAN_UNUSED_IMPL6(a, b, c, d, e, f) static_cast(a); _BOTAN_UNUSED_IMPL5(b, c, d, e, f) +#define _BOTAN_UNUSED_IMPL7(a, b, c, d, e, f, g) static_cast(a); _BOTAN_UNUSED_IMPL6(b, c, d, e, f, g) +#define _BOTAN_UNUSED_IMPL8(a, b, c, d, e, f, g, h) static_cast(a); _BOTAN_UNUSED_IMPL7(b, c, d, e, f, g, h) +#define _BOTAN_UNUSED_IMPL9(a, b, c, d, e, f, g, h, i) static_cast(a); _BOTAN_UNUSED_IMPL8(b, c, d, e, f, g, h, i) +#define _BOTAN_UNUSED_GET_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, IMPL_NAME, ...) IMPL_NAME + +#define BOTAN_UNUSED(...) _BOTAN_UNUSED_GET_IMPL(__VA_ARGS__, \ + _BOTAN_UNUSED_IMPL9, \ + _BOTAN_UNUSED_IMPL8, \ + _BOTAN_UNUSED_IMPL7, \ + _BOTAN_UNUSED_IMPL6, \ + _BOTAN_UNUSED_IMPL5, \ + _BOTAN_UNUSED_IMPL4, \ + _BOTAN_UNUSED_IMPL3, \ + _BOTAN_UNUSED_IMPL2, \ + _BOTAN_UNUSED_IMPL1, \ + unused dummy rest value \ + ) /* we got an one of _BOTAN_UNUSED_IMPL*, now call it */ (__VA_ARGS__) + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/bit_ops.h b/comm/third_party/botan/src/lib/utils/bit_ops.h new file mode 100644 index 0000000000..79d86f0f76 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/bit_ops.h @@ -0,0 +1,171 @@ +/* +* Bit/Word Operations +* (C) 1999-2008 Jack Lloyd +* (C) Copyright Projet SECRET, INRIA, Rocquencourt +* (C) Bhaskar Biswas and Nicolas Sendrier +* (C) 2014 cryptosource GmbH +* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BIT_OPS_H_ +#define BOTAN_BIT_OPS_H_ + +#include + +namespace Botan { + +/** +* If top bit of arg is set, return ~0. Otherwise return 0. +*/ +template +inline T expand_top_bit(T a) + { + return static_cast(0) - (a >> (sizeof(T)*8-1)); + } + +/** +* If arg is zero, return ~0. Otherwise return 0 +*/ +template +inline T ct_is_zero(T x) + { + return expand_top_bit(~x & (x - 1)); + } + +/** +* Power of 2 test. T should be an unsigned integer type +* @param arg an integer value +* @return true iff arg is 2^n for some n > 0 +*/ +template +inline constexpr bool is_power_of_2(T arg) + { + return (arg != 0) && (arg != 1) && ((arg & static_cast(arg-1)) == 0); + } + +/** +* Return the index of the highest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the highest set bit in n +*/ +template +inline size_t high_bit(T n) + { + size_t hb = 0; + + for(size_t s = 8*sizeof(T) / 2; s > 0; s /= 2) + { + const size_t z = s * ((~ct_is_zero(n >> s)) & 1); + hb += z; + n >>= z; + } + + hb += n; + + return hb; + } + +/** +* Return the number of significant bytes in n +* @param n an integer value +* @return number of significant bytes in n +*/ +template +inline size_t significant_bytes(T n) + { + size_t b = 0; + + for(size_t s = 8*sizeof(n) / 2; s >= 8; s /= 2) + { + const size_t z = s * (~ct_is_zero(n >> s) & 1); + b += z/8; + n >>= z; + } + + b += (n != 0); + + return b; + } + +/** +* Count the trailing zero bits in n +* @param n an integer value +* @return maximum x st 2^x divides n +*/ +template +inline size_t ctz(T n) + { + /* + * If n == 0 then this function will compute 8*sizeof(T)-1, so + * initialize lb to 1 if n == 0 to produce the expected result. + */ + size_t lb = ct_is_zero(n) & 1; + + for(size_t s = 8*sizeof(T) / 2; s > 0; s /= 2) + { + const T mask = (static_cast(1) << s) - 1; + const size_t z = s * (ct_is_zero(n & mask) & 1); + lb += z; + n >>= z; + } + + return lb; + } + +template +uint8_t ceil_log2(T x) + { + static_assert(sizeof(T) < 32, "Abnormally large scalar"); + + if(x >> (sizeof(T)*8-1)) + return sizeof(T)*8; + + uint8_t result = 0; + T compare = 1; + + while(compare < x) + { + compare <<= 1; + result++; + } + + return result; + } + +// Potentially variable time ctz used for OCB +inline size_t var_ctz32(uint32_t n) + { +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + if(n == 0) + return 32; + return __builtin_ctz(n); +#else + return ctz(n); +#endif + } + +template +inline T bit_permute_step(T x, T mask, size_t shift) + { + /* + See https://reflectionsonsecurity.wordpress.com/2014/05/11/efficient-bit-permutation-using-delta-swaps/ + and http://programming.sirrida.de/bit_perm.html + */ + const T swap = ((x >> shift) ^ x) & mask; + return (x ^ swap) ^ (swap << shift); + } + +template +inline void swap_bits(T& x, T& y, T mask, size_t shift) + { + const T swap = ((x >> shift) ^ y) & mask; + x ^= swap << shift; + y ^= swap; + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/boost/info.txt b/comm/third_party/botan/src/lib/utils/boost/info.txt new file mode 100644 index 0000000000..6330cbafdb --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/boost/info.txt @@ -0,0 +1,9 @@ + +BOOST_ASIO -> 20131228 + + +load_on vendor + + +all -> boost_system + diff --git a/comm/third_party/botan/src/lib/utils/bswap.h b/comm/third_party/botan/src/lib/utils/bswap.h new file mode 100644 index 0000000000..584fa33234 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/bswap.h @@ -0,0 +1,108 @@ +/* +* Byte Swapping Operations +* (C) 1999-2011,2018 Jack Lloyd +* (C) 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BYTE_SWAP_H_ +#define BOTAN_BYTE_SWAP_H_ + +#include + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include +#endif + +BOTAN_FUTURE_INTERNAL_HEADER(bswap.h) + +namespace Botan { + +/** +* Swap a 16 bit integer +*/ +inline uint16_t reverse_bytes(uint16_t val) + { +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) || defined(BOTAN_BUILD_COMPILER_IS_XLC) + return __builtin_bswap16(val); +#else + return static_cast((val << 8) | (val >> 8)); +#endif + } + +/** +* Swap a 32 bit integer +*/ +inline uint32_t reverse_bytes(uint32_t val) + { +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) || defined(BOTAN_BUILD_COMPILER_IS_XLC) + return __builtin_bswap32(val); + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) + return _byteswap_ulong(val); + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + // GCC-style inline assembly for x86 or x86-64 + asm("bswapl %0" : "=r" (val) : "0" (val)); + return val; + +#else + // Generic implementation + uint16_t hi = static_cast(val >> 16); + uint16_t lo = static_cast(val); + + hi = reverse_bytes(hi); + lo = reverse_bytes(lo); + + return (static_cast(lo) << 16) | hi; +#endif + } + +/** +* Swap a 64 bit integer +*/ +inline uint64_t reverse_bytes(uint64_t val) + { +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) || defined(BOTAN_BUILD_COMPILER_IS_XLC) + return __builtin_bswap64(val); + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) + return _byteswap_uint64(val); + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_X86_64) + // GCC-style inline assembly for x86-64 + asm("bswapq %0" : "=r" (val) : "0" (val)); + return val; + +#else + /* Generic implementation. Defined in terms of 32-bit bswap so any + * optimizations in that version can help. + */ + + uint32_t hi = static_cast(val >> 32); + uint32_t lo = static_cast(val); + + hi = reverse_bytes(hi); + lo = reverse_bytes(lo); + + return (static_cast(lo) << 32) | hi; +#endif + } + +/** +* Swap 4 Ts in an array +*/ +template +inline void bswap_4(T x[4]) + { + x[0] = reverse_bytes(x[0]); + x[1] = reverse_bytes(x[1]); + x[2] = reverse_bytes(x[2]); + x[3] = reverse_bytes(x[3]); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/calendar.cpp b/comm/third_party/botan/src/lib/utils/calendar.cpp new file mode 100644 index 0000000000..1c34a71572 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/calendar.cpp @@ -0,0 +1,124 @@ +/* +* Calendar Functions +* (C) 1999-2010,2017 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +std::tm do_gmtime(std::time_t time_val) + { + std::tm tm; + +#if defined(BOTAN_TARGET_OS_HAS_WIN32) + ::gmtime_s(&tm, &time_val); // Windows +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + ::gmtime_r(&time_val, &tm); // Unix/SUSv2 +#else + std::tm* tm_p = std::gmtime(&time_val); + if (tm_p == nullptr) + throw Encoding_Error("time_t_to_tm could not convert"); + tm = *tm_p; +#endif + + return tm; + } + +/* +Portable replacement for timegm, _mkgmtime, etc + +Algorithm due to Howard Hinnant + +See https://howardhinnant.github.io/date_algorithms.html#days_from_civil +for details and explaination. The code is slightly simplified by our assumption +that the date is at least 1970, which is sufficient for our purposes. +*/ +size_t days_since_epoch(uint32_t year, uint32_t month, uint32_t day) + { + if(month <= 2) + year -= 1; + const uint32_t era = year / 400; + const uint32_t yoe = year - era * 400; // [0, 399] + const uint32_t doy = (153*(month + (month > 2 ? -3 : 9)) + 2)/5 + day-1; // [0, 365] + const uint32_t doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] + return era * 146097 + doe - 719468; + } + +} + +std::chrono::system_clock::time_point calendar_point::to_std_timepoint() const + { + if(get_year() < 1970) + throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years before 1970"); + + // 32 bit time_t ends at January 19, 2038 + // https://msdn.microsoft.com/en-us/library/2093ets1.aspx + // Throw after 2037 if 32 bit time_t is used + + BOTAN_IF_CONSTEXPR(sizeof(std::time_t) == 4) + { + if(get_year() > 2037) + { + throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2037 on this system"); + } + } + + // This upper bound is completely arbitrary + if(get_year() >= 2400) + { + throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2400"); + } + + const uint64_t seconds_64 = (days_since_epoch(get_year(), get_month(), get_day()) * 86400) + + (get_hour() * 60 * 60) + (get_minutes() * 60) + get_seconds(); + + const time_t seconds_time_t = static_cast(seconds_64); + + if(seconds_64 - seconds_time_t != 0) + { + throw Invalid_Argument("calendar_point::to_std_timepoint time_t overflow"); + } + + return std::chrono::system_clock::from_time_t(seconds_time_t); + } + +std::string calendar_point::to_string() const + { + // desired format: --
T:: + std::stringstream output; + output << std::setfill('0') + << std::setw(4) << get_year() << "-" + << std::setw(2) << get_month() << "-" + << std::setw(2) << get_day() << "T" + << std::setw(2) << get_hour() << ":" + << std::setw(2) << get_minutes() << ":" + << std::setw(2) << get_seconds(); + return output.str(); + } + + +calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point) + { + std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point)); + + return calendar_point(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/calendar.h b/comm/third_party/botan/src/lib/utils/calendar.h new file mode 100644 index 0000000000..83759070b8 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/calendar.h @@ -0,0 +1,91 @@ +/* +* Calendar Functions +* (C) 1999-2009,2015 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CALENDAR_H_ +#define BOTAN_CALENDAR_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Struct representing a particular date and time +*/ +class BOTAN_PUBLIC_API(2,0) calendar_point + { + public: + + /** The year */ + uint32_t get_year() const { return year; } + + /** The month, 1 through 12 for Jan to Dec */ + uint32_t get_month() const { return month; } + + /** The day of the month, 1 through 31 (or 28 or 30 based on month */ + uint32_t get_day() const { return day; } + + /** Hour in 24-hour form, 0 to 23 */ + uint32_t get_hour() const { return hour; } + + /** Minutes in the hour, 0 to 60 */ + uint32_t get_minutes() const { return minutes; } + + /** Seconds in the minute, 0 to 60, but might be slightly + larger to deal with leap seconds on some systems + */ + uint32_t get_seconds() const { return seconds; } + + /** + * Initialize a calendar_point + * @param y the year + * @param mon the month + * @param d the day + * @param h the hour + * @param min the minute + * @param sec the second + */ + calendar_point(uint32_t y, uint32_t mon, uint32_t d, uint32_t h, uint32_t min, uint32_t sec) : + year(y), month(mon), day(d), hour(h), minutes(min), seconds(sec) {} + + /** + * Returns an STL timepoint object + */ + std::chrono::system_clock::time_point to_std_timepoint() const; + + /** + * Returns a human readable string of the struct's components. + * Formatting might change over time. Currently it is RFC339 'iso-date-time'. + */ + std::string to_string() const; + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + The member variables are public for historical reasons. Use the get_xxx() functions + defined above. These members will be made private in a future major release. + */ + uint32_t year; + uint32_t month; + uint32_t day; + uint32_t hour; + uint32_t minutes; + uint32_t seconds; + }; + +/** +* Convert a time_point to a calendar_point +* @param time_point a time point from the system clock +* @return calendar_point object representing this time point +*/ +BOTAN_PUBLIC_API(2,0) calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/charset.cpp b/comm/third_party/botan/src/lib/utils/charset.cpp new file mode 100644 index 0000000000..ca32c652db --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/charset.cpp @@ -0,0 +1,283 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +namespace { + +void append_utf8_for(std::string& s, uint32_t c) + { + if(c >= 0xD800 && c < 0xE000) + throw Decoding_Error("Invalid Unicode character"); + + if(c <= 0x7F) + { + const uint8_t b0 = static_cast(c); + s.push_back(static_cast(b0)); + } + else if(c <= 0x7FF) + { + const uint8_t b0 = 0xC0 | static_cast(c >> 6); + const uint8_t b1 = 0x80 | static_cast(c & 0x3F); + s.push_back(static_cast(b0)); + s.push_back(static_cast(b1)); + } + else if(c <= 0xFFFF) + { + const uint8_t b0 = 0xE0 | static_cast(c >> 12); + const uint8_t b1 = 0x80 | static_cast((c >> 6) & 0x3F); + const uint8_t b2 = 0x80 | static_cast(c & 0x3F); + s.push_back(static_cast(b0)); + s.push_back(static_cast(b1)); + s.push_back(static_cast(b2)); + } + else if(c <= 0x10FFFF) + { + const uint8_t b0 = 0xF0 | static_cast(c >> 18); + const uint8_t b1 = 0x80 | static_cast((c >> 12) & 0x3F); + const uint8_t b2 = 0x80 | static_cast((c >> 6) & 0x3F); + const uint8_t b3 = 0x80 | static_cast(c & 0x3F); + s.push_back(static_cast(b0)); + s.push_back(static_cast(b1)); + s.push_back(static_cast(b2)); + s.push_back(static_cast(b3)); + } + else + throw Decoding_Error("Invalid Unicode character"); + + } + +} + +std::string ucs2_to_utf8(const uint8_t ucs2[], size_t len) + { + if(len % 2 != 0) + throw Decoding_Error("Invalid length for UCS-2 string"); + + const size_t chars = len / 2; + + std::string s; + for(size_t i = 0; i != chars; ++i) + { + const uint16_t c = load_be(ucs2, i); + append_utf8_for(s, c); + } + + return s; + } + +std::string ucs4_to_utf8(const uint8_t ucs4[], size_t len) + { + if(len % 4 != 0) + throw Decoding_Error("Invalid length for UCS-4 string"); + + const size_t chars = len / 4; + + std::string s; + for(size_t i = 0; i != chars; ++i) + { + const uint32_t c = load_be(ucs4, i); + append_utf8_for(s, c); + } + + return s; + } + +/* +* Convert from UTF-8 to ISO 8859-1 +*/ +std::string utf8_to_latin1(const std::string& utf8) + { + std::string iso8859; + + size_t position = 0; + while(position != utf8.size()) + { + const uint8_t c1 = static_cast(utf8[position++]); + + if(c1 <= 0x7F) + { + iso8859 += static_cast(c1); + } + else if(c1 >= 0xC0 && c1 <= 0xC7) + { + if(position == utf8.size()) + throw Decoding_Error("UTF-8: sequence truncated"); + + const uint8_t c2 = static_cast(utf8[position++]); + const uint8_t iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F); + + if(iso_char <= 0x7F) + throw Decoding_Error("UTF-8: sequence longer than needed"); + + iso8859 += static_cast(iso_char); + } + else + throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used"); + } + + return iso8859; + } + +namespace Charset { + +namespace { + +/* +* Convert from UCS-2 to ISO 8859-1 +*/ +std::string ucs2_to_latin1(const std::string& ucs2) + { + if(ucs2.size() % 2 == 1) + throw Decoding_Error("UCS-2 string has an odd number of bytes"); + + std::string latin1; + + for(size_t i = 0; i != ucs2.size(); i += 2) + { + const uint8_t c1 = ucs2[i]; + const uint8_t c2 = ucs2[i+1]; + + if(c1 != 0) + throw Decoding_Error("UCS-2 has non-Latin1 characters"); + + latin1 += static_cast(c2); + } + + return latin1; + } + +/* +* Convert from ISO 8859-1 to UTF-8 +*/ +std::string latin1_to_utf8(const std::string& iso8859) + { + std::string utf8; + for(size_t i = 0; i != iso8859.size(); ++i) + { + const uint8_t c = static_cast(iso8859[i]); + + if(c <= 0x7F) + utf8 += static_cast(c); + else + { + utf8 += static_cast((0xC0 | (c >> 6))); + utf8 += static_cast((0x80 | (c & 0x3F))); + } + } + return utf8; + } + +} + +/* +* Perform character set transcoding +*/ +std::string transcode(const std::string& str, + Character_Set to, Character_Set from) + { + if(to == LOCAL_CHARSET) + to = LATIN1_CHARSET; + if(from == LOCAL_CHARSET) + from = LATIN1_CHARSET; + + if(to == from) + return str; + + if(from == LATIN1_CHARSET && to == UTF8_CHARSET) + return latin1_to_utf8(str); + if(from == UTF8_CHARSET && to == LATIN1_CHARSET) + return utf8_to_latin1(str); + if(from == UCS2_CHARSET && to == LATIN1_CHARSET) + return ucs2_to_latin1(str); + + throw Invalid_Argument("Unknown transcoding operation from " + + std::to_string(from) + " to " + std::to_string(to)); + } + +/* +* Check if a character represents a digit +*/ +bool is_digit(char c) + { + if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9') + return true; + return false; + } + +/* +* Check if a character represents whitespace +*/ +bool is_space(char c) + { + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + return true; + return false; + } + +/* +* Convert a character to a digit +*/ +uint8_t char2digit(char c) + { + switch(c) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + + throw Invalid_Argument("char2digit: Input is not a digit character"); + } + +/* +* Convert a digit to a character +*/ +char digit2char(uint8_t b) + { + switch(b) + { + case 0: return '0'; + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + case 8: return '8'; + case 9: return '9'; + } + + throw Invalid_Argument("digit2char: Input is not a digit"); + } + +/* +* Case-insensitive character comparison +*/ +bool caseless_cmp(char a, char b) + { + return (std::tolower(static_cast(a)) == + std::tolower(static_cast(b))); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/utils/charset.h b/comm/third_party/botan/src/lib/utils/charset.h new file mode 100644 index 0000000000..6e7ce30c91 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/charset.h @@ -0,0 +1,80 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CHARSET_H_ +#define BOTAN_CHARSET_H_ + +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(charset.h) + +namespace Botan { + +/** +* Convert a sequence of UCS-2 (big endian) characters to a UTF-8 string +* This is used for ASN.1 BMPString type +* @param ucs2 the sequence of UCS-2 characters +* @param len length of ucs2 in bytes, must be a multiple of 2 +*/ +std::string BOTAN_UNSTABLE_API ucs2_to_utf8(const uint8_t ucs2[], size_t len); + +/** +* Convert a sequence of UCS-4 (big endian) characters to a UTF-8 string +* This is used for ASN.1 UniversalString type +* @param ucs4 the sequence of UCS-4 characters +* @param len length of ucs4 in bytes, must be a multiple of 4 +*/ +std::string BOTAN_UNSTABLE_API ucs4_to_utf8(const uint8_t ucs4[], size_t len); + +/** +* Convert a UTF-8 string to Latin-1 +* If a character outside the Latin-1 range is encountered, an exception is thrown. +*/ +std::string BOTAN_UNSTABLE_API utf8_to_latin1(const std::string& utf8); + +/** +* The different charsets (nominally) supported by Botan. +*/ +enum Character_Set { + LOCAL_CHARSET, + UCS2_CHARSET, + UTF8_CHARSET, + LATIN1_CHARSET +}; + +namespace Charset { + +/* +* Character set conversion - avoid this. +* For specific conversions, use the functions above like +* ucs2_to_utf8 and utf8_to_latin1 +* +* If you need something more complex than that, use a real library +* such as iconv, Boost.Locale, or ICU +*/ +std::string BOTAN_PUBLIC_API(2,0) + BOTAN_DEPRECATED("Avoid. See comment in header.") + transcode(const std::string& str, + Character_Set to, + Character_Set from); + +/* +* Simple character classifier functions +*/ +bool BOTAN_PUBLIC_API(2,0) is_digit(char c); +bool BOTAN_PUBLIC_API(2,0) is_space(char c); +bool BOTAN_PUBLIC_API(2,0) caseless_cmp(char x, char y); + +uint8_t BOTAN_PUBLIC_API(2,0) char2digit(char c); +char BOTAN_PUBLIC_API(2,0) digit2char(uint8_t b); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/codec_base.h b/comm/third_party/botan/src/lib/utils/codec_base.h new file mode 100644 index 0000000000..2338fdfd7e --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/codec_base.h @@ -0,0 +1,220 @@ +/* +* Base Encoding and Decoding +* (C) 2018 Erwan Chaussy +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE_CODEC_H_ +#define BOTAN_BASE_CODEC_H_ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Perform encoding using the base provided +* @param base object giving access to the encodings specifications +* @param output an array of at least base.encode_max_output bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +template +size_t base_encode(Base&& base, + char output[], + const uint8_t input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + input_consumed = 0; + + const size_t encoding_bytes_in = base.encoding_bytes_in(); + const size_t encoding_bytes_out = base.encoding_bytes_out(); + + size_t input_remaining = input_length; + size_t output_produced = 0; + + while(input_remaining >= encoding_bytes_in) + { + base.encode(output + output_produced, input + input_consumed); + + input_consumed += encoding_bytes_in; + output_produced += encoding_bytes_out; + input_remaining -= encoding_bytes_in; + } + + if(final_inputs && input_remaining) + { + std::vector remainder(encoding_bytes_in, 0); + for(size_t i = 0; i != input_remaining; ++i) + { remainder[i] = input[input_consumed + i]; } + + base.encode(output + output_produced, remainder.data()); + + const size_t bits_consumed = base.bits_consumed(); + const size_t remaining_bits_before_padding = base.remaining_bits_before_padding(); + + size_t empty_bits = 8 * (encoding_bytes_in - input_remaining); + size_t index = output_produced + encoding_bytes_out - 1; + while(empty_bits >= remaining_bits_before_padding) + { + output[index--] = '='; + empty_bits -= bits_consumed; + } + + input_consumed += input_remaining; + output_produced += encoding_bytes_out; + } + + return output_produced; + } + + +template +std::string base_encode_to_string(Base&& base, const uint8_t input[], size_t input_length) + { + const size_t output_length = base.encode_max_output(input_length); + std::string output(output_length, 0); + + size_t consumed = 0; + size_t produced = 0; + + if(output_length > 0) + { + produced = base_encode(base, &output.front(), + input, input_length, + consumed, true); + } + + BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); + BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); + + return output; + } + +/** +* Perform decoding using the base provided +* @param base object giving access to the encodings specifications +* @param output an array of at least Base::decode_max_output bytes +* @param input some base input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +template +size_t base_decode(Base&& base, + uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true) + { + const size_t decoding_bytes_in = base.decoding_bytes_in(); + const size_t decoding_bytes_out = base.decoding_bytes_out(); + + uint8_t* out_ptr = output; + std::vector decode_buf(decoding_bytes_in, 0); + size_t decode_buf_pos = 0; + size_t final_truncate = 0; + + clear_mem(output, base.decode_max_output(input_length)); + + for(size_t i = 0; i != input_length; ++i) + { + const uint8_t bin = base.lookup_binary_value(input[i]); + + if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument + { + decode_buf[decode_buf_pos] = bin; + ++decode_buf_pos; + } + + /* + * If we're at the end of the input, pad with 0s and truncate + */ + if(final_inputs && (i == input_length - 1)) + { + if(decode_buf_pos) + { + for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j) + { decode_buf[j] = 0; } + + final_truncate = decoding_bytes_in - decode_buf_pos; + decode_buf_pos = decoding_bytes_in; + } + } + + if(decode_buf_pos == decoding_bytes_in) + { + base.decode(out_ptr, decode_buf.data()); + + out_ptr += decoding_bytes_out; + decode_buf_pos = 0; + input_consumed = i+1; + } + } + + while(input_consumed < input_length && + base.lookup_binary_value(input[input_consumed]) == 0x80) + { + ++input_consumed; + } + + size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate); + + return written; + } + +template +size_t base_decode_full(Base&& base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws) + { + size_t consumed = 0; + const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws); + + if(consumed != input_length) + { + throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes"); + } + + return written; + } + +template +Vector base_decode_to_vec(Base&& base, + const char input[], + size_t input_length, + bool ignore_ws) + { + const size_t output_length = base.decode_max_output(input_length); + Vector bin(output_length); + + const size_t written = + base_decode_full(base, bin.data(), input, input_length, ignore_ws); + + bin.resize(written); + return bin; + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/compiler.h b/comm/third_party/botan/src/lib/utils/compiler.h new file mode 100644 index 0000000000..832ab8f22c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/compiler.h @@ -0,0 +1,225 @@ +/* +* Define useful compiler-specific macros +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +/* This header is included in both C++ and C (via ffi.h) and should only + contain macro definitions. Avoid C++ style // comments in this file. +*/ + +#ifndef BOTAN_UTIL_COMPILER_FLAGS_H_ +#define BOTAN_UTIL_COMPILER_FLAGS_H_ + +/* Should we use GCC-style inline assembler? */ +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || \ + defined(BOTAN_BUILD_COMPILER_IS_CLANG) || \ + defined(BOTAN_BUILD_COMPILER_IS_XLC) || \ + defined(BOTAN_BUILD_COMPILER_IS_SUN_STUDIO) + + #define BOTAN_USE_GCC_INLINE_ASM +#endif + +/** +* Used to annotate API exports which are public and supported. +* These APIs will not be broken/removed unless strictly required for +* functionality or security, and only in new major versions. +* @param maj The major version this public API was released in +* @param min The minor version this public API was released in +*/ +#define BOTAN_PUBLIC_API(maj,min) BOTAN_DLL + +/** +* Used to annotate API exports which are public, but are now deprecated +* and which will be removed in a future major release. +*/ +#define BOTAN_DEPRECATED_API(msg) BOTAN_DLL BOTAN_DEPRECATED(msg) + +/** +* Used to annotate API exports which are public and can be used by +* applications if needed, but which are intentionally not documented, +* and which may change incompatibly in a future major version. +*/ +#define BOTAN_UNSTABLE_API BOTAN_DLL + +/** +* Used to annotate API exports which are exported but only for the +* purposes of testing. They should not be used by applications and +* may be removed or changed without notice. +*/ +#define BOTAN_TEST_API BOTAN_DLL + +/* +* Define BOTAN_GCC_VERSION +*/ +#if defined(__GNUC__) && !defined(__clang__) + #define BOTAN_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__) +#else + #define BOTAN_GCC_VERSION 0 +#endif + +/* +* Define BOTAN_CLANG_VERSION +*/ +#if defined(__clang__) + #define BOTAN_CLANG_VERSION (__clang_major__ * 10 + __clang_minor__) +#else + #define BOTAN_CLANG_VERSION 0 +#endif + +/* +* Define BOTAN_FUNC_ISA +*/ +#if (defined(__GNUC__) && !defined(__clang__)) || (BOTAN_CLANG_VERSION > 38) + #define BOTAN_FUNC_ISA(isa) __attribute__ ((target(isa))) +#else + #define BOTAN_FUNC_ISA(isa) +#endif + +/* +* Define BOTAN_WARN_UNUSED_RESULT +*/ +#if defined(__GNUC__) || defined(__clang__) + #define BOTAN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else + #define BOTAN_WARN_UNUSED_RESULT +#endif + +/* +* Define BOTAN_MALLOC_FN +*/ +#if defined(__ibmxl__) + /* XLC pretends to be both Clang and GCC, but is neither */ + #define BOTAN_MALLOC_FN __attribute__ ((malloc)) +#elif defined(__GNUC__) + #define BOTAN_MALLOC_FN __attribute__ ((malloc, alloc_size(1,2))) +#elif defined(_MSC_VER) + #define BOTAN_MALLOC_FN __declspec(restrict) +#else + #define BOTAN_MALLOC_FN +#endif + +/* +* Define BOTAN_DEPRECATED +*/ +#if !defined(BOTAN_NO_DEPRECATED_WARNINGS) && !defined(BOTAN_IS_BEING_BUILT) && !defined(BOTAN_AMALGAMATION_H_) + + #if defined(__clang__) + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated(msg))) + #define BOTAN_DEPRECATED_HEADER(hdr) _Pragma("message \"this header is deprecated\"") + #define BOTAN_FUTURE_INTERNAL_HEADER(hdr) _Pragma("message \"this header will be made internal in the future\"") + + #elif defined(_MSC_VER) + #define BOTAN_DEPRECATED(msg) __declspec(deprecated(msg)) + #define BOTAN_DEPRECATED_HEADER(hdr) __pragma(message("this header is deprecated")) + #define BOTAN_FUTURE_INTERNAL_HEADER(hdr) __pragma(message("this header will be made internal in the future")) + + #elif defined(__GNUC__) + /* msg supported since GCC 4.5, earliest we support is 4.8 */ + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated(msg))) + #define BOTAN_DEPRECATED_HEADER(hdr) _Pragma("GCC warning \"this header is deprecated\"") + #define BOTAN_FUTURE_INTERNAL_HEADER(hdr) _Pragma("GCC warning \"this header will be made internal in the future\"") + #endif + +#endif + +#if !defined(BOTAN_DEPRECATED) + #define BOTAN_DEPRECATED(msg) +#endif + +#if !defined(BOTAN_DEPRECATED_HEADER) + #define BOTAN_DEPRECATED_HEADER(hdr) +#endif + +#if !defined(BOTAN_FUTURE_INTERNAL_HEADER) + #define BOTAN_FUTURE_INTERNAL_HEADER(hdr) +#endif + +/* +* Define BOTAN_NORETURN +*/ +#if !defined(BOTAN_NORETURN) + + #if defined (__clang__) || defined (__GNUC__) + #define BOTAN_NORETURN __attribute__ ((__noreturn__)) + + #elif defined (_MSC_VER) + #define BOTAN_NORETURN __declspec(noreturn) + + #else + #define BOTAN_NORETURN + #endif + +#endif + +/* +* Define BOTAN_THREAD_LOCAL +*/ +#if !defined(BOTAN_THREAD_LOCAL) + + #if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_TARGET_OS_HAS_THREAD_LOCAL) + #define BOTAN_THREAD_LOCAL thread_local + #else + #define BOTAN_THREAD_LOCAL /**/ + #endif + +#endif + +/* +* Define BOTAN_IF_CONSTEXPR +*/ +#if !defined(BOTAN_IF_CONSTEXPR) + #if __cplusplus >= 201703 + #define BOTAN_IF_CONSTEXPR if constexpr + #else + #define BOTAN_IF_CONSTEXPR if + #endif +#endif + +/* +* Define BOTAN_PARALLEL_FOR +*/ +#if !defined(BOTAN_PARALLEL_FOR) + +#if defined(BOTAN_TARGET_HAS_OPENMP) + #define BOTAN_PARALLEL_FOR _Pragma("omp parallel for") for +#else + #define BOTAN_PARALLEL_FOR for +#endif + +#endif + +/* +* Define BOTAN_FORCE_INLINE +*/ +#if !defined(BOTAN_FORCE_INLINE) + + #if defined (__clang__) || defined (__GNUC__) + #define BOTAN_FORCE_INLINE __attribute__ ((__always_inline__)) inline + + #elif defined (_MSC_VER) + #define BOTAN_FORCE_INLINE __forceinline + + #else + #define BOTAN_FORCE_INLINE inline + #endif + +#endif + +/* +* Define BOTAN_PARALLEL_SIMD_FOR +*/ +#if !defined(BOTAN_PARALLEL_SIMD_FOR) + +#if defined(BOTAN_TARGET_HAS_OPENMP) + #define BOTAN_PARALLEL_SIMD_FOR _Pragma("omp simd") for +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) && (BOTAN_GCC_VERSION >= 490) + #define BOTAN_PARALLEL_SIMD_FOR _Pragma("GCC ivdep") for +#else + #define BOTAN_PARALLEL_SIMD_FOR for +#endif + +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp new file mode 100644 index 0000000000..e76e12ea8d --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.cpp @@ -0,0 +1,231 @@ +/* +* Runtime CPU detection +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +bool CPUID::has_simd_32() + { +#if defined(BOTAN_TARGET_SUPPORTS_SSE2) + return CPUID::has_sse2(); +#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) + return CPUID::has_altivec(); +#elif defined(BOTAN_TARGET_SUPPORTS_NEON) + return CPUID::has_neon(); +#else + return true; +#endif + } + +//static +std::string CPUID::to_string() + { + std::vector flags; + +#define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0) + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + CPUID_PRINT(sse2); + CPUID_PRINT(ssse3); + CPUID_PRINT(sse41); + CPUID_PRINT(sse42); + CPUID_PRINT(avx2); + CPUID_PRINT(avx512f); + CPUID_PRINT(avx512dq); + CPUID_PRINT(avx512bw); + CPUID_PRINT(avx512_icelake); + + CPUID_PRINT(rdtsc); + CPUID_PRINT(bmi1); + CPUID_PRINT(bmi2); + CPUID_PRINT(adx); + + CPUID_PRINT(aes_ni); + CPUID_PRINT(clmul); + CPUID_PRINT(rdrand); + CPUID_PRINT(rdseed); + CPUID_PRINT(intel_sha); + CPUID_PRINT(avx512_aes); + CPUID_PRINT(avx512_clmul); +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + CPUID_PRINT(altivec); + CPUID_PRINT(power_crypto); + CPUID_PRINT(darn_rng); +#endif + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + CPUID_PRINT(neon); + CPUID_PRINT(arm_sve); + + CPUID_PRINT(arm_sha1); + CPUID_PRINT(arm_sha2); + CPUID_PRINT(arm_aes); + CPUID_PRINT(arm_pmull); + CPUID_PRINT(arm_sha2_512); + CPUID_PRINT(arm_sha3); + CPUID_PRINT(arm_sm3); + CPUID_PRINT(arm_sm4); +#endif + +#undef CPUID_PRINT + + return string_join(flags, ' '); + } + +//static +void CPUID::print(std::ostream& o) + { + o << "CPUID flags: " << CPUID::to_string() << "\n"; + } + +//static +void CPUID::initialize() + { + state() = CPUID_Data(); + } + +CPUID::CPUID_Data::CPUID_Data() + { + m_cache_line_size = 0; + m_processor_features = 0; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + m_processor_features = detect_cpu_features(&m_cache_line_size); + +#endif + + m_processor_features |= CPUID::CPUID_INITIALIZED_BIT; + + if(m_cache_line_size == 0) + m_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; + + m_endian_status = runtime_check_endian(); + } + +//static +CPUID::Endian_Status CPUID::CPUID_Data::runtime_check_endian() + { + // Check runtime endian + const uint32_t endian32 = 0x01234567; + const uint8_t* e8 = reinterpret_cast(&endian32); + + CPUID::Endian_Status endian = CPUID::Endian_Status::Unknown; + + if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) + { + endian = CPUID::Endian_Status::Big; + } + else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) + { + endian = CPUID::Endian_Status::Little; + } + else + { + throw Internal_Error("Unexpected endian at runtime, neither big nor little"); + } + + // If we were compiled with a known endian, verify it matches at runtime +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + BOTAN_ASSERT(endian == CPUID::Endian_Status::Little, "Build and runtime endian match"); +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + BOTAN_ASSERT(endian == CPUID::Endian_Status::Big, "Build and runtime endian match"); +#endif + + return endian; + } + +std::vector +CPUID::bit_from_string(const std::string& tok) + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + if(tok == "sse2" || tok == "simd") + return {Botan::CPUID::CPUID_SSE2_BIT}; + if(tok == "ssse3") + return {Botan::CPUID::CPUID_SSSE3_BIT}; + if(tok == "sse41") + return {Botan::CPUID::CPUID_SSE41_BIT}; + if(tok == "sse42") + return {Botan::CPUID::CPUID_SSE42_BIT}; + // aes_ni is the string printed on the console when running "botan cpuid" + if(tok == "aesni" || tok == "aes_ni") + return {Botan::CPUID::CPUID_AESNI_BIT}; + if(tok == "clmul") + return {Botan::CPUID::CPUID_CLMUL_BIT}; + if(tok == "avx2") + return {Botan::CPUID::CPUID_AVX2_BIT}; + if(tok == "avx512f") + return {Botan::CPUID::CPUID_AVX512F_BIT}; + if(tok == "avx512_icelake") + return {Botan::CPUID::CPUID_AVX512_ICL_BIT}; + // there were two if statements testing "sha" and "intel_sha" separately; combined + if(tok == "sha" || tok=="intel_sha") + return {Botan::CPUID::CPUID_SHA_BIT}; + if(tok == "rdtsc") + return {Botan::CPUID::CPUID_RDTSC_BIT}; + if(tok == "bmi1") + return {Botan::CPUID::CPUID_BMI1_BIT}; + if(tok == "bmi2") + return {Botan::CPUID::CPUID_BMI2_BIT}; + if(tok == "adx") + return {Botan::CPUID::CPUID_ADX_BIT}; + if(tok == "rdrand") + return {Botan::CPUID::CPUID_RDRAND_BIT}; + if(tok == "rdseed") + return {Botan::CPUID::CPUID_RDSEED_BIT}; + if(tok == "avx512_aes") + return {Botan::CPUID::CPUID_AVX512_AES_BIT}; + if(tok == "avx512_clmul") + return {Botan::CPUID::CPUID_AVX512_CLMUL_BIT}; + +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + if(tok == "altivec" || tok == "simd") + return {Botan::CPUID::CPUID_ALTIVEC_BIT}; + if(tok == "power_crypto") + return {Botan::CPUID::CPUID_POWER_CRYPTO_BIT}; + if(tok == "darn_rng") + return {Botan::CPUID::CPUID_DARN_BIT}; + +#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + if(tok == "neon" || tok == "simd") + return {Botan::CPUID::CPUID_ARM_NEON_BIT}; + if(tok == "arm_sve") + return {Botan::CPUID::CPUID_ARM_SVE_BIT}; + if(tok == "armv8sha1" || tok == "arm_sha1") + return {Botan::CPUID::CPUID_ARM_SHA1_BIT}; + if(tok == "armv8sha2" || tok == "arm_sha2") + return {Botan::CPUID::CPUID_ARM_SHA2_BIT}; + if(tok == "armv8aes" || tok == "arm_aes") + return {Botan::CPUID::CPUID_ARM_AES_BIT}; + if(tok == "armv8pmull" || tok == "arm_pmull") + return {Botan::CPUID::CPUID_ARM_PMULL_BIT}; + if(tok == "armv8sha3" || tok == "arm_sha3") + return {Botan::CPUID::CPUID_ARM_SHA3_BIT}; + if(tok == "armv8sha2_512" || tok == "arm_sha2_512") + return {Botan::CPUID::CPUID_ARM_SHA2_512_BIT}; + if(tok == "armv8sm3" || tok == "arm_sm3") + return {Botan::CPUID::CPUID_ARM_SM3_BIT}; + if(tok == "armv8sm4" || tok == "arm_sm4") + return {Botan::CPUID::CPUID_ARM_SM4_BIT}; + +#else + BOTAN_UNUSED(tok); +#endif + + return {}; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid.h b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.h new file mode 100644 index 0000000000..04d0bbd191 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid.h @@ -0,0 +1,484 @@ +/* +* Runtime CPU detection +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CPUID_H_ +#define BOTAN_CPUID_H_ + +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(cpuid.h) + +namespace Botan { + +/** +* A class handling runtime CPU feature detection. It is limited to +* just the features necessary to implement CPU specific code in Botan, +* rather than being a general purpose utility. +* +* This class supports: +* +* - x86 features using CPUID. x86 is also the only processor with +* accurate cache line detection currently. +* +* - PowerPC AltiVec detection on Linux, NetBSD, OpenBSD, and macOS +* +* - ARM NEON and crypto extensions detection. On Linux and Android +* systems which support getauxval, that is used to access CPU +* feature information. Otherwise a relatively portable but +* thread-unsafe mechanism involving executing probe functions which +* catching SIGILL signal is used. +*/ +class BOTAN_PUBLIC_API(2,1) CPUID final + { + public: + /** + * Probe the CPU and see what extensions are supported + */ + static void initialize(); + + static bool has_simd_32(); + + /** + * Deprecated equivalent to + * o << "CPUID flags: " << CPUID::to_string() << "\n"; + */ + BOTAN_DEPRECATED("Use CPUID::to_string") + static void print(std::ostream& o); + + /** + * Return a possibly empty string containing list of known CPU + * extensions. Each name will be seperated by a space, and the ordering + * will be arbitrary. This list only contains values that are useful to + * Botan (for example FMA instructions are not checked). + * + * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec" + */ + static std::string to_string(); + + /** + * Return a best guess of the cache line size + */ + static size_t cache_line_size() + { + return state().cache_line_size(); + } + + static bool is_little_endian() + { +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + return true; +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + return false; +#else + return state().endian_status() == Endian_Status::Little; +#endif + } + + static bool is_big_endian() + { +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + return true; +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + return false; +#else + return state().endian_status() == Endian_Status::Big; +#endif + } + + enum CPUID_bits : uint64_t { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + // These values have no relation to cpuid bitfields + + // SIMD instruction sets + CPUID_SSE2_BIT = (1ULL << 0), + CPUID_SSSE3_BIT = (1ULL << 1), + CPUID_SSE41_BIT = (1ULL << 2), + CPUID_SSE42_BIT = (1ULL << 3), + CPUID_AVX2_BIT = (1ULL << 4), + CPUID_AVX512F_BIT = (1ULL << 5), + + CPUID_AVX512DQ_BIT = (1ULL << 6), + CPUID_AVX512BW_BIT = (1ULL << 7), + + // Ice Lake profile: AVX-512 F, DQ, BW, IFMA, VBMI, VBMI2, BITALG + CPUID_AVX512_ICL_BIT = (1ULL << 11), + + // Crypto-specific ISAs + CPUID_AESNI_BIT = (1ULL << 16), + CPUID_CLMUL_BIT = (1ULL << 17), + CPUID_RDRAND_BIT = (1ULL << 18), + CPUID_RDSEED_BIT = (1ULL << 19), + CPUID_SHA_BIT = (1ULL << 20), + CPUID_AVX512_AES_BIT = (1ULL << 21), + CPUID_AVX512_CLMUL_BIT = (1ULL << 22), + + // Misc useful instructions + CPUID_RDTSC_BIT = (1ULL << 48), + CPUID_ADX_BIT = (1ULL << 49), + CPUID_BMI1_BIT = (1ULL << 50), + CPUID_BMI2_BIT = (1ULL << 51), +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + CPUID_ALTIVEC_BIT = (1ULL << 0), + CPUID_POWER_CRYPTO_BIT = (1ULL << 1), + CPUID_DARN_BIT = (1ULL << 2), +#endif + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + CPUID_ARM_NEON_BIT = (1ULL << 0), + CPUID_ARM_SVE_BIT = (1ULL << 1), + CPUID_ARM_AES_BIT = (1ULL << 16), + CPUID_ARM_PMULL_BIT = (1ULL << 17), + CPUID_ARM_SHA1_BIT = (1ULL << 18), + CPUID_ARM_SHA2_BIT = (1ULL << 19), + CPUID_ARM_SHA3_BIT = (1ULL << 20), + CPUID_ARM_SHA2_512_BIT = (1ULL << 21), + CPUID_ARM_SM3_BIT = (1ULL << 22), + CPUID_ARM_SM4_BIT = (1ULL << 23), +#endif + + CPUID_INITIALIZED_BIT = (1ULL << 63) + }; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + /** + * Check if the processor supports AltiVec/VMX + */ + static bool has_altivec() + { return has_cpuid_bit(CPUID_ALTIVEC_BIT); } + + /** + * Check if the processor supports POWER8 crypto extensions + */ + static bool has_power_crypto() + { return has_cpuid_bit(CPUID_POWER_CRYPTO_BIT); } + + /** + * Check if the processor supports POWER9 DARN RNG + */ + static bool has_darn_rng() + { return has_cpuid_bit(CPUID_DARN_BIT); } + +#endif + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + /** + * Check if the processor supports NEON SIMD + */ + static bool has_neon() + { return has_cpuid_bit(CPUID_ARM_NEON_BIT); } + + /** + * Check if the processor supports ARMv8 SVE + */ + static bool has_arm_sve() + { return has_cpuid_bit(CPUID_ARM_SVE_BIT); } + + /** + * Check if the processor supports ARMv8 SHA1 + */ + static bool has_arm_sha1() + { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); } + + /** + * Check if the processor supports ARMv8 SHA2 + */ + static bool has_arm_sha2() + { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); } + + /** + * Check if the processor supports ARMv8 AES + */ + static bool has_arm_aes() + { return has_cpuid_bit(CPUID_ARM_AES_BIT); } + + /** + * Check if the processor supports ARMv8 PMULL + */ + static bool has_arm_pmull() + { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); } + + /** + * Check if the processor supports ARMv8 SHA-512 + */ + static bool has_arm_sha2_512() + { return has_cpuid_bit(CPUID_ARM_SHA2_512_BIT); } + + /** + * Check if the processor supports ARMv8 SHA-3 + */ + static bool has_arm_sha3() + { return has_cpuid_bit(CPUID_ARM_SHA3_BIT); } + + /** + * Check if the processor supports ARMv8 SM3 + */ + static bool has_arm_sm3() + { return has_cpuid_bit(CPUID_ARM_SM3_BIT); } + + /** + * Check if the processor supports ARMv8 SM4 + */ + static bool has_arm_sm4() + { return has_cpuid_bit(CPUID_ARM_SM4_BIT); } + +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + /** + * Check if the processor supports RDTSC + */ + static bool has_rdtsc() + { return has_cpuid_bit(CPUID_RDTSC_BIT); } + + /** + * Check if the processor supports SSE2 + */ + static bool has_sse2() + { return has_cpuid_bit(CPUID_SSE2_BIT); } + + /** + * Check if the processor supports SSSE3 + */ + static bool has_ssse3() + { return has_cpuid_bit(CPUID_SSSE3_BIT); } + + /** + * Check if the processor supports SSE4.1 + */ + static bool has_sse41() + { return has_cpuid_bit(CPUID_SSE41_BIT); } + + /** + * Check if the processor supports SSE4.2 + */ + static bool has_sse42() + { return has_cpuid_bit(CPUID_SSE42_BIT); } + + /** + * Check if the processor supports AVX2 + */ + static bool has_avx2() + { return has_cpuid_bit(CPUID_AVX2_BIT); } + + /** + * Check if the processor supports AVX-512F + */ + static bool has_avx512f() + { return has_cpuid_bit(CPUID_AVX512F_BIT); } + + /** + * Check if the processor supports AVX-512DQ + */ + static bool has_avx512dq() + { return has_cpuid_bit(CPUID_AVX512DQ_BIT); } + + /** + * Check if the processor supports AVX-512BW + */ + static bool has_avx512bw() + { return has_cpuid_bit(CPUID_AVX512BW_BIT); } + + /** + * Check if the processor supports AVX-512 Ice Lake profile + */ + static bool has_avx512_icelake() + { return has_cpuid_bit(CPUID_AVX512_ICL_BIT); } + + /** + * Check if the processor supports AVX-512 AES (VAES) + */ + static bool has_avx512_aes() + { return has_cpuid_bit(CPUID_AVX512_AES_BIT); } + + /** + * Check if the processor supports AVX-512 VPCLMULQDQ + */ + static bool has_avx512_clmul() + { return has_cpuid_bit(CPUID_AVX512_CLMUL_BIT); } + + /** + * Check if the processor supports BMI1 + */ + static bool has_bmi1() + { return has_cpuid_bit(CPUID_BMI1_BIT); } + + /** + * Check if the processor supports BMI2 + */ + static bool has_bmi2() + { return has_cpuid_bit(CPUID_BMI2_BIT); } + + /** + * Check if the processor supports AES-NI + */ + static bool has_aes_ni() + { return has_cpuid_bit(CPUID_AESNI_BIT); } + + /** + * Check if the processor supports CLMUL + */ + static bool has_clmul() + { return has_cpuid_bit(CPUID_CLMUL_BIT); } + + /** + * Check if the processor supports Intel SHA extension + */ + static bool has_intel_sha() + { return has_cpuid_bit(CPUID_SHA_BIT); } + + /** + * Check if the processor supports ADX extension + */ + static bool has_adx() + { return has_cpuid_bit(CPUID_ADX_BIT); } + + /** + * Check if the processor supports RDRAND + */ + static bool has_rdrand() + { return has_cpuid_bit(CPUID_RDRAND_BIT); } + + /** + * Check if the processor supports RDSEED + */ + static bool has_rdseed() + { return has_cpuid_bit(CPUID_RDSEED_BIT); } +#endif + + /** + * Check if the processor supports byte-level vector permutes + * (SSSE3, NEON, Altivec) + */ + static bool has_vperm() + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + return has_ssse3(); +#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + return has_neon(); +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + return has_altivec(); +#else + return false; +#endif + } + + /** + * Check if the processor supports hardware AES instructions + */ + static bool has_hw_aes() + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + return has_aes_ni(); +#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + return has_arm_aes(); +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + return has_power_crypto(); +#else + return false; +#endif + } + + /** + * Check if the processor supports carryless multiply + * (CLMUL, PMULL) + */ + static bool has_carryless_multiply() + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + return has_clmul(); +#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + return has_arm_pmull(); +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + return has_power_crypto(); +#else + return false; +#endif + } + + /* + * Clear a CPUID bit + * Call CPUID::initialize to reset + * + * This is only exposed for testing, don't use unless you know + * what you are doing. + */ + static void clear_cpuid_bit(CPUID_bits bit) + { + state().clear_cpuid_bit(static_cast(bit)); + } + + /* + * Don't call this function, use CPUID::has_xxx above + * It is only exposed for the tests. + */ + static bool has_cpuid_bit(CPUID_bits elem) + { + const uint64_t elem64 = static_cast(elem); + return state().has_bit(elem64); + } + + static std::vector bit_from_string(const std::string& tok); + private: + enum class Endian_Status : uint32_t { + Unknown = 0x00000000, + Big = 0x01234567, + Little = 0x67452301, + }; + + struct CPUID_Data + { + public: + CPUID_Data(); + + CPUID_Data(const CPUID_Data& other) = default; + CPUID_Data& operator=(const CPUID_Data& other) = default; + + void clear_cpuid_bit(uint64_t bit) + { + m_processor_features &= ~bit; + } + + bool has_bit(uint64_t bit) const + { + return (m_processor_features & bit) == bit; + } + + uint64_t processor_features() const { return m_processor_features; } + Endian_Status endian_status() const { return m_endian_status; } + size_t cache_line_size() const { return m_cache_line_size; } + + private: + static Endian_Status runtime_check_endian(); + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + static uint64_t detect_cpu_features(size_t* cache_line_size); + +#endif + uint64_t m_processor_features; + size_t m_cache_line_size; + Endian_Status m_endian_status; + }; + + static CPUID_Data& state() + { + static CPUID::CPUID_Data g_cpuid; + return g_cpuid; + } + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp new file mode 100644 index 0000000000..0711dfdf39 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_arm.cpp @@ -0,0 +1,237 @@ +/* +* Runtime CPU detection for ARM +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + +#if defined(BOTAN_TARGET_OS_IS_IOS) + #include + #include + +#else + #include + +#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) + #include +#endif + +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + +#if defined(BOTAN_TARGET_OS_IS_IOS) + +namespace { + +uint64_t flags_by_ios_machine_type(const std::string& machine) + { + /* + * This relies on a map of known machine names to features. This + * will quickly grow out of date as new products are introduced, but + * is apparently the best we can do for iOS. + */ + + struct version_info { + std::string name; + size_t min_version_neon; + size_t min_version_armv8; + }; + + static const version_info min_versions[] = { + { "iPhone", 2, 6 }, + { "iPad", 1, 4 }, + { "iPod", 4, 7 }, + { "AppleTV", 2, 5 }, + }; + + if(machine.size() < 3) + return 0; + + auto comma = machine.find(','); + + // Simulator, or something we don't know about + if(comma == std::string::npos) + return 0; + + std::string product = machine.substr(0, comma); + + size_t version = 0; + size_t place = 1; + while(product.size() > 1 && ::isdigit(product.back())) + { + const size_t digit = product.back() - '0'; + version += digit * place; + place *= 10; + product.pop_back(); + } + + if(version == 0) + return 0; + + for(const version_info& info : min_versions) + { + if(info.name != product) + continue; + + if(version >= info.min_version_armv8) + { + return CPUID::CPUID_ARM_AES_BIT | + CPUID::CPUID_ARM_PMULL_BIT | + CPUID::CPUID_ARM_SHA1_BIT | + CPUID::CPUID_ARM_SHA2_BIT | + CPUID::CPUID_ARM_NEON_BIT; + } + + if(version >= info.min_version_neon) + return CPUID::CPUID_ARM_NEON_BIT; + } + + // Some other product we don't know about + return 0; + } + +} + +#endif + +uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) + { + BOTAN_UNUSED(cache_line_size); + + uint64_t detected_features = 0; + +#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) + /* + * On systems with getauxval these bits should normally be defined + * in bits/auxv.h but some buggy? glibc installs seem to miss them. + * These following values are all fixed, for the Linux ELF format, + * so we just hardcode them in ARM_hwcap_bit enum. + */ + + enum ARM_hwcap_bit { +#if defined(BOTAN_TARGET_ARCH_IS_ARM32) + NEON_bit = (1 << 12), + AES_bit = (1 << 0), + PMULL_bit = (1 << 1), + SHA1_bit = (1 << 2), + SHA2_bit = (1 << 3), + + ARCH_hwcap_neon = 16, // AT_HWCAP + ARCH_hwcap_crypto = 26, // AT_HWCAP2 +#elif defined(BOTAN_TARGET_ARCH_IS_ARM64) + NEON_bit = (1 << 1), + AES_bit = (1 << 3), + PMULL_bit = (1 << 4), + SHA1_bit = (1 << 5), + SHA2_bit = (1 << 6), + SHA3_bit = (1 << 17), + SM3_bit = (1 << 18), + SM4_bit = (1 << 19), + SHA2_512_bit = (1 << 21), + SVE_bit = (1 << 22), + + ARCH_hwcap_neon = 16, // AT_HWCAP + ARCH_hwcap_crypto = 16, // AT_HWCAP +#endif + }; + +#if defined(AT_DCACHEBSIZE) + // Exists only on Linux + const unsigned long dcache_line = OS::get_auxval(AT_DCACHEBSIZE); + + // plausibility check + if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128) + *cache_line_size = static_cast(dcache_line); +#endif + + const unsigned long hwcap_neon = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_neon); + if(hwcap_neon & ARM_hwcap_bit::NEON_bit) + detected_features |= CPUID::CPUID_ARM_NEON_BIT; + + /* + On aarch64 this ends up calling getauxval twice with AT_HWCAP + It doesn't seem worth optimizing this out, since getauxval is + just reading a field in the ELF header. + */ + const unsigned long hwcap_crypto = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_crypto); + if(hwcap_crypto & ARM_hwcap_bit::AES_bit) + detected_features |= CPUID::CPUID_ARM_AES_BIT; + if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit) + detected_features |= CPUID::CPUID_ARM_PMULL_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit) + detected_features |= CPUID::CPUID_ARM_SHA1_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit) + detected_features |= CPUID::CPUID_ARM_SHA2_BIT; + +#if defined(BOTAN_TARGET_ARCH_IS_ARM64) + if(hwcap_crypto & ARM_hwcap_bit::SHA3_bit) + detected_features |= CPUID::CPUID_ARM_SHA3_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SM3_bit) + detected_features |= CPUID::CPUID_ARM_SM3_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SM4_bit) + detected_features |= CPUID::CPUID_ARM_SM4_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SHA2_512_bit) + detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SVE_bit) + detected_features |= CPUID::CPUID_ARM_SVE_BIT; +#endif + +#elif defined(BOTAN_TARGET_OS_IS_IOS) + + char machine[64] = { 0 }; + size_t size = sizeof(machine) - 1; + ::sysctlbyname("hw.machine", machine, &size, nullptr, 0); + + detected_features = flags_by_ios_machine_type(machine); + // No way to detect cache line size on iOS? + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64) + + /* + No getauxval API available, fall back on probe functions. We only + bother with Aarch64 here to simplify the code and because going to + extreme contortions to support detect NEON on devices that probably + don't support it doesn't seem worthwhile. + + NEON registers v0-v7 are caller saved in Aarch64 + */ + + auto neon_probe = []() noexcept -> int { asm("and v0.16b, v0.16b, v0.16b"); return 1; }; + auto aes_probe = []() noexcept -> int { asm(".word 0x4e284800"); return 1; }; + auto pmull_probe = []() noexcept -> int { asm(".word 0x0ee0e000"); return 1; }; + auto sha1_probe = []() noexcept -> int { asm(".word 0x5e280800"); return 1; }; + auto sha2_probe = []() noexcept -> int { asm(".word 0x5e282800"); return 1; }; + + // Only bother running the crypto detection if we found NEON + + if(OS::run_cpu_instruction_probe(neon_probe) == 1) + { + detected_features |= CPUID::CPUID_ARM_NEON_BIT; + + if(OS::run_cpu_instruction_probe(aes_probe) == 1) + detected_features |= CPUID::CPUID_ARM_AES_BIT; + if(OS::run_cpu_instruction_probe(pmull_probe) == 1) + detected_features |= CPUID::CPUID_ARM_PMULL_BIT; + if(OS::run_cpu_instruction_probe(sha1_probe) == 1) + detected_features |= CPUID::CPUID_ARM_SHA1_BIT; + if(OS::run_cpu_instruction_probe(sha2_probe) == 1) + detected_features |= CPUID::CPUID_ARM_SHA2_BIT; + } + +#endif + + return detected_features; + } + +#endif + +} diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp new file mode 100644 index 0000000000..604b97947c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp @@ -0,0 +1,132 @@ +/* +* Runtime CPU detection for POWER/PowerPC +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +/* +* On macOS and OpenBSD ppc, use sysctl to detect AltiVec +*/ +#if defined(BOTAN_TARGET_OS_IS_MACOS) + #include +#elif defined(BOTAN_TARGET_OS_IS_OPENBSD) + #include + #include + #include +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +/* +* PowerPC specific block: check for AltiVec using either +* sysctl or by reading processor version number register. +*/ +uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) + { + BOTAN_UNUSED(cache_line_size); + +#if defined(BOTAN_TARGET_OS_IS_MACOS) || defined(BOTAN_TARGET_OS_IS_OPENBSD) + // On macOS and OpenBSD, use sysctl + + int sels[2] = { +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + CTL_MACHDEP, CPU_ALTIVEC +#else + CTL_HW, HW_VECTORUNIT +#endif + }; + + int vector_type = 0; + size_t length = sizeof(vector_type); + int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0); + + if(error == 0 && vector_type > 0) + return CPUID::CPUID_ALTIVEC_BIT; + +#elif (defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_HAS_ELF_AUX_INFO)) && defined(BOTAN_TARGET_ARCH_IS_PPC64) + + enum PPC_hwcap_bit { + ALTIVEC_bit = (1 << 28), + CRYPTO_bit = (1 << 25), + DARN_bit = (1 << 21), + + ARCH_hwcap_altivec = 16, // AT_HWCAP + ARCH_hwcap_crypto = 26, // AT_HWCAP2 + }; + + uint64_t detected_features = 0; + + const unsigned long hwcap_altivec = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_altivec); + if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit) + detected_features |= CPUID::CPUID_ALTIVEC_BIT; + + const unsigned long hwcap_crypto = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_crypto); + if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit) + detected_features |= CPUID::CPUID_POWER_CRYPTO_BIT; + if(hwcap_crypto & PPC_hwcap_bit::DARN_bit) + detected_features |= CPUID::CPUID_DARN_BIT; + + return detected_features; + +#else + + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + Normally it is only accessible to ring 0, but Linux and NetBSD + (others, too, maybe?) will trap and emulate it for us. + */ + + int pvr = OS::run_cpu_instruction_probe([]() noexcept -> int { + uint32_t pvr = 0; + asm volatile("mfspr %0, 287" : "=r" (pvr)); + // Top 16 bits suffice to identify the model + return static_cast(pvr >> 16); + }); + + if(pvr > 0) + { + const uint16_t ALTIVEC_PVR[] = { + 0x003E, // IBM POWER6 + 0x003F, // IBM POWER7 + 0x004A, // IBM POWER7p + 0x004B, // IBM POWER8E + 0x004C, // IBM POWER8 NVL + 0x004D, // IBM POWER8 + 0x004E, // IBM POWER9 + 0x000C, // G4-7400 + 0x0039, // G5 970 + 0x003C, // G5 970FX + 0x0044, // G5 970MP + 0x0070, // Cell PPU + 0, // end + }; + + for(size_t i = 0; ALTIVEC_PVR[i]; ++i) + { + if(pvr == ALTIVEC_PVR[i]) + return CPUID::CPUID_ALTIVEC_BIT; + } + + return 0; + } + + // TODO try direct instruction probing + +#endif + + return 0; + } + +#endif + +} diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp new file mode 100644 index 0000000000..0595e1a604 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_x86.cpp @@ -0,0 +1,214 @@ +/* +* Runtime CPU detection for x86 +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + #include +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + #include +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) + { +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) + #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + #define X86_CPUID(type, out) do { __cpuid(out, type); } while(0) + #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && defined(BOTAN_USE_GCC_INLINE_ASM) + #define X86_CPUID(type, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type)) + + #define X86_CPUID_SUBLEVEL(type, level, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type), "2" (level)) + +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + #define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0) + + #define X86_CPUID_SUBLEVEL(type, level, out) \ + do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0) +#else + #warning "No way of calling x86 cpuid instruction for this compiler" + #define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0) + #define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0) +#endif + + uint64_t features_detected = 0; + uint32_t cpuid[4] = { 0 }; + + // CPUID 0: vendor identification, max sublevel + X86_CPUID(0, cpuid); + + const uint32_t max_supported_sublevel = cpuid[0]; + + const uint32_t INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 }; + const uint32_t AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 }; + const bool is_intel = same_mem(cpuid + 1, INTEL_CPUID, 3); + const bool is_amd = same_mem(cpuid + 1, AMD_CPUID, 3); + + if(max_supported_sublevel >= 1) + { + // CPUID 1: feature bits + X86_CPUID(1, cpuid); + const uint64_t flags0 = (static_cast(cpuid[2]) << 32) | cpuid[3]; + + enum x86_CPUID_1_bits : uint64_t { + RDTSC = (1ULL << 4), + SSE2 = (1ULL << 26), + CLMUL = (1ULL << 33), + SSSE3 = (1ULL << 41), + SSE41 = (1ULL << 51), + SSE42 = (1ULL << 52), + AESNI = (1ULL << 57), + RDRAND = (1ULL << 62) + }; + + if(flags0 & x86_CPUID_1_bits::RDTSC) + features_detected |= CPUID::CPUID_RDTSC_BIT; + if(flags0 & x86_CPUID_1_bits::SSE2) + features_detected |= CPUID::CPUID_SSE2_BIT; + if(flags0 & x86_CPUID_1_bits::CLMUL) + features_detected |= CPUID::CPUID_CLMUL_BIT; + if(flags0 & x86_CPUID_1_bits::SSSE3) + features_detected |= CPUID::CPUID_SSSE3_BIT; + if(flags0 & x86_CPUID_1_bits::SSE41) + features_detected |= CPUID::CPUID_SSE41_BIT; + if(flags0 & x86_CPUID_1_bits::SSE42) + features_detected |= CPUID::CPUID_SSE42_BIT; + if(flags0 & x86_CPUID_1_bits::AESNI) + features_detected |= CPUID::CPUID_AESNI_BIT; + if(flags0 & x86_CPUID_1_bits::RDRAND) + features_detected |= CPUID::CPUID_RDRAND_BIT; + } + + if(is_intel) + { + // Intel cache line size is in cpuid(1) output + *cache_line_size = 8 * get_byte(2, cpuid[1]); + } + else if(is_amd) + { + // AMD puts it in vendor zone + X86_CPUID(0x80000005, cpuid); + *cache_line_size = get_byte(3, cpuid[2]); + } + + if(max_supported_sublevel >= 7) + { + clear_mem(cpuid, 4); + X86_CPUID_SUBLEVEL(7, 0, cpuid); + + enum x86_CPUID_7_bits : uint64_t { + BMI1 = (1ULL << 3), + AVX2 = (1ULL << 5), + BMI2 = (1ULL << 8), + AVX512_F = (1ULL << 16), + AVX512_DQ = (1ULL << 17), + RDSEED = (1ULL << 18), + ADX = (1ULL << 19), + AVX512_IFMA = (1ULL << 21), + SHA = (1ULL << 29), + AVX512_BW = (1ULL << 30), + AVX512_VL = (1ULL << 31), + AVX512_VBMI = (1ULL << 33), + AVX512_VBMI2 = (1ULL << 38), + AVX512_VAES = (1ULL << 41), + AVX512_VCLMUL = (1ULL << 42), + AVX512_VBITALG = (1ULL << 44), + }; + + const uint64_t flags7 = (static_cast(cpuid[2]) << 32) | cpuid[1]; + + if(flags7 & x86_CPUID_7_bits::AVX2) + features_detected |= CPUID::CPUID_AVX2_BIT; + if(flags7 & x86_CPUID_7_bits::BMI1) + { + features_detected |= CPUID::CPUID_BMI1_BIT; + /* + We only set the BMI2 bit if BMI1 is also supported, so BMI2 + code can safely use both extensions. No known processor + implements BMI2 but not BMI1. + */ + if(flags7 & x86_CPUID_7_bits::BMI2) + features_detected |= CPUID::CPUID_BMI2_BIT; + } + + if(flags7 & x86_CPUID_7_bits::AVX512_F) + { + features_detected |= CPUID::CPUID_AVX512F_BIT; + + if(flags7 & x86_CPUID_7_bits::AVX512_DQ) + features_detected |= CPUID::CPUID_AVX512DQ_BIT; + if(flags7 & x86_CPUID_7_bits::AVX512_BW) + features_detected |= CPUID::CPUID_AVX512BW_BIT; + + const uint64_t ICELAKE_FLAGS = + x86_CPUID_7_bits::AVX512_F | + x86_CPUID_7_bits::AVX512_DQ | + x86_CPUID_7_bits::AVX512_IFMA | + x86_CPUID_7_bits::AVX512_BW | + x86_CPUID_7_bits::AVX512_VL | + x86_CPUID_7_bits::AVX512_VBMI | + x86_CPUID_7_bits::AVX512_VBMI2 | + x86_CPUID_7_bits::AVX512_VBITALG; + + if((flags7 & ICELAKE_FLAGS) == ICELAKE_FLAGS) + features_detected |= CPUID::CPUID_AVX512_ICL_BIT; + + if(flags7 & x86_CPUID_7_bits::AVX512_VAES) + features_detected |= CPUID::CPUID_AVX512_AES_BIT; + if(flags7 & x86_CPUID_7_bits::AVX512_VCLMUL) + features_detected |= CPUID::CPUID_AVX512_CLMUL_BIT; + } + + if(flags7 & x86_CPUID_7_bits::RDSEED) + features_detected |= CPUID::CPUID_RDSEED_BIT; + if(flags7 & x86_CPUID_7_bits::ADX) + features_detected |= CPUID::CPUID_ADX_BIT; + if(flags7 & x86_CPUID_7_bits::SHA) + features_detected |= CPUID::CPUID_SHA_BIT; + } + +#undef X86_CPUID +#undef X86_CPUID_SUBLEVEL + + /* + * If we don't have access to CPUID, we can still safely assume that + * any x86-64 processor has SSE2 and RDTSC + */ +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + if(features_detected == 0) + { + features_detected |= CPUID::CPUID_SSE2_BIT; + features_detected |= CPUID::CPUID_RDTSC_BIT; + } +#endif + + return features_detected; + } + +#endif + +} diff --git a/comm/third_party/botan/src/lib/utils/cpuid/info.txt b/comm/third_party/botan/src/lib/utils/cpuid/info.txt new file mode 100644 index 0000000000..987d7eae4d --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/info.txt @@ -0,0 +1,7 @@ + +CPUID -> 20170917 + + + +cpuid.h + diff --git a/comm/third_party/botan/src/lib/utils/ct_utils.cpp b/comm/third_party/botan/src/lib/utils/ct_utils.cpp new file mode 100644 index 0000000000..cbcecfc282 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ct_utils.cpp @@ -0,0 +1,83 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +namespace CT { + +secure_vector copy_output(CT::Mask bad_input, + const uint8_t input[], + size_t input_length, + size_t offset) + { + if(input_length == 0) + return secure_vector(); + + /* + * Ensure at runtime that offset <= input_length. This is an invalid input, + * but we can't throw without using the poisoned value. Instead, if it happens, + * set offset to be equal to the input length (so output_bytes becomes 0 and + * the returned vector is empty) + */ + const auto valid_offset = CT::Mask::is_lte(offset, input_length); + offset = valid_offset.select(offset, input_length); + + const size_t output_bytes = input_length - offset; + + secure_vector output(input_length); + + /* + Move the desired output bytes to the front using a slow (O^n) + but constant time loop that does not leak the value of the offset + */ + for(size_t i = 0; i != input_length; ++i) + { + /* + start index from i rather than 0 since we know j must be >= i + offset + to have any effect, and starting from i does not reveal information + */ + for(size_t j = i; j != input_length; ++j) + { + const uint8_t b = input[j]; + const auto is_eq = CT::Mask::is_equal(j, offset + i); + output[i] |= is_eq.if_set_return(b); + } + } + + bad_input.if_set_zero_out(output.data(), output.size()); + + CT::unpoison(output.data(), output.size()); + CT::unpoison(output_bytes); + + /* + This is potentially not const time, depending on how std::vector is + implemented. But since we are always reducing length, it should + just amount to setting the member var holding the length. + */ + output.resize(output_bytes); + return output; + } + +secure_vector strip_leading_zeros(const uint8_t in[], size_t length) + { + size_t leading_zeros = 0; + + auto only_zeros = Mask::set(); + + for(size_t i = 0; i != length; ++i) + { + only_zeros &= CT::Mask::is_zero(in[i]); + leading_zeros += only_zeros.if_set_return(1); + } + + return copy_output(CT::Mask::cleared(), in, length, leading_zeros); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/utils/ct_utils.h b/comm/third_party/botan/src/lib/utils/ct_utils.h new file mode 100644 index 0000000000..f2e7452931 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ct_utils.h @@ -0,0 +1,418 @@ +/* +* Functions for constant time operations on data and testing of +* constant time annotations using valgrind. +* +* For more information about constant time programming see +* Wagner, Molnar, et al "The Program Counter Security Model" +* +* (C) 2010 Falko Strenzke +* (C) 2015,2016,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CT_UTILS_H_ +#define BOTAN_CT_UTILS_H_ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_VALGRIND) + #include +#endif + +namespace Botan { + +namespace CT { + +/** +* Use valgrind to mark the contents of memory as being undefined. +* Valgrind will accept operations which manipulate undefined values, +* but will warn if an undefined value is used to decided a conditional +* jump or a load/store address. So if we poison all of our inputs we +* can confirm that the operations in question are truly const time +* when compiled by whatever compiler is in use. +* +* Even better, the VALGRIND_MAKE_MEM_* macros work even when the +* program is not run under valgrind (though with a few cycles of +* overhead, which is unfortunate in final binaries as these +* annotations tend to be used in fairly important loops). +* +* This approach was first used in ctgrind (https://github.com/agl/ctgrind) +* but calling the valgrind mecheck API directly works just as well and +* doesn't require a custom patched valgrind. +*/ +template +inline void poison(const T* p, size_t n) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); +#else + BOTAN_UNUSED(p); + BOTAN_UNUSED(n); +#endif + } + +template +inline void unpoison(const T* p, size_t n) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); +#else + BOTAN_UNUSED(p); + BOTAN_UNUSED(n); +#endif + } + +template +inline void unpoison(T& p) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); +#else + BOTAN_UNUSED(p); +#endif + } + +/** +* A Mask type used for constant-time operations. A Mask always has value +* either 0 (all bits cleared) or ~0 (all bits set). All operations in a Mask +* are intended to compile to code which does not contain conditional jumps. +* This must be verified with tooling (eg binary disassembly or using valgrind) +* since you never know what a compiler might do. +*/ +template +class Mask + { + public: + static_assert(std::is_unsigned::value, "CT::Mask only defined for unsigned integer types"); + + Mask(const Mask& other) = default; + Mask& operator=(const Mask& other) = default; + + /** + * Derive a Mask from a Mask of a larger type + */ + template + Mask(Mask o) : m_mask(static_cast(o.value())) + { + static_assert(sizeof(U) > sizeof(T), "sizes ok"); + } + + /** + * Return a Mask with all bits set + */ + static Mask set() + { + return Mask(static_cast(~0)); + } + + /** + * Return a Mask with all bits cleared + */ + static Mask cleared() + { + return Mask(0); + } + + /** + * Return a Mask which is set if v is != 0 + */ + static Mask expand(T v) + { + return ~Mask::is_zero(v); + } + + /** + * Return a Mask which is set if m is set + */ + template + static Mask expand(Mask m) + { + static_assert(sizeof(U) < sizeof(T), "sizes ok"); + return ~Mask::is_zero(m.value()); + } + + /** + * Return a Mask which is set if v is == 0 or cleared otherwise + */ + static Mask is_zero(T x) + { + return Mask(ct_is_zero(x)); + } + + /** + * Return a Mask which is set if x == y + */ + static Mask is_equal(T x, T y) + { + return Mask::is_zero(static_cast(x ^ y)); + } + + /** + * Return a Mask which is set if x < y + */ + static Mask is_lt(T x, T y) + { + return Mask(expand_top_bit(x^((x^y) | ((x-y)^x)))); + } + + /** + * Return a Mask which is set if x > y + */ + static Mask is_gt(T x, T y) + { + return Mask::is_lt(y, x); + } + + /** + * Return a Mask which is set if x <= y + */ + static Mask is_lte(T x, T y) + { + return ~Mask::is_gt(x, y); + } + + /** + * Return a Mask which is set if x >= y + */ + static Mask is_gte(T x, T y) + { + return ~Mask::is_lt(x, y); + } + + static Mask is_within_range(T v, T l, T u) + { + //return Mask::is_gte(v, l) & Mask::is_lte(v, u); + + const T v_lt_l = v^((v^l) | ((v-l)^v)); + const T v_gt_u = u^((u^v) | ((u-v)^u)); + const T either = v_lt_l | v_gt_u; + return ~Mask(expand_top_bit(either)); + } + + static Mask is_any_of(T v, std::initializer_list accepted) + { + T accept = 0; + + for(auto a: accepted) + { + const T diff = a ^ v; + const T eq_zero = ~diff & (diff - 1); + accept |= eq_zero; + } + + return Mask(expand_top_bit(accept)); + } + + /** + * AND-combine two masks + */ + Mask& operator&=(Mask o) + { + m_mask &= o.value(); + return (*this); + } + + /** + * XOR-combine two masks + */ + Mask& operator^=(Mask o) + { + m_mask ^= o.value(); + return (*this); + } + + /** + * OR-combine two masks + */ + Mask& operator|=(Mask o) + { + m_mask |= o.value(); + return (*this); + } + + /** + * AND-combine two masks + */ + friend Mask operator&(Mask x, Mask y) + { + return Mask(x.value() & y.value()); + } + + /** + * XOR-combine two masks + */ + friend Mask operator^(Mask x, Mask y) + { + return Mask(x.value() ^ y.value()); + } + + /** + * OR-combine two masks + */ + friend Mask operator|(Mask x, Mask y) + { + return Mask(x.value() | y.value()); + } + + /** + * Negate this mask + */ + Mask operator~() const + { + return Mask(~value()); + } + + /** + * Return x if the mask is set, or otherwise zero + */ + T if_set_return(T x) const + { + return m_mask & x; + } + + /** + * Return x if the mask is cleared, or otherwise zero + */ + T if_not_set_return(T x) const + { + return ~m_mask & x; + } + + /** + * If this mask is set, return x, otherwise return y + */ + T select(T x, T y) const + { + // (x & value()) | (y & ~value()) + return static_cast(y ^ (value() & (x ^ y))); + } + + T select_and_unpoison(T x, T y) const + { + T r = this->select(x, y); + CT::unpoison(r); + return r; + } + + /** + * If this mask is set, return x, otherwise return y + */ + Mask select_mask(Mask x, Mask y) const + { + return Mask(select(x.value(), y.value())); + } + + /** + * Conditionally set output to x or y, depending on if mask is set or + * cleared (resp) + */ + void select_n(T output[], const T x[], const T y[], size_t len) const + { + for(size_t i = 0; i != len; ++i) + output[i] = this->select(x[i], y[i]); + } + + /** + * If this mask is set, zero out buf, otherwise do nothing + */ + void if_set_zero_out(T buf[], size_t elems) + { + for(size_t i = 0; i != elems; ++i) + { + buf[i] = this->if_not_set_return(buf[i]); + } + } + + /** + * Return the value of the mask, unpoisoned + */ + T unpoisoned_value() const + { + T r = value(); + CT::unpoison(r); + return r; + } + + /** + * Return true iff this mask is set + */ + bool is_set() const + { + return unpoisoned_value() != 0; + } + + /** + * Return the underlying value of the mask + */ + T value() const + { + return m_mask; + } + + private: + Mask(T m) : m_mask(m) {} + + T m_mask; + }; + +template +inline Mask conditional_copy_mem(T cnd, + T* to, + const T* from0, + const T* from1, + size_t elems) + { + const auto mask = CT::Mask::expand(cnd); + mask.select_n(to, from0, from1, elems); + return mask; + } + +template +inline void conditional_swap(bool cnd, T& x, T& y) + { + const auto swap = CT::Mask::expand(cnd); + + T t0 = swap.select(y, x); + T t1 = swap.select(x, y); + x = t0; + y = t1; + } + +template +inline void conditional_swap_ptr(bool cnd, T& x, T& y) + { + uintptr_t xp = reinterpret_cast(x); + uintptr_t yp = reinterpret_cast(y); + + conditional_swap(cnd, xp, yp); + + x = reinterpret_cast(xp); + y = reinterpret_cast(yp); + } + +/** +* If bad_mask is unset, return in[delim_idx:input_length] copied to +* new buffer. If bad_mask is set, return an all zero vector of +* unspecified length. +*/ +secure_vector copy_output(CT::Mask bad_input, + const uint8_t input[], + size_t input_length, + size_t delim_idx); + +secure_vector strip_leading_zeros(const uint8_t in[], size_t length); + +inline secure_vector strip_leading_zeros(const secure_vector& in) + { + return strip_leading_zeros(in.data(), in.size()); + } + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/data_src.cpp b/comm/third_party/botan/src/lib/utils/data_src.cpp new file mode 100644 index 0000000000..c5689534ff --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/data_src.cpp @@ -0,0 +1,214 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + #include +#endif + +namespace Botan { + +/* +* Read a single byte from the DataSource +*/ +size_t DataSource::read_byte(uint8_t& out) + { + return read(&out, 1); + } + +/* +* Peek a single byte from the DataSource +*/ +size_t DataSource::peek_byte(uint8_t& out) const + { + return peek(&out, 1, 0); + } + +/* +* Discard the next N bytes of the data +*/ +size_t DataSource::discard_next(size_t n) + { + uint8_t buf[64] = { 0 }; + size_t discarded = 0; + + while(n) + { + const size_t got = this->read(buf, std::min(n, sizeof(buf))); + discarded += got; + n -= got; + + if(got == 0) + break; + } + + return discarded; + } + +/* +* Read from a memory buffer +*/ +size_t DataSource_Memory::read(uint8_t out[], size_t length) + { + const size_t got = std::min(m_source.size() - m_offset, length); + copy_mem(out, m_source.data() + m_offset, got); + m_offset += got; + return got; + } + +bool DataSource_Memory::check_available(size_t n) + { + return (n <= (m_source.size() - m_offset)); + } + +/* +* Peek into a memory buffer +*/ +size_t DataSource_Memory::peek(uint8_t out[], size_t length, + size_t peek_offset) const + { + const size_t bytes_left = m_source.size() - m_offset; + if(peek_offset >= bytes_left) return 0; + + const size_t got = std::min(bytes_left - peek_offset, length); + copy_mem(out, &m_source[m_offset + peek_offset], got); + return got; + } + +/* +* Check if the memory buffer is empty +*/ +bool DataSource_Memory::end_of_data() const + { + return (m_offset == m_source.size()); + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const std::string& in) : + m_source(cast_char_ptr_to_uint8(in.data()), + cast_char_ptr_to_uint8(in.data()) + in.length()), + m_offset(0) + { + } + +/* +* Read from a stream +*/ +size_t DataSource_Stream::read(uint8_t out[], size_t length) + { + m_source.read(cast_uint8_ptr_to_char(out), length); + if(m_source.bad()) + throw Stream_IO_Error("DataSource_Stream::read: Source failure"); + + const size_t got = static_cast(m_source.gcount()); + m_total_read += got; + return got; + } + +bool DataSource_Stream::check_available(size_t n) + { + const std::streampos orig_pos = m_source.tellg(); + m_source.seekg(0, std::ios::end); + const size_t avail = static_cast(m_source.tellg() - orig_pos); + m_source.seekg(orig_pos); + return (avail >= n); + } + +/* +* Peek into a stream +*/ +size_t DataSource_Stream::peek(uint8_t out[], size_t length, size_t offset) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); + + size_t got = 0; + + if(offset) + { + secure_vector buf(offset); + m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size()); + if(m_source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = static_cast(m_source.gcount()); + } + + if(got == offset) + { + m_source.read(cast_uint8_ptr_to_char(out), length); + if(m_source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = static_cast(m_source.gcount()); + } + + if(m_source.eof()) + m_source.clear(); + m_source.seekg(m_total_read, std::ios::beg); + + return got; + } + +/* +* Check if the stream is empty or in error +*/ +bool DataSource_Stream::end_of_data() const + { + return (!m_source.good()); + } + +/* +* Return a human-readable ID for this stream +*/ +std::string DataSource_Stream::id() const + { + return m_identifier; + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(const std::string& path, + bool use_binary) : + m_identifier(path), + m_source_memory(new std::ifstream(path, use_binary ? std::ios::binary : std::ios::in)), + m_source(*m_source_memory), + m_total_read(0) + { + if(!m_source.good()) + { + throw Stream_IO_Error("DataSource: Failure opening file " + path); + } + } + +#endif + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(std::istream& in, + const std::string& name) : + m_identifier(name), + m_source(in), + m_total_read(0) + { + } + +DataSource_Stream::~DataSource_Stream() + { + // for ~unique_ptr + } + +} diff --git a/comm/third_party/botan/src/lib/utils/data_src.h b/comm/third_party/botan/src/lib/utils/data_src.h new file mode 100644 index 0000000000..09c1bffdf7 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/data_src.h @@ -0,0 +1,181 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DATA_SRC_H_ +#define BOTAN_DATA_SRC_H_ + +#include +#include +#include + +namespace Botan { + +/** +* This class represents an abstract data source object. +*/ +class BOTAN_PUBLIC_API(2,0) DataSource + { + public: + /** + * Read from the source. Moves the internal offset so that every + * call to read will return a new portion of the source. + * + * @param out the byte array to write the result to + * @param length the length of the byte array out + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t read(uint8_t out[], size_t length) BOTAN_WARN_UNUSED_RESULT = 0; + + virtual bool check_available(size_t n) = 0; + + /** + * Read from the source but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the source starting at the same position. + * + * @param out the byte array to write the output to + * @param length the length of the byte array out + * @param peek_offset the offset into the stream to read at + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t peek(uint8_t out[], size_t length, size_t peek_offset) const BOTAN_WARN_UNUSED_RESULT = 0; + + /** + * Test whether the source still has data that can be read. + * @return true if there is no more data to read, false otherwise + */ + virtual bool end_of_data() const = 0; + /** + * return the id of this data source + * @return std::string representing the id of this data source + */ + virtual std::string id() const { return ""; } + + /** + * Read one byte. + * @param out the byte to read to + * @return length in bytes that was actually read and put + * into out + */ + size_t read_byte(uint8_t& out); + + /** + * Peek at one byte. + * @param out an output byte + * @return length in bytes that was actually read and put + * into out + */ + size_t peek_byte(uint8_t& out) const; + + /** + * Discard the next N bytes of the data + * @param N the number of bytes to discard + * @return number of bytes actually discarded + */ + size_t discard_next(size_t N); + + /** + * @return number of bytes read so far. + */ + virtual size_t get_bytes_read() const = 0; + + DataSource() = default; + virtual ~DataSource() = default; + DataSource& operator=(const DataSource&) = delete; + DataSource(const DataSource&) = delete; + }; + +/** +* This class represents a Memory-Based DataSource +*/ +class BOTAN_PUBLIC_API(2,0) DataSource_Memory final : public DataSource + { + public: + size_t read(uint8_t[], size_t) override; + size_t peek(uint8_t[], size_t, size_t) const override; + bool check_available(size_t n) override; + bool end_of_data() const override; + + /** + * Construct a memory source that reads from a string + * @param in the string to read from + */ + explicit DataSource_Memory(const std::string& in); + + /** + * Construct a memory source that reads from a byte array + * @param in the byte array to read from + * @param length the length of the byte array + */ + DataSource_Memory(const uint8_t in[], size_t length) : + m_source(in, in + length), m_offset(0) {} + + /** + * Construct a memory source that reads from a secure_vector + * @param in the MemoryRegion to read from + */ + explicit DataSource_Memory(const secure_vector& in) : + m_source(in), m_offset(0) {} + + /** + * Construct a memory source that reads from a std::vector + * @param in the MemoryRegion to read from + */ + explicit DataSource_Memory(const std::vector& in) : + m_source(in.begin(), in.end()), m_offset(0) {} + + size_t get_bytes_read() const override { return m_offset; } + private: + secure_vector m_source; + size_t m_offset; + }; + +/** +* This class represents a Stream-Based DataSource. +*/ +class BOTAN_PUBLIC_API(2,0) DataSource_Stream final : public DataSource + { + public: + size_t read(uint8_t[], size_t) override; + size_t peek(uint8_t[], size_t, size_t) const override; + bool check_available(size_t n) override; + bool end_of_data() const override; + std::string id() const override; + + DataSource_Stream(std::istream&, + const std::string& id = ""); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Construct a Stream-Based DataSource from filesystem path + * @param file the path to the file + * @param use_binary whether to treat the file as binary or not + */ + DataSource_Stream(const std::string& file, bool use_binary = false); +#endif + + DataSource_Stream(const DataSource_Stream&) = delete; + + DataSource_Stream& operator=(const DataSource_Stream&) = delete; + + ~DataSource_Stream(); + + size_t get_bytes_read() const override { return m_total_read; } + private: + const std::string m_identifier; + + std::unique_ptr m_source_memory; + std::istream& m_source; + size_t m_total_read; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/database.h b/comm/third_party/botan/src/lib/utils/database.h new file mode 100644 index 0000000000..713d4fc59c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/database.h @@ -0,0 +1,88 @@ +/* +* SQL database interface +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SQL_DATABASE_H_ +#define BOTAN_SQL_DATABASE_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) SQL_Database + { + public: + + class BOTAN_PUBLIC_API(2,0) SQL_DB_Error final : public Exception + { + public: + explicit SQL_DB_Error(const std::string& what) : + Exception("SQL database", what), + m_rc(0) + {} + + SQL_DB_Error(const std::string& what, int rc) : + Exception("SQL database", what), + m_rc(rc) + {} + + ErrorType error_type() const noexcept override { return Botan::ErrorType::DatabaseError; } + + int error_code() const noexcept override { return m_rc; } + private: + int m_rc; + }; + + class BOTAN_PUBLIC_API(2,0) Statement + { + public: + /* Bind statement parameters */ + virtual void bind(int column, const std::string& str) = 0; + + virtual void bind(int column, size_t i) = 0; + + virtual void bind(int column, std::chrono::system_clock::time_point time) = 0; + + virtual void bind(int column, const std::vector& blob) = 0; + + virtual void bind(int column, const uint8_t* data, size_t len) = 0; + + /* Get output */ + virtual std::pair get_blob(int column) = 0; + + virtual std::string get_str(int column) = 0; + + virtual size_t get_size_t(int column) = 0; + + /* Run to completion */ + virtual size_t spin() = 0; + + /* Maybe update */ + virtual bool step() = 0; + + virtual ~Statement() = default; + }; + + /* + * Create a new statement for execution. + * Use ?1, ?2, ?3, etc for parameters to set later with bind + */ + virtual std::shared_ptr new_statement(const std::string& base_sql) const = 0; + + virtual size_t row_count(const std::string& table_name) = 0; + + virtual void create_table(const std::string& table_schema) = 0; + + virtual ~SQL_Database() = default; +}; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/donna128.h b/comm/third_party/botan/src/lib/utils/donna128.h new file mode 100644 index 0000000000..ff571906d8 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/donna128.h @@ -0,0 +1,143 @@ +/* +* A minimal 128-bit integer type for curve25519-donna +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CURVE25519_DONNA128_H_ +#define BOTAN_CURVE25519_DONNA128_H_ + +#include + +namespace Botan { + +class donna128 final + { + public: + donna128(uint64_t ll = 0, uint64_t hh = 0) { l = ll; h = hh; } + + donna128(const donna128&) = default; + donna128& operator=(const donna128&) = default; + + friend donna128 operator>>(const donna128& x, size_t shift) + { + donna128 z = x; + if(shift > 0) + { + const uint64_t carry = z.h << (64 - shift); + z.h = (z.h >> shift); + z.l = (z.l >> shift) | carry; + } + return z; + } + + friend donna128 operator<<(const donna128& x, size_t shift) + { + donna128 z = x; + if(shift > 0) + { + const uint64_t carry = z.l >> (64 - shift); + z.l = (z.l << shift); + z.h = (z.h << shift) | carry; + } + return z; + } + + friend uint64_t operator&(const donna128& x, uint64_t mask) + { + return x.l & mask; + } + + uint64_t operator&=(uint64_t mask) + { + h = 0; + l &= mask; + return l; + } + + donna128& operator+=(const donna128& x) + { + l += x.l; + h += x.h; + + const uint64_t carry = (l < x.l); + h += carry; + return *this; + } + + donna128& operator+=(uint64_t x) + { + l += x; + const uint64_t carry = (l < x); + h += carry; + return *this; + } + + uint64_t lo() const { return l; } + uint64_t hi() const { return h; } + private: + uint64_t h = 0, l = 0; + }; + +inline donna128 operator*(const donna128& x, uint64_t y) + { + BOTAN_ARG_CHECK(x.hi() == 0, "High 64 bits of donna128 set to zero during multiply"); + + uint64_t lo = 0, hi = 0; + mul64x64_128(x.lo(), y, &lo, &hi); + return donna128(lo, hi); + } + +inline donna128 operator*(uint64_t y, const donna128& x) + { + return x * y; + } + +inline donna128 operator+(const donna128& x, const donna128& y) + { + donna128 z = x; + z += y; + return z; + } + +inline donna128 operator+(const donna128& x, uint64_t y) + { + donna128 z = x; + z += y; + return z; + } + +inline donna128 operator|(const donna128& x, const donna128& y) + { + return donna128(x.lo() | y.lo(), x.hi() | y.hi()); + } + +inline uint64_t carry_shift(const donna128& a, size_t shift) + { + return (a >> shift).lo(); + } + +inline uint64_t combine_lower(const donna128& a, size_t s1, + const donna128& b, size_t s2) + { + donna128 z = (a >> s1) | (b << s2); + return z.lo(); + } + +#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) +inline uint64_t carry_shift(const uint128_t a, size_t shift) + { + return static_cast(a >> shift); + } + +inline uint64_t combine_lower(const uint128_t a, size_t s1, + const uint128_t b, size_t s2) + { + return static_cast((a >> s1) | (b << s2)); + } +#endif + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.cpp b/comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.cpp new file mode 100644 index 0000000000..b32fe4b3ab --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.cpp @@ -0,0 +1,82 @@ +/* +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + #include +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include +#endif + +namespace Botan { + +namespace { + +void raise_runtime_loader_exception(const std::string& lib_name, + const char* msg) + { + const std::string ex_msg = + "Failed to load " + lib_name + ": " + + (msg ? msg : "Unknown error"); + + throw System_Error(ex_msg, 0); + } + +} + +Dynamically_Loaded_Library::Dynamically_Loaded_Library( + const std::string& library) : + m_lib_name(library), m_lib(nullptr) + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + m_lib = ::dlopen(m_lib_name.c_str(), RTLD_LAZY); + + if(!m_lib) + raise_runtime_loader_exception(m_lib_name, ::dlerror()); + +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + m_lib = ::LoadLibraryA(m_lib_name.c_str()); + + if(!m_lib) + raise_runtime_loader_exception(m_lib_name, "LoadLibrary failed"); +#endif + + if(!m_lib) + raise_runtime_loader_exception(m_lib_name, "Dynamic load not supported"); + } + +Dynamically_Loaded_Library::~Dynamically_Loaded_Library() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + ::dlclose(m_lib); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + ::FreeLibrary((HMODULE)m_lib); +#endif + } + +void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) + { + void* addr = nullptr; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + addr = ::dlsym(m_lib, symbol.c_str()); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + addr = reinterpret_cast(::GetProcAddress((HMODULE)m_lib, symbol.c_str())); +#endif + + if(!addr) + throw Invalid_Argument("Failed to resolve symbol " + symbol + + " in " + m_lib_name); + + return addr; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.h b/comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.h new file mode 100644 index 0000000000..3caf65f277 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/dyn_load/dyn_load.h @@ -0,0 +1,68 @@ +/* +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DYNAMIC_LOADER_H_ +#define BOTAN_DYNAMIC_LOADER_H_ + +#include +#include + +namespace Botan { + +/** +* Represents a DLL or shared object +*/ +class BOTAN_PUBLIC_API(2,0) Dynamically_Loaded_Library final + { + public: + /** + * Load a DLL (or fail with an exception) + * @param lib_name name or path to a library + * + * If you don't use a full path, the search order will be defined + * by whatever the system linker does by default. Always using fully + * qualified pathnames can help prevent code injection attacks (eg + * via manipulation of LD_LIBRARY_PATH on Linux) + */ + Dynamically_Loaded_Library(const std::string& lib_name); + + /** + * Unload the DLL + * @warning Any pointers returned by resolve()/resolve_symbol() + * should not be used after this destructor runs. + */ + ~Dynamically_Loaded_Library(); + + /** + * Load a symbol (or fail with an exception) + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + void* resolve_symbol(const std::string& symbol); + + /** + * Convenience function for casting symbol to the right type + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + template + T resolve(const std::string& symbol) + { + return reinterpret_cast(resolve_symbol(symbol)); + } + + private: + Dynamically_Loaded_Library(const Dynamically_Loaded_Library&); + Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&); + + std::string m_lib_name; + void* m_lib; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/dyn_load/info.txt b/comm/third_party/botan/src/lib/utils/dyn_load/info.txt new file mode 100644 index 0000000000..f20d000246 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/dyn_load/info.txt @@ -0,0 +1,18 @@ + +DYNAMIC_LOADER -> 20160310 + + +load_on dep + + +posix1 +win32 + + + +android -> dl +linux -> dl +solaris -> dl +macos -> dl +hurd -> dl + diff --git a/comm/third_party/botan/src/lib/utils/exceptn.cpp b/comm/third_party/botan/src/lib/utils/exceptn.cpp new file mode 100644 index 0000000000..e6d067f348 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/exceptn.cpp @@ -0,0 +1,183 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +std::string to_string(ErrorType type) + { + switch(type) + { + case ErrorType::Unknown: + return "Unknown"; + case ErrorType::SystemError: + return "SystemError"; + case ErrorType::NotImplemented: + return "NotImplemented"; + case ErrorType::OutOfMemory: + return "OutOfMemory"; + case ErrorType::InternalError: + return "InternalError"; + case ErrorType::IoError: + return "IoError"; + case ErrorType::InvalidObjectState : + return "InvalidObjectState"; + case ErrorType::KeyNotSet: + return "KeyNotSet"; + case ErrorType::InvalidArgument: + return "InvalidArgument"; + case ErrorType::InvalidKeyLength: + return "InvalidKeyLength"; + case ErrorType::InvalidNonceLength: + return "InvalidNonceLength"; + case ErrorType::LookupError: + return "LookupError"; + case ErrorType::EncodingFailure: + return "EncodingFailure"; + case ErrorType::DecodingFailure: + return "DecodingFailure"; + case ErrorType::TLSError: + return "TLSError"; + case ErrorType::HttpError: + return "HttpError"; + case ErrorType::InvalidTag: + return "InvalidTag"; + case ErrorType::RoughtimeError: + return "RoughtimeError"; + case ErrorType::OpenSSLError : + return "OpenSSLError"; + case ErrorType::CommonCryptoError: + return "CommonCryptoError"; + case ErrorType::Pkcs11Error: + return "Pkcs11Error"; + case ErrorType::TPMError: + return "TPMError"; + case ErrorType::DatabaseError: + return "DatabaseError"; + case ErrorType::ZlibError : + return "ZlibError"; + case ErrorType::Bzip2Error: + return "Bzip2Error" ; + case ErrorType::LzmaError: + return "LzmaError"; + } + + // No default case in above switch so compiler warns + return "Unrecognized Botan error"; + } + +Exception::Exception(const std::string& msg) : m_msg(msg) + {} + +Exception::Exception(const std::string& msg, const std::exception& e) : + m_msg(msg + " failed with " + std::string(e.what())) + {} + +Exception::Exception(const char* prefix, const std::string& msg) : + m_msg(std::string(prefix) + " " + msg) + {} + +Invalid_Argument::Invalid_Argument(const std::string& msg) : + Exception(msg) + {} + +Invalid_Argument::Invalid_Argument(const std::string& msg, const std::string& where) : + Exception(msg + " in " + where) + {} + +Invalid_Argument::Invalid_Argument(const std::string& msg, const std::exception& e) : + Exception(msg, e) {} + +Lookup_Error::Lookup_Error(const std::string& type, + const std::string& algo, + const std::string& provider) : + Exception("Unavailable " + type + " " + algo + + (provider.empty() ? std::string("") : (" for provider " + provider))) + {} + +Internal_Error::Internal_Error(const std::string& err) : + Exception("Internal error: " + err) + {} + +Invalid_Key_Length::Invalid_Key_Length(const std::string& name, size_t length) : + Invalid_Argument(name + " cannot accept a key of length " + + std::to_string(length)) + {} + +Invalid_IV_Length::Invalid_IV_Length(const std::string& mode, size_t bad_len) : + Invalid_Argument("IV length " + std::to_string(bad_len) + + " is invalid for " + mode) + {} + +Key_Not_Set::Key_Not_Set(const std::string& algo) : + Invalid_State("Key not set in " + algo) + {} + +Policy_Violation::Policy_Violation(const std::string& err) : + Invalid_State("Policy violation: " + err) {} + +PRNG_Unseeded::PRNG_Unseeded(const std::string& algo) : + Invalid_State("PRNG not seeded: " + algo) + {} + +Algorithm_Not_Found::Algorithm_Not_Found(const std::string& name) : + Lookup_Error("Could not find any algorithm named \"" + name + "\"") + {} + +No_Provider_Found::No_Provider_Found(const std::string& name) : + Exception("Could not find any provider for algorithm named \"" + name + "\"") + {} + +Provider_Not_Found::Provider_Not_Found(const std::string& algo, const std::string& provider) : + Lookup_Error("Could not find provider '" + provider + "' for " + algo) + {} + +Invalid_Algorithm_Name::Invalid_Algorithm_Name(const std::string& name): + Invalid_Argument("Invalid algorithm name: " + name) + {} + +Encoding_Error::Encoding_Error(const std::string& name) : + Invalid_Argument("Encoding error: " + name) + {} + +Decoding_Error::Decoding_Error(const std::string& name) : + Invalid_Argument(name) + {} + +Decoding_Error::Decoding_Error(const std::string& msg, const std::exception& e) : + Invalid_Argument(msg, e) + {} + +Decoding_Error::Decoding_Error(const std::string& name, const char* exception_message) : + Invalid_Argument(name + " failed with exception " + exception_message) {} + +Invalid_Authentication_Tag::Invalid_Authentication_Tag(const std::string& msg) : + Exception("Invalid authentication tag: " + msg) + {} + +Invalid_OID::Invalid_OID(const std::string& oid) : + Decoding_Error("Invalid ASN.1 OID: " + oid) + {} + +Stream_IO_Error::Stream_IO_Error(const std::string& err) : + Exception("I/O error: " + err) + {} + +System_Error::System_Error(const std::string& msg, int err_code) : + Exception(msg + " error code " + std::to_string(err_code)), + m_error_code(err_code) + {} + +Self_Test_Failure::Self_Test_Failure(const std::string& err) : + Internal_Error("Self test failed: " + err) + {} + +Not_Implemented::Not_Implemented(const std::string& err) : + Exception("Not implemented", err) + {} + +} diff --git a/comm/third_party/botan/src/lib/utils/exceptn.h b/comm/third_party/botan/src/lib/utils/exceptn.h new file mode 100644 index 0000000000..442ec91e6e --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/exceptn.h @@ -0,0 +1,441 @@ +/* +* Exceptions +* (C) 1999-2009,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EXCEPTION_H_ +#define BOTAN_EXCEPTION_H_ + +#include +#include +#include + +namespace Botan { + +/** +* Different types of errors that might occur +*/ +enum class ErrorType { + /** Some unknown error */ + Unknown = 1, + /** An error while calling a system interface */ + SystemError, + /** An operation seems valid, but not supported by the current version */ + NotImplemented, + /** Memory allocation failure */ + OutOfMemory, + /** An internal error occurred */ + InternalError, + /** An I/O error occurred */ + IoError, + + /** Invalid object state */ + InvalidObjectState = 100, + /** A key was not set on an object when this is required */ + KeyNotSet, + /** The application provided an argument which is invalid */ + InvalidArgument, + /** A key with invalid length was provided */ + InvalidKeyLength, + /** A nonce with invalid length was provided */ + InvalidNonceLength, + /** An object type was requested but cannot be found */ + LookupError, + /** Encoding a message or datum failed */ + EncodingFailure, + /** Decoding a message or datum failed */ + DecodingFailure, + /** A TLS error (error_code will be the alert type) */ + TLSError, + /** An error during an HTTP operation */ + HttpError, + /** A message with an invalid authentication tag was detected */ + InvalidTag, + /** An error during Roughtime validation */ + RoughtimeError, + + /** An error when calling OpenSSL */ + OpenSSLError = 200, + /** An error when interacting with CommonCrypto API */ + CommonCryptoError, + /** An error when interacting with a PKCS11 device */ + Pkcs11Error, + /** An error when interacting with a TPM device */ + TPMError, + /** An error when interacting with a database */ + DatabaseError, + + /** An error when interacting with zlib */ + ZlibError = 300, + /** An error when interacting with bzip2 */ + Bzip2Error, + /** An error when interacting with lzma */ + LzmaError, + +}; + +//! \brief Convert an ErrorType to string +std::string BOTAN_PUBLIC_API(2,11) to_string(ErrorType type); + +/** +* Base class for all exceptions thrown by the library +*/ +class BOTAN_PUBLIC_API(2,0) Exception : public std::exception + { + public: + /** + * Return a descriptive string which is hopefully comprehensible to + * a developer. It will likely not be useful for an end user. + * + * The string has no particular format, and the content of exception + * messages may change from release to release. Thus the main use of this + * function is for logging or debugging. + */ + const char* what() const noexcept override { return m_msg.c_str(); } + + /** + * Return the "type" of error which occurred. + */ + virtual ErrorType error_type() const noexcept { return Botan::ErrorType::Unknown; } + + /** + * Return an error code associated with this exception, or otherwise 0. + * + * The domain of this error varies depending on the source, for example on + * POSIX systems it might be errno, while on a Windows system it might be + * the result of GetLastError or WSAGetLastError. For error_type() is + * OpenSSLError, it will (if nonzero) be an OpenSSL error code from + * ERR_get_error. + */ + virtual int error_code() const noexcept { return 0; } + + /** + * Avoid throwing base Exception, use a subclass + */ + explicit Exception(const std::string& msg); + + /** + * Avoid throwing base Exception, use a subclass + */ + Exception(const char* prefix, const std::string& msg); + + /** + * Avoid throwing base Exception, use a subclass + */ + Exception(const std::string& msg, const std::exception& e); + + private: + std::string m_msg; + }; + +/** +* An invalid argument was provided to an API call. +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Argument : public Exception + { + public: + explicit Invalid_Argument(const std::string& msg); + + explicit Invalid_Argument(const std::string& msg, const std::string& where); + + Invalid_Argument(const std::string& msg, const std::exception& e); + + ErrorType error_type() const noexcept override { return ErrorType::InvalidArgument; } + }; + +/** +* An invalid key length was used +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Key_Length final : public Invalid_Argument + { + public: + Invalid_Key_Length(const std::string& name, size_t length); + ErrorType error_type() const noexcept override { return ErrorType::InvalidKeyLength; } + }; + +/** +* An invalid nonce length was used +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_IV_Length final : public Invalid_Argument + { + public: + Invalid_IV_Length(const std::string& mode, size_t bad_len); + ErrorType error_type() const noexcept override { return ErrorType::InvalidNonceLength; } + }; + +/** +* Invalid_Algorithm_Name Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Algorithm_Name final : public Invalid_Argument + { + public: + explicit Invalid_Algorithm_Name(const std::string& name); + }; + +/** +* Encoding_Error Exception +* +* This exception derives from Invalid_Argument for historical reasons, and it +* does not make any real sense for it to do so. In a future major release this +* exception type will derive directly from Exception instead. +*/ +class BOTAN_PUBLIC_API(2,0) Encoding_Error final : public Invalid_Argument + { + public: + explicit Encoding_Error(const std::string& name); + + ErrorType error_type() const noexcept override { return ErrorType::EncodingFailure; } + }; + +/** +* A decoding error occurred. +* +* This exception derives from Invalid_Argument for historical reasons, and it +* does not make any real sense for it to do so. In a future major release this +* exception type will derive directly from Exception instead. +*/ +class BOTAN_PUBLIC_API(2,0) Decoding_Error : public Invalid_Argument + { + public: + explicit Decoding_Error(const std::string& name); + + Decoding_Error(const std::string& name, const char* exception_message); + + Decoding_Error(const std::string& msg, const std::exception& e); + + ErrorType error_type() const noexcept override { return ErrorType::DecodingFailure; } + }; + +/** +* Invalid state was encountered. A request was made on an object while the +* object was in a state where the operation cannot be performed. +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_State : public Exception + { + public: + explicit Invalid_State(const std::string& err) : Exception(err) {} + + ErrorType error_type() const noexcept override { return ErrorType::InvalidObjectState; } + }; + +/** +* A PRNG was called on to produce output while still unseeded +*/ +class BOTAN_PUBLIC_API(2,0) PRNG_Unseeded final : public Invalid_State + { + public: + explicit PRNG_Unseeded(const std::string& algo); + }; + +/** +* The key was not set on an object. This occurs with symmetric objects where +* an operation which requires the key is called prior to set_key being called. +*/ +class BOTAN_PUBLIC_API(2,4) Key_Not_Set : public Invalid_State + { + public: + explicit Key_Not_Set(const std::string& algo); + + ErrorType error_type() const noexcept override { return ErrorType::KeyNotSet; } + }; + +/** +* A request was made for some kind of object which could not be located +*/ +class BOTAN_PUBLIC_API(2,0) Lookup_Error : public Exception + { + public: + explicit Lookup_Error(const std::string& err) : Exception(err) {} + + Lookup_Error(const std::string& type, + const std::string& algo, + const std::string& provider); + + ErrorType error_type() const noexcept override { return ErrorType::LookupError; } + }; + +/** +* Algorithm_Not_Found Exception +* +* @warning This exception type will be removed in the future. Instead +* just catch Lookup_Error. +*/ +class BOTAN_PUBLIC_API(2,0) Algorithm_Not_Found final : public Lookup_Error + { + public: + explicit Algorithm_Not_Found(const std::string& name); + }; + +/** +* Provider_Not_Found is thrown when a specific provider was requested +* but that provider is not available. +* +* @warning This exception type will be removed in the future. Instead +* just catch Lookup_Error. +*/ +class BOTAN_PUBLIC_API(2,0) Provider_Not_Found final : public Lookup_Error + { + public: + Provider_Not_Found(const std::string& algo, const std::string& provider); + }; + +/** +* An AEAD or MAC check detected a message modification +* +* In versions before 2.10, Invalid_Authentication_Tag was named +* Integrity_Failure, it was renamed to make its usage more clear. +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Authentication_Tag final : public Exception + { + public: + explicit Invalid_Authentication_Tag(const std::string& msg); + + ErrorType error_type() const noexcept override { return ErrorType::InvalidTag; } + }; + +/** +* For compatability with older versions +*/ +typedef Invalid_Authentication_Tag Integrity_Failure; + +/** +* An error occurred while operating on an IO stream +*/ +class BOTAN_PUBLIC_API(2,0) Stream_IO_Error final : public Exception + { + public: + explicit Stream_IO_Error(const std::string& err); + + ErrorType error_type() const noexcept override { return ErrorType::IoError; } + }; + +/** +* System_Error +* +* This exception is thrown in the event of an error related to interacting +* with the operating system. +* +* This exception type also (optionally) captures an integer error code eg +* POSIX errno or Windows GetLastError. +*/ +class BOTAN_PUBLIC_API(2,9) System_Error : public Exception + { + public: + System_Error(const std::string& msg) : Exception(msg), m_error_code(0) {} + + System_Error(const std::string& msg, int err_code); + + ErrorType error_type() const noexcept override { return ErrorType::SystemError; } + + int error_code() const noexcept override { return m_error_code; } + + private: + int m_error_code; + }; + +/** +* An internal error occurred. If observed, please file a bug. +*/ +class BOTAN_PUBLIC_API(2,0) Internal_Error : public Exception + { + public: + explicit Internal_Error(const std::string& err); + + ErrorType error_type() const noexcept override { return ErrorType::InternalError; } + }; + +/** +* Not Implemented Exception +* +* This is thrown in the situation where a requested operation is +* logically valid but is not implemented by this version of the library. +*/ +class BOTAN_PUBLIC_API(2,0) Not_Implemented final : public Exception + { + public: + explicit Not_Implemented(const std::string& err); + + ErrorType error_type() const noexcept override { return ErrorType::NotImplemented; } + }; + +/* + The following exception types are still in use for compatability reasons, + but are deprecated and will be removed in a future major release. + Instead catch the base class. +*/ + +/** +* An invalid OID string was used. +* +* This exception will be removed in a future major release. +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_OID final : public Decoding_Error + { + public: + explicit Invalid_OID(const std::string& oid); + }; + +/* + The following exception types are deprecated, no longer used, + and will be removed in a future major release +*/ + +/** +* Self Test Failure Exception +* +* This exception is no longer used. It will be removed in a future major release. +*/ +class BOTAN_PUBLIC_API(2,0) Self_Test_Failure final : public Internal_Error + { + public: + BOTAN_DEPRECATED("no longer used") explicit Self_Test_Failure(const std::string& err); + }; + +/** +* No_Provider_Found Exception +* +* This exception is no longer used. It will be removed in a future major release. +*/ +class BOTAN_PUBLIC_API(2,0) No_Provider_Found final : public Exception + { + public: + BOTAN_DEPRECATED("no longer used") explicit No_Provider_Found(const std::string& name); + }; + +/** +* Policy_Violation Exception +* +* This exception is no longer used. It will be removed in a future major release. +*/ +class BOTAN_PUBLIC_API(2,0) Policy_Violation final : public Invalid_State + { + public: + BOTAN_DEPRECATED("no longer used") explicit Policy_Violation(const std::string& err); + }; + +/** +* Unsupported_Argument Exception +* +* An argument that is invalid because it is not supported by Botan. +* It might or might not be valid in another context like a standard. +* +* This exception is no longer used, instead Not_Implemented is thrown. +* It will be removed in a future major release. +*/ +class BOTAN_PUBLIC_API(2,0) Unsupported_Argument final : public Invalid_Argument + { + public: + BOTAN_DEPRECATED("no longer used") explicit Unsupported_Argument(const std::string& msg) : Invalid_Argument(msg) {} + }; + +template +inline void do_throw_error(const char* file, int line, const char* func, Args... args) + { + throw E(file, line, func, args...); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/filesystem.cpp b/comm/third_party/botan/src/lib/utils/filesystem.cpp new file mode 100644 index 0000000000..3072a304f2 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/filesystem.cpp @@ -0,0 +1,144 @@ +/* +* (C) 2015,2017,2019 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + #include + #include + #include + #include +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + +std::vector impl_readdir(const std::string& dir_path) + { + std::vector out; + std::deque dir_list; + dir_list.push_back(dir_path); + + while(!dir_list.empty()) + { + const std::string cur_path = dir_list[0]; + dir_list.pop_front(); + + std::unique_ptr> dir(::opendir(cur_path.c_str()), ::closedir); + + if(dir) + { + while(struct dirent* dirent = ::readdir(dir.get())) + { + const std::string filename = dirent->d_name; + if(filename == "." || filename == "..") + continue; + const std::string full_path = cur_path + "/" + filename; + + struct stat stat_buf; + + if(::stat(full_path.c_str(), &stat_buf) == -1) + continue; + + if(S_ISDIR(stat_buf.st_mode)) + dir_list.push_back(full_path); + else if(S_ISREG(stat_buf.st_mode)) + out.push_back(full_path); + } + } + } + + return out; + } + +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + +std::vector impl_win32(const std::string& dir_path) + { + std::vector out; + std::deque dir_list; + dir_list.push_back(dir_path); + + while(!dir_list.empty()) + { + const std::string cur_path = dir_list[0]; + dir_list.pop_front(); + + WIN32_FIND_DATAA find_data; + HANDLE dir = ::FindFirstFileA((cur_path + "/*").c_str(), &find_data); + + if(dir != INVALID_HANDLE_VALUE) + { + do + { + const std::string filename = find_data.cFileName; + if(filename == "." || filename == "..") + continue; + const std::string full_path = cur_path + "/" + filename; + + if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + dir_list.push_back(full_path); + } + else + { + out.push_back(full_path); + } + } + while(::FindNextFileA(dir, &find_data)); + } + + ::FindClose(dir); + } + + return out; +} +#endif + +} + +bool has_filesystem_impl() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + return true; +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + return true; +#else + return false; +#endif + } + +std::vector get_files_recursive(const std::string& dir) + { + std::vector files; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + files = impl_readdir(dir); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + files = impl_win32(dir); +#else + BOTAN_UNUSED(dir); + throw No_Filesystem_Access(); +#endif + + std::sort(files.begin(), files.end()); + + return files; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/filesystem.h b/comm/third_party/botan/src/lib/utils/filesystem.h new file mode 100644 index 0000000000..382da7de34 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/filesystem.h @@ -0,0 +1,33 @@ +/* +* (C) 2015 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_FILESYSTEM_H_ +#define BOTAN_UTIL_FILESYSTEM_H_ + +#include +#include +#include + +namespace Botan { + +/** +* No_Filesystem_Access Exception +*/ +class BOTAN_PUBLIC_API(2,0) No_Filesystem_Access final : public Exception + { + public: + No_Filesystem_Access() : Exception("No filesystem access enabled.") + {} + }; + +BOTAN_TEST_API bool has_filesystem_impl(); + +BOTAN_TEST_API std::vector get_files_recursive(const std::string& dir); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/ghash/ghash.cpp b/comm/third_party/botan/src/lib/utils/ghash/ghash.cpp new file mode 100644 index 0000000000..e24f5e02ca --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/ghash.cpp @@ -0,0 +1,236 @@ +/* +* GCM GHASH +* (C) 2013,2015,2017 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +std::string GHASH::provider() const + { +#if defined(BOTAN_HAS_GHASH_CLMUL_CPU) + if(CPUID::has_carryless_multiply()) + return "clmul"; +#endif + +#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) + if(CPUID::has_vperm()) + return "vperm"; +#endif + + return "base"; + } + +void GHASH::ghash_multiply(secure_vector& x, + const uint8_t input[], + size_t blocks) + { +#if defined(BOTAN_HAS_GHASH_CLMUL_CPU) + if(CPUID::has_carryless_multiply()) + { + return ghash_multiply_cpu(x.data(), m_H_pow.data(), input, blocks); + } +#endif + +#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) + if(CPUID::has_vperm()) + { + return ghash_multiply_vperm(x.data(), m_HM.data(), input, blocks); + } +#endif + + CT::poison(x.data(), x.size()); + + const uint64_t ALL_BITS = 0xFFFFFFFFFFFFFFFF; + + uint64_t X[2] = { + load_be(x.data(), 0), + load_be(x.data(), 1) + }; + + for(size_t b = 0; b != blocks; ++b) + { + X[0] ^= load_be(input, 2*b); + X[1] ^= load_be(input, 2*b+1); + + uint64_t Z[2] = { 0, 0 }; + + for(size_t i = 0; i != 64; ++i) + { + const uint64_t X0MASK = (ALL_BITS + (X[0] >> 63)) ^ ALL_BITS; + const uint64_t X1MASK = (ALL_BITS + (X[1] >> 63)) ^ ALL_BITS; + + X[0] <<= 1; + X[1] <<= 1; + + Z[0] ^= m_HM[4*i ] & X0MASK; + Z[1] ^= m_HM[4*i+1] & X0MASK; + Z[0] ^= m_HM[4*i+2] & X1MASK; + Z[1] ^= m_HM[4*i+3] & X1MASK; + } + + X[0] = Z[0]; + X[1] = Z[1]; + } + + store_be(x.data(), X[0], X[1]); + CT::unpoison(x.data(), x.size()); + } + +void GHASH::ghash_update(secure_vector& ghash, + const uint8_t input[], size_t length) + { + verify_key_set(!m_HM.empty()); + + /* + This assumes if less than block size input then we're just on the + final block and should pad with zeros + */ + + const size_t full_blocks = length / GCM_BS; + const size_t final_bytes = length - (full_blocks * GCM_BS); + + if(full_blocks > 0) + { + ghash_multiply(ghash, input, full_blocks); + } + + if(final_bytes) + { + uint8_t last_block[GCM_BS] = { 0 }; + copy_mem(last_block, input + full_blocks * GCM_BS, final_bytes); + ghash_multiply(ghash, last_block, 1); + secure_scrub_memory(last_block, final_bytes); + } + } + +void GHASH::key_schedule(const uint8_t key[], size_t length) + { + m_H.assign(key, key+length); + m_H_ad.resize(GCM_BS); + m_ad_len = 0; + m_text_len = 0; + + uint64_t H0 = load_be(m_H.data(), 0); + uint64_t H1 = load_be(m_H.data(), 1); + + const uint64_t R = 0xE100000000000000; + + m_HM.resize(256); + + // precompute the multiples of H + for(size_t i = 0; i != 2; ++i) + { + for(size_t j = 0; j != 64; ++j) + { + /* + we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68 + to make indexing nicer in the multiplication code + */ + m_HM[4*j+2*i] = H0; + m_HM[4*j+2*i+1] = H1; + + // GCM's bit ops are reversed so we carry out of the bottom + const uint64_t carry = R * (H1 & 1); + H1 = (H1 >> 1) | (H0 << 63); + H0 = (H0 >> 1) ^ carry; + } + } + +#if defined(BOTAN_HAS_GHASH_CLMUL_CPU) + if(CPUID::has_carryless_multiply()) + { + m_H_pow.resize(8); + ghash_precompute_cpu(m_H.data(), m_H_pow.data()); + } +#endif + } + +void GHASH::start(const uint8_t nonce[], size_t len) + { + BOTAN_ARG_CHECK(len == 16, "GHASH requires a 128-bit nonce"); + m_nonce.assign(nonce, nonce + len); + m_ghash = m_H_ad; + } + +void GHASH::set_associated_data(const uint8_t input[], size_t length) + { + if(m_ghash.empty() == false) + throw Invalid_State("Too late to set AD in GHASH"); + + zeroise(m_H_ad); + + ghash_update(m_H_ad, input, length); + m_ad_len = length; + } + +void GHASH::update_associated_data(const uint8_t ad[], size_t length) + { + verify_key_set(m_ghash.size() == GCM_BS); + m_ad_len += length; + ghash_update(m_ghash, ad, length); + } + +void GHASH::update(const uint8_t input[], size_t length) + { + verify_key_set(m_ghash.size() == GCM_BS); + m_text_len += length; + ghash_update(m_ghash, input, length); + } + +void GHASH::add_final_block(secure_vector& hash, + size_t ad_len, size_t text_len) + { + /* + * stack buffer is fine here since the text len is public + * and the length of the AD is probably not sensitive either. + */ + uint8_t final_block[GCM_BS]; + store_be(final_block, 8*ad_len, 8*text_len); + ghash_update(hash, final_block, GCM_BS); + } + +void GHASH::final(uint8_t mac[], size_t mac_len) + { + BOTAN_ARG_CHECK(mac_len > 0 && mac_len <= 16, "GHASH output length"); + add_final_block(m_ghash, m_ad_len, m_text_len); + + for(size_t i = 0; i != mac_len; ++i) + mac[i] = m_ghash[i] ^ m_nonce[i]; + + m_ghash.clear(); + m_text_len = 0; + } + +void GHASH::nonce_hash(secure_vector& y0, const uint8_t nonce[], size_t nonce_len) + { + BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time"); + + ghash_update(y0, nonce, nonce_len); + add_final_block(y0, 0, nonce_len); + } + +void GHASH::clear() + { + zap(m_H); + zap(m_HM); + reset(); + } + +void GHASH::reset() + { + zeroise(m_H_ad); + m_ghash.clear(); + m_nonce.clear(); + m_text_len = m_ad_len = 0; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/ghash/ghash.h b/comm/third_party/botan/src/lib/utils/ghash/ghash.h new file mode 100644 index 0000000000..062a04b84b --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/ghash.h @@ -0,0 +1,110 @@ +/* +* (C) 2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_GCM_GHASH_H_ +#define BOTAN_GCM_GHASH_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(ghash.h) + +namespace Botan { + +/** +* GCM's GHASH +* This is not intended for general use, but is exposed to allow +* shared code between GCM and GMAC +*/ +class BOTAN_PUBLIC_API(2,0) GHASH final : public SymmetricAlgorithm + { + public: + void set_associated_data(const uint8_t ad[], size_t ad_len); + + secure_vector BOTAN_DEPRECATED("Use other impl") + nonce_hash(const uint8_t nonce[], size_t nonce_len) + { + secure_vector y0(GCM_BS); + nonce_hash(y0, nonce, nonce_len); + return y0; + } + + void nonce_hash(secure_vector& y0, const uint8_t nonce[], size_t len); + + void start(const uint8_t nonce[], size_t len); + + /* + * Assumes input len is multiple of 16 + */ + void update(const uint8_t in[], size_t len); + + /* + * Incremental update of associated data + */ + void update_associated_data(const uint8_t ad[], size_t len); + + secure_vector BOTAN_DEPRECATED("Use version taking output params") final() + { + secure_vector mac(GCM_BS); + final(mac.data(), mac.size()); + return mac; + } + + void final(uint8_t out[], size_t out_len); + + Key_Length_Specification key_spec() const override + { return Key_Length_Specification(16); } + + void clear() override; + + void reset(); + + std::string name() const override { return "GHASH"; } + + std::string provider() const; + + void ghash_update(secure_vector& x, + const uint8_t input[], size_t input_len); + + void add_final_block(secure_vector& x, + size_t ad_len, size_t pt_len); + private: + +#if defined(BOTAN_HAS_GHASH_CLMUL_CPU) + static void ghash_precompute_cpu(const uint8_t H[16], uint64_t H_pow[4*2]); + + static void ghash_multiply_cpu(uint8_t x[16], + const uint64_t H_pow[4*2], + const uint8_t input[], size_t blocks); +#endif + +#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) + static void ghash_multiply_vperm(uint8_t x[16], + const uint64_t HM[256], + const uint8_t input[], size_t blocks); +#endif + + void key_schedule(const uint8_t key[], size_t key_len) override; + + void ghash_multiply(secure_vector& x, + const uint8_t input[], + size_t blocks); + + static const size_t GCM_BS = 16; + + secure_vector m_H; + secure_vector m_H_ad; + secure_vector m_ghash; + secure_vector m_nonce; + secure_vector m_HM; + secure_vector m_H_pow; + size_t m_ad_len = 0; + size_t m_text_len = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/ghash_cpu.cpp b/comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/ghash_cpu.cpp new file mode 100644 index 0000000000..5d725933d9 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/ghash_cpu.cpp @@ -0,0 +1,207 @@ +/* +* Hook for CLMUL/PMULL/VPMSUM +* (C) 2013,2017,2019,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#if defined(BOTAN_SIMD_USE_SSE2) + #include + #include +#endif + +namespace Botan { + +namespace { + +BOTAN_FORCE_INLINE SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) reverse_vector(const SIMD_4x32& in) + { +#if defined(BOTAN_SIMD_USE_SSE2) + const __m128i BSWAP_MASK = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + return SIMD_4x32(_mm_shuffle_epi8(in.raw(), BSWAP_MASK)); +#elif defined(BOTAN_SIMD_USE_NEON) + const uint8_t maskb[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + const uint8x16_t mask = vld1q_u8(maskb); + return SIMD_4x32(vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(in.raw()), mask))); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const __vector unsigned char mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return SIMD_4x32(vec_perm(in.raw(), in.raw(), mask)); +#endif + } + +template +BOTAN_FORCE_INLINE SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_CLMUL_ISA) clmul(const SIMD_4x32& H, const SIMD_4x32& x) + { + static_assert(M == 0x00 || M == 0x01 || M == 0x10 || M == 0x11, "Valid clmul mode"); + +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_clmulepi64_si128(x.raw(), H.raw(), M)); +#elif defined(BOTAN_SIMD_USE_NEON) + const uint64_t a = vgetq_lane_u64(vreinterpretq_u64_u32(x.raw()), M & 0x01); + const uint64_t b = vgetq_lane_u64(vreinterpretq_u64_u32(H.raw()), (M & 0x10) >> 4); + return SIMD_4x32(reinterpret_cast(vmull_p64(a, b))); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const SIMD_4x32 mask_lo = SIMD_4x32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF); + + SIMD_4x32 i1 = x; + SIMD_4x32 i2 = H; + + if(M == 0x11) + { + i1 &= mask_lo; + i2 &= mask_lo; + } + else if(M == 0x10) + { + i1 = i1.shift_elems_left<2>(); + } + else if(M == 0x01) + { + i2 = i2.shift_elems_left<2>(); + } + else if(M == 0x00) + { + i1 = mask_lo.andc(i1); + i2 = mask_lo.andc(i2); + } + + auto i1v = reinterpret_cast<__vector unsigned long long>(i1.raw()); + auto i2v = reinterpret_cast<__vector unsigned long long>(i2.raw()); + +#if defined(__clang__) + auto rv = __builtin_altivec_crypto_vpmsumd(i1v, i2v); +#else + auto rv = __builtin_crypto_vpmsumd(i1v, i2v); +#endif + + return SIMD_4x32(reinterpret_cast<__vector unsigned int>(rv)); +#endif + } + +inline SIMD_4x32 gcm_reduce(const SIMD_4x32& B0, const SIMD_4x32& B1) + { + SIMD_4x32 X0 = B1.shr<31>(); + SIMD_4x32 X1 = B1.shl<1>(); + SIMD_4x32 X2 = B0.shr<31>(); + SIMD_4x32 X3 = B0.shl<1>(); + + X3 |= X0.shift_elems_right<3>(); + X3 |= X2.shift_elems_left<1>(); + X1 |= X0.shift_elems_left<1>(); + + X0 = X1.shl<31>() ^ X1.shl<30>() ^ X1.shl<25>(); + + X1 ^= X0.shift_elems_left<3>(); + + X0 = X1 ^ X3 ^ X0.shift_elems_right<1>(); + X0 ^= X1.shr<7>() ^ X1.shr<2>() ^ X1.shr<1>(); + return X0; + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_CLMUL_ISA) gcm_multiply(const SIMD_4x32& H, const SIMD_4x32& x) + { + SIMD_4x32 T0 = clmul<0x11>(H, x); + SIMD_4x32 T1 = clmul<0x10>(H, x); + SIMD_4x32 T2 = clmul<0x01>(H, x); + SIMD_4x32 T3 = clmul<0x00>(H, x); + + T1 ^= T2; + T0 ^= T1.shift_elems_right<2>(); + T3 ^= T1.shift_elems_left<2>(); + + return gcm_reduce(T0, T3); + } + +inline SIMD_4x32 BOTAN_FUNC_ISA(BOTAN_CLMUL_ISA) + gcm_multiply_x4(const SIMD_4x32& H1, const SIMD_4x32& H2, const SIMD_4x32& H3, const SIMD_4x32& H4, + const SIMD_4x32& X1, const SIMD_4x32& X2, const SIMD_4x32& X3, const SIMD_4x32& X4) + { + /* + * Mutiply with delayed reduction, algorithm by Krzysztof Jankowski + * and Pierre Laurent of Intel + */ + + const SIMD_4x32 lo = (clmul<0x00>(H1, X1) ^ clmul<0x00>(H2, X2)) ^ + (clmul<0x00>(H3, X3) ^ clmul<0x00>(H4, X4)); + + const SIMD_4x32 hi = (clmul<0x11>(H1, X1) ^ clmul<0x11>(H2, X2)) ^ + (clmul<0x11>(H3, X3) ^ clmul<0x11>(H4, X4)); + + SIMD_4x32 T; + + T ^= clmul<0x00>(H1 ^ H1.shift_elems_right<2>(), X1 ^ X1.shift_elems_right<2>()); + T ^= clmul<0x00>(H2 ^ H2.shift_elems_right<2>(), X2 ^ X2.shift_elems_right<2>()); + T ^= clmul<0x00>(H3 ^ H3.shift_elems_right<2>(), X3 ^ X3.shift_elems_right<2>()); + T ^= clmul<0x00>(H4 ^ H4.shift_elems_right<2>(), X4 ^ X4.shift_elems_right<2>()); + T ^= lo; + T ^= hi; + + return gcm_reduce(hi ^ T.shift_elems_right<2>(), + lo ^ T.shift_elems_left<2>()); + } + +} + +BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) +void GHASH::ghash_precompute_cpu(const uint8_t H_bytes[16], uint64_t H_pow[4*2]) + { + const SIMD_4x32 H1 = reverse_vector(SIMD_4x32::load_le(H_bytes)); + const SIMD_4x32 H2 = gcm_multiply(H1, H1); + const SIMD_4x32 H3 = gcm_multiply(H1, H2); + const SIMD_4x32 H4 = gcm_multiply(H2, H2); + + H1.store_le(H_pow); + H2.store_le(H_pow + 2); + H3.store_le(H_pow + 4); + H4.store_le(H_pow + 6); + } + +BOTAN_FUNC_ISA(BOTAN_VPERM_ISA) +void GHASH::ghash_multiply_cpu(uint8_t x[16], + const uint64_t H_pow[8], + const uint8_t input[], size_t blocks) + { + /* + * Algorithms 1 and 5 from Intel's CLMUL guide + */ + const SIMD_4x32 H1 = SIMD_4x32::load_le(H_pow); + + SIMD_4x32 a = reverse_vector(SIMD_4x32::load_le(x)); + + if(blocks >= 4) + { + const SIMD_4x32 H2 = SIMD_4x32::load_le(H_pow + 2); + const SIMD_4x32 H3 = SIMD_4x32::load_le(H_pow + 4); + const SIMD_4x32 H4 = SIMD_4x32::load_le(H_pow + 6); + + while(blocks >= 4) + { + const SIMD_4x32 m0 = reverse_vector(SIMD_4x32::load_le(input )); + const SIMD_4x32 m1 = reverse_vector(SIMD_4x32::load_le(input + 16*1)); + const SIMD_4x32 m2 = reverse_vector(SIMD_4x32::load_le(input + 16*2)); + const SIMD_4x32 m3 = reverse_vector(SIMD_4x32::load_le(input + 16*3)); + + a ^= m0; + a = gcm_multiply_x4(H1, H2, H3, H4, m3, m2, m1, a); + + input += 4*16; + blocks -= 4; + } + } + + for(size_t i = 0; i != blocks; ++i) + { + const SIMD_4x32 m = reverse_vector(SIMD_4x32::load_le(input + 16*i)); + + a ^= m; + a = gcm_multiply(H1, a); + } + + a = reverse_vector(a); + a.store_le(x); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/info.txt b/comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/info.txt new file mode 100644 index 0000000000..1f56377a29 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/ghash_cpu/info.txt @@ -0,0 +1,34 @@ + +GHASH_CLMUL_CPU -> 20201002 + + +endian little + + +simd + + + +x86_32:sse2 +x86_32:ssse3 +x86_32:aesni +x86_64:sse2 +x86_64:ssse3 +x86_64:aesni +arm64:neon +arm64:armv8crypto +ppc64:powercrypto + + + +x86_32 +x86_64 +arm64 +ppc64 + + + +gcc:4.9 +clang:3.8 +msvc + diff --git a/comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/ghash_vperm.cpp b/comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/ghash_vperm.cpp new file mode 100644 index 0000000000..f6f342cb9e --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/ghash_vperm.cpp @@ -0,0 +1,62 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +// TODO: extend this to support NEON and AltiVec + +BOTAN_FUNC_ISA("ssse3") +void GHASH::ghash_multiply_vperm(uint8_t x[16], + const uint64_t HM[256], + const uint8_t input_bytes[], size_t blocks) + { + const __m128i BSWAP_MASK = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + + const __m128i* HM_mm = reinterpret_cast(HM); + + __m128i X = _mm_loadu_si128(reinterpret_cast<__m128i*>(x)); + X = _mm_shuffle_epi8(X, BSWAP_MASK); + + const __m128i ones = _mm_set1_epi8(-1); + + for(size_t b = 0; b != blocks; ++b) + { + __m128i M = _mm_loadu_si128(reinterpret_cast(input_bytes) + b); + M = _mm_shuffle_epi8(M, BSWAP_MASK); + + X = _mm_xor_si128(X, M); + + __m128i Z = _mm_setzero_si128(); + + for(size_t i = 0; i != 64; i += 2) + { + const __m128i HM0 = _mm_loadu_si128(HM_mm + 2*i); + const __m128i HM1 = _mm_loadu_si128(HM_mm + 2*i + 1); + const __m128i HM2 = _mm_loadu_si128(HM_mm + 2*i + 2); + const __m128i HM3 = _mm_loadu_si128(HM_mm + 2*i + 3); + + const __m128i XMASK1 = _mm_add_epi64(_mm_srli_epi64(X, 63), ones); + X = _mm_slli_epi64(X, 1); + const __m128i XMASK2 = _mm_add_epi64(_mm_srli_epi64(X, 63), ones); + X = _mm_slli_epi64(X, 1); + + Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpackhi_epi64(XMASK1, XMASK1), HM0)); + Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpacklo_epi64(XMASK1, XMASK1), HM1)); + Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpackhi_epi64(XMASK2, XMASK2), HM2)); + Z = _mm_xor_si128(Z, _mm_andnot_si128(_mm_unpacklo_epi64(XMASK2, XMASK2), HM3)); + } + + X = _mm_shuffle_epi32(Z, _MM_SHUFFLE(1, 0, 3, 2)); + } + + X = _mm_shuffle_epi8(X, BSWAP_MASK); + _mm_storeu_si128(reinterpret_cast<__m128i*>(x), X); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/info.txt b/comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/info.txt new file mode 100644 index 0000000000..41d5e1e1b1 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/ghash_vperm/info.txt @@ -0,0 +1,8 @@ + +GHASH_CLMUL_VPERM -> 20201002 + + + +sse2 +ssse3 + diff --git a/comm/third_party/botan/src/lib/utils/ghash/info.txt b/comm/third_party/botan/src/lib/utils/ghash/info.txt new file mode 100644 index 0000000000..4e519eb3b5 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/ghash/info.txt @@ -0,0 +1,3 @@ + +GHASH -> 20201002 + diff --git a/comm/third_party/botan/src/lib/utils/http_util/http_util.cpp b/comm/third_party/botan/src/lib/utils/http_util/http_util.cpp new file mode 100644 index 0000000000..342fe2e843 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/http_util/http_util.cpp @@ -0,0 +1,267 @@ +/* +* Sketchy HTTP client +* (C) 2013,2016 Jack Lloyd +* 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace HTTP { + +namespace { + +/* +* Connect to a host, write some bytes, then read until the server +* closes the socket. +*/ +std::string http_transact(const std::string& hostname, + const std::string& service, + const std::string& message, + std::chrono::milliseconds timeout) + { + std::unique_ptr socket; + + const std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now(); + + try + { + socket = OS::open_socket(hostname, service, timeout); + if(!socket) + throw Not_Implemented("No socket support enabled in build"); + } + catch(std::exception& e) + { + throw HTTP_Error("HTTP connection to " + hostname + " failed: " + e.what()); + } + + // Blocks until entire message has been written + socket->write(cast_char_ptr_to_uint8(message.data()), + message.size()); + + if(std::chrono::system_clock::now() - start_time > timeout) + throw HTTP_Error("Timeout during writing message body"); + + std::ostringstream oss; + std::vector buf(BOTAN_DEFAULT_BUFFER_SIZE); + while(true) + { + const size_t got = socket->read(buf.data(), buf.size()); + if(got == 0) // EOF + break; + + if(std::chrono::system_clock::now() - start_time > timeout) + throw HTTP_Error("Timeout while reading message body"); + + oss.write(cast_uint8_ptr_to_char(buf.data()), + static_cast(got)); + } + + return oss.str(); + } + +} + +std::string url_encode(const std::string& in) + { + std::ostringstream out; + + for(auto c : in) + { + if(c >= 'A' && c <= 'Z') + out << c; + else if(c >= 'a' && c <= 'z') + out << c; + else if(c >= '0' && c <= '9') + out << c; + else if(c == '-' || c == '_' || c == '.' || c == '~') + out << c; + else + out << '%' << hex_encode(cast_char_ptr_to_uint8(&c), 1); + } + + return out.str(); + } + +std::ostream& operator<<(std::ostream& o, const Response& resp) + { + o << "HTTP " << resp.status_code() << " " << resp.status_message() << "\n"; + for(auto h : resp.headers()) + o << "Header '" << h.first << "' = '" << h.second << "'\n"; + o << "Body " << std::to_string(resp.body().size()) << " bytes:\n"; + o.write(cast_uint8_ptr_to_char(resp.body().data()), resp.body().size()); + return o; + } + +Response http_sync(http_exch_fn http_transact, + const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects) + { + if(url.empty()) + throw HTTP_Error("URL empty"); + + const auto protocol_host_sep = url.find("://"); + if(protocol_host_sep == std::string::npos) + throw HTTP_Error("Invalid URL '" + url + "'"); + + const auto host_loc_sep = url.find('/', protocol_host_sep + 3); + + std::string hostname, loc, service; + + if(host_loc_sep == std::string::npos) + { + hostname = url.substr(protocol_host_sep + 3, std::string::npos); + loc = "/"; + } + else + { + hostname = url.substr(protocol_host_sep + 3, host_loc_sep-protocol_host_sep-3); + loc = url.substr(host_loc_sep, std::string::npos); + } + + const auto port_sep = hostname.find(":"); + if(port_sep == std::string::npos) + { + service = "http"; + // hostname not modified + } + else + { + service = hostname.substr(port_sep + 1, std::string::npos); + hostname = hostname.substr(0, port_sep); + } + + std::ostringstream outbuf; + + outbuf << verb << " " << loc << " HTTP/1.0\r\n"; + outbuf << "Host: " << hostname << "\r\n"; + + if(verb == "GET") + { + outbuf << "Accept: */*\r\n"; + outbuf << "Cache-Control: no-cache\r\n"; + } + else if(verb == "POST") + outbuf << "Content-Length: " << body.size() << "\r\n"; + + if(!content_type.empty()) + outbuf << "Content-Type: " << content_type << "\r\n"; + outbuf << "Connection: close\r\n\r\n"; + outbuf.write(cast_uint8_ptr_to_char(body.data()), body.size()); + + std::istringstream io(http_transact(hostname, service, outbuf.str())); + + std::string line1; + std::getline(io, line1); + if(!io || line1.empty()) + throw HTTP_Error("No response"); + + std::stringstream response_stream(line1); + std::string http_version; + unsigned int status_code; + std::string status_message; + + response_stream >> http_version >> status_code; + + std::getline(response_stream, status_message); + + if(!response_stream || http_version.substr(0,5) != "HTTP/") + throw HTTP_Error("Not an HTTP response"); + + std::map headers; + std::string header_line; + while (std::getline(io, header_line) && header_line != "\r") + { + auto sep = header_line.find(": "); + if(sep == std::string::npos || sep > header_line.size() - 2) + throw HTTP_Error("Invalid HTTP header " + header_line); + const std::string key = header_line.substr(0, sep); + + if(sep + 2 < header_line.size() - 1) + { + const std::string val = header_line.substr(sep + 2, (header_line.size() - 1) - (sep + 2)); + headers[key] = val; + } + } + + if(status_code == 301 && headers.count("Location")) + { + if(allowable_redirects == 0) + throw HTTP_Error("HTTP redirection count exceeded"); + return GET_sync(headers["Location"], allowable_redirects - 1); + } + + std::vector resp_body; + std::vector buf(4096); + while(io.good()) + { + io.read(cast_uint8_ptr_to_char(buf.data()), buf.size()); + const size_t got = static_cast(io.gcount()); + resp_body.insert(resp_body.end(), buf.data(), &buf[got]); + } + + const std::string header_size = search_map(headers, std::string("Content-Length")); + + if(!header_size.empty()) + { + if(resp_body.size() != to_u32bit(header_size)) + throw HTTP_Error("Content-Length disagreement, header says " + + header_size + " got " + std::to_string(resp_body.size())); + } + + return Response(status_code, status_message, resp_body, headers); + } + +Response http_sync(const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects, + std::chrono::milliseconds timeout) + { + auto transact_with_timeout = + [timeout](const std::string& hostname, const std::string& service, const std::string& message) + { + return http_transact(hostname, service, message, timeout); + }; + + return http_sync( + transact_with_timeout, + verb, + url, + content_type, + body, + allowable_redirects); + } + +Response GET_sync(const std::string& url, + size_t allowable_redirects, + std::chrono::milliseconds timeout) + { + return http_sync("GET", url, "", std::vector(), allowable_redirects, timeout); + } + +Response POST_sync(const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects, + std::chrono::milliseconds timeout) + { + return http_sync("POST", url, content_type, body, allowable_redirects, timeout); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/utils/http_util/http_util.h b/comm/third_party/botan/src/lib/utils/http_util/http_util.h new file mode 100644 index 0000000000..7ad7c5828c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/http_util/http_util.h @@ -0,0 +1,107 @@ +/* +* HTTP utilities +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTILS_URLGET_H_ +#define BOTAN_UTILS_URLGET_H_ + +#include +#include +#include +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(http_util.h) + +namespace Botan { + +namespace HTTP { + +/** +* HTTP_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) HTTP_Error final : public Exception + { + public: + explicit HTTP_Error(const std::string& msg) : + Exception("HTTP error " + msg) + {} + + ErrorType error_type() const noexcept override { return ErrorType::HttpError; } + + }; + +class Response final + { + public: + Response() : m_status_code(0), m_status_message("Uninitialized") {} + + Response(unsigned int status_code, const std::string& status_message, + const std::vector& body, + const std::map& headers) : + m_status_code(status_code), + m_status_message(status_message), + m_body(body), + m_headers(headers) {} + + unsigned int status_code() const { return m_status_code; } + + const std::vector& body() const { return m_body; } + + const std::map& headers() const { return m_headers; } + + std::string status_message() const { return m_status_message; } + + void throw_unless_ok() + { + if(status_code() != 200) + throw HTTP_Error(status_message()); + } + + private: + unsigned int m_status_code; + std::string m_status_message; + std::vector m_body; + std::map m_headers; + }; + +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& o, const Response& resp); + +typedef std::function http_exch_fn; + +BOTAN_PUBLIC_API(2,0) Response http_sync(http_exch_fn fn, + const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects); + +BOTAN_PUBLIC_API(2,0) Response http_sync(const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +BOTAN_PUBLIC_API(2,0) Response GET_sync(const std::string& url, + size_t allowable_redirects = 1, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +BOTAN_PUBLIC_API(2,0) Response POST_sync(const std::string& url, + const std::string& content_type, + const std::vector& body, + size_t allowable_redirects = 1, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +BOTAN_PUBLIC_API(2,0) std::string url_encode(const std::string& url); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/http_util/info.txt b/comm/third_party/botan/src/lib/utils/http_util/info.txt new file mode 100644 index 0000000000..a3ebc249e2 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/http_util/info.txt @@ -0,0 +1,11 @@ + +HTTP_UTIL -> 20171003 + + + +http_util.h + + + +socket + diff --git a/comm/third_party/botan/src/lib/utils/info.txt b/comm/third_party/botan/src/lib/utils/info.txt new file mode 100644 index 0000000000..93ae795ef5 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/info.txt @@ -0,0 +1,43 @@ + +UTIL_FUNCTIONS -> 20180903 + + +load_on always + + +assert.h +bswap.h +calendar.h +charset.h +compiler.h +data_src.h +database.h +exceptn.h +loadstor.h +mem_ops.h +mul128.h +mutex.h +parsing.h +rotate.h +types.h +version.h +stl_compatibility.h + + + +bit_ops.h +codec_base.h +ct_utils.h +donna128.h +filesystem.h +os_utils.h +prefetch.h +rounding.h +safeint.h +stl_util.h +timer.h + + + +cpuid + diff --git a/comm/third_party/botan/src/lib/utils/loadstor.h b/comm/third_party/botan/src/lib/utils/loadstor.h new file mode 100644 index 0000000000..9a8e9d4bea --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/loadstor.h @@ -0,0 +1,701 @@ +/* +* Load/Store Operators +* (C) 1999-2007,2015,2017 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LOAD_STORE_H_ +#define BOTAN_LOAD_STORE_H_ + +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(loadstor.h) + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + #define BOTAN_ENDIAN_N2L(x) reverse_bytes(x) + #define BOTAN_ENDIAN_L2N(x) reverse_bytes(x) + #define BOTAN_ENDIAN_N2B(x) (x) + #define BOTAN_ENDIAN_B2N(x) (x) + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + #define BOTAN_ENDIAN_N2L(x) (x) + #define BOTAN_ENDIAN_L2N(x) (x) + #define BOTAN_ENDIAN_N2B(x) reverse_bytes(x) + #define BOTAN_ENDIAN_B2N(x) reverse_bytes(x) + +#endif + +namespace Botan { + +/** +* Byte extraction +* @param byte_num which byte to extract, 0 == highest byte +* @param input the value to extract from +* @return byte byte_num of input +*/ +template inline constexpr uint8_t get_byte(size_t byte_num, T input) + { + return static_cast( + input >> (((~byte_num)&(sizeof(T)-1)) << 3) + ); + } + +/** +* Make a uint16_t from two bytes +* @param i0 the first byte +* @param i1 the second byte +* @return i0 || i1 +*/ +inline constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1) + { + return static_cast((static_cast(i0) << 8) | i1); + } + +/** +* Make a uint32_t from four bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @return i0 || i1 || i2 || i3 +*/ +inline constexpr uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3) + { + return ((static_cast(i0) << 24) | + (static_cast(i1) << 16) | + (static_cast(i2) << 8) | + (static_cast(i3))); + } + +/** +* Make a uint64_t from eight bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @param i4 the fifth byte +* @param i5 the sixth byte +* @param i6 the seventh byte +* @param i7 the eighth byte +* @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7 +*/ +inline constexpr uint64_t make_uint64(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3, + uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7) + { + return ((static_cast(i0) << 56) | + (static_cast(i1) << 48) | + (static_cast(i2) << 40) | + (static_cast(i3) << 32) | + (static_cast(i4) << 24) | + (static_cast(i5) << 16) | + (static_cast(i6) << 8) | + (static_cast(i7))); + } + +/** +* Load a big-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a big-endian value +*/ +template +inline T load_be(const uint8_t in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = static_cast((out << 8) | in[i]); + return out; + } + +/** +* Load a little-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a litte-endian value +*/ +template +inline T load_le(const uint8_t in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[sizeof(T)-1-i]; + return out; + } + +/** +* Load a big-endian uint16_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint16_t of in, as a big-endian value +*/ +template<> +inline uint16_t load_be(const uint8_t in[], size_t off) + { + in += off * sizeof(uint16_t); + +#if defined(BOTAN_ENDIAN_N2B) + uint16_t x; + typecast_copy(x, in); + return BOTAN_ENDIAN_N2B(x); +#else + return make_uint16(in[0], in[1]); +#endif + } + +/** +* Load a little-endian uint16_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint16_t of in, as a little-endian value +*/ +template<> +inline uint16_t load_le(const uint8_t in[], size_t off) + { + in += off * sizeof(uint16_t); + +#if defined(BOTAN_ENDIAN_N2L) + uint16_t x; + typecast_copy(x, in); + return BOTAN_ENDIAN_N2L(x); +#else + return make_uint16(in[1], in[0]); +#endif + } + +/** +* Load a big-endian uint32_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint32_t of in, as a big-endian value +*/ +template<> +inline uint32_t load_be(const uint8_t in[], size_t off) + { + in += off * sizeof(uint32_t); +#if defined(BOTAN_ENDIAN_N2B) + uint32_t x; + typecast_copy(x, in); + return BOTAN_ENDIAN_N2B(x); +#else + return make_uint32(in[0], in[1], in[2], in[3]); +#endif + } + +/** +* Load a little-endian uint32_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint32_t of in, as a little-endian value +*/ +template<> +inline uint32_t load_le(const uint8_t in[], size_t off) + { + in += off * sizeof(uint32_t); +#if defined(BOTAN_ENDIAN_N2L) + uint32_t x; + typecast_copy(x, in); + return BOTAN_ENDIAN_N2L(x); +#else + return make_uint32(in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load a big-endian uint64_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint64_t of in, as a big-endian value +*/ +template<> +inline uint64_t load_be(const uint8_t in[], size_t off) + { + in += off * sizeof(uint64_t); +#if defined(BOTAN_ENDIAN_N2B) + uint64_t x; + typecast_copy(x, in); + return BOTAN_ENDIAN_N2B(x); +#else + return make_uint64(in[0], in[1], in[2], in[3], + in[4], in[5], in[6], in[7]); +#endif + } + +/** +* Load a little-endian uint64_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint64_t of in, as a little-endian value +*/ +template<> +inline uint64_t load_le(const uint8_t in[], size_t off) + { + in += off * sizeof(uint64_t); +#if defined(BOTAN_ENDIAN_N2L) + uint64_t x; + typecast_copy(x, in); + return BOTAN_ENDIAN_N2L(x); +#else + return make_uint64(in[7], in[6], in[5], in[4], + in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load two little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template +inline void load_le(const uint8_t in[], T& x0, T& x1) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + } + +/** +* Load four little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template +inline void load_le(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + x2 = load_le(in, 2); + x3 = load_le(in, 3); + } + +/** +* Load eight little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template +inline void load_le(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_le(in, 0); + x1 = load_le(in, 1); + x2 = load_le(in, 2); + x3 = load_le(in, 3); + x4 = load_le(in, 4); + x5 = load_le(in, 5); + x6 = load_le(in, 6); + x7 = load_le(in, 7); + } + +/** +* Load a variable number of little-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template +inline void load_le(T out[], + const uint8_t in[], + size_t count) + { + if(count > 0) + { +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + typecast_copy(out, in, count); + +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + typecast_copy(out, in, count); + + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_le(in, i); +#endif + } + } + +/** +* Load two big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template +inline void load_be(const uint8_t in[], T& x0, T& x1) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + } + +/** +* Load four big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template +inline void load_be(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + x2 = load_be(in, 2); + x3 = load_be(in, 3); + } + +/** +* Load eight big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template +inline void load_be(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_be(in, 0); + x1 = load_be(in, 1); + x2 = load_be(in, 2); + x3 = load_be(in, 3); + x4 = load_be(in, 4); + x5 = load_be(in, 5); + x6 = load_be(in, 6); + x7 = load_be(in, 7); + } + +/** +* Load a variable number of big-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template +inline void load_be(T out[], + const uint8_t in[], + size_t count) + { + if(count > 0) + { +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + typecast_copy(out, in, count); + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + typecast_copy(out, in, count); + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_be(in, i); +#endif + } + } + +/** +* Store a big-endian uint16_t +* @param in the input uint16_t +* @param out the byte array to write to +*/ +inline void store_be(uint16_t in, uint8_t out[2]) + { +#if defined(BOTAN_ENDIAN_N2B) + uint16_t o = BOTAN_ENDIAN_N2B(in); + typecast_copy(out, o); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); +#endif + } + +/** +* Store a little-endian uint16_t +* @param in the input uint16_t +* @param out the byte array to write to +*/ +inline void store_le(uint16_t in, uint8_t out[2]) + { +#if defined(BOTAN_ENDIAN_N2L) + uint16_t o = BOTAN_ENDIAN_N2L(in); + typecast_copy(out, o); +#else + out[0] = get_byte(1, in); + out[1] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian uint32_t +* @param in the input uint32_t +* @param out the byte array to write to +*/ +inline void store_be(uint32_t in, uint8_t out[4]) + { +#if defined(BOTAN_ENDIAN_B2N) + uint32_t o = BOTAN_ENDIAN_B2N(in); + typecast_copy(out, o); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); +#endif + } + +/** +* Store a little-endian uint32_t +* @param in the input uint32_t +* @param out the byte array to write to +*/ +inline void store_le(uint32_t in, uint8_t out[4]) + { +#if defined(BOTAN_ENDIAN_L2N) + uint32_t o = BOTAN_ENDIAN_L2N(in); + typecast_copy(out, o); +#else + out[0] = get_byte(3, in); + out[1] = get_byte(2, in); + out[2] = get_byte(1, in); + out[3] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian uint64_t +* @param in the input uint64_t +* @param out the byte array to write to +*/ +inline void store_be(uint64_t in, uint8_t out[8]) + { +#if defined(BOTAN_ENDIAN_B2N) + uint64_t o = BOTAN_ENDIAN_B2N(in); + typecast_copy(out, o); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); + out[4] = get_byte(4, in); + out[5] = get_byte(5, in); + out[6] = get_byte(6, in); + out[7] = get_byte(7, in); +#endif + } + +/** +* Store a little-endian uint64_t +* @param in the input uint64_t +* @param out the byte array to write to +*/ +inline void store_le(uint64_t in, uint8_t out[8]) + { +#if defined(BOTAN_ENDIAN_L2N) + uint64_t o = BOTAN_ENDIAN_L2N(in); + typecast_copy(out, o); +#else + out[0] = get_byte(7, in); + out[1] = get_byte(6, in); + out[2] = get_byte(5, in); + out[3] = get_byte(4, in); + out[4] = get_byte(3, in); + out[5] = get_byte(2, in); + out[6] = get_byte(1, in); + out[7] = get_byte(0, in); +#endif + } + +/** +* Store two little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template +inline void store_le(uint8_t out[], T x0, T x1) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + } + +/** +* Store two big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template +inline void store_be(uint8_t out[], T x0, T x1) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + } + +/** +* Store four little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template +inline void store_le(uint8_t out[], T x0, T x1, T x2, T x3) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + } + +/** +* Store four big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template +inline void store_be(uint8_t out[], T x0, T x1, T x2, T x3) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + } + +/** +* Store eight little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template +inline void store_le(uint8_t out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + store_le(x4, out + (4 * sizeof(T))); + store_le(x5, out + (5 * sizeof(T))); + store_le(x6, out + (6 * sizeof(T))); + store_le(x7, out + (7 * sizeof(T))); + } + +/** +* Store eight big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template +inline void store_be(uint8_t out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + store_be(x4, out + (4 * sizeof(T))); + store_be(x5, out + (5 * sizeof(T))); + store_be(x6, out + (6 * sizeof(T))); + store_be(x7, out + (7 * sizeof(T))); + } + +template +void copy_out_be(uint8_t out[], size_t out_bytes, const T in[]) + { + while(out_bytes >= sizeof(T)) + { + store_be(in[0], out); + out += sizeof(T); + out_bytes -= sizeof(T); + in += 1; + } + + for(size_t i = 0; i != out_bytes; ++i) + out[i] = get_byte(i%8, in[0]); + } + +template +void copy_out_vec_be(uint8_t out[], size_t out_bytes, const std::vector& in) + { + copy_out_be(out, out_bytes, in.data()); + } + +template +void copy_out_le(uint8_t out[], size_t out_bytes, const T in[]) + { + while(out_bytes >= sizeof(T)) + { + store_le(in[0], out); + out += sizeof(T); + out_bytes -= sizeof(T); + in += 1; + } + + for(size_t i = 0; i != out_bytes; ++i) + out[i] = get_byte(sizeof(T) - 1 - (i % 8), in[0]); + } + +template +void copy_out_vec_le(uint8_t out[], size_t out_bytes, const std::vector& in) + { + copy_out_le(out, out_bytes, in.data()); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/locking_allocator/info.txt b/comm/third_party/botan/src/lib/utils/locking_allocator/info.txt new file mode 100644 index 0000000000..5d7a2ba83e --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/locking_allocator/info.txt @@ -0,0 +1,12 @@ + +LOCKING_ALLOCATOR -> 20131128 + + + +posix1 +virtual_lock + + + +mem_pool + diff --git a/comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.cpp b/comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.cpp new file mode 100644 index 0000000000..1c10c362b6 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.cpp @@ -0,0 +1,75 @@ +/* +* Mlock Allocator +* (C) 2012,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +void* mlock_allocator::allocate(size_t num_elems, size_t elem_size) + { + if(!m_pool) + return nullptr; + + const size_t n = num_elems * elem_size; + if(n / elem_size != num_elems) + return nullptr; // overflow! + + return m_pool->allocate(n); + } + +bool mlock_allocator::deallocate(void* p, size_t num_elems, size_t elem_size) noexcept + { + if(!m_pool) + return false; + + size_t n = num_elems * elem_size; + + /* + We return nullptr in allocate if there was an overflow, so if an + overflow occurs here we know the pointer was not allocated by this pool. + */ + if(n / elem_size != num_elems) + return false; + + return m_pool->deallocate(p, n); + } + +mlock_allocator::mlock_allocator() + { + const size_t mem_to_lock = OS::get_memory_locking_limit(); + const size_t page_size = OS::system_page_size(); + + if(mem_to_lock > 0 && mem_to_lock % page_size == 0) + { + m_locked_pages = OS::allocate_locked_pages(mem_to_lock / page_size); + + if(m_locked_pages.size() > 0) + { + m_pool.reset(new Memory_Pool(m_locked_pages, page_size)); + } + } + } + +mlock_allocator::~mlock_allocator() + { + if(m_pool) + { + m_pool.reset(); + // OS::free_locked_pages scrubs the memory before free + OS::free_locked_pages(m_locked_pages); + } + } + +mlock_allocator& mlock_allocator::instance() + { + static mlock_allocator mlock; + return mlock; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.h b/comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.h new file mode 100644 index 0000000000..8d1d249809 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/locking_allocator/locking_allocator.h @@ -0,0 +1,45 @@ +/* +* Mlock Allocator +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MLOCK_ALLOCATOR_H_ +#define BOTAN_MLOCK_ALLOCATOR_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(locking_allocator.h) + +namespace Botan { + +class Memory_Pool; + +class BOTAN_PUBLIC_API(2,0) mlock_allocator final + { + public: + static mlock_allocator& instance(); + + void* allocate(size_t num_elems, size_t elem_size); + + bool deallocate(void* p, size_t num_elems, size_t elem_size) noexcept; + + mlock_allocator(const mlock_allocator&) = delete; + + mlock_allocator& operator=(const mlock_allocator&) = delete; + + private: + mlock_allocator(); + + ~mlock_allocator(); + + std::unique_ptr m_pool; + std::vector m_locked_pages; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/mem_ops.cpp b/comm/third_party/botan/src/lib/utils/mem_ops.cpp new file mode 100644 index 0000000000..9ef1d6c4e3 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mem_ops.cpp @@ -0,0 +1,68 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + #include +#endif + +namespace Botan { + +BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size) + { + if(elems == 0 || elem_size == 0) + return nullptr; + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(void* p = mlock_allocator::instance().allocate(elems, elem_size)) + return p; +#endif + + void* ptr = std::calloc(elems, elem_size); + if(!ptr) + throw std::bad_alloc(); + return ptr; + } + +void deallocate_memory(void* p, size_t elems, size_t elem_size) + { + if(p == nullptr) + return; + + secure_scrub_memory(p, elems * elem_size); + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(mlock_allocator::instance().deallocate(p, elems, elem_size)) + return; +#endif + + std::free(p); + } + +void initialize_allocator() + { +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + mlock_allocator::instance(); +#endif + } + +uint8_t ct_compare_u8(const uint8_t x[], + const uint8_t y[], + size_t len) + { + volatile uint8_t difference = 0; + + for(size_t i = 0; i != len; ++i) + difference |= (x[i] ^ y[i]); + + return CT::Mask::is_zero(difference).value(); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/mem_ops.h b/comm/third_party/botan/src/lib/utils/mem_ops.h new file mode 100644 index 0000000000..deb4c01f28 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mem_ops.h @@ -0,0 +1,365 @@ +/* +* Memory Operations +* (C) 1999-2009,2012,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MEMORY_OPS_H_ +#define BOTAN_MEMORY_OPS_H_ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Allocate a memory buffer by some method. This should only be used for +* primitive types (uint8_t, uint32_t, etc). +* +* @param elems the number of elements +* @param elem_size the size of each element +* @return pointer to allocated and zeroed memory, or throw std::bad_alloc on failure +*/ +BOTAN_PUBLIC_API(2,3) BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size); + +/** +* Free a pointer returned by allocate_memory +* @param p the pointer returned by allocate_memory +* @param elems the number of elements, as passed to allocate_memory +* @param elem_size the size of each element, as passed to allocate_memory +*/ +BOTAN_PUBLIC_API(2,3) void deallocate_memory(void* p, size_t elems, size_t elem_size); + +/** +* Ensure the allocator is initialized +*/ +void BOTAN_UNSTABLE_API initialize_allocator(); + +class Allocator_Initializer + { + public: + Allocator_Initializer() { initialize_allocator(); } + }; + +/** +* Scrub memory contents in a way that a compiler should not elide, +* using some system specific technique. Note that this function might +* not zero the memory (for example, in some hypothetical +* implementation it might combine the memory contents with the output +* of a system PRNG), but if you can detect any difference in behavior +* at runtime then the clearing is side-effecting and you can just +* use `clear_mem`. +* +* Use this function to scrub memory just before deallocating it, or on +* a stack buffer before returning from the function. +* +* @param ptr a pointer to memory to scrub +* @param n the number of bytes pointed to by ptr +*/ +BOTAN_PUBLIC_API(2,0) void secure_scrub_memory(void* ptr, size_t n); + +/** +* Memory comparison, input insensitive +* @param x a pointer to an array +* @param y a pointer to another array +* @param len the number of Ts in x and y +* @return 0xFF iff x[i] == y[i] forall i in [0...n) or 0x00 otherwise +*/ +BOTAN_PUBLIC_API(2,9) uint8_t ct_compare_u8(const uint8_t x[], + const uint8_t y[], + size_t len); + +/** +* Memory comparison, input insensitive +* @param x a pointer to an array +* @param y a pointer to another array +* @param len the number of Ts in x and y +* @return true iff x[i] == y[i] forall i in [0...n) +*/ +inline bool constant_time_compare(const uint8_t x[], + const uint8_t y[], + size_t len) + { + return ct_compare_u8(x, y, len) == 0xFF; + } + +/** +* Zero out some bytes. Warning: use secure_scrub_memory instead if the +* memory is about to be freed or otherwise the compiler thinks it can +* elide the writes. +* +* @param ptr a pointer to memory to zero +* @param bytes the number of bytes to zero in ptr +*/ +inline void clear_bytes(void* ptr, size_t bytes) + { + if(bytes > 0) + { + std::memset(ptr, 0, bytes); + } + } + +/** +* Zero memory before use. This simply calls memset and should not be +* used in cases where the compiler cannot see the call as a +* side-effecting operation (for example, if calling clear_mem before +* deallocating memory, the compiler would be allowed to omit the call +* to memset entirely under the as-if rule.) +* +* @param ptr a pointer to an array of Ts to zero +* @param n the number of Ts pointed to by ptr +*/ +template inline void clear_mem(T* ptr, size_t n) + { + clear_bytes(ptr, sizeof(T)*n); + } + +// is_trivially_copyable is missing in g++ < 5.0 +#if (BOTAN_GCC_VERSION > 0 && BOTAN_GCC_VERSION < 500) +#define BOTAN_IS_TRIVIALLY_COPYABLE(T) true +#else +#define BOTAN_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable::value +#endif + +/** +* Copy memory +* @param out the destination array +* @param in the source array +* @param n the number of elements of in/out +*/ +template inline void copy_mem(T* out, const T* in, size_t n) + { + static_assert(std::is_trivial::type>::value, ""); + BOTAN_ASSERT_IMPLICATION(n > 0, in != nullptr && out != nullptr, + "If n > 0 then args are not null"); + + if(in != nullptr && out != nullptr && n > 0) + { + std::memmove(out, in, sizeof(T)*n); + } + } + +template inline void typecast_copy(uint8_t out[], T in[], size_t N) + { + static_assert(BOTAN_IS_TRIVIALLY_COPYABLE(T), ""); + std::memcpy(out, in, sizeof(T)*N); + } + +template inline void typecast_copy(T out[], const uint8_t in[], size_t N) + { + static_assert(std::is_trivial::value, ""); + std::memcpy(out, in, sizeof(T)*N); + } + +template inline void typecast_copy(uint8_t out[], T in) + { + typecast_copy(out, &in, 1); + } + +template inline void typecast_copy(T& out, const uint8_t in[]) + { + static_assert(std::is_trivial::type>::value, ""); + typecast_copy(&out, in, 1); + } + +template inline To typecast_copy(const From *src) noexcept + { + static_assert(BOTAN_IS_TRIVIALLY_COPYABLE(From) && std::is_trivial::value, ""); + To dst; + std::memcpy(&dst, src, sizeof(To)); + return dst; + } + +/** +* Set memory to a fixed value +* @param ptr a pointer to an array of bytes +* @param n the number of Ts pointed to by ptr +* @param val the value to set each byte to +*/ +inline void set_mem(uint8_t* ptr, size_t n, uint8_t val) + { + if(n > 0) + { + std::memset(ptr, val, n); + } + } + +inline const uint8_t* cast_char_ptr_to_uint8(const char* s) + { + return reinterpret_cast(s); + } + +inline const char* cast_uint8_ptr_to_char(const uint8_t* b) + { + return reinterpret_cast(b); + } + +inline uint8_t* cast_char_ptr_to_uint8(char* s) + { + return reinterpret_cast(s); + } + +inline char* cast_uint8_ptr_to_char(uint8_t* b) + { + return reinterpret_cast(b); + } + +/** +* Memory comparison, input insensitive +* @param p1 a pointer to an array +* @param p2 a pointer to another array +* @param n the number of Ts in p1 and p2 +* @return true iff p1[i] == p2[i] forall i in [0...n) +*/ +template inline bool same_mem(const T* p1, const T* p2, size_t n) + { + volatile T difference = 0; + + for(size_t i = 0; i != n; ++i) + difference |= (p1[i] ^ p2[i]); + + return difference == 0; + } + +template +size_t buffer_insert(std::vector& buf, + size_t buf_offset, + const T input[], + size_t input_length) + { + BOTAN_ASSERT_NOMSG(buf_offset <= buf.size()); + const size_t to_copy = std::min(input_length, buf.size() - buf_offset); + if(to_copy > 0) + { + copy_mem(&buf[buf_offset], input, to_copy); + } + return to_copy; + } + +template +size_t buffer_insert(std::vector& buf, + size_t buf_offset, + const std::vector& input) + { + BOTAN_ASSERT_NOMSG(buf_offset <= buf.size()); + const size_t to_copy = std::min(input.size(), buf.size() - buf_offset); + if(to_copy > 0) + { + copy_mem(&buf[buf_offset], input.data(), to_copy); + } + return to_copy; + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length +* @param out the input/output buffer +* @param in the read-only input buffer +* @param length the length of the buffers +*/ +inline void xor_buf(uint8_t out[], + const uint8_t in[], + size_t length) + { + const size_t blocks = length - (length % 32); + + for(size_t i = 0; i != blocks; i += 32) + { + uint64_t x[4]; + uint64_t y[4]; + + typecast_copy(x, out + i, 4); + typecast_copy(y, in + i, 4); + + x[0] ^= y[0]; + x[1] ^= y[1]; + x[2] ^= y[2]; + x[3] ^= y[3]; + + typecast_copy(out + i, x, 4); + } + + for(size_t i = blocks; i != length; ++i) + { + out[i] ^= in[i]; + } + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length +* @param out the output buffer +* @param in the first input buffer +* @param in2 the second output buffer +* @param length the length of the three buffers +*/ +inline void xor_buf(uint8_t out[], + const uint8_t in[], + const uint8_t in2[], + size_t length) + { + const size_t blocks = length - (length % 32); + + for(size_t i = 0; i != blocks; i += 32) + { + uint64_t x[4]; + uint64_t y[4]; + + typecast_copy(x, in + i, 4); + typecast_copy(y, in2 + i, 4); + + x[0] ^= y[0]; + x[1] ^= y[1]; + x[2] ^= y[2]; + x[3] ^= y[3]; + + typecast_copy(out + i, x, 4); + } + + for(size_t i = blocks; i != length; ++i) + { + out[i] = in[i] ^ in2[i]; + } + } + +template +void xor_buf(std::vector& out, + const std::vector& in, + size_t n) + { + xor_buf(out.data(), in.data(), n); + } + +template +void xor_buf(std::vector& out, + const uint8_t* in, + size_t n) + { + xor_buf(out.data(), in, n); + } + +template +void xor_buf(std::vector& out, + const uint8_t* in, + const std::vector& in2, + size_t n) + { + xor_buf(out.data(), in, in2.data(), n); + } + +template +std::vector& +operator^=(std::vector& out, + const std::vector& in) + { + if(out.size() < in.size()) + out.resize(in.size()); + + xor_buf(out.data(), in.data(), in.size()); + return out; + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/mem_pool/info.txt b/comm/third_party/botan/src/lib/utils/mem_pool/info.txt new file mode 100644 index 0000000000..a8a5a53e1b --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mem_pool/info.txt @@ -0,0 +1,7 @@ + +MEM_POOL -> 20180309 + + + +mem_pool.h + diff --git a/comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.cpp b/comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.cpp new file mode 100644 index 0000000000..1ff3f0759b --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.cpp @@ -0,0 +1,435 @@ +/* +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) + #include +#endif + +namespace Botan { + +/* +* Memory pool theory of operation +* +* This allocator is not useful for general purpose but works well within the +* context of allocating cryptographic keys. It makes several assumptions which +* don't work for implementing malloc but simplify and speed up the implementation: +* +* - There is some set of pages, which cannot be expanded later. These are pages +* which were allocated, mlocked and passed to the Memory_Pool constructor. +* +* - The allocator is allowed to return null anytime it feels like not servicing +* a request, in which case the request will be sent to calloc instead. In +* particular, requests which are too small or too large are rejected. +* +* - Most allocations are powers of 2, the remainder are usually a multiple of 8 +* +* - Free requests include the size of the allocation, so there is no need to +* track this within the pool. +* +* - Alignment is important to the caller. For this allocator, any allocation of +* size N is aligned evenly at N bytes. +* +* Initially each page is in the free page list. Each page is used for just one +* size of allocation, with requests bucketed into a small number of common +* sizes. If the allocation would be too big or too small it is rejected by the pool. +* +* The free list is maintained by a bitmap, one per page/Bucket. Since each +* Bucket only maintains objects of a single size, each bit set or clear +* indicates the status of one object. +* +* An allocation walks the list of buckets and asks each in turn if there is +* space. If a Bucket does not have any space, it sets a boolean flag m_is_full +* so that it does not need to rescan when asked again. The flag is cleared on +* first free from that bucket. If no bucket has space, but there are some free +* pages left, a free page is claimed as a new Bucket for that size. In this case +* it is pushed to the front of the list so it is first in line to service new +* requests. +* +* A deallocation also walks the list of buckets for the size and asks each +* Bucket in turn if it recognizes the pointer. When a Bucket becomes empty as a +* result of a deallocation, it is recycled back into the free pool. When this +* happens, the Buckets page goes to the end of the free list. All pages on the +* free list are marked in the MMU as noaccess, so anything touching them will +* immediately crash. They are only marked R/W once placed into a new bucket. +* Making the free list FIFO maximizes the time between the last free of a bucket +* and that page being writable again, maximizing chances of crashing after a +* use-after-free. +* +* Future work +* ------------- +* +* The allocator is protected by a global lock. It would be good to break this +* up, since almost all of the work can actually be done in parallel especially +* when allocating objects of different sizes (which can't possibly share a +* bucket). +* +* It may be worthwhile to optimize deallocation by storing the Buckets in order +* (by pointer value) which would allow binary search to find the owning bucket. +* +* A useful addition would be to randomize the allocations. Memory_Pool would be +* changed to receive also a RandomNumberGenerator& object (presumably the system +* RNG, or maybe a ChaCha_RNG seeded with system RNG). Then the bucket to use and +* the offset within the bucket would be chosen randomly, instead of using first fit. +* +* Right now we don't make any provision for threading, so if two threads both +* allocate 32 byte values one after the other, the two allocations will likely +* share a cache line. Ensuring that distinct threads will (tend to) use distinct +* buckets would reduce this. +* +* Supporting a realloc-style API may be useful. +*/ + +namespace { + +size_t choose_bucket(size_t n) + { + const size_t MINIMUM_ALLOCATION = 16; + const size_t MAXIMUM_ALLOCATION = 256; + + if(n < MINIMUM_ALLOCATION || n > MAXIMUM_ALLOCATION) + return 0; + + // Need to tune these + + const size_t buckets[] = { + 16, 24, 32, 48, 64, 80, 96, 112, 128, 160, 192, 256, 0, + }; + + for(size_t i = 0; buckets[i]; ++i) + { + if(n <= buckets[i]) + { + return buckets[i]; + } + } + + return 0; + } + +inline bool ptr_in_pool(const void* pool_ptr, size_t poolsize, + const void* buf_ptr, size_t bufsize) + { + const uintptr_t pool = reinterpret_cast(pool_ptr); + const uintptr_t buf = reinterpret_cast(buf_ptr); + return (buf >= pool) && (buf + bufsize <= pool + poolsize); + } + +// return index of first set bit +template +size_t find_set_bit(T b) + { + size_t s = 8*sizeof(T) / 2; + size_t bit = 0; + + // In this context we don't need to be const-time + while(s > 0) + { + const T mask = (static_cast(1) << s) - 1; + if((b & mask) == 0) + { + bit += s; + b >>= s; + } + s /= 2; + } + + return bit; + } + +class BitMap final + { + public: + BitMap(size_t bits) : m_len(bits) + { + m_bits.resize((bits + BITMASK_BITS - 1) / BITMASK_BITS); + m_main_mask = static_cast(~0); + m_last_mask = m_main_mask; + + if(bits % BITMASK_BITS != 0) + m_last_mask = (static_cast(1) << (bits % BITMASK_BITS)) - 1; + } + + bool find_free(size_t* bit); + + void free(size_t bit) + { + BOTAN_ASSERT_NOMSG(bit <= m_len); + const size_t w = bit / BITMASK_BITS; + BOTAN_ASSERT_NOMSG(w < m_bits.size()); + const bitmask_type mask = static_cast(1) << (bit % BITMASK_BITS); + m_bits[w] = m_bits[w] & (~mask); + } + + bool empty() const + { + for(size_t i = 0; i != m_bits.size(); ++i) + { + if(m_bits[i] != 0) + { + return false; + } + } + + return true; + } + + private: +#if defined(BOTAN_ENABLE_DEBUG_ASSERTS) + typedef uint8_t bitmask_type; + enum { BITMASK_BITS = 8 }; +#else + typedef word bitmask_type; + enum { BITMASK_BITS = BOTAN_MP_WORD_BITS }; +#endif + + size_t m_len; + bitmask_type m_main_mask; + bitmask_type m_last_mask; + std::vector m_bits; + }; + +bool BitMap::find_free(size_t* bit) + { + for(size_t i = 0; i != m_bits.size(); ++i) + { + const bitmask_type mask = (i == m_bits.size() - 1) ? m_last_mask : m_main_mask; + if((m_bits[i] & mask) != mask) + { + size_t free_bit = find_set_bit(~m_bits[i]); + const bitmask_type bmask = static_cast(1) << (free_bit % BITMASK_BITS); + BOTAN_ASSERT_NOMSG((m_bits[i] & bmask) == 0); + m_bits[i] |= bmask; + *bit = BITMASK_BITS*i + free_bit; + return true; + } + } + + return false; + } + +} + +class Bucket final + { + public: + Bucket(uint8_t* mem, size_t mem_size, size_t item_size) : + m_item_size(item_size), + m_page_size(mem_size), + m_range(mem), + m_bitmap(mem_size / item_size), + m_is_full(false) + { + } + + uint8_t* alloc() + { + if(m_is_full) + { + // I know I am full + return nullptr; + } + + size_t offset; + if(!m_bitmap.find_free(&offset)) + { + // I just found out I am full + m_is_full = true; + return nullptr; + } + + BOTAN_ASSERT(offset * m_item_size < m_page_size, "Offset is in range"); + return m_range + m_item_size*offset; + } + + bool free(void* p) + { + if(!in_this_bucket(p)) + return false; + + /* + Zero also any trailing bytes, which should not have been written to, + but maybe the user was bad and wrote past the end. + */ + std::memset(p, 0, m_item_size); + + const size_t offset = (reinterpret_cast(p) - reinterpret_cast(m_range)) / m_item_size; + + m_bitmap.free(offset); + m_is_full = false; + + return true; + } + + bool in_this_bucket(void* p) const + { + return ptr_in_pool(m_range, m_page_size, p, m_item_size); + } + + bool empty() const + { + return m_bitmap.empty(); + } + + uint8_t* ptr() const + { + return m_range; + } + + private: + size_t m_item_size; + size_t m_page_size; + uint8_t* m_range; + BitMap m_bitmap; + bool m_is_full; + }; + +Memory_Pool::Memory_Pool(const std::vector& pages, size_t page_size) : + m_page_size(page_size) + { + m_min_page_ptr = ~static_cast(0); + m_max_page_ptr = 0; + + for(size_t i = 0; i != pages.size(); ++i) + { + const uintptr_t p = reinterpret_cast(pages[i]); + + m_min_page_ptr = std::min(p, m_min_page_ptr); + m_max_page_ptr = std::max(p, m_max_page_ptr); + + clear_bytes(pages[i], m_page_size); +#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) + OS::page_prohibit_access(pages[i]); +#endif + m_free_pages.push_back(static_cast(pages[i])); + } + + /* + Right now this points to the start of the last page, adjust it to instead + point to the first byte of the following page + */ + m_max_page_ptr += page_size; + } + +Memory_Pool::~Memory_Pool() + { +#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) + for(size_t i = 0; i != m_free_pages.size(); ++i) + { + OS::page_allow_access(m_free_pages[i]); + } +#endif + } + +void* Memory_Pool::allocate(size_t n) + { + if(n > m_page_size) + return nullptr; + + const size_t n_bucket = choose_bucket(n); + + if(n_bucket > 0) + { + lock_guard_type lock(m_mutex); + + std::deque& buckets = m_buckets_for[n_bucket]; + + /* + It would be optimal to pick the bucket with the most usage, + since a bucket with say 1 item allocated out of it has a high + chance of becoming later freed and then the whole page can be + recycled. + */ + for(auto& bucket : buckets) + { + if(uint8_t* p = bucket.alloc()) + return p; + + // If the bucket is full, maybe move it to the end of the list? + // Otoh bucket search should be very fast + } + + if(m_free_pages.size() > 0) + { + uint8_t* ptr = m_free_pages[0]; + m_free_pages.pop_front(); +#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) + OS::page_allow_access(ptr); +#endif + buckets.push_front(Bucket(ptr, m_page_size, n_bucket)); + void* p = buckets[0].alloc(); + BOTAN_ASSERT_NOMSG(p != nullptr); + return p; + } + } + + // out of room + return nullptr; + } + +bool Memory_Pool::deallocate(void* p, size_t len) noexcept + { + // Do a fast range check first, before taking the lock + const uintptr_t p_val = reinterpret_cast(p); + if(p_val < m_min_page_ptr || p_val > m_max_page_ptr) + return false; + + const size_t n_bucket = choose_bucket(len); + + if(n_bucket != 0) + { + try + { + lock_guard_type lock(m_mutex); + + std::deque& buckets = m_buckets_for[n_bucket]; + + for(size_t i = 0; i != buckets.size(); ++i) + { + Bucket& bucket = buckets[i]; + if(bucket.free(p)) + { + if(bucket.empty()) + { +#if defined(BOTAN_MEM_POOL_USE_MMU_PROTECTIONS) + OS::page_prohibit_access(bucket.ptr()); +#endif + m_free_pages.push_back(bucket.ptr()); + + if(i != buckets.size() - 1) + std::swap(buckets.back(), buckets[i]); + buckets.pop_back(); + } + return true; + } + } + } + catch(...) + { + /* + * The only exception throws that can occur in the above code are from + * either the STL or BOTAN_ASSERT failures. In either case, such an + * error indicates a logic error or data corruption in the memory + * allocator such that it is no longer safe to continue executing. + * + * Since this function is noexcept, simply letting the exception escape + * is sufficient for terminate to be called. However in this scenario + * it is implementation defined if any stack unwinding is performed. + * Since stack unwinding could cause further memory deallocations this + * could result in further corruption in this allocator state. To prevent + * this, call terminate directly. + */ + std::terminate(); + } + } + + return false; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.h b/comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.h new file mode 100644 index 0000000000..4fcec15eeb --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mem_pool/mem_pool.h @@ -0,0 +1,58 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MEM_POOL_H_ +#define BOTAN_MEM_POOL_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class Bucket; + +class BOTAN_TEST_API Memory_Pool final + { + public: + /** + * Initialize a memory pool. The memory is not owned by *this, + * it must be freed by the caller. + * @param pages a list of pages to allocate from + * @param page_size the system page size, each page should + * point to exactly this much memory. + */ + Memory_Pool(const std::vector& pages, + size_t page_size); + + ~Memory_Pool(); + + void* allocate(size_t size); + + bool deallocate(void* p, size_t size) noexcept; + + Memory_Pool(const Memory_Pool&) = delete; + Memory_Pool(Memory_Pool&&) = delete; + + Memory_Pool& operator=(const Memory_Pool&) = delete; + Memory_Pool& operator=(Memory_Pool&&) = delete; + + private: + const size_t m_page_size = 0; + + mutex_type m_mutex; + + std::deque m_free_pages; + std::map> m_buckets_for; + uintptr_t m_min_page_ptr; + uintptr_t m_max_page_ptr; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/mul128.h b/comm/third_party/botan/src/lib/utils/mul128.h new file mode 100644 index 0000000000..8cdaae21e0 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mul128.h @@ -0,0 +1,125 @@ +/* +* 64x64->128 bit multiply operation +* (C) 2013,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_MUL128_H_ +#define BOTAN_UTIL_MUL128_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(mul128.h) + +namespace Botan { + +#if defined(__SIZEOF_INT128__) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + #define BOTAN_TARGET_HAS_NATIVE_UINT128 + + // Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode + #if defined(__GNUG__) + typedef unsigned int uint128_t __attribute__((mode(TI))); + #else + typedef unsigned __int128 uint128_t; + #endif +#endif + +} + +#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { \ + const uint128_t r = static_cast(a) * b; \ + *hi = (r >> 64) & 0xFFFFFFFFFFFFFFFF; \ + *lo = (r ) & 0xFFFFFFFFFFFFFFFF; \ + } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + +#include +#pragma intrinsic(_umul128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { *lo = _umul128(a, b, hi); } while(0) + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulq %3" : "=d" (*hi), "=a" (*lo) : "a" (a), "rm" (b) : "cc"); \ + } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("umulh %1,%2,%0" : "=r" (*hi) : "r" (a), "r" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("xmpy.hu %0=%1,%2" : "=f" (*hi) : "f" (a), "f" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulhdu %0,%1,%2" : "=r" (*hi) : "r" (a), "r" (b) : "cc"); \ + *lo = a * b; \ +} while(0) + +#endif + +#endif + +namespace Botan { + +/** +* Perform a 64x64->128 bit multiplication +*/ +inline void mul64x64_128(uint64_t a, uint64_t b, uint64_t* lo, uint64_t* hi) + { +#if defined(BOTAN_FAST_64X64_MUL) + BOTAN_FAST_64X64_MUL(a, b, lo, hi); +#else + + /* + * Do a 64x64->128 multiply using four 32x32->64 multiplies plus + * some adds and shifts. Last resort for CPUs like UltraSPARC (with + * 64-bit registers/ALU, but no 64x64->128 multiply) or 32-bit CPUs. + */ + const size_t HWORD_BITS = 32; + const uint32_t HWORD_MASK = 0xFFFFFFFF; + + const uint32_t a_hi = (a >> HWORD_BITS); + const uint32_t a_lo = (a & HWORD_MASK); + const uint32_t b_hi = (b >> HWORD_BITS); + const uint32_t b_lo = (b & HWORD_MASK); + + uint64_t x0 = static_cast(a_hi) * b_hi; + uint64_t x1 = static_cast(a_lo) * b_hi; + uint64_t x2 = static_cast(a_hi) * b_lo; + uint64_t x3 = static_cast(a_lo) * b_lo; + + // this cannot overflow as (2^32-1)^2 + 2^32-1 < 2^64-1 + x2 += x3 >> HWORD_BITS; + + // this one can overflow + x2 += x1; + + // propagate the carry if any + x0 += static_cast(static_cast(x2 < x1)) << HWORD_BITS; + + *hi = x0 + (x2 >> HWORD_BITS); + *lo = ((x2 & HWORD_MASK) << HWORD_BITS) + (x3 & HWORD_MASK); +#endif + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/mutex.h b/comm/third_party/botan/src/lib/utils/mutex.h new file mode 100644 index 0000000000..a230af9888 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/mutex.h @@ -0,0 +1,60 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_MUTEX_H_ +#define BOTAN_UTIL_MUTEX_H_ + +#include + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + +#include + +namespace Botan { + +template using lock_guard_type = std::lock_guard; +typedef std::mutex mutex_type; +typedef std::recursive_mutex recursive_mutex_type; + +} + +#else + +// No threads + +namespace Botan { + +template +class lock_guard final + { + public: + explicit lock_guard(Mutex& m) : m_mutex(m) + { m_mutex.lock(); } + + ~lock_guard() { m_mutex.unlock(); } + + lock_guard(const lock_guard& other) = delete; + lock_guard& operator=(const lock_guard& other) = delete; + private: + Mutex& m_mutex; + }; + +class noop_mutex final + { + public: + void lock() {} + void unlock() {} + }; + +typedef noop_mutex mutex_type; +typedef noop_mutex recursive_mutex_type; +template using lock_guard_type = lock_guard; + +} + +#endif + +#endif diff --git a/comm/third_party/botan/src/lib/utils/os_utils.cpp b/comm/third_party/botan/src/lib/utils/os_utils.cpp new file mode 100644 index 0000000000..f5151da42b --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/os_utils.cpp @@ -0,0 +1,757 @@ +/* +* OS and machine specific utility functions +* (C) 2015,2016,2017,2018 Jack Lloyd +* (C) 2016 Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #undef B0 +#endif + +#if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_IS_ANDROID) || \ + defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_WIN32) + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include +#endif + +#if defined(BOTAN_TARGET_OS_IS_ANDROID) + #include + extern "C" char **environ; +#endif + +#if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS) + #include +#endif + +namespace Botan { + +// Not defined in OS namespace for historical reasons +void secure_scrub_memory(void* ptr, size_t n) + { +#if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY) + ::RtlSecureZeroMemory(ptr, n); + +#elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO) + ::explicit_bzero(ptr, n); + +#elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_MEMSET) + (void)::explicit_memset(ptr, 0, n); + +#elif defined(BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO) && (BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO == 1) + /* + Call memset through a static volatile pointer, which the compiler + should not elide. This construct should be safe in conforming + compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and + Clang 3.8 both create code that saves the memset address in the + data segment and unconditionally loads and jumps to that address. + */ + static void* (*const volatile memset_ptr)(void*, int, size_t) = std::memset; + (memset_ptr)(ptr, 0, n); +#else + + volatile uint8_t* p = reinterpret_cast(ptr); + + for(size_t i = 0; i != n; ++i) + p[i] = 0; +#endif + } + +uint32_t OS::get_process_id() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + return ::getpid(); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + return ::GetCurrentProcessId(); +#elif defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM) || defined(BOTAN_TARGET_OS_IS_NONE) + return 0; // truly no meaningful value +#else + #error "Missing get_process_id" +#endif + } + +unsigned long OS::get_auxval(unsigned long id) + { +#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) + return ::getauxval(id); +#elif defined(BOTAN_TARGET_OS_IS_ANDROID) && defined(BOTAN_TARGET_ARCH_IS_ARM32) + + if(id == 0) + return 0; + + char **p = environ; + + while(*p++ != nullptr) + ; + + Elf32_auxv_t *e = reinterpret_cast(p); + + while(e != nullptr) + { + if(e->a_type == id) + return e->a_un.a_val; + e++; + } + + return 0; +#elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO) + unsigned long auxinfo = 0; + ::elf_aux_info(id, &auxinfo, sizeof(auxinfo)); + return auxinfo; +#else + BOTAN_UNUSED(id); + return 0; +#endif + } + +bool OS::running_in_privileged_state() + { +#if defined(AT_SECURE) + return OS::get_auxval(AT_SECURE) != 0; +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + return (::getuid() != ::geteuid()) || (::getgid() != ::getegid()); +#else + return false; +#endif + } + +uint64_t OS::get_cpu_cycle_counter() + { + uint64_t rtc = 0; + +#if defined(BOTAN_TARGET_OS_HAS_WIN32) + LARGE_INTEGER tv; + ::QueryPerformanceCounter(&tv); + rtc = tv.QuadPart; + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + if(CPUID::has_rdtsc()) + { + uint32_t rtc_low = 0, rtc_high = 0; + asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); + rtc = (static_cast(rtc_high) << 32) | rtc_low; + } + +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + + for(;;) + { + uint32_t rtc_low = 0, rtc_high = 0, rtc_high2 = 0; + asm volatile("mftbu %0" : "=r" (rtc_high)); + asm volatile("mftb %0" : "=r" (rtc_low)); + asm volatile("mftbu %0" : "=r" (rtc_high2)); + + if(rtc_high == rtc_high2) + { + rtc = (static_cast(rtc_high) << 32) | rtc_low; + break; + } + } + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + asm volatile("rpcc %0" : "=r" (rtc)); + + // OpenBSD does not trap access to the %tick register +#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) + asm volatile("rd %%tick, %0" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + asm volatile("mov %0=ar.itc" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_S390X) + asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc"); + +#elif defined(BOTAN_TARGET_ARCH_IS_HPPA) + asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only? + +#else + //#warning "OS::get_cpu_cycle_counter not implemented" +#endif + +#endif + + return rtc; + } + +size_t OS::get_cpu_total() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_CONF) + const long res = ::sysconf(_SC_NPROCESSORS_CONF); + if(res > 0) + return static_cast(res); +#endif + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + return static_cast(std::thread::hardware_concurrency()); +#else + return 1; +#endif + } + +size_t OS::get_cpu_available() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN) + const long res = ::sysconf(_SC_NPROCESSORS_ONLN); + if(res > 0) + return static_cast(res); +#endif + + return OS::get_cpu_total(); + } + +uint64_t OS::get_high_resolution_clock() + { + if(uint64_t cpu_clock = OS::get_cpu_cycle_counter()) + return cpu_clock; + +#if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) + return emscripten_get_now(); +#endif + + /* + If we got here either we either don't have an asm instruction + above, or (for x86) RDTSC is not available at runtime. Try some + clock_gettimes and return the first one that works, or otherwise + fall back to std::chrono. + */ + +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + + // The ordering here is somewhat arbitrary... + const clockid_t clock_types[] = { +#if defined(CLOCK_MONOTONIC_HR) + CLOCK_MONOTONIC_HR, +#endif +#if defined(CLOCK_MONOTONIC_RAW) + CLOCK_MONOTONIC_RAW, +#endif +#if defined(CLOCK_MONOTONIC) + CLOCK_MONOTONIC, +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + CLOCK_PROCESS_CPUTIME_ID, +#endif +#if defined(CLOCK_THREAD_CPUTIME_ID) + CLOCK_THREAD_CPUTIME_ID, +#endif + }; + + for(clockid_t clock : clock_types) + { + struct timespec ts; + if(::clock_gettime(clock, &ts) == 0) + { + return (static_cast(ts.tv_sec) * 1000000000) + static_cast(ts.tv_nsec); + } + } +#endif + + // Plain C++11 fallback + auto now = std::chrono::high_resolution_clock::now().time_since_epoch(); + return std::chrono::duration_cast(now).count(); + } + +uint64_t OS::get_system_timestamp_ns() + { +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + struct timespec ts; + if(::clock_gettime(CLOCK_REALTIME, &ts) == 0) + { + return (static_cast(ts.tv_sec) * 1000000000) + static_cast(ts.tv_nsec); + } +#endif + + auto now = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast(now).count(); + } + +size_t OS::system_page_size() + { + const size_t default_page_size = 4096; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + long p = ::sysconf(_SC_PAGESIZE); + if(p > 1) + return static_cast(p); + else + return default_page_size; +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + BOTAN_UNUSED(default_page_size); + SYSTEM_INFO sys_info; + ::GetSystemInfo(&sys_info); + return sys_info.dwPageSize; +#else + return default_page_size; +#endif + } + +size_t OS::get_memory_locking_limit() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) && defined(RLIMIT_MEMLOCK) + /* + * If RLIMIT_MEMLOCK is not defined, likely the OS does not support + * unprivileged mlock calls. + * + * Linux defaults to only 64 KiB of mlockable memory per process + * (too small) but BSDs offer a small fraction of total RAM (more + * than we need). Bound the total mlock size to 512 KiB which is + * enough to run the entire test suite without spilling to non-mlock + * memory (and thus presumably also enough for many useful + * programs), but small enough that we should not cause problems + * even if many processes are mlocking on the same machine. + */ + const size_t user_req = read_env_variable_sz("BOTAN_MLOCK_POOL_SIZE", BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB); + + const size_t mlock_requested = std::min(user_req, BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB); + + if(mlock_requested > 0) + { + struct ::rlimit limits; + + ::getrlimit(RLIMIT_MEMLOCK, &limits); + + if(limits.rlim_cur < limits.rlim_max) + { + limits.rlim_cur = limits.rlim_max; + ::setrlimit(RLIMIT_MEMLOCK, &limits); + ::getrlimit(RLIMIT_MEMLOCK, &limits); + } + + return std::min(limits.rlim_cur, mlock_requested * 1024); + } + +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + SIZE_T working_min = 0, working_max = 0; + if(!::GetProcessWorkingSetSize(::GetCurrentProcess(), &working_min, &working_max)) + { + return 0; + } + + // According to Microsoft MSDN: + // The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead + // In the book "Windows Internals Part 2": the maximum lockable pages are minimum working set size - 8 pages + // But the information in the book seems to be inaccurate/outdated + // I've tested this on Windows 8.1 x64, Windows 10 x64 and Windows 7 x86 + // On all three OS the value is 11 instead of 8 + const size_t overhead = OS::system_page_size() * 11; + if(working_min > overhead) + { + const size_t lockable_bytes = working_min - overhead; + return std::min(lockable_bytes, BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024); + } +#endif + + // Not supported on this platform + return 0; + } + +bool OS::read_env_variable(std::string& value_out, const std::string& name) + { + value_out = ""; + + if(running_in_privileged_state()) + return false; + +#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC) + char val[128] = { 0 }; + size_t req_size = 0; + if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0) + { + value_out = std::string(val, req_size); + return true; + } +#else + if(const char* val = std::getenv(name.c_str())) + { + value_out = val; + return true; + } +#endif + + return false; + } + +size_t OS::read_env_variable_sz(const std::string& name, size_t def) + { + std::string value; + if(read_env_variable(value, name)) + { + try + { + const size_t val = std::stoul(value, nullptr); + return val; + } + catch(std::exception&) { /* ignore it */ } + } + + return def; + } + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + +namespace { + +int get_locked_fd() + { +#if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS) + // On Darwin, tagging anonymous pages allows vmmap to track these. + // Allowed from 240 to 255 for userland applications + static constexpr int default_locked_fd = 255; + int locked_fd = default_locked_fd; + + if(size_t locked_fdl = OS::read_env_variable_sz("BOTAN_LOCKED_FD", default_locked_fd)) + { + if(locked_fdl < 240 || locked_fdl > 255) + { + locked_fdl = default_locked_fd; + } + locked_fd = static_cast(locked_fdl); + } + return VM_MAKE_TAG(locked_fd); +#else + return -1; +#endif + } + +} + +#endif + +std::vector OS::allocate_locked_pages(size_t count) + { + std::vector result; + +#if (defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)) || defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + + result.reserve(count); + + const size_t page_size = OS::system_page_size(); + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + static const int locked_fd = get_locked_fd(); +#endif + + for(size_t i = 0; i != count; ++i) + { + void* ptr = nullptr; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + +#if !defined(MAP_ANONYMOUS) + #define MAP_ANONYMOUS MAP_ANON +#endif + +#if !defined(MAP_NOCORE) +#if defined(MAP_CONCEAL) + #define MAP_NOCORE MAP_CONCEAL +#else + #define MAP_NOCORE 0 +#endif +#endif + +#if !defined(PROT_MAX) + #define PROT_MAX(p) 0 +#endif + const int pflags = PROT_READ | PROT_WRITE; + + ptr = ::mmap(nullptr, 3*page_size, + pflags | PROT_MAX(pflags), + MAP_ANONYMOUS | MAP_PRIVATE | MAP_NOCORE, + /*fd=*/locked_fd, /*offset=*/0); + + if(ptr == MAP_FAILED) + { + continue; + } + + // lock the data page + if(::mlock(static_cast(ptr) + page_size, page_size) != 0) + { + ::munmap(ptr, 3*page_size); + continue; + } + +#if defined(MADV_DONTDUMP) + // we ignore errors here, as DONTDUMP is just a bonus + ::madvise(static_cast(ptr) + page_size, page_size, MADV_DONTDUMP); +#endif + +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + ptr = ::VirtualAlloc(nullptr, 3*page_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + if(ptr == nullptr) + continue; + + if(::VirtualLock(static_cast(ptr) + page_size, page_size) == 0) + { + ::VirtualFree(ptr, 0, MEM_RELEASE); + continue; + } +#endif + + std::memset(ptr, 0, 3*page_size); // zero data page and both guard pages + + // Make guard page preceeding the data page + page_prohibit_access(static_cast(ptr)); + // Make guard page following the data page + page_prohibit_access(static_cast(ptr) + 2*page_size); + + result.push_back(static_cast(ptr) + page_size); + } +#else + BOTAN_UNUSED(count); +#endif + + return result; + } + +void OS::page_allow_access(void* page) + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + const size_t page_size = OS::system_page_size(); + ::mprotect(page, page_size, PROT_READ | PROT_WRITE); +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + const size_t page_size = OS::system_page_size(); + DWORD old_perms = 0; + ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms); + BOTAN_UNUSED(old_perms); +#else + BOTAN_UNUSED(page); +#endif + } + +void OS::page_prohibit_access(void* page) + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + const size_t page_size = OS::system_page_size(); + ::mprotect(page, page_size, PROT_NONE); +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + const size_t page_size = OS::system_page_size(); + DWORD old_perms = 0; + ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms); + BOTAN_UNUSED(old_perms); +#else + BOTAN_UNUSED(page); +#endif + } + +void OS::free_locked_pages(const std::vector& pages) + { + const size_t page_size = OS::system_page_size(); + + for(size_t i = 0; i != pages.size(); ++i) + { + void* ptr = pages[i]; + + secure_scrub_memory(ptr, page_size); + + // ptr points to the data page, guard pages are before and after + page_allow_access(static_cast(ptr) - page_size); + page_allow_access(static_cast(ptr) + page_size); + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + ::munlock(ptr, page_size); + ::munmap(static_cast(ptr) - page_size, 3*page_size); +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + ::VirtualUnlock(ptr, page_size); + ::VirtualFree(static_cast(ptr) - page_size, 0, MEM_RELEASE); +#endif + } + } + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) + +namespace { + +static ::sigjmp_buf g_sigill_jmp_buf; + +void botan_sigill_handler(int) + { + siglongjmp(g_sigill_jmp_buf, /*non-zero return value*/1); + } + +} + +#endif + +int OS::run_cpu_instruction_probe(std::function probe_fn) + { + volatile int probe_result = -3; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) + struct sigaction old_sigaction; + struct sigaction sigaction; + + sigaction.sa_handler = botan_sigill_handler; + sigemptyset(&sigaction.sa_mask); + sigaction.sa_flags = 0; + + int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction); + + if(rc != 0) + throw System_Error("run_cpu_instruction_probe sigaction failed", errno); + + rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1); + + if(rc == 0) + { + // first call to sigsetjmp + probe_result = probe_fn(); + } + else if(rc == 1) + { + // non-local return from siglongjmp in signal handler: return error + probe_result = -1; + } + + // Restore old SIGILL handler, if any + rc = ::sigaction(SIGILL, &old_sigaction, nullptr); + if(rc != 0) + throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno); + +#else + BOTAN_UNUSED(probe_fn); +#endif + + return probe_result; + } + +std::unique_ptr OS::suppress_echo_on_terminal() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + class POSIX_Echo_Suppression : public Echo_Suppression + { + public: + POSIX_Echo_Suppression() + { + m_stdin_fd = fileno(stdin); + if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0) + throw System_Error("Getting terminal status failed", errno); + + struct termios noecho_flags = m_old_termios; + noecho_flags.c_lflag &= ~ECHO; + noecho_flags.c_lflag |= ECHONL; + + if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0) + throw System_Error("Clearing terminal echo bit failed", errno); + } + + void reenable_echo() override + { + if(m_stdin_fd > 0) + { + if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0) + throw System_Error("Restoring terminal echo bit failed", errno); + m_stdin_fd = -1; + } + } + + ~POSIX_Echo_Suppression() + { + try + { + reenable_echo(); + } + catch(...) + { + } + } + + private: + int m_stdin_fd; + struct termios m_old_termios; + }; + + return std::unique_ptr(new POSIX_Echo_Suppression); + +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + + class Win32_Echo_Suppression : public Echo_Suppression + { + public: + Win32_Echo_Suppression() + { + m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE); + if(::GetConsoleMode(m_input_handle, &m_console_state) == 0) + throw System_Error("Getting console mode failed", ::GetLastError()); + + DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + if(::SetConsoleMode(m_input_handle, new_mode) == 0) + throw System_Error("Setting console mode failed", ::GetLastError()); + } + + void reenable_echo() override + { + if(m_input_handle != INVALID_HANDLE_VALUE) + { + if(::SetConsoleMode(m_input_handle, m_console_state) == 0) + throw System_Error("Setting console mode failed", ::GetLastError()); + m_input_handle = INVALID_HANDLE_VALUE; + } + } + + ~Win32_Echo_Suppression() + { + try + { + reenable_echo(); + } + catch(...) + { + } + } + + private: + HANDLE m_input_handle; + DWORD m_console_state; + }; + + return std::unique_ptr(new Win32_Echo_Suppression); + +#else + + // Not supported on this platform, return null + return std::unique_ptr(); +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/utils/os_utils.h b/comm/third_party/botan/src/lib/utils/os_utils.h new file mode 100644 index 0000000000..d31dcb3baf --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/os_utils.h @@ -0,0 +1,200 @@ +/* +* OS specific utility functions +* (C) 2015,2016,2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OS_UTILS_H_ +#define BOTAN_OS_UTILS_H_ + +#include +#include +#include +#include + +namespace Botan { + +namespace OS { + +/* +* This header is internal (not installed) and these functions are not +* intended to be called by applications. However they are given public +* visibility (using BOTAN_TEST_API macro) for the tests. This also probably +* allows them to be overridden by the application on ELF systems, but +* this hasn't been tested. +*/ + +/** +* @return process ID assigned by the operating system. +* On Unix and Windows systems, this always returns a result +* On IncludeOS it returns 0 since there is no process ID to speak of +* in a unikernel. +*/ +uint32_t BOTAN_TEST_API get_process_id(); + +/** +* Test if we are currently running with elevated permissions +* eg setuid, setgid, or with POSIX caps set. +*/ +bool running_in_privileged_state(); + +/** +* @return CPU processor clock, if available +* +* On Windows, calls QueryPerformanceCounter. +* +* Under GCC or Clang on supported platforms the hardware cycle counter is queried. +* Currently supported processors are x86, PPC, Alpha, SPARC, IA-64, S/390x, and HP-PA. +* If no CPU cycle counter is available on this system, returns zero. +*/ +uint64_t BOTAN_TEST_API get_cpu_cycle_counter(); + +size_t BOTAN_TEST_API get_cpu_total(); +size_t BOTAN_TEST_API get_cpu_available(); + +/** +* Return the ELF auxiliary vector cooresponding to the given ID. +* This only makes sense on Unix-like systems and is currently +* only supported on Linux, Android, and FreeBSD. +* +* Returns zero if not supported on the current system or if +* the id provided is not known. +*/ +unsigned long get_auxval(unsigned long id); + +/* +* @return best resolution timestamp available +* +* The epoch and update rate of this clock is arbitrary and depending +* on the hardware it may not tick at a constant rate. +* +* Uses hardware cycle counter, if available. +* On POSIX platforms clock_gettime is used with a monotonic timer +* As a final fallback std::chrono::high_resolution_clock is used. +*/ +uint64_t BOTAN_TEST_API get_high_resolution_clock(); + +/** +* @return system clock (reflecting wall clock) with best resolution +* available, normalized to nanoseconds resolution. +*/ +uint64_t BOTAN_TEST_API get_system_timestamp_ns(); + +/** +* @return maximum amount of memory (in bytes) Botan could/should +* hyptothetically allocate for the memory poool. Reads environment +* variable "BOTAN_MLOCK_POOL_SIZE", set to "0" to disable pool. +*/ +size_t get_memory_locking_limit(); + +/** +* Return the size of a memory page, if that can be derived on the +* current system. Otherwise returns some default value (eg 4096) +*/ +size_t system_page_size(); + +/** +* Read the value of an environment variable, setting it to value_out if it +* exists. Returns false and sets value_out to empty string if no such variable +* is set. If the process seems to be running in a privileged state (such as +* setuid) then always returns false and does not examine the environment. +*/ +bool read_env_variable(std::string& value_out, const std::string& var_name); + +/** +* Read the value of an environment variable and convert it to an +* integer. If not set or conversion fails, returns the default value. +* +* If the process seems to be running in a privileged state (such as setuid) +* then always returns nullptr, similiar to glibc's secure_getenv. +*/ +size_t read_env_variable_sz(const std::string& var_name, size_t def_value = 0); + +/** +* Request count pages of RAM which are locked into memory using mlock, +* VirtualLock, or some similar OS specific API. Free it with free_locked_pages. +* +* Returns an empty list on failure. This function is allowed to return fewer +* than count pages. +* +* The contents of the allocated pages are undefined. +* +* Each page is preceded by and followed by a page which is marked +* as noaccess, such that accessing it will cause a crash. This turns +* out of bound reads/writes into crash events. +* +* @param count requested number of locked pages +*/ +std::vector allocate_locked_pages(size_t count); + +/** +* Free memory allocated by allocate_locked_pages +* @param pages a list of pages returned by allocate_locked_pages +*/ +void free_locked_pages(const std::vector& pages); + +/** +* Set the MMU to prohibit access to this page +*/ +void page_prohibit_access(void* page); + +/** +* Set the MMU to allow R/W access to this page +*/ +void page_allow_access(void* page); + + +/** +* Run a probe instruction to test for support for a CPU instruction. +* Runs in system-specific env that catches illegal instructions; this +* function always fails if the OS doesn't provide this. +* Returns value of probe_fn, if it could run. +* If error occurs, returns negative number. +* This allows probe_fn to indicate errors of its own, if it wants. +* For example the instruction might not only be only available on some +* CPUs, but also buggy on some subset of these - the probe function +* can test to make sure the instruction works properly before +* indicating that the instruction is available. +* +* @warning on Unix systems uses signal handling in a way that is not +* thread safe. It should only be called in a single-threaded context +* (ie, at static init time). +* +* If probe_fn throws an exception the result is undefined. +* +* Return codes: +* -1 illegal instruction detected +*/ +int BOTAN_TEST_API run_cpu_instruction_probe(std::function probe_fn); + +/** +* Represents a terminal state +*/ +class BOTAN_UNSTABLE_API Echo_Suppression + { + public: + /** + * Reenable echo on this terminal. Can be safely called + * multiple times. May throw if an error occurs. + */ + virtual void reenable_echo() = 0; + + /** + * Implicitly calls reenable_echo, but swallows/ignored all + * errors which would leave the terminal in an invalid state. + */ + virtual ~Echo_Suppression() = default; + }; + +/** +* Suppress echo on the terminal +* Returns null if this operation is not supported on the current system. +*/ +std::unique_ptr BOTAN_UNSTABLE_API suppress_echo_on_terminal(); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/parsing.cpp b/comm/third_party/botan/src/lib/utils/parsing.cpp new file mode 100644 index 0000000000..ff3d4ac0a2 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/parsing.cpp @@ -0,0 +1,458 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013,2014,2015,2018 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_ASN1) + #include +#endif + +namespace Botan { + +uint16_t to_uint16(const std::string& str) + { + const uint32_t x = to_u32bit(str); + + if(x >> 16) + throw Invalid_Argument("Integer value exceeds 16 bit range"); + + return static_cast(x); + } + +uint32_t to_u32bit(const std::string& str) + { + // std::stoul is not strict enough. Ensure that str is digit only [0-9]* + for(const char chr : str) + { + if(chr < '0' || chr > '9') + { + std::string chrAsString(1, chr); + throw Invalid_Argument("String contains non-digit char: " + chrAsString); + } + } + + const unsigned long int x = std::stoul(str); + + if(sizeof(unsigned long int) > 4) + { + // x might be uint64 + if (x > std::numeric_limits::max()) + { + throw Invalid_Argument("Integer value of " + str + " exceeds 32 bit range"); + } + } + + return static_cast(x); + } + +/* +* Convert a string into a time duration +*/ +uint32_t timespec_to_u32bit(const std::string& timespec) + { + if(timespec.empty()) + return 0; + + const char suffix = timespec[timespec.size()-1]; + std::string value = timespec.substr(0, timespec.size()-1); + + uint32_t scale = 1; + + if(Charset::is_digit(suffix)) + value += suffix; + else if(suffix == 's') + scale = 1; + else if(suffix == 'm') + scale = 60; + else if(suffix == 'h') + scale = 60 * 60; + else if(suffix == 'd') + scale = 24 * 60 * 60; + else if(suffix == 'y') + scale = 365 * 24 * 60 * 60; + else + throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); + + return scale * to_u32bit(value); + } + +/* +* Parse a SCAN-style algorithm name +*/ +std::vector parse_algorithm_name(const std::string& namex) + { + if(namex.find('(') == std::string::npos && + namex.find(')') == std::string::npos) + return std::vector(1, namex); + + std::string name = namex, substring; + std::vector elems; + size_t level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for(auto i = name.begin(); i != name.end(); ++i) + { + char c = *i; + + if(c == '(') + ++level; + if(c == ')') + { + if(level == 1 && i == name.end() - 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + return elems; + } + + if(level == 0 || (level == 1 && i != name.end() - 1)) + throw Invalid_Algorithm_Name(namex); + --level; + } + + if(c == ',' && level == 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + substring.clear(); + } + else + substring += c; + } + + if(!substring.empty()) + throw Invalid_Algorithm_Name(namex); + + return elems; + } + +std::vector split_on(const std::string& str, char delim) + { + return split_on_pred(str, [delim](char c) { return c == delim; }); + } + +std::vector split_on_pred(const std::string& str, + std::function pred) + { + std::vector elems; + if(str.empty()) return elems; + + std::string substr; + for(auto i = str.begin(); i != str.end(); ++i) + { + if(pred(*i)) + { + if(!substr.empty()) + elems.push_back(substr); + substr.clear(); + } + else + substr += *i; + } + + if(substr.empty()) + throw Invalid_Argument("Unable to split string: " + str); + elems.push_back(substr); + + return elems; + } + +/* +* Join a string +*/ +std::string string_join(const std::vector& strs, char delim) + { + std::string out = ""; + + for(size_t i = 0; i != strs.size(); ++i) + { + if(i != 0) + out += delim; + out += strs[i]; + } + + return out; + } + +/* +* Parse an ASN.1 OID string +*/ +std::vector parse_asn1_oid(const std::string& oid) + { +#if defined(BOTAN_HAS_ASN1) + return OID(oid).get_components(); +#else + BOTAN_UNUSED(oid); + throw Not_Implemented("ASN1 support not available"); +#endif + } + +/* +* X.500 String Comparison +*/ +bool x500_name_cmp(const std::string& name1, const std::string& name2) + { + auto p1 = name1.begin(); + auto p2 = name2.begin(); + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + while(p1 != name1.end() && p2 != name2.end()) + { + if(Charset::is_space(*p1)) + { + if(!Charset::is_space(*p2)) + return false; + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if(p1 == name1.end() && p2 == name2.end()) + return true; + if(p1 == name1.end() || p2 == name2.end()) + return false; + } + + if(!Charset::caseless_cmp(*p1, *p2)) + return false; + ++p1; + ++p2; + } + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; + } + +/* +* Convert a decimal-dotted string to binary IP +*/ +uint32_t string_to_ipv4(const std::string& str) + { + std::vector parts = split_on(str, '.'); + + if(parts.size() != 4) + throw Decoding_Error("Invalid IP string " + str); + + uint32_t ip = 0; + + for(auto part = parts.begin(); part != parts.end(); ++part) + { + uint32_t octet = to_u32bit(*part); + + if(octet > 255) + throw Decoding_Error("Invalid IP string " + str); + + ip = (ip << 8) | (octet & 0xFF); + } + + return ip; + } + +/* +* Convert an IP address to decimal-dotted string +*/ +std::string ipv4_to_string(uint32_t ip) + { + std::string str; + + for(size_t i = 0; i != sizeof(ip); ++i) + { + if(i) + str += "."; + str += std::to_string(get_byte(i, ip)); + } + + return str; + } + +std::string erase_chars(const std::string& str, const std::set& chars) + { + std::string out; + + for(auto c: str) + if(chars.count(c) == 0) + out += c; + + return out; + } + +std::string replace_chars(const std::string& str, + const std::set& chars, + char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(chars.count(out[i])) + out[i] = to_char; + + return out; + } + +std::string replace_char(const std::string& str, char from_char, char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(out[i] == from_char) + out[i] = to_char; + + return out; + } + +std::string tolower_string(const std::string& in) + { + std::string s = in; + for(size_t i = 0; i != s.size(); ++i) + { + const int cu = static_cast(s[i]); + if(std::isalpha(cu)) + s[i] = static_cast(std::tolower(cu)); + } + return s; + } + +bool host_wildcard_match(const std::string& issued_, const std::string& host_) + { + const std::string issued = tolower_string(issued_); + const std::string host = tolower_string(host_); + + if(host.empty() || issued.empty()) + return false; + + /* + If there are embedded nulls in your issued name + Well I feel bad for you son + */ + if(std::count(issued.begin(), issued.end(), char(0)) > 0) + return false; + + // If more than one wildcard, then issued name is invalid + const size_t stars = std::count(issued.begin(), issued.end(), '*'); + if(stars > 1) + return false; + + // '*' is not a valid character in DNS names so should not appear on the host side + if(std::count(host.begin(), host.end(), '*') != 0) + return false; + + // Similarly a DNS name can't end in . + if(host[host.size() - 1] == '.') + return false; + + // And a host can't have an empty name component, so reject that + if(host.find("..") != std::string::npos) + return false; + + // Exact match: accept + if(issued == host) + { + return true; + } + + /* + Otherwise it might be a wildcard + + If the issued size is strictly longer than the hostname size it + couldn't possibly be a match, even if the issued value is a + wildcard. The only exception is when the wildcard ends up empty + (eg www.example.com matches www*.example.com) + */ + if(issued.size() > host.size() + 1) + { + return false; + } + + // If no * at all then not a wildcard, and so not a match + if(stars != 1) + { + return false; + } + + /* + Now walk through the issued string, making sure every character + matches. When we come to the (singular) '*', jump forward in the + hostname by the corresponding amount. We know exactly how much + space the wildcard takes because it must be exactly `len(host) - + len(issued) + 1 chars`. + + We also verify that the '*' comes in the leftmost component, and + doesn't skip over any '.' in the hostname. + */ + size_t dots_seen = 0; + size_t host_idx = 0; + + for(size_t i = 0; i != issued.size(); ++i) + { + dots_seen += (issued[i] == '.'); + + if(issued[i] == '*') + { + // Fail: wildcard can only come in leftmost component + if(dots_seen > 0) + { + return false; + } + + /* + Since there is only one * we know the tail of the issued and + hostname must be an exact match. In this case advance host_idx + to match. + */ + const size_t advance = (host.size() - issued.size() + 1); + + if(host_idx + advance > host.size()) // shouldn't happen + return false; + + // Can't be any intervening .s that we would have skipped + if(std::count(host.begin() + host_idx, + host.begin() + host_idx + advance, '.') != 0) + return false; + + host_idx += advance; + } + else + { + if(issued[i] != host[host_idx]) + { + return false; + } + + host_idx += 1; + } + } + + // Wildcard issued name must have at least 3 components + if(dots_seen < 2) + { + return false; + } + + return true; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/parsing.h b/comm/third_party/botan/src/lib/utils/parsing.h new file mode 100644 index 0000000000..d2c0b5f8c8 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/parsing.h @@ -0,0 +1,181 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PARSING_UTILS_H_ +#define BOTAN_PARSING_UTILS_H_ + +#include +#include +#include +#include + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(parsing.h) + +namespace Botan { + +/** +* Parse a SCAN-style algorithm name +* @param scan_name the name +* @return the name components +*/ +BOTAN_PUBLIC_API(2,0) std::vector +parse_algorithm_name(const std::string& scan_name); + +/** +* Split a string +* @param str the input string +* @param delim the delimitor +* @return string split by delim +*/ +BOTAN_PUBLIC_API(2,0) std::vector split_on( + const std::string& str, char delim); + +/** +* Split a string on a character predicate +* @param str the input string +* @param pred the predicate +* +* This function will likely be removed in a future release +*/ +BOTAN_PUBLIC_API(2,0) std::vector +split_on_pred(const std::string& str, + std::function pred); + +/** +* Erase characters from a string +*/ +BOTAN_PUBLIC_API(2,0) +BOTAN_DEPRECATED("Unused") +std::string erase_chars(const std::string& str, const std::set& chars); + +/** +* Replace a character in a string +* @param str the input string +* @param from_char the character to replace +* @param to_char the character to replace it with +* @return str with all instances of from_char replaced by to_char +*/ +BOTAN_PUBLIC_API(2,0) +BOTAN_DEPRECATED("Unused") +std::string replace_char(const std::string& str, + char from_char, + char to_char); + +/** +* Replace a character in a string +* @param str the input string +* @param from_chars the characters to replace +* @param to_char the character to replace it with +* @return str with all instances of from_chars replaced by to_char +*/ +BOTAN_PUBLIC_API(2,0) +BOTAN_DEPRECATED("Unused") +std::string replace_chars(const std::string& str, + const std::set& from_chars, + char to_char); + +/** +* Join a string +* @param strs strings to join +* @param delim the delimitor +* @return string joined by delim +*/ +BOTAN_PUBLIC_API(2,0) +std::string string_join(const std::vector& strs, + char delim); + +/** +* Parse an ASN.1 OID +* @param oid the OID in string form +* @return OID components +*/ +BOTAN_PUBLIC_API(2,0) std::vector +BOTAN_DEPRECATED("Use OID::from_string(oid).get_components()") parse_asn1_oid(const std::string& oid); + +/** +* Compare two names using the X.509 comparison algorithm +* @param name1 the first name +* @param name2 the second name +* @return true if name1 is the same as name2 by the X.509 comparison rules +*/ +BOTAN_PUBLIC_API(2,0) +bool x500_name_cmp(const std::string& name1, + const std::string& name2); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_PUBLIC_API(2,0) uint32_t to_u32bit(const std::string& str); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_PUBLIC_API(2,3) uint16_t to_uint16(const std::string& str); + +/** +* Convert a time specification to a number +* @param timespec the time specification +* @return number of seconds represented by timespec +*/ +BOTAN_PUBLIC_API(2,0) uint32_t BOTAN_DEPRECATED("Not used anymore") +timespec_to_u32bit(const std::string& timespec); + +/** +* Convert a string representation of an IPv4 address to a number +* @param ip_str the string representation +* @return integer IPv4 address +*/ +BOTAN_PUBLIC_API(2,0) uint32_t string_to_ipv4(const std::string& ip_str); + +/** +* Convert an IPv4 address to a string +* @param ip_addr the IPv4 address to convert +* @return string representation of the IPv4 address +*/ +BOTAN_PUBLIC_API(2,0) std::string ipv4_to_string(uint32_t ip_addr); + +std::map BOTAN_PUBLIC_API(2,0) read_cfg(std::istream& is); + +/** +* Accepts key value pairs deliminated by commas: +* +* "" (returns empty map) +* "K=V" (returns map {'K': 'V'}) +* "K1=V1,K2=V2" +* "K1=V1,K2=V2,K3=V3" +* "K1=V1,K2=V2,K3=a_value\,with\,commas_and_\=equals" +* +* Values may be empty, keys must be non-empty and unique. Duplicate +* keys cause an exception. +* +* Within both key and value, comma and equals can be escaped with +* backslash. Backslash can also be escaped. +*/ +std::map BOTAN_PUBLIC_API(2,8) read_kv(const std::string& kv); + +std::string BOTAN_PUBLIC_API(2,0) clean_ws(const std::string& s); + +std::string tolower_string(const std::string& s); + +/** +* Check if the given hostname is a match for the specified wildcard +*/ +bool BOTAN_PUBLIC_API(2,0) host_wildcard_match(const std::string& wildcard, + const std::string& host); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/poly_dbl/info.txt b/comm/third_party/botan/src/lib/utils/poly_dbl/info.txt new file mode 100644 index 0000000000..5aae5b44f4 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/poly_dbl/info.txt @@ -0,0 +1,7 @@ + +POLY_DBL -> 20170927 + + + +poly_dbl.h + diff --git a/comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.cpp b/comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.cpp new file mode 100644 index 0000000000..8c728a1480 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.cpp @@ -0,0 +1,115 @@ +/* +* (C) 2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* The minimum weight irreducible binary polynomial of size n +* +* See http://www.hpl.hp.com/techreports/98/HPL-98-135.pdf +*/ +enum class MinWeightPolynomial : uint64_t { + P64 = 0x1B, + P128 = 0x87, + P192 = 0x87, + P256 = 0x425, + P512 = 0x125, + P1024 = 0x80043, +}; + +template +void poly_double(uint8_t out[], const uint8_t in[]) + { + uint64_t W[LIMBS]; + load_be(W, in, LIMBS); + + const uint64_t POLY = static_cast(P); + + const uint64_t carry = POLY * (W[0] >> 63); + + BOTAN_IF_CONSTEXPR(LIMBS > 0) + { + for(size_t i = 0; i != LIMBS - 1; ++i) + W[i] = (W[i] << 1) ^ (W[i+1] >> 63); + } + + W[LIMBS-1] = (W[LIMBS-1] << 1) ^ carry; + + copy_out_be(out, LIMBS*8, W); + } + +template +void poly_double_le(uint8_t out[], const uint8_t in[]) + { + uint64_t W[LIMBS]; + load_le(W, in, LIMBS); + + const uint64_t POLY = static_cast(P); + + const uint64_t carry = POLY * (W[LIMBS-1] >> 63); + + BOTAN_IF_CONSTEXPR(LIMBS > 0) + { + for(size_t i = 0; i != LIMBS - 1; ++i) + W[LIMBS-1-i] = (W[LIMBS-1-i] << 1) ^ (W[LIMBS-2-i] >> 63); + } + + W[0] = (W[0] << 1) ^ carry; + + copy_out_le(out, LIMBS*8, W); + } + +} + +void poly_double_n(uint8_t out[], const uint8_t in[], size_t n) + { + switch(n) + { + case 8: + return poly_double<1, MinWeightPolynomial::P64>(out, in); + case 16: + return poly_double<2, MinWeightPolynomial::P128>(out, in); + case 24: + return poly_double<3, MinWeightPolynomial::P192>(out, in); + case 32: + return poly_double<4, MinWeightPolynomial::P256>(out, in); + case 64: + return poly_double<8, MinWeightPolynomial::P512>(out, in); + case 128: + return poly_double<16, MinWeightPolynomial::P1024>(out, in); + default: + throw Invalid_Argument("Unsupported size for poly_double_n"); + } + } + +void poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n) + { + switch(n) + { + case 8: + return poly_double_le<1, MinWeightPolynomial::P64>(out, in); + case 16: + return poly_double_le<2, MinWeightPolynomial::P128>(out, in); + case 24: + return poly_double_le<3, MinWeightPolynomial::P192>(out, in); + case 32: + return poly_double_le<4, MinWeightPolynomial::P256>(out, in); + case 64: + return poly_double_le<8, MinWeightPolynomial::P512>(out, in); + case 128: + return poly_double_le<16, MinWeightPolynomial::P1024>(out, in); + default: + throw Invalid_Argument("Unsupported size for poly_double_n_le"); + } + } + +} diff --git a/comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.h b/comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.h new file mode 100644 index 0000000000..7d9f523319 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/poly_dbl/poly_dbl.h @@ -0,0 +1,39 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POLY_DBL_H_ +#define BOTAN_POLY_DBL_H_ + +#include + +namespace Botan { + +/** +* Polynomial doubling in GF(2^n) +*/ +void BOTAN_TEST_API poly_double_n(uint8_t out[], const uint8_t in[], size_t n); + +/** +* Returns true iff poly_double_n is implemented for this size. +*/ +inline bool poly_double_supported_size(size_t n) + { + return (n == 8 || n == 16 || n == 24 || n == 32 || n == 64 || n == 128); + } + +inline void poly_double_n(uint8_t buf[], size_t n) + { + return poly_double_n(buf, buf, n); + } + +/* +* Little endian convention - used for XTS +*/ +void BOTAN_TEST_API poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/prefetch.h b/comm/third_party/botan/src/lib/utils/prefetch.h new file mode 100644 index 0000000000..92c41e5738 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/prefetch.h @@ -0,0 +1,39 @@ +/* +* Prefetching Operations +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PREFETCH_H_ +#define BOTAN_PREFETCH_H_ + +#include + +namespace Botan { + +template +inline void prefetch_readonly(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 0); +#endif + } + +template +inline void prefetch_readwrite(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 1); +#endif + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/read_cfg.cpp b/comm/third_party/botan/src/lib/utils/read_cfg.cpp new file mode 100644 index 0000000000..02f2e0ac81 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/read_cfg.cpp @@ -0,0 +1,63 @@ +/* +* Simple config/test file reader +* (C) 2013,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::string clean_ws(const std::string& s) + { + const char* ws = " \t\n"; + auto start = s.find_first_not_of(ws); + auto end = s.find_last_not_of(ws); + + if(start == std::string::npos) + return ""; + + if(end == std::string::npos) + return s.substr(start, end); + else + return s.substr(start, start + end + 1); + } + +std::map read_cfg(std::istream& is) + { + std::map kv; + size_t line = 0; + + while(is.good()) + { + std::string s; + + std::getline(is, s); + + ++line; + + if(s.empty() || s[0] == '#') + continue; + + s = clean_ws(s.substr(0, s.find('#'))); + + if(s.empty()) + continue; + + auto eq = s.find("="); + + if(eq == std::string::npos || eq == 0 || eq == s.size() - 1) + throw Decoding_Error("Bad read_cfg input '" + s + "' on line " + std::to_string(line)); + + const std::string key = clean_ws(s.substr(0, eq)); + const std::string val = clean_ws(s.substr(eq + 1, std::string::npos)); + + kv[key] = val; + } + + return kv; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/read_kv.cpp b/comm/third_party/botan/src/lib/utils/read_kv.cpp new file mode 100644 index 0000000000..cdc84c6229 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/read_kv.cpp @@ -0,0 +1,85 @@ +/* +* (C) 2018 Ribose Inc +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::map read_kv(const std::string& kv) + { + std::map m; + if(kv == "") + return m; + + std::vector parts; + + try + { + parts = split_on(kv, ','); + } + catch(std::exception&) + { + throw Invalid_Argument("Bad KV spec"); + } + + bool escaped = false; + bool reading_key = true; + std::string cur_key; + std::string cur_val; + + for(char c : kv) + { + if(c == '\\' && !escaped) + { + escaped = true; + } + else if(c == ',' && !escaped) + { + if(cur_key.empty()) + throw Invalid_Argument("Bad KV spec empty key"); + + if(m.find(cur_key) != m.end()) + throw Invalid_Argument("Bad KV spec duplicated key"); + m[cur_key] = cur_val; + cur_key = ""; + cur_val = ""; + reading_key = true; + } + else if(c == '=' && !escaped) + { + if(reading_key == false) + throw Invalid_Argument("Bad KV spec unexpected equals sign"); + reading_key = false; + } + else + { + if(reading_key) + cur_key += c; + else + cur_val += c; + + if(escaped) + escaped = false; + } + } + + if(!cur_key.empty()) + { + if(reading_key == false) + { + if(m.find(cur_key) != m.end()) + throw Invalid_Argument("Bad KV spec duplicated key"); + m[cur_key] = cur_val; + } + else + throw Invalid_Argument("Bad KV spec incomplete string"); + } + + return m; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/rotate.h b/comm/third_party/botan/src/lib/utils/rotate.h new file mode 100644 index 0000000000..8599a2695f --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/rotate.h @@ -0,0 +1,112 @@ +/* +* Word Rotation Operations +* (C) 1999-2008,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_WORD_ROTATE_H_ +#define BOTAN_WORD_ROTATE_H_ + +#include + +BOTAN_FUTURE_INTERNAL_HEADER(rotate.h) + +namespace Botan { + +/** +* Bit rotation left by a compile-time constant amount +* @param input the input word +* @return input rotated left by ROT bits +*/ +template +inline constexpr T rotl(T input) + { + static_assert(ROT > 0 && ROT < 8*sizeof(T), "Invalid rotation constant"); + return static_cast((input << ROT) | (input >> (8*sizeof(T) - ROT))); + } + +/** +* Bit rotation right by a compile-time constant amount +* @param input the input word +* @return input rotated right by ROT bits +*/ +template +inline constexpr T rotr(T input) + { + static_assert(ROT > 0 && ROT < 8*sizeof(T), "Invalid rotation constant"); + return static_cast((input >> ROT) | (input << (8*sizeof(T) - ROT))); + } + +/** +* Bit rotation left, variable rotation amount +* @param input the input word +* @param rot the number of bits to rotate, must be between 0 and sizeof(T)*8-1 +* @return input rotated left by rot bits +*/ +template +inline T rotl_var(T input, size_t rot) + { + return rot ? static_cast((input << rot) | (input >> (sizeof(T)*8 - rot))) : input; + } + +/** +* Bit rotation right, variable rotation amount +* @param input the input word +* @param rot the number of bits to rotate, must be between 0 and sizeof(T)*8-1 +* @return input rotated right by rot bits +*/ +template +inline T rotr_var(T input, size_t rot) + { + return rot ? static_cast((input >> rot) | (input << (sizeof(T)*8 - rot))) : input; + } + +#if defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) || defined(BOTAN_TARGET_ARCH_IS_X86_32) + +template<> +inline uint32_t rotl_var(uint32_t input, size_t rot) + { + asm("roll %1,%0" + : "+r" (input) + : "c" (static_cast(rot)) + : "cc"); + return input; + } + +template<> +inline uint32_t rotr_var(uint32_t input, size_t rot) + { + asm("rorl %1,%0" + : "+r" (input) + : "c" (static_cast(rot)) + : "cc"); + return input; + } + +#endif + +#endif + + +template +BOTAN_DEPRECATED("Use rotl or rotl_var") +inline T rotate_left(T input, size_t rot) + { + // rotl_var does not reduce + return rotl_var(input, rot % (8 * sizeof(T))); + } + +template +BOTAN_DEPRECATED("Use rotr or rotr_var") +inline T rotate_right(T input, size_t rot) + { + // rotr_var does not reduce + return rotr_var(input, rot % (8 * sizeof(T))); + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/rounding.h b/comm/third_party/botan/src/lib/utils/rounding.h new file mode 100644 index 0000000000..ae0aedf07c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/rounding.h @@ -0,0 +1,56 @@ +/* +* Integer Rounding Functions +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ROUNDING_H_ +#define BOTAN_ROUNDING_H_ + +#include + +namespace Botan { + +/** +* Round up +* @param n a non-negative integer +* @param align_to the alignment boundary +* @return n rounded up to a multiple of align_to +*/ +inline size_t round_up(size_t n, size_t align_to) + { + BOTAN_ARG_CHECK(align_to != 0, "align_to must not be 0"); + + if(n % align_to) + n += align_to - (n % align_to); + return n; + } + +/** +* Round down +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded down to a multiple of align_to +*/ +template +inline constexpr T round_down(T n, T align_to) + { + return (align_to == 0) ? n : (n - (n % align_to)); + } + +/** +* Clamp +*/ +inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound) + { + if(n < lower_bound) + return lower_bound; + if(n > upper_bound) + return upper_bound; + return n; + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/safeint.h b/comm/third_party/botan/src/lib/utils/safeint.h new file mode 100644 index 0000000000..5c9ea49553 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/safeint.h @@ -0,0 +1,41 @@ +/* +* Safe(r) Integer Handling +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTILS_SAFE_INT_H_ +#define BOTAN_UTILS_SAFE_INT_H_ + +#include +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) Integer_Overflow_Detected final : public Exception + { + public: + Integer_Overflow_Detected(const std::string& file, int line) : + Exception("Integer overflow detected at " + file + ":" + std::to_string(line)) + {} + + ErrorType error_type() const noexcept override { return ErrorType::InternalError; } + }; + +inline size_t checked_add(size_t x, size_t y, const char* file, int line) + { + // TODO: use __builtin_x_overflow on GCC and Clang + size_t z = x + y; + if(z < x) + { + throw Integer_Overflow_Detected(file, line); + } + return z; + } + +#define BOTAN_CHECKED_ADD(x,y) checked_add(x,y,__FILE__,__LINE__) + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/simd/info.txt b/comm/third_party/botan/src/lib/utils/simd/info.txt new file mode 100644 index 0000000000..4a7044afc4 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/simd/info.txt @@ -0,0 +1,27 @@ + +SIMD_32 -> 20131128 + + + +simd_32.h + + + +x86_32:sse2 +x86_64:sse2 +x32:sse2 +arm32:neon +arm64:neon +ppc32:altivec +ppc64:altivec + + + +x86_32 +x86_64 +x32 +arm32 +arm64 +ppc32 +ppc64 + diff --git a/comm/third_party/botan/src/lib/utils/simd/simd_32.h b/comm/third_party/botan/src/lib/utils/simd/simd_32.h new file mode 100644 index 0000000000..5cbc32a187 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/simd/simd_32.h @@ -0,0 +1,621 @@ +/* +* Lightweight wrappers for SIMD operations +* (C) 2009,2011,2016,2017,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SIMD_32_H_ +#define BOTAN_SIMD_32_H_ + +#include + +#if defined(BOTAN_TARGET_SUPPORTS_SSE2) + #include + #define BOTAN_SIMD_USE_SSE2 + +#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) + #include + #include + #include + #undef vector + #undef bool + #define BOTAN_SIMD_USE_ALTIVEC + +#elif defined(BOTAN_TARGET_SUPPORTS_NEON) + #include + #include + #define BOTAN_SIMD_USE_NEON + +#else + #error "No SIMD instruction set enabled" +#endif + +#if defined(BOTAN_SIMD_USE_SSE2) + #define BOTAN_SIMD_ISA "sse2" + #define BOTAN_VPERM_ISA "ssse3" + #define BOTAN_CLMUL_ISA "pclmul" +#elif defined(BOTAN_SIMD_USE_NEON) + #if defined(BOTAN_TARGET_ARCH_IS_ARM64) + #define BOTAN_SIMD_ISA "+simd" + #define BOTAN_CLMUL_ISA "+crypto" + #else + #define BOTAN_SIMD_ISA "fpu=neon" + #endif + #define BOTAN_VPERM_ISA BOTAN_SIMD_ISA +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + #define BOTAN_SIMD_ISA "altivec" + #define BOTAN_VPERM_ISA "altivec" + #define BOTAN_CLMUL_ISA "crypto" +#endif + +namespace Botan { + +#if defined(BOTAN_SIMD_USE_SSE2) + typedef __m128i native_simd_type; +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + typedef __vector unsigned int native_simd_type; +#elif defined(BOTAN_SIMD_USE_NEON) + typedef uint32x4_t native_simd_type; +#endif + +/** +* 4x32 bit SIMD register +* +* This class is not a general purpose SIMD type, and only offers +* instructions needed for evaluation of specific crypto primitives. +* For example it does not currently have equality operators of any +* kind. +* +* Implemented for SSE2, VMX (Altivec), and NEON. +*/ +class SIMD_4x32 final + { + public: + + SIMD_4x32& operator=(const SIMD_4x32& other) = default; + SIMD_4x32(const SIMD_4x32& other) = default; + + SIMD_4x32& operator=(SIMD_4x32&& other) = default; + SIMD_4x32(SIMD_4x32&& other) = default; + + /** + * Zero initialize SIMD register with 4 32-bit elements + */ + SIMD_4x32() // zero initialized + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_setzero_si128(); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_simd = vec_splat_u32(0); +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = vdupq_n_u32(0); +#endif + } + + /** + * Load SIMD register with 4 32-bit elements + */ + explicit SIMD_4x32(const uint32_t B[4]) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_loadu_si128(reinterpret_cast(B)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + __vector unsigned int val = { B[0], B[1], B[2], B[3]}; + m_simd = val; +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = vld1q_u32(B); +#endif + } + + /** + * Load SIMD register with 4 32-bit elements + */ + SIMD_4x32(uint32_t B0, uint32_t B1, uint32_t B2, uint32_t B3) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_set_epi32(B3, B2, B1, B0); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + __vector unsigned int val = {B0, B1, B2, B3}; + m_simd = val; +#elif defined(BOTAN_SIMD_USE_NEON) + // Better way to do this? + const uint32_t B[4] = { B0, B1, B2, B3 }; + m_simd = vld1q_u32(B); +#endif + } + + /** + * Load SIMD register with one 32-bit element repeated + */ + static SIMD_4x32 splat(uint32_t B) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_set1_epi32(B)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vdupq_n_u32(B)); +#else + return SIMD_4x32(B, B, B, B); +#endif + } + + /** + * Load SIMD register with one 8-bit element repeated + */ + static SIMD_4x32 splat_u8(uint8_t B) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_set1_epi8(B)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vreinterpretq_u32_u8(vdupq_n_u8(B))); +#else + const uint32_t B4 = make_uint32(B, B, B, B); + return SIMD_4x32(B4, B4, B4, B4); +#endif + } + + /** + * Load a SIMD register with little-endian convention + */ + static SIMD_4x32 load_le(const void* in) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_loadu_si128(reinterpret_cast(in))); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + uint32_t R[4]; + Botan::load_le(R, static_cast(in), 4); + return SIMD_4x32(R); +#elif defined(BOTAN_SIMD_USE_NEON) + SIMD_4x32 l(vld1q_u32(static_cast(in))); + return CPUID::is_big_endian() ? l.bswap() : l; +#endif + } + + /** + * Load a SIMD register with big-endian convention + */ + static SIMD_4x32 load_be(const void* in) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return load_le(in).bswap(); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + uint32_t R[4]; + Botan::load_be(R, static_cast(in), 4); + return SIMD_4x32(R); + +#elif defined(BOTAN_SIMD_USE_NEON) + SIMD_4x32 l(vld1q_u32(static_cast(in))); + return CPUID::is_little_endian() ? l.bswap() : l; +#endif + } + + void store_le(uint32_t out[4]) const + { + this->store_le(reinterpret_cast(out)); + } + + void store_le(uint64_t out[2]) const + { + this->store_le(reinterpret_cast(out)); + } + + /** + * Load a SIMD register with little-endian convention + */ + void store_le(uint8_t out[]) const + { +#if defined(BOTAN_SIMD_USE_SSE2) + + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), raw()); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + union { + __vector unsigned int V; + uint32_t R[4]; + } vec; + vec.V = raw(); + Botan::store_le(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + +#elif defined(BOTAN_SIMD_USE_NEON) + if(CPUID::is_little_endian()) + { + vst1q_u8(out, vreinterpretq_u8_u32(m_simd)); + } + else + { + vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd)); + } +#endif + } + + /** + * Load a SIMD register with big-endian convention + */ + void store_be(uint8_t out[]) const + { +#if defined(BOTAN_SIMD_USE_SSE2) + + bswap().store_le(out); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + union { + __vector unsigned int V; + uint32_t R[4]; + } vec; + vec.V = m_simd; + Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + +#elif defined(BOTAN_SIMD_USE_NEON) + if(CPUID::is_little_endian()) + { + vst1q_u8(out, vreinterpretq_u8_u32(bswap().m_simd)); + } + else + { + vst1q_u8(out, vreinterpretq_u8_u32(m_simd)); + } +#endif + } + + /* + * This is used for SHA-2/SHACAL2 + * Return rotr(ROT1) ^ rotr(ROT2) ^ rotr(ROT3) + */ + template + SIMD_4x32 rho() const + { + const SIMD_4x32 rot1 = this->rotr(); + const SIMD_4x32 rot2 = this->rotr(); + const SIMD_4x32 rot3 = this->rotr(); + return (rot1 ^ rot2 ^ rot3); + } + + /** + * Left rotation by a compile time constant + */ + template + SIMD_4x32 rotl() const + { + static_assert(ROT > 0 && ROT < 32, "Invalid rotation constant"); + +#if defined(BOTAN_SIMD_USE_SSE2) + + return SIMD_4x32(_mm_or_si128(_mm_slli_epi32(m_simd, static_cast(ROT)), + _mm_srli_epi32(m_simd, static_cast(32-ROT)))); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + const unsigned int r = static_cast(ROT); + __vector unsigned int rot = {r, r, r, r}; + return SIMD_4x32(vec_rl(m_simd, rot)); + +#elif defined(BOTAN_SIMD_USE_NEON) + +#if defined(BOTAN_TARGET_ARCH_IS_ARM64) + + BOTAN_IF_CONSTEXPR(ROT == 8) + { + const uint8_t maskb[16] = { 3,0,1,2, 7,4,5,6, 11,8,9,10, 15,12,13,14 }; + const uint8x16_t mask = vld1q_u8(maskb); + return SIMD_4x32(vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(m_simd), mask))); + } + else BOTAN_IF_CONSTEXPR(ROT == 16) + { + return SIMD_4x32(vreinterpretq_u32_u16(vrev32q_u16(vreinterpretq_u16_u32(m_simd)))); + } +#endif + return SIMD_4x32(vorrq_u32(vshlq_n_u32(m_simd, static_cast(ROT)), + vshrq_n_u32(m_simd, static_cast(32-ROT)))); +#endif + } + + /** + * Right rotation by a compile time constant + */ + template + SIMD_4x32 rotr() const + { + return this->rotl<32-ROT>(); + } + + /** + * Add elements of a SIMD vector + */ + SIMD_4x32 operator+(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval += other; + return retval; + } + + /** + * Subtract elements of a SIMD vector + */ + SIMD_4x32 operator-(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval -= other; + return retval; + } + + /** + * XOR elements of a SIMD vector + */ + SIMD_4x32 operator^(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval ^= other; + return retval; + } + + /** + * Binary OR elements of a SIMD vector + */ + SIMD_4x32 operator|(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval |= other; + return retval; + } + + /** + * Binary AND elements of a SIMD vector + */ + SIMD_4x32 operator&(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval &= other; + return retval; + } + + void operator+=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_add_epi32(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_simd = vec_add(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = vaddq_u32(m_simd, other.m_simd); +#endif + } + + void operator-=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_sub_epi32(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_simd = vec_sub(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = vsubq_u32(m_simd, other.m_simd); +#endif + } + + void operator^=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_xor_si128(m_simd, other.m_simd); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_simd = vec_xor(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = veorq_u32(m_simd, other.m_simd); +#endif + } + + void operator|=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_or_si128(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_simd = vec_or(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = vorrq_u32(m_simd, other.m_simd); +#endif + } + + void operator&=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_simd = _mm_and_si128(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_simd = vec_and(m_simd, other.m_simd); +#elif defined(BOTAN_SIMD_USE_NEON) + m_simd = vandq_u32(m_simd, other.m_simd); +#endif + } + + + template SIMD_4x32 shl() const + { + static_assert(SHIFT > 0 && SHIFT <= 31, "Invalid shift count"); + +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_slli_epi32(m_simd, SHIFT)); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const unsigned int s = static_cast(SHIFT); + const __vector unsigned int shifts = {s, s, s, s}; + return SIMD_4x32(vec_sl(m_simd, shifts)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vshlq_n_u32(m_simd, SHIFT)); +#endif + } + + template SIMD_4x32 shr() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_srli_epi32(m_simd, SHIFT)); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const unsigned int s = static_cast(SHIFT); + const __vector unsigned int shifts = {s, s, s, s}; + return SIMD_4x32(vec_sr(m_simd, shifts)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vshrq_n_u32(m_simd, SHIFT)); +#endif + } + + SIMD_4x32 operator~() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_xor_si128(m_simd, _mm_set1_epi32(0xFFFFFFFF))); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + return SIMD_4x32(vec_nor(m_simd, m_simd)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vmvnq_u32(m_simd)); +#endif + } + + // (~reg) & other + SIMD_4x32 andc(const SIMD_4x32& other) const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_andnot_si128(m_simd, other.m_simd)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + /* + AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2 + so swap the arguments + */ + return SIMD_4x32(vec_andc(other.m_simd, m_simd)); +#elif defined(BOTAN_SIMD_USE_NEON) + // NEON is also a & ~b + return SIMD_4x32(vbicq_u32(other.m_simd, m_simd)); +#endif + } + + /** + * Return copy *this with each word byte swapped + */ + SIMD_4x32 bswap() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + + __m128i T = m_simd; + T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + return SIMD_4x32(_mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8))); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + union { + __vector unsigned int V; + uint32_t R[4]; + } vec; + + vec.V = m_simd; + bswap_4(vec.R); + return SIMD_4x32(vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(m_simd)))); +#endif + } + + template + SIMD_4x32 shift_elems_left() const + { + static_assert(I <= 3, "Invalid shift count"); + +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_slli_si128(raw(), 4*I)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vextq_u32(vdupq_n_u32(0), raw(), 4-I)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const __vector unsigned int zero = vec_splat_u32(0); + + const __vector unsigned char shuf[3] = { + { 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, + { 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7 }, + { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 1, 2, 3 }, + }; + + return SIMD_4x32(vec_perm(raw(), zero, shuf[I-1])); +#endif + } + + template + SIMD_4x32 shift_elems_right() const + { + static_assert(I <= 3, "Invalid shift count"); + +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_srli_si128(raw(), 4*I)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vextq_u32(raw(), vdupq_n_u32(0), I)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const __vector unsigned int zero = vec_splat_u32(0); + + const __vector unsigned char shuf[3] = { + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }, + { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }, + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, + }; + + return SIMD_4x32(vec_perm(raw(), zero, shuf[I-1])); +#endif + } + + /** + * 4x4 Transposition on SIMD registers + */ + static void transpose(SIMD_4x32& B0, SIMD_4x32& B1, + SIMD_4x32& B2, SIMD_4x32& B3) + { +#if defined(BOTAN_SIMD_USE_SSE2) + const __m128i T0 = _mm_unpacklo_epi32(B0.m_simd, B1.m_simd); + const __m128i T1 = _mm_unpacklo_epi32(B2.m_simd, B3.m_simd); + const __m128i T2 = _mm_unpackhi_epi32(B0.m_simd, B1.m_simd); + const __m128i T3 = _mm_unpackhi_epi32(B2.m_simd, B3.m_simd); + + B0.m_simd = _mm_unpacklo_epi64(T0, T1); + B1.m_simd = _mm_unpackhi_epi64(T0, T1); + B2.m_simd = _mm_unpacklo_epi64(T2, T3); + B3.m_simd = _mm_unpackhi_epi64(T2, T3); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const __vector unsigned int T0 = vec_mergeh(B0.m_simd, B2.m_simd); + const __vector unsigned int T1 = vec_mergeh(B1.m_simd, B3.m_simd); + const __vector unsigned int T2 = vec_mergel(B0.m_simd, B2.m_simd); + const __vector unsigned int T3 = vec_mergel(B1.m_simd, B3.m_simd); + + B0.m_simd = vec_mergeh(T0, T1); + B1.m_simd = vec_mergel(T0, T1); + B2.m_simd = vec_mergeh(T2, T3); + B3.m_simd = vec_mergel(T2, T3); + +#elif defined(BOTAN_SIMD_USE_NEON) && defined(BOTAN_TARGET_ARCH_IS_ARM32) + const uint32x4x2_t T0 = vzipq_u32(B0.m_simd, B2.m_simd); + const uint32x4x2_t T1 = vzipq_u32(B1.m_simd, B3.m_simd); + const uint32x4x2_t O0 = vzipq_u32(T0.val[0], T1.val[0]); + const uint32x4x2_t O1 = vzipq_u32(T0.val[1], T1.val[1]); + + B0.m_simd = O0.val[0]; + B1.m_simd = O0.val[1]; + B2.m_simd = O1.val[0]; + B3.m_simd = O1.val[1]; + +#elif defined(BOTAN_SIMD_USE_NEON) && defined(BOTAN_TARGET_ARCH_IS_ARM64) + const uint32x4_t T0 = vzip1q_u32(B0.m_simd, B2.m_simd); + const uint32x4_t T2 = vzip2q_u32(B0.m_simd, B2.m_simd); + const uint32x4_t T1 = vzip1q_u32(B1.m_simd, B3.m_simd); + const uint32x4_t T3 = vzip2q_u32(B1.m_simd, B3.m_simd); + + B0.m_simd = vzip1q_u32(T0, T1); + B1.m_simd = vzip2q_u32(T0, T1); + B2.m_simd = vzip1q_u32(T2, T3); + B3.m_simd = vzip2q_u32(T2, T3); +#endif + } + + native_simd_type raw() const BOTAN_FUNC_ISA(BOTAN_SIMD_ISA) { return m_simd; } + + explicit SIMD_4x32(native_simd_type x) : m_simd(x) {} + private: + native_simd_type m_simd; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/simd/simd_avx2/info.txt b/comm/third_party/botan/src/lib/utils/simd/simd_avx2/info.txt new file mode 100644 index 0000000000..13a9ae4cbb --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/simd/simd_avx2/info.txt @@ -0,0 +1,21 @@ + +SIMD_AVX2 -> 20180824 + + + +avx2 + + + +simd_avx2.h + + + +gcc +clang +msvc + +# Intel C++ 2020 doesn't support target attribute on overloaded +# operators, see GH #2260 +#icc + diff --git a/comm/third_party/botan/src/lib/utils/simd/simd_avx2/simd_avx2.h b/comm/third_party/botan/src/lib/utils/simd/simd_avx2/simd_avx2.h new file mode 100644 index 0000000000..3498c2ad08 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/simd/simd_avx2/simd_avx2.h @@ -0,0 +1,299 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SIMD_AVX2_H_ +#define BOTAN_SIMD_AVX2_H_ + +#include +#include + +namespace Botan { + +class SIMD_8x32 final + { + public: + + SIMD_8x32& operator=(const SIMD_8x32& other) = default; + SIMD_8x32(const SIMD_8x32& other) = default; + + SIMD_8x32& operator=(SIMD_8x32&& other) = default; + SIMD_8x32(SIMD_8x32&& other) = default; + + BOTAN_FUNC_ISA("avx2") + BOTAN_FORCE_INLINE SIMD_8x32() + { + m_avx2 = _mm256_setzero_si256(); + } + + BOTAN_FUNC_ISA("avx2") + explicit SIMD_8x32(const uint32_t B[8]) + { + m_avx2 = _mm256_loadu_si256(reinterpret_cast(B)); + } + + BOTAN_FUNC_ISA("avx2") + explicit SIMD_8x32(uint32_t B0, uint32_t B1, uint32_t B2, uint32_t B3, + uint32_t B4, uint32_t B5, uint32_t B6, uint32_t B7) + { + m_avx2 = _mm256_set_epi32(B7, B6, B5, B4, B3, B2, B1, B0); + } + + BOTAN_FUNC_ISA("avx2") + static SIMD_8x32 splat(uint32_t B) + { + return SIMD_8x32(_mm256_set1_epi32(B)); + } + + BOTAN_FUNC_ISA("avx2") + static SIMD_8x32 load_le(const uint8_t* in) + { + return SIMD_8x32(_mm256_loadu_si256(reinterpret_cast(in))); + } + + BOTAN_FUNC_ISA("avx2") + static SIMD_8x32 load_be(const uint8_t* in) + { + return load_le(in).bswap(); + } + + BOTAN_FUNC_ISA("avx2") + void store_le(uint8_t out[]) const + { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(out), m_avx2); + } + + BOTAN_FUNC_ISA("avx2") + void store_be(uint8_t out[]) const + { + bswap().store_le(out); + } + + template + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 rotl() const + { + static_assert(ROT > 0 && ROT < 32, "Invalid rotation constant"); + +#if defined(__AVX512VL__) + return SIMD_8x32(_mm256_rol_epi32(m_avx2, ROT)); +#else + BOTAN_IF_CONSTEXPR(ROT == 8) + { + const __m256i shuf_rotl_8 = _mm256_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3, + 14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + return SIMD_8x32(_mm256_shuffle_epi8(m_avx2, shuf_rotl_8)); + } + else BOTAN_IF_CONSTEXPR(ROT == 16) + { + const __m256i shuf_rotl_16 = _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, + 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + + return SIMD_8x32(_mm256_shuffle_epi8(m_avx2, shuf_rotl_16)); + } + else + { + return SIMD_8x32(_mm256_or_si256(_mm256_slli_epi32(m_avx2, static_cast(ROT)), + _mm256_srli_epi32(m_avx2, static_cast(32-ROT)))); + } +#endif + } + + template + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 rotr() const + { + return this->rotl<32-ROT>(); + } + + template + SIMD_8x32 BOTAN_FUNC_ISA("avx2") rho() const + { + SIMD_8x32 res; + + const SIMD_8x32 rot1 = this->rotr(); + const SIMD_8x32 rot2 = this->rotr(); + const SIMD_8x32 rot3 = this->rotr(); + + return rot1 ^ rot2 ^ rot3; + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 operator+(const SIMD_8x32& other) const + { + SIMD_8x32 retval(*this); + retval += other; + return retval; + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 operator-(const SIMD_8x32& other) const + { + SIMD_8x32 retval(*this); + retval -= other; + return retval; + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 operator^(const SIMD_8x32& other) const + { + SIMD_8x32 retval(*this); + retval ^= other; + return retval; + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 operator|(const SIMD_8x32& other) const + { + SIMD_8x32 retval(*this); + retval |= other; + return retval; + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 operator&(const SIMD_8x32& other) const + { + SIMD_8x32 retval(*this); + retval &= other; + return retval; + } + + BOTAN_FUNC_ISA("avx2") + void operator+=(const SIMD_8x32& other) + { + m_avx2 = _mm256_add_epi32(m_avx2, other.m_avx2); + } + + BOTAN_FUNC_ISA("avx2") + void operator-=(const SIMD_8x32& other) + { + m_avx2 = _mm256_sub_epi32(m_avx2, other.m_avx2); + } + + BOTAN_FUNC_ISA("avx2") + void operator^=(const SIMD_8x32& other) + { + m_avx2 = _mm256_xor_si256(m_avx2, other.m_avx2); + } + + BOTAN_FUNC_ISA("avx2") + void operator|=(const SIMD_8x32& other) + { + m_avx2 = _mm256_or_si256(m_avx2, other.m_avx2); + } + + BOTAN_FUNC_ISA("avx2") + void operator&=(const SIMD_8x32& other) + { + m_avx2 = _mm256_and_si256(m_avx2, other.m_avx2); + } + + template BOTAN_FUNC_ISA("avx2") SIMD_8x32 shl() const + { + return SIMD_8x32(_mm256_slli_epi32(m_avx2, SHIFT)); + } + + template BOTAN_FUNC_ISA("avx2") SIMD_8x32 shr() const + { + return SIMD_8x32(_mm256_srli_epi32(m_avx2, SHIFT)); + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 operator~() const + { + return SIMD_8x32(_mm256_xor_si256(m_avx2, _mm256_set1_epi32(0xFFFFFFFF))); + } + + // (~reg) & other + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 andc(const SIMD_8x32& other) const + { + return SIMD_8x32(_mm256_andnot_si256(m_avx2, other.m_avx2)); + } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32 bswap() const + { + const uint8_t BSWAP_MASK[32] = { 3, 2, 1, 0, + 7, 6, 5, 4, + 11, 10, 9, 8, + 15, 14, 13, 12, + 19, 18, 17, 16, + 23, 22, 21, 20, + 27, 26, 25, 24, + 31, 30, 29, 28 }; + + const __m256i bswap = _mm256_loadu_si256(reinterpret_cast(BSWAP_MASK)); + + const __m256i output = _mm256_shuffle_epi8(m_avx2, bswap); + + return SIMD_8x32(output); + } + + BOTAN_FUNC_ISA("avx2") + static void transpose(SIMD_8x32& B0, SIMD_8x32& B1, + SIMD_8x32& B2, SIMD_8x32& B3) + { + const __m256i T0 = _mm256_unpacklo_epi32(B0.m_avx2, B1.m_avx2); + const __m256i T1 = _mm256_unpacklo_epi32(B2.m_avx2, B3.m_avx2); + const __m256i T2 = _mm256_unpackhi_epi32(B0.m_avx2, B1.m_avx2); + const __m256i T3 = _mm256_unpackhi_epi32(B2.m_avx2, B3.m_avx2); + + B0.m_avx2 = _mm256_unpacklo_epi64(T0, T1); + B1.m_avx2 = _mm256_unpackhi_epi64(T0, T1); + B2.m_avx2 = _mm256_unpacklo_epi64(T2, T3); + B3.m_avx2 = _mm256_unpackhi_epi64(T2, T3); + } + + BOTAN_FUNC_ISA("avx2") + static void transpose(SIMD_8x32& B0, SIMD_8x32& B1, + SIMD_8x32& B2, SIMD_8x32& B3, + SIMD_8x32& B4, SIMD_8x32& B5, + SIMD_8x32& B6, SIMD_8x32& B7) + { + transpose(B0, B1, B2, B3); + transpose(B4, B5, B6, B7); + + swap_tops(B0, B4); + swap_tops(B1, B5); + swap_tops(B2, B6); + swap_tops(B3, B7); + } + + BOTAN_FUNC_ISA("avx2") + static void reset_registers() + { + _mm256_zeroupper(); + } + + BOTAN_FUNC_ISA("avx2") + static void zero_registers() + { + _mm256_zeroall(); + } + + __m256i BOTAN_FUNC_ISA("avx2") handle() const { return m_avx2; } + + BOTAN_FUNC_ISA("avx2") + SIMD_8x32(__m256i x) : m_avx2(x) {} + + private: + + BOTAN_FUNC_ISA("avx2") + static void swap_tops(SIMD_8x32& A, SIMD_8x32& B) + { + SIMD_8x32 T0 = _mm256_permute2x128_si256(A.handle(), B.handle(), 0 + (2 << 4)); + SIMD_8x32 T1 = _mm256_permute2x128_si256(A.handle(), B.handle(), 1 + (3 << 4)); + A = T0; + B = T1; + } + + __m256i m_avx2; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/socket/info.txt b/comm/third_party/botan/src/lib/utils/socket/info.txt new file mode 100644 index 0000000000..3862f0f74e --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/info.txt @@ -0,0 +1,18 @@ + +SOCKETS -> 20171216 + + + +uri.h +socket.h +socket_udp.h + + + +linux -> rt +mingw -> ws2_32 +windows -> ws2_32 +haiku -> network +solaris -> socket,nsl +qnx -> socket + diff --git a/comm/third_party/botan/src/lib/utils/socket/socket.cpp b/comm/third_party/botan/src/lib/utils/socket/socket.cpp new file mode 100644 index 0000000000..bc632259a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/socket.cpp @@ -0,0 +1,371 @@ +/* +* (C) 2015,2016,2017 Jack Lloyd +* (C) 2016 Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BOOST_ASIO) + /* + * We don't need serial port support anyway, and asking for it causes + * macro conflicts with termios.h when this file is included in the + * amalgamation. + */ + #define BOOST_ASIO_DISABLE_SERIAL_PORT + #include + #include + +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) + #include + #include + #include + #include + #include + #include + #include + #include + +#elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_BOOST_ASIO) + +class Asio_Socket final : public OS::Socket + { + public: + Asio_Socket(const std::string& hostname, + const std::string& service, + std::chrono::milliseconds timeout) : + m_timeout(timeout), m_timer(m_io), m_tcp(m_io) + { + m_timer.expires_from_now(m_timeout); + check_timeout(); + + boost::asio::ip::tcp::resolver resolver(m_io); + boost::asio::ip::tcp::resolver::query query(hostname, service); + boost::asio::ip::tcp::resolver::iterator dns_iter = resolver.resolve(query); + + boost::system::error_code ec = boost::asio::error::would_block; + + auto connect_cb = [&ec](const boost::system::error_code& e, + boost::asio::ip::tcp::resolver::iterator) { ec = e; }; + + boost::asio::async_connect(m_tcp, dns_iter, connect_cb); + + while(ec == boost::asio::error::would_block) + { + m_io.run_one(); + } + + if(ec) + throw boost::system::system_error(ec); + if(m_tcp.is_open() == false) + throw System_Error("Connection to host " + hostname + " failed"); + } + + void write(const uint8_t buf[], size_t len) override + { + m_timer.expires_from_now(m_timeout); + + boost::system::error_code ec = boost::asio::error::would_block; + + m_tcp.async_send(boost::asio::buffer(buf, len), + [&ec](boost::system::error_code e, size_t) { ec = e; }); + + while(ec == boost::asio::error::would_block) { m_io.run_one(); } + + if(ec) + { + throw boost::system::system_error(ec); + } + } + + size_t read(uint8_t buf[], size_t len) override + { + m_timer.expires_from_now(m_timeout); + + boost::system::error_code ec = boost::asio::error::would_block; + size_t got = 0; + + m_tcp.async_read_some(boost::asio::buffer(buf, len), + [&](boost::system::error_code cb_ec, size_t cb_got) { ec = cb_ec; got = cb_got; }); + + while(ec == boost::asio::error::would_block) { m_io.run_one(); } + + if(ec) + { + if(ec == boost::asio::error::eof) + return 0; + throw boost::system::system_error(ec); // Some other error. + } + + return got; + } + + private: + void check_timeout() + { + if(m_tcp.is_open() && m_timer.expires_at() < std::chrono::system_clock::now()) + { + boost::system::error_code err; + m_tcp.close(err); + } + + m_timer.async_wait(std::bind(&Asio_Socket::check_timeout, this)); + } + + const std::chrono::milliseconds m_timeout; + boost::asio::io_service m_io; + boost::asio::system_timer m_timer; + boost::asio::ip::tcp::socket m_tcp; + }; + +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + +class BSD_Socket final : public OS::Socket + { + private: +#if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + typedef SOCKET socket_type; + typedef int socket_op_ret_type; + typedef int socklen_type; + typedef int sendrecv_len_type; + static socket_type invalid_socket() { return INVALID_SOCKET; } + static void close_socket(socket_type s) { ::closesocket(s); } + static std::string get_last_socket_error() { return std::to_string(::WSAGetLastError()); } + + static bool nonblocking_connect_in_progress() + { + return (::WSAGetLastError() == WSAEWOULDBLOCK); + } + + static void set_nonblocking(socket_type s) + { + u_long nonblocking = 1; + ::ioctlsocket(s, FIONBIO, &nonblocking); + } + + static void socket_init() + { + WSAData wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + + if (::WSAStartup(wsa_version, &wsa_data) != 0) + { + throw System_Error("WSAStartup() failed", WSAGetLastError()); + } + + if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) + { + ::WSACleanup(); + throw System_Error("Could not find a usable version of Winsock.dll"); + } + } + + static void socket_fini() + { + ::WSACleanup(); + } +#else + typedef int socket_type; + typedef ssize_t socket_op_ret_type; + typedef socklen_t socklen_type; + typedef size_t sendrecv_len_type; + static socket_type invalid_socket() { return -1; } + static void close_socket(socket_type s) { ::close(s); } + static std::string get_last_socket_error() { return ::strerror(errno); } + static bool nonblocking_connect_in_progress() { return (errno == EINPROGRESS); } + static void set_nonblocking(socket_type s) + { + if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) + throw System_Error("Setting socket to non-blocking state failed", errno); + } + + static void socket_init() {} + static void socket_fini() {} +#endif + + public: + BSD_Socket(const std::string& hostname, + const std::string& service, + std::chrono::microseconds timeout) : m_timeout(timeout) + { + socket_init(); + + m_socket = invalid_socket(); + + addrinfo hints; + clear_mem(&hints, 1); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + addrinfo* res; + + int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res); + + if(rc != 0) + { + throw System_Error("Name resolution failed for " + hostname, rc); + } + + for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) + { + if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) + continue; + + m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + if(m_socket == invalid_socket()) + { + // unsupported socket type? + continue; + } + + set_nonblocking(m_socket); + + int err = ::connect(m_socket, rp->ai_addr, static_cast(rp->ai_addrlen)); + + if(err == -1) + { + int active = 0; + if(nonblocking_connect_in_progress()) + { + struct timeval timeout_tv = make_timeout_tv(); + fd_set write_set; + FD_ZERO(&write_set); + // Weirdly, Winsock uses a SOCKET type but wants FD_SET to get an int instead + FD_SET(static_cast(m_socket), &write_set); + + active = ::select(static_cast(m_socket + 1), nullptr, &write_set, nullptr, &timeout_tv); + + if(active) + { + int socket_error = 0; + socklen_t len = sizeof(socket_error); + + if(::getsockopt(m_socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&socket_error), &len) < 0) + throw System_Error("Error calling getsockopt", errno); + + if(socket_error != 0) + { + active = 0; + } + } + } + + if(active == 0) + { + close_socket(m_socket); + m_socket = invalid_socket(); + continue; + } + } + } + + ::freeaddrinfo(res); + + if(m_socket == invalid_socket()) + { + throw System_Error("Connecting to " + hostname + + " for service " + service + " failed", errno); + } + } + + ~BSD_Socket() + { + close_socket(m_socket); + m_socket = invalid_socket(); + socket_fini(); + } + + void write(const uint8_t buf[], size_t len) override + { + fd_set write_set; + FD_ZERO(&write_set); + FD_SET(m_socket, &write_set); + + size_t sent_so_far = 0; + while(sent_so_far != len) + { + struct timeval timeout = make_timeout_tv(); + int active = ::select(static_cast(m_socket + 1), nullptr, &write_set, nullptr, &timeout); + + if(active == 0) + throw System_Error("Timeout during socket write"); + + const size_t left = len - sent_so_far; + socket_op_ret_type sent = ::send(m_socket, cast_uint8_ptr_to_char(&buf[sent_so_far]), static_cast(left), 0); + if(sent < 0) + throw System_Error("Socket write failed", errno); + else + sent_so_far += static_cast(sent); + } + } + + size_t read(uint8_t buf[], size_t len) override + { + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(m_socket, &read_set); + + struct timeval timeout = make_timeout_tv(); + int active = ::select(static_cast(m_socket + 1), &read_set, nullptr, nullptr, &timeout); + + if(active == 0) + throw System_Error("Timeout during socket read"); + + socket_op_ret_type got = ::recv(m_socket, cast_uint8_ptr_to_char(buf), static_cast(len), 0); + + if(got < 0) + throw System_Error("Socket read failed", errno); + + return static_cast(got); + } + + private: + struct timeval make_timeout_tv() const + { + struct timeval tv; + tv.tv_sec = static_cast(m_timeout.count() / 1000000); + tv.tv_usec = static_cast(m_timeout.count() % 1000000);; + return tv; + } + + const std::chrono::microseconds m_timeout; + socket_type m_socket; + }; + +#endif + +} + +std::unique_ptr +OS::open_socket(const std::string& hostname, + const std::string& service, + std::chrono::milliseconds timeout) + { +#if defined(BOTAN_HAS_BOOST_ASIO) + return std::unique_ptr(new Asio_Socket(hostname, service, timeout)); + +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + return std::unique_ptr(new BSD_Socket(hostname, service, timeout)); + +#else + BOTAN_UNUSED(hostname); + BOTAN_UNUSED(service); + BOTAN_UNUSED(timeout); + // No sockets for you + return std::unique_ptr(); +#endif + } + +} diff --git a/comm/third_party/botan/src/lib/utils/socket/socket.h b/comm/third_party/botan/src/lib/utils/socket/socket.h new file mode 100644 index 0000000000..03a951478a --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/socket.h @@ -0,0 +1,64 @@ +/* +* OS specific utility functions +* (C) 2015,2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SOCKET_H_ +#define BOTAN_SOCKET_H_ + +#include +#include +#include + +namespace Botan { + +namespace OS { + +/* +* This header is internal (not installed) and these functions are not +* intended to be called by applications. However they are given public +* visibility (using BOTAN_TEST_API macro) for the tests. This also probably +* allows them to be overridden by the application on ELF systems, but +* this hasn't been tested. +*/ + + +/** +* A wrapper around a simple blocking TCP socket +*/ +class BOTAN_TEST_API Socket + { + public: + /** + * The socket will be closed upon destruction + */ + virtual ~Socket() = default; + + /** + * Write to the socket. Blocks until all bytes sent. + * Throws on error. + */ + virtual void write(const uint8_t buf[], size_t len) = 0; + + /** + * Reads up to len bytes, returns bytes written to buf. + * Returns 0 on EOF. Throws on error. + */ + virtual size_t read(uint8_t buf[], size_t len) = 0; + }; + +/** +* Open up a socket. Will throw on error. Returns null if sockets are +* not available on this platform. +*/ +std::unique_ptr +BOTAN_TEST_API open_socket(const std::string& hostname, + const std::string& service, + std::chrono::milliseconds timeout); + +} // OS +} // Botan + +#endif diff --git a/comm/third_party/botan/src/lib/utils/socket/socket_udp.cpp b/comm/third_party/botan/src/lib/utils/socket/socket_udp.cpp new file mode 100644 index 0000000000..fbbdd9abbc --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/socket_udp.cpp @@ -0,0 +1,344 @@ +/* +* (C) 2015,2016,2017 Jack Lloyd +* (C) 2016 Daniel Neus +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_BOOST_ASIO) + /* + * We don't need serial port support anyway, and asking for it + * causes macro conflicts with Darwin's termios.h when this + * file is included in the amalgamation. GH #350 + */ + #define BOOST_ASIO_DISABLE_SERIAL_PORT + #include + #include +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) + #include + #include + #include + #include + #include + #include + #include + #include + +#elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + #include +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_BOOST_ASIO) +class Asio_SocketUDP final : public OS::SocketUDP + { + public: + Asio_SocketUDP(const std::string& hostname, + const std::string& service, + std::chrono::microseconds timeout) : + m_timeout(timeout), m_timer(m_io), m_udp(m_io) + { + m_timer.expires_from_now(m_timeout); + check_timeout(); + + boost::asio::ip::udp::resolver resolver(m_io); + boost::asio::ip::udp::resolver::query query(hostname, service); + boost::asio::ip::udp::resolver::iterator dns_iter = resolver.resolve(query); + + boost::system::error_code ec = boost::asio::error::would_block; + + auto connect_cb = [&ec](const boost::system::error_code& e, + boost::asio::ip::udp::resolver::iterator) { ec = e; }; + + boost::asio::async_connect(m_udp, dns_iter, connect_cb); + + while(ec == boost::asio::error::would_block) + { + m_io.run_one(); + } + + if(ec) + { throw boost::system::system_error(ec); } + if(m_udp.is_open() == false) + { throw System_Error("Connection to host " + hostname + " failed"); } + } + + void write(const uint8_t buf[], size_t len) override + { + m_timer.expires_from_now(m_timeout); + + boost::system::error_code ec = boost::asio::error::would_block; + + m_udp.async_send(boost::asio::buffer(buf, len), + [&ec](boost::system::error_code e, size_t) { ec = e; }); + + while(ec == boost::asio::error::would_block) + { + m_io.run_one(); + } + + if(ec) + { + throw boost::system::system_error(ec); + } + } + + size_t read(uint8_t buf[], size_t len) override + { + m_timer.expires_from_now(m_timeout); + + boost::system::error_code ec = boost::asio::error::would_block; + size_t got = 0; + + m_udp.async_receive(boost::asio::buffer(buf, len), + [&](boost::system::error_code cb_ec, size_t cb_got) { ec = cb_ec; got = cb_got; }); + + while(ec == boost::asio::error::would_block) + { + m_io.run_one(); + } + + if(ec) + { + if(ec == boost::asio::error::eof) + { return 0; } + throw boost::system::system_error(ec); // Some other error. + } + + return got; + } + + private: + void check_timeout() + { + if(m_udp.is_open() && m_timer.expires_at() < std::chrono::system_clock::now()) + { + boost::system::error_code err; + m_udp.close(err); + } + + m_timer.async_wait(std::bind(&Asio_SocketUDP::check_timeout, this)); + } + + const std::chrono::microseconds m_timeout; + boost::asio::io_service m_io; + boost::asio::system_timer m_timer; + boost::asio::ip::udp::socket m_udp; + }; +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) +class BSD_SocketUDP final : public OS::SocketUDP + { + public: + BSD_SocketUDP(const std::string& hostname, + const std::string& service, + std::chrono::microseconds timeout) : m_timeout(timeout) + { + socket_init(); + + m_socket = invalid_socket(); + + addrinfo* res; + addrinfo hints; + clear_mem(&hints, 1); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res); + + if(rc != 0) + { + throw System_Error("Name resolution failed for " + hostname, rc); + } + + for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) + { + if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6) + { continue; } + + m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + if(m_socket == invalid_socket()) + { + // unsupported socket type? + continue; + } + + set_nonblocking(m_socket); + memcpy(&sa, res->ai_addr, res->ai_addrlen); + salen = static_cast(res->ai_addrlen); + } + + ::freeaddrinfo(res); + + if(m_socket == invalid_socket()) + { + throw System_Error("Connecting to " + hostname + + " for service " + service + " failed", errno); + } + } + + ~BSD_SocketUDP() + { + close_socket(m_socket); + m_socket = invalid_socket(); + socket_fini(); + } + + void write(const uint8_t buf[], size_t len) override + { + fd_set write_set; + FD_ZERO(&write_set); + FD_SET(m_socket, &write_set); + + size_t sent_so_far = 0; + while(sent_so_far != len) + { + struct timeval timeout = make_timeout_tv(); + int active = ::select(static_cast(m_socket + 1), nullptr, &write_set, nullptr, &timeout); + + if(active == 0) + { throw System_Error("Timeout during socket write"); } + + const size_t left = len - sent_so_far; + socket_op_ret_type sent = ::sendto(m_socket, cast_uint8_ptr_to_char(buf + sent_so_far), + static_cast(left), 0, + reinterpret_cast(&sa), salen); + if(sent < 0) + { throw System_Error("Socket write failed", errno); } + else + { sent_so_far += static_cast(sent); } + } + } + + size_t read(uint8_t buf[], size_t len) override + { + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(m_socket, &read_set); + + struct timeval timeout = make_timeout_tv(); + int active = ::select(static_cast(m_socket + 1), &read_set, nullptr, nullptr, &timeout); + + if(active == 0) + { throw System_Error("Timeout during socket read"); } + + socket_op_ret_type got = ::recvfrom(m_socket, cast_uint8_ptr_to_char(buf), static_cast(len), 0, nullptr, nullptr); + + if(got < 0) + { throw System_Error("Socket read failed", errno); } + + return static_cast(got); + } + + private: +#if defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + typedef SOCKET socket_type; + typedef int socket_op_ret_type; + typedef int sendrecv_len_type; + static socket_type invalid_socket() { return INVALID_SOCKET; } + static void close_socket(socket_type s) { ::closesocket(s); } + static std::string get_last_socket_error() { return std::to_string(::WSAGetLastError()); } + + static bool nonblocking_connect_in_progress() + { + return (::WSAGetLastError() == WSAEWOULDBLOCK); + } + + static void set_nonblocking(socket_type s) + { + u_long nonblocking = 1; + ::ioctlsocket(s, FIONBIO, &nonblocking); + } + + static void socket_init() + { + WSAData wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + + if(::WSAStartup(wsa_version, &wsa_data) != 0) + { + throw System_Error("WSAStartup() failed", WSAGetLastError()); + } + + if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) + { + ::WSACleanup(); + throw System_Error("Could not find a usable version of Winsock.dll"); + } + } + + static void socket_fini() + { + ::WSACleanup(); + } +#else + typedef int socket_type; + typedef ssize_t socket_op_ret_type; + typedef size_t sendrecv_len_type; + static socket_type invalid_socket() { return -1; } + static void close_socket(socket_type s) { ::close(s); } + static std::string get_last_socket_error() { return ::strerror(errno); } + static bool nonblocking_connect_in_progress() { return (errno == EINPROGRESS); } + static void set_nonblocking(socket_type s) + { + if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) + { throw System_Error("Setting socket to non-blocking state failed", errno); } + } + + static void socket_init() {} + static void socket_fini() {} +#endif + sockaddr_storage sa; + socklen_t salen; + struct timeval make_timeout_tv() const + { + struct timeval tv; + tv.tv_sec = static_cast(m_timeout.count() / 1000000); + tv.tv_usec = static_cast(m_timeout.count() % 1000000);; + return tv; + } + + const std::chrono::microseconds m_timeout; + socket_type m_socket; + }; +#endif +} + +std::unique_ptr +OS::open_socket_udp(const std::string& hostname, + const std::string& service, + std::chrono::microseconds timeout) + { +#if defined(BOTAN_HAS_BOOST_ASIO) + return std::unique_ptr(new Asio_SocketUDP(hostname, service, timeout)); +#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + return std::unique_ptr(new BSD_SocketUDP(hostname, service, timeout)); +#else + BOTAN_UNUSED(hostname); + BOTAN_UNUSED(service); + BOTAN_UNUSED(timeout); + return std::unique_ptr(); +#endif + } + +std::unique_ptr +OS::open_socket_udp(const std::string& uri_string, + std::chrono::microseconds timeout) + { + const auto uri = URI::fromAny(uri_string); + if(uri.port == 0) + { throw Invalid_Argument("UDP port not specified"); } + return open_socket_udp(uri.host, std::to_string(uri.port), timeout); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/socket/socket_udp.h b/comm/third_party/botan/src/lib/utils/socket/socket_udp.h new file mode 100644 index 0000000000..4a9346c2b3 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/socket_udp.h @@ -0,0 +1,73 @@ +/* +* (C) 2015,2016,2017 Jack Lloyd +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SOCKET_UDP_H_ +#define BOTAN_SOCKET_UDP_H_ + +#include +#include +#include + +namespace Botan { + +namespace OS { + +/* +* This header is internal (not installed) and these functions are not +* intended to be called by applications. However they are given public +* visibility (using BOTAN_TEST_API macro) for the tests. This also probably +* allows them to be overridden by the application on ELF systems, but +* this hasn't been tested. +*/ + + +/** +* A wrapper around a simple blocking UDP socket +*/ +class BOTAN_TEST_API SocketUDP + { + public: + /** + * The socket will be closed upon destruction + */ + virtual ~SocketUDP() = default; + + /** + * Write to the socket. Returns immediately. + * Throws on error. + */ + virtual void write(const uint8_t buf[], size_t len) = 0; + + /** + * Reads up to len bytes, returns bytes written to buf. + * Returns 0 on EOF. Throws on error. + */ + virtual size_t read(uint8_t buf[], size_t len) = 0; + }; + +/** +* Open up a socket. Will throw on error. Returns null if sockets are +* not available on this platform. +*/ +std::unique_ptr +BOTAN_TEST_API open_socket_udp(const std::string& hostname, + const std::string& service, + std::chrono::microseconds timeout); + +/** +* Open up a socket. Will throw on error. Returns null if sockets are +* not available on this platform. +*/ +std::unique_ptr +BOTAN_TEST_API open_socket_udp(const std::string& uri, + std::chrono::microseconds timeout); + + +} // OS +} // Botan + +#endif diff --git a/comm/third_party/botan/src/lib/utils/socket/uri.cpp b/comm/third_party/botan/src/lib/utils/socket/uri.cpp new file mode 100644 index 0000000000..5653d97e73 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/uri.cpp @@ -0,0 +1,188 @@ +/* +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include + +#if defined(BOTAN_TARGET_OS_HAS_SOCKETS) + #include + #include + #include +#elif defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + #include +#endif + +#if defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2) + +namespace { + +constexpr bool isdigit(char ch) + { + return ch >= '0' && ch <= '9'; + } + +bool isDomain(const std::string& domain) + { +#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20160726) + // GCC 4.8 does not support regex + BOTAN_UNUSED(domain); + return true; +#else + std::regex re( + R"(^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$)"); + std::cmatch m; + return std::regex_match(domain.c_str(), m, re); +#endif + } + +bool isIPv4(const std::string& ip) + { + sockaddr_storage inaddr; + return !!inet_pton(AF_INET, ip.c_str(), &inaddr); + } + +bool isIPv6(const std::string& ip) + { + sockaddr_storage in6addr; + return !!inet_pton(AF_INET6, ip.c_str(), &in6addr); + } +} + +namespace Botan { + +URI URI::fromDomain(const std::string& uri) + { + unsigned port = 0; + const auto port_pos = uri.find(':'); + if(port_pos != std::string::npos) + { + for(char c : uri.substr(port_pos+1)) + { + if(!isdigit(c)) + { throw Invalid_Argument("invalid"); } + port = port*10 + c - '0'; + if(port > 65535) + { throw Invalid_Argument("invalid"); } + } + } + const auto domain = uri.substr(0, port_pos); + if(isIPv4(domain)) + { throw Invalid_Argument("invalid"); } + if(!isDomain(domain)) + { throw Invalid_Argument("invalid"); } + return {Type::Domain, domain, uint16_t(port)}; + } + +URI URI::fromIPv4(const std::string& uri) + { + unsigned port = 0; + const auto port_pos = uri.find(':'); + if(port_pos != std::string::npos) + { + for(char c : uri.substr(port_pos+1)) + { + if(!isdigit(c)) + { throw Invalid_Argument("invalid"); } + port = port*10 + c - '0'; + if(port > 65535) + { throw Invalid_Argument("invalid"); } + } + } + const auto ip = uri.substr(0, port_pos); + if(!isIPv4(ip)) + { throw Invalid_Argument("invalid"); } + return { Type::IPv4, ip, uint16_t(port) }; + } + +URI URI::fromIPv6(const std::string& uri) + { + unsigned port = 0; + const auto port_pos = uri.find(']'); + const bool with_braces = (port_pos != std::string::npos); + if((uri[0]=='[') != with_braces) + { throw Invalid_Argument("invalid"); } + + if(with_braces && (uri.size() > port_pos + 1)) + { + if(uri[port_pos+1]!=':') + { throw Invalid_Argument("invalid"); } + for(char c : uri.substr(port_pos+2)) + { + if(!isdigit(c)) + { throw Invalid_Argument("invalid"); } + port = port*10 + c - '0'; + if(port > 65535) + { throw Invalid_Argument("invalid"); } + } + } + const auto ip = uri.substr((with_braces ? 1 : 0), port_pos - with_braces); + if(!isIPv6(ip)) + { throw Invalid_Argument("invalid"); } + return { Type::IPv6, ip, uint16_t(port) }; + } + +URI URI::fromAny(const std::string& uri) + { + + bool colon_seen=false; + bool non_number=false; + if(uri[0]=='[') + { return fromIPv6(uri); } + for(auto c : uri) + { + if(c == ':') + { + if(colon_seen) //seen two ':' + { return fromIPv6(uri); } + colon_seen = true; + } + else if(!isdigit(c) && c != '.') + { + non_number=true; + } + } + if(!non_number) + { + if(isIPv4(uri.substr(0, uri.find(':')))) + { + return fromIPv4(uri); + } + } + return fromDomain(uri); + } + +std::string URI::to_string() const + { + if(type == Type::NotSet) + { + throw Invalid_Argument("not set"); + } + + if(port != 0) + { + if(type == Type::IPv6) + { return "[" + host + "]:" + std::to_string(port); } + return host + ":" + std::to_string(port); + } + return host; + } + +} + +#else + +namespace Botan { + +URI URI::fromDomain(const std::string&) {throw Not_Implemented("No socket support enabled in build");} +URI URI::fromIPv4(const std::string&) {throw Not_Implemented("No socket support enabled in build");} +URI URI::fromIPv6(const std::string&) {throw Not_Implemented("No socket support enabled in build");} +URI URI::fromAny(const std::string&) {throw Not_Implemented("No socket support enabled in build");} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/socket/uri.h b/comm/third_party/botan/src/lib/utils/socket/uri.h new file mode 100644 index 0000000000..346f9f4f63 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/socket/uri.h @@ -0,0 +1,49 @@ +/* +* (C) 2019 Nuno Goncalves +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_URI_H_ +#define BOTAN_URI_H_ + +#include +#include + +#include + +namespace Botan { + +struct BOTAN_TEST_API URI + { + enum class Type : uint8_t + { + NotSet, + IPv4, + IPv6, + Domain, + }; + static URI fromAny(const std::string& uri); + static URI fromIPv4(const std::string& uri); + static URI fromIPv6(const std::string& uri); + static URI fromDomain(const std::string& uri); + URI() = default; + URI(Type xtype, const std::string& xhost, unsigned short xport) + : type { xtype } + , host { xhost } + , port { xport } + {} + bool operator==(const URI& a) const + { + return type == a.type && host == a.host && port == a.port; + } + std::string to_string() const; + + const Type type{Type::NotSet}; + const std::string host{}; + const uint16_t port{}; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/sqlite3/info.txt b/comm/third_party/botan/src/lib/utils/sqlite3/info.txt new file mode 100644 index 0000000000..9611944323 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/sqlite3/info.txt @@ -0,0 +1,13 @@ + +SQLITE3 -> 20171118 + + +load_on vendor + + +all -> sqlite3 + + + +sqlite3.h + diff --git a/comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.cpp b/comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.cpp new file mode 100644 index 0000000000..8c71ecd964 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.cpp @@ -0,0 +1,166 @@ +/* +* SQLite wrapper +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +Sqlite3_Database::Sqlite3_Database(const std::string& db_filename) + { + int rc = ::sqlite3_open(db_filename.c_str(), &m_db); + + if(rc) + { + const std::string err_msg = ::sqlite3_errmsg(m_db); + ::sqlite3_close(m_db); + m_db = nullptr; + throw SQL_DB_Error("sqlite3_open failed - " + err_msg); + } + } + +Sqlite3_Database::~Sqlite3_Database() + { + if(m_db) + ::sqlite3_close(m_db); + m_db = nullptr; + } + +std::shared_ptr Sqlite3_Database::new_statement(const std::string& base_sql) const + { + return std::make_shared(m_db, base_sql); + } + +size_t Sqlite3_Database::row_count(const std::string& table_name) + { + auto stmt = new_statement("select count(*) from " + table_name); + + if(stmt->step()) + return stmt->get_size_t(0); + else + throw SQL_DB_Error("Querying size of table " + table_name + " failed"); + } + +void Sqlite3_Database::create_table(const std::string& table_schema) + { + char* errmsg = nullptr; + int rc = ::sqlite3_exec(m_db, table_schema.c_str(), nullptr, nullptr, &errmsg); + + if(rc != SQLITE_OK) + { + const std::string err_msg = errmsg; + ::sqlite3_free(errmsg); + ::sqlite3_close(m_db); + m_db = nullptr; + throw SQL_DB_Error("sqlite3_exec for table failed - " + err_msg); + } + } + +Sqlite3_Database::Sqlite3_Statement::Sqlite3_Statement(sqlite3* db, const std::string& base_sql) + { + int rc = ::sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, nullptr); + + if(rc != SQLITE_OK) + throw SQL_DB_Error("sqlite3_prepare failed on " + base_sql, rc); + } + +void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::string& val) + { + int rc = ::sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw SQL_DB_Error("sqlite3_bind_text failed", rc); + } + +void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val) + { + if(val != static_cast(static_cast(val))) // is this cast legit? + throw SQL_DB_Error("sqlite3 cannot store " + std::to_string(val) + " without truncation"); + int rc = ::sqlite3_bind_int(m_stmt, column, val); + if(rc != SQLITE_OK) + throw SQL_DB_Error("sqlite3_bind_int failed", rc); + } + +void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time) + { + const int timeval = std::chrono::duration_cast(time.time_since_epoch()).count(); + bind(column, timeval); + } + +void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector& val) + { + int rc = ::sqlite3_bind_blob(m_stmt, column, val.data(), val.size(), SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw SQL_DB_Error("sqlite3_bind_text failed", rc); + } + +void Sqlite3_Database::Sqlite3_Statement::bind(int column, const uint8_t* p, size_t len) + { + int rc = ::sqlite3_bind_blob(m_stmt, column, p, len, SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw SQL_DB_Error("sqlite3_bind_text failed", rc); + } + +std::pair Sqlite3_Database::Sqlite3_Statement::get_blob(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_BLOB, + "Return value is a blob"); + + const void* session_blob = ::sqlite3_column_blob(m_stmt, column); + const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column); + + BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative"); + + return std::make_pair(static_cast(session_blob), + static_cast(session_blob_size)); + } + +std::string Sqlite3_Database::Sqlite3_Statement::get_str(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_TEXT, + "Return value is text"); + + const unsigned char* str = ::sqlite3_column_text(m_stmt, column); + + return std::string(cast_uint8_ptr_to_char(str)); + } + +size_t Sqlite3_Database::Sqlite3_Statement::get_size_t(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER, + "Return count is an integer"); + + const int sessions_int = ::sqlite3_column_int(m_stmt, column); + + BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative"); + + return static_cast(sessions_int); + } + +size_t Sqlite3_Database::Sqlite3_Statement::spin() + { + size_t steps = 0; + while(step()) + { + ++steps; + } + + return steps; + } + +bool Sqlite3_Database::Sqlite3_Statement::step() + { + return (::sqlite3_step(m_stmt) == SQLITE_ROW); + } + +Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement() + { + ::sqlite3_finalize(m_stmt); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.h b/comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.h new file mode 100644 index 0000000000..08a0f0ae7c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/sqlite3/sqlite3.h @@ -0,0 +1,58 @@ +/* +* SQLite3 wrapper +* (C) 2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTILS_SQLITE3_H_ +#define BOTAN_UTILS_SQLITE3_H_ + +#include + +class sqlite3; +class sqlite3_stmt; + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) Sqlite3_Database final : public SQL_Database + { + public: + Sqlite3_Database(const std::string& file); + + ~Sqlite3_Database(); + + size_t row_count(const std::string& table_name) override; + + void create_table(const std::string& table_schema) override; + + std::shared_ptr new_statement(const std::string& sql) const override; + private: + class Sqlite3_Statement final : public Statement + { + public: + void bind(int column, const std::string& val) override; + void bind(int column, size_t val) override; + void bind(int column, std::chrono::system_clock::time_point time) override; + void bind(int column, const std::vector& val) override; + void bind(int column, const uint8_t* data, size_t len) override; + + std::pair get_blob(int column) override; + std::string get_str(int column) override; + size_t get_size_t(int column) override; + + size_t spin() override; + bool step() override; + + Sqlite3_Statement(sqlite3* db, const std::string& base_sql); + ~Sqlite3_Statement(); + private: + sqlite3_stmt* m_stmt; + }; + + sqlite3* m_db; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/stl_compatibility.h b/comm/third_party/botan/src/lib/utils/stl_compatibility.h new file mode 100644 index 0000000000..03bd5c8ac1 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/stl_compatibility.h @@ -0,0 +1,80 @@ +/* +* STL standards compatibility functions +* (C) 2017 Tomasz Frydrych +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STL_COMPATIBILITY_H_ +#define BOTAN_STL_COMPATIBILITY_H_ + +#include +#include + +#if __cplusplus < 201402L +#include +#include +#include +#endif + +BOTAN_FUTURE_INTERNAL_HEADER(stl_compatability.h) + +namespace Botan +{ +/* +* std::make_unique functionality similar as we have in C++14. +* C++11 version based on proposal for C++14 implemenatation by Stephan T. Lavavej +* source: https://isocpp.org/files/papers/N3656.txt +*/ +#if __cplusplus >= 201402L +template +constexpr auto make_unique(Args&&... args) + { + return std::make_unique(std::forward(args)...); + } + +template +constexpr auto make_unique(std::size_t size) + { + return std::make_unique(size); + } + +#else +namespace stlCompatibilityDetails +{ +template struct _Unique_if + { + typedef std::unique_ptr _Single_object; + }; + +template struct _Unique_if + { + typedef std::unique_ptr _Unknown_bound; + }; + +template struct _Unique_if + { + typedef void _Known_bound; + }; +} // namespace stlCompatibilityDetails + +template +typename stlCompatibilityDetails::_Unique_if::_Single_object make_unique(Args&&... args) + { + return std::unique_ptr(new T(std::forward(args)...)); + } + +template +typename stlCompatibilityDetails::_Unique_if::_Unknown_bound make_unique(size_t n) + { + typedef typename std::remove_extent::type U; + return std::unique_ptr(new U[n]()); + } + +template +typename stlCompatibilityDetails::_Unique_if::_Known_bound make_unique(Args&&...) = delete; + +#endif + +} // namespace Botan +#endif diff --git a/comm/third_party/botan/src/lib/utils/stl_util.h b/comm/third_party/botan/src/lib/utils/stl_util.h new file mode 100644 index 0000000000..d9167bb7db --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/stl_util.h @@ -0,0 +1,110 @@ +/* +* STL Utility Functions +* (C) 1999-2007 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STL_UTIL_H_ +#define BOTAN_STL_UTIL_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +inline std::vector to_byte_vector(const std::string& s) + { + return std::vector(s.cbegin(), s.cend()); + } + +inline std::string to_string(const secure_vector &bytes) + { + return std::string(bytes.cbegin(), bytes.cend()); + } + +/** +* Return the keys of a map as a std::set +*/ +template +std::set map_keys_as_set(const std::map& kv) + { + std::set s; + for(auto&& i : kv) + { + s.insert(i.first); + } + return s; + } + +/* +* Searching through a std::map +* @param mapping the map to search +* @param key is what to look for +* @param null_result is the value to return if key is not in mapping +* @return mapping[key] or null_result +*/ +template +inline V search_map(const std::map& mapping, + const K& key, + const V& null_result = V()) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return i->second; + } + +template +inline R search_map(const std::map& mapping, const K& key, + const R& null_result, const R& found_result) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return found_result; + } + +/* +* Insert a key/value pair into a multimap +*/ +template +void multimap_insert(std::multimap& multimap, + const K& key, const V& value) + { + multimap.insert(std::make_pair(key, value)); + } + +/** +* Existence check for values +*/ +template +bool value_exists(const std::vector& vec, + const T& val) + { + for(size_t i = 0; i != vec.size(); ++i) + if(vec[i] == val) + return true; + return false; + } + +template +void map_remove_if(Pred pred, T& assoc) + { + auto i = assoc.begin(); + while(i != assoc.end()) + { + if(pred(i->first)) + assoc.erase(i++); + else + i++; + } + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/barrier.cpp b/comm/third_party/botan/src/lib/utils/thread_utils/barrier.cpp new file mode 100644 index 0000000000..c05c22121e --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/barrier.cpp @@ -0,0 +1,36 @@ +/* +* Barrier +* (C) 2016 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +void Barrier::wait(size_t delta) + { + std::lock_guard lock(m_mutex); + m_value += delta; + } + +void Barrier::sync() + { + std::unique_lock lock(m_mutex); + + if(m_value > 1) + { + --m_value; + const size_t current_syncs = m_syncs; + m_cond.wait(lock, [this, ¤t_syncs] { return m_syncs != current_syncs; }); + } + else + { + m_value = 0; + ++m_syncs; + m_cond.notify_all(); + } + } + +} diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/barrier.h b/comm/third_party/botan/src/lib/utils/thread_utils/barrier.h new file mode 100644 index 0000000000..749da92a77 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/barrier.h @@ -0,0 +1,42 @@ +/* +* Barrier +* (C) 2016 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_BARRIER_H_ +#define BOTAN_UTIL_BARRIER_H_ + +#include +#include + +namespace Botan { + +/** +Barrier implements a barrier synchronization primitive. wait() will +indicate how many threads to synchronize; each thread needing +synchronization should call sync(). When sync() returns, the barrier +is reset to zero, and the m_syncs counter is incremented. m_syncs is a +counter to ensure that wait() can be called after a sync() even if the +previously sleeping threads have not awoken.) +*/ +class Barrier final + { + public: + explicit Barrier(int value = 0) : m_value(value), m_syncs(0) {} + + void wait(size_t delta); + + void sync(); + + private: + size_t m_value; + size_t m_syncs; + std::mutex m_mutex; + std::condition_variable m_cond; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/info.txt b/comm/third_party/botan/src/lib/utils/thread_utils/info.txt new file mode 100644 index 0000000000..057f536005 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/info.txt @@ -0,0 +1,14 @@ + +THREAD_UTILS -> 20190922 + + + +rwlock.h +barrier.h +semaphore.h +thread_pool.h + + + +threads + diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.cpp b/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.cpp new file mode 100644 index 0000000000..58500a83de --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.cpp @@ -0,0 +1,58 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +RWLock::RWLock() : m_state(0) {} + +void RWLock::lock() + { + std::unique_lock lock(m_mutex); + while(m_state & is_writing) + m_gate1.wait(lock); + m_state |= is_writing; + while(m_state & readers_mask) + m_gate2.wait(lock); + } + +void RWLock::unlock() + { + std::unique_lock lock(m_mutex); + m_state = 0; + m_gate1.notify_all(); + } + +void RWLock::lock_shared() + { + std::unique_lock lock(m_mutex); + while((m_state & is_writing) || (m_state & readers_mask) == readers_mask) + m_gate1.wait(lock); + const uint32_t num_readers = (m_state & readers_mask) + 1; + m_state &= ~readers_mask; + m_state |= num_readers; + } + +void RWLock::unlock_shared() + { + std::unique_lock lock(m_mutex); + const uint32_t num_readers = (m_state & readers_mask) - 1; + m_state &= ~readers_mask; + m_state |= num_readers; + if(m_state & is_writing) + { + if(num_readers == 0) + m_gate2.notify_one(); + } + else + { + if(num_readers == readers_mask - 1) + m_gate1.notify_one(); + } + } + +} diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.h b/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.h new file mode 100644 index 0000000000..324e667538 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.h @@ -0,0 +1,42 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RWLOCK_H_ +#define BOTAN_RWLOCK_H_ + +#include +#include +#include + +namespace Botan { + +/** +* A read-write lock. Writers are favored. +*/ +class BOTAN_TEST_API RWLock final + { + public: + RWLock(); + + void lock(); + void unlock(); + + void lock_shared(); + void unlock_shared(); + private: + std::mutex m_mutex; + std::condition_variable m_gate1; + std::condition_variable m_gate2; + uint32_t m_state; + + // 2**31 concurrent readers should be enough for anyone + static const uint32_t is_writing = static_cast(1) << 31; + static const uint32_t readers_mask = ~is_writing; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/semaphore.cpp b/comm/third_party/botan/src/lib/utils/thread_utils/semaphore.cpp new file mode 100644 index 0000000000..0858a013f2 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/semaphore.cpp @@ -0,0 +1,38 @@ +/* +* Semaphore +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +// Based on code by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html) + +namespace Botan { + +void Semaphore::release(size_t n) + { + for(size_t i = 0; i != n; ++i) + { + std::lock_guard lock(m_mutex); + + if(m_value++ < 0) + { + ++m_wakeups; + m_cond.notify_one(); + } + } + } + +void Semaphore::acquire() + { + std::unique_lock lock(m_mutex); + if(m_value-- <= 0) + { + m_cond.wait(lock, [this] { return m_wakeups > 0; }); + --m_wakeups; + } + } + +} diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/semaphore.h b/comm/third_party/botan/src/lib/utils/thread_utils/semaphore.h new file mode 100644 index 0000000000..538d9ecb51 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/semaphore.h @@ -0,0 +1,34 @@ +/* +* Semaphore +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SEMAPHORE_H_ +#define BOTAN_SEMAPHORE_H_ + +#include +#include + +namespace Botan { + +class Semaphore final + { + public: + explicit Semaphore(int value = 0) : m_value(value), m_wakeups(0) {} + + void acquire(); + + void release(size_t n = 1); + + private: + int m_value; + int m_wakeups; + std::mutex m_mutex; + std::condition_variable m_cond; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.cpp b/comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.cpp new file mode 100644 index 0000000000..405f79585a --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.cpp @@ -0,0 +1,103 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +//static +Thread_Pool& Thread_Pool::global_instance() + { + static Thread_Pool g_thread_pool(OS::read_env_variable_sz("BOTAN_THREAD_POOL_SIZE")); + return g_thread_pool; + } + +Thread_Pool::Thread_Pool(size_t pool_size) + { + if(pool_size == 0) + { + pool_size = OS::get_cpu_available(); + + /* + * For large machines don't create too many threads, unless + * explicitly asked to by the caller. + */ + if(pool_size > 16) + pool_size = 16; + } + + if(pool_size <= 1) + pool_size = 2; + + m_shutdown = false; + + for(size_t i = 0; i != pool_size; ++i) + { + m_workers.push_back(std::thread(&Thread_Pool::worker_thread, this)); + } + } + +void Thread_Pool::shutdown() + { + { + std::unique_lock lock(m_mutex); + + if(m_shutdown == true) + return; + + m_shutdown = true; + + m_more_tasks.notify_all(); + } + + for(auto&& thread : m_workers) + { + thread.join(); + } + m_workers.clear(); + } + +void Thread_Pool::queue_thunk(std::function fn) + { + std::unique_lock lock(m_mutex); + + if(m_shutdown) + throw Invalid_State("Cannot add work after thread pool has shut down"); + + m_tasks.push_back(fn); + m_more_tasks.notify_one(); + } + +void Thread_Pool::worker_thread() + { + for(;;) + { + std::function task; + + { + std::unique_lock lock(m_mutex); + m_more_tasks.wait(lock, [this]{ return m_shutdown || !m_tasks.empty(); }); + + if(m_tasks.empty()) + { + if(m_shutdown) + return; + else + continue; + } + + task = m_tasks.front(); + m_tasks.pop_front(); + } + + task(); + } + } + +} diff --git a/comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.h b/comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.h new file mode 100644 index 0000000000..34f4f26dbc --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/thread_utils/thread_pool.h @@ -0,0 +1,82 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_THREAD_POOL_H_ +#define BOTAN_THREAD_POOL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class BOTAN_TEST_API Thread_Pool + { + public: + /** + * Return an instance to a shared thread pool + */ + static Thread_Pool& global_instance(); + + /** + * Initialize a thread pool with some number of threads + * @param pool_size number of threads in the pool, if 0 + * then some default value is chosen + */ + Thread_Pool(size_t pool_size = 0); + + ~Thread_Pool() { shutdown(); } + + void shutdown(); + + size_t worker_count() const { return m_workers.size(); } + + Thread_Pool(const Thread_Pool&) = delete; + Thread_Pool& operator=(const Thread_Pool&) = delete; + + Thread_Pool(Thread_Pool&&) = delete; + Thread_Pool& operator=(Thread_Pool&&) = delete; + + /* + * Enqueue some work + */ + void queue_thunk(std::function); + + template + auto run(F&& f, Args&&... args) -> std::future::type> + { + typedef typename std::result_of::type return_type; + + auto future_work = std::bind(std::forward(f), std::forward(args)...); + auto task = std::make_shared>(future_work); + auto future_result = task->get_future(); + queue_thunk([task]() { (*task)(); }); + return future_result; + } + + private: + void worker_thread(); + + // Only touched in constructor and destructor + std::vector m_workers; + + std::mutex m_mutex; + std::condition_variable m_more_tasks; + std::deque> m_tasks; + bool m_shutdown; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/timer.cpp b/comm/third_party/botan/src/lib/utils/timer.cpp new file mode 100644 index 0000000000..404da5ce8b --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/timer.cpp @@ -0,0 +1,150 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +void Timer::start() + { + stop(); + m_timer_start = OS::get_system_timestamp_ns(); + m_cpu_cycles_start = OS::get_cpu_cycle_counter(); + } + +void Timer::stop() + { + if(m_timer_start) + { + if(m_cpu_cycles_start != 0) + { + const uint64_t cycles_taken = OS::get_cpu_cycle_counter() - m_cpu_cycles_start; + if(cycles_taken > 0) + { + m_cpu_cycles_used += static_cast(cycles_taken * m_clock_cycle_ratio); + } + } + + const uint64_t now = OS::get_system_timestamp_ns(); + + if(now > m_timer_start) + { + const uint64_t dur = now - m_timer_start; + + m_time_used += dur; + + if(m_event_count == 0) + { + m_min_time = m_max_time = dur; + } + else + { + m_max_time = std::max(m_max_time, dur); + m_min_time = std::min(m_min_time, dur); + } + } + + m_timer_start = 0; + ++m_event_count; + } + } + +bool Timer::operator<(const Timer& other) const + { + if(this->doing() != other.doing()) + return (this->doing() < other.doing()); + + return (this->get_name() < other.get_name()); + } + +std::string Timer::to_string() const + { + if(m_custom_msg.size() > 0) + { + return m_custom_msg; + } + else if(this->buf_size() == 0) + { + return result_string_ops(); + } + else + { + return result_string_bps(); + } + } + +std::string Timer::result_string_bps() const + { + const size_t MiB = 1024 * 1024; + + const double MiB_total = static_cast(events()) / MiB; + const double MiB_per_sec = MiB_total / seconds(); + + std::ostringstream oss; + oss << get_name(); + + if(!doing().empty()) + { + oss << " " << doing(); + } + + if(buf_size() > 0) + { + oss << " buffer size " << buf_size() << " bytes:"; + } + + if(events() == 0) + oss << " " << "N/A"; + else + oss << " " << std::fixed << std::setprecision(3) << MiB_per_sec << " MiB/sec"; + + if(cycles_consumed() != 0) + { + const double cycles_per_byte = static_cast(cycles_consumed()) / events(); + oss << " " << std::fixed << std::setprecision(2) << cycles_per_byte << " cycles/byte"; + } + + oss << " (" << MiB_total << " MiB in " << milliseconds() << " ms)\n"; + + return oss.str(); + } + +std::string Timer::result_string_ops() const + { + std::ostringstream oss; + + oss << get_name() << " "; + + if(events() == 0) + { + oss << "no events\n"; + } + else + { + oss << static_cast(events_per_second()) + << ' ' << doing() << "/sec; " + << std::setprecision(2) << std::fixed + << ms_per_event() << " ms/op"; + + if(cycles_consumed() != 0) + { + const double cycles_per_op = static_cast(cycles_consumed()) / events(); + const int precision = (cycles_per_op < 10000) ? 2 : 0; + oss << " " << std::fixed << std::setprecision(precision) << cycles_per_op << " cycles/op"; + } + + oss << " (" << events() << " " << (events() == 1 ? "op" : "ops") + << " in " << milliseconds() << " ms)\n"; + } + + return oss.str(); + } + +} diff --git a/comm/third_party/botan/src/lib/utils/timer.h b/comm/third_party/botan/src/lib/utils/timer.h new file mode 100644 index 0000000000..f54c81fb62 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/timer.h @@ -0,0 +1,185 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TIMER_H_ +#define BOTAN_TIMER_H_ + +#include +#include +#include + +namespace Botan { + +class BOTAN_TEST_API Timer final + { + public: + Timer(const std::string& name, + const std::string& provider, + const std::string& doing, + uint64_t event_mult, + size_t buf_size, + double clock_cycle_ratio, + uint64_t clock_speed) + : m_name(name + ((provider.empty() || provider == "base") ? "" : " [" + provider + "]")) + , m_doing(doing) + , m_buf_size(buf_size) + , m_event_mult(event_mult) + , m_clock_cycle_ratio(clock_cycle_ratio) + , m_clock_speed(clock_speed) + {} + + Timer(const std::string& name) : + Timer(name, "", "", 1, 0, 0.0, 0) + {} + + Timer(const std::string& name, size_t buf_size) : + Timer(name, "", "", buf_size, buf_size, 0.0, 0) + {} + + Timer(const Timer& other) = default; + Timer& operator=(const Timer& other) = default; + + void start(); + + void stop(); + + bool under(std::chrono::milliseconds msec) + { + return (milliseconds() < msec.count()); + } + + class Timer_Scope final + { + public: + explicit Timer_Scope(Timer& timer) + : m_timer(timer) + { + m_timer.start(); + } + ~Timer_Scope() + { + try + { + m_timer.stop(); + } + catch(...) {} + } + private: + Timer& m_timer; + }; + + template + auto run(F f) -> decltype(f()) + { + Timer_Scope timer(*this); + return f(); + } + + template + void run_until_elapsed(std::chrono::milliseconds msec, F f) + { + while(this->under(msec)) + { + run(f); + } + } + + uint64_t value() const + { + return m_time_used; + } + + double seconds() const + { + return milliseconds() / 1000.0; + } + + double milliseconds() const + { + return value() / 1000000.0; + } + + double ms_per_event() const + { + return milliseconds() / events(); + } + + uint64_t cycles_consumed() const + { + if(m_clock_speed != 0) + { + return static_cast((m_clock_speed * value()) / 1000.0); + } + return m_cpu_cycles_used; + } + + uint64_t events() const + { + return m_event_count * m_event_mult; + } + + const std::string& get_name() const + { + return m_name; + } + + const std::string& doing() const + { + return m_doing; + } + + size_t buf_size() const + { + return m_buf_size; + } + + double bytes_per_second() const + { + return seconds() > 0.0 ? events() / seconds() : 0.0; + } + + double events_per_second() const + { + return seconds() > 0.0 ? events() / seconds() : 0.0; + } + + double seconds_per_event() const + { + return events() > 0 ? seconds() / events() : 0.0; + } + + void set_custom_msg(const std::string& s) + { + m_custom_msg = s; + } + + bool operator<(const Timer& other) const; + + std::string to_string() const; + + private: + std::string result_string_bps() const; + std::string result_string_ops() const; + + // const data + std::string m_name, m_doing; + size_t m_buf_size; + uint64_t m_event_mult; + double m_clock_cycle_ratio; + uint64_t m_clock_speed; + + // set at runtime + std::string m_custom_msg; + uint64_t m_time_used = 0, m_timer_start = 0; + uint64_t m_event_count = 0; + + uint64_t m_max_time = 0, m_min_time = 0; + uint64_t m_cpu_cycles_start = 0, m_cpu_cycles_used = 0; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/types.h b/comm/third_party/botan/src/lib/utils/types.h new file mode 100644 index 0000000000..549163aa8c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/types.h @@ -0,0 +1,112 @@ +/* +* Low Level Types +* (C) 1999-2007 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TYPES_H_ +#define BOTAN_TYPES_H_ + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export + +namespace Botan { + +/** +* @mainpage Botan Crypto Library API Reference +* +*
+*
Abstract Base Classes
+* BlockCipher, HashFunction, KDF, MessageAuthenticationCode, RandomNumberGenerator, +* StreamCipher, SymmetricAlgorithm, AEAD_Mode, Cipher_Mode +*
Public Key Interface Classes
+* PK_Key_Agreement, PK_Signer, PK_Verifier, PK_Encryptor, PK_Decryptor +*
Authenticated Encryption Modes
+* @ref CCM_Mode "CCM", @ref ChaCha20Poly1305_Mode "ChaCha20Poly1305", @ref EAX_Mode "EAX", +* @ref GCM_Mode "GCM", @ref OCB_Mode "OCB", @ref SIV_Mode "SIV" +*
Block Ciphers
+* @ref aria.h "ARIA", @ref aes.h "AES", @ref Blowfish, @ref camellia.h "Camellia", @ref Cascade_Cipher "Cascade", +* @ref CAST_128 "CAST-128", @ref CAST_128 "CAST-256", DES, @ref DESX "DES-X", @ref TripleDES "3DES", +* @ref GOST_28147_89 "GOST 28147-89", IDEA, KASUMI, Lion, MISTY1, Noekeon, SEED, Serpent, SHACAL2, SM4, +* @ref Threefish_512 "Threefish", Twofish, XTEA +*
Stream Ciphers
+* ChaCha, @ref CTR_BE "CTR", OFB, RC4, Salsa20 +*
Hash Functions
+* BLAKE2b, @ref GOST_34_11 "GOST 34.11", @ref Keccak_1600 "Keccak", MD4, MD5, @ref RIPEMD_160 "RIPEMD-160", +* @ref SHA_160 "SHA-1", @ref SHA_224 "SHA-224", @ref SHA_256 "SHA-256", @ref SHA_384 "SHA-384", +* @ref SHA_512 "SHA-512", @ref Skein_512 "Skein-512", SM3, Streebog, Tiger, Whirlpool +*
Non-Cryptographic Checksums
+* Adler32, CRC24, CRC32 +*
Message Authentication Codes
+* @ref CBC_MAC "CBC-MAC", CMAC, HMAC, Poly1305, SipHash, ANSI_X919_MAC +*
Random Number Generators
+* AutoSeeded_RNG, HMAC_DRBG, Processor_RNG, System_RNG +*
Key Derivation
+* HKDF, @ref KDF1 "KDF1 (IEEE 1363)", @ref KDF1_18033 "KDF1 (ISO 18033-2)", @ref KDF2 "KDF2 (IEEE 1363)", +* @ref sp800_108.h "SP800-108", @ref SP800_56C "SP800-56C", @ref PKCS5_PBKDF1 "PBKDF1 (PKCS#5), +* @ref PKCS5_PBKDF2 "PBKDF2 (PKCS#5)" +*
Password Hashing
+* @ref argon2.h "Argon2", @ref scrypt.h "scrypt", @ref bcrypt.h "bcrypt", @ref passhash9.h "passhash9" +*
Public Key Cryptosystems
+* @ref dlies.h "DLIES", @ref ecies.h "ECIES", @ref elgamal.h "ElGamal" +* @ref rsa.h "RSA", @ref newhope.h "NewHope", @ref mceliece.h "McEliece" and @ref mceies.h "MCEIES", +* @ref sm2.h "SM2" +*
Public Key Signature Schemes
+* @ref dsa.h "DSA", @ref ecdsa.h "ECDSA", @ref ecgdsa.h "ECGDSA", @ref eckcdsa.h "ECKCDSA", +* @ref gost_3410.h "GOST 34.10-2001", @ref sm2.h "SM2", @ref xmss.h "XMSS" +*
Key Agreement
+* @ref dh.h "DH", @ref ecdh.h "ECDH" +*
Compression
+* @ref bzip2.h "bzip2", @ref lzma.h "lzma", @ref zlib.h "zlib" +*
TLS
+* TLS::Client, TLS::Server, TLS::Policy, TLS::Protocol_Version, TLS::Callbacks, TLS::Ciphersuite, +* TLS::Session, TLS::Session_Manager, Credentials_Manager +*
X.509
+* X509_Certificate, X509_CRL, X509_CA, Certificate_Extension, PKCS10_Request, X509_Cert_Options, +* Certificate_Store, Certificate_Store_In_SQL, Certificate_Store_In_SQLite +*
+*/ + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::int32_t; +using std::int64_t; +using std::size_t; + +/* +* These typedefs are no longer used within the library headers +* or code. They are kept only for compatability with software +* written against older versions. +*/ +using byte = std::uint8_t; +using u16bit = std::uint16_t; +using u32bit = std::uint32_t; +using u64bit = std::uint64_t; +using s32bit = std::int32_t; + +#if (BOTAN_MP_WORD_BITS == 32) + typedef uint32_t word; +#elif (BOTAN_MP_WORD_BITS == 64) + typedef uint64_t word; +#else + #error BOTAN_MP_WORD_BITS must be 32 or 64 +#endif + +/* +* Should this assert fail on your system please contact the developers +* for assistance in porting. +*/ +static_assert(sizeof(std::size_t) == 8 || sizeof(std::size_t) == 4, + "This platform has an unexpected size for size_t"); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/uuid/info.txt b/comm/third_party/botan/src/lib/utils/uuid/info.txt new file mode 100644 index 0000000000..b078146e8a --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/uuid/info.txt @@ -0,0 +1,8 @@ + +UUID -> 20180930 + + + +rng +hex + diff --git a/comm/third_party/botan/src/lib/utils/uuid/uuid.cpp b/comm/third_party/botan/src/lib/utils/uuid/uuid.cpp new file mode 100644 index 0000000000..c81cae6657 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/uuid/uuid.cpp @@ -0,0 +1,82 @@ +/* +* UUID type +* (C) 2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +UUID::UUID(RandomNumberGenerator& rng) + { + m_uuid.resize(16); + rng.randomize(m_uuid.data(), m_uuid.size()); + + // Mark as a random v4 UUID (RFC 4122 sec 4.4) + m_uuid[6] = 0x40 | (m_uuid[6] & 0x0F); + + // Set reserved bits + m_uuid[8] = 0x80 | (m_uuid[8] & 0x3F); + } + +UUID::UUID(const std::vector& blob) + { + if(blob.size() != 16) + { + throw Invalid_Argument("Bad UUID blob " + hex_encode(blob)); + } + + m_uuid = blob; + } + +UUID::UUID(const std::string& uuid_str) + { + if(uuid_str.size() != 36 || + uuid_str[8] != '-' || + uuid_str[13] != '-' || + uuid_str[18] != '-' || + uuid_str[23] != '-') + { + throw Invalid_Argument("Bad UUID '" + uuid_str + "'"); + } + + std::string just_hex; + for(size_t i = 0; i != uuid_str.size(); ++i) + { + char c = uuid_str[i]; + + if(c == '-') + continue; + + just_hex += c; + } + + m_uuid = hex_decode(just_hex); + + if(m_uuid.size() != 16) + { + throw Invalid_Argument("Bad UUID '" + uuid_str + "'"); + } + } + +std::string UUID::to_string() const + { + if(is_valid() == false) + throw Invalid_State("UUID object is empty cannot convert to string"); + + std::string h = hex_encode(m_uuid); + + h.insert(8, "-"); + h.insert(13, "-"); + h.insert(18, "-"); + h.insert(23, "-"); + + return h; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/uuid/uuid.h b/comm/third_party/botan/src/lib/utils/uuid/uuid.h new file mode 100644 index 0000000000..8f95f4d672 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/uuid/uuid.h @@ -0,0 +1,69 @@ +/* +* UUID type +* (C) 2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UUID_H_ +#define BOTAN_UUID_H_ + +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(uuid.h) + +namespace Botan { + +class RandomNumberGenerator; + +class BOTAN_UNSTABLE_API UUID final + { + public: + /** + * Create an uninitialized UUID object + */ + UUID() : m_uuid() {} + + /** + * Create a random UUID + */ + UUID(RandomNumberGenerator& rng); + + /** + * Load a UUID from a 16 byte vector + */ + UUID(const std::vector& blob); + + UUID& operator=(const UUID& other) = default; + UUID(const UUID& other) = default; + + /** + * Decode a UUID string + */ + UUID(const std::string& uuid_str); + + /** + * Convert the UUID to a string + */ + std::string to_string() const; + + const std::vector& binary_value() const { return m_uuid; } + + bool operator==(const UUID& other) const + { + return m_uuid == other.m_uuid; + } + + bool operator!=(const UUID& other) const { return !(*this == other); } + + bool is_valid() const { return m_uuid.size() == 16; } + + private: + std::vector m_uuid; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/utils/version.cpp b/comm/third_party/botan/src/lib/utils/version.cpp new file mode 100644 index 0000000000..aa82d7cc95 --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/version.cpp @@ -0,0 +1,100 @@ +/* +* Version Information +* (C) 1999-2013,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +/* + These are intentionally compiled rather than inlined, so an + application running against a shared library can test the true + version they are running against. +*/ + +#define QUOTE(name) #name +#define STR(macro) QUOTE(macro) + +const char* short_version_cstr() + { + return STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH) +#if defined(BOTAN_VERSION_SUFFIX) + STR(BOTAN_VERSION_SUFFIX) +#endif + ; + } + +const char* version_cstr() + { + + /* + It is intentional that this string is a compile-time constant; + it makes it much easier to find in binaries. + */ + + return "Botan " STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH) +#if defined(BOTAN_VERSION_SUFFIX) + STR(BOTAN_VERSION_SUFFIX) +#endif + " (" +#if defined(BOTAN_UNSAFE_FUZZER_MODE) + "UNSAFE FUZZER MODE BUILD " +#endif + BOTAN_VERSION_RELEASE_TYPE +#if (BOTAN_VERSION_DATESTAMP != 0) + ", dated " STR(BOTAN_VERSION_DATESTAMP) +#endif + ", revision " BOTAN_VERSION_VC_REVISION + ", distribution " BOTAN_DISTRIBUTION_INFO ")"; + } + +#undef STR +#undef QUOTE + +/* +* Return the version as a string +*/ +std::string version_string() + { + return std::string(version_cstr()); + } + +std::string short_version_string() + { + return std::string(short_version_cstr()); + } + +uint32_t version_datestamp() { return BOTAN_VERSION_DATESTAMP; } + +/* +* Return parts of the version as integers +*/ +uint32_t version_major() { return BOTAN_VERSION_MAJOR; } +uint32_t version_minor() { return BOTAN_VERSION_MINOR; } +uint32_t version_patch() { return BOTAN_VERSION_PATCH; } + +std::string runtime_version_check(uint32_t major, + uint32_t minor, + uint32_t patch) + { + if(major != version_major() || minor != version_minor() || patch != version_patch()) + { + std::ostringstream oss; + oss << "Warning: linked version (" << short_version_string() << ")" + << " does not match version built against " + << "(" << major << '.' << minor << '.' << patch << ")\n"; + return oss.str(); + } + + return ""; + } + +} diff --git a/comm/third_party/botan/src/lib/utils/version.h b/comm/third_party/botan/src/lib/utils/version.h new file mode 100644 index 0000000000..fe59de625c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/version.h @@ -0,0 +1,101 @@ +/* +* Version Information +* (C) 1999-2011,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_VERSION_H_ +#define BOTAN_VERSION_H_ + +#include +#include + +namespace Botan { + +/* +* Get information describing the version +*/ + +/** +* Get a human-readable string identifying the version of Botan. +* No particular format should be assumed. +* @return version string +*/ +BOTAN_PUBLIC_API(2,0) std::string version_string(); + +/** +* Same as version_string() except returning a pointer to a statically +* allocated string. +* @return version string +*/ +BOTAN_PUBLIC_API(2,0) const char* version_cstr(); + +/** +* Return a version string of the form "MAJOR.MINOR.PATCH" where +* each of the values is an integer. +*/ +BOTAN_PUBLIC_API(2,4) std::string short_version_string(); + +/** +* Same as version_short_string except returning a pointer to the string. +*/ +BOTAN_PUBLIC_API(2,4) const char* short_version_cstr(); + +/** +* Return the date this version of botan was released, in an integer of +* the form YYYYMMDD. For instance a version released on May 21, 2013 +* would return the integer 20130521. If the currently running version +* is not an official release, this function will return 0 instead. +* +* @return release date, or zero if unreleased +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_datestamp(); + +/** +* Get the major version number. +* @return major version number +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_major(); + +/** +* Get the minor version number. +* @return minor version number +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_minor(); + +/** +* Get the patch number. +* @return patch number +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_patch(); + +/** +* Usable for checking that the DLL version loaded at runtime exactly +* matches the compile-time version. Call using BOTAN_VERSION_* macro +* values. Returns the empty string if an exact match, otherwise an +* appropriate message. Added with 1.11.26. +*/ +BOTAN_PUBLIC_API(2,0) std::string +runtime_version_check(uint32_t major, + uint32_t minor, + uint32_t patch); + +/* +* Macros for compile-time version checks +*/ +#define BOTAN_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +/** +* Compare using BOTAN_VERSION_CODE_FOR, as in +* # if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,8,0) +* # error "Botan version too old" +* # endif +*/ +#define BOTAN_VERSION_CODE BOTAN_VERSION_CODE_FOR(BOTAN_VERSION_MAJOR, \ + BOTAN_VERSION_MINOR, \ + BOTAN_VERSION_PATCH) + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/asn1_alt_name.cpp b/comm/third_party/botan/src/lib/x509/asn1_alt_name.cpp new file mode 100644 index 0000000000..a347a3114c --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/asn1_alt_name.cpp @@ -0,0 +1,265 @@ +/* +* AlternativeName +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Botan { + +/* +* Create an AlternativeName +*/ +AlternativeName::AlternativeName(const std::string& email_addr, + const std::string& uri, + const std::string& dns, + const std::string& ip) + { + add_attribute("RFC822", email_addr); + add_attribute("DNS", dns); + add_attribute("URI", uri); + add_attribute("IP", ip); + } + +/* +* Add an attribute to an alternative name +*/ +void AlternativeName::add_attribute(const std::string& type, + const std::string& value) + { + if(type.empty() || value.empty()) + return; + + auto range = m_alt_info.equal_range(type); + for(auto j = range.first; j != range.second; ++j) + if(j->second == value) + return; + + multimap_insert(m_alt_info, type, value); + } + +/* +* Add an OtherName field +*/ +void AlternativeName::add_othername(const OID& oid, const std::string& value, + ASN1_Tag type) + { + if(value.empty()) + return; + multimap_insert(m_othernames, oid, ASN1_String(value, type)); + } + +/* +* Return all of the alternative names +*/ +std::multimap AlternativeName::contents() const + { + std::multimap names; + + for(auto i = m_alt_info.begin(); i != m_alt_info.end(); ++i) + { + multimap_insert(names, i->first, i->second); + } + + for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i) + { + multimap_insert(names, i->first.to_formatted_string(), i->second.value()); + } + + return names; + } + +bool AlternativeName::has_field(const std::string& attr) const + { + auto range = m_alt_info.equal_range(attr); + return (range.first != range.second); + } + +std::string AlternativeName::get_first_attribute(const std::string& attr) const + { + auto i = m_alt_info.lower_bound(attr); + if(i != m_alt_info.end() && i->first == attr) + return i->second; + + return ""; + } + +std::vector AlternativeName::get_attribute(const std::string& attr) const + { + std::vector results; + auto range = m_alt_info.equal_range(attr); + for(auto i = range.first; i != range.second; ++i) + results.push_back(i->second); + return results; + } + +X509_DN AlternativeName::dn() const + { + X509_DN dn; + auto range = m_alt_info.equal_range("DN"); + + for(auto i = range.first; i != range.second; ++i) + { + std::istringstream strm(i->second); + strm >> dn; + } + + return dn; + } + +/* +* Return if this object has anything useful +*/ +bool AlternativeName::has_items() const + { + return (m_alt_info.size() > 0 || m_othernames.size() > 0); + } + +namespace { + +/* +* DER encode an AlternativeName entry +*/ +void encode_entries(DER_Encoder& encoder, + const std::multimap& attr, + const std::string& type, ASN1_Tag tagging) + { + auto range = attr.equal_range(type); + + for(auto i = range.first; i != range.second; ++i) + { + if(type == "RFC822" || type == "DNS" || type == "URI") + { + ASN1_String asn1_string(i->second, IA5_STRING); + encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.value()); + } + else if(type == "IP") + { + const uint32_t ip = string_to_ipv4(i->second); + uint8_t ip_buf[4] = { 0 }; + store_be(ip, ip_buf); + encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4); + } + else if (type == "DN") + { + std::stringstream ss(i->second); + X509_DN dn; + ss >> dn; + encoder.encode(dn); + } + } + } + +} + +/* +* DER encode an AlternativeName extension +*/ +void AlternativeName::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + encode_entries(der, m_alt_info, "RFC822", ASN1_Tag(1)); + encode_entries(der, m_alt_info, "DNS", ASN1_Tag(2)); + encode_entries(der, m_alt_info, "DN", ASN1_Tag(4)); + encode_entries(der, m_alt_info, "URI", ASN1_Tag(6)); + encode_entries(der, m_alt_info, "IP", ASN1_Tag(7)); + + for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i) + { + der.start_explicit(0) + .encode(i->first) + .start_explicit(0) + .encode(i->second) + .end_explicit() + .end_explicit(); + } + + der.end_cons(); + } + +/* +* Decode a BER encoded AlternativeName +*/ +void AlternativeName::decode_from(BER_Decoder& source) + { + BER_Decoder names = source.start_cons(SEQUENCE); + + // FIXME this is largely a duplication of GeneralName::decode_from + + while(names.more_items()) + { + BER_Object obj = names.get_next_object(); + + if(obj.is_a(0, CONTEXT_SPECIFIC)) + { + BER_Decoder othername(obj); + + OID oid; + othername.decode(oid); + if(othername.more_items()) + { + BER_Object othername_value_outer = othername.get_next_object(); + othername.verify_end(); + + if(othername_value_outer.is_a(0, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) + throw Decoding_Error("Invalid tags on otherName value"); + + BER_Decoder othername_value_inner(othername_value_outer); + + BER_Object value = othername_value_inner.get_next_object(); + othername_value_inner.verify_end(); + + if(ASN1_String::is_string_type(value.type()) && value.get_class() == UNIVERSAL) + { + add_othername(oid, ASN1::to_string(value), value.type()); + } + } + } + if(obj.is_a(1, CONTEXT_SPECIFIC)) + { + add_attribute("RFC822", ASN1::to_string(obj)); + } + else if(obj.is_a(2, CONTEXT_SPECIFIC)) + { + add_attribute("DNS", ASN1::to_string(obj)); + } + else if(obj.is_a(6, CONTEXT_SPECIFIC)) + { + add_attribute("URI", ASN1::to_string(obj)); + } + else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) + { + BER_Decoder dec(obj); + X509_DN dn; + std::stringstream ss; + + dec.decode(dn); + ss << dn; + + add_attribute("DN", ss.str()); + } + else if(obj.is_a(7, CONTEXT_SPECIFIC)) + { + if(obj.length() == 4) + { + const uint32_t ip = load_be(obj.bits(), 0); + add_attribute("IP", ipv4_to_string(ip)); + } + } + + } + } + +} diff --git a/comm/third_party/botan/src/lib/x509/asn1_alt_name.h b/comm/third_party/botan/src/lib/x509/asn1_alt_name.h new file mode 100644 index 0000000000..b0ca1d87e2 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/asn1_alt_name.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_ALT_NAME_H_ +#define BOTAN_X509_ALT_NAME_H_ + +#include +BOTAN_DEPRECATED_HEADER(asn1_alt_name.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/asn1_attribute.h b/comm/third_party/botan/src/lib/x509/asn1_attribute.h new file mode 100644 index 0000000000..0139c18c70 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/asn1_attribute.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_ATTRIBUTE_H_ +#define BOTAN_ASN1_ATTRIBUTE_H_ + +#include +BOTAN_DEPRECATED_HEADER(asn1_attribute.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/cert_status.cpp b/comm/third_party/botan/src/lib/x509/cert_status.cpp new file mode 100644 index 0000000000..e22d6e1be1 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/cert_status.cpp @@ -0,0 +1,125 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +const char* to_string(Certificate_Status_Code code) + { + switch(code) + { + case Certificate_Status_Code::VERIFIED: + return "Verified"; + case Certificate_Status_Code::OCSP_RESPONSE_GOOD: + return "OCSP response accepted as affirming unrevoked status for certificate"; + case Certificate_Status_Code::OCSP_SIGNATURE_OK: + return "Signature on OCSP response was found valid"; + case Certificate_Status_Code::VALID_CRL_CHECKED: + return "Valid CRL examined"; + + case Certificate_Status_Code::CERT_SERIAL_NEGATIVE: + return "Certificate serial number is negative"; + case Certificate_Status_Code::DN_TOO_LONG: + return "Distinguished name too long"; + case Certificate_Status_Code::OCSP_NO_REVOCATION_URL: + return "OCSP URL not available"; + case Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE: + return "OCSP server not available"; + + case Certificate_Status_Code::NO_REVOCATION_DATA: + return "No revocation data"; + case Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK: + return "Signature method too weak"; + case Certificate_Status_Code::UNTRUSTED_HASH: + return "Hash function used is considered too weak for security"; + + case Certificate_Status_Code::CERT_NOT_YET_VALID: + return "Certificate is not yet valid"; + case Certificate_Status_Code::CERT_HAS_EXPIRED: + return "Certificate has expired"; + case Certificate_Status_Code::OCSP_NOT_YET_VALID: + return "OCSP is not yet valid"; + case Certificate_Status_Code::OCSP_HAS_EXPIRED: + return "OCSP response has expired"; + case Certificate_Status_Code::OCSP_IS_TOO_OLD: + return "OCSP response is too old"; + case Certificate_Status_Code::CRL_NOT_YET_VALID: + return "CRL response is not yet valid"; + case Certificate_Status_Code::CRL_HAS_EXPIRED: + return "CRL has expired"; + + case Certificate_Status_Code::CERT_ISSUER_NOT_FOUND: + return "Certificate issuer not found"; + case Certificate_Status_Code::CANNOT_ESTABLISH_TRUST: + return "Cannot establish trust"; + case Certificate_Status_Code::CERT_CHAIN_LOOP: + return "Loop in certificate chain"; + case Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT: + return "Certificate chain does not end in a CA certificate"; + case Certificate_Status_Code::CHAIN_NAME_MISMATCH: + return "Certificate issuer does not match subject of issuing cert"; + + case Certificate_Status_Code::POLICY_ERROR: + return "Certificate policy error"; + case Certificate_Status_Code::DUPLICATE_CERT_POLICY: + return "Certificate contains duplicate policy"; + case Certificate_Status_Code::INVALID_USAGE: + return "Certificate does not allow the requested usage"; + case Certificate_Status_Code::CERT_CHAIN_TOO_LONG: + return "Certificate chain too long"; + case Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER: + return "CA certificate not allowed to issue certs"; + case Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER: + return "CA certificate not allowed to issue CRLs"; + case Certificate_Status_Code::NO_MATCHING_CRLDP: + return "No CRL with matching distribution point for certificate"; + case Certificate_Status_Code::OCSP_CERT_NOT_LISTED: + return "OCSP cert not listed"; + case Certificate_Status_Code::OCSP_BAD_STATUS: + return "OCSP bad status"; + case Certificate_Status_Code::CERT_NAME_NOMATCH: + return "Certificate does not match provided name"; + case Certificate_Status_Code::NAME_CONSTRAINT_ERROR: + return "Certificate does not pass name constraint"; + case Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION: + return "Unknown critical extension encountered"; + case Certificate_Status_Code::DUPLICATE_CERT_EXTENSION: + return "Duplicate certificate extension encountered"; + case Certificate_Status_Code::EXT_IN_V1_V2_CERT: + return "Encountered extension in certificate with version that does not allow it"; + case Certificate_Status_Code::V2_IDENTIFIERS_IN_V1_CERT: + return "Encountered v2 identifiers in v1 certificate"; + case Certificate_Status_Code::OCSP_SIGNATURE_ERROR: + return "OCSP signature error"; + case Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND: + return "Unable to find certificate issusing OCSP response"; + case Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE: + return "OCSP issuer's keyusage prohibits OCSP"; + case Certificate_Status_Code::OCSP_RESPONSE_INVALID: + return "OCSP parsing valid"; + case Certificate_Status_Code::OCSP_NO_HTTP: + return "OCSP requests not available, no HTTP support compiled in"; + case Certificate_Status_Code::CERT_IS_REVOKED: + return "Certificate is revoked"; + case Certificate_Status_Code::CRL_BAD_SIGNATURE: + return "CRL bad signature"; + case Certificate_Status_Code::SIGNATURE_ERROR: + return "Signature error"; + case Certificate_Status_Code::CERT_PUBKEY_INVALID: + return "Certificate public key invalid"; + case Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN: + return "Certificate signed with unknown/unavailable algorithm"; + case Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS: + return "Certificate signature has invalid parameters"; + + // intentionally no default so we are warned if new enum values are added + } + + return nullptr; + } + +} diff --git a/comm/third_party/botan/src/lib/x509/cert_status.h b/comm/third_party/botan/src/lib/x509/cert_status.h new file mode 100644 index 0000000000..f330ff348f --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/cert_status.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_PATH_RESULT_H_ +#define BOTAN_X509_PATH_RESULT_H_ + +#include +BOTAN_DEPRECATED_HEADER(cert_status.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor.cpp b/comm/third_party/botan/src/lib/x509/certstor.cpp new file mode 100644 index 0000000000..a066f208d4 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor.cpp @@ -0,0 +1,233 @@ +/* +* Certificate Store +* (C) 1999-2010,2013 Jack Lloyd +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +Certificate_Store::~Certificate_Store() {} + +std::shared_ptr +Certificate_Store::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const + { + const auto certs = find_all_certs(subject_dn, key_id); + + if(certs.empty()) + { + return nullptr; // certificate not found + } + + // `count` might be greater than 1, but we'll just select the first match + return certs.front(); + } + +std::shared_ptr Certificate_Store::find_crl_for(const X509_Certificate&) const + { + return {}; + } + +void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) + { + for(const auto& c : m_certs) + if(*c == cert) + return; + + m_certs.push_back(std::make_shared(cert)); + } + +void Certificate_Store_In_Memory::add_certificate(std::shared_ptr cert) + { + for(const auto& c : m_certs) + if(*c == *cert) + return; + + m_certs.push_back(cert); + } + +std::vector Certificate_Store_In_Memory::all_subjects() const + { + std::vector subjects; + for(const auto& cert : m_certs) + subjects.push_back(cert->subject_dn()); + return subjects; + } + +std::shared_ptr +Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn, + const std::vector& key_id) const + { + for(const auto& cert : m_certs) + { + // Only compare key ids if set in both call and in the cert + if(key_id.size()) + { + std::vector skid = cert->subject_key_id(); + + if(skid.size() && skid != key_id) // no match + continue; + } + + if(cert->subject_dn() == subject_dn) + return cert; + } + + return nullptr; + } + +std::vector> Certificate_Store_In_Memory::find_all_certs( + const X509_DN& subject_dn, + const std::vector& key_id) const + { + std::vector> matches; + + for(const auto& cert : m_certs) + { + if(key_id.size()) + { + std::vector skid = cert->subject_key_id(); + + if(skid.size() && skid != key_id) // no match + continue; + } + + if(cert->subject_dn() == subject_dn) + matches.push_back(cert); + } + + return matches; + } + +std::shared_ptr +Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector& key_hash) const + { + if(key_hash.size() != 20) + throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash"); + + std::unique_ptr hash(HashFunction::create("SHA-1")); + + for(const auto& cert : m_certs){ + hash->update(cert->subject_public_key_bitstring()); + if(key_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state + return cert; + } + + return nullptr; + } + +std::shared_ptr +Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const + { + if(subject_hash.size() != 32) + throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256 invalid hash"); + + std::unique_ptr hash(HashFunction::create("SHA-256")); + + for(const auto& cert : m_certs){ + hash->update(cert->raw_subject_dn()); + if(subject_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state + return cert; + } + + return nullptr; + } + +void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) + { + std::shared_ptr crl_s = std::make_shared(crl); + return add_crl(crl_s); + } + +void Certificate_Store_In_Memory::add_crl(std::shared_ptr crl) + { + X509_DN crl_issuer = crl->issuer_dn(); + + for(auto& c : m_crls) + { + // Found an update of a previously existing one; replace it + if(c->issuer_dn() == crl_issuer) + { + if(c->this_update() <= crl->this_update()) + c = crl; + return; + } + } + + // Totally new CRL, add to the list + m_crls.push_back(crl); + } + +std::shared_ptr Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const + { + const std::vector& key_id = subject.authority_key_id(); + + for(const auto& c : m_crls) + { + // Only compare key ids if set in both call and in the CRL + if(key_id.size()) + { + std::vector akid = c->authority_key_id(); + + if(akid.size() && akid != key_id) // no match + continue; + } + + if(c->issuer_dn() == subject.issuer_dn()) + return c; + } + + return {}; + } + +Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert) + { + add_certificate(cert); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir) + { + if(dir.empty()) + return; + + std::vector maybe_certs = get_files_recursive(dir); + + if(maybe_certs.empty()) + { + maybe_certs.push_back(dir); + } + + for(auto&& cert_file : maybe_certs) + { + try + { + DataSource_Stream src(cert_file, true); + while(!src.end_of_data()) + { + try + { + m_certs.push_back(std::make_shared(src)); + } + catch(std::exception&) + { + // stop searching for other certificate at first exception + break; + } + } + } + catch(std::exception&) + { + } + } + } +#endif + +} diff --git a/comm/third_party/botan/src/lib/x509/certstor.h b/comm/third_party/botan/src/lib/x509/certstor.h new file mode 100644 index 0000000000..6901589d26 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor.h @@ -0,0 +1,165 @@ +/* +* Certificate Store +* (C) 1999-2010,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_H_ +#define BOTAN_CERT_STORE_H_ + +#include +#include + +namespace Botan { + +/** +* Certificate Store Interface +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Store + { + public: + virtual ~Certificate_Store(); + + /** + * Find a certificate by Subject DN and (optionally) key identifier + * @param subject_dn the subject's distinguished name + * @param key_id an optional key id + * @return a matching certificate or nullptr otherwise + * If more than one certificate in the certificate store matches, then + * a single value is selected arbitrarily. + */ + virtual std::shared_ptr + find_cert(const X509_DN& subject_dn, const std::vector& key_id) const; + + /** + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + virtual std::vector> find_all_certs( + const X509_DN& subject_dn, const std::vector& key_id) const = 0; + + + /** + * Find a certificate by searching for one with a matching SHA-1 hash of + * public key. Used for OCSP. + * @param key_hash SHA-1 hash of the subject's public key + * @return a matching certificate or nullptr otherwise + */ + virtual std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const = 0; + + /** + * Find a certificate by searching for one with a matching SHA-256 hash of + * raw subject name. Used for OCSP. + * @param subject_hash SHA-256 hash of the subject's raw name + * @return a matching certificate or nullptr otherwise + */ + virtual std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const = 0; + + /** + * Finds a CRL for the given certificate + * @param subject the subject certificate + * @return the CRL for subject or nullptr otherwise + */ + virtual std::shared_ptr find_crl_for(const X509_Certificate& subject) const; + + /** + * @return whether the certificate is known + * @param cert certififcate to be searched + */ + bool certificate_known(const X509_Certificate& cert) const + { + return find_cert(cert.subject_dn(), cert.subject_key_id()) != nullptr; + } + + // remove this (used by TLS::Server) + virtual std::vector all_subjects() const = 0; + }; + +/** +* In Memory Certificate Store +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_Memory final : public Certificate_Store + { + public: + /** + * Attempt to parse all files in dir (including subdirectories) + * as certificates. Ignores errors. + */ + explicit Certificate_Store_In_Memory(const std::string& dir); + + /** + * Adds given certificate to the store. + */ + explicit Certificate_Store_In_Memory(const X509_Certificate& cert); + + /** + * Create an empty store. + */ + Certificate_Store_In_Memory() = default; + + /** + * Add a certificate to the store. + * @param cert certificate to be added + */ + void add_certificate(const X509_Certificate& cert); + + /** + * Add a certificate already in a shared_ptr to the store. + * @param cert certificate to be added + */ + void add_certificate(std::shared_ptr cert); + + /** + * Add a certificate revocation list (CRL) to the store. + * @param crl CRL to be added + */ + void add_crl(const X509_CRL& crl); + + /** + * Add a certificate revocation list (CRL) to the store as a shared_ptr + * @param crl CRL to be added + */ + void add_crl(std::shared_ptr crl); + + /** + * @return DNs for all certificates managed by the store + */ + std::vector all_subjects() const override; + + /* + * Find a certificate by Subject DN and (optionally) key identifier + * @return the first certificate that matches + */ + std::shared_ptr find_cert( + const X509_DN& subject_dn, + const std::vector& key_id) const override; + + /* + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + std::vector> find_all_certs( + const X509_DN& subject_dn, const std::vector& key_id) const override; + + std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const override; + + std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const override; + + /** + * Finds a CRL for the given certificate + */ + std::shared_ptr find_crl_for(const X509_Certificate& subject) const override; + private: + // TODO: Add indexing on the DN and key id to avoid linear search + std::vector> m_certs; + std::vector> m_crls; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp b/comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp new file mode 100644 index 0000000000..9804759b96 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.cpp @@ -0,0 +1,148 @@ +/* +* Certificate Store +* (C) 1999-2019 Jack Lloyd +* (C) 2019 Patrick Schmidt +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { +namespace { +std::vector> decode_all_certificates(DataSource& source) + { + std::vector> pems; + + while(!source.end_of_data()) + { + std::string label; + std::vector cert; + try + { + cert = unlock(PEM_Code::decode(source, label)); + + if(label == "CERTIFICATE" || label == "X509 CERTIFICATE" || label == "TRUSTED CERTIFICATE") + { + pems.push_back(cert); + } + } + catch(const Decoding_Error&) {} + } + + return pems; + } +} + +Flatfile_Certificate_Store::Flatfile_Certificate_Store(const std::string& file, bool ignore_non_ca) + { + if(file.empty()) + { + throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store invalid file path"); + } + + DataSource_Stream file_stream(file); + + for(const std::vector& der : decode_all_certificates(file_stream)) + { + std::shared_ptr cert = std::make_shared(der.data(), der.size()); + + /* + * Various weird or misconfigured system roots include intermediate certificates, + * or even stranger certificates which are not valid for cert issuance at all. + * Previously this code would error on such cases as an obvious misconfiguration, + * but we cannot fix the trust store. So instead just ignore any such certificate. + */ + if(cert->is_self_signed() && cert->is_CA_cert()) + { + m_all_subjects.push_back(cert->subject_dn()); + m_dn_to_cert[cert->subject_dn()].push_back(cert); + m_pubkey_sha1_to_cert.emplace(cert->subject_public_key_bitstring_sha1(), cert); + m_subject_dn_sha256_to_cert.emplace(cert->raw_subject_dn_sha256(), cert); + } + else if(!ignore_non_ca) + { + throw Invalid_Argument("Flatfile_Certificate_Store received non CA cert " + cert->subject_dn().to_string()); + } + } + + if(m_all_subjects.empty()) + { + throw Invalid_Argument("Flatfile_Certificate_Store::Flatfile_Certificate_Store cert file is empty"); + } + } + +std::vector Flatfile_Certificate_Store::all_subjects() const + { + return m_all_subjects; + } + +std::vector> Flatfile_Certificate_Store::find_all_certs( + const X509_DN& subject_dn, + const std::vector& key_id) const + { + std::vector> found_certs; + try + { + const auto certs = m_dn_to_cert.at(subject_dn); + + for(auto cert : certs) + { + if(key_id.empty() || key_id == cert->subject_key_id()) + { + found_certs.push_back(cert); + } + } + } + catch(const std::out_of_range&) + { + return {}; + } + + return found_certs; + } + +std::shared_ptr +Flatfile_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector& key_hash) const + { + if(key_hash.size() != 20) + { + throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_pubkey_sha1 invalid hash"); + } + + auto found_cert = m_pubkey_sha1_to_cert.find(key_hash); + + if(found_cert != m_pubkey_sha1_to_cert.end()) + { + return found_cert->second; + } + + return nullptr; + } + +std::shared_ptr +Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const + { + if(subject_hash.size() != 32) + { throw Invalid_Argument("Flatfile_Certificate_Store::find_cert_by_raw_subject_dn_sha256 invalid hash"); } + + auto found_cert = m_subject_dn_sha256_to_cert.find(subject_hash); + + if(found_cert != m_subject_dn_sha256_to_cert.end()) + { + return found_cert->second; + } + + return nullptr; + } + +std::shared_ptr Flatfile_Certificate_Store::find_crl_for(const X509_Certificate& subject) const + { + BOTAN_UNUSED(subject); + return {}; + } +} diff --git a/comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.h b/comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.h new file mode 100644 index 0000000000..1608aaa118 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_flatfile/certstor_flatfile.h @@ -0,0 +1,77 @@ +/* +* Certificate Store +* (C) 1999-2019 Jack Lloyd +* (C) 2019 Patrick Schmidt +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_FLATFILE_H_ +#define BOTAN_CERT_STORE_FLATFILE_H_ + +#include + +#include +#include +#include + +namespace Botan { +/** +* Certificate Store that is backed by a file of PEMs of trusted CAs. +*/ +class BOTAN_PUBLIC_API(2, 11) Flatfile_Certificate_Store final : public Certificate_Store + { + public: + /** + * Construct a new Certificate_Store given a file path to a file including + * PEMs of trusted self-signed CAs. + * + * @param file the name of the file to read certificates from + * @param ignore_non_ca if true, certs that are not self-signed CA certs will + * be ignored. Otherwise (if false), an exception will be thrown instead. + */ + Flatfile_Certificate_Store(const std::string& file, bool ignore_non_ca = false); + + Flatfile_Certificate_Store(const Flatfile_Certificate_Store&) = default; + Flatfile_Certificate_Store(Flatfile_Certificate_Store&&) = default; + Flatfile_Certificate_Store& operator=(const Flatfile_Certificate_Store&) = default; + Flatfile_Certificate_Store& operator=(Flatfile_Certificate_Store&&) = default; + + /** + * @return DNs for all certificates managed by the store + */ + std::vector all_subjects() const override; + + /** + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + std::vector> find_all_certs( + const X509_DN& subject_dn, const std::vector& key_id) const override; + + /** + * Find a certificate by searching for one with a matching SHA-1 hash of + * public key. + * @return a matching certificate or nullptr otherwise + */ + std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const override; + + std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const override; + + /** + * Fetching CRLs is not supported by this certificate store. This will + * always return an empty list. + */ + std::shared_ptr find_crl_for(const X509_Certificate& subject) const override; + + private: + std::vector m_all_subjects; + std::map>> m_dn_to_cert; + std::map, std::shared_ptr> m_pubkey_sha1_to_cert; + std::map, std::shared_ptr> m_subject_dn_sha256_to_cert; + }; +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor_flatfile/info.txt b/comm/third_party/botan/src/lib/x509/certstor_flatfile/info.txt new file mode 100644 index 0000000000..902997be73 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_flatfile/info.txt @@ -0,0 +1,12 @@ + +CERTSTOR_FLATFILE -> 20190410 + + + +filesystem + + + +certstor_flatfile.h + + diff --git a/comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.cpp b/comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.cpp new file mode 100644 index 0000000000..ab4b8e64a7 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.cpp @@ -0,0 +1,335 @@ +/* +* Certificate Store in SQL +* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +Certificate_Store_In_SQL::Certificate_Store_In_SQL(std::shared_ptr db, + const std::string& passwd, + RandomNumberGenerator& rng, + const std::string& table_prefix) : + m_rng(rng), + m_database(db), + m_prefix(table_prefix), + m_password(passwd) + { + m_database->create_table("CREATE TABLE IF NOT EXISTS " + + m_prefix + "certificates ( \ + fingerprint BLOB PRIMARY KEY, \ + subject_dn BLOB, \ + key_id BLOB, \ + priv_fingerprint BLOB, \ + certificate BLOB UNIQUE NOT NULL\ + )"); + m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "keys (\ + fingerprint BLOB PRIMARY KEY, \ + key BLOB UNIQUE NOT NULL \ + )"); + m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "revoked (\ + fingerprint BLOB PRIMARY KEY, \ + reason BLOB NOT NULL, \ + time BLOB NOT NULL \ + )"); + } + +// Certificate handling +std::shared_ptr +Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const + { + std::shared_ptr stmt; + + const std::vector dn_encoding = subject_dn.BER_encode(); + + if(key_id.empty()) + { + stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1 LIMIT 1"); + stmt->bind(1, dn_encoding); + } + else + { + stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE\ + subject_dn == ?1 AND (key_id == NULL OR key_id == ?2) LIMIT 1"); + stmt->bind(1, dn_encoding); + stmt->bind(2,key_id); + } + + while(stmt->step()) + { + auto blob = stmt->get_blob(0); + return std::make_shared(std::vector(blob.first, blob.first + blob.second)); + } + + return std::shared_ptr(); + } + +std::vector> +Certificate_Store_In_SQL::find_all_certs(const X509_DN& subject_dn, const std::vector& key_id) const + { + std::vector> certs; + + std::shared_ptr stmt; + + const std::vector dn_encoding = subject_dn.BER_encode(); + + if(key_id.empty()) + { + stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1"); + stmt->bind(1, dn_encoding); + } + else + { + stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE\ + subject_dn == ?1 AND (key_id == NULL OR key_id == ?2)"); + stmt->bind(1, dn_encoding); + stmt->bind(2, key_id); + } + + std::shared_ptr cert; + while(stmt->step()) + { + auto blob = stmt->get_blob(0); + certs.push_back(std::make_shared( + std::vector(blob.first,blob.first + blob.second))); + } + + return certs; + } + +std::shared_ptr +Certificate_Store_In_SQL::find_cert_by_pubkey_sha1(const std::vector& /*key_hash*/) const + { + throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_pubkey_sha1"); + } + +std::shared_ptr +Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256(const std::vector& /*subject_hash*/) const + { + throw Not_Implemented("Certificate_Store_In_SQL::find_cert_by_raw_subject_dn_sha256"); + } + +std::shared_ptr +Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const + { + auto all_crls = generate_crls(); + + for(auto crl: all_crls) + { + if(!crl.get_revoked().empty() && crl.issuer_dn() == subject.issuer_dn()) + return std::shared_ptr(new X509_CRL(crl)); + } + + return std::shared_ptr(); + } + +std::vector Certificate_Store_In_SQL::all_subjects() const + { + std::vector ret; + auto stmt = m_database->new_statement("SELECT subject_dn FROM " + m_prefix + "certificates"); + + while(stmt->step()) + { + auto blob = stmt->get_blob(0); + BER_Decoder dec(blob.first,blob.second); + X509_DN dn; + + dn.decode_from(dec); + + ret.push_back(dn); + } + + return ret; + } + +bool Certificate_Store_In_SQL::insert_cert(const X509_Certificate& cert) + { + const std::vector dn_encoding = cert.subject_dn().BER_encode(); + const std::vector cert_encoding = cert.BER_encode(); + + auto stmt = m_database->new_statement("INSERT OR REPLACE INTO " + + m_prefix + "certificates (\ + fingerprint, \ + subject_dn, \ + key_id, \ + priv_fingerprint, \ + certificate \ + ) VALUES ( ?1, ?2, ?3, ?4, ?5 )"); + + stmt->bind(1,cert.fingerprint("SHA-256")); + stmt->bind(2,dn_encoding); + stmt->bind(3,cert.subject_key_id()); + stmt->bind(4,std::vector()); + stmt->bind(5,cert_encoding); + stmt->spin(); + + return true; + } + + +bool Certificate_Store_In_SQL::remove_cert(const X509_Certificate& cert) + { + if(!find_cert(cert.subject_dn(),cert.subject_key_id())) + return false; + + auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "certificates WHERE fingerprint == ?1"); + + stmt->bind(1,cert.fingerprint("SHA-256")); + stmt->spin(); + + return true; + } + +// Private key handling +std::shared_ptr Certificate_Store_In_SQL::find_key(const X509_Certificate& cert) const + { + auto stmt = m_database->new_statement("SELECT key FROM " + m_prefix + "keys " + "JOIN " + m_prefix + "certificates ON " + + m_prefix + "keys.fingerprint == " + m_prefix + "certificates.priv_fingerprint " + "WHERE " + m_prefix + "certificates.fingerprint == ?1"); + stmt->bind(1,cert.fingerprint("SHA-256")); + + std::shared_ptr key; + while(stmt->step()) + { + auto blob = stmt->get_blob(0); + DataSource_Memory src(blob.first,blob.second); + key.reset(PKCS8::load_key(src, m_rng, m_password)); + } + + return key; + } + +std::vector> +Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const + { + auto fpr = key.fingerprint_private("SHA-256"); + auto stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE priv_fingerprint == ?1"); + + stmt->bind(1,fpr); + + std::vector> certs; + while(stmt->step()) + { + auto blob = stmt->get_blob(0); + certs.push_back(std::make_shared( + std::vector(blob.first,blob.first + blob.second))); + } + + return certs; + } + +bool Certificate_Store_In_SQL::insert_key(const X509_Certificate& cert, const Private_Key& key) { + insert_cert(cert); + + if(find_key(cert)) + return false; + + auto pkcs8 = PKCS8::BER_encode(key, m_rng, m_password); + auto fpr = key.fingerprint_private("SHA-256"); + + auto stmt1 = m_database->new_statement( + "INSERT OR REPLACE INTO " + m_prefix + "keys ( fingerprint, key ) VALUES ( ?1, ?2 )"); + + stmt1->bind(1,fpr); + stmt1->bind(2,pkcs8.data(),pkcs8.size()); + stmt1->spin(); + + auto stmt2 = m_database->new_statement( + "UPDATE " + m_prefix + "certificates SET priv_fingerprint = ?1 WHERE fingerprint == ?2"); + + stmt2->bind(1,fpr); + stmt2->bind(2,cert.fingerprint("SHA-256")); + stmt2->spin(); + + return true; + } + +void Certificate_Store_In_SQL::remove_key(const Private_Key& key) + { + auto fpr = key.fingerprint_private("SHA-256"); + auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "keys WHERE fingerprint == ?1"); + + stmt->bind(1,fpr); + stmt->spin(); + } + +// Revocation +void Certificate_Store_In_SQL::revoke_cert(const X509_Certificate& cert, CRL_Code code, const X509_Time& time) + { + insert_cert(cert); + + auto stmt1 = m_database->new_statement( + "INSERT OR REPLACE INTO " + m_prefix + "revoked ( fingerprint, reason, time ) VALUES ( ?1, ?2, ?3 )"); + + stmt1->bind(1,cert.fingerprint("SHA-256")); + stmt1->bind(2,code); + + if(time.time_is_set()) + { + stmt1->bind(3, time.BER_encode()); + } + else + { + stmt1->bind(3, static_cast(-1)); + } + + stmt1->spin(); + } + +void Certificate_Store_In_SQL::affirm_cert(const X509_Certificate& cert) + { + auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "revoked WHERE fingerprint == ?1"); + + stmt->bind(1,cert.fingerprint("SHA-256")); + stmt->spin(); + } + +std::vector Certificate_Store_In_SQL::generate_crls() const + { + auto stmt = m_database->new_statement( + "SELECT certificate,reason,time FROM " + m_prefix + "revoked " + "JOIN " + m_prefix + "certificates ON " + + m_prefix + "certificates.fingerprint == " + m_prefix + "revoked.fingerprint"); + + std::map> crls; + while(stmt->step()) + { + auto blob = stmt->get_blob(0); + auto cert = X509_Certificate( + std::vector(blob.first,blob.first + blob.second)); + auto code = static_cast(stmt->get_size_t(1)); + auto ent = CRL_Entry(cert,code); + + auto i = crls.find(cert.issuer_dn()); + if(i == crls.end()) + { + crls.insert(std::make_pair(cert.issuer_dn(),std::vector({ent}))); + } + else + { + i->second.push_back(ent); + } + } + + std::vector ret; + X509_Time t(std::chrono::system_clock::now()); + + for(auto p: crls) + { + ret.push_back(X509_CRL(p.first,t,t,p.second)); + } + + return ret; + } + +} diff --git a/comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.h b/comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.h new file mode 100644 index 0000000000..fd80eb1919 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_sql/certstor_sql.h @@ -0,0 +1,119 @@ +/* +* Certificate Store in SQL +* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_SQL_H_ +#define BOTAN_CERT_STORE_SQL_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class Private_Key; +class RandomNumberGenerator; + +/** + * Certificate and private key store backed by an SQL database. + */ +class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_SQL : public Certificate_Store + { + public: + /** + * Create/open a certificate store. + * @param db underlying database storage + * @param passwd password to encrypt private keys in the database + * @param rng used for encrypting keys + * @param table_prefix optional prefix for db table names + */ + explicit Certificate_Store_In_SQL(const std::shared_ptr db, + const std::string& passwd, + RandomNumberGenerator& rng, + const std::string& table_prefix = ""); + + /** + * Returns the first certificate with matching subject DN and optional key ID. + */ + std::shared_ptr + find_cert(const X509_DN& subject_dn, const std::vector& key_id) const override; + + /* + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + std::vector> find_all_certs( + const X509_DN& subject_dn, const std::vector& key_id) const override; + + std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const override; + + std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const override; + + /** + * Returns all subject DNs known to the store instance. + */ + std::vector all_subjects() const override; + + /** + * Inserts "cert" into the store, returns false if the certificate is + * already known and true if insertion was successful. + */ + bool insert_cert(const X509_Certificate& cert); + + /** + * Removes "cert" from the store. Returns false if the certificate could not + * be found and true if removal was successful. + */ + bool remove_cert(const X509_Certificate& cert); + + /// Returns the private key for "cert" or an empty shared_ptr if none was found. + std::shared_ptr find_key(const X509_Certificate&) const; + + /// Returns all certificates for private key "key". + std::vector> + find_certs_for_key(const Private_Key& key) const; + + /** + * Inserts "key" for "cert" into the store, returns false if the key is + * already known and true if insertion was successful. + */ + bool insert_key(const X509_Certificate& cert, const Private_Key& key); + + /// Removes "key" from the store. + void remove_key(const Private_Key& key); + + /// Marks "cert" as revoked starting from "time". + void revoke_cert(const X509_Certificate&, CRL_Code, const X509_Time& time = X509_Time()); + + /// Reverses the revokation for "cert". + void affirm_cert(const X509_Certificate&); + + /** + * Generates Certificate Revocation Lists for all certificates marked as revoked. + * A CRL is returned for each unique issuer DN. + */ + std::vector generate_crls() const; + + /** + * Generates a CRL for all certificates issued by the given issuer. + */ + std::shared_ptr + find_crl_for(const X509_Certificate& issuer) const override; + + private: + RandomNumberGenerator& m_rng; + std::shared_ptr m_database; + std::string m_prefix; + std::string m_password; + mutex_type m_mutex; + }; + +} +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor_sql/info.txt b/comm/third_party/botan/src/lib/x509/certstor_sql/info.txt new file mode 100644 index 0000000000..a6046e5d73 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_sql/info.txt @@ -0,0 +1,3 @@ + +CERTSTOR_SQL -> 20160818 + diff --git a/comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.cpp b/comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.cpp new file mode 100644 index 0000000000..b7c066483d --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.cpp @@ -0,0 +1,19 @@ +/* +* Certificate Store in SQL +* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +Certificate_Store_In_SQLite::Certificate_Store_In_SQLite(const std::string& db_path, + const std::string& passwd, + RandomNumberGenerator& rng, + const std::string& table_prefix) : + Certificate_Store_In_SQL(std::make_shared(db_path), passwd, rng, table_prefix) + {} +} diff --git a/comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.h b/comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.h new file mode 100644 index 0000000000..6d4187e148 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_sqlite3/certstor_sqlite.h @@ -0,0 +1,34 @@ +/* +* Certificate Store in SQL +* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_SQLITE_H_ +#define BOTAN_CERT_STORE_SQLITE_H_ + +#include + +namespace Botan { + +/** +* Certificate and private key store backed by an sqlite (https://sqlite.org) database. +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_SQLite final : public Certificate_Store_In_SQL + { + public: + /** + * Create/open a certificate store. + * @param db_path path to the database file + * @param passwd password to encrypt private keys in the database + * @param rng used for encrypting keys + * @param table_prefix optional prefix for db table names + */ + Certificate_Store_In_SQLite(const std::string& db_path, + const std::string& passwd, + RandomNumberGenerator& rng, + const std::string& table_prefix = ""); + }; +} +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor_sqlite3/info.txt b/comm/third_party/botan/src/lib/x509/certstor_sqlite3/info.txt new file mode 100644 index 0000000000..39b8c579b8 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_sqlite3/info.txt @@ -0,0 +1,8 @@ + +CERTSTOR_SQLITE3 -> 20160818 + + + +certstor_sql +sqlite3 + diff --git a/comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.cpp b/comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.cpp new file mode 100644 index 0000000000..0fca1a9757 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.cpp @@ -0,0 +1,70 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#if defined(BOTAN_HAS_CERTSTOR_MACOS) + #include +#elif defined(BOTAN_HAS_CERTSTOR_WINDOWS) + #include +#elif defined(BOTAN_HAS_CERTSTOR_FLATFILE) && defined(BOTAN_SYSTEM_CERT_BUNDLE) + #include +#endif + +namespace Botan { + +System_Certificate_Store::System_Certificate_Store() + { +#if defined(BOTAN_HAS_CERTSTOR_MACOS) + m_system_store = std::make_shared(); +#elif defined(BOTAN_HAS_CERTSTOR_WINDOWS) + m_system_store = std::make_shared(); +#elif defined(BOTAN_HAS_CERTSTOR_FLATFILE) && defined(BOTAN_SYSTEM_CERT_BUNDLE) + m_system_store = std::make_shared(BOTAN_SYSTEM_CERT_BUNDLE, true); +#else + throw Not_Implemented("No system certificate store available in this build"); +#endif + } + +std::shared_ptr +System_Certificate_Store::find_cert(const X509_DN& subject_dn, const std::vector& key_id) const + { + return m_system_store->find_cert(subject_dn, key_id); + } + +std::vector> +System_Certificate_Store::find_all_certs(const X509_DN& subject_dn, + const std::vector& key_id) const + { + return m_system_store->find_all_certs(subject_dn, key_id); + } + +std::shared_ptr +System_Certificate_Store::find_cert_by_pubkey_sha1(const std::vector& key_hash) const + { + return m_system_store->find_cert_by_pubkey_sha1(key_hash); + } + +std::shared_ptr +System_Certificate_Store::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const + { + return m_system_store->find_cert_by_raw_subject_dn_sha256(subject_hash); + } + +std::shared_ptr +System_Certificate_Store::find_crl_for(const X509_Certificate& subject) const + { + return m_system_store->find_crl_for(subject); + } + +std::vector System_Certificate_Store::all_subjects() const + { + return m_system_store->all_subjects(); + } + +} diff --git a/comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.h b/comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.h new file mode 100644 index 0000000000..3a0fc6153a --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system/certstor_system.h @@ -0,0 +1,42 @@ +/* +* (C) 2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYSTEM_CERT_STORE_H_ +#define BOTAN_SYSTEM_CERT_STORE_H_ + +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(2,11) System_Certificate_Store final : public Certificate_Store + { + public: + + System_Certificate_Store(); + + std::shared_ptr + find_cert(const X509_DN& subject_dn, const std::vector& key_id) const override; + + std::vector> + find_all_certs(const X509_DN& subject_dn, const std::vector& key_id) const override; + + std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const override; + + std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const override; + + std::shared_ptr find_crl_for(const X509_Certificate& subject) const override; + + std::vector all_subjects() const override; + + private: + std::shared_ptr m_system_store; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor_system/info.txt b/comm/third_party/botan/src/lib/x509/certstor_system/info.txt new file mode 100644 index 0000000000..c9b3ca73ef --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system/info.txt @@ -0,0 +1,8 @@ + +CERTSTOR_SYSTEM -> 20190411 + + + +apple_keychain +filesystem + diff --git a/comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.cpp b/comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.cpp new file mode 100644 index 0000000000..1836f3da4b --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.cpp @@ -0,0 +1,470 @@ +/* +* Certificate Store +* (C) 1999-2019 Jack Lloyd +* (C) 2019-2020 René Meusel +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 +#include +#include + +namespace Botan { + +namespace { + +/** + * Abstract RAII wrapper for CFTypeRef-style object handles + * All of those xxxRef types are eventually typedefs to void* + */ +template +class scoped_CFType + { + public: + explicit scoped_CFType(T value) + : m_value(value) + { + } + + scoped_CFType(const scoped_CFType& rhs) = delete; + scoped_CFType(scoped_CFType&& rhs) : + m_value(std::move(rhs.m_value)) + { + rhs.m_value = nullptr; + } + + ~scoped_CFType() + { + if(m_value) + { + CFRelease(m_value); + } + } + + operator bool() const { return m_value != nullptr; } + + void assign(T value) + { + BOTAN_ASSERT(m_value == nullptr, "scoped_CFType was not set yet"); + m_value = value; + } + + T& get() { return m_value; } + const T& get() const { return m_value; } + + private: + T m_value; + }; + +/** + * Apple's DN parser "normalizes" ASN1 'PrintableString' into upper-case values + * and strips leading, trailing as well as multiple white spaces. + * See: opensource.apple.com/source/Security/Security-55471/sec/Security/SecCertificate.c.auto.html + */ +X509_DN normalize(const X509_DN& dn) + { + X509_DN result; + + for(const auto& rdn : dn.dn_info()) + { + // TODO: C++14 - use std::get(), resp. std::get() + const auto oid = rdn.first; + auto str = rdn.second; + + if(str.tagging() == ASN1_Tag::PRINTABLE_STRING) + { + std::string normalized; + normalized.reserve(str.value().size()); + for(const char c : str.value()) + { + if(c != ' ') + { + // store all 'normal' characters as upper case + normalized.push_back(::toupper(c)); + } + else if(!normalized.empty() && normalized.back() != ' ') + { + // remove leading and squash multiple white spaces + normalized.push_back(c); + } + } + + if(normalized.back() == ' ') + { + // remove potential remaining single trailing white space char + normalized.erase(normalized.end() - 1); + } + + str = ASN1_String(normalized, str.tagging()); + } + + result.add_attribute(oid, str); + } + + return result; + } + +std::vector normalizeAndSerialize(const X509_DN& dn) + { + std::vector result_dn; + DER_Encoder encoder(result_dn); + normalize(dn).encode_into(encoder); + return result_dn; + } + +std::string to_string(const CFStringRef cfstring) + { + const char* ccstr = CFStringGetCStringPtr(cfstring, kCFStringEncodingUTF8); + + if(ccstr != nullptr) + { + return std::string(ccstr); + } + + auto utf16_pairs = CFStringGetLength(cfstring); + auto max_utf8_bytes = CFStringGetMaximumSizeForEncoding(utf16_pairs, kCFStringEncodingUTF8); + + std::vector cstr(max_utf8_bytes, '\0'); + auto result = CFStringGetCString(cfstring, + cstr.data(), cstr.size(), + kCFStringEncodingUTF8); + + return (result) ? std::string(cstr.data()) : std::string(); + } + +std::string to_string(const OSStatus status) + { + scoped_CFType eCFString( + SecCopyErrorMessageString(status, nullptr)); + return to_string(eCFString.get()); + } + +void check_success(const OSStatus status, const std::string context) + { + if(errSecSuccess == status) + { + return; + } + + throw Internal_Error( + std::string("failed to " + context + ": " + to_string(status))); + } + +template +void check_notnull(const T& value, const std::string context) + { + if(value) + { + return; + } + + throw Internal_Error(std::string("failed to ") + context); + } + +} // namespace + +/** + * Internal class implementation (i.e. Pimpl) to keep the required platform- + * dependent members of Certificate_Store_MacOS contained in this compilation + * unit. + */ +class Certificate_Store_MacOS_Impl + { + private: + static constexpr const char* system_roots = + "/System/Library/Keychains/SystemRootCertificates.keychain"; + static constexpr const char* system_keychain = + "/Library/Keychains/System.keychain"; + + public: + /** + * Wraps a list of search query parameters that are later passed into + * Apple's certifificate store API. The class provides some convenience + * functionality and handles the query paramenter's data lifetime. + */ + class Query + { + public: + Query() = default; + ~Query() = default; + Query(Query&& other) = default; + Query& operator=(Query&& other) = default; + + Query(const Query& other) = delete; + Query& operator=(const Query& other) = delete; + + public: + void addParameter(CFStringRef key, CFTypeRef value) + { + m_keys.emplace_back(key); + m_values.emplace_back(value); + } + + void addParameter(CFStringRef key, std::vector value) + { + // TODO C++17: std::vector::emplace_back will return the reference + // to the inserted object straight away. + m_data_store.emplace_back(std::move(value)); + const auto& data = m_data_store.back(); + + m_data_refs.emplace_back(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + data.data(), + data.size(), + kCFAllocatorNull)); + const auto& data_ref = m_data_refs.back(); + check_notnull(data_ref, "create CFDataRef of search object failed"); + + addParameter(key, data_ref.get()); + } + + /** + * Amends the user-provided search query with generic filter rules + * for the associated system keychains and transforms it into a + * representation that can be passed to the Apple keychain API. + */ + scoped_CFType prepare(const CFArrayRef& keychains, + const SecPolicyRef& policy) + { + addParameter(kSecClass, kSecClassCertificate); + addParameter(kSecReturnRef, kCFBooleanTrue); + addParameter(kSecMatchLimit, kSecMatchLimitAll); + addParameter(kSecMatchTrustedOnly, kCFBooleanTrue); + addParameter(kSecMatchSearchList, keychains); + addParameter(kSecMatchPolicy, policy); + + BOTAN_ASSERT_EQUAL(m_keys.size(), m_values.size(), "valid key-value pairs"); + + auto query = scoped_CFType(CFDictionaryCreate( + kCFAllocatorDefault, (const void**)m_keys.data(), + (const void**)m_values.data(), m_keys.size(), + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + check_notnull(query, "create search query"); + + return query; + } + + private: + using Data = std::vector>; + using DataRefs = std::vector>; + using Keys = std::vector; + using Values = std::vector; + + Data m_data_store; //! makes sure that data parameters are kept alive + DataRefs m_data_refs; //! keeps track of CFDataRef objects refering into \p m_data_store + Keys m_keys; //! ordered list of search parameter keys + Values m_values; //! ordered list of search parameter values + }; + + public: + Certificate_Store_MacOS_Impl() : + m_policy(SecPolicyCreateBasicX509()), + m_system_roots(nullptr), + m_system_chain(nullptr), + m_keychains(nullptr) + { + check_success(SecKeychainOpen(system_roots, &m_system_roots.get()), + "open system root certificates"); + check_success(SecKeychainOpen(system_keychain, &m_system_chain.get()), + "open system keychain"); + check_notnull(m_system_roots, "open system root certificate chain"); + check_notnull(m_system_chain, "open system certificate chain"); + + // m_keychains is merely a convenience list view into all open keychain + // objects. This list is required in prepareQuery(). + std::array keychains{{ + m_system_roots.get(), + m_system_chain.get() + }}; + + m_keychains.assign( + CFArrayCreate(kCFAllocatorDefault, + keychains.data(), + keychains.size(), + &kCFTypeArrayCallBacks)); + check_notnull(m_keychains, "initialize keychain array"); + } + + std::shared_ptr findOne(Query query) const + { + query.addParameter(kSecMatchLimit, kSecMatchLimitOne); + + scoped_CFType result(nullptr); + search(std::move(query), &result.get()); + + return (result) ? readCertificate(result.get()) : nullptr; + } + + std::vector> findAll(Query query) const + { + query.addParameter(kSecMatchLimit, kSecMatchLimitAll); + + scoped_CFType result(nullptr); + search(std::move(query), (CFTypeRef*)&result.get()); + + std::vector> output; + + if(result) + { + const auto count = CFArrayGetCount(result.get()); + BOTAN_ASSERT(count > 0, "certificate result list contains data"); + + for(unsigned int i = 0; i < count; ++i) + { + auto cert = CFArrayGetValueAtIndex(result.get(), i); + output.emplace_back(readCertificate(cert)); + } + } + + return output; + } + + protected: + void search(Query query, CFTypeRef* result) const + { + scoped_CFType fullQuery(query.prepare(keychains(), policy())); + + auto status = SecItemCopyMatching(fullQuery.get(), result); + + if(errSecItemNotFound == status) + { + return; // no matches + } + + check_success(status, "look up certificate"); + check_notnull(result, "look up certificate (invalid result value)"); + } + + /** + * Convert a CFTypeRef object into a Botan::X509_Certificate + */ + std::shared_ptr readCertificate(CFTypeRef object) const + { + if(!object || CFGetTypeID(object) != SecCertificateGetTypeID()) + { + throw Internal_Error("cannot convert CFTypeRef to SecCertificateRef"); + } + + auto cert = static_cast(const_cast(object)); + + scoped_CFType derData(SecCertificateCopyData(cert)); + check_notnull(derData, "read extracted certificate"); + + const auto data = CFDataGetBytePtr(derData.get()); + const auto length = CFDataGetLength(derData.get()); + + DataSource_Memory ds(data, length); + return std::make_shared(ds); + } + + CFArrayRef keychains() const { return m_keychains.get(); } + SecPolicyRef policy() const { return m_policy.get(); } + + private: + scoped_CFType m_policy; + scoped_CFType m_system_roots; + scoped_CFType m_system_chain; + scoped_CFType m_keychains; + }; + +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// +// Implementation of Botan::Certificate_Store interface ... +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// + +Certificate_Store_MacOS::Certificate_Store_MacOS() : + m_impl(std::make_shared()) + { + } + +std::vector Certificate_Store_MacOS::all_subjects() const + { + // Note: This fetches and parses all certificates in the trust store. + // Apple's API provides SecCertificateCopyNormalizedSubjectSequence + // which facilitates reading the certificate DN without parsing the + // entire certificate via Botan::X509_Certificate. However, this + // function applies the same DN "normalization" as stated above. + const auto certificates = m_impl->findAll({}); + + std::vector output; + std::transform(certificates.cbegin(), certificates.cend(), + std::back_inserter(output), + [](const std::shared_ptr cert) + { + return cert->subject_dn(); + }); + + return output; + } + +std::shared_ptr +Certificate_Store_MacOS::find_cert(const X509_DN& subject_dn, + const std::vector& key_id) const + { + Certificate_Store_MacOS_Impl::Query query; + query.addParameter(kSecAttrSubject, normalizeAndSerialize(subject_dn)); + + if(!key_id.empty()) + { + query.addParameter(kSecAttrSubjectKeyID, key_id); + } + + return m_impl->findOne(std::move(query)); + } + +std::vector> Certificate_Store_MacOS::find_all_certs( + const X509_DN& subject_dn, + const std::vector& key_id) const + { + Certificate_Store_MacOS_Impl::Query query; + query.addParameter(kSecAttrSubject, normalizeAndSerialize(subject_dn)); + + if(!key_id.empty()) + { + query.addParameter(kSecAttrSubjectKeyID, key_id); + } + + return m_impl->findAll(std::move(query)); + } + +std::shared_ptr +Certificate_Store_MacOS::find_cert_by_pubkey_sha1(const std::vector& key_hash) const + { + if(key_hash.size() != 20) + { + throw Invalid_Argument("Certificate_Store_MacOS::find_cert_by_pubkey_sha1 invalid hash"); + } + + Certificate_Store_MacOS_Impl::Query query; + query.addParameter(kSecAttrPublicKeyHash, key_hash); + + return m_impl->findOne(std::move(query)); + } + +std::shared_ptr +Certificate_Store_MacOS::find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const + { + BOTAN_UNUSED(subject_hash); + throw Not_Implemented("Certificate_Store_MacOS::find_cert_by_raw_subject_dn_sha256"); + } + +std::shared_ptr Certificate_Store_MacOS::find_crl_for(const X509_Certificate& subject) const + { + BOTAN_UNUSED(subject); + return {}; + } + +} // namespace Botan diff --git a/comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.h b/comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.h new file mode 100644 index 0000000000..e7416e631c --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system_macos/certstor_macos.h @@ -0,0 +1,81 @@ +/* +* Certificate Store +* (C) 1999-2019 Jack Lloyd +* (C) 2019 René Meusel +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_SYSTEM_MACOS_H_ +#define BOTAN_CERT_STORE_SYSTEM_MACOS_H_ + +#include + +#include + +namespace Botan { + +class Certificate_Store_MacOS_Impl; + +/** +* Certificate Store that is backed by the system trust store on macOS. This +* opens a handle to the macOS keychain and serves certificate queries directly +* from there. +*/ +class BOTAN_PUBLIC_API(2, 10) Certificate_Store_MacOS final : public Certificate_Store + { + public: + Certificate_Store_MacOS(); + + Certificate_Store_MacOS(const Certificate_Store_MacOS&) = default; + Certificate_Store_MacOS(Certificate_Store_MacOS&&) = default; + Certificate_Store_MacOS& operator=(const Certificate_Store_MacOS&) = default; + Certificate_Store_MacOS& operator=(Certificate_Store_MacOS&&) = default; + + /** + * @return DNs for all certificates managed by the store + */ + std::vector all_subjects() const override; + + /** + * Find a certificate by Subject DN and (optionally) key identifier + * @return the first certificate that matches + */ + std::shared_ptr find_cert( + const X509_DN& subject_dn, + const std::vector& key_id) const override; + + /** + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + std::vector> find_all_certs( + const X509_DN& subject_dn, const std::vector& key_id) const override; + + /** + * Find a certificate by searching for one with a matching SHA-1 hash of + * public key. + * @return a matching certificate or nullptr otherwise + */ + std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const override; + + /** + * @throws Botan::Not_Implemented + */ + std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const override; + + /** + * Fetching CRLs is not supported by the keychain on macOS. This will + * always return an empty list. + */ + std::shared_ptr find_crl_for(const X509_Certificate& subject) const override; + + private: + std::shared_ptr m_impl; + }; + +} + +#endif \ No newline at end of file diff --git a/comm/third_party/botan/src/lib/x509/certstor_system_macos/info.txt b/comm/third_party/botan/src/lib/x509/certstor_system_macos/info.txt new file mode 100644 index 0000000000..723ec61bd9 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system_macos/info.txt @@ -0,0 +1,15 @@ + +CERTSTOR_MACOS -> 20190207 + + + +apple_keychain + + + +certstor_macos.h + + + +macos -> CoreFoundation,Security + diff --git a/comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.cpp b/comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.cpp new file mode 100644 index 0000000000..51530954ac --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.cpp @@ -0,0 +1,258 @@ +/* +* Certificate Store +* (C) 1999-2019 Jack Lloyd +* (C) 2018-2019 Patrik Fiedler, Tim Oesterreich +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +#include +#include + +#define NOMINMAX 1 +#define _WINSOCKAPI_ // stop windows.h including winsock.h +#include +#include + +#define WINCRYPT_UNUSED_PARAM 0 // for avoiding warnings when passing NULL to unused params in win32 api that accept integer types + +namespace Botan { +namespace { + +using Cert_Pointer = std::shared_ptr; +using Cert_Vector = std::vector; +const std::array cert_store_names{"Root", "CA"}; + +/** + * Abstract RAII wrapper for PCCERT_CONTEXT and HCERTSTORE + * The Windows API partly takes care of those pointers destructions itself. + * Especially, iteratively calling `CertFindCertificateInStore` with the previous PCCERT_CONTEXT + * will free the context and return a new one. In this case, this guard takes care of freeing the context + * in case of an exception and at the end of the iterative process. + */ +template +class Handle_Guard + { + public: + Handle_Guard(T context) + : m_context(context) + { + } + + Handle_Guard(const Handle_Guard& rhs) = delete; + Handle_Guard(Handle_Guard&& rhs) : + m_context(std::move(rhs.m_context)) + { + rhs.m_context = nullptr; + } + + ~Handle_Guard() + { + close(); + } + + operator bool() const + { + return m_context != nullptr; + } + + bool assign(T context) + { + m_context = context; + return m_context != nullptr; + } + + T& get() + { + return m_context; + } + + const T& get() const + { + return m_context; + } + + T operator->() + { + return m_context; + } + + private: + template + typename std::enable_if::value>::type close() + { + if(m_context) + { + CertFreeCertificateContext(m_context); + } + } + + template + typename std::enable_if::value>::type close() + { + if(m_context) + { + // second parameter is a flag that tells the store how to deallocate memory + // using the default "0", this function works like decreasing the reference counter + // in a shared_ptr + CertCloseStore(m_context, 0); + } + } + + T m_context; + }; + +HCERTSTORE open_cert_store(const char* cert_store_name) + { + auto store = CertOpenSystemStoreA(WINCRYPT_UNUSED_PARAM, cert_store_name); + if(!store) + { + throw Botan::Internal_Error( + "failed to open windows certificate store '" + std::string(cert_store_name) + + "' (Error Code: " + + std::to_string(::GetLastError()) + ")"); + } + return store; + } + +Cert_Vector search_cert_stores(const _CRYPTOAPI_BLOB& blob, const DWORD& find_type, + std::function filter, + bool return_on_first_found) + { + Cert_Vector certs; + for(const auto store_name : cert_store_names) + { + Handle_Guard windows_cert_store = open_cert_store(store_name); + Handle_Guard cert_context = nullptr; + while(cert_context.assign(CertFindCertificateInStore( + windows_cert_store.get(), PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + WINCRYPT_UNUSED_PARAM, find_type, + &blob, cert_context.get()))) + { + auto cert = std::make_shared(cert_context->pbCertEncoded, cert_context->cbCertEncoded); + if(filter(certs, cert)) + { + if(return_on_first_found) + { + return {cert}; + } + certs.push_back(cert); + } + } + } + + return certs; + } + +bool already_contains_certificate(const Cert_Vector& certs, Cert_Pointer cert) + { + return std::any_of(certs.begin(), certs.end(), [&](std::shared_ptr c) + { + return *c == *cert; + }); + } + +Cert_Vector find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn, + const std::vector& key_id, + bool return_on_first_found) + { + _CRYPTOAPI_BLOB blob; + DWORD find_type; + std::vector dn_data; + + // if key_id is available, prefer searching that, as it should be "more unique" than the subject DN + if(key_id.empty()) + { + find_type = CERT_FIND_SUBJECT_NAME; + DER_Encoder encoder(dn_data); + subject_dn.encode_into(encoder); + blob.cbData = static_cast(dn_data.size()); + blob.pbData = reinterpret_cast(dn_data.data()); + } + else + { + find_type = CERT_FIND_KEY_IDENTIFIER; + blob.cbData = static_cast(key_id.size()); + blob.pbData = const_cast(key_id.data()); + } + + auto filter = [&](const Cert_Vector& certs, Cert_Pointer cert) + { + return !already_contains_certificate(certs, cert) && (key_id.empty() || cert->subject_dn() == subject_dn); + }; + + return search_cert_stores(blob, find_type, filter, return_on_first_found); + } +} // namespace + +Certificate_Store_Windows::Certificate_Store_Windows() {} + +std::vector Certificate_Store_Windows::all_subjects() const + { + std::vector subject_dns; + for(const auto store_name : cert_store_names) + { + Handle_Guard windows_cert_store = open_cert_store(store_name); + Handle_Guard cert_context = nullptr; + + // Handle_Guard::assign exchanges the underlying pointer. No RAII is needed here, because the Windows API takes care of + // freeing the previous context. + while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get()))) + { + X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded); + subject_dns.push_back(cert.subject_dn()); + } + } + + return subject_dns; + } + +Cert_Pointer Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn, + const std::vector& key_id) const + { + const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id, true); + return certs.empty() ? nullptr : certs.front(); + } + +Cert_Vector Certificate_Store_Windows::find_all_certs( + const X509_DN& subject_dn, + const std::vector& key_id) const + { + return find_cert_by_dn_and_key_id(subject_dn, key_id, false); + } + +Cert_Pointer Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector& key_hash) const + { + if(key_hash.size() != 20) + { + throw Invalid_Argument("Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash"); + } + + CRYPT_HASH_BLOB blob; + blob.cbData = static_cast(key_hash.size()); + blob.pbData = const_cast(key_hash.data()); + + auto filter = [](const Cert_Vector&, Cert_Pointer) { return true; }; + + const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true); + return certs.empty() ? nullptr : certs.front(); + } + +Cert_Pointer Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256( + const std::vector& subject_hash) const + { + BOTAN_UNUSED(subject_hash); + throw Not_Implemented("Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256"); + } + +std::shared_ptr Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const + { + // TODO: this could be implemented by using the CertFindCRLInStore function + BOTAN_UNUSED(subject); + return {}; + } +} diff --git a/comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.h b/comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.h new file mode 100644 index 0000000000..f47e718c85 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system_windows/certstor_windows.h @@ -0,0 +1,70 @@ +/* +* Certificate Store +* (C) 1999-2019 Jack Lloyd +* (C) 2019 Patrick Schmidt +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_SYSTEM_WINDOWS_H_ +#define BOTAN_CERT_STORE_SYSTEM_WINDOWS_H_ + +#include + +namespace Botan { +/** +* Certificate Store that is backed by the system trust store on Windows. +*/ +class BOTAN_PUBLIC_API(2, 11) Certificate_Store_Windows final : public Certificate_Store + { + public: + Certificate_Store_Windows(); + + Certificate_Store_Windows(const Certificate_Store_Windows&) = default; + Certificate_Store_Windows(Certificate_Store_Windows&&) = default; + Certificate_Store_Windows& operator=(const Certificate_Store_Windows&) = default; + Certificate_Store_Windows& operator=(Certificate_Store_Windows&&) = default; + + /** + * @return DNs for all certificates managed by the store + */ + std::vector all_subjects() const override; + + /** + * Find a certificate by Subject DN and (optionally) key identifier + * @return the first certificate that matches + */ + std::shared_ptr find_cert( + const X509_DN& subject_dn, + const std::vector& key_id) const override; + + /** + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + std::vector> find_all_certs( + const X509_DN& subject_dn, const std::vector& key_id) const override; + + /** + * Find a certificate by searching for one with a matching SHA-1 hash of + * public key. + * @return a matching certificate or nullptr otherwise + */ + std::shared_ptr + find_cert_by_pubkey_sha1(const std::vector& key_hash) const override; + + /** + * @throws Botan::Not_Implemented + */ + std::shared_ptr + find_cert_by_raw_subject_dn_sha256(const std::vector& subject_hash) const override; + + /** + * Not Yet Implemented + * @return nullptr; + */ + std::shared_ptr find_crl_for(const X509_Certificate& subject) const override; + }; +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/certstor_system_windows/info.txt b/comm/third_party/botan/src/lib/x509/certstor_system_windows/info.txt new file mode 100644 index 0000000000..6d70de8bf2 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/certstor_system_windows/info.txt @@ -0,0 +1,16 @@ + +CERTSTOR_WINDOWS -> 20190430 + + + +win32,certificate_store + + + +certstor_windows.h + + + +windows -> crypt32 +mingw -> crypt32 + diff --git a/comm/third_party/botan/src/lib/x509/crl_ent.cpp b/comm/third_party/botan/src/lib/x509/crl_ent.cpp new file mode 100644 index 0000000000..d83d43d73c --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/crl_ent.cpp @@ -0,0 +1,140 @@ +/* +* CRL Entry +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +struct CRL_Entry_Data + { + std::vector m_serial; + X509_Time m_time; + CRL_Code m_reason = UNSPECIFIED; + Extensions m_extensions; + }; + +/* +* Create a CRL_Entry +*/ +CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) + { + m_data.reset(new CRL_Entry_Data); + m_data->m_serial = cert.serial_number(); + m_data->m_time = X509_Time(std::chrono::system_clock::now()); + m_data->m_reason = why; + + if(why != UNSPECIFIED) + { + m_data->m_extensions.add(new Cert_Extension::CRL_ReasonCode(why)); + } + } + +/* +* Compare two CRL_Entrys for equality +*/ +bool operator==(const CRL_Entry& a1, const CRL_Entry& a2) + { + if(a1.serial_number() != a2.serial_number()) + return false; + if(a1.expire_time() != a2.expire_time()) + return false; + if(a1.reason_code() != a2.reason_code()) + return false; + return true; + } + +/* +* Compare two CRL_Entrys for inequality +*/ +bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2) + { + return !(a1 == a2); + } + +/* +* DER encode a CRL_Entry +*/ +void CRL_Entry::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE) + .encode(BigInt::decode(serial_number())) + .encode(expire_time()) + .start_cons(SEQUENCE) + .encode(extensions()) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded CRL_Entry +*/ +void CRL_Entry::decode_from(BER_Decoder& source) + { + BigInt serial_number_bn; + + std::unique_ptr data(new CRL_Entry_Data); + + BER_Decoder entry = source.start_cons(SEQUENCE); + + entry.decode(serial_number_bn).decode(data->m_time); + data->m_serial = BigInt::encode(serial_number_bn); + + if(entry.more_items()) + { + entry.decode(data->m_extensions); + if(auto ext = data->m_extensions.get_extension_object_as()) + { + data->m_reason = ext->get_reason(); + } + else + { + data->m_reason = UNSPECIFIED; + } + } + + entry.end_cons(); + + m_data.reset(data.release()); + } + +const CRL_Entry_Data& CRL_Entry::data() const + { + if(!m_data) + { + throw Invalid_State("CRL_Entry_Data uninitialized"); + } + + return *m_data.get(); + } + +const std::vector& CRL_Entry::serial_number() const + { + return data().m_serial; + } + +const X509_Time& CRL_Entry::expire_time() const + { + return data().m_time; + } + +CRL_Code CRL_Entry::reason_code() const + { + return data().m_reason; + } + +const Extensions& CRL_Entry::extensions() const + { + return data().m_extensions; + } + + +} diff --git a/comm/third_party/botan/src/lib/x509/crl_ent.h b/comm/third_party/botan/src/lib/x509/crl_ent.h new file mode 100644 index 0000000000..aa60d4172b --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/crl_ent.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CRL_ENTRY_H_ +#define BOTAN_CRL_ENTRY_H_ + +#include +BOTAN_DEPRECATED_HEADER(crl_ent.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/datastor.cpp b/comm/third_party/botan/src/lib/x509/datastor.cpp new file mode 100644 index 0000000000..2cdd3458ca --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/datastor.cpp @@ -0,0 +1,205 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Data_Store Equality Comparison +*/ +bool Data_Store::operator==(const Data_Store& other) const + { + return (m_contents == other.m_contents); + } + +/* +* Check if this key has at least one value +*/ +bool Data_Store::has_value(const std::string& key) const + { + return (m_contents.lower_bound(key) != m_contents.end()); + } + +/* +* Search based on an arbitrary predicate +*/ +std::multimap Data_Store::search_for( + std::function predicate) const + { + std::multimap out; + + for(auto i = m_contents.begin(); i != m_contents.end(); ++i) + if(predicate(i->first, i->second)) + out.insert(std::make_pair(i->first, i->second)); + + return out; + } + +/* +* Search based on key equality +*/ +std::vector Data_Store::get(const std::string& looking_for) const + { + std::vector out; + auto range = m_contents.equal_range(looking_for); + for(auto i = range.first; i != range.second; ++i) + out.push_back(i->second); + return out; + } + +/* +* Get a single atom +*/ +std::string Data_Store::get1(const std::string& key) const + { + std::vector vals = get(key); + + if(vals.empty()) + throw Invalid_State("Data_Store::get1: No values set for " + key); + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + return vals[0]; + } + +std::string Data_Store::get1(const std::string& key, + const std::string& default_value) const + { + std::vector vals = get(key); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + if(vals.empty()) + return default_value; + + return vals[0]; + } + +/* +* Get a single std::vector atom +*/ +std::vector +Data_Store::get1_memvec(const std::string& key) const + { + std::vector vals = get(key); + + if(vals.empty()) + return std::vector(); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_memvec: Multiple values for " + + key); + + return hex_decode(vals[0]); + } + +/* +* Get a single uint32_t atom +*/ +uint32_t Data_Store::get1_uint32(const std::string& key, + uint32_t default_val) const + { + std::vector vals = get(key); + + if(vals.empty()) + return default_val; + else if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_uint32: Multiple values for " + key); + + return to_u32bit(vals[0]); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const std::string& val) + { + multimap_insert(m_contents, key, val); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, uint32_t val) + { + add(key, std::to_string(val)); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const secure_vector& val) + { + add(key, hex_encode(val.data(), val.size())); + } + +void Data_Store::add(const std::string& key, const std::vector& val) + { + add(key, hex_encode(val.data(), val.size())); + } + +/* +* Insert a mapping of key/value pairs +*/ +void Data_Store::add(const std::multimap& in) + { + std::multimap::const_iterator i = in.begin(); + while(i != in.end()) + { + m_contents.insert(*i); + ++i; + } + } + +/* +* Create and populate a X509_DN +*/ +X509_DN create_dn(const Data_Store& info) + { + auto names = info.search_for( + [](const std::string& key, const std::string&) + { + return (key.find("X520.") != std::string::npos); + }); + + X509_DN dn; + + for(auto i = names.begin(); i != names.end(); ++i) + dn.add_attribute(i->first, i->second); + + return dn; + } + +/* +* Create and populate an AlternativeName +*/ +AlternativeName create_alt_name(const Data_Store& info) + { + auto names = info.search_for( + [](const std::string& key, const std::string&) + { + return (key == "RFC822" || + key == "DNS" || + key == "URI" || + key == "IP"); + }); + + AlternativeName alt_name; + + for(auto i = names.begin(); i != names.end(); ++i) + alt_name.add_attribute(i->first, i->second); + + return alt_name; + } + +} diff --git a/comm/third_party/botan/src/lib/x509/datastor.h b/comm/third_party/botan/src/lib/x509/datastor.h new file mode 100644 index 0000000000..1ff85c22cf --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/datastor.h @@ -0,0 +1,85 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DATA_STORE_H_ +#define BOTAN_DATA_STORE_H_ + +#include +#include +#include +#include +#include + +BOTAN_FUTURE_INTERNAL_HEADER(datastor.h) + +namespace Botan { + +/** +* Data Store +* +* This class is used internally by the library, and exposed for ABI +* reasons. There is no reason for applications to use this type directly. +* It will be removed in a future major release. +*/ +class BOTAN_UNSTABLE_API Data_Store final + { + public: + /** + * A search function + */ + bool operator==(const Data_Store&) const; + + std::multimap search_for( + std::function predicate) const; + + std::vector get(const std::string&) const; + + std::string get1(const std::string& key) const; + + std::string get1(const std::string& key, + const std::string& default_value) const; + + std::vector get1_memvec(const std::string&) const; + uint32_t get1_uint32(const std::string&, uint32_t = 0) const; + + bool has_value(const std::string&) const; + + void add(const std::multimap&); + void add(const std::string&, const std::string&); + void add(const std::string&, uint32_t); + void add(const std::string&, const secure_vector&); + void add(const std::string&, const std::vector&); + private: + std::multimap m_contents; + }; + +/* +* Data Store Extraction Operations +*/ + +/* +* Create and populate a X509_DN +* @param info data store containing DN information +* @return DN containing attributes from data store +*/ +BOTAN_PUBLIC_API(2,0) X509_DN +BOTAN_DEPRECATED("Avoid roundtripping names through Data_Store") +create_dn(const Data_Store& info); + +/* +* Create and populate an AlternativeName +* @param info data store containing AlternativeName information +* @return AlternativeName containing attributes from data store +*/ +BOTAN_PUBLIC_API(2,0) AlternativeName +BOTAN_DEPRECATED("Avoid roundtripping names through Data_Store") +create_alt_name(const Data_Store& info); + + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/info.txt b/comm/third_party/botan/src/lib/x509/info.txt new file mode 100644 index 0000000000..20a1aa2b08 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/info.txt @@ -0,0 +1,12 @@ + +X509_CERTIFICATES -> 20151023 +X509 -> 20180911 +OCSP -> 20161118 + + + +asn1 +pubkey +sha1 +sha2_32 + diff --git a/comm/third_party/botan/src/lib/x509/key_constraint.cpp b/comm/third_party/botan/src/lib/x509/key_constraint.cpp new file mode 100644 index 0000000000..09a4c059a3 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/key_constraint.cpp @@ -0,0 +1,106 @@ +/* +* KeyUsage +* (C) 1999-2007,2016 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +std::string key_constraints_to_string(Key_Constraints constraints) + { + std::vector str; + + if(constraints == NO_CONSTRAINTS) + return "no_constraints"; + + if(constraints & DIGITAL_SIGNATURE) + str.push_back("digital_signature"); + + if(constraints & NON_REPUDIATION) + str.push_back("non_repudiation"); + + if(constraints & KEY_ENCIPHERMENT) + str.push_back("key_encipherment"); + + if(constraints & DATA_ENCIPHERMENT) + str.push_back("data_encipherment"); + + if(constraints & KEY_AGREEMENT) + str.push_back("key_agreement"); + + if(constraints & KEY_CERT_SIGN) + str.push_back("key_cert_sign"); + + if(constraints & CRL_SIGN) + str.push_back("crl_sign"); + + if(constraints & ENCIPHER_ONLY) + str.push_back("encipher_only"); + + if(constraints & DECIPHER_ONLY) + str.push_back("decipher_only"); + + // Not 0 (checked at start) but nothing matched above! + if(str.empty()) + return "other_unknown_constraints"; + + if(str.size() == 1) + return str[0]; + + std::string out; + for(size_t i = 0; i < str.size() - 1; ++i) + { + out += str[i]; + out += ','; + } + out += str[str.size() - 1]; + + return out; + } + +/* +* Make sure the given key constraints are permitted for the given key type +*/ +void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, + Key_Constraints constraints) + { + const std::string name = pub_key.algo_name(); + + size_t permitted = 0; + + const bool can_agree = (name == "DH" || name == "ECDH"); + const bool can_encrypt = (name == "RSA" || name == "ElGamal"); + + const bool can_sign = + (name == "RSA" || name == "DSA" || + name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA" || name == "Ed25519" || + name == "GOST-34.10" || name == "GOST-34.10-2012-256" || name == "GOST-34.10-2012-512"); + + if(can_agree) + { + permitted |= KEY_AGREEMENT | ENCIPHER_ONLY | DECIPHER_ONLY; + } + + if(can_encrypt) + { + permitted |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; + } + + if(can_sign) + { + permitted |= DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_CERT_SIGN | CRL_SIGN; + } + + if(Key_Constraints(constraints & permitted) != constraints) + { + throw Invalid_Argument("Invalid " + name + " constraints " + key_constraints_to_string(constraints)); + } + } + +} diff --git a/comm/third_party/botan/src/lib/x509/key_constraint.h b/comm/third_party/botan/src/lib/x509/key_constraint.h new file mode 100644 index 0000000000..5d5c7b0832 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/key_constraint.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEY_CONSTRAINT_H_ +#define BOTAN_KEY_CONSTRAINT_H_ + +#include +BOTAN_DEPRECATED_HEADER(key_constraint.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/name_constraint.cpp b/comm/third_party/botan/src/lib/x509/name_constraint.cpp new file mode 100644 index 0000000000..c9045729de --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/name_constraint.cpp @@ -0,0 +1,273 @@ +/* +* X.509 Name Constraint +* (C) 2015 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class DER_Encoder; + +GeneralName::GeneralName(const std::string& str) : GeneralName() + { + size_t p = str.find(':'); + + if(p != std::string::npos) + { + m_type = str.substr(0, p); + m_name = str.substr(p + 1, std::string::npos); + } + else + { + throw Invalid_Argument("Failed to decode Name Constraint"); + } + } + +void GeneralName::encode_into(DER_Encoder&) const + { + throw Not_Implemented("GeneralName encoding"); + } + +void GeneralName::decode_from(class BER_Decoder& ber) + { + BER_Object obj = ber.get_next_object(); + + if(obj.is_a(1, CONTEXT_SPECIFIC)) + { + m_type = "RFC822"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(2, CONTEXT_SPECIFIC)) + { + m_type = "DNS"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(6, CONTEXT_SPECIFIC)) + { + m_type = "URI"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) + { + m_type = "DN"; + X509_DN dn; + BER_Decoder dec(obj); + std::stringstream ss; + + dn.decode_from(dec); + ss << dn; + + m_name = ss.str(); + } + else if(obj.is_a(7, CONTEXT_SPECIFIC)) + { + if(obj.length() == 8) + { + m_type = "IP"; + m_name = ipv4_to_string(load_be(obj.bits(), 0)) + "/" + + ipv4_to_string(load_be(obj.bits(), 1)); + } + else if(obj.length() == 32) + { + throw Decoding_Error("Unsupported IPv6 name constraint"); + } + else + { + throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length())); + } + } + else + { + throw Decoding_Error("Found unknown GeneralName type"); + } + } + +GeneralName::MatchResult GeneralName::matches(const X509_Certificate& cert) const + { + std::vector nam; + std::function match_fn; + + const X509_DN& dn = cert.subject_dn(); + const AlternativeName& alt_name = cert.subject_alt_name(); + + if(type() == "DNS") + { + match_fn = std::mem_fn(&GeneralName::matches_dns); + + nam = alt_name.get_attribute("DNS"); + + if(nam.empty()) + { + nam = dn.get_attribute("CN"); + } + } + else if(type() == "DN") + { + match_fn = std::mem_fn(&GeneralName::matches_dn); + + nam.push_back(dn.to_string()); + + const auto alt_dn = alt_name.dn(); + if(alt_dn.empty() == false) + { + nam.push_back(alt_dn.to_string()); + } + } + else if(type() == "IP") + { + match_fn = std::mem_fn(&GeneralName::matches_ip); + nam = alt_name.get_attribute("IP"); + } + else + { + return MatchResult::UnknownType; + } + + if(nam.empty()) + { + return MatchResult::NotFound; + } + + bool some = false; + bool all = true; + + for(const std::string& n: nam) + { + bool m = match_fn(this, n); + + some |= m; + all &= m; + } + + if(all) + { + return MatchResult::All; + } + else if(some) + { + return MatchResult::Some; + } + else + { + return MatchResult::None; + } + } + +bool GeneralName::matches_dns(const std::string& nam) const + { + if(nam.size() == name().size()) + { + return tolower_string(nam) == tolower_string(name()); + } + else if(name().size() > nam.size()) + { + // The constraint is longer than the issued name: not possibly a match + return false; + } + else // name.size() < nam.size() + { + // constr is suffix of nam + const std::string constr = name().front() == '.' ? name() : "." + name(); + const std::string substr = nam.substr(nam.size() - constr.size(), constr.size()); + return tolower_string(constr) == tolower_string(substr); + } + } + +bool GeneralName::matches_dn(const std::string& nam) const + { + std::stringstream ss(nam); + std::stringstream tt(name()); + X509_DN nam_dn, my_dn; + + ss >> nam_dn; + tt >> my_dn; + + auto attr = nam_dn.get_attributes(); + bool ret = true; + size_t trys = 0; + + for(const auto& c: my_dn.dn_info()) + { + auto i = attr.equal_range(c.first); + + if(i.first != i.second) + { + trys += 1; + ret = ret && (i.first->second == c.second.value()); + } + } + + return trys > 0 && ret; + } + +bool GeneralName::matches_ip(const std::string& nam) const + { + uint32_t ip = string_to_ipv4(nam); + std::vector p = split_on(name(), '/'); + + if(p.size() != 2) + throw Decoding_Error("failed to parse IPv4 address"); + + uint32_t net = string_to_ipv4(p.at(0)); + uint32_t mask = string_to_ipv4(p.at(1)); + + return (ip & mask) == net; + } + +std::ostream& operator<<(std::ostream& os, const GeneralName& gn) + { + os << gn.type() << ":" << gn.name(); + return os; + } + +GeneralSubtree::GeneralSubtree(const std::string& str) : GeneralSubtree() + { + size_t p0, p1; + const auto min = std::stoull(str, &p0, 10); + const auto max = std::stoull(str.substr(p0 + 1), &p1, 10); + GeneralName gn(str.substr(p0 + p1 + 2)); + + if(p0 > 0 && p1 > 0) + { + m_minimum = static_cast(min); + m_maximum = static_cast(max); + m_base = gn; + } + else + { + throw Invalid_Argument("Failed to decode Name Constraint"); + } + } + +void GeneralSubtree::encode_into(DER_Encoder&) const + { + throw Not_Implemented("General Subtree encoding"); + } + +void GeneralSubtree::decode_from(class BER_Decoder& ber) + { + ber.start_cons(SEQUENCE) + .decode(m_base) + .decode_optional(m_minimum,ASN1_Tag(0), CONTEXT_SPECIFIC,size_t(0)) + .end_cons(); + + if(m_minimum != 0) + throw Decoding_Error("GeneralSubtree minimum must be 0"); + + m_maximum = std::numeric_limits::max(); + } + +std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs) + { + os << gs.minimum() << "," << gs.maximum() << "," << gs.base(); + return os; + } +} diff --git a/comm/third_party/botan/src/lib/x509/name_constraint.h b/comm/third_party/botan/src/lib/x509/name_constraint.h new file mode 100644 index 0000000000..4f56f89eda --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/name_constraint.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NAME_CONSTRAINT_H_ +#define BOTAN_NAME_CONSTRAINT_H_ + +#include +BOTAN_DEPRECATED_HEADER(name_constraint.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/ocsp.cpp b/comm/third_party/botan/src/lib/x509/ocsp.cpp new file mode 100644 index 0000000000..1ca8232634 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/ocsp.cpp @@ -0,0 +1,363 @@ +/* +* OCSP +* (C) 2012,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_HTTP_UTIL) + #include +#endif + +namespace Botan { + +namespace OCSP { + +namespace { + +// TODO: should this be in a header somewhere? +void decode_optional_list(BER_Decoder& ber, + ASN1_Tag tag, + std::vector& output) + { + BER_Object obj = ber.get_next_object(); + + if(obj.is_a(tag, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) + { + ber.push_back(obj); + return; + } + + BER_Decoder list(obj); + + while(list.more_items()) + { + BER_Object certbits = list.get_next_object(); + X509_Certificate cert(certbits.bits(), certbits.length()); + output.push_back(std::move(cert)); + } + } + +} + +Request::Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert) : + m_issuer(issuer_cert), + m_certid(m_issuer, BigInt::decode(subject_cert.serial_number())) + { + if(subject_cert.issuer_dn() != issuer_cert.subject_dn()) + throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)"); + } + +Request::Request(const X509_Certificate& issuer_cert, + const BigInt& subject_serial) : + m_issuer(issuer_cert), + m_certid(m_issuer, subject_serial) + { + } + +std::vector Request::BER_encode() const + { + std::vector output; + DER_Encoder(output).start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .start_explicit(0) + .encode(static_cast(0)) // version # + .end_explicit() + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(m_certid) + .end_cons() + .end_cons() + .end_cons() + .end_cons(); + + return output; + } + +std::string Request::base64_encode() const + { + return Botan::base64_encode(BER_encode()); + } + +Response::Response(Certificate_Status_Code status) + { + m_status = Response_Status_Code::Successful; + m_dummy_response_status = status; + } + +Response::Response(const uint8_t response_bits[], size_t response_bits_len) : + m_response_bits(response_bits, response_bits + response_bits_len) + { + m_dummy_response_status = Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE); + + size_t resp_status = 0; + + response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); + + m_status = static_cast(resp_status); + + if(m_status != Response_Status_Code::Successful) + { return; } + + if(response_outer.more_items()) + { + BER_Decoder response_bytes = + response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); + + response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), + "Unknown response type in OCSP response"); + + BER_Decoder basicresponse = + BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); + + basicresponse.start_cons(SEQUENCE) + .raw_bytes(m_tbs_bits) + .end_cons() + .decode(m_sig_algo) + .decode(m_signature, BIT_STRING); + decode_optional_list(basicresponse, ASN1_Tag(0), m_certs); + + size_t responsedata_version = 0; + Extensions extensions; + + BER_Decoder(m_tbs_bits) + .decode_optional(responsedata_version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional(m_signer_name, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional_string(m_key_hash, OCTET_STRING, 2, + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode(m_produced_at) + + .decode_list(m_responses) + + .decode_optional(extensions, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + } + + response_outer.end_cons(); + } + +Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const + { + if (m_responses.empty()) + return m_dummy_response_status; + + try + { + std::unique_ptr pub_key(issuer.subject_public_key()); + + const std::vector sig_info = + split_on(m_sig_algo.get_oid().to_formatted_string(), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + return Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + std::string padding = sig_info[1]; + const Signature_Format format = pub_key->default_x509_signature_format(); + + PK_Verifier verifier(*pub_key, padding, format); + + if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature)) + return Certificate_Status_Code::OCSP_SIGNATURE_OK; + else + return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; + } + catch(Exception&) + { + return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; + } + } + +Certificate_Status_Code Response::check_signature(const std::vector& trusted_roots, + const std::vector>& ee_cert_path) const + { + if (m_responses.empty()) + return m_dummy_response_status; + + std::shared_ptr signing_cert; + + for(size_t i = 0; i != trusted_roots.size(); ++i) + { + if(m_signer_name.empty() && m_key_hash.empty()) + return Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + if(!m_signer_name.empty()) + { + signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector()); + if(signing_cert) + { + break; + } + } + + if(m_key_hash.size() > 0) + { + signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash); + if(signing_cert) + { + break; + } + } + } + + if(!signing_cert && ee_cert_path.size() > 1) + { + // End entity cert is not allowed to sign their own OCSP request :) + for(size_t i = 1; i < ee_cert_path.size(); ++i) + { + // Check all CA certificates in the (assumed validated) EE cert path + if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name) + { + signing_cert = ee_cert_path[i]; + break; + } + + if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash) + { + signing_cert = ee_cert_path[i]; + break; + } + } + } + + if(!signing_cert && m_certs.size() > 0) + { + for(size_t i = 0; i < m_certs.size(); ++i) + { + // Check all CA certificates in the (assumed validated) EE cert path + if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name) + { + signing_cert = std::make_shared(m_certs[i]); + break; + } + + if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash) + { + signing_cert = std::make_shared(m_certs[i]); + break; + } + } + } + + if(!signing_cert) + return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND; + + if(!signing_cert->allowed_usage(CRL_SIGN) && + !signing_cert->allowed_extended_usage("PKIX.OCSPSigning")) + { + return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE; + } + + return this->verify_signature(*signing_cert); + } + +Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, + const X509_Certificate& subject, + std::chrono::system_clock::time_point ref_time, + std::chrono::seconds max_age) const + { + if(m_responses.empty()) + { return m_dummy_response_status; } + + for(const auto& response : m_responses) + { + if(response.certid().is_id_for(issuer, subject)) + { + X509_Time x509_ref_time(ref_time); + + if(response.cert_status() == 1) + { return Certificate_Status_Code::CERT_IS_REVOKED; } + + if(response.this_update() > x509_ref_time) + { return Certificate_Status_Code::OCSP_NOT_YET_VALID; } + + if(response.next_update().time_is_set()) + { + if(x509_ref_time > response.next_update()) + { return Certificate_Status_Code::OCSP_HAS_EXPIRED; } + } + else if(max_age > std::chrono::seconds::zero() && ref_time - response.this_update().to_std_timepoint() > max_age) + { return Certificate_Status_Code::OCSP_IS_TOO_OLD; } + + if(response.cert_status() == 0) + { return Certificate_Status_Code::OCSP_RESPONSE_GOOD; } + else + { return Certificate_Status_Code::OCSP_BAD_STATUS; } + } + } + + return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; + } + +#if defined(BOTAN_HAS_HTTP_UTIL) + +Response online_check(const X509_Certificate& issuer, + const BigInt& subject_serial, + const std::string& ocsp_responder, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout) + { + if(ocsp_responder.empty()) + throw Invalid_Argument("No OCSP responder specified"); + + OCSP::Request req(issuer, subject_serial); + + auto http = HTTP::POST_sync(ocsp_responder, + "application/ocsp-request", + req.BER_encode(), + 1, + timeout); + + http.throw_unless_ok(); + + // Check the MIME type? + + OCSP::Response response(http.body()); + + std::vector trusted_roots_vec; + trusted_roots_vec.push_back(trusted_roots); + + if(trusted_roots) + response.check_signature(trusted_roots_vec); + + return response; + } + + +Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout) + { + if(subject.issuer_dn() != issuer.subject_dn()) + throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)"); + + return online_check(issuer, + BigInt::decode(subject.serial_number()), + subject.ocsp_responder(), + trusted_roots, + timeout); + } + +#endif + +} + +} diff --git a/comm/third_party/botan/src/lib/x509/ocsp.h b/comm/third_party/botan/src/lib/x509/ocsp.h new file mode 100644 index 0000000000..5522456442 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/ocsp.h @@ -0,0 +1,282 @@ +/* +* OCSP +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OCSP_H_ +#define BOTAN_OCSP_H_ + +#include +#include +#include +#include +#include + +namespace Botan { + +class Certificate_Store; + +namespace OCSP { + +class BOTAN_PUBLIC_API(2,0) CertID final : public ASN1_Object + { + public: + CertID() = default; + + CertID(const X509_Certificate& issuer, + const BigInt& subject_serial); + + bool is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + + const std::vector& issuer_key_hash() const { return m_issuer_key_hash; } + + private: + AlgorithmIdentifier m_hash_id; + std::vector m_issuer_dn_hash; + std::vector m_issuer_key_hash; + BigInt m_subject_serial; + }; + +class BOTAN_PUBLIC_API(2,0) SingleResponse final : public ASN1_Object + { + public: + const CertID& certid() const { return m_certid; } + + size_t cert_status() const { return m_cert_status; } + + X509_Time this_update() const { return m_thisupdate; } + + X509_Time next_update() const { return m_nextupdate; } + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + private: + CertID m_certid; + size_t m_cert_status = 2; // unknown + X509_Time m_thisupdate; + X509_Time m_nextupdate; + }; + +/** +* An OCSP request. +*/ +class BOTAN_PUBLIC_API(2,0) Request final + { + public: + /** + * Create an OCSP request. + * @param issuer_cert issuer certificate + * @param subject_cert subject certificate + */ + Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert); + + Request(const X509_Certificate& issuer_cert, + const BigInt& subject_serial); + + /** + * @return BER-encoded OCSP request + */ + std::vector BER_encode() const; + + /** + * @return Base64-encoded OCSP request + */ + std::string base64_encode() const; + + /** + * @return issuer certificate + */ + const X509_Certificate& issuer() const { return m_issuer; } + + /** + * @return subject certificate + */ + const X509_Certificate& subject() const { throw Not_Implemented("Method have been deprecated"); } + + const std::vector& issuer_key_hash() const + { return m_certid.issuer_key_hash(); } + private: + X509_Certificate m_issuer; + CertID m_certid; + }; + +/** +* OCSP response status. +* +* see https://tools.ietf.org/html/rfc6960#section-4.2.1 +*/ +enum class Response_Status_Code { + Successful = 0, + Malformed_Request = 1, + Internal_Error = 2, + Try_Later = 3, + Sig_Required = 5, + Unauthorized = 6 +}; + +/** +* OCSP response. +* +* Note this class is only usable as an OCSP client +*/ +class BOTAN_PUBLIC_API(2,0) Response final + { + public: + /** + * Creates an empty OCSP response. + */ + Response() = default; + + /** + * Create a fake OCSP response from a given status code. + * @param status the status code the check functions will return + */ + Response(Certificate_Status_Code status); + + /** + * Parses an OCSP response. + * @param response_bits response bits received + */ + Response(const std::vector& response_bits) : + Response(response_bits.data(), response_bits.size()) + {} + + /** + * Parses an OCSP response. + * @param response_bits response bits received + * @param response_bits_len length of response in bytes + */ + Response(const uint8_t response_bits[], + size_t response_bits_len); + + /** + * Check signature and return status + * The optional cert_path is the (already validated!) certificate path of + * the end entity which is being inquired about + * @param trust_roots list of certstores containing trusted roots + * @param cert_path optionally, the (already verified!) certificate path for the certificate + * this is an OCSP response for. This is necessary to find the correct intermediate CA in + * some cases. + */ + Certificate_Status_Code check_signature(const std::vector& trust_roots, + const std::vector>& cert_path = {}) const; + + /** + * Verify that issuer's key signed this response + * @param issuer certificate of issuer + * @return if signature valid OCSP_SIGNATURE_OK else an error code + */ + Certificate_Status_Code verify_signature(const X509_Certificate& issuer) const; + + /** + * @return the status of the response + */ + Response_Status_Code status() const { return m_status; } + + /** + * @return the time this OCSP response was supposedly produced at + */ + const X509_Time& produced_at() const { return m_produced_at; } + + /** + * @return DN of signer, if provided in response (may be empty) + */ + const X509_DN& signer_name() const { return m_signer_name; } + + /** + * @return key hash, if provided in response (may be empty) + */ + const std::vector& signer_key_hash() const { return m_key_hash; } + + const std::vector& raw_bits() const { return m_response_bits; } + + /** + * Searches the OCSP response for issuer and subject certificate. + * @param issuer issuer certificate + * @param subject subject certificate + * @param ref_time the reference time + * @param max_age the maximum age the response should be considered valid + * if next_update is not set + * @return OCSP status code, possible values: + * CERT_IS_REVOKED, + * OCSP_NOT_YET_VALID, + * OCSP_HAS_EXPIRED, + * OCSP_IS_TOO_OLD, + * OCSP_RESPONSE_GOOD, + * OCSP_BAD_STATUS, + * OCSP_CERT_NOT_LISTED + */ + Certificate_Status_Code status_for(const X509_Certificate& issuer, + const X509_Certificate& subject, + std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now(), + std::chrono::seconds max_age = std::chrono::seconds::zero()) const; + + /** + * @return the certificate chain, if provided in response + */ + const std::vector &certificates() const { return m_certs; } + + private: + Response_Status_Code m_status; + std::vector m_response_bits; + X509_Time m_produced_at; + X509_DN m_signer_name; + std::vector m_key_hash; + std::vector m_tbs_bits; + AlgorithmIdentifier m_sig_algo; + std::vector m_signature; + std::vector m_certs; + + std::vector m_responses; + + Certificate_Status_Code m_dummy_response_status; + }; + +#if defined(BOTAN_HAS_HTTP_UTIL) + +/** +* Makes an online OCSP request via HTTP and returns the OCSP response. +* @param issuer issuer certificate +* @param subject_serial the subject's serial number +* @param ocsp_responder the OCSP responder to query +* @param trusted_roots trusted roots for the OCSP response +* @param timeout a timeout on the HTTP request +* @return OCSP response +*/ +BOTAN_PUBLIC_API(2,1) +Response online_check(const X509_Certificate& issuer, + const BigInt& subject_serial, + const std::string& ocsp_responder, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +/** +* Makes an online OCSP request via HTTP and returns the OCSP response. +* @param issuer issuer certificate +* @param subject subject certificate +* @param trusted_roots trusted roots for the OCSP response +* @param timeout a timeout on the HTTP request +* @return OCSP response +*/ +BOTAN_PUBLIC_API(2,0) +Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +#endif + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/ocsp_types.cpp b/comm/third_party/botan/src/lib/x509/ocsp_types.cpp new file mode 100644 index 0000000000..c4b78112eb --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/ocsp_types.cpp @@ -0,0 +1,105 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +CertID::CertID(const X509_Certificate& issuer, + const BigInt& subject_serial) + { + /* + In practice it seems some responders, including, notably, + ocsp.verisign.com, will reject anything but SHA-1 here + */ + std::unique_ptr hash(HashFunction::create_or_throw("SHA-160")); + + m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); + m_issuer_key_hash = unlock(hash->process(issuer.subject_public_key_bitstring())); + m_issuer_dn_hash = unlock(hash->process(issuer.raw_subject_dn())); + m_subject_serial = subject_serial; + } + +bool CertID::is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const + { + try + { + if(BigInt::decode(subject.serial_number()) != m_subject_serial) + return false; + + const std::string hash_algo = m_hash_id.get_oid().to_formatted_string(); + std::unique_ptr hash = HashFunction::create_or_throw(hash_algo); + + if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) + return false; + + if(m_issuer_key_hash != unlock(hash->process(issuer.subject_public_key_bitstring()))) + return false; + } + catch(...) + { + return false; + } + + return true; + } + +void CertID::encode_into(class DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .encode(m_hash_id) + .encode(m_issuer_dn_hash, OCTET_STRING) + .encode(m_issuer_key_hash, OCTET_STRING) + .encode(m_subject_serial) + .end_cons(); + } + +void CertID::decode_from(class BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .decode(m_hash_id) + .decode(m_issuer_dn_hash, OCTET_STRING) + .decode(m_issuer_key_hash, OCTET_STRING) + .decode(m_subject_serial) + .end_cons(); + + } + +void SingleResponse::encode_into(class DER_Encoder&) const + { + throw Not_Implemented("SingleResponse::encode_into"); + } + +void SingleResponse::decode_from(class BER_Decoder& from) + { + BER_Object cert_status; + Extensions extensions; + + from.start_cons(SEQUENCE) + .decode(m_certid) + .get_next(cert_status) + .decode(m_thisupdate) + .decode_optional(m_nextupdate, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .decode_optional(extensions, + ASN1_Tag(1), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .end_cons(); + + m_cert_status = cert_status.type(); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/x509/ocsp_types.h b/comm/third_party/botan/src/lib/x509/ocsp_types.h new file mode 100644 index 0000000000..aa628d8d60 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/ocsp_types.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OCSP_TYPES_H_ +#define BOTAN_OCSP_TYPES_H_ + +#include +BOTAN_DEPRECATED_HEADER(ocsp_types.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/pkcs10.cpp b/comm/third_party/botan/src/lib/x509/pkcs10.cpp new file mode 100644 index 0000000000..1da5ecca48 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/pkcs10.cpp @@ -0,0 +1,304 @@ +/* +* PKCS #10 +* (C) 1999-2007,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +struct PKCS10_Data + { + X509_DN m_subject_dn; + std::vector m_public_key_bits; + AlternativeName m_alt_name; + std::string m_challenge; + Extensions m_extensions; + }; + +std::string PKCS10_Request::PEM_label() const + { + return "CERTIFICATE REQUEST"; + } + +std::vector PKCS10_Request::alternate_PEM_labels() const + { + return { "NEW CERTIFICATE REQUEST" }; + } + +PKCS10_Request::PKCS10_Request(DataSource& src) + { + load_data(src); + } + +PKCS10_Request::PKCS10_Request(const std::vector& vec) + { + DataSource_Memory src(vec.data(), vec.size()); + load_data(src); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +PKCS10_Request::PKCS10_Request(const std::string& fsname) + { + DataSource_Stream src(fsname, true); + load_data(src); + } +#endif + +//static +PKCS10_Request PKCS10_Request::create(const Private_Key& key, + const X509_DN& subject_dn, + const Extensions& extensions, + const std::string& hash_fn, + RandomNumberGenerator& rng, + const std::string& padding_scheme, + const std::string& challenge) + { + AlgorithmIdentifier sig_algo; + std::unique_ptr signer = choose_sig_format(sig_algo, key, rng, hash_fn, padding_scheme); + + const size_t PKCS10_VERSION = 0; + + DER_Encoder tbs_req; + + tbs_req.start_cons(SEQUENCE) + .encode(PKCS10_VERSION) + .encode(subject_dn) + .raw_bytes(key.subject_public_key()) + .start_explicit(0); + + if(challenge.empty() == false) + { + std::vector value; + DER_Encoder(value).encode(ASN1_String(challenge, DIRECTORY_STRING)); + tbs_req.encode(Attribute("PKCS9.ChallengePassword", value)); + } + + std::vector extension_req; + DER_Encoder(extension_req).start_cons(SEQUENCE).encode(extensions).end_cons(); + tbs_req.encode(Attribute("PKCS9.ExtensionRequest", extension_req)); + + // end the start_explicit above + tbs_req.end_explicit().end_cons(); + + const std::vector req = + X509_Object::make_signed(signer.get(), rng, sig_algo, + tbs_req.get_contents()); + + return PKCS10_Request(req); + } + +/* +* Decode the CertificateRequestInfo +*/ +namespace { + +std::unique_ptr decode_pkcs10(const std::vector& body) + { + std::unique_ptr data(new PKCS10_Data); + + BER_Decoder cert_req_info(body); + + size_t version; + cert_req_info.decode(version); + if(version != 0) + throw Decoding_Error("Unknown version code in PKCS #10 request: " + + std::to_string(version)); + + cert_req_info.decode(data->m_subject_dn); + + BER_Object public_key = cert_req_info.get_next_object(); + if(public_key.is_a(SEQUENCE, CONSTRUCTED) == false) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging()); + + data->m_public_key_bits = ASN1::put_in_sequence(public_key.bits(), public_key.length()); + + BER_Object attr_bits = cert_req_info.get_next_object(); + + std::set pkcs9_email; + + if(attr_bits.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + BER_Decoder attributes(attr_bits); + while(attributes.more_items()) + { + Attribute attr; + attributes.decode(attr); + + const OID& oid = attr.get_oid(); + BER_Decoder value(attr.get_parameters()); + + if(oid == OID::from_string("PKCS9.EmailAddress")) + { + ASN1_String email; + value.decode(email); + pkcs9_email.insert(email.value()); + } + else if(oid == OID::from_string("PKCS9.ChallengePassword")) + { + ASN1_String challenge_password; + value.decode(challenge_password); + data->m_challenge = challenge_password.value(); + } + else if(oid == OID::from_string("PKCS9.ExtensionRequest")) + { + value.decode(data->m_extensions).verify_end(); + } + } + attributes.verify_end(); + } + else if(attr_bits.is_set()) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging()); + + cert_req_info.verify_end(); + + if(auto ext = data->m_extensions.get_extension_object_as()) + { + data->m_alt_name = ext->get_alt_name(); + } + + for(std::string email : pkcs9_email) + { + data->m_alt_name.add_attribute("RFC882", email); + } + + return data; + } + +} + +void PKCS10_Request::force_decode() + { + m_data.reset(); + + std::unique_ptr data = decode_pkcs10(signed_body()); + + m_data.reset(data.release()); + + if(!this->check_signature(subject_public_key())) + throw Decoding_Error("PKCS #10 request: Bad signature detected"); + } + +const PKCS10_Data& PKCS10_Request::data() const + { + if(m_data == nullptr) + throw Decoding_Error("PKCS10_Request decoding failed"); + return *m_data.get(); + } + +/* +* Return the challenge password (if any) +*/ +std::string PKCS10_Request::challenge_password() const + { + return data().m_challenge; + } + +/* +* Return the name of the requestor +*/ +const X509_DN& PKCS10_Request::subject_dn() const + { + return data().m_subject_dn; + } + +/* +* Return the public key of the requestor +*/ +const std::vector& PKCS10_Request::raw_public_key() const + { + return data().m_public_key_bits; + } + +/* +* Return the public key of the requestor +*/ +Public_Key* PKCS10_Request::subject_public_key() const + { + DataSource_Memory source(raw_public_key()); + return X509::load_key(source); + } + +/* +* Return the alternative names of the requestor +*/ +const AlternativeName& PKCS10_Request::subject_alt_name() const + { + return data().m_alt_name; + } + +/* +* Return the X509v3 extensions +*/ +const Extensions& PKCS10_Request::extensions() const + { + return data().m_extensions; + } + +/* +* Return the key constraints (if any) +*/ +Key_Constraints PKCS10_Request::constraints() const + { + if(auto ext = extensions().get(OID::from_string("X509v3.KeyUsage"))) + { + return dynamic_cast(*ext).get_constraints(); + } + + return NO_CONSTRAINTS; + } + +/* +* Return the extendend key constraints (if any) +*/ +std::vector PKCS10_Request::ex_constraints() const + { + if(auto ext = extensions().get(OID::from_string("X509v3.ExtendedKeyUsage"))) + { + return dynamic_cast(*ext).get_oids(); + } + + return {}; + } + +/* +* Return is a CA certificate is requested +*/ +bool PKCS10_Request::is_CA() const + { + if(auto ext = extensions().get(OID::from_string("X509v3.BasicConstraints"))) + { + return dynamic_cast(*ext).get_is_ca(); + } + + return false; + } + +/* +* Return the desired path limit (if any) +*/ +size_t PKCS10_Request::path_limit() const + { + if(auto ext = extensions().get(OID::from_string("X509v3.BasicConstraints"))) + { + Cert_Extension::Basic_Constraints& basic_constraints = dynamic_cast(*ext); + if(basic_constraints.get_is_ca()) + { + return basic_constraints.get_path_limit(); + } + } + + return 0; + } + +} diff --git a/comm/third_party/botan/src/lib/x509/pkcs10.h b/comm/third_party/botan/src/lib/x509/pkcs10.h new file mode 100644 index 0000000000..3f3f87357d --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/pkcs10.h @@ -0,0 +1,148 @@ +/* +* PKCS #10 +* (C) 1999-2007 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PKCS10_H_ +#define BOTAN_PKCS10_H_ + +#include +#include +#include + +namespace Botan { + +struct PKCS10_Data; + +class Private_Key; +class Extensions; +class X509_DN; +class AlternativeName; + +/** +* PKCS #10 Certificate Request. +*/ +class BOTAN_PUBLIC_API(2,0) PKCS10_Request final : public X509_Object + { + public: + /** + * Get the subject public key. + * @return subject public key + */ + Public_Key* subject_public_key() const; + + /** + * Get the raw DER encoded public key. + * @return raw DER encoded public key + */ + const std::vector& raw_public_key() const; + + /** + * Get the subject DN. + * @return subject DN + */ + const X509_DN& subject_dn() const; + + /** + * Get the subject alternative name. + * @return subject alternative name. + */ + const AlternativeName& subject_alt_name() const; + + /** + * Get the key constraints for the key associated with this + * PKCS#10 object. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the extendend key constraints (if any). + * @return extended key constraints + */ + std::vector ex_constraints() const; + + /** + * Find out whether this is a CA request. + * @result true if it is a CA request, false otherwise. + */ + bool is_CA() const; + + /** + * Return the constraint on the path length defined + * in the BasicConstraints extension. + * @return path limit + */ + size_t path_limit() const; + + /** + * Get the challenge password for this request + * @return challenge password for this request + */ + std::string challenge_password() const; + + /** + * Get the X509v3 extensions. + * @return X509v3 extensions + */ + const Extensions& extensions() const; + + /** + * Create a PKCS#10 Request from a data source. + * @param source the data source providing the DER encoded request + */ + explicit PKCS10_Request(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Create a PKCS#10 Request from a file. + * @param filename the name of the file containing the DER or PEM + * encoded request file + */ + explicit PKCS10_Request(const std::string& filename); +#endif + + /** + * Create a PKCS#10 Request from binary data. + * @param vec a std::vector containing the DER value + */ + explicit PKCS10_Request(const std::vector& vec); + + /** + * Create a new PKCS10 certificate request + * @param key the key that will be included in the certificate request + * @param subject_dn the DN to be placed in the request + * @param extensions extensions to include in the request + * @param hash_fn the hash function to use to create the signature + * @param rng a random number generator + * @param padding_scheme if set specifies the padding scheme, otherwise an + * algorithm-specific default is used. + * @param challenge a challenge string to be included in the PKCS10 request, + * sometimes used for revocation purposes. + */ + static PKCS10_Request create(const Private_Key& key, + const X509_DN& subject_dn, + const Extensions& extensions, + const std::string& hash_fn, + RandomNumberGenerator& rng, + const std::string& padding_scheme = "", + const std::string& challenge = ""); + + private: + std::string PEM_label() const override; + + std::vector alternate_PEM_labels() const override; + + void force_decode() override; + + const PKCS10_Data& data() const; + + std::shared_ptr m_data; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/pkix_enums.h b/comm/third_party/botan/src/lib/x509/pkix_enums.h new file mode 100644 index 0000000000..a1c85293b8 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/pkix_enums.h @@ -0,0 +1,143 @@ +/* +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_PKIX_ENUMS_H_ +#define BOTAN_X509_PKIX_ENUMS_H_ + +#include + +namespace Botan { + +/** +* Certificate validation status code +*/ +enum class Certificate_Status_Code { + OK = 0, + VERIFIED = 0, + + // Revocation status + OCSP_RESPONSE_GOOD = 1, + OCSP_SIGNATURE_OK = 2, + VALID_CRL_CHECKED = 3, + OCSP_NO_HTTP = 4, + + // Warnings + FIRST_WARNING_STATUS = 500, + CERT_SERIAL_NEGATIVE = 500, + DN_TOO_LONG = 501, + OCSP_NO_REVOCATION_URL = 502, + OCSP_SERVER_NOT_AVAILABLE = 503, + + // Typo versions of above - will be removed in future major release + OSCP_NO_REVOCATION_URL = 502, + OSCP_SERVER_NOT_AVAILABLE = 503, + + // Errors + FIRST_ERROR_STATUS = 1000, + + SIGNATURE_METHOD_TOO_WEAK = 1000, + UNTRUSTED_HASH = 1001, + NO_REVOCATION_DATA = 1002, + NO_MATCHING_CRLDP = 1003, + + // Time problems + CERT_NOT_YET_VALID = 2000, + CERT_HAS_EXPIRED = 2001, + OCSP_NOT_YET_VALID = 2002, + OCSP_HAS_EXPIRED = 2003, + CRL_NOT_YET_VALID = 2004, + CRL_HAS_EXPIRED = 2005, + OCSP_IS_TOO_OLD = 2006, + + // Chain generation problems + CERT_ISSUER_NOT_FOUND = 3000, + CANNOT_ESTABLISH_TRUST = 3001, + CERT_CHAIN_LOOP = 3002, + CHAIN_LACKS_TRUST_ROOT = 3003, + CHAIN_NAME_MISMATCH = 3004, + + // Validation errors + POLICY_ERROR = 4000, + INVALID_USAGE = 4001, + CERT_CHAIN_TOO_LONG = 4002, + CA_CERT_NOT_FOR_CERT_ISSUER = 4003, + NAME_CONSTRAINT_ERROR = 4004, + + // Revocation errors + CA_CERT_NOT_FOR_CRL_ISSUER = 4005, + OCSP_CERT_NOT_LISTED = 4006, + OCSP_BAD_STATUS = 4007, + + // Other problems + CERT_NAME_NOMATCH = 4008, + UNKNOWN_CRITICAL_EXTENSION = 4009, + DUPLICATE_CERT_EXTENSION = 4010, + OCSP_SIGNATURE_ERROR = 4501, + OCSP_ISSUER_NOT_FOUND = 4502, + OCSP_RESPONSE_MISSING_KEYUSAGE = 4503, + OCSP_RESPONSE_INVALID = 4504, + EXT_IN_V1_V2_CERT = 4505, + DUPLICATE_CERT_POLICY = 4506, + V2_IDENTIFIERS_IN_V1_CERT = 4507, + + // Hard failures + CERT_IS_REVOKED = 5000, + CRL_BAD_SIGNATURE = 5001, + SIGNATURE_ERROR = 5002, + CERT_PUBKEY_INVALID = 5003, + SIGNATURE_ALGO_UNKNOWN = 5004, + SIGNATURE_ALGO_BAD_PARAMS = 5005 +}; + +/** +* Convert a status code to a human readable diagnostic message +* @param code the certifcate status +* @return string literal constant, or nullptr if code unknown +*/ +BOTAN_PUBLIC_API(2,0) const char* to_string(Certificate_Status_Code code); + +/** +* X.509v3 Key Constraints. +* If updating update copy in ffi.h +*/ +enum Key_Constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 1 << 15, + NON_REPUDIATION = 1 << 14, + KEY_ENCIPHERMENT = 1 << 13, + DATA_ENCIPHERMENT = 1 << 12, + KEY_AGREEMENT = 1 << 11, + KEY_CERT_SIGN = 1 << 10, + CRL_SIGN = 1 << 9, + ENCIPHER_ONLY = 1 << 8, + DECIPHER_ONLY = 1 << 7 +}; + +/** +* X.509v2 CRL Reason Code. +* This will become an enum class in a future major release +*/ +enum CRL_Code : uint32_t { + UNSPECIFIED = 0, + KEY_COMPROMISE = 1, + CA_COMPROMISE = 2, + AFFILIATION_CHANGED = 3, + SUPERSEDED = 4, + CESSATION_OF_OPERATION = 5, + CERTIFICATE_HOLD = 6, + REMOVE_FROM_CRL = 8, + PRIVLEDGE_WITHDRAWN = 9, + PRIVILEGE_WITHDRAWN = 9, + AA_COMPROMISE = 10, + + DELETE_CRL_ENTRY = 0xFF00, + OCSP_GOOD = 0xFF01, + OCSP_UNKNOWN = 0xFF02 +}; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/pkix_types.h b/comm/third_party/botan/src/lib/x509/pkix_types.h new file mode 100644 index 0000000000..983121955f --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/pkix_types.h @@ -0,0 +1,613 @@ +/* +* (C) 1999-2010,2012,2018,2020 Jack Lloyd +* (C) 2007 Yves Jerschow +* (C) 2015 Kai Michaelis +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PKIX_TYPES_H_ +#define BOTAN_PKIX_TYPES_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +class X509_Certificate; +class Data_Store; +class Public_Key; + +/** +* Check that key constraints are permitted for a specific public key. +* @param pub_key the public key on which the constraints shall be enforced on +* @param constraints the constraints that shall be enforced on the key +* @throw Invalid_Argument if the given constraints are not permitted for this key +*/ +BOTAN_PUBLIC_API(2,0) void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, + Key_Constraints constraints); + +std::string BOTAN_PUBLIC_API(2,0) key_constraints_to_string(Key_Constraints); + +/** +* Distinguished Name +*/ +class BOTAN_PUBLIC_API(2,0) X509_DN final : public ASN1_Object + { + public: + X509_DN() = default; + + explicit X509_DN(const std::multimap& args) + { + for(auto i : args) + add_attribute(i.first, i.second); + } + + explicit X509_DN(const std::multimap& args) + { + for(auto i : args) + add_attribute(i.first, i.second); + } + + void encode_into(DER_Encoder&) const override; + void decode_from(BER_Decoder&) override; + + bool has_field(const OID& oid) const; + ASN1_String get_first_attribute(const OID& oid) const; + + /* + * Return the BER encoded data, if any + */ + const std::vector& get_bits() const { return m_dn_bits; } + + bool empty() const { return m_rdn.empty(); } + + std::string to_string() const; + + const std::vector>& dn_info() const { return m_rdn; } + + std::multimap get_attributes() const; + std::multimap contents() const; + + bool has_field(const std::string& attr) const; + std::vector get_attribute(const std::string& attr) const; + std::string get_first_attribute(const std::string& attr) const; + + void add_attribute(const std::string& key, const std::string& val); + + void add_attribute(const OID& oid, const std::string& val) + { + add_attribute(oid, ASN1_String(val)); + } + + void add_attribute(const OID& oid, const ASN1_String& val); + + static std::string deref_info_field(const std::string& key); + + /** + * Lookup upper bounds in characters for the length of distinguished name fields + * as given in RFC 5280, Appendix A. + * + * @param oid the oid of the DN to lookup + * @return the upper bound, or zero if no ub is known to Botan + */ + static size_t lookup_ub(const OID& oid); + + private: + std::vector> m_rdn; + std::vector m_dn_bits; + }; + +bool BOTAN_PUBLIC_API(2,0) operator==(const X509_DN& dn1, const X509_DN& dn2); +bool BOTAN_PUBLIC_API(2,0) operator!=(const X509_DN& dn1, const X509_DN& dn2); + +/* +The ordering here is arbitrary and may change from release to release. +It is intended for allowing DNs as keys in std::map and similiar containers +*/ +bool BOTAN_PUBLIC_API(2,0) operator<(const X509_DN& dn1, const X509_DN& dn2); + +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, const X509_DN& dn); +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, X509_DN& dn); + +/** +* Alternative Name +*/ +class BOTAN_PUBLIC_API(2,0) AlternativeName final : public ASN1_Object + { + public: + void encode_into(DER_Encoder&) const override; + void decode_from(BER_Decoder&) override; + + std::multimap contents() const; + + bool has_field(const std::string& attr) const; + std::vector get_attribute(const std::string& attr) const; + + std::string get_first_attribute(const std::string& attr) const; + + void add_attribute(const std::string& type, const std::string& value); + void add_othername(const OID& oid, const std::string& value, ASN1_Tag type); + + const std::multimap& get_attributes() const + { + return m_alt_info; + } + + const std::multimap& get_othernames() const + { + return m_othernames; + } + + X509_DN dn() const; + + bool has_items() const; + + AlternativeName(const std::string& email_addr = "", + const std::string& uri = "", + const std::string& dns = "", + const std::string& ip_address = ""); + private: + std::multimap m_alt_info; + std::multimap m_othernames; + }; + +/** +* Attribute +*/ +class BOTAN_PUBLIC_API(2,0) Attribute final : public ASN1_Object + { + public: + void encode_into(DER_Encoder& to) const override; + void decode_from(BER_Decoder& from) override; + + Attribute() = default; + Attribute(const OID&, const std::vector&); + Attribute(const std::string&, const std::vector&); + + const OID& get_oid() const { return oid; } + + const std::vector& get_parameters() const { return parameters; } + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * These values are public for historical reasons, but in a future release + * they will be made private. Do not access them. + */ + OID oid; + std::vector parameters; + }; + +/** +* @brief X.509 GeneralName Type +* +* Handles parsing GeneralName types in their BER and canonical string +* encoding. Allows matching GeneralNames against each other using +* the rules laid out in the RFC 5280, sec. 4.2.1.10 (Name Contraints). +*/ +class BOTAN_PUBLIC_API(2,0) GeneralName final : public ASN1_Object + { + public: + enum MatchResult : int + { + All, + Some, + None, + NotFound, + UnknownType, + }; + + /** + * Creates an empty GeneralName. + */ + GeneralName() = default; + + /** + * Creates a new GeneralName for its string format. + * @param str type and name, colon-separated, e.g., "DNS:google.com" + */ + GeneralName(const std::string& str); + + void encode_into(DER_Encoder&) const override; + + void decode_from(BER_Decoder&) override; + + /** + * @return Type of the name. Can be DN, DNS, IP, RFC822 or URI. + */ + const std::string& type() const { return m_type; } + + /** + * @return The name as string. Format depends on type. + */ + const std::string& name() const { return m_name; } + + /** + * Checks whether a given certificate (partially) matches this name. + * @param cert certificate to be matched + * @return the match result + */ + MatchResult matches(const X509_Certificate& cert) const; + + private: + std::string m_type; + std::string m_name; + + bool matches_dns(const std::string&) const; + bool matches_dn(const std::string&) const; + bool matches_ip(const std::string&) const; + }; + +std::ostream& operator<<(std::ostream& os, const GeneralName& gn); + +/** +* @brief A single Name Constraint +* +* The Name Constraint extension adds a minimum and maximum path +* length to a GeneralName to form a constraint. The length limits +* are currently unused. +*/ +class BOTAN_PUBLIC_API(2,0) GeneralSubtree final : public ASN1_Object + { + public: + /** + * Creates an empty name constraint. + */ + GeneralSubtree() : m_base(), m_minimum(0), m_maximum(std::numeric_limits::max()) + {} + + /*** + * Creates a new name constraint. + * @param base name + * @param min minimum path length + * @param max maximum path length + */ + GeneralSubtree(const GeneralName& base, size_t min, size_t max) + : m_base(base), m_minimum(min), m_maximum(max) + {} + + /** + * Creates a new name constraint for its string format. + * @param str name constraint + */ + GeneralSubtree(const std::string& str); + + void encode_into(DER_Encoder&) const override; + + void decode_from(BER_Decoder&) override; + + /** + * @return name + */ + const GeneralName& base() const { return m_base; } + + /** + * @return minimum path length + */ + size_t minimum() const { return m_minimum; } + + /** + * @return maximum path length + */ + size_t maximum() const { return m_maximum; } + + private: + GeneralName m_base; + size_t m_minimum; + size_t m_maximum; + }; + +std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs); + +/** +* @brief Name Constraints +* +* Wraps the Name Constraints associated with a certificate. +*/ +class BOTAN_PUBLIC_API(2,0) NameConstraints final + { + public: + /** + * Creates an empty name NameConstraints. + */ + NameConstraints() : m_permitted_subtrees(), m_excluded_subtrees() {} + + /** + * Creates NameConstraints from a list of permitted and excluded subtrees. + * @param permitted_subtrees names for which the certificate is permitted + * @param excluded_subtrees names for which the certificate is not permitted + */ + NameConstraints(std::vector&& permitted_subtrees, + std::vector&& excluded_subtrees) + : m_permitted_subtrees(permitted_subtrees), m_excluded_subtrees(excluded_subtrees) + {} + + /** + * @return permitted names + */ + const std::vector& permitted() const { return m_permitted_subtrees; } + + /** + * @return excluded names + */ + const std::vector& excluded() const { return m_excluded_subtrees; } + + private: + std::vector m_permitted_subtrees; + std::vector m_excluded_subtrees; + }; + +/** +* X.509 Certificate Extension +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Extension + { + public: + /** + * @return OID representing this extension + */ + virtual OID oid_of() const = 0; + + /* + * @return specific OID name + * If possible OIDS table should match oid_name to OIDS, ie + * OID::from_string(ext->oid_name()) == ext->oid_of() + * Should return empty string if OID is not known + */ + virtual std::string oid_name() const = 0; + + /** + * Make a copy of this extension + * @return copy of this + */ + virtual Certificate_Extension* copy() const = 0; + + /* + * Add the contents of this extension into the information + * for the subject and/or issuer, as necessary. + * @param subject the subject info + * @param issuer the issuer info + */ + virtual void contents_to(Data_Store& subject, + Data_Store& issuer) const = 0; + + /* + * Callback visited during path validation. + * + * An extension can implement this callback to inspect + * the path during path validation. + * + * If an error occurs during validation of this extension, + * an appropriate status code shall be added to cert_status. + * + * @param subject Subject certificate that contains this extension + * @param issuer Issuer certificate + * @param status Certificate validation status codes for subject certificate + * @param cert_path Certificate path which is currently validated + * @param pos Position of subject certificate in cert_path + */ + virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector>& cert_path, + std::vector>& cert_status, + size_t pos); + + virtual ~Certificate_Extension() = default; + protected: + friend class Extensions; + virtual bool should_encode() const { return true; } + virtual std::vector encode_inner() const = 0; + virtual void decode_inner(const std::vector&) = 0; + }; + +/** +* X.509 Certificate Extension List +*/ +class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object + { + public: + /** + * Look up an object in the extensions, based on OID Returns + * nullptr if not set, if the extension was either absent or not + * handled. The pointer returned is owned by the Extensions + * object. + * This would be better with an optional return value + */ + const Certificate_Extension* get_extension_object(const OID& oid) const; + + template + const T* get_extension_object_as(const OID& oid = T::static_oid()) const + { + if(const Certificate_Extension* extn = get_extension_object(oid)) + { + // Unknown_Extension oid_name is empty + if(extn->oid_name().empty()) + { + return nullptr; + } + else if(const T* extn_as_T = dynamic_cast(extn)) + { + return extn_as_T; + } + else + { + throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); + } + } + + return nullptr; + } + + /** + * Return the set of extensions in the order they appeared in the certificate + * (or as they were added, if constructed) + */ + const std::vector& get_extension_oids() const + { + return m_extension_oids; + } + + /** + * Return true if an extension was set + */ + bool extension_set(const OID& oid) const; + + /** + * Return true if an extesion was set and marked critical + */ + bool critical_extension_set(const OID& oid) const; + + /** + * Return the raw bytes of the extension + * Will throw if OID was not set as an extension. + */ + std::vector get_extension_bits(const OID& oid) const; + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + void contents_to(Data_Store&, Data_Store&) const; + + /** + * Adds a new extension to the list. + * @param extn pointer to the certificate extension (Extensions takes ownership) + * @param critical whether this extension should be marked as critical + * @throw Invalid_Argument if the extension is already present in the list + */ + void add(Certificate_Extension* extn, bool critical = false); + + /** + * Adds a new extension to the list unless it already exists. If the extension + * already exists within the Extensions object, the extn pointer will be deleted. + * + * @param extn pointer to the certificate extension (Extensions takes ownership) + * @param critical whether this extension should be marked as critical + * @return true if the object was added false if the extension was already used + */ + bool add_new(Certificate_Extension* extn, bool critical = false); + + /** + * Adds an extension to the list or replaces it. + * @param extn the certificate extension + * @param critical whether this extension should be marked as critical + */ + void replace(Certificate_Extension* extn, bool critical = false); + + /** + * Remove an extension from the list. Returns true if the + * extension had been set, false otherwise. + */ + bool remove(const OID& oid); + + /** + * Searches for an extension by OID and returns the result. + * Only the known extensions types declared in this header + * are searched for by this function. + * @return Copy of extension with oid, nullptr if not found. + * Can avoid creating a copy by using get_extension_object function + */ + std::unique_ptr get(const OID& oid) const; + + /** + * Searches for an extension by OID and returns the result decoding + * it to some arbitrary extension type chosen by the application. + * + * Only the unknown extensions, that is, extensions types that + * are not declared in this header, are searched for by this + * function. + * + * @return Pointer to new extension with oid, nullptr if not found. + */ + template + std::unique_ptr get_raw(const OID& oid) const + { + auto extn_info = m_extension_info.find(oid); + + if(extn_info != m_extension_info.end()) + { + // Unknown_Extension oid_name is empty + if(extn_info->second.obj().oid_name() == "") + { + std::unique_ptr ext(new T); + ext->decode_inner(extn_info->second.bits()); + return ext; + } + } + return nullptr; + } + + /** + * Returns a copy of the list of extensions together with the corresponding + * criticality flag. All extensions are encoded as some object, falling back + * to Unknown_Extension class which simply allows reading the bytes as well + * as the criticality flag. + */ + std::vector, bool>> extensions() const; + + /** + * Returns the list of extensions as raw, encoded bytes + * together with the corresponding criticality flag. + * Contains all extensions, including any extensions encoded as Unknown_Extension + */ + std::map, bool>> extensions_raw() const; + + Extensions() {} + + Extensions(const Extensions&) = default; + Extensions& operator=(const Extensions&) = default; + + Extensions(Extensions&&) = default; + Extensions& operator=(Extensions&&) = default; + + private: + static std::unique_ptr + create_extn_obj(const OID& oid, + bool critical, + const std::vector& body); + + class Extensions_Info + { + public: + Extensions_Info(bool critical, + Certificate_Extension* ext) : + m_obj(ext), + m_bits(m_obj->encode_inner()), + m_critical(critical) + { + } + + Extensions_Info(bool critical, + const std::vector& encoding, + Certificate_Extension* ext) : + m_obj(ext), + m_bits(encoding), + m_critical(critical) + { + } + + bool is_critical() const { return m_critical; } + const std::vector& bits() const { return m_bits; } + const Certificate_Extension& obj() const + { + BOTAN_ASSERT_NONNULL(m_obj.get()); + return *m_obj.get(); + } + + private: + std::shared_ptr m_obj; + std::vector m_bits; + bool m_critical = false; + }; + + std::vector m_extension_oids; + std::map m_extension_info; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509_attribute.cpp b/comm/third_party/botan/src/lib/x509/x509_attribute.cpp new file mode 100644 index 0000000000..035f254c88 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_attribute.cpp @@ -0,0 +1,58 @@ +/* +* Attribute +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { + +/* +* Create an Attribute +*/ +Attribute::Attribute(const OID& attr_oid, const std::vector& attr_value) : + oid(attr_oid), + parameters(attr_value) + {} + +/* +* Create an Attribute +*/ +Attribute::Attribute(const std::string& attr_oid, + const std::vector& attr_value) : + oid(OID::from_string(attr_oid)), + parameters(attr_value) + {} + +/* +* DER encode a Attribute +*/ +void Attribute::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded Attribute +*/ +void Attribute::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +} diff --git a/comm/third_party/botan/src/lib/x509/x509_ca.cpp b/comm/third_party/botan/src/lib/x509/x509_ca.cpp new file mode 100644 index 0000000000..542a3a9191 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_ca.cpp @@ -0,0 +1,338 @@ +/* +* X.509 Certificate Authority +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Load the certificate and private key +*/ +X509_CA::X509_CA(const X509_Certificate& c, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) : + m_ca_cert(c), + m_hash_fn(hash_fn) + { + if(!m_ca_cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + std::map opts; + // constructor without additional options: use the padding used in the CA certificate + // sig_oid_str = /, so padding with all its options will look + // like a cipher mode to the scanner + std::string sig_oid_str = OIDS::oid2str_or_throw(c.signature_algorithm().get_oid()); + SCAN_Name scanner(sig_oid_str); + std::string pad = scanner.cipher_mode(); + if(!pad.empty()) + opts.insert({"padding",pad}); + + m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo)); + } + +/* +* Load the certificate and private key, and additional options +*/ +X509_CA::X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::map& opts, + const std::string& hash_fn, + RandomNumberGenerator& rng) : m_ca_cert(ca_certificate), m_hash_fn(hash_fn) + { + if(!m_ca_cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo)); + } + +/* +* X509_CA Destructor +*/ +X509_CA::~X509_CA() + { + /* for unique_ptr */ + } + +namespace { + +Extensions choose_extensions(const PKCS10_Request& req, + const X509_Certificate& ca_cert, + const std::string& hash_fn) + { + Key_Constraints constraints; + if(req.is_CA()) + { + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + } + else + { + std::unique_ptr key(req.subject_public_key()); + verify_cert_constraints_valid_for_key_type(*key, req.constraints()); + constraints = req.constraints(); + } + + Extensions extensions = req.extensions(); + + extensions.replace( + new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), + true); + + if(constraints != NO_CONSTRAINTS) + { + extensions.replace(new Cert_Extension::Key_Usage(constraints), true); + } + + extensions.replace(new Cert_Extension::Authority_Key_ID(ca_cert.subject_key_id())); + extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key(), hash_fn)); + + extensions.replace( + new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); + + extensions.replace( + new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); + + return extensions; + } + +} + +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const BigInt& serial_number, + const X509_Time& not_before, + const X509_Time& not_after) const + { + auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn); + + return make_cert(m_signer.get(), rng, serial_number, + m_ca_sig_algo, req.raw_public_key(), + not_before, not_after, + m_ca_cert.subject_dn(), req.subject_dn(), + extensions); + } + +/* +* Sign a PKCS #10 certificate request +*/ +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after) const + { + auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn); + + return make_cert(m_signer.get(), rng, m_ca_sig_algo, + req.raw_public_key(), + not_before, not_after, + m_ca_cert.subject_dn(), req.subject_dn(), + extensions); + } + +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const std::vector& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions) + { + const size_t SERIAL_BITS = 128; + BigInt serial_no(rng, SERIAL_BITS); + + return make_cert(signer, rng, serial_no, sig_algo, pub_key, + not_before, not_after, issuer_dn, subject_dn, extensions); + } + +/* +* Create a new certificate +*/ +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const BigInt& serial_no, + const AlgorithmIdentifier& sig_algo, + const std::vector& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions) + { + const size_t X509_CERT_VERSION = 3; + + // clang-format off + return X509_Certificate(X509_Object::make_signed( + signer, rng, sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .start_explicit(0) + .encode(X509_CERT_VERSION-1) + .end_explicit() + + .encode(serial_no) + + .encode(sig_algo) + .encode(issuer_dn) + + .start_cons(SEQUENCE) + .encode(not_before) + .encode(not_after) + .end_cons() + + .encode(subject_dn) + .raw_bytes(pub_key) + + .start_explicit(3) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents() + )); + // clang-format on + } + +/* +* Create a new, empty CRL +*/ +X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, + uint32_t next_update) const + { + return new_crl(rng, + std::chrono::system_clock::now(), + std::chrono::seconds(next_update)); + } + +/* +* Update a CRL with new entries +*/ +X509_CRL X509_CA::update_crl(const X509_CRL& crl, + const std::vector& new_revoked, + RandomNumberGenerator& rng, + uint32_t next_update) const + { + return update_crl(crl, new_revoked, rng, + std::chrono::system_clock::now(), + std::chrono::seconds(next_update)); + } + + +X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const + { + std::vector empty; + return make_crl(empty, 1, rng, issue_time, next_update); + } + +X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, + const std::vector& new_revoked, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const + { + std::vector revoked = last_crl.get_revoked(); + + std::copy(new_revoked.begin(), new_revoked.end(), + std::back_inserter(revoked)); + + return make_crl(revoked, last_crl.crl_number() + 1, rng, issue_time, next_update); + } + +/* +* Create a CRL +*/ +X509_CRL X509_CA::make_crl(const std::vector& revoked, + uint32_t crl_number, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const + { + const size_t X509_CRL_VERSION = 2; + + auto expire_time = issue_time + next_update; + + Extensions extensions; + extensions.add(new Cert_Extension::Authority_Key_ID(m_ca_cert.subject_key_id())); + extensions.add(new Cert_Extension::CRL_Number(crl_number)); + + // clang-format off + const std::vector crl = X509_Object::make_signed( + m_signer.get(), rng, m_ca_sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .encode(X509_CRL_VERSION-1) + .encode(m_ca_sig_algo) + .encode(m_ca_cert.subject_dn()) + .encode(X509_Time(issue_time)) + .encode(X509_Time(expire_time)) + .encode_if(revoked.size() > 0, + DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(revoked) + .end_cons() + ) + .start_explicit(0) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents()); + // clang-format on + + return X509_CRL(crl); + } + +/* +* Return the CA's certificate +*/ +X509_Certificate X509_CA::ca_certificate() const + { + return m_ca_cert; + } + +/* +* Choose a signing format for the key +*/ + +PK_Signer* choose_sig_format(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& sig_algo) + { + return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, "").release(); + } + +PK_Signer* choose_sig_format(const Private_Key& key, + const std::map& opts, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& sig_algo) + { + std::string padding; + if(opts.count("padding")) + padding = opts.at("padding"); + return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, padding).release(); + } + +} diff --git a/comm/third_party/botan/src/lib/x509/x509_ca.h b/comm/third_party/botan/src/lib/x509/x509_ca.h new file mode 100644 index 0000000000..20e9b1bccf --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_ca.h @@ -0,0 +1,261 @@ +/* +* X.509 Certificate Authority +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CA_H_ +#define BOTAN_X509_CA_H_ + +#include +#include +#include +#include + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include +#endif + +namespace Botan { + +class BigInt; +class Private_Key; +class PKCS10_Request; +class PK_Signer; + +/** +* This class represents X.509 Certificate Authorities (CAs). +*/ +class BOTAN_PUBLIC_API(2,0) X509_CA final + { + public: + /** + * Sign a PKCS#10 Request. + * @param req the request to sign + * @param rng the rng to use + * @param not_before the starting time for the certificate + * @param not_after the expiration time for the certificate + * @return resulting certificate + */ + X509_Certificate sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after) const; + + /** + * Sign a PKCS#10 Request. + * @param req the request to sign + * @param rng the rng to use + * @param serial_number the serial number the cert will be assigned. + * @param not_before the starting time for the certificate + * @param not_after the expiration time for the certificate + * @return resulting certificate + */ + X509_Certificate sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const BigInt& serial_number, + const X509_Time& not_before, + const X509_Time& not_after) const; + + /** + * Get the certificate of this CA. + * @return CA certificate + */ + X509_Certificate ca_certificate() const; + + /** + * Create a new and empty CRL for this CA. + * @param rng the random number generator to use + * @param issue_time the issue time (typically system_clock::now) + * @param next_update the time interval after issue_data within which + * a new CRL will be produced. + * @return new CRL + */ + X509_CRL new_crl(RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const; + + /** + * Create a new CRL by with additional entries. + * @param last_crl the last CRL of this CA to add the new entries to + * @param new_entries contains the new CRL entries to be added to the CRL + * @param rng the random number generator to use + * @param issue_time the issue time (typically system_clock::now) + * @param next_update the time interval after issue_data within which + * a new CRL will be produced. + */ + X509_CRL update_crl(const X509_CRL& last_crl, + const std::vector& new_entries, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const; + + /** + * Create a new and empty CRL for this CA. + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + * @return new CRL + */ + X509_CRL new_crl(RandomNumberGenerator& rng, + uint32_t next_update = 604800) const; + + /** + * Create a new CRL by with additional entries. + * @param last_crl the last CRL of this CA to add the new entries to + * @param new_entries contains the new CRL entries to be added to the CRL + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + */ + X509_CRL update_crl(const X509_CRL& last_crl, + const std::vector& new_entries, + RandomNumberGenerator& rng, + uint32_t next_update = 604800) const; + + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param sig_algo the signature algorithm identifier + * @param pub_key the serialized public key + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const std::vector& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions); + + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param serial_number the serial number the cert will be assigned + * @param sig_algo the signature algorithm identifier + * @param pub_key the serialized public key + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const BigInt& serial_number, + const AlgorithmIdentifier& sig_algo, + const std::vector& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions); + + /** + * Create a new CA object. + * @param ca_certificate the certificate of the CA + * @param key the private key of the CA + * @param hash_fn name of a hash function to use for signing + * @param rng the random generator to use + */ + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + + /** + * Create a new CA object. + * @param ca_certificate the certificate of the CA + * @param key the private key of the CA + * @param opts additional options, e.g. padding, as key value pairs + * @param hash_fn name of a hash function to use for signing + * @param rng the random generator to use + */ + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::map& opts, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +#if defined(BOTAN_HAS_SYSTEM_RNG) + BOTAN_DEPRECATED("Use version taking RNG object") + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn) : + X509_CA(ca_certificate, key, hash_fn, system_rng()) + {} +#endif + + X509_CA(const X509_CA&) = delete; + X509_CA& operator=(const X509_CA&) = delete; + + X509_CA(X509_CA&&) = default; + X509_CA& operator=(X509_CA&&) = default; + + ~X509_CA(); + + private: + X509_CRL make_crl(const std::vector& entries, + uint32_t crl_number, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const; + + AlgorithmIdentifier m_ca_sig_algo; + X509_Certificate m_ca_cert; + std::string m_hash_fn; + std::unique_ptr m_signer; + }; + +/** +* Choose the default signature format for a certain public key signature +* scheme. +* @param key will be the key to choose a padding scheme for +* @param rng the random generator to use +* @param hash_fn is the desired hash function +* @param alg_id will be set to the chosen scheme +* @return A PK_Signer object for generating signatures +*/ +BOTAN_PUBLIC_API(2,0) PK_Signer* choose_sig_format(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& alg_id); + +/** +* @verbatim +* Choose the default signature format for a certain public key signature +* scheme. +* +* The only option recognized by opts at this moment is "padding" +* Find an entry from src/build-data/oids.txt under [signature] of the form +* /[()] and add {"padding",} +* to opts. +* @endverbatim +* +* @param key will be the key to choose a padding scheme for +* @param opts contains additional options for building the certificate +* @param rng the random generator to use +* @param hash_fn is the desired hash function +* @param alg_id will be set to the chosen scheme +* @return A PK_Signer object for generating signatures +*/ +PK_Signer* choose_sig_format(const Private_Key& key, + const std::map& opts, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& alg_id); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509_crl.cpp b/comm/third_party/botan/src/lib/x509/x509_crl.cpp new file mode 100644 index 0000000000..1b5df1a083 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_crl.cpp @@ -0,0 +1,268 @@ +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +#include + +namespace Botan { + +struct CRL_Data + { + X509_DN m_issuer; + X509_Time m_this_update; + X509_Time m_next_update; + std::vector m_entries; + Extensions m_extensions; + + // cached values from extensions + size_t m_crl_number = 0; + std::vector m_auth_key_id; + std::string m_issuing_distribution_point; + }; + +std::string X509_CRL::PEM_label() const + { + return "X509 CRL"; + } + +std::vector X509_CRL::alternate_PEM_labels() const + { + return { "CRL" }; + } + +X509_CRL::X509_CRL(DataSource& src) + { + load_data(src); + } + +X509_CRL::X509_CRL(const std::vector& vec) + { + DataSource_Memory src(vec.data(), vec.size()); + load_data(src); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +X509_CRL::X509_CRL(const std::string& fsname) + { + DataSource_Stream src(fsname, true); + load_data(src); + } +#endif + +X509_CRL::X509_CRL(const X509_DN& issuer, + const X509_Time& this_update, + const X509_Time& next_update, + const std::vector& revoked) : + X509_Object() + { + m_data.reset(new CRL_Data); + m_data->m_issuer = issuer; + m_data->m_this_update = this_update; + m_data->m_next_update = next_update; + m_data->m_entries = revoked; + } + +/** +* Check if this particular certificate is listed in the CRL +*/ +bool X509_CRL::is_revoked(const X509_Certificate& cert) const + { + /* + If the cert wasn't issued by the CRL issuer, it's possible the cert + is revoked, but not by this CRL. Maybe throw an exception instead? + */ + if(cert.issuer_dn() != issuer_dn()) + return false; + + std::vector crl_akid = authority_key_id(); + std::vector cert_akid = cert.authority_key_id(); + + if(!crl_akid.empty() && !cert_akid.empty()) + { + if(crl_akid != cert_akid) + return false; + } + + std::vector cert_serial = cert.serial_number(); + + bool is_revoked = false; + + // FIXME would be nice to avoid a linear scan here - maybe sort the entries? + for(const CRL_Entry& entry : get_revoked()) + { + if(cert_serial == entry.serial_number()) + { + if(entry.reason_code() == REMOVE_FROM_CRL) + is_revoked = false; + else + is_revoked = true; + } + } + + return is_revoked; + } + +/* +* Decode the TBSCertList data +*/ +namespace { + +std::unique_ptr decode_crl_body(const std::vector& body, + const AlgorithmIdentifier& sig_algo) + { + std::unique_ptr data(new CRL_Data); + + BER_Decoder tbs_crl(body); + + size_t version; + tbs_crl.decode_optional(version, INTEGER, UNIVERSAL); + + if(version != 0 && version != 1) + throw X509_CRL::X509_CRL_Error("Unknown X.509 CRL version " + + std::to_string(version+1)); + + AlgorithmIdentifier sig_algo_inner; + tbs_crl.decode(sig_algo_inner); + + if(sig_algo != sig_algo_inner) + throw X509_CRL::X509_CRL_Error("Algorithm identifier mismatch"); + + tbs_crl.decode(data->m_issuer) + .decode(data->m_this_update) + .decode(data->m_next_update); + + BER_Object next = tbs_crl.get_next_object(); + + if(next.is_a(SEQUENCE, CONSTRUCTED)) + { + BER_Decoder cert_list(std::move(next)); + + while(cert_list.more_items()) + { + CRL_Entry entry; + cert_list.decode(entry); + data->m_entries.push_back(entry); + } + next = tbs_crl.get_next_object(); + } + + if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + BER_Decoder crl_options(std::move(next)); + crl_options.decode(data->m_extensions).verify_end(); + next = tbs_crl.get_next_object(); + } + + if(next.is_set()) + throw X509_CRL::X509_CRL_Error("Unknown tag in CRL"); + + tbs_crl.verify_end(); + + // Now cache some fields from the extensions + if(auto ext = data->m_extensions.get_extension_object_as()) + { + data->m_crl_number = ext->get_crl_number(); + } + if(auto ext = data->m_extensions.get_extension_object_as()) + { + data->m_auth_key_id = ext->get_key_id(); + } + if(auto ext = data->m_extensions.get_extension_object_as()) + { + std::stringstream ss; + + for(const auto& pair : ext->get_point().contents()) + { + ss << pair.first << ": " << pair.second << " "; + } + data->m_issuing_distribution_point = ss.str(); + } + + return data; + } + +} + +void X509_CRL::force_decode() + { + m_data.reset(decode_crl_body(signed_body(), signature_algorithm()).release()); + } + +const CRL_Data& X509_CRL::data() const + { + if(!m_data) + { + throw Invalid_State("X509_CRL uninitialized"); + } + return *m_data.get(); + } + +const Extensions& X509_CRL::extensions() const + { + return data().m_extensions; + } + +/* +* Return the list of revoked certificates +*/ +const std::vector& X509_CRL::get_revoked() const + { + return data().m_entries; + } + +/* +* Return the distinguished name of the issuer +*/ +const X509_DN& X509_CRL::issuer_dn() const + { + return data().m_issuer; + } + +/* +* Return the key identifier of the issuer +*/ +const std::vector& X509_CRL::authority_key_id() const + { + return data().m_auth_key_id; + } + +/* +* Return the CRL number of this CRL +*/ +uint32_t X509_CRL::crl_number() const + { + return static_cast(data().m_crl_number); + } + +/* +* Return the issue data of the CRL +*/ +const X509_Time& X509_CRL::this_update() const + { + return data().m_this_update; + } + +/* +* Return the date when a new CRL will be issued +*/ +const X509_Time& X509_CRL::next_update() const + { + return data().m_next_update; + } + +/* +* Return the CRL's distribution point +*/ +std::string X509_CRL::crl_issuing_distribution_point() const + { + return data().m_issuing_distribution_point; + } +} diff --git a/comm/third_party/botan/src/lib/x509/x509_crl.h b/comm/third_party/botan/src/lib/x509/x509_crl.h new file mode 100644 index 0000000000..6d4a301abd --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_crl.h @@ -0,0 +1,209 @@ +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CRL_H_ +#define BOTAN_X509_CRL_H_ + +#include +#include +#include +#include + +namespace Botan { + +class Extensions; +class X509_Certificate; +class X509_DN; + +struct CRL_Entry_Data; +struct CRL_Data; + +/** +* This class represents CRL entries +*/ +class BOTAN_PUBLIC_API(2,0) CRL_Entry final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + /** + * Get the serial number of the certificate associated with this entry. + * @return certificate's serial number + */ + const std::vector& serial_number() const; + + /** + * Get the revocation date of the certificate associated with this entry + * @return certificate's revocation date + */ + const X509_Time& expire_time() const; + + /** + * Get the entries reason code + * @return reason code + */ + CRL_Code reason_code() const; + + /** + * Get the extensions on this CRL entry + */ + const Extensions& extensions() const; + + /** + * Create uninitialized CRL_Entry object + */ + CRL_Entry() = default; + + /** + * Construct an CRL entry. + * @param cert the certificate to revoke + * @param reason the reason code to set in the entry + */ + CRL_Entry(const X509_Certificate& cert, + CRL_Code reason = UNSPECIFIED); + + private: + friend class X509_CRL; + + const CRL_Entry_Data& data() const; + + std::shared_ptr m_data; + }; + +/** +* Test two CRL entries for equality in all fields. +*/ +BOTAN_PUBLIC_API(2,0) bool operator==(const CRL_Entry&, const CRL_Entry&); + +/** +* Test two CRL entries for inequality in at least one field. +*/ +BOTAN_PUBLIC_API(2,0) bool operator!=(const CRL_Entry&, const CRL_Entry&); + +/** +* This class represents X.509 Certificate Revocation Lists (CRLs). +*/ +class BOTAN_PUBLIC_API(2,0) X509_CRL final : public X509_Object + { + public: + /** + * This class represents CRL related errors. + * + * In a future major release this exception type will be removed and + * replaced with Decoding_Error + */ + class BOTAN_PUBLIC_API(2,0) X509_CRL_Error final : public Decoding_Error + { + public: + explicit X509_CRL_Error(const std::string& error) : + Decoding_Error("X509_CRL: " + error) {} + }; + + /** + * Check if this particular certificate is listed in the CRL + */ + bool is_revoked(const X509_Certificate& cert) const; + + /** + * Get the entries of this CRL in the form of a vector. + * @return vector containing the entries of this CRL. + */ + const std::vector& get_revoked() const; + + /** + * Get the issuer DN of this CRL. + * @return CRLs issuer DN + */ + const X509_DN& issuer_dn() const; + + /** + * @return extension data for this CRL + */ + const Extensions& extensions() const; + + /** + * Get the AuthorityKeyIdentifier of this CRL. + * @return this CRLs AuthorityKeyIdentifier + */ + const std::vector& authority_key_id() const; + + /** + * Get the serial number of this CRL. + * @return CRLs serial number + */ + uint32_t crl_number() const; + + /** + * Get the CRL's thisUpdate value. + * @return CRLs thisUpdate + */ + const X509_Time& this_update() const; + + /** + * Get the CRL's nextUpdate value. + * @return CRLs nextdUpdate + */ + const X509_Time& next_update() const; + + /** + * Get the CRL's distribution point + * @return CRL.IssuingDistributionPoint from the CRL's Data_Store + */ + std::string crl_issuing_distribution_point() const; + + /** + * Create an uninitialized CRL object. Any attempts to access + * this object will throw an exception. + */ + X509_CRL() = default; + + /** + * Construct a CRL from a data source. + * @param source the data source providing the DER or PEM encoded CRL. + */ + X509_CRL(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Construct a CRL from a file containing the DER or PEM encoded CRL. + * @param filename the name of the CRL file + */ + X509_CRL(const std::string& filename); +#endif + + /** + * Construct a CRL from a binary vector + * @param vec the binary (DER) representation of the CRL + */ + X509_CRL(const std::vector& vec); + + /** + * Construct a CRL + * @param issuer issuer of this CRL + * @param thisUpdate valid from + * @param nextUpdate valid until + * @param revoked entries to be included in the CRL + */ + X509_CRL(const X509_DN& issuer, const X509_Time& thisUpdate, + const X509_Time& nextUpdate, const std::vector& revoked); + + private: + std::string PEM_label() const override; + + std::vector alternate_PEM_labels() const override; + + void force_decode() override; + + const CRL_Data& data() const; + + std::shared_ptr m_data; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509_dn.cpp b/comm/third_party/botan/src/lib/x509/x509_dn.cpp new file mode 100644 index 0000000000..99aad475a9 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_dn.cpp @@ -0,0 +1,428 @@ +/* +* X509_DN +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const std::string& type, + const std::string& str) + { + add_attribute(OID::from_string(type), str); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const OID& oid, const ASN1_String& str) + { + if(str.empty()) + return; + + m_rdn.push_back(std::make_pair(oid, str)); + m_dn_bits.clear(); + } + +/* +* Get the attributes of this X509_DN +*/ +std::multimap X509_DN::get_attributes() const + { + std::multimap retval; + + for(auto& i : m_rdn) + multimap_insert(retval, i.first, i.second.value()); + return retval; + } + +/* +* Get the contents of this X.500 Name +*/ +std::multimap X509_DN::contents() const + { + std::multimap retval; + + for(auto& i : m_rdn) + { + multimap_insert(retval, i.first.to_formatted_string(), i.second.value()); + } + return retval; + } + +bool X509_DN::has_field(const std::string& attr) const + { + const OID o = OIDS::str2oid_or_empty(deref_info_field(attr)); + if(o.has_value()) + return has_field(o); + else + return false; + } + +bool X509_DN::has_field(const OID& oid) const + { + for(auto& i : m_rdn) + { + if(i.first == oid) + return true; + } + + return false; + } + +std::string X509_DN::get_first_attribute(const std::string& attr) const + { + const OID oid = OID::from_string(deref_info_field(attr)); + return get_first_attribute(oid).value(); + } + +ASN1_String X509_DN::get_first_attribute(const OID& oid) const + { + for(auto& i : m_rdn) + { + if(i.first == oid) + { + return i.second; + } + } + + return ASN1_String(); + } + +/* +* Get a single attribute type +*/ +std::vector X509_DN::get_attribute(const std::string& attr) const + { + const OID oid = OID::from_string(deref_info_field(attr)); + + std::vector values; + + for(auto& i : m_rdn) + { + if(i.first == oid) + { + values.push_back(i.second.value()); + } + } + + return values; + } + +/* +* Deref aliases in a subject/issuer info request +*/ +std::string X509_DN::deref_info_field(const std::string& info) + { + if(info == "Name" || info == "CommonName" || info == "CN") return "X520.CommonName"; + if(info == "SerialNumber" || info == "SN") return "X520.SerialNumber"; + if(info == "Country" || info == "C") return "X520.Country"; + if(info == "Organization" || info == "O") return "X520.Organization"; + if(info == "Organizational Unit" || info == "OrgUnit" || info == "OU") + return "X520.OrganizationalUnit"; + if(info == "Locality" || info == "L") return "X520.Locality"; + if(info == "State" || info == "Province" || info == "ST") return "X520.State"; + if(info == "Email") return "RFC822"; + return info; + } + +/* +* Compare two X509_DNs for equality +*/ +bool operator==(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() != attr2.size()) return false; + + auto p1 = attr1.begin(); + auto p2 = attr2.begin(); + + while(true) + { + if(p1 == attr1.end() && p2 == attr2.end()) + break; + if(p1 == attr1.end()) return false; + if(p2 == attr2.end()) return false; + if(p1->first != p2->first) return false; + if(!x500_name_cmp(p1->second, p2->second)) + return false; + ++p1; + ++p2; + } + return true; + } + +/* +* Compare two X509_DNs for inequality +*/ +bool operator!=(const X509_DN& dn1, const X509_DN& dn2) + { + return !(dn1 == dn2); + } + +/* +* Induce an arbitrary ordering on DNs +*/ +bool operator<(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + // If they are not the same size, choose the smaller as the "lessor" + if(attr1.size() < attr2.size()) + return true; + if(attr1.size() > attr2.size()) + return false; + + // We know they are the same # of elements, now compare the OIDs: + auto p1 = attr1.begin(); + auto p2 = attr2.begin(); + + while(p1 != attr1.end() && p2 != attr2.end()) + { + if(p1->first != p2->first) + { + return (p1->first < p2->first); + } + + ++p1; + ++p2; + } + + // We know this is true because maps have the same size + BOTAN_ASSERT_NOMSG(p1 == attr1.end()); + BOTAN_ASSERT_NOMSG(p2 == attr2.end()); + + // Now we know all elements have the same OIDs, compare + // their string values: + + p1 = attr1.begin(); + p2 = attr2.begin(); + while(p1 != attr1.end() && p2 != attr2.end()) + { + BOTAN_DEBUG_ASSERT(p1->first == p2->first); + + // They may be binary different but same by X.500 rules, check this + if(!x500_name_cmp(p1->second, p2->second)) + { + // If they are not (by X.500) the same string, pick the + // lexicographic first as the lessor + return (p1->second < p2->second); + } + + ++p1; + ++p2; + } + + // if we reach here, then the DNs should be identical + BOTAN_DEBUG_ASSERT(dn1 == dn2); + return false; + } + +/* +* DER encode a DistinguishedName +*/ +void X509_DN::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + if(!m_dn_bits.empty()) + { + /* + If we decoded this from somewhere, encode it back exactly as + we received it + */ + der.raw_bytes(m_dn_bits); + } + else + { + for(const auto& dn : m_rdn) + { + der.start_cons(SET) + .start_cons(SEQUENCE) + .encode(dn.first) + .encode(dn.second) + .end_cons() + .end_cons(); + } + } + + der.end_cons(); + } + +/* +* Decode a BER encoded DistinguishedName +*/ +void X509_DN::decode_from(BER_Decoder& source) + { + std::vector bits; + + source.start_cons(SEQUENCE) + .raw_bytes(bits) + .end_cons(); + + BER_Decoder sequence(bits); + + while(sequence.more_items()) + { + BER_Decoder rdn = sequence.start_cons(SET); + + while(rdn.more_items()) + { + OID oid; + ASN1_String str; + + rdn.start_cons(SEQUENCE) + .decode(oid) + .decode(str) // TODO support Any + .end_cons(); + + add_attribute(oid, str); + } + } + + m_dn_bits = bits; + } + +namespace { + +std::string to_short_form(const OID& oid) + { + const std::string long_id = oid.to_formatted_string(); + + if(long_id == "X520.CommonName") + return "CN"; + + if(long_id == "X520.Country") + return "C"; + + if(long_id == "X520.Organization") + return "O"; + + if(long_id == "X520.OrganizationalUnit") + return "OU"; + + return long_id; + } + +} + +std::string X509_DN::to_string() const + { + std::ostringstream out; + out << *this; + return out.str(); + } + +std::ostream& operator<<(std::ostream& out, const X509_DN& dn) + { + auto info = dn.dn_info(); + + for(size_t i = 0; i != info.size(); ++i) + { + out << to_short_form(info[i].first) << "=\""; + for(char c : info[i].second.value()) + { + if(c == '\\' || c == '\"') + { + out << "\\"; + } + out << c; + } + out << "\""; + + if(i + 1 < info.size()) + { + out << ","; + } + } + return out; + } + +std::istream& operator>>(std::istream& in, X509_DN& dn) + { + in >> std::noskipws; + do + { + std::string key; + std::string val; + char c; + + while(in.good()) + { + in >> c; + + if(std::isspace(c) && key.empty()) + continue; + else if(!std::isspace(c)) + { + key.push_back(c); + break; + } + else + break; + } + + while(in.good()) + { + in >> c; + + if(!std::isspace(c) && c != '=') + key.push_back(c); + else if(c == '=') + break; + else + throw Invalid_Argument("Ill-formed X.509 DN"); + } + + bool in_quotes = false; + while(in.good()) + { + in >> c; + + if(std::isspace(c)) + { + if(!in_quotes && !val.empty()) + break; + else if(in_quotes) + val.push_back(' '); + } + else if(c == '"') + in_quotes = !in_quotes; + else if(c == '\\') + { + if(in.good()) + in >> c; + val.push_back(c); + } + else if(c == ',' && !in_quotes) + break; + else + val.push_back(c); + } + + if(!key.empty() && !val.empty()) + dn.add_attribute(X509_DN::deref_info_field(key),val); + else + break; + } + while(in.good()); + return in; + } +} diff --git a/comm/third_party/botan/src/lib/x509/x509_dn.h b/comm/third_party/botan/src/lib/x509/x509_dn.h new file mode 100644 index 0000000000..cd7beebe9c --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_dn.h @@ -0,0 +1,11 @@ +/* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_DN_H_ +#define BOTAN_X509_DN_H_ + +#include +BOTAN_DEPRECATED_HEADER(x509_dn.h) + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509_dn_ub.cpp b/comm/third_party/botan/src/lib/x509/x509_dn_ub.cpp new file mode 100644 index 0000000000..b5c7645a13 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_dn_ub.cpp @@ -0,0 +1,60 @@ +/* +* DN_UB maps: Upper bounds on the length of DN strings +* +* This file was automatically generated by ./src/scripts/oids.py on 2019-10-21 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace { + +/** + * Upper bounds for the length of distinguished name fields as given in RFC 5280, Appendix A. + * Only OIDS recognized by botan are considered, so far. + * Maps OID string representations instead of human readable strings in order + * to avoid an additional lookup. + */ +static const std::map DN_UB = + { + { Botan::OID({2,5,4,10}), 64 }, // X520.Organization + { Botan::OID({2,5,4,11}), 64 }, // X520.OrganizationalUnit + { Botan::OID({2,5,4,12}), 64 }, // X520.Title + { Botan::OID({2,5,4,3}), 64 }, // X520.CommonName + { Botan::OID({2,5,4,4}), 40 }, // X520.Surname + { Botan::OID({2,5,4,42}), 32768 }, // X520.GivenName + { Botan::OID({2,5,4,43}), 32768 }, // X520.Initials + { Botan::OID({2,5,4,44}), 32768 }, // X520.GenerationalQualifier + { Botan::OID({2,5,4,46}), 64 }, // X520.DNQualifier + { Botan::OID({2,5,4,5}), 64 }, // X520.SerialNumber + { Botan::OID({2,5,4,6}), 3 }, // X520.Country + { Botan::OID({2,5,4,65}), 128 }, // X520.Pseudonym + { Botan::OID({2,5,4,7}), 128 }, // X520.Locality + { Botan::OID({2,5,4,8}), 128 }, // X520.State + { Botan::OID({2,5,4,9}), 128 } // X520.StreetAddress + }; +} + +namespace Botan { + +//static +size_t X509_DN::lookup_ub(const OID& oid) + { + auto ub_entry = DN_UB.find(oid); + if(ub_entry != DN_UB.end()) + { + return ub_entry->second; + } + else + { + return 0; + } + } +} + diff --git a/comm/third_party/botan/src/lib/x509/x509_ext.cpp b/comm/third_party/botan/src/lib/x509/x509_ext.cpp new file mode 100644 index 0000000000..e81e15c187 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_ext.cpp @@ -0,0 +1,1023 @@ +/* +* X.509 Certificate Extensions +* (C) 1999-2010,2012 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/* +* Create a Certificate_Extension object of some kind to handle +*/ +std::unique_ptr +Extensions::create_extn_obj(const OID& oid, + bool critical, + const std::vector& body) + { + const std::string oid_str = oid.to_string(); + + std::unique_ptr extn; + + if(oid == Cert_Extension::Subject_Key_ID::static_oid()) + { + extn.reset(new Cert_Extension::Subject_Key_ID); + } + else if(oid == Cert_Extension::Key_Usage::static_oid()) + { + extn.reset(new Cert_Extension::Key_Usage); + } + else if(oid == Cert_Extension::Subject_Alternative_Name::static_oid()) + { + extn.reset(new Cert_Extension::Subject_Alternative_Name); + } + else if(oid == Cert_Extension::Issuer_Alternative_Name::static_oid()) + { + extn.reset(new Cert_Extension::Issuer_Alternative_Name); + } + else if(oid == Cert_Extension::Basic_Constraints::static_oid()) + { + extn.reset(new Cert_Extension::Basic_Constraints); + } + else if(oid == Cert_Extension::CRL_Number::static_oid()) + { + extn.reset(new Cert_Extension::CRL_Number); + } + else if(oid == Cert_Extension::CRL_ReasonCode::static_oid()) + { + extn.reset(new Cert_Extension::CRL_ReasonCode); + } + else if(oid == Cert_Extension::Authority_Key_ID::static_oid()) + { + extn.reset(new Cert_Extension::Authority_Key_ID); + } + else if(oid == Cert_Extension::Name_Constraints::static_oid()) + { + extn.reset(new Cert_Extension::Name_Constraints); + } + else if(oid == Cert_Extension::CRL_Distribution_Points::static_oid()) + { + extn.reset(new Cert_Extension::CRL_Distribution_Points); + } + else if(oid == Cert_Extension::CRL_Issuing_Distribution_Point::static_oid()) + { + extn.reset(new Cert_Extension::CRL_Issuing_Distribution_Point); + } + else if(oid == Cert_Extension::Certificate_Policies::static_oid()) + { + extn.reset(new Cert_Extension::Certificate_Policies); + } + else if(oid == Cert_Extension::Extended_Key_Usage::static_oid()) + { + extn.reset(new Cert_Extension::Extended_Key_Usage); + } + else if(oid == Cert_Extension::Authority_Information_Access::static_oid()) + { + extn.reset(new Cert_Extension::Authority_Information_Access); + } + else + { + // some other unknown extension type + extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); + } + + try + { + extn->decode_inner(body); + } + catch(Decoding_Error&) + { + extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); + extn->decode_inner(body); + } + return extn; + } + +/* +* Validate the extension (the default implementation is a NOP) +*/ +void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&, + const std::vector>&, + std::vector>&, + size_t) + { + } + +/* +* Add a new cert +*/ +void Extensions::add(Certificate_Extension* extn, bool critical) + { + // sanity check: we don't want to have the same extension more than once + if(m_extension_info.count(extn->oid_of()) > 0) + { + const std::string name = extn->oid_name(); + delete extn; + throw Invalid_Argument("Extension " + name + " already present in Extensions::add"); + } + + const OID oid = extn->oid_of(); + Extensions_Info info(critical, extn); + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + } + +bool Extensions::add_new(Certificate_Extension* extn, bool critical) + { + if(m_extension_info.count(extn->oid_of()) > 0) + { + delete extn; + return false; // already exists + } + + const OID oid = extn->oid_of(); + Extensions_Info info(critical, extn); + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + return true; + } + +bool Extensions::remove(const OID& oid) + { + const bool erased = m_extension_info.erase(oid) > 0; + + if(erased) + { + m_extension_oids.erase(std::find(m_extension_oids.begin(), m_extension_oids.end(), oid)); + } + + return erased; + } + +void Extensions::replace(Certificate_Extension* extn, bool critical) + { + // Remove it if it existed + remove(extn->oid_of()); + + const OID oid = extn->oid_of(); + Extensions_Info info(critical, extn); + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + } + +bool Extensions::extension_set(const OID& oid) const + { + return (m_extension_info.find(oid) != m_extension_info.end()); + } + +bool Extensions::critical_extension_set(const OID& oid) const + { + auto i = m_extension_info.find(oid); + if(i != m_extension_info.end()) + return i->second.is_critical(); + return false; + } + +std::vector Extensions::get_extension_bits(const OID& oid) const + { + auto i = m_extension_info.find(oid); + if(i == m_extension_info.end()) + throw Invalid_Argument("Extensions::get_extension_bits no such extension set"); + + return i->second.bits(); + } + +const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const + { + auto extn = m_extension_info.find(oid); + if(extn == m_extension_info.end()) + return nullptr; + + return &extn->second.obj(); + } + +std::unique_ptr Extensions::get(const OID& oid) const + { + if(const Certificate_Extension* ext = this->get_extension_object(oid)) + { + return std::unique_ptr(ext->copy()); + } + return nullptr; + } + +std::vector, bool>> Extensions::extensions() const + { + std::vector, bool>> exts; + for(auto&& ext : m_extension_info) + { + exts.push_back( + std::make_pair( + std::unique_ptr(ext.second.obj().copy()), + ext.second.is_critical()) + ); + } + return exts; + } + +std::map, bool>> Extensions::extensions_raw() const + { + std::map, bool>> out; + for(auto&& ext : m_extension_info) + { + out.emplace(ext.first, + std::make_pair(ext.second.bits(), + ext.second.is_critical())); + } + return out; + } + +/* +* Encode an Extensions list +*/ +void Extensions::encode_into(DER_Encoder& to_object) const + { + for(auto ext_info : m_extension_info) + { + const OID& oid = ext_info.first; + const bool should_encode = ext_info.second.obj().should_encode(); + + if(should_encode) + { + const bool is_critical = ext_info.second.is_critical(); + const std::vector& ext_value = ext_info.second.bits(); + + to_object.start_cons(SEQUENCE) + .encode(oid) + .encode_optional(is_critical, false) + .encode(ext_value, OCTET_STRING) + .end_cons(); + } + } + } + +/* +* Decode a list of Extensions +*/ +void Extensions::decode_from(BER_Decoder& from_source) + { + m_extension_oids.clear(); + m_extension_info.clear(); + + BER_Decoder sequence = from_source.start_cons(SEQUENCE); + + while(sequence.more_items()) + { + OID oid; + bool critical; + std::vector bits; + + sequence.start_cons(SEQUENCE) + .decode(oid) + .decode_optional(critical, BOOLEAN, UNIVERSAL, false) + .decode(bits, OCTET_STRING) + .end_cons(); + + std::unique_ptr obj = create_extn_obj(oid, critical, bits); + Extensions_Info info(critical, bits, obj.release()); + + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + } + sequence.verify_end(); + } + +/* +* Write the extensions to an info store +*/ +void Extensions::contents_to(Data_Store& subject_info, + Data_Store& issuer_info) const + { + for(auto&& m_extn_info : m_extension_info) + { + m_extn_info.second.obj().contents_to(subject_info, issuer_info); + subject_info.add(m_extn_info.second.obj().oid_name() + ".is_critical", + m_extn_info.second.is_critical()); + } + } + +namespace Cert_Extension { + +/* +* Checked accessor for the path_limit member +*/ +size_t Basic_Constraints::get_path_limit() const + { + if(!m_is_ca) + throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); + return m_path_limit; + } + +/* +* Encode the extension +*/ +std::vector Basic_Constraints::encode_inner() const + { + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_if(m_is_ca, + DER_Encoder() + .encode(m_is_ca) + .encode_optional(m_path_limit, NO_CERT_PATH_LIMIT) + ) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Basic_Constraints::decode_inner(const std::vector& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional(m_is_ca, BOOLEAN, UNIVERSAL, false) + .decode_optional(m_path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT) + .end_cons(); + + if(m_is_ca == false) + m_path_limit = 0; + } + +/* +* Return a textual representation +*/ +void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.BasicConstraints.is_ca", (m_is_ca ? 1 : 0)); + subject.add("X509v3.BasicConstraints.path_constraint", static_cast(m_path_limit)); + } + +/* +* Encode the extension +*/ +std::vector Key_Usage::encode_inner() const + { + if(m_constraints == NO_CONSTRAINTS) + throw Encoding_Error("Cannot encode zero usage constraints"); + + const size_t unused_bits = ctz(static_cast(m_constraints)); + + std::vector der; + der.push_back(BIT_STRING); + der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); + der.push_back(unused_bits % 8); + der.push_back((m_constraints >> 8) & 0xFF); + if(m_constraints & 0xFF) + der.push_back(m_constraints & 0xFF); + + return der; + } + +/* +* Decode the extension +*/ +void Key_Usage::decode_inner(const std::vector& in) + { + BER_Decoder ber(in); + + BER_Object obj = ber.get_next_object(); + + obj.assert_is_a(BIT_STRING, UNIVERSAL, "usage constraint"); + + if(obj.length() != 2 && obj.length() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + + uint16_t usage = 0; + + const uint8_t* bits = obj.bits(); + + if(bits[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + const uint8_t mask = static_cast(0xFF << bits[0]); + + if(obj.length() == 2) + { + usage = make_uint16(bits[1] & mask, 0); + } + else if(obj.length() == 3) + { + usage = make_uint16(bits[1], bits[2] & mask); + } + + m_constraints = Key_Constraints(usage); + } + +/* +* Return a textual representation +*/ +void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.KeyUsage", m_constraints); + } + +/* +* Encode the extension +*/ +std::vector Subject_Key_ID::encode_inner() const + { + std::vector output; + DER_Encoder(output).encode(m_key_id, OCTET_STRING); + return output; + } + +/* +* Decode the extension +*/ +void Subject_Key_ID::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(m_key_id, OCTET_STRING).verify_end(); + } + +/* +* Return a textual representation +*/ +void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.SubjectKeyIdentifier", m_key_id); + } + +/* +* Subject_Key_ID Constructor +*/ +Subject_Key_ID::Subject_Key_ID(const std::vector& pub_key, const std::string& hash_name) + { + std::unique_ptr hash(HashFunction::create_or_throw(hash_name)); + + m_key_id.resize(hash->output_length()); + + hash->update(pub_key); + hash->final(m_key_id.data()); + + // Truncate longer hashes, 192 bits here seems plenty + const size_t max_skid_len = (192 / 8); + if(m_key_id.size() > max_skid_len) + m_key_id.resize(max_skid_len); + } + +/* +* Encode the extension +*/ +std::vector Authority_Key_ID::encode_inner() const + { + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode(m_key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Authority_Key_ID::decode_inner(const std::vector& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional_string(m_key_id, OCTET_STRING, 0); + } + +/* +* Return a textual representation +*/ +void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const + { + if(m_key_id.size()) + issuer.add("X509v3.AuthorityKeyIdentifier", m_key_id); + } + +/* +* Encode the extension +*/ +std::vector Subject_Alternative_Name::encode_inner() const + { + std::vector output; + DER_Encoder(output).encode(m_alt_name); + return output; + } + +/* +* Encode the extension +*/ +std::vector Issuer_Alternative_Name::encode_inner() const + { + std::vector output; + DER_Encoder(output).encode(m_alt_name); + return output; + } + +/* +* Decode the extension +*/ +void Subject_Alternative_Name::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(m_alt_name); + } + +/* +* Decode the extension +*/ +void Issuer_Alternative_Name::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(m_alt_name); + } + +/* +* Return a textual representation +*/ +void Subject_Alternative_Name::contents_to(Data_Store& subject_info, + Data_Store&) const + { + subject_info.add(get_alt_name().contents()); + } + +/* +* Return a textual representation +*/ +void Issuer_Alternative_Name::contents_to(Data_Store&, Data_Store& issuer_info) const + { + issuer_info.add(get_alt_name().contents()); + } + +/* +* Encode the extension +*/ +std::vector Extended_Key_Usage::encode_inner() const + { + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_list(m_oids) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Extended_Key_Usage::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode_list(m_oids); + } + +/* +* Return a textual representation +*/ +void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + for(size_t i = 0; i != m_oids.size(); ++i) + subject.add("X509v3.ExtendedKeyUsage", m_oids[i].to_string()); + } + +/* +* Encode the extension +*/ +std::vector Name_Constraints::encode_inner() const + { + throw Not_Implemented("Name_Constraints encoding"); + } + + +/* +* Decode the extension +*/ +void Name_Constraints::decode_inner(const std::vector& in) + { + std::vector permit, exclude; + BER_Decoder ber(in); + BER_Decoder ext = ber.start_cons(SEQUENCE); + BER_Object per = ext.get_next_object(); + + ext.push_back(per); + if(per.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + ext.decode_list(permit,ASN1_Tag(0),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + if(permit.empty()) + throw Encoding_Error("Empty Name Contraint list"); + } + + BER_Object exc = ext.get_next_object(); + ext.push_back(exc); + if(per.is_a(1, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + ext.decode_list(exclude,ASN1_Tag(1),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + if(exclude.empty()) + throw Encoding_Error("Empty Name Contraint list"); + } + + ext.end_cons(); + + if(permit.empty() && exclude.empty()) + throw Encoding_Error("Empty Name Contraint extension"); + + m_name_constraints = NameConstraints(std::move(permit),std::move(exclude)); + } + +/* +* Return a textual representation +*/ +void Name_Constraints::contents_to(Data_Store& subject, Data_Store&) const + { + std::stringstream ss; + + for(const GeneralSubtree& gs: m_name_constraints.permitted()) + { + ss << gs; + subject.add("X509v3.NameConstraints.permitted", ss.str()); + ss.str(std::string()); + } + for(const GeneralSubtree& gs: m_name_constraints.excluded()) + { + ss << gs; + subject.add("X509v3.NameConstraints.excluded", ss.str()); + ss.str(std::string()); + } + } + +void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector>& cert_path, + std::vector>& cert_status, + size_t pos) + { + if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) + { + if(!subject.is_CA_cert()) + { + cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); + } + + const bool issuer_name_constraint_critical = + issuer.is_critical("X509v3.NameConstraints"); + + // Check that all subordinate certs pass the name constraint + for(size_t j = 0; j < pos; ++j) + { + bool permitted = m_name_constraints.permitted().empty(); + bool failed = false; + + for(auto c: m_name_constraints.permitted()) + { + switch(c.base().matches(*cert_path.at(j))) + { + case GeneralName::MatchResult::NotFound: + case GeneralName::MatchResult::All: + permitted = true; + break; + case GeneralName::MatchResult::UnknownType: + failed = issuer_name_constraint_critical; + permitted = true; + break; + default: + break; + } + } + + for(auto c: m_name_constraints.excluded()) + { + switch(c.base().matches(*cert_path.at(j))) + { + case GeneralName::MatchResult::All: + case GeneralName::MatchResult::Some: + failed = true; + break; + case GeneralName::MatchResult::UnknownType: + failed = issuer_name_constraint_critical; + break; + default: + break; + } + } + + if(failed || !permitted) + { + cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); + } + } + } + } + +namespace { + +/* +* A policy specifier +*/ +class Policy_Information final : public ASN1_Object + { + public: + Policy_Information() = default; + explicit Policy_Information(const OID& oid) : m_oid(oid) {} + + const OID& oid() const { return m_oid; } + + void encode_into(DER_Encoder& codec) const override + { + codec.start_cons(SEQUENCE) + .encode(m_oid) + .end_cons(); + } + + void decode_from(BER_Decoder& codec) override + { + codec.start_cons(SEQUENCE) + .decode(m_oid) + .discard_remaining() + .end_cons(); + } + + private: + OID m_oid; + }; + +} + +/* +* Encode the extension +*/ +std::vector Certificate_Policies::encode_inner() const + { + std::vector policies; + + for(size_t i = 0; i != m_oids.size(); ++i) + policies.push_back(Policy_Information(m_oids[i])); + + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_list(policies) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Certificate_Policies::decode_inner(const std::vector& in) + { + std::vector policies; + + BER_Decoder(in).decode_list(policies); + m_oids.clear(); + for(size_t i = 0; i != policies.size(); ++i) + m_oids.push_back(policies[i].oid()); + } + +/* +* Return a textual representation +*/ +void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const + { + for(size_t i = 0; i != m_oids.size(); ++i) + info.add("X509v3.CertificatePolicies", m_oids[i].to_string()); + } + +void Certificate_Policies::validate( + const X509_Certificate& /*subject*/, + const X509_Certificate& /*issuer*/, + const std::vector>& /*cert_path*/, + std::vector>& cert_status, + size_t pos) + { + std::set oid_set(m_oids.begin(), m_oids.end()); + if(oid_set.size() != m_oids.size()) + { + cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY); + } + } + +std::vector Authority_Information_Access::encode_inner() const + { + ASN1_String url(m_ocsp_responder, IA5_STRING); + + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(OID::from_string("PKIX.OCSP")) + .add_object(ASN1_Tag(6), CONTEXT_SPECIFIC, url.value()) + .end_cons() + .end_cons(); + return output; + } + +void Authority_Information_Access::decode_inner(const std::vector& in) + { + BER_Decoder ber = BER_Decoder(in).start_cons(SEQUENCE); + + while(ber.more_items()) + { + OID oid; + + BER_Decoder info = ber.start_cons(SEQUENCE); + + info.decode(oid); + + if(oid == OID::from_string("PKIX.OCSP")) + { + BER_Object name = info.get_next_object(); + + if(name.is_a(6, CONTEXT_SPECIFIC)) + { + m_ocsp_responder = ASN1::to_string(name); + } + + } + if(oid == OID::from_string("PKIX.CertificateAuthorityIssuers")) + { + BER_Object name = info.get_next_object(); + + if(name.is_a(6, CONTEXT_SPECIFIC)) + { + m_ca_issuers.push_back(ASN1::to_string(name)); + } + } + } + } + +void Authority_Information_Access::contents_to(Data_Store& subject, Data_Store&) const + { + if(!m_ocsp_responder.empty()) + subject.add("OCSP.responder", m_ocsp_responder); + for(const std::string& ca_issuer : m_ca_issuers) + subject.add("PKIX.CertificateAuthorityIssuers", ca_issuer); + } + +/* +* Checked accessor for the crl_number member +*/ +size_t CRL_Number::get_crl_number() const + { + if(!m_has_value) + throw Invalid_State("CRL_Number::get_crl_number: Not set"); + return m_crl_number; + } + +/* +* Copy a CRL_Number extension +*/ +CRL_Number* CRL_Number::copy() const + { + if(!m_has_value) + throw Invalid_State("CRL_Number::copy: Not set"); + return new CRL_Number(m_crl_number); + } + +/* +* Encode the extension +*/ +std::vector CRL_Number::encode_inner() const + { + std::vector output; + DER_Encoder(output).encode(m_crl_number); + return output; + } + +/* +* Decode the extension +*/ +void CRL_Number::decode_inner(const std::vector& in) + { + BER_Decoder(in).decode(m_crl_number); + m_has_value = true; + } + +/* +* Return a textual representation +*/ +void CRL_Number::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLNumber", static_cast(m_crl_number)); + } + +/* +* Encode the extension +*/ +std::vector CRL_ReasonCode::encode_inner() const + { + std::vector output; + DER_Encoder(output).encode(static_cast(m_reason), ENUMERATED, UNIVERSAL); + return output; + } + +/* +* Decode the extension +*/ +void CRL_ReasonCode::decode_inner(const std::vector& in) + { + size_t reason_code = 0; + BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL); + m_reason = static_cast(reason_code); + } + +/* +* Return a textual representation +*/ +void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLReasonCode", m_reason); + } + +std::vector CRL_Distribution_Points::encode_inner() const + { + throw Not_Implemented("CRL_Distribution_Points encoding"); + } + +void CRL_Distribution_Points::decode_inner(const std::vector& buf) + { + BER_Decoder(buf) + .decode_list(m_distribution_points) + .verify_end(); + + std::stringstream ss; + + for(size_t i = 0; i != m_distribution_points.size(); ++i) + { + auto contents = m_distribution_points[i].point().contents(); + + for(const auto& pair : contents) + { + ss << pair.first << ": " << pair.second << " "; + } + } + + m_crl_distribution_urls.push_back(ss.str()); + } + +void CRL_Distribution_Points::contents_to(Data_Store& subject, Data_Store&) const + { + for(const std::string& crl_url : m_crl_distribution_urls) + subject.add("CRL.DistributionPoint", crl_url); + } + +void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const + { + throw Not_Implemented("CRL_Distribution_Points encoding"); + } + +void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) + { + ber.start_cons(SEQUENCE) + .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC) + .decode_optional_implicit(m_point, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED), + SEQUENCE, CONSTRUCTED) + .end_cons().end_cons(); + } + +std::vector CRL_Issuing_Distribution_Point::encode_inner() const + { + throw Not_Implemented("CRL_Issuing_Distribution_Point encoding"); + } + +void CRL_Issuing_Distribution_Point::decode_inner(const std::vector& buf) + { + BER_Decoder(buf).decode(m_distribution_point).verify_end(); + } + +void CRL_Issuing_Distribution_Point::contents_to(Data_Store& info, Data_Store&) const + { + auto contents = m_distribution_point.point().contents(); + std::stringstream ss; + + for(const auto& pair : contents) + { + ss << pair.first << ": " << pair.second << " "; + } + + info.add("X509v3.CRLIssuingDistributionPoint", ss.str()); + } + +std::vector Unknown_Extension::encode_inner() const + { + return m_bytes; + } + +void Unknown_Extension::decode_inner(const std::vector& bytes) + { + // Just treat as an opaque blob at this level + m_bytes = bytes; + } + +void Unknown_Extension::contents_to(Data_Store&, Data_Store&) const + { + // No information store + } + +} + +} diff --git a/comm/third_party/botan/src/lib/x509/x509_ext.h b/comm/third_party/botan/src/lib/x509/x509_ext.h new file mode 100644 index 0000000000..cb6e064c9d --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_ext.h @@ -0,0 +1,529 @@ +/* +* X.509 Certificate Extensions +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_EXTENSIONS_H_ +#define BOTAN_X509_EXTENSIONS_H_ + +#include +#include + +namespace Botan { + +class Data_Store; +class X509_Certificate; + +namespace Cert_Extension { + +static const size_t NO_CERT_PATH_LIMIT = 0xFFFFFFF0; + +/** +* Basic Constraints Extension +*/ +class BOTAN_PUBLIC_API(2,0) Basic_Constraints final : public Certificate_Extension + { + public: + Basic_Constraints* copy() const override + { return new Basic_Constraints(m_is_ca, m_path_limit); } + + Basic_Constraints(bool ca = false, size_t limit = 0) : + m_is_ca(ca), m_path_limit(limit) {} + + bool get_is_ca() const { return m_is_ca; } + size_t get_path_limit() const; + + static OID static_oid() { return OID("2.5.29.19"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.BasicConstraints"; } + + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + bool m_is_ca; + size_t m_path_limit; + }; + +/** +* Key Usage Constraints Extension +*/ +class BOTAN_PUBLIC_API(2,0) Key_Usage final : public Certificate_Extension + { + public: + Key_Usage* copy() const override { return new Key_Usage(m_constraints); } + + explicit Key_Usage(Key_Constraints c = NO_CONSTRAINTS) : m_constraints(c) {} + + Key_Constraints get_constraints() const { return m_constraints; } + + static OID static_oid() { return OID("2.5.29.15"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.KeyUsage"; } + + bool should_encode() const override + { return (m_constraints != NO_CONSTRAINTS); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + Key_Constraints m_constraints; + }; + +/** +* Subject Key Identifier Extension +*/ +class BOTAN_PUBLIC_API(2,0) Subject_Key_ID final : public Certificate_Extension + { + public: + Subject_Key_ID() = default; + + explicit Subject_Key_ID(const std::vector& k) : m_key_id(k) {} + + Subject_Key_ID(const std::vector& public_key, + const std::string& hash_fn); + + Subject_Key_ID* copy() const override + { return new Subject_Key_ID(m_key_id); } + + const std::vector& get_key_id() const { return m_key_id; } + + static OID static_oid() { return OID("2.5.29.14"); } + OID oid_of() const override { return static_oid(); } + + private: + + std::string oid_name() const override + { return "X509v3.SubjectKeyIdentifier"; } + + bool should_encode() const override { return (m_key_id.size() > 0); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector m_key_id; + }; + +/** +* Authority Key Identifier Extension +*/ +class BOTAN_PUBLIC_API(2,0) Authority_Key_ID final : public Certificate_Extension + { + public: + Authority_Key_ID* copy() const override + { return new Authority_Key_ID(m_key_id); } + + Authority_Key_ID() = default; + explicit Authority_Key_ID(const std::vector& k) : m_key_id(k) {} + + const std::vector& get_key_id() const { return m_key_id; } + + static OID static_oid() { return OID("2.5.29.35"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.AuthorityKeyIdentifier"; } + + bool should_encode() const override { return (m_key_id.size() > 0); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector m_key_id; + }; + +/** +* Subject Alternative Name Extension +*/ +class BOTAN_PUBLIC_API(2,4) Subject_Alternative_Name final : public Certificate_Extension + { + public: + const AlternativeName& get_alt_name() const { return m_alt_name; } + + static OID static_oid() { return OID("2.5.29.17"); } + OID oid_of() const override { return static_oid(); } + + Subject_Alternative_Name* copy() const override + { return new Subject_Alternative_Name(get_alt_name()); } + + explicit Subject_Alternative_Name(const AlternativeName& name = AlternativeName()) : + m_alt_name(name) {} + + private: + std::string oid_name() const override { return "X509v3.SubjectAlternativeName"; } + + bool should_encode() const override { return m_alt_name.has_items(); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + AlternativeName m_alt_name; + }; + +/** +* Issuer Alternative Name Extension +*/ +class BOTAN_PUBLIC_API(2,0) Issuer_Alternative_Name final : public Certificate_Extension + { + public: + const AlternativeName& get_alt_name() const { return m_alt_name; } + + static OID static_oid() { return OID("2.5.29.18"); } + OID oid_of() const override { return static_oid(); } + + Issuer_Alternative_Name* copy() const override + { return new Issuer_Alternative_Name(get_alt_name()); } + + explicit Issuer_Alternative_Name(const AlternativeName& name = AlternativeName()) : + m_alt_name(name) {} + + private: + std::string oid_name() const override { return "X509v3.IssuerAlternativeName"; } + + bool should_encode() const override { return m_alt_name.has_items(); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + AlternativeName m_alt_name; + }; + +/** +* Extended Key Usage Extension +*/ +class BOTAN_PUBLIC_API(2,0) Extended_Key_Usage final : public Certificate_Extension + { + public: + Extended_Key_Usage* copy() const override + { return new Extended_Key_Usage(m_oids); } + + Extended_Key_Usage() = default; + explicit Extended_Key_Usage(const std::vector& o) : m_oids(o) {} + + const std::vector& get_oids() const { return m_oids; } + + static OID static_oid() { return OID("2.5.29.37"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.ExtendedKeyUsage"; } + + bool should_encode() const override { return (m_oids.size() > 0); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector m_oids; + }; + +/** +* Name Constraints +*/ +class BOTAN_PUBLIC_API(2,0) Name_Constraints final : public Certificate_Extension + { + public: + Name_Constraints* copy() const override + { return new Name_Constraints(m_name_constraints); } + + Name_Constraints() = default; + Name_Constraints(const NameConstraints &nc) : m_name_constraints(nc) {} + + void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector>& cert_path, + std::vector>& cert_status, + size_t pos) override; + + const NameConstraints& get_name_constraints() const { return m_name_constraints; } + + static OID static_oid() { return OID("2.5.29.30"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.NameConstraints"; } + + bool should_encode() const override { return true; } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + NameConstraints m_name_constraints; + }; + +/** +* Certificate Policies Extension +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Policies final : public Certificate_Extension + { + public: + Certificate_Policies* copy() const override + { return new Certificate_Policies(m_oids); } + + Certificate_Policies() = default; + explicit Certificate_Policies(const std::vector& o) : m_oids(o) {} + + BOTAN_DEPRECATED("Use get_policy_oids") + std::vector get_oids() const { return m_oids; } + + const std::vector& get_policy_oids() const { return m_oids; } + + static OID static_oid() { return OID("2.5.29.32"); } + OID oid_of() const override { return static_oid(); } + + void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector>& cert_path, + std::vector>& cert_status, + size_t pos) override; + private: + std::string oid_name() const override + { return "X509v3.CertificatePolicies"; } + + bool should_encode() const override { return (m_oids.size() > 0); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector m_oids; + }; + +/** +* Authority Information Access Extension +*/ +class BOTAN_PUBLIC_API(2,0) Authority_Information_Access final : public Certificate_Extension + { + public: + Authority_Information_Access* copy() const override + { return new Authority_Information_Access(m_ocsp_responder, m_ca_issuers); } + + Authority_Information_Access() = default; + + explicit Authority_Information_Access(const std::string& ocsp, const std::vector& ca_issuers = std::vector()) : + m_ocsp_responder(ocsp), m_ca_issuers(ca_issuers) {} + + std::string ocsp_responder() const { return m_ocsp_responder; } + + static OID static_oid() { return OID("1.3.6.1.5.5.7.1.1"); } + OID oid_of() const override { return static_oid(); } + const std::vector ca_issuers() const { return m_ca_issuers; } + + private: + std::string oid_name() const override + { return "PKIX.AuthorityInformationAccess"; } + + bool should_encode() const override { return (!m_ocsp_responder.empty()); } + + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + + void contents_to(Data_Store&, Data_Store&) const override; + + std::string m_ocsp_responder; + std::vector m_ca_issuers; + }; + +/** +* CRL Number Extension +*/ +class BOTAN_PUBLIC_API(2,0) CRL_Number final : public Certificate_Extension + { + public: + CRL_Number* copy() const override; + + CRL_Number() : m_has_value(false), m_crl_number(0) {} + CRL_Number(size_t n) : m_has_value(true), m_crl_number(n) {} + + size_t get_crl_number() const; + + static OID static_oid() { return OID("2.5.29.20"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.CRLNumber"; } + + bool should_encode() const override { return m_has_value; } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + bool m_has_value; + size_t m_crl_number; + }; + +/** +* CRL Entry Reason Code Extension +*/ +class BOTAN_PUBLIC_API(2,0) CRL_ReasonCode final : public Certificate_Extension + { + public: + CRL_ReasonCode* copy() const override + { return new CRL_ReasonCode(m_reason); } + + explicit CRL_ReasonCode(CRL_Code r = UNSPECIFIED) : m_reason(r) {} + + CRL_Code get_reason() const { return m_reason; } + + static OID static_oid() { return OID("2.5.29.21"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.ReasonCode"; } + + bool should_encode() const override { return (m_reason != UNSPECIFIED); } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + CRL_Code m_reason; + }; + +/** +* CRL Distribution Points Extension +* todo enforce restrictions from RFC 5280 4.2.1.13 +*/ +class BOTAN_PUBLIC_API(2,0) CRL_Distribution_Points final : public Certificate_Extension + { + public: + class BOTAN_PUBLIC_API(2,0) Distribution_Point final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + const AlternativeName& point() const { return m_point; } + private: + AlternativeName m_point; + }; + + CRL_Distribution_Points* copy() const override + { return new CRL_Distribution_Points(m_distribution_points); } + + CRL_Distribution_Points() = default; + + explicit CRL_Distribution_Points(const std::vector& points) : + m_distribution_points(points) {} + + const std::vector& distribution_points() const + { return m_distribution_points; } + + const std::vector& crl_distribution_urls() const + { return m_crl_distribution_urls; } + + static OID static_oid() { return OID("2.5.29.31"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.CRLDistributionPoints"; } + + bool should_encode() const override + { return !m_distribution_points.empty(); } + + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector m_distribution_points; + std::vector m_crl_distribution_urls; + }; + +/** +* CRL Issuing Distribution Point Extension +* todo enforce restrictions from RFC 5280 5.2.5 +*/ +class CRL_Issuing_Distribution_Point final : public Certificate_Extension + { + public: + CRL_Issuing_Distribution_Point() = default; + + explicit CRL_Issuing_Distribution_Point(const CRL_Distribution_Points::Distribution_Point& distribution_point) : + m_distribution_point(distribution_point) {} + + CRL_Issuing_Distribution_Point* copy() const override + { return new CRL_Issuing_Distribution_Point(m_distribution_point); } + + const AlternativeName& get_point() const + { return m_distribution_point.point(); } + + static OID static_oid() { return OID("2.5.29.28"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.CRLIssuingDistributionPoint"; } + + bool should_encode() const override { return true; } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + CRL_Distribution_Points::Distribution_Point m_distribution_point; + }; + +/** +* An unknown X.509 extension +* Will add a failure to the path validation result, if critical +*/ +class BOTAN_PUBLIC_API(2,4) Unknown_Extension final : public Certificate_Extension + { + public: + Unknown_Extension(const OID& oid, bool critical) : + m_oid(oid), m_critical(critical) {} + + Unknown_Extension* copy() const override + { return new Unknown_Extension(m_oid, m_critical); } + + /** + * Return the OID of this unknown extension + */ + OID oid_of() const override + { return m_oid; } + + //static_oid not defined for Unknown_Extension + + /** + * Return the extension contents + */ + const std::vector& extension_contents() const { return m_bytes; } + + /** + * Return if this extension was marked critical + */ + bool is_critical_extension() const { return m_critical; } + + void validate(const X509_Certificate&, const X509_Certificate&, + const std::vector>&, + std::vector>& cert_status, + size_t pos) override + { + if(m_critical) + { + cert_status.at(pos).insert(Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION); + } + } + + private: + std::string oid_name() const override { return ""; } + + bool should_encode() const override { return true; } + std::vector encode_inner() const override; + void decode_inner(const std::vector&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + OID m_oid; + bool m_critical; + std::vector m_bytes; + }; + + } + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509_obj.cpp b/comm/third_party/botan/src/lib/x509/x509_obj.cpp new file mode 100644 index 0000000000..2bb67629a6 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_obj.cpp @@ -0,0 +1,424 @@ +/* +* X.509 SIGNED Object +* (C) 1999-2007,2020 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { +struct Pss_params + { + AlgorithmIdentifier hash_algo; + AlgorithmIdentifier mask_gen_algo; + AlgorithmIdentifier mask_gen_hash; // redundant: decoded mask_gen_algo.parameters + size_t salt_len; + size_t trailer_field; + }; + +Pss_params decode_pss_params(const std::vector& encoded_pss_params) + { + const AlgorithmIdentifier default_hash("SHA-160", AlgorithmIdentifier::USE_NULL_PARAM); + const AlgorithmIdentifier default_mgf("MGF1", default_hash.BER_encode()); + + Pss_params pss_parameter; + BER_Decoder(encoded_pss_params) + .start_cons(SEQUENCE) + .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, default_hash) + .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE, default_mgf) + .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20)) + .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1)) + .end_cons(); + + BER_Decoder(pss_parameter.mask_gen_algo.get_parameters()).decode(pss_parameter.mask_gen_hash); + + return pss_parameter; + } +} + +/* +* Read a PEM or BER X.509 object +*/ +void X509_Object::load_data(DataSource& in) + { + try { + if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) + { + BER_Decoder dec(in); + decode_from(dec); + } + else + { + std::string got_label; + DataSource_Memory ber(PEM_Code::decode(in, got_label)); + + if(got_label != PEM_label()) + { + bool is_alternate = false; + for(std::string alt_label : alternate_PEM_labels()) + { + if(got_label == alt_label) + { + is_alternate = true; + break; + } + } + + if(!is_alternate) + throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label); + } + + BER_Decoder dec(ber); + decode_from(dec); + } + } + catch(Decoding_Error& e) + { + throw Decoding_Error(PEM_label() + " decoding", e); + } + } + + +void X509_Object::encode_into(DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(signed_body()) + .end_cons() + .encode(signature_algorithm()) + .encode(signature(), BIT_STRING) + .end_cons(); + } + +/* +* Read a BER encoded X.509 object +*/ +void X509_Object::decode_from(BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(m_tbs_bits) + .end_cons() + .decode(m_sig_algo) + .decode(m_sig, BIT_STRING) + .end_cons(); + + force_decode(); + } + +/* +* Return a PEM encoded X.509 object +*/ +std::string X509_Object::PEM_encode() const + { + return PEM_Code::encode(BER_encode(), PEM_label()); + } + +/* +* Return the TBS data +*/ +std::vector X509_Object::tbs_data() const + { + return ASN1::put_in_sequence(m_tbs_bits); + } + +/* +* Return the hash used in generating the signature +*/ +std::string X509_Object::hash_used_for_signature() const + { + const OID& oid = m_sig_algo.get_oid(); + const std::vector sig_info = split_on(oid.to_formatted_string(), '/'); + + if(sig_info.size() == 1 && sig_info[0] == "Ed25519") + return "SHA-512"; + else if(sig_info.size() != 2) + throw Internal_Error("Invalid name format found for " + oid.to_string()); + + if(sig_info[1] == "EMSA4") + { + const OID hash_oid = decode_pss_params(signature_algorithm().get_parameters()).hash_algo.get_oid(); + return hash_oid.to_formatted_string(); + } + else + { + const std::vector pad_and_hash = + parse_algorithm_name(sig_info[1]); + + if(pad_and_hash.size() != 2) + { + throw Internal_Error("Invalid name format " + sig_info[1]); + } + + return pad_and_hash[1]; + } + } + +/* +* Check the signature on an object +*/ +bool X509_Object::check_signature(const Public_Key* pub_key) const + { + if(!pub_key) + throw Invalid_Argument("No key provided for " + PEM_label() + " signature check"); + std::unique_ptr key(pub_key); + return check_signature(*key); + } + +bool X509_Object::check_signature(const Public_Key& pub_key) const + { + const Certificate_Status_Code code = verify_signature(pub_key); + return (code == Certificate_Status_Code::VERIFIED); + } + +Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const + { + const std::vector sig_info = + split_on(m_sig_algo.get_oid().to_formatted_string(), '/'); + + if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name()) + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + + const std::string pub_key_algo = sig_info[0]; + std::string padding; + if(sig_info.size() == 2) + padding = sig_info[1]; + else if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS") + padding = "Pure"; + else + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + + const Signature_Format format = pub_key.default_x509_signature_format(); + + if(padding == "EMSA4") + { + // "MUST contain RSASSA-PSS-params" + if(signature_algorithm().get_parameters().empty()) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + Pss_params pss_parameter = decode_pss_params(signature_algorithm().get_parameters()); + + // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 + const std::string hash_algo = pss_parameter.hash_algo.get_oid().to_formatted_string(); + if(hash_algo != "SHA-160" && + hash_algo != "SHA-224" && + hash_algo != "SHA-256" && + hash_algo != "SHA-384" && + hash_algo != "SHA-512") + { + return Certificate_Status_Code::UNTRUSTED_HASH; + } + + const std::string mgf_algo = pss_parameter.mask_gen_algo.get_oid().to_formatted_string(); + if(mgf_algo != "MGF1") + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm + // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 + if(pss_parameter.mask_gen_hash.get_oid() != pss_parameter.hash_algo.get_oid()) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + if(pss_parameter.trailer_field != 1) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")"; + } + else + { + /* + * For all other signature types the signature parameters should + * be either NULL or empty. In theory there is some distinction between + * these but in practice they seem to be used somewhat interchangeably. + * + * The various RFCs all have prescriptions of what is allowed: + * RSA - NULL (RFC 3279) + * DSA - empty (RFC 3279) + * ECDSA - empty (RFC 3279) + * GOST - empty (RFC 4491) + * Ed25519 - empty (RFC 8410) + * XMSS - empty (draft-vangeest-x509-hash-sigs) + * + * But in practice we find RSA with empty and ECDSA will NULL all + * over the place so it's not really possible to enforce. For Ed25519 + * and XMSS because they are new we attempt to enforce. + */ + if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS") + { + if(!signature_algorithm().parameters_are_empty()) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + } + else + { + if(!signature_algorithm().parameters_are_null_or_empty()) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + } + } + + try + { + PK_Verifier verifier(pub_key, padding, format); + const bool valid = verifier.verify_message(tbs_data(), signature()); + + if(valid) + return Certificate_Status_Code::VERIFIED; + else + return Certificate_Status_Code::SIGNATURE_ERROR; + } + catch(Algorithm_Not_Found&) + { + return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN; + } + catch(...) + { + // This shouldn't happen, fallback to generic signature error + return Certificate_Status_Code::SIGNATURE_ERROR; + } + } + +/* +* Apply the X.509 SIGNED macro +*/ +std::vector X509_Object::make_signed(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& algo, + const secure_vector& tbs_bits) + { + const std::vector signature = signer->sign_message(tbs_bits, rng); + + std::vector output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .encode(algo) + .encode(signature, BIT_STRING) + .end_cons(); + + return output; + } + +namespace { + +std::string choose_sig_algo(AlgorithmIdentifier& sig_algo, + const Private_Key& key, + const std::string& hash_fn, + const std::string& user_specified) + { + const std::string algo_name = key.algo_name(); + std::string padding; + + // check algo_name and set default + if(algo_name == "RSA") + { + // set to EMSA3 for compatibility reasons, originally it was the only option + padding = "EMSA3(" + hash_fn + ")"; + } + else if(algo_name == "DSA" || + algo_name == "ECDSA" || + algo_name == "ECGDSA" || + algo_name == "ECKCDSA" || + algo_name == "GOST-34.10" || + algo_name == "GOST-34.10-2012-256" || + algo_name == "GOST-34.10-2012-512") + { + padding = "EMSA1(" + hash_fn + ")"; + } + else if(algo_name == "Ed25519") + { + padding = "Pure"; + } + else if(algo_name == "XMSS") + { + if(user_specified.empty() == true) + { + throw Invalid_Argument("XMSS requires padding scheme"); + } + padding = user_specified; + sig_algo = AlgorithmIdentifier(OID::from_string("XMSS"), AlgorithmIdentifier::USE_EMPTY_PARAM); + return padding; + } + else + { + throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + } + + if(user_specified.empty() == false) + { + padding = user_specified; + } + + if(padding != "Pure") + { + // try to construct an EMSA object from the padding options or default + std::unique_ptr emsa; + try + { + emsa.reset(get_emsa(padding)); + } + /* + * get_emsa will throw if opts contains {"padding",} but + * does not specify a hash function. + * Omitting it is valid since it needs to be identical to hash_fn. + * If it still throws, something happened that we cannot repair here, + * e.g. the algorithm/padding combination is not supported. + */ + catch(...) + { + emsa.reset(get_emsa(padding + "(" + hash_fn + ")")); + } + + if(!emsa) + { + throw Invalid_Argument("Could not parse padding scheme " + padding); + } + + sig_algo = emsa->config_for_x509(key, hash_fn); + return emsa->name(); + } + else + { + sig_algo = AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM); + return "Pure"; + } + } + +} + +/* +* Choose a signing format for the key +*/ +std::unique_ptr X509_Object::choose_sig_format(AlgorithmIdentifier& sig_algo, + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + const std::string& padding_algo) + { + const Signature_Format format = key.default_x509_signature_format(); + + const std::string emsa = choose_sig_algo(sig_algo, key, hash_fn, padding_algo); + + return std::unique_ptr(new PK_Signer(key, rng, emsa, format)); + } + +} diff --git a/comm/third_party/botan/src/lib/x509/x509_obj.h b/comm/third_party/botan/src/lib/x509/x509_obj.h new file mode 100644 index 0000000000..fd972aed9d --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509_obj.h @@ -0,0 +1,144 @@ +/* +* X.509 SIGNED Object +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_OBJECT_H_ +#define BOTAN_X509_OBJECT_H_ + +#include +#include +#include + +namespace Botan { + +class Public_Key; +class Private_Key; +class RandomNumberGenerator; + +/** +* This class represents abstract X.509 signed objects as in the X.500 +* SIGNED macro +*/ +class BOTAN_PUBLIC_API(2,0) X509_Object : public ASN1_Object + { + public: + /** + * The underlying data that is to be or was signed + * @return data that is or was signed + */ + std::vector tbs_data() const; + + /** + * @return signature on tbs_data() + */ + const std::vector& signature() const { return m_sig; } + + /** + * @return signed body + */ + const std::vector& signed_body() const { return m_tbs_bits; } + + /** + * @return signature algorithm that was used to generate signature + */ + const AlgorithmIdentifier& signature_algorithm() const { return m_sig_algo; } + + /** + * @return hash algorithm that was used to generate signature + */ + std::string hash_used_for_signature() const; + + /** + * Create a signed X509 object. + * @param signer the signer used to sign the object + * @param rng the random number generator to use + * @param alg_id the algorithm identifier of the signature scheme + * @param tbs the tbs bits to be signed + * @return signed X509 object + */ + static std::vector make_signed(class PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& alg_id, + const secure_vector& tbs); + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * @return status of the signature - OK if verified or otherwise an indicator of + * the problem preventing verification. + */ + Certificate_Status_Code verify_signature(const Public_Key& key) const; + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * @return true if the signature is valid, otherwise false + */ + bool check_signature(const Public_Key& key) const; + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * the object will be deleted after use (this should have + * been a std::unique_ptr) + * @return true if the signature is valid, otherwise false + */ + bool check_signature(const Public_Key* key) const; + + /** + * DER encode an X509_Object + * See @ref ASN1_Object::encode_into() + */ + void encode_into(class DER_Encoder& to) const override; + + /** + * Decode a BER encoded X509_Object + * See @ref ASN1_Object::decode_from() + */ + void decode_from(class BER_Decoder& from) override; + + /** + * @return PEM encoding of this + */ + std::string PEM_encode() const; + + X509_Object(const X509_Object&) = default; + X509_Object& operator=(const X509_Object&) = default; + + virtual std::string PEM_label() const = 0; + + virtual std::vector alternate_PEM_labels() const + { return std::vector(); } + + virtual ~X509_Object() = default; + + static std::unique_ptr + choose_sig_format(AlgorithmIdentifier& sig_algo, + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + const std::string& padding_algo); + + protected: + + X509_Object() = default; + + /** + * Decodes from src as either DER or PEM data, then calls force_decode() + */ + void load_data(DataSource& src); + + private: + virtual void force_decode() = 0; + + AlgorithmIdentifier m_sig_algo; + std::vector m_tbs_bits; + std::vector m_sig; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509cert.cpp b/comm/third_party/botan/src/lib/x509/x509cert.cpp new file mode 100644 index 0000000000..55f279c58c --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509cert.cpp @@ -0,0 +1,956 @@ +/* +* X.509 Certificates +* (C) 1999-2010,2015,2017 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +struct X509_Certificate_Data + { + std::vector m_serial; + AlgorithmIdentifier m_sig_algo_inner; + X509_DN m_issuer_dn; + X509_DN m_subject_dn; + std::vector m_issuer_dn_bits; + std::vector m_subject_dn_bits; + X509_Time m_not_before; + X509_Time m_not_after; + std::vector m_subject_public_key_bits; + std::vector m_subject_public_key_bits_seq; + std::vector m_subject_public_key_bitstring; + std::vector m_subject_public_key_bitstring_sha1; + AlgorithmIdentifier m_subject_public_key_algid; + + std::vector m_v2_issuer_key_id; + std::vector m_v2_subject_key_id; + Extensions m_v3_extensions; + + std::vector m_extended_key_usage; + std::vector m_authority_key_id; + std::vector m_subject_key_id; + std::vector m_cert_policies; + + std::vector m_crl_distribution_points; + std::string m_ocsp_responder; + std::vector m_ca_issuers; + + std::vector m_issuer_dn_bits_sha256; + std::vector m_subject_dn_bits_sha256; + + std::string m_fingerprint_sha1; + std::string m_fingerprint_sha256; + + AlternativeName m_subject_alt_name; + AlternativeName m_issuer_alt_name; + NameConstraints m_name_constraints; + + Data_Store m_subject_ds; + Data_Store m_issuer_ds; + + size_t m_version = 0; + size_t m_path_len_constraint = 0; + Key_Constraints m_key_constraints = NO_CONSTRAINTS; + bool m_self_signed = false; + bool m_is_ca_certificate = false; + bool m_serial_negative = false; + }; + +std::string X509_Certificate::PEM_label() const + { + return "CERTIFICATE"; + } + +std::vector X509_Certificate::alternate_PEM_labels() const + { + return { "X509 CERTIFICATE" }; + } + +X509_Certificate::X509_Certificate(DataSource& src) + { + load_data(src); + } + +X509_Certificate::X509_Certificate(const std::vector& vec) + { + DataSource_Memory src(vec.data(), vec.size()); + load_data(src); + } + +X509_Certificate::X509_Certificate(const uint8_t data[], size_t len) + { + DataSource_Memory src(data, len); + load_data(src); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +X509_Certificate::X509_Certificate(const std::string& fsname) + { + DataSource_Stream src(fsname, true); + load_data(src); + } +#endif + +namespace { + +std::unique_ptr parse_x509_cert_body(const X509_Object& obj) + { + std::unique_ptr data(new X509_Certificate_Data); + + BigInt serial_bn; + BER_Object public_key; + BER_Object v3_exts_data; + + BER_Decoder(obj.signed_body()) + .decode_optional(data->m_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + .decode(serial_bn) + .decode(data->m_sig_algo_inner) + .decode(data->m_issuer_dn) + .start_cons(SEQUENCE) + .decode(data->m_not_before) + .decode(data->m_not_after) + .end_cons() + .decode(data->m_subject_dn) + .get_next(public_key) + .decode_optional_string(data->m_v2_issuer_key_id, BIT_STRING, 1) + .decode_optional_string(data->m_v2_subject_key_id, BIT_STRING, 2) + .get_next(v3_exts_data) + .verify_end("TBSCertificate has extra data after extensions block"); + + if(data->m_version > 2) + throw Decoding_Error("Unknown X.509 cert version " + std::to_string(data->m_version)); + if(obj.signature_algorithm() != data->m_sig_algo_inner) + throw Decoding_Error("X.509 Certificate had differing algorithm identifers in inner and outer ID fields"); + + public_key.assert_is_a(SEQUENCE, CONSTRUCTED, "X.509 certificate public key"); + + // crude method to save the serial's sign; will get lost during decoding, otherwise + data->m_serial_negative = serial_bn.is_negative(); + + // for general sanity convert wire version (0 based) to standards version (v1 .. v3) + data->m_version += 1; + + data->m_serial = BigInt::encode(serial_bn); + data->m_subject_dn_bits = ASN1::put_in_sequence(data->m_subject_dn.get_bits()); + data->m_issuer_dn_bits = ASN1::put_in_sequence(data->m_issuer_dn.get_bits()); + + // validate_public_key_params(public_key.value); + AlgorithmIdentifier public_key_alg_id; + BER_Decoder(public_key).decode(public_key_alg_id).discard_remaining(); + + const std::vector public_key_info = + split_on(OIDS::oid2str_or_empty(public_key_alg_id.get_oid()), '/'); + + if(!public_key_info.empty() && public_key_info[0] == "RSA") + { + // RFC4055: If PublicKeyAlgo = PSS or OAEP: limit the use of the public key exclusively to either RSASSA - PSS or RSAES - OAEP + if(public_key_info.size() >= 2) + { + if(public_key_info[1] == "EMSA4") + { + /* + When the RSA private key owner wishes to limit the use of the public + key exclusively to RSASSA-PSS, then the id-RSASSA-PSS object + identifier MUST be used in the algorithm field within the subject + public key information, and, if present, the parameters field MUST + contain RSASSA-PSS-params. + + All parameters in the signature structure algorithm identifier MUST + match the parameters in the key structure algorithm identifier + except the saltLength field. The saltLength field in the signature parameters + MUST be greater or equal to that in the key parameters field. + + ToDo: Allow salt length to be greater + */ + if(public_key_alg_id != obj.signature_algorithm()) + { + throw Decoding_Error("Algorithm identifier mismatch"); + } + } + } + else + { + // oid = rsaEncryption -> parameters field MUST contain NULL + if(public_key_alg_id != AlgorithmIdentifier(public_key_alg_id.get_oid(), AlgorithmIdentifier::USE_NULL_PARAM)) + { + throw Decoding_Error("RSA algorithm parameters field MUST contain NULL"); + } + } + } + + data->m_subject_public_key_bits.assign(public_key.bits(), public_key.bits() + public_key.length()); + + data->m_subject_public_key_bits_seq = ASN1::put_in_sequence(data->m_subject_public_key_bits); + + BER_Decoder(data->m_subject_public_key_bits) + .decode(data->m_subject_public_key_algid) + .decode(data->m_subject_public_key_bitstring, BIT_STRING); + + if(v3_exts_data.is_a(3, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + // Path validation will reject a v1/v2 cert with v3 extensions + BER_Decoder(v3_exts_data).decode(data->m_v3_extensions).verify_end(); + } + else if(v3_exts_data.is_set()) + { + throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging()); + } + + // Now cache some fields from the extensions + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_key_constraints = ext->get_constraints(); + /* + RFC 5280: When the keyUsage extension appears in a certificate, + at least one of the bits MUST be set to 1. + */ + if(data->m_key_constraints == NO_CONSTRAINTS) + { + throw Decoding_Error("Certificate has invalid encoding for KeyUsage"); + } + } + else + { + data->m_key_constraints = NO_CONSTRAINTS; + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_subject_key_id = ext->get_key_id(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_authority_key_id = ext->get_key_id(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_name_constraints = ext->get_name_constraints(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + if(ext->get_is_ca() == true) + { + /* + * RFC 5280 section 4.2.1.3 requires that CAs include KeyUsage in all + * intermediate CA certificates they issue. Currently we accept it being + * missing, as do most other implementations. But it may be worth + * removing this entirely, or alternately adding a warning level + * validation failure for it. + */ + if(data->m_key_constraints == NO_CONSTRAINTS || + (data->m_key_constraints & KEY_CERT_SIGN)) + { + data->m_is_ca_certificate = true; + data->m_path_len_constraint = ext->get_path_limit(); + } + } + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_issuer_alt_name = ext->get_alt_name(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_subject_alt_name = ext->get_alt_name(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_extended_key_usage = ext->get_oids(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_cert_policies = ext->get_policy_oids(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_ocsp_responder = ext->ocsp_responder(); + data->m_ca_issuers = ext->ca_issuers(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as()) + { + data->m_crl_distribution_points = ext->crl_distribution_urls(); + } + + // Check for self-signed vs self-issued certificates + if(data->m_subject_dn == data->m_issuer_dn) + { + if(data->m_subject_key_id.empty() == false && data->m_authority_key_id.empty() == false) + { + data->m_self_signed = (data->m_subject_key_id == data->m_authority_key_id); + } + else + { + /* + If a parse error or unknown algorithm is encountered, default + to assuming it is self signed. We have no way of being certain but + that is usually the default case (self-issued is rare in practice). + */ + data->m_self_signed = true; + + try + { + std::unique_ptr pub_key(X509::load_key(data->m_subject_public_key_bits_seq)); + + Certificate_Status_Code sig_status = obj.verify_signature(*pub_key); + + if(sig_status == Certificate_Status_Code::OK || + sig_status == Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN) + { + data->m_self_signed = true; + } + else + { + data->m_self_signed = false; + } + } + catch(...) + { + // ignore errors here to allow parsing to continue + } + } + } + + const std::vector full_encoding = obj.BER_encode(); + + std::unique_ptr sha1(HashFunction::create("SHA-1")); + if(sha1) + { + sha1->update(data->m_subject_public_key_bitstring); + data->m_subject_public_key_bitstring_sha1 = sha1->final_stdvec(); + // otherwise left as empty, and we will throw if subject_public_key_bitstring_sha1 is called + + data->m_fingerprint_sha1 = create_hex_fingerprint(full_encoding, "SHA-1"); + } + + std::unique_ptr sha256(HashFunction::create("SHA-256")); + if(sha256) + { + sha256->update(data->m_issuer_dn_bits); + data->m_issuer_dn_bits_sha256 = sha256->final_stdvec(); + + sha256->update(data->m_subject_dn_bits); + data->m_subject_dn_bits_sha256 = sha256->final_stdvec(); + + data->m_fingerprint_sha256 = create_hex_fingerprint(full_encoding, "SHA-256"); + } + + data->m_subject_ds.add(data->m_subject_dn.contents()); + data->m_issuer_ds.add(data->m_issuer_dn.contents()); + data->m_v3_extensions.contents_to(data->m_subject_ds, data->m_issuer_ds); + + return data; + } + +} + +/* +* Decode the TBSCertificate data +*/ +void X509_Certificate::force_decode() + { + m_data.reset(); + + std::unique_ptr data = parse_x509_cert_body(*this); + + m_data.reset(data.release()); + } + +const X509_Certificate_Data& X509_Certificate::data() const + { + if(m_data == nullptr) + { + throw Invalid_State("X509_Certificate uninitialized"); + } + return *m_data.get(); + } + +uint32_t X509_Certificate::x509_version() const + { + return static_cast(data().m_version); + } + +bool X509_Certificate::is_self_signed() const + { + return data().m_self_signed; + } + +const X509_Time& X509_Certificate::not_before() const + { + return data().m_not_before; + } + +const X509_Time& X509_Certificate::not_after() const + { + return data().m_not_after; + } + +const AlgorithmIdentifier& X509_Certificate::subject_public_key_algo() const + { + return data().m_subject_public_key_algid; + } + +const std::vector& X509_Certificate::v2_issuer_key_id() const + { + return data().m_v2_issuer_key_id; + } + +const std::vector& X509_Certificate::v2_subject_key_id() const + { + return data().m_v2_subject_key_id; + } + +const std::vector& X509_Certificate::subject_public_key_bits() const + { + return data().m_subject_public_key_bits; + } + +const std::vector& X509_Certificate::subject_public_key_info() const + { + return data().m_subject_public_key_bits_seq; + } + +const std::vector& X509_Certificate::subject_public_key_bitstring() const + { + return data().m_subject_public_key_bitstring; + } + +const std::vector& X509_Certificate::subject_public_key_bitstring_sha1() const + { + if(data().m_subject_public_key_bitstring_sha1.empty()) + throw Encoding_Error("X509_Certificate::subject_public_key_bitstring_sha1 called but SHA-1 disabled in build"); + + return data().m_subject_public_key_bitstring_sha1; + } + +const std::vector& X509_Certificate::authority_key_id() const + { + return data().m_authority_key_id; + } + +const std::vector& X509_Certificate::subject_key_id() const + { + return data().m_subject_key_id; + } + +const std::vector& X509_Certificate::serial_number() const + { + return data().m_serial; + } + +bool X509_Certificate::is_serial_negative() const + { + return data().m_serial_negative; + } + + +const X509_DN& X509_Certificate::issuer_dn() const + { + return data().m_issuer_dn; + } + +const X509_DN& X509_Certificate::subject_dn() const + { + return data().m_subject_dn; + } + +const std::vector& X509_Certificate::raw_issuer_dn() const + { + return data().m_issuer_dn_bits; + } + +const std::vector& X509_Certificate::raw_subject_dn() const + { + return data().m_subject_dn_bits; + } + +bool X509_Certificate::is_CA_cert() const + { + if(data().m_version < 3 && data().m_self_signed) + return true; + + return data().m_is_ca_certificate; + } + +uint32_t X509_Certificate::path_limit() const + { + if(data().m_version < 3 && data().m_self_signed) + return 32; // in theory infinite, but this is more than enough + + return static_cast(data().m_path_len_constraint); + } + +Key_Constraints X509_Certificate::constraints() const + { + return data().m_key_constraints; + } + +const std::vector& X509_Certificate::extended_key_usage() const + { + return data().m_extended_key_usage; + } + +const std::vector& X509_Certificate::certificate_policy_oids() const + { + return data().m_cert_policies; + } + +const NameConstraints& X509_Certificate::name_constraints() const + { + return data().m_name_constraints; + } + +const Extensions& X509_Certificate::v3_extensions() const + { + return data().m_v3_extensions; + } + +bool X509_Certificate::allowed_usage(Key_Constraints usage) const + { + if(constraints() == NO_CONSTRAINTS) + return true; + return ((constraints() & usage) == usage); + } + +bool X509_Certificate::allowed_extended_usage(const std::string& usage) const + { + return allowed_extended_usage(OID::from_string(usage)); + } + +bool X509_Certificate::allowed_extended_usage(const OID& usage) const + { + const std::vector& ex = extended_key_usage(); + if(ex.empty()) + return true; + + if(std::find(ex.begin(), ex.end(), usage) != ex.end()) + return true; + + return false; + } + +bool X509_Certificate::allowed_usage(Usage_Type usage) const + { + // These follow suggestions in RFC 5280 4.2.1.12 + + switch(usage) + { + case Usage_Type::UNSPECIFIED: + return true; + + case Usage_Type::TLS_SERVER_AUTH: + return (allowed_usage(KEY_AGREEMENT) || allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DIGITAL_SIGNATURE)) && allowed_extended_usage("PKIX.ServerAuth"); + + case Usage_Type::TLS_CLIENT_AUTH: + return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(KEY_AGREEMENT)) && allowed_extended_usage("PKIX.ClientAuth"); + + case Usage_Type::OCSP_RESPONDER: + return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(NON_REPUDIATION)) && allowed_extended_usage("PKIX.OCSPSigning"); + + case Usage_Type::CERTIFICATE_AUTHORITY: + return is_CA_cert(); + + case Usage_Type::ENCRYPTION: + return (allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DATA_ENCIPHERMENT)); + } + + return false; + } + +bool X509_Certificate::has_constraints(Key_Constraints constraints) const + { + if(this->constraints() == NO_CONSTRAINTS) + { + return false; + } + + return ((this->constraints() & constraints) != 0); + } + +bool X509_Certificate::has_ex_constraint(const std::string& ex_constraint) const + { + return has_ex_constraint(OID::from_string(ex_constraint)); + } + +bool X509_Certificate::has_ex_constraint(const OID& usage) const + { + const std::vector& ex = extended_key_usage(); + return (std::find(ex.begin(), ex.end(), usage) != ex.end()); + } + +/* +* Return if a certificate extension is marked critical +*/ +bool X509_Certificate::is_critical(const std::string& ex_name) const + { + return v3_extensions().critical_extension_set(OID::from_string(ex_name)); + } + +std::string X509_Certificate::ocsp_responder() const + { + return data().m_ocsp_responder; + } + +std::vector X509_Certificate::ca_issuers() const + { + return data().m_ca_issuers; + } + +std::string X509_Certificate::crl_distribution_point() const + { + // just returns the first (arbitrarily) + if(data().m_crl_distribution_points.size() > 0) + return data().m_crl_distribution_points[0]; + return ""; + } + +const AlternativeName& X509_Certificate::subject_alt_name() const + { + return data().m_subject_alt_name; + } + +const AlternativeName& X509_Certificate::issuer_alt_name() const + { + return data().m_issuer_alt_name; + } + +/* +* Return information about the subject +*/ +std::vector +X509_Certificate::subject_info(const std::string& req) const + { + if(req == "Email") + return this->subject_info("RFC822"); + + if(subject_dn().has_field(req)) + return subject_dn().get_attribute(req); + + if(subject_alt_name().has_field(req)) + return subject_alt_name().get_attribute(req); + + // These will be removed later: + if(req == "X509.Certificate.v2.key_id") + return {hex_encode(this->v2_subject_key_id())}; + if(req == "X509v3.SubjectKeyIdentifier") + return {hex_encode(this->subject_key_id())}; + if(req == "X509.Certificate.dn_bits") + return {hex_encode(this->raw_subject_dn())}; + if(req == "X509.Certificate.start") + return {not_before().to_string()}; + if(req == "X509.Certificate.end") + return {not_after().to_string()}; + + if(req == "X509.Certificate.version") + return {std::to_string(x509_version())}; + if(req == "X509.Certificate.serial") + return {hex_encode(serial_number())}; + + return data().m_subject_ds.get(req); + } + +/* +* Return information about the issuer +*/ +std::vector +X509_Certificate::issuer_info(const std::string& req) const + { + if(issuer_dn().has_field(req)) + return issuer_dn().get_attribute(req); + + if(issuer_alt_name().has_field(req)) + return issuer_alt_name().get_attribute(req); + + // These will be removed later: + if(req == "X509.Certificate.v2.key_id") + return {hex_encode(this->v2_issuer_key_id())}; + if(req == "X509v3.AuthorityKeyIdentifier") + return {hex_encode(this->authority_key_id())}; + if(req == "X509.Certificate.dn_bits") + return {hex_encode(this->raw_issuer_dn())}; + + return data().m_issuer_ds.get(req); + } + +/* +* Return the public key in this certificate +*/ +std::unique_ptr X509_Certificate::load_subject_public_key() const + { + try + { + return std::unique_ptr(X509::load_key(subject_public_key_info())); + } + catch(std::exception& e) + { + throw Decoding_Error("X509_Certificate::load_subject_public_key", e); + } + } + +Public_Key* X509_Certificate::subject_public_key() const + { + return load_subject_public_key().release(); + } + +std::vector X509_Certificate::raw_issuer_dn_sha256() const + { + if(data().m_issuer_dn_bits_sha256.empty()) + throw Encoding_Error("X509_Certificate::raw_issuer_dn_sha256 called but SHA-256 disabled in build"); + return data().m_issuer_dn_bits_sha256; + } + +std::vector X509_Certificate::raw_subject_dn_sha256() const + { + if(data().m_subject_dn_bits_sha256.empty()) + throw Encoding_Error("X509_Certificate::raw_subject_dn_sha256 called but SHA-256 disabled in build"); + return data().m_subject_dn_bits_sha256; + } + +namespace { + +/* +* Lookup each OID in the vector +*/ +std::vector lookup_oids(const std::vector& oids) + { + std::vector out; + + for(const OID& oid : oids) + { + out.push_back(oid.to_formatted_string()); + } + return out; + } + +} + +/* +* Return the list of extended key usage OIDs +*/ +std::vector X509_Certificate::ex_constraints() const + { + return lookup_oids(extended_key_usage()); + } + +/* +* Return the list of certificate policies +*/ +std::vector X509_Certificate::policies() const + { + return lookup_oids(certificate_policy_oids()); + } + +std::string X509_Certificate::fingerprint(const std::string& hash_name) const + { + /* + * The SHA-1 and SHA-256 fingerprints are precomputed since these + * are the most commonly used. Especially, SHA-256 fingerprints are + * used for cycle detection during path construction. + * + * If SHA-1 or SHA-256 was missing at parsing time the vectors are + * left empty in which case we fall back to create_hex_fingerprint + * which will throw if the hash is unavailable. + */ + if(hash_name == "SHA-256" && data().m_fingerprint_sha256.size() > 0) + return data().m_fingerprint_sha256; + else if(hash_name == "SHA-1" && data().m_fingerprint_sha1.size() > 0) + return data().m_fingerprint_sha1; + else + return create_hex_fingerprint(this->BER_encode(), hash_name); + } + +bool X509_Certificate::matches_dns_name(const std::string& name) const + { + if(name.empty()) + return false; + + std::vector issued_names = subject_info("DNS"); + + // Fall back to CN only if no DNS names are set (RFC 6125 sec 6.4.4) + if(issued_names.empty()) + issued_names = subject_info("Name"); + + for(size_t i = 0; i != issued_names.size(); ++i) + { + if(host_wildcard_match(issued_names[i], name)) + return true; + } + + return false; + } + +/* +* Compare two certificates for equality +*/ +bool X509_Certificate::operator==(const X509_Certificate& other) const + { + return (this->signature() == other.signature() && + this->signature_algorithm() == other.signature_algorithm() && + this->signed_body() == other.signed_body()); + } + +bool X509_Certificate::operator<(const X509_Certificate& other) const + { + /* If signature values are not equal, sort by lexicographic ordering of that */ + if(this->signature() != other.signature()) + { + return (this->signature() < other.signature()); + } + + // Then compare the signed contents + return this->signed_body() < other.signed_body(); + } + +/* +* X.509 Certificate Comparison +*/ +bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2) + { + return !(cert1 == cert2); + } + +std::string X509_Certificate::to_string() const + { + std::ostringstream out; + + out << "Version: " << this->x509_version() << "\n"; + out << "Subject: " << subject_dn() << "\n"; + out << "Issuer: " << issuer_dn() << "\n"; + out << "Issued: " << this->not_before().readable_string() << "\n"; + out << "Expires: " << this->not_after().readable_string() << "\n"; + + out << "Constraints:\n"; + Key_Constraints constraints = this->constraints(); + if(constraints == NO_CONSTRAINTS) + out << " None\n"; + else + { + if(constraints & DIGITAL_SIGNATURE) + out << " Digital Signature\n"; + if(constraints & NON_REPUDIATION) + out << " Non-Repudiation\n"; + if(constraints & KEY_ENCIPHERMENT) + out << " Key Encipherment\n"; + if(constraints & DATA_ENCIPHERMENT) + out << " Data Encipherment\n"; + if(constraints & KEY_AGREEMENT) + out << " Key Agreement\n"; + if(constraints & KEY_CERT_SIGN) + out << " Cert Sign\n"; + if(constraints & CRL_SIGN) + out << " CRL Sign\n"; + if(constraints & ENCIPHER_ONLY) + out << " Encipher Only\n"; + if(constraints & DECIPHER_ONLY) + out << " Decipher Only\n"; + } + + const std::vector& policies = this->certificate_policy_oids(); + if(!policies.empty()) + { + out << "Policies: " << "\n"; + for(auto oid : policies) + out << " " << oid.to_string() << "\n"; + } + + const std::vector& ex_constraints = this->extended_key_usage(); + if(!ex_constraints.empty()) + { + out << "Extended Constraints:\n"; + for(auto&& oid : ex_constraints) + { + out << " " << oid.to_formatted_string() << "\n"; + } + } + + const NameConstraints& name_constraints = this->name_constraints(); + + if(!name_constraints.permitted().empty() || !name_constraints.excluded().empty()) + { + out << "Name Constraints:\n"; + + if(!name_constraints.permitted().empty()) + { + out << " Permit"; + for(auto st: name_constraints.permitted()) + { + out << " " << st.base(); + } + out << "\n"; + } + + if(!name_constraints.excluded().empty()) + { + out << " Exclude"; + for(auto st: name_constraints.excluded()) + { + out << " " << st.base(); + } + out << "\n"; + } + } + + if(!ocsp_responder().empty()) + out << "OCSP responder " << ocsp_responder() << "\n"; + + const std::vector ca_issuers = this->ca_issuers(); + if(!ca_issuers.empty()) + { + out << "CA Issuers:\n"; + for(size_t i = 0; i != ca_issuers.size(); i++) + out << " URI: " << ca_issuers[i] << "\n"; + } + + if(!crl_distribution_point().empty()) + out << "CRL " << crl_distribution_point() << "\n"; + + out << "Signature algorithm: " << this->signature_algorithm().get_oid().to_formatted_string() << "\n"; + + out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; + + if(this->authority_key_id().size()) + out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; + + if(this->subject_key_id().size()) + out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; + + try + { + std::unique_ptr pubkey(this->subject_public_key()); + out << "Public Key [" << pubkey->algo_name() << "-" << pubkey->key_length() << "]\n\n"; + out << X509::PEM_encode(*pubkey); + } + catch(Decoding_Error&) + { + const AlgorithmIdentifier& alg_id = this->subject_public_key_algo(); + out << "Failed to decode key with oid " << alg_id.get_oid().to_string() << "\n"; + } + + return out.str(); + } + +} diff --git a/comm/third_party/botan/src/lib/x509/x509cert.h b/comm/third_party/botan/src/lib/x509/x509cert.h new file mode 100644 index 0000000000..0355bbb58e --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509cert.h @@ -0,0 +1,461 @@ +/* +* X.509 Certificates +* (C) 1999-2007,2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CERTS_H_ +#define BOTAN_X509_CERTS_H_ + +#include +#include + +namespace Botan { + +class Public_Key; +class X509_DN; +class Extensions; +class AlternativeName; +class NameConstraints; + +enum class Usage_Type + { + UNSPECIFIED, // no restrictions + TLS_SERVER_AUTH, + TLS_CLIENT_AUTH, + CERTIFICATE_AUTHORITY, + OCSP_RESPONDER, + ENCRYPTION + }; + +struct X509_Certificate_Data; + +/** +* This class represents an X.509 Certificate +*/ +class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object + { + public: + /** + * Return a newly allocated copy of the public key associated + * with the subject of this certificate. This object is owned + * by the caller. + * + * Prefer load_subject_public_key in new code + * + * @return public key + */ + Public_Key* subject_public_key() const; + + /** + * Create a public key object associated with the public key bits in this + * certificate. If the public key bits was valid for X.509 encoding + * purposes but invalid algorithmically (for example, RSA with an even + * modulus) that will be detected at this point, and an exception will be + * thrown. + * + * @return subject public key of this certificate + */ + std::unique_ptr load_subject_public_key() const; + + /** + * Get the public key associated with this certificate. This includes the + * outer AlgorithmIdentifier + * @return subject public key of this certificate + */ + const std::vector& subject_public_key_bits() const; + + /** + * Get the SubjectPublicKeyInfo associated with this certificate. + * @return subject public key info of this certificate + */ + const std::vector& subject_public_key_info() const; + + /** + * Return the algorithm identifier of the public key + */ + const AlgorithmIdentifier& subject_public_key_algo() const; + + /** + * Get the bit string of the public key associated with this certificate + * @return public key bits + */ + const std::vector& subject_public_key_bitstring() const; + + /** + * Get the SHA-1 bit string of the public key associated with this certificate. + * This is used for OCSP among other protocols. + * This function will throw if SHA-1 is not available. + * @return hash of subject public key of this certificate + */ + const std::vector& subject_public_key_bitstring_sha1() const; + + /** + * Get the certificate's issuer distinguished name (DN). + * @return issuer DN of this certificate + */ + const X509_DN& issuer_dn() const; + + /** + * Get the certificate's subject distinguished name (DN). + * @return subject DN of this certificate + */ + const X509_DN& subject_dn() const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the parameter to look up. Possible names include + * "X509.Certificate.version", "X509.Certificate.serial", + * "X509.Certificate.start", "X509.Certificate.end", + * "X509.Certificate.v2.key_id", "X509.Certificate.public_key", + * "X509v3.BasicConstraints.path_constraint", + * "X509v3.BasicConstraints.is_ca", "X509v3.NameConstraints", + * "X509v3.ExtendedKeyUsage", "X509v3.CertificatePolicies", + * "X509v3.SubjectKeyIdentifier", "X509.Certificate.serial", + * "X520.CommonName", "X520.Organization", "X520.Country", + * "RFC822" (Email in SAN) or "PKCS9.EmailAddress" (Email in DN). + * @return value(s) of the specified parameter + */ + std::vector subject_info(const std::string& name) const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the parameter to look up. Possible names are + * "X509.Certificate.v2.key_id" or "X509v3.AuthorityKeyIdentifier". + * @return value(s) of the specified parameter + */ + std::vector issuer_info(const std::string& name) const; + + /** + * Raw issuer DN bits + */ + const std::vector& raw_issuer_dn() const; + + /** + * SHA-256 of Raw issuer DN + */ + std::vector raw_issuer_dn_sha256() const; + + /** + * Raw subject DN + */ + const std::vector& raw_subject_dn() const; + + /** + * SHA-256 of Raw subject DN + */ + std::vector raw_subject_dn_sha256() const; + + /** + * Get the notBefore of the certificate as a string + * @return notBefore of the certificate + */ + std::string BOTAN_DEPRECATED("Use not_before().to_string()") start_time() const + { + return not_before().to_string(); + } + + /** + * Get the notAfter of the certificate as a string + * @return notAfter of the certificate + */ + std::string BOTAN_DEPRECATED("Use not_after().to_string()") end_time() const + { + return not_after().to_string(); + } + + /** + * Get the notBefore of the certificate as X509_Time + * @return notBefore of the certificate + */ + const X509_Time& not_before() const; + + /** + * Get the notAfter of the certificate as X509_Time + * @return notAfter of the certificate + */ + const X509_Time& not_after() const; + + /** + * Get the X509 version of this certificate object. + * @return X509 version + */ + uint32_t x509_version() const; + + /** + * Get the serial number of this certificate. + * @return certificates serial number + */ + const std::vector& serial_number() const; + + /** + * Get the serial number's sign + * @return 1 iff the serial is negative. + */ + bool is_serial_negative() const; + + /** + * Get the DER encoded AuthorityKeyIdentifier of this certificate. + * @return DER encoded AuthorityKeyIdentifier + */ + const std::vector& authority_key_id() const; + + /** + * Get the DER encoded SubjectKeyIdentifier of this certificate. + * @return DER encoded SubjectKeyIdentifier + */ + const std::vector& subject_key_id() const; + + /** + * Check whether this certificate is self signed. + * If the DN issuer and subject agree, + * @return true if this certificate is self signed + */ + bool is_self_signed() const; + + /** + * Check whether this certificate is a CA certificate. + * @return true if this certificate is a CA certificate + */ + bool is_CA_cert() const; + + /** + * Returns true if the specified @param usage is set in the key usage extension + * or if no key usage constraints are set at all. + * To check if a certain key constraint is set in the certificate + * use @see X509_Certificate#has_constraints. + */ + bool allowed_usage(Key_Constraints usage) const; + + /** + * Returns true if the specified @param usage is set in the extended key usage extension + * or if no extended key usage constraints are set at all. + * To check if a certain extended key constraint is set in the certificate + * use @see X509_Certificate#has_ex_constraint. + */ + bool allowed_extended_usage(const std::string& usage) const; + + /** + * Returns true if the specified usage is set in the extended key usage extension, + * or if no extended key usage constraints are set at all. + * To check if a certain extended key constraint is set in the certificate + * use @see X509_Certificate#has_ex_constraint. + */ + bool allowed_extended_usage(const OID& usage) const; + + /** + * Returns true if the required key and extended key constraints are set in the certificate + * for the specified @param usage or if no key constraints are set in both the key usage + * and extended key usage extension. + */ + bool allowed_usage(Usage_Type usage) const; + + /** + * Returns true if the specified @param constraints are included in the key + * usage extension. + */ + bool has_constraints(Key_Constraints constraints) const; + + /** + * Returns true if and only if @param ex_constraint (referring to an + * extended key constraint, eg "PKIX.ServerAuth") is included in the + * extended key extension. + */ + bool BOTAN_DEPRECATED("Use version taking an OID") + has_ex_constraint(const std::string& ex_constraint) const; + + /** + * Returns true if and only if OID @param ex_constraint is + * included in the extended key extension. + */ + bool has_ex_constraint(const OID& ex_constraint) const; + + /** + * Get the path limit as defined in the BasicConstraints extension of + * this certificate. + * @return path limit + */ + uint32_t path_limit() const; + + /** + * Check whenever a given X509 Extension is marked critical in this + * certificate. + */ + bool is_critical(const std::string& ex_name) const; + + /** + * Get the key constraints as defined in the KeyUsage extension of this + * certificate. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the key constraints as defined in the ExtendedKeyUsage + * extension of this certificate. + * @return key constraints + */ + std::vector + BOTAN_DEPRECATED("Use extended_key_usage") ex_constraints() const; + + /** + * Get the key usage as defined in the ExtendedKeyUsage extension + * of this certificate, or else an empty vector. + * @return key usage + */ + const std::vector& extended_key_usage() const; + + /** + * Get the name constraints as defined in the NameConstraints + * extension of this certificate. + * @return name constraints + */ + const NameConstraints& name_constraints() const; + + /** + * Get the policies as defined in the CertificatePolicies extension + * of this certificate. + * @return certificate policies + */ + std::vector BOTAN_DEPRECATED("Use certificate_policy_oids") policies() const; + + const std::vector& certificate_policy_oids() const; + + /** + * Get all extensions of this certificate. + * @return certificate extensions + */ + const Extensions& v3_extensions() const; + + /** + * Return the v2 issuer key ID. v2 key IDs are almost never used, + * instead see v3_subject_key_id. + */ + const std::vector& v2_issuer_key_id() const; + + /** + * Return the v2 subject key ID. v2 key IDs are almost never used, + * instead see v3_subject_key_id. + */ + const std::vector& v2_subject_key_id() const; + + /** + * Return the subject alternative names (DNS, IP, ...) + */ + const AlternativeName& subject_alt_name() const; + + /** + * Return the issuer alternative names (DNS, IP, ...) + */ + const AlternativeName& issuer_alt_name() const; + + /** + * Return the listed address of an OCSP responder, or empty if not set + */ + std::string ocsp_responder() const; + + /** + * Return the listed addresses of ca issuers, or empty if not set + */ + std::vector ca_issuers() const; + + /** + * Return the CRL distribution point, or empty if not set + */ + std::string crl_distribution_point() const; + + /** + * @return a free-form string describing the certificate + */ + std::string to_string() const; + + /** + * @return a fingerprint of the certificate + * @param hash_name hash function used to calculate the fingerprint + */ + std::string fingerprint(const std::string& hash_name = "SHA-1") const; + + /** + * Check if a certain DNS name matches up with the information in + * the cert + * @param name DNS name to match + */ + bool matches_dns_name(const std::string& name) const; + + /** + * Check to certificates for equality. + * @return true both certificates are (binary) equal + */ + bool operator==(const X509_Certificate& other) const; + + /** + * Impose an arbitrary (but consistent) ordering, eg to allow sorting + * a container of certificate objects. + * @return true if this is less than other by some unspecified criteria + */ + bool operator<(const X509_Certificate& other) const; + + /** + * Create a certificate from a data source providing the DER or + * PEM encoded certificate. + * @param source the data source + */ + explicit X509_Certificate(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Create a certificate from a file containing the DER or PEM + * encoded certificate. + * @param filename the name of the certificate file + */ + explicit X509_Certificate(const std::string& filename); +#endif + + /** + * Create a certificate from a buffer + * @param in the buffer containing the DER-encoded certificate + */ + explicit X509_Certificate(const std::vector& in); + + /** + * Create a certificate from a buffer + * @param data the buffer containing the DER-encoded certificate + * @param length length of data in bytes + */ + X509_Certificate(const uint8_t data[], size_t length); + + /** + * Create an uninitialized certificate object. Any attempts to + * access this object will throw an exception. + */ + X509_Certificate() = default; + + X509_Certificate(const X509_Certificate& other) = default; + + X509_Certificate& operator=(const X509_Certificate& other) = default; + + private: + std::string PEM_label() const override; + + std::vector alternate_PEM_labels() const override; + + void force_decode() override; + + const X509_Certificate_Data& data() const; + + std::shared_ptr m_data; + }; + +/** +* Check two certificates for inequality +* @param cert1 The first certificate +* @param cert2 The second certificate +* @return true if the arguments represent different certificates, +* false if they are binary identical +*/ +BOTAN_PUBLIC_API(2,0) bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2); + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509opt.cpp b/comm/third_party/botan/src/lib/x509/x509opt.cpp new file mode 100644 index 0000000000..f762acd7b7 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509opt.cpp @@ -0,0 +1,100 @@ +/* +* X.509 Certificate Options +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Set when the certificate should become valid +*/ +void X509_Cert_Options::not_before(const std::string& time_string) + { + start = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME); + } + +/* +* Set when the certificate should expire +*/ +void X509_Cert_Options::not_after(const std::string& time_string) + { + end = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_constraints(Key_Constraints usage) + { + constraints = usage; + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const OID& oid) + { + ex_constraints.push_back(oid); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const std::string& oid_str) + { + ex_constraints.push_back(OID::from_string(oid_str)); + } + +/* +* Mark this certificate for CA usage +*/ +void X509_Cert_Options::CA_key(size_t limit) + { + is_CA = true; + path_limit = limit; + } + +void X509_Cert_Options::set_padding_scheme(const std::string& scheme) + { + padding_scheme = scheme; + } + +/* +* Initialize the certificate options +*/ +X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, + uint32_t expiration_time) + { + is_CA = false; + path_limit = 0; + constraints = NO_CONSTRAINTS; + // use default for chosen algorithm + padding_scheme = ""; + + auto now = std::chrono::system_clock::now(); + + start = X509_Time(now); + end = X509_Time(now + std::chrono::seconds(expiration_time)); + + if(initial_opts.empty()) + return; + + std::vector parsed = split_on(initial_opts, '/'); + + if(parsed.size() > 4) + throw Invalid_Argument("X.509 cert options: Too many names: " + + initial_opts); + + if(parsed.size() >= 1) common_name = parsed[0]; + if(parsed.size() >= 2) country = parsed[1]; + if(parsed.size() >= 3) organization = parsed[2]; + if(parsed.size() == 4) org_unit = parsed[3]; + } + +} diff --git a/comm/third_party/botan/src/lib/x509/x509path.cpp b/comm/third_party/botan/src/lib/x509/x509path.cpp new file mode 100644 index 0000000000..b5cdc27c2d --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509path.cpp @@ -0,0 +1,1088 @@ +/* +* X.509 Certificate Path Validation +* (C) 2010,2011,2012,2014,2016 Jack Lloyd +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + #include + #include +#endif + +namespace Botan { + +/* +* PKIX path validation +*/ +CertificatePathStatusCodes +PKIX::check_chain(const std::vector>& cert_path, + std::chrono::system_clock::time_point ref_time, + const std::string& hostname, + Usage_Type usage, + size_t min_signature_algo_strength, + const std::set& trusted_hashes) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_chain cert_path empty"); + + const bool self_signed_ee_cert = (cert_path.size() == 1); + + X509_Time validation_time(ref_time); + + CertificatePathStatusCodes cert_status(cert_path.size()); + + if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname)) + cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH); + + if(!cert_path[0]->allowed_usage(usage)) + cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); + + if(cert_path[0]->is_CA_cert() == false && + cert_path[0]->has_constraints(KEY_CERT_SIGN)) + { + /* + "If the keyCertSign bit is asserted, then the cA bit in the + basic constraints extension (Section 4.2.1.9) MUST also be + asserted." - RFC 5280 + + We don't bother doing this check on the rest of the path since they + must have the cA bit asserted or the validation will fail anyway. + */ + cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); + } + + for(size_t i = 0; i != cert_path.size(); ++i) + { + std::set& status = cert_status.at(i); + + const bool at_self_signed_root = (i == cert_path.size() - 1); + + const std::shared_ptr& subject = cert_path[i]; + + const std::shared_ptr& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; + + if(at_self_signed_root && (issuer->is_self_signed() == false)) + { + status.insert(Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT); + } + + if(subject->issuer_dn() != issuer->subject_dn()) + { + status.insert(Certificate_Status_Code::CHAIN_NAME_MISMATCH); + } + + // Check the serial number + if(subject->is_serial_negative()) + { + status.insert(Certificate_Status_Code::CERT_SERIAL_NEGATIVE); + } + + // Check the subject's DN components' length + + for(const auto& dn_pair : subject->subject_dn().dn_info()) + { + const size_t dn_ub = X509_DN::lookup_ub(dn_pair.first); + // dn_pair = + if(dn_ub > 0 && dn_pair.second.size() > dn_ub) + { + status.insert(Certificate_Status_Code::DN_TOO_LONG); + } + } + + // Check all certs for valid time range + if(validation_time < subject->not_before()) + status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID); + + if(validation_time > subject->not_after()) + status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED); + + // Check issuer constraints + if(!issuer->is_CA_cert() && !self_signed_ee_cert) + status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER); + + std::unique_ptr issuer_key(issuer->subject_public_key()); + + // Check the signature algorithm is known + if(OIDS::oid2str_or_empty(subject->signature_algorithm().get_oid()).empty()) + { + status.insert(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN); + } + else + { + // only perform the following checks if the signature algorithm is known + if(!issuer_key) + { + status.insert(Certificate_Status_Code::CERT_PUBKEY_INVALID); + } + else + { + const Certificate_Status_Code sig_status = subject->verify_signature(*issuer_key); + + if(sig_status != Certificate_Status_Code::VERIFIED) + status.insert(sig_status); + + if(issuer_key->estimated_strength() < min_signature_algo_strength) + status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK); + } + + // Ignore untrusted hashes on self-signed roots + if(trusted_hashes.size() > 0 && !at_self_signed_root) + { + if(trusted_hashes.count(subject->hash_used_for_signature()) == 0) + status.insert(Certificate_Status_Code::UNTRUSTED_HASH); + } + } + + // Check cert extensions + + if(subject->x509_version() == 1) + { + if(subject->v2_issuer_key_id().empty() == false || + subject->v2_subject_key_id().empty() == false) + { + status.insert(Certificate_Status_Code::V2_IDENTIFIERS_IN_V1_CERT); + } + } + + Extensions extensions = subject->v3_extensions(); + const auto& extensions_vec = extensions.extensions(); + if(subject->x509_version() < 3 && !extensions_vec.empty()) + { + status.insert(Certificate_Status_Code::EXT_IN_V1_V2_CERT); + } + for(auto& extension : extensions_vec) + { + extension.first->validate(*subject, *issuer, cert_path, cert_status, i); + } + if(extensions.extensions().size() != extensions.get_extension_oids().size()) + { + status.insert(Certificate_Status_Code::DUPLICATE_CERT_EXTENSION); + } + } + + // path len check + size_t max_path_length = cert_path.size(); + for(size_t i = cert_path.size() - 1; i > 0 ; --i) + { + std::set& status = cert_status.at(i); + const std::shared_ptr& subject = cert_path[i]; + + /* + * If the certificate was not self-issued, verify that max_path_length is + * greater than zero and decrement max_path_length by 1. + */ + if(subject->subject_dn() != subject->issuer_dn()) + { + if(max_path_length > 0) + { + --max_path_length; + } + else + { + status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG); + } + } + + /* + * If pathLenConstraint is present in the certificate and is less than max_path_length, + * set max_path_length to the value of pathLenConstraint. + */ + if(subject->path_limit() != Cert_Extension::NO_CERT_PATH_LIMIT && subject->path_limit() < max_path_length) + { + max_path_length = subject->path_limit(); + } + } + + return cert_status; + } + +CertificatePathStatusCodes +PKIX::check_ocsp(const std::vector>& cert_path, + const std::vector>& ocsp_responses, + const std::vector& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::seconds max_ocsp_age) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_ocsp cert_path empty"); + + CertificatePathStatusCodes cert_status(cert_path.size() - 1); + + for(size_t i = 0; i != cert_path.size() - 1; ++i) + { + std::set& status = cert_status.at(i); + + std::shared_ptr subject = cert_path.at(i); + std::shared_ptr ca = cert_path.at(i+1); + + if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr) + && (ocsp_responses.at(i)->status() == OCSP::Response_Status_Code::Successful)) + { + try + { + Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, cert_path); + + if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK) + { + // Signature ok, so check the claimed status + Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time, max_ocsp_age); + status.insert(ocsp_status); + } + else + { + // Some signature problem + status.insert(ocsp_signature_status); + } + } + catch(Exception&) + { + status.insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID); + } + } + } + + while(cert_status.size() > 0 && cert_status.back().empty()) + cert_status.pop_back(); + + return cert_status; + } + +CertificatePathStatusCodes +PKIX::check_crl(const std::vector>& cert_path, + const std::vector>& crls, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl cert_path empty"); + + CertificatePathStatusCodes cert_status(cert_path.size()); + const X509_Time validation_time(ref_time); + + for(size_t i = 0; i != cert_path.size() - 1; ++i) + { + std::set& status = cert_status.at(i); + + if(i < crls.size() && crls.at(i)) + { + std::shared_ptr subject = cert_path.at(i); + std::shared_ptr ca = cert_path.at(i+1); + + if(!ca->allowed_usage(CRL_SIGN)) + status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER); + + if(validation_time < crls[i]->this_update()) + status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID); + + if(validation_time > crls[i]->next_update()) + status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED); + + if(crls[i]->check_signature(ca->subject_public_key()) == false) + status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE); + + status.insert(Certificate_Status_Code::VALID_CRL_CHECKED); + + if(crls[i]->is_revoked(*subject)) + status.insert(Certificate_Status_Code::CERT_IS_REVOKED); + + std::string dp = subject->crl_distribution_point(); + if(!dp.empty()) + { + if(dp != crls[i]->crl_issuing_distribution_point()) + { + status.insert(Certificate_Status_Code::NO_MATCHING_CRLDP); + } + } + + for(const auto& extension : crls[i]->extensions().extensions()) + { + // XXX this is wrong - the OID might be defined but the extention not full parsed + // for example see #1652 + + // is the extension critical and unknown? + if(extension.second && OIDS::oid2str_or_empty(extension.first->oid_of()) == "") + { + /* NIST Certificate Path Valiadation Testing document: "When an implementation does not recognize a critical extension in the + * crlExtensions field, it shall assume that identified certificates have been revoked and are no longer valid" + */ + status.insert(Certificate_Status_Code::CERT_IS_REVOKED); + } + } + + } + } + + while(cert_status.size() > 0 && cert_status.back().empty()) + cert_status.pop_back(); + + return cert_status; + } + +CertificatePathStatusCodes +PKIX::check_crl(const std::vector>& cert_path, + const std::vector& certstores, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl cert_path empty"); + + if(certstores.empty()) + throw Invalid_Argument("PKIX::check_crl certstores empty"); + + std::vector> crls(cert_path.size()); + + for(size_t i = 0; i != cert_path.size(); ++i) + { + BOTAN_ASSERT_NONNULL(cert_path[i]); + for(size_t c = 0; c != certstores.size(); ++c) + { + crls[i] = certstores[c]->find_crl_for(*cert_path[i]); + if(crls[i]) + break; + } + } + + return PKIX::check_crl(cert_path, crls, ref_time); + } + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + +CertificatePathStatusCodes +PKIX::check_ocsp_online(const std::vector>& cert_path, + const std::vector& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout, + bool ocsp_check_intermediate_CAs, + std::chrono::seconds max_ocsp_age) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty"); + + std::vector>> ocsp_response_futures; + + size_t to_ocsp = 1; + + if(ocsp_check_intermediate_CAs) + to_ocsp = cert_path.size() - 1; + if(cert_path.size() == 1) + to_ocsp = 0; + + for(size_t i = 0; i < to_ocsp; ++i) + { + const std::shared_ptr& subject = cert_path.at(i); + const std::shared_ptr& issuer = cert_path.at(i+1); + + if(subject->ocsp_responder() == "") + { + ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr { + return std::make_shared(Certificate_Status_Code::OCSP_NO_REVOCATION_URL); + })); + } + else + { + ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr { + OCSP::Request req(*issuer, BigInt::decode(subject->serial_number())); + + HTTP::Response http; + try + { + http = HTTP::POST_sync(subject->ocsp_responder(), + "application/ocsp-request", + req.BER_encode(), + /*redirects*/1, + timeout); + } + catch(std::exception&) + { + // log e.what() ? + } + if (http.status_code() != 200) + return std::make_shared(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE); + // Check the MIME type? + + return std::make_shared(http.body()); + })); + } + } + + std::vector> ocsp_responses; + + for(size_t i = 0; i < ocsp_response_futures.size(); ++i) + { + ocsp_responses.push_back(ocsp_response_futures[i].get()); + } + + return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time, max_ocsp_age); + } + +CertificatePathStatusCodes +PKIX::check_crl_online(const std::vector>& cert_path, + const std::vector& certstores, + Certificate_Store_In_Memory* crl_store, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl_online cert_path empty"); + if(certstores.empty()) + throw Invalid_Argument("PKIX::check_crl_online certstores empty"); + + std::vector>> future_crls; + std::vector> crls(cert_path.size()); + + for(size_t i = 0; i != cert_path.size(); ++i) + { + const std::shared_ptr& cert = cert_path.at(i); + for(size_t c = 0; c != certstores.size(); ++c) + { + crls[i] = certstores[c]->find_crl_for(*cert); + if(crls[i]) + break; + } + + // TODO: check if CRL is expired and re-request? + + // Only request if we don't already have a CRL + if(crls[i]) + { + /* + We already have a CRL, so just insert this empty one to hold a place in the vector + so that indexes match up + */ + future_crls.emplace_back(std::future>()); + } + else if(cert->crl_distribution_point() == "") + { + // Avoid creating a thread for this case + future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr { + throw Not_Implemented("No CRL distribution point for this certificate"); + })); + } + else + { + future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr { + auto http = HTTP::GET_sync(cert->crl_distribution_point(), + /*redirects*/ 1, timeout); + + http.throw_unless_ok(); + // check the mime type? + return std::make_shared(http.body()); + })); + } + } + + for(size_t i = 0; i != future_crls.size(); ++i) + { + if(future_crls[i].valid()) + { + try + { + crls[i] = future_crls[i].get(); + } + catch(std::exception&) + { + // crls[i] left null + // todo: log exception e.what() ? + } + } + } + + const CertificatePathStatusCodes crl_status = PKIX::check_crl(cert_path, crls, ref_time); + + if(crl_store) + { + for(size_t i = 0; i != crl_status.size(); ++i) + { + if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED)) + { + // better be non-null, we supposedly validated it + BOTAN_ASSERT_NONNULL(crls[i]); + crl_store->add_crl(crls[i]); + } + } + } + + return crl_status; + } + +#endif + +Certificate_Status_Code +PKIX::build_certificate_path(std::vector>& cert_path, + const std::vector& trusted_certstores, + const std::shared_ptr& end_entity, + const std::vector>& end_entity_extra) + { + if(end_entity->is_self_signed()) + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + + /* + * This is an inelegant but functional way of preventing path loops + * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate + * fingerprints in the path. If there is a duplicate, we error out. + * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. + */ + std::set certs_seen; + + cert_path.push_back(end_entity); + certs_seen.insert(end_entity->fingerprint("SHA-256")); + + Certificate_Store_In_Memory ee_extras; + for(size_t i = 0; i != end_entity_extra.size(); ++i) + ee_extras.add_certificate(end_entity_extra[i]); + + // iterate until we reach a root or cannot find the issuer + for(;;) + { + const X509_Certificate& last = *cert_path.back(); + const X509_DN issuer_dn = last.issuer_dn(); + const std::vector auth_key_id = last.authority_key_id(); + + std::shared_ptr issuer; + bool trusted_issuer = false; + + for(Certificate_Store* store : trusted_certstores) + { + issuer = store->find_cert(issuer_dn, auth_key_id); + if(issuer) + { + trusted_issuer = true; + break; + } + } + + if(!issuer) + { + // fall back to searching supplemental certs + issuer = ee_extras.find_cert(issuer_dn, auth_key_id); + } + + if(!issuer) + return Certificate_Status_Code::CERT_ISSUER_NOT_FOUND; + + const std::string fprint = issuer->fingerprint("SHA-256"); + + if(certs_seen.count(fprint) > 0) // already seen? + { + return Certificate_Status_Code::CERT_CHAIN_LOOP; + } + + certs_seen.insert(fprint); + cert_path.push_back(issuer); + + if(issuer->is_self_signed()) + { + if(trusted_issuer) + { + return Certificate_Status_Code::OK; + } + else + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + } + } + } + +/** + * utilities for PKIX::build_all_certificate_paths + */ +namespace +{ +// +using cert_maybe_trusted = std::pair,bool>; +} + +/** + * Build all possible certificate paths from the end certificate to self-signed trusted roots. + * + * All potentially valid paths are put into the cert_paths vector. If no potentially valid paths are found, + * one of the encountered errors is returned arbitrarily. + * + * todo add a path building function that returns detailed information on errors encountered while building + * the potentially numerous path candidates. + * + * Basically, a DFS is performed starting from the end certificate. A stack (vector) serves to control the DFS. + * At the beginning of each iteration, a pair is popped from the stack that contains (1) the next certificate + * to add to the path (2) a bool that indicates if the certificate is part of a trusted certstore. Ideally, we + * follow the unique issuer of the current certificate until a trusted root is reached. However, the issuer DN + + * authority key id need not be unique among the certificates used for building the path. In such a case, + * we consider all the matching issuers by pushing on the stack for each of them. + * + */ +Certificate_Status_Code +PKIX::build_all_certificate_paths(std::vector>>& cert_paths_out, + const std::vector& trusted_certstores, + const std::shared_ptr& end_entity, + const std::vector>& end_entity_extra) + { + if(!cert_paths_out.empty()) + { + throw Invalid_Argument("PKIX::build_all_certificate_paths: cert_paths_out must be empty"); + } + + if(end_entity->is_self_signed()) + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + + /* + * Pile up error messages + */ + std::vector stats; + + Certificate_Store_In_Memory ee_extras; + for(size_t i = 0; i != end_entity_extra.size(); ++i) + { + ee_extras.add_certificate(end_entity_extra[i]); + } + + /* + * This is an inelegant but functional way of preventing path loops + * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate + * fingerprints in the path. If there is a duplicate, we error out. + * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. + */ + std::set certs_seen; + + // new certs are added and removed from the path during the DFS + // it is copied into cert_paths_out when we encounter a trusted root + std::vector> path_so_far; + + // todo can we assume that the end certificate is not trusted? + std::vector stack = { {end_entity, false} }; + + while(!stack.empty()) + { + // found a deletion marker that guides the DFS, backtracing + if(stack.back().first == nullptr) + { + stack.pop_back(); + std::string fprint = path_so_far.back()->fingerprint("SHA-256"); + certs_seen.erase(fprint); + path_so_far.pop_back(); + } + // process next cert on the path + else + { + std::shared_ptr last = stack.back().first; + bool trusted = stack.back().second; + stack.pop_back(); + + // certificate already seen? + const std::string fprint = last->fingerprint("SHA-256"); + if(certs_seen.count(fprint) == 1) + { + stats.push_back(Certificate_Status_Code::CERT_CHAIN_LOOP); + // the current path ended in a loop + continue; + } + + // the current path ends here + if(last->is_self_signed()) + { + // found a trust anchor + if(trusted) + { + cert_paths_out.push_back(path_so_far); + cert_paths_out.back().push_back(last); + + continue; + } + // found an untrustworthy root + else + { + stats.push_back(Certificate_Status_Code::CANNOT_ESTABLISH_TRUST); + continue; + } + } + + const X509_DN issuer_dn = last->issuer_dn(); + const std::vector auth_key_id = last->authority_key_id(); + + // search for trusted issuers + std::vector> trusted_issuers; + for(Certificate_Store* store : trusted_certstores) + { + auto new_issuers = store->find_all_certs(issuer_dn, auth_key_id); + trusted_issuers.insert(trusted_issuers.end(), new_issuers.begin(), new_issuers.end()); + } + + // search the supplemental certs + std::vector> misc_issuers = + ee_extras.find_all_certs(issuer_dn, auth_key_id); + + // if we could not find any issuers, the current path ends here + if(trusted_issuers.size() + misc_issuers.size() == 0) + { + stats.push_back(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND); + continue; + } + + // push the latest certificate onto the path_so_far + path_so_far.push_back(last); + certs_seen.emplace(fprint); + + // push a deletion marker on the stack for backtracing later + stack.push_back({std::shared_ptr(nullptr),false}); + + for(const auto& trusted_cert : trusted_issuers) + { + stack.push_back({trusted_cert,true}); + } + + for(const auto& misc : misc_issuers) + { + stack.push_back({misc,false}); + } + } + } + + // could not construct any potentially valid path + if(cert_paths_out.empty()) + { + if(stats.empty()) + throw Internal_Error("X509 path building failed for unknown reasons"); + else + // arbitrarily return the first error + return stats[0]; + } + else + { + return Certificate_Status_Code::OK; + } + } + + +void PKIX::merge_revocation_status(CertificatePathStatusCodes& chain_status, + const CertificatePathStatusCodes& crl, + const CertificatePathStatusCodes& ocsp, + bool require_rev_on_end_entity, + bool require_rev_on_intermediates) + { + if(chain_status.empty()) + throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty"); + + for(size_t i = 0; i != chain_status.size() - 1; ++i) + { + bool had_crl = false, had_ocsp = false; + + if(i < crl.size() && crl[i].size() > 0) + { + for(auto&& code : crl[i]) + { + if(code == Certificate_Status_Code::VALID_CRL_CHECKED) + { + had_crl = true; + } + chain_status[i].insert(code); + } + } + + if(i < ocsp.size() && ocsp[i].size() > 0) + { + for(auto&& code : ocsp[i]) + { + if(code == Certificate_Status_Code::OCSP_RESPONSE_GOOD || + code == Certificate_Status_Code::OCSP_NO_REVOCATION_URL || // softfail + code == Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE) // softfail + { + had_ocsp = true; + } + + chain_status[i].insert(code); + } + } + + if(had_crl == false && had_ocsp == false) + { + if((require_rev_on_end_entity && i == 0) || + (require_rev_on_intermediates && i > 0)) + { + chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA); + } + } + } + } + +Certificate_Status_Code PKIX::overall_status(const CertificatePathStatusCodes& cert_status) + { + if(cert_status.empty()) + throw Invalid_Argument("PKIX::overall_status empty cert status"); + + Certificate_Status_Code overall_status = Certificate_Status_Code::OK; + + // take the "worst" error as overall + for(const std::set& s : cert_status) + { + if(!s.empty()) + { + auto worst = *s.rbegin(); + // Leave informative OCSP/CRL confirmations on cert-level status only + if(worst >= Certificate_Status_Code::FIRST_ERROR_STATUS && worst > overall_status) + { + overall_status = worst; + } + } + } + return overall_status; + } + +Path_Validation_Result x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector& trusted_roots, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds ocsp_timeout, + const std::vector>& ocsp_resp) + { + if(end_certs.empty()) + { + throw Invalid_Argument("x509_path_validate called with no subjects"); + } + + std::shared_ptr end_entity(std::make_shared(end_certs[0])); + std::vector> end_entity_extra; + for(size_t i = 1; i < end_certs.size(); ++i) + { + end_entity_extra.push_back(std::make_shared(end_certs[i])); + } + + std::vector>> cert_paths; + Certificate_Status_Code path_building_result = PKIX::build_all_certificate_paths(cert_paths, trusted_roots, end_entity, end_entity_extra); + + // If we cannot successfully build a chain to a trusted self-signed root, stop now + if(path_building_result != Certificate_Status_Code::OK) + { + return Path_Validation_Result(path_building_result); + } + + std::vector error_results; + // Try validating all the potentially valid paths and return the first one to validate properly + for(auto cert_path : cert_paths) + { + CertificatePathStatusCodes status = + PKIX::check_chain(cert_path, ref_time, + hostname, usage, + restrictions.minimum_key_strength(), + restrictions.trusted_hashes()); + + CertificatePathStatusCodes crl_status = + PKIX::check_crl(cert_path, trusted_roots, ref_time); + + CertificatePathStatusCodes ocsp_status; + + if(ocsp_resp.size() > 0) + { + ocsp_status = PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time, restrictions.max_ocsp_age()); + } + + if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0)) + { +#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) + ocsp_status = PKIX::check_ocsp_online(cert_path, trusted_roots, ref_time, + ocsp_timeout, restrictions.ocsp_all_intermediates()); +#else + ocsp_status.resize(1); + ocsp_status[0].insert(Certificate_Status_Code::OCSP_NO_HTTP); +#endif + } + + PKIX::merge_revocation_status(status, crl_status, ocsp_status, + restrictions.require_revocation_information(), + restrictions.ocsp_all_intermediates()); + + Path_Validation_Result pvd(status, std::move(cert_path)); + if(pvd.successful_validation()) + { + return pvd; + } + else + { + error_results.push_back(std::move(pvd)); + } + } + return error_results[0]; + } + +Path_Validation_Result x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const std::vector& trusted_roots, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector>& ocsp_resp) + { + std::vector certs; + certs.push_back(end_cert); + return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); + } + +Path_Validation_Result x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector>& ocsp_resp) + { + std::vector trusted_roots; + trusted_roots.push_back(const_cast(&store)); + + return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); + } + +Path_Validation_Result x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector>& ocsp_resp) + { + std::vector certs; + certs.push_back(end_cert); + + std::vector trusted_roots; + trusted_roots.push_back(const_cast(&store)); + + return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); + } + +Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, + size_t key_strength, + bool ocsp_intermediates, + std::chrono::seconds max_ocsp_age) : + m_require_revocation_information(require_rev), + m_ocsp_all_intermediates(ocsp_intermediates), + m_minimum_key_strength(key_strength), + m_max_ocsp_age(max_ocsp_age) + { + if(key_strength <= 80) + { m_trusted_hashes.insert("SHA-160"); } + + m_trusted_hashes.insert("SHA-224"); + m_trusted_hashes.insert("SHA-256"); + m_trusted_hashes.insert("SHA-384"); + m_trusted_hashes.insert("SHA-512"); + } + +namespace { +CertificatePathStatusCodes find_warnings(const CertificatePathStatusCodes& all_statuses) + { + CertificatePathStatusCodes warnings; + for(const auto& status_set_i : all_statuses) + { + std::set warning_set_i; + for(const auto& code : status_set_i) + { + if(code >= Certificate_Status_Code::FIRST_WARNING_STATUS && + code < Certificate_Status_Code::FIRST_ERROR_STATUS) + { + warning_set_i.insert(code); + } + } + warnings.push_back(warning_set_i); + } + return warnings; + } +} + +Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status, + std::vector>&& cert_chain) : + m_all_status(status), + m_warnings(find_warnings(m_all_status)), + m_cert_path(cert_chain), + m_overall(PKIX::overall_status(m_all_status)) + { + } + +const X509_Certificate& Path_Validation_Result::trust_root() const + { + if(m_cert_path.empty()) + throw Invalid_State("Path_Validation_Result::trust_root no path set"); + if(result() != Certificate_Status_Code::VERIFIED) + throw Invalid_State("Path_Validation_Result::trust_root meaningless with invalid status"); + + return *m_cert_path[m_cert_path.size()-1]; + } + +std::set Path_Validation_Result::trusted_hashes() const + { + std::set hashes; + for(size_t i = 0; i != m_cert_path.size(); ++i) + hashes.insert(m_cert_path[i]->hash_used_for_signature()); + return hashes; + } + +bool Path_Validation_Result::successful_validation() const + { + return (result() == Certificate_Status_Code::VERIFIED || + result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD || + result() == Certificate_Status_Code::VALID_CRL_CHECKED); + } + +bool Path_Validation_Result::no_warnings() const + { + for(auto status_set_i : m_warnings) + if(!status_set_i.empty()) + return false; + return true; + } + +CertificatePathStatusCodes Path_Validation_Result::warnings() const + { + return m_warnings; + } + +std::string Path_Validation_Result::result_string() const + { + return status_string(result()); + } + +const char* Path_Validation_Result::status_string(Certificate_Status_Code code) + { + if(const char* s = to_string(code)) + return s; + + return "Unknown error"; + } + +std::string Path_Validation_Result::warnings_string() const + { + const std::string sep(", "); + std::string res; + for(size_t i = 0; i < m_warnings.size(); i++) + { + for(auto code : m_warnings[i]) + res += "[" + std::to_string(i) + "] " + status_string(code) + sep; + } + // remove last sep + if(res.size() >= sep.size()) + res = res.substr(0, res.size() - sep.size()); + return res; + } +} diff --git a/comm/third_party/botan/src/lib/x509/x509path.h b/comm/third_party/botan/src/lib/x509/x509path.h new file mode 100644 index 0000000000..c8575fd32b --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509path.h @@ -0,0 +1,475 @@ +/* +* X.509 Cert Path Validation +* (C) 2010-2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CERT_PATH_VALIDATION_H_ +#define BOTAN_X509_CERT_PATH_VALIDATION_H_ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) + #define BOTAN_HAS_ONLINE_REVOCATION_CHECKS +#endif + +namespace Botan { + +/** +* This type represents the validation status of an entire certificate path. +* There is one set of status codes for each certificate in the path. +*/ +typedef std::vector> CertificatePathStatusCodes; + +/** +* Specifies restrictions on the PKIX path validation +*/ +class BOTAN_PUBLIC_API(2,0) Path_Validation_Restrictions final + { + public: + /** + * @param require_rev if true, revocation information is required + + * @param minimum_key_strength is the minimum strength (in terms of + * operations, eg 80 means 2^80) of a signature. Signatures weaker than + * this are rejected. If more than 80, SHA-1 signatures are also + * rejected. If possible use at least setting 110. + * + * 80 bit strength requires 1024 bit RSA + * 110 bit strength requires 2k bit RSA + * 128 bit strength requires ~3k bit RSA or P-256 + * @param ocsp_all_intermediates Make OCSP requests for all CAs as + * well as end entity (if OCSP enabled in path validation request) + * @param max_ocsp_age maximum age of OCSP responses w/o next_update. + * If zero, there is no maximum age + */ + Path_Validation_Restrictions(bool require_rev = false, + size_t minimum_key_strength = 110, + bool ocsp_all_intermediates = false, + std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero()); + + /** + * @param require_rev if true, revocation information is required + * @param minimum_key_strength is the minimum strength (in terms of + * operations, eg 80 means 2^80) of a signature. Signatures + * weaker than this are rejected. + * @param ocsp_all_intermediates Make OCSP requests for all CAs as + * well as end entity (if OCSP enabled in path validation request) + * @param trusted_hashes a set of trusted hashes. Any signatures + * created using a hash other than one of these will be + * rejected. + * @param max_ocsp_age maximum age of OCSP responses w/o next_update. + * If zero, there is no maximum age + */ + Path_Validation_Restrictions(bool require_rev, + size_t minimum_key_strength, + bool ocsp_all_intermediates, + const std::set& trusted_hashes, + std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero()) : + m_require_revocation_information(require_rev), + m_ocsp_all_intermediates(ocsp_all_intermediates), + m_trusted_hashes(trusted_hashes), + m_minimum_key_strength(minimum_key_strength), + m_max_ocsp_age(max_ocsp_age) {} + + /** + * @return whether revocation information is required + */ + bool require_revocation_information() const + { return m_require_revocation_information; } + + /** + * @return whether all intermediate CAs should also be OCSPed. If false + * then only end entity OCSP is required/requested. + */ + bool ocsp_all_intermediates() const + { return m_ocsp_all_intermediates; } + + /** + * @return trusted signature hash functions + */ + const std::set& trusted_hashes() const + { return m_trusted_hashes; } + + /** + * @return minimum required key strength + */ + size_t minimum_key_strength() const + { return m_minimum_key_strength; } + + /** + * @return maximum age of OCSP responses w/o next_update. + * If zero, there is no maximum age + */ + std::chrono::seconds max_ocsp_age() const + { return m_max_ocsp_age; } + + private: + bool m_require_revocation_information; + bool m_ocsp_all_intermediates; + std::set m_trusted_hashes; + size_t m_minimum_key_strength; + std::chrono::seconds m_max_ocsp_age; + }; + +/** +* Represents the result of a PKIX path validation +*/ +class BOTAN_PUBLIC_API(2,0) Path_Validation_Result final + { + public: + typedef Certificate_Status_Code Code; + + /** + * @return the set of hash functions you are implicitly + * trusting by trusting this result. + */ + std::set trusted_hashes() const; + + /** + * @return the trust root of the validation if successful + * throws an exception if the validation failed + */ + const X509_Certificate& trust_root() const; + + /** + * @return the full path from subject to trust root + * This path may be empty + */ + const std::vector>& cert_path() const { return m_cert_path; } + + /** + * @return true iff the validation was successful + */ + bool successful_validation() const; + + /** + * @return true iff no warnings occured during validation + */ + bool no_warnings() const; + + /** + * @return overall validation result code + */ + Certificate_Status_Code result() const { return m_overall; } + + /** + * @return a set of status codes for each certificate in the chain + */ + const CertificatePathStatusCodes& all_statuses() const + { return m_all_status; } + + /** + * @return the subset of status codes that are warnings + */ + CertificatePathStatusCodes warnings() const; + + /** + * @return string representation of the validation result + */ + std::string result_string() const; + + /** + * @return string representation of the warnings + */ + std::string warnings_string() const; + + /** + * @param code validation status code + * @return corresponding validation status message + */ + static const char* status_string(Certificate_Status_Code code); + + /** + * Create a Path_Validation_Result + * @param status list of validation status codes + * @param cert_chain the certificate chain that was validated + */ + Path_Validation_Result(CertificatePathStatusCodes status, + std::vector>&& cert_chain); + + /** + * Create a Path_Validation_Result + * @param status validation status code + */ + explicit Path_Validation_Result(Certificate_Status_Code status) : m_overall(status) {} + + private: + CertificatePathStatusCodes m_all_status; + CertificatePathStatusCodes m_warnings; + std::vector> m_cert_path; + Certificate_Status_Code m_overall; + }; + +/** +* PKIX Path Validation +* @param end_certs certificate chain to validate (with end entity certificate in end_certs[0]) +* @param restrictions path validation restrictions +* @param trusted_roots list of certificate stores that contain trusted certificates +* @param hostname if not empty, compared against the DNS name in end_certs[0] +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0] +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +* note: when enabled, OCSP check is softfail by default: if the OCSP server is not +* reachable, Path_Validation_Result::successful_validation() will return true. +* Hardfail OCSP check can be achieve by also calling Path_Validation_Result::no_warnings(). +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector& trusted_roots, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector>& ocsp_resp = {}); + +/** +* PKIX Path Validation +* @param end_cert certificate to validate +* @param restrictions path validation restrictions +* @param trusted_roots list of stores that contain trusted certificates +* @param hostname if not empty, compared against the DNS name in end_cert +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const std::vector& trusted_roots, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector>& ocsp_resp = {}); + +/** +* PKIX Path Validation +* @param end_cert certificate to validate +* @param restrictions path validation restrictions +* @param store store that contains trusted certificates +* @param hostname if not empty, compared against the DNS name in end_cert +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector>& ocsp_resp = {}); + +/** +* PKIX Path Validation +* @param end_certs certificate chain to validate +* @param restrictions path validation restrictions +* @param store store that contains trusted certificates +* @param hostname if not empty, compared against the DNS name in end_certs[0] +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0] +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const std::vector& end_certs, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector>& ocsp_resp = {}); + + +/** +* namespace PKIX holds the building blocks that are called by x509_path_validate. +* This allows custom validation logic to be written by applications and makes +* for easier testing, but unless you're positive you know what you're doing you +* probably want to just call x509_path_validate instead. +*/ +namespace PKIX { + +Certificate_Status_Code +build_all_certificate_paths(std::vector>>& cert_paths, + const std::vector& trusted_certstores, + const std::shared_ptr& end_entity, + const std::vector>& end_entity_extra); + + +/** +* Build certificate path +* @param cert_path_out output parameter, cert_path will be appended to this vector +* @param trusted_certstores list of certificate stores that contain trusted certificates +* @param end_entity the cert to be validated +* @param end_entity_extra optional list of additional untrusted certs for path building +* @return result of the path building operation (OK or error) +*/ +Certificate_Status_Code +BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector>& cert_path_out, + const std::vector& trusted_certstores, + const std::shared_ptr& end_entity, + const std::vector>& end_entity_extra); + +/** +* Check the certificate chain, but not any revocation data +* +* @param cert_path path built by build_certificate_path with OK result +* @param ref_time whatever time you want to perform the validation +* against (normally current system clock) +* @param hostname the hostname +* @param usage end entity usage checks +* @param min_signature_algo_strength 80 or 110 typically +* Note 80 allows 1024 bit RSA and SHA-1. 110 allows 2048 bit RSA and SHA-2. +* Using 128 requires ECC (P-256) or ~3000 bit RSA keys. +* @param trusted_hashes set of trusted hash functions, empty means accept any +* hash we have an OID for +* @return vector of results on per certificate in the path, each containing a set of +* results. If all codes in the set are < Certificate_Status_Code::FIRST_ERROR_STATUS, +* then the result for that certificate is successful. If all results are +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_chain(const std::vector>& cert_path, + std::chrono::system_clock::time_point ref_time, + const std::string& hostname, + Usage_Type usage, + size_t min_signature_algo_strength, + const std::set& trusted_hashes); + +/** +* Check OCSP responses for revocation information +* @param cert_path path already validated by check_chain +* @param ocsp_responses the OCSP responses to consider +* @param certstores trusted roots +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param max_ocsp_age maximum age of OCSP responses w/o next_update. If zero, +* there is no maximum age +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2, 0) check_ocsp(const std::vector>& cert_path, + const std::vector>& ocsp_responses, + const std::vector& certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero()); + +/** +* Check CRLs for revocation information +* @param cert_path path already validated by check_chain +* @param crls the list of CRLs to check, it is assumed that crls[i] (if not null) +* is the associated CRL for the subject in cert_path[i]. +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_crl(const std::vector>& cert_path, + const std::vector>& crls, + std::chrono::system_clock::time_point ref_time); + +/** +* Check CRLs for revocation information +* @param cert_path path already validated by check_chain +* @param certstores a list of certificate stores to query for the CRL +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_crl(const std::vector>& cert_path, + const std::vector& certstores, + std::chrono::system_clock::time_point ref_time); + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + +/** +* Check OCSP using online (HTTP) access. Current version creates a thread and +* network connection per OCSP request made. +* +* @param cert_path path already validated by check_chain +* @param trusted_certstores a list of certstores with trusted certs +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param timeout for timing out the responses, though actually this function +* may block for up to timeout*cert_path.size()*C for some small C. +* @param ocsp_check_intermediate_CAs if true also performs OCSP on any intermediate +* CA certificates. If false, only does OCSP on the end entity cert. +* @param max_ocsp_age maximum age of OCSP responses w/o next_update. If zero, +* there is no maximum age +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2, 0) check_ocsp_online(const std::vector>& cert_path, + const std::vector& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout, + bool ocsp_check_intermediate_CAs, + std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero()); + +/** +* Check CRL using online (HTTP) access. Current version creates a thread and +* network connection per CRL access. + +* @param cert_path path already validated by check_chain +* @param trusted_certstores a list of certstores with trusted certs +* @param certstore_to_recv_crls optional (nullptr to disable), all CRLs +* retreived will be saved to this cert store. +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param timeout for timing out the responses, though actually this function +* may block for up to timeout*cert_path.size()*C for some small C. +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_crl_online(const std::vector>& cert_path, + const std::vector& trusted_certstores, + Certificate_Store_In_Memory* certstore_to_recv_crls, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout); + +#endif + +/** +* Find overall status (OK, error) of a validation +* @param cert_status result of merge_revocation_status or check_chain +*/ +Certificate_Status_Code BOTAN_PUBLIC_API(2,0) overall_status(const CertificatePathStatusCodes& cert_status); + +/** +* Merge the results from CRL and/or OCSP checks into chain_status +* @param chain_status the certificate status +* @param crl_status results from check_crl +* @param ocsp_status results from check_ocsp +* @param require_rev_on_end_entity require valid CRL or OCSP on end-entity cert +* @param require_rev_on_intermediates require valid CRL or OCSP on all intermediate certificates +*/ +void BOTAN_PUBLIC_API(2,0) merge_revocation_status(CertificatePathStatusCodes& chain_status, + const CertificatePathStatusCodes& crl_status, + const CertificatePathStatusCodes& ocsp_status, + bool require_rev_on_end_entity, + bool require_rev_on_intermediates); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/lib/x509/x509self.cpp b/comm/third_party/botan/src/lib/x509/x509self.cpp new file mode 100644 index 0000000000..f75827fd83 --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509self.cpp @@ -0,0 +1,152 @@ +/* +* PKCS #10/Self Signed Cert Creation +* (C) 1999-2008,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Load information from the X509_Cert_Options +*/ +void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn, + AlternativeName& subject_alt) + { + subject_dn.add_attribute("X520.CommonName", opts.common_name); + subject_dn.add_attribute("X520.Country", opts.country); + subject_dn.add_attribute("X520.State", opts.state); + subject_dn.add_attribute("X520.Locality", opts.locality); + subject_dn.add_attribute("X520.Organization", opts.organization); + subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit); + for(auto extra_ou : opts.more_org_units) { + subject_dn.add_attribute("X520.OrganizationalUnit", extra_ou); + } + + subject_dn.add_attribute("X520.SerialNumber", opts.serial_number); + subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip); + subject_alt.add_othername(OID::from_string("PKIX.XMPPAddr"), + opts.xmpp, UTF8_STRING); + + for(auto dns : opts.more_dns) + subject_alt.add_attribute("DNS", dns); + } +} + +namespace X509 { + +/* +* Create a new self-signed X.509 certificate +*/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + // for now, only the padding option is used + std::map sig_opts = { {"padding",opts.padding_scheme} }; + + const std::vector pub_key = X509::BER_encode(key); + std::unique_ptr signer(choose_sig_format(key, sig_opts, rng, hash_fn, sig_algo)); + BOTAN_ASSERT_NOMSG(sig_algo.get_oid().has_value()); + load_info(opts, subject_dn, subject_alt); + + Extensions extensions = opts.extensions; + + Key_Constraints constraints; + if(opts.is_CA) + { + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + } + else + { + verify_cert_constraints_valid_for_key_type(key, opts.constraints); + constraints = opts.constraints; + } + + extensions.add_new( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), + true); + + if(constraints != NO_CONSTRAINTS) + { + extensions.add_new(new Cert_Extension::Key_Usage(constraints), true); + } + + std::unique_ptr skid(new Cert_Extension::Subject_Key_ID(pub_key, hash_fn)); + + extensions.add_new(new Cert_Extension::Authority_Key_ID(skid->get_key_id())); + extensions.add_new(skid.release()); + + extensions.add_new( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + extensions.add_new( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + + return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key, + opts.start, opts.end, + subject_dn, subject_dn, + extensions); + } + +/* +* Create a PKCS #10 certificate request +*/ +PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + X509_DN subject_dn; + AlternativeName subject_alt; + load_info(opts, subject_dn, subject_alt); + + Key_Constraints constraints; + if(opts.is_CA) + { + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + } + else + { + verify_cert_constraints_valid_for_key_type(key, opts.constraints); + constraints = opts.constraints; + } + + Extensions extensions = opts.extensions; + + extensions.add_new(new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); + + if(constraints != NO_CONSTRAINTS) + { + extensions.add_new(new Cert_Extension::Key_Usage(constraints)); + } + extensions.add_new(new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + extensions.add_new(new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + return PKCS10_Request::create(key, + subject_dn, + extensions, + hash_fn, + rng, + opts.padding_scheme, + opts.challenge); + } + +} + +} diff --git a/comm/third_party/botan/src/lib/x509/x509self.h b/comm/third_party/botan/src/lib/x509/x509self.h new file mode 100644 index 0000000000..27c30b12dc --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/x509self.h @@ -0,0 +1,222 @@ +/* +* X.509 Self-Signed Certificate +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_SELF_H_ +#define BOTAN_X509_SELF_H_ + +#include +#include +#include + +namespace Botan { + +class RandomNumberGenerator; +class Private_Key; + +/** +* Options for X.509 certificates. +*/ +class BOTAN_PUBLIC_API(2,0) X509_Cert_Options final + { + public: + /** + * the subject common name + */ + std::string common_name; + + /** + * the subject counry + */ + std::string country; + + /** + * the subject organization + */ + std::string organization; + + /** + * the subject organizational unit + */ + std::string org_unit; + + /** + * additional subject organizational units. + */ + std::vector more_org_units; + + /** + * the subject locality + */ + std::string locality; + + /** + * the subject state + */ + std::string state; + + /** + * the subject serial number + */ + std::string serial_number; + + /** + * the subject email adress + */ + std::string email; + + /** + * the subject URI + */ + std::string uri; + + /** + * the subject IPv4 address + */ + std::string ip; + + /** + * the subject DNS + */ + std::string dns; + + /** + * additional subject DNS entries. + */ + std::vector more_dns; + + /** + * the subject XMPP + */ + std::string xmpp; + + /** + * the subject challenge password + */ + std::string challenge; + + /** + * the subject notBefore + */ + X509_Time start; + /** + * the subject notAfter + */ + X509_Time end; + + /** + * Indicates whether the certificate request + */ + bool is_CA; + + /** + * Indicates the BasicConstraints path limit + */ + size_t path_limit; + + std::string padding_scheme; + + /** + * The key constraints for the subject public key + */ + Key_Constraints constraints; + + /** + * The key extended constraints for the subject public key + */ + std::vector ex_constraints; + + /** + * Additional X.509 extensions + */ + Extensions extensions; + + /** + * Mark the certificate as a CA certificate and set the path limit. + * @param limit the path limit to be set in the BasicConstraints extension. + */ + void CA_key(size_t limit = 1); + + /** + * Choose a padding scheme different from the default for the key used. + */ + void set_padding_scheme(const std::string& scheme); + + /** + * Set the notBefore of the certificate. + * @param time the notBefore value of the certificate + */ + void not_before(const std::string& time); + + /** + * Set the notAfter of the certificate. + * @param time the notAfter value of the certificate + */ + void not_after(const std::string& time); + + /** + * Add the key constraints of the KeyUsage extension. + * @param constr the constraints to set + */ + void add_constraints(Key_Constraints constr); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param oid the oid to add + */ + void add_ex_constraint(const OID& oid); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param name the name to look up the oid to add + */ + void add_ex_constraint(const std::string& name); + + /** + * Construct a new options object + * @param opts define the common name of this object. An example for this + * parameter would be "common_name/country/organization/organizational_unit". + * @param expire_time the expiration time (from the current clock in seconds) + */ + X509_Cert_Options(const std::string& opts = "", + uint32_t expire_time = 365 * 24 * 60 * 60); + }; + +namespace X509 { + +/** +* Create a self-signed X.509 certificate. +* @param opts the options defining the certificate to create +* @param key the private key used for signing, i.e. the key +* associated with this self-signed certificate +* @param hash_fn the hash function to use +* @param rng the rng to use +* @return newly created self-signed certificate +*/ +BOTAN_PUBLIC_API(2,0) X509_Certificate +create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +/** +* Create a PKCS#10 certificate request. +* @param opts the options defining the request to create +* @param key the key used to sign this request +* @param rng the rng to use +* @param hash_fn the hash function to use +* @return newly created PKCS#10 request +*/ +BOTAN_PUBLIC_API(2,0) PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +} + +} + +#endif diff --git a/comm/third_party/botan/src/python/botan2.py b/comm/third_party/botan/src/python/botan2.py new file mode 100755 index 0000000000..6ae1bd6da3 --- /dev/null +++ b/comm/third_party/botan/src/python/botan2.py @@ -0,0 +1,1787 @@ +#!/usr/bin/python + +""" +Python wrapper of the botan crypto library +https://botan.randombit.net + +(C) 2015,2017,2018,2019 Jack Lloyd +(C) 2015 Uri Blumenthal (extensions and patches) + +Botan is released under the Simplified BSD License (see license.txt) + +This module uses the ctypes module and is usable by programs running +under at least CPython 2.7, CPython 3.x, and PyPy + +It uses botan's ffi module, which exposes a C API. This version of the +module requires FFI API version 20180713, which was introduced in +Botan 2.8 + +""" + +from ctypes import CDLL, POINTER, byref, create_string_buffer, \ + c_void_p, c_size_t, c_uint8, c_uint32, c_uint64, c_int, c_uint, c_char_p + +from sys import version_info, platform +from time import strptime, mktime, time as system_time +from binascii import hexlify +from datetime import datetime + +BOTAN_FFI_VERSION = 20191214 + +# +# Base exception for all exceptions raised from this module +# +class BotanException(Exception): + + def __init__(self, message, rc=0): + + self.__rc = rc + + if rc == 0: + super(BotanException, self).__init__(message) + else: + descr = _DLL.botan_error_description(rc).decode('ascii') + super(BotanException, self).__init__("%s: %d (%s)" % (message, rc, descr)) + + def error_code(self): + return self.__rc + +# +# Module initialization +# + +def _load_botan_dll(expected_version): + + possible_dll_names = [] + + if platform in ['win32', 'cygwin', 'msys']: + possible_dll_names.append('botan.dll') + elif platform in ['darwin', 'macos']: + possible_dll_names.append('libbotan-2.dylib') + else: + # assumed to be some Unix/Linux system + possible_dll_names.append('libbotan-2.so') + possible_dll_names += ['libbotan-2.so.%d' % (v) for v in reversed(range(13, 20))] + + for dll_name in possible_dll_names: + try: + dll = CDLL(dll_name) + dll.botan_ffi_supports_api.argtypes = [c_uint32] + dll.botan_ffi_supports_api.restype = c_int + if dll.botan_ffi_supports_api(expected_version) == 0: + return dll + except OSError: + pass + + raise BotanException("Could not find a usable Botan shared object library") + +def _errcheck(rc, fn, _args): + # This errcheck should only be used for int-returning functions + assert isinstance(rc, int) + + if rc >= 0 or rc in fn.allowed_errors: + return rc + raise BotanException('%s failed' % (fn.__name__), rc) + +def _set_prototypes(dll): + # pylint: disable=too-many-statements,line-too-long + def ffi_api(fn, args, allowed_errors=None): + if allowed_errors is None: + allowed_errors = [-10] + fn.argtypes = args + fn.restype = c_int + fn.errcheck = _errcheck + fn.allowed_errors = allowed_errors + + dll.botan_version_string.argtypes = [] + dll.botan_version_string.restype = c_char_p + + dll.botan_version_string.argtypes = [] + dll.botan_version_string.restype = c_char_p + + dll.botan_version_major.argtypes = [] + dll.botan_version_major.restype = c_uint32 + + dll.botan_version_minor.argtypes = [] + dll.botan_version_minor.restype = c_uint32 + + dll.botan_version_patch.argtypes = [] + dll.botan_version_patch.restype = c_uint32 + + dll.botan_ffi_api_version.argtypes = [] + dll.botan_ffi_api_version.restype = c_uint32 + + dll.botan_error_description.argtypes = [c_int] + dll.botan_error_description.restype = c_char_p + + # These are generated using src/scripts/ffi_decls.py: + ffi_api(dll.botan_constant_time_compare, [c_void_p, c_void_p, c_size_t], [-1]) + ffi_api(dll.botan_scrub_mem, [c_void_p, c_size_t]) + + ffi_api(dll.botan_hex_encode, [c_char_p, c_size_t, c_char_p, c_uint32]) + ffi_api(dll.botan_hex_decode, [c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + + ffi_api(dll.botan_base64_encode, [c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_base64_decode, [c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + + # RNG + ffi_api(dll.botan_rng_init, [c_void_p, c_char_p]) + ffi_api(dll.botan_rng_get, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_rng_reseed, [c_void_p, c_size_t]) + ffi_api(dll.botan_rng_reseed_from_rng, [c_void_p, c_void_p, c_size_t]) + ffi_api(dll.botan_rng_add_entropy, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_rng_destroy, [c_void_p]) + + # HASH + ffi_api(dll.botan_hash_init, [c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_hash_copy_state, [c_void_p, c_void_p]) + ffi_api(dll.botan_hash_output_length, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_hash_block_size, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_hash_update, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_hash_final, [c_void_p, c_char_p]) + ffi_api(dll.botan_hash_clear, [c_void_p]) + ffi_api(dll.botan_hash_destroy, [c_void_p]) + ffi_api(dll.botan_hash_name, [c_void_p, c_char_p, POINTER(c_size_t)]) + + # MAC + ffi_api(dll.botan_mac_init, [c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_mac_output_length, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_mac_set_key, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_mac_update, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_mac_final, [c_void_p, c_char_p]) + ffi_api(dll.botan_mac_clear, [c_void_p]) + ffi_api(dll.botan_mac_name, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_mac_get_keyspec, [c_void_p, POINTER(c_size_t), POINTER(c_size_t), POINTER(c_size_t)]) + ffi_api(dll.botan_mac_destroy, [c_void_p]) + + # CIPHER + ffi_api(dll.botan_cipher_init, [c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_cipher_name, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_output_length, [c_void_p, c_size_t, POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_valid_nonce_length, [c_void_p, c_size_t]) + ffi_api(dll.botan_cipher_get_tag_length, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_get_default_nonce_length, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_get_update_granularity, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_query_keylen, [c_void_p, POINTER(c_size_t), POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_get_keyspec, [c_void_p, POINTER(c_size_t), POINTER(c_size_t), POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_set_key, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_cipher_reset, [c_void_p]) + ffi_api(dll.botan_cipher_set_associated_data, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_cipher_start, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_cipher_update, + [c_void_p, c_uint32, c_char_p, c_size_t, POINTER(c_size_t), c_char_p, c_size_t, POINTER(c_size_t)]) + ffi_api(dll.botan_cipher_clear, [c_void_p]) + ffi_api(dll.botan_cipher_destroy, [c_void_p]) + + ffi_api(dll.botan_pbkdf, + [c_char_p, c_char_p, c_size_t, c_char_p, c_char_p, c_size_t, c_size_t]) + ffi_api(dll.botan_pbkdf_timed, + [c_char_p, c_char_p, c_size_t, c_char_p, c_char_p, c_size_t, c_size_t, POINTER(c_size_t)]) + + ffi_api(dll.botan_pwdhash, + [c_char_p, c_size_t, c_size_t, c_size_t, c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, c_size_t]) + ffi_api(dll.botan_pwdhash_timed, + [c_char_p, c_uint32, POINTER(c_size_t), POINTER(c_size_t), POINTER(c_size_t), c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, c_size_t]) + + ffi_api(dll.botan_scrypt, + [c_char_p, c_size_t, c_char_p, c_char_p, c_size_t, c_size_t, c_size_t, c_size_t]) + + ffi_api(dll.botan_kdf, + [c_char_p, c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, c_size_t]) + + # BLOCK + ffi_api(dll.botan_block_cipher_init, [c_void_p, c_char_p]) + ffi_api(dll.botan_block_cipher_destroy, [c_void_p]) + ffi_api(dll.botan_block_cipher_clear, [c_void_p]) + ffi_api(dll.botan_block_cipher_set_key, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_block_cipher_block_size, [c_void_p]) + ffi_api(dll.botan_block_cipher_encrypt_blocks, [c_void_p, c_char_p, c_char_p, c_size_t]) + ffi_api(dll.botan_block_cipher_decrypt_blocks, [c_void_p, c_char_p, c_char_p, c_size_t]) + ffi_api(dll.botan_block_cipher_name, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_block_cipher_get_keyspec, [c_void_p, POINTER(c_size_t), POINTER(c_size_t), POINTER(c_size_t)]) + + # MP + ffi_api(dll.botan_mp_init, [c_void_p]) + ffi_api(dll.botan_mp_destroy, [c_void_p]) + ffi_api(dll.botan_mp_to_hex, [c_void_p, c_char_p]) + ffi_api(dll.botan_mp_to_str, [c_void_p, c_uint8, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_mp_clear, [c_void_p]) + ffi_api(dll.botan_mp_set_from_int, [c_void_p, c_int]) + ffi_api(dll.botan_mp_set_from_mp, [c_void_p, c_void_p]) + ffi_api(dll.botan_mp_set_from_str, [c_void_p, c_char_p]) + ffi_api(dll.botan_mp_set_from_radix_str, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_mp_num_bits, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_mp_num_bytes, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_mp_to_bin, [c_void_p, c_char_p]) + ffi_api(dll.botan_mp_from_bin, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_mp_to_uint32, [c_void_p, POINTER(c_uint32)]) + ffi_api(dll.botan_mp_is_positive, [c_void_p]) + ffi_api(dll.botan_mp_is_negative, [c_void_p]) + ffi_api(dll.botan_mp_flip_sign, [c_void_p]) + ffi_api(dll.botan_mp_is_zero, [c_void_p]) + ffi_api(dll.botan_mp_is_odd, [c_void_p]) + ffi_api(dll.botan_mp_is_even, [c_void_p]) + ffi_api(dll.botan_mp_add_u32, [c_void_p, c_void_p, c_uint32]) + ffi_api(dll.botan_mp_sub_u32, [c_void_p, c_void_p, c_uint32]) + ffi_api(dll.botan_mp_add, [c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_sub, [c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_mul, [c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_div, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_mod_mul, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_equal, [c_void_p, c_void_p]) + ffi_api(dll.botan_mp_cmp, [POINTER(c_int), c_void_p, c_void_p]) + ffi_api(dll.botan_mp_swap, [c_void_p, c_void_p]) + ffi_api(dll.botan_mp_powmod, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_lshift, [c_void_p, c_void_p, c_size_t]) + ffi_api(dll.botan_mp_rshift, [c_void_p, c_void_p, c_size_t]) + ffi_api(dll.botan_mp_mod_inverse, [c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_rand_bits, [c_void_p, c_void_p, c_size_t]) + ffi_api(dll.botan_mp_rand_range, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_gcd, [c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_mp_is_prime, [c_void_p, c_void_p, c_size_t]) + ffi_api(dll.botan_mp_get_bit, [c_void_p, c_size_t]) + ffi_api(dll.botan_mp_set_bit, [c_void_p, c_size_t]) + ffi_api(dll.botan_mp_clear_bit, [c_void_p, c_size_t]) + + ffi_api(dll.botan_bcrypt_generate, + [c_char_p, POINTER(c_size_t), c_char_p, c_void_p, c_size_t, c_uint32]) + ffi_api(dll.botan_bcrypt_is_valid, [c_char_p, c_char_p]) + + # PUBKEY + ffi_api(dll.botan_privkey_create, [c_void_p, c_char_p, c_char_p, c_void_p]) + ffi_api(dll.botan_privkey_check_key, [c_void_p, c_void_p, c_uint32], [-1]) + ffi_api(dll.botan_privkey_create_rsa, [c_void_p, c_void_p, c_size_t]) + ffi_api(dll.botan_privkey_create_ecdsa, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_create_ecdh, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_create_mceliece, [c_void_p, c_void_p, c_size_t, c_size_t]) + ffi_api(dll.botan_privkey_create_dh, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_create_dsa, [c_void_p, c_void_p, c_size_t, c_size_t]) + ffi_api(dll.botan_privkey_create_elgamal, [c_void_p, c_void_p, c_size_t, c_size_t]) + ffi_api(dll.botan_privkey_load, + [c_void_p, c_void_p, c_char_p, c_size_t, c_char_p]) + ffi_api(dll.botan_privkey_destroy, [c_void_p]) + ffi_api(dll.botan_privkey_export, [c_void_p, c_char_p, POINTER(c_size_t), c_uint32]) + ffi_api(dll.botan_privkey_algo_name, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_privkey_export_encrypted, + [c_void_p, c_char_p, POINTER(c_size_t), c_void_p, c_char_p, c_char_p, c_uint32]) + ffi_api(dll.botan_privkey_export_encrypted_pbkdf_msec, + [c_void_p, c_char_p, POINTER(c_size_t), c_void_p, c_char_p, c_uint32, POINTER(c_size_t), c_char_p, c_char_p, c_uint32]) + ffi_api(dll.botan_privkey_export_encrypted_pbkdf_iter, + [c_void_p, c_char_p, POINTER(c_size_t), c_void_p, c_char_p, c_size_t, c_char_p, c_char_p, c_uint32]) + ffi_api(dll.botan_privkey_export_pubkey, [c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_load, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_pubkey_export, [c_void_p, c_char_p, POINTER(c_size_t), c_uint32]) + ffi_api(dll.botan_pubkey_algo_name, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pubkey_check_key, [c_void_p, c_void_p, c_uint32], [-1]) + ffi_api(dll.botan_pubkey_estimated_strength, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pubkey_fingerprint, [c_void_p, c_char_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pubkey_destroy, [c_void_p]) + ffi_api(dll.botan_pubkey_get_field, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_get_field, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_load_rsa, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_load_rsa_pkcs1, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_privkey_rsa_get_p, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_rsa_get_q, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_rsa_get_d, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_rsa_get_n, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_rsa_get_e, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_rsa_get_privkey, [c_void_p, c_char_p, POINTER(c_size_t), c_uint32]) + ffi_api(dll.botan_pubkey_load_rsa, [c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_rsa_get_e, [c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_rsa_get_n, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_load_dsa, + [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_load_dsa, + [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_dsa_get_x, [c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_dsa_get_p, [c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_dsa_get_q, [c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_dsa_get_g, [c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_dsa_get_y, [c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_load_dh, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_load_dh, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_pubkey_load_elgamal, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_load_elgamal, [c_void_p, c_void_p, c_void_p, c_void_p]) + ffi_api(dll.botan_privkey_load_ed25519, [c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_load_ed25519, [c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_ed25519_get_privkey, [c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_ed25519_get_pubkey, [c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_load_x25519, [c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_load_x25519, [c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_x25519_get_privkey, [c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_x25519_get_pubkey, [c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_load_ecdsa, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_load_ecdsa, [c_void_p, c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_load_ecdh, [c_void_p, c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_load_ecdh, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_load_sm2, [c_void_p, c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_load_sm2, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_load_sm2_enc, [c_void_p, c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_privkey_load_sm2_enc, [c_void_p, c_void_p, c_char_p]) + ffi_api(dll.botan_pubkey_sm2_compute_za, + [c_char_p, POINTER(c_size_t), c_char_p, c_char_p, c_void_p]) + + # PK + ffi_api(dll.botan_pk_op_encrypt_create, [c_void_p, c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_pk_op_encrypt_destroy, [c_void_p]) + ffi_api(dll.botan_pk_op_encrypt_output_length, [c_void_p, c_size_t, POINTER(c_size_t)]) + ffi_api(dll.botan_pk_op_encrypt, + [c_void_p, c_void_p, c_char_p, POINTER(c_size_t), c_char_p, c_size_t]) + ffi_api(dll.botan_pk_op_decrypt_create, [c_void_p, c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_pk_op_decrypt_destroy, [c_void_p]) + ffi_api(dll.botan_pk_op_decrypt_output_length, [c_void_p, c_size_t, POINTER(c_size_t)]) + ffi_api(dll.botan_pk_op_decrypt, + [c_void_p, c_char_p, POINTER(c_size_t), c_char_p, c_size_t]) + ffi_api(dll.botan_pk_op_sign_create, [c_void_p, c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_pk_op_sign_destroy, [c_void_p]) + ffi_api(dll.botan_pk_op_sign_output_length, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pk_op_sign_update, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_pk_op_sign_finish, [c_void_p, c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pk_op_verify_create, [c_void_p, c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_pk_op_verify_destroy, [c_void_p]) + ffi_api(dll.botan_pk_op_verify_update, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_pk_op_verify_finish, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_pk_op_key_agreement_create, [c_void_p, c_void_p, c_char_p, c_uint32]) + ffi_api(dll.botan_pk_op_key_agreement_destroy, [c_void_p]) + ffi_api(dll.botan_pk_op_key_agreement_export_public, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pk_op_key_agreement_size, [c_void_p, POINTER(c_size_t)]) + ffi_api(dll.botan_pk_op_key_agreement, + [c_void_p, c_char_p, POINTER(c_size_t), c_char_p, c_size_t, c_char_p, c_size_t]) + + ffi_api(dll.botan_pkcs_hash_id, [c_char_p, c_char_p, POINTER(c_size_t)]) + + ffi_api(dll.botan_mceies_encrypt, + [c_void_p, c_void_p, c_char_p, c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_mceies_decrypt, + [c_void_p, c_char_p, c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + + # X509 + ffi_api(dll.botan_x509_cert_load, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_x509_cert_load_file, [c_void_p, c_char_p]) + ffi_api(dll.botan_x509_cert_destroy, [c_void_p]) + ffi_api(dll.botan_x509_cert_dup, [c_void_p, c_void_p]) + ffi_api(dll.botan_x509_cert_get_time_starts, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_time_expires, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_not_before, [c_void_p, POINTER(c_uint64)]) + ffi_api(dll.botan_x509_cert_not_after, [c_void_p, POINTER(c_uint64)]) + ffi_api(dll.botan_x509_cert_get_fingerprint, [c_void_p, c_char_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_serial_number, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_authority_key_id, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_subject_key_id, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_public_key_bits, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_public_key, [c_void_p, c_void_p]) + ffi_api(dll.botan_x509_cert_get_issuer_dn, + [c_void_p, c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_get_subject_dn, + [c_void_p, c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_to_string, [c_void_p, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_x509_cert_allowed_usage, [c_void_p, c_uint]) + ffi_api(dll.botan_x509_cert_hostname_match, [c_void_p, c_char_p], [-1]) + ffi_api(dll.botan_x509_cert_verify, + [POINTER(c_int), c_void_p, c_void_p, c_size_t, c_void_p, c_size_t, c_char_p, c_size_t, c_char_p, c_uint64]) + + dll.botan_x509_cert_validation_status.argtypes = [c_int] + dll.botan_x509_cert_validation_status.restype = c_char_p + + # X509 CRL + ffi_api(dll.botan_x509_crl_load, [c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_x509_crl_load_file, [c_void_p, c_char_p]) + ffi_api(dll.botan_x509_crl_destroy, [c_void_p]) + ffi_api(dll.botan_x509_is_revoked, [c_void_p, c_void_p], [-1]) + ffi_api(dll.botan_x509_cert_verify_with_crl, + [POINTER(c_int), c_void_p, c_void_p, c_size_t, c_void_p, c_size_t, c_void_p, c_size_t, c_char_p, c_size_t, c_char_p, c_uint64]) + + ffi_api(dll.botan_key_wrap3394, + [c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + ffi_api(dll.botan_key_unwrap3394, + [c_char_p, c_size_t, c_char_p, c_size_t, c_char_p, POINTER(c_size_t)]) + + # HOTP + ffi_api(dll.botan_hotp_init, + [c_void_p, c_char_p, c_size_t, c_char_p, c_size_t]) + ffi_api(dll.botan_hotp_destroy, [c_void_p]) + ffi_api(dll.botan_hotp_generate, [c_void_p, POINTER(c_uint32), c_uint64]) + ffi_api(dll.botan_hotp_check, + [c_void_p, POINTER(c_uint64), c_uint32, c_uint64, c_size_t]) + + # TOTP + ffi_api(dll.botan_totp_init, + [c_void_p, c_char_p, c_size_t, c_char_p, c_size_t, c_size_t]) + ffi_api(dll.botan_totp_destroy, [c_void_p]) + ffi_api(dll.botan_totp_generate, [c_void_p, POINTER(c_uint32), c_uint64]) + ffi_api(dll.botan_totp_check, [c_void_p, c_uint32, c_uint64, c_size_t]) + + # FPE + ffi_api(dll.botan_fpe_fe1_init, + [c_void_p, c_void_p, c_char_p, c_size_t, c_size_t, c_uint32]) + ffi_api(dll.botan_fpe_destroy, [c_void_p]) + ffi_api(dll.botan_fpe_encrypt, [c_void_p, c_void_p, c_char_p, c_size_t]) + ffi_api(dll.botan_fpe_decrypt, [c_void_p, c_void_p, c_char_p, c_size_t]) + + return dll + +# +# Load the DLL and set prototypes on it +# +_DLL = _set_prototypes(_load_botan_dll(BOTAN_FFI_VERSION)) + +# +# Internal utilities +# +def _call_fn_returning_sz(fn): + sz = c_size_t(0) + fn(byref(sz)) + return int(sz.value) + +def _call_fn_returning_vec(guess, fn): + + buf = create_string_buffer(guess) + buf_len = c_size_t(len(buf)) + + rc = fn(buf, byref(buf_len)) + if rc == -10 and buf_len.value > len(buf): + return _call_fn_returning_vec(buf_len.value, fn) + + assert buf_len.value <= len(buf) + return buf.raw[0:int(buf_len.value)] + +def _call_fn_returning_str(guess, fn): + # Assumes that anything called with this is returning plain ASCII strings + # (base64 data, algorithm names, etc) + v = _call_fn_returning_vec(guess, fn) + return v.decode('ascii')[:-1] + +def _ctype_str(s): + if s is None: + return None + assert isinstance(s, str) + if version_info[0] < 3: + return s + else: + return s.encode('utf-8') + +def _ctype_to_str(s): + if version_info[0] < 3: + return s.encode('utf-8') + else: + return s.decode('utf-8') + +def _ctype_bits(s): + if version_info[0] < 3: + if isinstance(s, str): + return s + elif isinstance(s, unicode): # pylint: disable=undefined-variable + return s.decode('utf-8') + else: + raise Exception("Internal error - unexpected type %s provided to _ctype_bits" % (type(s).__name__)) + else: + if isinstance(s, bytes): + return s + elif isinstance(s, str): + return s.encode('utf-8') + else: + raise Exception("Internal error - unexpected type %s provided to _ctype_bits" % (type(s).__name__)) + +def _ctype_bufout(buf): + if version_info[0] < 3: + return str(buf.raw) + else: + return buf.raw + +def _hex_encode(buf): + return hexlify(buf).decode('ascii') + +# +# Versioning +# +def version_major(): + return int(_DLL.botan_version_major()) + +def version_minor(): + return int(_DLL.botan_version_minor()) + +def version_patch(): + return int(_DLL.botan_version_patch()) + +def ffi_api_version(): + return int(_DLL.botan_ffi_api_version()) + +def version_string(): + return _DLL.botan_version_string().decode('ascii') + +# +# Utilities +# +def const_time_compare(x, y): + len_x = len(x) + len_y = len(y) + if len_x != len_y: + return False + rc = _DLL.botan_constant_time_compare(_ctype_bits(x), _ctype_bits(y), c_size_t(len_x)) + return rc == 0 + +# +# RNG +# +class RandomNumberGenerator(object): + # Can also use type "system" + def __init__(self, rng_type='system'): + self.__obj = c_void_p(0) + _DLL.botan_rng_init(byref(self.__obj), _ctype_str(rng_type)) + + def __del__(self): + _DLL.botan_rng_destroy(self.__obj) + + def handle_(self): + return self.__obj + + def reseed(self, bits=256): + _DLL.botan_rng_reseed(self.__obj, bits) + + def reseed_from_rng(self, source_rng, bits=256): + _DLL.botan_rng_reseed_from_rng(self.__obj, source_rng.handle_(), bits) + + def add_entropy(self, seed): + _DLL.botan_rng_add_entropy(self.__obj, _ctype_bits(seed), len(seed)) + + def get(self, length): + out = create_string_buffer(length) + l = c_size_t(length) + _DLL.botan_rng_get(self.__obj, out, l) + return _ctype_bufout(out) + +# +# Block cipher +# +class BlockCipher(object): + def __init__(self, algo): + + if isinstance(algo, c_void_p): + self.__obj = algo + else: + flags = c_uint32(0) # always zero in this API version + self.__obj = c_void_p(0) + _DLL.botan_block_cipher_init(byref(self.__obj), _ctype_str(algo), flags) + + min_keylen = c_size_t(0) + max_keylen = c_size_t(0) + mod_keylen = c_size_t(0) + _DLL.botan_block_cipher_get_keyspec(self.__obj, byref(min_keylen), byref(max_keylen), byref(mod_keylen)) + + self.__min_keylen = min_keylen.value + self.__max_keylen = max_keylen.value + self.__mod_keylen = mod_keylen.value + + self.__block_size = _DLL.botan_block_cipher_block_size(self.__obj) + + def __del__(self): + _DLL.botan_block_cipher_destroy(self.__obj) + + def set_key(self, key): + _DLL.botan_block_cipher_set_key(self.__obj, key, len(key)) + + def encrypt(self, pt): + if len(pt) % self.block_size() != 0: + raise Exception("Invalid input must be multiple of block size") + + blocks = c_size_t(len(pt) // self.block_size()) + output = create_string_buffer(len(pt)) + _DLL.botan_block_cipher_encrypt_blocks(self.__obj, pt, output, blocks) + return output + + def decrypt(self, ct): + if len(ct) % self.block_size() != 0: + raise Exception("Invalid input must be multiple of block size") + + blocks = c_size_t(len(ct) // self.block_size()) + output = create_string_buffer(len(ct)) + _DLL.botan_block_cipher_decrypt_blocks(self.__obj, ct, output, blocks) + return output + + def algo_name(self): + return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_block_cipher_name(self.__obj, b, bl)) + + def clear(self): + _DLL.botan_block_cipher_clear(self.__obj) + + def block_size(self): + return self.__block_size + + def minimum_keylength(self): + return self.__min_keylen + + def maximum_keylength(self): + return self.__max_keylen + + +# +# Hash function +# +class HashFunction(object): + def __init__(self, algo): + + if isinstance(algo, c_void_p): + self.__obj = algo + else: + flags = c_uint32(0) # always zero in this API version + self.__obj = c_void_p(0) + _DLL.botan_hash_init(byref(self.__obj), _ctype_str(algo), flags) + + self.__output_length = _call_fn_returning_sz(lambda l: _DLL.botan_hash_output_length(self.__obj, l)) + self.__block_size = _call_fn_returning_sz(lambda l: _DLL.botan_hash_block_size(self.__obj, l)) + + def __del__(self): + _DLL.botan_hash_destroy(self.__obj) + + def copy_state(self): + copy = c_void_p(0) + _DLL.botan_hash_copy_state(byref(copy), self.__obj) + return HashFunction(copy) + + def algo_name(self): + return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_hash_name(self.__obj, b, bl)) + + def clear(self): + _DLL.botan_hash_clear(self.__obj) + + def output_length(self): + return self.__output_length + + def block_size(self): + return self.__block_size + + def update(self, x): + _DLL.botan_hash_update(self.__obj, _ctype_bits(x), len(x)) + + def final(self): + out = create_string_buffer(self.output_length()) + _DLL.botan_hash_final(self.__obj, out) + return _ctype_bufout(out) + +# +# Message authentication codes +# +class MsgAuthCode(object): + def __init__(self, algo): + flags = c_uint32(0) # always zero in this API version + self.__obj = c_void_p(0) + _DLL.botan_mac_init(byref(self.__obj), _ctype_str(algo), flags) + + min_keylen = c_size_t(0) + max_keylen = c_size_t(0) + mod_keylen = c_size_t(0) + _DLL.botan_mac_get_keyspec(self.__obj, byref(min_keylen), byref(max_keylen), byref(mod_keylen)) + + self.__min_keylen = min_keylen.value + self.__max_keylen = max_keylen.value + self.__mod_keylen = mod_keylen.value + + output_length = c_size_t(0) + _DLL.botan_mac_output_length(self.__obj, byref(output_length)) + self.__output_length = output_length.value + + def __del__(self): + _DLL.botan_mac_destroy(self.__obj) + + def clear(self): + _DLL.botan_mac_clear(self.__obj) + + def algo_name(self): + return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_mac_name(self.__obj, b, bl)) + + def output_length(self): + return self.__output_length + + def minimum_keylength(self): + return self.__min_keylen + + def maximum_keylength(self): + return self.__max_keylen + + def set_key(self, key): + _DLL.botan_mac_set_key(self.__obj, key, len(key)) + + def update(self, x): + _DLL.botan_mac_update(self.__obj, x, len(x)) + + def final(self): + out = create_string_buffer(self.output_length()) + _DLL.botan_mac_final(self.__obj, out) + return _ctype_bufout(out) + +class SymmetricCipher(object): + def __init__(self, algo, encrypt=True): + flags = 0 if encrypt else 1 + self.__obj = c_void_p(0) + _DLL.botan_cipher_init(byref(self.__obj), _ctype_str(algo), flags) + + def __del__(self): + _DLL.botan_cipher_destroy(self.__obj) + + def algo_name(self): + return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_cipher_name(self.__obj, b, bl)) + + def default_nonce_length(self): + l = c_size_t(0) + _DLL.botan_cipher_get_default_nonce_length(self.__obj, byref(l)) + return l.value + + def update_granularity(self): + l = c_size_t(0) + _DLL.botan_cipher_get_update_granularity(self.__obj, byref(l)) + return l.value + + def key_length(self): + kmin = c_size_t(0) + kmax = c_size_t(0) + _DLL.botan_cipher_query_keylen(self.__obj, byref(kmin), byref(kmax)) + return kmin.value, kmax.value + + def minimum_keylength(self): + l = c_size_t(0) + _DLL.botan_cipher_get_keyspec(self.__obj, byref(l), None, None) + return l.value + + def maximum_keylength(self): + l = c_size_t(0) + _DLL.botan_cipher_get_keyspec(self.__obj, None, byref(l), None) + return l.value + + def tag_length(self): + l = c_size_t(0) + _DLL.botan_cipher_get_tag_length(self.__obj, byref(l)) + return l.value + + def is_authenticated(self): + return self.tag_length() > 0 + + def valid_nonce_length(self, nonce_len): + rc = _DLL.botan_cipher_valid_nonce_length(self.__obj, nonce_len) + return rc == 1 + + def reset(self): + _DLL.botan_cipher_reset(self.__obj) + + def clear(self): + _DLL.botan_cipher_clear(self.__obj) + + def set_key(self, key): + _DLL.botan_cipher_set_key(self.__obj, key, len(key)) + + def set_assoc_data(self, ad): + _DLL.botan_cipher_set_associated_data(self.__obj, ad, len(ad)) + + def start(self, nonce): + _DLL.botan_cipher_start(self.__obj, nonce, len(nonce)) + + def _update(self, txt, final): + + inp = txt if txt else '' + inp_sz = c_size_t(len(inp)) + inp_consumed = c_size_t(0) + out = create_string_buffer(inp_sz.value + (self.tag_length() if final else 0)) + out_sz = c_size_t(len(out)) + out_written = c_size_t(0) + flags = c_uint32(1 if final else 0) + + _DLL.botan_cipher_update(self.__obj, flags, + out, out_sz, byref(out_written), + _ctype_bits(inp), inp_sz, byref(inp_consumed)) + + # buffering not supported yet + assert inp_consumed.value == inp_sz.value + return out.raw[0:int(out_written.value)] + + def update(self, txt): + return self._update(txt, False) + + def finish(self, txt=None): + return self._update(txt, True) + +def bcrypt(passwd, rng_obj, work_factor=10): + """ + Bcrypt password hashing + """ + out_len = c_size_t(64) + out = create_string_buffer(out_len.value) + flags = c_uint32(0) + _DLL.botan_bcrypt_generate(out, byref(out_len), _ctype_str(passwd), + rng_obj.handle_(), c_size_t(work_factor), flags) + b = out.raw[0:int(out_len.value)-1] + if b[-1] == '\x00': + b = b[:-1] + return _ctype_to_str(b) + +def check_bcrypt(passwd, passwd_hash): + rc = _DLL.botan_bcrypt_is_valid(_ctype_str(passwd), _ctype_str(passwd_hash)) + return rc == 0 + +# +# PBKDF +# +def pbkdf(algo, password, out_len, iterations=10000, salt=None): + if salt is None: + salt = RandomNumberGenerator().get(12) + + out_buf = create_string_buffer(out_len) + + _DLL.botan_pwdhash(_ctype_str(algo), iterations, 0, 0, + out_buf, out_len, + _ctype_str(password), len(password), + salt, len(salt)) + return (salt, iterations, out_buf.raw) + +def pbkdf_timed(algo, password, out_len, ms_to_run=300, salt=None): + if salt is None: + salt = RandomNumberGenerator().get(12) + + out_buf = create_string_buffer(out_len) + iterations = c_size_t(0) + + _DLL.botan_pwdhash_timed(_ctype_str(algo), c_uint32(ms_to_run), + byref(iterations), None, None, + out_buf, out_len, + _ctype_str(password), len(password), + salt, len(salt)) + return (salt, iterations.value, out_buf.raw) + +# +# Scrypt +# +def scrypt(out_len, password, salt, n=1024, r=8, p=8): + out_buf = create_string_buffer(out_len) + _DLL.botan_pwdhash(_ctype_str("Scrypt"), n, r, p, + out_buf, out_len, + _ctype_str(password), len(password), + _ctype_bits(salt), len(salt)) + + return out_buf.raw + +# +# KDF +# +def kdf(algo, secret, out_len, salt, label): + out_buf = create_string_buffer(out_len) + out_sz = c_size_t(out_len) + _DLL.botan_kdf(_ctype_str(algo), out_buf, out_sz, + secret, len(secret), + salt, len(salt), + label, len(label)) + return out_buf.raw[0:int(out_sz.value)] + +# +# Public key +# +class PublicKey(object): # pylint: disable=invalid-name + + def __init__(self, obj=c_void_p(0)): + self.__obj = obj + + @classmethod + def load(cls, val): + obj = c_void_p(0) + _DLL.botan_pubkey_load(byref(obj), _ctype_bits(val), len(val)) + return PublicKey(obj) + + @classmethod + def load_rsa(cls, n, e): + obj = c_void_p(0) + n = MPI(n) + e = MPI(e) + _DLL.botan_pubkey_load_rsa(byref(obj), n.handle_(), e.handle_()) + return PublicKey(obj) + + @classmethod + def load_dsa(cls, p, q, g, y): + obj = c_void_p(0) + p = MPI(p) + q = MPI(q) + g = MPI(g) + y = MPI(y) + _DLL.botan_pubkey_load_dsa(byref(obj), p.handle_(), q.handle_(), g.handle_(), y.handle_()) + return PublicKey(obj) + + @classmethod + def load_dh(cls, p, g, y): + obj = c_void_p(0) + p = MPI(p) + g = MPI(g) + y = MPI(y) + _DLL.botan_pubkey_load_dh(byref(obj), p.handle_(), g.handle_(), y.handle_()) + return PublicKey(obj) + + @classmethod + def load_elgamal(cls, p, q, g, y): + obj = c_void_p(0) + p = MPI(p) + q = MPI(q) + g = MPI(g) + y = MPI(y) + _DLL.botan_pubkey_load_elgamal(byref(obj), p.handle_(), q.handle_(), g.handle_(), y.handle_()) + return PublicKey(obj) + + @classmethod + def load_ecdsa(cls, curve, pub_x, pub_y): + obj = c_void_p(0) + pub_x = MPI(pub_x) + pub_y = MPI(pub_y) + _DLL.botan_pubkey_load_ecdsa(byref(obj), pub_x.handle_(), pub_y.handle_(), _ctype_str(curve)) + return PublicKey(obj) + + @classmethod + def load_ecdh(cls, curve, pub_x, pub_y): + obj = c_void_p(0) + pub_x = MPI(pub_x) + pub_y = MPI(pub_y) + _DLL.botan_pubkey_load_ecdh(byref(obj), pub_x.handle_(), pub_y.handle_(), _ctype_str(curve)) + return PublicKey(obj) + + @classmethod + def load_sm2(cls, curve, pub_x, pub_y): + obj = c_void_p(0) + pub_x = MPI(pub_x) + pub_y = MPI(pub_y) + _DLL.botan_pubkey_load_sm2(byref(obj), pub_x.handle_(), pub_y.handle_(), _ctype_str(curve)) + return PublicKey(obj) + + def __del__(self): + _DLL.botan_pubkey_destroy(self.__obj) + + def handle_(self): + return self.__obj + + def check_key(self, rng_obj, strong=True): + flags = 1 if strong else 0 + rc = _DLL.botan_pubkey_check_key(self.__obj, rng_obj.handle_(), flags) + return rc == 0 + + def estimated_strength(self): + r = c_size_t(0) + _DLL.botan_pubkey_estimated_strength(self.__obj, byref(r)) + return r.value + + def algo_name(self): + return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_pubkey_algo_name(self.__obj, b, bl)) + + def export(self, pem=False): + if pem: + return _call_fn_returning_str(4096, lambda b, bl: _DLL.botan_pubkey_export(self.__obj, b, bl, 1)) + else: + return _call_fn_returning_vec(4096, lambda b, bl: _DLL.botan_pubkey_export(self.__obj, b, bl, 0)) + + def encoding(self, pem=False): + return self.export(pem) + + def to_der(self): + return self.export(False) + + def to_pem(self): + return self.export(True) + + def fingerprint(self, hash_algorithm='SHA-256'): + n = HashFunction(hash_algorithm).output_length() + buf = create_string_buffer(n) + buf_len = c_size_t(n) + + _DLL.botan_pubkey_fingerprint(self.__obj, _ctype_str(hash_algorithm), buf, byref(buf_len)) + return _hex_encode(buf[0:int(buf_len.value)]) + + def get_field(self, field_name): + v = MPI() + _DLL.botan_pubkey_get_field(v.handle_(), self.__obj, _ctype_str(field_name)) + return int(v) + +# +# Private Key +# +class PrivateKey(object): + + def __init__(self, obj=c_void_p(0)): + self.__obj = obj + + @classmethod + def load(cls, val, passphrase=""): + obj = c_void_p(0) + rng_obj = c_void_p(0) # unused in recent versions + _DLL.botan_privkey_load(byref(obj), rng_obj, _ctype_bits(val), len(val), _ctype_str(passphrase)) + return PrivateKey(obj) + + @classmethod + def create(cls, algo, params, rng_obj): + if algo == 'rsa': + algo = 'RSA' + params = "%d" % (params) + elif algo == 'ecdsa': + algo = 'ECDSA' + elif algo in ['ecdh', 'ECDH']: + if params == 'curve25519': + algo = 'Curve25519' + params = '' + else: + algo = 'ECDH' + elif algo in ['mce', 'mceliece']: + algo = 'McEliece' + params = "%d,%d" % (params[0], params[1]) + + obj = c_void_p(0) + _DLL.botan_privkey_create(byref(obj), _ctype_str(algo), _ctype_str(params), rng_obj.handle_()) + return PrivateKey(obj) + + @classmethod + def load_rsa(cls, p, q, e): + obj = c_void_p(0) + p = MPI(p) + q = MPI(q) + e = MPI(e) + _DLL.botan_privkey_load_rsa(byref(obj), p.handle_(), q.handle_(), e.handle_()) + return PrivateKey(obj) + + @classmethod + def load_dsa(cls, p, q, g, x): + obj = c_void_p(0) + p = MPI(p) + q = MPI(q) + g = MPI(g) + x = MPI(x) + _DLL.botan_privkey_load_dsa(byref(obj), p.handle_(), q.handle_(), g.handle_(), x.handle_()) + return PrivateKey(obj) + + @classmethod + def load_dh(cls, p, g, x): + obj = c_void_p(0) + p = MPI(p) + g = MPI(g) + x = MPI(x) + _DLL.botan_privkey_load_dh(byref(obj), p.handle_(), g.handle_(), x.handle_()) + return PrivateKey(obj) + + @classmethod + def load_elgamal(cls, p, q, g, x): + obj = c_void_p(0) + p = MPI(p) + q = MPI(q) + g = MPI(g) + x = MPI(x) + _DLL.botan_privkey_load_elgamal(byref(obj), p.handle_(), q.handle_(), g.handle_(), x.handle_()) + return PrivateKey(obj) + + @classmethod + def load_ecdsa(cls, curve, x): + obj = c_void_p(0) + x = MPI(x) + _DLL.botan_privkey_load_ecdsa(byref(obj), x.handle_(), _ctype_str(curve)) + return PrivateKey(obj) + + @classmethod + def load_ecdh(cls, curve, x): + obj = c_void_p(0) + x = MPI(x) + _DLL.botan_privkey_load_ecdh(byref(obj), x.handle_(), _ctype_str(curve)) + return PrivateKey(obj) + + @classmethod + def load_sm2(cls, curve, x): + obj = c_void_p(0) + x = MPI(x) + _DLL.botan_privkey_load_sm2(byref(obj), x.handle_(), _ctype_str(curve)) + return PrivateKey(obj) + + def __del__(self): + _DLL.botan_privkey_destroy(self.__obj) + + def handle_(self): + return self.__obj + + def check_key(self, rng_obj, strong=True): + flags = 1 if strong else 0 + rc = _DLL.botan_privkey_check_key(self.__obj, rng_obj.handle_(), flags) + return rc == 0 + + def algo_name(self): + return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_privkey_algo_name(self.__obj, b, bl)) + + def get_public_key(self): + pub = c_void_p(0) + _DLL.botan_privkey_export_pubkey(byref(pub), self.__obj) + return PublicKey(pub) + + def to_der(self): + return self.export(False) + + def to_pem(self): + return self.export(True) + + def export(self, pem=False): + if pem: + return _call_fn_returning_str(4096, lambda b, bl: _DLL.botan_privkey_export(self.__obj, b, bl, 1)) + else: + return _call_fn_returning_vec(4096, lambda b, bl: _DLL.botan_privkey_export(self.__obj, b, bl, 0)) + + def export_encrypted(self, passphrase, rng_obj, pem=False, msec=300, cipher=None, pbkdf=None): # pylint: disable=redefined-outer-name + flags = 1 if pem else 0 + msec = c_uint32(msec) + _iters = c_size_t(0) + + cb = lambda b, bl: _DLL.botan_privkey_export_encrypted_pbkdf_msec( + self.__obj, b, bl, rng_obj.handle_(), _ctype_str(passphrase), + msec, byref(_iters), _ctype_str(cipher), _ctype_str(pbkdf), flags) + + if pem: + return _call_fn_returning_str(8192, cb) + else: + return _call_fn_returning_vec(4096, cb) + + def get_field(self, field_name): + v = MPI() + _DLL.botan_privkey_get_field(v.handle_(), self.__obj, _ctype_str(field_name)) + return int(v) + +class PKEncrypt(object): + def __init__(self, key, padding): + self.__obj = c_void_p(0) + flags = c_uint32(0) # always zero in this ABI + _DLL.botan_pk_op_encrypt_create(byref(self.__obj), key.handle_(), _ctype_str(padding), flags) + + def __del__(self): + _DLL.botan_pk_op_encrypt_destroy(self.__obj) + + def encrypt(self, msg, rng_obj): + outbuf_sz = c_size_t(0) + _DLL.botan_pk_op_encrypt_output_length(self.__obj, len(msg), byref(outbuf_sz)) + outbuf = create_string_buffer(outbuf_sz.value) + _DLL.botan_pk_op_encrypt(self.__obj, rng_obj.handle_(), outbuf, byref(outbuf_sz), msg, len(msg)) + return outbuf.raw[0:int(outbuf_sz.value)] + + +class PKDecrypt(object): + def __init__(self, key, padding): + self.__obj = c_void_p(0) + flags = c_uint32(0) # always zero in this ABI + _DLL.botan_pk_op_decrypt_create(byref(self.__obj), key.handle_(), _ctype_str(padding), flags) + + def __del__(self): + _DLL.botan_pk_op_decrypt_destroy(self.__obj) + + def decrypt(self, msg): + outbuf_sz = c_size_t(0) + _DLL.botan_pk_op_decrypt_output_length(self.__obj, len(msg), byref(outbuf_sz)) + outbuf = create_string_buffer(outbuf_sz.value) + _DLL.botan_pk_op_decrypt(self.__obj, outbuf, byref(outbuf_sz), _ctype_bits(msg), len(msg)) + return outbuf.raw[0:int(outbuf_sz.value)] + +class PKSign(object): # pylint: disable=invalid-name + def __init__(self, key, padding, der=False): + self.__obj = c_void_p(0) + flags = c_uint32(1) if der else c_uint32(0) + _DLL.botan_pk_op_sign_create(byref(self.__obj), key.handle_(), _ctype_str(padding), flags) + + def __del__(self): + _DLL.botan_pk_op_sign_destroy(self.__obj) + + def update(self, msg): + _DLL.botan_pk_op_sign_update(self.__obj, _ctype_str(msg), len(msg)) + + def finish(self, rng_obj): + outbuf_sz = c_size_t(0) + _DLL.botan_pk_op_sign_output_length(self.__obj, byref(outbuf_sz)) + outbuf = create_string_buffer(outbuf_sz.value) + _DLL.botan_pk_op_sign_finish(self.__obj, rng_obj.handle_(), outbuf, byref(outbuf_sz)) + return outbuf.raw[0:int(outbuf_sz.value)] + +class PKVerify(object): + def __init__(self, key, padding, der=False): + self.__obj = c_void_p(0) + flags = c_uint32(1) if der else c_uint32(0) + _DLL.botan_pk_op_verify_create(byref(self.__obj), key.handle_(), _ctype_str(padding), flags) + + def __del__(self): + _DLL.botan_pk_op_verify_destroy(self.__obj) + + def update(self, msg): + _DLL.botan_pk_op_verify_update(self.__obj, _ctype_bits(msg), len(msg)) + + def check_signature(self, signature): + rc = _DLL.botan_pk_op_verify_finish(self.__obj, _ctype_bits(signature), len(signature)) + if rc == 0: + return True + return False + +class PKKeyAgreement(object): + def __init__(self, key, kdf_name): + self.__obj = c_void_p(0) + flags = c_uint32(0) # always zero in this ABI + _DLL.botan_pk_op_key_agreement_create(byref(self.__obj), key.handle_(), _ctype_str(kdf_name), flags) + + self.m_public_value = _call_fn_returning_vec( + 0, lambda b, bl: _DLL.botan_pk_op_key_agreement_export_public(key.handle_(), b, bl)) + + def __del__(self): + _DLL.botan_pk_op_key_agreement_destroy(self.__obj) + + def public_value(self): + return self.m_public_value + + def underlying_output_length(self): + out_len = c_size_t(0) + _DLL.botan_pk_op_key_agreement_size(self.__obj, byref(out_len)) + return out_len.value + + def agree(self, other, key_len, salt): + if key_len == 0: + key_len = self.underlying_output_length() + return _call_fn_returning_vec(key_len, lambda b, bl: + _DLL.botan_pk_op_key_agreement(self.__obj, b, bl, + other, len(other), + salt, len(salt))) + +# +# MCEIES encryption +# Must be used with McEliece keys +# +def mceies_encrypt(mce, rng_obj, aead, pt, ad): + return _call_fn_returning_vec(len(pt) + 1024, lambda b, bl: + _DLL.botan_mceies_encrypt(mce.handle_(), + rng_obj.handle_(), + _ctype_str(aead), + _ctype_bits(pt), + len(pt), + _ctype_bits(ad), + len(ad), + b, bl)) + +def mceies_decrypt(mce, aead, ct, ad): + + #msg = cast(msg, c_char_p) + #ll = c_size_t(ll) + + return _call_fn_returning_vec(len(ct), lambda b, bl: + _DLL.botan_mceies_decrypt(mce.handle_(), + _ctype_str(aead), + _ctype_bits(ct), + len(ct), + _ctype_bits(ad), + len(ad), + b, bl)) + + +def _load_buf_or_file(filename, buf, file_fn, buf_fn): + if filename is None and buf is None: + raise BotanException("No filename or buf given") + if filename is not None and buf is not None: + raise BotanException("Both filename and buf given") + + obj = c_void_p(0) + + if filename is not None: + file_fn(byref(obj), _ctype_str(filename)) + elif buf is not None: + buf_fn(byref(obj), _ctype_bits(buf), len(buf)) + + return obj + + +# +# X.509 certificates +# +class X509Cert(object): # pylint: disable=invalid-name + def __init__(self, filename=None, buf=None): + self.__obj = _load_buf_or_file(filename, buf, _DLL.botan_x509_cert_load_file, _DLL.botan_x509_cert_load) + + def __del__(self): + _DLL.botan_x509_cert_destroy(self.__obj) + + def time_starts(self): + starts = _call_fn_returning_str( + 16, lambda b, bl: _DLL.botan_x509_cert_get_time_starts(self.__obj, b, bl)) + if len(starts) == 13: + # UTC time + struct_time = strptime(starts, "%y%m%d%H%M%SZ") + elif len(starts) == 15: + # Generalized time + struct_time = strptime(starts, "%Y%m%d%H%M%SZ") + else: + raise BotanException("Unexpected date/time format for x509 start time") + + return datetime.fromtimestamp(mktime(struct_time)) + + def time_expires(self): + expires = _call_fn_returning_str( + 16, lambda b, bl: _DLL.botan_x509_cert_get_time_expires(self.__obj, b, bl)) + if len(expires) == 13: + # UTC time + struct_time = strptime(expires, "%y%m%d%H%M%SZ") + elif len(expires) == 15: + # Generalized time + struct_time = strptime(expires, "%Y%m%d%H%M%SZ") + else: + raise BotanException("Unexpected date/time format for x509 expire time") + + return datetime.fromtimestamp(mktime(struct_time)) + + def to_string(self): + return _call_fn_returning_str( + 4096, lambda b, bl: _DLL.botan_x509_cert_to_string(self.__obj, b, bl)) + + def fingerprint(self, hash_algo='SHA-256'): + n = HashFunction(hash_algo).output_length() * 3 + return _call_fn_returning_str( + n, lambda b, bl: _DLL.botan_x509_cert_get_fingerprint(self.__obj, _ctype_str(hash_algo), b, bl)) + + def serial_number(self): + return _call_fn_returning_vec( + 32, lambda b, bl: _DLL.botan_x509_cert_get_serial_number(self.__obj, b, bl)) + + def authority_key_id(self): + return _call_fn_returning_vec( + 32, lambda b, bl: _DLL.botan_x509_cert_get_authority_key_id(self.__obj, b, bl)) + + def subject_key_id(self): + return _call_fn_returning_vec( + 32, lambda b, bl: _DLL.botan_x509_cert_get_subject_key_id(self.__obj, b, bl)) + + def subject_public_key_bits(self): + return _call_fn_returning_vec( + 512, lambda b, bl: _DLL.botan_x509_cert_get_public_key_bits(self.__obj, b, bl)) + + def subject_public_key(self): + pub = c_void_p(0) + _DLL.botan_x509_cert_get_public_key(self.__obj, byref(pub)) + return PublicKey(pub) + + def subject_dn(self, key, index): + return _call_fn_returning_str( + 0, lambda b, bl: _DLL.botan_x509_cert_get_subject_dn(self.__obj, _ctype_str(key), index, b, bl)) + + def issuer_dn(self, key, index): + return _call_fn_returning_str( + 0, lambda b, bl: _DLL.botan_x509_cert_get_issuer_dn(self.__obj, _ctype_str(key), index, b, bl)) + + def hostname_match(self, hostname): + rc = _DLL.botan_x509_cert_hostname_match(self.__obj, _ctype_str(hostname)) + return rc == 0 + + def not_before(self): + time = c_uint64(0) + _DLL.botan_x509_cert_not_before(self.__obj, byref(time)) + return time.value + + def not_after(self): + time = c_uint64(0) + _DLL.botan_x509_cert_not_after(self.__obj, byref(time)) + return time.value + + def allowed_usage(self, usage_list): + usage_values = {"NO_CONSTRAINTS": 0, + "DIGITAL_SIGNATURE": 32768, + "NON_REPUDIATION": 16384, + "KEY_ENCIPHERMENT": 8192, + "DATA_ENCIPHERMENT": 4096, + "KEY_AGREEMENT": 2048, + "KEY_CERT_SIGN": 1024, + "CRL_SIGN": 512, + "ENCIPHER_ONLY": 256, + "DECIPHER_ONLY": 128} + usage = 0 + for u in usage_list: + if u not in usage_values: + return False + usage += usage_values[u] + + rc = _DLL.botan_x509_cert_allowed_usage(self.__obj, c_uint(usage)) + return rc == 0 + + def handle_(self): + return self.__obj + + def verify(self, + intermediates=None, + trusted=None, + trusted_path=None, + required_strength=0, + hostname=None, + reference_time=0, + crls=None): + #pylint: disable=too-many-locals + + if intermediates is not None: + c_intermediates = len(intermediates) * c_void_p + arr_intermediates = c_intermediates() + for i, ca in enumerate(intermediates): + arr_intermediates[i] = ca.handle_() + len_intermediates = c_size_t(len(intermediates)) + else: + arr_intermediates = c_void_p(0) + len_intermediates = c_size_t(0) + + if trusted is not None: + c_trusted = len(trusted) * c_void_p + arr_trusted = c_trusted() + for i, ca in enumerate(trusted): + arr_trusted[i] = ca.handle_() + len_trusted = c_size_t(len(trusted)) + else: + arr_trusted = c_void_p(0) + len_trusted = c_size_t(0) + + if crls is not None: + c_crls = len(crls) * c_void_p + arr_crls = c_crls() + for i, crl in enumerate(crls): + arr_crls[i] = crl.handle_() + len_crls = c_size_t(len(crls)) + else: + arr_crls = c_void_p(0) + len_crls = c_size_t(0) + + error_code = c_int(0) + + _DLL.botan_x509_cert_verify_with_crl(byref(error_code), + self.__obj, + byref(arr_intermediates), + len_intermediates, + byref(arr_trusted), + len_trusted, + byref(arr_crls), + len_crls, + _ctype_str(trusted_path), + c_size_t(required_strength), + _ctype_str(hostname), + c_uint64(reference_time)) + + return error_code.value + + @classmethod + def validation_status(cls, error_code): + return _ctype_to_str(_DLL.botan_x509_cert_validation_status(c_int(error_code))) + + def is_revoked(self, crl): + rc = _DLL.botan_x509_is_revoked(crl.handle_(), self.__obj) + return rc == 0 + + +# +# X.509 Certificate revocation lists +# +class X509CRL(object): + def __init__(self, filename=None, buf=None): + self.__obj = _load_buf_or_file(filename, buf, _DLL.botan_x509_crl_load_file, _DLL.botan_x509_crl_load) + + def __del__(self): + _DLL.botan_x509_crl_destroy(self.__obj) + + def handle_(self): + return self.__obj + + +class MPI(object): # pylint: disable=too-many-public-methods + + def __init__(self, initial_value=None, radix=None): + + self.__obj = c_void_p(0) + _DLL.botan_mp_init(byref(self.__obj)) + + if initial_value is None: + pass # left as zero + elif isinstance(initial_value, MPI): + _DLL.botan_mp_set_from_mp(self.__obj, initial_value.handle_()) + elif radix is not None: + _DLL.botan_mp_set_from_radix_str(self.__obj, _ctype_str(initial_value), c_size_t(radix)) + elif isinstance(initial_value, str): + _DLL.botan_mp_set_from_str(self.__obj, _ctype_str(initial_value)) + else: + # For int or long (or whatever else), try converting to string: + _DLL.botan_mp_set_from_str(self.__obj, _ctype_str(str(initial_value))) + + @classmethod + def random(cls, rng_obj, bits): + bn = MPI() + _DLL.botan_mp_rand_bits(bn.handle_(), rng_obj.handle_(), c_size_t(bits)) + return bn + + @classmethod + def random_range(cls, rng_obj, lower, upper): + bn = MPI() + _DLL.botan_mp_rand_range(bn.handle_(), rng_obj.handle_(), lower.handle_(), upper.handle_()) + return bn + + def __del__(self): + _DLL.botan_mp_destroy(self.__obj) + + def handle_(self): + return self.__obj + + def __int__(self): + out = create_string_buffer(2*self.byte_count() + 1) + _DLL.botan_mp_to_hex(self.__obj, out) + val = int(out.value, 16) + if self.is_negative(): + return -val + else: + return val + + def __repr__(self): + # Should have a better size estimate than this ... + out_len = c_size_t(self.bit_count() // 2) + out = create_string_buffer(out_len.value) + + _DLL.botan_mp_to_str(self.__obj, c_uint8(10), out, byref(out_len)) + + out = out.raw[0:int(out_len.value)] + if out[-1] == '\x00': + out = out[:-1] + s = _ctype_to_str(out) + if s[0] == '0': + return s[1:] + else: + return s + + def to_bytes(self): + byte_count = self.byte_count() + out_len = c_size_t(byte_count) + out = create_string_buffer(out_len.value) + _DLL.botan_mp_to_bin(self.__obj, out, byref(out_len)) + assert out_len.value == byte_count + return out + + def is_negative(self): + rc = _DLL.botan_mp_is_negative(self.__obj) + return rc == 1 + + def is_positive(self): + rc = _DLL.botan_mp_is_positive(self.__obj) + return rc == 1 + + def is_zero(self): + rc = _DLL.botan_mp_is_zero(self.__obj) + return rc == 1 + + def is_odd(self): + return self.get_bit(0) == 1 + + def is_even(self): + return self.get_bit(0) == 0 + + def flip_sign(self): + _DLL.botan_mp_flip_sign(self.__obj) + + def cmp(self, other): + r = c_int(0) + _DLL.botan_mp_cmp(byref(r), self.__obj, other.handle_()) + return r.value + + def __hash__(self): + return hash(self.to_bytes()) + + def __eq__(self, other): + return self.cmp(other) == 0 + + def __ne__(self, other): + return self.cmp(other) != 0 + + def __lt__(self, other): + return self.cmp(other) < 0 + + def __le__(self, other): + return self.cmp(other) <= 0 + + def __gt__(self, other): + return self.cmp(other) > 0 + + def __ge__(self, other): + return self.cmp(other) >= 0 + + def __add__(self, other): + r = MPI() + _DLL.botan_mp_add(r.handle_(), self.__obj, other.handle_()) + return r + + def __iadd__(self, other): + _DLL.botan_mp_add(self.__obj, self.__obj, other.handle_()) + return self + + def __sub__(self, other): + r = MPI() + _DLL.botan_mp_sub(r.handle_(), self.__obj, other.handle_()) + return r + + def __isub__(self, other): + _DLL.botan_mp_sub(self.__obj, self.__obj, other.handle_()) + return self + + def __mul__(self, other): + r = MPI() + _DLL.botan_mp_mul(r.handle_(), self.__obj, other.handle_()) + return r + + def __imul__(self, other): + _DLL.botan_mp_mul(self.__obj, self.__obj, other.handle_()) + return self + + def __divmod__(self, other): + d = MPI() + q = MPI() + _DLL.botan_mp_div(d.handle_(), q.handle_(), self.__obj, other.handle_()) + return (d, q) + + def __mod__(self, other): + d = MPI() + q = MPI() + _DLL.botan_mp_div(d.handle_(), q.handle_(), self.__obj, other.handle_()) + return q + + def __lshift__(self, shift): + shift = c_size_t(shift) + r = MPI() + _DLL.botan_mp_lshift(r.handle_(), self.__obj, shift) + return r + + def __ilshift__(self, shift): + shift = c_size_t(shift) + _DLL.botan_mp_lshift(self.__obj, self.__obj, shift) + return self + + def __rshift__(self, shift): + shift = c_size_t(shift) + r = MPI() + _DLL.botan_mp_rshift(r.handle_(), self.__obj, shift) + return r + + def __irshift__(self, shift): + shift = c_size_t(shift) + _DLL.botan_mp_rshift(self.__obj, self.__obj, shift) + return self + + def mod_mul(self, other, modulus): + r = MPI() + _DLL.botan_mp_mod_mul(r.handle_(), self.__obj, other.handle_(), modulus.handle_()) + return r + + def gcd(self, other): + r = MPI() + _DLL.botan_mp_gcd(r.handle_(), self.__obj, other.handle_()) + return r + + def pow_mod(self, exponent, modulus): + r = MPI() + _DLL.botan_mp_powmod(r.handle_(), self.__obj, exponent.handle_(), modulus.handle_()) + return r + + def is_prime(self, rng_obj, prob=128): + return _DLL.botan_mp_is_prime(self.__obj, rng_obj.handle_(), c_size_t(prob)) == 1 + + def inverse_mod(self, modulus): + r = MPI() + _DLL.botan_mp_mod_inverse(r.handle_(), self.__obj, modulus.handle_()) + return r + + def bit_count(self): + b = c_size_t(0) + _DLL.botan_mp_num_bits(self.__obj, byref(b)) + return b.value + + def byte_count(self): + b = c_size_t(0) + _DLL.botan_mp_num_bytes(self.__obj, byref(b)) + return b.value + + def get_bit(self, bit): + return _DLL.botan_mp_get_bit(self.__obj, c_size_t(bit)) == 1 + + def clear_bit(self, bit): + _DLL.botan_mp_clear_bit(self.__obj, c_size_t(bit)) + + def set_bit(self, bit): + _DLL.botan_mp_set_bit(self.__obj, c_size_t(bit)) + +class FormatPreservingEncryptionFE1(object): + + def __init__(self, modulus, key, rounds=5, compat_mode=False): + flags = c_uint32(1 if compat_mode else 0) + self.__obj = c_void_p(0) + _DLL.botan_fpe_fe1_init(byref(self.__obj), modulus.handle_(), key, len(key), c_size_t(rounds), flags) + + def __del__(self): + _DLL.botan_fpe_destroy(self.__obj) + + def encrypt(self, msg, tweak): + r = MPI(msg) + _DLL.botan_fpe_encrypt(self.__obj, r.handle_(), _ctype_bits(tweak), len(tweak)) + return r + + def decrypt(self, msg, tweak): + r = MPI(msg) + _DLL.botan_fpe_decrypt(self.__obj, r.handle_(), _ctype_bits(tweak), len(tweak)) + return r + +class HOTP(object): + def __init__(self, key, digest="SHA-1", digits=6): + self.__obj = c_void_p(0) + _DLL.botan_hotp_init(byref(self.__obj), key, len(key), _ctype_str(digest), digits) + + def __del__(self): + _DLL.botan_hotp_destroy(self.__obj) + + def generate(self, counter): + code = c_uint32(0) + _DLL.botan_hotp_generate(self.__obj, byref(code), counter) + return code.value + + def check(self, code, counter, resync_range=0): + next_ctr = c_uint64(0) + rc = _DLL.botan_hotp_check(self.__obj, byref(next_ctr), code, counter, resync_range) + if rc == 0: + return (True, next_ctr.value) + else: + return (False, counter) + +class TOTP(object): + def __init__(self, key, digest="SHA-1", digits=6, timestep=30): + self.__obj = c_void_p(0) + _DLL.botan_totp_init(byref(self.__obj), key, len(key), _ctype_str(digest), digits, timestep) + + def __del__(self): + _DLL.botan_totp_destroy(self.__obj) + + def generate(self, timestamp=None): + if timestamp is None: + timestamp = int(system_time()) + code = c_uint32(0) + _DLL.botan_totp_generate(self.__obj, byref(code), timestamp) + return code.value + + def check(self, code, timestamp=None, acceptable_drift=0): + if timestamp is None: + timestamp = int(system_time()) + rc = _DLL.botan_totp_check(self.__obj, code, timestamp, acceptable_drift) + if rc == 0: + return True + return False + +def nist_key_wrap(kek, key): + output = create_string_buffer(len(key) + 8) + out_len = c_size_t(len(output)) + _DLL.botan_key_wrap3394(key, len(key), kek, len(kek), output, byref(out_len)) + return output[0:int(out_len.value)] + +def nist_key_unwrap(kek, wrapped): + output = create_string_buffer(len(wrapped)) + out_len = c_size_t(len(output)) + _DLL.botan_key_unwrap3394(wrapped, len(wrapped), kek, len(kek), output, byref(out_len)) + return output[0:int(out_len.value)] + +# Typedefs for compat with older versions +# Will be removed in a future major release +cipher = SymmetricCipher # pylint: disable=invalid-name +rng = RandomNumberGenerator # pylint: disable=invalid-name +hash_function = HashFunction # pylint: disable=invalid-name +message_authentication_code = MsgAuthCode # pylint: disable=invalid-name + +x509_cert = X509Cert # pylint: disable=invalid-name +public_key = PublicKey # pylint: disable=invalid-name +private_key = PrivateKey # pylint: disable=invalid-name + +pk_op_encrypt = PKEncrypt # pylint: disable=invalid-name +pk_op_decrypt = PKDecrypt # pylint: disable=invalid-name +pk_op_sign = PKSign # pylint: disable=invalid-name +pk_op_verify = PKVerify # pylint: disable=invalid-name +pk_op_key_agreement = PKKeyAgreement # pylint: disable=invalid-name diff --git a/comm/third_party/botan/src/scripts/Dockerfile.android b/comm/third_party/botan/src/scripts/Dockerfile.android new file mode 100644 index 0000000000..124d5d4f6d --- /dev/null +++ b/comm/third_party/botan/src/scripts/Dockerfile.android @@ -0,0 +1,17 @@ +FROM devnexen/android-ndk:r20 AS android-ndk +ARG ANDROID_ARCH +ARG ANDROID_TOOLCHAIN_SUF +ARG ANDROID_ARCH_SUF +ARG ANDROID_SDK_VER +RUN apt-get update && apt-get install -y --no-install-recommends python +RUN mkdir -p /botan/android +WORKDIR /botan +COPY configure.py configure.py +COPY src src +COPY doc doc +COPY license.txt license.txt +COPY news.rst news.rst +ENV PATH=$PATH:/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/ +RUN ./configure.py --prefix=android/arm --os=android --cpu=${ANDROID_ARCH} --cc=clang --cc-bin=${ANDROID_ARCH}${ANDROID_ARCH_SUF}-linux-android${ANDROID_TOOLCHAIN_SUF}${ANDROID_SDK_VER}-clang++ --ar-command=${ANDROID_ARCH}${ANDROID_ARCH_SUF}-linux-android${ANDROID_TOOLCHAIN_SUF}-ar +RUN make -j`getconf _NPROCESSORS_ONLN` +RUN make install diff --git a/comm/third_party/botan/src/scripts/bench.py b/comm/third_party/botan/src/scripts/bench.py new file mode 100755 index 0000000000..1cc626366f --- /dev/null +++ b/comm/third_party/botan/src/scripts/bench.py @@ -0,0 +1,216 @@ +#!/usr/bin/python + +""" +Compare Botan with OpenSSL using their respective benchmark utils + +(C) 2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) + +TODO + - Also compare RSA, ECDSA, ECDH + - Output pretty graphs with matplotlib +""" + +import logging +import os +import sys +import optparse # pylint: disable=deprecated-module +import subprocess +import re +import json + +def setup_logging(options): + if options.verbose: + log_level = logging.DEBUG + elif options.quiet: + log_level = logging.WARNING + else: + log_level = logging.INFO + + class LogOnErrorHandler(logging.StreamHandler, object): + def emit(self, record): + super(LogOnErrorHandler, self).emit(record) + if record.levelno >= logging.ERROR: + sys.exit(1) + + lh = LogOnErrorHandler(sys.stdout) + lh.setFormatter(logging.Formatter('%(levelname) 7s: %(message)s')) + logging.getLogger().addHandler(lh) + logging.getLogger().setLevel(log_level) + +def run_command(cmd): + logging.debug("Running '%s'", ' '.join(cmd)) + + proc = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + stdout, stderr = proc.communicate() + + if proc.returncode != 0: + logging.error("Running command %s failed ret %d", ' '.join(cmd), proc.returncode) + + return stdout + stderr + +def get_openssl_version(openssl): + output = run_command([openssl, 'version']) + + openssl_version_re = re.compile(r'OpenSSL ([0-9a-z\.]+) .*') + + match = openssl_version_re.match(output) + + if match: + return match.group(1) + else: + logging.warning("Unable to parse OpenSSL version output %s", output) + return output + +def get_botan_version(botan): + return run_command([botan, 'version']).strip() + +EVP_MAP = { + 'Blowfish': 'bf-ecb', + 'AES-128/GCM': 'aes-128-gcm', + 'AES-256/GCM': 'aes-256-gcm', + 'ChaCha20': 'chacha20', + 'MD5': 'md5', + 'SHA-1': 'sha1', + 'RIPEMD-160': 'ripemd160', + 'SHA-256': 'sha256', + 'SHA-384': 'sha384', + 'SHA-512': 'sha512' + } + +def run_openssl_bench(openssl, algo): + + logging.info('Running OpenSSL benchmark for %s', algo) + + cmd = [openssl, 'speed', '-mr'] + + if algo in EVP_MAP: + cmd += ['-evp', EVP_MAP[algo]] + else: + cmd += [algo] + + output = run_command(cmd) + + buf_header = re.compile(r'\+DT:([a-z0-9-]+):([0-9]+):([0-9]+)$') + res_header = re.compile(r'\+R:([0-9]+):[a-z0-9-]+:([0-9]+\.[0-9]+)$') + ignored = re.compile(r'\+(H|F):.*') + + results = [] + + result = None + + for l in output.splitlines(): + if ignored.match(l): + continue + + if result is None: + match = buf_header.match(l) + if match is None: + logging.error("Unexpected output from OpenSSL %s", l) + + result = {'algo': algo, 'buf_size': int(match.group(3))} + else: + match = res_header.match(l) + + result['bytes'] = int(match.group(1)) * result['buf_size'] + result['runtime'] = float(match.group(2)) + result['bps'] = int(result['bytes'] / result['runtime']) + results.append(result) + result = None + + return results + +def run_botan_bench(botan, runtime, buf_sizes, algo): + + runtime = .05 + + cmd = [botan, 'speed', '--format=json', '--msec=%d' % int(runtime * 1000), + '--buf-size=%s' % (','.join([str(i) for i in buf_sizes])), algo] + output = run_command(cmd) + output = json.loads(output) + + return output + +class BenchmarkResult(object): + def __init__(self, algo, buf_sizes, openssl_results, botan_results): + self.algo = algo + self.results = {} + + def find_result(results, sz): + for r in results: + if 'buf_size' in r and r['buf_size'] == sz: + return r['bps'] + raise Exception("Could not find expected result in data") + + for buf_size in buf_sizes: + self.results[buf_size] = { + 'openssl': find_result(openssl_results, buf_size), + 'botan': find_result(botan_results, buf_size) + } + + def result_string(self): + + out = "" + for (k, v) in self.results.items(): + out += "algo %s buf_size % 6d botan % 12d bps openssl % 12d bps adv %.02f\n" % ( + self.algo, k, v['botan'], v['openssl'], float(v['botan']) / v['openssl']) + return out + +def bench_algo(openssl, botan, algo): + openssl_results = run_openssl_bench(openssl, algo) + + buf_sizes = sorted([x['buf_size'] for x in openssl_results]) + runtime = sum(x['runtime'] for x in openssl_results) / len(openssl_results) + + botan_results = run_botan_bench(botan, runtime, buf_sizes, algo) + + return BenchmarkResult(algo, buf_sizes, openssl_results, botan_results) + +def main(args=None): + if args is None: + args = sys.argv + + parser = optparse.OptionParser() + + parser.add_option('--verbose', action='store_true', default=False, help="be noisy") + parser.add_option('--quiet', action='store_true', default=False, help="be very quiet") + + parser.add_option('--openssl-cli', metavar='PATH', + default='/usr/bin/openssl', + help='Path to openssl binary (default %default)') + + parser.add_option('--botan-cli', metavar='PATH', + default='/usr/bin/botan', + help='Path to botan binary (default %default)') + + (options, args) = parser.parse_args(args) + + setup_logging(options) + + openssl = options.openssl_cli + botan = options.botan_cli + + if os.access(openssl, os.X_OK) is False: + logging.error("Unable to access openssl binary at %s", openssl) + + if os.access(botan, os.X_OK) is False: + logging.error("Unable to access botan binary at %s", botan) + + openssl_version = get_openssl_version(openssl) + botan_version = get_botan_version(botan) + + logging.info("Comparing Botan %s with OpenSSL %s", botan_version, openssl_version) + + for algo in sorted(EVP_MAP.keys()): + result = bench_algo(openssl, botan, algo) + print(result.result_string()) + + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/build_docs.py b/comm/third_party/botan/src/scripts/build_docs.py new file mode 100755 index 0000000000..6eb9b656c9 --- /dev/null +++ b/comm/third_party/botan/src/scripts/build_docs.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python + +""" +Botan doc generation script + +(C) 2014,2015,2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import sys +import optparse # pylint: disable=deprecated-module +import subprocess +import shutil +import logging +import json +import tempfile +import os +import stat + +def get_concurrency(): + """ + Get default concurrency level of build + """ + def_concurrency = 2 + + try: + import multiprocessing + return max(def_concurrency, multiprocessing.cpu_count()) + except ImportError: + return def_concurrency + +def have_prog(prog): + """ + Check if some named program exists in the path + """ + for path in os.environ['PATH'].split(os.pathsep): + exe_file = os.path.join(path, prog) + if os.path.exists(exe_file) and os.access(exe_file, os.X_OK): + return True + return False + +def find_rst2man(): + possible_names = ['rst2man', 'rst2man.py'] + + for name in possible_names: + if have_prog(name): + return name + raise Exception("Was configured with rst2man but could not be located in PATH") + +def touch(fname): + try: + os.utime(fname, None) + except OSError: + open(fname, 'a').close() + +def copy_files(src_path, dest_dir): + + logging.debug("Copying %s to %s", src_path, dest_dir) + + file_mode = os.stat(src_path).st_mode + + try: + os.mkdir(dest_dir) + except OSError: + pass + + if stat.S_ISREG(file_mode): + logging.debug("Copying file %s to %s", src_path, dest_dir) + shutil.copy(src_path, dest_dir) + else: + for f in os.listdir(src_path): + src_file = os.path.join(src_path, f) + file_mode = os.stat(src_file).st_mode + if stat.S_ISREG(file_mode): + dest_file = os.path.join(dest_dir, f) + shutil.copyfile(src_file, dest_file) + elif stat.S_ISDIR(file_mode): + copy_files(os.path.join(src_path, f), os.path.join(dest_dir, f)) + +def run_and_check(cmd_line, cwd=None): + + logging.info("Starting %s", ' '.join(cmd_line)) + + try: + proc = subprocess.Popen(cmd_line, cwd=cwd) + + proc.communicate() + except OSError as e: + logging.error("Executing %s failed (%s)", ' '.join(cmd_line), e) + + if proc.returncode != 0: + logging.error("Error running %s", ' '.join(cmd_line)) + sys.exit(1) + + +def parse_options(args): + parser = optparse.OptionParser() + + parser.add_option('--verbose', action='store_true', default=False, + help='Show debug messages') + parser.add_option('--quiet', action='store_true', default=False, + help='Show only warnings and errors') + + parser.add_option('--build-dir', metavar='DIR', default='build', + help='Location of build output (default \'%default\')') + parser.add_option('--dry-run', default=False, action='store_true', + help='Just display what would be done') + + (options, args) = parser.parse_args(args) + + if len(args) > 1: + logging.error("Unknown arguments") + return None + + def log_level(): + if options.verbose: + return logging.DEBUG + if options.quiet: + return logging.WARNING + return logging.INFO + + logging.getLogger().setLevel(log_level()) + + return options + +def sphinx_supports_concurrency(): + import re + from distutils.version import StrictVersion + + proc = subprocess.Popen(['sphinx-build', '--version'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + output, _ = proc.communicate() + if isinstance(output, bytes): + output = output.decode('ascii') + output = output.strip() + + # Sphinx v1.1.3 + # sphinx-build 1.7.4 + match = re.match(r'^(?:[a-zA-Z_-]+) v?(([0-9]+)\.([0-9]+))', output) + + if match is None: + # If regex doesn't match, disable by default + logging.warning("Did not recognize sphinx version from '%s'", output) + return False + + version = StrictVersion(match.group(1)) + + if version < StrictVersion('1.4'): + # not supported + return False + if version == StrictVersion('3.0'): + # Bug in Sphinx 3.0 https://github.com/sphinx-doc/sphinx/issues/7438 + return False + return True + +def read_config(config): + try: + f = open(config) + cfg = json.load(f) + f.close() + except OSError: + raise Exception('Failed to load build config %s - is build dir correct?' % (config)) + + return cfg + +def main(args=None): + # pylint: disable=too-many-branches + + if args is None: + args = sys.argv + + logging.basicConfig(stream=sys.stdout, + format='%(levelname) 7s: %(message)s') + + options = parse_options(args) + + if options is None: + return 1 + + cfg = read_config(os.path.join(options.build_dir, 'build_config.json')) + + with_docs = bool(cfg['with_documentation']) + with_sphinx = bool(cfg['with_sphinx']) + with_pdf = bool(cfg['with_pdf']) + with_rst2man = bool(cfg['with_rst2man']) + with_doxygen = bool(cfg['with_doxygen']) + + doc_stamp_file = cfg['doc_stamp_file'] + + handbook_src = cfg['doc_dir'] + handbook_output = cfg['handbook_output_dir'] + + if with_docs is False: + logging.debug('Documentation build disabled') + return 0 + + cmds = [] + + if with_doxygen: + cmds.append(['doxygen', os.path.join(cfg['build_dir'], 'botan.doxy')]) + + if with_sphinx: + sphinx_build = ['sphinx-build', '-q', '-c', cfg['sphinx_config_dir']] + if sphinx_supports_concurrency(): + sphinx_build += ['-j', str(get_concurrency())] + + cmds.append(sphinx_build + ['-b', 'html', handbook_src, handbook_output]) + + if with_pdf: + latex_output = tempfile.mkdtemp(prefix='botan_latex_') + cmds.append(sphinx_build + ['-b', 'latex', handbook_src, latex_output]) + cmds.append(['make', '-C', latex_output]) + cmds.append(['cp', os.path.join(latex_output, 'botan.pdf'), handbook_output]) + else: + # otherwise just copy it + cmds.append(['cp', handbook_src, handbook_output]) + + if with_rst2man: + cmds.append([find_rst2man(), + os.path.join(cfg['build_dir'], 'botan.rst'), + os.path.join(cfg['build_dir'], 'botan.1')]) + + cmds.append(['touch', doc_stamp_file]) + + for cmd in cmds: + if options.dry_run: + print(' '.join(cmd)) + else: + if cmd[0] == 'cp': + assert len(cmd) == 3 + copy_files(cmd[1], cmd[2]) + elif cmd[0] == 'touch': + assert len(cmd) == 2 + touch(cmd[1]) + else: + run_and_check(cmd) + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/check.py b/comm/third_party/botan/src/scripts/check.py new file mode 100644 index 0000000000..ea80d552d2 --- /dev/null +++ b/comm/third_party/botan/src/scripts/check.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +""" +Implements the "make check" target + +(C) 2020 Jack Lloyd, Rene Meusel + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import json +import logging +import optparse # pylint: disable=deprecated-module +import os +import subprocess +import sys + +def run_and_check(cmd_line, env=None, cwd=None): + + logging.info("Starting %s", ' '.join(cmd_line)) + + try: + proc = subprocess.Popen(cmd_line, cwd=cwd, env=env) + proc.communicate() + except OSError as e: + logging.error("Executing %s failed (%s)", ' '.join(cmd_line), e) + + if proc.returncode != 0: + logging.error("Error running %s", ' '.join(cmd_line)) + sys.exit(1) + + +def make_environment(build_shared_lib): + if not build_shared_lib: + return None + + env = os.environ.copy() + + def extend_colon_list(k, n): + env[k] = n if k not in env else ":".join([env[k], n]) + + extend_colon_list("DYLD_LIBRARY_PATH", os.path.abspath(".")) + extend_colon_list("LD_LIBRARY_PATH", os.path.abspath(".")) + + return env + + +def parse_options(args): + parser = optparse.OptionParser() + parser.add_option('--build-dir', default='build', metavar='DIR', + help='specify the botan build directory (default %default)') + + (options, args) = parser.parse_args(args) + + if len(args) > 1: + raise Exception("Unknown arguments") + + return options + + +def read_config(config): + try: + with open(config) as f: + return json.load(f) + except OSError: + raise Exception('Failed to load build config %s - is build dir correct?' % (config)) + + +def main(args=None): + if args is None: + args = sys.argv + + options = parse_options(args) + + cfg = read_config(os.path.join(options.build_dir, 'build_config.json')) + + test_exe = cfg.get('test_exe') + build_shared_lib = cfg.get('build_shared_lib') + + if not os.path.isfile(test_exe) or not os.access(test_exe, os.X_OK): + raise Exception("Test binary not built") + + run_and_check([test_exe, "--data-dir=%s" % cfg.get('test_data_dir')], + make_environment(build_shared_lib)) + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/ci/appveyor.yml b/comm/third_party/botan/src/scripts/ci/appveyor.yml new file mode 100644 index 0000000000..35345841a4 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/appveyor.yml @@ -0,0 +1,90 @@ + +clone_depth: 5 + +environment: + SCCACHE_CACHE_SIZE: 160M + SCCACHE_VERSION: 0.2.12 + APPVEYOR_SAVE_CACHE_ON_ERROR: true + + matrix: + + # MSVC 2015 DLL x86-32 + - CC: VC2015 + PLATFORM: x86 + TARGET: shared + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + BOOST_ROOT: "C:\\Libraries\\boost_1_69_0" + BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib32-msvc-14.0" + BOOST_SYSTEM_LIBRARY: "libboost_system-vc140-mt-x32-1_69" + MAKE_TOOL: nmake + TARGET_CC: msvc + EXTRA_FLAGS: "--disable-werror" + DISABLED_TESTS: "certstor_system" # requires 'ISRG Root X1' / not in this AppVeyor image + + # MSVC 2017 DLL x86-32 + - CC: VC2017 + PLATFORM: x86 + TARGET: shared + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + BOOST_ROOT: "C:\\Libraries\\boost_1_69_0" + BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib32-msvc-14.1" + BOOST_SYSTEM_LIBRARY: "libboost_system-vc141-mt-x32-1_69" + MAKE_TOOL: jom + TARGET_CC: msvc + DISABLED_TESTS: "certstor_system" # requires 'ISRG Root X1' / not in this AppVeyor image + + # MSVC 2017 DLL x86-64 + - CC: VC2017 + PLATFORM: x86_amd64 + TARGET: shared + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + BOOST_ROOT: "C:\\Libraries\\boost_1_69_0" + BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib64-msvc-14.1" + BOOST_SYSTEM_LIBRARY: "libboost_system-vc141-mt-x64-1_69" + MAKE_TOOL: jom + TARGET_CC: msvc + DISABLED_TESTS: "certstor_system" # requires 'ISRG Root X1' / not in this AppVeyor image + + # MSVC 2017 static x86-64 + - CC: VC2017 + PLATFORM: x86_amd64 + TARGET: static + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + BOOST_ROOT: "C:\\Libraries\\boost_1_69_0" + BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib64-msvc-14.1" + BOOST_SYSTEM_LIBRARY: "libboost_system-vc141-mt-x64-1_69" + MAKE_TOOL: jom + TARGET_CC: msvc + EXTRA_FLAGS: "--extra-cxxflags=/DUNICODE --extra-cxxflags=/D_UNICODE" + DISABLED_TESTS: "certstor_system" # requires 'ISRG Root X1' / not in this AppVeyor image + + # MSVC 2019 static x86-64 w/debug iterators + - CC: VC2019 + PLATFORM: x86_amd64 + TARGET: sanitizer + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + MAKE_TOOL: jom + TARGET_CC: msvc + + # MinGW GCC + - CC: MinGW + PLATFORM: x86_amd64 + TARGET: static + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + MAKE_TOOL: mingw32-make + TARGET_CC: gcc + +install: + - call src\scripts\ci\setup_appveyor.bat + +build_script: + - python src\scripts\ci_build.py --os=windows --cc=%TARGET_CC% --without-python3 --compiler-cache=sccache --make-tool=%MAKE_TOOL% --cpu=%PLATFORM% --disabled-tests=%DISABLED_TESTS% %EXTRA_FLAGS% %TARGET% + +# whitelist branches to avoid testing feature branches twice (as branch and as pull request) +branches: + only: + - master + - release-2 + +cache: + - C:\Users\appveyor\AppData\Local\Mozilla\sccache\cache diff --git a/comm/third_party/botan/src/scripts/ci/codecov.yml b/comm/third_party/botan/src/scripts/ci/codecov.yml new file mode 100644 index 0000000000..db26a6bd55 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/codecov.yml @@ -0,0 +1,15 @@ +--- + +# Documentation +# https://github.com/codecov/support/wiki/Codecov-Yaml#full-yaml +# +# Validate this file +# curl --data-binary @codecov.yml https://codecov.io/validate + +coverage: + status: + project: + default: + # Random seeds in tests lead to a +/-0.05% coverage span even for PRs + # that do not change source code + threshold: 0.05 diff --git a/comm/third_party/botan/src/scripts/ci/lgtm.yml b/comm/third_party/botan/src/scripts/ci/lgtm.yml new file mode 100644 index 0000000000..fa2423858b --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/lgtm.yml @@ -0,0 +1,31 @@ + +queries: + - include: cpp/inconsistent-null-check + - include: cpp/overrunning-write + - include: cpp/unbounded-write + - include: cpp/offset-use-before-range-check + - include: cpp/incomplete-parity-check + - include: cpp/mistyped-function-arguments + - include: cpp/comparison-with-wider-type + - include: cpp/inconsistent-call-on-result + - include: cpp/incorrect-not-operator-usage + - include: cpp/stack-address-escape + - include: cpp/nested-loops-with-same-variable + - include: cpp/suspicious-allocation-size + - include: cpp/allocation-too-small + - include: cpp/uninitialized-local + - include: cpp/static-buffer-overflow + - include: cpp/suspicious-sizeof + - include: cpp/suspicious-pointer-scaling-void + - include: cpp/declaration-hides-variable + - include: cpp/empty-if + - include: cpp/unused-local-variable + - include: cpp/unused-static-function + - include: cpp/unused-static-variable + - exclude: cpp/fixme-comment + +extraction: + cpp: + configure: + command: + - ./configure.py --build-targets="static,shared,cli,tests,bogo_shim" --build-fuzzers=test --with-zlib --with-bzip2 --with-lzma --with-openssl --with-sqlite3 --no-store-vc-rev diff --git a/comm/third_party/botan/src/scripts/ci/setup_appveyor.bat b/comm/third_party/botan/src/scripts/ci/setup_appveyor.bat new file mode 100644 index 0000000000..5b48e78d8f --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/setup_appveyor.bat @@ -0,0 +1,19 @@ + +echo Current build setup CC="%CC%" PLATFORM="%PLATFORM%" TARGET="%TARGET%" + +if %CC% == VC2015 call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %PLATFORM% +if %CC% == VC2017 call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% +if %CC% == VC2019 call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% +if %CC% == MinGW set PATH=%PATH%;C:\msys64\mingw64\bin + +rem check compiler version +if %CC% == MinGW g++ -v +if not %CC% == MinGW cl + +appveyor DownloadFile https://github.com/mozilla/sccache/releases/download/%SCCACHE_VERSION%/sccache-%SCCACHE_VERSION%-x86_64-pc-windows-msvc.tar.gz +tar -xf sccache-%SCCACHE_VERSION%-x86_64-pc-windows-msvc.tar.gz + +appveyor DownloadFile http://download.qt.io/official_releases/jom/jom.zip -FileName jom.zip +7z e jom.zip + +set PATH=%PATH%;sccache-%SCCACHE_VERSION%-x86_64-pc-windows-msvc diff --git a/comm/third_party/botan/src/scripts/ci/setup_gh_actions.sh b/comm/third_party/botan/src/scripts/ci/setup_gh_actions.sh new file mode 100755 index 0000000000..33737ffe37 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/setup_gh_actions.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# GitHub Actions setup script for Botan build +# +# (C) 2015,2017 Simon Warta +# (C) 2016,2017,2018,2020 Jack Lloyd +# +# Botan is released under the Simplified BSD License (see license.txt) + +command -v shellcheck > /dev/null && shellcheck "$0" # Run shellcheck on this if available + +set -ex + +TARGET=$1 + +if type -p "apt-get"; then + sudo apt-get -qq update + sudo apt-get -qq install ccache + + if [ "$TARGET" = "valgrind" ]; then + sudo apt-get -qq install valgrind + + elif [ "$TARGET" = "clang" ]; then + sudo apt-get -qq install clang + + elif [ "$TARGET" = "cross-i386" ]; then + sudo apt-get -qq install g++-multilib linux-libc-dev libc6-dev-i386 + + elif [ "$TARGET" = "cross-win64" ]; then + sudo apt-get -qq install wine-development g++-mingw-w64-x86-64 + + elif [ "$TARGET" = "cross-arm64" ]; then + sudo apt-get -qq install qemu-user g++-aarch64-linux-gnu + + elif [ "$TARGET" = "cross-ppc64" ]; then + sudo apt-get -qq install qemu-user g++-powerpc64le-linux-gnu + + elif [ "$TARGET" = "cross-android-arm32" ] || [ "$TARGET" = "cross-android-arm64" ]; then + wget -nv https://dl.google.com/android/repository/"$ANDROID_NDK"-linux-x86_64.zip + unzip -qq "$ANDROID_NDK"-linux-x86_64.zip + + elif [ "$TARGET" = "baremetal" ]; then + sudo apt-get -qq install gcc-arm-none-eabi libstdc++-arm-none-eabi-newlib + + echo 'extern "C" void __sync_synchronize() {}' >> src/tests/main.cpp + echo 'extern "C" void __sync_synchronize() {}' >> src/cli/main.cpp + + elif [ "$TARGET" = "lint" ]; then + sudo apt-get -qq install pylint + + elif [ "$TARGET" = "coverage" ]; then + sudo apt-get -qq install g++-8 softhsm2 libtspi-dev lcov python-coverage libboost-all-dev gdb + pip install --user codecov + echo "$HOME/.local/bin" >> "$GITHUB_PATH" + + git clone --depth 1 --branch runner-changes https://github.com/randombit/boringssl.git + + sudo chgrp -R "$(id -g)" /var/lib/softhsm/ /etc/softhsm + sudo chmod g+w /var/lib/softhsm/tokens + + softhsm2-util --init-token --free --label test --pin 123456 --so-pin 12345678 + echo "PKCS11_LIB=/usr/lib/softhsm/libsofthsm2.so" >> "$GITHUB_ENV" + + elif [ "$TARGET" = "docs" ]; then + sudo apt-get -qq install doxygen python-docutils python3-sphinx + fi +else + HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache +fi diff --git a/comm/third_party/botan/src/scripts/ci/setup_travis.sh b/comm/third_party/botan/src/scripts/ci/setup_travis.sh new file mode 100755 index 0000000000..f039e574dd --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/setup_travis.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# Travis CI setup script for Botan build +# +# (C) 2015,2017 Simon Warta +# (C) 2016,2017,2018 Jack Lloyd + +command -v shellcheck > /dev/null && shellcheck "$0" # Run shellcheck on this if available + +set -ev + +if [ "$TRAVIS_OS_NAME" = "linux" ]; then + + if [ "$TARGET" = "valgrind" ]; then + sudo apt-get -qq update + sudo apt-get install valgrind + + elif [ "$TARGET" = "gcc4.8" ]; then + sudo apt-get -qq update + sudo apt-get install g++-4.8 + + elif [ "$TARGET" = "clang8" ]; then + sudo apt-get -qq update + sudo apt-get install clang-8 + + elif [ "$TARGET" = "cross-i386" ]; then + sudo apt-get -qq update + sudo apt-get install g++-multilib linux-libc-dev libc6-dev-i386 + + elif [ "$TARGET" = "cross-win64" ]; then + sudo apt-get -qq update + sudo apt-get install wine-development g++-mingw-w64-x86-64 + + elif [ "$TARGET" = "cross-arm32" ]; then + sudo dpkg --add-architecture armhf + sudo apt-get -qq update + sudo apt-get install g++-arm-linux-gnueabihf + sudo apt-get install -o APT::Immediate-Configure=0 libc6:armhf libstdc++6:armhf + + elif [ "$TARGET" = "cross-arm64" ]; then + sudo apt-get -qq update + sudo apt-get install qemu-user g++-aarch64-linux-gnu + + elif [ "$TARGET" = "cross-ppc32" ]; then + sudo apt-get -qq update + sudo apt-get install qemu-user g++-powerpc-linux-gnu + + elif [ "$TARGET" = "cross-ppc64" ]; then + sudo apt-get -qq update + sudo apt-get install qemu-user g++-powerpc64le-linux-gnu + + elif [ "$TARGET" = "cross-mips64" ]; then + sudo apt-get -qq update + sudo apt-get install qemu-user g++-mips64-linux-gnuabi64 + + elif [ "$TARGET" = "cross-android-arm32" ] || [ "$TARGET" = "cross-android-arm64" ]; then + wget -nv https://dl.google.com/android/repository/"$ANDROID_NDK"-linux-x86_64.zip + unzip -qq "$ANDROID_NDK"-linux-x86_64.zip + + elif [ "$TARGET" = "baremetal" ]; then + sudo apt-get -qq update + sudo apt-get install gcc-arm-none-eabi libstdc++-arm-none-eabi-newlib + + echo 'extern "C" void __sync_synchronize() {}' >> src/tests/main.cpp + echo 'extern "C" void __sync_synchronize() {}' >> src/cli/main.cpp + + elif [ "$TARGET" = "lint" ]; then + sudo apt-get -qq update + sudo apt-get install pylint + + elif [ "$TARGET" = "coverage" ]; then + sudo apt-get -qq update + sudo apt-get install g++-8 softhsm2 libtspi-dev lcov python-coverage libboost-all-dev gdb + pip install --user codecov + git clone --depth 1 --branch runner-changes-golang1.10 https://github.com/randombit/boringssl.git + + sudo chgrp -R "$(id -g)" /var/lib/softhsm/ /etc/softhsm + sudo chmod g+w /var/lib/softhsm/tokens + + softhsm2-util --init-token --free --label test --pin 123456 --so-pin 12345678 + + elif [ "$TARGET" = "docs" ]; then + sudo apt-get -qq update + sudo apt-get install doxygen python-docutils python3-sphinx + fi + +elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache +fi diff --git a/comm/third_party/botan/src/scripts/ci/travis.yml b/comm/third_party/botan/src/scripts/ci/travis.yml new file mode 100644 index 0000000000..15609864c4 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci/travis.yml @@ -0,0 +1,50 @@ +language: cpp +os: linux +dist: focal +compiler: gcc + +jobs: + include: + - name: Linux ppc64le (GCC) + arch: ppc64le + env: + - TARGET="shared" + + - name: Linux arm64 (GCC) + arch: arm64 + env: + - TARGET="shared" + + - name: Linux GCC 4.8 + dist: bionic + env: + - TARGET="gcc4.8" + - EXTRA_FLAGS="--disable-werror" + +install: + - ./src/scripts/ci/setup_travis.sh + +script: + - ./src/scripts/ci_build.py --os=$TRAVIS_OS_NAME --cc=$CC --cc-bin=$CXX --without-pylint3 --pkcs11-lib=$PKCS11_LIB $EXTRA_FLAGS $TARGET + +# whitelist branches to avoid testing feature branches twice (as branch and as pull request) +branches: + only: + - master + - release-2 + - coverity_scan + +git: + depth: 10 + +cache: + ccache: true + +addons: + coverity_scan: + project: + name: "randombit/botan" + notification_email: jack@randombit.net + build_command_prepend: "./configure.py --no-optimizations --with-zlib --with-openssl" + build_command: "make -j2" + branch_pattern: coverity_scan diff --git a/comm/third_party/botan/src/scripts/ci_build.py b/comm/third_party/botan/src/scripts/ci_build.py new file mode 100755 index 0000000000..93a5ec3626 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci_build.py @@ -0,0 +1,620 @@ +#!/usr/bin/env python + +""" +CI build script +(C) 2017,2020 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import os +import platform +import subprocess +import sys +import time +import tempfile +import optparse # pylint: disable=deprecated-module + +def get_concurrency(): + def_concurrency = 2 + + try: + import multiprocessing + return multiprocessing.cpu_count() + except ImportError: + return def_concurrency + +def build_targets(target, target_os): + if target in ['shared', 'minimized', 'bsi', 'nist']: + yield 'shared' + elif target in ['static', 'fuzzers', 'baremetal']: + yield 'static' + elif target_os in ['windows']: + yield 'shared' + elif target_os in ['ios', 'mingw']: + yield 'static' + else: + yield 'shared' + yield 'static' + + yield 'cli' + yield 'tests' + + if target in ['coverage']: + yield 'bogo_shim' + +def determine_flags(target, target_os, target_cpu, target_cc, cc_bin, + ccache, root_dir, pkcs11_lib, use_gdb, disable_werror, extra_cxxflags, + disabled_tests): + # pylint: disable=too-many-branches,too-many-statements,too-many-arguments,too-many-locals + + """ + Return the configure.py flags as well as make/test running prefixes + """ + is_cross_target = target.startswith('cross-') + + if target_os not in ['linux', 'osx', 'windows', 'freebsd']: + print('Error unknown OS %s' % (target_os)) + return (None, None, None) + + if is_cross_target: + if target_os == 'osx': + target_os = 'ios' + elif target == 'cross-win64': + target_os = 'mingw' + elif target in ['cross-android-arm32', 'cross-android-arm64']: + target_os = 'android' + + if target_os == 'windows' and target_cc == 'gcc': + target_os = 'mingw' + + if target == 'baremetal': + target_os = 'none' + + make_prefix = [] + test_prefix = [] + test_cmd = [os.path.join(root_dir, 'botan-test')] + + install_prefix = tempfile.mkdtemp(prefix='botan-install-') + + flags = ['--prefix=%s' % (install_prefix), + '--cc=%s' % (target_cc), + '--os=%s' % (target_os), + '--build-targets=%s' % ','.join(build_targets(target, target_os))] + + if ccache is not None: + flags += ['--no-store-vc-rev', '--compiler-cache=%s' % (ccache)] + + if target_os != 'osx' and not disable_werror: + flags += ['--werror-mode'] + + if target_cpu is not None: + flags += ['--cpu=%s' % (target_cpu)] + + for flag in extra_cxxflags: + flags += ['--extra-cxxflags=%s' % (flag)] + + if target in ['minimized']: + flags += ['--minimized-build', '--enable-modules=system_rng,sha2_32,sha2_64,aes'] + + if target in ['bsi', 'nist']: + # tls is optional for bsi/nist but add it so verify tests work with these minimized configs + flags += ['--module-policy=%s' % (target), '--enable-modules=tls'] + + if target == 'docs': + flags += ['--with-doxygen', '--with-sphinx', '--with-rst2man'] + test_cmd = None + + if target == 'cross-win64': + # this test compiles under MinGW but fails when run under Wine + disabled_tests.append('certstor_system') + + if target == 'coverage': + flags += ['--with-coverage-info', '--with-debug-info', '--test-mode'] + + if target == 'valgrind': + flags += ['--with-valgrind'] + test_prefix = ['valgrind', '--error-exitcode=9', '-v', '--leak-check=full', '--show-reachable=yes'] + # valgrind is single threaded anyway + test_cmd += ['--test-threads=1'] + # valgrind is slow + slow_tests = [ + 'cryptobox', 'dh_invalid', 'dh_kat', 'dh_keygen', + 'dl_group_gen', 'dlies', 'dsa_param', 'ecc_basemul', + 'ecdsa_verify_wycheproof', 'mce_keygen', 'passhash9', + 'rsa_encrypt', 'rsa_pss', 'rsa_pss_raw', 'scrypt', + 'srp6_kat', 'x509_path_bsi', 'xmss_keygen', 'xmss_sign', + 'pbkdf', 'argon2', 'bcrypt', 'bcrypt_pbkdf', 'compression', + 'ed25519_sign', 'elgamal_keygen', 'x509_path_rsa_pss'] + + disabled_tests += slow_tests + + if target == 'fuzzers': + flags += ['--unsafe-fuzzer-mode'] + + if target in ['fuzzers', 'coverage']: + flags += ['--build-fuzzers=test'] + + if target in ['fuzzers', 'sanitizer']: + flags += ['--with-debug-asserts'] + + if target_cc in ['clang', 'gcc']: + flags += ['--enable-sanitizers=address,undefined'] + else: + flags += ['--with-sanitizers'] + + if target in ['valgrind', 'sanitizer', 'fuzzers']: + flags += ['--disable-modules=locking_allocator'] + + if target == 'baremetal': + cc_bin = 'arm-none-eabi-c++' + flags += ['--cpu=arm32', '--disable-neon', '--without-stack-protector', '--ldflags=-specs=nosys.specs'] + test_cmd = None + + if is_cross_target: + if target_os == 'ios': + make_prefix = ['xcrun', '--sdk', 'iphoneos'] + test_cmd = None + if target == 'cross-ios-arm64': + flags += ['--cpu=arm64', '--cc-abi-flags=-arch arm64 -stdlib=libc++'] + else: + raise Exception("Unknown cross target '%s' for iOS" % (target)) + elif target_os == 'android': + + ndk = os.getenv('ANDROID_NDK') + if ndk is None: + raise Exception('Android CI build requires ANDROID_NDK env variable be set') + + api_lvl = int(os.getenv('ANDROID_API_LEVEL', '0')) + if api_lvl == 0: + # If not set arbitrarily choose API 16 (Android 4.1) for ARMv7 and 28 (Android 9) for AArch64 + api_lvl = 16 if target == 'cross-android-arm32' else 28 + + toolchain_dir = os.path.join(ndk, 'toolchains/llvm/prebuilt/linux-x86_64/bin') + test_cmd = None + + if target == 'cross-android-arm32': + cc_bin = os.path.join(toolchain_dir, 'armv7a-linux-androideabi%d-clang++' % (api_lvl)) + flags += ['--cpu=armv7', + '--ar-command=%s' % (os.path.join(toolchain_dir, 'arm-linux-androideabi-ar'))] + elif target == 'cross-android-arm64': + cc_bin = os.path.join(toolchain_dir, 'aarch64-linux-android%d-clang++' % (api_lvl)) + flags += ['--cpu=arm64', + '--ar-command=%s' % (os.path.join(toolchain_dir, 'aarch64-linux-android-ar'))] + + if api_lvl < 18: + flags += ['--without-os-features=getauxval'] + if api_lvl >= 28: + flags += ['--with-os-features=getentropy'] + + elif target == 'cross-i386': + flags += ['--cpu=x86_32'] + + elif target == 'cross-win64': + # MinGW in 16.04 is lacking std::mutex for unknown reason + cc_bin = 'x86_64-w64-mingw32-g++' + flags += ['--cpu=x86_64', '--cc-abi-flags=-static', + '--ar-command=x86_64-w64-mingw32-ar', '--without-os-feature=threads'] + test_cmd = [os.path.join(root_dir, 'botan-test.exe')] + test_cmd[1:] + test_prefix = ['wine'] + else: + if target == 'cross-arm32': + flags += ['--cpu=armv7'] + cc_bin = 'arm-linux-gnueabihf-g++' + # Currently arm32 CI only runs on native AArch64 + #test_prefix = ['qemu-arm', '-L', '/usr/arm-linux-gnueabihf/'] + elif target == 'cross-arm64': + flags += ['--cpu=aarch64'] + cc_bin = 'aarch64-linux-gnu-g++' + test_prefix = ['qemu-aarch64', '-L', '/usr/aarch64-linux-gnu/'] + elif target == 'cross-ppc32': + flags += ['--cpu=ppc32'] + cc_bin = 'powerpc-linux-gnu-g++' + test_prefix = ['qemu-ppc', '-L', '/usr/powerpc-linux-gnu/'] + elif target == 'cross-ppc64': + flags += ['--cpu=ppc64', '--with-endian=little'] + cc_bin = 'powerpc64le-linux-gnu-g++' + test_prefix = ['qemu-ppc64le', '-cpu', 'POWER8', '-L', '/usr/powerpc64le-linux-gnu/'] + elif target == 'cross-mips64': + flags += ['--cpu=mips64', '--with-endian=big'] + cc_bin = 'mips64-linux-gnuabi64-g++' + test_prefix = ['qemu-mips64', '-L', '/usr/mips64-linux-gnuabi64/'] + test_cmd.remove('simd_32') # no SIMD on MIPS + else: + raise Exception("Unknown cross target '%s' for Linux" % (target)) + else: + # Flags specific to native targets + + if target_os in ['osx', 'linux']: + flags += ['--with-bzip2', '--with-sqlite', '--with-zlib'] + + if target_os in ['osx', 'ios']: + flags += ['--with-commoncrypto'] + + if target == 'coverage': + flags += ['--with-boost'] + + if target_os == 'windows' and target in ['shared', 'static']: + # ./configure.py needs extra hand-holding for boost on windows + boost_root = os.environ.get('BOOST_ROOT') + boost_libs = os.environ.get('BOOST_LIBRARYDIR') + boost_system = os.environ.get('BOOST_SYSTEM_LIBRARY') + + if boost_root and boost_libs and boost_system: + flags += ['--with-boost', + '--with-external-includedir', boost_root, + '--with-external-libdir', boost_libs, + '--boost-library-name', boost_system] + + if target_os == 'linux': + flags += ['--with-lzma'] + + if target_os == 'linux': + if target not in ['sanitizer', 'valgrind', 'minimized']: + # Avoid OpenSSL when using dynamic checkers, or on OS X where it sporadically + # is not installed on the CI image + flags += ['--with-openssl'] + + if target in ['coverage']: + flags += ['--with-tpm'] + test_cmd += ['--run-online-tests'] + if pkcs11_lib and os.access(pkcs11_lib, os.R_OK): + test_cmd += ['--pkcs11-lib=%s' % (pkcs11_lib)] + + if target in ['coverage', 'sanitizer']: + test_cmd += ['--run-long-tests'] + + flags += ['--cc-bin=%s' % (cc_bin)] + + if test_cmd is None: + run_test_command = None + else: + if use_gdb: + disabled_tests.append("os_utils") + + # render 'disabled_tests' array into test_cmd + if disabled_tests: + test_cmd += ['--skip-tests=%s' % (','.join(disabled_tests))] + + if use_gdb: + (cmd, args) = test_cmd[0], test_cmd[1:] + run_test_command = test_prefix + ['gdb', cmd, + '-ex', 'run %s' % (' '.join(args)), + '-ex', 'bt', + '-ex', 'quit'] + else: + run_test_command = test_prefix + test_cmd + + return flags, run_test_command, make_prefix + +def run_cmd(cmd, root_dir): + """ + Execute a command, die if it failed + """ + print("Running '%s' ..." % (' '.join(cmd))) + sys.stdout.flush() + + start = time.time() + + cmd = [os.path.expandvars(elem) for elem in cmd] + sub_env = os.environ.copy() + sub_env['LD_LIBRARY_PATH'] = os.path.abspath(root_dir) + sub_env['DYLD_LIBRARY_PATH'] = os.path.abspath(root_dir) + sub_env['PYTHONPATH'] = os.path.abspath(os.path.join(root_dir, 'src/python')) + cwd = None + + redirect_stdout = None + if len(cmd) >= 3 and cmd[-2] == '>': + redirect_stdout = open(cmd[-1], 'w') + cmd = cmd[:-2] + if len(cmd) > 1 and cmd[0].startswith('indir:'): + cwd = cmd[0][6:] + cmd = cmd[1:] + while len(cmd) > 1 and cmd[0].startswith('env:') and cmd[0].find('=') > 0: + env_key, env_val = cmd[0][4:].split('=') + sub_env[env_key] = env_val + cmd = cmd[1:] + + proc = subprocess.Popen(cmd, cwd=cwd, close_fds=True, env=sub_env, stdout=redirect_stdout) + proc.communicate() + + time_taken = int(time.time() - start) + + if time_taken > 10: + print("Ran for %d seconds" % (time_taken)) + + if proc.returncode != 0: + print("Command '%s' failed with error code %d" % (' '.join(cmd), proc.returncode)) + + if cmd[0] not in ['lcov']: + sys.exit(proc.returncode) + +def default_os(): + platform_os = platform.system().lower() + if platform_os == 'darwin': + return 'osx' + return platform_os + +def parse_args(args): + """ + Parse arguments + """ + parser = optparse.OptionParser() + + parser.add_option('--os', default=default_os(), + help='Set the target os (default %default)') + parser.add_option('--cc', default='gcc', + help='Set the target compiler type (default %default)') + parser.add_option('--cc-bin', default=None, + help='Set path to compiler') + parser.add_option('--root-dir', metavar='D', default='.', + help='Set directory to execute from (default %default)') + + parser.add_option('--make-tool', metavar='TOOL', default='make', + help='Specify tool to run to build source (default %default)') + + parser.add_option('--extra-cxxflags', metavar='FLAGS', default=[], action='append', + help='Specify extra build flags') + + parser.add_option('--cpu', default=None, + help='Specify a target CPU platform') + + parser.add_option('--with-debug', action='store_true', default=False, + help='Include debug information') + parser.add_option('--amalgamation', action='store_true', default=False, + help='Build via amalgamation') + parser.add_option('--disable-shared', action='store_true', default=False, + help='Disable building shared libraries') + parser.add_option('--disabled-tests', metavar='DISABLED_TESTS', default=[], action='append', + help='Comma separated list of tests that should not be run') + + parser.add_option('--branch', metavar='B', default=None, + help='Specify branch being built') + + parser.add_option('--dry-run', action='store_true', default=False, + help='Just show commands to be executed') + parser.add_option('--build-jobs', metavar='J', default=get_concurrency(), + help='Set number of jobs to run in parallel (default %default)') + + parser.add_option('--compiler-cache', default=None, metavar='CC', + help='Set a compiler cache to use (ccache, sccache)') + + parser.add_option('--pkcs11-lib', default=os.getenv('PKCS11_LIB'), metavar='LIB', + help='Set PKCS11 lib to use for testing') + + parser.add_option('--with-python3', dest='use_python3', action='store_true', default=None, + help='Enable using python3') + parser.add_option('--without-python3', dest='use_python3', action='store_false', + help='Disable using python3') + + parser.add_option('--with-pylint3', dest='use_pylint3', action='store_true', default=True, + help='Enable using python3 pylint') + parser.add_option('--without-pylint3', dest='use_pylint3', action='store_false', + help='Disable using python3 pylint') + + parser.add_option('--disable-werror', action='store_true', default=False, + help='Allow warnings to compile') + + parser.add_option('--run-under-gdb', dest='use_gdb', action='store_true', default=False, + help='Run test suite under gdb and capture backtrace') + + return parser.parse_args(args) + +def have_prog(prog): + """ + Check if some named program exists in the path + """ + for path in os.environ['PATH'].split(os.pathsep): + exe_file = os.path.join(path, prog) + if os.path.exists(exe_file) and os.access(exe_file, os.X_OK): + return True + return False + +def main(args=None): + # pylint: disable=too-many-branches,too-many-statements,too-many-locals,too-many-return-statements,too-many-locals + """ + Parse options, do the things + """ + + if os.getenv('COVERITY_SCAN_BRANCH') == '1': + print('Skipping build COVERITY_SCAN_BRANCH set in environment') + return 0 + + if args is None: + args = sys.argv + print("Invoked as '%s'" % (' '.join(args))) + (options, args) = parse_args(args) + + if len(args) != 2: + print('Usage: %s [options] target' % (args[0])) + return 1 + + target = args[1] + + if options.use_python3 is None: + use_python3 = have_prog('python3') + else: + use_python3 = options.use_python3 + + py_interp = 'python' + if use_python3: + py_interp = 'python3' + + if options.cc_bin is None: + if options.cc == 'gcc': + options.cc_bin = 'g++' + elif options.cc == 'clang': + options.cc_bin = 'clang++' + elif options.cc == 'msvc': + options.cc_bin = 'cl' + else: + print('Error unknown compiler %s' % (options.cc)) + return 1 + + if options.compiler_cache is None and options.cc != 'msvc': + # Autodetect ccache + if have_prog('ccache'): + options.compiler_cache = 'ccache' + + if options.compiler_cache not in [None, 'ccache', 'sccache']: + raise Exception("Don't know about %s as a compiler cache" % (options.compiler_cache)) + + root_dir = options.root_dir + + if not os.access(root_dir, os.R_OK): + raise Exception('Bad root dir setting, dir %s not readable' % (root_dir)) + + cmds = [] + + if target == 'lint': + + pylint_rc = '--rcfile=%s' % (os.path.join(root_dir, 'src/configs/pylint.rc')) + pylint_flags = [pylint_rc, '--reports=no'] + + # Some disabled rules specific to Python3 + # useless-object-inheritance: complains about code still useful in Python2 + py3_flags = '--disable=useless-object-inheritance' + + py_scripts = [ + 'configure.py', + 'src/python/botan2.py', + 'src/scripts/ci_build.py', + 'src/scripts/install.py', + 'src/scripts/ci_check_install.py', + 'src/scripts/dist.py', + 'src/scripts/cleanup.py', + 'src/scripts/check.py', + 'src/scripts/build_docs.py', + 'src/scripts/website.py', + 'src/scripts/bench.py', + 'src/scripts/test_python.py', + 'src/scripts/test_fuzzers.py', + 'src/scripts/test_cli.py', + 'src/scripts/python_unittests.py', + 'src/scripts/python_unittests_unix.py'] + + full_paths = [os.path.join(root_dir, s) for s in py_scripts] + + if use_python3 and options.use_pylint3: + cmds.append(['python3', '-m', 'pylint'] + pylint_flags + [py3_flags] + full_paths) + + else: + config_flags, run_test_command, make_prefix = determine_flags( + target, options.os, options.cpu, options.cc, + options.cc_bin, options.compiler_cache, root_dir, + options.pkcs11_lib, options.use_gdb, options.disable_werror, + options.extra_cxxflags, options.disabled_tests) + + cmds.append([py_interp, os.path.join(root_dir, 'configure.py')] + config_flags) + + make_cmd = [options.make_tool] + if root_dir != '.': + make_cmd += ['-C', root_dir] + if options.build_jobs > 1 and options.make_tool != 'nmake': + make_cmd += ['-j%d' % (options.build_jobs)] + make_cmd += ['-k'] + + if target == 'docs': + cmds.append(make_cmd + ['docs']) + else: + if options.compiler_cache is not None: + cmds.append([options.compiler_cache, '--show-stats']) + + make_targets = ['libs', 'tests', 'cli'] + + if target in ['coverage', 'fuzzers']: + make_targets += ['fuzzer_corpus_zip', 'fuzzers'] + + if target in ['coverage']: + make_targets += ['bogo_shim'] + + cmds.append(make_prefix + make_cmd + make_targets) + + if options.compiler_cache is not None: + cmds.append([options.compiler_cache, '--show-stats']) + + if run_test_command is not None: + cmds.append(run_test_command) + + if target == 'coverage': + runner_dir = os.path.abspath(os.path.join(root_dir, 'boringssl', 'ssl', 'test', 'runner')) + + cmds.append(['indir:%s' % (runner_dir), + 'go', 'test', '-pipe', + '-num-workers', str(4*get_concurrency()), + '-shim-path', os.path.abspath(os.path.join(root_dir, 'botan_bogo_shim')), + '-shim-config', os.path.abspath(os.path.join(root_dir, 'src', 'bogo_shim', 'config.json'))]) + + if target in ['coverage', 'fuzzers']: + cmds.append([py_interp, os.path.join(root_dir, 'src/scripts/test_fuzzers.py'), + os.path.join(root_dir, 'fuzzer_corpus'), + os.path.join(root_dir, 'build/fuzzer')]) + + if target in ['shared', 'coverage'] and options.os != 'windows': + botan_exe = os.path.join(root_dir, 'botan-cli.exe' if options.os == 'windows' else 'botan') + + args = ['--threads=%d' % (options.build_jobs)] + test_scripts = ['test_cli.py', 'test_cli_crypt.py'] + for script in test_scripts: + cmds.append([py_interp, os.path.join(root_dir, 'src/scripts', script)] + + args + [botan_exe]) + + python_tests = os.path.join(root_dir, 'src/scripts/test_python.py') + + if target in ['shared', 'coverage']: + + if options.os == 'windows': + if options.cpu == 'x86': + # Python on AppVeyor is a 32-bit binary so only test for 32-bit + cmds.append([py_interp, '-b', python_tests]) + else: + if use_python3: + cmds.append(['python3', '-b', python_tests]) + + if target in ['shared', 'static', 'bsi', 'nist']: + cmds.append(make_cmd + ['install']) + build_config = os.path.join(root_dir, 'build', 'build_config.json') + cmds.append([py_interp, os.path.join(root_dir, 'src/scripts/ci_check_install.py'), build_config]) + + if target in ['coverage']: + if not have_prog('lcov'): + print('Error: lcov not found in PATH (%s)' % (os.getenv('PATH'))) + return 1 + + if not have_prog('gcov'): + print('Error: gcov not found in PATH (%s)' % (os.getenv('PATH'))) + return 1 + + cov_file = 'coverage.info' + raw_cov_file = 'coverage.info.raw' + + cmds.append(['lcov', '--capture', '--directory', options.root_dir, + '--output-file', raw_cov_file]) + cmds.append(['lcov', '--remove', raw_cov_file, '/usr/*', '--output-file', cov_file]) + cmds.append(['lcov', '--list', cov_file]) + + if have_prog('coverage'): + cmds.append(['coverage', 'run', '--branch', + '--rcfile', os.path.join(root_dir, 'src/configs/coverage.rc'), + python_tests]) + + if have_prog('codecov'): + # If codecov exists assume we are in CI and report to codecov.io + cmds.append(['codecov', '>', 'codecov_stdout.log']) + else: + # Otherwise generate a local HTML report + cmds.append(['genhtml', cov_file, '--output-directory', 'lcov-out']) + + cmds.append(make_cmd + ['clean']) + cmds.append(make_cmd + ['distclean']) + + for cmd in cmds: + if options.dry_run: + print('$ ' + ' '.join(cmd)) + else: + run_cmd(cmd, root_dir) + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/ci_check_install.py b/comm/third_party/botan/src/scripts/ci_check_install.py new file mode 100755 index 0000000000..c0a3727629 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ci_check_install.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# coding=utf8 + +""" +Botan CI check installation script +This script is used to validate the results of `make install` + +(C) 2020 Jack Lloyd, René Meusel, Hannes Rantzsch + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import os +import sys +import json +import re + +def verify_library(build_config): + lib_dir = build_config['libdir'] + if not os.path.isdir(lib_dir): + print('Error: libdir "%s" is not a directory' % lib_dir) + return False + + found_libs = set([]) + + major_version = int(build_config["version_major"]) + + if build_config['compiler'] == 'msvc': + expected_lib_format = r'^botan\.(dll|lib)$' + elif build_config['os'] == 'macos': + expected_lib_format = r'^libbotan-%d\.(a|dylib)$' % (major_version) + else: + expected_lib_format = r'^libbotan-%d\.(a|so)$' % (major_version) + + lib_re = re.compile(expected_lib_format) + + # Unlike the include dir this may have other random libs in it + for (_, _, filenames) in os.walk(lib_dir): + for filename in filenames: + if lib_re.match(filename) is not None: + found_libs.add(filename) + + if len(found_libs) == 0: + print("Could not find any libraries from us") + return False + + # This should match up the count and names of libraries installed + # vs the build configuration (eg static lib installed or not) + + return True + +def verify_includes(build_config): + include_dir = build_config['installed_include_dir'] + if not os.path.isdir(include_dir): + print('Error: installed_include_dir "%s" is not a directory' % include_dir) + return False + + expected_headers = set(build_config['public_headers'] + build_config['external_headers']) + found_headers = set([]) + + for (_, _, filenames) in os.walk(include_dir): + for filename in filenames: + found_headers.add(filename) + + if found_headers != expected_headers: + missing = expected_headers - found_headers + extra = found_headers - expected_headers + + if len(missing) > 0: + print("Missing expected headers: %s" % (" ".join(sorted(missing)))) + + if len(extra) > 0: + print("Have unexpected headers: %s" % (" ".join(sorted(extra)))) + return False + + return True + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) < 2: + print("Usage: %s " % args[0]) + return 1 + + with open(os.path.join(args[1])) as f: + build_config = json.load(f) + + install_prefix = build_config['prefix'] + + if not os.path.isdir(install_prefix): + print('Error: install_prefix "%s" is not a directory' % install_prefix) + return 1 + + if not verify_includes(build_config): + return 1 + + if not verify_library(build_config): + return 1 + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/cleanup.py b/comm/third_party/botan/src/scripts/cleanup.py new file mode 100755 index 0000000000..3e8142bab0 --- /dev/null +++ b/comm/third_party/botan/src/scripts/cleanup.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +""" +Implements the "make clean" target + +(C) 2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import os +import sys +import stat +import re +import optparse # pylint: disable=deprecated-module +import logging +import json +import shutil +import errno + +def remove_dir(d): + try: + if os.access(d, os.X_OK): + logging.debug('Removing directory "%s"', d) + shutil.rmtree(d) + else: + logging.debug('Directory %s was missing', d) + except Exception as e: # pylint: disable=broad-except + logging.error('Failed removing directory "%s": %s', d, e) + +def remove_file(f): + try: + logging.debug('Removing file "%s"', f) + os.unlink(f) + except OSError as e: + if e.errno != errno.ENOENT: + logging.error('Failed removing file "%s": %s', f, e) + +def remove_all_in_dir(d): + if os.access(d, os.X_OK): + logging.debug('Removing all files in directory "%s"', d) + + for f in os.listdir(d): + full_path = os.path.join(d, f) + mode = os.lstat(full_path).st_mode + + if stat.S_ISDIR(mode): + remove_dir(full_path) + else: + remove_file(full_path) + +def parse_options(args): + parser = optparse.OptionParser() + parser.add_option('--build-dir', default='build', metavar='DIR', + help='specify build dir to clean (default %default)') + + parser.add_option('--distclean', action='store_true', default=False, + help='clean everything') + parser.add_option('--verbose', action='store_true', default=False, + help='noisy logging') + + (options, args) = parser.parse_args(args) + + if len(args) > 1: + raise Exception("Unknown arguments") + + return options + +def main(args=None): + if args is None: + args = sys.argv + + options = parse_options(args) + + logging.basicConfig(stream=sys.stderr, + format='%(levelname) 7s: %(message)s', + level=logging.DEBUG if options.verbose else logging.INFO) + + build_dir = options.build_dir + + if not os.access(build_dir, os.X_OK): + logging.debug('No build directory found') + # No build dir: clean enough! + return 0 + + build_config_path = os.path.join(build_dir, 'build_config.json') + build_config_str = None + + try: + build_config_file = open(build_config_path) + build_config_str = build_config_file.read() + build_config_file.close() + except Exception: # pylint: disable=broad-except + # Ugh have to do generic catch as different exception type thrown in Python2 + logging.error("Unable to access build_config.json in build dir") + return 1 + + build_config = json.loads(build_config_str) + + if options.distclean: + build_dir = build_config['build_dir'] + remove_file(build_config['makefile_path']) + remove_dir(build_dir) + else: + for dir_type in ['libobj_dir', 'cliobj_dir', 'testobj_dir', 'handbook_output_dir', 'doc_output_dir_doxygen']: + dir_path = build_config[dir_type] + if dir_path: + remove_all_in_dir(dir_path) + + remove_file(build_config['doc_stamp_file']) + + remove_file(build_config['cli_exe']) + remove_file(build_config['test_exe']) + + lib_basename = build_config['lib_prefix'] + build_config['libname'] + matches_libname = re.compile('^' + lib_basename + '.([a-z]+)((\\.[0-9\\.]+)|$)') + + known_suffix = ['a', 'so', 'dll', 'manifest', 'exp'] + + for f in os.listdir(build_config['out_dir']): + match = matches_libname.match(f) + if match and match.group(1) in known_suffix: + remove_file(os.path.join(build_config['out_dir'], f)) + + if options.distclean: + if 'generated_files' in build_config: + for f in build_config['generated_files'].split(' '): + remove_file(f) + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/comba.py b/comm/third_party/botan/src/scripts/comba.py new file mode 100755 index 0000000000..309dca0821 --- /dev/null +++ b/comm/third_party/botan/src/scripts/comba.py @@ -0,0 +1,126 @@ +#!/usr/bin/python3 + +import sys +import datetime + +# (C) 2011,2014,2015,2016 Jack Lloyd +# Botan is released under the Simplified BSD License (see license.txt) + +# Used to generate src/lib/math/mp/mp_comba.cpp + +def comba_indexes(N): + + indexes = [] + + for i in range(0, 2*N): + x = [] + + for j in range(max(0, i-N+1), min(N, i+1)): + x += [(j,i-j)] + indexes += [sorted(x)] + + return indexes + +def comba_sqr_indexes(N): + + indexes = [] + + for i in range(0, 2*N): + x = [] + + for j in range(max(0, i-N+1), min(N, i+1)): + if j < i-j: + x += [(j,i-j)] + else: + x += [(i-j,j)] + indexes += [sorted(x)] + + return indexes + +def comba_multiply_code(N): + indexes = comba_indexes(N) + + w2 = 'w2' + w1 = 'w1' + w0 = 'w0' + + for (i,idx) in zip(range(0, len(indexes)), indexes): + for pair in idx: + print(" word3_muladd(&%s, &%s, &%s, x[%2d], y[%2d]);" % (w2, w1, w0, pair[0], pair[1])) + + if i < 2*N-2: + print(" z[%2d] = %s; %s = 0;\n" % (i, w0, w0)) + else: + print(" z[%2d] = %s;" % (i, w0)) + (w0,w1,w2) = (w1,w2,w0) + #print("z[%2d] = w0; w0 = w1; w1 = w2; w2 = 0;" % (i)) + +def comba_square_code(N): + indexes = comba_sqr_indexes(N) + + w2 = 'w2' + w1 = 'w1' + w0 = 'w0' + + for (rnd,idx) in zip(range(0, len(indexes)), indexes): + for (i,pair) in zip(range(0, len(idx)), idx): + if pair[0] == pair[1]: + print(" word3_muladd (&%s, &%s, &%s, x[%2d], x[%2d]);" % (w2, w1, w0, pair[0], pair[1])) + elif i % 2 == 0: + print(" word3_muladd_2(&%s, &%s, &%s, x[%2d], x[%2d]);" % (w2, w1, w0, pair[0], pair[1])) + + if rnd < 2*N-2: + print(" z[%2d] = %s; %s = 0;\n" % (rnd, w0, w0)) + else: + print(" z[%2d] = %s;" % (rnd, w0)) + + (w0,w1,w2) = (w1,w2,w0) + +def main(args = None): + if args is None: + args = sys.argv + + if len(args) <= 1: + sizes = [4, 6, 8, 9, 16, 24] + else: + sizes = map(int, args[1:]) + + print("""/* +* Comba Multiplication and Squaring +* +* This file was automatically generated by %s on %s +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { +""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"))) + + for n in sizes: + print("/*\n* Comba %dx%d Squaring\n*/" % (n, n)) + print("void bigint_comba_sqr%d(word z[%d], const word x[%d])" % (n, 2*n, n)) + print(" {") + print(" word w2 = 0, w1 = 0, w0 = 0;\n") + + comba_square_code(n) + + print(" }\n") + + print("/*\n* Comba %dx%d Multiplication\n*/" % (n, n)) + print("void bigint_comba_mul%d(word z[%d], const word x[%d], const word y[%d])" % (n, 2*n, n, n)) + print(" {") + print(" word w2 = 0, w1 = 0, w0 = 0;\n") + + comba_multiply_code(n) + + print(" }\n") + + print("}") + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/create_corpus_zip.py b/comm/third_party/botan/src/scripts/create_corpus_zip.py new file mode 100755 index 0000000000..5faee3b526 --- /dev/null +++ b/comm/third_party/botan/src/scripts/create_corpus_zip.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# These is used to create fuzzer corpus zip files + +# This is primarily used by OSS-Fuzz but might be useful if you were +# deploying the binaries in a custom fuzzer deployment system. + +import sys +import os +import zipfile +import stat + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 2 and len(args) != 3: + print("Usage: %s corpus_dir " % (args[0])) + return 1 + + root_dir = args[1] + + if len(args) == 3: + output_dir = args[2] + else: + output_dir = '' + + if not os.access(root_dir, os.R_OK): + print("Error could not access directory '%s'" % (root_dir)) + return 1 + + for corpus_dir in os.listdir(root_dir): + if corpus_dir == '.git': + continue + subdir = os.path.join(root_dir, corpus_dir) + if not stat.S_ISDIR(os.stat(subdir).st_mode): + continue + + zipfile_path = os.path.join(output_dir, '%s.zip' % (corpus_dir)) + zf = zipfile.ZipFile(zipfile_path, 'w', zipfile.ZIP_DEFLATED) + for f in os.listdir(subdir): + zf.write(os.path.join(subdir, f), f) + zf.close() + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/dist.py b/comm/third_party/botan/src/scripts/dist.py new file mode 100755 index 0000000000..ce072ec105 --- /dev/null +++ b/comm/third_party/botan/src/scripts/dist.py @@ -0,0 +1,466 @@ +#!/usr/bin/env python + +""" +Release script for botan (https://botan.randombit.net/) + +This script requires Python 2.7 or 3.6 + +(C) 2011,2012,2013,2015,2016,2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import datetime +import errno +import hashlib +import io +import logging +import optparse # pylint: disable=deprecated-module +import os +import re +import shutil +import subprocess +import sys +import tarfile +import time +import traceback + +# This is horrible, but there is no way to override tarfile's use of time.time +# in setting the gzip header timestamp, which breaks deterministic archives + +GZIP_HEADER_TIME = 0 + +def fake_time(): + return GZIP_HEADER_TIME +time.time = fake_time + + +def check_subprocess_results(subproc, name): + (raw_stdout, raw_stderr) = subproc.communicate() + + stderr = raw_stderr.decode('utf-8') + + if subproc.returncode != 0: + stdout = raw_stdout.decode('utf-8') + if stdout != '': + logging.error(stdout) + if stderr != '': + logging.error(stderr) + raise Exception('Running %s failed' % (name)) + + if stderr != '': + logging.warning(stderr) + + return raw_stdout + +def run_git(args): + cmd = ['git'] + args + logging.debug('Running %s' % (' '.join(cmd))) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + return check_subprocess_results(proc, 'git') + +def maybe_gpg(val): + val = val.decode('ascii') + if 'BEGIN PGP SIGNATURE' in val: + return val.split('\n')[-2] + else: + return val.strip() + +def rel_time_to_epoch(year, month, day, hour, minute, second): + dt = datetime.datetime(year, month, day, hour, minute, second) + return (dt - datetime.datetime(1970, 1, 1)).total_seconds() + +def datestamp(tag): + ts = maybe_gpg(run_git(['show', '--no-patch', '--format=%ai', tag])) + + ts_matcher = re.compile(r'^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) .*') + + logging.debug('Git returned timestamp of %s for tag %s' % (ts, tag)) + match = ts_matcher.match(ts) + + if match is None: + logging.error('Failed parsing timestamp "%s" of tag %s' % (ts, tag)) + return 0 + + rel_date = int(match.group(1) + match.group(2) + match.group(3)) + rel_epoch = rel_time_to_epoch(*[int(match.group(i)) for i in range(1, 7)]) + + return rel_date, rel_epoch + +def revision_of(tag): + return maybe_gpg(run_git(['show', '--no-patch', '--format=%H', tag])) + +def extract_revision(revision, to): + tar_val = run_git(['archive', '--format=tar', '--prefix=%s/' % (to), revision]) + tar_f = tarfile.open(fileobj=io.BytesIO(tar_val)) + tar_f.extractall() + +def gpg_sign(keyid, passphrase_file, files, detached=True): + + options = ['--armor', '--detach-sign'] if detached else ['--clearsign'] + + gpg_cmd = ['gpg', '--batch'] + options + ['--local-user', keyid] + if passphrase_file is not None: + gpg_cmd[1:1] = ['--passphrase-file', passphrase_file] + + for filename in files: + logging.info('Signing %s using PGP id %s' % (filename, keyid)) + + cmd = gpg_cmd + [filename] + + logging.debug('Running %s' % (' '.join(cmd))) + + gpg = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + check_subprocess_results(gpg, 'gpg') + + return [filename + '.asc' for filename in files] + +def parse_args(args): + parser = optparse.OptionParser( + "usage: %prog [options] \n" + + " %prog [options] snapshot " + ) + + parser.add_option('--verbose', action='store_true', + default=False, help='Extra debug output') + + parser.add_option('--quiet', action='store_true', + default=False, help='Only show errors') + + parser.add_option('--output-dir', metavar='DIR', default='.', + help='Where to place output (default %default)') + + parser.add_option('--print-output-names', action='store_true', + help='Print output archive filenames to stdout') + + parser.add_option('--archive-types', metavar='LIST', default='txz', + help='Set archive types to generate (default %default)') + + parser.add_option('--pgp-key-id', metavar='KEYID', + default='EFBADFBC', + help='PGP signing key (default %default, "none" to disable)') + + parser.add_option('--pgp-passphrase-file', metavar='FILE', + default=None, + help='PGP signing key passphrase file') + + parser.add_option('--write-hash-file', metavar='FILE', default=None, + help='Write a file with checksums') + + return parser.parse_args(args) + +def remove_file_if_exists(fspath): + try: + os.unlink(fspath) + except OSError as e: + if e.errno != errno.ENOENT: + raise + +def rewrite_version_file(version_file, target_version, snapshot_branch, rev_id, rel_date): + + if snapshot_branch: + assert target_version == snapshot_branch + + contents = open(version_file).readlines() + + version_re = re.compile('release_(major|minor|patch) = ([0-9]+)') + version_suffix_re = re.compile('release_suffix = \'(-(alpha|beta|rc)[0-9]+)\'') + + def content_rewriter(target_version): + version_info = {} + + release_type = 'release' + + # Not included in old version files so set a default + version_info["suffix"] = "" + + for line in contents: + + if not snapshot_branch: + match = version_re.match(line) + if match: + version_info[match.group(1)] = int(match.group(2)) + + match = version_suffix_re.match(line) + if match: + suffix = match.group(1) + version_info['suffix'] = suffix + if suffix.find('alpha') >= 0: + release_type = 'alpha' + elif suffix.find('beta') >= 0: + release_type = 'beta' + elif suffix.find('rc') >= 0: + release_type = 'release candidate' + + if line == 'release_vc_rev = None\n': + yield 'release_vc_rev = \'git:%s\'\n' % (rev_id) + elif line == 'release_datestamp = 0\n': + yield 'release_datestamp = %d\n' % (rel_date) + elif line == "release_type = \'unreleased\'\n": + if target_version == snapshot_branch: + yield "release_type = 'snapshot:%s'\n" % (snapshot_branch) + else: + yield "release_type = '%s'\n" % (release_type) + else: + yield line + + if not snapshot_branch: + for req_var in ["major", "minor", "patch", "suffix"]: + if req_var not in version_info.keys(): + raise Exception('Missing version field for %s in version file' % (req_var)) + + marked_version = "%d.%d.%d%s" % (version_info["major"], + version_info["minor"], + version_info["patch"], + version_info["suffix"]) + + if marked_version != target_version: + raise Exception('Release version file %s does not match tagged version %s' % ( + marked_version, target_version)) + + new_contents = ''.join(list(content_rewriter(target_version))) + open(version_file, 'w').write(new_contents) + +def write_archive(version, output_basename, archive_type, rel_epoch, all_files, hash_file): + # pylint: disable=too-many-locals + def archive_suffix(archive_type): + if archive_type == 'tgz': + return 'tgz' + elif archive_type == 'tbz': + return 'tar.bz2' + elif archive_type == 'txz': + return 'tar.xz' + elif archive_type == 'tar': + return 'tar' + else: + raise Exception("Unknown archive type '%s'" % (archive_type)) + + output_archive = output_basename + '.' + archive_suffix(archive_type) + logging.info('Writing archive "%s"' % (output_archive)) + + remove_file_if_exists(output_archive) + remove_file_if_exists(output_archive + '.asc') + + def write_mode(archive_type): + if archive_type == 'tgz': + return 'w:gz' + elif archive_type == 'tbz': + return 'w:bz2' + elif archive_type == 'txz': + return 'w:xz' + elif archive_type == 'tar': + return 'w' + else: + raise Exception("Unknown archive type '%s'" % (archive_type)) + + # gzip format embeds the original filename, tarfile.py does the wrong + # thing unless the output name ends in .gz. So pass an explicit + # fileobj in that case, and supply a name in the form tarfile expects. + archive_suffix = '.tar.gz' if archive_type == 'tgz' else '.tar' + + def archive_format(version): + # A change in Python meant that 2.14 and 2.15 were released with a + # tarfile using POSIX pax format (the new default for tarfile module) + # instead of the previously used GNU format. + if version in ['2.14.0', '2.15.0']: + return tarfile.PAX_FORMAT + else: + return tarfile.GNU_FORMAT + + archive = tarfile.open(output_basename + archive_suffix, + write_mode(archive_type), + format=archive_format(version), + fileobj=open(output_archive, 'wb')) + + for f in all_files: + tarinfo = archive.gettarinfo(f) + tarinfo.uid = 500 + tarinfo.gid = 500 + tarinfo.uname = "botan" + tarinfo.gname = "botan" + tarinfo.mtime = rel_epoch + archive.addfile(tarinfo, open(f, 'rb')) + archive.close() + + archive_contents = open(output_archive, 'rb').read() + + sha256 = hashlib.new('sha256') + sha256.update(archive_contents) + archive_hash = sha256.hexdigest().upper() + + logging.info('%s is %.2f MiB' % (output_archive, len(archive_contents) / (1024.0*1024.0))) + logging.info('SHA-256(%s) = %s' % (output_archive, archive_hash)) + if hash_file is not None: + hash_file.write("%s %s\n" % (archive_hash, output_archive)) + + return output_archive + +def configure_logging(options): + class ExitOnErrorLogHandler(logging.StreamHandler, object): + def emit(self, record): + super(ExitOnErrorLogHandler, self).emit(record) + # Exit script if and ERROR or worse occurred + if record.levelno >= logging.ERROR: + if sys.exc_info()[2] is not None: + logging.info(traceback.format_exc()) + sys.exit(1) + + def log_level(): + if options.verbose: + return logging.DEBUG + if options.quiet: + return logging.ERROR + return logging.INFO + + lh = ExitOnErrorLogHandler(sys.stderr) + lh.setFormatter(logging.Formatter('%(levelname) 7s: %(message)s')) + logging.getLogger().addHandler(lh) + logging.getLogger().setLevel(log_level()) + +def main(args=None): + # pylint: disable=too-many-branches,too-many-locals,too-many-statements + if args is None: + args = sys.argv[1:] + + (options, args) = parse_args(args) + + configure_logging(options) + + if len(args) != 1 and len(args) != 2: + logging.error('Usage: %s [options] ' % (sys.argv[0])) + + snapshot_branch = None + target_version = None + + archives = options.archive_types.split(',') if options.archive_types != '' else [] + for archive_type in archives: + if archive_type not in ['tar', 'tgz', 'tbz', 'txz']: + logging.error('Unknown archive type "%s"' % (archive_type)) + + if args[0] == 'snapshot': + if len(args) != 2: + logging.error('Missing branch name for snapshot command') + snapshot_branch = args[1] + else: + if len(args) != 1: + logging.error('Usage error, try --help') + target_version = args[0] + + if snapshot_branch: + logging.info('Creating snapshot release from branch %s', snapshot_branch) + target_version = snapshot_branch + elif len(args) == 1: + try: + logging.info('Creating release for version %s' % (target_version)) + except ValueError as e: + logging.error('Invalid version number %s' % (target_version)) + + rev_id = revision_of(target_version) + if rev_id == '': + logging.error('No tag matching %s found' % (target_version)) + + rel_date, rel_epoch = datestamp(target_version) + if rel_date == 0 or rel_epoch == 0: + logging.error('No date found for version, git error?') + + logging.info('Found %s at revision id %s released %d' % (target_version, rev_id, rel_date)) + + global GZIP_HEADER_TIME # pylint: disable=global-statement + GZIP_HEADER_TIME = rel_epoch + + def output_name(): + if snapshot_branch: + if snapshot_branch == 'master': + return 'Botan-snapshot-%s' % (rel_date) + else: + return 'Botan-snapshot-%s-%s' % (snapshot_branch, rel_date) + else: + return 'Botan-' + target_version + + output_basename = output_name() + + logging.debug('Output basename %s' % (output_basename)) + + if os.access(output_basename, os.X_OK): + logging.info('Removing existing output dir %s' % (output_basename)) + shutil.rmtree(output_basename) + + extract_revision(rev_id, output_basename) + + all_files = [] + for (curdir, _, files) in os.walk(output_basename): + all_files += [os.path.join(curdir, f) for f in files] + all_files.sort(key=lambda f: (os.path.dirname(f), os.path.basename(f))) + + def find_version_file(): + + # location of file with version information has moved over time + for possible_version_file in ['src/build-data/version.txt', 'version.txt', 'botan_version.py']: + full_path = os.path.join(output_basename, possible_version_file) + if os.access(full_path, os.R_OK): + return full_path + + logging.error('Cannot locate version file') + return None + + version_file = find_version_file() + + if not os.access(version_file, os.R_OK): + logging.error('Cannot read %s' % (version_file)) + + rewrite_version_file(version_file, target_version, snapshot_branch, rev_id, rel_date) + + try: + os.makedirs(options.output_dir) + except OSError as e: + if e.errno != errno.EEXIST: + logging.error('Creating dir %s failed %s' % (options.output_dir, e)) + + output_files = [] + + hash_file = None + if options.write_hash_file is not None: + hash_file = open(options.write_hash_file, 'w') + + for archive_type in archives: + output_files.append(write_archive(target_version, + output_basename, + archive_type, + rel_epoch, + all_files, + hash_file)) + + if hash_file is not None: + hash_file.close() + + shutil.rmtree(output_basename) + + if options.pgp_key_id != 'none': + if options.write_hash_file is not None: + output_files += gpg_sign(options.pgp_key_id, options.pgp_passphrase_file, + [options.write_hash_file], False) + else: + output_files += gpg_sign(options.pgp_key_id, options.pgp_passphrase_file, + output_files, True) + + if options.output_dir != '.': + for output_file in output_files: + logging.debug('Moving %s to %s' % (output_file, options.output_dir)) + shutil.move(output_file, os.path.join(options.output_dir, output_file)) + + if options.print_output_names: + for output_file in output_files: + print(output_file) + + return 0 + +if __name__ == '__main__': + try: + sys.exit(main()) + except Exception as e: # pylint: disable=broad-except + logging.info(traceback.format_exc()) + logging.error(e) + sys.exit(1) diff --git a/comm/third_party/botan/src/scripts/docker-android.sh b/comm/third_party/botan/src/scripts/docker-android.sh new file mode 100755 index 0000000000..22bbc41f43 --- /dev/null +++ b/comm/third_party/botan/src/scripts/docker-android.sh @@ -0,0 +1,11 @@ +VERSION=`./configure.py --version` +mkdir -p docker-builds +docker build -f src/scripts/Dockerfile.android --force-rm -t botan-android-${VERSION} \ + --build-arg ANDROID_ARCH=${ANDROID_ARCH} \ + --build-arg ANDROID_ARCH_SUF=${ANDROID_ARCH_SUF} \ + --build-arg ANDROID_SDK_VER=${ANDROID_SDK_VER} \ + --build-arg ANDROID_TOOLCHAIN_SUF=${ANDROID_TOOLCHAIN_SUF} \ + . +docker create --name botan-android-${VERSION} botan-android-${VERSION} +docker cp botan-android-${VERSION}:/botan/android docker-builds +docker rm -f botan-android-${VERSION} diff --git a/comm/third_party/botan/src/scripts/ffi_decls.py b/comm/third_party/botan/src/scripts/ffi_decls.py new file mode 100755 index 0000000000..b336e61f53 --- /dev/null +++ b/comm/third_party/botan/src/scripts/ffi_decls.py @@ -0,0 +1,113 @@ +#!/usr/bin/python + +""" +Automatically generate declarations for the FFI layer + +(C) 2019 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +from pycparser import c_ast, parse_file + +ffi_header = 'src/lib/ffi/ffi.h' + +def to_ctype(typ, is_ptr): + + if typ.startswith('botan_') and typ.endswith('_t'): + return 'c_void_p' + + if is_ptr is False: + if typ == 'uint32': + return 'c_uint32' + elif typ == 'size_t': + return 'c_size_t' + elif typ == 'uint8_t': + return 'c_uint8' + elif typ == 'uint32_t': + return 'c_uint32' + elif typ == 'uint64_t': + return 'c_uint64' + elif typ == 'int': + return 'c_int' + elif typ == 'unsigned': + return 'c_uint' + else: + if typ == 'void': + return 'c_void_p' + elif typ in ['char', 'uint8_t']: # hack + return 'c_char_p' + elif typ == 'size_t': + return 'POINTER(c_size_t)' + #elif typ == 'uint8_t': + # return 'POINTER(c_uint8)' + elif typ == 'uint32_t': + return 'POINTER(c_uint32)' + elif typ == 'uint64_t': + return 'POINTER(c_uint64)' + elif typ == 'int': + return 'POINTER(c_int)' + + raise Exception("Unknown type %s/%d" % (typ, is_ptr)) + +GROUP = None + +class FuncDefVisitor(c_ast.NodeVisitor): + def visit_FuncDecl(self, node): + + if not isinstance(node.type, c_ast.TypeDecl): + #print("ignoring", node.type) + return + + if node.type.type.names != ['int']: + #print("ignoring", node.type) + return + + # all functions returning ints: + fn_name = node.type.declname + + fn_group = fn_name.split('_')[1] + if fn_group == 'privkey': + fn_group = 'pubkey' # hack + + global GROUP + + if fn_group != GROUP: + if fn_group in ['rng', 'hash', 'mac', 'cipher', 'block', 'mp', 'pubkey', 'pk', 'x509', 'hotp', 'totp', 'fpe']: + print("\n # ", fn_group.upper()) + else: + print("") + GROUP = fn_group + + + fn_args = [] + + for param in node.args.params: + + is_ptr = False + typ = None + if isinstance(param.type, c_ast.PtrDecl): + is_ptr = True + typ = param.type.type.type.names[0] + elif isinstance(param.type, c_ast.ArrayDecl): + is_ptr = True + typ = param.type.type.type.names[0] + else: + typ = param.type.type.names[0] + + ctype = to_ctype(typ, is_ptr) + fn_args.append(ctype) + + decl = " ffi_api(dll.%s," % (fn_name) + if len(fn_args) > 4: + decl += "\n " + else: + decl += ' ' + + decl += '[' + ', '.join(fn_args) + '])' + + print(decl) + +ast = parse_file(ffi_header, use_cpp=True, cpp_args=['-Ibuild/include', '-std=c89', '-DBOTAN_DLL=']) +v = FuncDefVisitor() +v.visit(ast) diff --git a/comm/third_party/botan/src/scripts/fuzzer.xml b/comm/third_party/botan/src/scripts/fuzzer.xml new file mode 100644 index 0000000000..686059f8c8 --- /dev/null +++ b/comm/third_party/botan/src/scripts/fuzzer.xml @@ -0,0 +1,17 @@ + + + + $botan_cli + $tls_port + $workflow_dir + TLS_CONSTANT,LENGTH,COUNT,PUBLIC_KEY,PADDING,SIGNATURE,PLAIN_PROTOCOL_MESSAGE + /tmp/ + + + simple_fuzzer -connect localhost:$PORT + tls_server $rsa_cert $rsa_key --port=$PORT --policy=$fuzz_policy --dump-traces=/tmp/tls/ --output=/tmp/botan_output.log --error-output=/tmp/botan_error_output.log + botan-rsa + + + + diff --git a/comm/third_party/botan/src/scripts/gen_os_features.py b/comm/third_party/botan/src/scripts/gen_os_features.py new file mode 100755 index 0000000000..bfcfac7d19 --- /dev/null +++ b/comm/third_party/botan/src/scripts/gen_os_features.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +""" +A script to automatically write docs to /docs. Currently it generates +os.rst, a feature table of OS features. + +Requires Python 3. + +(C) 2015 Simon Warta (Kullo GmbH) + +Botan is released under the Simplified BSD License (see license.txt) +""" + +# global +import argparse +import glob +import os +import sys + +# Assume this script is in botan/src/scripts +botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..") + +# locale +sys.path.append(botan_root) +from configure import OsInfo + +parser = argparse.ArgumentParser(description="") +parser.add_argument('--verbose', dest='verbose', action='store_const', + const=True, default=False, + help='Verbose output (default: false)') +args = parser.parse_args() + +def update_os(): + TABLE_TITLE="OS Features" + + files = [] + files += glob.glob(botan_root + '/src/build-data/os/*.txt') + files.sort() + + if len(files) == 0: + print("No info.txt files found.") + sys.exit(1) + + f1 = open(os.path.join(botan_root, 'doc', 'dev_ref', 'os.rst'), 'w+') + + all_features = set() + oss = {} + + for filename in files: + o = OsInfo(filename) + oss[o.basename] = o + all_features |= set(o.target_features) + if args.verbose: + print(o.basename) + print(o.target_features) + + featurelist = list(all_features) + featurelist.sort() + oslist = list(oss.keys()) + oslist.sort() + + if args.verbose: + print(featurelist) + + print(TABLE_TITLE, file=f1) + print("========================================", file=f1) + print("", file=f1) + + print("A summary of OS features as defined in ``src/build-data/os``.", file=f1) + print("", file=f1) + + print("::", file=f1) + print("", file=f1) + for o in oslist: + print(" %s: %s" % (o[0:1], o), file=f1) + print("", file=f1) + + print('.. csv-table::', file=f1) + print(' :header: "Feature", "' + '", "'.join([o[0:1] for o in oslist]) + '"', file=f1) + print('', file=f1) + + for f in featurelist: + line = ' "' + f + '"' + for o in oslist: + line += ', "' + line += 'X' if f in oss[o].target_features else ' ' + line += '"' + print(line, file=f1) + print("", file=f1) + print(".. note::", file=f1) + print(" This file is auto generated by ``src/scripts/%s``. Dont modify it manually." + % os.path.basename(sys.argv[0]), file=f1) + +if __name__ == '__main__': + update_os() diff --git a/comm/third_party/botan/src/scripts/install.py b/comm/third_party/botan/src/scripts/install.py new file mode 100755 index 0000000000..32a7a7e9e8 --- /dev/null +++ b/comm/third_party/botan/src/scripts/install.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python + +""" +Botan install script + +(C) 2014,2015,2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import errno +import json +import logging +import optparse # pylint: disable=deprecated-module +import os +import shutil +import sys +import traceback + +def parse_command_line(args): + + parser = optparse.OptionParser() + + parser.add_option('--verbose', action='store_true', default=False, + help='Show debug messages') + parser.add_option('--quiet', action='store_true', default=False, + help='Show only warnings and errors') + + build_group = optparse.OptionGroup(parser, 'Source options') + build_group.add_option('--build-dir', metavar='DIR', default='build', + help='Location of build output (default \'%default\')') + parser.add_option_group(build_group) + + install_group = optparse.OptionGroup(parser, 'Installation options') + install_group.add_option('--prefix', default='/usr/local', + help='Set output directory (default %default)') + install_group.add_option('--bindir', default='bin', metavar='DIR', + help='Set binary subdir (default %default)') + install_group.add_option('--libdir', default='lib', metavar='DIR', + help='Set library subdir (default %default)') + install_group.add_option('--includedir', default='include', metavar='DIR', + help='Set include subdir (default %default)') + install_group.add_option('--docdir', default='share/doc', metavar='DIR', + help='Set documentation subdir (default %default)') + install_group.add_option('--pkgconfigdir', default='pkgconfig', metavar='DIR', + help='Set pkgconfig subdir (default %default)') + + install_group.add_option('--umask', metavar='MASK', default='022', + help='Umask to set (default %default)') + parser.add_option_group(install_group) + + (options, args) = parser.parse_args(args) + + def log_level(): + if options.verbose: + return logging.DEBUG + if options.quiet: + return logging.WARNING + return logging.INFO + + logging.getLogger().setLevel(log_level()) + + return (options, args) + + +class PrependDestdirError(Exception): + pass + + +def is_subdir(path, subpath): + return os.path.relpath(path, start=subpath).startswith("..") + + +def prepend_destdir(path): + """ + Needed because os.path.join() discards the first path if the + second one is absolute, which is usually the case here. Still, we + want relative paths to work and leverage the os awareness of + os.path.join(). + """ + destdir = os.environ.get('DESTDIR', "") + + if destdir: + # DESTDIR is non-empty, but we only join absolute paths on UNIX-like file systems + if os.path.sep != "/": + raise PrependDestdirError("Only UNIX-like file systems using forward slash " \ + "separator supported when DESTDIR is set.") + if not os.path.isabs(path): + raise PrependDestdirError("--prefix must be an absolute path when DESTDIR is set.") + + path = os.path.normpath(path) + # Remove / or \ prefixes if existent to accomodate for os.path.join() + path = path.lstrip(os.path.sep) + path = os.path.join(destdir, path) + + if not is_subdir(destdir, path): + raise PrependDestdirError("path escapes DESTDIR (path='%s', destdir='%s')" % (path, destdir)) + + return path + + +def makedirs(dirname, exist_ok=True): + try: + logging.debug('Creating directory %s' % (dirname)) + os.makedirs(dirname) + except OSError as e: + if e.errno != errno.EEXIST or not exist_ok: + raise e + +# Clear link and create new one +def force_symlink(target, linkname): + try: + os.unlink(linkname) + except OSError as e: + if e.errno != errno.ENOENT: + raise e + os.symlink(target, linkname) + +def calculate_exec_mode(options): + out = 0o777 + if 'umask' in os.__dict__: + umask = int(options.umask, 8) + logging.debug('Setting umask to %s' % oct(umask)) + os.umask(int(options.umask, 8)) + out &= (umask ^ 0o777) + return out + +def main(args): + # pylint: disable=too-many-locals,too-many-branches,too-many-statements + + logging.basicConfig(stream=sys.stdout, + format='%(levelname) 7s: %(message)s') + + (options, args) = parse_command_line(args) + + exe_mode = calculate_exec_mode(options) + + def copy_file(src, dst): + logging.debug('Copying %s to %s' % (src, dst)) + shutil.copyfile(src, dst) + + def copy_executable(src, dst): + copy_file(src, dst) + logging.debug('Make %s executable' % dst) + os.chmod(dst, exe_mode) + + with open(os.path.join(options.build_dir, 'build_config.json')) as f: + cfg = json.load(f) + + ver_major = int(cfg['version_major']) + ver_minor = int(cfg['version_minor']) + ver_patch = int(cfg['version_patch']) + target_os = cfg['os'] + build_shared_lib = bool(cfg['build_shared_lib']) + build_static_lib = bool(cfg['build_static_lib']) + build_cli = bool(cfg['build_cli_exe']) + out_dir = cfg['out_dir'] + + bin_dir = options.bindir + lib_dir = options.libdir + target_include_dir = os.path.join(options.prefix, + options.includedir, + 'botan-%d' % (ver_major), + 'botan') + + for d in [options.prefix, lib_dir, bin_dir, target_include_dir]: + makedirs(prepend_destdir(d)) + + build_include_dir = os.path.join(options.build_dir, 'include', 'botan') + + for include in sorted(os.listdir(build_include_dir)): + if include == 'internal': + continue + copy_file(os.path.join(build_include_dir, include), + prepend_destdir(os.path.join(target_include_dir, include))) + + build_external_include_dir = os.path.join(options.build_dir, 'include', 'external') + + for include in sorted(os.listdir(build_external_include_dir)): + copy_file(os.path.join(build_external_include_dir, include), + prepend_destdir(os.path.join(target_include_dir, include))) + + if build_static_lib or target_os == 'windows': + static_lib = cfg['static_lib_name'] + copy_file(os.path.join(out_dir, static_lib), + prepend_destdir(os.path.join(lib_dir, os.path.basename(static_lib)))) + + if build_shared_lib: + if target_os == "windows": + libname = cfg['libname'] + soname_base = libname + '.dll' + copy_executable(os.path.join(out_dir, soname_base), + prepend_destdir(os.path.join(bin_dir, soname_base))) + else: + soname_patch = cfg['soname_patch'] + soname_abi = cfg['soname_abi'] + soname_base = cfg['soname_base'] + + copy_executable(os.path.join(out_dir, soname_patch), + prepend_destdir(os.path.join(lib_dir, soname_patch))) + + if target_os != "openbsd": + prev_cwd = os.getcwd() + try: + os.chdir(prepend_destdir(lib_dir)) + force_symlink(soname_patch, soname_abi) + force_symlink(soname_patch, soname_base) + finally: + os.chdir(prev_cwd) + + if build_cli: + copy_executable(cfg['cli_exe'], prepend_destdir(os.path.join(bin_dir, cfg['cli_exe_name']))) + + if 'botan_pkgconfig' in cfg: + pkgconfig_dir = os.path.join(options.prefix, options.libdir, options.pkgconfigdir) + makedirs(prepend_destdir(pkgconfig_dir)) + copy_file(cfg['botan_pkgconfig'], + prepend_destdir(os.path.join(pkgconfig_dir, os.path.basename(cfg['botan_pkgconfig'])))) + + if 'ffi' in cfg['mod_list'] and cfg['build_shared_lib'] is True and cfg['install_python_module'] is True: + for ver in cfg['python_version'].split(','): + py_lib_path = os.path.join(lib_dir, 'python%s' % (ver), 'site-packages') + logging.debug('Installing python module to %s' % (py_lib_path)) + makedirs(prepend_destdir(py_lib_path)) + + py_dir = cfg['python_dir'] + + copy_file(os.path.join(py_dir, 'botan2.py'), + prepend_destdir(os.path.join(py_lib_path, 'botan2.py'))) + + if cfg['with_documentation']: + target_doc_dir = os.path.join(options.prefix, options.docdir, + 'botan-%d.%d.%d' % (ver_major, ver_minor, ver_patch)) + + shutil.rmtree(prepend_destdir(target_doc_dir), True) + shutil.copytree(cfg['doc_output_dir'], prepend_destdir(target_doc_dir)) + + copy_file(os.path.join(cfg['base_dir'], 'license.txt'), + prepend_destdir(os.path.join(target_doc_dir, 'license.txt'))) + copy_file(os.path.join(cfg['base_dir'], 'news.rst'), + prepend_destdir(os.path.join(target_doc_dir, 'news.txt'))) + for f in [f for f in os.listdir(cfg['doc_dir']) if f.endswith('.txt')]: + copy_file(os.path.join(cfg['doc_dir'], f), prepend_destdir(os.path.join(target_doc_dir, f))) + + if cfg['with_rst2man']: + man1_dir = prepend_destdir(os.path.join(options.prefix, os.path.join(cfg['mandir'], 'man1'))) + makedirs(man1_dir) + + copy_file(os.path.join(cfg['build_dir'], 'botan.1'), + os.path.join(man1_dir, 'botan.1')) + + logging.info('Botan %s installation complete', cfg['version']) + return 0 + +if __name__ == '__main__': + try: + sys.exit(main(sys.argv)) + except Exception as e: # pylint: disable=broad-except + logging.error('Failure: %s' % (e)) + logging.info(traceback.format_exc()) + sys.exit(1) diff --git a/comm/third_party/botan/src/scripts/macro_checks.py b/comm/third_party/botan/src/scripts/macro_checks.py new file mode 100755 index 0000000000..df1a503c6c --- /dev/null +++ b/comm/third_party/botan/src/scripts/macro_checks.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +# (C) 2018 Jack Lloyd +# Botan is released under the Simplified BSD License (see license.txt) + +# Scans all source and test files and makes sure we are not using a +# BOTAN_HAS_xxx macro which is not actually defined anywhere. + +from configure import ModuleInfo, load_info_files +import os +import re +import logging + +src_dir = 'src' +lib_dir = os.path.join(src_dir, 'lib') + +info_modules = load_info_files(lib_dir, 'Modules', "info.txt", ModuleInfo) + +all_defines = set() + +for module in info_modules.values(): + for define in module._defines: + all_defines.add(define) + +extras = ['MP_DWORD', 'VALGRIND', 'SANITIZER_UNDEFINED', + 'ONLINE_REVOCATION_CHECKS', 'NIST_PRIME_REDUCERS_W32'] + +for extra in extras: + all_defines.add(extra) + +macro = re.compile('BOTAN_HAS_([A-Z0-9_]+)') + +for dirname, subdirs, files in os.walk(src_dir): + for fname in files: + if fname.endswith('.h') or fname.endswith('.cpp'): + contents = open(os.path.join(dirname, fname)).read() + + for m in re.finditer(macro, contents): + + if m.group(1) not in all_defines: + logging.error('In %s found unknown feature macro %s' % (fname, m.group(1))) + diff --git a/comm/third_party/botan/src/scripts/monty.py b/comm/third_party/botan/src/scripts/monty.py new file mode 100755 index 0000000000..f253da3f67 --- /dev/null +++ b/comm/third_party/botan/src/scripts/monty.py @@ -0,0 +1,98 @@ +#!/usr/bin/python3 + +import sys +import datetime + +# (C) 2018 Jack Lloyd +# Botan is released under the Simplified BSD License (see license.txt) + +# Used to generate src/lib/math/mp/mp_monty_n.cpp + +def monty_redc_code(n): + + lines = [] + + lines.append("word w2 = 0, w1 = 0, w0 = 0;") + lines.append("w0 = z[0];") + lines.append("ws[0] = w0 * p_dash;") + + lines.append("word3_muladd(&w2, &w1, &w0, ws[0], p[0]);") + lines.append("w0 = w1; w1 = w2; w2 = 0;") + + for i in range(1, n): + for j in range(0, i): + lines.append("word3_muladd(&w2, &w1, &w0, ws[%d], p[%d]);" % (j, i-j)) + + lines.append("word3_add(&w2, &w1, &w0, z[%d]);" % (i)) + lines.append("ws[%d] = w0 * p_dash;" % (i)) + + lines.append("word3_muladd(&w2, &w1, &w0, ws[%d], p[0]);" % (i)) + lines.append("w0 = w1; w1 = w2; w2 = 0;") + + for i in range(0, n): + for j in range(i + 1, n): + lines.append("word3_muladd(&w2, &w1, &w0, ws[%d], p[%d]);" % (j, n + i-j)) + + lines.append("word3_add(&w2, &w1, &w0, z[%d]);" % (n+i)) + lines.append("ws[%d] = w0;" % (i)) + lines.append("w0 = w1; w1 = w2; w2 = 0;") + + lines.append("word3_add(&w2, &w1, &w0, z[%d]);" % (2*(n+1) - 1)) + + lines.append("ws[%d] = w0;" % (n)) + lines.append("ws[%d] = w1;" % (n+1)) + + if n < 16: + lines.append("word borrow = 0;") + for i in range(n): + lines.append("ws[%d] = word_sub(ws[%d], p[%d], &borrow);" % (n + 1 + i, i, i)) + lines.append("ws[%d] = word_sub(ws[%d], 0, &borrow);" % (2*n+1, n)) + else: + lines.append("word borrow = bigint_sub3(ws + %d + 1, ws, %d + 1, p, %d);" % (n, n, n)) + + lines.append("CT::conditional_copy_mem(borrow, z, ws, ws + %d, %d);" % (n + 1, n + 1)) + lines.append("clear_mem(z + %d, 2*(%d+1) - %d);" % (n, n, n)) + + for line in lines: + print(" %s" % (line)) + +def main(args = None): + if args is None: + args = sys.argv + + if len(args) <= 1: + sizes = [4, 6, 8, 16, 24, 32] + else: + sizes = map(int, args[1:]) + + print("""/* +* This file was automatically generated by %s on %s +* All manual changes will be lost. Edit the script instead. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include + +namespace Botan { +""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"))) + + for n in sizes: + print("void bigint_monty_redc_%d(word z[], const word p[%d], word p_dash, word ws[])" % (n, n)) + print(" {") + + monty_redc_code(n) + + print(" }\n") + + print("}") + + return 0 + +if __name__ == '__main__': + sys.exit(main()) + + diff --git a/comm/third_party/botan/src/scripts/oids.py b/comm/third_party/botan/src/scripts/oids.py new file mode 100755 index 0000000000..323b6efb50 --- /dev/null +++ b/comm/third_party/botan/src/scripts/oids.py @@ -0,0 +1,337 @@ +#!/usr/bin/python + +""" +(C) 2016 Jack Lloyd +(C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import sys +import datetime +import re +from collections import defaultdict + +def format_oid(oid): + #return '"' + oid + '"' + return "{" + oid.replace('.', ',') + '}' + +def format_map(m, for_oid = False): + s = '' + for k in sorted(m.keys()): + v = m[k] + + if len(s) > 0: + s += ' ' + + if for_oid: + s += '{ "%s", OID(%s) },\n' % (k,format_oid(v)) + else: + s += '{ "%s", "%s" },\n' % (k,v) + + s = s[:-2] # chomp last two chars + + return s + + +def format_as_map(oid2str, str2oid): + return """/* +* OID maps +* +* This file was automatically generated by %s on %s +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include + +namespace Botan { + +std::unordered_map OIDS::load_oid2str_map() + { + return std::unordered_map{ + %s + }; + } + +std::unordered_map OIDS::load_str2oid_map() + { + return std::unordered_map{ + %s + }; + } + +} +""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"), + format_map(oid2str), format_map(str2oid, True)) + + +def format_if(m, nm,t=False): + s = '' + for k in sorted(m.keys()): + v = m[k] + + if t: + s += ' if(%s == "%s") return OID(%s);\n' % (nm,k, format_oid(v)) + else: + s += ' if(%s == "%s") return "%s";\n' % (nm,k, v) + + s = s[:-1] + + return s + +def format_as_ifs(oid2str, str2oid): + return """/* +* OID maps +* +* This file was automatically generated by %s on %s +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +namespace Botan { + +namespace OIDS { + +std::string lookup(const OID& oid) + { + const std::string oid_str = oid.to_string(); +%s + + return std::string(); + } + +OID lookup(const std::string& name) + { +%s + + return OID(); + } + +} + +} +""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"), + format_if(oid2str,"oid_str"), format_if(str2oid, "name", True)) + + +def format_dn_ub_map(dn_ub, oid2str): + s = '' + for k in sorted(dn_ub.keys()): + v = dn_ub[k] + + s += ' { Botan::OID({%s}), %s }, // %s\n' % (k.replace('.',','),v,oid2str[k]) + + # delete last ',' and \n + idx = s.rfind(',') + if idx != -1: + s = s[:idx] + s[idx+1:-1] + + return s + + +def format_dn_ub_as_map(dn_ub, oid2str): + return """/* +* DN_UB maps: Upper bounds on the length of DN strings +* +* This file was automatically generated by %s on %s +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include + +namespace { + +/** + * Upper bounds for the length of distinguished name fields as given in RFC 5280, Appendix A. + * Only OIDS recognized by botan are considered, so far. + * Maps OID string representations instead of human readable strings in order + * to avoid an additional lookup. + */ +static const std::map DN_UB = + { +%s + }; +} + +namespace Botan { + +//static +size_t X509_DN::lookup_ub(const OID& oid) + { + auto ub_entry = DN_UB.find(oid); + if(ub_entry != DN_UB.end()) + { + return ub_entry->second; + } + else + { + return 0; + } + } +} +""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"), + format_dn_ub_map(dn_ub,oid2str)) + + +def format_set_map(m): + s = '' + for k in sorted(m.keys()): + v = m[k] + + if len(s) > 0: + s += ' ' + + s += '{ "%s", {' % k + for pad in v: + s += '"%s", ' % pad + if len(v) is not 0: + s = s[:-2] + s += '} },\n' + s = s[:-1] + return s + + +def format_pads_as_map(sig_dict): + return """/* +* Sets of allowed padding schemes for public key types +* +* This file was automatically generated by %s on %s +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const std::unordered_map> allowed_signature_paddings = + { + %s + }; + +} + +const std::vector get_sig_paddings(const std::string algo) + { + auto i = allowed_signature_paddings.find(algo); + if(i != allowed_signature_paddings.end()) + return i->second; + return {}; + } + +bool sig_algo_and_pad_ok(const std::string algo, std::string padding) + { + const std::vector pads = get_sig_paddings(algo); + return std::find(pads.begin(), pads.end(), padding) != pads.end(); + } + +} +""" % (sys.argv[0], datetime.date.today().strftime("%Y-%m-%d"), + format_set_map(sig_dict)) + + +def main(args = None): + """ Print header files (oids.cpp, dn_ub.cpp) depending on the first argument and on src/build-data/oids.txt + + Choose 'oids' to print oids.cpp, needs to be written to src/lib/asn1/oids.cpp + Choose 'dn_ub' to print dn_ub.cpp, needs to be written to src/lib/x509/X509_dn_ub.cpp + Choose 'pads' to print padding.cpp, needs to be written to src/lib/pk_pad/padding.cpp + """ + if args is None: + args = sys.argv + if len(args) < 2: + raise Exception("Use either 'oids', 'dn_ub', 'pads' as first argument") + + oid_lines = open('./src/build-data/oids.txt').readlines() + + oid_re = re.compile("^([0-9][0-9.]+) = ([A-Za-z0-9_\./\(\), -]+)(?: = )?([0-9]+)?$") + hdr_re = re.compile("^\[([a-z0-9_]+)\]$") + pad_re = re.compile("^([A-Za-z0-9_\., -]+)/([A-Za-z0-9_-]+)[A-Za-z0-9_\.\(\), -]*$") + + oid2str = {} + str2oid = {} + dn_ub = {} + sig2pads = defaultdict(set) + cur_hdr = None + + for line in oid_lines: + line = line.strip() + if len(line) == 0: + continue + + if line[0] == '#': + continue + + match = hdr_re.match(line) + if match is not None: + cur_hdr = match.group(1) + continue + + match = oid_re.match(line) + if match is None: + raise Exception(line) + + oid = match.group(1) + nam = match.group(2) + + if oid in str2oid: + print("Duplicated OID", oid, name, oid2str[oid]) + sys.exit() # hard error + else: + oid2str[oid] = nam + + # parse upper bounds for DNs + if cur_hdr == "dn": + if match.lastindex < 3: + raise Exception("Could not find an upper bound for DN " + match.group(1)) + dn_ub[oid] = match.group(3) + # parse signature paddings + elif cur_hdr == "signature": + pad_match = pad_re.search(nam) + if pad_match is not None: + sig2pads[pad_match.group(1)].add(pad_match.group(2)) + + if nam in str2oid: + #str2oid[nam] = oid + pass + else: + str2oid[nam] = oid + + if args[1] == "oids": + print(format_as_map(oid2str, str2oid)) + elif args[1] == "dn_ub": + print(format_dn_ub_as_map(dn_ub,oid2str)) + elif args[1] == "pads": + print(format_pads_as_map(sig2pads)) + else: + print("Unknown command: try oids, dn_ub, or pads") + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/python_unittests.py b/comm/third_party/botan/src/scripts/python_unittests.py new file mode 100755 index 0000000000..a6a22f3f0b --- /dev/null +++ b/comm/third_party/botan/src/scripts/python_unittests.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 + +""" +Unittests for Botan Python scripts. + +Requires Python 3. + +(C) 2017 Simon Warta (Kullo GmbH) + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import sys +import unittest + +sys.path.append("../..") # Botan repo root +from configure import AmalgamationHelper # pylint: disable=wrong-import-position +from configure import ModulesChooser # pylint: disable=wrong-import-position + +class AmalgamationHelperTests(unittest.TestCase): + def test_matcher_std_includes(self): + self.assertEqual(AmalgamationHelper.is_unconditional_std_include("#include "), "string") + self.assertEqual(AmalgamationHelper.is_unconditional_std_include("#include // comment"), "string") + + self.assertEqual(AmalgamationHelper.is_unconditional_std_include("#include "), None) + self.assertEqual(AmalgamationHelper.is_unconditional_std_include("#include "), None) + self.assertEqual(AmalgamationHelper.is_unconditional_std_include(" #include "), None) + + def test_matcher_botan_include(self): + self.assertEqual(AmalgamationHelper.is_botan_include("#include "), + "oids.h") + self.assertEqual(AmalgamationHelper.is_botan_include("#include "), + "internal/socket.h") + self.assertEqual(AmalgamationHelper.is_botan_include("#include // comment"), + "oids.h") + self.assertEqual(AmalgamationHelper.is_botan_include("#include // comment"), + "internal/socket.h") + self.assertEqual(AmalgamationHelper.is_botan_include(" #include "), + "oids.h") + self.assertEqual(AmalgamationHelper.is_botan_include(" #include "), + "internal/socket.h") + + self.assertEqual(AmalgamationHelper.is_botan_include("#include "), None) + self.assertEqual(AmalgamationHelper.is_botan_include("#include "), None) + self.assertEqual(AmalgamationHelper.is_botan_include("#include "), None) + + def test_matcher_any_includes(self): + self.assertEqual(AmalgamationHelper.is_any_include("#include "), "string") + self.assertEqual(AmalgamationHelper.is_any_include("#include "), "myfile.h") + self.assertEqual(AmalgamationHelper.is_any_include("#include "), "unistd.h") + self.assertEqual(AmalgamationHelper.is_any_include("#include "), + "botan/oids.h") + self.assertEqual(AmalgamationHelper.is_any_include(" #include "), "string") + self.assertEqual(AmalgamationHelper.is_any_include(" #include "), "myfile.h") + self.assertEqual(AmalgamationHelper.is_any_include(" #include "), "unistd.h") + self.assertEqual(AmalgamationHelper.is_any_include(" #include "), + "botan/oids.h") + self.assertEqual(AmalgamationHelper.is_any_include("#include // comment"), "string") + self.assertEqual(AmalgamationHelper.is_any_include("#include // comment"), "myfile.h") + self.assertEqual(AmalgamationHelper.is_any_include("#include // comment"), "unistd.h") + self.assertEqual(AmalgamationHelper.is_any_include("#include // comment"), + "botan/oids.h") + +class ModulesChooserResolveDependencies(unittest.TestCase): + def test_base(self): + available_modules = set(["A", "B"]) + table = { + "A": [], + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A"])) + + def test_no_dependencies_defined(self): + available_modules = set(["A", "B"]) + table = { + "A": [], + } + with self.assertRaises(KeyError): + ModulesChooser.resolve_dependencies(available_modules, table, "B") + + available_modules = set(["A", "B"]) + table = { + "A": ["B"], + } + with self.assertRaises(KeyError): + ModulesChooser.resolve_dependencies(available_modules, table, "A") + + def test_add_dependency(self): + available_modules = set(["A", "B"]) + table = { + "A": ["B"], + "B": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "B"])) + + def test_add_dependencies_two_levels(self): + available_modules = set(["A", "B", "C"]) + table = { + "A": ["B"], + "B": ["C"], + "C": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "B", "C"])) + + def test_circular(self): + available_modules = set(["A", "B", "C"]) + table = { + "A": ["B"], + "B": ["C"], + "C": ["A"] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "B", "C"])) + + def test_not_available(self): + available_modules = set(["A", "C"]) + table = { + "A": ["B"], + "B": ["C"], + "C": ["A"] + } + ok, _ = ModulesChooser.resolve_dependencies(available_modules, table, "B") + self.assertFalse(ok) + + def test_dependency_not_available(self): + available_modules = set(["A", "C"]) + table = { + "A": ["B"], + "B": ["C"], + "C": ["A"] + } + ok, _ = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertFalse(ok) + + def test_dependency2_not_available(self): + available_modules = set(["A", "B"]) + table = { + "A": ["B"], + "B": ["C"], + "C": ["A"] + } + ok, _ = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertFalse(ok) + + def test_dependency_choices(self): + available_modules = set(["A", "B", "C"]) + table = { + "A": ["B|C"], + "B": [], + "C": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertTrue(modules == set(["A", "B"]) or modules == set(["A", "C"])) + + def test_dependency_prefer_existing(self): + available_modules = set(["A", "B", "C"]) + table = { + "A": ["C", "B|C"], + "B": [], + "C": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "C"])) + + def test_dependency_prefer_existing2(self): + available_modules = set(["A", "B", "C"]) + table = { + "A": ["B", "B|C"], + "B": [], + "C": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "B"])) + + def test_dependency_choices_impossible(self): + available_modules = set(["A", "C"]) + table = { + "A": ["B|C"], + "B": [], + "C": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "C"])) + + def test_dependency_choices_impossible2(self): + available_modules = set(["A", "B"]) + table = { + "A": ["B|C"], + "B": [], + "C": [] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "A") + self.assertTrue(ok) + self.assertEqual(modules, set(["A", "B"])) + + def test_deep(self): + available_modules = set(["A", "B", "C", "E", "G"]) + table = { + "A": ["B|C"], + "B": ["D"], + "C": ["E"], + "D": [], + "E": ["F|G"], + "F": ["A", "B"], + "G": ["A", "G"] + } + ok, modules = ModulesChooser.resolve_dependencies(available_modules, table, "G") + self.assertTrue(ok) + self.assertEqual(modules, set(["G", "A", "C", "E"])) + + +if __name__ == '__main__': + unittest.TestCase.longMessage = True + unittest.main() diff --git a/comm/third_party/botan/src/scripts/python_unittests_unix.py b/comm/third_party/botan/src/scripts/python_unittests_unix.py new file mode 100755 index 0000000000..fe9f06a62a --- /dev/null +++ b/comm/third_party/botan/src/scripts/python_unittests_unix.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +""" +Unittests for Botan Python scripts. Those tests only need to pass un UNIX-like +operating systems. + +Requires Python 3. + +(C) 2017 Simon Warta (Kullo GmbH) + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import os +import sys +import unittest + +sys.path.append("../..") # Botan repo root +from install import prepend_destdir # pylint: disable=wrong-import-position +from install import PrependDestdirError # pylint: disable=wrong-import-position + + +class PrependDestdir(unittest.TestCase): + def test_absolute_destdir(self): + os.environ["DESTDIR"] = "/" + self.assertEqual(prepend_destdir("/home/me"), "/home/me") + self.assertEqual(prepend_destdir("/home/me/"), "/home/me") + self.assertEqual(prepend_destdir("/home/me/../me2"), "/home/me2") + + os.environ["DESTDIR"] = "/opt" + self.assertEqual(prepend_destdir("/home/me"), "/opt/home/me") + self.assertEqual(prepend_destdir("/home/me/"), "/opt/home/me") + self.assertEqual(prepend_destdir("/home/me/../me2"), "/opt/home/me2") + + def test_relative_destdir(self): + os.environ["DESTDIR"] = "." + self.assertEqual(prepend_destdir("/home/me"), "./home/me") + self.assertEqual(prepend_destdir("/home/me/"), "./home/me") + self.assertEqual(prepend_destdir("/home/me/../me2"), "./home/me2") + + os.environ["DESTDIR"] = "bar" + self.assertEqual(prepend_destdir("/home/me"), "bar/home/me") + self.assertEqual(prepend_destdir("/home/me/"), "bar/home/me") + self.assertEqual(prepend_destdir("/home/me/../me2"), "bar/home/me2") + + def test_relative(self): + # No destdir set + os.environ["DESTDIR"] = "" + self.assertEqual(prepend_destdir("foo"), "foo") + self.assertEqual(prepend_destdir("../foo"), "../foo") + + # Destdir set + os.environ["DESTDIR"] = "/opt" + with self.assertRaises(PrependDestdirError): + prepend_destdir("foo") + with self.assertRaises(PrependDestdirError): + prepend_destdir("../foo") + + def test_escaping(self): + os.environ["DESTDIR"] = "/opt" + with self.assertRaises(PrependDestdirError): + prepend_destdir("/foo/../..") + + +if __name__ == '__main__': + unittest.TestCase.longMessage = True + unittest.main() diff --git a/comm/third_party/botan/src/scripts/run_tls_attacker.py b/comm/third_party/botan/src/scripts/run_tls_attacker.py new file mode 100755 index 0000000000..a773646334 --- /dev/null +++ b/comm/third_party/botan/src/scripts/run_tls_attacker.py @@ -0,0 +1,138 @@ +#!/usr/bin/python + +import os +import sys +import subprocess +import tempfile +import time +import random +import optparse +import string + +def run_subprocess(cmd): + print("Running '%s'" % (' '.join(cmd))) + + proc = subprocess.Popen(cmd, bufsize=-1) + proc.communicate() + + if proc.returncode != 0: + print('Running "%s" failed rc %d' % (' '.join(cmd), proc.returncode)) + sys.exit(proc.returncode) + +def spawn_server(cmd): + print("Spawning '%s'" % (' '.join(cmd))) + return subprocess.Popen(cmd, bufsize=-1)#,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + +def main(args=None): + if args is None: + args = sys.argv + + parser = optparse.OptionParser() + + parser.add_option('--type', default='tests', + help='Which TLS-Attacker tests to run (tests, policy, fuzzer)') + parser.add_option('--src-dir', metavar='DIR', default='./src', + help='Specify path to botan sources (default "%default")') + parser.add_option('--verbose', action='store_true', + help='Be noisy') + + (options, args) = parser.parse_args(args) + + if len(args) != 3: + print("Usage: %s botan_cli_exe botan_ci_tools" % (args[0])) + return 1 + + cli_exe = args[1] + ci_tools = args[2] + test_type = options.type + src_dir = options.src_dir + + if test_type not in ['tests', 'policy', 'fuzzer']: + print("Unknown --type %s" % (options.test_type)) + return 1 + + if os.access(cli_exe, os.X_OK) != True: + print("Unable to find CLI tool at %s" % (cli_exe)) + return 1 + + if os.access(src_dir, os.X_OK) != True: + print("Unable to find src dir at %s" % (src_dir)) + return 1 + + test_data_dir = os.path.join(src_dir, 'tests/data') + + lax_policy_txt = os.path.join(test_data_dir, 'tls-policy/compat.txt') + bsi_policy_txt = os.path.join(test_data_dir, 'tls-policy/bsi.txt') + + tls_attacker_dir = os.path.join(ci_tools, 'TLS-Attacker') + tls_attacker_jar = os.path.join(tls_attacker_dir, 'TLS-Attacker-1.2.jar') + tls_attacker_testsuites = os.path.join(tls_attacker_dir, 'resources/testsuite') + tls_fuzzer_workflows = os.path.join(tls_attacker_dir, 'resources/fuzzing/workflows') + + if os.access(tls_attacker_jar, os.R_OK) != True: + print("Unable to find TLS-Attacker jar at %s" % (tls_attacker_jar)) + return 1 + + rsa_key = tempfile.NamedTemporaryFile(prefix='rsa_key_') + rsa_crt = tempfile.NamedTemporaryFile(prefix='rsa_crt_') + + run_subprocess([cli_exe, 'keygen', '--algo=RSA', '--params=2048', '--output=%s' % (rsa_key.name)]) + run_subprocess([cli_exe, 'gen_self_signed', rsa_key.name, 'localhost', '--output=%s' % (rsa_crt.name)]) + + server_log = 'botan_log.txt' + server_err_log = 'botan_err_log.txt' + + tls_port = random.randint(50000, 60000) + + botan_server_cmd = [cli_exe, 'tls_server', rsa_crt.name, rsa_key.name, + '--port=%d' % (tls_port), + '--output='+server_log, + '--error-output='+server_err_log] + + java_tls_attacker = ['java', '-jar', tls_attacker_jar, + '-loglevel', 'DEBUG' if options.verbose else 'ERROR'] + tls_attacker_opts = ['-tls_timeout', '300', '-connect', 'localhost:%d' % (tls_port)] + + if test_type == 'tests': + try: + server_process = spawn_server(botan_server_cmd + + ['--policy=%s' % (lax_policy_txt)]) + time.sleep(1) + run_subprocess(java_tls_attacker + ['testsuite_server'] + tls_attacker_opts + + ['-folder', tls_attacker_testsuites]) + finally: + server_process.terminate() + elif test_type == 'policy': + try: + server_process = spawn_server(botan_server_cmd + + ['--policy=%s' % (bsi_policy_txt)]) + time.sleep(1) + run_subprocess(java_tls_attacker + ['testtls_server'] + tls_attacker_opts + + ['-policy', bsi_policy_txt]) + finally: + server_process.terminate() + elif test_type == 'fuzzer': + + template_mapping = { + 'rsa_key': rsa_key.name, + 'rsa_cert': rsa_crt.name, + 'botan_cli': cli_exe, + 'workflow_dir': tls_fuzzer_workflows, + 'fuzz_policy': lax_policy_txt, + 'tls_port': str(tls_port), + 'PORT': '$PORT' # this is a var for TLS-Attacker don't touch it + } + + template_txt = open(os.path.join(src_dir, 'scripts/fuzzer.xml')).read() + + config = string.Template(template_txt).substitute(template_mapping) + + fuzzer_config = tempfile.NamedTemporaryFile(prefix='fuzzer_cfg_', delete=False) + fuzzer_config.write(config.encode('ascii')) + fuzzer_config.close() + + run_subprocess(java_tls_attacker + ['multi_fuzzer'] + + ['-startup_command_file', fuzzer_config.name]) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/run_tls_fuzzer.py b/comm/third_party/botan/src/scripts/run_tls_fuzzer.py new file mode 100755 index 0000000000..b4ee91d247 --- /dev/null +++ b/comm/third_party/botan/src/scripts/run_tls_fuzzer.py @@ -0,0 +1,98 @@ +#!/usr/bin/python + +import argparse +import subprocess +import logging +import sys +import os +import time + +def script_is_disabled(script_name): + if script_name.find('tls13') >= 0: + return True + if script_name.find('sslv2') >= 0: + return True + + disabled = { + 'test-SSLv3-padding.py', + 'test-serverhello-random.py', # assumes support for SSLv2 hello + 'test-x25519.py', # assumes support for X448 (!) + } + + if script_name in disabled: + return True + + slow = { + 'test-bleichenbacher-workaround.py', + 'test-client-compatibility.py', + 'test-dhe-key-share-random.py', + 'test-dhe-no-shared-secret-padding.py', + 'test-ecdhe-padded-shared-secret.py', + 'test-ecdhe-rsa-key-share-random.py', + 'test-fuzzed-plaintext.py', + 'test-invalid-client-hello-w-record-overflow.py', + 'test-invalid-client-hello.py', + 'test-large-hello.py', + } + if script_name in slow: + return True + + return False + +def main(args = None): + if args is None: + args = sys.argv[1:] + + parser = argparse.ArgumentParser() + + # TODO generate key and spawn the server on some random port in tmp dir + # TODO support running tls_server binary under valgrind + + parser.add_argument('--verbose', action='store_true', default=False) + parser.add_argument('tls-fuzzer-dir') + + args = vars(parser.parse_args(args)) + + tlsfuzzer_dir = args['tls-fuzzer-dir'] + + if not os.access(tlsfuzzer_dir, os.X_OK): + raise Exception("Unable to read TLS fuzzer dir") + + tls_scripts_dir = os.path.join(tlsfuzzer_dir, 'scripts') + if not os.access(tlsfuzzer_dir, os.X_OK): + raise Exception("Unable to read TLS fuzzer scripts dir") + + scripts = sorted(os.listdir(tls_scripts_dir)) + + procs = {} + + for script in scripts: + if script_is_disabled(script): + logging.debug('Skipping %s' % (script)) + continue + + procs[script] = subprocess.Popen([sys.executable, os.path.join(tls_scripts_dir, script)], + cwd=tlsfuzzer_dir, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + results = {} + + while len(results) != len(procs): + time.sleep(.5) + for (script, proc) in procs.items(): + + if script in results: + continue + + if proc.poll() != None: + rv = proc.returncode + results[script] = rv + if rv == 0: + print("PASS %s" % (script)) + else: + print("FAIL %s" % (script)) + sys.stdout.flush() + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/show_dependencies.py b/comm/third_party/botan/src/scripts/show_dependencies.py new file mode 100755 index 0000000000..edf2d91e01 --- /dev/null +++ b/comm/third_party/botan/src/scripts/show_dependencies.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python + +""" +Show Botan module dependencies as a list or graph. + +Requires graphviz from pip when graphical output is selected: +https://pypi.python.org/pypi/graphviz + +(C) 2015,2018 Simon Warta (Kullo GmbH) + +Botan is released under the Simplified BSD License (see license.txt) +""" + +# global +import argparse +import copy +import sys +import subprocess +from collections import OrderedDict +import glob +import os + +# Assume this script is in botan/src/scripts +botan_root = os.path.join(os.path.dirname(sys.argv[0]), "..", "..") + +# locale +sys.path.append(botan_root) +from configure import ModuleInfo + +parser = argparse.ArgumentParser(description= + 'Show Botan module dependencies. ' + 'The output is reduced by indirect dependencies, ' + 'i.e. you must look at the result recursively to get all dependencies.') + +parser.add_argument('mode', + choices=["list", "draw"], + help='The output mode') +parser.add_argument('--format', + nargs='?', + choices=["pdf", "png"], + default="pdf", + help='The file format (drawing mode only)') +parser.add_argument('--engine', + nargs='?', + choices=["fdp", "dot"], + default="dot", + help='The graph engine (drawing mode only)') +parser.add_argument('--all', dest='all', action='store_const', + const=True, default=False, + help='Show all dependencies. Default: direct dependencies only. (list mode only)') +parser.add_argument('--verbose', dest='verbose', action='store_const', + const=True, default=False, + help='Verbose output (default: false)') +args = parser.parse_args() + +files = [] +files += glob.glob(botan_root + '/src/lib/*/*/*/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/*/info.txt') +files += glob.glob(botan_root + '/src/lib/*/info.txt') +files += glob.glob(botan_root + '/src/lib/info.txt') +files.sort() + +if len(files) == 0: + print("No info.txt files found.") + sys.exit(1) + +modules = [] + +def dicts(t): return {k: dicts(t[k]) for k in t} + +def paths(t, path = [], level=0): + ret = [] + for key in t: + ret.append(path + [key]) + ret += paths(t[key], path + [key], level+1) + return ret + +if args.verbose: + print("Getting dependencies from into.txt files ...") + +for filename in files: + (rest, info_txt) = os.path.split(filename) + (rest, modname) = os.path.split(rest) + module = ModuleInfo(filename) + modules.append(module) + if args.verbose: + print(module.basename) + print("\t" + str(set(module.dependencies(None)))) + +if args.verbose: + print(str(len(modules)) + " modules:") + names=[m.basename for m in modules] + names.sort() + print(names) + print("") + +if args.verbose: + print("resolving dependencies ...") + +def cartinality(depdict): + return sum([len(depdict[k]) for k in depdict]) + +registered_dependencies = dict() +all_dependencies = dict() +direct_dependencies = dict() + +for module in modules: + lst = module.dependencies(None) + registered_dependencies[module.basename] = set(lst) - set([module.basename]) + +# Get all_dependencies from registered_dependencies +def add_dependency(): + for key in all_dependencies: + potentially_new_modules_for_key = None + new_modules_for_key = None + for currently_in in all_dependencies[key]: + if currently_in in all_dependencies: + potentially_new_modules_for_key = all_dependencies[currently_in] - set([key]) + if not potentially_new_modules_for_key <= all_dependencies[key]: + new_modules_for_key = potentially_new_modules_for_key.copy() + break + if new_modules_for_key: + all_dependencies[key] |= new_modules_for_key + return + + +all_dependencies = copy.deepcopy(registered_dependencies) +direct_dependencies = copy.deepcopy(registered_dependencies) + +# Sort +all_dependencies = OrderedDict(sorted(all_dependencies.items())) +direct_dependencies = OrderedDict(sorted(direct_dependencies.items())) + +#print(direct_dependencies) + +last_card = -1 +while True: + card = cartinality(all_dependencies) + # print(card) + if card == last_card: + break + last_card = card + add_dependency() + +# Return true iff a depends on b, +# i.e. b is in the dependencies of a +def depends_on(a, b): + if not a in direct_dependencies: + return False + else: + return b in direct_dependencies[a] + +def remove_indirect_dependencies(): + for mod in direct_dependencies: + for one in direct_dependencies[mod]: + others = direct_dependencies[mod] - set([one]) + for other in others: + if depends_on(other, one): + direct_dependencies[mod].remove(one) + return + # Go to next mod + +last_card = -1 +while True: + card = cartinality(direct_dependencies) + # print(card) + if card == last_card: + break + last_card = card + remove_indirect_dependencies() + +def openfile(f): + # pylint: disable=no-member + # os.startfile is available on Windows only + if sys.platform.startswith('linux'): + subprocess.call(["xdg-open", f]) + else: + os.startfile(f) + +if args.verbose: + print("Done resolving dependencies.") + +if args.mode == "list": + if args.all: + for key in all_dependencies: + print(key.ljust(17) + " : " + ", ".join(sorted(all_dependencies[key]))) + else: + for key in direct_dependencies: + print(key.ljust(17) + " : " + ", ".join(sorted(direct_dependencies[key]))) + +if args.mode == "draw": + import graphviz as gv + import tempfile + + tmpdir = tempfile.mkdtemp(prefix="botan-") + + g2 = gv.Digraph(format=args.format, engine=args.engine) + g2.attr('graph', rankdir='RL') # draw horizontally + for key in direct_dependencies: + g2.node(key) + for dep in direct_dependencies[key]: + g2.edge(key, dep) + + if args.verbose: + print("Rendering graph ...") + filename = g2.render(filename='graph', directory=tmpdir) + + if args.verbose: + print("Opening " + filename + " ...") + openfile(filename) diff --git a/comm/third_party/botan/src/scripts/test_all_configs.py b/comm/third_party/botan/src/scripts/test_all_configs.py new file mode 100755 index 0000000000..227abd952f --- /dev/null +++ b/comm/third_party/botan/src/scripts/test_all_configs.py @@ -0,0 +1,136 @@ +#!/usr/bin/python + +""" +This configures and builds with many different sub-configurations +in an attempt to flush out missing feature macro checks, etc. + +There is probably no reason for you to run this. Unless you want to. + +(C) 2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import optparse # pylint: disable=deprecated-module +import sys +import subprocess + +def get_module_list(configure_py): + configure = subprocess.Popen([configure_py, '--list-modules'], stdout=subprocess.PIPE) + + (stdout, _) = configure.communicate() + + if configure.returncode != 0: + raise Exception("Running configure.py --list-modules failed") + + modules = [s.decode('ascii') for s in stdout.split()] + modules.remove('tpm') # can't test + modules.remove('base') # can't remove + return modules + +def get_concurrency(): + def_concurrency = 2 + + try: + import multiprocessing + return max(def_concurrency, multiprocessing.cpu_count()) + except ImportError: + return def_concurrency + +def try_to_run(cmdline): + print("Running %s ... " % (' '.join(cmdline))) + sys.stdout.flush() + + cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = cmd.communicate() + + failed = (cmd.returncode != 0) + + if failed: + print("FAILURE") + print(stdout) + print(stderr) + sys.stdout.flush() + + return not failed + +def run_test_build(configure_py, modules, include, jobs, run_tests): + config = [configure_py, '--without-documentation'] + + if include: + config.append('--minimized') + if modules: + config.append('--enable-modules=' + ','.join(modules)) + else: + config.append('--disable-modules=' + ','.join(modules)) + + if try_to_run(config) is False: + return False + + if try_to_run(['make', '-j', str(jobs)]) is False: + return False + + if run_tests is False: + return True + + # Flaky test causing errors when running tests + tests_to_skip = [] + + cmdline = ['./botan-test', '--test-threads=%d' % (jobs)] + + if len(tests_to_skip) > 0: + cmdline.append('--skip-tests=%s' % (','.join(tests_to_skip))) + + return try_to_run(cmdline) + +def main(args): + + # TODO take configure.py and botan-test paths via options + + parser = optparse.OptionParser() + + parser.add_option('--run-tests', default=False, action='store_true') + parser.add_option('--jobs', default=get_concurrency(), + help="jobs to run (default %default)") + + (options, args) = parser.parse_args(args) + + run_tests = options.run_tests + jobs = int(options.jobs) + + configure_py = './configure.py' + modules = get_module_list(configure_py) + + cant_disable = ['block', 'hash', 'hex', 'mac', 'modes', 'rng', 'stream', 'utils', 'cpuid', 'entropy'] + always_include = ['thread_utils', 'sha2_64']#, 'sha2_64', 'aes'] + + fails = 0 + failed = [] + + for module in sorted(modules): + if (module in always_include) or (module in cant_disable): + continue # already testing it + + extra = [] + if module == 'auto_rng': + extra.append('dev_random') + if run_test_build(configure_py, [module] + always_include + extra, True, jobs, run_tests) is False: + failed.append(module) + fails += 1 + + for module in sorted(modules): + if module in cant_disable or module in always_include: + continue + if run_test_build(configure_py, [module], False, jobs, run_tests) is False: + failed.append(module) + fails += 1 + + if len(failed) > 0: + print("Failed building with %s" % (' '.join(failed))) + else: + print("All configurations ok") + + return fails + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/comm/third_party/botan/src/scripts/test_cli.py b/comm/third_party/botan/src/scripts/test_cli.py new file mode 100755 index 0000000000..4e0f8ab830 --- /dev/null +++ b/comm/third_party/botan/src/scripts/test_cli.py @@ -0,0 +1,1429 @@ +#!/usr/bin/python + +""" +(C) 2018,2019 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import subprocess +import sys +import os +import logging +import optparse # pylint: disable=deprecated-module +import time +import shutil +import tempfile +import re +import random +import json +import binascii +import multiprocessing +from multiprocessing.pool import ThreadPool + +# pylint: disable=global-statement,unused-argument + +CLI_PATH = None +TESTS_RUN = 0 +TESTS_FAILED = 0 + +class TestLogHandler(logging.StreamHandler, object): + def emit(self, record): + # Do the default stuff first + super(TestLogHandler, self).emit(record) + if record.levelno >= logging.ERROR: + global TESTS_FAILED + TESTS_FAILED += 1 + +def setup_logging(options): + if options.verbose: + log_level = logging.DEBUG + elif options.quiet: + log_level = logging.WARNING + else: + log_level = logging.INFO + + lh = TestLogHandler(sys.stdout) + lh.setFormatter(logging.Formatter('%(levelname) 7s: %(message)s')) + logging.getLogger().addHandler(lh) + logging.getLogger().setLevel(log_level) + +def random_port_number(): + return random.randint(1024, 65535) + +def test_cli(cmd, cmd_options, expected_output=None, cmd_input=None, expected_stderr=None, use_drbg=True): + global TESTS_RUN + + TESTS_RUN += 1 + + opt_list = [] + + if isinstance(cmd_options, str): + opt_list = cmd_options.split(' ') + elif isinstance(cmd_options, list): + opt_list = cmd_options + + if use_drbg: + fixed_drbg_seed = "802" * 32 + drbg_options = ['--rng-type=drbg', '--drbg-seed=' + fixed_drbg_seed] + else: + drbg_options = [] + + cmdline = [CLI_PATH, cmd] + drbg_options + opt_list + + logging.debug("Executing '%s'" % (' '.join([CLI_PATH, cmd] + opt_list))) + + stdout = None + stderr = None + + if cmd_input is None: + proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = proc.communicate() + else: + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = proc.communicate(cmd_input.encode()) + + if stderr: + if expected_stderr is None: + logging.error("Got output on stderr %s (stdout was %s)", stderr, stdout) + else: + if stderr != expected_stderr: + logging.error("Got output on stderr %s which did not match expected value %s", stderr, expected_stderr) + else: + if expected_stderr is not None: + logging.error('Expected output on stderr but got nothing') + + output = stdout.decode('ascii').strip() + + if expected_output is not None: + if output != expected_output: + logging.error("Got unexpected output running cmd %s %s", cmd, cmd_options) + logging.info("Output lengths %d vs expected %d", len(output), len(expected_output)) + logging.info("Got %s", output) + logging.info("Exp %s", expected_output) + + return output + +def check_for_command(cmd): + cmdline = [CLI_PATH, 'has_command', cmd] + proc = subprocess.Popen(cmdline) + proc.communicate() + + return proc.returncode == 0 + +def cli_config_tests(_tmp_dir): + prefix = test_cli("config", "prefix") + cflags = test_cli("config", "cflags") + ldflags = test_cli("config", "ldflags") + libs = test_cli("config", "libs") + + if len(prefix) < 4 or prefix[0] != '/': + logging.error("Bad prefix %s" % (prefix)) + if ("-I%s/include/botan-2" % (prefix)) not in cflags: + logging.error("Bad cflags %s" % (cflags)) + if not ldflags.endswith(("-L%s/lib" % (prefix))): + logging.error("Bad ldflags %s" % (ldflags)) + if "-lbotan-2" not in libs: + logging.error("Bad libs %s" % (libs)) + +def cli_help_tests(_tmp_dir): + output = test_cli("help", None, None) + + # Maybe test format somehow?? + if len(output) < 500: + logging.error("Help output seems very short") + +def cli_version_tests(_tmp_dir): + output = test_cli("version", None, None) + + version_re = re.compile(r'[0-9]\.[0-9]+\.[0-9]') + if not version_re.match(output): + logging.error("Unexpected version output %s" % (output)) + + output = test_cli("version", ["--full"], None, None) + version_full_re = re.compile(r'Botan [0-9]\.[0-9]+\.[0-9] \(.* revision .*, distribution .*\)$') + if not version_full_re.match(output): + logging.error("Unexpected version output %s" % (output)) + +def cli_is_prime_tests(_tmp_dir): + test_cli("is_prime", "5", "5 is probably prime") + test_cli("is_prime", "9", "9 is composite") + test_cli("is_prime", "548950623407687320763", "548950623407687320763 is probably prime") + +def cli_gen_prime_tests(_tmp_dir): + test_cli("gen_prime", "64", "15568813029901363163") + test_cli("gen_prime", "128", "287193909494025008847286845478788766073") + +def cli_cycle_counter(_tmp_dir): + output = test_cli("cpu_clock", None, None) + + if output.startswith('No CPU cycle counter on this machine'): + return + + have_clock_re = re.compile(r'Estimated CPU clock [0-9\.]+ (M|G)Hz') + + if have_clock_re.match(output): + return + + logging.error('Unexpected output from cpu_clock: %s', output) + +def cli_entropy_tests(_tmp_dir): + output = test_cli("entropy", ["all"], None) + + status_re = re.compile('Polling [a-z0-9_]+ gathered [0-9]+ bytes in [0-9]+ outputs with estimated entropy [0-9]+') + unavail_re = re.compile('Source [a-z0-9_]+ is unavailable') + comp_re = re.compile('Sample from [a-z0-9_]+ was .* compressed from [0-9]+ bytes to [0-9]+ bytes') + output_re = re.compile(r'[A-F0-9]+(...)?') + + status_next = True + + for line in output.split('\n'): + if comp_re.match(line): + continue + + if status_next: + if status_re.match(line) is not None: + status_next = False + elif unavail_re.match(line) is not None: + pass + else: + logging.error('Unexpected status line %s', line) + status_next = False + else: + if output_re.match(line) is None: + logging.error('Unexpected sample line %s', line) + status_next = True + +def cli_factor_tests(_tmp_dir): + test_cli("factor", "97", "97: 97") + test_cli("factor", "9753893489562389", "9753893489562389: 21433 455087644733") + test_cli("factor", "12019502040659149507", "12019502040659149507: 3298628633 3643787579") + +def cli_mod_inverse_tests(_tmp_dir): + test_cli("mod_inverse", "97 802", "339") + test_cli("mod_inverse", "98 802", "0") + +def cli_base64_tests(_tmp_dir): + test_cli("base64_enc", "-", "YmVlcyE=", "bees!") + test_cli("base64_dec", "-", "bees!", "YmVlcyE=") + +def cli_base32_tests(_tmp_dir): + test_cli("base32_enc", "-", "MJSWK4ZB", "bees!") + test_cli("base32_dec", "-", "bees!", "MJSWK4ZB") + +def cli_base58_tests(_tmp_dir): + test_cli("base58_enc", "-", "C6sRAr4", "bees!") + test_cli("base58_dec", "-", "bees!", "C6sRAr4") + + test_cli("base58_enc", ["--check", "-"], "Cjv15cdjaBc", "F00F") + test_cli("base58_dec", ["--check", "-"], "F00F", "Cjv15cdjaBc") + +def cli_hex_tests(_tmp_dir): + test_cli("hex_enc", "-", "6265657321", "bees!") + test_cli("hex_dec", "-", "bees!", "6265657321") + +def cli_hash_tests(_tmp_dir): + test_cli("hash", "--algo=SHA-256", + "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -", "") + + test_cli("hash", "--algo=SHA-256", + "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD -", "abc") + + test_cli("hash", ["--algo=SHA-256", "--format=base64"], + "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= -", "abc") + + test_cli("hash", ["--algo=SHA-224", "--format=base58", "--no-fsname"], + "MuGc8HkSVyJjfMjPM5UQikPToBTzNucEghcGLe", "abc") + + test_cli("hash", ["--algo=SHA-224", "--format=base58check", "--no-fsname"], + "3MmfMqgrhemdVa9bDAGfooukbviWtKMBx2xauL2RsyAe", "abc") + +def cli_hmac_tests(tmp_dir): + key_file = os.path.join(tmp_dir, 'hmac.key') + + test_cli("rng", ["64", "--output=%s" % (key_file)], "") + + test_cli("hmac", ["--no-fsname", "--hash=SHA-384", key_file, key_file], + "E3A8529377030B28A7DBDFC50DDEC8E4ECEFB6EA850D95EB785938CD3E3AFEF9EF8B08AF219C1496633193468AB755CB") + +def cli_bcrypt_tests(_tmp_dir): + test_cli("gen_bcrypt", "--work-factor=4 s3kr1t", + "$2a$04$0.8G7o08XYwvBBWA3l0WUujtwoGZgGDzVSN8fNkNqXikcK4A3lHPS") + + test_cli("check_bcrypt", "s3kr1t $2a$04$gHX4Qg7pDSJuXiPXnmt8leyb.FFzX1Bv4rXwIj2cPSakJ8zNnhIka", + "Password is valid") + + test_cli("check_bcrypt", "santa $2a$04$gHX4Qg7pDSJuXiPXnmt8leyb.FFzX1Bv4rXwIj2cPSakJ8zNnhIka", + "Password is NOT valid") + +def cli_argon2_tests(_tmp_dir): + password = "s3kr1t" + expected = "$argon2id$v=19$m=8,t=1,p=1$2A+I9q2+ZayxDDYC5n2YWw$/Lhx+Jbtlpw+Kxpskfv7+AKhBL/5ebalTJkVC1O5+1E" + test_cli("gen_argon2", ['--mem=8', password], expected) + test_cli("gen_argon2", ['--mem=8', '--t=1', password], expected) + test_cli("gen_argon2", ['--mem=8', '--t=1', '--p=1', password], expected) + + test_cli("check_argon2", [password, expected], "Password is valid") + test_cli("check_argon2", ["guessing", expected], "Password is NOT valid") + +def cli_gen_dl_group_tests(_tmp_dir): + + pem = """-----BEGIN X9.42 DH PARAMETERS----- +MIIBJAKBgwTw7LQiLkXJsrgMVQxTPlWaQlYz/raZ+5RtIZe4YluQgRQGPFADLZ/t +TOYzuIzZJFOcdKtEtrVkxZRGSkjZwKFKLUD6fzSjoC2M2EHktK/y5HsvxBxL4tKr +q1ffbyPQi+iBLYTZAXygvxj2vWyrvA+/w4nbt1fStCHTDhWjLWqFpV9nAoGDAKzA +HUu/IRl7OiUtW/dz36gzEJnaYtz4ZtJl0FG8RJiOe02lD8myqW2sVzYqMvKD0LGx +x9fdSKC1G+aZ/NWtqrQjb66Daf7b0ddDx+bfWTWJ2dOtZd8IL2rmQQJm+JogDi9i +huVYFicDNQGzi+nEKAzrZ1L/VxtiSiw/qw0IyOuVtz8CFjgPiPatvmWssQw2AuZ9 +mFvAZ/8wal0= +-----END X9.42 DH PARAMETERS-----""" + + test_cli("gen_dl_group", "--pbits=1043", pem) + + dsa_grp = """-----BEGIN X9.42 DH PARAMETERS----- +MIIBHgKBgQCyP1vosC/axliM2hmJ9EOSdd1zBkuzMP25CYD8PFkRVrPLr1ClSUtn +eXTIsHToJ7d7sRwtidQGW9BrvUEyiAWE06W/wnLPxB3/g2/l/P2EhbNmNHAO7rV7 +ZVz/uKR4Xcvzxg9uk5MpT1VsxA8H6VEwzefNF1Rya92rqGgBTNT3/wKBgC7HLL8A +Gu3tqJxTk1iNgojjOiSreLn6ihA8R8kQnRXDTNtDKz996KHGInfMBurUI1zPM3xq +bHc0CvU1Nf87enhPIretzJcFgiCWrNFUIC25zPEjp0s3/ERHT4Bi1TABZ3j6YUEQ +fnnj+9XriKKHf2WtX0T4FXorvnKq30m934rzAhUAvwhWDK3yZEmphc7dwl4/J3Zp ++MU= +-----END X9.42 DH PARAMETERS-----""" + + test_cli("gen_dl_group", ["--type=dsa", "--pbits=1024"], dsa_grp) + + +def cli_key_tests(tmp_dir): + + pem = """-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQg2A+I9q2+ZayxDDYC5n2Y +W8Bn/zBm4D3mwS5qMwADRDehRANCAATwnDFqsjXL9SD/Rr1Vy4pb79PswXdQNZBN +mlLtJ5JvZ0/p6zP3x+Y9yPIrAR8L/acG5ItSrAKXzzuqQQZMv4aN +-----END PRIVATE KEY-----""" + + priv_key = os.path.join(tmp_dir, 'priv.pem') + pub_key = os.path.join(tmp_dir, 'pub.pem') + pub_der_key = os.path.join(tmp_dir, 'pub.der') + enc_pem = os.path.join(tmp_dir, 'priv_enc.pem') + enc_der = os.path.join(tmp_dir, 'priv_enc.der') + ca_cert = os.path.join(tmp_dir, 'ca.crt') + crt_req = os.path.join(tmp_dir, 'crt.req') + user_cert = os.path.join(tmp_dir, 'user.crt') + + test_cli("keygen", ["--algo=ECDSA", "--params=secp256k1"], pem) + + test_cli("keygen", ["--algo=ECDSA", "--params=secp256r1", "--output=" + priv_key], "") + + test_cli("pkcs8", "--pub-out --output=%s %s" % (pub_key, priv_key), "") + test_cli("pkcs8", "--pub-out --der-out --output=%s %s" % (pub_der_key, priv_key), "") + + test_cli("pkcs8", "--pass-out=foof --der-out --output=%s %s" % (enc_der, priv_key), "") + test_cli("pkcs8", "--pass-out=foof --output=%s %s" % (enc_pem, priv_key), "") + + dec_pem = test_cli("pkcs8", ["--pass-in=foof", enc_pem], None) + dec_der = test_cli("pkcs8", ["--pass-in=foof", enc_der], None) + + if dec_pem != dec_der: + logging.error("Problem decrypting PKCS8 key") + + test_cli("fingerprint", ['--no-fsname', pub_key], + "83:FC:67:87:30:C7:0C:9C:54:9A:E7:A1:FA:25:83:4C:77:A4:43:16:33:6D:47:3C:CE:4B:91:62:30:97:62:D4") + + test_cli("fingerprint", ['--no-fsname', pub_der_key], + "83:FC:67:87:30:C7:0C:9C:54:9A:E7:A1:FA:25:83:4C:77:A4:43:16:33:6D:47:3C:CE:4B:91:62:30:97:62:D4") + + test_cli("fingerprint", ['--no-fsname', pub_key, pub_der_key], + "83:FC:67:87:30:C7:0C:9C:54:9A:E7:A1:FA:25:83:4C:77:A4:43:16:33:6D:47:3C:CE:4B:91:62:30:97:62:D4\n" + "83:FC:67:87:30:C7:0C:9C:54:9A:E7:A1:FA:25:83:4C:77:A4:43:16:33:6D:47:3C:CE:4B:91:62:30:97:62:D4") + + test_cli("fingerprint", [pub_der_key], + pub_der_key + + ": 83:FC:67:87:30:C7:0C:9C:54:9A:E7:A1:FA:25:83:4C:77:A4:43:16:33:6D:47:3C:CE:4B:91:62:30:97:62:D4") + + test_cli("fingerprint", ['-'], + "83:FC:67:87:30:C7:0C:9C:54:9A:E7:A1:FA:25:83:4C:77:A4:43:16:33:6D:47:3C:CE:4B:91:62:30:97:62:D4", + open(pub_key, 'rb').read().decode()) + + valid_sig = "nI4mI1ec14Y7nYUWs2edysAVvkob0TWpmGh5rrYWDA+/W9Fj0ZM21qJw8qa3/avAOIVBO6hoMEVmfJYXlS+ReA==" + + test_cli("sign", "--provider=base %s %s" % (priv_key, pub_key), valid_sig) + + test_cli("verify", [pub_key, pub_key, '-'], + "Signature is valid", valid_sig) + + test_cli("verify", [pub_key, pub_key, '-'], + "Signature is invalid", + valid_sig.replace("G", "H")) + + test_cli("gen_self_signed", + [priv_key, "CA", "--ca", "--country=VT", + "--dns=ca.example", "--hash=SHA-384", "--output="+ca_cert], + "") + + test_cli("cert_verify", ca_cert, "Certificate did not validate - Cannot establish trust") + + cert_info = test_cli("cert_info", ['--fingerprint', ca_cert], None) + + if cert_info.find('Subject: CN="CA",C="VT"') < 0: + logging.error('Unexpected output for cert_info command %s', cert_info) + if cert_info.find('Subject keyid: 69DD911C9EEE3400C67CBC3F3056CBE711BD56AF9495013F') < 0: + logging.error('Unexpected output for cert_info command %s', cert_info) + + test_cli("gen_pkcs10", "%s User --output=%s" % (priv_key, crt_req)) + + test_cli("sign_cert", "%s %s %s --output=%s" % (ca_cert, priv_key, crt_req, user_cert)) + + test_cli("cert_verify", [user_cert, ca_cert], + "Certificate passes validation checks") + + test_cli("cert_verify", user_cert, + "Certificate did not validate - Certificate issuer not found") + +def cli_xmss_sign_tests(tmp_dir): + priv_key = os.path.join(tmp_dir, 'priv.pem') + pub_key = os.path.join(tmp_dir, 'pub.pem') + pub_key2 = os.path.join(tmp_dir, 'pub2.pem') + msg = os.path.join(tmp_dir, 'input') + sig1 = os.path.join(tmp_dir, 'sig1') + sig2 = os.path.join(tmp_dir, 'sig2') + + test_cli("rng", ['--output=%s' % (msg)], "") + test_cli("hash", ["--no-fsname", msg], "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855") + + test_cli("keygen", ["--algo=XMSS", "--output=%s" % (priv_key)], "") + test_cli("hash", ["--no-fsname", priv_key], "5B38F737BA41BE7F40433DB30EAEF7C41ABB0F7D9E7A09DEB5FDCE7B6811693F") + + test_cli("pkcs8", "--pub-out --output=%s %s" % (pub_key, priv_key), "") + test_cli("fingerprint", ['--no-fsname', pub_key], + "B0:F4:98:6E:D8:4E:05:63:A1:D8:4B:37:61:5A:A0:41:78:7E:DE:0E:72:46:E0:A8:D6:CF:09:54:08:DA:A4:22") + + # verify the key is updated after each signature: + test_cli("sign", [priv_key, msg, "--output=%s" % (sig1)], "") + test_cli("verify", [pub_key, msg, sig1], "Signature is valid") + test_cli("hash", ["--no-fsname", sig1], "04AF45451C7A9AF2D828E1AD6EC262E012436F4087C5DA6F32C689D781E597D0") + test_cli("hash", ["--no-fsname", priv_key], "67929FAEC636E43DE828C1CD7E2D11CE7C3388CE90DD0A0F687C6627FFA850CD") + + test_cli("sign", [priv_key, msg, "--output=%s" % (sig2)], "") + test_cli("verify", [pub_key, msg, sig2], "Signature is valid") + test_cli("hash", ["--no-fsname", sig2], "0785A6AD54CC7D01F2BE2BC6463A3EAA1159792E52210ED754992C5068E8F24F") + test_cli("hash", ["--no-fsname", priv_key], "1940945D68B1CF54D79E05DD7913A4D0B4959183F1E12B81A4E43EF4E63FBD20") + + # private key updates, public key is unchanged: + test_cli("pkcs8", "--pub-out --output=%s %s" % (pub_key2, priv_key), "") + test_cli("fingerprint", ['--no-fsname', pub_key2], + "B0:F4:98:6E:D8:4E:05:63:A1:D8:4B:37:61:5A:A0:41:78:7E:DE:0E:72:46:E0:A8:D6:CF:09:54:08:DA:A4:22") + +def cli_pbkdf_tune_tests(_tmp_dir): + if not check_for_command("pbkdf_tune"): + return + + expected = re.compile(r'For (default|[1-9][0-9]*) ms selected Scrypt\([0-9]+,[0-9]+,[0-9]+\) using [0-9]+ MiB') + + output = test_cli("pbkdf_tune", ["--check", "1", "10", "50", "default"], None).split('\n') + + for line in output: + if expected.match(line) is None: + logging.error("Unexpected line '%s'" % (line)) + + expected_pbkdf2 = re.compile(r'For (default|[1-9][0-9]*) ms selected PBKDF2\(HMAC\(SHA-256\),[0-9]+\)') + + output = test_cli("pbkdf_tune", ["--algo=PBKDF2(SHA-256)", "--check", "1", "10", "50", "default"], None).split('\n') + + for line in output: + if expected_pbkdf2.match(line) is None: + logging.error("Unexpected line '%s'" % (line)) + + expected_argon2 = re.compile(r'For (default|[1-9][0-9]*) ms selected Argon2id\([0-9]+,[0-9]+,[0-9]+\)') + + output = test_cli("pbkdf_tune", ["--algo=Argon2id", "--check", "1", "10", "50", "default"], None).split('\n') + + for line in output: + if expected_argon2.match(line) is None: + logging.error("Unexpected line '%s'" % (line)) + +def cli_psk_db_tests(tmp_dir): + if not check_for_command("psk_get"): + return + + psk_db = os.path.join(tmp_dir, 'psk.db') + db_key1 = "909"*32 + db_key2 = "451"*32 + + test_cli("psk_set", [psk_db, db_key1, "name", "F00FEE"], "") + test_cli("psk_set", [psk_db, db_key2, "name", "C00FEE11"], "") + test_cli("psk_set", [psk_db, db_key1, "name2", "50051029"], "") + + test_cli("psk_get", [psk_db, db_key1, "name"], "F00FEE") + test_cli("psk_get", [psk_db, db_key2, "name"], "C00FEE11") + + test_cli("psk_list", [psk_db, db_key1], "name\nname2") + test_cli("psk_list", [psk_db, db_key2], "name") + +def cli_compress_tests(tmp_dir): + + if not check_for_command("compress"): + return + + input_file = os.path.join(tmp_dir, 'input.txt') + output_file = os.path.join(tmp_dir, 'input.txt.gz') + + with open(input_file, 'w') as f: + f.write("hi there") + f.close() + + test_cli("compress", input_file) + + if not os.access(output_file, os.R_OK): + logging.error("Compression did not created expected output file") + + is_py3 = sys.version_info[0] == 3 + + output_hdr = open(output_file, 'rb').read(2) + + if is_py3: + if output_hdr[0] != 0x1F or output_hdr[1] != 0x8B: + logging.error("Did not see expected gzip header") + else: + if ord(output_hdr[0]) != 0x1F or ord(output_hdr[1]) != 0x8B: + logging.error("Did not see expected gzip header") + + os.unlink(input_file) + + test_cli("decompress", output_file) + + if not os.access(input_file, os.R_OK): + logging.error("Decompression did not created expected output file") + + recovered = open(input_file).read() + if recovered != "hi there": + logging.error("Decompression did not recover original input") + +def cli_rng_tests(_tmp_dir): + test_cli("rng", "10", "D80F88F6ADBE65ACB10C") + test_cli("rng", "16", "D80F88F6ADBE65ACB10C3602E67D985B") + test_cli("rng", "10 6", "D80F88F6ADBE65ACB10C\n1B119CC068AF") + + test_cli("rng", ['--format=base64', '10'], "2A+I9q2+ZayxDA==") + test_cli("rng", ['--format=base58', '10'], "D93XRyVfxqs7oR") + test_cli("rng", ['--format=base58check', '10'], "2NS1jYUq92TyGFVnhVLa") + + hex_10 = re.compile('[A-F0-9]{20}') + + for rng in ['system', 'auto', 'entropy']: + output = test_cli("rng", ["10", '--%s' % (rng)], use_drbg=False) + if output == "D80F88F6ADBE65ACB10C": + logging.error('RNG produced DRBG output') + if hex_10.match(output) is None: + logging.error('Unexpected RNG output %s' % (output)) + + has_rdrand = test_cli("cpuid", []).find(' rdrand ') > 0 + + if has_rdrand: + output = test_cli("rng", ["10", '--rdrand'], use_drbg=False) + + if output == "D80F88F6ADBE65ACB10C": + logging.error('RDRAND produced DRBG output') + if hex_10.match(output) is None: + logging.error('Unexpected RNG output %s' % (output)) + +def cli_roughtime_check_tests(tmp_dir): + # pylint: disable=line-too-long + if not check_for_command("roughtime_check"): + return + chain = os.path.join(tmp_dir, 'roughtime-chain') + + with open(chain, 'w') as f: + f.write("""\ +ed25519 bbT+RPS7zKX6w71ssPibzmwWqU9ffRV5oj2OresSmhE= eu9yhsJfVfguVSqGZdE8WKIxaBBM0ZG3Vmuc+IyZmG2YVmrIktUByDdwIFw6F4rZqmSFsBO85ljoVPz5bVPCOw== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWBnGOEajOwPA6G7oL47seBP4C7eEpr57H43C2/fK/kMA0UGZVUdf4KNX8oxOK6JIcsbVk8qhghTwA70qtwpYmQkDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AJrA8tEqPBQAqisiuAxgy2Pj7UJAiWbCdzGz1xcCnja3T+AqhC8fwpeIwW4GPy/vEb/awXW2DgSLKJfzWIAz+2lsR7t4UjNPvAgAAAEAAAABTSUcAREVMRes9Ch4X0HIw5KdOTB8xK4VDFSJBD/G9t7Et/CU7UW61OiTBXYYQTG2JekWZmGa0OHX1JPGG+APkpbsNw0BKUgYDAAAAIAAAACgAAABQVUJLTUlOVE1BWFR/9BWjpsWTQ1f6iUJea3EfZ1MkX3ftJiV3ABqNLpncFwAAAAAAAAAA//////////8AAAAA +ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= uLeTON9D+2HqJMzK6sYWLNDEdtBl9t/9yw1cVAOm0/sONH5Oqdq9dVPkC9syjuWbglCiCPVF+FbOtcxCkrgMmA== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWOw1jl0uSiBEH9HE8/6r7zxoSc01f48vw+UzH8+VJoPelnvVJBj4lnH8uRLh5Aw0i4Du7XM1dp2u0r/I5PzhMQoDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AUBo+tEqPBQC47l77to7ESFTVhlw1SC74P5ssx6gpuJ6eP+1916GuUiySGE/x3Fp0c3otUGAdsRQou5p9PDTeane/YEeVq4/8AgAAAEAAAABTSUcAREVMRe5T1ml8wHyWAcEtHP/U5Rg/jFXTEXOSglngSa4aI/CECVdy4ZNWeP6vv+2//ZW7lQsrWo7ZkXpvm9BdBONRSQIDAAAAIAAAACgAAABQVUJLTUlOVE1BWFQpXlenV0OfVisvp9jDHXLw8vymZVK9Pgw9k6Edf8ZEhUgSGEc5jwUASHLvZE2PBQAAAAAA +ed25519 etPaaIxcBMY1oUeGpwvPMCJMwlRVNxv51KK/tktoJTQ= U53wX99JzZwy4BXa9C6R04bPu4yqFB5w5/wTgG8Mw5wm+VLrY70ECxJ9ZHnpdHVHaLEU3aeLnQFZyZPRAEOCyw== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWMh3mPWCCbOlX8xDWbU9qdfKoReJX/XLsivom8bJJYmcC7T03tyXrtWUheEJweHtg4qMgSyifQS1MjHJSy1jPAsDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8Akxw/tEqPBQBfOsOuciR7jiAW5itQ39y8yVr/ZJmgMwvTjqaU4/wA05ZqG4RqoLdvDXh5bCNySL6LrrnBNSAHwn5COt0CItNuAgAAAEAAAABTSUcAREVMRVP3BIOzsZmuxqMi+ScIBPyKtzFfK7ZlPFNP0JrNwln2QYtAcQFIKywDdNAAL+n8i3dz1p99K50FJjCkCl2J6AMDAAAAIAAAACgAAABQVUJLTUlOVE1BWFQKC/kZVdjiNT2NCSGfnpot4eqipyMFsyMjiIQmqqqXqQCAa245jwUAAGCgA56PBQAAAAAA +ed25519 AW5uAoTSTDfG5NfY1bTh08GUnOqlRb+HVhbJ3ODJvsE= IcZcXFuaLKYYhWcK3sT/6PrVeXMmabCRbf9hvVfkMkqEW1PFL++ZnHJ1/m+G8azITxvktwsfP1YAOOxWdbf9XQ== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWL5DAl8GPNUQ/mSXl0tI4N9yZAO+PiXTodJOTDL+WU/x26iqgyyQRikSSocRMzAEVLDGasdyW19mVC6H/6vfXggDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8Av/JAtEqPBQBIP346SHhCdDfughzeH+uYSbxngDYxqHzBDtZt0obUKrzxfRWzD1oR61B1reLvoPVCKSfzEngi/g1NSQjTrzNMAgAAAEAAAABTSUcAREVMRTQLLplQv0rN4p77Bo59qT8bbquV6MKSwILI/Tw2LLGo9noaZegUFmM+rNu1d1AVOEVQ01j6/2xDmBvp0d6MZgEDAAAAIAAAACgAAABQVUJLTUlOVE1BWFS4a1dYoIB5u/zkbR3sIteuhVrQkszzj+Gng9ywo6O9VgAAAAAAAAAA//////////8AAAAA +ed25519 cj8GsiNlRkqiDElAeNMSBBMwrAl15hYPgX50+GWX/lA= Tsy82BBU2xxVqNe1ip11OyEGoKWhKoSggWjBmDTSBmKbTs7bPPCEidYc5TQ23sQUWe62G35fQOVU28q+Eq5uhQ== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWDAmi7zgXAqLgQXVfbjeqnUZRiXCZI64QIoAKFL83CQHbyXgB4cNwHfQ9mSg0hYxTp1M8QxOuzusnUpk05DIRwwDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AcOBCtEqPBQBhsr1mKOxxCf4VDFzAtYB4Nhs332AN1LrJU/8+VqktzfPd2R7awJHEVEWugvSvOrr+9d332mQObAkYfKfDtbSFAgAAAEAAAABTSUcAREVMRUjnhDvkIjFzTEYtgHOfMpRHtnNZj4P31RFtapkwzGjOtc93pYDd7zqQCw2AVcfbSnPqa8k26z96Q9fVRzq0pw8DAAAAIAAAACgAAABQVUJLTUlOVE1BWFR7qp2oerjpbN8Y23nUGARIlsgkodW4owH29ZKhxDMn8AAAAAAAAAAA//////////8AAAAA +""") + + test_cli("roughtime_check", chain, """\ +1: UTC 2019-08-04T13:38:17 (+-1000000us) + 2: UTC 2019-08-04T13:38:17 (+-1000000us) + 3: UTC 2019-08-04T13:38:17 (+-1000000us) + 4: UTC 2019-08-04T13:38:18 (+-1000000us) + 5: UTC 2019-08-04T13:38:18 (+-1000000us)""") + + with open(chain, 'w') as f: + f.write("ed25519 bbT+RPS7zKX6w71ssPibzmwWqU9ffRV5oj2OresSmhE= eu9yhsJfVfguVSqGZdE8WKIxaBBM0ZG3Vmuc+IyZmG2YVmrIktUByDdwIFw6F4rZqmSFsBO85ljoVPz5bVPCOw== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWBnGOEajOwPA6G7oL47seBP4C7eEpr57H43C2/fK/kMA0UGZVUdf4KNX8oxOK6JIcsbVk8qhghTwA70qtwpYmQkDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AJrA8tEqPBQAqisiuAxgy2Pj7UJAiWbCdzGz1xcCnja3T+AqhC8fwpeIwW4GPy/vEb/awXW2DgSLKJfzWIAz+2lsR7t4UjNPvAgAAAEAAAABTSUcAREVMRes9Ch4X0HIw5KdOTB8xK4VDFSJBD/G9t7Et/CU7UW61OiTBXYYQTG2JekWZmGa0OHX1JPGG+APkpbsNw0BKUgYDAAAAIAAAACgAAABQVUJLTUlOVE1BWFR/9BWjpsWTQ1f6iUJea3EfZ1MkX3ftJiV3ABqNLpncFwAAAAAAAAAA//////////8AAAAA") + test_cli("roughtime_check", [chain, "--raw-time"], "1: UTC 1564925897781286 (+-1000000us)") + + with open(chain, 'w') as f: + f.write("ed25519 cbT+RPS7zKX6w71ssPibzmwWqU9ffRV5oj2OresSmhE= eu9yhsJfVfguVSqGZdE8WKIxaBBM0ZG3Vmuc+IyZmG2YVmrIktUByDdwIFw6F4rZqmSFsBO85ljoVPz5bVPCOw== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWBnGOEajOwPA6G7oL47seBP4C7eEpr57H43C2/fK/kMA0UGZVUdf4KNX8oxOK6JIcsbVk8qhghTwA70qtwpYmQkDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AJrA8tEqPBQAqisiuAxgy2Pj7UJAiWbCdzGz1xcCnja3T+AqhC8fwpeIwW4GPy/vEb/awXW2DgSLKJfzWIAz+2lsR7t4UjNPvAgAAAEAAAABTSUcAREVMRes9Ch4X0HIw5KdOTB8xK4VDFSJBD/G9t7Et/CU7UW61OiTBXYYQTG2JekWZmGa0OHX1JPGG+APkpbsNw0BKUgYDAAAAIAAAACgAAABQVUJLTUlOVE1BWFR/9BWjpsWTQ1f6iUJea3EfZ1MkX3ftJiV3ABqNLpncFwAAAAAAAAAA//////////8AAAAA") + test_cli("roughtime_check", chain, expected_stderr=b'Error: Roughtime Invalid signature or public key\n') + +def cli_roughtime_tests(tmp_dir): + # pylint: disable=line-too-long + # pylint: disable=too-many-locals + import socket + import base64 + import threading + + if not check_for_command("roughtime"): + return + + server_port = random_port_number() + chain_file = os.path.join(tmp_dir, 'roughtime-chain') + ecosystem = os.path.join(tmp_dir, 'ecosystem') + + def run_udp_server(): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + server_address = ('127.0.0.1', server_port) + sock.bind(server_address) + + while True: + data, address = sock.recvfrom(4096) + + if data: + if data != base64.b64decode(server_request): + logging.error("unexpected request") + + sock.sendto(base64.b64decode(server_response), address) + + udp_thread = threading.Thread(target=run_udp_server) + udp_thread.daemon = True + udp_thread.start() + + chain = [ + """\ +ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= 2A+I9q2+ZayxDDYC5n2YW8Bn/zBm4D3mwS5qMwADRDcbFpBcf3yPOyeZiqpLBTkxo8GT8zMQFeApv4ScffjC8A== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWDwlo/AkUnTrecAW4Ci5Tkh3KOqs6R7KLTsFtq16RXN5F7G5ckGv11UtzHoZTbKbEk03a6ogAOK54Q2CI/7XGA8DAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AWDLihlaSBQAoq/5gEjRCrhfH16X2GYjQJSG/CgSuGhYeCsrw7XkphLI3cxw2unJRDW8DAJrYqEGaW0NPKZk7bbpPjU/Q6Es1AgAAAEAAAABTSUcAREVMRUJbs67Sb5Wx/jzWyT1PhWR0c4kg59tjSGofo8R3eHzcA9CGwavuRdxOArhVWWODG99gYgfmjcRLgt9/jH+99w4DAAAAIAAAACgAAABQVUJLTUlOVE1BWFRXRfQ1RHLWGOgqABUTYfVBDZrv3OL2nPLYve9ldfNVLOjdPVFFkgUA6D0Vb1mSBQAAAAAA +""", + """\ +ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= 2A+I9q2+ZayxDDYC5n2YW8Bn/zBm4D3mwS5qMwADRDcbFpBcf3yPOyeZiqpLBTkxo8GT8zMQFeApv4ScffjC8A== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWDwlo/AkUnTrecAW4Ci5Tkh3KOqs6R7KLTsFtq16RXN5F7G5ckGv11UtzHoZTbKbEk03a6ogAOK54Q2CI/7XGA8DAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AWDLihlaSBQAoq/5gEjRCrhfH16X2GYjQJSG/CgSuGhYeCsrw7XkphLI3cxw2unJRDW8DAJrYqEGaW0NPKZk7bbpPjU/Q6Es1AgAAAEAAAABTSUcAREVMRUJbs67Sb5Wx/jzWyT1PhWR0c4kg59tjSGofo8R3eHzcA9CGwavuRdxOArhVWWODG99gYgfmjcRLgt9/jH+99w4DAAAAIAAAACgAAABQVUJLTUlOVE1BWFRXRfQ1RHLWGOgqABUTYfVBDZrv3OL2nPLYve9ldfNVLOjdPVFFkgUA6D0Vb1mSBQAAAAAA +ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= 2A+I9q2+ZayxDDYC5n2YW8Bn/zBm4D3mwS5qMwADRDcbFpBcf3yPOyeZiqpLBTkxo8GT8zMQFeApv4ScffjC8A== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWHH5Ofs4HciIFXjE9egjDbistJptoMXIC7ugCgHhI4NPJqfYY256NpULXKc9c30ul7oHXQyKLfGd84mIAxC3UwQDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AuOoUh1aSBQANeC4gGGG3a23PpmF+y6CrUS9VWjyj0Ydpl2tMVDLaK2vd5QtYKKJ3UOyprGKk0D/aPn4E3Bk2rE3BKBZRXM1AAgAAAEAAAABTSUcAREVMRci9uvioJssgd8txxFlqz9RqPx+YLVMkHmm24fMUtYGWF/nhkoEYVGT7O+tXSfHHY/KHcUZjVaZpEt/tmXlXBAUDAAAAIAAAACgAAABQVUJLTUlOVE1BWFSxhKhavdriTvCAtNVcK5yr0cAbsWp2MsrwUV5YTc+7V0CsaLZSkgUAQAxA1GaSBQAAAAAA +""", + """\ +ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= SbWKPilWYrt+1vgFU3jlxGNOH6I/1npX8wl+KoraN3S6VDsyM6EfCV+JPEK8BsNoM2VIpMcSdjcVna/GwXwZkg== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWHH5Ofs4HciIFXjE9egjDbistJptoMXIC7ugCgHhI4NPJqfYY256NpULXKc9c30ul7oHXQyKLfGd84mIAxC3UwQDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AuOoUh1aSBQANeC4gGGG3a23PpmF+y6CrUS9VWjyj0Ydpl2tMVDLaK2vd5QtYKKJ3UOyprGKk0D/aPn4E3Bk2rE3BKBZRXM1AAgAAAEAAAABTSUcAREVMRci9uvioJssgd8txxFlqz9RqPx+YLVMkHmm24fMUtYGWF/nhkoEYVGT7O+tXSfHHY/KHcUZjVaZpEt/tmXlXBAUDAAAAIAAAACgAAABQVUJLTUlOVE1BWFSxhKhavdriTvCAtNVcK5yr0cAbsWp2MsrwUV5YTc+7V0CsaLZSkgUAQAxA1GaSBQAAAAAA +ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= 2A+I9q2+ZayxDDYC5n2YW8Bn/zBm4D3mwS5qMwADRDcbFpBcf3yPOyeZiqpLBTkxo8GT8zMQFeApv4ScffjC8A== BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWN5Y0b2irPS1JgqJFQMciPg4aWd9qj1ZqcJc5bGXe1m4ZdAXa5OIhXa0+680MgpyhEHhqYJDIwH1XRa1OZx5YAUDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AgBW3iFaSBQD9WI+Qr6NOZsDmP0PsnCo66mstM3ac5ZON+I+ZeEK8lZWBASvsD2JIfq3v4d1QH5g4STs3wOazQPc25Puy659ZAgAAAEAAAABTSUcAREVMRUJbs67Sb5Wx/jzWyT1PhWR0c4kg59tjSGofo8R3eHzcA9CGwavuRdxOArhVWWODG99gYgfmjcRLgt9/jH+99w4DAAAAIAAAACgAAABQVUJLTUlOVE1BWFRXRfQ1RHLWGOgqABUTYfVBDZrv3OL2nPLYve9ldfNVLOjdPVFFkgUA6D0Vb1mSBQAAAAAA +""", + ] + request = [ + "AgAAAEAAAABOT05DUEFE/9gPiPatvmWssQw2AuZ9mFvAZ/8wZuA95sEuajMAA0Q3GxaQXH98jzsnmYqqSwU5MaPBk/MzEBXgKb+EnH34wvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "AgAAAEAAAABOT05DUEFE/0m1ij4pVmK7ftb4BVN45cRjTh+iP9Z6V/MJfiqK2jd0ulQ7MjOhHwlfiTxCvAbDaDNlSKTHEnY3FZ2vxsF8GZIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "AgAAAEAAAABOT05DUEFE/0AcDP0F/L7NTiOCQlHovyMlovVtG4lBRqAgydNYk9WOoanOwclZuV8z2b/SCHj5thxbSNxuLNZoDQ2b6TWgPfsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + ] + response = [ + "BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWDwlo/AkUnTrecAW4Ci5Tkh3KOqs6R7KLTsFtq16RXN5F7G5ckGv11UtzHoZTbKbEk03a6ogAOK54Q2CI/7XGA8DAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AWDLihlaSBQAoq/5gEjRCrhfH16X2GYjQJSG/CgSuGhYeCsrw7XkphLI3cxw2unJRDW8DAJrYqEGaW0NPKZk7bbpPjU/Q6Es1AgAAAEAAAABTSUcAREVMRUJbs67Sb5Wx/jzWyT1PhWR0c4kg59tjSGofo8R3eHzcA9CGwavuRdxOArhVWWODG99gYgfmjcRLgt9/jH+99w4DAAAAIAAAACgAAABQVUJLTUlOVE1BWFRXRfQ1RHLWGOgqABUTYfVBDZrv3OL2nPLYve9ldfNVLOjdPVFFkgUA6D0Vb1mSBQAAAAAA", + "BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWHH5Ofs4HciIFXjE9egjDbistJptoMXIC7ugCgHhI4NPJqfYY256NpULXKc9c30ul7oHXQyKLfGd84mIAxC3UwQDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AuOoUh1aSBQANeC4gGGG3a23PpmF+y6CrUS9VWjyj0Ydpl2tMVDLaK2vd5QtYKKJ3UOyprGKk0D/aPn4E3Bk2rE3BKBZRXM1AAgAAAEAAAABTSUcAREVMRci9uvioJssgd8txxFlqz9RqPx+YLVMkHmm24fMUtYGWF/nhkoEYVGT7O+tXSfHHY/KHcUZjVaZpEt/tmXlXBAUDAAAAIAAAACgAAABQVUJLTUlOVE1BWFSxhKhavdriTvCAtNVcK5yr0cAbsWp2MsrwUV5YTc+7V0CsaLZSkgUAQAxA1GaSBQAAAAAA", + "BQAAAEAAAABAAAAApAAAADwBAABTSUcAUEFUSFNSRVBDRVJUSU5EWN5Y0b2irPS1JgqJFQMciPg4aWd9qj1ZqcJc5bGXe1m4ZdAXa5OIhXa0+680MgpyhEHhqYJDIwH1XRa1OZx5YAUDAAAABAAAAAwAAABSQURJTUlEUFJPT1RAQg8AgBW3iFaSBQD9WI+Qr6NOZsDmP0PsnCo66mstM3ac5ZON+I+ZeEK8lZWBASvsD2JIfq3v4d1QH5g4STs3wOazQPc25Puy659ZAgAAAEAAAABTSUcAREVMRUJbs67Sb5Wx/jzWyT1PhWR0c4kg59tjSGofo8R3eHzcA9CGwavuRdxOArhVWWODG99gYgfmjcRLgt9/jH+99w4DAAAAIAAAACgAAABQVUJLTUlOVE1BWFRXRfQ1RHLWGOgqABUTYfVBDZrv3OL2nPLYve9ldfNVLOjdPVFFkgUA6D0Vb1mSBQAAAAAA", + ] + + server_request = request[0] + server_response = response[0] + test_cli("roughtime", [], expected_stderr=b'Please specify either --servers-file or --host and --pubkey\n') + + with open(ecosystem, 'w') as f: + f.write("Cloudflare-Roughtime ed25519 gD63hSj4ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= udp 127.0.0.1:" + str(server_port)) + + test_cli("roughtime", [ + "--check-local-clock=0", + "--chain-file=", + "--servers-file=" + ecosystem] + , expected_stderr=b'ERROR: Public key does not match!\n') + + with open(ecosystem, 'w') as f: + f.write("Cloudflare-Roughtime ed25519 gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo= udp 127.0.0.1:" + str(server_port)) + + test_cli("roughtime", [ + "--chain-file=", + "--servers-file=" + ecosystem] + , expected_stderr=b'ERROR: Local clock mismatch\n') + + test_cli("roughtime", [ + "--check-local-clock=0", + "--chain-file=" + chain_file, + "--servers-file=" + ecosystem] + , "Cloudflare-Roughtime : UTC 2019-09-12T08:00:11 (+-1000000us)") + + with open(chain_file, 'r') as f: + read_data = f.read() + if read_data != chain[0]: + logging.error("unexpected chain") + + server_request = request[1] + server_response = response[1] + test_cli("roughtime", [ + "--check-local-clock=0", + "--chain-file=" + chain_file, + "--host=127.0.0.1:" + str(server_port), + "--pubkey=gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo=", + "--raw-time"] + , "UTC 1568275214691000 (+-1000000us)") + + with open(chain_file, 'r') as f: + read_data = f.read() + if read_data != chain[1]: + logging.error("unexpected chain") + + server_request = request[2] + server_response = response[2] + test_cli("roughtime", [ + "--check-local-clock=0", + "--chain-file=" + chain_file, + "--host=127.0.0.1:" + str(server_port), + "--pubkey=gD63hSj3ScS+wuOeGrubXlq35N1c5Lby/S+T7MNTjxo=", + "--max-chain-size=2"] + , "UTC 2019-09-12T08:00:42 (+-1000000us)") + + with open(chain_file, 'r') as f: + read_data = f.read() + if read_data != chain[2]: + logging.error("unexpected chain") + +def cli_pk_workfactor_tests(_tmp_dir): + test_cli("pk_workfactor", "1024", "80") + test_cli("pk_workfactor", "2048", "111") + test_cli("pk_workfactor", ["--type=rsa", "512"], "58") + test_cli("pk_workfactor", ["--type=dl", "512"], "58") + test_cli("pk_workfactor", ["--type=dl_exp", "512"], "128") + +def cli_dl_group_info_tests(_tmp_dir): + + dl_output = re.compile('(P|G) = [A-F0-9]+') + + for bits in [1024, 1536, 2048, 3072, 4096, 6144, 8192]: + output = test_cli("dl_group_info", "modp/ietf/%d" % (bits)) + lines = output.split('\n') + + if len(lines) != 2: + logging.error('Unexpected output from dl_group_info') + + for l in lines: + if not dl_output.match(l): + logging.error('Unexpected output from dl_group_info') + + + +def cli_ec_group_info_tests(_tmp_dir): + + # pylint: disable=line-too-long + secp256r1_info = """P = FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF +A = FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC +B = 5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B +N = FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 +G = 6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5""" + + secp256r1_pem = """-----BEGIN EC PARAMETERS----- +MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP////////// +/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6 +k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDydwN9 +gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA +/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE= +-----END EC PARAMETERS-----""" + + test_cli("ec_group_info", "secp256r1", secp256r1_info) + test_cli("ec_group_info", "--pem secp256r1", secp256r1_pem) + +def cli_cpuid_tests(_tmp_dir): + cpuid_output = test_cli("cpuid", []) + + if not cpuid_output.startswith('CPUID flags:'): + logging.error('Unexpected cpuid output "%s"' % (cpuid_output)) + + flag_re = re.compile('[a-z0-9_]+') + flags = cpuid_output[13:].split(' ') + for flag in flags: + if flag != '' and flag_re.match(flag) is None: + logging.error('Unexpected CPUID flag name "%s"' % (flag)) + +def cli_cc_enc_tests(_tmp_dir): + test_cli("cc_encrypt", ["8028028028028029", "pass"], "4308989841607208") + test_cli("cc_decrypt", ["4308989841607208", "pass"], "8028028028028027") + +def cli_cert_issuance_tests(tmp_dir): + root_key = os.path.join(tmp_dir, 'root.key') + root_crt = os.path.join(tmp_dir, 'root.crt') + int_key = os.path.join(tmp_dir, 'int.key') + int_crt = os.path.join(tmp_dir, 'int.crt') + int_csr = os.path.join(tmp_dir, 'int.csr') + leaf_key = os.path.join(tmp_dir, 'leaf.key') + leaf_crt = os.path.join(tmp_dir, 'leaf.crt') + leaf_csr = os.path.join(tmp_dir, 'leaf.csr') + + test_cli("keygen", ["--params=2048", "--output=" + root_key], "") + test_cli("keygen", ["--params=2048", "--output=" + int_key], "") + test_cli("keygen", ["--params=2048", "--output=" + leaf_key], "") + + test_cli("gen_self_signed", + [root_key, "Root", "--ca", "--path-limit=2", "--output="+root_crt], "") + + test_cli("gen_pkcs10", "%s Intermediate --ca --output=%s" % (int_key, int_csr)) + test_cli("sign_cert", "%s %s %s --output=%s" % (root_crt, root_key, int_csr, int_crt)) + + test_cli("gen_pkcs10", "%s Leaf --output=%s" % (leaf_key, leaf_csr)) + test_cli("sign_cert", "%s %s %s --output=%s" % (int_crt, int_key, leaf_csr, leaf_crt)) + + test_cli("cert_verify" "%s %s %s" % (leaf_crt, int_crt, root_crt), "Certificate passes validation checks") + +def cli_timing_test_tests(_tmp_dir): + + timing_tests = ["bleichenbacher", "manger", + "ecdsa", "ecc_mul", "inverse_mod", "pow_mod", + "lucky13sec3", "lucky13sec4sha1", + "lucky13sec4sha256", "lucky13sec4sha384"] + + output_re = re.compile('[0-9]+;[0-9];[0-9]+') + + for suite in timing_tests: + output = test_cli("timing_test", [suite, "--measurement-runs=16", "--warmup-runs=3"], None).split('\n') + + for line in output: + if output_re.match(line) is None: + logging.error("Unexpected output in timing_test %s: %s", suite, line) + +def cli_tls_ciphersuite_tests(_tmp_dir): + policies = ['default', 'suiteb_128', 'suiteb_192', 'strict', 'all'] + + versions = ['tls1.0', 'tls1.1', 'tls1.2'] + + ciphersuite_re = re.compile('^[A-Z0-9_]+$') + + for policy in policies: + for version in versions: + + if version != 'tls1.2' and policy != 'all': + continue + + output = test_cli("tls_ciphers", ["--version=" + version, "--policy=" + policy], None).split('\n') + + for line in output: + if ciphersuite_re.match(line) is None: + logging.error("Unexpected ciphersuite line %s", line) + +def cli_asn1_tests(_tmp_dir): + input_pem = """-----BEGIN BLOB----- +MCACAQUTBnN0cmluZzEGAQH/AgFjBAUAAAAAAAMEAP///w== +-----END BLOB------ +""" + + expected = """d= 0, l= 32: SEQUENCE + d= 1, l= 1: INTEGER 05 + d= 1, l= 6: PRINTABLE STRING string + d= 1, l= 6: SET + d= 2, l= 1: BOOLEAN true + d= 2, l= 1: INTEGER 63 + d= 1, l= 5: OCTET STRING 0000000000 + d= 1, l= 4: BIT STRING FFFFFF""" + + test_cli("asn1print", "--pem -", expected, input_pem) + +def cli_tls_socket_tests(tmp_dir): + client_msg = b'Client message %d\n' % (random.randint(0, 2**128)) + server_port = random_port_number() + + priv_key = os.path.join(tmp_dir, 'priv.pem') + ca_cert = os.path.join(tmp_dir, 'ca.crt') + crt_req = os.path.join(tmp_dir, 'crt.req') + server_cert = os.path.join(tmp_dir, 'server.crt') + + test_cli("keygen", ["--algo=ECDSA", "--params=secp256r1", "--output=" + priv_key], "") + + test_cli("gen_self_signed", + [priv_key, "CA", "--ca", "--country=VT", + "--dns=ca.example", "--hash=SHA-384", "--output="+ca_cert], + "") + + test_cli("cert_verify", ca_cert, "Certificate did not validate - Cannot establish trust") + + test_cli("gen_pkcs10", "%s localhost --output=%s" % (priv_key, crt_req)) + + test_cli("sign_cert", "%s %s %s --output=%s" % (ca_cert, priv_key, crt_req, server_cert)) + + tls_server = subprocess.Popen([CLI_PATH, 'tls_server', '--max-clients=1', + '--port=%d' % (server_port), server_cert, priv_key], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + wait_time = 1.0 + + time.sleep(wait_time) + + tls_client = subprocess.Popen([CLI_PATH, 'tls_client', 'localhost', + '--port=%d' % (server_port), '--trusted-cas=%s' % (ca_cert)], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + time.sleep(wait_time) + + tls_client.stdin.write(client_msg) + tls_client.stdin.flush() + + time.sleep(wait_time) + + (stdout, stderr) = tls_client.communicate() + + if stderr: + logging.error("Got unexpected stderr output %s" % (stderr)) + + if b'Handshake complete' not in stdout: + logging.error('Failed to complete handshake: %s' % (stdout)) + + if client_msg not in stdout: + logging.error("Missing client message from stdout %s" % (stdout)) + + tls_server.communicate() + +def cli_tls_http_server_tests(tmp_dir): + if not check_for_command("tls_http_server"): + return + + try: + from http.client import HTTPSConnection + except ImportError: + try: + from httplib import HTTPSConnection + except ImportError: + return + import ssl + + server_port = random_port_number() + + priv_key = os.path.join(tmp_dir, 'priv.pem') + ca_cert = os.path.join(tmp_dir, 'ca.crt') + crt_req = os.path.join(tmp_dir, 'crt.req') + server_cert = os.path.join(tmp_dir, 'server.crt') + + test_cli("keygen", ["--algo=ECDSA", "--params=secp384r1", "--output=" + priv_key], "") + + test_cli("gen_self_signed", + [priv_key, "CA", "--ca", "--country=VT", + "--dns=ca.example", "--hash=SHA-384", "--output="+ca_cert], + "") + + test_cli("gen_pkcs10", "%s localhost --output=%s" % (priv_key, crt_req)) + + test_cli("sign_cert", "%s %s %s --output=%s" % (ca_cert, priv_key, crt_req, server_cert)) + + tls_server = subprocess.Popen([CLI_PATH, 'tls_http_server', '--max-clients=2', + '--port=%d' % (server_port), server_cert, priv_key], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + wait_time = 1.0 + time.sleep(wait_time) + + context = ssl.create_default_context(cafile=ca_cert) + conn = HTTPSConnection('localhost', port=server_port, context=context) + conn.request("GET", "/") + resp = conn.getresponse() + + if resp.status != 200: + logging.error('Unexpected response status %d' % (resp.status)) + + body = str(resp.read()) + + if body.find('TLS negotiation with Botan 2.') < 0: + logging.error('Unexpected response body') + + conn.request("POST", "/logout") + resp = conn.getresponse() + + if resp.status != 405: + logging.error('Unexpected response status %d' % (resp.status)) + + if sys.version_info.major >= 3: + rc = tls_server.wait(5) # pylint: disable=too-many-function-args + else: + rc = tls_server.wait() + + if rc != 0: + logging.error("Unexpected return code from https_server %d", rc) + +def cli_tls_proxy_tests(tmp_dir): + # pylint: disable=too-many-locals,too-many-statements + if not check_for_command("tls_proxy"): + return + + try: + from http.client import HTTPSConnection + except ImportError: + try: + from httplib import HTTPSConnection + except ImportError: + return + + try: + from http.server import HTTPServer, BaseHTTPRequestHandler + except ImportError: + try: + from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler + except ImportError: + return + + import ssl + import threading + + server_port = random_port_number() + proxy_port = random_port_number() + + while server_port == proxy_port: + proxy_port = random_port_number() + + priv_key = os.path.join(tmp_dir, 'priv.pem') + ca_cert = os.path.join(tmp_dir, 'ca.crt') + crt_req = os.path.join(tmp_dir, 'crt.req') + server_cert = os.path.join(tmp_dir, 'server.crt') + + test_cli("keygen", ["--algo=ECDSA", "--params=secp384r1", "--output=" + priv_key], "") + + test_cli("gen_self_signed", + [priv_key, "CA", "--ca", "--country=VT", + "--dns=ca.example", "--hash=SHA-384", "--output="+ca_cert], + "") + + test_cli("gen_pkcs10", "%s localhost --output=%s" % (priv_key, crt_req)) + + test_cli("sign_cert", "%s %s %s --output=%s" % (ca_cert, priv_key, crt_req, server_cert)) + + tls_proxy = subprocess.Popen([CLI_PATH, 'tls_proxy', str(proxy_port), '127.0.0.1', str(server_port), + server_cert, priv_key, '--output=/tmp/proxy.err', '--max-clients=2'], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + wait_time = 1.0 + + time.sleep(wait_time) + + server_response = binascii.hexlify(os.urandom(32)) + + def run_http_server(): + class Handler(BaseHTTPRequestHandler): + + def do_GET(self): # pylint: disable=invalid-name + self.send_response(200) + self.end_headers() + self.wfile.write(server_response) + + httpd = HTTPServer(('', server_port), Handler) + httpd.serve_forever() + + http_thread = threading.Thread(target=run_http_server) + http_thread.daemon = True + http_thread.start() + + time.sleep(wait_time) + + context = ssl.create_default_context(cafile=ca_cert) + + for _i in range(2): + conn = HTTPSConnection('localhost', port=proxy_port, context=context) + conn.request("GET", "/") + resp = conn.getresponse() + + if resp.status != 200: + logging.error('Unexpected response status %d' % (resp.status)) + + body = resp.read() + + if body != server_response: + logging.error('Unexpected response from server %s' % (body)) + + if sys.version_info.major >= 3: + rc = tls_proxy.wait(5) # pylint: disable=too-many-function-args + else: + rc = tls_proxy.wait() + + if rc != 0: + logging.error('Unexpected return code %d', rc) + +def cli_trust_root_tests(tmp_dir): + pem_file = os.path.join(tmp_dir, 'pems') + dn_file = os.path.join(tmp_dir, 'dns') + + test_cli("trust_roots", ['--dn-only', '--output=%s' % (dn_file)], "") + + dn_re = re.compile('(.+=\".+\")(,.+=\".+\")') + for line in open(dn_file): + if dn_re.match(line) is None: + logging.error("Unexpected DN line %s", line) + + test_cli("trust_roots", ['--output=%s' % (pem_file)], "") + +def cli_tss_tests(tmp_dir): + data_file = os.path.join(tmp_dir, 'data') + + exp_hash = "53B3C59276AE30EA7FD882268E80FD96AD80CC9FEB15F9FB940E7C4B5CF80B9E" + + test_cli("rng", ["32", "--output=%s" % (data_file)], "") + test_cli("hash", ["--no-fsname", data_file], exp_hash) + + m = 3 + n = 5 + + test_cli("tss_split", [str(m), str(n), data_file, "--share-prefix=%s/split" % (tmp_dir)], "") + + share_files = [] + + for i in range(1, n+1): + share = os.path.join(tmp_dir, "split%d.tss" % (i)) + if not os.access(share, os.R_OK): + logging.error("Failed to create expected split file %s", share) + share_files.append(share) + + rec5 = os.path.join(tmp_dir, "recovered_5") + test_cli("tss_recover", share_files + ["--output=%s" % (rec5)], "") + test_cli("hash", ["--no-fsname", rec5], exp_hash) + + rec4 = os.path.join(tmp_dir, "recovered_4") + test_cli("tss_recover", share_files[1:] + ["--output=%s" % (rec4)], "") + test_cli("hash", ["--no-fsname", rec4], exp_hash) + + rec3 = os.path.join(tmp_dir, "recovered_3") + test_cli("tss_recover", share_files[2:] + ["--output=%s" % (rec3)], "") + test_cli("hash", ["--no-fsname", rec3], exp_hash) + + rec2 = os.path.join(tmp_dir, "recovered_2") + test_cli("tss_recover", share_files[3:] + ["--output=%s" % (rec2)], "", None, + b'Error: Insufficient shares to do TSS reconstruction\n') + + +def cli_pk_encrypt_tests(tmp_dir): + input_file = os.path.join(tmp_dir, 'input') + ctext_file = os.path.join(tmp_dir, 'ctext') + recovered_file = os.path.join(tmp_dir, 'recovered') + rsa_priv_key = os.path.join(tmp_dir, 'rsa.priv') + rsa_pub_key = os.path.join(tmp_dir, 'rsa.pub') + + test_cli("keygen", ["--algo=RSA", "--provider=base", "--params=2048", "--output=%s" % (rsa_priv_key)], "") + + key_hash = "72AF3227EF57A728E894D54623EB8E2C0CD11A4A98BF2DF32DB052BF60897873" + test_cli("hash", ["--no-fsname", "--algo=SHA-256", rsa_priv_key], key_hash) + + test_cli("pkcs8", ["--pub-out", "%s/rsa.priv" % (tmp_dir), "--output=%s" % (rsa_pub_key)], "") + + # Generate a random input file + test_cli("rng", ["10", "16", "32", "--output=%s" % (input_file)], "") + + # Because we used a fixed DRBG for each invocation the same ctext is generated each time + rng_output_hash = "32F5E7B61357DE8397EFDA1E598379DFD5EE21767BDF4E2A435F05117B836AC6" + ctext_hash = "FF1F0EEC2C42DD61D78505C5DF624A19AE6FE2BAB0B8F7D878C7655D54C68FE0" + + test_cli("hash", ["--no-fsname", "--algo=SHA-256", input_file], rng_output_hash) + + # Encrypt and verify ciphertext is the expected value + test_cli("pk_encrypt", [rsa_pub_key, input_file, "--output=%s" % (ctext_file)], "") + test_cli("hash", ["--no-fsname", "--algo=SHA-256", ctext_file], ctext_hash) + + # Decrypt and verify plaintext is recovered + test_cli("pk_decrypt", [rsa_priv_key, ctext_file, "--output=%s" % (recovered_file)], "") + test_cli("hash", ["--no-fsname", "--algo=SHA-256", recovered_file], rng_output_hash) + +def cli_uuid_tests(_tmp_dir): + test_cli("uuid", [], "D80F88F6-ADBE-45AC-B10C-3602E67D985B") + + uuid_re = re.compile(r'[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}') + + output = test_cli("uuid", []) + + if uuid_re.match(output) is None: + logging.error('Bad uuid output %s' % (output)) + +def cli_tls_client_hello_tests(_tmp_dir): + + # pylint: disable=line-too-long + chello = "16030100cf010000cb03035b3cf2457b864d7bef2a4b1f84fc3ced2b68d9551f3455ffdd305af277a91bb200003a16b816b716ba16b9cca9cca8c02cc030c02bc02fc0adc0acc024c00ac028c014c023c009c027c013ccaa009f009ec09fc09e006b003900670033010000680000000e000c000009676d61696c2e636f6d000500050100000000000a001a0018001d0017001a0018001b0019001c01000101010201030104000b00020100000d00140012080508040806050106010401050306030403001600000017000000230000ff01000100" + + output = test_cli("tls_client_hello", ["--hex", "-"], None, chello) + + output_hash = "8EBFC3205ACFA98461128FE5D081D19254237AF84F7DAF000A3C992C3CF6DE44" + test_cli("hash", ["--no-fsname", "--algo=SHA-256", "-"], output_hash, output) + +def cli_speed_pk_tests(_tmp_dir): + msec = 1 + + pk_algos = ["ECDSA", "ECDH", "SM2", "ECKCDSA", "ECGDSA", "GOST-34.10", + "DH", "DSA", "ElGamal", "Ed25519", "Curve25519", "NEWHOPE", "McEliece", + "RSA", "RSA_keygen", "XMSS"] + + output = test_cli("speed", ["--msec=%d" % (msec)] + pk_algos, None).split('\n') + + # ECDSA-secp256r1 106 keygen/sec; 9.35 ms/op 37489733 cycles/op (1 op in 9 ms) + format_re = re.compile(r'^.* [0-9]+ ([A-Za-z ]+)/sec; [0-9]+\.[0-9]+ ms/op .*\([0-9]+ (op|ops) in [0-9\.]+ ms\)') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + +def cli_speed_pbkdf_tests(_tmp_dir): + msec = 1 + pbkdf_ops = ['bcrypt', 'passhash9', 'argon2'] + + format_re = re.compile(r'^.* [0-9]+ /sec; [0-9]+\.[0-9]+ ms/op .*\([0-9]+ (op|ops) in [0-9]+(\.[0-9]+)? ms\)') + for op in pbkdf_ops: + output = test_cli("speed", ["--msec=%d" % (msec), op], None).split('\n') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + +def cli_speed_table_tests(_tmp_dir): + msec = 1 + + version_re = re.compile(r'^Botan 2\.[0-9]+\.[0-9] \(.*, revision .*, distribution .*\)') + cpuid_re = re.compile(r'^CPUID: [a-z_0-9 ]*$') + format_re = re.compile(r'^AES-128 .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') + tbl_hdr_re = re.compile(r'^algo +operation +1024 bytes$') + tbl_val_re = re.compile(r'^AES-128 +(encrypt|decrypt) +[0-9]+(\.[0-9]{2})$') + + output = test_cli("speed", ["--format=table", "--provider=base", "--msec=%d" % (msec), "AES-128"], None).split('\n') + + if len(output) != 11: + logging.error('Unexpected number of lines from table output') + + if version_re.match(output[0]) is None: + logging.error("Unexpected version line %s", output[0]) + + if output[1] != '': + if cpuid_re.match(output[1]) is None: + logging.error("Unexpected cpuid line %s", output[1]) + elif output[2] != '': + logging.error("Expected newline got %s", output[2]) + + if format_re.match(output[3]) is None: + logging.error("Unexpected line %s", output[3]) + if format_re.match(output[4]) is None: + logging.error("Unexpected line %s", output[4]) + if output[5] != '': + logging.error("Expected newline got %s", output[5]) + + if tbl_hdr_re.match(output[6]) is None: + logging.error("Unexpected table header %s", output[6]) + if tbl_val_re.match(output[7]) is None: + logging.error("Unexpected table header %s", output[7]) + if tbl_val_re.match(output[8]) is None: + logging.error("Unexpected table header %s", output[8]) + if output[9] != '': + logging.error("Expected newline got %s", output[9]) + if output[10].find('results are the number of 1000s bytes processed per second') < 0: + logging.error("Unexpected trailing message got %s", output[10]) + +def cli_speed_invalid_option_tests(_tmp_dir): + speed_usage = b"Usage: speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos\n" + + test_cli("speed", ["--buf-size=0", "--msec=1", "AES-128"], + expected_stderr=b"Usage error: Cannot have a zero-sized buffer\n%s" % (speed_usage)) + + test_cli("speed", ["--buf-size=F00F", "--msec=1", "AES-128"], + expected_stderr=b"Usage error: Invalid integer value 'F00F' for option buf-size\n%s" % (speed_usage)) + + test_cli("speed", ["--buf-size=90000000", "--msec=1", "AES-128"], + expected_stderr=b"Usage error: Specified buffer size is too large\n%s" % (speed_usage)) + + test_cli("speed", ["--clear-cpuid=goku", "--msec=1", "AES-128"], + expected_stderr=b"Warning don't know CPUID flag 'goku'\n") + +def cli_speed_math_tests(_tmp_dir): + msec = 1 + # these all have a common output format + math_ops = ['mp_mul', 'mp_div', 'mp_div10', 'modexp', 'random_prime', 'inverse_mod', + 'rfc3394', 'fpe_fe1', 'ecdsa_recovery', 'ecc_init', 'poly_dbl', + 'bn_redc', 'nistp_redc', 'ecc_mult', 'ecc_ops', 'os2ecp', 'primality_test'] + + format_re = re.compile(r'^.* [0-9]+ /sec; [0-9]+\.[0-9]+ ms/op .*\([0-9]+ (op|ops) in [0-9]+(\.[0-9]+)? ms\)') + for op in math_ops: + output = test_cli("speed", ["--msec=%d" % (msec), op], None).split('\n') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + +def cli_speed_tests(_tmp_dir): + # pylint: disable=too-many-branches + + msec = 1 + + output = test_cli("speed", ["--msec=%d" % (msec), "--buf-size=64,512", "AES-128"], None).split('\n') + + if len(output) % 4 != 0: + logging.error("Unexpected number of lines for AES-128 speed test") + + # pylint: disable=line-too-long + format_re = re.compile(r'^AES-128 .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + + output = test_cli("speed", ["--msec=%d" % (msec), "ChaCha20", "SHA-256", "HMAC(SHA-256)"], None).split('\n') + + # pylint: disable=line-too-long + format_re = re.compile(r'^.* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + + output = test_cli("speed", ["--msec=%d" % (msec), "AES-128/GCM"], None).split('\n') + format_re_ks = re.compile(r'^AES-128/GCM\(16\).* [0-9]+ key schedule/sec; [0-9]+\.[0-9]+ ms/op .*\([0-9]+ (op|ops) in [0-9\.]+ ms\)') + format_re_cipher = re.compile(r'^AES-128/GCM\(16\) .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') + for line in output: + if format_re_ks.match(line) is None: + if format_re_cipher.match(line) is None: + logging.error('Unexpected line %s', line) + + output = test_cli("speed", ["--msec=%d" % (msec), "scrypt"], None).split('\n') + + format_re = re.compile(r'^scrypt-[0-9]+-[0-9]+-[0-9]+ \([0-9]+ MiB\) [0-9]+ /sec; [0-9]+\.[0-9]+ ms/op .*\([0-9]+ (op|ops) in [0-9\.]+ ms\)') + + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + + output = test_cli("speed", ["--msec=%d" % (msec), "RNG"], None).split('\n') + + # ChaCha_RNG generate buffer size 1024 bytes: 954.431 MiB/sec 4.01 cycles/byte (477.22 MiB in 500.00 ms) + format_re = re.compile(r'^.* generate buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + + # Entropy source rdseed output 128 bytes estimated entropy 0 in 0.02168 ms total samples 32 + output = test_cli("speed", ["--msec=%d" % (msec), "entropy"], None).split('\n') + format_re = re.compile(r'^Entropy source [_a-z0-9]+ output [0-9]+ bytes estimated entropy [0-9]+ in [0-9]+\.[0-9]+ ms .*total samples [0-9]+') + for line in output: + if format_re.match(line) is None: + logging.error("Unexpected line %s", line) + + output = test_cli("speed", ["--msec=%d" % (msec), "--format=json", "AES-128"], None) + + json_blob = json.loads(output) + if len(json_blob) < 2: + logging.error("Unexpected size for JSON output") + + for b in json_blob: + for field in ['algo', 'op', 'events', 'bps', 'buf_size', 'nanos']: + if field not in b: + logging.error('Missing field %s in JSON record %s' % (field, b)) + +def run_test(fn_name, fn): + start = time.time() + tmp_dir = tempfile.mkdtemp(prefix='botan_cli_') + try: + fn(tmp_dir) + except Exception as e: # pylint: disable=broad-except + logging.error("Test %s threw exception: %s", fn_name, e) + + shutil.rmtree(tmp_dir) + end = time.time() + logging.info("Ran %s in %.02f sec", fn_name, end-start) + +def main(args=None): + # pylint: disable=too-many-branches,too-many-locals + if args is None: + args = sys.argv + + parser = optparse.OptionParser( + formatter=optparse.IndentedHelpFormatter(max_help_position=50)) + + parser.add_option('--verbose', action='store_true', default=False) + parser.add_option('--quiet', action='store_true', default=False) + parser.add_option('--threads', action='store', type='int', default=0) + + (options, args) = parser.parse_args(args) + + setup_logging(options) + + if len(args) < 2: + logging.error("Usage: %s path_to_botan_cli [test_regex]", args[0]) + return 1 + + if not os.access(args[1], os.X_OK): + logging.error("Could not access/execute %s", args[1]) + return 2 + + threads = options.threads + if threads == 0: + threads = multiprocessing.cpu_count() + + global CLI_PATH + CLI_PATH = args[1] + + test_regex = None + if len(args) == 3: + try: + test_regex = re.compile(args[2]) + except re.error as e: + logging.error("Invalid regex: %s", str(e)) + return 1 + + # some of the slowest tests are grouped up front + test_fns = [ + cli_speed_tests, + cli_speed_pk_tests, + cli_speed_math_tests, + cli_speed_pbkdf_tests, + cli_speed_table_tests, + cli_speed_invalid_option_tests, + cli_xmss_sign_tests, + + cli_argon2_tests, + cli_asn1_tests, + cli_base32_tests, + cli_base58_tests, + cli_base64_tests, + cli_bcrypt_tests, + cli_cc_enc_tests, + cli_cycle_counter, + cli_cert_issuance_tests, + cli_compress_tests, + cli_config_tests, + cli_cpuid_tests, + cli_dl_group_info_tests, + cli_ec_group_info_tests, + cli_entropy_tests, + cli_factor_tests, + cli_gen_dl_group_tests, + cli_gen_prime_tests, + cli_hash_tests, + cli_help_tests, + cli_hex_tests, + cli_hmac_tests, + cli_is_prime_tests, + cli_key_tests, + cli_mod_inverse_tests, + cli_pbkdf_tune_tests, + cli_pk_encrypt_tests, + cli_pk_workfactor_tests, + cli_psk_db_tests, + cli_rng_tests, + cli_roughtime_check_tests, + cli_roughtime_tests, + cli_timing_test_tests, + cli_tls_ciphersuite_tests, + cli_tls_client_hello_tests, + cli_tls_http_server_tests, + cli_tls_proxy_tests, + cli_tls_socket_tests, + cli_trust_root_tests, + cli_tss_tests, + cli_uuid_tests, + cli_version_tests, + ] + + tests_to_run = [] + for fn in test_fns: + fn_name = fn.__name__ + + if test_regex is None or test_regex.search(fn_name) is not None: + tests_to_run.append((fn_name, fn)) + + start_time = time.time() + + if threads > 1: + pool = ThreadPool(processes=threads) + results = [] + for test in tests_to_run: + results.append(pool.apply_async(run_test, test)) + + for result in results: + result.get() + else: + for test in tests_to_run: + run_test(test[0], test[1]) + + end_time = time.time() + + print("Ran %d tests with %d failures in %.02f seconds" % ( + TESTS_RUN, TESTS_FAILED, end_time - start_time)) + + if TESTS_FAILED > 0: + return 1 + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/test_cli_crypt.py b/comm/third_party/botan/src/scripts/test_cli_crypt.py new file mode 100755 index 0000000000..6160d03690 --- /dev/null +++ b/comm/third_party/botan/src/scripts/test_cli_crypt.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python + +import binascii +import argparse +import re +import subprocess +import sys +import os.path +import logging +import time +from collections import OrderedDict +import multiprocessing +from multiprocessing.pool import ThreadPool + +SUPPORTED_ALGORITHMS = { + "AES-128/CFB": "aes-128-cfb", + "AES-192/CFB": "aes-192-cfb", + "AES-256/CFB": "aes-256-cfb", + "AES-128/GCM": "aes-128-gcm", + "AES-192/GCM": "aes-192-gcm", + "AES-256/GCM": "aes-256-gcm", + "AES-128/OCB": "aes-128-ocb", + "AES-128/XTS": "aes-128-xts", + "AES-256/XTS": "aes-256-xts", + "ChaCha20Poly1305": "chacha20poly1305", +} + +class VecDocument: + def __init__(self, filepath): + self.data = OrderedDict() + last_testcase_number = 1 + current_testcase_number = 1 + current_group_name = "" + last_group_name = "" + current_testcase = {} + + PATTERN_GROUPHEADER = "^\[(.+)\]$" + PATTERN_KEYVALUE = "^\s*([a-zA-Z]+)\s*=(.*)$" + + with open(filepath, 'r') as f: + # Append one empty line to simplify parsing + lines = f.read().splitlines() + ["\n"] + + for line in lines: + line = line.strip() + if line.startswith("#"): + pass # Skip + elif line == "": + current_testcase_number += 1 + elif re.match(PATTERN_GROUPHEADER, line): + match = re.match(PATTERN_GROUPHEADER, line) + current_group_name = match.group(1) + elif re.match(PATTERN_KEYVALUE, line): + match = re.match(PATTERN_KEYVALUE, line) + key = match.group(1) + value = match.group(2).strip() + current_testcase[key] = value + + if current_testcase_number != last_testcase_number: + if not current_group_name in self.data: + self.data[current_group_name] = [] + if len(current_testcase) != 0: + self.data[current_group_name].append(current_testcase) + current_testcase = {} + last_testcase_number = current_testcase_number + + if current_group_name != last_group_name: + last_group_name = current_group_name + # Reset testcase number + last_testcase_number = 1 + current_testcase_number = 1 + + def get_data(self): + return self.data + +TESTS_RUN = 0 +TESTS_FAILED = 0 + +class TestLogHandler(logging.StreamHandler, object): + def emit(self, record): + # Do the default stuff first + super(TestLogHandler, self).emit(record) + if record.levelno >= logging.ERROR: + global TESTS_FAILED + TESTS_FAILED += 1 + +def setup_logging(options): + if options.verbose: + log_level = logging.DEBUG + elif options.quiet: + log_level = logging.WARNING + else: + log_level = logging.INFO + + lh = TestLogHandler(sys.stdout) + lh.setFormatter(logging.Formatter('%(levelname) 7s: %(message)s')) + logging.getLogger().addHandler(lh) + logging.getLogger().setLevel(log_level) + +def test_cipher_kat(cli_binary, data): + iv = data['Nonce'] + key = data['Key'] + ad = data['AD'] if 'AD' in data else "" + plaintext = data['In'].lower() + ciphertext = data['Out'].lower() + algorithm = data['Algorithm'] + direction = data['Direction'] + + mode = SUPPORTED_ALGORITHMS.get(algorithm) + if mode is None: + raise Exception("Unknown algorithm: '" + algorithm + "'") + + cmd = [ + cli_binary, + "encryption", + "--mode=%s" % mode, + "--iv=%s" % iv, + "--ad=%s" % ad, + "--key=%s" % key] + if direction == "decrypt": + cmd += ['--decrypt'] + + if direction == "decrypt": + invalue = ciphertext + else: + invalue = plaintext + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) + out_raw = p.communicate(input=binascii.unhexlify(invalue))[0] + output = binascii.hexlify(out_raw).decode("UTF-8").lower() + + expected = plaintext if direction == "decrypt" else ciphertext + if expected != output: + logging.error("For test %s got %s expected %s" % (data['testname'], output, expected)) + +def get_testdata(document, max_tests): + out = [] + for algorithm in document: + if algorithm in SUPPORTED_ALGORITHMS: + testcase_number = 0 + for testcase in document[algorithm]: + testcase_number += 1 + for direction in ['encrypt', 'decrypt']: + testname = "{} no {:0>3} ({})".format( + algorithm.lower(), testcase_number, direction) + testname = re.sub("[^a-z0-9-]", "_", testname) + testname = re.sub("_+", "_", testname) + testname = testname.strip("_") + test = {'testname': testname} + for key in testcase: + value = testcase[key] + test[key] = value + test['Algorithm'] = algorithm + test['Direction'] = direction + + out.append(test) + + if max_tests > 0 and testcase_number > max_tests: + break + return out + +def main(args=None): + if args is None: + args = sys.argv + + parser = argparse.ArgumentParser(description="") + parser.add_argument('cli_binary', help='path to the botan cli binary') + parser.add_argument('--max-tests', type=int, default=50, metavar="M") + parser.add_argument('--threads', type=int, default=0, metavar="T") + parser.add_argument('--verbose', action='store_true', default=False) + parser.add_argument('--quiet', action='store_true', default=False) + args = parser.parse_args() + + setup_logging(args) + + cli_binary = args.cli_binary + max_tests = args.max_tests + threads = args.threads + + if threads == 0: + threads = multiprocessing.cpu_count() + + test_data_dir = os.path.join('src', 'tests', 'data') + + mode_test_data = [os.path.join(test_data_dir, 'modes', 'cfb.vec'), + os.path.join(test_data_dir, 'aead', 'gcm.vec'), + os.path.join(test_data_dir, 'aead', 'ocb.vec'), + os.path.join(test_data_dir, 'modes', 'xts.vec'), + os.path.join(test_data_dir, 'aead', 'chacha20poly1305.vec')] + + kats = [] + for f in mode_test_data: + vecfile = VecDocument(f) + kats += get_testdata(vecfile.get_data(), max_tests) + + start_time = time.time() + + if threads > 1: + pool = ThreadPool(processes=threads) + results = [] + for test in kats: + results.append(pool.apply_async(test_cipher_kat, (cli_binary, test))) + + for result in results: + result.get() + else: + for test in kats: + test_cipher_kat(test) + + end_time = time.time() + + print("Ran %d tests with %d failures in %.02f seconds" % ( + len(kats), TESTS_FAILED, end_time - start_time)) + + if TESTS_FAILED > 0: + return 1 + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/test_fuzzers.py b/comm/third_party/botan/src/scripts/test_fuzzers.py new file mode 100755 index 0000000000..01c202f236 --- /dev/null +++ b/comm/third_party/botan/src/scripts/test_fuzzers.py @@ -0,0 +1,187 @@ +#!/usr/bin/python + +# (C) 2017,2018 Jack Lloyd + +import sys +import os +import subprocess +import optparse # pylint: disable=deprecated-module +import stat +import multiprocessing +import time + +def run_fuzzer_gdb(args): + (fuzzer_bin, corpus_file) = args + + gdb_proc = subprocess.Popen(['gdb', '--quiet', '--return-child-result', fuzzer_bin], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + + gdb_commands = ('run < %s\nbt\nquit\n' % (corpus_file)).encode('ascii') + + (stdout, stderr) = gdb_proc.communicate(gdb_commands) + + if gdb_proc.returncode == 0: + return (0, '', '') + + return (corpus_file, gdb_proc.returncode, stdout.decode('ascii'), stderr.decode('ascii')) + +def run_fuzzer(args): + (fuzzer_bin, corpus_file) = args + corpus_fd = open(corpus_file, 'r') + fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + (stdout, stderr) = fuzzer_proc.communicate() + corpus_fd.close() + return (corpus_file, fuzzer_proc.returncode, stdout.decode('ascii'), stderr.decode('ascii')) + +def run_fuzzer_many_files(fuzzer_bin, corpus_files): + fuzzer_proc = subprocess.Popen([fuzzer_bin] + corpus_files, stdin=None, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + (stdout, stderr) = fuzzer_proc.communicate() + return (fuzzer_proc.returncode, stdout.decode('ascii'), stderr.decode('ascii')) + +def main(args=None): + #pylint: disable=too-many-branches + #pylint: disable=too-many-statements + #pylint: disable=too-many-locals + + if args is None: + args = sys.argv + + parser = optparse.OptionParser( + usage='Usage: %prog [options] corpus_dir fuzzers_dir', + ) + + parser.add_option('--gdb', action='store_true', + help='Run under GDB and capture backtraces') + + parser.add_option('--one-at-a-time', action='store_true', default=False, + help='Test one corpus input at a time') + + (options, args) = parser.parse_args(args) + + if len(args) != 3: + parser.print_usage() + return 1 + + if options.gdb and not options.one_at_a_time: + print("Option --gdb requires --one-at-a-time") + return 1 + + corpus_dir = args[1] + fuzzer_dir = args[2] + + if not os.access(corpus_dir, os.R_OK): + print("Error could not access corpus directory '%s'" % (corpus_dir)) + return 1 + + if not os.access(fuzzer_dir, os.R_OK): + print("Error could not access fuzzers directory '%s'" % (fuzzer_dir)) + return 1 + + fuzzers = set([]) + for fuzzer in os.listdir(fuzzer_dir): + if fuzzer.endswith('.zip'): + continue + fuzzers.add(fuzzer) + + corpii = set([]) + for corpus in os.listdir(corpus_dir): + # Ignore regular files in toplevel dir + if not stat.S_ISDIR(os.stat(os.path.join(corpus_dir, corpus)).st_mode): + continue + + if corpus == '.git': + continue + + corpii.add(corpus) + + fuzzers_without_corpus = fuzzers - corpii + corpus_without_fuzzers = corpii - fuzzers + + for f in sorted(list(fuzzers_without_corpus)): + print("Warning: Fuzzer %s has no corpus" % (f)) + for c in sorted(list(corpus_without_fuzzers)): + print("Warning: Corpus %s has no fuzzer" % (c)) + + fuzzers_with_corpus = fuzzers & corpii + + crash_count = 0 + stderr_count = 0 + stdout_count = 0 + + if options.one_at_a_time: + pool = multiprocessing.Pool(multiprocessing.cpu_count() * 2) + chunk_size = 32 # arbitrary + + run_fuzzer_func = run_fuzzer_gdb if options.gdb else run_fuzzer + + for fuzzer in sorted(list(fuzzers_with_corpus)): + fuzzer_bin = os.path.join(fuzzer_dir, fuzzer) + corpus_subdir = os.path.join(corpus_dir, fuzzer) + corpus_files = [os.path.join(corpus_subdir, l) for l in sorted(list(os.listdir(corpus_subdir)))] + + # We have to do this hack because multiprocessing's Pool.map doesn't support + # passing any initial arguments, just the single iteratable + map_args = [(fuzzer_bin, f) for f in corpus_files] + + start = time.time() + + for result in pool.map(run_fuzzer_func, map_args, chunk_size): + (corpus_file, retcode, stdout, stderr) = result + + if retcode != 0: + print("Fuzzer %s crashed with input %s returncode %d" % (fuzzer, corpus_file, retcode)) + crash_count += 1 + + if stdout: + print("Fuzzer %s produced stdout on input %s:\n%s" % (fuzzer, corpus_file, stdout)) + stdout_count += 1 + + if stderr: + print("Fuzzer %s produced stderr on input %s:\n%s" % (fuzzer, corpus_file, stderr)) + stderr_count += 1 + + duration = time.time() - start + print("Tested fuzzer %s with %d test cases, %d crashes in %.02f seconds" % ( + fuzzer, len(corpus_files), crash_count, duration)) + crash_count = 0 + sys.stdout.flush() + else: + for fuzzer in sorted(list(fuzzers_with_corpus)): + fuzzer_bin = os.path.join(fuzzer_dir, fuzzer) + corpus_subdir = os.path.join(corpus_dir, fuzzer) + corpus_files = [os.path.join(corpus_subdir, l) for l in sorted(list(os.listdir(corpus_subdir)))] + + start = time.time() + + (retcode, stdout, stderr) = run_fuzzer_many_files(fuzzer_bin, corpus_files) + + if retcode != 0: + print("Fuzzer %s crashed returncode %d" % (fuzzer, retcode)) + crash_count += 1 + + if stdout: + print("Fuzzer %s produced stdout:\n%s" % (fuzzer, stdout)) + stdout_count += 1 + + if stderr: + print("Fuzzer %s produced stderr:\n%s" % (fuzzer, stderr)) + stderr_count += 1 + + duration = time.time() - start + + print("Tested fuzzer %s with %d test cases, %d crashes in %.02f seconds" % ( + fuzzer, len(corpus_files), crash_count, duration)) + crash_count = 0 + + if crash_count > 0 or stderr_count > 0 or stdout_count > 0: + print("Ran fuzzer tests, %d crashes %d stdout %d stderr" % (crash_count, stdout_count, stderr_count)) + return 2 + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/test_python.py b/comm/third_party/botan/src/scripts/test_python.py new file mode 100644 index 0000000000..2202c0e4bc --- /dev/null +++ b/comm/third_party/botan/src/scripts/test_python.py @@ -0,0 +1,695 @@ +#!/usr/bin/env python + +""" +(C) 2015,2017,2018,2019 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import unittest +import binascii +import botan2 + +def hex_encode(buf): + return binascii.hexlify(buf).decode('ascii') + +def hex_decode(buf): + return binascii.unhexlify(buf.encode('ascii')) + +class BotanPythonTests(unittest.TestCase): + # pylint: disable=too-many-public-methods,too-many-locals + + def test_version(self): + version_str = botan2.version_string() + self.assertTrue(version_str.startswith('Botan ')) + + self.assertEqual(botan2.version_major(), 2) + self.assertGreaterEqual(botan2.version_minor(), 8) + + self.assertGreaterEqual(botan2.ffi_api_version(), 20180713) + + def test_compare(self): + + x = "1234" + y = "1234" + z = "1233" + self.assertTrue(botan2.const_time_compare(x, y)) + self.assertFalse(botan2.const_time_compare(x, z)) + self.assertFalse(botan2.const_time_compare(x, x + z)) + + def test_block_cipher(self): + aes = botan2.BlockCipher("AES-128") + self.assertEqual(aes.algo_name(), "AES-128") + self.assertEqual(aes.block_size(), 16) + self.assertEqual(aes.minimum_keylength(), 16) + self.assertEqual(aes.maximum_keylength(), 16) + + aes.set_key(hex_decode("000102030405060708090a0b0c0d0e0f")) + ct = aes.encrypt(hex_decode("00112233445566778899aabbccddeeff")) + + self.assertEqual(hex_encode(ct), "69c4e0d86a7b0430d8cdb78070b4c55a") + + pt = aes.decrypt(ct) + + self.assertEqual(hex_encode(pt), "00112233445566778899aabbccddeeff") + + def test_kdf(self): + + secret = hex_decode('6FD4C3C0F38E5C7A6F83E99CD9BD') + salt = hex_decode('DBB986') + label = hex_decode('') + expected = hex_decode('02AEB40A3D4B66FBA540F9D4B20006F2046E0F3A029DEAB201FC692B79EB27CEF7E16069046A') + + produced = botan2.kdf('KDF2(SHA-1)', secret, 38, salt, label) + + self.assertEqual(hex_encode(produced), hex_encode(expected)) + + def test_pbkdf(self): + + (salt, iterations, pbkdf) = botan2.pbkdf('PBKDF2(SHA-1)', '', 32, 10000, hex_decode('0001020304050607')) + + self.assertEqual(iterations, 10000) + self.assertEqual(hex_encode(pbkdf), + '59b2b1143b4cb1059ec58d9722fb1c72471e0d85c6f7543ba5228526375b0127') + + (salt, iterations, pbkdf) = botan2.pbkdf_timed('PBKDF2(SHA-256)', 'xyz', 32, 200) + + cmp_pbkdf = botan2.pbkdf('PBKDF2(SHA-256)', 'xyz', 32, iterations, salt)[2] + + self.assertEqual(pbkdf, cmp_pbkdf) + + def test_scrypt(self): + scrypt = botan2.scrypt(10, '', '', 16, 1, 1) + self.assertEqual(hex_encode(scrypt), "77d6576238657b203b19") + + scrypt = botan2.scrypt(32, 'password', 'NaCl', 1024, 8, 16) + self.assertEqual(hex_encode(scrypt), "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162") + + def test_bcrypt(self): + r = botan2.RandomNumberGenerator() + phash = botan2.bcrypt('testing', r) + self.assertTrue(isinstance(phash, str)) + self.assertTrue(phash.startswith("$2a$")) + + self.assertTrue(botan2.check_bcrypt('testing', phash)) + self.assertFalse(botan2.check_bcrypt('live fire', phash)) + + self.assertTrue(botan2.check_bcrypt('test', '$2a$04$wjen1fAA.UW6UxthpKK.huyOoxvCR7ATRCVC4CBIEGVDOCtr8Oj1C')) + + def test_mac(self): + + hmac = botan2.MsgAuthCode('HMAC(SHA-256)') + self.assertEqual(hmac.algo_name(), 'HMAC(SHA-256)') + self.assertEqual(hmac.minimum_keylength(), 0) + self.assertEqual(hmac.maximum_keylength(), 4096) + hmac.set_key(hex_decode('0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20')) + hmac.update(hex_decode('616263')) + + expected = hex_decode('A21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181') + produced = hmac.final() + + self.assertEqual(hex_encode(expected), hex_encode(produced)) + + def test_rng(self): + user_rng = botan2.RandomNumberGenerator("user") + + output1 = user_rng.get(32) + output2 = user_rng.get(32) + + self.assertEqual(len(output1), 32) + self.assertEqual(len(output2), 32) + self.assertNotEqual(output1, output2) + + output3 = user_rng.get(1021) + self.assertEqual(len(output3), 1021) + + system_rng = botan2.RandomNumberGenerator('system') + + user_rng.reseed_from_rng(system_rng, 256) + + user_rng.add_entropy('seed material...') + + def test_hash(self): + + try: + _h = botan2.HashFunction('NoSuchHash') + except botan2.BotanException as e: + self.assertEqual(str(e), "botan_hash_init failed: -40 (Not implemented)") + + sha256 = botan2.HashFunction('SHA-256') + self.assertEqual(sha256.algo_name(), 'SHA-256') + self.assertEqual(sha256.output_length(), 32) + self.assertEqual(sha256.block_size(), 64) + sha256.update('ignore this please') + sha256.clear() + sha256.update('a') + hash1 = sha256.final() + + self.assertEqual(hex_encode(hash1), "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb") + + sha256.update(hex_decode('61')) + sha256_2 = sha256.copy_state() + sha256.update(hex_decode('6263')) + h2 = sha256.final() + self.assertEqual(hex_encode(h2), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + + self.assertEqual(hex_encode(sha256_2.final()), hex_encode(hash1)) + + def test_cipher(self): + for mode in ['AES-128/CTR-BE', 'Serpent/GCM', 'ChaCha20Poly1305']: + enc = botan2.SymmetricCipher(mode, encrypt=True) + + if mode == 'AES-128/CTR-BE': + self.assertEqual(enc.algo_name(), 'CTR-BE(AES-128)') + elif mode == 'Serpent/GCM': + self.assertEqual(enc.algo_name(), 'Serpent/GCM(16)') + else: + self.assertEqual(enc.algo_name(), mode) + + (kmin, kmax) = enc.key_length() + + self.assertLessEqual(kmin, kmax) + + rng = botan2.RandomNumberGenerator() + iv = rng.get(enc.default_nonce_length()) + key = rng.get(kmax) + pt = rng.get(21) + + enc.set_key(key) + enc.start(iv) + + update_result = enc.update('') + assert not update_result + + ct = enc.finish(pt) + + dec = botan2.SymmetricCipher(mode, encrypt=False) + dec.set_key(key) + dec.start(iv) + decrypted = dec.finish(ct) + + self.assertEqual(decrypted, pt) + + + def test_mceliece(self): + rng = botan2.RandomNumberGenerator() + mce_priv = botan2.PrivateKey.create('McEliece', '2960,57', rng) + mce_pub = mce_priv.get_public_key() + self.assertEqual(mce_pub.estimated_strength(), 128) + + mce_plaintext = rng.get(16) + mce_ad = rng.get(48) + mce_ciphertext = botan2.mceies_encrypt(mce_pub, rng, 'ChaCha20Poly1305', mce_plaintext, mce_ad) + + mce_decrypt = botan2.mceies_decrypt(mce_priv, 'ChaCha20Poly1305', mce_ciphertext, mce_ad) + + self.assertEqual(mce_plaintext, mce_decrypt) + + def test_rsa_load_store(self): + + rsa_priv_pem = """-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALWtiBjcofJW/4+r +CIjQZn2V3yCYsNIBpMdVkNPr36FZ3ZHGSv2ggmCe+IWy0fTcBVyP+fo3HC8zmOC2 +EsYDFRExyB2zIsjRXlPrVrTfcyXwUEaInLJQId5CguFrmyj1y7K43ezg+OTop39n +TyaukrciCSCh++Q/UQOanHnR8ctrAgMBAAECgYBPfKySgBmk31ZyA7k4rsFgye01 +JEkcoNZ41iGG7ujJffl4maLew9a3MmZ2jI3azVbVMDMFPA5rQm5tRowBMYEJ5oBc +LP4AP41Lujfa+vua6l3t94bAV+CufZiY0297FcPbGqNu+xSQ2Bol2uHh9mrcgQUs +fevA50KOLR9hv4zH6QJBAPCOKiExONtVhJn8qVPCBlJ8Vjjnt9Uno5EzMBAKMbZi +OySkGwo9/9LUWO03r7tjrGSy5jJk+iOrcLeDl6zETfkCQQDBV6PpD/3ccQ1IfWcw +jG8yik0bIuXgrD0uW4g8Cvj+05wrv7RYPHuFtj3Rtb94YjtgYn7QvjH7y88XmTC4 +2k2DAkEA4E9Ae7kBUoz42/odDswyxwHICMIRyoJu5Ht9yscmufH5Ql6AFFnhzf9S +eMjfZfY4j6G+Q6mjElXQAl+DtIdMSQJBAJzdMkuBggI8Zv6NYA9voThsJSsDIWcr +12epM9sjO+nkXizQmM2OJNnThkyDHRna+Tm2MBXEemFEdn06+ODBnWkCQQChAbG4 +255RiCuYdrfiTPF/WLtvRyGd1LRwHcYIW4mJFPzxYAMTwQKbppLAnxw73vyef/zC +2BgXEW02tjRBtgZ+ +-----END PRIVATE KEY----- +""" + + rsa_pub_pem = """-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1rYgY3KHyVv+PqwiI0GZ9ld8g +mLDSAaTHVZDT69+hWd2Rxkr9oIJgnviFstH03AVcj/n6NxwvM5jgthLGAxURMcgd +syLI0V5T61a033Ml8FBGiJyyUCHeQoLha5so9cuyuN3s4Pjk6Kd/Z08mrpK3Igkg +ofvkP1EDmpx50fHLawIDAQAB +-----END PUBLIC KEY----- +""" + + rsapriv = botan2.PrivateKey.load(rsa_priv_pem) + + self.assertEqual(rsapriv.to_pem(), rsa_priv_pem) + + rsapub = rsapriv.get_public_key() + self.assertEqual(rsapub.to_pem(), rsa_pub_pem) + + rsapub = botan2.PublicKey.load(rsa_pub_pem) + self.assertEqual(rsapub.to_pem(), rsa_pub_pem) + + n = 0xB5AD8818DCA1F256FF8FAB0888D0667D95DF2098B0D201A4C75590D3EBDFA159DD91C64AFDA082609EF885B2D1F4DC055C8FF9FA371C2F3398E0B612C603151131C81DB322C8D15E53EB56B4DF7325F05046889CB25021DE4282E16B9B28F5CBB2B8DDECE0F8E4E8A77F674F26AE92B7220920A1FBE43F51039A9C79D1F1CB6B # pylint: disable=line-too-long + e = 0x10001 + + rsapub2 = botan2.PublicKey.load_rsa(n, e) + self.assertEqual(rsapub2.to_pem(), rsa_pub_pem) + + self.assertEqual(rsapub2.get_field("n"), n) + self.assertEqual(rsapub2.get_field("e"), e) + + def test_key_crypto(self): + rng = botan2.RandomNumberGenerator() + priv = botan2.PrivateKey.create('RSA', '1024', rng) + passphrase = "super secret tell noone" + + for is_pem in [True, False]: + ref_val = priv.export(is_pem) + + enc1 = priv.export_encrypted(passphrase, rng, True, msec=10) + dec1 = botan2.PrivateKey.load(enc1, passphrase) + self.assertEqual(dec1.export(is_pem), ref_val) + + pem2 = priv.export_encrypted(passphrase, rng, True, msec=10, cipher="AES-128/SIV") + dec2 = botan2.PrivateKey.load(pem2, passphrase) + self.assertEqual(dec2.export(is_pem), ref_val) + + pem3 = priv.export_encrypted(passphrase, rng, True, msec=10, cipher="AES-128/GCM", pbkdf="Scrypt") + dec3 = botan2.PrivateKey.load(pem3, passphrase) + self.assertEqual(dec3.export(is_pem), ref_val) + + def test_check_key(self): + # valid (if rather small) RSA key + n = 273279220906618527352827457840955116141 + e = 0x10001 + + rng = botan2.RandomNumberGenerator() + + rsapub = botan2.PublicKey.load_rsa(n, e) + self.assertTrue(rsapub.check_key(rng)) + + # invalid + try: + rsapub = botan2.PublicKey.load_rsa(n - 1, e) + except botan2.BotanException as e: + self.assertEqual(str(e), "botan_pubkey_load_rsa failed: -1 (Invalid input)") + + def test_rsa(self): + # pylint: disable=too-many-locals + rng = botan2.RandomNumberGenerator() + rsapriv = botan2.PrivateKey.create('RSA', '1024', rng) + self.assertEqual(rsapriv.algo_name(), 'RSA') + + priv_pem = rsapriv.to_pem() + priv_der = rsapriv.to_der() + + self.assertEqual(priv_pem[0:28], "-----BEGIN PRIVATE KEY-----\n") + self.assertGreater(len(priv_pem), len(priv_der)) + + rsapub = rsapriv.get_public_key() + self.assertEqual(rsapub.algo_name(), 'RSA') + self.assertEqual(rsapub.estimated_strength(), 80) + + pub_pem = rsapub.to_pem() + pub_der = rsapub.to_der() + + self.assertEqual(pub_pem[0:27], "-----BEGIN PUBLIC KEY-----\n") + self.assertGreater(len(pub_pem), len(pub_der)) + + enc = botan2.PKEncrypt(rsapub, "OAEP(SHA-256)") + dec = botan2.PKDecrypt(rsapriv, "OAEP(SHA-256)") + + symkey = rng.get(32) + ctext = enc.encrypt(symkey, rng) + + ptext = dec.decrypt(ctext) + + self.assertEqual(ptext, symkey) + + signer = botan2.PKSign(rsapriv, 'EMSA4(SHA-384)') + + signer.update('messa') + signer.update('ge') + sig = signer.finish(botan2.RandomNumberGenerator()) + + verify = botan2.PKVerify(rsapub, 'EMSA4(SHA-384)') + + verify.update('mess') + verify.update('age') + self.assertTrue(verify.check_signature(sig)) + + verify.update('mess of things') + verify.update('age') + self.assertFalse(verify.check_signature(sig)) + + verify.update('message') + self.assertTrue(verify.check_signature(sig)) + + def test_ecdsa(self): + rng = botan2.RandomNumberGenerator() + + hash_fn = 'EMSA1(SHA-256)' + group = 'secp256r1' + msg = 'test message' + + priv = botan2.PrivateKey.create('ECDSA', group, rng) + pub = priv.get_public_key() + self.assertEqual(pub.get_field('public_x'), priv.get_field('public_x')) + self.assertEqual(pub.get_field('public_y'), priv.get_field('public_y')) + + signer = botan2.PKSign(priv, hash_fn, True) + signer.update(msg) + signature = signer.finish(rng) + + verifier = botan2.PKVerify(pub, hash_fn) + verifier.update(msg) + #fails because DER/not-DER mismatch + self.assertFalse(verifier.check_signature(signature)) + + verifier = botan2.PKVerify(pub, hash_fn, True) + verifier.update(msg) + self.assertTrue(verifier.check_signature(signature)) + + pub_x = pub.get_field('public_x') + pub_y = priv.get_field('public_y') + pub2 = botan2.PublicKey.load_ecdsa(group, pub_x, pub_y) + verifier = botan2.PKVerify(pub2, hash_fn, True) + verifier.update(msg) + self.assertTrue(verifier.check_signature(signature)) + + priv2 = botan2.PrivateKey.load_ecdsa(group, priv.get_field('x')) + signer = botan2.PKSign(priv2, hash_fn, True) + # sign empty message + signature = signer.finish(rng) + + # verify empty message + self.assertTrue(verifier.check_signature(signature)) + + def test_sm2(self): + rng = botan2.RandomNumberGenerator() + + hash_fn = 'EMSA1(SM3)' + group = 'sm2p256v1' + msg = 'test message' + + priv = botan2.PrivateKey.create('SM2', group, rng) + pub = priv.get_public_key() + self.assertEqual(pub.get_field('public_x'), priv.get_field('public_x')) + self.assertEqual(pub.get_field('public_y'), priv.get_field('public_y')) + + signer = botan2.PKSign(priv, hash_fn) + signer.update(msg) + signature = signer.finish(rng) + + verifier = botan2.PKVerify(pub, hash_fn) + verifier.update(msg) + self.assertTrue(verifier.check_signature(signature)) + + pub_x = pub.get_field('public_x') + pub_y = priv.get_field('public_y') + pub2 = botan2.PublicKey.load_sm2(group, pub_x, pub_y) + verifier = botan2.PKVerify(pub2, hash_fn) + verifier.update(msg) + self.assertTrue(verifier.check_signature(signature)) + + priv2 = botan2.PrivateKey.load_sm2(group, priv.get_field('x')) + signer = botan2.PKSign(priv2, hash_fn) + # sign empty message + signature = signer.finish(rng) + + # verify empty message + self.assertTrue(verifier.check_signature(signature)) + + def test_ecdh(self): + # pylint: disable=too-many-locals + a_rng = botan2.RandomNumberGenerator('user') + b_rng = botan2.RandomNumberGenerator('user') + + kdf = 'KDF2(SHA-384)' + + for grp in ['secp256r1', 'secp384r1', 'brainpool256r1']: + a_priv = botan2.PrivateKey.create('ECDH', grp, a_rng) + b_priv = botan2.PrivateKey.create('ECDH', grp, b_rng) + + a_op = botan2.PKKeyAgreement(a_priv, kdf) + b_op = botan2.PKKeyAgreement(b_priv, kdf) + + a_pub = a_op.public_value() + b_pub = b_op.public_value() + + salt = a_rng.get(8) + b_rng.get(8) + + a_key = a_op.agree(b_pub, 32, salt) + b_key = b_op.agree(a_pub, 32, salt) + + self.assertEqual(a_key, b_key) + + a_pem = a_priv.to_pem() + + a_priv_x = a_priv.get_field('x') + + new_a = botan2.PrivateKey.load_ecdh(grp, a_priv_x) + + self.assertEqual(a_pem, new_a.to_pem()) + + def test_certs(self): + # pylint: disable=too-many-statements + cert = botan2.X509Cert(filename="src/tests/data/x509/ecc/CSCA.CSCA.csca-germany.1.crt") + pubkey = cert.subject_public_key() + + self.assertEqual(pubkey.algo_name(), 'ECDSA') + self.assertEqual(pubkey.estimated_strength(), 112) + + self.assertEqual(cert.fingerprint("SHA-1"), + "32:42:1C:C3:EC:54:D7:E9:43:EC:51:F0:19:23:BD:85:1D:F2:1B:B9") + + self.assertEqual(hex_encode(cert.serial_number()), "01") + self.assertEqual(hex_encode(cert.authority_key_id()), + "0096452de588f966c4ccdf161dd1f3f5341b71e7") + + self.assertEqual(cert.subject_dn('Name', 0), 'csca-germany') + self.assertEqual(cert.subject_dn('Email', 0), 'csca-germany@bsi.bund.de') + self.assertEqual(cert.subject_dn('Organization', 0), 'bund') + self.assertEqual(cert.subject_dn('Organizational Unit', 0), 'bsi') + self.assertEqual(cert.subject_dn('Country', 0), 'DE') + + self.assertTrue(cert.to_string().startswith("Version: 3")) + + self.assertEqual(cert.issuer_dn('Name', 0), 'csca-germany') + self.assertEqual(cert.issuer_dn('Organization', 0), 'bund') + self.assertEqual(cert.issuer_dn('Organizational Unit', 0), 'bsi') + self.assertEqual(cert.issuer_dn('Country', 0), 'DE') + + self.assertTrue(cert.hostname_match('csca-germany')) + self.assertFalse(cert.hostname_match('csca-slovakia')) + + self.assertEqual(cert.not_before(), 1184858838) + self.assertEqual(cert.not_after(), 1831907880) + + self.assertTrue(cert.allowed_usage(["CRL_SIGN", "KEY_CERT_SIGN"])) + self.assertTrue(cert.allowed_usage(["KEY_CERT_SIGN"])) + self.assertFalse(cert.allowed_usage(["DIGITAL_SIGNATURE"])) + self.assertFalse(cert.allowed_usage(["DIGITAL_SIGNATURE", "CRL_SIGN"])) + + root = botan2.X509Cert("src/tests/data/x509/nist/root.crt") + + int09 = botan2.X509Cert("src/tests/data/x509/nist/test09/int.crt") + end09 = botan2.X509Cert("src/tests/data/x509/nist/test09/end.crt") + self.assertEqual(end09.verify([int09], [root]), 2001) + + end04 = botan2.X509Cert("src/tests/data/x509/nist/test04/end.crt") + int04_1 = botan2.X509Cert("src/tests/data/x509/nist/test04/int1.crt") + int04_2 = botan2.X509Cert("src/tests/data/x509/nist/test04/int2.crt") + self.assertEqual(end04.verify([int04_1, int04_2], [], "src/tests/data/x509/nist/", required_strength=80), 0) + self.assertEqual(end04.verify([int04_1, int04_2], [], required_strength=80), 3000) + self.assertEqual(end04.verify([int04_1, int04_2], [root], required_strength=80, hostname="User1-CP.02.01"), 0) + self.assertEqual(end04.verify([int04_1, int04_2], [root], required_strength=80, hostname="invalid"), 4008) + self.assertEqual(end04.verify([int04_1, int04_2], [root], required_strength=80, reference_time=1), 2000) + + self.assertEqual(botan2.X509Cert.validation_status(0), 'Verified') + self.assertEqual(botan2.X509Cert.validation_status(3000), 'Certificate issuer not found') + self.assertEqual(botan2.X509Cert.validation_status(4008), 'Certificate does not match provided name') + + rootcrl = botan2.X509CRL("src/tests/data/x509/nist/root.crl") + + end01 = botan2.X509Cert("src/tests/data/x509/nist/test01/end.crt") + self.assertEqual(end01.verify([], [root], required_strength=80, crls=[rootcrl]), 0) + + int20 = botan2.X509Cert("src/tests/data/x509/nist/test20/int.crt") + end20 = botan2.X509Cert("src/tests/data/x509/nist/test20/end.crt") + int20crl = botan2.X509CRL("src/tests/data/x509/nist/test20/int.crl") + + self.assertEqual(end20.verify([int20], [root], required_strength=80, crls=[int20crl, rootcrl]), 5000) + self.assertEqual(botan2.X509Cert.validation_status(5000), 'Certificate is revoked') + + int21 = botan2.X509Cert("src/tests/data/x509/nist/test21/int.crt") + end21 = botan2.X509Cert("src/tests/data/x509/nist/test21/end.crt") + int21crl = botan2.X509CRL("src/tests/data/x509/nist/test21/int.crl") + self.assertEqual(end21.verify([int21], [root], required_strength=80, crls=[int21crl, rootcrl]), 5000) + + self.assertTrue(int20.is_revoked(rootcrl)) + self.assertFalse(int04_1.is_revoked(rootcrl)) + self.assertTrue(end21.is_revoked(int21crl)) + + + def test_mpi(self): + # pylint: disable=too-many-statements,too-many-locals + z = botan2.MPI() + self.assertEqual(z.bit_count(), 0) + five = botan2.MPI('5') + self.assertEqual(five.bit_count(), 3) + big = botan2.MPI('0x85839682368923476892367235') + self.assertEqual(big.bit_count(), 104) + small = botan2.MPI(0xDEADBEEF) + radix = botan2.MPI("DEADBEEF", 16) + + self.assertEqual(hex_encode(small.to_bytes()), "deadbeef") + self.assertEqual(hex_encode(big.to_bytes()), "85839682368923476892367235") + + self.assertEqual(int(small), 0xDEADBEEF) + self.assertEqual(int(radix), int(small)) + + self.assertEqual(int(small >> 16), 0xDEAD) + + small >>= 15 + + self.assertEqual(int(small), 0x1BD5B) + + small <<= 15 + + self.assertEqual(int(small), 0xDEAD8000) + + ten = botan2.MPI(10) + + self.assertEqual(ten, five + five) + self.assertNotEqual(ten, five) + self.assertLess(five, ten) + self.assertLessEqual(five, ten) + + x = botan2.MPI(five) + + self.assertEqual(x, five) + + x += botan2.MPI(1) + self.assertNotEqual(x, five) + + self.assertEqual(int(x * five), 30) + + x *= five + x *= five + self.assertEqual(int(x), 150) + + self.assertTrue(not x.is_negative()) + + x.flip_sign() + self.assertTrue(x.is_negative()) + self.assertEqual(int(x), -150) + + x.flip_sign() + + x.set_bit(0) + self.assertTrue(int(x), 151) + self.assertTrue(x.get_bit(0)) + self.assertTrue(x.get_bit(4)) + self.assertFalse(x.get_bit(6)) + + x.clear_bit(4) + self.assertEqual(int(x), 135) + + rng = botan2.RandomNumberGenerator() + self.assertFalse(x.is_prime(rng)) + + two = botan2.MPI(2) + + x += two + self.assertTrue(x.is_prime(rng)) + + mod = x + two + + inv = x.inverse_mod(mod) + self.assertEqual(int(inv), 69) + self.assertEqual(int((inv * x) % mod), 1) + + p = inv.pow_mod(botan2.MPI(46), mod) + self.assertEqual(int(p), 42) + + one = botan2.MPI(1) + twelve = botan2.MPI("C", 16) + eight = botan2.MPI(8) + + mul = twelve.mod_mul(eight, inv) + self.assertEqual(int(mul), 27) + + gcd = one.gcd(one) + self.assertEqual(one, gcd) + gcd = one.gcd(twelve) + self.assertEqual(one, gcd) + gcd = twelve.gcd(eight) + self.assertEqual(4, int(gcd)) + + def test_mpi_random(self): + rng = botan2.RandomNumberGenerator() + + u = botan2.MPI.random(rng, 512) + self.assertEqual(u.bit_count(), 512) + + l = u >> 32 + self.assertEqual(l.bit_count(), 512-32) + + for _i in range(10): + x = botan2.MPI.random_range(rng, l, u) + self.assertLess(x, u) + self.assertGreater(x, l) + + def test_fpe(self): + + modulus = botan2.MPI('1000000000') + key = b'001122334455' + + fpe = botan2.FormatPreservingEncryptionFE1(modulus, key) + + value = botan2.MPI('392910392') + tweak = 'tweak value' + + ctext = fpe.encrypt(value, tweak) + + ptext = fpe.decrypt(ctext, tweak) + + self.assertEqual(value, ptext) + + def test_keywrap(self): + key = hex_decode('00112233445566778899aabbccddeeff') + kek = hex_decode('000102030405060708090a0b0c0d0e0f') + + wrapped = botan2.nist_key_wrap(kek, key) + self.assertEqual(hex_encode(wrapped), '1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5') + + self.assertEqual(len(wrapped), 16+8) + unwrapped = botan2.nist_key_unwrap(kek, wrapped) + self.assertEqual(hex_encode(unwrapped), '00112233445566778899aabbccddeeff') + + def test_hotp(self): + + hotp = botan2.HOTP(b'12345678901234567890') + + self.assertEqual(hotp.generate(0), 755224) + self.assertEqual(hotp.generate(1), 287082) + self.assertEqual(hotp.generate(9), 520489) + + self.assertEqual(hotp.check(520489, 8), (False, 8)) + self.assertEqual(hotp.check(520489, 8, 1), (True, 10)) + self.assertEqual(hotp.check(520489, 7, 2), (True, 10)) + self.assertEqual(hotp.check(520489, 0, 9), (True, 10)) + + def test_totp(self): + + totp = botan2.TOTP(b'12345678901234567890', digest="SHA-1", digits=8) + + self.assertEqual(totp.generate(59), 94287082) + self.assertEqual(totp.generate(1111111109), 7081804) + self.assertEqual(totp.generate(1111111111), 14050471) + self.assertEqual(totp.generate(1234567890), 89005924) + self.assertEqual(totp.generate(1234567890), 89005924) + self.assertEqual(totp.generate(2000000000), 69279037) + + self.assertTrue(totp.check(7081804, 1111111109)) + self.assertTrue(totp.check(7081804, 1111111109 - 29)) + self.assertFalse(totp.check(7081804, 1111111109 + 1)) + self.assertTrue(totp.check(7081804, 1111111109 + 30, 1)) + +if __name__ == '__main__': + unittest.main() diff --git a/comm/third_party/botan/src/scripts/tls_scanner/boa.txt b/comm/third_party/botan/src/scripts/tls_scanner/boa.txt new file mode 100644 index 0000000000..436b785728 --- /dev/null +++ b/comm/third_party/botan/src/scripts/tls_scanner/boa.txt @@ -0,0 +1 @@ +bankofamerica.com diff --git a/comm/third_party/botan/src/scripts/tls_scanner/policy.txt b/comm/third_party/botan/src/scripts/tls_scanner/policy.txt new file mode 100644 index 0000000000..ddd7a7c57d --- /dev/null +++ b/comm/third_party/botan/src/scripts/tls_scanner/policy.txt @@ -0,0 +1,19 @@ +allow_tls10=true +allow_tls11=true +allow_tls12=true +allow_dtls10=false +allow_dtls12=false + +# Camellia first just to see if there is anyone out there who will negotiate it with us +ciphers=Camellia-128 Camellia-256 Camellia-128/GCM Camellia-256/GCM ChaCha20Poly1305 AES-256/GCM AES-128/GCM AES-256 AES-128 +signature_hashes=SHA-384 SHA-256 SHA-1 +macs=AEAD SHA-384 SHA-256 SHA-1 +key_exchange_methods=CECPQ1 ECDH DH RSA +signature_methods=ECDSA RSA DSA IMPLICIT +ecc_curves=x25519 secp256r1 secp384r1 +minimum_dh_group_size=1024 +minimum_ecdh_group_size=255 +minimum_rsa_bits=2048 + +allow_insecure_renegotiation=false +allow_server_initiated_renegotiation=false diff --git a/comm/third_party/botan/src/scripts/tls_scanner/readme.txt b/comm/third_party/botan/src/scripts/tls_scanner/readme.txt new file mode 100644 index 0000000000..a4754b02df --- /dev/null +++ b/comm/third_party/botan/src/scripts/tls_scanner/readme.txt @@ -0,0 +1,5 @@ + +Simple script to scan hosts to check basic TLS client compatability. + +URL list chosen mostly from large tech/software vendors, feel free to +send suggestions. diff --git a/comm/third_party/botan/src/scripts/tls_scanner/tls_scanner.py b/comm/third_party/botan/src/scripts/tls_scanner/tls_scanner.py new file mode 100755 index 0000000000..8fdf046ca7 --- /dev/null +++ b/comm/third_party/botan/src/scripts/tls_scanner/tls_scanner.py @@ -0,0 +1,60 @@ +#!/usr/bin/python2 + +import sys +import time +import subprocess +import re + +def format_report(client_output): + version_re = re.compile('TLS (v1\.[0-2]) using ([A-Z0-9_]+)') + + version_match = version_re.search(client_output) + + #print client_output + + if version_match: + return "Established %s %s" % (version_match.group(1), version_match.group(2)) + else: + return client_output + +def scanner(args = None): + if args is None: + args = sys.argv + + if len(args) != 2: + print "Error: Usage tls_scanner.py host_file" + return 2 + + scanners = {} + + for url in [s.strip() for s in open(args[1]).readlines()]: + scanners[url] = subprocess.Popen(['../../../botan', 'tls_client', '--policy=policy.txt', url], + stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) + + for url in scanners.keys(): + scanners[url].stdin.close() + + report = {} + timeout = 10 + + for url in scanners.keys(): + print "waiting for", url + + for i in range(timeout): + scanners[url].poll() + if scanners[url].returncode != None: + break + #print "Waiting %d more seconds for %s" % (timeout-i, url) + time.sleep(1) + + if scanners[url].returncode != None: + output = scanners[url].stdout.read() + scanners[url].stderr.read() + report[url] = format_report(output) + + for url in report.keys(): + print url, ":", report[url] + + return 0 + +if __name__ == '__main__': + sys.exit(scanner()) diff --git a/comm/third_party/botan/src/scripts/tls_scanner/urls.txt b/comm/third_party/botan/src/scripts/tls_scanner/urls.txt new file mode 100644 index 0000000000..3be7276b32 --- /dev/null +++ b/comm/third_party/botan/src/scripts/tls_scanner/urls.txt @@ -0,0 +1,58 @@ +adobe.com +adp.com +airbnb.com +akamai.com +amazon.com +apache.org +apple.com +bbc.co.uk +bing.com +ca.com +cisco.com +citrix.com +cloudflare.com +craigslist.org +dell.com +ebay.com +facebook.com +github.com +gmail.com +google.com +hp.com +huawei.com +ibm.com +ietf.org +intuit.com +linkedin.com +medium.com +microsoft.com +mikestoolbox.org +netflix.com +openssl.org +oracle.com +chase.com +bankofamerica.com +citibank.com +wellsfargo.com +ebay.com +paypal.com +randombit.net +reddit.com +redhat.com +salesforce.com +sas.com +siemens.com +sony.com +stripe.com +symantec.com +tls.mbed.org +twitter.com +uber.com +vmware.com +whatsapp.com +wikipedia.org +www.iso.org +www.lg.com +yahoo.com +yandex.ru +youtube.com diff --git a/comm/third_party/botan/src/scripts/tls_suite_info.py b/comm/third_party/botan/src/scripts/tls_suite_info.py new file mode 100755 index 0000000000..21dcd7fcdb --- /dev/null +++ b/comm/third_party/botan/src/scripts/tls_suite_info.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python2 + +""" +Used to generate lib/tls/tls_suite_info.cpp from IANA params + +(C) 2011, 2012, 2013, 2014, 2015, 2016, 2017 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import sys +import re +import datetime +import hashlib +import optparse + +def to_ciphersuite_info(code, name): + + (sig_and_kex,cipher_and_mac) = name.split('_WITH_') + + if sig_and_kex == 'RSA': + sig_algo = 'IMPLICIT' + kex_algo = 'RSA' + elif 'PSK' in sig_and_kex: + sig_algo = 'IMPLICIT' + kex_algo = sig_and_kex + elif 'SRP' in sig_and_kex: + srp_info = sig_and_kex.split('_') + if len(srp_info) == 2: # 'SRP_' + hash + kex_algo = sig_and_kex + sig_algo = 'IMPLICIT' + else: + kex_algo = '_'.join(srp_info[0:-1]) + sig_algo = srp_info[-1] + else: + (kex_algo, sig_algo) = sig_and_kex.split('_') + + cipher_and_mac = cipher_and_mac.split('_') + + mac_algo = cipher_and_mac[-1] + + cipher = cipher_and_mac[:-1] + + if mac_algo == '8' and cipher[-1] == 'CCM': + cipher = cipher[:-1] + mac_algo = 'CCM_8' + elif cipher[-2] == 'CCM' and cipher[-1] == '8': + cipher = cipher[:-1] + mac_algo = 'CCM_8' + + if mac_algo == 'CCM': + cipher += ['CCM'] + mac_algo = 'SHA256' + elif mac_algo == 'CCM_8': + cipher += ['CCM(8)'] + mac_algo = 'SHA256' + + cipher_info = { + 'CHACHA20': ('ChaCha',32), + 'IDEA': ('IDEA',16), + 'DES': ('DES',8), + '3DES': ('3DES',24), + 'CAMELLIA': ('Camellia',None), + 'AES': ('AES',None), + 'SEED': ('SEED',16), + 'ARIA': ('ARIA',None), + } + + tls_to_botan_names = { + 'IMPLICIT': 'IMPLICIT', + + 'anon': 'ANONYMOUS', + 'MD5': 'MD5', + 'SHA': 'SHA-1', + 'SHA256': 'SHA-256', + 'SHA384': 'SHA-384', + 'SHA512': 'SHA-512', + + 'CHACHA': 'ChaCha', + '3DES': 'TripleDES', + + 'DSS': 'DSA', + 'ECDSA': 'ECDSA', + 'RSA': 'RSA', + 'SRP_SHA': 'SRP_SHA', + 'DHE': 'DH', + 'DH': 'DH', + 'ECDHE': 'ECDH', + 'ECDH': 'ECDH', + '': '', + 'PSK': 'PSK', + 'DHE_PSK': 'DHE_PSK', + 'PSK_DHE': 'DHE_PSK', + 'ECDHE_PSK': 'ECDHE_PSK', + 'CECPQ1': 'CECPQ1', + 'CECPQ1_PSK': 'CECPQ1_PSK', + } + + mac_keylen = { + 'MD5': 16, + 'SHA-1': 20, + 'SHA-256': 32, + 'SHA-384': 48, + 'SHA-512': 64, + } + + mac_algo = tls_to_botan_names[mac_algo] + sig_algo = tls_to_botan_names[sig_algo] + kex_algo = tls_to_botan_names[kex_algo] + if kex_algo == 'RSA': + kex_algo = 'STATIC_RSA' + + (cipher_algo, cipher_keylen) = cipher_info[cipher[0]] + + if cipher_keylen is None: + cipher_keylen = int(cipher[1]) / 8 + + if cipher_algo in ['AES', 'Camellia', 'ARIA']: + cipher_algo += '-%d' % (cipher_keylen*8) + + mode = '' + + if cipher[0] == 'CHACHA20' and cipher[1] == 'POLY1305': + return (name, code, sig_algo, kex_algo, "ChaCha20Poly1305", cipher_keylen, "AEAD", 0, mac_algo, 'AEAD_XOR_12') + + mode = cipher[-1] + if mode not in ['CBC', 'GCM', 'CCM(8)', 'CCM', 'OCB']: + print "#warning Unknown mode '%s' for ciphersuite %s (0x%d)" % (' '.join(cipher), name, code) + + if mode != 'CBC': + if mode == 'OCB': + cipher_algo += '/OCB(12)' + else: + cipher_algo += '/' + mode + + if mode == 'CBC': + return (name, code, sig_algo, kex_algo, cipher_algo, cipher_keylen, mac_algo, mac_keylen[mac_algo], mac_algo, 'CBC_MODE') + elif mode == 'OCB': + return (name, code, sig_algo, kex_algo, cipher_algo, cipher_keylen, "AEAD", 0, mac_algo, 'AEAD_XOR_12') + else: + return (name, code, sig_algo, kex_algo, cipher_algo, cipher_keylen, "AEAD", 0, mac_algo, 'AEAD_IMPLICIT_4') + +def open_input(args): + iana_url = 'https://www.iana.org/assignments/tls-parameters/tls-parameters.txt' + + if len(args) == 1: + try: + return open('tls-parameters.txt') + except OSError: + pass + + import urllib2 + return urllib2.urlopen(iana_url) + else: + return open(args[1]) + +""" +Handle command line options +""" +def process_command_line(args): + + parser = optparse.OptionParser() + + parser.add_option('--with-ocb', action='store_true', default=True, + help='enable OCB AEAD suites') + parser.add_option('--without-ocb', action='store_false', dest='with_ocb', + help='disable OCB AEAD suites') + + parser.add_option('--with-aria-cbc', action='store_true', default=False, + help='enable ARIA CBC suites') + parser.add_option('--without-aria-cbc', action='store_false', dest='with_aria_cbc', + help='disable ARIA CBC suites') + + parser.add_option('--with-cecpq1', action='store_true', default=True, + help='enable CECPQ1 suites') + parser.add_option('--without-cecpq1', action='store_false', dest='with_cecpq1', + help='disable CECPQ1 suites') + + parser.add_option('--with-srp-aead', action='store_true', default=False, + help='add SRP AEAD suites') + parser.add_option('--without-srp-aead', action='store_false', dest='with_srp_aead', + help='disable SRP AEAD suites') + + parser.add_option('--save-download', action='store_true', default=False, + help='save downloaded tls-parameters.txt to cwd') + + parser.add_option('--output', '-o', + help='file to write output to (default %default)', + default='src/lib/tls/tls_suite_info.cpp') + + return parser.parse_args(args) + +def main(args = None): + if args is None: + args = sys.argv + + weak_crypto = ['EXPORT', 'RC2', 'IDEA', 'RC4', '_DES_', 'WITH_NULL', 'GOST'] + static_dh = ['ECDH_ECDSA', 'ECDH_RSA', 'DH_DSS', 'DH_RSA'] # not supported + protocol_goop = ['SCSV', 'KRB5'] + maybe_someday = ['RSA_PSK', 'ECCPWD'] + not_supported = weak_crypto + static_dh + protocol_goop + maybe_someday + + (options, args) = process_command_line(args) + + if not options.with_aria_cbc: + not_supported += ['ARIA_128_CBC', 'ARIA_256_CBC'] + + ciphersuite_re = re.compile(' +0x([0-9a-fA-F][0-9a-fA-F]),0x([0-9a-fA-F][0-9a-fA-F]) + TLS_([A-Za-z_0-9]+) ') + + suites = {} + + contents = '' + + for line in open_input(args): + contents += line + match = ciphersuite_re.match(line) + if match: + code = match.group(1) + match.group(2) + name = match.group(3) + + should_use = True + for ns in not_supported: + if ns in name: + should_use = False + + if should_use and name.find('_WITH_') > 0: + suites[code] = to_ciphersuite_info(code, name) + + sha1 = hashlib.sha1() + sha1.update(contents) + contents_hash = sha1.hexdigest() + + if options.save_download: + out = open('tls-parameters.txt', 'w') + out.write(contents) + out.close() + + def define_custom_ciphersuite(name, code): + suites[code] = to_ciphersuite_info(code, name) + + if options.with_cecpq1: + # CECPQ1 key exchange + define_custom_ciphersuite('CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256', '16B7') + define_custom_ciphersuite('CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256', '16B8') + define_custom_ciphersuite('CECPQ1_RSA_WITH_AES_256_GCM_SHA384', '16B9') + define_custom_ciphersuite('CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384', '16BA') + + if options.with_ocb: + # OCB ciphersuites draft-zauner-tls-aes-ocb-04 + define_custom_ciphersuite('DHE_RSA_WITH_AES_128_OCB_SHA256', 'FFC0') + define_custom_ciphersuite('DHE_RSA_WITH_AES_256_OCB_SHA256', 'FFC1') + define_custom_ciphersuite('ECDHE_RSA_WITH_AES_128_OCB_SHA256', 'FFC2') + define_custom_ciphersuite('ECDHE_RSA_WITH_AES_256_OCB_SHA256', 'FFC3') + define_custom_ciphersuite('ECDHE_ECDSA_WITH_AES_128_OCB_SHA256', 'FFC4') + define_custom_ciphersuite('ECDHE_ECDSA_WITH_AES_256_OCB_SHA256', 'FFC5') + + define_custom_ciphersuite('PSK_WITH_AES_128_OCB_SHA256', 'FFC6') + define_custom_ciphersuite('PSK_WITH_AES_256_OCB_SHA256', 'FFC7') + define_custom_ciphersuite('DHE_PSK_WITH_AES_128_OCB_SHA256', 'FFC8') + define_custom_ciphersuite('DHE_PSK_WITH_AES_256_OCB_SHA256', 'FFC9') + define_custom_ciphersuite('ECDHE_PSK_WITH_AES_128_OCB_SHA256', 'FFCA') + define_custom_ciphersuite('ECDHE_PSK_WITH_AES_256_OCB_SHA256', 'FFCB') + + if options.with_cecpq1 and options.with_ocb: + # CECPQ1 OCB ciphersuites - Botan extension + define_custom_ciphersuite('CECPQ1_RSA_WITH_AES_256_OCB_SHA256', 'FFCC') + define_custom_ciphersuite('CECPQ1_ECDSA_WITH_AES_256_OCB_SHA256', 'FFCD') + #define_custom_ciphersuite('CECPQ1_PSK_WITH_AES_256_OCB_SHA256', 'FFCE') + + if options.with_srp_aead: + # SRP using GCM or OCB - Botan extension + define_custom_ciphersuite('SRP_SHA_WITH_AES_256_GCM_SHA384', 'FFA0') + define_custom_ciphersuite('SRP_SHA_RSA_WITH_AES_256_GCM_SHA384', 'FFA1') + define_custom_ciphersuite('SRP_SHA_DSS_WITH_AES_256_GCM_SHA384', 'FFA2') + define_custom_ciphersuite('SRP_SHA_ECDSA_WITH_AES_256_GCM_SHA384', 'FFA3') + + if options.with_ocb: + define_custom_ciphersuite('SRP_SHA_WITH_AES_256_OCB_SHA256', 'FFA4') + define_custom_ciphersuite('SRP_SHA_RSA_WITH_AES_256_OCB_SHA256', 'FFA5') + define_custom_ciphersuite('SRP_SHA_DSS_WITH_AES_256_OCB_SHA256', 'FFA6') + define_custom_ciphersuite('SRP_SHA_ECDSA_WITH_AES_256_OCB_SHA256', 'FFA7') + + suite_info = '' + + def header(): + return """/* +* TLS cipher suite information +* +* This file was automatically generated from the IANA assignments +* (tls-parameters.txt hash %s) +* by %s on %s +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +""" % (contents_hash, sys.argv[0], datetime.date.today().strftime("%Y-%m-%d")) + + suite_info += header() + + suite_info += """#include + +namespace Botan { + +namespace TLS { + +//static +const std::vector& Ciphersuite::all_known_ciphersuites() + { + // Note that this list of ciphersuites is ordered by id! + static const std::vector g_ciphersuite_list = { +""" + + for code in sorted(suites.keys()): + info = suites[code] + assert len(info) == 10 + + suite_expr = 'Ciphersuite(0x%s, "%s", Auth_Method::%s, Kex_Algo::%s, "%s", %d, "%s", %d, KDF_Algo::%s, Nonce_Format::%s)' % ( + code, info[0], info[2], info[3], info[4], info[5], info[6], info[7], info[8].replace('-','_'), info[9]) + + suite_info += " " + suite_expr + ",\n" + + suite_info += """ }; + + return g_ciphersuite_list; + } + +} + +} +""" + + if options.output == '-': + print suite_info, + else: + out = open(options.output, 'w') + out.write(suite_info) + out.close() + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/comm/third_party/botan/src/scripts/website.py b/comm/third_party/botan/src/scripts/website.py new file mode 100755 index 0000000000..e28909531f --- /dev/null +++ b/comm/third_party/botan/src/scripts/website.py @@ -0,0 +1,166 @@ +#!/usr/bin/python + +""" +Generate the Botan website + +(C) 2017 Jack Lloyd +""" + +import optparse # pylint: disable=deprecated-module +import subprocess +import sys +import errno +import shutil +import tempfile +import os + +def run_and_check(cmd_line, cwd=None): + print("Executing %s ..." % (' '.join(cmd_line))) + + proc = subprocess.Popen(cmd_line, + cwd=cwd, + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + (stdout, stderr) = proc.communicate() + + if proc.returncode != 0: + print("Error running %s" % (' '.join(cmd_line))) + print(stdout) + print(stderr) + sys.exit(1) + +def rmtree_ignore_missing(path): + try: + shutil.rmtree(path) + except OSError: + # check errno? + pass + +def configure_build(botan_dir, build_dir): + + run_and_check([os.path.join(botan_dir, 'configure.py'), + '--with-doxygen', '--with-sphinx', + '--with-build-dir=%s' % (build_dir)]) + +def run_doxygen(tmp_dir, output_dir): + run_and_check(['doxygen', os.path.join(tmp_dir, 'build/botan.doxy')]) + shutil.move(os.path.join(tmp_dir, 'build/docs/doxygen'), output_dir) + +def run_sphinx(botan_dir, tmp_dir, output_dir): + + sphinx_config = os.path.join(botan_dir, 'src/configs/sphinx') + sphinx_dir = os.path.join(tmp_dir, 'sphinx') + os.mkdir(sphinx_dir) + + shutil.copyfile(os.path.join(botan_dir, 'readme.rst'), + os.path.join(sphinx_dir, 'index.rst')) + + for f in ['news.rst', os.path.join('doc', 'security.rst')]: + shutil.copy(os.path.join(botan_dir, f), sphinx_dir) + + toc = """.. toctree:: + + index + news + security + User Guide + API Reference +""" + + contents_rst = open(os.path.join(sphinx_dir, 'contents.rst'), 'w') + contents_rst.write(toc) + contents_rst.close() + + sphinx_invoke = ['sphinx-build', '-t', 'website', '-c', sphinx_config, '-b', 'html'] + + handbook_dir = os.path.join(botan_dir, 'doc') + + run_and_check(sphinx_invoke + [sphinx_dir, output_dir]) + run_and_check(sphinx_invoke + [handbook_dir, os.path.join(output_dir, 'handbook')]) + + rmtree_ignore_missing(os.path.join(output_dir, '.doctrees')) + rmtree_ignore_missing(os.path.join(output_dir, 'handbook', '.doctrees')) + os.remove(os.path.join(output_dir, '.buildinfo')) + os.remove(os.path.join(output_dir, 'handbook', '.buildinfo')) + + # share _static subdirs + shutil.rmtree(os.path.join(output_dir, 'handbook', '_static')) + os.symlink('../_static', os.path.join(output_dir, 'handbook', '_static')) + + # Build PDF + latex_output = os.path.join(tmp_dir, 'latex') + run_and_check(['sphinx-build', '-c', sphinx_config, '-b', 'latex', handbook_dir, latex_output]) + + # Have to run twice because TeX + run_and_check(['pdflatex', 'botan.tex'], cwd=latex_output) + run_and_check(['pdflatex', 'botan.tex'], cwd=latex_output) + + shutil.copy(os.path.join(latex_output, 'botan.pdf'), + os.path.join(output_dir, 'handbook')) + + +def main(args): + parser = optparse.OptionParser() + + parser.add_option('-o', '--output-dir', default=None, + help="Where to write output") + + (options, args) = parser.parse_args(args) + + output_dir = options.output_dir + tmp_dir = tempfile.mkdtemp(prefix='botan_website_') + + # assumes we live in src/scripts + botan_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), + "..", "..")) + + if os.access(os.path.join(botan_dir, 'configure.py'), os.X_OK) is False: + print("Can't find configure.py in %s", botan_dir) + return 1 + + if output_dir is None: + cwd = os.getcwd() + + if os.path.basename(cwd) == 'botan-website': + output_dir = '.' + else: + output_dir = os.path.join(cwd, 'botan-website') + + try: + os.mkdir(output_dir) + except OSError as e: + if e.errno == errno.EEXIST: + pass + else: + raise e + + for subdir in ['_static', '_sources', 'doxygen', 'handbook']: + try: + shutil.rmtree(os.path.join(output_dir, subdir)) + except OSError as e: + if e.errno == errno.ENOENT: + pass + else: + print("Error removing dir", e) + return 1 + + configure_build(botan_dir, tmp_dir) + run_doxygen(tmp_dir, output_dir) + run_sphinx(botan_dir, tmp_dir, output_dir) + + for f in ['doc/pgpkey.txt', 'license.txt']: + shutil.copy(os.path.join(botan_dir, f), output_dir) + + favicon = open(os.path.join(output_dir, 'favicon.ico'), 'w') + # Create an empty favicon.ico file so it gets cached by browsers + favicon.close() + + shutil.rmtree(tmp_dir) + + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/comm/third_party/bzip2/CHANGES b/comm/third_party/bzip2/CHANGES new file mode 100644 index 0000000000..30afead258 --- /dev/null +++ b/comm/third_party/bzip2/CHANGES @@ -0,0 +1,356 @@ + ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.8 of 13 July 2019 + Copyright (C) 1996-2019 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ + + +0.9.0 +~~~~~ +First version. + + +0.9.0a +~~~~~~ +Removed 'ranlib' from Makefile, since most modern Unix-es +don't need it, or even know about it. + + +0.9.0b +~~~~~~ +Fixed a problem with error reporting in bzip2.c. This does not effect +the library in any way. Problem is: versions 0.9.0 and 0.9.0a (of the +program proper) compress and decompress correctly, but give misleading +error messages (internal panics) when an I/O error occurs, instead of +reporting the problem correctly. This shouldn't give any data loss +(as far as I can see), but is confusing. + +Made the inline declarations disappear for non-GCC compilers. + + +0.9.0c +~~~~~~ +Fixed some problems in the library pertaining to some boundary cases. +This makes the library behave more correctly in those situations. The +fixes apply only to features (calls and parameters) not used by +bzip2.c, so the non-fixedness of them in previous versions has no +effect on reliability of bzip2.c. + +In bzlib.c: + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. + +In compress.c: + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files. This _does_ effect + bzip2.c. + + +0.9.5a +~~~~~~ +Major change: add a fallback sorting algorithm (blocksort.c) +to give reasonable behaviour even for very repetitive inputs. +Nuked --repetitive-best and --repetitive-fast since they are +no longer useful. + +Minor changes: mostly a whole bunch of small changes/ +bugfixes in the driver (bzip2.c). Changes pertaining to the +user interface are: + + allow decompression of symlink'd files to stdout + decompress/test files even without .bz2 extension + give more accurate error messages for I/O errors + when compressing/decompressing to stdout, don't catch control-C + read flags from BZIP2 and BZIP environment variables + decline to break hard links to a file unless forced with -f + allow -c flag even with no filenames + preserve file ownerships as far as possible + make -s -1 give the expected block size (100k) + add a flag -q --quiet to suppress nonessential warnings + stop decoding flags after --, so files beginning in - can be handled + resolved inconsistent naming: bzcat or bz2cat ? + bzip2 --help now returns 0 + +Programming-level changes are: + + fixed syntax error in GET_LL4 for Borland C++ 5.02 + let bzBuffToBuffDecompress return BZ_DATA_ERROR{_MAGIC} + fix overshoot of mode-string end in bzopen_or_bzdopen + wrapped bzlib.h in #ifdef __cplusplus ... extern "C" { ... } + close file handles under all error conditions + added minor mods so it compiles with DJGPP out of the box + fixed Makefile so it doesn't give problems with BSD make + fix uninitialised memory reads in dlltest.c + +0.9.5b +~~~~~~ +Open stdin/stdout in binary mode for DJGPP. + +0.9.5c +~~~~~~ +Changed BZ_N_OVERSHOOT to be ... + 2 instead of ... + 1. The + 1 +version could cause the sorted order to be wrong in some extremely +obscure cases. Also changed setting of quadrant in blocksort.c. + +0.9.5d +~~~~~~ +The only functional change is to make bzlibVersion() in the library +return the correct string. This has no effect whatsoever on the +functioning of the bzip2 program or library. Added a couple of casts +so the library compiles without warnings at level 3 in MS Visual +Studio 6.0. Included a Y2K statement in the file Y2K_INFO. All other +changes are minor documentation changes. + +1.0 +~~~ +Several minor bugfixes and enhancements: + +* Large file support. The library uses 64-bit counters to + count the volume of data passing through it. bzip2.c + is now compiled with -D_FILE_OFFSET_BITS=64 to get large + file support from the C library. -v correctly prints out + file sizes greater than 4 gigabytes. All these changes have + been made without assuming a 64-bit platform or a C compiler + which supports 64-bit ints, so, except for the C library + aspect, they are fully portable. + +* Decompression robustness. The library/program should be + robust to any corruption of compressed data, detecting and + handling _all_ corruption, instead of merely relying on + the CRCs. What this means is that the program should + never crash, given corrupted data, and the library should + always return BZ_DATA_ERROR. + +* Fixed an obscure race-condition bug only ever observed on + Solaris, in which, if you were very unlucky and issued + control-C at exactly the wrong time, both input and output + files would be deleted. + +* Don't run out of file handles on test/decompression when + large numbers of files have invalid magic numbers. + +* Avoid library namespace pollution. Prefix all exported + symbols with BZ2_. + +* Minor sorting enhancements from my DCC2000 paper. + +* Advance the version number to 1.0, so as to counteract the + (false-in-this-case) impression some people have that programs + with version numbers less than 1.0 are in some way, experimental, + pre-release versions. + +* Create an initial Makefile-libbz2_so to build a shared library. + Yes, I know I should really use libtool et al ... + +* Make the program exit with 2 instead of 0 when decompression + fails due to a bad magic number (ie, an invalid bzip2 header). + Also exit with 1 (as the manual claims :-) whenever a diagnostic + message would have been printed AND the corresponding operation + is aborted, for example + bzip2: Output file xx already exists. + When a diagnostic message is printed but the operation is not + aborted, for example + bzip2: Can't guess original name for wurble -- using wurble.out + then the exit value 0 is returned, unless some other problem is + also detected. + + I think it corresponds more closely to what the manual claims now. + + +1.0.1 +~~~~~ +* Modified dlltest.c so it uses the new BZ2_ naming scheme. +* Modified makefile-msc to fix minor build probs on Win2k. +* Updated README.COMPILATION.PROBLEMS. + +There are no functionality changes or bug fixes relative to version +1.0.0. This is just a documentation update + a fix for minor Win32 +build problems. For almost everyone, upgrading from 1.0.0 to 1.0.1 is +utterly pointless. Don't bother. + + +1.0.2 +~~~~~ +A bug fix release, addressing various minor issues which have appeared +in the 18 or so months since 1.0.1 was released. Most of the fixes +are to do with file-handling or documentation bugs. To the best of my +knowledge, there have been no data-loss-causing bugs reported in the +compression/decompression engine of 1.0.0 or 1.0.1. + +Note that this release does not improve the rather crude build system +for Unix platforms. The general plan here is to autoconfiscate/ +libtoolise 1.0.2 soon after release, and release the result as 1.1.0 +or perhaps 1.2.0. That, however, is still just a plan at this point. + +Here are the changes in 1.0.2. Bug-reporters and/or patch-senders in +parentheses. + +* Fix an infinite segfault loop in 1.0.1 when a directory is + encountered in -f (force) mode. + (Trond Eivind Glomsrod, Nicholas Nethercote, Volker Schmidt) + +* Avoid double fclose() of output file on certain I/O error paths. + (Solar Designer) + +* Don't fail with internal error 1007 when fed a long stream (> 48MB) + of byte 251. Also print useful message suggesting that 1007s may be + caused by bad memory. + (noticed by Juan Pedro Vallejo, fixed by me) + +* Fix uninitialised variable silly bug in demo prog dlltest.c. + (Jorj Bauer) + +* Remove 512-MB limitation on recovered file size for bzip2recover + on selected platforms which support 64-bit ints. At the moment + all GCC supported platforms, and Win32. + (me, Alson van der Meulen) + +* Hard-code header byte values, to give correct operation on platforms + using EBCDIC as their native character set (IBM's OS/390). + (Leland Lucius) + +* Copy file access times correctly. + (Marty Leisner) + +* Add distclean and check targets to Makefile. + (Michael Carmack) + +* Parameterise use of ar and ranlib in Makefile. Also add $(LDFLAGS). + (Rich Ireland, Bo Thorsen) + +* Pass -p (create parent dirs as needed) to mkdir during make install. + (Jeremy Fusco) + +* Dereference symlinks when copying file permissions in -f mode. + (Volker Schmidt) + +* Majorly simplify implementation of uInt64_qrm10. + (Bo Lindbergh) + +* Check the input file still exists before deleting the output one, + when aborting in cleanUpAndFail(). + (Joerg Prante, Robert Linden, Matthias Krings) + +Also a bunch of patches courtesy of Philippe Troin, the Debian maintainer +of bzip2: + +* Wrapper scripts (with manpages): bzdiff, bzgrep, bzmore. + +* Spelling changes and minor enhancements in bzip2.1. + +* Avoid race condition between creating the output file and setting its + interim permissions safely, by using fopen_output_safely(). + No changes to bzip2recover since there is no issue with file + permissions there. + +* do not print senseless report with -v when compressing an empty + file. + +* bzcat -f works on non-bzip2 files. + +* do not try to escape shell meta-characters on unix (the shell takes + care of these). + +* added --fast and --best aliases for -1 -9 for gzip compatibility. + + +1.0.3 (15 Feb 05) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.2. + +* Further robustification against corrupted compressed data. + There are currently no known bitstreams which can cause the + decompressor to crash, loop or access memory which does not + belong to it. If you are using bzip2 or the library to + decompress bitstreams from untrusted sources, an upgrade + to 1.0.3 is recommended. This fixes CAN-2005-1260. + +* The documentation has been converted to XML, from which html + and pdf can be derived. + +* Various minor bugs in the documentation have been fixed. + +* Fixes for various compilation warnings with newer versions of + gcc, and on 64-bit platforms. + +* The BZ_NO_STDIO cpp symbol was not properly observed in 1.0.2. + This has been fixed. + + +1.0.4 (20 Dec 06) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.3. + +* Fix file permissions race problem (CAN-2005-0953). + +* Avoid possible segfault in BZ2_bzclose. From Coverity's NetBSD + scan. + +* 'const'/prototype cleanups in the C code. + +* Change default install location to /usr/local, and handle multiple + 'make install's without error. + +* Sanitise file names more carefully in bzgrep. Fixes CAN-2005-0758 + to the extent that applies to bzgrep. + +* Use 'mktemp' rather than 'tempfile' in bzdiff. + +* Tighten up a couple of assertions in blocksort.c following automated + analysis. + +* Fix minor doc/comment bugs. + + +1.0.5 (10 Dec 07) +~~~~~~~~~~~~~~~~~ +Security fix only. Fixes CERT-FI 20469 as it applies to bzip2. + + +1.0.6 (6 Sept 10) +~~~~~~~~~~~~~~~~~ + +* Security fix for CVE-2010-0405. This was reported by Mikolaj + Izdebski. + +* Make the documentation build on Ubuntu 10.04 + +1.0.7 (27 Jun 19) +~~~~~~~~~~~~~~~~~ + +* Fix undefined behavior in the macros SET_BH, CLEAR_BH, & ISSET_BH + +* bzip2: Fix return value when combining --test,-t and -q. + +* bzip2recover: Fix buffer overflow for large argv[0] + +* bzip2recover: Fix use after free issue with outFile (CVE-2016-3189) + +* Make sure nSelectors is not out of range (CVE-2019-12900) + +1.0.8 (13 Jul 19) +~~~~~~~~~~~~~~~~~ + +* Accept as many selectors as the file format allows. + This relaxes the fix for CVE-2019-12900 from 1.0.7 + so that bzip2 allows decompression of bz2 files that + use (too) many selectors again. + +* Fix handling of large (> 4GB) files on Windows. + +* Cleanup of bzdiff and bzgrep scripts so they don't use + any bash extensions and handle multiple archives correctly. + +* There is now a bz2-files testsuite at + https://sourceware.org/git/bzip2-tests.git diff --git a/comm/third_party/bzip2/Changelog.mzla b/comm/third_party/bzip2/Changelog.mzla new file mode 100644 index 0000000000..801451b924 --- /dev/null +++ b/comm/third_party/bzip2/Changelog.mzla @@ -0,0 +1,7 @@ +MZLA Technologies Changelog for bzip2 + +- 2020-Apr-15 + Based on 1.0.8 release. + Removed unneeded files. + bug #1621782 + diff --git a/comm/third_party/bzip2/LICENSE b/comm/third_party/bzip2/LICENSE new file mode 100644 index 0000000000..81a37eab7a --- /dev/null +++ b/comm/third_party/bzip2/LICENSE @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2019 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@acm.org +bzip2/libbzip2 version 1.0.8 of 13 July 2019 + +-------------------------------------------------------------------------- diff --git a/comm/third_party/bzip2/README b/comm/third_party/bzip2/README new file mode 100644 index 0000000000..b9c6099fd1 --- /dev/null +++ b/comm/third_party/bzip2/README @@ -0,0 +1,196 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.8 of 13 July 2019 +Copyright (C) 1996-2019 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (https://sourceware.org/bzip2/). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.x ? + + See the CHANGES file. + +I hope you find bzip2 useful. Feel free to contact the developers at + bzip2-devel@sourceware.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is https://sourceware.org/bzip2/ + +Julian Seward +jseward@acm.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) +10 December 2007 (bzip2, version 1.0.5) + 6 Sept 2010 (bzip2, version 1.0.6) +27 June 2019 (bzip2, version 1.0.7) +13 July 2019 (bzip2, version 1.0.8) diff --git a/comm/third_party/bzip2/README.COMPILATION.PROBLEMS b/comm/third_party/bzip2/README.COMPILATION.PROBLEMS new file mode 100644 index 0000000000..fa317a50c8 --- /dev/null +++ b/comm/third_party/bzip2/README.COMPILATION.PROBLEMS @@ -0,0 +1,58 @@ +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.8 of 13 July 2019 +Copyright (C) 1996-2019 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +bzip2 should compile without problems on the vast majority of +platforms. Using the supplied Makefile, I've built and tested it +myself for x86-linux and amd64-linux. With makefile.msc, Visual C++ +6.0 and nmake, you can build a native Win32 version too. Large file +support seems to work correctly on at least on amd64-linux. + +When I say "large file" I mean a file of size 2,147,483,648 (2^31) +bytes or above. Many older OSs can't handle files above this size, +but many newer ones can. Large files are pretty huge -- most files +you'll encounter are not Large Files. + +Early versions of bzip2 (0.1, 0.9.0, 0.9.5) compiled on a wide variety +of platforms without difficulty, and I hope this version will continue +in that tradition. However, in order to support large files, I've had +to include the define -D_FILE_OFFSET_BITS=64 in the Makefile. This +can cause problems. + +The technique of adding -D_FILE_OFFSET_BITS=64 to get large file +support is, as far as I know, the Recommended Way to get correct large +file support. For more details, see the Large File Support +Specification, published by the Large File Summit, at + + http://ftp.sas.com/standards/large.file + +As a general comment, if you get compilation errors which you think +are related to large file support, try removing the above define from +the Makefile, ie, delete the line + + BIGFILES=-D_FILE_OFFSET_BITS=64 + +from the Makefile, and do 'make clean ; make'. This will give you a +version of bzip2 without large file support, which, for most +applications, is probably not a problem. + +Alternatively, try some of the platform-specific hints listed below. + +You can use the spewG.c program to generate huge files to test bzip2's +large file support, if you are feeling paranoid. Be aware though that +any compilation problems which affect bzip2 will also affect spewG.c, +alas. + +AIX: I have reports that for large file support, you need to specify +-D_LARGE_FILES rather than -D_FILE_OFFSET_BITS=64. I have not tested +this myself. diff --git a/comm/third_party/bzip2/README.XML.STUFF b/comm/third_party/bzip2/README.XML.STUFF new file mode 100644 index 0000000000..1503476ebe --- /dev/null +++ b/comm/third_party/bzip2/README.XML.STUFF @@ -0,0 +1,45 @@ + ---------------------------------------------------------------- + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.8 of 13 July 2019 + Copyright (C) 1996-2019 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ---------------------------------------------------------------- + +The script xmlproc.sh takes an xml file as input, +and processes it to create .pdf, .html or .ps output. +It uses format.pl, a perl script to format
 blocks nicely,
+ and add CDATA tags so writers do not have to use eg. < 
+
+The file "entities.xml" must be edited to reflect current
+version, year, etc.
+
+
+Usage:
+
+  ./xmlproc.sh -v manual.xml
+  Validates an xml file to ensure no dtd-compliance errors
+
+  ./xmlproc.sh -html manual.xml
+  Output: manual.html
+
+  ./xmlproc.sh -pdf manual.xml
+  Output: manual.pdf
+
+  ./xmlproc.sh -ps manual.xml
+  Output: manual.ps
+
+
+Notum bene: 
+- pdfxmltex barfs if given a filename with an underscore in it
+
+- xmltex won't work yet - there's a bug in passivetex
+    which we are all waiting for Sebastian to fix.
+  So we are going the xml -> pdf -> ps route for the time being,
+    using pdfxmltex.
diff --git a/comm/third_party/bzip2/blocksort.c b/comm/third_party/bzip2/blocksort.c
new file mode 100644
index 0000000000..92d81fe287
--- /dev/null
+++ b/comm/third_party/bzip2/blocksort.c
@@ -0,0 +1,1094 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery                               ---*/
+/*---                                           blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting        ---*/
+/*--- algorithm, for repetitive blocks      ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static 
+__inline__
+void fallbackSimpleSort ( UInt32* fmap, 
+                          UInt32* eclass, 
+                          Int32   lo, 
+                          Int32   hi )
+{
+   Int32 i, j, tmp;
+   UInt32 ec_tmp;
+
+   if (lo == hi) return;
+
+   if (hi - lo > 3) {
+      for ( i = hi-4; i >= lo; i-- ) {
+         tmp = fmap[i];
+         ec_tmp = eclass[tmp];
+         for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+            fmap[j-4] = fmap[j];
+         fmap[j-4] = tmp;
+      }
+   }
+
+   for ( i = hi-1; i >= lo; i-- ) {
+      tmp = fmap[i];
+      ec_tmp = eclass[tmp];
+      for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+         fmap[j-1] = fmap[j];
+      fmap[j-1] = tmp;
+   }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      fswap(fmap[yyp1], fmap[yyp2]);  \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+                       stackHi[sp] = hz; \
+                       sp++; }
+
+#define fpop(lz,hz) { sp--;              \
+                      lz = stackLo[sp];  \
+                      hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE   100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap, 
+                      UInt32* eclass,
+                      Int32   loSt, 
+                      Int32   hiSt )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m;
+   Int32 sp, lo, hi;
+   UInt32 med, r, r3;
+   Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+   Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+   r = 0;
+
+   sp = 0;
+   fpush ( loSt, hiSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+      fpop ( lo, hi );
+      if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+         fallbackSimpleSort ( fmap, eclass, lo, hi );
+         continue;
+      }
+
+      /* Random partitioning.  Median of 3 sometimes fails to
+         avoid bad cases.  Median of 9 seems to help but 
+         looks rather expensive.  This too seems to work but
+         is cheaper.  Guidance for the magic constants 
+         7621 and 32768 is taken from Sedgewick's algorithms
+         book, chapter 35.
+      */
+      r = ((r * 7621) + 1) % 32768;
+      r3 = r % 3;
+      if (r3 == 0) med = eclass[fmap[lo]]; else
+      if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+                   med = eclass[fmap[hi]];
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (1) {
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unLo], fmap[ltLo]); 
+               ltLo++; unLo++; 
+               continue; 
+            };
+            if (n > 0) break;
+            unLo++;
+         }
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unHi], fmap[gtHi]); 
+               gtHi--; unHi--; 
+               continue; 
+            };
+            if (n < 0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+      if (gtHi < ltLo) continue;
+
+      n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+      m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      if (n - lo > hi - m) {
+         fpush ( lo, n );
+         fpush ( m, hi );
+      } else {
+         fpush ( m, hi );
+         fpush ( lo, n );
+      }
+   }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      eclass exists for [0 .. nblock-1]
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      All other areas of eclass destroyed
+      fmap [0 .. nblock-1] holds sorted order
+      bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define       SET_BH(zz)  bhtab[(zz) >> 5] |= ((UInt32)1 << ((zz) & 31))
+#define     CLEAR_BH(zz)  bhtab[(zz) >> 5] &= ~((UInt32)1 << ((zz) & 31))
+#define     ISSET_BH(zz)  (bhtab[(zz) >> 5] & ((UInt32)1 << ((zz) & 31)))
+#define      WORD_BH(zz)  bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz)  ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap, 
+                    UInt32* eclass, 
+                    UInt32* bhtab,
+                    Int32   nblock,
+                    Int32   verb )
+{
+   Int32 ftab[257];
+   Int32 ftabCopy[256];
+   Int32 H, i, j, k, l, r, cc, cc1;
+   Int32 nNotDone;
+   Int32 nBhtab;
+   UChar* eclass8 = (UChar*)eclass;
+
+   /*--
+      Initial 1-char radix sort to generate
+      initial fmap and initial BH bits.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        bucket sorting ...\n" );
+   for (i = 0; i < 257;    i++) ftab[i] = 0;
+   for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+   for (i = 0; i < 256;    i++) ftabCopy[i] = ftab[i];
+   for (i = 1; i < 257;    i++) ftab[i] += ftab[i-1];
+
+   for (i = 0; i < nblock; i++) {
+      j = eclass8[i];
+      k = ftab[j] - 1;
+      ftab[j] = k;
+      fmap[k] = i;
+   }
+
+   nBhtab = 2 + (nblock / 32);
+   for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+   for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+   /*--
+      Inductively refine the buckets.  Kind-of an
+      "exponential radix sort" (!), inspired by the
+      Manber-Myers suffix array construction algorithm.
+   --*/
+
+   /*-- set sentinel bits for block-end detection --*/
+   for (i = 0; i < 32; i++) { 
+      SET_BH(nblock + 2*i);
+      CLEAR_BH(nblock + 2*i + 1);
+   }
+
+   /*-- the log(N) loop --*/
+   H = 1;
+   while (1) {
+
+      if (verb >= 4) 
+         VPrintf1 ( "        depth %6d has ", H );
+
+      j = 0;
+      for (i = 0; i < nblock; i++) {
+         if (ISSET_BH(i)) j = i;
+         k = fmap[i] - H; if (k < 0) k += nblock;
+         eclass[k] = j;
+      }
+
+      nNotDone = 0;
+      r = -1;
+      while (1) {
+
+	 /*-- find the next non-singleton bucket --*/
+         k = r + 1;
+         while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (ISSET_BH(k)) {
+            while (WORD_BH(k) == 0xffffffff) k += 32;
+            while (ISSET_BH(k)) k++;
+         }
+         l = k - 1;
+         if (l >= nblock) break;
+         while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (!ISSET_BH(k)) {
+            while (WORD_BH(k) == 0x00000000) k += 32;
+            while (!ISSET_BH(k)) k++;
+         }
+         r = k - 1;
+         if (r >= nblock) break;
+
+         /*-- now [l, r] bracket current bucket --*/
+         if (r > l) {
+            nNotDone += (r - l + 1);
+            fallbackQSort3 ( fmap, eclass, l, r );
+
+            /*-- scan bucket and generate header bits-- */
+            cc = -1;
+            for (i = l; i <= r; i++) {
+               cc1 = eclass[fmap[i]];
+               if (cc != cc1) { SET_BH(i); cc = cc1; };
+            }
+         }
+      }
+
+      if (verb >= 4) 
+         VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+      H *= 2;
+      if (H > nblock || nNotDone == 0) break;
+   }
+
+   /*-- 
+      Reconstruct the original block in
+      eclass8 [0 .. nblock-1], since the
+      previous phase destroyed it.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        reconstructing block ...\n" );
+   j = 0;
+   for (i = 0; i < nblock; i++) {
+      while (ftabCopy[j] == 0) j++;
+      ftabCopy[j]--;
+      eclass8[fmap[i]] = (UChar)j;
+   }
+   AssertH ( j < 256, 1005 );
+}
+
+#undef       SET_BH
+#undef     CLEAR_BH
+#undef     ISSET_BH
+#undef      WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting       ---*/
+/*--- algorithm.  Faster for "normal"       ---*/
+/*--- non-repetitive blocks.                ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32  i1, 
+               UInt32  i2,
+               UChar*  block, 
+               UInt16* quadrant,
+               UInt32  nblock,
+               Int32*  budget )
+{
+   Int32  k;
+   UChar  c1, c2;
+   UInt16 s1, s2;
+
+   AssertD ( i1 != i2, "mainGtU" );
+   /* 1 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 2 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 3 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 4 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 5 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 6 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 7 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 8 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 9 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 10 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 11 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 12 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+
+   k = nblock + 8;
+
+   do {
+      /* 1 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 2 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 3 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 4 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 5 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 6 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 7 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 8 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+
+      if (i1 >= nblock) i1 -= nblock;
+      if (i2 >= nblock) i2 -= nblock;
+
+      k -= 8;
+      (*budget)--;
+   }
+      while (k >= 0);
+
+   return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+   Knuth's increments seem to work better
+   than Incerpi-Sedgewick here.  Possibly
+   because the number of elems to sort is
+   usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+                   9841, 29524, 88573, 265720,
+                   797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+                      UChar*  block,
+                      UInt16* quadrant,
+                      Int32   nblock,
+                      Int32   lo, 
+                      Int32   hi, 
+                      Int32   d,
+                      Int32*  budget )
+{
+   Int32 i, j, h, bigN, hp;
+   UInt32 v;
+
+   bigN = hi - lo + 1;
+   if (bigN < 2) return;
+
+   hp = 0;
+   while (incs[hp] < bigN) hp++;
+   hp--;
+
+   for (; hp >= 0; hp--) {
+      h = incs[hp];
+
+      i = lo + h;
+      while (True) {
+
+         /*-- copy 1 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 2 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 3 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         if (*budget < 0) return;
+      }
+   }
+}
+
+
+/*---------------------------------------------*/
+/*--
+   The following is an implementation of
+   an elegant 3-way quicksort for strings,
+   described in a paper "Fast Algorithms for
+   Sorting and Searching Strings", by Robert
+   Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      mswap(ptr[yyp1], ptr[yyp2]);    \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+static 
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+   UChar t;
+   if (a > b) { t = a; a = b; b = t; };
+   if (b > c) { 
+      b = c;
+      if (a > b) b = a;
+   }
+   return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+                          stackHi[sp] = hz; \
+                          stackD [sp] = dz; \
+                          sp++; }
+
+#define mpop(lz,hz,dz) { sp--;             \
+                         lz = stackLo[sp]; \
+                         hz = stackHi[sp]; \
+                         dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz)                                        \
+   { Int32 tz;                                                  \
+     tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+     tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+     tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+                  UChar*  block,
+                  UInt16* quadrant,
+                  Int32   nblock,
+                  Int32   loSt, 
+                  Int32   hiSt, 
+                  Int32   dSt,
+                  Int32*  budget )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+   Int32 sp, lo, hi, d;
+
+   Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+   Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+   Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+   Int32 nextLo[3];
+   Int32 nextHi[3];
+   Int32 nextD [3];
+
+   sp = 0;
+   mpush ( loSt, hiSt, dSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+      mpop ( lo, hi, d );
+      if (hi - lo < MAIN_QSORT_SMALL_THRESH || 
+          d > MAIN_QSORT_DEPTH_THRESH) {
+         mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+         if (*budget < 0) return;
+         continue;
+      }
+
+      med = (Int32) 
+            mmed3 ( block[ptr[ lo         ]+d],
+                    block[ptr[ hi         ]+d],
+                    block[ptr[ (lo+hi)>>1 ]+d] );
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (True) {
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unLo]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unLo], ptr[ltLo]); 
+               ltLo++; unLo++; continue; 
+            };
+            if (n >  0) break;
+            unLo++;
+         }
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unHi]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unHi], ptr[gtHi]); 
+               gtHi--; unHi--; continue; 
+            };
+            if (n <  0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+      if (gtHi < ltLo) {
+         mpush(lo, hi, d+1 );
+         continue;
+      }
+
+      n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+      m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      nextLo[0] = lo;  nextHi[0] = n;   nextD[0] = d;
+      nextLo[1] = m;   nextHi[1] = hi;  nextD[1] = d;
+      nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+      if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+      AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+      AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+      mpush (nextLo[0], nextHi[0], nextD[0]);
+      mpush (nextLo[1], nextHi[1], nextD[1]);
+      mpush (nextLo[2], nextHi[2], nextD[2]);
+   }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > N_OVERSHOOT
+      block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      All other areas of block32 destroyed
+      ftab [0 .. 65536 ] destroyed
+      ptr [0 .. nblock-1] holds sorted order
+      if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr, 
+                UChar*  block,
+                UInt16* quadrant, 
+                UInt32* ftab,
+                Int32   nblock,
+                Int32   verb,
+                Int32*  budget )
+{
+   Int32  i, j, k, ss, sb;
+   Int32  runningOrder[256];
+   Bool   bigDone[256];
+   Int32  copyStart[256];
+   Int32  copyEnd  [256];
+   UChar  c1;
+   Int32  numQSorted;
+   UInt16 s;
+   if (verb >= 4) VPrintf0 ( "        main sort initialise ...\n" );
+
+   /*-- set up the 2-byte frequency table --*/
+   for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+   j = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+      quadrant[i-1] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+      ftab[j]++;
+      quadrant[i-2] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+      ftab[j]++;
+      quadrant[i-3] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+      ftab[j]++;
+   }
+   for (; i >= 0; i--) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+   }
+
+   /*-- (emphasises close relationship of block & quadrant) --*/
+   for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+      block   [nblock+i] = block[i];
+      quadrant[nblock+i] = 0;
+   }
+
+   if (verb >= 4) VPrintf0 ( "        bucket sorting ...\n" );
+
+   /*-- Complete the initial radix sort --*/
+   for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+   s = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+      s = (s >> 8) | (block[i-1] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-1;
+      s = (s >> 8) | (block[i-2] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-2;
+      s = (s >> 8) | (block[i-3] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-3;
+   }
+   for (; i >= 0; i--) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+   }
+
+   /*--
+      Now ftab contains the first loc of every small bucket.
+      Calculate the running order, from smallest to largest
+      big bucket.
+   --*/
+   for (i = 0; i <= 255; i++) {
+      bigDone     [i] = False;
+      runningOrder[i] = i;
+   }
+
+   {
+      Int32 vv;
+      Int32 h = 1;
+      do h = 3 * h + 1; while (h <= 256);
+      do {
+         h = h / 3;
+         for (i = h; i <= 255; i++) {
+            vv = runningOrder[i];
+            j = i;
+            while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+               runningOrder[j] = runningOrder[j-h];
+               j = j - h;
+               if (j <= (h - 1)) goto zero;
+            }
+            zero:
+            runningOrder[j] = vv;
+         }
+      } while (h != 1);
+   }
+
+   /*--
+      The main sorting loop.
+   --*/
+
+   numQSorted = 0;
+
+   for (i = 0; i <= 255; i++) {
+
+      /*--
+         Process big buckets, starting with the least full.
+         Basically this is a 3-step process in which we call
+         mainQSort3 to sort the small buckets [ss, j], but
+         also make a big effort to avoid the calls if we can.
+      --*/
+      ss = runningOrder[i];
+
+      /*--
+         Step 1:
+         Complete the big bucket [ss] by quicksorting
+         any unsorted small buckets [ss, j], for j != ss.  
+         Hopefully previous pointer-scanning phases have already
+         completed many of the small buckets [ss, j], so
+         we don't have to sort them at all.
+      --*/
+      for (j = 0; j <= 255; j++) {
+         if (j != ss) {
+            sb = (ss << 8) + j;
+            if ( ! (ftab[sb] & SETMASK) ) {
+               Int32 lo = ftab[sb]   & CLEARMASK;
+               Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+               if (hi > lo) {
+                  if (verb >= 4)
+                     VPrintf4 ( "        qsort [0x%x, 0x%x]   "
+                                "done %d   this %d\n",
+                                ss, j, numQSorted, hi - lo + 1 );
+                  mainQSort3 ( 
+                     ptr, block, quadrant, nblock, 
+                     lo, hi, BZ_N_RADIX, budget 
+                  );   
+                  numQSorted += (hi - lo + 1);
+                  if (*budget < 0) return;
+               }
+            }
+            ftab[sb] |= SETMASK;
+         }
+      }
+
+      AssertH ( !bigDone[ss], 1006 );
+
+      /*--
+         Step 2:
+         Now scan this big bucket [ss] so as to synthesise the
+         sorted order for small buckets [t, ss] for all t,
+         including, magically, the bucket [ss,ss] too.
+         This will avoid doing Real Work in subsequent Step 1's.
+      --*/
+      {
+         for (j = 0; j <= 255; j++) {
+            copyStart[j] =  ftab[(j << 8) + ss]     & CLEARMASK;
+            copyEnd  [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+         }
+         for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1])
+               ptr[ copyStart[c1]++ ] = k;
+         }
+         for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1]) 
+               ptr[ copyEnd[c1]-- ] = k;
+         }
+      }
+
+      AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+                || 
+                /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+                   Necessity for this case is demonstrated by compressing 
+                   a sequence of approximately 48.5 million of character 
+                   251; 1.0.0/1.0.1 will then die here. */
+                (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+                1007 )
+
+      for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+      /*--
+         Step 3:
+         The [ss] big bucket is now done.  Record this fact,
+         and update the quadrant descriptors.  Remember to
+         update quadrants in the overshoot area too, if
+         necessary.  The "if (i < 255)" test merely skips
+         this updating for the last bucket processed, since
+         updating for the last bucket is pointless.
+
+         The quadrant array provides a way to incrementally
+         cache sort orderings, as they appear, so as to 
+         make subsequent comparisons in fullGtU() complete
+         faster.  For repetitive blocks this makes a big
+         difference (but not big enough to be able to avoid
+         the fallback sorting mechanism, exponential radix sort).
+
+         The precise meaning is: at all times:
+
+            for 0 <= i < nblock and 0 <= j <= nblock
+
+            if block[i] != block[j], 
+
+               then the relative values of quadrant[i] and 
+                    quadrant[j] are meaningless.
+
+               else {
+                  if quadrant[i] < quadrant[j]
+                     then the string starting at i lexicographically
+                     precedes the string starting at j
+
+                  else if quadrant[i] > quadrant[j]
+                     then the string starting at j lexicographically
+                     precedes the string starting at i
+
+                  else
+                     the relative ordering of the strings starting
+                     at i and j has not yet been determined.
+               }
+      --*/
+      bigDone[ss] = True;
+
+      if (i < 255) {
+         Int32 bbStart  = ftab[ss << 8] & CLEARMASK;
+         Int32 bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+         Int32 shifts   = 0;
+
+         while ((bbSize >> shifts) > 65534) shifts++;
+
+         for (j = bbSize-1; j >= 0; j--) {
+            Int32 a2update     = ptr[bbStart + j];
+            UInt16 qVal        = (UInt16)(j >> shifts);
+            quadrant[a2update] = qVal;
+            if (a2update < BZ_N_OVERSHOOT)
+               quadrant[a2update + nblock] = qVal;
+         }
+         AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+      }
+
+   }
+
+   if (verb >= 4)
+      VPrintf3 ( "        %d pointers, %d sorted, %d scanned\n",
+                 nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)arr2)  [0 .. nblock-1] holds block
+      arr1 exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)arr2) [0 .. nblock-1] holds block
+      All other areas of block destroyed
+      ftab [ 0 .. 65536 ] destroyed
+      arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+   UInt32* ptr    = s->ptr; 
+   UChar*  block  = s->block;
+   UInt32* ftab   = s->ftab;
+   Int32   nblock = s->nblock;
+   Int32   verb   = s->verbosity;
+   Int32   wfact  = s->workFactor;
+   UInt16* quadrant;
+   Int32   budget;
+   Int32   budgetInit;
+   Int32   i;
+
+   if (nblock < 10000) {
+      fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+   } else {
+      /* Calculate the location for quadrant, remembering to get
+         the alignment right.  Assumes that &(block[0]) is at least
+         2-byte aligned -- this should be ok since block is really
+         the first section of arr2.
+      */
+      i = nblock+BZ_N_OVERSHOOT;
+      if (i & 1) i++;
+      quadrant = (UInt16*)(&(block[i]));
+
+      /* (wfact-1) / 3 puts the default-factor-30
+         transition point at very roughly the same place as 
+         with v0.1 and v0.9.0.  
+         Not that it particularly matters any more, since the
+         resulting compressed stream is now the same regardless
+         of whether or not we use the main sort or fallback sort.
+      */
+      if (wfact < 1  ) wfact = 1;
+      if (wfact > 100) wfact = 100;
+      budgetInit = nblock * ((wfact-1) / 3);
+      budget = budgetInit;
+
+      mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+      if (verb >= 3) 
+         VPrintf3 ( "      %d work, %d block, ratio %5.2f\n",
+                    budgetInit - budget,
+                    nblock, 
+                    (float)(budgetInit - budget) /
+                    (float)(nblock==0 ? 1 : nblock) ); 
+      if (budget < 0) {
+         if (verb >= 2) 
+            VPrintf0 ( "    too repetitive; using fallback"
+                       " sorting algorithm\n" );
+         fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+      }
+   }
+
+   s->origPtr = -1;
+   for (i = 0; i < s->nblock; i++)
+      if (ptr[i] == 0)
+         { s->origPtr = i; break; };
+
+   AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/bzlib.c b/comm/third_party/bzip2/bzlib.c
new file mode 100644
index 0000000000..21786551b6
--- /dev/null
+++ b/comm/third_party/bzip2/bzlib.c
@@ -0,0 +1,1572 @@
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions.                          ---*/
+/*---                                               bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+/* CHANGES
+   0.9.0    -- original version.
+   0.9.0a/b -- no changes in this file.
+   0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
+     fixed bzWrite/bzRead to ignore zero-length requests.
+     fixed bzread to correctly handle read requests after EOF.
+     wrong parameter order in call to bzDecompressInit in
+     bzBuffToBuffDecompress.  Fixed.
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Compression stuff                           ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------------*/
+#ifndef BZ_NO_STDIO
+void BZ2_bz__AssertH__fail ( int errcode )
+{
+   fprintf(stderr, 
+      "\n\nbzip2/libbzip2: internal error number %d.\n"
+      "This is a bug in bzip2/libbzip2, %s.\n"
+      "Please report it to: bzip2-devel@sourceware.org.  If this happened\n"
+      "when you were using some program which uses libbzip2 as a\n"
+      "component, you should also report this bug to the author(s)\n"
+      "of that program.  Please make an effort to report this bug;\n"
+      "timely and accurate bug reports eventually lead to higher\n"
+      "quality software.  Thanks.\n\n",
+      errcode,
+      BZ2_bzlibVersion()
+   );
+
+   if (errcode == 1007) {
+   fprintf(stderr,
+      "\n*** A special note about internal error number 1007 ***\n"
+      "\n"
+      "Experience suggests that a common cause of i.e. 1007\n"
+      "is unreliable memory or other hardware.  The 1007 assertion\n"
+      "just happens to cross-check the results of huge numbers of\n"
+      "memory reads/writes, and so acts (unintendedly) as a stress\n"
+      "test of your memory system.\n"
+      "\n"
+      "I suggest the following: try compressing the file again,\n"
+      "possibly monitoring progress in detail with the -vv flag.\n"
+      "\n"
+      "* If the error cannot be reproduced, and/or happens at different\n"
+      "  points in compression, you may have a flaky memory system.\n"
+      "  Try a memory-test program.  I have used Memtest86\n"
+      "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
+      "  Memtest86 tests memory much more thorougly than your BIOSs\n"
+      "  power-on test, and may find failures that the BIOS doesn't.\n"
+      "\n"
+      "* If the error can be repeatably reproduced, this is a bug in\n"
+      "  bzip2, and I would very much like to hear about it.  Please\n"
+      "  let me know, and, ideally, save a copy of the file causing the\n"
+      "  problem -- without which I will be unable to investigate it.\n"
+      "\n"
+   );
+   }
+
+   exit(3);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+static
+int bz_config_ok ( void )
+{
+   if (sizeof(int)   != 4) return 0;
+   if (sizeof(short) != 2) return 0;
+   if (sizeof(char)  != 1) return 0;
+   return 1;
+}
+
+
+/*---------------------------------------------------*/
+static
+void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
+{
+   void* v = malloc ( items * size );
+   return v;
+}
+
+static
+void default_bzfree ( void* opaque, void* addr )
+{
+   if (addr != NULL) free ( addr );
+}
+
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block ( EState* s )
+{
+   Int32 i;
+   s->nblock = 0;
+   s->numZ = 0;
+   s->state_out_pos = 0;
+   BZ_INITIALISE_CRC ( s->blockCRC );
+   for (i = 0; i < 256; i++) s->inUse[i] = False;
+   s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+void init_RL ( EState* s )
+{
+   s->state_in_ch  = 256;
+   s->state_in_len = 0;
+}
+
+
+static
+Bool isempty_RL ( EState* s )
+{
+   if (s->state_in_ch < 256 && s->state_in_len > 0)
+      return False; else
+      return True;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressInit) 
+                    ( bz_stream* strm, 
+                     int        blockSize100k,
+                     int        verbosity,
+                     int        workFactor )
+{
+   Int32   n;
+   EState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL || 
+       blockSize100k < 1 || blockSize100k > 9 ||
+       workFactor < 0 || workFactor > 250)
+     return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(EState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm = strm;
+
+   s->arr1 = NULL;
+   s->arr2 = NULL;
+   s->ftab = NULL;
+
+   n       = 100000 * blockSize100k;
+   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
+   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
+   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
+
+   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
+      if (s->arr1 != NULL) BZFREE(s->arr1);
+      if (s->arr2 != NULL) BZFREE(s->arr2);
+      if (s->ftab != NULL) BZFREE(s->ftab);
+      if (s       != NULL) BZFREE(s);
+      return BZ_MEM_ERROR;
+   }
+
+   s->blockNo           = 0;
+   s->state             = BZ_S_INPUT;
+   s->mode              = BZ_M_RUNNING;
+   s->combinedCRC       = 0;
+   s->blockSize100k     = blockSize100k;
+   s->nblockMAX         = 100000 * blockSize100k - 19;
+   s->verbosity         = verbosity;
+   s->workFactor        = workFactor;
+
+   s->block             = (UChar*)s->arr2;
+   s->mtfv              = (UInt16*)s->arr1;
+   s->zbits             = NULL;
+   s->ptr               = (UInt32*)s->arr1;
+
+   strm->state          = s;
+   strm->total_in_lo32  = 0;
+   strm->total_in_hi32  = 0;
+   strm->total_out_lo32 = 0;
+   strm->total_out_hi32 = 0;
+   init_RL ( s );
+   prepare_new_block ( s );
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block ( EState* s )
+{
+   Int32 i;
+   UChar ch = (UChar)(s->state_in_ch);
+   for (i = 0; i < s->state_in_len; i++) {
+      BZ_UPDATE_CRC( s->blockCRC, ch );
+   }
+   s->inUse[s->state_in_ch] = True;
+   switch (s->state_in_len) {
+      case 1:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 2:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 3:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      default:
+         s->inUse[s->state_in_len-4] = True;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
+         s->nblock++;
+         break;
+   }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL ( EState* s )
+{
+   if (s->state_in_ch < 256) add_pair_to_block ( s );
+   init_RL ( s );
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
+{                                                 \
+   UInt32 zchh = (UInt32)(zchh0);                 \
+   /*-- fast track the common case --*/           \
+   if (zchh != zs->state_in_ch &&                 \
+       zs->state_in_len == 1) {                   \
+      UChar ch = (UChar)(zs->state_in_ch);        \
+      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
+      zs->inUse[zs->state_in_ch] = True;          \
+      zs->block[zs->nblock] = (UChar)ch;          \
+      zs->nblock++;                               \
+      zs->state_in_ch = zchh;                     \
+   }                                              \
+   else                                           \
+   /*-- general, uncommon cases --*/              \
+   if (zchh != zs->state_in_ch ||                 \
+      zs->state_in_len == 255) {                  \
+      if (zs->state_in_ch < 256)                  \
+         add_pair_to_block ( zs );                \
+      zs->state_in_ch = zchh;                     \
+      zs->state_in_len = 1;                       \
+   } else {                                       \
+      zs->state_in_len++;                         \
+   }                                              \
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_input_until_stop ( EState* s )
+{
+   Bool progress_in = False;
+
+   if (s->mode == BZ_M_RUNNING) {
+
+      /*-- fast track the common case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+      }
+
+   } else {
+
+      /*-- general, uncommon case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         /*-- flush/finish end? --*/
+         if (s->avail_in_expect == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+         s->avail_in_expect--;
+      }
+   }
+   return progress_in;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_output_until_stop ( EState* s )
+{
+   Bool progress_out = False;
+
+   while (True) {
+
+      /*-- no output space? --*/
+      if (s->strm->avail_out == 0) break;
+
+      /*-- block done? --*/
+      if (s->state_out_pos >= s->numZ) break;
+
+      progress_out = True;
+      *(s->strm->next_out) = s->zbits[s->state_out_pos];
+      s->state_out_pos++;
+      s->strm->avail_out--;
+      s->strm->next_out++;
+      s->strm->total_out_lo32++;
+      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+   }
+
+   return progress_out;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool handle_compress ( bz_stream* strm )
+{
+   Bool progress_in  = False;
+   Bool progress_out = False;
+   EState* s = strm->state;
+   
+   while (True) {
+
+      if (s->state == BZ_S_OUTPUT) {
+         progress_out |= copy_output_until_stop ( s );
+         if (s->state_out_pos < s->numZ) break;
+         if (s->mode == BZ_M_FINISHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+         prepare_new_block ( s );
+         s->state = BZ_S_INPUT;
+         if (s->mode == BZ_M_FLUSHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+      }
+
+      if (s->state == BZ_S_INPUT) {
+         progress_in |= copy_input_until_stop ( s );
+         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+            flush_RL ( s );
+            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->nblock >= s->nblockMAX) {
+            BZ2_compressBlock ( s, False );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->strm->avail_in == 0) {
+            break;
+         }
+      }
+
+   }
+
+   return progress_in || progress_out;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
+{
+   Bool progress;
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   preswitch:
+   switch (s->mode) {
+
+      case BZ_M_IDLE:
+         return BZ_SEQUENCE_ERROR;
+
+      case BZ_M_RUNNING:
+         if (action == BZ_RUN) {
+            progress = handle_compress ( strm );
+            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
+         } 
+         else
+	 if (action == BZ_FLUSH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FLUSHING;
+            goto preswitch;
+         }
+         else
+         if (action == BZ_FINISH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FINISHING;
+            goto preswitch;
+         }
+         else 
+            return BZ_PARAM_ERROR;
+
+      case BZ_M_FLUSHING:
+         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
+         s->mode = BZ_M_RUNNING;
+         return BZ_RUN_OK;
+
+      case BZ_M_FINISHING:
+         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (!progress) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
+         s->mode = BZ_M_IDLE;
+         return BZ_STREAM_END;
+   }
+   return BZ_OK; /*--not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
+{
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->arr1 != NULL) BZFREE(s->arr1);
+   if (s->arr2 != NULL) BZFREE(s->arr2);
+   if (s->ftab != NULL) BZFREE(s->ftab);
+   BZFREE(strm->state);
+
+   strm->state = NULL;   
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/*--- Decompression stuff                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressInit) 
+                     ( bz_stream* strm, 
+                       int        verbosity,
+                       int        small )
+{
+   DState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
+   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
+
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(DState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm                  = strm;
+   strm->state              = s;
+   s->state                 = BZ_X_MAGIC_1;
+   s->bsLive                = 0;
+   s->bsBuff                = 0;
+   s->calculatedCombinedCRC = 0;
+   strm->total_in_lo32      = 0;
+   strm->total_in_hi32      = 0;
+   strm->total_out_lo32     = 0;
+   strm->total_out_hi32     = 0;
+   s->smallDecompress       = (Bool)small;
+   s->ll4                   = NULL;
+   s->ll16                  = NULL;
+   s->tt                    = NULL;
+   s->currBlockNo           = 0;
+   s->verbosity             = verbosity;
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_FAST ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+               
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      /* restore */
+      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
+      UChar         c_state_out_ch       = s->state_out_ch;
+      Int32         c_state_out_len      = s->state_out_len;
+      Int32         c_nblock_used        = s->nblock_used;
+      Int32         c_k0                 = s->k0;
+      UInt32*       c_tt                 = s->tt;
+      UInt32        c_tPos               = s->tPos;
+      char*         cs_next_out          = s->strm->next_out;
+      unsigned int  cs_avail_out         = s->strm->avail_out;
+      Int32         ro_blockSize100k     = s->blockSize100k;
+      /* end restore */
+
+      UInt32       avail_out_INIT = cs_avail_out;
+      Int32        s_save_nblockPP = s->save_nblock+1;
+      unsigned int total_out_lo32_old;
+
+      while (True) {
+
+         /* try to finish existing run */
+         if (c_state_out_len > 0) {
+            while (True) {
+               if (cs_avail_out == 0) goto return_notr;
+               if (c_state_out_len == 1) break;
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               c_state_out_len--;
+               cs_next_out++;
+               cs_avail_out--;
+            }
+            s_state_out_len_eq_one:
+            {
+               if (cs_avail_out == 0) { 
+                  c_state_out_len = 1; goto return_notr;
+               };
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               cs_next_out++;
+               cs_avail_out--;
+            }
+         }   
+         /* Only caused by corrupt data stream? */
+         if (c_nblock_used > s_save_nblockPP)
+            return True;
+
+         /* can a new run be started? */
+         if (c_nblock_used == s_save_nblockPP) {
+            c_state_out_len = 0; goto return_notr;
+         };   
+         c_state_out_ch = c_k0;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (k1 != c_k0) { 
+            c_k0 = k1; goto s_state_out_len_eq_one; 
+         };
+         if (c_nblock_used == s_save_nblockPP) 
+            goto s_state_out_len_eq_one;
+   
+         c_state_out_len = 2;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         c_state_out_len = 3;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         c_state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST_C(c_k0); c_nblock_used++;
+      }
+
+      return_notr:
+      total_out_lo32_old = s->strm->total_out_lo32;
+      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
+      if (s->strm->total_out_lo32 < total_out_lo32_old)
+         s->strm->total_out_hi32++;
+
+      /* save */
+      s->calculatedBlockCRC = c_calculatedBlockCRC;
+      s->state_out_ch       = c_state_out_ch;
+      s->state_out_len      = c_state_out_len;
+      s->nblock_used        = c_nblock_used;
+      s->k0                 = c_k0;
+      s->tt                 = c_tt;
+      s->tPos               = c_tPos;
+      s->strm->next_out     = cs_next_out;
+      s->strm->avail_out    = cs_avail_out;
+      /* end save */
+   }
+   return False;
+}
+
+
+
+/*---------------------------------------------------*/
+__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
+{
+   Int32 nb, na, mid;
+   nb = 0;
+   na = 256;
+   do {
+      mid = (nb + na) >> 1;
+      if (indx >= cftab[mid]) nb = mid; else na = mid;
+   }
+   while (na - nb != 1);
+   return nb;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); s->nblock_used++;
+      }
+
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
+{
+   Bool    corrupt;
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   while (True) {
+      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
+      if (s->state == BZ_X_OUTPUT) {
+         if (s->smallDecompress)
+            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+            corrupt = unRLE_obuf_to_output_FAST  ( s );
+         if (corrupt) return BZ_DATA_ERROR;
+         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
+            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
+            if (s->verbosity >= 3) 
+               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
+                          s->calculatedBlockCRC );
+            if (s->verbosity >= 2) VPrintf0 ( "]" );
+            if (s->calculatedBlockCRC != s->storedBlockCRC)
+               return BZ_DATA_ERROR;
+            s->calculatedCombinedCRC 
+               = (s->calculatedCombinedCRC << 1) | 
+                    (s->calculatedCombinedCRC >> 31);
+            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
+            s->state = BZ_X_BLKHDR_1;
+         } else {
+            return BZ_OK;
+         }
+      }
+      if (s->state >= BZ_X_MAGIC_1) {
+         Int32 r = BZ2_decompress ( s );
+         if (r == BZ_STREAM_END) {
+            if (s->verbosity >= 3)
+               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
+                          s->storedCombinedCRC, s->calculatedCombinedCRC );
+            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
+               return BZ_DATA_ERROR;
+            return r;
+         }
+         if (s->state != BZ_X_OUTPUT) return r;
+      }
+   }
+
+   AssertH ( 0, 6001 );
+
+   return 0;  /*NOTREACHED*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
+{
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->tt   != NULL) BZFREE(s->tt);
+   if (s->ll16 != NULL) BZFREE(s->ll16);
+   if (s->ll4  != NULL) BZFREE(s->ll4);
+
+   BZFREE(strm->state);
+   strm->state = NULL;
+
+   return BZ_OK;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+/*--- File I/O stuff                              ---*/
+/*---------------------------------------------------*/
+
+#define BZ_SETERR(eee)                    \
+{                                         \
+   if (bzerror != NULL) *bzerror = eee;   \
+   if (bzf != NULL) bzf->lastErr = eee;   \
+}
+
+typedef 
+   struct {
+      FILE*     handle;
+      Char      buf[BZ_MAX_UNUSED];
+      Int32     bufN;
+      Bool      writing;
+      bz_stream strm;
+      Int32     lastErr;
+      Bool      initialisedOk;
+   }
+   bzFile;
+
+
+/*---------------------------------------------*/
+static Bool myfeof ( FILE* f )
+{
+   Int32 c = fgetc ( f );
+   if (c == EOF) return True;
+   ungetc ( c, f );
+   return False;
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzWriteOpen) 
+                    ( int*  bzerror,      
+                      FILE* f, 
+                      int   blockSize100k, 
+                      int   verbosity,
+                      int   workFactor )
+{
+   Int32   ret;
+   bzFile* bzf = NULL;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL ||
+       (blockSize100k < 1 || blockSize100k > 9) ||
+       (workFactor < 0 || workFactor > 250) ||
+       (verbosity < 0 || verbosity > 4))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+   bzf->initialisedOk = False;
+   bzf->bufN          = 0;
+   bzf->handle        = f;
+   bzf->writing       = True;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+
+   if (workFactor == 0) workFactor = 30;
+   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = 0;
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWrite)
+             ( int*    bzerror, 
+               BZFILE* b, 
+               void*   buf, 
+               int     len )
+{
+   Int32 n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return; };
+
+   bzf->strm.avail_in = len;
+   bzf->strm.next_in  = buf;
+
+   while (True) {
+      bzf->strm.avail_out = BZ_MAX_UNUSED;
+      bzf->strm.next_out = bzf->buf;
+      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
+      if (ret != BZ_RUN_OK)
+         { BZ_SETERR(ret); return; };
+
+      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                       n, bzf->handle );
+         if (n != n2 || ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return; };
+      }
+
+      if (bzf->strm.avail_in == 0)
+         { BZ_SETERR(BZ_OK); return; };
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWriteClose)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in,
+                    unsigned int* nbytes_out )
+{
+   BZ2_bzWriteClose64 ( bzerror, b, abandon, 
+                        nbytes_in, NULL, nbytes_out, NULL );
+}
+
+
+void BZ_API(BZ2_bzWriteClose64)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in_lo32,
+                    unsigned int* nbytes_in_hi32,
+                    unsigned int* nbytes_out_lo32,
+                    unsigned int* nbytes_out_hi32 )
+{
+   Int32   n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
+   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
+   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
+   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
+
+   if ((!abandon) && bzf->lastErr == BZ_OK) {
+      while (True) {
+         bzf->strm.avail_out = BZ_MAX_UNUSED;
+         bzf->strm.next_out = bzf->buf;
+         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
+         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
+            { BZ_SETERR(ret); return; };
+
+         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                          n, bzf->handle );
+            if (n != n2 || ferror(bzf->handle))
+               { BZ_SETERR(BZ_IO_ERROR); return; };
+         }
+
+         if (ret == BZ_STREAM_END) break;
+      }
+   }
+
+   if ( !abandon && !ferror ( bzf->handle ) ) {
+      fflush ( bzf->handle );
+      if (ferror(bzf->handle))
+         { BZ_SETERR(BZ_IO_ERROR); return; };
+   }
+
+   if (nbytes_in_lo32 != NULL)
+      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
+   if (nbytes_in_hi32 != NULL)
+      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
+   if (nbytes_out_lo32 != NULL)
+      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
+   if (nbytes_out_hi32 != NULL)
+      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
+
+   BZ_SETERR(BZ_OK);
+   BZ2_bzCompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzReadOpen) 
+                   ( int*  bzerror, 
+                     FILE* f, 
+                     int   verbosity,
+                     int   small,
+                     void* unused,
+                     int   nUnused )
+{
+   bzFile* bzf = NULL;
+   int     ret;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL || 
+       (small != 0 && small != 1) ||
+       (verbosity < 0 || verbosity > 4) ||
+       (unused == NULL && nUnused != 0) ||
+       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL) 
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+
+   bzf->initialisedOk = False;
+   bzf->handle        = f;
+   bzf->bufN          = 0;
+   bzf->writing       = False;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+   
+   while (nUnused > 0) {
+      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
+      unused = ((void*)( 1 + ((UChar*)(unused))  ));
+      nUnused--;
+   }
+
+   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = bzf->bufN;
+   bzf->strm.next_in  = bzf->buf;
+
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
+{
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+
+   if (bzf->initialisedOk)
+      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzRead) 
+           ( int*    bzerror, 
+             BZFILE* b, 
+             void*   buf, 
+             int     len )
+{
+   Int32   n, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return 0; };
+
+   bzf->strm.avail_out = len;
+   bzf->strm.next_out = buf;
+
+   while (True) {
+
+      if (ferror(bzf->handle)) 
+         { BZ_SETERR(BZ_IO_ERROR); return 0; };
+
+      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
+         n = fread ( bzf->buf, sizeof(UChar), 
+                     BZ_MAX_UNUSED, bzf->handle );
+         if (ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return 0; };
+         bzf->bufN = n;
+         bzf->strm.avail_in = bzf->bufN;
+         bzf->strm.next_in = bzf->buf;
+      }
+
+      ret = BZ2_bzDecompress ( &(bzf->strm) );
+
+      if (ret != BZ_OK && ret != BZ_STREAM_END)
+         { BZ_SETERR(ret); return 0; };
+
+      if (ret == BZ_OK && myfeof(bzf->handle) && 
+          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
+         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
+
+      if (ret == BZ_STREAM_END)
+         { BZ_SETERR(BZ_STREAM_END);
+           return len - bzf->strm.avail_out; };
+      if (bzf->strm.avail_out == 0)
+         { BZ_SETERR(BZ_OK); return len; };
+      
+   }
+
+   return 0; /*not reached*/
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadGetUnused) 
+                     ( int*    bzerror, 
+                       BZFILE* b, 
+                       void**  unused, 
+                       int*    nUnused )
+{
+   bzFile* bzf = (bzFile*)b;
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (bzf->lastErr != BZ_STREAM_END)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (unused == NULL || nUnused == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+
+   BZ_SETERR(BZ_OK);
+   *nUnused = bzf->strm.avail_in;
+   *unused = bzf->strm.next_in;
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff                      ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffCompress) 
+                         ( char*         dest, 
+                           unsigned int* destLen,
+                           char*         source, 
+                           unsigned int  sourceLen,
+                           int           blockSize100k, 
+                           int           verbosity, 
+                           int           workFactor )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       blockSize100k < 1 || blockSize100k > 9 ||
+       verbosity < 0 || verbosity > 4 ||
+       workFactor < 0 || workFactor > 250) 
+      return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzCompressInit ( &strm, blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
+   if (ret == BZ_FINISH_OK) goto output_overflow;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;   
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow:
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OUTBUFF_FULL;
+
+   errhandler:
+   BZ2_bzCompressEnd ( &strm );
+   return ret;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffDecompress) 
+                           ( char*         dest, 
+                             unsigned int* destLen,
+                             char*         source, 
+                             unsigned int  sourceLen,
+                             int           small,
+                             int           verbosity )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       (small != 0 && small != 1) ||
+       verbosity < 0 || verbosity > 4) 
+          return BZ_PARAM_ERROR;
+
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzDecompress ( &strm );
+   if (ret == BZ_OK) goto output_overflow_or_eof;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;
+   BZ2_bzDecompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow_or_eof:
+   if (strm.avail_out > 0) {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_UNEXPECTED_EOF;
+   } else {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_OUTBUFF_FULL;
+   };      
+
+   errhandler:
+   BZ2_bzDecompressEnd ( &strm );
+   return ret; 
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+/*--
+   return version like "0.9.5d, 4-Sept-1999".
+--*/
+const char * BZ_API(BZ2_bzlibVersion)(void)
+{
+   return BZ_VERSION;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#   include 
+#   include 
+#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
+#else
+#   define SET_BINARY_MODE(file)
+#endif
+static
+BZFILE * bzopen_or_bzdopen
+               ( const char *path,   /* no use when bzdopen */
+                 int fd,             /* no use when bzdopen */
+                 const char *mode,
+                 int open_mode)      /* bzopen: 0, bzdopen:1 */
+{
+   int    bzerr;
+   char   unused[BZ_MAX_UNUSED];
+   int    blockSize100k = 9;
+   int    writing       = 0;
+   char   mode2[10]     = "";
+   FILE   *fp           = NULL;
+   BZFILE *bzfp         = NULL;
+   int    verbosity     = 0;
+   int    workFactor    = 30;
+   int    smallMode     = 0;
+   int    nUnused       = 0; 
+
+   if (mode == NULL) return NULL;
+   while (*mode) {
+      switch (*mode) {
+      case 'r':
+         writing = 0; break;
+      case 'w':
+         writing = 1; break;
+      case 's':
+         smallMode = 1; break;
+      default:
+         if (isdigit((int)(*mode))) {
+            blockSize100k = *mode-BZ_HDR_0;
+         }
+      }
+      mode++;
+   }
+   strcat(mode2, writing ? "w" : "r" );
+   strcat(mode2,"b");   /* binary mode */
+
+   if (open_mode==0) {
+      if (path==NULL || strcmp(path,"")==0) {
+        fp = (writing ? stdout : stdin);
+        SET_BINARY_MODE(fp);
+      } else {
+        fp = fopen(path,mode2);
+      }
+   } else {
+#ifdef BZ_STRICT_ANSI
+      fp = NULL;
+#else
+      fp = fdopen(fd,mode2);
+#endif
+   }
+   if (fp == NULL) return NULL;
+
+   if (writing) {
+      /* Guard against total chaos and anarchy -- JRS */
+      if (blockSize100k < 1) blockSize100k = 1;
+      if (blockSize100k > 9) blockSize100k = 9; 
+      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
+                             verbosity,workFactor);
+   } else {
+      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
+                            unused,nUnused);
+   }
+   if (bzfp == NULL) {
+      if (fp != stdin && fp != stdout) fclose(fp);
+      return NULL;
+   }
+   return bzfp;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   open file for read or write.
+      ex) bzopen("file","w9")
+      case path="" or NULL => use stdin or stdout.
+--*/
+BZFILE * BZ_API(BZ2_bzopen)
+               ( const char *path,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
+}
+
+
+/*---------------------------------------------------*/
+BZFILE * BZ_API(BZ2_bzdopen)
+               ( int fd,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
+{
+   int bzerr, nread;
+   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
+   nread = BZ2_bzRead(&bzerr,b,buf,len);
+   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
+      return nread;
+   } else {
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
+{
+   int bzerr;
+
+   BZ2_bzWrite(&bzerr,b,buf,len);
+   if(bzerr == BZ_OK){
+      return len;
+   }else{
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzflush) (BZFILE *b)
+{
+   /* do nothing now... */
+   return 0;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzclose) (BZFILE* b)
+{
+   int bzerr;
+   FILE *fp;
+   
+   if (b==NULL) {return;}
+   fp = ((bzFile *)b)->handle;
+   if(((bzFile*)b)->writing){
+      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
+      if(bzerr != BZ_OK){
+         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
+      }
+   }else{
+      BZ2_bzReadClose(&bzerr,b);
+   }
+   if(fp!=stdin && fp!=stdout){
+      fclose(fp);
+   }
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   return last error code 
+--*/
+static const char *bzerrorstrings[] = {
+       "OK"
+      ,"SEQUENCE_ERROR"
+      ,"PARAM_ERROR"
+      ,"MEM_ERROR"
+      ,"DATA_ERROR"
+      ,"DATA_ERROR_MAGIC"
+      ,"IO_ERROR"
+      ,"UNEXPECTED_EOF"
+      ,"OUTBUFF_FULL"
+      ,"CONFIG_ERROR"
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+};
+
+
+const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
+{
+   int err = ((bzFile *)b)->lastErr;
+
+   if(err>0) err = 0;
+   *errnum = err;
+   return bzerrorstrings[err*-1];
+}
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/bzlib.h b/comm/third_party/bzip2/bzlib.h
new file mode 100644
index 0000000000..8966a6c580
--- /dev/null
+++ b/comm/third_party/bzip2/bzlib.h
@@ -0,0 +1,282 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library.                   ---*/
+/*---                                               bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_H
+#define _BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN               0
+#define BZ_FLUSH             1
+#define BZ_FINISH            2
+
+#define BZ_OK                0
+#define BZ_RUN_OK            1
+#define BZ_FLUSH_OK          2
+#define BZ_FINISH_OK         3
+#define BZ_STREAM_END        4
+#define BZ_SEQUENCE_ERROR    (-1)
+#define BZ_PARAM_ERROR       (-2)
+#define BZ_MEM_ERROR         (-3)
+#define BZ_DATA_ERROR        (-4)
+#define BZ_DATA_ERROR_MAGIC  (-5)
+#define BZ_IO_ERROR          (-6)
+#define BZ_UNEXPECTED_EOF    (-7)
+#define BZ_OUTBUFF_FULL      (-8)
+#define BZ_CONFIG_ERROR      (-9)
+
+typedef 
+   struct {
+      char *next_in;
+      unsigned int avail_in;
+      unsigned int total_in_lo32;
+      unsigned int total_in_hi32;
+
+      char *next_out;
+      unsigned int avail_out;
+      unsigned int total_out_lo32;
+      unsigned int total_out_hi32;
+
+      void *state;
+
+      void *(*bzalloc)(void *,int,int);
+      void (*bzfree)(void *,void *);
+      void *opaque;
+   } 
+   bz_stream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include 
+#endif
+
+#ifdef _WIN32
+#   include 
+#   ifdef small
+      /* windows.h define small to char */
+#      undef small
+#   endif
+#   ifdef BZ_EXPORT
+#   define BZ_API(func) WINAPI func
+#   define BZ_EXTERN extern
+#   else
+   /* import windows dll dynamically */
+#   define BZ_API(func) (WINAPI * func)
+#   define BZ_EXTERN
+#   endif
+#else
+#   define BZ_API(func) func
+#   define BZ_EXTERN extern
+#endif
+
+
+/*-- Core (low-level) library functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 
+      bz_stream* strm, 
+      int        blockSize100k, 
+      int        verbosity, 
+      int        workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 
+      bz_stream* strm, 
+      int action 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( 
+      bz_stream *strm, 
+      int       verbosity, 
+      int       small
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( 
+      bz_stream *strm 
+   );
+
+
+
+/*-- High(er) level library functions --*/
+
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 
+      int*  bzerror,   
+      FILE* f, 
+      int   verbosity, 
+      int   small,
+      void* unused,    
+      int   nUnused 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 
+      int*    bzerror, 
+      BZFILE* b 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void**  unused,  
+      int*    nUnused 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 
+      int*  bzerror,      
+      FILE* f, 
+      int   blockSize100k, 
+      int   verbosity, 
+      int   workFactor 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in, 
+      unsigned int* nbytes_out 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in_lo32, 
+      unsigned int* nbytes_in_hi32, 
+      unsigned int* nbytes_out_lo32, 
+      unsigned int* nbytes_out_hi32
+   );
+#endif
+
+
+/*-- Utility functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           blockSize100k, 
+      int           verbosity, 
+      int           workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           small, 
+      int           verbosity 
+   );
+
+
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+      void
+   );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+      const char *path,
+      const char *mode
+   );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+      int        fd,
+      const char *mode
+   );
+         
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+      BZFILE* b, 
+      void* buf, 
+      int len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+      BZFILE* b
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+      BZFILE* b
+   );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+      BZFILE *b, 
+      int    *errnum
+   );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/bzlib_private.h b/comm/third_party/bzip2/bzlib_private.h
new file mode 100644
index 0000000000..3755a6f701
--- /dev/null
+++ b/comm/third_party/bzip2/bzlib_private.h
@@ -0,0 +1,509 @@
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library.                  ---*/
+/*---                                       bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_PRIVATE_H
+#define _BZLIB_PRIVATE_H
+
+#include 
+
+#ifndef BZ_NO_STDIO
+#include 
+#include 
+#include 
+#endif
+
+#include "bzlib.h"
+
+
+
+/*-- General stuff. --*/
+
+#define BZ_VERSION  "1.0.8, 13-Jul-2019"
+
+typedef char            Char;
+typedef unsigned char   Bool;
+typedef unsigned char   UChar;
+typedef int             Int32;
+typedef unsigned int    UInt32;
+typedef short           Int16;
+typedef unsigned short  UInt16;
+
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+#ifndef __GNUC__
+#define __inline__  /* */
+#endif 
+
+#ifndef BZ_NO_STDIO
+
+extern void BZ2_bz__AssertH__fail ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
+
+#if BZ_DEBUG
+#define AssertD(cond,msg) \
+   { if (!(cond)) {       \
+      fprintf ( stderr,   \
+        "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
+      exit(1); \
+   }}
+#else
+#define AssertD(cond,msg) /* */
+#endif
+
+#define VPrintf0(zf) \
+   fprintf(stderr,zf)
+#define VPrintf1(zf,za1) \
+   fprintf(stderr,zf,za1)
+#define VPrintf2(zf,za1,za2) \
+   fprintf(stderr,zf,za1,za2)
+#define VPrintf3(zf,za1,za2,za3) \
+   fprintf(stderr,zf,za1,za2,za3)
+#define VPrintf4(zf,za1,za2,za3,za4) \
+   fprintf(stderr,zf,za1,za2,za3,za4)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) \
+   fprintf(stderr,zf,za1,za2,za3,za4,za5)
+
+#else
+
+extern void bz_internal_error ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) bz_internal_error ( errcode ); }
+#define AssertD(cond,msg)                do { } while (0)
+#define VPrintf0(zf)                     do { } while (0)
+#define VPrintf1(zf,za1)                 do { } while (0)
+#define VPrintf2(zf,za1,za2)             do { } while (0)
+#define VPrintf3(zf,za1,za2,za3)         do { } while (0)
+#define VPrintf4(zf,za1,za2,za3,za4)     do { } while (0)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
+
+#endif
+
+
+#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
+#define BZFREE(ppp)  (strm->bzfree)(strm->opaque,(ppp))
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42   /* 'B' */
+#define BZ_HDR_Z 0x5a   /* 'Z' */
+#define BZ_HDR_h 0x68   /* 'h' */
+#define BZ_HDR_0 0x30   /* '0' */
+  
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN    23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE   50
+#define BZ_N_ITERS  4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+
+/*-- Stuff for randomising repetitive blocks. --*/
+
+extern Int32 BZ2_rNums[512];
+
+#define BZ_RAND_DECLS                          \
+   Int32 rNToGo;                               \
+   Int32 rTPos                                 \
+
+#define BZ_RAND_INIT_MASK                      \
+   s->rNToGo = 0;                              \
+   s->rTPos  = 0                               \
+
+#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
+
+#define BZ_RAND_UPD_MASK                       \
+   if (s->rNToGo == 0) {                       \
+      s->rNToGo = BZ2_rNums[s->rTPos];         \
+      s->rTPos++;                              \
+      if (s->rTPos == 512) s->rTPos = 0;       \
+   }                                           \
+   s->rNToGo--;
+
+
+
+/*-- Stuff for doing CRCs. --*/
+
+extern UInt32 BZ2_crc32Table[256];
+
+#define BZ_INITIALISE_CRC(crcVar)              \
+{                                              \
+   crcVar = 0xffffffffL;                       \
+}
+
+#define BZ_FINALISE_CRC(crcVar)                \
+{                                              \
+   crcVar = ~(crcVar);                         \
+}
+
+#define BZ_UPDATE_CRC(crcVar,cha)              \
+{                                              \
+   crcVar = (crcVar << 8) ^                    \
+            BZ2_crc32Table[(crcVar >> 24) ^    \
+                           ((UChar)cha)];      \
+}
+
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE      1
+#define BZ_M_RUNNING   2
+#define BZ_M_FLUSHING  3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT    1
+#define BZ_S_INPUT     2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* mode this stream is in, and whether inputting */
+      /* or outputting data */
+      Int32    mode;
+      Int32    state;
+
+      /* remembers avail_in when flush/finish requested */
+      UInt32   avail_in_expect;
+
+      /* for doing the block sorting */
+      UInt32*  arr1;
+      UInt32*  arr2;
+      UInt32*  ftab;
+      Int32    origPtr;
+
+      /* aliases for arr1 and arr2 */
+      UInt32*  ptr;
+      UChar*   block;
+      UInt16*  mtfv;
+      UChar*   zbits;
+
+      /* for deciding when to use the fallback sorting algorithm */
+      Int32    workFactor;
+
+      /* run-length-encoding of the input */
+      UInt32   state_in_ch;
+      Int32    state_in_len;
+      BZ_RAND_DECLS;
+
+      /* input and output limits and current posns */
+      Int32    nblock;
+      Int32    nblockMAX;
+      Int32    numZ;
+      Int32    state_out_pos;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      UChar    unseqToSeq[256];
+
+      /* the buffer for bit stream creation */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* block and combined CRCs */
+      UInt32   blockCRC;
+      UInt32   combinedCRC;
+
+      /* misc administratium */
+      Int32    verbosity;
+      Int32    blockNo;
+      Int32    blockSize100k;
+
+      /* stuff for coding the MTF values */
+      Int32    nMTF;
+      Int32    mtfFreq    [BZ_MAX_ALPHA_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+
+      UChar    len     [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    code    [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    rfreq   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      /* second dimension: only 3 needed; 4 makes index calculations faster */
+      UInt32   len_pack[BZ_MAX_ALPHA_SIZE][4];
+
+   }
+   EState;
+
+
+
+/*-- externs for compression. --*/
+
+extern void 
+BZ2_blockSort ( EState* );
+
+extern void 
+BZ2_compressBlock ( EState*, Bool );
+
+extern void 
+BZ2_bsInitWrite ( EState* );
+
+extern void 
+BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
+
+extern void 
+BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
+
+
+
+/*-- states for decompression. --*/
+
+#define BZ_X_IDLE        1
+#define BZ_X_OUTPUT      2
+
+#define BZ_X_MAGIC_1     10
+#define BZ_X_MAGIC_2     11
+#define BZ_X_MAGIC_3     12
+#define BZ_X_MAGIC_4     13
+#define BZ_X_BLKHDR_1    14
+#define BZ_X_BLKHDR_2    15
+#define BZ_X_BLKHDR_3    16
+#define BZ_X_BLKHDR_4    17
+#define BZ_X_BLKHDR_5    18
+#define BZ_X_BLKHDR_6    19
+#define BZ_X_BCRC_1      20
+#define BZ_X_BCRC_2      21
+#define BZ_X_BCRC_3      22
+#define BZ_X_BCRC_4      23
+#define BZ_X_RANDBIT     24
+#define BZ_X_ORIGPTR_1   25
+#define BZ_X_ORIGPTR_2   26
+#define BZ_X_ORIGPTR_3   27
+#define BZ_X_MAPPING_1   28
+#define BZ_X_MAPPING_2   29
+#define BZ_X_SELECTOR_1  30
+#define BZ_X_SELECTOR_2  31
+#define BZ_X_SELECTOR_3  32
+#define BZ_X_CODING_1    33
+#define BZ_X_CODING_2    34
+#define BZ_X_CODING_3    35
+#define BZ_X_MTF_1       36
+#define BZ_X_MTF_2       37
+#define BZ_X_MTF_3       38
+#define BZ_X_MTF_4       39
+#define BZ_X_MTF_5       40
+#define BZ_X_MTF_6       41
+#define BZ_X_ENDHDR_2    42
+#define BZ_X_ENDHDR_3    43
+#define BZ_X_ENDHDR_4    44
+#define BZ_X_ENDHDR_5    45
+#define BZ_X_ENDHDR_6    46
+#define BZ_X_CCRC_1      47
+#define BZ_X_CCRC_2      48
+#define BZ_X_CCRC_3      49
+#define BZ_X_CCRC_4      50
+
+
+
+/*-- Constants for the fast MTF decoder. --*/
+
+#define MTFA_SIZE 4096
+#define MTFL_SIZE 16
+
+
+
+/*-- Structure holding all the decompression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* state indicator for this stream */
+      Int32    state;
+
+      /* for doing the final run-length decoding */
+      UChar    state_out_ch;
+      Int32    state_out_len;
+      Bool     blockRandomised;
+      BZ_RAND_DECLS;
+
+      /* the buffer for bit stream reading */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* misc administratium */
+      Int32    blockSize100k;
+      Bool     smallDecompress;
+      Int32    currBlockNo;
+      Int32    verbosity;
+
+      /* for undoing the Burrows-Wheeler transform */
+      Int32    origPtr;
+      UInt32   tPos;
+      Int32    k0;
+      Int32    unzftab[256];
+      Int32    nblock_used;
+      Int32    cftab[257];
+      Int32    cftabCopy[257];
+
+      /* for undoing the Burrows-Wheeler transform (FAST) */
+      UInt32   *tt;
+
+      /* for undoing the Burrows-Wheeler transform (SMALL) */
+      UInt16   *ll16;
+      UChar    *ll4;
+
+      /* stored and calculated CRCs */
+      UInt32   storedBlockCRC;
+      UInt32   storedCombinedCRC;
+      UInt32   calculatedBlockCRC;
+      UInt32   calculatedCombinedCRC;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      Bool     inUse16[16];
+      UChar    seqToUnseq[256];
+
+      /* for decoding the MTF values */
+      UChar    mtfa   [MTFA_SIZE];
+      Int32    mtfbase[256 / MTFL_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+      UChar    len  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+      Int32    limit  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    base   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    perm   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    minLens[BZ_N_GROUPS];
+
+      /* save area for scalars in the main decompress code */
+      Int32    save_i;
+      Int32    save_j;
+      Int32    save_t;
+      Int32    save_alphaSize;
+      Int32    save_nGroups;
+      Int32    save_nSelectors;
+      Int32    save_EOB;
+      Int32    save_groupNo;
+      Int32    save_groupPos;
+      Int32    save_nextSym;
+      Int32    save_nblockMAX;
+      Int32    save_nblock;
+      Int32    save_es;
+      Int32    save_N;
+      Int32    save_curr;
+      Int32    save_zt;
+      Int32    save_zn; 
+      Int32    save_zvec;
+      Int32    save_zj;
+      Int32    save_gSel;
+      Int32    save_gMinlen;
+      Int32*   save_gLimit;
+      Int32*   save_gBase;
+      Int32*   save_gPerm;
+
+   }
+   DState;
+
+
+
+/*-- Macros for decompression. --*/
+
+#define BZ_GET_FAST(cccc)                     \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    s->tPos = s->tt[s->tPos];                 \
+    cccc = (UChar)(s->tPos & 0xff);           \
+    s->tPos >>= 8;
+
+#define BZ_GET_FAST_C(cccc)                   \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
+    c_tPos = c_tt[c_tPos];                    \
+    cccc = (UChar)(c_tPos & 0xff);            \
+    c_tPos >>= 8;
+
+#define SET_LL4(i,n)                                          \
+   { if (((i) & 0x1) == 0)                                    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4);  \
+   }
+
+#define GET_LL4(i)                             \
+   ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
+
+#define SET_LL(i,n)                          \
+   { s->ll16[i] = (UInt16)(n & 0x0000ffff);  \
+     SET_LL4(i, n >> 16);                    \
+   }
+
+#define GET_LL(i) \
+   (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
+
+#define BZ_GET_SMALL(cccc)                            \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    cccc = BZ2_indexIntoF ( s->tPos, s->cftab );    \
+    s->tPos = GET_LL(s->tPos);
+
+
+/*-- externs for decompression. --*/
+
+extern Int32 
+BZ2_indexIntoF ( Int32, Int32* );
+
+extern Int32 
+BZ2_decompress ( DState* );
+
+extern void 
+BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
+                           Int32,  Int32, Int32 );
+
+
+#endif
+
+
+/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
+
+#ifdef BZ_NO_STDIO
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                   bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/compress.c b/comm/third_party/bzip2/compress.c
new file mode 100644
index 0000000000..5dfa00231b
--- /dev/null
+++ b/comm/third_party/bzip2/compress.c
@@ -0,0 +1,672 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting)        ---*/
+/*---                                            compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+/* CHANGES
+    0.9.0    -- original version.
+    0.9.0a/b -- no changes in this file.
+    0.9.0c   -- changed setting of nGroups in sendMTFValues() 
+                so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+   s->bsLive = 0;
+   s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+   while (s->bsLive > 0) {
+      s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+      s->numZ++;
+      s->bsBuff <<= 8;
+      s->bsLive -= 8;
+   }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz)                           \
+{                                             \
+   while (s->bsLive >= 8) {                   \
+      s->zbits[s->numZ]                       \
+         = (UChar)(s->bsBuff >> 24);          \
+      s->numZ++;                              \
+      s->bsBuff <<= 8;                        \
+      s->bsLive -= 8;                         \
+   }                                          \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+   bsNEEDW ( n );
+   s->bsBuff |= (v << (32 - s->bsLive - n));
+   s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+   bsW ( s, 8, (u >> 24) & 0xffL );
+   bsW ( s, 8, (u >> 16) & 0xffL );
+   bsW ( s, 8, (u >>  8) & 0xffL );
+   bsW ( s, 8,  u        & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+   bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->unseqToSeq[i] = s->nInUse;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+   UChar   yy[256];
+   Int32   i, j;
+   Int32   zPend;
+   Int32   wr;
+   Int32   EOB;
+
+   /* 
+      After sorting (eg, here),
+         s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+         and
+         ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] 
+         holds the original block data.
+
+      The first thing to do is generate the MTF values,
+      and put them in
+         ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+      Because there are strictly fewer or equal MTF values
+      than block values, ptr values in this area are overwritten
+      with MTF values only when they are no longer needed.
+
+      The final compressed bitstream is generated into the
+      area starting at
+         (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+      These storage aliases are set up in bzCompressInit(),
+      except for the last one, which is arranged in 
+      compressBlock().
+   */
+   UInt32* ptr   = s->ptr;
+   UChar* block  = s->block;
+   UInt16* mtfv  = s->mtfv;
+
+   makeMaps_e ( s );
+   EOB = s->nInUse+1;
+
+   for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+   wr = 0;
+   zPend = 0;
+   for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+   for (i = 0; i < s->nblock; i++) {
+      UChar ll_i;
+      AssertD ( wr <= i, "generateMTFValues(1)" );
+      j = ptr[i]-1; if (j < 0) j += s->nblock;
+      ll_i = s->unseqToSeq[block[j]];
+      AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+      if (yy[0] == ll_i) { 
+         zPend++;
+      } else {
+
+         if (zPend > 0) {
+            zPend--;
+            while (True) {
+               if (zPend & 1) {
+                  mtfv[wr] = BZ_RUNB; wr++; 
+                  s->mtfFreq[BZ_RUNB]++; 
+               } else {
+                  mtfv[wr] = BZ_RUNA; wr++; 
+                  s->mtfFreq[BZ_RUNA]++; 
+               }
+               if (zPend < 2) break;
+               zPend = (zPend - 2) / 2;
+            };
+            zPend = 0;
+         }
+         {
+            register UChar  rtmp;
+            register UChar* ryy_j;
+            register UChar  rll_i;
+            rtmp  = yy[1];
+            yy[1] = yy[0];
+            ryy_j = &(yy[1]);
+            rll_i = ll_i;
+            while ( rll_i != rtmp ) {
+               register UChar rtmp2;
+               ryy_j++;
+               rtmp2  = rtmp;
+               rtmp   = *ryy_j;
+               *ryy_j = rtmp2;
+            };
+            yy[0] = rtmp;
+            j = ryy_j - &(yy[0]);
+            mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+         }
+
+      }
+   }
+
+   if (zPend > 0) {
+      zPend--;
+      while (True) {
+         if (zPend & 1) {
+            mtfv[wr] = BZ_RUNB; wr++; 
+            s->mtfFreq[BZ_RUNB]++; 
+         } else {
+            mtfv[wr] = BZ_RUNA; wr++; 
+            s->mtfFreq[BZ_RUNA]++; 
+         }
+         if (zPend < 2) break;
+         zPend = (zPend - 2) / 2;
+      };
+      zPend = 0;
+   }
+
+   mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+   s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST  0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+   Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+   Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+   Int32 nGroups, nBytes;
+
+   /*--
+   UChar  len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   is a global since the decoder also needs it.
+
+   Int32  code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   Int32  rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   are also globals only used in this proc.
+   Made global to keep stack frame size small.
+   --*/
+
+
+   UInt16 cost[BZ_N_GROUPS];
+   Int32  fave[BZ_N_GROUPS];
+
+   UInt16* mtfv = s->mtfv;
+
+   if (s->verbosity >= 3)
+      VPrintf3( "      %d in block, %d after MTF & 1-2 coding, "
+                "%d+2 syms in use\n", 
+                s->nblock, s->nMTF, s->nInUse );
+
+   alphaSize = s->nInUse+2;
+   for (t = 0; t < BZ_N_GROUPS; t++)
+      for (v = 0; v < alphaSize; v++)
+         s->len[t][v] = BZ_GREATER_ICOST;
+
+   /*--- Decide how many coding tables to use ---*/
+   AssertH ( s->nMTF > 0, 3001 );
+   if (s->nMTF < 200)  nGroups = 2; else
+   if (s->nMTF < 600)  nGroups = 3; else
+   if (s->nMTF < 1200) nGroups = 4; else
+   if (s->nMTF < 2400) nGroups = 5; else
+                       nGroups = 6;
+
+   /*--- Generate an initial set of coding tables ---*/
+   { 
+      Int32 nPart, remF, tFreq, aFreq;
+
+      nPart = nGroups;
+      remF  = s->nMTF;
+      gs = 0;
+      while (nPart > 0) {
+         tFreq = remF / nPart;
+         ge = gs-1;
+         aFreq = 0;
+         while (aFreq < tFreq && ge < alphaSize-1) {
+            ge++;
+            aFreq += s->mtfFreq[ge];
+         }
+
+         if (ge > gs 
+             && nPart != nGroups && nPart != 1 
+             && ((nGroups-nPart) % 2 == 1)) {
+            aFreq -= s->mtfFreq[ge];
+            ge--;
+         }
+
+         if (s->verbosity >= 3)
+            VPrintf5( "      initial group %d, [%d .. %d], "
+                      "has %d syms (%4.1f%%)\n",
+                      nPart, gs, ge, aFreq, 
+                      (100.0 * (float)aFreq) / (float)(s->nMTF) );
+ 
+         for (v = 0; v < alphaSize; v++)
+            if (v >= gs && v <= ge) 
+               s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+               s->len[nPart-1][v] = BZ_GREATER_ICOST;
+ 
+         nPart--;
+         gs = ge+1;
+         remF -= aFreq;
+      }
+   }
+
+   /*--- 
+      Iterate up to BZ_N_ITERS times to improve the tables.
+   ---*/
+   for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+      for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+      for (t = 0; t < nGroups; t++)
+         for (v = 0; v < alphaSize; v++)
+            s->rfreq[t][v] = 0;
+
+      /*---
+        Set up an auxiliary length table which is used to fast-track
+	the common case (nGroups == 6). 
+      ---*/
+      if (nGroups == 6) {
+         for (v = 0; v < alphaSize; v++) {
+            s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+            s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+            s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+	 }
+      }
+
+      nSelectors = 0;
+      totc = 0;
+      gs = 0;
+      while (True) {
+
+         /*--- Set group start & end marks. --*/
+         if (gs >= s->nMTF) break;
+         ge = gs + BZ_G_SIZE - 1; 
+         if (ge >= s->nMTF) ge = s->nMTF-1;
+
+         /*-- 
+            Calculate the cost of this group as coded
+            by each of the coding tables.
+         --*/
+         for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            register UInt32 cost01, cost23, cost45;
+            register UInt16 icv;
+            cost01 = cost23 = cost45 = 0;
+
+#           define BZ_ITER(nn)                \
+               icv = mtfv[gs+(nn)];           \
+               cost01 += s->len_pack[icv][0]; \
+               cost23 += s->len_pack[icv][1]; \
+               cost45 += s->len_pack[icv][2]; \
+
+            BZ_ITER(0);  BZ_ITER(1);  BZ_ITER(2);  BZ_ITER(3);  BZ_ITER(4);
+            BZ_ITER(5);  BZ_ITER(6);  BZ_ITER(7);  BZ_ITER(8);  BZ_ITER(9);
+            BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+            BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+            BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+            BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+            BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+            BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+            BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+            BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+#           undef BZ_ITER
+
+            cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+            cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+            cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++) { 
+               UInt16 icv = mtfv[i];
+               for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+            }
+         }
+ 
+         /*-- 
+            Find the coding table which is best for this group,
+            and record its identity in the selector table.
+         --*/
+         bc = 999999999; bt = -1;
+         for (t = 0; t < nGroups; t++)
+            if (cost[t] < bc) { bc = cost[t]; bt = t; };
+         totc += bc;
+         fave[bt]++;
+         s->selector[nSelectors] = bt;
+         nSelectors++;
+
+         /*-- 
+            Increment the symbol frequencies for the selected table.
+          --*/
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+
+#           define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+            BZ_ITUR(0);  BZ_ITUR(1);  BZ_ITUR(2);  BZ_ITUR(3);  BZ_ITUR(4);
+            BZ_ITUR(5);  BZ_ITUR(6);  BZ_ITUR(7);  BZ_ITUR(8);  BZ_ITUR(9);
+            BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+            BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+            BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+            BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+            BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+            BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+            BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+            BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+#           undef BZ_ITUR
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++)
+               s->rfreq[bt][ mtfv[i] ]++;
+         }
+
+         gs = ge+1;
+      }
+      if (s->verbosity >= 3) {
+         VPrintf2 ( "      pass %d: size is %d, grp uses are ", 
+                   iter+1, totc/8 );
+         for (t = 0; t < nGroups; t++)
+            VPrintf1 ( "%d ", fave[t] );
+         VPrintf0 ( "\n" );
+      }
+
+      /*--
+        Recompute the tables based on the accumulated frequencies.
+      --*/
+      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
+         comment in huffman.c for details. */
+      for (t = 0; t < nGroups; t++)
+         BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
+                                 alphaSize, 17 /*20*/ );
+   }
+
+
+   AssertH( nGroups < 8, 3002 );
+   AssertH( nSelectors < 32768 &&
+            nSelectors <= BZ_MAX_SELECTORS,
+            3003 );
+
+
+   /*--- Compute MTF values for the selectors. ---*/
+   {
+      UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+      for (i = 0; i < nGroups; i++) pos[i] = i;
+      for (i = 0; i < nSelectors; i++) {
+         ll_i = s->selector[i];
+         j = 0;
+         tmp = pos[j];
+         while ( ll_i != tmp ) {
+            j++;
+            tmp2 = tmp;
+            tmp = pos[j];
+            pos[j] = tmp2;
+         };
+         pos[0] = tmp;
+         s->selectorMtf[i] = j;
+      }
+   };
+
+   /*--- Assign actual codes for the tables. --*/
+   for (t = 0; t < nGroups; t++) {
+      minLen = 32;
+      maxLen = 0;
+      for (i = 0; i < alphaSize; i++) {
+         if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+         if (s->len[t][i] < minLen) minLen = s->len[t][i];
+      }
+      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+      AssertH ( !(minLen < 1),  3005 );
+      BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
+                          minLen, maxLen, alphaSize );
+   }
+
+   /*--- Transmit the mapping table. ---*/
+   { 
+      Bool inUse16[16];
+      for (i = 0; i < 16; i++) {
+          inUse16[i] = False;
+          for (j = 0; j < 16; j++)
+             if (s->inUse[i * 16 + j]) inUse16[i] = True;
+      }
+     
+      nBytes = s->numZ;
+      for (i = 0; i < 16; i++)
+         if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+      for (i = 0; i < 16; i++)
+         if (inUse16[i])
+            for (j = 0; j < 16; j++) {
+               if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+            }
+
+      if (s->verbosity >= 3) 
+         VPrintf1( "      bytes: mapping %d, ", s->numZ-nBytes );
+   }
+
+   /*--- Now the selectors. ---*/
+   nBytes = s->numZ;
+   bsW ( s, 3, nGroups );
+   bsW ( s, 15, nSelectors );
+   for (i = 0; i < nSelectors; i++) { 
+      for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+      bsW(s,1,0);
+   }
+   if (s->verbosity >= 3)
+      VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+   /*--- Now the coding tables. ---*/
+   nBytes = s->numZ;
+
+   for (t = 0; t < nGroups; t++) {
+      Int32 curr = s->len[t][0];
+      bsW ( s, 5, curr );
+      for (i = 0; i < alphaSize; i++) {
+         while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+         while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+         bsW ( s, 1, 0 );
+      }
+   }
+
+   if (s->verbosity >= 3)
+      VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+   /*--- And finally, the block data proper ---*/
+   nBytes = s->numZ;
+   selCtr = 0;
+   gs = 0;
+   while (True) {
+      if (gs >= s->nMTF) break;
+      ge = gs + BZ_G_SIZE - 1; 
+      if (ge >= s->nMTF) ge = s->nMTF-1;
+      AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+      if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            UInt16 mtfv_i;
+            UChar* s_len_sel_selCtr 
+               = &(s->len[s->selector[selCtr]][0]);
+            Int32* s_code_sel_selCtr
+               = &(s->code[s->selector[selCtr]][0]);
+
+#           define BZ_ITAH(nn)                      \
+               mtfv_i = mtfv[gs+(nn)];              \
+               bsW ( s,                             \
+                     s_len_sel_selCtr[mtfv_i],      \
+                     s_code_sel_selCtr[mtfv_i] )
+
+            BZ_ITAH(0);  BZ_ITAH(1);  BZ_ITAH(2);  BZ_ITAH(3);  BZ_ITAH(4);
+            BZ_ITAH(5);  BZ_ITAH(6);  BZ_ITAH(7);  BZ_ITAH(8);  BZ_ITAH(9);
+            BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+            BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+            BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+            BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+            BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+            BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+            BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+            BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+#           undef BZ_ITAH
+
+      } else {
+	 /*--- slow version which correctly handles all situations ---*/
+         for (i = gs; i <= ge; i++) {
+            bsW ( s, 
+                  s->len  [s->selector[selCtr]] [mtfv[i]],
+                  s->code [s->selector[selCtr]] [mtfv[i]] );
+         }
+      }
+
+
+      gs = ge+1;
+      selCtr++;
+   }
+   AssertH( selCtr == nSelectors, 3007 );
+
+   if (s->verbosity >= 3)
+      VPrintf1( "codes %d\n", s->numZ-nBytes );
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+   if (s->nblock > 0) {
+
+      BZ_FINALISE_CRC ( s->blockCRC );
+      s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+      s->combinedCRC ^= s->blockCRC;
+      if (s->blockNo > 1) s->numZ = 0;
+
+      if (s->verbosity >= 2)
+         VPrintf4( "    block %d: crc = 0x%08x, "
+                   "combined CRC = 0x%08x, size = %d\n",
+                   s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+      BZ2_blockSort ( s );
+   }
+
+   s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+   /*-- If this is the first block, create the stream header. --*/
+   if (s->blockNo == 1) {
+      BZ2_bsInitWrite ( s );
+      bsPutUChar ( s, BZ_HDR_B );
+      bsPutUChar ( s, BZ_HDR_Z );
+      bsPutUChar ( s, BZ_HDR_h );
+      bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+   }
+
+   if (s->nblock > 0) {
+
+      bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+      bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+      bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+      /*-- Now the block's CRC, so it is in a known place. --*/
+      bsPutUInt32 ( s, s->blockCRC );
+
+      /*-- 
+         Now a single bit indicating (non-)randomisation. 
+         As of version 0.9.5, we use a better sorting algorithm
+         which makes randomisation unnecessary.  So always set
+         the randomised bit to 'no'.  Of course, the decoder
+         still needs to be able to handle randomised blocks
+         so as to maintain backwards compatibility with
+         older versions of bzip2.
+      --*/
+      bsW(s,1,0);
+
+      bsW ( s, 24, s->origPtr );
+      generateMTFValues ( s );
+      sendMTFValues ( s );
+   }
+
+
+   /*-- If this is the last block, add the stream trailer. --*/
+   if (is_last_block) {
+
+      bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+      bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+      bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+      bsPutUInt32 ( s, s->combinedCRC );
+      if (s->verbosity >= 2)
+         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
+      bsFinishWrite ( s );
+   }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/crctable.c b/comm/third_party/bzip2/crctable.c
new file mode 100644
index 0000000000..2b33c25353
--- /dev/null
+++ b/comm/third_party/bzip2/crctable.c
@@ -0,0 +1,104 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for doing CRCs                                  ---*/
+/*---                                            crctable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*--
+  I think this is an implementation of the AUTODIN-II,
+  Ethernet & FDDI 32-bit CRC standard.  Vaguely derived
+  from code by Rob Warnock, in Section 51 of the
+  comp.compression FAQ.
+--*/
+
+UInt32 BZ2_crc32Table[256] = {
+
+   /*-- Ugly, innit? --*/
+
+   0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+   0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+   0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+   0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+   0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+   0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+   0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+   0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+   0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+   0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+   0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+   0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+   0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+   0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+   0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+   0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+   0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+   0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+   0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+   0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+   0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+   0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+   0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+   0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+   0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+   0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+   0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+   0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+   0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+   0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+   0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+   0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+   0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+   0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+   0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+   0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+   0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+   0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+   0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+   0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+   0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+   0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+   0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+   0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+   0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+   0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+   0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+   0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+   0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+   0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+   0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+   0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+   0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+   0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+   0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+   0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+   0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+   0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+   0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+   0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+   0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+   0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+   0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+   0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        crctable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/decompress.c b/comm/third_party/bzip2/decompress.c
new file mode 100644
index 0000000000..a1a0bac892
--- /dev/null
+++ b/comm/third_party/bzip2/decompress.c
@@ -0,0 +1,652 @@
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery                               ---*/
+/*---                                          decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->seqToUnseq[s->nInUse] = i;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr)                               \
+   { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn)                     \
+   case lll: s->state = lll;                      \
+   while (True) {                                 \
+      if (s->bsLive >= nnn) {                     \
+         UInt32 v;                                \
+         v = (s->bsBuff >>                        \
+             (s->bsLive-nnn)) & ((1 << nnn)-1);   \
+         s->bsLive -= nnn;                        \
+         vvv = v;                                 \
+         break;                                   \
+      }                                           \
+      if (s->strm->avail_in == 0) RETURN(BZ_OK);  \
+      s->bsBuff                                   \
+         = (s->bsBuff << 8) |                     \
+           ((UInt32)                              \
+              (*((UChar*)(s->strm->next_in))));   \
+      s->bsLive += 8;                             \
+      s->strm->next_in++;                         \
+      s->strm->avail_in--;                        \
+      s->strm->total_in_lo32++;                   \
+      if (s->strm->total_in_lo32 == 0)            \
+         s->strm->total_in_hi32++;                \
+   }
+
+#define GET_UCHAR(lll,uuu)                        \
+   GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu)                          \
+   GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval)           \
+{                                                 \
+   if (groupPos == 0) {                           \
+      groupNo++;                                  \
+      if (groupNo >= nSelectors)                  \
+         RETURN(BZ_DATA_ERROR);                   \
+      groupPos = BZ_G_SIZE;                       \
+      gSel = s->selector[groupNo];                \
+      gMinlen = s->minLens[gSel];                 \
+      gLimit = &(s->limit[gSel][0]);              \
+      gPerm = &(s->perm[gSel][0]);                \
+      gBase = &(s->base[gSel][0]);                \
+   }                                              \
+   groupPos--;                                    \
+   zn = gMinlen;                                  \
+   GET_BITS(label1, zvec, zn);                    \
+   while (1) {                                    \
+      if (zn > 20 /* the longest code */)         \
+         RETURN(BZ_DATA_ERROR);                   \
+      if (zvec <= gLimit[zn]) break;              \
+      zn++;                                       \
+      GET_BIT(label2, zj);                        \
+      zvec = (zvec << 1) | zj;                    \
+   };                                             \
+   if (zvec - gBase[zn] < 0                       \
+       || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)  \
+      RETURN(BZ_DATA_ERROR);                      \
+   lval = gPerm[zvec - gBase[zn]];                \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+   UChar      uc;
+   Int32      retVal;
+   Int32      minLen, maxLen;
+   bz_stream* strm = s->strm;
+
+   /* stuff that needs to be saved/restored */
+   Int32  i;
+   Int32  j;
+   Int32  t;
+   Int32  alphaSize;
+   Int32  nGroups;
+   Int32  nSelectors;
+   Int32  EOB;
+   Int32  groupNo;
+   Int32  groupPos;
+   Int32  nextSym;
+   Int32  nblockMAX;
+   Int32  nblock;
+   Int32  es;
+   Int32  N;
+   Int32  curr;
+   Int32  zt;
+   Int32  zn; 
+   Int32  zvec;
+   Int32  zj;
+   Int32  gSel;
+   Int32  gMinlen;
+   Int32* gLimit;
+   Int32* gBase;
+   Int32* gPerm;
+
+   if (s->state == BZ_X_MAGIC_1) {
+      /*initialise the save area*/
+      s->save_i           = 0;
+      s->save_j           = 0;
+      s->save_t           = 0;
+      s->save_alphaSize   = 0;
+      s->save_nGroups     = 0;
+      s->save_nSelectors  = 0;
+      s->save_EOB         = 0;
+      s->save_groupNo     = 0;
+      s->save_groupPos    = 0;
+      s->save_nextSym     = 0;
+      s->save_nblockMAX   = 0;
+      s->save_nblock      = 0;
+      s->save_es          = 0;
+      s->save_N           = 0;
+      s->save_curr        = 0;
+      s->save_zt          = 0;
+      s->save_zn          = 0;
+      s->save_zvec        = 0;
+      s->save_zj          = 0;
+      s->save_gSel        = 0;
+      s->save_gMinlen     = 0;
+      s->save_gLimit      = NULL;
+      s->save_gBase       = NULL;
+      s->save_gPerm       = NULL;
+   }
+
+   /*restore from the save area*/
+   i           = s->save_i;
+   j           = s->save_j;
+   t           = s->save_t;
+   alphaSize   = s->save_alphaSize;
+   nGroups     = s->save_nGroups;
+   nSelectors  = s->save_nSelectors;
+   EOB         = s->save_EOB;
+   groupNo     = s->save_groupNo;
+   groupPos    = s->save_groupPos;
+   nextSym     = s->save_nextSym;
+   nblockMAX   = s->save_nblockMAX;
+   nblock      = s->save_nblock;
+   es          = s->save_es;
+   N           = s->save_N;
+   curr        = s->save_curr;
+   zt          = s->save_zt;
+   zn          = s->save_zn; 
+   zvec        = s->save_zvec;
+   zj          = s->save_zj;
+   gSel        = s->save_gSel;
+   gMinlen     = s->save_gMinlen;
+   gLimit      = s->save_gLimit;
+   gBase       = s->save_gBase;
+   gPerm       = s->save_gPerm;
+
+   retVal = BZ_OK;
+
+   switch (s->state) {
+
+      GET_UCHAR(BZ_X_MAGIC_1, uc);
+      if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_2, uc);
+      if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_3, uc)
+      if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+      if (s->blockSize100k < (BZ_HDR_0 + 1) || 
+          s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
+      s->blockSize100k -= BZ_HDR_0;
+
+      if (s->smallDecompress) {
+         s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+         s->ll4  = BZALLOC( 
+                      ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) 
+                   );
+         if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+      } else {
+         s->tt  = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+         if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+      }
+
+      GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+      if (uc == 0x17) goto endhdr_2;
+      if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_2, uc);
+      if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_3, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_4, uc);
+      if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_5, uc);
+      if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_6, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+      s->currBlockNo++;
+      if (s->verbosity >= 2)
+         VPrintf1 ( "\n    [%d: huff+mtf ", s->currBlockNo );
+ 
+      s->storedBlockCRC = 0;
+      GET_UCHAR(BZ_X_BCRC_1, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_2, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_3, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_4, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+      GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+      s->origPtr = 0;
+      GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+      if (s->origPtr < 0)
+         RETURN(BZ_DATA_ERROR);
+      if (s->origPtr > 10 + 100000*s->blockSize100k) 
+         RETURN(BZ_DATA_ERROR);
+
+      /*--- Receive the mapping table ---*/
+      for (i = 0; i < 16; i++) {
+         GET_BIT(BZ_X_MAPPING_1, uc);
+         if (uc == 1) 
+            s->inUse16[i] = True; else 
+            s->inUse16[i] = False;
+      }
+
+      for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+      for (i = 0; i < 16; i++)
+         if (s->inUse16[i])
+            for (j = 0; j < 16; j++) {
+               GET_BIT(BZ_X_MAPPING_2, uc);
+               if (uc == 1) s->inUse[i * 16 + j] = True;
+            }
+      makeMaps_d ( s );
+      if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+      alphaSize = s->nInUse+2;
+
+      /*--- Now the selectors ---*/
+      GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+      if (nGroups < 2 || nGroups > BZ_N_GROUPS) RETURN(BZ_DATA_ERROR);
+      GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+      if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+      for (i = 0; i < nSelectors; i++) {
+         j = 0;
+         while (True) {
+            GET_BIT(BZ_X_SELECTOR_3, uc);
+            if (uc == 0) break;
+            j++;
+            if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+         }
+         /* Having more than BZ_MAX_SELECTORS doesn't make much sense
+            since they will never be used, but some implementations might
+            "round up" the number of selectors, so just ignore those. */
+         if (i < BZ_MAX_SELECTORS)
+           s->selectorMtf[i] = j;
+      }
+      if (nSelectors > BZ_MAX_SELECTORS)
+        nSelectors = BZ_MAX_SELECTORS;
+
+      /*--- Undo the MTF values for the selectors. ---*/
+      {
+         UChar pos[BZ_N_GROUPS], tmp, v;
+         for (v = 0; v < nGroups; v++) pos[v] = v;
+   
+         for (i = 0; i < nSelectors; i++) {
+            v = s->selectorMtf[i];
+            tmp = pos[v];
+            while (v > 0) { pos[v] = pos[v-1]; v--; }
+            pos[0] = tmp;
+            s->selector[i] = tmp;
+         }
+      }
+
+      /*--- Now the coding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         GET_BITS(BZ_X_CODING_1, curr, 5);
+         for (i = 0; i < alphaSize; i++) {
+            while (True) {
+               if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+               GET_BIT(BZ_X_CODING_2, uc);
+               if (uc == 0) break;
+               GET_BIT(BZ_X_CODING_3, uc);
+               if (uc == 0) curr++; else curr--;
+            }
+            s->len[t][i] = curr;
+         }
+      }
+
+      /*--- Create the Huffman decoding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         minLen = 32;
+         maxLen = 0;
+         for (i = 0; i < alphaSize; i++) {
+            if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+            if (s->len[t][i] < minLen) minLen = s->len[t][i];
+         }
+         BZ2_hbCreateDecodeTables ( 
+            &(s->limit[t][0]), 
+            &(s->base[t][0]), 
+            &(s->perm[t][0]), 
+            &(s->len[t][0]),
+            minLen, maxLen, alphaSize
+         );
+         s->minLens[t] = minLen;
+      }
+
+      /*--- Now the MTF values ---*/
+
+      EOB      = s->nInUse+1;
+      nblockMAX = 100000 * s->blockSize100k;
+      groupNo  = -1;
+      groupPos = 0;
+
+      for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+      /*-- MTF init --*/
+      {
+         Int32 ii, jj, kk;
+         kk = MTFA_SIZE-1;
+         for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+            for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+               s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+               kk--;
+            }
+            s->mtfbase[ii] = kk + 1;
+         }
+      }
+      /*-- end MTF init --*/
+
+      nblock = 0;
+      GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+      while (True) {
+
+         if (nextSym == EOB) break;
+
+         if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+            es = -1;
+            N = 1;
+            do {
+               /* Check that N doesn't get too big, so that es doesn't
+                  go negative.  The maximum value that can be
+                  RUNA/RUNB encoded is equal to the block size (post
+                  the initial RLE), viz, 900k, so bounding N at 2
+                  million should guard against overflow without
+                  rejecting any legitimate inputs. */
+               if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
+               if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+               if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+               N = N * 2;
+               GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+            }
+               while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+            es++;
+            uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+            s->unzftab[uc] += es;
+
+            if (s->smallDecompress)
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->ll16[nblock] = (UInt16)uc;
+                  nblock++;
+                  es--;
+               }
+            else
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->tt[nblock] = (UInt32)uc;
+                  nblock++;
+                  es--;
+               };
+
+            continue;
+
+         } else {
+
+            if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+            /*-- uc = MTF ( nextSym-1 ) --*/
+            {
+               Int32 ii, jj, kk, pp, lno, off;
+               UInt32 nn;
+               nn = (UInt32)(nextSym - 1);
+
+               if (nn < MTFL_SIZE) {
+                  /* avoid general-case expense */
+                  pp = s->mtfbase[0];
+                  uc = s->mtfa[pp+nn];
+                  while (nn > 3) {
+                     Int32 z = pp+nn;
+                     s->mtfa[(z)  ] = s->mtfa[(z)-1];
+                     s->mtfa[(z)-1] = s->mtfa[(z)-2];
+                     s->mtfa[(z)-2] = s->mtfa[(z)-3];
+                     s->mtfa[(z)-3] = s->mtfa[(z)-4];
+                     nn -= 4;
+                  }
+                  while (nn > 0) { 
+                     s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; 
+                  };
+                  s->mtfa[pp] = uc;
+               } else { 
+                  /* general case */
+                  lno = nn / MTFL_SIZE;
+                  off = nn % MTFL_SIZE;
+                  pp = s->mtfbase[lno] + off;
+                  uc = s->mtfa[pp];
+                  while (pp > s->mtfbase[lno]) { 
+                     s->mtfa[pp] = s->mtfa[pp-1]; pp--; 
+                  };
+                  s->mtfbase[lno]++;
+                  while (lno > 0) {
+                     s->mtfbase[lno]--;
+                     s->mtfa[s->mtfbase[lno]] 
+                        = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+                     lno--;
+                  }
+                  s->mtfbase[0]--;
+                  s->mtfa[s->mtfbase[0]] = uc;
+                  if (s->mtfbase[0] == 0) {
+                     kk = MTFA_SIZE-1;
+                     for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+                        for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+                           s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+                           kk--;
+                        }
+                        s->mtfbase[ii] = kk + 1;
+                     }
+                  }
+               }
+            }
+            /*-- end uc = MTF ( nextSym-1 ) --*/
+
+            s->unzftab[s->seqToUnseq[uc]]++;
+            if (s->smallDecompress)
+               s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+               s->tt[nblock]   = (UInt32)(s->seqToUnseq[uc]);
+            nblock++;
+
+            GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+            continue;
+         }
+      }
+
+      /* Now we know what nblock is, we can do a better sanity
+         check on s->origPtr.
+      */
+      if (s->origPtr < 0 || s->origPtr >= nblock)
+         RETURN(BZ_DATA_ERROR);
+
+      /*-- Set up cftab to facilitate generation of T^(-1) --*/
+      /* Check: unzftab entries in range. */
+      for (i = 0; i <= 255; i++) {
+         if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
+            RETURN(BZ_DATA_ERROR);
+      }
+      /* Actually generate cftab. */
+      s->cftab[0] = 0;
+      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+      /* Check: cftab entries in range. */
+      for (i = 0; i <= 256; i++) {
+         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+            /* s->cftab[i] can legitimately be == nblock */
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+      /* Check: cftab entries non-descending. */
+      for (i = 1; i <= 256; i++) {
+         if (s->cftab[i-1] > s->cftab[i]) {
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+
+      s->state_out_len = 0;
+      s->state_out_ch  = 0;
+      BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+      s->state = BZ_X_OUTPUT;
+      if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+      if (s->smallDecompress) {
+
+         /*-- Make a copy of cftab, used in generation of T --*/
+         for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+         /*-- compute the T vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->ll16[i]);
+            SET_LL(i, s->cftabCopy[uc]);
+            s->cftabCopy[uc]++;
+         }
+
+         /*-- Compute T^(-1) by pointer reversal on T --*/
+         i = s->origPtr;
+         j = GET_LL(i);
+         do {
+            Int32 tmp = GET_LL(j);
+            SET_LL(j, i);
+            i = j;
+            j = tmp;
+         }
+            while (i != s->origPtr);
+
+         s->tPos = s->origPtr;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+         }
+
+      } else {
+
+         /*-- compute the T^(-1) vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->tt[i] & 0xff);
+            s->tt[s->cftab[uc]] |= (i << 8);
+            s->cftab[uc]++;
+         }
+
+         s->tPos = s->tt[s->origPtr] >> 8;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+         }
+
+      }
+
+      RETURN(BZ_OK);
+
+
+
+    endhdr_2:
+
+      GET_UCHAR(BZ_X_ENDHDR_2, uc);
+      if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_3, uc);
+      if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_4, uc);
+      if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_5, uc);
+      if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_6, uc);
+      if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+      s->storedCombinedCRC = 0;
+      GET_UCHAR(BZ_X_CCRC_1, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_2, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_3, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_4, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+      s->state = BZ_X_IDLE;
+      RETURN(BZ_STREAM_END);
+
+      default: AssertH ( False, 4001 );
+   }
+
+   AssertH ( False, 4002 );
+
+   save_state_and_return:
+
+   s->save_i           = i;
+   s->save_j           = j;
+   s->save_t           = t;
+   s->save_alphaSize   = alphaSize;
+   s->save_nGroups     = nGroups;
+   s->save_nSelectors  = nSelectors;
+   s->save_EOB         = EOB;
+   s->save_groupNo     = groupNo;
+   s->save_groupPos    = groupPos;
+   s->save_nextSym     = nextSym;
+   s->save_nblockMAX   = nblockMAX;
+   s->save_nblock      = nblock;
+   s->save_es          = es;
+   s->save_N           = N;
+   s->save_curr        = curr;
+   s->save_zt          = zt;
+   s->save_zn          = zn;
+   s->save_zvec        = zvec;
+   s->save_zj          = zj;
+   s->save_gSel        = gSel;
+   s->save_gMinlen     = gMinlen;
+   s->save_gLimit      = gLimit;
+   s->save_gBase       = gBase;
+   s->save_gPerm       = gPerm;
+
+   return retVal;   
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                      decompress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/huffman.c b/comm/third_party/bzip2/huffman.c
new file mode 100644
index 0000000000..43a1899e46
--- /dev/null
+++ b/comm/third_party/bzip2/huffman.c
@@ -0,0 +1,205 @@
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff                        ---*/
+/*---                                             huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0)  ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1)   ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2)                           \
+   (WEIGHTOF(zw1)+WEIGHTOF(zw2)) |                    \
+   (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z)                                     \
+{                                                     \
+   Int32 zz, tmp;                                     \
+   zz = z; tmp = heap[zz];                            \
+   while (weight[tmp] < weight[heap[zz >> 1]]) {      \
+      heap[zz] = heap[zz >> 1];                       \
+      zz >>= 1;                                       \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+#define DOWNHEAP(z)                                   \
+{                                                     \
+   Int32 zz, yy, tmp;                                 \
+   zz = z; tmp = heap[zz];                            \
+   while (True) {                                     \
+      yy = zz << 1;                                   \
+      if (yy > nHeap) break;                          \
+      if (yy < nHeap &&                               \
+          weight[heap[yy+1]] < weight[heap[yy]])      \
+         yy++;                                        \
+      if (weight[tmp] < weight[heap[yy]]) break;      \
+      heap[zz] = heap[yy];                            \
+      zz = yy;                                        \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbMakeCodeLengths ( UChar *len, 
+                             Int32 *freq,
+                             Int32 alphaSize,
+                             Int32 maxLen )
+{
+   /*--
+      Nodes and heap entries run from 1.  Entry 0
+      for both the heap and nodes is a sentinel.
+   --*/
+   Int32 nNodes, nHeap, n1, n2, i, j, k;
+   Bool  tooLong;
+
+   Int32 heap   [ BZ_MAX_ALPHA_SIZE + 2 ];
+   Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
+   Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; 
+
+   for (i = 0; i < alphaSize; i++)
+      weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+   while (True) {
+
+      nNodes = alphaSize;
+      nHeap = 0;
+
+      heap[0] = 0;
+      weight[0] = 0;
+      parent[0] = -2;
+
+      for (i = 1; i <= alphaSize; i++) {
+         parent[i] = -1;
+         nHeap++;
+         heap[nHeap] = i;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
+   
+      while (nHeap > 1) {
+         n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         nNodes++;
+         parent[n1] = parent[n2] = nNodes;
+         weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+         parent[nNodes] = -1;
+         nHeap++;
+         heap[nHeap] = nNodes;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
+
+      tooLong = False;
+      for (i = 1; i <= alphaSize; i++) {
+         j = 0;
+         k = i;
+         while (parent[k] >= 0) { k = parent[k]; j++; }
+         len[i-1] = j;
+         if (j > maxLen) tooLong = True;
+      }
+      
+      if (! tooLong) break;
+
+      /* 17 Oct 04: keep-going condition for the following loop used
+         to be 'i < alphaSize', which missed the last element,
+         theoretically leading to the possibility of the compressor
+         looping.  However, this count-scaling step is only needed if
+         one of the generated Huffman code words is longer than
+         maxLen, which up to and including version 1.0.2 was 20 bits,
+         which is extremely unlikely.  In version 1.0.3 maxLen was
+         changed to 17 bits, which has minimal effect on compression
+         ratio, but does mean this scaling step is used from time to
+         time, enough to verify that it works.
+
+         This means that bzip2-1.0.3 and later will only produce
+         Huffman codes with a maximum length of 17 bits.  However, in
+         order to preserve backwards compatibility with bitstreams
+         produced by versions pre-1.0.3, the decompressor must still
+         handle lengths of up to 20. */
+
+      for (i = 1; i <= alphaSize; i++) {
+         j = weight[i] >> 8;
+         j = 1 + (j / 2);
+         weight[i] = j << 8;
+      }
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbAssignCodes ( Int32 *code,
+                         UChar *length,
+                         Int32 minLen,
+                         Int32 maxLen,
+                         Int32 alphaSize )
+{
+   Int32 n, vec, i;
+
+   vec = 0;
+   for (n = minLen; n <= maxLen; n++) {
+      for (i = 0; i < alphaSize; i++)
+         if (length[i] == n) { code[i] = vec; vec++; };
+      vec <<= 1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbCreateDecodeTables ( Int32 *limit,
+                                Int32 *base,
+                                Int32 *perm,
+                                UChar *length,
+                                Int32 minLen,
+                                Int32 maxLen,
+                                Int32 alphaSize )
+{
+   Int32 pp, i, j, vec;
+
+   pp = 0;
+   for (i = minLen; i <= maxLen; i++)
+      for (j = 0; j < alphaSize; j++)
+         if (length[j] == i) { perm[pp] = j; pp++; };
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
+   for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+   for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
+   vec = 0;
+
+   for (i = minLen; i <= maxLen; i++) {
+      vec += (base[i+1] - base[i]);
+      limit[i] = vec-1;
+      vec <<= 1;
+   }
+   for (i = minLen + 1; i <= maxLen; i++)
+      base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                         huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/bzip2/moz.build b/comm/third_party/bzip2/moz.build
new file mode 100644
index 0000000000..be51400f7d
--- /dev/null
+++ b/comm/third_party/bzip2/moz.build
@@ -0,0 +1,28 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Library("bz2")
+FINAL_LIBRARY = "rnp"
+
+# Honor --with-system-bz2
+if CONFIG["MZLA_SYSTEM_BZIP2"]:
+    OS_LIBS += CONFIG["MZLA_BZIP2_LIBS"]
+else:
+    include("../rnpdefs.mozbuild")
+
+    COMPILE_FLAGS["WARNINGS_CFLAGS"] += [
+        "-Wno-unreachable-code-return",
+    ]
+
+    SOURCES += [
+        "blocksort.c",
+        "bzlib.c",
+        "compress.c",
+        "crctable.c",
+        "decompress.c",
+        "huffman.c",
+        "randtable.c",
+    ]
diff --git a/comm/third_party/bzip2/randtable.c b/comm/third_party/bzip2/randtable.c
new file mode 100644
index 0000000000..bdc6d4a4cc
--- /dev/null
+++ b/comm/third_party/bzip2/randtable.c
@@ -0,0 +1,84 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for randomising repetitive blocks               ---*/
+/*---                                           randtable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.8 of 13 July 2019
+   Copyright (C) 1996-2019 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------*/
+Int32 BZ2_rNums[512] = { 
+   619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 
+   985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 
+   733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 
+   419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 
+   878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 
+   862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 
+   150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 
+   170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 
+   73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 
+   909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 
+   641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 
+   161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 
+   382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 
+   98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 
+   227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 
+   469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 
+   184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 
+   715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 
+   951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 
+   652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 
+   645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 
+   609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 
+   653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 
+   411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 
+   170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 
+   857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 
+   669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 
+   944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 
+   344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 
+   897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 
+   433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 
+   686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 
+   946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 
+   978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 
+   680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 
+   707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 
+   297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 
+   134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 
+   343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 
+   140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 
+   170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 
+   369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 
+   804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 
+   896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 
+   661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 
+   768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 
+   61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 
+   372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 
+   780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 
+   920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 
+   645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 
+   936, 638
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       randtable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/comm/third_party/clang/aarch64-apple-darwin.cfg b/comm/third_party/clang/aarch64-apple-darwin.cfg
new file mode 100644
index 0000000000..0f790452bb
--- /dev/null
+++ b/comm/third_party/clang/aarch64-apple-darwin.cfg
@@ -0,0 +1 @@
+-target aarch64-apple-darwin
diff --git a/comm/third_party/clang/aarch64-linux-gnu.cfg b/comm/third_party/clang/aarch64-linux-gnu.cfg
new file mode 100644
index 0000000000..273a435cb6
--- /dev/null
+++ b/comm/third_party/clang/aarch64-linux-gnu.cfg
@@ -0,0 +1 @@
+-target aarch64-linux-gnu
diff --git a/comm/third_party/clang/i686-linux-gnu.cfg b/comm/third_party/clang/i686-linux-gnu.cfg
new file mode 100644
index 0000000000..07fdd21051
--- /dev/null
+++ b/comm/third_party/clang/i686-linux-gnu.cfg
@@ -0,0 +1,6 @@
+-target i686-linux-gnu
+-m32
+-march=pentium-m
+-msse
+-msse2
+-mfpmath=sse
diff --git a/comm/third_party/clang/x86_64-apple-darwin.cfg b/comm/third_party/clang/x86_64-apple-darwin.cfg
new file mode 100644
index 0000000000..a4a7299dd8
--- /dev/null
+++ b/comm/third_party/clang/x86_64-apple-darwin.cfg
@@ -0,0 +1 @@
+-target x86_64-apple-darwin
diff --git a/comm/third_party/json-c/AUTHORS b/comm/third_party/json-c/AUTHORS
new file mode 100644
index 0000000000..b36fa9b347
--- /dev/null
+++ b/comm/third_party/json-c/AUTHORS
@@ -0,0 +1,61 @@
+Alan Coopersmith 
+Alexander Dahl 
+Alexandru Ardelean 
+andy5995 
+Aram Poghosyan 
+Björn Esser 
+BonsaY 
+changyong guo 
+chenguoping 
+Chris Lamb 
+Christopher Head 
+Chris Wolfe 
+C. Watford (christopher.watford@gmail.com)
+Darjan Krijan 
+David McCann 
+DeX77 
+dota17 
+Eric Haszlakiewicz 
+Eric Hawicz 
+Even Rouault 
+Gianluigi Tiesi 
+grdowns 
+Hex052 
+hofnarr 
+ihsinme <61293369+ihsinme@users.noreply.github.com>
+Ivan Romanov 
+Jaap Keuter 
+Jakov Smolic 
+janczer 
+Jehan 
+Jehiah Czebotar 
+Jonathan Wiens 
+Jose Bollo 
+José Bollo 
+Juuso Alasuutari 
+Keith Holman 
+Kizuna-Meraki 
+Leon Gross 
+Liang, Gao 
+Marc <34656315+MarcT512@users.noreply.github.com>
+max 
+Micah Snyder 
+Michael Clark 
+myd7349 
+Pascal Cuoq 
+Pawday 
+Philosoph228 
+Pierce Lopez 
+Po-Chuan Hsieh 
+Ramiro Polla 
+Rikard Falkeborn 
+Robert Bielik 
+Robert 
+Rosen Penev 
+Rubasri Kalidas 
+Simon McVittie 
+ssrlive <30760636+ssrlive@users.noreply.github.com>
+Tobias Nießen 
+Tobias Stoeckmann 
+Tudor Brindus 
+Unmanned Player <36690541+unmanned-player@users.noreply.github.com>
diff --git a/comm/third_party/json-c/COPYING b/comm/third_party/json-c/COPYING
new file mode 100644
index 0000000000..740d1258d4
--- /dev/null
+++ b/comm/third_party/json-c/COPYING
@@ -0,0 +1,42 @@
+
+Copyright (c) 2009-2012 Eric Haszlakiewicz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----------------------------------------------------------------
+
+Copyright (c) 2004, 2005 Metaparadigm Pte Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/comm/third_party/json-c/ChangeLog b/comm/third_party/json-c/ChangeLog
new file mode 100644
index 0000000000..b03a77710e
--- /dev/null
+++ b/comm/third_party/json-c/ChangeLog
@@ -0,0 +1,583 @@
+
+0.16 (up to commit 66dcdf5, 2022-04-13)
+========================================
+
+Deprecated and removed features:
+--------------------------------
+* JSON_C_OBJECT_KEY_IS_CONSTANT is deprecated in favor of
+  JSON_C_OBJECT_ADD_CONSTANT_KEY
+* Direct access to lh_table and lh_entry structure members is deprecated.  
+  Use access functions instead, lh_table_head(), lh_entry_next(), etc...
+* Drop REFCOUNT_DEBUG code.
+
+New features
+------------
+* The 0.16 release introduces no new features
+
+Build changes
+-------------
+* Add a DISABLE_EXTRA_LIBS option to skip using libbsd
+* Add a DISABLE_JSON_POINTER option to skip compiling in json_pointer support.
+
+Significant changes and bug fixes
+---------------------------------
+* Cap string length at INT_MAX to avoid various issues with very long strings.
+* json_object_deep_copy: fix deep copy of strings containing '\0'
+* Fix read past end of buffer in the "json_parse" command
+* Avoid out of memory accesses in the locally provided vasprintf() function
+  (for those platforms that use it)
+* Handle allocation failure in json_tokener_new_ex
+* Fix use-after-free in json_tokener_new_ex() in the event of printbuf_new() returning NULL
+* printbuf_memset(): set gaps to zero - areas within the print buffer which
+  have not been initialized by using printbuf_memset
+* printbuf: return -1 on invalid arguments (len < 0 or total buffer > INT_MAX)
+* sprintbuf(): propagate printbuf_memappend errors back to the caller
+
+Optimizations
+--------------
+* Speed up parsing by replacing ctype functions with simplified, faster 
+  non-locale-sensitive ones in json_tokener and json_object_to_json_string.
+* Neither vertical tab nor formfeed are considered whitespace per the JSON spec
+* json_object: speed up creation of objects, calloc() -> malloc() + set fields
+* Avoid needless extra strlen() call in json_c_shallow_copy_default() and
+  json_object_equal() when the object is known to be a json_type_string.
+
+Other changes
+-------------
+* Validate size arguments in arraylist functions.
+* Use getrandom() if available; with GRND_NONBLOCK to allow use of json-c
+  very early during boot, such as part of cryptsetup.
+* Use arc4random() if it's available.
+* random_seed: on error, continue to next method instead of exiting the process
+* Close file when unable to read from /dev/urandom in get_dev_random_seed()
+
+***
+
+0.15 (up to commit 870965e, 2020/07/26)
+========================================
+
+Deprecated and removed features:
+--------------------------------
+* Deprecate `array_list_new()` in favor of `array_list_new2()`
+* Remove the THIS_FUNCTION_IS_DEPRECATED define.
+* Remove config.h.win32
+
+New features
+------------
+* Add a `JSON_TOKENER_ALLOW_TRAILING_CHARS` flag to allow multiple objects
+  to be parsed even when `JSON_TOKENER_STRICT` is set.
+* Add `json_object_new_array_ext(int)` and `array_list_new_2(int)` to allow
+   arrays to be allocated with the exact size needed, when known.
+* Add `json_object_array_shrink()` (and `array_list_shrink()`) and use it in 
+   json_tokener to minimize the amount of memory used.
+* Add a json_parse binary, for use in testing changes (not installed, but 
+   available in the apps directory).
+
+Build changes
+-------------
+* #639/#621 - Add symbol versions to all exported symbols
+* #508/#634 - Always enable -fPIC to allow use of the json-c static library in
+   other libraries
+* Build both static and shared libraries at the same time.
+* #626 - Restore compatibility with cmake 2.8 
+* #471 - Always create directories with mode 0755, regardless of umask.
+* #606/#604 - Improve support for OSes like AIX and IBM i, as well as for
+   MINGW32 and old versions of MSVC
+* #451/#617 - Add a DISABLE_THREAD_LOCAL_STORAGE cmake option to disable 
+   the use of thread-local storage.
+
+Significant changes and bug fixes
+---------------------------------
+* Split the internal json_object structure into several sub-types, one for
+   each json_type (json_object_object, json_object_string, etc...).
+  This improves memory usage and speed, with the benchmark under
+   bench/ report 5.8% faster test time and 6%(max RSS)-12%(peak heap)
+   less memory usage.
+  Memory used just for json_object structures decreased 27%, so use cases
+   with fewer arrays and/or strings would benefit more.
+* Minimize memory usage in array handling in json_tokener by shrinking
+   arrays to the exact number of elements parsed.  On bench/ benchmark:
+   9% faster test time, 39%(max RSS)-50%(peak heap) less memory usage.
+   Add json_object_array_shrink() and array_list_shrink() functions.
+* #616 - Parsing of surrogate pairs in unicode escapes now properly handles
+   incremental parsing.
+* Fix incremental parsing of numbers, especially those with exponents, e.g.
+   so parsing "[0", "e+", "-]" now properly returns an error.
+  Strict mode now rejects missing exponents ("0e").
+* Successfully return number objects at the top level even when they are
+   followed by a "-", "." or "e".  This makes parsing things like "123-45"
+   behave consistently with things like "123xyz".
+
+Other changes
+-------------
+* #589 - Detect broken RDRAND during initialization; also, fix segfault
+    in the CPUID check.
+* #592 - Fix integer overflows to prevert out of bounds write on large input.
+* Protect against division by zero in linkhash, when created with zero size.
+* #602 - Fix json_parse_uint64() internal error checking, leaving the retval
+    untouched in more failure cases.
+* #614 - Prevent truncation when custom double formatters insert extra \0's
+
+
+***
+
+0.14 (up to commit 9ed00a6, 2020/04/14)
+=========================================
+
+Deprecated and removed features:
+--------------------------------
+* bits.h has been removed
+* lh_abort() has been removed
+* lh_table_lookup() has been removed, use lh_table_lookup_ex() instead.
+* Remove TRUE and FALSE defines, use 1 and 0 instead.
+
+Build changes:
+--------------
+## Deprecated and removed features:
+* bits.h has been removed
+* lh_abort() has been removed
+* lh_table_lookup() has been removed, use lh_table_lookup_ex() instead.
+* Remove TRUE and FALSE defines, use 1 and 0 instead.
+* autoconf support, including autogen.sh, has been removed.  See details about cmake, below.
+* With the addition of json_tokener_get_parse_end(), access to internal fields of json_tokener, as well as use of many other symbols and types in json_tokener.h, is deprecated now.
+* The use of Android.configure.mk to build for Android no longer works, and it is unknown how (or if) the new cmake-based build machinery can be used.
+    * Reports of success, or pull requests to correct issues are welcome.
+
+## Notable improvements and new features
+
+### Builds and documentation
+* Build machinery has been switched to CMake.  See README.md for details about how to build.
+    * TL;DR: `mkdir build ; cd build ; cmake -DCMAKE_INSTALL_PREFIX=/some/path ../json-c ; make all test install`
+    * To ease the transition, there is a `cmake-configure` wrapper that emulates the old autoconf-based configure script.
+    * This has enabled improvements to the build on Windows system; also all public functions have been fixed to be properly exported.  For best results, use Visual Studio 2015 or newer.
+* The json-c style guide has been updated to specify the use of clang-format, and all code has been reformatted.
+    * Since many lines of code have trivial changes now, when using git blame, be sure to specify -w
+* Numerous improvements have been made to the documentation including function effects on refcounts, when passing a NULL is safe, and so on.
+
+### json_tokener changes
+* Added a json_tokener_get_parse_end() function to replace direct access of tok->char_offset.
+    * The char_offset field, and the rest of the json_tokener structure remain exposed for now, but expect a future release to hide it like is done with json_object_private.h
+* json_tokener_parse_ex() now accepts a new JSON_TOKENER_VALIDATE_UTF8 flag to validate that input is UTF8.
+    * If validation fails, json_tokener_get_error(tok) will return json_tokener_error_parse_utf8_string (see enum json_tokener_error).
+
+### Other changes and additions
+* Add support for unsigned 64-bit integers, uint64_t, to gain one extra bit of magnitude for positive ints.
+    * json_tokener will now parse values up to UINT64_MAX (18446744073709551615)
+    * Existing methods returning int32_t or int64_t will cap out-of-range values at INT32_MAX or INT64_MAX, preserving existing behavior.
+    * The implementation includes the possibility of easily extending this to larger sizes in the future.
+* A total of 7 new functions were added:
+    * json_object_get_uint64 ( struct json_object const* jso )
+    * json_object_new_uint64 ( uint64_t i )
+    * json_object_set_uint64 ( struct json_object* jso, uint64_t new_value )
+    * json_parse_uint64 ( char const* buf, uint64_t* retval )
+        * See description of uint64 support, above.
+    * json_tokener_get_parse_end ( struct json_tokener* tok )
+        * See details under "json_tokener changes", above.
+    * json_object_from_fd_ex ( int fd, int in_depth )
+        * Allows the max nesting depth to be specified.
+    * json_object_new_null ( )
+        * Simply returns NULL.  Its use is not recommended.
+* The size of struct json_object has decreased from 96 bytes to 88 bytes.
+
+### Testing
+* Many updates were made to test cases, increasing code coverage.
+* There is now a quick way (JSONC_TEST_TRACE=1) to turn on shell tracing in tests.
+* To run tests, use `make test`; the old "check" target no longer exists.
+
+## Significant bug fixes
+For the full list of issues and pull requests since the previous release, please see issues_closed_for_0.14.md
+
+* [Issue #389](https://github.com/json-c/json-c/issues/389): Add an assert to explicitly crash when _ref_count is corrupted, instead of a later "double free" error.
+* [Issue #407](https://github.com/json-c/json-c/issues/407): fix incorrect casts in calls to ctype functions (isdigit and isspace) so we don't crash when asserts are enabled on certain platforms and characters > 128 are parsed.
+* [Issue #418](https://github.com/json-c/json-c/issues/418): Fix docs for json_util_from_fd and json_util_from_file to say that they return NULL on failures.
+* [Issue #422](https://github.com/json-c/json-c/issues/422): json_object.c:set errno in json_object_get_double() when called on a json_type_string object with bad content.
+* [Issue #453](https://github.com/json-c/json-c/issues/453): Fixed misalignment in JSON serialization when JSON_C_TO_STRING_SPACED and JSON_C_TO_STRING_PRETTY are used together.
+* [Issue #463](https://github.com/json-c/json-c/issues/463): fix newlocale() call to use LC_NUMERIC_MASK instead of LC_NUMERIC, and remove incorrect comment.
+* [Issue #486](https://github.com/json-c/json-c/issues/486): append a missing ".0" to negative double values to ensure they are serialized as floating point numbers.
+* [Issue #488](https://github.com/json-c/json-c/issues/488): use JSON_EXPORT on functions so they are properly exported on Windows.
+* [Issue #539](https://github.com/json-c/json-c/issues/539): use an internal-only serializer function in json_object_new_double_s() to avoid potential conflicts with user code that uses the json_object_userdata_to_json_string serializer.
+
+***
+
+0.13.1 (up to commit 0f814e5, 2018/03/04)
+=========================================
+
+* Bump the major version of the .so library generated up to 4.0 to avoid
+  conflicts because some downstream packagers of json-c had already done
+  their own bump to ".so.3" for a much older 0.12 release.
+* Add const size_t json_c_object_sizeof()
+* Avoid invalid free (and thus a segfault) when ref_count gets < 0
+* PR#394: fix handling of custom double formats that include a ".0"
+* Avoid uninitialized variable warnings in json_object_object_foreach
+* Issue #396: fix build for certain uClibc based systems.
+* Add a top level fuzz directory for fuzzers run by OSS-Fuzz
+
+
+0.13 (up to commit 5dae561, 2017/11/29)
+=================================
+
+This release, being three and a half years after the 0.12 branch (f84d9c),
+   has quite a number of changes included.  The following is a sampling of
+   the most significant ones.
+
+Since the 0.12 release, 250 issues and pull requests have been closed.
+See issues_closed_for_0.13.md for a complete list.
+
+
+Deprecated and removed features:
+--------------------------------
+* All internal use of bits.h has been eliminated.  The file will be removed.
+	Do not use: hexdigit(), error_ptr(), error_descrition() and it_error()
+* lh_abort() is deprecated.  It will be removed.
+
+Behavior changes:
+-----------------
+* Tighten the number parsing algorithm to raise errors instead of truncating
+     the results.  For example 12.3.4 or 2015-01-15, which now return null.
+	 See commit 99d8fc
+
+* Use size_t for array length and size.  Platforms where sizeof(size_t) != sizeof(int) may not be backwards compatible
+	See commits 45c56b, 92e9a5 and others.
+
+* Check for failure when allocating memory, returning NULL and errno=ENOMEM.
+	 See commit 2149a04.
+
+* Change json_object_object_add() return type from void to int, and will return -1 on failures, instead of exiting. (Note: this is not an ABI change)
+
+New features:
+-------------
+* We're aiming to follow RFC 7159 now.
+
+* Add a couple of additional option to json_object_to_json_string_ext:
+	JSON_C_TO_STRING_PRETTY_TAB
+	JSON_C_TO_STRING_NOSLASHESCAPE
+
+* Add a json_object_object_add_ex() function to allow for performance
+	improvements when certain constraints are known to be true.
+
+* Make serialization format of doubles configurable, in two different ways:
+	Call json_object_set_serializer with json_object_double_to_json_string and a custom
+	 format on each double object, or
+	Call json_c_set_serialization_double_format() to set a global or thread-wide format.
+
+* Add utility function for comparing json_objects - json_object_equal()
+
+* Add a way to copy entire object trees: json_object_deep_copy()
+* Add json_object_set_ function to modify the value of existing json_object's
+ without the need to recreate them.  Also add a json_object_int_inc function to
+ adjust an int's value.
+* Add support for JSON pointer, RFC 6901.  See json_pointer.h
+* Add a json_util_get_last_err() function to retrieve the string describing the
+ cause of errors, instead of printing to stderr.
+* Add perllike hash function for strings, and json_global_set_string_hash() 8f8d03d
+* Add a json_c_visit() function to provide a way to iterate over a tree of json-c objects.
+
+Notable bug fixes and other improvements:
+-----------------------------------------
+* Make reference increment and decrement atomic to allow passing json objects between threads.
+* Fix json_object_object_foreach to avoid uninitialized variable warnings.
+* Improve performance by removing unneeded data items from hashtable code and reducing duplicate hash computation.
+* Improve performance by storing small strings inside json_object
+* Improve performance of json_object_to_json_string by removing variadic printf. commit 9ff0f49
+* Issue #371: fix parsing of "-Infinity", and avoid needlessly copying the input when doing so.
+* Fix stack buffer overflow in json_object_double_to_json_string_format() - commit 2c2deb87
+* Fix various potential null ptr deref and int32 overflows
+* Issue #332: fix a long-standing bug in array_list_put_idx() where it would attempt to free previously free'd entries due to not checking the current array length.
+* Issue #195: use uselocale() instead of setlocale() in json_tokener to behave better in threaded environments.
+* Issue #275: fix out of bounds read when handling unicode surrogate pairs.
+* Ensure doubles that happen to be a whole number are emitted with ".0" - commit ca7a19
+* PR#331: for Visual Studio, use a snprintf/vsnprintf wrapper that ensures the string is terminated.
+* Fix double to int cast overflow in json_object_get_int64.
+* Clamp double to int32 when narrowing in json_object_get_int.
+* Use strtoll() to parse ints - instead of sscanf
+* Miscellaneous smaller changes, including removing unused variables, fixing warning
+ about uninitialized variables adding const qualifiers, reformatting code, etc...
+
+Build changes:
+--------------
+* Add Appveyor and Travis build support
+* Switch to using CMake when building on Windows with Visual Studio.
+	A dynamic .dll is generated instead of a .lib
+	config.h is now generated, config.h.win32 should no longer be manually copied
+* Add support for MacOS through CMake too.
+* Enable silent build by default
+* Link against libm when needed
+* Add support for building with AddressSanitizer
+* Add support for building with Clang
+* Add a --enable-threading configure option, and only use the (slower) __sync_add_and_fetch()/__sync_sub_and_fetch() function when it is specified.
+
+List of new functions added:
+----------------------------
+### json_object.h
+* array_list_bsearch()
+* array_list_del_idx()
+* json_object_to_json_string_length()
+* json_object_get_userdata()
+* json_object_set_userdata()
+* json_object_object_add_ex()
+* json_object_array_bsearch()
+* json_object_array_del_idx()
+* json_object_set_boolean()
+* json_object_set_int()
+* json_object_int_inc()
+* json_object_set_int64()
+* json_c_set_serialization_double_format()
+* json_object_double_to_json_string()
+* json_object_set_double()
+* json_object_set_string()
+* json_object_set_string_len()
+* json_object_equal()
+* json_object_deep_copy()
+
+### json_pointer.h
+* json_pointer_get()
+* json_pointer_getf()
+* json_pointer_set()
+* json_pointer_setf()
+
+### json_util.h
+* json_object_from_fd()
+* json_object_to_fd()
+* json_util_get_last_err()
+
+### json_visit.h
+* json_c_visit()
+
+### linkhash.h
+* json_global_set_string_hash()
+* lh_table_resize()
+
+### printbuf.h
+* printbuf_strappend()
+
+
+0.12.1
+======
+
+  * Minimal changes to address compile issues.
+
+0.12
+====
+
+  * Address security issues:
+    * CVE-2013-6371: hash collision denial of service
+    * CVE-2013-6370: buffer overflow if size_t is larger than int
+
+  * Avoid potential overflow in json_object_get_double
+
+  * Eliminate the mc_abort() function and MC_ABORT macro.
+
+  * Make the json_tokener_errors array local.  It has been deprecated for
+     a while, and json_tokener_error_desc() should be used instead.
+
+  * change the floating point output format to %.17g so values with
+     more than 6 digits show up in the output.
+
+  * Remove the old libjson.so name compatibility support.  The library is
+      only created as libjson-c.so now and headers are only installed
+      into the ${prefix}/json-c directory.
+
+  * When supported by the linker, add the -Bsymbolic-functions flag.
+
+  * Various changes to fix the build on MSVC.
+
+  * Make strict mode more strict:
+    * number must not start with 0
+    * no single-quote strings
+    * no comments
+    * trailing char not allowed
+    * only allow lowercase literals
+
+  * Added a json_object_new_double_s() convenience function to allow
+    an exact string representation of a double to be specified when
+    creating the object and use it in json_tokener_parse_ex() so
+    a re-serialized object more exactly matches the input.
+
+  * Add support NaN and Infinity
+
+
+0.11
+====
+
+  * IMPORTANT: the name of the library has changed to libjson-c.so and
+     the header files are now in include/json-c.
+     The pkgconfig name has also changed from json to json-c.
+     You should change your build to use appropriate -I and -l options.
+     A compatibility shim is in place so builds using the old name will
+     continue to work, but that will be removed in the next release.
+  * Maximum recursion depth is now a runtime option.
+     json_tokener_new() is provided for compatibility.
+     json_tokener_new_ex(depth)
+  * Include json_object_iterator.h in the installed headers.
+  * Add support for building on Android.
+  * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid.
+  * Make it safe to delete keys while iterating with the json_object_object_foreach macro.
+  * Add a json_set_serializer() function to allow the string output of a json_object to be customized.
+  * Make float parsing locale independent.
+  * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag.
+  * Enable -Werror when building.
+  * speed improvements to parsing 64-bit integers on systems with working sscanf
+  * Add a json_object_object_length function.
+  * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries.
+
+0.10
+====
+
+  * Add a json_object_to_json_string_ext() function to allow output to be
+     formatted in a more human readable form.
+  * Add json_object_object_get_ex(), a NULL-safe get object method, to be able
+     to distinguish between a key not present and the value being NULL.
+  * Add an alternative iterator implementation, see json_object_iterator.h
+  * Make json_object_iter public to enable external use of the
+     json_object_object_foreachC macro.
+  * Add a printbuf_memset() function to provide an efficient way to set and
+     append things like whitespace indentation.
+  * Adjust json_object_is_type and json_object_get_type so they return
+      json_type_null for NULL objects and handle NULL passed to
+      json_objct_object_get().
+  * Rename boolean type to json_bool.
+  * Fix various compile issues for Visual Studio and MinGW.
+  * Allow json_tokener_parse_ex() to be re-used to parse multiple object.
+     Also, fix some parsing issues with capitalized hexadecimal numbers and
+     number in E notation.
+  * Add json_tokener_get_error() and json_tokener_error_desc() to better
+     encapsulate the process of retrieving errors while parsing.
+  * Various improvements to the documentation of many functions.
+  * Add new json_object_array_sort() function.
+  * Fix a bug in json_object_get_int(), which would incorrectly return 0
+    when called on a string type object.
+    Eric Haszlakiewicz
+  * Add a json_type_to_name() function.
+    Eric Haszlakiewicz
+  * Add a json_tokener_parse_verbose() function.
+    Jehiah Czebotar
+  * Improve support for null bytes within JSON strings.
+    Jehiah Czebotar
+  * Fix file descriptor leak if memory allocation fails in json_util
+    Zachary Blair, zack_blair at hotmail dot com
+  * Add int64 support. Two new functions json_object_net_int64 and
+    json_object_get_int64. Binary compatibility preserved.
+    Eric Haszlakiewicz, EHASZLA at transunion com
+    Rui Miguel Silva Seabra, rms at 1407 dot org
+  * Fix subtle bug in linkhash where lookup could hang after all slots
+    were filled then successively freed.
+    Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com
+  * Make json_object_from_file take const char *filename
+    Spotted by Vikram Raj V, vsagar at attinteractive dot com
+  * Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am)
+    Brent Miller, bdmiller at yahoo dash inc dot com
+  * Correction to comment describing printbuf_memappend in printbuf.h
+    Brent Miller, bdmiller at yahoo dash inc dot com
+
+0.9
+===
+  * Add README.html README-WIN32.html config.h.win32 to Makefile.am
+    Michael Clark, 
+  * Add const qualifier to the json_tokener_parse functions
+    Eric Haszlakiewicz, EHASZLA at transunion dot com
+  * Rename min and max so we can never clash with C or C++ std library
+    Ian Atha, thatha at yahoo dash inc dot com
+  * Fix any noticeable spelling or grammar errors.
+  * Make sure every va_start has a va_end.
+  * Check all pointers for validity.
+    Erik Hovland, erik at hovland dot org
+  * Fix json_object_get_boolean to return false for empty string
+    Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com
+  * optimizations to json_tokener_parse_ex(), printbuf_memappend()
+    Brent Miller, bdmiller at yahoo dash inc dot com
+  * Disable REFCOUNT_DEBUG by default in json_object.c
+  * Don't use this as a variable, so we can compile with a C++ compiler
+  * Add casts from void* to type of assignment when using malloc
+  * Add #ifdef __cplusplus guards to all of the headers
+  * Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table
+    Michael Clark, 
+  * Null pointer dereference fix. Fix json_object_get_boolean strlen test
+    to not return TRUE for zero length string. Remove redundant includes.
+    Erik Hovland, erik at hovland dot org
+  * Fixed warning reported by adding -Wstrict-prototypes
+    -Wold-style-definition to the compilatin flags.
+    Dotan Barak, dotanba at gmail dot com
+  * Add const correctness to public interfaces
+    Gerard Krol, g dot c dot krol at student dot tudelft dot nl
+
+0.8
+===
+  * Add va_end for every va_start
+    Dotan Barak, dotanba at gmail dot com
+  * Add macros to enable compiling out debug code
+    Geoffrey Young, geoff at modperlcookbook dot org
+  * Fix bug with use of capital E in numbers with exponents
+    Mateusz Loskot, mateusz at loskot dot net
+  * Add stddef.h include
+  * Patch allows for json-c compile with -Werror and not fail due to
+    -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
+    Geoffrey Young, geoff at modperlcookbook dot org
+
+0.7
+===
+  * Add escaping of backslash to json output
+  * Add escaping of forward slash on tokenizing and output
+  * Changes to internal tokenizer from using recursion to
+    using a depth state structure to allow incremental parsing
+
+0.6
+===
+  * Fix bug in escaping of control characters
+    Johan Björklund, johbjo09 at kth dot se
+  * Remove include "config.h" from headers (should only
+    be included from .c files)
+    Michael Clark 
+
+0.5
+===
+  * Make headers C++ compatible by change *this to *obj
+  * Add ifdef C++ extern "C" to headers
+  * Use simpler definition of min and max in bits.h
+    Larry Lansing, llansing at fuzzynerd dot com
+
+  * Remove automake 1.6 requirement
+  * Move autogen commands into autogen.sh. Update README
+  * Remove error pointer special case for Windows
+  * Change license from LGPL to MIT
+    Michael Clark 
+
+0.4
+===
+  * Fix additional error case in object parsing
+  * Add back sign reversal in nested object parse as error pointer
+    value is negative, while error value is positive.
+    Michael Clark 
+
+0.3
+===
+  * fix pointer arithmetic bug for error pointer check in is_error() macro
+  * fix type passed to printbuf_memappend in json_tokener
+  * update autotools bootstrap instructions in README
+    Michael Clark 
+
+0.2
+===
+  * printbuf.c - C. Watford (christopher.watford@gmail.com)
+    Added a Win32/Win64 compliant implementation of vasprintf
+  * debug.c - C. Watford (christopher.watford@gmail.com)
+    Removed usage of vsyslog on Win32/Win64 systems, needs to be handled
+    by a configure script
+  * json_object.c - C. Watford (christopher.watford@gmail.com)
+    Added scope operator to wrap usage of json_object_object_foreach, this
+    needs to be rethought to be more ANSI C friendly
+  * json_object.h - C. Watford (christopher.watford@gmail.com)
+    Added Microsoft C friendly version of json_object_object_foreach
+  * json_tokener.c - C. Watford (christopher.watford@gmail.com)
+    Added a Win32/Win64 compliant implementation of strndup
+  * json_util.c - C. Watford (christopher.watford@gmail.com)
+    Added cast and mask to suffice size_t v. unsigned int conversion
+    correctness
+  * json_tokener.c - sign reversal issue on error info for nested object parse
+    spotted by Johan Björklund (johbjo09 at kth.se)
+  * json_object.c - escape " in json_escape_str
+  * Change to automake and libtool to build shared and static library
+    Michael Clark 
+
+0.1
+===
+  * initial release
diff --git a/comm/third_party/json-c/INSTALL b/comm/third_party/json-c/INSTALL
new file mode 100644
index 0000000000..d8575d3fb6
--- /dev/null
+++ b/comm/third_party/json-c/INSTALL
@@ -0,0 +1,2 @@
+
+See README.md for installation instructions.
diff --git a/comm/third_party/json-c/NEWS b/comm/third_party/json-c/NEWS
new file mode 100644
index 0000000000..5798fb41b9
--- /dev/null
+++ b/comm/third_party/json-c/NEWS
@@ -0,0 +1 @@
+See the git repo.
diff --git a/comm/third_party/json-c/README.html b/comm/third_party/json-c/README.html
new file mode 100644
index 0000000000..483e4075b2
--- /dev/null
+++ b/comm/third_party/json-c/README.html
@@ -0,0 +1,41 @@
+
+
+	
+		JSON-C - A JSON implementation in C
+		
+	
+	
+		

JSON-C - A JSON implementation in C

+ +

Overview

+

JSON-C implements a reference counting object model that allows you to easily + construct JSON objects in C, output them as JSON formatted strings and parse + JSON formatted strings back into the C representation of JSON objects. + It aims to conform to RFC 7159. +

+ +

Building

+

To setup JSON-C to build on your system please run configure and make.

+

If you are on Win32 cmake is required, generally:

+
    +
  • mkdir build
  • +
  • cd build
  • +
  • cmake ..
  • +
  • msbuild "json-c.vcxproj" /m /verbosity:normal /p:OutDir=lib\
  • +
  • Or, open the project in Visual Studio
  • +
+ +

Documentation

+

Doxygen generated documentation exists here.

+ +

GIT Reposository

+

git clone https://github.com/json-c/json-c.git

+ +

Mailing List

+ Send email to json-c <at> googlegroups <dot> com

+ +

License

+

This program is free software; you can redistribute it and/or modify it under the terms of the MIT License.

+
+ + diff --git a/comm/third_party/json-c/README.md b/comm/third_party/json-c/README.md new file mode 100644 index 0000000000..7e642a1111 --- /dev/null +++ b/comm/third_party/json-c/README.md @@ -0,0 +1,300 @@ +\mainpage + +`json-c` +======== + +1. [Overview and Build Status](#overview) +2. [Building on Unix](#buildunix) + * [Prerequisites](#installprereq) + * [Build commands](#buildcmds) +3. [CMake options](#CMake) +4. [Testing](#testing) +5. [Building with `vcpkg`](#buildvcpkg) +6. [Linking to libjson-c](#linking) +7. [Using json-c](#using) + +JSON-C - A JSON implementation in C +----------------------------------- + +JSON-C implements a reference counting object model that allows you to easily +construct JSON objects in C, output them as JSON formatted strings and parse +JSON formatted strings back into the C representation of JSON objects. +It aims to conform to [RFC 7159](https://tools.ietf.org/html/rfc7159). + +Skip down to [Using json-c](#using) +or check out the [API docs](https://json-c.github.io/json-c/), +if you already have json-c installed and ready to use. + +Home page for json-c: https://github.com/json-c/json-c/wiki + +Build Status +* [AppVeyor Build](https://ci.appveyor.com/project/hawicz/json-c) ![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/json-c/json-c?branch=master&svg=true) +* [Travis Build](https://travis-ci.org/json-c/json-c) ![Travis Build Status](https://travis-ci.org/json-c/json-c.svg?branch=master) + +Test Status +* [Coveralls](https://coveralls.io/github/json-c/json-c?branch=master) [![Coverage Status](https://coveralls.io/repos/github/json-c/json-c/badge.svg?branch=master)](https://coveralls.io/github/json-c/json-c?branch=master) + +Building on Unix with `git`, `gcc` and `cmake` +-------------------------------------------------- + +If you already have json-c installed, see [Linking to `libjson-c`](#linking) +for how to build and link your program against it. + +### Prerequisites: + + - `gcc`, `clang`, or another C compiler + + - `cmake>=2.8`, `>=3.16` recommended, `cmake=>3.1` for tests + +To generate docs you'll also need: + - `doxygen>=1.8.13` + +If you are on a relatively modern system, you'll likely be able to install +the prerequisites using your OS's packaging system. + +### Install using apt (e.g. Ubuntu 16.04.2 LTS) +```sh +sudo apt install git +sudo apt install cmake +sudo apt install doxygen # optional +sudo apt install valgrind # optional +``` + +### Build instructions: + +`json-c` GitHub repo: https://github.com/json-c/json-c + +```sh +$ git clone https://github.com/json-c/json-c.git +$ mkdir json-c-build +$ cd json-c-build +$ cmake ../json-c # See CMake section below for custom arguments +``` + +Note: it's also possible to put your build directory inside the json-c +source directory, or even not use a separate build directory at all, but +certain things might not work quite right (notably, `make distcheck`) + +Then: + +```sh +$ make +$ make test +$ make USE_VALGRIND=0 test # optionally skip using valgrind +$ make install +``` + + +### Generating documentation with Doxygen: + +The library documentation can be generated directly from the source code using Doxygen tool: + +```sh +# in build directory +make doc +google-chrome doc/html/index.html +``` + + +CMake Options +-------------------- + +The json-c library is built with [CMake](https://cmake.org/cmake-tutorial/), +which can take a few options. + +Variable | Type | Description +-----------------------------|--------|-------------- +CMAKE_INSTALL_PREFIX | String | The install location. +CMAKE_BUILD_TYPE | String | Defaults to "debug". +BUILD_SHARED_LIBS | Bool | The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library only. +BUILD_STATIC_LIBS | Bool | The default build generates a static (lib/a) library. Set this to OFF to create a shared library only. +DISABLE_STATIC_FPIC | Bool | The default builds position independent code. Set this to OFF to create a shared library only. +DISABLE_BSYMBOLIC | Bool | Disable use of -Bsymbolic-functions. +DISABLE_THREAD_LOCAL_STORAGE | Bool | Disable use of Thread-Local Storage (HAVE___THREAD). +DISABLE_WERROR | Bool | Disable use of -Werror. +ENABLE_RDRAND | Bool | Enable RDRAND Hardware RNG Hash Seed. +ENABLE_THREADING | Bool | Enable partial threading support. +OVERRIDE_GET_RANDOM_SEED | String | A block of code to use instead of the default implementation of json_c_get_random_seed(), e.g. on embedded platforms where not even the fallback to time() works. Must be a single line. + +Pass these options as `-D` on CMake's command-line. + +```sh +# build a static library only +cmake -DBUILD_SHARED_LIBS=OFF .. +``` + +### Building with partial threading support + +Although json-c does not support fully multi-threaded access to +object trees, it has some code to help make its use in threaded programs +a bit safer. Currently, this is limited to using atomic operations for +json_object_get() and json_object_put(). + +Since this may have a performance impact, of at least 3x slower +according to https://stackoverflow.com/a/11609063, it is disabled by +default. You may turn it on by adjusting your cmake command with: + -DENABLE_THREADING=ON + +Separately, the default hash function used for object field keys, +lh_char_hash, uses a compare-and-swap operation to ensure the random +seed is only generated once. Because this is a one-time operation, it +is always compiled in when the compare-and-swap operation is available. + + +### cmake-configure wrapper script + +For those familiar with the old autoconf/autogen.sh/configure method, +there is a `cmake-configure` wrapper script to ease the transition to cmake. + +```sh +mkdir build +cd build +../cmake-configure --prefix=/some/install/path +make +``` + +cmake-configure can take a few options. + +| options | Description| +| ---- | ---- | +| prefix=PREFIX | install architecture-independent files in PREFIX | +| enable-threading | Enable code to support partly multi-threaded use | +| enable-rdrand | Enable RDRAND Hardware RNG Hash Seed generation on supported x86/x64 platforms. | +| enable-shared | build shared libraries [default=yes] | +| enable-static | build static libraries [default=yes] | +| disable-Bsymbolic | Avoid linking with -Bsymbolic-function | +| disable-werror | Avoid treating compiler warnings as fatal errors | + + +Testing: +---------- + +By default, if valgrind is available running tests uses it. +That can slow the tests down considerably, so to disable it use: +```sh +export USE_VALGRIND=0 +``` + +To run tests a separate build directory is recommended: +```sh +mkdir build-test +cd build-test +# VALGRIND=1 causes -DVALGRIND=1 to be passed when compiling code +# which uses slightly slower, but valgrind-safe code. +VALGRIND=1 cmake .. +make + +make test +# By default, if valgrind is available running tests uses it. +make USE_VALGRIND=0 test # optionally skip using valgrind +``` + +If a test fails, check `Testing/Temporary/LastTest.log`, +`tests/testSubDir/${testname}/${testname}.vg.out`, and other similar files. +If there is insufficient output try: +```sh +VERBOSE=1 CTEST_OUTPUT_ON_FAILURE=1 make test +``` +or +```sh +JSONC_TEST_TRACE=1 make test +``` +and check the log files again. + + +Building on Unix and Windows with `vcpkg` +-------------------------------------------------- + +You can download and install JSON-C using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: + + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + ./bootstrap-vcpkg.sh + ./vcpkg integrate install + vcpkg install json-c + +The JSON-C port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + + +Linking to `libjson-c` +---------------------- + +If your system has `pkgconfig`, +then you can just add this to your `makefile`: + +```make +CFLAGS += $(shell pkg-config --cflags json-c) +LDFLAGS += $(shell pkg-config --libs json-c) +``` + +Without `pkgconfig`, you might do something like this: + +```make +JSON_C_DIR=/path/to/json_c/install +CFLAGS += -I$(JSON_C_DIR)/include/json-c +# Or to use lines like: #include +#CFLAGS += -I$(JSON_C_DIR)/include +LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c +``` + +If your project uses cmake: + +* Add to your CMakeLists.txt file: + +```cmake +find_package(json-c CONFIG) +target_link_libraries(${PROJECT_NAME} PRIVATE json-c::json-c) +``` + +* Then you might run in your project: + +```sh +cd build +cmake -DCMAKE_PREFIX_PATH=/path/to/json_c/install/lib64/cmake .. +``` + +Using json-c +------------ + +To use json-c you can either include json.h, or preferably, one of the +following more specific header files: + +* json_object.h - Core types and methods. +* json_tokener.h - Methods for parsing and serializing json-c object trees. +* json_pointer.h - JSON Pointer (RFC 6901) implementation for retrieving + objects from a json-c object tree. +* json_object_iterator.h - Methods for iterating over single json_object instances. (See also `json_object_object_foreach()` in json_object.h) +* json_visit.h - Methods for walking a tree of json-c objects. +* json_util.h - Miscellaneous utility functions. + +For a full list of headers see [files.html](https://json-c.github.io/json-c/json-c-current-release/doc/html/files.html) + +The primary type in json-c is json_object. It describes a reference counted +tree of json objects which are created by either parsing text with a +json_tokener (i.e. `json_tokener_parse_ex()`), or by creating +(with `json_object_new_object()`, `json_object_new_int()`, etc...) and adding +(with `json_object_object_add()`, `json_object_array_add()`, etc...) them +individually. +Typically, every object in the tree will have one reference, from its parent. +When you are done with the tree of objects, you call json_object_put() on just +the root object to free it, which recurses down through any child objects +calling json_object_put() on each one of those in turn. + +You can get a reference to a single child +(`json_object_object_get()` or `json_object_array_get_idx()`) +and use that object as long as its parent is valid. +If you need a child object to live longer than its parent, you can +increment the child's refcount (`json_object_get()`) to allow it to survive +the parent being freed or it being removed from its parent +(`json_object_object_del()` or `json_object_array_del_idx()`) + +When parsing text, the json_tokener object is independent from the json_object +that it returns. It can be allocated (`json_tokener_new()`) +used one or multiple times (`json_tokener_parse_ex()`, and +freed (`json_tokener_free()`) while the json_object objects live on. + +A json_object tree can be serialized back into a string with +`json_object_to_json_string_ext()`. The string that is returned +is only valid until the next "to_json_string" call on that same object. +Also, it is freed when the json_object is freed. + diff --git a/comm/third_party/json-c/RELEASE_CHECKLIST.txt b/comm/third_party/json-c/RELEASE_CHECKLIST.txt new file mode 100644 index 0000000000..e8d2943a8a --- /dev/null +++ b/comm/third_party/json-c/RELEASE_CHECKLIST.txt @@ -0,0 +1,179 @@ + +# Release checklist: + +## Pre-release tasks + +* Figure out whether a release is worthwhile to do. +* Analyze the previous release branch to see if anything should have been + applied to master. +* Collect changes and assemble tentative release notes. + * Identify previous release branch point + * Check commit logs between previous branch point and now for + notable changes worth mentioning + * Create a new issues_closed_for_X.Y.md file + * Include notable entries from here in the release notes. + * Analyze APIs between previous release branch and master to produce list of + changes (added/removed/updated funcs, etc...), and detect backwards compat + issues. + * https://github.com/lvc/abi-compliance-checker + * If the new release is not backwards compatible, then this is a MAJOR release. + * Mention removed features in ChangeLog + * Consider re-adding backwards compatible support, through symbol + aliases and appropriate entries in json-c.sym + * Be sure any new symbols are listed in json-c.sym as part of + the _new_ release version. + * Update the AUTHORS file + + PREV=$(git tag | tail -1) + ( git log -r ${PREV}..HEAD | grep Author: | sed -e's/Author: //' ; cat AUTHORS ) | sort -u > A1 + mv A1 AUTHORS + + * Exclude mentioning changes that have already been included in a point + release of the previous release branch. + +* Update ChangeLog with relevant notes before branching. + +* Check that the compile works on Linux - automatic through Travis +* Check that the compile works on NetBSD +* Check that the compile works on Windows - automatic through AppVeyor + +## Release creation + +Start creating the new release: + release=0.16 + git clone https://github.com/json-c/json-c json-c-${release} + + mkdir distcheck + cd distcheck + # Note, the build directory *must* be entirely separate from + # the source tree for distcheck to work properly. + cmake -DCMAKE_BUILD_TYPE=Release ../json-c-${release} + make distcheck + cd .. + +Make any fixes/changes *before* branching. + + cd json-c-${release} + git branch json-c-${release} + git checkout json-c-${release} + +------------ + +Using ${release}: + Update the version in json_c_version.h + Update the version in CMakeLists.txt (VERSION in the project(...) line) + +Update the set_target_properties() line in CmakeLists.txt to set the shared +library version. Generally, unless we're doing a major release, change: + VERSION x.y.z +to + VERSION x.y+1.z + + git commit -a -m "Bump version to ${release}" + +If we're doing a major release (SONAME bump), also bump the version + of ALL symbols in json-c.sym. + See explanation at https://github.com/json-c/json-c/issues/621 + More info at: https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf + +------------ + +Generate the doxygen documentation: + + (cd ../distcheck && make doc) + cp -r -p ../distcheck/doc/{html,Doxyfile} doc/. + rm doc/Doxyfile # Remove generated file w/ hardcoded paths + git add -f doc + git commit doc -m "Generate docs for the ${release} release" + +------------ + +Create the release tarballs: + + cd .. + echo .git > excludes + tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} + + echo 'doc/*' >> excludes + tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} + +------------ + +Tag the branch: + + cd json-c-${release} + git tag -a json-c-${release}-$(date +%Y%m%d) -m "Release json-c-${release}" + + git push origin json-c-${release} + git push --tags + +------------ + +Go to Amazon S3 service at: + https://console.aws.amazon.com/s3/ + +Upload the two tarballs in the json-c_releases/releases folder. + When uploading, use "Standard" storage class, and make the uploaded files publicly accessible. + +Logout of Amazon S3, and verify that the files are visible. + https://s3.amazonaws.com/json-c_releases/releases/index.html + +=================================== + +Post-release checklist: + + git checkout master + +Add new section to ChangeLog for ${release}+1 + +Use ${release}.99 to indicate a version "newer" than anything on the branch: + Update the version in json_c_version.h + Update the version in CMakeLists.txt + +Update RELEASE_CHECKLIST.txt, set release=${release}+1 + +Add a new empty section to the json-c.sym file, for ${release}+1 + +Update the set_target_properties() line in CmakeLists.txt to match the release branch. + + git commit -a -m "Update the master branch to version ${release}.99" + git push + +------------ + +Update the gh-pages branch with new docs: + + cd json-c-${release} + git checkout json-c-${release} + cd .. + + git clone -b gh-pages https://github.com/json-c/json-c json-c-pages + cd json-c-pages + mkdir json-c-${release} + cp -R ../json-c-${release}/doc json-c-${release}/. + git add json-c-${release} + rm json-c-current-release + ln -s json-c-${release} json-c-current-release + git commit -a -m "Add the ${release} docs." + + vi index.html + # Add/change links to current release. + + git commit -a -m "Update the doc links to point at ${release}" + + git push + +------------ + +Update checksums on wiki page. + + cd .. + openssl sha -sha256 json-c*gz + openssl md5 json-c*gz + +Copy and paste this output into the wiki page at: + https://github.com/json-c/json-c/wiki + +------------ + +Send an email to the mailing list. diff --git a/comm/third_party/json-c/STYLE.txt b/comm/third_party/json-c/STYLE.txt new file mode 100644 index 0000000000..4e5d75ac5b --- /dev/null +++ b/comm/third_party/json-c/STYLE.txt @@ -0,0 +1,31 @@ +In general: +For minor changes to a function, copy the existing formatting. +When changing the style, commit that separately from other changes. +For new code and major changes to a function, switch to the official json-c style. + +Official json-c style: + +Aim for readability, not strict conformance to fixed style rules. +Formatting is tab based; previous attempts at proper alignment with +spaces for continuation lines have been abandoned in favor of the +convenience of using clang-format. +Refer to the .clang-format file for details, and run the tool before commit: + + clang-format -i somefile.c foo.h + +For sections of code that would be significantly negatively impacted, surround +them with magic comments to disable formatting: + + /* clang-format off */ + ...code... + /* clang-format on */ + + +Naming: +Words within function and variable names are separated with underscores. Avoid camel case. +Prefer longer, more descriptive names, but not excessively so. No single letter variable names. + +Other: +Variables should be defined for the smallest scope needed. +Functions should be defined static when possible. +When possible, avoid exposing internals in the public API. diff --git a/comm/third_party/json-c/arraylist.c b/comm/third_party/json-c/arraylist.c new file mode 100644 index 0000000000..d8e12d11cb --- /dev/null +++ b/comm/third_party/json-c/arraylist.c @@ -0,0 +1,205 @@ +/* + * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include + +#ifdef STDC_HEADERS +#include +#include +#endif /* STDC_HEADERS */ + +#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD) +#include +#endif /* HAVE_STRINGS_H */ + +#ifndef SIZE_T_MAX +#if SIZEOF_SIZE_T == SIZEOF_INT +#define SIZE_T_MAX UINT_MAX +#elif SIZEOF_SIZE_T == SIZEOF_LONG +#define SIZE_T_MAX ULONG_MAX +#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG +#define SIZE_T_MAX ULLONG_MAX +#else +#error Unable to determine size of size_t +#endif +#endif + +#include "arraylist.h" + +struct array_list *array_list_new(array_list_free_fn *free_fn) +{ + return array_list_new2(free_fn, ARRAY_LIST_DEFAULT_SIZE); +} + +struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size) +{ + struct array_list *arr; + + if (initial_size < 0 || (size_t)initial_size >= SIZE_T_MAX / sizeof(void *)) + return NULL; + arr = (struct array_list *)malloc(sizeof(struct array_list)); + if (!arr) + return NULL; + arr->size = initial_size; + arr->length = 0; + arr->free_fn = free_fn; + if (!(arr->array = (void **)malloc(arr->size * sizeof(void *)))) + { + free(arr); + return NULL; + } + return arr; +} + +extern void array_list_free(struct array_list *arr) +{ + size_t i; + for (i = 0; i < arr->length; i++) + if (arr->array[i]) + arr->free_fn(arr->array[i]); + free(arr->array); + free(arr); +} + +void *array_list_get_idx(struct array_list *arr, size_t i) +{ + if (i >= arr->length) + return NULL; + return arr->array[i]; +} + +static int array_list_expand_internal(struct array_list *arr, size_t max) +{ + void *t; + size_t new_size; + + if (max < arr->size) + return 0; + /* Avoid undefined behaviour on size_t overflow */ + if (arr->size >= SIZE_T_MAX / 2) + new_size = max; + else + { + new_size = arr->size << 1; + if (new_size < max) + new_size = max; + } + if (new_size > (~((size_t)0)) / sizeof(void *)) + return -1; + if (!(t = realloc(arr->array, new_size * sizeof(void *)))) + return -1; + arr->array = (void **)t; + arr->size = new_size; + return 0; +} + +int array_list_shrink(struct array_list *arr, size_t empty_slots) +{ + void *t; + size_t new_size; + + if (empty_slots >= SIZE_T_MAX / sizeof(void *) - arr->length) + return -1; + new_size = arr->length + empty_slots; + if (new_size == arr->size) + return 0; + if (new_size > arr->size) + return array_list_expand_internal(arr, new_size); + if (new_size == 0) + new_size = 1; + + if (!(t = realloc(arr->array, new_size * sizeof(void *)))) + return -1; + arr->array = (void **)t; + arr->size = new_size; + return 0; +} + +//static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data) +int array_list_put_idx(struct array_list *arr, size_t idx, void *data) +{ + if (idx > SIZE_T_MAX - 1) + return -1; + if (array_list_expand_internal(arr, idx + 1)) + return -1; + if (idx < arr->length && arr->array[idx]) + arr->free_fn(arr->array[idx]); + arr->array[idx] = data; + if (idx > arr->length) + { + /* Zero out the arraylist slots in between the old length + and the newly added entry so we know those entries are + empty. + e.g. when setting array[7] in an array that used to be + only 5 elements longs, array[5] and array[6] need to be + set to 0. + */ + memset(arr->array + arr->length, 0, (idx - arr->length) * sizeof(void *)); + } + if (arr->length <= idx) + arr->length = idx + 1; + return 0; +} + +int array_list_add(struct array_list *arr, void *data) +{ + /* Repeat some of array_list_put_idx() so we can skip several + checks that we know are unnecessary when appending at the end + */ + size_t idx = arr->length; + if (idx > SIZE_T_MAX - 1) + return -1; + if (array_list_expand_internal(arr, idx + 1)) + return -1; + arr->array[idx] = data; + arr->length++; + return 0; +} + +void array_list_sort(struct array_list *arr, int (*compar)(const void *, const void *)) +{ + qsort(arr->array, arr->length, sizeof(arr->array[0]), compar); +} + +void *array_list_bsearch(const void **key, struct array_list *arr, + int (*compar)(const void *, const void *)) +{ + return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]), compar); +} + +size_t array_list_length(struct array_list *arr) +{ + return arr->length; +} + +int array_list_del_idx(struct array_list *arr, size_t idx, size_t count) +{ + size_t i, stop; + + /* Avoid overflow in calculation with large indices. */ + if (idx > SIZE_T_MAX - count) + return -1; + stop = idx + count; + if (idx >= arr->length || stop > arr->length) + return -1; + for (i = idx; i < stop; ++i) + { + // Because put_idx can skip entries, we need to check if + // there's actually anything in each slot we're erasing. + if (arr->array[i]) + arr->free_fn(arr->array[i]); + } + memmove(arr->array + idx, arr->array + stop, (arr->length - stop) * sizeof(void *)); + arr->length -= count; + return 0; +} diff --git a/comm/third_party/json-c/arraylist.h b/comm/third_party/json-c/arraylist.h new file mode 100644 index 0000000000..f541706936 --- /dev/null +++ b/comm/third_party/json-c/arraylist.h @@ -0,0 +1,88 @@ +/* + * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Internal methods for working with json_type_array objects. + * Although this is exposed by the json_object_get_array() method, + * it is not recommended for direct use. + */ +#ifndef _json_c_arraylist_h_ +#define _json_c_arraylist_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define ARRAY_LIST_DEFAULT_SIZE 32 + +typedef void(array_list_free_fn)(void *data); + +struct array_list +{ + void **array; + size_t length; + size_t size; + array_list_free_fn *free_fn; +}; +typedef struct array_list array_list; + +/** + * Allocate an array_list of the default size (32). + * @deprecated Use array_list_new2() instead. + */ +extern struct array_list *array_list_new(array_list_free_fn *free_fn); + +/** + * Allocate an array_list of the desired size. + * + * If possible, the size should be chosen to closely match + * the actual number of elements expected to be used. + * If the exact size is unknown, there are tradeoffs to be made: + * - too small - the array_list code will need to call realloc() more + * often (which might incur an additional memory copy). + * - too large - will waste memory, but that can be mitigated + * by calling array_list_shrink() once the final size is known. + * + * @see array_list_shrink + */ +extern struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size); + +extern void array_list_free(struct array_list *al); + +extern void *array_list_get_idx(struct array_list *al, size_t i); + +extern int array_list_put_idx(struct array_list *al, size_t i, void *data); + +extern int array_list_add(struct array_list *al, void *data); + +extern size_t array_list_length(struct array_list *al); + +extern void array_list_sort(struct array_list *arr, int (*compar)(const void *, const void *)); + +extern void *array_list_bsearch(const void **key, struct array_list *arr, + int (*compar)(const void *, const void *)); + +extern int array_list_del_idx(struct array_list *arr, size_t idx, size_t count); + +/** + * Shrink the array list to just enough to fit the number of elements in it, + * plus empty_slots. + */ +extern int array_list_shrink(struct array_list *arr, size_t empty_slots); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/config.h.in b/comm/third_party/json-c/config.h.in new file mode 100644 index 0000000000..06c0f20886 --- /dev/null +++ b/comm/third_party/json-c/config.h.in @@ -0,0 +1,217 @@ +/* config.h.in. Modified for moz.build from cmake/config.h.in. */ + +/* Enable RDRAND Hardware RNG Hash Seed */ +#undef ENABLE_RDRAND + +/* Override json_c_get_random_seed() with custom code */ +#undef OVERRIDE_GET_RANDOM_SEED + +/* Enable partial threading support */ +#undef ENABLE_THREADING + +/* Define if .gnu.warning accepts long strings. */ +#undef HAS_GNU_WARNING_LONG + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CDEFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RANDOM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_XLOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_BSD_STDLIB_H + +/* Define to 1 if you have `arc4random' */ +#undef HAVE_ARC4RANDOM + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Has atomic builtins */ +#undef HAVE_ATOMIC_BUILTINS + +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you + don't. */ +#undef HAVE_DECL_INFINITY + +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. + */ +#undef HAVE_DECL_ISINF + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. + */ +#undef HAVE_DECL_ISNAN + +/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ +#undef HAVE_DECL_NAN + +/* Define to 1 if you have the declaration of `_finite', and to 0 if you + don't. */ +#undef HAVE_DECL__FINITE + +/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. + */ +#undef HAVE_DECL__ISNAN + +/* Define to 1 if you have the `open' function. */ +#undef HAVE_OPEN + +/* Define to 1 if you have the `realloc' function. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `uselocale' function. */ +#undef HAVE_USELOCALE + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define if you have the `getrandom' function. */ +#undef HAVE_GETRANDOM + +/* Define if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Have __thread */ +#undef HAVE___THREAD + +/* Public define for json_inttypes.h */ +#undef JSON_C_HAVE_INTTYPES_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The number of bytes in type int */ +#undef SIZEOF_INT + +/* The number of bytes in type int64_t */ +#undef SIZEOF_INT64_T + +/* The number of bytes in type long */ +#undef SIZEOF_LONG + +/* The number of bytes in type long long */ +#undef SIZEOF_LONG_LONG + +/* The number of bytes in type size_t */ +#undef SIZEOF_SIZE_T + +/* The number of bytes in type ssize_t */ +#undef SIZEOF_SSIZE_T + +/* Specifier for __thread */ +#undef SPEC___THREAD + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/comm/third_party/json-c/debug.c b/comm/third_party/json-c/debug.c new file mode 100644 index 0000000000..7971744ccf --- /dev/null +++ b/comm/third_party/json-c/debug.c @@ -0,0 +1,96 @@ +/* + * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include +#include +#include +#include + +#if HAVE_SYSLOG_H +#include +#endif /* HAVE_SYSLOG_H */ + +#if HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#if HAVE_SYS_PARAM_H +#include +#endif /* HAVE_SYS_PARAM_H */ + +#include "debug.h" + +static int _syslog = 0; +static int _debug = 0; + +void mc_set_debug(int debug) +{ + _debug = debug; +} +int mc_get_debug(void) +{ + return _debug; +} + +extern void mc_set_syslog(int syslog) +{ + _syslog = syslog; +} + +void mc_debug(const char *msg, ...) +{ + va_list ap; + if (_debug) + { + va_start(ap, msg); +#if HAVE_VSYSLOG + if (_syslog) + { + vsyslog(LOG_DEBUG, msg, ap); + } + else +#endif + vprintf(msg, ap); + va_end(ap); + } +} + +void mc_error(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); +#if HAVE_VSYSLOG + if (_syslog) + { + vsyslog(LOG_ERR, msg, ap); + } + else +#endif + vfprintf(stderr, msg, ap); + va_end(ap); +} + +void mc_info(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); +#if HAVE_VSYSLOG + if (_syslog) + { + vsyslog(LOG_INFO, msg, ap); + } + else +#endif + vfprintf(stderr, msg, ap); + va_end(ap); +} diff --git a/comm/third_party/json-c/debug.h b/comm/third_party/json-c/debug.h new file mode 100644 index 0000000000..4af0ba9236 --- /dev/null +++ b/comm/third_party/json-c/debug.h @@ -0,0 +1,98 @@ +/* + * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef _JSON_C_DEBUG_H_ +#define _JSON_C_DEBUG_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JSON_EXPORT +#if defined(_MSC_VER) && defined(JSON_C_DLL) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif +#endif + +JSON_EXPORT void mc_set_debug(int debug); +JSON_EXPORT int mc_get_debug(void); + +JSON_EXPORT void mc_set_syslog(int syslog); + +JSON_EXPORT void mc_debug(const char *msg, ...); +JSON_EXPORT void mc_error(const char *msg, ...); +JSON_EXPORT void mc_info(const char *msg, ...); + +#ifndef __STRING +#define __STRING(x) #x +#endif + +#ifndef PARSER_BROKEN_FIXED + +#define JASSERT(cond) \ + do \ + { \ + } while (0) + +#else + +#define JASSERT(cond) \ + do \ + { \ + if (!(cond)) \ + { \ + mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", \ + __FILE__, __LINE__); \ + *(int *)0 = 1; \ + abort(); \ + } \ + } while (0) + +#endif + +#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) + +#ifdef MC_MAINTAINER_MODE +#define MC_SET_DEBUG(x) mc_set_debug(x) +#define MC_GET_DEBUG() mc_get_debug() +#define MC_SET_SYSLOG(x) mc_set_syslog(x) +#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) +#else +#define MC_SET_DEBUG(x) \ + if (0) \ + mc_set_debug(x) +#define MC_GET_DEBUG() (0) +#define MC_SET_SYSLOG(x) \ + if (0) \ + mc_set_syslog(x) +#define MC_DEBUG(x, ...) \ + if (0) \ + mc_debug(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) \ + if (0) \ + mc_info(x, ##__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json.h.cmakein b/comm/third_party/json-c/json.h.cmakein new file mode 100644 index 0000000000..4fed013b31 --- /dev/null +++ b/comm/third_party/json-c/json.h.cmakein @@ -0,0 +1,38 @@ +/* + * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief A convenience header that may be included instead of other individual ones. + */ +#ifndef _json_h_ +#define _json_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "arraylist.h" +#include "debug.h" +#include "json_c_version.h" +#include "json_object.h" +#include "json_object_iterator.h" +@JSON_H_JSON_POINTER@ +#include "json_tokener.h" +#include "json_util.h" +#include "linkhash.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_c_version.c b/comm/third_party/json-c/json_c_version.c new file mode 100644 index 0000000000..9b21db4546 --- /dev/null +++ b/comm/third_party/json-c/json_c_version.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2012 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ +#include "config.h" + +#include "json_c_version.h" + +const char *json_c_version(void) +{ + return JSON_C_VERSION; +} + +int json_c_version_num(void) +{ + return JSON_C_VERSION_NUM; +} diff --git a/comm/third_party/json-c/json_c_version.h b/comm/third_party/json-c/json_c_version.h new file mode 100644 index 0000000000..1b7d531a69 --- /dev/null +++ b/comm/third_party/json-c/json_c_version.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012,2017-2022 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +/** + * @file + * @brief Methods for retrieving the json-c version. + */ +#ifndef _json_c_version_h_ +#define _json_c_version_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_C_MAJOR_VERSION 0 +#define JSON_C_MINOR_VERSION 16 +#define JSON_C_MICRO_VERSION 0 +#define JSON_C_VERSION_NUM \ + ((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION) +#define JSON_C_VERSION "0.16" + +#ifndef JSON_EXPORT +#if defined(_MSC_VER) && defined(JSON_C_DLL) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif +#endif + +/** + * @see JSON_C_VERSION + * @return the version of the json-c library as a string + */ +JSON_EXPORT const char *json_c_version(void); /* Returns JSON_C_VERSION */ + +/** + * The json-c version encoded into an int, with the low order 8 bits + * being the micro version, the next higher 8 bits being the minor version + * and the next higher 8 bits being the major version. + * For example, 7.12.99 would be 0x00070B63. + * + * @see JSON_C_VERSION_NUM + * @return the version of the json-c library as an int + */ +JSON_EXPORT int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_config.h.in b/comm/third_party/json-c/json_config.h.in new file mode 100644 index 0000000000..7888e02170 --- /dev/null +++ b/comm/third_party/json-c/json_config.h.in @@ -0,0 +1,3 @@ + +/* Define to 1 if you have the header file. */ +#undef JSON_C_HAVE_INTTYPES_H diff --git a/comm/third_party/json-c/json_inttypes.h b/comm/third_party/json-c/json_inttypes.h new file mode 100644 index 0000000000..e047d4f18b --- /dev/null +++ b/comm/third_party/json-c/json_inttypes.h @@ -0,0 +1,24 @@ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef _json_inttypes_h_ +#define _json_inttypes_h_ + +#include "json_config.h" + +#ifdef JSON_C_HAVE_INTTYPES_H +/* inttypes.h includes stdint.h */ +#include + +#else +#include + +#define PRId64 "I64d" +#define SCNd64 "I64d" +#define PRIu64 "I64u" + +#endif + +#endif diff --git a/comm/third_party/json-c/json_object.c b/comm/third_party/json-c/json_object.c new file mode 100644 index 0000000000..e52ca4071a --- /dev/null +++ b/comm/third_party/json-c/json_object.c @@ -0,0 +1,1808 @@ +/* + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include "strerror_override.h" + +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include +#include +#include + +#include "arraylist.h" +#include "debug.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_object_private.h" +#include "json_util.h" +#include "linkhash.h" +#include "math_compat.h" +#include "printbuf.h" +#include "snprintf_compat.h" +#include "strdup_compat.h" + +/* Avoid ctype.h and locale overhead */ +#define is_plain_digit(c) ((c) >= '0' && (c) <= '9') + +#if SIZEOF_LONG_LONG != SIZEOF_INT64_T +#error The long long type is not 64-bits +#endif + +#ifndef SSIZE_T_MAX +#if SIZEOF_SSIZE_T == SIZEOF_INT +#define SSIZE_T_MAX INT_MAX +#elif SIZEOF_SSIZE_T == SIZEOF_LONG +#define SSIZE_T_MAX LONG_MAX +#elif SIZEOF_SSIZE_T == SIZEOF_LONG_LONG +#define SSIZE_T_MAX LLONG_MAX +#else +#error Unable to determine size of ssize_t +#endif +#endif + +const char *json_hex_chars = "0123456789abcdefABCDEF"; + +static void json_object_generic_delete(struct json_object *jso); + +#if defined(_MSC_VER) && (_MSC_VER <= 1800) +/* VS2013 doesn't know about "inline" */ +#define inline __inline +#elif defined(AIX_CC) +#define inline +#endif + +/* + * Helper functions to more safely cast to a particular type of json_object + */ +static inline struct json_object_object *JC_OBJECT(struct json_object *jso) +{ + return (void *)jso; +} +static inline const struct json_object_object *JC_OBJECT_C(const struct json_object *jso) +{ + return (const void *)jso; +} +static inline struct json_object_array *JC_ARRAY(struct json_object *jso) +{ + return (void *)jso; +} +static inline const struct json_object_array *JC_ARRAY_C(const struct json_object *jso) +{ + return (const void *)jso; +} +static inline struct json_object_boolean *JC_BOOL(struct json_object *jso) +{ + return (void *)jso; +} +static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object *jso) +{ + return (const void *)jso; +} +static inline struct json_object_double *JC_DOUBLE(struct json_object *jso) +{ + return (void *)jso; +} +static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object *jso) +{ + return (const void *)jso; +} +static inline struct json_object_int *JC_INT(struct json_object *jso) +{ + return (void *)jso; +} +static inline const struct json_object_int *JC_INT_C(const struct json_object *jso) +{ + return (const void *)jso; +} +static inline struct json_object_string *JC_STRING(struct json_object *jso) +{ + return (void *)jso; +} +static inline const struct json_object_string *JC_STRING_C(const struct json_object *jso) +{ + return (const void *)jso; +} + +#define JC_CONCAT(a, b) a##b +#define JC_CONCAT3(a, b, c) a##b##c + +#define JSON_OBJECT_NEW(jtype) \ + (struct JC_CONCAT(json_object_, jtype) *)json_object_new( \ + JC_CONCAT(json_type_, jtype), sizeof(struct JC_CONCAT(json_object_, jtype)), \ + &JC_CONCAT3(json_object_, jtype, _to_json_string)) + +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, + json_object_to_json_string_fn *to_json_string); + +static void json_object_object_delete(struct json_object *jso_base); +static void json_object_string_delete(struct json_object *jso); +static void json_object_array_delete(struct json_object *jso); + +static json_object_to_json_string_fn json_object_object_to_json_string; +static json_object_to_json_string_fn json_object_boolean_to_json_string; +static json_object_to_json_string_fn json_object_double_to_json_string_default; +static json_object_to_json_string_fn json_object_int_to_json_string; +static json_object_to_json_string_fn json_object_string_to_json_string; +static json_object_to_json_string_fn json_object_array_to_json_string; +static json_object_to_json_string_fn _json_object_userdata_to_json_string; + +#ifndef JSON_NORETURN +#if defined(_MSC_VER) +#define JSON_NORETURN __declspec(noreturn) +#elif defined(__OS400__) +#define JSON_NORETURN +#else +/* 'cold' attribute is for optimization, telling the computer this code + * path is unlikely. + */ +#define JSON_NORETURN __attribute__((noreturn, cold)) +#endif +#endif +/** + * Abort and optionally print a message on standard error. + * This should be used rather than assert() for unconditional abortion + * (in particular for code paths which are never supposed to be run). + * */ +JSON_NORETURN static void json_abort(const char *message); + +/* helper for accessing the optimized string data component in json_object + */ +static inline char *get_string_component_mutable(struct json_object *jso) +{ + if (JC_STRING_C(jso)->len < 0) + { + /* Due to json_object_set_string(), we might have a pointer */ + return JC_STRING(jso)->c_string.pdata; + } + return JC_STRING(jso)->c_string.idata; +} +static inline const char *get_string_component(const struct json_object *jso) +{ + return get_string_component_mutable((void *)(uintptr_t)(const void *)jso); +} + +/* string escaping */ + +static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int flags) +{ + size_t pos = 0, start_offset = 0; + unsigned char c; + while (len) + { + --len; + c = str[pos]; + switch (c) + { + case '\b': + case '\n': + case '\r': + case '\t': + case '\f': + case '"': + case '\\': + case '/': + if ((flags & JSON_C_TO_STRING_NOSLASHESCAPE) && c == '/') + { + pos++; + break; + } + + if (pos > start_offset) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + + if (c == '\b') + printbuf_memappend(pb, "\\b", 2); + else if (c == '\n') + printbuf_memappend(pb, "\\n", 2); + else if (c == '\r') + printbuf_memappend(pb, "\\r", 2); + else if (c == '\t') + printbuf_memappend(pb, "\\t", 2); + else if (c == '\f') + printbuf_memappend(pb, "\\f", 2); + else if (c == '"') + printbuf_memappend(pb, "\\\"", 2); + else if (c == '\\') + printbuf_memappend(pb, "\\\\", 2); + else if (c == '/') + printbuf_memappend(pb, "\\/", 2); + + start_offset = ++pos; + break; + default: + if (c < ' ') + { + char sbuf[7]; + if (pos > start_offset) + printbuf_memappend(pb, str + start_offset, + pos - start_offset); + snprintf(sbuf, sizeof(sbuf), "\\u00%c%c", json_hex_chars[c >> 4], + json_hex_chars[c & 0xf]); + printbuf_memappend_fast(pb, sbuf, (int)sizeof(sbuf) - 1); + start_offset = ++pos; + } + else + pos++; + } + } + if (pos > start_offset) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + return 0; +} + +/* reference counting */ + +struct json_object *json_object_get(struct json_object *jso) +{ + if (!jso) + return jso; + + // Don't overflow the refcounter. + assert(jso->_ref_count < UINT32_MAX); + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + __sync_add_and_fetch(&jso->_ref_count, 1); +#else + ++jso->_ref_count; +#endif + + return jso; +} + +int json_object_put(struct json_object *jso) +{ + if (!jso) + return 0; + + /* Avoid invalid free and crash explicitly instead of (silently) + * segfaulting. + */ + assert(jso->_ref_count > 0); + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + /* Note: this only allow the refcount to remain correct + * when multiple threads are adjusting it. It is still an error + * for a thread to decrement the refcount if it doesn't "own" it, + * as that can result in the thread that loses the race to 0 + * operating on an already-freed object. + */ + if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) + return 0; +#else + if (--jso->_ref_count > 0) + return 0; +#endif + + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + switch (jso->o_type) + { + case json_type_object: json_object_object_delete(jso); break; + case json_type_array: json_object_array_delete(jso); break; + case json_type_string: json_object_string_delete(jso); break; + default: json_object_generic_delete(jso); break; + } + return 1; +} + +/* generic object construction and destruction parts */ + +static void json_object_generic_delete(struct json_object *jso) +{ + printbuf_free(jso->_pb); + free(jso); +} + +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, + json_object_to_json_string_fn *to_json_string) +{ + struct json_object *jso; + + jso = (struct json_object *)malloc(alloc_size); + if (!jso) + return NULL; + + jso->o_type = o_type; + jso->_ref_count = 1; + jso->_to_json_string = to_json_string; + jso->_pb = NULL; + jso->_user_delete = NULL; + jso->_userdata = NULL; + //jso->... // Type-specific fields must be set by caller + + return jso; +} + +/* type checking functions */ + +int json_object_is_type(const struct json_object *jso, enum json_type type) +{ + if (!jso) + return (type == json_type_null); + return (jso->o_type == type); +} + +enum json_type json_object_get_type(const struct json_object *jso) +{ + if (!jso) + return json_type_null; + return jso->o_type; +} + +void *json_object_get_userdata(json_object *jso) +{ + return jso ? jso->_userdata : NULL; +} + +void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) +{ + // Can't return failure, so abort if we can't perform the operation. + assert(jso != NULL); + + // First, clean up any previously existing user info + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + + jso->_userdata = userdata; + jso->_user_delete = user_delete; +} + +/* set a custom conversion to string */ + +void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, + void *userdata, json_object_delete_fn *user_delete) +{ + json_object_set_userdata(jso, userdata, user_delete); + + if (to_string_func == NULL) + { + // Reset to the standard serialization function + switch (jso->o_type) + { + case json_type_null: jso->_to_json_string = NULL; break; + case json_type_boolean: + jso->_to_json_string = &json_object_boolean_to_json_string; + break; + case json_type_double: + jso->_to_json_string = &json_object_double_to_json_string_default; + break; + case json_type_int: jso->_to_json_string = &json_object_int_to_json_string; break; + case json_type_object: + jso->_to_json_string = &json_object_object_to_json_string; + break; + case json_type_array: + jso->_to_json_string = &json_object_array_to_json_string; + break; + case json_type_string: + jso->_to_json_string = &json_object_string_to_json_string; + break; + } + return; + } + + jso->_to_json_string = to_string_func; +} + +/* extended conversion to string */ + +const char *json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) +{ + const char *r = NULL; + size_t s = 0; + + if (!jso) + { + s = 4; + r = "null"; + } + else if ((jso->_pb) || (jso->_pb = printbuf_new())) + { + printbuf_reset(jso->_pb); + + if (jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) + { + s = (size_t)jso->_pb->bpos; + r = jso->_pb->buf; + } + } + + if (length) + *length = s; + return r; +} + +const char *json_object_to_json_string_ext(struct json_object *jso, int flags) +{ + return json_object_to_json_string_length(jso, flags, NULL); +} + +/* backwards-compatible conversion to string */ + +const char *json_object_to_json_string(struct json_object *jso) +{ + return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); +} + +static void indent(struct printbuf *pb, int level, int flags) +{ + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (flags & JSON_C_TO_STRING_PRETTY_TAB) + { + printbuf_memset(pb, -1, '\t', level); + } + else + { + printbuf_memset(pb, -1, ' ', level * 2); + } + } +} + +/* json_object_object */ + +static int json_object_object_to_json_string(struct json_object *jso, struct printbuf *pb, + int level, int flags) +{ + int had_children = 0; + struct json_object_iter iter; + + printbuf_strappend(pb, "{" /*}*/); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + json_object_object_foreachC(jso, iter) + { + if (had_children) + { + printbuf_strappend(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) + printbuf_strappend(pb, " "); + indent(pb, level + 1, flags); + printbuf_strappend(pb, "\""); + json_escape_str(pb, iter.key, strlen(iter.key), flags); + if (flags & JSON_C_TO_STRING_SPACED) + printbuf_strappend(pb, "\": "); + else + printbuf_strappend(pb, "\":"); + if (iter.val == NULL) + printbuf_strappend(pb, "null"); + else if (iter.val->_to_json_string(iter.val, pb, level + 1, flags) < 0) + return -1; + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + printbuf_strappend(pb, "\n"); + indent(pb, level, flags); + } + if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) + return printbuf_strappend(pb, /*{*/ " }"); + else + return printbuf_strappend(pb, /*{*/ "}"); +} + +static void json_object_lh_entry_free(struct lh_entry *ent) +{ + if (!lh_entry_k_is_constant(ent)) + free(lh_entry_k(ent)); + json_object_put((struct json_object *)lh_entry_v(ent)); +} + +static void json_object_object_delete(struct json_object *jso_base) +{ + lh_table_free(JC_OBJECT(jso_base)->c_object); + json_object_generic_delete(jso_base); +} + +struct json_object *json_object_new_object(void) +{ + struct json_object_object *jso = JSON_OBJECT_NEW(object); + if (!jso) + return NULL; + jso->c_object = + lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); + if (!jso->c_object) + { + json_object_generic_delete(&jso->base); + errno = ENOMEM; + return NULL; + } + return &jso->base; +} + +struct lh_table *json_object_get_object(const struct json_object *jso) +{ + if (!jso) + return NULL; + switch (jso->o_type) + { + case json_type_object: return JC_OBJECT_C(jso)->c_object; + default: return NULL; + } +} + +int json_object_object_add_ex(struct json_object *jso, const char *const key, + struct json_object *const val, const unsigned opts) +{ + struct json_object *existing_value = NULL; + struct lh_entry *existing_entry; + unsigned long hash; + + assert(json_object_get_type(jso) == json_type_object); + + // We lookup the entry and replace the value, rather than just deleting + // and re-adding it, so the existing key remains valid. + hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)key); + existing_entry = + (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) + ? NULL + : lh_table_lookup_entry_w_hash(JC_OBJECT(jso)->c_object, (const void *)key, hash); + + // The caller must avoid creating loops in the object tree, but do a + // quick check anyway to make sure we're not creating a trivial loop. + if (jso == val) + return -1; + + if (!existing_entry) + { + const void *const k = + (opts & JSON_C_OBJECT_ADD_CONSTANT_KEY) ? (const void *)key : strdup(key); + if (k == NULL) + return -1; + return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts); + } + existing_value = (json_object *)lh_entry_v(existing_entry); + if (existing_value) + json_object_put(existing_value); + lh_entry_set_val(existing_entry, val); + return 0; +} + +int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val) +{ + return json_object_object_add_ex(jso, key, val, 0); +} + +int json_object_object_length(const struct json_object *jso) +{ + assert(json_object_get_type(jso) == json_type_object); + return lh_table_length(JC_OBJECT_C(jso)->c_object); +} + +size_t json_c_object_sizeof(void) +{ + return sizeof(struct json_object); +} + +struct json_object *json_object_object_get(const struct json_object *jso, const char *key) +{ + struct json_object *result = NULL; + json_object_object_get_ex(jso, key, &result); + return result; +} + +json_bool json_object_object_get_ex(const struct json_object *jso, const char *key, + struct json_object **value) +{ + if (value != NULL) + *value = NULL; + + if (NULL == jso) + return 0; + + switch (jso->o_type) + { + case json_type_object: + return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, + (void **)value); + default: + if (value != NULL) + *value = NULL; + return 0; + } +} + +void json_object_object_del(struct json_object *jso, const char *key) +{ + assert(json_object_get_type(jso) == json_type_object); + lh_table_delete(JC_OBJECT(jso)->c_object, key); +} + +/* json_object_boolean */ + +static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, + int level, int flags) +{ + if (JC_BOOL(jso)->c_boolean) + return printbuf_strappend(pb, "true"); + return printbuf_strappend(pb, "false"); +} + +struct json_object *json_object_new_boolean(json_bool b) +{ + struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean); + if (!jso) + return NULL; + jso->c_boolean = b; + return &jso->base; +} + +json_bool json_object_get_boolean(const struct json_object *jso) +{ + if (!jso) + return 0; + switch (jso->o_type) + { + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; + case json_type_int: + switch (JC_INT_C(jso)->cint_type) + { + case json_object_int_type_int64: return (JC_INT_C(jso)->cint.c_int64 != 0); + case json_object_int_type_uint64: return (JC_INT_C(jso)->cint.c_uint64 != 0); + default: json_abort("invalid cint_type"); + } + case json_type_double: return (JC_DOUBLE_C(jso)->c_double != 0); + case json_type_string: return (JC_STRING_C(jso)->len != 0); + default: return 0; + } +} + +int json_object_set_boolean(struct json_object *jso, json_bool new_value) +{ + if (!jso || jso->o_type != json_type_boolean) + return 0; + JC_BOOL(jso)->c_boolean = new_value; + return 1; +} + +/* json_object_int */ + +static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, + int flags) +{ + /* room for 19 digits, the sign char, and a null term */ + char sbuf[21]; + if (JC_INT(jso)->cint_type == json_object_int_type_int64) + snprintf(sbuf, sizeof(sbuf), "%" PRId64, JC_INT(jso)->cint.c_int64); + else + snprintf(sbuf, sizeof(sbuf), "%" PRIu64, JC_INT(jso)->cint.c_uint64); + return printbuf_memappend(pb, sbuf, strlen(sbuf)); +} + +struct json_object *json_object_new_int(int32_t i) +{ + return json_object_new_int64(i); +} + +int32_t json_object_get_int(const struct json_object *jso) +{ + int64_t cint64 = 0; + double cdouble; + enum json_type o_type; + + if (!jso) + return 0; + + o_type = jso->o_type; + if (o_type == json_type_int) + { + const struct json_object_int *jsoint = JC_INT_C(jso); + if (jsoint->cint_type == json_object_int_type_int64) + { + cint64 = jsoint->cint.c_int64; + } + else + { + if (jsoint->cint.c_uint64 >= INT64_MAX) + cint64 = INT64_MAX; + else + cint64 = (int64_t)jsoint->cint.c_uint64; + } + } + else if (o_type == json_type_string) + { + /* + * Parse strings into 64-bit numbers, then use the + * 64-to-32-bit number handling below. + */ + if (json_parse_int64(get_string_component(jso), &cint64) != 0) + return 0; /* whoops, it didn't work. */ + o_type = json_type_int; + } + + switch (o_type) + { + case json_type_int: + /* Make sure we return the correct values for out of range numbers. */ + if (cint64 <= INT32_MIN) + return INT32_MIN; + if (cint64 >= INT32_MAX) + return INT32_MAX; + return (int32_t)cint64; + case json_type_double: + cdouble = JC_DOUBLE_C(jso)->c_double; + if (cdouble <= INT32_MIN) + return INT32_MIN; + if (cdouble >= INT32_MAX) + return INT32_MAX; + return (int32_t)cdouble; + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; + default: return 0; + } +} + +int json_object_set_int(struct json_object *jso, int new_value) +{ + return json_object_set_int64(jso, (int64_t)new_value); +} + +struct json_object *json_object_new_int64(int64_t i) +{ + struct json_object_int *jso = JSON_OBJECT_NEW(int); + if (!jso) + return NULL; + jso->cint.c_int64 = i; + jso->cint_type = json_object_int_type_int64; + return &jso->base; +} + +struct json_object *json_object_new_uint64(uint64_t i) +{ + struct json_object_int *jso = JSON_OBJECT_NEW(int); + if (!jso) + return NULL; + jso->cint.c_uint64 = i; + jso->cint_type = json_object_int_type_uint64; + return &jso->base; +} + +int64_t json_object_get_int64(const struct json_object *jso) +{ + int64_t cint; + + if (!jso) + return 0; + switch (jso->o_type) + { + case json_type_int: + { + const struct json_object_int *jsoint = JC_INT_C(jso); + switch (jsoint->cint_type) + { + case json_object_int_type_int64: return jsoint->cint.c_int64; + case json_object_int_type_uint64: + if (jsoint->cint.c_uint64 >= INT64_MAX) + return INT64_MAX; + return (int64_t)jsoint->cint.c_uint64; + default: json_abort("invalid cint_type"); + } + } + case json_type_double: + // INT64_MAX can't be exactly represented as a double + // so cast to tell the compiler it's ok to round up. + if (JC_DOUBLE_C(jso)->c_double >= (double)INT64_MAX) + return INT64_MAX; + if (JC_DOUBLE_C(jso)->c_double <= INT64_MIN) + return INT64_MIN; + return (int64_t)JC_DOUBLE_C(jso)->c_double; + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; + case json_type_string: + if (json_parse_int64(get_string_component(jso), &cint) == 0) + return cint; + /* FALLTHRU */ + default: return 0; + } +} + +uint64_t json_object_get_uint64(const struct json_object *jso) +{ + uint64_t cuint; + + if (!jso) + return 0; + switch (jso->o_type) + { + case json_type_int: + { + const struct json_object_int *jsoint = JC_INT_C(jso); + switch (jsoint->cint_type) + { + case json_object_int_type_int64: + if (jsoint->cint.c_int64 < 0) + return 0; + return (uint64_t)jsoint->cint.c_int64; + case json_object_int_type_uint64: return jsoint->cint.c_uint64; + default: json_abort("invalid cint_type"); + } + } + case json_type_double: + // UINT64_MAX can't be exactly represented as a double + // so cast to tell the compiler it's ok to round up. + if (JC_DOUBLE_C(jso)->c_double >= (double)UINT64_MAX) + return UINT64_MAX; + if (JC_DOUBLE_C(jso)->c_double < 0) + return 0; + return (uint64_t)JC_DOUBLE_C(jso)->c_double; + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; + case json_type_string: + if (json_parse_uint64(get_string_component(jso), &cuint) == 0) + return cuint; + /* FALLTHRU */ + default: return 0; + } +} + +int json_object_set_int64(struct json_object *jso, int64_t new_value) +{ + if (!jso || jso->o_type != json_type_int) + return 0; + JC_INT(jso)->cint.c_int64 = new_value; + JC_INT(jso)->cint_type = json_object_int_type_int64; + return 1; +} + +int json_object_set_uint64(struct json_object *jso, uint64_t new_value) +{ + if (!jso || jso->o_type != json_type_int) + return 0; + JC_INT(jso)->cint.c_uint64 = new_value; + JC_INT(jso)->cint_type = json_object_int_type_uint64; + return 1; +} + +int json_object_int_inc(struct json_object *jso, int64_t val) +{ + struct json_object_int *jsoint; + if (!jso || jso->o_type != json_type_int) + return 0; + jsoint = JC_INT(jso); + switch (jsoint->cint_type) + { + case json_object_int_type_int64: + if (val > 0 && jsoint->cint.c_int64 > INT64_MAX - val) + { + jsoint->cint.c_uint64 = (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; + jsoint->cint_type = json_object_int_type_uint64; + } + else if (val < 0 && jsoint->cint.c_int64 < INT64_MIN - val) + { + jsoint->cint.c_int64 = INT64_MIN; + } + else + { + jsoint->cint.c_int64 += val; + } + return 1; + case json_object_int_type_uint64: + if (val > 0 && jsoint->cint.c_uint64 > UINT64_MAX - (uint64_t)val) + { + jsoint->cint.c_uint64 = UINT64_MAX; + } + else if (val < 0 && jsoint->cint.c_uint64 < (uint64_t)(-val)) + { + jsoint->cint.c_int64 = (int64_t)jsoint->cint.c_uint64 + val; + jsoint->cint_type = json_object_int_type_int64; + } + else if (val < 0 && jsoint->cint.c_uint64 >= (uint64_t)(-val)) + { + jsoint->cint.c_uint64 -= (uint64_t)(-val); + } + else + { + jsoint->cint.c_uint64 += val; + } + return 1; + default: json_abort("invalid cint_type"); + } +} + +/* json_object_double */ + +#if defined(HAVE___THREAD) +// i.e. __thread or __declspec(thread) +static SPEC___THREAD char *tls_serialization_float_format = NULL; +#endif +static char *global_serialization_float_format = NULL; + +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread) +{ + if (global_or_thread == JSON_C_OPTION_GLOBAL) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } +#endif + if (global_serialization_float_format) + free(global_serialization_float_format); + if (double_format) + { + char *p = strdup(double_format); + if (p == NULL) + { + _json_c_set_last_err("json_c_set_serialization_double_format: " + "out of memory\n"); + return -1; + } + global_serialization_float_format = p; + } + else + { + global_serialization_float_format = NULL; + } + } + else if (global_or_thread == JSON_C_OPTION_THREAD) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } + if (double_format) + { + char *p = strdup(double_format); + if (p == NULL) + { + _json_c_set_last_err("json_c_set_serialization_double_format: " + "out of memory\n"); + return -1; + } + tls_serialization_float_format = p; + } + else + { + tls_serialization_float_format = NULL; + } +#else + _json_c_set_last_err("json_c_set_serialization_double_format: not compiled " + "with __thread support\n"); + return -1; +#endif + } + else + { + _json_c_set_last_err("json_c_set_serialization_double_format: invalid " + "global_or_thread value: %d\n", global_or_thread); + return -1; + } + return 0; +} + +static int json_object_double_to_json_string_format(struct json_object *jso, struct printbuf *pb, + int level, int flags, const char *format) +{ + struct json_object_double *jsodbl = JC_DOUBLE(jso); + char buf[128], *p, *q; + int size; + /* Although JSON RFC does not support + * NaN or Infinity as numeric values + * ECMA 262 section 9.8.1 defines + * how to handle these cases as strings + */ + if (isnan(jsodbl->c_double)) + { + size = snprintf(buf, sizeof(buf), "NaN"); + } + else if (isinf(jsodbl->c_double)) + { + if (jsodbl->c_double > 0) + size = snprintf(buf, sizeof(buf), "Infinity"); + else + size = snprintf(buf, sizeof(buf), "-Infinity"); + } + else + { + const char *std_format = "%.17g"; + int format_drops_decimals = 0; + int looks_numeric = 0; + + if (!format) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + format = tls_serialization_float_format; + else +#endif + if (global_serialization_float_format) + format = global_serialization_float_format; + else + format = std_format; + } + size = snprintf(buf, sizeof(buf), format, jsodbl->c_double); + + if (size < 0) + return -1; + + p = strchr(buf, ','); + if (p) + *p = '.'; + else + p = strchr(buf, '.'); + + if (format == std_format || strstr(format, ".0f") == NULL) + format_drops_decimals = 1; + + looks_numeric = /* Looks like *some* kind of number */ + is_plain_digit(buf[0]) || (size > 1 && buf[0] == '-' && is_plain_digit(buf[1])); + + if (size < (int)sizeof(buf) - 2 && looks_numeric && !p && /* Has no decimal point */ + strchr(buf, 'e') == NULL && /* Not scientific notation */ + format_drops_decimals) + { + // Ensure it looks like a float, even if snprintf didn't, + // unless a custom format is set to omit the decimal. + strcat(buf, ".0"); + size += 2; + } + if (p && (flags & JSON_C_TO_STRING_NOZERO)) + { + /* last useful digit, always keep 1 zero */ + p++; + for (q = p; *q; q++) + { + if (*q != '0') + p = q; + } + /* drop trailing zeroes */ + if (*p != 0) + *(++p) = 0; + size = p - buf; + } + } + // although unlikely, snprintf can fail + if (size < 0) + return -1; + + if (size >= (int)sizeof(buf)) + // The standard formats are guaranteed not to overrun the buffer, + // but if a custom one happens to do so, just silently truncate. + size = sizeof(buf) - 1; + printbuf_memappend(pb, buf, size); + return size; +} + +static int json_object_double_to_json_string_default(struct json_object *jso, struct printbuf *pb, + int level, int flags) +{ + return json_object_double_to_json_string_format(jso, pb, level, flags, NULL); +} + +int json_object_double_to_json_string(struct json_object *jso, struct printbuf *pb, int level, + int flags) +{ + return json_object_double_to_json_string_format(jso, pb, level, flags, + (const char *)jso->_userdata); +} + +struct json_object *json_object_new_double(double d) +{ + struct json_object_double *jso = JSON_OBJECT_NEW(double); + if (!jso) + return NULL; + jso->base._to_json_string = &json_object_double_to_json_string_default; + jso->c_double = d; + return &jso->base; +} + +struct json_object *json_object_new_double_s(double d, const char *ds) +{ + char *new_ds; + struct json_object *jso = json_object_new_double(d); + if (!jso) + return NULL; + + new_ds = strdup(ds); + if (!new_ds) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + json_object_set_serializer(jso, _json_object_userdata_to_json_string, new_ds, + json_object_free_userdata); + return jso; +} + +/* + * A wrapper around json_object_userdata_to_json_string() used only + * by json_object_new_double_s() just so json_object_set_double() can + * detect when it needs to reset the serializer to the default. + */ +static int _json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, + int level, int flags) +{ + return json_object_userdata_to_json_string(jso, pb, level, flags); +} + +int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, + int flags) +{ + int userdata_len = strlen((const char *)jso->_userdata); + printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); + return userdata_len; +} + +void json_object_free_userdata(struct json_object *jso, void *userdata) +{ + free(userdata); +} + +double json_object_get_double(const struct json_object *jso) +{ + double cdouble; + char *errPtr = NULL; + + if (!jso) + return 0.0; + switch (jso->o_type) + { + case json_type_double: return JC_DOUBLE_C(jso)->c_double; + case json_type_int: + switch (JC_INT_C(jso)->cint_type) + { + case json_object_int_type_int64: return JC_INT_C(jso)->cint.c_int64; + case json_object_int_type_uint64: return JC_INT_C(jso)->cint.c_uint64; + default: json_abort("invalid cint_type"); + } + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; + case json_type_string: + errno = 0; + cdouble = strtod(get_string_component(jso), &errPtr); + + /* if conversion stopped at the first character, return 0.0 */ + if (errPtr == get_string_component(jso)) + { + errno = EINVAL; + return 0.0; + } + + /* + * Check that the conversion terminated on something sensible + * + * For example, { "pay" : 123AB } would parse as 123. + */ + if (*errPtr != '\0') + { + errno = EINVAL; + return 0.0; + } + + /* + * If strtod encounters a string which would exceed the + * capacity of a double, it returns +/- HUGE_VAL and sets + * errno to ERANGE. But +/- HUGE_VAL is also a valid result + * from a conversion, so we need to check errno. + * + * Underflow also sets errno to ERANGE, but it returns 0 in + * that case, which is what we will return anyway. + * + * See CERT guideline ERR30-C + */ + if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) && (ERANGE == errno)) + cdouble = 0.0; + return cdouble; + default: errno = EINVAL; return 0.0; + } +} + +int json_object_set_double(struct json_object *jso, double new_value) +{ + if (!jso || jso->o_type != json_type_double) + return 0; + JC_DOUBLE(jso)->c_double = new_value; + if (jso->_to_json_string == &_json_object_userdata_to_json_string) + json_object_set_serializer(jso, NULL, NULL, NULL); + return 1; +} + +/* json_object_string */ + +static int json_object_string_to_json_string(struct json_object *jso, struct printbuf *pb, + int level, int flags) +{ + ssize_t len = JC_STRING(jso)->len; + printbuf_strappend(pb, "\""); + json_escape_str(pb, get_string_component(jso), len < 0 ? -(ssize_t)len : len, flags); + printbuf_strappend(pb, "\""); + return 0; +} + +static void json_object_string_delete(struct json_object *jso) +{ + if (JC_STRING(jso)->len < 0) + free(JC_STRING(jso)->c_string.pdata); + json_object_generic_delete(jso); +} + +static struct json_object *_json_object_new_string(const char *s, const size_t len) +{ + size_t objsize; + struct json_object_string *jso; + + /* + * Structures Actual memory layout + * ------------------- -------------------- + * [json_object_string [json_object_string + * [json_object] [json_object] + * ...other fields... ...other fields... + * c_string] len + * bytes + * of + * string + * data + * \0] + */ + if (len > (SSIZE_T_MAX - (sizeof(*jso) - sizeof(jso->c_string)) - 1)) + return NULL; + objsize = (sizeof(*jso) - sizeof(jso->c_string)) + len + 1; + if (len < sizeof(void *)) + // We need a minimum size to support json_object_set_string() mutability + // so we can stuff a pointer into pdata :( + objsize += sizeof(void *) - len; + + jso = (struct json_object_string *)json_object_new(json_type_string, objsize, + &json_object_string_to_json_string); + + if (!jso) + return NULL; + jso->len = len; + memcpy(jso->c_string.idata, s, len); + // Cast below needed for Clang UB sanitizer + ((char *)jso->c_string.idata)[len] = '\0'; + return &jso->base; +} + +struct json_object *json_object_new_string(const char *s) +{ + return _json_object_new_string(s, strlen(s)); +} + +struct json_object *json_object_new_string_len(const char *s, const int len) +{ + return _json_object_new_string(s, len); +} + +const char *json_object_get_string(struct json_object *jso) +{ + if (!jso) + return NULL; + switch (jso->o_type) + { + case json_type_string: return get_string_component(jso); + default: return json_object_to_json_string(jso); + } +} + +static inline ssize_t _json_object_get_string_len(const struct json_object_string *jso) +{ + ssize_t len; + len = jso->len; + return (len < 0) ? -(ssize_t)len : len; +} +int json_object_get_string_len(const struct json_object *jso) +{ + if (!jso) + return 0; + switch (jso->o_type) + { + case json_type_string: return _json_object_get_string_len(JC_STRING_C(jso)); + default: return 0; + } +} + +static int _json_object_set_string_len(json_object *jso, const char *s, size_t len) +{ + char *dstbuf; + ssize_t curlen; + ssize_t newlen; + if (jso == NULL || jso->o_type != json_type_string) + return 0; + + if (len >= INT_MAX - 1) + // jso->len is a signed ssize_t, so it can't hold the + // full size_t range. json_object_get_string_len returns + // length as int, cap length at INT_MAX. + return 0; + + dstbuf = get_string_component_mutable(jso); + curlen = JC_STRING(jso)->len; + if (curlen < 0) + curlen = -curlen; + newlen = len; + + if ((ssize_t)len > curlen) + { + // We have no way to return the new ptr from realloc(jso, newlen) + // and we have no way of knowing whether there's extra room available + // so we need to stuff a pointer in to pdata :( + dstbuf = (char *)malloc(len + 1); + if (dstbuf == NULL) + return 0; + if (JC_STRING(jso)->len < 0) + free(JC_STRING(jso)->c_string.pdata); + JC_STRING(jso)->c_string.pdata = dstbuf; + newlen = -(ssize_t)len; + } + else if (JC_STRING(jso)->len < 0) + { + // We've got enough room in the separate allocated buffer, + // so use it as-is and continue to indicate that pdata is used. + newlen = -(ssize_t)len; + } + + memcpy(dstbuf, (const void *)s, len); + dstbuf[len] = '\0'; + JC_STRING(jso)->len = newlen; + return 1; +} + +int json_object_set_string(json_object *jso, const char *s) +{ + return _json_object_set_string_len(jso, s, strlen(s)); +} + +int json_object_set_string_len(json_object *jso, const char *s, int len) +{ + return _json_object_set_string_len(jso, s, len); +} + +/* json_object_array */ + +static int json_object_array_to_json_string(struct json_object *jso, struct printbuf *pb, int level, + int flags) +{ + int had_children = 0; + size_t ii; + + printbuf_strappend(pb, "["); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + for (ii = 0; ii < json_object_array_length(jso); ii++) + { + struct json_object *val; + if (had_children) + { + printbuf_strappend(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) + printbuf_strappend(pb, " "); + indent(pb, level + 1, flags); + val = json_object_array_get_idx(jso, ii); + if (val == NULL) + printbuf_strappend(pb, "null"); + else if (val->_to_json_string(val, pb, level + 1, flags) < 0) + return -1; + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + printbuf_strappend(pb, "\n"); + indent(pb, level, flags); + } + + if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) + return printbuf_strappend(pb, " ]"); + return printbuf_strappend(pb, "]"); +} + +static void json_object_array_entry_free(void *data) +{ + json_object_put((struct json_object *)data); +} + +static void json_object_array_delete(struct json_object *jso) +{ + array_list_free(JC_ARRAY(jso)->c_array); + json_object_generic_delete(jso); +} + +struct json_object *json_object_new_array(void) +{ + return json_object_new_array_ext(ARRAY_LIST_DEFAULT_SIZE); +} +struct json_object *json_object_new_array_ext(int initial_size) +{ + struct json_object_array *jso = JSON_OBJECT_NEW(array); + if (!jso) + return NULL; + jso->c_array = array_list_new2(&json_object_array_entry_free, initial_size); + if (jso->c_array == NULL) + { + free(jso); + return NULL; + } + return &jso->base; +} + +struct array_list *json_object_get_array(const struct json_object *jso) +{ + if (!jso) + return NULL; + switch (jso->o_type) + { + case json_type_array: return JC_ARRAY_C(jso)->c_array; + default: return NULL; + } +} + +void json_object_array_sort(struct json_object *jso, int (*sort_fn)(const void *, const void *)) +{ + assert(json_object_get_type(jso) == json_type_array); + array_list_sort(JC_ARRAY(jso)->c_array, sort_fn); +} + +struct json_object *json_object_array_bsearch(const struct json_object *key, + const struct json_object *jso, + int (*sort_fn)(const void *, const void *)) +{ + struct json_object **result; + + assert(json_object_get_type(jso) == json_type_array); + result = (struct json_object **)array_list_bsearch((const void **)(void *)&key, + JC_ARRAY_C(jso)->c_array, sort_fn); + + if (!result) + return NULL; + return *result; +} + +size_t json_object_array_length(const struct json_object *jso) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_length(JC_ARRAY_C(jso)->c_array); +} + +int json_object_array_add(struct json_object *jso, struct json_object *val) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_add(JC_ARRAY(jso)->c_array, val); +} + +int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_put_idx(JC_ARRAY(jso)->c_array, idx, val); +} + +int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_del_idx(JC_ARRAY(jso)->c_array, idx, count); +} + +struct json_object *json_object_array_get_idx(const struct json_object *jso, size_t idx) +{ + assert(json_object_get_type(jso) == json_type_array); + return (struct json_object *)array_list_get_idx(JC_ARRAY_C(jso)->c_array, idx); +} + +static int json_array_equal(struct json_object *jso1, struct json_object *jso2) +{ + size_t len, i; + + len = json_object_array_length(jso1); + if (len != json_object_array_length(jso2)) + return 0; + + for (i = 0; i < len; i++) + { + if (!json_object_equal(json_object_array_get_idx(jso1, i), + json_object_array_get_idx(jso2, i))) + return 0; + } + return 1; +} + +int json_object_array_shrink(struct json_object *jso, int empty_slots) +{ + if (empty_slots < 0) + json_abort("json_object_array_shrink called with negative empty_slots"); + return array_list_shrink(JC_ARRAY(jso)->c_array, empty_slots); +} + +struct json_object *json_object_new_null(void) +{ + return NULL; +} + +static int json_object_all_values_equal(struct json_object *jso1, struct json_object *jso2) +{ + struct json_object_iter iter; + struct json_object *sub; + + assert(json_object_get_type(jso1) == json_type_object); + assert(json_object_get_type(jso2) == json_type_object); + /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ + json_object_object_foreachC(jso1, iter) + { + if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, + (void **)(void *)&sub)) + return 0; + if (!json_object_equal(iter.val, sub)) + return 0; + } + + /* Iterate over jso2 keys to see if any exist that are not in jso1 */ + json_object_object_foreachC(jso2, iter) + { + if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, + (void **)(void *)&sub)) + return 0; + } + + return 1; +} + +int json_object_equal(struct json_object *jso1, struct json_object *jso2) +{ + if (jso1 == jso2) + return 1; + + if (!jso1 || !jso2) + return 0; + + if (jso1->o_type != jso2->o_type) + return 0; + + switch (jso1->o_type) + { + case json_type_boolean: return (JC_BOOL(jso1)->c_boolean == JC_BOOL(jso2)->c_boolean); + + case json_type_double: return (JC_DOUBLE(jso1)->c_double == JC_DOUBLE(jso2)->c_double); + + case json_type_int: + { + struct json_object_int *int1 = JC_INT(jso1); + struct json_object_int *int2 = JC_INT(jso2); + if (int1->cint_type == json_object_int_type_int64) + { + if (int2->cint_type == json_object_int_type_int64) + return (int1->cint.c_int64 == int2->cint.c_int64); + if (int1->cint.c_int64 < 0) + return 0; + return ((uint64_t)int1->cint.c_int64 == int2->cint.c_uint64); + } + // else jso1 is a uint64 + if (int2->cint_type == json_object_int_type_uint64) + return (int1->cint.c_uint64 == int2->cint.c_uint64); + if (int2->cint.c_int64 < 0) + return 0; + return (int1->cint.c_uint64 == (uint64_t)int2->cint.c_int64); + } + + case json_type_string: + { + return (_json_object_get_string_len(JC_STRING(jso1)) == + _json_object_get_string_len(JC_STRING(jso2)) && + memcmp(get_string_component(jso1), get_string_component(jso2), + _json_object_get_string_len(JC_STRING(jso1))) == 0); + } + + case json_type_object: return json_object_all_values_equal(jso1, jso2); + + case json_type_array: return json_array_equal(jso1, jso2); + + case json_type_null: return 1; + }; + + return 0; +} + +static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) +{ + if (!src->_userdata && !src->_user_delete) + return 0; + + if (dst->_to_json_string == json_object_userdata_to_json_string || + dst->_to_json_string == _json_object_userdata_to_json_string) + { + char *p; + assert(src->_userdata); + p = strdup(src->_userdata); + if (p == NULL) + { + _json_c_set_last_err("json_object_copy_serializer_data: out of memory\n"); + return -1; + } + dst->_userdata = p; + } + // else if ... other supported serializers ... + else + { + _json_c_set_last_err( + "json_object_copy_serializer_data: unable to copy unknown serializer data: " + "%p\n", (void *)dst->_to_json_string); + return -1; + } + dst->_user_delete = src->_user_delete; + return 0; +} + +/** + * The default shallow copy implementation. Simply creates a new object of the same + * type but does *not* copy over _userdata nor retain any custom serializer. + * If custom serializers are in use, json_object_deep_copy() must be passed a shallow copy + * implementation that is aware of how to copy them. + * + * This always returns -1 or 1. It will never return 2 since it does not copy the serializer. + */ +int json_c_shallow_copy_default(json_object *src, json_object *parent, const char *key, + size_t index, json_object **dst) +{ + switch (src->o_type) + { + case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; + + case json_type_double: *dst = json_object_new_double(JC_DOUBLE(src)->c_double); break; + + case json_type_int: + switch (JC_INT(src)->cint_type) + { + case json_object_int_type_int64: + *dst = json_object_new_int64(JC_INT(src)->cint.c_int64); + break; + case json_object_int_type_uint64: + *dst = json_object_new_uint64(JC_INT(src)->cint.c_uint64); + break; + default: json_abort("invalid cint_type"); + } + break; + + case json_type_string: + *dst = json_object_new_string_len(get_string_component(src), + _json_object_get_string_len(JC_STRING(src))); + break; + + case json_type_object: *dst = json_object_new_object(); break; + + case json_type_array: *dst = json_object_new_array(); break; + + default: errno = EINVAL; return -1; + } + + if (!*dst) + { + errno = ENOMEM; + return -1; + } + (*dst)->_to_json_string = src->_to_json_string; + // _userdata and _user_delete are copied later + return 1; +} + +/* + * The actual guts of json_object_deep_copy(), with a few additional args + * needed so we can keep track of where we are within the object tree. + * + * Note: caller is responsible for freeing *dst if this fails and returns -1. + */ +static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, + const char *key_in_parent, size_t index_in_parent, + struct json_object **dst, + json_c_shallow_copy_fn *shallow_copy) +{ + struct json_object_iter iter; + size_t src_array_len, ii; + + int shallow_copy_rc = 0; + shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); + /* -1=error, 1=object created ok, 2=userdata set */ + if (shallow_copy_rc < 1) + { + errno = EINVAL; + return -1; + } + assert(*dst != NULL); + + switch (src->o_type) + { + case json_type_object: + json_object_object_foreachC(src, iter) + { + struct json_object *jso = NULL; + /* This handles the `json_type_null` case */ + if (!iter.val) + jso = NULL; + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, UINT_MAX, + &jso, shallow_copy) < 0) + { + json_object_put(jso); + return -1; + } + + if (json_object_object_add(*dst, iter.key, jso) < 0) + { + json_object_put(jso); + return -1; + } + } + break; + + case json_type_array: + src_array_len = json_object_array_length(src); + for (ii = 0; ii < src_array_len; ii++) + { + struct json_object *jso = NULL; + struct json_object *jso1 = json_object_array_get_idx(src, ii); + /* This handles the `json_type_null` case */ + if (!jso1) + jso = NULL; + else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, + shallow_copy) < 0) + { + json_object_put(jso); + return -1; + } + + if (json_object_array_add(*dst, jso) < 0) + { + json_object_put(jso); + return -1; + } + } + break; + + default: + break; + /* else, nothing to do, shallow_copy already did. */ + } + + if (shallow_copy_rc != 2) + return json_object_copy_serializer_data(src, *dst); + + return 0; +} + +int json_object_deep_copy(struct json_object *src, struct json_object **dst, + json_c_shallow_copy_fn *shallow_copy) +{ + int rc; + + /* Check if arguments are sane ; *dst must not point to a non-NULL object */ + if (!src || !dst || *dst) + { + errno = EINVAL; + return -1; + } + + if (shallow_copy == NULL) + shallow_copy = json_c_shallow_copy_default; + + rc = json_object_deep_copy_recursive(src, NULL, NULL, UINT_MAX, dst, shallow_copy); + if (rc < 0) + { + json_object_put(*dst); + *dst = NULL; + } + + return rc; +} + +static void json_abort(const char *message) +{ + if (message != NULL) + fprintf(stderr, "json-c aborts with error: %s\n", message); + abort(); +} diff --git a/comm/third_party/json-c/json_object.h b/comm/third_party/json-c/json_object.h new file mode 100644 index 0000000000..e22392f39c --- /dev/null +++ b/comm/third_party/json-c/json_object.h @@ -0,0 +1,1077 @@ +/* + * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Core json-c API. Start here, or with json_tokener.h + */ +#ifndef _json_object_h_ +#define _json_object_h_ + +#ifdef __GNUC__ +#define JSON_C_CONST_FUNCTION(func) func __attribute__((const)) +#else +#define JSON_C_CONST_FUNCTION(func) func +#endif + +#include "json_inttypes.h" +#include "json_types.h" +#include "printbuf.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_OBJECT_DEF_HASH_ENTRIES 16 + +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output + * to have no extra whitespace or formatting applied. + */ +#define JSON_C_TO_STRING_PLAIN 0 +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output to have + * minimal whitespace inserted to make things slightly more readable. + */ +#define JSON_C_TO_STRING_SPACED (1 << 0) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * See the "Two Space Tab" option at https://jsonformatter.curiousconcept.com/ + * for an example of the format. + */ +#define JSON_C_TO_STRING_PRETTY (1 << 1) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * Instead of a "Two Space Tab" this gives a single tab character. + */ +#define JSON_C_TO_STRING_PRETTY_TAB (1 << 3) +/** + * A flag to drop trailing zero for float values + */ +#define JSON_C_TO_STRING_NOZERO (1 << 2) + +/** + * Don't escape forward slashes. + */ +#define JSON_C_TO_STRING_NOSLASHESCAPE (1 << 4) + +/** + * A flag for the json_object_object_add_ex function which + * causes the value to be added without a check if it already exists. + * Note: it is the responsibility of the caller to ensure that no + * key is added multiple times. If this is done, results are + * unpredictable. While this option is somewhat dangerous, it + * permits potentially large performance savings in code that + * knows for sure the key values are unique (e.g. because the + * code adds a well-known set of constant key values). + */ +#define JSON_C_OBJECT_ADD_KEY_IS_NEW (1 << 1) +/** + * A flag for the json_object_object_add_ex function which + * flags the key as being constant memory. This means that + * the key will NOT be copied via strdup(), resulting in a + * potentially huge performance win (malloc, strdup and + * free are usually performance hogs). It is acceptable to + * use this flag for keys in non-constant memory blocks if + * the caller ensure that the memory holding the key lives + * longer than the corresponding json object. However, this + * is somewhat dangerous and should only be done if really + * justified. + * The general use-case for this flag is cases where the + * key is given as a real constant value in the function + * call, e.g. as in + * json_object_object_add_ex(obj, "ip", json, + * JSON_C_OBJECT_ADD_CONSTANT_KEY); + */ +#define JSON_C_OBJECT_ADD_CONSTANT_KEY (1 << 2) +/** + * This flag is an alias to JSON_C_OBJECT_ADD_CONSTANT_KEY. + * Historically, this flag was used first and the new name + * JSON_C_OBJECT_ADD_CONSTANT_KEY was introduced for version + * 0.16.00 in order to have regular naming. + * Use of this flag is now legacy. + */ +#define JSON_C_OBJECT_KEY_IS_CONSTANT JSON_C_OBJECT_ADD_CONSTANT_KEY + +/** + * Set the global value of an option, which will apply to all + * current and future threads that have not set a thread-local value. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_GLOBAL (0) +/** + * Set a thread-local value of an option, overriding the global value. + * This will fail if json-c is not compiled with threading enabled, and + * with the __thread specifier (or equivalent) available. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_THREAD (1) + +/* reference counting functions */ + +/** + * Increment the reference count of json_object, thereby taking ownership of it. + * + * Cases where you might need to increase the refcount include: + * - Using an object field or array index (retrieved through + * `json_object_object_get()` or `json_object_array_get_idx()`) + * beyond the lifetime of the parent object. + * - Detaching an object field or array index from its parent object + * (using `json_object_object_del()` or `json_object_array_del_idx()`) + * - Sharing a json_object with multiple (not necessarily parallel) threads + * of execution that all expect to free it (with `json_object_put()`) when + * they're done. + * + * @param obj the json_object instance + * @see json_object_put() + * @see json_object_object_get() + * @see json_object_array_get_idx() + */ +JSON_EXPORT struct json_object *json_object_get(struct json_object *obj); + +/** + * Decrement the reference count of json_object and free if it reaches zero. + * + * You must have ownership of obj prior to doing this or you will cause an + * imbalance in the reference count, leading to a classic use-after-free bug. + * In particular, you normally do not need to call `json_object_put()` on the + * json_object returned by `json_object_object_get()` or `json_object_array_get_idx()`. + * + * Just like after calling `free()` on a block of memory, you must not use + * `obj` after calling `json_object_put()` on it or any object that it + * is a member of (unless you know you've called `json_object_get(obj)` to + * explicitly increment the refcount). + * + * NULL may be passed, which which case this is a no-op. + * + * @param obj the json_object instance + * @returns 1 if the object was freed. + * @see json_object_get() + */ +JSON_EXPORT int json_object_put(struct json_object *obj); + +/** + * Check if the json_object is of a given type + * @param obj the json_object instance + * @param type one of: + json_type_null (i.e. obj == NULL), + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string + */ +JSON_EXPORT int json_object_is_type(const struct json_object *obj, enum json_type type); + +/** + * Get the type of the json_object. See also json_type_to_name() to turn this + * into a string suitable, for instance, for logging. + * + * @param obj the json_object instance + * @returns type being one of: + json_type_null (i.e. obj == NULL), + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string + */ +JSON_EXPORT enum json_type json_object_get_type(const struct json_object *obj); + +/** Stringify object to json format. + * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) + * The pointer you get is an internal of your json object. You don't + * have to free it, later use of json_object_put() should be sufficient. + * If you can not ensure there's no concurrent access to *obj use + * strdup(). + * @param obj the json_object instance + * @returns a string in JSON format + */ +JSON_EXPORT const char *json_object_to_json_string(struct json_object *obj); + +/** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @returns a string in JSON format + */ +JSON_EXPORT const char *json_object_to_json_string_ext(struct json_object *obj, int flags); + +/** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @param length a pointer where, if not NULL, the length (without null) is stored + * @returns a string in JSON format and the length if not NULL + */ +JSON_EXPORT const char *json_object_to_json_string_length(struct json_object *obj, int flags, + size_t *length); + +/** + * Returns the userdata set by json_object_set_userdata() or + * json_object_set_serializer() + * + * @param jso the object to return the userdata for + */ +JSON_EXPORT void *json_object_get_userdata(json_object *jso); + +/** + * Set an opaque userdata value for an object + * + * The userdata can be retrieved using json_object_get_userdata(). + * + * If custom userdata is already set on this object, any existing user_delete + * function is called before the new one is set. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * Note: Objects created by parsing strings may have custom serializers set + * which expect the userdata to contain specific data (due to use of + * json_object_new_double_s()). In this case, json_object_set_serialiser() with + * NULL as to_string_func should be used instead to set the userdata and reset + * the serializer to its default value. + * + * @param jso the object to set the userdata for + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +JSON_EXPORT void json_object_set_userdata(json_object *jso, void *userdata, + json_object_delete_fn *user_delete); + +/** + * Set a custom serialization function to be used when this particular object + * is converted to a string by json_object_to_json_string. + * + * If custom userdata is already set on this object, any existing user_delete + * function is called before the new one is set. + * + * If to_string_func is NULL the default behaviour is reset (but the userdata + * and user_delete fields are still set). + * + * The userdata parameter is optional and may be passed as NULL. It can be used + * to provide additional data for to_string_func to use. This parameter may + * be NULL even if user_delete is non-NULL. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * Note that the userdata is the same as set by json_object_set_userdata(), so + * care must be taken not to overwrite the value when both a custom serializer + * and json_object_set_userdata() are used. + * + * @param jso the object to customize + * @param to_string_func the custom serialization function + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +JSON_EXPORT void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn *to_string_func, + void *userdata, json_object_delete_fn *user_delete); + +#ifdef __clang__ +/* + * Clang doesn't pay attention to the parameters defined in the + * function typedefs used here, so turn off spurious doc warnings. + * { + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif + +/** + * Simply call free on the userdata pointer. + * Can be used with json_object_set_serializer(). + * + * @param jso unused + * @param userdata the pointer that is passed to free(). + */ +JSON_EXPORT json_object_delete_fn json_object_free_userdata; + +/** + * Copy the jso->_userdata string over to pb as-is. + * Can be used with json_object_set_serializer(). + * + * @param jso The object whose _userdata is used. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +JSON_EXPORT json_object_to_json_string_fn json_object_userdata_to_json_string; + +#ifdef __clang__ +/* } */ +#pragma clang diagnostic pop +#endif + +/* object type methods */ + +/** Create a new empty object with a reference count of 1. The caller of + * this object initially has sole ownership. Remember, when using + * json_object_object_add or json_object_array_put_idx, ownership will + * transfer to the object/array. Call json_object_get if you want to maintain + * shared ownership or also add this object as a child of multiple objects or + * arrays. Any ownerships you acquired but did not transfer must be released + * through json_object_put. + * + * @returns a json_object of type json_type_object + */ +JSON_EXPORT struct json_object *json_object_new_object(void); + +/** Get the hashtable of a json_object of type json_type_object + * @param obj the json_object instance + * @returns a linkhash + */ +JSON_EXPORT struct lh_table *json_object_get_object(const struct json_object *obj); + +/** Get the size of an object in terms of the number of fields it has. + * @param obj the json_object whose length to return + */ +JSON_EXPORT int json_object_object_length(const struct json_object *obj); + +/** Get the sizeof (struct json_object). + * @returns a size_t with the sizeof (struct json_object) + */ +JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void)); + +/** Add an object field to a json_object of type json_type_object + * + * The reference count of `val` will *not* be incremented, in effect + * transferring ownership that object to `obj`, and thus `val` will be + * freed when `obj` is. (i.e. through `json_object_put(obj)`) + * + * If you want to retain a reference to the added object, independent + * of the lifetime of obj, you must increment the refcount with + * `json_object_get(val)` (and later release it with json_object_put()). + * + * Since ownership transfers to `obj`, you must make sure + * that you do in fact have ownership over `val`. For instance, + * json_object_new_object() will give you ownership until you transfer it, + * whereas json_object_object_get() does not. + * + * Any previous object stored under `key` in `obj` will have its refcount + * decremented, and be freed normally if that drops to zero. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +JSON_EXPORT int json_object_object_add(struct json_object *obj, const char *key, + struct json_object *val); + +/** Add an object field to a json_object of type json_type_object + * + * The semantics are identical to json_object_object_add, except that an + * additional flag fields gives you more control over some detail aspects + * of processing. See the description of JSON_C_OBJECT_ADD_* flags for more + * details. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + * @param opts process-modifying options. To specify multiple options, use + * (OPT1|OPT2) + */ +JSON_EXPORT int json_object_object_add_ex(struct json_object *obj, const char *const key, + struct json_object *const val, const unsigned opts); + +/** Get the json_object associate with a given object field. + * Deprecated/discouraged: used json_object_object_get_ex instead. + * + * This returns NULL if the field is found but its value is null, or if + * the field is not found, or if obj is not a json_type_object. If you + * need to distinguish between these cases, use json_object_object_get_ex(). + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of the returned value is retained + * by obj (do not do json_object_put unless you have done a json_object_get). + * If you delete the value from obj (json_object_object_del) and wish to access + * the returned reference afterwards, make sure you have first gotten shared + * ownership through json_object_get (& don't forget to do a json_object_put + * or transfer ownership to prevent a memory leak). + * + * @param obj the json_object instance + * @param key the object field name + * @returns the json_object associated with the given field name + */ +JSON_EXPORT struct json_object *json_object_object_get(const struct json_object *obj, + const char *key); + +/** Get the json_object associated with a given object field. + * + * This returns true if the key is found, false in all other cases (including + * if obj isn't a json_type_object). + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of value is retained by obj. + * + * @param obj the json_object instance + * @param key the object field name + * @param value a pointer where to store a reference to the json_object + * associated with the given field name. + * + * It is safe to pass a NULL value. + * @returns whether or not the key exists + */ +JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, const char *key, + struct json_object **value); + +/** Delete the given json_object field + * + * The reference count will be decremented for the deleted object. If there + * are no more owners of the value represented by this key, then the value is + * freed. Otherwise, the reference to the value will remain in memory. + * + * @param obj the json_object instance + * @param key the object field name + */ +JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key); + +/** + * Iterate through all keys and values of an object. + * + * Adding keys to the object while iterating is NOT allowed. + * + * Deleting an existing key, or replacing an existing key with a + * new value IS allowed. + * + * @param obj the json_object instance + * @param key the local name for the char* key variable defined in the body + * @param val the local name for the json_object* object variable defined in + * the body + */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) + +#define json_object_object_foreach(obj, key, val) \ + char *key = NULL; \ + struct json_object *val __attribute__((__unused__)) = NULL; \ + for (struct lh_entry *entry##key = lh_table_head(json_object_get_object(obj)), \ + *entry_next##key = NULL; \ + ({ \ + if (entry##key) \ + { \ + key = (char *)lh_entry_k(entry##key); \ + val = (struct json_object *)lh_entry_v(entry##key); \ + entry_next##key = lh_entry_next(entry##key); \ + }; \ + entry##key; \ + }); \ + entry##key = entry_next##key) + +#else /* ANSI C or MSC */ + +#define json_object_object_foreach(obj, key, val) \ + char *key = NULL; \ + struct json_object *val = NULL; \ + struct lh_entry *entry##key; \ + struct lh_entry *entry_next##key = NULL; \ + for (entry##key = lh_table_head(json_object_get_object(obj)); \ + (entry##key ? (key = (char *)lh_entry_k(entry##key), \ + val = (struct json_object *)lh_entry_v(entry##key), \ + entry_next##key = lh_entry_next(entry##key), entry##key) \ + : 0); \ + entry##key = entry_next##key) + +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) */ + +/** Iterate through all keys and values of an object (ANSI C Safe) + * @param obj the json_object instance + * @param iter the object iterator, use type json_object_iter + */ +#define json_object_object_foreachC(obj, iter) \ + for (iter.entry = lh_table_head(json_object_get_object(obj)); \ + (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ + iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ + : 0); \ + iter.entry = lh_entry_next(iter.entry)) + +/* Array type methods */ + +/** Create a new empty json_object of type json_type_array + * with 32 slots allocated. + * If you know the array size you'll need ahead of time, use + * json_object_new_array_ext() instead. + * @see json_object_new_array_ext() + * @see json_object_array_shrink() + * @returns a json_object of type json_type_array + */ +JSON_EXPORT struct json_object *json_object_new_array(void); + +/** Create a new empty json_object of type json_type_array + * with the desired number of slots allocated. + * @see json_object_array_shrink() + * @param initial_size the number of slots to allocate + * @returns a json_object of type json_type_array + */ +JSON_EXPORT struct json_object *json_object_new_array_ext(int initial_size); + +/** Get the arraylist of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an arraylist + */ +JSON_EXPORT struct array_list *json_object_get_array(const struct json_object *obj); + +/** Get the length of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an int + */ +JSON_EXPORT size_t json_object_array_length(const struct json_object *obj); + +/** Sorts the elements of jso of type json_type_array +* +* Pointers to the json_object pointers will be passed as the two arguments +* to sort_fn +* +* @param jso the json_object instance +* @param sort_fn a sorting function +*/ +JSON_EXPORT void json_object_array_sort(struct json_object *jso, + int (*sort_fn)(const void *, const void *)); + +/** Binary search a sorted array for a specified key object. + * + * It depends on your compare function what's sufficient as a key. + * Usually you create some dummy object with the parameter compared in + * it, to identify the right item you're actually looking for. + * + * @see json_object_array_sort() for hints on the compare function. + * + * @param key a dummy json_object with the right key + * @param jso the array object we're searching + * @param sort_fn the sort/compare function + * + * @return the wanted json_object instance + */ +JSON_EXPORT struct json_object * +json_object_array_bsearch(const struct json_object *key, const struct json_object *jso, + int (*sort_fn)(const void *, const void *)); + +/** Add an element to the end of a json_object of type json_type_array + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * @param obj the json_object instance + * @param val the json_object to be added + */ +JSON_EXPORT int json_object_array_add(struct json_object *obj, struct json_object *val); + +/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * The reference count of a replaced object will be decremented. + * + * The array size will be automatically be expanded to the size of the + * index if the index is larger than the current size. + * + * @param obj the json_object instance + * @param idx the index to insert the element at + * @param val the json_object to be added + */ +JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, + struct json_object *val); + +/** Get the element at specified index of array `obj` (which must be a json_object of type json_type_array) + * + * *No* reference counts will be changed, and ownership of the returned + * object remains with `obj`. See json_object_object_get() for additional + * implications of this behavior. + * + * Calling this with anything other than a json_type_array will trigger + * an assert. + * + * @param obj the json_object instance + * @param idx the index to get the element at + * @returns the json_object at the specified index (or NULL) + */ +JSON_EXPORT struct json_object *json_object_array_get_idx(const struct json_object *obj, + size_t idx); + +/** Delete an elements from a specified index in an array (a json_object of type json_type_array) + * + * The reference count will be decremented for each of the deleted objects. If there + * are no more owners of an element that is being deleted, then the value is + * freed. Otherwise, the reference to the value will remain in memory. + * + * @param obj the json_object instance + * @param idx the index to start deleting elements at + * @param count the number of elements to delete + * @returns 0 if the elements were successfully deleted + */ +JSON_EXPORT int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t count); + +/** + * Shrink the internal memory allocation of the array to just + * enough to fit the number of elements in it, plus empty_slots. + * + * @param jso the json_object instance, must be json_type_array + * @param empty_slots the number of empty slots to leave allocated + */ +JSON_EXPORT int json_object_array_shrink(struct json_object *jso, int empty_slots); + +/* json_bool type methods */ + +/** Create a new empty json_object of type json_type_boolean + * @param b a json_bool 1 or 0 + * @returns a json_object of type json_type_boolean + */ +JSON_EXPORT struct json_object *json_object_new_boolean(json_bool b); + +/** Get the json_bool value of a json_object + * + * The type is coerced to a json_bool if the passed object is not a json_bool. + * integer and double objects will return 0 if there value is zero + * or 1 otherwise. If the passed object is a string it will return + * 1 if it has a non zero length. + * If any other object type is passed 0 will be returned, even non-empty + * json_type_array and json_type_object objects. + * + * @param obj the json_object instance + * @returns a json_bool + */ +JSON_EXPORT json_bool json_object_get_boolean(const struct json_object *obj); + +/** Set the json_bool value of a json_object + * + * The type of obj is checked to be a json_type_boolean and 0 is returned + * if it is not without any further actions. If type of obj is json_type_boolean + * the object value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_boolean(struct json_object *obj, json_bool new_value); + +/* int type methods */ + +/** Create a new empty json_object of type json_type_int + * Note that values are stored as 64-bit values internally. + * To ensure the full range is maintained, use json_object_new_int64 instead. + * @param i the integer + * @returns a json_object of type json_type_int + */ +JSON_EXPORT struct json_object *json_object_new_int(int32_t i); + +/** Create a new empty json_object of type json_type_int + * @param i the integer + * @returns a json_object of type json_type_int + */ +JSON_EXPORT struct json_object *json_object_new_int64(int64_t i); + +/** Create a new empty json_object of type json_type_uint + * @param i the integer + * @returns a json_object of type json_type_uint + */ +JSON_EXPORT struct json_object *json_object_new_uint64(uint64_t i); + +/** Get the int value of a json_object + * + * The type is coerced to a int if the passed object is not a int. + * double objects will return their integer conversion. Strings will be + * parsed as an integer. If no conversion exists then 0 is returned + * and errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * Note that integers are stored internally as 64-bit values. + * If the value of too big or too small to fit into 32-bit, INT32_MAX or + * INT32_MIN are returned, respectively. + * + * @param obj the json_object instance + * @returns an int + */ +JSON_EXPORT int32_t json_object_get_int(const struct json_object *obj); + +/** Set the int value of a json_object + * + * The type of obj is checked to be a json_type_int and 0 is returned + * if it is not without any further actions. If type of obj is json_type_int + * the object value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_int(struct json_object *obj, int new_value); + +/** Increment a json_type_int object by the given amount, which may be negative. + * + * If the type of obj is not json_type_int then 0 is returned with no further + * action taken. + * If the addition would result in a overflow, the object value + * is set to INT64_MAX. + * If the addition would result in a underflow, the object value + * is set to INT64_MIN. + * Neither overflow nor underflow affect the return value. + * + * @param obj the json_object instance + * @param val the value to add + * @returns 1 if the increment succeeded, 0 otherwise + */ +JSON_EXPORT int json_object_int_inc(struct json_object *obj, int64_t val); + +/** Get the int value of a json_object + * + * The type is coerced to a int64 if the passed object is not a int64. + * double objects will return their int64 conversion. Strings will be + * parsed as an int64. If no conversion exists then 0 is returned. + * + * NOTE: Set errno to 0 directly before a call to this function to determine + * whether or not conversion was successful (it does not clear the value for + * you). + * + * @param obj the json_object instance + * @returns an int64 + */ +JSON_EXPORT int64_t json_object_get_int64(const struct json_object *obj); + +/** Get the uint value of a json_object + * + * The type is coerced to a uint64 if the passed object is not a uint64. + * double objects will return their uint64 conversion. Strings will be + * parsed as an uint64. If no conversion exists then 0 is returned. + * + * NOTE: Set errno to 0 directly before a call to this function to determine + * whether or not conversion was successful (it does not clear the value for + * you). + * + * @param obj the json_object instance + * @returns an uint64 + */ +JSON_EXPORT uint64_t json_object_get_uint64(const struct json_object *obj); + +/** Set the int64_t value of a json_object + * + * The type of obj is checked to be a json_type_int and 0 is returned + * if it is not without any further actions. If type of obj is json_type_int + * the object value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_int64(struct json_object *obj, int64_t new_value); + +/** Set the uint64_t value of a json_object + * + * The type of obj is checked to be a json_type_uint and 0 is returned + * if it is not without any further actions. If type of obj is json_type_uint + * the object value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_uint64(struct json_object *obj, uint64_t new_value); + +/* double type methods */ + +/** Create a new empty json_object of type json_type_double + * + * @see json_object_double_to_json_string() for how to set a custom format string. + * + * @param d the double + * @returns a json_object of type json_type_double + */ +JSON_EXPORT struct json_object *json_object_new_double(double d); + +/** + * Create a new json_object of type json_type_double, using + * the exact serialized representation of the value. + * + * This allows for numbers that would otherwise get displayed + * inefficiently (e.g. 12.3 => "12.300000000000001") to be + * serialized with the more convenient form. + * + * Notes: + * + * This is used by json_tokener_parse_ex() to allow for + * an exact re-serialization of a parsed object. + * + * The userdata field is used to store the string representation, so it + * can't be used for other data if this function is used. + * + * A roughly equivalent sequence of calls, with the difference being that + * the serialization function won't be reset by json_object_set_double(), is: + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(jso, json_object_userdata_to_json_string, + * strdup(ds), json_object_free_userdata); + * @endcode + * + * @param d the numeric value of the double. + * @param ds the string representation of the double. This will be copied. + */ +JSON_EXPORT struct json_object *json_object_new_double_s(double d, const char *ds); + +/** + * Set a global or thread-local json-c option, depending on whether + * JSON_C_OPTION_GLOBAL or JSON_C_OPTION_THREAD is passed. + * Thread-local options default to undefined, and inherit from the global + * value, even if the global value is changed after the thread is created. + * Attempting to set thread-local options when threading is not compiled in + * will result in an error. Be sure to check the return value. + * + * double_format is a "%g" printf format, such as "%.20g" + * + * @return -1 on errors, 0 on success. + */ +JSON_EXPORT int json_c_set_serialization_double_format(const char *double_format, + int global_or_thread); + +/** Serialize a json_object of type json_type_double to a string. + * + * This function isn't meant to be called directly. Instead, you can set a + * custom format string for the serialization of this double using the + * following call (where "%.17g" actually is the default): + * + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(jso, json_object_double_to_json_string, + * "%.17g", NULL); + * @endcode + * + * @see printf(3) man page for format strings + * + * @param jso The json_type_double object that is serialized. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +JSON_EXPORT int json_object_double_to_json_string(struct json_object *jso, struct printbuf *pb, + int level, int flags); + +/** Get the double floating point value of a json_object + * + * The type is coerced to a double if the passed object is not a double. + * integer objects will return their double conversion. Strings will be + * parsed as a double. If no conversion exists then 0.0 is returned and + * errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * If the value is too big to fit in a double, then the value is set to + * the closest infinity with errno set to ERANGE. If strings cannot be + * converted to their double value, then EINVAL is set & NaN is returned. + * + * Arrays of length 0 are interpreted as 0 (with no error flags set). + * Arrays of length 1 are effectively cast to the equivalent object and + * converted using the above rules. All other arrays set the error to + * EINVAL & return NaN. + * + * NOTE: Set errno to 0 directly before a call to this function to + * determine whether or not conversion was successful (it does not clear + * the value for you). + * + * @param obj the json_object instance + * @returns a double floating point number + */ +JSON_EXPORT double json_object_get_double(const struct json_object *obj); + +/** Set the double value of a json_object + * + * The type of obj is checked to be a json_type_double and 0 is returned + * if it is not without any further actions. If type of obj is json_type_double + * the object value is changed to new_value + * + * If the object was created with json_object_new_double_s(), the serialization + * function is reset to the default and the cached serialized value is cleared. + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_double(struct json_object *obj, double new_value); + +/* string type methods */ + +/** Create a new empty json_object of type json_type_string + * + * A copy of the string is made and the memory is managed by the json_object + * + * @param s the string + * @returns a json_object of type json_type_string + * @see json_object_new_string_len() + */ +JSON_EXPORT struct json_object *json_object_new_string(const char *s); + +/** Create a new empty json_object of type json_type_string and allocate + * len characters for the new string. + * + * A copy of the string is made and the memory is managed by the json_object + * + * @param s the string + * @param len max length of the new string + * @returns a json_object of type json_type_string + * @see json_object_new_string() + */ +JSON_EXPORT struct json_object *json_object_new_string_len(const char *s, const int len); + +/** Get the string value of a json_object + * + * If the passed object is of type json_type_null (i.e. obj == NULL), + * NULL is returned. + * + * If the passed object of type json_type_string, the string contents + * are returned. + * + * Otherwise the JSON representation of the object is returned. + * + * The returned string memory is managed by the json_object and will + * be freed when the reference count of the json_object drops to zero. + * + * @param obj the json_object instance + * @returns a string or NULL + */ +JSON_EXPORT const char *json_object_get_string(struct json_object *obj); + +/** Get the string length of a json_object + * + * If the passed object is not of type json_type_string then zero + * will be returned. + * + * @param obj the json_object instance + * @returns int + */ +JSON_EXPORT int json_object_get_string_len(const struct json_object *obj); + +/** Set the string value of a json_object with zero terminated strings + * equivalent to json_object_set_string_len (obj, new_value, strlen(new_value)) + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_string(json_object *obj, const char *new_value); + +/** Set the string value of a json_object str + * + * The type of obj is checked to be a json_type_string and 0 is returned + * if it is not without any further actions. If type of obj is json_type_string + * the object value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set; Since string length is given in len this need not be zero terminated + * @param len the length of new_value + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_string_len(json_object *obj, const char *new_value, int len); + +/** This method exists only to provide a complementary function + * along the lines of the other json_object_new_* functions. + * It always returns NULL, and it is entirely acceptable to simply use NULL directly. + */ +JSON_EXPORT struct json_object *json_object_new_null(void); + +/** Check if two json_object's are equal + * + * If the passed objects are equal 1 will be returned. + * Equality is defined as follows: + * - json_objects of different types are never equal + * - json_objects of the same primitive type are equal if the + * c-representation of their value is equal + * - json-arrays are considered equal if all values at the same + * indices are equal (same order) + * - Complex json_objects are considered equal if all + * contained objects referenced by their key are equal, + * regardless their order. + * + * @param obj1 the first json_object instance + * @param obj2 the second json_object instance + * @returns whether both objects are equal or not + */ +JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *obj2); + +/** + * Perform a shallow copy of src into *dst as part of an overall json_object_deep_copy(). + * + * If src is part of a containing object or array, parent will be non-NULL, + * and key or index will be provided. + * When shallow_copy is called *dst will be NULL, and must be non-NULL when it returns. + * src will never be NULL. + * + * If shallow_copy sets the serializer on an object, return 2 to indicate to + * json_object_deep_copy that it should not attempt to use the standard userdata + * copy function. + * + * @return On success 1 or 2, -1 on errors + */ +typedef int(json_c_shallow_copy_fn)(json_object *src, json_object *parent, const char *key, + size_t index, json_object **dst); + +/** + * The default shallow copy implementation for use with json_object_deep_copy(). + * This simply calls the appropriate json_object_new_() function and + * copies over the serializer function (_to_json_string internal field of + * the json_object structure) but not any _userdata or _user_delete values. + * + * If you're writing a custom shallow_copy function, perhaps because you're using + * your own custom serializer, you can call this first to create the new object + * before customizing it with json_object_set_serializer(). + * + * @return 1 on success, -1 on errors, but never 2. + */ +JSON_EXPORT json_c_shallow_copy_fn json_c_shallow_copy_default; + +/** + * Copy the contents of the JSON object. + * The destination object must be initialized to NULL, + * to make sure this function won't overwrite an existing JSON object. + * + * This does roughly the same thing as + * `json_tokener_parse(json_object_get_string(src))`. + * + * @param src source JSON object whose contents will be copied + * @param dst pointer to the destination object where the contents of `src`; + * make sure this pointer is initialized to NULL + * @param shallow_copy an optional function to copy individual objects, needed + * when custom serializers are in use. See also + * json_object set_serializer. + * + * @returns 0 if the copy went well, -1 if an error occurred during copy + * or if the destination pointer is non-NULL + */ + +JSON_EXPORT int json_object_deep_copy(struct json_object *src, struct json_object **dst, + json_c_shallow_copy_fn *shallow_copy); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_object_iterator.c b/comm/third_party/json-c/json_object_iterator.c new file mode 100644 index 0000000000..db8488ae1e --- /dev/null +++ b/comm/third_party/json-c/json_object_iterator.c @@ -0,0 +1,153 @@ +/** +******************************************************************************* +* @file json_object_iterator.c +* +* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. +* +* This library is free software; you can redistribute it and/or modify +* it under the terms of the MIT license. See COPYING for details. +* +******************************************************************************* +*/ +#include "config.h" + +#include + +#include "json.h" +#include "json_object_private.h" + +#include "json_object_iterator.h" + +/** + * How It Works + * + * For each JSON Object, json-c maintains a linked list of zero + * or more lh_entry (link-hash entry) structures inside the + * Object's link-hash table (lh_table). + * + * Each lh_entry structure on the JSON Object's linked list + * represents a single name/value pair. The "next" field of the + * last lh_entry in the list is set to NULL, which terminates + * the list. + * + * We represent a valid iterator that refers to an actual + * name/value pair via a pointer to the pair's lh_entry + * structure set as the iterator's opaque_ field. + * + * We follow json-c's current pair list representation by + * representing a valid "end" iterator (one that refers past the + * last pair) with a NULL value in the iterator's opaque_ field. + * + * A JSON Object without any pairs in it will have the "head" + * field of its lh_table structure set to NULL. For such an + * object, json_object_iter_begin will return an iterator with + * the opaque_ field set to NULL, which is equivalent to the + * "end" iterator. + * + * When iterating, we simply update the iterator's opaque_ field + * to point to the next lh_entry structure in the linked list. + * opaque_ will become NULL once we iterate past the last pair + * in the list, which makes the iterator equivalent to the "end" + * iterator. + */ + +/// Our current representation of the "end" iterator; +/// +/// @note May not always be NULL +static const void *kObjectEndIterValue = NULL; + +/** + * **************************************************************************** + */ +struct json_object_iterator json_object_iter_begin(struct json_object *obj) +{ + struct json_object_iterator iter; + struct lh_table *pTable; + + /// @note json_object_get_object will return NULL if passed NULL + /// or a non-json_type_object instance + pTable = json_object_get_object(obj); + JASSERT(NULL != pTable); + + /// @note For a pair-less Object, head is NULL, which matches our + /// definition of the "end" iterator + iter.opaque_ = lh_table_head(pTable); + return iter; +} + +/** + * **************************************************************************** + */ +struct json_object_iterator json_object_iter_end(const struct json_object *obj) +{ + struct json_object_iterator iter; + + JASSERT(NULL != obj); + JASSERT(json_object_is_type(obj, json_type_object)); + + iter.opaque_ = kObjectEndIterValue; + + return iter; +} + +/** + * **************************************************************************** + */ +void json_object_iter_next(struct json_object_iterator *iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + iter->opaque_ = lh_entry_next(((const struct lh_entry *)iter->opaque_)); +} + +/** + * **************************************************************************** + */ +const char *json_object_iter_peek_name(const struct json_object_iterator *iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + return (const char *)(((const struct lh_entry *)iter->opaque_)->k); +} + +/** + * **************************************************************************** + */ +struct json_object *json_object_iter_peek_value(const struct json_object_iterator *iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + return (struct json_object *)lh_entry_v((const struct lh_entry *)iter->opaque_); +} + +/** + * **************************************************************************** + */ +json_bool json_object_iter_equal(const struct json_object_iterator *iter1, + const struct json_object_iterator *iter2) +{ + JASSERT(NULL != iter1); + JASSERT(NULL != iter2); + + return (iter1->opaque_ == iter2->opaque_); +} + +/** + * **************************************************************************** + */ +struct json_object_iterator json_object_iter_init_default(void) +{ + struct json_object_iterator iter; + + /** + * @note Make this a negative, invalid value, such that + * accidental access to it would likely be trapped by the + * hardware as an invalid address. + */ + iter.opaque_ = NULL; + + return iter; +} diff --git a/comm/third_party/json-c/json_object_iterator.h b/comm/third_party/json-c/json_object_iterator.h new file mode 100644 index 0000000000..a9b1433c74 --- /dev/null +++ b/comm/third_party/json-c/json_object_iterator.h @@ -0,0 +1,228 @@ +/** +******************************************************************************* +* @file json_object_iterator.h +* +* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. +* +* This library is free software; you can redistribute it and/or modify +* it under the terms of the MIT license. See COPYING for details. +* +* @brief An API for iterating over json_type_object objects, +* styled to be familiar to C++ programmers. +* Unlike json_object_object_foreach() and +* json_object_object_foreachC(), this avoids the need to expose +* json-c internals like lh_entry. +* +* API attributes:
+* * Thread-safe: NO
+* * Reentrant: NO +* +******************************************************************************* +*/ + +#ifndef JSON_OBJECT_ITERATOR_H +#define JSON_OBJECT_ITERATOR_H + +#include "json_types.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Forward declaration for the opaque iterator information. + */ +struct json_object_iter_info_; + +/** + * The opaque iterator that references a name/value pair within + * a JSON Object instance or the "end" iterator value. + */ +struct json_object_iterator +{ + const void *opaque_; +}; + +/** + * forward declaration of json-c's JSON value instance structure + */ +struct json_object; + +/** + * Initializes an iterator structure to a "default" value that + * is convenient for initializing an iterator variable to a + * default state (e.g., initialization list in a class' + * constructor). + * + * @code + * struct json_object_iterator iter = json_object_iter_init_default(); + * MyClass() : iter_(json_object_iter_init_default()) + * @endcode + * + * @note The initialized value doesn't reference any specific + * pair, is considered an invalid iterator, and MUST NOT + * be passed to any json-c API that expects a valid + * iterator. + * + * @note User and internal code MUST NOT make any assumptions + * about and dependencies on the value of the "default" + * iterator value. + * + * @return json_object_iterator + */ +JSON_EXPORT struct json_object_iterator json_object_iter_init_default(void); + +/** Retrieves an iterator to the first pair of the JSON Object. + * + * @warning Any modification of the underlying pair invalidates all + * iterators to that pair. + * + * @param obj JSON Object instance (MUST be of type json_object) + * + * @return json_object_iterator If the JSON Object has at + * least one pair, on return, the iterator refers + * to the first pair. If the JSON Object doesn't + * have any pairs, the returned iterator is + * equivalent to the "end" iterator for the same + * JSON Object instance. + * + * @code + * struct json_object_iterator it; + * struct json_object_iterator itEnd; + * struct json_object* obj; + * + * obj = json_tokener_parse("{'first':'george', 'age':100}"); + * it = json_object_iter_begin(obj); + * itEnd = json_object_iter_end(obj); + * + * while (!json_object_iter_equal(&it, &itEnd)) { + * printf("%s\n", + * json_object_iter_peek_name(&it)); + * json_object_iter_next(&it); + * } + * + * @endcode + */ +JSON_EXPORT struct json_object_iterator json_object_iter_begin(struct json_object *obj); + +/** Retrieves the iterator that represents the position beyond the + * last pair of the given JSON Object instance. + * + * @warning Do NOT write code that assumes that the "end" + * iterator value is NULL, even if it is so in a + * particular instance of the implementation. + * + * @note The reason we do not (and MUST NOT) provide + * "json_object_iter_is_end(json_object_iterator* iter)" + * type of API is because it would limit the underlying + * representation of name/value containment (or force us + * to add additional, otherwise unnecessary, fields to + * the iterator structure). The "end" iterator and the + * equality test method, on the other hand, permit us to + * cleanly abstract pretty much any reasonable underlying + * representation without burdening the iterator + * structure with unnecessary data. + * + * @note For performance reasons, memorize the "end" iterator prior + * to any loop. + * + * @param obj JSON Object instance (MUST be of type json_object) + * + * @return json_object_iterator On return, the iterator refers + * to the "end" of the Object instance's pairs + * (i.e., NOT the last pair, but "beyond the last + * pair" value) + */ +JSON_EXPORT struct json_object_iterator json_object_iter_end(const struct json_object *obj); + +/** Returns an iterator to the next pair, if any + * + * @warning Any modification of the underlying pair + * invalidates all iterators to that pair. + * + * @param iter [IN/OUT] Pointer to iterator that references a + * name/value pair; MUST be a valid, non-end iterator. + * WARNING: bad things will happen if invalid or "end" + * iterator is passed. Upon return will contain the + * reference to the next pair if there is one; if there + * are no more pairs, will contain the "end" iterator + * value, which may be compared against the return value + * of json_object_iter_end() for the same JSON Object + * instance. + */ +JSON_EXPORT void json_object_iter_next(struct json_object_iterator *iter); + +/** Returns a const pointer to the name of the pair referenced + * by the given iterator. + * + * @param iter pointer to iterator that references a name/value + * pair; MUST be a valid, non-end iterator. + * + * @warning bad things will happen if an invalid or + * "end" iterator is passed. + * + * @return const char* Pointer to the name of the referenced + * name/value pair. The name memory belongs to the + * name/value pair, will be freed when the pair is + * deleted or modified, and MUST NOT be modified or + * freed by the user. + */ +JSON_EXPORT const char *json_object_iter_peek_name(const struct json_object_iterator *iter); + +/** Returns a pointer to the json-c instance representing the + * value of the referenced name/value pair, without altering + * the instance's reference count. + * + * @param iter pointer to iterator that references a name/value + * pair; MUST be a valid, non-end iterator. + * + * @warning bad things will happen if invalid or + * "end" iterator is passed. + * + * @return struct json_object* Pointer to the json-c value + * instance of the referenced name/value pair; the + * value's reference count is not changed by this + * function: if you plan to hold on to this json-c node, + * take a look at json_object_get() and + * json_object_put(). IMPORTANT: json-c API represents + * the JSON Null value as a NULL json_object instance + * pointer. + */ +JSON_EXPORT struct json_object * +json_object_iter_peek_value(const struct json_object_iterator *iter); + +/** Tests two iterators for equality. Typically used to test + * for end of iteration by comparing an iterator to the + * corresponding "end" iterator (that was derived from the same + * JSON Object instance). + * + * @note The reason we do not (and MUST NOT) provide + * "json_object_iter_is_end(json_object_iterator* iter)" + * type of API is because it would limit the underlying + * representation of name/value containment (or force us + * to add additional, otherwise unnecessary, fields to + * the iterator structure). The equality test method, on + * the other hand, permits us to cleanly abstract pretty + * much any reasonable underlying representation. + * + * @param iter1 Pointer to first valid, non-NULL iterator + * @param iter2 POinter to second valid, non-NULL iterator + * + * @warning if a NULL iterator pointer or an uninitialized + * or invalid iterator, or iterators derived from + * different JSON Object instances are passed, bad things + * will happen! + * + * @return json_bool non-zero if iterators are equal (i.e., both + * reference the same name/value pair or are both at + * "end"); zero if they are not equal. + */ +JSON_EXPORT json_bool json_object_iter_equal(const struct json_object_iterator *iter1, + const struct json_object_iterator *iter2); + +#ifdef __cplusplus +} +#endif + +#endif /* JSON_OBJECT_ITERATOR_H */ diff --git a/comm/third_party/json-c/json_object_private.h b/comm/third_party/json-c/json_object_private.h new file mode 100644 index 0000000000..e143b4649a --- /dev/null +++ b/comm/third_party/json-c/json_object_private.h @@ -0,0 +1,107 @@ +/* + * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef _json_object_private_h_ +#define _json_object_private_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct json_object; +#include "json_inttypes.h" +#include "json_types.h" + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#endif + +/* json object int type, support extension*/ +typedef enum json_object_int_type +{ + json_object_int_type_int64, + json_object_int_type_uint64 +} json_object_int_type; + +struct json_object +{ + enum json_type o_type; + uint32_t _ref_count; + json_object_to_json_string_fn *_to_json_string; + struct printbuf *_pb; + json_object_delete_fn *_user_delete; + void *_userdata; + // Actually longer, always malloc'd as some more-specific type. + // The rest of a struct json_object_${o_type} follows +}; + +struct json_object_object +{ + struct json_object base; + struct lh_table *c_object; +}; +struct json_object_array +{ + struct json_object base; + struct array_list *c_array; +}; + +struct json_object_boolean +{ + struct json_object base; + json_bool c_boolean; +}; +struct json_object_double +{ + struct json_object base; + double c_double; +}; +struct json_object_int +{ + struct json_object base; + enum json_object_int_type cint_type; + union + { + int64_t c_int64; + uint64_t c_uint64; + } cint; +}; +struct json_object_string +{ + struct json_object base; + ssize_t len; // Signed b/c negative lengths indicate data is a pointer + // Consider adding an "alloc" field here, if json_object_set_string calls + // to expand the length of a string are common operations to perform. + union + { + char idata[1]; // Immediate data. Actually longer + char *pdata; // Only when len < 0 + } c_string; +}; + +void _json_c_set_last_err(const char *err_fmt, ...); + +extern const char *json_hex_chars; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_pointer.c b/comm/third_party/json-c/json_pointer.c new file mode 100644 index 0000000000..395567a5ba --- /dev/null +++ b/comm/third_party/json-c/json_pointer.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2016 Alexandru Ardelean. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include "strerror_override.h" + +#include +#include +#include +#include + +#include "json_pointer.h" +#include "strdup_compat.h" +#include "vasprintf_compat.h" + +/* Avoid ctype.h and locale overhead */ +#define is_plain_digit(c) ((c) >= '0' && (c) <= '9') + +/** + * JavaScript Object Notation (JSON) Pointer + * RFC 6901 - https://tools.ietf.org/html/rfc6901 + */ + +static void string_replace_all_occurrences_with_char(char *s, const char *occur, char repl_char) +{ + int slen = strlen(s); + int skip = strlen(occur) - 1; /* length of the occurrence, minus the char we're replacing */ + char *p = s; + while ((p = strstr(p, occur))) + { + *p = repl_char; + p++; + slen -= skip; + memmove(p, (p + skip), slen - (p - s) + 1); /* includes null char too */ + } +} + +static int is_valid_index(struct json_object *jo, const char *path, int32_t *idx) +{ + int i, len = strlen(path); + /* this code-path optimizes a bit, for when we reference the 0-9 index range + * in a JSON array and because leading zeros not allowed + */ + if (len == 1) + { + if (is_plain_digit(path[0])) + { + *idx = (path[0] - '0'); + goto check_oob; + } + errno = EINVAL; + return 0; + } + /* leading zeros not allowed per RFC */ + if (path[0] == '0') + { + errno = EINVAL; + return 0; + } + /* RFC states base-10 decimals */ + for (i = 0; i < len; i++) + { + if (!is_plain_digit(path[i])) + { + errno = EINVAL; + return 0; + } + } + + *idx = strtol(path, NULL, 10); + if (*idx < 0) + { + errno = EINVAL; + return 0; + } +check_oob: + len = json_object_array_length(jo); + if (*idx >= len) + { + errno = ENOENT; + return 0; + } + + return 1; +} + +static int json_pointer_get_single_path(struct json_object *obj, char *path, + struct json_object **value) +{ + if (json_object_is_type(obj, json_type_array)) + { + int32_t idx; + if (!is_valid_index(obj, path, &idx)) + return -1; + obj = json_object_array_get_idx(obj, idx); + if (obj) + { + if (value) + *value = obj; + return 0; + } + /* Entry not found */ + errno = ENOENT; + return -1; + } + + /* RFC states that we first must eval all ~1 then all ~0 */ + string_replace_all_occurrences_with_char(path, "~1", '/'); + string_replace_all_occurrences_with_char(path, "~0", '~'); + + if (!json_object_object_get_ex(obj, path, value)) + { + errno = ENOENT; + return -1; + } + + return 0; +} + +static int json_pointer_set_single_path(struct json_object *parent, const char *path, + struct json_object *value) +{ + if (json_object_is_type(parent, json_type_array)) + { + int32_t idx; + /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */ + if (path[0] == '-' && path[1] == '\0') + return json_object_array_add(parent, value); + if (!is_valid_index(parent, path, &idx)) + return -1; + return json_object_array_put_idx(parent, idx, value); + } + + /* path replacements should have been done in json_pointer_get_single_path(), + * and we should still be good here + */ + if (json_object_is_type(parent, json_type_object)) + return json_object_object_add(parent, path, value); + + /* Getting here means that we tried to "dereference" a primitive JSON type + * (like string, int, bool).i.e. add a sub-object to it + */ + errno = ENOENT; + return -1; +} + +static int json_pointer_get_recursive(struct json_object *obj, char *path, + struct json_object **value) +{ + char *endp; + int rc; + + /* All paths (on each recursion level must have a leading '/' */ + if (path[0] != '/') + { + errno = EINVAL; + return -1; + } + path++; + + endp = strchr(path, '/'); + if (endp) + *endp = '\0'; + + /* If we err-ed here, return here */ + if ((rc = json_pointer_get_single_path(obj, path, &obj))) + return rc; + + if (endp) + { + /* Put the slash back, so that the sanity check passes on next recursion level */ + *endp = '/'; + return json_pointer_get_recursive(obj, endp, value); + } + + /* We should be at the end of the recursion here */ + if (value) + *value = obj; + + return 0; +} + +int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res) +{ + char *path_copy = NULL; + int rc; + + if (!obj || !path) + { + errno = EINVAL; + return -1; + } + + if (path[0] == '\0') + { + if (res) + *res = obj; + return 0; + } + + /* pass a working copy to the recursive call */ + if (!(path_copy = strdup(path))) + { + errno = ENOMEM; + return -1; + } + rc = json_pointer_get_recursive(obj, path_copy, res); + free(path_copy); + + return rc; +} + +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...) +{ + char *path_copy = NULL; + int rc = 0; + va_list args; + + if (!obj || !path_fmt) + { + errno = EINVAL; + return -1; + } + + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') + { + if (res) + *res = obj; + goto out; + } + + rc = json_pointer_get_recursive(obj, path_copy, res); +out: + free(path_copy); + + return rc; +} + +int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value) +{ + const char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + int rc; + + if (!obj || !path) + { + errno = EINVAL; + return -1; + } + + if (path[0] == '\0') + { + json_object_put(*obj); + *obj = value; + return 0; + } + + if (path[0] != '/') + { + errno = EINVAL; + return -1; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path, '/')) == path) + { + path++; + return json_pointer_set_single_path(*obj, path, value); + } + + /* pass a working copy to the recursive call */ + if (!(path_copy = strdup(path))) + { + errno = ENOMEM; + return -1; + } + path_copy[endp - path] = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + free(path_copy); + + if (rc) + return rc; + + endp++; + return json_pointer_set_single_path(set, endp, value); +} + +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, + ...) +{ + char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + va_list args; + int rc = 0; + + if (!obj || !path_fmt) + { + errno = EINVAL; + return -1; + } + + /* pass a working copy to the recursive call */ + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') + { + json_object_put(*obj); + *obj = value; + goto out; + } + + if (path_copy[0] != '/') + { + errno = EINVAL; + rc = -1; + goto out; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path_copy, '/')) == path_copy) + { + set = *obj; + goto set_single_path; + } + + *endp = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + + if (rc) + goto out; + +set_single_path: + endp++; + rc = json_pointer_set_single_path(set, endp, value); +out: + free(path_copy); + return rc; +} diff --git a/comm/third_party/json-c/json_pointer.h b/comm/third_party/json-c/json_pointer.h new file mode 100644 index 0000000000..06c395b9ad --- /dev/null +++ b/comm/third_party/json-c/json_pointer.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016 Alexadru Ardelean. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief JSON Pointer (RFC 6901) implementation for retrieving + * objects from a json-c object tree. + */ +#ifndef _json_pointer_h_ +#define _json_pointer_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieves a JSON sub-object from inside another JSON object + * using the JSON pointer notation as defined in RFC 6901 + * https://tools.ietf.org/html/rfc6901 + * + * The returned JSON sub-object is equivalent to parsing manually the + * 'obj' JSON tree ; i.e. it's not a new object that is created, but rather + * a pointer inside the JSON tree. + * + * Internally, this is equivalent to doing a series of 'json_object_object_get()' + * and 'json_object_array_get_idx()' along the given 'path'. + * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'res' param will be treated as an argument for 'path' + * Example: json_pointer_get(obj, "/foo/%d/%s", &res, 0, bar) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * + * @param obj the json_object instance/tree from where to retrieve sub-objects + * @param path a (RFC6901) string notation for the sub-object to retrieve + * @param res a pointer that stores a reference to the json_object + * associated with the given path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +JSON_EXPORT int json_pointer_get(struct json_object *obj, const char *path, + struct json_object **res); + +/** + * This is a variant of 'json_pointer_get()' that supports printf() style arguments. + * + * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param res a pointer that stores a reference to the json_object + * associated with the given path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +JSON_EXPORT int json_pointer_getf(struct json_object *obj, struct json_object **res, + const char *path_fmt, ...); + +/** + * Sets JSON object 'value' in the 'obj' tree at the location specified + * by the 'path'. 'path' is JSON pointer notation as defined in RFC 6901 + * https://tools.ietf.org/html/rfc6901 + * + * Note that 'obj' is a double pointer, mostly for the "" (empty string) + * case, where the entire JSON object would be replaced by 'value'. + * In the case of the "" path, the object at '*obj' will have it's refcount + * decremented with 'json_object_put()' and the 'value' object will be assigned to it. + * + * For other cases (JSON sub-objects) ownership of 'value' will be transferred into + * '*obj' via 'json_object_object_add()' & 'json_object_array_put_idx()', so the + * only time the refcount should be decremented for 'value' is when the return value of + * 'json_pointer_set()' is negative (meaning the 'value' object did not get set into '*obj'). + * + * That also implies that 'json_pointer_set()' does not do any refcount incrementing. + * (Just that single decrement that was mentioned above). + * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'value' param will be treated as an argument for 'path' + * Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param path a (RFC6901) string notation for the sub-object to set in the tree + * @param value object to set at path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +JSON_EXPORT int json_pointer_set(struct json_object **obj, const char *path, + struct json_object *value); + +/** + * This is a variant of 'json_pointer_set()' that supports printf() style arguments. + * + * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param value object to set at path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +JSON_EXPORT int json_pointer_setf(struct json_object **obj, struct json_object *value, + const char *path_fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_tokener.c b/comm/third_party/json-c/json_tokener.c new file mode 100644 index 0000000000..0c09b66e8d --- /dev/null +++ b/comm/third_party/json-c/json_tokener.c @@ -0,0 +1,1300 @@ +/* + * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (https://www.opensource.org/licenses/mit-license.php) + */ + +#include "config.h" + +#include "math_compat.h" +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_object_private.h" +#include "json_tokener.h" +#include "json_util.h" +#include "printbuf.h" +#include "strdup_compat.h" + +#ifdef HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ +#ifdef HAVE_XLOCALE_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif /* HAVE_STRINGS_H */ + +#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x)&7) + 9) + +#if !HAVE_STRNCASECMP && defined(_MSC_VER) +/* MSC has the version as _strnicmp */ +#define strncasecmp _strnicmp +#elif !HAVE_STRNCASECMP +#error You do not have strncasecmp on your system. +#endif /* HAVE_STRNCASECMP */ + +#if defined(_MSC_VER) && (_MSC_VER <= 1800) +/* VS2013 doesn't know about "inline" */ +#define inline __inline +#elif defined(AIX_CC) +#define inline +#endif + +/* The following helper functions are used to speed up parsing. They + * are faster than their ctype counterparts because they assume that + * the input is in ASCII and that the locale is set to "C". The + * compiler will also inline these functions, providing an additional + * speedup by saving on function calls. + */ +static inline int is_ws_char(char c) +{ + return c == ' ' + || c == '\t' + || c == '\n' + || c == '\r'; +} + +static inline int is_hex_char(char c) +{ + return (c >= '0' && c <= '9') + || (c >= 'A' && c <= 'F') + || (c >= 'a' && c <= 'f'); +} + +/* Use C99 NAN by default; if not available, nan("") should work too. */ +#ifndef NAN +#define NAN nan("") +#endif /* !NAN */ + +static const char json_null_str[] = "null"; +static const int json_null_str_len = sizeof(json_null_str) - 1; +static const char json_inf_str[] = "Infinity"; +/* Swapped case "Infinity" to avoid need to call tolower() on input chars: */ +static const char json_inf_str_invert[] = "iNFINITY"; +static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1; +static const char json_nan_str[] = "NaN"; +static const int json_nan_str_len = sizeof(json_nan_str) - 1; +static const char json_true_str[] = "true"; +static const int json_true_str_len = sizeof(json_true_str) - 1; +static const char json_false_str[] = "false"; +static const int json_false_str_len = sizeof(json_false_str) - 1; + +/* clang-format off */ +static const char *json_tokener_errors[] = { + "success", + "continue", + "nesting too deep", + "unexpected end of data", + "unexpected character", + "null expected", + "boolean expected", + "number expected", + "array value separator ',' expected", + "quoted object property name expected", + "object property name separator ':' expected", + "object value separator ',' expected", + "invalid string sequence", + "expected comment", + "invalid utf-8 string", + "buffer size overflow" +}; +/* clang-format on */ + +/** + * validete the utf-8 string in strict model. + * if not utf-8 format, return err. + */ +static json_bool json_tokener_validate_utf8(const char c, unsigned int *nBytes); + +static int json_tokener_parse_double(const char *buf, int len, double *retval); + +const char *json_tokener_error_desc(enum json_tokener_error jerr) +{ + int jerr_int = (int)jerr; + if (jerr_int < 0 || + jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) + return "Unknown error, " + "invalid json_tokener_error value passed to json_tokener_error_desc()"; + return json_tokener_errors[jerr]; +} + +enum json_tokener_error json_tokener_get_error(struct json_tokener *tok) +{ + return tok->err; +} + +/* Stuff for decoding unicode sequences */ +#define IS_HIGH_SURROGATE(uc) (((uc)&0xFC00) == 0xD800) +#define IS_LOW_SURROGATE(uc) (((uc)&0xFC00) == 0xDC00) +#define DECODE_SURROGATE_PAIR(hi, lo) ((((hi)&0x3FF) << 10) + ((lo)&0x3FF) + 0x10000) +static unsigned char utf8_replacement_char[3] = {0xEF, 0xBF, 0xBD}; + +struct json_tokener *json_tokener_new_ex(int depth) +{ + struct json_tokener *tok; + + tok = (struct json_tokener *)calloc(1, sizeof(struct json_tokener)); + if (!tok) + return NULL; + tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec)); + if (!tok->stack) + { + free(tok); + return NULL; + } + tok->pb = printbuf_new(); + if (!tok->pb) + { + free(tok->stack); + free(tok); + return NULL; + } + tok->max_depth = depth; + json_tokener_reset(tok); + return tok; +} + +struct json_tokener *json_tokener_new(void) +{ + return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH); +} + +void json_tokener_free(struct json_tokener *tok) +{ + json_tokener_reset(tok); + if (tok->pb) + printbuf_free(tok->pb); + free(tok->stack); + free(tok); +} + +static void json_tokener_reset_level(struct json_tokener *tok, int depth) +{ + tok->stack[depth].state = json_tokener_state_eatws; + tok->stack[depth].saved_state = json_tokener_state_start; + json_object_put(tok->stack[depth].current); + tok->stack[depth].current = NULL; + free(tok->stack[depth].obj_field_name); + tok->stack[depth].obj_field_name = NULL; +} + +void json_tokener_reset(struct json_tokener *tok) +{ + int i; + if (!tok) + return; + + for (i = tok->depth; i >= 0; i--) + json_tokener_reset_level(tok, i); + tok->depth = 0; + tok->err = json_tokener_success; +} + +struct json_object *json_tokener_parse(const char *str) +{ + enum json_tokener_error jerr_ignored; + struct json_object *obj; + obj = json_tokener_parse_verbose(str, &jerr_ignored); + return obj; +} + +struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokener_error *error) +{ + struct json_tokener *tok; + struct json_object *obj; + + tok = json_tokener_new(); + if (!tok) + return NULL; + obj = json_tokener_parse_ex(tok, str, -1); + *error = tok->err; + if (tok->err != json_tokener_success +#if 0 + /* This would be a more sensible default, and cause parsing + * things like "null123" to fail when the caller can't know + * where the parsing left off, but starting to fail would + * be a notable behaviour change. Save for a 1.0 release. + */ + || json_tokener_get_parse_end(tok) != strlen(str) +#endif + ) + + { + if (obj != NULL) + json_object_put(obj); + obj = NULL; + } + + json_tokener_free(tok); + return obj; +} + +#define state tok->stack[tok->depth].state +#define saved_state tok->stack[tok->depth].saved_state +#define current tok->stack[tok->depth].current +#define obj_field_name tok->stack[tok->depth].obj_field_name + +/* Optimization: + * json_tokener_parse_ex() consumed a lot of CPU in its main loop, + * iterating character-by character. A large performance boost is + * achieved by using tighter loops to locally handle units such as + * comments and strings. Loops that handle an entire token within + * their scope also gather entire strings and pass them to + * printbuf_memappend() in a single call, rather than calling + * printbuf_memappend() one char at a time. + * + * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is + * common to both the main loop and the tighter loops. + */ + +/* PEEK_CHAR(dest, tok) macro: + * Peeks at the current char and stores it in dest. + * Returns 1 on success, sets tok->err and returns 0 if no more chars. + * Implicit inputs: str, len, nBytesp vars + */ +#define PEEK_CHAR(dest, tok) \ + (((tok)->char_offset == len) \ + ? (((tok)->depth == 0 && state == json_tokener_state_eatws && \ + saved_state == json_tokener_state_finish) \ + ? (((tok)->err = json_tokener_success), 0) \ + : (((tok)->err = json_tokener_continue), 0)) \ + : (((tok->flags & JSON_TOKENER_VALIDATE_UTF8) && \ + (!json_tokener_validate_utf8(*str, nBytesp))) \ + ? ((tok->err = json_tokener_error_parse_utf8_string), 0) \ + : (((dest) = *str), 1))) + +/* ADVANCE_CHAR() macro: + * Increments str & tok->char_offset. + * For convenience of existing conditionals, returns the old value of c (0 on eof) + * Implicit inputs: c var + */ +#define ADVANCE_CHAR(str, tok) (++(str), ((tok)->char_offset)++, c) + +/* End optimization macro defs */ + +struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len) +{ + struct json_object *obj = NULL; + char c = '\1'; + unsigned int nBytes = 0; + unsigned int *nBytesp = &nBytes; + +#ifdef HAVE_USELOCALE + locale_t oldlocale = uselocale(NULL); + locale_t newloc; +#elif defined(HAVE_SETLOCALE) + char *oldlocale = NULL; +#endif + + tok->char_offset = 0; + tok->err = json_tokener_success; + + /* this interface is presently not 64-bit clean due to the int len argument + * and the internal printbuf interface that takes 32-bit int len arguments + * so the function limits the maximum string size to INT32_MAX (2GB). + * If the function is called with len == -1 then strlen is called to check + * the string length is less than INT32_MAX (2GB) + */ + if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) + { + tok->err = json_tokener_error_size; + return NULL; + } + +#ifdef HAVE_USELOCALE + { + locale_t duploc = duplocale(oldlocale); + newloc = newlocale(LC_NUMERIC_MASK, "C", duploc); + if (newloc == NULL) + { + freelocale(duploc); + return NULL; + } + uselocale(newloc); + } +#elif defined(HAVE_SETLOCALE) + { + char *tmplocale; + tmplocale = setlocale(LC_NUMERIC, NULL); + if (tmplocale) + oldlocale = strdup(tmplocale); + setlocale(LC_NUMERIC, "C"); + } +#endif + + while (PEEK_CHAR(c, tok)) // Note: c might be '\0' ! + { + + redo_char: + switch (state) + { + + case json_tokener_state_eatws: + /* Advance until we change state */ + while (is_ws_char(c)) + { + if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) + goto out; + } + if (c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) + { + printbuf_reset(tok->pb); + printbuf_memappend_fast(tok->pb, &c, 1); + state = json_tokener_state_comment_start; + } + else + { + state = saved_state; + goto redo_char; + } + break; + + case json_tokener_state_start: + switch (c) + { + case '{': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_object_field_start; + current = json_object_new_object(); + if (current == NULL) + goto out; + break; + case '[': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_array; + current = json_object_new_array(); + if (current == NULL) + goto out; + break; + case 'I': + case 'i': + state = json_tokener_state_inf; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case 'N': + case 'n': + state = json_tokener_state_null; // or NaN + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case '\'': + if (tok->flags & JSON_TOKENER_STRICT) + { + /* in STRICT mode only double-quote are allowed */ + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + /* FALLTHRU */ + case '"': + state = json_tokener_state_string; + printbuf_reset(tok->pb); + tok->quote_char = c; + break; + case 'T': + case 't': + case 'F': + case 'f': + state = json_tokener_state_boolean; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + state = json_tokener_state_number; + printbuf_reset(tok->pb); + tok->is_double = 0; + goto redo_char; + default: tok->err = json_tokener_error_parse_unexpected; goto out; + } + break; + + case json_tokener_state_finish: + if (tok->depth == 0) + goto out; + obj = json_object_get(current); + json_tokener_reset_level(tok, tok->depth); + tok->depth--; + goto redo_char; + + case json_tokener_state_inf: /* aka starts with 'i' (or 'I', or "-i", or "-I") */ + { + /* If we were guaranteed to have len set, then we could (usually) handle + * the entire "Infinity" check in a single strncmp (strncasecmp), but + * since len might be -1 (i.e. "read until \0"), we need to check it + * a character at a time. + * Trying to handle it both ways would make this code considerably more + * complicated with likely little performance benefit. + */ + int is_negative = 0; + + /* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */ + while (tok->st_pos < (int)json_inf_str_len) + { + char inf_char = *str; + if (inf_char != json_inf_str[tok->st_pos] && + ((tok->flags & JSON_TOKENER_STRICT) || + inf_char != json_inf_str_invert[tok->st_pos]) + ) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + tok->st_pos++; + (void)ADVANCE_CHAR(str, tok); + if (!PEEK_CHAR(c, tok)) + { + /* out of input chars, for now at least */ + goto out; + } + } + /* We checked the full length of "Infinity", so create the object. + * When handling -Infinity, the number parsing code will have dropped + * the "-" into tok->pb for us, so check it now. + */ + if (printbuf_length(tok->pb) > 0 && *(tok->pb->buf) == '-') + { + is_negative = 1; + } + current = json_object_new_double(is_negative ? -INFINITY : INFINITY); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + break; + case json_tokener_state_null: /* aka starts with 'n' */ + { + int size; + int size_nan; + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos + 1, json_null_str_len); + size_nan = json_min(tok->st_pos + 1, json_nan_str_len); + if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_null_str, tok->pb->buf, size) == 0) || + (strncmp(json_null_str, tok->pb->buf, size) == 0)) + { + if (tok->st_pos == json_null_str_len) + { + current = NULL; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } + else if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) || + (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0)) + { + if (tok->st_pos == json_nan_str_len) + { + current = json_object_new_double(NAN); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } + else + { + tok->err = json_tokener_error_parse_null; + goto out; + } + tok->st_pos++; + } + break; + + case json_tokener_state_comment_start: + if (c == '*') + { + state = json_tokener_state_comment; + } + else if (c == '/') + { + state = json_tokener_state_comment_eol; + } + else + { + tok->err = json_tokener_error_parse_comment; + goto out; + } + printbuf_memappend_fast(tok->pb, &c, 1); + break; + + case json_tokener_state_comment: + { + /* Advance until we change state */ + const char *case_start = str; + while (c != '*') + { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + goto out; + } + } + printbuf_memappend_fast(tok->pb, case_start, 1 + str - case_start); + state = json_tokener_state_comment_end; + } + break; + + case json_tokener_state_comment_eol: + { + /* Advance until we change state */ + const char *case_start = str; + while (c != '\n') + { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + goto out; + } + } + printbuf_memappend_fast(tok->pb, case_start, str - case_start); + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); + state = json_tokener_state_eatws; + } + break; + + case json_tokener_state_comment_end: + printbuf_memappend_fast(tok->pb, &c, 1); + if (c == '/') + { + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); + state = json_tokener_state_eatws; + } + else + { + state = json_tokener_state_comment; + } + break; + + case json_tokener_state_string: + { + /* Advance until we change state */ + const char *case_start = str; + while (1) + { + if (c == tok->quote_char) + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + current = + json_object_new_string_len(tok->pb->buf, tok->pb->bpos); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + break; + } + else if (c == '\\') + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + saved_state = json_tokener_state_string; + state = json_tokener_state_string_escape; + break; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + goto out; + } + } + } + break; + + case json_tokener_state_string_escape: + switch (c) + { + case '"': + case '\\': + case '/': + printbuf_memappend_fast(tok->pb, &c, 1); + state = saved_state; + break; + case 'b': + case 'n': + case 'r': + case 't': + case 'f': + if (c == 'b') + printbuf_memappend_fast(tok->pb, "\b", 1); + else if (c == 'n') + printbuf_memappend_fast(tok->pb, "\n", 1); + else if (c == 'r') + printbuf_memappend_fast(tok->pb, "\r", 1); + else if (c == 't') + printbuf_memappend_fast(tok->pb, "\t", 1); + else if (c == 'f') + printbuf_memappend_fast(tok->pb, "\f", 1); + state = saved_state; + break; + case 'u': + tok->ucs_char = 0; + tok->st_pos = 0; + state = json_tokener_state_escape_unicode; + break; + default: tok->err = json_tokener_error_parse_string; goto out; + } + break; + + // =================================================== + + case json_tokener_state_escape_unicode: + { + /* Handle a 4-byte \uNNNN sequence, or two sequences if a surrogate pair */ + while (1) + { + if (!c || !is_hex_char(c)) + { + tok->err = json_tokener_error_parse_string; + goto out; + } + tok->ucs_char |= + ((unsigned int)jt_hexdigit(c) << ((3 - tok->st_pos) * 4)); + tok->st_pos++; + if (tok->st_pos >= 4) + break; + + (void)ADVANCE_CHAR(str, tok); + if (!PEEK_CHAR(c, tok)) + { + /* + * We're out of characters in the current call to + * json_tokener_parse(), but a subsequent call might + * provide us with more, so leave our current state + * as-is (including tok->high_surrogate) and return. + */ + goto out; + } + } + tok->st_pos = 0; + + /* Now, we have a full \uNNNN sequence in tok->ucs_char */ + + /* If the *previous* sequence was a high surrogate ... */ + if (tok->high_surrogate) + { + if (IS_LOW_SURROGATE(tok->ucs_char)) + { + /* Recalculate the ucs_char, then fall thru to process normally */ + tok->ucs_char = DECODE_SURROGATE_PAIR(tok->high_surrogate, + tok->ucs_char); + } + else + { + /* High surrogate was not followed by a low surrogate + * Replace the high and process the rest normally + */ + printbuf_memappend_fast(tok->pb, + (char *)utf8_replacement_char, 3); + } + tok->high_surrogate = 0; + } + + if (tok->ucs_char < 0x80) + { + unsigned char unescaped_utf[1]; + unescaped_utf[0] = tok->ucs_char; + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 1); + } + else if (tok->ucs_char < 0x800) + { + unsigned char unescaped_utf[2]; + unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6); + unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 2); + } + else if (IS_HIGH_SURROGATE(tok->ucs_char)) + { + /* + * The next two characters should be \u, HOWEVER, + * we can't simply peek ahead here, because the + * characters we need might not be passed to us + * until a subsequent call to json_tokener_parse. + * Instead, transition through a couple of states. + * (now): + * _escape_unicode => _unicode_need_escape + * (see a '\\' char): + * _unicode_need_escape => _unicode_need_u + * (see a 'u' char): + * _unicode_need_u => _escape_unicode + * ...and we'll end up back around here. + */ + tok->high_surrogate = tok->ucs_char; + tok->ucs_char = 0; + state = json_tokener_state_escape_unicode_need_escape; + break; + } + else if (IS_LOW_SURROGATE(tok->ucs_char)) + { + /* Got a low surrogate not preceded by a high */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + } + else if (tok->ucs_char < 0x10000) + { + unsigned char unescaped_utf[3]; + unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 3); + } + else if (tok->ucs_char < 0x110000) + { + unsigned char unescaped_utf[4]; + unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f); + unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 4); + } + else + { + /* Don't know what we got--insert the replacement char */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + } + state = saved_state; // i.e. _state_string or _state_object_field + } + break; + + case json_tokener_state_escape_unicode_need_escape: + // We get here after processing a high_surrogate + // require a '\\' char + if (!c || c != '\\') + { + /* Got a high surrogate without another sequence following + * it. Put a replacement char in for the high surrogate + * and pop back up to _state_string or _state_object_field. + */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + tok->high_surrogate = 0; + tok->ucs_char = 0; + tok->st_pos = 0; + state = saved_state; + goto redo_char; + } + state = json_tokener_state_escape_unicode_need_u; + break; + + case json_tokener_state_escape_unicode_need_u: + /* We already had a \ char, check that it's \u */ + if (!c || c != 'u') + { + /* Got a high surrogate with some non-unicode escape + * sequence following it. + * Put a replacement char in for the high surrogate + * and handle the escape sequence normally. + */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + tok->high_surrogate = 0; + tok->ucs_char = 0; + tok->st_pos = 0; + state = json_tokener_state_string_escape; + goto redo_char; + } + state = json_tokener_state_escape_unicode; + break; + + // =================================================== + + case json_tokener_state_boolean: + { + int size1, size2; + printbuf_memappend_fast(tok->pb, &c, 1); + size1 = json_min(tok->st_pos + 1, json_true_str_len); + size2 = json_min(tok->st_pos + 1, json_false_str_len); + if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_true_str, tok->pb->buf, size1) == 0) || + (strncmp(json_true_str, tok->pb->buf, size1) == 0)) + { + if (tok->st_pos == json_true_str_len) + { + current = json_object_new_boolean(1); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } + else if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_false_str, tok->pb->buf, size2) == 0) || + (strncmp(json_false_str, tok->pb->buf, size2) == 0)) + { + if (tok->st_pos == json_false_str_len) + { + current = json_object_new_boolean(0); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } + else + { + tok->err = json_tokener_error_parse_boolean; + goto out; + } + tok->st_pos++; + } + break; + + case json_tokener_state_number: + { + /* Advance until we change state */ + const char *case_start = str; + int case_len = 0; + int is_exponent = 0; + int neg_sign_ok = 1; + int pos_sign_ok = 0; + if (printbuf_length(tok->pb) > 0) + { + /* We don't save all state from the previous incremental parse + so we need to re-generate it based on the saved string so far. + */ + char *e_loc = strchr(tok->pb->buf, 'e'); + if (!e_loc) + e_loc = strchr(tok->pb->buf, 'E'); + if (e_loc) + { + char *last_saved_char = + &tok->pb->buf[printbuf_length(tok->pb) - 1]; + is_exponent = 1; + pos_sign_ok = neg_sign_ok = 1; + /* If the "e" isn't at the end, we can't start with a '-' */ + if (e_loc != last_saved_char) + { + neg_sign_ok = 0; + pos_sign_ok = 0; + } + // else leave it set to 1, i.e. start of the new input + } + } + + while (c && ((c >= '0' && c <= '9') || + (!is_exponent && (c == 'e' || c == 'E')) || + (neg_sign_ok && c == '-') || (pos_sign_ok && c == '+') || + (!tok->is_double && c == '.'))) + { + pos_sign_ok = neg_sign_ok = 0; + ++case_len; + + /* non-digit characters checks */ + /* note: since the main loop condition to get here was + * an input starting with 0-9 or '-', we are + * protected from input starting with '.' or + * e/E. + */ + switch (c) + { + case '.': + tok->is_double = 1; + pos_sign_ok = 1; + neg_sign_ok = 1; + break; + case 'e': /* FALLTHRU */ + case 'E': + is_exponent = 1; + tok->is_double = 1; + /* the exponent part can begin with a negative sign */ + pos_sign_ok = neg_sign_ok = 1; + break; + default: break; + } + + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) + { + printbuf_memappend_fast(tok->pb, case_start, case_len); + goto out; + } + } + /* + Now we know c isn't a valid number char, but check whether + it might have been intended to be, and return a potentially + more understandable error right away. + However, if we're at the top-level, use the number as-is + because c can be part of a new object to parse on the + next call to json_tokener_parse(). + */ + if (tok->depth > 0 && c != ',' && c != ']' && c != '}' && c != '/' && + c != 'I' && c != 'i' && !is_ws_char(c)) + { + tok->err = json_tokener_error_parse_number; + goto out; + } + if (case_len > 0) + printbuf_memappend_fast(tok->pb, case_start, case_len); + + // Check for -Infinity + if (tok->pb->buf[0] == '-' && case_len <= 1 && (c == 'i' || c == 'I')) + { + state = json_tokener_state_inf; + tok->st_pos = 0; + goto redo_char; + } + if (tok->is_double && !(tok->flags & JSON_TOKENER_STRICT)) + { + /* Trim some chars off the end, to allow things + like "123e+" to parse ok. */ + while (printbuf_length(tok->pb) > 1) + { + char last_char = tok->pb->buf[printbuf_length(tok->pb) - 1]; + if (last_char != 'e' && last_char != 'E' && + last_char != '-' && last_char != '+') + { + break; + } + tok->pb->buf[printbuf_length(tok->pb) - 1] = '\0'; + printbuf_length(tok->pb)--; + } + } + } + { + int64_t num64; + uint64_t numuint64; + double numd; + if (!tok->is_double && tok->pb->buf[0] == '-' && + json_parse_int64(tok->pb->buf, &num64) == 0) + { + current = json_object_new_int64(num64); + if (current == NULL) + goto out; + } + else if (!tok->is_double && tok->pb->buf[0] != '-' && + json_parse_uint64(tok->pb->buf, &numuint64) == 0) + { + if (numuint64 && tok->pb->buf[0] == '0' && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_number; + goto out; + } + if (numuint64 <= INT64_MAX) + { + num64 = (uint64_t)numuint64; + current = json_object_new_int64(num64); + if (current == NULL) + goto out; + } + else + { + current = json_object_new_uint64(numuint64); + if (current == NULL) + goto out; + } + } + else if (tok->is_double && + json_tokener_parse_double( + tok->pb->buf, printbuf_length(tok->pb), &numd) == 0) + { + current = json_object_new_double_s(numd, tok->pb->buf); + if (current == NULL) + goto out; + } + else + { + tok->err = json_tokener_error_parse_number; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + break; + + case json_tokener_state_array_after_sep: + case json_tokener_state_array: + if (c == ']') + { + // Minimize memory usage; assume parsed objs are unlikely to be changed + json_object_array_shrink(current, 0); + + if (state == json_tokener_state_array_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } + else + { + if (tok->depth >= tok->max_depth - 1) + { + tok->err = json_tokener_error_depth; + goto out; + } + state = json_tokener_state_array_add; + tok->depth++; + json_tokener_reset_level(tok, tok->depth); + goto redo_char; + } + break; + + case json_tokener_state_array_add: + if (json_object_array_add(current, obj) != 0) + goto out; + saved_state = json_tokener_state_array_sep; + state = json_tokener_state_eatws; + goto redo_char; + + case json_tokener_state_array_sep: + if (c == ']') + { + // Minimize memory usage; assume parsed objs are unlikely to be changed + json_object_array_shrink(current, 0); + + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } + else if (c == ',') + { + saved_state = json_tokener_state_array_after_sep; + state = json_tokener_state_eatws; + } + else + { + tok->err = json_tokener_error_parse_array; + goto out; + } + break; + + case json_tokener_state_object_field_start: + case json_tokener_state_object_field_start_after_sep: + if (c == '}') + { + if (state == json_tokener_state_object_field_start_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } + else if (c == '"' || c == '\'') + { + tok->quote_char = c; + printbuf_reset(tok->pb); + state = json_tokener_state_object_field; + } + else + { + tok->err = json_tokener_error_parse_object_key_name; + goto out; + } + break; + + case json_tokener_state_object_field: + { + /* Advance until we change state */ + const char *case_start = str; + while (1) + { + if (c == tok->quote_char) + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + obj_field_name = strdup(tok->pb->buf); + saved_state = json_tokener_state_object_field_end; + state = json_tokener_state_eatws; + break; + } + else if (c == '\\') + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + saved_state = json_tokener_state_object_field; + state = json_tokener_state_string_escape; + break; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) + { + printbuf_memappend_fast(tok->pb, case_start, + str - case_start); + goto out; + } + } + } + break; + + case json_tokener_state_object_field_end: + if (c == ':') + { + saved_state = json_tokener_state_object_value; + state = json_tokener_state_eatws; + } + else + { + tok->err = json_tokener_error_parse_object_key_sep; + goto out; + } + break; + + case json_tokener_state_object_value: + if (tok->depth >= tok->max_depth - 1) + { + tok->err = json_tokener_error_depth; + goto out; + } + state = json_tokener_state_object_value_add; + tok->depth++; + json_tokener_reset_level(tok, tok->depth); + goto redo_char; + + case json_tokener_state_object_value_add: + json_object_object_add(current, obj_field_name, obj); + free(obj_field_name); + obj_field_name = NULL; + saved_state = json_tokener_state_object_sep; + state = json_tokener_state_eatws; + goto redo_char; + + case json_tokener_state_object_sep: + /* { */ + if (c == '}') + { + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } + else if (c == ',') + { + saved_state = json_tokener_state_object_field_start_after_sep; + state = json_tokener_state_eatws; + } + else + { + tok->err = json_tokener_error_parse_object_value_sep; + goto out; + } + break; + } + (void)ADVANCE_CHAR(str, tok); + if (!c) // This is the char *before* advancing + break; + } /* while(PEEK_CHAR) */ + +out: + if ((tok->flags & JSON_TOKENER_VALIDATE_UTF8) && (nBytes != 0)) + { + tok->err = json_tokener_error_parse_utf8_string; + } + if (c && (state == json_tokener_state_finish) && (tok->depth == 0) && + (tok->flags & (JSON_TOKENER_STRICT | JSON_TOKENER_ALLOW_TRAILING_CHARS)) == + JSON_TOKENER_STRICT) + { + /* unexpected char after JSON data */ + tok->err = json_tokener_error_parse_unexpected; + } + if (!c) + { + /* We hit an eof char (0) */ + if (state != json_tokener_state_finish && saved_state != json_tokener_state_finish) + tok->err = json_tokener_error_parse_eof; + } + +#ifdef HAVE_USELOCALE + uselocale(oldlocale); + freelocale(newloc); +#elif defined(HAVE_SETLOCALE) + setlocale(LC_NUMERIC, oldlocale); + free(oldlocale); +#endif + + if (tok->err == json_tokener_success) + { + json_object *ret = json_object_get(current); + int ii; + + /* Partially reset, so we parse additional objects on subsequent calls. */ + for (ii = tok->depth; ii >= 0; ii--) + json_tokener_reset_level(tok, ii); + return ret; + } + + MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n", json_tokener_errors[tok->err], + tok->char_offset); + return NULL; +} + +static json_bool json_tokener_validate_utf8(const char c, unsigned int *nBytes) +{ + unsigned char chr = c; + if (*nBytes == 0) + { + if (chr >= 0x80) + { + if ((chr & 0xe0) == 0xc0) + *nBytes = 1; + else if ((chr & 0xf0) == 0xe0) + *nBytes = 2; + else if ((chr & 0xf8) == 0xf0) + *nBytes = 3; + else + return 0; + } + } + else + { + if ((chr & 0xC0) != 0x80) + return 0; + (*nBytes)--; + } + return 1; +} + +void json_tokener_set_flags(struct json_tokener *tok, int flags) +{ + tok->flags = flags; +} + +size_t json_tokener_get_parse_end(struct json_tokener *tok) +{ + assert(tok->char_offset >= 0); /* Drop this line when char_offset becomes a size_t */ + return (size_t)tok->char_offset; +} + +static int json_tokener_parse_double(const char *buf, int len, double *retval) +{ + char *end; + *retval = strtod(buf, &end); + if (buf + len == end) + return 0; // It worked + return 1; +} diff --git a/comm/third_party/json-c/json_tokener.h b/comm/third_party/json-c/json_tokener.h new file mode 100644 index 0000000000..a07e12ce7e --- /dev/null +++ b/comm/third_party/json-c/json_tokener.h @@ -0,0 +1,328 @@ +/* + * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Methods to parse an input string into a tree of json_object objects. + */ +#ifndef _json_tokener_h_ +#define _json_tokener_h_ + +#include "json_object.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum json_tokener_error +{ + json_tokener_success, + json_tokener_continue, + json_tokener_error_depth, + json_tokener_error_parse_eof, + json_tokener_error_parse_unexpected, + json_tokener_error_parse_null, + json_tokener_error_parse_boolean, + json_tokener_error_parse_number, + json_tokener_error_parse_array, + json_tokener_error_parse_object_key_name, + json_tokener_error_parse_object_key_sep, + json_tokener_error_parse_object_value_sep, + json_tokener_error_parse_string, + json_tokener_error_parse_comment, + json_tokener_error_parse_utf8_string, + json_tokener_error_size +}; + +/** + * @deprecated Don't use this outside of json_tokener.c, it will be made private in a future release. + */ +enum json_tokener_state +{ + json_tokener_state_eatws, + json_tokener_state_start, + json_tokener_state_finish, + json_tokener_state_null, + json_tokener_state_comment_start, + json_tokener_state_comment, + json_tokener_state_comment_eol, + json_tokener_state_comment_end, + json_tokener_state_string, + json_tokener_state_string_escape, + json_tokener_state_escape_unicode, + json_tokener_state_escape_unicode_need_escape, + json_tokener_state_escape_unicode_need_u, + json_tokener_state_boolean, + json_tokener_state_number, + json_tokener_state_array, + json_tokener_state_array_add, + json_tokener_state_array_sep, + json_tokener_state_object_field_start, + json_tokener_state_object_field, + json_tokener_state_object_field_end, + json_tokener_state_object_value, + json_tokener_state_object_value_add, + json_tokener_state_object_sep, + json_tokener_state_array_after_sep, + json_tokener_state_object_field_start_after_sep, + json_tokener_state_inf +}; + +/** + * @deprecated Don't use this outside of json_tokener.c, it will be made private in a future release. + */ +struct json_tokener_srec +{ + enum json_tokener_state state, saved_state; + struct json_object *obj; + struct json_object *current; + char *obj_field_name; +}; + +#define JSON_TOKENER_DEFAULT_DEPTH 32 + +/** + * Internal state of the json parser. + * Do not access any fields of this structure directly. + * Its definition is published due to historical limitations + * in the json tokener API, and will be changed to be an opaque + * type in the future. + */ +struct json_tokener +{ + /** + * @deprecated Do not access any of these fields outside of json_tokener.c + */ + char *str; + struct printbuf *pb; + int max_depth, depth, is_double, st_pos; + /** + * @deprecated See json_tokener_get_parse_end() instead. + */ + int char_offset; + /** + * @deprecated See json_tokener_get_error() instead. + */ + enum json_tokener_error err; + unsigned int ucs_char, high_surrogate; + char quote_char; + struct json_tokener_srec *stack; + int flags; +}; + +/** + * Return the offset of the byte after the last byte parsed + * relative to the start of the most recent string passed in + * to json_tokener_parse_ex(). i.e. this is where parsing + * would start again if the input contains another JSON object + * after the currently parsed one. + * + * Note that when multiple parse calls are issued, this is *not* the + * total number of characters parsed. + * + * In the past this would have been accessed as tok->char_offset. + * + * See json_tokener_parse_ex() for an example of how to use this. + */ +JSON_EXPORT size_t json_tokener_get_parse_end(struct json_tokener *tok); + +/** + * @deprecated Unused in json-c code + */ +typedef struct json_tokener json_tokener; + +/** + * Be strict when parsing JSON input. Use caution with + * this flag as what is considered valid may become more + * restrictive from one release to the next, causing your + * code to fail on previously working input. + * + * Note that setting this will also effectively disable parsing + * of multiple json objects in a single character stream + * (e.g. {"foo":123}{"bar":234}); if you want to allow that + * also set JSON_TOKENER_ALLOW_TRAILING_CHARS + * + * This flag is not set by default. + * + * @see json_tokener_set_flags() + */ +#define JSON_TOKENER_STRICT 0x01 + +/** + * Use with JSON_TOKENER_STRICT to allow trailing characters after the + * first parsed object. + * + * @see json_tokener_set_flags() + */ +#define JSON_TOKENER_ALLOW_TRAILING_CHARS 0x02 + +/** + * Cause json_tokener_parse_ex() to validate that input is UTF8. + * If this flag is specified and validation fails, then + * json_tokener_get_error(tok) will return + * json_tokener_error_parse_utf8_string + * + * This flag is not set by default. + * + * @see json_tokener_set_flags() + */ +#define JSON_TOKENER_VALIDATE_UTF8 0x10 + +/** + * Given an error previously returned by json_tokener_get_error(), + * return a human readable description of the error. + * + * @return a generic error message is returned if an invalid error value is provided. + */ +JSON_EXPORT const char *json_tokener_error_desc(enum json_tokener_error jerr); + +/** + * Retrieve the error caused by the last call to json_tokener_parse_ex(), + * or json_tokener_success if there is no error. + * + * When parsing a JSON string in pieces, if the tokener is in the middle + * of parsing this will return json_tokener_continue. + * + * @see json_tokener_error_desc(). + */ +JSON_EXPORT enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); + +/** + * Allocate a new json_tokener. + * When done using that to parse objects, free it with json_tokener_free(). + * See json_tokener_parse_ex() for usage details. + */ +JSON_EXPORT struct json_tokener *json_tokener_new(void); + +/** + * Allocate a new json_tokener with a custom max nesting depth. + * @see JSON_TOKENER_DEFAULT_DEPTH + */ +JSON_EXPORT struct json_tokener *json_tokener_new_ex(int depth); + +/** + * Free a json_tokener previously allocated with json_tokener_new(). + */ +JSON_EXPORT void json_tokener_free(struct json_tokener *tok); + +/** + * Reset the state of a json_tokener, to prepare to parse a + * brand new JSON object. + */ +JSON_EXPORT void json_tokener_reset(struct json_tokener *tok); + +/** + * Parse a json_object out of the string `str`. + * + * If you need more control over how the parsing occurs, + * see json_tokener_parse_ex(). + */ +JSON_EXPORT struct json_object *json_tokener_parse(const char *str); + +/** + * Parser a json_object out of the string `str`, but if it fails + * return the error in `*error`. + * @see json_tokener_parse() + * @see json_tokener_parse_ex() + */ +JSON_EXPORT struct json_object *json_tokener_parse_verbose(const char *str, + enum json_tokener_error *error); + +/** + * Set flags that control how parsing will be done. + */ +JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags); + +/** + * Parse a string and return a non-NULL json_object if a valid JSON value + * is found. The string does not need to be a JSON object or array; + * it can also be a string, number or boolean value. + * + * A partial JSON string can be parsed. If the parsing is incomplete, + * NULL will be returned and json_tokener_get_error() will return + * json_tokener_continue. + * json_tokener_parse_ex() can then be called with additional bytes in str + * to continue the parsing. + * + * If json_tokener_parse_ex() returns NULL and the error is anything other than + * json_tokener_continue, a fatal error has occurred and parsing must be + * halted. Then, the tok object must not be reused until json_tokener_reset() + * is called. + * + * When a valid JSON value is parsed, a non-NULL json_object will be + * returned, with a reference count of one which belongs to the caller. Also, + * json_tokener_get_error() will return json_tokener_success. Be sure to check + * the type with json_object_is_type() or json_object_get_type() before using + * the object. + * + * Trailing characters after the parsed value do not automatically cause an + * error. It is up to the caller to decide whether to treat this as an + * error or to handle the additional characters, perhaps by parsing another + * json value starting from that point. + * + * If the caller knows that they are at the end of their input, the length + * passed MUST include the final '\0' character, so values with no inherent + * end (i.e. numbers) can be properly parsed, rather than just returning + * json_tokener_continue. + * + * Extra characters can be detected by comparing the value returned by + * json_tokener_get_parse_end() against + * the length of the last len parameter passed in. + * + * The tokener does \b not maintain an internal buffer so the caller is + * responsible for a subsequent call to json_tokener_parse_ex with an + * appropriate str parameter starting with the extra characters. + * + * This interface is presently not 64-bit clean due to the int len argument + * so the function limits the maximum string size to INT32_MAX (2GB). + * If the function is called with len == -1 then strlen is called to check + * the string length is less than INT32_MAX (2GB) + * + * Example: + * @code +json_object *jobj = NULL; +const char *mystring = NULL; +int stringlen = 0; +enum json_tokener_error jerr; +do { + mystring = ... // get JSON string, e.g. read from file, etc... + stringlen = strlen(mystring); + if (end_of_input) + stringlen++; // Include the '\0' if we know we're at the end of input + jobj = json_tokener_parse_ex(tok, mystring, stringlen); +} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); +if (jerr != json_tokener_success) +{ + fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); + // Handle errors, as appropriate for your application. +} +if (json_tokener_get_parse_end(tok) < stringlen) +{ + // Handle extra characters after parsed object as desired. + // e.g. issue an error, parse another object from that point, etc... +} +// Success, use jobj here. + +@endcode + * + * @param tok a json_tokener previously allocated with json_tokener_new() + * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. + * @param len the length of str + */ +JSON_EXPORT struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *str, + int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_types.h b/comm/third_party/json-c/json_types.h new file mode 100644 index 0000000000..b7e55ada89 --- /dev/null +++ b/comm/third_party/json-c/json_types.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Eric Hawicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +#ifndef _json_types_h_ +#define _json_types_h_ + +/** + * @file + * @brief Basic types used in a few places in json-c, but you should include "json_object.h" instead. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JSON_EXPORT +#if defined(_MSC_VER) && defined(JSON_C_DLL) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif +#endif + +struct printbuf; + +/** + * A structure to use with json_object_object_foreachC() loops. + * Contains key, val and entry members. + */ +struct json_object_iter +{ + char *key; + struct json_object *val; + struct lh_entry *entry; +}; +typedef struct json_object_iter json_object_iter; + +typedef int json_bool; + +/** + * @brief The core type for all type of JSON objects handled by json-c + */ +typedef struct json_object json_object; + +/** + * Type of custom user delete functions. See json_object_set_serializer. + */ +typedef void(json_object_delete_fn)(struct json_object *jso, void *userdata); + +/** + * Type of a custom serialization function. See json_object_set_serializer. + */ +typedef int(json_object_to_json_string_fn)(struct json_object *jso, struct printbuf *pb, int level, + int flags); + +/* supported object types */ + +typedef enum json_type +{ + /* If you change this, be sure to update json_type_to_name() too */ + json_type_null, + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string +} json_type; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_util.c b/comm/third_party/json-c/json_util.c new file mode 100644 index 0000000000..3e6a6c681b --- /dev/null +++ b/comm/third_party/json-c/json_util.c @@ -0,0 +1,296 @@ +/* + * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" +#undef realloc + +#include "strerror_override.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef HAVE_SYS_STAT_H +#include +#endif /* HAVE_SYS_STAT_H */ + +#ifdef HAVE_FCNTL_H +#include +#endif /* HAVE_FCNTL_H */ + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif /* defined(WIN32) */ + +#if !defined(HAVE_OPEN) && defined(WIN32) +#define open _open +#endif + +#include "snprintf_compat.h" + +#include "debug.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" +#include "printbuf.h" + +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); + +static char _last_err[256] = ""; + +const char *json_util_get_last_err() +{ + if (_last_err[0] == '\0') + return NULL; + return _last_err; +} + +void _json_c_set_last_err(const char *err_fmt, ...) +{ + va_list ap; + va_start(ap, err_fmt); + // Ignore (attempted) overruns from snprintf + (void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap); + va_end(ap); +} + +struct json_object *json_object_from_fd(int fd) +{ + return json_object_from_fd_ex(fd, -1); +} +struct json_object *json_object_from_fd_ex(int fd, int in_depth) +{ + struct printbuf *pb; + struct json_object *obj; + char buf[JSON_FILE_BUF_SIZE]; + int ret; + int depth = JSON_TOKENER_DEFAULT_DEPTH; + json_tokener *tok; + + if (!(pb = printbuf_new())) + { + _json_c_set_last_err("json_object_from_fd_ex: printbuf_new failed\n"); + return NULL; + } + + if (in_depth != -1) + depth = in_depth; + tok = json_tokener_new_ex(depth); + if (!tok) + { + _json_c_set_last_err( + "json_object_from_fd_ex: unable to allocate json_tokener(depth=%d): %s\n", depth, + strerror(errno)); + printbuf_free(pb); + return NULL; + } + + while ((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) + { + printbuf_memappend(pb, buf, ret); + } + if (ret < 0) + { + _json_c_set_last_err("json_object_from_fd_ex: error reading fd %d: %s\n", fd, + strerror(errno)); + json_tokener_free(tok); + printbuf_free(pb); + return NULL; + } + + obj = json_tokener_parse_ex(tok, pb->buf, printbuf_length(pb)); + if (obj == NULL) + _json_c_set_last_err("json_tokener_parse_ex failed: %s\n", + json_tokener_error_desc(json_tokener_get_error(tok))); + + json_tokener_free(tok); + printbuf_free(pb); + return obj; +} + +struct json_object *json_object_from_file(const char *filename) +{ + struct json_object *obj; + int fd; + + if ((fd = open(filename, O_RDONLY)) < 0) + { + _json_c_set_last_err("json_object_from_file: error opening file %s: %s\n", + filename, strerror(errno)); + return NULL; + } + obj = json_object_from_fd(fd); + close(fd); + return obj; +} + +/* extended "format and write to file" function */ + +int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) +{ + int fd, ret; + int saved_errno; + + if (!obj) + { + _json_c_set_last_err("json_object_to_file_ext: object is null\n"); + return -1; + } + + if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) + { + _json_c_set_last_err("json_object_to_file_ext: error opening file %s: %s\n", + filename, strerror(errno)); + return -1; + } + ret = _json_object_to_fd(fd, obj, flags, filename); + saved_errno = errno; + close(fd); + errno = saved_errno; + return ret; +} + +int json_object_to_fd(int fd, struct json_object *obj, int flags) +{ + if (!obj) + { + _json_c_set_last_err("json_object_to_fd: object is null\n"); + return -1; + } + + return _json_object_to_fd(fd, obj, flags, NULL); +} +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename) +{ + int ret; + const char *json_str; + unsigned int wpos, wsize; + + filename = filename ? filename : "(fd)"; + + if (!(json_str = json_object_to_json_string_ext(obj, flags))) + { + return -1; + } + + /* CAW: probably unnecessary, but the most 64bit safe */ + wsize = (unsigned int)(strlen(json_str) & UINT_MAX); + wpos = 0; + while (wpos < wsize) + { + if ((ret = write(fd, json_str + wpos, wsize - wpos)) < 0) + { + _json_c_set_last_err("json_object_to_fd: error writing file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; + } + + return 0; +} + +// backwards compatible "format and write to file" function + +int json_object_to_file(const char *filename, struct json_object *obj) +{ + return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); +} + +// Deprecated json_parse_double function. See json_tokener_parse_double instead. +int json_parse_double(const char *buf, double *retval) +{ + char *end; + *retval = strtod(buf, &end); + return end == buf ? 1 : 0; +} + +int json_parse_int64(const char *buf, int64_t *retval) +{ + char *end = NULL; + int64_t val; + + errno = 0; + val = strtoll(buf, &end, 10); + if (end != buf) + *retval = val; + return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; +} + +int json_parse_uint64(const char *buf, uint64_t *retval) +{ + char *end = NULL; + uint64_t val; + + errno = 0; + while (*buf == ' ') + buf++; + if (*buf == '-') + return 1; /* error: uint cannot be negative */ + + val = strtoull(buf, &end, 10); + if (end != buf) + *retval = val; + return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; +} + +#ifndef HAVE_REALLOC +void *rpl_realloc(void *p, size_t n) +{ + if (n == 0) + n = 1; + if (p == 0) + return malloc(n); + return realloc(p, n); +} +#endif + +#define NELEM(a) (sizeof(a) / sizeof(a[0])) +/* clang-format off */ +static const char *json_type_name[] = { + /* If you change this, be sure to update the enum json_type definition too */ + "null", + "boolean", + "double", + "int", + "object", + "array", + "string", +}; +/* clang-format on */ + +const char *json_type_to_name(enum json_type o_type) +{ + int o_type_int = (int)o_type; + if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) + { + _json_c_set_last_err("json_type_to_name: type %d is out of range [0,%u]\n", o_type, + (unsigned)NELEM(json_type_name)); + return NULL; + } + return json_type_name[o_type]; +} diff --git a/comm/third_party/json-c/json_util.h b/comm/third_party/json-c/json_util.h new file mode 100644 index 0000000000..1f663e872a --- /dev/null +++ b/comm/third_party/json-c/json_util.h @@ -0,0 +1,121 @@ +/* + * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Miscllaneous utility functions and macros. + */ +#ifndef _json_util_h_ +#define _json_util_h_ + +#include "json_object.h" + +#ifndef json_min +#define json_min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef json_max +#define json_max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_FILE_BUF_SIZE 4096 + +/* utility functions */ +/** + * Read the full contents of the given file, then convert it to a + * json_object using json_tokener_parse(). + * + * Returns NULL on failure. See json_util_get_last_err() for details. + */ +JSON_EXPORT struct json_object *json_object_from_file(const char *filename); + +/** + * Create a JSON object from already opened file descriptor. + * + * This function can be helpful, when you opened the file already, + * e.g. when you have a temp file. + * Note, that the fd must be readable at the actual position, i.e. + * use lseek(fd, 0, SEEK_SET) before. + * + * The depth argument specifies the maximum object depth to pass to + * json_tokener_new_ex(). When depth == -1, JSON_TOKENER_DEFAULT_DEPTH + * is used instead. + * + * Returns NULL on failure. See json_util_get_last_err() for details. + */ +JSON_EXPORT struct json_object *json_object_from_fd_ex(int fd, int depth); + +/** + * Create a JSON object from an already opened file descriptor, using + * the default maximum object depth. (JSON_TOKENER_DEFAULT_DEPTH) + * + * See json_object_from_fd_ex() for details. + */ +JSON_EXPORT struct json_object *json_object_from_fd(int fd); + +/** + * Equivalent to: + * json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +JSON_EXPORT int json_object_to_file(const char *filename, struct json_object *obj); + +/** + * Open and truncate the given file, creating it if necessary, then + * convert the json_object to a string and write it to the file. + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +JSON_EXPORT int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); + +/** + * Convert the json_object to a string and write it to the file descriptor. + * Handles partial writes and will keep writing until done, or an error + * occurs. + * + * @param fd an open, writable file descriptor to write to + * @param obj the object to serializer and write + * @param flags flags to pass to json_object_to_json_string_ext() + * @return -1 if something fails. See json_util_get_last_err() for details. + */ +JSON_EXPORT int json_object_to_fd(int fd, struct json_object *obj, int flags); + +/** + * Return the last error from various json-c functions, including: + * json_object_to_file{,_ext}, json_object_to_fd() or + * json_object_from_{file,fd}, or NULL if there is none. + */ +JSON_EXPORT const char *json_util_get_last_err(void); + +/* these parsing helpers return zero on success */ +JSON_EXPORT int json_parse_int64(const char *buf, int64_t *retval); +JSON_EXPORT int json_parse_uint64(const char *buf, uint64_t *retval); +/** + * @deprecated + */ +JSON_EXPORT int json_parse_double(const char *buf, double *retval); + +/** + * Return a string describing the type of the object. + * e.g. "int", or "object", etc... + */ +JSON_EXPORT const char *json_type_to_name(enum json_type o_type); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/json_visit.c b/comm/third_party/json-c/json_visit.c new file mode 100644 index 0000000000..fb16fa6fa6 --- /dev/null +++ b/comm/third_party/json-c/json_visit.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016 Eric Haszlakiewicz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +#include + +#include "config.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_visit.h" +#include "linkhash.h" + +static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *jso_key, + size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg); + +int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *userfunc, void *userarg) +{ + int ret = _json_c_visit(jso, NULL, NULL, NULL, userfunc, userarg); + switch (ret) + { + case JSON_C_VISIT_RETURN_CONTINUE: + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + case JSON_C_VISIT_RETURN_STOP: return 0; + default: return JSON_C_VISIT_RETURN_ERROR; + } +} +static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *jso_key, + size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg) +{ + int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg); + switch (userret) + { + case JSON_C_VISIT_RETURN_CONTINUE: break; + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + case JSON_C_VISIT_RETURN_STOP: + case JSON_C_VISIT_RETURN_ERROR: return userret; + default: + fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", + userret); + return JSON_C_VISIT_RETURN_ERROR; + } + + switch (json_object_get_type(jso)) + { + case json_type_null: + case json_type_boolean: + case json_type_double: + case json_type_int: + case json_type_string: + // we already called userfunc above, move on to the next object + return JSON_C_VISIT_RETURN_CONTINUE; + + case json_type_object: + { + json_object_object_foreach(jso, key, child) + { + userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg); + if (userret == JSON_C_VISIT_RETURN_POP) + break; + if (userret == JSON_C_VISIT_RETURN_STOP || + userret == JSON_C_VISIT_RETURN_ERROR) + return userret; + if (userret != JSON_C_VISIT_RETURN_CONTINUE && + userret != JSON_C_VISIT_RETURN_SKIP) + { + fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", + userret); + return JSON_C_VISIT_RETURN_ERROR; + } + } + break; + } + case json_type_array: + { + size_t array_len = json_object_array_length(jso); + size_t ii; + for (ii = 0; ii < array_len; ii++) + { + json_object *child = json_object_array_get_idx(jso, ii); + userret = _json_c_visit(child, jso, NULL, &ii, userfunc, userarg); + if (userret == JSON_C_VISIT_RETURN_POP) + break; + if (userret == JSON_C_VISIT_RETURN_STOP || + userret == JSON_C_VISIT_RETURN_ERROR) + return userret; + if (userret != JSON_C_VISIT_RETURN_CONTINUE && + userret != JSON_C_VISIT_RETURN_SKIP) + { + fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", + userret); + return JSON_C_VISIT_RETURN_ERROR; + } + } + break; + } + default: + fprintf(stderr, "INTERNAL ERROR: _json_c_visit found object of unknown type: %d\n", + json_object_get_type(jso)); + return JSON_C_VISIT_RETURN_ERROR; + } + + // Call userfunc for the second type on container types, after all + // members of the container have been visited. + // Non-container types will have already returned before this point. + + userret = userfunc(jso, JSON_C_VISIT_SECOND, parent_jso, jso_key, jso_index, userarg); + switch (userret) + { + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + // These are not really sensible during JSON_C_VISIT_SECOND, + // but map them to JSON_C_VISIT_CONTINUE anyway. + // FALLTHROUGH + case JSON_C_VISIT_RETURN_CONTINUE: return JSON_C_VISIT_RETURN_CONTINUE; + case JSON_C_VISIT_RETURN_STOP: + case JSON_C_VISIT_RETURN_ERROR: return userret; + default: + fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", + userret); + return JSON_C_VISIT_RETURN_ERROR; + } + // NOTREACHED +} diff --git a/comm/third_party/json-c/json_visit.h b/comm/third_party/json-c/json_visit.h new file mode 100644 index 0000000000..35c46f5b18 --- /dev/null +++ b/comm/third_party/json-c/json_visit.h @@ -0,0 +1,101 @@ + +#ifndef _json_c_json_visit_h_ +#define _json_c_json_visit_h_ + +/** + * @file + * @brief Methods for walking a tree of objects. + */ +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int(json_c_visit_userfunc)(json_object *jso, int flags, json_object *parent_jso, + const char *jso_key, size_t *jso_index, void *userarg); + +/** + * Visit each object in the JSON hierarchy starting at jso. + * For each object, userfunc is called, passing the object and userarg. + * If the object has a parent (i.e. anything other than jso itself) + * its parent will be passed as parent_jso, and either jso_key or jso_index + * will be set, depending on whether the parent is an object or an array. + * + * Nodes will be visited depth first, but containers (arrays and objects) + * will be visited twice, the second time with JSON_C_VISIT_SECOND set in + * flags. + * + * userfunc must return one of the defined return values, to indicate + * whether and how to continue visiting nodes, or one of various ways to stop. + * + * Returns 0 if nodes were visited successfully, even if some were + * intentionally skipped due to what userfunc returned. + * Returns <0 if an error occurred during iteration, including if + * userfunc returned JSON_C_VISIT_RETURN_ERROR. + */ +JSON_EXPORT int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *userfunc, + void *userarg); + +/** + * Passed to json_c_visit_userfunc as one of the flags values to indicate + * that this is the second time a container (array or object) is being + * called, after all of it's members have been iterated over. + */ +#define JSON_C_VISIT_SECOND 0x02 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should proceed normally. + */ +#define JSON_C_VISIT_RETURN_CONTINUE 0 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * over the members of the current object should be skipped. + * If the current object isn't a container (array or object), this + * is no different than JSON_C_VISIT_RETURN_CONTINUE. + */ +#define JSON_C_VISIT_RETURN_SKIP 7547 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * of the fields/elements of the containing object should stop + * and continue "popped up" a level of the object hierarchy. + * For example, returning this when handling arg will result in + * arg3 and any other fields being skipped. The next call to userfunc + * will be the JSON_C_VISIT_SECOND call on "foo", followed by a userfunc + * call on "bar". + *
+ * {
+ *   "foo": {
+ *     "arg1": 1,
+ *     "arg2": 2,
+ *     "arg3": 3,
+ *     ...
+ *   },
+ *   "bar": {
+ *     ...
+ *   }
+ * }
+ * 
+ */ +#define JSON_C_VISIT_RETURN_POP 767 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should stop immediately, and cause json_c_visit to return success. + */ +#define JSON_C_VISIT_RETURN_STOP 7867 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should stop immediately, and cause json_c_visit to return an error. + */ +#define JSON_C_VISIT_RETURN_ERROR -1 + +#ifdef __cplusplus +} +#endif + +#endif /* _json_c_json_visit_h_ */ diff --git a/comm/third_party/json-c/libjson.c b/comm/third_party/json-c/libjson.c new file mode 100644 index 0000000000..83d0a87fda --- /dev/null +++ b/comm/third_party/json-c/libjson.c @@ -0,0 +1,26 @@ + +/* dummy source file for compatibility purposes */ + +#if defined(HAVE_CDEFS_H) +#include +#endif + +#ifndef __warn_references + +#if defined(__GNUC__) && defined(HAS_GNU_WARNING_LONG) + +#define __warn_references(sym, msg) \ + __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text"); + +#else +#define __warn_references(sym, msg) /* nothing */ +#endif + +#endif + +#include "json_object.h" + +__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson"); + +/* __asm__(".section .gnu.warning." __STRING(sym) \ + " ; .ascii \"" msg "\" ; .text") */ diff --git a/comm/third_party/json-c/linkhash.c b/comm/third_party/json-c/linkhash.c new file mode 100644 index 0000000000..5e12c51e7c --- /dev/null +++ b/comm/third_party/json-c/linkhash.c @@ -0,0 +1,716 @@ +/* + * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ENDIAN_H +#include /* attempt to define endianness */ +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) +#define WIN32_LEAN_AND_MEAN +#include /* Get InterlockedCompareExchange */ +#endif + +#include "linkhash.h" +#include "random_seed.h" + +/* hash functions */ +static unsigned long lh_char_hash(const void *k); +static unsigned long lh_perllike_str_hash(const void *k); +static lh_hash_fn *char_hash_fn = lh_char_hash; + +/* comparison functions */ +int lh_char_equal(const void *k1, const void *k2); +int lh_ptr_equal(const void *k1, const void *k2); + +int json_global_set_string_hash(const int h) +{ + switch (h) + { + case JSON_C_STR_HASH_DFLT: char_hash_fn = lh_char_hash; break; + case JSON_C_STR_HASH_PERLLIKE: char_hash_fn = lh_perllike_str_hash; break; + default: return -1; + } + return 0; +} + +static unsigned long lh_ptr_hash(const void *k) +{ + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); +} + +int lh_ptr_equal(const void *k1, const void *k2) +{ + return (k1 == k2); +} + +/* + * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * https://burtleburtle.net/bob/c/lookup3.c + * minor modifications to make functions static so no symbols are exported + * minor modifications to compile with -Werror + */ + +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__i686__) || defined(vax) || defined(MIPSEL)) +#define HASH_LITTLE_ENDIAN 1 +#define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 1 +#else +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1 << (n)) +#define hashmask(n) (hashsize(n) - 1) +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used https://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +/* clang-format off */ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} +/* clang-format on */ + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +/* clang-format off */ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} +/* clang-format on */ + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + * AddressSanitizer is similarly picky about overrunning + * the buffer. (https://clang.llvm.org/docs/AddressSanitizer.html) + */ +#ifdef VALGRIND +#define PRECISE_MEMORY_ACCESS 1 +#elif defined(__SANITIZE_ADDRESS__) /* GCC's ASAN */ +#define PRECISE_MEMORY_ACCESS 1 +#elif defined(__has_feature) +#if __has_feature(address_sanitizer) /* Clang's ASAN */ +#define PRECISE_MEMORY_ACCESS 1 +#endif +#endif +#ifndef PRECISE_MEMORY_ACCESS + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } + else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) + { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } + else + { + /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; /* FALLTHRU */ + case 11: c+=((uint32_t)k[10])<<16; /* FALLTHRU */ + case 10: c+=((uint32_t)k[9])<<8; /* FALLTHRU */ + case 9 : c+=k[8]; /* FALLTHRU */ + case 8 : b+=((uint32_t)k[7])<<24; /* FALLTHRU */ + case 7 : b+=((uint32_t)k[6])<<16; /* FALLTHRU */ + case 6 : b+=((uint32_t)k[5])<<8; /* FALLTHRU */ + case 5 : b+=k[4]; /* FALLTHRU */ + case 4 : a+=((uint32_t)k[3])<<24; /* FALLTHRU */ + case 3 : a+=((uint32_t)k[2])<<16; /* FALLTHRU */ + case 2 : a+=((uint32_t)k[1])<<8; /* FALLTHRU */ + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} +/* clang-format on */ + +/* a simple hash function similar to what perl does for strings. + * for good results, the string should not be excessively large. + */ +static unsigned long lh_perllike_str_hash(const void *k) +{ + const char *rkey = (const char *)k; + unsigned hashval = 1; + + while (*rkey) + hashval = hashval * 33 + *rkey++; + + return hashval; +} + +static unsigned long lh_char_hash(const void *k) +{ +#if defined _MSC_VER || defined __MINGW32__ +#define RANDOM_SEED_TYPE LONG +#else +#define RANDOM_SEED_TYPE int +#endif + static volatile RANDOM_SEED_TYPE random_seed = -1; + + if (random_seed == -1) + { + RANDOM_SEED_TYPE seed; + /* we can't use -1 as it is the uninitialized sentinel */ + while ((seed = json_c_get_random_seed()) == -1) {} +#if SIZEOF_INT == 8 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if SIZEOF_INT == 4 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if SIZEOF_INT == 2 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if defined USE_SYNC_COMPARE_AND_SWAP + (void)__sync_val_compare_and_swap(&random_seed, -1, seed); +#elif defined _MSC_VER || defined __MINGW32__ + InterlockedCompareExchange(&random_seed, seed, -1); +#else + //#warning "racy random seed initialization if used by multiple threads" + random_seed = seed; /* potentially racy */ +#endif + } + + return hashlittle((const char *)k, strlen((const char *)k), (uint32_t)random_seed); +} + +int lh_char_equal(const void *k1, const void *k2) +{ + return (strcmp((const char *)k1, (const char *)k2) == 0); +} + +struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn) +{ + int i; + struct lh_table *t; + + /* Allocate space for elements to avoid divisions by zero. */ + assert(size > 0); + t = (struct lh_table *)calloc(1, sizeof(struct lh_table)); + if (!t) + return NULL; + + t->count = 0; + t->size = size; + t->table = (struct lh_entry *)calloc(size, sizeof(struct lh_entry)); + if (!t->table) + { + free(t); + return NULL; + } + t->free_fn = free_fn; + t->hash_fn = hash_fn; + t->equal_fn = equal_fn; + for (i = 0; i < size; i++) + t->table[i].k = LH_EMPTY; + return t; +} + +struct lh_table *lh_kchar_table_new(int size, lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, free_fn, char_hash_fn, lh_char_equal); +} + +struct lh_table *lh_kptr_table_new(int size, lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, free_fn, lh_ptr_hash, lh_ptr_equal); +} + +int lh_table_resize(struct lh_table *t, int new_size) +{ + struct lh_table *new_t; + struct lh_entry *ent; + + new_t = lh_table_new(new_size, NULL, t->hash_fn, t->equal_fn); + if (new_t == NULL) + return -1; + + for (ent = t->head; ent != NULL; ent = ent->next) + { + unsigned long h = lh_get_hash(new_t, ent->k); + unsigned int opts = 0; + if (ent->k_is_constant) + opts = JSON_C_OBJECT_ADD_CONSTANT_KEY; + if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0) + { + lh_table_free(new_t); + return -1; + } + } + free(t->table); + t->table = new_t->table; + t->size = new_size; + t->head = new_t->head; + t->tail = new_t->tail; + free(new_t); + + return 0; +} + +void lh_table_free(struct lh_table *t) +{ + struct lh_entry *c; + if (t->free_fn) + { + for (c = t->head; c != NULL; c = c->next) + t->free_fn(c); + } + free(t->table); + free(t); +} + +int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, + const unsigned opts) +{ + unsigned long n; + + if (t->count >= t->size * LH_LOAD_FACTOR) + { + /* Avoid signed integer overflow with large tables. */ + int new_size = (t->size > INT_MAX / 2) ? INT_MAX : (t->size * 2); + if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0) + return -1; + } + + n = h % t->size; + + while (1) + { + if (t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) + break; + if ((int)++n == t->size) + n = 0; + } + + t->table[n].k = k; + t->table[n].k_is_constant = (opts & JSON_C_OBJECT_ADD_CONSTANT_KEY); + t->table[n].v = v; + t->count++; + + if (t->head == NULL) + { + t->head = t->tail = &t->table[n]; + t->table[n].next = t->table[n].prev = NULL; + } + else + { + t->tail->next = &t->table[n]; + t->table[n].prev = t->tail; + t->table[n].next = NULL; + t->tail = &t->table[n]; + } + + return 0; +} +int lh_table_insert(struct lh_table *t, const void *k, const void *v) +{ + return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0); +} + +struct lh_entry *lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, + const unsigned long h) +{ + unsigned long n = h % t->size; + int count = 0; + + while (count < t->size) + { + if (t->table[n].k == LH_EMPTY) + return NULL; + if (t->table[n].k != LH_FREED && t->equal_fn(t->table[n].k, k)) + return &t->table[n]; + if ((int)++n == t->size) + n = 0; + count++; + } + return NULL; +} + +struct lh_entry *lh_table_lookup_entry(struct lh_table *t, const void *k) +{ + return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k)); +} + +json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if (e != NULL) + { + if (v != NULL) + *v = lh_entry_v(e); + return 1; /* key found */ + } + if (v != NULL) + *v = NULL; + return 0; /* key not found */ +} + +int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) +{ + /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ + ptrdiff_t n = (ptrdiff_t)(e - t->table); + + /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ + if (n < 0) + { + return -2; + } + + if (t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) + return -1; + t->count--; + if (t->free_fn) + t->free_fn(e); + t->table[n].v = NULL; + t->table[n].k = LH_FREED; + if (t->tail == &t->table[n] && t->head == &t->table[n]) + { + t->head = t->tail = NULL; + } + else if (t->head == &t->table[n]) + { + t->head->next->prev = NULL; + t->head = t->head->next; + } + else if (t->tail == &t->table[n]) + { + t->tail->prev->next = NULL; + t->tail = t->tail->prev; + } + else + { + t->table[n].prev->next = t->table[n].next; + t->table[n].next->prev = t->table[n].prev; + } + t->table[n].next = t->table[n].prev = NULL; + return 0; +} + +int lh_table_delete(struct lh_table *t, const void *k) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if (!e) + return -1; + return lh_table_delete_entry(t, e); +} + +int lh_table_length(struct lh_table *t) +{ + return t->count; +} diff --git a/comm/third_party/json-c/linkhash.h b/comm/third_party/json-c/linkhash.h new file mode 100644 index 0000000000..5e5e240822 --- /dev/null +++ b/comm/third_party/json-c/linkhash.h @@ -0,0 +1,447 @@ +/* + * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Internal methods for working with json_type_object objects. Although + * this is exposed by the json_object_get_object() function and within the + * json_object_iter type, it is not recommended for direct use. + */ +#ifndef _json_c_linkhash_h_ +#define _json_c_linkhash_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * golden prime used in hash functions + */ +#define LH_PRIME 0x9e370001UL + +/** + * The fraction of filled hash buckets until an insert will cause the table + * to be resized. + * This can range from just above 0 up to 1.0. + */ +#define LH_LOAD_FACTOR 0.66 + +/** + * sentinel pointer value for empty slots + */ +#define LH_EMPTY (void *)-1 + +/** + * sentinel pointer value for freed slots + */ +#define LH_FREED (void *)-2 + +/** + * default string hash function + */ +#define JSON_C_STR_HASH_DFLT 0 + +/** + * perl-like string hash function + */ +#define JSON_C_STR_HASH_PERLLIKE 1 + +/** + * This function sets the hash function to be used for strings. + * Must be one of the JSON_C_STR_HASH_* values. + * @returns 0 - ok, -1 if parameter was invalid + */ +int json_global_set_string_hash(const int h); + +struct lh_entry; + +/** + * callback function prototypes + */ +typedef void(lh_entry_free_fn)(struct lh_entry *e); +/** + * callback function prototypes + */ +typedef unsigned long(lh_hash_fn)(const void *k); +/** + * callback function prototypes + */ +typedef int(lh_equal_fn)(const void *k1, const void *k2); + +/** + * An entry in the hash table. Outside of linkhash.c, treat this as opaque. + */ +struct lh_entry +{ + /** + * The key. + * @deprecated Use lh_entry_k() instead of accessing this directly. + */ + const void *k; + /** + * A flag for users of linkhash to know whether or not they + * need to free k. + * @deprecated use lh_entry_k_is_constant() instead. + */ + int k_is_constant; + /** + * The value. + * @deprecated Use lh_entry_v() instead of accessing this directly. + */ + const void *v; + /** + * The next entry. + * @deprecated Use lh_entry_next() instead of accessing this directly. + */ + struct lh_entry *next; + /** + * The previous entry. + * @deprecated Use lh_entry_prev() instead of accessing this directly. + */ + struct lh_entry *prev; +}; + +/** + * The hash table structure. Outside of linkhash.c, treat this as opaque. + */ +struct lh_table +{ + /** + * Size of our hash. + * @deprecated do not use outside of linkhash.c + */ + int size; + /** + * Numbers of entries. + * @deprecated Use lh_table_length() instead. + */ + int count; + + /** + * The first entry. + * @deprecated Use lh_table_head() instead. + */ + struct lh_entry *head; + + /** + * The last entry. + * @deprecated Do not use, may be removed in a future release. + */ + struct lh_entry *tail; + + /** + * Internal storage of the actual table of entries. + * @deprecated do not use outside of linkhash.c + */ + struct lh_entry *table; + + /** + * A pointer to the function responsible for freeing an entry. + * @deprecated do not use outside of linkhash.c + */ + lh_entry_free_fn *free_fn; + /** + * @deprecated do not use outside of linkhash.c + */ + lh_hash_fn *hash_fn; + /** + * @deprecated do not use outside of linkhash.c + */ + lh_equal_fn *equal_fn; +}; +typedef struct lh_table lh_table; + +/** + * Convenience list iterator. + */ +#define lh_foreach(table, entry) for (entry = lh_table_head(table); entry; entry = lh_entry_next(entry)) + +/** + * lh_foreach_safe allows calling of deletion routine while iterating. + * + * @param table a struct lh_table * to iterate over + * @param entry a struct lh_entry * variable to hold each element + * @param tmp a struct lh_entry * variable to hold a temporary pointer to the next element + */ +#define lh_foreach_safe(table, entry, tmp) \ + for (entry = lh_table_head(table); entry && ((tmp = lh_entry_next(entry)) || 1); entry = tmp) + +/** + * Create a new linkhash table. + * + * @param size initial table size. The table is automatically resized + * although this incurs a performance penalty. + * @param free_fn callback function used to free memory for entries + * when lh_table_free or lh_table_delete is called. + * If NULL is provided, then memory for keys and values + * must be freed by the caller. + * @param hash_fn function used to hash keys. 2 standard ones are defined: + * lh_ptr_hash and lh_char_hash for hashing pointer values + * and C strings respectively. + * @param equal_fn comparison function to compare keys. 2 standard ones defined: + * lh_ptr_hash and lh_char_hash for comparing pointer values + * and C strings respectively. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. + */ +extern struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn); + +/** + * Convenience function to create a new linkhash table with char keys. + * + * @param size initial table size. + * @param free_fn callback function used to free memory for entries. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. + */ +extern struct lh_table *lh_kchar_table_new(int size, lh_entry_free_fn *free_fn); + +/** + * Convenience function to create a new linkhash table with ptr keys. + * + * @param size initial table size. + * @param free_fn callback function used to free memory for entries. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. + */ +extern struct lh_table *lh_kptr_table_new(int size, lh_entry_free_fn *free_fn); + +/** + * Free a linkhash table. + * + * If a lh_entry_free_fn callback free function was provided then it is + * called for all entries in the table. + * + * @param t table to free. + */ +extern void lh_table_free(struct lh_table *t); + +/** + * Insert a record into the table. + * + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +extern int lh_table_insert(struct lh_table *t, const void *k, const void *v); + +/** + * Insert a record into the table using a precalculated key hash. + * + * The hash h, which should be calculated with lh_get_hash() on k, is provided by + * the caller, to allow for optimization when multiple operations with the same + * key are known to be needed. + * + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + * @param h hash value of the key to insert + * @param opts if set to JSON_C_OBJECT_ADD_CONSTANT_KEY, sets lh_entry.k_is_constant + * so t's free function knows to avoid freeing the key. + */ +extern int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, + const unsigned long h, const unsigned opts); + +/** + * Lookup a record in the table. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry *lh_table_lookup_entry(struct lh_table *t, const void *k); + +/** + * Lookup a record in the table using a precalculated key hash. + * + * The hash h, which should be calculated with lh_get_hash() on k, is provided by + * the caller, to allow for optimization when multiple operations with the same + * key are known to be needed. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param h hash value of the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry *lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, + const unsigned long h); + +/** + * Lookup a record in the table. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). + * @return whether or not the key was found + */ +extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v); + +/** + * Delete a record from the table. + * + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param e a pointer to the entry to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); + +/** + * Delete a record from the table. + * + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param k a pointer to the key to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete(struct lh_table *t, const void *k); + +/** + * Return the number of entries in the table. + */ +extern int lh_table_length(struct lh_table *t); + +/** + * Resizes the specified table. + * + * @param t Pointer to table to resize. + * @param new_size New table size. Must be positive. + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +int lh_table_resize(struct lh_table *t, int new_size); + +/** + * @deprecated Don't use this outside of linkhash.h: + */ +#if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)) ) +/* VS2010 can't handle inline funcs, so skip it there */ +#define _LH_INLINE +#else +#define _LH_INLINE inline +#endif + +/** + * Return the first entry in the lh_table. + * @see lh_entry_next() + */ +static _LH_INLINE struct lh_entry *lh_table_head(const lh_table *t) +{ + return t->head; +} + +/** + * Calculate the hash of a key for a given table. + * + * This is an extension to support functions that need to calculate + * the hash several times and allows them to do it just once and then pass + * in the hash to all utility functions. Depending on use case, this can be a + * considerable performance improvement. + * @param t the table (used to obtain hash function) + * @param k a pointer to the key to lookup + * @return the key's hash + */ +static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void *k) +{ + return t->hash_fn(k); +} + + +/** + * @deprecated Don't use this outside of linkhash.h: + */ +#ifdef __UNCONST +#define _LH_UNCONST(a) __UNCONST(a) +#else +#define _LH_UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) +#endif + +/** + * Return a non-const version of lh_entry.k. + * + * lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify + * it, but callers are allowed to do what they want with it. + * @see lh_entry_k_is_constant() + */ +static _LH_INLINE void *lh_entry_k(const struct lh_entry *e) +{ + return _LH_UNCONST(e->k); +} + +/** + * Returns 1 if the key for the given entry is constant, and thus + * does not need to be freed when the lh_entry is freed. + * @see lh_table_insert_w_hash() + */ +static _LH_INLINE int lh_entry_k_is_constant(const struct lh_entry *e) +{ + return e->k_is_constant; +} + +/** + * Return a non-const version of lh_entry.v. + * + * v is const to indicate and help ensure that linkhash itself doesn't modify + * it, but callers are allowed to do what they want with it. + */ +static _LH_INLINE void *lh_entry_v(const struct lh_entry *e) +{ + return _LH_UNCONST(e->v); +} + +/** + * Change the value for an entry. The caller is responsible for freeing + * the previous value. + */ +static _LH_INLINE void lh_entry_set_val(struct lh_entry *e, void *newval) +{ + e->v = newval; +} + +/** + * Return the next element, or NULL if there is no next element. + * @see lh_table_head() + * @see lh_entry_prev() + */ +static _LH_INLINE struct lh_entry *lh_entry_next(const struct lh_entry *e) +{ + return e->next; +} + +/** + * Return the previous element, or NULL if there is no previous element. + * @see lh_table_head() + * @see lh_entry_next() + */ +static _LH_INLINE struct lh_entry *lh_entry_prev(const struct lh_entry *e) +{ + return e->prev; +} + +#undef _LH_INLINE + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/math_compat.h b/comm/third_party/json-c/math_compat.h new file mode 100644 index 0000000000..2382fe15b3 --- /dev/null +++ b/comm/third_party/json-c/math_compat.h @@ -0,0 +1,43 @@ +#ifndef __math_compat_h +#define __math_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* Define isnan, isinf, infinity and nan on Windows/MSVC */ + +#ifndef HAVE_DECL_ISNAN +#ifdef HAVE_DECL__ISNAN +#include +#define isnan(x) _isnan(x) +#else +/* On platforms like AIX and "IBM i" we need to provide our own isnan */ +#define isnan(x) ((x) != (x)) +#endif +#endif + +#ifndef HAVE_DECL_ISINF +#ifdef HAVE_DECL__FINITE +#include +#define isinf(x) (!_finite(x)) +#else +#include +/* On platforms like AIX and "IBM i" we need to provide our own isinf */ +#define isinf(x) ((x) < -DBL_MAX || (x) > DBL_MAX) +#endif +#endif + +#ifndef HAVE_DECL_INFINITY +#include +#define INFINITY (DBL_MAX + DBL_MAX) +#define HAVE_DECL_INFINITY +#endif + +#ifndef HAVE_DECL_NAN +#define NAN (INFINITY - INFINITY) +#define HAVE_DECL_NAN +#endif + +#endif diff --git a/comm/third_party/json-c/moz.build b/comm/third_party/json-c/moz.build new file mode 100644 index 0000000000..788f9856db --- /dev/null +++ b/comm/third_party/json-c/moz.build @@ -0,0 +1,52 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library("json-c") +FINAL_LIBRARY = "rnp" + +# Honor --with-system-jsonc +if CONFIG["MZLA_SYSTEM_JSONC"]: + OS_LIBS += CONFIG["MZLA_JSONC_LIBS"] +else: + include("../rnpdefs.mozbuild") + + if CONFIG["CC_TYPE"] == "clang-cl": + COMPILE_FLAGS["WARNINGS_CFLAGS"] += [ + "-Wno-macro-redefined", + ] + + DEFINES["_GNU_SOURCE"] = True + DEFINES["CC"] = CONFIG["_CC"] + + CONFIGURE_DEFINE_FILES += ["config.h", "json_config.h"] + + GeneratedFile( + "json.h", + script="/python/mozbuild/mozbuild/action/preprocessor.py", + entry_point="generate", + inputs=["json.h.cmakein"], + flags=[ + "--marker", "%", + "-F", "substitution", + "-DJSON_H_JSON_POINTER=#include \"json_pointer.h\"" + ] + ) + + SOURCES += [ + "arraylist.c", + "debug.c", + "json_c_version.c", + "json_object.c", + "json_object_iterator.c", + "json_pointer.c", + "json_tokener.c", + "json_util.c", + "json_visit.c", + "linkhash.c", + "printbuf.c", + "random_seed.c", + "strerror_override.c", + ] diff --git a/comm/third_party/json-c/printbuf.c b/comm/third_party/json-c/printbuf.c new file mode 100644 index 0000000000..a08f7b1582 --- /dev/null +++ b/comm/third_party/json-c/printbuf.c @@ -0,0 +1,180 @@ +/* + * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (https://www.opensource.org/licenses/mit-license.php) + */ + +#include "config.h" + +#include +#include +#include +#include + +#ifdef HAVE_STDARG_H +#include +#else /* !HAVE_STDARG_H */ +#error Not enough var arg support! +#endif /* HAVE_STDARG_H */ + +#include "debug.h" +#include "printbuf.h" +#include "snprintf_compat.h" +#include "vasprintf_compat.h" + +static int printbuf_extend(struct printbuf *p, int min_size); + +struct printbuf *printbuf_new(void) +{ + struct printbuf *p; + + p = (struct printbuf *)calloc(1, sizeof(struct printbuf)); + if (!p) + return NULL; + p->size = 32; + p->bpos = 0; + if (!(p->buf = (char *)malloc(p->size))) + { + free(p); + return NULL; + } + p->buf[0] = '\0'; + return p; +} + +/** + * Extend the buffer p so it has a size of at least min_size. + * + * If the current size is large enough, nothing is changed. + * + * Note: this does not check the available space! The caller + * is responsible for performing those calculations. + */ +static int printbuf_extend(struct printbuf *p, int min_size) +{ + char *t; + int new_size; + + if (p->size >= min_size) + return 0; + /* Prevent signed integer overflows with large buffers. */ + if (min_size > INT_MAX - 8) + return -1; + if (p->size > INT_MAX / 2) + new_size = min_size + 8; + else { + new_size = p->size * 2; + if (new_size < min_size + 8) + new_size = min_size + 8; + } +#ifdef PRINTBUF_DEBUG + MC_DEBUG("printbuf_memappend: realloc " + "bpos=%d min_size=%d old_size=%d new_size=%d\n", + p->bpos, min_size, p->size, new_size); +#endif /* PRINTBUF_DEBUG */ + if (!(t = (char *)realloc(p->buf, new_size))) + return -1; + p->size = new_size; + p->buf = t; + return 0; +} + +int printbuf_memappend(struct printbuf *p, const char *buf, int size) +{ + /* Prevent signed integer overflows with large buffers. */ + if (size < 0 || size > INT_MAX - p->bpos - 1) + return -1; + if (p->size <= p->bpos + size + 1) + { + if (printbuf_extend(p, p->bpos + size + 1) < 0) + return -1; + } + memcpy(p->buf + p->bpos, buf, size); + p->bpos += size; + p->buf[p->bpos] = '\0'; + return size; +} + +int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) +{ + int size_needed; + + if (offset == -1) + offset = pb->bpos; + /* Prevent signed integer overflows with large buffers. */ + if (len < 0 || offset < -1 || len > INT_MAX - offset) + return -1; + size_needed = offset + len; + if (pb->size < size_needed) + { + if (printbuf_extend(pb, size_needed) < 0) + return -1; + } + + if (pb->bpos < offset) + memset(pb->buf + pb->bpos, '\0', offset - pb->bpos); + memset(pb->buf + offset, charvalue, len); + if (pb->bpos < size_needed) + pb->bpos = size_needed; + + return 0; +} + +int sprintbuf(struct printbuf *p, const char *msg, ...) +{ + va_list ap; + char *t; + int size; + char buf[128]; + + /* use stack buffer first */ + va_start(ap, msg); + size = vsnprintf(buf, 128, msg, ap); + va_end(ap); + /* if string is greater than stack buffer, then use dynamic string + * with vasprintf. Note: some implementations of vsnprintf return -1 + * if output is truncated whereas some return the number of bytes that + * would have been written - this code handles both cases. + */ + if (size < 0 || size > 127) + { + va_start(ap, msg); + if ((size = vasprintf(&t, msg, ap)) < 0) + { + va_end(ap); + return -1; + } + va_end(ap); + size = printbuf_memappend(p, t, size); + free(t); + } + else + { + size = printbuf_memappend(p, buf, size); + } + return size; +} + +void printbuf_reset(struct printbuf *p) +{ + p->buf[0] = '\0'; + p->bpos = 0; +} + +void printbuf_free(struct printbuf *p) +{ + if (p) + { + free(p->buf); + free(p); + } +} diff --git a/comm/third_party/json-c/printbuf.h b/comm/third_party/json-c/printbuf.h new file mode 100644 index 0000000000..8dbf2c6ae1 --- /dev/null +++ b/comm/third_party/json-c/printbuf.h @@ -0,0 +1,131 @@ +/* + * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (https://www.opensource.org/licenses/mit-license.php) + */ + +/** + * @file + * @brief Internal string buffer handling. Unless you're writing a + * json_object_to_json_string_fn implementation for use with + * json_object_set_serializer() direct use of this is not + * recommended. + */ +#ifndef _json_c_printbuf_h_ +#define _json_c_printbuf_h_ + +#ifndef JSON_EXPORT +#if defined(_MSC_VER) && defined(JSON_C_DLL) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct printbuf +{ + char *buf; + int bpos; + int size; +}; +typedef struct printbuf printbuf; + +JSON_EXPORT struct printbuf *printbuf_new(void); + +/* As an optimization, printbuf_memappend_fast() is defined as a macro + * that handles copying data if the buffer is large enough; otherwise + * it invokes printbuf_memappend() which performs the heavy + * lifting of realloc()ing the buffer and copying data. + * + * Your code should not use printbuf_memappend() directly unless it + * checks the return code. Use printbuf_memappend_fast() instead. + */ +JSON_EXPORT int printbuf_memappend(struct printbuf *p, const char *buf, int size); + +#define printbuf_memappend_fast(p, bufptr, bufsize) \ + do \ + { \ + if ((p->size - p->bpos) > bufsize) \ + { \ + memcpy(p->buf + p->bpos, (bufptr), bufsize); \ + p->bpos += bufsize; \ + p->buf[p->bpos] = '\0'; \ + } \ + else \ + { \ + printbuf_memappend(p, (bufptr), bufsize); \ + } \ + } while (0) + +#define printbuf_length(p) ((p)->bpos) + +/** + * Results in a compile error if the argument is not a string literal. + */ +#define _printbuf_check_literal(mystr) ("" mystr) + +/** + * This is an optimization wrapper around printbuf_memappend() that is useful + * for appending string literals. Since the size of string constants is known + * at compile time, using this macro can avoid a costly strlen() call. This is + * especially helpful when a constant string must be appended many times. If + * you got here because of a compilation error caused by passing something + * other than a string literal, use printbuf_memappend_fast() in conjunction + * with strlen(). + * + * See also: + * printbuf_memappend_fast() + * printbuf_memappend() + * sprintbuf() + */ +#define printbuf_strappend(pb, str) \ + printbuf_memappend((pb), _printbuf_check_literal(str), sizeof(str) - 1) + +/** + * Set len bytes of the buffer to charvalue, starting at offset offset. + * Similar to calling memset(x, charvalue, len); + * + * The memory allocated for the buffer is extended as necessary. + * + * If offset is -1, this starts at the end of the current data in the buffer. + */ +JSON_EXPORT int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len); + +/** + * Formatted print to printbuf. + * + * This function is the most expensive of the available functions for appending + * string data to a printbuf and should be used only where convenience is more + * important than speed. Avoid using this function in high performance code or + * tight loops; in these scenarios, consider using snprintf() with a static + * buffer in conjunction with one of the printbuf_*append() functions. + * + * See also: + * printbuf_memappend_fast() + * printbuf_memappend() + * printbuf_strappend() + */ +JSON_EXPORT int sprintbuf(struct printbuf *p, const char *msg, ...); + +JSON_EXPORT void printbuf_reset(struct printbuf *p); + +JSON_EXPORT void printbuf_free(struct printbuf *p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/random_seed.c b/comm/third_party/json-c/random_seed.c new file mode 100644 index 0000000000..7945824c7a --- /dev/null +++ b/comm/third_party/json-c/random_seed.c @@ -0,0 +1,355 @@ +/* + * random_seed.c + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "random_seed.h" +#include "config.h" +#include "strerror_override.h" +#include +#include +#ifdef HAVE_BSD_STDLIB_H +#include +#endif + +#define DEBUG_SEED(s) + +#if defined(__APPLE__) || defined(__unix__) || defined(__linux__) +#define HAVE_DEV_RANDOM 1 +#endif + +#ifdef HAVE_ARC4RANDOM +#undef HAVE_GETRANDOM +#undef HAVE_DEV_RANDOM +#undef HAVE_CRYPTGENRANDOM +#endif + +#if defined ENABLE_RDRAND + +/* cpuid */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) +#define HAS_X86_CPUID 1 + +static void do_cpuid(int regs[], int h) +{ + /* clang-format off */ + __asm__ __volatile__("cpuid" + : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(h)); + /* clang-format on */ +} + +#elif defined _MSC_VER + +#define HAS_X86_CPUID 1 +#define do_cpuid __cpuid + +#endif + +/* has_rdrand */ + +#if HAS_X86_CPUID + +static int get_rdrand_seed(void); + +/* Valid values are -1 (haven't tested), 0 (no), and 1 (yes). */ +static int _has_rdrand = -1; + +static int has_rdrand(void) +{ + if (_has_rdrand != -1) + { + return _has_rdrand; + } + + /* CPUID.01H:ECX.RDRAND[bit 30] == 1 */ + int regs[4]; + do_cpuid(regs, 1); + if (!(regs[2] & (1 << 30))) + { + _has_rdrand = 0; + return 0; + } + + /* + * Some CPUs advertise RDRAND in CPUID, but return 0xFFFFFFFF + * unconditionally. To avoid locking up later, test RDRAND here. If over + * 3 trials RDRAND has returned the same value, declare it broken. + * Example CPUs are AMD Ryzen 3000 series + * and much older AMD APUs, such as the E1-1500 + * https://github.com/systemd/systemd/issues/11810 + * https://linuxreviews.org/RDRAND_stops_returning_random_values_on_older_AMD_CPUs_after_suspend + */ + _has_rdrand = 0; + int prev = get_rdrand_seed(); + for (int i = 0; i < 3; i++) + { + int temp = get_rdrand_seed(); + if (temp != prev) + { + _has_rdrand = 1; + break; + } + + prev = temp; + } + + return _has_rdrand; +} + +#endif + +/* get_rdrand_seed - GCC x86 and X64 */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + +#define HAVE_RDRAND 1 + +static int get_rdrand_seed(void) +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; + /* rdrand eax */ + /* clang-format off */ + __asm__ __volatile__("1: .byte 0x0F\n" + " .byte 0xC7\n" + " .byte 0xF0\n" + " jnc 1b;\n" + : "=a" (_eax)); + /* clang-format on */ + return _eax; +} + +#endif + +#if defined _MSC_VER + +#if _MSC_VER >= 1700 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2012 and above */ + +static int get_rdrand_seed(void) +{ + DEBUG_SEED("get_rdrand_seed"); + int r; + while (_rdrand32_step(&r) == 0) + ; + return r; +} + +#elif defined _M_IX86 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */ + +/* clang-format off */ +static int get_rdrand_seed(void) +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; +retry: + /* rdrand eax */ + __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 + __asm jnc retry + __asm mov _eax, eax + return _eax; +} +/* clang-format on */ + +#endif +#endif + +#endif /* defined ENABLE_RDRAND */ + +#ifdef HAVE_GETRANDOM + +#include +#ifdef HAVE_SYS_RANDOM_H +#include +#endif + +static int get_getrandom_seed(int *seed) +{ + DEBUG_SEED("get_getrandom_seed"); + + ssize_t ret; + + do + { + ret = getrandom(seed, sizeof(*seed), GRND_NONBLOCK); + } while ((ret == -1) && (errno == EINTR)); + + if (ret == -1) + { + if (errno == ENOSYS) /* syscall not available in kernel */ + return -1; + if (errno == EAGAIN) /* entropy not yet initialized */ + return -1; + + fprintf(stderr, "error from getrandom(): %s", strerror(errno)); + return -1; + } + + if (ret != sizeof(*seed)) + return -1; + + return 0; +} +#endif /* defined HAVE_GETRANDOM */ + +/* get_dev_random_seed */ + +#ifdef HAVE_DEV_RANDOM + +#include +#include +#if HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include +#include + +static const char *dev_random_file = "/dev/urandom"; + +static int get_dev_random_seed(int *seed) +{ + DEBUG_SEED("get_dev_random_seed"); + + struct stat buf; + if (stat(dev_random_file, &buf)) + return -1; + if ((buf.st_mode & S_IFCHR) == 0) + return -1; + + int fd = open(dev_random_file, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); + return -1; + } + + ssize_t nread = read(fd, seed, sizeof(*seed)); + + close(fd); + + if (nread != sizeof(*seed)) + { + fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); + return -1; + } + + return 0; +} + +#endif + +/* get_cryptgenrandom_seed */ + +#ifdef WIN32 + +#define HAVE_CRYPTGENRANDOM 1 + +/* clang-format off */ +#include + +/* Caution: these blank lines must remain so clang-format doesn't reorder + includes to put windows.h after wincrypt.h */ + +#include +/* clang-format on */ +#ifndef __GNUC__ +#pragma comment(lib, "advapi32.lib") +#endif + +static int get_cryptgenrandom_seed(int *seed) +{ + HCRYPTPROV hProvider = 0; + DWORD dwFlags = CRYPT_VERIFYCONTEXT; + + DEBUG_SEED("get_cryptgenrandom_seed"); + + /* WinNT 4 and Win98 do no support CRYPT_SILENT */ + if (LOBYTE(LOWORD(GetVersion())) > 4) + dwFlags |= CRYPT_SILENT; + + if (!CryptAcquireContextA(&hProvider, 0, 0, PROV_RSA_FULL, dwFlags)) + { + fprintf(stderr, "error CryptAcquireContextA 0x%08lx", GetLastError()); + return -1; + } + else + { + BOOL ret = CryptGenRandom(hProvider, sizeof(*seed), (BYTE *)seed); + CryptReleaseContext(hProvider, 0); + if (!ret) + { + fprintf(stderr, "error CryptGenRandom 0x%08lx", GetLastError()); + return -1; + } + } + + return 0; +} + +#endif + +/* get_time_seed */ + +#ifndef HAVE_ARC4RANDOM +#include + +static int get_time_seed(void) +{ + DEBUG_SEED("get_time_seed"); + + return (unsigned)time(NULL) * 433494437; +} +#endif + +/* json_c_get_random_seed */ + +int json_c_get_random_seed(void) +{ +#ifdef OVERRIDE_GET_RANDOM_SEED + OVERRIDE_GET_RANDOM_SEED; +#endif +#if defined HAVE_RDRAND && HAVE_RDRAND + if (has_rdrand()) + return get_rdrand_seed(); +#endif +#ifdef HAVE_ARC4RANDOM + /* arc4random never fails, so use it if it's available */ + return arc4random(); +#else +#ifdef HAVE_GETRANDOM + { + int seed = 0; + if (get_getrandom_seed(&seed) == 0) + return seed; + } +#endif +#if defined HAVE_DEV_RANDOM && HAVE_DEV_RANDOM + { + int seed = 0; + if (get_dev_random_seed(&seed) == 0) + return seed; + } +#endif +#if defined HAVE_CRYPTGENRANDOM && HAVE_CRYPTGENRANDOM + { + int seed = 0; + if (get_cryptgenrandom_seed(&seed) == 0) + return seed; + } +#endif + return get_time_seed(); +#endif /* !HAVE_ARC4RANDOM */ +} diff --git a/comm/third_party/json-c/random_seed.h b/comm/third_party/json-c/random_seed.h new file mode 100644 index 0000000000..72ee5f6e85 --- /dev/null +++ b/comm/third_party/json-c/random_seed.h @@ -0,0 +1,29 @@ +/* + * random_seed.h + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef seed_h +#define seed_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern int json_c_get_random_seed(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/comm/third_party/json-c/snprintf_compat.h b/comm/third_party/json-c/snprintf_compat.h new file mode 100644 index 0000000000..76f7a6ce22 --- /dev/null +++ b/comm/third_party/json-c/snprintf_compat.h @@ -0,0 +1,41 @@ +#ifndef __snprintf_compat_h +#define __snprintf_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* + * Microsoft's _vsnprintf and _snprint don't always terminate + * the string, so use wrappers that ensure that. + */ + +#include + +#if !defined(HAVE_SNPRINTF) && (defined(_MSC_VER) || defined(__MINGW32__)) +static int json_c_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int ret; + ret = _vsnprintf(str, size, format, ap); + str[size - 1] = '\0'; + return ret; +} +#define vsnprintf json_c_vsnprintf + +static int json_c_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int ret; + va_start(ap, format); + ret = json_c_vsnprintf(str, size, format, ap); + va_end(ap); + return ret; +} +#define snprintf json_c_snprintf + +#elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ +#error Need vsnprintf! +#endif /* !HAVE_SNPRINTF && defined(WIN32) */ + +#endif /* __snprintf_compat_h */ diff --git a/comm/third_party/json-c/strdup_compat.h b/comm/third_party/json-c/strdup_compat.h new file mode 100644 index 0000000000..2f2df65a0d --- /dev/null +++ b/comm/third_party/json-c/strdup_compat.h @@ -0,0 +1,16 @@ +#ifndef __strdup_compat_h +#define __strdup_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#if !defined(HAVE_STRDUP) && defined(_MSC_VER) +/* MSC has the version as _strdup */ +#define strdup _strdup +#elif !defined(HAVE_STRDUP) +#error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + +#endif diff --git a/comm/third_party/json-c/strerror_override.c b/comm/third_party/json-c/strerror_override.c new file mode 100644 index 0000000000..a3dd377a3d --- /dev/null +++ b/comm/third_party/json-c/strerror_override.c @@ -0,0 +1,110 @@ +#define STRERROR_OVERRIDE_IMPL 1 +#include "strerror_override.h" + +/* + * Override strerror() to get consistent output across platforms. + */ + +static struct +{ + int errno_value; + const char *errno_str; +} errno_list[] = { +/* clang-format off */ +#define STRINGIFY(x) #x +#define ENTRY(x) {x, &STRINGIFY(undef_ ## x)[6]} + ENTRY(EPERM), + ENTRY(ENOENT), + ENTRY(ESRCH), + ENTRY(EINTR), + ENTRY(EIO), + ENTRY(ENXIO), + ENTRY(E2BIG), +#ifdef ENOEXEC + ENTRY(ENOEXEC), +#endif + ENTRY(EBADF), + ENTRY(ECHILD), + ENTRY(EDEADLK), + ENTRY(ENOMEM), + ENTRY(EACCES), + ENTRY(EFAULT), +#ifdef ENOTBLK + ENTRY(ENOTBLK), +#endif + ENTRY(EBUSY), + ENTRY(EEXIST), + ENTRY(EXDEV), + ENTRY(ENODEV), + ENTRY(ENOTDIR), + ENTRY(EISDIR), + ENTRY(EINVAL), + ENTRY(ENFILE), + ENTRY(EMFILE), + ENTRY(ENOTTY), +#ifdef ETXTBSY + ENTRY(ETXTBSY), +#endif + ENTRY(EFBIG), + ENTRY(ENOSPC), + ENTRY(ESPIPE), + ENTRY(EROFS), + ENTRY(EMLINK), + ENTRY(EPIPE), + ENTRY(EDOM), + ENTRY(ERANGE), + ENTRY(EAGAIN), + { 0, (char *)0 } +}; +/* clang-format on */ + +// Enabled during tests +static int _json_c_strerror_enable = 0; +extern char *getenv(const char *name); // Avoid including stdlib.h + +#define PREFIX "ERRNO=" +static char errno_buf[128] = PREFIX; +char *_json_c_strerror(int errno_in) +{ + int start_idx; + char digbuf[20]; + int ii, jj; + + if (!_json_c_strerror_enable) + _json_c_strerror_enable = (getenv("_JSON_C_STRERROR_ENABLE") == NULL) ? -1 : 1; + if (_json_c_strerror_enable == -1) + return strerror(errno_in); + + // Avoid standard functions, so we don't need to include any + // headers, or guess at signatures. + + for (ii = 0; errno_list[ii].errno_str != (char *)0; ii++) + { + const char *errno_str = errno_list[ii].errno_str; + if (errno_list[ii].errno_value != errno_in) + continue; + + for (start_idx = sizeof(PREFIX) - 1, jj = 0; errno_str[jj] != '\0'; + jj++, start_idx++) + { + errno_buf[start_idx] = errno_str[jj]; + } + errno_buf[start_idx] = '\0'; + return errno_buf; + } + + // It's not one of the known errno values, return the numeric value. + for (ii = 0; errno_in >= 10; errno_in /= 10, ii++) + { + digbuf[ii] = "0123456789"[(errno_in % 10)]; + } + digbuf[ii] = "0123456789"[(errno_in % 10)]; + + // Reverse the digits + for (start_idx = sizeof(PREFIX) - 1; ii >= 0; ii--, start_idx++) + { + errno_buf[start_idx] = digbuf[ii]; + } + errno_buf[start_idx] = '\0'; + return errno_buf; +} diff --git a/comm/third_party/json-c/strerror_override.h b/comm/third_party/json-c/strerror_override.h new file mode 100644 index 0000000000..0b04eb4cab --- /dev/null +++ b/comm/third_party/json-c/strerror_override.h @@ -0,0 +1,30 @@ +#ifndef _json_strerror_override_h_ +#define _json_strerror_override_h_ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "config.h" +#include + +#include "json_object.h" /* for JSON_EXPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +JSON_EXPORT char *_json_c_strerror(int errno_in); + +#ifndef STRERROR_OVERRIDE_IMPL +#define strerror _json_c_strerror +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _json_strerror_override_h_ */ diff --git a/comm/third_party/json-c/strerror_override_private.h b/comm/third_party/json-c/strerror_override_private.h new file mode 100644 index 0000000000..8726e59fc3 --- /dev/null +++ b/comm/third_party/json-c/strerror_override_private.h @@ -0,0 +1,14 @@ +#ifndef __json_strerror_override_private_h__ +#define __json_strerror_override_private_h__ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "json_types.h" + +/* Used by tests to get consistent output */ +JSON_EXPORT int _json_c_strerror_enable; + +#endif diff --git a/comm/third_party/json-c/vasprintf_compat.h b/comm/third_party/json-c/vasprintf_compat.h new file mode 100644 index 0000000000..59b2e96074 --- /dev/null +++ b/comm/third_party/json-c/vasprintf_compat.h @@ -0,0 +1,67 @@ +#ifndef __vasprintf_compat_h +#define __vasprintf_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "snprintf_compat.h" + +#ifndef WIN32 +#include +#endif /* !defined(WIN32) */ +#include +#include + +#if !defined(HAVE_VASPRINTF) +/* CAW: compliant version of vasprintf */ +static int vasprintf(char **buf, const char *fmt, va_list ap) +{ +#ifndef WIN32 + static char _T_emptybuffer = '\0'; + va_list ap2; +#endif /* !defined(WIN32) */ + int chars; + char *b; + + if (!buf) + { + return -1; + } + +#ifdef WIN32 + chars = _vscprintf(fmt, ap); +#else /* !defined(WIN32) */ + /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite + * our buffer like on some 64bit sun systems... but hey, it's time to move on + */ + va_copy(ap2, ap); + chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap2); + va_end(ap2); +#endif /* defined(WIN32) */ + if (chars < 0 || (size_t)chars + 1 > SIZE_MAX / sizeof(char)) + { + return -1; + } + + b = (char *)malloc(sizeof(char) * ((size_t)chars + 1)); + if (!b) + { + return -1; + } + + if ((chars = vsprintf(b, fmt, ap)) < 0) + { + free(b); + } + else + { + *buf = b; + } + + return chars; +} +#endif /* !HAVE_VASPRINTF */ + +#endif /* __vasprintf_compat_h */ diff --git a/comm/third_party/libgcrypt/AUTHORS b/comm/third_party/libgcrypt/AUTHORS new file mode 100644 index 0000000000..f6bfcb851f --- /dev/null +++ b/comm/third_party/libgcrypt/AUTHORS @@ -0,0 +1,257 @@ +Library: Libgcrypt +Homepage: https://www.gnupg.org/related_software/libgcrypt/ +Download: https://ftp.gnupg.org/ftp/gcrypt/libgcrypt/ + ftp://ftp.gnupg.org/gcrypt/libgcrypt/ +Repository: git://git.gnupg.org/libgcrypt.git +Maintainer: Werner Koch +Bug reports: https://bugs.gnupg.org +Security related bug reports: +End-of-life: TBD +License (library): LGPLv2.1+ +License (manual and tools): GPLv2+ + + +Libgcrypt is free software. See the files COPYING.LIB and COPYING for +copying conditions, and LICENSES for notices about a few contributions +that require these additional notices to be distributed. License +copyright years may be listed using range notation, e.g., 2000-2013, +indicating that every year in the range, inclusive, is a copyrightable +year that would otherwise be listed individually. + + +List of Copyright holders +========================= + + Copyright (C) 1989,1991-2018 Free Software Foundation, Inc. + Copyright (C) 1994 X Consortium + Copyright (C) 1996 L. Peter Deutsch + Copyright (C) 1997 Werner Koch + Copyright (C) 1998 The Internet Society + Copyright (C) 1996-1999 Peter Gutmann, Paul Kendall, and Chris Wedgwood + Copyright (C) 1996-2006 Peter Gutmann, Matt Thomlinson and Blake Coverett + Copyright (C) 2003 Nikos Mavroyanopoulos + Copyright (C) 2006-2007 NTT (Nippon Telegraph and Telephone Corporation) + Copyright (C) 2012-2021 g10 Code GmbH + Copyright (C) 2012 Simon Josefsson, Niels Möller + Copyright (c) 2012 Intel Corporation + Copyright (C) 2013 Christian Grothoff + Copyright (C) 2013-2021 Jussi Kivilinna + Copyright (C) 2013-2014 Dmitry Eremin-Solenikov + Copyright (C) 2014 Stephan Mueller + Copyright (C) 2017 Jia Zhang + Copyright (C) 2018 Bundesamt für Sicherheit in der Informationstechnik + Copyright (C) 2020 Alibaba Group. + Copyright (C) 2020 Tianjia Zhang + + +Authors with a FSF copyright assignment +======================================= + +LIBGCRYPT Werner Koch 2001-06-07 +Assigns past and future changes. +Assignment for future changes terminated on 2012-12-04. +wk@gnupg.org +Designed and implemented Libgcrypt. + +GNUPG Matthew Skala 1998-08-10 +Disclaims changes. +mskala@ansuz.sooke.bc.ca +Wrote cipher/twofish.c. + +GNUPG Natural Resources Canada 1998-08-11 +Disclaims changes by Matthew Skala. + +GNUPG Michael Roth Germany 1998-09-17 +Assigns changes. +mroth@nessie.de +Wrote cipher/des.c. +Changes and bug fixes all over the place. + +GNUPG Niklas Hernaeus 1998-09-18 +Disclaims changes. +nh@df.lth.se +Weak key patches. + +GNUPG Rémi Guyomarch 1999-05-25 +Assigns past and future changes. (g10/compress.c, g10/encr-data.c, +g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c) +rguyom@mail.dotcom.fr + +ANY g10 Code GmbH 2001-06-07 +Assignment for future changes terminated on 2012-12-04. +Code marked with ChangeLog entries of g10 Code employees. + +LIBGCRYPT Timo Schulz 2001-08-31 +Assigns past and future changes. +twoaday@freakmail.de + +LIBGCRYPT Simon Josefsson 2002-10-25 +Assigns past and future changes to FSF (cipher/{md4,crc}.c, CTR mode, +CTS/MAC flags, self test improvements) +simon@josefsson.org + +LIBGCRYPT Moritz Schulte 2003-04-17 +Assigns past and future changes. +moritz@g10code.com + +GNUTLS Nikolaos Mavrogiannopoulos 2003-11-22 +nmav@gnutls.org +Original code for cipher/rfc2268.c. + +LIBGCRYPT The Written Word 2005-04-15 +Assigns past and future changes. (new: src/libgcrypt.pc.in, +src/Makefile.am, src/secmem.c, mpi/hppa1.1/mpih-mul3.S, +mpi/hppa1.1/udiv-qrnnd.S, mpi/hppa1.1/mpih-mul2.S, +mpi/hppa1.1/mpih-mul1.S, mpi/Makefile.am, tests/prime.c, +tests/register.c, tests/ac.c, tests/basic.c, tests/tsexp.c, +tests/keygen.c, tests/pubkey.c, configure.ac, acinclude.m4) + +LIBGCRYPT Brad Hards 2006-02-09 +Assigns Past and Future Changes +bradh@frogmouth.net +(Added OFB mode. Changed cipher/cipher.c, test/basic.c doc/gcrypt.tex. + added SHA-224, changed cipher/sha256.c, added HMAC tests.) + +LIBGCRYPT Hye-Shik Chang 2006-09-07 +Assigns Past and Future Changes +perky@freebsd.org +(SEED cipher) + +LIBGCRYPT Werner Dittmann 2009-05-20 +Assigns Past and Future Changes +werner.dittmann@t-online.de +(mpi/amd64, tests/mpitests.c) + +GNUPG David Shaw +Assigns past and future changes. +dshaw@jabberwocky.com +(cipher/camellia-glue.c and related stuff) + +LIBGCRYPT Andrey Jivsov 2010-12-09 +Assigns Past and Future Changes +openpgp@brainhub.org +(cipher/ecc.c and related files) + +LIBGCRYPT Ulrich Müller 2012-02-15 +Assigns Past and Future Changes +ulm@gentoo.org +(Changes to cipher/idea.c and related files) + +LIBGCRYPT Vladimir Serbinenko 2012-04-26 +Assigns Past and Future Changes +phcoder@gmail.com +(cipher/serpent.c) + + +Authors with a DCO +================== + +Andrei Scherer +2014-08-22:BF7CEF794F9.000003F0andsch@inbox.com: + +Christian Aistleitner +2013-02-26:20130226110144.GA12678@quelltextlich.at: + +Christian Grothoff +2013-03-21:514B5D8A.6040705@grothoff.org: + +Dmitry Baryshkov +Dmitry Eremin-Solenikov +2013-07-13:20130713144407.GA27334@fangorn.rup.mentorg.com: + +Dmitry Kasatkin +2012-12-14:50CAE2DB.80302@intel.com: + +H.J. Lu +2020-01-19:20200119135241.GA4970@gmail.com: + +Jia Zhang +2017-10-17:59E56E30.9060503@alibaba-inc.com: + +Jérémie Courrèges-Anglas +2016-05-26:87bn3ssqg0.fsf@ritchie.wxcvbn.org: + +Jussi Kivilinna +2012-11-15:20121115172331.150537dzb5i6jmy8@www.dalek.fi: + +Jussi Kivilinna +2013-05-06:5186720A.4090101@iki.fi: + +Markus Teich +2014-10-08:20141008180509.GA2770@trolle: + +Martin Storsjö +2018-03-28:dc1605ce-a47d-34c5-8851-d9569f9ea5d3@martin.st: + +Mathias L. Baumann +2017-01-30:07c06d79-0828-b564-d604-fd16c7c86ebe@sociomantic.com: + +Milan Broz +2014-01-13:52D44CC6.4050707@gmail.com: + +Paul Wolneykien +2019-11-19:20191119204459.312927aa@rigel.localdomain: + +Peter Wu +2015-07-22:20150722191325.GA8113@al: + +Rafaël Carré +2012-04-20:4F91988B.1080502@videolan.org: + +Sergey V. +2013-11-07:2066221.5IYa7Yq760@darkstar: + +Shawn Landden +2019-07-09:2794651562684255@iva4-64850291ca1c.qloud-c.yandex.net: + +Stephan Mueller +2014-08-22:2008899.25OeoelVVA@myon.chronox.de: + +Tianjia Zhang +2020-01-08:dcda0127-2f45-93a3-0736-27259a33bffa@linux.alibaba.com: + +Tomáš Mráz +2012-04-16:1334571250.5056.52.camel@vespa.frost.loc: + +Vitezslav Cizek +2015-11-05:20151105131424.GA32700@kolac.suse.cz: + +Werner Koch (g10 Code GmbH) +2012-12-05:87obi8u4h2.fsf@vigenere.g10code.de: + + +More credits +============ + +Libgcrypt used to be part of GnuPG but has been taken out into its own +package on 2000-12-21. + +Most of the stuff in mpi has been taken from an old GMP library +version by Torbjorn Granlund . + +The files cipher/rndunix.c and cipher/rndw32.c are based on those +files from Cryptlib. Copyright Peter Gutmann, Paul Kendall, and Chris +Wedgwood 1996-1999. + +The ECC code cipher/ecc.c was based on code by Sergi Blanch i Torne, +sergi at calcurco dot org. + +The implementation of the Camellia cipher has been been taken from the +original NTT provided GPL source. + +The CAVS testing program tests/cavs_driver.pl is not to be considered +a part of libgcrypt proper. We distribute it merely for convenience. +It has a permissive license and is copyrighted by atsec information +security corporation. See the file for details. + +The file salsa20.c is based on D.J. Bernstein's public domain code and +taken from Nettle. Copyright 2012 Simon Josefsson and Niels Möller. + + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/comm/third_party/libgcrypt/COPYING b/comm/third_party/libgcrypt/COPYING new file mode 100644 index 0000000000..d60c31a97a --- /dev/null +++ b/comm/third_party/libgcrypt/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/comm/third_party/libgcrypt/COPYING.LIB b/comm/third_party/libgcrypt/COPYING.LIB new file mode 100644 index 0000000000..cf9b6b9972 --- /dev/null +++ b/comm/third_party/libgcrypt/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. +^L + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/comm/third_party/libgcrypt/ChangeLog b/comm/third_party/libgcrypt/ChangeLog new file mode 100644 index 0000000000..72ea034caf --- /dev/null +++ b/comm/third_party/libgcrypt/ChangeLog @@ -0,0 +1,13947 @@ +2021-02-17 Werner Koch + + Release 1.9.2. + + commit 24bd7e8215f7982b0c8db46fd87b47b370a52ec6 + + +2021-02-12 NIIBE Yutaka + + random: Fix build for macOS. + + commit d78cdf42854b17e2216890e7b78f9e7e05c0b1f8 + * random/rndlinux.c [__APPLE__] (HAVE_GETENTROPY): Valid only when the + macro __MAC_10_11 is available. + +2021-02-08 Werner Koch + + tests: Fix minor glitches. + + commit 82395f11b444651f544f5e51c62fc6b65c04f9ef + * tests/basic.c (ALWAYS_INLINE): Make sure it is defined. + * tests/version.c (main): Print the config info to stdout. + + New test Makefile target xtestsuite. + + commit ebc4d5670a1ada54ad907a4836eb8f6f573c2c38 + * tests/Makefile.am (xtestsuite, xcheck): New targets. + + New test driver to allow for standalone regression tests. + + commit b142da4c88deef4798ef96061dac399df3ddd73d + * tests/testdrv.c: New. + +2021-02-03 Jussi Kivilinna + + sha256-avx2: fix reading beyond end of input buffer. + + commit 24af2a55d862d45fe3aef6b5626a52d9bb0fb17e + * cipher/sha256-avx2-bmi2-amd64.S + (_gcry_sha256_transform_amd64_avx2): Use 'last block' code path if + input length is only one block. + * tests/basic.c (check_one_md_final): Use dynamic allocated buffer + so that in future similar access errors get detected by + tests/basic + valgrind. + + ecc-ecdh: fix memory leak. + + commit 289543544e41cd5fe90352c5c7548ac09da533cc + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Free 'ec' at function exit. + + tests: allow running 'make check' with ASAN. + + commit f46a6bd9b3d7ef7d1a72c5b6da5cf34ace2ff156 + * tests/t-secmem.c (main): Skip test if environment variable + GCRYPT_IN_ASAN_TEST is defined. + * tests/t-sexp.c (main): Do not initialize secmem if environment + variable GCRYPT_IN_ASAN_TEST is defined. + + global: make sure that bulk config string is null-terminated. + + commit 8716e4b2ada21456802aee67c2bc8edfec78f820 + * src/global.c (_gcry_get_config): Append null-terminator to output + in the 'what == NULL' case. + + Add handling for -Og with O-flag munging. + + commit a71b7de32b0c7c41359335a488cfe4dd70c65121 + * cipher/Makefile.am (o_flag_munging): Add handling for '-Og'. + * random/Makefile.am (o_flag_munging): Add handling for '-Og'. + + jent: silence ubsan warning about signed overflow. + + commit 6fc11291282a668839040c72a1d558a6ebbd4972 + * random/jitterentropy-base.c (jent_stuck): Cast 'delta2' values to + 'uint64_t' for calculation. + + Fix ubsan warnings for i386 build. + + commit 364e9e9d10503b36f98fbb1b489e00026f22c9d7 + * mpi/mpicoder.c (_gcry_mpi_set_buffer) [BYTES_PER_MPI_LIMB == 4]: Cast + "*p--" values to mpi_limb_t before left shifting. + * tests/t-lock.c (main): Cast 'time(NULL)' to unsigned type. + + Fix building with --disable-asm on x86. + + commit af23ab5c5482d625ff52e60606cf044e2b0106c8 + * cipher/keccak.c (USE_64BIT_BMI2, USE_64BIT_SHLD) + (USE_32BIT_BMI2): Depend also on HAVE_CPU_ARCH_X86. + * random/rndjent.c [__i386__ || __x86_64__] (USE_JENT): Depend + also on HAVE_CPU_ARCH_X86. + + md: clear bctx.count at final function. + + commit cb95fc53003e9f34ff80fc33627ceda605de223c + * cipher/md4.c (md4_final): Set bctx.count zero after + finalizing. + * cipher/md5.c (md5_final): Ditto. + * cipher/rmd160.c (rmd160_final): Ditto. + * cipher/sha1.c (sha1_final): Ditto. + * cipher/sha256.c (sha256_final): Ditto. + * cipher/sha512.c (sha512_final): Ditto. + * cipher/sm3.c (sm3_final): Ditto. + * cipher/stribog.c (stribog_final): Ditto. + * cipher/tiger.c (tiger_final): Ditto. + +2021-02-02 NIIBE Yutaka + + ecc: Add checking key for ECDSA. + + commit 598d0f3e0294a487e01b88cc714a8cd0a47329bb + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_verify): Validate public key. + * cipher/ecc-gost.c (_gcry_ecc_gost_verify): Likewise. + * cipher/ecc-sm2.c (_gcry_ecc_sm2_verify): Likewise. + +2021-01-29 Werner Koch + + Release 1.9.1. + + commit 466299b1ceb82ec7c4dd0ca376de50399a896adf + * configure.ac: Bump LT version to C23/A3/R1. + +2021-01-29 Jussi Kivilinna + + hash-common: fix heap overflow when writing more data after final. + + commit 512c0c75276949f13b6373b5c04f7065af750b08 + * tests/basic.c (check_one_md): Test writing to digest after read. + * cipher/hash-common.c (_gcry_md_block_write): Reset 'hd->count' if + greater than blocksize. + +2021-01-28 Werner Koch + + Add a compliance keyword to gcry_get_config. + + commit aa3f595341eb263980210776c7fe377b2ed24c5e + * src/global.c (print_config): New config line. + +2021-01-27 Jussi Kivilinna + + asm-common-aarch64: add MacOS support for GET_DATA_POINTER. + + commit 014fed5153647641376b9131ea1d87dc5e88cf42 + * cipher/asm-common-aarch64.h [__APPLE__] (GET_DATA_POINTER): Add MacOS + variant of macro. + +2021-01-27 NIIBE Yutaka + + random: Use getentropy on macOS when available. + + commit 6cb0faf6ceec5b2e799e6fb5f04b85d135a7da9b + * random/rndlinux.c [__APPLE__ && __MACH__] (getentropy): Declare. + (_gcry_rndlinux_gather_random): Check the symbol and use getentropy. + + mpi: Fix _gcry_mpih_mod implementation. + + commit f06ff4e31c8e162f4a59986241c7ab43d5085927 + * mpi/mpih-const-time.c (_gcry_mpih_mod): Handle the overflow. + + build: Check spawn.h for MacOS X Tiger. + + commit fc901e978a0c18a3524cad5d1ef3451ed11b9347 + * configure.ac: Add check for spawn.h. + * tests/random.c: Only use posix_spawn if available. + +2021-01-26 Jussi Kivilinna + + global: fix compile error at pragma GCC diagnostic. + + commit 3d095206c30d772d5fc68bf69bfc384e43f766e9 + * src/global.c (_gcry_vcontrol): Move "pragma GCC diagnostics" outside + function. + + cipher-proto: remove forward typedef of cipher_bulk_ops_t. + + commit 17aad639d29c7c835a7effb89181c7c99b16cb6a + * cipher/cipher-proto (cipher_bulk_ops_t): Remove typedef, leave + forward declaration of 'struct cipher_bulk_ops'. + (gcry_cipher_setkey_t): Change 'bulk_ops' to + 'struct cipher_bulk_ops *'. + * cipher/arcfour.c: Include 'cipher-internal.h'. + * cipher/gost28147.c: Ditto. + * cipher/idea.c: Ditto. + * cipher/rfc2268.c: Ditto. + * cipher/salsa20.c: Ditto. + * cipher/seed.c: Ditto. + * cipher/mac-internal.h (CTX_MAGIC_NORMAL): Rename to... + (CTX_MAC_MAGIC_NORMAL): ... this. + (CTX_MAGIC_SECURE): Rename to... + (CTX_MAC_MAGIC_SECURE): ... this. + * cipher/mac-cmac.c (cmac_open): Use CTX_MAC_MAGIC_SECURE. + * cipher/mac-gmac.c (gmac_open): Ditto. + * cipher/mac-hmac.c (hmac_open): Ditto. + * cipher/mac-poly1305.c (poly1305mac_open): Ditto. + * cipher/mac.c (mac_open): Use CTX_MAC_MAGIC_SECURE and + CTX_MAC_MAGIC_NORMAL. + +2021-01-26 David Michael + + cipher/sha512: Fix non-NEON ARM assembly implementation. + + commit 1e72c50f864ae1c77ba80c191224b9ef1d22a2e2 + * cipher/sha512.c (do_transform_generic) + [USE_ARM_ASM]: Switch to the non-NEON assembly implementation. + +2021-01-26 Jussi Kivilinna + + blake2: fix RIP register access for AVX/AVX2 implementations. + + commit b2f78ae034b8d4aa3d4cc7bf85262317832f6e0a + * cipher/blake2b-amd64-avx2.S: Use rRIP instead of (RIP). + * cipher/blake2s-amd64-avx.S: Use rRIP instead of (RIP). + + sha512/sha256: remove assembler macros from AMD64 implementations. + + commit 9f49e806f9506533236fd44b17f17b85961b20f1 + * configure.ac (gcry_cv_gcc_platform_as_ok_for_intel_syntax): Remove + assembler macro check from Intel syntax assembly support check. + * cipher/sha256-avx-amd64.S: Replace assembler macros with C + preprocessor counterparts. + * cipher/sha256-avx2-bmi2-amd64.S: Ditto. + * cipher/sha256-ssse3-amd64.S: Ditto. + * cipher/sha512-avx-amd64.S: Ditto. + * cipher/sha512-avx2-bmi2-amd64.S: Ditto. + * cipher/sha512-ssse3-amd64.S: Ditto. + + configure.ac: run assembler checks through linker for better LTO support + + commit 393bd6c3d1aa2b2a1b05be0e2d7fb2514e6c5ad0 + * configure.ac (gcry_cv_gcc_arm_platform_as_ok) + (gcry_cv_gcc_aarch64_platform_as_ok) + (gcry_cv_gcc_inline_asm_ssse3, gcry_cv_gcc_inline_asm_pclmul) + (gcry_cv_gcc_inline_asm_shaext, gcry_cv_gcc_inline_asm_sse41) + (gcry_cv_gcc_inline_asm_avx, gcry_cv_gcc_inline_asm_avx2) + (gcry_cv_gcc_inline_asm_bmi2, gcry_cv_gcc_as_const_division_ok) + (gcry_cv_gcc_as_const_division_with_wadivide_ok) + (gcry_cv_gcc_amd64_platform_as_ok, gcry_cv_gcc_win64_platform_as_ok) + (gcry_cv_gcc_platform_as_ok_for_intel_syntax) + (gcry_cv_gcc_inline_asm_neon, gcry_cv_gcc_inline_asm_aarch32_crypto) + (gcry_cv_gcc_inline_asm_aarch64_neon) + (gcry_cv_gcc_inline_asm_aarch64_crypto) + (gcry_cv_gcc_inline_asm_ppc_altivec) + (gcry_cv_gcc_inline_asm_ppc_arch_3_00) + (gcry_cv_gcc_inline_asm_s390x, gcry_cv_gcc_inline_asm_s390x): Use + AC_LINK_IFELSE check instead of AC_COMPILE_IFELSE. + + rijndael: remove unused use_xxx flags. + + commit a14447f8169aff30a49f5c2ab06bd5bbd1cc3531 + * cipher/rijndael-internal.h (RIJNDAEL_context_s): Remove unused + 'use_padlock', 'use_aesni', 'use_ssse3', 'use_arm_ce', 'use_ppc_crypto' + and 'use_ppc9le_crypto'. + * cipher/rijndael.c (do_setkey): Do not setup 'use_padlock', + 'use_aesni', 'use_ssse3', 'use_arm_ce', 'use_ppc_crypto' and + 'use_ppc9le_crypto'. + + Define HW-feature flags per architecture. + + commit 8d404a629167d67ed56e45de3e65d1e0b7cdeb24 + * random/rand-internal.h (_gcry_rndhw_poll_slow): Add requested length + parameter. + * random/rndhw.c (_gcry_rndhw_poll_slow): Limit accounted bytes to 50% + (or 25% for RDRAND) - this code is moved from caller side. + * random/rndlinux.c (_gcry_rndlinux_gather_random): Move + HWF_INTEL_RDRAND check to _gcry_rndhw_poll_slow. + * src/g10lib.h (HWF_PADLOCK_*, HWF_INTEL_*): Define only if + HAVE_CPU_ARCH_X86. + (HWF_ARM_*): Define only if HAVE_CPU_ARCH_ARM. + (HWF_PPC_*): Define only if HAVE_CPU_ARCH_PPC. + (HWF_S390X_*): Define only if HAVE_CPU_ARCH_S390X. + + Add configure option to force enable 'soft' HW feature bits. + + commit 3b34bd6e178614d6021ee7d1140646f7c8ed7519 + * configure.ac (force_soft_hwfeatures) + (ENABLE_FORCE_SOFT_HWFEATURES): New. + * src/hwf-x86.c (detect_x86_gnuc): Enable HWF_INTEL_FAST_SHLD + and HWF_INTEL_FAST_VPGATHER if ENABLE_FORCE_SOFT_HWFEATURES enabled. + +2021-01-26 NIIBE Yutaka + + ecc: Fix Ed25519 private key handling for preceding ZEROs. + + commit 1b74f633bd3e358fb07a856a70597019980651d2 + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Fill-up or remove + preceding ZEROs correctly, fixing the third argument of mpi_set_opaque. + + ecc: Fix initialization of CTX for sign and verify. + + commit 652b102697cbfe2d7bc642fc7374cb21a9cf03e6 + * cipher/ecc.c (ecc_sign, ecc_verify): Call + _gcry_pk_util_init_encoding_ctx at first. + +2021-01-21 NIIBE Yutaka + + build: Fix build of tests with non-default installation. + + commit fa3420b011c105ca21894489e62c7e882a3ac4dd + * tests/Makefile.am: Add forgotten @LDADD_FOR_TESTS_KLUDGE@. + +2021-01-20 Jussi Kivilinna + + Split inline assembly blocks with many memory operands. + + commit 00df9f27181d77166ceb55f319329400bf2e6a48 + * cipher/rijndael-aesni.c (aesni_ocb_checksum, aesni_ocb_enc) + (aesni_ocb_dec, _gcry_aes_aesni_ocb_auth): Split assembly blocks + with more than 4 memory operands to smaller blocks. + * cipher/sha512-ssse3-i386.c (W2): Split big assembly block to + three smaller blocks. + + tests/basic: fix build on ARM32 when NEON disabled. + + commit 81354e911bfa3e135d3e07f6a8d9e98033cd921a + * tests/basic.c (CLUTTER_VECTOR_REGISTER_NEON) + (CLUTTER_VECTOR_REGISTER_AARCH64): Remove check for __ARM_FEATURE_SIMD32. + + kdf: make self-test test-vector array read-only. + + commit 097148bc89ec8c18b9e4795733e0f0b1ae0ecd1d + * cipher/kdf.c (selftest_pbkdf2): Make 'tv[]' constant. + + kdf: add missing null-terminator for self-test test-vector array. + + commit c6425a5537294dfe2beaafc9105f7af4ceac677f + * cipher/kdf.c (selftest_pbkdf2): Add null-terminator to TV array. + + cipher/bithelp: use __builtin_ctzl when available. + + commit 807827cda3bacf5f475167ee6d34657713111838 + * cipher/bithelp.h (_gcry_ctz64): Use __builtin_ctzl if available. + + mpi/longlong: make use of compiler provided __builtin_ctz/__builtin_clz. + + commit 477355047e5c75ad2b2238a8716e4646b861184c + * configure.ac (gcry_cv_have_builtin_ctzl, gcry_cv_have_builtin_clz) + (gcry_cv_have_builtin_clzl): New checks. + * mpi/longlong.h (count_leading_zeros, count_trailing_zeros): Use + __buildin_clz[l]/__builtin_ctz[l] if available and bit counting + macros not yet provided by inline assembly. + +2021-01-19 Werner Koch + + Release 1.9.0. + + commit 0dc49af9b5371c5e2f766b70c3bede2b10db9f7e + + +2021-01-19 NIIBE Yutaka + + Fix DSA for FIPS 186-3. + + commit 30ed9593f632c728d918598037358deaeccd1968 + * cipher/dsa.c (generate_fips186): Supply INITIAL_SEED to + _gcry_generate_fips186_3_prime. + * tests/fips186-dsa.c (check_dsa_gen_186_2): Add where tv comes from. + (check_dsa_gen_186_3): Implement tests. + * tests/pubkey.c (get_dsa_key_fips186_with_seed_new): Use the qbits + and seed of tests/fips186-dsa.c. + +2021-01-19 NIIBE Yutaka + Tomáš Mráz + + Check if FIPS is operational and error return if not. + + commit ebeae53222648c637907f4b358888fc0e7123dc9 + * src/visibility.c (gcry_kdf_derive): Add the check. + (gcry_prime_generate, gcry_prime_group_generator): Likewise. + (gcry_mpi_randomize): Likewise, but no return. + +2021-01-18 Werner Koch + + ecc: Change an error code of gcry_ecc_mul_point. + + commit ca5a90bf70598247589078478d237287ca524453 + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Return + GPG_ERR_UNKNOWN_CURVE. + +2021-01-15 NIIBE Yutaka + Tomáš Mráz + + kdf: Add selftest. + + commit 7a0da24925361a3109474d0e433511467a9e35d1 + * src/cipher-proto.h (_gcry_kdf_selftest): New. + * cipher/kdf.c (check_one, selftest_pbkdf2): New. + (_gcry_kdf_selftest): New. + * src/fips.c (run_kdf_selftests): New. + (_gcry_fips_run_selftests): Call run_kdf_selftests. + +2021-01-13 NIIBE Yutaka + Tomáš Mráz + + cmac: Add selftest. + + commit 385a89e35b0b95f15b4c6e4d5482b1fc6906f7c5 + * cipher/mac-cmac.c (check_one, selftests_cmac_3des): New. + (selftests_cmac_aes, cmac_selftest): New. + (cmac_ops): Add cmac_selftest. + * src/fips.c (run_mac_selftests): Add CMAC selftests. + +2021-01-13 NIIBE Yutaka + + sexp: Raise an error when an integer is negative with USG. + + commit 00d7c1c632019066a4884930d413ccc044d81af5 + * src/sexp.c (do_vsexp_sscan): Return GPG_ERR_INV_ARG if negative. + +2021-01-08 NIIBE Yutaka + + ecc: Add backward compatibility support for Ed25519 key in SEXP. + + commit 4768baf74be03d8973d004725f796aef329c45bf + * cipher/ecc-curves.c (_gcry_ecc_get_curve): Support Ed25519 keys with + parameter {p,a,b,g,n}. + + ecc: Minor implementation change for _gcry_ecc_get_curve. + + commit 3fe7036d05f283df9441d42242f0047b6ea11a32 + * cipher/ecc-curves.c (_gcry_ecc_get_curve): Flatten. + +2020-12-30 Jussi Kivilinna + + Add s390x/zSeries implementation of Poly1305. + + commit 1f75681cbba895ea2f7ea0637900721f4522e729 + * cipher/Makefile.am: Add 'poly1305-s390x.S' and + 'asm-poly1305-s390x.h'. + * cipher/asm-poly1305-s390x.h: New + * cipher/chacha20-s390x.S (_gcry_chacha20_poly1305_s390x_vx_blocks8) + (_gcry_chacha20_poly1305_s390x_vx_blocks4_2_1): New, stitched + chacha20-poly1305 implementation. + * cipher/chacha20.c (USE_S390X_VX_POLY1305): New. + (_gcry_chacha20_poly1305_s390x_vx_blocks8) + (_gcry_chacha20_poly1305_s390x_vx_blocks4_2_1): New prototypes. + (_gcry_chacha20_poly1305_encrypt, _gcry_chacha20_poly1305_decrypt): Add + s390x/VX stitched chacha20-poly1305 code-path. + * cipher/poly1305-s390x.S: New. + * cipher/poly1305.c (USE_S390X_ASM, HAVE_ASM_POLY1305_BLOCKS): New. + [USE_S390X_ASM] (_gcry_poly1305_s390x_blocks1, poly1305_blocks): New. + * configure.ac (gcry_cv_gcc_inline_asm_s390x): Check for 'risbgn' and + 'algrk' instructions. + * tests/basic.c (_check_poly1305_cipher): Add large chacha20-poly1305 + test vector. + + Add s390x/zSeries implementation of ChaCha20. + + commit 6a0bb9ab7f886087d7edb0725c90485086a1c0b4 + * cipher/Makefile.am: Add 'asm-common-s390x.h' and 'chacha20-s390x.S'. + * cipher/asm-common-s390x.h: New. + * cipher/chacha20-s390x.S: New. + * cipher/chacha20.c (USE_S390X_VX): New. + (CHACHA20_context_t): Change 'use_*' bit-field to unsigned type; Add + 'use_s390x'. + (_gcry_chacha20_s390x_vx_blocks8) + (_gcry_chacha20_s390x_vx_blocks4_2_1): New. + (chacha20_do_setkey): Add HW feature detect for s390x/VX. + (chacha20_blocks, do_chacha20_encrypt_stream_tail): Add s390x/VX + code-path. + * configure.ac: Add 'chacha20-s390x.lo'. + + hwf-s390x: add VX vector instruction set detection. + + commit 1d13794780e3d052cd5ed6f900bf5900cf44b377 + * configure.ac (gcry_cv_gcc_inline_asm_s390x_vx): New check. + * src/g10lib.h (HWF_S390X_VX): New. + * src/hwf-s390x.c (HWCAP_S390_VXRS): New. + (s390x_features) [HAVE_GCC_INLINE_ASM_S390X_VX]: Add VX feature check. + * src/hwfeatures.c (hwlist): Add "s390x-vx". + + mpi/longlong: add s390x/zSeries macros. + + commit 0252cc9b62dfe20c77211f093b4fda54786177d3 + * mpi/longlong.h [__s390x__] (add_ssaaaa, sub_ddmmss, UTItype) + (umul_ppmm, udiv_qrnnd): New. + +2020-12-22 Jussi Kivilinna + + hwf-arm: fix incorrect HWCAP2 for SHA1 and SHA2 on AArch32. + + commit 6b6bfd57d0a6b2b4577c084db35078cd9fadafa5 + * src/hwf-arm.c (HWCAP2_SHA1, HWCAP2_SHA2): Change from bit indexes to + flags. + + Add missing prototype for _gcry_mac_selftest. + + commit e47f04b4a28947c90db70ccaf93e149cfd5213c9 + * src/cipher-proto.h (_gcry_hmac_selftest): Rename to... + (_gcry_mac_selftest): ... this. + +2020-12-21 NIIBE Yutaka + + Merge hmac-tests.c into mac-hmac.c. + + commit 2ab14b23afc092fd25395954c2a94db932ca4d95 + * cipher/Makefile.am (EXTRA_DIST): Remove hmac-tests.c. + * cipher/hmac-tests.c: Remove, merge into... + * cipher/mac-hmac.c: ... here. + +2020-12-18 Jussi Kivilinna + + Add s390x/zSeries acceleration for SHA3. + + commit 7532e27cacb74c92fd561524a0897163b0fcd7f4 + * cipher/asm-inline-s390x.h (KLMD_PADDING_STATE): New. + (kimd_execute): Change 'reg0' from read-only to read/write. + (klmd_shake_execute): New. + * cipher/keccak.c (USE_S390X_CRYPTO): New. + (KECCAK_CONTEXT) [USE_S390X_CRYPTO]: New members. + [USE_S390X_CRYPTO] (keccak_bwrite_s390x, keccak_final_s390x) + (keccak_bextract_s390x, keccak_write_s390x, keccak_extract_s390x): New. + (keccak_write) [USE_S390X_CRYPTO]: Use accelerated function if enabled. + (keccak_final) [USE_S390X_CRYPTO]: Likewise. + (keccak_extract) [USE_S390X_CRYPTO]: Likewise. + (keccak_init) [USE_S390X_CRYPTO]: Detect and setup zSeries + acceleration. + + Add s390x/zSeries acceleration for SHA512. + + commit 45f0ec0c4e3b08627cbf7e65f5f110c321710d01 + * cipher/sha512.c (USE_S390X_CRYPTO): New. + (SHA512_CONTEXT) [USE_S390X_CRYPTO]: New members. + (do_sha512_transform_s390x, do_sha512_final_s390x): New. + (sha512_init_common) [USE_S390X_CRYPTO]: Detect and setup s390x/zSeries + acceleration. + (sha512_final) [USE_S390X_CRYPTO]: Use accelerated final function. + + Add s390x/zSeries acceleration for SHA256. + + commit 0b555c3cc7c2b80ec2628685946a6139a1996911 + * cipher/sha256.c (USE_S390X_CRYPTO): New. + (SHA256_CONTEXT) [USE_S390X_CRYPTO]: New members. + (do_sha256_transform_s390x, do_sha256_final_s390x): New. + (sha256_common_init) [USE_S390X_CRYPTO]: Detect and setup s390x/zSeries + acceleration. + (sha256_final) [USE_S390X_CRYPTO]: Use accelerated final function. + + Add s390x/zSeries acceleration for SHA1. + + commit 88570515b4ca92a44c4e40c31f877c11cc00ab68 + * cipher/asm-inline-s390x.h (ALWAYS_INLINE): New. + (klmd_query): New. + (km_function_to_mask, kimd_execute, klmd_execute): Mark as always + inline. + * cipher/rijndael-s390x.c (ALWAYS_INLINE): Remove. + * cipher/sha1.c (do_sha1_transform_s390x, do_sha1_final_s390x): New. + (sha1_init) [SHA1_USE_S390X_CRYPTO]: Detect and setup s390x/zSeries + acceleration. + (sha1_final) [SHA1_USE_S390X_CRYPTO]: Use accelerated final function. + * cipher/sha1.h (SHA1_USE_S390X_CRYPTO): New. + (SHA1_CONTEXT) [SHA1_USE_S390X_CRYPTO]: New. + + Add bulk AES-GCM acceleration for s390x/zSeries. + + commit 5aeb091f911398217b2e9facb9bdeb05c63d7844 + * cipher/Makefile.am: Add 'asm-inline-s390x.h'. + * cipher/asm-inline-s390x.h: New. + * cipher/cipher-gcm.c [GCM_USE_S390X_CRYPTO] (ghash_s390x_kimd): New. + (setupM) [GCM_USE_S390X_CRYPTO]: Add setup for s390x GHASH function. + * cipher/cipher-internal.h (GCM_USE_S390X_CRYPTO): New. + * cipher/rijndael-s390x.c (u128_t, km_functions_e): Move to + 'asm-inline-s390x.h'. + (aes_s390x_gcm_crypt): New. + (_gcry_aes_s390x_setup_acceleration): Use 'km_function_to_mask'; Add + setup for GCM bulk function. + + Add bulk function interface for GCM mode. + + commit f4e63e92dc0b79633f48b11d292dd7bdf2752ede + * cipher/cipher-gcm.c (do_ghash_buf): Proper handling for the case + where 'unused' gets filled to full blocksize. + (gcm_crypt_inner): New. + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt): Use + 'gcm_crypt_inner'. + * cipher/cipher-internal.h (cipher_bulk_ops_t): Add 'gcm_crypt'. + + Add s390x/zSeries acceleration for AES. + + commit 9219d9d1b60c01a4c7dbde05ee6b5b52e0d7d072 + * configure.ac: Add 'rijndael-s390x.lo'. + * cipher/Makefile.am: Add 'rijndael-s390x.c'. + * cipher/rijndael-internal.c (USE_S390X_CRYPTO): New. + (RIJNDAEL_context_s) [USE_S390X_CRYPTO]: New 'km*_func' members. + * cipher/rijndael-s390x.c: New. + * cipher/rijndael.c (_gcry_aes_s390x_setup_acceleration) + (_gcry_aes_s390x_setup_setkey) + (_gcry_aes_s390x_setup_prepare_decryption, _gcry_aes_s390x_encrypt) + (_gcry_aes_s390x_decrypt): New. + (do_setkey) [USE_S390X_CRYPTO]: Add s390x acceleration setup. + + Add bulk function interface for OFB mode. + + commit f12b6788f2297391265af93a7794bfbc503de6d7 + * cipher/cipher-internal.h (cipher_bulk_ops): Add 'ofb_enc'. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_encrypt): Use bulk encryption + function if defined. + * cipher/basic.c (check_bulk_cipher_modes): Add OFB-AES test vectors. + + hwf: add detection of s390x/zSeries hardware features. + + commit 128054767d5f864798a39d432997f7d38c4bf729 + * configure.ac (gcry_cv_gcc_inline_asm_s390x) + (HAVE_CPU_ARCH_S390X): Add s390x detection support. + * mpi/config.links: Add setup for s390x links. + * src/Makefile.am: Add 'hwf-s390x.c'. + * src/g10lib.h (HWF_S390X_MSA, HWF_S390X_MSA_4, HWF_S390X_8): New. + * src/hwf_common.h (_gcry_hwf_detect_s390x): New. + * src/hwf-s390x.c: New. + * src/hwfeatures.c: Add "s390x-msa", "s390x-msa-4" and "s390x-msa-8". + + tests/bench-slope: use same benchmarking for XTS as for other modes. + + commit 0e37bb32e215feb4716341f7053c4f54806645cb + * tests/bench-slope.c (bench_xts_encrypt_init): Use same buffer + sizes as other tests. + (bench_xts_encrypt_do_bench, bench_xts_decrypt_do_bench): Remove. + (xts_encrypt_ops): Use 'bench_encrypt_do_bench'. + (xts_decrypt_ops): Use 'bench_decrypt_do_bench'. + + aarch64: mpi/longlong.h: fix operand size mismatch. + + commit c59b5b03a063ebc73935dbb10bc4f568faddbedf + * mpi/longlong.h [__aarch64__] (count_leading_zeros): Use correctly + sized temporary variable for asm output. + + aarch64: use configure check for assembly ELF directives support. + + commit 8352b0ece5237e3f86f1525b072e8f690ad0fa94 + * configure.ac (gcry_cv_gcc_asm_elf_directives): New check. + (HAVE_GCC_ASM_ELF_DIRECTIVES): New 'config.h' macro. + * cipher/asm-common-aarch64.h (ELF): Change feature macro check from + __ELF__ to HAVE_GCC_ASM_ELF_DIRECTIVES. + +2020-12-18 NIIBE Yutaka + + Reorganize self-tests for HMAC. + + commit c90fb0d8fb7a84bbcc8d6832de6a554405591850 + * cipher/Makefile.am: Prepare merge of hmac-test.c into mac-hmac.c. + * cipher/hmac-tests.c: Ifdef-out run_selftests and _gcry_hmac_selftest. + * cipher/mac-internal.h: Include cipher-proto.h for selftest. + (gcry_mac_spec_ops): Add selftest field. + * cipher/mac-hmac.c: Include hmac-tests.c for migration. + (hmac_selftest) New. + (hmac_ops): Add hmac_selftest. + * cipher/gost28147.c, cipher/mac-cmac.c: Add new field for selftest. + * cipher/mac-gmac.c, cipher/mac-poly1305.c: Likewise.. + * cipher/mac.c (_gcry_mac_selftest): New. + * src/fips.c (run_mac_selftests): Rename from run_hmac_selftests. + Use GCRY_MAC_HMAC_*, and call _gcry_mac_selftest. + (_gcry_fips_run_selftests): Use run_mac_selftests. + +2020-12-03 Jussi Kivilinna + + Prevent link-time optimization from inlining __gcry_burn_stack. + + commit 1a83df98b198902ee6d71549231a3af37088d452 + * src/g10lib.h (NOINLINE_FUNC): New attribute macro. + * src/misc.c (__gcry_burn_stack): Add NOINLINE_FUNC attribute. + + tests/basic: check 32-bit and 64-bit overflow for CTR and ChaCha20. + + commit 2065720b5b0642cc1a0e08086a434244ebb1abf2 + * tests/basic.c (check_one_cipher_ctr_reset) + (check_one_cipher_ctr_overflow): New. + (check_one_cipher): Add counter overflow tests for ChaCha20 and CTR + mode. + + chacha20-ppc: fix 32-bit counter overflow handling. + + commit ed45eac3b721c1313902b977379fbd4886ccca7b + * cipher/chacha20-ppc.c (vec_add_ctr_u64, ADD_U64): New. + (_gcry_chacha20_ppc8_blocks1, _gcry_chacha20_ppc8_blocks4) + (_gcry_chacha20_poly1305_ppc8_blocks4): Use ADD_U64 when incrementing + counter. + +2020-12-03 NIIBE Yutaka + + tests: Put a work around to tests/random for macOS. + + commit 9769b40b54cf010a0c41c4ab05a7a88e17d70613 + * configure.ac [*-apple-darwin*] (USE_POSIX_SPAWN_FOR_TESTS): New. + * tests/random.c [USE_POSIX_SPAWN_FOR_TESTS] (run_all_rng_tests): New. + +2020-11-18 NIIBE Yutaka + + build: Update to newer autoconf constructs. + + commit 9485ca7b5bf11194cff59edbfa6a0fba3bf6162a + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Use AS_MESSAGE_LOG_FD + instead of AC_FD_CC. + (GNUPG_CHECK_MLOCK): Use AC_LINK_IFELSE instead of AC_TRY_LINK. + Use AC_RUN_IFELSE instead of AC_TRY_RUN. + * configure.ac (AC_ISC_POSIX): Replace by AC_SEARCH_LIBS. + Use AC_USE_SYSTEM_EXTENSIONS instead of AC_GNU_SOURCE. + Use AS_HELP_STRING instead of AC_HELP_STRING. + (AC_TYPE_SIGNAL): Remove. + (AC_DECL_SYS_SIGLIST): Remove. + * m4/Makefile.am (EXTRA_DIST): Update. + * m4/onceonly.m4: Remove. + * m4/socklen.m4: Update from gnulib. + * m4/libtool.m4: Update from libgpg-error. + * m4/gpg-error.m4: Update from libgpg-error. + * m4/noexecstack.m4: Use AS_HELP_STRING instead of AC_HELP_STRING. + + build: Use modern Autoconf check for type. + + commit 425bf499185d78aa8fcad6a30b8771e7865d449d + * configure.ac (byte, ushort, us6, u32, u64): Use AC_CHECK_TYPES. + * cipher/poly1305.c: Use HAVE_TYPE_U64. + * src/hmac256.c: HAVE_TYPE_U32. + * src/types.h: Use HAVE_TYPE_BYTE, HAVE_TYPE_USHORT, HAVE_TYPE_U16, + HAVE_TYPE_U32, and HAVE_TYPE_U64. + + m4: Update with newer autoconf constructs. + + commit 908e347fb68b28e180ac816b5050406358e81a0f + * src/libgcrypt.m4: Replace AC_HELP_STRING to AS_HELP_STRING. + +2020-10-30 NIIBE Yutaka + + ecc: Handle removed zeros at the beginning for Ed25519. + + commit 361a0588489cf4a539da8debd1771024a1faa218 + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Accept private + key with removed zeros. + +2020-10-23 Werner Koch + + random: Allow for a Unicode random seed file on Windows. + + commit 24341f58f0d38bd62c45d285bcf8472f82b56135 + * random/random-csprng.c (utf8_to_wchar) [W32]: New. + (any8bitchar) [W32]: New. + (my_open): New. Replace all calls to open with this. + +2020-10-01 Tianjia Zhang + + tests: Fix typo in comment. + + commit 4a50c6b88d6d8d843e50add851a8a5e691349097 + * tests/basic.c: Fix typo in comment. + +2020-09-27 Jussi Kivilinna + + rijndael: clean-up prepare_decryption function. + + commit 2051d5bd6f732a36e5a536cba734531a9e2e915f + * cipher/rijndael-internal.h (rijndael_prepare_decfn_t): New. + (RIJNDAEL_context_s): New member 'prepare_decryption'. + * cipher/rijndael-padlock.c (_gcry_aes_padlock_prepare_decryption): New. + * cipher/rijndael.c (_gcry_aes_padlock_prepare_decryption): New. + (do_setkey): Setup 'ctx->prepare_decryption' for each acceleration type. + (prepare_decryption): Remove calls to other prepare decryption functions. + (check_decryption_preparation): Call 'ctx->prepare_decryption' instead + of 'prepare_decryption'. + + rijndael: clean-up generic bulk functions. + + commit 7679c918ade9d334bc80cb8c10916bbc847ff382 + * cipher/rijndael.c (_gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (_gcry_aes_ctr_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_dec) + (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth, _gcry_aes_xts_crypt): Remove + calls to hardware accelerated AES bulk functions. + + cipher: setup bulk functions at each algorithms key setup. + + commit 51271eb86bcb0eb89e55a2add9607c503f182c89 + * cipher/cipher-internal.h (cipher_mode_ops_t, cipher_bulk_ops_t): New. + (gcry_cipher_handle): Define members 'mode_ops' and 'bulk' using new + types. + * cipher/cipher.c (_gcry_cipher_open_internal): Remove bulk function + setup. + (cipher_setkey): Pass context bulk function pointer to algorithm setkey + function. + * cipher/cipher-selftest.c (_gcry_selftest_helper_cbc) + (_gcry_selftest_helper_cfb, _gcry_selftest_helper_ctr): Remove bulk + function parameter; Use bulk function returned by setkey function. + * cipher/cipher-selftest.h (_gcry_selftest_helper_cbc) + (_gcry_selftest_helper_cfb, _gcry_selftest_helper_ctr): Remove bulk + function parameter. + * cipher/arcfour.c (arcfour_setkey): Change 'hd' parameter to + 'bulk_ops'. + * cipher/blowfish.c (bf_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (_gcry_blowfish_ctr_enc, _gcry_blowfish_cbc_dec) + (_gcry_blowfish_cfb_dec): Make static. + (selftest_ctr, selftest_cbc, selftest_cfb): Do not pass bulk function + to selftest helper. + (selftest): Pass 'bulk_ops' to setkey function. + * cipher/camellia.c (camellia_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (_gcry_camellia_ctr_enc, _gcry_camellia_cbc_dec) + (_gcry_camellia_cfb_dec, _gcry_camellia_ocb_crypt) + (_gcry_camellia_ocb_auth): Make static. + (selftest_ctr, selftest_cbc, selftest_cfb): Do not pass bulk function + to selftest helper. + (selftest): Pass 'bulk_ops' to setkey function. + * cipher/cast5.c (cast_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (_gcry_cast5_ctr_enc, _gcry_cast5_cbc_dec, _gcry_cast5_cfb_dec): Make + static. + (selftest_ctr, selftest_cbc, selftest_cfb): Do not pass bulk function + to selftest helper. + (selftest): Pass 'bulk_ops' to setkey function. + * cipher/chacha20.c (chacha20_setkey): Change 'hd' parameter to + 'bulk_ops'. + * cipher/cast5.c (do_tripledes_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (_gcry_3des_ctr_enc, _gcry_3des_cbc_dec, _gcry_3des_cfb_dec): Make + static. + (bulk_selftest_setkey): Change 'hd' parameter to 'bulk_ops'. + (selftest_ctr, selftest_cbc, selftest_cfb): Do not pass bulk function + to selftest helper. + (do_des_setkey): Change 'hd' parameter to 'bulk_ops'. + * cipher/gost28147.c (gost_setkey): Change 'hd' parameter to + 'bulk_ops'. + * cipher/idea.c (idea_setkey): Change 'hd' parameter to 'bulk_ops'. + * cipher/rfc2268.c (do_setkey): Change 'hd' parameter to 'bulk_ops'. + * cipher/rijndael.c (do_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (rijndael_setkey): Change 'hd' parameter to 'bulk_ops'. + (_gcry_aes_cfb_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_enc) + (_gcry_aes_cbc_dec, _gcry_aes_ctr_enc, _gcry_aes_ocb_crypt) + (_gcry_aes_ocb_auth, _gcry_aes_xts_crypt): Make static. + (selftest_basic_128, selftest_basic_192, selftest_basic_256): Pass + 'bulk_ops' to setkey function. + (selftest_ctr, selftest_cbc, selftest_cfb): Do not pass bulk function + to selftest helper. + * cipher/salsa20.c (salsa20_setkey): Change 'hd' parameter to + 'bulk_ops'. + * cipher/seed.c (seed_setkey): Change 'hd' parameter to 'bulk_ops'. + * cipher/serpent.c (serpent_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (_gcry_serpent_ctr_enc, _gcry_serpent_cbc_dec, _gcry_serpent_cfb_dec) + (_gcry_serpent_ocb_crypt, _gcry_serpent_ocb_auth): Make static. + (selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): Do not pass + bulk function to selftest helper. + * cipher/sm4.c (sm4_setkey): Change 'hd' parameter to 'bulk_ops'; Setup + 'bulk_ops' with bulk acceleration functions. + (_gcry_sm4_ctr_enc, _gcry_sm4_cbc_dec, _gcry_sm4_cfb_dec) + (_gcry_sm4_ocb_crypt, _gcry_sm4_ocb_auth): Make static. + (selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): Do not pass + bulk function to selftest helper. + * cipher/twofish.c (twofish_setkey): Change 'hd' parameter to + 'bulk_ops'; Setup 'bulk_ops' with bulk acceleration functions. + (_gcry_twofish_ctr_enc, _gcry_twofish_cbc_dec) + (_gcry_twofish_cfb_dec, _gcry_twofish_ocb_crypt) + (_gcry_twofish_ocb_auth): Make static. + (selftest_ctr, selftest_cbc, selftest_cfb): Do not pass bulk function + to selftest helper. + (selftest, main): Pass 'bulk_ops' to setkey function. + * src/cipher-proto.h: Forward declare 'cipher_bulk_ops_t'. + (gcry_cipher_setkey_t): Replace 'hd' with 'bulk_ops'. + * src/cipher.h: Remove bulk acceleration function prototypes for + 'aes', 'blowfish', 'cast5', 'camellia', '3des', 'serpent', 'sm4' and + 'twofish'. + +2020-09-21 Jussi Kivilinna + + rijndael: tidy do_setkey little bit. + + commit e0829ae648d9d9da67cd8a8fae7aa05774a0d0f7 + * cipher/rijndael.c (do_setkey): Reduce number of ifdefs by using + function pointer for accelerated key-setup. + +2020-09-18 Jussi Kivilinna + + rijndael-aesni: tweak x86_64 AES-NI for better performance on AMD Zen2. + + commit f96989f0e9085fa58b475131d29b37f68ba564ec + * cipher/rijndael-aesni.c (do_aesni_enc_vec8, do_aesni_dec_vec8): Move + first round key xoring and last round out to caller. + (do_aesni_ctr_4): Change low 8-bit counter overflow check to 8-bit + addition to low-bits and detect overflow from carry flag; Adjust + slow path to restore counter. + (do_aesni_ctr_8): Same as above; Interleave first round key xoring and + first round with CTR generation on fast path; Interleave last round + with output xoring. + (_gcry_aes_aesni_cfb_dec, _gcry_aes_aesni_cbc_dec): Add first round + key xoring; Change order of last round xoring and output xoring + (shorten the dependency path). + (_gcry_aes_aesni_ocb_auth): Add first round key xoring and last round + handling. + +2020-08-26 Werner Koch + + build: Allow customization of the signing key. + + commit 9cd92ebae21900e54cc3d8b607c8ed1afbf2eb9b + * Makefile.am (sign-release): Read variabales from user configuration. + +2020-08-21 NIIBE Yutaka + + tests: Fix basic.c. + + commit fd51bc523d095168ee9367fe3f18d18f7a88ad90 + * tests/basic.c (check_one_hmac): Fix error paths. + (check_pubkey_crypt): Fix wrong call of gcry_sexp_new. + + ecc: Fix an error path. + + commit 65a2cd139e21250e6581a4f610015937e7b91451 + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Avoid null dereference on + error. + +2020-07-23 Jussi Kivilinna + + chacha20-aarch64: improve performance through higher SIMD interleaving. + + commit 8d7b1d0a52bde173646e5b42b31d23593eabecf2 + * cipher/chacha20-aarch64.S (ROTATE2, ROTATE2_8, ROTATE2_16) + (QUARTERROUND2): Replace with... + (ROTATE4, ROTATE4_8, ROTATE4_16, QUARTERROUND4): ...these. + (_gcry_chacha20_aarch64_blocks4) + (_gcry_chacha20_poly1305_aarch64_blocks4): Adjust to use QUARTERROUND4. + + tests/bench-slope: improve CPU frequency auto-detection. + + commit f1c3db3bf40e07cfd1a6a92209865ee7a98129ca + * configure.ac (gcry_cv_have_asm_volatile_memory): Check also if + assembly memory barrier with input/output register is supported. + * tests/bench-slope.c (auto_ghz_bench): Change to use base operation + that takes two CPU cycles and unroll loop by 1024 operations. + + Enable jitter entropy also on non-x86 architectures. + + commit 886120f33bd3f10e6e6a09920eca1f9ed81044e7 + * configure.ac: Do not force jentsupport to "n/a" on non-x86 + architectures. + + random/jitterentropy: fix USE_JENT == JENT_USES_GETTIME code path. + + commit 4ed9b949485448816a70d86260d572f08ae34621 + * random/jitterentropy-base-user.h (jent_get_nstime): Use 'tv' variable + instead of non-existing 'time'. + + Camellia AES-NI/AVX/AVX2 size optimization. + + commit 4c0e244fc53e0f7b927bfe4cf54695b5d282fd27 + * cipher/camellia-aesni-avx-amd64.S: Use loop for handling repeating + '(enc|dec)_rounds16/fls16' portions of encryption/decryption. + * cipher/camellia-aesni-avx2-amd64.S: Use loop for handling repeating + '(enc|dec)_rounds32/fls32' portions of encryption/decryption. + +2020-07-14 NIIBE Yutaka + + ecc: Support reading EC point in compressed format for good curves. + + commit e0dabf74bf276500257f15b85ded9cf24ccc8334 + * cipher/ecc-curves.c (gcry_ecc_get_curve): Handle G, differently. + * cipher/ecc-misc.c (_gcry_ecc_sec_decodepoint): Support compressed + representation of EC point. Rename from _gcry_ecc_os2ec. + * cipher/ecc-sm2.c (_gcry_ecc_sm2_decrypt) Follow the change. + * cipher/ecc.c (ecc_decrypt_raw): Likewise. + * mpi/ec.c (_gcry_mpi_ec_set_point): Likewise. + * src/ec-context.h: API change _gcry_ecc_sec_decodepoint from + _gcry_ecc_os2ec. + * tests/basic.c (check_pubkey): Use compressed representation + for two public keys of NIST P192 and NIST P256. + +2020-07-06 Werner Koch + + mpi: Consider +0 and -0 the same in mpi_cmp. + + commit 1f3a92e103d4a8e019d8d022647a2b9fb2681327 + * mpi/mpi-cmp.c (do_mpi_cmp): Check size of U an V. + +2020-06-23 NIIBE Yutaka + + ecc: Fix length computation. + + commit 1db1dc7945b111b6e20a8420ad38a358316681ab + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Add one only for + Edwards case. + +2020-06-20 Jussi Kivilinna + + Add SM4 x86-64/AES-NI/AVX2 implementation. + + commit 35a78eb248d6bacd2a58477a122a0020d796ce63 + * cipher/Makefile.am: Add 'sm4-aesni-avx2-amd64.S'. + * cipher/sm4-aesni-avx2-amd64.S: New. + * cipher/sm4.c (USE_AESNI_AVX2): New. + (SM4_context) [USE_AESNI_AVX2]: Add 'use_aesni_avx2'. + [USE_AESNI_AVX2] (_gcry_sm4_aesni_avx2_ctr_enc) + (_gcry_sm4_aesni_avx2_cbc_dec, _gcry_sm4_aesni_avx2_cfb_dec) + (_gcry_sm4_aesni_avx2_ocb_enc, _gcry_sm4_aesni_avx2_ocb_dec) + (_gcry_sm4_aesni_avx_ocb_auth): New. + (sm4_setkey): Enable AES-NI/AVX2 if supported by HW. + (_gcry_sm4_ctr_enc, _gcry_sm4_cbc_dec, _gcry_sm4_cfb_dec) + (_gcry_sm4_ocb_crypt, _gcry_sm4_ocb_auth) [USE_AESNI_AVX2]: Add + AES-NI/AVX2 bulk functions. + * configure.ac: Add ''sm4-aesni-avx2-amd64.lo'. + + Add SM4 x86-64/AES-NI/AVX implementation. + + commit c9a3f1bb91e63033e3bf3e06bdd6075622626d0d + * cipher/Makefile.am: Add 'sm4-aesni-avx-amd64.S'. + * cipher/sm4-aesni-avx-amd64.S: New. + * cipher/sm4.c (USE_AESNI_AVX, ASM_FUNC_ABI): New. + (SM4_context) [USE_AESNI_AVX]: Add 'use_aesni_avx'. + [USE_AESNI_AVX] (_gcry_sm4_aesni_avx_expand_key) + (_gcry_sm4_aesni_avx_crypt_blk1_8, _gcry_sm4_aesni_avx_ctr_enc) + (_gcry_sm4_aesni_avx_cbc_dec, _gcry_sm4_aesni_avx_cfb_dec) + (_gcry_sm4_aesni_avx_ocb_enc, _gcry_sm4_aesni_avx_ocb_dec) + (_gcry_sm4_aesni_avx_ocb_auth, sm4_aesni_avx_crypt_blk1_8): New. + (sm4_expand_key) [USE_AESNI_AVX]: Use AES-NI/AVX key setup. + (sm4_setkey): Enable AES-NI/AVX if supported by HW. + (_gcry_sm4_ctr_enc, _gcry_sm4_cbc_dec, _gcry_sm4_cfb_dec) + (_gcry_sm4_ocb_crypt, _gcry_sm4_ocb_auth) [USE_AESNI_AVX]: Add + AES-NI/AVX bulk functions. + * configure.ac: Add ''sm4-aesni-avx-amd64.lo'. + + Optimizations for SM4 cipher. + + commit 81fee26bbbae820a311a3ce3ac55e304655c2acd + * cipher/cipher.c (_gcry_cipher_open_internal): Add SM4 bulk + functions. + * cipher/sm4.c (ATTR_ALIGNED_64): New. + (sbox): Convert to ... + (sbox_table): ... this structure for sbox hardening as is done + for AES and GCM. + (prefetch_sbox_table): New. + (sm4_t_non_lin_sub): Make inline; Optimize sbox access pattern. + (sm4_key_lin_sub): Make inline; Tune slightly. + (sm4_key_sub, sm4_enc_sub): Make inline. + (sm4_round): Make inline; Take 'x' as separate parameters instead + of array. + (sm4_expand_key): Return void; Drop keylen; Unroll loops by 4; + Wipe sensitive variables at end; Move key-length check to + 'sm4_setkey'. + (sm4_setkey): Add initial self-test step; Add key-length check; + Remove burn stack (as variables wiped in 'sm4_expand_key'). + (sm4_do_crypt): Return burn stack depth; Unroll loops by 4. + (sm4_encrypt, sm4_decrypt): Prefetch sbox table; Return burn + stack from 'sm4_do_crypt', as allows tail-call optimization + by compiler. + (sm4_do_crypt_blks2): New two parallel block function for greater + instruction level parallelism. + (sm4_crypt_blocks, _gcry_sm4_ctr_enc, _gcry_sm4_cbc_dec) + (_gcry_sm4_cfb_dec, _gcry_sm4_ocb_crypt, _gcry_sm4_ocb_auth): New + bulk processing functions. + (selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): New + bulk processing self-tests. + (sm4_selftest): Clear SM4 context before use; Use 'sm4_expand_key' + instead of 'sm4_setkey'; Call bulk processing self-tests. + * src/cipher.h (_gcry_sm4_ctr_enc, _gcry_sm4_ctr_dec) + (_gcry_sm4_cfb_dec, _gcry_sm4_ocb_crypt, _gcry_sm4_ocb_auth): New. + * tests/basic.c (check_ocb_cipher): Add SM4-OCB test vector. + +2020-06-18 NIIBE Yutaka + + ecc: For Ed448, it's only for EdDSA. + + commit a6177e1bc948a7af052d62bcd62aa6b5825bfaff + * cipher/ecc.c (ecc_sign): Ed448 is only for EdDSA. + Hash algo is determined by the curve. + (ecc_verify): Likewise. + * tests/t-ed448.c (one_test): Don't specify (flags eddsa). + Don't specify hash-algo. + + ecc: Fix the condition for EdDSA data handling. + + commit f2847d56cce2afdd993f797812a673495a41c234 + * cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): It may be + the encoding context which determines EdDSA. Hash-algo can be + omitted. Flags are OR-ed. + + ecc: Support EdDSA with context and enabling PH(M). + + commit ba78ad8f19674b94edfdf4998f40feee081481bc + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_compute_h_d): Simplify. + (DOM4_0_NONE, DOM4_0_NONE_LEN): Remove. + (DOM25519, DOM25519_LEN): New. + (DOM448, DOM448_LEN): New. + (_gcry_ecc_eddsa_sign): Support EdDSA with context and PH. + (_gcry_ecc_eddsa_verify): Likewise. + * tests/t-ed448.c: Add tests with context and PH=1. + * tests/t-ed448.inp: Add test data. + + ecc: Change EdDSA internal API. + + commit 2856ac14ae3e4c9e6288e1f0d8bc1945bb874081 + * cipher/ecc-common.h (_gcry_ecc_eddsa_sign): Last arg is CTX. + (_gcry_ecc_eddsa_verify): Ditto. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_sign): Get hash algo from CTX. + (_gcry_ecc_eddsa_verify): Ditto. + * cipher/ecc.c (ecc_sign, ecc_verify): Follow the change. + +2020-06-17 NIIBE Yutaka + + ecc: Support "label" for EdDSA context in data. + + commit 1cf49754694611620fd383327cf127e91f6883df + * cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Handle ctx->label. + + ecc: Initialize key before handling data. + + commit d51a9c259d49c63121fab48bce48d826e9b57733 + * cipher/ecc.c (ecc_sign): Initialize key at first. + (ecc_verify): Likewise. + + ecc: Add new flag "prehash". + + commit 9a640eba6dd7504c90a65151cdaf1e4093a8b475 + * src/cipher.h (PUBKEY_FLAG_PREHASH): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Parse it. + + ecc: No (flags eddsa) required for Ed448. + + commit b1721f9b291a4c226caa2bfbe4fefe8fde5216e0 + * cipher/ecc.c (check_secret_key): Ed448 means EdDSA. + (ecc_generate): Likewise. + * tests/t-ed448.c (one_test): Remove the flag in key. + + ecc: Support Ed448 by _gcry_ecc_compute_public. + + commit 5585ee4947082f932ee01d93dfe295c769e96671 + * cipher/ecc-misc.c (_gcry_ecc_compute_public): Handle Ed448. + +2020-06-16 Tianjia Zhang + + tests: Add basic test-vectors for SM4. + + commit c1535d0b8797e9b3bbfb5193b6ab23bf788ffd36 + * tests/basic.c (check_ciphers): Add SM4 check and test-vectors. + + Add SM4 symmetric cipher algorithm. + + commit ddcce166ab8bc6f51f5b509bcbea13a8746384ec + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add sm4.c. + * cipher/cipher.c (cipher_list, cipher_list_algo301): Add + _gcry_cipher_spec_sm4. + * cipher/mac-cmac.c (map_mac_algo_to_cipher): Add cmac SM4. + (_gcry_mac_type_spec_cmac_sm4): Add cmac SM4. + * cipher/mac-internal.h: Declare spec_cmac_sm4. + * cipher/mac.c (mac_list, mac_list_algo201): Add cmac SM4. + * cipher/sm4.c: New. + * configure.ac (available_ciphers): Add sm4. + * doc/gcrypt.texi: Add SM4 document. + * src/cipher.h: Add declarations for SM4 and cmac SM4. + * src/gcrypt.h.in (gcry_cipher_algos): Add algorithm ID for SM4. + +2020-06-16 Jussi Kivilinna + + doc: add GCRY_MD_SM3, GCRY_MAC_HMAC_SM3 and GCRY_MAC_GOST28147_IMIT. + + commit 6c571bfda6409d7d668f5d44cea0c6c31e2688be + * doc/gcrypt.texi: add GCRY_MD_SM3, GCRY_MAC_HMAC_SM3 and + GCRY_MAC_GOST28147_IMIT. + +2020-06-16 NIIBE Yutaka + + ecc: Fix Ed448 key generation. + + commit c15cc1a38199cf0d758579eb01d0e88c99cd4b80 + * cipher/ecc.c (ecc_generate): Fix point representation for Ed448. + + ecc,test: Add testing Ed448. + + commit c7779e499e9051ee79ed720f576dbf40d90cdfb1 + + + ecc: Support Ed448 for verify. + + commit d1baad35c65030e41fcba69854c57032eee0d111 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_verify): Support Ed448. + + ecc: Support Ed448 signing. + + commit 951b37c5038667b461692454397bb058b5e1e184 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_sign): Support Ed448. + + ecc: Use SHAKE256 in EdDSA with Ed448. + + commit 32d6d73d44d372dd1ec0b08ba03f1b7b085c09d9 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_compute_h_d): Fix for SHAKE256. + + ecc: Support shake128 and shake256 for message digest. + + commit f6815a96e51be44a361ddcd3a20a5b969b1dab1b + * cipher/pubkey-util.c (get_hash_algo): Add shake128 and shake256. + + ecc: Support Ed448 for key generation. + + commit e25446ecc04442b399302ce72db6d5ea2e9e85e8 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_compute_h_d): Support Ed448. + (_gcry_ecc_eddsa_genkey): Support Ed448, using + _gcry_ecc_eddsa_compute_h_d. + + ecc: Support Ed448 in decoding point. + + commit bd22b029bbf50737f90535c506fba4f812bcf040 + * cipher/ecc-eddsa.c (ecc_ed448_recover_x): New. + (_gcry_ecc_eddsa_recover_x): Support Ed448. + (_gcry_ecc_eddsa_decodepoint): Support Ed448. + * mpi/ec.c (_gcry_mpi_ec_decode_point): For Ed448, use + _gcry_ecc_eddsa_decodepoint. + + ecc: Add new curve: Ed448. + + commit 339b03acf0971a31997901dd674fb75c4dde31d0 + * cipher/ecc-curves.c (curve_aliases): Add Ed448. + (domain_parms): Add domain parameters for Ed448. + * tests/curves.c (N_CURVES): Increment. + + ecc: Fix EdDSA encoding for Ed448. + + commit 3386aaf84d4d89b6ff931533df2ff82ed3f7c7f9 + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Fix point/scalar + length condition. + * cipher/ecc-eddsa.c (eddsa_encodempi): The second argument is NBITS. + (eddsa_encode_x_y): Likewise. + (_gcry_ecc_eddsa_encodepoint): Follow the change. + (_gcry_ecc_eddsa_ensure_compact): Likewise. + (_gcry_ecc_eddsa_decodepoint): Likewise. + (_gcry_ecc_eddsa_sign): Likewise. Remove restriction of 256 bits. + +2020-06-12 NIIBE Yutaka + + ecc: Fix NBITS in domain_parms. + + commit db7b2c591004868abedbc2c19d3bb2efebf8529d + * cipher/ecc-curves.c (cipher/ecc-curves.c): It's NBITS of 'p'. + +2020-06-08 Jussi Kivilinna + + rijndael: fix UBSAN warning on left shift by 24 places with type 'int' + + commit 6cdd7268fe19b066ddb373e2f3c0b7ebf9b938dd + * cipher/rijndael.c (do_encrypt_fn, do_decrypt_fn): Cast final + sbox/inv_sbox look-ups to 'u32' type. + + Disable all assembly modules with --disable-asm. + + commit 3060aadec396802af13f08c4b2dd1b28f2a68c5d + * configure.ac (try_asm_modules): Update description, + "MPI" => "MPI and cipher". + (gcry_cv_gcc_arm_platform_as_ok, gcry_cv_gcc_aarch64_platform_as_ok) + (gcry_cv_gcc_inline_asm_ssse3, gcry_cv_gcc_inline_asm_pclmul) + (gcry_cv_gcc_inline_asm_shaext, gcry_cv_gcc_inline_asm_sse41) + (gcry_cv_gcc_inline_asm_avx, gcry_cv_gcc_inline_asm_avx2) + (gcry_cv_gcc_inline_asm_bmi2, gcry_cv_gcc_amd64_platform_as_ok) + (gcry_cv_gcc_platform_as_ok_for_intel_syntax) + (gcry_cv_cc_arm_arch_is_v6, gcry_cv_gcc_inline_asm_neon) + (gcry_cv_gcc_inline_asm_aarch32_crypto) + (gcry_cv_gcc_inline_asm_aarch64_neon) + (gcry_cv_gcc_inline_asm_aarch64_crypto) + (gcry_cv_cc_ppc_altivec, gcry_cv_gcc_inline_asm_ppc_altivec) + (gcry_cv_gcc_inline_asm_ppc_arch_3_00): Check for "try_asm_modules". + * mpi/config.links: Set "mpi_cpu_arch" to "disabled" + with --disable-asm. + +2020-06-05 Dmitry Eremin-Solenikov + + mpicalc: fix typo. + + commit 2dd3e27fc53cf408f799d2e7b379c1441e0d62c8 + * src/mpicalc.c (print_help): fix typo in commands description. + +2020-06-04 NIIBE Yutaka + + mpi: Fix flags in mpi_copy for opaque MPI. + + commit 78a5a1aa7627afaa24e2ea1eb9b08f1cfdd71561 + * mpi/mpiutil.c (_gcry_mpi_copy): Copy flags. + +2020-06-03 NIIBE Yutaka + + ecc: Use opaque MPI for 'd' of Ed25519/EdDSA. + + commit 0d8346f84a1f5865da3375ce92420d92fb5ae652 + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Add FLAGS. + Use opaque MPI for Ed25519/EdDSA, too. + (_gcry_mpi_ec_internal_new): Follow the change. + (_gcry_mpi_ec_new): Likewise. + +2020-06-01 Jussi Kivilinna + + cipher-ocb: fix out-of-array stack memory access. + + commit 8cfaeae42522778052c36fceccab504826a30cbf + * cipher/cipher-ocb.c (bit_copy): Do not access memory beyond + 's' array when bitoff > 8. + +2020-06-01 NIIBE Yutaka + + mpi: More fix of off-by-one mistake mpi_invm_pow2. + + commit 6a2cd0fe78a9cdc78911694a84b08762dd8658b4 + * mpi/mpi-inv.c (mpi_invm_pow2): Avoid out-of-band read/write. + + ecc: Consistently handle parameters as unsigned value. + + commit 6f8b1d4cb798375e6d830fd6b73c71da93ee5f3f + * cipher/ecc-curves.c (_gcry_ecc_get_curve): Parse as unsigned value. + +2020-05-27 NIIBE Yutaka + + sexp: Fix coding of line break. + + commit 33c972b6a6fe79aacb0a732d1df9a9deacafca29 + * src/sexp.c (_gcry_sexp_vextract_param): Add missing newline. + +2020-05-14 NIIBE Yutaka + + ecc: Make sure it's the fixed size bytes. + + commit eb2288f3b1f338a9aec11d559ec84bdb201960e1 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_decodepoint): Checking the size + of EC point representation, return GPG_ERR_INV_OBJ if not valid. + +2020-05-13 Werner Koch + + ecc: Detect the use of a Montgomery curve earlier in ecc_verify. + + commit d0f995afe2e0228d3b9e30b0fc7091631d7d0090 + * cipher/ecc.c (ecc_verify): Do not allow a Montgomery curve. + +2020-05-13 NIIBE Yutaka + + mpi: Fix off-by-one mistake mpi_invm_pow2. + + commit 69b55f87053ce2494cd4b38dc600f867bc4355be + * mpi/mpi-inv.c (mpi_invm_pow2): Avoid out-of-band read/write. + +2020-05-12 Werner Koch + + ecc: Initialize a dummy parameter. + + commit 75a7b17878e02c3882070d6c86e0d2efbc3d680a + * cipher/ecc.c (ecc_verify): Rename flags to dummy_flags and + initialize. + +2020-05-06 Dmitry Eremin-Solenikov + + tests/benchmark.c: fix error message for invalid MAC algo. + + commit 79e196a610b1b734a1f573288b148d62787f5281 + + +2020-04-27 Tianjia Zhang + + ecc: Fix typo error in ecc-gost. + + commit fe688ce7e14f14d7d3a7e16aa0304d24b5b1a179 + * cipher/ecc-gost.c (_gcry_ecc_gost_verify): Fix typo in comment. + +2020-04-27 NIIBE Yutaka + + mpi: Fix the return value of mpi_invm_generic. + + commit f10eb240a30ac115cfeb63848c67a936e1059ab9 + * mpi/mpi-inv.c (mpi_invm_generic): Return correct value. + +2020-04-24 NIIBE Yutaka + + mpi: Fix return value of mpi_invm_generic. + + commit bc3b6a6a45cf9fa6cc0556da870628c53570f52f + * mpi/mpi-inv.c (mpi_invm_generic): Return 0 if inverse does not exist. + + mpi: More use of mpih API for _gcry_mpi_invm. + + commit 559ba9b36c9cdf4762d28beb3b4c59665c671818 + * mpi/mpi-inv.c (mpi_invm_pow2): Remove. + (_gcry_mpi_invm): Use mpih_invm_pow2 instead. + + mpi: Use mpih interface internally for mpi-inv. + + commit beefbb90d71d7fbd0b4429472b7d4b39670ff64b + * mpi/mpi-inv.c (mpih_invm_pow2): Converted from mpi_invm_pow2. + (mpi_invm_pow2): Use mpih_invm_pow2. + + mpi: Fix size of A in mpi_invm_pow2. + + commit efa5151ea1c2a2c049b2651581e71b6becba4e16 + * mpi/mpi-inv.c (mpi_invm_pow2): Fix size of A. + +2020-04-23 NIIBE Yutaka + + mpi: More fix for _gcry_mpi_invm. + + commit f81a1dd7317513000e5bc4d1bfffd6d2bfb8c2a2 + * mpi/mpi-inv.c (_gcry_mpi_invm): Fix comments and use of CRT path. + +2020-04-22 NIIBE Yutaka + + mpi: Fix off-by-one mistake mpi_invm_pow2. + + commit 3bb9f74764b3626ed1116fc7e517921232d6be54 + * mpi/mpi-inv.c (mpi_invm_pow2): Fix computation of iterations. + +2020-04-21 NIIBE Yutaka + + mpi: Use mpi_invm_pow2 for mpi_invm. + + commit bac01a6cfb3d645ff8439cbd3b310d255735d792 + * mpi/mpi-inv.c (_gcry_mpi_invm): Use mpi_invm_pow2. + + mpi: Fix mpi_invm_pow2. + + commit 2a3c58a0b4db01c17da0bf8c035fb1def2af114c + * mpi/mpi-inv.c (mpi_invm_pow2): Fix the algo implementation. + +2020-04-19 Dmitry Baryshkov + + gost28147: implement special MAC mode called imitovstavka (IMIT) + + commit 45f21f871982753716d4a7676d948e8c7d644db5 + * src/gcrypt.h.in (GCRY_MAC_GOST28147_IMIT): New. + * cipher/gost28147.c (gost_imit_open, gost_imit_close) + (gost_imit_setkey, gost_imit_setiv, gost_imit_reset, _gost_imit_block) + (gost_imit_block, gost_imit_write, gost_imit_finish, gost_imit_read) + (gost_imit_verify, gost_imit_get_maclen, gost_imit_get_keylen) + (gost_imit_set_extra_info): New functions implementing GOST 28147-89 + MAC (imitovstavka, IMIT) mode. + * cipher/gost28147.c (gost_imit_ops) + (_gcry_mac_type_spec_gost28147_imit): declare GOST 28147-89 IMIT + handler. + * cipher/mac-internal.h (gcry_mac_handle): add fields to support GOST + 28147-89 IMIT mode. + * cipher/mac.c (mac_list): add _gcry_mac_type_spec_gost28147_imit. + (spec_from_algo): handle GCRY_MAC_GOST28147_IMIT. + * tests/basic.c (check_mac): add GOST28147-89 IMIT test vector. + + mac: add support for gcry_mac_ctl(GCRYCTL_SET_SBOX) + + commit d7fa70ed9ddc6e0189a8b59016b1f17717a26865 + * cipher/mac-internal.h (gcry_mac_spec_ops_t): add set_extra_info field + for providing additional settings. + * cipher/mac.c (_gcry_mac_ctl): support GCRYCTL_SET_SBOX call. + * cipher/mac-cmac.c (cmac_ops): set set_extra_info to NULL. + * cipher/mac-gmac.c (gmac_ops): the same. + * cipher/mac-hmac.c (hmac_ops): the same. + * cipher/mac-poly1305.c (poly1305mac_ops): the same. + +2020-04-17 NIIBE Yutaka + + mpi: Use mpi_invm_pow2 for N=2^k. + + commit 469e2fefb64e3a4bd80995935f82caf416e3a4ae + * mpi/mpi-inv.c (mpi_invm_pow2): Fix. + (_gcry_mpi_invm): Use mpi_invm_pow2. + + mpi: Rewrite mpi_invm_odd into mpih_invm_odd. + + commit 05ceac8e2f6f28f97428c005d0a318d71d7cf9d9 + * mpi/mpi-inv.c (mpih_invm_odd): Use mpi_ptr_t API. + (_gcry_mpi_invm): Use _gcry_mpih_mod and mpih_invm_odd. + + mpi: Add _gcry_mpih_cmp_ui. + + commit 128045a12139fe2e4be877df59da10c7d4857d9a + * mpi/mpih-const-time.c (_gcry_mpih_cmp_ui): New. + + mpi: Add internal functipn mpi_invm_pow2. + + commit 515bd6e9fae448e966f71e23635503716201158d + * mpi/mpi-inv.c (mpi_invm_pow2): New. + +2020-04-16 NIIBE Yutaka + + mpi: Add mpi_set_bit_cond. + + commit a91bd0211c4e5f0ce575b3a63a36049dd9edbf90 + * mpi/mpiutil.c (_gcry_mpi_set_bit_cond): New. + * src/mpi.h (mpi_set_bit_cond): New macro. + (_gcry_mpi_set_bit_cond): New. + + mpi: Add _gcry_mpih_mod. + + commit 95bdfd9ce9e114f447f3639e551e8f4f63d024fe + * mpi/mpi-internal.h (mpih_mod, _gcry_mpih_mod): New. + * mpi/mpih-const-time.c (_gcry_mpih_mod): New. + + mpih: Expose const-time MPI helper functions. + + commit 9b7e0d89006fce0641da05d8ef2696b1fb73145b + * mpi/Makefile.am (libmpi_la_SOURCES): Add mpih-const-time.c. + * mpi/ec.c (mpih_set_cond): Move to mpih-const-time.c. + * mpi/mpi-internal.h: Add macros and declarations. + * mpi/mpi-inv.c (mpih_add_n_cond): Likewise. + (mpih_sub_n_cond, mpih_swap_cond, mpih_abs_cond): Likewise. + * mpi/mpih-const-time.c: New. + +2020-04-14 Werner Koch + + sexp: Extend gcry_sexp_extract_param with a multi-string extractor. + + commit 32b08e38628b3ed409054db05a7f73b1ab86464a + * src/sexp.c (_gcry_sexp_vextract_param): Implement "%#s" control + sequence. + +2020-04-14 NIIBE Yutaka + + ecc: Remove hard-coded value for ECC_DIALECT_ED25519. + + commit 0ff36e04f7cdef961610e7bc674a9c9ef0fd4853 + * mpi/ec.c (ec_p_init): Remove special handling for Ed25519. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_encodepoint): Fix assumption + ec->nbits is 256 for EdDSA. + (_gcry_ecc_eddsa_decodepoint): Likewise. + (_gcry_ecc_eddsa_verify): Likewise. + +2020-04-09 Werner Koch + + sexp: Extend gcry_sexp_extract_param with new format specifiers. + + commit 60c179b59e538aebb3a5f7621d92eee60b90c785 + * src/sexp.c (_gcry_sexp_vextract_param): Add new conversion methods. + * tests/t-sexp.c (check_extract_param): Add corresponding tests. + +2020-04-04 Jussi Kivilinna + + ppc: avoid using vec_vsx_ld/vec_vsx_st for 2x64-bit vectors. + + commit 1250a9cd859d99f487ca8d76a98d70d464324bbe + * cipher/crc-ppc.c (CRC_VEC_U64_LOAD, CRC_VEC_U64_LOAD_LE) + (CRC_VEC_U64_LOAD_BE): Remove vec_vsx_ld usage. + (asm_vec_u64_load, asm_vec_u64_load_le): New. + * cipher/sha512-ppc.c (vec_vshasigma_u64): Use '__asm__' instead of + 'asm' for assembly block. + (vec_u64_load, vec_u64_store): New. + (_gcry_sha512_transform_ppc8): Use vec_u64_load/store instead of + vec_vsx_ld/vec_vsx_st. + * configure.ac (gcy_cv_cc_ppc_altivec) + (gcy_cv_cc_ppc_altivec_cflags): Add check for vec_vsx_ld with + 'unsigned int *' pointer type. + +2020-04-02 Jussi Kivilinna + + asm-poly1305-aarch64: fix building with clang. + + commit 89b3ded8df969fe5fb31313c60419dd34d36b605 + * cipher/asm-poly1305-aarch64.h (POLY1305_BLOCK_PART25): Use correct + instruction format for right-shifting. + +2020-03-31 Daniel Kahn Gillmor + + libgcrypt.m4: Fix spelling. + + commit 6a5743469a4366b1e238d378e427442f04400950 + + + libgcrypt.m4: Fix spelling. + + commit e16e7e619183f36720d17855419860d1dc6fe3a5 + + +2020-03-20 Dmitry Baryshkov + + tests/basic: add GOST 28147 keymeshing testcase from LibreSSL testsuite. + + commit 3441f4c94c49a589c5e323b1526d2d6b5974cf2f + * tests/basic.c (check_cfb_cipher): add check for GOST 28147 CFB with + KeyMeshing enabled. + + gost28147: add support for CryptoPro key meshing per RFC 4357. + + commit dcee00adbd1c0a2cde1aeed1bb94421e81d0de3b + * cipher/gost28147.c (gost_do_set_sbox, cryptopro_key_meshing, + CryptoProMeshingKey, gost_encrypt_block_mesh): New. + (_gcry_cipher_spec_gost28147_mesh): New cipher with keymeshing, + (_gcry_cipher_spec_gost28147): Remove OIDs for this cipher should not + be selected using these OIDs (they are for CFB with keymeshing). + + * cipher/cipher.c (cipher_list, cipher_list_algo301): add + _gcry_cipher_spec_gost28147_mesh. + + * src/gcrypt.h.in (GCRY_CIPHER_GOST28147_MESH): New cipher with + keymeshing. + + * doc/gcrypt.texi (GCRY_CIPHER_GOST28147_MESH): Add definition. + + * tests/basic.c (check_gost28147_cipher, check_gost28147_cipher_basic): + Run basic tests on GCRY_CIPHER_GOST28147_MESH. + + gost: add keymeshing support per RFC 4357. + + commit 18cd3f0c473ae909cdaa5a820faef50d7670fcbb + * cipher/gost-s-box.c (gost_sbox): define if keymeshing should be + enabled or not. + (main): output whether we should enable or disable keymeshing for a + particular parameters set. + +2020-03-18 NIIBE Yutaka + + DSA,ECDSA: Fix use of mpi_invm. + + commit ada758e3019c2585213a132960613b1ac48502b8 + * cipher/dsa.c (sign): Call mpi_invm before _gcry_dsa_modify_k. + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Likewise. + + mpi: Constant time mpi_inv with some conditions. + + commit 20082ca965eab5665af60956c4ed72709836b1ed + * mpi/mpi-inv.c (mpih_add_n_cond, mpih_sub_n_cond, mpih_swap_cond) + (mpih_abs_cond): New. + (mpi_invm_odd): New. + (mpi_invm_generic): Rename from _gcry_mpi_invm. + (_gcry_mpi_invm): Use mpi_invm_odd for usual odd cases. + +2020-03-11 NIIBE Yutaka + + mpi: Support opaque MPI with gcry_mpi_print. + + commit b4b04ae6c2e55bc2b24efc663d1eeaa0b3613f4c + * mpi/mpicoder.c (_gcry_mpi_get_buffer): Return the bytes as-is. + +2020-03-09 Werner Koch + + mpi: Abort on division by zero also in _gcry_mpi_tdiv_qr. + + commit afbab896fa04d9481dbb9f4d01f607b12e31dcbf + * mpi/mpi-div.c (_gcry_mpi_tdiv_qr): Error out on division by zero. + +2020-02-25 NIIBE Yutaka + + build: More accurate dependency to -lgpg-error. + + commit 9b8ac13761f0407bd701e43b0a65fbada204958f + * configure.ac (LIBGCRYPT_CONFIG_LIBS): Remove DL_LIBS. + * src/libgcrypt.c.in: Distinguish static link use case. + * tests/Makefile.am: Fix use of -lgpg-error. + + build: Fix linking -ldl. + + commit c21e5d72e24e62752559f92b1825287298ae2f03 + * src/Makefile.am (libgcrypt_la_LIBADD): Add DL_LIBS. + (mpicalc_LDADD): Remove DL_LIBS. + * tests/Makefile.am (standard_ldadd): Remove DL_LIBS. + +2020-02-02 Jussi Kivilinna + + crc-ppc: fix bad register used for vector load/store assembly. + + commit b64b029318e7d0b66123015146614118f466a7a9 + * cipher/crc-ppc.c (CRC_VEC_U64_LOAD_BE): Move implementation to... + (asm_vec_u64_load_be): ...here; Add "r0" to clobber list for load + instruction when offset is not zero; Add zero offset path. + + rinjdael-aes: use zero offset vector load/store when possible. + + commit 89776d45c824032409f581e5fd1db6bf149df57f + * cipher/rijndael-ppc-common.h (asm_aligned_ld, asm_aligned_st): Use + zero offset instruction variant when input offset is constant zero. + * cipher/rijndael-ppc.c (asm_load_be_noswap) + (asm_store_be_noswap): Likewise. + + Add POWER9 little-endian variant of PPC AES implementation. + + commit 114bbc45e9717f9ad9641f64d8df8690db8da434 + * configure.ac: Add 'rijndael-ppc9le.lo'. + * cipher/Makefile.am: Add 'rijndael-ppc9le.c', 'rijndael-ppc-common.h' + and 'rijndael-ppc-functions.h'. + * cipher/rijndael-internal.h (USE_PPC_CRYPTO_WITH_PPC9LE): New. + (RIJNDAEL_context_s): Add 'use_ppc9le_crypto'. + * cipher/rijndael.c (_gcry_aes_ppc9le_encrypt) + (_gcry_aes_ppc9le_decrypt, _gcry_aes_ppc9le_cfb_enc) + (_gcry_aes_ppc9le_cfb_dec, _gcry_aes_ppc9le_ctr_enc) + (_gcry_aes_ppc9le_cbc_enc, _gcry_aes_ppc9le_cbc_dec) + (_gcry_aes_ppc9le_ocb_crypt, _gcry_aes_ppc9le_ocb_auth) + (_gcry_aes_ppc9le_xts_crypt): New. + (do_setkey, _gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (_gcry_aes_ctr_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_dec) + (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth, _gcry_aes_xts_crypt) + [USE_PPC_CRYPTO_WITH_PPC9LE]: New. + * cipher/rijndael-ppc.c: Split common code to headers + 'rijndael-ppc-common.h' and 'rijndael-ppc-functions.h'. + * cipher/rijndael-ppc-common.h: Split from 'rijndael-ppc.c'. + (asm_add_uint64, asm_sra_int64, asm_swap_uint64_halfs): New. + * cipher/rijndael-ppc-functions.h: Split from 'rijndael-ppc.c'. + (CFB_ENC_FUNC, CBC_ENC_FUNC): Unroll loop by 2. + (XTS_CRYPT_FUNC, GEN_TWEAK): Tweak generation without vperm + instruction. + * cipher/rijndael-ppc9le.c: New. + + Add gcry_cipher_ctl command to allow weak keys in testing use-cases. + + commit 5beadf201312d0c649971b0c1d4c3827b434a0b5 + * cipher/cipher-internal.h (gcry_cipher_handle): Add + 'marks.allow_weak_key' flag. + * cipher/cipher.c (cipher_setkey): Do not handle weak key as error when + weak keys are allowed. + (cipher_reset): Preserve 'marks.allow_weak_key' flag on object reset. + (_gcry_cipher_ctl): Add handling for GCRYCTL_SET_ALLOW_WEAK_KEY. + * src/gcrypt.h.in (gcry_ctl_cmds): Add GCRYCTL_SET_ALLOW_WEAK_KEY. + * tests/basic.c (check_ecb_cipher): Add tests for weak key errors and + for GCRYCTL_SET_ALLOW_WEAK_KEY. + +2020-01-23 NIIBE Yutaka + + random: Fix include of config.h. + + commit e0898d0628789414da23e0526c87df1885c8b3ae + * random/random-drbg.c: Include config.h earlier. + +2020-01-22 Jussi Kivilinna + + sexp: fix cast from 'int' pointer to 'size_t' pointer. + + commit 8b31091da092e22dba78b2402c2f436bbffc1c73 + * src/sexp.c (do_vsexp_sscan): Change 'datalen' from 'int' to + 'size_t'; Remove &datalen pointer cast to 'size_t *' type. + + mpi/i386: fix DWARF CFI for _gcry_mpih_sub_n and _gcry_mpih_add_n. + + commit 5f098f7e6ceb899ac27a0a30ee036de5f1be4e3d + * mpi/i386/mpih-add1.S (_gcry_mpih_add_n) [PIC]: Adjust CFI CFA offset + when making call and restoring stack pointer. + * mpi/i386/mpih-sub1.S (_gcry_mpih_sub_n) [PIC]: Ditto. + +2020-01-22 H.J. Lu + + i386: Add _CET_ENDBR to indirect jump targets. + + commit cb9f0a2df8225eed071ae0a56265e38e9f6ff184 + * mpi/i386/mpih-add1.S (_gcry_mpih_add_n): Save and restore + %ebx if IBT is enabed. Add _CET_ENDBR to indirect jump targets + and adjust jump destination for _CET_ENDBR. + * mpi/i386/mpih-sub1.S (_gcry_mpih_sub_n): Likewise. + + amd64: Always include in cipher assembly codes. + + commit 22e577071790834f07753c42a191a568c9f2644d + * cipher/camellia-aesni-avx-amd64.S: Always include . + * cipher/camellia-aesni-avx2-amd64.S: Likewise. + * cipher/serpent-avx2-amd64.S: Likewise. + + mpi: Add .note.gnu.property section for Intel CET. + + commit 24b4d5c10a97aaf82ac7402cc3a5b429d580cd66 + * mpi/config.links: Include in . + + x86: Add .note.gnu.property section for Intel CET. + + commit 4c88c2bd2a418435506325cd53246acaaa52750c + * configure.ac: Include in for assembly + codes. + +2020-01-22 Jussi Kivilinna + + tests/basic: add vector cluttering to detect implementation bugs. + + commit 4aa8ff904262f331abbb8c988069a7029ca13502 + * src/global.c (_gcry_check_version): Fix missing newline. + * src/basic.c (ALWAYS_INLINE, CLUTTER_REGISTER_*, prepare_vector_data) + (clutter_vector_registers): New. + (progress_handler): Make static function. + (check_bulk_cipher_modes, check_one_cipher_core_reset) + (check_one_cipher_core, check_one_md, check_one_md_multi) + (check_one_md_final, check_one_mac): Clutter vector registers before + gcry_* calls to cipher/md/mac algorithms. + +2020-01-22 Marvin W + + Set vZZ.16b register to zero before use in armv8 gcm implementation. + + commit 79ed620ec46adbb08f5cea6a4865a95a436e4109 + * cipher/cipher-gcm-armv8-aarch64-ce.S + (_gcry_ghash_setup_armv8_ce_pmull): Set vZZ to zero. + +2020-01-21 Tianjia Zhang + + tests: Add basic test cases for sm2. + + commit aa9c78afa1d867bb7b9b3c695cf31a832c9419e5 + * tests/basic.c (check_pubkey): Add test cases for ecc-sm2. + + Add elliptic curve SM2 implementation. + + commit 6b55246c77089dd372eb1807808111660fd789c7 + * configure.ac (enabled_pubkey_ciphers): Add ecc-sm2. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add ecc-sm2.c. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist, + _gcry_pk_util_preparse_sigval): Add sm2 flags. + * cipher/ecc.c: Support ecc-sm2. + * cipher/ecc-common.h: Add declarations for ecc-sm2. + * cipher/ecc-sm2.c: New. + * src/cipher.h: Define PUBKEY_FLAG_SM2. + + ecc: Simplify signature code. + + commit 8d9958910e54f3fecbab6e133c3971843f6ef310 + * cipher/ecc-gost.c (_gcry_ecc_gost_sign): Use implemented function. + * cipher/ecc.c (ecc_verify): Remove redundant code. + +2020-01-21 NIIBE Yutaka + NIIBE Yutaka + + tests: Fix check_pubkey. + + commit 95e9cee802419adf6f4b01b29d7874793004fa8d + * tests/basic.c (check_pubkey): Fix constants of pubkeys. + +2020-01-21 NIIBE Yutaka + + Avoid use of ulong in internal code. + + commit 4997139b3e83761c9af0246cec829305c3d7d13b + * configure.ac (HAVE_ULONG_TYPEDEF): Remove. + * mpi/mpi-div.c (_gcry_mpi_fdiv_r_ui): Use unsigned long. + (_gcry_mpi_divisible_ui): Likewise. + * random/rndunix.c (_gcry_rndunix_gather_random): Likewise. + * random/rndw32.c (_gcry_rndw32_gather_random_fast): Likewise. + (ADDINT): Likewise. + * random/rndw32ce.c (_gcry_rndw32ce_gather_random_fast): Likewise. + * src/mpi.h: Follow the change. + * src/types.h (HAVE_ULONG_TYPEDEF): Remove. + +2020-01-19 Jussi Kivilinna + + gcrypt.texi: fix GCRYCTL_GET_ALGO_NENCR typo. + + commit 5ebb2f0671c902863eee91cbcfc85a72be506410 + * doc/gcrypt.texi: Fix GCRYCTL_GET_ALGO_NENC to GCRYCTL_GET_ALGO_NENCR. + +2020-01-19 Tianjia Zhang + + mpi: Fix error that point not uninitialized. + + commit 7e3aac7ba49b3b6e6c5ebe7c880b5b323c423ef7 + * cipher/ecc-curves.c (mpi_ec_get_elliptic_curve): Initialize E->G poing + + ecc: Wrong flag and elements_enc fix. + + commit 43cfc1632dd3a9579a906f31cd3b6c88d242d1a5 + * cipher/ecc.c (ecc_generate): Fix wrong flag and elements_enc. + + Update .gitignore. + + commit 176a5f162acd0cfebc5517d061205681bc3658d0 + + +2020-01-16 Tianjia Zhang + + Add new curve named sm2p256v1. + + commit d154c1e9e11019980253f0a65758932cd0656470 + * cipher/ecc-curves.c (domain_parms): Add sm2p256v1 for SM2. + * tests/curves.c (N_CURVES): Update N_CURVES for SM2. + +2019-12-23 Jussi Kivilinna + + rijndael-ppc: performance improvements. + + commit 110077505acacae62cec3d09b32a084b9cee0368 + * cipher/rijndael-ppc.c (ALIGNED_LOAD, ALIGNED_STORE, VEC_LOAD_BE) + (VEC_STORE_BE): Rewrite. + (VEC_BE_SWAP, VEC_LOAD_BE_NOSWAP, VEC_STORE_BE_NOSWAP): New. + (PRELOAD_ROUND_KEYS, AES_ENCRYPT, AES_DECRYPT): Adjust to new + input parameters for vector load macros. + (ROUND_KEY_VARIABLES_ALL, PRELOAD_ROUND_KEYS_ALL) + (AES_ENCRYPT_ALL): New. + (vec_bswap32_const_neg): New. + (vec_aligned_ld, vec_aligned_st, vec_load_be_const): Rename to... + (asm_aligned_ls, asm_aligned_st, asm_load_be_const): ...these. + (asm_be_swap, asm_vperm1, asm_load_be_noswap) + (asm_store_be_noswap): New. + (vec_add_uint128): Rename to... + (asm_add_uint128): ...this. + (asm_xor, asm_cipher_be, asm_cipherlast_be, asm_ncipher_be) + (asm_ncipherlast_be): New inline assembly functions with volatile + keyword to allow manual instruction ordering. + (_gcry_aes_ppc8_setkey, aes_ppc8_prepare_decryption) + (_gcry_aes_ppc8_encrypt, _gcry_aes_ppc8_decrypt) + (_gcry_aes_ppc8_cfb_enc, _gcry_aes_ppc8_cbc_enc) + (_gcry_aes_ppc8_ocb_auth): Update to use new&rewritten helper macros. + (_gcry_aes_ppc8_cfb_dec, _gcry_aes_ppc8_cbc_dec) + (_gcry_aes_ppc8_ctr_enc, _gcry_aes_ppc8_ocb_crypt) + (_gcry_aes_ppc8_xts_crypt): Update to use new&rewritten helper + macros; Tune 8-block parallel paths with manual instruction ordering. + + rijndael-ppc: fix bad register used for vector load/store assembly. + + commit 0837d7e6be3e604c1f7b86d18c582d8aa7ed858c + * cipher/rijndael-ppc.c (vec_aligned_ld, vec_load_be, vec_aligned_st) + (vec_store_be): Add "r0" to clobber list for load/store instructions. + +2019-12-22 Jussi Kivilinna + + cipher: fix typo in error log. + + commit 5b9ea3df0dc355d77b9f061f63064614a97b8b67 + * cipher/cipher.c (_gcry_cipher_encrypt): Fix log "cipher_decrypt: ..." + to "cipher_encrypt: ...". + +2019-11-21 Dmitry Eremin-Solenikov + + gost28147: inline gost_val function to speed up code. + + commit e5c4cf0efb8fd297963e6b4392ab98c41dbad536 + * cipher/gost28147.c (gost_val): mark function as inline + + gost28147: do not use GOST28147_CONTEXT outside of GOST 28147 calculation + + commit f9894240bed36eab17fabf5aa482799b148618e2 + * cipher/gost28147.c (_gcry_gost_enc_data): remove unused context + argument + * cipher/gostr3411-94.c (GOSTR3411_CONTEXT, gostr3411_init, + do_hash_step): remove unused GOST 28147-89 context. + + gost28147: simplify internal code. + + commit d164a8e7f6829163f1279517f07b61805311f8f2 + * cipher/gost28147.c (gost_val, _gost_encrypt_data): don't use gost + context internally + * cipher/gost28147.c (gost_encrypt_block, gost_decrypt_block, + _gcry_gost_enc_data): adapt to internal changes. + + gostr3411-94: small speedup. + + commit 8f573a67d12e6d9026f1676a6dae7813105bc490 + * cipher/gostr3411-94.c (do_p): unroll loop for a small spedup + +2019-11-18 Paul Wolneykien + + ecc: update GOST2012 curves. + + commit a3a866f63e7a527fe3c053758b84d70c142f8283 + * cipher/ecc-curves.c (domain_parms): rename GOST 2012 curves to contain + curve bit size + (curve_aliases): rename curves, provide backwards-compatible + aliases, add new OIDs and two new curves. + * cipher/ecc-curves.c (curve_aliases): add new OIDs and aliases for + * tests/basic.c (check_pubkey): use new name for GOST2012 512-bit test + curve. + * tests/benchmark.c (ecc_bench): use new name for GOST2012 512-bit test + curve. + +2019-11-05 Jussi Kivilinna + + ec: fix left shift overflows on WIN64 build. + + commit bdbd032d1626dbb34e1840e5f5393524dd546a1d + * mpi/ec.c (ec_mulm_448): Cast constants to (mpi_limb_t) before + shifting left by 32. + + mpi/amd64: use SSE2 for shifting instead of MMX. + + commit 1322c6a5d1e9aa0c69a2b259aa5ec7bcf5cb5653 + * mpi/amd64/mpih-lshift.S: Convert to SSE2. + * mpi/amd64/mpih-rshift.S: Ditto. + + Add i386/SSSE3 implementation of SHA512. + + commit b52dde860963c794b12d14b0a9c5848bca7ba51e + * LICENSES: Add 'sha512-ssse3-i386.c'. + * configure.ac: Add 'sha512-ssse3-i386.lo'. + * cipher/Makefile.am: Add 'sha512-ssse3-i386.c'. + * cipher/sha512-ssse3-i386.c: New. + * cipher/sha512.c (USE_SSSE3_I386, _gcry_sha512_transform_i386_ssse3) + (do_sha512_transform_i386_ssse3): New. + (_gcry_sha512_transform_arm) [USE_SSSE3_I386]: Use i386/SSSE3 transform + function if supported by CPU. + +2019-10-28 NIIBE Yutaka + + ecc: Add Curve for X448 with ECC_DIALECT_SAFECURVE. + + commit d9c418305e1053decebefbd5a98a95f845404a09 + * cipher/ecc-curves.c (domain_parms): Add X448. + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Support X448. + * mpi/ec.c (ec_addm_448, ec_subm_448, ec_mulm_448): New. + (ec_mul2_448, ec_pow2_448): New. + (field_table): Add for X448. + (curve448_bad_points): New. + (bad_points_table): New. + (ec_p_init): Use bad_points_table. + * tests/Makefile.am (t-x448): Add. + * tests/curves.c (N_CURVES): Update. + * tests/t-x448.c: New. + +2019-10-25 NIIBE Yutaka + + ecc: Introduce new dialect: ECC_DIALECT_SAFECURVE. + + commit 498ab6d9f2f8b0775da41553be7868e59cf4cc2e + * src/mpi.h (ECC_DIALECT_SAFECURVE): New. + * cipher/ecc-misc.c (_gcry_ecc_dialect2str): Support the new dialect. + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Support opaque + MPI handling of secret 'd' for ECC_DIALECT_SAFECURVE. + * cipher/ecc.c (nist_generate_key): Support opaque secret for + ECC_DIALECT_SAFECURVE. + (test_ecdh_only_keys): Likewise. + (ecc_generate): Support native point representation for + ECC_DIALECT_SAFECURVE. + (ecc_encrypt_raw): Support opaque MPI handling of secret and + native point representation for ECC_DIALECT_SAFECURVE. + (ecc_decrypt_raw): Support native point representation for + ECC_DIALECT_SAFECURVE. + (_gcry_pk_ecc_get_sexp): Likewise. + + ecc: Make _gcry_mpi_ec_mul_point friendly to X25519 computation. + + commit 2dfedafe08ac57a87e6892d1af4d72cbb398fe40 + * mpi/ec.c (_gcry_mpi_ec_mul_point): Support scalar input as an opaque + MPI in little-endian native format. + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Use an opaque scalar. + + pubkey: Support a method to get data as an opaque MPI. + + commit 050e0b4accfae6a49dda6b1bac52749edec5ce22 + * cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Support an + opaque MPI in old style. + +2019-10-24 NIIBE Yutaka + + ecc: Support an opaque MPI handling in mpi_from_keyparam. + + commit 05a7d2f262bc5c2d108dcfa6e3d907dd895a4074 + * cipher/ecc-curves.c (mpi_from_keyparam): Add OPAQUE argument. + + ecc: Fix handling of point representation in EdDSA. + + commit 3d5a05767b84e0f781ed5dfe434adb4d4e9d2aa5 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_ensure_compact): Use + GCRYMPI_FMT_USG, since integer is defined as unsigned in SEC1. + (_gcry_ecc_eddsa_decodepoint): Likewise. + + ecc: Return an opaque MPI by _gcry_ecc_ec2os. + + commit 8fce1027c2531127dd52a8b883f34333ffd3763b + * cipher/ecc-misc.c (_gcry_ecc_ec2os): Use mpi_set_opaque instead of + _gcry_mpi_scan to make an opaque MPI. + + ecc: String constant fix. + + commit 35c1faaea2b0aee9b127d02d93158826d17eb107 + * cipher/ecc-curves.c (domain_parms): Same string length for NIST + P-521. + + ecc: Simplify _gcry_ecc_compute_public. + + commit ad8927f40169364003f72fc188ea60b295ef5e59 + * cipher/ecc-misc.c (_gcry_ecc_compute_public): Don't need G and d. + Use ec->G and ec->d. + * cipher/ecc-curves.c (_gcry_ecc_get_mpi): Follow the change. + (_gcry_ecc_get_point): Likewise. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_compute_h_d): Don't need d, + but use ec->d. + (_gcry_ecc_eddsa_sign): Follow the change. + +2019-10-23 NIIBE Yutaka + + ecc: Use opaque MPI for _gcry_ecc_mul_point. + + commit c5a7191c1bd18292a34ad4da45d743dfac035f9a + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Use opaque MPI for U. + + ecc: Fix _gcry_ecc_mont_decodepoint for data by old implementation. + + commit bbe15758c893dbf546416c1a6bccdad1ab000ad7 + * cipher/ecc-misc.c (_gcry_ecc_mont_decodepoint): Support data by old + implementation by opaque public key. + Fix confusion of endian, in the handling of data by normal MPI key. + + ecc: ECDH clean up for use of ec->nbits. + + commit 27e848666b4a03939b0c8db15aa6e6f79bc7db30 + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Use ec->nbits. + * cipher/ecc.c (test_ecdh_only_keys): Likewise. + (ecc_encrypt_raw): Likewise. + (ecc_generate): Fix debug output format. + +2019-10-22 NIIBE Yutaka + + ecc: Fix key generation for ECDH. + + commit 82441bbb82903c21cd2b9b4e2d50202b14fdc24c + * cipher/ecc.c (test_ecdh_only_keys): Don't free EC here. + + ecc: Fix debug output. + + commit 6d93812aa312a92d4de2dc034bdf87c276a24b8a + * cipher/ecc-curves.c (_gcry_mpi_ec_internal_new): Fix debug output. + + ecc: Simplify using mpi_ec_t directly. + + commit 6a30a9a2cc48d2343c3e9815567dbd4bf9eec058 + * cipher/ecc-common.h (ECC_public_key, ECC_secret_key): Remove. + (_gcry_ecc_ecdsa_sign, _gcry_ecc_ecdsa_verify): Use mpi_ec_t. + (_gcry_ecc_eddsa_genkey, gcry_ecc_eddsa_sign): Likewise. + (_gcry_ecc_eddsa_verify): Likewise. + (_gcry_ecc_gost_sign, _gcry_ecc_gost_verify): Likewise. + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Use mpi_ec_t directly. + (_gcry_ecc_ecdsa_verify): Likewise. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_genkey): Likewise. + (_gcry_ecc_eddsa_sign, _gcry_ecc_eddsa_verify): Likewise. + * cipher/ecc-gost.c (_gcry_ecc_gost_sign): Likewise. + (_gcry_ecc_gost_verify): Likewise. + + ecc: Fix for NBITS support. + + commit 975de38796917392e83152447c6575648a5a5ee3 + * cipher/ecc-curves.c (mpi_ec_get_elliptic_curve): Fill curve + parameters by NBITS. + (_gcry_mpi_ec_internal_new): Show "EdDSA". + + ecc: Add NAME member to struct mpi_ec_ctx_s. + + commit e921ad5b3ad093304312aca90a3c971de05cbf03 + * src/ec-context.h (struct mpi_ec_ctx_s): Add NAME. + * cipher/ecc-curves.c (mpi_ec_setup_elliptic_curve): Initialize NAME. + + ecc: Add key generation support to mpi_ec_get_elliptic_curve. + + commit 488704be6e044e23770d95344511c5a347b533c5 + * cipher/ecc-curves.c (mpi_ec_get_elliptic_curve): Handle params for + key generation. + (_gcry_mpi_ec_internal_new): Remove duplication for handling of flags. + + ecc: Consolidate with _gcry_mpi_ec_internal_new. + + commit 5415bc578080018e1cd36aa44cf5c0a9995cbafc + * cipher/ecc-ecdh.c (prepare_ec): Use _gcry_mpi_ec_internal_new. + (_gcry_ecc_mul_point): Don't need to have E of elliptic_curve_t. + * cipher/ecc.c (ecc_encrypt_raw): Use _gcry_mpi_ec_internal_new. + (ecc_decrypt_raw): Likewise. + + ecc: Support flags and debug print in _gcry_mpi_ec_internal_new. + + commit c2aa333dd88b4cd337329128a2018dd3b00f5114 + * cipher/ecc-curves.c (mpi_ec_get_elliptic_curve): Don't set *r_flags. + (_gcry_mpi_ec_internal_new): Add r_flags argument. + Parse the flag list. + Output to debug channel when DBG_CIPHER. + +2019-10-21 NIIBE Yutaka + + ecc: Add new function _gcry_mpi_ec_internal_new. + + commit c7b97ac9bdf96f5a89ae553cac12954043ab174d + * cipher/ecc-curves.c (mpi_ec_get_elliptic_curve) + (mpi_ec_setup_elliptic_curve): Factor out from _gcry_mpi_ec_new. + (_gcry_mpi_ec_internal_new): New. + (_gcry_mpi_ec_new): Rewrite using mpi_ec_get_elliptic_curve and + mpi_ec_setup_elliptic_curve. + + ecc: Simplify ecc_encrypt_raw and ecc_decrypt_raw. + + commit 10b8cc280a535f14b017106c87f2b26bb68d9489 + * cipher/ecc.c (ecc_encrypt_raw): Use elliptic_curve_t directly. + (ecc_decrypt_raw): Likewise. + + ecc: More fixes for cofactor with PUBKEY_FLAG_PARAM. + + commit 61a0518282537ad52367354c96986c3d1b698d6f + * cipher/ecc.c (ecc_check_secret_key): Support "h" in KEYPARMS. + (ecc_sign, ecc_verify, ecc_encrypt_raw, ecc_decrypt_raw): Likewise. + + ecc: Simply use unsigned int for cofactor, not MPI. + + commit a258ae728de62607b3ef4eca940cfbcf9965fa5f + * cipher/ecc-common.h (elliptic_curve_t): Use unsigned int for H. + * src/ec-context.h (struct mpi_ec_ctx_s): Ditto. + * cipher/ecc-curves.c (ecc_domain_parms_t): Ditto. + (domain_parms): Update for the cofactors. + (_gcry_ecc_fill_in_curve): H is no longer MPI, but unsigned int. + (_gcry_ecc_get_curve): Remove handling for H. + (_gcry_mpi_ec_new): In KEYPARM, cofactor is still MPI. + (_gcry_ecc_get_param_sexp): H is no longer MPI, but unsigned int. + (_gcry_ecc_get_mpi): Keep the API, returning MPI for "h". + (_gcry_ecc_set_mpi): Likewise. + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Fix for unsigned int. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_genkey): Likewise. + * cipher/ecc-misc.c (_gcry_ecc_curve_free): Likewise. + * cipher/ecc.c (nist_generate_key, test_ecdh_only_keys): Likewise. + (test_ecdh_only_keys, ecc_generate, ecc_check_secret_key): Likewise. + (ecc_sign, ecc_verify, ecc_encrypt_raw, ecc_decrypt_raw): Likewise. + (_gcry_pk_ecc_get_sexp): Likewise. + * mpi/ec.c (ec_deinit): Likewise. + +2019-10-18 NIIBE Yutaka + + ecc: Simplify compute_keygrip. + + commit 579d5d6017d63b5eabec588b24d1a22566455bac + * cipher/ecc-curves.c (_gcry_ecc_update_curve_param): Remove H. + * cipher/ecc.c (compute_keygrip): Don't get H, since it's not + used in the computation. + + ecc: Clean up key generation code. + + commit 95cc9b8f4483fd7edfc7555199f6a05cfa68a236 + * cipher/ecc.c (test_ecdh_only_keys): No need to make PK by SK. + +2019-10-14 Jussi Kivilinna + + Fix building t-lock for WIN32. + + commit 7e1383cfd43fdc2b6f743e6a1304f0f0b2142847 + * tests/t-lock.c (external_lock_test_init, external_lock_test_lock) + (externel_lock_test_unlock, external_lock_test_destroy) + (nonce_thread, get_rand, pick_account, pick_value, revision_thread) + (accountant_thread): Build also if _WIN32 defined in addition to + HAVE_PTHREAD. + + hash-common: avoid integer division to reduce call overhead. + + commit f9d8b5a0369cc94e125d36d9c8864d5cd2eaa1d2 + * cipher/hash-common.h (gcry_md_block_ctx): Replace 'blocksize' with + 'blocksize_shift'. + * cipher/hash-common.c (_gcry_md_block_write): Use bit-level operations + instead of division to get number of blocks. + * cipher/gostr2411-94.c (gost3411_init): Initialize 'blocksize_shift' + instead of 'blocksize'. + * cipher/md2.c (md2_init): Ditto. + * cipher/md4.c (md4_init): Ditto. + * cipher/md5.c (md5_init): Ditto. + * cipher/rmd160.c (rmd160_init): Ditto. + * cipher/sha1.c (sha1_init): Ditto. + * cipher/sha256.c (sha256_common_init): Ditto. + * cipher/sha512.c (sha512_init_common): Ditto. + * cipher/sm3.c (sm3_init): Ditto. + * cipher/stribog.c (stribog_init_512): Ditto. + * cipher/tiger.c (do_init): Ditto. + * cipher/whirlpool.c (whirlpool_init): Ditto. + +2019-10-11 NIIBE Yutaka + + ecc: Handle ephemeral key as opaque octets. + + commit ff0f1782560eb45458d9a8dd97088dabeddb34e7 + * cipher/ecc.c (ecc_decrypt_raw): Extract an ephemeral key + as opaque octets. + +2019-10-10 NIIBE Yutaka + + ecc: Consolidate encoding a point for Montgomery curve. + + commit 80cf289905ace9f174eb06d7f55f38980f7e4dbd + * cipher/ecc-common.h (_gcry_ecc_mont_encodepoint): New. + * cipher/ecc-misc.c (_gcry_ecc_mont_encodepoint): New. + * cipher/ecc.c (ecc_generate): Use _gcry_ecc_mont_encodepoint. + (ecc_encrypt_raw, ecc_decrypt_raw, _gcry_pk_ecc_get_sexp): Likewise. + +2019-10-09 NIIBE Yutaka + + ecc: More clean-up for Ed25519 and Curve25519. + + commit ba0b31f2636632b1b39ebd2202de3ba5d60588b8 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_ensure_compact): Fix calc for + bytes. + * cipher/ecc.c (ecc_encrypt_raw): Use public key as opaque byte-string + with "/q" for both cases, since it is always fixed size with a prefix. + (compute_keygrip): Likewise. + Fix hard-coded value of 256 for Ed25519. + Handle Curve25519 differently. + +2019-10-08 NIIBE Yutaka + + ecc: Fix hard-coded value for 25519 to allow other modern curves. + + commit d66a4856eb0c39823bf3414b3ca4cf6322f32aef + * cipher/ecc.c (nist_generate_key): Support other modern curves. + (test_ecdh_only_keys): Likewise. + (check_secret_key): Don't use ECC_DIALECT_ED25519 for the check. + (_gcry_pk_ecc_get_sexp): Support Montgomery curve. + + ecc: Clean up for decoding point. + + commit 254c5279058f0aea2d3568d6e756002242e82f8f + * cipher/ecc-curves.c (point_from_keyparam): Possibly supporting + Montgomery curve, use _gcry_mpi_ec_decode_point. + (_gcry_ecc_set_mpi): Likewise. + * cipher/ecc.c (ecc_check_secret_key): Likewise. + + random: Clean up unused old internal API. + + commit 6e57242c61bca38b3cc8fdf424b5667ab953e4cd + * random/random.h (_gcry_get_random_bits): Remove. + +2019-10-02 NIIBE Yutaka + + ecc: Fix regression in keygrip computation for cv25519 (2). + + commit 1cfe2329b91cc7be30f7c3a14fc634ec89a1be96 + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Recover g_y + for Curve25519. + +2019-09-28 Werner Koch + + ecc: Fix regression in keygrip computation for cv25519. + + commit f67b6492e0b0a2a661cd53a08b20f23e6e3f9f89 + * cipher/ecc-curves.c (domain_parms): Revert g_y for cv25519. + * tests/keygrip.c: Add test case for cv25519. + +2019-09-24 Jussi Kivilinna + + Add stitched ChaCha20-Poly1305 ARMv8/AArch64 implementation. + + commit 4bebafb7bae8343f543728937caf7d3453c88b7c + * cipher/Makefile.am: Add 'asm-poly1305-aarch64.h'. + * cipher/asm-poly1305-aarch64.h: New. + * cipher/chacha20-aarch64.S (ROT8, _, ROTATE2_8): New. + (ROTATE2): Add interleave operator. + (QUARTERROUND2): Add interleave operators; Use ROTATE2_8. + (chacha20_data): Rename to... + (_gcry_chacha20_aarch64_blocks4_data_inc_counter): ...to this. + (_gcry_chacha20_aarch64_blocks4_data_rot8): New. + (_gcry_chacha20_aarch64_blocks4): Preload ROT8; Fill empty parameters + for QUARTERROUND2 interleave operators. + (_gcry_chacha20_poly1305_aarch64_blocks4): New. + * cipher/chacha20.c + [USE_AARCH64_SIMD] (_gcry_chacha20_poly1305_aarch64_blocks4): New. + (_gcry_chacha20_poly1305_encrypt, _gcry_chacha20_poly1305_decrypt) + [USE_AARCH64_SIMD]: Use stitched implementation if ctr->use_neon is + set. + +2019-09-22 Jussi Kivilinna + + Small tweak for PowerPC Chacha20-Poly1305 round loop. + + commit 96b91e164160dfbd913aefe258f472d386f5b642 + * cipher/chacha20-ppc.c (_gcry_chacha20_poly1305_ppc8_block4): Use + inner/outer round loop structure instead of two separate loops for + stitched and non-stitched parts. + + Reduce size of x86-64 stitched Chacha20-Poly1305 implementations. + + commit 664370ea02df883d16db1ffdd9ada023335b0f63 + * cipher/chacha20-amd64-avx2.c + (_gcry_chacha20_poly1305_amd64_avx2_blocks8): De-unroll round loop. + * cipher/chacha20-amd64-ssse3.c + (_gcry_chacha20_poly1305_amd64_ssse3_blocks4): + (_gcry_chacha20_poly1305_amd64_ssse3_blocks1): Ditto. + +2019-09-16 Jussi Kivilinna + + Add PowerPC extra CFLAGS also for chacha20-ppc and crc-ppc. + + commit 5516072451d46be8827455afff840eb6d49155fb + * cipher/Makefile.am: Add 'ppc_vcrypto_cflags' for chacha20-ppc.o/.lo + and crc-ppc.o/.lo. + +2019-09-15 Jussi Kivilinna + + Add PowerPC vpmsum implementation of CRC. + + commit 0486b85bd1fb65013e77f858cae9ea4530f868df + * cipher/Makefile.am: Add 'crc-ppc.c'. + * cipher/crc-armv8-ce.c: Remove 'USE_INTEL_PCLMUL' comment. + * cipher/crc-ppc.c: New. + * cipher/crc.c (USE_PPC_VPMSUM): New. + (CRC_CONTEXT): Add 'use_vpmsum'. + (_gcry_crc32_ppc8_vpmsum, _gcry_crc24rfc2440_ppc8_vpmsum): New. + (crc32_init, crc24rfc2440_init): Add HWF check for 'use_vpmsum'. + (crc32_write, crc24rfc2440_write): Add 'use_vpmsum' code-path. + * configure.ac: Add 'vpmsumd' instruction to PowerPC VSX inline + assembly check; Add 'crc-ppc.lo'. + + Add PowerPC vector implementation of ChaCha20. + + commit 557702f0d53a7ad1cf2ce0333c9df799a8abad59 + * cipher/Makefile.am: Add 'chacha20-ppc.c'. + * cipher/chacha20-ppc.c: New. + * cipher/chacha20.c (USE_PPC_VEC, _gcry_chacha20_ppc8_blocks4) + (_gcry_chacha20_ppc8_blocks1, USE_PPC_VEC_POLY1305) + (_gcry_chacha20_poly1305_ppc8_blocks4): New. + (CHACHA20_context_t): Add 'use_ppc'. + (chacha20_blocks, chacha20_keysetup) + (do_chacha20_encrypt_stream_tail): Add USE_PPC_VEC code. + (_gcry_chacha20_poly1305_encrypt, _gcry_chacha20_poly1305_decrypt): Add + USE_PPC_VEC_POLY1305 code. + * configure.ac: Add 'chacha20-ppc.lo'. + * src/g10lib.h (HWF_PPC_ARCH_2_07): New. + * src/hwf-ppc.c (PPC_FEATURE2_ARCH_2_07): New. + (ppc_features): Add HWF_PPC_ARCH_2_07. + * src/hwfeatures.c (hwflist): Add 'ppc-arch_2_07'. + +2019-09-06 Jussi Kivilinna + + poly1305: add fast addition macro for ppc64. + + commit 0564757b934d24c7fef10df8594099985fbbc0ac + * cipher/poly1305.c [USE_MPI_64BIT && __powerpc__] (ADD_1305_64): New. + +2019-09-03 Jussi Kivilinna + + Add SHA-512 implementations for POWER8 and POWER9. + + commit 93632f1adf57f142e5d9e9653c405f2ca8c601c0 + * cipher/Makefile.am: Add 'sha512-ppc.c'; Add extra CFLAG handling for + 'sha512-ppc.c'. + * cipher/sha512-ppc.c: New. + * cipher/sha512.c (USE_PPC_CRYPTO, _gcry_sha512_transform_ppc8) + (_gcry_sha512_transform_ppc9, do_sha512_transform_ppc8) + (do_sha512_transform_ppc9): New. + (sha512_init_common): Add PowerPC HW feature detection and + implementation selection. + * configure.ac: Add 'vshasigmad' instruction to PowerPC assembly + support check; Add 'sha512-ppc.lo'. + +2019-08-31 Jussi Kivilinna + + Add SHA-256 implementations for POWER8 and POWER9. + + commit e19dc973bc8e2a0ce92dd87515df3ee338265a8d + * cipher/Makefile.am: Add 'sha256-ppc.c'; Add extra CFLAG handling for + 'sha256-ppc.c'. + * cipher/sha256-ppc.c: New. + * cipher/sha256.c (USE_PPC_CRYPTO, _gcry_sha256_transform_ppc8) + (_gcry_sha256_transform_ppc9, do_sha256_transform_ppc8) + (do_sha256_transform_ppc9): New. + (sha256_init, sha224_init): Split common part to new function named... + (sha256_common_init): ...this; Add PowerPC HW feature detection and + implementation selection. + * configure.ac: Add 'vshasigmaw' instruction to PowerPC assembly + support check; Add 'sha256-ppc.lo'. + +2019-08-26 Jussi Kivilinna + + hwf-ppc: add detection for PowerISA 3.00. + + commit 418179593080f3028426657c4ef1941cdad85513 + * src/g10lib.h (HWF_PPC_ARCH_3_00): New. + * src/hwf-ppc.c (feature_map_s): Remove unused 'feature_match'. + (PPC_FEATURE2_ARCH_3_00): New. + (ppc_features, get_hwcap): Add PowerISA 3.00. + * src/hwfeatures.c (hwflist): Rename "ppc-crypto" to "ppc-vcrypto"; Add + "ppc-arch_3_00". + + rijndael-ppc: add bulk modes for CBC, CFB, CTR and XTS. + + commit 81d555d3473016eb9382fb1df153ba1effbbe32e + * cipher/rijndael-ppc.c (vec_add_uint128, _gcry_aes_ppc8_cfb_enc) + (_gcry_aes_ppc8_cfb_dec, _gcry_aes_ppc8_cbc_enc) + (_gcry_aes_ppc8_cbc_dec, _gcry_aes_ppc8_ctr_enc) + (_gcry_aes_ppc8_xts_crypt): New. + * cipher/rijndael.c [USE_PPC_CRYPTO] (_gcry_aes_ppc8_cfb_enc) + (_gcry_aes_ppc8_cfb_dec, _gcry_aes_ppc8_cbc_enc) + (_gcry_aes_ppc8_cbc_dec, _gcry_aes_ppc8_ctr_enc) + (_gcry_aes_ppc8_xts_crypt): New. + (do_setkey, _gcry_aes_cfb_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_enc) + (_gcry_aes_cbc_dec, _gcry_aes_ctr_enc) + (_gcry_aes_xts_crypto) [USE_PPC_CRYPTO]: Enable PowerPC AES + CFB/CBC/CTR/XTS bulk implementations. + * configure.ac (gcry_cv_gcc_inline_asm_ppc_altivec): Add 'vadduwm' + instruction. + + rijndael-ppc: add bulk mode for ocb_auth. + + commit bd1367bb607846d582ad09ded6c4ce4be4e52778 + * cipher/rijndael-ppc.c (_gcry_aes_ppc8_ocb_auth): New. + * cipher/rijndael.c [USE_PPC_CRYPTO] (_gcry_aes_ppc8_ocb_auth): New + prototype. + (do_setkey, _gcry_aes_ocb_auth) [USE_PPC_CRYPTO]: Add PowerPC AES + ocb_auth. + + rijndael-ppc: enable PowerPC AES-OCB implemention. + + commit 821602c60c7d144c978c335f91ae1641cf668df5 + * cipher/rijndael-ppc.c (ROUND_KEY_VARIABLES, PRELOAD_ROUND_KEYS) + (AES_ENCRYPT, AES_DECRYPT): New. + (_gcry_aes_ppc8_prepare_decryption): Rename to... + (aes_ppc8_prepare_decryption): ... this. + (_gcry_aes_ppc8_prepare_decryption): New. + (aes_ppc8_encrypt_altivec, aes_ppc8_decrypt_altivec): Remove. + (_gcry_aes_ppc8_encrypt): Use AES_ENCRYPT macro. + (_gcry_aes_ppc8_decrypt): Use AES_DECRYPT macro. + (_gcry_aes_ppc8_ocb_crypt): Uncomment; Optimizations for OCB offset + calculations, etc; Use new load/store and encryption/decryption macros. + * cipher/rijndaelc [USE_PPC_CRYPTO] (_gcry_aes_ppc8_ocb_crypt): New + prototype. + (do_setkey, _gcry_aes_ocb_crypt) [USE_PPC_CRYPTO]: Add PowerPC AES OCB + encryption/decryption. + + rijndael-ppc: add key setup and enable single block PowerPC AES. + + commit 9dca65ef71b4bdbd89a087f41f4dbba71e6d2822 + * cipher/Makefile.am: Add 'rijndael-ppc.c'. + * cipher/rijndael-internal.h (USE_PPC_CRYPTO): New. + (RIJNDAEL_context): Add 'use_ppc_crypto'. + * cipher/rijndael-ppc.c (backwards, swap_if_le): Remove. + (u128_t, ALWAYS_INLINE, NO_INLINE, NO_INSTRUMENT_FUNCTION) + (ASM_FUNC_ATTR, ASM_FUNC_ATTR_INLINE, ASM_FUNC_ATTR_NOINLINE) + (ALIGNED_LOAD, ALIGNED_STORE, VEC_LOAD_BE, VEC_STORE_BE) + (vec_bswap32_const, vec_aligned_ld, vec_load_be_const) + (vec_load_be, vec_aligned_st, vec_store_be, _gcry_aes_sbox4_ppc8) + (_gcry_aes_ppc8_setkey, _gcry_aes_ppc8_prepare_decryption) + (aes_ppc8_encrypt_altivec, aes_ppc8_decrypt_altivec): New. + (_gcry_aes_ppc8_encrypt, _gcry_aes_ppc8_decrypt): Rewrite. + (_gcry_aes_ppc8_ocb_crypt): Comment out. + * cipher/rijndael.c [USE_PPC_CRYPTO] (_gcry_aes_ppc8_setkey) + (_gcry_aes_ppc8_prepare_decryption, _gcry_aes_ppc8_encrypt) + (_gcry_aes_ppc8_decrypt): New prototypes. + (do_setkey) [USE_PPC_CRYPTO]: Add setup for PowerPC AES. + (prepare_decryption) [USE_PPC_CRYPTO]: Ditto. + * configure.ac: Add 'rijndael-ppc.lo'. + (gcry_cv_ppc_altivec, gcry_cv_cc_ppc_altivec_cflags) + (gcry_cv_gcc_inline_asm_ppc_altivec) + (gcry_cv_gcc_inline_asm_ppc_arch_3_00): New checks. + +2019-08-26 Shawn Landden + + rijndael/ppc: implement single-block mode, and implement OCB block cipher + + commit 92f38a619b1cf759057e9cd532ae7c1d0331100f + * cipher/rijndael-ppc.c: New implementation of single-block mode, and + implementation of OCB mode. + + hwf: add detection of PowerPC hardware features. + + commit b4a3c76fabfa07c10fd18b90230f60b806ad9620 + * src/Makefile.am: PowerPC hardware detection. + * src/g10lib.h: Likewise. + * src/hwf-common.h: Likewise. + * src/hwf-ppc.c: Likewise. + * src/hwfeatures.c: Likewise. + * configure.ac: Likewise. + +2019-08-20 NIIBE Yutaka + + pkgconfig: Fix libgcrypt.pc. + + commit 761d12f140b77b907087590646651d9578b68a54 + * src/libgcrypt.pc.in (Cflags, Libs): Have flags. + +2019-08-16 NIIBE Yutaka + + build: Fix build with !HAVE_PTHREAD. + + commit 900647d96cb7806cd9b2de343e4a4bd66c073fba + * tests/t-lock.c [!HAVE_PTHREAD]: Buildable now. + + ecdsa: Fix unblinding too early. + + commit cdaeb86f067b94d9dff4235ade20dde6479d9bb8 + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Keep the blinding until + the last step. + +2019-08-12 NIIBE Yutaka + + build: Fix testapi.c to be buildable. + + commit 376124f86097414cf1f9cbbc17af935d30064c82 + * tests/testapi.c: Fix for xgcry_control. + +2019-08-08 NIIBE Yutaka + + dsa,ecdsa: Fix use of nonce, use larger one. + + commit 7c2943309d14407b51c8166c4dcecb56a3628567 + * cipher/dsa-common.c (_gcry_dsa_modify_k): New. + * cipher/pubkey-internal.h (_gcry_dsa_modify_k): New. + * cipher/dsa.c (sign): Use _gcry_dsa_modify_k. + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Likewise. + * cipher/ecc-gost.c (_gcry_ecc_gost_sign): Likewise. + +2019-08-07 NIIBE Yutaka + Ján JanÄár + + ecc: Add mitigation against timing attack. + + commit b9577f7c89b4327edc09f2231bc8b31521102c79 + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Add the order N to K. + * mpi/ec.c (_gcry_mpi_ec_mul_point): Compute with NBITS of P or larger. + +2019-08-07 NIIBE Yutaka + + dsa,ecdsa: Allocate secure memory for RFC6979 generation. + + commit 75c2fbc43d2f2cf5f4c60cb28001fda7324185c2 + * cipher/dsa-common.c (_gcry_dsa_gen_rfc6979_k): Use secure memory + just like _gcry_dsa_gen_k does. + +2019-07-22 NIIBE Yutaka + + build: Fix previous commit. + + commit 6126fc2f180a9b61064cea5c838d2ff7e0b7774a + + + build: Use {CFLAGS,CPPFLAGS,LDFLAGS}_FOR_BUILD for helper programs. + + commit 6d80f3f12dc2ff04b0eaa3ba29ee8725b6fb4f69 + * configure.ac (CC_FOR_BUILD): Use AX_CC_FOR_BUILD. + * cipher/Makefile.am (gost-s-box): Add + {CFLAGS,CPPFLAGS,LDFLAGS}_FOR_BUILD. + * doc/Makefile.am (yat2m): Likewise. + * m4/ax_cc_for_build.m4: New. + +2019-07-18 Jussi Kivilinna + + Fix use of AVX instruction in SHA1/SSSE3 assembly. + + commit 320ed47963032aab7aadd8aefa054b9a7725c9f7 + * cipher/sha1-ssse3-amd64.S: Replace 'vmovdqa' with 'movdqa' + instruction. + +2019-07-15 Werner Koch + + sexp: Improve argument checking of sexp parser. + + commit 1c2cecbb35e1a0760121d76c327651fe7b2b791a + * src/sexp.c (do_vsexp_sscan): Check for bad length in '%b'. + +2019-07-15 NIIBE Yutaka + + tests: t-mpi-point: Remove implementation dependent checks. + + commit 8a0bde8c211c70756a2d8aa46e1bcf1f6f89e55d + * tests/t-mpi-point.c (basic_ec_math): Remove comparing X and Y, + only comparison of Z is relevant, mathematically. + Remove useless check, where different values in equivalence class + exist. + (basic_ec_math_simplified): Likewise. + +2019-06-25 NIIBE Yutaka + + sexp: Support reading base64. + + commit ab57613f10ad57d2fec648017c18d7abb189863b + * configure.ac (NEED_GPG_ERROR_VERSION): Require libgpg-error >= 1.27. + * src/sexp.c (do_vsexp_sscan): Support data in base64 format. + * tests/t-sexp.c (check_extract_param): Add a test case. + +2019-06-24 NIIBE Yutaka + + ecc: Correctly return an error. + + commit b4a1114dc77617f0e772ddc4faf8820399b4354a + * cipher/ecc-ecdh.c (_gcry_ecc_get_algo_keylen): Return 0 for + unknow algorithm. + (_gcry_ecc_mul_point): Return GPG_ERR_UNSUPPORTED_ALGORITHM for + GCRY_ECC_CURVE448 for now. + Return GPG_ERR_UNKNOWN_ALGORITHM, otherwise. + +2019-06-21 NIIBE Yutaka + + tests: Fix the Curve25519 test. + + commit 6934711d572e13e9e78fb2c53bb119034b088c5a + * tests/t-cv25519.c (test_cv_x25519): Initialize SCALAR. + + ecc: Improve new ECDH API. + + commit a658c9ccc2c741f40b0b5cdbcd184cfb9a841d17 + * cipher/ecc-ecdh.c (_gcry_ecc_get_algo_keylen): New. + (_gcry_ecc_mul_point): Fill into the RESULT buffer, instead of + allocating new buffer. + * src/gcrypt-int.h: Change the API. + * src/gcrypt.h.in: Likewise. + * src/libgcrypt.def (gcry_ecc_get_algo_keylen): New. + * src/libgcrypt.vers (gcry_ecc_get_algo_keylen): New. + * src/visibility.c (gcry_ecc_get_algo_keylen): New. + * src/visibility.h (gcry_ecc_get_algo_keylen): New. + * tests/t-cv25519.c: Fix the use case. + +2019-06-20 NIIBE Yutaka + + ecc: X25519 API change to allow NULL for POINT. + + commit 6d77c2054ea0358fb4c6f59b4c91c673c0a83b03 + * cipher/ecc-ecdh.c (_gcry_ecc_mul_point): Allow NULL for point, + meaning G. + + ecc: Add an API for X25519 function as gcry_ecc_mul_point. + + commit ec8c2cdf977aa8d9ca5af0a9bd25aeb9190570b3 + * configure.ac: Add ecc-ecdh.lo. + * cipher/Makefile.am: Add ecc-ecdh.c. + * cipher/ecc-common.h (reverse_buffer): Expose. + * cipher/ecc-eddsa.c (reverse_buffer): Expose. + * cipher/ecc-curves.c (domain_parms): Fix as the errata of RFC. + * cipher/ecc-ecdh.c: New. + * cipher/ecc-misc.c (_gcry_ecc_mont_decodepoint): Fix for other curves + than Curve25519. + * src/gcrypt-int.h (_gcry_ecc_mul_point): New. + * src/gcrypt.h.in (enum gcry_ecc_curves): New. + (gcry_ecc_mul_point): new. + * src/libgcrypt.def (gcry_ecc_mul_point): New. + * src/libgcrypt.vers (gcry_ecc_mul_point): New. + * src/visibility.h (gcry_ecc_mul_point): New. + * src/visibility.c (gcry_ecc_mul_point): New. + * tests/t-cv25519.c (test_cv_hl): Rename from test_cv. + (test_cv_x25519): New. + (test_cv): Call both of test_cv_hl and test_cv_x25519. + +2019-06-05 Jussi Kivilinna + + tests/basic: add CTR mode carry overflow test vectors. + + commit 971d372f512ff6805d5b8b54e9ac1446f3f66643 + * tests/basic.c (check_ctr_cipher): Change tv structure 'plaintext' + and 'out' to pointers; Add counter carry overflow test vectors; Make + temporary buffer large enough for new test vectors. + + GCM: move look-up table to .data section and unshare between processes. + + commit a4c561aab1014c3630bc88faf6f5246fee16b020 + * cipher/cipher-gcm.c (ATTR_ALIGNED_64): New. + (gcmR): Move to 'gcm_table' structure. + (gcm_table): New structure for look-up table with counters before and + after. + (gcmR): New macro. + (prefetch_table): Handle input with length not multiple of 256. + (do_prefetch_tables): Modify pre- and post-table counters to unshare + look-up table pages between processes. + + AES: move look-up tables to .data section and unshare between processes. + + commit daedbbb5541cd8ecda1459d3b843ea4d92788762 + * cipher/rijndael-internal.h (ATTR_ALIGNED_64): New. + * cipher/rijndael-tables.h (encT): Move to 'enc_tables' structure. + (enc_tables): New structure for encryption table with counters before + and after. + (encT): New macro. + (dec_tables): Add counters before and after encryption table; Move + from .rodata to .data section. + (do_encrypt): Change 'encT' to 'enc_tables.T'. + (do_decrypt): Change '&dec_tables' to 'dec_tables.T'. + * cipher/cipher-gcm.c (prefetch_table): Make inline; Handle input + with length not multiple of 256. + (prefetch_enc, prefetch_dec): Modify pre- and post-table counters + to unshare look-up table pages between processes. + +2019-05-19 Jussi Kivilinna + + cipher/Makefile.am: add '-fcoverage-*' to instrumentation munging. + + commit c6ffa216976d80a13486b13f64d6776cdb8b6ccf + * cipher/Makefile.am: Remove '-fcoverage-*' flag for mixed asm/C + i386+amd64 implementations. + +2019-05-15 Jussi Kivilinna + + md: fix UBSAN warning. + + commit dad94696d9c48c18b59576776c7caa95123dfa1b + * cipher/md.c (gcry_md_list): Define 'context' as array of + PROPERLY_ALIGNED_TYPE. + (md_enable, _gcry_md_reset, _gcry_md_close, md_final, md_set_key) + (prepare_macpads, md_read, md_extract): Access md context through + 'gcry_md_list->context' pointer instead of 'gcry_md_list->context.c'. + + Disable instrumentation on mixed Intel SSE C/assembly implementations. + + commit d24dae4538dbbda9e6c72a34fae69682cfb2fef0 + * cipher/Makefile.am: Make 'tiger.o' and 'tiger.lo' depend on Makefile; + Add instrumentation option munging. + * cipher/cipher-gcm-intel-pcmul.c (ALWAYS_INLINE) + (NO_INSTRUMENT_FUNCTION, ASM_FUNC_ATTR, ASM_FUNC_ATTR_INLINE): New. + (reduction, gfmul_pclmul, gfmul_pclmul_aggr4, gfmul_pclmul_aggr8) + (gcm_lsh): Define with 'ASM_FUNC_ATTR_INLINE' instead of 'inline'. + (_gcry_ghash_setup_intel_pclmul, _gcry_ghash_intel_pclmul): Define with + 'ASM_FUNC_ATTR'. + * cipher/crc-intel-pcmul.c (ALWAYS_INLINE, NO_INSTRUMENT_FUNCTION) + (ASM_FUNC_ATTR, ASM_FUNC_ATTR_INLINE): New. + (crc32_reflected_bulk, crc32_reflected_less_than_16, crc32_bulk) + (crc32_less_than_16): Define with 'ASM_FUNC_ATTR_INLINE' instead of + 'inline'. + (_gcry_crc32_intel_pclmul, _gcry_crc24rfc2440_intel_pclmul): Define + with 'ASM_FUNC_ATTR'. + * cipher/rijndael-aesni.c (NO_INSTRUMENT_FUNCTION, ASM_FUNC_ATTR) + (ASM_FUNC_ATTR_INLINE, ASM_FUNC_ATTR_NOINLINE): New. + (aes_ocb_get_l, do_aesni_prepare_decryption, do_aesni_enc) + (do_aesni_dec, do_aesni_enc_vec4, do_aesni_dec_vec4, do_aesni_enc_vec8) + (do_aesni_dec_vec8, aesni_ocb_checksum): Define with + 'ASM_FUNC_ATTR_INLINE' instead of 'inline'. + (do_aesni_ctr, do_aesni_ctr_4, do_aesni_ctr_8): Define wtih + 'ASM_FUNC_ATTR_INLINE'. + (aesni_ocb_enc, aesni_ocb_dec): Define with 'ASM_FUNC_ATTR_NOINLINE' + instead of 'NO_INLINE'. + (_gcry_aes_aesni_do_setkey, _gcry_aes_aesni_prepare_decryption) + (_gcry_aes_aesni_encrypt, _gcry_aes_aesni_cfg_enc) + (_gcry_aes_aesni_cbc_enc, _gcry_aes_aesni_ctr_enc) + (_gcry_aes_aesni_decrypt, _gcry_aes_aesni_cfb_dec) + (_gcry_aes_aesni_cbc_dec, _gcry_aes_aesni_ocb_crypt) + (_gcry_aes_aesni_ocb_auth, _gcry_aes_aesni_xts_enc) + (_gcry_aes_aesni_xts_dec, _gcry_aes_aesni_xts_crypt): Define with + 'ASM_FUNC_ATTR'. + * cipher/rijndael-ssse3-amd64.c (ALWAYS_INLINE, NO_INSTRUMENT_FUNCTION) + (ASM_FUNC_ATTR, ASM_FUNC_ATTR_INLINE): New. + (aes_ocb_get_l, do_ssse3_prepare_decryption, do_vpaes_ssse3_enc) + (do_vpaes_ssse3_dec): Define with 'ASM_FUNC_ATTR_INLINE' instead of + 'inline'. + (_gcry_aes_ssse3_do_setkey, _gcry_aes_ssse3_prepare_decryption) + (_gcry_aes_ssse3_encrypt, _gcry_aes_ssse3_cfb_enc) + (_gcry_aes_ssse3_cbc_enc, _gcry_aes_ssse3_ctr_enc) + (_gcry_aes_ssse3_decrypt, _gcry_aes_ssse3_cfb_dec) + (_gcry_aes_ssse3_cbc_dec, ssse3_ocb_enc, ssse3_ocb_dec) + (_gcry_aes_ssse3_ocb_crypt, _gcry_aes_ssse3_ocb_auth): Define with + 'ASM_FUNC_ATTR'. + * cipher/sha1-intel-shaext.c (NO_INSTRUMENT_FUNCTION) + (ASM_FUNC_ATTR): New. + (_gcry_sha1_transform_intel_shaext): Define with 'ASM_FUNC_ATTR'. + * cipher/sha256-intel-shaext.c (NO_INSTRUMENT_FUNCTION) + (ASM_FUNC_ATTR): New. + (_gcry_sha256_transform_intel_shaext): Define with 'ASM_FUNC_ATTR'. + * configure.ac (ENABLE_INSTRUMENTATION_MUNGING): New. + + tests/basic: fix signed interger overflow. + + commit 3c7ff6bd1c40d5216d6c12b6b28f77fd1a57baa7 + * tests/basic.c (check_ocb_cipher_largebuf_split): Cast to unsigned + when generating buffer values. + +2019-05-14 Jussi Kivilinna + + tests: do not use GCC variadic macro extension for xgcry_control. + + commit be567cb5dd629e9aa22d81b29d4326e5aa97efa7 + * tests/t-common.h (xgcry_control): Use doubly nested parenthesis for + passing arguments for gcry_control instead of GCC specific variadic + macro extension. + * tests/aeswrap.c: Change xgcry_control to use doubly nested + parenthesis. + * tests/basic.c: Ditto. + * tests/bench-slope.c: Ditto. + * tests/benchmark.c: Ditto. + * tests/curves.c: Ditto. + * tests/dsa-rfc6979.c: Ditto. + * tests/fips186-dsa: Ditto. + * tests/fipsdrv.c: Ditto. + * tests/fipsrngdrv.c: Ditto. + * tests/gchash.c: Ditto. + * tests/hashtest.c: Ditto. + * tests/hmac.c: Ditto. + * tests/keygen.c: Ditto. + * tests/keygrip.c: Ditto. + * tests/mpitests.c: Ditto. + * tests/pkbench.c: Ditto. + * tests/pkcs1v2.c: Ditto. + * tests/prime.c: Ditto. + * tests/pubkey.c: Ditto. + * tests/random.c: Ditto. + * tests/rsacvt.c: Ditto. + * tests/t-convert.c: Ditto. + * tests/t-cv25519.c: Ditto. + * tests/t-ed25519.c: Ditto. + * tests/t-kdf.c: Ditto. + * tests/t-lock.c: Ditto. + * tests/t-mpi-bit.c: Ditto. + * tests/t-mpi-point.c: Ditto. + * tests/t-secmem.c: Ditto. + * tests/t-sexp.c: Ditto. + * tests/version.c: Ditto. + +2019-05-10 Jussi Kivilinna + + tests/basic: mark CFB and CFB8 as stream block cipher modes. + + commit 34e9306a66b47785ddbab6594ae4c23581d35b5a + * tests/basic.c (get_algo_mode_blklen): Return '1' for CFB and CFB8. + +2019-05-09 Jussi Kivilinna + + Fix message digest final function for MD4, MD5 and RMD160. + + commit 15592cd52f543aadb2fab8f6c112c68075309ad6 + * cipher/md4.c (md4_final): Use buffer offset '64 + 56' for bit count + on 'need one extra block' path. + * cipher/md5.c (md5_final): Ditto. + * cipher/rmd160.c (rmd160_final): Ditto. + * tests/basic.c (check_one_md_final): New. + (check_digest): Add new '*' test vectors and handle them with + check_one_md_final. + +2019-05-06 Dmitry Eremin-Solenikov + + Fix carry overflow in Stribog in 512-bit addition. + + commit da6cd4fea30f79cf9d8f9b2f1c6daf3aea39fa9c + * cipher/stribog.c (transform_bits): properly calculate carry flag + * tests/basic.c (check_digests): add two more test cases + +2019-04-27 Jussi Kivilinna + + Add support for explicit_memset. + + commit 71b0eb3fb75d2e6bbd86df055dc667b2debab0c1 + * configure.ac: Add function check for 'explicit_memset'. + * src/misc.c (_gcry_fast_wipememory, _gcry_fast_wipememory2): Use + explicit_memset if available. + + Fix CFI_PUSH/CFI_POP redefine build warning with AMD64 MPI. + + commit 78b1047eded8d5f8a13162d13160fce1809f6ee4 + * mpi/amd64/func_abi.h: Move CFI macros into [__x86_64__] block. + * mpi/i386/syntax.h: Move CFI macros into [__i386__] block. + + Enable four block aggregated GCM Intel PCLMUL implementation on i386. + + commit a6e7c411e5f67a9473675ca8d49017a4d13a8d3e + * cipher/cipher-gcm-intel-pclmul.c (reduction): Change "%%xmm7" to + "%%xmm5". + (gfmul_pclmul_aggr4): Move outside [__x86_64__] block; Remove usage of + XMM8-XMM15 registers; Do not preload H-values and be_mask to reduce + register usage for i386. + (_gcry_ghash_setup_intel_pclmul): Enable calculation of H2, H3 and H4 + on i386. + (_gcry_ghash_intel_pclmul): Adjust to above gfmul_pclmul_aggr4 + changes; Move 'aggr4' code path outside [__x86_64__] block. + + Prefetch GCM look-up tables. + + commit 1374254c2904ab5b18ba4a890856824a102d4705 + * cipher/cipher-gcm.c (prefetch_table, do_prefetch_tables) + (prefetch_tables): New. + (ghash_internal): Call prefetch_tables. + + Optimizations for generic table-based GCM implementations. + + commit ecd02cdd61e8c690f48637656f0e1e08b750fe30 + * cipher/cipher-gcm.c [GCM_TABLES_USE_U64] (do_fillM): Precalculate + M[32..63] values. + [GCM_TABLES_USE_U64] (do_ghash): Split processing of two 64-bit halfs + of the input to two separate loops; Use precalculated M[] values. + [GCM_USE_TABLES && !GCM_TABLES_USE_U64] (do_fillM): Precalculate + M[64..127] values. + [GCM_USE_TABLES && !GCM_TABLES_USE_U64] (do_ghash): Use precalculated + M[] values. + [GCM_USE_TABLES] (bshift): Avoid conditional execution for mask + calculation. + * cipher/cipher-internal.h (gcry_cipher_handle): Double gcm_table size. + +2019-04-26 Jussi Kivilinna + + Optimizations for GCM Intel/PCLMUL implementation. + + commit af5f3fb08674608acf6617ea622ed0b9a2ee77a5 + * cipher/cipher-gcm-intel-pclmul.c (reduction): New. + (glmul_pclmul): Include shifting to left into pclmul operations; Use + 'reduction' helper function. + [__x86_64__] (gfmul_pclmul_aggr4): Reorder instructions and adjust + register usage to free up registers; Use 'reduction' helper function; + Include shifting to left into pclmul operations; Moving load H values + and input from caller into this function. + [__x86_64__] (gfmul_pclmul_aggr8): New. + (gcm_lsh): New. + (_gcry_ghash_setup_intel_pclmul): Left shift H values to left by + one; Preserve XMM6-XMM15 registers on WIN64. + (_gcry_ghash_intel_pclmul) [__x86_64__]: Use 8 block aggregated + reduction function. + + Move data pointer macro for 64-bit ARM assembly to common header. + + commit b9be297bb8eba7a09fa8413261de1587adcfd381 + * cipher/asm-common-aarch64.h (GET_DATA_POINTER): New. + * cipher/chacha20-aarch64.S (GET_DATA_POINTER): Remove. + * cipher/cipher-gcm-armv8-aarch64-ce.S (GET_DATA_POINTER): Remove. + * cipher/crc-armv8-aarch64-ce.S (GET_DATA_POINTER): Remove. + * cipher/rijndael-armv8-aarch64-ce.S (GET_DATA_POINTER): Remove. + * cipher/sha1-armv8-aarch64-ce.S (GET_DATA_POINTER): Remove. + * cipher/sha256-armv8-aarch64-ce.S (GET_DATA_POINTER): Remove. + + Add CFI unwind assembly directives for 64-bit ARM assembly. + + commit 5a2a96a63517838e04f9fc0fb2d932fac5124b8a + * cipher/asm-common-aarch64.h (CFI_STARTPROC, CFI_ENDPROC) + (CFI_REMEMBER_STATE, CFI_RESTORE_STATE, CFI_ADJUST_CFA_OFFSET) + (CFI_REL_OFFSET, CFI_DEF_CFA_REGISTER, CFI_REGISTER, CFI_RESTORE) + (DW_REGNO_SP, DW_SLEB128_7BIT, DW_SLEB128_28BIT, CFI_CFA_ON_STACK) + (CFI_REG_ON_STACK): New. + * cipher/camellia-aarch64.S: Add CFI directives. + * cipher/chacha20-aarch64.S: Add CFI directives. + * cipher/cipher-gcm-armv8-aarch64-ce.S: Add CFI directives. + * cipher/crc-armv8-aarch64-ce.S: Add CFI directives. + * cipher/rijndael-aarch64.S: Add CFI directives. + * cipher/rijndael-armv8-aarch64-ce.S: Add CFI directives. + * cipher/sha1-armv8-aarch64-ce.S: Add CFI directives. + * cipher/sha256-armv8-aarch64-ce.S: Add CFI directives. + * cipher/twofish-aarch64.S: Add CFI directives. + * mpi/aarch64/mpih-add1.S: Add CFI directives. + * mpi/aarch64/mpih-mul1.S: Add CFI directives. + * mpi/aarch64/mpih-mul2.S: Add CFI directives. + * mpi/aarch64/mpih-mul3.S: Add CFI directives. + * mpi/aarch64/mpih-sub1.S: Add CFI directives. + * mpi/asm-common-aarch64.h: Include "../cipher/asm-common-aarch64.h". + (ELF): Remove. + + Add 64-bit ARMv8/CE PMULL implementation of CRC. + + commit 14c8a593ede42f51f567ed7ba77b53124151aa38 + * cipher/Makefile.am: Add 'crc-armv8-ce.c' and + 'crc-armv8-aarch64-ce.S'. + * cipher/asm-common-aarch64.h [HAVE_GCC_ASM_CFI_DIRECTIVES]: Add CFI + helper macros. + * cipher/crc-armv8-aarch64-ce.S: New. + * cipher/crc-armv8-ce.c: New. + * cipher/crc.c (USE_ARM_PMULL): New. + (CRC_CONTEXT) [USE_ARM_PMULL]: Add 'use_pmull'. + [USE_ARM_PMULL] (_gcry_crc32_armv8_ce_pmull) + (_gcry_crc24rfc2440_armv8_ce_pmull): New prototypes. + (crc32_init, crc32rfc1510_init, crc24rfc2440_init): Enable ARM PMULL + implementations if supported by HW features. + (crc32_write, crc24rfc2440_write) [USE_ARM_PMULL]: Use ARM PMULL + implementations if enabled. + * configure.ac: Add 'crc-armv8-ce.lo' and 'crc-armv8-aarch64-ce.lo'. + +2019-04-18 Jussi Kivilinna + + mpi: make stack unwinding work at i386 mpi functions. + + commit b878a986f3ab2c35aff89c7f66f137a91542ed5b + * mpi/i386/syntax.h: Include 'config.h'. + (CFI_STARTPROC, CFI_ENDPROC, CFI_ADJUST_CFA_OFFSET, CFI_REL_OFFSET) + (CFI_RESTORE, CFI_PUSH, CFI_POP): New. + * mpi/i386/mpih-add1.S: Add CFI directives. + * mpi/i386/mpih-lshift.S: Add CFI directives. + * mpi/i386/mpih-mul1.S: Add CFI directives. + * mpi/i386/mpih-mul2.S: Add CFI directives. + * mpi/i386/mpih-mul3.S: Add CFI directives. + * mpi/i386/mpih-rshift.S: Add CFI directives. + * mpi/i386/mpih-sub1.S: Add CFI directives. + + hwf-x86: make stack unwinding work at i386 cpuid functions. + + commit 0bd18e8bf7d67072f8c77352140b4ed4cfde3c6c + * src/hwf-x86.c (FORCE_FUNC_FRAME_POINTER): New. + [__i386__] (is_cpuid_available): Force use of stack frame pointer as + inline assembly modifies stack register; Add 'memory' constraint for + inline assembly. + [__i386__] (get_cpuid): Avoid push/pop instruction when preserving + %ebx register over cpuid. + + Limit and document Blowfish key lengths to 8-576 bits. + + commit 3546599e5578f89f9e77b08bf599f9c44b23da5f + * cipher/blowfish.c (BLOWFISH_KEY_MIN_BITS) + (BLOWFISH_KEY_MAX_BITS): New. + (do_bf_setkey): Check input key length to MIN_BITS and MAX_BITS. + * doc/gcrypt.texi: Update supported Blowfish key lengths. + * tests/basic.c (check_ecb_cipher): New, with Blowfish test vectors + for different key lengths. + (check_cipher_modes): Call 'check_ecb_cipher'. + +2019-04-16 Jussi Kivilinna + + Add CFI unwind assembly directives for AMD64 assembly. + + commit d11ae95d05dc39ec6b825d1109afadd964589880 + * configure.ac (gcry_cv_gcc_asm_cfi_directives): New. + * cipher/asm-common-amd64.h (ADD_RIP, CFI_STARTPROC, CFI_ENDPROC) + (CFI_REMEMBER_STATE, CFI_RESTORE_STATE, CFI_ADJUST_CFA_OFFSET) + (CFI_REL_OFFSET, CFI_DEF_CFA_REGISTER, CFI_REGISTER, CFI_RESTORE) + (CFI_PUSH, CFI_POP, CFI_POP_TMP_REG, CFI_LEAVE, DW_REGNO) + (DW_SLEB128_7BIT, DW_SLEB128_28BIT, CFI_CFA_ON_STACK) + (CFI_REG_ON_STACK): New. + (ENTER_SYSV_FUNCPARAMS_0_4, EXIT_SYSV_FUNC): Add CFI directives. + * cipher/arcfour-amd64.S: Add CFI directives. + * cipher/blake2b-amd64-avx2.S: Add CFI directives. + * cipher/blake2s-amd64-avx.S: Add CFI directives. + * cipher/blowfish-amd64.S: Add CFI directives. + * cipher/camellia-aesni-avx-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/camellia-aesni-avx2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/cast5-amd64.S: Add CFI directives. + * cipher/chacha20-amd64-avx2.S: Add CFI directives. + * cipher/chacha20-amd64-ssse3.S: Add CFI directives. + * cipher/des-amd64.S: Add CFI directives. + * cipher/rijndael-amd64.S: Add CFI directives. + * cipher/rijndael-ssse3-amd64-asm.S: Add CFI directives. + * cipher/salsa20-amd64.S: Add CFI directives; Use 'asm-common-amd64.h'. + * cipher/serpent-avx2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/serpent-sse2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha1-avx-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha1-avx-bmi2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha1-avx2-bmi2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha1-ssse3-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha256-avx-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha256-avx2-bmi2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha256-ssse3-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha512-avx-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha512-avx2-bmi2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/sha512-ssse3-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/twofish-amd64.S: Add CFI directives. + * cipher/twofish-avx2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * cipher/whirlpool-sse2-amd64.S: Add CFI directives; Use + 'asm-common-amd64.h'. + * mpi/amd64/func_abi.h: Include 'config.h'. + (CFI_STARTPROC, CFI_ENDPROC, CFI_ADJUST_CFA_OFFSET, CFI_REL_OFFSET) + (CFI_RESTORE, CFI_PUSH, CFI_POP): New. + (FUNC_ENTRY, FUNC_EXIT): Add CFI directives. + +2019-04-15 Jussi Kivilinna + + twofish-amd64: do not use xchg instruction. + + commit 0903b215ef5a18332b740a24e6e2bfbed9e1d97b + * cipher/twofish-amd64.S (g1g2_3): Swap ab and cd registers using + 'movq' instructions instead of 'xchgq'. + +2019-04-09 Jussi Kivilinna + + Use FreeBSD's elf_aux_info for detecting ARM HW features. + + commit 2ffc689d4757f31f1e2c4961b94b0b0c8dc302b7 + * configure.ac: Add function check for 'elf_aux_info'. + * src/hwf-arm.c [HAVE_ELF_AUX_INFO]: Include 'sys/auxv.h'. + [HAVE_ELF_AUX_INFO && !HAVE_GETAUXVAL] (HAVE_GETAUXVAL) + (getauxval): New. + +2019-04-08 Jussi Kivilinna + + Use getauxval system function for detecting ARM HW features. + + commit 6812a2c5bd2d9129bfdf34f3daf89cd8543ed8e5 + * configure.ac: Add header check for 'sys/auxv.h'; Add function check + for 'getauxval'. + * src/hwf-arm.c [HAVE_SYS_AUXV_H && HAVE_GETAUXVAL]: Include + 'sys/auxv.h'. + (HAS_SYS_AT_HWCAP): Enable AT_HWCAP if have 'getauxval' in addition of + __linux__. + (AT_HWCAP, AT_HWCAP2, HWCAP_NEON, HWCAP2_AES, HWCAP2_PMULL) + (HWCAP2_SHA1, HWCAP2_SHA2, HWCAP_ASIMD, HWCAP_AES) + (HWCAP_PMULL, HWCAP_SHA1, HWCAP_SHA2): Define these macros only if not + already defined. + (get_hwcap) [HAVE_SYS_AUXV_H && HAVE_GETAUXVAL]: Use 'getauxval' to + fetch HW capability flags. + + Disable SM3 in FIPS mode. + + commit 04a6c3c7482dd1ecb5113a049b1765b0d5f212fb + * cipher/sm3.h (_gcry_digest_spec_sm3): Set flags.fips to zero. + +2019-04-07 Jussi Kivilinna + + Tune SHA-512/AVX2 and SHA-256/AVX2 implementations. + + commit 478581c5107ae75281c54e56cdcef5165f3155ca + * cipher/sha256-avx2-bmi2-amd64.S (ONE_ROUND_PART1, ONE_ROUND_PART2) + (ONE_ROUND): New round function. + (FOUR_ROUNDS_AND_SCHED, FOUR_ROUNDS): Use new round function. + (_gcry_sha256_transform_amd64_avx2): Exit early if number of blocks is + zero; Writing XFER to stack earlier and handle XREF writing in + FOUR_ROUNDS_AND_SCHED. + * cipher/sha512-avx2-bmi2-amd64.S (MASK_YMM_LO, MASK_YMM_LOx): New. + (ONE_ROUND_PART1, ONE_ROUND_PART2, ONE_ROUND): New round function. + (FOUR_ROUNDS_AND_SCHED, FOUR_ROUNDS): Use new round function. + (_gcry_sha512_transform_amd64_avx2): Writing XFER to stack earlier and + handle XREF writing in FOUR_ROUNDS_AND_SCHED. + +2019-04-05 Jussi Kivilinna + + Add SHA512/224 and SHA512/256 algorithms. + + commit a3683b6f623189a4b65bb584bb9e65e3ad7b3139 + * cipher/mac-hmac.c (map_mac_algo_to_md): Add mapping for SHA512/224 + and SHA512/256. + (_gcry_mac_type_spec_hmac_sha512_256) + (_gcry_mac_type_spec_hmac_sha512_224): New. + * cipher/mac-internal.h (_gcry_mac_type_spec_hmac_sha512_256) + (_gcry_mac_type_spec_hmac_sha512_224): New. + * cipher/mac.c (mac_list, mac_list_algo101): Add SHA512/224 and + SHA512/256. + * cipher/md.c (digest_list, digest_list_algo301) + (prepare_macpads): Ditto. + * cipher/sha512.c (run_selftests): Ditto. + (sha512_init_common): Move common initialization here. + (sha512_init, sha384_init): Use common initialization function. + (sha512_224_init, sha512_256_init, _gcry_sha512_224_hash_buffer) + (_gcry_sha512_224_hash_buffers, _gcry_sha512_256_hash_buffer) + (_gcry_sha512_256_hash_buffers, selftests_sha512_224) + (selftests_sha512_256, sha512_224_asn, oid_spec_sha512_224) + (_gcry_digest_spec_sha512_224, sha512_256_asn, oid_spec_sha512_256) + (_gcry_digest_spec_sha512_256): New. + * doc/gcrypt.texi: Add SHA512/224 and SHA512/256; Add missing + HMAC-BLAKE2s and HMAC-BLAKE2b. + * src/cipher.h (_gcry_digest_spec_sha512_224) + (_gcry_digest_spec_sha512_256): New. + * src/gcrypt.h.in (GCRY_MD_SHA512_256, GCRY_MD_SHA512_224): New. + (GCRY_MAC_HMAC_SHA512_256, GCRY_MAC_HMAC_SHA512_224): New. + * tests/basic.c (check_digests): Add SHA512/224 and SHA512/256 + test vectors. + + Remove extra buffer flush at begining of digest final functions. + + commit c6055aaccac86e1ca8a9d35c980d7abbacf2a9ff + * cipher/md2.c (md2_final): Remove _gcry_md_block_write flush call + from entry. + * cipher/md4.c (md4_final): Ditto. + * cipher/md5.c (md5_final): Ditto. + * cipher/rmd160.c (rmd160_final): Ditto. + * cipher/sha1.c (sha1_final): Ditto. + * cipher/sha256.c (sha256_final): Ditto. + * cipher/sha512.c (sha512_final): Ditto. + * cipher/sm3.c (sm3_final): Ditto. + * cipher/stribog.c (stribog_final): Ditto. + * cipher/tiger.c (tiger_final): Ditto. + + Optimizations for digest final functions. + + commit e76cd0e2b1f6025c1319576a5848815d1d231aeb + * cipher/md4.c (md4_final): Avoid byte-by-byte buffer setting when + padding; Merge extra and last block processing. + * cipher/md5.c (md5_final): Ditto. + * cipher/rmd160.c (rmd160_final): Ditto. + * cipher/sha1.c (sha1_final): Ditto. + * cipher/sha256.c (sha256_final): Ditto. + * cipher/sm3.c (sm3_final): Ditto. + * cipher/tiger.c (tiger_final): Ditto. + * cipher/sha512.c (sha512_final): Avoid byte-by-byte buffer setting + when padding. + * cipher/stribog.c (stribog_final): Ditto. + * cipher/whirlpool.c (whirlpool_final): Ditto. + + tests/basic: add hash test for small block sizes. + + commit c54b1c96c644c941f3eb3d2a09432b82f25b6ff1 + * tests/basic.c (check_one_md): Compare hashing buffers sizes from 1 to + 129 as full buffer input and byte-by-byte input. + + Burn stack in transform functions for SHA2 AMD64 implementations. + + commit 74ef3ecbf94e704975e238a99c0e0480cebf46ac + * cipher/sha256-avx-amd64.S: Burn stack inside transform functions. + * cipher/sha256-avx2-bmi2-amd64.S: Ditto. + * cipher/sha256-ssse3-amd64.S: Ditto. + * cipher/sha512-avx-amd64.S: Ditto. + * cipher/sha512-avx2-bmi2-amd64.S: Ditto. + * cipher/sha512-ssse3-amd64.S: Ditto. + + Burn stack in transform functions for SHA1 AMD64 implementations. + + commit f3d4bd90662faaedd37ce0dae1f9e7f91748e91e + * cipher/sha1-avx-amd64.S: Burn stack inside transform functions. + * cipher/sha1-avx-bmi2-amd64.S: Ditto. + * cipher/sha1-avx2-bmi2-amd64.S: Ditto. + * cipher/sha1-ssse3-amd64.S: Ditto. + + Add AVX2/BMI2 implementation of SHA1. + + commit b982900bfe6403e95a157271d8d811c9c573af9e + * cipher/Makefile.am: Add 'sha1-avx2-bmi2-amd64.S'. + * cipher/hash-common.h (MD_BLOCK_CTX_BUFFER_SIZE): New. + (gcry_md_block_ctx): Change buffer length to MD_BLOCK_CTX_BUFFER_SIZE. + * cipher/sha1-avx-amd64.S: Add missing .size for transform function. + * cipher/sha1-ssse3-amd64.S: Add missing .size for transform function. + * cipher/sha1-avx-bmi2-amd64.S: Add missing .size for transform + function; Tweak implementation for small ~1% speed increase. + * cipher/sha1-avx2-bmi2-amd64.S: New. + * cipher/sha1.c (USE_AVX2, _gcry_sha1_transform_amd64_avx2_bmi2) + (do_sha1_transform_amd64_avx2_bmi2): New. + (sha1_init) [USE_AVX2]: Enable AVX2 implementation if supported by + HW features. + (sha1_final): Merge processing of two last blocks when extra block is + needed. + +2019-03-31 Jussi Kivilinna + + blowfish: add three rounds parallel handling to generic C implementation + + commit ced7508c857c0cc37da2299a393e5b167dd28e54 + * cipher/blowfish.c (BLOWFISH_ROUNDS): Remove. + [BLOWFISH_ROUNDS != 16] (function_F): Remove. + (F): Replace big-endian and little-endian version with single + endian-neutral version. + (R3, do_encrypt_3, do_decrypt_3): New. + (_gcry_blowfish_ctr_enc, _gcry_blowfish_cbc_dec) + (_gcry_blowfish_cfb_dec): Use new three block functions. + + cast5: add three rounds parallel handling to generic C implementation. + + commit 4ec566b3689eff4a712eacfcbb4161eb243bb1df + * cipher/cast5.c (do_encrypt_block_3, do_decrypt_block_3): New. + (_gcry_cast5_ctr_enc, _gcry_cast5_cbc_dec, _gcry_cast5_cfb_dec): Use + new three block functions. + + cast5: read Kr four blocks at time and shift for current round. + + commit 8a0e68be1020d0c359bf8191159ac1ebe32a5aa0 + * cipher/cast5.c (do_encrypt_block, do_decrypt_block): Read Kr as + 32-bit words instead of bytes and shift value for each round. + + Add helper function for adding value to cipher block. + + commit 0fe918fa897cca9e01cbdb80d14106cfe5af680e + * cipher/cipher-internal.h (cipher_block_add): New. + * cipher/blowfish.c (_gcry_blowfish_ctr_enc): Use new helper function + for CTR block increment. + * cipher/camellia-glue.c (_gcry_camellia_ctr_enc): Ditto. + * cipher/cast5.c (_gcry_cast5_ctr_enc): Ditto. + * cipher/cipher-ctr.c (_gcry_cipher_ctr_encrypt): Ditto. + * cipher/des.c (_gcry_3des_ctr_enc): Ditto. + * cipher/rijndael.c (_gcry_aes_ctr_enc): Ditto. + * cipher/serpent.c (_gcry_serpent_ctr_enc): Ditto. + * cipher/twofish.c (_gcry_twofish_ctr_enc): Ditto. + +2019-03-28 Jussi Kivilinna + + Optimize OCB set_key and set_nonce. + + commit efd700e31dc8e1e386d367d1b682000977e0c810 + * cipher/cipher-ocb.c (double_block): Change to input/output + host-endian block instead of big-endian buffer. + (double_block_cpy): Remove. + (bit_copy): Use fixed length copy and 'u64' for calculations. + (ocb_get_L_big): Handle block endian conversions for double_block. + (_gcry_cipher_ocb_setkey): Handle block endian conversions for + double_block. + (_gcry_cipher_ocb_set_nonce): Set full length of 'ktop' to zero; Drop + length parameter for bit_copy. + + AES-NI/OCB: Optimize last and first key XORing. + + commit eacbd59b1333b95858886999c8049e04bf72ad74 + * cipher/rijndael-aesni.c (aesni_ocb_enc, aesni_ocb_dec) + [__x86_64__]: Reorder and mix first and last key XORing with OCB offset + XOR operations. + + AES-NI/OCB: Perform checksumming inline with encryption. + + commit e924ce456d5728a81c148de4a6eb23373cb70ca0 + * cipher/rijndael-aesni.c (aesni_ocb_enc): Remove call to + 'aesni_ocb_checksum', instead perform checksumming inline with offset + calculations. + +2019-03-27 Jussi Kivilinna + + AES-NI/OCB: Use stack for temporary storage. + + commit b82dbbedf027327e0b4444a01edb045f51c4152b + * cipher/rijndael-aesni.c (aesni_ocb_enc, aesni_ocb_dec): Use stack + allocated 'tmpbuf' instead of output buffer as temporary storage. + +2019-03-26 Jussi Kivilinna + + tests/basic: add large buffer testing for ciphers. + + commit cabeebfc1179c8f5982834a8cbce02c55b3468e2 + * tests/basic.c (check_one_cipher_core): Allocate buffers from heap. + (check_one_cipher): Add testing with large buffer (~65 KiB) in addition + to medium size buffer (~2 KiB). + + chacha20-poly1305: fix wrong en/decryption on large input buffers. + + commit 049376470b31832d3331fc0037d273b4147e9d38 + * cipher/chacha20.c (_gcry_chacha20_poly1305_encrypt) + (_gcry_chacha20_poly1305_decrypt): Correctly use 'currlen' for chacha20 + on the non-stitched code path. + +2019-03-24 Jussi Kivilinna + + doc: add mention about aligning data to cachelines for best performance. + + commit bb03edcbba95e06686188957a65c1967ee07cd6a + * doc/gcrypt.text: Add mention about aligning data to cachelines for + best performance. + + random-drbg: do not use calloc for zero ctr. + + commit 5a20151213c2e496513c541c36e4ebd086b20be9 + * random/random-drbg.c (DRBG_CTR_NULL_LEN): Move to 'constants' + section. + (drbg_state_s): Remove 'ctr_null' member. + (drbg_ctr_generate): Add 'drbg_ctr_null'. + (drbg_sym_fini, drbg_sym_init): Remove 'drbg->ctr_null' usage. + +2019-03-23 Jussi Kivilinna + + Add ARMv7/NEON accelerated GCM implementation. + + commit 2445cf7431fab921f6c1870da7084ee698992064 + * cipher/Makefile.am: Add 'cipher-gcm-armv7-neon.S'. + * cipher/cipher-gcm-armv7-neon.S: New. + * cipher/cipher-gcm.c [GCM_USE_ARM_NEON] (_gcry_ghash_setup_armv7_neon) + (_gcry_ghash_armv7_neon, ghash_setup_armv7_neon) + (ghash_armv7_neon): New. + (setupM) [GCM_USE_ARM_NEON]: Use armv7/neon implementation if have + HWF_ARM_NEON. + * cipher/cipher-internal.h (GCM_USE_ARM_NEON): New. + + Use memset instead of setting buffers byte by byte. + + commit 6f2391d2df029b0e1a4e5dde17c3d97cc594a1c7 + * cipher/cipher-ccm.c (do_cbc_mac): Replace buffer setting loop with memset call. + * cipher/cipher-gcm.c (do_ghash_buf): Ditto. + * cipher/poly1305.c (poly1305_final): Ditto. + + Use buf_cpy instead of copying buffers byte by byte. + + commit 4db6d8796c0d95ab89e9ad69336509b604b957cd + * cipher/bufhelp.h (buf_cpy): Skip memcpy if length is zero. + * cipher/cipher-ccm.c (do_cbc_mac): Replace buffer copy loops with buf_cpy call. + * cipher/cipher-cmac.c (_gcry_cmac_write): Ditto. + * cipher/cipher-ocb.c (_gcry_cipher_ocb_authenticate): Ditto. + + Reduce overhead on generic hash write function. + + commit e76617cbab018dd8f41fd6b4ec6740b5303f7e13 + * cipher/hash-common.c (_gcry_md_block_write): Remove recursive + function call; Use buf_cpy for copying buffers; Burn stack only once. + + sha1-avx: use vmovdqa instead of movdqa. + + commit f8d14df1abd645c3279b14da43b4a7983d87f89f + * cipher/sha1-avx-amd64.S: Replace 'movdqa' with 'vmovdqa'. + * cipher/sha1-avx-bmi2-amd64.S: Replace 'movdqa' with 'vmovdqa'. + + doc/gcrypt.texi: update HW feature list. + + commit 7abf65da84c7106250a5ed2de78b05610cf251f4 + * doc/gcrypt.texi: Update FW feature list. + +2019-03-20 Daniel Kahn Gillmor + + ecc: Adjust debugging output. + + commit 54db6a4b44124ed7e95897174f32262482b4b0cb + * cipher/ecc.c (ecc_check_secret_key): Adjust debugging output to use + full column titles. + +2019-02-25 NIIBE Yutaka + + fips: Only test check_binary_integrity when fips_mode is enabled. + + commit ad133fc79757236359252e92244fe16e9adb45a3 + * src/fips.c (_gcry_fips_run_selftests): Check the status of fips_mode + before calling check_binary_integrity. + +2019-02-07 Jussi Kivilinna + + Add 2-way path for SSSE3 version of ChaCha20. + + commit d455068988e5779b0200c51415ddab6b51e12dc4 + * cipher/chacha20-amd64-ssse3.S (_gcry_chacha20_amd64_ssse3_blocks1) + (_gcry_chacha20_poly1305_amd64_ssse3_blocks1): Add 2-way code paths. + * cipher/chacha20.c (_gcry_chacha20_poly1305_encrypt): Add + preprosessing of 2 blocks with SSSE3. + +2019-01-27 Jussi Kivilinna + + Do not precalculate OCB offset L0+L1+L0. + + commit afab94d222425ecb838eb56cb0723bdaf3e5de36 + * cipher/cipher-internal.h (gcry_cipher_handle): Remove OCB L0L1L0. + * cipher/cipher-ocb.c (_gcry_cipher_ocb_setkey): Ditto. + * cipher/rijndael-aesni.c (aesni_ocb_enc, aesni_ocb_dec) + (_gcry_aes_aesni_ocb_auth): Replace L0L1L0 use with L1. + + Calculate OCB L-tables when setting key instead of when setting nonce. + + commit c15409c49993166ab1325d45360b3a8fe72a5556 + * cipher/cipher-internal.h (gcry_cipher_handle): Mark areas of + u_mode.ocb that are and are not cleared by gcry_cipher_reset. + (_gcry_cipher_ocb_setkey): New. + * cipher/cipher-ocb.c (_gcry_cipher_ocb_set_nonce): Split + L-table generation to ... + (_gcry_cipher_ocb_setkey): ... this new function. + * cipher/cipher.c (cipher_setkey): Add handling for OCB mode. + (cipher_reset): Do not clear L-values for OCB mode. + + chacha20-amd64-avx2: optimize output xoring. + + commit 08e0650c21984bb9ddf5a1dabb1cc890fabf63ab + * cipher/chacha20-amd64-avx2.S (STACK_TMP2): Remove. + (transpose_16byte_2x2, xor_src_dst): New. + (BUF_XOR_256_TO_128): Remove. + (_gcry_chaha20_amd64_avx2_blocks8) + (_gcry_chacha20_poly1305_amd64_avx2_blocks8): Replace + BUF_XOR_256_TO_128 with transpose_16byte_2x2/xor_src_dst; Reduce stack + usage; Better interleave chacha20 state merging and output xoring. + + tests/bench-slope: prevent auto-mhz detection getting stuck. + + commit 28614a77a28190ab902a2b98039de2cd0635c7c7 + * cipher/bench-slope.c (bench_ghz, bench_ghz_diff): New static + variables. + (AUTO_GHZ_TARGET_DIFF): New macro. + (do_slope_benchmark): Reduce target auto-mhz accuracy after + repeated failures. + (bench_print_result_csv, bench_print_result_std): Print auto-ghz + different if 1 Mhz or more. + (do_slope_benchmark, bench_print_result_csv, bench_print_result_std) + (bench_print_result): Remove 'bench_ghz' parameter. + (cipher_bench_one, hash_bench_one, mac_bench_one) + (kdf_bench_one): Remove 'bench_ghz' variable. + + tests/bench-slope: add missing cipher context reset. + + commit 546f13ae08918726791600cdd0d0be56cc52c790 + * tests/bench-slope.c (bench_encrypt_do_bench) + (bench_decrypt_do_bench): Add call to 'gcry_cipher_reset'. + + Add stitched ChaCha20-Poly1305 SSSE3 and AVX2 implementations. + + commit d6330dfb4b0e9fb3f8eef65ea13146060b804a97 + * cipher/asm-poly1305-amd64.h: New. + * cipher/Makefile.am: Add 'asm-poly1305-amd64.h'. + * cipher/chacha20-amd64-avx2.S (QUATERROUND2): Add interleave + operators. + (_gcry_chacha20_poly1305_amd64_avx2_blocks8): New. + * cipher/chacha20-amd64-ssse3.S (QUATERROUND2): Add interleave + operators. + (_gcry_chacha20_poly1305_amd64_ssse3_blocks4) + (_gcry_chacha20_poly1305_amd64_ssse3_blocks1): New. + * cipher/chacha20.c (_gcry_chacha20_poly1305_amd64_ssse3_blocks4) + (_gcry_chacha20_poly1305_amd64_ssse3_blocks1) + (_gcry_chacha20_poly1305_amd64_avx2_blocks8): New prototypes. + (chacha20_encrypt_stream): Split tail to... + (do_chacha20_encrypt_stream_tail): ... new function. + (_gcry_chacha20_poly1305_encrypt) + (_gcry_chacha20_poly1305_decrypt): New. + * cipher/cipher-internal.h (_gcry_chacha20_poly1305_encrypt) + (_gcry_chacha20_poly1305_decrypt): New prototypes. + * cipher/cipher-poly1305.c (_gcry_cipher_poly1305_encrypt): Call + '_gcry_chacha20_poly1305_encrypt' if cipher is ChaCha20. + (_gcry_cipher_poly1305_decrypt): Call + '_gcry_chacha20_poly1305_decrypt' if cipher is ChaCha20. + * cipher/poly1305-internal.h (_gcry_cipher_poly1305_update_burn): New + prototype. + * cipher/poly1305.c (poly1305_blocks): Make static. + (_gcry_poly1305_update): Split main function body to ... + (_gcry_poly1305_update_burn): ... new function. + + Add SSSE3 optimized non-parallel ChaCha20 function. + + commit 7d9b2f114f3edf4d13640616cf34c79364234781 + * cipher/chacha20-amd64-ssse3.S (ROTATE_SHUF, ROTATE, WORD_SHUF) + (QUARTERROUND4, _gcry_chacha20_amd64_ssse3_blocks1): New. + * cipher/chacha20.c (_gcry_chacha20_amd64_ssse3_blocks1): New + prototype. + (chacha20_blocks): Rename to ... + (do_chacha20_blocks): ... this. + (chacha20_blocks): New. + (chacha20_encrypt_stream): Adjust for new chacha20_blocks function. + + tests/basic: increase buffer size for check_one_cipher. + + commit 88e482d16ee80de41b6f133e77f0d15423fcd266 + * tests/basic.c (check_one_cipher_core) + (check_one_cipher): Increase buffer from 1040 to 1904 bytes. + + tests/basic: check AEAD tags in check_one_cipher test. + + commit eee1f152a5b3040f6723d287d1b01fb939be67b7 + * tests/basic.c (get_algo_mode_taglen): New. + (check_one_cipher_core_reset): Check that tags are same with + AEAD modes. + +2019-01-15 NIIBE Yutaka + + build: With LD_LIBRARY_PATH defined, use --disable-new-dtags. + + commit e5c2f8a2cd2b89d90ea30de2dedb0e92498a5f70 + * configure.ac (LDADD_FOR_TESTS_KLUDGE): New for --disable-new-dtags. + * tests/Makefile.am (LDADD, t_lock_LDADD): Use LDADD_FOR_TESTS_KLUDGE. + + random: Fix previous commit for getentropy function. + + commit 17f246c7044ab9ed236f6ec73fc126654257f0f9 + * random/rndlinux.c [__NR_getrandom] (_gcry_rndlinux_gather_random): + Check return value only for use of syscall. + + random: Use getentropy when available for not GNU/Linux. + + commit 2677d7d482bf2d078c1dce64854747c5b148924b + * configure.ac: Detect getentropy. + * random/rndlinux.c [__linux__] (getentropy): Macro defined. + [HAVE_GETENTROPY] (_gcry_rndlinux_gather_random): Use getentropy. + +2019-01-14 Jussi Kivilinna + + camellia-aarch64: do not export look-up table globally. + + commit 09c27280cc09798d15369b3a143036b7ab5ddd69 + * cipher/camellia-aarch64.S (_gcry_camellia_arm_tables): Remove + '.globl' export. + +2019-01-02 Jussi Kivilinna + + Process CCM/EAX/GCM/Poly1305 AEAD cipher modes input in 24 KiB chucks. + + commit 3ee6588de8311b461ef8707c70ff86d2b252966d + * cipher/cipher-ccm.c (_gcry_cipher_ccm_encrypt) + (_gcry_cipher_ccm_decrypt): Process data in 24 KiB chunks. + * cipher/cipher-eax.c (_gcry_cipher_eax_encrypt) + (_gcry_cipher_eax_decrypt): Ditto. + * cipher/cipher-gcm.c (_gcry_cipher_gcm_encrypt) + (_gcry_cipher_gcm_decrypt): Ditto. + * cipher/cipher-poly1305.c (_gcry_cipher_poly1305_encrypt) + (_gcry_cipher_poly1305_decrypt): Ditto. + + tests/benchmark: add Chacha20-Poly1305 benchmarking. + + commit 4871f11745f33c5c5051bfe6f325ac1c10764b04 + * tests/benchmark.c (cipher_bench): Add Chacha20-Poly1305. + + tests/benchmark: add --huge-buffers option for cipher tests. + + commit edde61f325e4b345f17c47369f3b6b1400656f04 + * tests/benchmark.c (huge_buffers, cipher_encrypt, cipher_decrypt): New. + (cipher_bench): Add 'max_inlen' to modes structure; add huge buffers + mode selection. + (main): Add '--huge-buffers'. + +2018-12-19 NIIBE Yutaka + + random: Add finalizer for rndjent. + + commit 3028a221d39c1b593ea0c1bcbfccd33959769692 + * random/rand-internal.h (_gcry_rndjent_fini): New. + * random/rndjent.c (_gcry_rndjent_fini): New. + * random/rndlinux.c (_gcry_rndlinux_gather_random): Call the finalizer + when GCRYCTL_CLOSE_RANDOM_DEVICE. + +2018-12-12 Werner Koch + + secmem: Prepare for easier debugging. + + commit 876f7280e8604bc99ddda0526339ec5ec6b23c4b + * src/secmem.c (_gcry_secmem_dump_stats): Factor code out to ... + (secmem_dump_stats_internal): new. + +2018-12-01 Jussi Kivilinna + + rijndael-aesni: interleave last CTR encryption round with xoring. + + commit 66d2b7fc17258f1424f4ca4adb1096e48b818bd0 + * cipher/rijndael-aesni.c (do_aesni_ctr_8): Interleave aesenclast + with input xoring. + +2018-11-20 Jussi Kivilinna + + Use explicit_bzero for wipememory. + + commit 168668228c7c49e70612cb4d602d6d603a2add2c + * configure.ac (AC_CHECK_FUNCS): Check for 'explicit_bzero'. + * src/g10lib.h (wipememory2): Use _gcry_fast_wipememory if _SET is + zero. + (_gcry_fast_wipememory): New. + (_gcry_wipememory2): Rename to... + (_gcry_fast_wipememory2): ...this. + * src/misc.c (_gcry_wipememory): New. + (_gcry_wipememory2): Rename to... + (_gcry_fast_wipememory2): ...this. + (_gcry_fast_wipememory2) [HAVE_EXPLICIT_BZERO]: Use explicit_bzero if + SET is zero. + (_gcry_burn_stack): Use _gcry_fast_wipememory. + + Add clang target pragma for mixed C/assembly x86-64 implementations. + + commit 9d9c4fd18b445ff414d11678285d54af3afdb222 + * cipher/cipher-gcm-intel-pclmul.c: Add target 'no-sse' attribute + pragma for clang. + * cipher/crc-intel-pclmul.c: Ditto. + * cipher/rijndael-aesni.c: Ditto. + * cipher/rijndael-ssse3-amd64.c: Ditto. + * cipher/sha1-intel-shaext.c: Ditto. + * cipher/sha256-intel-shaext.c: Ditto. + + Optimizations for AES-NI OCB. + + commit b42de67f34871a2520cfe370af513f2aab6e4f75 + * cipher/cipher-internal.h (gcry_cipher_handle): New pre-computed OCB + values L0L1 and L0L1L0; Swap dimensions for OCB L table. + * cipher/cipher-ocb.c (_gcry_cipher_ocb_set_nonce): Setup L0L1 and + L0L1L0 values. + (ocb_crypt): Process input in 24KiB chunks for better cache locality + for checksumming. + * cipher/rijndael-aesni.c (ALWAYS_INLINE): New macro for always + inlining functions, change all functions with 'inline' to use + ALWAYS_INLINE. + (NO_INLINE): New macro. + (aesni_prepare_2_6_variable, aesni_prepare_7_15_variable): Rename to... + (aesni_prepare_2_7_variable, aesni_prepare_8_15_variable): ...these and + adjust accordingly (xmm7 moved from *_7_15 to *_2_7). + (aesni_prepare_2_6, aesni_prepare_7_15): Rename to... + (aesni_prepare_2_7, aesni_prepare_8_15): ...these and adjust + accordingly. + (aesni_cleanup_2_6, aesni_cleanup_7_15): Rename to... + (aesni_cleanup_2_7, aesni_cleanup_8_15): ...these and adjust + accordingly. + (aesni_ocb_checksum): New. + (aesni_ocb_enc, aesni_ocb_dec): Calculate OCB offsets in parallel + with help of pre-computed offsets L0+L1 ja L0+L1+L0; Do checksum + calculation as separate pass instead of inline; Use NO_INLINE. + (_gcry_aes_aesni_ocb_auth): Calculate OCB offsets in parallel + with help of pre-computed offsets L0+L1 ja L0+L1+L0. + * cipher/rijndael-internal.h (RIJNDAEL_context_s) [USE_AESNI]: Add + 'use_avx2' and 'use_avx'. + * cipher/rijndael.c (do_setkey) [USE_AESNI]: Set 'use_avx2' if + Intel AVX2 HW feature is available and 'use_avx' if Intel AVX HW + feature is available. + * tests/basic.c (do_check_ocb_cipher): New test vector; increase + size of temporary buffers for new test vector. + (check_ocb_cipher_largebuf_split): Make test plaintext non-uniform + for better checksum testing. + (check_ocb_cipher_checksum): New. + (check_ocb_cipher_largebuf): Call check_ocb_cipher_checksum. + (check_ocb_cipher): New expected tags for check_ocb_cipher_largebuf + test runs. + +2018-11-19 Andreas Metzler + + doc: Fix library initialization examples. + + commit af0bbdb9019e0b4a72e87e8b1b4a55506d349834 + + +2018-11-14 Werner Koch + + random: Initialize variable as requested by valgrind. + + commit aa686dfc9b563ff79c01d2f8560b88f69c42ecba + random/jitterentropy-base.c: Init. + +2018-11-13 NIIBE Yutaka + + libgcrypt.m4: Prefer gpgrt-config to SYSROOT support. + + commit 852245390ef7fd8ca9e36010886a4cf42cf710bf + * libgcrypt.m4: Move SYSROOT support after check of GPGRT_CONFIG. + + build: Update autogen.rc. + + commit bea193446351c24b10a4342466978d57bd53f599 + * autogen.rc: Remove obsolete --with-gpg-error-prefix option. + +2018-11-07 Jussi Kivilinna + + Fix 'variable may be used uninitialized' warning for CTR mode. + + commit 3f76319803a4abcd33fa29a0ac39f8ed9d646226 + * cipher/cipher-ctr.c (_gcry_cipher_ctr_encrypt): Set N to BLOCKSIZE + before counter loop. + +2018-11-06 Jussi Kivilinna + + Fix inlining of ocb_get_l for x86 AES implementations. + + commit 9d6431604b5ee21572c1c2cfa8376e6d81162cbb + * cipher/rijndael-aesni.c (aes_ocb_get_l): New. + (aesni_ocb_enc, aesni_ocb_dec, _gcry_aes_aesni_ocb_auth): Use + 'aes_ocb_get_l'. + * cipher/rijndael-ssse3-amd4.c (aes_ocb_get_l): New. + (ssse3_ocb_enc, ssse3_ocb_dec, _gcry_aes_ssse3_ocb_auth): Use + 'aes_ocb_get_l'. + +2018-11-05 Jussi Kivilinna + + stdmem: free: only call _gcry_secmem_free if needed. + + commit 23f56d3359ca7d152aa87874ddd6305171a91408 + * src/stdmem.c (_gcry_private_free): Check if memory is secure before + calling _gcry_secmem_free to avoid unnecessarily taking secmem lock. + + secmem: fix potential memory visibility issue. + + commit d6c6680ca31c05bafbb8becda56da051346eceb3 + * configure.ac (gcry_cv_have_sync_synchronize): New check. + * src/secmem.c (pooldesc_s): Make next pointer volatile. + (memory_barrier): New. + (_gcry_secmem_malloc_internal): Insert memory barrier between + pool->next and mainpool.next assigments. + (_gcry_private_is_secure): Update comments. + + wipememory: use memset for non-constant length or large buffer wipes. + + commit 4faeaa1cbd235a2560fa04a8ac3766a07029acd8 + * src/g10lib.h (CONSTANT_P): New. + (_gcry_wipememory2): New prototype. + (wipememory2): Use _gcry_wipememory2 if _len not constant expression or + lenght is larger than 64 bytes. + (FASTWIPE_T, FASTWIPE_MULT, fast_wipememory2_unaligned_head): Remove. + (fast_wipememory2): Always handle buffer as unaligned. + * src/misc.c (__gcry_burn_stack): Move memset_ptr variable to... + (memset_ptr): ... here. New. + (_gcry_wipememory2): New. + + Change buf_cpy and buf_xor* functions to use buf_put/buf_get helpers. + + commit 0068d41d9304ebcdb2caba1fa8848925e2bfaac7 + * cipher/bufhelp.h (BUFHELP_FAST_UNALIGNED_ACCESS) + (bufhelp_int_s, buf_xor_1): Remove. + (buf_cpy, buf_xor, buf_xor_2dst, buf_xor_n_copy_2): Use + buf_put/buf_get helpers to handle unaligned memory accesses. + + rijndael: fix unused parameter warning. + + commit 30e783ec487466132324673f197d36b85a91b060 + * cipher/rijndael.c (do_setkey): Silence unused 'hd' warning. + + mpi/longlong.h: enable inline assembly for powerpc64. + + commit ec49013d23d9a7b874c42d77ceb08bd313ba69e1 + * mpi/longlong.h [__powerpc__ && W_TYPE_SIZE == 64]: Remove '#if 0'. + + Change remaining users of _gcry_fips_mode to use fips_mode. + + commit 2aece89d3967e692743541cea857f2e4771b0b62 + * src/fips.c (_gcry_fips_mode): Remove. + (_gcry_enforced_fips_mode, _gcry_inactivate_fips_mode) + (_gcry_is_fips_mode_inactive): Use fips_mode. + * src/g10lib.h (_gcry_fips_mode): Remove. + +2018-11-02 NIIBE Yutaka + + aarch64: mpi: Distribute the header file as a part of source. + + commit a2e0cb1542818ad8a71de34ccbf191adab0a0b86 + * mpi/Makefile.am (EXTRA_libmpi_la_SOURCES): Add asm-common-aarch64.h. + + build: Fix GCRYPT_HWF_MODULES. + + commit f7395338d71d4d82180a11707fd6e77787162e24 + * configure.ac (GCRYPT_HWF_MODULES): Add libgcrypt_la- prefix. + + build: Update gpg-error.m4 and libgcrypt.m4. + + commit f46286851158878d5041ac5381b2807ecec541eb + * m4/gpg-error.m4: Update to 2018-11-02. + * src/libgrypt.m4: Add AC_MSG_NOTICE. + Bump the version date. + +2018-10-29 NIIBE Yutaka + + build: Update gpg-error.m4 and ksba.m4. + + commit 4a4d4a284ca996df874e2534f8529c1611289943 + * m4/gpg-error.m4: Update to 2018-10-29. + * src/libgrypt.m4: Follow the change of gpgrt-config. + Bump the version date. + +2018-10-27 Jussi Kivilinna + + Fix missing global initialization in fips_is_operational. + + commit 6e669e09603e5a98b59dcf35f77f346db6c81eac + * src/g10lib.h (_gcry_global_any_init_done): New extern. + (fips_is_operational): Check for _gcry_global_any_init_done and call + _gcry_global_is_operational. + * src/global.c (any_init_done): Rename to ... + (_gcry_global_any_init_done): ... this and make externally available. + +2018-10-26 Daniel Kahn Gillmor + + random: use getrandom() on Linux where available. + + commit 7e662680c170968661ee0105d132813f8281d229 + * random/rndlinux.c (_gcry_rndlinux_gather_random): use the + getrandom() syscall on Linux if it exists, regardless of what kind of + entropy was requested. + +2018-10-26 Werner Koch + + random: Make sure to re-open /dev/random after a fork. + + commit 319f55e6e5793c59f1ba4cfe481b562bca42194d + * random/rndlinux.c (_gcry_rndlinux_gather_random): Detect fork and + re-open devices. + + primes: Avoid leaking bits of the prime test to pageable memory. + + commit 2e2e68ad4874a4678cfbe452b70ae987e0402eca + * cipher/primegen.c (gen_prime): Allocate MODS in secure memory. + +2018-10-26 NIIBE Yutaka + + libgcrypt.m4: Better compatibility support. + + commit a755bd0ea09af2ae5a66e3f5aeb8707673c687cf + * src/gpg-error.m4: Update. + * src/libgcrypt.m4: Don't assume libgcrypt-config is newer. + + build: Fix libgcrypt.m4. + + commit 630ece1b7e0a94442bca91d8e96d9b1d4cd3ec66 + * src/libgcrypt.m4: Use AC_PATH_PROG to detect libgcrypt-config. + + build: Relax build requirements. + + commit 8e5641ed65f86783542d5caccdeeee42eeb9457c + * m4/gpg-error.m4: Update from libgpg-error 1.33. + * src/libgcrypt.m4: Don't require AM_PATH_GPG_ERROR. Use GPGRT_CONFIG + instead of libgcrypt-config when it is confirmed that it is available + and working well. + * configure.ac (AM_PATH_GPG_ERROR): No requirement for newer version + (It was because of new gpgrt-config which supports *.pc files). + +2018-10-25 NIIBE Yutaka + + build: Require libgpg-error >= 1.33. + + commit b376dc2abbb208b10bbc76998ff39adb2f301905 + * configure.ac (NEED_GPG_ERROR_VERSION): Require 1.33. + * m4/gpg-error.m4: Update from libgpg-error 1.33. + * src/libgcrypt.m4: Bump version date. + Use --variable option. + +2018-10-24 Werner Koch + + build: Add release make target. + + commit 03bb25ee7ed6f1076bf788ab981ca68672880daa + * Makefile.am (release, sign-release): New targets. + + build: Make distcheck work again. + + commit b0ad66e48c46b79af69349606e276cf0a6b9a020 + * cipher/Makefile.am: Prettified source file lists. + EXTRA_libcipher_la_SOURCES): Add missing asm-common-aarch64.h. + + Fix memory leak in secmem in out of core conditions. + + commit f74687fd43f5772a372f54031d5a9527597f4ce4 + * src/secmem.c (_gcry_secmem_malloc_internal): Release pool descriptor + if the pool could not be allocated. + + ecc: Fix memory leak in the error case of ecc_encrypt_raw. + + commit e57e75ea517f32109b508113f18298fc69fd1192 + * cipher/ecc.c (ecc_encrypt_raw): Add proper error cleanup in the main + block. + + ecc: Fix possible memory leakage in parameter check of eddsa. + + commit 149ceb3cae03d0385341d32430aa5ae57de90007 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_verify): Fix mem leak. + +2018-10-24 NIIBE Yutaka + + build: Fix libgcrypt.pc. + + commit 0e071372fc0e6fed4a449955ed0789803ba5e709 + * src/libgcrypt.pc.in: Fix typo. + + build: Compatibility to pkg-config. + + commit c60eabb11435665fa84a3a82b2a15f48870cc4d7 + * src/libgcrypt-config.in: Support --variable and --modversion. + + build: Make libgcrypt.m4 use gpg-error-config. + + commit 7da887d69d72ea0ea0d106054c48a8c03e242a18 + * src/libgcrypt.m4: Use gpg-error-config. + + build: Provide libgcrypt.pc, generated by configure. + + commit 97194b422bc89a6137f4e218d4cdee118c63e96e + * configure.ac: Generate src/libgcrypt.pc. + * src/Makefile.am (pkgconfigdir, pkgconfig_DATA): New. + (EXTRA_DIST): Add libgcrypt.pc.in. + * src/libgcrypt-config.in: Use @PACKAGE_VERSION@. + * src/libgcrypt.pc.in: New. + + build: Update gpg-error.m4 from libgpg-error. + + commit 5b1febb5e40d92072bef425bd9e63f7a07edd57e + * m4/gpg-error.m4: Update from libgpg-error 1.33. + + build: Don't default to underscore=yes for cross-build. + + commit 0f4545b441b6fbdd6e9c4e95f5f2a367483e78ad + * acinclude.m4: Don't set ac_cv_sys_symbol_underscore + for cross build. + +2018-10-23 Werner Koch + + ecc: Fix potential unintended freeing of an internal param. + + commit e2da4e8dee4b371804f3b2659b53431fb6380d93 + * cipher/ecc-curves.c (_gcry_ecc_get_mpi): Fix c+p error + + sexp: Fix uninitialized use of a var in the error case. + + commit 9f2c7ec4d8b07e82663ad084c90c016d3c3b80c2 + * src/sexp.c (_gcry_sexp_vextract_param): Initialize L1. + +2018-10-16 NIIBE Yutaka + + build: Let configure create the VERSION file. + + commit 0f2c6ce2c9504c6df435463243edaa669e57b109 + * autogen.sh: Update from libgpg-error. + * configure.ac: Use mym4_versoin to create VERSION file. + * Makefile.am (dist-hook): Do not create VERSION file. + (EXTRA_DIST): Add VERSION. + +2018-07-21 Jussi Kivilinna + + Add size optimized cipher block copy and xor functions. + + commit 86e5e06a97ae13b8bbf6923ecc76e02b9c429b46 + * cipher/bufhelp.h (buf_get_he32, buf_put_he32, buf_get_he64) + (buf_put_he64): New. + * cipher/cipher-internal.h (cipher_block_cpy, cipher_block_xor) + (cipher_block_xor_1, cipher_block_xor_2dst, cipher_block_xor_n_copy_2) + (cipher_block_xor_n_copy): New. + * cipher/cipher-gcm-intel-pclmul.c + (_gcry_ghash_setup_intel_pclmul): Use assembly for swapping endianness + instead of buf_get_be64 and buf_cpy. + * cipher/blowfish.c: Use new cipher_block_* functions for cipher block + sized buf_cpy/xor* operations. + * cipher/camellia-glue.c: Ditto. + * cipher/cast5.c: Ditto. + * cipher/cipher-aeswrap.c: Ditto. + * cipher/cipher-cbc.c: Ditto. + * cipher/cipher-ccm.c: Ditto. + * cipher/cipher-cfb.c: Ditto. + * cipher/cipher-cmac.c: Ditto. + * cipher/cipher-ctr.c: Ditto. + * cipher/cipher-eax.c: Ditto. + * cipher/cipher-gcm.c: Ditto. + * cipher/cipher-ocb.c: Ditto. + * cipher/cipher-ofb.c: Ditto. + * cipher/cipher-xts.c: Ditto. + * cipher/des.c: Ditto. + * cipher/rijndael.c: Ditto. + * cipher/serpent.c: Ditto. + * cipher/twofish.c: Ditto. + +2018-07-04 NIIBE Yutaka + + RFC-8439 was published. + + commit 9660c3fafd732b1857bb2697c6f43aed077b9ad6 + * cipher/cipher-poly1305.c: Update RFC reference. + +2018-06-19 Jussi Kivilinna + + Clean-up implementation selection for SHA1 and SHA2. + + commit 8a44c55d2fb758f726b8b436aa5c0b88a6c6f112 + * cipher/sha1.c (ASM_EXTRA_STACK): Increase by sizeof(void*)*4. + (do_sha1_transform_amd64_ssse3, do_sha1_transform_amd64_avx) + (do_sha1_transform_amd64_avx_bmi2, do_sha1_transform_intel_shaext) + (do_sha1_transform_armv7_neon, do_sha1_transform_armv8_ce): New. + (transform_blk, transform): Merge to ... + (do_transform_generic): ... this and remove calls to assembly + implementations. + (sha1_init): Select hd->bctx.bwrite based on HW features. + (_gcry_sha1_mixblock, sha1_final): Call hd->bctx.bwrite instead of + transform. + * cipher/sha1.h (SHA1_CONTEXT): Remove implementation selection bits. + * cipher/sha256.h (SHA256_CONTEXT): Remove implementation selection + bits. + (ASM_EXTRA_STACK): Increase by sizeof(void*)*4. + (do_sha256_transform_amd64_ssse3, do_sha256_transform_amd64_avx) + (do_sha256_transform_amd64_avx2, do_sha256_transform_intel_shaext) + (do_sha256_transform_armv8_ce): New. + (transform_blk, transform): Merge to ... + (do_transform_generic): ... this and remove calls to assembly + implementations. + (sha256_init, sha224_init): Select hd->bctx.bwrite based on HW + features. + (sha256_final): Call hd->bctx.bwrite instead of transform. + * cipher/sha512-armv7-neon.S + (_gcry_sha512_transform_armv7_neon): Return zero. + * cipher/sha512.h (SHA512_CONTEXT): Remove implementation selection + bits. + (ASM_EXTRA_STACK): Increase by sizeof(void*)*4. + (do_sha512_transform_armv7_neon, do_sha512_transform_amd64_ssse3) + (do_sha512_transform_amd64_avx, do_sha512_transform_amd64_avx2): New. + [USE_ARM_ASM] (do_transform_generic): New. + (transform_blk, transform): Merge to ... + [!USE_ARM_ASM] (do_transform_generic): ... this and remove calls to + assembly implementations. + (sha512_init, sha384_init): Select hd->bctx.bwrite based on HW + features. + (sha512_final): Call hd->bctx.bwrite instead of transform. + + Add hash_buffer and hash_buffers for SHA-224, SHA-385, SHA3 and BLAKE2. + + commit 59c4e344eec61cff45185e1caea6815b3266a0f8 + * cipher/blake2.c (DEFINE_BLAKE2_VARIANT): Add hash_buffer and + hash_buffers functions for BLAKE2 variants. + * cipher/keccak.c (_gcry_sha3_hash_buffer, _gcry_sha3_hash_buffers) + (_gcry_sha3_224_hash_buffer, _gcry_sha3_224_hash_buffers) + (_gcry_sha3_256_hash_buffer, _gcry_sha3_256_hash_buffers) + (_gcry_sha3_384_hash_buffer, _gcry_sha3_384_hash_buffers) + (_gcry_sha3_512_hash_buffer, _gcry_sha3_512_hash_buffers): New. + * cipher/sha256.c (_gcry_sha224_hash_buffer) + (_gcry_sha224_hash_buffers): New. + * cipher/sha512.c (_gcry_sha384_hash_buffer) + (_gcry_sha384_hash_buffers): New. + + Add hash_buffer and hash_buffers pointers to message digest spec. + + commit b136703ea0ddbd9fec6dfd1f8dfda8373653ba39 + * src/cipher-proto.h (gcry_md_hash_buffer_t) + (gcry_md_hash_buffers_t): New. + (gcry_md_spec): Add hash_buffer and hash_buffers. + * cipher/md.c (_gcry_md_hash_buffer, _gcry_md_hash_buffers): Use + hash_buffer/hash_buffers from MD spec instead of hard-coding supported + algorithms. + * cipher/blake2.c: Add NULL to MD spec hash_buffer and hash_buffers + pointers. + * cipher/crc.c: Ditto. + * cipher/gostr3411-94.c: Ditto. + * cipher/keccak.c: Ditto. + * cipher/md2.c: Ditto. + * cipher/md4.c: Ditto. + * cipher/md5.c: Ditto. + * cipher/stribog.c: Ditto. + * cipher/tiger.c: Ditto. + * cipher/whirlpool.c: Ditto. + * cipher/rmd160.c (_gcry_rmd160_hash_buffers): New. + (_gcry_digest_spec_rmd160): Add hash_buffer and hash_buffers functions. + * cipher/sha1.c (_gcry_digest_spec_sha1): Add hash_buffer and + hash_buffers functions. + * cipher/sha256.c (_gcry_digest_spec_sha256): Add hash_buffer and + hash_buffers functions. + (_gcry_digest_spec_sha224): Add NULL pointers for hash_buffer and + hash_buffers. + * cipher/sha512.c (_gcry_digest_spec_sha1): Add hash_buffer and + hash_buffers functions. + (_gcry_digest_spec_sha384): Add NULL pointers for hash_buffer and + hash_buffers. + * cipher/sm3.c (_gcry_digest_spec_sha1): Add hash_buffer and + hash_buffers functions. + + AES: setup cipher object bulk routines with optimized versions. + + commit a15c1def7e0f170f6663635db84fecab1cbfcca7 + * cipher/rijndael-aesni.c + (_gcry_aes_aesni_prepare_decryption): Rename... + (do_aesni_prepare_decryption): .. to this. + (_gcry_aes_aesni_prepare_decryption): New. + (_gcry_aes_aesni_cfb_enc, _gcry_aes_aesni_cbc_enc) + (_gcry_aes_aesni_ctr_enc, _gcry_aes_aesni_cfb_dec) + (_gcry_aes_aesni_cbc_dec): Reorder parameters to match bulk + operations. + (_gcry_aes_aesni_cbc_dec, aesni_ocb_dec) + (_gcry_aes_aesni_xts_dec): Check and prepare decryption. + (_gcry_aes_aesni_ocb_crypt, _gcry_aes_aesni_ocb_auth): Change return + type to size_t. + * cipher/rijndael-armv8-ce.c + (_gcry_aes_armv8_ce_cfb_enc, _gcry_aes_armv8_ce_cbc_enc) + (_gcry_aes_armv8_ce_ctr_enc, _gcry_aes_armv8_ce_cfb_dec) + (_gcry_aes_armv8_ce_cbc_dec): Reorder parameters to match bulk + operations. + (_gcry_aes_armv8_ce_cbc_dec, _gcry_aes_armv8_ce_ocb_crypt) + (_gcry_aes_armv8_ce_xts_dec): Check and prepare decryption. + (_gcry_aes_armv8_ce_ocb_crypt, _gcry_aes_armv8_ce_ocb_auth): Change + return type to size_t. + * cipher/rijndael-ssse3-amd64.c + (_gcry_ssse3_prepare_decryption): Rename... + (do_ssse3_prepare_decryption): .. to this. + (_gcry_ssse3_prepare_decryption): New. + (_gcry_aes_ssse3_cfb_enc, _gcry_aes_ssse3_cbc_enc) + (_gcry_aes_ssse3_ctr_enc, _gcry_aes_ssse3_cfb_dec) + (_gcry_aes_ssse3_cbc_dec): Reorder parameters to match bulk + operations. + (_gcry_aes_ssse3_cbc_dec, ssse3_ocb_dec): Check and prepare decryption. + (_gcry_aes_ssse3_ocb_crypt, _gcry_aes_ssse3_ocb_auth): Change return + type to size_t. + * cipher/rijndael.c + (_gcry_aes_aesni_cfb_enc, _gcry_aes_aesni_cbc_enc) + (_gcry_aes_aesni_ctr_enc, _gcry_aes_aesni_cfb_dec) + (_gcry_aes_aesni_cbc_dec, _gcry_aes_aesni_ocb_crypt) + (_gcry_aes_aesni_ocb_auth, _gcry_aes_aesni_xts_crypt) + (_gcry_aes_ssse3_cfb_enc, _gcry_aes_ssse3_cbc_enc) + (_gcry_aes_ssse3_ctr_enc, _gcry_aes_ssse3_cfb_dec) + (_gcry_aes_ssse3_cbc_dec, _gcry_aes_ssse3_ocb_crypt) + (_gcry_aes_ssse3_ocb_auth, _gcry_aes_ssse3_xts_crypt) + (_gcry_aes_armv8_ce_cfb_enc, _gcry_aes_armv8_ce_cbc_enc) + (_gcry_aes_armv8_ce_ctr_enc, _gcry_aes_armv8_ce_cfb_dec) + (_gcry_aes_armv8_ce_cbc_dec, _gcry_aes_armv8_ce_ocb_crypt) + (_gcry_aes_armv8_ce_ocb_auth, _gcry_aes_armv8_ce_xts_crypt): Change + prototypes to match bulk operations. + (do_setkey): Setup bulk operations with optimized implementations. + (_gcry_aes_cfb_enc, _gcry_aes_cbc_enc, _gcry_aes_ctr_enc) + (_gcry_aes_cfb_dec, _gcry_aes_cbc_dec, _gcry_aes_ocb_crypt) + (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth, _gcry_aes_xts_crypt): Update + usage to match new prototypes, avoid prefetch and decryption + preparation on optimized code paths. + + Pass cipher object pointer to setkey functions. + + commit ca21a24808efa5d562ac91f683504ae0d6dfa69f + * cipher/cipher.c (cipher_setkey): Pass cipher object pointer to + cipher's setkey function. + * cipher/arcfour.c: Add gcry_cipher_hd_t parameter for setkey + functions and update selftests to pass NULL pointer. + * cipher/blowfish.c: Ditto. + * cipher/camellia-glue.c: Ditto. + * cipher/cast5.c: Ditto. + * cipher/chacha20.c: Ditto. + * cipher/cipher-selftest.c: Ditto. + * cipher/des.c: Ditto. + * cipher/gost28147.c: Ditto. + * cipher/idea.c: Ditto. + * cipher/rfc2268.c: Ditto. + * cipher/rijndael.c: Ditto. + * cipher/salsa20.c: Ditto. + * cipher/seed.c: Ditto. + * cipher/serpent.c: Ditto. + * cipher/twofish.c: Ditto. + * src/cipher-proto.h: Ditto. + + Add fast path for _gcry_fips_is_operational. + + commit b6e6ace324440f564df664e27f8276ef01f76795 + * src/fips.c (no_fips_mode_required): Rename to... + (_gcry_no_fips_mode_required): ...this and make externally available. + * src/g10lib.h (_gcry_no_fips_mode_required): New extern. + (fips_mode): Inline _gcry_fips_mode to macro, use + _gcry_no_fips_mode_required directly. + (fips_is_operational): Inline fips_mode check from + _gcry_fips_in_operational. + + Access cipher mode routines through routine pointers. + + commit 233e2049a2cc1c1110f541b6a7ef145a737e2c65 + * cipher/cipher-internal.h (gcry_cipher_handle): Add function pointers + for mode operations. + (_gcry_cipher_xts_crypt): Remove. + (_gcry_cipher_xts_encrypt, _gcry_cipher_xts_decrypt): New. + * cipher/cipher-xts.c (_gcry_cipher_xts_encrypt) + (_gcry_cipher_xts_decrypt): New. + * cipher/cipher.c (_gcry_cipher_setup_mode_ops): New. + (_gcry_cipher_open_internal): Setup mode routines. + (cipher_encrypt, cipher_decrypt): Remove. + (do_stream_encrypt, do_stream_decrypt, do_encrypt_none_unknown) + (do_decrypt_none_unknown): New. + (_gcry_cipher_encrypt, _gcry_cipher_decrypt, _gcry_cipher_setiv) + (_gcry_cipher_authenticate, _gcry_cipher_gettag) + (_gcry_cipher_checktag): Adapted to use mode routines through pointers. + + Add separate handlers for CBC-CTS variant. + + commit 87d8caa47e00f1b1cea968fe38cf30c0ccc9749c + * cipher/cipher-cbc.c (cbc_encrypt_inner, cbc_decrypt_inner) + (_gcry_cipher_cbc_cts_encrypt, _gcry_cipher_cbc_cts_decrypt): New. + (_gcry_cipher_cbc_encrypt, _gcry_cipher_cbc_decrypt): Remove CTS + handling. + * cipher/cipher-internal.h (_gcry_cipher_cbc_cts_encrypt) + (_gcry_cipher_cbc_cts_decrypt): New. + * cipher/cipher.c (cipher_encrypt, cipher_decrypt): Call CBC-CTS + handler if CBC-CTS flag is set. + + Avoid division by spec->blocksize in cipher mode handlers. + + commit f5168091c1930e948af8f25da11cad5dfa62c7ba + * cipher/cipher-internal.h (_gcry_blocksize_shift): New. + * cipher/cipher-cbc.c (_gcry_cipher_cbc_encrypt) + (_gcry_cipherp_cbc_decrypt): Use bit-level operations instead of + division to get number of blocks and check input length against + blocksize. + * cipher/cipher-cfb.c (_gcry_cipher_cfb_encrypt) + (_gcry_cipher_cfb_decrypt): Ditto. + * cipher/cipher-cmac.c (_gcry_cmac_write): Ditto. + * cipher/cipher-ctr.c (_gcry_cipher_ctr_crypt): Ditto. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_encrypt) + (_gcry_cipher_ofb_decrypt): Ditto. + + Fix CBC-CTS+CBC-MAC flag check. + + commit a69021535b472556651eb2bab65666206c56c24b + * cipher/cipher.c (_gcry_cipher_open_internal): Check flags separately + instead of AND masking two flags to zero. + + tests/basic: silence GCC-8 warning. + + commit 2a94bdfc0538a340a24c1a7b524bb0c5f606457c + * tests/basic.c (check_ofb_cipher, check_stream_cipher): Change + tv[].data[].inlen type from signed to unsigned integer. + +2018-06-19 Will Dietz + + random: Fix hang of _gcry_rndjent_get_version. + + commit 355f5b7f69075c010fe33aa5b10ac60c08fae0c7 + * random/rndjent.c (_gcry_rndjent_get_version): Move locking. + +2018-06-13 NIIBE Yutaka + + ecc: Add blinding for ECDSA. + + commit 9010d1576e278a4274ad3f4aa15776c28f6ba965 + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Blind secret D with + randomized nonce B. + +2018-06-06 Werner Koch + + ecc: Improve gcry_mpi_ec_curve_point. + + commit 7b6c2afd699e889f5f054cc3d202a61bd0ee1dcf + * mpi/ec.c (_gcry_mpi_ec_curve_point): Check range of coordinates. + * tests/t-mpi-point.c (point_on_curve): New. + +2018-06-05 Werner Koch + + mpi: New internal function _gcry_mpi_cmpabs. + + commit 6606ae44e0de1069b29dd4215ee9748280940e1b + * mpi/mpi-cmp.c (_gcry_mpi_cmp): Factor out to ... + (do_mpi_cmp): New. Add arg absmode. + (_gcry_mpi_cmpabs): New. + * src/gcrypt-int.h (mpi_cmpabs): New macro. + +2018-04-29 Werner Koch + + build: Convince gcc not to delete NULL ptr checks. + + commit 61dbb7c08ab11c10060e193b52e3e1d2ec6dd062 + * configure.ac: Try to use -fno-delete-null-pointer-checks. + +2018-04-28 Werner Koch + + prime: Avoid rare assertion failure in gcry_prime_check. + + commit f3362f10f6f671246c38115ed12b0047966c200e + * cipher/primegen.c (is_prime): Don't fail on the assert X > 1. + +2018-04-17 Werner Koch + + mpi: Fix for buidling for MIPS64 with Clang. + + commit e7ae0ae243c8978a67c802169183187d88557be8 + * mpi/longlong.h [MIPS64][__clang__]: Use the C version like we + already do for 32 bit MIPS. + +2018-04-11 NIIBE Yutaka + + hmac: Use xtrymalloc. + + commit 3e3b520fb32a37c5c23762531a7b3168e112ac36 + * src/hmac256.c (_gcry_hmac256_new): Use xtrymalloc. + (_gcry_hmac256_file): Likewise. + +2018-04-10 Jussi Kivilinna + + basic_all_hwfeature_combinations.sh: use $njobs to limit parallel tasks. + + commit 5e01705ca90830c27a4cbd8bad41243915f4538a + * tests/basic_all_hwfeature_combinations.sh: Use $njobs to limit + parallel tasks instead of fixed number "8". + + Faster look-up for spec by algo for digests, ciphers and MAC. + + commit 634a85412a4073aa1890589ce5e97eac7b0f3ca3 + * cipher/cipher.c (cipher_list_algo0, cipher_list_algo301): New cipher + spec lists with same order and spacing as 'gcry_cipher_algos' + enumeration. + (spec_from_algo): Use new spec lists for faster look-up. + * cipher/mac.c (mac_list_algo101, mac_list_algo201, mac_list_algo401) + (mac_list_algo501): New MAC spec lists with same order and spacing as + 'gcry_mac_algos' enumeration. + (spec_from_algo): Use new spec lists for faster look-up. + * cipher/md.c (digest_list_algo0, digest_list_algo301): New digest + spec lists with same order and spacing as 'gcry_md_algos' + enumeration. + (spec_from_algo): Use new spec lists for faster look-up. + + Fix building with BLAKE2 disabled. + + commit 35b59d0ea52e8a1c30c43554dc4dbca97da4bf87 + * cipher/md.c (md_setkey): Enclose Blake2 part with USE_BLAKE2. + + Add missing BLAKE2, SM3 and GOSTR3411_CP to MAC-HMAC interface. + + commit 52e52eb0e3e5541cfc86e04c5047500db5d538b7 + * cipher/mac-hmac.c (map_mac_algo_to_md): Add GOSTR3411_CP, BLAKE2 and + SM3. + (_gcry_mac_type_spec_hmac_gost3411_cp) + (_gcry_mac_type_spec_hmac_blake2b_512) + (_gcry_mac_type_spec_hmac_blake2b_384) + (_gcry_mac_type_spec_hmac_blake2b_256) + (_gcry_mac_type_spec_hmac_blake2b_160) + (_gcry_mac_type_spec_hmac_blake2s_256) + (_gcry_mac_type_spec_hmac_blake2s_224) + (_gcry_mac_type_spec_hmac_blake2s_160) + (_gcry_mac_type_spec_hmac_blake2s_128) + (_gcry_mac_type_spec_hmac_sm3): New. + * cipher/mac-internal.h (_gcry_mac_type_spec_hmac_gost3411_cp) + (_gcry_mac_type_spec_hmac_blake2b_512) + (_gcry_mac_type_spec_hmac_blake2b_384) + (_gcry_mac_type_spec_hmac_blake2b_256) + (_gcry_mac_type_spec_hmac_blake2b_160) + (_gcry_mac_type_spec_hmac_blake2s_256) + (_gcry_mac_type_spec_hmac_blake2s_224) + (_gcry_mac_type_spec_hmac_blake2s_160) + (_gcry_mac_type_spec_hmac_blake2s_128) + (_gcry_mac_type_spec_hmac_sm3): New. + * cipher/mac.c (mac_list): Add GOSTR3411_CP, BLAKE2 and SM3. + * src/gcrypt.h.in (GCRY_MAC_HMAC_GOSTR3411_CP) + (GCRY_MAC_HMAC_BLAKE2B_512, GCRY_MAC_HMAC_BLAKE2B_384) + (GCRY_MAC_HMAC_BLAKE2B_256, GCRY_MAC_HMAC_BLAKE2B_160) + (GCRY_MAC_HMAC_BLAKE2S_256, GCRY_MAC_HMAC_BLAKE2S_224) + (GCRY_MAC_HMAC_BLAKE2S_160, GCRY_MAC_HMAC_BLAKE2S_128) + (GCRY_MAC_HMAC_SM3): New. + +2018-04-10 NIIBE Yutaka + + random: Protect another use of jent_rng_collector. + + commit 0de2a22fcf6607d0aecb550feefa414cee3731b2 + * random/rndjent.c (_gcry_rndjent_get_version): Lock the access. + +2018-03-28 Jussi Kivilinna + + aarch64/assembly: only use the lower 32 bit of an int parameters. + + commit 9b58e4a03ba3aeff7bae3f40da706977870c9649 + * cipher/camellia-aarch64.S (_gcry_camellia_arm_encrypt_block) + (__gcry_camellia_arm_decrypt_block): Make comment section about input + registers match usage. + * cipher/rijndael-armv8-aarch64-ce.S (_gcry_aes_ocb_auth_armv8_ce): Use + 'w12' and 'w7' instead of 'x12' and 'x7'. + (_gcry_aes_xts_enc_armv8_ce, _gcry_aes_xts_dec_armv8_ce): Fix function + prototype in comments. + * mpi/aarch64/mpih-add1.S: Use 32-bit registers for 32-bit mpi_size_t + parameters. + * mpi/aarch64/mpih-mul1.S: Ditto. + * mpi/aarch64/mpih-mul2.S: Ditto. + * mpi/aarch64/mpih-mul3.S: Ditto. + * mpi/aarch64/mpih-sub1.S: Ditto. + + poly1305: silence compiler warning on clang/aarch64. + + commit 8cdb010f04528703a502344e00d52447de12547d + * cipher/poly1305.c (MUL_MOD_1305_64): cast zero constant to 64-bits. + +2018-03-28 Martin Storsjö + + aarch64: Enable building the aarch64 cipher assembly for windows. + + commit 0de2191a07d69ef1fa34ca4c5d5fc4985ff7b4c4 + * cipher/asm-common-aarch64.h: New. + * cipher/camellia-aarch64.S: Use ELF macro, use x19 instead of x18. + * cipher/chacha20-aarch64.S: Use ELF macro, don't use GOT on windows. + * cipher/cipher-gcm-armv8-aarch64-ce.S: Use ELF macro. + * cipher/rijndael-aarch64.S: Use ELF macro. + * cipher/rijndael-armv8-aarch64-ce.S: Use ELF macro. + * cipher/sha1-armv8-aarch64-ce.S: Use ELF macro. + * cipher/sha256-armv8-aarch64-ce.S: Use ELF macro. + * cipher/twofish-aarch64.S: Use ELF macro. + * configure.ac: Don't require .size and .type in aarch64 assembly check. + + aarch64: camellia: Only use the lower 32 bit of an int parameter. + + commit 4e1b628f492643d4e9b830bcdab7b49daaec5854 + * cipher/camellia-aarch64.S: Use 'w3' instead of 'x3'. + + aarch64: Fix assembling chacha20-aarch64.S with clang/llvm. + + commit 36e916fc332eda74963192b1c0bf6860a3e5d67b + * cipher/chacha20-aarch64.S: Remove superfluous lane counts. + + aarch64: mpi: Fix building the mpi aarch64 assembly for windows. + + commit ec0a2f25c0f64a7b65b373508ce9081e10461965 + * mpi/aarch64/mpih-add1.S: Use ELF macro. + * mpi/aarch64/mpih-mul1.S: Use ELF macro. + * mpi/aarch64/mpih-mul2.S: Use ELF macro. + * mpi/aarch64/mpih-mul3.S: Use ELF macro. + * mpi/aarch64/mpih-sub1.S: Use ELF macro. + * mpi/asm-common-aarch64.h: New. + + random: Don't assume that _WIN64 implies x86_64. + + commit ed41d6d6fb4551342b22ef763de1bd60e964e186 + * random/rndw32.c: Change _WIN64 ifdef into __x86_64__. + +2018-03-22 Jussi Kivilinna + + tests/aeswrap: add in-place encryption/decryption testing. + + commit 885f031fbd17abc1c0fedbb98df22823b647fc11 + * tests/aeswrap.c (check): Rename to... + (check_one): ...this and add in-place testing. + (check): New. + +2018-03-22 Stephan Mueller + + AES-KW: fix in-place encryption. + + commit 330ec66e0babdabb658dc7d6db78f37b2a1b996e + * cipher/cipher-aeswrap.c: move memmove call before KW IV setting + +2018-03-22 Jussi Kivilinna + + bench-slope: add CPU frequency auto-detection. + + commit 617f5e746f8295cc36d1002c8c53edc95d04d0f6 + * tests/bench-slope.c (bench_obj): Add 'hd'. + (bench_encrypt_init, bench_encrypt_free, bench_encrypt_do_bench) + (bench_decrypt_do_bench, bench_xts_encrypt_init) + (bench_xts_encrypt_do_bench, bench_xts_decrypt_do_bench) + (bench_ccm_encrypt_init, bench_ccm_encrypt_do_bench) + (bench_ccm_decrypt_do_bench, bench_aead_encrypt_init) + (bench_aead_encrypt_do_bench, bench_aead_decrypt_do_bench) + (bench_hash_init, bench_hash_free, bench_hash_do_bench) + (bench_mac_init, bench_mac_free, bench_mac_do_bench): Use 'obj->hd' + for storing pointer to crypto context. + (auto_ghz): New. + (do_slope_benchmark): Rename to... + (slope_benchmark): ...this. + (auto_ghz_init, auto_ghz_free, auto_ghz_bench, auto_ghz_detect_ops) + (get_auto_ghz, do_slope_benchmark): New. + (double_to_str): Round number larger than 1000 to integer. + (bench_print_result_csv, bench_print_result_std) + (bench_print_result, bench_print_header, cipher_bench_one) + (hash_bench_one, mac_bench_one, kdf_bench_one, kdf_bench): Add + auto-detected frequency printing. + (print_help): Help for CPU speed auto-detection mode. + (main): Add parsing for "--cpu-mhz auto". + + _gcry_burn_stack: use memset for clearing memory. + + commit 3841b23c0ccb24d555b7570083bba958e3126d26 + * src/misc.c (__gcry_burn_stack) [HAVE_VLA]: Use 'memset' for clearing + stack. + + Improve constant-time buffer compare. + + commit a1127dbbada4302abf09eec90fbaceca87bfcdf0 + * cipher/bufhelp.h (buf_eq_const): Rewrite logic. + +2018-02-16 Jussi Kivilinna + + Add Intel SHA Extensions accelerated SHA256 implementation. + + commit 0b3ec359e2279c3b46b171372b1b7733bba20cd7 + * cipher/Makefile.am: Add 'sha256-intel-shaext.c'. + * cipher/sha256-intel-shaext.c: New. + * cipher/sha256.c (USE_SHAEXT) + (_gcry_sha256_transform_intel_shaext): New. + (SHA256_CONTEXT): Add 'use_shaext'. + (sha256_init, sha224_init) [USE_SHAEXT]: Use shaext if supported. + (transform) [USE_SHAEXT]: Use shaext if enabled. + (transform): Only add ASM_EXTRA_STACK if returned burn length is not + zero. + * configure.ac: Add 'sha256-intel-shaext.lo'. + + Add Intel SHA Extensions accelerated SHA1 implementation. + + commit d02958bd300d2c80bc92b1e072103e95e256b297 + * cipher/Makefile.am: Add 'sha1-intel-shaext.c'. + * cipher/sha1-intel-shaext.c: New. + * cipher/sha1.c (USE_SHAEXT, _gcry_sha1_transform_intel_shaext): New. + (sha1_init) [USE_SHAEXT]: Use shaext implementation is supported. + (transform) [USE_SHAEXT]: Use shaext if enabled. + (transform): Only add ASM_EXTRA_STACK if returned burn length is not + zero. + * cipher/sha1.h (SHA1_CONTEXT): Add 'use_shaext'. + * configure.ac: Add 'sha1-intel-shaext.lo'. + (shaextsupport, gcry_cv_gcc_inline_asm_shaext): New. + * src/g10lib.h: Add HWF_INTEL_SHAEXT and reorder HWF flags. + * src/hwf-x86.c (detect_x86_gnuc): Detect SHA Extensions. + * src/hwfeatures.c (hwflist): Add 'intel-shaext'. + + AVX implementation of BLAKE2s. + + commit da58a62ac1b7a8d97b0895dcb41d15af531e45e5 + * cipher/Makefile.am: Add 'blake2s-amd64-avx.S'. + * cipher/blake2.c (USE_AVX, _gry_blake2s_transform_amd64_avx): New. + (BLAKE2S_CONTEXT) [USE_AVX]: Add 'use_avx'. + (blake2s_transform): Rename to ... + (blake2s_transform_generic): ... this. + (blake2s_transform): New. + (blake2s_final): Pass 'ctx' pointer to transform function instead of + 'S'. + (blake2s_init_ctx): Check HW features and enable AVX implementation + if supported. + * cipher/blake2s-amd64-avx.S: New. + * configure.ac: Add 'blake2s-amd64-avx.lo'. + +2018-02-04 Jussi Kivilinna + + AVX2 implementation of BLAKE2b. + + commit af7fc732f9a7af7a70276f1e8364d2132db314f1 + * cipher/Makefile.am: Add 'blake2b-amd64-avx2.S'. + * cipher/blake2.c (USE_AVX2, ASM_FUNC_ABI, ASM_EXTRA_STACK) + (_gry_blake2b_transform_amd64_avx2): New. + (BLAKE2B_CONTEXT) [USE_AVX2]: Add 'use_avx2'. + (blake2b_transform): Rename to ... + (blake2b_transform_generic): ... this. + (blake2b_transform): New. + (blake2b_final): Pass 'ctx' pointer to transform function instead of + 'S'. + (blake2b_init_ctx): Check HW features and enable AVX2 implementation + if supported. + * cipher/blake2b-amd64-avx2.S: New. + * configure.ac: Add 'blake2b-amd64-avx2.lo'. + +2018-01-31 Jussi Kivilinna + + Fix incorrect counter overflow handling for GCM. + + commit ffdc6f3623a0bcb41324d562340b2cd1c288e387 + * cipher/cipher-gcm.c (gcm_ctr_encrypt): New function to handle + 32-bit CTR increment for GCM. + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt): Do not use + generic CTR implementation directly, use gcm_ctr_encrypt instead. + * tests/basic.c (_check_gcm_cipher): Add test-vectors for 32-bit + CTR overflow. + (check_gcm_cipher): Add 'split input to 15 bytes and 17 bytes' + test-runs. + +2018-01-22 Jussi Kivilinna + + Fix use of AVX instructions in Chaha20 SSSE3 implementation. + + commit 0b55f349a8b8f4b0ac9ed724c2d5b8dcc9f5401c + * cipher/chacha20-amd64-ssse3.S: Replace two 'vmovdqa' instructions + with 'movdqa'. + +2018-01-20 Jussi Kivilinna + + doc: fix double "See" in front of reference. + + commit bd75f0e89817b5708c57efab49e3eb4e035186e2 + * doc/gcrypt.texi: Change @xref to @ref when text already has 'see' in + the front. + + Add EAX mode. + + commit e8629e535bd0e9711b07904d4501de8ad57aaecd + * cipher/Makefile.am: Add 'cipher-eax.c'. + * cipher/cipher-cmac.c (cmac_write): Rename to ... + (_gcry_cmac_write): ... this; Take CMAC context as new input + parameter; Return error code. + (cmac_generate_subkeys): Rename to ... + (_gcry_cmac_generate_subkeys): ... this; Take CMAC context as new + input parameter; Return error code. + (cmac_final): Rename to ... + (_gcry_cmac_final): ... this; Take CMAC context as new input + parameter; Return error code. + (cmac_tag): Take CMAC context as new input parameter. + (_gcry_cmac_reset): New. + (_gcry_cipher_cmac_authenticate): Remove duplicate tag flag check; + Adapt to changes above. + (_gcry_cipher_cmac_get_tag): Adapt to changes above. + (_gcry_cipher_cmac_check_tag): Ditto. + (_gcry_cipher_cmac_set_subkeys): Ditto. + * cipher-eax.c: New. + * cipher-internal.h (gcry_cmac_context_t): New. + (gcry_cipher_handle): Update u_mode.cmac; Add u_mode.eax. + (_gcry_cmac_write, _gcry_cmac_generate_subkeys, _gcry_cmac_final) + (_gcry_cmac_reset, _gcry_cipher_eax_encrypt, _gcry_cipher_eax_decrypt) + (_gcry_cipher_eax_set_nonce, _gcry_cipher_eax_authenticate) + (_gcry_cipher_eax_get_tag, _gcry_cipher_eax_check_tag) + (_gcry_cipher_eax_setkey): New prototypes. + * cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey) + (cipher_reset, cipher_encrypt, cipher_decrypt, _gcry_cipher_setiv) + (_gcry_cipher_authenticate, _gcry_cipher_gettag, _gcry_cipher_checktag) + (_gcry_cipher_info): Add EAX mode. + * doc/gcrypt.texi: Add EAX mode. + * src/gcrypt.h.in (GCRY_CIPHER_MODE_EAX): New. + * tests/basic.c (_check_gcm_cipher, _check_poly1305_cipher): Constify + test vectors array. + (_check_eax_cipher, check_eax_cipher): New. + (check_ciphers, check_cipher_modes): Add EAX mode. + * tests/bench-slope.c (bench_eax_encrypt_do_bench) + (bench_eax_decrypt_do_bench, bench_eax_authenticate_do_bench) + (eax_encrypt_ops, eax_decrypt_ops, eax_authenticate_ops): New. + (cipher_modes): Add EAX mode. + * tests/benchmark.c (cipher_bench): Add EAX mode. + + cipher: constify spec arrays. + + commit cd7ed2e3546b12dd98df4211949f1cdbf5827013 + * cipher/cipher.c (cipher_list): Constify array. + * cipher/mac.c (mac_list): Constify array. + * cipher/md.c (digest_list): Constify array. + * cipher/pubkey.c (pubkey_list): Constify array. + + Add ARMv8/CE acceleration for AES-XTS. + + commit 93503c127a52c1f6a193750e2bf181a744ba3e6b + * cipher/rijndael-armv8-aarch32-ce.S (_gcry_aes_xts_enc_armv8_ce) + (_gcry_aes_xts_dec_armv8_ce): New. + * cipher/rijndael-armv8-aarch64-ce.S (_gcry_aes_xts_enc_armv8_ce) + (_gcry_aes_xts_dec_armv8_ce): New. + * cipher/rijndael-armv8-ce.c (_gcry_aes_xts_enc_armv8_ce) + (_gcry_aes_xts_dec_armv8_ce, xts_crypt_fn_t) + (_gcry_aes_armv8_ce_xts_crypt): New. + * cipher/rijndael.c (_gcry_aes_armv8_ce_xts_crypt): New. + (_gcry_aes_xts_crypt) [USE_ARM_CE]: New. + +2018-01-09 Jussi Kivilinna + + rijndael-ssse3: call assembly functions directly. + + commit c3d60acc3ab5c6d60c2258882175bf31351cc998 + * cipher/rijndael-ssse3-amd64-asm.S (_gcry_aes_ssse3_enc_preload) + (_gcry_aes_ssse3_dec_preload, _gcry_aes_ssse3_encrypt_core) + (_gcry_aes_ssse3_decrypt_core, _gcry_aes_schedule_core): Add + ENTER_SYSV_FUNC_PARAMS_* at function entry and EXIT_SYSV_FUNC at exit. + (_gcry_aes_ssse3_encrypt_core, _gcry_aes_ssse3_decrypt_core): Change + to input parameters to RDI and RSI registers. + * cipher/rijndael-ssse3-amd64.c (_gcry_aes_ssse3_encrypt_core) + (_gcry_aes_ssse3_decrypt_core, _gcry_aes_schedule_core): Add parameters + for function prototypes. + (PUSH_STACK_PTR, POP_STACK_PTR): Remove. + (vpaes_ssse3_prepare_enc, vpaes_ssse3_prepare_dec) + (_gcry_aes_ssse3_do_setkey, _gcry_aes_ssse3_prepare_decryption) + (do_vpaes_ssse3_enc, do_vpaes_ssse3_dec): Remove inline assembly to + call functions, and call directly instead. + + Move AMD64 MS to SysV calling convention conversion to assembly side. + + commit a518b6680ea80a4325731028545a701c1d71fc02 + * cipher/Makefile.am: Add 'asm-common-amd64.h'. + * cipher/asm-common-amd64.h: New. + * cipher/blowfish-amd64.S: Add ENTER_SYSV_FUNC_* and EXIT_SYSV_FUNC for + each global function from 'asm-common-amd64.h'. + * cipher/cast5-amd64.S: Ditto. + * cipher/des-amd64.S: Ditto. + * cipher/rijndael-amd64.S: Ditto. + * cipher/twofish-amd64.S: Ditto. + * cipher/arcfour-amd64.S: Ditto. + * cipher/blowfish.c [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] + (call_sysv_fn): Remove. + * cipher/cast5.c [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] + (call_sysv_fn): Remove. + * cipher/twofish.c [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] + (call_sysv_fn, call_sysv_fn5, call_sysv_fn6): Remove. + * cipher/rijndael.c (do_encrypt, do_decrypt) + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS]: Remove assembly block for + calling SysV ABI function. + * cipher/arcfour.c [USE_AMD64_ASM] (encrypt_stream): Ditto. + + Make BMI2 inline assembly check more robust. + + commit 135250e3060e79be698d4f36a819aa8a880789f8 + * configure.ac (gcry_cv_gcc_inline_asm_bmi2): New assembly test. + + Add AES-NI acceleration for AES-XTS. + + commit a00c5b2988cea256c7823a76ce601febf02c790f + * cipher/cipher-internal.h (gcry_cipher_handle): Change bulk + XTS function to take cipher context. + * cipher/cipher-xts.c (_gcry_cipher_xts_crypt): Ditto. + * cipher/cipher.c (_gcry_cipher_open_internal): Setup AES-NI + XTS bulk function. + * cipher/rijndael-aesni.c (xts_gfmul_const, _gcry_aes_aesni_xts_enc) + (_gcry_aes_aesni_xts_enc, _gcry_aes_aesni_xts_crypt): New. + * cipher/rijndael.c (_gcry_aes_aesni_xts_crypt) + (_gcry_aes_xts_crypt): New. + * src/cipher.h (_gcry_aes_xts_crypt): New. + + AES-NI improvements for AMD64. + + commit c9e9cb2eb6a1c659d3825ca627228b732f2f2152 + * cipher/rijndael-aesni.c [__x86_64__] (aesni_prepare_7_15_variable) + (aesni_prepare_7_15, aesni_cleanup_7_15, do_aesni_enc_vec8) + (do_aesni_dec_vec8, do_aesni_ctr_8): New. + (_gcry_aes_aesni_ctr_enc, _gcry_aes_aesni_cfb_dec) + (_gcry_aes_aesni_cbc_dec, aesni_ocb_enc, aesni_ocb_dec) + (_gcry_aes_aesni_ocb_auth) [__x86_64__]: Add 8 parallel blocks + processing. + + Add ARMv8/AArch64 implementation of chacha20. + + commit b3ec0f752c925cde36f560f0f9309ab6450bbfd9 + * cipher/Makefile.am: Add 'chacha20-aarch64.S'. + * cipher/chacha20-aarch64.S: New. + * cipher/chacha20.c (USE_AARCH64_SIMD): New. + (_gcry_chacha20_aarch_blocks4): New. + (chacha20_do_setkey): Add HWF selection for Aarch64 implementation. + * configure.ac: Add 'chacha20-aarch64.lo'. + + New ChaCha implementations. + + commit 172ad09cbedc893f147180875335f4c525393c0b + * cipher/Makefile.am: Remove 'chacha20-sse2-amd64.S', + 'chacha20-ssse3-amd64.S', 'chacha20-avx2-amd64.S'; Add + 'chacha20-amd64-ssse3.S', 'chacha20-amd64-avx2.S'. + * cipher/chacha20-amd64-avx2.S: New. + * cipher/chacha20-amd64-ssse3.S: New. + * cipher/chacha20-armv7-neon.S: Rewrite. + * cipher/chacha20-avx2-amd64.S: Remove. + * cipher/chacha20-sse2-amd64.S: Remove. + * cipher/chacha20-ssse3-amd64.S: Remove. + * cipher/chacha20.c (CHACHA20_INPUT_LENGTH, USE_SSE2, USE_NEON) + (ASM_EXTRA_STACK, chacha20_blocks_t, _gcry_chacha20_amd64_sse2_blocks) + (_gcry_chacha20_amd64_ssse3_blocks, _gcry_chacha20_amd64_avx2_blocks) + (_gcry_chacha20_armv7_neon_blocks, QROUND, QOUT, chacha20_core) + (chacha20_do_encrypt_stream): Remove. + (_gcry_chacha20_amd64_ssse3_blocks4, _gcry_chacha20_amd64_avx2_blocks8) + (_gcry_chacha20_armv7_neon_blocks4, ROTATE, XOR, PLUS, PLUSONE) + (QUARTERROUND, BUF_XOR_LE32): New. + (CHACHA20_context_s, chacha20_blocks, chacha20_keysetup) + (chacha20_encrypt_stream): Rewrite. + (chacha20_do_setkey): Adjust for new CHACHA20_context_s. + * configure.ac: Remove 'chacha20-sse2-amd64.lo', + 'chacha20-ssse3-amd64.lo', 'chacha20-avx2-amd64.lo'; Add + 'chacha20-amd64-ssse3.lo', 'chacha20-amd64-avx2.lo'. + + New Poly1305 implementations. + + commit b9a471ccf5f02f89e25c7ccc29898d0e4e486099 + * cipher/Makefile.am: Include '../mpi' for 'longlong.h'; Remove + 'poly1305-sse2-amd64.S', 'poly1305-avx2-amd64.S' and + 'poly1305-armv7-neon.S'. + * cipher/poly1305-armv7-neon.S: Remove. + * cipher/poly1305-avx2-amd64.S: Remove. + * cipher/poly1305-sse2-amd64.S: Remove. + * cipher/poly1305-internal.h (POLY1305_BLOCKSIZE) + (POLY1305_STATE): New. + (POLY1305_SYSV_FUNC_ABI, POLY1305_REF_BLOCKSIZE) + (POLY1305_REF_STATESIZE, POLY1305_REF_ALIGNMENT) + (POLY1305_USE_SSE2, POLY1305_SSE2_BLOCKSIZE, POLY1305_SSE2_STATESIZE) + (POLY1305_SSE2_ALIGNMENT, POLY1305_USE_AVX2, POLY1305_AVX2_BLOCKSIZE) + (POLY1305_AVX2_STATESIZE, POLY1305_AVX2_ALIGNMENT) + (POLY1305_USE_NEON, POLY1305_NEON_BLOCKSIZE, POLY1305_NEON_STATESIZE) + (POLY1305_NEON_ALIGNMENT, POLY1305_LARGEST_BLOCKSIZE) + (POLY1305_LARGEST_STATESIZE, POLY1305_LARGEST_ALIGNMENT) + (POLY1305_STATE_BLOCKSIZE, POLY1305_STATE_STATESIZE) + (POLY1305_STATE_ALIGNMENT, OPS_FUNC_ABI, poly1305_key_s) + (poly1305_ops_s): Remove. + (poly1305_context_s): Rewrite. + * cipher/poly1305.c (_gcry_poly1305_amd64_sse2_init_ext) + (_gcry_poly1305_amd64_sse2_finish_ext) + (_gcry_poly1305_amd64_sse2_blocks, poly1305_amd64_sse2_ops) + (poly1305_init_ext_ref32, poly1305_blocks_ref32) + (poly1305_finish_ext_ref32, poly1305_default_ops) + (_gcry_poly1305_amd64_avx2_init_ext) + (_gcry_poly1305_amd64_avx2_finish_ext) + (_gcry_poly1305_amd64_avx2_blocks) + (poly1305_amd64_avx2_ops, poly1305_get_state): Remove. + (poly1305_init): Rewrite. + (USE_MPI_64BIT, USE_MPI_32BIT): New. + [USE_MPI_64BIT] (ADD_1305_64, MUL_MOD_1305_64, poly1305_blocks) + (poly1305_final): New implementation using 64-bit limbs. + [USE_MPI_32BIT] (UMUL_ADD_32, ADD_1305_32, MUL_MOD_1305_32) + (poly1305_blocks): New implementation using 32-bit limbs. + (_gcry_poly1305_update, _gcry_poly1305_finish) + (_gcry_poly1305_init): Adapt to new implementation. + * configure.ac: Remove 'poly1305-sse2-amd64.lo', + 'poly1305-avx2-amd64.lo' and 'poly1305-armv7-neon.lo'. + + mpi/ec: fix when 'unsigned long' is 32-bit but limb size is 64-bit. + + commit d39deb0a41dbeec81174704904d3d29c66d10d7e + * mpi/ec.c (ec_addm_25519, ec_subm_25519, ec_mulm_25519): Cast '1' to + mpi_limb_t before left shift. + +2017-11-24 Werner Koch + + sexp: Avoid a fatal error in case of ENOMEM in called functions. + + commit 2ad912d5b7794fb32192fddab1b559c7b86303a2 + * src/sexp.c (do_vsexp_sscan): Replace BUG() by a proper error + return. Replace sprintf by snprintf. + (convert_to_hex): Replace sprintf by snprintf. + (convert_to_string): Ditto. + (_gcry_sexp_sprint): Ditto. + + api: Add GCRYCTL_AUTO_EXPAND_SECMEM. + + commit 1f6b2f6099ebcfd785e2d2ae0aeca810394dbbac + * src/gcrypt.h.in (GCRYCTL_AUTO_EXPAND_SECMEM): New enum. + * src/global.c (_gcry_vcontrol): Implement that. + * src/secmem.c (auto_expand): New var. + (_gcry_secmem_set_auto_expand): New. + (_gcry_secmem_malloc_internal): Act upon AUTO_EXPAND. + +2017-11-14 NIIBE Yutaka + + tests: Add HAVE_MMAP check for MinGW. + + commit c594f187bd457b757112adc551ffa4db92962dc1 + * tests/t-secmem.c (main): Conditionalize with HAVE_MMAP. + +2017-11-09 NIIBE Yutaka + + Fix secmem test for machine with larger page. + + commit 621f5c4e837347308a6b06a8cfbfc47ca9fae69e + * tests/t-secmem.c (main): Detect page size and setup chunk size. + * src/secmem.c (init_pool): Simplify the expression. + +2017-10-25 NIIBE Yutaka + + Add OID information for SM3. + + commit 94b84360ca55c407222a3eb8222d8b1816fc617f + * cipher/sm3.c (asn_sm3, oid_spec_sm3): New. + (_gcry_digest_spec_sm3): Add asn_sm3, oid_spec_sm3. + +2017-10-24 Jia Zhang + + Add crypto hash SM3. + + commit 4423bf3cc4432b9bfe801ff74cb05e6f0dd3eccd + * configure.ac (available_digests): Add sm3. + * src/cipher.h: Add declarations for SM3. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add sm3.c. + * cipher/md.c [USE_SM3] (digest_list): Add _gcry_digest_spec_sm3. + * cipher/pubkey-util.c (hashnames): Add "sm3". + * cipher/sm3.c: New. + * tests/basic.c (check_digests): Add test vectors for SM3. + * tests/hashtest-256g.in (algos): Add SM3. + * tests/hashtest.c (testvectors): Add for SM3. + +2017-10-24 NIIBE Yutaka + + Add new constant GCRY_MD_SM3 for crypto hash SM3. + + commit 5b31e22d9fc542bdccb1586ef2c83d9794a731d3 + * src/gcrypt.h.in (GCRY_MD_SM3): New. + +2017-10-17 Werner Koch + + api: New function gcry_mpi_get_ui. + + commit c6e42e7ec3d1046969d783c443c13aad7cb61bb8 + * src/gcrypt.h.in (gcry_mpi_get_ui): New. + (mpi_get_ui): New macro. + * src/libgcrypt.def, src/libgcrypt.vers: Add new function. + * src/visibility.c (gcry_mpi_get_ui): New. + * src/visibility.h: Mark that function. + (gcry_mpi_get_ui): New. + * mpi/mpiutil.c (MY_UINT_MAX): New macro. + (_gcry_mpi_get_ui): Re-implemented. This function existed but was + never imported or used. + * tests/mpitests.c (test_maxsize): Add some test for this function. + +2017-08-29 NIIBE Yutaka + + Tweak GCC version check. + + commit e4dc458b0b7dc9b8417a2177ef17822d9b9064ec + * src/global.c (_gcry_vcontrol): It's GCC 4.2 which started to support + diagnostic pragma. + + random: Fix warnings on Windows. + + commit 8126a6717c80d4fc1766d7f975e872bee2f9f203 + * random/random-csprng.c (lock_seed_file): Vars with no use. + + tests: Fix warnings on Windows. + + commit a848ef44470a524c05624afb54b92cf25595acd2 + * tests/fipsdrv.c (print_dsa_domain_parameters, print_ecdsa_dq): Fix. + + ecc: Fix scratch MPI. + + commit db3a8d6890fb4a6436e082b49378c0bd891563ca + * mpi/ec.c (ec_p_init): Check if scratch MPI is allocated. + + ecc: Fix ec_mulm_25519. + + commit 1d5f726668b9cc32d6bb601f2329987058146c6c + * mpi/ec.c (ec_mulm_25519): Improve reduction to 25519. + + ecc: Use 25519 method also for ed25519. + + commit fab712d654b2ccd24696ed90bc239860a128ad5b + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Don't use mpi_add + since it resizes to have more limbs. + * mpi/ec.c (point_resize): Fix for Edwards curve. + (ec_p_init): Support Edwards curve. + (_gcry_mpi_ec_get_affine): Use the methods. + (dup_point_edwards, add_points_edwards, sub_points_edwards): Ditto. + (_gcry_mpi_ec_mul_point): Resize MPIs of point to fixed size. + (_gcry_mpi_ec_curve_point): Use the methods. + + ecc: Clean up curve specific method support. + + commit 1ac3d3637dd80013b78e03b9b9f582091710d908 + * src/ec-context.h (struct mpi_ec_ctx_s): Remove MOD method. + * mpi/ec.c (ec_mod_25519): Remove. + (ec_p_init): Follow the removal of the MOD method. + + ecc: Relax condition for 25519 computations. + + commit e9be23c4ad9f42c9d3198c706f912b7e27f574bc + * mpi/ec.c (ec_addm_25519, ec_subm_25519, ec_mulm_25519): Check number + of limbs, allocated more is OK. + + ecc: Fix ec_mulm_25519. + + commit 449459a2770d3aecb1f36502bf1903e0cbd2873e + * mpi/ec.c (ec_mulm_25519): Fix the cases of 0 to 18. + + ecc: field specific routines for 25519. + + commit 9ed0fb37bd637d1a2e9498c24097cfeadec682ec + * mpi/ec.c (point_resize): Improve for X25519. + (mpih_set_cond): New. + (ec_mod_25519, ec_addm_25519, ec_subm_25519, ec_mulm_25519) + (ec_mul2_25519, ec_pow2_25519): New. + (ec_p_init): Fill by FIELD_TABLE. + + ecc: Add field specific computation methods. + + commit d4cd381defe5b37dda19bbda0986bdd38065bd31 + * src/ec-context.h (struct mpi_ec_ctx_s): Add methods. + * mpi/ec.c (ec_p_init): Initialize the default methods. + (montgomery_ladder): Use the methods. + +2017-08-27 Werner Koch + + Release 1.8.1. + + commit 80fd8615048c3897b91a315cca22ab139b056ccd + * configure.ac: Set LT version to C22/A2/R1. + +2017-08-27 NIIBE Yutaka + + ecc: Add input validation for X25519. + + commit bf76acbf0da6b0f245e491bec12c0f0a1b5be7c9 + * cipher/ecc.c (ecc_decrypt_raw): Add input validation. + * mpi/ec.c (ec_p_init): Use scratch buffer for bad points. + (_gcry_mpi_ec_bad_point): New. + +2017-08-07 Marcus Brinkmann + + cipher: Add OID for SHA384WithECDSA. + + commit a7bd2cbd3eabda88fb3cac5cbc13c21c97a7b315 + * cipher/sha512.c (oid_spec_sha384): Add SHA384WithECDSA. + +2017-08-02 Werner Koch + + tests: Fix a printf glitch for a Windows test. + + commit df1e221b3012e96bbffbc7d5fd70836a9ae1cc19 + * tests/t-convert.c (check_formats): Fix print format glitch on + Windows. + * tests/t-ed25519.c: Typo fix. + + tests: Add benchmarking option to tests/random. + + commit 21d0f068a721c022f955084c28304934fd198c5e + * tests/random.c: Always include unistd.h. + (prepend_srcdir): New. + (run_benchmark): New. + (main): Add options --benchmark and --with-seed-file. Print whetehr + JENT has been used. + * tests/t-common.h (split_fields_colon): New. Taken from GnuPG. + License of that code changed to LGPLv2.1. + + random: Add more bytes to the pool in addition to the seed file. + + commit eea36574f37830a6a80b4fad884825e815b2912f + * random/random-csprng.c (read_seed_file): Read 128 or 32 butes + depending on whether we have the Jitter RNG. + +2017-08-01 Jussi Kivilinna + + Add script to run basic tests with all supported HWF combinations. + + commit 94a92a3db909aef0ebcc009c2d7f5a2663e99004 + * tests/basic_all_hwfeature_combinations.sh: New. + * tests/Makefile.am: Add basic_all_hwfeature_combinations.sh. + +2017-07-29 Jussi Kivilinna + + Fix return value type for _gcry_md_extract. + + commit cf1528e7f2761774d06ace0de48f39c96b52dc4f + * src/gcrypt-int.h (_gcry_md_extract): Use gpg_err_code_t instead of + gpg_error_t for internal function return type. + + Fix building AArch32 CE implementations when target is ARMv6 arch. + + commit 4a7aa30ae9f3ce798dd886c2f2d4164c43027748 + * cipher/cipher-gcm-armv8-aarch32-ce.S: Select ARMv8 architecure. + * cipher/rijndael-armv8-aarch32-ce.S: Ditto. + * cipher/sha1-armv8-aarch32-ce.S: Ditto. + * cipher/sha256-armv8-aarch32-ce.S: Ditto. + * configure.ac (gcry_cv_gcc_inline_asm_aarch32_crypto): Ditto. + +2017-07-25 NIIBE Yutaka + + sexp: Add fall through annotation. + + commit b7cd44335d9cde43be6f693dca6399ed0762649c + * src/dumpsexp.c (parse_and_print): It's fall through. + +2017-07-24 Werner Koch + + random: Fix the command line munging for jitterbase. + + commit ac39522ab08fcd2483edc223334c6ab9d19e91f3 + * random/Makefile.am (o_flag_munging): Make the first sed term also + global. + +2017-07-19 NIIBE Yutaka + + Remove byte order mark. + + commit 1d8e4c2c3a7d0a4154caf5bd720a9a0b04179390 + * random/jitterentropy-base.c, random/jitterentropy.h: Remove + byte order mark. + +2017-07-18 Werner Koch + + Release 1.8.0. + + commit 850aca744eeda5fd410f478a0778e353045ac962 + + + mac: Add selftests for HMAC-SHA3-xxx. + + commit 95194c550443e8d5558856633f920daec8a975c4 + * cipher/hmac-tests.c (check_one): Add arg trunc and change all + callers to pass false. + (selftests_sha3): New. + (run_selftests): Call new selftests. + + api: New function gcry_mpi_point_copy. + + commit ecf73dafb7aafed0d0f339d07235b58c2113f94c + * src/gcrypt.h.in (gcry_mpi_point_copy): New. + (mpi_point_copy): New macro. + * src/visibility.c (gcry_mpi_point_copy): New. + * src/libgcrypt.def, src/libgcrypt.vers: Add function. + * mpi/ec.c (_gcry_mpi_point_copy): New. + * tests/t-mpi-point.c (set_get_point): Add test. + +2017-07-17 Werner Koch + + random: Minor fix for getting the rndjent version. + + commit 9d99c6b973caa7fdf93b53cf764066214f763803 + * random/rndjent.c (_gcry_rndjent_get_version): Always set R_ACTIVE. + * tests/version.c (test_get_config): Check number of fields for + rng-type. + +2017-07-07 NIIBE Yutaka + + mpi: Minor fix of mpi_pow. + + commit 61b0f52c1cc85bf8c3cac9aba40e28682e4e1b8b + * mpi/mpi-pow.c (_gcry_mpi_powm): Allocate size fix. + + mpi: Fix mpi_pow alternative implementation. + + commit 66ed4d53789892def7b237756d8a0ab28df9d222 + * mpi/mpi-pow.c + [USE_ALGORITHM_SIMPLE_EXPONENTIATION] (_gcry_mpi_powm): Use + mpi_set_cond. + + Fix mpi_pow alternative implementation. + + commit 619ebae9847831f43314a95cc3180f4b329b4d3b + * mpi/mpi-pow.c [USE_ALGORITHM_SIMPLE_EXPONENTIATION] (_gcry_mpi_powm): + Allocate size fix. + +2017-07-06 Werner Koch + + rsa: Use modern MPI allocation function. + + commit 208aba6f9a0475ba049f5a66fe02cf9a6214a887 + * cipher/rsa.c (secret_core_crt): Use modern function _gcry_mpi_snew. + +2017-07-05 Werner Koch + + build: Minor API fixes to fix build problems on AIX. + + commit 85a9a913da9ecc6b2cd6f743e90e49983251d706 + * src/gcrypt.h.in (gcry_error_from_errno): Fix return type. + * src/visibility.c (gcry_md_extract): Change return type to match the + prototype. + + tools: Add left shift to mpicalc. + + commit 0d30a4a9791d20c8881b5b12bd44611d9f4274cd + * src/mpicalc.c (do_lshift): New. + (main): Handle '<'. + +2017-07-04 NIIBE Yutaka + + mpi: Fix mpi_set_secure. + + commit 5feaf1cc8f22c1f8d19a34850d86fe190f1432e2 + * mpi/mpiutil.c (mpi_set_secure): Allocate by ->alloced. + +2017-06-29 NIIBE Yutaka + Werner Koch + + rsa: Add exponent blinding. + + commit 8725c99ffa41778f382ca97233183bcd687bb0ce + * cipher/rsa.c (secret_core_crt): Blind secret D with randomized + nonce R for mpi_powm computation. + +2017-06-28 NIIBE Yutaka + + Same computation for square and multiply. + + commit 78130828e9a140a9de4dafadbc844dbb64cb709a + * mpi/mpi-pow.c (_gcry_mpi_powm): Compare msize for max_u_size. Move + the assignment to base_u into the loop. Copy content refered by RP to + BASE_U except the last of the loop. + +2017-06-24 Werner Koch + + rsa: Minor refactoring. + + commit e6a3dc9900433bbc8ad362a595a3837318c28fa9 + * cipher/rsa.c (secret): Factor code out to ... + (secret_core_std, secret_core_crt): new functions. + +2017-06-23 Werner Koch + + random: Add missing dependency. + + commit d091610377b2c92cf385282b1adfc30fa6cd5c75 + * random/Makefile.am (EXTRA_librandom_la_SOURCES): Fix file name. + (rndjent.o, rndjent.lo): Depend on jitterentropy-base-user.h. + + random: Update jitterentropy to 2.1.0. + + commit 8dfae89ecd3e9ae0967586cb38d12ef9111fc7cd + * random/rndjent.c (jent_get_nstime, jent_zfree) + (jent_fips_enabled, jent_zalloc): Move functions and macros to ... + * random/jitterentropy-base-user.h: this file. That files was not + used before. + * random/Makefile.am (EXTRA_librandom_la_SOURCES): Add + jitterentropy-base-user. + * random/jitterentropy-base.c: Update to version 2.1.0. + * random/jitterentropy.h: Ditto. + +2017-06-21 Werner Koch + + api: New function gcry_get_config. + + commit 27148e60ba15b0cb73b47a75c688fcb48a1a3444 + * src/misc.c (_gcry_log_info_with_dummy_fp): Remove. + * src/global.c (print_config): New arg WHAT. Remove arg FNC and use + gpgrt_fprintf directly. + (_gcry_get_config): New. + (_gcry_vcontrol) : Use _gcry_get_config instead + of print_config. + * src/gcrypt.h.in (gcry_get_config): New. + * src/libgcrypt.def, src/libgcrypt.vers: Add new function. + * src/visibility.c (gcry_get_config): New. + * src/visibility.h: Mark new function. + + * tests/version.c (test_get_config): New. + (main): Call new test. + + random: Allow building rndjent on non-x86. + + commit c2319464b03e61aaf34ef6d5f4b59b0c0483a373 + * random/jitterentropy-base.c (jent_version): Uncomment function. + * random/rndjent.c: Include time.h + (JENT_USES_RDTSC): New. + (JENT_USES_GETTIME): New. + (JENT_USES_READ_REAL_TIME): New. + (jent_get_nstime): Support clock_gettime and AIX specific + function. Taken from Stephan Müller's code. + (is_rng_available): New. + (_gcry_rndjent_dump_stats): Use that function. + (_gcry_rndjent_poll): Use that fucntion. Allow an ADD of NULL for an + intialize only mode. + (_gcry_rndjent_get_version): New. + +2017-06-18 Jussi Kivilinna + + rijndael-padlock: change asm operands from read-only to read/write. + + commit 32b4ab209067f6f08b87b27bc78ec27dc497b708 + * cipher/rijndael-padlock.c (do_padlock): Change ESI/EDI/ECX to use + read/write operands as XCRYPT instruction modifies these registers. + +2017-06-16 Werner Koch + + random: Make rndjent.c NTG.1 compliant. + + commit 82bc052eda5b3897724c7ad11e54f8203e8e88e9 + * random/rndjent.c (_gcry_rndjent_poll): Hash the retrieved jitter. + + md: Optimize gcry_md_hash_buffers for SHA-256 and SHA-512. + + commit e6f90a392a1fd59b19b16f7a2bc7c439ae369d5f + * cipher/sha256.c (_gcry_sha256_hash_buffer): New. + (_gcry_sha256_hash_buffers): New. + * cipher/sha512.c (_gcry_sha512_hash_buffer): New. + (_gcry_sha512_hash_buffers): New. + * cipher/md.c (_gcry_md_hash_buffer): Optimize for SHA246 and SHA512. + (_gcry_md_hash_buffers): Ditto. + + random: Allow building rndjent.c with stats collecting enabled. + + commit ee3a74f5539cbc5182ce089994e37c16ce612149 + * random/rndjent.c: Change license to the one used by jitterentropy.h. + (jent_init_statistic): New. + (jent_bit_count): New. + (jent_statistic_copy_stat): new. + (jent_calc_statistic): New. + + New global config option "only-urandom". + + commit 8f6082e95f30c1ba68d2de23da90146f87f0c66c + * random/rand-internal.h (RANDOM_CONF_ONLY_URANDOM): New. + * random/random.c (_gcry_random_read_conf): Add option "only-urandom". + * random/rndlinux.c (_gcry_rndlinux_gather_random): Implement that + option. + * tests/keygen.c (main): Add option --no-quick for better manual + tests. + + Implement global config file /etc/gcrypt/random.conf. + + commit b05a4abc358b204dba343d9cfbd59fdc828c1686 + * src/hwfeatures.c (my_isascii): Move macro to ... + * src/g10lib.h: here. + * tests/random.c (main): Dump random stats. + * random/random.c (RANDOM_CONF_FILE): New. + (_gcry_random_read_conf): New. + (_gcry_random_dump_stats): Call rndjent stats. + * random/rndjent.c (jent_rng_totalcalls, jent_rng_totalbytes): New. + (_gcry_rndjent_poll): Take care of config option disable-jent. Wipe + buffer. Bump counters. + (_gcry_rndjent_dump_stats): New. + +2017-06-14 Werner Koch + + random: Add jitter RND based entropy collector. + + commit f5e7763ddca59dcd9ac9f2f4d50cb41b14a34a9e + * random/rndjent.c: New. + * random/rndlinux.c (_gcry_rndlinux_gather_random): Use rndjent. + * random/rndw32.c (_gcry_rndw32_gather_random): Use rndjent. + (slow_gatherer): Fix compiler warning. + * random/Makefile.am (librandom_la_SOURCES): Add rndjent.c + (EXTRA_librandom_la_SOURCES): Add jitterentropy-base.c and + jitterentropy.h. + (rndjent.o, rndjent.lo): New rules. + * configure.ac: New option --disbale-jent-support + (ENABLE_JENT_SUPPORT): New ac-define. + + cipher: New helper function rol64. + + commit 6c882fb1fdb6c7cba2215fa7391110d63e24b9dc + * cipher/bithelp.h (rol64): New inline functions. + + New hardware feature flag HWF_INTEL_RDTSC. + + commit 06f303a633ea2b992259688bef2b023c3f388f73 + * src/g10lib.h (HWF_INTEL_RDTSC): New. + * src/hwfeatures.c (hwflist): Add "intel-rdtsc". + * src/hwf-x86.c (detect_x86_gnuc): Get EDX features and test for TSC. + + random: Changes to original Jitter RNG implementation. + + commit a44c45675f8b631e11048a540bb1fbb7a022ebb4 + * random/jitterentropy-base.c: Change double underscore symbols and + make all functions static. + * random/jitterentropy.h: Likewise. + +2017-06-13 Stephan Mueller + + random: Add original Jitter RNG implementation. + + commit f0ae18ecf48fbe2da0b9fb3f354d0dd3173d91d3 + * random/jitterentropy-base-user.h: New. + * random/jitterentropy-base.c: New. + * random/jitterentropy.h: New. + +2017-06-08 Werner Koch + + build: Fix ChangeLog building for builds from other worktrees. + + commit cdfd7ea72a44657f037dd0dbba6e5ea0c2b344aa + * Makefile.am (gen-ChangeLog): Test for existance of ".git" regardless + on whether it is a file or directory. + +2017-06-02 NIIBE Yutaka + + secmem: Fix SEGV and stat calculation. + + commit e0958debe1a7db1bec1283115cdc6a14bf3b43e5 + * src/secmem (init_pool): Care about the header size. + (_gcry_secmem_malloc_internal): Likewise. + (_gcry_secmem_malloc_internal): Use mb->size for stats. + +2017-06-01 Jo Van Bulck + + ecc: Store EdDSA session key in secure memory. + + commit 5a22de904a0a366ae79f03ff1e13a1232a89e26b + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_sign): use mpi_snew to allocate + session key. + +2017-05-31 Werner Koch + + api: Deprecate gcry_md_info. + + commit 45c39340c9926c2c5801dbab7609687c41e9ff1f + + +2017-05-30 Werner Koch + + mpi: Distribute asm files for aarch64 and asm. + + commit c65f9558f12ffa2810538ef616e71b4052dacb81 + * mpi/aarch64/distfiles: New. + * mpi/arm/distfiles: New. + + mpi: Distribute asm definitions for amd64. + + commit 87e481137debabb7f989d7fa9b1c21c336e10c98 + * mpi/amd64/distfiles: Add mpi-asm-defs.h. + +2017-05-23 Werner Koch + + cipher: Fix compiler warnings. + + commit d764c9894013727ff82eb194da6030209c273528 + * cipher/poly1305.c (poly1305_default_ops): Move to the top. Add + prototypes and compile only if USE_SSE2 is not defined. + (poly1305_init_ext_ref32): Compile only if USE_SSE2 is not defined. + (poly1305_blocks_ref32): Ditto. + (poly1305_finish_ext_ref32): Ditto. + + doc: Comment fixes. + + commit c1bb3d9fdb6fe5f336af1d5a03fc42bfdc1f8b0b + + +2017-05-18 Jussi Kivilinna + + rijndael-ssse3: fix functions calls from assembly blocks. + + commit 4cd94994a9abec9b92fa5972869baf089a28fa76 + * cipher/rijndael-ssse3-amd64.c (PUSH_STACK_PTR, POP_STACK_PTR): New. + (vpaes_ssse3_prepare_enc, vpaes_ssse3_prepare_dec) + (_gcry_aes_ssse3_do_setkey, _gcry_aes_ssse3_prepare_decryption) + (do_vpaes_ssse3_enc, do_vpaes_ssse3_dec): Use PUSH_STACK_PTR and + POP_STACK_PTR. + + chacha20-armv7-neon: fix to use fast code path when memory is aligned. + + commit 68861ae5d3e007d7a39f14ea27dc3dd8ef13ba02 + * cipher/chacha20-armv7-neon.S (UNALIGNED_LDMIA4): Uncomment + instruction for jump to aligned code path. + + Move data in AMD64 assembly to text section. + + commit 1a094bc5b2aa730833faf593a931d4e5d7f9ab4d + * cipher/camellia-aesni-avx-amd64.S: Move data to .text section to + ensure that RIP relative addressing of data will work. + * cipher/camellia-aesni-avx2-amd64.S: Ditto. + * cipher/chacha20-avx2-amd64.S: Ditto. + * cipher/chacha20-ssse3-amd64.S: Ditto. + * cipher/des-amd64.S: Ditto. + * cipher/serpent-avx2-amd64.S: Ditto. + * cipher/sha1-avx-amd64.S: Ditto. + * cipher/sha1-avx-bmi2-amd64.S: Ditto. + * cipher/sha1-ssse3-amd64.S: Ditto. + * cipher/sha256-avx-amd64.S: Ditto. + * cipher/sha256-avx2-bmi2-amd64.S: Ditto. + * cipher/sha256-ssse3-amd64.S: Ditto. + * cipher/sha512-avx-amd64.S: Ditto. + * cipher/sha512-avx2-bmi2-amd64.S: Ditto. + * cipher/sha512-ssse3-amd64.S: Ditto. + + cast5-amd64: use 64-bit relocation with large PIC memory model. + + commit ff02fca39c83bcf30c79368611ac65e273e77f6c + * cipher/cast5-amd64.S [__code_model_large__] + (GET_EXTERN_POINTER): New. + +2017-05-13 Jussi Kivilinna + + Fix building with x86-64 medium and large memory models. + + commit 434d4f2af39033fc626044ba9a060da298522293 + * cipher/cast5-amd64.S [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] + (GET_EXTERN_POINTER): Load 64-bit address instead of 32-bit. + * cipher/rijndael.c (do_encrypt, do_decrypt) + [USE_AMD64_ASM && !HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Load + table pointer through register instead of generic reference. + +2017-04-04 NIIBE Yutaka + + mpi: Simplify mpi_powm. + + commit 719468e53133d3bdf12156c5bfdea2bf15f9f6f1 + * mpi/mpi-pow.c (_gcry_mpi_powm): Simplify the loop. + +2017-03-08 Justus Winter + + build: Use macOS' compatibility macros to enable all features. + + commit 654024081cfa103c87bb163b117ea3568171d408 + * configure.ac: On macOS, use the compatibility macros to expose every + feature of the libc. This is the equivalent of _GNU_SOURCE on GNU + libc. + +2017-02-27 Jussi Kivilinna + + Add BLAKE2b and BLAKE2s hash algorithms (RFC 7693) + + commit 5bd530b8a4624f101b8d42e68f1b28bcc13f4f76 + * cipher/blake2.c: New. + * cipher/Makefile.am: Add 'blake2.c'. + * cipher/md.c (digest_list, prepare_macpads): Add BLAKE2. + (md_setkey): New. + (_gcry_md_setkey): Call 'md_setkey' for non-HMAC md. + * configure.ac: Add BLAKE2 digest. + * doc/gcrypt.texi: Add BLAKE2. + * src/cipher.h (_gcry_blake2_init_with_key) + (_gcry_digest_spec_blake2b_512, _gcry_digest_spec_blake2b_384) + (_gcry_digest_spec_blake2b_256, _gcry_digest_spec_blake2b_160) + (_gcry_digest_spec_blake2s_256, _gcry_digest_spec_blake2s_224) + (_gcry_digest_spec_blake2s_160, _gcry_digest_spec_blake2s_128): New. + * src/gcrypt.h.in (GCRY_MD_BLAKE2B_512, GCRY_MD_BLAKE2B_384) + (GCRY_MD_BLAKE2B_256, GCRY_MD_BLAKE2B_160, GCRY_MD_BLAKE2S_256) + (GCRY_MD_BLAKE2S_224, GCRY_MD_BLAKE2S_160, GCRY_MD_BLAKE2S_128): New. + * tests/basic.c (check_one_md): Add testing for keyed hashes. + (check_digests): Add BLAKE2 test vectors; Add testing for keyed hashes. + * tests/blake2b.h: New. + * tests/blake2s.h: New. + * tests/Makefile.am: Add 'blake2b.h' and 'blake2s.h'. + + Fix building with clang on ARM64/FreeBSD. + + commit da213db2c6cda6f57e5853e8c591d69bfa1cfa74 + * cipher/cipher-gcm-armv8-aarch64-ce.S: Use '.cpu generic+simd+crypto' + instead of '.arch armv8-a+crypto'. + * cipher/rijndael-armv8-aarch64-ce.S: Ditto. + * cipher/sha1-armv8-aarch64-ce.S: Ditto. + * cipher/sha256-armv8-aarch64-ce.S: Ditto. + * configure.ac (gcry_cv_gcc_inline_asm_aarch64_neon): Ditto. + (gcry_cv_gcc_inline_asm_aarch64_crypto): Ditto; and include NEON + instructions to crypto instructions check. + +2017-02-07 Justus Winter + + Fix building with a pre C99 compiler. + + commit 75d91ffeaf83098ade325bb3b6b2c8a76eb1f6a6 + * cipher/cipher-cfb.c (_gcry_cipher_cfb8_encrypt): Move the + declaration of 'i' out of the loop. + (_gcry_cipher_cfb8_decrypt): Likewise. + +2017-02-04 Mathias L. Baumann + + Implement CFB with 8-bit mode. + + commit d1ee9a660571ce4a998c9ab2299d4f2419f99127 + * cipher/cipher-cfb.c (_gcry_cipher_cfb8_encrypt) + (_gcry_cipher_cfg8_decrypt): Add 8-bit variants of decrypt/encrypt + functions. + * cipher/cipher-internal.h (_gcry_cipher_cfb8_encrypt) + (_gcry_cipher_cfg8_decrypt): Ditto. + * cipher/cipher.c: Adjust code flow to work with GCRY_CIPHER_MODE_CFB8. + * tests/basic.c: Add tests for cfb8 with AES and 3DES. + +2017-02-04 Jussi Kivilinna + + rndhw: add missing "memory" clobbers. + + commit c67c728478e8f47b6e8296b643fd35d66d4a1052 + * random/rndhw.c: (poll_padlock, rdrand_long): Add "memory" to asm + clobbers. + + Add UNLIKELY and LIKELY macros. + + commit 4b7451d3e8e7b87d8e407fbbd924ad5b13bd0f00 + * src/g10lib.h (LIKELY, UNLIKELY): New. + (gcry_assert): Use LIKELY for assert check. + (fast_wipememory2_unaligned_head): Use UNLIKELY for unaligned + branching. + * cipher/bufhelp.h (buf_cpy, buf_xor, buf_xor_1, buf_xor_2dst) + (buf_xor_n_copy_2): Ditto. + + rndhw: avoid type-punching. + + commit 37b537600f33fcf8e1c8dc2c658a142fbba44199 + * random/rndhw.c (rdrand_long, rdrand_nlong): Add 'volatile' for + pointer. + (poll_drng): Convert buffer to 'unsigned long[]' and make use of DIM + macro. + +2017-01-28 Jussi Kivilinna + + hwf-x86: avoid type-punching. + + commit 1407317a6112a23d4fec5827a9d74faef4196f66 + * src/hwf-x86.c (detect_x86_gnuc): Use union for vendor_id. + + cipher: add explicit blocksize checks to allow better optimization. + + commit efa9042f82ffed3d076b8e26ac62d29e00bb756a + * cipher/cipher-cbc.c (_gcry_cipher_cbc_encrypt) + (_gcry_cipher_cbc_decrypt): Add explicit check for cipher blocksize of + 64-bit or 128-bit. + * cipher/cipher-cfb.c (_gcry_cipher_cfb_encrypt) + (_gcry_cipher_cfb_decrypt): Ditto. + * cipher/cipher-cmac.c (cmac_write, cmac_generate_subkeys) + (cmac_final): Ditto. + * cipher/cipher-ctr.c (_gcry_cipher_ctr_encrypt): Ditto. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_encrypt): Ditto. + + bufhelp: use unaligned dword and qword types for endianess helpers. + + commit e7b941c3de9c9b6319298c02f844cc0cadbf8562 + * cipher/bufhelp.h (BUFHELP_UNALIGNED_ACCESS): New, defined + if attributes 'packed', 'aligned' and 'may_alias' are supported. + (BUFHELP_FAST_UNALIGNED_ACCESS): Define if have + BUFHELP_UNALIGNED_ACCESS. + + rijndael-aesni: fix u128_t strict-aliasing rule breaking. + + commit 92b4a29d2453712192ced2d7226abc49679dcb1e + * cipher/rijndael-aesni.c (u128_t): Add attributes to tell GCC and clang + that casting from 'char *' to 'u128_t *' is ok. + + cipher-xts: fix pointer casting to wrong alignment and aliasing. + + commit 4f31d816dcc1e95dc647651e92acbdfed53f5c14 + * cipher/cipher-xts.c (xts_gfmul_byA, xts_inc128): Use buf_get_le64 + and buf_put_le64 for accessing data; Change parameter pointers to + 'unsigned char *' type. + (_gcry_cipher_xts_crypt): Do not cast buffer pointers to 'u64 *' + for helper functions. + + crc-intel-pclmul: fix undefined behavior with unaligned access. + + commit 55cf1b5588705cab5f45e2817c4aa1d204dc0042 + * cipher/crc-intel-pclmul.c (u16_unaligned_s): New. + (crc32_reflected_less_than_16, crc32_less_than_16): Use + 'u16_unaligned_s' for unaligned memory access. + + configure.ac: fix attribute checks. + + commit b29b1b9f576f501d4b993be0a751567045274a1a + * configure.ac: Add -Werror flag for attribute checks. + + configure.ac: fix may_alias attribute check. + + commit 136c8416ea540dd126be3997d94d7063b3aaf577 + * configure.ac: Test may_alias attribute on type, not on variable. + + bufhelp: add 'may_alias' attribute for properly aligned 'bufhelp_int_t' + + commit d1ae52a0e23308f33b78cffeba56005b687f23c0 + * cipher/bufhelp.h [!BUFHELP_FAST_UNALIGNED_ACCESS] + (bufhelp_int_t): Add 'may_alias' attribute. + +2017-01-27 Werner Koch + + w32: New envvar GCRYPT_RNDW32_DBG. + + commit a351fbde8548ce3f57298c618426f043844fbc78 + * random/rndw32.c (_gcry_rndw32_gather_random): Use getenv to set + DEBUG_ME. + +2017-01-23 Jussi Kivilinna + + rijndael-ssse3-amd64: fix building on x32. + + commit 39b9302da5d08bd52688d20befe626fee0b6c41d + * cipher/rijndael-ssse3-amd64.c: Use 64-bit call instructions + with 64-bit registers. + + bufhelp: use 'may_alias' attribute unaligned pointer types. + + commit bf9e0b79e620ca2324224893b07522462b125412 + * configure.ac (gcry_cv_gcc_attribute_may_alias) + (HAVE_GCC_ATTRIBUTE_MAY_ALIAS): New check for 'may_alias' attribute. + * cipher/bufhelp.h (BUFHELP_FAST_UNALIGNED_ACCESS): Enable only if + HAVE_GCC_ATTRIBUTE_MAY_ALIAS is defined. + [BUFHELP_FAST_UNALIGNED_ACCESS] (bufhelp_int_t, bufhelp_u32_t) + (bufhelp_u64_t): Add 'may_alias' attribute. + * src/g10lib.h (fast_wipememory_t): Add HAVE_GCC_ATTRIBUTE_MAY_ALIAS + defined check; Add 'may_alias' attribute. + +2017-01-18 Werner Koch + + random: Call getrandom before select and emitting a progress callback. + + commit 623aab8a940ea61afe3fef650ad485a755ed9fe7 + * random/rndlinux.c (_gcry_rndlinux_gather_random): Move the getrandom + call before the select. + +2017-01-06 Jussi Kivilinna + + mpi: amd64: fix too large jump alignment in mpih-rshift. + + commit ddcfe31e2425e88b280e7cdaf3f0eaaad8ccc023 + * mpi/amd64/mpih-rshift.S (_gcry_mpih_rshift): Use 16-byte alignment + with 'ALIGN(4)' instead of 256-byte. + + rijndael-ssse3: move assembly functions to separate source-file. + + commit 54c57bc49edb5c00e9ed8103cc4837bb72c5e863 + * cipher/Makefile.am: Add 'rinjdael-ssse3-amd64-asm.S'. + * cipher/rinjdael-ssse3-amd64-asm.S: Moved assembly functions + here ... + * cipher/rinjdael-ssse3-amd64.c: ... from this file. + (_gcry_aes_ssse3_enc_preload, _gcry_aes_ssse3_dec_preload) + (_gcry_aes_ssse3_shedule_core, _gcry_aes_ssse3_encrypt_core) + (_gcry_aes_ssse3_decrypt_core): New. + (vpaes_ssse3_prepare_enc, vpaes_ssse3_prepare_dec) + (_gcry_aes_ssse3_do_setkey, _gcry_aes_ssse3_prepare_decryption) + (do_vpaes_ssse3_enc, do_vpaes_ssse3_dec): Update to use external + assembly functions; remove 'aes_const_ptr' variable usage. + (_gcry_aes_ssse3_encrypt, _gcry_aes_ssse3_decrypt) + (_gcry_aes_ssse3_cfb_enc, _gcry_aes_ssse3_cbc_enc) + (_gcry_aes_ssse3_ctr_enc, _gcry_aes_ssse3_cfb_dec) + (_gcry_aes_ssse3_cbc_dec, ssse3_ocb_enc, ssse3_ocb_dec) + (_gcry_aes_ssse3_ocb_auth): Remove 'aes_const_ptr' variable usage. + * configure.ac: Add 'rinjdael-ssse3-amd64-asm.lo'. + + Add AVX2/vpgather bulk implementation of Twofish. + + commit c59a8ce51ceb9a80169c44ef86a67e95cf8528c3 + * cipher/Makefile.am: Add 'twofish-avx2-amd64.S'. + * cipher/twofish-avx2-amd64.S: New. + * cipher/twofish.c (USE_AVX2): New. + (TWOFISH_context) [USE_AVX2]: Add 'use_avx2' member. + (ASM_FUNC_ABI): New. + (twofish_setkey): Add check for AVX2 and fast VPGATHER HW features. + (_gcry_twofish_avx2_ctr_enc, _gcry_twofish_avx2_cbc_dec) + (_gcry_twofish_avx2_cfb_dec, _gcry_twofish_avx2_ocb_enc) + (_gcry_twofish_avx2_ocb_dec, _gcry_twofish_avx2_ocb_auth): New. + (_gcry_twofish_ctr_enc, _gcry_twofish_cbc_dec, _gcry_twofish_cfb_dec) + (_gcry_twofish_ocb_crypt, _gcry_twofish_ocb_auth): Add AVX2 bulk + handling. + (selftest_ctr, selftest_cbc, selftest_cfb): Increase nblocks from + 3+X to 16+X. + * configure.ac: Add 'twofish-avx2-amd64.lo'. + * src/g10lib.h (HWF_INTEL_FAST_VPGATHER): New. + * src/hwf-x86.c (detect_x86_gnuc): Add detection for + HWF_INTEL_FAST_VPGATHER. + * src/hwfeatures.c (HWF_INTEL_FAST_VPGATHER): Add + "intel-fast-vpgather" for HWF_INTEL_FAST_VPGATHER. + + Add XTS cipher mode. + + commit 232a129b1f915fc54881506e4b07c89cf84932e6 + * cipher/Makefile.am: Add 'cipher-xts.c'. + * cipher/cipher-internal.h (gcry_cipher_handle): Add 'bulk.xts_crypt' + and 'u_mode.xts' members. + (_gcry_cipher_xts_crypt): New prototype. + * cipher/cipher-xts.c: New. + * cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey) + (cipher_reset, cipher_encrypt, cipher_decrypt): Add XTS mode handling. + * doc/gcrypt.texi: Add XTS mode to documentation. + * src/gcrypt.h.in (GCRY_CIPHER_MODE_XTS, GCRY_XTS_BLOCK_LEN): New. + * tests/basic.c (do_check_xts_cipher, check_xts_cipher): New. + (check_bulk_cipher_modes): Add XTS test-vectors. + (check_one_cipher_core, check_one_cipher, check_ciphers): Add XTS + testing support. + (check_cipher_modes): Add XTS test. + * tests/bench-slope.c (bench_xts_encrypt_init) + (bench_xts_encrypt_do_bench, bench_xts_decrypt_do_bench) + (xts_encrypt_ops, xts_decrypt_ops): New. + (cipher_modes, cipher_bench_one): Add XTS. + * tests/benchmark.c (cipher_bench): Add XTS testing. + +2017-01-04 Jussi Kivilinna + + rijndael-ssse3: fix counter operand from read-only to read/write. + + commit aada604594fd42224d366d3cb98f67fd3b989cd6 + * cipher/rijndael-ssse3-amd64.c (_gcry_aes_ssse3_ctr_enc): Change + 'ctrlow' operand from read-only to read-write. + +2017-01-03 Werner Koch + + Extend GCRYCTL_PRINT_CONFIG to print compiler version. + + commit 98b49695b1ffe3c406ae39a45051b8594f903b9d + * src/global.c (print_config): Print version of libgpg-error and used + compiler. + + tests: Add option --disable-hwf to the version utility. + + commit 3582641469f1c74078f0d758c4d5458cc0ee5649 + * src/hwfeatures.c (_gcry_disable_hw_feature): Rewrite to allow + passing a colon delimited feature set. + (parse_hwf_deny_file): Remove unused var I. + * tests/version.c (main): Add options --verbose and --disable-hwf. + +2016-12-15 Werner Koch + Nicolas Porcel + + Fix regression in broken mlock detection. + + commit 0a90f87799903a3fb97189ef7cba19e7b3534e1c + * acinclude.m4 (GNUPG_CHECK_MLOCK): Fix typo EGAIN->EAGAIN. + +2016-12-10 Jussi Kivilinna + + hwfeatures: add 'all' for disabling all hardware features. + + commit c83d0d2a26059cf471d09f5cb8e7fc5d76c4907b + * .gitignore: Add 'tests/basic-disable-all-hwf'. + * configure.ac: Ditto. + * tests/Makefile.am: Ditto. + * src/hwfeatures.c (_gcry_disable_hw_feature): Match 'all' for + masking all HW features off. + (parse_hwf_deny_file): Use '_gcry_disable_hw_feature' for matching. + * tests/basic-disable-all-hwf.in: New. + + tests/hashtest-256g: add missing executable extension for Win32. + + commit 2b7b227b8a0bd5ff286258bc187782efac180a7e + * tests/hashtest-256g.in: Add @EXEEXT@. + + OCB ARM CE: Move ocb_get_l handling to assembly part. + + commit 5c418e597f0f20a546d953161695e6caf1f57689 + * cipher/rijndael-armv8-aarch32-ce.S: Add OCB 'L_{ntz(i)}' calculation. + * cipher/rijndael-armv8-aarch64-ce.S: Ditto. + * cipher/rijndael-armv8-ce.c (_gcry_aes_ocb_enc_armv8_ce) + (_gcry_aes_ocb_dec_armv8_ce, _gcry_aes_ocb_auth_armv8_ce) + (ocb_cryt_fn_t): Updated arguments. + (_gcry_aes_armv8_ce_ocb_crypt, _gcry_aes_armv8_ce_ocb_auth): Remove + 'ocb_get_l' handling and splitting input to 32 block chunks, instead + pass full buffers to assembly. + + OCB: Move large L handling from bottom to upper level. + + commit 2d2e5286d53e1f62fe040dff4c6e01961f00afe2 + * cipher/cipher-ocb.c (_gcry_cipher_ocb_get_l): Remove. + (ocb_get_L_big): New. + (_gcry_cipher_ocb_authenticate): L-big handling done in upper + processing loop, so that lower level never sees the case where + 'aad_nblocks % 65536 == 0'; Add missing stack burn. + (ocb_aad_finalize): Add missing stack burn. + (ocb_crypt): L-big handling done in upper processing loop, so that + lower level never sees the case where 'data_nblocks % 65536 == 0'. + * cipher/cipher-internal.h (_gcry_cipher_ocb_get_l): Remove. + (ocb_get_l): Remove 'l_tmp' usage and simplify since input + is more limited now, 'N is not multiple of 65536'. + * cipher/rijndael-aesni.c (get_l): Remove. + (aesni_ocb_enc, aesni_ocb_dec, _gcry_aes_aesni_ocb_auth): Remove + l_tmp; Use 'ocb_get_l'. + * cipher/rijndael-ssse3-amd64.c (get_l): Remove. + (ssse3_ocb_enc, ssse3_ocb_dec, _gcry_aes_ssse3_ocb_auth): Remove + l_tmp; Use 'ocb_get_l'. + * cipher/camellia-glue.c: Remove OCB l_tmp usage. + * cipher/rijndael-armv8-ce.c: Ditto. + * cipher/rijndael.c: Ditto. + * cipher/serpent.c: Ditto. + * cipher/twofish.c: Ditto. + + OCB: remove 'int64_t' usage. + + commit 161d339f48c03be7fd0f4249d730f7f1767ef8e4 + * cipher/cipher-ocb.c (double_block): Use alternative way to generate + sign-bit mask, without 'int64_t'. + + random-drbg: use bufhelp function for big-endian store. + + commit 0b03b658bebc69a84d87ef13f9b60a27b0c42305 + * random/random-drbg.c (drbg_cpu_to_be32): Remove. + (drbg_ctr_df, drbg_hash_df): Use 'buf_put_be32' instead of + 'drbg_cpu_to_be32'. + +2016-12-09 Werner Koch + + Improve handling of mlock error codes. + + commit 618b8978f46f4011c11512fd5f30c15e01652e2e + * acinclude.m4 (GNUPG_CHECK_MLOCK): Check also for EAGAIN which is a + legitimate return code and does not indicate a broken mlock(). + * src/secmem.c (lock_pool_pages): Test ERR instead of ERRNO which + could have been overwritten by cap_from+text et al. + +2016-12-08 Stephan Mueller + + random: Eliminate unneeded memcpy invocations in the DRBG. + + commit 656395ba4cf34f42dda3a120bda3ed1220755a3d + * random/random-drbg.c (drbg_hash): Remove arg 'outval' and return a + pointer instead. + (drbg_instantiate): Reduce size of scratchpad. + (drbg_hmac_update): Avoid use of scratch buffers for the hash. + (drbg_hmac_generate, drbg_hash_df): Ditto. + (drbg_hash_process_addtl): Ditto. + (drbg_hash_hashgen): Ditto. + (drbg_hash_generate): Ditto. + + random: Add performance improvements for the DRBG. + + commit 20886fdcb841b0bf89bb1d44303d42f1804e38cb + * random/random-drbg.c (struct drbg_state_ops_s): New function + pointers 'crypto_init' and 'crypto-fini'. + (struct drbg_state_s): New fields 'priv_data', 'ctr_handle', and + 'ctr_null'. + (drbg_hash_init, drbg_hash_fini): New. + (drbg_hmac_init, drbg_hmac_setkey): New. + (drbg_sym_fini, drbg_sym_init, drbg_sym_setkey): New. + (drbg_sym_ctr): New. + (drbg_ctr_bcc): Set the key. + (drbg_ctr_df): Ditto. + (drbg_hmac_update): Ditto. + (drbg_hmac_generate): Replace drgb_hmac by drbg_hash. + (drbg_hash_df): Ditto. + (drbg_hash_process_addtl): Ditto. + (drbg_hash_hashgen): Ditto. + (drbg_ctr_update): Rework. + (drbg_ctr_generate): Rework. + (drbg_ctr_ops): Init new functions pointers. + (drbg_uninstantiate): Call fini function. + (drbg_instantiate): Call init function. + + cipher: New function for reading the counter in CTR mode. + + commit 227099f179df9dcf083d0ef6be9883c775df0874 + * cipher/cipher.c (gcry_cipher_getctr): New. + +2016-12-07 Werner Koch + + Document the overflow pools and add a stupid test case. + + commit 95bac312644ad45e486c94c2efd25d0748b9a20b + * tests/t-secmem.c (test_secmem_overflow): New func. + (main): Disable warning and call new function. + + Implement overflow secmem pools for xmalloc style allocators. + + commit b6870cf25c0b1eb9c127a94af8326c446421a472 + * src/secmem.c (pooldesc_s): Add fields next, cur_alloced, and + cur_blocks. + (cur_alloced, cur_blocks): Remove vars. + (ptr_into_pool_p): Make it inline. + (stats_update): Add arg pool and update the new pool specific + counters. + (_gcry_secmem_malloc_internal): Add arg xhint and allocate overflow + pools as needed. + (_gcry_secmem_malloc): Pass XHINTS along. + (_gcry_secmem_realloc_internal): Ditto. + (_gcry_secmem_realloc): Ditto. + (_gcry_secmem_free_internal): Take multiple pools in account. Add + return value to indicate whether the arg was freed. + (_gcry_secmem_free): Add return value to indicate whether the arg was + freed. + (_gcry_private_is_secure): Take multiple pools in account. + (_gcry_secmem_term): Release all pools. + (_gcry_secmem_dump_stats): Print stats for all pools. + * src/stdmem.c (_gcry_private_free): Replace _gcry_private_is_secure + test with a direct call of _gcry_secmem_free to avoid double checking. + + Give the secmem allocators a hint when a xmalloc calls them. + + commit b7df907dca4d525f8930c533b763ffce44ceed87 + * src/secmem.c (_gcry_secmem_malloc): New not yet used arg XHINT. + (_gcry_secmem_realloc): Ditto. + * src/stdmem.c (_gcry_private_malloc_secure): New arg XHINT to be + passed to the secmem functions. + (_gcry_private_realloc): Ditto. + * src/g10lib.h (GCRY_ALLOC_FLAG_XHINT): New. + * src/global.c (do_malloc): Pass this flag as XHINT to the private + allocator. + (_gcry_malloc_secure): Factor code out to ... + (_gcry_malloc_secure_core): this. Add arg XHINT. + (_gcry_realloc): Factor code out to ... + (_gcry_realloc_core): here. Add arg XHINT. + (_gcry_strdup): Factor code out to ... + (_gcry_strdup_core): here. Add arg XHINT. + (_gcry_xrealloc): Use the core function and pass true for XHINT. + (_gcry_xmalloc_secure): Ditto. + (_gcry_xstrdup): Ditto. + + tests: New test t-secmem. + + commit e366c19b34922c770af82cd035fd815680b29dee + * src/secmem.c (_gcry_secmem_dump_stats): Add arg EXTENDED and adjust + caller. + * src/gcrypt-testapi.h (PRIV_CTL_DUMP_SECMEM_STATS): New. + * src/global.c (_gcry_vcontrol): Implement that. + * tests/t-secmem.c: New. + * tests/Makefile.am (tests_bin): Add that test. + +2016-12-06 Werner Koch + + Fix compiler warning about possible-NULL-dreference. + + commit 995ce697308320c6a52a307f83dc49eeb8d784b4 + * src/mpi.h (mpi_is_const, mpi_is_immutable): Do check arg before + deref-ing. The are only used at places where the arg shall not be NULL. + + Fix possible NULL-deref in gcry_log_debugsxp. + + commit 984a97f0750f812f0ad3c343ee6a67560953a504 + * src/misc.c (_gcry_log_printsxp): Prevent passing NULL to strlen. + + Reorganize code in secmem.c. + + commit 603f479a919311f720a05da738150c2192d5e562 + * src/secmem.c (pooldesc_t): New type to collect information about one + pool. + (pool_size): Remove. Now a member of pooldesc_t. + (pool_okay): Ditto. + (pool_is_mmapped): Ditto. + (pool): Rename variable ... + (mainpool): And change type to pooldesc_t. + (ptr_into_pool_p): Add arg 'pool'. + (mb_get_next): Ditto. + (mb_get_prev): Ditto. + (mb_merge): Ditto. + (mb_get_new): Ditto. + (init_pool): Ditto. + (lock_pool): Rename to ... + (look_pool_pages: this. + (secmem_init): Rename to ... + (_gcry_secmem_init_internal): this. Add local var POOL and init with + address of MAINPOOL. + (_gcry_secmem_malloc_internal): Add local var POOL and init with + address of MAINPOOL. + (_gcry_private_is_secure): Ditto. + (_gcry_secmem_term): Ditto. + (_gcry_secmem_dump_stats): Ditto. + (_gcry_secmem_free_internal): Ditto. Remove check for NULL arg. + (_gcry_secmem_free): Add check for NULL arg before taking the lock. + (_gcry_secmem_realloc): Factor most code out to ... + (_gcry_secmem_realloc_internal): this. + +2016-11-28 Dmitry Eremin-Solenikov + + tests: Add PBKDF2 tests for Stribog512. + + commit a0580d446fef648a177ca4ab060d0e449780db84 + * tests/t-kdf.c (check_pbkdf2): Add Stribog512 test cases from TC26's + additions to PKCS#5. + + tests: Add Stribog HMAC tests from TC26ALG. + + commit fe6077e6ee8565bfcc91bad14a73e68f45b3c32b + * tests/basic.c (check_mac): add HMAC test vectors from TC26ALG document + for Stribog. + + cipher: Add Stribog OIDs from TC26 space. + + commit ccffacaf6c3abe6120a0898db922981d28ab7af2 + * cipher/stribog.c (oid_spec_stribog256, oid_spec_stribog512): New. + +2016-11-25 Justus Winter + + tests: Fix memory leak. + + commit 5530a8234d703ce9b685f78fb6e951136eb0aeb2 + * tests/basic.c (check_gost28147_cipher): Free cipher handles. + +2016-11-25 Dmitry Eremin-Solenikov + + Cast oid argument of gcry_cipher_set_sbox to disable compiler warning. + + commit 1a67e3195896704f8b3ba09e3db1214bab834491 + * src/gcrypt.h.in (gcry_cipher_set_sbox): Cast oid to (void *). + + gost: Rename tc26 s-box from A to Z. + + commit dc8ceb8d2dfef949f3afa14fc75f9de8cd07c7ad + * cipher/gost-s-box.c (gost_sboxes): Rename TC26_A to TC26_Z as it is + the name that ended up in all standards. + + tests: Add test to verify GOST 28147-89 against known results. + + commit 4f5c26c73c66daf2e4aff966e43c22b2db7e0138 + * tests/basic.c (check_gost28147_cipher): new test function. + +2016-11-17 Dmitry Eremin-Solenikov + + cipher/gost28147: Fix CryptoPro-B S-BOX. + + commit 5ca63c92825453fdb369a97bbc19cb95b49b4296 + * cipher/gost-s-box.c: CryptoPro_B s-box missed one line, resulting in + incorrect encryption/decryption using that s-box. Add missing data. + +2016-11-12 Werner Koch + + Put blocking calls into Libgpg-error's system call clamp. + + commit b829dfe9f0eeff08c956ba3f3a6b559b9d2199dd + * src/gcrypt.h.in (GCRYCTL_REINIT_SYSCALL_CLAMP): New. + * configure.ac: Require Libgpg-error 1.25. Set version number to + 1.8.0. + * src/gcrypt-int.h: Remove error code emulation. + * src/global.c (pre_syscall_func, post_syscall_func): New. + (global_init): Call gpgrt_get_syscall_clamp. + (_gcry_vcontrol) : Ditto. + (_gcry_pre_syscall, _gcry_post_syscall): New. + * random/rndlinux.c (_gcry_rndlinux_gather_random): Use the new + functions. + +2016-11-01 NIIBE Yutaka + + cipher: Fix IDEA cipher for clearing memory. + + commit bf6d5b10cb4173826f47ac080506b68bb001acb2 + * cipher/idea.c (invert_key): Use wipememory, since this kind of memset + may be removed by compiler optimization. + +2016-10-09 Jussi Kivilinna + + GCM: Add bulk processing for ARMv8/AArch64 implementation. + + commit bfd732f53a9b5dfe14217a68a0fa289bf6913ec0 + * cipher/cipher-gcm-armv8-aarch64-ce.S: Add 6 blocks bulk processing. + + GCM: Add bulk processing for ARMv8/AArch32 implementation. + + commit 27747921cb1dfced83c5666cd1c474764724c52b + * cipher/cipher-gcm-armv8-aarch32-ce.S: Add 4 blocks bulk processing. + * tests/basic.c (check_digests): Print correct data length for "?" + tests. + (check_one_mac): Add large 1000000 bytes tests, when input is "!" or + "?". + (check_mac): Add "?" tests vectors for HMAC, CMAC, GMAC and POLY1305. + +2016-09-11 Jussi Kivilinna + + Add Aarch64 assembly implementation of Twofish. + + commit 5418d9ca4c0e087fd6872ad350a996fe74880d86 + * cipher/Makefile.am: Add 'twofish-aarch64.S'. + * cipher/twofish-aarch64.S: New. + * cipher/twofish.c: Enable USE_ARM_ASM if __AARCH64EL__ and + HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS defined. + * configure.ac [host=aarch64]: Add 'twofish-aarch64.lo'. + +2016-09-05 Jussi Kivilinna + + Add Aarch64 assembly implementation of Camellia. + + commit de73a2e7237ba7c34ce48bb5fb671aa3993de832 + * cipher/Makefile.am: Add 'camellia-aarch64.S'. + * cipher/camellia-aarch64.S: New. + * cipher/camellia-glue.c [USE_ARM_ASM][__aarch64__]: Set stack burn + size to zero. + * cipher/camellia.h: Enable USE_ARM_ASM if __AARCH64EL__ and + HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS defined. + * configure.ac [host=aarch64]: Add 'rijndael-aarch64.lo'. + + Add ARMv8/AArch64 Crypto Extension implementation of AES. + + commit 4cd8d40d698564d24ece2af24546e34c58bf2961 + * cipher/Makefile.am: Add 'rijndael-armv-aarch64-ce.S'. + * cipher/rijndael-armv8-aarch64-ce.S: New. + * cipher/rijndael-internal.h (USE_ARM_CE): Enable for ARMv8/AArch64. + * configure.ac: Add 'rijndael-armv-aarch64-ce.lo' and + 'rijndael-armv8-ce.lo' for ARMv8/AArch64. + + Add ARMv8/AArch64 Crypto Extension implementation of GCM. + + commit 0b332c1aef03a735c1fb0df184f74d523deb2f98 + * cipher/Makefile.am: Add 'cipher-gcm-armv8-aarch64-ce.S'. + * cipher/cipher-gcm-armv8-aarch64-ce.S: New. + * cipher/cipher-internal.h (GCM_USE_ARM_PMULL): Enable on + ARMv8/AArch64. + + Add ARMv8/AArch64 Crypto Extension implementation of SHA-256. + + commit 2d4bbc0ad62c54bbdef77799f9db82d344b7219e + * cipher/Makefile.am: Add 'sha256-armv8-aarch64-ce.S'. + * cipher/sha256-armv8-aarch64-ce.S: New. + * cipher/sha256-armv8-aarch32-ce.S: Move round macros to correct + section. + * cipher/sha256.c (USE_ARM_CE): Enable on ARMv8/AArch64. + * configure.ac: Add 'sha256-armv8-aarch64-ce.lo'; Swap places for + 'sha512-arm.lo' and 'sha256-armv8-aarch32-ce.lo'. + + Add ARMv8/AArch64 Crypto Extension implementation of SHA-1. + + commit e4eb03f56683317c908cb55be727832810dc8c72 + * cipher/Makefile.am: Add 'sha1-armv8-aarch64-ce.S'. + * cipher/sha1-armv8-aarch64-ce.S: New. + * cipher/sha1.c (USE_ARM_CE): Enable on ARMv8/AArch64. + * configure.ac: Add 'sha1-armv8-aarch64-ce.lo'. + +2016-09-04 Jussi Kivilinna + + Add AArch64 assembly implementation of AES. + + commit 595251ad37bf1968261d7e781752513f67525803 + * cipher/Makefile.am: Add 'rijndael-aarch64.S'. + * cipher/rijndael-aarch64.S: New. + * cipher/rijndael-internal.h: Enable USE_ARM_ASM if __AARCH64EL__ and + HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS defined. + * configure.ac (gcry_cv_gcc_aarch64_platform_as_ok): New check. + [host=aarch64]: Add 'rijndael-aarch64.lo'. + +2016-08-17 Werner Koch + + Release 1.7.3. + + commit f8241874971478bdcd2bc2082d901d05db7b256d + * configure.ac: Set LT version to C21/A1/R3. + + random: Hash continuous areas in the csprng pool. + + commit 8dd45ad957b54b939c288a68720137386c7f6501 + * random/random-csprng.c (mix_pool): Store the first hash at the end + of the pool. + + random: Improve the diagram showing the random mixing. + + commit 2f62103b4bb6d6f9ce806e01afb7fdc58aa33513 + * random/random-csprng.c (mix_pool): Use DIGESTLEN instead of 20. + +2016-07-19 Jussi Kivilinna + + crc-intel-pclmul: split assembly block to ease register pressure. + + commit f38199dbc290003898a1799adc367265267784c2 + * cipher/crc-intel-pclmul.c (crc32_less_than_16): Split inline + assembly block handling 4 byte input into multiple blocks. + + rijndael-aesni: split assembly block to ease register pressure. + + commit a4d1595a2638db63ac4c73e722c8ba95fdd85ff7 + * cipher/rijndael-aesni.c (do_aesni_ctr_4): Use single register + constraint for passing 'bige_addb' to assembly block; split + first inline assembly block into two parts. + +2016-07-14 Jussi Kivilinna + + Add ARMv8/AArch32 Crypto Extension implementation of AES. + + commit 05a4cecae0c02d2b4ee1cadd9c08115beae3a94a + * cipher/Makefile.am: Add 'rijndael-armv8-ce.c' and + 'rijndael-armv-aarch32-ce.S'. + * cipher/rijndael-armv8-aarch32-ce.S: New. + * cipher/rijndael-armv8-ce.c: New. + * cipher/rijndael-internal.h (USE_ARM_CE): New. + (RIJNDAEL_context_s): Add 'use_arm_ce'. + * cipher/rijndael.c [USE_ARM_CE] (_gcry_aes_armv8_ce_setkey) + (_gcry_aes_armv8_ce_prepare_decryption) + (_gcry_aes_armv8_ce_encrypt, _gcry_aes_armv8_ce_decrypt) + (_gcry_aes_armv8_ce_cfb_enc, _gcry_aes_armv8_ce_cbc_enc) + (_gcry_aes_armv8_ce_ctr_enc, _gcry_aes_armv8_ce_cfb_dec) + (_gcry_aes_armv8_ce_cbc_dec, _gcry_aes_armv8_ce_ocb_crypt) + (_gcry_aes_armv8_ce_ocb_auth): New. + (do_setkey) [USE_ARM_CE]: Add ARM CE/AES HW feature check and key + setup for ARM CE. + (prepare_decryption, _gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (_gcry_aes_ctr_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_dec) + (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth) [USE_ARM_CE]: Add + ARM CE support. + * configure.ac: Add 'rijndael-armv8-ce.lo' and + 'rijndael-armv8-aarch32-ce.lo'. + + Add ARMv8/AArch32 Crypto Extension implementation of GCM. + + commit 962b15470663db11e5c35b86768f1b5d8e600017 + * cipher/Makefile.am: Add 'cipher-gcm-armv8-aarch32-ce.S'. + * cipher/cipher-gcm-armv8-aarch32-ce.S: New. + * cipher/cipher-gcm.c [GCM_USE_ARM_PMULL] + (_gcry_ghash_setup_armv8_ce_pmull, _gcry_ghash_armv8_ce_pmull) + (ghash_setup_armv8_ce_pmull, ghash_armv8_ce_pmull): New. + (setupM) [GCM_USE_ARM_PMULL]: Enable ARM PMULL implementation if + HWF_ARM_PULL HW feature flag is enabled. + * cipher/cipher-gcm.h (GCM_USE_ARM_PMULL): New. + + Add ARMv8/AArch32 Crypto Extension implemenation of SHA-256. + + commit 34c64eb03178fbfd34190148fec5a189df2b8f83 + * cipher/Makefile.am: Add 'sha256-armv8-aarch32-ce.S'. + * cipher/sha256-armv8-aarch32-ce.S: New. + * cipher/sha256.c (USE_ARM_CE): New. + (sha256_init, sha224_init): Check features for HWF_ARM_SHA1. + [USE_ARM_CE] (_gcry_sha256_transform_armv8_ce): New. + (transform) [USE_ARM_CE]: Use ARMv8 CE implementation if HW supports. + (SHA256_CONTEXT): Add 'use_arm_ce'. + * configure.ac: Add 'sha256-armv8-aarch32-ce.lo'. + + Add ARMv8/AArch32 Crypto Extension implementation of SHA-1. + + commit 3d6334f8d94c2a4df10eed203ae928298a4332ef + * cipher/Makefile.am: Add 'sha1-armv8-aarch32-ce.S'. + * cipher/sha1-armv7-neon.S (_gcry_sha1_transform_armv7_neon): Add + missing size. + * cipher/sha1-armv8-aarch32-ce.S: New. + * cipher/sha1.c (USE_ARM_CE): New. + (sha1_init): Check features for HWF_ARM_SHA1. + [USE_ARM_CE] (_gcry_sha1_transform_armv8_ce): New. + (transform) [USE_ARM_CE]: Use ARMv8 CE implementation if HW supports + it. + * cipher/sha1.h (SHA1_CONTEXT): Add 'use_arm_ce'. + * configure.ac: Add 'sha1-armv8-aarch32-ce.lo'. + + Add HW feature check for ARMv8 AArch64 and crypto extensions. + + commit eee78f6e1fbce7d54c43fb7efc5aa8be9f52755f + * configure.ac: Add '--disable-arm-crypto-support'; enable hwf-arm + module on 64-bit ARM. + (armcryptosupport, gcry_cv_gcc_inline_aarch32_crypto) + (gcry_cv_inline_asm_aarch64_neon) + (gcry_cv_gcc_inline_asm_aarch64_crypto): New. + * src/g10lib.h (HWF_ARM_AES, HWF_ARM_SHA1, HWF_ARM_SHA2) + (HWF_ARM_PMULL): New. + * src/hwf-arm.c [__aarch64__]: Enable building in AArch64 mode. + (feature_map_s): New. + [__arm__] (AT_HWCAP, AT_HWCAP2, HWCAP2_AES, HWCAP2_PMULL) + (HWCAP2_SHA1, HWCAP2_SHA2, arm_features): New. + [__aarch64__] (AT_HWCAP, AT_HWCAP2, HWCAP_ASIMD, HWCAP_AES) + (HWCAP_PMULL, HWCAP_SHA1, HWCAP_SHA2, arm_features): New. + (get_hwcap): Add reading of 'AT_HWCAP2'; Change auxv use + 'unsigned long'. + (detect_arm_at_hwcap): Add mapping of HWCAP/HWCAP2 to HWF flags. + (detect_arm_proc_cpuinfo): Add mapping of CPU features to HWF flags. + (_gcry_hwf_detect_arm): Use __ARM_NEON instead of legacy __ARM_NEON__. + * src/hwfeatures.c (hwflist): Add 'arm-aes', 'arm-sha1', 'arm-sha2' + and 'arm-pmull'. + +2016-07-14 Werner Koch + + Release 1.7.2. + + commit be0bec7d9208b2f2d2ffce9cc2ca6154853e7e59 + * configure.ac: Set LT version to C21/A1/R2. + * Makefile.am (distcheck-hook): New. + +2016-07-13 Werner Koch + + build: Update config.{guess,sub} to {2016-05-15,2016-06-20}. + + commit e535ea1bdc42309553007d60599d3147b8defe93 + * build-aux/config.guess: Update. + * build-aux/config.sub: Update. + +2016-07-08 Jussi Kivilinna + + Fix unaligned accesses with ldm/stm in ChaCha20 and Poly1305 ARM/NEON. + + commit 1111d311fd6452abd4080d1072c75ddb1b5a3dd1 + * cipher/chacha20-armv7-neon.S (UNALIGNED_STMIA8) + (UNALIGNED_LDMIA4): New. + (_gcry_chacha20_armv7_neon_blocks): Use new helper macros instead of + ldm/stm instructions directly. + * cipher/poly1305-armv7-neon.S (UNALIGNED_LDMIA2) + (UNALIGNED_LDMIA4): New. + (_gcry_poly1305_armv7_neon_init_ext, _gcry_poly1305_armv7_neon_blocks) + (_gcry_poly1305_armv7_neon_finish_ext): Use new helper macros instead + of ldm instruction directly. + +2016-07-03 Jussi Kivilinna + + bench-slope: add unaligned buffer mode. + + commit 496790940753226f96b731a43d950bd268acd97a + * tests/bench-slope.c (unaligned_mode): New. + (do_slope_benchmark): Unalign buffer if in unaligned mode enabled. + (print_help, main): Add '--unaligned' parameter. + +2016-07-01 Jussi Kivilinna + + Fix static build. + + commit cb79630ec567a5f2e03e5f863cda168faa7b8cc8 + * tests/pubkey.c (_gcry_pk_util_get_nbits): Make function 'static'. + +2016-06-30 Jussi Kivilinna + + Disallow encryption/decryption if key is not set. + + commit 07de9858032826f5a7b08c372f6bcc73bbb503eb + * cipher/cipher.c (cipher_encrypt, cipher_decrypt): If mode is not + NONE, make sure that key is set. + * cipher/cipher-ccm.c (_gcry_cipher_ccm_set_nonce): Do not clear + 'marks.key' when reseting state. + + Avoid unaligned accesses with ARM ldm/stm instructions. + + commit a6158a01a4d81a5d862e1e0a60bfd6063443311d + * cipher/rijndael-arm.S: Remove __ARM_FEATURE_UNALIGNED ifdefs, always + compile with unaligned load/store code paths. + * cipher/sha512-arm.S: Ditto. + + Fix non-PIC reference in PIC for poly1305/ARMv7-NEON. + + commit a09126242a51c4ea4564b0f70b808e4f27fe5a91 + * cipher/poly1305-armv7-neon.S (GET_DATA_POINTER): New. + (_gcry_poly1305_armv7_neon_init_ext): Use GET_DATA_POINTER. + + Fix wrong CPU feature #ifdef for SHA1/AVX. + + commit 4a983e3bef58b9d056517e25e0ab10b72d12ceba + * cipher/sha1-avx-amd64.S: Check for HAVE_GCC_INLINE_ASM_AVX instead of + HAVE_GCC_INLINE_ASM_AVX2 & HAVE_GCC_INLINE_ASM_BMI2. + +2016-06-30 Werner Koch + + random: Remove debug message about not supported getrandom syscall. + + commit 6965515c73632a088fb126a4a55e95121671fa98 + * random/rndlinux.c (_gcry_rndlinux_gather_random): Remove log_debug + for getrandom error ENOSYS. + +2016-06-27 Werner Koch + + tests: Do not test SHAKE128 et al with gcry_md_hash_buffer. + + commit 4d634a098742ff425b324e9f2a67b9f62de09744 + * tests/benchmark.c (md_bench): Do not test variable lengths algos + with the gcry_md_hash_buffer. + + md: Improve diagnostic when using SHAKE128 with gcry_md_hash_buffer. + + commit ae26edf4b60359bfa5fe3a27b2c24b336e7ec35c + * cipher/md.c (md_read): Detect missing read function. + (_gcry_md_hash_buffers): Return an error. + +2016-06-25 Werner Koch + + ecc: Fix memory leak. + + commit 7a7f7c147f888367dfee6093d26bfeaf750efc3a + * cipher/ecc.c (ecc_check_secret_key): Do not init point if already + set. + + doc: Update yat2m. + + commit 1feb01940062a74c27230434fc3babdddca8caf4 + * doc/yat2m.c: Update from Libgpg-error + + tests: Add attributes to helper functions. + + commit c870cb5d385c1d6e1e28ca481cf9cf44b3bfeea9 + * tests/t-common.h (die, fail, info): Add attributes. + * tests/random.c (die, inf): Ditto. + * tests/pubkey.c (die, fail, info): Add attributes. + * tests/fipsdrv.c (die): Add attribute. + (main): Take care of missing --key,--iv,--dt options. + + Improve robustness and help lint. + + commit 5a5b055b81ee60a22a846bdf2031516b1c24df98 + * cipher/rsa.c (rsa_encrypt): Check for !DATA. + * cipher/md.c (search_oid): Check early for !OID. + (md_copy): Use gpg_err_code_from_syserror. Replace chains of if(!err) + tests. + * cipher/cipher.c (search_oid): Check early for !OID. + * src/misc.c (do_printhex): Allow for BUFFER==NULL even with LENGTH>0. + * mpi/mpicoder.c (onecompl): Allow for A==NULL to help static + analyzers. + + cipher: Improve fatal error message for bad use of gcry_md_read. + + commit 3f98b1e92d5afd720d7cea5b4e8295c5018bf9ac + * cipher/md.c (md_read): Use _gcry_fatal_error instead of BUG. + +2016-06-16 Niibe Yutaka + + ecc: Default cofactor 1 for PUBKEY_FLAG_PARAM. + + commit b0b70e7fe37b1bf13ec0bfc8effcb5c7f5db6b7d + * cipher/ecc.c (ecc_check_secret_key, ecc_sign, ecc_verify) + (ecc_encrypt_raw, ecc_decrypt_raw, compute_keygrip): Set default + cofactor as 1, when not specified. + + ecc: Default cofactor 1 for PUBKEY_FLAG_PARAM. + + commit 0f3a069211d8d24a61aa0dc2cc6c4ef04cc4fab7 + * cipher/ecc.c (ecc_check_secret_key, ecc_sign, ecc_verify) + (ecc_encrypt_raw, ecc_decrypt_raw, compute_keygrip): Set default + cofactor as 1, when not specified. + +2016-06-15 Werner Koch + + Release 1.7.1. + + commit 48aa6d6602564d6ba0cef10cf08f9fb0c59b3223 + + + doc: Describe envvars. + + commit c3173bbe3f1a9c73f81a538dd49ccfa0447bfcdc + * doc/gcrypt.texi: Add chapter Configuration. + + random: Change names of debug envvars. + + commit 131b4f0634cee0e5c47d2250c59f51127b10f7b3 + * random/rndunix.c (start_gatherer): Change GNUPG_RNDUNIX_DBG to + GCRYPT_RNDUNIX_DBG, change GNUPG_RNDUNIX_DBG to GCRYPT_RNDUNIX_DBG. + * random/rndw32.c (registry_poll): Change GNUPG_RNDW32_NOPERF to + GCRYPT_RNDW32_NOPERF. + +2016-06-14 Werner Koch + + cipher: Assign OIDs to the Serpent cipher. + + commit e13a6a1ba53127af602713d0c2aaa85c94b3cd7e + * cipher/serpent.c (serpent128_oids, serpent192_oids) + (serpent256_oids): New. Add them to the specs blow. + (serpent128_aliases): Add "SERPENT-128". + (serpent256_aliases, serpent192_aliases): New. + + cipher: Assign OIDs to the Serpent cipher. + + commit 6cc2100c00a65dff07b095dea7b32cb5c5cd96d4 + * cipher/serpent.c (serpent128_oids, serpent192_oids) + (serpent256_oids): New. Add them to the specs blow. + (serpent128_aliases): Add "SERPENT-128". + (serpent256_aliases, serpent192_aliases): New. + +2016-06-08 Werner Koch + + rsa: Implement blinding also for signing. + + commit 1f769e3e8442bae2f1f73c656920bb2df70153c0 + * cipher/rsa.c (rsa_decrypt): Factor blinding code out to ... + (secret_blinded): new. + (rsa_sign): Use blinding by default. + + random: Remove debug output for getrandom(2) output. + + commit 52cdfb1960808aaad48b5a501bbce0e3141c3961 + * random/rndlinux.c (_gcry_rndlinux_gather_random): Remove debug + output. + + Fix gcc portability on Solaris 9 SPARC boxes. + + commit b766ea14ad1c27d6160531b200cc70aaa479c6dc + * mpi/longlong.h: Use __sparcv8 as alias for __sparc_v8__. + +2016-06-08 Jérémie Courrèges-Anglas + + Check for compiler SSE4.1 support in PCLMUL CRC code. + + commit dc76313308c184c92eb78452b503405b90fc7ebd + * cipher/crc-intel-pclmul.c: Build PCLMUL CRC implementation only if + compiler supports PCLMUL *and* SSE4.1 + * cipher/crc.c: Ditto + * configure.ac (sse41support, gcry_cv_gcc_inline_asm_sse41): New. + +2016-06-08 NIIBE Yutaka + + ecc: Fix ecc_verify for cofactor support. + + commit bd39eb9fba47dc8500c83769a679cc8b683d6c6e + * cipher/ecc.c (ecc_verify): Fix the argument for cofactor "h". + +2016-06-08 Werner Koch + + random: Try to use getrandom() instead of /dev/urandom (Linux only). + + commit c05837211e5221d3f56146865e823bc20b4ff1ab + * configure.ac: Check for syscall. + * random/rndlinux.c [HAVE_SYSCALL]: Include sys/syscall.h. + (_gcry_rndlinux_gather_random): Use getrandom is available. + +2016-06-03 Werner Koch + + rsa: Implement blinding also for signing. + + commit ef6e4d004b10f5740bcd2125fb70e199dd21e3e8 + * cipher/rsa.c (rsa_decrypt): Factor blinding code out to ... + (secret_blinded): new. + (rsa_sign): Use blinding by default. + + random: Remove debug output for getrandom(2) output. + + commit 82df6c63a72fdd969c3923523f10d0cef5713ac7 + * random/rndlinux.c (_gcry_rndlinux_gather_random): Remove debug + output. + +2016-06-02 Werner Koch + + Fix gcc portability on Solaris 9 SPARC boxes. + + commit 4121f15122501d8946f1589b303d1f7949c15e30 + * mpi/longlong.h: Use __sparcv8 as alias for __sparc_v8__. + +2016-05-28 Jérémie Courrèges-Anglas + + Check for compiler SSE4.1 support in PCLMUL CRC code. + + commit 3e8074ecd3a534e8bd7f11cf17f0b22d252584c8 + * cipher/crc-intel-pclmul.c: Build PCLMUL CRC implementation only if + compiler supports PCLMUL *and* SSE4.1 + * cipher/crc.c: Ditto + * configure.ac (sse41support, gcry_cv_gcc_inline_asm_sse41): New. + +2016-05-06 NIIBE Yutaka + + ecc: Fix ecc_verify for cofactor support. + + commit c7430aa752232aa690c5d8f16575a345442ad8d7 + * cipher/ecc.c (ecc_verify): Fix the argument for cofactor "h". + +2016-04-26 Werner Koch + + random: Try to use getrandom() instead of /dev/urandom (Linux only). + + commit ee5a32226a7ca4ab067864e06623fc11a1768900 + * configure.ac: Check for syscall. + * random/rndlinux.c [HAVE_SYSCALL]: Include sys/syscall.h. + (_gcry_rndlinux_gather_random): Use getrandom is available. + +2016-04-19 Werner Koch + + asm fix for older gcc versions. + + commit caa9d14c914bf6116ec3f773a322a94e2be0c0fb + * cipher/crc-intel-pclmul.c: Remove extra trailing colon from + asm statements. + + asm fix for older gcc versions. + + commit 4545372c0f8dd35aef2a7abc12b588ed1a4a0363 + * cipher/crc-intel-pclmul.c: Remove extra trailing colon from + asm statements. + +2016-04-15 Werner Koch + + Release 1.7.0. + + commit 795f9cb090c776658a0e3117996e3fb7e2ebd94a + + +2016-04-14 Werner Koch + + tests: Add test vectors for 256 GiB test of SHA3-256. + + commit 1737c546dc7268fa9edcd4a23b7439c56d37ee4f + * tests/hashtest.c: Add new test vectros. + +2016-04-14 Justus Winter + + src: Improve S-expression parsing. + + commit 491586bc7f7b9edc6b78331a77e653543983c9e4 + * src/sexp.c (do_vsexp_sscan): Return an error if a closing + parenthesis is encountered with no matching opening parenthesis. + +2016-04-14 Werner Koch + + cipher: Add constant for 8 bit CFB mode. + + commit 47c6a1f88eb763e9baa394e34d873b761abcebbe + * src/gcrypt.h.in (GCRY_CIPHER_MODE_CFB8): New. + * tests/basic.c (check_cfb_cipher): Prepare for CFB-8 tests. + + tests: Add a new test for S-expressions. + + commit 88c6b98350193abbdcfb227754979b0c097ee09c + * tests/t-sexp.c (compare_to_canon): New. + (back_and_forth_one): Add another test. + +2016-04-13 NIIBE Yutaka + + ecc: Fix corner cases for X25519. + + commit 8472b71812e71c69d66e2fcc02a6e21b66755f8b + * cipher/ecc.c (ecc_encrypt_raw): For invalid input, returns + GPG_ERR_INV_DATA instead of aborting with log_fatal. For X25519, + it's not an error, thus, let it return 0. + (ecc_decrypt_raw): Use the flag PUBKEY_FLAG_DJB_TWEAK to distinguish + X25519, not by the name of the curve. + (ecc_decrypt_raw): For invalid input, returns GPG_ERR_INV_DATA instead + of aborting with log_fatal. For X25519, it's not an error by its + definition, but we deliberately let it return the error to detect + looks-like-encrypted-message. + * tests/t-cv25519.c: Add points to record the issue. + +2016-04-12 Werner Koch + + cipher: Buffer data from gcry_cipher_authenticate in OCB mode. + + commit b6d2a25a275a35ec4dbd53ecaa9ea0ed7aa99c7b + * cipher/cipher-internal.h (gcry_cipher_handle): Add fields + aad_leftover and aad_nleftover to u_mode.ocb. + * cipher/cipher-ocb.c (_gcry_cipher_ocb_set_nonce): Clear + aad_nleftover. + (_gcry_cipher_ocb_authenticate): Add buffering and facor some code out + to ... + (ocb_aad_finalize): new. + (compute_tag_if_needed): Call new function. + * tests/basic.c (check_ocb_cipher_splitaad): New. + (check_ocb_cipher): Call new function. + (main): Also call check_cipher_modes with --ciper-modes. + +2016-04-12 NIIBE Yutaka + + ecc: Fix X25519 computation on Curve25519. + + commit ee7e1a0e835f8ffcfbcba2a44abab8632db8fed5 + * cipher/ecc.c (ecc_encrypt_raw): Tweak of bits when + PUBKEY_FLAG_DJB_TWEAK is enabled. + (ecc_decrypt_raw): Return 0 when PUBKEY_FLAG_DJB_TWEAK is enabled. + * tests/t-cv25519.c (test_cv): Update by using gcry_pk_encrypt. + + ecc: Fix initialization of EC context. + + commit 7fbdb99b8c56360adfd1fb4e7f4c95e0f8aa34de + * cipher/ecc.c (test_ecdh_only_keys, ecc_generate) + (ecc_check_secret_key, ecc_encrypt_raw, ecc_decrypt_raw): Initialize + by _gcry_mpi_ec_p_internal_new should carry FLAGS. + +2016-04-06 Werner Koch + + Allow building with configure option --enable-hmac-binary-check. + + commit 65c63144b66392f40b991684789b8b793248e3ba + * src/Makefile.am (mpicalc_LDADD): Add DL_LIBS. + * src/fips.c (check_binary_integrity): Allow use of hmac256 output. + * src/hmac256.c (main): Add option --stdkey + +2016-04-06 NIIBE Yutaka + + ecc: Positive values in computation. + + commit 6f386ceae86a058e26294f744750f1ed2a95e604 + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Make sure + coefficients A and B are positive. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_recover_x): For negation, do + "P - T" instead of "-T", so that the result will be positive. + (_gcry_ecc_eddsa_verify): Likewise. + * cipher/ecc.c (ecc_check_secret_key): Use _gcry_ecc_fill_in_curve + instead of _gcry_ecc_update_curve_param. + * mpi/ec.c (ec_subm): Make sure the result will be positive. + (dup_point_edwards, sub_points_edwards, _gcry_mpi_ec_curve_point): Use + mpi_sub instead of mpi_neg. + (add_points_edwards): Simply use ec_addm. + * tests/t-mpi-point.c (test_curve): Define curves with positive + coefficients. + +2016-04-01 Werner Koch + + mpi: Explicitly limit the allowed input length for gcry_mpi_scan. + + commit 862cf19a119427dd7ee7959a36c72d905f5ea5ca + * mpi/mpicoder.c (MAX_EXTERN_SCAN_BYTES): New. + (mpi_fromstr): Check against this limit. + (_gcry_mpi_scan): Ditto. + * tests/mpitests.c (test_maxsize): New. + (main): Cal that test. + +2016-03-31 Werner Koch + + cipher: Remove specialized rmd160 functions. + + commit fcce0cb6e8af70b134c6ecc3f56afa07a7d31f27 + * cipher/rmd160.c: Replace rmd.h by hash-common.h. + (RMD160_CONTEXT): Move from rmd.h to here. + (_gcry_rmd160_init): Remove. + (_gcry_rmd160_mixblock): Remove. + (_gcry_rmd160_hash_buffer): Use rmd160_init directly. + * cipher/md.c: Remove rmd.h which was not actually used. + * cipher/rmd.h: Remove. + * cipher/Makefile.am (libcipher_la_SOURCES): Remove rmd.h. + * configure.ac (USE_RMD160): Allow to build without RMD160. + + random: Replace RMD160 by SHA-1 for mixing the CSPRNG pool. + + commit a9cbe2d1f6a517a831517da8bc1d29e3e0b2c0c0 + * cipher/sha1.c (_gcry_sha1_mixblock_init): New. + (_gcry_sha1_mixblock): New. + * random/random-csprng.c: Include sha1.h instead of rmd.h. + (mix_pool): Use SHA-1 instead of RIPE-MD-160 for mixing. + + cipher: Move sha1 context definition to a separate file. + + commit 142a479a484cb4e84d0561be9b05b44dac9e6fe2 + * cipher/sha1.c: Replace hash-common.h by sha1.h. + (SHA1_CONTEXT): Move to ... + * cipher/sha1.h: new. Always include all flags. + * cipher/Makefile.am (libcipher_la_SOURCES): Add sha1.h. + +2016-03-29 Werner Koch + + tests: Fix buffer overflow in bench-slope. + + commit 48ee918400762281bec5b6fc218a9f0d119aac7c + * tests/bench-slope.c (bench_print_result_std): Remove wrong use of + strncat. + +2016-03-27 Jussi Kivilinna + + cipher: GCM: check that length of supplied tag is one of valid lengths. + + commit f2260e3a2e962ac80124ef938e54041bbea08561 + * cipher/cipher-gcm.c (is_tag_length_valid): New. + (_gcry_cipher_gcm_tag): Check that 'outbuflen' has valid tag length. + * tests/basic.c (_check_gcm_cipher): Add test-vectors with different + valid tag lengths and negative test vectors with invalid lengths. + +2016-03-24 Peter Wu + + cipher: Fix memleaks in (self)tests. + + commit 4a064e2a06fe737f344d1dfd8a45cc4c2abbe4c9 + * cipher/dsa.c: Release memory for MPI and sexp structures. + * cipher/ecc.c: Release memory for sexp structure. + * tests/keygen.c: Likewise. + + Mark constant MPIs as non-leaked. + + commit 470a30db241a2d567739ef2adb2a2ee64992d8b4 + * mpi/mpiutil.c: Mark "constant" MPIs as explicitly leaked. + +2016-03-23 Werner Koch + + Add new control GCRYCTL_GET_TAGLEN for use with gcry_cipher_info. + + commit fea5971488e049f902d7912df22a945bc755ad6d + * src/gcrypt.h.in (GCRYCTL_GET_TAGLEN): New. + * cipher/cipher.c (_gcry_cipher_info): Add GCRYCTL_GET_TAGLEN feature. + + * tests/basic.c (_check_gcm_cipher): Check that new feature. + (_check_poly1305_cipher): Ditto. + (check_ccm_cipher): Ditto. + (do_check_ocb_cipher): Ditto. + (check_ctr_cipher): Add negative test for new feature. + + cipher: Avoid NULL-segv in GCM mode if a key has not been set. + + commit e709d86fe596a4bcf235799468947c13ae657d78 + * cipher/cipher-gcm.c (_gcry_cipher_gcm_encrypt): Check that GHASH_FN + has been initialized. + (_gcry_cipher_gcm_decrypt): Ditto. + (_gcry_cipher_gcm_authenticate): Ditto. + (_gcry_cipher_gcm_initiv): Ditto. + (_gcry_cipher_gcm_tag): Ditto. + + cipher: Check length of supplied tag in _gcry_cipher_poly1305_check_tag. + + commit 7c9c82feecf94a455c66d9c38576f36c9c4b484c + * cipher/cipher-poly1305.c (_gcry_cipher_poly1305_tag): Check that the + provided tag length matches the actual tag length. + +2016-03-23 Peter Wu + + Fix buffer overrun in gettag for Poly1305. + + commit 6821e1bd94969106a70e3de17b86f6e6181f4e59 + * cipher/cipher-poly1305.c: copy a fixed length instead of the + user-supplied number. + +2016-03-23 Werner Koch + + cipher: Check length of supplied tag in _gcry_cipher_gcm_check_tag. + + commit 15785bc9fb1787554bf371945ecb191830c15bfd + * cipher/cipher-gcm.c (_gcry_cipher_gcm_tag): Check that the provided + tag length matches the actual tag length. Avoid gratuitous return + statements. + +2016-03-23 Peter Wu + + Fix buffer overrun in gettag for GCM. + + commit d3d7bdf8215275b3b20690dfde3f43dbe25b6f85 + * cipher/cipher-gcm.c: copy a fixed length instead of the user-supplied + number. + +2016-03-22 Werner Koch + + tests: Add options --fips to keygen for manual tests. + + commit d328095dd4de83b839d9d8c4bdbeec0956971016 + (main): Add option --fips. + * tests/keygen.c (check_rsa_keys): Create an 2048 bit key with e=65539 + because that is valid in FIPS mode. Check that key generation fails + for too short keys in FIPS mode. + (check_ecc_keys): Check that key generation fails for Ed25519 keys in + FIPS mode. + +2016-03-22 Tomáš Mráz + + rsa: Add FIPS 186-4 compliant RSA probable prime key generator. + + commit 5f9b3c2e220ca6d0eaff32324a973ef67933a844 + * cipher/primegen.c (_gcry_fips186_4_prime_check): New. + * cipher/rsa.c (generate_fips): New. + (rsa_generate): Use new function in fips mode or with test-parms. + + * tests/keygen.c (check_rsa_keys): Add test using e=65539. + +2016-03-20 Jussi Kivilinna + + Fix ARM NEON support detection on ARMv6 target. + + commit 583919d70763671ed9feeaa14e1f66379aff88cc + * configure.ac (gcry_cv_gcc_inline_asm_neon): Use '.arm' directive + instead of '.thumb'. + +2016-03-18 Werner Koch + + Always require a 64 bit integer type. + + commit 897ccd21b7221982806b5c024518f4e989152f14 + * configure.ac (available_digests_64): Merge with available_digests. + (available_kdfs_64): Merge with available_kdfs. + <64 bit datatype test>: Bail out if no such type is available. + * src/types.h: Emit #error if no u64 can be defined. + (PROPERLY_ALIGNED_TYPE): Always add u64 type. + * cipher/bithelp.h: Remove all code paths which handle the + case of !HAVE_U64_TYPEDEF. + * cipher/bufhelp.h: Ditto. + * cipher/cipher-ccm.c: Ditto. + * cipher/cipher-gcm.c: Ditto. + * cipher/cipher-internal.h: Ditto. + * cipher/cipher.c: Ditto. + * cipher/hash-common.h: Ditto. + * cipher/md.c: Ditto. + * cipher/poly1305.c: Ditto. + * cipher/scrypt.c: Ditto. + * cipher/tiger.c: Ditto. + * src/g10lib.h: Ditto. + * tests/basic.c: Ditto. + * tests/bench-slope.c: Ditto. + * tests/benchmark.c: Ditto. + +2016-03-18 Vitezslav Cizek + + tests: Fix testsuite after the FIPS adjustments. + + commit 9ecc2690181ba0bb44f66451a7dce2fc19965793 + * tests/benchmark.c (ecc_bench): Avoid not approved curves in FIPS. + * tests/curves.c (check_get_params): Skip Brainpool curves in FIPS. + * tests/keygen.c (check_dsa_keys): Generate 2048 and 3072 bits keys. + (check_ecc_keys): Skip Ed25519 in FIPS mode. + * tests/random.c (main): Don't switch DRBG in FIPS mode. + * tests/t-ed25519.c (main): Ed25519 isn't supported in FIPS mode. + * tests/t-kdf.c (check_openpgp): Skip vectors using md5 in FIPS. + * tests/t-mpi-point.c (context_param): Skip P-192 and Ed25519 in FIPS. + (main): Skip math tests that use P-192 and Ed25519 in FIPS. + + tests: Add new --pss option to fipsdrv. + + commit 1a02d741cacc3b57fe3d6ffebd794d53a60c9e97 + * tests/fipsdrv.c (run_rsa_sign, run_rsa_verify): Set salt-length + to 0 for PSS. + + cipher: Add option to specify salt length for PSS verification. + + commit 0bd8137e68c201b6c2290710e348aaf57efa2b2e + * cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Check for + salt-length token. + + tests: Add support for RSA keygen tests to fipsdrv. + + commit 2e139456369a834cf87d983da4f61241fda76efe + * tests/fipsdrv.c (run_rsa_keygen): New. + (main): Support RSA keygen and RSA keygen KAT tests. + + tests: Fixes for RSA testsuite in FIPS mode. + + commit c690230af5a66b809f8f6fbab1a6262a5ba078cb + * tests/basic.c (get_keys_new): Generate 2048 bit key. + * tests/benchmark.c (rsa_bench): Skip keys of lengths different + than 2048 and 3072 in FIPS mode. + * tests/keygen.c (check_rsa_keys): Failure if short keys can be + generated in FIPS mode. + (check_dsa_keys): Ditto for DSA keys. + * tests/pubkey.c (check_x931_derived_key): Skip keys < 2048 in FIPS. + + rsa: Use 2048 bit RSA keys for selftest. + + commit 78cec8b4754fdf774edb2d575000cb3e972e244c + * cipher/rsa.c (selftests_rsa): Use 2048 bit keys. + (selftest_encr_1024): Replaced by selftest_encr_2048. + (selftest_sign_1024): Replaced by selftest_sign_2048. + (selftest_encr_2048): Add check against known ciphertext. + (selftest_sign_2048): Add check against known signature. + (selftest_sign_2048): Free SIG_MPI. + * tests/pubkey.c (get_keys_new): Generate 2048 bit keys. + + Disable non-allowed algorithms in FIPS mode. + + commit ce1cbe16992a7340edcf8e6576973e3508267640 + * cipher/cipher.c (_gcry_cipher_init), + * cipher/mac.c (_gcry_mac_init), + * cipher/md.c (_gcry_md_init), + * cipher/pubkey.c (_gcry_pk_init): In the FIPS mode, disable all the + non-allowed ciphers. + * cipher/md5.c: Mark MD5 as not allowed in FIPS. + * src/g10lib.h (_gcry_mac_init): New. + * src/global.c (global_init): Call the new _gcry_mac_init. + * tests/basic.c (check_ciphers): Fix a typo. + +2016-03-18 Werner Koch + + kdf: Make PBKDF2 check work on all platforms. + + commit c478cf175887c84dc071c4f73a7667603b354789 + * cipher/kdf.c (_gcry_kdf_pkdf2): Chnage DKLEN to unsigned long. + +2016-03-18 Vitezslav Cizek + + kdf: Add upper bound for derived key length in PBKDF2. + + commit 0f741b0704bac5c0e2d2a0c2b34b44b35baa76d6 + * cipher/kdf.c (_gcry_kdf_pkdf2): limit dkLen. + + ecc: ECDSA adjustments for FIPS 186-4. + + commit a242e3d9185e6e2dc13902ea9331131755bbba01 + * cipher/ecc-curves.c: Unmark curve P-192 for FIPS. + * cipher/ecc.c: Add ECDSA self test. + * cipher/pubkey-util.c (_gcry_pk_util_init_encoding_ctx): Use SHA-2 + in FIPS mode. + * tests/fipsdrv.c: Add support for ECDSA signatures. + +2016-03-18 Werner Koch + + dsa: Make regression tests work. + + commit e40939b2141306238cc30a340b867b60fa4dc2a3 + * cipher/dsa.c (sample_secret_key_1024): Comment out unused constant. + (ogenerate_fips186): Make it work with use-fips183-2 flag. + * cipher/primegen.c (_gcry_generate_fips186_3_prime): Use Emacs + standard comment out format. + * tests/fips186-dsa.c (check_dsa_gen_186_3): New dummy fucntion. + (main): Call it. + (main): Compare against current version. + * tests/pubkey.c (get_dsa_key_fips186_new): Create 2048 bit key. + (get_dsa_key_fips186_with_seed_new): Ditto. + (get_dsa_key_fips186_with_domain_new): Comment out. + (check_run): Do not call that function. + +2016-03-18 Vitezslav Cizek + + dsa: Adjustments to conform with FIPS 186-4. + + commit 80e9f95e6f419daa765e4876c858e3e36e808897 + * cipher/dsa.c (generate_fips186): FIPS 186-4 adjustments. + * cipher/primegen.c (_gcry_generate_fips186_3_prime): Fix incorrect + buflen passed to _gcry_mpi_scan. + +2016-03-16 Justus Winter + + Update documentation for 'gcry_sexp_extract_param'. + + commit 4051fe7fec6ffdc7a2f5c3856665478866991ee7 + * doc/gcrypt.texi (gcry_sexp_extract_param): Mention that all MIPs + must be set to NULL first, and document how the function behaves in + case of errors. + * src/sexp.c (_gcry_sexp_extract_param): Likewise. + * src/gcrypt.h.in (gcry_sexp_extract_param): Copy the comment from + '_gcry_sexp_extract_param'. + + cipher: Update comment. + + commit fcf4358a7a7ba8d32bf385ea99ced5f47cbd3ae2 + * cipher/ecc.c (ecc_get_nbits): Update comment to reflect the fact + that a curve parameter can be given. + +2016-03-12 Jussi Kivilinna + + Add Intel PCLMUL implementations of CRC algorithms. + + commit 5d601dd57fcb41aa2015ab655fd6fc51537da667 + * cipher/Makefile.am: Add 'crc-intel-pclmul.c'. + * cipher/crc-intel-pclmul.c: New. + * cipher/crc.c (USE_INTEL_PCLMUL): New macro. + (CRC_CONTEXT) [USE_INTEL_PCLMUL]: Add 'use_pclmul'. + [USE_INTEL_PCLMUL] (_gcry_crc32_intel_pclmul) + (gcry_crc24rfc2440_intel_pclmul): New. + (crc32_init, crc32rfc1510_init, crc24rfc2440_init) + [USE_INTEL_PCLMUL]: Select PCLMUL implementation if SSE4.1 and PCLMUL + HW features detected. + (crc32_write, crc24rfc2440_write) [USE_INTEL_PCLMUL]: Use PCLMUL + implementation if enabled. + (crc24_init): Document storage format of 24-bit CRC. + (crc24_next4): Use only 'data' for last table look-up. + * configure.ac: Add 'crc-intel-pclmul.lo'. + * src/g10lib.h (HWF_*, HWF_INTEL_SSE4_1): Update HWF flags to include + Intel SSE4.1. + * src/hwf-x86.c (detect_x86_gnuc): Add SSE4.1 detection. + * src/hwfeatures.c (hwflist): Add 'intel-sse4.1'. + * tests/basic.c (fillbuf_count): New. + (check_one_md): Add "?" check (million byte data-set with byte pattern + 0x00,0x01,0x02,...); Test all buffer sizes 1 to 1000, for "!" and "?" + checks. + (check_one_md_multi): Skip "?". + (check_digests): Add "?" test-vectors for MD5, SHA1, SHA224, SHA256, + SHA384, SHA512, SHA3_224, SHA3_256, SHA3_384, SHA3_512, RIPEMD160, + CRC32, CRC32_RFC1510, CRC24_RFC2440, TIGER1 and WHIRLPOOL; Add "!" + test-vectors for CRC32_RFC1510 and CRC24_RFC2440. + +2016-02-25 NIIBE Yutaka + + mpi: Normalize EXPO for mpi_powm. + + commit fdfa5bfefdde316688a3c8021bd3528c5273b0f4 + * mpi/mpi-pow.c (gcry_mpi_powm): Normalize EP. + +2016-02-22 Andreas Metzler + + Do not ship generated header file in tarball. + + commit 2b40a16333fa75f1cee85ab901a5aa9cff845a92 + * src/Makefile.am: Move gcrypt.h from include_HEADERS to + nodist_include_HEADERS to prevent inclusion in release tarball. + This could break out-of-tree-builds because the potentially outdated + src/gcrypt.h was not updated but was in the compiler search path. + +2016-02-20 Jussi Kivilinna + + Fix building random-drbg for Win32/64. + + commit 531b25aa94c58f6d2168a9537c8cea6c53d7bbe0 + * random/random-drbg.c: Remove include for sys/types.h and asm/types.h. + (DRBG_PREDICTION_RESIST, DRBG_CTRAES, DRBG_CTRSERPENT, DRBG_CTRTWOFISH) + (DRBG_HASHSHA1, DRBG_HASHSHA224, DRBG_HASHSHA256, DRBG_HASHSHA384) + (DRBG_HASHSHA512, DRBG_HMAC, DRBG_SYM128, DRBG_SYM192) + (DRBG_SYM256): Change 'u_int32_t' to 'u32'. + (drbg_get_entropy) [USE_RNDUNIX, USE_RNDW32]: Fix parameters + 'drbg_read_cb' and 'len'. + +2016-02-20 Werner Koch + + tests: Do not test DRBG_REINIT from "make check" + + commit 839d12c221430b60db5e0d6fbb107f22e0a6837f + * tests/random.c (main): Run check_drbg_reinit only if the envvar + GCRYPT_IN_REGRESSION_TEST is set. + + doc: Fix possible dependency problem. + + commit 3b57e5a1ba68e26dcaea38b763287fddba9b6b7c + * doc/Makefile.am (gcrypt.texi): Use the right traget. + +2016-02-19 Stephan Mueller + + random: Remove ANSI X9.31 DRNG. + + commit e9b692d25d1c149b5417b70e18f2ce173bc25b6d + * random-fips.c: Remove. + +2016-02-19 Werner Koch + + random: Add a test case for DRBG_REINIT. + + commit 934ba2ae5a95a96fdbb3b935b51ba43df66f11df + * src/global.c (_gcry_vcontrol) : Test for FIPS RNG. + * tests/random.c (check_drbg_reinit): New. + (main): Call new test. + + random: Allow DRBG_REINIT before initialization. + + commit 7cdbd6e6a3cf1ee366b981e148d41b1187a6fdcf + * random/random-drbg.c (DRBG_DEFAULT_TYPE): New. + (_drbg_init_internal): Set the default type if no type has been set + before. + (_gcry_rngdrbg_inititialize): Pass 0 for flags to use the default. + + Add new private header gcrypt-testapi.h. + + commit 744b030cff61fd25114b0b25394c62782c153343 + * src/gcrypt-testapi.h: New. + * src/Makefile.am (libgcrypt_la_SOURCES): Add new file. + * random/random.h: Include gcrypt-testapi.h. + (struct gcry_drbg_test_vector) : Move to gcrypt-testapi.h. + * src/global.c: Include gcrypt-testapi.h. + (_gcry_vcontrol): Use PRIV_CTL_* constants instead of 58, 59, 60, 61. + * cipher/cipher.c: Include gcrypt-testapi.h. + (_gcry_cipher_ctl): Use PRIV_CIPHERCTL_ constants instead of 61, 62. + * tests/fipsdrv.c: Include gcrypt-testapi.h. Remove definition of + PRIV_CTL_ constants and replace their use by the new PRIV_CIPHERCTL_ + constants. + * tests/t-lock.c: Include gcrypt-testapi.h. Remove + PRIV_CTL_EXTERNAL_LOCK_TEST and EXTERNAL_LOCK_TEST_ constants. + + * random/random-drbg.c (gcry_rngdrbg_cavs_test): Rename to ... + (_gcry_rngdrbg_cavs_test): this. + (gcry_rngdrbg_healthcheck_one): Rename to ... + (_gcry_rngdrbg_healthcheck_one): this. + + random: Make the DRBG C-90 clean and use a flag string. + + commit 95f1db3affb9f5b8a2c814c211d4a02b30446c15 + * random/random.h (struct gcry_drbg_test_vector): Rename "flags" to + "flagstr" and turn it into a string. + * random/random-drbg.c (drbg_test_pr, drbg_test_nopr): Replace use of + designated initializers. Use a string for the flags. + (gcry_rngdrbg_cavs_test): Parse the flag string into a flag value. + (drbg_healthcheck_sanity): Ditto. + + random: Symbol name cleanup for random-drbg.c. + + commit 85ed07790552297586258e8fe09b546eee357a8b + * random/random-drbg.c: Rename all static objects and macros from + "gcry_drbg" to "drbg". + (drbg_string_t): New typedef. + (drbg_gen_t): New typedef. + (drbg_state_t): New typedef. Replace all "struct drbg_state_s *" by + this. + (_drbg_init_internal): Replace xcalloc_secure by xtrycalloc_secure so + that an error if actually returned. + (gcry_rngdrbg_cavs_test): Ditto. + (gcry_drbg_healthcheck_sanity): Ditto. + + random: Use our symbol name pattern also for drbg functions. + + commit 7cf3c929331133e4381dbceac53d3addd921c929 + * random/random-drbg.c: Rename global functions from _gcry_drbg_* + to _gcry_rngdrbg_*. + * random/random.c: Adjust for this change. + * src/global.c: Ditto. + + random: Rename drbg.c to random-drbg.c. + + commit e49b3f2c10e012509b5930c0df4d6df378d3b9f4 + * random/drbg.c: Rename to ... + * random/random-drbg.c: this. + * random/Makefile.am (librandom_la_SOURCES): Adjust accordingly. + + random: Remove the new API introduced by the new DRBG. + + commit dfac2b13d0068b2b1b420d77e9771a49964b81c1 + * src/gcrypt.h.in (struct gcry_drbg_gen): Move to random/drbg.c. + (struct gcry_drbg_string): Ditto. + (gcry_drbg_string_fill): Ditto. + (gcry_randomize_drbg): Remove. + * random/drbg.c (parse_flag_string): New. + (_gcry_drbg_reinit): Change the way the arguments are passed. + * src/global.c (_gcry_vcontrol) : Change calling + convention. + + Add helper function _gcry_strtokenize. + + commit 4e134b6e77f558730ec1eceb6b816b0bcfd845e9 + * src/misc.c (_gcry_strtokenize): New. + +2016-02-18 Werner Koch + + random: Remove DRBG constants from the public API. + + commit fd13372fa9069d3a72947ea59c57e33637c936bf + * src/gcrypt.h.in (GCRY_DRBG_): Remove all new flags to ... + * random/drbg.c: here. + +2016-02-18 Stephan Mueller + + random: Add SP800-90A DRBG. + + commit ed57fed6de1465e02ec5e3bc0affeabdd35e2eb7 + * random/drbg.c: New. + * random/random.c (_gcry_random_initialize): Replace rngfips init by + drbg init. + (__gcry_random_close_fds): Likewise. + (_gcry_random_dump_stats): Likewise. + (_gcry_random_is_faked): Likewise. + (do_randomize): Likewise. + (_gcry_random_selftest): Likewise. + (_gcry_create_nonce): Replace rngfips_create_noce by drbg_randomize. + (_gcry_random_init_external_test): Remove. + (_gcry_random_run_external_test): Remove. + (_gcry_random_deinit_external_test): Remove. + * random/random.h (struct gcry_drbg_test_vector): New. + * src/gcrypt.h.in (struct gcry_drbg_gen): New. + (struct gcry_drbg_string): New. + (gcry_drbg_string_fill): New. + (gcry_randomize_drbg): New. + (GCRY_DRBG_): Lots of new macros. + * src/global.c (_gcry_vcontrol) : Turn into + a nop. + (_gcry_vcontrol) : Ditto. + (_gcry_vcontrol) : Change. + (_gcry_vcontrol) : New. + +2016-02-13 Jussi Kivilinna + + bufhelp: disable unaligned memory accesses on powerpc. + + commit 1da793d089b65ac8c1ead65dacb6b8699f5b6e69 + * cipher/bufhelp.h (BUFHELP_FAST_UNALIGNED_ACCESS): Disable for + __powerpc__ and __powerpc64__. + +2016-02-12 NIIBE Yutaka + + ecc: Not validate input point for Curve25519. + + commit 7a019bc7ecdbdfdef51094e090ce95e062da9b64 + * cipher/ecc.c (ecc_decrypt_raw): Curve25519 is an exception. + +2016-02-10 NIIBE Yutaka + + ecc: Fix memory leaks on error. + + commit b12dd550fd6af687ef95c584d0d8366c34965cc8 + * cipher/ecc.c (ecc_decrypt_raw): Go to leave to release memory. + * mpi/ec.c (_gcry_mpi_ec_curve_point): Likewise. + +2016-02-09 NIIBE Yutaka + + ecc: input validation on ECDH. + + commit 23b72901f8a5ba9a78485b235c7a917fbc8faae0 + * cipher/ecc.c (ecc_decrypt_raw): Validate the point. + +2016-02-08 Jussi Kivilinna + + Add ARM assembly implementation of SHA-512. + + commit 8353884bc65c820d5bcacaf1ac23cdee72091a09 + * cipher/Makefile.am: Add 'sha512-arm.S'. + * cipher/sha512-arm.S: New. + * cipher/sha512.c (USE_ARM_ASM): New. + (_gcry_sha512_transform_arm): New. + (transform) [USE_ARM_ASM]: Use ARM assembly implementation instead of + generic. + * configure.ac: Add 'sha512-arm.lo'. + +2016-02-03 NIIBE Yutaka + + tests: Add a test for Curve25519. + + commit b8b3361504950689ef1e779fb3357cecf8a9f739 + * tests/Makefile.am (tests_bin): Add t-cv25519. + * tests/t-cv25519.c: New. + +2016-02-02 NIIBE Yutaka + + ecc: Fix Curve25519 for data by older implementation. + + commit 6cb6df9dddac6ad246002b83c2ce0aaa0ecf30e5 + * cipher/ecc-misc.c (gcry_ecc_mont_decodepoint): Fix code path for + short length data. + + ecc: more fix of Curve25519. + + commit 48ba5a50066611ecacea850ced13f5cb66097a81 + * cipher/ecc-misc.c (gcry_ecc_mont_decodepoint): Fix removing of + prefix. Clear the MSB, according to RFC7748. + + ecc: Fix ECDH of Curve25519. + + commit a2f9afcd7fcdafd5951498b07f34957f9766dce9 + * cipher/ecc-misc.c (_gcry_ecc_mont_decodepoint): Fix calc of NBITS + and prefix detection. + * cipher/ecc.c (ecc_generate): Use NBITS instead of CTX->NBITS. + (ecc_encrypt_raw): Use NBITS from curve instead of from P. + Fix rawmpilen calculation. + (ecc_decrypt_raw): Likewise. Add debug output. + +2016-01-29 Jussi Kivilinna + + Improve performance of generic SHA256 implementation. + + commit f3e51161036382429c3491c7c881f36c0a653c7b + * cipher/sha256.c (R): Let caller do variable shuffling. + (Chro, Maj, Sum0, Sum1): Convert from inline functions to macros. + (W, I): New. + (transform_blk): Unroll round loop; inline message expansion to rounds + to make message expansion buffer smaller. + +2016-01-28 Werner Koch + + ecc: New API function gcry_mpi_ec_decode_point. + + commit 2cf2ca7bb9741ac86e8aa92d8f03b1c5f5938897 + * mpi/ec.c (_gcry_mpi_ec_decode_point): New. + * cipher/ecc-common.h: Move two prototypes to ... + * src/ec-context.h: here. + * src/gcrypt.h.in (gcry_mpi_ec_decode_point): New. + * src/libgcrypt.def (gcry_mpi_ec_decode_point): New. + * src/libgcrypt.vers (gcry_mpi_ec_decode_point): New. + * src/visibility.c (gcry_mpi_ec_decode_point): New. + * src/visibility.h: Add new function. + +2016-01-15 Werner Koch + + Fix build problem for rndegd.c. + + commit 191c2e4fe2dc0e00f61aa44e011a9596887e6ce1 + * Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Test all RND modules. + * random/rndegd.c (_gcry_rndegd_connect_socket) + (my_make_filename): Use functions with '_' prefix. + + random: Fix possible AIX problem with sysconf in rndunix. + + commit 6303b0e83856ee89374b447e710f0ab2af61caec + * random/rndunix.c [HAVE_STDINT_H]: Include stdint.h. + (start_gatherer): Detect misbehaving sysconf. + +2015-12-27 Werner Koch + + random: Take at max 25% from RDRAND. + + commit 5a78e7f15e0dd96a8bf64e2bb142880bf8ea6965 + * random/rndlinux.c (_gcry_rndlinux_gather_random): Change use of + RDRAND from 50% to 25%. + +2015-12-07 Justus Winter + + cipher: Improve error handling. + + commit b9c02fbeb7efb7d0593b33485fb30c298291cf80 + * cipher/ecc.c (ecc_decrypt_raw): Improve error handling. + + cipher: Initialize 'flags'. + + commit ca06cd7f77acb317c2649c58918908f043dfe6bd + * cipher/ecc.c (ecc_encrypt_raw): Initialize 'flags' to 0. + +2015-12-05 NIIBE Yutaka + + ecc: CHANGE point representation of Curve25519. + + commit dd3d06e7f113cf7608f060ceb043262efd0b0c9d + * cipher/ecc-misc.c (_gcry_ecc_mont_decodepoint): Decode point with + the prefix 0x40, additional 0x00 by MPI handling, and shorter octets + by MPI normalization. + * cipher/ecc.c (ecc_generate, ecc_encrypt_raw, ecc_decrypt_raw): + Always add the prefix 0x40. + +2015-12-03 Jussi Kivilinna + + chacha20: fix alignment of self-test context. + + commit 6fadbcd088e2af3e48407b95d8d0c2a8b7ad6c38 + * cipher/chacha20.c (selftest): Ensure 16-byte alignment for chacha20 + context structure. + + salsa20: fix alignment of self-test context. + + commit 2cba0dbda462237f55438d4199eccd10c5e3f6ca + * cipher/salsa20.c (selftest): Ensure 16-byte alignment for salsa20 + context structure. + +2015-12-02 Justus Winter + + random: Drop fake entropy gathering function. + + commit d421ac283ec46d0ecaf6278ba4c24843f65fb2fa + * random/random-csprng.c (faked_rng): Drop variable. + (gather_faked): Drop prototype and function. + (initialize): Drop fallback code. + (_gcry_rngcsprng_is_faked): Change accordingly. + + random: Fix selection of entropy gathering function. + + commit 468a5796ffb1a7776db4004d534376c1b981d740 + * random/random-csprng.c (getfnc_gather_random): Do return NULL if no + usable entropy gathering function is found. The callsite then + installs the fake gather function. + +2015-11-26 NIIBE Yutaka + + ecc: minor improvement of point multiplication. + + commit 3658afd09c3b03b4398aaa5748387220c93b1a94 + * mpi/ec.c (_gcry_mpi_ec_mul_point): Move ec_subm out of the loop. + +2015-11-25 NIIBE Yutaka + + ecc: Constant-time multiplication for Weierstrass curve. + + commit 88e1358962e902ff1cbec8d53ba3eee46407851a + * mpi/ec.c (_gcry_mpi_ec_mul_point): Use simple left-to-right binary + method for Weierstrass curve when SCALAR is secure. + + mpi: fix gcry_mpi_swap_cond. + + commit f88adee3e1f3e2de7d63f92f90bfb3078afd3b4f + * mpi/mpiutil.c (_gcry_mpi_swap_cond): Relax the condition. + + mpi: Fix mpi_set_cond and mpi_swap_cond . + + commit 8ad682c412047d3b9196950709dbd7bd14ac8732 + * mpi/mpiutil.c (_gcry_mpi_set_cond, _gcry_mpi_swap_cond): Don't use + the operator of !!, but assume SET/SWAP is 0 or 1. + + ecc: multiplication of Edwards curve to be constant-time. + + commit 295b1c3540752af4fc5e6f41480e6db215222fba + * mpi/ec.c (_gcry_mpi_ec_mul_point): Use point_swap_cond. + + ecc: Add point_resize and point_swap_cond. + + commit b6015176df6bfae107ac82f9baa29ef2c175c9f9 + * mpi/ec.c (point_resize, point_swap_cond): New. + (_gcry_mpi_ec_mul_point): Use point_resize and point_swap_cond. + +2015-11-18 Justus Winter + + cipher: Fix error handling. + + commit 940dc8adc034a6c6c38742f6bfd7d837a532d537 + * cipher/cipher.c (_gcry_cipher_ctl): Fix error handling. + +2015-11-18 Jussi Kivilinna + + Tweak Keccak for small speed-up. + + commit 6571a64331839d7d952292163afbf34c8bef62e0 + * cipher/keccak_permute_32.h (KECCAK_F1600_PERMUTE_FUNC_NAME): Track + rounds with round constant pointer instead of separate round counter. + * cipher/keccak_permute_64.h (KECCAK_F1600_PERMUTE_FUNC_NAME): Ditto. + (KECCAK_F1600_ABSORB_FUNC_NAME): Tweak lanes pointer increment for bulk + absorb loops. + + Update license information for CRC. + + commit 15ea0acf8bb0aa307eccc23024a0bd7878fb8080 + * LICENSES: Remove 'Simple permissive' and 'IETF permissive' licenses + for 'cipher/crc.c' as result of rewrite of CRC implementations. + +2015-11-17 Justus Winter + + Fix typos found using codespell. + + commit 0e395944b70c7a92a6437f6bcc14f287c19ce9de + * cipher/cipher-ocb.c: Fix typos. + * cipher/des.c: Likewise. + * cipher/dsa-common.c: Likewise. + * cipher/ecc.c: Likewise. + * cipher/pubkey.c: Likewise. + * cipher/rsa-common.c: Likewise. + * cipher/scrypt.c: Likewise. + * random/random-csprng.c: Likewise. + * random/random-fips.c: Likewise. + * random/rndw32.c: Likewise. + * src/cipher-proto.h: Likewise. + * src/context.c: Likewise. + * src/fips.c: Likewise. + * src/gcrypt.h.in: Likewise. + * src/global.c: Likewise. + * src/sexp.c: Likewise. + * tests/mpitests.c: Likewise. + * tests/t-lock.c: Likewise. + +2015-11-01 Jussi Kivilinna + + Improve performance of Tiger hash algorithms. + + commit 89fa74d6b3e58cd4fcd6e0939a35e46cbaca2ea0 + * cipher/tiger.c (tiger_round, pass, key_schedule): Convert functions + to macros. + (transform_blk): Pass variable names instead of pointers to 'pass'. + + Add ARMv7/NEON implementation of Keccak. + + commit a1cc7bb15473a2419b24ecac765ae0ce5989a13b + * cipher/Makefile.am: Add 'keccak-armv7-neon.S'. + * cipher/keccak-armv7-neon.S: New. + * cipher/keccak.c (USE_64BIT_ARM_NEON): New. + (NEED_COMMON64): Select if USE_64BIT_ARM_NEON. + [NEED_COMMON64] (round_consts_64bit): Rename to... + [NEED_COMMON64] (_gcry_keccak_round_consts_64bit): ...this; Add + terminator at end. + [USE_64BIT_ARM_NEON] (_gcry_keccak_permute_armv7_neon) + (_gcry_keccak_absorb_lanes64_armv7_neon, keccak_permute64_armv7_neon) + (keccak_absorb_lanes64_armv7_neon, keccak_armv7_neon_64_ops): New. + (keccak_init) [USE_64BIT_ARM_NEON]: Select ARM/NEON implementation + if supported by HW. + * cipher/keccak_permute_64.h (KECCAK_F1600_PERMUTE_FUNC_NAME): Update + to use new round constant table. + * configure.ac: Add 'keccak-armv7-neon.lo'. + + Optimize Keccak 64-bit absorb functions. + + commit 2857cb89c6dc1c02266600bc1fd2967a3cd5cf88 + * cipher/keccak.c [USE_64BIT] [__x86_64__] (absorb_lanes64_8) + (absorb_lanes64_4, absorb_lanes64_2, absorb_lanes64_1): New. + * cipher/keccak.c [USE_64BIT] [!__x86_64__] (absorb_lanes64_8) + (absorb_lanes64_4, absorb_lanes64_2, absorb_lanes64_1): New. + [USE_64BIT] (KECCAK_F1600_ABSORB_FUNC_NAME): New. + [USE_64BIT] (keccak_absorb_lanes64): Remove. + [USE_64BIT_SHLD] (KECCAK_F1600_ABSORB_FUNC_NAME): New. + [USE_64BIT_SHLD] (keccak_absorb_lanes64_shld): Remove. + [USE_64BIT_BMI2] (KECCAK_F1600_ABSORB_FUNC_NAME): New. + [USE_64BIT_BMI2] (keccak_absorb_lanes64_bmi2): Remove. + * cipher/keccak_permute_64.h (KECCAK_F1600_ABSORB_FUNC_NAME): New. + +2015-10-31 Jussi Kivilinna + + Enable CRC test vectors with zero bytes. + + commit 07e4839e75a7bca3a6c0a94aecfe75efe61d7ff2 + * tests/basic.c (check_digests): Enable CRC test-vectors with zero + bytes. + + Keccak: Add SHAKE Extendable-Output Functions. + + commit c0b9eee2d93a13930244f9ce0c14ed6b4aeb6c29 + * src/hash-common.c (_gcry_hash_selftest_check_one): Add handling for + XOFs. + * src/keccak.c (keccak_ops_t): Rename 'extract_inplace' to 'extract' + and add 'pos' argument. + (KECCAK_CONTEXT): Add 'suffix'. + (keccak_extract_inplace64): Rename to... + (keccak_extract64): ...this; Add handling for 'pos' argument. + (keccak_extract_inplace32bi): Rename to... + (keccak_extract32bi): ...this; Add handling for 'pos' argument. + (keccak_extract_inplace64): Rename to... + (keccak_extract64): ...this; Add handling for 'pos' argument. + (keccak_extract_inplace32bi_bmi2): Rename to... + (keccak_extract32bi_bmi2): ...this; Add handling for 'pos' argument. + (keccak_init): Setup 'suffix'; add SHAKE128 & SHAKE256. + (shake128_init, shake256_init): New. + (keccak_final): Do not initial permute for SHAKE output; use correct + suffix for SHAKE. + (keccak_extract): New. + (keccak_selftests_keccak): Add SHAKE128 & SHAKE256 test-vectors. + (run_selftests): Add SHAKE128 & SHAKE256. + (shake128_asn, oid_spec_shake128, shake256_asn, oid_spec_shake256) + (_gcry_digest_spec_shake128, _gcry_digest_spec_shake256): New. + * cipher/md.c (digest_list): Add SHAKE128 & SHAKE256. + * doc/gcrypt.texi: Ditto. + * src/cipher.h (_gcry_digest_spec_shake128) + (_gcry_digest_spec_shake256): New. + * src/gcrypt.h.in (GCRY_MD_SHAKE128, GCRY_MD_SHAKE256): New. + * tests/basic.c (check_one_md): Add XOF check; Add 'elen' argument. + (check_one_md_multi): Skip if algo is XOF. + (check_digests): Add SHAKE128 & SHAKE256 test vectors. + * tests/bench-slope.c (kdf_bench_one): Skip XOFs. + + Few updates to documentation. + + commit 28de6f9e16e386018e81a9cdaee596be7616ccab + * doc/gcrypt.text: Add mention of new 'intel-fast-shld' hw feature + flag; Add mention of x86 RDRAND support in rndhw. + + Add HMAC-SHA3 test vectors. + + commit 92ad19873562cfce7bcc4a0b5aed8195d8284cfc + * tests/basic.c (check_mac): Add HMAC_SHA3 test vectors. + +2015-10-28 Jussi Kivilinna + + md: add variable length output interface. + + commit 577dc2b63ceca6a8a716256d034ea4e7414f65fa + * cipher/crc.c (_gcry_digest_spec_crc32) + (_gcry_digest_spec_crc32_rfc1510, _gcry_digest_spec_crc24_rfc2440): Set + 'extract' NULL. + * cipher/gostr3411-94.c (_gcry_digest_spec_gost3411_94) + (_gcry_digest_spec_gost3411_cp): Ditto. + * cipher/keccak.c (_gcry_digest_spec_sha3_224) + (_gcry_digest_spec_sha3_256, _gcry_digest_spec_sha3_384) + (_gcry_digest_spec_sha3_512): Ditto. + * cipher/md2.c (_gcry_digest_spec_md2): Ditto. + * cipher/md4.c (_gcry_digest_spec_md4): Ditto. + * cipher/md5.c (_gcry_digest_spec_md5): Ditto. + * cipher/rmd160.c (_gcry_digest_spec_rmd160): Ditto. + * cipher/sha1.c (_gcry_digest_spec_sha1): Ditto. + * cipher/sha256.c (_gcry_digest_spec_sha224) + (_gcry_digest_spec_sha256): Ditto. + * cipher/sha512.c (_gcry_digest_spec_sha384) + (_gcry_digest_spec_sha512): Ditto. + * cipher/stribog.c (_gcry_digest_spec_stribog_256) + (_gcry_digest_spec_stribog_512): Ditto. + * cipher/tiger.c (_gcry_digest_spec_tiger) + (_gcry_digest_spec_tiger1, _gcry_digest_spec_tiger2): Ditto. + * cipher/whirlpool.c (_gcry_digest_spec_whirlpool): Ditto. + * cipher/md.c (md_enable): Do not allow combination of HMAC and + 'expandable-output function'. + (md_final): Check if spec->read is NULL before calling. + (md_read): Ditto. + (md_extract, _gcry_md_extract): New. + * doc/gcrypt.texi: Add SHA3 algorithms and gcry_md_extract. + * src/cipher-proto.h (gcry_md_extract_t): New. + (gcry_md_spec_t): Add 'extract'. + * src/gcrypt-int.g (_gcry_md_extract): New. + * src/gcrypt.h.in (gcry_md_extract): New. + * src/libgcrypt.def: Add gcry_md_extract. + * src/libgcrypt.vers: Add gcry_md_extract. + * src/visibility.c (gcry_md_extract): New. + * src/visibility.h (gcry_md_extract): New. + + md: check hmac flag in prepare_macpads. + + commit cee2e122ec6c1886957a8d47498eb63a6a921725 + * cipher/md.c (prepare_macpads): Check hmac flag. + + keccak: rewrite for improved performance. + + commit 74184c28fbe7ff58cf57f0094ef957d94045da7d + * cipher/Makefile.am: Add 'keccak_permute_32.h' and + 'keccak_permute_64.h'. + * cipher/hash-common.h [USE_SHA3] (MD_BLOCK_MAX_BLOCKSIZE): Remove. + * cipher/keccak.c (USE_64BIT, USE_32BIT, USE_64BIT_BMI2) + (USE_64BIT_SHLD, USE_32BIT_BMI2, NEED_COMMON64, NEED_COMMON32BI) + (keccak_ops_t): New. + (KECCAK_STATE): Add 'state64' and 'state32bi' members. + (KECCAK_CONTEXT): Remove 'bctx'; add 'blocksize', 'count' and 'ops'. + (rol64, keccak_f1600_state_permute): Remove. + [NEED_COMMON64] (round_consts_64bit, keccak_extract_inplace64): New. + [NEED_COMMON32BI] (round_consts_32bit, keccak_extract_inplace32bi) + (keccak_absorb_lane32bi): New. + [USE_64BIT] (ANDN64, ROL64, keccak_f1600_state_permute64) + (keccak_absorb_lanes64, keccak_generic64_ops): New. + [USE_64BIT_SHLD] (ANDN64, ROL64, keccak_f1600_state_permute64_shld) + (keccak_absorb_lanes64_shld, keccak_shld_64_ops): New. + [USE_64BIT_BMI2] (ANDN64, ROL64, keccak_f1600_state_permute64_bmi2) + (keccak_absorb_lanes64_bmi2, keccak_bmi2_64_ops): New. + [USE_32BIT] (ANDN64, ROL64, keccak_f1600_state_permute32bi) + (keccak_absorb_lanes32bi, keccak_generic32bi_ops): New. + [USE_32BIT_BMI2] (ANDN64, ROL64, keccak_f1600_state_permute32bi_bmi2) + (pext, pdep, keccak_absorb_lane32bi_bmi2, keccak_absorb_lanes32bi_bmi2) + (keccak_extract_inplace32bi_bmi2, keccak_bmi2_32bi_ops): New. + (keccak_write): New. + (keccak_init): Adjust to KECCAK_CONTEXT changes; add implementation + selection based on HWF features. + (keccak_final): Adjust to KECCAK_CONTEXT changes; use selected 'ops' + for state manipulation. + (keccak_read): Adjust to KECCAK_CONTEXT changes. + (_gcry_digest_spec_sha3_224, _gcry_digest_spec_sha3_256) + (_gcry_digest_spec_sha3_348, _gcry_digest_spec_sha3_512): Use + 'keccak_write' instead of '_gcry_md_block_write'. + * cipher/keccak_permute_32.h: New. + * cipher/keccak_permute_64.h: New. + + hwf-x86: add detection for Intel CPUs with fast SHLD instruction. + + commit 909644ef5883927262366c356eed530e55aba478 + * cipher/sha1.c (sha1_init): Use HWF_INTEL_FAST_SHLD instead of + HWF_INTEL_CPU. + * cipher/sha256.c (sha256_init, sha224_init): Ditto. + * cipher/sha512.c (sha512_init, sha384_init): Ditto. + * src/g10lib.h (HWF_INTEL_FAST_SHLD): New. + (HWF_INTEL_BMI2, HWF_INTEL_SSSE3, HWF_INTEL_PCLMUL, HWF_INTEL_AESNI) + (HWF_INTEL_RDRAND, HWF_INTEL_AVX, HWF_INTEL_AVX2) + (HWF_ARM_NEON): Update. + * src/hwf-x86.c (detect_x86_gnuc): Add detection of Intel Core + CPUs with fast SHLD/SHRD instruction. + * src/hwfeatures.c (hwflist): Add "intel-fast-shld". + + Fix OCB amd64 assembly implementations for x32. + + commit 16fd540f4d01eb6dc23d9509ae549353617c7a67 + * cipher/camellia-glue.c (_gcry_camellia_aesni_avx_ocb_enc) + (_gcry_camellia_aesni_avx_ocb_dec, _gcry_camellia_aesni_avx_ocb_auth) + (_gcry_camellia_aesni_avx2_ocb_enc, _gcry_camellia_aesni_avx2_ocb_dec) + (_gcry_camellia_aesni_avx2_ocb_auth, _gcry_camellia_ocb_crypt) + (_gcry_camellia_ocb_auth): Change 'Ls' from pointer array to u64 array. + * cipher/serpent.c (_gcry_serpent_sse2_ocb_enc) + (_gcry_serpent_sse2_ocb_dec, _gcry_serpent_sse2_ocb_auth) + (_gcry_serpent_avx2_ocb_enc, _gcry_serpent_avx2_ocb_dec) + (_gcry_serpent_ocb_crypt, _gcry_serpent_ocb_auth): Ditto. + * cipher/twofish.c (_gcry_twofish_amd64_ocb_enc) + (_gcry_twofish_amd64_ocb_dec, _gcry_twofish_amd64_ocb_auth) + (twofish_amd64_ocb_enc, twofish_amd64_ocb_dec, twofish_amd64_ocb_auth) + (_gcry_twofish_ocb_crypt, _gcry_twofish_ocb_auth): Ditto. + + bench-slope: add KDF/PBKDF2 benchmark. + + commit ae40af427fd2a856b24ec2a41323ec8b80ffc9c0 + * tests/bench-slope.c (bench_kdf_mode, bench_kdf_init, bench_kdf_free) + (bench_kdf_do_bench, kdf_ops, kdf_bench_one, kdf_bench): New. + (print_help): Add 'kdf'. + (main): Add KDF benchmarks. + +2015-10-22 NIIBE Yutaka + + md: keep contexts for HMAC in GcryDigestEntry. + + commit f7505b550dd591e33d3a3fab9277c43c460f1bad + * cipher/md.c (struct gcry_md_context): Add flags.hmac. + Remove macpads and mcpads_Bsize. + (md_open): Initialize flags.hmac. Remove macpads initialization. + (md_enable): Allocate contexts when flags.hmac is enabled. + (md_copy): Remove macpads copying. Add copying contexts. + (_gcry_md_reset): When flags.hmac is enabled, restore precomputed + context with input pad + (md_close): Remove macpads wiping. + (md_final): When flags.hmac is enabled, compute hmac by precomputed + context with output pad. + (prepare_macpads): Prepare precomputed contexts with input pad and + output pad for each registered digest entry. + (_gcry_md_setkey): Just call prepare_macpads. + +2015-10-15 NIIBE Yutaka + + Fix double free on error. + + commit 1c6d2698a84e4bf82735287c1d64954bfc1a1982 + * src/hmac256.c (_gcry_hmac256_finalize): Don't free HD. + +2015-10-14 NIIBE Yutaka + + Fix gpg_error_t and gpg_err_code_t confusion. + + commit 813565a07ca575c87e1252c6ed26018653ecd338 + * src/gcrypt-int.h (_gcry_sexp_extract_param): Revert the change. + * cipher/dsa.c (dsa_check_secret_key): Ditto. + * src/sexp.c (_gcry_sexp_extract_param): Return gpg_err_code_t. + + * src/gcrypt-int.h (_gcry_err_make_from_errno) + (_gcry_error_from_errno): Return gpg_error_t. + * cipher/cipher.c (_gcry_cipher_open_internal) + (_gcry_cipher_ctl, _gcry_cipher_ctl): Don't use gcry_error. + * src/global.c (_gcry_vcontrol): Likewise. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_genkey): Use + gpg_err_code_from_syserror. + * cipher/mac.c (mac_reset, mac_setkey, mac_setiv, mac_write) + (mac_read, mac_verify): Return gcry_err_code_t. + * cipher/rsa-common.c (mgf1): Use gcry_err_code_t for ERR. + * src/visibility.c (gcry_error_from_errno): Return gpg_error_t. + +2015-10-13 Jussi Kivilinna + + Fix compiling AES/AES-NI implementation on linux-i386. + + commit fa94b6111948a614ebdcb67f7942eced8b84c579 + * cipher/rijndael-aesni.c (do_aesni_ctr_4): Split assembly block in + two parts to reduce number of register constraints needed. + +2015-10-13 NIIBE Yutaka + + Fix declaration of return type. + + commit 73374fdd27c7ba28b19f9672c68a6f5b72252fe5 + * src/gcrypt-int.h (_gcry_sexp_extract_param): Return gpg_error_t. + * cipher/dsa.c (dsa_generate): Fix call to _gcry_sexp_extract_param. + * src/g10lib.h (_gcry_vcontrol): Return gcry_err_code_t. + * src/visibility.c (gcry_mpi_snatch): Fix call to _gcry_mpi_snatch. + +2015-09-07 Werner Koch + + Improve GCRYCTL_DISABLE_PRIV_DROP by also disabling cap_ calls. + + commit 3a3d5410cc83f7069c7cb1ab384905f382292d32 + * src/secmem.c (lock_pool, secmem_init): Do not call any cap_ + functions if NO_PRIV_DROP is set. + +2015-09-04 Werner Koch + + w32: Avoid a few compiler warnings. + + commit e97c62a4a687b56d00a2d0a63e072a977f8eb81c + * cipher/cipher-selftest.c (_gcry_selftest_helper_cbc) + (_gcry_selftest_helper_cfb, _gcry_selftest_helper_ctr): Mark variable + as unused. + * random/rndw32.c (slow_gatherer): Avoid signed pointer mismatch + warning. + * src/secmem.c (init_pool): Avoid unused variable warning. + * tests/random.c (writen, readn): Include on if needed. + + w32: Fix alignment problem with AESNI on Windows >= 8. + + commit e2785a2268702312529521df3bd2f4e6b43cea3a + * cipher/cipher-selftest.c (_gcry_cipher_selftest_alloc_ctx): New. + * cipher/rijndael.c (selftest_basic_128, selftest_basic_192) + (selftest_basic_256): Allocate context on the heap. + +2015-08-31 Werner Koch + + rsa: Add verify after sign to avoid Lenstra's CRT attack. + + commit c17f84bd02d7ee93845e92e20f6ddba814961588 + * cipher/rsa.c (rsa_sign): Check the CRT. + + Add pubkey algo id for EdDSA. + + commit dd87639abd38afc91a6f27af33f0ba17402ad02d + * src/gcrypt.h.in (GCRY_PK_EDDSA): New. + +2015-08-25 Werner Koch + + Add configure option --enable-build-timestamp. + + commit a785cc3db0c4e8eb8ebbf784b833a40d2c42ec3e + * configure.ac (BUILD_TIMESTAMP): Set to "" by default. + +2015-08-23 Werner Koch + + tests: Add missing files for the make distcheck target. + + commit fb3cb47b0a29d3e73150297aa4495c20915e4a75 + * tests/Makefile.am (EXTRA_DIST): Add sha3-x test vector files. + +2015-08-19 Werner Koch + + Change SHA-3 algorithm ids. + + commit 65639ecaaeba642e40487446c40d045482001285 + * src/gcrypt.h.in (GCRY_MD_SHA3_224, GCRY_MD_SHA3_256) + (GCRY_MD_SHA3_384, GCRY_MD_SHA3_512): Change values. + +2015-08-12 Jussi Kivilinna + + Keccak: Fix array indexes in θ step. + + commit 48822ae0b436bcea0fe92dbf0d88475ba3179320 + * cipher/keccak.c (keccak_f1600_state_permute): Fix indexes for D[5]. + + Simplify OCB offset calculation for parallel implementations. + + commit 24ebf53f1e8a8afa27dcd768339bda70a740bb03 + * cipher/camellia-glue.c (_gcry_camellia_ocb_crypt) + (_gcry_camellia_ocb_auth): Precalculate Ls array always, instead of + just if 'blkn % == 0'. + * cipher/serpent.c (_gcry_serpent_ocb_crypt) + (_gcry_serpent_ocb_auth): Ditto. + * cipher/rijndael-aesni.c (get_l): Remove low-bit checks. + (aes_ocb_enc, aes_ocb_dec, _gcry_aes_aesni_ocb_auth): Handle leading + blocks until block counter is multiple of 4, so that parallel block + processing loop can use 'c->u_mode.ocb.L' array directly. + * tests/basic.c (check_ocb_cipher_largebuf): Rename to... + (check_ocb_cipher_largebuf_split): ...this and add option to process + large buffer as two split buffers. + (check_ocb_cipher_largebuf): New. + + Add carryless 8-bit addition fast-path for AES-NI CTR mode. + + commit e11895da1f4af9782d89e92ba2e6b1a63235b54b + * cipher/rijndael-aesni.c (do_aesni_ctr_4): Do addition using + CTR in big-endian form, if least-significant byte does not overflow. + +2015-08-10 Jussi Kivilinna + + Add additional SHA3 test-vectors. + + commit 80321eb3a63a20f86734d6eebb3f419c0ec895aa + * tests/basic.c (check_digests): Allow datalen to be specified so that + input data can have byte with value 0x00; Include sha3-*.h header files + to test-vector structure. + * tests/sha3-224.h: New. + * tests/sha3-256.h: New. + * tests/sha3-384.h: New. + * tests/sha3-512.h: New. + + Add generic SHA3 implementation. + + commit 434ba17d1d5ad59c70d721ad3ecb376c2403a7e5 + * cipher/hash-common.h (MD_BLOCK_MAX_BLOCKSIZE): Increase blocksize + USE_SHA3 enabled. + * cipher/keccak.c (SHA3_DELIMITED_SUFFIX, SHAKE_DELIMITED_SUFFIX): New. + (KECCAK_STATE): Add proper state. + (KECCAK_CONTEXT): Add 'outlen'. + (rol64, keccak_f1600_state_permute, transform_blk, transform): New. + (keccak_init): Add proper initialization. + (keccak_final): Add proper finalization. + (selftests_keccak): Add selftests. + (oid_spec_sha3_224, oid_spec_sha3_256, oid_spec_sha3_384) + (oid_spec_sha3_512): Add OID. + (_gcry_digest_spec_sha3_224, _gcry_digest_spec_sha3_256) + (_gcry_digest_spec_sha3_384, _gcry_digest_spec_sha3_512): Fix output + length. + * cipher/mac-hmac.c (map_mac_algo_to_md): Fix mapping for SHA3-512. + (hmac_get_keylen): Return proper blocksizes for SHA3 algorithms. + [USE_SHA3] (_gcry_mac_type_spec_hmac_sha3_224) + (_gcry_mac_type_spec_hmac_sha3_256, _gcry_mac_type_spec_hmac_sha3_384) + (_gcry_mac_type_spec_hmac_sha3_512): New. + * cipher/mac-internal [USE_SHA3] (_gcry_mac_type_spec_hmac_sha3_224) + (_gcry_mac_type_spec_hmac_sha3_256, _gcry_mac_type_spec_hmac_sha3_384) + (_gcry_mac_type_spec_hmac_sha3_512): New. + * cipher/mac.c (mac_list) [USE_SHA3]: Add SHA3 algorithms. + * cipher/md.c (md_open): Use proper SHA-3 blocksizes for HMAC macpads. + * tests/basic.c (check_digests): Add SHA3 test vectors. + + Optimize OCB offset calculation. + + commit 49f52c67fb42c0656c8f9af655087f444562ca82 + * cipher/cipher-internal.h (ocb_get_l): New. + * cipher/cipher-ocb.c (_gcry_cipher_ocb_authenticate) + (ocb_crypt): Use 'ocb_get_l' instead of '_gcry_cipher_ocb_get_l'. + * cipher/camellia-glue.c (get_l): Remove. + (_gcry_camellia_ocb_crypt, _gcry_camellia_ocb_auth): Precalculate + offset array when block count matches parallel operation size; Use + 'ocb_get_l' instead of 'get_l'. + * cipher/rijndael-aesni.c (get_l): Add fast path for 75% most common + offsets. + (aesni_ocb_enc, aesni_ocb_dec, _gcry_aes_aesni_ocb_auth): Precalculate + offset array when block count matches parallel operation size. + * cipher/rijndael-ssse3-amd64.c (get_l): Add fast path for 75% most + common offsets. + * cipher/rijndael.c (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth): Use + 'ocb_get_l' instead of '_gcry_cipher_ocb_get_l'. + * cipher/serpent.c (get_l): Remove. + (_gcry_serpent_ocb_crypt, _gcry_serpent_ocb_auth): Precalculate + offset array when block count matches parallel operation size; Use + 'ocb_get_l' instead of 'get_l'. + * cipher/twofish.c (get_l): Remove. + (_gcry_twofish_ocb_crypt, _gcry_twofish_ocb_auth): Use 'ocb_get_l' + instead of 'get_l'. + +2015-08-10 NIIBE Yutaka + + ecc: fix Montgomery curve bugs. + + commit ce746936b6c210e602d106cfbf45cf60b408d871 + * cipher/ecc.c (check_secret_key): Y1 should not be NULL when check. + (ecc_check_secret_key): Support Montgomery curve. + * mpi/ec.c (_gcry_mpi_ec_curve_point): Fix condition. + +2015-08-08 Werner Koch + + Add framework to eventually support SHA3. + + commit 0e17f7a05bba309a87811992aa47a77af9935b99 + * src/gcrypt.h.in (GCRY_MD_SHA3_224, GCRY_MD_SHA3_256) + (GCRY_MD_SHA3_384, GCRY_MD_SHA3_512): New. + (GCRY_MAC_HMAC_SHA3_224, GCRY_MAC_HMAC_SHA3_256) + (GCRY_MAC_HMAC_SHA3_384, GCRY_MAC_HMAC_SHA3_512): New. + * cipher/keccak.c: New with stub functions. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add keccak.c. + * configure.ac (available_digests): Add sha3. + (USE_SHA3): New. + * src/fips.c (run_hmac_selftests): Add SHA3 to the required selftests. + * cipher/md.c (digest_list) [USE_SHA3]: Add standard SHA3 algos. + (md_open): Ditto for hmac processing. + * cipher/mac-hmac.c (map_mac_algo_to_md): Add mapping. + * cipher/hmac-tests.c (run_selftests): Prepare for tests. + * cipher/pubkey-util.c (get_hash_algo): Add "sha3-xxx". + +2015-08-06 Werner Koch + + tools: Fix memory leak for functions "I" and "G". + + commit 10789e3cdda7b944acb4b59624c34a2ccfaea6e5 + * src/mpicalc.c (do_inv, do_gcd): Init A after stack check. + +2015-08-06 Ismo Puustinen + + ecc: Free memory also when in error branch. + + commit 1d896371fbc94c605fce35eabcde01e24dd22892 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_sign): Init DISGEST and goto + leave on error. + +2015-08-06 NIIBE Yutaka + + Add Curve25519 support. + + commit e93f4c21c59756604440ad8cbf27e67d29c99ffd + * cipher/ecc-curves.c (curve_aliases, domain_parms): Add Curve25519. + * tests/curves.c (N_CURVES): It's 22 now. + * src/cipher.h (PUBKEY_FLAG_DJB_TWEAK): New. + * cipher/ecc-common.h (_gcry_ecc_mont_decodepoint): New. + * cipher/ecc-misc.c (_gcry_ecc_mont_decodepoint): New. + * cipher/ecc.c (nist_generate_key): Handle the case of + PUBKEY_FLAG_DJB_TWEAK and Montgomery curve. + (test_ecdh_only_keys, check_secret_key): Likewise. + (ecc_generate): Support Curve25519 which is Montgomery curve with flag + PUBKEY_FLAG_DJB_TWEAK and PUBKEY_FLAG_COMP. + (ecc_encrypt_raw): Get flags from KEYPARMS and handle + PUBKEY_FLAG_DJB_TWEAK and Montgomery curve. + (ecc_decrypt_raw): Likewise. + (compute_keygrip): Handle the case of PUBKEY_FLAG_DJB_TWEAK. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): + PUBKEY_FLAG_EDDSA implies PUBKEY_FLAG_DJB_TWEAK. + Parse "djb-tweak" for PUBKEY_FLAG_DJB_TWEAK. + +2015-07-27 Jussi Kivilinna + + Reduce code size for Twofish key-setup and remove key dependend branch. + + commit b4b1d872ba651bc44761b35d245b1a519a33f515 + * cipher/twofish.c (poly_to_exp): Increase size by one, change type + from byte to u16 and insert '492' to index 0. + (exp_to_poly): Increase size by 256, let new cells have zero value. + (CALC_S): Execute unconditionally with help of modified tables. + (do_twofish_setkey): Change type for 'tmp' to 'unsigned int'; Un-unroll + CALC_K256 and CALC_K phases to reduce generated object size. + + Reduce amount of duplicated code in OCB bulk implementations. + + commit e950052bc6f5ff11a7c23091ff3f6b5cc431e875 + * cipher/cipher-ocb.c (_gcry_cipher_ocb_authenticate) + (ocb_crypt): Change bulk function to return number of unprocessed + blocks. + * src/cipher.h (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth) + (_gcry_camellia_ocb_crypt, _gcry_camellia_ocb_auth) + (_gcry_serpent_ocb_crypt, _gcry_serpent_ocb_auth) + (_gcry_twofish_ocb_crypt, _gcry_twofish_ocb_auth): Change return type + to 'size_t'. + * cipher/camellia-glue.c (get_l): Only if USE_AESNI_AVX or + USE_AESNI_AVX2 defined. + (_gcry_camellia_ocb_crypt, _gcry_camellia_ocb_auth): Change return type + to 'size_t' and return remaining blocks; Remove unaccelerated common + code path. Enable remaining common code only if USE_AESNI_AVX or + USE_AESNI_AVX2 defined; Remove unaccelerated common code. + * cipher/rijndael.c (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth): Change + return type to 'size_t' and return zero. + * cipher/serpent.c (get_l): Only if USE_SSE2, USE_AVX2 or USE_NEON + defined. + (_gcry_serpent_ocb_crypt, _gcry_serpent_ocb_auth): Change return type + to 'size_t' and return remaining blocks; Remove unaccelerated common + code path. Enable remaining common code only if USE_SSE2, USE_AVX2 or + USE_NEON defined; Remove unaccelerated common code. + * cipher/twofish.c (get_l): Only if USE_AMD64_ASM defined. + (_gcry_twofish_ocb_crypt, _gcry_twofish_ocb_auth): Change return type + to 'size_t' and return remaining blocks; Remove unaccelerated common + code path. Enable remaining common code only if USE_AMD64_ASM defined; + Remove unaccelerated common code. + + Add bulk OCB for Serpent SSE2, AVX2 and NEON implementations. + + commit adbdca0d58f9c06dc3850b95e3455e179c1e6960 + * cipher/cipher.c (_gcry_cipher_open_internal): Setup OCB bulk + functions for Serpent. + * cipher/serpent-armv7-neon.S: Add OCB assembly functions. + * cipher/serpent-avx2-amd64.S: Add OCB assembly functions. + * cipher/serpent-sse2-amd64.S: Add OCB assembly functions. + * cipher/serpent.c (_gcry_serpent_sse2_ocb_enc) + (_gcry_serpent_sse2_ocb_dec, _gcry_serpent_sse2_ocb_auth) + (_gcry_serpent_neon_ocb_enc, _gcry_serpent_neon_ocb_dec) + (_gcry_serpent_neon_ocb_auth, _gcry_serpent_avx2_ocb_enc) + (_gcry_serpent_avx2_ocb_dec, _gcry_serpent_avx2_ocb_auth): New + prototypes. + (get_l, _gcry_serpent_ocb_crypt, _gcry_serpent_ocb_auth): New. + * src/cipher.h (_gcry_serpent_ocb_crypt) + (_gcry_serpent_ocb_auth): New. + * tests/basic.c (check_ocb_cipher): Add test-vector for serpent. + + Add bulk OCB for Twofish AMD64 implementation. + + commit 7f6804c37c4b41d85fb26aa723b1c41e4a3cf278 + * cipher/cipher.c (_gcry_cipher_open_internal): Setup OCB bulk + functions for Twofish. + * cipher/twofish-amd64.S: Add OCB assembly functions. + * cipher/twofish.c (_gcry_twofish_amd64_ocb_enc) + (_gcry_twofish_amd64_ocb_dec, _gcry_twofish_amd64_ocb_auth): New + prototypes. + (call_sysv_fn5, call_sysv_fn6, twofish_amd64_ocb_enc) + (twofish_amd64_ocb_dec, twofish_amd64_ocb_auth, get_l) + (_gcry_twofish_ocb_crypt, _gcry_twofish_ocb_auth): New. + * src/cipher.h (_gcry_twofish_ocb_crypt) + (_gcry_twofish_ocb_auth): New. + * tests/basic.c (check_ocb_cipher): Add test-vector for Twofish. + + Add bulk OCB for Camellia AES-NI/AVX and AES-NI/AVX2 implementations. + + commit bb088c6b1620504fdc79e89af27c2bf3fb02b4b4 + * cipher/camellia-aesni-avx-amd64.S: Add OCB assembly functions. + * cipher/camellia-aesni-avx2-amd64.S: Add OCB assembly functions. + * cipher/camellia-glue.c (_gcry_camellia_aesni_avx_ocb_enc) + (_gcry_camellia_aesni_avx_ocb_dec, _gcry_camellia_aesni_avx_ocb_auth) + (_gcry_camellia_aesni_avx2_ocb_enc, _gcry_camellia_aesni_avx2_ocb_dec) + (_gcry_camellia_aesni_avx2_ocb_auth): New prototypes. + (get_l, _gcry_camellia_ocb_crypt, _gcry_camellia_ocb_auth): New. + * cipher/cipher.c (_gcry_cipher_open_internal): Setup OCB bulk + functions for Camellia. + * src/cipher.h (_gcry_camellia_ocb_crypt) + (_gcry_camellia_ocb_auth): New. + * tests/basic.c (check_ocb_cipher): Add test-vector for Camellia. + +2015-07-26 Jussi Kivilinna + + Add OCB bulk mode for AES SSSE3 implementation. + + commit 620e1e0300c79943a1846a49563b04386dc60546 + * cipher/rijndael-ssse3-amd64.c (SSSE3_STATE_SIZE): New. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (vpaes_ssse3_prepare): Use + 'ssse3_state' for storing current SSSE3 state. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] + (vpaes_ssse3_cleanup): Restore SSSE3 state from 'ssse3_state'. + (_gcry_aes_ssse3_do_setkey, _gcry_aes_ssse3_prepare_decryption) + (_gcry_aes_ssse3_encrypt, _gcry_aes_ssse3_cfb_enc) + (_gcry_aes_ssse3_cbc_enc, _gcry_aes_ssse3_ctr_enc) + (_gcry_aes_ssse3_decrypt, _gcry_aes_ssse3_cfb_dec) + (_gcry_aes_ssse3_cbc_dec, _gcry_aes_ssse3_cbc_dec): Add 'ssse3_state' + array. + (get_l, ssse3_ocb_enc, ssse3_ocb_dec, _gcry_aes_ssse3_ocb_crypt) + (_gcry_aes_ssse3_ocb_auth): New. + * cipher/rijndael.c (_gcry_aes_ssse3_ocb_crypt) + (_gcry_aes_ssse3_ocb_auth): New. + (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth) [USE_SSSE3]: Use SSSE3 + implementation for OCB. + +2015-07-26 Peter Wu + + Fix undefined behavior wrt memcpy. + + commit 46c072669eb81ed610cc5b3c0dc0c75a143afbb4 + * cipher/cipher-gcm.c: Do not copy zero bytes from an empty buffer. Let + the function continue to add padding as needed though. + * cipher/mac-poly1305.c: If the caller requested to finish the hash + function without a copy of the result, return immediately. + +2015-07-23 Peter Wu + + build: ignore scissor line for the commit-msg hook. + + commit ada0a7d302cca97b327faaacac7a5d0b8043df88 + * build-aux/git-hooks/commit-msg: Stop processing more lines when the + scissor line is encountered. + +2015-07-16 Peter Wu + + rsa: Fix error in comments. + + commit 9cd55e8e948f0049cb23495f536decf797d072f7 + * cipher/rsa.c: Fix. + +2015-07-14 Peter Wu + + sexp: Fix invalid deallocation in error path. + + commit 0f9532b186c1e0b54d7e7a6d76bce82b6226122b + * src/sexp.c: Fix wrong condition. + +2015-07-10 Peter Wu + + ecc: fix memory leak. + + commit 2a7aa3ea4d03a9c808d5888f5509c08cd27aa27c + * cipher/ecc.c (ecc_verify): Release memory which was allocated before + by _gcry_pk_util_preparse_sigval. + (ecc_decrypt_raw): Likewise. + +2015-07-06 NIIBE Yutaka + + ecc: fix memory leaks. + + commit 0a7547e487a8bc4e7ac9599c55579eb2e4a13f06 + cipher/ecc.c (ecc_generate): Fix memory leak on error of + _gcry_pk_util_parse_flaglist and _gcry_ecc_eddsa_encodepoint. + (ecc_check_secret_key): Fix memory leak on error of + _gcry_ecc_update_curve_param. + (ecc_sign, ecc_verify, ecc_encrypt_raw, ecc_decrypt_raw): Remove + unnecessary sexp_release and fix memory leak on error of + _gcry_ecc_fill_in_curve. + (ecc_decrypt_raw): Fix double free of the point kG and memory leak + on error of _gcry_ecc_os2ec. + +2015-06-11 NIIBE Yutaka + + mpi: Support FreeBSD 10 or later. + + commit a36ee7501f68ad7ebcfe31f9659430b9d2c3ddd1 + * mpi/config.links: Include FreeBSD 10 to 29. + +2015-05-21 Werner Koch + + ecc: Add key generation flag "no-keytest". + + commit 2bddd947fd1c11b4ec461576db65a5e34fea1b07 + * src/cipher.h (PUBKEY_FLAG_NO_KEYTEST): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Add flag + "no-keytest". Return an error for invalid flags of length 10. + + * cipher/ecc.c (nist_generate_key): Replace arg random_level by flags + set random level depending on flags. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_genkey): Ditto. + * cipher/ecc.c (ecc_generate): Pass flags to generate fucntion and + remove var random_level. + (nist_generate_key): Implement "no-keytest" flag. + + * tests/keygen.c (check_ecc_keys): Add tests for transient-key and + no-keytest. + + ecc: Avoid double conversion to affine coordinates in keygen. + + commit 102d68b3bd77813a3ff989526855bb1e283bf9d7 + * cipher/ecc.c (nist_generate_key): Add args r_x and r_y. + (ecc_generate): Rename vars. Convert to affine coordinates only if + not returned by the lower level generation function. + + random: Change initial extra seeding from 2400 bits to 128 bits. + + commit 8124e357b732a719696bfd5271def4e528f2a1e1 + * random/random-csprng.c (read_pool): Reduce initial seeding. + +2015-05-14 Jussi Kivilinna + + Enable AMD64 Twofish implementation on WIN64. + + commit 9b0c6c8141ae9bd056392a3f6b5704b505fc8501 + * cipher/twofish-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/twofish.c (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (call_sysv_fn): New. + (twofish_amd64_encrypt_block, twofish_amd64_decrypt_block) + (twofish_amd64_ctr_enc, twofish_amd64_cbc_dec) + (twofish_amd64_cfb_dec): New wrapper functions for AMD64 + assembly functions. + + Enable AMD64 Serpent implementations on WIN64. + + commit eb0ed576893b6c7990dbcb568510f831d246cea6 + * cipher/serpent-avx2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/serpent-sse2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/chacha20.c (USE_SSE2, USE_AVX2): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_SSE2 || USE_AVX2] (ASM_FUNC_ABI): New. + (_gcry_serpent_sse2_ctr_enc, _gcry_serpent_sse2_cbc_dec) + (_gcry_serpent_sse2_cfb_dec, _gcry_serpent_avx2_ctr_enc) + (_gcry_serpent_avx2_cbc_dec, _gcry_serpent_avx2_cfb_dec): Add + ASM_FUNC_ABI. + + Enable AMD64 Salsa20 implementation on WIN64. + + commit 12bc93ca8187b8061c2e705427ef22f5a71d29b0 + * cipher/salsa20-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/salsa20.c (USE_AMD64): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_AMD64] (ASM_FUNC_ABI, ASM_EXTRA_STACK): New. + (_gcry_salsa20_amd64_keysetup, _gcry_salsa20_amd64_ivsetup) + (_gcry_salsa20_amd64_encrypt_blocks): Add ASM_FUNC_ABI. + [USE_AMD64] (salsa20_core): Add ASM_EXTRA_STACK. + (salsa20_do_encrypt_stream) [USE_AMD64]: Add ASM_EXTRA_STACK. + + Enable AMD64 Poly1305 implementations on WIN64. + + commit 8d7de4dbf7732c6eb9e9853ad7c19c89075ace6f + * cipher/poly1305-avx2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/poly1305-sse2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/poly1305-internal.h (POLY1305_SYSV_FUNC_ABI): New. + (POLY1305_USE_SSE2, POLY1305_USE_AVX2): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (OPS_FUNC_ABI): New. + (poly1305_ops_t): Use OPS_FUNC_ABI. + * cipher/poly1305.c (_gcry_poly1305_amd64_sse2_init_ext) + (_gcry_poly1305_amd64_sse2_finish_ext) + (_gcry_poly1305_amd64_sse2_blocks, _gcry_poly1305_amd64_avx2_init_ext) + (_gcry_poly1305_amd64_avx2_finish_ext) + (_gcry_poly1305_amd64_avx2_blocks, _gcry_poly1305_armv7_neon_init_ext) + (_gcry_poly1305_armv7_neon_finish_ext) + (_gcry_poly1305_armv7_neon_blocks, poly1305_init_ext_ref32) + (poly1305_blocks_ref32, poly1305_finish_ext_ref32) + (poly1305_init_ext_ref8, poly1305_blocks_ref8) + (poly1305_finish_ext_ref8): Use OPS_FUNC_ABI. + + Enable AMD64 3DES implementation on WIN64. + + commit b65e9e71d5ee992db5c96793c6af999545daad28 + * cipher/des-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/des.c (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (call_sysv_fn): New. + (tripledes_ecb_crypt) [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS]: Call + assembly function through 'call_sysv_fn'. + (tripledes_amd64_ctr_enc, tripledes_amd64_cbc_dec) + (tripledes_amd64_cfb_dec): New wrapper functions for bulk + assembly functions. + + Enable AMD64 ChaCha20 implementations on WIN64. + + commit 9597cfddf03c467825da152be5ca0d12a8c30d88 + * cipher/chacha20-avx2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/chacha20-sse2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/chacha20-ssse3-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/chacha20.c (USE_SSE2, USE_SSSE3, USE_AVX2): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ASM_FUNC_ABI, ASM_EXTRA_STACK): New. + (chacha20_blocks_t, _gcry_chacha20_amd64_sse2_blocks) + (_gcry_chacha20_amd64_ssse3_blocks, _gcry_chacha20_amd64_avx2_blocks) + (_gcry_chacha20_armv7_neon_blocks, chacha20_blocks): Add ASM_FUNC_ABI. + (chacha20_core): Add ASM_EXTRA_STACK. + + Enable AMD64 CAST5 implementation on WIN64. + + commit 6a6646df80386204675d8b149ab60e74d7ca124c + * cipher/cast5-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (RIP): Remove. + (GET_EXTERN_POINTER): Use 'leaq' version on WIN64. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/cast5.c (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (call_sysv_fn): New. + (do_encrypt_block, do_decrypt_block) + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS]: Call assembly + function through 'call_sysv_fn'. + (cast5_amd64_ctr_enc, cast5_amd64_cbc_dec) + (cast5_amd64_cfb_dec): New wrapper functions for bulk + assembly functions. + + Enable AMD64 Camellia implementations on WIN64. + + commit 9a4fb3709864bf3e3918800d44ff576590cd4e92 + * cipher/camellia-aesni-avx-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/camellia-aesni-avx2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/camellia-glue.c (USE_AESNI_AVX, USE_AESNI_AVX2): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_AESNI_AVX || USE_AESNI_AVX2] (ASM_FUNC_ABI, ASM_EXTRA_STACK): New. + (_gcry_camellia_aesni_avx_ctr_enc, _gcry_camellia_aesni_avx_cbc_dec) + (_gcry_camellia_aesni_avx_cfb_dec, _gcry_camellia_aesni_avx_keygen) + (_gcry_camellia_aesni_avx2_ctr_enc, _gcry_camellia_aesni_avx2_cbc_dec) + (_gcry_camellia_aesni_avx2_cfb_dec): Add ASM_FUNC_ABI. + + Enable AMD64 Blowfish implementation on WIN64. + + commit e05682093ffb003b589a697428d918d755ac631d + * cipher/blowfish-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/blowfish.c (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (call_sysv_fn): New. + (do_encrypt, do_encrypt_block, do_decrypt_block) + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS]: Call assembly + function through 'call_sysv_fn'. + (blowfish_amd64_ctr_enc, blowfish_amd64_cbc_dec) + (blowfish_amd64_cfb_dec): New wrapper functions for bulk + assembly functions. + .. + + Enable AMD64 arcfour implementation on WIN64. + + commit c46b015bedba7ce0db68929bd33a86a54ab3d919 + * cipher/arcfour-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/arcfour.c (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (do_encrypt, do_decrypt) [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS]: Use + assembly block to call AMD64 assembly function. + + Update documentation for Poly1305-ChaCha20 AEAD, RFC-7539. + + commit ee8fc4edcb3466b03246c8720b90731bf274ff1d + * cipher/cipher-poly1305.c: Add RFC-7539 to header. + * doc/gcrypt.texi: Update Poly1305 AEAD documentation with mention of + RFC-7539; Drop Salsa from supported stream ciphers for Poly1305 AEAD. + + hwf-x86: use edi for passing value to ebx for i386 cpuid. + + commit bac42c68b069f17abcca810a21439c7233815747 + * src/hwf-x86.c [__i386__] (get_cpuid): Use '=D' for regs[1] instead + of '=r'. + + hwf-x86: add EDX as output register for xgetbv asm block. + + commit e15beb584a5ebdfc363e1ff15f87102508652d71 + * src/hwf-x86.c (get_xgetbv): Add EDX as output. + +2015-05-04 Werner Koch + + build: Update build-aux files. + + commit 5a7d55eed3316f40ca61acbee032bfc285e28803 + + + Fix possible regression on old 32 bit mingw compilers. + + commit 090ca7435156b5f52064357dd59059570d466f46 + * acinclude.m4: Add new pattern for mingw32. + + build: Add new file. + + commit 4af52b2e72ce004b7d8f99e09c4324e3c2a84379 + * mpi/amd64/distfiles: Add func_abi.h. + +2015-05-03 Jussi Kivilinna + + Fix WIN64 assembly glue for AES. + + commit 24a769a7c7601dbb85332e550f6fbd121b56df5f + * cipher/rinjdael.c (do_encrypt, do_decrypt) + [!HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Change input operands to + input+output to mark volatile nature of the used registers. + + Add '1 million a characters' test vectors. + + commit 2f4fefdbc62857b6e2da26ce111ee140a068c471 + * tests/basic.c (check_digests): Add "!" test vectors for MD5, SHA-384, + SHA-512, RIPEMD160 and CRC32. + +2015-05-02 Jussi Kivilinna + + More optimized CRC implementations. + + commit 06e122baa3321483a47bbf82fd2a4540becfa0c9 + * cipher/crc.c (crc32_table, crc24_table): Replace with new table + contents. + (update_crc32, CRC24_INIT, CRC24_POLY): Remove. + (crc32_next, crc32_next4, crc24_init, crc24_next, crc24_next4) + (crc24_final): New. + (crc24rfc2440_init): Use crc24_init. + (crc32_write): Rewrite to use crc32_next & crc32_next4. + (crc24_write): Rewrite to use crc24_next & crc24_next4. + (crc32_final, crc32rfc1510_final): Use buf_put_be32. + (crc24rfc2440_final): Use crc24_final & buf_put_le32. + * tests/basic.c (check_digests): Add CRC "123456789" tests. + + Enable AMD64 AES implementation for WIN64. + + commit 66129b3334a5aa54ff8a97981507e4704f759571 + * cipher/rijndael-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/rijndael-internal.h (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (do_encrypt, do_decrypt) + [USE_AMD64_ASM && !HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Use + assembly block to call AMD64 assembly encrypt/decrypt function. + + Enable AMD64 Whirlpool implementation for WIN64. + + commit 8422d5d699265b960bd1ca837044ee052fc5b614 + * cipher/whirlpool-sse2-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/whirlpool.c (USE_AMD64_ASM): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_AMD64_ASM] (ASM_FUNC_ABI, ASM_EXTRA_STACK): New. + [USE_AMD64_ASM] (_gcry_whirlpool_transform_amd64): Add ASM_FUNC_ABI to + prototype. + [USE_AMD64_ASM] (whirlpool_transform): Add ASM_EXTRA_STACK to stack + burn value. + + Enable AMD64 SHA512 implementations for WIN64. + + commit 1089a13073c26a9a456e43ec38d937e6ee7f4077 + * cipher/sha512-avx-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/sha512-avx-bmi2-amd64.S: Ditto. + * cipher/sha512-ssse3-amd64.S: Ditto. + * cipher/sha512.c (USE_SSSE3, USE_AVX, USE_AVX2): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_SSSE3 || USE_AVX || USE_AVX2] (ASM_FUNC_ABI) + (ASM_EXTRA_STACK): New. + (_gcry_sha512_transform_amd64_ssse3, _gcry_sha512_transform_amd64_avx) + (_gcry_sha512_transform_amd64_avx_bmi2): Add ASM_FUNC_ABI to + prototypes. + (transform): Add ASM_EXTRA_STACK to stack burn value. + + Enable AMD64 SHA256 implementations for WIN64. + + commit 022959099644f64df5f2a83ade21159864f64837 + * cipher/sha256-avx-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/sha256-avx2-bmi2-amd64.S: Ditto. + * cipher/sha256-ssse3-amd64.S: Ditto. + * cipher/sha256.c (USE_SSSE3, USE_AVX, USE_AVX2): Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_SSSE3 || USE_AVX || USE_AVX2] (ASM_FUNC_ABI) + (ASM_EXTRA_STACK): New. + (_gcry_sha256_transform_amd64_ssse3, _gcry_sha256_transform_amd64_avx) + (_gcry_sha256_transform_amd64_avx2): Add ASM_FUNC_ABI to prototypes. + (transform): Add ASM_EXTRA_STACK to stack burn value. + + Enable AMD64 SHA1 implementations for WIN64. + + commit e433676a899fa0d274d40547166b03c7c8bd8e78 + * cipher/sha1-avx-amd64.S: Enable when + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + (ELF): New macro to mask lines with ELF specific commands. + * cipher/sha1-avx-bmi2-amd64.S: Ditto. + * cipher/sha1-ssse3-amd64.S: Ditto. + * cipher/sha1.c (USE_SSSE3, USE_AVX, USE_BMI2): Enable + when HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS defined. + [USE_SSSE3 || USE_AVX || USE_BMI2] (ASM_FUNC_ABI) + (ASM_EXTRA_STACK): New. + (_gcry_sha1_transform_amd64_ssse3, _gcry_sha1_transform_amd64_avx) + (_gcry_sha1_transform_amd64_avx_bmi2): Add ASM_FUNC_ABI to + prototypes. + (transform): Add ASM_EXTRA_STACK to stack burn value. + +2015-05-01 Jussi Kivilinna + + Enable AES/AES-NI, AES/SSSE3 and GCM/PCLMUL implementations on WIN64. + + commit 4e09aaa36d151c3312019724a77fc09aa345b82f + * cipher/cipher-gcm-intel-pclmul.c (_gcry_ghash_intel_pclmul) + ( _gcry_ghash_intel_pclmul) [__WIN64__]: Store non-volatile vector + registers before use and restore after. + * cipher/cipher-internal.h (GCM_USE_INTEL_PCLMUL): Remove dependency + on !defined(__WIN64__). + * cipher/rijndael-aesni.c [__WIN64__] (aesni_prepare_2_6_variable, + aesni_prepare, aesni_prepare_2_6, aesni_cleanup) + ( aesni_cleanup_2_6): New. + [!__WIN64__] (aesni_prepare_2_6_variable, aesni_prepare_2_6): New. + (_gcry_aes_aesni_do_setkey, _gcry_aes_aesni_cbc_enc) + (_gcry_aesni_ctr_enc, _gcry_aesni_cfb_dec, _gcry_aesni_cbc_dec) + (_gcry_aesni_ocb_crypt, _gcry_aesni_ocb_auth): Use + 'aesni_prepare_2_6'. + * cipher/rijndael-internal.h (USE_SSSE3): Enable if + HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS or + HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS. + (USE_AESNI): Remove dependency on !defined(__WIN64__) + * cipher/rijndael-ssse3-amd64.c [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] + (vpaes_ssse3_prepare, vpaes_ssse3_cleanup): New. + [!HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (vpaes_ssse3_prepare): New. + (vpaes_ssse3_prepare_enc, vpaes_ssse3_prepare_dec): Use + 'vpaes_ssse3_prepare'. + (_gcry_aes_ssse3_do_setkey, _gcry_aes_ssse3_prepare_decryption): Use + 'vpaes_ssse3_prepare' and 'vpaes_ssse3_cleanup'. + [HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS] (X): Add masking macro to + exclude '.type' and '.size' markers from assembly code, as they are + not support on WIN64/COFF objects. + * configure.ac (gcry_cv_gcc_attribute_ms_abi) + (gcry_cv_gcc_attribute_sysv_abi, gcry_cv_gcc_default_abi_is_ms_abi) + (gcry_cv_gcc_default_abi_is_sysv_abi) + (gcry_cv_gcc_win64_platform_as_ok): New checks. + + Add W64 support for mpi amd64 assembly. + + commit 460355f23e770637d29e3af7b998a957a2b5bc88 + acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Set + 'ac_cv_sys_symbol_underscore=no' on MingW-W64. + mpi/amd64/func_abi.h: New. + mpi/amd64/mpih-add1.S (_gcry_mpih_add_n): Add FUNC_ENTRY and FUNC_EXIT. + mpi/amd64/mpih-lshift.S (_gcry_mpih_lshift): Ditto. + mpi/amd64/mpih-mul1.S (_gcry_mpih_mul_1): Ditto. + mpi/amd64/mpih-mul2.S (_gcry_mpih_addmul_1): Ditto. + mpi/amd64/mpih-mul3.S (_gcry_mpih_submul_1): Ditto. + mpi/amd64/mpih-rshift.S (_gcry_mpih_rshift): Ditto. + mpi/amd64/mpih-sub1.S (_gcry_mpih_sub_n): Ditto. + mpi/config.links [host=x86_64-*mingw*]: Enable assembly modules. + [host=x86_64-*-*]: Append mpi/amd64/func_abi.h to mpi/asm-syntax.h. + + DES: Silence compiler warnings on Windows. + + commit 6c21cf5fed1ad430fa41445eac2350802bc8aaed + * cipher/des.c (working_memcmp): Make pointer arguments 'const void *'. + + Cast pointers to integers using uintptr_t instead of long. + + commit 9cf224322007d90193d4910f0da6e0e29ce01d70 + + + Fix rndhw for 64-bit Windows build. + + commit d5a7e00b6b222566a5650639ef29684b047c1909 + * configure.ac: Add sizeof check for 'void *'. + * random/rndhw.c (poll_padlock): Check for SIZEOF_VOID_P == 8 + instead of defined(__LP64__). + (RDRAND_LONG): Check for SIZEOF_UNSIGNED_LONG == 8 instead of + defined(__LP64__). + + Prepare random/win32.c fast poll for 64-bit Windows. + + commit 0cdd24456b33defc7f8176fa82ab694fbc284385 + * random/win32.c (_gcry_rndw32_gather_random_fast) [ADD]: Rename to + ADDINT. + (_gcry_rndw32_gather_random_fast): Add ADDPTR. + (_gcry_rndw32_gather_random_fast): Disable entropy gathering from + GetQueueStatus(QS_ALLEVENTS). + (_gcry_rndw32_gather_random_fast): Change minimumWorkingSetSize and + maximumWorkingSetSize to SIZE_T from DWORD. + (_gcry_rndw32_gather_random_fast): Only add lower 32-bits of + minimumWorkingSetSize and maximumWorkingSetSize to random poll. + (_gcry_rndw32_gather_random_fast) [__WIN64__]: Read TSC directly + using intrinsic. + + Disable GCM and AES-NI assembly implementations for WIN64. + + commit f701954555340a503f6e52cc18d58b0c515427b7 + * cipher/cipher-internal.h (GCM_USE_INTEL_PCLMUL): Do not enable when + __WIN64__ defined. + * cipher/rijndael-internal.h (USE_AESNI): Ditto. + + Disable building mpi assembly routines on WIN64. + + commit e78560a4b717f7154f910a8ce4128de152f586da + * mpi/config.links: Disable assembly for host 'x86_64-*mingw32*'. + + Fix packed attribute check for Windows targets. + + commit e886e4f5e73fe6a9f9191f5155852ce5d8bb88fe + * configure.ac (gcry_cv_gcc_attribute_packed): Move 'long b' to its + own packed structure. + + Fix tail handling in buf_xor_1. + + commit c2dba93e639639bdac139b3a3a456d10ddc61f79 + * cipher/bufhelp.h (buf_xor_1): Increment source pointer at tail + handling. + + Add --disable-hwf for basic tests. + + commit 839a3bbe2bb045139223b32753d656cc6c3d4669 + * tests/basic.c (main): Add handling for '--disable-hwf'. + + Use more odd chuck sizes for check_one_md. + + commit 9f086ffa43f2507b9d17522a0a2e394cb273baf8 + * tests/basic.c (check_one_md): Make chuck size vary oddly, instead + of using fixed length of 1000 bytes. + + Enable more modes in basic ciphers test. + + commit e40eff94f9f8654c3d29e03bbb7e5ee6a43c1435 + * src/gcrypt.h.in (GCRY_OCB_BLOCK_LEN): New. + * tests/basic.c (check_one_cipher_core_reset): New. + (check_one_cipher_core): Use check_one_cipher_core_reset inplace of + gcry_cipher_reset. + (check_ciphers): Add CCM and OCB modes for block cipher tests. + + Fix reseting cipher in OCB mode. + + commit 88842cbc68beb4f73c87fdbcb74182cba818f789 + * cipher/cipher.c (cipher_reset): Setup default taglen for OCB after + clearing state. + +2015-04-30 Jussi Kivilinna + + Fix buggy RC4 AMD64 assembly and add test to notice similar issues. + + commit 124dfce7c5a2d9405fa2b2832e91ac1267943830 + * cipher/arcfour-amd64.S (_gcry_arcfour_amd64): Fix swapped store of + 'x' and 'y'. + * tests/basic.c (get_algo_mode_blklen): New. + (check_one_cipher_core): Add new tests for split buffer input on + encryption and decryption. + +2015-04-26 Jussi Kivilinna + + Disallow compiler from generating SSE instructions in mixed C+asm source + + commit f88266c0f868d7bf51a215d5531bb9f2b4dad19e + * cipher/cipher-gcm-intel-pclmul.c [gcc-version >= 4.4]: Add GCC target + pragma to disable compiler use of SSE. + * cipher/rijndael-aesni.c [gcc-version >= 4.4]: Ditto. + * cipher/rijndael-ssse3-amd64.c [gcc-version >= 4.4]: Ditto. + +2015-04-18 Jussi Kivilinna + + Add OCB bulk crypt/auth functions for AES/AES-NI. + + commit 305cc878d395475c46b4ef52f4764bd0c85bf8ac + * cipher/cipher-internal.h (gcry_cipher_handle): Add bulk.ocb_crypt + and bulk.ocb_auth. + (_gcry_cipher_ocb_get_l): New prototype. + * cipher/cipher-ocb.c (get_l): Rename to ... + (_gcry_cipher_ocb_get_l): ... this. + (_gcry_cipher_ocb_authenticate, ocb_crypt): Use bulk function when + available. + * cipher/cipher.c (_gcry_cipher_open_internal): Setup OCB bulk + functions for AES. + * cipher/rijndael-aesni.c (get_l, aesni_ocb_enc, aes_ocb_dec) + (_gcry_aes_aesni_ocb_crypt, _gcry_aes_aesni_ocb_auth): New. + * cipher/rijndael.c [USE_AESNI] (_gcry_aes_aesni_ocb_crypt) + (_gcry_aes_aesni_ocb_auth): New prototypes. + (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth): New. + * src/cipher.h (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth): New + prototypes. + * tests/basic.c (check_ocb_cipher_largebuf): New. + (check_ocb_cipher): Add large buffer encryption/decryption test. + +2015-04-15 Werner Koch + + tests: Add option to time the S2K function. + + commit fe38d3815b4cd203cd529949e244aca80d32897f + * tests/t-kdf.c: Include stopwatch.h. + (dummy_consumer): new. + (bench_s2k): New. + (main): Add option parser and option --s2k. + + tests: Improve stopwatch.h. + + commit 3b03a3b493233a472da531d8d9582d1be6d376b0 + * tests/stopwatch.h (elapsed_time): Add arg divisor. + +2015-04-13 Werner Koch + + mpi: Fix gcry_mpi_copy for NULL opaque data. + + commit 9fca46864e1b5a9c788072113589454adb89fa97 + * mpi/mpiutil.c (_gcry_mpi_copy): Copy opaque only if needed. + +2015-03-21 Jussi Kivilinna + + wipememory: use one-byte aligned type for unaligned memory accesses. + + commit a06fbc0d1e98eb1218eff55ad2f37d471e4f33b2 + * src/g10lib.h (fast_wipememory2_unaligned_head): Enable unaligned + access only when HAVE_GCC_ATTRIBUTE_PACKED and + HAVE_GCC_ATTRIBUTE_ALIGNED defined. + (fast_wipememory_t): New. + (fast_wipememory2): Use 'fast_wipememory_t'. + + bufhelp: use one-byte aligned type for unaligned memory accesses. + + commit 92fa5f16d69707e302c0f85b2e5e80af8dc037f1 + * cipher/bufhelp.h (BUFHELP_FAST_UNALIGNED_ACCESS): Enable only when + HAVE_GCC_ATTRIBUTE_PACKED and HAVE_GCC_ATTRIBUTE_ALIGNED are defined. + (bufhelp_int_t): New type. + (buf_cpy, buf_xor, buf_xor_1, buf_xor_2dst, buf_xor_n_copy_2): Use + 'bufhelp_int_t'. + [BUFHELP_FAST_UNALIGNED_ACCESS] (bufhelp_u32_t, bufhelp_u64_t): New. + [BUFHELP_FAST_UNALIGNED_ACCESS] (buf_get_be32, buf_get_le32) + (buf_put_be32, buf_put_le32, buf_get_be64, buf_get_le64) + (buf_put_be64, buf_put_le64): Use 'bufhelp_uXX_t'. + * configure.ac (gcry_cv_gcc_attribute_packed): New. + + tests/bench-slope: fix memory-leak and use-after-free bugs. + + commit aa234561d00c3fb15fe501df4bf58f3db7c7c06b + * tests/bench-slope.c (do_slope_benchmark): Free 'measurements' at end. + (bench_mac_init): Move 'key' free at end of function. + +2015-03-19 Werner Koch + + Fix two pedantic warnings. + + commit f5832285b0e420d77be1b8da10a1e1d86583b414 + * src/gcrypt.h.in (gcry_mpi_flag, gcry_mac_algos): Remove trailing + comma. + +2015-03-16 Werner Koch + + Use well defined type instead of size_t in secmem.c. + + commit db8ae3616987fa288173446398a107e31e2e28aa + * src/secmem.c (ptr_into_pool_p): Replace size_t by uintptr_t. + + Make uintptr_t global available. + + commit f0f60c1a04d664936bcf52e8f46705bdc63e7ad9 + * cipher/bufhelp.h: Move include for uintptr_t to ... + * src/types.h: here. Check that config.h has been included. + + mpi: Remove useless condition. + + commit 0a9cdb8ae092d050ca12a7a4f2f50e25b82154ec + * mpi/mpi-pow.c: Remove condition rp==mp. + + cipher: Remove useless NULL check. + + commit fbb97dcf763e28e81e01092ad4c934b3eaf88cc8 + * cipher/hash-common.c (_gcry_md_block_write): Remove NUL check for + hd->buf. + +2015-02-28 Jussi Kivilinna + + Fix in-place encryption for OCB mode. + + commit 5e66a4f8d5a63f58caeee367433dd8dd32346083 + * cipher/cipher-ocb.c (ocb_checksum): New. + (ocb_crypt): Move checksum calculation outside main crypt loop, do + checksum calculation for encryption before inbuf is overwritten. + * tests/basic.c (check_ocb_cipher): Rename to ... + (do_check_ocb_cipher): ... to this and add argument for testing + in-place encryption/decryption. + (check_ocb_cipher): New. + +2015-02-27 NIIBE Yutaka + + tests: fix t-sexp.c. + + commit 505decf5369970219ddc9e78a20f97c623957b78 + * tests/t-sexp.c (bug_1594): Free N and PUBKEY. + + mpi: Avoid data-dependent timing variations in mpi_powm. + + commit 6636c4fd0c6ceab9f79827bf96967d1e112c0b82 + * mpi/mpi-pow.c (mpi_powm): Access all data in the table by + mpi_set_cond. + + mpi: Revise mpi_powm. + + commit 1fa8cdb933505960d4e4b4842b122d4e06953e88 + * mpi/mpi-pow.c (_gcry_mpi_powm): Rename the table to PRECOMP. + +2015-02-23 Werner Koch + + cipher: Use ciphertext blinding for Elgamal decryption. + + commit 410d70bad9a650e3837055e36f157894ae49a57d + * cipher/elgamal.c (USE_BLINDING): New. + (decrypt): Rewrite to use ciphertext blinding. + +2015-02-12 NIIBE Yutaka + + mpi: Add mpi_set_cond. + + commit 653a9fa1a3a4c35a4dc1841cb57d7e2a318f3288 + * mpi/mpiutil.c (_gcry_mpi_set_cond): New. + (_gcry_mpi_swap_cond): Fix types. + * src/mpi.h (mpi_set_cond): New. + +2015-01-30 Werner Koch + + w32: Use -static-libgcc to avoid linking to libgcc_s_sjlj-1.dll. + + commit 40a7bdf50e19faaf106470897fed72af623adc50 + * src/Makefile.am (extra_ltoptions): New. + (libgcrypt_la_LDFLAGS): Use it. + +2015-01-28 Werner Koch + + Fix building of GOST s-boxes when cross-compiling. + + commit 2564d204e408b296425ac0660c6bdc6270575fb6 + * cipher/Makefile.am (gost-s-box): USe CC_FOR_BUILD. + (noinst_PROGRAMS): Remove. + (EXTRA_DIST): New. + (CLEANFILES): New. + +2015-01-20 Jussi Kivilinna + + rijndael: fix wrong ifdef for SSSE3 setkey. + + commit ceaa97f0d849c07f3a15b642fc3a2b0a477b4a47 + * cipher/rijndael.c (do_setkey): Use USE_SSSE3 instead of USE_AESNI + around SSSE3 setkey selection. + +2015-01-16 Werner Koch + + Add OCB cipher mode. + + commit 067d7d8752d4d8a98f8e0e5e9b1a5b13e1b7ff9c + * cipher/cipher-ocb.c: New. + * cipher/Makefile.am (libcipher_la_SOURCES): Add cipher-ocb.c + * cipher/cipher-internal.h (OCB_BLOCK_LEN, OCB_L_TABLE_SIZE): New. + (gcry_cipher_handle): Add fields marks.finalize and u_mode.ocb. + * cipher/cipher.c (_gcry_cipher_open_internal): Add OCB mode. + (_gcry_cipher_open_internal): Setup default taglen of OCB. + (cipher_reset): Clear OCB specific data. + (cipher_encrypt, cipher_decrypt, _gcry_cipher_authenticate) + (_gcry_cipher_gettag, _gcry_cipher_checktag): Call OCB functions. + (_gcry_cipher_setiv): Add OCB specific nonce setting. + (_gcry_cipher_ctl): Add GCRYCTL_FINALIZE and GCRYCTL_SET_TAGLEN + + * src/gcrypt.h.in (GCRYCTL_SET_TAGLEN): New. + (gcry_cipher_final): New. + + * cipher/bufhelp.h (buf_xor_1): New. + + * tests/basic.c (hex2buffer): New. + (check_ocb_cipher): New. + (main): Call it here. Add option --cipher-modes. + * tests/bench-slope.c (bench_aead_encrypt_do_bench): Call + gcry_cipher_final. + (bench_aead_decrypt_do_bench): Ditto. + (bench_aead_authenticate_do_bench): Ditto. Check error code. + (bench_ocb_encrypt_do_bench): New. + (bench_ocb_decrypt_do_bench): New. + (bench_ocb_authenticate_do_bench): New. + (ocb_encrypt_ops): New. + (ocb_decrypt_ops): New. + (ocb_authenticate_ops): New. + (cipher_modes): Add them. + (cipher_bench_one): Skip wrong block length for OCB. + * tests/benchmark.c (cipher_bench): Add field noncelen to MODES. Add + OCB support. + +2015-01-15 Werner Koch + + Add functions to count trailing zero bits in a word. + + commit 9d2a22c94ae99f9301321082c4fb8d73f4085fda + * cipher/bithelp.h (_gcry_ctz, _gcry_ctz64): New. + * configure.ac (HAVE_BUILTIN_CTZ): Add new test. + +2015-01-08 Werner Koch + + cipher: Prepare for OCB mode. + + commit 9d328962660da72f094dc5424d5ef67abbaffdf6 + * src/gcrypt.h.in (GCRY_CIPHER_MODE_OCB): New. + +2015-01-06 Werner Koch + + Make make distcheck work again. + + commit 4f7dcdc25af269b12275126edeef30b262fb891d + * Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Remove --enable-ciphers. + * cipher/Makefile.am (DISTCLEANFILES): Add gost-sb.h. + +2015-01-06 Dmitry Eremin-Solenikov + + stribog: Reduce table size to the needed one. + + commit e4de52378a85cf383994ded8edf0d5cf98dcb10c + * cipher/stribog.c (C16): Avoid allocating superfluous space. + + gostr3411-94: Fix the iteration count for length filling loop. + + commit 05dc5bcd234909ae9c9366b653346076b9a834ed + * cipher/gostr3411-94.c (gost3411_final): Fix loop + +2015-01-05 Werner Koch + + random: Silent warning under NetBSD using rndunix. + + commit 817472358a093438e802380caecf7139406400cf + * random/rndunix.c (STDERR_FILENO): Define if needed. + (start_gatherer): Re-open standard descriptors. Fix an + unsigned/signed pointer warning. + + primegen: Fix memory leak for invalid call sequences. + + commit 8c5eee51d9a25b143e41ffb7ff4a6b2a29b82d83 + * cipher/primegen.c (prime_generate_internal): Refactor generator code + to not leak memory for non-implemented feature. + (_gcry_prime_group_generator): Refactor to not leak memory for invalid + args. Also make sure that R_G is set as soon as possible. + + doc: Update yat2m to current upstream version (GnuPG). + + commit dd5df198727ea5d8f6b04288e14fd732051453c8 + + + build: Require automake 1.14. + + commit f65276970a6dcd6d9bca94cecc49b68acdcc9492 + * configure.ac (AM_INIT_AUTOMAKE): Add serial-tests. + + Replace camel case of internal scrypt functions. + + commit 1a6d65ac0aab335541726d02f2046d883a768ec3 + * cipher/scrypt.c (_salsa20_core): Rename to salsa20_core. Change + callers. + (_scryptBlockMix): Rename to scrypt_block_mix. Change callers. + (_scryptROMix): Rename to scrypt_ro_mix. Change callers. + +2015-01-02 Jussi Kivilinna + + rmd160: restore native-endian store in _gcry_rmd160_mixblock. + + commit d7c7453cf5e6b8f3c6b522a30e680f844a28c9de + * cipher/rmd160.c (_gcry_rmd160_mixblock): Store result to buffer in + native-endianess. + +2014-12-27 Jussi Kivilinna + + Add Intel SSSE3 based vector permutation AES implementation. + + commit 8eabecc883332156adffc1df42d27f614c157e06 + * cipher/Makefile.am: Add 'rijndael-ssse3-amd64.c'. + * cipher/rijndael-internal.h (USE_SSSE3): New. + (RIJNDAEL_context_s) [USE_SSSE3]: Add 'use_ssse3'. + * cipher/rijndael-ssse3-amd64.c: New. + * cipher/rijndael.c [USE_SSSE3] (_gcry_aes_ssse3_do_setkey) + (_gcry_aes_ssse3_prepare_decryption, _gcry_aes_ssse3_encrypt) + (_gcry_aes_ssse3_decrypt, _gcry_aes_ssse3_cfb_enc) + (_gcry_aes_ssse3_cbc_enc, _gcry_aes_ssse3_ctr_enc) + (_gcry_aes_ssse3_cfb_dec, _gcry_aes_ssse3_cbc_dec): New. + (do_setkey): Add HWF check for SSSE3 and setup for SSSE3 + implementation. + (prepare_decryption, _gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (_gcry_aes_ctr_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_dec): Add + selection for SSSE3 implementation. + * configure.ac [host=x86_64]: Add 'rijndael-ssse3-amd64.lo'. + +2014-12-25 Jussi Kivilinna + + random-csprng: fix compiler warnings on ARM. + + commit c2e1f8fea271f3ef8027809547c4a52e0b1e24a2 + * random/random-csprng.c (_gcry_rngcsprng_update_seed_file) + (read_pool): Cast keypool and rndpool to 'unsigned long *' through + 'void *'. + + scrypt: fix compiler warnings on ARM. + + commit 1dab4c9422bf0f3cdc7a4d3ccf9db090abd90e94 + * cipher/scrypt.c (_scryptBlockMix): Cast X to 'u32 *' through 'void *'. + + secmem: fix compiler warnings on ARM. + + commit 99faf9cb34f872144313403f29f3379798debfc9 + * src/secmem.c (ADDR_TO_BLOCK, mb_get_next, mb_get_new): Cast pointer + from 'char *' to 'memblock_t *' through 'void *'. + (MB_WIPE_OUT): Remove unneeded cast to 'memblock_t *'. + + hash: fix compiler warning on ARM. + + commit 4515315f61fbf79413e150fbd1d5f5a2435f2bc5 + * cipher/md.c (md_open, md_copy): Cast 'char *' to ctx through + 'void *'. + * cipher/md4.c (md4_final): Use buf_put_* helper instead of + converting 'char *' to 'u32 *'. + * cipher/md5.c (md5_final): Ditto. + * cipher/rmd160.c (_gcry_rmd160_mixblock, rmd160_final): Ditto. + * cipher/sha1.c (sha1_final): Ditto. + * cipher/sha256.c (sha256_final): Ditto. + * cipher/sha512.c (sha512_final): Ditto. + * cipher/tiger.c (tiger_final): Ditto. + + rijndael: fix compiler warnings on ARM. + + commit cc26106dbebeb84d481661813edc3e5aea9a7d99 + * cipher/rijndael-internal.h (RIJNDAEL_context_s): Add u32 variants of + keyschedule arrays to unions u1 and u2. + (keyschedenc32, keyscheddec32): New. + * cipher/rijndael.c (u32_a_t): Remove. + (do_setkey): Add and use tkk[].data32, k_u32, tk_u32 and W_u32; Remove + casting byte arrays to u32_a_t. + (prepare_decryption, do_encrypt_fn, do_decrypt_fn): Use keyschedenc32 + and keyscheddec32; Remove casting byte arrays to u32_a_t. + +2014-12-23 Jussi Kivilinna + + Poly1305-AEAD: updated implementation to match draft-irtf-cfrg-chacha20-poly1305-03 + + commit 520070e02e2e6ee7228945015573a6e1f4895ec3 + * cipher/cipher-internal.h (gcry_cipher_handle): Use separate byte + counters for AAD and data in Poly1305. + * cipher/cipher-poly1305.c (poly1305_fill_bytecount): Remove. + (poly1305_fill_bytecounts, poly1305_do_padding): New. + (poly1305_aad_finish): Fill padding to Poly1305 and do not fill AAD + length. + (_gcry_cipher_poly1305_authenticate, _gcry_cipher_poly1305_encrypt) + (_gcry_cipher_poly1305_decrypt): Update AAD and data length separately. + (_gcry_cipher_poly1305_tag): Fill padding and bytecounts to Poly1305. + (_gcry_cipher_poly1305_setkey, _gcry_cipher_poly1305_setiv): Reset + AAD and data byte counts; only allow 96-bit IV. + * cipher/cipher.c (_gcry_cipher_open_internal): Limit Poly1305-AEAD to + ChaCha20 cipher. + * tests/basic.c (_check_poly1305_cipher): Update test-vectors. + (check_ciphers): Limit Poly1305-AEAD checks to ChaCha20. + * tests/bench-slope.c (cipher_bench_one): Ditto. + + chacha20: allow setting counter for stream random access. + + commit 11b8d2d449a7bc664b4371ae14c57caa6704d272 + * cipher/chacha20.c (CHACHA20_CTR_SIZE): New. + (chacha20_ivsetup): Add setup for full counter. + (chacha20_setiv): Allow ivlen == CHACHA20_CTR_SIZE. + + gcm: do not pass extra key pointer for setupM/fillM. + + commit c964321c8a1328e89d636d899a45d68802f5ac9f + * cipher/cipher-gcm-intel-pclmul.c + (_gcry_ghash_setup_intel_pclmul): Remove 'h' parameter. + * cipher/cipher-gcm.c (_gcry_ghash_setup_intel_pclmul): Ditto. + (fillM): Get 'h' pointer from 'c'. + (setupM): Remome 'h' parameter. + (_gcry_cipher_gcm_setkey): Only pass 'c' to setupM. + + rijndael: use more compact look-up tables and add table prefetching. + + commit 2374753938df64f6fd8015b44613806a326eff1a + * cipher/rijndael-internal.h (rijndael_prefetchfn_t): New. + (RIJNDAEL_context): Add 'prefetch_enc_fn' and 'prefetch_dec_fn'. + * cipher/rijndael-tables.h (S, T1, T2, T3, T4, T5, T6, T7, T8, S5, U1) + (U2, U3, U4): Remove. + (encT, dec_tables, decT, inv_sbox): Add. + * cipher/rijndael.c (_gcry_aes_amd64_encrypt_block) + (_gcry_aes_amd64_decrypt_block, _gcry_aes_arm_encrypt_block) + (_gcry_aes_arm_encrypt_block): Add parameter for passing table pointer + to assembly implementation. + (prefetch_table, prefetch_enc, prefetch_dec): New. + (do_setkey): Setup context prefetch functions depending on selected + rijndael implementation; Use new tables for key setup. + (prepare_decryption): Use new tables for decryption key setup. + (do_encrypt_aligned): Rename to... + (do_encrypt_fn): ... to this, change to use new compact tables, + make handle unaligned input and unroll rounds loop by two. + (do_encrypt): Remove handling of unaligned input/output; pass table + pointer to assembly implementations. + (rijndael_encrypt, _gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (_gcry_aes_ctr_enc, _gcry_aes_cfb_dec): Prefetch encryption tables + before encryption. + (do_decrypt_aligned): Rename to... + (do_decrypt_fn): ... to this, change to use new compact tables, + make handle unaligned input and unroll rounds loop by two. + (do_decrypt): Remove handling of unaligned input/output; pass table + pointer to assembly implementations. + (rijndael_decrypt, _gcry_aes_cbc_dec): Prefetch decryption tables + before decryption. + * cipher/rijndael-amd64.S: Use 1+1.25 KiB tables for + encryption+decryption; remove tables from assembly file. + * cipher/rijndael-arm.S: Ditto. + +2014-12-15 Werner Koch + + build: Add configure option --disable-doc. + + commit ad50e360ef4851e66e51a03fc420175636336b58 + * Makefile.am (AUTOMAKE_OPTIONS): Remove. + (doc) [!BUILD_DOC]: Do not recurse into the dir. + * configure.ac (AM_INIT_AUTOMAKE): Add option formerly in Makefile.am. + (BUILD_DOC): Add new am_conditional. + +2014-12-12 Jussi Kivilinna + + rijndael: further optimizations for AES-NI accelerated CBC and CFB bulk modes + + commit 4f46374502eb988d701b904f83819e2cf7b1755c + * cipher/rijndael-aesni.c (do_aesni_enc, do_aesni_dec): Pass + input/output through SSE register XMM0. + (do_aesni_cfb): Remove. + (_gcry_aes_aesni_encrypt, _gcry_aes_aesni_decrypt): Add loading/storing + input/output to/from XMM0. + (_gcry_aes_aesni_cfb_enc, _gcry_aes_aesni_cbc_enc) + (_gcry_aes_aesni_cfb_dec): Update to use renewed 'do_aesni_enc' and + move IV loading/storing outside loop. + (_gcry_aes_aesni_cbc_dec): Update to use renewed 'do_aesni_dec'. + + GCM: move Intel PCLMUL accelerated implementation to separate file. + + commit 4a0795af021305f9240f23626a3796157db46bd7 + * cipher/Makefile.am: Add 'cipher-gcm-intel-pclmul.c'. + * cipher/cipher-gcm-intel-pclmul.c: New. + * cipher/cipher-gcm.c [GCM_USE_INTEL_PCLMUL] + (_gcry_ghash_setup_intel_pclmul, _gcry_ghash_intel_pclmul): New + prototypes. + [GCM_USE_INTEL_PCLMUL] (gfmul_pclmul, gfmul_pclmul_aggr4): Move + to 'cipher-gcm-intel-pclmul.c'. + (ghash): Rename to... + (ghash_internal): ...this and move GCM_USE_INTEL_PCLMUL part to new + function in 'cipher-gcm-intel-pclmul.c'. + (setupM): Move GCM_USE_INTEL_PCLMUL part to new function in + 'cipher-gcm-intel-pclmul.c'; Add selection of ghash function based + on available HW acceleration. + (do_ghash_buf): Change use of 'ghash' to 'c->u_mode.gcm.ghash_fn'. + * cipher/internal.h (ghash_fn_t): New. + (gcry_cipher_handle): Remove 'use_intel_pclmul'; Add 'ghash_fn'. + +2014-12-06 Jussi Kivilinna + + rijndael: split Padlock part to separate file. + + commit cbf4c8cb6bbda15eea61885279f2a6f1d4bcedfd + * cipher/Makefile.am: Add 'rijndael-padlock.c'. + * cipher/rijndael-padlock.c: New. + * cipher/rijndael.c (do_padlock, do_padlock_encrypt) + (do_padlock_decrypt): Move to 'rijndael-padlock.c'. + * configure.ac [mpi_cpu_arch=x86]: Add 'rijndael-padlock.lo'. + +2014-12-01 Jussi Kivilinna + + rijndael: refactor to reduce number of #ifdefs and branches. + + commit 3d5b51786e2050c461e9791b59142a731462b66d + * cipher/rijndael-aesni.c (_gcry_aes_aesni_encrypt) + (_gcry_aes_aesni_decrypt): Make return stack burn depth. + * cipher/rijndael-amd64.S (_gcry_aes_amd64_encrypt_block) + (_gcry_aes_amd64_decrypt_block): Ditto. + * cipher/rijndael-arm.S (_gcry_aes_arm_encrypt_block) + (_gcry_aes_arm_decrypt_block): Ditto. + * cipher/rijndael-internal.h (RIJNDAEL_context_s) + (rijndael_cryptfn_t): New. + (RIJNDAEL_context): New members 'encrypt_fn' and 'decrypt_fn'. + * cipher/rijndael.c (_gcry_aes_amd64_encrypt_block) + (_gcry_aes_amd64_decrypt_block, _gcry_aes_aesni_encrypt) + (_gcry_aes_aesni_decrypt, _gcry_aes_arm_encrypt_block) + (_gcry_aes_arm_decrypt_block): Change prototypes. + (do_padlock_encrypt, do_padlock_decrypt): New. + (do_setkey): Separate key-length to rounds conversion from + HW features check; Add selection for ctx->encrypt_fn and + ctx->decrypt_fn. + (do_encrypt_aligned, do_decrypt_aligned): Move inside + '[!USE_AMD64_ASM && !USE_ARM_ASM]'; Move USE_AMD64_ASM and + USE_ARM_ASM to... + (do_encrypt, do_decrypt): ...here; Return stack depth; Remove second + temporary buffer from non-aligned input/output case. + (do_padlock): Move decrypt_flag to last argument; Return stack depth. + (rijndael_encrypt): Remove #ifdefs, just call ctx->encrypt_fn. + (_gcry_aes_cfb_enc, _gcry_aes_cbc_enc): Remove USE_PADLOCK; Call + ctx->encrypt_fn in place of do_encrypt/do_encrypt_aligned. + (_gcry_aes_ctr_enc): Call ctx->encrypt_fn in place of + do_encrypt_aligned; Make tmp buffer 16-byte aligned and wipe buffer + after use. + (rijndael_encrypt): Remove #ifdefs, just call ctx->decrypt_fn. + (_gcry_aes_cfb_dec): Remove USE_PADLOCK; Call ctx->decrypt_fn in place + of do_decrypt/do_decrypt_aligned. + (_gcry_aes_cbc_dec): Ditto; Make savebuf buffer 16-byte aligned. + + rijndael: move AES-NI blocks before Padlock. + + commit dbf9e95dd3891f6e6ad370e8ab78fec03595687b + * cipher/rijndael.c (do_setkey, rijndael_encrypt, _gcry_aes_cfb_enc) + (rijndael_decrypt, _gcry_aes_cfb_dec): Move USE_AESNI before + USE_PADLOCK. + (check_decryption_praparation) [USE_PADLOCK]: Move to... + (prepare_decryption) [USE_PADLOCK]: ...here. + + rijndael: split AES-NI functions to separate file. + + commit 67d529630e838daeb8cb9c6d7ef660c01ef34fee + * cipher/Makefile.in: Add 'rijndael-aesni.c'. + * cipher/rijndael-aesni.c: New. + * cipher/rijndael-internal.h: New. + * cipher/rijndael.c (MAXKC, MAXROUNDS, BLOCKSIZE, ATTR_ALIGNED_16) + (USE_AMD64_ASM, USE_ARM_ASM, USE_PADLOCK, USE_AESNI, RIJNDAEL_context) + (keyschenc, keyschdec, padlockkey): Move to 'rijndael-internal.h'. + (u128_s, aesni_prepare, aesni_cleanup, aesni_cleanup_2_6) + (aesni_do_setkey, do_aesni_enc, do_aesni_dec, do_aesni_enc_vec4) + (do_aesni_dec_vec4, do_aesni_cfb, do_aesni_ctr, do_aesni_ctr_4): Move + to 'rijndael-aesni.c'. + (prepare_decryption, rijndael_encrypt, _gcry_aes_cfb_enc) + (_gcry_aes_cbc_enc, _gcry_aes_ctr_enc, rijndael_decrypt) + (_gcry_aes_cfb_dec, _gcry_aes_cbc_dec) [USE_AESNI]: Move to functions + in 'rijdael-aesni.c'. + * configure.ac [mpi_cpu_arch=x86]: Add 'rijndael-aesni.lo'. + +2014-11-24 Werner Koch + + Remove duplicated prototypes. + + commit d53ea84bed37b973f7ce59262c50b33700cd8311 + * src/gcrypt-int.h (_gcry_mpi_ec_new, _gcry_mpi_ec_set_mpi) + (gcry_mpi_ec_set_point): Remove. + + tests: Add a prime mode to benchmark. + + commit 1b4210c204a5ef5e631187509e011b8468a134ef + * tests/benchmark.c (progress_cb): Add a single char mode. + (prime_bench): New. + (main): Add a "prime" mode. Factor with_progress out to file scope. + +2014-11-19 NIIBE Yutaka + + ecc: Improve Montgomery curve implementation. + + commit e6130034506013d6153465a2bedb6fb08a43f74d + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Support + MPI_EC_MONTGOMERY. + * cipher/ecc.c (test_ecdh_only_keys): New. + (nist_generate_key): Call test_ecdh_only_keys for MPI_EC_MONTGOMERY. + (check_secret_key): Handle Montgomery curve of x-coordinate only. + * mpi/ec.c (_gcry_mpi_ec_mul_point): Resize points before the loop. + Simplify, using pointers of Q1, Q2, PRD, and SUM. + +2014-11-02 Jussi Kivilinna + + Disable NEON for CPUs that are known to have broken NEON implementation. + + commit 95eef21583d8e998efc48f22898c1ae31b77cb48 + * src/hwf-arm.c (detect_arm_proc_cpuinfo): Add parsing for CPU version + information and check if CPU is known to have broken NEON + implementation. + (_gcry_hwf_detect_arm): Filter out broken HW features. + + Add ARM/NEON implementation of Poly1305. + + commit 0b520128551054d83fb0bb2db8873394f38de498 + * cipher/Makefile.am: Add 'poly1305-armv7-neon.S'. + * cipher/poly1305-armv7-neon.S: New. + * cipher/poly1305-internal.h (POLY1305_USE_NEON) + (POLY1305_NEON_BLOCKSIZE, POLY1305_NEON_STATESIZE) + (POLY1305_NEON_ALIGNMENT): New. + * cipher/poly1305.c [POLY1305_USE_NEON] + (_gcry_poly1305_armv7_neon_init_ext) + (_gcry_poly1305_armv7_neon_finish_ext) + (_gcry_poly1305_armv7_neon_blocks, poly1305_armv7_neon_ops): New. + (_gcry_poly1305_init) [POLY1305_USE_NEON]: Select NEON implementation + if HWF_ARM_NEON set. + * configure.ac [neonsupport=yes]: Add 'poly1305-armv7-neon.lo'. + + chacha20: add ARMv7/NEON implementation. + + commit c584f44543883346d5a565581ff99a0afce9c5e1 + * cipher/Makefile.am: Add 'chacha20-armv7-neon.S'. + * cipher/chacha20-armv7-neon.S: New. + * cipher/chacha20.c (USE_NEON): New. + [USE_NEON] (_gcry_chacha20_armv7_neon_blocks): New. + (chacha20_do_setkey) [USE_NEON]: Use Neon implementation if + HWF_ARM_NEON flag set. + (selftest): Self-test encrypting buffer byte by byte. + * configure.ac [neonsupport=yes]: Add 'chacha20-armv7-neon.lo'. + +2014-10-08 Markus Teich + + mpi: Add gcry_mpi_ec_sub. + + commit 23ecadf309f8056c35cc092e58df801ac0eab862 + * NEWS (gcry_mpi_ec_sub): New. + * doc/gcrypt.texi (gcry_mpi_ec_sub): New. + * mpi/ec.c (_gcry_mpi_ec_sub, sub_points_edwards): New. + (sub_points_montgomery, sub_points_weierstrass): New stubs. + * src/gcrypt-int.h (_gcry_mpi_ec_sub): New. + * src/gcrypt.h.in (gcry_mpi_ec_sub): New. + * src/libgcrypt.def (gcry_mpi_ec_sub): New. + * src/libgcrypt.vers (gcry_mpi_ec_sub): New. + * src/mpi.h (_gcry_mpi_ec_sub_points): New. + * src/visibility.c (gcry_mpi_ec_sub): New. + * src/visibility.h (gcry_mpi_ec_sub): New. + +2014-10-08 Werner Koch + + Fix prime test for 2 and lower and add check command to mpicalc. + + commit 5c906e2cdb14e93fb4915fdc69c7353a5fa35709 + * cipher/primegen.c (check_prime): Return true for the small primes. + (_gcry_prime_check): Return correct values for 2 and lower numbers. + + * src/mpicalc.c (do_primecheck): New. + (main): Add command 'P'. + (main): Allow for larger input data. + +2014-10-04 Jussi Kivilinna + + Add Whirlpool AMD64/SSE2 assembly implementation. + + commit de0ccd4dce7ec185a678d78878d4538dd609ca0f + * cipher/Makefile.am: Add 'whirlpool-sse2-amd64.S'. + * cipher/whirlpool-sse2-amd64.S: New. + * cipher/whirlpool.c (USE_AMD64_ASM): New. + (whirlpool_tables_s): New. + (rc, C0, C1, C2, C3, C4, C5, C6, C7): Combine these tables into single + structure and replace old tables with macros of same name. + (tab): New structure containing above tables. + [USE_AMD64_ASM] (_gcry_whirlpool_transform_amd64) + (whirlpool_transform): New. + * configure.ac [host=x86_64]: Add 'whirlpool-sse2-amd64.lo'. + +2014-10-04 Andrei Scherer + + Improved ripemd160 performance. + + commit 30bd759f398f45b04d0a783b875f59ce9bd1e51d + * cipher/rmd160.c (transform): Interleave the left and right lane + rounds to introduce more instruction level parallelism. + +2014-10-02 Werner Koch + + build: Document SYSROOT. + + commit 0ecd136a6ca02252f63ad229fa5240897bfe6544 + * configure.ac: Mark SYSROOT as arg var. + + build: Support SYSROOT based config script finding. + + commit 1e8b86494cf8fa045696bd447b16267ffd1797f0 + * src/libgcrypt.m4: Add support for SYSROOT and set + gpg_config_script_warn. Use AC_PATH_PROG instead of AC_PATH_TOOL + because the config script is not expected to be installed with a + prefix for its name + * configure.ac: Print a library mismatch warning. + * m4/gpg-error.m4: Update from git master. + +2014-09-30 Werner Koch + + mac: Fix gcry_mac_close to allow for a NULL handle. + + commit 51dae8c8c4b63bb5e1685cbd8722e35342524737 + * cipher/mac.c (_gcry_mac_close): Check for NULL. + +2014-09-03 Werner Koch + + Add a constant for a forthcoming new RNG. + + commit 8b960a807d168000d2690897a7634bd384ac1346 + * src/gcrypt.h.in (GCRYCTL_DRBG_REINIT): New constant. + +2014-09-02 Jussi Kivilinna + + Add new Poly1305 MAC test vectors. + + commit 8a2a328742012a7c528dd007437185e4584c1e48 + * tests/basic.c (check_mac): Add new test vectors for Poly1305 MAC. + +2014-09-02 Werner Koch + + asm: Allow building x86 and amd64 using old compilers. + + commit 5eec04a43e6c562e956353449be931dd43dfe1cc + * src/hwf-x86.c (get_xgetbv): Build only if AVX support is enabled. + +2014-08-21 Werner Koch + + sexp: Check args of gcry_sexp_build. + + commit e606d5f1bada1f2d21faeedd3fa2cf2dca7b274c + * src/sexp.c (do_vsexp_sscan): Return error for invalid args. + + cipher: Fix a segv in case of calling with wrong parameters. + + commit f850add813d783f31ca6a60459dea25ef71bce7e + * cipher/md.c (_gcry_md_info): Fix arg testing. + + cipher: Fix possible NULL deref in call to prime generator. + + commit 18056ace7f466cb8c1eaf08e5dc0400516d83b4c + * cipher/primegen.c (_gcry_generate_elg_prime): Change to return an + error code. + * cipher/dsa.c (generate): Take care of new return code. + * cipher/elgamal.c (generate): Change to return an error code. Take + care of _gcry_generate_elg_prime return code. + (generate_using_x): Take care of _gcry_generate_elg_prime return code. + (elg_generate): Propagate return code from generate. + +2014-08-12 NIIBE Yutaka + + ecc: Support Montgomery curve for gcry_mpi_ec_mul_point. + + commit 34bb55ee36df3aca3ebca88f8b61c786cd0c0701 + * mpi/ec.c (_gcry_mpi_ec_get_affine): Support Montgomery curve. + (montgomery_ladder): New. + (_gcry_mpi_ec_mul_point): Implemention using montgomery_ladder. + (_gcry_mpi_ec_curve_point): Check x-coordinate is valid. + +2014-08-09 Werner Koch + + tests: Add a benchmark for Elgamal. + + commit e6d354865bf8f3d4c1bb5e8157a76fdd442cff41 + * tests/benchmark.c (sample_public_elg_key_1024): New. + (sample_private_elg_key_1024): New. + (sample_public_elg_key_2048, sample_private_elg_key_2048): New. + (sample_public_elg_key_3072, sample_private_elg_key_3072): New. + (elg_bench): New. + (main): Add elg_bench. Add commands "elg" and "public". + +2014-08-08 NIIBE Yutaka + + ecc: Add cofactor to domain parameters. + + commit 9933b9e5e1a3f5b1019c75f93bd265d4a1ecc270 + * src/ec-context.h (mpi_ec_ctx_s): Add cofactor 'h'. + * cipher/ecc-common.h (elliptic_curve_t): Add cofactor 'h'. + (_gcry_ecc_update_curve_param): New API adding cofactor. + + * cipher/ecc-curves.c (ecc_domain_parms_t): Add cofactor 'h'. + (ecc_domain_parms_t domain_parms): Add cofactors. + (_gcry_ecc_fill_in_curve, _gcry_ecc_update_curve_param) + (_gcry_ecc_get_curve, _gcry_mpi_ec_new, _gcry_ecc_get_param_sexp) + (_gcry_ecc_get_mpi): Handle cofactor. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_genkey): Likewise. + * cipher/ecc-misc.c (_gcry_ecc_curve_free) + (_gcry_ecc_curve_copy): Likewise. + * cipher/ecc.c (nist_generate_key, ecc_generate) + (ecc_check_secret_key, ecc_sign, ecc_verify, ecc_encrypt_raw) + (ecc_decrypt_raw, _gcry_pk_ecc_get_sexp, _gcry_pubkey_spec_ecc): + Likewise. + (compute_keygrip): Handle cofactor, but skip it for its computation. + * mpi/ec.c (ec_deinit): Likewise. + * tests/t-mpi-point.c (context_param): Likewise. + (test_curve): Add cofactors. + * tests/curves.c (sample_key_1, sample_key_2): Add cofactors. + * tests/keygrip.c (key_grips): Add cofactors. + +2014-08-05 Werner Koch + + mpi: Fix regression for powerpc-apple-darwin detection. + + commit 4ce77b0a810d3c889c07dfb385127d90fa1ae36a + * mpi/config.links: Add separate entry for powerpc-apple-darwin. + + Fix bug inhibiting the use of the sentinel attribute. + + commit d2d28298ccc0d0f3c0b03fd323deb1e8808ef74f + * src/gcrypt.h.in: Fix typo in macro. + + mpi: Use BSD syntax for x86_64-apple-darwin. + + commit 71939faa7c54e7b4b28d115e748a85f134876a02 + * mpi/config.links: Add case for x86_64-apple-darwin. + +2014-08-05 Kristian Fiskerstrand + + Fix building for the x32 target without asm modules. + + commit a17c29844b63e9e869f7855d901bc9d859234ead + * mpi/generic/mpi-asm-defs.h: Use a fixed value for the x32 ABI. + +2014-07-25 Werner Koch + + ecc: Support the non-standard 0x40 compression flag for EdDSA. + + commit 4556f9b19c024f16bdf542da7173395c0741b91d + * cipher/ecc.c (ecc_generate): Check the "comp" flag for EdDSA. + * cipher/ecc-eddsa.c (eddsa_encode_x_y): Add arg WITH_PREFIX. + (_gcry_ecc_eddsa_encodepoint): Ditto. + (_gcry_ecc_eddsa_ensure_compact): Handle the 0x40 compression prefix. + (_gcry_ecc_eddsa_decodepoint): Ditto. + * tests/keygrip.c: Check an compresssed with prefix Ed25519 key. + * tests/t-ed25519.inp: Ditto. + + mpi: Extend the internal mpi_get_buffer. + + commit 0e10902ad7584277ac966367efc712b183784532 + * mpi/mpicoder.c (do_get_buffer): Add arg EXTRAALLOC. + (_gcry_mpi_get_buffer_extra): New. + + cipher: Fix compiler warning for chacha20. + + commit 4e0bf1b9190ce08fb23eb3ae0c3be58954ff36ab + * cipher/chacha20.c (chacha20_blocks) [!USE_SSE2]: Do not build. + +2014-07-16 NIIBE Yutaka + + mpi: Add mpi_swap_cond. + + commit 4846e52728970e3117f3a046ef9010be089a3ae4 + * mpi/mpiutil.c (_gcry_mpi_swap_cond): New. + * src/mpi.h (mpi_swap_cond): New. + +2014-06-29 Jussi Kivilinna + + Speed-up SHA-1 NEON assembly implementation. + + commit 1b9b00bbe41bbed32563f1102049521e703e72bd + * cipher/sha1-armv7-neon.S: Tweak implementation for speed-up. + +2014-06-28 Dmitry Eremin-Solenikov + + gostr3411_94: rewrite to use u32 mathematic. + + commit 066f068bd0bc4d8e01f1f18b6153cdc8d2c245d7 + * cipher/gost28147.c (_gcry_gost_enc_data): New. + * cipher/gostr3411-94.c: Rewrite implementation to use u32 mathematic + internally. + * cipher/gost28147.c (_gcry_gost_enc_one): Remove. + + gost28147: use bufhelp helpers. + + commit 7aeba6c449169926076df83b01ddbfa6b41fe411 + * cipher/gost28147.c (gost_setkey, gost_encrypt_block, gost_decrypt_block): + use buf_get_le32/buf_put_le32 helpers. + + Fixup curve name in the GOST2012 test case. + + commit b78d504fa8745b8b04589acbbcf7dd5fe9279d13 + * tests/basic.c (check_pubkey): fixup curve name in public key. + + Update PBKDF2 tests with GOST R 34.11-94 test cases. + + commit 7533b2ad46f42e98d9dba52e88e79c0311d2d3b7 + * tests/t-kdf.c (check_pbkdf2): Add MD_GOSTR3411_CP test cases. + + Add GOST R 34.11-94 variant using id-GostR3411-94-CryptoProParamSet. + + commit 25d6af77e2336b5979ddbe8b90978fe5b61dfaf9 + * src/gcrypt.h.in (GCRY_MD_GOSTR3411_CP): New. + * src/cipher.h (_gcry_digest_spec_gost3411_cp): New. + * cipher/gost28147.c (_gcry_gost_enc_one): Differentiate between + CryptoPro and Test S-Boxes. + * cipher/gostr3411-94.c (_gcry_digest_spec_gost3411_cp, + gost3411_cp_init): New. + * cipher/md.c (md_open): GCRY_MD_GOSTR3411_CP also uses B=32. + + gost28147: support GCRYCTL_SET_SBOX. + + commit 5ee35a04362c94e680ef3633fa83b72e0aee8626 + cipher/gost28147.c (gost_set_extra_info, gost_set_sbox): New. + + Support setting s-box for the ciphers that require it. + + commit fb074d113fcbf66a5c20592625cb19051f3430f5 + * src/gcrypt.h.in (GCRYCTL_SET_SBOX, gcry_cipher_set_sbox): New. + * cipher/cipher.c (_gcry_cipher_ctl): pass GCRYCTL_SET_SBOX to + set_extra_info callback. + + cipher/gost28147: generate optimized s-boxes from compact ones. + + commit 164738a0292b3f32c7747099ad9cadace58e5eda + * cipher/gost-s-box.c: New. Outputs optimized expanded representation of + s-boxes (4x256) from compact 16x8 representation. + * cipher/Makefile.am: Add gost-sb.h dependency to gost28147.lo + * cipher/gost.h: Add sbox to the GOST28147_context structure. + * cipher/gost28147.c (gost_setkey): Set default s-box to test s-box from + GOST R 34.11 (this was the only one S-box before). + * cipher/gost28147.c (gost_val): Use sbox from the context. + + gost28147: add OIDs used to define cipher mode. + + commit 34a58010000288515636706811c3837f32957b2e + * cipher/gost28147 (oids_gost28147): Add OID from RFC4357. + + GOST R 34.11-94 add OIDs. + + commit 8b221cf5ce233c8c49a4e4ecebb70d523fc37837 + * cipher/gostr3411-94.c: Add OIDs for GOST R 34.11-94 from RFC 4357. + +2014-05-21 Jussi Kivilinna + + tests: add larger test-vectors for hash algorithms. + + commit f14fb5b427b5159fcd9603d2b3cde936889cf430 + * tests/basic.c (check_digests): Add large test-vectors for MD5, SHA1, + SHA224, SHA256, SHA384, RMD160, CRC32, TIGER1, WHIRLPOOL and + GOSTR3411_94. + + sha512: fix ARM/NEON implementation. + + commit beb901575f0d6cd6a0a27506ebea9a725754d0cc + * cipher/sha512-armv7-neon.S + (_gcry_sha512_transform_armv7_neon): Byte-swap RW67q and RW1011q + correctly in multi-block loop. + * tests/basic.c (check_digests): Add large test vector for SHA512. + +2014-05-20 Jussi Kivilinna + + Fix ARM assembly when building __PIC__ + + commit 994c758d8f5471c7e9c38c2834742cca2502d35f + * cipher/camellia-arm.S (GET_DATA_POINTER): New. + (_gcry_camellia_arm_encrypt_block): Use GET_DATA_POINTER. + (_gcry_camellia_arm_decrypt_block): Ditto. + * cipher/cast5-arm.S (GET_DATA_POINTER): New. + (_gcry_cast5_arm_encrypt_block, _gcry_cast5_arm_decrypt_block) + (_gcry_cast5_arm_enc_blk2, _gcry_cast5_arm_dec_blk2): Use + GET_DATA_POINTER. + * cipher/rijndael-arm.S (GET_DATA_POINTER): New. + (_gcry_aes_arm_encrypt_block, _gcry_aes_arm_decrypt_block): Use + GET_DATA_POINTER. + * cipher/sha1-armv7-neon.S (GET_DATA_POINTER): New. + (.LK_VEC): Move from .text to .data section. + (_gcry_sha1_transform_armv7_neon): Use GET_DATA_POINTER. + +2014-05-17 Jussi Kivilinna + + Add Poly1305 to documentation. + + commit bf4943932dae95a0573b63bf32a9b9acd5a6ddf3 + * doc/gcrypt.texi: Add documentation for Poly1305 MACs and AEAD mode. + +2014-05-16 Jussi Kivilinna + + chacha20: add SSE2/AMD64 optimized implementation. + + commit 323b1eb80ff3396d83fedbe5bba9a4e6c412d192 + * cipher/Makefile.am: Add 'chacha20-sse2-amd64.S'. + * cipher/chacha20-sse2-amd64.S: New. + * cipher/chacha20.c (USE_SSE2): New. + [USE_SSE2] (_gcry_chacha20_amd64_sse2_blocks): New. + (chacha20_do_setkey) [USE_SSE2]: Use SSE2 implementation for blocks + function. + * configure.ac [host=x86-64]: Add 'chacha20-sse2-amd64.lo'. + + poly1305: add AMD64/AVX2 optimized implementation. + + commit 98f021961ee65669037bc8bb552a69fd78f610fc + * cipher/Makefile.am: Add 'poly1305-avx2-amd64.S'. + * cipher/poly1305-avx2-amd64.S: New. + * cipher/poly1305-internal.h (POLY1305_USE_AVX2) + (POLY1305_AVX2_BLOCKSIZE, POLY1305_AVX2_STATESIZE) + (POLY1305_AVX2_ALIGNMENT): New. + (POLY1305_LARGEST_BLOCKSIZE, POLY1305_LARGEST_STATESIZE) + (POLY1305_STATE_ALIGNMENT): Use AVX2 versions when needed. + * cipher/poly1305.c [POLY1305_USE_AVX2] + (_gcry_poly1305_amd64_avx2_init_ext) + (_gcry_poly1305_amd64_avx2_finish_ext) + (_gcry_poly1305_amd64_avx2_blocks, poly1305_amd64_avx2_ops): New. + (_gcry_poly1305_init) [POLY1305_USE_AVX2]: Use AVX2 implementation if + AVX2 supported by CPU. + * configure.ac [host=x86_64]: Add 'poly1305-avx2-amd64.lo'. + +2014-05-12 Jussi Kivilinna + + poly1305: add AMD64/SSE2 optimized implementation. + + commit 297532602ed2d881d8fdc393d1961068a143a891 + * cipher/Makefile.am: Add 'poly1305-sse2-amd64.S'. + * cipher/poly1305-internal.h (POLY1305_USE_SSE2) + (POLY1305_SSE2_BLOCKSIZE, POLY1305_SSE2_STATESIZE) + (POLY1305_SSE2_ALIGNMENT): New. + (POLY1305_LARGEST_BLOCKSIZE, POLY1305_LARGEST_STATESIZE) + (POLY1305_STATE_ALIGNMENT): Use SSE2 versions when needed. + * cipher/poly1305-sse2-amd64.S: New. + * cipher/poly1305.c [POLY1305_USE_SSE2] + (_gcry_poly1305_amd64_sse2_init_ext) + (_gcry_poly1305_amd64_sse2_finish_ext) + (_gcry_poly1305_amd64_sse2_blocks, poly1305_amd64_sse2_ops): New. + (_gcry_polu1305_init) [POLY1305_USE_SSE2]: Use SSE2 version. + * configure.ac [host=x86_64]: Add 'poly1305-sse2-amd64.lo'. + + Add Poly1305 based cipher AEAD mode. + + commit e813958419b0ec4439e6caf07d3b2234cffa2bfa + * cipher/Makefile.am: Add 'cipher-poly1305.c'. + * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode.poly1305'. + (_gcry_cipher_poly1305_encrypt, _gcry_cipher_poly1305_decrypt) + (_gcry_cipher_poly1305_setiv, _gcry_cipher_poly1305_authenticate) + (_gcry_cipher_poly1305_get_tag, _gcry_cipher_poly1305_check_tag): New. + * cipher/cipher-poly1305.c: New. + * cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey) + (cipher_reset, cipher_encrypt, cipher_decrypt, _gcry_cipher_setiv) + (_gcry_cipher_authenticate, _gcry_cipher_gettag) + (_gcry_cipher_checktag): Handle 'GCRY_CIPHER_MODE_POLY1305'. + (cipher_setiv): Move handling of 'GCRY_CIPHER_MODE_GCM' to ... + (_gcry_cipher_setiv): ... here, as with other modes. + * src/gcrypt.h.in: Add 'GCRY_CIPHER_MODE_POLY1305'. + * tests/basic.c (_check_poly1305_cipher, check_poly1305_cipher): New. + (check_ciphers): Add Poly1305 check. + (check_cipher_modes): Call 'check_poly1305_cipher'. + * tests/bench-slope.c (bench_gcm_encrypt_do_bench): Rename to + bench_aead_... and take nonce as argument. + (bench_gcm_decrypt_do_bench, bench_gcm_authenticate_do_bench): Ditto. + (bench_gcm_encrypt_do_bench, bench_gcm_decrypt_do_bench) + (bench_gcm_authenticate_do_bench, bench_poly1305_encrypt_do_bench) + (bench_poly1305_decrypt_do_bench) + (bench_poly1305_authenticate_do_bench, poly1305_encrypt_ops) + (poly1305_decrypt_ops, poly1305_authenticate_ops): New. + (cipher_modes): Add Poly1305. + (cipher_bench_one): Add special handling for Poly1305. + + Add Poly1305-AES (-Camellia, etc) MACs. + + commit 73b3b75c2221a6e3bed4117e0a206a1193acd2ed + * cipher/mac-internal.h (_gcry_mac_type_spec_poly1305_aes) + (_gcry_mac_type_spec_poly1305_camellia) + (_gcry_mac_type_spec_poly1305_twofish) + (_gcry_mac_type_spec_poly1305_serpent) + (_gcry_mac_type_spec_poly1305_seed): New. + * cipher/mac-poly1305.c (poly1305mac_context_s): Add 'hd' and + 'nonce_set'. + (poly1305mac_open, poly1305mac_close, poly1305mac_setkey): Add handling + for Poly1305-*** MACs. + (poly1305mac_prepare_key, poly1305mac_setiv): New. + (poly1305mac_reset, poly1305mac_write, poly1305mac_read): Add handling + for 'nonce_set'. + (poly1305mac_ops): Add 'poly1305mac_setiv'. + (_gcry_mac_type_spec_poly1305_aes) + (_gcry_mac_type_spec_poly1305_camellia) + (_gcry_mac_type_spec_poly1305_twofish) + (_gcry_mac_type_spec_poly1305_serpent) + (_gcry_mac_type_spec_poly1305_seed): New. + * cipher/mac.c (mac_list): Add Poly1305-AES, Poly1305-Twofish, + Poly1305-Serpent, Poly1305-SEED and Poly1305-Camellia. + * src/gcrypt.h.in: Add 'GCRY_MAC_POLY1305_AES', + 'GCRY_MAC_POLY1305_CAMELLIA', 'GCRY_MAC_POLY1305_TWOFISH', + 'GCRY_MAC_POLY1305_SERPENT' and 'GCRY_MAC_POLY1305_SEED'. + * tests/basic.c (check_mac): Add Poly1305-AES test vectors. + * tests/bench-slope.c (bench_mac_init): Set IV for Poly1305-*** MACs. + * tests/bench-slope.c (mac_bench): Set IV for Poly1305-*** MACs. + + Add Poly1305 MAC. + + commit b8794fed68ebe7567f4617141f0996ad290d9120 + * cipher/Makefile.am: Add 'mac-poly1305.c', 'poly1305.c' and + 'poly1305-internal.h'. + * cipher/mac-internal.h (poly1305mac_context_s): New. + (gcry_mac_handle): Add 'u.poly1305mac'. + (_gcry_mac_type_spec_poly1305mac): New. + * cipher/mac-poly1305.c: New. + * cipher/mac.c (mac_list): Add Poly1305. + * cipher/poly1305-internal.h: New. + * cipher/poly1305.c: New. + * src/gcrypt.h.in: Add 'GCRY_MAC_POLY1305'. + * tests/basic.c (check_mac): Add Poly1035 test vectors; Allow + overriding lengths of data and key buffers. + * tests/bench-slope.c (mac_bench): Increase max algo number from 500 to + 600. + * tests/benchmark.c (mac_bench): Ditto. + + chacha20/AVX2: clear upper-halfs of YMM registers on entry. + + commit c20daeeb05329bfc6cc2c562cbd4b965291fe0e1 + * cipher/chacha20-avx2-amd64.S (_gcry_chacha20_amd64_avx2_blocks): Add + 'vzeroupper' at beginning. + + chacha20/AVX2: check for ENABLE_AVX2_SUPPORT instead of HAVE_GCC_INLINE_ASM_AVX2 + + commit a3062db748f272e0f7346e1ed9e0bf7ed61a4eae + * cipher/chacha20.c (USE_AVX2): Enable depending on + ENABLE_AVX2_SUPPORT, not HAVE_GCC_INLINE_ASM_AVX2. + * cipher/chacha20-avx2-amd64.S: Ditto. + + chacha20/SSSE3: clear XMM registers after use. + + commit a7d9eeeba632b7eb4a5b15ff17f6565181642f3c + * cipher/chacha20-ssse3-amd64.S (_gcry_chacha20_amd64_ssse3_blocks): On + return, clear XMM registers. + +2014-05-11 Jussi Kivilinna + + chacha20: add AVX2/AMD64 assembly implementation. + + commit a39ee7555691d18cae97560f130aaf952bfbd278 + * cipher/Makefile.am: Add 'chacha20-avx2-amd64.S'. + * cipher/chacha20-avx2-amd64.S: New. + * cipher/chacha20.c (USE_AVX2): New macro. + [USE_AVX2] (_gcry_chacha20_amd64_avx2_blocks): New. + (chacha20_do_setkey): Select AVX2 implementation if there is HW + support. + (selftest): Increase size of buf by 256. + * configure.ac [host=x86-64]: Add 'chacha20-avx2-amd64.lo'. + + chacha20: add SSSE3 assembly implementation. + + commit def7d4cad386271c6d4e2f10aabe0cb4abd871e4 + * cipher/Makefile.am: Add 'chacha20-ssse3-amd64.S'. + * cipher/chacha20-ssse3-amd64.S: New. + * cipher/chacha20.c (USE_SSSE3): New macro. + [USE_SSSE3] (_gcry_chacha20_amd64_ssse3_blocks): New. + (chacha20_do_setkey): Select SSSE3 implementation if there is HW + support. + * configure.ac [host=x86-64]: Add 'chacha20-ssse3-amd64.lo'. + + Add ChaCha20 stream cipher. + + commit 23f33d57c9b6f2295a8ddfc9a8eee5a2c30cf406 + * cipher/Makefile.am: Add 'chacha20.c'. + * cipher/chacha20.c: New. + * cipher/cipher.c (cipher_list): Add ChaCha20. + * configure.ac: Add ChaCha20. + * doc/gcrypt.texi: Add ChaCha20. + * src/cipher.h (_gcry_cipher_spec_chacha20): New. + * src/gcrypt.h.in (GCRY_CIPHER_CHACHA20): Add new algo. + * tests/basic.c (MAX_DATA_LEN): Increase to 128 from 100. + (check_stream_cipher): Add ChaCha20 test-vectors. + (check_ciphers): Add ChaCha20. + +2014-05-09 Werner Koch + + mpi: Fix a subtle bug setting spurious bits with in mpi_set_bit. + + commit 246b7aaae1ee459f440260bbc4ec2c01c5dc3362 + * mpi/mpi-bit.c (_gcry_mpi_set_bit, _gcry_mpi_set_highbit): Clear + allocated but not used bits before resizing. + * tests/t-mpi-bits.c (set_bit_with_resize): New. + +2014-05-07 Werner Koch + + Bump LT version. + + commit fc6ff6f73a51bcbbbb3757dc1386da40aa3ae75d + * configure.ac: Bumb LT version to C21/A1/R0. + +2014-04-22 Werner Koch + + random: Small patch for consistency and really burn the stack. + + commit a79c4ad7c56ee4410f17beb73eeb58b0dd36bfc6 + * random/rndlinux.c (_gcry_rndlinux_gather_random): s/int/size_t/. + (_gcry_rndlinux_gather_random): Replace memset by wipememory. + +2014-04-16 Werner Koch + + pubkey: Re-map all depreccated RSA algo numbers. + + commit 773e23698218755e9172d2507031a8263c47cc0b + * cipher/pubkey.c (map_algo): Mape RSA_E and RSA_S. + +2014-04-15 Werner Koch + + cipher: Fix possible NULL dereference. + + commit ae1fbce6dacf14747af0126e640bd4e54cb8c680 + * cipher/md.c (_gcry_md_selftest): Check for spec being NULL. + +2014-03-30 Jussi Kivilinna + + 3des: add amd64 assembly implementation for 3DES. + + commit b76b632a453b8d100d024e2439b4358454dc286e + * cipher/Makefile.am: Add 'des-amd64.S'. + * cipher/cipher-selftests.c (_gcry_selftest_helper_cbc) + (_gcry_selftest_helper_cfb, _gcry_selftest_helper_ctr): Handle failures + from 'setkey' function. + * cipher/cipher.c (_gcry_cipher_open_internal) [USE_DES]: Setup bulk + functions for 3DES. + * cipher/des-amd64.S: New file. + * cipher/des.c (USE_AMD64_ASM, ATTR_ALIGNED_16): New macros. + [USE_AMD64_ASM] (_gcry_3des_amd64_crypt_block) + (_gcry_3des_amd64_ctr_enc), _gcry_3des_amd64_cbc_dec) + (_gcry_3des_amd64_cfb_dec): New prototypes. + [USE_AMD64_ASM] (tripledes_ecb_crypt): New function. + (TRIPLEDES_ECB_BURN_STACK): New macro. + (_gcry_3des_ctr_enc, _gcry_3des_cbc_dec, _gcry_3des_cfb_dec) + (bulk_selftest_setkey, selftest_ctr, selftest_cbc, selftest_cfb): New + functions. + (selftest): Add call to CTR, CBC and CFB selftest functions. + (do_tripledes_encrypt, do_tripledes_decrypt): Use + TRIPLEDES_ECB_BURN_STACK. + * configure.ac [host=x86-64]: Add 'des-amd64.lo'. + * src/cipher.h (_gcry_3des_ctr_enc, _gcry_3des_cbc_dec) + (_gcry_3des_cfb_dec): New prototypes. + +2014-03-13 Werner Koch + + tests: Print diagnostics for skipped tests. + + commit 50aeee51a0b1a09dd9fff2bb71749a816fe7a791 + * tests/basic.c (show_note): New. + (show_md_not_available): + (show_old_hmac_not_available): + (show_mac_not_available): + (check_digests): Remove USE_foo cpp tests from the test table. Call + show_md_not_available if algo is not available. + (check_hmac): Likewise. + (check_mac): Likewise. + +2014-03-11 Dmitry Eremin-Solenikov + + Add MD2 message digest implementation. + + commit 5a8e1504bf8a2ffbc018be576dea77b685200444 + * cipher/md2.c: New. + * cipher/md.c (digest_list): add _gcry_digest_spec_md2. + * tests/basic.c (check_digests): add MD2 test vectors. + * configure.ac (default_digests): disable md2 by default. + +2014-03-04 Dmitry Eremin-Solenikov + + Add an utility to calculate hashes over a set of files. + + commit 2b5403c408dfbd71be24c7635f5fa0b61ab4c9bb + * tests/gchash.c: New. + + Add a simple (raw) PKCS#1 padding mode. + + commit ea8d597726305274214224757b32730644e12bd8 + * src/cipher.h (PUBKEY_ENC_PKCS1_RAW): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Handle pkcs1-raw + flag. + * cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): + Handle s-exp like (data (flags pkcs1-raw) (value xxxxx)) + * cipher/rsa-common.c (_gcry_rsa_pkcs1_encode_raw_for_sig): + PKCS#1-encode data with embedded hash OID for signature verification. + * tests/basic.c (check_pubkey_sign): Add tests for s-exps with pkcs1-raw + flag. + +2014-02-04 Jussi Kivilinna + + Fix ARMv6 detection when CFLAGS modify target CPU architecture. + + commit 6be3032048ee2466511d2384fcf2d28b856219b2 + * configure.ac (gcry_cv_cc_arm_arch_is_v6): Use compiler test instead + of preprocessor test. + +2014-01-29 Werner Koch + + Reserve control code for FIPS extensions. + + commit aea96a64fbc58a0b6f9f435e97e93294c6eb1052 + * src/gcrypt.h.in (GCRYCTL_INACTIVATE_FIPS_FLAG): New. + (GCRYCTL_REACTIVATE_FIPS_FLAG): New. + * src/global.c (_gcry_vcontrol): Add them but return not_implemented. + +2014-01-29 NIIBE Yutaka + + Fix RSA Blinding. + + commit 121a90d8931944974054f7d94f63b7f89df87fa5 + * cipher/rsa.c (rsa_decrypt): Loop to get multiplicative inverse. + +2014-01-28 Werner Koch + + cipher: Take care of ENABLE_NEON_SUPPORT. + + commit 52f7c48c901a3de51bd690a218f3de2f71e8d790 + * cipher/salsa20.c (USE_ARM_NEON_ASM): Define only if + ENABLE_NEON_SUPPORT is defined. + * cipher/serpent.c (USE_NEON): Ditto. + * cipher/sha1.c (USE_NEON): Ditto. + * cipher/sha512.c (USE_ARM_NEON_ASM): Ditto. + + sexp: Fix broken gcry_sexp_nth. + + commit cbdc355415f83ed62da4f3618767eba54d7e6d37 + * src/sexp.c (_gcry_sexp_nth): Return a valid S-expression for a data + element. + (NODE): Remove unused typedef. + (ST_HINT): Comment unused macro. + + * tests/t-sexp.c (bug_1594): New. + (main): Run new test. + +2014-01-27 Werner Koch + + tests: Improve t-common.h. + + commit 7460e9243b3cc050631c37ed4f2713ae7bcb6762 + * tests/t-common.h: Add couple of macros. Check that config.h has + been included. + (show): Rename to info. + * tests/t-lock.c, tests/t-sexp.c: Adjust for changes. + + mpi: Minor fix for Atari-mint. + + commit 3caa0f1319dc4779e0d6eee4460c1af2a12b2c3c + * mpi/config.links [m68k-atari-mint]: Do not assume 68020. Suggested + by Alan Hourihane. + + (cherry picked from commit 420f42a5752e90a8b27d58ffa1ddfe6e4ab341e8) + +2014-01-27 Dmitry Eremin-Solenikov + + Fix most of memory leaks in tests code. + + commit 5c150ece094bf0a504a111ce6c7b72e8d0b0457a + * tests/basic.c (check_ccm_cipher): Close cipher after use. + * tests/basic.c (check_one_cipher): Correct length of used buffer. + * tests/benchmark.c (cipher_bench): Use xcalloc to make buffer + initialized. + * tests/keygen.c (check_ecc_keys): Release generated key. + * tests/t-mpi-point.c (context_param): Release mpi Q. + * tests/t-sexp.c (check_extract_param): Release extracted number. + + Fix memory leaks in ecc code. + + commit 6d87e6abdfb7552323a95401f14e6367398a3e5a + * cipher/ecc-curves.c (_gcry_ecc_update_curve_param): Release passed mpi + values. + * cipher/ecc.c (compute_keygrip): Fix potential memory leak in error + path. + * cipher/ecc.c (_gcry_ecc_get_curve): Release temporary mpi. + + Fix number of blocks passed used in _gcry_rmd160_mixblock. + + commit 5d23e7b9a77421f3ebfda4a84c459a8729f3bb41 + * cipher/rmd160.c (_gcry_rmd160_mixblock): pass 1 to transform + +2014-01-27 Werner Koch + + Small Windows build tweaks. + + commit f7df906171854b6b6506b82d4fee2c2ebb0327ea + * configure.ac (HAVE_PTHREAD): Do test when building for Windows. + + * tests/basic.c: Replace "%zi" by "%z" and a cast to make it work + under Windows. + + Update gpg-error autoconf macros to fix threading problems. + + commit 79da0358fd555361e1ce4202f55494a8918eb8ae + * m4/gpg-error.m4: Update to version 2014-01-24. + * tests/Makefile.am (t_lock_LDADD): Use MT Libs. + +2014-01-24 Dmitry Eremin-Solenikov + + tests: Pass -no-install to libtool. + + commit bf34bfa5c458ee5ece91f25e3b4194d768498ab6 + * tests/Makefile.am: add AM_LDFLAGS = -no-install + +2014-01-24 Werner Koch + + tests: Add a test for the internal locking. + + commit ff91ec934ed52294cddcd7dcfacc04721a0487bf + * src/global.c (external_lock_test): New. + (_gcry_vcontrol): Call new function with formerly reserved code 61. + + * tests/t-common.h: New. Taken from current libgpg-error. + * tests/t-lock.c: New. Based on t-lock.c from libgpg-error. + * configure.ac (HAVE_PTHREAD): Set macro to 1 if defined. + (AC_CHECK_FUNCS): Check for flockfile. + * tests/Makefile.am (tests_bin): Add t-lock. + (noinst_HEADERS): Add t-common.h + (LDADD): Move value to ... + (default_ldadd): new. + (t_lock_LDADD): New. + + Check compiler features only for the relevant platform. + + commit 24e65d715812cea28732397870cb1585b8435521 + * mpi/config.links (mpi_cpu_arch): Always set for ARM. Set for HPPA. + Set to "undefined" for unknown platforms. + (try_asm_modules): Act upon only after having detected the CPU. + * configure.ac: Move the call to config.links before the platform + specific compiler checks. Check platform specific features only if + the platform is targeted. + +2014-01-23 Werner Koch + + Support building using the latest mingw-w64 toolchain. + + commit 4ad3417acab5021db1f722c314314ce4b781833a + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Change mingw detection. + +2014-01-20 Werner Koch + + cipher: Fix commit 94030e44. + + commit dad06e4d1b835bac778b87090b1d3894b7535b14 + * cipher/tiger.c (tiger_init): Add arg FLAGS. + (tiger1_init, tiger2_init): Ditto. + + tests: Rename tsexp.c. + + commit 192e77d123fdb04c459c998b9eb1731618a833fa + * tests/tsexp.c: Rename to t-sexp.c + +2014-01-19 Werner Koch + + md: Add Whirlpool bug emulation feature. + + commit 94030e44aaff805d754e368507f16dd51a531b72 + * src/gcrypt.h.in (GCRY_MD_FLAG_BUGEMU1): New. + * src/cipher-proto.h (gcry_md_init_t): Add arg FLAGS. Change all code + to implement that flag. + * cipher/md.c (gcry_md_context): Replace SECURE and FINALIZED by bit + field FLAGS. Add flag BUGEMU1. Change all users. + (md_open): Replace args SECURE and HMAC by FLAGS. Init flags.bugemu1. + (_gcry_md_open): Add for GCRY_MD_FLAG_BUGEMU1. + (md_enable): Pass bugemu1 flag to the hash init function. + (_gcry_md_reset): Ditto. + +2014-01-17 Werner Koch + + Actually check for uint64_t. + + commit c3b30bae7d1e157f8b65e32ba1b3a516f2bbf58b + * configure.ac: Check size of uint64_t and the UINT64_C macro. + +2014-01-16 Werner Koch + + Replace ath based mutexes by gpgrt based locks. + + commit cfc151ba637200e4fc05d9481a8df2071b2f9a47 + * configure.ac (NEED_GPG_ERROR_VERSION): Require 1.13. + (gl_LOCK): Remove. + * src/ath.c, src/ath.h: Remove. Remove from all files. Replace all + mutexes by gpgrt based statically initialized locks. + * src/global.c (global_init): Remove ath_init. + (_gcry_vcontrol): Make ath install a dummy function. + (print_config): Remove threads info line. + + * doc/gcrypt.texi: Simplify the multi-thread related documentation. + +2014-01-15 NIIBE Yutaka + + ecc: Fix _gcry_mpi_ec_p_new to allow secp256k1. + + commit 49edeebb43174865cf4fa2c170a42a8e4274c4f0 + * mpi/ec.c (_gcry_mpi_ec_p_new): Remove checking a!=0. + * tests/t-mpi-point.c (context_alloc): Remove two spurious tests. + +2014-01-14 Milan Broz + + PBKDF2: Use gcry_md_reset to speed up calculation. + + commit 04cda6b7cc16f3f52c12d9d3e46c56701003496e + * cipher/kdf.c (_gcry_kdf_pkdf2): Use gcry_md_reset + to speed up calculation. + +2014-01-13 Werner Koch + + Fix macro conflict in NetBSD. + + commit 5f2af6c26bc04975c0b518881532871d7387d7ce + * cipher/bithelp.h (bswap32): Rename to _gcry_bswap32. + (bswap64): Rename to _gcry_bswap64. + + Use internal malloc function in fips.c. + + commit 518ae274a1845ce626b2b4223a9b3805cbbab1a7 + * src/fips.c (check_binary_integrity): s/gcry_malloc/xtrymalloc/. + +2014-01-13 Dmitry Eremin-Solenikov + + Truncate hash values for ECDSA signature scheme. + + commit 9edcf1090e0485f9f383b6c54b18ea8ca3d4a225 + * cipher/dsa-common (_gcry_dsa_normalize_hash): New. Truncate opaque + mpis as required for DSA and ECDSA signature schemas. + * cipher/dsa.c (verify): Return gpg_err_code_t value from verify() to + behave like the rest of internal sign/verify functions. + * cipher/dsa.c (sign, verify, dsa_verify): Factor out hash truncation. + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Factor out hash truncation. + * cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_verify): + as required by ECDSA scheme, truncate hash values to bitlength of + used curve. + * tests/pubkey.c (check_ecc_sample_key): add a testcase for hash + truncation. + + Add GOST R 34.10-2012 curves proposed by TC26. + + commit 2c5ec803100ed8261e51442fb93b75367b7725ea + * cipher/ecc-curves.c (domain_parmss): Add two GOST R 34.10-2012 curves + proposed/pending to standardization by TC26 (Russian cryptography + technical comitee). + * cipher/ecc-curves.c (curve_alias): Add OID aliases. + * tests/curves.c: Increase N_CURVES. + + Add GOST R 34.10-2001 curves per RFC4357. + + commit 9bedc5c3b646dfe481678ca58f5466ac46decaf7 + * cipher/ecc-curves.c (domain_parms): Add 3 curves defined in rfc4357. + * cipher/ecc-curves.c (curve_aliases): Add OID and Xch aliases for GOST + curves. + * tests/curves.c (N_CURVES): Update value. + + Fix typo in search_oid. + + commit 7edcb574d8d6dffb6e234c2ba1996a9a04923859 + * cipher/md.c (search_oid): Invert condition on oid comparison. + + Add MD2-HMAC calculation support. + + commit 653b58cb5e85511b6c04c3f85ef3e372c2e9f74f + * src/gcrypt.h.in (GCRY_MAC_HMAC_MD2): New. + * cipher/mac-hmac.c: Support GCRY_MAC_HMAC_MD2. + + Add a function to retrieve algorithm used by MAC handler. + + commit 8439a379c86ef1088465ea70ac10840759a1638e + * cipher/mac.c (_gcry_mac_get_algo): New function, returns used algo. + * src/visibility.c (gcry_mac_get_algo): New wrapper. + * src/visibility.h: Hanlde gcry_mac_get_algo. + * src/gcrypt-int.h (_gcry_mac_get_algo): New. + * src/gcrypt.h.in (gcry_mac_get_algo): New. + * src/libgcrypt.def (gcry_mac_get_algo): New. + * src/libgcrypt.vers (gcry_mac_get_algo): New. + * doc/gcrypt.texi: Document gcry_mac_get_algo. + * tests/basic.c (check_one_mac): Verify gcry_mac_get_algo. + + Correct formatting of gcry_mac_get_algo_keylen documentation. + + commit 36c9e0e4eb4f935da90df1c8df484d1940bda5eb + * doc/gcrypt.texi: add braces near gcry_mac_get_algo_keylen + documentation. + + Use braces around unsigned int in gcry_mac_get_algo_keylen + documentation, otherwise texinfo breaks that and uses 'int' as a + function definition. + +2014-01-13 Werner Koch + + ecc: Make a macro shorter. + + commit 2ef48ba59c32bfa1a9265d5eea8ab225a658903a + * src/mpi.h (MPI_EC_TWISTEDEDWARDS): Rename to MPI_EC_EDWARDS. CHnage + all users. + * cipher/ecc-curves.c (domain_parms): Add parameters for Curve3617 as + comment. + * mpi/ec.c (dup_point_twistededwards): Rename to dup_point_edwards. + (add_points_twistededwards): Rename to add_points_edwards. + +2014-01-12 Jussi Kivilinna + + Fix assembly division check. + + commit ef3e66e168c4b9b86bfc4903001631e53a7125d8 + * configure.ac (gcry_cv_gcc_as_const_division_ok): Correct variable + name mismatch at '--Wa,--divide' workaround check. + +2014-01-12 NIIBE Yutaka + + Add secp256k1 curve. + + commit 019e0e9e8c77a2edf283745e05e9301673ea6a0a + * cipher/ecc-curves.c (curve_aliases): Add secp256k1 and its OID. + (domain_parms): Add secp256k1's domain paramerter. + + * tests/basic.c (check_pubkey): Add a key of secp256k1. + + * tests/curves.c (N_CURVES): Updated. + +2014-01-12 Jussi Kivilinna + + Fix constant division for AMD64 assembly on Solaris/x86. + + commit 43376891c01f4aff1fbfb23beafebb5adfd0868c + * configure.ac (gcry_cv_gcc_as_const_division_ok): Add new check for + constant division in assembly and test for "-Wa,--divide" workaround. + (gcry_cv_gcc_amd64_platform_as_ok): Check for also constant division. + +2014-01-10 Werner Koch + + Use the generic autogen.sh script. + + commit b0ac1f9b143aa15855914ba93fef900288d45c9c + * autogen.rc: New. + * Makefile.am (EXTRA_DIST): Add it. + * autogen.sh: Update from current GnuPG. + + Move all helper scripts to build-aux/ + + commit df9b4eabf52faee6f289a4bc62219684442ae383 + * scripts/: Rename to build-aux/. + * compile, config.guess, config.rpath, config.sub + * depcomp, doc/mdate-sh, doc/texinfo.tex + * install-sh, ltmain.sh, missing: Move to build-aux/. + * Makefile.am (EXTRA_DIST): Adjust. + * configure.ac (AC_CONFIG_AUX_DIR): New. + (AM_SILENT_RULES): New. + +2013-12-30 Jussi Kivilinna + + Add blowfish/serpent ARM assembly files to Makefile.am. + + commit 7fef7f481c0a1542be34d1dc831f58d41846ac29 + * cipher/Makefile.am: Add 'blowfish-arm.S' and 'serpent-armv7-neon.S'. + + Add AMD64 assembly implementation for arcfour. + + commit 7547898109c72a97e3102b2a045ee4fdb2aa40bf + * cipher/Makefile.am: Add 'arcfour-amd64.S'. + * cipher/arcfour-amd64.S: New. + * cipher/arcfour.c (USE_AMD64_ASM): New. + [USE_AMD64_ASM] (ARCFOUR_context, _gcry_arcfour_amd64) + (encrypt_stream): New. + * configure.ac [host=x86_64]: Add 'arcfour-amd64.lo'. + + Parse /proc/cpuinfo for ARM HW features. + + commit a05be441d8cd89b90d8d58e3a343a436dae377d0 + * src/hwf-arm.c [__linux__] (HAS_PROC_CPUINFO) + (detect_arm_proc_cpuinfo): New. + (_gcry_hwf_detect_arm) [HAS_PROC_CPUINFO]: Check '/proc/cpuinfo' for + HW features. + + Fix buggy/incomplete detection of AVX/AVX2 support. + + commit bbcb12187afb1756cb27296166b57fa19ee45d4d + * configure.ac: Also check for 'xgetbv' instruction in AVX and AVX2 + inline assembly checks. + * src/hwf-x86.c [__i386__] (get_xgetbv): New function. + [__x86_64__] (get_xgetbv): New function. + [HAS_X86_CPUID] (detect_x86_gnuc): Check for OSXSAVE and OS support for + XMM&YMM registers and enable AVX/AVX2 only if XMM&YMM registers are + supported by OS. + +2013-12-18 Jussi Kivilinna + + Change utf-8 copyright characters to '(C)' + + commit b7e814f93ee40fcfe17a187a8989c07fde2ba0cd + cipher/blowfish-amd64.S: Change utf-8 encoded copyright character to + '(C)'. + cipher/blowfish-arm.S: Ditto. + cipher/bufhelp.h: Ditto. + cipher/camellia-aesni-avx-amd64.S: Ditto. + cipher/camellia-aesni-avx2-amd64.S: Ditto. + cipher/camellia-arm.S: Ditto. + cipher/cast5-amd64.S: Ditto. + cipher/cast5-arm.S: Ditto. + cipher/cipher-ccm.c: Ditto. + cipher/cipher-cmac.c: Ditto. + cipher/cipher-gcm.c: Ditto. + cipher/cipher-selftest.c: Ditto. + cipher/cipher-selftest.h: Ditto. + cipher/mac-cmac.c: Ditto. + cipher/mac-gmac.c: Ditto. + cipher/mac-hmac.c: Ditto. + cipher/mac-internal.h: Ditto. + cipher/mac.c: Ditto. + cipher/rijndael-amd64.S: Ditto. + cipher/rijndael-arm.S: Ditto. + cipher/salsa20-amd64.S: Ditto. + cipher/salsa20-armv7-neon.S: Ditto. + cipher/serpent-armv7-neon.S: Ditto. + cipher/serpent-avx2-amd64.S: Ditto. + cipher/serpent-sse2-amd64.S: Ditto. + + Add ARM/NEON implementation for SHA-1. + + commit fc7dcf616937afaf73cfda1bf7bd79566a96b130 + * cipher/Makefile.am: Add 'sha1-armv7-neon.S'. + * cipher/sha1-armv7-neon.S: New. + * cipher/sha1.c (USE_NEON): New. + (SHA1_CONTEXT, sha1_init) [USE_NEON]: Add and initialize 'use_neon'. + [USE_NEON] (_gcry_sha1_transform_armv7_neon): New. + (transform) [USE_NEON]: Use ARM/NEON assembly if enabled. + * configure.ac: Add 'sha1-armv7-neon.lo'. + + Improve performance of SHA-512/ARM/NEON implementation. + + commit df629ba53a662427ebd3ddca90c3fe9ddd6511d3 + * cipher/sha512-armv7-neon.S (RT01q, RT23q, RT45q, RT67q): New. + (round_0_63, round_64_79): Remove. + (rounds2_0_63, rounds2_64_79): New. + (_gcry_sha512_transform_armv7_neon): Add 'nblks' input; Handle multiple + input blocks; Use new round macros. + * cipher/sha512.c [USE_ARM_NEON_ASM] + (_gcry_sha512_transform_armv7_neon): Add 'num_blks'. + (transform) [USE_ARM_NEON_ASM]: Pass nblks to assembly. + + Add AVX and AVX2/BMI implementations for SHA-256. + + commit a5c2bbfe0db515d739ab683297903c77b1eec124 + * LICENSES: Add 'cipher/sha256-avx-amd64.S' and + 'cipher/sha256-avx2-bmi2-amd64.S'. + * cipher/Makefile.am: Add 'sha256-avx-amd64.S' and + 'sha256-avx2-bmi2-amd64.S'. + * cipher/sha256-avx-amd64.S: New. + * cipher/sha256-avx2-bmi2-amd64.S: New. + * cipher/sha256-ssse3-amd64.S: Use 'lea' instead of 'add' in few + places for tiny speed improvement. + * cipher/sha256.c (USE_AVX, USE_AVX2): New. + (SHA256_CONTEXT) [USE_AVX, USE_AVX2]: Add 'use_avx' and 'use_avx2'. + (sha256_init, sha224_init) [USE_AVX, USE_AVX2]: Initialize above + new context members. + [USE_AVX] (_gcry_sha256_transform_amd64_avx): New. + [USE_AVX2] (_gcry_sha256_transform_amd64_avx2): New. + (transform) [USE_AVX2]: Use AVX2 assembly if enabled. + (transform) [USE_AVX]: Use AVX assembly if enabled. + * configure.ac: Add 'sha256-avx-amd64.lo' and + 'sha256-avx2-bmi2-amd64.lo'. + +2013-12-17 Jussi Kivilinna + + Add AVX and AVX/BMI2 implementations for SHA-1. + + commit e4e458465b124e25b6aec7a60174bf1ca32dc5fd + * cipher/Makefile.am: Add 'sha1-avx-amd64.S' and + 'sha1-avx-bmi2-amd64.S'. + * cipher/sha1-avx-amd64.S: New. + * cipher/sha1-avx-bmi2-amd64.S: New. + * cipher/sha1.c (USE_AVX, USE_BMI2): New. + (SHA1_CONTEXT) [USE_AVX]: Add 'use_avx'. + (SHA1_CONTEXT) [USE_BMI2]: Add 'use_bmi2'. + (sha1_init): Initialize 'use_avx' and 'use_bmi2'. + [USE_AVX] (_gcry_sha1_transform_amd64_avx): New. + [USE_BMI2] (_gcry_sha1_transform_amd64_bmi2): New. + (transform) [USE_BMI2]: Use BMI2 assembly if enabled. + (transform) [USE_AVX]: Use AVX assembly if enabled. + * configure.ac: Add 'sha1-avx-amd64.lo' and 'sha1-avx-bmi2-amd64.lo'. + + SHA-1/SSSE3: Improve performance on large buffers. + + commit 6fd0dd2a5f1362f91e2861cd9d300341a43842a5 + * cipher/sha1-ssse3-amd64.S (RNBLKS): New. + (_gcry_sha1_transform_amd64_ssse3): Handle multiple input blocks, with + software pipelining of next data block processing. + * cipher/sha1.c [USE_SSSE3] (_gcry_sha1_transform_amd64_ssse3): Add + 'nblks'. + (transform) [USE_SSSE3]: Pass nblks to assembly function. + + Add bulk processing for hash transform functions. + + commit 50b8c8342d023038a4b528af83153293dd2756ea + * cipher/hash-common.c (_gcry_md_block_write): Preload 'hd->blocksize' + to stack, pass number of blocks to 'hd->bwrite'. + * cipher/hash-common.c (_gcry_md_block_write_t): Add 'nblks'. + * cipher/gostr3411-94.c: Rename 'transform' function to + 'transform_blk', add new 'transform' function with 'nblks' as + additional input. + * cipher/md4.c: Ditto. + * cipher/md5.c: Ditto. + * cipher/md4.c: Ditto. + * cipher/rmd160.c: Ditto. + * cipher/sha1.c: Ditto. + * cipher/sha256.c: Ditto. + * cipher/sha512.c: Ditto. + * cipher/stribog.c: Ditto. + * cipher/tiger.c: Ditto. + * cipher/whirlpool.c: Ditto. + +2013-12-16 Werner Koch + + Release 1.6.0. + + commit 0ea9731e1c93a962f6266004ab0e7418c19d6277 + + + doc: Change yat2m to allow arbitrary condition names. + + commit 9a912f8c4f366c53f1cdb94513b67b937e87178b + * doc/yat2m.c (MAX_CONDITION_NESTING): New. + (gpgone_defined): Remove. + (condition_s, condition_stack, condition_stack_idx): New. + (cond_is_active, cond_in_verbatim): New. + (add_predefined_macro, set_macro, macro_set_p): New. + (evaluate_conditions, push_condition, pop_condition): New. + (parse_file): Rewrite to use the condition stack. + (top_parse_file): Set prefined macros. + (main): Change -D to define arbitrary macros. + + tests: Add SHA-512 to the long hash test. + + commit 0d3bd23d7f730b9bbc81fc8da8d99f4853c36020 + * tests/hashtest.c (testvectors): Add vectors for 256GiB SHA-512. + * tests/hashtest-256g.in (algos): Add test for SHA-512. + + Add configure option --enable-large-data-tests. + + commit a6b9304a889397ac98e1c2c4ac3e178669d94492 + * configure.ac: Add option --enable-large-data-tests. + * tests/hashtest-256g.in: New. + * tests/Makefile.am (EXTRA_DIST): Add hashtest-256g.in. + (TESTS): Split up into tests_bin, tests_bin_last, tests_sh, and + tests_sh_last. + (tests_sh_last): Add hashtest-256g + (noinst_PROGRAMS): Add only tests_bin and tests_bin_last. + (bench-slope.log, hashtest-256g.log): New rules to enforce serial run. + + random: Call random progress handler more often. + + commit 5a7ce59396fe56f0d681df314bfbdb5f7732d4b1 + * random/rndlinux.c (_gcry_rndlinux_gather_random): Update progress + indicator earlier. + + cipher: Normalize the MPIs used as input to secret key functions. + + commit dec048b2ec79271a2f4405be5b87b1e768b3f1a9 + * cipher/dsa.c (sign): Normalize INPUT. + * cipher/elgamal.c (decrypt): Normalize A and B. + * cipher/rsa.c (secret): Normalize the INPUT. + (rsa_decrypt): Reduce DATA before passing to secret. + +2013-12-16 Jussi Kivilinna + + Change dummy variable in mpih-div.c to mpi_limb_t type. + + commit 953535a7de68cf62b5b1ad6f96ea3a9edd83762c + * mpi/mpih-div.c (_gcry_mpih_mod_1, _gcry_mpih_divmod_1): Change dummy + variable to 'mpi_limb_t' type from 'int'. + + Remove duplicate gcry_mac_hd_t typedef. + + commit 5c31990214b58c4e17edb01fbbe6d9f573975a22 + * cipher/mac-internal.h (gcry_mac_hd_t): Remove. + +2013-12-15 Jussi Kivilinna + + Use u64 for CCM data lengths. + + commit 110fed2d6b0bbc97cb5cc0a3a564e05fc42afa2d + * cipher/cipher-ccm.c: Move code inside [HAVE_U64_TYPEDEF]. + [HAVE_U64_TYPEDEF] (_gcry_cipher_ccm_set_lengths): Use 'u64' for + data lengths. + [!HAVE_U64_TYPEDEF] (_gcry_cipher_ccm_encrypt) + (_gcry_cipher_ccm_decrypt, _gcry_cipher_ccm_set_nonce) + (_gcry_cipher_ccm_authenticate, _gcry_cipher_ccm_get_tag) + (_gcry_cipher_ccm_check_tag): Dummy functions returning + GPG_ERROR_NOT_SUPPORTED. + * cipher/cipher-internal.h (gcry_cipher_handle.u_mode.ccm) + (_gcry_cipher_ccm_set_lengths): Move inside [HAVE_U64_TYPEDEF] and use + u64 instead of size_t for CCM data lengths. + * cipher/cipher.c (_gcry_cipher_open_internal, cipher_reset) + (_gcry_cipher_ctl) [!HAVE_U64_TYPEDEF]: Return GPG_ERR_NOT_SUPPORTED + for CCM. + (_gcry_cipher_ctl) [HAVE_U64_TYPEDEF]: Use u64 for + GCRYCTL_SET_CCM_LENGTHS length parameters. + * tests/basic.c: Do not use CCM if !HAVE_U64_TYPEDEF. + * tests/bench-slope.c: Ditto. + * tests/benchmark.c: Ditto. + +2013-12-14 Werner Koch + + tests: Prevent rare failure of gcry_pk_decrypt test. + + commit bfb43a17d8db571fca4ed433ee8be5c366745844 + * tests/basic.c (check_pubkey_crypt): Add special mode 1. + (main): Add option --loop. + +2013-12-14 Jussi Kivilinna + + Minor fixes to SHA assembly implementations. + + commit ffd9b2aa5abda7f4d7790ed48116ed5d71ab9995 + * cipher/Makefile.am: Correct 'sha256-avx*.S' to 'sha512-avx*.S'. + * cipher/sha1-ssse3-amd64.S: First line, correct filename. + * cipher/sha256-ssse3-amd64.S: Return correct stack burn depth. + * cipher/sha512-avx-amd64.S: Use 'vzeroall' to clear registers. + * cipher/sha512-avx2-bmi2-amd64.S: Ditto and return correct stack burn + depth. + + SHA-1/SSSE3: Do not check for Intel syntax assembly support. + + commit c86c35534a153b13e880d0bb0ea3e48e1c0ecaf9 + * cipher/sha1-ssse3-amd64.S: Remove check for + HAVE_INTEL_SYNTAX_PLATFORM_AS. + * cipher/sha1.c [USE_SSSE3]: Ditto. + +2013-12-13 Jussi Kivilinna + + Convert SHA-1 SSSE3 implementation from mixed asm&C to pure asm. + + commit d2b853246c2ed056a92096d89c3ca057e45c9c92 + * cipher/Makefile.am: Change 'sha1-ssse3-amd64.c' to + 'sha1-ssse3-amd64.S'. + * cipher/sha1-ssse3-amd64.c: Remove. + * cipher/sha1-ssse3-amd64.S: New. + + SHA-1: Add SSSE3 implementation. + + commit be2238f68abcc6f2b4e8c38ad9141376ce622a22 + * cipher/Makefile.am: Add 'sha1-ssse3-amd64.c'. + * cipher/sha1-ssse3-amd64.c: New. + * cipher/sha1.c (USE_SSSE3): New. + (SHA1_CONTEXT) [USE_SSSE3]: Add 'use_ssse3'. + (sha1_init) [USE_SSSE3]: Initialize 'use_ssse3'. + (transform): Rename to... + (_transform): this. + (transform): New. + * configure.ac [host=x86_64]: Add 'sha1-ssse3-amd64.lo'. + + Add missing register clearing in to SHA-256 and SHA-512 assembly. + + commit 04615cc6803cdede25fa92e3ff697e252a23cd7a + * cipher/sha256-ssse3-amd64.S: Clear used XMM/YMM registers at return. + * cipher/sha512-avx-amd64.S: Ditto. + * cipher/sha512-avx2-bmi2-amd64.S: Ditto. + * cipher/sha512-ssse3-amd64.S: Ditto. + +2013-12-13 Werner Koch + + Update license information. + + commit 764643a3d5634bcbc47790bd8505f6a1a5280d9c + * LICENSES: New. + * Makefile.am (EXTRA_DIST): Add LICENSES. + * AUTHORS: Add list of copyright holders. + * README: Reference AUTHORS. + +2013-12-13 Jussi Kivilinna + + Fix empty clobber in AVX2 assembly check. + + commit e41d605ee41469e8a33cdc4d38f742cfb931f835 + * configure.ac (gcry_cv_gcc_inline_asm_avx2): Add "cc" as assembly + globber. + + Fix W32 build. + + commit a71b810ddd67ca3a1773d8f929d162551abb58eb + * random/rndw32.c (register_poll, slow_gatherer): Change gcry_xmalloc to + xmalloc, and gcry_xrealloc to xrealloc. + +2013-12-12 Jussi Kivilinna + + SHA-512: Add AVX and AVX2 implementations for x86-64. + + commit 2e4253dc8eb512cd0e807360926dc6ba912c95b4 + * cipher/Makefile.am: Add 'sha512-avx-amd64.S' and + 'sha512-avx2-bmi2-amd64.S'. + * cipher/sha512-avx-amd64.S: New. + * cipher/sha512-avx2-bmi2-amd64.S: New. + * cipher/sha512.c (USE_AVX, USE_AVX2): New. + (SHA512_CONTEXT) [USE_AVX]: Add 'use_avx'. + (SHA512_CONTEXT) [USE_AVX2]: Add 'use_avx2'. + (sha512_init, sha384_init) [USE_AVX]: Initialize 'use_avx'. + (sha512_init, sha384_init) [USE_AVX2]: Initialize 'use_avx2'. + [USE_AVX] (_gcry_sha512_transform_amd64_avx): New. + [USE_AVX2] (_gcry_sha512_transform_amd64_avx2): New. + (transform) [USE_AVX2]: Add call for AVX2 implementation. + (transform) [USE_AVX]: Add call for AVX implementation. + * configure.ac (HAVE_GCC_INLINE_ASM_BMI2): New check. + (sha512): Add 'sha512-avx-amd64.lo' and 'sha512-avx2-bmi2-amd64.lo'. + * doc/gcrypt.texi: Document 'intel-cpu' and 'intel-bmi2'. + * src/g10lib.h (HWF_INTEL_CPU, HWF_INTEL_BMI2): New. + * src/hwfeatures.c (hwflist): Add "intel-cpu" and "intel-bmi2". + * src/hwf-x86.c (detect_x86_gnuc): Check for HWF_INTEL_CPU and + HWF_INTEL_BMI2. + + SHA-512: Add SSSE3 implementation for x86-64. + + commit 69a6d0f9562fcd26112a589318c13de66ce1700e + * cipher/Makefile.am: Add 'sha512-ssse3-amd64.S'. + * cipher/sha512-ssse3-amd64.S: New. + * cipher/sha512.c (USE_SSSE3): New. + (SHA512_CONTEXT) [USE_SSSE3]: Add 'use_ssse3'. + (sha512_init, sha384_init) [USE_SSSE3]: Initialize 'use_ssse3'. + [USE_SSSE3] (_gcry_sha512_transform_amd64_ssse3): New. + (transform) [USE_SSSE3]: Call SSSE3 implementation. + * configure.ac (sha512): Add 'sha512-ssse3-amd64.lo'. + + SHA-256: Add SSSE3 implementation for x86-64. + + commit e1a3931263e67aacec3c0bfcaa86c7d1441d5c6a + * cipher/Makefile.am: Add 'sha256-ssse3-amd64.S'. + * cipher/sha256-ssse3-amd64.S: New. + * cipher/sha256.c (USE_SSSE3): New. + (SHA256_CONTEXT) [USE_SSSE3]: Add 'use_ssse3'. + (sha256_init, sha224_init) [USE_SSSE3]: Initialize 'use_ssse3'. + (transform): Rename to... + (_transform): This. + [USE_SSSE3] (_gcry_sha256_transform_amd64_ssse3): New. + (transform): New. + * configure.ac (HAVE_INTEL_SYNTAX_PLATFORM_AS): New check. + (sha256): Add 'sha256-ssse3-amd64.lo'. + * doc/gcrypt.texi: Document 'intel-ssse3'. + * src/g10lib.h (HWF_INTEL_SSSE3): New. + * src/hwfeatures.c (hwflist): Add "intel-ssse3". + * src/hwf-x86.c (detect_x86_gnuc): Test for SSSE3. + +2013-12-12 Werner Koch + + Add a configuration file to disable hardware features. + + commit 5e1239b1e2948211ff2675f45cce2b28c3379cfb + * src/hwfeatures.c: Inclyde syslog.h and ctype.h. + (HWF_DENY_FILE): New. + (my_isascii): New. + (parse_hwf_deny_file): New. + (_gcry_detect_hw_features): Call it. + + * src/mpicalc.c (main): Correctly initialize Libgcrypt. Add options + "--print-config" and "--disable-hwf". + + Move list of hardware features to hwfeatures.c. + + commit 4ae77322b681a13da62d01274bcab25be2af12d0 + * src/global.c (hwflist, disabled_hw_features): Move to .. + * src/hwfeatures.c: here. + (_gcry_disable_hw_feature): New. + (_gcry_enum_hw_features): New. + (_gcry_detect_hw_features): Remove arg DISABLED_FEATURES. + * src/global.c (print_config, _gcry_vcontrol, global_init): Adjust + accordingly. + + Remove macro hacks for internal vs. external functions. Part 2 and last. + + commit 3b30e9840d4b351c4de73b126e561154cb7df4cc + * src/visibility.h: Remove remaining define/undef hacks for symbol + visibility. Add macros to detect the use of the public functions. + Change all affected functions by replacing them by the x-macros. + * src/g10lib.h: Add internal prototypes. + (xtrymalloc, xtrycalloc, xtrymalloc_secure, xtrycalloc_secure) + (xtryrealloc, xtrystrdup, xmalloc, xcalloc, xmalloc_secure) + (xcalloc_secure, xrealloc, xstrdup, xfree): New macros. + +2013-12-11 Werner Koch + + random: Add a feature to close device file descriptors. + + commit cd548ba2dc777b8b27d8d33182ba733c20222120 + * src/gcrypt.h.in (GCRYCTL_CLOSE_RANDOM_DEVICE): New. + * src/global.c (_gcry_vcontrol): Call _gcry_random_close_fds. + * random/random.c (_gcry_random_close_fds): New. + * random/random-csprng.c (_gcry_rngcsprng_close_fds): New. + * random/random-fips.c (_gcry_rngfips_close_fds): New. + * random/random-system.c (_gcry_rngsystem_close_fds): New. + * random/rndlinux.c (open_device): Add arg retry. + (_gcry_rndlinux_gather_random): Add mode to close open fds. + + * tests/random.c (check_close_random_device): New. + (main): Call new test. + +2013-12-10 Werner Koch + + Fix last commit (9a37470c) + + commit eae1e7712e1b687bd77eb37d0eb505fc9d46d93c + * src/secmem.c (lock_pool): Remove remaining line. Reported by Ian + Goldberg. + +2013-12-09 Werner Koch + + Fix one-off memory leak when build with Linux capability support. + + commit 9a37470c50ee9966cb2652617a404ddd54a9c096 + * src/secmem.c (lock_pool, secmem_init): Use cap_free. Reported by + Mike Crowe . + +2013-12-09 David 'Digit' Turner + + Update libtool to support Android. + + commit 2516f0b660b1a7181ad38c44310c627f4f498595 + * m4/libtool.m4: Add "linux*android*" case. Taken from the libtool + repository. + +2013-12-09 Werner Koch + + tests: Speed up benchmarks in regression test mode. + + commit 2e5354fe8db5288939733d0fb63ad4c87bc20105 + * tests/tsexp.c (check_extract_param): Fix compiler warning. + * tests/Makefile.am (TESTS_ENVIRONMENT): Set GCRYPT_IN_REGRESSION_TEST. + * tests/bench-slope.c (main): Speed up if in regression test mode. + * tests/benchmark.c (main): Ditto. + + tests: Add --csv option to bench-slope. + + commit 8072e9fa4b42ae8e65e266aa158fd903f1bb0927 + * tests/bench-slope.c (STR, STR2): New. + (cvs_mode): New. + (num_measurement_repetitions): New. Replace use of + NUM_MEASUREMENT_REPETITIONS by this. + (current_section_name, current_algo_name, current_mode_name): New. + (bench_print_result_csv): New. + (bench_print_result_std): Rename from bench_print_result. + (bench_print_result): New. Divert depending on CSV_MODE. + (bench_print_header, bench_print_footer): take care of CSV_MODE. + (bench_print_algo, bench_print_mode): New. Use them instead of + explicit printfs. + (main): Add options --csv and --repetitions. + +2013-12-07 Werner Koch + + sexp: Allow long names and white space in gcry_sexp_extract_param. + + commit d4555433b6e422fa69a85cae99961f513e55d82b + * src/sexp.c (_gcry_sexp_vextract_param): Skip white space. Support + long parameter names. + * tests/tsexp.c (check_extract_param): Add test cases for long parameter + names and white space. + +2013-12-06 Werner Koch + + ecc: Merge partly duplicated code. + + commit 405021cb6d4e470337302c65dec5bc91491a89c1 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_sign): Factor A hashing out to ... + (_gcry_ecc_eddsa_compute_h_d): new function. + * cipher/ecc-misc.c (_gcry_ecc_compute_public): Use new function. + (reverse_buffer): Remove. + + ecc: Remove unused internal function. + + commit 4cf2c65fe15173c8d68a141a01b34fc1fb9080b7 + * src/cipher-proto.h (gcry_pk_spec): Remove get_param. + * cipher/ecc-curves.c (_gcry_ecc_get_param_sexp): Merge in code from + _gcry_ecc_get_param. + (_gcry_ecc_get_param): Remove. + * cipher/ecc.c (_gcry_pubkey_spec_ecc): Remove _gcry_ecc_get_param. + +2013-12-06 Jussi Kivilinna + + Fix building on mingw32. + + commit 5917ce34e3b3eac4c15f62577e4723974024f818 + * src/gcrypt-int.h: Include . + +2013-12-05 Werner Koch + + ecc: Change OID for Ed25519. + + commit 7ef43d1eebb4f8226e860982dfe5fa2e2c82ad0f + * cipher/ecc-curves.c (curve_aliased): Add more suitable OID for + Ed25519. + + Remove macro hacks for internal vs. external functions. Part 1. + + commit 7bacf1812b55fa78db63abaa1f5a9220e9c6cccc + * src/visibility.h: Remove almost all define/undef hacks for symbol + visibility. Add macros to detect the use of the public functions. + Change all affected functions by prefixing them explicitly with an + underscore and change all internal callers to call the underscore + prefixed versions. Provide convenience macros from sexp and mpi + functions. + * src/visibility.c: Change all functions to use only gpg_err_code_t + and translate to gpg_error_t only in visibility.c. + +2013-12-04 Jussi Kivilinna + + mpi: add inline assembly for x86-64. + + commit 85bb0a98ea5add0296cbcc415d557eaa1f6bd294 + * mpi/longlong.h [__x86_64] (add_ssaaaa, sub_ddmmss, umul_ppmm) + (udiv_qrnnd, count_leading_zeros, count_trailing_zeros): New. + +2013-12-04 NIIBE Yutaka + + mpi: fix gcry_mpi_powm for negative base. + + commit c56080c26186d25dec05f01831494c77d8d07e13 + * mpi/mpi-pow.c (gcry_mpi_powm) [USE_ALGORITHM_SIMPLE_EXPONENTIATION]: + Fix for the case where BASE is negative. + * tests/mpitests.c (test_powm): Add a test case of (-17)^6 mod 19. + +2013-12-03 Werner Koch + + Add build support for ppc64le. + + commit 2ff86db2e1b0f6cc22a1ca86037b526c5fa3be51 + * config.guess, config.sub: Update to latest version (2013-11-29). + * m4/libtool.m4: Add patches for ppc64le. + +2013-12-03 Jussi Kivilinna + + rijndael: fix compiler warning on aarch64. + + commit 59b1a1b7ee2923e1bf091071ae716d180c6c6006 + * cipher/rijndael.c (do_setkey): Use braces for empty if statement + instead of semicolon. + + Add aarch64 (arm64) mpi assembly. + + commit 80896bc8f5e6ed9a627374e34f040ad5f3617584 + * mpi/aarch64/mpi-asm-defs.h: New. + * mpi/aarch64/mpih-add1.S: New. + * mpi/aarch64/mpih-mul1.S: New. + * mpi/aarch64/mpih-mul2.S: New. + * mpi/aarch64/mpih-mul3.S: New. + * mpi/aarch64/mpih-sub1.S: New. + * mpi/config.links [host=aarch64-*-*]: Add configguration for aarch64 + assembly. + * mpi/longlong.h [__aarch64__] (add_ssaaaa, sub_ddmmss, umul_ppmm) + (count_leading_zeros): New. + +2013-12-02 Werner Koch + + ecc: Use constant time point operation for Twisted Edwards. + + commit d4ce0cfe0d35d7ec69c115456848b5b735c928ea + * mpi/ec.c (_gcry_mpi_ec_mul_point): Try to do a constant time + operation if needed. + * tests/benchmark.c (main): Add option --use-secmem. + + ecc: Make gcry_pk_testkey work for Ed25519. + + commit 14ae6224b1b17abbfc80c26ad0f4c60f1e8635e2 + * cipher/ecc-misc.c (_gcry_ecc_compute_public): Add optional args G + and d. Change all callers. + * cipher/ecc.c (gen_y_2): Remove. + (check_secret_key): Use generic public key compute function. Adjust + for use with Ed25519 and EdDSA. + (nist_generate_key): Do not use the compliant key thingy for Ed25519. + (ecc_check_secret_key): Make parameter parsing similar to the other + functions. + * cipher/ecc-curves.c (domain_parms): Zero prefix some parameters so + that _gcry_ecc_update_curve_param works correctly. + * tests/keygen.c (check_ecc_keys): Add "param" flag. Check all + Ed25519 keys. + + ecc: Fix eddsa point decompression. + + commit 485f35124b1a74af0bad321ed70be3a79d8d11d7 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_recover_x): Fix the negative + case. + + ecc: Fix gcry_mpi_ec_curve_point for Weierstrass. + + commit ecb90f8e7c6f2516080d27ed7da6a25f2314da3c + * mpi/ec.c (_gcry_mpi_ec_curve_point): Use correct equation. + (ec_pow3): New. + (ec_p_init): Always copy B. + + mpi: Introduce 4 user flags for gcry_mpi_t. + + commit 29eddc2558d4cf39995f66d5fccd62f584d5b203 + * src/gcrypt.h.in (GCRYMPI_FLAG_USER1, GCRYMPI_FLAG_USER2) + (GCRYMPI_FLAG_USER3, GCRYMPI_FLAG_USER4): New. + * mpi/mpiutil.c (gcry_mpi_set_flag, gcry_mpi_clear_flag) + (gcry_mpi_get_flag, _gcry_mpi_free): Implement them. + (gcry_mpi_set_opaque): Keep user flags. + +2013-11-29 Vladimir 'φ-coder/phcoder' Serbinenko + + Fix armv3 compile error. + + commit 3b1cc9e6c357574f54160298d731c18f3d717b6c + * mpi/longlong.h [__arm__ && __ARM_ARCH < 4] (umul_ppmm): Use + __AND_CLOBBER_CC instead of __CLOBBER_CC. + + longlong.h on mips with clang. + + commit 1ecbd0bca31d462719a2a6590c1d03244e76ef89 + * mpi/longlong.h [__mips__]: Use C-language version with clang. + +2013-11-24 Jussi Kivilinna + + Camellia: Tweaks for AES-NI implementations. + + commit 3ef21e7e1b8003db9792155044db95f9d9ced184 + * cipher/camellia-aesni-avx-amd64.S: Align stack to 16 bytes; tweak + key-setup for small speed up. + * cipher/camellia-aesni-avx2-amd64.S: Use vmovdqu even with aligned + stack; reorder vinsert128 instructions; use rbp for stack frame. + +2013-11-21 Jussi Kivilinna + + Add GMAC to MAC API. + + commit a34448c929b13bfb7b66d69169c89e7319a18b31 + * cipher/Makefile.am: Add 'mac-gmac.c'. + * cipher/mac-gmac.c: New. + * cipher/mac-internal.h (gcry_mac_handle): Add 'u.gcm'. + (_gcry_mac_type_spec_gmac_aes, _gcry_mac_type_spec_gmac_twofish) + (_gcry_mac_type_spec_gmac_serpent, _gcry_mac_type_spec_gmac_seed) + (_gcry_mac_type_spec_gmac_camellia): New externs. + * cipher/mac.c (mac_list): Add GMAC specifications. + * doc/gcrypt.texi: Add mention of GMAC. + * src/gcrypt.h.in (gcry_mac_algos): Add GCM algorithms. + * tests/basic.c (check_one_mac): Add support for MAC IVs. + (check_mac): Add support for MAC IVs and add GMAC test vectors. + * tests/bench-slope.c (mac_bench): Iterate algorithm numbers to 499. + * tests/benchmark.c (mac_bench): Iterate algorithm numbers to 499. + + GCM: Move gcm_table initialization to setkey. + + commit dbfa651618693da7ea73b4d2d00d4efd411bfb46 + * cipher/cipher-gcm.c: Change all 'c->u_iv.iv' to + 'c->u_mode.gcm.u_ghash_key.key'. + (_gcry_cipher_gcm_setkey): New. + (_gcry_cipher_gcm_initiv): Move ghash initialization to function above. + * cipher/cipher-internal.h (gcry_cipher_handle): Add + 'u_mode.gcm.u_ghash_key'; Reorder 'u_mode.gcm' members for partial + clearing in gcry_cipher_reset. + (_gcry_cipher_gcm_setkey): New prototype. + * cipher/cipher.c (cipher_setkey): Add GCM setkey. + (cipher_reset): Clear 'u_mode' only partially for GCM. + +2013-11-20 Jussi Kivilinna + + GCM: Add support for split data buffers and online operation. + + commit fb1e52e3fe231671de546eacd6becd31c26c4f7b + * cipher/cipher-gcm.c (do_ghash_buf): Add buffering for less than + blocksize length input and padding handling. + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt): Add handling + for AAD padding and check if data has already being padded. + (_gcry_cipher_gcm_authenticate): Check that AAD or data has not being + padded yet. + (_gcry_cipher_gcm_initiv): Clear padding marks. + (_gcry_cipher_gcm_tag): Add finalization and padding; Clear sensitive + data from cipher handle, since they are not used after generating tag. + * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode.gcm.macbuf', + 'u_mode.gcm.mac_unused', 'u_mode.gcm.ghash_data_finalized' and + 'u_mode.gcm.ghash_aad_finalized'. + * tests/basic.c (check_gcm_cipher): Rename to... + (_check_gcm_cipher): ...this and add handling for different buffer step + lengths; Enable per byte buffer testing. + (check_gcm_cipher): Call _check_gcm_cipher with different buffer step + sizes. + + GCM: Use size_t for buffer sizes. + + commit 2d870a9142e8c8b3f008e1ad8e83e4bdf7a8e4e7 + * cipher/cipher-gcm.c (ghash, gcm_bytecounter_add, do_ghash_buf) + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt) + (_gcry_cipher_gcm_authenticate, _gcry_cipher_gcm_geniv) + (_gcry_cipher_gcm_tag): Use size_t for buffer lengths. + * cipher/cipher-internal.h (_gcry_cipher_gcm_encrypt) + (_gcry_cipher_gcm_decrypt, _gcry_cipher_gcm_authenticate): Use size_t + for buffer lengths. + + GCM: add FIPS mode restrictions. + + commit 56d352d6bdcf7abaa33c3399741f5063e2ddc32a + * cipher/cipher-gcm.c (_gcry_cipher_gcm_encrypt) + (_gcry_cipher_gcm_get_tag): Do not allow using in FIPS mode is setiv + was invocated directly. + (_gcry_cipher_gcm_setiv): Rename to... + (_gcry_cipher_gcm_initiv): ...this. + (_gcry_cipher_gcm_setiv): New setiv function with check for FIPS mode. + [TODO] (_gcry_cipher_gcm_getiv): New. + * cipher/cipher-internal.h (gcry_cipher_handle): Add + 'u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode'. + + GCM: Add clearing and checking of marks.tag. + + commit 32a2da9abc91394b23cf565c1c833fa964394083 + * cipher/cipher-gcm.c (_gcry_cipher_gcm_encrypt) + (_gcry_cipher_gcm_decrypt, _gcry_cipher_gcm_authenticate): Make sure + that tag has not been finalized yet. + (_gcry_cipher_gcm_setiv): Clear 'marks.tag'. + + GCM: Add stack burning. + + commit 018f08354b1b116672e82f9ce942884b288aaf9e + * cipher/cipher-gcm.c (do_ghash, ghash): Return stack burn depth. + (setupM): Wipe 'tmp' buffer. + (do_ghash_buf): Wipe 'tmp' buffer and add stack burning. + + Add aggregated bulk processing for GCM on x86-64. + + commit c9537fbf8ff0af919cff2bebadc4c6e7caea8076 + * cipher/cipher-gcm.c [__x86_64__] (gfmul_pclmul_aggr4): New. + (ghash) [GCM_USE_INTEL_PCLMUL]: Add aggregated bulk processing + for __x86_64__. + (setupM) [__x86_64__]: Add initialization for aggregated bulk + processing. + + GCM: Tweak Intel PCLMUL ghash loop for small speed-up. + + commit 9b6764944284fed733c2f88619b3d9eb5d5c259a + * cipher/cipher-gcm.c (do_ghash): Mark 'inline'. + [GCM_USE_INTEL_PCLMUL] (do_ghash_pclmul): Rename to... + [GCM_USE_INTEL_PCLMUL] (gfmul_pclmul): ..this and make inline function. + (ghash) [GCM_USE_INTEL_PCLMUL]: Preload data before ghash-pclmul loop. + + GCM: Use counter mode code for speed-up. + + commit bd4bd23a2511a4bce63c3217cca0d4ecf0c79532 + * cipher/cipher-gcm.c (ghash): Add process for multiple blocks. + (gcm_bytecounter_add, gcm_add32_be128, gcm_check_datalen) + (gcm_check_aadlen_or_ivlen, do_ghash_buf): New functions. + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt) + (_gcry_cipher_gcm_authenticate, _gcry_cipher_gcm_set_iv) + (_gcry_cipher_gcm_tag): Adjust to use above new functions and + counter mode functions for encryption/decryption. + * cipher/cipher-internal.h (gcry_cipher_handle): Remove 'length'; Add + 'u_mode.gcm.(addlen|datalen|tagiv|datalen_over_limits)'. + (_gcry_cipher_gcm_setiv): Return gcry_err_code_t. + * cipher/cipher.c (cipher_setiv): Return error code. + (_gcry_cipher_setiv): Handle error code from 'cipher_setiv'. + + Add Intel PCLMUL acceleration for GCM. + + commit 5a65ffabadd50f174ab7375faad7a726cce49e61 + * cipher/cipher-gcm.c (fillM): Rename... + (do_fillM): ...to this. + (ghash): Remove. + (fillM): New macro. + (GHASH): Use 'do_ghash' instead of 'ghash'. + [GCM_USE_INTEL_PCLMUL] (do_ghash_pclmul): New. + (ghash): New. + (setupM): New. + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt) + (_gcry_cipher_gcm_authenticate, _gcry_cipher_gcm_setiv) + (_gcry_cipher_gcm_tag): Use 'ghash' instead of 'GHASH' and + 'c->u_mode.gcm.u_tag.tag' instead of 'c->u_tag.tag'. + * cipher/cipher-internal.h (GCM_USE_INTEL_PCLMUL): New. + (gcry_cipher_handle): Move 'u_tag' and 'gcm_table' under + 'u_mode.gcm'. + * configure.ac (pclmulsupport, gcry_cv_gcc_inline_asm_pclmul): New. + * src/g10lib.h (HWF_INTEL_PCLMUL): New. + * src/global.c: Add "intel-pclmul". + * src/hwf-x86.c (detect_x86_gnuc): Add check for Intel PCLMUL. + + GCM: GHASH optimizations. + + commit 0e9e7d72f3c9eb7ac832746c3034855faaf8d02c + * cipher/cipher-gcm.c [GCM_USE_TABLES] (gcmR, ghash): Replace with new. + [GCM_USE_TABLES] [GCM_TABLES_USE_U64] (bshift, fillM, do_ghash): New. + [GCM_USE_TABLES] [!GCM_TABLES_USE_U64] (bshift, fillM): Replace with + new. + [GCM_USE_TABLES] [!GCM_TABLES_USE_U64] (do_ghash): New. + (_gcry_cipher_gcm_tag): Remove extra memcpy to outbuf and use + buf_eq_const for comparing authentication tag. + * cipher/cipher-internal.h (gcry_cipher_handle): Different 'gcm_table' + for 32-bit and 64-bit platforms. + + Add some documentation for GCM mode. + + commit 332da0ed7c8fab6c2bee841c94d8364c2ab4e30d + * doc/gcrypt.texi: Add mention of GCM mode. + +2013-11-19 Dmitry Eremin-Solenikov + + Initial implementation of GCM. + + commit 90cce18b9eced4f412ceeec5bcae18c4493322df + * cipher/Makefile.am: Add 'cipher-gcm.c'. + * cipher/cipher-ccm.c (_gcry_ciphert_ccm_set_lengths) + (_gcry_cipher_ccm_authenticate, _gcry_cipher_ccm_tag) + (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt): Change + 'c->u_mode.ccm.tag' to 'c->marks.tag'. + * cipher/cipher-gcm.c: New. + * cipher/cipher-internal.h (GCM_USE_TABLES): New. + (gcry_cipher_handle): Add 'marks.tag', 'u_tag', 'length' and + 'gcm_table'; Remove 'u_mode.ccm.tag'. + (_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt) + (_gcry_cipher_gcm_setiv, _gcry_cipher_gcm_authenticate) + (_gcry_cipher_gcm_get_tag, _gcry_cipher_gcm_check_tag): New. + * cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey) + (cipher_encrypt, cipher_decrypt, _gcry_cipher_authenticate) + (_gcry_cipher_gettag, _gcry_cipher_checktag): Add GCM mode handling. + * src/gcrypt.h.in (gcry_cipher_modes): Add GCRY_CIPHER_MODE_GCM. + (GCRY_GCM_BLOCK_LEN): New. + * tests/basic.c (check_gcm_cipher): New. + (check_ciphers): Add GCM check. + (check_cipher_modes): Call 'check_gcm_cipher'. + * tests/bench-slope.c (bench_gcm_encrypt_do_bench) + (bench_gcm_decrypt_do_bench, bench_gcm_authenticate_do_bench) + (gcm_encrypt_ops, gcm_decrypt_ops, gcm_authenticate_ops): New. + (cipher_modes): Add GCM enc/dec/auth. + (cipher_bench_one): Limit GCM to block ciphers with 16 byte block-size. + * tests/benchmark.c (cipher_bench): Add GCM. + +2013-11-19 Jussi Kivilinna + + Camellia: fix compiler warning. + + commit 9816ae9d9931b75e4fdc9a5be10e6af447132313 + * cipher/camellia-glue.c (camellia_setkey): Use braces around empty if + statement. + + Tweak Camellia-AVX key-setup for small speed-up. + + commit 77922a82c3f2e30eca04511fa5a355208349c657 + * cipher/camellia-aesni-avx-amd64.S (camellia_f): Merge S-function output + rotation with P-function. + + Add CMAC (Cipher-based MAC) to MAC API. + + commit b49cd64aaaff2e5488a84665362ef7150683226c + * cipher/Makefile.am: Add 'cipher-cmac.c' and 'mac-cmac.c'. + * cipher/cipher-cmac.c: New. + * cipher/cipher-internal.h (gcry_cipher_handle.u_mode): Add 'cmac'. + * cipher/cipher.c (gcry_cipher_open): Rename to... + (_gcry_cipher_open_internal): ...this and add CMAC. + (gcry_cipher_open): New wrapper that disallows use of internal + modes (CMAC) from outside. + (cipher_setkey, cipher_encrypt, cipher_decrypt) + (_gcry_cipher_authenticate, _gcry_cipher_gettag) + (_gcry_cipher_checktag): Add handling for CMAC mode. + (cipher_reset): Do not reset 'marks.key' and do not clear subkeys in + 'u_mode' in CMAC mode. + * cipher/mac-cmac.c: New. + * cipher/mac-internal.h: Add CMAC support and algorithms. + * cipher/mac.c: Add CMAC algorithms. + * doc/gcrypt.texi: Add documentation for CMAC. + * src/cipher.h (gcry_cipher_internal_modes): New. + (_gcry_cipher_open_internal, _gcry_cipher_cmac_authenticate) + (_gcry_cipher_cmac_get_tag, _gcry_cipher_cmac_check_tag) + (_gcry_cipher_cmac_set_subkeys): New prototypes. + * src/gcrypt.h.in (gcry_mac_algos): Add CMAC algorithms. + * tests/basic.c (check_mac): Add CMAC test vectors. + +2013-11-16 Jussi Kivilinna + + Add new MAC API, initially with HMAC. + + commit fcd6da37d55f248d3558ee0ff385b41b866e7ded + * cipher/Makefile.am: Add 'mac.c', 'mac-internal.h' and 'mac-hmac.c'. + * cipher/bufhelp.h (buf_eq_const): New. + * cipher/cipher-ccm.c (_gcry_cipher_ccm_tag): Use 'buf_eq_const' for + constant-time compare. + * cipher/mac-hmac.c: New. + * cipher/mac-internal.h: New. + * cipher/mac.c: New. + * doc/gcrypt.texi: Add documentation for MAC API. + * src/gcrypt-int.h [GPG_ERROR_VERSION_NUMBER < 1.13] + (GPG_ERR_MAC_ALGO): New. + * src/gcrypt.h.in (gcry_mac_handle, gcry_mac_hd_t, gcry_mac_algos) + (gcry_mac_flags, gcry_mac_open, gcry_mac_close, gcry_mac_ctl) + (gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write) + (gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen) + (gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name) + (gcry_mac_reset, gcry_mac_test_algo): New. + * src/libgcrypt.def (gcry_mac_open, gcry_mac_close, gcry_mac_ctl) + (gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write) + (gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen) + (gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New. + * src/libgcrypt.vers (gcry_mac_open, gcry_mac_close, gcry_mac_ctl) + (gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write) + (gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen) + (gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New. + * src/visibility.c (gcry_mac_open, gcry_mac_close, gcry_mac_ctl) + (gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write) + (gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen) + (gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New. + * src/visibility.h (gcry_mac_open, gcry_mac_close, gcry_mac_ctl) + (gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write) + (gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen) + (gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New. + * tests/basic.c (check_one_mac, check_mac): New. + (main): Call 'check_mac'. + * tests/bench-slope.c (bench_print_header, bench_print_footer): Allow + variable algorithm name width. + (_cipher_bench, hash_bench): Update to above change. + (bench_hash_do_bench): Add 'gcry_md_reset'. + (bench_mac_mode, bench_mac_init, bench_mac_free, bench_mac_do_bench) + (mac_ops, mac_modes, mac_bench_one, _mac_bench, mac_bench): New. + (main): Add 'mac' benchmark options. + * tests/benchmark.c (mac_repetitions, mac_bench): New. + (main): Add 'mac' benchmark options. + + Use correct blocksize of 32 bytes for GOSTR3411-94 HMAC. + + commit b95a557a43aeed68ea5e5ce02aca42ee97bfdb3b + * cipher/md.c (md_open): Set macpads_Bsize to 32 for + GCRY_MD_GOST24311_94. + +2013-11-15 Jussi Kivilinna + + cipher: use size_t for internal buffer lengths. + + commit b787657a9d2c1d8e19f9fcb0b21e31cb062630cf + * cipher/arcfour.c (do_encrypt_stream, encrypt_stream): Use 'size_t' + for buffer lengths. + * cipher/blowfish.c (_gcry_blowfish_ctr_enc, _gcry_blowfish_cbc_dec) + (_gcry_blowfish_cfb_dec): Ditto. + * cipher/camellia-glue.c (_gcry_camellia_ctr_enc) + (_gcry_camellia_cbc_dec, _gcry_blowfish_cfb_dec): Ditto. + * cipher/cast5.c (_gcry_cast5_ctr_enc, _gcry_cast5_cbc_dec) + (_gcry_cast5_cfb_dec): Ditto. + * cipher/cipher-aeswrap.c (_gcry_cipher_aeswrap_encrypt) + (_gcry_cipher_aeswrap_decrypt): Ditto. + * cipher/cipher-cbc.c (_gcry_cipher_cbc_encrypt) + (_gcry_cipher_cbc_decrypt): Ditto. + * cipher/cipher-ccm.c (_gcry_cipher_ccm_encrypt) + (_gcry_cipher_ccm_decrypt): Ditto. + * cipher/cipher-cfb.c (_gcry_cipher_cfb_encrypt) + (_gcry_cipher_cfb_decrypt): Ditto. + * cipher/cipher-ctr.c (_gcry_cipher_ctr_encrypt): Ditto. + * cipher/cipher-internal.h (gcry_cipher_handle->bulk) + (_gcry_cipher_cbc_encrypt, _gcry_cipher_cbc_decrypt) + (_gcry_cipher_cfb_encrypt, _gcry_cipher_cfb_decrypt) + (_gcry_cipher_ofb_encrypt, _gcry_cipher_ctr_encrypt) + (_gcry_cipher_aeswrap_encrypt, _gcry_cipher_aeswrap_decrypt) + (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt): Ditto. + * cipher/cipher-ofb.c (_gcry_cipher_cbc_encrypt): Ditto. + * cipher/cipher-selftest.h (gcry_cipher_bulk_cbc_dec_t) + (gcry_cipher_bulk_cfb_dec_t, gcry_cipher_bulk_ctr_enc_t): Ditto. + * cipher/cipher.c (cipher_setkey, cipher_setiv, do_ecb_crypt) + (do_ecb_encrypt, do_ecb_decrypt, cipher_encrypt) + (cipher_decrypt): Ditto. + * cipher/rijndael.c (_gcry_aes_ctr_enc, _gcry_aes_cbc_dec) + (_gcry_aes_cfb_dec, _gcry_aes_cbc_enc, _gcry_aes_cfb_enc): Ditto. + * cipher/salsa20.c (salsa20_setiv, salsa20_do_encrypt_stream) + (salsa20_encrypt_stream, salsa20r12_encrypt_stream): Ditto. + * cipher/serpent.c (_gcry_serpent_ctr_enc, _gcry_serpent_cbc_dec) + (_gcry_serpent_cfb_dec): Ditto. + * cipher/twofish.c (_gcry_twofish_ctr_enc, _gcry_twofish_cbc_dec) + (_gcry_twofish_cfb_dec): Ditto. + * src/cipher-proto.h (gcry_cipher_stencrypt_t) + (gcry_cipher_stdecrypt_t, cipher_setiv_fuct_t): Ditto. + * src/cipher.h (_gcry_aes_cfb_enc, _gcry_aes_cfb_dec) + (_gcry_aes_cbc_enc, _gcry_aes_cbc_dec, _gcry_aes_ctr_enc) + (_gcry_blowfish_cfb_dec, _gcry_blowfish_cbc_dec) + (_gcry_blowfish_ctr_enc, _gcry_cast5_cfb_dec, _gcry_cast5_cbc_dec) + (_gcry_cast5_ctr_enc, _gcry_camellia_cfb_dec, _gcry_camellia_cbc_dec) + (_gcry_camellia_ctr_enc, _gcry_serpent_cfb_dec, _gcry_serpent_cbc_dec) + (_gcry_serpent_ctr_enc, _gcry_twofish_cfb_dec, _gcry_twofish_cbc_dec) + (_gcry_twofish_ctr_enc): Ditto. + + Camellia: Add AVX/AES-NI key setup. + + commit ef9f52cbb39e46918c96200b09c21e931eff174f + * cipher/camellia-aesni-avx-amd64.S (key_bitlength, key_table): New + order of fields in ctx. + (camellia_f, vec_rol128, vec_ror128): New macros. + (__camellia_avx_setup128, __camellia_avx_setup256) + (_gcry_camellia_aesni_avx_keygen): New functions. + * cipher/camellia-aesni-avx2-amd64.S (key_bitlength, key_table): New + order of fields in ctx. + * cipher/camellia-arm.S (CAMELLIA_TABLE_BYTE_LEN, key_length): Remove + unused macros. + * cipher/camellia-glue.c (CAMELLIA_context): Move keytable to head for + better alignment; Make 'use_aesni_avx' and 'use_aesni_avx2' bitfield + members. + [USE_AESNI_AVX] (_gcry_camellia_aesni_avx_keygen): New prototype. + (camellia_setkey) [USE_AESNI_AVX || USE_AESNI_AVX2]: Read hw features + to variable 'hwf' and match features from it. + (camellia_setkey) [USE_AESNI_AVX]: Use AES-NI/AVX key setup if + available. + + Avoid unneeded stack burning with AES-NI and reduce number of 'decryption_prepared' checks + + commit c8ad83fb605fdbf6dc0b0dbcc8aedfbd477640da + * cipher/rijndael.c (RIJNDAEL_context): Make 'decryption_prepared', + 'use_padlock' and 'use_aesni' 1-bit members in bitfield. + (do_setkey): Move 'hwfeatures' inside [USE_AESNI || USE_PADLOCK]. + (do_aesni_enc_aligned): Rename to... + (do_aesni_enc): ...this, as function does not require aligned input. + (do_aesni_dec_aligned): Rename to... + (do_aesni_dec): ...this, as function does not require aligned input. + (do_aesni): Remove. + (rijndael_encrypt): Call 'do_aesni_enc' instead of 'do_aesni'. + (rijndael_decrypt): Call 'do_aesni_dec' instead of 'do_aesni'. + (check_decryption_preparation): New. + (do_decrypt): Remove 'decryption_prepared' check. + (rijndael_decrypt): Ditto and call 'check_decryption_preparation'. + (_gcry_aes_cbc_dec): Ditto. + (_gcry_aes_cfb_enc): Add 'burn_depth' and burn stack only when needed. + (_gcry_aes_cbc_enc): Ditto. + (_gcry_aes_ctr_enc): Ditto. + (_gcry_aes_cfb_dec): Ditto. + (_gcry_aes_cbc_dec): Ditto and correct clearing of 'savebuf'. + +2013-11-14 Werner Koch + + md: Fix hashing for data >= 256 GB. + + commit c43a8c0d81a711161f7a81b24ef7c33a1353eee0 + * cipher/hash-common.h (gcry_md_block_ctx): Add "nblocks_high". + * cipher/hash-common.c (_gcry_md_block_write): Bump NBLOCKS_HIGH. + * cipher/md4.c (md4_init, md4_final): Take care of NBLOCKS_HIGH. + * cipher/md5.c (md5_init, md5_final): Ditto. + * cipher/rmd160.c (_gcry_rmd160_init, rmd160_final): Ditto. + * cipher/sha1.c (sha1_init, sha1_final): Ditto. + * cipher/sha256.c (sha256_init, sha224_init, sha256_final): Ditto. + * cipher/sha512.c (sha512_init, sha384_init, sha512_final): Ditto. + * cipher/tiger.c (do_init, tiger_final): Ditto. + * cipher/whirlpool.c (whirlpool_final): Ditto. + + * cipher/md.c (gcry_md_algo_info): Add GCRYCTL_SELFTEST. + (_gcry_md_selftest): Return "not implemented" as required. + * tests/hashtest.c: New. + * tests/genhashdata.c: New. + * tests/Makefile.am (TESTS): Add hashtest. + (noinst_PROGRAMS): Add genhashdata + +2013-11-13 Christian Grothoff + + ecc: Fix key generation for a plain Ed25519 key. + + commit 7d91e99bcd30a463dd4faed014b8521a663d8316 + * cipher/ecc.c (nist_generate_key): Use custom code for ED25519. + + ecc: Fix some memory leaks. + + commit c4f9af49f228df59c218381a25fa3c0f93ccbeae + * cipher/ecc-curves.c (_gcry_mpi_ec_new): Free ec->b before assigning. + * cipher/ecc.c (nist_generate_key): Release Q. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_genkey): Ditto. + +2013-11-11 Werner Koch + + ecc: Change keygrip computation for Ed25519+EdDSA. + + commit 4fb3c8e5a7fc6a1568f54bcc0be17fecf75e0742 + * cipher/ecc.c (compute_keygrip): Rework. + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_ensure_compact): New. + * cipher/ecc-curves.c (_gcry_ecc_update_curve_param): New. + * tests/keygrip.c (key_grips): Add flag param and test cases for + Ed25519. + + mpi: Add special format GCRYMPI_FMT_OPAQUE. + + commit 8b3eecee2d89179297e43de7d650f74759c61a58 + * src/gcrypt.h.in (GCRYMPI_FMT_OPAQUE): New. + (_gcry_sexp_nth_opaque_mpi): Remove. + * src/sexp.c (gcry_sexp_nth_mpi): Add support for GCRYMPI_FMT_OPAQUE. + (_gcry_sexp_vextract_param): Replace removed function by + GCRYMPI_FMT_OPAQUE. + +2013-11-10 Jussi Kivilinna + + Fix error output in CTR selftest. + + commit 7b26586e35a6d407ca31b41528b0810b1408fd4b + * cipher/cipher-selftest.c (_gcry_selftest_helper_ctr): Change + fprintf(stderr,...) to syslog(); Correct error output for bulk + IV check, plaintext mismatch => ciphertext mismatch. + +2013-11-09 Jussi Kivilinna + + Fix Serpent-AVX2 and Camellia-AVX2 counter modes. + + commit df29831d008e32faf74091d080a415731418d158 + * cipher/camellia-aesni-avx2-amd64.S + (_gcry_camellia_aesni_avx2_ctr_enc): Byte-swap before checking for + overflow handling. + * cipher/camellia-glue.c (selftest_ctr_128, selftest_cfb_128) + (selftest_cbc_128): Add 16 to nblocks. + * cipher/cipher-selftest.c (_gcry_selftest_helper_ctr): Add test with + non-overflowing IV and modify overflow IV to detect broken endianness + handling. + * cipher/serpent-avx2-amd64.S (_gcry_serpent_avx2_ctr_enc): Byte-swap + before checking for overflow handling; Fix crazy-mixed-endian IV + construction to big-endian. + * cipher/serpent.c (selftest_ctr_128, selftest_cfb_128) + (selftest_cbc_128): Add 8 to nblocks. + +2013-11-09 Sergey V + + cipher/gost28147: optimization: use precomputed S-box tables. + + commit 51501b638546665163bbb85a14308fdb99211a28 + * cipher/gost.h (GOST28147_context): Remove unneeded subst and + subst_set members. + * cipher/gost28147.c (max): Remove unneeded macro. + (test_sbox): Replace with new precomputed tables. + (gost_set_subst): Remove function. + (gost_val): Use new S-box tables. + (gost_encrypt_block, gost_decrypt_block): Tweak to use new ctx and + S-box tables. + +2013-11-09 Jussi Kivilinna + + Fix tail handling for AES-NI counter mode. + + commit 60ed0abbbc7cb15812f1e713143c72555acea69e + * cipher/rijndael.c (do_aesni_ctr): Fix outputting of updated + counter-IV. + +2013-11-08 Werner Koch + + ecc: Improve gcry_pk_get_curve. + + commit 03aed1acec611362285db5156a6b92c91604fba4 + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Factor some code out + to .. + (find_domain_parms_idx): new. + (_gcry_ecc_get_curve): Find by curve name on error. + + cipher: Avoid signed divisions in idea.c. + + commit e241dde1420475459e32608137829e52748d0212 + * cipher/idea.c (mul_inv): Use unsigned division. + + ecc: Implement the "nocomp" flag for key generation. + + commit 9f63c0f7a3b2c15c7e258cd17395cabd0a8f00cc + * cipher/ecc.c (ecc_generate): Support the "nocomp" flag. + * tests/keygen.c (check_ecc_keys): Add a test for it. + + ecc: Make "noparam" the default and replace by "param". + + commit ed45fd2e60c88e2f005282e6eadd018b59dcf65b + * src/cipher.h (PUBKEY_FLAG_NOCOMP): New. + (PUBKEY_FLAG_NOPARAM): Remove. + (PUBKEY_FLAG_PARAM): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Support the new + flags and ignore the obsolete "noparam" flag. + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Return the curve name + also for curves selected by NBITS. + (_gcry_mpi_ec_new): Support the "param" flag. + * cipher/ecc.c (ecc_generate, ecc_sign, ecc_verify): Ditto. + * tests/keygen.c (check_ecc_keys): Remove the "noparam" flag. + +2013-11-07 Jussi Kivilinna + + Fix decryption function size in AES AMD64 assembly. + + commit bfe4f6523b80bae0040328ef324b9000ee5b38a4 + * cipher/rijndael-amd64.S (_gcry_aes_amd64_decrypt_block): Set '.size' + for '_gcry_aes_amd64_decrypt_block', not '..._encrypt_block'. + + Change 64-bit shift to 32-bit in AES AMD64 assembly. + + commit 57b296ea3a5204cd3711b7bf57c8fb14d8542402 + * cipher/rijndael-amd64.S (do16bit_shr): Change 'shrq' to 'shrl'. + +2013-11-06 Jussi Kivilinna + + Speed-up AES-NI key setup. + + commit f702d62d888b30e24c19f203566a1473098b2b31 + * cipher/rijndael.c [USE_AESNI] (m128i_t): Remove. + [USE_AESNI] (u128_t): New. + [USE_AESNI] (aesni_do_setkey): New. + (do_setkey) [USE_AESNI]: Move AES-NI accelerated key setup to + 'aesni_do_setkey'. + (do_setkey): Call _gcry_get_hw_features only once. Clear stack after + use in generic key setup part. + (rijndael_setkey): Remove stack burning. + (prepare_decryption) [USE_AESNI]: Use 'u128_t' instead of 'm128i_t' to + avoid compiler generated SSE2 instructions and XMM register usage, + unroll 'aesimc' setup loop + (prepare_decryption): Clear stack after use. + [USE_AESNI] (do_aesni_enc_aligned): Update comment about alignment. + (do_decrypt): Do not burning stack after prepare_decryption. + + Avoid burn stack in Arcfour setkey. + + commit a50a6ba3540f49fc7dcdb32e691327d5942e3509 + * cipher/arcfour.c (arcfour_setkey): Remove stack burning. + + Avoid burn_stack in CAST5 setkey. + + commit 5797ebc268b4e953cedd0c729c5cdb1f8fd764e4 + * cipher/cast5.c (do_cast_setkey): Use wipememory instead of memset. + (cast_setkey): Remove stack burning. + + Improve Serpent key setup speed. + + commit 9897ccb381503455edc490679b2e9251a09ac5cb + * cipher/serpent.c (SBOX, SBOX_INVERSE): Remove index argument. + (serpent_subkeys_generate): Use smaller temporary arrays for subkey + generation and perform stack clearing locally. + (serpent_setkey_internal): Use wipememory to clear stack and remove + _gcry_burn_stack. + (serpent_setkey): Remove unneeded _gcry_burn_stack. + + Modify encrypt/decrypt arguments for in-place. + + commit b8515aa70b00baba3fba8121ed305edcd029c8c7 + * cipher/cipher.c (gcry_cipher_encrypt, gcry_cipher_decrypt): Modify + local arguments if in-place operation. + + Speed up Stribog. + + commit a48d07ccadee4cb8b666a9a4ba2f00129bad5b2f + * cipher/stribog.c (STRIBOG_TABLES): Remove. + (Pi): Remove. + [!STRIBOG_TABLES] (A, strido): Remove. + (stribog_table): New table pre-reordered with Pi values. + (strido): Rewrite for new table. + (LPSX): Rewrite for new table. + (xor): Remove. + (g): Small tweaks. + + Tweak AES-NI bulk CTR mode slightly. + + commit 3b5058b58a183fa23ecf3ef819e2ae6ac64c0216 + * cipher/rijndael.c [USE_AESNI] (aesni_cleanup_2_5): Rename to... + (aesni_cleanup_2_6): ...this and clear also 'xmm6'. + [USE_AESNI && __i386__] (do_aesni_ctr, do_aesni_ctr_4): Prevent + inlining only on i386, allow on AMD64. + [USE_AESNI] (do_aesni_ctr, do_aesni_ctr_4): Use counter block from + 'xmm5' and byte-swap mask from 'xmm6'. + (_gcry_aes_ctr_enc) [USE_AESNI]: Preload counter block to 'xmm5' and + byte-swap mask to 'xmm6'. + (_gcry_aes_ctr_enc, _gcry_aes_cfb_dec, _gcry_aes_cbc_dec): Use + 'aesni_cleanup_2_6'. + + Tweak bench-slope parameters. + + commit 7e98eecc1a955bc253765f92a166b6560f085b8c + * tests/bench-slope.c (BUF_STEP_SIZE): Half step size to 64. + (NUM_MEASUREMENT_REPETITIONS): Double repetitions to 64. + + Optimize Blowfish weak key check. + + commit 8e1c0f9b894c39b6554c544208dc000682f520c7 + * cipher/blowfish.c (hashset_elem, val_to_hidx, add_val): New. + (do_bf_setkey): Use faster algorithm for detecting weak keys. + (bf_setkey): Move stack burning to do_bf_setkey. + + Fix __builtin_bswap32/64 checks. + + commit 2590a5df6f5fc884614c8c379324027d2d61b9b5 + * configure.ac (gcry_cv_have_builtin_bswap32) + (gcry_cv_have_builtin_bswap64): Change compile checks to link checks. + + Fix 'u32' build error with Camellia. + + commit 84bcb400e7db7268abfc29b5ab1513b0c063b293 + * cipher/camellia.c: Add include for and "types.h". + (u32): Remove. + (u8): Typedef as 'byte'. + +2013-11-06 Werner Koch + + pubkey: Add forward compatibility feature. + + commit 6d169b654c7ff04c10f73afe80b2c70cefa410c1 + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Add + "igninvflag". + +2013-11-05 Werner Koch + + ecc: Require "eddsa" flag for curve Ed25519. + + commit b9fd3988b54b50109f4e7179e7fe0739bb1d97c5 + * src/cipher.h (PUBKEY_FLAG_ECDSA): Remove. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Remove "ecdsa". + * cipher/ecc.c (ecc_generate, ecc_sign, ecc_verify): Require "eddsa" flag. + * cipher/ecc-misc.c (_gcry_ecc_compute_public): Depend "eddsa" flag. + * tests/benchmark.c, tests/keygen.c, tests/pubkey.c + * tests/t-ed25519.c, tests/t-mpi-point.c: Adjust for changed flags. + + ecc: Fully implement Ed25519 compression in ECDSA mode. + + commit f09ffe8a4802af65a116e79eceeb1cb4ed4fa2f4 + * src/ec-context.h (mpi_ec_ctx_s): Add field FLAGS. + * mpi/ec.c (ec_p_init): Add arg FLAGS. Change all callers to pass it. + * cipher/ecc-curves.c (point_from_keyparam): Add arg EC, parse as + opaque mpi and use eddsa decoding depending on the flag. + (_gcry_mpi_ec_new): Rearrange to parse Q and D after knowing the + curve. + + mpi: Add function gcry_mpi_set_opaque_copy. + + commit 630aca794ddf057fb7265b7dc346374743036af4 + * src/gcrypt.h.in (gcry_mpi_set_opaque_copy): New. + * src/visibility.c (gcry_mpi_set_opaque_copy): New. + * src/visibility.h (gcry_mpi_set_opaque_copy): Mark visible. + * src/libgcrypt.def, src/libgcrypt.vers: Add new API. + * tests/mpitests.c (test_opaque): Add test. + +2013-11-04 Jussi Kivilinna + + Make test vectors 'static const' + + commit d50a88d1e29124d038196fec6082fd093e922604 + * cipher/arcfour.c (selftest): Change test vectors to 'static const'. + * cipher/blowfish.c (selftest): Ditto. + * cipher/camellia-glue.c (selftest): Ditto. + * cipher/cast5.c (selftest): Ditto. + * cipher/des.c (selftest): Ditto. + * cipher/rijndael.c (selftest): Ditto. + * tests/basic.c (cipher_cbc_mac_cipher, check_aes128_cbc_cts_cipher) + (check_ctr_cipher, check_cfb_cipher, check_ofb_cipher) + (check_ccm_cipher, check_stream_cipher) + (check_stream_cipher_large_block, check_bulk_cipher_modes) + (check_ciphers, check_digests, check_hmac, check_pubkey_sign) + (check_pubkey_sign_ecdsa, check_pubkey_crypt, check_pubkey): Ditto. + +2013-11-03 Jussi Kivilinna + + Make jump labels local in Salsa20 assembly. + + commit d4697862266f3c96b6946dc92139dd8f3e81e5f6 + * cipher/salsa20-amd64.S: Rename '._labels' to '.L_labels'. + * cipher/salsa20-armv7-neon.S: Ditto. + +2013-10-30 Jussi Kivilinna + + bithelp: fix undefined behaviour with rol and ror. + + commit d1cadd145199040299538891ab2ccd1208f7776e + * cipher/bithelp.h (rol, ror): Mask shift with 31. + +2013-10-29 Werner Koch + + tests: Add feature to skip benchmarks. + + commit ba6bffafd17bea11985afc500022d66da261d59a + * tests/benchmark.c (main): Add feature to skip the test. + * tests/bench-slope.c (main): Ditto. + (get_slope): Repace C++ style comment. + (double_cmp, cipher_bench, _hash_bench): Repalce system reserved + symbols. + + ecc: Finish Ed25519/ECDSA hack. + + commit c284f15db99e9cb135612de710199abb23baafd3 + * cipher/ecc.c (ecc_generate): Fix Ed25519/ECDSA case. + (ecc_verify): Implement ED25519/ECDSA uncompression. + + ecc: Add flags "noparam" and "comp". + + commit ba892a0a874c8b2a83dbf0940608cd7e2911ce01 + * src/cipher.h (PUBKEY_FLAG_NOPARAM, PUBKEY_FLAG_COMP): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Parse new flags + and change code for possible faster parsing. + * cipher/ecc.c (ecc_generate): Implement the "noparam" flag. + (ecc_sign): Ditto. + (ecc_verify): Ditto. + * tests/keygen.c (check_ecc_keys): Use the "noparam" flag. + + * cipher/ecc.c (ecc_generate): Fix parsing of the deprecated + transient-flag parameter. + (ecc_verify): Do not make Q optional in the extract-param call. + +2013-10-28 Jussi Kivilinna + + Fix typos in documentation. + + commit 1faa61845f180bd47e037e400dde2d864ee83c89 + * doc/gcrypt.texi: Fix some typos. + + Add ARM NEON assembly implementation of Serpent. + + commit 2cb6e1f323d24359b1c5b113be5c2f79a2a4cded + * cipher/Makefile.am: Add 'serpent-armv7-neon.S'. + * cipher/serpent-armv7-neon.S: New. + * cipher/serpent.c (USE_NEON): New macro. + (serpent_context_t) [USE_NEON]: Add 'use_neon'. + [USE_NEON] (_gcry_serpent_neon_ctr_enc, _gcry_serpent_neon_cfb_dec) + (_gcry_serpent_neon_cbc_dec): New prototypes. + (serpent_setkey_internal) [USE_NEON]: Detect NEON support. + (_gcry_serpent_neon_ctr_enc, _gcry_serpent_neon_cfb_dec) + (_gcry_serpent_neon_cbc_dec) [USE_NEON]: Use NEON implementations + to process eight blocks in parallel. + * configure.ac [neonsupport]: Add 'serpent-armv7-neon.lo'. + + Add ARM NEON assembly implementation of Salsa20. + + commit 3ff9d2571c18cd7a34359f9c60a10d3b0f932b23 + * cipher/Makefile.am: Add 'salsa20-armv7-neon.S'. + * cipher/salsa20-armv7-neon.S: New. + * cipher/salsa20.c [USE_ARM_NEON_ASM]: New macro. + (struct SALSA20_context_s, salsa20_core_t, salsa20_keysetup_t) + (salsa20_ivsetup_t): New. + (SALSA20_context_t) [USE_ARM_NEON_ASM]: Add 'use_neon'. + (SALSA20_context_t): Add 'keysetup', 'ivsetup' and 'core'. + (salsa20_core): Change 'src' argument to 'ctx'. + [USE_ARM_NEON_ASM] (_gcry_arm_neon_salsa20_encrypt): New prototype. + [USE_ARM_NEON_ASM] (salsa20_core_neon, salsa20_keysetup_neon) + (salsa20_ivsetup_neon): New. + (salsa20_do_setkey): Setup keysetup, ivsetup and core with default + functions. + (salsa20_do_setkey) [USE_ARM_NEON_ASM]: When NEON support detect, + set keysetup, ivsetup and core with ARM NEON functions. + (salsa20_do_setkey): Call 'ctx->keysetup'. + (salsa20_setiv): Call 'ctx->ivsetup'. + (salsa20_do_encrypt_stream) [USE_ARM_NEON_ASM]: Process large buffers + in ARM NEON implementation. + (salsa20_do_encrypt_stream): Call 'ctx->core' instead of directly + calling 'salsa20_core'. + (selftest): Add test to check large buffer processing and block counter + updating. + * configure.ac [neonsupport]: 'Add salsa20-armv7-neon.lo'. + + Add AMD64 assembly implementation of Salsa20. + + commit 5a3d43485efdc09912be0967ee0a3ce345b3b15a + * cipher/Makefile.am: Add 'salsa20-amd64.S'. + * cipher/salsa20-amd64.S: New. + * cipher/salsa20.c (USE_AMD64): New macro. + [USE_AMD64] (_gcry_salsa20_amd64_keysetup, _gcry_salsa20_amd64_ivsetup) + (_gcry_salsa20_amd64_encrypt_blocks): New prototypes. + [USE_AMD64] (salsa20_keysetup, salsa20_ivsetup, salsa20_core): New. + [!USE_AMD64] (salsa20_core): Change 'src' to non-constant, update block + counter in 'salsa20_core' and return burn stack depth. + [!USE_AMD64] (salsa20_keysetup, salsa20_ivsetup): New. + (salsa20_do_setkey): Move generic key setup to 'salsa20_keysetup'. + (salsa20_setkey): Fix burn stack depth. + (salsa20_setiv): Move generic IV setup to 'salsa20_ivsetup'. + (salsa20_do_encrypt_stream) [USE_AMD64]: Process large buffers in AMD64 + implementation. + (salsa20_do_encrypt_stream): Move stack burning to this function... + (salsa20_encrypt_stream, salsa20r12_encrypt_stream): ...from these + functions. + * configure.ac [x86-64]: Add 'salsa20-amd64.lo'. + + Add new benchmarking utility, bench-slope. + + commit e214e8392671dd30e9c33260717b5e756debf3bf + * tests/Makefile.am (TESTS): Add 'bench-slope'. + * tests/bench-slope.c: New. + + Change .global to .globl in assembly files. + + commit ebc8abfcb09d6106fcfce40f240a513e276f46e9 + * cipher/blowfish-arm.S: Change '.global' to '.globl'. + * cipher/camellia-aesni-avx-amd64.S: Ditto. + * cipher/camellia-aesni-avx2-amd64.S: Ditto. + * cipher/camellia-arm.S: Ditto. + * cipher/cast5-amd64.S: Ditto. + * cipher/rijndael-amd64.S: Ditto. + * cipher/rijndael-arm.S: Ditto. + * cipher/serpent-avx2-amd64.S: Ditto. + * cipher/serpent-sse2-amd64.S: Ditto. + * cipher/twofish-amd64.S: Ditto. + * cipher/twofish-arm.S: Ditto. + +2013-10-26 Jussi Kivilinna + + Deduplicate code for ECB encryption and decryption. + + commit 51f1beab3d1e879942a95f58b08de7dbcce75dce + * cipher/cipher.c (do_ecb_crypt): New, based on old 'do_ecb_encrypt'. + (do_ecb_encrypt): Use 'do_ecb_crypt', pass encryption function. + (do_ecb_decrypt): Use 'do_ecb_crypt', pass decryption function. + +2013-10-26 Dmitry Eremin-Solenikov + + Drop _gcry_cipher_ofb_decrypt as it duplicates _gcry_cipher_ofb_encrypt. + + commit d9431725952e40f201c7eda000d3c8511ebd5b33 + * cipher/cipher.c (cipher_decrypt): Use _gcry_cipher_ofb_encrypt for OFB + decryption. + * cipher/cipher-internal.h: Remove _gcry_cipher_ofb_decrypt declaration. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_decrypt): Remove. + (_gcry_cipher_ofb_encrypt): remove copying of IV to lastiv, it's + unused there. + +2013-10-25 Werner Koch + + tests: Add tests for mpi_cmp. + + commit 6c6d4810927de7310ae7bac61b4ff5467d7cb485 + * tests/mpitests.c (die): Modernize. + (fail): New. + (test_opaque, test_add, test_sub, test_mul): Use gcry_log_xx + (main): Return error count. + (test_cmp): New. + +2013-10-24 Werner Koch + + ecc: Change algorithm for Ed25519 x recovery. + + commit c630fd71b336eb9209e914d24dc1e26a34521882 + * cipher/ecc-eddsa.c (scanval): Add as temporary hack. + (_gcry_ecc_eddsa_recover_x): Use the algorithm from page 15 of the + paper. Return an error code. + (_gcry_ecc_eddsa_decodepoint): Take care of the error code. + * mpi/mpi-mul.c (gcry_mpi_mulm): Use truncated division. + + ecc: Refactor _gcry_ecc_eddsa_decodepoint. + + commit 1cf5699b6febab1ef9d300531acc2ee33a7df739 + * cipher/ecc-eddsa.c (_gcry_ecc_eddsa_decodepoint): Factor some code + out to .. + (_gcry_ecc_eddsa_recover_x): new. + +2013-10-24 Jussi Kivilinna + + ecc-gost: Add missing include. + + commit 9ce54e5b512418ddf45ce18f2cbd48cdced779f5 + * ecc-gost.c: Include "pubkey-internal.h". + +2013-10-23 Jussi Kivilinna + + Replace architecture specific fast_wipememory2 with generic. + + commit 54df6fcd806f8c150cffe6cc09925bb8b638bb5b + * src/g10lib.h (fast_wipememory2): Remove architecture specific + implementations and add generic implementation. + + Improve the speed of the cipher mode code. + + commit 293e93672fdabc829e35cc624c397276342bafe4 + * cipher/bufhelp.h (buf_cpy): New. + (buf_xor, buf_xor_2dst): If buffers unaligned, always jump to per-byte + processing. + (buf_xor_n_copy_2): New. + (buf_xor_n_copy): Use 'buf_xor_n_copy_2'. + * cipher/blowfish.c (_gcry_blowfish_cbc_dec): Avoid extra memory copy + and use new 'buf_xor_n_copy_2'. + * cipher/camellia-glue.c (_gcry_camellia_cbc_dec): Ditto. + * cipher/cast5.c (_gcry_cast_cbc_dec): Ditto. + * cipher/serpent.c (_gcry_serpent_cbc_dec): Ditto. + * cipher/twofish.c (_gcry_twofish_cbc_dec): Ditto. + * cipher/rijndael.c (_gcry_aes_cbc_dec): Ditto. + (do_encrypt, do_decrypt): Use 'buf_cpy' instead of 'memcpy'. + (_gcry_aes_cbc_enc): Avoid copying IV, use 'last_iv' pointer instead. + * cipher/cipher-cbc.c (_gcry_cipher_cbc_encrypt): Avoid copying IV, + update pointer to IV instead. + (_gcry_cipher_cbc_decrypt): Avoid extra memory copy and use new + 'buf_xor_n_copy_2'. + (_gcry_cipher_cbc_encrypt, _gcry_cipher_cbc_decrypt): Avoid extra + accesses to c->spec, use 'buf_cpy' instead of memcpy. + * cipher/cipher-ccm.c (do_cbc_mac): Ditto. + * cipher/cipher-cfb.c (_gcry_cipher_cfb_encrypt) + (_gcry_cipher_cfb_decrypt): Ditto. + * cipher/cipher-ctr.c (_gcry_cipher_ctr_encrypt): Ditto. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_encrypt) + (_gcry_cipher_ofb_decrypt): Ditto. + * cipher/cipher.c (do_ecb_encrypt, do_ecb_decrypt): Ditto. + + bufhelp: enable unaligned memory accesses for AArch64 (64-bit ARM) + + commit 2901a10dbf1264707debc8402546c07eeac60932 + * cipher/bufhelp.h [__aarch64__] (BUFHELP_FAST_UNALIGNED_ACCESS): Set + macro on AArch64. + +2013-10-23 Dmitry Eremin-Solenikov + + Enable assembler optimizations on earlier ARM cores. + + commit 2fd83faa876d0be91ab7884b1a9eaa7793559eb9 + * cipher/blowfish-armv6.S => cipher/blowfish-arm.S: adapt to pre-armv6 CPUs. + * cipher/blowfish.c: enable assembly on armv4/armv5 little-endian CPUs. + * cipher/camellia-armv6.S => cipher/camellia-arm.S: adapt to pre-armv6 CPUs. + * cipher/camellia.c, cipher-camellia-glue.c: enable assembly on armv4/armv5 + little-endian CPUs. + * cipher/cast5-armv6.S => cipher/cast5-arm.S: adapt to pre-armv6 CPUs. + * cipher/cast5.c: enable assembly on armv4/armv5 little-endian CPUs. + * cipher/rijndael-armv6.S => cipher/rijndael-arm.S: adapt to pre-armv6 CPUs. + * cipher/rijndael.c: enable assembly on armv4/armv5 little-endian CPUs. + * cipher/twofish-armv6.S => cipher/twofish-arm.S: adapt to pre-armv6 CPUs. + * cipher/twofish.c: enable assembly on armv4/armv5 little-endian CPUs. + + mpi: enable assembler on all arm architectures. + + commit 0b39fce7e3ce6761d6bd5195d093ec6857edb7c2 + * mpi/config.links: remove check for arm >= v6 + * mpi/armv6 => mpi/arm: rename directory to reflect that is is generic + enough + + Correct ASM assembly test in configure.ac. + + commit 10bf6a7e16ed193f90d2749970a420f00d1d3320 + * configure.ac: correct HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS test to + require neither ARMv6, nor thumb mode. Our assembly code works + perfectly even on ARMv4 now. + +2013-10-23 Werner Koch + + ecc: Refactor ecc.c. + + commit 164eb8c85d773ef4f0939115ec45f5e4b47c1700 + * cipher/ecc-ecdsa.c, cipher/ecc-eddsa.c, cipher/ecc-gost.c: New. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add new files. + * configure.ac (GCRYPT_PUBKEY_CIPHERS): Add new files. + * cipher/ecc.c (point_init, point_free): Move to ecc-common.h. + (sign_ecdsa): Move to ecc-ecdsa.c as _gcry_ecc_ecdsa_sign. + (verify_ecdsa): Move to ecc-ecdsa.c as _gcry_ecc_ecdsa_verify. + (sign_gost): Move to ecc-gots.c as _gcry_ecc_gost_sign. + (verify_gost): Move to ecc-gost.c as _gcry_ecc_gost_verify. + (sign_eddsa): Move to ecc-eddsa.c as _gcry_ecc_eddsa_sign. + (verify_eddsa): Move to ecc-eddsa.c as _gcry_ecc_eddsa_verify. + (eddsa_generate_key): Move to ecc-eddsa.c as _gcry_ecc_eddsa_genkey. + (reverse_buffer): Move to ecc-eddsa.c. + (eddsa_encodempi, eddsa_encode_x_y): Ditto. + (_gcry_ecc_eddsa_encodepoint, _gcry_ecc_eddsa_decodepoint): Ditto. + + mpi: Fix scanning of negative SSH formats and add more tests. + + commit 45f6e6268bfdc4b608beaba6b7086b2286e33c71 + * mpi/mpicoder.c (gcry_mpi_scan): Fix sign setting for SSH format. + * tests/t-convert.c (negative_zero): Test all formats. + (check_formats): Add tests for PGP and scan tests for SSH and USG. + + * src/gcrypt.h.in (mpi_is_neg): Fix macro. + + * mpi/mpi-scan.c (_gcry_mpi_getbyte, _gcry_mpi_putbyte): Comment out + these unused functions. + +2013-10-22 Jussi Kivilinna + + twofish: add ARMv6 assembly implementation. + + commit 98674fdaa30ab22a3ac86ca05d688b5b6112895d + * cipher/Makefile.am: Add 'twofish-armv6.S'. + * cipher/twofish-armv6.S: New. + * cipher/twofish.c (USE_ARMV6_ASM): New macro. + [USE_ARMV6_ASM] (_gcry_twofish_armv6_encrypt_block) + (_gcry_twofish_armv6_decrypt_block): New prototypes. + [USE_AMDV6_ASM] (twofish_encrypt, twofish_decrypt): Add. + [USE_AMD64_ASM] (do_twofish_encrypt, do_twofish_decrypt): Remove. + (_gcry_twofish_ctr_enc, _gcry_twofish_cfb_dec): Use 'twofish_encrypt' + instead of 'do_twofish_encrypt'. + (_gcry_twofish_cbc_dec): Use 'twofish_decrypt' instead of + 'do_twofish_decrypt'. + * configure.ac [arm]: Add 'twofish-armv6.lo'. + + mpi: allow building with clang on ARM. + + commit e67c67321ce240c93dd0fa2b21c649c0a8e233f7 + * mpi/longlong.h [__arm__] (add_ssaaaa, sub_ddmmss, umul_ppmm) + (count_leading_zeros): Do not cast assembly output arguments. + [__arm__] (umul_ppmm): Remove the extra '%' ahead of assembly comment. + [_ARM_ARCH >= 4] (umul_ppmm): Use correct inputs and outputs instead of + registers. + + serpent-amd64: do not use GAS macros. + + commit c7efaa5fe0ee92e321a7b49d56752cc12eb75fe0 + * cipher/serpent-avx2-amd64.S: Remove use of GAS macros. + * cipher/serpent-sse2-amd64.S: Ditto. + * configure.ac [HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS]: Do not check + for GAS macros. + + Add Counter with CBC-MAC mode (CCM) + + commit 335d9bf7b035815750b63a3a8334d6ce44dc4449 + * cipher/Makefile.am: Add 'cipher-ccm.c'. + * cipher/cipher-ccm.c: New. + * cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode'. + (_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt) + (_gcry_cipher_ccm_set_nonce, _gcry_cipher_ccm_authenticate) + (_gcry_cipher_ccm_get_tag, _gcry_cipher_ccm_check_tag) + (_gcry_cipher_ccm_set_lengths): New prototypes. + * cipher/cipher.c (gcry_cipher_open, cipher_encrypt, cipher_decrypt) + (_gcry_cipher_setiv, _gcry_cipher_authenticate, _gcry_cipher_gettag) + (_gcry_cipher_checktag, gry_cipher_ctl): Add handling for CCM mode. + * doc/gcrypt.texi: Add documentation for GCRY_CIPHER_MODE_CCM. + * src/gcrypt.h.in (gcry_cipher_modes): Add 'GCRY_CIPHER_MODE_CCM'. + (gcry_ctl_cmds): Add 'GCRYCTL_SET_CCM_LENGTHS'. + (GCRY_CCM_BLOCK_LEN): New. + * tests/basic.c (check_ccm_cipher): New. + (check_cipher_modes): Call 'check_ccm_cipher'. + * tests/benchmark.c (ccm_aead_init): New. + (cipher_bench): Add handling for AEAD modes and add CCM benchmarking. + + Add API to support AEAD cipher modes. + + commit 95654041f2aa62f71aac4d8614dafe8433d10f95 + * cipher/cipher.c (_gcry_cipher_authenticate, _gcry_cipher_checktag) + (_gcry_cipher_gettag): New. + * doc/gcrypt.texi: Add documentation for new API functions. + * src/visibility.c (gcry_cipher_authenticate, gcry_cipher_checktag) + (gcry_cipher_gettag): New. + * src/gcrypt.h.in, src/visibility.h: add declarations of these + functions. + * src/libgcrypt.defs, src/libgcrypt.vers: export functions. + +2013-10-22 NIIBE Yutaka + + ecc: Correct compliant key generation for Edwards curves. + + commit a5a277a9016ccb34f1858a65e0ed1791b2fc3db3 + * cipher/ecc.c: Add case for Edwards curves. + +2013-10-17 Werner Koch + + tests: Add test options to keygen. + + commit f7711e6eb5f02d03c74911f6f037ab28075e7c0d + * tests/keygen.c (usage): New. + (main): Print usage info. Allow running just one algo. + + mpi: Do not clear the sign of the mpi_mod result. + + commit 91e007606f1f6f8e1416c403fe809d47fddf9b1f + * mpi/mpi-mod.c (_gcry_mpi_mod): Remove sign setting. + + ecc: Put the curve name again into the output of gcry_pk_genkey. + + commit 4776dcd394ce59fa50d959921857b3427c5a63c8 + * cipher/ecc.c (ecc_generate): Use the correct var. Release + CURVE_FLAGS. + + ecc: Support Weierstrass curves in gcry_mpi_ec_curve_point. + + commit b22417158c50ec3a0b2ff55b4ade063b42a87e8f + * mpi/ec.c (_gcry_mpi_ec_curve_point): Support MPI_EC_WEIERSTRASS. + +2013-10-16 Jussi Kivilinna + + arcfour: more optimized version for non-i386 architectures. + + commit f9371c026aad09ff48746d22c8333746c886e773 + * cipher/arcfour.c (ARCFOUR_context): Reorder members. + (do_encrypt_stream) [!__i386__]: Faster implementation for non-i386. + (do_arcfour_setkey): Avoid modulo operations. + + Avoid void* pointer arithmetic. + + commit c89ab921ccfaefe6c4f6a724d01e0df41a1a381f + * tests/tsexp.c (check_extract_param): Cast void* pointers to char* + before doing arithmetics. + +2013-10-16 Dmitry Eremin-Solenikov + + ecc: Add support for GOST R 34.10-2001/-2012 signatures. + + commit 83902f1f1dbc8263a0c3f61be59cd2eb95293c97 + * src/cipher.h: define PUBKEY_FLAG_GOST + * cipher/ecc-curves.c: Add GOST2001-test and GOST2012-test curves + defined in standards. Typical applications would use either those + curves, or curves defined in RFC 4357 (will be added later). + * cipher/ecc.c (sign_gost, verify_gost): New. + (ecc_sign, ecc_verify): use sign_gost/verify_gost if PUBKEY_FLAG_GOST + is set. + (ecc_names): add "gost" for gost signatures. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist, + _gcry_pk_util_preparse_sigval): set PUBKEY_FLAG_GOST if gost flag + is present in s-exp. + * tests/benchmark.c (ecc_bench): also benchmark GOST signatures. + * tests/basic.c (check_pubkey): add two public keys from + GOST R 34.10-2012 standard. + (check_pubkey_sign_ecdsa): add two data sets to check gost signatures. + * tests/curves.c: correct N_CURVES as we now have 2 more curves. + + + Removed some comments from the new curve definitions in ecc-curves.c + to avoid line wrapping. Eventually we will develop a precompiler to + avoid parsing those hex strings. -wk + + Fix 256-bit ecdsa test key definition. + + commit 187b2bb541b985255aee262d181434a7cb4ae2e7 + * tests/basic.c (check_pubkey): fix nistp256 testing key declaration - + add missing comma. + +2013-10-16 Werner Koch + + sexp: Add function gcry_sexp_extract_param. + + commit a329b6abf00c990faf1986f9fbad7b4d71c13bcb + * src/gcrypt.h.in (_GCRY_GCC_ATTR_SENTINEL): New. + (gcry_sexp_extract_param): New. + * src/visibility.c (gcry_sexp_extract_param): New. + * src/visibility.h (gcry_sexp_extract_param): Add hack to detect + internal use. + * cipher/pubkey-util.c (_gcry_pk_util_extract_mpis): Move and split + into ... + * src/sexp.c (_gcry_sexp_vextract_param) + (_gcry_sexp_extract_param): this. Change all callers. Add support for buffer + descriptors and a path option/ + + * tests/tsexp.c (die, hex2buffer, hex2mpi, hex2mpiopa): New. + (cmp_mpihex, cmp_bufhex): New. + (check_extract_param): New. + +2013-10-16 NIIBE Yutaka + + mpi: mpi-pow improvement. + + commit 45aa6131e93fac89d46733b3436d960f35fb99b2 + * mpi/mpi-pow.c (gcry_mpi_powm): New implementation of left-to-right + k-ary exponentiation. + +2013-10-15 Werner Koch + + ecc: Support use of Ed25519 with ECDSA. + + commit 537969fbbb1104b8305a7edb331b7666d54eff2c + * src/cipher.h (PUBKEY_FLAG_ECDSA): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Add flag "ecdsa". + * cipher/ecc.c (verify_ecdsa, verify_eddsa): Remove some debug output. + (ecc_generate, ecc_sign, ecc_verify): Support Ed25519 with ECDSA. + * tests/keygen.c (check_ecc_keys): Create such a test key. + * tests/pubkey.c (fail, info, data_from_hex, extract_cmp_data): New. + Take from dsa-6979.c + (check_ed25519ecdsa_sample_key): new. + (main): Call new test. + +2013-10-14 Werner Koch + + pubkey: Support flags list in gcry_pk_genkey. + + commit d3a605d7827b8a73ef844e9e5183590bd6b1389a + * src/cipher.h (PUBKEY_FLAG_TRANSIENT_KEY): New. + (PUBKEY_FLAG_USE_X931): New. + (PUBKEY_FLAG_USE_FIPS186): New. + (PUBKEY_FLAG_USE_FIPS186_2): New. + * cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Rename from + parse_flags_list. Parse new flags. + * cipher/dsa.c (dsa_generate): Support flag list. + * cipher/ecc.c (ecc_generate): Ditto. + * cipher/rsa.c (rsa_generate): Ditto. + + pubkey: Remove duplicated flag parsing code. + + commit 5be2345ddec4147e535d5b039ee74f84bcacf9e4 + * cipher/pubkey-util.c (_gcry_pk_util_preparse_encval) + (_gcry_pk_util_data_to_mpi): Factor flag parsing code out to .. + (parse_flag_list): New. + * src/cipher.h (PUBKEY_FLAG_RAW_FLAG): New. + + mpicalc: Accept lowercase hex digits. + + commit 0cd551faa775ad5309a40629ae30bf86b75fca09 + * src/mpicalc.c (main): Test for lowercase hex digits. + +2013-10-11 Werner Koch + + pubkey: Move sexp parsing of remaining fucntions to the modules. + + commit a951c061523e1c13f1358c9760fc3a9d787ab2d4 + * cipher/pubkey.c (release_mpi_array): Remove. + (pubkey_check_secret_key): Remove. + (sexp_elements_extract): Remove. + (sexp_elements_extract_ecc): Remove. + (sexp_to_key): Remove. + (get_hash_algo): Remove. + (gcry_pk_testkey): Revamp. + (gcry_pk_get_curve): Revamp. + * cipher/rsa.c (rsa_check_secret_key): Revamp. + * cipher/elgamal.c (elg_check_secret_key): Revamp. + * cipher/dsa.c (dsa_check_secret_key): Revamp. + * cipher/ecc.c (ecc_check_secret_key): Revamp. + * cipher/ecc-curves.c: Include cipher.h and pubkey-internal.h + (_gcry_ecc_get_curve): Revamp. + + * cipher/pubkey-util.c (_gcry_pk_util_extract_mpis): Set passed and + used parameters on error to NULL. + + pubkey: Move sexp parsing for gcry_pk_decrypt to the modules. + + commit 07950c865a901afc48acb46f0695040cadfd5068 + * cipher/rsa.c (rsa_decrypt): Revamp. + * cipher/elgamal.c (elg_decrypt): Revamp. + * cipher/ecc.c (ecc_decrypt_raw): Revamp. + * cipher/pubkey.c (gcry_pk_decrypt): Simplify. + (sexp_to_enc): Remove. + * cipher/pubkey-util.c (_gcry_pk_util_preparse_encval): New. + + pubkey: Move sexp parsing for gcry_pk_encrypt to the modules. + + commit 6bd5d18c45a4a3ce8f0f66f56c83b80594877f53 + * cipher/rsa.c (rsa_encrypt): Revamp. + * cipher/elgamal.c (elg_encrypt): Revamp. + * cipher/ecc.c (ecc_encrypt_raw): Revamp. + * cipher/pubkey.c (gcry_pk_encrypt): Simplify. + + * tests/basic.c (check_pubkey_crypt): Init plain, ciph, and data so + that they are initialized even after an encrypt failure. + + pubkey: Move sexp parsing for gcry_pk_sign to the modules. + + commit d0ae6635e4e6ae273c3a137c513d518f28f6eab3 + * cipher/rsa.c (rsa_sign): Revamp. + * cipher/dsa.c (dsa_sign): Revamp. + * cipher/elgamal.c (elg_sign): Revamp. + * cipher/ecc.c (ecc_sign): Revamp. + * cipher/pubkey.c (gcry_pk_sign): Simplify. + +2013-10-10 Jussi Kivilinna + + Prevent tail call optimization with _gcry_burn_stack. + + commit 150c0313f971bcea62d2802f0389c883e11ebb31 + * configure.ac: New check, HAVE_GCC_ASM_VOLATILE_MEMORY. + * src/g10lib.h (_gcry_burn_stack): Rename to __gcry_burn_stack. + (__gcry_burn_stack_dummy): New. + (_gcry_burn_stack): New macro. + * src/misc.c (_gcry_burn_stack): Rename to __gcry_burn_stack. + (__gcry_burn_stack_dummy): New. + +2013-10-09 Werner Koch + + pubkey: Move sexp parsing for gcry_pk_verify to the modules. + + commit 94b652ecb006c29fa2ffb1badc9f02b758581737 + * cipher/rsa.c (rsa_verify): Revamp. + * cipher/dsa.c (dsa_verify): Revamp. + * cipher/elgamal.c (elg_verify): Revamp. + * cipher/ecc.c (ecc_verify): Revamp. + * cipher/pubkey.c (sexp_to_sig): Remove. + (pss_verify_cmp): Move to pubkey-util.c + (sexp_data_to_mpi): Ditto. + (init_encoding_ctx): Ditto. + (gcry_pk_verify): Simplify. + * cipher/pubkey-util.c (_gcry_pk_util_init_encoding_ctx): Add. Take + from pubkey.c + (get_hash_algo): Ditto. + (_gcry_pk_util_data_to_mpi): Ditto. + (pss_verify_cmp): Ditto. + (_gcry_pk_util_extract_mpis): New. + (_gcry_pk_util_preparse_sigval): New. + (_gcry_pk_util_free_encoding_ctx): New. + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Make curve init + optional. + + * src/g10lib.h (GCC_ATTR_SENTINEL): New. + + * tests/basic.c (check_pubkey_sign): Print the algo name. + (main): Add option --pubkey. + +2013-10-08 Werner Koch + + pubkey: Move sexp parsing for gcry_pk_get_nbits to the modules. + + commit 4645f3728bb0900591b0aef85831fdee52c59e3c + * cipher/pubkey.c (spec_from_sexp): New. + (gcry_pk_get_nbits): Simplify. + * cipher/rsa.c (rsa_get_nbits): Take only PARMS as args and do sexp + parsing here. + * cipher/dsa.c (dsa_get_nbits): Ditto. + * cipher/elgamal.c (elg_get_nbits): Ditto. + * cipher/ecc.c (ecc_get_nbits): Ditto. + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Allow NULL for arg + CURVE. + + pubkey: Move sexp parsing for gcry_pk_getkey to the modules. + + commit 3816e46ce211e63adf46dbc775510aa137572248 + * cipher/pubkey-util.c: New. + (_gcry_pk_util_get_nbits): New. Based on code from gcry_pk_genkey. + (_gcry_pk_util_get_rsa_use_e): Ditto. + * cipher/pubkey.c (gcry_pk_genkey): Strip most code and pass. + * cipher/rsa.c (rsa_generate): Remove args ALGO, NBITS and EVALUE. + Call new fucntions to get these values. + * cipher/dsa.c (dsa_generate): Remove args ALGO, NBITS and EVALUE. + Call _gcry_pk_util_get_nbits to get nbits. Always parse genparms. + * cipher/elgamal.c (elg_generate): Ditto. + * cipher/ecc.c (ecc_generate): Ditto. + + cipher: Deprecate GCRY_PK_ELG_E. + + commit f79d3e13d3229115c47cbe5007647cb44105fe3f + * cipher/elgamal.c (_gcry_pubkey_spec_elg_e): Remove. + * cipher/pubkey.c (pubkey_list): Remove double included + _gcry_pubkey_spec_elg. + (map_algo): MAke ELG_E to ELG. + +2013-10-02 Werner Koch + + Provide Pth compatiblity for use with GnuPG 2.0. + + commit 2f767f6a17f7e99da4075882f7fe3ca597b31bdb + * src/ath.c (ath_install): Call ath_init and declare Pth as + compatible. + +2013-10-02 Jussi Kivilinna + + sha512: fix building on ARM. + + commit 6410152338a2b2ac1216e70c153cd16f9199c94e + * cipher/sha512.c (transform) [USE_ARM_NEON_ASM]: Fix 'hd' to 'ctx'. + +2013-10-02 Werner Koch + + Remove deprecated control codes. + + commit f04a1db22d982627ba87da4e5df52df9b994c779 + * src/gcrypt.h.in (GCRYCTL_SET_KEY): Remove. + (GCRYCTL_SET_IV): Remove. + (GCRYCTL_SET_CTR): Remove. + * cipher/md.c (gcry_md_ctl): Remove deprecated GCRYCTL_SET_KEY. + * cipher/cipher.c (gcry_cipher_ctl): Remove deprecated + GCRYCTL_SET_KEY, GCRYCTL_SET_IV, GCRYCTL_SET_CTR. + +2013-10-02 Dmitry Eremin-Solenikov + + Fix errors when building with Clang on PPC. + + commit 33757c1e03f1d885920633edf543cd1c77999455 + * mpi/longlong.h (add_ssaaaa, sub_ddmmss, count_leading_zeros, + umul_ppmm): Do not cast asm output to USItype. + +2013-10-02 Werner Koch + + Remove last remains of the former module system. + + commit 628ed5ba0ef4b1f04b5a77e29e4bc49a1fe13c07 + * src/gcrypt-module.h, src/module.c: Remove. + * src/visibility.h: Do not include gcrypt-module.h. + * src/g10lib.h: Remove all prototypes from module.c + (gcry_module): Remove. + * cipher/cipher-internal.h (gcry_cipher_handle): Remove unused field. + + Fix missing prototype warning in visibility.c. + + commit 52783d483293d48cd468143ae6ae2cccbfe17200 + * src/ec-context.h (_gcry_mpi_ec_new): Move prototype to mpi.h. + + md: Simplify the message digest dispatcher md.c. + + commit 0d39997932617ba20656f8bcc230ba744b76c87e + * src/gcrypt-module.h (gcry_md_spec_t): Move to ... + * src/cipher-proto.h: here. Merge with md_extra_spec_t. Add fields + ALGO and FLAGS. Set these fields in all digest modules. + * cipher/md.c: Change most code to replace the former module + system by a simpler system to gain information about the algorithms. + +2013-10-01 Werner Koch + + cipher: Simplify the cipher dispatcher cipher.c. + + commit 3ca180b25e8df252fc16f802cfdc27496e307830 + * src/gcrypt-module.h (gcry_cipher_spec_t): Move to ... + * src/cipher-proto.h (gcry_cipher_spec_t): here. Merge with + cipher_extra_spec_t. Add fields ALGO and FLAGS. Set these fields in + all cipher modules. + * cipher/cipher.c: Change most code to replace the former module + system by a simpler system to gain information about the algorithms. + (disable_pubkey_algo): Simplified. Not anymore thread-safe, though. + + * cipher/md.c (_gcry_md_selftest): Use correct structure. Not a real + problem because both define the same function as their first field. + + * cipher/pubkey.c (_gcry_pk_selftest): Take care of the disabled flag. + + mpi: Fix gcry_mpi_neg. + + commit 4153fa859816e799e506055321a22e6450aacdcc + * mpi/mpiutil.c (_gcry_mpi_neg): Copy U to W. + +2013-10-01 Peter Wu + + cipher: Add support for 128-bit keys in RC2. + + commit 738177ec0eae05069ec61bc4f724a69d4e052e42 + * cipher/rfc2268.c (oids_rfc2268_128): New + (_gcry_cipher_spec_rfc2268_128): New. + * cipher/cipher.c (cipher_table_entry): Add GCRY_CIPHER_RFC2268_128. + +2013-09-30 Werner Koch + + ecc: Use faster b parameter for Ed25519. + + commit 1d85452412b65e7976bc94969fc513ff6b880ed8 + * cipher/ecc-curves.c (domain_parms): Replace b. + * tests/t-mpi-point.c (test_curve): Ditto. + + ecc: Prepare for future Ed25519 optimization. + + commit a2618c822e666d4121cba29bee3fd50bf70c9743 + * mpi/ec-ed25519.c: New but empty file. + * mpi/ec-internal.h: New. + * mpi/ec.c: Include ec-internal.h. + (ec_mod): New. + (ec_addm): Use ec_mod. + (ec_mulm): Remove commented code. Use ec_mod. + (ec_subm): Call simple sub. + (ec_pow2): Use ec_mulm. + (ec_mul2): New. + (dup_point_weierstrass): Use ec_mul2. + (dup_point_twistededwards): Add special case for a == -1. Use + ec_mul2. + (add_points_weierstrass): Use ec_mul2. + (add_points_twistededwards): Add special case for a == -1. + (_gcry_mpi_ec_curve_point): Ditto. + (ec_p_init): Add hack to test Barrett functions. + * src/ec-context.h (mpi_ec_ctx_s): Add P_BARRETT. + + * mpi/mpi-mod.c (_gcry_mpi_mod_barrett): Fix sign problem. + + ecc: Fix recomputing of Q for Ed25519. + + commit c325adb8f5092b80a626bd3bb5e49cf7f3a29fc8 + * cipher/ecc-misc.c (reverse_buffer): New. + (_gcry_ecc_compute_public): Add ED255519 specific code. + * cipher/ecc.c (sign_eddsa): Allocate DIGEST in secure memory. Get + rid of HASH_D. + * tests/t-mpi-point.c (context_param): Test recomputing of Q for + Ed25519. + + log: Try to print s-expressions in a more compact format. + + commit d69a13d3d1c14ad6a6aa7cd349d6d2dfb152d422 + * src/misc.c (count_closing_parens): New. + (_gcry_log_printsxp): Use new function. + * mpi/ec.c (_gcry_mpi_point_log): Take care of a NULL point. + +2013-09-30 Jussi Kivilinna + + Make Whirlpool use the _gcry_md_block_write helper. + + commit 68cefd0f1d60ac33b58031df9b1d165cb1bf0f14 + * cipher/whirlpool.c (whirlpool_context_t): Add 'bctx', remove + 'buffer', 'count' and 'nblocks'. + (whirlpool_init): Initialize 'bctx'. + (whirlpool_transform): Adjust context argument type and burn stack + depth. + (whirlpool_add): Remove. + (whirlpool_write): Use _gcry_md_block_write. + (whirlpool_final, whirlpool_read): Adjust for 'bctx' usage. + + whirlpool: add stack burning after transform. + + commit a96d622e1a36d40d1504b7ada567e90ec9957443 + * cipher/whirlpool.c (whirlpool_transform): Return burn stack depth. + (whirlpool_add): Do burn_stack. + + whirlpool: do bitcount calculation in finalization part. + + commit 10d7351411f19bb2c03d2e24ca5a38dabe45023b + * cipher/whirlpool.c (whirlpool_context_t): Remove 'length', add + 'nblocks'. + (whirlpool_add): Update 'nblocks' instead of 'length', and add early + return at one spot. + (whirlpool_write): Check for 'nblocks' overflow. + (whirlpool_final): Convert 'nblocks' to bit-counter, and use + whirlpool_write instead of whirlpool_add. + +2013-09-30 Werner Koch + + Add logging functions to the API. + + commit d2076f27bb7c5d505abf25fc622d21794c4a5df3 + * src/gcrypt.h.in (_GCRY_GCC_ATTR_PRINTF): New. + (gcry_log_debug, gcry_log_debughex, gcry_log_debugmpi): New. + (gcry_log_debugpnt, gcry_log_debugsxp): New. + * src/visibility.c (gcry_log_debug): New. + (gcry_log_debughex, gcry_log_debugmpi, gcry_log_debugpnt): New. + (gcry_log_debugsxp): New. + * src/libgcrypt.def, src/libgcrypt.vers: Add new functions. + * src/misc.c (_gcry_logv): Make public. + (_gcry_log_printsxp): New. + * src/g10lib.h (log_printsxp): New macro. + +2013-09-26 Jussi Kivilinna + + Make libgcrypt build with Clang on i386. + + commit db60d828137c4f3682ca4ca2a54fe3d96d3db5f9 + * cipher/longlong.h [__i386__] (add_ssaaaa, sub_ddmmss) + (umul_ppmm, udiv_qrnnd): Do not cast asm output to USItype. + +2013-09-25 Werner Koch + + mpi: Change not yet used _gcry_mpi_set_opaque_copy. + + commit 1c6660debdbf1e4c3e80074c846a3e3097f214bb + * mpi/mpiutil.c (_gcry_mpi_set_opaque_copy): Change prototype. + (_gcry_mpi_get_opaque_copy): Take care of gcry_malloc failure. + + sexp: Improve printing of data with a leading zero. + + commit 9b7c49971588edf6acfc74bfb797eb79d19cb350 + * src/sexp.c (suitable_encoding): Detect leading zero byte. + + ecc: Allow the name "q@eddsa" to get/set the public key. + + commit d6683d2a6065986a9198d2d2eaa02c005b68cea4 + * cipher/ecc-curves.c (_gcry_ecc_get_mpi): Support "q@eddsa". + (_gcry_ecc_set_mpi): Support "q". + * cipher/ecc.c (eddsa_encodepoint): Rename to ... + (_gcry_ecc_eddsa_encodepoint): this and make global. Remove arg + MINLEN and take from context. + (eddsa_decodepoint): Rename to + (_gcry_ecc_eddsa_decodepoint): this and make global. Remove arg LEN + and take from context. + (sign_eddsa, verify_eddsa): Take B from context. + (ecc_sign, ecc_verify): Add hack to set DIALECT. + (_gcry_pk_ecc_get_sexp): Use _gcry_ecc_compute_public. Handle EdDSA. + * src/ec-context.h (mpi_ec_ctx_s): Add field NBITS. + * mpi/ec.c (ec_p_init): Init NBITS. + * tests/t-mpi-point.c (test_curve): Add Ed25519. + (sample_ed25519_q): New. + (context_param): Check new sample key. + (hex2buffer, hex2mpiopa): New. + (cmp_mpihex): Take care of opaque MPIs. + + mpicalc: Add statement to compute the number of bits. + + commit 9a4447ccd1b90bcd701941e80a7f484a1825fcea + * src/mpicalc.c (do_nbits): New. + (main): Add statement 'b'. + + ecc: Refactor low-level access functions. + + commit 64a7d347847d606eb5f4c156e24ba060271b8f6b + * mpi/ec.c (point_copy): Move to cipher/ecc-curves.c. + (ec_get_reset): Rename to _gcry_mpi_ec_get_reset and make global. + (_gcry_mpi_ec_get_mpi): Factor most code out to _gcry_ecc_get_mpi. + (_gcry_mpi_ec_get_point): Factor most code out to _gcry_ecc_get_point. + (_gcry_mpi_ec_set_mpi): Factor most code out to _gcry_ecc_set_mpi. + (_gcry_mpi_ec_set_point): Factor most code out to _gcry_ecc_set_point. + * cipher/ecc-curves.c (_gcry_ecc_get_mpi): New. + (_gcry_ecc_get_point, _gcry_ecc_set_mpi, _gcry_ecc_set_point): New. + * cipher/ecc-misc.c (_gcry_ecc_compute_public): New. + + ecc: Fix highly unlikely endless loop in sign_ecdsa. + + commit 1f5f4452e5bca105ec2197a4facbf9778e7dc31e + * cipher/ecc.c (sign_ecdsa): Turn while-do into do-while loops. + +2013-09-24 Werner Koch + + ecc: Allow the use of an uncompressed public key. + + commit df013c9820709421ef9550158ac5df0060d73379 + * cipher/ecc.c (eddsa_encodepoint): Factor most code out to ... + (eddsa_encode_x_y): new fucntion. + (eddsa_decodepoint): Allow use of an uncompressed public key. + * tests/t-ed25519.c (N_TESTS): Adjust. + * tests/t-ed25519.inp: Add test 1025. + +2013-09-23 Werner Koch + + pk: Add algo id GCRY_PK_ECC and deprecate ECDSA and ECDH. + + commit d5f91466695c5736f441c9bf1998436184a4bf61 + * src/gcrypt.h.in (GCRY_PK_ECC): New. + * cipher/pubkey.c (map_algo): New. + (spec_from_algo, gcry_pk_get_param, _gcry_pk_selftest): Use it. + * cipher/ecc.c (selftests_ecdsa): Report using GCRY_PK_ECC. + (run_selftests): Simplify. + (ecdh_names, ecdsa_names): Merge into a new ecc_names. + (_gcry_pubkey_spec_ecdh, _gcry_pubkey_spec_ecdsa): Merge into new + _gcry_pubkey_spec_ecc. + + ec: Use mpi_mulm instead of mpi_powm. + + commit 4552437bb3c5ff96a889fd31e4bc504b2a12fac7 + * mpi/ec.c (ec_pow2): New. + (ec_powm): Remove call to mpi_abs. + (dup_point_weierstrass, dup_point_twistededwards) + (add_points_weierstrass, add_points_twistededwards) + (_gcry_mpi_ec_curve_point): Use ec_pow2. + +2013-09-21 Jussi Kivilinna + + bufhelp: enable fast unaligned memory accesses on powerpc. + + commit 925d4fb3e8f2df3c5566ec6b5df7620a3d3504e5 + * cipher/bufhelp.h [__powerpc__] (BUFHELP_FAST_UNALIGNED_ACCESS): Set + macro enabled. + [__powerpc64__] (BUFHELP_FAST_UNALIGNED_ACCESS): Ditto. + + Remove i386 inline assembly version of rotation functions. + + commit cfea5c28a3822e1e7e401e5107ebe07ba7fdcf37 + * cipher/bithelp.h (rol, ror): Remove i386 version, change + macros to inline functions. + * src/hmac256.c (ror): Ditto. + + Optimize and cleanup 32-bit and 64-bit endianess transforms. + + commit 9337e03824a5bdd3bbbcb8382cabefe6d6c32e1e + * cipher/bithelp.h (bswap32, bswap64, le_bswap32, be_bswap32) + (le_bswap64, be_bswap64): New. + * cipher/bufhelp.h (buf_get_be32, buf_get_le32, buf_put_le32) + (buf_put_be32, buf_get_be64, buf_get_le64, buf_put_be64) + (buf_put_le64): New. + * cipher/blowfish.c (do_encrypt_block, do_decrypt_block): Use new + endian conversion helpers. + (do_bf_setkey): Turn endian specific code to generic. + * cipher/camellia.c (GETU32, PUTU32): Use new endian conversion + helpers. + * cipher/cast5.c (rol): Remove, use rol from bithelp. + (F1, F2, F3): Fix to use rol from bithelp. + (do_encrypt_block, do_decrypt_block, do_cast_setkey): Use new endian + conversion helpers. + * cipher/des.c (READ_64BIT_DATA, WRITE_64BIT_DATA): Ditto. + * cipher/md4.c (transform, md4_final): Ditto. + * cipher/md5.c (transform, md5_final): Ditto. + * cipher/rmd160.c (transform, rmd160_final): Ditto. + * cipher/salsa20.c (LE_SWAP32, LE_READ_UINT32): Ditto. + * cipher/scrypt.c (READ_UINT64, LE_READ_UINT64, LE_SWAP32): Ditto. + * cipher/seed.c (GETU32, PUTU32): Ditto. + * cipher/serpent.c (byte_swap_32): Remove. + (serpent_key_prepare, serpent_encrypt_internal) + (serpent_decrypt_internal): Use new endian conversion helpers. + * cipher/sha1.c (transform, sha1_final): Ditto. + * cipher/sha256.c (transform, sha256_final): Ditto. + * cipher/sha512.c (__transform, sha512_final): Ditto. + * cipher/stribog.c (transform, stribog_final): Ditto. + * cipher/tiger.c (transform, tiger_final): Ditto. + * cipher/twofish.c (INPACK, OUTUNPACK): Ditto. + * cipher/whirlpool.c (buffer_to_block, block_to_buffer): Ditto. + * configure.ac (gcry_cv_have_builtin_bswap32): Check for compiler + provided __builtin_bswap32. + (gcry_cv_have_builtin_bswap64): Check for compiler provided + __builtin_bswap64. + + gostr3411_94: set better burn stack depth estimate. + + commit 7409de7bc28ff8847c9d71d8c3e35e1968d59d60 + * cipher/gost28147.c (_gcry_gost_enc_one): Account function stack to + burn stack depth. + * cipher/gostr3411-94.c (max): New macro. + (do_hash_step, transform): Return stack burn depth. + + Use hash transform function return type for passing burn stack depth. + + commit 592c2ab3deeeccbb6d3b078ed7bf0e6627c8e1fb + * cipher/gostr4311-94.c (transform): Return stack burn depth. + * cipher/hash-common.c (_gcry_md_block_write): Use stack burn depth + returned by 'hd->bwrite'. + * cipher/hash-common.h (_gcry_md_block_write_t): Change return type to + 'unsigned int'. + (gry_md_block_ctx_t): Remove 'stack_burn'. + * cipher/md4.c (transform): Return stack burn depth. + (md4_final): Use stack burn depth from transform. + * cipher/md5.c (transform): Return stack burn depth. + (md5_final): Use stack burn depth from transform. + * cipher/rmd160.c (transform): Return stack burn depth. + (rmd160_final): Use stack burn depth from transform. + * cipher/sha1.c (transform): Return stack burn depth. + (sha1_final): Use stack burn depth from transform. + * cipher/sha256.c (transform): Return stack burn depth. + (sha256_final): Use stack burn depth from transform. + * cipher/sha512.c (__transform, transform): Return stack burn depth. + (sha512_final): Use stack burn depth from transform. + * cipher/stribog.c (transform64): Return stack burn depth. + * cipher/tiger.c (transform): Return stack burn depth. + (tiger_final): Use stack burn depth from transform. + + Make STRIBOG use the new _gcry_md_block_write helper. + + commit 902ea6052c11108bd19333c31b03e084bed1fb86 + * cipher/stribog.c (STRIBOG_STRUCT): Add 'bctx' and remove 'buf' and + 'count'. + (stribog_init_512): Initialize 'bctx'. + (transform64): New function. + (stribog_write): Remove. + (stribog_final): Use _gcry_md_block_write and bctx. + (_gcry_digest_spec_stribog_256, _gcry_digest_spec_stribog_512): Use + _gcry_md_block_write. + + Make SHA-512 use the new _gcry_md_block_write helper. + + commit cce7449efe471b076c5a97929ac8907162011394 + * cipher/hash-common.c (_gcry_md_block_write): Check that hd->buf is + large enough. + * cipher/hash-common.h (MD_BLOCK_MAX_BLOCKSIZE, MD_NBLOCKS_TYPE): New + macros. + (gcry_md_block_ctx_t): Use above macros for 'nblocks' and 'buf'. + * cipher/sha512.c (SHA512_STATE): New struct. + (SHA512_CONTEXT): Add 'bctx' and 'state'. + (sha512_init, sha384_init): Initialize 'bctx'. + (__transform, _gcry_sha512_transform_armv7_neon): Use SHA512_STATE for + 'hd'. + (transform): For now, do not return burn stack. + (sha512_write): Remove. + (sha512_final): Use _gcry_md_block_write and bctx. + (_gcry_digest_spec_sha512, _gcry_digest_spec_sha384): Use + _gcry_md_block_write. + +2013-09-20 Werner Koch + + sexp: Change internal versions to always use gpg_err_code_t. + + commit 3e5cfa20acfeccb9df2c3fae2730344b40b36104 + * src/sexp.c (gcry_sexp_new, gcry_sexp_create, gcry_sexp_build) + (gcry_sexp_build_array, gcry_sexp_canon_len): Change error return type + from gpg_error_t to gpg_err_code_t. Remove all calls to gpg_error. + * src/visibility.c (gcry_sexp_new, gcry_sexp_create, gcry_sexp_sscan) + (gcry_sexp_build, gcry_sexp_build_array, gcry_sexp_canon_len): Map + error codes via gpg_error. + * cipher/dsa.c, cipher/ecc.c, cipher/elgamal.c, cipher/rsa.c: Remove + use gpg_err_code wrappers. + + pk: Move s-exp creation for gcry_pk_decrypt to the modules. + + commit 722bfc1e5f2268453db62f38cc46b5ec6ef3adee + * cipher/pubkey.c (sexp_to_enc): Remove RET_MODERN arg and merge it + into FLAGS. + (gcry_pk_decrypt): Move result s-exp building into the modules. + * src/cipher-proto.h (gcry_pk_decrypt_t): Add some args. + * cipher/ecc.c (ecc_decrypt_raw): Change to return an s-exp. + * cipher/elgamal.c (elg_decrypt): Ditto. + * cipher/rsa.c (rsa_decrypt): Ditto. + (rsa_blind, rsa_unblind): Merge into rsa_decrypt. This saves several + extra MPI allocations. + + pk: Remove unused function. + + commit 64cd7ab93da7c95cc8aa320c61c6e29f9e2399c4 + * cipher/pubkey.c (_gcry_pk_aliased_algo_name): Remove + +2013-09-19 Werner Koch + + Beautify debug output of the prime generator. + + commit 6576f0a7684292cb5691bfcabad0acca4c06c014 + * cipher/primegen.c: Adjust output of log_mpidump to recently changed + log_mpidump code changes. + + pk: Move s-expr creation for genkey to the modules. + + commit 1bf08850bf9343146c938bc03917417e16393e9a + * cipher/pubkey.c (pubkey_generate): Fold into gcry_pk_genkey + (gcry_pk_genkey): Move result s-exp creation into the modules. + * cipher/dsa.c (dsa_generate): Create result as s-exp. + * cipher/elgamal.c (elg_generate): Ditto. + * cipher/rsa.c (rsa_generate): Ditto. + * cipher/ecc.c (ecc_generate): Ditto. + * src/cipher-proto.h (pk_ext_generate_t): Remove type + (gcry_pk_spec): and remove from struct. + + tests: Beautify some diagnostics. + + commit 2fe084873333c4d67bcfba0b527d63cd3cff6c47 + * tests/benchmark.c (ecc_bench): Print the key sexp in very verbose + mode. + (main): Add option --pk-count. + * tests/keygen.c: Add Elgamal generation and improved diagnostics. + * tests/t-ed25519.c (check_ed25519): Print running number of tests + done. + + sexp: Improve printing data representing a negative number. + + commit b3f3d47d347c14ed41d755cee580f000309b9c03 + * src/sexp.c (suitable_encoding): Detect a negative number. + + pk: Move RSA encoding functions to a new file. + + commit 071f70b9a766187fc70f6abc6a69d50752449285 + * cipher/rsa-common: New. + * cipher/pubkey.c (pkcs1_encode_for_encryption): Move to rsa-common.c + and rename to _gcry_rsa_pkcs1_encode_for_enc. + (pkcs1_decode_for_encryption): Move to rsa-common.c and rename to + _gcry_rsa_pkcs1_decode_for_enc. + (pkcs1_encode_for_signature): Move to rsa-common.c and rename to + _gcry_rsa_pkcs1_encode_for_sig. + (oaep_encode): Move to rsa-common.c and rename to + _gcry_rsa_oaep_encode. + (oaep_decode): Move to rsa-common.c and rename to + _gcry_rsa_oaep_decode. + (pss_encode): Move to rsa-common.c and rename to _gcry_rsa_pss_encode. + (pss_verify): Move to rsa-common.c and rename to _gcry_rsa_pss_decode. + (octet_string_from_mpi, mgf1): Move to rsa-common.c. + + pk: Move s-expr creation for sign and encrypt to the modules. + + commit eca9e2e50ddd4c9020fe1d4a9a3c77d20ebb90f6 + * cipher/pubkey.c (pubkey_encrypt): Fold into gcry_pk_encrypt. + (pubkey_decrypt): Fold into gcry_pk_decrypt. + (pubkey_sign): Fold into gcry_pk_sign. + (pubkey_verify): Fold into gcry_pk_verify. + (octet_string_from_mpi): Make it a wrapper and factor code out to ... + * mpi/mpicoder.c (_gcry_mpi_to_octet_string): New function. + + * src/cipher.h (PUBKEY_FLAG_FIXEDLEN): New. + * cipher/pubkey.c (sexp_data_to_mpi): Set flag for some encodings. + (gcry_pk_encrypt): Simply by moving the s-expr generation to the modules. + (gcry_pk_sign): Ditto. + * cipher/dsa.c (dsa_sign): Create s-expr. + * cipher/elgamal.c (elg_encrypt, elg_sign): Ditto. + * cipher/rsa.c (rsa_encrypt, rsa_sign): Ditto. + * cipher/ecc.c (ecc_sign, ecc_encrypt_raw): Ditto. + (ecdsa_names): Add "eddsa". + * tests/t-ed25519.c (one_test): Expect "eddsa" token. + +2013-09-19 Dmitry Eremin-Solenikov + + Fix Stribog digest on bigendian platforms. + + commit d399faf5db71d429bfd6fa4a9cfc82e2a55055f0 + * cipher/stribog.c (stribog_final): swap bytes in the result of digest + calculations. + +2013-09-18 Werner Koch + + pk: Simplify the public key dispatcher pubkey.c. + + commit 85722afb379f7a392a8117b895de273fd88c4ebc + * src/cipher-proto.h (gcry_pk_spec_t): Add fields ALGO and FLAGS. + * cipher/dsa.c (_gcry_pubkey_spec_dsa): Set these fields. + * cipher/ecc.c (_gcry_pubkey_spec_ecdsa): Ditto. + (_gcry_pubkey_spec_ecdh): Ditto. + * cipher/rsa.c (_gcry_pubkey_spec_rsa): Ditto. + * cipher/elgamal.c (_gcry_pubkey_spec_elg): Ditto + (_gcry_pubkey_spec_elg_e): New. + * cipher/pubkey.c: Change most code to replace the former module + system by a simpler system to gain information about the algorithms. + (disable_pubkey_algo): SImplified. Not anymore thread-safe, though. + + pk: Merge extraspecs struct with standard specs struct. + + commit 89103ce00e862cc709e80fa41f2ee13d54093ec5 + * src/gcrypt-module.h (gcry_pk_spec_t): Move this typedef and the + corresponding function typedefs to ... + * src/cipher-proto.h: here. + (pk_extra_spec_t): Remove typedef and merge fields into + gcry_pk_spec_t. + * cipher/rsa.c, cipher/dsa.c, cipher/elg.c, cipher/ecc.c: Ditto. + * cipher/pubkey.c: Change accordingly. + * src/cipher.h (_gcry_pubkey_extraspec_rsa): Remove. + (_gcry_pubkey_extraspec_dsa): Remove. + (_gcry_pubkey_extraspec_elg): Remove. + (_gcry_pubkey_extraspec_ecdsa): Remove. + +2013-09-18 Jussi Kivilinna + + Fix encryption/decryption return type for GOST28147. + + commit 2ad7ea9cb388fd31e4b0852b68d77f599ef4adce + * cipher/gost.h (_gcry_gost_enc_one): Change return type to + 'unsigned int'. + * cipher/gost28147.c (max): New macro. + (gost_encrypt_block, gost_decrypt_block): Return burn stack depth. + (_gcry_gost_enc_one): Return burn stack depth from gost_encrypt_block. + +2013-09-18 Dmitry Eremin-Solenikov + + doc: fix building of ps and pdf documentation. + + commit bd33fa21c9afc6c81e0da24016fc13001e9c7390 + * doc/gcrypt.texi, doc/gpl.texi, doc/lgpl.texi: fix texinfo errors. + + Add GOST R 34.11-2012 implementation (Stribog) + + commit c22064bdd773a807801e300aa9214b2fdcafcf20 + * src/gcrypt.h.in (GCRY_MD_GOSTR3411_12_256) + (GCRY_MD_GOSTR3411_12_512): New. + * cipher/stribog.c: New. + * configure.ac (available_digests_64): Add stribog. + * src/cipher.h: Declare Stribog declarations. + * cipher/md.c: Register Stribog digest. + * tests/basic.c (check_digests) Add 4 testcases for Stribog from + standard. + * doc/gcrypt.texi: Document new constants. + + Add basic implementation of GOST R 34.11-94 message digest. + + commit b0579baaa04fb91eabbbdc295bcabea04cf84056 + * src/gcrypt.h.in (GCRY_MD_GOSTR3411_94): New. + * cipher/gostr3411-94.c: New. + * configure.ac (available_digests): Add gostr3411-94. + * src/cipher.h: Add gostr3411-94 definitions. + * cipher/md.c: Register GOST R 34.11-94. + * tests/basic.c (check_digests): Add 4 tests for GOST R 34.11-94 + hash algo. Two are defined in the standard itself, two other are + more or less common tests - an empty string an exclamation mark. + * doc/gcrypt.texi: Add an entry describing GOST R 34.11-94 to the MD + algorithms table. + + Separate common md block code. + + commit ecde77ad98690540abb21db08e5531297ed72bd0 + * cipher/hash-common.c (_gcry_md_block_write): New function to handle + block md operations. The current implementation is limited to 64 byte + buffer and u32 block counter. + + * cipher/md4.c, cipher/md5.c, cipher/rmd.h, cipher/rmd160.c + *cipher/sha1.c, cipher/sha256.c, cipher/tiger.c: Convert to use + _gcry_md_block_write. + + Add limited implementation of GOST 28147-89 cipher. + + commit 56b5949f71f501744998f5ebc12488ebf6f1c0b5 + * src/gcrypt.h.in (GCRY_CIPHER_GOST28147): New. + * cipher/gost.h, cipher/gost28147.c: New. + * configure.ac (available_ciphers): Add gost28147. + * src/cipher.h: Add gost28147 definitions. + * cipher/cipher.c: Register gost28147. + * tests/basic.c (check_ciphers): Enable simple test for gost28147. + * doc/gcrypt.texi: document GCRY_CIPHER_GOST28147. + +2013-09-18 Werner Koch + + ecc: Add Ed25519 key generation and prepare for optimizations. + + commit 63cd3474425cb5a7ec4d1a56be15b248ecda4680 + * src/mpi.h (enum ecc_dialects): New. + * src/ec-context.h (mpi_ec_ctx_s): Add field DIALECT. + * cipher/ecc-common.h (elliptic_curve_t): Ditto. + * cipher/ecc-curves.c (ecc_domain_parms_t): Ditto. + (domain_parms): Add dialect values. + (_gcry_ecc_fill_in_curve): Set dialect. + (_gcry_ecc_get_curve): Ditto. + (_gcry_mpi_ec_new): Ditto. + (_gcry_ecc_get_param): Use ECC_DIALECT_STANDARD for now. + * cipher/ecc-misc.c (_gcry_ecc_curve_copy): Copy dialect. + (_gcry_ecc_dialect2str): New. + * mpi/ec.c (ec_p_init): Add arg DIALECT. + (_gcry_mpi_ec_p_internal_new): Ditto. + (_gcry_mpi_ec_p_new): Ditto. + + * mpi/mpiutil.c (gcry_mpi_set_opaque): Set the secure flag. + (_gcry_mpi_set_opaque_copy): New. + + * cipher/ecc-misc.c (_gcry_ecc_os2ec): Take care of an opaque MPI. + * cipher/ecc.c (eddsa_generate_key): New. + (generate_key): Rename to nist_generate_key and factor some code out + to ... + (ecc_generate_ext): here. Divert to eddsa_generate_key if desired. + (eddsa_decodepoint): Take care of an opaque MPI. + (ecc_check_secret_key): Ditto. + (ecc_sign): Ditto. + * cipher/pubkey.c (sexp_elements_extract_ecc): Store public and secret + key as opaque MPIs. + (gcry_pk_genkey): Add the curve_name also to the private key part of + the result. + + * tests/benchmark.c (ecc_bench): Support Ed25519. + (main): Add option --debug. + * tests/curves.c (sample_key_2): Make sure that P and N are positive. + * tests/keygen.c (show): New. + (check_ecc_keys): Support Ed25519. + +2013-09-17 Werner Koch + + mpi: Support printing of negative numbers. + + commit 89fe2173649a72019d75e059e6c6938efd10421f + * mpi/mpicoder.c (twocompl, onecompl): New. + (gcry_mpi_print): Use it for STD and SSH. + (gcry_mpi_scan): Use it for STD and SSH. Always set NSCANNED. + (gcry_mpi_aprint): Clear the extra allocated byte. + * tests/t-convert.c (showhex, showmpi): New. + (mpi2bitstr_nlz): New. + (check_formats): New. + (main): Call new test. + +2013-09-16 Werner Koch + + Fix bug in _gcry_mpi_tdiv_q_2exp. + + commit a7a9cdcaaf3979baa18dad51e722882581349f45 + * mpi/mpi-internal.h (MPN_COPY_INCR): Make it work. + + ecc: Implement Curve Ed25519 signing and verification. + + commit bc5199a02abe428ad377443280b3eda60141a1d6 + * cipher/ecc-curves.c (domain_parms): Add curve "Ed25519". + * cipher/ecc.c (reverse_buffer): New. + (eddsa_encodempi): New. + (eddsa_encodepoint): New. + (eddsa_decodepoint): New. + (sign_eddsa): Implement. + (verify_eddsa): Implement. + (ecc_sign): Init unused Q. Pass public key to sign_eddsa. + (ecc_verify): Init pk.Q if not used. Pass public key verbatim to + verify_eddsa. + * cipher/pubkey.c (sexp_elements_extract): Add arg OPAQUE. Change all + callers to pass 0. + (sexp_to_sig): Add arg OPAQUE and pass it to sexp_elements_extract. + (sexp_data_to_mpi): Allow for a zero length "value". + (gcry_pk_verify): Reorder parameter processing. Pass OPAQUE flag as + required. + * mpi/ec.c (ec_invm): Print a warning if the inverse does not exist. + (_gcry_mpi_ec_get_affine): Implement for our Twisted Edwards curve + model. + (dup_point_twistededwards): Implement. + (add_points_twistededwards): Implement. + (_gcry_mpi_ec_mul_point): Support Twisted Edwards. + + * mpi/mpicoder.c (do_get_buffer): Add arg FILL_LE. + (_gcry_mpi_get_buffer): Ditto. Change all callers. + (_gcry_mpi_get_secure_buffer): Ditto. + + * src/sexp.c (_gcry_sexp_nth_opaque_mpi): New. + + * tests/t-ed25519.c: New. + * tests/t-ed25519.inp: New. + * tests/t-mpi-point.c (basic_ec_math_simplified): Print some output + only in debug mode. + (twistededwards_math): New test. + (main): Call new test. + + mpi: Add internal convenience function. + + commit 44a2c34e90ed7de149952398787906d8823b636b + * mpi/mpiutil.c (_gcry_mpi_get_opaque_copy): New. + + mpi: Add debug function to print a point. + + commit 8ebc94d11a1eb93f2365c93f555e958700fdfbd4 + * mpi/ec.c (_gcry_mpi_point_log): New. + * src/mpi.h (log_printpnt): new macro. + + tests: Factor time measurement code out. + + commit 58eaf0c4332ac2f645ede28c4d18337389dfa753 + * tests/benchmark.c (started_at, stopped_at, start_timer, stop_timer) + (elapsed time): Factor out to .. + * tests/stopwatch.h: new file. + +2013-09-12 Werner Koch + + Fix _gcry_log_printmpi to print 00 instead of a sole sign. + + commit 1c76349c69c70a62b516a4f837c6287def640807 + * src/misc.c: Special case an mpi length of 0. + +2013-09-11 Werner Koch + + Streamline the use of the internal mpi and hex debug functions. + + commit e35ed615acc624a8b6c07576ea0650aac2bdb0db + * mpi/mpicoder.c (gcry_mpi_dump): Remove. + (_gcry_log_mpidump): Remove. + * src/misc.c (_gcry_log_printhex): Factor all code out to ... + (do_printhex): new. Add line wrapping a and compact printing. + (_gcry_log_printmpi): New. + * src/mpi.h (log_mpidump): Remove macro. + * src/g10lib.h (log_mpidump): Add compatibility macro. + (log_printmpi): New macro + * src/visibility.c (gcry_mpi_dump): Call _gcry_log_printmpi. + * cipher/primegen.c (prime_generate_internal): Replace gcry_mpi_dump + by log_printmpi. + (gcry_prime_group_generator): Ditto. + * cipher/pubkey.c: Remove extra colons from log_mpidump call. + * cipher/rsa.c (stronger_key_check): Use log_printmpi. + +2013-09-10 Werner Koch + + md: Add function gcry_md_hash_buffers. + + commit f3bca0c77c4979504f95fdbc618f7458e61e3e45 + * src/gcrypt.h.in (gcry_buffer_t): new. + (gcry_md_hash_buffers): New. + * src/visibility.c, src/visibility.h: Add wrapper for new function. + * src/libgcrypt.def, src/libgcrypt.vers: Export new function. + * cipher/md.c (gcry_md_hash_buffers): New. + * cipher/sha1.c (_gcry_sha1_hash_buffers): New. + * tests/basic.c (check_one_md_multi): New. + (check_digests): Run that test. + * tests/hmac.c (check_hmac_multi): New. + (main): Run that test. + + md: Fix Whirlpool flaw. + + commit 0a28b2d2c9181a536fc894e24626714832619923 + * cipher/whirlpool.c (whirlpool_add): Remove shortcut return so that + byte counter is always properly updated. + +2013-09-07 Jussi Kivilinna + + Fix static build on AMD64. + + commit 90fdf25f0dcc5feac7195ede55bd15948a11363e + * cipher/rijndael-amd64.S: Correct 'RIP' macro for non-PIC build. + + scrypt: fix for big-endian systems. + + commit 38a038a135d82231eff9d84f1ae3c4a25c6a5e75 + * cipher/scrypt.c (_salsa20_core): Fix endianess issues. + +2013-09-07 Werner Koch + + Use gcc "unused" attribute only with gcc >= 3.5. + + commit f7135e299e659d78906aac3dfdf30f380b5cf9c6 + * src/g10lib.h (GCC_ATTR_UNUSED): Fix gcc version detection. + +2013-09-07 Dmitry Eremin-Solenikov + + Add support for Salsa20/12 - 12 round version of Salsa20. + + commit ae6f6c47d2e0c536f3eab0823b5f23d26956cda2 + * src/gcrypt.h.in (GCRY_CIPHER_SALSA20R12): New. + * src/salsa20.c (salsa20_core, salsa20_do_encrypt_stream): Add support + for reduced round versions. + (salsa20r12_encrypt_stream, _gcry_cipher_spec_salsa20r12): Implement + Salsa20/12 - a 12 round version of Salsa20 selected by eStream. + * src/cipher.h: Declsare Salsa20/12 definition. + * cipher/cipher.c: Register Salsa20/12 + * tests/basic.c: (check_stream_cipher, check_stream_cipher_large_block): + Populate Salsa20/12 tests with test vectors from ecrypt + (check_ciphers): Add simple test for Salsa20/12 + +2013-09-07 Werner Koch + + Add configure option --disable-amd64-as-feature-detection. + + commit 49d5b9dcd622cdc87fb02a211bd51e3d46345bf2 + * configure.ac: Implement new disable flag. + + mpi: Improve support for non-Weierstrass support. + + commit 4d8c8c7aa88cddb1624301957e6245405f46d027 + * mpi/ec.c (ec_p_init): Add args MODEL and P. Change all callers. + (_gcry_mpi_ec_p_internal_new): Ditto. + (_gcry_mpi_ec_p_new): Ditto. + * cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Return + GPG_ERR_UNKNOWN_CURVE instead of invalid value. Init curve model. + * cipher/ecc.c (ecc_verify, ecc_encrypt_raw): Ditto. + * cipher/pubkey.c (sexp_data_to_mpi): Fix EDDSA flag error checking. + + mpi: Add gcry_mpi_ec_curve_point. + + commit ddfefe429660cc5d798f3517208936449247ae5c + * mpi/ec.c (_gcry_mpi_ec_curve_point): New. + (ec_powm): Return the absolute value. + * src/visibility.c, src/visibility.c: Add wrappers. + * src/libgcrypt.def, src/libgcrypt.vers: Export them. + + mpi: Add functions to manipulate the sign. + + commit 1bd2c67aa55b40589654d3fa5dea05cf1ed7dc5f + * src/gcrypt.h.in (gcry_mpi_is_neg): New. + (gcry_mpi_neg, gcry_mpi_abs): New. + * mpi/mpiutil.c (_gcry_mpi_is_neg): New. + (_gcry_mpi_neg, _gcry_mpi_abs): New. + * src/visibility.c, src/visibility.h: Add wrappers. + * src/libgcrypt.def, src/libgcrypt.vers: Export them. + * src/mpi.h (mpi_is_neg): New. Rename old macro to mpi_has_sign. + * mpi/mpi-mod.c (_gcry_mpi_mod_barrett): Use mpi_has_sign. + * mpi/mpi-mpow.c (calc_barrett): Ditto. + * cipher/primegen.c (_gcry_derive_x931_prime): Ditto + * cipher/rsa.c (secret): Ditto. + +2013-09-06 Jussi Kivilinna + + Tune armv6 mpi assembly. + + commit 4e4440153258e2f0dfdcaa8443820af06984ecb1 + * mpi/armv6/mpih-mul1.S: Tune assembly for Cortex-A8. + * mpi/armv6/mpih-mul2.S: Ditto. + * mpi/armv6/mpih-mul3.S: Ditto. + +2013-09-05 Jussi Kivilinna + + Change _gcry_burn_stack take burn depth as unsigned integer. + + commit e0ae31fcce3bd57b24751ff3c82cba820e493c3a + * src/misc.c (_gcry_burn_stack): Change to handle 'unsigned int' bytes. + + mpicalc: fix building on linux and win32. + + commit 50ec983666f0ca9d50c84aa1afad0d7bd5810779 + * src/Makefile.am (mpicalc): Adjust CFLAGS and LDADD. + +2013-09-04 Werner Koch + + Change mpicalc to use Libgcrypt and install it. + + commit 1d23040b659661b4086c079cb9fd5f37189a7020 + * src/mpicalc.c: Make use of gcry_ functions. + (MPICALC_VERSION): New. Set to 2.0. + (strusage): Remove. + (scan_mpi): New. Replaces mpi_fromstr. + (print_mpi): New. Replaces mpi_print. + (my_getc): New. + (print_help): New. + (main): Use simple option parser and print version info. + * src/Makefile.am (bin_PROGRAMS): Add mpicalc. + (mpicalc_SOURCES, mpicalc_CFLAGS, mpicalc_LDADD): New. + + Add mpicalc.c to help with testing. + + commit a70c46e29c480fa0f56ab4814666a5b115f84fd7 + * src/mpicalc.c: Take from GnuPG 1.4 + + Prepare support for EdDSA. + + commit c47d4001033f68212d2847b3074a0bdda990342e + * src/cipher.h (PUBKEY_FLAG_EDDSA): New. + * cipher/pubkey.c (pubkey_verify): Repalce args CMP and OPAQUEV by + CTX. Pass flags and hash algo to the verify function. Change all + verify functions to accept these args. + (sexp_data_to_mpi): Implement new flag "eddsa". + (gcry_pk_verify): Pass CTX instead of the compare function to + pubkey_verify. + * cipher/ecc.c (sign): Rename to sign_ecdsa. Change all callers. + (verify): Rename to verify_ecdsa. Change all callers. + (sign_eddsa, verify_eddsa): New stub functions. + (ecc_sign): Divert to sign_ecdsa or sign_eddsa. + (ecc_verify): Divert to verify_ecdsa or verify_eddsa. + + Prepare support for non-Weierstrass EC equations. + + commit c26be7a337d0bf98193bc58e043209e46d0769bb + * src/mpi.h (gcry_mpi_ec_models): New. + * src/ec-context.h (mpi_ec_ctx_s): Add MODEL. + * cipher/ecc-common.h (elliptic_curve_t): Ditto. + * cipher/ecc-curves.c (ecc_domain_parms_t): Ditto. + (domain_parms): Mark als as Weierstrass. + (_gcry_ecc_fill_in_curve): Check model. + (_gcry_ecc_get_curve): Set model to Weierstrass. + * cipher/ecc-misc.c (_gcry_ecc_model2str): New. + * cipher/ecc.c (generate_key, ecc_generate_ext): Print model in the + debug output. + + * mpi/ec.c (_gcry_mpi_ec_dup_point): Switch depending on model. + Factor code out to ... + (dup_point_weierstrass): new. + (dup_point_montgomery, dup_point_twistededwards): New stub functions. + (_gcry_mpi_ec_add_points): Switch depending on model. Factor code out + to ... + (add_points_weierstrass): new. + (add_points_montgomery, add_points_twistededwards): New stub + functions. + + * tests/Makefile.am (TESTS): Reorder tests. + + mpi: Suppress newer gcc warnings. + + commit 8698530b2f9ef95542f1dd550961de7af86cc256 + * src/g10lib.h (GCC_ATTR_UNUSED): Define for gcc >= 3.5. + * mpi/mpih-div.c (_gcry_mpih_mod_1, _gcry_mpih_divmod_1): Mark dummy + as unused. + * mpi/mpi-internal.h (UDIV_QRNND_PREINV): Mark _ql as unused. + + Do not check with cpp for typedefed constants. + + commit b28b1f732e1b4f9c62a9de87c22c6bb0d3f8fdb8 + * src/gcrypt-int.h: Include error code replacements depeding on the + version of libgpg-error. + +2013-09-04 Jussi Kivilinna + + Make _gcry_burn_stack use variable length array. + + commit 4b0edf53440239d3bcc95941980c062a0801a149 + * configure.ac (HAVE_VLA): Add check. + * src/misc.c (_gcry_burn_stack) [HAVE_VLA]: Add VLA code. + + Move stack burning from block ciphers to cipher modes. + + commit a3aaa6ad03388ea3eaa24304b604cb864633332f + * src/gcrypt-module.h (gcry_cipher_encrypt_t) + (gcry_cipher_decrypt_t): Return 'unsigned int'. + * cipher/cipher.c (dummy_encrypt_block, dummy_decrypt_block): Return + zero. + (do_ecb_encrypt, do_ecb_decrypt): Get largest stack burn depth from + block cipher crypt function and burn stack at end. + * cipher/cipher-aeswrap.c (_gcry_cipher_aeswrap_encrypt) + (_gcry_cipher_aeswrap_decrypt): Ditto. + * cipher/cipher-cbc.c (_gcry_cipher_cbc_encrypt) + (_gcry_cipher_cbc_decrypt): Ditto. + * cipher/cipher-cfb.c (_gcry_cipher_cfb_encrypt) + (_gcry_cipher_cfb_decrypt): Ditto. + * cipher/cipher-ctr.c (_gcry_cipher_cbc_encrypt): Ditto. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_encrypt) + (_gcry_cipher_ofb_decrypt): Ditto. + * cipher/blowfish.c (encrypt_block, decrypt_block): Return burn stack + depth. + * cipher/camellia-glue.c (camellia_encrypt, camellia_decrypt): Ditto. + * cipher/cast5.c (encrypt_block, decrypt_block): Ditto. + * cipher/des.c (do_tripledes_encrypt, do_tripledes_decrypt) + (do_des_encrypt, do_des_decrypt): Ditto. + * cipher/idea.c (idea_encrypt, idea_decrypt): Ditto. + * cipher/rijndael.c (rijndael_encrypt, rijndael_decrypt): Ditto. + * cipher/seed.c (seed_encrypt, seed_decrypt): Ditto. + * cipher/serpent.c (serpent_encrypt, serpent_decrypt): Ditto. + * cipher/twofish.c (twofish_encrypt, twofish_decrypt): Ditto. + * cipher/rfc2268.c (encrypt_block, decrypt_block): New. + (_gcry_cipher_spec_rfc2268_40): Use encrypt_block and decrypt_block. + +2013-09-01 Jussi Kivilinna + + camellia-aesni-avx2-amd64: Move register clearing to assembly functions. + + commit f3515240de9513ead975985c9f8ab714022cac8e + * cipher/camellia-aesni-avx2-amd64.S + (_gcry_camellia_aesni_avx2_ctr_enc): Add 'vzeroall'. + (_gcry_camellia_aesni_avx2_cbc_dec) + (_gcry_camellia_aesni_avx2_cfb_dec): Add 'vzeroupper' at head and + 'vzeroall' at tail. + * cipher/camellia-glue.c (_gcry_serpent_ctr_enc, _gcry_serpent_cbc_dec) + (_gcry_serpent_avx2_cfb_dec) [USE_AESNI_AVX2]: Remove register + clearing. + + camellia-aesni-avx-amd64: Move register clearing to assembly functions. + + commit 8b735cb563dff7aafbf8a970972522b5621e665c + * cipher/camellia-aesni-avx-amd64.S (_gcry_camellia_aesni_avx_ctr_enc) + (_gcry_camellia_aesni_avx_cbc_dec) + (_gcry_camellia_aesni_avx_cfb_dec): Add 'vzeroupper' at head and + 'vzeroall' at tail. + * cipher/camellia-glue.c (_gcry_serpent_ctr_enc, _gcry_serpent_cbc_dec) + (_gcry_serpent_avx2_cfb_dec) [USE_AESNI_AVX]: Remove register clearing. + + serpent-avx2-amd64: Move register clearing to assembly. + + commit d12828cd821a4b4428eae19de5aee02cf536e536 + * cipher/serpent-avx2-amd64.S (_gcry_serpent_avx2_ctr_enc) + (_gcry_serpent_avx2_cbc_dec, _gcry_serpent_avx2_cfb_dec): Change last + 'vzeroupper' to 'vzeroall'. + * cipher/serpent.c (_gcry_serpent_ctr_enc, _gcry_serpent_cbc_dec) + (_gcry_serpent_avx2_cfb_dec) [USE_AVX2]: Remove register clearing with + 'vzeroall'. + + Fix building for x32 target. + + commit fd6721c235a5bdcb332c8eb708fbd4f96e52e824 + * mpi/amd64/mpi-asm-defs.h: New file. + * random/rndhw.c (poll_padlock) [__x86_64__]: Also check if __LP64__ is + defined. + [USE_DRNG, __x86_64__]: Also check if __LP64__ is defined. + +2013-08-31 Jussi Kivilinna + + sha512: add ARM/NEON assembly version of transform function. + + commit 99d15543b8d94a8f1ef66c6ccb862b0ce82c514d + * cipher/Makefile.am: Add 'sha512-armv7-neon.S'. + * cipher/sha512-armv7-neon.S: New file. + * cipher/sha512.c (USE_ARM_NEON_ASM): New macro. + (SHA512_CONTEXT) [USE_ARM_NEON_ASM]: Add 'use_neon'. + (sha512_init, sha384_init) [USE_ARM_NEON_ASM]: Enable 'use_neon' if + CPU support NEON instructions. + (k): Round constant array moved outside of 'transform' function. + (__transform): Renamed from 'tranform' function. + [USE_ARM_NEON_ASM] (_gcry_sha512_transform_armv7_neon): New prototype. + (transform): New wrapper function for different transform versions. + (sha512_write, sha512_final): Burn stack by the amount returned by + transform function. + * configure.ac (sha512) [neonsupport]: Add 'sha512-armv7-neon.lo'. + + sha512: reduce stack use in transform function by 512 bytes. + + commit 03da7f8ba3ec24d4639a2bcebbc0d9d831734c08 + * cipher/sha512.c (transform): Change 'u64 w[80]' to 'u64 w[16]' and + inline input expansion to first 64 rounds. + (sha512_write, sha512_final): Reduce burn_stack depth by 512 bytes. + + Add ARM HW feature detection module and add NEON detection. + + commit 9c95be105f518d18407115c2c06893857c24b116 + * configure.ac: Add option --disable-neon-support. + (HAVE_GCC_INLINE_ASM_NEON): New. + (ENABLE_NEON_SUPPORT): New. + [arm]: Add 'hwf-arm.lo' as HW feature module. + * src/Makefile.am: Add 'hwf-arm.c'. + * src/g10lib.h (HWF_ARM_NEON): New macro. + * src/global.c (hwflist): Add HWF_ARM_NEON entry. + * src/hwf-arm.c: New file. + * src/hwf-common.h (_gcry_hwf_detect_arm): New prototype. + * src/hwfeatures.c (_gcry_detect_hw_features) [HAVE_CPU_ARCH_ARM]: Add + call to _gcry_hwf_detect_arm. + + Correct mpi_cpu_arch for ARMv6. + + commit 7b0ebe69fe35f2ee13e1e1beb2766a1eaadb7f0c + * mpi/config.links [armv6]: Set mpi_cpu_arch to "arm", instead of + "armv6". + +2013-08-30 Werner Koch + + mpi: Make gcry_mpi_print work with negative zeroes. + + commit e9b711e6ddb480a71d2996465074e436c752c005 + * mpi/mpicoder.c (gcry_mpi_print): Take care of negative zero. + (gcry_mpi_aprint): Allocate at least 1 byte. + * tests/t-convert.c: New. + * tests/Makefile.am (TESTS): Add t-convert. + + Refactor the ECC code into 3 files. + + commit 800d4e01376d52a94a157b53978c7c3f957fc476 + * cipher/ecc-common.h, cipher/ecc-curves.c, cipher/ecc-misc.c: New. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add new files. + * configure.ac (GCRYPT_PUBKEY_CIPHERS): Add new .c files. + * cipher/ecc.c (curve_aliases, ecc_domain_parms_t, domain_parms) + (scanval): Move to ecc-curves.c. + (fill_in_curve): Move to ecc-curve.c as _gcry_ecc_fill_in_curve. + (ecc_get_curve): Move to ecc-curve.c as _gcry_ecc_get_curve. + (_gcry_mpi_ec_ec2os): Move to ecc-misc.c. + (ec2os): Move to ecc-misc.c as _gcry_ecc_ec2os. + (os2ec): Move to ecc-misc.c as _gcry_ecc_os2ec. + (point_set): Move as inline function to ecc-common.h. + (_gcry_ecc_curve_free): Move to ecc-misc.c as _gcry_ecc_curve_free. + (_gcry_ecc_curve_copy): Move to ecc-misc.c as _gcry_ecc_curve_copy. + (mpi_from_keyparam, point_from_keyparam): Move to ecc-curves.c. + (_gcry_mpi_ec_new): Move to ecc-curves.c. + (ecc_get_param): Move to ecc-curves.c as _gcry_ecc_get_param. + (ecc_get_param_sexp): Move to ecc-curves.c as _gcry_ecc_get_param_sexp. + +2013-08-22 Jussi Kivilinna + + serpent-sse2-amd64: Move register clearing to assembly functions. + + commit 040aa7688296e93659cb32ca31e9a001a6ab1edd + cipher/serpent-sse2-amd64.S (_gcry_serpent_sse2_ctr_enc) + (_gcry_serpent_sse2_cbc_dec, _gcry_serpent_sse2_cfb_dec): Clear used + XMM registers. + cipher/serpent.c (_gcry_serpent_ctr_enc, _gcry_serpent_cbc_dec) + ( _gcry_serpent_cfb_dec) [USE_SSE2]: Remove XMM register clearing from + bulk functions. + + twofish-amd64: do not make __twofish_dec_blk3 global. + + commit 82db04a6a0058cf870485459abe7c1659b138ec5 + * cipher/twofish-amd64.S (__twofish_dec_blk3): Do not export symbol as + global. + (__twofish_dec_blk3): Mark symbol as function. + +2013-08-20 Jussi Kivilinna + + mpi: add ARMv6 assembly. + + commit da327aef3fe24fdf98fffbc8aea69de42ed12456 + * mpi/armv6/mpi-asm-defs.h: New. + * mpi/armv6/mpih-add1.S: New. + * mpi/armv6/mpih-mul1.S: New. + * mpi/armv6/mpih-mul2.S: New. + * mpi/armv6/mpih-mul3.S: New. + * mpi/armv6/mpih-sub1.S: New. + * mpi/config.links [arm]: Enable ARMv6 assembly. + + Move ARMv6 detection to configure.ac. + + commit 151f1e518be2d16bed748ba832384b0472ddcf9b + * cipher/blowfish-armv6.S: Replace __ARM_ARCH >= 6 checks with + HAVE_ARM_ARCH_V6. + * cipher/blowfish.c: Ditto. + * cipher/camellia-armv6.S: Ditto. + * cipher/camellia.h: Ditto. + * cipher/cast5-armv6.S: Ditto. + * cipher/cast5.c: Ditto. + * cipher/rijndael-armv6.S: Ditto. + * cipher/rijndael.c: Ditto. + * configure.ac: Add HAVE_ARM_ARCH_V6 check. + +2013-08-19 Jussi Kivilinna + + Add optimized wipememory for ARM. + + commit c030e33533fb819afe195eff5f89ec39863b1fbc + src/g10lib.h [__arm__] (fast_wipememory2_unaligned_head) + (fast_wipememory2): New macros. + + cipher: bufhelp: allow unaligned memory accesses on ARM. + + commit 796dda37b957b20dba391343937c6325a8c8b288 + * cipher/bufhelp.h [__arm__ && __ARM_FEATURE_UNALIGNED]: Enable + BUFHELP_FAST_UNALIGNED_ACCESS. + +2013-08-17 Jussi Kivilinna + + Remove burn_stack optimization. + + commit 79895b9459b9bf8c60cb7abf09d5bf16ed0cf6e3 + * src/misc.c (_gcry_burn_stack): Remove SIZEOF_UNSIGNED_LONG == 4 or 8 + optimization. + +2013-08-16 Jussi Kivilinna + + camellia: add ARMv6 assembly implementation. + + commit cafadc1e4fb97581262b0081ba251e05613d4394 + * cipher/Makefile.am: Add 'camellia-armv6.S'. + * cipher/camellia-armv6.S: New file. + * cipher/camellia-glue.c [USE_ARMV6_ASM] + (_gcry_camellia_armv6_encrypt_block) + (_gcry_camellia_armv6_decrypt_block): New prototypes. + [USE_ARMV6_ASM] (Camellia_EncryptBlock, Camellia_DecryptBlock) + (camellia_encrypt, camellia_decrypt): New functions. + * cipher/camellia.c [!USE_ARMV6_ASM]: Compile encryption and decryption + routines if USE_ARMV6_ASM macro is _not_ defined. + * cipher/camellia.h (USE_ARMV6_ASM): New macro. + [!USE_ARMV6_ASM] (Camellia_EncryptBlock, Camellia_DecryptBlock): If + USE_ARMV6_ASM is defined, disable these function prototypes. + (camellia) [arm]: Add 'camellia-armv6.lo'. + + blowfish: add ARMv6 assembly implementation. + + commit 31e4b1a96a07e9a3698fcb7be0643a136ebb8e5c + * cipher/Makefile.am: Add 'blowfish-armv6.S'. + * cipher/blowfish-armv6.S: New file. + * cipher/blowfish.c (USE_ARMV6_ASM): New macro. + [USE_ARMV6_ASM] (_gcry_blowfish_armv6_do_encrypt) + (_gcry_blowfish_armv6_encrypt_block) + (_gcry_blowfish_armv6_decrypt_block, _gcry_blowfish_armv6_ctr_enc) + (_gcry_blowfish_armv6_cbc_dec, _gcry_blowfish_armv6_cfb_dec): New + prototypes. + [USE_ARMV6_ASM] (do_encrypt, do_encrypt_block, do_decrypt_block) + (encrypt_block, decrypt_block): New functions. + (_gcry_blowfish_ctr_enc) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (_gcry_blowfish_cbc_dec) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (_gcry_blowfish_cfb_dec) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + * configure.ac (blowfish) [arm]: Add 'blowfish-armv6.lo'. + + cast5: add ARMv6 assembly implementation. + + commit 8d1faf56714598301580ce370e0bfa6d65e73644 + * cipher/Makefile.am: Add 'cast5-armv6.S'. + * cipher/cast5-armv6.S: New file. + * cipher/cast5.c (USE_ARMV6_ASM): New macro. + (CAST5_context) [USE_ARMV6_ASM]: New members 'Kr_arm_enc' and + 'Kr_arm_dec'. + [USE_ARMV6_ASM] (_gcry_cast5_armv6_encrypt_block) + (_gcry_cast5_armv6_decrypt_block, _gcry_cast5_armv6_ctr_enc) + (_gcry_cast5_armv6_cbc_dec, _gcry_cast5_armv6_cfb_dec): New prototypes. + [USE_ARMV6_ASM] (do_encrypt_block, do_decrypt_block, encrypt_block) + (decrypt_block): New functions. + (_gcry_cast5_ctr_enc) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (_gcry_cast5_cbc_dec) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (_gcry_cast5_cfb_dec) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (do_cast_setkey) [USE_ARMV6_ASM]: Initialize 'Kr_arm_enc' and + 'Kr_arm_dec'. + * configure.ac (cast5) [arm]: Add 'cast5-armv6.lo'. + +2013-08-14 Jussi Kivilinna + + rijndael: add ARMv6 assembly implementation. + + commit f365961422f1c8b3d89b8bcd9c99828f38c1f158 + * cipher/Makefile.am: Add 'rijndael-armv6.S'. + * cipher/rijndael-armv6.S: New file. + * cipher/rijndael.c (USE_ARMV6_ASM): New macro. + [USE_ARMV6_ASM] (_gcry_aes_armv6_encrypt_block) + (_gcry_aes_armv6_decrypt_block): New prototypes. + (do_encrypt_aligned) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (do_encrypt): Disable input/output alignment when USE_ARMV6_ASM. + (do_decrypt_aligned) [USE_ARMV6_ASM]: Use ARMv6 assembly function. + (do_decrypt): Disable input/output alignment when USE_ARMV6_ASM. + * configure.ac (HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS): New check for + gcc/as compatibility with ARM assembly implementations. + (aes) [arm]: Add 'rijndael-armv6.lo'. + +2013-08-09 NIIBE Yutaka + + cipher: fix memory leak. + + commit 2b5bbe264fcd61e5e458e5f71a6507ba0271c729 + * cipher/pubkey.c (gcry_pk_sign): Handle the specific case of ECC, + where there is NULL whichi is not the sentinel. + +2013-08-08 Werner Koch + + mpi: Clear immutable flag on the result of gcry_mpi_set. + + commit 426cbc9feca0c8f46208fb3670adab95f9e46087 + * mpi/mpiutil.c (gcry_mpi_set): Reset immutable and const flags. + * tests/mpitests.c (test_const_and_immutable): Add a test for this. + +2013-08-07 NIIBE Yutaka + + tests: fix memory leaks. + + commit cc082642c1b0f2a3e9ca78e1ffd3f64417c204bd + * tests/benchmark.c (dsa_bench): Release SIG. + + * tests/mpitests.c (test_powm): Release BASE, EXP, MOD, and RES. + + * tests/prime.c (check_primes): Release PRIME. + + * tests/tsexp.c (basic): Use intermediate variable M for constant. + Release S1, S2 and A. + +2013-08-07 Jussi Kivilinna + + Fix building on W32 (cannot export symbol 'gcry_sexp_get_buffer') + + commit 065d446478bf68553339fc77a89b8369bd110a18 + * src/libgcrypt.def: Change 'gcry_sexp_get_buffer' to + 'gcry_sexp_nth_buffer'. + +2013-08-06 NIIBE Yutaka + + cipher: fix another memory leak. + + commit 9a421813123a2f5db0a91eaee4a45138efc9ad34 + * cipher/ecc.c (ecc_get_curve): Free TMP. + + tests: fix memory leaks. + + commit 87eddc31ccba6decbddd1761dd42a208666cd311 + * tests/pubkey.c (check_keys_crypt): Release L, X0, and X1. + (check_keys): Release X. + + cipher: fix memory leaks. + + commit ae6ffd9af38cbcac57c220960f683aab91db85cb + * cipher/elgamal.c (elg_generate_ext): Free XVALUE. + + * cipher/pubkey.c (sexp_elements_extract): Don't use IDX for loop. + Call mpi_free. + (sexp_elements_extract_ecc): Call mpi_free. + +2013-08-05 Werner Koch + + mpi: Improve gcry_mpi_invm to detect bad input. + + commit d8e99a04dba6a606e879464cd11deee760d1e000 + * mpi/mpi-inv.c (gcry_mpi_invm): Return 0 for bad input. + +2013-07-31 Dmitry Eremin-Solenikov + + Correct checks for ecc secret key. + + commit 10dfa41b43a906031bc674ea41cd3073701011f3 + * cipher/ecc.c (check_secret_key): replace wrong comparison of Q and + sk->Q points with correct one. + +2013-07-29 Werner Koch + + sexp: Allow white space anywhere in a hex format. + + commit 43320961a8751ee28dc95cdb0ae01ea8a7ff7f91 + * src/sexp.c (hextobyte): Remove. + (hextonibble): New. + (vsexp_sscan): Skip whtespace between hex nibbles. + + Implement deterministic ECDSA as specified by rfc-6979. + + commit 6e0a9786637d649b48aae0e611a12e12beef9b3b + * cipher/ecc.c (sign): Add args FLAGS and HASHALGO. Convert an opaque + MPI as INPUT. Implement rfc-6979. + (ecc_sign): Remove the opaque MPI code and pass FLAGS to sign. + (verify): Do not allocate and compute Y; it is not used. + (ecc_verify): Truncate the hash value if needed. + * tests/dsa-rfc6979.c (check_dsa_rfc6979): Add ECDSA test cases. + +2013-07-26 Werner Koch + + Implement deterministic DSA as specified by rfc-6979. + + commit 1cfa79aabc5d0fd8d124901054475e90ab7d9cde + * cipher/dsa.c (dsa_sign): Move opaque mpi extraction to sign. + (sign): Add args FLAGS and HASHALGO. Implement deterministic DSA. + Add code path for R==0 to comply with the standard. + (dsa_verify): Left fill opaque mpi based hash values. + * cipher/dsa-common.c (int2octets, bits2octets): New. + (_gcry_dsa_gen_rfc6979_k): New. + * tests/dsa-rfc6979.c: New. + * tests/Makefile.am (TESTS): Add dsa-rfc6979. + + Allow the use of a private-key s-expression with gcry_pk_verify. + + commit b72d312ad11887fc416aa821786f6bdb663c0f4a + * cipher/pubkey.c (sexp_to_key): Fallback to private key. + +2013-07-25 Werner Koch + + Mitigate a flush+reload cache attack on RSA secret exponents. + + commit 287bf0e543f244d784cf8b58340bf0ab3c6aba97 + * mpi/mpi-pow.c (gcry_mpi_powm): Always perfrom the mpi_mul for + exponents in secure memory. + +2013-07-19 Werner Koch + + pk: Allow the use of a hash element for DSA sign and verify. + + commit 37d0a1ebdc2dc74df4fb6bf0621045018122a68f + * cipher/pubkey.c (pubkey_sign): Add arg ctx and pass it to the sign + module. + (gcry_pk_sign): Pass CTX to pubkey_sign. + (sexp_data_to_mpi): Add flag rfc6979 and code to alls hash with *DSA + * cipher/rsa.c (rsa_sign, rsa_verify): Return an error if an opaque + MPI is given for DATA/HASH. + * cipher/elgamal.c (elg_sign, elg_verify): Ditto. + * cipher/dsa.c (dsa_sign, dsa_verify): Convert a given opaque MPI. + * cipher/ecc.c (ecc_sign, ecc_verify): Ditto. + * tests/basic.c (check_pubkey_sign_ecdsa): Add a test for using a hash + element with DSA. + + sexp: Add function gcry_sexp_nth_buffer. + + commit 2d3e8d4d9562d666420aadd9ffa8ac0456a1cd91 + * src/sexp.c (gcry_sexp_nth_buffer): New. + * src/visibility.c, src/visibility.h: Add function wrapper. + * src/libgcrypt.vers, src/libgcrypt.def: Add to API. + * src/gcrypt.h.in: Add prototype. + +2013-07-18 Werner Koch + + Add support for Salsa20. + + commit c4885092088431e7928e4459fda20cc0e8ceb201 + * src/gcrypt.h.in (GCRY_CIPHER_SALSA20): New. + * cipher/salsa20.c: New. + * configure.ac (available_ciphers): Add Salsa20. + * cipher/cipher.c: Register Salsa20. + (cipher_setiv): Allow to divert an IV to a cipher module. + * src/cipher-proto.h (cipher_setiv_func_t): New. + (cipher_extra_spec): Add field setiv. + * src/cipher.h: Declare Salsa20 definitions. + * tests/basic.c (check_stream_cipher): New. + (check_stream_cipher_large_block): New. + (check_cipher_modes): Run new test functions. + (check_ciphers): Add simple test for Salsa20. + +2013-07-17 Werner Koch + + Allow gcry_mpi_dump to print opaque MPIs. + + commit 364d019e3ffedfcb434576702f73e767cb9389ef + * mpi/mpicoder.c (gcry_mpi_dump): Detect abd print opaque MPIs. + * tests/mpitests.c (test_opaque): New. + (main): Call new test. + + cipher: Prepare to pass extra info to the sign functions. + + commit 5940e66cbefea3de5924f494f18aed69bb694bff + * src/gcrypt-module.h (gcry_pk_sign_t): Add parms flags and hashalgo. + * cipher/rsa.c (rsa_sign): Add parms and mark them as unused. + * cipher/dsa.c (dsa_sign): Ditto. + * cipher/elgamal.c (elg_sign): Ditto. + * cipher/pubkey.c (dummy_sign): Ditto. + (pubkey_sign): Pass 0 for the new args. + + Fix a special case bug in mpi_powm for e==0. + + commit 6e1adb05d290aeeb1c230c763970695f4a538526 + * mpi/mpi-pow.c (gcry_mpi_powm): For a zero exponent, make sure that + the result has been allocated. + +2013-07-15 Dmitry Eremin-Solenikov + + Fix memory leak in t-mpi-point test. + + commit a7b80e9fba6b1b095f7c53469747967b40ebfbfd + * tests/t-mpi-point.c (basic_ec_math, basic_ec_math_simplified): add + calls to gcry_ctx_release() to free contexts after they become unused. + +2013-07-10 Jussi Kivilinna + + Fix 'Please include winsock2.h before windows.h' warnings with mingw32. + + commit d6c9c86cb7f571ae0bd9aee4efa01a0f9c4c3104 + * random/rndw32.c: include winsock2.h before windows.h. + * src/ath.h [_WIN32]: Ditto. + * tests/benchmark.c [_WIN32]: Ditto. + + Remove duplicate header from mpi/amd64/mpih-mul2.S. + + commit c64a0dcbefc5b0055954e37a3c86b32ff7a1b1da + * mpi/amd64/mpih-mul2.S: remove duplicated header. + + Fix i386/amd64 inline assembly "cc" clobbers. + + commit ed0a598172208ec67234a4edd73189bf6808fd04 + * cipher/bithelp.h [__GNUC__, __i386__] (rol, ror): add "cc" globber + for inline assembly. + * cipher/cast5.c [__GNUC__, __i386__] (rol): Ditto. + * random/rndhw.c [USE_DRNG] (rdrand_long): Ditto. + * src/hmac256.c [__GNUC__, __i386__] (ror): Ditto. + * mpi/longlong.c [__i386__] (add_ssaaaa, sub_ddmmss, umul_ppmm) + (udiv_qrnnd, count_leading_zeros, count_trailing_zeros): Ditto. + + bufhelp: Suppress 'cast increases required alignment' warning. + + commit c3902a6b5cea9acef2e15fbee24eb601eeb25168 + * cipher/bufhelp.h (buf_xor, buf_xor_2dst, buf_xor_n_copy): Cast + to larger element pointer through (void *) to suppress -Wcast-error. + + mpi: Add __ARM_ARCH for older GCC. + + commit 97f392f43cf2e4da1297cbecacbfbff33a869478 + * mpi/longlong.h [__arm__]: Construct __ARM_ARCH if not provided by + compiler. + + mpi: add missing "cc" clobber for ARM assembly. + + commit 8aa4f2161cf643ce36d87d2e2786b546736f8232 + * mpi/longlong.h [__arm__] (add_ssaaaa, sub_ddmmss): Add __CLOBBER_CC. + [__arm__][__ARM_ARCH <= 3] (umul_ppmm): Ditto. + + Tweak ARM inline assembly for mpi. + + commit 71dda4507053379433dc8b0fc6462c15de7299df + mpi/longlong.h [__arm__]: Enable inline assembly if __thumb2__ is + defined. + [__arm__]: Use __ARCH_ARM when defined. + [__arm__] [__ARM_ARCH >= 5] (count_leading_zeros): New. + +2013-06-26 Werner Koch + + Make gpg-error replacement defines more robust. + + commit 6540b84a6e9113813e7e49e3ad2024d4a0073300 + * configure.ac (AH_BOTTOM): Move GPG_ERR_ replacement defines to ... + * src/gcrypt-int.h: new file. + * src/visibility.h, src/cipher.h: Replace gcrypt.h by gcrypt-int.h. + * tests/: Ditto for all test files. + +2013-06-20 Jussi Kivilinna + + Check if assembler is compatible with AMD64 assembly implementations. + + commit 3544fa8aa63bef9a35abf236e9376191b5ec206b + * cipher/blowfish-amd64.S: Enable only if + HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS is defined. + * cipher/camellia-aesni-avx-amd64.S: Ditto. + * cipher/camellia-aesni-avx2-amd64.S: Ditto. + * cipher/cast5-amd64.S: Ditto. + * cipher/rinjdael-amd64.S: Ditto. + * cipher/serpent-avx2-amd64.S: Ditto. + * cipher/serpent-sse2-amd64.S: Ditto. + * cipher/twofish-amd64.S: Ditto. + * cipher/blowfish.c: Use AMD64 assembly implementation only if + HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS is defined + * cipher/camellia-glue.c: Ditto. + * cipher/cast5.c: Ditto. + * cipher/rijndael.c: Ditto. + * cipher/serpent.c: Ditto. + * cipher/twofish.c: Ditto. + * configure.ac: Check gcc/as compatibility with AMD64 assembly + implementations. + +2013-06-09 Jussi Kivilinna + + Optimize _gcry_burn_stack for 32-bit and 64-bit architectures. + + commit ec2f8de409a93c80efa658134df22074a9bca5a4 + * src/misc.c (_gcry_burn_stack): Add optimization for 32-bit and 64-bit + architectures. + + Add Camellia AES-NI/AVX2 implementation. + + commit d94ec5f5f8a5d40a7d344025aa466f276f9718df + * cipher/Makefile.am: Add 'camellia-aesni-avx2-amd64.S'. + * cipher/camellia-aesni-avx2-amd64.S: New file. + * cipher/camellia-glue.c (USE_AESNI_AVX2): New macro. + (CAMELLIA_context) [USE_AESNI_AVX2]: Add 'use_aesni_avx2'. + [USE_AESNI_AVX2] (_gcry_camellia_aesni_avx2_ctr_enc) + (_gcry_camellia_aesni_avx2_cbc_dec) + (_gcry_camellia_aesni_avx2_cfb_dec): New prototypes. + (camellia_setkey) [USE_AESNI_AVX2]: Check AVX2+AES-NI capable hardware + and set 'ctx->use_aesni_avx2'. + (_gcry_camellia_ctr_enc) [USE_AESNI_AVX2]: Add AVX2 accelerated code. + (_gcry_camellia_cbc_dec) [USE_AESNI_AVX2]: Add AVX2 accelerated code. + (_gcry_camellia_cfb_dec) [USE_AESNI_AVX2]: Add AVX2 accelerated code. + (selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): Grow 'nblocks' + so that AVX2 codepaths get tested. + * configure.ac (camellia) [avx2support, aesnisupport]: Add + 'camellia-aesni-avx2-amd64.lo'. + + Add Serpent AVX2 implementation. + + commit e7ab4e1a7396f4609b9033207015b239ab4a5140 + * cipher/Makefile.am: Add 'serpent-avx2-amd64.S'. + * cipher/serpent-avx2-amd64.S: New file. + * cipher/serpent.c (USE_AVX2): New macro. + (serpent_context_t) [USE_AVX2]: Add 'use_avx2'. + [USE_AVX2] (_gcry_serpent_avx2_ctr_enc, _gcry_serpent_avx2_cbc_dec) + (_gcry_serpent_avx2_cfb_dec): New prototypes. + (serpent_setkey_internal) [USE_AVX2]: Check for AVX2 capable hardware + and set 'use_avx2'. + (_gcry_serpent_ctr_enc) [USE_AVX2]: Use AVX2 accelerated functions. + (_gcry_serpent_cbc_dec) [USE_AVX2]: Use AVX2 accelerated functions. + (_gcry_serpent_cfb_dec) [USE_AVX2]: Use AVX2 accelerated functions. + (selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): Grow 'nblocks' + so that AVX2 codepaths are tested. + * configure.ac (serpent) [avx2support]: Add 'serpent-avx2-amd64.lo'. + + Add detection for Intel AVX2 instruction set. + + commit 3289bca708bdd02c69a331095ac6ca9a1efd74cc + * configure.ac: Add option --disable-avx2-support. + (HAVE_GCC_INLINE_ASM_AVX2): New. + (ENABLE_AVX2_SUPPORT): New. + * src/g10lib.h (HWF_INTEL_AVX2): New. + * src/global.c (hwflist): Add HWF_INTEL_AVX2. + * src/hwf-x86.c [__i386__] (get_cpuid): Initialize registers to zero + before cpuid. + [__x86_64__] (get_cpuid): Initialize registers to zero before cpuid. + (detect_x86_gnuc): Store maximum cpuid level. + (detect_x86_gnuc) [ENABLE_AVX2_SUPPORT]: Add detection for AVX2. + + twofish: add amd64 assembly implementation. + + commit d325ab5d86e6107a46007a4d0131122bbd719f8c + * cipher/Makefile.am: Add 'twofish-amd64.S'. + * cipher/twofish-amd64.S: New file. + * cipher/twofish.c (USE_AMD64_ASM): New macro. + [USE_AMD64_ASM] (_gcry_twofish_amd64_encrypt_block) + (_gcry_twofish_amd64_decrypt_block, _gcry_twofish_amd64_ctr_enc) + (_gcry_twofish_amd64_cbc_dec, _gcry_twofish_amd64_cfb_dec): New + prototypes. + [USE_AMD64_ASM] (do_twofish_encrypt, do_twofish_decrypt) + (twofish_encrypt, twofish_decrypt): New functions. + (_gcry_twofish_ctr_enc, _gcry_twofish_cbc_dec, _gcry_twofish_cfb_dec) + (selftest_ctr, selftest_cbc, selftest_cfb): New functions. + (selftest): Call new bulk selftests. + * cipher/cipher.c (gcry_cipher_open) [USE_TWOFISH]: Register Twofish + bulk functions for ctr-enc, cbc-dec and cfb-dec. + * configure.ac (twofish) [x86_64]: Add 'twofish-amd64.lo'. + * src/cipher.h (_gcry_twofish_ctr_enc, _gcry_twofish_cbc_dec) + (gcry_twofish_cfb_dec): New prototypes. + +2013-05-29 Jussi Kivilinna + + rinjdael: add amd64 assembly implementation. + + commit 7317fcfadf00789df140e51c0d16b60f6b144b59 + * cipher/Makefile.am: Add 'rijndael-amd64.S'. + * cipher/rijndael-amd64.S: New file. + * cipher/rijndael.c (USE_AMD64_ASM): New macro. + [USE_AMD64_ASM] (_gcry_aes_amd64_encrypt_block) + (_gcry_aes_amd64_decrypt_block): New prototypes. + (do_encrypt_aligned) [USE_AMD64_ASM]: Use amd64 assembly function. + (do_encrypt): Disable input/output alignment when USE_AMD64_ASM is set. + (do_decrypt_aligned) [USE_AMD64_ASM]: Use amd64 assembly function. + (do_decrypt): Disable input/output alignment when USE_AMD64_AES is set. + * configure.ac (aes) [x86-64]: Add 'rijndael-amd64.lo'. + + blowfish: add amd64 assembly implementation. + + commit 9a61edd1f00cefe8ffa3ad54a53eed163883053c + * cipher/Makefile.am: Add 'blowfish-amd64.S'. + * cipher/blowfish-amd64.S: New file. + * cipher/blowfish.c (USE_AMD64_ASM): New macro. + [USE_AMD64_ASM] (_gcry_blowfish_amd64_do_encrypt) + (_gcry_blowfish_amd64_encrypt_block) + (_gcry_blowfish_amd64_decrypt_block, _gcry_blowfish_amd64_ctr_enc) + (_gcry_blowfish_amd64_cbc_dec, _gcry_blowfish_amd64_cfb_dec): New + prototypes. + [USE_AMD64_ASM] (do_encrypt, do_encrypt_block, do_decrypt_block) + (encrypt_block, decrypt_block): New functions. + (_gcry_blowfish_ctr_enc, _gcry_blowfish_cbc_dec) + (_gcry_blowfish_cfb_dec, selftest_ctr, selftest_cbc, selftest_cfb): New + functions. + (selftest): Call new bulk selftests. + * cipher/cipher.c (gcry_cipher_open) [USE_BLOWFISH]: Register Blowfish + bulk functions for ctr-enc, cbc-dec and cfb-dec. + * configure.ac (blowfish) [x86_64]: Add 'blowfish-amd64.lo'. + * src/cipher.h (_gcry_blowfish_ctr_enc, _gcry_blowfish_cbc_dec) + (gcry_blowfish_cfb_dec): New prototypes. + +2013-05-24 Werner Koch + + ecc: Simplify the compliant point generation. + + commit 99b18aa536703ef90c9a1f5c8f40bc68b2064593 + * cipher/ecc.c (generate_key): Use point_snatch_set, replaces unneeded + variable copies, etc. + + ecc: Fix a minor flaw in the generation of K. + + commit 9711384f75564a71979e3fb971b5f4cadcf1afef + * cipher/dsa.c (gen_k): Factor code out to .. + * cipher/dsa-common.c (_gcry_dsa_gen_k): new file and function. Add + arg security_level and re-indent a bit. + * cipher/ecc.c (gen_k): Remove and change callers to _gcry_dsa_gen_k. + * cipher/dsa.c: Include pubkey-internal. + * cipher/Makefile.am (libcipher_la_SOURCES): Add dsa-common.c + +2013-05-24 Jussi Kivilinna + + cast5: add amd64 assembly implementation. + + commit 0bdf26eea8cdbffefe7e37578f8f896c4f5f5275 + * cipher/Makefile.am: Add 'cast5-amd64.S'. + * cipher/cast5-amd64.S: New file. + * cipher/cast5.c (USE_AMD64_ASM): New macro. + (_gcry_cast5_s1tos4): Merge arrays s1, s2, s3, s4 to single array to + simplify access from assembly implementation. + (s1, s2, s3, s4): New macros pointing to subarrays in + _gcry_cast5_s1tos4. + [USE_AMD64_ASM] (_gcry_cast5_amd64_encrypt_block) + (_gcry_cast5_amd64_decrypt_block, _gcry_cast5_amd64_ctr_enc) + (_gcry_cast5_amd64_cbc_dec, _gcry_cast5_amd64_cfb_dec): New prototypes. + [USE_AMD64_ASM] (do_encrypt_block, do_decrypt_block, encrypt_block) + (decrypt_block): New functions. + (_gcry_cast5_ctr_enc, _gcry_cast5_cbc_dec, _gcry_cast5_cfb_dec) + (selftest_ctr, selftest_cbc, selftest_cfb): New functions. + (selftest): Call new bulk selftests. + * cipher/cipher.c (gcry_cipher_open) [USE_CAST5]: Register CAST5 bulk + functions for ctr-enc, cbc-dec and cfb-dec. + * configure.ac (cast5) [x86_64]: Add 'cast5-amd64.lo'. + * src/cipher.h (_gcry_cast5_ctr_enc, _gcry_cast5_cbc_dec) + (gcry_cast5_cfb_dec): New prototypes. + + cipher-selftest: make selftest work with any block-size. + + commit ab8fc70b5f0c396a5bc941267f59166e860b8c5d + * cipher/cipher-selftest.c (_gcry_selftest_helper_cbc_128) + (_gcry_selftest_helper_cfb_128, _gcry_selftest_helper_ctr_128): Renamed + functions from '_128' to ''. + (_gcry_selftest_helper_cbc, _gcry_selftest_helper_cfb) + (_gcry_selftest_helper_ctr): Make work with different block sizes. + * cipher/cipher-selftest.h (_gcry_selftest_helper_cbc_128) + (_gcry_selftest_helper_cfb_128, _gcry_selftest_helper_ctr_128): Renamed + prototypes from '_128' to ''. + * cipher/camellia-glue.c (selftest_ctr_128, selftest_cfb_128) + (selftest_ctr_128): Change to use new function names. + * cipher/rijndael.c (selftest_ctr_128, selftest_cfb_128) + (selftest_ctr_128): Change to use new function names. + * cipher/serpent.c (selftest_ctr_128, selftest_cfb_128) + (selftest_ctr_128): Change to use new function names. + +2013-05-23 Jussi Kivilinna + + serpent: add parallel processing for CFB decryption. + + commit 6deb0ccdf718a0670f80e6762a3842caf76437d6 + * cipher/cipher.c (gcry_cipher_open): Add bulf CFB decryption function + for Serpent. + * cipher/serpent-sse2-amd64.S (_gcry_serpent_sse2_cfb_dec): New + function. + * cipher/serpent.c (_gcry_serpent_sse2_cfb_dec): New prototype. + (_gcry_serpent_cfb_dec) New function. + (selftest_cfb_128) New function. + (selftest) Call selftest_cfb_128. + * src/cipher.h (_gcry_serpent_cfb_dec): New prototype. + + camellia: add parallel processing for CFB decryption. + + commit b60f06f70227c1e69e1010da8b47ea51ade48145 + * cipher/camellia-aesni-avx-amd64.S + (_gcry_camellia_aesni_avx_cfb_dec): New function. + * cipher/camellia-glue.c (_gcry_camellia_aesni_avx_cfb_dec): New + prototype. + (_gcry_camellia_cfb_dec): New function. + (selftest_cfb_128): New function. + (selftest): Call selftest_cfb_128. + * cipher/cipher.c (gry_cipher_open): Add bulk CFB decryption function + for Camellia. + * src/cipher.h (_gcry_camellia_cfb_dec): New prototype. + + rinjdael: add parallel processing for CFB decryption with AES-NI. + + commit 319ee14f2aab8db56a830fd7ac8926f91b4f738a + * cipher/cipher-selftest.c (_gcry_selftest_helper_cfb_128): New + function for CFB selftests. + * cipher/cipher-selftest.h (_gcry_selftest_helper_cfb_128): New + prototype. + * cipher/rijndael.c [USE_AESNI] (do_aesni_enc_vec4): New function. + (_gcry_aes_cfb_dec) [USE_AESNI]: Add parallelized CFB decryption. + (selftest_cfb_128): New function. + (selftest): Call selftest_cfb_128. + +2013-05-23 Werner Koch + + Avoid compiler warning due to the global symbol setkey. + + commit b402de8b9c4a9f269faf03ca952b1eb68a1f33c8 + * cipher/cipher-selftest.c (_gcry_selftest_helper_cbc_128) + (_gcry_selftest_helper_ctr_128): Rename setkey to setkey_func. + +2013-05-23 Jussi Kivilinna + + serpent: add SSE2 accelerated amd64 implementation. + + commit 2fd06e207dcea1d8a7f0e7e92f3359615a99421b + * configure.ac (serpent): Add 'serpent-sse2-amd64.lo'. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add + 'serpent-sse2-amd64.S'. + * cipher/cipher.c (gcry_cipher_open) [USE_SERPENT]: Register bulk + functions for CBC-decryption and CTR-mode. + * cipher/serpent.c (USE_SSE2): New macro. + [USE_SSE2] (_gcry_serpent_sse2_ctr_enc, _gcry_serpent_sse2_cbc_dec): + New prototypes to assembler functions. + (serpent_setkey): Set 'serpent_init_done' before calling serpent_test. + (_gcry_serpent_ctr_enc): New function. + (_gcry_serpent_cbc_dec): New function. + (selftest_ctr_128): New function. + (selftest_cbc_128): New function. + (selftest): Call selftest_ctr_128 and selftest_cbc_128. + * cipher/serpent-sse2-amd64.S: New file. + * src/cipher.h (_gcry_serpent_ctr_enc): New prototype. + (_gcry_serpent_cbc_dec): New prototype. + + Serpent: faster S-box implementation. + + commit c85501af8222913f0a1e20e77fceb88e93417925 + * cipher/serpent.c (SBOX0, SBOX1, SBOX2, SBOX3, SBOX4, SBOX5, SBOX6) + (SBOX7, SBOX0_INVERSE, SBOX1_INVERSE, SBOX2_INVERSE, SBOX3_INVERSE) + (SBOX4_INVERSE, SBOX5_INVERSE, SBOX6_INVERSE, SBOX7_INVERSE): Replace + with new definitions. + +2013-05-22 Werner Koch + + w32: Fix installing of .def file. + + commit 4e46d8bc78008ba06f106b368cefb0dddf15fe38 + * src/Makefile.am (install-def-file): Create libdir first. + + Add control commands to disable mlock and setuid dropping. + + commit 2b8014af202c9e0f7619f7a4377f5eb752235220 + * src/gcrypt.h.in (GCRYCTL_DISABLE_LOCKED_SECMEM): New. + (GCRYCTL_DISABLE_PRIV_DROP): New. + * src/global.c (_gcry_vcontrol): Implement them. + * src/secmem.h (GCRY_SECMEM_FLAG_NO_MLOCK): New. + (GCRY_SECMEM_FLAG_NO_PRIV_DROP): New. + * src/secmem.c (no_mlock, no_priv_drop): New. + (_gcry_secmem_set_flags, _gcry_secmem_get_flags): Set and get them. + (lock_pool): Handle no_mlock and no_priv_drop. + + Fix libtool 2.4.2 to correctly detect .def files. + + commit 05b3e2dda61d3d532a7f1ffd2487a85ed1c4f3ab + * ltmain.sh (sed_uncomment_deffile): New. + (orig_export_symbols): Uncomment def file before testing for EXPORTS. + * m4/libtool.m4: Do the same for the generated code. + +2013-05-22 Jussi Kivilinna + + Add AES bulk CBC decryption selftest. + + commit b65281a1b76d7898eb7607932246b78277d8570b + * cipher/rinjdael.c (selftest_cbc_128): New. + (selftest): Call selftest_cbc_128. + + Change AES bulk CTR encryption selftest use new selftest helper function + + commit 3637bdbb5f30a5e06745d448a6a8ad00e5cdd740 + * cipher/rinjdael.c: (selftest_ctr_128): Change to use new selftest + helper function. + + Convert bulk CTR and CBC selftest functions in Camellia to generic selftest helper functions + + commit eed4042fa028b3f73bad6a768f5b0a82f642e545 + * cipher/Makefile.am (libcipher_la_SOURCES): Add cipher-selftest files. + * cipher/camellia-glue.c (selftest_ctr_128, selftest_cbc_128): Change + to use the new selftest helper functions. + * cipher/cipher-selftest.c: New. + * cipher/cipher-selftest.h: New. + + camellia: add bulk CBC decryption selftest. + + commit f2986f03d1ae59f973bae56ce4333e5457003de5 + * cipher/camellia-glue.c: (selftest_cbc_128): New selftest function for + bulk CBC decryption. + (selftest): Add call to selftest_cbc_128. + + camellia: Rename camellia_aesni_avx_x86-64.S to camellia-aesni-avx-amd64.S + + commit 194ae35da7830a76b96e9b21121a2e1248762d3f + * cipher/camellia_aesni_avx_x86-64.S: Remove. + * cipher/camellia-aesni-avx-amd64.S: New. + * cipher/Makefile.am: Use the new filename. + * configure.ac: Use the new filename. + +2013-05-21 Werner Koch + + Fix indentation and save on string space. + + commit 2ac3a7c2b7154379738d17cfde8cd9017dc142f0 + * cipher/ecc.c (generate_key): Use the same string for both fatal + messages. + +2013-05-20 Andrey + + cipher: Fix segv in last ECC change. + + commit eb4937914db3fb7317502e97e4f0e40c1857f59d + * cipher/ecc.c (generate_key): Make sure R is initialized. + +2013-05-09 Andrey + + cipher: Generate compliant ECC keys. + + commit 296f38a2bd2e25788643a42e4881faed00884a40 + * cipher/ecc.c (generate_key): Make sure a key is compliant for + using the compact representation. + +2013-04-18 Werner Koch + + cipher: Fix regression in Padlock support. + + commit 6c942ec4d63032539f1fc56c3b970cfec2369e2b + * cipher/rijndael.c (do_setkey): Remove dummy padlock key generation case + and use the standard one. + + mpi: Yet another fix to get option flag munging right. + + commit 03557687a09b9c8878c77cbfdd0f5049940c72da + * cipher/Makefile.am (o_flag_munging): Yet another fix. + + mpi: Make using gcc's -Ofast easier. + + commit 1ab26bc304c559b0a8d29823d656f7ad8d10a59d + * cipher/Makefile.am (o_flag_munging): Take -Ofast in account. + + Fix alignment problem in idea.c. + + commit 3271b0dfda67e26c381d7ed667737f08f865ee40 + * cipher/idea.c (cipher): Rework parameter use to fix alignment + problems. + + * cipher/idea.c (FNCCAST_SETKEY, FNCCAST_CRYPT): Remove unused macros. + + Fix alignment problem in idea.c. + + * cipher/idea.c (cipher): Rework parameter use to fix alignment + problems. + + * cipher/idea.c (FNCCAST_SETKEY, FNCCAST_CRYPT): Remove unused macros. + + + (cherry picked from 4cd279556777e02eda79973f68efaa4b741f9175) + +2013-04-18 Vladimir Serbinenko + + Add some const attributes. + + commit ff0b94c22b36600fff1db9f1d48f9de61f9038f7 + * cipher/md4.c (transform): Add const attribute. + * cipher/md5.c (transform): Ditto. + * cipher/rmd160.c (transform): Ditto. + + Fix alignment problem in serpent.c. + + commit 86e72b490a5790a9c23341067c7e4d3e38be1634 + * cipher/serpent.c (serpent_key_prepare): Fix misaligned access. + (serpent_setkey): Likewise. + (serpent_encrypt_internal): Likewise. + (serpent_decrypt_internal): Likewise. + (serpent_encrypt): Don't put an alignment-increasing cast. + (serpent_decrypt): Likewise. + (serpent_test): Likewise. + +2013-04-16 Werner Koch + + Fix multiply by zero in gcry_mpi_ec_mul. + + commit 78cd0ba8a8eceee9d0b3397a2ab3bda6ba37c8a4 + * mpi/ec.c (_gcry_mpi_ec_mul_point): Handle case of SCALAR == 0. + * tests/t-mpi-point.c (basic_ec_math): Add a test case for this. + +2013-04-15 Werner Koch + + Add macros to return pre-defined MPIs. + + commit bd3afc27459a44df8cf501a7e1ae37bb849a8b0e + * src/gcrypt.h.in (GCRYMPI_CONST_ONE, GCRYMPI_CONST_TWO) + (GCRYMPI_CONST_THREE, GCRYMPI_CONST_FOUR, GCRYMPI_CONST_EIGHT): New. + (_gcry_mpi_get_const): New private function. + * src/visibility.c (_gcry_mpi_get_const): New. + * src/visibility.h: Mark it visible. + + Fix addition of EC points. + + commit 71b25a5562f68aad81eae52cc1bab9ca7731a7e9 + * mpi/ec.c (_gcry_mpi_ec_add_points): Fix case of P1 given in affine + coordinates. + +2013-04-12 Werner Koch + + Add hack to allow using an "ecc" key for "ecdsa" or "ecdh". + + commit af8a79aea80217a0c85a592db1fa001792a6bf0f + * cipher/pubkey.c (sexp_to_key): Add optional arg USE. + (gcry_pk_encrypt, gcry_pk_decrypt): Call sexp_to_key with usage sign. + (gcry_pk_sign, gcry_pk_verify): Call sexp_to_key with usage encrypt. + * tests/basic.c (show_sexp): New. + (check_pubkey_sign): Print test number and add cases for ecc. + (check_pubkey_sign_ecdsa): New. + (do_check_one_pubkey): Divert to new function. + +2013-04-11 Werner Koch + + Add gcry_pubkey_get_sexp. + + commit 1f3cfad66456dd6f2e48f20b8eb0c51343449a1c + * src/gcrypt.h.in (GCRY_PK_GET_PUBKEY): New. + (GCRY_PK_GET_SECKEY): New. + (gcry_pubkey_get_sexp): New. + * src/visibility.c (gcry_pubkey_get_sexp): New. + * src/visibility.h (gcry_pubkey_get_sexp): Mark visible. + * src/libgcrypt.def, src/libgcrypt.vers: Add new function. + * cipher/pubkey-internal.h: New. + * cipher/Makefile.am (libcipher_la_SOURCES): Add new file. + * cipher/ecc.c: Include pubkey-internal.h + (_gcry_pk_ecc_get_sexp): New. + * cipher/pubkey.c: Include pubkey-internal.h and context.h. + (_gcry_pubkey_get_sexp): New. + * src/context.c (_gcry_ctx_find_pointer): New. + * src/cipher-proto.h: Add _gcry_pubkey_get_sexp. + * tests/t-mpi-point.c (print_sexp): New. + (context_param, basic_ec_math_simplified): Add tests for the new + function. + + * configure.ac (NEED_GPG_ERROR_VERSION): Set to 1.11. + (AH_BOTTOM) Add error codes from gpg-error 1.12 + * src/g10lib.h (fips_not_operational): Use GPG_ERR_NOT_OPERATIONAL. + + * mpi/ec.c (_gcry_mpi_ec_get_mpi): Fix computation of Q. + (_gcry_mpi_ec_get_point): Ditto. + + Remove unused code. + + commit 7524da2ba83d83a766c22d704006380c893e1c49 + * cipher/pubkey.c (_gcry_pk_module_lookup, _gcry_pk_module_release) + (_gcry_pk_get_elements): Remove. + +2013-04-05 Werner Koch + + Make the Q parameter optional for ECC signing. + + commit fe91a642c7c257aca095b96406fbcace88fa3df4 + * cipher/ecc.c (ecc_sign): Remove the need for Q. + * cipher/pubkey.c (sexp_elements_extract_ecc): Make Q optional for a + private key. + (sexp_to_key): Add optional arg R_IS_ECC. + (gcry_pk_sign): Do not call gcry_pk_get_nbits for ECC keys. + * tests/pubkey.c (die): Make sure to print a LF. + (check_ecc_sample_key): New. + (main): Call new test. + + Add test case for SCRYPT and rework the code. + + commit f23a068bcb6ec9788710698578d8be0a2a006dbc + * tests/t-kdf.c (check_scrypt): New. + (main): Call new test. + + * configure.ac: Support disabling of the scrypt algorithm. Make KDF + enabling similar to the other algorithm classes. Disable scrypt if we + don't have a 64 bit type. + * cipher/memxor.c, cipher/memxor.h: Remove. + * cipher/scrypt.h: Remove. + * cipher/kdf-internal.h: New. + * cipher/Makefile.am: Remove files. Add new file. Move scrypt.c to + EXTRA_libcipher_la_SOURCES. + (GCRYPT_MODULES): Add GCRYPT_KDFS. + * src/gcrypt.h.in (GCRY_KDF_SCRYPT): Change value. + * cipher/kdf.c (pkdf2): Rename to _gcry_kdf_pkdf2. + (_gcry_kdf_pkdf2): Don't bail out for SALTLEN==0. + (gcry_kdf_derive): Allow for a passwordlen of zero for scrypt. Check + for SALTLEN > 0 for GCRY_KDF_PBKDF2. Pass algo to _gcry_kdf_scrypt. + (gcry_kdf_derive) [!USE_SCRYPT]: Return an error. + * cipher/scrypt.c: Replace memxor.h by bufhelp.h. Replace scrypt.h by + kdf-internal.h. Enable code only if HAVE_U64_TYPEDEF is defined. + Replace C99 types uint64_t, uint32_t, and uint8_t by libgcrypt types. + (_SALSA20_INPUT_LENGTH): Remove underscore from identifier. + (_scryptBlockMix): Replace memxor by buf_xor. + (_gcry_kdf_scrypt): Use gcry_malloc and gcry_free. Check for integer + overflow. Add hack to support blocksize of 1 for tests. Return + errors from calls to _gcry_kdf_pkdf2. + + * cipher/kdf.c (openpgp_s2k): Make static. + +2013-04-04 Christian Grothoff + + Add the SCRYPT KDF function. + + commit 855b1a8f81b5a3b5b31d0c3c303675425f58a5af + * scrypt.c, scrypt.h: New files. + * memxor.c, memxor.h: New files. + * cipher/Makefile.am: Add new files. + * cipher/kdf.c (gcry_kdf_derive): Support GCRY_KDF_SCRYPT. + * src/gcrypt.h.in (GCRY_KDF_SCRYPT): New. + +2013-03-22 Werner Koch + + Replace deprecated AM_CONFIG_HEADER macro. + + commit d0c8fda5af45354ac32928c9a01e688d6893599d + * configure.ac: s/AM_CONFIG_HEADER/AC_CONFIG_HEADER/ + + Disable AES-NI support if as does not support SSSE3. + + commit 9f4df1612ae21a5ce70d98930cb194e5193f5e2d + * configure.ac (HAVE_GCC_INLINE_ASM_SSSE3): New test. + (ENABLE_AESNI_SUPPORT): Do not define without SSSE3 support. + (HAVE_GCC_INLINE_ASM_SSSE3, ENABLE_AVX_SUPPORT): Split up detection + and definition. + +2013-03-21 Werner Koch + + Fix make dependency regression. + + commit 2a1e03c5a481689c43d197dd8034a1d73de0a1a4 + * src/Makefile.am (libgcrypt_la_DEPENDENCIES): Add missing backslash. + Reported by LRN. + +2013-03-20 Werner Koch + + Use finer grained on-the-fly helper computations for EC. + + commit 5fb3501aa0cf5f2b2a9012706bb9ad2b1c4bfd7d + * src/ec-context.h (mpi_ec_ctx_s): Replace NEED_SYNC by a bitfield. + * mpi/ec.c (ec_p_sync): Remove. + (ec_get_reset, ec_get_a_is_pminus3, ec_get_two_inv_p): New. + (ec_p_init): Use ec_get_reset. + (_gcry_mpi_ec_set_mpi, _gcry_mpi_ec_dup_point) + (_gcry_mpi_ec_add_points): Replace ec_p_sync by the ec_get_ accessors. + + Allow building with w64-mingw32. + + commit b402e550041782b770a6ae267c7c28ca8324a12e + * autogen.sh <--build-w32>: Support the w64-mingw32 toolchain. Also + prepare for 64 bit building. + + Provide GCRYPT_VERSION_NUMBER macro, add build info to the binary. + + commit 1eaad0a8c4cab227685a6a8768e539df2f1f4dac + * src/gcrypt.h.in (GCRYPT_VERSION_NUMBER): New. + * configure.ac (VERSION_NUMBER): New ac_subst. + * src/global.c (_gcry_vcontrol): Move call to above function ... + (gcry_check_version): .. here. + + * configure.ac (BUILD_REVISION, BUILD_FILEVERSION) + (BUILD_TIMESTAMP): Define on all platforms. + * compat/compat.c (_gcry_compat_identification): Include revision and + timestamp. + + Fix a memory leak in the new EC code. + + commit de07974d807b703a2554d6ba885ea249e648bd44 + * cipher/ecc.c (point_from_keyparam): Always call mpi_free on A. + +2013-03-19 Werner Koch + + Extend the new EC interface and fix two bugs. + + commit 931e409e877d1e444edd53dead327ec8e64daf9a + * src/ec-context.h (mpi_ec_ctx_s): Add field NEED_SYNC. + * mpi/ec.c (ec_p_sync): New. + (ec_p_init): Only set NEED_SYNC. + (_gcry_mpi_ec_set_mpi): Set NEED_SYNC for 'p' and 'a'. + (_gcry_mpi_ec_dup_point, _gcry_mpi_ec_add_points) + (_gcry_mpi_ec_mul_point): Call ec_p_sync. + (_gcry_mpi_ec_get_point): Recompute 'q' is needed. + (_gcry_mpi_ec_get_mpi): Ditto. Also allow for names 'q', 'q.x', + 'q.y', and 'g'. + * cipher/ecc.c (_gcry_mpi_ec_ec2os): New. + + * cipher/ecc.c (_gcry_mpi_ec_new): Fix init from parameters 'Q'->'q', + 'G'->'q'. + +2013-03-15 Werner Koch + + mpi: Add functions to manipulate an EC context. + + commit 229f3219f80c9369ed9624242c0436ae6d293201 + * src/gcrypt.h.in (gcry_mpi_ec_p_new): Remove. + (gcry_mpi_ec_new): New. + (gcry_mpi_ec_get_mpi): New. + (gcry_mpi_ec_get_point): New. + (gcry_mpi_ec_set_mpi): New. + (gcry_mpi_ec_set_point): New. + * src/visibility.c (gcry_mpi_ec_p_new): Remove. + * mpi/ec.c (_gcry_mpi_ec_p_new): Make it an internal function and + change to return an error code. + (_gcry_mpi_ec_get_mpi): New. + (_gcry_mpi_ec_get_point): New. + (_gcry_mpi_ec_set_mpi): New. + (_gcry_mpi_ec_set_point): New. + * src/mpi.h: Add new prototypes. + * src/ec-context.h: New. + * mpi/ec.c: Include that header. + (mpi_ec_ctx_s): Move to ec-context.h, add new fields, and put some + fields into an inner struct. + (point_copy): New. + * cipher/ecc.c (fill_in_curve): Allow passing NULL for R_NBITS. + (mpi_from_keyparam, point_from_keyparam): New. + (_gcry_mpi_ec_new): New. + + * tests/t-mpi-point.c (test-curve): New. + (ec_p_new): New. Use it instead of the removed gcry_mpi_ec_p_new. + (get_and_cmp_mpi, get_and_cmp_point): New. + (context_param): New test. + (basic_ec_math_simplified): New test. + (main): Call new tests. + + * src/context.c (_gcry_ctx_get_pointer): Check for a NULL CTX. + +2013-03-13 Werner Koch + + Add GCRYMPI_FLAG_CONST and make use constants. + + commit e005629bd7bebb3e13945645c6e1230b44ab16a2 + * src/gcrypt.h.in (GCRYMPI_FLAG_CONST): New. + * src/mpi.h (mpi_is_const, mpi_const): New. + (enum gcry_mpi_constants, MPI_NUMBER_OF_CONSTANTS): New. + * mpi/mpiutil.c (_gcry_mpi_init): New. + (constants): New. + (_gcry_mpi_free): Do not release a constant flagged MPI. + (gcry_mpi_copy): Clear the const and immutable flags. + (gcry_mpi_set_flag, gcry_mpi_clear_flag, gcry_mpi_get_flag): Support + GCRYMPI_FLAG_CONST. + (_gcry_mpi_const): New. + * src/global.c (global_init): Call _gcry_mpi_init. + * mpi/ec.c (mpi_ec_ctx_s): Remove fields one, two, three, four, and + eight. Change all users to call mpi_const() instead. + + * src/mpiutils.c (gcry_mpi_set_opaque): Check the immutable flag. + + Add GCRYMPI_FLAG_IMMUTABLE to help debugging. + + commit 1fecae98ee7e0fa49b29f98efa6817ca121ed98a + * src/gcrypt.h.in (GCRYMPI_FLAG_IMMUTABLE): New. + * src/mpi.h (mpi_is_immutable): New macro. + * mpi/mpiutil.c (gcry_mpi_set_flag, gcry_mpi_clear_flag) + (gcry_mpi_get_flag): Implement new flag + (_gcry_mpi_immutable_failed): New. + + * mpi/mpiutil.c (_gcry_mpi_clear, _gcry_mpi_free, gcry_mpi_snatch) + (gcry_mpi_set, gcry_mpi_randomize): Act upon the immutable flag. + * mpi/mpi-bit.c (gcry_mpi_set_bit, gcry_mpi_set_highbit) + (gcry_mpi_clear_highbit, gcry_mpi_clear_bit) + (_gcry_mpi_rshift_limbs, gcry_mpi_lshift): Ditto. + * mpi/mpicoder.c (_gcry_mpi_set_buffer): Ditto. + +2013-03-08 Werner Koch + + mpi: Add an API for EC math. + + commit 8ac9e756d3ca545a9b97e61ad3d42fc2e877d788 + * src/context.c, src/context.h: New. + * src/Makefile.am (libgcrypt_la_SOURCES): Add new files. + * src/gcrypt.h.in (struct gcry_context, gcry_ctx_t): New types. + (gcry_ctx_release): New prototype. + (gcry_mpi_ec_p_new, gcry_mpi_ec_get_affine, gcry_mpi_ec_dup) + (gcry_mpi_ec_add, gcry_mpi_ec_mul): New prototypes. + * mpi/ec.c: Include errno.h and context.h. + (_gcry_mpi_ec_init): Rename to .. + (ec_p_init): this, make static, remove allocation and add arg CTX. + (_gcry_mpi_ec_p_internal_new): New; to replace _gcry_mpi_ec_init. + Change all callers to use this func. + (_gcry_mpi_ec_free): Factor code out to .. + (ec_deinit): New func. + (gcry_mpi_ec_p_new): New. + * src/visibility.c: Include context.h and mpi.h. + (gcry_mpi_ec_p_new, gcry_mpi_ec_get_affine, gcry_mpi_ec_dup) + (gcry_mpi_ec_add, gcry_mpi_ec_mul) + (gcry_ctx_release): New wrapper functions. + * src/visibility.h: Mark new wrapper functions visible. + * src/libgcrypt.def, src/libgcrypt.vers: Add new symbols. + * tests/t-mpi-point.c (print_mpi, hex2mpi, cmp_mpihex): New. + (context_alloc): New. + (make_point, basic_ec_math): New. + + mpi: Add an API for EC point operations. + + commit 7cce620acddac2df024ca421ed3abc32a88f3738 + * mpi/ec.c (gcry_mpi_point_new, gcry_mpi_point_release): New. + (gcry_mpi_point_get, gcry_mpi_point_snatch_get): New. + (gcry_mpi_point_set, gcry_mpi_point_snatch_set): New. + * src/visibility.h, src/visibility.c: Add corresponding macros and + wrappers. + * src/gcrypt.h.in (struct gcry_mpi_point, gcry_mpi_point_t): New. + (gcry_mpi_point_new, gcry_mpi_point_release, gcry_mpi_point_get) + (gcry_mpi_point_snatch_get, gcry_mpi_point_set) + (gcry_mpi_point_snatch_set): New prototypes. + (mpi_point_new, mpi_point_release, mpi_point_get, mpi_point_snatch_get) + (mpi_point_set, mpi_point_snatch_set): New macros. + * src/libgcrypt.vers (gcry_mpi_point_new, gcry_mpi_point_release) + (gcry_mpi_point_get, gcry_mpi_point_snatch_get, gcry_mpi_point_set) + (gcry_mpi_point_snatch_set): New symbols. + * src/libgcrypt.def: Ditto. + * tests/t-mpi-point.c: New. + * tests/Makefile.am (TESTS): Add t-mpi-point + +2013-03-07 Werner Koch + + mpi: Add mpi_snatch and change an internal typedef. + + commit 6c4767637c512127a4362732b3ec51068554d328 + * src/mpi.h (struct mpi_point_s): Rename to struct gcry_mpi_point. + (mpi_point_struct): New typedef. + (mpi_point_t): Change typedef to a pointer. Replace all occurrences + to use mpi_point_struct. + * mpi/ec.c (_gcry_mpi_ec_point_init): Rename to .. + (_gcry_mpi_point_init): this. Change all callers. + (_gcry_mpi_ec_point_free): Rename to .. + (_gcry_mpi_point_free_parts): this. Change all callers. + + * mpi/mpiutil.c (gcry_mpi_snatch): New function. + * src/gcrypt.h.in (gcry_mpi_snatch, mpi_snatch): Add protoype and + macro. + * src/visibility.c (gcry_mpi_snatch): Add wrapper. + * src/visibility.h (gcry_mpi_snatch): Add macro magic. + * src/libgcrypt.def, src/libgcrypt.vers: Add new function. + + Pretty print the configure feedback. + + commit c620099e4ab2f35e0196b395a805bb655c984ac2 + * acinclude.m4 (GNUPG_MSG_PRINT): Remove. + (GCRY_MSG_SHOW, GCRY_MSG_WRAP): New. + * configure.ac: Use new macros for the feedback. + +2013-02-20 Werner Koch + + Fix building of hwf-x86.c. + + commit 70dcac663de06b012417015c175973d64e6980df + * src/Makefile.am (AM_CFLAGS): Set to GPG_ERROR_CFLAGS + (AM_CCASFLAGS): Set NOEXECSTACK_FLAGS. + + Remove build hacks for FreeBSD. + + commit fb48ebf7081400a24ee48f8a9894a361e8834b6e + * configure.ac [freebsd]: Do not add /usr/local to CPPFLAGS and + LDFLAGS. + +2013-02-19 Jussi Kivilinna + + Rinjdael: Fix use of SSE2 outside USE_AESNI/ctx->use_aesni. + + commit 0da77955a097bfd2469ad084b3e9fcac4fb1e3fa + * cipher/rijndael.c (_gcry_aes_cbc_enc): Check if AES-NI is enabled before + calling aesni_prepare() and aesni_cleanup(). + + Add AES-NI/AVX accelerated Camellia implementation. + + commit 63ac3ba07dba82fde040d31b90b4eff627bd92b9 + * configure.ac: Add option --disable-avx-support. + (HAVE_GCC_INLINE_ASM_AVX): New. + (ENABLE_AVX_SUPPORT): New. + (camellia) [ENABLE_AVX_SUPPORT, ENABLE_AESNI_SUPPORT]: Add + camellia_aesni_avx_x86-64.lo. + * cipher/Makefile.am (AM_CCASFLAGS): Add. + (EXTRA_libcipher_la_SOURCES): Add camellia_aesni_avx_x86-64.S + * cipher/camellia-glue.c [ENABLE_AESNI_SUPPORT, ENABLE_AVX_SUPPORT] + [__x86_64__] (USE_AESNI_AVX): Add macro. + (struct Camellia_context) [USE_AESNI_AVX]: Add use_aesni_avx. + [USE_AESNI_AVX] (_gcry_camellia_aesni_avx_ctr_enc) + (_gcry_camellia_aesni_avx_cbc_dec): New prototypes to assembly + functions. + (camellia_setkey) [USE_AESNI_AVX]: Enable AES-NI/AVX if hardware + support both. + (_gcry_camellia_ctr_enc) [USE_AESNI_AVX]: Add AES-NI/AVX code. + (_gcry_camellia_cbc_dec) [USE_AESNI_AVX]: Add AES-NI/AVX code. + * cipher/camellia_aesni_avx_x86-64.S: New. + * src/g10lib.h (HWF_INTEL_AVX): New. + * src/global.c (hwflist): Add HWF_INTEL_AVX. + * src/hwf-x86.c (detect_x86_gnuc) [ENABLE_AVX_SUPPORT]: Add detection + for AVX. + + camellia.c: Prepare for AES-NI/AVX implementation. + + commit 4de62d80644228fc5db2a9f9c94a7eb633d8de2e + * cipher/camellia-glue.c (CAMELLIA_encrypt_stack_burn_size) + (CAMELLIA_decrypt_stack_burn_size): Increase stack burn size. + * cipher/camellia.c (CAMELLIA_ROUNDSM): Move key-material mixing in + the front. + (camellia_setup128, camellia_setup256): Remove now unneeded + key-material mangling. + (camellia_encrypt128, camellia_decrypt128, amellia_encrypt256) + (camellia_decrypt256): Copy block to stack, so that compiler can + optimize it for register usage. + + Camellia, prepare glue code for AES-NI/AVX implementation. + + commit 537f12ce072d568f9fa344c447d32b2e0efffbe8 + * cipher/camellia-glue.c (ATTR_ALIGNED_16): Add macro. + (CAMELLIA_encrypt_stack_burn_size): Add macro. + (camellia_encrypt): Use macro above for stack burn size. + (CAMELLIA_decrypt_stack_burn_size): Add macro. + (camellia_decrypt): Use macro above for stack burn size. + (_gcry_camellia_ctr_enc): New function. + (_gcry_camellia_cbc_dec): New function. + (selftest_ctr_128): New function. + (selftest): Call function above. + * cipher/cipher.c (gcry_cipher_open) [USE_CAMELLIA]: Register bulk + functions for CBC-decryption and CTR-mode. + * src/cipher.h (_gcry_camellia_ctr_enc): New prototype. + (_gcry_camellia_cbc_dec): New prototype. + +2012-12-21 Werner Koch + + Prepare for hardware feature detection on other platforms. + + commit 09ac5d87d11aa0b1fa0e0a4184ab03b3671a73e2 + * configure.ac (GCRYPT_HWF_MODULES): New. + (HAVE_CPU_ARCH_X86, HAVE_CPU_ARCH_ALPHA, HAVE_CPU_ARCH_SPARC) + (HAVE_CPU_ARCH_MIPS, HAVE_CPU_ARCH_M68K, HAVE_CPU_ARCH_PPC) + (HAVE_CPU_ARCH_ARM): New AC_DEFINEs. + * mpi/config.links (mpi_cpu_arch): New. + * src/global.c (print_config): Print new tag "cpu-arch". + * src/Makefile.am (libgcrypt_la_SOURCES): Add hwf-common.h + (EXTRA_libgcrypt_la_SOURCES): New. + (gcrypt_hwf_modules): New. + (libgcrypt_la_DEPENDENCIES, libgcrypt_la_LIBADD): Add that one. + * src/hwfeatures.c: Factor most code out to ... + * src/hwf-x86.c: New file. + (detect_x86_gnuc): Return the feature vector. + (_gcry_hwf_detect_x86): New. + * src/hwf-common.h: New. + * src/hwfeatures.c (_gcry_detect_hw_features): Dispatch using + HAVE_CPU_ARCH_ macros. + +2012-12-21 Jussi Kivilinna + + Clean up i386/x86-64 cpuid usage in hwfeatures.c. + + commit d842eea55e22c05da3959a7a4422b5fcd7884f60 + * src/hwfeatures.c [__i386__ && __GNUC__] (detect_ia32_gnuc): Remove. + [__x86_64__ && __GNUC__] (detect_x86_64_gnuc): Remove. + [__i386__ && __GNUC__] (is_cpuid_available, get_cpuid) + (HAS_X86_CPUID): New. + [__x86_64__ && __GNUC__] (is_cpuid_available, get_cpuid) + (HAS_X86_CPUID): New. + [HAS_X86_CPUID] (detect_x86_gnuc): New. + (_gcry_detect_hw_features) [__i386__ && GNUC]: Remove detect_ia32_gnuc + call. + (_gcry_detect_hw_features) [__x86_64__ && GNUC]: Remove + detect_x86_64_gnuc call. + (_gcry_detect_hw_features) [HAS_X86_CPUID]: Add detect_x86_gnuc call. + +2012-12-18 Dmitry Kasatkin + + Add support for using DRNG random number generator. + + commit efd7002188e6d50013e4d9a920a8b9afa9d210e5 + * configure.ac: Add option --disable-drng-support. + (ENABLE_DRNG_SUPPORT): New. + * random/rndhw.c (USE_DRNG): New. + (rdrand_long, rdrand_nlong, poll_drng): New. + (_gcry_rndhw_poll_fast, _gcry_rndhw_poll_slow): Call poll function. + * src/g10lib.h (HWF_INTEL_RDRAND): New. + * src/global.c (hwflist): Add "intel-rdrand". + * src/hwfeatures.c (detect_x86_64_gnuc) [ENABLE_DRNG_SUPPORT]: Detect + RDRAND. + (detect_ia32_gnuc) [ENABLE_DRNG_SUPPORT]: Detect RDRAND. + +2012-12-03 Werner Koch + + random: Add a RNG selection interface and system RNG wrapper. + + commit 7607ab81504ce44060ed0b331d309606f5da1e75 + * random/random-system.c: New. + * random/Makefile.am (librandom_la_SOURCES): Add new module. + * random/random.c (struct rng_types): New. + (_gcry_set_preferred_rng_type, _gcry_get_rng_type): New. + (_gcry_random_initialize, gcry_random_add_bytes, do_randomize) + (_gcry_set_random_seed_file, _gcry_update_random_seed_file) + (_gcry_fast_random_poll): Dispatch to the actual RNG. + * src/gcrypt.h.in (GCRYCTL_SET_PREFERRED_RNG_TYPE): New. + GCRYCTL_GET_CURRENT_RNG_TYPE): New. + (gcry_rng_types): New. + * src/global.c (print_config): Print the TNG type. + (global_init, _gcry_vcontrol): Implement the new control codes. + * doc/gcrypt.texi (Controlling the library): Document the new control + codes. + + * tests/benchmark.c (main): Add options to test the RNG types. + * tests/random.c (main): Add new options. + (print_hex): Print to stderr. + (progress_cb, rng_type): New. + (check_rng_type_switching, check_early_rng_type_switching): New. + (run_all_rng_tests): New. + + tests: Allow use of random.c under Windows. + + commit 76c622e24a07f7c826812be173aa173b4334776b + * tests/Makefile.am (TESTS): Always include random.c + * tests/random.c [!W32]: Include sys/wait.h. + (inf): New. + (check_forking, check_nonce_forking): Print a notice what will be done. + (main) [W32]: Do not call signal. + + Make random-fips.c work multi-threaded. + + commit 75760021b511ba438606af746431223357e7a155 + * random/random-fips.c (basic_initialization): Fix reversed logic. + + Move nonce creation from csprng backend to random main module. + + commit c324644aa14e54fc7051983b38222db32b8ab227 + * random/random-csprng.c (_gcry_rngcsprng_create_nonce): Remove. + (nonce_buffer_lock): Remove. + (initialize_basics): Remove init of nonce_buffer_lock. + * random/random.c: Add a few header files. + (nonce_buffer_lock): New. + (_gcry_random_initialize): Init nonce_buffer_lock. + (gcry_create_nonce): Add code from _gcry_rngcsprng_create_nonce. + + * random/random-daemon.c (_gcry_daemon_create_nonce): Remove. + +2012-12-03 Jussi Kivilinna + + Fix building with CC="gcc -std=c90". + + commit f851b9a932ee64fa5a06000d1ac763ba4349f07d + * configure.ac: Add check for missing 'asm' keyword in C90 mode and + replacement with '__asm__'. + +2012-12-03 Werner Koch + + Try to use inttypes.h if stdint.h is not available. + + commit d9ec7aec1301b13a89e5c9c54d7ad52e1a29b846 + * cipher/bufhelp.h [HAVE_INTTYPES_H]: Include inttypes.h + +2012-12-03 Jussi Kivilinna + + Optimize buffer xoring. + + commit 162791bc08f4fc9b3882671e68ecdfd9e130ae59 + * cipher/Makefile.am (libcipher_la_SOURCES): Add 'bufhelp.h'. + * cipher/bufhelp.h: New. + * cipher/cipher-aeswrap.c (_gcry_cipher_aeswrap_encrypt) + (_gcry_cipher_aeswrap_decrypt): Use 'buf_xor' for buffer xoring. + * cipher/cipher-cbc.c (_gcry_cipher_cbc_encrypt) + (_gcry_cipher_cbc_decrypt): Use 'buf_xor' for buffer xoring and remove + resulting unused variables. + * cipher/cipher-cfb.c (_gcry_cipher_cfb_encrypt) Use 'buf_xor_2dst' + for buffer xoring and remove resulting unused variables. + (_gcry_cipher_cfb_decrypt): Use 'buf_xor_n_copy' for buffer xoring and + remove resulting unused variables. + * cipher/cipher-ctr.c (_gcry_cipher_ctr_encrypt): Use 'buf_xor' for + buffer xoring and remove resulting unused variables. + * cipher/cipher-ofb.c (_gcry_cipher_ofb_encrypt) + (_gcry_cipher_ofb_decrypt): Use 'buf_xor' for buffer xoring and remove + resulting used variables. + * cipher/rijndael.c (_gry_aes_cfb_enc): Use 'buf_xor_2dst' for buffer + xoring and remove resulting unused variables. + (_gry_aes_cfb_dev): Use 'buf_xor_n_copy' for buffer xoring and remove + resulting unused variables. + (_gry_aes_cbc_enc, _gry_aes_ctr_enc, _gry_aes_cbc_dec): Use 'buf_xor' + for buffer xoring and remove resulting unused variables. + +2012-11-29 Jussi Kivilinna + + Optimize AES-NI CTR mode. + + commit 9ee9e25f519696d509b1a5c1cc04ab0121e98a51 + * cipher/rijndael.c [USE_AESNI] (do_aesni_ctr, do_aesni_ctr_4): Make + handling of 64-bit overflow and carry conditional. Avoid generic to + vector register passing of value '1'. Generate and use '-1' instead. + +2012-11-28 Werner Koch + + Make a cpp conditional in rijndael.c better readable. + + commit 6765e0a8618000d3dc7bda035163e0708c43791b + * cipher/rijndael.c (USE_AESNI): Modify cpp conditionals for better + readability. + +2012-11-28 Jussi Kivilinna + + Fix building with Clang on x86-64 and i386. + + commit 99e272d938fe23efec25af409bdb91dae0e659e5 + * cipher/rijndael.c [USE_AESNI] (do_aesni_enc_aligned) + (do_aesni_dec_vec4, do_aesni_cfb, do_aesni_ctr, do_aesni_ctr_4): Add + explicit suffix to 'cmp' instructions. + +2012-11-26 Jussi Kivilinna + + Optimize wipememory2 for i386 and x86-64. + + commit faec12e23f03c7cd1614594bfdd51f1302cadb42 + * src/g10lib.h (wipememory2): Add call to fast_wipememory2. + (fast_wipememory2): New macros for i386 and x86-64 architectures. + Empty macro provided for other architectures. + + Fix missing 64bit carry handling in AES-NI CTR mode. + + commit fc37e805c6394c2e635d1a033670be961f36a6d2 + * cipher/rijndael.c [USE_AESNI] (do_aesni_ctr, do_aesni_ctr_4): Add + carry handling to 64-bit addition. + (selftest_ctr_128): New function for testing IV handling in bulk CTR + function. + (selftest): Add call to selftest_ctr_128. + + Add parallelized AES-NI CBC decryption. + + commit 35aff0cd43885b5f5c076432ec614698abeb63d8 + * cipher/rijndael.c [USE_AESNI] (aesni_cleanup_5): New macro. + [USE_AESNI] (do_aesni_dec_vec4): New function. + (_gcry_aes_cbc_dec) [USE_AESNI]: Add parallelized CBC loop. + (_gcry_aes_cbc_dec) [USE_AESNI]: Change IV storage register from xmm3 + to xmm5. + + Clear xmm5 after use in AES-NI CTR mode. + + commit 5acd0e5ae2a58dda51c2b56c879b80a1a6d2c42f + * cipher/rijndael.c [USE_AESNI]: Rename aesni_cleanup_2_4 to + aesni_cleanup_2_5. + [USE_AESNI] (aesni_cleanup_2_5): Clear xmm5 register. + (_gcry_aes_ctr_enc, _gcry_aes_cbc_dec) [USE_AESNI]: Use + aesni_cleanup_2_5 instead of aesni_cleanup_2_4. + + Optimize AES-NI CBC encryption. + + commit be3768994ad362dfc849a8cd0146b4c9bb287d20 + * cipher/rijndeal.c (_gcry_aes_cbc_enc) [USE_AESNI]: Add AES-NI + spesific loop and use SSE2 assembler for xoring and copying of + blocks. + + Improve parallelizability of CBC decryption for AES-NI. + + commit 3369d960158ab4231b83926a0f982e2a8819f173 + * cipher/rijndael.c (_gcry_aes_cbc_dec) [USE_AESNI]: Add AES-NI + specific CBC mode loop with temporary block and IV stored in free SSE + registers. + + Extend test of chained modes for 128bit ciphers. + + commit 55b96be08531664ed3f4230acebe0f45954bbc33 + * tests/basic.c (check_one_cipher_core, check_one_cipher): Increase + input and output buffer sizes from 16 bytes to 1024+16=1040 bytes. + (check_one_cipher_core): Add asserts to verify sizes of temporary + buffers. + +2012-11-21 Werner Koch + + Fix for strict aliasing rules. + + commit dfb4673da8ee52d95e0a62c9f49ca8599943f22e + * cipher/rijndael.c (do_setkey, prepare_decryption): Use u32_a_t for + casting. + + Do not detect AES-NI support if disabled by configure. + + commit 3047795794eb238aa684bd0729acf64c82a19e09 + * src/hwfeatures.c (detect_ia32_gnuc): Detect AESNI support only if + that support has been enabled. + +2012-11-21 Jussi Kivilinna + + Fix too large burn_stack in camellia-glue.c. + + commit 8afabc2813948778a3db52d9dee9a041a3dd50d4 + * cipher/camellia-glue.c (camellia_encrypt, camellia_decrypt): Do not + take full array size of KEY_TABLE_TYPE, but argument size instead. + + Add x86_64 support for AES-NI. + + commit d8bdfa42ed582655c180e7db9b16d4e756a12a6e + * cipher/rijndael.c [ENABLE_AESNI_SUPPORT]: Enable USE_AESNI on x86-64. + (do_setkey) [USE_AESNI_is_disabled_here]: Use %[key] and %[ksch] + directly as registers instead of using temporary register %%esi. + [USE_AESNI] (do_aesni_enc_aligned, do_aesni_dec_aligned, do_aesni_cfb, + do_aesni_ctr, do_aesni_ctr_4): Use %[key] directly as register instead + of using temporary register %%esi. + [USE_AESNI] (do_aesni_cfb, do_aesni_ctr, do_aesni_ctr_4): Change %[key] + from generic "g" type to register "r". + * src/hwfeatures.c (_gcry_detect_hw_features) [__x86_64__]: Do not + clear AES-NI feature flag. + + Fix cpuid vendor-id check for i386 and x86-64. + + commit 9e1552517f68459a165ddebbba85e7cf37ff4f0c + * src/hwfeatures.c (detect_x86_64_gnuc, detect_ia32_gnuc): Allow + Intel features be detect from CPU by other vendors too. + + Fix hwdetect assembler clobbers. + + commit 19b9efd1f47a5de9c450ce8212dfa3174a029c7a + * src/hwfeatures.c (detect_x86_64_gnuc): Add missing %ebx assembler + clobbers. + (detect_x86_64_gnuc, detect_ia32_gnuc) [ENABLE_PADLOCK_SUPPORT]: Add + missing %ecx assembler clobbers. + +2012-11-21 Werner Koch + + Use configure test for aligned attribute. + + commit 6368ed542150956ff4ba8170a15bbc534143675c + * configure.ac (HAVE_GCC_ATTRIBUTE_ALIGNED): New test and ac_define. + * cipher/cipher-internal.h, cipher/rijndael.c, random/rndhw.c: Use new + macro instead of a fixed test for __GNUC__. + + Fix segv with AES-NI on some platforms. + + commit a96974de734beb51a733a89b3283bcf7b433b54c + * cipher/rijndael.c (RIJNDAEL_context): Align on 16 bytes. + +2012-11-16 Werner Koch + + Improve parsing of the GIT revision number. + + commit 4b18e530f417d4af401a3fd721ad2a07e5310e3e + * configure.ac (mmm4_revision): Use git rev-parse. + +2012-11-08 Werner Koch + + Fix extern inline use for gcc > 4.3 in c99 mode. + + commit 5abc06114e91beca0177331e1c79815f5fb6d7be + * mpi/mpi-inline.h [!G10_MPI_INLINE_DECL]: Take care of changed extern + inline semantics in gcc. + +2012-11-07 Werner Koch + + Fix memory leak in gcry_pk_testkey for ECC. + + commit 8cbbad5f94f6e0429fffe66d689aea20f7e35957 + * cipher/ecc.c (check_secret_key): Restructure for easier allocation + tracking. Fix memory leak. + +2012-11-05 Werner Koch + + Prepare for a backported interface in 1.5.1. + + commit 7af98ef78d45e813f47ae4e180a02757a379953f + * configure.ac: Bump LT version at C20/A0/R0 to adjust for a planned + API update in 1.5.1. + + Adjust for stricter autoconf requirements. + + commit 1241fbbc896e9bbad68f1007a17b20493f6cd1af + * configure.ac: Fix usage of AC_LANG_PROGRAM. + + Update build helper scripts. + + commit a5c4d45e8d12737cd21b095c81da5c18e2afc39e + * config.guess, config.sub: Update to version 2012-07-31. + * ltmain.sh: Update to version 2.4.2. + * install-sh, m4/libtool.m4, m4/ltoptions.m4, m4/ltversion.m4 + * m4/lt~obsolete.m4: Update to autoconf 2.69 versions. + + Do not distribute a copy of gitlog-to-changelog. + + commit 40976d7da5420453bf93a9c99f0cc4c7044d0774 + * Makefile.am (GITLOG_TO_CHANGELOG): New. + (gen-ChangeLog): Require an installed gitlog-to-changelog. + * scripts/gitlog-to-changelog: Remove. + + * README.SVN: Remove. + * REMOVE.GIT: New. + + Allow building with w64-mingw32. + + commit 4f6fb150558d0ed250bfbd50352c258a4456ba50 + * autogen.sh <--build-w32>: Support the w64-mingw32 toolchain. Also + prepare for 64 bit building. + : Remove option -c from chmod. + + Switch to the new automagic beta numbering scheme. + + commit 7d5195be76d9dd4adc28976ad153e8f7761c5855 + * configure.ac: Add all the required m4 magic. + + Avoid dereferencing pointer right after the end. + + commit 79502e2c1982047dcf2b776f52826f38bbd9b1fe + * mpi/mpicoder.c (do_get_buffer): Check the length before derefing P. + +2012-10-30 Werner Koch + + Make ancient test program useful again. + + commit 66adf76e634423bb72ce1f0b5ed78f4e4798f190 + * tests/testapi.c (test_sexp): Adjust to current API. Print the + return code. Mark unused args. + (test_genkey): Mark unused args. + (main): Do not pass NULL to printf. + + tests: Add ECC key generation tests. + + commit c13164884ade6b1e945cddacce2d244fd881de6b + * tests/keygen.c (check_generated_ecc_key): New. + (check_ecc_keys): New. + (main): Call simple ECC checks. + +2012-10-30 Milan Broz + + PBKDF2: Allow empty passphrase. + + commit 8528f1ba40e587dc17e02822e529fbd7ac69a189 + * cipher/kdf.c (gcry_kdf_derive): Allow empty passphrase for PBKDF2. + * tests/t-kdf.c (check_pbkdf2): Add test case for above. + +2012-08-16 Xi Wang + + Replace deliberate division by zero with _gcry_divide_by_zero. + + commit 2c54c4da19d3a79e9f749740828026dd41f0521a + * mpi/mpi-pow.c: Replace 1 / msize. + * mpi/mpih-div.c: Replace 1 / dsize. + * src/misc.c: Add _gcry_divide_by_zero. + +2012-06-21 Werner Koch + + Clear AESNI feature flag for x86_64. + + commit 2196728e2252917849c1be94417258076767021b + * src/hwfeatures.c (_gcry_detect_hw_features) [__x86_64__]: Clear + AESNI feature flag. + + Beautify last change. + + commit 20e423212c9710ee663e12dd0f62580ceb245a6f + * cipher/rijndael.c: Replace C99 feature from last patch. Keep cpp + lines short. + * random/rndhw.c: Keep cpp lines short. + * src/hwfeatures.c (_gcry_detect_hw_features): Make cpp def chain + better readable. + +2012-06-21 Rafaël Carré + + Enable VIA Padlock on x86_64 platforms. + + commit baf0dc7e9c26167ab43ba2adebcf2f1abc9d9b3b + * cipher/rijndael.c: Duplicate x86 assembly and convert to x86_64. + * random/rndhw.c: Likewise. + * src/hwfeatures.c: Likewise. + +2012-05-14 Werner Koch + + Add curve aliases from RFC-5656. + + commit 39c123b729a472ace039f8536d07f8b9a5f4675a + * cipher/ecc.c (curve_aliases): Add "nistp???" entries. + +2012-04-16 Werner Koch + + State new contribution rules. + + commit 3bb858551cd5d84e43b800edfa2b07d1529718a9 + * doc/DCO: New. + * doc/HACKING: Document new rules. + +2012-04-04 Tomas Mraz + + Add GCRYCTL_SET_ENFORCED_FIPS_FLAG command. + + commit 90e49a11733bfba9c3c505ac487282d35757f682 + * doc/gcrypt.texi: Add documentation of the new command. + * src/fips.c (_gcry_enforced_fips_mode): Report the enforced fips mode + only when fips mode is enabled. + (_gcry_set_enforced_fips_mode): New function. + * src/g10lib.h: Add the _gcry_set_enforced_fips_mode prototype. + * src/gcrypt.h.in: Add the GCRYCTL_SET_ENFORCED_FIPS_FLAG. + * src/global.c (_gcry_vcontrol): Handle the new command. + +2012-02-17 Ulrich Müller + + Rework selftest in idea.c. + + commit 70cca617ed75ea292e1fed769114dda5cc1d76f1 + * cipher/idea.c (do_setkey): Execute selftest when first called. + (decrypt_block): Remove commented-out code. + (selftest): Execute all selftests. Return NULL on success, or + string in case of error. + +2012-02-16 Werner Koch + + Fix missing prototype. + + commit 46035d28c9b413851d43a4008fdc8e4cdf5d686b + * src/g10lib.h (_gcry_secmem_module_init): Make it a real prototype. + +2012-02-16 Ulrich Müller + + Add support for the IDEA cipher. + + commit 318fd85f377c060908d371f792d41e599b3b7483 + Adapt idea.c to the Libgcrypt framework. + Add IDEA to cipher_table and to the build system. + + Patents on IDEA have expired: + Europe: EP0482154 on 2011-05-16, + Japan: JP3225440 on 2011-05-16, + U.S.: 5,214,703 on 2012-01-07. + + * configure.ac: Add idea to the list of available ciphers. + Define USE_IDEA if idea is enabled. + * cipher/cipher.c (cipher_table): Add entry for IDEA. + * cipher/idea.c: Update comment about patents. + Include proper header files and remove redundant declarations. + (expand_key, cipher, do_setkey, encrypt_block, decrypt_block): + Define function arguments as const where appropriate. + (cipher): Test for !WORDS_BIGENDIAN instead of LITTLE_ENDIAN_HOST. + (do_setkey, decrypt_block): Don't call selftest. + (idea_setkey): New function, wrapper for do_setkey. + (idea_encrypt): New function, wrapper for encrypt_block. + (_gcry_cipher_spec_idea): Define. + * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add idea.c. + * src/cipher.h (_gcry_cipher_spec_idea): Declare. + * tests/basic.c (check_ciphers): Add GCRY_CIPHER_IDEA. + +2012-01-09 Werner Koch + + Include an IDEA implementation. + + commit 6078b05f5340d886e0b9e6cee1d9b5043e0cb210 + The code is the old IDEA test code, written by me back in 1997 and + distributed on a Danish FTP server. This commit is only for + reference. To use the code it has to be adjusted to the Libgcrypt + framework. + +2012-01-03 Marcus Brinkmann + + Fix pthread locking and remove defunctional support for static lock init. + + commit 38fcd59ce774eaa3d65f2f7534c989afd860eb56 + * src/ath.c: Include assert.h. + (ath_mutex_destroy, ath_mutex_lock, ath_mutex_unlock): Dereference LOCK. + * src/g10lib.h (_gcry_secmem_module_init): New declaration. + * src/global.c (global_init): Call _gcry_secmem_module_init. + * src/secmem.c (_gcry_secmem_module_init): New function. + +2011-12-16 Werner Koch + + Add alignment tests for the cipher tests. + + commit 14cf1f7e338fedb8edaff5631441746605152bd6 + * tests/basic.c (check_one_cipher): Factor most code out to + check_one_cipher_core. Call that core function several times using + different alignment settings. + (check_one_cipher_core): New. Add extra args to allow alignment + testing. + +2011-12-07 Werner Koch + + tests/prime: Add option to create a well known private key. + + commit 16f5654643d584e3bc739b636752d779176b2191 + * tests/prime.c (print_mpi, create_42prime): New. + (main): Add option --42. + +2011-12-01 Werner Koch + + Do not build the random-daemon by make distcheck. + + commit ea1fb538d99f1ec093f2fef86f4f29176ec27826 + * Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Disable building of the + random daemon + + Generate the ChangeLog from commit logs. + + commit 137d73191c904926ba529376144ee8239af4ca02 + * scripts/gitlog-to-changelog: New script. Taken from gnulib. + * scripts/git-log-fix: New file. + * scripts/git-log-footer: New file. + * doc/HACKING: Describe the ChangeLog policy + * ChangeLog: New file. + * Makefile.am (EXTRA_DIST): Add new files. + (gen-ChangeLog): New. + (dist-hook): Run gen-ChangeLog. + + Rename all ChangeLog files to ChangeLog-2011. + +2011-12-01 Werner Koch + + NB: Changes done before December 1st, 2011 are described in + per directory files named ChangeLog-2011. See doc/HACKING for + details. + + ----- + Copyright (C) 2011 Free Software Foundation, Inc. + + Copying and distribution of this file and/or the original GIT + commit log messages, with or without modification, are + permitted provided the copyright notice and this notice are + preserved. diff --git a/comm/third_party/libgcrypt/ChangeLog-2011 b/comm/third_party/libgcrypt/ChangeLog-2011 new file mode 100644 index 0000000000..3c70a1f8e9 --- /dev/null +++ b/comm/third_party/libgcrypt/ChangeLog-2011 @@ -0,0 +1,1499 @@ +2011-12-01 Werner Koch + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2011-11-28 Jim Meyering + + accept --with-libgpg-error-prefix as well as --with-gpg-error-prefix + * m4/gpg-error.m4: Update from git master. + +2011-09-16 Werner Koch + + * configure.ac (HAVE_PTHREAD): New. + +2011-09-15 Werner Koch + + * configure.ac: Bump LT version at C19/A0/R0 due to the ABI change. + + * configure.ac (CC_FOR_BUILD): New. + +2011-06-29 Werner Koch + + Release 1.5.0. + + * configure.ac: Keep LT version at C18/A7/R0 because it has + already been bumped up at 2010-07-09. + + * config.guess, config.sub: Update to 2011-06-03. + +2011-04-06 Werner Koch + + * configure.ac (emacs_local_vars_begin): Move more to the top to + avoid Emacs warnings. + +2011-03-30 Werner Koch + + * compat/compat.c (_gcry_compat_identification): Add version string. + +2011-03-08 Werner Koch + + * configure.ac (BUILD_REVISION): Use new git_brevis macro. + +2011-02-23 Werner Koch + + * configure.ac (LIBGCRYPT_CONFIG_HOST): New. + + * acinclude.m4 (AM_PATH_GPG_ERROR): Remove. + +2011-02-21 Werner Koch + + Release 1.5.0-beta1. + +2011-02-18 Werner Koch + + * configure.ac [GCC]: Remove the use of -fno-strict-aliasing. + +2011-02-11 Werner Koch + + * configure.ac: Add option --disbale-aesni-support. + (ENABLE_AESNI_SUPPORT): New macro. + +2011-02-04 Werner Koch + + * autogen.sh: Install the git pre-commit if not yet done. + +2010-12-23 Werner Koch + + * configure.ac (BUILD_REVISION): Use git_revision. + +2010-08-19 Werner Koch + + * configure.ac: Define GPG_ERR_ENABLE_ERRNO_MACROS. Remove + definition of _GNU_SOURCE. + (AC_GNU_SOURCE): New. + +2010-08-16 Werner Koch + + * configure.ac (INSERT_SYS_SELECT_H): New. + +2010-07-09 Werner Koch + + * configure.ac: Bump LT version to C18/A7/R0 to prepare a backport + of a new API to the 1.4 series. + +2010-04-19 Marcus Brinkmann + + * configure.ac: Check for -fno-strict-aliasing. + +2010-04-12 Brad Hards (wk) + + * configure.ac: Print more verbose info at the end. + +2010-03-24 Werner Koch + + * configure.ac (USE_RNDW32CE): New. + +2010-03-15 Werner Koch + + * configure.ac (emacs_local_vars_begin) + (emacs_local_vars_read_only, emacs_local_vars_end): New. + +2010-01-21 Werner Koch + + * compat/Makefile.am: New. + * compat/compat.c: New. + * compat/libcompat.h: New. + * compat/getpid.c, compat/clock.c: New. + + * configure.ac: Require libgpg-error 1.8. + (HAVE_W32CE_SYSTEM): New am_defines and am_conditionals. + (getpid): Check for replacement function. + (AC_CONFIG_LIBOBJ_DIR): New. + (AC_TYPE_PID_T): New. + (AM_INIT_AUTOMAKE): Use modern variant. + (AC_CONFIG_FILES): Add compat/Makfile. + * autogen.sh: Support W32CE. + * ltmain.sh: Update to 2.2.6b + (wrappers_required): Don't set for mingw32ce. + * Makefile.am (DIST_SUBDIRS, SUBDIRS): Add compat. + +2009-12-10 Werner Koch + + * configure.ac: Add option --disable-O-flag-munging. + +2009-12-08 Marcus Brinkmann + + Update to libtool 2.2.6a. + * configure.ac: Invoke AC_CONFIG_MACRO_DIR. + (AC_LIBTOOL_WIN32_DLL, AC_LIBTOOL_RC): Replace by ... + (LT_PREREQ, LT_INIT, LT_LANG): ... these. + * config.guess, config.sub, install-sh, ltmain.sh, m4/libtool.m4: + Updated to libtool 2.2.6a. + * m4/ltoptions.m4, m4/ltsugar.m4, m4/ltversion.m4, + m4/lt~obsolete.m4: New files from libtool 2.2.6a. + +2009-08-05 Werner Koch + + * configure.ac: Test for sys/msg.h. + +2009-04-23 Werner Koch + + * README: Add a section on build problems. + +2009-01-22 Werner Koch + + * configure.ac: Bump LT version to C17/A6/R0 to mark the start of + a new development series. + +2009-01-22 Werner Koch + + Release 1.4.4. + + * configure.ac: Bump LT version to C16/A5/R2. + +2008-10-30 Werner Koch + + * configure.ac: Remove option --enable-gcc-warnings. Autodetect + useful gcc warnings in maintainer mode. + +2008-09-18 Werner Koch + + Release 1.4.3. + + * configure.ac: Bump LT version to C16/A5/R1. + +2008-09-15 Werner Koch + + * configure.ac: Cehck for syslog. + +2008-09-08 Werner Koch + + Release 1.4.2. + +2008-09-01 Werner Koch + + Release 1.4.2rc2. + + * configure.ac: Update svn_revision macro. + +2008-08-22 Werner Koch + + * configure.ac: Add option --enable-hmac-binary-check. + (DL_LIBS): Check whether -ldl is required. + +2008-08-19 Werner Koch + + Release 1.4.2rc1. + + * configure.ac: Bump LT version to C16/A5/R0. + +2008-08-18 Werner Koch + + * Makefile.am (EXTRA_DIST): Remove the unused BUGS file. + +2008-08-15 Werner Koch + + * configure.ac (AH_BOTTOM): Define GCRY_GPG_ERR_NOT_OPERATIONAL. + +2008-07-05 Werner Koch + + * random/: New. + * Makefile.am (DIST_SUBDIRS): Add random. + * configure.ac (AC_CONFIG_FILES): Add random/Makefile. + +2008-04-25 Werner Koch + + Release 1.4.1. + + * configure.ac: Bump LT version to C15/A4/R4. + +2008-04-22 Werner Koch + + * configure.ac: Set version to 1.4.1rc1. + +2008-04-18 Werner Koch + + * configure.ac (AH_BOTTOM): Add CAMELLIA_EXT_SYM_PREFIX. + (NAME_OF_DEV_RANDOM): Remove special cases for Solaris etc. This + matches the gnupg 1.4.9 version. + +2008-04-01 Werner Koch + + * configure.ac (AC_INIT): Fix quoting. + +2008-03-19 Werner Koch + + * configure.ac: Fix the tests for USE_ to either define or + undef the macros. Suggested by Dirk Stoecker. + +2008-03-18 Werner Koch + + * configure.ac: Test for uintptr_t. + +2008-02-18 Werner Koch + + * configure.ac (IS_DEVELOPMENT_VERSION): Set depending on the my_svn. + +2007-12-11 Werner Koch + + * configure.ac: We actually require libgpg-error 1.4. Reported by + Tim Mooney. + +2007-12-10 Werner Koch + + Released 1.4.0. + + * configure.ac: Set LT to C15/A4/R3. + +2007-12-05 Werner Koch + + * configure.ac: Add option --disable-padlock-support. + +2007-12-03 Werner Koch + + Released 1.3.2. + + * configure.ac: Set LT to C15/A4/R2. + + * config.sub, config.guess: Update to version 2007-11-19. + +2007-10-30 Werner Koch + + * configure.ac: Protect config.h against double inclusion. + +2007-10-26 Werner Koch + + Released 1.3.1. + + * configure.ac: Set LT to C15/A4/R1. + +2007-08-22 Werner Koch + + * README: Rewrite the license description. + * configure.ac (USE_RNDW32, USE_RNDUNIX): Unmark as GPL modules. + +2007-08-08 Werner Koch + + * configure.ac: Use $host and not $target. + +2007-07-26 Werner Koch + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Fix a syntax error + in the test program which lurked there for 4 years. Adjusted name + of libtools global_system_pipe variable and add extra cut stage. + Reported by Gregor Riepl. + +2007-06-15 Werner Koch + + * autogen.sh (FORCE): Use = and not == in test to be POSIXly correct. + +2007-05-30 Werner Koch + + * configure.ac: Camellia is no longer GPL. + +2007-05-24 Werner Koch + + * configure.ac: Try to use -Wpointer-arith. + +2007-05-19 Marcus Brinkmann + + * configure.ac: Fix test for optional UDIV and UDIV_QRNND MPI + modules. + +2007-05-09 Marcus Brinkmann + + * configure.ac (ac_cv_mpi_config_done): Unused variable removed. + (ac_cv_mpi_mod_list, MPI_MOD_LIST_LO, MPI_MOD_LIST_O): Removed. + (MPI_MOD_ASM_MPIH_ADD1, MPI_MOD_ASM_MPIH_SUB1, + MPI_MOD_ASM_MPIH_MUL1, MPI_MOD_ASM_MPIH_MUL2, + MPI_MOD_ASM_MPIH_MUL3, MPI_MOD_ASM_MPIH_LSHIFT, + MPI_MOD_ASM_MPIH_RSHIFT, MPI_MOD_ASM_MPIH_UDIV, + MPI_MOD_ASM_MPIH_UDIV_QRNND, MPI_MOD_C_MPIH_ADD1, + MPI_MOD_C_MPIH_SUB1, MPI_MOD_C_MPIH_MUL1, MPI_MOD_C_MPIH_MUL2, + MPI_MOD_C_MPIH_MUL3, MPI_MOD_C_MPIH_LSHIFT, MPI_MOD_C_MPIH_RSHIFT, + MPI_MOD_C_MPIH_UDIV, MPI_MOD_C_MPIH_UDIV_QRNND): New automake + variables. + +2007-05-04 Werner Koch + + Released 1.3.0. + + * configure.ac: Set LT to C15/A4/R0. + + * configure.ac: Require automake 1.10 + (AM_PROG_CC_C_O): New. + +2007-05-03 Werner Koch + + * configure.ac: Fix detection of GPLed random modules. + +2007-05-02 Werner Koch + + * configure.ac (LIBGCRYPT_DIGESTS, LIBGCRYPT_CIPHERS) + (LIBGCRYPT_PUBKEY_CIPHERS): Ac_define lists of algorithms. + (default_ciphers): Don't make camellia a default. + +2007-05-02 David Shaw + + * NEWS, configure.ac: Add Camellia. + +2007-04-30 Werner Koch + + * README.apichanges: Move to doc/. + * Makefile.am (EXTRA_DIST): Removed that file. + +2007-04-28 Marcus Brinkmann + + * configure.ac: Allow to specify additional search directories + with --enable-mpi-path. + +2007-04-16 Werner Koch + + * configure.ac: Check for sysconf. + * acinclude.m4 (GNUPG_CHECK_MLOCK): Try to use sysconf to get the + page size and use getpagesize only then if available. + +2007-03-22 Werner Koch + + * configure.ac: Add support for ECC. + +2007-02-22 Werner Koch + + * Makefile.am (DISTCHECK_CONFIGURE_FLAGS): Use + --enable-random-daemon. + + * configure.ac: New option --enable-random-daemon. + Create versioninfo.rc and provide the build information. + +2007-02-21 Werner Koch + + * Makefile.am, configure.ac: Ignore w32-dll/. + +2007-02-20 Werner Koch + + * configure.ac: Bump LT version to C14/A3/R0 in preparation for a + release. + + * autogen.sh: Add option --force. + * configure.ac: New option --disable-endian-check. Use a real + noexecstack test instead of requiring an option. Add SVN version + magic. + +2007-02-02 Werner Koch + + * configure.ac (FALLBACK_SOCKLEN_T): Special case for mingw32. + +2006-11-15 Werner Koch + + * autogen.sh: Add convenience option --build-amd64. + +2006-10-20 Werner Koch + + * Makefile.am (stowinstall): New convenience target. + +2006-10-12 Marcus Brinkmann + + * configure.ac (FALLBACK_SOCKLEN_T): Third time is a charm. + Define gcry_socklen_t, to avoid conflicts with socklen_t + definitions by autoconf. + +2006-10-11 Marcus Brinkmann + + * configure.ac (FALLBACK_SOCKLEN_T): Rewrite in terms of + socklen.m4. + +2006-10-11 Marcus Brinkmann + + * acinclude.m4 (GNUPG_FIX_HDR_VERSION): Removed. + * configure.ac: Do not call GNUPG_FIX_HDR_VERSION. + +2006-10-10 Marcus Brinkmann + + * configure.ac: Invoke AC_CHECK_SOCKLEN_TYPE. + (AC_CONFIG_FILES): Add src/gcrypt.h. + (AC_CONFIG_SRCDIR): Change to src/libgcrypt.vers. + +2006-10-02 Werner Koch + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Test on HOST and not + TARGET. Hardwire for mingw32. Allow setting via command line when + cross compiling. + +2006-08-29 Werner Koch + + * configure.ac (USE_SEED): New. + +2006-07-26 Werner Koch + + * configure.ac: New options --enable-noexecstack and + --disable-optimization. + +2006-07-04 Marcus Brinkmann + + * configure.ac: Call AC_LIBTOO_WIN32_DLL and AC_LIBTOOL_RC. + + * configure.ac: Call gl_TYPE_SOCKLEN_T instead of the other + socklen_t checks. + +2006-06-08 Marcus Brinkmann + + * configure.ac (PTH_LIBS): Add --all to pth-config invocation. + +2006-03-14 Werner Koch + + * configure.ac: Check for fctnl and ftruncate. + (HAVE_PTH): Check for GNU Pth. + (HAVE_W32_SYSTEM): Define it. + * acinclude.m4 (GNUPG_PTH_VERSION_CHECK): New. Taken from GnuPG 1.4. + +2005-12-08 Werner Koch + + * configure.ac: Changed the random device names for netbsd. From + Christian Biere. + +2005-11-02 Moritz Schulte + + * NEWS: Documented minor API changes. + +2005-09-15 Moritz Schulte + + * Makefile.am (EXTRA_DIST): Depend on README.SVN, not on README.CVS. + +2005-06-25 Moritz Schulte + + * configure.ac: Removed src/libgcrypt.pc from AC_CONFIG_FILES. + +2005-06-10 Werner Koch + + * configure.ac: Move detection of basic stuff to the top. For + example we need to know whether gcc is used before testing for it. + Reported by Ralf Fassel. + +2005-04-23 Moritz Schulte + + * acinclude.m4 (TYPE_SOCKLEN_T): New type definition test; + provided by Albert Chin. + * configure.ac: Don't use $(CMD) as it's not portable; use CMD in + backticks instead. Simpler -lnsl/-lsocket test. Use + TYPE_SOCKLEN_T test. Don't forget to set `random_modules' + correctly. + +2005-04-22 Moritz Schulte + + * configure.ac: Added support for pkgconfig; provided by Albert + Chin. + +2005-04-11 Moritz Schulte + + * configure.ac: Integrate Whirlpool. + +2005-01-04 Werner Koch + + Updated to automake 1.9. + + * acinclude.m4: Updated for use with automake 1.9. + + * configure.ac: Require libgpg-error 1.0; not really needed but + that is the first stable version. + + * Makefile.am (ACLOCAL_AMFLAGS): New for -I m4. + (AUTOMAKE_OPTIONS): New to create a bzip archive. + +2005-02-03 Moritz Schulte + + * THANKS: Updated. + +2004-08-09 Moritz Schulte + + * THANKS: Updated. + +2004-07-04 Moritz Schulte + + * THANKS: Updated. + +2004-04-21 Werner Koch + + * configure.ac: Don't print a warning if GNU make was not found. + +2004-05-07 Moritz Schulte + + * THANKS: Updated. + +2004-04-02 Thomas Schwinge + + * autogen.sh: Added ACLOCAL_FLAGS. + +2004-04-15 Werner Koch + + Released 1.2.0. + + * configure.ac: Set LT to C12/A1/R1. + +2004-04-06 Werner Koch + + * config.guess, config.sub, ltmain.sh: Updated to those from + libtools 1.5.4. + +2004-03-29 Werner Koch + + Released 1.1.94. + + * configure.ac: Set LT to C12/A1/R0. + +2004-03-10 Marcus Brinkmann + + * configure.ac (LIBGCRYPT_CONFIG_LIBS_PTHREAD, + LIBGCRYPT_CONFIG_CFLAGS_PTHREAD, LIBGCRYPT_CONFIG_LIBS_PTH, + LIBGCRYPT_CONFIG_CFLAGS_PTH, have_pth, have_pthread, AC_CHECK_PTH, + AC_CHECK_LIB(pthread), HAVE_PTH, HAVE_PTHREAD): Removed. + +2004-03-06 Werner Koch + + Released 1.1.93. + + * configure.ac (LIBGCRYPT_CONFIG_SONAME_NUMBER): Replaced by + LIBGCRYPT_CONPIG_API_VERSION. Set it to 1. Set LT to C11/A0/R1. + +2004-03-05 Werner Koch + + * configure.ac (LIBGCRYPT_CONFIG_SONAME_NUMBER): New. + +2004-02-20 Werner Koch + + Released 1.1.92. + + * configure.ac: Set LT to C11/A0/R0. + +2004-02-11 Werner Koch + + * autogen.sh (check_version): Removed bashism and simplified. + +2004-02-06 Werner Koch + + * configure.ac: Add rfc2268 cipher algorithm. + +2004-01-25 Moritz Schulte + + * THANKS: Updated. + +2003-12-19 Werner Koch + + Released 1.1.91. + + * configure.ac: Bumbed LT version to C10/A3/R1. + +2003-12-08 Werner Koch + + * Makefile.am (dist-hook): Don't distribute stuff from the now + obsolete scripts dir. + (EXTRA_DIST): Remove README_alpha + * README-alpha: Removed. + * configure.ac (AM_CONFIG_AUX_DIR): Removed. + + * COPYING.DOC: Removed. + * Makefile.am (EXTRA_DIST): Added README.CVS and + autogen.sh. Removed COPYING.DOC. + +2003-11-14 Werner Koch + + Released 1.1.90. + + * configure.ac: Bumbed LT version to C10/A3/R0. + + * configure.ac (have_ld_version_script): Set the default in + a separate test. + (PRINTABLE_OS_NAME): Don't handle the Hurd extra, this leads to + conflicts with BSD based GNU systems. The Hurd has now a working + uname. + +2003-11-04 Werner Koch + + * configure.ac (USE_SHA1): Make sure it is always included. + (USE_RMD160): Removed this AM conditional. + +2003-10-31 Werner Koch + + * configure.ac: Bumbed version number to 1.1.90-cvs for futher + development + + Released 1.1.44. + + * acinclude.m4 (AC_CHECK_PTH): Added. + * configure.ac: Use it here instead of the generic lib test. + Bumbed LT vesion to C9/A2/R0. + +2003-10-27 Werner Koch + + * configure.ac: Give a hint on where libgpg-error is available. + Reformatted long lines. Don't include gcrypt-defs.h. + (--enable-gcc-warnings): New option. + +2003-10-24 Moritz Schulte + + * configure.ac: Check for socklen_t. + +2003-10-11 Moritz Schulte + + * acinclude.m4: Update AM_PATH_GPG_ERROR macro. + +2003-09-04 Werner Koch + + Released 1.1.43. + + * configure.ac: Require libgpg-error 0.4 due to the prime interface. + +2003-08-29 Werner Koch + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Re-implemented. + * configure.ac: Use it here. + +2003-08-27 Moritz Schulte + + * configure.ac: Substitute: LIBGCRYPT_CONFIG_LIBS_PTHREAD, + LIBGCRYPT_CONFIG_CFLAGS_PTHREAD, LIBGCRYPT_CONFIG_LIBS_PTH, + LIBGCRYPT_CONFIG_CFLAGS_PTH, LIBGCRYPT_THREAD_MODULES. + +2003-08-07 Moritz Schulte + + * configure.ac: Fail, if libgpg-error could not be found. + +2003-07-31 Werner Koch + + Released 1.1.42. + + * configure.ac: Set LT version to 7/0/0. + +2003-07-30 Werner Koch + + * AUTHORS (Maintainer): Assigned Moritz as Maintainer. + +2003-07-30 Moritz Schulte + + * NEWS: Include much more complete list of `Interface changes + relative to the 1.1.12 release'. + +2003-07-14 Moritz Schulte + + * configure.ac: Bumbed version number up to 1.1.42-cvs. + +2003-07-09 Moritz Schulte + + * configure.ac: Reintroduce --disable-asm, since it is needed by + mpi/config.links. + +2003-07-05 Moritz Schulte + + * README: Few changes, mention libgpg-error. + +2003-06-18 Moritz Schulte + + * configure.ac (available_ciphers): Removed Serpent, hrrm. + +2003-06-17 Moritz Schulte + + * acinclude.m4: Removed macro definitions: GNUPG_CHECK_FAQPROG, + GNUPG_CHECK_ENDIAN, GNUPG_CHECK_CACHE, GNUPG_CHECK_PIC, + GNUPG_CHECK_EXPORTDYNAMIC, GNUPG_CHECK_IPC, GNUPG_PROG_NM, + GNUPG_SYS_SYMBOL_UNDERSCORE, GNUPG_FUNC_MKDIR_TAKES_ONE_ARG, + GPH_PROG_DB2ANY. + Added macro definitions: AM_PATH_GPG_ERROR. + + * configure.ac: Use alternative approach for building based on + conditional sources, which does not make automake eat all your + memory, etc. + Removed unused tests. + Renamed --enable-static-rnd to --enable-random. + Use Autoconf's AC_C_BIGENDIAN macro instead of our own. + Re-organized the whole file. + +2003-06-16 Moritz Schulte + + * configure.ac (AC_CONFIG_FILES): Removed doc/version.sgml. + +2003-06-11 Moritz Schulte + + * configure.ac: Remove --enable-libgpg-error flag. + Ue AC_PATH_GPG_ERROR. + +2003-06-09 Moritz Schulte + + * NEWS: Mention API changes and libgpg-error. + +2003-05-25 Moritz Schulte + + * configure.ac (USE_LIBGPG_ERROR): Implementation of the + --enable-libgpg-error switch. + Define USE_LIBGPG_ERROR in LIBGCRYPT_CONFIG_FLAGS, in case + libgpg-error is used. + +2003-05-22 Moritz Schulte + + * configure.ac (AC_CHECK_HEADERS): Removed unused headers: + termio.h, langinfo.h. + (AC_CHECK_FUNCS): Removed unused functions: strsep, strlwr, + tcgetattr, setrlimit, strftime, nl_langinfo, sigaction, + sigprocmask, fopen64, fstat64. + +2003-04-27 Moritz Schulte + + * README: Documented new configure switches. + Mention the --enable-maintainer-switch. + + * configure.ac: Merged some code from GnuPG's configure.ac for + disabling sha512/tiger in case no 64 data types are available. + +2003-04-17 Moritz Schulte + + * configure.ac: Include support for sha512. + +2003-04-17 Moritz Schulte + + * AUTHORS: Updated. + +2003-04-16 Moritz Schulte + + * configure.ac: Implement command line switches: --enable-ciphers, + --enable-pubkey-ciphers and --enable-digests. + Set Automake conditionals and config.h symbols depending on the + selected ciphers, pubkey-ciphers, digests and random-modules. + + * acinclude.m4 (LIST_MEMBER): New macro. + + * configure.ac: Simplified, removed code for parsing + EXTRA_PROGRAMS from Makefile.am. + +2003-04-08 Moritz Schulte + + * configure.ac: Merged random-module selection code from GnuPG's + configure.ac. + +2003-04-07 Moritz Schulte + + * configure.ac: Removed code for generating contruct.c. + Remove digest modules from the static_modules list, only handle + random module selection. + + +2003-03-24 Moritz Schulte + + * NEWS: Mention new CBC_MAC flag. + + * AUTHORS (Maintainer): Update entry for Simon Josefsson. + +2003-03-04 Moritz Schulte + + * TODO: Remove item about resetting handles, since + gcry_cipher_reset is implemented by now. + + * NEWS: Mentioned gcry_cipher_reset. + +2003-01-21 Werner Koch + + * README (Configure options): New. + * configure.ac (have_ld_version_script): New option + --enable-ld-version-script. + +2003-01-20 Simon Josefsson + + * configure.ac (MODULES_IN_CIPHER): Add crc. + +2003-01-20 Werner Koch + + Released 1.1.12. + + * configure.ac (LIBGCRYPT_LT_REVISION): Bumbed up. + +2002-12-21 Werner Koch + + Released 1.1.11. + + * configure.ac (LIBGCRYPT_LT_CURRENT: Bumbed to 6/5/0 due to a new + interface + +2002-12-19 Werner Koch + + * configure.ac (have_pthread): Check for pthreads in libc. + (have_ld_version_script): New. + +2002-11-10 Werner Koch + + * configure.ac (MODULES_IN_CIPHER): Add md4.c. By Simon Josefsson. + +2002-09-20 Werner Koch + + Released 1.1.10. + + * configure.ac (HAVE_DEV_RANDOM_IOCTL): Don't check for it; it is + not used. + (AS_CHECK_HEADERS): Check for sys/select.h. + * Makefile.am (DIST_SUBDIRS): New to include the w32-dll directory + +2002-09-18 Timo Schulz + + * configure.ac: Added makefile for the W32 DLL. + +2002-09-17 Werner Koch + + * configure.ac: Check for Pth and Pthreads. + +2002-08-23 Werner Koch + + Released 1.1.9. + + * configure.ac (LIBGCRYPT_CONFIG_CFLAGS): Renamed from + LIBGCRYPT_CFLAGS and removed the libpath because it is set by the + config script. + (LIBGCRYPT_LT_REVISION): Set LT version to 5/4/1. + +2002-06-25 Werner Koch + + Released 1.1.8. + + * configure.ac: Set LT version to 5/4/0. + +2002-05-21 Werner Koch + + Released 1.1.7. + + * configure.ac: Set LT version to 4/3/0. + +2002-05-17 Werner Koch + + * configure.ac: Removed all the dynamic loading stuff. + +2002-05-16 Werner Koch + + * configure.ac: Reordered the C_CHECK_FUNCS. + +2002-05-15 Werner Koch + + * configure.ac: Adjusted for new MPI module stuff. + +2002-05-14 Werner Koch + + Changed license to the LGPL. + +2002-05-02 Werner Koch + + * jnlib/: Removed. + * Makefile.am (SUBDIRS): Removed jnlib. + * configure.ac (jnlib/Makefile): Removed. + + * configure.ac: Define _REENTRANT. + +2002-02-18 Werner Koch + + * configure.ac (MPI_EXTRA_ASM_OBJS): Use .lo suffix. + (AC_CANONICAL_TARGET): Added. + +2002-02-07 Werner Koch + + Released 1.1.6. + +2002-01-24 Werner Koch + + * jnlib/: Replaced by a fresh copy from GnuPG (actually the NewPG + development branch). Adjusted Makefile.am and jnlib-config.h + accordingly. + +2001-12-18 Werner Koch + + Released 1.1.5. + + * Makefile.am (dist-hook): Only look in mpi and scripts for + distfiles; this way we don't include those of a stale "make dist" + directory. + + * acinclude.m4 (GNUPG_FIX_HDR_VERSION): Make it work with the new + automake. + * configure.ac: Don't chmod db2any. + +2001-08-06 Werner Koch + + * configure.ac: Removed cross compiling hacks. + +2001-08-03 Werner Koch + + Released 1.1.4. + + * acinclude.m4 (GNUPG_CHECK_TYPEDEF): Define GNU Source. + + Migrated to autoconf 2.52. + * acinclude.m4: Removed GNUPG_LINK_FILES and converted. + * acconfig.h: Removed + * configure.in: Replaced by... + * configure.ac: and modified for use with autoconf 2.52. Replaced + GNUPG_LINK_FILES with AC_CONFIG_LINKS and moved some informational + messages to the end. Removed --enable-m-debug + + * tests/: New. + * Makefile.am: Included tests directory + + * configure.in (DYNLINK_MOD_CFLAGS): Use -shared with dec-osf. + Reported by Chris Adams. Merged some cases. + +2001-05-31 Werner Koch + + Released 1.1.3. + + * configure.in: Use _gcry_ prefix when creating the cipher constructor. + + * acconfig.h (_GCRYPT_IN_LIBGCRYPT): Define it here. + +2001-05-28 Werner Koch + + * acinclude.m4 (GPH_PROG_DOCBOOK): Removed. + (GPH_PROG_DB2ANY): New. Taken from GPH. + * configure.in: Use it here. + +2000-12-19 Werner Koch + + Major change: + Removed all GnuPG stuff and renamed this piece of software + to gcrypt. The directory gcrypt has been renamed to src. + +2000-11-14 Werner Koch + + Version 1.1.2 released. + +2000-11-13 Werner Koch + + * acinclude.m4 (GNUPG_FIX_HDR_VERSION): VPATH build fix. + +2000-10-10 Werner Koch + + * Makefile.am (dist-hook): Create the version file. + * configure.in: Set the libtool version here, removed the need + for the version file. + +Mon Sep 18 16:35:45 CEST 2000 Werner Koch + + * acinclude.m4 (GNUPG_CHECK_MLOCK): Removed that silly mkdir(). + + * configure.in: Changes to allow for Solaris random device. + By Nils Ellmenreich. + (--with-egd-socket): New. + + * configure.in (GNUPG_HOMEDIR): New. + + * configure.in: Check for fstat64 and fopen64 + + * acinclude.m4 (GNUPG_CHECK_FAQPROG): New. + * configure.in: Test for this. + + * configure.in (DYNLINK_MOD_CFLAGS): Fix by David Champion. + +Tue Aug 22 14:31:15 CEST 2000 Werner Koch + + Version 1.1.1 + +Fri Aug 18 14:27:14 CEST 2000 Werner Koch + + * agent/: New. + * Makefile.am, configure.in: Support for the new directory. + +Mon Jul 17 16:35:47 CEST 2000 Werner Koch + + * configure.in (mingw32): Changes to allow for mingw32msvc + +Fri Jul 14 19:38:23 CEST 2000 Werner Koch + + The big merge between this one and the stable branch 1.0. Still need + to merge TNANKS, AUTHORS and such. It probaly does not compile yet. + + * acinclude.m4 (GNUPG_CHECK_MLOCK): Fixed syntax error in C code. + + * configure.in: Add check for termio.h, wait unctiosn and sigaction. + + * acinclude.m4, configure.in (GNUPG_CHECK_GNUMAKE): New. + + * acinclude.m4 (MKDIR_TAKES_ONE_ARG): Check some headers. By Gaël Quéri. + + * configure.in (AM_INIT_AUTOMAKE): Use this now. By Gaël. + + * acinclude.m4 (GNUPG_CHECK_EXPORTDYNAMIC): Replacement for + GNUPG_CHECK_RDYNAMIC which should handle gcc with non GNU ld nicer. + Contributed by Dave Dykstra. + * configure.in (GNYPG_CHECK_RDYNAMIC): Replaced by the new check. + + * configure.in: Add a test for unisgned long long. + + * configure.in (DYNLINK_MOD_CFLAGS): Set different for NetBSD. + + * configure.in: Add check for clock_gettime + + * configure.in (ALL_LINGUAS): Add nl. + * configure.in (ALL_LINGUAS): Add Esperanto. + * configure.in (ALL_LINGUAS): Add sv and ja. + + * configure.in: Use /usr/local for CFLAGS and LDFLAGS when + target is freebsd. By Rémi. + + * configure.in: Do not set development version when the version has + a dash in it. Suggested by Dave Dykstra. + + * configure.in: Removed substitution for doc/gph/Makefile. + Do all the gcc warning only in maintainer mode. + + * configure.in (dlopen): Use CHECK_FUNC for a test of dlopen in libc. + Suggested by Alexandre Oliva. + (-Wall): Moved the settting of gcc warning options near to the end + so that tests don't get confused. Suggested by Paul D. Smith. + + * acinclude.m4 (GNUPG_SYS_NM_PARSE): Added BSDI support. + (GNUPG_CHECK_RDYNAMIC): Ditto. + + * acinclude.m4 (GNUPG_CHECK_MLOCK): Changed the way to test for + librt. Test suggested by Jeff Long. + + * acinclude.m4 (GNUPG_CHECK_MLOCK): Do librt check only when + we can't link a test program. This way GNU systems don't need + to link against linrt. + (GNUPG_CHECK_IPC): Fixed use of TRY_COMPILE macro. From Tim Mooney. + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add support for + DJGPP. + (GNUPG_CHECK_MLOCK): Check whether mlock sits in librt. + + * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Add NetBSD. By Thomas Klausner. + + * acconfig.h (HAVE_MLOCK): Added + +Mon Mar 13 19:22:46 CET 2000 Werner Koch + + * configure.in: Now uses the Docbook M4s from GPH. + +Mon Jan 31 17:46:35 CET 2000 Werner Koch + + * Makefile.am: Re-added tools. By Rémi. + +Mon Jan 31 16:37:34 CET 2000 Werner Koch + + * configure.in: Create a symlink for types.h in gcrypt/. + +Thu Jan 27 18:00:44 CET 2000 Werner Koch + + * configure.in (g10defs.h): Replaced by gnupg-defs.h + +Mon Jan 24 13:04:28 CET 2000 Werner Koch + + * jnlib/ : New. + + * configure.in: Do set development version when the version has + a dash in it. Suggested by Dave Dykstra. + +Thu Dec 9 17:22:27 CET 1999 Werner Koch + + * acinclude.m4 (GNUPG_FIX_HDR_VERSION): New. + * configure.in: Check and fix the version number of gcrypt/gcrypt.h + so that it is always the save as VERSION. + +Thu Oct 28 16:17:46 CEST 1999 Werner Koch + + * Started with development series 1.1 on 1999-10-26 + +Tue Oct 26 14:10:21 CEST 1999 Werner Koch + + * README-alpha: New + + * configure.in: Fixed quoting in test for development version. + + * THANKS: Add entries for Michael, Brenno and J Horacio who did + very nice Howto documents - I apoligize for forgetting to mention them + earlier. + +Fri Sep 17 12:56:42 CEST 1999 Werner Koch + + + * configure.in: Add "-lcap" when capabilities are requested. + Add the conditional CROSS_COMPILING. + * Makefile.am: Don't use checks when CROSS_COMPILING. + + +Wed Sep 15 16:22:17 CEST 1999 Werner Koch + + + * configure.in (ALL_LINGUAS): Add pt_PT. + + * configure.in: Some tweaks for cross compiling under MingW32 + * acconfig.h (USE_STATIC_RNDW32): New. + +Tue Sep 7 17:08:10 CEST 1999 Werner Koch + + + * VERSION: Set to 1.0.0. + +Mon Sep 6 19:59:08 CEST 1999 Werner Koch + + + * configure.in: Create makefile in doc/gph + + * acinclude.m4 (GNUPG_FUNC_MKDIR_TAKES_ONE_ARG): New + * configure.in: use the above. + +Thu Sep 2 16:40:55 CEST 1999 Werner Koch + + + * VERSION: Set to 0.9.11. + +Tue Aug 31 17:20:44 CEST 1999 Werner Koch + + * configure.in: Minor changes to the OS/2 and Mingw32 system labels. + Add a printable name for Hurd. + +Mon Aug 30 20:38:33 CEST 1999 Werner Koch + + * configure.in: Some support for DJGPP (Mark Elbrecht) + +Wed Aug 4 10:34:46 CEST 1999 Werner Koch + + * VERSION: Set to 0.9.10. + +Mon Jul 26 09:34:46 CEST 1999 Werner Koch + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): remove init of ac_cv_... + + * Makefile.am (DISCLEANFILES): New + +Fri Jul 23 13:53:03 CEST 1999 Werner Koch + + * VERSION: Set to 0.9.9. + + * configure.in: Print a notice when rndunix is used. + +Thu Jul 15 10:15:35 CEST 1999 Werner Koch + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Fixed last modification. + +Wed Jul 7 13:08:40 CEST 1999 Werner Koch + + * Makefile.am: Support for libtool. + * configure.in: Ditto. + +Tue Jun 29 21:44:25 CEST 1999 Werner Koch + + * configure.in (use_local_zlib): The lost dollar is back. + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add EMX case. + * configure.in: Another variant of the MX vendor string + + * configure.in (--with-capabilities): Some test code (Remi). + +Sat Jun 26 12:15:59 CEST 1999 Werner Koch + + * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Support for HPUX and IRIX. + * configure.in (HAVE_DL_SHL_LOAD): New for HPUX (Dave Dykstra). + + * VERSION: Now 0.9.8 + +Wed Jun 16 20:16:21 CEST 1999 Werner Koch + + * configure.in: Add test for docbook-to-man + +Tue Jun 15 12:21:08 CEST 1999 Werner Koch + + * acinclude.m4 (GNUPG_SYS_NM_PARSE): Support for {net,free}bsd, + +Thu Jun 10 14:18:23 CEST 1999 Werner Koch + + * configure.in (ZLIB,GDBM): Check both, header and lib. + +Sat Jun 5 15:30:33 CEST 1999 Werner Koch + + * pkclist.c (key_present_in_pk_list): New (Michael). + +Tue May 25 19:50:32 CEST 1999 Werner Koch + + * configure.in (IS_DEVELOPMENT_VERSION): Fixed detection. + +Sun May 23 14:20:22 CEST 1999 Werner Koch + + * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): assume yes when + cross-compiling. + +Mon May 17 21:54:43 CEST 1999 Werner Koch + + * configure.in (socket): Fix for Unisys by Katsuhiro Kondou. + +Sat May 8 19:28:08 CEST 1999 Werner Koch + + * NEWS: Add a marker line which I forgot to do for 0.9.6. + +Thu May 6 14:18:17 CEST 1999 Werner Koch + + * README: Minor updates + + * VERSION: Now 0.9.6 + +Thu Apr 8 09:35:53 CEST 1999 Werner Koch + + * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Fix for + amiga-openbsd (Peter Reich) + (GNUPG_PROG_NM): Ditto + +Wed Apr 7 20:51:39 CEST 1999 Werner Koch + + * Makefile.am (g10defs.h): Removed. + * configure.in (AC_OUTPUT_COMMANDS): Create g10defs.h + +Sat Mar 20 12:55:33 CET 1999 Werner Koch + + * VERSION: Now 0.9.5 + +Sun Mar 14 19:34:36 CET 1999 Werner Koch + + * acinclude.m4 (AM_SYS_SYMBOL_UNDERSCORE): Removed because it is + now in the latest libtool. + +Thu Mar 11 16:39:46 CET 1999 Werner Koch + + * configure.in: Removed the need for libtool + +Mon Mar 8 20:47:17 CET 1999 Werner Koch + + * configure.in (DLSYM_NEEDS_UNDERSCORE): Replaced. + * acinclude.in (AM_SYS_SYMBOL_UNDERSCORE): New. + + * VERSION: Now 0.9.4 + +Sun Feb 28 19:11:00 CET 1999 Werner Koch + + * configure.in (dld): Test disabled. + +Fri Feb 26 17:55:41 CET 1999 Werner Koch + + * encode.c (encode_simple): temporary fix. + +Wed Feb 24 11:07:27 CET 1999 Werner Koch + + * configure.in: New option --enable-static-rnd. + +Mon Feb 22 20:04:00 CET 1999 Werner Koch + + * BUGS: Now we assign bug numbers. + * OBUGS: New to keep rack o fixed bugs (CVS only) + +Fri Feb 19 18:01:54 CET 1999 Werner Koch + + * VERSION: Released 0.9.3 + +Fri Feb 19 15:49:15 CET 1999 Werner Koch + + * acinclude.m4: Removed gettext macros. + +Tue Feb 16 14:10:02 CET 1999 Werner Koch + + * configure.in (socket): Check for -lsocket and -lnsl. + (osf4): Disable all warnings for DEC's cc. + (-Wall): Add more warning options for gcc + +Sat Feb 13 12:04:43 CET 1999 Werner Koch + + * configure.in: Changed detection of compiler flags. + * intl/ : Removed directory + +Wed Feb 10 17:15:39 CET 1999 Werner Koch + + * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Fix for freebsd 2.2 + + * configure.in: a lot of changes to allow selection of modules. + Add support for OS/2. + + * acinclude.m4: add some more caching + + * README: Spelling and grammar corrections (John A. Martin) + * INSTALL: Ditto. + +Wed Jan 20 21:40:21 CET 1999 Werner Koch + + * configure.in: --enable-m-guard is now default + +Wed Jan 13 12:49:36 CET 1999 Werner Koch + + * INSTALL: Applied new information how to build rpms by Fabio Coatti + * Makefile.in (gnupg.spec): Changed the names. + +Tue Jan 12 11:17:18 CET 1999 Werner Koch + + * config.links (m68k-atari-mint): New + +Tue Jan 12 09:17:19 CET 1999 Gaël Quéri + + * all: Fixed typos all over the place + +Sat Jan 9 16:02:23 CET 1999 Werner Koch + + * configure.in: Add a way to statically link rndunix + +Sun Jan 3 15:28:44 CET 1999 Werner Koch + + * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): New. + * configure.in (DYNLOAD_CFLAGS): Use result from CHECK_RDYNAMIC + +Wed Dec 23 13:18:14 CET 1998 Werner Koch + + * README: Replaced the command overview with a short intro. + +Sat Dec 12 18:40:32 CET 1998 Werner Koch + + * configure.in: Add check for dlopen in libc (Greg Troxel) + and a new define + * acconfig.h (DLSYM_NEEDS_UNDERSCORE): New. + +Thu Dec 10 20:15:36 CET 1998 Werner Koch + + * acinclude.m (GNUPG_CHECK_PIC): New + * configure.in, acinclude.m4: Renamed all WK_ to GNUPG_ + +Tue Dec 8 15:09:29 CET 1998 Werner Koch + + * VERSION: Set to 0.4.5 + +Wed Nov 25 12:38:29 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (USE_RNDLINUX): New. + +Fri Nov 20 19:34:57 1998 Werner Koch (wk@isil.d.shuttle.de) + + * VERSION: Released 0.4.4 + + * configure.in (try_asm_modules): For option --disable-asm + +Tue Nov 10 19:32:40 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (MPI_SFLAGS): New. + +Tue Nov 10 13:44:53 1998 Werner Koch (wk@isil.d.shuttle.de) + + * ABOUT-NLS: New + * configure.in (AC_REVISION): New. + +Sun Nov 8 18:20:35 1998 Werner Koch (wk@isil.d.shuttle.de) + + * VERSION: Set to 0.4.3 + +Sun Oct 25 19:49:37 1998 Werner Koch (wk@isil.d.shuttle.de) + + * Makefile.am (g10defs.h): New macro GNUPG_DATADIR. + +Wed Oct 21 17:24:24 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in: Removed gettext kludge + * acinclude.m4: Add patched AM_WITH_NKS macro + +Tue Oct 20 19:03:36 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in: Kludge to make AM_GNU_GETTEXT work, + changed some macors to more modern versions. Also + changeg the all makefiles to remove duplicate ../intl. + * acinclude.m4: Removed the gettext stuff, as this + already comes with automake now. + +Wed Oct 14 12:11:34 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (NAME_OF_DEV_RANDOM): New. + (DYNLINK_MOD_CFLAGS): New. + +Thu Oct 8 10:55:15 1998 Werner Koch (wk@isil.d.shuttle.de) + + * Makefile.am (g10defs.h): creates include file + * acconfig.h: now includes g10defs.h + * configure.in: Removed G10_LOCALEDIR and GNUPG_LIB + +Thu Sep 17 18:49:40 1998 Werner Koch (wk@(none)) + + * Makefile.am (dist-hook): Now creates RPM file. + * scripts/gnupg.spec: New template file for RPMs + +Thu Jul 30 19:17:07 1998 Werner Koch (wk@(none)) + + * acinclude.h (WK_CHECK_IPC): New + * configure.in : Add checks for SysV IPC + +Thu Jun 25 11:18:49 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (--disable-dynload): New. + +Wed Jun 10 07:48:59 1998 Werner Koch,mobil,,, (wk@tobold) + + * configure.in (GNUPG_LIBDIR): New. + +Mon May 25 19:10:59 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rand-unix.c (fast_random_poll): fixed syntax bug. + +Mon May 11 10:21:31 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (PRINTABLE_OS_NAME): Linux is now GNU/Linux + +Tue Apr 14 19:08:05 1998 Werner Koch (wk@isil.d.shuttle.de) + + * [all files]: Applied Matthew Skala's typo and grammar fixes. + +Wed Mar 4 10:32:40 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (getrusage,gettimeofday): New tests. + +Fri Feb 27 13:14:17 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (--disable-m-guard): New. + +Thu Feb 26 17:09:27 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in, acinclude.m4, intl/, po/: New macros taken + from GNOME, switched to automake 1.2f + +Thu Feb 26 09:05:46 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (doc/Makefile): New + +Thu Feb 26 07:40:47 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in: Changed gettext stuff + +Wed Feb 25 11:44:10 1998 Werner Koch (wk@isil.d.shuttle.de) + + * checks/*test : restructured the directory. + +Tue Feb 24 15:59:12 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in: Changed the name of the package to GNUPG and + chnaged several other names too. + +Wed Feb 18 17:36:45 1998 Werner Koch (wk@isil.d.shuttle.de) + + * Makefile.am (checks): New. + +Sat Feb 14 15:37:55 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (mpi_config_done): Removed asm links caching. + +Sat Feb 14 14:02:20 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in (PRINTABLE_OS_NAME): New. + * acconfig.h: Likewise. + +Fri Feb 13 19:43:41 1998 Werner Koch (wk@isil.d.shuttle.de) + + * configure.in : Fixed zlib stuff + * Makefile.am: Likewise + + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, + 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +Local Variables: +buffer-read-only: t +End: diff --git a/comm/third_party/libgcrypt/INSTALL b/comm/third_party/libgcrypt/INSTALL new file mode 100644 index 0000000000..5458714e1e --- /dev/null +++ b/comm/third_party/libgcrypt/INSTALL @@ -0,0 +1,234 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/comm/third_party/libgcrypt/LICENSES b/comm/third_party/libgcrypt/LICENSES new file mode 100644 index 0000000000..31f8eae831 --- /dev/null +++ b/comm/third_party/libgcrypt/LICENSES @@ -0,0 +1,239 @@ +Additional license notices for Libgcrypt. -*- org -*- + +This file contains the copying permission notices for various files in +the Libgcrypt distribution which are not covered by the GNU Lesser +General Public License (LGPL) or the GNU General Public License (GPL). + +These notices all require that a copy of the notice be included +in the accompanying documentation and be distributed with binary +distributions of the code, so be sure to include this file along +with any binary distributions derived from the GNU C Library. + +* BSD_3Clause + + For files: + - cipher/sha256-avx-amd64.S + - cipher/sha256-avx2-bmi2-amd64.S + - cipher/sha256-ssse3-amd64.S + - cipher/sha512-avx-amd64.S + - cipher/sha512-avx2-bmi2-amd64.S + - cipher/sha512-ssse3-amd64.S + - cipher/sha512-ssse3-i386.c + +#+begin_quote + Copyright (c) 2012, Intel Corporation + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + * Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + + THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#+end_quote + + + For files: + - random/jitterentropy-base.c + - random/jitterentropy.h + - random/rndjent.c (plus common Libgcrypt copyright holders) + +#+begin_quote + * Copyright Stephan Mueller , 2013 + * + * License + * ======= + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. +#+end_quote + +* X License + + For files: + - install.sh + +#+begin_quote + Copyright (C) 1994 X Consortium + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- + TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the X Consortium shall not + be used in advertising or otherwise to promote the sale, use or other deal- + ings in this Software without prior written authorization from the X Consor- + tium. +#+end_quote + +* Public domain + + For files: + - cipher/arcfour-amd64.S + +#+begin_quote + Author: Marc Bevand + Licence: I hereby disclaim the copyright on this code and place it + in the public domain. +#+end_quote + +* OCB license 1 + + For files: + - cipher/cipher-ocb.c + +#+begin_quote + OCB is covered by several patents but may be used freely by most + software. See http://web.cs.ucdavis.edu/~rogaway/ocb/license.htm . + In particular license 1 is suitable for Libgcrypt: See + http://web.cs.ucdavis.edu/~rogaway/ocb/license1.pdf for the full + license document; it basically says: + + License 1 — License for Open-Source Software Implementations of OCB + (Jan 9, 2013) + + Under this license, you are authorized to make, use, and + distribute open-source software implementations of OCB. This + license terminates for you if you sue someone over their + open-source software implementation of OCB claiming that you have + a patent covering their implementation. + + + + License for Open Source Software Implementations of OCB + January 9, 2013 + + 1 Definitions + + 1.1 “Licensor†means Phillip Rogaway. + + 1.2 “Licensed Patents†means any patent that claims priority to United + States Patent Application No. 09/918,615 entitled “Method and Apparatus + for Facilitating Efficient Authenticated Encryption,†and any utility, + divisional, provisional, continuation, continuations-in-part, reexamination, + reissue, or foreign counterpart patents that may issue with respect to the + aforesaid patent application. This includes, but is not limited to, United + States Patent No. 7,046,802; United States Patent No. 7,200,227; United + States Patent No. 7,949,129; United States Patent No. 8,321,675 ; and any + patent that issues out of United States Patent Application No. 13/669,114. + + 1.3 “Use†means any practice of any invention claimed in the Licensed Patents. + + 1.4 “Software Implementation†means any practice of any invention + claimed in the Licensed Patents that takes the form of software executing on + a user-programmable, general-purpose computer or that takes the form of a + computer-readable medium storing such software. Software Implementation does + not include, for example, application-specific integrated circuits (ASICs), + field-programmable gate arrays (FPGAs), embedded systems, or IP cores. + + 1.5 “Open Source Software†means software whose source code is published + and made available for inspection and use by anyone because either (a) the + source code is subject to a license that permits recipients to copy, modify, + and distribute the source code without payment of fees or royalties, or + (b) the source code is in the public domain, including code released for + public use through a CC0 waiver. All licenses certified by the Open Source + Initiative at opensource.org as of January 9, 2013 and all Creative Commons + licenses identified on the creativecommons.org website as of January 9, + 2013, including the Public License Fallback of the CC0 waiver, satisfy these + requirements for the purposes of this license. + + 1.6 “Open Source Software Implementation†means a Software + Implementation in which the software implicating the Licensed Patents is + Open Source Software. Open Source Software Implementation does not include + any Software Implementation in which the software implicating the Licensed + Patents is combined, so as to form a larger program, with software that is + not Open Source Software. + + 2 License Grant + + 2.1 License. Subject to your compliance with the term s of this license, + including the restriction set forth in Section 2.2, Licensor hereby + grants to you a perpetual, worldwide, non-exclusive, non-transferable, + non-sublicenseable, no-charge, royalty-free, irrevocable license to practice + any invention claimed in the Licensed Patents in any Open Source Software + Implementation. + + 2.2 Restriction. If you or your affiliates institute patent litigation + (including, but not limited to, a cross-claim or counterclaim in a lawsuit) + against any entity alleging that any Use authorized by this license + infringes another patent, then any rights granted to you under this license + automatically terminate as of the date such litigation is filed. + + 3 Disclaimer + YOUR USE OF THE LICENSED PATENTS IS AT YOUR OWN RISK AND UNLESS REQUIRED + BY APPLICABLE LAW, LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY + KIND CONCERNING THE LICENSED PATENTS OR ANY PRODUCT EMBODYING ANY LICENSED + PATENT, EXPRESS OR IMPLIED, STATUT ORY OR OTHERWISE, INCLUDING, WITHOUT + LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR + PURPOSE, OR NONINFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM OR RELATED TO ANY USE OF THE LICENSED PATENTS, INCLUDING, + WITHOUT LIMITATION, DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE + OR SPECIAL DAMAGES, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF + SUCH DAMAGES PRIOR TO SUCH AN OCCURRENCE. +#+end_quote diff --git a/comm/third_party/libgcrypt/Makefile.am b/comm/third_party/libgcrypt/Makefile.am new file mode 100644 index 0000000000..0c622b0e49 --- /dev/null +++ b/comm/third_party/libgcrypt/Makefile.am @@ -0,0 +1,158 @@ +## Process this file with automake to produce Makefile.in +# Copyright (C) 1992, 1999, 2000, 2002 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# Libgcrypt is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +# SPDX-License-Identifier: LGPL-2.1-or-later + +# Location of the released tarball archives. This is prefixed by +# the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example: +# RELEASE_ARCHIVE=wk@somehost:archive/tarballs +RELEASE_ARCHIVE_SUFFIX = libgcrypt/v1.9 +# The variable RELEASE_SIGNING_KEY in ~/.gnupg-autogen.rc is used +# to specify the key for signing. For example: +# RELEASE_SIGNKEY=D8692123C4065DEA5E0F3AB5249B39D24F25E3B6 + + +ACLOCAL_AMFLAGS = -I m4 +DISTCHECK_CONFIGURE_FLAGS = --disable-random-daemon --enable-doc \ + --enable-random=auto + +# (A suitable gitlog-to-changelog script can be found in GnuPG master.) +GITLOG_TO_CHANGELOG=gitlog-to-changelog + +if BUILD_DOC +doc = doc +else +doc = +endif + + +DIST_SUBDIRS = m4 compat mpi cipher random src doc tests +SUBDIRS = compat mpi cipher random src $(doc) tests + +EXTRA_DIST = autogen.sh autogen.rc README.GIT LICENSES \ + ChangeLog-2011 build-aux/ChangeLog-2011 doc/ChangeLog-2011 \ + m4/ChangeLog-2011 cipher/ChangeLog-2011 src/ChangeLog-2011 \ + random/ChangeLog-2011 tests/ChangeLog-2011 mpi/ChangeLog-2011 \ + build-aux/git-log-footer build-aux/git-log-fix VERSION + +DISTCLEANFILES = + + +# Add all the files listed in "distfiles" files to the distribution +dist-hook: gen-ChangeLog + @set -e; \ + for file in `cd $(top_srcdir); \ + find mpi -type f -name distfiles`; do \ + dir=`dirname $$file` ; $(mkinstalldirs) $(distdir)/$$dir ; \ + for i in distfiles `cat $(top_srcdir)/$$file` ; do \ + ln $(top_srcdir)/$$dir/$$i $(distdir)/$$dir/$$i 2> /dev/null \ + || cp -p $(top_srcdir)/$$dir/$$i $(distdir)/$$dir/$$i; \ + done ; \ + done + +distcheck-hook: + set -e; ( \ + pref="#+macro: $$(echo $(PACKAGE_NAME)|tr '-' '_')_" ;\ + reldate="$$(date -u +%Y-%m-%d)" ;\ + echo "$${pref}ver $(PACKAGE_VERSION)" ;\ + echo "$${pref}date $${reldate}" ;\ + list='$(DIST_ARCHIVES)'; for i in $$list; do \ + case "$$i" in *.tar.bz2) \ + echo "$${pref}size $$(wc -c <$$i|awk '{print int($$1/1024)}')k" ;\ + echo "$${pref}sha1 $$(sha1sum <$$i|cut -d' ' -f1)" ;\ + echo "$${pref}sha2 $$(sha256sum <$$i|cut -d' ' -f1)" ;;\ + esac;\ + done ) | tee $(distdir).swdb + + + +gen_start_date = 2011-12-01T14:00:00 +.PHONY: gen-ChangeLog +gen-ChangeLog: + if test -e $(top_srcdir)/.git; then \ + (cd $(top_srcdir) && \ + $(GITLOG_TO_CHANGELOG) --append-dot --tear-off \ + --amend=build-aux/git-log-fix \ + --since=$(gen_start_date) ) > $(distdir)/cl-t; \ + cat $(top_srcdir)/build-aux/git-log-footer >> $(distdir)/cl-t;\ + rm -f $(distdir)/ChangeLog; \ + mv $(distdir)/cl-t $(distdir)/ChangeLog; \ + fi + + + +stowinstall: + $(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/libgcrypt + +# Macro to help the release target. +RELEASE_NAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) + +release: + +(set -e;\ + if [ "$(abs_top_builddir)" = "$(abs_top_srcdir)" ]; then \ + echo "error: build directory must not be the source directory" >&2;\ + exit 2;\ + fi ;\ + echo "/* Build started at $$(date -uIseconds) */" ;\ + cd $(top_srcdir); \ + ./autogen.sh --force; \ + cd $(abs_top_builddir); \ + rm -rf dist; mkdir dist ; cd dist ; \ + $(abs_top_srcdir)/configure --enable-maintainer-mode; \ + $(MAKE) distcheck; \ + echo "/* Build finished at $$(date -uIseconds) */" ;\ + echo "/*" ;\ + echo " * Please run the final step interactivly:" ;\ + echo " * make sign-release" ;\ + echo " */" ;\ + ) 2>&1 | tee "$(RELEASE_NAME).buildlog" + +sign-release: + +(set -e; \ + cd dist; \ + x=$$(grep '^RELEASE_ARCHIVE=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\ + if [ -z "$$x" ]; then \ + echo "error: RELEASE_ARCHIVE missing in ~/.gnupg-autogen.rc">&2; \ + exit 2;\ + fi;\ + myarchive="$$x/$(RELEASE_ARCHIVE_SUFFIX)";\ + x=$$(grep '^RELEASE_SIGNKEY=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\ + if [ -z "$$x" ]; then \ + echo "error: RELEASE_SIGNKEY missing in ~/.gnupg-autogen.rc">&2; \ + exit 2;\ + fi;\ + mysignkey="$$x";\ + files1="$(RELEASE_NAME).tar.bz2 \ + $(RELEASE_NAME).tar.gz" ; \ + files2="$(RELEASE_NAME).tar.bz2.sig \ + $(RELEASE_NAME).tar.gz.sig \ + $(RELEASE_NAME).swdb \ + $(RELEASE_NAME).buildlog" ;\ + echo "/* Signing the source tarball ..." ;\ + gpg -sbu $$mysignkey $(RELEASE_NAME).tar.bz2 ;\ + gpg -sbu $$mysignkey $(RELEASE_NAME).tar.gz ;\ + cat $(RELEASE_NAME).swdb >swdb.snippet;\ + echo >>swdb.snippet ;\ + sha1sum $${files1} >>swdb.snippet ;\ + cat "../$(RELEASE_NAME).buildlog" swdb.snippet \ + | gzip >$(RELEASE_NAME).buildlog ;\ + echo "Copying to archive $$myarchive ..." ;\ + scp -p $${files1} $${files2} $${myarchive}/ || true;\ + echo '/*' ;\ + echo ' * All done; for checksums see dist/swdb.snippet' ;\ + echo ' */' ;\ + ) diff --git a/comm/third_party/libgcrypt/Makefile.in b/comm/third_party/libgcrypt/Makefile.in new file mode 100644 index 0000000000..6c8ca44a45 --- /dev/null +++ b/comm/third_party/libgcrypt/Makefile.in @@ -0,0 +1,1019 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Copyright (C) 1992, 1999, 2000, 2002 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# Libgcrypt is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +# SPDX-License-Identifier: LGPL-2.1-or-later +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/noexecstack.m4 $(top_srcdir)/m4/socklen.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir distdir-am dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(top_srcdir)/build-aux/compile \ + $(top_srcdir)/build-aux/config.guess \ + $(top_srcdir)/build-aux/config.sub \ + $(top_srcdir)/build-aux/install-sh \ + $(top_srcdir)/build-aux/ltmain.sh \ + $(top_srcdir)/build-aux/missing AUTHORS COPYING COPYING.LIB \ + ChangeLog INSTALL NEWS README THANKS TODO build-aux/compile \ + build-aux/config.guess build-aux/config.rpath \ + build-aux/config.sub build-aux/depcomp build-aux/install-sh \ + build-aux/ltmain.sh build-aux/mdate-sh build-aux/missing \ + build-aux/texinfo.tex mkinstalldirs +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 +GZIP_ENV = --best +DIST_TARGETS = dist-bzip2 dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DL_LIBS = @DL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FALLBACK_SOCKLEN_T = @FALLBACK_SOCKLEN_T@ +FGREP = @FGREP@ +GCRYPT_CIPHERS = @GCRYPT_CIPHERS@ +GCRYPT_DIGESTS = @GCRYPT_DIGESTS@ +GCRYPT_HWF_MODULES = @GCRYPT_HWF_MODULES@ +GCRYPT_KDFS = @GCRYPT_KDFS@ +GCRYPT_PUBKEY_CIPHERS = @GCRYPT_PUBKEY_CIPHERS@ +GCRYPT_RANDOM = @GCRYPT_RANDOM@ +GPGRT_CONFIG = @GPGRT_CONFIG@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@ +GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@ +GREP = @GREP@ +INSERT_SYS_SELECT_H = @INSERT_SYS_SELECT_H@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CIPHERS = @LIBGCRYPT_CIPHERS@ +LIBGCRYPT_CONFIG_API_VERSION = @LIBGCRYPT_CONFIG_API_VERSION@ +LIBGCRYPT_CONFIG_CFLAGS = @LIBGCRYPT_CONFIG_CFLAGS@ +LIBGCRYPT_CONFIG_HOST = @LIBGCRYPT_CONFIG_HOST@ +LIBGCRYPT_CONFIG_LIBS = @LIBGCRYPT_CONFIG_LIBS@ +LIBGCRYPT_DIGESTS = @LIBGCRYPT_DIGESTS@ +LIBGCRYPT_LT_AGE = @LIBGCRYPT_LT_AGE@ +LIBGCRYPT_LT_CURRENT = @LIBGCRYPT_LT_CURRENT@ +LIBGCRYPT_LT_REVISION = @LIBGCRYPT_LT_REVISION@ +LIBGCRYPT_PUBKEY_CIPHERS = @LIBGCRYPT_PUBKEY_CIPHERS@ +LIBGCRYPT_THREAD_MODULES = @LIBGCRYPT_THREAD_MODULES@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MPI_SFLAGS = @MPI_SFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOEXECSTACK_FLAGS = @NOEXECSTACK_FLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTH_CFLAGS = @PTH_CFLAGS@ +PTH_CONFIG = @PTH_CONFIG@ +PTH_LIBS = @PTH_LIBS@ +RANLIB = @RANLIB@ +RC = @RC@ +RUN_LARGE_DATA_TESTS = @RUN_LARGE_DATA_TESTS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSROOT = @SYSROOT@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +emacs_local_vars_begin = @emacs_local_vars_begin@ +emacs_local_vars_end = @emacs_local_vars_end@ +emacs_local_vars_read_only = @emacs_local_vars_read_only@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Location of the released tarball archives. This is prefixed by +# the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example: +# RELEASE_ARCHIVE=wk@somehost:archive/tarballs +RELEASE_ARCHIVE_SUFFIX = libgcrypt/v1.9 +# The variable RELEASE_SIGNING_KEY in ~/.gnupg-autogen.rc is used +# to specify the key for signing. For example: +# RELEASE_SIGNKEY=D8692123C4065DEA5E0F3AB5249B39D24F25E3B6 +ACLOCAL_AMFLAGS = -I m4 +DISTCHECK_CONFIGURE_FLAGS = --disable-random-daemon --enable-doc \ + --enable-random=auto + + +# (A suitable gitlog-to-changelog script can be found in GnuPG master.) +GITLOG_TO_CHANGELOG = gitlog-to-changelog +@BUILD_DOC_FALSE@doc = +@BUILD_DOC_TRUE@doc = doc +DIST_SUBDIRS = m4 compat mpi cipher random src doc tests +SUBDIRS = compat mpi cipher random src $(doc) tests +EXTRA_DIST = autogen.sh autogen.rc README.GIT LICENSES \ + ChangeLog-2011 build-aux/ChangeLog-2011 doc/ChangeLog-2011 \ + m4/ChangeLog-2011 cipher/ChangeLog-2011 src/ChangeLog-2011 \ + random/ChangeLog-2011 tests/ChangeLog-2011 mpi/ChangeLog-2011 \ + build-aux/git-log-footer build-aux/git-log-fix VERSION + +DISTCLEANFILES = +gen_start_date = 2011-12-01T14:00:00 + +# Macro to help the release target. +RELEASE_NAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && $(MAKE) $(AM_MAKEFLAGS) distcheck-hook \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) all install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \ + dist-tarZ dist-xz dist-zip distcheck distclean \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Add all the files listed in "distfiles" files to the distribution +dist-hook: gen-ChangeLog + @set -e; \ + for file in `cd $(top_srcdir); \ + find mpi -type f -name distfiles`; do \ + dir=`dirname $$file` ; $(mkinstalldirs) $(distdir)/$$dir ; \ + for i in distfiles `cat $(top_srcdir)/$$file` ; do \ + ln $(top_srcdir)/$$dir/$$i $(distdir)/$$dir/$$i 2> /dev/null \ + || cp -p $(top_srcdir)/$$dir/$$i $(distdir)/$$dir/$$i; \ + done ; \ + done + +distcheck-hook: + set -e; ( \ + pref="#+macro: $$(echo $(PACKAGE_NAME)|tr '-' '_')_" ;\ + reldate="$$(date -u +%Y-%m-%d)" ;\ + echo "$${pref}ver $(PACKAGE_VERSION)" ;\ + echo "$${pref}date $${reldate}" ;\ + list='$(DIST_ARCHIVES)'; for i in $$list; do \ + case "$$i" in *.tar.bz2) \ + echo "$${pref}size $$(wc -c <$$i|awk '{print int($$1/1024)}')k" ;\ + echo "$${pref}sha1 $$(sha1sum <$$i|cut -d' ' -f1)" ;\ + echo "$${pref}sha2 $$(sha256sum <$$i|cut -d' ' -f1)" ;;\ + esac;\ + done ) | tee $(distdir).swdb +.PHONY: gen-ChangeLog +gen-ChangeLog: + if test -e $(top_srcdir)/.git; then \ + (cd $(top_srcdir) && \ + $(GITLOG_TO_CHANGELOG) --append-dot --tear-off \ + --amend=build-aux/git-log-fix \ + --since=$(gen_start_date) ) > $(distdir)/cl-t; \ + cat $(top_srcdir)/build-aux/git-log-footer >> $(distdir)/cl-t;\ + rm -f $(distdir)/ChangeLog; \ + mv $(distdir)/cl-t $(distdir)/ChangeLog; \ + fi + +stowinstall: + $(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/libgcrypt + +release: + +(set -e;\ + if [ "$(abs_top_builddir)" = "$(abs_top_srcdir)" ]; then \ + echo "error: build directory must not be the source directory" >&2;\ + exit 2;\ + fi ;\ + echo "/* Build started at $$(date -uIseconds) */" ;\ + cd $(top_srcdir); \ + ./autogen.sh --force; \ + cd $(abs_top_builddir); \ + rm -rf dist; mkdir dist ; cd dist ; \ + $(abs_top_srcdir)/configure --enable-maintainer-mode; \ + $(MAKE) distcheck; \ + echo "/* Build finished at $$(date -uIseconds) */" ;\ + echo "/*" ;\ + echo " * Please run the final step interactivly:" ;\ + echo " * make sign-release" ;\ + echo " */" ;\ + ) 2>&1 | tee "$(RELEASE_NAME).buildlog" + +sign-release: + +(set -e; \ + cd dist; \ + x=$$(grep '^RELEASE_ARCHIVE=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\ + if [ -z "$$x" ]; then \ + echo "error: RELEASE_ARCHIVE missing in ~/.gnupg-autogen.rc">&2; \ + exit 2;\ + fi;\ + myarchive="$$x/$(RELEASE_ARCHIVE_SUFFIX)";\ + x=$$(grep '^RELEASE_SIGNKEY=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\ + if [ -z "$$x" ]; then \ + echo "error: RELEASE_SIGNKEY missing in ~/.gnupg-autogen.rc">&2; \ + exit 2;\ + fi;\ + mysignkey="$$x";\ + files1="$(RELEASE_NAME).tar.bz2 \ + $(RELEASE_NAME).tar.gz" ; \ + files2="$(RELEASE_NAME).tar.bz2.sig \ + $(RELEASE_NAME).tar.gz.sig \ + $(RELEASE_NAME).swdb \ + $(RELEASE_NAME).buildlog" ;\ + echo "/* Signing the source tarball ..." ;\ + gpg -sbu $$mysignkey $(RELEASE_NAME).tar.bz2 ;\ + gpg -sbu $$mysignkey $(RELEASE_NAME).tar.gz ;\ + cat $(RELEASE_NAME).swdb >swdb.snippet;\ + echo >>swdb.snippet ;\ + sha1sum $${files1} >>swdb.snippet ;\ + cat "../$(RELEASE_NAME).buildlog" swdb.snippet \ + | gzip >$(RELEASE_NAME).buildlog ;\ + echo "Copying to archive $$myarchive ..." ;\ + scp -p $${files1} $${files2} $${myarchive}/ || true;\ + echo '/*' ;\ + echo ' * All done; for checksums see dist/swdb.snippet' ;\ + echo ' */' ;\ + ) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgcrypt/NEWS b/comm/third_party/libgcrypt/NEWS new file mode 100644 index 0000000000..69ab074394 --- /dev/null +++ b/comm/third_party/libgcrypt/NEWS @@ -0,0 +1,1440 @@ +Noteworthy changes in version 1.9.2 (2021-02-17) [C23/A3/R2] +------------------------------------------------ + + * Bug fixes: + + - Fix build problem for macOS in the random code. [#5268] + + - Fix building with --disable-asm on x86. [#5277] + + - Check public key for ECDSA verify operation. [#5282] + + - Make sure gcry_get_config (NULL) returns a nul-terminated string. + [8716e4b2ad] + + - Fix a memory leak in the ECDH code. [289543544e] + + - Fix a reading beyond end of input buffer in SHA2-avx2. + [24af2a55d8] + + * Other features: + + - New test driver to allow for standalone regression + tests. [b142da4c88] + + Release-info: https://dev.gnupg.org/T5276 + + +Noteworthy changes in version 1.9.1 (2021-01-29) [C23/A3/R1] +------------------------------------------------ + + * Bug fixes: + + - Fix exploitable bug in hash functions introduced with 1.9.0. + [#5275] + + - Return an error if a negative MPI is used with sexp scan + functions. [#4964] + + - Check for operational FIPS in the random and KDF functions. + [#5243] + + - Fix compile error on ARMv7 with NEON disabled. [#5251] + + - Fix self-test in KDF module. [#5254] + + - Improve assembler checks for better LTO support. [#5255] + + - Fix assember problem on macOS running on M1. [#5157] + + - Support older macOS without posix_spawn. [#5159] + + - Fix 32-bit cross build on x86. [#5257] + + - Fix non-NEON ARM assembly implementation for SHA512. [#5263] + + - Fix build problems with the cipher_bulk_ops_t typedef. [#5264] + + - Fix Ed25519 private key handling for preceding ZEROs. [#5267] + + - Fix overflow in modular inverse implementation. [#5269] + + - Fix register access for AVX/AVX2 implementations of Blake2. + [#5271]. + + * Performance: + + - Add optimized cipher and hash functions for s390x/zSeries. + + - Use hardware bit counting functions when available. + + * Internal changes: + + - The macOS getentropy syscall is used when available. [#5268] + + - Update DSA functions to match FIPS 186-3. [30ed9593f6] + + - New self-tests for CMACs and KDFs. [385a89e35b,7a0da24925] + + - Add bulk cipher functions for OFB and GCM modes. + [f12b6788f2,f4e63e92dc] + + Release-info: https://dev.gnupg.org/T5259 + + +Noteworthy changes in version 1.9.0 (2021-01-19) [C23/A3/R0] +------------------------------------------------ + + * New and extended interfaces: + + - New curves Ed448, X448, and SM2. + + - New cipher mode EAX. + + - New cipher algo SM4. + + - New hash algo SM3. + + - New hash algo variants SHA512/224 and SHA512/256. + + - New MAC algos for Blake-2 algorithms, the new SHA512 variants, + SM3, SM4 and for a GOST variant. + + - New convenience function gcry_mpi_get_ui. + + - gcry_sexp_extract_param understands new format specifiers to + directly store to integers and strings. + + - New function gcry_ecc_mul_point and curve constants for Curve448 + and Curve25519. [#4293] + + - New function gcry_ecc_get_algo_keylen. + + - New control code GCRYCTL_AUTO_EXPAND_SECMEM to allow growing the + secure memory area. Also in 1.8.2 as an undocumented feature. + + * Performance: + + - Optimized implementations for Aarch64. + + - Faster implementations for Poly1305 and ChaCha. Also for + PowerPC. [b9a471ccf5,172ad09cbe,#4460] + + - Optimized implementations of AES and SHA-256 on PowerPC. + [#4529,#4530] + + - Improved use of AES-NI to speed up AES-XTS (6 times faster). + [a00c5b2988] + + - Improved use of AES-NI for OCB. [eacbd59b13,e924ce456d] + + - Speedup AES-XTS on ARMv8/CE (2.5 times faster). [93503c127a] + + - New AVX and AVX2 implementations for Blake-2 (1.3/1.4 times + faster). [af7fc732f9, da58a62ac1] + + - Use Intel SHA extension for SHA-1 and SHA-256 (4.0/3.7 times + faster). [d02958bd30, 0b3ec359e2] + + - Use ARMv7/NEON accelerated GCM implementation (3 times faster). + [2445cf7431] + + - Use of i386/SSSE3 for SHA-512 (4.5 times faster on Ryzen 7). + [b52dde8609] + + - Use 64 bit ARMv8/CE PMULL for CRC (7 times faster). [14c8a593ed] + + - Improve CAST5 (40% to 70% faster). [4ec566b368] + + - Improve Blowfish (60% to 80% faster). [ced7508c85] + + * Bug fixes: + + - Fix infinite loop due to applications using fork the wrong + way. [#3491][also in 1.8.4] + + - Fix possible leak of a few bits of secret primes to pageable + memory. [#3848][also in 1.8.4] + + - Fix possible hang in the RNG (1.8.3 only). [#4034][also in 1.8.4] + + - Several minor fixes. [#4102,#4208,#4209,#4210,#4211,#4212] + [also in 1.8.4] + + - On Linux always make use of getrandom if possible and then use + its /dev/urandom behaviour. [#3894][also in 1.8.4] + + - Use blinding for ECDSA signing to mitigate a novel side-channel + attack. [#4011,CVE-2018-0495] [also in 1.8.3, 1.7.10] + + - Fix incorrect counter overflow handling for GCM when using an IV + size other than 96 bit. [#3764] [also in 1.8.3, 1.7.10] + + - Fix incorrect output of AES-keywrap mode for in-place encryption + on some platforms. [also in 1.8.3, 1.7.10] + + - Fix the gcry_mpi_ec_curve_point point validation function. + [also in 1.8.3, 1.7.10] + + - Fix rare assertion failure in gcry_prime_check. [also in 1.8.3] + + - Do not use /dev/srandom on OpenBSD. [also in 1.8.2] + + - Fix test suite failure on systems with large pages. [#3351] + [also in 1.8.2] + + - Fix test suite to not use mmap on Windows. [also in 1.8.2] + + - Fix fatal out of secure memory status in the s-expression parser + on heavy loaded systems. [also in 1.8.2] + + - Fix build problems on OpenIndiana et al. [#4818, also in 1.8.6] + + - Fix GCM bug on arm64 which troubles for example OMEMO. [#4986, + also in 1.8.6] + + - Detect a div-by-zero in a debug helper tool. [#4868, also in 1.8.6] + + - Use a constant time mpi_inv and related changes. [#4869, partly + also in 1.8.6] + + - Fix mpi_copy to correctly handle flags of opaque MPIs. + [also in 1.8.6] + + - Fix mpi_cmp to consider +0 and -0 the same. [also in 1.8.6] + + - Fix extra entropy collection via clock_gettime. Note that this + fallback code path is not used on any decent hardware. [#4966, + also in 1.8.7] + + - Support opaque MPI with gcry_mpi_print. [#4872, also in 1.8.7] + + - Allow for a Unicode random seed file on Windows. [#5098, also in + 1.8.7] + + * Other features: + + - Add OIDs from RFC-8410 as aliases for Ed25519 and Curve25519. + [also in 1.8.6] + + - Add mitigation against ECC timing attack CVE-2019-13627. [#4626] + + - Internal cleanup of the ECC implementation. + + - Support reading EC point in compressed format for some curves. + [#4951] + + * Interface changes relative to the 1.8.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gcry_mpi_get_ui NEW function. + GCRYCTL_AUTO_EXPAND_SECMEM NEW control code. + gcry_sexp_extract_param EXTENDED. + GCRY_CIPHER_GOST28147_MESH NEW cipher algo. + GCRY_CIPHER_SM4 NEW cipher algo. + GCRY_CIPHER_MODE_EAX NEW mode. + GCRY_ECC_CURVE25519 NEW curve id. + GCRY_ECC_CURVE448 NEW curve id. + gcry_ecc_get_algo_keylen NEW function. + gcry_ecc_mul_point NEW function. + GCRY_MD_SM3 NEW hash algo. + GCRY_MD_SHA512_256 NEW hash algo. + GCRY_MD_SHA512_224 NEW hash algo. + GCRY_MAC_GOST28147_IMIT NEW mac algo. + GCRY_MAC_HMAC_GOSTR3411_CP NEW mac algo. + GCRY_MAC_HMAC_BLAKE2B_512 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2B_384 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2B_256 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2B_160 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2S_256 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2S_224 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2S_160 NEW mac algo. + GCRY_MAC_HMAC_BLAKE2S_128 NEW mac algo. + GCRY_MAC_HMAC_SM3 NEW mac algo. + GCRY_MAC_HMAC_SHA512_256 NEW mac algo. + GCRY_MAC_HMAC_SHA512_224 NEW mac algo. + GCRY_MAC_CMAC_SM4 NEW mac algo. + + Release-info: https://dev.gnupg.org/T4294 + + Release dates of 1.8.x versions: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Version 1.8.2 (2017-12-13) + Version 1.8.3 (2018-06-13) + Version 1.8.4 (2018-10-26) + Version 1.8.5 (2019-08-29) + Version 1.8.6 (2020-07-06) + Version 1.8.7 (2020-10-23) + + +Noteworthy changes in version 1.8.1 (2017-08-27) [C22/A2/R1] +------------------------------------------------ + + * Bug fixes: + + - Mitigate a local side-channel attack on Curve25519 dubbed "May + the Fourth be With You". [CVE-2017-0379] [also in 1.7.9] + + - Add more extra bytes to the pool after reading a seed file. + + - Add the OID SHA384WithECDSA from RFC-7427 to SHA-384. + + - Fix build problems with the Jitter RNG + + - Fix assembler code build problems on Rasbian (ARMv8/AArch32-CE). + + +Noteworthy changes in version 1.8.0 (2017-07-18) [C22/A2/R0] +------------------------------------------------ + + * New interfaces: + + - New cipher mode XTS + + - New hash function Blake-2 + + - New function gcry_mpi_point_copy. + + - New function gcry_get_config. + + - GCRYCTL_REINIT_SYSCALL_CLAMP allows to init nPth after Libgcrypt. + + - New global configuration file /etc/gcrypt/random.conf. + + * Extended interfaces: + + - GCRYCTL_PRINT_CONFIG does now also print build information for + libgpg-error and the used compiler version. + + - GCRY_CIPHER_MODE_CFB8 is now supported. + + - Add Stribog OIDs. [also in 1.7.4] + + * Performance: + + - A jitter based entropy collector is now used in addition to the + other entropy collectors. + + - Optimized gcry_md_hash_buffers for SHA-256 and SHA-512. + + - More ARMv8/AArch32 improvements for AES, GCM, SHA-256, and SHA-1. + [also in 1.7.4] + + - Add ARMv8/AArch32 assembly implementation for Twofish and + Camellia. [also in 1.7.4] + + - Add bulk processing implementation for ARMv8/AArch32. + [also in 1.7.4] + + - Improve the DRBG performance and sync the code with the Linux + version. [also in 1.7.4] + + * Internal changes: + + - Libgpg-error 1.25 is now required. This avoids stalling of nPth + threads due to contention on internal Libgcrypt locks (e.g. the + random pool lock). + + - The system call clamp of libgpg-error is now used to wrap the + blocking read of /dev/random. This allows other nPth threads to + run while Libgcrypt is gathering entropy. + + - When secure memory is requested by the MPI functions or by + gcry_xmalloc_secure, they do not anymore lead to a fatal error if + the secure memory pool is used up. Instead new pools are + allocated as needed. These new pools are not protected against + being swapped out (mlock can't be used). However, these days + this is considered a minor issue and can easily be mitigated by + using encrypted swap space. [also in 1.7.4] + + * Bug fixes: + + - Fix AES CTR self-check detected failure in the SSSE3 based + implementation. [also in 1.7.6] + + - Remove gratuitous select before the getrandom syscall. + [also in 1.7.6] + + - Fix regression in mlock detection. [bug#2870] [also in 1.7.5] + + - Fix GOST 28147 CryptoPro-B S-box. [also in 1.7.4] + + - Fix error code handling of mlock calls. [also in 1.7.4] + + - Fix possible timing attack on EdDSA session key. [also in 1.7.7] + + - Fix long standing bug in secure memory implementation which could + lead to a segv on free. [bug#3027] [also in 1.7.7] + + - Mitigate a flush+reload side-channel attack on RSA secret keys + dubbed "Sliding right into disaster". For details see + . [CVE-2017-7526] [also in 1.7.8] + + * Interface changes relative to the 1.7.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gcry_get_config NEW function. + gcry_mpi_point_copy NEW function. + GCRYCTL_REINIT_SYSCALL_CLAMP NEW macro. + GCRY_MD_BLAKE2B_512 NEW constant. + GCRY_MD_BLAKE2B_384 NEW constant. + GCRY_MD_BLAKE2B_256 NEW constant. + GCRY_MD_BLAKE2B_160 NEW constant. + GCRY_MD_BLAKE2S_256 NEW constant. + GCRY_MD_BLAKE2S_224 NEW constant. + GCRY_MD_BLAKE2S_160 NEW constant. + GCRY_MD_BLAKE2S_128 NEW constant. + GCRY_CIPHER_MODE_XTS NEW constant. + gcry_md_info DEPRECATED. + + * Release dates of 1.7.x versions: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Version 1.7.10 (2018-06-13) [C21/A1/R10] + Version 1.7.9 (2017-08-27) [C21/A1/R9] + Version 1.7.8 (2017-06-29) [C21/A1/R8] + Version 1.7.7 (2017-06-02) [C21/A1/R7] + Version 1.7.6 (2017-01-18) [C21/A1/R6] + Version 1.7.5 (2016-12-15) [C21/A1/R5] + Version 1.7.4 (2016-12-09) [C21/A1/R4] + + +Noteworthy changes in version 1.7.3 (2016-08-17) [C21/A1/R3] +------------------------------------------------ + + * Bug fixes: + + - Fix critical security bug in the RNG [CVE-2016-6313]. An + attacker who obtains 580 bytes from the standard RNG can + trivially predict the next 20 bytes of output. Problem + detected by Felix Dörre and Vladimir Klebanov, KIT. + + - Fix building of some asm modules with older compilers and CPUs. + + * Performance: + + - ARMv8/AArch32 improvements for AES, GCM, SHA-256, and SHA-1. + + +Noteworthy changes in version 1.7.2 (2016-07-14) [C21/A1/R2] +------------------------------------------------ + + * Bug fixes: + + - Fix setting of the ECC cofactor if parameters are specified. + + - Fix memory leak in the ECC code. + + - Remove debug message about unsupported getrandom syscall. + + - Fix build problems related to AVX use. + + - Fix bus errors on ARM for Poly1305, ChaCha20, AES, and SHA-512. + + * Internal changes: + + - Improved fatal error message for wrong use of gcry_md_read. + + - Disallow symmetric encryption/decryption if key is not set. + + +Noteworthy changes in version 1.7.1 (2016-06-15) [C21/A1/R1] +------------------------------------------------ + + * Bug fixes: + + - Fix ecc_verify for cofactor support. + + - Fix portability bug when using gcc with Solaris 9 SPARC. + + - Build fix for OpenBSD/amd64 + + - Add OIDs to the Serpent ciphers. + + * Internal changes: + + - Use getrandom system call on Linux if available. + + - Blinding is now also used for RSA signature creation. + + - Changed names of debug envvars + + +Noteworthy changes in version 1.7.0 (2016-04-15) [C21/A1/R0] +------------------------------------------------ + + * New algorithms and modes: + + - SHA3-224, SHA3-256, SHA3-384, SHA3-512, and MD2 hash algorithms. + + - SHAKE128 and SHAKE256 extendable-output hash algorithms. + + - ChaCha20 stream cipher. + + - Poly1305 message authentication algorithm + + - ChaCha20-Poly1305 Authenticated Encryption with Associated Data + mode. + + - OCB mode. + + - HMAC-MD2 for use by legacy applications. + + * New curves for ECC: + + - Curve25519. + + - sec256k1. + + - GOST R 34.10-2001 and GOST R 34.10-2012. + + * Performance: + + - Improved performance of KDF functions. + + - Assembler optimized implementations of Blowfish and Serpent on + ARM. + + - Assembler optimized implementation of 3DES on x86. + + - Improved AES using the SSSE3 based vector permutation method by + Mike Hamburg. + + - AVX/BMI is used for SHA-1 and SHA-256 on x86. This is for SHA-1 + about 20% faster than SSSE3 and more than 100% faster than the + generic C implementation. + + - 40% speedup for SHA-512 and 72% for SHA-1 on ARM Cortex-A8. + + - 60-90% speedup for Whirlpool on x86. + + - 300% speedup for RIPE MD-160. + + - Up to 11 times speedup for CRC functions on x86. + + * Other features: + + - Improved ECDSA and FIPS 186-4 compliance. + + - Support for Montgomery curves. + + - gcry_cipher_set_sbox to tweak S-boxes of the gost28147 cipher + algorithm. + + - gcry_mpi_ec_sub to subtract two points on a curve. + + - gcry_mpi_ec_decode_point to decode an MPI into a point object. + + - Emulation for broken Whirlpool code prior to 1.6.0. [from 1.6.1] + + - Flag "pkcs1-raw" to enable PCKS#1 padding with a user supplied + hash part. + + - Parameter "saltlen" to set a non-default salt length for RSA PSS. + + - A SP800-90A conforming DRNG replaces the former X9.31 alternative + random number generator. + + - Map deprecated RSA algo number to the RSA algo number for better + backward compatibility. [from 1.6.2] + + - Use ciphertext blinding for Elgamal decryption [CVE-2014-3591]. + See http://www.cs.tau.ac.il/~tromer/radioexp/ for details. + [from 1.6.3] + + - Fixed data-dependent timing variations in modular exponentiation + [related to CVE-2015-0837, Last-Level Cache Side-Channel Attacks + are Practical]. [from 1.6.3] + + - Flag "no-keytest" for ECC key generation. Due to a bug in + the parser that flag will also be accepted but ignored by older + version of Libgcrypt. [from 1.6.4] + + - Speed up the random number generator by requiring less extra + seeding. [from 1.6.4] + + - Always verify a created RSA signature to avoid private key leaks + due to hardware failures. [from 1.6.4] + + - Mitigate side-channel attack on ECDH with Weierstrass curves + [CVE-2015-7511]. See http://www.cs.tau.ac.IL/~tromer/ecdh/ for + details. [from 1.6.5] + + * Internal changes: + + - Moved locking out to libgpg-error. + + - Support of the SYSROOT envvar in the build system. + + - Refactor some code. + + - The availability of a 64 bit integer type is now mandatory. + + * Bug fixes: + + - Fixed message digest lookup by OID (regression in 1.6.0). + + - Fixed a build problem on NetBSD + + - Fixed memory leaks in ECC code. + + - Fixed some asm build problems and feature detection bugs. + + * Interface changes relative to the 1.6.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gcry_cipher_final NEW macro. + GCRY_CIPHER_MODE_CFB8 NEW constant. + GCRY_CIPHER_MODE_OCB NEW. + GCRY_CIPHER_MODE_POLY1305 NEW. + gcry_cipher_set_sbox NEW macro. + gcry_mac_get_algo NEW. + GCRY_MAC_HMAC_MD2 NEW. + GCRY_MAC_HMAC_SHA3_224 NEW. + GCRY_MAC_HMAC_SHA3_256 NEW. + GCRY_MAC_HMAC_SHA3_384 NEW. + GCRY_MAC_HMAC_SHA3_512 NEW. + GCRY_MAC_POLY1305 NEW. + GCRY_MAC_POLY1305_AES NEW. + GCRY_MAC_POLY1305_CAMELLIA NEW. + GCRY_MAC_POLY1305_SEED NEW. + GCRY_MAC_POLY1305_SERPENT NEW. + GCRY_MAC_POLY1305_TWOFISH NEW. + gcry_md_extract NEW. + GCRY_MD_FLAG_BUGEMU1 NEW [from 1.6.1]. + GCRY_MD_GOSTR3411_CP NEW. + GCRY_MD_SHA3_224 NEW. + GCRY_MD_SHA3_256 NEW. + GCRY_MD_SHA3_384 NEW. + GCRY_MD_SHA3_512 NEW. + GCRY_MD_SHAKE128 NEW. + GCRY_MD_SHAKE256 NEW. + gcry_mpi_ec_decode_point NEW. + gcry_mpi_ec_sub NEW. + GCRY_PK_EDDSA NEW constant. + GCRYCTL_GET_TAGLEN NEW. + GCRYCTL_SET_SBOX NEW. + GCRYCTL_SET_TAGLEN NEW. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Version 1.6.5 (2016-02-09) [C20/A0/R5] +Version 1.6.4 (2015-09-08) [C20/A0/R4] +Version 1.6.3 (2015-02-27) [C20/A0/R3] +Version 1.6.2 (2014-08-21) [C20/A0/R2] +Version 1.6.1 (2014-01-29) [C20/A0/R1] + + +Noteworthy changes in version 1.6.0 (2013-12-16) [C20/A0/R0] +------------------------------------------------ + + * Removed the long deprecated gcry_ac interface. Thus Libgcrypt is + not anymore ABI compatible to previous versions if they used the ac + interface. + + * Removed the module register subsystem. + + * The deprecated message digest debug macros have been removed. Use + gcry_md_debug instead. + + * Removed deprecated control codes. + + * Improved performance of most cipher algorithms as well as for the + SHA family of hash functions. + + * Added support for the IDEA cipher algorithm. + + * Added support for the Salsa20 and reduced Salsa20/12 stream ciphers. + + * Added limited support for the GOST 28147-89 cipher algorithm. + + * Added support for the GOST R 34.11-94 and R 34.11-2012 (Stribog) + hash algorithms. + + * Added a random number generator to directly use the system's RNG. + Also added an interface to prefer the use of a specified RNG. + + * Added support for the SCRYPT algorithm. + + * Mitigated the Yarom/Falkner flush+reload side-channel attack on RSA + secret keys. See [CVE-2013-4242]. + + * Added support for Deterministic DSA as per RFC-6979. + + * Added support for curve Ed25519. + + * Added a scatter gather hash convenience function. + + * Added several MPI amd SEXP helper functions. + + * Added support for negative numbers to gcry_mpi_print, + gcry_mpi_aprint and gcry_mpi_scan. + + * The algorithm ids GCRY_PK_ECDSA and GCRY_PK_ECDH are now + deprecated. Use GCRY_PK_ECC if you need an algorithm id. + + * Changed gcry_pk_genkey for "ecc" to only include the curve name and + not the parameters. The flag "param" may be used to revert this. + + * Added a feature to globally disable selected hardware features. + + * Added debug helper functions. + + * Interface changes relative to the 1.5.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gcry_ac_* REMOVED. + GCRY_AC_* REMOVED. + gcry_module_t REMOVED. + gcry_cipher_register REMOVED. + gcry_cipher_unregister REMOVED. + gcry_cipher_list REMOVED. + gcry_pk_register REMOVED. + gcry_pk_unregister REMOVED. + gcry_pk_list REMOVED. + gcry_md_register REMOVED. + gcry_md_unregister REMOVED. + gcry_md_list REMOVED. + gcry_md_start_debug REMOVED (macro). + gcry_md_stop_debug REMOVED (macro). + GCRYCTL_SET_KEY REMOVED. + GCRYCTL_SET_IV REMOVED. + GCRYCTL_SET_CTR REMOVED. + GCRYCTL_DISABLE_ALGO CHANGED: Not anymore thread-safe. + gcry_pk_genkey CHANGED: ECC curve params not returned. + gcry_md_hash_buffers NEW. + gcry_buffer_t NEW. + GCRYCTL_SET_ENFORCED_FIPS_FLAG NEW. + GCRYCTL_SET_PREFERRED_RNG_TYPE NEW. + GCRYCTL_GET_CURRENT_RNG_TYPE NEW. + GCRYCTL_CLOSE_RANDOM_DEVICE NEW. + GCRY_RNG_TYPE_STANDARD NEW. + GCRY_RNG_TYPE_FIPS NEW. + GCRY_RNG_TYPE_SYSTEM NEW. + gcry_mpi_is_neg NEW. + gcry_mpi_neg NEW. + gcry_mpi_abs NEW. + gcry_mpi_snatch NEW. + gcry_mpi_set_opaque_copy NEW. + gcry_mpi_point_t NEW. + gcry_mpi_point_new NEW. + gcry_mpi_point_release NEW. + gcry_mpi_point_get NEW. + gcry_mpi_point_snatch_get NEW. + gcry_mpi_point_set NEW. + gcry_mpi_point_snatch_set NEW. + gcry_ctx_t NEW. + gcry_ctx_release NEW. + gcry_mpi_ec_new NEW. + gcry_mpi_ec_get_mpi NEW. + gcry_mpi_ec_get_point NEW. + gcry_mpi_ec_set_mpi NEW. + gcry_mpi_ec_set_point NEW. + gcry_mpi_ec_get_affine NEW. + gcry_mpi_ec_dup NEW. + gcry_mpi_ec_add NEW. + gcry_mpi_ec_mul NEW. + gcry_mpi_ec_curve_point NEW. + GCRYMPI_FLAG_IMMUTABLE NEW. + GCRYMPI_FLAG_CONST NEW. + GCRYMPI_FLAG_USER1 NEW. + GCRYMPI_FLAG_USER2 NEW. + GCRYMPI_FLAG_USER3 NEW. + GCRYMPI_FLAG_USER4 NEW. + GCRYMPI_CONST_ONE NEW. + GCRYMPI_CONST_TWO NEW. + GCRYMPI_CONST_THREE NEW. + GCRYMPI_CONST_FOUR NEW. + GCRYMPI_CONST_EIGHT NEW. + GCRYMPI_FMT_OPAQUE NEW. + GCRYPT_VERSION_NUMBER NEW. + GCRY_KDF_SCRYPT NEW. + gcry_pubkey_get_sexp NEW. + GCRYCTL_DISABLE_LOCKED_SECMEM NEW. + GCRYCTL_DISABLE_PRIV_DROP NEW. + GCRY_CIPHER_SALSA20 NEW. + gcry_sexp_nth_buffer NEW. + gcry_sexp_extract_param NEW. + GCRY_CIPHER_SALSA20R12 NEW. + GCRY_CIPHER_GOST28147 NEW. + GCRY_MD_GOSTR3411_94 NEW. + GCRY_MD_STRIBOG256 NEW. + GCRY_MD_STRIBOG512 NEW. + GCRY_PK_ECC NEW. + gcry_log_debug NEW. + gcry_log_debughex NEW. + gcry_log_debugmpi NEW. + gcry_log_debugpnt NEW. + + +Noteworthy changes in version 1.5.0 (2011-06-29) +------------------------------------------------ + + * New function gcry_kdf_derive implementing OpenPGP S2K algorithms + and PBKDF2. + + * Support for WindowsCE. + + * Support for ECDH. + + * Support for OAEP and PSS methods as described by RFC-3447. + + * Fixed PKCS v1.5 code to always return the leading zero. + + * New format specifiers "%M" and "%u" for gcry_sexp_build. + + * Support opaque MPIs with "%m" and "%M" in gcry_sexp_build. + + * New functions gcry_pk_get_curve and gcry_pk_get_param to map ECC + parameters to a curve name and to retrieve parameter values. + + * gcry_mpi_cmp applied to opaque values has a defined semantic now. + + * Uses the Intel AES-NI instructions if available. + + * The use of the deprecated Alternative Public Key Interface + (gcry_ac_*) will now print compile time warnings. + + * The module register subsystem has been deprecated. This subsystem + is not flexible enough and would always require ABI changes to + extend the internal interfaces. It will eventually be removed. + Please contact us on the gcrypt-devel mailing list to discuss + whether you really need this feature or how it can be replaced by + an internal plugin mechanism. + + * CTR mode may now be used with data chunks of arbitrary length. + + * Changes also done in 1.4.6 (2010-07-13): + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + * New variants of the TIGER algorithm. + + * New cipher algorithm mode for AES-WRAP. + + * Changes also done in 1.4.5 (2009-12-11): + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + * Fixed minor memory leak in DSA key generation. + + * No more switching to FIPS mode if /proc/version is not readable. + + * Fixed sigill during Padlock detection on old CPUs. + + * Fixed a hang on some W2000 machines. + + * Boosted SHA-512 performance by 30% on ia32 boxes and gcc 4.3; + SHA-256 went up by 25%. + + * Interface changes relative to the 1.4.6 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GCRY_PK_ECDH NEW. + gcry_pk_get_curve NEW. + gcry_pk_get_param NEW. + GCRYCTL_DISABLE_HWF NEW. + gcry_kdf_derive NEW. + gcry_pk_encrypt EXTENDED: Support OAEP. + gcry_pk_decrypt EXTENDED: Support OAEP. + gcry_pk_sign EXTENDED: Support PSS. + gcry_pk_verify EXTENDED: Support PSS. + gcry_sexp_build EXTENDED: Add format specifiers M and u. + + * Interface changes relative to the 1.4.2 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GCRY_CIPHER_MODE_AESWRAP NEW. + GCRY_MD_TIGER1 NEW. + GCRY_MD_TIGER2 NEW. + + +Noteworthy changes in version 1.4.4 (2009-01-22) +------------------------------------------------ + + * Publish GCRY_MODULE_ID_USER and GCRY_MODULE_ID_USER_LAST constants. + This functionality has been in Libgcrypt since 1.3.0. + + * MD5 may now be used in non-enforced fips mode. + + * Fixed HMAC for SHA-384 and SHA-512 with keys longer than 64 bytes. + + * In fips mode, RSA keys are now generated using the X9.31 algorithm + and DSA keys using the FIPS 186-2 algorithm. + + * The transient-key flag is now also supported for DSA key + generation. DSA domain parameters may be given as well. + + +Noteworthy changes in version 1.4.3 (2008-09-18) +------------------------------------------------ + + * Try to auto-initialize Libgcrypt to minimize the effect of + applications not doing that correctly. This is not a perfect + solution but given that many applicationion would totally fail + without such a hack, we try to help at least with the most common + cases. Folks, please read the manual to learn how to properly + initialize Libgcrypt! + + * Auto-initialize the secure memory to 32k instead of aborting the + process. + + * Log fatal errors via syslog. + + * Changed the name and the semantics of the fips mode config file. + + * Add convenience macro gcry_fips_mode_active. + + * More self-tests. + + * Documentation cleanups. + + +Noteworthy changes in version 1.4.2 (2008-09-08) +------------------------------------------------ + + * The long missing gcry_mpi_lshift function has been added. + + * RSA key generation now supports a "transient-key" flag. + + * The keygrip computation for ECDSA has been implemented thus ECDSA + is now fully supported. + + * A few macros have been replaced by functions for better type + checking. + + * The thread initialization structure now carries version + information. + + * The manual describes more clearly how to initialize Libgcrypt. + + * The library may now be switched into a FIPS mode. + + * Interface changes relative to the 1.3.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GCRYCTL_OPERATIONAL_P NEW. + GCRYCTL_FIPS_MODE_P NEW. + GCRYCTL_FORCE_FIPS_MODE NEW. + gcry_cipher_setkey NEW: Replaces macro. + gcry_cipher_setiv NEW: Replaces macro. + gcry_cipher_setctr NEW: Replaces macro. + gcry_mpi_lshift NEW. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Noteworthy changes in version 1.4.1 (2008-04-25) +------------------------------------------------ + + * Fixed a bug introduced by 1.3.1 which led to the comsumption of far + too much entropy for the intial seeding. + + * Improved AES performance for CFB and CBC modes. + + * Removed build problems for the Padlock support. + + +Noteworthy changes in version 1.4.0 (2007-12-10) +------------------------------------------------ + + * New configure option --disable-padlock-support which is mostly + useful in case of build problems. + + +Noteworthy changes in version 1.3.2 (2007-12-03) +------------------------------------------------ + + * The visibility attribute is now used if supported by the toolchain. + + * The ACE engine of VIA processors is now used for AES-128. + + * The ASN.1 DER template for SHA-224 has been fixed. + + +Noteworthy changes in version 1.3.1 (2007-10-26) +------------------------------------------------ + + * The entire library is now under the LGPL. The helper programs and + the manual are under the GPL. Kudos to Peter Gutmann for giving + permissions to relicense the rndw32 and rndunix modules. + + * The Camellia cipher is now under the LGPL and included by default. + + * Fixed a bug in the detection of symbol prefixes which inhibited the + build of optimzied assembler code on certain systems. + + * Updated the entropy gatherer for W32. + + +Noteworthy changes in version 1.3.0 (2007-05-04) +------------------------------------------------ + + * Changed the way the RNG gets initialized. This allows to keep it + uninitialized as long as no random numbers are used. To override + this, the new macro gcry_fast_random_poll may be used. It is in + general a good idea to spread this macro into the application code + to make sure that these polls happen often enough. + + * Made the RNG immune against fork without exec. + + * Reading and writing the random seed file is now protected by a + fcntl style file lock on systems that provide this function. + + * Support for SHA-224 and HMAC using SHA-384 and SHA-512. + + * Support for the SEED cipher. + + * Support for the Camellia cipher. Note that Camellia is disabled by + default, and that enabling it changes the license of libgcrypt from + LGPL to GPL. + + * Support for OFB encryption mode. + + * gcry_mpi_rshift does not anymore truncate the shift count. + + * Reserved algorithm ranges for use by applications. + + * Support for DSA2. + + * The new function gcry_md_debug should be used instead of the + gcry_md_start_debug and gcry_md_stop_debug macros. + + * New configure option --enable-random-daemon to support a system + wide random daemon. The daemon code is experimental and not yet + very well working. It will eventually allow to keep a global + random pool for the sake of short living processes. + + * Non executable stack support is now used by default on systems + supporting it. + + * Support for Microsoft Windows. + + * Assembler support for the AMD64 architecture. + + * New configure option --enable-mpi-path for optimized builds. + + * Experimental support for ECDSA; should only be used for testing. + + * New control code GCRYCTL_PRINT_CONFIG to print the build + configuration. + + * Minor changes to some function declarations. Buffer arguments are + now typed as void pointer. This should not affect any compilation. + Fixed two bugs in return values and clarified documentation. + + * Interface changes relative to the 1.2.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gcry_fast_random_poll NEW + gcry_md_debug NEW + gcry_sexp_nth_string NEW + GCRY_MD_SHA224 NEW + GCRY_PK_USAGE_CERT NEW + GCRY_PK_USAGE_AUTH NEW + GCRY_PK_USAGE_UNKN NEW + GCRY_PK_ECDSA NEW + GCRY_CIPHER_SEED NEW + GCRY_CIPHER_CAMELLIA128 NEW + GCRY_CIPHER_CAMELLIA192 NEW + GCRY_CIPHER_CAMELLIA256 NEW + GCRYCTL_FAKED_RANDOM_P NEW + GCRYCTL_PRINT_CONFIG NEW + GCRYCTL_SET_RNDEGD_SOCKET NEW. + gcry_mpi_scan CHANGED: Argument BUFFER is now void*. + gcry_pk_algo_name CHANGED: Returns "?" instead of NULL. + gcry_cipher_algo_name CHANGED: Returns "?" instead of "". + gcry_pk_spec_t CHANGED: Element ALIASES is now const ptr. + gcry_md_write_t CHANGED: Argument BUF is now a const void*. + gcry_md_ctl CHANGED: Argument BUFFER is now void*. + gcry_cipher_encrypt CHANGED: Arguments IN and OUT are now void*. + gcry_cipher_decrypt CHANGED: Arguments IN and OUT are now void*. + gcry_sexp_sprint CHANGED: Argument BUFFER is now void*. + gcry_create_nonce CHANGED: Argument BUFFER is now void*. + gcry_randomize CHANGED: Argument BUFFER is now void*. + gcry_cipher_register CHANGED: Argument ALGORITHM_ID is now int*. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Noteworthy changes in version 1.2.0 (2004-04-15) +------------------------------------------------ + + * First stable release. + + +Noteworthy changes in version 1.1.94 (2004-03-29) +------------------------------------------------- + + * The support for multi-threaded users goes into its third + incarnation. We removed compile time support for thread libraries. + To support the thread library of your choice, you have to set up + callback handlers at initialization time. New data structures, a + new control command, and default initializers are provided for this + purpose. + + * Interface changes relative to the 1.1.93 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +libgcrypt-config --thread OBSOLETE +libgcrypt-pth.la REMOVED +libgcrypt-pthread.la REMOVED +GCRYCTL_SET_THREAD_CBS NEW +struct gcrypt_thread_cbs NEW +enum gcry_thread_option NEW +GCRY_THREAD_OPTION_PTH_IMPL NEW +GCRY_THREAD_OPTION_PTHREAD_IMPL NEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Noteworthy changes in version 1.1.93 (2004-03-06) +------------------------------------------------- + + * The automatic thread library detection has finally been removed. + From now on, only linking explicitely to libgcrypt, libgcrypt-pth + or libgcrypt-pthread is supported. + +Noteworthy changes in version 1.1.92 (2004-02-20) +------------------------------------------------- + + * Minor bug fixes. + + * Included a limited implementation of RFC2268. + + * Changed API of the gcry_ac_ functions. Only a very few programs + should be affected by this. + + * Interface changes relative to the 1.1.91 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +GCRY_CIPHER_RFC2268_40 NEW. +gcry_ac_data_set CHANGED: New argument FLAGS. +gcry_ac_data_get_name CHANGED: New argument FLAGS. +gcry_ac_data_get_index CHANGED: New argument FLAGS. +gcry_ac_key_pair_generate CHANGED: New and reordered arguments. +gcry_ac_key_test CHANGED: New argument HANDLE. +gcry_ac_key_get_nbits CHANGED: New argument HANDLE. +gcry_ac_key_get_grip CHANGED: New argument HANDLE. +gcry_ac_data_search REMOVED. +gcry_ac_data_add REMOVED. +GCRY_AC_DATA_FLAG_NO_BLINDING REMOVED. +GCRY_AC_FLAG_NO_BLINDING NEW: Replaces above. + + +Noteworthy changes in version 1.1.91 (2003-12-19) +------------------------------------------------- + + * Code cleanups and minor bug fixes. + + +Noteworthy changes in version 1.1.90 (2003-11-14) +------------------------------------------------- + + * The use of the GCRY_WEAK_RANDOM level is now deprecated in favor of + the new gcry_create_nonce function. + + * gcry_sexp_build now supports a "%b" format to include a memory buffer. + + * Minor configuration fixes. + + * Interface changes relative to the 1.1.44 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +gcry_create_nonce NEW +gcry_sexp_build ENHANCED + + +Noteworthy changes in version 1.1.44 (2003-10-31) +------------------------------------------------- + + * Bug fixes and more code cleanups. + + * Enhanced the prime API. + + * Interface changes relative to the 1.1.43 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +gcry_prime_group_generator NEW +gcry_prime_release_factors NEW + + +Noteworthy changes in version 1.1.43 (2003-09-04) +------------------------------------------------- + + * Bug fixes and internal code cleanups. + + * Support for the Serpent cipher algorithm. + + * Interface changes relative to the 1.1.42 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +gcry_prime_generate NEW +gcry_prime_check NEW + + +Noteworthy changes in version 1.1.42 (2003-07-31) +------------------------------------------------- + + * Major API cleanup. Applications need to be converted to the new + API. See README.apichanges for hints on how to do that. Backward + compatibility is provided where it was possible without too much + effort and did not collide with the overall sanitization effort. + However, this is only for ease of transition. NO DEPRECATED + FUNCTION OR DATA TYPE IS CONSIDERED A PART OF THE API OR ABI AND + WILL BE DROPPED IN THE FUTURE WITHOUT CHANGING THE SONAME OF THE + LIBRARY. + + * If gcrypt.h is included in sources compiled by GCC 3.1 or later, + deprecated attributes will warn about use of obsolete functions and + type definitions. You can suppress these warnings by passing + -Wno-deprecated-declarations to the gcc command. + + * gcry_check_version must be called from now on to initialize the + library, it is not longer optional. + + * Removed `libgcrypt errno' concept. + + * Libgcrypt depends on libgpg-error, a library that provides error + codes and according functions for all GnuPG components. Functions + that used to return error codes asa `int' have been changed to + return a code of type `gcry_error_t'. All GCRYERR_* error symbols + have been removed, since they are now contained in libgpg-error + (GPG_ERR_*). All functions and types in libgpg-error have also been + wrapped in Libgcrypt. The new types are gcry_err_code_t and + gcry_err_source_t. The new functions are gcry_err_code, + gcry_err_source, gcry_error, gcry_err_make, gcry_error_from_errno, + gcry_err_make_from_errno, gcry_err_code_from_errno, + gcry_err_code_to_errno, gcry_strsource. + + * New function gcry_mpi_dump to help in debugging. + + * Added alternative interface for asymmetric cryptography. + + * CRC-32, CRC-32 a'la RFC 1510, CRC-24 a'la RFC 2440 are now + supported. + + * SHA-256, SHA-384 and SHA-512 are now supported. + + * 128 bit Twofish is now supported. + + * The random module won't print the "not enough random bytes + available" anymore. A new progress status is issued instead. + + * CBC-MAC for block ciphers is now supported, by using a + GCRY_CIPHER_CBC_MAC cipher flag. + + * CTR mode for block ciphers is now supported. + + * The public RSA exponent can now be specified in key generation. + + * RSA blinding is now supported and is used automatically for RSA + decryption. It can be explicitely disabled by using the + `no-blinding' symbol in the `flags' S-Expression or by using the + GCRY_AC_FLAG_DATA_NO_BLINDING flag when using the ac interface. + + * gcry_sexp_canon_len does not use a `historically encoded' error + code anymore. + + + * Interface changes relative to the 1.1.12 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +GCRY_MPI DEPRECATED; Use: gcry_mpi_t +GcryMPI DEPRECATED; Use: gcry_mpi_t +GCRY_SEXP DEPRECATED; Use: gcry_sexp_t +GcrySexp DEPRECATED; Use: gcry_sexp_t +GCRY_CIPHER_HD DEPRECATED; Use: gcry_cipher_hd_t +GcryCipherHd DEPRECATED; Use: gcry_cipher_hd_t +GCRY_MD_HD DEPRECATED; Use: gcry_md_hd_t +GcryMDHd DEPRECATED; Use: gcry_md_hd_t +gcry_error_t NEW +gcry_err_code_t NEW +gcry_err_source_t NEW +gcry_err_make NEW +gcry_error NEW +gcry_err_code NEW +gcry_err_source NEW +gcry_err_code_from_errno NEW +gcry_err_code_to_errno NEW +gcry_err_make_from_errno NEW +gcry_error_from_errno NEW +gcry_strsource NEW +GCRYERR_{some error code} REMOVED; Use GPG_ERR_* + from libgpg-error instead. +gcry_errno REMOVED +gcry_sexp_canon_len CHANGED +gcry_sexp_build_array NEW +gcry_mpi_scan CHANGED: New argument to separate in/out args. +gcry_mpi_print CHANGED: Ditto. +gcry_mpi_dump NEW +gcry_cipher_open CHANGED +gcry_cipher_reset NEW +gcry_cipher_register NEW +gcry_cipher_unregister NEW +gcry_cipher_list NEW +gcry_cipher_algo_keylen REPLACED macro with function. +gcry_cipher_algo_blklen REPLACED macro with function. +gcry_pk_register NEW +gcry_pk_unregister NEW +gcry_pk_list NEW +gcry_pk_decrypt ENHANCED: Allows flag to return + complete S-expression. +gcry_md_open CHANGED +gcry_md_copy CHANGED +gcry_md_is_enabled NEW +gcry_md_is_secure NEW +gcry_md_register NEW +gcry_md_unregister NEW +gcry_md_list NEW +gcry_ac_data_t NEW +gcry_ac_key_t NEW +gcry_ac_key_pair_t NEW +gcry_ac_handle_t NEW +gcry_ac_key_spec_rsa_t NEW +gcry_ac_data_new NEW +gcry_ac_data_destroy NEW +gcry_ac_data_set NEW +gcry_ac_data_copy NEW +gcry_ac_data_length NEW +gcry_ac_data_get_name NEW +gcry_ac_data_get_index NEW +gcry_ac_data_clear NEW +gcry_ac_open NEW +gcry_ac_close NEW +gcry_ac_key_init NEW +gcry_ac_key_pair_generate NEW +gcry_ac_key_pair_extract NEW +gcry_ac_key_data_get NEW +gcry_ac_key_test NEW +gcry_ac_key_get_nbits NEW +gcry_ac_key_get_grip NEW +gcry_ac_key_destroy NEW +gcry_ac_key_pair_destroy NEW +gcry_ac_data_encrypt NEW +gcry_ac_data_decrypt NEW +gcry_ac_data_sign NEW +gcry_ac_data_verify NEW +gcry_ac_id_to_name NEW +gcry_ac_name_to_id NEW +gcry_handler_progress_t NEW +gcry_handler_alloc_t NEW +gcry_handler_secure_check_t NEW +gcry_handle_realloc_t NEW +gcry_handler_free_t NEW +gcry_handler_no_mem_t NEW +gcry_handler_error_t NEW +gcry_handler_log_t NEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Noteworthy changes in version 1.1.12 (2003-01-20) +------------------------------------------------- + + * gcry_pk_sign, gcry_pk_verify and gcry_pk_encrypt can now handle an + optional pkcs1 flags parameter in the S-expression. A similar flag + may be passed to gcry_pk_decrypt but it is only syntactically + implemented. + + * New convenience macro gcry_md_get_asnoid. + + * There is now some real stuff in the manual. + + +Noteworthy changes in version 1.1.11 (2002-12-21) +------------------------------------------------- + + * Don't export internal symbols anymore (currently only for GNU systems) + + * New algorithm: MD4 + + * Implemented ciphertext stealing. + + * Smaller bugs fixes and a few new OIDs. + + * Interface changes relative to the 1.1.8 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +gcry_cipher_cts NEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Noteworthy changes in version 1.1.10 (2002-09-20) +------------------------------------------------- + + * Fixed shared library builds for i386, PPC and Sparc. + + * Added simple benchmark tool. + + * Replaced the internal mutexes by code which automatically adapts to + the used threading library. Currently Pth and Pthread are + supported. For non-ELF systems the GNU toolchain is now required.. + + * Added untested support to build Windows DLLs. + +Noteworthy changes in version 1.1.9 (2002-08-23) +------------------------------------------------ + + * Support for plain old DES. + + +Noteworthy changes in version 1.1.8 (2002-06-25) +------------------------------------------------ + + * Minor cleanups and exported a few new functions. + + * Interface changes relative to the 1.1.7 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +gcry_mpi_div NEW +gcry_mpi_mod NEW +gcry_mpi_invm NEW +gcry_mpi_swap NEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Noteworthy changes in version 1.1.7 (2002-05-21) +------------------------------------------------ + +* Libgcrypt is now distributed under the terms of the GNU Lesser + General Public License; see the README file for details. + +* It is possible to use libgcrypt w/o intialized secure memory. + +* Libgcrypt should now be thread safe after the initialization. + gcry_control (GCRYCRL_INITIALIZATION_FINISHED,NULL,0) should have + been called before creating additional threads. + + * Interface changes relative to the 1.1.6 release: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +GCRYCTL_DISABLE_INTERNAL_LOCKING NEW +GCRYCTL_DISABLE_SECMEM NEW +GCRYCTL_INITIALIZATION_FINISHED NEW +GCRYCTL_INITIALIZATION_FINISHED_P NEW +GCRYCTL_ANY_INITIALIZATION_P NEW +gcry_strdup NEW +gcry_sexp_create NEW +gcry_sexp_new NEW +gcry_set_progress_handler NEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Noteworthy changes in version 1.1.6 (2002-02-07) +------------------------------------------------ + + * Enhanced the S-expression conversion functions. + +Noteworthy changes in version 1.1.5 (2001-12-18) +------------------------------------------------ + + * gcry_{cipher,md}_map_name are now able to map stringified object IDs. + + * New functions gcry_sexp_canon_len and gcry_cipher_mode_from_oid. + + * Closed some memory leaks. + + +Noteworthy changes in version 1.1.4 (2001-08-03) +------------------------------------------------ + + * Arcfour does now work. + + * Some minor fixes. + + * Added a first test program + + * Migrated to autoconf 2.52. + + +Noteworthy changes in version 1.1.3 (2001-05-31) +------------------------------------------------ + + * First release of Libgcrypt which is a result of splitting GnuPG + into into libgcrypt and GnuPG. + + +Copyright 2001, 2002, 2003, 2004, 2007, 2008, + 2009, 2011 Free Software Foundation, Inc. +Copyright 2013 g10 Code GmbH + +This file is free software; as a special exception the author gives +unlimited permission to copy and/or distribute it, with or without +modifications, as long as this notice is preserved. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/comm/third_party/libgcrypt/README b/comm/third_party/libgcrypt/README new file mode 100644 index 0000000000..1304669a1c --- /dev/null +++ b/comm/third_party/libgcrypt/README @@ -0,0 +1,276 @@ + Libgcrypt - The GNU Crypto Library + ------------------------------------ + Version 1.9 + + Copyright (C) 1989,1991-2018 Free Software Foundation, Inc. + Copyright (C) 2012-2021 g10 Code GmbH + Copyright (C) 2013-2021 Jussi Kivilinna + + Libgcrypt is free software. See the file AUTHORS for full copying + notices, and LICENSES for notices about contributions that require + these additional notices to be distributed. + + + Overview + -------- + + Libgcrypt is a general purpose crypto library based on the code + used in GnuPG. Libgcrypt depends on the library `libgpg-error', + which must be installed correctly before Libgcrypt is to be built. + Libgcrypt is distributed under the LGPL, see the section "License" + below for details. + + + Build Instructions + ------------------ + + The download canonical location for libgcrypt is: + + ftp://ftp.gnupg.org/gcrypt/libgcrypt/ + or + https://gnupg.org/ftp/gcrypt/libgcrypt/ + + To build libgcrypt you need libgpg-error: + + ftp://ftp.gnupg.org/gcrypt/libgpg-error/ + or + https://gnupg.org/ftp/gcrypt/libgpg-error/ + + You should get the latest versions of course. + + After building and installing the libgpg-error package, you may + continue with Libgcrypt installation as with allmost all GNU + packages, you just have to do + + ./configure + make + make check + make install + + The "make check" is not required but a good idea to see whether + the library works as expected. The check takes some while and + prints some benchmarking results. Before doing "make install" you + probably need to become root. + + To build libgcrypt for Microsoft Windows, you need to have the + mingw32 cross-building toolchain installed. Instead of running a + plain configure you use + + ./autogen.sh --build-w32 + make + make install + + By default this command sequences expectsd a libgpg-error + installed below $HOME/w32root and installs libgcrypt to that + directory too. See the autogen.sh code for details. + + The documentation is available as an Info file (gcrypt.info). To + build documentation in PDF, run this: + + cd doc + make pdf + + + + Mailing List + ------------ + + You may want to join the developer's mailing list + gcrypt-devel@gnupg.org by sending mail with a subject of + "subscribe" to gcrypt-devel-request@gnupg.org. An archive of this + list is available at https://lists.gnupg.org . + + + Configure options + ----------------- + Here is a list of configure options which are sometimes useful + for installation. + + --enable-large-data-tests + With this option a "make check" will take really + long due to extra checks for the hash algorithms. + + --enable-m-guard + Enable the integrated malloc checking code. Please + note that this feature does not work on all CPUs + (e.g. SunOS 5.7 on UltraSparc-2) and might give + you a bus error. + + --disable-asm + Do not use assembler modules. It is not possible + to use this on some CPU types. + + --enable-ld-version-script + Libgcrypt tries to build a library where internal + symbols are not exported. This requires support + from ld and is currently enabled for a few OSes. + If you know that your ld supports the so called + ELF version scripts, you can use this option to + force its use. OTOH, if you get error message + from the linker, you probably want to use this + option to disable the use of version scripts. + Note, that you should never ever use an + undocumented symbol or one which is prefixed with + an underscore. + + --enable-ciphers=list + --enable-pubkey-ciphers=list + --enable-digests=list + If not otherwise specified, all algorithms + included in the libgcrypt source tree are built. + An exception are algorithms, which depend on + features not provided by the system, like 64bit + data types. With these switches it is possible + to select exactly those algorithm modules, which + should be built. The algorithms are to be + separated by spaces, commas or colons. To view + the list used with the current build the program + tests/version may be used. + + --disable-endian-check + Don't let configure test for the endianness but + try to use the OS provided macros at compile + time. This is helpful to create OS X fat binaries. + + --enable-random-daemon + Include support for a global random daemon and + build the daemon. This is an experimental feature. + + --enable-mpi-path=EXTRA_PATH + Prepend EXTRA_PATH to list of CPU specific + optimizations. For example, if you want to add + optimizations forn a Intel Pentium 4 compatible + CPU, you may use + --enable-mpi-path=pentium4/sse2:pentium4/mmx + Take care: The generated library may crash on + non-compatible CPUs. + + --enable-random=NAME + Force the use of the random gathering module + NAME. Default is either to use /dev/random or + the auto mode. Possible values for NAME are: + egd - Use the module which accesses the + Entropy Gathering Daemon. See the webpages + for more information about it. + unix - Use the standard Unix module which does not + have a very good performance. + linux - Use the module which accesses /dev/random. + This is the first choice and the default one + for GNU/Linux or *BSD. + auto - Compile linux, egd and unix in and + automagically select at runtime. + + --enable-hmac-binary-check + Include support to check the binary at runtime + against a HMAC checksum. This works only in FIPS + mode and on systems providing the dladdr function. + + --disable-padlock-support + Disable support for the PadLock engine of VIA + processors. The default is to use PadLock if + available. Try this if you get problems with + assembler code. + + --disable-aesni-support + Disable support for the AES-NI instructions of + newer Intel CPUs. The default is to use AES-NI + if available. Try this if you get problems with + assembler code. + + --disable-O-flag-munging + Some code is too complex for some compilers while + in higher optimization modes, thus the compiler + invocation is modified to use a lower + optimization level. Usually this works very well + but on some platforms these rules break the + invocation. This option may be used to disable + the feature under the assumption that either good + CFLAGS are given or the compiler can grok the code. + + + + + Build Problems + -------------- + + If you have a problem with a a certain release, please first check + the Release-info URL given in the NEWS file. + + We can't check all assembler files, so if you have problems + assembling them (or the program crashes) use --disable-asm with + ./configure. If you opt to delete individual replacement files in + hopes of using the remaining ones, be aware that the configure + scripts may consider several subdirectories to get all available + assembler files; be sure to delete the correct ones. Never delete + udiv-qrnnd.S in any CPU directory, because there may be no C + substitute (in mpi/genereic). Don't forget to delete + "config.cache" and run "./config.status --recheck". We got a few + reports about problems using versions of gcc earlier than 2.96 + along with a non-GNU assembler (as). If this applies to your + platform, you can either upgrade gcc to a more recent version, or + use the GNU assembler. + + Some make tools are broken - the best solution is to use GNU's + make. Try gmake or grab the sources from a GNU archive and + install them. + + Specific problems on some machines: + + * IBM RS/6000 running AIX + + Due to a change in gcc (since version 2.8) the MPI stuff may + not build. In this case try to run configure using: + CFLAGS="-g -O2 -mcpu=powerpc" ./configure + + * SVR4.2 (ESIX V4.2 cc) + + Due to problems with the ESIX as(1), you probably want to do: + CFLAGS="-O -K pentium" ./configure --disable-asm + + * SunOS 4.1.4 + + ./configure ac_cv_sys_symbol_underscore=yes + + * Sparc64 CPUs + + We have reports about failures in the AES module when + compiling using gcc (e.g. version 4.1.2) and the option -O3; + using -O2 solves the problem. + + + License + ------- + + The library is distributed under the terms of the GNU Lesser + General Public License (LGPL); see the file COPYING.LIB for the + actual terms. + + The helper programs as well as the documentation are distributed + under the terms of the GNU General Public License (GPL); see the + file COPYING for the actual terms. + + The file LICENSES has notices about contributions that require + that these additional notices are distributed. + + + Contact + ------- + + See the file AUTHORS. + + Commercial grade support for Libgcrypt is available; for a listing + of offers see https://www.gnupg.org/service.html . + + Since 2001 maintenance and development of Libgcrypt is done by g10 + Code GmbH and mostly financed by donations. g10 Code currently + employs 3 full-time developers and two contractors. They all work + on GnuPG and closely related software like Libgcrypt. Please + visit https://gnupg.org/donate/ to see how you can help. + + This file is Free Software; as a special exception the authors gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. For conditions + of the whole package, please see the file COPYING. This file is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY, to the extent permitted by law; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/comm/third_party/libgcrypt/README.GIT b/comm/third_party/libgcrypt/README.GIT new file mode 100644 index 0000000000..ee2c6383f4 --- /dev/null +++ b/comm/third_party/libgcrypt/README.GIT @@ -0,0 +1,49 @@ +If you are building from GIT, run the script + +./autogen.sh + +first, to make sure that you have all the necessary maintainer tools +are installed and to build the actual configuration files. If you +have just checked out from GIT, you should add the option "--force" to +autogen.sh so that meta data is noticed by autom4te.cache. Then run + +./configure --enable-maintainer-mode + +followed by the usual make. + +If autogen.sh complains about insufficient versions of the required +tools, or the tools are not installed, you may use environment +variables to override the default tool names: + + AUTOMAKE_SUFFIX is used as a suffix for all tools from the automake + package. For example + AUTOMAKE_SUFFIX="-1.7" ./autogen.sh + uses "automake-1.7" and "aclocal-1.7. + AUTOMAKE_PREFIX is used as a prefix for all tools from the automake + page and may be combined with AUTOMAKE_SUFFIX. e.g.: + AUTOMAKE_PREFIX=/usr/foo/bin ./autogen.sh + uses "automake" and "aclocal" in the /usr/foo/bin + directory. + AUTOCONF_SUFFIX is used as a suffix for all tools from the automake + package + AUTOCONF_PREFIX is used as a prefix for all tools from the automake + package + GETTEXT_SUFFIX is used as a suffix for all tools from the gettext + package + GETTEXT_PREFIX is used as a prefix for all tools from the gettext + package + +It is also possible to use the variable name AUTOMAKE, AUTOCONF, +ACLOCAL, AUTOHEADER, GETTEXT and MSGMERGE to directly specify the name +of the programs to run. It is however better to use the suffix and +prefix forms as described above because that does not require +knowledge about the actual tools used by autogen.sh. + + +Please don't use autopoint, libtoolize or autoreconf unless you are +the current maintainer and want to update the standard configuration +files. All those files should be in GIT and only updated manually +if the maintainer decides that newer versions are required. The +maintainer should also make sure that the required version of automake +et al. are properly indicated at the top of configure.ac and take care +to copy the files and not merely use symlinks. diff --git a/comm/third_party/libgcrypt/THANKS b/comm/third_party/libgcrypt/THANKS new file mode 100644 index 0000000000..6a44eade05 --- /dev/null +++ b/comm/third_party/libgcrypt/THANKS @@ -0,0 +1,168 @@ +Libgcrypt is based on the GnuPG code. Here is a list of people, who +helped in GnuPG and Libgcrypt development. Please help us to keep it +complete and free of errors. + +Albert Chin china at thewrittenword com +Allan Clark allanc@sco.com +Anand Kumria wildfire@progsoc.uts.edu.au +Andreas Metzler ametzler at downhill.at.eu.org +Ariel T Glenn ariel@columbia.edu +Aurelien Jarno aurel32 at debian.org +Ben Hutchings ben decadent org uk +Bodo Moeller Bodo_Moeller@public.uni-hamburg.de +Brenno de Winter brenno@dewinter.com +Brian Moore bem@cmc.net +Brian Warner warner@lothar.com +Brieuc Jeunhomme bbp@via.ecp.fr +Bryan Fullerton bryanf@samurai.com +Caskey L. Dickson caskey@technocage.com +Cees van de Griend cees-list@griend.xs4all.nl +Charles Levert charles@comm.polymtl.ca +Christian Biere christianbiere@gmx.de +Christian Grothoff christian at grothoff org +Christian von Roques roques@pond.sub.org +Christopher Oliver oliver@fritz.traverse.net +Christian Recktenwald chris@citecs.de +Daiki Ueno ueno at unixuser org +Dan Fandrich dan at coneharvesters com +Daniel Eisenbud eisenbud@cs.swarthmore.edu +Daniel Koening dan@mail.isis.de +David Ellement ellement@sdd.hp.com +Detlef Lannert lannert@lannert.rz.uni-duesseldorf.de +Dirk Lattermann dlatt@t-online.de +Dirk Stoecker gcrypt@dstoecker.de +Ed Boraas ecxjo@esperanto.org +Elie De Brauwer elie@de-brauwer.be +Enzo Michelangeli em@MailAndNews.com +Ernst Molitor ernst.molitor@uni-bonn.de +Fabian Keil fk at fabiankeil de +Fabio Coatti cova@felix.unife.it +Felix von Leitner leitner@amdiv.de +Frank Heckenbach heckenb@mi.uni-erlangen.de +Frank Stajano frank.stajano@cl.cam.ac.uk +Gabriele Monti psicus78 gmail com +Gaël Quéri gqueri@mail.dotcom.fr +Gregor Riepl seto-kun@freesurf.ch +Gerlinde Klaes gk@u64.de +Greg Louis glouis@dynamicro.on.ca +Greg Troxel gdt@ir.bbn.com +Gregory Steuck steuck@iname.com +Geoff Keating geoffk@ozemail.com.au +Harald Denker harry@hal.westfalen.de +Hendrik Buschkamp buschkamp@rheumanet.org +Holger Schurig holger@d.om.org +Hugh Daniel hugh@toad.com +Ian McKellar imckellar@harvestroad.com.au +Ian Peters itp@ximian.com +Janusz A. Urbanowicz alex@bofh.torun.pl +James Troup james@nocrew.org +Jean-loup Gailly gzip@prep.ai.mit.edu +Jeff Johnson jbj@redhat.com +Jens Bachem bachem@rrz.uni-koeln.de +J Horacio MG homega@ciberia.es +Joachim Backes backes@rhrk.uni-kl.de +Jordi Mallach jordi@sindominio.net +John A. Martin jam@jamux.com +Johnny Teveßen j.tevessen@gmx.de +Jörg Schilling schilling@fokus.gmd.de +Jun Kuriyama kuriyama@sky.rim.or.jp +Karl Fogel kfogel@guanabana.onshore.com +Karsten Thygesen karthy@kom.auc.dk +Katsuhiro Kondou kondou@nec.co.jp +Kazu Yamamoto kazu@iijlab.net +Lars Kellogg-Stedman lars@bu.edu +Lee Fisher blibbet at gmail dot com +Marco d'Itri md@linux.it +Mark Adler madler@alumni.caltech.edu +Mark Elbrecht snowball3@bigfoot.com +Markus Friedl Markus.Friedl@informatik.uni-erlangen.de +Matthias Urlichs smurf@smurf.noris.de +Martin Kahlert martin.kahlert@provi.de +Martin Hamilton +Martin Schulte schulte@thp.uni-koeln.de +Matthew Skala mskala@ansuz.sooke.bc.ca +Max Kellermann max@duempel.org +Max Valianskiy maxcom@maxcom.ml.org +Michael Fischer v. Mollard mfvm@gmx.de +Michael Roth mroth@nessie.de +Michael Sobolev mss@despair.transas.com +Michele Baldessari michele@pupazzo.org +Modestas Vainius geromanas@mailas.com +Neil Dunbar neil.dunbar at pobox.com +Neil Spring nspring@cs.washington.edu +Newton Hammet newton@hammet.net +Nicolas Graner Nicolas.Graner@cri.u-psud.fr +NIIBE Yutaka gniibe@chroot.org +Niklas Hernaeus +Nikolay Sturm sturm@sec.informatik.tu-darmstadt.de +Nikos Mavroyanopoulos nmav@hellug.gr +Nimrod Zimerman zimerman@forfree.at +N J Doye nic@niss.ac.uk +Oliver Haakert haakert@hsp.de +Oskari Jääskeläinen f33003a@cc.hut.fi +Paul D. Smith psmith@baynetworks.com +Philippe Laliberte arsphl@oeil.qc.ca +Peter Gutmann pgut001@cs.auckland.ac.nz +QingLong qinglong@bolizm.ihep.su +Rafael Ãvila de Espíndola rafael.espindola@gmail.com +Rafaël Carré funman@videolan.org +Ralf Fassel ralf@akutech.de +Ralf Hildebrandt Ralf.Hildebrandt@innominate.com +Ralf Schneider ralf@tapfere-schneiderleins.de +Ralph Gillen gillen@theochem.uni-duesseldorf.de +Rami Lehti Rami.Lehti@finland.sun.com +Randolph Chung tausq@debian.org +Randy mcclellr@oit.edu +Rat ratinox@peorth.gweep.net +Reinhard Wobst R.Wobst@ifw-dresden.de +Rémi Guyomarch rguyom@mail.dotcom.fr +Reuben Sumner rasumner@wisdom.weizmann.ac.il +Richard Outerbridge outer@interlog.com +Roddy Strachan roddy@satlink.com.au +Roland Rosenfeld roland@spinnaker.rhein.de +Ross Golder rossigee@bigfoot.com +Serge Munhoven munhoven@mema.ucl.ac.be +Sergi Blanch i Torné sergi at calcurco cat +Simon Josefsson jas@extundo.com +SL Baur steve@xemacs.org +Stephan Austermuehle au@hcsd.de +Stephan Müller smueller at atsec com +Stephane Corthesy stephane@sente.ch +Stefan Karrmann S.Karrmann@gmx.net +Stefan Keller dres@cs.tu-berlin.de +Stefan Krüger stadtkind2 at gmx de +Steffen Ullrich ccrlphr@xensei.com +Steffen Zahn zahn@berlin.snafu.de +Steven Bakker steven@icoe.att.com +Susanne Schultz schultz@hsp.de +Sven Bjorn +Szakats Istvan szaki.ms@gmail.com +Thiago Jung Bauermann jungmann@cwb.matrix.com.br +Thomas Roessler roessler@guug.de +Tom Holroyd tomh@po.crl.go.jp +Tom Spindler dogcow@home.merit.edu +Tom Zerucha tzeruch@ceddec.com +Tomas Fasth tomas.fasth@twinspot.net +Tommi Komulainen Tommi.Komulainen@iki.fi +Thomas Mikkelsen tbm@image.dk +Ulf Möller 3umoelle@informatik.uni-hamburg.de +Umberto Salsi salsi@icosaedro.it +Uoti Urpala +Urko Lusa ulusa@euskalnet.net +Victor Stinner haypo@inl.fr +Walter Koch koch@u32.de +Werner Koch wk@gnupg.org +Wim Vandeputte wim@kd85.com + nbecker@hns.com + + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, + 2009, 2011 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/comm/third_party/libgcrypt/TODO b/comm/third_party/libgcrypt/TODO new file mode 100644 index 0000000000..7aa4de1af6 --- /dev/null +++ b/comm/third_party/libgcrypt/TODO @@ -0,0 +1,59 @@ +# What's left to do -*- org -*- + +* Next API break: +** gcry_ac_io_t + Remove use of anonymous union. +** gcry_ac + Consider to remove it. + +* udiv-qrnbd.o should get build as *.lo [HPUX] + +* Allow operation using RSA keys consisting of the OpenSSL keys. + This requires the introduction of a parameter names (say) U which + is calculated according to OpenSSL/PKCS#1 rules. + +* linker script test + Write an autoconf test to check whether the linker supports a + version script. + +* Add attributes to the MPI functions. + +* cipher/pubkey.c and pubkey implementations. + Don't rely on the secure memory based wiping function but add an + extra wiping. + +* Use builtin bit functions of gcc 3.4 + +* Consider using a daemon to maintain the random pool + [Partly done] The down side of this is that we can't assume that the + random has has always been stored in "secure memory". And we rely + on that sniffing of Unix domain sockets is not possible. We can + implement this simply by detecting a special prefixed random seed + name and divert in this case to the daemon. There are several + benefits with such an approach: We keep the state of the RNG over + invocations of libgcrypt based applications, don't need time + consuming initialization of the pool and in case the entropy + collectros need to run that bunch of Unix utilities we don't waste + their precious results. + +* gcryptrnd.c + Requires a test for pth [done] as well as some other tests. + +* secmem.c + Check whether the memory block is valid before releasing it and + print a diagnosic, like glibc does. + +* threads +** We need to document fork problems + In particular that reinitialization is required in random.c + However, there is no code yet to do it. + +* Tests + We need a lot more tests. Lets keep an ever growing list here. +** Write tests for the progress function +** mpitests does no real checks yet. +** pthreads + To catch simple errors like the one fixed on 2007-03-16. +** C++ tests + We have some code to allow using libgcrypt from C++, so we also + should have a test case. diff --git a/comm/third_party/libgcrypt/VERSION b/comm/third_party/libgcrypt/VERSION new file mode 100644 index 0000000000..8fdcf38694 --- /dev/null +++ b/comm/third_party/libgcrypt/VERSION @@ -0,0 +1 @@ +1.9.2 diff --git a/comm/third_party/libgcrypt/acinclude.m4 b/comm/third_party/libgcrypt/acinclude.m4 new file mode 100644 index 0000000000..3c8dfba711 --- /dev/null +++ b/comm/third_party/libgcrypt/acinclude.m4 @@ -0,0 +1,392 @@ +dnl macros to configure Libgcrypt +dnl Copyright (C) 1998, 1999, 2000, 2001, 2002, +dnl 2003 Free Software Foundation, Inc. +dnl Copyright (C) 2013 g10 Code GmbH +dnl +dnl This file is part of Libgcrypt. +dnl +dnl Libgcrypt is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU Lesser General Public License as +dnl published by the Free Software Foundation; either version 2.1 of +dnl the License, or (at your option) any later version. +dnl +dnl Libgcrypt is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +dnl GCRY_MSG_SHOW(PREFIX,STRING) +dnl Print a message with a prefix. +dnl +define([GCRY_MSG_SHOW], + [ + echo " $1 $2" 1>&AS_MESSAGE_FD([]) + ]) + +dnl GCRY_MSG_WRAP(PREFIX, ALGOLIST) +dnl Print a nicely formatted list of algorithms +dnl with an appropriate line wrap. +dnl +define([GCRY_MSG_WRAP], + [ + tmp=" $1" + tmpi="abc" + if test "${#tmpi}" -ne 3 >/dev/null 2>&1 ; then + dnl Without a POSIX shell, we don't botter to wrap it + echo "$tmp $2" 1>&AS_MESSAGE_FD([]) + else + tmpi=`echo "$tmp"| sed 's/./ /g'` + echo $2 EOF | tr ' ' '\n' | \ + while read word; do + if test "${#tmp}" -gt 70 ; then + echo "$tmp" 1>&AS_MESSAGE_FD([]) + tmp="$tmpi" + fi + if test "$word" = "EOF" ; then + echo "$tmp" 1>&AS_MESSAGE_FD([]) + else + tmp="$tmp $word" + fi + done + fi + ]) + + +dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME) +dnl Check whether a typedef exists and create a #define $2 if it exists +dnl +AC_DEFUN([GNUPG_CHECK_TYPEDEF], + [ AC_MSG_CHECKING(for $1 typedef) + AC_CACHE_VAL(gnupg_cv_typedef_$1, + [AC_TRY_COMPILE([#define _GNU_SOURCE 1 + #include + #include ], [ + #undef $1 + int a = sizeof($1); + ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )]) + AC_MSG_RESULT($gnupg_cv_typedef_$1) + if test "$gnupg_cv_typedef_$1" = yes; then + AC_DEFINE($2,1,[Defined if a `]$1[' is typedef'd]) + fi + ]) + + +dnl GNUPG_CHECK_GNUMAKE +dnl +AC_DEFUN([GNUPG_CHECK_GNUMAKE], + [ + if ${MAKE-make} --version 2>/dev/null | grep '^GNU ' >/dev/null 2>&1; then + : + else + AC_MSG_WARN([[ +*** +*** It seems that you are not using GNU make. Some make tools have serious +*** flaws and you may not be able to build this software at all. Before you +*** complain, please try GNU make: GNU make is easy to build and available +*** at all GNU archives. It is always available from ftp.gnu.org:/gnu/make. +***]]) + fi + ]) + + +# +# GNUPG_SYS_SYMBOL_UNDERSCORE +# Does the compiler prefix global symbols with an underscore? +# +# Taken from GnuPG 1.2 and modified to use the libtool macros. +AC_DEFUN([GNUPG_SYS_SYMBOL_UNDERSCORE], +[tmp_do_check="no" +case "${host}" in + i?86-mingw32* | i?86-*-mingw32*) + ac_cv_sys_symbol_underscore=yes + ;; + x86_64-*-mingw32*) + ac_cv_sys_symbol_underscore=no + ;; + i386-emx-os2 | i[3456]86-pc-os2*emx | i386-pc-msdosdjgpp) + ac_cv_sys_symbol_underscore=yes + ;; + *) + if test "$cross_compiling" != yes; then + tmp_do_check="yes" + fi + ;; +esac +if test "$tmp_do_check" = "yes"; then + AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) + AC_MSG_CHECKING([for _ prefix in compiled symbols]) + AC_CACHE_VAL(ac_cv_sys_symbol_underscore, + [ac_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if egrep '^_nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if egrep '^nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.c >&AS_MESSAGE_LOG_FD + fi + rm -rf conftest* + ]) + else + AC_MSG_CHECKING([for _ prefix in compiled symbols]) + fi +AC_MSG_RESULT($ac_cv_sys_symbol_underscore) +if test x$ac_cv_sys_symbol_underscore = xyes; then + AC_DEFINE(WITH_SYMBOL_UNDERSCORE,1, + [Defined if compiled symbols have a leading underscore]) +fi +]) + + +###################################################################### +# Check whether mlock is broken (hpux 10.20 raises a SIGBUS if mlock +# is not called from uid 0 (not tested whether uid 0 works) +# For DECs Tru64 we have also to check whether mlock is in librt +# mlock is there a macro using memlk() +###################################################################### +dnl GNUPG_CHECK_MLOCK +dnl +define(GNUPG_CHECK_MLOCK, + [ AC_CHECK_FUNCS(mlock) + if test "$ac_cv_func_mlock" = "no"; then + AC_CHECK_HEADERS(sys/mman.h) + if test "$ac_cv_header_sys_mman_h" = "yes"; then + # Add librt to LIBS: + AC_CHECK_LIB(rt, memlk) + AC_CACHE_CHECK([whether mlock is in sys/mman.h], + gnupg_cv_mlock_is_in_sys_mman, + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ + #include + #ifdef HAVE_SYS_MMAN_H + #include + #endif + ]], [[ +int i; + +/* glibc defines this for functions which it implements + * to always fail with ENOSYS. Some functions are actually + * named something starting with __ and the normal name + * is an alias. */ +#if defined (__stub_mlock) || defined (__stub___mlock) +choke me +#else +mlock(&i, 4); +#endif +; return 0; + ]])], + gnupg_cv_mlock_is_in_sys_mman=yes, + gnupg_cv_mlock_is_in_sys_mman=no)]) + if test "$gnupg_cv_mlock_is_in_sys_mman" = "yes"; then + AC_DEFINE(HAVE_MLOCK,1, + [Defined if the system supports an mlock() call]) + fi + fi + fi + if test "$ac_cv_func_mlock" = "yes"; then + AC_CHECK_FUNCS(sysconf getpagesize) + AC_MSG_CHECKING(whether mlock is broken) + AC_CACHE_VAL(gnupg_cv_have_broken_mlock, + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +#include +#include +#include + +int main() +{ + char *pool; + int err; + long int pgsize; + +#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) + pgsize = sysconf (_SC_PAGESIZE); +#elif defined (HAVE_GETPAGESIZE) + pgsize = getpagesize(); +#else + pgsize = -1; +#endif + + if (pgsize == -1) + pgsize = 4096; + + pool = malloc( 4096 + pgsize ); + if( !pool ) + return 2; + pool += (pgsize - ((long int)pool % pgsize)); + + err = mlock( pool, 4096 ); + if( !err || errno == EPERM || errno == EAGAIN) + return 0; /* okay */ + + return 1; /* hmmm */ +} + ]])], + gnupg_cv_have_broken_mlock="no", + gnupg_cv_have_broken_mlock="yes", + gnupg_cv_have_broken_mlock="assume-no" + ) + ) + if test "$gnupg_cv_have_broken_mlock" = "yes"; then + AC_DEFINE(HAVE_BROKEN_MLOCK,1, + [Defined if the mlock() call does not work]) + AC_MSG_RESULT(yes) + else + if test "$gnupg_cv_have_broken_mlock" = "no"; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(assuming no) + fi + fi + fi + ]) + +# GNUPG_SYS_LIBTOOL_CYGWIN32 - find tools needed on cygwin32 +AC_DEFUN([GNUPG_SYS_LIBTOOL_CYGWIN32], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +AC_CHECK_TOOL(AS, as, false) +]) + +dnl LIST_MEMBER() +dnl Check whether an element ist contained in a list. Set `found' to +dnl `1' if the element is found in the list, to `0' otherwise. +AC_DEFUN([LIST_MEMBER], +[ +name=$1 +list=$2 +found=0 + +for n in $list; do + if test "x$name" = "x$n"; then + found=1 + fi +done +]) + + +dnl Check for socklen_t: historically on BSD it is an int, and in +dnl POSIX 1g it is a type of its own, but some platforms use different +dnl types for the argument to getsockopt, getpeername, etc. So we +dnl have to test to find something that will work. +AC_DEFUN([TYPE_SOCKLEN_T], +[ + AC_CHECK_TYPE([socklen_t], ,[ + AC_MSG_CHECKING([for socklen_t equivalent]) + AC_CACHE_VAL([socklen_t_equiv], + [ + # Systems have either "struct sockaddr *" or + # "void *" as the second argument to getpeername + socklen_t_equiv= + for arg2 in "struct sockaddr" void; do + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ +#include +#include + +int getpeername (int, $arg2 *, $t *); + ],[ + $t len; + getpeername(0,0,&len); + ],[ + socklen_t_equiv="$t" + break + ]) + done + done + + if test "x$socklen_t_equiv" = x; then + AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) + fi + ]) + AC_MSG_RESULT($socklen_t_equiv) + AC_DEFINE_UNQUOTED(socklen_t, $socklen_t_equiv, + [type to use in place of socklen_t if not defined])], + [#include +#include ]) +]) + + +# GNUPG_PTH_VERSION_CHECK(REQUIRED) +# +# If the version is sufficient, HAVE_PTH will be set to yes. +# +# Taken form the m4 macros which come with Pth +AC_DEFUN([GNUPG_PTH_VERSION_CHECK], + [ + _pth_version=`$PTH_CONFIG --version | awk 'NR==1 {print [$]3}'` + _req_version="ifelse([$1],,1.2.0,$1)" + + AC_MSG_CHECKING(for PTH - version >= $_req_version) + for _var in _pth_version _req_version; do + eval "_val=\"\$${_var}\"" + _major=`echo $_val | sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\([[ab.]]\)\([[0-9]]*\)/\1/'` + _minor=`echo $_val | sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\([[ab.]]\)\([[0-9]]*\)/\2/'` + _rtype=`echo $_val | sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\([[ab.]]\)\([[0-9]]*\)/\3/'` + _micro=`echo $_val | sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\([[ab.]]\)\([[0-9]]*\)/\4/'` + case $_rtype in + "a" ) _rtype=0 ;; + "b" ) _rtype=1 ;; + "." ) _rtype=2 ;; + esac + _hex=`echo dummy | awk '{ printf("%d%02d%1d%02d", major, minor, rtype, micro); }' \ + "major=$_major" "minor=$_minor" "rtype=$_rtype" "micro=$_micro"` + eval "${_var}_hex=\"\$_hex\"" + done + have_pth=no + if test ".$_pth_version_hex" != .; then + if test ".$_req_version_hex" != .; then + if test $_pth_version_hex -ge $_req_version_hex; then + have_pth=yes + fi + fi + fi + if test $have_pth = yes; then + AC_MSG_RESULT(yes) + AC_MSG_CHECKING([whether PTH installation is sane]) + AC_CACHE_VAL(gnupg_cv_pth_is_sane,[ + _gnupg_pth_save_cflags=$CFLAGS + _gnupg_pth_save_ldflags=$LDFLAGS + _gnupg_pth_save_libs=$LIBS + CFLAGS="$CFLAGS `$PTH_CONFIG --cflags`" + LDFLAGS="$LDFLAGS `$PTH_CONFIG --ldflags`" + LIBS="$LIBS `$PTH_CONFIG --libs`" + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include + ], + [[ pth_init ();]])], + gnupg_cv_pth_is_sane=yes, + gnupg_cv_pth_is_sane=no) + CFLAGS=$_gnupg_pth_save_cflags + LDFLAGS=$_gnupg_pth_save_ldflags + LIBS=$_gnupg_pth_save_libs + ]) + if test $gnupg_cv_pth_is_sane != yes; then + have_pth=no + fi + AC_MSG_RESULT($gnupg_cv_pth_is_sane) + else + AC_MSG_RESULT(no) + fi + ]) diff --git a/comm/third_party/libgcrypt/aclocal.m4 b/comm/third_party/libgcrypt/aclocal.m4 new file mode 100644 index 0000000000..55a2f8dbee --- /dev/null +++ b/comm/third_party/libgcrypt/aclocal.m4 @@ -0,0 +1,1201 @@ +# generated automatically by aclocal 1.16.1 -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.16' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.16.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.16.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Figure out how to run the assembler. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_AS +# ---------- +AC_DEFUN([AM_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS +AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) +AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll need in +# order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. +AC_DEFUN([AM_MAKE_INCLUDE], +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/ax_cc_for_build.m4]) +m4_include([m4/gpg-error.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) +m4_include([m4/noexecstack.m4]) +m4_include([m4/socklen.m4]) +m4_include([acinclude.m4]) diff --git a/comm/third_party/libgcrypt/autogen.rc b/comm/third_party/libgcrypt/autogen.rc new file mode 100644 index 0000000000..646f659cc0 --- /dev/null +++ b/comm/third_party/libgcrypt/autogen.rc @@ -0,0 +1,13 @@ +# autogen.sh configuration for Libgcrypt -*- sh -*- + +case "$myhost" in + w32) + configure_opts="" + ;; + + amd64) + configure_opts="" + ;; +esac + +final_info="./configure --enable-maintainer-mode && make" diff --git a/comm/third_party/libgcrypt/autogen.sh b/comm/third_party/libgcrypt/autogen.sh new file mode 100755 index 0000000000..9b36158121 --- /dev/null +++ b/comm/third_party/libgcrypt/autogen.sh @@ -0,0 +1,513 @@ +#! /bin/sh +# autogen.sh +# Copyright (C) 2003, 2014, 2017, 2018 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# This is a generic script to create the configure script and handle cross +# build environments. It requires the presence of a autogen.rc file to +# configure it for the respective package. It is maintained as part of +# GnuPG and source copied by other packages. +# +# Version: 2018-07-10 + +configure_ac="configure.ac" + +cvtver () { + awk 'NR==1 {split($NF,A,".");X=1000000*A[1]+1000*A[2]+A[3];print X;exit 0}' +} + +check_version () { + if [ $(( `("$1" --version || echo "0") | cvtver` >= $2 )) = 1 ]; then + return 0 + fi + echo "**Error**: "\`$1\'" not installed or too old." >&2 + echo ' Version '$3' or newer is required.' >&2 + [ -n "$4" ] && echo ' Note that this is part of '\`$4\''.' >&2 + DIE="yes" + return 1 +} + +fatal () { + echo "autogen.sh:" "$*" >&2 + DIE=yes +} + +info () { + if [ -z "${SILENT}" ]; then + echo "autogen.sh:" "$*" >&2 + fi +} + +die_p () { + if [ "$DIE" = "yes" ]; then + echo "autogen.sh: Stop." >&2 + exit 1 + fi +} + +replace_sysroot () { + configure_opts=$(echo $configure_opts | sed "s#@SYSROOT@#${w32root}#g") + extraoptions=$(echo $extraoptions | sed "s#@SYSROOT@#${w32root}#g") +} + +# Allow to override the default tool names +AUTOCONF=${AUTOCONF_PREFIX}${AUTOCONF:-autoconf}${AUTOCONF_SUFFIX} +AUTOHEADER=${AUTOCONF_PREFIX}${AUTOHEADER:-autoheader}${AUTOCONF_SUFFIX} + +AUTOMAKE=${AUTOMAKE_PREFIX}${AUTOMAKE:-automake}${AUTOMAKE_SUFFIX} +ACLOCAL=${AUTOMAKE_PREFIX}${ACLOCAL:-aclocal}${AUTOMAKE_SUFFIX} + +GETTEXT=${GETTEXT_PREFIX}${GETTEXT:-gettext}${GETTEXT_SUFFIX} +MSGMERGE=${GETTEXT_PREFIX}${MSGMERGE:-msgmerge}${GETTEXT_SUFFIX} + +DIE=no +FORCE= +SILENT= +PRINT_HOST=no +PRINT_BUILD=no +tmp=$(dirname "$0") +tsdir=$(cd "${tmp}"; pwd) + +if [ -n "${AUTOGEN_SH_SILENT}" ]; then + SILENT=" --silent" +fi +if test x"$1" = x"--help"; then + echo "usage: ./autogen.sh [OPTIONS] [ARGS]" + echo " Options:" + echo " --silent Silent operation" + echo " --force Pass --force to autoconf" + echo " --find-version Helper for configure.ac" + echo " --git-build Run all commands to build from a Git" + echo " --print-host Print only the host triplet" + echo " --print-build Print only the build platform triplet" + echo " --build-TYPE Configure to cross build for TYPE" + echo "" + echo " ARGS are passed to configure in --build-TYPE mode." + echo " Configuration for this script is expected in autogen.rc" + exit 0 +fi +if test x"$1" = x"--silent"; then + SILENT=" --silent" + shift +fi +if test x"$1" = x"--force"; then + FORCE=" --force" + shift +fi +if test x"$1" = x"--print-host"; then + PRINT_HOST=yes + shift +fi +if test x"$1" = x"--print-build"; then + PRINT_BUILD=yes + shift +fi + + +# Reject unsafe characters in $HOME, $tsdir and cwd. We consider spaces +# as unsafe because it is too easy to get scripts wrong in this regard. +am_lf=' +' +case `pwd` in + *[\;\\\"\#\$\&\'\`$am_lf\ \ ]*) + fatal "unsafe working directory name" ;; +esac +case $tsdir in + *[\;\\\"\#\$\&\'\`$am_lf\ \ ]*) + fatal "unsafe source directory: \`$tsdir'" ;; +esac +case $HOME in + *[\;\\\"\#\$\&\'\`$am_lf\ \ ]*) + fatal "unsafe home directory: \`$HOME'" ;; +esac +die_p + + +# List of variables sourced from autogen.rc. The strings '@SYSROOT@' in +# these variables are replaced by the actual system root. +configure_opts= +extraoptions= +# List of optional variables sourced from autogen.rc and ~/.gnupg-autogen.rc +w32_toolprefixes= +w32_extraoptions= +w32ce_toolprefixes= +w32ce_extraoptions= +w64_toolprefixes= +w64_extraoptions= +amd64_toolprefixes= +# End list of optional variables sourced from ~/.gnupg-autogen.rc +# What follows are variables which are sourced but default to +# environment variables or lacking them hardcoded values. +#w32root= +#w32ce_root= +#w64root= +#amd64root= + +# Convenience option to use certain configure options for some hosts. +myhost="" +myhostsub="" +case "$1" in + --find-version) + myhost="find-version" + SILENT=" --silent" + shift + ;; + --git-build) + myhost="git-build" + shift + ;; + --build-w32) + myhost="w32" + shift + ;; + --build-w32ce) + myhost="w32" + myhostsub="ce" + shift + ;; + --build-w64) + myhost="w32" + myhostsub="64" + shift + ;; + --build-amd64) + myhost="amd64" + shift + ;; + --build*) + fatal "**Error**: invalid build option $1" + shift + ;; + *) + ;; +esac +die_p + + +# **** GIT BUILD **** +# This is a helper to build from git. +if [ "$myhost" = "git-build" ]; then + tmp="$(pwd)" + cd "$tsdir" || fatal "error cd-ing to $tsdir" + ./autogen.sh || fatal "error running ./autogen.sh" + cd "$tmp" || fatal "error cd-ing back to $tmp" + die_p + "$tsdir"/configure || fatal "error running $tsdir/configure" + die_p + make || fatal "error running make" + die_p + make check || fatal "error running male check" + die_p + exit 0 +fi +# **** end GIT BUILD **** + + +# Source our configuration +if [ -f "${tsdir}/autogen.rc" ]; then + . "${tsdir}/autogen.rc" +fi + +# Source optional site specific configuration +if [ -f "$HOME/.gnupg-autogen.rc" ]; then + info "sourcing extra definitions from $HOME/.gnupg-autogen.rc" + . "$HOME/.gnupg-autogen.rc" +fi + + +# **** FIND VERSION **** +# This is a helper for the configure.ac M4 magic +# Called +# ./autogen.sh --find-version PACKAGE MAJOR MINOR [MICRO] +# returns a complete version string with automatic beta numbering. +if [ "$myhost" = "find-version" ]; then + package="$1" + major="$2" + minor="$3" + micro="$4" + + if [ -z "$package" -o -z "$major" -o -z "$minor" ]; then + echo "usage: ./autogen.sh --find-version PACKAGE MAJOR MINOR [MICRO]" >&2 + exit 1 + fi + + if [ -z "$micro" ]; then + matchstr1="$package-$major.[0-9]*" + matchstr2="$package-$major-base" + vers="$major.$minor" + else + matchstr1="$package-$major.$minor.[0-9]*" + matchstr2="$package-$major.$minor-base" + vers="$major.$minor.$micro" + fi + + beta=no + if [ -e .git ]; then + ingit=yes + tmp=$(git describe --match "${matchstr1}" --long 2>/dev/null) + tmp=$(echo "$tmp" | sed s/^"$package"//) + if [ -n "$tmp" ]; then + tmp=$(echo "$tmp" | sed s/^"$package"// \ + | awk -F- '$3!=0 && $3 !~ /^beta/ {print"-beta"$3}') + else + tmp=$(git describe --match "${matchstr2}" --long 2>/dev/null \ + | awk -F- '$4!=0{print"-beta"$4}') + fi + [ -n "$tmp" ] && beta=yes + rev=$(git rev-parse --short HEAD | tr -d '\n\r') + rvd=$((0x$(echo ${rev} | dd bs=1 count=4 2>/dev/null))) + else + ingit=no + beta=yes + tmp="-unknown" + rev="0000000" + rvd="0" + fi + + echo "$package-$vers$tmp:$beta:$ingit:$vers$tmp:$vers:$tmp:$rev:$rvd:" + exit 0 +fi +# **** end FIND VERSION **** + + +if [ ! -f "$tsdir/build-aux/config.guess" ]; then + fatal "$tsdir/build-aux/config.guess not found" + exit 1 +fi +build=`$tsdir/build-aux/config.guess` +if [ $PRINT_BUILD = yes ]; then + echo "$build" + exit 0 +fi + + + +# ****************** +# W32 build script +# ****************** +if [ "$myhost" = "w32" ]; then + case $myhostsub in + ce) + w32root="$w32ce_root" + [ -z "$w32root" ] && w32root="$HOME/w32ce_root" + toolprefixes="$w32ce_toolprefixes arm-mingw32ce" + extraoptions="$extraoptions $w32ce_extraoptions" + ;; + 64) + w32root="$w64root" + [ -z "$w32root" ] && w32root="$HOME/w64root" + toolprefixes="$w64_toolprefixes x86_64-w64-mingw32" + extraoptions="$extraoptions $w64_extraoptions" + ;; + *) + [ -z "$w32root" ] && w32root="$HOME/w32root" + toolprefixes="$w32_toolprefixes i686-w64-mingw32 i586-mingw32msvc" + toolprefixes="$toolprefixes i386-mingw32msvc mingw32" + extraoptions="$extraoptions $w32_extraoptions" + ;; + esac + info "Using $w32root as standard install directory" + replace_sysroot + + # Locate the cross compiler + crossbindir= + for host in $toolprefixes; do + if ${host}-gcc --version >/dev/null 2>&1 ; then + crossbindir=/usr/${host}/bin + conf_CC="CC=${host}-gcc" + break; + fi + done + if [ -z "$crossbindir" ]; then + fatal "cross compiler kit not installed" + if [ -z "$myhostsub" ]; then + info "Under Debian GNU/Linux, you may install it using" + info " apt-get install mingw32 mingw32-runtime mingw32-binutils" + fi + die_p + fi + if [ $PRINT_HOST = yes ]; then + echo "$host" + exit 0 + fi + + if [ -f "$tsdir/config.log" ]; then + if ! head $tsdir/config.log | grep "$host" >/dev/null; then + fatal "Please run a 'make distclean' first" + die_p + fi + fi + + $tsdir/configure --enable-maintainer-mode ${SILENT} \ + --prefix=${w32root} \ + --host=${host} --build=${build} SYSROOT=${w32root} \ + PKG_CONFIG_LIBDIR=${w32root}/lib/pkgconfig \ + ${configure_opts} ${extraoptions} "$@" + rc=$? + exit $rc +fi +# ***** end W32 build script ******* + +# ***** AMD64 cross build script ******* +# Used to cross-compile for AMD64 (for testing) +if [ "$myhost" = "amd64" ]; then + [ -z "$amd64root" ] && amd64root="$HOME/amd64root" + info "Using $amd64root as standard install directory" + replace_sysroot + + toolprefixes="$amd64_toolprefixes x86_64-linux-gnu amd64-linux-gnu" + + # Locate the cross compiler + crossbindir= + for host in $toolprefixes ; do + if ${host}-gcc --version >/dev/null 2>&1 ; then + crossbindir=/usr/${host}/bin + conf_CC="CC=${host}-gcc" + break; + fi + done + if [ -z "$crossbindir" ]; then + echo "Cross compiler kit not installed" >&2 + echo "Stop." >&2 + exit 1 + fi + if [ $PRINT_HOST = yes ]; then + echo "$host" + exit 0 + fi + + if [ -f "$tsdir/config.log" ]; then + if ! head $tsdir/config.log | grep "$host" >/dev/null; then + echo "Please run a 'make distclean' first" >&2 + exit 1 + fi + fi + + $tsdir/configure --enable-maintainer-mode ${SILENT} \ + --prefix=${amd64root} \ + --host=${host} --build=${build} \ + ${configure_opts} ${extraoptions} "$@" + rc=$? + exit $rc +fi +# ***** end AMD64 cross build script ******* + + +# Grep the required versions from configure.ac +autoconf_vers=`sed -n '/^AC_PREREQ(/ { +s/^.*(\(.*\))/\1/p +q +}' ${configure_ac}` +autoconf_vers_num=`echo "$autoconf_vers" | cvtver` + +automake_vers=`sed -n '/^min_automake_version=/ { +s/^.*="\(.*\)"/\1/p +q +}' ${configure_ac}` +automake_vers_num=`echo "$automake_vers" | cvtver` + +if [ -d "${tsdir}/po" ]; then + gettext_vers=`sed -n '/^AM_GNU_GETTEXT_VERSION(/ { +s/^.*\[\(.*\)])/\1/p +q +}' ${configure_ac}` + gettext_vers_num=`echo "$gettext_vers" | cvtver` +else + gettext_vers="n/a" +fi + +if [ -z "$autoconf_vers" -o -z "$automake_vers" -o -z "$gettext_vers" ] +then + echo "**Error**: version information not found in "\`${configure_ac}\'"." >&2 + exit 1 +fi + + +if check_version $AUTOCONF $autoconf_vers_num $autoconf_vers ; then + check_version $AUTOHEADER $autoconf_vers_num $autoconf_vers autoconf +fi +if check_version $AUTOMAKE $automake_vers_num $automake_vers; then + check_version $ACLOCAL $automake_vers_num $autoconf_vers automake +fi +if [ "$gettext_vers" != "n/a" ]; then + if check_version $GETTEXT $gettext_vers_num $gettext_vers; then + check_version $MSGMERGE $gettext_vers_num $gettext_vers gettext + fi +fi + +if [ "$DIE" = "yes" ]; then + cat </dev/null 2>/dev/null; then + [ -z "${SILENT}" ] && CP="$CP -v" + fi + if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then + [ -z "${SILENT}" ] && cat < + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2003-12-08 Werner Koch + + * autogen.sh, config.sub, install-sh, mkinstalldirs, config.guess, + * missing: Removed + +2003-10-31 Werner Koch + + * autogen.sh: Allow to override the tool name. Do not run + libtoolize. Update required version numbers. + +2003-07-30 Werner Koch + + * config.guess, config.sub: Updated from ftp.gnu.org/gnu/config/ + +2003-07-07 Moritz Schulte + + * autogen.sh: Undo last change. + * autogen.sh: Remove -a argument for automake. + +2003-03-06 Moritz Schulte + + * autogen.sh (run): New function. + Let automake run with -a for adding missing files automatically + +2002-11-12 Werner Koch + + * config.sub, config.guess: Updated from ftp.gnu.org/gnu/config + to version 2002-11-08. + +2002-05-14 Werner Koch + + * autogen.sh: Require version 2.53 of autoconf + +2001-12-18 Werner Koch + + * distfiles: Remove files which are automatically added by automake. + +2001-08-06 Werner Koch + + * autogen.sh: Added --build-w32 option. + +2001-05-28 Werner Koch + + * db2html.in: Removed. + * db2any: New. Taken from GPH + +Mon Jul 17 16:35:47 CEST 2000 Werner Koch + + * config.gues, config.sub: Support for s390-ibm-linux-gnu; thanks + to Holger Smolinski. Add support for QNX; by Sam Roberts. + +Tue Oct 26 14:10:21 CEST 1999 Werner Koch + + * commit: Remove leading and trailing empty lines when copying + Changes to Changelog + +Wed Sep 15 16:22:17 CEST 1999 Werner Koch + + * gnupg.spec: Add Portuguese description + +Thu Sep 2 16:40:55 CEST 1999 Werner Koch + + * mkdiff: changed format of diff file name and made script more + general. + +Wed Aug 4 10:34:18 CEST 1999 Werner Koch + + * config.guess: Updated from gnu/common and applied my emx patch again. + * config.sub: Updated from gnu/common. + +Wed Jul 14 19:42:08 CEST 1999 Werner Koch + + * ltmain.sh, ltconfig.sh : Updated to libtool 1.3.3 + +Mon Jul 12 14:55:34 CEST 1999 Werner Koch + + * autogen.sh: Run libtoolize + +Sat May 22 22:47:26 CEST 1999 Werner Koch + + * autogen.sh: Fixed the error message for a missing libtool. + +Sat May 8 19:28:08 CEST 1999 Werner Koch + + * mkinstalldirs, install-sh: New from GNU repository + * config.sub, config.guess: Merged with rep version. + +Sun Mar 14 19:34:36 CET 1999 Werner Koch + + * autogen.sh: Add a check for libtool because some autoconf macros + are needed. + +Mon Feb 22 20:04:00 CET 1999 Werner Koch + + * autogen.sh: Enhanced the version testing code (Philippe Laliberte) + + * mkwebpage: Edits the buglist. + +Sat Feb 13 12:04:43 CET 1999 Werner Koch + + * autogen.sh: Now uses gettextize + +Wed Feb 10 17:15:39 CET 1999 Werner Koch + + * config.sub, config.guess: Support i386-emx-os2 + +Sun Jan 17 11:04:33 CET 1999 Werner Koch + + * autogen.sh: Now checks for installed gettext + +Sat Jan 16 09:27:30 CET 1999 Werner Koch + + * config.guess (m68k-atari-mint): New. + * config.sub: Add support for atarist-MiNT + +Wed Jan 13 12:49:36 CET 1999 Werner Koch + + * gnupg.spec.in: New + * gnupg.spec: Removed + +Wed Dec 23 13:18:14 CET 1998 Werner Koch + + * gnupg.spec: Updated version by Fabio Coatti + +Thu Dec 17 18:31:15 CET 1998 Werner Koch + + * gnupg.spec: New version by Reuben Sumner and did some more + changes. + +Fri Nov 27 12:39:29 CET 1998 Werner Koch + + + * commit: New + + +Fri Nov 20 12:01:57 1998 Werner Koch (wk@isil.d.shuttle.de) + + * mkdiff: signs the patch file + +Sat Oct 17 16:10:16 1998 Werner Koch (wk@isil.d.shuttle.de) + + * autogen.sh: New. + +Wed Oct 14 09:55:25 1998 Werner Koch (wk@isil.d.shuttle.de) + + * config.guess (FreeBSD): Changes from Jun Kuriyama to support ELF + * config.sub: (freebsd): Add to maybe_os + + + Copyright 1998,1999,2000,2001,2002 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +Local Variables: +buffer-read-only: t +End: diff --git a/comm/third_party/libgcrypt/build-aux/compile b/comm/third_party/libgcrypt/build-aux/compile new file mode 100755 index 0000000000..531136b068 --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/config.guess b/comm/third_party/libgcrypt/build-aux/config.guess new file mode 100755 index 0000000000..c4bd827a7b --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/config.guess @@ -0,0 +1,1456 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-05-15' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/config.rpath b/comm/third_party/libgcrypt/build-aux/config.rpath new file mode 100755 index 0000000000..c38b914d6b --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/config.rpath @@ -0,0 +1,690 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2013 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + nagfor*) + wl='-Wl,-Wl,,' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + xl* | bgxl* | bgf* | mpixl*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + wl= + ;; + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + newsos6) + ;; + *nto* | *qnx*) + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + wl='-Qoption ld ' + ;; + *) + wl='-Wl,' + ;; + esac + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + case "$host_cpu" in + powerpc) + ;; + m68k) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + haiku*) + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + case "$host_cpu" in + powerpc) + ;; + m68k) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then + : + else + ld_shlibs=no + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + *nto* | *qnx*) + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + case "$host_cpu" in + powerpc*) + library_names_spec='$libname$shrext' ;; + m68k) + library_names_spec='$libname.a' ;; + esac + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + haiku*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + *nto* | *qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + tpf*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/depcomp b/comm/third_party/libgcrypt/build-aux/depcomp new file mode 100755 index 0000000000..4ebd5b3a2f --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2013-05-30.07; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The second -e expression handles DOS-style file names with drive + # letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool generates 2 separate objects for the 2 libraries. These + # two compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E \ + | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + | sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/git-log-fix b/comm/third_party/libgcrypt/build-aux/git-log-fix new file mode 100644 index 0000000000..3e3fd95c50 --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/git-log-fix @@ -0,0 +1,14 @@ +# This file is expected to be used via gitlog-to-changelog's --amend=FILE +# option. It specifies what changes to make to each given SHA1's commit +# log and metadata, using Perl-eval'able expressions. + +eb4937914db3fb7317502e97e4f0e40c1857f59d +# Fix bad formatted entry dated 2013-05-20 +s/(?s)mpi_sub.*$/cipher: Fix segv in last ECC change. +* cipher\/ecc.c (generate_key): Make sure R is initialized./ + +296f38a2bd2e25788643a42e4881faed00884a40 +# Fix bad formatted entry dated 2013-05-09 +s/(?s)Generate ECC.*$/cipher: Generate compliant ECC keys. +* cipher\/ecc.c (generate_key): Make sure a key is compliant for +using the compact representation./ diff --git a/comm/third_party/libgcrypt/build-aux/git-log-footer b/comm/third_party/libgcrypt/build-aux/git-log-footer new file mode 100644 index 0000000000..c31fe936a5 --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/git-log-footer @@ -0,0 +1,14 @@ + +2011-12-01 Werner Koch + + NB: Changes done before December 1st, 2011 are described in + per directory files named ChangeLog-2011. See doc/HACKING for + details. + + ----- + Copyright (C) 2011 Free Software Foundation, Inc. + + Copying and distribution of this file and/or the original GIT + commit log messages, with or without modification, are + permitted provided the copyright notice and this notice are + preserved. diff --git a/comm/third_party/libgcrypt/build-aux/install-sh b/comm/third_party/libgcrypt/build-aux/install-sh new file mode 100755 index 0000000000..377bb8687f --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-11-20.07; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/ltmain.sh b/comm/third_party/libgcrypt/build-aux/ltmain.sh new file mode 100644 index 0000000000..859599aa3d --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/ltmain.sh @@ -0,0 +1,9664 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.2 Debian-2.4.2-1" +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Sed substitution to remove simple comments and empty +# lines from a Windows .def file. +sed_uncomment_deffile='/^;/d; /^[ ]*$/d' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED "$sed_uncomment_deffile" $export_symbols | $SED 1q`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 diff --git a/comm/third_party/libgcrypt/build-aux/mdate-sh b/comm/third_party/libgcrypt/build-aux/mdate-sh new file mode 100755 index 0000000000..b3719cf761 --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/mdate-sh @@ -0,0 +1,224 @@ +#!/bin/sh +# Get modification time of a file or directory and pretty-print it. + +scriptversion=2010-08-21.06; # UTC + +# Copyright (C) 1995-2013 Free Software Foundation, Inc. +# written by Ulrich Drepper , June 1995 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +fi + +case $1 in + '') + echo "$0: No file. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: mdate-sh [--help] [--version] FILE + +Pretty-print the modification day of FILE, in the format: +1 January 1970 + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "mdate-sh $scriptversion" + exit $? + ;; +esac + +error () +{ + echo "$0: $1" >&2 + exit 1 +} + + +# Prevent date giving response in another language. +LANG=C +export LANG +LC_ALL=C +export LC_ALL +LC_TIME=C +export LC_TIME + +# GNU ls changes its time format in response to the TIME_STYLE +# variable. Since we cannot assume 'unset' works, revert this +# variable to its documented default. +if test "${TIME_STYLE+set}" = set; then + TIME_STYLE=posix-long-iso + export TIME_STYLE +fi + +save_arg1=$1 + +# Find out how to get the extended ls output of a file or directory. +if ls -L /dev/null 1>/dev/null 2>&1; then + ls_command='ls -L -l -d' +else + ls_command='ls -l -d' +fi +# Avoid user/group names that might have spaces, when possible. +if ls -n /dev/null 1>/dev/null 2>&1; then + ls_command="$ls_command -n" +fi + +# A 'ls -l' line looks as follows on OS/2. +# drwxrwx--- 0 Aug 11 2001 foo +# This differs from Unix, which adds ownership information. +# drwxrwx--- 2 root root 4096 Aug 11 2001 foo +# +# To find the date, we split the line on spaces and iterate on words +# until we find a month. This cannot work with files whose owner is a +# user named "Jan", or "Feb", etc. However, it's unlikely that '/' +# will be owned by a user whose name is a month. So we first look at +# the extended ls output of the root directory to decide how many +# words should be skipped to get the date. + +# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. +set x`$ls_command /` + +# Find which argument is the month. +month= +command= +until test $month +do + test $# -gt 0 || error "failed parsing '$ls_command /' output" + shift + # Add another shift to the command. + command="$command shift;" + case $1 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; + esac +done + +test -n "$month" || error "failed parsing '$ls_command /' output" + +# Get the extended ls output of the file or directory. +set dummy x`eval "$ls_command \"\\\$save_arg1\""` + +# Remove all preceding arguments +eval $command + +# Because of the dummy argument above, month is in $2. +# +# On a POSIX system, we should have +# +# $# = 5 +# $1 = file size +# $2 = month +# $3 = day +# $4 = year or time +# $5 = filename +# +# On Darwin 7.7.0 and 7.6.0, we have +# +# $# = 4 +# $1 = day +# $2 = month +# $3 = year or time +# $4 = filename + +# Get the month. +case $2 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; +esac + +case $3 in + ???*) day=$1;; + *) day=$3; shift;; +esac + +# Here we have to deal with the problem that the ls output gives either +# the time of day or the year. +case $3 in + *:*) set `date`; eval year=\$$# + case $2 in + Jan) nummonthtod=1;; + Feb) nummonthtod=2;; + Mar) nummonthtod=3;; + Apr) nummonthtod=4;; + May) nummonthtod=5;; + Jun) nummonthtod=6;; + Jul) nummonthtod=7;; + Aug) nummonthtod=8;; + Sep) nummonthtod=9;; + Oct) nummonthtod=10;; + Nov) nummonthtod=11;; + Dec) nummonthtod=12;; + esac + # For the first six month of the year the time notation can also + # be used for files modified in the last year. + if (expr $nummonth \> $nummonthtod) > /dev/null; + then + year=`expr $year - 1` + fi;; + *) year=$3;; +esac + +# The result. +echo $day $month $year + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/missing b/comm/third_party/libgcrypt/build-aux/missing new file mode 100755 index 0000000000..db98974ff5 --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2013-10-28.13; # UTC + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try '$0 --help' for more information" + exit 1 +fi + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: unknown '$1' option" + echo 1>&2 "Try '$0 --help' for more information" + exit 1 + ;; + +esac + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=http://www.perl.org/ +flex_URL=http://flex.sourceforge.net/ +gnu_software_URL=http://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libgcrypt/build-aux/texinfo.tex b/comm/third_party/libgcrypt/build-aux/texinfo.tex new file mode 100644 index 0000000000..5a17f97938 --- /dev/null +++ b/comm/third_party/libgcrypt/build-aux/texinfo.tex @@ -0,0 +1,8638 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{2007-05-03.09} +% +% Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, +% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, +% 2007 Free Software Foundation, Inc. +% +% This texinfo.tex file is free software; you can redistribute it and/or +% modify it under the terms of the GNU General Public License as +% published by the Free Software Foundation; either version 3, or (at +% your option) any later version. +% +% This texinfo.tex file is distributed in the hope that it will be +% useful, but WITHOUT ANY WARRANTY; without even the implied warranty +% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this texinfo.tex file; see the file COPYING. If not, +% see . +% +% As a special exception, when this file is read by TeX when processing +% a Texinfo source document, you may use the result without +% restriction. (This has been our intent since Texinfo was invented.) +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% http://www.gnu.org/software/texinfo/ (the Texinfo home page), or +% ftp://tug.org/tex/texinfo.tex +% (and all CTAN mirrors, see http://www.ctan.org). +% The texinfo.tex in any given distribution could well be out +% of date, so if that's what you're using, please check. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever; this makes foo.ps. +% The extra TeX runs get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages, to some +% extent. You can get the existing language-specific files from the +% full Texinfo distribution. +% +% The GNU Texinfo home page is http://www.gnu.org/software/texinfo. + + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + + +\chardef\other=12 + +% We never want plain's \outer definition of \+ in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +% Save some plain tex macros whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexfootnote=\footnote +\let\ptexgtr=> +\let\ptexhat=^ +\let\ptexi=\i +\let\ptexindent=\indent +\let\ptexinsert=\insert +\let\ptexlbrace=\{ +\let\ptexless=< +\let\ptexnewwrite\newwrite +\let\ptexnoindent=\noindent +\let\ptexplus=+ +\let\ptexrbrace=\} +\let\ptexslash=\/ +\let\ptexstar=\* +\let\ptext=\t + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Pre-3.0. +\else + \def\linenumber{l.\the\inputlineno:\space} +\fi + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi + +% Since the category of space is not known, we have to be careful. +\chardef\spacecat = 10 +\def\spaceisspace{\catcode`\ =\spacecat} + +% sometimes characters are active, so we need control sequences. +\chardef\colonChar = `\: +\chardef\commaChar = `\, +\chardef\dashChar = `\- +\chardef\dotChar = `\. +\chardef\exclamChar= `\! +\chardef\lquoteChar= `\` +\chardef\questChar = `\? +\chardef\rquoteChar= `\' +\chardef\semiChar = `\; +\chardef\underChar = `\_ + +% Ignore a token. +% +\def\gobble#1{} + +% The following is used inside several \edef's. +\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} + +% Hyphenation fixes. +\hyphenation{ + Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script + ap-pen-dix bit-map bit-maps + data-base data-bases eshell fall-ing half-way long-est man-u-script + man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm + par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces + spell-ing spell-ings + stand-alone strong-est time-stamp time-stamps which-ever white-space + wide-spread wrap-around +} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen\bindingoffset +\newdimen\normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. We also make +% some effort to order the tracing commands to reduce output in the log +% file; cf. trace.sty in LaTeX. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{% + \tracingstats2 + \tracingpages1 + \tracinglostchars2 % 2 gives us more in etex + \tracingparagraphs1 + \tracingoutput1 + \tracingmacros2 + \tracingrestores1 + \showboxbreadth\maxdimen \showboxdepth\maxdimen + \ifx\eTeXversion\undefined\else % etex gives us more logging + \tracingscantokens1 + \tracingifs1 + \tracinggroups1 + \tracingnesting2 + \tracingassigns1 + \fi + \tracingcommands3 % 3 gives us more in etex + \errorcontextlines16 +}% + +% add check for \lastpenalty to plain's definitions. If the last thing +% we did was a \nobreak, we don't want to insert more space. +% +\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount + \removelastskip\penalty-50\smallskip\fi\fi} +\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount + \removelastskip\penalty-100\medskip\fi\fi} +\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount + \removelastskip\penalty-200\bigskip\fi\fi} + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + % We don't want .vr (or whatever) entries like this: + % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} + % "\acronym" won't work when it's read back in; + % it needs to be + % {\code {{\tt \backslashcurfont }acronym} + \shipout\vbox{% + % Do this early so pdf references go to the beginning of the page. + \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi + % + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingyyy.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 24pt + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \indexdummies + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg{\parseargusing{}} +\def\parseargusing#1#2{% + \def\argtorun{#2}% + \begingroup + \obeylines + \spaceisspace + #1% + \parseargline\empty% Insert the \empty token, see \finishparsearg below. +} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + \argremovecomment #1\comment\ArgTerm% + }% +} + +% First remove any @comment, then any @c comment. +\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} +\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} + +% Each occurrence of `\^^M' or `\^^M' is replaced by a single space. +% +% \argremovec might leave us with trailing space, e.g., +% @end itemize @c foo +% This space token undergoes the same procedure and is eventually removed +% by \finishparsearg. +% +\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} +\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} +\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% + \def\temp{#3}% + \ifx\temp\empty + % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: + \let\temp\finishparsearg + \else + \let\temp\argcheckspaces + \fi + % Put the space token in: + \temp#1 #3\ArgTerm +} + +% If a _delimited_ argument is enclosed in braces, they get stripped; so +% to get _exactly_ the rest of the line, we had to prevent such situation. +% We prepended an \empty token at the very beginning and we expand it now, +% just before passing the control to \argtorun. +% (Similarly, we have to think about #3 of \argcheckspacesY above: it is +% either the null string, or it ends with \^^M---thus there is no danger +% that a pair of braces would be stripped. +% +% But first, we have to remove the trailing space token. +% +\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} + +% \parseargdef\foo{...} +% is roughly equivalent to +% \def\foo{\parsearg\Xfoo} +% \def\Xfoo#1{...} +% +% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my +% favourite TeX trick. --kasal, 16nov03 + +\def\parseargdef#1{% + \expandafter \doparseargdef \csname\string#1\endcsname #1% +} +\def\doparseargdef#1#2{% + \def#2{\parsearg#1}% + \def#1##1% +} + +% Several utility definitions with active space: +{ + \obeyspaces + \gdef\obeyedspace{ } + + % Make each space character in the input produce a normal interword + % space in the output. Don't allow a line break at this space, as this + % is used only in environments like @example, where each line of input + % should produce a line of output anyway. + % + \gdef\sepspaces{\obeyspaces\let =\tie} + + % If an index command is used in an @example environment, any spaces + % therein should become regular spaces in the raw index file, not the + % expansion of \tie (\leavevmode \penalty \@M \ ). + \gdef\unsepspaces{\let =\space} +} + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +% Define the framework for environments in texinfo.tex. It's used like this: +% +% \envdef\foo{...} +% \def\Efoo{...} +% +% It's the responsibility of \envdef to insert \begingroup before the +% actual body; @end closes the group after calling \Efoo. \envdef also +% defines \thisenv, so the current environment is known; @end checks +% whether the environment name matches. The \checkenv macro can also be +% used to check whether the current environment is the one expected. +% +% Non-false conditionals (@iftex, @ifset) don't fit into this, so they +% are not treated as environments; they don't open a group. (The +% implementation of @end takes care not to call \endgroup in this +% special case.) + + +% At runtime, environments start with this: +\def\startenvironment#1{\begingroup\def\thisenv{#1}} +% initialize +\let\thisenv\empty + +% ... but they get defined via ``\envdef\foo{...}'': +\long\def\envdef#1#2{\def#1{\startenvironment#1#2}} +\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} + +% Check whether we're in the right environment: +\def\checkenv#1{% + \def\temp{#1}% + \ifx\thisenv\temp + \else + \badenverr + \fi +} + +% Environment mismatch, #1 expected: +\def\badenverr{% + \errhelp = \EMsimple + \errmessage{This command can appear only \inenvironment\temp, + not \inenvironment\thisenv}% +} +\def\inenvironment#1{% + \ifx#1\empty + out of any environment% + \else + in environment \expandafter\string#1% + \fi +} + +% @end foo executes the definition of \Efoo. +% But first, it executes a specialized version of \checkenv +% +\parseargdef\end{% + \if 1\csname iscond.#1\endcsname + \else + % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 + \expandafter\checkenv\csname#1\endcsname + \csname E#1\endcsname + \endgroup + \fi +} + +\newhelp\EMsimple{Press RETURN to continue.} + + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce \{ and \} commands for indices, + % and @{ and @} for the aux/toc files. + \catcode`\{ = \other \catcode`\} = \other + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\! = 0 \catcode`\\ = \other + !gdef!lbracecmd[\{]% + !gdef!rbracecmd[\}]% + !gdef!lbraceatcmd[@{]% + !gdef!rbraceatcmd[@}]% +!endgroup + +% @comma{} to avoid , parsing problems. +\let\comma = , + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown @ordf @ordm +% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} +\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} +\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% The \TeX{} logo, as in plain, but resetting the spacing so that a +% period following counts as ending a sentence. (Idea found in latex.) +% +\edef\TeX{\TeX \spacefactor=1000 } + +% @LaTeX{} logo. Not quite the same results as the definition in +% latex.ltx, since we use a different font for the raised A; it's most +% convenient for us to use an explicitly smaller font, rather than using +% the \scriptstyle font (since we don't reset \scriptstyle and +% \scriptscriptstyle). +% +\def\LaTeX{% + L\kern-.36em + {\setbox0=\hbox{T}% + \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% + \kern-.15em + \TeX +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @/ allows a line break. +\let\/=\allowbreak + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=\endofsentencespacefactor\space} + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=\endofsentencespacefactor\space} + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=\endofsentencespacefactor\space} + +% @frenchspacing on|off says whether to put extra space after punctuation. +% +\def\onword{on} +\def\offword{off} +% +\parseargdef\frenchspacing{% + \def\temp{#1}% + \ifx\temp\onword \plainfrenchspacing + \else\ifx\temp\offword \plainnonfrenchspacing + \else + \errhelp = \EMsimple + \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% + \fi\fi +} + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +% Another complication is that the group might be very large. This can +% cause the glue on the previous page to be unduly stretched, because it +% does not have much material. In this case, it's better to add an +% explicit \vfill so that the extra space is at the bottom. The +% threshold for doing this is if the group is more than \vfilllimit +% percent of a page (\vfilllimit can be changed inside of @tex). +% +\newbox\groupbox +\def\vfilllimit{0.7} +% +\envdef\group{% + \ifnum\catcode`\^^M=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + \startsavinginserts + % + \setbox\groupbox = \vtop\bgroup + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% The \vtop produces a box with normal height and large depth; thus, TeX puts +% \baselineskip glue before it, and (when the next line of text is done) +% \lineskip glue after it. Thus, space below is not quite equal to space +% above. But it's pretty close. +\def\Egroup{% + % To get correct interline space between the last line of the group + % and the first line afterwards, we have to propagate \prevdepth. + \endgraf % Not \par, as it may have been set to \lisppar. + \global\dimen1 = \prevdepth + \egroup % End the \vtop. + % \dimen0 is the vertical size of the group's box. + \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox + % \dimen2 is how much space is left on the page (more or less). + \dimen2 = \pageheight \advance\dimen2 by -\pagetotal + % if the group doesn't fit on the current page, and it's a big big + % group, force a page break. + \ifdim \dimen0 > \dimen2 + \ifdim \pagetotal < \vfilllimit\pageheight + \page + \fi + \fi + \box\groupbox + \prevdepth = \dimen1 + \checkinserts +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +% Old definition--didn't work. +%\parseargdef\need{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\parseargdef\need{% + % Ensure vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % If the @need value is less than one line space, it's useless. + \dimen0 = #1\mil + \dimen2 = \ht\strutbox + \advance\dimen2 by \dp\strutbox + \ifdim\dimen0 > \dimen2 + % + % Do a \strut just to make the height of this box be normal, so the + % normal leading is inserted relative to the preceding line. + % And a page break here is fine. + \vtop to #1\mil{\strut\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + \fi +} + +% @br forces paragraph break (and is undocumented). + +\let\br = \par + +% @page forces the start of a new page. +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} + +% This defn is used inside nofill environments such as @example. +\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount + \leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current +% paragraph. For more general purposes, use the \margin insertion +% class. WHICH is `l' or `r'. +% +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} +% +\def\doinmargin#1#2{\strut\vadjust{% + \nobreak + \kern-\strutdepth + \vtop to \strutdepth{% + \baselineskip=\strutdepth + \vss + % if you have multiple lines of stuff to put here, you'll need to + % make the vbox yourself of the appropriate size. + \ifx#1l% + \llap{\ignorespaces #2\hskip\inmarginspacing}% + \else + \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% + \fi + \null + }% +}} +\def\inleftmargin{\doinmargin l} +\def\inrightmargin{\doinmargin r} +% +% @inmargin{TEXT [, RIGHT-TEXT]} +% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; +% else use TEXT for both). +% +\def\inmargin#1{\parseinmargin #1,,\finish} +\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \def\lefttext{#1}% have both texts + \def\righttext{#2}% + \else + \def\lefttext{#1}% have only one text + \def\righttext{#1}% + \fi + % + \ifodd\pageno + \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin + \else + \def\temp{\inleftmargin\lefttext}% + \fi + \temp +} + +% @include file insert text of that file as input. +% +\def\include{\parseargusing\filenamecatcodes\includezzz} +\def\includezzz#1{% + \pushthisfilestack + \def\thisfile{#1}% + {% + \makevalueexpandable + \def\temp{\input #1 }% + \expandafter + }\temp + \popthisfilestack +} +\def\filenamecatcodes{% + \catcode`\\=\other + \catcode`~=\other + \catcode`^=\other + \catcode`_=\other + \catcode`|=\other + \catcode`<=\other + \catcode`>=\other + \catcode`+=\other + \catcode`-=\other +} + +\def\pushthisfilestack{% + \expandafter\pushthisfilestackX\popthisfilestack\StackTerm +} +\def\pushthisfilestackX{% + \expandafter\pushthisfilestackY\thisfile\StackTerm +} +\def\pushthisfilestackY #1\StackTerm #2\StackTerm {% + \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% +} + +\def\popthisfilestack{\errthisfilestackempty} +\def\errthisfilestackempty{\errmessage{Internal error: + the stack of filenames is empty.}} + +\def\thisfile{} + +% @center line +% outputs that line, centered. +% +\parseargdef\center{% + \ifhmode + \let\next\centerH + \else + \let\next\centerV + \fi + \next{\hfil \ignorespaces#1\unskip \hfil}% +} +\def\centerH#1{% + {% + \hfil\break + \advance\hsize by -\leftskip + \advance\hsize by -\rightskip + \line{#1}% + \break + }% +} +\def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} + +% @sp n outputs n lines of vertical space + +\parseargdef\sp{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% NCHARS can also be the word `asis' or `none'. +% We cannot feasibly implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\parseargdef\paragraphindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\parseargdef\exampleindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @firstparagraphindent WORD +% If WORD is `none', then suppress indentation of the first paragraph +% after a section heading. If WORD is `insert', then do indent at such +% paragraphs. +% +% The paragraph indentation is suppressed or not by calling +% \suppressfirstparagraphindent, which the sectioning commands do. +% We switch the definition of this back and forth according to WORD. +% By default, we suppress indentation. +% +\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} +\def\insertword{insert} +% +\parseargdef\firstparagraphindent{% + \def\temp{#1}% + \ifx\temp\noneword + \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent + \else\ifx\temp\insertword + \let\suppressfirstparagraphindent = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @firstparagraphindent option `\temp'}% + \fi\fi +} + +% Here is how we actually suppress indentation. Redefine \everypar to +% \kern backwards by \parindent, and then reset itself to empty. +% +% We also make \indent itself not actually do anything until the next +% paragraph. +% +\gdef\dosuppressfirstparagraphindent{% + \gdef\indent{% + \restorefirstparagraphindent + \indent + }% + \gdef\noindent{% + \restorefirstparagraphindent + \noindent + }% + \global\everypar = {% + \kern -\parindent + \restorefirstparagraphindent + }% +} + +\gdef\restorefirstparagraphindent{% + \global \let \indent = \ptexindent + \global \let \noindent = \ptexnoindent + \global \everypar = {}% +} + + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math outputs its argument in math mode. +% +% One complication: _ usually means subscripts, but it could also mean +% an actual _ character, as in @math{@var{some_variable} + 1}. So make +% _ active, and distinguish by seeing if the current family is \slfam, +% which is what @var uses. +{ + \catcode`\_ = \active + \gdef\mathunderscore{% + \catcode`\_=\active + \def_{\ifnum\fam=\slfam \_\else\sb\fi}% + } +} +% Another complication: we want \\ (and @\) to output a \ character. +% FYI, plain.tex uses \\ as a temporary control sequence (why?), but +% this is not advertised and we don't care. Texinfo does not +% otherwise define @\. +% +% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. +\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} +% +\def\math{% + \tex + \mathunderscore + \let\\ = \mathbackslash + \mathactive + $\finishmath +} +\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. + +% Some active characters (such as <) are spaced differently in math. +% We have to reset their definitions in case the @math was an argument +% to a command which sets the catcodes (such as @item or @section). +% +{ + \catcode`^ = \active + \catcode`< = \active + \catcode`> = \active + \catcode`+ = \active + \gdef\mathactive{% + \let^ = \ptexhat + \let< = \ptexless + \let> = \ptexgtr + \let+ = \ptexplus + } +} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{$\ptexbullet$} +\def\minus{$-$} + +% @dots{} outputs an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in the cm +% typewriter fonts as three actual period characters; on the other hand, +% in other typewriter fonts three periods are wider than 1.5em. So do +% whichever is larger. +% +\def\dots{% + \leavevmode + \setbox0=\hbox{...}% get width of three periods + \ifdim\wd0 > 1.5em + \dimen0 = \wd0 + \else + \dimen0 = 1.5em + \fi + \hbox to \dimen0{% + \hskip 0pt plus.25fil + .\hskip 0pt plus1fil + .\hskip 0pt plus1fil + .\hskip 0pt plus.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \dots + \spacefactor=\endofsentencespacefactor +} + +% @comma{} is so commas can be inserted into text without messing up +% Texinfo's parsing. +% +\let\comma = , + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \iflinks + \tryauxfile + % Open the new aux file. TeX will close it automatically at exit. + \immediate\openout\auxfile=\jobname.aux + \fi % \openindices needs to do some work in any case. + \openindices + \let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + \openin 1 texinfo.cnf + \ifeof 1 \else \input texinfo.cnf \fi + \closein 1 + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 +% can be set). So we test for \relax and 0 as well as \undefined, +% borrowed from ifpdf.sty. +\ifx\pdfoutput\undefined +\else + \ifx\pdfoutput\relax + \else + \ifcase\pdfoutput + \else + \pdftrue + \fi + \fi +\fi + +% PDF uses PostScript string constants for the names of xref targets, +% for display in the outlines, and in other places. Thus, we have to +% double any backslashes. Otherwise, a name like "\node" will be +% interpreted as a newline (\n), followed by o, d, e. Not good. +% http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html +% (and related messages, the final outcome is that it is up to the TeX +% user to double the backslashes and otherwise make the string valid, so +% that's what we do). + +% double active backslashes. +% +{\catcode`\@=0 \catcode`\\=\active + @gdef@activebackslashdouble{% + @catcode`@\=@active + @let\=@doublebackslash} +} + +% To handle parens, we must adopt a different approach, since parens are +% not active characters. hyperref.dtx (which has the same problem as +% us) handles it with this amazing macro to replace tokens, with minor +% changes for Texinfo. It is included here under the GPL by permission +% from the author, Heiko Oberdiek. +% +% #1 is the tokens to replace. +% #2 is the replacement. +% #3 is the control sequence with the string. +% +\def\HyPsdSubst#1#2#3{% + \def\HyPsdReplace##1#1##2\END{% + ##1% + \ifx\\##2\\% + \else + #2% + \HyReturnAfterFi{% + \HyPsdReplace##2\END + }% + \fi + }% + \xdef#3{\expandafter\HyPsdReplace#3#1\END}% +} +\long\def\HyReturnAfterFi#1\fi{\fi#1} + +% #1 is a control sequence in which to do the replacements. +\def\backslashparens#1{% + \xdef#1{#1}% redefine it as its expansion; the definition is simply + % \lastnode when called from \setref -> \pdfmkdest. + \HyPsdSubst{(}{\realbackslash(}{#1}% + \HyPsdSubst{)}{\realbackslash)}{#1}% +} + +\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images +with PDF output, and none of those formats could be found. (.eps cannot +be supported due to the design of the PDF format; use regular TeX (DVI +output) for that.)} + +\ifpdf + \input pdfcolor + \pdfcatalog{/PageMode /UseOutlines} + % + % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). + \def\dopdfimage#1#2#3{% + \def\imagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% + \def\imageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% + % + % pdftex (and the PDF format) support .png, .jpg, .pdf (among + % others). Let's try in that order. + \let\pdfimgext=\empty + \begingroup + \openin 1 #1.png \ifeof 1 + \openin 1 #1.jpg \ifeof 1 + \openin 1 #1.jpeg \ifeof 1 + \openin 1 #1.JPG \ifeof 1 + \openin 1 #1.pdf \ifeof 1 + \errhelp = \nopdfimagehelp + \errmessage{Could not find image file #1 for pdf}% + \else \gdef\pdfimgext{pdf}% + \fi + \else \gdef\pdfimgext{JPG}% + \fi + \else \gdef\pdfimgext{jpeg}% + \fi + \else \gdef\pdfimgext{jpg}% + \fi + \else \gdef\pdfimgext{png}% + \fi + \closein 1 + \endgroup + % + % without \immediate, pdftex seg faults when the same image is + % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) + \ifnum\pdftexversion < 14 + \immediate\pdfimage + \else + \immediate\pdfximage + \fi + \ifdim \wd0 >0pt width \imagewidth \fi + \ifdim \wd2 >0pt height \imageheight \fi + \ifnum\pdftexversion<13 + #1.\pdfimgext + \else + {#1.\pdfimgext}% + \fi + \ifnum\pdftexversion < 14 \else + \pdfrefximage \pdflastximage + \fi} + % + \def\pdfmkdest#1{{% + % We have to set dummies so commands such as @code, and characters + % such as \, aren't expanded when present in a section title. + \indexnofonts + \turnoffactive + \activebackslashdouble + \makevalueexpandable + \def\pdfdestname{#1}% + \backslashparens\pdfdestname + \safewhatsit{\pdfdest name{\pdfdestname} xyz}% + }} + % + % used to mark target names; must be expandable. + \def\pdfmkpgn#1{#1} + % + % by default, use a color that is dark enough to print on paper as + % nearly black, but still distinguishable for online viewing. + % (Defined in pdfcolor.tex.) + \let\urlcolor = \BrickRed + \let\linkcolor = \BrickRed + \def\endlink{\Black\pdfendlink} + % + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by 1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + % + % #1 is the section text, which is what will be displayed in the + % outline by the pdf viewer. #2 is the pdf expression for the number + % of subentries (or empty, for subsubsections). #3 is the node text, + % which might be empty if this toc entry had no corresponding node. + % #4 is the page number + % + \def\dopdfoutline#1#2#3#4{% + % Generate a link to the node text if that exists; else, use the + % page number. We could generate a destination for the section + % text in the case where a section has no node, but it doesn't + % seem worth the trouble, since most documents are normally structured. + \def\pdfoutlinedest{#3}% + \ifx\pdfoutlinedest\empty + \def\pdfoutlinedest{#4}% + \else + % Doubled backslashes in the name. + {\activebackslashdouble \xdef\pdfoutlinedest{#3}% + \backslashparens\pdfoutlinedest}% + \fi + % + % Also double the backslashes in the display string. + {\activebackslashdouble \xdef\pdfoutlinetext{#1}% + \backslashparens\pdfoutlinetext}% + % + \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% + } + % + \def\pdfmakeoutlines{% + \begingroup + % Thanh's hack / proper braces in bookmarks + \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace + \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace + % + % Read toc silently, to get counts of subentries for \pdfoutline. + \def\numchapentry##1##2##3##4{% + \def\thischapnum{##2}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + }% + \def\numsecentry##1##2##3##4{% + \advancenumber{chap\thischapnum}% + \def\thissecnum{##2}% + \def\thissubsecnum{0}% + }% + \def\numsubsecentry##1##2##3##4{% + \advancenumber{sec\thissecnum}% + \def\thissubsecnum{##2}% + }% + \def\numsubsubsecentry##1##2##3##4{% + \advancenumber{subsec\thissubsecnum}% + }% + \def\thischapnum{0}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + % + % use \def rather than \let here because we redefine \chapentry et + % al. a second time, below. + \def\appentry{\numchapentry}% + \def\appsecentry{\numsecentry}% + \def\appsubsecentry{\numsubsecentry}% + \def\appsubsubsecentry{\numsubsubsecentry}% + \def\unnchapentry{\numchapentry}% + \def\unnsecentry{\numsecentry}% + \def\unnsubsecentry{\numsubsecentry}% + \def\unnsubsubsecentry{\numsubsubsecentry}% + \readdatafile{toc}% + % + % Read toc second time, this time actually producing the outlines. + % The `-' means take the \expnumber as the absolute number of + % subentries, which we calculated on our first read of the .toc above. + % + % We use the node names as the destinations. + \def\numchapentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% + \def\numsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% + \def\numsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% + \def\numsubsubsecentry##1##2##3##4{% count is always zero + \dopdfoutline{##1}{}{##3}{##4}}% + % + % PDF outlines are displayed using system fonts, instead of + % document fonts. Therefore we cannot use special characters, + % since the encoding is unknown. For example, the eogonek from + % Latin 2 (0xea) gets translated to a | character. Info from + % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. + % + % xx to do this right, we have to translate 8-bit characters to + % their "best" equivalent, based on the @documentencoding. Right + % now, I guess we'll just let the pdf reader have its way. + \indexnofonts + \setupdatafile + \catcode`\\=\active \otherbackslash + \input \jobname.toc + \endgroup + } + % + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \ifx\p\space\else\addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \fi + \nextsp} + \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + % make a live url in pdf output. + \def\pdfurl#1{% + \begingroup + % it seems we really need yet another set of dummies; have not + % tried to figure out what each command should do in the context + % of @url. for now, just make @/ a no-op, that's the only one + % people have actually reported a problem with. + % + \normalturnoffactive + \def\@{@}% + \let\/=\empty + \makevalueexpandable + \leavevmode\urlcolor + \startlink attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS|\relax + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} + \linkcolor #1\endlink} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\else + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\linkcolor = \relax + \let\pdfmakeoutlines = \relax +\fi % \ifx\pdfoutput + + +\message{fonts,} + +% Change the current font style to #1, remembering it in \curfontstyle. +% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in +% italics, not bold italics. +% +\def\setfontstyle#1{% + \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. + \csname ten#1\endcsname % change the current font +} + +% Select #1 fonts with the current style. +% +\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} + +\def\rm{\fam=0 \setfontstyle{rm}} +\def\it{\fam=\itfam \setfontstyle{it}} +\def\sl{\fam=\slfam \setfontstyle{sl}} +\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} +\def\tt{\fam=\ttfam \setfontstyle{tt}} + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf. +\newfam\sffam +\def\sf{\fam=\sffam \setfontstyle{sf}} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this font style. +\def\ttsl{\setfontstyle{ttsl}} + + +% Default leading. +\newdimen\textleading \textleading = 13.2pt + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% +% PDF CMaps. See also LaTeX's t1.cmap. +% +% \cmapOT1 +\ifpdf + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1-0) +%%Title: (TeX-OT1-0 TeX OT1 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1) +/Supplement 0 +>> def +/CMapName /TeX-OT1-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<23> <26> <0023> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +40 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1IT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1IT-0) +%%Title: (TeX-OT1IT-0 TeX OT1IT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1IT) +/Supplement 0 +>> def +/CMapName /TeX-OT1IT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<25> <26> <0025> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +42 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<23> <0023> +<24> <00A3> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1IT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1TT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1TT-0) +%%Title: (TeX-OT1TT-0 TeX OT1TT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1TT) +/Supplement 0 +>> def +/CMapName /TeX-OT1TT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +5 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<21> <26> <0021> +<28> <5F> <0028> +<61> <7E> <0061> +endbfrange +32 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <2191> +<0C> <2193> +<0D> <0027> +<0E> <00A1> +<0F> <00BF> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<20> <2423> +<27> <2019> +<60> <2018> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1TT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +\else + \expandafter\let\csname cmapOT1\endcsname\gobble + \expandafter\let\csname cmapOT1IT\endcsname\gobble + \expandafter\let\csname cmapOT1TT\endcsname\gobble +\fi + + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor, #5 is the CMap +% encoding (currently only OT1, OT1IT and OT1TT are allowed, pass +% empty to omit). +\def\setfont#1#2#3#4#5{% + \font#1=\fontprefix#2#3 scaled #4 + \csname cmap#5\endcsname#1% +} +% This is what gets called when #5 of \setfont is empty. +\let\cmap\gobble + + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +% Definitions for a main text size of 11pt. This is the default in +% Texinfo. +% +\def\definetextfontsizexi{% +% Text fonts (11.2pt, magstep1). +\def\textnominalsize{11pt} +\edef\mainmagstep{\magstephalf} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstep1}{OT1} +\setfont\deftt\ttshape{10}{\magstep1}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} +\def\authortt{\sectt} + +% Chapter (and unnumbered) fonts (17.28pt). +\def\chapnominalsize{17pt} +\setfont\chaprm\rmbshape{12}{\magstep2}{OT1} +\setfont\chapit\itbshape{10}{\magstep3}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep3}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} +\setfont\chapsf\sfbshape{17}{1000}{OT1} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3}{OT1} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\def\secnominalsize{14pt} +\setfont\secrm\rmbshape{12}{\magstep1}{OT1} +\setfont\secit\itbshape{10}{\magstep2}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep2}{OT1} +\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\secsf\sfbshape{12}{\magstep1}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2}{OT1} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% Subsection fonts (13.15pt). +\def\ssecnominalsize{13pt} +\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} +\setfont\ssecit\itbshape{10}{1315}{OT1IT} +\setfont\ssecsl\slbshape{10}{1315}{OT1} +\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} +\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1315}{OT1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 + +% Reduced fonts for @acro in text (10pt). +\def\reducednominalsize{10pt} +\setfont\reducedrm\rmshape{10}{1000}{OT1} +\setfont\reducedtt\ttshape{10}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{1000}{OT1} +\setfont\reducedit\itshape{10}{1000}{OT1IT} +\setfont\reducedsl\slshape{10}{1000}{OT1} +\setfont\reducedsf\sfshape{10}{1000}{OT1} +\setfont\reducedsc\scshape{10}{1000}{OT1} +\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} +\font\reducedi=cmmi10 +\font\reducedsy=cmsy10 + +% reset the current fonts +\textfonts +\rm +} % end of 11pt text font size definitions + + +% Definitions to make the main text be 10pt Computer Modern, with +% section, chapter, etc., sizes following suit. This is for the GNU +% Press printing of the Emacs 22 manual. Maybe other manuals in the +% future. Used with @smallbook, which sets the leading to 12pt. +% +\def\definetextfontsizex{% +% Text fonts (10pt). +\def\textnominalsize{10pt} +\edef\mainmagstep{1000} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstephalf}{OT1} +\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} +\def\authortt{\sectt} + +% Chapter fonts (14.4pt). +\def\chapnominalsize{14pt} +\setfont\chaprm\rmbshape{12}{\magstep1}{OT1} +\setfont\chapit\itbshape{10}{\magstep2}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep2}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\chapsf\sfbshape{12}{\magstep1}{OT1} +\let\chapbf\chaprm +\setfont\chapsc\scbshape{10}{\magstep2}{OT1} +\font\chapi=cmmi12 scaled \magstep1 +\font\chapsy=cmsy10 scaled \magstep2 + +% Section fonts (12pt). +\def\secnominalsize{12pt} +\setfont\secrm\rmbshape{12}{1000}{OT1} +\setfont\secit\itbshape{10}{\magstep1}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep1}{OT1} +\setfont\sectt\ttbshape{12}{1000}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} +\setfont\secsf\sfbshape{12}{1000}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep1}{OT1} +\font\seci=cmmi12 +\font\secsy=cmsy10 scaled \magstep1 + +% Subsection fonts (10pt). +\def\ssecnominalsize{10pt} +\setfont\ssecrm\rmbshape{10}{1000}{OT1} +\setfont\ssecit\itbshape{10}{1000}{OT1IT} +\setfont\ssecsl\slbshape{10}{1000}{OT1} +\setfont\ssectt\ttbshape{10}{1000}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} +\setfont\ssecsf\sfbshape{10}{1000}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1000}{OT1} +\font\sseci=cmmi10 +\font\ssecsy=cmsy10 + +% Reduced fonts for @acro in text (9pt). +\def\reducednominalsize{9pt} +\setfont\reducedrm\rmshape{9}{1000}{OT1} +\setfont\reducedtt\ttshape{9}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{900}{OT1} +\setfont\reducedit\itshape{9}{1000}{OT1IT} +\setfont\reducedsl\slshape{9}{1000}{OT1} +\setfont\reducedsf\sfshape{9}{1000}{OT1} +\setfont\reducedsc\scshape{10}{900}{OT1} +\setfont\reducedttsl\ttslshape{10}{900}{OT1TT} +\font\reducedi=cmmi9 +\font\reducedsy=cmsy9 + +% reduce space between paragraphs +\divide\parskip by 2 + +% reset the current fonts +\textfonts +\rm +} % end of 10pt text font size definitions + + +% We provide the user-level command +% @fonttextsize 10 +% (or 11) to redefine the text font size. pt is assumed. +% +\def\xword{10} +\def\xiword{11} +% +\parseargdef\fonttextsize{% + \def\textsizearg{#1}% + \wlog{doing @fonttextsize \textsizearg}% + % + % Set \globaldefs so that documents can use this inside @tex, since + % makeinfo 4.8 does not support it, but we need it nonetheless. + % + \begingroup \globaldefs=1 + \ifx\textsizearg\xword \definetextfontsizex + \else \ifx\textsizearg\xiword \definetextfontsizexi + \else + \errhelp=\EMsimple + \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} + \fi\fi + \endgroup +} + + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts except +% in the main text, we don't bother to reset \scriptfont and +% \scriptscriptfont (which would also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy + \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf + \textfont\ttfam=\tentt \textfont\sffam=\tensf +} + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this because \STYLE needs to also set the +% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire +% \tenSTYLE to set the current font. +% +% Each font-changing command also sets the names \lsize (one size lower) +% and \lllsize (three sizes lower). These relative commands are used in +% the LaTeX logo and acronyms. +% +% This all needs generalizing, badly. +% +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy + \let\tenttsl=\textttsl + \def\curfontsize{text}% + \def\lsize{reduced}\def\lllsize{smaller}% + \resetmathfonts \setleading{\textleading}} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \def\curfontsize{title}% + \def\lsize{chap}\def\lllsize{subsec}% + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \let\tenttsl=\chapttsl + \def\curfontsize{chap}% + \def\lsize{sec}\def\lllsize{text}% + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \let\tenttsl=\secttsl + \def\curfontsize{sec}% + \def\lsize{subsec}\def\lllsize{reduced}% + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \let\tenttsl=\ssecttsl + \def\curfontsize{ssec}% + \def\lsize{text}\def\lllsize{small}% + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts +\def\reducedfonts{% + \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl + \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc + \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy + \let\tenttsl=\reducedttsl + \def\curfontsize{reduced}% + \def\lsize{small}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallfonts{% + \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl + \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc + \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy + \let\tenttsl=\smallttsl + \def\curfontsize{small}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallerfonts{% + \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl + \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc + \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy + \let\tenttsl=\smallerttsl + \def\curfontsize{smaller}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{9.5pt}} + +% Set the fonts to use with the @small... environments. +\let\smallexamplefonts = \smallfonts + +% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample +% can fit this many characters: +% 8.5x11=86 smallbook=72 a4=90 a5=69 +% If we use \scriptfonts (8pt), then we can fit this many characters: +% 8.5x11=90+ smallbook=80 a4=90+ a5=77 +% For me, subjectively, the few extra characters that fit aren't worth +% the additional smallness of 8pt. So I'm making the default 9pt. +% +% By the way, for comparison, here's what fits with @example (10pt): +% 8.5x11=71 smallbook=60 a4=75 a5=58 +% +% I wish the USA used A4 paper. +% --karl, 24jan03. + + +% Set up the default fonts, so we can use them for creating boxes. +% +\definetextfontsizexi + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000}{OT1} +\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 +\setfont\shortcontsl\slshape{12}{1000}{OT1} +\setfont\shortconttt\ttshape{12}{1000}{OT1TT} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else + \ptexslash\fi\fi\fi} +\def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally uses \ttsl. +% @var is set to this for defun arguments. +\def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally use \sl. We never want +% ttsl for book titles, do we? +\def\cite#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\slanted=\smartslanted +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic + +% @b, explicit bold. +\def\b#1{{\bf #1}} +\let\strong=\b + +% @sansserif, explicit sans. +\def\sansserif#1{{\sf #1}} + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +% Set sfcode to normal for the chars that usually have another value. +% Can't use plain's \frenchspacing because it uses the `\x notation, and +% sometimes \x has an active definition that messes things up. +% +\catcode`@=11 + \def\plainfrenchspacing{% + \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m + \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m + \def\endofsentencespacefactor{1000}% for @. and friends + } + \def\plainnonfrenchspacing{% + \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 + \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 + \def\endofsentencespacefactor{3000}% for @. and friends + } +\catcode`@=\other +\def\endofsentencespacefactor{3000}% default + +\def\t#1{% + {\tt \rawbackslash \plainfrenchspacing #1}% + \null +} +\def\samp#1{`\tclose{#1}'\null} +\setfont\keyrm\rmshape{8}{1000}{OT1} +\font\keysy=cmsy9 +\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +\def\key #1{{\nohyphenation \uppercase{#1}}\null} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \plainfrenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in @code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active \catcode`\_=\active + \catcode`\'=\active \catcode`\`=\active + % + \global\def\code{\begingroup + \catcode\rquoteChar=\active \catcode\lquoteChar=\active + \let'\codequoteright \let`\codequoteleft + % + \catcode\dashChar=\active \catcode\underChar=\active + \ifallowcodebreaks + \let-\codedash + \let_\codeunder + \else + \let-\realdash + \let_\realunder + \fi + \codex + } +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{% + % this is all so @math{@code{var_name}+1} can work. In math mode, _ + % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) + % will therefore expand the active definition of _, which is us + % (inside @code that is), therefore an endless loop. + \ifusingtt{\ifmmode + \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. + \else\normalunderscore \fi + \discretionary{}{}{}}% + {\_}% +} +\def\codex #1{\tclose{#1}\endgroup} + +% An additional complication: the above will allow breaks after, e.g., +% each of the four underscores in __typeof__. This is undesirable in +% some manuals, especially if they don't have long identifiers in +% general. @allowcodebreaks provides a way to control this. +% +\newif\ifallowcodebreaks \allowcodebreakstrue + +\def\keywordtrue{true} +\def\keywordfalse{false} + +\parseargdef\allowcodebreaks{% + \def\txiarg{#1}% + \ifx\txiarg\keywordtrue + \allowcodebreakstrue + \else\ifx\txiarg\keywordfalse + \allowcodebreaksfalse + \else + \errhelp = \EMsimple + \errmessage{Unknown @allowcodebreaks option `\txiarg'}% + \fi\fi +} + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\parseargdef\kbdinputstyle{% + \def\txiarg{#1}% + \ifx\txiarg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\txiarg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\txiarg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \else + \errhelp = \EMsimple + \errmessage{Unknown @kbdinputstyle option `\txiarg'}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is `distinct.' +\kbdinputstyle distinct + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @indicateurl, @env, @command quotes seem unnecessary, so use \code. +\let\indicateurl=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{\begingroup + \unsepspaces + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \ifpdf + \unhbox0 % PDF: 2nd arg given, show only it + \else + \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url + \fi + \else + \code{#1}% only url given, so show it + \fi + \fi + \endlink +\endgroup} + +% @url synonym for @uref, since that's how everyone uses it. +% +\let\url=\uref + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} +\else + \let\email=\uref +\fi + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym for "FBI", "NATO", and the like. +% We print this one point size smaller, since it's intended for +% all-uppercase. +% +\def\acronym#1{\doacronym #1,,\finish} +\def\doacronym#1,#2,#3\finish{% + {\selectfonts\lsize #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @abbr for "Comput. J." and the like. +% No font change, but don't do end-of-sentence spacing. +% +\def\abbr#1{\doabbr #1,,\finish} +\def\doabbr#1,#2,#3\finish{% + {\plainfrenchspacing #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @pounds{} is a sterling sign, which Knuth put in the CM italic font. +% +\def\pounds{{\it\$}} + +% @euro{} comes from a separate font, depending on the current style. +% We use the free feym* fonts from the eurosym package by Henrik +% Theiling, which support regular, slanted, bold and bold slanted (and +% "outlined" (blackboard board, sort of) versions, which we don't need). +% It is available from http://www.ctan.org/tex-archive/fonts/eurosym. +% +% Although only regular is the truly official Euro symbol, we ignore +% that. The Euro is designed to be slightly taller than the regular +% font height. +% +% feymr - regular +% feymo - slanted +% feybr - bold +% feybo - bold slanted +% +% There is no good (free) typewriter version, to my knowledge. +% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. +% Hmm. +% +% Also doesn't work in math. Do we need to do math with euro symbols? +% Hope not. +% +% +\def\euro{{\eurofont e}} +\def\eurofont{% + % We set the font at each command, rather than predefining it in + % \textfonts and the other font-switching commands, so that + % installations which never need the symbol don't have to have the + % font installed. + % + % There is only one designed size (nominal 10pt), so we always scale + % that to the current nominal size. + % + % By the way, simply using "at 1em" works for cmr10 and the like, but + % does not work for cmbx10 and other extended/shrunken fonts. + % + \def\eurosize{\csname\curfontsize nominalsize\endcsname}% + % + \ifx\curfontstyle\bfstylename + % bold: + \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize + \else + % regular: + \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize + \fi + \thiseurofont +} + +% @registeredsymbol - R in a circle. The font for the R should really +% be smaller yet, but lllsize is the best we can do for now. +% Adapted from the plain.tex definition of \copyright. +% +\def\registeredsymbol{% + $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% + \hfil\crcr\Orb}}% + }$% +} + +% @textdegree - the normal degrees sign. +% +\def\textdegree{$^\circ$} + +% Laurent Siebenmann reports \Orb undefined with: +% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 +% so we'll define it if necessary. +% +\ifx\Orb\undefined +\def\Orb{\mathhexbox20D} +\fi + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\envdef\titlepage{% + % Open one extra group, as we want to close it in the middle of \Etitlepage. + \begingroup + \parindent=0pt \textfonts + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \let\page = \oldpage + \page + \null + }% +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % Need this before the \...aftertitlepage checks so that if they are + % in effect the toc pages will come out with page numbers. + \HEADINGSon + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Macros to be used within @titlepage: + +\let\subtitlerm=\tenrm +\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} + +\def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines + \let\tt=\authortt} + +\parseargdef\title{% + \checkenv\titlepage + \leftline{\titlefonts\rm #1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt +} + +\parseargdef\subtitle{% + \checkenv\titlepage + {\subtitlefont \rightline{#1}}% +} + +% @author should come last, but may come many times. +% It can also be used inside @quotation. +% +\parseargdef\author{% + \def\temp{\quotation}% + \ifx\thisenv\temp + \def\quotationauthor{#1}% printed in \Equotation. + \else + \checkenv\titlepage + \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi + {\authorfont \leftline{#1}}% + \fi +} + + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make TeX use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + + +\def\evenheading{\parsearg\evenheadingxxx} +\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} +\def\evenheadingyyy #1\|#2\|#3\|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddheading{\parsearg\oddheadingxxx} +\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} +\def\oddheadingyyy #1\|#2\|#3\|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} +\def\evenfootingyyy #1\|#2\|#3\|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddfooting{\parsearg\oddfootingxxx} +\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} +\def\oddfootingyyy #1\|#2\|#3\|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -12pt + \global\advance\vsize by -12pt +} + +\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} + + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{% +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% This produces Day Month Year style of output. +% Only define if not already defined, in case a txi-??.tex file has set +% up a different format (e.g., txi-cs.tex does this). +\ifx\today\undefined +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} +\fi + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg{\gdef\thistitle}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @ftable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemindicate{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. However, if + % what follows is an environment such as @example, there will be no + % \parskip glue; then the negative vskip we just inserted would + % cause the example and the item to crash together. So we use this + % bizarre value of 10001 as a signal to \aboveenvbreak to insert + % \parskip glue after all. Section titles are handled this way also. + % + \penalty 10001 + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a list environment}} +\def\itemx{\errmessage{@itemx while not in a list environment}} + +% @table, @ftable, @vtable. +\envdef\table{% + \let\itemindex\gobble + \tablecheck{table}% +} +\envdef\ftable{% + \def\itemindex ##1{\doind {fn}{\code{##1}}}% + \tablecheck{ftable}% +} +\envdef\vtable{% + \def\itemindex ##1{\doind {vr}{\code{##1}}}% + \tablecheck{vtable}% +} +\def\tablecheck#1{% + \ifnum \the\catcode`\^^M=\active + \endgroup + \errmessage{This command won't work in this context; perhaps the problem is + that we are \inenvironment\thisenv}% + \def\next{\doignore{#1}}% + \else + \let\next\tablex + \fi + \next +} +\def\tablex#1{% + \def\itemindicate{#1}% + \parsearg\tabley +} +\def\tabley#1{% + {% + \makevalueexpandable + \edef\temp{\noexpand\tablez #1\space\space\space}% + \expandafter + }\temp \endtablez +} +\def\tablez #1 #2 #3 #4\endtablez{% + \aboveenvbreak + \ifnum 0#1>0 \advance \leftskip by #1\mil \fi + \ifnum 0#2>0 \tableindent=#2\mil \fi + \ifnum 0#3>0 \advance \rightskip by #3\mil \fi + \itemmax=\tableindent + \advance \itemmax by -\itemmargin + \advance \leftskip by \tableindent + \exdentamount=\tableindent + \parindent = 0pt + \parskip = \smallskipamount + \ifdim \parskip=0pt \parskip=2pt \fi + \let\item = \internalBitem + \let\itemx = \internalBitemx +} +\def\Etable{\endgraf\afterenvbreak} +\let\Eftable\Etable +\let\Evtable\Etable +\let\Eitemize\Etable +\let\Eenumerate\Etable + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\envdef\itemize{\parsearg\doitemize} + +\def\doitemize#1{% + \aboveenvbreak + \itemmax=\itemindent + \advance\itemmax by -\itemmargin + \advance\leftskip by \itemindent + \exdentamount=\itemindent + \parindent=0pt + \parskip=\smallskipamount + \ifdim\parskip=0pt \parskip=2pt \fi + \def\itemcontents{#1}% + % @itemize with no arg is equivalent to @itemize @bullet. + \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi + \let\item=\itemizeitem +} + +% Definition of @item while inside @itemize and @enumerate. +% +\def\itemizeitem{% + \advance\itemno by 1 % for enumerations + {\let\par=\endgraf \smallbreak}% reasonable place to break + {% + % If the document has an @itemize directly after a section title, a + % \nobreak will be last on the list, and \sectionheading will have + % done a \vskip-\parskip. In that case, we don't want to zero + % parskip, or the item text will crash with the heading. On the + % other hand, when there is normal text preceding the item (as there + % usually is), we do want to zero parskip, or there would be too much + % space. In that case, we won't have a \nobreak before. At least + % that's the theory. + \ifnum\lastpenalty<10000 \parskip=0in \fi + \noindent + \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% + \vadjust{\penalty 1200}}% not good to break after first line of item. + \flushcr +} + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\envparseargdef\enumerate{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call \doitemize, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \doitemize{#1.}\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab do not need to be on their own lines, but it will not hurt +% if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the @columnfraction, usually a decimal number like .5, but might +% be just 1. We just use it, whatever it is. +% +\def\pickupwholefraction#1 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a + % separator; typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable-only commands. +% +% @headitem starts a heading row, which we typeset in bold. +% Assignments have to be global since we are inside the implicit group +% of an alignment entry. Note that \everycr resets \everytab. +\def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}% +% +% A \tab used to include \hskip1sp. But then the space in a template +% line is not enough. That is bad. So let's go back to just `&' until +% we encounter the problem it was intended to solve again. +% --karl, nathan@acm.org, 20apr99. +\def\tab{\checkenv\multitable &\the\everytab}% + +% @multitable ... @end multitable definitions: +% +\newtoks\everytab % insert after every tab. +% +\envdef\multitable{% + \vskip\parskip + \startsavinginserts + % + % @item within a multitable starts a normal row. + % We use \def instead of \let so that if one of the multitable entries + % contains an @itemize, we don't choke on the \item (seen as \crcr aka + % \endtemplate) expanding \doitemize. + \def\item{\crcr}% + % + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + % + \everycr = {% + \noalign{% + \global\everytab={}% + \global\colcount=0 % Reset the column counter. + % Check for saved footnotes, etc. + \checkinserts + % Keeps underfull box messages off when table breaks over pages. + %\filbreak + % Maybe so, but it also creates really weird page breaks when the + % table breaks over pages. Wouldn't \vfil be better? Wait until the + % problem manifests itself, so it can be fixed for real --karl. + }% + }% + % + \parsearg\domultitable +} +\def\domultitable#1{% + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup &% + \global\advance\colcount by 1 + \multistrut + \vtop{% + % Use the current \colcount to find the correct column width: + \hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively + % marking characters. + \noindent\ignorespaces##\unskip\multistrut + }\cr +} +\def\Emultitable{% + \crcr + \egroup % end the \halign + \global\setpercentfalse +} + +\def\setmultitablespacing{% + \def\multistrut{\strut}% just use the standard line spacing + % + % Compute \multitablelinespace (if not defined by user) for use in + % \multitableparskip calculation. We used define \multistrut based on + % this, but (ironically) that caused the spacing to be off. + % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. +\ifdim\multitablelinespace=0pt +\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip +\global\advance\multitablelinespace by-\ht0 +\fi +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} + +% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, +% @ifnotxml always succeed. They currently do nothing; we don't +% attempt to check whether the conditionals are properly nested. But we +% have to remember that they are conditionals, so that @end doesn't +% attempt to close an environment group. +% +\def\makecond#1{% + \expandafter\let\csname #1\endcsname = \relax + \expandafter\let\csname iscond.#1\endcsname = 1 +} +\makecond{iftex} +\makecond{ifnotdocbook} +\makecond{ifnothtml} +\makecond{ifnotinfo} +\makecond{ifnotplaintext} +\makecond{ifnotxml} + +% Ignore @ignore, @ifhtml, @ifinfo, and the like. +% +\def\direntry{\doignore{direntry}} +\def\documentdescription{\doignore{documentdescription}} +\def\docbook{\doignore{docbook}} +\def\html{\doignore{html}} +\def\ifdocbook{\doignore{ifdocbook}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifinfo{\doignore{ifinfo}} +\def\ifnottex{\doignore{ifnottex}} +\def\ifplaintext{\doignore{ifplaintext}} +\def\ifxml{\doignore{ifxml}} +\def\ignore{\doignore{ignore}} +\def\menu{\doignore{menu}} +\def\xml{\doignore{xml}} + +% Ignore text until a line `@end #1', keeping track of nested conditionals. +% +% A count to remember the depth of nesting. +\newcount\doignorecount + +\def\doignore#1{\begingroup + % Scan in ``verbatim'' mode: + \obeylines + \catcode`\@ = \other + \catcode`\{ = \other + \catcode`\} = \other + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \spaceisspace + % + % Count number of #1's that we've seen. + \doignorecount = 0 + % + % Swallow text until we reach the matching `@end #1'. + \dodoignore{#1}% +} + +{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. + \obeylines % + % + \gdef\dodoignore#1{% + % #1 contains the command name as a string, e.g., `ifinfo'. + % + % Define a command to find the next `@end #1'. + \long\def\doignoretext##1^^M@end #1{% + \doignoretextyyy##1^^M@#1\_STOP_}% + % + % And this command to find another #1 command, at the beginning of a + % line. (Otherwise, we would consider a line `@c @ifset', for + % example, to count as an @ifset for nesting.) + \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% + % + % And now expand that command. + \doignoretext ^^M% + }% +} + +\def\doignoreyyy#1{% + \def\temp{#1}% + \ifx\temp\empty % Nothing found. + \let\next\doignoretextzzz + \else % Found a nested condition, ... + \advance\doignorecount by 1 + \let\next\doignoretextyyy % ..., look for another. + % If we're here, #1 ends with ^^M\ifinfo (for example). + \fi + \next #1% the token \_STOP_ is present just after this macro. +} + +% We have to swallow the remaining "\_STOP_". +% +\def\doignoretextzzz#1{% + \ifnum\doignorecount = 0 % We have just found the outermost @end. + \let\next\enddoignore + \else % Still inside a nested condition. + \advance\doignorecount by -1 + \let\next\doignoretext % Look for the next @end. + \fi + \next +} + +% Finish off ignored text. +{ \obeylines% + % Ignore anything after the last `@end #1'; this matters in verbatim + % environments, where otherwise the newline after an ignored conditional + % would result in a blank line in the output. + \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% +} + + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% We rely on the fact that \parsearg sets \catcode`\ =10. +% +\parseargdef\set{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + {% + \makevalueexpandable + \def\temp{#2}% + \edef\next{\gdef\makecsname{SET#1}}% + \ifx\temp\empty + \next{}% + \else + \setzzz#2\endsetzzz + \fi + }% +} +% Remove the trailing space \setxxx inserted. +\def\setzzz#1 \endsetzzz{\next{#1}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\parseargdef\clear{% + {% + \makevalueexpandable + \global\expandafter\let\csname SET#1\endcsname=\relax + }% +} + +% @value{foo} gets the text saved in variable foo. +\def\value{\begingroup\makevalueexpandable\valuexxx} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} +{ + \catcode`\- = \active \catcode`\_ = \active + % + \gdef\makevalueexpandable{% + \let\value = \expandablevalue + % We don't want these characters active, ... + \catcode`\-=\other \catcode`\_=\other + % ..., but we might end up with active ones in the argument if + % we're called from @code, as @code{@value{foo-bar_}}, though. + % So \let them to their normal equivalents. + \let-\realdash \let_\normalunderscore + } +} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we call \makevalueexpandable in \indexdummies). +% The command has to be fully expandable (if the variable is set), since +% the result winds up in the index file. This means that if the +% variable's value contains other Texinfo commands, it's almost certain +% it will fail (although perhaps we could fix that with sufficient work +% to do a one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \message{Variable `#1', used in @value, is not set.}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +% To get special treatment of `@end ifset,' call \makeond and the redefine. +% +\makecond{ifset} +\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} +\def\doifset#1#2{% + {% + \makevalueexpandable + \let\next=\empty + \expandafter\ifx\csname SET#2\endcsname\relax + #1% If not set, redefine \next. + \fi + \expandafter + }\next +} +\def\ifsetfail{\doignore{ifset}} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +% The `\else' inside the `\doifset' parameter is a trick to reuse the +% above code: if the variable is not set, do nothing, if it is set, +% then redefine \next to \ifclearfail. +% +\makecond{ifclear} +\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} +\def\ifclearfail{\doignore{ifclear}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory=\comment + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within macros and \if's. +\edef\newwrite{\makecsname{ptexnewwrite}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} +% +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. +% +\def\defcodeindex{\parsearg\newcodeindex} +% +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}}% +} + + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +% +\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} +\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} + +% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), +% #3 the target index (bar). +\def\dosynindex#1#2#3{% + % Only do \closeout if we haven't already done it, else we'll end up + % closing the target index. + \expandafter \ifx\csname donesynindex#2\endcsname \undefined + % The \closeout helps reduce unnecessary open files; the limit on the + % Acorn RISC OS is a mere 16 files. + \expandafter\closeout\csname#2indfile\endcsname + \expandafter\let\csname\donesynindex#2\endcsname = 1 + \fi + % redefine \fooindfile: + \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname + \expandafter\let\csname#2indfile\endcsname=\temp + % redefine \fooindex: + \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +% Take care of Texinfo commands that can appear in an index entry. +% Since there are some commands we want to expand, and others we don't, +% we have to laboriously prevent expansion for those that we don't. +% +\def\indexdummies{% + \escapechar = `\\ % use backslash in output files. + \def\@{@}% change to @@ when we switch to @ as escape char in index files. + \def\ {\realbackslash\space }% + % + % Need these in case \tex is in effect and \{ is a \delimiter again. + % But can't use \lbracecmd and \rbracecmd because texindex assumes + % braces and backslashes are used only as delimiters. + \let\{ = \mylbrace + \let\} = \myrbrace + % + % I don't entirely understand this, but when an index entry is + % generated from a macro call, the \endinput which \scanmacro inserts + % causes processing to be prematurely terminated. This is, + % apparently, because \indexsorttmp is fully expanded, and \endinput + % is an expandable command. The redefinition below makes \endinput + % disappear altogether for that purpose -- although logging shows that + % processing continues to some further point. On the other hand, it + % seems \endinput does not hurt in the printed index arg, since that + % is still getting written without apparent harm. + % + % Sample source (mac-idx3.tex, reported by Graham Percival to + % help-texinfo, 22may06): + % @macro funindex {WORD} + % @findex xyz + % @end macro + % ... + % @funindex commtest + % + % The above is not enough to reproduce the bug, but it gives the flavor. + % + % Sample whatsit resulting: + % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} + % + % So: + \let\endinput = \empty + % + % Do the redefinitions. + \commondummies +} + +% For the aux and toc files, @ is the escape character. So we want to +% redefine everything using @ as the escape character (instead of +% \realbackslash, still used for index files). When everything uses @, +% this will be simpler. +% +\def\atdummies{% + \def\@{@@}% + \def\ {@ }% + \let\{ = \lbraceatcmd + \let\} = \rbraceatcmd + % + % Do the redefinitions. + \commondummies + \otherbackslash +} + +% Called from \indexdummies and \atdummies. +% +\def\commondummies{% + % + % \definedummyword defines \#1 as \string\#1\space, thus effectively + % preventing its expansion. This is used only for control% words, + % not control letters, because the \space would be incorrect for + % control characters, but is needed to separate the control word + % from whatever follows. + % + % For control letters, we have \definedummyletter, which omits the + % space. + % + % These can be used both for control words that take an argument and + % those that do not. If it is followed by {arg} in the input, then + % that will dutifully get written to the index (or wherever). + % + \def\definedummyword ##1{\def##1{\string##1\space}}% + \def\definedummyletter##1{\def##1{\string##1}}% + \let\definedummyaccent\definedummyletter + % + \commondummiesnofonts + % + \definedummyletter\_% + % + % Non-English letters. + \definedummyword\AA + \definedummyword\AE + \definedummyword\L + \definedummyword\OE + \definedummyword\O + \definedummyword\aa + \definedummyword\ae + \definedummyword\l + \definedummyword\oe + \definedummyword\o + \definedummyword\ss + \definedummyword\exclamdown + \definedummyword\questiondown + \definedummyword\ordf + \definedummyword\ordm + % + % Although these internal commands shouldn't show up, sometimes they do. + \definedummyword\bf + \definedummyword\gtr + \definedummyword\hat + \definedummyword\less + \definedummyword\sf + \definedummyword\sl + \definedummyword\tclose + \definedummyword\tt + % + \definedummyword\LaTeX + \definedummyword\TeX + % + % Assorted special characters. + \definedummyword\bullet + \definedummyword\comma + \definedummyword\copyright + \definedummyword\registeredsymbol + \definedummyword\dots + \definedummyword\enddots + \definedummyword\equiv + \definedummyword\error + \definedummyword\euro + \definedummyword\expansion + \definedummyword\minus + \definedummyword\pounds + \definedummyword\point + \definedummyword\print + \definedummyword\result + \definedummyword\textdegree + % + % We want to disable all macros so that they are not expanded by \write. + \macrolist + % + \normalturnoffactive + % + % Handle some cases of @value -- where it does not contain any + % (non-fully-expandable) commands. + \makevalueexpandable +} + +% \commondummiesnofonts: common to \commondummies and \indexnofonts. +% +\def\commondummiesnofonts{% + % Control letters and accents. + \definedummyletter\!% + \definedummyaccent\"% + \definedummyaccent\'% + \definedummyletter\*% + \definedummyaccent\,% + \definedummyletter\.% + \definedummyletter\/% + \definedummyletter\:% + \definedummyaccent\=% + \definedummyletter\?% + \definedummyaccent\^% + \definedummyaccent\`% + \definedummyaccent\~% + \definedummyword\u + \definedummyword\v + \definedummyword\H + \definedummyword\dotaccent + \definedummyword\ringaccent + \definedummyword\tieaccent + \definedummyword\ubaraccent + \definedummyword\udotaccent + \definedummyword\dotless + % + % Texinfo font commands. + \definedummyword\b + \definedummyword\i + \definedummyword\r + \definedummyword\sc + \definedummyword\t + % + % Commands that take arguments. + \definedummyword\acronym + \definedummyword\cite + \definedummyword\code + \definedummyword\command + \definedummyword\dfn + \definedummyword\emph + \definedummyword\env + \definedummyword\file + \definedummyword\kbd + \definedummyword\key + \definedummyword\math + \definedummyword\option + \definedummyword\pxref + \definedummyword\ref + \definedummyword\samp + \definedummyword\strong + \definedummyword\tie + \definedummyword\uref + \definedummyword\url + \definedummyword\var + \definedummyword\verb + \definedummyword\w + \definedummyword\xref +} + +% \indexnofonts is used when outputting the strings to sort the index +% by, and when constructing control sequence names. It eliminates all +% control sequences and just writes whatever the best ASCII sort string +% would be for a given command (usually its argument). +% +\def\indexnofonts{% + % Accent commands should become @asis. + \def\definedummyaccent##1{\let##1\asis}% + % We can just ignore other control letters. + \def\definedummyletter##1{\let##1\empty}% + % Hopefully, all control words can become @asis. + \let\definedummyword\definedummyaccent + % + \commondummiesnofonts + % + % Don't no-op \tt, since it isn't a user-level command + % and is used in the definitions of the active chars like <, >, |, etc. + % Likewise with the other plain tex font commands. + %\let\tt=\asis + % + \def\ { }% + \def\@{@}% + % how to handle braces? + \def\_{\normalunderscore}% + % + % Non-English letters. + \def\AA{AA}% + \def\AE{AE}% + \def\L{L}% + \def\OE{OE}% + \def\O{O}% + \def\aa{aa}% + \def\ae{ae}% + \def\l{l}% + \def\oe{oe}% + \def\o{o}% + \def\ss{ss}% + \def\exclamdown{!}% + \def\questiondown{?}% + \def\ordf{a}% + \def\ordm{o}% + % + \def\LaTeX{LaTeX}% + \def\TeX{TeX}% + % + % Assorted special characters. + % (The following {} will end up in the sort string, but that's ok.) + \def\bullet{bullet}% + \def\comma{,}% + \def\copyright{copyright}% + \def\registeredsymbol{R}% + \def\dots{...}% + \def\enddots{...}% + \def\equiv{==}% + \def\error{error}% + \def\euro{euro}% + \def\expansion{==>}% + \def\minus{-}% + \def\pounds{pounds}% + \def\point{.}% + \def\print{-|}% + \def\result{=>}% + \def\textdegree{degrees}% + % + % We need to get rid of all macros, leaving only the arguments (if present). + % Of course this is not nearly correct, but it is the best we can do for now. + % makeinfo does not expand macros in the argument to @deffn, which ends up + % writing an index entry, and texindex isn't prepared for an index sort entry + % that starts with \. + % + % Since macro invocations are followed by braces, we can just redefine them + % to take a single TeX argument. The case of a macro invocation that + % goes to end-of-line is not handled. + % + \macrolist +} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% Most index entries go through here, but \dosubind is the general case. +% #1 is the index name, #2 is the entry text. +\def\doind#1#2{\dosubind{#1}{#2}{}} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% empty if called from \doind, as we usually are (the main exception +% is with most defuns, which call us directly). +% +\def\dosubind#1#2#3{% + \iflinks + {% + % Store the main index entry text (including the third arg). + \toks0 = {#2}% + % If third arg is present, precede it with a space. + \def\thirdarg{#3}% + \ifx\thirdarg\empty \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + \edef\writeto{\csname#1indfile\endcsname}% + % + \safewhatsit\dosubindwrite + }% + \fi +} + +% Write the entry in \toks0 to the index file: +% +\def\dosubindwrite{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% + \fi + % + % Remember, we are within a group. + \indexdummies % Must do this here, since \bf, etc expand at this stage + \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % Process the index entry with all font commands turned off, to + % get the string to sort by. + {\indexnofonts + \edef\temp{\the\toks0}% need full expansion + \xdef\indexsorttmp{\temp}% + }% + % + % Set up the complete index entry, with both the sort key and + % the original text, including any font commands. We write + % three arguments to \entry to the .?? file (four in the + % subentry case), texindex reduces to two when writing the .??s + % sorted result. + \edef\temp{% + \write\writeto{% + \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% + }% + \temp +} + +% Take care of unwanted page breaks/skips around a whatsit: +% +% If a skip is the last thing on the list now, preserve it +% by backing up by \lastskip, doing the \write, then inserting +% the skip again. Otherwise, the whatsit generated by the +% \write or \pdfdest will make \lastskip zero. The result is that +% sequences like this: +% @end defun +% @tindex whatever +% @defun ... +% will have extra space inserted, because the \medbreak in the +% start of the @defun won't see the skip inserted by the @end of +% the previous defun. +% +% But don't do any of this if we're not in vertical mode. We +% don't want to do a \vskip and prematurely end a paragraph. +% +% Avoid page breaks due to these extra skips, too. +% +% But wait, there is a catch there: +% We'll have to check whether \lastskip is zero skip. \ifdim is not +% sufficient for this purpose, as it ignores stretch and shrink parts +% of the skip. The only way seems to be to check the textual +% representation of the skip. +% +% The following is almost like \def\zeroskipmacro{0.0pt} except that +% the ``p'' and ``t'' characters have catcode \other, not 11 (letter). +% +\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} +% +\newskip\whatsitskip +\newcount\whatsitpenalty +% +% ..., ready, GO: +% +\def\safewhatsit#1{% +\ifhmode + #1% +\else + % \lastskip and \lastpenalty cannot both be nonzero simultaneously. + \whatsitskip = \lastskip + \edef\lastskipmacro{\the\lastskip}% + \whatsitpenalty = \lastpenalty + % + % If \lastskip is nonzero, that means the last item was a + % skip. And since a skip is discardable, that means this + % -\skip0 glue we're inserting is preceded by a + % non-discardable item, therefore it is not a potential + % breakpoint, therefore no \nobreak needed. + \ifx\lastskipmacro\zeroskipmacro + \else + \vskip-\whatsitskip + \fi + % + #1% + % + \ifx\lastskipmacro\zeroskipmacro + % If \lastskip was zero, perhaps the last item was a penalty, and + % perhaps it was >=10000, e.g., a \nobreak. In that case, we want + % to re-insert the same penalty (values >10000 are used for various + % signals); since we just inserted a non-discardable item, any + % following glue (such as a \parskip) would be a breakpoint. For example: + % + % @deffn deffn-whatever + % @vindex index-whatever + % Description. + % would allow a break between the index-whatever whatsit + % and the "Description." paragraph. + \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi + \else + % On the other hand, if we had a nonzero \lastskip, + % this make-up glue would be preceded by a non-discardable item + % (the whatsit from the \write), so we must insert a \nobreak. + \nobreak\vskip\whatsitskip + \fi +\fi +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\parseargdef\printindex{\begingroup + \dobreak \chapheadingskip{10000}% + % + \smallfonts \rm + \tolerance = 9500 + \plainfrenchspacing + \everypar = {}% don't want the \kern\-parindent from indentation suppression. + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\backslashcurfont}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \nobreak + \vskip 0pt plus 3\baselineskip + \penalty 0 + \vskip 0pt plus -3\baselineskip + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + % Do our best not to break after the initial. + \nobreak + \vskip .33\baselineskip plus .1\baselineskip +}} + +% \entry typesets a paragraph consisting of the text (#1), dot leaders, and +% then page number (#2) flushed to the right margin. It is used for index +% and table of contents entries. The paragraph is indented by \leftskip. +% +% A straightforward implementation would start like this: +% \def\entry#1#2{... +% But this frozes the catcodes in the argument, and can cause problems to +% @code, which sets - active. This problem was fixed by a kludge--- +% ``-'' was active throughout whole index, but this isn't really right. +% +% The right solution is to prevent \entry from swallowing the whole text. +% --kasal, 21nov03 +\def\entry{% + \begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing + % columns. + \vskip 0pt plus1pt + % + % Swallow the left brace of the text (first parameter): + \afterassignment\doentry + \let\temp = +} +\def\doentry{% + \bgroup % Instead of the swallowed brace. + \noindent + \aftergroup\finishentry + % And now comes the text of the entry. +} +\def\finishentry#1{% + % #1 is the page number. + % + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#1}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd + \ % + \else + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ifpdf + \pdfgettoks#1.% + \ \the\toksA + \else + \ #1% + \fi + \fi + \par + \endgroup +} + +% Like plain.tex's \dotfill, except uses up at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm +\def\secondary#1#2{{% + \parfillskip=0in + \parskip=0in + \hangindent=1in + \hangafter=1 + \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + #2 + \fi + \par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + \advance\dimen@ by -\ht\partialpage + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +% +% Re-output the contents of the output page -- any previous material, +% followed by the two boxes we just split, in box0 and box2. +\def\pagesofar{% + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +% +% All done with double columns. +\def\enddoublecolumns{% + % The following penalty ensures that the page builder is exercised + % _before_ we change the output routine. This is necessary in the + % following situation: + % + % The last section of the index consists only of a single entry. + % Before this section, \pagetotal is less than \pagegoal, so no + % break occurs before the last section starts. However, the last + % section, consisting of \initial and the single \entry, does not + % fit on the page and has to be broken off. Without the following + % penalty the page builder will not be exercised until \eject + % below, and by that time we'll already have changed the output + % routine to the \balancecolumns version, so the next-to-last + % double-column page will be processed with \balancecolumns, which + % is wrong: The two columns will go to the main vertical list, with + % the broken-off section in the recent contributions. As soon as + % the output routine finishes, TeX starts reconsidering the page + % break. The two columns and the broken-off section both fit on the + % page, because the two columns now take up only half of the page + % goal. When TeX sees \eject from below which follows the final + % section, it invokes the new output routine that we've set after + % \balancecolumns below; \onepageout will try to fit the two columns + % and the final section into the vbox of \pageheight (see + % \pagebody), causing an overfull box. + % + % Note that glue won't work here, because glue does not exercise the + % page builder, unlike penalties (see The TeXbook, pp. 280-281). + \penalty0 + % + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +% +% Called at the end of the double column material. +\def\balancecolumns{% + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +% \unnumberedno is an oxymoron, of course. But we count the unnumbered +% sections so that we can refer to them unambiguously in the pdf +% outlines by their "section number". We avoid collisions with chapter +% numbers by starting them at 10000. (If a document ever has 10000 +% chapters, we're in trouble anyway, I'm sure.) +\newcount\unnumberedno \unnumberedno = 10000 +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +% +% \def\appendixletter{\char\the\appendixno} +% We do the following ugly conditional instead of the above simple +% construct for the sake of pdftex, which needs the actual +% letter in the expansion, not just typeset. +% +\def\appendixletter{% + \ifnum\appendixno=`A A% + \else\ifnum\appendixno=`B B% + \else\ifnum\appendixno=`C C% + \else\ifnum\appendixno=`D D% + \else\ifnum\appendixno=`E E% + \else\ifnum\appendixno=`F F% + \else\ifnum\appendixno=`G G% + \else\ifnum\appendixno=`H H% + \else\ifnum\appendixno=`I I% + \else\ifnum\appendixno=`J J% + \else\ifnum\appendixno=`K K% + \else\ifnum\appendixno=`L L% + \else\ifnum\appendixno=`M M% + \else\ifnum\appendixno=`N N% + \else\ifnum\appendixno=`O O% + \else\ifnum\appendixno=`P P% + \else\ifnum\appendixno=`Q Q% + \else\ifnum\appendixno=`R R% + \else\ifnum\appendixno=`S S% + \else\ifnum\appendixno=`T T% + \else\ifnum\appendixno=`U U% + \else\ifnum\appendixno=`V V% + \else\ifnum\appendixno=`W W% + \else\ifnum\appendixno=`X X% + \else\ifnum\appendixno=`Y Y% + \else\ifnum\appendixno=`Z Z% + % The \the is necessary, despite appearances, because \appendixletter is + % expanded while writing the .toc file. \char\appendixno is not + % expandable, thus it is written literally, thus all appendixes come out + % with the same letter (or @) in the toc without it. + \else\char\the\appendixno + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +% However, they are not reliable, because we don't use marks. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% we only have subsub. +\chardef\maxseclevel = 3 +% +% A numbered section within an unnumbered changes to unnumbered too. +% To achive this, remember the "biggest" unnum. sec. we are currently in: +\chardef\unmlevel = \maxseclevel +% +% Trace whether the current chapter is an appendix or not: +% \chapheadtype is "N" or "A", unnumbered chapters are ignored. +\def\chapheadtype{N} + +% Choose a heading macro +% #1 is heading type +% #2 is heading level +% #3 is text for heading +\def\genhead#1#2#3{% + % Compute the abs. sec. level: + \absseclevel=#2 + \advance\absseclevel by \secbase + % Make sure \absseclevel doesn't fall outside the range: + \ifnum \absseclevel < 0 + \absseclevel = 0 + \else + \ifnum \absseclevel > 3 + \absseclevel = 3 + \fi + \fi + % The heading type: + \def\headtype{#1}% + \if \headtype U% + \ifnum \absseclevel < \unmlevel + \chardef\unmlevel = \absseclevel + \fi + \else + % Check for appendix sections: + \ifnum \absseclevel = 0 + \edef\chapheadtype{\headtype}% + \else + \if \headtype A\if \chapheadtype N% + \errmessage{@appendix... within a non-appendix chapter}% + \fi\fi + \fi + % Check for numbered within unnumbered: + \ifnum \absseclevel > \unmlevel + \def\headtype{U}% + \else + \chardef\unmlevel = 3 + \fi + \fi + % Now print the heading: + \if \headtype U% + \ifcase\absseclevel + \unnumberedzzz{#3}% + \or \unnumberedseczzz{#3}% + \or \unnumberedsubseczzz{#3}% + \or \unnumberedsubsubseczzz{#3}% + \fi + \else + \if \headtype A% + \ifcase\absseclevel + \appendixzzz{#3}% + \or \appendixsectionzzz{#3}% + \or \appendixsubseczzz{#3}% + \or \appendixsubsubseczzz{#3}% + \fi + \else + \ifcase\absseclevel + \chapterzzz{#3}% + \or \seczzz{#3}% + \or \numberedsubseczzz{#3}% + \or \numberedsubsubseczzz{#3}% + \fi + \fi + \fi + \suppressfirstparagraphindent +} + +% an interface: +\def\numhead{\genhead N} +\def\apphead{\genhead A} +\def\unnmhead{\genhead U} + +% @chapter, @appendix, @unnumbered. Increment top-level counter, reset +% all lower-level sectioning counters to zero. +% +% Also set \chaplevelprefix, which we prepend to @float sequence numbers +% (e.g., figures), q.v. By default (before any chapter), that is empty. +\let\chaplevelprefix = \empty +% +\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz#1{% + % section resetting is \global in case the chapter is in a group, such + % as an @include file. + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\chapno by 1 + % + % Used for \float. + \gdef\chaplevelprefix{\the\chapno.}% + \resetallfloatnos + % + \message{\putwordChapter\space \the\chapno}% + % + % Write the actual heading. + \chapmacro{#1}{Ynumbered}{\the\chapno}% + % + % So @section and the like are numbered underneath this chapter. + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec +} + +\outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\appendixno by 1 + \gdef\chaplevelprefix{\appendixletter.}% + \resetallfloatnos + % + \def\appendixnum{\putwordAppendix\space \appendixletter}% + \message{\appendixnum}% + % + \chapmacro{#1}{Yappendix}{\appendixletter}% + % + \global\let\section = \appendixsec + \global\let\subsection = \appendixsubsec + \global\let\subsubsection = \appendixsubsubsec +} + +\outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\unnumberedno by 1 + % + % Since an unnumbered has no number, no prefix for figures. + \global\let\chaplevelprefix = \empty + \resetallfloatnos + % + % This used to be simply \message{#1}, but TeX fully expands the + % argument to \message. Therefore, if #1 contained @-commands, TeX + % expanded them. For example, in `@unnumbered The @cite{Book}', TeX + % expanded @cite (which turns out to cause errors because \cite is meant + % to be executed, not expanded). + % + % Anyway, we don't want the fully-expanded definition of @cite to appear + % as a result of the \message, we just want `@cite' itself. We use + % \the to achieve this: TeX expands \the only once, + % simply yielding the contents of . (We also do this for + % the toc entries.) + \toks0 = {#1}% + \message{(\the\toks0)}% + % + \chapmacro{#1}{Ynothing}{\the\unnumberedno}% + % + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\parseargdef\centerchap{% + % Well, we could do the following in a group, but that would break + % an assumption that \chapmacro is called at the outermost level. + % Thus we are safer this way: --kasal, 24feb04 + \let\centerparametersmaybe = \centerparameters + \unnmhead0{#1}% + \let\centerparametersmaybe = \relax +} + +% @top is like @unnumbered. +\let\top\unnumbered + +% Sections. +\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz +\def\seczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% +} + +\outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% +} +\let\appendixsec\appendixsection + +\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% +} + +% Subsections. +\outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno}% +} + +% Subsubsections. +\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynumbered}% + {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\let\section = \numberedsec +\let\subsection = \numberedsubsec +\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{% + {\advance\chapheadingskip by 10pt \chapbreak }% + \parsearg\chapheadingzzz +} + +\def\chapheading{\chapbreak \parsearg\chapheadingzzz} +\def\chapheadingzzz#1{% + {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% + \bigskip \par\penalty 200\relax + \suppressfirstparagraphindent +} + +% @heading, @subheading, @subsubheading. +\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{% +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +% Chapter opening. +% +% #1 is the text, #2 is the section type (Ynumbered, Ynothing, +% Yappendix, Yomitfromtoc), #3 the chapter number. +% +% To test against our argument. +\def\Ynothingkeyword{Ynothing} +\def\Yomitfromtockeyword{Yomitfromtoc} +\def\Yappendixkeyword{Yappendix} +% +\def\chapmacro#1#2#3{% + \pchapsepmacro + {% + \chapfonts \rm + % + % Have to define \thissection before calling \donoderef, because the + % xref code eventually uses it. On the other hand, it has to be called + % after \pchapsepmacro, or the headline will change too soon. + \gdef\thissection{#1}% + \gdef\thischaptername{#1}% + % + % Only insert the separating space if we have a chapter/appendix + % number, and don't print the unnumbered ``number''. + \def\temptype{#2}% + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unnchap}% + \gdef\thischapternum{}% + \gdef\thischapter{#1}% + \else\ifx\temptype\Yomitfromtockeyword + \setbox0 = \hbox{}% contents like unnumbered, but no toc entry + \def\toctype{omit}% + \gdef\thischapternum{}% + \gdef\thischapter{}% + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% + \def\toctype{app}% + \xdef\thischapternum{\appendixletter}% + % We don't substitute the actual chapter name into \thischapter + % because we don't want its macros evaluated now. And we don't + % use \thissection because that changes with each section. + % + \xdef\thischapter{\putwordAppendix{} \appendixletter: + \noexpand\thischaptername}% + \else + \setbox0 = \hbox{#3\enspace}% + \def\toctype{numchap}% + \xdef\thischapternum{\the\chapno}% + \xdef\thischapter{\putwordChapter{} \the\chapno: + \noexpand\thischaptername}% + \fi\fi\fi + % + % Write the toc entry for this chapter. Must come before the + % \donoderef, because we include the current node name in the toc + % entry, and \donoderef resets it to empty. + \writetocentry{\toctype}{#1}{#3}% + % + % For pdftex, we have to write out the node definition (aka, make + % the pdfdest) after any page break, but before the actual text has + % been typeset. If the destination for the pdf outline is after the + % text, then jumping from the outline may wind up with the text not + % being visible, for instance under high magnification. + \donoderef{#2}% + % + % Typeset the actual heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent=\wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerparameters{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt +} + + +% I don't think this chapter style is supported any more, so I'm not +% updating it with the new noderef stuff. We'll see. --karl, 11aug03. +% +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} +% +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} +\def\CHAPFopen{% + \global\let\chapmacro=\chfopen + \global\let\centerchapmacro=\centerchfopen} + + +% Section titles. These macros combine the section number parts and +% call the generic \sectionheading to do the printing. +% +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip{-1000}} + +% Subsection titles. +\newskip\subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} + +% Subsubsection titles. +\def\subsubsecheadingskip{\subsecheadingskip} +\def\subsubsecheadingbreak{\subsecheadingbreak} + + +% Print any size, any type, section title. +% +% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is +% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the +% section number. +% +\def\sectionheading#1#2#3#4{% + {% + % Switch to the right set of fonts. + \csname #2fonts\endcsname \rm + % + % Insert space above the heading. + \csname #2headingbreak\endcsname + % + % Only insert the space after the number if we have a section number. + \def\sectionlevel{#2}% + \def\temptype{#3}% + % + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unn}% + \gdef\thissection{#1}% + \else\ifx\temptype\Yomitfromtockeyword + % for @headings -- no section number, don't include in toc, + % and don't redefine \thissection. + \setbox0 = \hbox{}% + \def\toctype{omit}% + \let\sectionlevel=\empty + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{#4\enspace}% + \def\toctype{app}% + \gdef\thissection{#1}% + \else + \setbox0 = \hbox{#4\enspace}% + \def\toctype{num}% + \gdef\thissection{#1}% + \fi\fi\fi + % + % Write the toc entry (before \donoderef). See comments in \chapmacro. + \writetocentry{\toctype\sectionlevel}{#1}{#4}% + % + % Write the node reference (= pdf destination for pdftex). + % Again, see comments in \chapmacro. + \donoderef{#3}% + % + % Interline glue will be inserted when the vbox is completed. + % That glue will be a valid breakpoint for the page, since it'll be + % preceded by a whatsit (usually from the \donoderef, or from the + % \writetocentry if there was no node). We don't want to allow that + % break, since then the whatsits could end up on page n while the + % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. + \nobreak + % + % Output the actual section heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent=\wd0 % zero if no section number + \unhbox0 #1}% + }% + % Add extra space after the heading -- half of whatever came above it. + % Don't allow stretch, though. + \kern .5 \csname #2headingskip\endcsname + % + % Do not let the kern be a potential breakpoint, as it would be if it + % was followed by glue. + \nobreak + % + % We'll almost certainly start a paragraph next, so don't let that + % glue accumulate. (Not a breakpoint because it's preceded by a + % discardable item.) + \vskip-\parskip + % + % This is purely so the last item on the list is a known \penalty > + % 10000. This is so \startdefun can avoid allowing breakpoints after + % section headings. Otherwise, it would insert a valid breakpoint between: + % + % @section sec-whatever + % @deffn def-whatever + \penalty 10001 +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. +% +% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} +% We append the current node name (if any) and page number as additional +% arguments for the \{chap,sec,...}entry macros which will eventually +% read this. The node name is used in the pdf outlines as the +% destination to jump to. +% +% We open the .toc file for writing here instead of at @setfilename (or +% any other fixed time) so that @contents can be anywhere in the document. +% But if #1 is `omit', then we don't do anything. This is used for the +% table of contents chapter openings themselves. +% +\newif\iftocfileopened +\def\omitkeyword{omit}% +% +\def\writetocentry#1#2#3{% + \edef\writetoctype{#1}% + \ifx\writetoctype\omitkeyword \else + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + % + \iflinks + {\atdummies + \edef\temp{% + \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% + \temp + }% + \fi + \fi + % + % Tell \shipout to create a pdf destination on each page, if we're + % writing pdf. These are used in the table of contents. We can't + % just write one on every page because the title pages are numbered + % 1 and 2 (the page numbers aren't printed), and so are the first + % two pages of the document. Thus, we'd have two destinations named + % `1', and two named `2'. + \ifpdf \global\pdfmakepagedesttrue \fi +} + + +% These characters do not print properly in the Computer Modern roman +% fonts, so we must take special care. This is more or less redundant +% with the Texinfo input format setup at the end of this file. +% +\def\activecatcodes{% + \catcode`\"=\active + \catcode`\$=\active + \catcode`\<=\active + \catcode`\>=\active + \catcode`\\=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\|=\active + \catcode`\~=\active +} + + +% Read the toc file, which is essentially Texinfo input. +\def\readtocfile{% + \setupdatafile + \activecatcodes + \input \jobname.toc +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Prepare to read what we've written to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \def\thischapter{}% + \chapmacro{#1}{Yomitfromtoc}{}% + % + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \jobname.toc + \ifeof 1 \else + \readtocfile + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \ifeof 1 \else + \pdfmakeoutlines + \fi + \closein 1 + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\numchapentry = \shortchapentry + \let\appentry = \shortchapentry + \let\unnchapentry = \shortunnchapentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf + \let\sl=\shortcontsl \let\tt=\shortconttt + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\numsecentry##1##2##3##4{} + \let\appsecentry = \numsecentry + \let\unnsecentry = \numsecentry + \let\numsubsecentry = \numsecentry + \let\appsubsecentry = \numsecentry + \let\unnsubsecentry = \numsecentry + \let\numsubsubsecentry = \numsecentry + \let\appsubsubsecentry = \numsecentry + \let\unnsubsubsecentry = \numsecentry + \openin 1 \jobname.toc + \ifeof 1 \else + \readtocfile + \fi + \closein 1 + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g., `A' for an appendix, or `3' for a chapter. +% +\def\shortchaplabel#1{% + % This space should be enough, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % But use \hss just in case. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + % + % We'd like to right-justify chapter numbers, but that looks strange + % with appendix letters. And right-justifying numbers and + % left-justifying letters looks strange when there is less than 10 + % chapters. Have to read the whole toc once to know how many chapters + % there are before deciding ... + \hbox to 1em{#1\hss}% +} + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapters, in the main contents. +\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} +% +% Chapters, in the short toc. +% See comments in \dochapentry re vbox and related settings. +\def\shortchapentry#1#2#3#4{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% +} + +% Appendices, in the main contents. +% Need the word Appendix, and a fixed-size box. +% +\def\appendixbox#1{% + % We use M since it's probably the widest letter. + \setbox0 = \hbox{\putwordAppendix{} M}% + \hbox to \wd0{\putwordAppendix{} #1\hss}} +% +\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} + +% Unnumbered chapters. +\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} +\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} + +% Sections. +\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} +\let\appsecentry=\numsecentry +\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} + +% Subsections. +\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} +\let\appsubsecentry=\numsubsecentry +\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} + +% And subsubsections. +\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} +\let\appsubsubsecentry=\numsubsubsecentry +\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} + +% This parameter controls the indentation of the various levels. +% Same as \defaultparindent. +\newdimen\tocindent \tocindent = 15pt + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% We use the same \entry macro as for the index entries. +\let\tocentry = \entry + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\def\subsecentryfonts{\textfonts} +\def\subsubsecentryfonts{\textfonts} + + +\message{environments,} +% @foo ... @end foo. + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +% +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% The @error{} command. +% Adapted from the TeXbook's \boxit. +% +\newbox\errorbox +% +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \reducedsf error\kern-1.5pt} +% +\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{% + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} +% +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\envdef\tex{% + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie + \catcode `\%=14 + \catcode `\+=\other + \catcode `\"=\other + \catcode `\|=\other + \catcode `\<=\other + \catcode `\>=\other + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\/=\ptexslash + \let\*=\ptexstar + \let\t=\ptext + \let\frenchspacing=\plainfrenchspacing + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +} +% There is no need to define \Etex. + +% Define @lisp ... @end lisp. +% @lisp environment forms a group so it can rebind things, +% including the definition of @end lisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip. +% +\def\aboveenvbreak{{% + % =10000 instead of <10000 because of a special case in \itemzzz and + % \sectionheading, q.v. + \ifnum \lastpenalty=10000 \else + \advance\envskipamount by \parskip + \endgraf + \ifdim\lastskip<\envskipamount + \removelastskip + % it's not a good place to break if the last penalty was \nobreak + % or better ... + \ifnum\lastpenalty<10000 \penalty-50 \fi + \vskip\envskipamount + \fi + \fi +}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will +% also clear it, so that its embedded environments do the narrowing again. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\envdef\cartouche{% + \ifhmode\par\fi % can't be in the midst of a paragraph. + \startsavinginserts + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt % we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either + % side, and for 6pt waste from + % each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing = t% + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \kern3pt + \hsize=\cartinner + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip + \comment % For explanation, see the end of \def\group. +} +\def\Ecartouche{% + \ifhmode\par\fi + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup + \checkinserts +} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \let\exdent=\nofillexdent +} + +% If you want all examples etc. small: @set dispenvsize small. +% If you want even small examples the full size: @set dispenvsize nosmall. +% This affects the following displayed environments: +% @example, @display, @format, @lisp +% +\def\smallword{small} +\def\nosmallword{nosmall} +\let\SETdispenvsize\relax +\def\setnormaldispenv{% + \ifx\SETdispenvsize\smallword + % end paragraph for sake of leading, in case document has no blank + % line. This is redundant with what happens in \aboveenvbreak, but + % we need to do it before changing the fonts, and it's inconvenient + % to change the fonts afterward. + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} +\def\setsmalldispenv{% + \ifx\SETdispenvsize\nosmallword + \else + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} + +% We often define two environments, @foo and @smallfoo. +% Let's do it by one command: +\def\makedispenv #1#2{ + \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} + \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} + \expandafter\let\csname E#1\endcsname \afterenvbreak + \expandafter\let\csname Esmall#1\endcsname \afterenvbreak +} + +% Define two synonyms: +\def\maketwodispenvs #1#2#3{ + \makedispenv{#1}{#3} + \makedispenv{#2}{#3} +} + +% @lisp: indented, narrowed, typewriter font; @example: same as @lisp. +% +% @smallexample and @smalllisp: use smaller fonts. +% Originally contributed by Pavel@xerox. +% +\maketwodispenvs {lisp}{example}{% + \nonfillstart + \tt\quoteexpand + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} +% @display/@smalldisplay: same as @lisp except keep current font. +% +\makedispenv {display}{% + \nonfillstart + \gobble +} + +% @format/@smallformat: same as @display except don't narrow margins. +% +\makedispenv{format}{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} + +% @flushleft: same as @format, but doesn't obey \SETdispenvsize. +\envdef\flushleft{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} +\let\Eflushleft = \afterenvbreak + +% @flushright. +% +\envdef\flushright{% + \let\nonarrowing = t% + \nonfillstart + \advance\leftskip by 0pt plus 1fill + \gobble +} +\let\Eflushright = \afterenvbreak + + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. We keep \parskip nonzero in general, since +% we're doing normal filling. So, when using \aboveenvbreak and +% \afterenvbreak, temporarily make \parskip 0. +% +\envdef\quotation{% + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \parindent=0pt + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \parsearg\quotationlabel +} + +% We have retained a nonzero parskip for the environment, since we're +% doing normal filling. +% +\def\Equotation{% + \par + \ifx\quotationauthor\undefined\else + % indent a bit. + \leftline{\kern 2\leftskip \sl ---\quotationauthor}% + \fi + {\parskip=0pt \afterenvbreak}% +} + +% If we're given an argument, typeset it in bold with a colon after. +\def\quotationlabel#1{% + \def\temp{#1}% + \ifx\temp\empty \else + {\bf #1: }% + \fi +} + + +% LaTeX-like @verbatim...@end verbatim and @verb{...} +% If we want to allow any as delimiter, +% we need the curly braces so that makeinfo sees the @verb command, eg: +% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org +% +% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. +% +% [Knuth] p.344; only we need to do the other characters Texinfo sets +% active too. Otherwise, they get lost as the first character on a +% verbatim line. +\def\dospecials{% + \do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% + \do\<\do\>\do\|\do\@\do+\do\"% +} +% +% [Knuth] p. 380 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1=\other}\dospecials} +% +% [Knuth] pp. 380,381,391 +% Disable Spanish ligatures ?` and !` of \tt font +\begingroup + \catcode`\`=\active\gdef`{\relax\lq} +\endgroup +% +% Setup for the @verb command. +% +% Eight spaces for a tab +\begingroup + \catcode`\^^I=\active + \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} +\endgroup +% +\def\setupverb{% + \tt % easiest (and conventionally used) font for verbatim + \def\par{\leavevmode\endgraf}% + \catcode`\`=\active + \tabeightspaces + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces +} + +% Setup for the @verbatim environment +% +% Real tab expansion +\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount +% +\def\starttabbox{\setbox0=\hbox\bgroup} + +% Allow an option to not replace quotes with a regular directed right +% quote/apostrophe (char 0x27), but instead use the undirected quote +% from cmtt (char 0x0d). The undirected quote is ugly, so don't make it +% the default, but it works for pasting with more pdf viewers (at least +% evince), the lilypond developers report. xpdf does work with the +% regular 0x27. +% +\def\codequoteright{% + \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax + '% + \else + \char'15 + \fi +} +% +% and a similar option for the left quote char vs. a grave accent. +% Modern fonts display ASCII 0x60 as a grave accent, so some people like +% the code environments to do likewise. +% +\def\codequoteleft{% + \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax + `% + \else + \char'22 + \fi +} +% +\begingroup + \catcode`\^^I=\active + \gdef\tabexpand{% + \catcode`\^^I=\active + \def^^I{\leavevmode\egroup + \dimen0=\wd0 % the width so far, or since the previous tab + \divide\dimen0 by\tabw + \multiply\dimen0 by\tabw % compute previous multiple of \tabw + \advance\dimen0 by\tabw % advance to next multiple of \tabw + \wd0=\dimen0 \box0 \starttabbox + }% + } + \catcode`\'=\active + \gdef\rquoteexpand{\catcode\rquoteChar=\active \def'{\codequoteright}}% + % + \catcode`\`=\active + \gdef\lquoteexpand{\catcode\lquoteChar=\active \def`{\codequoteleft}}% + % + \gdef\quoteexpand{\rquoteexpand \lquoteexpand}% +\endgroup + +% start the verbatim environment. +\def\setupverbatim{% + \let\nonarrowing = t% + \nonfillstart + % Easiest (and conventionally used) font for verbatim + \tt + \def\par{\leavevmode\egroup\box0\endgraf}% + \catcode`\`=\active + \tabexpand + \quoteexpand + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces + \everypar{\starttabbox}% +} + +% Do the @verb magic: verbatim text is quoted by unique +% delimiter characters. Before first delimiter expect a +% right brace, after last delimiter expect closing brace: +% +% \def\doverb'{'#1'}'{#1} +% +% [Knuth] p. 382; only eat outer {} +\begingroup + \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other + \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] +\endgroup +% +\def\verb{\begingroup\setupverb\doverb} +% +% +% Do the @verbatim magic: define the macro \doverbatim so that +% the (first) argument ends when '@end verbatim' is reached, ie: +% +% \def\doverbatim#1@end verbatim{#1} +% +% For Texinfo it's a lot easier than for LaTeX, +% because texinfo's \verbatim doesn't stop at '\end{verbatim}': +% we need not redefine '\', '{' and '}'. +% +% Inspired by LaTeX's verbatim command set [latex.ltx] +% +\begingroup + \catcode`\ =\active + \obeylines % + % ignore everything up to the first ^^M, that's the newline at the end + % of the @verbatim input line itself. Otherwise we get an extra blank + % line in the output. + \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% + % We really want {...\end verbatim} in the body of the macro, but + % without the active space; thus we have to use \xdef and \gobble. +\endgroup +% +\envdef\verbatim{% + \setupverbatim\doverbatim +} +\let\Everbatim = \afterenvbreak + + +% @verbatiminclude FILE - insert text of file in verbatim environment. +% +\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} +% +\def\doverbatiminclude#1{% + {% + \makevalueexpandable + \setupverbatim + \input #1 + \afterenvbreak + }% +} + +% @copying ... @end copying. +% Save the text away for @insertcopying later. +% +% We save the uninterpreted tokens, rather than creating a box. +% Saving the text in a box would be much easier, but then all the +% typesetting commands (@smallbook, font changes, etc.) have to be done +% beforehand -- and a) we want @copying to be done first in the source +% file; b) letting users define the frontmatter in as flexible order as +% possible is very desirable. +% +\def\copying{\checkenv{}\begingroup\scanargctxt\docopying} +\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} +% +\def\insertcopying{% + \begingroup + \parindent = 0pt % paragraph indentation looks wrong on title page + \scanexp\copyingtext + \endgroup +} + + +\message{defuns,} +% @defun etc. + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deflastargmargin \deflastargmargin=18pt +\newcount\defunpenalty + +% Start the processing of @deffn: +\def\startdefun{% + \ifnum\lastpenalty<10000 + \medbreak + \defunpenalty=10003 % Will keep this @deffn together with the + % following @def command, see below. + \else + % If there are two @def commands in a row, we'll have a \nobreak, + % which is there to keep the function description together with its + % header. But if there's nothing but headers, we need to allow a + % break somewhere. Check specifically for penalty 10002, inserted + % by \printdefunline, instead of 10000, since the sectioning + % commands also insert a nobreak penalty, and we don't want to allow + % a break between a section heading and a defun. + % + % As a minor refinement, we avoid "club" headers by signalling + % with penalty of 10003 after the very first @deffn in the + % sequence (see above), and penalty of 10002 after any following + % @def command. + \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi + % + % Similarly, after a section heading, do not allow a break. + % But do insert the glue. + \medskip % preceded by discardable penalty, so not a breakpoint + \fi + % + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent +} + +\def\dodefunx#1{% + % First, check whether we are in the right environment: + \checkenv#1% + % + % As above, allow line break if we have multiple x headers in a row. + % It's not a great place, though. + \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi + % + % And now, it's time to reuse the body of the original defun: + \expandafter\gobbledefun#1% +} +\def\gobbledefun#1\startdefun{} + +% \printdefunline \deffnheader{text} +% +\def\printdefunline#1#2{% + \begingroup + % call \deffnheader: + #1#2 \endheader + % common ending: + \interlinepenalty = 10000 + \advance\rightskip by 0pt plus 1fil + \endgraf + \nobreak\vskip -\parskip + \penalty\defunpenalty % signal to \startdefun and \dodefunx + % Some of the @defun-type tags do not enable magic parentheses, + % rendering the following check redundant. But we don't optimize. + \checkparencounts + \endgroup +} + +\def\Edefun{\endgraf\medbreak} + +% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; +% the only thing remainnig is to define \deffnheader. +% +\def\makedefun#1{% + \expandafter\let\csname E#1\endcsname = \Edefun + \edef\temp{\noexpand\domakedefun + \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% + \temp +} + +% \domakedefun \deffn \deffnx \deffnheader +% +% Define \deffn and \deffnx, without parameters. +% \deffnheader has to be defined explicitly. +% +\def\domakedefun#1#2#3{% + \envdef#1{% + \startdefun + \parseargusing\activeparens{\printdefunline#3}% + }% + \def#2{\dodefunx#1}% + \def#3% +} + +%%% Untyped functions: + +% @deffn category name args +\makedefun{deffn}{\deffngeneral{}} + +% @deffn category class name args +\makedefun{defop}#1 {\defopon{#1\ \putwordon}} + +% \defopon {category on}class name args +\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deffngeneral {subind}category name args +% +\def\deffngeneral#1#2 #3 #4\endheader{% + % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. + \dosubind{fn}{\code{#3}}{#1}% + \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% +} + +%%% Typed functions: + +% @deftypefn category type name args +\makedefun{deftypefn}{\deftypefngeneral{}} + +% @deftypeop category class type name args +\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} + +% \deftypeopon {category on}class type name args +\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deftypefngeneral {subind}category type name args +% +\def\deftypefngeneral#1#2 #3 #4 #5\endheader{% + \dosubind{fn}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Typed variables: + +% @deftypevr category type var args +\makedefun{deftypevr}{\deftypecvgeneral{}} + +% @deftypecv category class type var args +\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} + +% \deftypecvof {category of}class type var args +\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } + +% \deftypecvgeneral {subind}category type var args +% +\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% + \dosubind{vr}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Untyped variables: + +% @defvr category var args +\makedefun{defvr}#1 {\deftypevrheader{#1} {} } + +% @defcv category class var args +\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} + +% \defcvof {category of}class var args +\def\defcvof#1#2 {\deftypecvof{#1}#2 {} } + +%%% Type: +% @deftp category name args +\makedefun{deftp}#1 #2 #3\endheader{% + \doind{tp}{\code{#2}}% + \defname{#1}{}{#2}\defunargs{#3\unskip}% +} + +% Remaining @defun-like shortcuts: +\makedefun{defun}{\deffnheader{\putwordDeffunc} } +\makedefun{defmac}{\deffnheader{\putwordDefmac} } +\makedefun{defspec}{\deffnheader{\putwordDefspec} } +\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } +\makedefun{defvar}{\defvrheader{\putwordDefvar} } +\makedefun{defopt}{\defvrheader{\putwordDefopt} } +\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } +\makedefun{defmethod}{\defopon\putwordMethodon} +\makedefun{deftypemethod}{\deftypeopon\putwordMethodon} +\makedefun{defivar}{\defcvof\putwordInstanceVariableof} +\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} + +% \defname, which formats the name of the @def (not the args). +% #1 is the category, such as "Function". +% #2 is the return type, if any. +% #3 is the function name. +% +% We are followed by (but not passed) the arguments, if any. +% +\def\defname#1#2#3{% + % Get the values of \leftskip and \rightskip as they were outside the @def... + \advance\leftskip by -\defbodyindent + % + % How we'll format the type name. Putting it in brackets helps + % distinguish it from the body text that may end up on the next line + % just below it. + \def\temp{#1}% + \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} + % + % Figure out line sizes for the paragraph shape. + % The first line needs space for \box0; but if \rightskip is nonzero, + % we need only space for the part of \box0 which exceeds it: + \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip + % The continuations: + \dimen2=\hsize \advance\dimen2 by -\defargsindent + % (plain.tex says that \dimen1 should be used only as global.) + \parshape 2 0in \dimen0 \defargsindent \dimen2 + % + % Put the type name to the right margin. + \noindent + \hbox to 0pt{% + \hfil\box0 \kern-\hsize + % \hsize has to be shortened this way: + \kern\leftskip + % Intentionally do not respect \rightskip, since we need the space. + }% + % + % Allow all lines to be underfull without complaint: + \tolerance=10000 \hbadness=10000 + \exdentamount=\defbodyindent + {% + % defun fonts. We use typewriter by default (used to be bold) because: + % . we're printing identifiers, they should be in tt in principle. + % . in languages with many accents, such as Czech or French, it's + % common to leave accents off identifiers. The result looks ok in + % tt, but exceedingly strange in rm. + % . we don't want -- and --- to be treated as ligatures. + % . this still does not fix the ?` and !` ligatures, but so far no + % one has made identifiers using them :). + \df \tt + \def\temp{#2}% return value type + \ifx\temp\empty\else \tclose{\temp} \fi + #3% output function name + }% + {\rm\enskip}% hskip 0.5 em of \tenrm + % + \boldbrax + % arguments will be output next, if any. +} + +% Print arguments in slanted roman (not ttsl), inconsistently with using +% tt for the name. This is because literal text is sometimes needed in +% the argument list (groff manual), and ttsl and tt are not very +% distinguishable. Prevent hyphenation at `-' chars. +% +\def\defunargs#1{% + % use sl by default (not ttsl), + % tt for the names. + \df \sl \hyphenchar\font=0 + % + % On the other hand, if an argument has two dashes (for instance), we + % want a way to get ttsl. Let's try @var for that. + \let\var=\ttslanted + #1% + \sl\hyphenchar\font=45 +} + +% We want ()&[] to print specially on the defun line. +% +\def\activeparens{% + \catcode`\(=\active \catcode`\)=\active + \catcode`\[=\active \catcode`\]=\active + \catcode`\&=\active +} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +{ + \activeparens + \global\let(=\lparen \global\let)=\rparen + \global\let[=\lbrack \global\let]=\rbrack + \global\let& = \& + + \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + \gdef\magicamp{\let&=\amprm} +} + +\newcount\parencount + +% If we encounter &foo, then turn on ()-hacking afterwards +\newif\ifampseen +\def\amprm#1 {\ampseentrue{\bf\ }} + +\def\parenfont{% + \ifampseen + % At the first level, print parens in roman, + % otherwise use the default font. + \ifnum \parencount=1 \rm \fi + \else + % The \sf parens (in \boldbrax) actually are a little bolder than + % the contained text. This is especially needed for [ and ] . + \sf + \fi +} +\def\infirstlevel#1{% + \ifampseen + \ifnum\parencount=1 + #1% + \fi + \fi +} +\def\bfafterword#1 {#1 \bf} + +\def\opnr{% + \global\advance\parencount by 1 + {\parenfont(}% + \infirstlevel \bfafterword +} +\def\clnr{% + {\parenfont)}% + \infirstlevel \sl + \global\advance\parencount by -1 +} + +\newcount\brackcount +\def\lbrb{% + \global\advance\brackcount by 1 + {\bf[}% +} +\def\rbrb{% + {\bf]}% + \global\advance\brackcount by -1 +} + +\def\checkparencounts{% + \ifnum\parencount=0 \else \badparencount \fi + \ifnum\brackcount=0 \else \badbrackcount \fi +} +\def\badparencount{% + \errmessage{Unbalanced parentheses in @def}% + \global\parencount=0 +} +\def\badbrackcount{% + \errmessage{Unbalanced square braces in @def}% + \global\brackcount=0 +} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scantokens#1{% + \toks0={#1}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \input \jobname.tmp + } +\fi + +\def\scanmacro#1{% + \begingroup + \newlinechar`\^^M + \let\xeatspaces\eatspaces + % Undo catcode changes of \startcontents and \doprintindex + % When called from @insertcopying or (short)caption, we need active + % backslash to get it printed correctly. Previously, we had + % \catcode`\\=\other instead. We'll see whether a problem appears + % with macro expansion. --kasal, 19aug04 + \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ + % ... and \example + \spaceisspace + % + % Append \endinput to make sure that TeX does not see the ending newline. + % I've verified that it is necessary both for e-TeX and for ordinary TeX + % --kasal, 29nov03 + \scantokens{#1\endinput}% + \endgroup +} + +\def\scanexp#1{% + \edef\temp{\noexpand\scanmacro{#1}}% + \temp +} + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? + +% List of all defined macros in the form +% \definedummyword\macro1\definedummyword\macro2... +% Currently is also contains all @aliases; the list can be split +% if there is a need. +\def\macrolist{} + +% Add the macro to \macrolist +\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} +\def\addtomacrolistxxx#1{% + \toks0 = \expandafter{\macrolist\definedummyword#1}% + \xdef\macrolist{\the\toks0}% +} + +% Utility routines. +% This does \let #1 = #2, with \csnames; that is, +% \let \csname#1\endcsname = \csname#2\endcsname +% (except of course we have to play expansion games). +% +\def\cslet#1#2{% + \expandafter\let + \csname#1\expandafter\endcsname + \csname#2\endcsname +} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=\other \catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\scanctxt{% + \catcode`\"=\other + \catcode`\+=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\@=\other + \catcode`\^=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\~=\other +} + +\def\scanargctxt{% + \scanctxt + \catcode`\\=\other + \catcode`\^^M=\other +} + +\def\macrobodyctxt{% + \scanctxt + \catcode`\{=\other + \catcode`\}=\other + \catcode`\^^M=\other + \usembodybackslash +} + +\def\macroargctxt{% + \scanctxt + \catcode`\\=\other +} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{Macro name \the\macname\space already defined}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + \addtomacrolist{\the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\parseargdef\unmacro{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist: + \begingroup + \expandafter\let\csname#1\endcsname \relax + \let\definedummyword\unmacrodo + \xdef\macrolist{\macrolist}% + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% Called by \do from \dounmacro on each macro. The idea is to omit any +% macro definitions that have been changed to \relax. +% +\def\unmacrodo#1{% + \ifx #1\relax + % remove this + \else + \noexpand\definedummyword \noexpand#1% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \macnamexxx} + + +% @alias. +% We need some trickery to remove the optional spaces around the equal +% sign. Just make them active and then expand them all to nothing. +\def\alias{\parseargusing\obeyspaces\aliasxxx} +\def\aliasxxx #1{\aliasyyy#1\relax} +\def\aliasyyy #1=#2\relax{% + {% + \expandafter\let\obeyedspace=\empty + \addtomacrolist{#1}% + \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% + }% + \next +} + + +\message{cross references,} + +\newwrite\auxfile +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's only job in TeX is to define \lastnode, which is used in +% cross-references. The @node line might or might not have commas, and +% might or might not have spaces before the first comma, like: +% @node foo , bar , ... +% We don't want such trailing spaces in the node name. +% +\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} +% +% also remove a trailing comma, in case of something like this: +% @node Help-Cross, , , Cross-refs +\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} +\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} + +\let\nwnode=\node +\let\lastnode=\empty + +% Write a cross-reference definition for the current node. #1 is the +% type (Ynumbered, Yappendix, Ynothing). +% +\def\donoderef#1{% + \ifx\lastnode\empty\else + \setref{\lastnode}{#1}% + \global\let\lastnode=\empty + \fi +} + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\newcount\savesfregister +% +\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} +\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} +\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} + +% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an +% anchor), which consists of three parts: +% 1) NAME-title - the current sectioning name taken from \thissection, +% or the anchor name. +% 2) NAME-snt - section number and type, passed as the SNT arg, or +% empty for anchors. +% 3) NAME-pg - the page number. +% +% This is called from \donoderef, \anchor, and \dofloat. In the case of +% floats, there is an additional part, which is not written here: +% 4) NAME-lof - the text as it should appear in a @listoffloats. +% +\def\setref#1#2{% + \pdfmkdest{#1}% + \iflinks + {% + \atdummies % preserve commands, but don't expand them + \edef\writexrdef##1##2{% + \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef + ##1}{##2}}% these are parameters of \writexrdef + }% + \toks0 = \expandafter{\thissection}% + \immediate \writexrdef{title}{\the\toks0 }% + \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. + \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, during \shipout + }% + \fi +} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \unsepspaces + \def\printedmanual{\ignorespaces #5}% + \def\printedrefname{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual\unskip}% + \setbox0=\hbox{\printedrefname\unskip}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printedrefname{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printedrefname{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printedrefname{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printedrefname{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % Make link in pdf output. + \ifpdf + \leavevmode + \getfilename{#4}% + {\indexnofonts + \turnoffactive + % See comments at \activebackslashdouble. + {\activebackslashdouble \xdef\pdfxrefdest{#1}% + \backslashparens\pdfxrefdest}% + % + \ifnum\filenamelength>0 + \startlink attr{/Border [0 0 0]}% + goto file{\the\filename.pdf} name{\pdfxrefdest}% + \else + \startlink attr{/Border [0 0 0]}% + goto name{\pdfmkpgn{\pdfxrefdest}}% + \fi + }% + \linkcolor + \fi + % + % Float references are printed completely differently: "Figure 1.2" + % instead of "[somenode], p.3". We distinguish them by the + % LABEL-title being set to a magic string. + {% + % Have to otherify everything special to allow the \csname to + % include an _ in the xref name, etc. + \indexnofonts + \turnoffactive + \expandafter\global\expandafter\let\expandafter\Xthisreftitle + \csname XR#1-title\endcsname + }% + \iffloat\Xthisreftitle + % If the user specified the print name (third arg) to the ref, + % print it instead of our usual "Figure 1.2". + \ifdim\wd0 = 0pt + \refx{#1-snt}{}% + \else + \printedrefname + \fi + % + % if the user also gave the printed manual name (fifth arg), append + % "in MANUALNAME". + \ifdim \wd1 > 0pt + \space \putwordin{} \cite{\printedmanual}% + \fi + \else + % node/anchor (non-float) references. + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % output the `[mynode]' via a macro so it can be overridden. + \xrefprintnodename\printedrefname + % + % But we always want a comma and a space: + ,\space + % + % output the `page 3'. + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \fi + \endlink +\endgroup} + +% This macro is called from \xrefX for the `[nodename]' part of xref +% output. It's a separate macro only so it can be changed more easily, +% since square brackets don't work well in some documents. Particularly +% one that Bob is working on :). +% +\def\xrefprintnodename#1{[#1]} + +% Things referred to by \setref. +% +\def\Ynothing{} +\def\Yomitfromtoc{} +\def\Ynumbered{% + \ifnum\secno=0 + \putwordChapter@tie \the\chapno + \else \ifnum\subsecno=0 + \putwordSection@tie \the\chapno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno + \else + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} +\def\Yappendix{% + \ifnum\secno=0 + \putwordAppendix@tie @char\the\appendixno{}% + \else \ifnum\subsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno + \else + \putwordSection@tie + @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. +% +\def\refx#1#2{% + {% + \indexnofonts + \otherbackslash + \expandafter\global\expandafter\let\expandafter\thisrefX + \csname XR#1\endcsname + }% + \ifx\thisrefX\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \thisrefX + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. Usually it's +% just a \def (we prepend XR to the control sequence name to avoid +% collisions). But if this is a float type, we have more work to do. +% +\def\xrdef#1#2{% + {% The node name might contain 8-bit characters, which in our current + % implementation are changed to commands like @'e. Don't let these + % mess up the control sequence name. + \indexnofonts + \turnoffactive + \xdef\safexrefname{#1}% + }% + % + \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref + % + % Was that xref control sequence that we just defined for a float? + \expandafter\iffloat\csname XR\safexrefname\endcsname + % it was a float, and we have the (safe) float type in \iffloattype. + \expandafter\let\expandafter\floatlist + \csname floatlist\iffloattype\endcsname + % + % Is this the first time we've seen this float type? + \expandafter\ifx\floatlist\relax + \toks0 = {\do}% yes, so just \do + \else + % had it before, so preserve previous elements in list. + \toks0 = \expandafter{\floatlist\do}% + \fi + % + % Remember this xref in the control sequence \floatlistFLOATTYPE, + % for later use in \listoffloats. + \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 + {\safexrefname}}% + \fi +} + +% Read the last existing aux file, if any. No error if none exists. +% +\def\tryauxfile{% + \openin 1 \jobname.aux + \ifeof 1 \else + \readdatafile{aux}% + \global\havexrefstrue + \fi + \closein 1 +} + +\def\setupdatafile{% + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\^=\other + % + % Special characters. Should be turned off anyway, but... + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`\%=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % + % This is to support \ in node names and titles, since the \ + % characters end up in a \csname. It's easier than + % leaving it active and making its active definition an actual \ + % character. What I don't understand is why it works in the *value* + % of the xrdef. Seems like it should be a catcode12 \, and that + % should not typeset properly. But it works, so I'm moving on for + % now. --karl, 15jan04. + \catcode`\\=\other + % + % Make the characters 128-255 be printing characters. + {% + \count1=128 + \def\loop{% + \catcode\count1=\other + \advance\count1 by 1 + \ifnum \count1<256 \loop \fi + }% + }% + % + % @ is our escape character in .aux files, and we need braces. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\@=0 +} + +\def\readdatafile#1{% +\begingroup + \setupdatafile + \input\jobname.#1 +\endgroup} + + +\message{insertions,} +% including footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \dofootnote +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset (and anything else that uses +% \parseargline) fails inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\gdef\dofootnote{% + \insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \hsize=\pagewidth + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + \smallfonts \rm + % + % Because we use hanging indentation in footnotes, a @noindent appears + % to exdent this text, so make it be a no-op. makeinfo does not use + % hanging indentation so @noindent can still be needed within footnote + % text after an @example or the like (not that this is good style). + \let\noindent = \relax + % + % Hang the footnote text off the number. Use \everypar in case the + % footnote extends for more than one paragraph. + \everypar = {\hang}% + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +}%end \catcode `\@=11 + +% In case a @footnote appears in a vbox, save the footnote text and create +% the real \insert just after the vbox finished. Otherwise, the insertion +% would be lost. +% Similarly, if a @footnote appears inside an alignment, save the footnote +% text to a box and make the \insert when a row of the table is finished. +% And the same can be done for other insert classes. --kasal, 16nov03. + +% Replace the \insert primitive by a cheating macro. +% Deeper inside, just make sure that the saved insertions are not spilled +% out prematurely. +% +\def\startsavinginserts{% + \ifx \insert\ptexinsert + \let\insert\saveinsert + \else + \let\checkinserts\relax + \fi +} + +% This \insert replacement works for both \insert\footins{foo} and +% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. +% +\def\saveinsert#1{% + \edef\next{\noexpand\savetobox \makeSAVEname#1}% + \afterassignment\next + % swallow the left brace + \let\temp = +} +\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} +\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} + +\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} + +\def\placesaveins#1{% + \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname + {\box#1}% +} + +% eat @SAVE -- beware, all of them have catcode \other: +{ + \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) + \gdef\gobblesave @SAVE{} +} + +% initialization: +\def\newsaveins #1{% + \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% + \next +} +\def\newsaveinsX #1{% + \csname newbox\endcsname #1% + \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts + \checksaveins #1}% +} + +% initialize: +\let\checkinserts\empty +\newsaveins\footins +\newsaveins\margin + + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + % Do not bother showing banner with epsf.tex v2.7k (available in + % doc/epsf.tex and on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +\closein 1 +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is (ignored optional) html alt text. +% #5 is (ignored optional) extension. +% #6 is just the usual extra ignored arg for parsing this stuff. +\newif\ifimagevmode +\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup + \catcode`\^^M = 5 % in case we're inside an example + \normalturnoffactive % allow _ et al. in names + % If the image is by itself, center it. + \ifvmode + \imagevmodetrue + \nobreak\bigskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \line\bgroup + \fi + % + % Output the image. + \ifpdf + \dopdfimage{#1}{#2}{#3}% + \else + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% + \fi + % + \ifimagevmode \egroup \bigbreak \fi % space after the image +\endgroup} + + +% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, +% etc. We don't actually implement floating yet, we always include the +% float "here". But it seemed the best name for the future. +% +\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} + +% There may be a space before second and/or third parameter; delete it. +\def\eatcommaspace#1, {#1,} + +% #1 is the optional FLOATTYPE, the text label for this float, typically +% "Figure", "Table", "Example", etc. Can't contain commas. If omitted, +% this float will not be numbered and cannot be referred to. +% +% #2 is the optional xref label. Also must be present for the float to +% be referable. +% +% #3 is the optional positioning argument; for now, it is ignored. It +% will somehow specify the positions allowed to float to (here, top, bottom). +% +% We keep a separate counter for each FLOATTYPE, which we reset at each +% chapter-level command. +\let\resetallfloatnos=\empty +% +\def\dofloat#1,#2,#3,#4\finish{% + \let\thiscaption=\empty + \let\thisshortcaption=\empty + % + % don't lose footnotes inside @float. + % + % BEWARE: when the floats start float, we have to issue warning whenever an + % insert appears inside a float which could possibly float. --kasal, 26may04 + % + \startsavinginserts + % + % We can't be used inside a paragraph. + \par + % + \vtop\bgroup + \def\floattype{#1}% + \def\floatlabel{#2}% + \def\floatloc{#3}% we do nothing with this yet. + % + \ifx\floattype\empty + \let\safefloattype=\empty + \else + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + \fi + % + % If label is given but no type, we handle that as the empty type. + \ifx\floatlabel\empty \else + % We want each FLOATTYPE to be numbered separately (Figure 1, + % Table 1, Figure 2, ...). (And if no label, no number.) + % + \expandafter\getfloatno\csname\safefloattype floatno\endcsname + \global\advance\floatno by 1 + % + {% + % This magic value for \thissection is output by \setref as the + % XREFLABEL-title value. \xrefX uses it to distinguish float + % labels (which have a completely different output format) from + % node and anchor labels. And \xrdef uses it to construct the + % lists of floats. + % + \edef\thissection{\floatmagic=\safefloattype}% + \setref{\floatlabel}{Yfloat}% + }% + \fi + % + % start with \parskip glue, I guess. + \vskip\parskip + % + % Don't suppress indentation if a float happens to start a section. + \restorefirstparagraphindent +} + +% we have these possibilities: +% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap +% @float Foo,lbl & no caption: Foo 1.1 +% @float Foo & @caption{Cap}: Foo: Cap +% @float Foo & no caption: Foo +% @float ,lbl & Caption{Cap}: 1.1: Cap +% @float ,lbl & no caption: 1.1 +% @float & @caption{Cap}: Cap +% @float & no caption: +% +\def\Efloat{% + \let\floatident = \empty + % + % In all cases, if we have a float type, it comes first. + \ifx\floattype\empty \else \def\floatident{\floattype}\fi + % + % If we have an xref label, the number comes next. + \ifx\floatlabel\empty \else + \ifx\floattype\empty \else % if also had float type, need tie first. + \appendtomacro\floatident{\tie}% + \fi + % the number. + \appendtomacro\floatident{\chaplevelprefix\the\floatno}% + \fi + % + % Start the printed caption with what we've constructed in + % \floatident, but keep it separate; we need \floatident again. + \let\captionline = \floatident + % + \ifx\thiscaption\empty \else + \ifx\floatident\empty \else + \appendtomacro\captionline{: }% had ident, so need a colon between + \fi + % + % caption text. + \appendtomacro\captionline{\scanexp\thiscaption}% + \fi + % + % If we have anything to print, print it, with space before. + % Eventually this needs to become an \insert. + \ifx\captionline\empty \else + \vskip.5\parskip + \captionline + % + % Space below caption. + \vskip\parskip + \fi + % + % If have an xref label, write the list of floats info. Do this + % after the caption, to avoid chance of it being a breakpoint. + \ifx\floatlabel\empty \else + % Write the text that goes in the lof to the aux file as + % \floatlabel-lof. Besides \floatident, we include the short + % caption if specified, else the full caption if specified, else nothing. + {% + \atdummies + % + % since we read the caption text in the macro world, where ^^M + % is turned into a normal character, we have to scan it back, so + % we don't write the literal three characters "^^M" into the aux file. + \scanexp{% + \xdef\noexpand\gtemp{% + \ifx\thisshortcaption\empty + \thiscaption + \else + \thisshortcaption + \fi + }% + }% + \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident + \ifx\gtemp\empty \else : \gtemp \fi}}% + }% + \fi + \egroup % end of \vtop + % + % place the captured inserts + % + % BEWARE: when the floats start floating, we have to issue warning + % whenever an insert appears inside a float which could possibly + % float. --kasal, 26may04 + % + \checkinserts +} + +% Append the tokens #2 to the definition of macro #1, not expanding either. +% +\def\appendtomacro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +} + +% @caption, @shortcaption +% +\def\caption{\docaption\thiscaption} +\def\shortcaption{\docaption\thisshortcaption} +\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} +\def\defcaption#1#2{\egroup \def#1{#2}} + +% The parameter is the control sequence identifying the counter we are +% going to use. Create it if it doesn't exist and assign it to \floatno. +\def\getfloatno#1{% + \ifx#1\relax + % Haven't seen this figure type before. + \csname newcount\endcsname #1% + % + % Remember to reset this floatno at the next chap. + \expandafter\gdef\expandafter\resetallfloatnos + \expandafter{\resetallfloatnos #1=0 }% + \fi + \let\floatno#1% +} + +% \setref calls this to get the XREFLABEL-snt value. We want an @xref +% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we +% first read the @float command. +% +\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% + +% Magic string used for the XREFLABEL-title value, so \xrefX can +% distinguish floats from other xref types. +\def\floatmagic{!!float!!} + +% #1 is the control sequence we are passed; we expand into a conditional +% which is true if #1 represents a float ref. That is, the magic +% \thissection value which we \setref above. +% +\def\iffloat#1{\expandafter\doiffloat#1==\finish} +% +% #1 is (maybe) the \floatmagic string. If so, #2 will be the +% (safe) float type for this float. We set \iffloattype to #2. +% +\def\doiffloat#1=#2=#3\finish{% + \def\temp{#1}% + \def\iffloattype{#2}% + \ifx\temp\floatmagic +} + +% @listoffloats FLOATTYPE - print a list of floats like a table of contents. +% +\parseargdef\listoffloats{% + \def\floattype{#1}% floattype + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + % + % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. + \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax + \ifhavexrefs + % if the user said @listoffloats foo but never @float foo. + \message{\linenumber No `\safefloattype' floats to list.}% + \fi + \else + \begingroup + \leftskip=\tocindent % indent these entries like a toc + \let\do=\listoffloatsdo + \csname floatlist\safefloattype\endcsname + \endgroup + \fi +} + +% This is called on each entry in a list of floats. We're passed the +% xref label, in the form LABEL-title, which is how we save it in the +% aux file. We strip off the -title and look up \XRLABEL-lof, which +% has the text we're supposed to typeset here. +% +% Figures without xref labels will not be included in the list (since +% they won't appear in the aux file). +% +\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} +\def\listoffloatsdoentry#1-title\finish{{% + % Can't fully expand XR#1-lof because it can contain anything. Just + % pass the control sequence. On the other hand, XR#1-pg is just the + % page number, and we want to fully expand that so we can get a link + % in pdf output. + \toksA = \expandafter{\csname XR#1-lof\endcsname}% + % + % use the same \entry macro we use to generate the TOC and index. + \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% + \writeentry +}} + + +\message{localization,} + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language abbreviation. +% It would be nice if we could set up a hyphenation file here. +% +\parseargdef\documentlanguage{% + \tex % read txi-??.tex file in plain TeX. + % Read the file if it exists. + \openin 1 txi-#1.tex + \ifeof 1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \else + \input txi-#1.tex + \fi + \closein 1 + \endgroup +} +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + +% Set the catcode of characters 128 through 255 to the specified number. +% +\def\setnonasciicharscatcode#1{% + \count255=128 + \loop\ifnum\count255<256 + \global\catcode\count255=#1 + \advance\count255 by 1 + \repeat +} + +% @documentencoding sets the definition of non-ASCII characters +% according to the specified encoding. +% +\parseargdef\documentencoding{% + % Encoding being declared for the document. + \def\declaredencoding{\csname #1.enc\endcsname}% + % + % Supported encodings: names converted to tokens in order to be able + % to compare them with \ifx. + \def\ascii{\csname US-ASCII.enc\endcsname}% + \def\latnine{\csname ISO-8859-15.enc\endcsname}% + \def\latone{\csname ISO-8859-1.enc\endcsname}% + \def\lattwo{\csname ISO-8859-2.enc\endcsname}% + \def\utfeight{\csname UTF-8.enc\endcsname}% + % + \ifx \declaredencoding \ascii + \asciichardefs + % + \else \ifx \declaredencoding \lattwo + \setnonasciicharscatcode\active + \lattwochardefs + % + \else \ifx \declaredencoding \latone + \setnonasciicharscatcode\active + \latonechardefs + % + \else \ifx \declaredencoding \latnine + \setnonasciicharscatcode\active + \latninechardefs + % + \else \ifx \declaredencoding \utfeight + \setnonasciicharscatcode\active + \utfeightchardefs + % + \else + \message{Unknown document encoding #1, ignoring.}% + % + \fi % utfeight + \fi % latnine + \fi % latone + \fi % lattwo + \fi % ascii +} + +% A message to be logged when using a character that isn't available +% the default font encoding (OT1). +% +\def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} + +% Take account of \c (plain) vs. \, (Texinfo) difference. +\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} + +% First, make active non-ASCII characters in order for them to be +% correctly categorized when TeX reads the replacement text of +% macros containing the character definitions. +\setnonasciicharscatcode\active +% +% Latin1 (ISO-8859-1) character definitions. +\def\latonechardefs{% + \gdef^^a0{~} + \gdef^^a1{\exclamdown} + \gdef^^a2{\missingcharmsg{CENT SIGN}} + \gdef^^a3{{\pounds}} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\missingcharmsg{YEN SIGN}} + \gdef^^a6{\missingcharmsg{BROKEN BAR}} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\copyright} + \gdef^^aa{\ordf} + \gdef^^ab{\missingcharmsg{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}} + \gdef^^ac{$\lnot$} + \gdef^^ad{\-} + \gdef^^ae{\registeredsymbol} + \gdef^^af{\={}} + % + \gdef^^b0{\textdegree} + \gdef^^b1{$\pm$} + \gdef^^b2{$^2$} + \gdef^^b3{$^3$} + \gdef^^b4{\'{}} + \gdef^^b5{$\mu$} + \gdef^^b6{\P} + % + \gdef^^b7{$^.$} + \gdef^^b8{\cedilla\ } + \gdef^^b9{$^1$} + \gdef^^ba{\ordm} + % + \gdef^^bb{\missingcharmsg{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}} + \gdef^^bc{$1\over4$} + \gdef^^bd{$1\over2$} + \gdef^^be{$3\over4$} + \gdef^^bf{\questiondown} + % + \gdef^^c0{\`A} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\~A} + \gdef^^c4{\"A} + \gdef^^c5{\ringaccent A} + \gdef^^c6{\AE} + \gdef^^c7{\cedilla C} + \gdef^^c8{\`E} + \gdef^^c9{\'E} + \gdef^^ca{\^E} + \gdef^^cb{\"E} + \gdef^^cc{\`I} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\"I} + % + \gdef^^d0{\missingcharmsg{LATIN CAPITAL LETTER ETH}} + \gdef^^d1{\~N} + \gdef^^d2{\`O} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\~O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\O} + \gdef^^d9{\`U} + \gdef^^da{\'U} + \gdef^^db{\^U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\missingcharmsg{LATIN CAPITAL LETTER THORN}} + \gdef^^df{\ss} + % + \gdef^^e0{\`a} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\~a} + \gdef^^e4{\"a} + \gdef^^e5{\ringaccent a} + \gdef^^e6{\ae} + \gdef^^e7{\cedilla c} + \gdef^^e8{\`e} + \gdef^^e9{\'e} + \gdef^^ea{\^e} + \gdef^^eb{\"e} + \gdef^^ec{\`{\dotless i}} + \gdef^^ed{\'{\dotless i}} + \gdef^^ee{\^{\dotless i}} + \gdef^^ef{\"{\dotless i}} + % + \gdef^^f0{\missingcharmsg{LATIN SMALL LETTER ETH}} + \gdef^^f1{\~n} + \gdef^^f2{\`o} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\~o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\o} + \gdef^^f9{\`u} + \gdef^^fa{\'u} + \gdef^^fb{\^u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\missingcharmsg{LATIN SMALL LETTER THORN}} + \gdef^^ff{\"y} +} + +% Latin9 (ISO-8859-15) encoding character definitions. +\def\latninechardefs{% + % Encoding is almost identical to Latin1. + \latonechardefs + % + \gdef^^a4{\euro} + \gdef^^a6{\v S} + \gdef^^a8{\v s} + \gdef^^b4{\v Z} + \gdef^^b8{\v z} + \gdef^^bc{\OE} + \gdef^^bd{\oe} + \gdef^^be{\"Y} +} + +% Latin2 (ISO-8859-2) character definitions. +\def\lattwochardefs{% + \gdef^^a0{~} + \gdef^^a1{\missingcharmsg{LATIN CAPITAL LETTER A WITH OGONEK}} + \gdef^^a2{\u{}} + \gdef^^a3{\L} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\v L} + \gdef^^a6{\'S} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\v S} + \gdef^^aa{\cedilla S} + \gdef^^ab{\v T} + \gdef^^ac{\'Z} + \gdef^^ad{\-} + \gdef^^ae{\v Z} + \gdef^^af{\dotaccent Z} + % + \gdef^^b0{\textdegree} + \gdef^^b1{\missingcharmsg{LATIN SMALL LETTER A WITH OGONEK}} + \gdef^^b2{\missingcharmsg{OGONEK}} + \gdef^^b3{\l} + \gdef^^b4{\'{}} + \gdef^^b5{\v l} + \gdef^^b6{\'s} + \gdef^^b7{\v{}} + \gdef^^b8{\cedilla\ } + \gdef^^b9{\v s} + \gdef^^ba{\cedilla s} + \gdef^^bb{\v t} + \gdef^^bc{\'z} + \gdef^^bd{\H{}} + \gdef^^be{\v z} + \gdef^^bf{\dotaccent z} + % + \gdef^^c0{\'R} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\u A} + \gdef^^c4{\"A} + \gdef^^c5{\'L} + \gdef^^c6{\'C} + \gdef^^c7{\cedilla C} + \gdef^^c8{\v C} + \gdef^^c9{\'E} + \gdef^^ca{\missingcharmsg{LATIN CAPITAL LETTER E WITH OGONEK}} + \gdef^^cb{\"E} + \gdef^^cc{\v E} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\v D} + % + \gdef^^d0{\missingcharmsg{LATIN CAPITAL LETTER D WITH STROKE}} + \gdef^^d1{\'N} + \gdef^^d2{\v N} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\H O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\v R} + \gdef^^d9{\ringaccent U} + \gdef^^da{\'U} + \gdef^^db{\H U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\cedilla T} + \gdef^^df{\ss} + % + \gdef^^e0{\'r} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\u a} + \gdef^^e4{\"a} + \gdef^^e5{\'l} + \gdef^^e6{\'c} + \gdef^^e7{\cedilla c} + \gdef^^e8{\v c} + \gdef^^e9{\'e} + \gdef^^ea{\missingcharmsg{LATIN SMALL LETTER E WITH OGONEK}} + \gdef^^eb{\"e} + \gdef^^ec{\v e} + \gdef^^ed{\'\i} + \gdef^^ee{\^\i} + \gdef^^ef{\v d} + % + \gdef^^f0{\missingcharmsg{LATIN SMALL LETTER D WITH STROKE}} + \gdef^^f1{\'n} + \gdef^^f2{\v n} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\H o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\v r} + \gdef^^f9{\ringaccent u} + \gdef^^fa{\'u} + \gdef^^fb{\H u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\cedilla t} + \gdef^^ff{\dotaccent{}} +} + +% UTF-8 character definitions. +% +% This code to support UTF-8 is based on LaTeX's utf8.def, with some +% changes for Texinfo conventions. It is included here under the GPL by +% permission from Frank Mittelbach and the LaTeX team. +% +\newcount\countUTFx +\newcount\countUTFy +\newcount\countUTFz + +\gdef\UTFviiiTwoOctets#1#2{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\endcsname} +% +\gdef\UTFviiiThreeOctets#1#2#3{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} +% +\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} + +\gdef\UTFviiiDefined#1{% + \ifx #1\relax + \message{\linenumber Unicode char \string #1 not defined for Texinfo}% + \else + \expandafter #1% + \fi +} + +\begingroup + \catcode`\~13 + \catcode`\"12 + + \def\UTFviiiLoop{% + \global\catcode\countUTFx\active + \uccode`\~\countUTFx + \uppercase\expandafter{\UTFviiiTmp}% + \advance\countUTFx by 1 + \ifnum\countUTFx < \countUTFy + \expandafter\UTFviiiLoop + \fi} + + \countUTFx = "C2 + \countUTFy = "E0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiTwoOctets\string~}} + \UTFviiiLoop + + \countUTFx = "E0 + \countUTFy = "F0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiThreeOctets\string~}} + \UTFviiiLoop + + \countUTFx = "F0 + \countUTFy = "F4 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiFourOctets\string~}} + \UTFviiiLoop +\endgroup + +\begingroup + \catcode`\"=12 + \catcode`\<=12 + \catcode`\.=12 + \catcode`\,=12 + \catcode`\;=12 + \catcode`\!=12 + \catcode`\~=13 + + \gdef\DeclareUnicodeCharacter#1#2{% + \countUTFz = "#1\relax + \wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% + \begingroup + \parseXMLCharref + \def\UTFviiiTwoOctets##1##2{% + \csname u8:##1\string ##2\endcsname}% + \def\UTFviiiThreeOctets##1##2##3{% + \csname u8:##1\string ##2\string ##3\endcsname}% + \def\UTFviiiFourOctets##1##2##3##4{% + \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \gdef\UTFviiiTmp{#2}% + \endgroup} + + \gdef\parseXMLCharref{% + \ifnum\countUTFz < "A0\relax + \errhelp = \EMsimple + \errmessage{Cannot define Unicode char value < 00A0}% + \else\ifnum\countUTFz < "800\relax + \parseUTFviiiA,% + \parseUTFviiiB C\UTFviiiTwoOctets.,% + \else\ifnum\countUTFz < "10000\relax + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% + \else + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiA!% + \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% + \fi\fi\fi + } + + \gdef\parseUTFviiiA#1{% + \countUTFx = \countUTFz + \divide\countUTFz by 64 + \countUTFy = \countUTFz + \multiply\countUTFz by 64 + \advance\countUTFx by -\countUTFz + \advance\countUTFx by 128 + \uccode `#1\countUTFx + \countUTFz = \countUTFy} + + \gdef\parseUTFviiiB#1#2#3#4{% + \advance\countUTFz by "#10\relax + \uccode `#3\countUTFz + \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} +\endgroup + +\def\utfeightchardefs{% + \DeclareUnicodeCharacter{00A0}{\tie} + \DeclareUnicodeCharacter{00A1}{\exclamdown} + \DeclareUnicodeCharacter{00A3}{\pounds} + \DeclareUnicodeCharacter{00A8}{\"{ }} + \DeclareUnicodeCharacter{00A9}{\copyright} + \DeclareUnicodeCharacter{00AA}{\ordf} + \DeclareUnicodeCharacter{00AD}{\-} + \DeclareUnicodeCharacter{00AE}{\registeredsymbol} + \DeclareUnicodeCharacter{00AF}{\={ }} + + \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} + \DeclareUnicodeCharacter{00B4}{\'{ }} + \DeclareUnicodeCharacter{00B8}{\cedilla{ }} + \DeclareUnicodeCharacter{00BA}{\ordm} + \DeclareUnicodeCharacter{00BF}{\questiondown} + + \DeclareUnicodeCharacter{00C0}{\`A} + \DeclareUnicodeCharacter{00C1}{\'A} + \DeclareUnicodeCharacter{00C2}{\^A} + \DeclareUnicodeCharacter{00C3}{\~A} + \DeclareUnicodeCharacter{00C4}{\"A} + \DeclareUnicodeCharacter{00C5}{\AA} + \DeclareUnicodeCharacter{00C6}{\AE} + \DeclareUnicodeCharacter{00C7}{\cedilla{C}} + \DeclareUnicodeCharacter{00C8}{\`E} + \DeclareUnicodeCharacter{00C9}{\'E} + \DeclareUnicodeCharacter{00CA}{\^E} + \DeclareUnicodeCharacter{00CB}{\"E} + \DeclareUnicodeCharacter{00CC}{\`I} + \DeclareUnicodeCharacter{00CD}{\'I} + \DeclareUnicodeCharacter{00CE}{\^I} + \DeclareUnicodeCharacter{00CF}{\"I} + + \DeclareUnicodeCharacter{00D1}{\~N} + \DeclareUnicodeCharacter{00D2}{\`O} + \DeclareUnicodeCharacter{00D3}{\'O} + \DeclareUnicodeCharacter{00D4}{\^O} + \DeclareUnicodeCharacter{00D5}{\~O} + \DeclareUnicodeCharacter{00D6}{\"O} + \DeclareUnicodeCharacter{00D8}{\O} + \DeclareUnicodeCharacter{00D9}{\`U} + \DeclareUnicodeCharacter{00DA}{\'U} + \DeclareUnicodeCharacter{00DB}{\^U} + \DeclareUnicodeCharacter{00DC}{\"U} + \DeclareUnicodeCharacter{00DD}{\'Y} + \DeclareUnicodeCharacter{00DF}{\ss} + + \DeclareUnicodeCharacter{00E0}{\`a} + \DeclareUnicodeCharacter{00E1}{\'a} + \DeclareUnicodeCharacter{00E2}{\^a} + \DeclareUnicodeCharacter{00E3}{\~a} + \DeclareUnicodeCharacter{00E4}{\"a} + \DeclareUnicodeCharacter{00E5}{\aa} + \DeclareUnicodeCharacter{00E6}{\ae} + \DeclareUnicodeCharacter{00E7}{\cedilla{c}} + \DeclareUnicodeCharacter{00E8}{\`e} + \DeclareUnicodeCharacter{00E9}{\'e} + \DeclareUnicodeCharacter{00EA}{\^e} + \DeclareUnicodeCharacter{00EB}{\"e} + \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} + \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} + \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} + \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} + + \DeclareUnicodeCharacter{00F1}{\~n} + \DeclareUnicodeCharacter{00F2}{\`o} + \DeclareUnicodeCharacter{00F3}{\'o} + \DeclareUnicodeCharacter{00F4}{\^o} + \DeclareUnicodeCharacter{00F5}{\~o} + \DeclareUnicodeCharacter{00F6}{\"o} + \DeclareUnicodeCharacter{00F8}{\o} + \DeclareUnicodeCharacter{00F9}{\`u} + \DeclareUnicodeCharacter{00FA}{\'u} + \DeclareUnicodeCharacter{00FB}{\^u} + \DeclareUnicodeCharacter{00FC}{\"u} + \DeclareUnicodeCharacter{00FD}{\'y} + \DeclareUnicodeCharacter{00FF}{\"y} + + \DeclareUnicodeCharacter{0100}{\=A} + \DeclareUnicodeCharacter{0101}{\=a} + \DeclareUnicodeCharacter{0102}{\u{A}} + \DeclareUnicodeCharacter{0103}{\u{a}} + \DeclareUnicodeCharacter{0106}{\'C} + \DeclareUnicodeCharacter{0107}{\'c} + \DeclareUnicodeCharacter{0108}{\^C} + \DeclareUnicodeCharacter{0109}{\^c} + \DeclareUnicodeCharacter{010A}{\dotaccent{C}} + \DeclareUnicodeCharacter{010B}{\dotaccent{c}} + \DeclareUnicodeCharacter{010C}{\v{C}} + \DeclareUnicodeCharacter{010D}{\v{c}} + \DeclareUnicodeCharacter{010E}{\v{D}} + + \DeclareUnicodeCharacter{0112}{\=E} + \DeclareUnicodeCharacter{0113}{\=e} + \DeclareUnicodeCharacter{0114}{\u{E}} + \DeclareUnicodeCharacter{0115}{\u{e}} + \DeclareUnicodeCharacter{0116}{\dotaccent{E}} + \DeclareUnicodeCharacter{0117}{\dotaccent{e}} + \DeclareUnicodeCharacter{011A}{\v{E}} + \DeclareUnicodeCharacter{011B}{\v{e}} + \DeclareUnicodeCharacter{011C}{\^G} + \DeclareUnicodeCharacter{011D}{\^g} + \DeclareUnicodeCharacter{011E}{\u{G}} + \DeclareUnicodeCharacter{011F}{\u{g}} + + \DeclareUnicodeCharacter{0120}{\dotaccent{G}} + \DeclareUnicodeCharacter{0121}{\dotaccent{g}} + \DeclareUnicodeCharacter{0124}{\^H} + \DeclareUnicodeCharacter{0125}{\^h} + \DeclareUnicodeCharacter{0128}{\~I} + \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} + \DeclareUnicodeCharacter{012A}{\=I} + \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} + \DeclareUnicodeCharacter{012C}{\u{I}} + \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} + + \DeclareUnicodeCharacter{0130}{\dotaccent{I}} + \DeclareUnicodeCharacter{0131}{\dotless{i}} + \DeclareUnicodeCharacter{0132}{IJ} + \DeclareUnicodeCharacter{0133}{ij} + \DeclareUnicodeCharacter{0134}{\^J} + \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} + \DeclareUnicodeCharacter{0139}{\'L} + \DeclareUnicodeCharacter{013A}{\'l} + + \DeclareUnicodeCharacter{0141}{\L} + \DeclareUnicodeCharacter{0142}{\l} + \DeclareUnicodeCharacter{0143}{\'N} + \DeclareUnicodeCharacter{0144}{\'n} + \DeclareUnicodeCharacter{0147}{\v{N}} + \DeclareUnicodeCharacter{0148}{\v{n}} + \DeclareUnicodeCharacter{014C}{\=O} + \DeclareUnicodeCharacter{014D}{\=o} + \DeclareUnicodeCharacter{014E}{\u{O}} + \DeclareUnicodeCharacter{014F}{\u{o}} + + \DeclareUnicodeCharacter{0150}{\H{O}} + \DeclareUnicodeCharacter{0151}{\H{o}} + \DeclareUnicodeCharacter{0152}{\OE} + \DeclareUnicodeCharacter{0153}{\oe} + \DeclareUnicodeCharacter{0154}{\'R} + \DeclareUnicodeCharacter{0155}{\'r} + \DeclareUnicodeCharacter{0158}{\v{R}} + \DeclareUnicodeCharacter{0159}{\v{r}} + \DeclareUnicodeCharacter{015A}{\'S} + \DeclareUnicodeCharacter{015B}{\'s} + \DeclareUnicodeCharacter{015C}{\^S} + \DeclareUnicodeCharacter{015D}{\^s} + \DeclareUnicodeCharacter{015E}{\cedilla{S}} + \DeclareUnicodeCharacter{015F}{\cedilla{s}} + + \DeclareUnicodeCharacter{0160}{\v{S}} + \DeclareUnicodeCharacter{0161}{\v{s}} + \DeclareUnicodeCharacter{0162}{\cedilla{t}} + \DeclareUnicodeCharacter{0163}{\cedilla{T}} + \DeclareUnicodeCharacter{0164}{\v{T}} + + \DeclareUnicodeCharacter{0168}{\~U} + \DeclareUnicodeCharacter{0169}{\~u} + \DeclareUnicodeCharacter{016A}{\=U} + \DeclareUnicodeCharacter{016B}{\=u} + \DeclareUnicodeCharacter{016C}{\u{U}} + \DeclareUnicodeCharacter{016D}{\u{u}} + \DeclareUnicodeCharacter{016E}{\ringaccent{U}} + \DeclareUnicodeCharacter{016F}{\ringaccent{u}} + + \DeclareUnicodeCharacter{0170}{\H{U}} + \DeclareUnicodeCharacter{0171}{\H{u}} + \DeclareUnicodeCharacter{0174}{\^W} + \DeclareUnicodeCharacter{0175}{\^w} + \DeclareUnicodeCharacter{0176}{\^Y} + \DeclareUnicodeCharacter{0177}{\^y} + \DeclareUnicodeCharacter{0178}{\"Y} + \DeclareUnicodeCharacter{0179}{\'Z} + \DeclareUnicodeCharacter{017A}{\'z} + \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} + \DeclareUnicodeCharacter{017C}{\dotaccent{z}} + \DeclareUnicodeCharacter{017D}{\v{Z}} + \DeclareUnicodeCharacter{017E}{\v{z}} + + \DeclareUnicodeCharacter{01C4}{D\v{Z}} + \DeclareUnicodeCharacter{01C5}{D\v{z}} + \DeclareUnicodeCharacter{01C6}{d\v{z}} + \DeclareUnicodeCharacter{01C7}{LJ} + \DeclareUnicodeCharacter{01C8}{Lj} + \DeclareUnicodeCharacter{01C9}{lj} + \DeclareUnicodeCharacter{01CA}{NJ} + \DeclareUnicodeCharacter{01CB}{Nj} + \DeclareUnicodeCharacter{01CC}{nj} + \DeclareUnicodeCharacter{01CD}{\v{A}} + \DeclareUnicodeCharacter{01CE}{\v{a}} + \DeclareUnicodeCharacter{01CF}{\v{I}} + + \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} + \DeclareUnicodeCharacter{01D1}{\v{O}} + \DeclareUnicodeCharacter{01D2}{\v{o}} + \DeclareUnicodeCharacter{01D3}{\v{U}} + \DeclareUnicodeCharacter{01D4}{\v{u}} + + \DeclareUnicodeCharacter{01E2}{\={\AE}} + \DeclareUnicodeCharacter{01E3}{\={\ae}} + \DeclareUnicodeCharacter{01E6}{\v{G}} + \DeclareUnicodeCharacter{01E7}{\v{g}} + \DeclareUnicodeCharacter{01E8}{\v{K}} + \DeclareUnicodeCharacter{01E9}{\v{k}} + + \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} + \DeclareUnicodeCharacter{01F1}{DZ} + \DeclareUnicodeCharacter{01F2}{Dz} + \DeclareUnicodeCharacter{01F3}{dz} + \DeclareUnicodeCharacter{01F4}{\'G} + \DeclareUnicodeCharacter{01F5}{\'g} + \DeclareUnicodeCharacter{01F8}{\`N} + \DeclareUnicodeCharacter{01F9}{\`n} + \DeclareUnicodeCharacter{01FC}{\'{\AE}} + \DeclareUnicodeCharacter{01FD}{\'{\ae}} + \DeclareUnicodeCharacter{01FE}{\'{\O}} + \DeclareUnicodeCharacter{01FF}{\'{\o}} + + \DeclareUnicodeCharacter{021E}{\v{H}} + \DeclareUnicodeCharacter{021F}{\v{h}} + + \DeclareUnicodeCharacter{0226}{\dotaccent{A}} + \DeclareUnicodeCharacter{0227}{\dotaccent{a}} + \DeclareUnicodeCharacter{0228}{\cedilla{E}} + \DeclareUnicodeCharacter{0229}{\cedilla{e}} + \DeclareUnicodeCharacter{022E}{\dotaccent{O}} + \DeclareUnicodeCharacter{022F}{\dotaccent{o}} + + \DeclareUnicodeCharacter{0232}{\=Y} + \DeclareUnicodeCharacter{0233}{\=y} + \DeclareUnicodeCharacter{0237}{\dotless{j}} + + \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} + \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} + \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} + \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} + \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} + \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} + \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} + \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} + \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} + \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} + \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} + \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} + + \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} + \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} + + \DeclareUnicodeCharacter{1E20}{\=G} + \DeclareUnicodeCharacter{1E21}{\=g} + \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} + \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} + \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} + \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} + \DeclareUnicodeCharacter{1E26}{\"H} + \DeclareUnicodeCharacter{1E27}{\"h} + + \DeclareUnicodeCharacter{1E30}{\'K} + \DeclareUnicodeCharacter{1E31}{\'k} + \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} + \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} + \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} + \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} + \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} + \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} + \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} + \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} + \DeclareUnicodeCharacter{1E3E}{\'M} + \DeclareUnicodeCharacter{1E3F}{\'m} + + \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} + \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} + \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} + \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} + \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} + \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} + \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} + \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} + \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} + \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} + + \DeclareUnicodeCharacter{1E54}{\'P} + \DeclareUnicodeCharacter{1E55}{\'p} + \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} + \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} + \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} + \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} + \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} + \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} + \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} + \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} + + \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} + \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} + \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} + \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} + \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} + \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} + \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} + \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} + \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} + \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} + + \DeclareUnicodeCharacter{1E7C}{\~V} + \DeclareUnicodeCharacter{1E7D}{\~v} + \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} + \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} + + \DeclareUnicodeCharacter{1E80}{\`W} + \DeclareUnicodeCharacter{1E81}{\`w} + \DeclareUnicodeCharacter{1E82}{\'W} + \DeclareUnicodeCharacter{1E83}{\'w} + \DeclareUnicodeCharacter{1E84}{\"W} + \DeclareUnicodeCharacter{1E85}{\"w} + \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} + \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} + \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} + \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} + \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} + \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} + \DeclareUnicodeCharacter{1E8C}{\"X} + \DeclareUnicodeCharacter{1E8D}{\"x} + \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} + \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} + + \DeclareUnicodeCharacter{1E90}{\^Z} + \DeclareUnicodeCharacter{1E91}{\^z} + \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} + \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} + \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} + \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} + \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} + \DeclareUnicodeCharacter{1E97}{\"t} + \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} + \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} + + \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} + \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} + + \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} + \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} + \DeclareUnicodeCharacter{1EBC}{\~E} + \DeclareUnicodeCharacter{1EBD}{\~e} + + \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} + \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} + \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} + \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} + + \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} + \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} + + \DeclareUnicodeCharacter{1EF2}{\`Y} + \DeclareUnicodeCharacter{1EF3}{\`y} + \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} + + \DeclareUnicodeCharacter{1EF8}{\~Y} + \DeclareUnicodeCharacter{1EF9}{\~y} + + \DeclareUnicodeCharacter{2013}{--} + \DeclareUnicodeCharacter{2014}{---} + \DeclareUnicodeCharacter{2022}{\bullet} + \DeclareUnicodeCharacter{2026}{\dots} + \DeclareUnicodeCharacter{20AC}{\euro} + + \DeclareUnicodeCharacter{2192}{\expansion} + \DeclareUnicodeCharacter{21D2}{\result} + + \DeclareUnicodeCharacter{2212}{\minus} + \DeclareUnicodeCharacter{2217}{\point} + \DeclareUnicodeCharacter{2261}{\equiv} +}% end of \utfeightchardefs + + +% US-ASCII character definitions. +\def\asciichardefs{% nothing need be done + \relax +} + +% Make non-ASCII characters printable again for compatibility with +% existing Texinfo documents that may use them, even without declaring a +% document encoding. +% +\setnonasciicharscatcode \other + + +\message{formatting,} + +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; +% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; +% 7) physical page height; 8) physical page width. +% +% We also call \setleading{\textleading}, so the caller should define +% \textleading. The caller should also set \parskip. +% +\def\internalpagesizes#1#2#3#4#5#6#7#8{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \ifpdf + \pdfpageheight #7\relax + \pdfpagewidth #8\relax + \fi + % + \setleading{\textleading} + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}% + {\voffset}{.25in}% + {\bindingoffset}{36pt}% + {11in}{8.5in}% +}} + +% Use @smallbook to reset parameters for 7x9.25 trim size. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.5in}{5in}% + {\voffset}{.25in}% + {\bindingoffset}{16pt}% + {9.25in}{7in}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .5cm +}} + +% Use @smallerbook to reset parameters for 6x9 trim size. +% (Just testing, parameters still in flux.) +\def\smallerbook{{\globaldefs = 1 + \parskip = 1.5pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.4in}{4.8in}% + {-.2in}{-.4in}% + {0pt}{14pt}% + {9in}{6in}% + % + \lispnarrowing = 0.25in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .4cm +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % Double-side printing via postscript on Laserjet 4050 + % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. + % To change the settings for a different printer or situation, adjust + % \normaloffset until the front-side and back-side texts align. Then + % do the same for \bindingoffset. You can set these for testing in + % your texinfo source file like this: + % @tex + % \global\normaloffset = -6mm + % \global\bindingoffset = 10mm + % @end tex + \internalpagesizes{51\baselineskip}{160mm} + {\voffset}{\hoffset}% + {\bindingoffset}{44pt}% + {297mm}{210mm}% + % + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = 5mm +}} + +% Use @afivepaper to print on European A5 paper. +% From romildo@urano.iceb.ufop.br, 2 July 2000. +% He also recommends making @example and @lisp be small. +\def\afivepaper{{\globaldefs = 1 + \parskip = 2pt plus 1pt minus 0.1pt + \textleading = 12.5pt + % + \internalpagesizes{160mm}{120mm}% + {\voffset}{\hoffset}% + {\bindingoffset}{8pt}% + {210mm}{148mm}% + % + \lispnarrowing = 0.2in + \tolerance = 800 + \hfuzz = 1.2pt + \contentsrightmargin = 0pt + \defbodyindent = 2mm + \tableindent = 12mm +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. +\def\afourlatex{{\globaldefs = 1 + \afourpaper + \internalpagesizes{237mm}{150mm}% + {\voffset}{4.6mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + % + % Must explicitly reset to 0 because we call \afourpaper. + \globaldefs = 0 +}} + +% Use @afourwide to print on A4 paper in landscape format. +\def\afourwide{{\globaldefs = 1 + \afourpaper + \internalpagesizes{241mm}{165mm}% + {\voffset}{-2.95mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + \globaldefs = 0 +}} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\parseargdef\pagesizes{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{\textleading}% + % + \dimen0 = #1 + \advance\dimen0 by \voffset + % + \dimen2 = \hsize + \advance\dimen2 by \normaloffset + % + \internalpagesizes{#1}{\hsize}% + {\voffset}{\normaloffset}% + {\bindingoffset}{44pt}% + {\dimen0}{\dimen2}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\catcode`\$=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} +\def\normaldollar{$}%$ font-lock fix + +% This macro is used to make a character print one way in \tt +% (where it can probably be output as-is), and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +\let\realunder=_ +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +\catcode`\$=\active +\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +% Used sometimes to turn off (effectively) the active characters even after +% parsing them. +\def\turnoffactive{% + \normalturnoffactive + \otherbackslash +} + +\catcode`\@=0 + +% \backslashcurfont outputs one backslash character in current font, +% as in \char`\\. +\global\chardef\backslashcurfont=`\\ +\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work + +% \realbackslash is an actual character `\' with catcode other, and +% \doublebackslash is two of them (for the pdf outlines). +{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} + +% In texinfo, backslash is an active character; it prints the backslash +% in fixed width font. +\catcode`\\=\active +@def@normalbackslash{{@tt@backslashcurfont}} +% On startup, @fixbackslash assigns: +% @let \ = @normalbackslash + +% \rawbackslash defines an active \ to do \backslashcurfont. +% \otherbackslash defines an active \ to be a literal `\' character with +% catcode other. +@gdef@rawbackslash{@let\=@backslashcurfont} +@gdef@otherbackslash{@let\=@realbackslash} + +% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of +% the literal character `\'. +% +@def@normalturnoffactive{% + @let\=@normalbackslash + @let"=@normaldoublequote + @let~=@normaltilde + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let<=@normalless + @let>=@normalgreater + @let+=@normalplus + @let$=@normaldollar %$ font-lock fix + @unsepspaces +} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\' in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also turn back on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active + @catcode`@_=@active +} + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These look ok in all fonts, so just make them not special. +@catcode`@& = @other +@catcode`@# = @other +@catcode`@% = @other + + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: + +@c vim:sw=2: + +@ignore + arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 +@end ignore diff --git a/comm/third_party/libgcrypt/cipher/ChangeLog-2011 b/comm/third_party/libgcrypt/cipher/ChangeLog-2011 new file mode 100644 index 0000000000..1ce6bd1e68 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ChangeLog-2011 @@ -0,0 +1,4279 @@ +2011-12-01 Werner Koch + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2011-09-16 Werner Koch + + * primegen.c (_gcry_primegen_init): New. + +2011-09-15 Werner Koch + + * cipher-cbc.c, cipher-cfb.c, cipher-ofb.c, cipher-ctr.c: New. + * cipher-aeswrap.c: New. + * cipher-internal.h: New. + * cipher.c (cipher_context_alignment_t, struct gcry_cipher_handle) + (CTX_MAGIC_NORMAL, CTX_MAGIC_SECURE, NEED_16BYTE_ALIGNED_CONTEXT) + (MAX_BLOCKSIZE): Move to cipher-internal.h. + (do_aeswrap_encrypt, do_aeswrap_encrypt) + (do_cbc_encrypt, do_cbc_decrypt, do_ctr_encrypt, do_ctr_decrypt) + (do_ofb_encrypt, do_ofb_decrypt, do_ctr_encrypt): Move to the + respective new cipher-foo.c files. + (do_ctr_decrypt): Remove. + +2011-09-15 Werner Koch + + * pubkey.c (gcry_pk_list): Remove. + (gcry_pk_unregister): Remove. + * md.c (gcry_md_list): Remove. + (gcry_md_unregister): Remove. + * cipher.c (gcry_cipher_list): Remove. + (gcry_cipher_unregister): Remove. + * ac.c: Remove. + +2011-06-29 Werner Koch + + * cipher.c (cipher_get_keylen): Return zero for an invalid algorithm. + (cipher_get_blocksize): Ditto. + +2011-06-13 Werner Koch + + * dsa.c (selftest_sign_1024): Use the raw and not the pkcs1 flag. + + * pubkey.c (gcry_pk_sign): Special case output generation for PKCS1. + (sexp_data_to_mpi): Parse "random-override" for pkcs1 encryption. + (pkcs1_encode_for_encryption): Add args RANDOM_OVERRIDE and + RANDOM_OVERRIDE_LEN. + (gcry_pk_encrypt): Special case output generation for PKCS1. + (sexp_data_to_mpi): Use GCRYMPI_FMT_USG for raw encoding. + +2011-06-10 Werner Koch + + * pubkey.c (gcry_pk_sign): Use format specifier '%M' to avoid + leading zeroes. Special case output generation for PSS. + (gcry_pk_encrypt): Special case output generation for OAEP. + (sexp_data_to_mpi): Use GCRYMPI_FMT_USG for PSS verify. + +2011-06-09 Werner Koch + + * pubkey.c (oaep_decode): Make use of octet_string_from_mpi. + (sexp_to_enc): Skip "random-override". + + * pubkey.c (oaep_encode, pss_encode): Add args RANDOM_OVERRIDE and + RANDOM_OVERRIDE_LEN. + (sexp_data_to_mpi): Extract new random-override parameter. + + * pubkey.c (pss_encode, pss_verify): Use VALUE verbatim for MHASH. + (octet_string_from_mpi): Add arg SPACE. + +2011-06-08 Werner Koch + + * pubkey.c (pss_encode, pss_verify): Restructure and comment code + to match rfc-3447. Replace secure allocs by plain allocs and + wipememory. Use gcry_md_hash_buffer. + (octet_string_from_mpi): New. + +2011-06-03 Werner Koch + + * pubkey.c (oaep_decode): Add more comments and restructure to + match the description in RFC-3447. + (oaep_encode): Check for mgf1 error. s/dlen/hlen/. + +2011-05-31 Werner Koch + + * pubkey.c (mgf1): Optimize by using gcry_md_reset. Re-implement + for easier readability. + (oaep_encode): Add more comments and restructure to match the + description in RFC-3447. + + * pubkey.c (pkcs1_encode_for_signature, oaep_decode): Change + return value from one MPI to a buffer. + (gcry_pk_decrypt): Adjust for this change. + +2011-05-30 Werner Koch + + * pubkey.c (pkcs1_decode_for_encryption): Change handling of + leading zero byte. + +2011-05-27 Daiki Ueno + + * pubkey.c (gcry_pk_decrypt): Fix double-free when un-padding + invalid data. Thanks to Tom Ritter. + +2011-05-24 Daiki Ueno + + * rsa.c (rsa_verify): Use CMP if given, to check the decrypted + sig. + + * pubkey.c (sexp_to_enc, sexp_data_to_mpi): Factor out + CTX initialization to ... + (init_encoding_ctx): .. new. + (gcry_pk_verify): Pass verify func and the arg to pubkey_verify. + (pss_encode, pss_verify, pss_verify_cmp): New. + +2011-05-23 Daiki Ueno + + * pubkey.c (pkcs1_decode_for_encryption, oaep_decode): Fix memleak + when gcry_mpi_print fails. + +2011-05-18 Daiki Ueno + + * pubkey.c (sexp_data_to_mpi): Factor some code out to ... + (pkcs1_encode_for_encryption): .. new, + (pkcs1_encode_for_signature): .. new. + (pkcs1_decode_for_encryption): New. + (gcry_pk_decrypt): Do un-padding for PKCS#1 as well as OAEP. + (sexp_to_enc): Abolish "unpad" flag, which is not necessary since + we can do un-padding implicitly when "pkcs1" or "oaep" is given. + +2011-05-11 Werner Koch + + * pubkey.c (sexp_to_enc, sexp_data_to_mpi): Set LABEL to NULL + after free. + (sexp_to_enc, sexp_data_to_mpi): Do not allow multiple encoding + flags. + (oaep_encode, oaep_decode, sexp_to_key, sexp_to_sig) + (sexp_to_enc, sexp_data_to_mpi, gcry_pk_encrypt, gcry_pk_sign) + (gcry_pk_genkey, _gcry_pk_get_elements): Replace access to ERRNO + by gpg_err_code_from_syserror. + +2011-05-11 Daiki Ueno + + * pubkey.c (sexp_data_to_mpi): Factor some code out to ... + (get_hash_algo): .. new. + (mgf1, oaep_encode, oaep_decode): New. + (sexp_to_enc): Add arg CTX. Remove arg RET_WANT_PKCS1. Support + OAEP. + (sexp_data_to_mpi): Add arg CTX. Support OAEP. + (gcry_pk_encrypt): Pass a CTX to sexp_data_to_mpi. + (gcry_pk_decrypt): Pass a CTX tp sexp_to_enc and replace + WANT_PKCS1. Implement unpadding for OAEP. + (gcry_pk_sign): Pass NULL for CTX arg of sexp_data_to_mpi. + (gcry_pk_verify): Ditto. + +2011-04-19 Werner Koch + + * cipher.c (gcry_cipher_open): Replace gpg_err_code_from_errno by + gpg_err_code_from_syserror. + +2011-04-11 Werner Koch + + * pubkey.c (gcry_pk_get_keygrip): Avoid double free of L2. + + * cipher.c (_gcry_cipher_setctr): Clear unused lastiv info. + (gcry_cipher_ctl) : Implement by calling + _gcry_cipher_setctr. + (do_ctr_encrypt): Save last counter and reuse it. + + * cipher.c (do_ctr_encrypt): Allow arbitrary length inputs to + match the 1.4 behaviour. + +2011-04-04 Werner Koch + + * ecc.c (compute_keygrip): Release L1 while parsing "curve". + + * pubkey.c (gcry_pk_get_keygrip): Always release NAME and L2. + Reported by Ben Kibbey. + +2011-03-28 Werner Koch + + * primegen.c (_gcry_generate_elg_prime): Make sure that PRIME is + NULL if the called func ever returns an error. + + * pubkey.c (gcry_pk_decrypt): Remove unused var PUBKEY. + +2011-03-09 Werner Koch + + * kdf.c: New. + +2011-02-22 Werner Koch + + * rijndael.c (aesni_cleanup_2_4): New. + (aesenc_xmm1_xmm0, do_aesni_ctr_4): New. + (_gcry_aes_ctr_enc): New. + * cipher.c (struct gcry_cipher_handle): Add CTR_ENC. Move field + CTR into an u_ctr union and adjust all users. + (gcry_cipher_open): Use _gcry_aes_ctr_enc. + (do_ctr_encrypt): Use bulk mode. + +2011-02-18 Werner Koch + + * rijndael.c (u32_a_t): New. + (do_encrypt_aligned, do_encrypt_aligned): Use the new type to + avoid problems with strict aliasing rules. + +2011-02-16 Werner Koch + + * rijndael.c (do_aesni_cfb) [USE_AESNI]: New. + (_gcry_aes_cfb_enc, _gcry_aes_cfb_dec) [USE_AESNI]: Use new fucntion. + +2011-02-15 Werner Koch + + * rijndael.c (do_aesni_enc_aligned, do_aesni_dec_aligned): Use + movdqa for the key but keep using movdqu for the data. + (do_aesni): Remove alignment detection. Don't burn the stack. + (aesni_prepare, aesni_cleanup): New macros. + (rijndael_encrypt, _gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (rijndael_decrypt, _gcry_aes_cfb_dec, _gcry_aes_cbc_dec): Use + these macros. Don't burn the stack in the USE_AESNI case. + (do_setkey): Add disabled code to use aeskeygenassist. + +2011-02-14 Werner Koch + + * rijndael.c (ATTR_ALIGNED_16): New + (do_aesni): Do not copy if already aligned. + (do_encrypt, do_decrypt): Ditto. + (rijndael_decrypt, rijndael_encrypt): Increase stack burning amount. + + * rijndael.c (RIJNDAEL_context): Reorder fields. Change fieldname + ROUNDS to rounds. Move padlock_key into u1. + (keySched, keySched2): Rename macros to keyscherr and keyschdec + and change all users. + (padlockkey): New macro. Change all users of padlock_key. + * cipher.c (NEED_16BYTE_ALIGNED_CONTEXT): Always define if using gcc. + (struct gcry_cipher_handle): Align U_IV to at least 16 byte. + +2011-02-13 Werner Koch + + * rijndael.c (USE_AESNI): New. Define for ia32 and gcc >= 4. + (m128i_t) [USE_AESNI]: New. + (RIJNDAEL_context) [USE_AESNI]: Add field use_aesni. + (do_setkey): Set USE_AESNI for all key lengths. + (prepare_decryption) [USE_AESNI]: Use aesimc instn if requested. + (do_aesni_enc_aligned, do_aesni_dec_aligned) + (do_aesni) [USE_AESNI]: New. + (rijndael_encrypt, _gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (rijndael_decrypt, _gcry_aes_cfb_dec) + (_gcry_aes_cbc_dec) [USE_AESNI]: Use do_aesni. + +2011-02-01 Werner Koch + + * pubkey.c (gcry_pk_get_curve): New. + (sexp_to_key): Add arg OVERRIDE_ELEMS. + (sexp_elements_extract_ecc): Allow for params only. + (gcry_pk_get_param): New. + * ecc.c (ecc_get_curve): New. + (ecc_get_param_sexp): New. + +2011-01-28 Werner Koch + + * pubkey.c (gcry_pk_genkey): Hack to insert the used curve name. + +2011-01-27 Werner Koch + + * ecc.c (fill_in_curve): Remove. + (generate_curve): Rename to .. + (fill_in_curve): this. Remove setting of NAME_OID. + (ecc_encrypt_raw): Change name of arg DATA to K for better + readability. Use ECC_public_key instead of ECC_secret_key. + Require a caller to pass a complete pkey array. + (ecc_decrypt_raw): Require a caller to pass a complete skey array. + (elliptic_curve_t): Add field NAME. + (fill_in_curve): Set field. + (generate_key): Add arg R_USED_CURVE. + (ecc_generate_ext): Return used curve name. + +2011-01-13 Andrey Jivsov (wk) + + * ecc.c (ec2os): Do not free passed parameters X and Y. Adjust + callers. + (ecc_encrypt_raw, ecc_decrypt_raw): New. + (ecdh_names, _gcry_pubkey_spec_ecdh): New. + * pubkey.c (pubkey_table): Support ECDH. + +2010-08-19 Werner Koch + + * cipher.c (gcry_cipher_open): Remove double release of the module. + Fixes bug#1263. + +2010-06-10 Jeff Johnson (wk) + + * ecc.c (ecc_generate_ext): Parse transient-key flag. + (generate_key): Add arg TRANSIENT_KEY and use it to set the random + level. + +2010-04-12 Brad Hards (wk) + + Spelling fixes. + +2010-03-26 Werner Koch + + * tiger.c (asn): Unfetter the old TIGER from an OID. + (TIGER_CONTEXT): Add field VARIANT. + (tiger_init): Factor code out to ... + (do_init): New. + (tiger1_init, tiger2_init): New. + (_gcry_digest_spec_tiger1, _gcry_digest_spec_tiger2): New. + * md.c (digest_table): Add TIGER1 and TIGER2 variants. + +2009-12-11 Werner Koch + + * sha256.c (Cho, Maj, Sum0, Sum1): Turn macros into inline + functions. + (transform): Partly unroll to interweave the chain variables + + * sha512.c (ROTR, Ch, Maj, Sum0, Sum1): Turn macros into inline + functions. + (transform): Partly unroll to interweave the chain variables. + Suggested by Christian Grothoff. + +2009-12-10 Werner Koch + + * Makefile.am (o_flag_munging): New. + (tiger.o, tiger.lo): Use it. + + * cipher.c (do_ctr_encrypt): Add arg OUTBUFLEN. Check for + suitable value. Add check for valid inputlen. Wipe temporary + memory. + (do_ctr_decrypt): Likewise. + (do_cbc_encrypt, do_cbc_decrypt): Add arg OUTBUFLEN. Check for + suitable value. Move check for valid inputlen to here; change + returned error from INV_ARG to INV_LENGTH. + (do_ecb_encrypt, do_ecb_decrypt): Ditto. + (do_cfb_encrypt, do_cfb_decrypt): Ditto. + (do_ofb_encrypt, do_ofb_decrypt): Ditto. + (cipher_encrypt, cipher_encrypt): Adjust for above changes. + (gcry_cipher_encrypt, gcry_cipher_decrypt): Simplify. + +2009-12-09 Werner Koch + + * cipher.c (gcry_cipher_open): Allow for GCRY_CIPHER_MODE_AESWRAP. + (cipher_encrypt, cipher_decrypt): Ditto. + (do_aeswrap_encrypt, do_aeswrap_decrypt): New. + (struct gcry_cipher_handle): Add field marks. + (cipher_setkey, cipher_setiv): Update marks flags. + (cipher_reset): Reset marks. + (cipher_encrypt, cipher_decrypt): Add new arg OUTBUFLEN. + (gcry_cipher_encrypt, gcry_cipher_decrypt): Pass outbuflen to + cipher_encrypt. Replace GPG_ERR_TOO_SHORT by + GPG_ERR_BUFFER_TOO_SHORT. + +2009-08-21 Werner Koch + + * dsa.c (dsa_generate_ext): Release retfactors array before + setting it to NULL. Reported by Daiko Ueno. + +2009-07-02 Werner Koch + + * md.c (md_read): Fix incomplete check for NULL. + Reported by Fabian Kail. + +2009-03-31 Werner Koch + + * rsa.c (rsa_check_secret_key): Return GPG_ERR_BAD_SECKEY and not + GPG_ERR_PUBKEY_ALGO. + +2009-02-16 Werner Koch + + * rsa.c (generate_x931): Do not initialize TBL with automatic + variables. + * whirlpool.c, tiger.c, sha256.c, sha1.c, rmd160.c, md5.c + * md4.c, crc.c: Remove memory.h. This is garbage from gnupg. + Reported by Dan Fandrich. + +2009-01-22 Werner Koch + + * ecc.c (compute_keygrip): Remove superfluous const. + +2009-01-06 Werner Koch + + * rmd160.c (oid_spec_rmd160): Add TeleTrust identifier. + +2008-12-10 Werner Koch + + * dsa.c (generate): Add arg DOMAIN and use it if specified. + (generate_fips186): Ditto. + (dsa_generate_ext): Parse and check the optional "domain" + parameter and pass them to the generate functions. + + * rijndael.c (rijndael_names): Add "AES128" and "AES-128". + (rijndael192_names): Add "AES-192". + (rijndael256_names): Add "AES-256". + +2008-12-05 Werner Koch + + * dsa.c (generate): Add arg TRANSIENT_KEY and use it to detrmine + the RNG quality needed. + (dsa_generate_ext): Parse the transient-key flag und pass it to + generate. + +2008-11-28 Werner Koch + + * dsa.c (generate_fips186): Add arg DERIVEPARMS and use the seed + value if available. + + * primegen.c (_gcry_generate_fips186_2_prime): Fix inner p loop. + +2008-11-26 Werner Koch + + * primegen.c (_gcry_generate_fips186_3_prime): New. + * dsa.c (generate_fips186): Add arg USE_FIPS186_2. + (dsa_generate_ext): Parse new flag use-fips183-2. + +2008-11-25 Werner Koch + + * dsa.c (generate_fips186): New. + (dsa_generate_ext): Use new function if derive-parms are given or + if in FIPS mode. + * primegen.c (_gcry_generate_fips186_2_prime): New. + +2008-11-24 Werner Koch + + * pubkey.c (gcry_pk_genkey): Insert code to output extrainfo. + (pubkey_generate): Add arg R_EXTRAINFO and pass it to the extended + key generation function. + * rsa.c (gen_x931_parm_xp, gen_x931_parm_xi): New. + (generate_x931): Generate params if not given. + (rsa_generate_ext): Parse use-x931 flag. Return p-q-swapped + indicator. + * dsa.c (dsa_generate_ext): Put RETFACTORS into R_EXTRAINFO if + possible. + + * pubkey.c (gcry_pk_genkey): Remove parsing of almost all + parameters and pass the parameter S-expression to pubkey_generate. + (pubkey_generate): Simplify by requitring modules to parse the + parameters. Remove the special cases for Elgamal and ECC. + (sexp_elements_extract_ecc): Add arg EXTRASPEC and use it. Fix + small memory leak. + (sexp_to_key): Pass EXTRASPEC to sexp_elements_extract_ecc. + (pubkey_table) [USE_ELGAMAL]: Add real extraspec. + * rsa.c (rsa_generate_ext): Adjust for new calling convention. + * dsa.c (dsa_generate_ext): Ditto. + * elgamal.c (_gcry_elg_generate): Ditto. Rename to elg_generate_ext. + (elg_generate): New. + (_gcry_elg_generate_using_x): Remove after merging code with + elg_generate_ext. + (_gcry_pubkey_extraspec_elg): New. + (_gcry_elg_check_secret_key, _gcry_elg_encrypt, _gcry_elg_sign) + (_gcry_elg_verify, _gcry_elg_get_nbits): Make static and remove + _gcry_ prefix. + * ecc.c (_gcry_ecc_generate): Rename to ecc_generate_ext and + adjust for new calling convention. + (_gcry_ecc_get_param): Rename to ecc_get_param and make static. + (_gcry_pubkey_extraspec_ecdsa): Add ecc_generate_ext and + ecc_get_param. + +2008-11-20 Werner Koch + + * pubkey.c (pubkey_generate): Add arg DERIVEPARMS. + (gcry_pk_genkey): Parse derive-parms and pass it to above. + * rsa.c (generate_x931): New. + (rsa_generate_ext): Add arg DERIVEPARMS and call new function in + fips mode or if DERIVEPARMS is given. + * primegen.c (_gcry_derive_x931_prime, find_x931_prime): New. + +2008-11-19 Werner Koch + + * rsa.c (rsa_decrypt): Use gcry_create_nonce for blinding. + (generate): Rename to generate_std. + +2008-11-05 Werner Koch + + * md.c (md_open): Use a switch to set the Bsize. + (prepare_macpads): Fix long key case for SHA384 and SHA512. + + * cipher.c (gcry_cipher_handle): Add field EXTRASPEC. + (gcry_cipher_open): Set it. + (gcry_cipher_ctl): Add private control code to disable weak key + detection and to return the current input block. + * des.c (_tripledes_ctx): Add field FLAGS. + (do_tripledes_set_extra_info): New. + (_gcry_cipher_extraspec_tripledes): Add new function. + (do_tripledes_setkey): Disable weak key detection. + +2008-10-24 Werner Koch + + * md.c (digest_table): Allow MD5 in fips mode. + (md_register_default): Take special action for MD5. + (md_enable, gcry_md_hash_buffer): Ditto. + +2008-09-30 Werner Koch + + * rijndael.c (do_setkey): Properly align "t" and "tk". + (prepare_decryption): Properly align "w". Fixes bug #936. + +2008-09-18 Werner Koch + + * pubkey.c (gcry_pk_genkey): Parse domain parameter. + (pubkey_generate): Add new arg DOMAIN and remove special case for + DSA with qbits. + * rsa.c (rsa_generate): Add dummy args QBITS, NAME and DOMAIN and + rename to rsa_generate_ext. Change caller. + (_gcry_rsa_generate, _gcry_rsa_check_secret_key) + (_gcry_rsa_encrypt, _gcry_rsa_decrypt, _gcry_rsa_sign) + (_gcry_rsa_verify, _gcry_rsa_get_nbits): Make static and remove + _gcry_ prefix. + (_gcry_pubkey_spec_rsa, _gcry_pubkey_extraspec_rsa): Adjust names. + * dsa.c (dsa_generate_ext): New. + (_gcry_dsa_generate): Replace code by a call to dsa_generate. + (_gcry_dsa_check_secret_key, _gcry_dsa_sign, _gcry_dsa_verify) + (_gcry_dsa_get_nbits): Make static and remove _gcry prefix. + (_gcry_dsa_generate2): Remove. + (_gcry_pubkey_spec_dsa): Adjust to name changes. + (_gcry_pubkey_extraspec_rsa): Add dsa_generate_ext. + +2008-09-16 Werner Koch + + * ecc.c (run_selftests): Add arg EXTENDED. + +2008-09-12 Werner Koch + + * rsa.c (test_keys): Do a bad case signature check. + * dsa.c (test_keys): Do a bad case check. + + * cipher.c (_gcry_cipher_selftest): Add arg EXTENDED and pass it + to the called tests. + * md.c (_gcry_md_selftest): Ditto. + * pubkey.c (_gcry_pk_selftest): Ditto. + * rijndael.c (run_selftests): Add arg EXTENDED and pass it to the + called tests. + (selftest_fips_128): Add arg EXTENDED and run only one test + non-extended mode. + (selftest_fips_192): Add dummy arg EXTENDED. + (selftest_fips_256): Ditto. + * hmac-tests.c (_gcry_hmac_selftest): Ditto. + (run_selftests): Ditto. + (selftests_sha1): Add arg EXTENDED and run only one test + non-extended mode. + (selftests_sha224, selftests_sha256): Ditto. + (selftests_sha384, selftests_sha512): Ditto. + * sha1.c (run_selftests): Add arg EXTENDED and pass it to the + called test. + (selftests_sha1): Add arg EXTENDED and run only one test + non-extended mode. + * sha256.c (run_selftests): Add arg EXTENDED and pass it to the + called tests. + (selftests_sha224): Add arg EXTENDED and run only one test + non-extended mode. + (selftests_sha256): Ditto. + * sha512.c (run_selftests): Add arg EXTENDED and pass it to the + called tests. + (selftests_sha384): Add arg EXTENDED and run only one test + non-extended mode. + (selftests_sha512): Ditto. + * des.c (run_selftests): Add arg EXTENDED and pass it to the + called test. + (selftest_fips): Add dummy arg EXTENDED. + * rsa.c (run_selftests): Add dummy arg EXTENDED. + + * dsa.c (run_selftests): Add dummy arg EXTENDED. + + * rsa.c (extract_a_from_sexp): New. + (selftest_encr_1024): Check that the ciphertext does not match the + plaintext. + (test_keys): Improve tests and return an error status. + (generate): Return an error if test_keys fails. + * dsa.c (test_keys): Add comments and return an error status. + (generate): Return an error if test_keys failed. + +2008-09-11 Werner Koch + + * rsa.c (_gcry_rsa_decrypt): Return an error instead of calling + BUG in case of a practically impossible condition. + (sample_secret_key, sample_public_key): New. + (selftest_sign_1024, selftest_encr_1024): New. + (selftests_rsa): Implement tests. + * dsa.c (sample_secret_key, sample_public_key): New. + (selftest_sign_1024): New. + (selftests_dsa): Implement tests. + +2008-09-09 Werner Koch + + * hmac-tests.c (selftests_sha1): Add tests. + (selftests_sha224, selftests_sha384, selftests_sha512): Make up tests. + + * hash-common.c, hash-common.h: New. + * sha1.c (selftests_sha1): Add 3 tests. + * sha256.c (selftests_sha256, selftests_sha224): Ditto. + * sha512.c (selftests_sha512, selftests_sha384): Ditto. + +2008-08-29 Werner Koch + + * pubkey.c (gcry_pk_get_keygrip): Remove the special case for RSA + and check whether a custom computation function has been setup. + * rsa.c (compute_keygrip): New. + (_gcry_pubkey_extraspec_rsa): Setup this function. + * ecc.c (compute_keygrip): New. + (_gcry_pubkey_extraspec_ecdsa): Setup this function. + +2008-08-28 Werner Koch + + * cipher.c (cipher_decrypt, cipher_encrypt): Return an error if + mode NONE is used. + (gcry_cipher_open): Allow mode NONE only with a debug flag set and + if not in FIPS mode. + +2008-08-26 Werner Koch + + * pubkey.c (pubkey_generate): Add arg KEYGEN_FLAGS. + (gcry_pk_genkey): Implement new parameter "transient-key" and + pass it as flags to pubkey_generate. + (pubkey_generate): Make use of an ext_generate function. + * rsa.c (generate): Add new arg transient_key and pass appropriate + args to the prime generator. + (_gcry_rsa_generate): Factor all code out to ... + (rsa_generate): .. new func with extra arg KEYGEN_FLAGS. + (_gcry_pubkey_extraspec_ecdsa): Setup rsa_generate. + * primegen.c (_gcry_generate_secret_prime) + (_gcry_generate_public_prime): Add new arg RANDOM_LEVEL. + +2008-08-21 Werner Koch + + * primegen.c (_gcry_generate_secret_prime) + (_gcry_generate_public_prime): Use a constant macro for the random + level. + +2008-08-19 Werner Koch + + * pubkey.c (sexp_elements_extract_ecc) [!USE_ECC]: Do not allow + allow "curve" parameter. + +2008-08-15 Werner Koch + + * pubkey.c (_gcry_pk_selftest): New. + * dsa.c (selftests_dsa, run_selftests): New. + * rsa.c (selftests_rsa, run_selftests): New. + * ecc.c (selftests_ecdsa, run_selftests): New. + + * md.c (_gcry_md_selftest): New. + * sha1.c (run_selftests, selftests_sha1): New. + * sha256.c (selftests_sha224, selftests_sha256, run_selftests): New. + * sha512.c (selftests_sha384, selftests_sha512, run_selftests): New. + + * des.c (selftest): Remove static variable form selftest. + (des_setkey): No on-the-fly self test in fips mode. + (tripledes_set3keys): Ditto. + + * cipher.c (_gcry_cipher_setkey, _gcry_cipher_setiv): + + * dsa.c (generate): Bail out in fips mode if NBITS is less than 1024. + * rsa.c (generate): Return an error code if the the requested size + is less than 1024 and we are in fpis mode. + (_gcry_rsa_generate): Take care of that error code. + + * ecc.c (generate_curve): In fips mode enable only NIST curves. + + * cipher.c (_gcry_cipher_selftest): New. + + * sha512.c (_gcry_digest_extraspec_sha384) + (_gcry_digest_extraspec_sha512): New. + * sha256.c (_gcry_digest_extraspec_sha224) + (_gcry_digest_extraspec_sha256): New. + * sha1.c (_gcry_digest_extraspec_sha1): New. + * ecc.c (_gcry_pubkey_extraspec_ecdsa): New. + * dsa.c (_gcry_pubkey_extraspec_dsa): New. + * rsa.c (_gcry_pubkey_extraspec_rsa): New. + * rijndael.c (_gcry_cipher_extraspec_aes) + (_gcry_cipher_extraspec_aes192, _gcry_cipher_extraspec_aes256): New. + * des.c (_gcry_cipher_extraspec_tripledes): New. + + * cipher.c (gcry_cipher_register): Rename to _gcry_cipher_register. + Add arg EXTRASPEC. + (dummy_extra_spec): New. + (cipher_table_entry): Add extraspec field. + * md.c (_gcry_md_register): Rename to _gcry_md_register. Add + arg EXTRASPEC. + (dummy_extra_spec): New. + (digest_table_entry): Add extraspec field. + * pubkey.c (gcry_pk_register): Rename to _gcry_pk_register. Add + arg EXTRASPEC. + (dummy_extra_spec): New. + (pubkey_table_entry): Add extraspec field. + + * ac.c: Let most public functions return GPG_ERR_UNSUPPORTED in + fips mode. + + * pubkey.c (pubkey_table_entry): Add field FIPS_ALLOWED and mark + appropriate algorithms. + (dummy_generate, dummy_check_secret_key, dummy_encrypt) + (dummy_decrypt, dummy_sign, dummy_verify, dummy_get_nbits): Signal + a fips error when used. + (gcry_pk_register): In fips mode do not allow to register new + algorithms. + + * md.c (digest_table): Add field FIPS_ALLOWED and mark appropriate + algorithms. + (md_register_default): In fips mode register only fips algorithms. + (gcry_md_register): In fips mode do not allow to register new + algorithms. + (gcry_md_get): Signal a fips error if called. + (gcry_md_hash_buffer): Do not allow rmd160 when not in fips mode. + (md_start_debug): Disable in fips_mode. + + * md.c (gcry_md_register_default): Rename to .. + (md_register_default): .. this. + (md_digest): Remove this commented fucntion. + * pubkey.c (gcry_pk_register_default): Rename to .. + (pk_register_default): .. this. + + * cipher.c (cipher_table_entry): Add field FIPS_ALLOWED. + (gcry_cipher_register_default): Register only fips approved + algorithms. + (gcry_cipher_register): Do not allow to register new ciphers. + (cipher_setiv): Signal fips error. + + * cipher (gcry_cipher_register_default): Rename to .. + (cipher_register_default): .. this. + (REGISTER_DEFAULT_CIPHERS): Adjust for that change. + +2008-07-05 Werner Koch + + * random-daemon.c, random.h, rndhw.c, rndunix.c, rand-internal.h + * random.c, rndegd.c, rndlinux.c, rndw32.c: Move to ../cipher. + * Makefile.am: Remove random stuff. + +2008-06-24 Szakats Istvan (wk) + + * ac.c (_gcry_ac_key_destroy, _gcry_ac_key_pair_generate): Relase + some more memory. + +2008-04-22 Werner Koch + + * rijndael.c (_gcry_aes_cfb_enc, _gcry_aes_cbc_enc) + (_gcry_aes_cfb_dec, _gcry_aes_cbc_dec): Use Padlock if possible. + +2008-04-18 Werner Koch + + * sha1.c (transform_aligned): Remove. That is will obviosuly not + work because we need a scratch working area and our internal API + does not allow to modify the buffers. + + * rijndael.c: Factor tables out to .. + * rijndael-tables.h: .. new. + + * ac.c (ac_data_extract): Make static. + + * camellia.h [HAVE_CONFIG_H]: Include config.h. + + * rndw32.c (registry_poll): Only print the performance data + problem warning once. Suggested by Simon Josefsson. + +2008-03-19 Werner Koch + + * cipher.c (gcry_cipher_open) [USE_AES]: Init bulk encryption only + if requested. Suggested by Dirk Stoecker. + +2008-03-18 Werner Koch + + * sha1.c: Include stdint.h. + (transform): Add arg NBLOCKS so that we can work on more than one + block and avoid updates of the chaining variables. Changed all + callers to use 1. + (sha1_write): Replace loop around transform. + (transform_aligned) [WORDS_BIGENDIAN]: New. + (TRANSFORM): New macro to replace all direct calls of transform. + +2008-03-17 Werner Koch + + * rijndael.c (_gcry_aes_cfb_dec): New. + (do_encrypt): Factor code out to .. + (do_encrypt_aligned): .. New. + (_gcry_aes_cfb_enc, _gcry_aes_cfb_dec): Use new function. + (do_decrypt): Factor code out to .. + (do_decrypt_aligned): .. new. + (_gcry_aes_cbc_enc, _gcry_aes_cbc_dec): New. + * cipher.c (struct gcry_cipher_handle): Put field IV into new + union U_IV to enforce proper alignment. Change all users. + (do_cfb_decrypt): Optimize. + (do_cbc_encrypt, do_cbc_decrypt): Optimize. + +2008-03-15 Werner Koch + + * rijndael.c (_gcry_aes_cfb_enc): New. + * cipher.c (struct gcry_cipher_handle): Add field ALGO and BULK. + (gcry_cipher_open): Set ALGO and BULK. + (do_cfb_encrypt): Optimize. + +2008-02-18 Werner Koch + + * rsa.c (_gcry_rsa_verify) [IS_DEVELOPMENT_VERSION]: Print + intermediate results. + +2008-01-08 Werner Koch + + * random.c (add_randomness): Do not just increment + POOL_FILLED_COUNTER but update it by the actual amount of data. + +2007-12-13 Werner Koch + + * pubkey.c (sexp_data_to_mpi): Support SHA-224. + +2007-12-05 Werner Koch + + * rijndael.c (USE_PADLOCK): Depend on ENABLE_PADLOCK_SUPPORT. + * rndhw.c (USE_PADLOCK): Ditto + + * rsa.c (secret): Fixed condition test for using CRT. Reported by + Dean Scarff. Fixes bug#864. + (_gcry_rsa_check_secret_key): Return an erro if the optional + parameters are missing. + * pubkey.c (sexp_elements_extract): Add arg ALGO_NAME. Changed all + callers to pass NULL. Add hack to allow for optional RSA + parameters. + (sexp_to_key): Pass algo name to sexp_elements_extract. + +2007-12-03 Werner Koch + + * random.c (gcry_random_add_bytes): Implement it. + * rand-internal.h (RANDOM_ORIGIN_EXTERNAL): New. + +2007-11-30 Werner Koch + + * rndhw.c: New. + * rndlinux.c (_gcry_rndlinux_gather_random): Try to read 50% + directly from the hwrng. + * random.c (do_fast_random_poll): Also run the hw rng fast poll. + (_gcry_random_dump_stats): Tell whether the hw rng failed. + +2007-11-29 Werner Koch + + * rijndael.c (USE_PADLOCK): Define new macro used for ia32. + (RIJNDAEL_context) [USE_PADLOCK]: Add fields USE_PADLOCK and + PADLOCK_KEY. + (do_setkey) [USE_PADLOCK]: Enable padlock if available for 128 bit + AES. + (do_padlock) [USE_PADLOCK]: New. + (rijndael_encrypt, rijndael_decrypt) [USE_PADLOCK]: Divert to + do_padlock. + * cipher.c (cipher_context_alignment_t): New. Use it in this + module in place of PROPERLY_ALIGNED_TYPE. + (NEED_16BYTE_ALIGNED_CONTEXT): Define macro for ia32. + (struct gcry_cipher_handle): Add field HANDLE_OFFSET. + (gcry_cipher_open): Take care of increased alignment requirements. + (gcry_cipher_close): Ditto. + +2007-11-28 Werner Koch + + * sha256.c (asn224): Fixed wrong template. It happened due to a + bug in RFC4880. SHA-224 is not in the stable version of libgcrypt + so the consequences are limited to users of this devel version. + +2007-10-31 Werner Koch + + * ac.c (gcry_ac_data_new): Remove due to the visibility wrapper. + (gcry_ac_data_destroy, gcry_ac_data_copy, gcry_ac_data_length) + (gcry_ac_data_set, gcry_ac_data_get_name, gcry_ac_data_get_index) + (gcry_ac_data_to_sexp, gcry_ac_data_from_sexp) + (gcry_ac_data_clear, gcry_ac_io_init, gcry_ac_open) + (gcry_ac_close, gcry_ac_key_init, gcry_ac_key_pair_generate) + (gcry_ac_key_pair_extract, gcry_ac_key_destroy) + (gcry_ac_key_pair_destroy, gcry_ac_key_data_get) + (gcry_ac_key_test, gcry_ac_key_get_nbits, gcry_ac_key_get_grip) + (gcry_ac_data_encrypt, gcry_ac_data_decrypt, gcry_ac_data_sign) + (gcry_ac_data_verify, gcry_ac_data_encode, gcry_ac_data_decode) + (gcry_ac_mpi_to_os, gcry_ac_mpi_to_os_alloc, gcry_ac_os_to_mpi) + (gcry_ac_data_encrypt_scheme, gcry_ac_data_decrypt_scheme) + (gcry_ac_data_sign_scheme, gcry_ac_data_verify_scheme) + (gcry_ac_io_init_va): Ditto. + (gcry_ac_id_to_name, gcry_ac_name_to_id): Remove as these + deprecated functions are now implemented by visibility.c. + +2007-10-26 Werner Koch + + * rndw32.c: Disable debug flag. + +2007-10-25 Werner Koch + + * rndw32.c: Updated from current cryptlib snapshot and modified + for our use. Removed support from pre NT systems. + (slow_gatherer_windows95): Remove. + (_gcry_rndw32_gather_random): Require an NT platform. + (init_system_rng, read_system_rng, read_mbm_data): New. + (slow_gatherer_windowsNT): Rename to ... + (slow_gatherer): .. this. Read system RNG and MBM. + (registry_poll): New with code factored out from slow_gatherer. + +2007-08-23 Werner Koch + + * random.c (pool_filled_counter): New. + (add_randomness): Use it. + +2007-08-22 Werner Koch + + * rndw32.c, rndunix.c: Switched to LGPL. + +2007-05-30 Werner Koch + + * camellia.h, camellia.c: Replace by new LGPL version and adjusted + camellia.h. + +2007-05-09 Marcus Brinkmann + + * ac.c (_gcry_ac_io_init_va, _gcry_ac_io_write, _gcry_ac_io_read): + Adjust users of gcry_ac_io_t because union is not anonymous + anymore. + +2007-05-02 Werner Koch + + * camellia-glue.c (camellia_setkey, camellia_encrypt) + (camellia_decrypt): Recalculated used stack size in called + functions. + * camellia.h: Redefine external symbols. + +2007-05-02 David Shaw + + * Makefile.am, cipher.c: Add Camellia. + + * camellia-glue.c: New. The necessary glue to interface libgcrypt + to the stock NTT Camellia distribution. + + * camellia.h, camellia.c: The stock NTT Camellia distribution + (GPL). + +2007-04-30 David Shaw + + * cipher.c: Use #if instead of #ifdef as configure defines the + USE_cipher defines as 0 for disabled. + +2007-04-30 Werner Koch + + * rndegd.c (_gcry_rndegd_set_socket_name): New. + +2007-04-30 Marcus Brinkmann + + * ecc.c (ec2os): Fix relocation of short numbers. + + * ecc.c (generate_key): Do not allocate D, which will be allocated + by GEN_K. Remove G. Fix test if g_x, g_y resp. q_x, q_y are + requested. + (_gcry_ecc_generate): Release unneeded members of SK. + * pubkey.c (sexp_to_key): Release NAME. + +2007-04-28 Marcus Brinkmann + + * ac.c (gcry_ac_mpi): Remove member NAME_PROVIDED. + (ac_data_mpi_copy, _gcry_ac_data_set, _gcry_ac_data_get_name) + (_gcry_ac_data_get_index, ac_data_construct): Adjust handling of + NAME accordingly. + +2007-04-20 Werner Koch + + * ecc.c (domain_parms): Add standard brainpool curves. + +2007-04-18 Werner Koch + + * ecc.c (generate_curve): Implement alias mechanism. + + * pubkey.c (sexp_elements_extract_ecc): New. + (sexp_to_key): Add special case for ecc. + (sexp_to_key, sexp_to_sig, sexp_to_enc, gcry_pk_genkey): Replace + name_terminated stuff by a call to _gcry_sexp_nth_string. + (gcry_pk_get_keygrip): Ditto. + +2007-04-16 Werner Koch + + * ecc.c (_gcry_ecc_generate): Renamed DUMMY to CURVE and use it. + +2007-04-13 Marcus Brinkmann + + * ac.c (ac_data_construct): Cast const away to suppress compiler + warning. + + * ecc.c (ecc_generate): Avoid compiler warning for unused argument + DUMMY. + (ecc_verify): Avoid compiler warning for unused arguments CMP and + OPAQUEV. + +2007-04-06 Werner Koch + + * sha1.c (oid_spec_sha1): Add another oid from X9.62. + +2007-03-28 Werner Koch + + * pubkey.c (gcry_pk_genkey): Do not issue misc-key-info if it is + empty. + (gcry_pk_genkey): New parameter "curve". + + * ecc.c: Entirely rewritten with only a few traces of the old + code left. + (_gcry_ecc_generate): New. + (generate_key) New arg NAME. + (generate_curve): Ditto. Return actual number of NBITS. + +2007-03-26 Werner Koch + + * pubkey.c (gcry_pk_genkey): Increase size of SKEY array and add a + runtime bounds check. + +2007-03-23 Werner Koch + + * ecc.c (ecc_ctx_init, ecc_ctx_free, ecc_mod, ecc_mulm): New. + (duplicate_point, sum_points, escalar_mult): Don't use a + copy of base->p. Replaced all mpi_mulm by ecc_mulm so that we can + experiment with different algorithms. + (generate_key, check_secret_key, sign, verify): Initialize a + computation context for use by ecc_mulm. + +2007-03-22 Werner Koch + + * pubkey.c (pubkey_table): Initialize ECC. + * Makefile.am (EXTRA_libcipher_la_SOURCES): Add ecc.c. + * ecc.c: New. Heavily reformatted and changed for use in libgcrypt. + (point_init): New. + (escalar_mult): Make arg R the first arg to be similar to the mpi + functions. + (duplicate_point): Ditto + (sum_points): Ditto + (sign, verify): Remove unneeded copy operations. + (sum_points): Removed memory leaks and optimized some compares. + (verify): Simplified input check. + +2007-03-14 Werner Koch + + * random.c (MASK_LEVEL): Removed macro as it was used only at one + place. Open coded it there. + (gcry_randomize, _gcry_update_random_seed_file) + (_gcry_fast_random_poll): Factor lock code out to .. + (lock_pool, unlock_pool): .. new. + (initialize): Look the pool while allocating. + (read_random_source, do_fast_random_poll): Moved intialization to ... + (initialize): .. here. + (_gcry_enable_quick_random_gen): No more need for initialization. + (is_initialized): Moved this global flag to .. + (initialize): .. here and changed all users to unconditionally call + initialize. + (add_randomness): Remove initalization here. It simply can't + happen. + + * random.c (enum random_origins): Moved to .. + * rand-internal.h: .. here. + * rndunix.c (_gcry_rndunix_gather_random): Use enum in prototype + for ORIGIN and renamed REQUESTOR to ORIGIN. + * rndegd.c (_gcry_rndegd_gather_random): Ditto. + * rndlinux.c (_gcry_rndlinux_gather_random): Ditto. + * rndw32.c (_gcry_rndw32_gather_random): Ditto. + (_gcry_rndw32_gather_random_fast): Ditto. + +2007-03-13 Werner Koch + + * random.c (enum random_origins): New. + (add_randomness): Renamed arg SOURCE to ORIGIN. + (read_random_source): Renamed arg REQUESTOR to ORIGIN. + (getfnc_gather_random): Removed static variable because this + function is only called one and thus we don't need this + optimization. + (_gcry_quick_random_gen): Removed and replaced by.. + (_gcry_enable_quick_random_gen): .. this. It is onlyu used to + enable it and it does not make sense to disable it later. Changed + the only one caller too. + (get_random_bytes): Removed. + (gcry_random_bytes, gcry_random_bytes_secure): Implement in terms + of gcry_randomize. + * random-daemon.c (_gcry_daemon_get_random_bytes): Removed. + +2007-02-23 Werner Koch + + * elgamal.c (generate): Removed unused variable TEMP. + (test_keys): New arg NODIE. + (generate_using_x, _gcry_elg_generate_using_x): New. + * pubkey.c (pubkey_generate): New arg XVALUE and direct call to + the new elgamal generate fucntion. + (gcry_pk_genkey): Parse the new "xvalue" tag. + +2007-02-22 Werner Koch + + * pubkey.c (sexp_data_to_mpi): Handle dynamically allocated + algorithms. Suggested by Neil Dunbar. Fixes bug#596. + + * rndw32.c (_gcry_rndw32_gather_random_fast): Make it return void. + + * cipher.c (gcry_cipher_algo_name): Simplified. + + * random.c: Use the daemon only if compiled with USE_RANDOM_DAEMON. + + * Makefile.am (libcipher_la_SOURCES): Build random-daemon support + only if requested. + +2007-02-21 Werner Koch + + * random.c (rndpool, keypool): Make unsigned. + (mix_pool): Change char* variables to unsigned char*. + (gcry_randomize): Make arg BUFFER a void*. + (gcry_create_nonce): Ditto. + + * rmd160.c (gcry_rmd160_mixblock): Make BUFFER a void*. + (_gcry_rmd160_hash_buffer): Make OUTBUF and BUFFER void*. + * sha1.c (_gcry_sha1_hash_buffer): Ditto. + + * cipher.c (gcry_cipher_encrypt, cry_cipher_decrypt): Change + buffer args to void*. + (gcry_cipher_register): Make ALGORITHM_ID a int *. + + * md.c (md_start_debug): Make SUFFIX a const char*. Use snprintf. + (gcry_md_debug): New. + (gcry_md_ctl): Changed arg BUFFER from unsigned char*. + + * md.c (md_write): Make INBUF a const void*. + (gcry_md_write): Remove needless cast. + * crc.c (crc32_write): Make INBUF a const void* + (update_crc32, crc24rfc2440_write): Ditto. + * sha512.c (sha512_write, transform): Ditto. + * sha256.c (sha256_write, transform): Ditto. + * rmd160.c (rmd160_write, transform): Ditto. + * md5.c (md5_write, transform): Ditto. + * md4.c (md4_write, transform): Ditto. + * sha1.c (sha1_write, transform): Ditto. + + * tiger.c (tiger_write, transform): Ditto. + * whirlpool.c (whirlpool_write, whirlpool_add, transform): Ditto. + + * elgamal.c (elg_names): Change to a const*. + * dsa.c (dsa_names): Ditto. + * rsa.c (rsa_names): Ditto. + * pubkey.c (gcry_pk_lookup_func_name): Make ALIASES a const. + +2007-02-20 Werner Koch + + * rndlinux.c (open_device): Remove unsused arg MINOR. + +2007-01-30 Werner Koch + + * sha256.c (oid_spec_sha256): Add alias from pkcs#1. + * sha512.c (oid_spec_sha512): Ditto. + (oid_spec_sha384): Ditto. + +2006-12-18 Werner Koch + + * rndlinux.c (set_cloexec_flag): New. + (open_device): Set close-on-exit flags. Suggested by Max + Kellermann. Fixes Debian#403613. + + * Makefile.am (AM_CPPFLAGS, AM_CFLAGS): Splitted and merged + Moritz' changes. + (INCLUDES): Removed. + +2006-11-30 Werner Koch + + * serpent.c (byte_swap_32): Remove trailing semicolon. + +2006-11-15 Werner Koch + + * Makefile.am (INCLUDES): Include ../src/ + +2006-11-03 Werner Koch + + * random.c [HAVE_GETTIMEOFDAY]: Included sys/time.h and not + sys/times.h. Reported by Rafaël Carré. + +2006-11-05 Moritz Schulte + + * Makefile.am (AM_CFLAGS): Added -I$(top_builddir)/src so that the + new gcrypt.h is used, not the one installed in the system. + +2006-10-25 Werner Koch + + * primegen.c (prime_generate_internal): Tweaked use of secure + memory and entropy use. Safe unused primes from the pool. Allocate + at least a pool of 30. + (save_pool_prime, get_pool_prime): New. + +2006-10-23 Werner Koch + + * ac.c (_gcry_ac_data_from_sexp): Reset sexp_tmp for failsafe + means. Release sexp_cur if needed. Reported by Dirk Stoecker. + + * pubkey.c (pubkeys_registered_lock): Intialized it. It is not + realy needed because this is a mere initialization to 0 anyway. + Noted by Victor Stinner. + +2006-10-17 Werner Koch + + * dsa.c (_gcry_dsa_generate2): New. + (generate): New arg QBITS. Add sanity checks for reasonable qbits + and nbits. + * pubkey.c (gcry_pk_genkey): Parse an qbits element. + (pubkey_generate): New arg QBITS. Pass it to the DSA generation. + +2006-10-05 Werner Koch + + * md.c (gcry_md_algo_info) : Check that the algo is + available. + +2006-10-04 David Shaw (wk) + + * tiger.c (round): Rename to tiger_round as gcc 4 has a built-in + round function that this conflicts with. + +2006-09-11 Werner Koch + + * rndw32.c (slow_gatherer_windowsNT): While adding data use the + size of the diskPerformance and not its address. Has been fixed in + GnuPG more than a year ago. Noted by Lee Fisher. + +2006-08-30 Werner Koch + + * pubkey.c (sexp_data_to_mpi): Need to allow "ripemd160" here as + this is the canonical name. + +2006-08-29 Hye-Shik Chang (wk) + + * seed.c: New. + +2006-08-03 Werner Koch + + * random-daemon.c (_gcry_daemon_initialize_basics): Don't + initialize the socket. Remove arg SOCKETNAME. + (connect_to_socket): Make sure that daemon is set to -1 on error. + (call_daemon): Initialize the socket on the first call. + (_gcry_daemon_randomize, _gcry_daemon_get_random_bytes) + (_gcry_daemon_create_nonce): New arg SOCKETNAME. + * random.c (initialize): Call new daemon initializator. + (get_random_bytes, gcry_randomize, gcry_create_nonce): Pass socket + name to daemon call and reset allow_daemon on failure. + +2006-07-26 Werner Koch + + * rmd160.c (_gcry_rmd160_mixblock): Add cast to transform call. + + * blowfish.c (selftest): Cast string to usnigned char*. + + * primegen.c (prime_generate_internal): Cast unsigned/char* + mismatch in calling m_out_of_n. + (is_prime): Changed COUNT to unsigned int *. + + * ac.c (_gcry_ac_data_copy): Initialize DATA_MPIS. + + * random.c (gcry_create_nonce): Update the pid after a fork. + Reported by Uoti Urpala. + +2006-07-04 Marcus Brinkmann + + * sha512.c: Fix typo in copyright notice. + +2006-06-21 Werner Koch + + * rsa.c (_gcry_rsa_generate): Replace xcalloc by calloc. + * pubkey.c (gcry_pk_encrypt, gcry_pk_sign): Ditto. + (sexp_to_key, sexp_to_sig, sexp_to_enc, gcry_pk_encrypt) + (gcry_pk_sign, gcry_pk_genkey, gcry_pk_get_keygrip): Ditto. + * md.c (md_copy): Ditto. + +2006-04-22 Moritz Schulte + + * random-daemon.c (_gcry_daemon_initialize_basics): New argument: + SOCKETNAME. Passing on to connect_to_socket() if non-NULL. + (connect_to_socket, writen, readn, call_daemon): New functions. + (_gcry_daemon_randomize, _gcry_daemon_get_random_bytes) + (_gcry_daemon_create_nonce): Call call_daemon(). + (RANDOM_DAEMON_SOCKET): New symbol. + (daemon_socket): New static variable. + + * random.h (_gcry_daemon_initialize_basics): New parameter: + SOCKETNAME. + (_gcry_set_random_daemon_socket): New declaration. + + * random.c (initialize_basics): Pass DAEMON_SOCKET_NAME to + _gcry_daemon_initialize_basics. + (_gcry_set_random_daemon_socket): New function, setting + DAEMON_SOCKET_NAME. + +2006-04-01 Moritz Schulte + + * ac.c (eme_pkcs_v1_5_encode): Use KEY_SIZE directly, no need to + call gcry_ac_key_get_nbits. + (eme_pkcs_v1_5_decode): Likewise. + (ac_es_dencode_prepare_pkcs_v1_5): Fill options_em structure with + key_size. + (_gcry_ac_data_dump, gcry_ac_data_dump): New functions. + (_gcry_ac_data_to_sexp, _gcry_ac_data_from_sexp): More or less + rewritten; changed S-Expression format so that it matches the one + used in pubkey.c. + +2006-03-15 Werner Koch + + * random-daemon.c: New. + * random.c (_gcry_use_random_daemon): New. + (get_random_bytes, gcry_randomize, gcry_create_nonce): Try + diverting to the daemon functions. + +2006-03-14 Werner Koch + + * random.c (lock_seed_file): New. + (read_seed_file, _gcry_update_random_seed_file): Use it. + + * random.c (gcry_create_nonce): Detect a fork and re-seed. + (read_pool): Fixed the fork detection; it used to work only for + multi-threaded processes. + +2006-03-12 Brad Hards (wk) + + * md.c (md_open): Use new variable macpads_Bsize instead of + hardwiring the block size. Changed at all places. + +2006-03-10 Brad Hards (wk, patch 2005-04-22) + + * md.c, sha256.c: Add support for SHA-224. + (sha224_init): New. + +2006-01-18 Brad Hards (wk 2006-03-07) + + * cipher.c (cipher_encrypt, cipher_decrypt, do_ofb_encrypt) + (do_ofb_decrypt, gcry_cipher_open): Implement Output Feedback Mode. + +2005-11-02 Moritz Schulte + + * pubkey.c (gcry_pk_algo_name): Return "?" instead of NULL for + unknown algorithm IDs. + * cipher.c (cipher_algo_to_string): Likewise. + +2005-11-01 Moritz Schulte + + * pubkey.c (gcry_pk_algo_info): Don't forget to break after switch + case. + +2005-09-19 Werner Koch + + * dsa.c (generate): Add preliminary support for 2 and 4 keys. + Return an error code if the key size is not supported. + (_gcry_dsa_generate): Return an error. + +2005-08-22 Werner Koch + + * primegen.c (check_prime): New arg RM_ROUNDS. + (prime_generate_internal): Call it here with 5 rounds as used + before. + (gcry_prime_check): But here with 64 rounds. + (is_prime): Make sure never to use less than 5 rounds. + +2005-04-16 Moritz Schulte + + * ac.c (_gcry_ac_init): New function. + +2005-04-12 Moritz Schulte + + * ac.c (_gcry_ac_io_write, _gcry_ac_io_read): Initialize err to + make the compiler happy. + Always use errno, now that gcry_malloc() is guaranteed to set + errno on failure. + (_gcry_ac_data_to_sexp): Don't forget to goto out after error in + loop. + (_gcry_ac_data_to_sexp): Remove unused variable: mpi_list; + (_gcry_ac_data_to_sexp): Always deallocate sexp_buffer. + (_gcry_ac_data_from_sexp): Don't forget to initialize data_set_new. + (_gcry_ac_data_from_sexp): Handle special case, which is + necessary, since gcry_sexp_nth() does not distinguish between + "element does not exist" and "element is the empty list". + (_gcry_ac_io_init_va): Use assert to make sure that mode and type + are correct. + Use gcry_error_t types where gcry_err_code_t types have been used + before. + +2005-04-11 Moritz Schulte + + * ac.c (_gcry_ac_data_sign_scheme): Don't forget to initialize + buffer. + + * whirlpool.c: New file. + * md.c (digest_table): Add whirlpool. + * Makefile.am (EXTRA_libcipher_la_SOURCES): Added: whirlpool.c. + +2005-03-30 Moritz Schulte + + * ac.c (_gcry_ac_data_from_sexp): Use length of SEXP_CUR, not + length of SEXP; do not forget to set SEXP_TMP to NULL after it has + been released. + + (struct gcry_ac_mpi): New member: name_provided. + (_gcry_ac_data_set): Rename variable `name_final' to `name_cp'; + remove const qualifier; change code to not cast away const + qualifiers; use name_provided member as well. + (_gcry_ac_data_set, _gcry_ac_data_get_name): Use name_provided + member of named mpi structure. + + (gcry_ac_name_to_id): Do not forget to initialize err. + (_gcry_ac_data_get_index): Do not forget to initialize mpi_return; + use gcry_free() instead of free(); remove unnecessary cast; rename + mpi_return and name_return to mpi_cp and name_cp; adjust code. + (ac_data_mpi_copy): Do not cast away const qualifier. + (ac_data_values_destroy): Likewise. + (ac_data_construct): Likewise. + + (ac_data_mpi_copy): Initialize flags to GCRY_AC_FLAG_DEALLOC. + (ac_data_extract): Use GCRY_AC_FLAG_DEALLOC instead of + GCRY_AC_FLAG_COPY. + + (_gcry_ac_io_init_va, _gcry_ac_io_init, gcry_ac_io_init) + (gcry_ac_io_init_va, _gcry_ac_io_write, _gcry_ac_io_read) + (_gcry_ac_io_read_all, _gcry_ac_io_process): New functions. + (gry_ac_em_dencode_t): Use gcry_ac_io_t in prototype instead of + memroy strings directly; adjust encode/decode functions to use io + objects. + (emsa_pkcs_v1_5_encode_data_cb): New function ... + (emsa_pkcs_v1_5_encode): ... use it here. + (ac_data_dencode): Use io objects. + (_gcry_ac_data_encode, _gcry_ac_data_decode, gcry_ac_data_encode) + (gcry_ac_data_decode): Likewise. + (_gcry_ac_data_encrypt_scheme, gcry_ac_data_encrypt_scheme) + (_gcry_ac_data_decrypt_scheme, gcry_ac_data_decrypt_scheme) + (_gcry_ac_data_sign_scheme, gcry_ac_data_sign_scheme) + (_gcry_ac_data_verify_scheme, gcry_ac_data_verify_scheme): + Likewise. + +2005-03-23 Werner Koch + + * rndw32.c (_gcry_rndw32_gather_random_fast): While adding data + use the size of the object and not the one of its address. Bug + reported by Sascha Kiefer. + +2005-03-19 Moritz Schulte + + * cipher.c (do_cbc_encrypt): Be careful to not overwrite data, + which is to be used later on. This happend, in case CTS is + enabled and OUTBUF is equal to INBUF. + +2005-02-25 Werner Koch + + * pubkey.c (gcry_pk_get_keygrip): Allow for shadowed-private-key. + +2005-02-13 Moritz Schulte + + * serpent.c: Updated from 1.2 branch: + + s/u32_t/u32/ and s/byte_t/byte/. Too match what we have always + used and are using in all other files too + (serpent_test): Moved prototype out of a fucntion. + +2005-02-07 Moritz Schulte + + * ac.c: Major parts rewritten. + * pubkey.c (_gcry_pk_get_elements): New function. + +2004-12-09 Werner Koch + + * serpent.c (serpent_setkey): Moved prototype of serpent_test to + outer scope. + +2004-09-11 Moritz Schulte + + * pubkey.c (pubkey_table): Added an alias entry for GCRY_PK_ELG_E. + +2004-08-23 Moritz Schulte + + * ac.c: Do not include . + * rndegd.c: Likewise. + * sha1.c: Likewise. + * rndunix.c: Likewise. + * rndlinux.c: Likewise. + * rmd160.c: Likewise. + * md5.c: Likewise. + * md4.c: Likewise. + * cipher.c: Likewise. + * crc.c: Likewise. + * blowfish.c: Likewise. + + * pubkey.c (dummy_generate, dummy_check_secret_key) + (dummy_encrypt, dummy_decrypt, dummy_sign, dummy_verify): Return + err code GPG_ERR_NOT_IMPLEMENTED instead of aborting through + log_bug(). + (dummy_get_nbits): Return 0 instead of aborting though log_bug(). + +2004-08-19 Werner Koch + + * pubkey.c (sexp_data_to_mpi): Changed the zero random byte + substituting code to actually do clever things. Thanks to + Matthias Urlichs for noting the implementation problem. + +2004-08-09 Moritz Schulte + + * pubkey.c (gcry_pk_sign): Fixed memory leak; fix provided by + Modestas Vainius. + +2004-07-16 Werner Koch + + * rijndael.c (do_encrypt): Fix alignment problem. Bugs found by + Matthias Urlichs. + (do_decrypt): Ditto. + (keySched, keySched2): Use 2 macros along with unions in the key + schedule context. + +2004-07-14 Moritz Schulte + + * rsa.c (_gcry_rsa_decrypt): Don't forget to free "a". Thanks to + Nikos Mavroyanopoulos. + +2004-05-09 Werner Koch + + * random.c (read_pool): Mix the PID in to better protect after a + fork. + +2004-07-04 Moritz Schulte + + * serpent.c: Use "u32_t" instead of "unsigned long", do not + declare S-Box variables as "register". Fixes failure on + OpenBSD/sparc64, reported by Nikolay Sturm. + +2004-05-07 Werner Koch + + * random.c (initialize): Factored out some code to .. + (initialize_basics): .. new function. + (_gcry_random_initialize): Just call initialize_basics unless the + new arg FULL is set to TRUE. + (_gcry_fast_random_poll): Don't do anything unless the random + system has been really initialized. + +2004-05-07 Moritz Schulte + + * ac.c (gcry_ac_open): Do not dereference NULL pointer. Reported + by Umberto Salsi. + +2004-02-20 Werner Koch + + * primegen.c (check_prime): New args CB_FUNC and CB_ARG; call them + at different stages. Pass these arguments through all callers. + +2004-02-06 Werner Koch + + * des.c: Add a new OID as used by pkcs#12. + + * rfc2268.c: New. Taken from libgcrypt. + * cipher.c: Setup the rfc2268 algorithm. + +2004-01-25 Moritz Schulte + + * primegen.c (prime_generate_internal): Do not forget to free + `q_factor'; fixed by Brieuc Jeunhomme. + (prime_generate_internal): Do not forget to free `prime'. + +2004-01-14 Moritz Schulte + + * ac.c (gcry_ac_data_set): New argument: flags; slightly + rewritten. + (gcry_ac_data_get_name, gcry_ac_data_get_index): Likewise. + (gcry_ac_key_pair_generate): New argument: misc_data; modified + order of arguments. + (gcry_ac_key_test): New argument: handle. + (gcry_ac_key_get_nbits, gcry_ac_key_get_grip): Likewise. + Use GCRY_AC_FLAG_NO_BLINDING instead of + GCRY_AC_DATA_FLAG_NO_BLINDING. + (gcry_ac_mpi): New member: flags. + (gcry_ac_data_search, gcry_ac_data_add): Removed functions. + +2003-12-22 Werner Koch + + * primegen.c (is_prime): Release A2. + +2003-12-19 Werner Koch + + * md.c: Moved a couple of functions down below the data structure + definitions. + (struct gcry_md_context): New field ACTUAL_HANDLE_SIZE. + (md_open): Set it here. + (strcut gcry_md_list): New field ACTUAL_STRUCT_SIZE. + (md_enable): Set it here. + (md_close): Wipe the context memory. + secure memory. + * cipher.c (struct gcry_cipher_handle): New field ACTUAL_HANDLE_SIZE. + (gcry_cipher_open): Set it here. + (gcry_cipher_close): Use it to always wipe out the handle data. + + * ac.c (gcry_ac_open): Make sure HANDLE gets initialized even when + the function is not successful. + (gcry_ac_close): Allow a NULL handle. + (gcry_ac_key_destroy, gcry_ac_key_pair_destroy): Ditto. + (gcry_ac_key_get_grip): Return INV_OBJ on error. + + * primegen.c (prime_generate_internal): Fixed error code for + failed malloc. Replaced the !err if chain by gotos. + (gcry_prime_group_generator): Remove the extra sanity check. + + * md.c: Minor code and comment cleanups. + +2003-12-16 Werner Koch + + * primegen.c (gen_prime): Doc fix. Thanks to Newton Hammet. + +2003-12-11 Werner Koch + + * rndunix.c (slow_poll): Don't use #warning but #error. + + * rndegd.c: Changed indentation. + (my_make_filename): Removd the var_arg cruft becuase we + don't need it here. Changed caller. + + * rndlinux.c: Changed indentation. + (open_device): Remove the superfluous stat call and clarify + comment. + + * rsa.c: Changed indentation. + (secret): Use the standard algorithm if p, q and u are not + available. + (rsa_blind, rsa_unblind): Renamed from _gcry_rsa_blind, + _gcry_rsa_unblind and moved more to the top. + + * md4.c: Changed indentation. Removed unnecessary casts. + * md5.c, rmd160.c, sha1.c, tiger.c: Ditto. + * rijndael.c, twofish.c: Ditto. + * serpent.c: Removed unnecessary casts. + * sha256.c, sha512.c: Ditto. + +2003-12-09 Werner Koch + + * dsa.c: Unified indentation style. + * elgamal.c: Ditto. + * des.c (des_key_schedule): Code beautifications. + * blowfish.c: Changed indentation style. + * cast5.c (do_cast_setkey): Ditto. + + * pubkey.c (gcry_pk_encrypt): Replaced the chain of if(!err) tests + by straightforward gotos. Other cleanups. + (gcry_pk_decrypt): Ditto. + (gcry_pk_sign): Ditto. + (gcry_pk_verify): Ditto. + (gcry_pk_genkey): Ditto. Use strtoul instead of strtol. + (gcry_pk_ctl): Use GPG_ERR_INV_ARG to indicate bad arguments. + +2003-12-07 Werner Koch + + * pubkey.c (gcry_pk_register_default): Undef the helper macro. + (gcry_pk_map_name): Allow NULL for string. + (sexp_to_key): Use memcpy and not strncpy. Use gcry_free and not + free. + (sexp_to_sig): Ditto. + (sexp_to_enc): Ditto. Replaced the chain of if(!err) tests by + straightforward gotos. + +2003-12-05 Werner Koch + + * cipher.c: Documentation cleanups. + (gcry_cipher_mode_from_oid): Allow NULL for STRING. + +2003-12-03 Werner Koch + + * elgamal.c (sign, do_encrypt, gen_k): Make sure that a small K is + only used for encryption. + +2003-11-18 Werner Koch + + * random.h (rndw32_set_dll_name): Removed unused prototype. + + * Makefile.am (EXTRA_DIST): Added Manifest. + +2003-11-11 Werner Koch + + * Manifest: New. + +2003-11-04 Werner Koch + + * md.c (gcry_md_hash_buffer): Use shortcut for SHA1 + * sha1.c (_gcry_sha1_hash_buffer): New. + + * random.c: Reformatted most functions. + (mix_pool): Moved the failsafe_digest from global + scope to here. + (do_fast_random_poll): Use the generic fucntions even if a fast + gathering function has been used. + (read_pool): Detect a fork and retry. + (gcry_randomize, get_random_bytes): Don't distinguish anymore + between weak and strong random. + (gcry_create_nonce): New. + +2003-10-31 Werner Koch + + * rndw32.c (slow_gatherer_windowsNT): Use a plain buffer for the + disk performance values and not the W32 API structure. + + * dsa.c (verify): s/exp/ex/ due to shadowing of a builtin. + * elgamal.c (verify): Ditto. + + * ac.c (gcry_ac_data_get_index): s/index/idx/ + (gcry_ac_data_copy_internal): Remove the cast in _gcry_malloc. + (gcry_ac_data_add): Must use gcry_realloc instead of realloc. + * pubkey.c (sexp_elements_extract): s/index/idx/ as tribute to the + forehackers. + (gcry_pk_encrypt): Removed shadowed definition of I. Reordered + arguments to malloc for clarity. + (gcry_pk_sign, gcry_pk_genkey): Ditto. + * primegen.c (prime_generate_internal): s/random/randomlevel/. + +2003-10-27 Moritz Schulte + + * pubkey.c (gcry_pk_encrypt): Don't forget to deallocate pkey. + +2003-10-27 Werner Koch + + * random.c (gcry_random_add_bytes): Return if buflen is zero to + avoid gcc warning about unsed parameter. + (MASK_LEVEL): Simplified; does now work for signed and unsigned + w/o warnings. + + * md.c (md_start_debug): Removed the const from SUFFIX, because + this function is called from the control fucntion which does not + require const. + + Prefixed all (pubkey,digest,cipher}_spec_* globale variables with + _gcry_. + + * ac.c (ac_key_identifiers): Made static. + + * random.c (getfnc_gather_random,getfnc_fast_random_poll): Move + prototypes to .. + * rand-internal.h: .. here + * random.c (getfnc_gather_random): Include rndw32 gatherer. + * rndunix.c, rndw32.c, rndegd.c: Include them here. + * rndlinux.c (_gcry_rndlinux_gather_random): Prepend the _gcry_ + prefix. Changed all callers. + * rndegd.c (_gcry_rndegd_gather_random): Likewise. + (_gcry_rndegd_connect_socket): Likewise. + * rndunix.c (_gcry_rndunix_gather_random): Likewise. + (waitpid): Made static. + * rndw32.c: Removed the old and unused winseed.dll cruft. + (_gcry_rndw32_gather_random_fast): Renamed from + gather_random_fast. + (_gcry_rndw32_gather_random): Renamed from gather_random. Note, + that the changes 2003-04-08 somehow got lost. + + * sha512.c (sha512_init, sha384_init): Made static. + + * cipher.c (do_ctr_decrypt): Removed "return" from this void + function. + +2003-10-24 Moritz Schulte + + * serpent.c: Fix an issue on big-endian systems. + + * rndw32.c: Removed IS_MODULE -cruft. + * rndlinux.c (rndlinux_gather_random): Likewise. + +2003-10-10 Werner Koch + + * primegen.c (gen_prime): Bail out if NBITS is less than 16. + (prime_generate_internal): Initialize prime variable to suppress + compiler warning. Check pbits, initialize qbits when passed as + zero. + + * primegen.c (prime_generate_internal): New arg + ALL_FACTORS. Changed all callers. + (gcry_prime_generate): Make the factors arg optional. Request + all_factors. Make sure PRIME is set to NULL even on error. + (gcry_prime_group_generator): New. + (gcry_prime_release_factors): New. + +2003-10-06 Werner Koch + + * primegen.c (gen_prime): Assert that NBITS is never zero, it + would cause a segv. + +2003-09-28 Moritz Schulte + + * ac.c: Include "cipher.h". + +2003-09-27 Moritz Schulte + + * rndegd.c (do_read): Return nread instead of nbytes; thanks to + Michael Caerwyn. + +2003-09-04 Werner Koch + + * pubkey.c (_gcry_pk_aliased_algo_name): New. + * ac.c (gcry_ac_open): Use it here. + + * Makefile.am (EXTRA_libcipher_la_SOURCES): Add serpent.c + +2003-09-02 Moritz Schulte + + * primegen.c (gcry_prime_check, gcry_prime_generate): New + functions. + (prime_generate_internal): New function, based on + _gcry_generate_elg_prime. + (_gcry_generate_elg_prime): Rewritten as a wrapper for + prime_generate_internal. + +2003-08-28 Werner Koch + + * pubkey.c (gcry_pk_encrypt): Don't include the flags list in the + return value. This does not make sense and breaks any programs + parsing the output strictly (e.g. current gpgsm). + (gcry_pk_encrypt): If aliases for the algorithm name exists, take + the first one instead of the regular name to adhere to SPKI + conventions. + (gcry_pk_genkey): Ditto. + (gcry_pk_sign): Ditto. Removed unused KEY_ALGO_NAME. + +2003-08-19 Moritz Schulte + + * cipher.c: Add support for Serpent + * serpent.c: New file. + +2003-08-10 Moritz Schulte + + * rsa.c (_gcry_rsa_blind, _gcry_rsa_unblind): Declare static. + +2003-08-09 Timo Schulz + + * random.c (getfnc_gather_random): Don't check NAME_OF_DEV_RANDOM + two times, but also the NAME_OF_DEV_URANDOM device. + +2003-08-08 Moritz Schulte + + * pubkey.c (sexp_to_enc): Fixed extraction of S-Expression: do not + fail if no `flags' sub S-Expression is found. + +2003-07-27 Werner Koch + + * md.c (gcry_md_lookup_func_oid): Allow for empty OID lists. + +2003-07-23 Moritz Schulte + + * ac.c (gcry_ac_data_construct): New argument: include_flags, only + include `flags' S-expression, if include_flags is true. Adjust + callers. Thanks for triggering a bug caused by `flags' + sub-S-expression where they are not expected to Ralf Schneider. + +2003-07-21 Moritz Schulte + + * pubkey.c (gcry_pk_lookup_func_name): Use new member name + `aliases' instead of `sexp_names'. + + * ac.c (gcry_ac_key_data_get): New function. + + * cipher.c (gcry_cipher_lookup_func_name): Fix return value. + +2003-07-20 Moritz Schulte + + * blowfish.c: Adjusted for new gcry_cipher_spec_t structure. + * cast5.c: Likewise. + * twofish.c: Likewise. + * arcfour.c: Likewise. + * rijndael.c (rijndael_oids, rijndael192_oids, rijndael256_oids): + New variables, adjust for new gcry_cipher_spec_t structure. + * des.c (oids_tripledes): New variable, adjust for new + gcry_cipher_spec_t structure. + + * md.c (oid_table): Removed. + + * tiger.c (oid_spec_tiger): New variable. + (digest_spec_tiger): Adjusted for new gry_md_spec_t structure. + + * sha512.c (oid_spec_sha512): New variable. + (digest_spec_sha512): Adjusted for new gry_md_spec_t structure. + + * sha512.c (oid_spec_sha384): New variable. + (digest_spec_sha384): Adjusted for new gry_md_spec_t structure. + + * sha256.c (oid_spec_sha256): New variable. + (digest_spec_sha256): Adjusted for new gry_md_spec_t structure. + + * sha1.c (oid_spec_sha1): New variable. + (digest_spec_sha1): Adjusted for new gry_md_spec_t structure. + + * rmd160.c (oid_spec_rmd160): New variable. + (digest_spec_rnd160): Adjusted for new gry_md_spec_t structure. + + * md5.c (oid_spec_md5): New variable. + (digest_spec_md5): Adjusted for new gry_md_spec_t structure. + + * md4.c (oid_spec_md4): New variable. + (digest_spec_md4): Adjusted for new gry_md_spec_t structure. + + * crc.c (digest_spec_crc32, digest_spec_crc32_rfc1510, + digest_spec_crc32_rfc2440): Adjusted for new gry_md_spec_t + structure. + +2003-07-19 Moritz Schulte + + * md.c (gcry_md_lookup_func_oid): New function. + (search_oid): New function, copied from cipher.c. + (gcry_md_map_name): Adjust for new search_oid_interface. + + * cipher.c (oid_table): Removed table. + (gcry_cipher_lookup_func_oid): New function. + (search_oid): Rewritten to use the module functions. + (gcry_cipher_map_name): Adjust for new search_oid interface. + (gcry_cipher_mode_from_oid): Likewise. + +2003-07-18 Werner Koch + + * md.c (gcry_md_hash_buffer): Convert ERR to gpg_error_t in + gpg_strerror. + +2003-07-14 Moritz Schulte + + * cipher.c (gcry_cipher_lookup_func_name): Also check the cipher + name aliases, not just the primary name. + (gcry_cipher_map_name): Remove kludge for aliasing Rijndael to + AES. + + * arcfour.c, blowfish.c, cast5.c, des.c, twofish.c: Adjust cipher + specification structures. + + * rijndael.c (rijndael_names, rijndael192_names, + rijndael256_names): New variables, use them in the cipher + specifications. + + * rmd160test.c: Removed file. + + * ac.c, arcfour.c, blowfish.c, cast5.c, cipher.c, des.c, dsa.c, + elgamal.c, md.c, pubkey.c, random.c, rijndael.c, rsa.c, twofish.c: + Used gcry_err* wrappers for libgpg symbols. + + * primegen.c (gen_prime): Correct the order arguments to + extra_check. + +2003-07-12 Moritz Schulte + + * ac.c: Replaced all public occurences of gpg_error_t with + gcry_error_t. + * cipher.c: Likewise. + * md.c: Likewise. + * pubkey.c: Likewise. + * random.c: Likewise. + + * cipher.c: Added support for TWOFISH128. + +2003-07-08 Moritz Schulte + + * ac.c (gcry_ac_data_copy_internal): New function, based on + gcry_ac_data_copy. + (gcry_ac_data_copy): Made public, use gcry_ac_data_copy_internal. + (gcry_ac_key_init): Use gcry_ac_data_copy_internal. + +2003-07-07 Moritz Schulte + + * ac.c (gcry_ac_data_set): Only release old MPI value if it is + different from the new value. Bug reported by Simon Josefsson + . + + * pubkey.c (gcry_pk_list): New function. + * md.c (gcry_md_list): New function. + + * ac.c (gcry_ac_key_pair_generate): Fix calculation of format + string size. + +2003-07-05 Moritz Schulte + + * md.c: Named struct of digest_table `digest_table_entry'. + (digest_table_entry): New member: algorithm; filled in. + (digest_table_entry): Removed unused member: flags. + (gcry_md_register): New argument: algorithm_id, filled in. + (gcry_md_register_default): Used algorithm ID from module + structure. + (gcry_md_map_name): Likewise. + (md_enable): Likewise. + (md_read): Likewise. + (gcry_md_info): Likewise. + + * pubkey.c: Named truct for pubkey_table `pubkey_table_entry'. + (pubkey_table_entry): New member: algorithm; filled in. + (gcry_pk_register_default): Used algorithm ID from pubkey_table. + (gcry_pk_register): New argument: algorithm_id, filled in. + (gcry_pk_map_name): Used algorithm ID from module structure. + (gcry_pk_decrypt): Likewise. + (gcry_pk_encrypt): Likewise. + (gcry_pk_verify): Likewise. + (gcry_pk_sign): Likewise. + (gcry_pk_testkey): Likewise. + (gcry_pk_genkey): Likewise. + (gcry_pk_get_nbits): Likewise. + (sexp_to_key): Removed unused variable: algo. + (sexp_to_sig): Likewise. + + * cipher.c: Named struct for cipher_table `cipher_table_entry'. + (cipher_table_entry): New member: algorithm; filled in. + (gcry_cipher_register_default): Used algorithm ID from + cipher_table. + (gcry_cipher_register): New argument: algorithm_id, filled in. + (gcry_cipher_map_name): Used algorithm ID from module structure. + + * arcfour.c (cipher_spec_arcfour): Removed algorithm ID. + * blowfish.c (cipher_spec_blowfish): Likewise. + * cast5.c (cipher_spec_cast5): Likewise. + * crc.c (digest_spec_crc32): Likewise. + * crc.c (digest_spec_crc32_rfc1510): Likewise. + * crc.c (digest_spec_crc32_rfc2440): Likewise. + * des.c (cipher_spec_des): Likewise. + * des.c (cipher_spec_tripledes): Likewise. + * dsa.c (pubkey_spec_dsa): Likewise. + * elgamal.c (pubkey_spec_elg): Likewise. + * md4.c (digest_spec_md4): Likewise. + * md5.c (digest_spec_md5): Likewise. + * aes.c (cipher_spec_aes): Likewise. + * aes.c (cipher_spec_aes192): Likewise. + * aes.c (cipher_spec_aes256): Likewise. + * rsa.c (pubkey_spec_rsa): Likewise. + * sha1.c (digest_spec_sha1): Likewise. + * sha256.c (digest_spec_sha256): Likewise. + * sha512.c (digest_spec_sha512): Likewise. + * tiger.c (digest_spec_tiger): Likewise. + * twofish.c (cipher_spec_twofish): Likewise. + * twofish.c (cipher_spec_twofish128): Likewise. + + * Makefile.am (EXTRA_libcipher_la_SOURCES): Fix list of source + files; reported by Simon Josefsson . + + * pubkey.c: Replaced all occurences of `id' with `algorithm', + since `id' is a keyword in obj-c. + * md.c: Likewise. + * cipher.c: Likewise. + + * crc.c, md4.c, md5.c, rmd160.c, sha1.c, sha256.c, tiger.c: + Replaced all occurences of gcry_digest_spec_t with gcry_md_spec_t. + + * dsa.c, rsa.c, elgamal.c: Replaced all occurencens of + gcry_pubkey_spec_t with gcry_pk_spec_t. + + * md.c: Replaced all occurences of gcry_digest_spec_t with + gcry_md_spec_t. + (gcry_digest_register_default): Renamed to ... + (gcry_md_register_default): ... this; adjusted callers. + (gcry_digest_lookup_func_name): Renamed to ... + (gcry_md_lookup_func_name): ... this; adjusted callers. + (gcry_digest_lookup_name): Renamed to ... + (gcry_md_lookup_name): ... this; adjusted callers. + (gcry_digest_register): Renamed to ... + (gcry_md_register): ... this. + (gcry_digest_unregister): Renamed to ... + (gcry_md_unregister): ... this. + + * pubkey.c (gcry_pubkey_register): Renamed to ... + (gcry_pk_register): ... this. + (gcry_pubkey_unregister): Renamed to ... + (gcry_pk_unregister): ... this. + Replaced all occurences of gcry_pubkey_spec_t with gcry_pk_spec_t. + (gcry_pubkey_register_default): Renamed to ... + (gcry_pk_register_default): ... this; adjusted callers. + (gcry_pubkey_lookup_func_name): Renamed to ... + (gcry_pk_lookup_func_name): ... this; adjusted callers. + (gcry_pubkey_lookup_name): Renamed to ... + (gcry_pk_lookup_name): ... this; adjusted callers. + + * md.c (gcry_md_hash_buffer): Fix error checking. Thanks to Simon + Josefsson . + +2003-07-04 Moritz Schulte + + * cipher.c (gcry_cipher_list): New function. + +2003-07-01 Moritz Schulte + + * pubkey.c (sexp_to_sig): Accept a `flags' S-expression to be more + consistent with sexp_to_enc. + +2003-06-30 Moritz Schulte + + * Makefile.am (libcipher_la_SOURCES): Added: ac.c. + + * pubkey.c (_gcry_pk_module_lookup): New function. + (_gcry_pk_module_release): New function. + +2003-06-29 Moritz Schulte + + * ac.c: New file. + +2003-06-26 Werner Koch + + * md.c (gcry_md_hash_buffer): Trigger BUG correcly with new API. + +2003-06-19 Werner Koch + + * md.c (gcry_md_is_enabled): Fixed. + +2003-06-18 Werner Koch + + * cipher.c (gcry_cipher_get_algo_keylen): New. + (gcry_cipher_get_algo_blklen): New. + +2003-06-18 Moritz Schulte + + * arcfour.c, cipher.c, blowfish.c, md.c, cast5.c, pubkey.c, crc.c, + des.c, dsa.c, elgamal.c, md4.c, md5.c, random.c, rijndael.c, + rmd160.c, rsa.c, sha1.c, sha256.c, sha512.c, tiger.c, twofish.c: + Replaced older types GcryDigestSpec, GcryCipherSpec and + GcryPubkeySpec with newer types: gcry_digest_spec_t, + gcry_cipher_spec_t and gcry_pubkey_spec_t. + + * md.c (gcry_digest_id_new): Removed function. + (gcry_digest_register): Removed code for generating a new module + ID. + + * pubkey.c (gcry_pubkey_id_new): Removed function. + (gcry_pubkey_register): Removed code for generating a new module + ID. + + * cipher.c, md.c, pubkey.c: Replace old type GcryModule with newer + one: gcry_module_t. + (gcry_cipher_id_new): Removed function. + (gcry_cipher_register): Removed code for generating a new module + ID. + + * cipher.c (gcry_cipher_register): Adjust call to + _gcry_module_add. + (gcry_cipher_register_default): Likewise. + * pubkey.c (gcry_pubkey_register_default): Likewise. + (gcry_pubkey_register): Likewise. + * md.c (gcry_digest_register_default): Likewise. + (gcry_digest_register): Likewise. + + * md.c (gcry_digest_lookup_func_id): Removed function. + (gcry_digest_lookup_id): Likewise. + (gcry_digest_id_new): Use _gcry_module_lookup_id instead of + gcry_digest_lookup_id. + (digest_algo_to_string): Likewise. + (check_digest_algo): Likewise. + (md_enable): Likewise. + (md_digest_length): Likewise. + (md_asn_oid): Likewise. + + * pubkey.c (gcry_pubkey_lookup_id): Removed function. + (gcry_pubkey_lookup_func_id): Likewise. + (gcry_pubkey_id_new): Use _gcry_module_lookup_id instead of + gcry_pubkey_id_new. + (gcry_pk_algo_name): Likewise. + (disable_pubkey_algo): Likewise. + (check_pubkey_algo): Likewise. + (pubkey_get_npkey): Likewise. + (pubkey_get_nskey): Likewise. + (pubkey_get_nsig): Likewise. + (pubkey_get_nenc): Likewise. + (pubkey_generate): Likewise. + (pubkey_check_secret_key): Likewise. + (pubkey_encrypt): Likewise. + (pubkey_decrypt): Likewise. + (pubkey_sign): Likewise. + (pubkey_verify): Likewise. + (gcry_pk_algo_info): Likewise. + + * cipher.c (gcry_cipher_lookup_func_id): Removed function. + (gcry_cipher_lookup_id): Likewise. + (cipher_algo_to_string): use _gcry_module_lookup_id instead of + gcry_cipher_lookup_id. + (disable_cipher_algo): Likewise. + (check_cipher_algo): Likewise. + (cipher_get_blocksize): Likewise. + (gcry_cipher_open): Likewise. + (gcry_cipher_id_new): Likewise. + +2003-06-17 Moritz Schulte + + * Makefile.am (GCRYPT_MODULES): Set to @GCRYPT_CIPHERS@, + @GCRYPT_PUBKEY_CIPHERS@, @GCRYPT_DIGESTS@ and @GCRYPT_RANDOM@. + (libcipher_la_DEPENDENCIES): Set to $(GCRYPT_MODULES). + (libcipher_la_LIBADD): Likewise. + (AM_CFLAGS): Added: @GPG_ERROR_CFLAGS@. + (EXTRA_libcipher_la_SOURCES): Added all conditional sources. + + * md.c (md_open): Use _gcry_fast_random_poll instead of + fast_random_poll. + * cipher.c (gcry_cipher_open): Likewise. + + * random.h (fast_random_poll): Removed macro. + + * blowfish.c, md4.c, md5.c, rmd160.c, sha1.c, sha256.c, sha512.c, + tiger.c: Use Autoconf's WORDS_BIGENDIAN instead of our own + BIG_ENDIAN_HOST. + +2003-06-16 Moritz Schulte + + * random.c (getfnc_gather_random): Do not special-case + USE_ALL_RANDOM_MODULES, make it the default. + + * dsa.c: Replace last occurences of old type names with newer + names (i.e. replace MPI with gcry_mpi_t). + * elgamal.c: Likewise. + * primegen.c: Likewise. + * pubkey.c: Likewise. + * rsa.c: Likewise. + +2003-06-14 Moritz Schulte + + * des.c (des_setkey): Add selftest check. + (tripledes_set3keys): Likewise. + (do_tripledes_setkey): Remove selftest check. + (do_des_setkey): Likewise. + +2003-06-11 Moritz Schulte + + * md.c (_gcry_md_init): New function. + * cipher.c (_gcry_cipher_init): New function. + * pubkey.c (_gcry_pk_init): New function. + +2003-06-13 Werner Koch + + * md.c (gcry_md_get_algo): Reverted to old API. This is a + convenience function anyway and error checking is not approriate. + (gcry_md_is_secure): New. + (gcry_md_is_enabled): New. + +2003-06-12 Werner Koch + + * cipher.c (gcry_cipher_open): Make sure HANDLE is set to NULL on + error. + +2003-06-11 Werner Koch + + * md.c (gcry_md_open): Make sure H receives either NULL or an + valid handle. + (gcry_md_copy): Swapped arguments so that it is more in lione with + md_open and most other API fucntions like memcpy (destination + comes first). Make sure HANDLE is set to NULL on error. + + * rijndael.c (do_encrypt): Hack to force correct alignment. It + seems not to be not sufficient, though. We should rework this + fucntions and remove all these ugly casts. Let the compiler + optimize or have an assembler implementation. + +2003-06-09 Moritz Schulte + + * Makefile.am: Removed rules serpent, since that is not commited + yet. + +2003-06-08 Moritz Schulte + + * pubkey.c (gcry_pk_encrypt): Improve calculation for size of the + format string. + +2003-06-07 Moritz Schulte + + * arcfour.c, bithelp.h, blowfish.c, cast5.c, cipher.c, crc.c, + des.c, dsa.c, elgamal.c, md4.c, md5.c, md.c, primegen.c, pubkey.c, + rand-internal.h, random.c, random.h, rijndael.c, rmd160.c, + rmd160test.c, rmd.h, rndeged.c, rndlinux.c, rndunix.c, rndw32.c, + rsa.c, sha1.c, sha256.c, sha512.c, tiger.c, twofish.c: Edited all + preprocessor instructions to remove whitespace before the '#'. + This is not required by C89, but there are some compilers out + there that don't like it. Replaced any occurence of the now + deprecated type names with the new ones. + +2003-06-04 Moritz Schulte + + * pubkey.c (gcry_pk_encrypt): Construct an arg_list and use + gcry_sexp_build_array instead of gcry_sexp_build. + (gcry_pk_sign): Likewise. + (gcry_pk_genkey): Likewise. + +2003-06-01 Moritz Schulte + + * dsa.c (_gcry_dsa_generate): Do not check wether the algorithm ID + does indeed belong to DSA. + (_gcry_dsa_sign): Likewise. + (_gcry_dsa_verify): Likewise. + (_gcry_dsa_get_nbits): Likewise. + + * elgamal.c (_gcry_elg_check_secret_key): Do not check wether the + algorithm ID does indeed belong to ElGamal. + (_gcry_elg_encrypt): Likewise. + (_gcry_elg_decrypt): Likewise. + (_gcry_elg_sign): Likewise. + (_gcry_elg_verify): Likewise. + (_gcry_elg_get_nbits): Likewise. + (_gcry_elg_generate): Likewise. + + * rsa.c (_gcry_rsa_generate): Do not check wether the algorithm ID + does indeed belong to RSA. + (_gcry_rsa_encrypt): Likewise. + (_gcry_rsa_decrypt): Likewise. + (_gcry_rsa_sign): Likewise. + (_gcry_rsa_verify): Likewise. + (_gcry_rsa_get_nbits): Likewise. + +2003-05-30 Moritz Schulte + + * md.c (md_get_algo): Return zero in case to algorithm is enabled. + + * md.c (gcry_md_info): Adjusted for new no-errno-API. + (md_final): Likewise. + (gcry_md_get_algo): Likewise. + * pubkey.c (gcry_pk_get_keygrip): Likewise. + (gcry_pk_ctl): Likewise. + (gcry_pk_algo_info): Likewise. + * des.c (selftest): Likewise. + +2003-05-29 Moritz Schulte + + * md.c (md_enable): Do not forget to release module on error. + (gcry_md_open): Adjusted for new no-errno-API. + (md_open): Likewise. + (md_copy): Likewise. + (gcry_md_copy): Likewise. + (gcry_md_setkey): Likewise. + (gcry_md_algo_info): Likewise. + + * cipher.c (gcry_cipher_open): Adjusted for new no-errno-API and + also fixed a locking bug. + (gcry_cipher_encrypt): Adjusted for new no-errno-API. + (gcry_cipher_decrypt): Likewise. + (gcry_cipher_ctl): Likewise. + (gcry_cipher_info): Likewise. + (gcry_cipher_algo_info): Likewise. + +2003-05-28 Moritz Schulte + + * md.c (md_enable): Adjusted for libgpg-error. + (gcry_md_enable): Likewise. + (gcry_digest_register_default): Likewise. + (gcry_digest_register): Likewise. + (check_digest_algo): Likewise. + (prepare_macpads): Likewise. + (gcry_md_setkey): Likewise. + (gcry_md_ctl): Likewise. + (gcry_md_get): Likewise. + (gcry_md_algo_info): Likewise. + (gcry_md_info): Likewise. + * dsa.c (_gcry_dsa_generate): Likewise. + (_gcry_dsa_check_secret_key): Likewise. + (_gcry_dsa_sign): Likewie. + (_gcry_dsa_verify): Likewise. + * twofish.c (do_twofish_setkey): Likewise. + (twofish_setkey): Likewise. + * cipher.c (gcry_cipher_register): Likewise. + +2003-05-25 Moritz Schulte + + * rijndael.c (do_setkey): Adjusted for libgpg-error. + (rijndael_setkey): Likewise. + * random.c (gcry_random_add_bytes): Likewise. + * elgamal.c (_gcry_elg_generate): Likewise. + (_gcry_elg_check_secret_key): Likewise. + (_gcry_elg_encrypt): Likewise. + (_gcry_elg_decrypt): Likewise. + (_gcry_elg_sign): Likewise. + (_gcry_elg_verify): Likewise. + * rsa.c (_gcry_rsa_generate): Likewise. + (_gcry_rsa_check_secret_key): Likewise. + (_gcry_rsa_encrypt): Likewise. + (_gcry_rsa_decrypt): Likewise. + (_gcry_rsa_sign): Likewise. + (_gcry_rsa_verify): Likewise. + * pubkey.c (dummy_generate, dummy_check_secret_key, dummy_encrypt, + dummy_decrypt, dummy_sign, dummy_verify): Likewise. + (gcry_pubkey_register): Likewise. + (check_pubkey_algo): Likewise. + (pubkey_generate): Likewise. + (pubkey_check_secret_key): Likewise. + (pubkey_encrypt): Likewise. + (pubkey_decrypt): Likewise. + (pubkey_sign): Likewise. + (pubkey_verify): Likewise. + (sexp_elements_extract): Likewise. + (sexp_to_key): Likewise. + (sexp_to_sig): Likewise. + (sexp_to_enc): Likewise. + (sexp_data_to_mpi): Likewise. + (gcry_pk_encrypt): Likewise. + (gcry_pk_decrypt): Likewise. + (gcry_pk_sign): Likewise. + (gcry_pk_verify): Likewise. + (gcry_pk_testkey): Likewise. + (gcry_pk_genkey): Likewise. + (gcry_pk_ctl): Likewise. + * cipher.c (dummy_setkey): Likewise. + (check_cipher_algo): Likewise. + (gcry_cipher_open): Likewise. + (cipher_setkey): Likewise. + (gcry_cipher_ctl): Likewise. + (cipher_encrypt): Likewise. + (gcry_cipher_encrypt): Likewise. + (cipher_decrypt): Likewise. + (gcry_cipher_decrypt): Likewise. + (gcry_cipher_info): Likewise. + (gcry_cipher_algo_info): Likewise. + * cast5.c (cast_setkey): Likewise. + (do_cast_setkey): Likewise. + * arcfour.c (arcfour_setkey): Likewise. + (do_arcfour_setkey): Likewise. + * blowfish.c (do_bf_setkey): Likewise. + (bf_setkey): Likewise. + * des.c (do_des_setkey): Likewise. + (do_tripledes_setkey): Likewise. + +2003-05-22 Moritz Schulte + + * tiger.c: Merged code ussing the U64_C macro from GnuPG. + + * sha512.c: Likewise. + +2003-05-17 Moritz Schulte + + * pubkey.c (gcry_pk_genkey): Fix type: acquire a lock, instead of + releasing it. + +2003-05-11 Moritz Schulte + + * pubkey.c (gcry_pk_testkey): Call REGISTER_DEFAULT_CIPHERS. + (gcry_pk_ctl): Likewise. + +2003-04-27 Moritz Schulte + + * pubkey.c (gcry_pk_genkey): Release sexp after extracted data has + been used. + + * md.c (gcry_md_get_algo_dlen): Simplified, simply call + md_digest_length to do the job. + + * des.c (do_des_setkey): Check for selftest failure not only + during initialization. + (do_tripledes_setkey): Include check for selftest failure. + + * pubkey.c (gcry_pubkey_register_default): New macro + `pubkey_use_dummy', use it. + + * elgamal.c (elg_names): New variable. + (pubkey_spec_elg): Include elg_names. + + * dsa.c (dsa_names): New variable. + (pubkey_spec_dsa): Include dsa_names. + + * rsa.c (rsa_names): New variable. + (pubkey_spec_rsa): Include rsa_names. + + * pubkey.c (gcry_pubkey_lookup_func_name): Compare name also with + the names listed in `sexp_names'. + +2003-04-24 Moritz Schulte + + * pubkey.c (sexp_to_key): New variables: module, pubkey. Adjusted + to new module interface. + (sexp_to_key): Changend type of argument `retalgo' from `int *' to + `GcryModule **'. Adjusted all callers. Removed argument: + r_algotblidx. + (sexp_to_sig): Changend type of argument `retalgo' from `int *' to + `GcryModule **'. Adjusted all callers. + (sexp_to_enc): Likewise. + + (pubkey_get_npkey, pubkey_get_nskey, pubkey_get_nsig, + pubkey_get_nenc): Use strlen to find out the number. + + * rsa.c: Adjust pubkey_spec_rsa to new internal interface. + * dsa.c: Likewise. + * elgamal.c: Likewise. + +2003-04-17 Moritz Schulte + + * pubkey.c (sexp_elements_extract): New function. + * pubkey.c (sexp_to_key): Removed variable `idx', added `err', use + sexp_elements_extract. + (sexp_to_sig): Likewise. + (sexp_to_enc): Likewise. + + * pubkey.c: Terminate list correctly. + * md.c: Include sha512/sha384 in digest_table. + +2003-04-16 Moritz Schulte + + * Makefile.am: Include support for sha512.c. + + * sha512.c: New file, merged from GnuPG, with few modifications + for libgcrypt. + + * rand-internal.h: Removed declarations for constructor functions. + + * md.c (md_copy): Call _gcry_module_use for incrementing the usage + counter of the digest modules. + + * rsa.c: Do not include "rsa.h". + * dsa.c: Do not include "dsa.h". + * elgamal.c: Do not include "elgamal.h". + * des.c: Do not include "des.h". + * cast5.c: Do not include "cast5.h". + * blowfish.c: Do not include "blowfish.h". + * arcfour.c: Do not include "arcfour.h". + + * Makefile.am (libcipher_la_DEPENDENCIES): Removed. + (libcipher_la_LIBADD): Removed. + Use Automake conditionals for conditional compilation. + +2003-04-13 Moritz Schulte + + * cipher.c (gcry_cipher_open): Call REGISTER_DEFAULT_CIPHERS. + + * md.c (gcry_md_list): New member: module. + (md_enable): New variable: module, changed use of module and + digest. + (md_enable): Initialize member: module. + (md_close): Call _gcry_module_release. + + * cipher.c (gcry_cipher_open): New variable: module, changed use of + module and cipher. + (struct gcry_cipher_handle): New member: module. + (gcry_cipher_open): Initialize member: module. + (gcry_cipher_close): Call _gcry_module_release. + +2003-04-09 Moritz Schulte + + * cipher.c: Include "ath.h". + * md.c: Likewise. + * pubkey.c: Likewise. + + * cipher.c (ciphers_registered_lock): New variable. + * md.c (digests_registered_lock): New variable. + * pubkey.c (pubkeys_registered_lock): New variable. + + * rndlinux.c (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_rndlinux_constructor): Removed function. + + * rndegd.c (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_rndegd_constructor): Removed function. + + * rndunix.c (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_rndunix_constructor): Removed function. + + * rndw32.c (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_rndw32_constructor): Removed function. + + * rndegd.c (rndegd_connect_socket): Simplify code for creating the + egd socket address. + (rndegd_connect_socket): Call log_fatal use instead of + g10_log_fatal. + (egd_gather_random): Renamed to ... + (rndegd_gather_random): ... here. + +2003-04-08 Moritz Schulte + + * rndlinux.c: Do not include "dynload.h". + * rndunix.c: Likewise. + * rndw32.c: Likewise. + + * rndegd.c (rndegd_connect_socket): Factored out from ... + (egd_gather_random): here; call it. + (egd_socket): New variable. + (egd_gather_random): Initialize fd with egd_socket, do not declare + fd static. + (do_read): Merged few changes from GnuPG. FIXME - not finished? + Do not include "dynload.h". + + * rndw32.c (gather_random): Renamed to rndw32_gather_random, do + not declare static. + (gather_random_fast): Renamed to rndw32_gather_random_fast, do not + declare static. + + * rndunix.c (gather_random): Renamed to rndunix_gather_random, do + not declare static. + * rndegd.c (gather_random): Renamed to rndegd_gather_random, do + not declare static. + * rndlinux.c (gather_random): Renamed to rndlinux_gather_random, + do not declare static. + +2003-04-07 Moritz Schulte + + * Makefile.am (libcipher_la_SOURCES): Removed construct.c. + (libcipher_la_SOURCES): Added sha1.c, sha256.c, rmd160.c, md4.c, + md5.c, tiger.c and crc.c + (EXTRA_PROGRAMS): Removed sha1, sha256, rmd160, md4, md5, tiger + and crc. Removed definitions: EXTRA_md4_SOURCES, + EXTRA_md5_SOURCES, EXTRA_rmd160_SOURCES, EXTRA_sha1_SOURCES, + EXTRA_sha256_SOURCES, EXTRA_tiger_SOURCES and EXTRA_crc_SOURCES, + BUILT_SOURCES, DISTCLEANFILES. + + * pubkey.c: Do not include "elgamal.h", "dsa.h" and "rsa.h". + + * Makefile.am (libcipher_la_SOURCES): Removed rsa.h, elgamal.h, + dsa.h, des.h, cast5.h, arcfour.h and blowfish.h. + + * rsa.h: Removed file. + * elgamal.h: Removed file. + * dsa.h: Removed file. + * des.h: Removed file. + * cast5.h: Removed file. + * arcfour.h: Removed file. + * blowfish.h: Removed file. + + * Makefile.am (libcipher_la_SOURCES): Removed dynload.c and + dynload.h. + + * rsa.c (pubkey_spec_rsa): New variable. + * dsa.c (pubkey_spec_rsa): New variable. + * elgamal.c (pubkey_spec_elg): New variable. + + * rsa.c (_gcry_rsa_get_info): Removed function. + * elgamal.c (_gcry_elg_get_info): Removed function. + * dsa.c (_gcry_dsa_get_info): Removed function. + + * tiger.c (tiger_get_info): Removed function. + (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_tiger_constructor): Removed function. + + * sha1.c (sha1_get_info): Removed function. + (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_sha1_constructor): Removed function. + + * sha256.c (sha256_get_info): Removed function. + (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_sha256_constructor): Removed function. + + * rmd160.c (rmd160_get_info): Removed function. + (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_rmd160_constructor): Removed function. + + * md5.c (md5_get_info): Removed function. + (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_md5_constructor): Removed function. + + * md4.c (md4_get_info): Removed function. + (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func): Removed function. + (_gcry_md4_constructor): Removed function. + + * crc.c (crc_get_info): Removed function. + + * arcfour.c (do_arcfour_setkey): Changed type of context argument + to `void *', added local variable for cast, adjusted callers. + (arcfour_setkey): Likewise. + (encrypt_stream): Likewise. + * cast5.c (cast_setkey): Likewise. + (encrypt_block): Likewise. + * rijndael.c (rijndael_setkey): Likewise. + (rijndael_encrypt): Likewise. + (rijndael_decrypt): Likewise. + * twofish.c (twofish_setkey): Likewise. + (twofish_encrypt): Likewise. + (twofish_decrypt): Likewise. + * des.c (do_des_setkey): Likewise. + (do_des_encrypt): Likewise. + (do_des_encrypt): Likewise. + (do_tripledes_encrypt): Likewise. + (do_tripledes_encrypt): Likewise. + * blowfish.c (bf_setkey: Likewise. + (encrypt_block): Likewise. + (decrypt_block): Likewise. + + * arcfour.c (encrypt_stream): Likewise. + + * rijndael.c (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func) Removed function. + + * twofish.c (gnupgext_version, func_table): Removed definitions. + (gnupgext_enum_func) Removed function. + + * cast5.c (CIPHER_ALGO_CAST5): Removed. + + * blowfish.c (FNCCAST_SETKEY, FNCCAST_CRYPT): Removed macros. + (CIPHER_ALGO_BLOWFISH): Removed symbol. + * cast5.c (FNCCAST_SETKEY, FNCCAST_CRYPT): Likewise. + * des.c (selftest_failed): Removed. + (initialized): New variable. + (do_des_setkey): Run selftest, if not yet done. + (FNCCAST_SETKEY, FNCCAST_CRYPT): Removed macros. + + * arcfour.c (_gcry_arcfour_get_info): Removed function. + * blowfish.c (_gcry_blowfish_get_info): Removed function. + * cast5.c (_gcry_cast5_get_info): Removed function. + * des.c (_gcry_des_get_info): Removed function. + * rijndael.c (_gcry_rijndael_get_info): Removed function. + * twofish.c (_gcry_twofish_get_info): Removed function. + + * arcfour.c (cipher_spec_arcfour): New variable. + * twofish.c (cipher_spec_twofish, cipher_spec_twofish128): New + variables. + * rijndael.c (cipher_spec_aes, cipher_spec_aes192, + cipher_spec256): New variables. + * des.c (cipher_spec_des, cipher_spec_tripledes): New variables. + * cast5.c (cipher_spec_cast5): New variable. + * blowfish.c (cipher_spec_blowfish): Likewise. + + * twofish.c: Do not include "dynload.h". + * rijndael.c: Likewise. + * des.c: Likewise. + * cast5.c: Likewise. + * blowfish.c: Likewise. + * cipher.c: Likewise. + * crc.c: Likewise. + * md4.c: Likewise. + * md5.c: Likewise. + * md.c: Likewise. + * pubkey.c: Likewise. + * rijndael.c: Likewise. + * sha1.c: Likewise. + * sha256.c: Likewise. + + * arcfour.c: Include "cipher.h". + * twofish.c: Likewise. + * rijndael.c: Likewise. + * des.c: Likewise. + * cast5.c: Likewise. + * blowfish.c: Likewise. + + * twofish.c (twofish_setkey): Declared argument `key' const. + (twofish_encrypt): Declared argument `inbuf' const. + (twofish_decrypt): Likewise. + + * rijndael.c (rijndael_setkey): Declared argument `key' const. + (rijndael_encrypt): Declared argument `inbuf' const. + (rijndael_decrypt): Likewise. + + * des.c (do_des_setkey): Declared argument `key' const. + (do_tripledes_setkey): Likewise. + (do_des_encrypt): Declared argument `inbuf' const. + (do_des_decrypt): Likewise. + (do_tripledes_encrypt): Likewise. + (do_tripledes_decrypt): Likewise. + + * cast5.c (encrypt_block): Declared argument `inbuf' const. + (decrypt_block): Likewise. + (cast_setkey): Declared argument `key' const. + + * blowfish.c (do_bf_setkey): Declared argument `key' const. + (encrypt_block): Declared argument `inbuf' const. + (encrypt_block): Likewise. + + + + * cipher.c: Remove CIPHER_ALGO_DUMMY related code. + Removed struct cipher_table_s. + Changed definition of cipher_table. + Removed definition of disabled_algos. + (ciphers_registered, default_ciphers_registered): New variables. + (REGISTER_DEFAULT_CIPHERS): New macro. + (dummy_setkey): Declared argument `key' const. + (dummy_encrypt_block): Declared argument `inbuf' const. + (dummy_encrypt_block): Likewise. + (dummy_encrypt_stream): Likewise. + (dummy_encrypt_stream): Likewise. + (dummy_setkey): Use `unsigned char' instead of `byte'. + (dummy_encrypt_block): Likewise. + (dummy_decrypt_block): Likewise. + (dummy_encrypt_stream): Likewise. + (dummy_decrypt_stream): Likewise. + (gcry_cipher_register_default): New function. + (gcry_cipher_lookup_func_id): New function. + (gcry_cipher_lookup_func_name): New function. + (gcry_cipher_lookup_id): New function. + (gcry_cipher_lookup_name): New function. + (gcry_cipher_id_new): New function. + (gcry_cipher_register): New function. + (gcry_cipher_unregister): New function. + (setup_cipher_table): Removed function. + (load_cipher_modules): Removed function. + (gcry_cipher_map_name): Adjusted to use new module management. + (cipher_algo_to_string): Likewise. + (disable_cipher_algo): Likewise. + (check_cipher_algo): Likewise. + (cipher_get_keylen): Likewise. + (cipher_get_blocksize): Likewise. + (gcry_cipher_open): Likewise. + (struct gcry_cipher_handle): Replaced members algo, algo_index, + blocksize, setkey, encrypt, decrypt, stencrypt, stdecrypt with one + member: cipher. + (gcry_cipher_open): Adjusted code for new handle structure. + (cipher_setkey): Likewise. + (cipher_setiv): Likewise. + (cipher_reset): Likewise. + (do_ecb_encrypt): Likewise. + (do_ecb_decrypt): Likewise. + (do_cbc_encrypt): Likewise. + (do_cbc_decrypt): Likewise. + (do_cfb_encrypt): Likewise. + (do_cfb_decrypt): Likewise. + (do_ctr_encrypt): Likewise. + (cipher_encrypt): Likewise. + (gcry_cipher_encrypt): Likewise. + (cipher_decrypt): Likewise. + (gcry_cipher_decrypt): Likewise. + (cipher_sync): Likewise. + (gcry_cipher_ctl): Likewise. + + * pubkey.c: Removed struct pubkey_table_s. + Changed definition of pubkey_table. + Removed definition of disabled_algos. + (pubkeys_registered, default_pubkeys_registered): New variables. + (REGISTER_DEFAULT_PUBKEYS): New macro. + (setup_pubkey_table): Removed function. + (load_pubkey_modules): Removed function. + (gcry_pubkey_register_default): New function. + (gcry_pubkey_lookup_func_id): New function. + (gcry_pubkey_lookup_func_name): New function. + (gcry_pubkey_lookup_id): New function. + (gcry_pubkey_lookup_name): New function. + (gcry_pubkey_id_new): New function. + (gcry_pubkey_register): New function. + (gcry_pubkey_unregister): New function. + (gcry_pk_map_name): Adjusted to use new module management. + (gcry_pk_algo_name): Likewise. + (disable_pubkey_algo): Likewise. + (check_pubkey_algo): Likewise. + (pubkey_get_npkey): Likewise. + (pubkey_get_nskey): Likewise. + (pubkey_get_nsig): Likewise. + (pubkey_get_nenc): Likewise. + (pubkey_generate): Likewise. + (pubkey_check_secret_key): Likewise. + (pubkey_encrypt): Likewise. + (pubkey_decrypt): Likewise. + (pubkey_sign): Likewise. + (pubkey_verify): Likewise. + (gcry_pk_get_nbits): Likewise. + (gcry_pk_algo_info): Likewise. + + * md.c: Removed struct md_digest_list_s. + (digest_list): Changed definition. + (digests_registered, default_digests_registered): New variables. + (REGISTER_DEFAULT_DIGESTS): New macro. + (new_list_item): Removed function. + (setup_md_table): Removed function. + (load_digest_module): Removed function. + (gcry_digest_register_default): New function. + (gcry_digest_lookup_func_id): New function. + (gcry_digest_lookup_func_name): New function. + (gcry_digest_lookup_id): New function. + (gcry_digest_lookup_name): New function. + (gcry_digest_id_new): New function. + (gcry_digest_register): New function. + (gcry_digest_unregister): New function. + (GcryDigestEntry): New type. + (struct gcry_md_context): Adjusted type of `list'. + (gcry_md_map_name): Adjusted to use new module management. + (digest_algo_to_string): Likewise. + (check_digest_algo): Likewise. + (md_enable): Likewise. + (md_digest_length): Likewise. + (md_asn_oid): Likewise. + +2003-04-07 Moritz Schulte + + * pubkey.c: Replaced PUBKEY_ALGO_DSA with GCRY_PK_DSA, + PUBKEY_ALGO_RSA with GCRY_PK_RSA and PUBKEY_ALGO_ELGAMAL with + GCRY_PK_ELG. + + * dsa.c: Replaced PUBKEY_ALGO_DSA with GCRY_PK_DSA. + +2003-04-01 Moritz Schulte + + * des.c: Removed checks for GCRY_CIPHER_3DES and GCRY_CIPHER_DES. + +2003-03-31 Moritz Schulte + + * tiger.c (tiger_get_info): Do not declare static. + * sha256.c (sha256_get_info): Likewise. + * sha1.c (sha1_get_info): Likewise. + * rmd160.c (rmd160_get_info): Likewise. + * md5.c (md5_get_info): Likewise. + * md4.c (md4_get_info): Likewise. + * crc.c (crc_get_info): Likewise. + + * md.c (load_digest_module): Call setup_md_table during + initialization. + (new_list_item): Link new element into digest_list. + + * cipher.c (do_ctr_decrypt): Made do_ctr_encrypt act as a wrapper + for do_ctr_encrypt, since these functions are identical. + +2003-03-30 Simon Josefsson + + * cipher.c (struct gcry_cipher_handle): Add counter field. + (gcry_cipher_open): Add CTR. + (cipher_reset): Clear counter field. + (do_ctr_encrypt, do_ctr_decrypt): New functions. + (cipher_encrypt, cipher_decrypt): Call CTR functions. + (gcry_cipher_ctl): Add SET_CTR to set counter. + +2003-03-30 Moritz Schulte + + * rsa.c (_gcry_rsa_blind): New function. + (_gcry_rsa_unblind): New function. + (_gcry_rsa_decrypt): Use _gcry_rsa_blind and _gcry_rsa_decrypt. + +2003-03-26 Moritz Schulte + + * dynload.c (_gcry_enum_gnupgext_pubkeys): Adjust `encrypt' and + `decrypt' function arguments. + (_gcry_enum_gnupgext_pubkeys): Likewise. + * dynload.h: Likewise. + + * pubkey.c (dummy_decrypt): Add argument: int flags. + (dummy_encrypt): Likewise. + + * elgamal.c (_gcry_elg_encrypt): Add argument: int flags. + (_gcry_elg_decrypt): Likewise. + + * rsa.c (_gcry_rsa_encrypt): Add argument: int flags. + (_gcry_rsa_decrypt): Likewise. + + * pubkey.c: Add `flags' argument to members `encrypt' and + `decrypt' of struct `pubkey_table_s'. + + * rsa.h: Add `flags' argument to function declarations. + * elgamal.h: Likewise. + + * pubkey.c (sexp_data_to_mpi): New variable: int parsed_flags. + (sexp_data_to_mpi): Set `parsed_flags'. + (sexp_data_to_mpi): New argument: int *flags. + (gcry_pk_encrypt): New variable: int flags. + (gcry_pk_encrypt): Pass `flags' to pubkey_encrypt. + (pubkey_encrypt): New variable: int flags. + (pubkey_encrypt): Pass `flags' to pubkey encrypt function. + (pubkey_decrypt): Likewise. + (pubkey_decrypt): Pass `flags' to pubkey encrypt function. + (gcry_pk_encrypt): Include `flags' s-exp in return list. + (sexp_to_enc): New argument: int *flags. + (gcry_pk_decrypt): New variable: int flags. + (gcry_pk_decrypt): Pass `flags' to pubkey_decrypt. + (sexp_to_enc): New variable: int parsed_flags. + (sexp_to_enc): Set `parsed_flags'. + +2003-03-22 Simon Josefsson + + * cipher.c (gcry_cipher_open, do_cbc_encrypt) + (gcry_cipher_encrypt): Support GCRY_CIPHER_CBC_MAC. + (gcry_cipher_ctl): Support GCRYCTL_SET_CBC_MAC. + +2003-03-19 Werner Koch + + * primegen.c (gen_prime): New args EXTRA_CHECK and EXTRA_CHECK_ARG + to allow for a user callback. Changed all callers. + (_gcry_generate_secret_prime) + (_gcry_generate_public_prime): Ditto, pass them to gen_prime. + * rsa.c (check_exponent): New. + (generate): Use a callback to ensure that a given exponent is + actually generated. + +2003-03-12 Moritz Schulte + + * primegen.c: Initialize `no_of_small_prime_numbers' statically. + (gen_prime): Remove calculation of `no_of_small_prime_numbers'. + +2003-03-03 Moritz Schulte + + * md.c (gcry_md_ctl): Rewritten to use same style like the other + functions dispatchers. + +2003-03-02 Moritz Schulte + + * cipher.c (struct gcry_cipher_handle): New member: algo_index. + (gcry_cipher_open): Allocate memory for two cipher contexts. + Initialize algo_index. + (cipher_setkey): Duplicate context into reserved memory. + (cipher_reset): New function, which resets the context and clear + the IV. + (gcry_cipher_ctl): Call cipher_reset. + +2003-02-23 Moritz Schulte + + * cipher.c: Remove (bogus) `digitp' macro definition. + * md.c: Likewise. + + * blowfish.c (burn_stack): Removed. + * arcfour.c (burn_stack): Likewise. + * cast5.c (burn_stack): Likewise. + * des.c (burn_stack): Likewise. + * md4.c (burn_stack): Likewise. + * md5.c (burn_stack): Likewise. + * random.c (burn_stack): Likewise. + * rijndael.c (burn_stack): Likewise. + * rmd160.c (burn_stack): Likewise. + * sha1.c (burn_stack): Likewise. + * sha256.c (burn_stack): Likewise. + * tiger.c (burn_stack): Likewise. + * twofish.c (burn_stack): Likewise. + + * blowfish.c: Changed all occurences of burn_stack to + _gcry_burn_stack. + * arcfour.c: Likewise. + * cast5.c: Likewise. + * des.c: Likewise. + * md4.c: Likewise. + * md5.c: Likewise. + * random.c: Likewise. + * rijndael.c: Likewise. + * rmd160.c: Likewise. + * sha1.c: Likewise. + * sha256.c: Likewise. + * tiger.c: Likewise. + * twofish.c: Likewise. + + * arcfour.c (_gcry_arcfour_get_info): Use GCRY_CIPHER_ARCFOUR + instead of hard-coded value `301'. + +2003-01-24 Werner Koch + + * random.c (_gcry_register_random_progress): New. + (_gcry_random_progress): New. + + * rndlinux.c (gather_random): Call the random progress function. + +2003-01-23 Werner Koch + + * rsa.c (generate): New arg USE_E to request a specific public + exponent. + (_gcry_rsa_generate): Ditto. + * elgamal.c (_gcry_elg_generate): Must add an dummy argument + instead of USE_E. + * dsa.c (_gcry_dsa_generate): Ditto. + * pubkey.c (dummy_generate): Ditto. + (pubkey_generate): Add USE_E arg and pass it down. + (gcry_pk_genkey): Detect "rsa-use-e" parameter and pass it to generate. + + * pubkey.c (sexp_to_enc): New arg RET_MODERN. + (gcry_pk_decrypt): Make use of it to return a real S-expression. + Return better error codes. + (gcry_pk_verify): Return better error codes. + +2003-01-21 Werner Koch + + * random.c (gcry_random_add_bytes): Add QUALITY argument, let + function return an error code and disable its core for now. + +2003-01-21 Timo Schulz + + * random.c (gcry_random_add_bytes): New. Function to add external + random to the pool. + +2003-01-20 Simon Josefsson + + * crc.c: New. + * Makefile.am (EXTRA_PROGRAMS, EXTRA_crc_SOURCES): Add crc.c. + * md.c (gcry_md_get_algo_dlen): Add values for CRC. + +2003-01-20 Werner Koch + + * sha256.c: New. + * bithelp.h (ror): New. + * Makfile.am: Add sha256.c. + * md.c (oid_table): Add values for SHA256 et al. + (gcry_md_get_algo_dlen): Likewise + +2003-01-20 Werner Koch + + * pubkey.c (gcry_pk_get_keygrip): Implemented keygrips for DSA + and ElGamal. + +2003-01-17 Werner Koch + + * cipher.c (gcry_cipher_encrypt): Reworked so that the output will + never contain the plaintext even if the caller did not checked the + return value. + + * md.c (gcry_md_get_algo): Changed error code to GCRYERR_GENERAL + because we don't have an invalid md algo but no algorithm enabled. + + * pubkey.c (gcry_pk_genkey): Changed error code for bounds check + of table parameters to GCRYERR_INTERNAL. + + * md.c (gcry_md_open): Partly reverted Timo's change from + 2002-10-10 by removing the check for the algorithm. An algorithm + of 0 is allowed and anyway we should not double check it or check + it using a different function. Also fixed the flags check. + + * pubkey.c (gcry_pk_encrypt): Make sure that R_CIPH points to NULL + on error. + (gcry_pk_decrypt): Ditto for R_PLAIN. + (gcry_pk_sign): Ditto for R_SIG. + (gcry_pk_genkey): Ditto for R_KEY. + +2003-01-16 Werner Koch + + * md.c (gcry_md_write): Changed 2nd argument type to void*. + (gcry_md_hash_buffer): Changed type of boths buffers to void*. + (gcry_md_setkey): Changed 2nd argument type to void*. + +2003-01-15 Werner Koch + + * pubkey.c (sexp_data_to_mpi): New. This handles pkcs1 padding. + (gcry_pk_sign, gcry_pk_verify): Use it here. + (gcry_pk_encrypt): And here. + (pubkey_verify): Add debug code. + (sexp_to_enc): Handle flags in the input and return the pkcs1 flag + in a new parameter. + (gcry_pk_decrypt): Prepare for future pkcs1 handling. + +2002-12-19 Werner Koch + + * random.c (_gcry_random_initialize): New. + +2002-12-16 Werner Koch + + * cipher.c: Added a Teletrust specific OID for 3DES. + +2002-12-12 Werner Koch + + * md.c: Added another oddball OIW OID (sha-1WithRSAEncryption). + +2002-11-23 Werner Koch + + * md.c (load_digest_module): Enlarged checked_algos bitmap. + * md4.c (func_table): Fixed entry for md4. + Both by Simon Josephson. + (transform): Copy data to get the alignment straight. Tested only + on i386. + +2002-11-10 Simon Josefsson + + * cipher.c (gcry_cipher_open): Don't reject CTS flag. + (do_cbc_encrypt, do_cbc_decrypt, cipher_encrypt) + (gcry_cipher_encrypt, cipher_decrypt) + (gcry_cipher_decrypt): Support CTS flag. + (gcry_cipher_ctl): Toggle CTS flag. + +2002-11-10 Werner Koch + + * md4.c: New. By Simon Josefsson. + * Makefile.am (EXTRA_PROGRAMS): Add md4.c. + * md.c (oid_table,gcry_md_get_algo_dlen): MD4 support. + +2002-10-14 Werner Koch + + * arcfour.c (do_encrypt_stream): Don't use increment op when + assigning to the same variable. + +2002-10-10 Timo Schulz + + * pubkey.c (gcry_pk_genkey): Check boundaries. + + * md.c (gcry_md_open): Check that algo is available and only + valid flag values are used. + (gcry_md_get_algo): Add error handling. + +2002-09-26 Werner Koch + + * md.c: Include an OID for TIGER. + * tiger.c (tiger_get_info): Use a regular OID. + +2002-09-17 Werner Koch + + * random.c: Replaced mutex.h by the new ath.h. Changed all calls. + +2002-09-16 Werner Koch + + * arcfour.c (do_encrypt_stream): Use register modifier and modulo. + According to Nikos Mavroyanopoulos this increases perfromace on + i386 system noticable. And I always tought gcc is clever enough. + * md5.c (transform): Use register modifier. + * rmd160.c (transform): Ditto. + * sha1.c (transform): Ditto. We hope that there are 6 free registers. + * random.c (gcry_randomize): Rewrote to avoid malloc calls. + + * rndlinux.c (gather_random): Replaced remaining fprintfs by log_*. + * arcfour.c (do_arcfour_setkey): Ditto. + * twofish.c (do_twofish_setkey): Ditto. + * rndegd.c (gather_random): Ditto. + * rijndael.c (do_setkey): Ditto. + * random.c (_gcry_random_dump_stats): Ditto. + * primegen.c (_gcry_generate_elg_prime): Ditto. + * des.c (_gcry_des_get_info): Ditto. + * cast5.c (do_cast_setkey): Ditto. + * blowfish.c (do_bf_setkey): Ditto. + +2002-08-26 Werner Koch + + * des.c (weak_keys): Fixed one entry in the table and compared + all entries against the literature. + (selftest): Checksum the weak key table. + +2002-08-21 Werner Koch + + * pubkey.c: Enable keygrip calculation for "openpgp-rsa". + +2002-08-17 Werner Koch + + * cipher.c (setup_cipher_table): Don't overwrite the DES entry + with the entry for DUMMY. + +2002-08-14 Werner Koch + + * des.c (do_des_setkey,do_des_encrypt, do_des_decrypt): New. + (_gcry_des_get_info): Support plain old DES. + * cipher.c (setup_cipher_table): Put DES into the table. + +2002-07-25 Werner Koch + + * rndunix.c (_gcry_rndunix_constructor): Prefixed with _gcry_. + Noted by Stephan Austermuehle. + +2002-07-08 Timo Schulz + + * rndw32.c: Replaced the m_ memory functions with the real + gcry_ functions. Renamed all g10_ prefixed functions to log_. + +2002-06-12 Werner Koch + + * rsa.c (generate): Use e = 65537 for now. + +2002-06-11 Werner Koch + + * pubkey.c (gcry_pk_get_keygrip): Allow a "protected-private-key". + +2002-06-05 Timo Schulz + + * cipher.c (gcry_cipher_encrypt, gcry_cipher_decrypt): + Check that the input size is a multiple of the blocksize. + +2002-05-23 Werner Koch + + * md.c (oid_table): Add an rsadsi OID for MD5. + +2002-05-21 Werner Koch + + * primegen.c, elgamal.c, dsa.c (progress): Do not print anything + by default. Pass an extra identifying string to the callback and + reserved 2 argumenst for current and total counters. Changed the + register function prototype. + +2002-05-17 Werner Koch + + * rndegd.c (rndegd_constructor): Fixed name of register function + and prefixed the function name with _gcry_. + * rndw32.c (rndw32_constructor): Ditto. + * tiger.c (tiger_constructor): Ditto. + + * Makefile.am: Removed all dynamic loading stuff. + * dynload.c: Ditto. Now only used for the constructor system. + +2002-05-15 Werner Koch + + * random.c (gcry_random_bytes,gcry_random_bytes_secure) + (gcry_randomize): Make sure we are initialized. + +2002-05-14 Werner Koch + + Changed license of most files to the LGPL. + +2002-05-02 Werner Koch + + * random.c (_gcry_fast_random_poll): Initialize the module so the + mutex can be used. + + * primegen.c (small_prime_numbers): Moved table from smallprime.c + * smallprime.c: File removed. + + * des.c (leftkey_swap, rightkey_swap, working_memcmp): Made static. + + * cipher.c (gcry_cipher_map_name): Map "RIJNDAEL" to "AES". + * rijndael.c (rijndael_get_info): We do only support a 128 bit + blocksize so it makes sense to change the algorithm strings to + AES. + + * tiger.c (tiger_final): Removed superfluous token pasting operators. + * md5.c (md5_final): Ditto. + +2002-04-30 Werner Koch + + * cipher.c: Fixed list of copyright years. + +2002-03-18 Werner Koch + + * random.c (initialize): Initialize the new pool lock mutex. + (_gcry_fast_random_poll): Add locking and moved main + code out to... + (do_fast_random_poll): new function. + (read_pool): Use the new function here. + (get_random_bytes): Add locking. + (_gcry_update_random_seed_file): Ditto. + +2002-03-11 Werner Koch + + * md.c: Add rsaSignatureWithripemd160 to OID table. + +2002-02-20 Werner Koch + + * sha1.c: Removed a left over comment note. The code has been + rewritten from scratch in 1998. Thanks to Niels Möller for + reporting this misleading comment. + +2002-02-18 Werner Koch + + * rndunix.c (rndunix_constructor): Use the the new prefixed + function name. Reported by Jordi Mallach. + +2002-02-10 Werner Koch + + * random.c (mix_pool): Carry an extra failsafe_digest buffer + around to make the function more robust. + +2002-02-08 Werner Koch + + * random.c (add_randomness): Xor new data into the pool and not + just copy it. This avoids any choosen input attacks which are not + serious in our setting because an outsider won't be able to mix + data in and even then we keep going with a PRNG. Thanks to Stefan + Keller for pointing this out. + +2002-01-04 Werner Koch + + * pubkey.c (gcry_pk_genkey): Do not release skey - it is static. + + * primegen.c (gen_prime): Of course we should use set_bit + and not set_highbit to set the second high bit. + +2001-12-18 Werner Koch + + * rsa.c (generate): Loop until we find the exact modulus size. + Changed the exponent to 41. + (rsa_get_info): s/usage/r_usage/ to avoid shadow warnings. + * primegen.c (gen_prime): Set 2 high order bits for secret primes. + + * Makefile.am (DISTCLEANFILES): Include construct.c. + +2001-12-17 Werner Koch + + * pubkey.c (gcry_pk_get_keygrip): New - experimental. + +2001-12-11 Werner Koch + + * cipher.c: Added OIDs for AES. + (gcry_cipher_mode_from_oid): New. + (gcry_cipher_map_name): Moved OID search code to .. + (search_oid): .. new function. + +2001-12-10 Werner Koch + + * pubkey.c (gcry_pk_encrypt): Find the signature algorithm by name + and not by number. + + * pubkey.c (gcry_pk_encrypt,gcry_pk_decrypt,gcry_pk_sign) + (gcry_pk_verify,gcry_pk_testkey, gcry_pk_genkey) + (gcry_pk_get_nbits): Release the arrays. Noted by Nikos + Mavroyanopoulos. + +2001-12-06 Werner Koch + + * cipher.c (gcry_cipher_map_name): Look also for OIDs prefixed + with "oid." or "OID.". + +2001-12-05 Werner Koch + + * pubkey.c (algo_info_table): Fixed entry for openpgp-rsa. + +2001-11-24 Werner Koch + + * pubkey.c: Added the rsaEncryption OID to the tables. + (sexp_to_key): Add an arg to return the index of the algorithm, + changed all callers. + (gcry_pk_sign): Find the signature algorithm by name and not by + number. + (gcry_pk_get_nbits): Fixed so that we can now really pass a secret + key to get the result. + + * md.c (gcry_md_map_name): Look also for OIDs prefixed with "oid." + or "OID." so that an OID string can be used as an S-Exp token. + +2001-11-20 Werner Koch + + * md.c (gcry_md_map_name): Lookup by OID if the the name begins + with a digit. + (oid_table): New. + +2001-11-16 Werner Koch + + * md.c (gcry_md_info): New operator GCRYCTL_IS_ALGO_ENABLED. + +2001-11-07 Werner Koch + + * md.c (gcry_md_hash_buffer): Close the handle which was left open + for algorithms other than rmd160. + +2001-08-08 Werner Koch + + * rndw32.c (gather_random): Use toolhelp in addition to the NT + gatherer for Windows2000. Suggested by Sami Tolvanen. + + * random.c (read_pool): Fixed length check, this used to be one + byte to strict. Made an assert out of it because the caller has + already made sure that only poolsize bytes are requested. + Reported by Marcus Brinkmann. + +2001-08-03 Werner Koch + + * cipher.c (cipher_encrypt, cipher_decrypt): Prepare to return + errors. We have to change the interface to all ciphers to make + this really work but we should do so to prepare for hardware + encryption modules. + (gcry_cipher_encrypt, gcry_cipher_decrypt): Return the error and + set lasterr. + (gcry_cipher_ctl): Make sure that errors from setkey are returned. + +2001-08-02 Werner Koch + + * rndlinux.c (gather_random): casted a size_t arg to int so that + the format string is correct. Casting is okay here and avoids + translation changes. + + * random.c (fast_random_poll): Do not check the return code of + getrusage. + + * rndunix.c: Add a signal.h header to avoid warnings on Solaris 7 + and 8. + + * tiger.c (print_abc,print_data): Removed. + + * rijndael.c, des.c, blowfish.c, twofish.c, cast5.c, arcfour.c + (burn_stack): New. Add wrappers for most functions to be able to + call burn_stack after the function invocation. This methods seems + to be the most portable way to zeroise the stack used. It does + only work on stack frame based machines but it is highly portable + and has no side effects. Just setting the automatic variables at + the end of a function to zero does not work well because the + compiler will optimize them away - marking them as volatile would + be bad for performance. + * md5.c, sha1.c, rmd160.c, tiger.c (burn_stack): Likewise. + * random.c (burn_stack): New. + (mix_pool): Use it here to burn the stack of the mixblock function. + + * primegen.c (_gcry_generate_elg_prime): Freed q at 3 places. + Thanks to Tommi Komulainen. + + * arcfour.c (arcfour_setkey): Check the minimim keylength against + bytes and not bits. + (selftest): Must reset the key before decryption. + +2001-05-31 Werner Koch + + * sha1.c (sha1_init): Made static. + + Changed all g10_ prefixed function names as well as some mpi_ + function names to cope with the introduced naming changes. + + * md.c (prepare_macpads): Made key const. + +2001-05-28 Werner Koch + + * rndegd.c (gather_random): Removed the use of tty_printf. + +2001-03-29 Werner Koch + + * md5.c (md5_final): Fixed calculation of hashed length. Thanks + to disastry@saiknes.lv for pointing out that it was horrible wrong + for more than 512MB of input. + * sha1.c (sha1_final): Ditto. + * rmd160.c (rmd160_final): Ditto. + * tiger.c (tiger_final): Ditto. + + * blowfish.c (encrypt,do_encrypt): Changed name to do_encrypt to + avoid name clashes with an encrypt function in stdlib.h of + Dynix/PIX. Thanks to Gene Carter. + * elgamal.c (encrypt,do_encrypt): Ditto. + + * twofish.c (gnupgext_enum_func): Use only when when compiled as a + module. + * rijndael.c (gnupgext_enum_func): Ditto. + + * tiger.c (tiger_get_info): Return "TIGER192" and not just + "TIGER". By Edwin Woudt. + + * random.c: Always include time.h - standard requirement. Thanks + to James Troup. + + * rndw32.c: Fixes to the macros. + +2001-01-11 Werner Koch + + * cipher.c (cipher_encrypt,gcry_cipher_encrypt): Use blocksize and + not 8. + +2000-12-19 Werner Koch + + Major change: + Removed all GnuPG stuff and renamed this piece of software + to gcrypt. + +2000-11-14 Werner Koch + + * dsa.c (test_keys): Replaced mpi_alloc by gcry_mpi_new and + mpi_free by gcry_mpi_release. + * elgamal.c (test_keys,generate): Ditto, also for mpi_alloc_secure. + * rsa.c (test_keys,generate,rsa_verify): Ditto. + * primegen.c (generate_elg_prime): Ditto. + (gen_prime): Ditto and removed nlimbs. + + * rsa.c (generate): Allocate 2 more vars in secure memory. + + * Makefile.am (OMIT_DEPENDENCIES): Hack to work around dependency + problems. + +2000-10-09 Werner Koch + + * arcfour.c, arcfour.h: New. + * cipher.c (cipher_encrypt, cipher_decrypt): Add stream mode. + (setup_cipher_table): Add Arcfour. + (gcry_cipher_open): Kludge to allow stream mode. + +Wed Oct 4 13:16:18 CEST 2000 Werner Koch + + * sha1.c (transform): Use rol() macro. Actually this is not needed + for a newer gcc but there are still aoter compilers. + + * rsa.c (test_keys): Use new random function. + + * md.c (gcry_md_setkey): New function to overcome problems with + const conflics. + (gcry_md_ctl): Pass set key to the new functions. + + * rijndael.c: New. + * cipher.c: Add Rijndael support. + +Mon Sep 18 16:35:45 CEST 2000 Werner Koch + + * rndlinux.c (open_device): Loose random device checking. + By Nils Ellmenreich. + + * random.c (fast_random_poll): Check ENOSYS for getrusage. + * rndunix.c: Add 2 sources for QNX. By Sam Roberts. + + * pubkey.c (gcry_pk_algo_info): Add GCRYCTL_GET_ALGO_USAGE. + + * rsa.c: Changed the comment about the patent. + (secret): Speed up by using the CRT. For a 2k keys this + is about 3 times faster. + (stronger_key_check): New but unused code to check the secret key. + * Makefile.am: Included rsa.[ch]. + * pubkey.c: Enabled RSA support. + (pubkey_get_npkey): Removed RSA workaround. + +Mon Jul 31 10:04:47 CEST 2000 Werner Koch + + * pubkey.c: Replaced all gcry_sexp_{car,cdr}_{data,mpi} by the new + gcry_sexp_nth_{data,mpi} functions. + +Tue Jul 25 17:44:15 CEST 2000 Werner Koch + + * pubkey.c (exp_to_key,sexp_to_sig,sexp_to_enc,gcry_pk_encrypt, + gcry_pk_decrypt,gcry_pk_sign,gcry_pk_genkey): Changed to work with + the new S-Exp interface. + +Mon Jul 17 16:35:47 CEST 2000 Werner Koch + + * random.c (gather_faked): Replaced make_timestamp by time(2) again. + +Fri Jul 14 19:38:23 CEST 2000 Werner Koch + + * md.c (gcry_md_ctl): Support GCRYCTL_{START,STOP}_DUMP. + + * Makefile.am: Never compile mingw32 as module. + + * Makefile.am: Tweaked module build and removed libtool + + * Makefile.am: Replaced -O1 by -O. Suggested by Alec Habig. + + * elgamal.c (sign): Removed inactive code. + + * rsa.c, rsa.h: New based on the old module version (only in CVS for now). + * pubkey.c (setup_pubkey_table): Added commented support for RSA. + + * rndunix.c (waitpid): New. For UTS 2.1. All by Dave Dykstra. + (my_popen): Do the FD_CLOEXEC only if it is available + (start_gatherer): Cope with missing _SC_OPEN_MAX + + * rndunix.c: Add some more headers for QNX. By Sam Roberts. + + * rndegd.c (gather_random): Shortcut level 0. + * rndunix.c (gather_random): Ditto. + * rndw32.c (gather_random): Ditto. + + * rndw32.c: Replaced with code from Cryptlib and commented the old stuff. + * rndw32.c: Add some debuging code enabled by an environment variable. + + * random.c (read_seed_file): Binary open for DOSish system + (update_random_seed_file): Ditto. + * random.c [MINGW32]: Include process.h for getpid. + * random.c (fast_random_poll): Add clock_gettime() as fallback for + system which support this POSIX.4 fucntion. By Sam Roberts. + + * random.c (read_seed_file): Removed the S_ISLNK test becuase it + is already covered by !S_ISREG and is not defined in Unixware. + Reported by Dave Dykstra. + (update_random_seed_file): Silently ignore update request when pool + is not filled. + + * random.c (read_seed_file): New. + (set_random_seed_file): New. + (read_pool): Try to read the seeding file. + (update_random_seed_file): New. + + (read_pool): Do an initial extra seeding when level 2 quality random + is requested the first time. This requestes at least POOLSIZE/2 bytes + of entropy. Compined with the seeding file this should make normal + random bytes cheaper and increase the quality of the random bytes + used for key generation. + + * random.c (read_pool): Print a more friendly error message in + cases when too much random is requested in one call. + + * random.c (fast_random_poll): Check whether RUSAGE_SELF is defined; + this is not the case for some ESIX and Unixware, although they have + getrusage(). + + * primegen.c (generate_elg_prime): All primes are now generated with + the lowest random quality level. Because they are public anyway we + don't need stronger random and by this we do not drain the systems + entropy so much. + + * primegen.c (register_primegen_progress): New. + * dsa.c (register_pk_dsa_progress): New. + * elgamal.c (register_pk_elg_progress): New. + + * elgamal.c (wiener_map): New. + (gen_k): Use a much smaller k. + (generate): Calculate the qbits using the wiener map and + choose an x at a size comparable to the one choosen in gen_k + + * rmd160.c (rmd160_get_info): Moved casting to the left side due to a + problem with UTS4.3. Suggested by Dave Dykstra. + * sha1.c (sha1_get_info): Ditto. + * tiger.c (tiger_get_info): Ditto. + * md5.c (md5_get_info): Ditto + * des.c (des_get_info): Ditto. + * blowfish.c (blowfish_get_info): Ditto. + * cast5.c (cast5_get_info): Ditto. + * twofish.c (twofish_get_info): Ditto. + +Fri Mar 24 11:25:45 CET 2000 Werner Koch + + * md.c (md_open): Add hmac arg and allocate space for the pads. + (md_finalize): Add HMAC support. + (md_copy): Ditto. + (md_close): Ditto. + (gcry_md_reset): Ditto. + (gcry_md_ctl): Ditto. + (prepare_macpdas): New. + +Mon Mar 13 19:22:46 CET 2000 Werner Koch + + * md.c (gcry_md_hash_buffer): Add support for the other algorithms. + +Mon Jan 31 16:37:34 CET 2000 Werner Koch + + * genprime.c (generate_elg_prime): Fixed returned factors which never + worked for non-DSA keys. + +Thu Jan 27 18:00:44 CET 2000 Werner Koch + + * pubkey.c (sexp_to_key): Fixed mem leaks in case of errors. + +Mon Jan 24 22:24:38 CET 2000 Werner Koch + + * pubkey.c (gcry_pk_decrypt): Implemented. + (gcry_pk_encrypt): Implemented. + (gcry_pk_testkey): New. + (gcry_pk_genkey): New. + (pubkey_decrypt): Made static. + (pubkey_encrypt): Ditto. + (pubkey_check_secret_key): Ditto. + (pubkey_generate): Ditto. + +Mon Jan 24 13:04:28 CET 2000 Werner Koch + + * pubkey.c (pubkey_nbits): Removed and replaced by ... + (gcry_pk_get_nbits): this new one. + +Wed Dec 8 21:58:32 CET 1999 Werner Koch + + * dsa.c: s/mpi_powm/gcry_mpi_powm/g + * elgamal.c: Ditto. + * primegen.c: Ditto. + + * : Replaced g10_opt_verbose by g10_log_verbosity(). + + * Makefile.am (INCLUDES): removed intl, add ../gcrypt + +Fri Nov 19 17:15:20 CET 1999 Werner Koch + + * dynload.c (cmp_filenames): New to replaced compare_filename() in + module. + (register_cipher_extension): Removed the tilde expansion stuff. + * rndeg.c (my_make_filename): New. + + * : Replaced header util.h by g10lib.h + + * random.c (gather_faked): Replaced make_timestamp by time(2). + Disabled wrning printed with tty_printf. + * rndlinux.c (gather_random): Always use fprintf instead of tty_xxx; + this should be replaced by a callback function. + + * primegen.c (gen_prime): Use gcry_mpi_randomize. + (is_prime): Ditto. + * elgamal.c (test_keys): Ditto. + * dsa.c (test_keys): Ditto. + + * cipher.c (gcry_cipher_close): Die on invalid handle. + +Mon Nov 15 21:36:02 CET 1999 Werner Koch + + * elgamal.c (gen_k): Use the new random API. + (generate): Ditto. + * dsa.c (gen_k): Ditto. + (generate): Ditto. + +Sat Nov 13 17:44:23 CET 1999 Werner Koch + + * pubkey.c (disable_pubkey_algo): Made static. + (gcry_pk_ctl): New. + + * random.c (get_random_bits): Renamed to ... + (get_random_bytes): ... this and made static. + (gcry_random_bytes): New. + (gcry_random_bytes_secure): New. + (randomize_buffer): Renamed to ... + (gcry_randomize): ...this. + + * md.c (gcry_md_hash_buffer): New. + + * pubkey.c (gcry_pk_algo_info): 4 new commands. + (pubkey_get_npkey): Made static. + (pubkey_get_nskey): Made static. + (pubkey_get_nsig): Made static. + (pubkey_get_nenc): Made static. + + * pubkey.c: Removed all G10ERR_xxx. + * cipher.c: Changed all GCRYERR_INV_ALGO to GCRYERR_INV_CIPHER_ALGO. + * md.c: Changed all GCRYERR_INV_ALGO to GCRYERR_INV_MD_ALGO. + * cast5.c (cast_setkey): Changed errocodes to GCRYERR_xxx. + * blowfish.c: Ditto. + * des.c: Ditto. + * twofish.c: Ditto. + * dsa.c: Ditto. + * elgamal.c: Ditto. + + * g10c.c: Removed + + * cipher.c (gcry_cipher_open): Replaced alloc functions and return NULL + if we are out of core. + * dynload.c: Replaced all memory allocation functions. + * md.c: Ditto. + * primegen.c: Ditto. + * pubkey.c: Ditto. + * random.c: Ditto. + * rndw32.c: Ditto. + * elgamal.c: Ditto. + * dsa.c: Ditto. + +Tue Oct 26 14:10:21 CEST 1999 Werner Koch + + * elgamal.c (sign): Hugh found strange code here. Replaced by BUG(). + + * cipher.c: Merged with gcrypt/symapi.c. + + * pubkey.c (string_to_pubkey_algo): Renamed function to ... + (gcry_pk_map_name): ... this. + (pubkey_algo_to_string): Renamed function to ... + (gcry_pk_algo_name): ... this. + (gcry_pk_algo_info): New. + * pubkey.c: Merged with gcrypt/pkapi.c. + + * md.c (md_reset): Clear finalized; thanks to Ulf Moeller for + fixing this bug. + + * md.c: Merged with gcrypt/mdapi.c + +Wed Sep 15 14:39:59 CEST 1999 Michael Roth + + * des.c: Various speed improvements: One bit pre rotation + trick after initial permutation (Richard Outerbridge). + Finished test of SSLeay Tripple-DES patterns. + +Wed Sep 15 16:22:17 CEST 1999 Werner Koch + + * rndw32.c: New. + +Mon Sep 13 10:51:29 CEST 1999 Werner Koch + + * bithelp.h: New. + * rmd160.h, sha1.h, md5.h: Use the rol macro from bithelp.h + +Tue Sep 7 16:23:36 CEST 1999 Werner Koch + + * Makefile.am: Fixed seds for latest egcc. By Ollivier Robert. + +Mon Sep 6 19:59:08 CEST 1999 Werner Koch + + * des.c (selftest): Add some testpattern + +Mon Aug 30 20:38:33 CEST 1999 Werner Koch + + * cipher.c (do_cbc_encrypt): Fixed serious bug occuring when not using + in place encryption. Pointed out by Frank Stajano. + +Mon Jul 26 09:34:46 CEST 1999 Werner Koch + + * md5.c (md5_final): Fix for a SCO cpp bug. + +Thu Jul 15 10:15:35 CEST 1999 Werner Koch + + * elgamal.c (elg_check_secret_key,elg_encrypt + elg_decrypt,elg_sign,elg_verify): Sanity check on the args. + * dsa.c (dsa_check_secret_key,dsa_sign,dsa_verify): Ditto. + + * pubkey.c (disable_pubkey_algo): New. + (check_pubkey_algo2): Look at disabled algo table. + * cipher.c (disable_cipher_algo): New. + (check_cipher_algo): Look at disabled algo table. + +Wed Jul 7 13:08:40 CEST 1999 Werner Koch + + * Makefile.am: Support for libtool. + +Fri Jul 2 11:45:54 CEST 1999 Werner Koch + + * dsa.c (gen_k): Changed algorithm to consume less random bytes + * elgamal.c (gen_k): Ditto. + + * random.c (random_dump_stats): New. + +Thu Jul 1 12:47:31 CEST 1999 Werner Koch + + * primegen.c, elgamal.c, dsa.c (progess): New and replaced all + fputc with a call to this function. + +Sat Jun 26 12:15:59 CEST 1999 Werner Koch + + * rndegd.c (do_write): s/ssize_t/int/ due to SunOS 4.1 probs. + + * cipher.c (do_cbc_encrypt, do_cbc_decrypt): New. + + * dynload.c (HAVE_DL_SHL_LOAD): Map hpux API to dlopen (Dave Dykstra). + * Makefile.am (install-exec-hook): Removed. + +Sun May 23 14:20:22 CEST 1999 Werner Koch + + * cipher.c (setup_cipher_table): Enable Twofish + + * random.c (fast_random_poll): Disable use of times() for mingw32. + +Mon May 17 21:54:43 CEST 1999 Werner Koch + + * dynload.c (register_internal_cipher_extension): Minor init fix. + +Tue May 4 15:47:53 CEST 1999 Werner Koch + + * primegen.c (gen_prime): Readded the Fermat test. Fixed the bug + that we didn't correct for step when passing the prime to the + Rabin-Miller test which led to bad performance (Stefan Keller). + (check_prime): Add a first Fermat test. + +Sun Apr 18 10:11:28 CEST 1999 Werner Koch + + * cipher.c (cipher_setiv): Add ivlen arg, changed all callers. + + * random.c (randomize_buffer): alway use secure memory because + we can't use m_is_secure() on a statically allocated buffer. + + * twofish.c: Replaced some macros by a loop to reduce text size. + * Makefile.am (twofish): No more need for sed editing. + +Fri Apr 9 12:26:25 CEST 1999 Werner Koch + + * cipher.c (cipher_open): Reversed the changes for AUTO_CFB. + + * blowfish.c: Dropped the Blowfish 160 mode. + * cipher.c (cipher_open): Ditto. + (setup_cipher_table): Ditto. And removed support of twofish128 + +Wed Apr 7 20:51:39 CEST 1999 Werner Koch + + * random.c (get_random_bits): Can now handle requests > POOLSIZE + + * cipher.c (cipher_open): Now uses standard CFB for automode if + the blocksize is gt 8 (according to rfc2440). + + * twofish.c: Applied Matthew Skala's patches for 256 bit key. + +Tue Apr 6 19:58:12 CEST 1999 Werner Koch + + * random.c (get_random_bits): Can now handle requests > POOLSIZE + + * cipher.c (cipher_open): Now uses standard CFB for automode if + the blocksize is gt 8 (according to rfc2440). + +Sat Mar 20 11:44:21 CET 1999 Werner Koch + + * rndlinux.c (tty_printf) [IS_MODULE]: Removed. + + * rndegd.c (gather_random): Some fixes. + +Wed Mar 17 13:09:03 CET 1999 Werner Koch + + * rndegd.c (do_read): New. + (gather_random): Changed the implementation. + +Mon Mar 8 20:47:17 CET 1999 Werner Koch + + * dynload.c (DLSYM_NEEDS_UNDERSCORE): Renamed. + +Fri Feb 26 17:55:41 CET 1999 Werner Koch + + * md.c: Nearly a total rewrote. + +Wed Feb 24 11:07:27 CET 1999 Werner Koch + + * cipher.c (context): Fixed alignment + * md.c: Ditto. + + * rndegd.c: New + +Mon Feb 22 20:04:00 CET 1999 Werner Koch + + * rndegd.c: New. + +Wed Feb 10 17:15:39 CET 1999 Werner Koch + + * Makefile.am: Modules are now figured out by configure + * construct.c: New. Generated by configure. Changed all modules + to work with that. + * sha1.h: Removed. + * md5.h: Removed. + + * twofish.c: Changed interface to allow Twofish/256 + + * rndunix.c (start_gatherer): Die on SIGPIPE. + +Wed Jan 20 18:59:49 CET 1999 Werner Koch + + * rndunix.c (gather_random): Fix to avoid infinite loop. + +Sun Jan 17 11:04:33 CET 1999 Werner Koch + + * des.c (is_weak_key): Replace system memcmp due to bugs + in SunOS's memcmp. + (des_get_info): Return error on failed selftest. + * twofish.c (twofish_setkey): Return error on failed selftest or + invalid keylength. + * cast5.c (cast_setkey): Ditto. + * blowfish.c (bf_setkey): Return error on failed selftest. + +Tue Jan 12 11:17:18 CET 1999 Werner Koch + + * random.c (random_is_faked): New. + + * tiger.c: Only compile if we have the u64 type + +Sat Jan 9 16:02:23 CET 1999 Werner Koch + + * rndunix.c (gather_random): check for setuid. + + * Makefile.am: Add a way to staically link random modules + +Thu Jan 7 18:00:58 CET 1999 Werner Koch + + * md.c (md_stop_debug): Do a flush first. + (md_open): size of buffer now depends on the secure parameter + +Sun Jan 3 15:28:44 CET 1999 Werner Koch + + * rndunix.c (start_gatherer): Fixed stupid ==/= bug + +1998-12-31 Geoff Keating + + * des.c (is_weak_key): Rewrite loop end condition. + +Tue Dec 29 14:41:47 CET 1998 Werner Koch + + * random.c: add unistd.h for getpid(). + (RAND_MAX): Fallback value for Sun. + +Wed Dec 23 17:12:24 CET 1998 Werner Koch + + * md.c (md_copy): Reset debug. + +Mon Dec 14 21:18:49 CET 1998 Werner Koch + + * random.c (read_random_source): Changed the interface to the + random gathering function. + (gather_faked): Use new interface. + * dynload.c (dynload_getfnc_fast_random_poll): Ditto. + (dynload_getfnc_gather_random): Ditto. + * rndlinux.c (gather_random): Ditto. + * rndunix.c (gather_random): Ditto. + +Sat Dec 12 18:40:32 CET 1998 Werner Koch + + * dynload.c (SYMBOL_VERSION): New to cope with system which needs + underscores. + + * rndunix.c: Rewrote large parts + +Thu Dec 10 20:15:36 CET 1998 Werner Koch + + * dynload.c (load_extension): increased needed verbosity level. + + * random.c (fast_random_poll): Fallback to a default fast random + poll function. + (read_random_source): Always use the faked entroy gatherer if no + gather module is available. + * rndlinux.c (fast_poll): Removed. + * rndunix.c (fast_poll): Removed. + + +Wed Nov 25 12:33:41 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rand-*.c: Removed. + * rndlinux.c : New. + * rndunix.c : New. + * random.c : Restructured the interface to the gather modules. + (intialize): Call constructor functions + (read_radnom_source): Moved to here. + * dynload.c (dynload_getfnc_gather_random): New. + (dynload_getfnc_fast_random_poll): New. + (register_internal_cipher_extension): New. + (register_cipher_extension): Support of internal modules. + +Sun Nov 8 17:44:36 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rand-unix.c (read_random_source): Removed the assert. + +Mon Oct 19 18:34:30 1998 me,,, (wk@tobold) + + * pubkey.c: Hack to allow us to give some info about RSA keys back. + +Thu Oct 15 11:47:57 1998 Werner Koch (wk@isil.d.shuttle.de) + + * dynload.c: Support for DLD + +Wed Oct 14 12:13:07 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rand-unix.c: Now uses names from configure for /dev/random. + +1998-10-10 SL Baur + + * Makefile.am: fix sed -O substitutions to catch -O6, etc. + +Tue Oct 6 10:06:32 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rand-unix.c (HAVE_GETTIMEOFDAY): Fixed (was ..GETTIMEOFTIME :-) + * rand-dummy.c (HAVE_GETTIMEOFDAY): Ditto. + +Mon Sep 28 13:23:09 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c (md_digest): New. + (md_reset): New. + +Wed Sep 23 12:27:02 1998 Werner Koch (wk@isil.d.shuttle.de) + + * tiger.c (TIGER_CONTEXT): moved "buf", so that it is 64 bit aligned. + +Mon Sep 21 06:22:53 1998 Werner Koch (wk@(none)) + + * des.c: Some patches from Michael. + +Thu Sep 17 19:00:06 1998 Werner Koch (wk@(none)) + + * des.c : New file from Michael Roth + +Mon Sep 14 11:10:55 1998 Werner Koch (wk@(none)) + + * blowfish.c (bf_setkey): Niklas Hernaeus patch to detect weak keys. + +Mon Sep 14 09:19:25 1998 Werner Koch (wk@(none)) + + * dynload.c (RTLD_NOW): Now defined to 1 if it is undefined. + +Mon Sep 7 17:04:33 1998 Werner Koch (wk@(none)) + + * Makefile.am: Fixes to allow a different build directory + +Thu Aug 6 17:25:38 1998 Werner Koch,mobil,,, (wk@tobold) + + * random.c (get_random_byte): Removed and changed all callers + to use get_random_bits() + +Mon Jul 27 10:30:22 1998 Werner Koch (wk@(none)) + + * cipher.c : Support for other blocksizes + (cipher_get_blocksize): New. + * twofish.c: New. + * Makefile.am: Add twofish module. + +Mon Jul 13 21:30:52 1998 Werner Koch (wk@isil.d.shuttle.de) + + * random.c (read_pool): Simple alloc if secure_alloc is not set. + (get_random_bits): Ditto. + +Thu Jul 9 13:01:14 1998 Werner Koch (wk@isil.d.shuttle.de) + + * dynload.c (load_extension): Function now nbails out if + the program is run setuid. + +Wed Jul 8 18:58:23 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rmd160.c (rmd160_hash_buffer): New. + +Thu Jul 2 10:50:30 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cipher.c (cipher_open): algos >=100 use standard CFB + +Thu Jun 25 11:18:25 1998 Werner Koch (wk@isil.d.shuttle.de) + + * Makefile.am: Support for extensions + +Thu Jun 18 12:09:38 1998 Werner Koch (wk@isil.d.shuttle.de) + + * random.c (mix_pool): simpler handling for level 0 + +Mon Jun 15 14:40:48 1998 Werner Koch (wk@isil.d.shuttle.de) + + * tiger.c: Removed from dist, will reappear as dynload module + +Sat Jun 13 14:16:57 1998 Werner Koch (wk@isil.d.shuttle.de) + + * pubkey.c: Major changes to allow extensions. Changed the inteface + of all public key ciphers and added the ability to load extensions + on demand. + + * misc.c: Removed. + +Wed Jun 10 07:52:08 1998 Werner Koch,mobil,,, (wk@tobold) + + * dynload.c: New. + * cipher.c: Major changes to allow extensions. + +Mon Jun 8 22:43:00 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cipher.c: Major internal chnages to support extensions. + * blowfish.c (blowfish_get_info): New and made all internal + functions static, changed heder. + * cast5.c (cast5_get_info): Likewise. + +Mon Jun 8 12:27:52 1998 Werner Koch (wk@isil.d.shuttle.de) + + * tiger.c (transform): Fix for big endian + + * cipher.c (do_cfb_decrypt): Big endian fix. + +Fri May 22 07:30:39 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c (md_get_oid): Add a new one for TIGER. + +Thu May 21 13:24:52 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cipher.c: Add support for a dummy cipher + +Thu May 14 15:40:36 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rmd160.c (transform): fixed sigbus - I should better + add Christian von Roques's new implemenation of rmd160_write. + +Fri May 8 18:07:44 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rand-internal.h, rand-unix.c, rand-w32.c, rand_dummy.c: New + * random.c: Moved system specific functions to rand-****.c + +Fri May 8 14:01:17 1998 Werner Koch (wk@isil.d.shuttle.de) + + * random.c (fast_random_poll): add call to gethrtime. + +Tue May 5 21:28:55 1998 Werner Koch (wk@isil.d.shuttle.de) + + * elgamal.c (elg_generate): choosing x was not correct, could + yield 6 bytes which are not from the random pool, tsss, tsss.. + +Tue May 5 14:09:06 1998 Werner Koch (wk@isil.d.shuttle.de) + + * primegen.c (generate_elg_prime): Add arg mode, changed all + callers and implemented mode 1. + +Mon Apr 27 14:41:58 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cipher.c (cipher_get_keylen): New. + +Sun Apr 26 14:44:52 1998 Werner Koch (wk@isil.d.shuttle.de) + + * tiger.c, tiger.h: New. + +Wed Apr 8 14:57:11 1998 Werner Koch (wk@isil.d.shuttle.de) + + * misc.c (check_pubkey_algo2): New. + +Tue Apr 7 18:46:49 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cipher.c: New + * misc.c (check_cipher_algo): Moved to cipher.c + * cast5.c: Moved many functions to cipher.c + * blowfish.c: Likewise. + +Sat Apr 4 19:52:08 1998 Werner Koch (wk@isil.d.shuttle.de) + + * cast5.c: Implemented and tested. + +Wed Apr 1 16:38:27 1998 Werner Koch (wk@isil.d.shuttle.de) + + * elgamal.c (elg_generate): Faster generation of x in some cases. + +Thu Mar 19 13:54:48 1998 Werner Koch (wk@isil.d.shuttle.de) + + * blowfish.c (blowfish_decode_cfb): changed XOR operation + (blowfish_encode_cfb): Ditto. + +Thu Mar 12 14:04:05 1998 Werner Koch (wk@isil.d.shuttle.de) + + * sha1.c (transform): Rewrote + + * blowfish.c (encrypt): Unrolled for rounds == 16 + (decrypt): Ditto. + +Tue Mar 10 16:32:08 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rmd160.c (transform): Unrolled the loop. + +Tue Mar 10 13:05:14 1998 Werner Koch (wk@isil.d.shuttle.de) + + * random.c (read_pool): Add pool_balance stuff. + (get_random_bits): New. + + * elgamal.c (elg_generate): Now uses get_random_bits to generate x. + + +Tue Mar 10 11:33:51 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c (md_digest_length): New. + +Tue Mar 10 11:27:41 1998 Werner Koch (wk@isil.d.shuttle.de) + + * dsa.c (dsa_verify): Works. + +Mon Mar 9 12:59:08 1998 Werner Koch (wk@isil.d.shuttle.de) + + * dsa.c, dsa.h: Removed some unused code. + +Wed Mar 4 10:39:22 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c (md_open): Add call to fast_random_poll. + blowfish.c (blowfish_setkey): Ditto. + +Tue Mar 3 13:32:54 1998 Werner Koch (wk@isil.d.shuttle.de) + + * rmd160.c (rmd160_mixblock): New. + * random.c: Restructured to start with a new RNG implementation. + * random.h: New. + +Mon Mar 2 19:21:46 1998 Werner Koch (wk@isil.d.shuttle.de) + + * gost.c, gost.h: Removed because they did only contain trash. + +Sun Mar 1 16:42:29 1998 Werner Koch (wk@isil.d.shuttle.de) + + * random.c (fill_buffer): removed error message if n == -1. + +Fri Feb 27 16:39:34 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c (md_enable): No init if called twice. + +Thu Feb 26 07:57:02 1998 Werner Koch (wk@isil.d.shuttle.de) + + * primegen.c (generate_elg_prime): Changed the progress printing. + (gen_prime): Ditto. + +Tue Feb 24 12:28:42 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md5.c, md.5 : Replaced by a modified version of md5.c from + GNU textutils 1.22. + +Wed Feb 18 14:08:30 1998 Werner Koch (wk@isil.d.shuttle.de) + + * md.c, md.h : New debugging support + +Mon Feb 16 10:08:47 1998 Werner Koch (wk@isil.d.shuttle.de) + + * misc.c (cipher_algo_to_string): New + (pubkey_algo_to_string): New. + (digest_algo_to_string): New. + + + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +Local Variables: +buffer-read-only: t +End: diff --git a/comm/third_party/libgcrypt/cipher/Makefile.am b/comm/third_party/libgcrypt/cipher/Makefile.am new file mode 100644 index 0000000000..d644005634 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/Makefile.am @@ -0,0 +1,258 @@ +# Makefile for cipher modules +# Copyright (C) 1998, 1999, 2000, 2001, 2002, +# 2003, 2009 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# Libgcrypt is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . + +# Process this file with automake to produce Makefile.in + +# Need to include ../src in addition to top_srcdir because gcrypt.h is +# a built header. +AM_CPPFLAGS = -I../src -I$(top_srcdir)/src -I../mpi -I$(top_srcdir)/mpi +AM_CFLAGS = $(GPG_ERROR_CFLAGS) + +AM_CCASFLAGS = $(NOEXECSTACK_FLAGS) + +EXTRA_DIST = gost-s-box.c + +CLEANFILES = gost-s-box +DISTCLEANFILES = gost-sb.h + +noinst_LTLIBRARIES = libcipher.la + +GCRYPT_MODULES = @GCRYPT_CIPHERS@ @GCRYPT_PUBKEY_CIPHERS@ \ + @GCRYPT_DIGESTS@ @GCRYPT_KDFS@ + +libcipher_la_DEPENDENCIES = $(GCRYPT_MODULES) +libcipher_la_LIBADD = $(GCRYPT_MODULES) + +libcipher_la_SOURCES = \ + cipher.c cipher-internal.h \ + cipher-cbc.c \ + cipher-cfb.c \ + cipher-ofb.c \ + cipher-ctr.c \ + cipher-aeswrap.c \ + cipher-ccm.c \ + cipher-cmac.c \ + cipher-gcm.c cipher-gcm-intel-pclmul.c cipher-gcm-armv7-neon.S \ + cipher-gcm-armv8-aarch32-ce.S cipher-gcm-armv8-aarch64-ce.S \ + cipher-poly1305.c \ + cipher-ocb.c \ + cipher-xts.c \ + cipher-eax.c \ + cipher-selftest.c cipher-selftest.h \ + pubkey.c pubkey-internal.h pubkey-util.c \ + md.c \ + mac.c mac-internal.h \ + mac-hmac.c mac-cmac.c mac-gmac.c mac-poly1305.c \ + poly1305.c poly1305-internal.h \ + poly1305-s390x.S \ + kdf.c kdf-internal.h \ + bithelp.h \ + bufhelp.h \ + primegen.c \ + hash-common.c hash-common.h \ + dsa-common.c rsa-common.c \ + sha1.h + +EXTRA_libcipher_la_SOURCES = \ + asm-common-aarch64.h \ + asm-common-amd64.h \ + asm-common-s390x.h \ + asm-inline-s390x.h \ + asm-poly1305-aarch64.h \ + asm-poly1305-amd64.h \ + asm-poly1305-s390x.h \ + arcfour.c arcfour-amd64.S \ + blowfish.c blowfish-amd64.S blowfish-arm.S \ + cast5.c cast5-amd64.S cast5-arm.S \ + chacha20.c chacha20-amd64-ssse3.S chacha20-amd64-avx2.S \ + chacha20-armv7-neon.S chacha20-aarch64.S \ + chacha20-ppc.c chacha20-s390x.S \ + crc.c crc-intel-pclmul.c crc-armv8-ce.c \ + crc-armv8-aarch64-ce.S \ + crc-ppc.c \ + des.c des-amd64.S \ + dsa.c \ + elgamal.c \ + ecc.c ecc-curves.c ecc-misc.c ecc-common.h \ + ecc-ecdh.c ecc-ecdsa.c ecc-eddsa.c ecc-gost.c ecc-sm2.c \ + idea.c \ + gost28147.c gost.h \ + gostr3411-94.c \ + md4.c \ + md5.c \ + rijndael.c rijndael-internal.h rijndael-tables.h \ + rijndael-aesni.c rijndael-padlock.c \ + rijndael-amd64.S rijndael-arm.S \ + rijndael-ssse3-amd64.c rijndael-ssse3-amd64-asm.S \ + rijndael-armv8-ce.c rijndael-armv8-aarch32-ce.S \ + rijndael-armv8-aarch64-ce.S rijndael-aarch64.S \ + rijndael-ppc.c rijndael-ppc9le.c \ + rijndael-ppc-common.h rijndael-ppc-functions.h \ + rijndael-s390x.c \ + rmd160.c \ + rsa.c \ + salsa20.c salsa20-amd64.S salsa20-armv7-neon.S \ + scrypt.c \ + seed.c \ + serpent.c serpent-sse2-amd64.S \ + sm4.c sm4-aesni-avx-amd64.S sm4-aesni-avx2-amd64.S \ + serpent-avx2-amd64.S serpent-armv7-neon.S \ + sha1.c sha1-ssse3-amd64.S sha1-avx-amd64.S sha1-avx-bmi2-amd64.S \ + sha1-avx2-bmi2-amd64.S sha1-armv7-neon.S sha1-armv8-aarch32-ce.S \ + sha1-armv8-aarch64-ce.S sha1-intel-shaext.c \ + sha256.c sha256-ssse3-amd64.S sha256-avx-amd64.S \ + sha256-avx2-bmi2-amd64.S \ + sha256-armv8-aarch32-ce.S sha256-armv8-aarch64-ce.S \ + sha256-intel-shaext.c sha256-ppc.c \ + sha512.c sha512-ssse3-amd64.S sha512-avx-amd64.S \ + sha512-avx2-bmi2-amd64.S \ + sha512-armv7-neon.S sha512-arm.S \ + sha512-ppc.c sha512-ssse3-i386.c \ + sm3.c \ + keccak.c keccak_permute_32.h keccak_permute_64.h keccak-armv7-neon.S \ + stribog.c \ + tiger.c \ + whirlpool.c whirlpool-sse2-amd64.S \ + twofish.c twofish-amd64.S twofish-arm.S twofish-aarch64.S \ + twofish-avx2-amd64.S \ + rfc2268.c \ + camellia.c camellia.h camellia-glue.c camellia-aesni-avx-amd64.S \ + camellia-aesni-avx2-amd64.S camellia-arm.S camellia-aarch64.S \ + blake2.c \ + blake2b-amd64-avx2.S blake2s-amd64-avx.S + +gost28147.lo: gost-sb.h +gost-sb.h: gost-s-box + ./gost-s-box $@ + +gost-s-box: gost-s-box.c + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD)-o $@ $(srcdir)/gost-s-box.c + + +if ENABLE_O_FLAG_MUNGING +o_flag_munging = sed -e 's/-O\([2-9sg][2-9sg]*\)/-O1/' -e 's/-Ofast/-O1/g' +else +o_flag_munging = cat +endif + + +# We need to lower the optimization for this module. +tiger.o: $(srcdir)/tiger.c Makefile + `echo $(COMPILE) -c $< | $(o_flag_munging) ` + +tiger.lo: $(srcdir)/tiger.c Makefile + `echo $(LTCOMPILE) -c $< | $(o_flag_munging) ` + + +# We need to disable instrumentation for these modules as they use cc as +# thin assembly front-end and do not tolerate in-between function calls +# inserted by compiler as those functions may clobber the XMM registers. +if ENABLE_INSTRUMENTATION_MUNGING +instrumentation_munging = sed \ + -e 's/-fsanitize[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' \ + -e 's/-fprofile[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' \ + -e 's/-fcoverage[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' +else +instrumentation_munging = cat +endif + +rijndael-aesni.o: $(srcdir)/rijndael-aesni.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-aesni.lo: $(srcdir)/rijndael-aesni.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-ssse3-amd64.o: $(srcdir)/rijndael-ssse3-amd64.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-ssse3-amd64.lo: $(srcdir)/rijndael-ssse3-amd64.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +cipher-gcm-intel-pclmul.o: $(srcdir)/cipher-gcm-intel-pclmul.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +cipher-gcm-intel-pclmul.lo: $(srcdir)/cipher-gcm-intel-pclmul.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +sha1-intel-shaext.o: $(srcdir)/sha1-intel-shaext.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +sha1-intel-shaext.lo: $(srcdir)/sha1-intel-shaext.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +sha256-intel-shaext.o: $(srcdir)/sha256-intel-shaext.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +sha256-intel-shaext.lo: $(srcdir)/sha256-intel-shaext.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +sha256-ssse3-i386.o: $(srcdir)/sha256-ssse3-i386.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +sha256-ssse3-i386.lo: $(srcdir)/sha256-ssse3-i386.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +crc-intel-pclmul.o: $(srcdir)/crc-intel-pclmul.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +crc-intel-pclmul.lo: $(srcdir)/crc-intel-pclmul.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +if ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS +ppc_vcrypto_cflags = -maltivec -mvsx -mcrypto +else +ppc_vcrypto_cflags = +endif + +rijndael-ppc.o: $(srcdir)/rijndael-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +rijndael-ppc.lo: $(srcdir)/rijndael-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +rijndael-ppc9le.o: $(srcdir)/rijndael-ppc9le.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +rijndael-ppc9le.lo: $(srcdir)/rijndael-ppc9le.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha256-ppc.o: $(srcdir)/sha256-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha256-ppc.lo: $(srcdir)/sha256-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha512-ppc.o: $(srcdir)/sha512-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha512-ppc.lo: $(srcdir)/sha512-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +chacha20-ppc.o: $(srcdir)/chacha20-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +chacha20-ppc.lo: $(srcdir)/chacha20-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +crc-ppc.o: $(srcdir)/crc-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +crc-ppc.lo: $(srcdir)/crc-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` diff --git a/comm/third_party/libgcrypt/cipher/Makefile.in b/comm/third_party/libgcrypt/cipher/Makefile.in new file mode 100644 index 0000000000..ceba51b45a --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/Makefile.in @@ -0,0 +1,1445 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile for cipher modules +# Copyright (C) 1998, 1999, 2000, 2001, 2002, +# 2003, 2009 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# Libgcrypt is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . + +# Process this file with automake to produce Makefile.in + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = cipher +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/noexecstack.m4 $(top_srcdir)/m4/socklen.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +am_libcipher_la_OBJECTS = cipher.lo cipher-cbc.lo cipher-cfb.lo \ + cipher-ofb.lo cipher-ctr.lo cipher-aeswrap.lo cipher-ccm.lo \ + cipher-cmac.lo cipher-gcm.lo cipher-gcm-intel-pclmul.lo \ + cipher-gcm-armv7-neon.lo cipher-gcm-armv8-aarch32-ce.lo \ + cipher-gcm-armv8-aarch64-ce.lo cipher-poly1305.lo \ + cipher-ocb.lo cipher-xts.lo cipher-eax.lo cipher-selftest.lo \ + pubkey.lo pubkey-util.lo md.lo mac.lo mac-hmac.lo mac-cmac.lo \ + mac-gmac.lo mac-poly1305.lo poly1305.lo poly1305-s390x.lo \ + kdf.lo primegen.lo hash-common.lo dsa-common.lo rsa-common.lo +libcipher_la_OBJECTS = $(am_libcipher_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/arcfour-amd64.Plo \ + ./$(DEPDIR)/arcfour.Plo ./$(DEPDIR)/blake2.Plo \ + ./$(DEPDIR)/blake2b-amd64-avx2.Plo \ + ./$(DEPDIR)/blake2s-amd64-avx.Plo \ + ./$(DEPDIR)/blowfish-amd64.Plo ./$(DEPDIR)/blowfish-arm.Plo \ + ./$(DEPDIR)/blowfish.Plo ./$(DEPDIR)/camellia-aarch64.Plo \ + ./$(DEPDIR)/camellia-aesni-avx-amd64.Plo \ + ./$(DEPDIR)/camellia-aesni-avx2-amd64.Plo \ + ./$(DEPDIR)/camellia-arm.Plo ./$(DEPDIR)/camellia-glue.Plo \ + ./$(DEPDIR)/camellia.Plo ./$(DEPDIR)/cast5-amd64.Plo \ + ./$(DEPDIR)/cast5-arm.Plo ./$(DEPDIR)/cast5.Plo \ + ./$(DEPDIR)/chacha20-aarch64.Plo \ + ./$(DEPDIR)/chacha20-amd64-avx2.Plo \ + ./$(DEPDIR)/chacha20-amd64-ssse3.Plo \ + ./$(DEPDIR)/chacha20-armv7-neon.Plo \ + ./$(DEPDIR)/chacha20-ppc.Plo ./$(DEPDIR)/chacha20-s390x.Plo \ + ./$(DEPDIR)/chacha20.Plo ./$(DEPDIR)/cipher-aeswrap.Plo \ + ./$(DEPDIR)/cipher-cbc.Plo ./$(DEPDIR)/cipher-ccm.Plo \ + ./$(DEPDIR)/cipher-cfb.Plo ./$(DEPDIR)/cipher-cmac.Plo \ + ./$(DEPDIR)/cipher-ctr.Plo ./$(DEPDIR)/cipher-eax.Plo \ + ./$(DEPDIR)/cipher-gcm-armv7-neon.Plo \ + ./$(DEPDIR)/cipher-gcm-armv8-aarch32-ce.Plo \ + ./$(DEPDIR)/cipher-gcm-armv8-aarch64-ce.Plo \ + ./$(DEPDIR)/cipher-gcm-intel-pclmul.Plo \ + ./$(DEPDIR)/cipher-gcm.Plo ./$(DEPDIR)/cipher-ocb.Plo \ + ./$(DEPDIR)/cipher-ofb.Plo ./$(DEPDIR)/cipher-poly1305.Plo \ + ./$(DEPDIR)/cipher-selftest.Plo ./$(DEPDIR)/cipher-xts.Plo \ + ./$(DEPDIR)/cipher.Plo ./$(DEPDIR)/crc-armv8-aarch64-ce.Plo \ + ./$(DEPDIR)/crc-armv8-ce.Plo ./$(DEPDIR)/crc-intel-pclmul.Plo \ + ./$(DEPDIR)/crc-ppc.Plo ./$(DEPDIR)/crc.Plo \ + ./$(DEPDIR)/des-amd64.Plo ./$(DEPDIR)/des.Plo \ + ./$(DEPDIR)/dsa-common.Plo ./$(DEPDIR)/dsa.Plo \ + ./$(DEPDIR)/ecc-curves.Plo ./$(DEPDIR)/ecc-ecdh.Plo \ + ./$(DEPDIR)/ecc-ecdsa.Plo ./$(DEPDIR)/ecc-eddsa.Plo \ + ./$(DEPDIR)/ecc-gost.Plo ./$(DEPDIR)/ecc-misc.Plo \ + ./$(DEPDIR)/ecc-sm2.Plo ./$(DEPDIR)/ecc.Plo \ + ./$(DEPDIR)/elgamal.Plo ./$(DEPDIR)/gost28147.Plo \ + ./$(DEPDIR)/gostr3411-94.Plo ./$(DEPDIR)/hash-common.Plo \ + ./$(DEPDIR)/idea.Plo ./$(DEPDIR)/kdf.Plo \ + ./$(DEPDIR)/keccak-armv7-neon.Plo ./$(DEPDIR)/keccak.Plo \ + ./$(DEPDIR)/mac-cmac.Plo ./$(DEPDIR)/mac-gmac.Plo \ + ./$(DEPDIR)/mac-hmac.Plo ./$(DEPDIR)/mac-poly1305.Plo \ + ./$(DEPDIR)/mac.Plo ./$(DEPDIR)/md.Plo ./$(DEPDIR)/md4.Plo \ + ./$(DEPDIR)/md5.Plo ./$(DEPDIR)/poly1305-s390x.Plo \ + ./$(DEPDIR)/poly1305.Plo ./$(DEPDIR)/primegen.Plo \ + ./$(DEPDIR)/pubkey-util.Plo ./$(DEPDIR)/pubkey.Plo \ + ./$(DEPDIR)/rfc2268.Plo ./$(DEPDIR)/rijndael-aarch64.Plo \ + ./$(DEPDIR)/rijndael-aesni.Plo ./$(DEPDIR)/rijndael-amd64.Plo \ + ./$(DEPDIR)/rijndael-arm.Plo \ + ./$(DEPDIR)/rijndael-armv8-aarch32-ce.Plo \ + ./$(DEPDIR)/rijndael-armv8-aarch64-ce.Plo \ + ./$(DEPDIR)/rijndael-armv8-ce.Plo \ + ./$(DEPDIR)/rijndael-padlock.Plo ./$(DEPDIR)/rijndael-ppc.Plo \ + ./$(DEPDIR)/rijndael-ppc9le.Plo ./$(DEPDIR)/rijndael-s390x.Plo \ + ./$(DEPDIR)/rijndael-ssse3-amd64-asm.Plo \ + ./$(DEPDIR)/rijndael-ssse3-amd64.Plo ./$(DEPDIR)/rijndael.Plo \ + ./$(DEPDIR)/rmd160.Plo ./$(DEPDIR)/rsa-common.Plo \ + ./$(DEPDIR)/rsa.Plo ./$(DEPDIR)/salsa20-amd64.Plo \ + ./$(DEPDIR)/salsa20-armv7-neon.Plo ./$(DEPDIR)/salsa20.Plo \ + ./$(DEPDIR)/scrypt.Plo ./$(DEPDIR)/seed.Plo \ + ./$(DEPDIR)/serpent-armv7-neon.Plo \ + ./$(DEPDIR)/serpent-avx2-amd64.Plo \ + ./$(DEPDIR)/serpent-sse2-amd64.Plo ./$(DEPDIR)/serpent.Plo \ + ./$(DEPDIR)/sha1-armv7-neon.Plo \ + ./$(DEPDIR)/sha1-armv8-aarch32-ce.Plo \ + ./$(DEPDIR)/sha1-armv8-aarch64-ce.Plo \ + ./$(DEPDIR)/sha1-avx-amd64.Plo \ + ./$(DEPDIR)/sha1-avx-bmi2-amd64.Plo \ + ./$(DEPDIR)/sha1-avx2-bmi2-amd64.Plo \ + ./$(DEPDIR)/sha1-intel-shaext.Plo \ + ./$(DEPDIR)/sha1-ssse3-amd64.Plo ./$(DEPDIR)/sha1.Plo \ + ./$(DEPDIR)/sha256-armv8-aarch32-ce.Plo \ + ./$(DEPDIR)/sha256-armv8-aarch64-ce.Plo \ + ./$(DEPDIR)/sha256-avx-amd64.Plo \ + ./$(DEPDIR)/sha256-avx2-bmi2-amd64.Plo \ + ./$(DEPDIR)/sha256-intel-shaext.Plo ./$(DEPDIR)/sha256-ppc.Plo \ + ./$(DEPDIR)/sha256-ssse3-amd64.Plo ./$(DEPDIR)/sha256.Plo \ + ./$(DEPDIR)/sha512-arm.Plo ./$(DEPDIR)/sha512-armv7-neon.Plo \ + ./$(DEPDIR)/sha512-avx-amd64.Plo \ + ./$(DEPDIR)/sha512-avx2-bmi2-amd64.Plo \ + ./$(DEPDIR)/sha512-ppc.Plo ./$(DEPDIR)/sha512-ssse3-amd64.Plo \ + ./$(DEPDIR)/sha512-ssse3-i386.Plo ./$(DEPDIR)/sha512.Plo \ + ./$(DEPDIR)/sm3.Plo ./$(DEPDIR)/sm4-aesni-avx-amd64.Plo \ + ./$(DEPDIR)/sm4-aesni-avx2-amd64.Plo ./$(DEPDIR)/sm4.Plo \ + ./$(DEPDIR)/stribog.Plo ./$(DEPDIR)/tiger.Plo \ + ./$(DEPDIR)/twofish-aarch64.Plo ./$(DEPDIR)/twofish-amd64.Plo \ + ./$(DEPDIR)/twofish-arm.Plo ./$(DEPDIR)/twofish-avx2-amd64.Plo \ + ./$(DEPDIR)/twofish.Plo ./$(DEPDIR)/whirlpool-sse2-amd64.Plo \ + ./$(DEPDIR)/whirlpool.Plo +am__mv = mv -f +CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +LTCPPASCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CCASFLAGS) $(CCASFLAGS) +AM_V_CPPAS = $(am__v_CPPAS_@AM_V@) +am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@) +am__v_CPPAS_0 = @echo " CPPAS " $@; +am__v_CPPAS_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libcipher_la_SOURCES) $(EXTRA_libcipher_la_SOURCES) +DIST_SOURCES = $(libcipher_la_SOURCES) $(EXTRA_libcipher_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DL_LIBS = @DL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FALLBACK_SOCKLEN_T = @FALLBACK_SOCKLEN_T@ +FGREP = @FGREP@ +GCRYPT_CIPHERS = @GCRYPT_CIPHERS@ +GCRYPT_DIGESTS = @GCRYPT_DIGESTS@ +GCRYPT_HWF_MODULES = @GCRYPT_HWF_MODULES@ +GCRYPT_KDFS = @GCRYPT_KDFS@ +GCRYPT_PUBKEY_CIPHERS = @GCRYPT_PUBKEY_CIPHERS@ +GCRYPT_RANDOM = @GCRYPT_RANDOM@ +GPGRT_CONFIG = @GPGRT_CONFIG@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@ +GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@ +GREP = @GREP@ +INSERT_SYS_SELECT_H = @INSERT_SYS_SELECT_H@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CIPHERS = @LIBGCRYPT_CIPHERS@ +LIBGCRYPT_CONFIG_API_VERSION = @LIBGCRYPT_CONFIG_API_VERSION@ +LIBGCRYPT_CONFIG_CFLAGS = @LIBGCRYPT_CONFIG_CFLAGS@ +LIBGCRYPT_CONFIG_HOST = @LIBGCRYPT_CONFIG_HOST@ +LIBGCRYPT_CONFIG_LIBS = @LIBGCRYPT_CONFIG_LIBS@ +LIBGCRYPT_DIGESTS = @LIBGCRYPT_DIGESTS@ +LIBGCRYPT_LT_AGE = @LIBGCRYPT_LT_AGE@ +LIBGCRYPT_LT_CURRENT = @LIBGCRYPT_LT_CURRENT@ +LIBGCRYPT_LT_REVISION = @LIBGCRYPT_LT_REVISION@ +LIBGCRYPT_PUBKEY_CIPHERS = @LIBGCRYPT_PUBKEY_CIPHERS@ +LIBGCRYPT_THREAD_MODULES = @LIBGCRYPT_THREAD_MODULES@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MPI_SFLAGS = @MPI_SFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOEXECSTACK_FLAGS = @NOEXECSTACK_FLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTH_CFLAGS = @PTH_CFLAGS@ +PTH_CONFIG = @PTH_CONFIG@ +PTH_LIBS = @PTH_LIBS@ +RANLIB = @RANLIB@ +RC = @RC@ +RUN_LARGE_DATA_TESTS = @RUN_LARGE_DATA_TESTS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSROOT = @SYSROOT@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +emacs_local_vars_begin = @emacs_local_vars_begin@ +emacs_local_vars_end = @emacs_local_vars_end@ +emacs_local_vars_read_only = @emacs_local_vars_read_only@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Need to include ../src in addition to top_srcdir because gcrypt.h is +# a built header. +AM_CPPFLAGS = -I../src -I$(top_srcdir)/src -I../mpi -I$(top_srcdir)/mpi +AM_CFLAGS = $(GPG_ERROR_CFLAGS) +AM_CCASFLAGS = $(NOEXECSTACK_FLAGS) +EXTRA_DIST = gost-s-box.c +CLEANFILES = gost-s-box +DISTCLEANFILES = gost-sb.h +noinst_LTLIBRARIES = libcipher.la +GCRYPT_MODULES = @GCRYPT_CIPHERS@ @GCRYPT_PUBKEY_CIPHERS@ \ + @GCRYPT_DIGESTS@ @GCRYPT_KDFS@ + +libcipher_la_DEPENDENCIES = $(GCRYPT_MODULES) +libcipher_la_LIBADD = $(GCRYPT_MODULES) +libcipher_la_SOURCES = \ + cipher.c cipher-internal.h \ + cipher-cbc.c \ + cipher-cfb.c \ + cipher-ofb.c \ + cipher-ctr.c \ + cipher-aeswrap.c \ + cipher-ccm.c \ + cipher-cmac.c \ + cipher-gcm.c cipher-gcm-intel-pclmul.c cipher-gcm-armv7-neon.S \ + cipher-gcm-armv8-aarch32-ce.S cipher-gcm-armv8-aarch64-ce.S \ + cipher-poly1305.c \ + cipher-ocb.c \ + cipher-xts.c \ + cipher-eax.c \ + cipher-selftest.c cipher-selftest.h \ + pubkey.c pubkey-internal.h pubkey-util.c \ + md.c \ + mac.c mac-internal.h \ + mac-hmac.c mac-cmac.c mac-gmac.c mac-poly1305.c \ + poly1305.c poly1305-internal.h \ + poly1305-s390x.S \ + kdf.c kdf-internal.h \ + bithelp.h \ + bufhelp.h \ + primegen.c \ + hash-common.c hash-common.h \ + dsa-common.c rsa-common.c \ + sha1.h + +EXTRA_libcipher_la_SOURCES = \ + asm-common-aarch64.h \ + asm-common-amd64.h \ + asm-common-s390x.h \ + asm-inline-s390x.h \ + asm-poly1305-aarch64.h \ + asm-poly1305-amd64.h \ + asm-poly1305-s390x.h \ + arcfour.c arcfour-amd64.S \ + blowfish.c blowfish-amd64.S blowfish-arm.S \ + cast5.c cast5-amd64.S cast5-arm.S \ + chacha20.c chacha20-amd64-ssse3.S chacha20-amd64-avx2.S \ + chacha20-armv7-neon.S chacha20-aarch64.S \ + chacha20-ppc.c chacha20-s390x.S \ + crc.c crc-intel-pclmul.c crc-armv8-ce.c \ + crc-armv8-aarch64-ce.S \ + crc-ppc.c \ + des.c des-amd64.S \ + dsa.c \ + elgamal.c \ + ecc.c ecc-curves.c ecc-misc.c ecc-common.h \ + ecc-ecdh.c ecc-ecdsa.c ecc-eddsa.c ecc-gost.c ecc-sm2.c \ + idea.c \ + gost28147.c gost.h \ + gostr3411-94.c \ + md4.c \ + md5.c \ + rijndael.c rijndael-internal.h rijndael-tables.h \ + rijndael-aesni.c rijndael-padlock.c \ + rijndael-amd64.S rijndael-arm.S \ + rijndael-ssse3-amd64.c rijndael-ssse3-amd64-asm.S \ + rijndael-armv8-ce.c rijndael-armv8-aarch32-ce.S \ + rijndael-armv8-aarch64-ce.S rijndael-aarch64.S \ + rijndael-ppc.c rijndael-ppc9le.c \ + rijndael-ppc-common.h rijndael-ppc-functions.h \ + rijndael-s390x.c \ + rmd160.c \ + rsa.c \ + salsa20.c salsa20-amd64.S salsa20-armv7-neon.S \ + scrypt.c \ + seed.c \ + serpent.c serpent-sse2-amd64.S \ + sm4.c sm4-aesni-avx-amd64.S sm4-aesni-avx2-amd64.S \ + serpent-avx2-amd64.S serpent-armv7-neon.S \ + sha1.c sha1-ssse3-amd64.S sha1-avx-amd64.S sha1-avx-bmi2-amd64.S \ + sha1-avx2-bmi2-amd64.S sha1-armv7-neon.S sha1-armv8-aarch32-ce.S \ + sha1-armv8-aarch64-ce.S sha1-intel-shaext.c \ + sha256.c sha256-ssse3-amd64.S sha256-avx-amd64.S \ + sha256-avx2-bmi2-amd64.S \ + sha256-armv8-aarch32-ce.S sha256-armv8-aarch64-ce.S \ + sha256-intel-shaext.c sha256-ppc.c \ + sha512.c sha512-ssse3-amd64.S sha512-avx-amd64.S \ + sha512-avx2-bmi2-amd64.S \ + sha512-armv7-neon.S sha512-arm.S \ + sha512-ppc.c sha512-ssse3-i386.c \ + sm3.c \ + keccak.c keccak_permute_32.h keccak_permute_64.h keccak-armv7-neon.S \ + stribog.c \ + tiger.c \ + whirlpool.c whirlpool-sse2-amd64.S \ + twofish.c twofish-amd64.S twofish-arm.S twofish-aarch64.S \ + twofish-avx2-amd64.S \ + rfc2268.c \ + camellia.c camellia.h camellia-glue.c camellia-aesni-avx-amd64.S \ + camellia-aesni-avx2-amd64.S camellia-arm.S camellia-aarch64.S \ + blake2.c \ + blake2b-amd64-avx2.S blake2s-amd64-avx.S + +@ENABLE_O_FLAG_MUNGING_FALSE@o_flag_munging = cat +@ENABLE_O_FLAG_MUNGING_TRUE@o_flag_munging = sed -e 's/-O\([2-9sg][2-9sg]*\)/-O1/' -e 's/-Ofast/-O1/g' +@ENABLE_INSTRUMENTATION_MUNGING_FALSE@instrumentation_munging = cat + +# We need to disable instrumentation for these modules as they use cc as +# thin assembly front-end and do not tolerate in-between function calls +# inserted by compiler as those functions may clobber the XMM registers. +@ENABLE_INSTRUMENTATION_MUNGING_TRUE@instrumentation_munging = sed \ +@ENABLE_INSTRUMENTATION_MUNGING_TRUE@ -e 's/-fsanitize[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' \ +@ENABLE_INSTRUMENTATION_MUNGING_TRUE@ -e 's/-fprofile[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' \ +@ENABLE_INSTRUMENTATION_MUNGING_TRUE@ -e 's/-fcoverage[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' + +@ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS_FALSE@ppc_vcrypto_cflags = +@ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS_TRUE@ppc_vcrypto_cflags = -maltivec -mvsx -mcrypto +all: all-am + +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu cipher/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu cipher/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libcipher.la: $(libcipher_la_OBJECTS) $(libcipher_la_DEPENDENCIES) $(EXTRA_libcipher_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libcipher_la_OBJECTS) $(libcipher_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arcfour-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arcfour.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blake2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blake2b-amd64-avx2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blake2s-amd64-avx.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blowfish-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blowfish-arm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blowfish.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/camellia-aarch64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/camellia-aesni-avx-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/camellia-aesni-avx2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/camellia-arm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/camellia-glue.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/camellia.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cast5-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cast5-arm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cast5.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20-aarch64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20-amd64-avx2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20-amd64-ssse3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20-ppc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20-s390x.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chacha20.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-aeswrap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-cbc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-ccm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-cfb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-cmac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-ctr.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-eax.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-gcm-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-gcm-armv8-aarch32-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-gcm-armv8-aarch64-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-gcm-intel-pclmul.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-gcm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-ocb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-ofb.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-poly1305.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-selftest.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher-xts.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cipher.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc-armv8-aarch64-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc-armv8-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc-intel-pclmul.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc-ppc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsa-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsa.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-curves.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-ecdh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-ecdsa.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-eddsa.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-gost.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-misc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc-sm2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elgamal.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gost28147.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gostr3411-94.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idea.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kdf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keccak-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keccak.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac-cmac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac-gmac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac-hmac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac-poly1305.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/poly1305-s390x.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/poly1305.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/primegen.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubkey-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubkey.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rfc2268.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-aarch64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-aesni.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-arm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-armv8-aarch32-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-armv8-aarch64-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-armv8-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-padlock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-ppc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-ppc9le.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-s390x.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-ssse3-amd64-asm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael-ssse3-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rijndael.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rmd160.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/salsa20-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/salsa20-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/salsa20.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scrypt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seed.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serpent-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serpent-avx2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serpent-sse2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serpent.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-armv8-aarch32-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-armv8-aarch64-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-avx-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-avx-bmi2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-avx2-bmi2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-intel-shaext.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1-ssse3-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-armv8-aarch32-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-armv8-aarch64-ce.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-avx-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-avx2-bmi2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-intel-shaext.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-ppc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256-ssse3-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-arm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-armv7-neon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-avx-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-avx2-bmi2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-ppc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-ssse3-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512-ssse3-i386.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm3.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm4-aesni-avx-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm4-aesni-avx2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm4.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stribog.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiger.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish-aarch64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish-arm.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish-avx2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twofish.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whirlpool-sse2-amd64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whirlpool.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.S.o: +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ $< + +.S.obj: +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.S.lo: +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(LTCPPASCOMPILE) -c -o $@ $< + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/arcfour-amd64.Plo + -rm -f ./$(DEPDIR)/arcfour.Plo + -rm -f ./$(DEPDIR)/blake2.Plo + -rm -f ./$(DEPDIR)/blake2b-amd64-avx2.Plo + -rm -f ./$(DEPDIR)/blake2s-amd64-avx.Plo + -rm -f ./$(DEPDIR)/blowfish-amd64.Plo + -rm -f ./$(DEPDIR)/blowfish-arm.Plo + -rm -f ./$(DEPDIR)/blowfish.Plo + -rm -f ./$(DEPDIR)/camellia-aarch64.Plo + -rm -f ./$(DEPDIR)/camellia-aesni-avx-amd64.Plo + -rm -f ./$(DEPDIR)/camellia-aesni-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/camellia-arm.Plo + -rm -f ./$(DEPDIR)/camellia-glue.Plo + -rm -f ./$(DEPDIR)/camellia.Plo + -rm -f ./$(DEPDIR)/cast5-amd64.Plo + -rm -f ./$(DEPDIR)/cast5-arm.Plo + -rm -f ./$(DEPDIR)/cast5.Plo + -rm -f ./$(DEPDIR)/chacha20-aarch64.Plo + -rm -f ./$(DEPDIR)/chacha20-amd64-avx2.Plo + -rm -f ./$(DEPDIR)/chacha20-amd64-ssse3.Plo + -rm -f ./$(DEPDIR)/chacha20-armv7-neon.Plo + -rm -f ./$(DEPDIR)/chacha20-ppc.Plo + -rm -f ./$(DEPDIR)/chacha20-s390x.Plo + -rm -f ./$(DEPDIR)/chacha20.Plo + -rm -f ./$(DEPDIR)/cipher-aeswrap.Plo + -rm -f ./$(DEPDIR)/cipher-cbc.Plo + -rm -f ./$(DEPDIR)/cipher-ccm.Plo + -rm -f ./$(DEPDIR)/cipher-cfb.Plo + -rm -f ./$(DEPDIR)/cipher-cmac.Plo + -rm -f ./$(DEPDIR)/cipher-ctr.Plo + -rm -f ./$(DEPDIR)/cipher-eax.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-armv7-neon.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-intel-pclmul.Plo + -rm -f ./$(DEPDIR)/cipher-gcm.Plo + -rm -f ./$(DEPDIR)/cipher-ocb.Plo + -rm -f ./$(DEPDIR)/cipher-ofb.Plo + -rm -f ./$(DEPDIR)/cipher-poly1305.Plo + -rm -f ./$(DEPDIR)/cipher-selftest.Plo + -rm -f ./$(DEPDIR)/cipher-xts.Plo + -rm -f ./$(DEPDIR)/cipher.Plo + -rm -f ./$(DEPDIR)/crc-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/crc-armv8-ce.Plo + -rm -f ./$(DEPDIR)/crc-intel-pclmul.Plo + -rm -f ./$(DEPDIR)/crc-ppc.Plo + -rm -f ./$(DEPDIR)/crc.Plo + -rm -f ./$(DEPDIR)/des-amd64.Plo + -rm -f ./$(DEPDIR)/des.Plo + -rm -f ./$(DEPDIR)/dsa-common.Plo + -rm -f ./$(DEPDIR)/dsa.Plo + -rm -f ./$(DEPDIR)/ecc-curves.Plo + -rm -f ./$(DEPDIR)/ecc-ecdh.Plo + -rm -f ./$(DEPDIR)/ecc-ecdsa.Plo + -rm -f ./$(DEPDIR)/ecc-eddsa.Plo + -rm -f ./$(DEPDIR)/ecc-gost.Plo + -rm -f ./$(DEPDIR)/ecc-misc.Plo + -rm -f ./$(DEPDIR)/ecc-sm2.Plo + -rm -f ./$(DEPDIR)/ecc.Plo + -rm -f ./$(DEPDIR)/elgamal.Plo + -rm -f ./$(DEPDIR)/gost28147.Plo + -rm -f ./$(DEPDIR)/gostr3411-94.Plo + -rm -f ./$(DEPDIR)/hash-common.Plo + -rm -f ./$(DEPDIR)/idea.Plo + -rm -f ./$(DEPDIR)/kdf.Plo + -rm -f ./$(DEPDIR)/keccak-armv7-neon.Plo + -rm -f ./$(DEPDIR)/keccak.Plo + -rm -f ./$(DEPDIR)/mac-cmac.Plo + -rm -f ./$(DEPDIR)/mac-gmac.Plo + -rm -f ./$(DEPDIR)/mac-hmac.Plo + -rm -f ./$(DEPDIR)/mac-poly1305.Plo + -rm -f ./$(DEPDIR)/mac.Plo + -rm -f ./$(DEPDIR)/md.Plo + -rm -f ./$(DEPDIR)/md4.Plo + -rm -f ./$(DEPDIR)/md5.Plo + -rm -f ./$(DEPDIR)/poly1305-s390x.Plo + -rm -f ./$(DEPDIR)/poly1305.Plo + -rm -f ./$(DEPDIR)/primegen.Plo + -rm -f ./$(DEPDIR)/pubkey-util.Plo + -rm -f ./$(DEPDIR)/pubkey.Plo + -rm -f ./$(DEPDIR)/rfc2268.Plo + -rm -f ./$(DEPDIR)/rijndael-aarch64.Plo + -rm -f ./$(DEPDIR)/rijndael-aesni.Plo + -rm -f ./$(DEPDIR)/rijndael-amd64.Plo + -rm -f ./$(DEPDIR)/rijndael-arm.Plo + -rm -f ./$(DEPDIR)/rijndael-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/rijndael-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/rijndael-armv8-ce.Plo + -rm -f ./$(DEPDIR)/rijndael-padlock.Plo + -rm -f ./$(DEPDIR)/rijndael-ppc.Plo + -rm -f ./$(DEPDIR)/rijndael-ppc9le.Plo + -rm -f ./$(DEPDIR)/rijndael-s390x.Plo + -rm -f ./$(DEPDIR)/rijndael-ssse3-amd64-asm.Plo + -rm -f ./$(DEPDIR)/rijndael-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/rijndael.Plo + -rm -f ./$(DEPDIR)/rmd160.Plo + -rm -f ./$(DEPDIR)/rsa-common.Plo + -rm -f ./$(DEPDIR)/rsa.Plo + -rm -f ./$(DEPDIR)/salsa20-amd64.Plo + -rm -f ./$(DEPDIR)/salsa20-armv7-neon.Plo + -rm -f ./$(DEPDIR)/salsa20.Plo + -rm -f ./$(DEPDIR)/scrypt.Plo + -rm -f ./$(DEPDIR)/seed.Plo + -rm -f ./$(DEPDIR)/serpent-armv7-neon.Plo + -rm -f ./$(DEPDIR)/serpent-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/serpent-sse2-amd64.Plo + -rm -f ./$(DEPDIR)/serpent.Plo + -rm -f ./$(DEPDIR)/sha1-armv7-neon.Plo + -rm -f ./$(DEPDIR)/sha1-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/sha1-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/sha1-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sha1-avx-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha1-avx2-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha1-intel-shaext.Plo + -rm -f ./$(DEPDIR)/sha1-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/sha1.Plo + -rm -f ./$(DEPDIR)/sha256-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/sha256-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/sha256-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sha256-avx2-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha256-intel-shaext.Plo + -rm -f ./$(DEPDIR)/sha256-ppc.Plo + -rm -f ./$(DEPDIR)/sha256-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/sha256.Plo + -rm -f ./$(DEPDIR)/sha512-arm.Plo + -rm -f ./$(DEPDIR)/sha512-armv7-neon.Plo + -rm -f ./$(DEPDIR)/sha512-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sha512-avx2-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha512-ppc.Plo + -rm -f ./$(DEPDIR)/sha512-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/sha512-ssse3-i386.Plo + -rm -f ./$(DEPDIR)/sha512.Plo + -rm -f ./$(DEPDIR)/sm3.Plo + -rm -f ./$(DEPDIR)/sm4-aesni-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sm4-aesni-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/sm4.Plo + -rm -f ./$(DEPDIR)/stribog.Plo + -rm -f ./$(DEPDIR)/tiger.Plo + -rm -f ./$(DEPDIR)/twofish-aarch64.Plo + -rm -f ./$(DEPDIR)/twofish-amd64.Plo + -rm -f ./$(DEPDIR)/twofish-arm.Plo + -rm -f ./$(DEPDIR)/twofish-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/twofish.Plo + -rm -f ./$(DEPDIR)/whirlpool-sse2-amd64.Plo + -rm -f ./$(DEPDIR)/whirlpool.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/arcfour-amd64.Plo + -rm -f ./$(DEPDIR)/arcfour.Plo + -rm -f ./$(DEPDIR)/blake2.Plo + -rm -f ./$(DEPDIR)/blake2b-amd64-avx2.Plo + -rm -f ./$(DEPDIR)/blake2s-amd64-avx.Plo + -rm -f ./$(DEPDIR)/blowfish-amd64.Plo + -rm -f ./$(DEPDIR)/blowfish-arm.Plo + -rm -f ./$(DEPDIR)/blowfish.Plo + -rm -f ./$(DEPDIR)/camellia-aarch64.Plo + -rm -f ./$(DEPDIR)/camellia-aesni-avx-amd64.Plo + -rm -f ./$(DEPDIR)/camellia-aesni-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/camellia-arm.Plo + -rm -f ./$(DEPDIR)/camellia-glue.Plo + -rm -f ./$(DEPDIR)/camellia.Plo + -rm -f ./$(DEPDIR)/cast5-amd64.Plo + -rm -f ./$(DEPDIR)/cast5-arm.Plo + -rm -f ./$(DEPDIR)/cast5.Plo + -rm -f ./$(DEPDIR)/chacha20-aarch64.Plo + -rm -f ./$(DEPDIR)/chacha20-amd64-avx2.Plo + -rm -f ./$(DEPDIR)/chacha20-amd64-ssse3.Plo + -rm -f ./$(DEPDIR)/chacha20-armv7-neon.Plo + -rm -f ./$(DEPDIR)/chacha20-ppc.Plo + -rm -f ./$(DEPDIR)/chacha20-s390x.Plo + -rm -f ./$(DEPDIR)/chacha20.Plo + -rm -f ./$(DEPDIR)/cipher-aeswrap.Plo + -rm -f ./$(DEPDIR)/cipher-cbc.Plo + -rm -f ./$(DEPDIR)/cipher-ccm.Plo + -rm -f ./$(DEPDIR)/cipher-cfb.Plo + -rm -f ./$(DEPDIR)/cipher-cmac.Plo + -rm -f ./$(DEPDIR)/cipher-ctr.Plo + -rm -f ./$(DEPDIR)/cipher-eax.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-armv7-neon.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/cipher-gcm-intel-pclmul.Plo + -rm -f ./$(DEPDIR)/cipher-gcm.Plo + -rm -f ./$(DEPDIR)/cipher-ocb.Plo + -rm -f ./$(DEPDIR)/cipher-ofb.Plo + -rm -f ./$(DEPDIR)/cipher-poly1305.Plo + -rm -f ./$(DEPDIR)/cipher-selftest.Plo + -rm -f ./$(DEPDIR)/cipher-xts.Plo + -rm -f ./$(DEPDIR)/cipher.Plo + -rm -f ./$(DEPDIR)/crc-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/crc-armv8-ce.Plo + -rm -f ./$(DEPDIR)/crc-intel-pclmul.Plo + -rm -f ./$(DEPDIR)/crc-ppc.Plo + -rm -f ./$(DEPDIR)/crc.Plo + -rm -f ./$(DEPDIR)/des-amd64.Plo + -rm -f ./$(DEPDIR)/des.Plo + -rm -f ./$(DEPDIR)/dsa-common.Plo + -rm -f ./$(DEPDIR)/dsa.Plo + -rm -f ./$(DEPDIR)/ecc-curves.Plo + -rm -f ./$(DEPDIR)/ecc-ecdh.Plo + -rm -f ./$(DEPDIR)/ecc-ecdsa.Plo + -rm -f ./$(DEPDIR)/ecc-eddsa.Plo + -rm -f ./$(DEPDIR)/ecc-gost.Plo + -rm -f ./$(DEPDIR)/ecc-misc.Plo + -rm -f ./$(DEPDIR)/ecc-sm2.Plo + -rm -f ./$(DEPDIR)/ecc.Plo + -rm -f ./$(DEPDIR)/elgamal.Plo + -rm -f ./$(DEPDIR)/gost28147.Plo + -rm -f ./$(DEPDIR)/gostr3411-94.Plo + -rm -f ./$(DEPDIR)/hash-common.Plo + -rm -f ./$(DEPDIR)/idea.Plo + -rm -f ./$(DEPDIR)/kdf.Plo + -rm -f ./$(DEPDIR)/keccak-armv7-neon.Plo + -rm -f ./$(DEPDIR)/keccak.Plo + -rm -f ./$(DEPDIR)/mac-cmac.Plo + -rm -f ./$(DEPDIR)/mac-gmac.Plo + -rm -f ./$(DEPDIR)/mac-hmac.Plo + -rm -f ./$(DEPDIR)/mac-poly1305.Plo + -rm -f ./$(DEPDIR)/mac.Plo + -rm -f ./$(DEPDIR)/md.Plo + -rm -f ./$(DEPDIR)/md4.Plo + -rm -f ./$(DEPDIR)/md5.Plo + -rm -f ./$(DEPDIR)/poly1305-s390x.Plo + -rm -f ./$(DEPDIR)/poly1305.Plo + -rm -f ./$(DEPDIR)/primegen.Plo + -rm -f ./$(DEPDIR)/pubkey-util.Plo + -rm -f ./$(DEPDIR)/pubkey.Plo + -rm -f ./$(DEPDIR)/rfc2268.Plo + -rm -f ./$(DEPDIR)/rijndael-aarch64.Plo + -rm -f ./$(DEPDIR)/rijndael-aesni.Plo + -rm -f ./$(DEPDIR)/rijndael-amd64.Plo + -rm -f ./$(DEPDIR)/rijndael-arm.Plo + -rm -f ./$(DEPDIR)/rijndael-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/rijndael-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/rijndael-armv8-ce.Plo + -rm -f ./$(DEPDIR)/rijndael-padlock.Plo + -rm -f ./$(DEPDIR)/rijndael-ppc.Plo + -rm -f ./$(DEPDIR)/rijndael-ppc9le.Plo + -rm -f ./$(DEPDIR)/rijndael-s390x.Plo + -rm -f ./$(DEPDIR)/rijndael-ssse3-amd64-asm.Plo + -rm -f ./$(DEPDIR)/rijndael-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/rijndael.Plo + -rm -f ./$(DEPDIR)/rmd160.Plo + -rm -f ./$(DEPDIR)/rsa-common.Plo + -rm -f ./$(DEPDIR)/rsa.Plo + -rm -f ./$(DEPDIR)/salsa20-amd64.Plo + -rm -f ./$(DEPDIR)/salsa20-armv7-neon.Plo + -rm -f ./$(DEPDIR)/salsa20.Plo + -rm -f ./$(DEPDIR)/scrypt.Plo + -rm -f ./$(DEPDIR)/seed.Plo + -rm -f ./$(DEPDIR)/serpent-armv7-neon.Plo + -rm -f ./$(DEPDIR)/serpent-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/serpent-sse2-amd64.Plo + -rm -f ./$(DEPDIR)/serpent.Plo + -rm -f ./$(DEPDIR)/sha1-armv7-neon.Plo + -rm -f ./$(DEPDIR)/sha1-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/sha1-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/sha1-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sha1-avx-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha1-avx2-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha1-intel-shaext.Plo + -rm -f ./$(DEPDIR)/sha1-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/sha1.Plo + -rm -f ./$(DEPDIR)/sha256-armv8-aarch32-ce.Plo + -rm -f ./$(DEPDIR)/sha256-armv8-aarch64-ce.Plo + -rm -f ./$(DEPDIR)/sha256-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sha256-avx2-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha256-intel-shaext.Plo + -rm -f ./$(DEPDIR)/sha256-ppc.Plo + -rm -f ./$(DEPDIR)/sha256-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/sha256.Plo + -rm -f ./$(DEPDIR)/sha512-arm.Plo + -rm -f ./$(DEPDIR)/sha512-armv7-neon.Plo + -rm -f ./$(DEPDIR)/sha512-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sha512-avx2-bmi2-amd64.Plo + -rm -f ./$(DEPDIR)/sha512-ppc.Plo + -rm -f ./$(DEPDIR)/sha512-ssse3-amd64.Plo + -rm -f ./$(DEPDIR)/sha512-ssse3-i386.Plo + -rm -f ./$(DEPDIR)/sha512.Plo + -rm -f ./$(DEPDIR)/sm3.Plo + -rm -f ./$(DEPDIR)/sm4-aesni-avx-amd64.Plo + -rm -f ./$(DEPDIR)/sm4-aesni-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/sm4.Plo + -rm -f ./$(DEPDIR)/stribog.Plo + -rm -f ./$(DEPDIR)/tiger.Plo + -rm -f ./$(DEPDIR)/twofish-aarch64.Plo + -rm -f ./$(DEPDIR)/twofish-amd64.Plo + -rm -f ./$(DEPDIR)/twofish-arm.Plo + -rm -f ./$(DEPDIR)/twofish-avx2-amd64.Plo + -rm -f ./$(DEPDIR)/twofish.Plo + -rm -f ./$(DEPDIR)/whirlpool-sse2-amd64.Plo + -rm -f ./$(DEPDIR)/whirlpool.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +gost28147.lo: gost-sb.h +gost-sb.h: gost-s-box + ./gost-s-box $@ + +gost-s-box: gost-s-box.c + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD)-o $@ $(srcdir)/gost-s-box.c + +# We need to lower the optimization for this module. +tiger.o: $(srcdir)/tiger.c Makefile + `echo $(COMPILE) -c $< | $(o_flag_munging) ` + +tiger.lo: $(srcdir)/tiger.c Makefile + `echo $(LTCOMPILE) -c $< | $(o_flag_munging) ` + +rijndael-aesni.o: $(srcdir)/rijndael-aesni.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-aesni.lo: $(srcdir)/rijndael-aesni.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-ssse3-amd64.o: $(srcdir)/rijndael-ssse3-amd64.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-ssse3-amd64.lo: $(srcdir)/rijndael-ssse3-amd64.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +cipher-gcm-intel-pclmul.o: $(srcdir)/cipher-gcm-intel-pclmul.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +cipher-gcm-intel-pclmul.lo: $(srcdir)/cipher-gcm-intel-pclmul.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +sha1-intel-shaext.o: $(srcdir)/sha1-intel-shaext.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +sha1-intel-shaext.lo: $(srcdir)/sha1-intel-shaext.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +sha256-intel-shaext.o: $(srcdir)/sha256-intel-shaext.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +sha256-intel-shaext.lo: $(srcdir)/sha256-intel-shaext.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +sha256-ssse3-i386.o: $(srcdir)/sha256-ssse3-i386.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +sha256-ssse3-i386.lo: $(srcdir)/sha256-ssse3-i386.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +crc-intel-pclmul.o: $(srcdir)/crc-intel-pclmul.c Makefile + `echo $(COMPILE) -c $< | $(instrumentation_munging) ` + +crc-intel-pclmul.lo: $(srcdir)/crc-intel-pclmul.c Makefile + `echo $(LTCOMPILE) -c $< | $(instrumentation_munging) ` + +rijndael-ppc.o: $(srcdir)/rijndael-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +rijndael-ppc.lo: $(srcdir)/rijndael-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +rijndael-ppc9le.o: $(srcdir)/rijndael-ppc9le.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +rijndael-ppc9le.lo: $(srcdir)/rijndael-ppc9le.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha256-ppc.o: $(srcdir)/sha256-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha256-ppc.lo: $(srcdir)/sha256-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha512-ppc.o: $(srcdir)/sha512-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +sha512-ppc.lo: $(srcdir)/sha512-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +chacha20-ppc.o: $(srcdir)/chacha20-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +chacha20-ppc.lo: $(srcdir)/chacha20-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +crc-ppc.o: $(srcdir)/crc-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +crc-ppc.lo: $(srcdir)/crc-ppc.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgcrypt/cipher/arcfour-amd64.S b/comm/third_party/libgcrypt/cipher/arcfour-amd64.S new file mode 100644 index 0000000000..221dfeff77 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/arcfour-amd64.S @@ -0,0 +1,108 @@ +/* +** RC4 implementation optimized for AMD64. +** +** Author: Marc Bevand +** Licence: I hereby disclaim the copyright on this code and place it +** in the public domain. +** +** The throughput achieved by this code is about 320 MBytes/sec, on +** a 1.8 GHz AMD Opteron (rev C0) processor. +** +** 2013/12/20 : +** - Integrated to libgcrypt +** - 4.18 cycles/byte on Intel i5-4570 +*/ + +#ifdef __x86_64__ +#include +#if defined(USE_ARCFOUR) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +#include "asm-common-amd64.h" + +.text +.align 16 +.globl _gcry_arcfour_amd64 +ELF(.type _gcry_arcfour_amd64,@function) +_gcry_arcfour_amd64: + CFI_STARTPROC() + ENTER_SYSV_FUNC_PARAMS_0_4 + push %rbp + CFI_PUSH(%rbp) + push %rbx + CFI_PUSH(%rbx) + mov %rdi, %rbp # key = ARG(key) + mov %rsi, %rbx # rbx = ARG(len) + mov %rdx, %rsi # in = ARG(in) + mov %rcx, %rdi # out = ARG(out) + mov (4*256)(%rbp), %ecx # x = key->x + mov (4*256+4)(%rbp),%edx # y = key->y + inc %rcx # x++ + and $255, %rcx # x &= 0xff + lea -8(%rbx,%rsi), %rbx # rbx = in+len-8 + mov %rbx, %r9 # tmp = in+len-8 + mov (%rbp,%rcx,4), %eax # tx = d[x] + cmp %rsi, %rbx # cmp in with in+len-8 + jl .Lend # jump if (in+len-8 < in) + +.Lstart: + add $8, %rsi # increment in + add $8, %rdi # increment out + + # generate the next 8 bytes of the rc4 stream into %r8 + mov $8, %r11 # byte counter +1: add %al, %dl # y += tx + mov (%rbp,%rdx,4), %ebx # ty = d[y] + mov %ebx, (%rbp,%rcx,4) # d[x] = ty + add %al, %bl # val = ty + tx + mov %eax, (%rbp,%rdx,4) # d[y] = tx + inc %cl # x++ (NEXT ROUND) + mov (%rbp,%rcx,4), %eax # tx = d[x] (NEXT ROUND) + shl $8, %r8 + movb (%rbp,%rbx,4), %r8b # val = d[val] + dec %r11b + jnz 1b + + # xor 8 bytes + bswap %r8 + xor -8(%rsi), %r8 + cmp %r9, %rsi # cmp in+len-8 with in + mov %r8, -8(%rdi) + jle .Lstart # jump if (in <= in+len-8) + +.Lend: + add $8, %r9 # tmp = in+len + + # handle the last bytes, one by one +1: cmp %rsi, %r9 # cmp in with in+len + jle .Lfinished # jump if (in+len <= in) + add %al, %dl # y += tx + mov (%rbp,%rdx,4), %ebx # ty = d[y] + mov %ebx, (%rbp,%rcx,4) # d[x] = ty + add %al, %bl # val = ty + tx + mov %eax, (%rbp,%rdx,4) # d[y] = tx + inc %cl # x++ (NEXT ROUND) + mov (%rbp,%rcx,4), %eax # tx = d[x] (NEXT ROUND) + movb (%rbp,%rbx,4), %r8b # val = d[val] + xor (%rsi), %r8b # xor 1 byte + movb %r8b, (%rdi) + inc %rsi # in++ + inc %rdi # out++ + jmp 1b + +.Lfinished: + dec %rcx # x-- + movb %cl, (4*256)(%rbp) # key->y = y + movb %dl, (4*256+4)(%rbp) # key->x = x + pop %rbx + CFI_POP(%rbx) + pop %rbp + CFI_POP(%rbp) + EXIT_SYSV_FUNC + ret + CFI_ENDPROC() +.L__gcry_arcfour_amd64_end: +ELF(.size _gcry_arcfour_amd64,.L__gcry_arcfour_amd64_end-_gcry_arcfour_amd64) + +#endif +#endif diff --git a/comm/third_party/libgcrypt/cipher/arcfour.c b/comm/third_party/libgcrypt/cipher/arcfour.c new file mode 100644 index 0000000000..353de00bd7 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/arcfour.c @@ -0,0 +1,216 @@ +/* arcfour.c - The arcfour stream cipher + * Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 397 ff. + */ + + +#include +#include +#include +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "cipher-internal.h" + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AMD64_ASM 1 +#endif + +static const char *selftest(void); + +#ifdef USE_AMD64_ASM + +typedef struct { + u32 sbox[256]; + u32 idx_i, idx_j; +} ARCFOUR_context; + +void _gcry_arcfour_amd64(void *key, size_t len, const byte *indata, + byte *outdata); + +static void +encrypt_stream (void *context, + byte *outbuf, const byte *inbuf, size_t length) +{ + _gcry_arcfour_amd64 (context, length, inbuf, outbuf ); +} + +#else /*!USE_AMD64_ASM*/ + +typedef struct { + byte sbox[256]; + int idx_i, idx_j; +} ARCFOUR_context; + +static void +do_encrypt_stream( ARCFOUR_context *ctx, + byte *outbuf, const byte *inbuf, size_t length ) +{ +#ifndef __i386__ + register unsigned int i = ctx->idx_i; + register byte j = ctx->idx_j; + register byte *sbox = ctx->sbox; + register byte t, u; + + while ( length-- ) + { + i++; + t = sbox[(byte)i]; + j += t; + u = sbox[j]; + sbox[(byte)i] = u; + u += t; + sbox[j] = t; + *outbuf++ = sbox[u] ^ *inbuf++; + } + + ctx->idx_i = (byte)i; + ctx->idx_j = (byte)j; +#else /*__i386__*/ + /* Old implementation of arcfour is faster on i386 than the version above. + * This is because version above increases register pressure which on i386 + * would push some of the variables to memory/stack. Therefore keep this + * version for i386 to avoid regressing performance. */ + register int i = ctx->idx_i; + register int j = ctx->idx_j; + register byte *sbox = ctx->sbox; + register int t; + + while ( length-- ) + { + i++; + i = i & 255; /* The and-op seems to be faster than the mod-op. */ + j += sbox[i]; + j &= 255; + t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t; + *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255]; + } + + ctx->idx_i = i; + ctx->idx_j = j; +#endif +} + +static void +encrypt_stream (void *context, + byte *outbuf, const byte *inbuf, size_t length) +{ + ARCFOUR_context *ctx = (ARCFOUR_context *) context; + do_encrypt_stream (ctx, outbuf, inbuf, length ); + _gcry_burn_stack (64); +} + +#endif /*!USE_AMD64_ASM*/ + + +static gcry_err_code_t +do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) +{ + static int initialized; + static const char* selftest_failed; + int i, j; + byte karr[256]; + ARCFOUR_context *ctx = (ARCFOUR_context *) context; + + if (!initialized ) + { + initialized = 1; + selftest_failed = selftest(); + if( selftest_failed ) + log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed ); + } + if( selftest_failed ) + return GPG_ERR_SELFTEST_FAILED; + + if( keylen < 40/8 ) /* we want at least 40 bits */ + return GPG_ERR_INV_KEYLEN; + + ctx->idx_i = ctx->idx_j = 0; + for (i=0; i < 256; i++ ) + ctx->sbox[i] = i; + for (i=j=0; i < 256; i++,j++ ) + { + if (j >= keylen) + j = 0; + karr[i] = key[j]; + } + for (i=j=0; i < 256; i++ ) + { + int t; + j = (j + ctx->sbox[i] + karr[i]) & 255; + t = ctx->sbox[i]; + ctx->sbox[i] = ctx->sbox[j]; + ctx->sbox[j] = t; + } + wipememory( karr, sizeof(karr) ); + + return GPG_ERR_NO_ERROR; +} + +static gcry_err_code_t +arcfour_setkey ( void *context, const byte *key, unsigned int keylen, + cipher_bulk_ops_t *bulk_ops ) +{ + ARCFOUR_context *ctx = (ARCFOUR_context *) context; + gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen ); + (void)bulk_ops; + return rc; +} + + +static const char* +selftest(void) +{ + ARCFOUR_context ctx; + byte scratch[16]; + + /* Test vector from Cryptlib labeled there: "from the + State/Commerce Department". */ + static const byte key_1[] = + { 0x61, 0x8A, 0x63, 0xD2, 0xFB }; + static const byte plaintext_1[] = + { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C }; + static const byte ciphertext_1[] = + { 0xF1, 0x38, 0x29, 0xC9, 0xDE }; + + arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL); + encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1)); + if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1))) + return "Arcfour encryption test 1 failed."; + arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL); + encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */ + if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1))) + return "Arcfour decryption test 1 failed."; + return NULL; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_arcfour = + { + GCRY_CIPHER_ARCFOUR, {0, 0}, + "ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context), + arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream, + }; diff --git a/comm/third_party/libgcrypt/cipher/asm-common-aarch64.h b/comm/third_party/libgcrypt/cipher/asm-common-aarch64.h new file mode 100644 index 0000000000..cf0afe1f87 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-common-aarch64.h @@ -0,0 +1,104 @@ +/* asm-common-aarch64.h - Common macros for AArch64 assembly + * + * Copyright (C) 2018 Martin Storsjö + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_COMMON_AARCH64_H +#define GCRY_ASM_COMMON_AARCH64_H + +#include + +#ifdef HAVE_GCC_ASM_ELF_DIRECTIVES +# define ELF(...) __VA_ARGS__ +#else +# define ELF(...) /*_*/ +#endif + +#ifdef __APPLE__ +#define GET_DATA_POINTER(reg, name) \ + adrp reg, name@GOTPAGE ; \ + add reg, reg, name@GOTPAGEOFF ; +#elif defined(_WIN32) +#define GET_DATA_POINTER(reg, name) \ + adrp reg, name ; \ + add reg, reg, #:lo12:name ; +#else +#define GET_DATA_POINTER(reg, name) \ + adrp reg, :got:name ; \ + ldr reg, [reg, #:got_lo12:name] ; +#endif + +#ifdef HAVE_GCC_ASM_CFI_DIRECTIVES +/* CFI directives to emit DWARF stack unwinding information. */ +# define CFI_STARTPROC() .cfi_startproc +# define CFI_ENDPROC() .cfi_endproc +# define CFI_REMEMBER_STATE() .cfi_remember_state +# define CFI_RESTORE_STATE() .cfi_restore_state +# define CFI_ADJUST_CFA_OFFSET(off) .cfi_adjust_cfa_offset off +# define CFI_REL_OFFSET(reg,off) .cfi_rel_offset reg, off +# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg +# define CFI_REGISTER(ro,rn) .cfi_register ro, rn +# define CFI_RESTORE(reg) .cfi_restore reg + +/* CFA expressions are used for pointing CFA and registers to + * SP relative offsets. */ +# define DW_REGNO_SP 31 + +/* Fixed length encoding used for integers for now. */ +# define DW_SLEB128_7BIT(value) \ + 0x00|((value) & 0x7f) +# define DW_SLEB128_28BIT(value) \ + 0x80|((value)&0x7f), \ + 0x80|(((value)>>7)&0x7f), \ + 0x80|(((value)>>14)&0x7f), \ + 0x00|(((value)>>21)&0x7f) + +# define CFI_CFA_ON_STACK(rsp_offs,cfa_depth) \ + .cfi_escape \ + 0x0f, /* DW_CFA_def_cfa_expression */ \ + DW_SLEB128_7BIT(11), /* length */ \ + 0x8f, /* DW_OP_breg31, rsp + constant */ \ + DW_SLEB128_28BIT(rsp_offs), \ + 0x06, /* DW_OP_deref */ \ + 0x23, /* DW_OP_plus_constu */ \ + DW_SLEB128_28BIT((cfa_depth)+8) + +# define CFI_REG_ON_STACK(regno,rsp_offs) \ + .cfi_escape \ + 0x10, /* DW_CFA_expression */ \ + DW_SLEB128_7BIT(regno), \ + DW_SLEB128_7BIT(5), /* length */ \ + 0x8f, /* DW_OP_breg31, rsp + constant */ \ + DW_SLEB128_28BIT(rsp_offs) + +#else +# define CFI_STARTPROC() +# define CFI_ENDPROC() +# define CFI_REMEMBER_STATE() +# define CFI_RESTORE_STATE() +# define CFI_ADJUST_CFA_OFFSET(off) +# define CFI_REL_OFFSET(reg,off) +# define CFI_DEF_CFA_REGISTER(reg) +# define CFI_REGISTER(ro,rn) +# define CFI_RESTORE(reg) + +# define CFI_CFA_ON_STACK(rsp_offs,cfa_depth) +# define CFI_REG_ON_STACK(reg,rsp_offs) +#endif + +#endif /* GCRY_ASM_COMMON_AARCH64_H */ diff --git a/comm/third_party/libgcrypt/cipher/asm-common-amd64.h b/comm/third_party/libgcrypt/cipher/asm-common-amd64.h new file mode 100644 index 0000000000..9d4a028a04 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-common-amd64.h @@ -0,0 +1,189 @@ +/* asm-common-amd64.h - Common macros for AMD64 assembly + * + * Copyright (C) 2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_COMMON_AMD64_H +#define GCRY_ASM_COMMON_AMD64_H + +#include + +#ifdef HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS +# define ELF(...) __VA_ARGS__ +#else +# define ELF(...) /*_*/ +#endif + +#ifdef __PIC__ +# define rRIP (%rip) +#else +# define rRIP +#endif + +#ifdef __PIC__ +# define RIP %rip +#else +# define RIP +#endif + +#ifdef __PIC__ +# define ADD_RIP +rip +#else +# define ADD_RIP +#endif + +#if defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS) || !defined(__PIC__) +# define GET_EXTERN_POINTER(name, reg) movabsq $name, reg +#else +# ifdef __code_model_large__ +# define GET_EXTERN_POINTER(name, reg) \ + pushq %r15; \ + pushq %r14; \ + 1: leaq 1b(%rip), reg; \ + movabsq $_GLOBAL_OFFSET_TABLE_-1b, %r14; \ + movabsq $name@GOT, %r15; \ + addq %r14, reg; \ + popq %r14; \ + movq (reg, %r15), reg; \ + popq %r15; +# else +# define GET_EXTERN_POINTER(name, reg) movq name@GOTPCREL(%rip), reg +# endif +#endif + +#ifdef HAVE_GCC_ASM_CFI_DIRECTIVES +/* CFI directives to emit DWARF stack unwinding information. */ +# define CFI_STARTPROC() .cfi_startproc +# define CFI_ENDPROC() .cfi_endproc +# define CFI_REMEMBER_STATE() .cfi_remember_state +# define CFI_RESTORE_STATE() .cfi_restore_state +# define CFI_ADJUST_CFA_OFFSET(off) .cfi_adjust_cfa_offset off +# define CFI_REL_OFFSET(reg,off) .cfi_rel_offset reg, off +# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg +# define CFI_REGISTER(ro,rn) .cfi_register ro, rn +# define CFI_RESTORE(reg) .cfi_restore reg + +# define CFI_PUSH(reg) \ + CFI_ADJUST_CFA_OFFSET(8); CFI_REL_OFFSET(reg, 0) +# define CFI_POP(reg) \ + CFI_ADJUST_CFA_OFFSET(-8); CFI_RESTORE(reg) +# define CFI_POP_TMP_REG() \ + CFI_ADJUST_CFA_OFFSET(-8); +# define CFI_LEAVE() \ + CFI_ADJUST_CFA_OFFSET(-8); CFI_DEF_CFA_REGISTER(%rsp) + +/* CFA expressions are used for pointing CFA and registers to + * %rsp relative offsets. */ +# define DW_REGNO_rax 0 +# define DW_REGNO_rdx 1 +# define DW_REGNO_rcx 2 +# define DW_REGNO_rbx 3 +# define DW_REGNO_rsi 4 +# define DW_REGNO_rdi 5 +# define DW_REGNO_rbp 6 +# define DW_REGNO_rsp 7 +# define DW_REGNO_r8 8 +# define DW_REGNO_r9 9 +# define DW_REGNO_r10 10 +# define DW_REGNO_r11 11 +# define DW_REGNO_r12 12 +# define DW_REGNO_r13 13 +# define DW_REGNO_r14 14 +# define DW_REGNO_r15 15 + +# define DW_REGNO(reg) DW_REGNO_ ## reg + +/* Fixed length encoding used for integers for now. */ +# define DW_SLEB128_7BIT(value) \ + 0x00|((value) & 0x7f) +# define DW_SLEB128_28BIT(value) \ + 0x80|((value)&0x7f), \ + 0x80|(((value)>>7)&0x7f), \ + 0x80|(((value)>>14)&0x7f), \ + 0x00|(((value)>>21)&0x7f) + +# define CFI_CFA_ON_STACK(rsp_offs,cfa_depth) \ + .cfi_escape \ + 0x0f, /* DW_CFA_def_cfa_expression */ \ + DW_SLEB128_7BIT(11), /* length */ \ + 0x77, /* DW_OP_breg7, rsp + constant */ \ + DW_SLEB128_28BIT(rsp_offs), \ + 0x06, /* DW_OP_deref */ \ + 0x23, /* DW_OP_plus_constu */ \ + DW_SLEB128_28BIT((cfa_depth)+8) + +# define CFI_REG_ON_STACK(reg,rsp_offs) \ + .cfi_escape \ + 0x10, /* DW_CFA_expression */ \ + DW_SLEB128_7BIT(DW_REGNO(reg)), \ + DW_SLEB128_7BIT(5), /* length */ \ + 0x77, /* DW_OP_breg7, rsp + constant */ \ + DW_SLEB128_28BIT(rsp_offs) + +#else +# define CFI_STARTPROC() +# define CFI_ENDPROC() +# define CFI_REMEMBER_STATE() +# define CFI_RESTORE_STATE() +# define CFI_ADJUST_CFA_OFFSET(off) +# define CFI_REL_OFFSET(reg,off) +# define CFI_DEF_CFA_REGISTER(reg) +# define CFI_REGISTER(ro,rn) +# define CFI_RESTORE(reg) + +# define CFI_PUSH(reg) +# define CFI_POP(reg) +# define CFI_POP_TMP_REG() +# define CFI_LEAVE() + +# define CFI_CFA_ON_STACK(rsp_offs,cfa_depth) +# define CFI_REG_ON_STACK(reg,rsp_offs) +#endif + +#ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS +# define ENTER_SYSV_FUNC_PARAMS_0_4 \ + pushq %rdi; \ + CFI_PUSH(%rdi); \ + pushq %rsi; \ + CFI_PUSH(%rsi); \ + movq %rcx, %rdi; \ + movq %rdx, %rsi; \ + movq %r8, %rdx; \ + movq %r9, %rcx; \ + +# define ENTER_SYSV_FUNC_PARAMS_5 \ + ENTER_SYSV_FUNC_PARAMS_0_4; \ + movq 0x38(%rsp), %r8; + +# define ENTER_SYSV_FUNC_PARAMS_6 \ + ENTER_SYSV_FUNC_PARAMS_5; \ + movq 0x40(%rsp), %r9; + +# define EXIT_SYSV_FUNC \ + popq %rsi; \ + CFI_POP(%rsi); \ + popq %rdi; \ + CFI_POP(%rdi); +#else +# define ENTER_SYSV_FUNC_PARAMS_0_4 +# define ENTER_SYSV_FUNC_PARAMS_5 +# define ENTER_SYSV_FUNC_PARAMS_6 +# define EXIT_SYSV_FUNC +#endif + +#endif /* GCRY_ASM_COMMON_AMD64_H */ diff --git a/comm/third_party/libgcrypt/cipher/asm-common-s390x.h b/comm/third_party/libgcrypt/cipher/asm-common-s390x.h new file mode 100644 index 0000000000..b3a996cd6e --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-common-s390x.h @@ -0,0 +1,90 @@ +/* asm-common-s390x.h - Common macros for zSeries assembly + * + * Copyright (C) 2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_COMMON_S390X_H +#define GCRY_ASM_COMMON_S390X_H + +#include + +#ifdef HAVE_GCC_ASM_ELF_DIRECTIVES +# define ELF(...) __VA_ARGS__ +#else +# define ELF(...) /*_*/ +#endif + +#ifdef HAVE_GCC_ASM_CFI_DIRECTIVES +/* CFI directives to emit DWARF stack unwinding information. */ +# define CFI_STARTPROC() .cfi_startproc +# define CFI_ENDPROC() .cfi_endproc +# define CFI_REMEMBER_STATE() .cfi_remember_state +# define CFI_RESTORE_STATE() .cfi_restore_state +# define CFI_ADJUST_CFA_OFFSET(off) .cfi_adjust_cfa_offset off +# define CFI_REL_OFFSET(reg,off) .cfi_rel_offset reg, off +# define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg +# define CFI_REGISTER(ro,rn) .cfi_register ro, rn +# define CFI_RESTORE(reg) .cfi_restore reg + +/* CFA expressions are used for pointing CFA and registers to + * SP relative offsets. */ +# define DW_REGNO_SP 15 + +/* Fixed length encoding used for integers for now. */ +# define DW_SLEB128_7BIT(value) \ + 0x00|((value) & 0x7f) +# define DW_SLEB128_28BIT(value) \ + 0x80|((value)&0x7f), \ + 0x80|(((value)>>7)&0x7f), \ + 0x80|(((value)>>14)&0x7f), \ + 0x00|(((value)>>21)&0x7f) + +# define CFI_CFA_ON_STACK(rsp_offs,cfa_depth) \ + .cfi_escape \ + 0x0f, /* DW_CFA_def_cfa_expression */ \ + DW_SLEB128_7BIT(11), /* length */ \ + 0x7f, /* DW_OP_breg15, rsp + constant */ \ + DW_SLEB128_28BIT(rsp_offs), \ + 0x06, /* DW_OP_deref */ \ + 0x23, /* DW_OP_plus_constu */ \ + DW_SLEB128_28BIT((cfa_depth)+160) + +# define CFI_REG_ON_STACK(regno,rsp_offs) \ + .cfi_escape \ + 0x10, /* DW_CFA_expression */ \ + DW_SLEB128_7BIT(regno), \ + DW_SLEB128_7BIT(5), /* length */ \ + 0x7f, /* DW_OP_breg15, rsp + constant */ \ + DW_SLEB128_28BIT(rsp_offs) + +#else +# define CFI_STARTPROC() +# define CFI_ENDPROC() +# define CFI_REMEMBER_STATE() +# define CFI_RESTORE_STATE() +# define CFI_ADJUST_CFA_OFFSET(off) +# define CFI_REL_OFFSET(reg,off) +# define CFI_DEF_CFA_REGISTER(reg) +# define CFI_REGISTER(ro,rn) +# define CFI_RESTORE(reg) + +# define CFI_CFA_ON_STACK(rsp_offs,cfa_depth) +# define CFI_REG_ON_STACK(reg,rsp_offs) +#endif + +#endif /* GCRY_ASM_COMMON_AMD64_H */ diff --git a/comm/third_party/libgcrypt/cipher/asm-inline-s390x.h b/comm/third_party/libgcrypt/cipher/asm-inline-s390x.h new file mode 100644 index 0000000000..bacb45fe2e --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-inline-s390x.h @@ -0,0 +1,157 @@ +/* asm-inline-s390x.h - Common macros for zSeries inline assembly + * + * Copyright (C) 2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_INLINE_S390X_H +#define GCRY_ASM_INLINE_S390X_H + +#include + +#define ALWAYS_INLINE inline __attribute__((always_inline)) + +typedef unsigned int u128_t __attribute__ ((mode (TI))); + +enum kmxx_functions_e +{ + KM_FUNCTION_AES_128 = 18, + KM_FUNCTION_AES_192 = 19, + KM_FUNCTION_AES_256 = 20, + KM_FUNCTION_XTS_AES_128 = 50, + KM_FUNCTION_XTS_AES_256 = 52, + + KMID_FUNCTION_SHA1 = 1, + KMID_FUNCTION_SHA256 = 2, + KMID_FUNCTION_SHA512 = 3, + KMID_FUNCTION_SHA3_224 = 32, + KMID_FUNCTION_SHA3_256 = 33, + KMID_FUNCTION_SHA3_384 = 34, + KMID_FUNCTION_SHA3_512 = 35, + KMID_FUNCTION_SHAKE128 = 36, + KMID_FUNCTION_SHAKE256 = 37, + KMID_FUNCTION_GHASH = 65, +}; + +enum kmxx_function_flags_e +{ + KM_ENCRYPT = 0 << 7, + KM_DECRYPT = 1 << 7, + + KMF_LCFB_16 = 16 << 24, + + KMA_LPC = 1 << 8, + KMA_LAAD = 1 << 9, + KMA_HS = 1 << 10, + + KLMD_PADDING_STATE = 1 << 8, +}; + +static ALWAYS_INLINE u128_t km_function_to_mask(enum kmxx_functions_e func) +{ + return (u128_t)1 << (127 - func); +} + +static inline u128_t kimd_query(void) +{ + static u128_t function_codes = 0; + static int initialized = 0; + register unsigned long reg0 asm("0") = 0; + register void *reg1 asm("1") = &function_codes; + u128_t r1; + + if (initialized) + return function_codes; + + asm volatile ("0: .insn rre,0xb93e << 16, 0, %[r1]\n\t" + " brc 1,0b\n\t" + : [r1] "=a" (r1) + : [reg0] "r" (reg0), [reg1] "r" (reg1) + : "cc", "memory"); + + initialized = 1; + return function_codes; +} + +static inline u128_t klmd_query(void) +{ + static u128_t function_codes = 0; + static int initialized = 0; + register unsigned long reg0 asm("0") = 0; + register void *reg1 asm("1") = &function_codes; + u128_t r1; + + if (initialized) + return function_codes; + + asm volatile ("0: .insn rre,0xb93f << 16, 0, %[r1]\n\t" + " brc 1,0b\n\t" + : [r1] "=a" (r1) + : [reg0] "r" (reg0), [reg1] "r" (reg1) + : "cc", "memory"); + + initialized = 1; + return function_codes; +} + +static ALWAYS_INLINE void +kimd_execute(unsigned int func, void *param_block, const void *src, + size_t src_len) +{ + register unsigned long reg0 asm("0") = func; + register byte *reg1 asm("1") = param_block; + u128_t r1 = ((u128_t)(uintptr_t)src << 64) | (u64)src_len; + + asm volatile ("0: .insn rre,0xb93e << 16, 0, %[r1]\n\t" + " brc 1,0b\n\t" + : [r1] "+a" (r1) + : [func] "r" (reg0), [param_ptr] "r" (reg1) + : "cc", "memory"); +} + +static ALWAYS_INLINE void +klmd_execute(unsigned int func, void *param_block, const void *src, + size_t src_len) +{ + register unsigned long reg0 asm("0") = func; + register byte *reg1 asm("1") = param_block; + u128_t r1 = ((u128_t)(uintptr_t)src << 64) | (u64)src_len; + + asm volatile ("0: .insn rre,0xb93f << 16, 0, %[r1]\n\t" + " brc 1,0b\n\t" + : [func] "+r" (reg0), [r1] "+a" (r1) + : [param_ptr] "r" (reg1) + : "cc", "memory"); +} + +static ALWAYS_INLINE void +klmd_shake_execute(unsigned int func, void *param_block, void *dst, + size_t dst_len, const void *src, size_t src_len) +{ + register unsigned long reg0 asm("0") = func; + register byte *reg1 asm("1") = param_block; + u128_t r1 = ((u128_t)(uintptr_t)dst << 64) | (u64)dst_len; + u128_t r2 = ((u128_t)(uintptr_t)src << 64) | (u64)src_len; + + asm volatile ("0: .insn rre,0xb93f << 16, %[r1], %[r2]\n\t" + " brc 1,0b\n\t" + : [func] "+r" (reg0), [r1] "+a" (r1), [r2] "+a" (r2) + : [param_ptr] "r" (reg1) + : "cc", "memory"); +} + +#endif /* GCRY_ASM_INLINE_S390X_H */ diff --git a/comm/third_party/libgcrypt/cipher/asm-poly1305-aarch64.h b/comm/third_party/libgcrypt/cipher/asm-poly1305-aarch64.h new file mode 100644 index 0000000000..9009270956 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-poly1305-aarch64.h @@ -0,0 +1,245 @@ +/* asm-common-aarch64.h - Poly1305 macros for ARMv8/AArch64 assembly + * + * Copyright (C) 2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_POLY1305_AARCH64_H +#define GCRY_ASM_POLY1305_AARCH64_H + +#include "asm-common-aarch64.h" + +#ifdef __AARCH64EL__ + #define le_to_host(reg) /*_*/ +#else + #define le_to_host(reg) rev reg, reg; +#endif + +/********************************************************************** + poly1305 for stitched chacha20-poly1305 Aarch64 implementations + **********************************************************************/ + +#define POLY_RSTATE x8 +#define POLY_RSRC x9 + +#define POLY_R_H0 x10 +#define POLY_R_H1 x11 +#define POLY_R_H2 x12 +#define POLY_R_H2d w12 +#define POLY_R_R0 x13 +#define POLY_R_R1 x14 +#define POLY_R_R1_MUL5 x15 +#define POLY_R_X0_HI x16 +#define POLY_R_X0_LO x17 +#define POLY_R_X1_HI x19 +#define POLY_R_X1_LO x20 +#define POLY_R_ONE x21 +#define POLY_R_ONEd w21 + +#define POLY_TMP0 x22 +#define POLY_TMP1 x23 +#define POLY_TMP2 x24 +#define POLY_TMP3 x25 + +#define POLY_CHACHA_ROUND x26 + +#define POLY_S_R0 (4 * 4 + 0 * 8) +#define POLY_S_R1 (4 * 4 + 1 * 8) +#define POLY_S_H0 (4 * 4 + 2 * 8 + 0 * 8) +#define POLY_S_H1 (4 * 4 + 2 * 8 + 1 * 8) +#define POLY_S_H2d (4 * 4 + 2 * 8 + 2 * 8) + +#define POLY1305_PUSH_REGS() \ + stp x19, x20, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + CFI_REG_ON_STACK(19, 0); \ + CFI_REG_ON_STACK(20, 8); \ + stp x21, x22, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + CFI_REG_ON_STACK(21, 0); \ + CFI_REG_ON_STACK(22, 8); \ + stp x23, x24, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + CFI_REG_ON_STACK(23, 0); \ + CFI_REG_ON_STACK(24, 8); \ + stp x25, x26, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + CFI_REG_ON_STACK(25, 0); \ + CFI_REG_ON_STACK(26, 8); + +#define POLY1305_POP_REGS() \ + ldp x25, x26, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + CFI_RESTORE(x25); \ + CFI_RESTORE(x26); \ + ldp x23, x24, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + CFI_RESTORE(x23); \ + CFI_RESTORE(x24); \ + ldp x21, x22, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + CFI_RESTORE(x21); \ + CFI_RESTORE(x22); \ + ldp x19, x20, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + CFI_RESTORE(x19); \ + CFI_RESTORE(x20); + +#define POLY1305_LOAD_STATE() \ + ldr POLY_R_R1, [POLY_RSTATE, #(POLY_S_R1)]; \ + ldr POLY_R_H0, [POLY_RSTATE, #(POLY_S_H0)]; \ + ldr POLY_R_H1, [POLY_RSTATE, #(POLY_S_H1)]; \ + ldr POLY_R_H2d, [POLY_RSTATE, #(POLY_S_H2d)]; \ + ldr POLY_R_R0, [POLY_RSTATE, #(POLY_S_R0)]; \ + add POLY_R_R1_MUL5, POLY_R_R1, POLY_R_R1, lsr #2; \ + mov POLY_R_ONE, #1; + +#define POLY1305_STORE_STATE() \ + str POLY_R_H0, [POLY_RSTATE, #(POLY_S_H0)]; \ + str POLY_R_H1, [POLY_RSTATE, #(POLY_S_H1)]; \ + str POLY_R_H2d, [POLY_RSTATE, #(POLY_S_H2d)]; + +#define POLY1305_BLOCK_PART1(src_offset) \ + /* a = h + m */ \ + ldr POLY_TMP0, [POLY_RSRC, #((src_offset) + 0 * 8)]; +#define POLY1305_BLOCK_PART2(src_offset) \ + ldr POLY_TMP1, [POLY_RSRC, #((src_offset) + 1 * 8)]; +#define POLY1305_BLOCK_PART3() \ + le_to_host(POLY_TMP0); +#define POLY1305_BLOCK_PART4() \ + le_to_host(POLY_TMP1); +#define POLY1305_BLOCK_PART5() \ + adds POLY_R_H0, POLY_R_H0, POLY_TMP0; +#define POLY1305_BLOCK_PART6() \ + adcs POLY_R_H1, POLY_R_H1, POLY_TMP1; +#define POLY1305_BLOCK_PART7() \ + adc POLY_R_H2d, POLY_R_H2d, POLY_R_ONEd; + +#define POLY1305_BLOCK_PART8() \ + /* h = a * r (partial mod 2^130-5): */ \ + mul POLY_R_X1_LO, POLY_R_H0, POLY_R_R1; /* lo: h0 * r1 */ +#define POLY1305_BLOCK_PART9() \ + mul POLY_TMP0, POLY_R_H1, POLY_R_R0; /* lo: h1 * r0 */ +#define POLY1305_BLOCK_PART10() \ + mul POLY_R_X0_LO, POLY_R_H0, POLY_R_R0; /* lo: h0 * r0 */ +#define POLY1305_BLOCK_PART11() \ + umulh POLY_R_X1_HI, POLY_R_H0, POLY_R_R1; /* hi: h0 * r1 */ +#define POLY1305_BLOCK_PART12() \ + adds POLY_R_X1_LO, POLY_R_X1_LO, POLY_TMP0; +#define POLY1305_BLOCK_PART13() \ + umulh POLY_TMP1, POLY_R_H1, POLY_R_R0; /* hi: h1 * r0 */ +#define POLY1305_BLOCK_PART14() \ + mul POLY_TMP2, POLY_R_H1, POLY_R_R1_MUL5; /* lo: h1 * r1 mod 2^130-5 */ +#define POLY1305_BLOCK_PART15() \ + umulh POLY_R_X0_HI, POLY_R_H0, POLY_R_R0; /* hi: h0 * r0 */ +#define POLY1305_BLOCK_PART16() \ + adc POLY_R_X1_HI, POLY_R_X1_HI, POLY_TMP1; +#define POLY1305_BLOCK_PART17() \ + umulh POLY_TMP3, POLY_R_H1, POLY_R_R1_MUL5; /* hi: h1 * r1 mod 2^130-5 */ +#define POLY1305_BLOCK_PART18() \ + adds POLY_R_X0_LO, POLY_R_X0_LO, POLY_TMP2; +#define POLY1305_BLOCK_PART19() \ + mul POLY_R_H1, POLY_R_H2, POLY_R_R1_MUL5; /* h2 * r1 mod 2^130-5 */ +#define POLY1305_BLOCK_PART20() \ + adc POLY_R_X0_HI, POLY_R_X0_HI, POLY_TMP3; +#define POLY1305_BLOCK_PART21() \ + mul POLY_R_H2, POLY_R_H2, POLY_R_R0; /* h2 * r0 */ +#define POLY1305_BLOCK_PART22() \ + adds POLY_R_H1, POLY_R_H1, POLY_R_X1_LO; +#define POLY1305_BLOCK_PART23() \ + adc POLY_R_H0, POLY_R_H2, POLY_R_X1_HI; + +#define POLY1305_BLOCK_PART24() \ + /* carry propagation */ \ + and POLY_R_H2, POLY_R_H0, #3; +#define POLY1305_BLOCK_PART25() \ + lsr POLY_R_H0, POLY_R_H0, #2; +#define POLY1305_BLOCK_PART26() \ + add POLY_R_H0, POLY_R_H0, POLY_R_H0, lsl #2; +#define POLY1305_BLOCK_PART27() \ + adds POLY_R_H0, POLY_R_H0, POLY_R_X0_LO; +#define POLY1305_BLOCK_PART28() \ + adcs POLY_R_H1, POLY_R_H1, POLY_R_X0_HI; +#define POLY1305_BLOCK_PART29() \ + adc POLY_R_H2d, POLY_R_H2d, wzr; + +//#define TESTING_POLY1305_ASM +#ifdef TESTING_POLY1305_ASM +/* for testing only. */ +.align 3 +.globl _gcry_poly1305_aarch64_blocks1 +ELF(.type _gcry_poly1305_aarch64_blocks1,%function;) +_gcry_poly1305_aarch64_blocks1: + /* input: + * x0: poly1305-state + * x1: src + * x2: nblks + */ + CFI_STARTPROC() + POLY1305_PUSH_REGS(); + + mov POLY_RSTATE, x0; + mov POLY_RSRC, x1; + + POLY1305_LOAD_STATE(); + +.L_gcry_poly1305_aarch64_loop1: + POLY1305_BLOCK_PART1(0 * 16); + POLY1305_BLOCK_PART2(0 * 16); + add POLY_RSRC, POLY_RSRC, #16; + POLY1305_BLOCK_PART3(); + POLY1305_BLOCK_PART4(); + POLY1305_BLOCK_PART5(); + POLY1305_BLOCK_PART6(); + POLY1305_BLOCK_PART7(); + POLY1305_BLOCK_PART8(); + POLY1305_BLOCK_PART9(); + POLY1305_BLOCK_PART10(); + POLY1305_BLOCK_PART11(); + POLY1305_BLOCK_PART12(); + POLY1305_BLOCK_PART13(); + POLY1305_BLOCK_PART14(); + POLY1305_BLOCK_PART15(); + POLY1305_BLOCK_PART16(); + POLY1305_BLOCK_PART17(); + POLY1305_BLOCK_PART18(); + POLY1305_BLOCK_PART19(); + POLY1305_BLOCK_PART20(); + POLY1305_BLOCK_PART21(); + POLY1305_BLOCK_PART22(); + POLY1305_BLOCK_PART23(); + POLY1305_BLOCK_PART24(); + POLY1305_BLOCK_PART25(); + POLY1305_BLOCK_PART26(); + POLY1305_BLOCK_PART27(); + POLY1305_BLOCK_PART28(); + POLY1305_BLOCK_PART29(); + + subs x2, x2, #1; + b.ne .L_gcry_poly1305_aarch64_loop1; + + POLY1305_STORE_STATE(); + + mov x0, #0; + + POLY1305_POP_REGS(); + ret; + CFI_ENDPROC() +ELF(.size _gcry_poly1305_aarch64_blocks1, .-_gcry_poly1305_aarch64_blocks1;) +#endif + +#endif /* GCRY_ASM_POLY1305_AARCH64_H */ diff --git a/comm/third_party/libgcrypt/cipher/asm-poly1305-amd64.h b/comm/third_party/libgcrypt/cipher/asm-poly1305-amd64.h new file mode 100644 index 0000000000..3f99ea3e16 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-poly1305-amd64.h @@ -0,0 +1,171 @@ +/* asm-common-amd64.h - Poly1305 macros for AMD64 assembly + * + * Copyright (C) 2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_POLY1305_AMD64_H +#define GCRY_ASM_POLY1305_AMD64_H + +#include "asm-common-amd64.h" + +/********************************************************************** + poly1305 for stitched chacha20-poly1305 AMD64 implementations + **********************************************************************/ + +#define POLY_RSTATE %r8 +#define POLY_RSRC %r9 + +#define POLY_R_H0 %rbx +#define POLY_R_H1 %rcx +#define POLY_R_H2 %r10 +#define POLY_R_H2d %r10d +#define POLY_R_R0 %r11 +#define POLY_R_R1_MUL5 %r12 +#define POLY_R_X0_HI %r13 +#define POLY_R_X0_LO %r14 +#define POLY_R_X1_HI %r15 +#define POLY_R_X1_LO %rsi + +#define POLY_S_R0 (4 * 4 + 0 * 8)(POLY_RSTATE) +#define POLY_S_R1 (4 * 4 + 1 * 8)(POLY_RSTATE) +#define POLY_S_H0 (4 * 4 + 2 * 8 + 0 * 8)(POLY_RSTATE) +#define POLY_S_H1 (4 * 4 + 2 * 8 + 1 * 8)(POLY_RSTATE) +#define POLY_S_H2d (4 * 4 + 2 * 8 + 2 * 8)(POLY_RSTATE) + +#define POLY1305_LOAD_STATE() \ + movq POLY_S_H0, POLY_R_H0; \ + movq POLY_S_H1, POLY_R_H1; \ + movl POLY_S_H2d, POLY_R_H2d; \ + movq POLY_S_R0, POLY_R_R0; \ + movq POLY_S_R1, POLY_R_R1_MUL5; \ + shrq $2, POLY_R_R1_MUL5; \ + addq POLY_S_R1, POLY_R_R1_MUL5; + +#define POLY1305_STORE_STATE() \ + movq POLY_R_H0, POLY_S_H0; \ + movq POLY_R_H1, POLY_S_H1; \ + movl POLY_R_H2d, POLY_S_H2d; + +/* a = h + m */ +#define POLY1305_BLOCK_PART1(src_offset) \ + addq ((src_offset) + 0 * 8)(POLY_RSRC), POLY_R_H0; \ + adcq ((src_offset) + 1 * 8)(POLY_RSRC), POLY_R_H1; \ + adcl $1, POLY_R_H2d; \ + \ + /* h = a * r (partial mod 2^130-5): */ \ + \ + /* h0 * r1 */ \ + movq POLY_R_H0, %rax; \ + mulq POLY_S_R1; \ + movq %rax, POLY_R_X1_LO; \ + movq %rdx, POLY_R_X1_HI; + +#define POLY1305_BLOCK_PART2() \ + \ + /* h0 * r0 */ \ + movq POLY_R_H0, %rax; \ + mulq POLY_R_R0; \ + movq %rax, POLY_R_X0_LO; \ + movq %rdx, POLY_R_X0_HI; + +#define POLY1305_BLOCK_PART3() \ + \ + /* h1 * r0 */ \ + movq POLY_R_H1, %rax; \ + mulq POLY_R_R0; \ + addq %rax, POLY_R_X1_LO; \ + adcq %rdx, POLY_R_X1_HI; \ + \ + /* h1 * r1 mod 2^130-5 */ \ + movq POLY_R_R1_MUL5, %rax; \ + mulq POLY_R_H1; + +#define POLY1305_BLOCK_PART4() \ + movq POLY_R_H2, POLY_R_H1; \ + imulq POLY_R_R1_MUL5, POLY_R_H1; /* h2 * r1 mod 2^130-5 */ \ + addq %rax, POLY_R_X0_LO; \ + adcq %rdx, POLY_R_X0_HI; \ + imulq POLY_R_R0, POLY_R_H2; /* h2 * r0 */ \ + addq POLY_R_X1_LO, POLY_R_H1; \ + adcq POLY_R_X1_HI, POLY_R_H2; + +#define POLY1305_BLOCK_PART5() \ + \ + /* carry propagation */ \ + movq POLY_R_H2, POLY_R_H0; \ + andl $3, POLY_R_H2d; \ + shrq $2, POLY_R_H0; \ + leaq (POLY_R_H0, POLY_R_H0, 4), POLY_R_H0; \ + addq POLY_R_X0_LO, POLY_R_H0; \ + adcq POLY_R_X0_HI, POLY_R_H1; \ + adcl $0, POLY_R_H2d; + +#ifdef TESTING_POLY1305_ASM +/* for testing only, mixed C/asm poly1305.c is marginally faster (~2%). */ +.align 8 +.globl _gcry_poly1305_amd64_ssse3_blocks1 +ELF(.type _gcry_poly1305_amd64_ssse3_blocks1,@function;) + +_gcry_poly1305_amd64_ssse3_blocks1: + /* input: + * %rdi: poly1305-state + * %rsi: src + * %rdx: nblks + */ + pushq %rbp; + movq %rsp, %rbp; + + subq $(10 * 8), %rsp; + movq %rbx, (1 * 8)(%rsp); + movq %r12, (2 * 8)(%rsp); + movq %r13, (3 * 8)(%rsp); + movq %r14, (4 * 8)(%rsp); + movq %r15, (5 * 8)(%rsp); + + movq %rdx, (8 * 8)(%rsp); # NBLKS + + movq %rdi, POLY_RSTATE; + movq %rsi, POLY_RSRC; + + POLY1305_LOAD_STATE(); + +.L_poly1: + POLY1305_BLOCK_PART1(0 * 16); + POLY1305_BLOCK_PART2(); + POLY1305_BLOCK_PART3(); + POLY1305_BLOCK_PART4(); + POLY1305_BLOCK_PART5(); + + subq $1, (8 * 8)(%rsp); # NBLKS + leaq (16)(POLY_RSRC), POLY_RSRC; + jnz .L_poly1; + + POLY1305_STORE_STATE(); + + movq (1 * 8)(%rsp), %rbx; + movq (2 * 8)(%rsp), %r12; + movq (3 * 8)(%rsp), %r13; + movq (4 * 8)(%rsp), %r14; + movq (5 * 8)(%rsp), %r15; + + xorl %eax, %eax; + leave + ret; +#endif + +#endif /* GCRY_ASM_POLY1305_AMD64_H */ diff --git a/comm/third_party/libgcrypt/cipher/asm-poly1305-s390x.h b/comm/third_party/libgcrypt/cipher/asm-poly1305-s390x.h new file mode 100644 index 0000000000..113ab94913 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/asm-poly1305-s390x.h @@ -0,0 +1,140 @@ +/* asm-common-amd64.h - Poly1305 macros for zSeries assembly + * + * Copyright (C) 2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ASM_POLY1305_S390X_H +#define GCRY_ASM_POLY1305_S390X_H + +#include "asm-common-s390x.h" + +/********************************************************************** + poly1305 for stitched chacha20-poly1305 + **********************************************************************/ + +#define POLY_RSTATE %r1 +#define POLY_RSRC %r14 + +#define POLY_R_H0_TMP_HI %r6 // even- +#define POLY_R_H0 %r7 // odd pair +#define POLY_R_H1_TMP_HI %r8 // even- +#define POLY_R_H1 %r9 // odd pair +#define POLY_R_H2 %r10 +#define POLY_R_R0 %r11 +#define POLY_R_R1 %r12 +#define POLY_R_R1_MUL5 %r13 +#define POLY_R_X0_HI %r2 // even- +#define POLY_R_X0_LO %r3 // odd pair +#define POLY_R_X1_HI %r4 // even- +#define POLY_R_X1_LO %r5 // odd pair + +#define POLY_S_R0 (4 * 4 + 0 * 8)(POLY_RSTATE) +#define POLY_S_R1 (4 * 4 + 1 * 8)(POLY_RSTATE) +#define POLY_S_H0 (4 * 4 + 2 * 8 + 0 * 8)(POLY_RSTATE) +#define POLY_S_H1 (4 * 4 + 2 * 8 + 1 * 8)(POLY_RSTATE) +#define POLY_S_H2d (4 * 4 + 2 * 8 + 2 * 8)(POLY_RSTATE) + +#define INC_POLY1305_SRC(a) \ + aghi POLY_RSRC, (a); + +#define POLY1305_LOAD_STATE() \ + lg POLY_R_H0, POLY_S_H0; \ + lg POLY_R_H1, POLY_S_H1; \ + llgf POLY_R_H2, POLY_S_H2d; \ + rllg POLY_R_H0, POLY_R_H0, 32; \ + rllg POLY_R_H1, POLY_R_H1, 32; \ + lg POLY_R_R0, POLY_S_R0; \ + lg POLY_R_R1, POLY_S_R1; \ + rllg POLY_R_R0, POLY_R_R0, 32; \ + rllg POLY_R_R1, POLY_R_R1, 32; \ + srlg POLY_R_R1_MUL5, POLY_R_R1, 2; \ + algr POLY_R_R1_MUL5, POLY_R_R1; + +#define POLY1305_STORE_STATE() \ + rllg POLY_R_H0, POLY_R_H0, 32; \ + rllg POLY_R_H1, POLY_R_H1, 32; \ + stg POLY_R_H0, POLY_S_H0; \ + stg POLY_R_H1, POLY_S_H1; \ + st POLY_R_H2, POLY_S_H2d; + +/* a = h + m */ +#define POLY1305_BLOCK_PART1_HB(src_offset, high_pad) \ + lrvg POLY_R_X0_HI, ((src_offset) + 1 * 8)(POLY_RSRC); \ + lrvg POLY_R_X0_LO, ((src_offset) + 0 * 8)(POLY_RSRC); \ + lghi POLY_R_H1_TMP_HI, (high_pad); + +#define POLY1305_BLOCK_PART1(src_offset) \ + POLY1305_BLOCK_PART1_HB(src_offset, 1); + +#define POLY1305_BLOCK_PART2() \ + algr POLY_R_H0, POLY_R_X0_LO; \ + alcgr POLY_R_H1, POLY_R_X0_HI; \ + alcgr POLY_R_H2, POLY_R_H1_TMP_HI; \ + lgr POLY_R_X1_LO, POLY_R_H0; \ + lgr POLY_R_X0_LO, POLY_R_H0; + +#define POLY1305_BLOCK_PART3() \ + /* h = a * r (partial mod 2^130-5): */ \ + \ + /* h0 * r1 */ \ + mlgr POLY_R_X1_HI, POLY_R_R1; \ + \ + /* h1 * r0 */ \ + lgr POLY_R_H0, POLY_R_H1; \ + mlgr POLY_R_H0_TMP_HI, POLY_R_R0; \ + \ + /* h1 * r1 mod 2^130-5 */ \ + mlgr POLY_R_H1_TMP_HI, POLY_R_R1_MUL5; + +#define POLY1305_BLOCK_PART4() \ + \ + /* h0 * r0 */ \ + mlgr POLY_R_X0_HI, POLY_R_R0; \ + \ + algr POLY_R_X1_LO, POLY_R_H0; \ + alcgr POLY_R_X1_HI, POLY_R_H0_TMP_HI; \ + \ + lgr POLY_R_H0_TMP_HI, POLY_R_H2; \ + msgr POLY_R_H0_TMP_HI, POLY_R_R1_MUL5; /* h2 * r1 mod 2^130-5 */ \ + msgr POLY_R_H2, POLY_R_R0; /* h2 * r0 */ + +#define POLY1305_BLOCK_PART5() \ + \ + algr POLY_R_X0_LO, POLY_R_H1; \ + alcgr POLY_R_X0_HI, POLY_R_H1_TMP_HI; + +#define POLY1305_BLOCK_PART6() \ + \ + algrk POLY_R_H1, POLY_R_H0_TMP_HI, POLY_R_X1_LO; \ + alcgr POLY_R_H2, POLY_R_X1_HI; + +#define POLY1305_BLOCK_PART7() \ + \ + /* carry propagation */ \ + srlg POLY_R_H0, POLY_R_H2, 2; \ + risbgn POLY_R_X1_LO, POLY_R_H2, 0, 0x80 | 61, 0; \ + lghi POLY_R_H1_TMP_HI, 0; \ + agr POLY_R_H0, POLY_R_X1_LO; \ + risbgn POLY_R_H2, POLY_R_H2, 62, 0x80 | 63, 0; + +#define POLY1305_BLOCK_PART8() \ + algr POLY_R_H0, POLY_R_X0_LO; \ + alcgr POLY_R_H1, POLY_R_X0_HI; \ + alcgr POLY_R_H2, POLY_R_H1_TMP_HI; + +#endif /* GCRY_ASM_POLY1305_AMD64_H */ diff --git a/comm/third_party/libgcrypt/cipher/bithelp.h b/comm/third_party/libgcrypt/cipher/bithelp.h new file mode 100644 index 0000000000..7793ce7ca3 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/bithelp.h @@ -0,0 +1,123 @@ +/* bithelp.h - Some bit manipulation helpers + * Copyright (C) 1999, 2002 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ +#ifndef GCRYPT_BITHELP_H +#define GCRYPT_BITHELP_H + +#include "types.h" + + +/**************** + * Rotate the 32 bit unsigned integer X by N bits left/right + */ +static inline u32 rol(u32 x, int n) +{ + return ( (x << (n&(32-1))) | (x >> ((32-n)&(32-1))) ); +} + +static inline u32 ror(u32 x, int n) +{ + return ( (x >> (n&(32-1))) | (x << ((32-n)&(32-1))) ); +} + +static inline u64 rol64(u64 x, int n) +{ + return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) ); +} + +/* Byte swap for 32-bit and 64-bit integers. If available, use compiler + provided helpers. */ +#ifdef HAVE_BUILTIN_BSWAP32 +# define _gcry_bswap32 __builtin_bswap32 +#else +static inline u32 +_gcry_bswap32(u32 x) +{ + return ((rol(x, 8) & 0x00ff00ffL) | (ror(x, 8) & 0xff00ff00L)); +} +#endif + +#ifdef HAVE_BUILTIN_BSWAP64 +# define _gcry_bswap64 __builtin_bswap64 +#else +static inline u64 +_gcry_bswap64(u64 x) +{ + return ((u64)_gcry_bswap32(x) << 32) | (_gcry_bswap32(x >> 32)); +} +#endif + +/* Endian dependent byte swap operations. */ +#ifdef WORDS_BIGENDIAN +# define le_bswap32(x) _gcry_bswap32(x) +# define be_bswap32(x) ((u32)(x)) +# define le_bswap64(x) _gcry_bswap64(x) +# define be_bswap64(x) ((u64)(x)) +#else +# define le_bswap32(x) ((u32)(x)) +# define be_bswap32(x) _gcry_bswap32(x) +# define le_bswap64(x) ((u64)(x)) +# define be_bswap64(x) _gcry_bswap64(x) +#endif + + +/* Count trailing zero bits in an unsigend int. We return an int + because that is what gcc's builtin does. Returns the number of + bits in X if X is 0. */ +static inline int +_gcry_ctz (unsigned int x) +{ +#if defined (HAVE_BUILTIN_CTZ) + return x ? __builtin_ctz (x) : 8 * sizeof (x); +#else + /* See + * http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightModLookup + */ + static const unsigned char mod37[] = + { + sizeof (unsigned int)*8, + 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, + 4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, + 5, 20, 8, 19, 18 + }; + return (int)mod37[(-x & x) % 37]; +#endif +} + + +/* Count trailing zero bits in an u64. We return an int because that + is what gcc's builtin does. Returns the number of bits in X if X + is 0. */ +static inline int +_gcry_ctz64(u64 x) +{ +#if defined (HAVE_BUILTIN_CTZL) && SIZEOF_UNSIGNED_LONG >= 8 + return x ? __builtin_ctzl (x) : 8 * sizeof (x); +#elif defined (HAVE_BUILTIN_CTZ) && SIZEOF_UNSIGNED_INT >= 8 +#warning hello + return x ? __builtin_ctz (x) : 8 * sizeof (x); +#else + if ((x & 0xffffffff)) + return _gcry_ctz (x); + else + return 32 + _gcry_ctz (x >> 32); +#endif +} + + +#endif /*GCRYPT_BITHELP_H*/ diff --git a/comm/third_party/libgcrypt/cipher/blake2.c b/comm/third_party/libgcrypt/cipher/blake2.c new file mode 100644 index 0000000000..f2bf49e522 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/blake2.c @@ -0,0 +1,996 @@ +/* blake2.c - BLAKE2b and BLAKE2s hash functions (RFC 7693) + * Copyright (C) 2017 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* The code is based on public-domain/CC0 BLAKE2 reference implementation + * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/ref + * Copyright 2012, Samuel Neves + */ + +#include +#include +#include "g10lib.h" +#include "bithelp.h" +#include "bufhelp.h" +#include "cipher.h" +#include "hash-common.h" + +/* USE_AVX indicates whether to compile with Intel AVX code. */ +#undef USE_AVX +#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_AVX) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AVX 1 +#endif + +/* USE_AVX2 indicates whether to compile with Intel AVX2 code. */ +#undef USE_AVX2 +#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_AVX2) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AVX2 1 +#endif + +/* AMD64 assembly implementations use SystemV ABI, ABI conversion and additional + * stack to store XMM6-XMM15 needed on Win64. */ +#undef ASM_FUNC_ABI +#undef ASM_EXTRA_STACK +#if defined(USE_AVX2) && defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS) +# define ASM_FUNC_ABI __attribute__((sysv_abi)) +# define ASM_EXTRA_STACK (10 * 16) +#else +# define ASM_FUNC_ABI +# define ASM_EXTRA_STACK 0 +#endif + +#define BLAKE2B_BLOCKBYTES 128 +#define BLAKE2B_OUTBYTES 64 +#define BLAKE2B_KEYBYTES 64 + +#define BLAKE2S_BLOCKBYTES 64 +#define BLAKE2S_OUTBYTES 32 +#define BLAKE2S_KEYBYTES 32 + +typedef struct +{ + u64 h[8]; + u64 t[2]; + u64 f[2]; +} BLAKE2B_STATE; + +struct blake2b_param_s +{ + byte digest_length; + byte key_length; + byte fanout; + byte depth; + byte leaf_length[4]; + byte node_offset[4]; + byte xof_length[4]; + byte node_depth; + byte inner_length; + byte reserved[14]; + byte salt[16]; + byte personal[16]; +}; + +typedef struct BLAKE2B_CONTEXT_S +{ + BLAKE2B_STATE state; + byte buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; +#ifdef USE_AVX2 + unsigned int use_avx2:1; +#endif +} BLAKE2B_CONTEXT; + +typedef struct +{ + u32 h[8]; + u32 t[2]; + u32 f[2]; +} BLAKE2S_STATE; + +struct blake2s_param_s +{ + byte digest_length; + byte key_length; + byte fanout; + byte depth; + byte leaf_length[4]; + byte node_offset[4]; + byte xof_length[2]; + byte node_depth; + byte inner_length; + /* byte reserved[0]; */ + byte salt[8]; + byte personal[8]; +}; + +typedef struct BLAKE2S_CONTEXT_S +{ + BLAKE2S_STATE state; + byte buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; +#ifdef USE_AVX + unsigned int use_avx:1; +#endif +} BLAKE2S_CONTEXT; + +typedef unsigned int (*blake2_transform_t)(void *S, const void *inblk, + size_t nblks); + + +static const u64 blake2b_IV[8] = +{ + U64_C(0x6a09e667f3bcc908), U64_C(0xbb67ae8584caa73b), + U64_C(0x3c6ef372fe94f82b), U64_C(0xa54ff53a5f1d36f1), + U64_C(0x510e527fade682d1), U64_C(0x9b05688c2b3e6c1f), + U64_C(0x1f83d9abfb41bd6b), U64_C(0x5be0cd19137e2179) +}; + +static const u32 blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static byte zero_block[BLAKE2B_BLOCKBYTES] = { 0, }; + + +static void blake2_write(void *S, const void *inbuf, size_t inlen, + byte *tmpbuf, size_t *tmpbuflen, size_t blkbytes, + blake2_transform_t transform_fn) +{ + const byte* in = inbuf; + unsigned int burn = 0; + + if (inlen > 0) + { + size_t left = *tmpbuflen; + size_t fill = blkbytes - left; + size_t nblks; + + if (inlen > fill) + { + if (fill > 0) + buf_cpy (tmpbuf + left, in, fill); /* Fill buffer */ + left = 0; + + burn = transform_fn (S, tmpbuf, 1); /* Increment counter + Compress */ + + in += fill; + inlen -= fill; + + nblks = inlen / blkbytes - !(inlen % blkbytes); + if (nblks) + { + burn = transform_fn(S, in, nblks); + in += blkbytes * nblks; + inlen -= blkbytes * nblks; + } + } + + gcry_assert (inlen > 0); + + buf_cpy (tmpbuf + left, in, inlen); + *tmpbuflen = left + inlen; + } + + if (burn) + _gcry_burn_stack (burn); + + return; +} + + +static inline void blake2b_set_lastblock(BLAKE2B_STATE *S) +{ + S->f[0] = U64_C(0xffffffffffffffff); +} + +static inline int blake2b_is_lastblock(const BLAKE2B_STATE *S) +{ + return S->f[0] != 0; +} + +static inline void blake2b_increment_counter(BLAKE2B_STATE *S, const int inc) +{ + S->t[0] += (u64)inc; + S->t[1] += (S->t[0] < (u64)inc) - (inc < 0); +} + +static inline u64 rotr64(u64 x, u64 n) +{ + return ((x >> (n & 63)) | (x << ((64 - n) & 63))); +} + +static unsigned int blake2b_transform_generic(BLAKE2B_STATE *S, + const void *inblks, + size_t nblks) +{ + static const byte blake2b_sigma[12][16] = + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } + }; + const byte* in = inblks; + u64 m[16]; + u64 v[16]; + + while (nblks--) + { + /* Increment counter */ + blake2b_increment_counter (S, BLAKE2B_BLOCKBYTES); + + /* Compress */ + m[0] = buf_get_le64 (in + 0 * sizeof(m[0])); + m[1] = buf_get_le64 (in + 1 * sizeof(m[0])); + m[2] = buf_get_le64 (in + 2 * sizeof(m[0])); + m[3] = buf_get_le64 (in + 3 * sizeof(m[0])); + m[4] = buf_get_le64 (in + 4 * sizeof(m[0])); + m[5] = buf_get_le64 (in + 5 * sizeof(m[0])); + m[6] = buf_get_le64 (in + 6 * sizeof(m[0])); + m[7] = buf_get_le64 (in + 7 * sizeof(m[0])); + m[8] = buf_get_le64 (in + 8 * sizeof(m[0])); + m[9] = buf_get_le64 (in + 9 * sizeof(m[0])); + m[10] = buf_get_le64 (in + 10 * sizeof(m[0])); + m[11] = buf_get_le64 (in + 11 * sizeof(m[0])); + m[12] = buf_get_le64 (in + 12 * sizeof(m[0])); + m[13] = buf_get_le64 (in + 13 * sizeof(m[0])); + m[14] = buf_get_le64 (in + 14 * sizeof(m[0])); + m[15] = buf_get_le64 (in + 15 * sizeof(m[0])); + + v[ 0] = S->h[0]; + v[ 1] = S->h[1]; + v[ 2] = S->h[2]; + v[ 3] = S->h[3]; + v[ 4] = S->h[4]; + v[ 5] = S->h[5]; + v[ 6] = S->h[6]; + v[ 7] = S->h[7]; + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + +#undef G +#undef ROUND + + S->h[0] = S->h[0] ^ v[0] ^ v[0 + 8]; + S->h[1] = S->h[1] ^ v[1] ^ v[1 + 8]; + S->h[2] = S->h[2] ^ v[2] ^ v[2 + 8]; + S->h[3] = S->h[3] ^ v[3] ^ v[3 + 8]; + S->h[4] = S->h[4] ^ v[4] ^ v[4 + 8]; + S->h[5] = S->h[5] ^ v[5] ^ v[5 + 8]; + S->h[6] = S->h[6] ^ v[6] ^ v[6 + 8]; + S->h[7] = S->h[7] ^ v[7] ^ v[7 + 8]; + + in += BLAKE2B_BLOCKBYTES; + } + + return sizeof(void *) * 4 + sizeof(u64) * 16 * 2; +} + +#ifdef USE_AVX2 +unsigned int _gcry_blake2b_transform_amd64_avx2(BLAKE2B_STATE *S, + const void *inblks, + size_t nblks) ASM_FUNC_ABI; +#endif + +static unsigned int blake2b_transform(void *ctx, const void *inblks, + size_t nblks) +{ + BLAKE2B_CONTEXT *c = ctx; + unsigned int nburn; + + if (0) + {} +#ifdef USE_AVX2 + if (c->use_avx2) + nburn = _gcry_blake2b_transform_amd64_avx2(&c->state, inblks, nblks); +#endif + else + nburn = blake2b_transform_generic(&c->state, inblks, nblks); + + if (nburn) + nburn += ASM_EXTRA_STACK; + + return nburn; +} + +static void blake2b_final(void *ctx) +{ + BLAKE2B_CONTEXT *c = ctx; + BLAKE2B_STATE *S = &c->state; + unsigned int burn; + size_t i; + + gcry_assert (sizeof(c->buf) >= c->outlen); + if (blake2b_is_lastblock(S)) + return; + + if (c->buflen < BLAKE2B_BLOCKBYTES) + memset (c->buf + c->buflen, 0, BLAKE2B_BLOCKBYTES - c->buflen); /* Padding */ + blake2b_set_lastblock (S); + blake2b_increment_counter (S, (int)c->buflen - BLAKE2B_BLOCKBYTES); + burn = blake2b_transform (ctx, c->buf, 1); + + /* Output full hash to buffer */ + for (i = 0; i < 8; ++i) + buf_put_le64 (c->buf + sizeof(S->h[i]) * i, S->h[i]); + + /* Zero out extra buffer bytes. */ + if (c->outlen < sizeof(c->buf)) + memset (c->buf + c->outlen, 0, sizeof(c->buf) - c->outlen); + + if (burn) + _gcry_burn_stack (burn); +} + +static byte *blake2b_read(void *ctx) +{ + BLAKE2B_CONTEXT *c = ctx; + return c->buf; +} + +static void blake2b_write(void *ctx, const void *inbuf, size_t inlen) +{ + BLAKE2B_CONTEXT *c = ctx; + BLAKE2B_STATE *S = &c->state; + blake2_write(S, inbuf, inlen, c->buf, &c->buflen, BLAKE2B_BLOCKBYTES, + blake2b_transform); +} + +static inline void blake2b_init_param(BLAKE2B_STATE *S, + const struct blake2b_param_s *P) +{ + const byte *p = (const byte *)P; + size_t i; + + /* init xors IV with input parameter block */ + + /* IV XOR ParamBlock */ + for (i = 0; i < 8; ++i) + S->h[i] = blake2b_IV[i] ^ buf_get_le64(p + sizeof(S->h[i]) * i); +} + +static inline gcry_err_code_t blake2b_init(BLAKE2B_CONTEXT *ctx, + const byte *key, size_t keylen) +{ + struct blake2b_param_s P[1] = { { 0, } }; + BLAKE2B_STATE *S = &ctx->state; + + if (!ctx->outlen || ctx->outlen > BLAKE2B_OUTBYTES) + return GPG_ERR_INV_ARG; + if (sizeof(P[0]) != sizeof(u64) * 8) + return GPG_ERR_INTERNAL; + if (keylen && (!key || keylen > BLAKE2B_KEYBYTES)) + return GPG_ERR_INV_KEYLEN; + + P->digest_length = ctx->outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + + blake2b_init_param (S, P); + wipememory (P, sizeof(P)); + + if (key) + { + blake2b_write (ctx, key, keylen); + blake2b_write (ctx, zero_block, BLAKE2B_BLOCKBYTES - keylen); + } + + return 0; +} + +static gcry_err_code_t blake2b_init_ctx(void *ctx, unsigned int flags, + const byte *key, size_t keylen, + unsigned int dbits) +{ + BLAKE2B_CONTEXT *c = ctx; + unsigned int features = _gcry_get_hw_features (); + + (void)features; + (void)flags; + + memset (c, 0, sizeof (*c)); + +#ifdef USE_AVX2 + c->use_avx2 = !!(features & HWF_INTEL_AVX2); +#endif + + c->outlen = dbits / 8; + c->buflen = 0; + return blake2b_init(c, key, keylen); +} + +static inline void blake2s_set_lastblock(BLAKE2S_STATE *S) +{ + S->f[0] = 0xFFFFFFFFUL; +} + +static inline int blake2s_is_lastblock(BLAKE2S_STATE *S) +{ + return S->f[0] != 0; +} + +static inline void blake2s_increment_counter(BLAKE2S_STATE *S, const int inc) +{ + S->t[0] += (u32)inc; + S->t[1] += (S->t[0] < (u32)inc) - (inc < 0); +} + +static unsigned int blake2s_transform_generic(BLAKE2S_STATE *S, + const void *inblks, + size_t nblks) +{ + static const byte blake2s_sigma[10][16] = + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 }, + }; + unsigned int burn = 0; + const byte* in = inblks; + u32 m[16]; + u32 v[16]; + + while (nblks--) + { + /* Increment counter */ + blake2s_increment_counter (S, BLAKE2S_BLOCKBYTES); + + /* Compress */ + m[0] = buf_get_le32 (in + 0 * sizeof(m[0])); + m[1] = buf_get_le32 (in + 1 * sizeof(m[0])); + m[2] = buf_get_le32 (in + 2 * sizeof(m[0])); + m[3] = buf_get_le32 (in + 3 * sizeof(m[0])); + m[4] = buf_get_le32 (in + 4 * sizeof(m[0])); + m[5] = buf_get_le32 (in + 5 * sizeof(m[0])); + m[6] = buf_get_le32 (in + 6 * sizeof(m[0])); + m[7] = buf_get_le32 (in + 7 * sizeof(m[0])); + m[8] = buf_get_le32 (in + 8 * sizeof(m[0])); + m[9] = buf_get_le32 (in + 9 * sizeof(m[0])); + m[10] = buf_get_le32 (in + 10 * sizeof(m[0])); + m[11] = buf_get_le32 (in + 11 * sizeof(m[0])); + m[12] = buf_get_le32 (in + 12 * sizeof(m[0])); + m[13] = buf_get_le32 (in + 13 * sizeof(m[0])); + m[14] = buf_get_le32 (in + 14 * sizeof(m[0])); + m[15] = buf_get_le32 (in + 15 * sizeof(m[0])); + + v[ 0] = S->h[0]; + v[ 1] = S->h[1]; + v[ 2] = S->h[2]; + v[ 3] = S->h[3]; + v[ 4] = S->h[4]; + v[ 5] = S->h[5]; + v[ 6] = S->h[6]; + v[ 7] = S->h[7]; + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = ror(d ^ a, 16); \ + c = c + d; \ + b = ror(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = ror(d ^ a, 8); \ + c = c + d; \ + b = ror(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + +#undef G +#undef ROUND + + S->h[0] = S->h[0] ^ v[0] ^ v[0 + 8]; + S->h[1] = S->h[1] ^ v[1] ^ v[1 + 8]; + S->h[2] = S->h[2] ^ v[2] ^ v[2 + 8]; + S->h[3] = S->h[3] ^ v[3] ^ v[3 + 8]; + S->h[4] = S->h[4] ^ v[4] ^ v[4 + 8]; + S->h[5] = S->h[5] ^ v[5] ^ v[5 + 8]; + S->h[6] = S->h[6] ^ v[6] ^ v[6 + 8]; + S->h[7] = S->h[7] ^ v[7] ^ v[7 + 8]; + + in += BLAKE2S_BLOCKBYTES; + } + + return burn; +} + +#ifdef USE_AVX +unsigned int _gcry_blake2s_transform_amd64_avx(BLAKE2S_STATE *S, + const void *inblks, + size_t nblks) ASM_FUNC_ABI; +#endif + +static unsigned int blake2s_transform(void *ctx, const void *inblks, + size_t nblks) +{ + BLAKE2S_CONTEXT *c = ctx; + unsigned int nburn; + + if (0) + {} +#ifdef USE_AVX + if (c->use_avx) + nburn = _gcry_blake2s_transform_amd64_avx(&c->state, inblks, nblks); +#endif + else + nburn = blake2s_transform_generic(&c->state, inblks, nblks); + + if (nburn) + nburn += ASM_EXTRA_STACK; + + return nburn; +} + +static void blake2s_final(void *ctx) +{ + BLAKE2S_CONTEXT *c = ctx; + BLAKE2S_STATE *S = &c->state; + unsigned int burn; + size_t i; + + gcry_assert (sizeof(c->buf) >= c->outlen); + if (blake2s_is_lastblock(S)) + return; + + if (c->buflen < BLAKE2S_BLOCKBYTES) + memset (c->buf + c->buflen, 0, BLAKE2S_BLOCKBYTES - c->buflen); /* Padding */ + blake2s_set_lastblock (S); + blake2s_increment_counter (S, (int)c->buflen - BLAKE2S_BLOCKBYTES); + burn = blake2s_transform (ctx, c->buf, 1); + + /* Output full hash to buffer */ + for (i = 0; i < 8; ++i) + buf_put_le32 (c->buf + sizeof(S->h[i]) * i, S->h[i]); + + /* Zero out extra buffer bytes. */ + if (c->outlen < sizeof(c->buf)) + memset (c->buf + c->outlen, 0, sizeof(c->buf) - c->outlen); + + if (burn) + _gcry_burn_stack (burn); +} + +static byte *blake2s_read(void *ctx) +{ + BLAKE2S_CONTEXT *c = ctx; + return c->buf; +} + +static void blake2s_write(void *ctx, const void *inbuf, size_t inlen) +{ + BLAKE2S_CONTEXT *c = ctx; + BLAKE2S_STATE *S = &c->state; + blake2_write(S, inbuf, inlen, c->buf, &c->buflen, BLAKE2S_BLOCKBYTES, + blake2s_transform); +} + +static inline void blake2s_init_param(BLAKE2S_STATE *S, + const struct blake2s_param_s *P) +{ + const byte *p = (const byte *)P; + size_t i; + + /* init2 xors IV with input parameter block */ + + /* IV XOR ParamBlock */ + for (i = 0; i < 8; ++i) + S->h[i] ^= blake2s_IV[i] ^ buf_get_le32(&p[i * 4]); +} + +static inline gcry_err_code_t blake2s_init(BLAKE2S_CONTEXT *ctx, + const byte *key, size_t keylen) +{ + struct blake2s_param_s P[1] = { { 0, } }; + BLAKE2S_STATE *S = &ctx->state; + + if (!ctx->outlen || ctx->outlen > BLAKE2S_OUTBYTES) + return GPG_ERR_INV_ARG; + if (sizeof(P[0]) != sizeof(u32) * 8) + return GPG_ERR_INTERNAL; + if (keylen && (!key || keylen > BLAKE2S_KEYBYTES)) + return GPG_ERR_INV_KEYLEN; + + P->digest_length = ctx->outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + + blake2s_init_param (S, P); + wipememory (P, sizeof(P)); + + if (key) + { + blake2s_write (ctx, key, keylen); + blake2s_write (ctx, zero_block, BLAKE2S_BLOCKBYTES - keylen); + } + + return 0; +} + +static gcry_err_code_t blake2s_init_ctx(void *ctx, unsigned int flags, + const byte *key, size_t keylen, + unsigned int dbits) +{ + BLAKE2S_CONTEXT *c = ctx; + unsigned int features = _gcry_get_hw_features (); + + (void)features; + (void)flags; + + memset (c, 0, sizeof (*c)); + +#ifdef USE_AVX + c->use_avx = !!(features & HWF_INTEL_AVX); +#endif + + c->outlen = dbits / 8; + c->buflen = 0; + return blake2s_init(c, key, keylen); +} + +/* Selftests from "RFC 7693, Appendix E. BLAKE2b and BLAKE2s Self-Test + * Module C Source". */ +static void selftest_seq(byte *out, size_t len, u32 seed) +{ + size_t i; + u32 t, a, b; + + a = 0xDEAD4BAD * seed; + b = 1; + + for (i = 0; i < len; i++) + { + t = a + b; + a = b; + b = t; + out[i] = (t >> 24) & 0xFF; + } +} + +static gpg_err_code_t +selftests_blake2b (int algo, int extended, selftest_report_func_t report) +{ + static const byte blake2b_res[32] = + { + 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD, + 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56, + 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73, + 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75 + }; + static const size_t b2b_md_len[4] = { 20, 32, 48, 64 }; + static const size_t b2b_in_len[6] = { 0, 3, 128, 129, 255, 1024 }; + size_t i, j, outlen, inlen; + byte in[1024], key[64]; + BLAKE2B_CONTEXT ctx; + BLAKE2B_CONTEXT ctx2; + const char *what; + const char *errtxt; + + (void)extended; + + what = "rfc7693 BLAKE2b selftest"; + + /* 256-bit hash for testing */ + if (blake2b_init_ctx(&ctx, 0, NULL, 0, 32 * 8)) + { + errtxt = "init failed"; + goto failed; + } + + for (i = 0; i < 4; i++) + { + outlen = b2b_md_len[i]; + for (j = 0; j < 6; j++) + { + inlen = b2b_in_len[j]; + + selftest_seq(in, inlen, inlen); /* unkeyed hash */ + blake2b_init_ctx(&ctx2, 0, NULL, 0, outlen * 8); + blake2b_write(&ctx2, in, inlen); + blake2b_final(&ctx2); + blake2b_write(&ctx, ctx2.buf, outlen); /* hash the hash */ + + selftest_seq(key, outlen, outlen); /* keyed hash */ + blake2b_init_ctx(&ctx2, 0, key, outlen, outlen * 8); + blake2b_write(&ctx2, in, inlen); + blake2b_final(&ctx2); + blake2b_write(&ctx, ctx2.buf, outlen); /* hash the hash */ + } + } + + /* compute and compare the hash of hashes */ + blake2b_final(&ctx); + for (i = 0; i < 32; i++) + { + if (ctx.buf[i] != blake2b_res[i]) + { + errtxt = "digest mismatch"; + goto failed; + } + } + + return 0; + +failed: + if (report) + report ("digest", algo, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + +static gpg_err_code_t +selftests_blake2s (int algo, int extended, selftest_report_func_t report) +{ + static const byte blake2s_res[32] = + { + 0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD, + 0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC, + 0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87, + 0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE + }; + static const size_t b2s_md_len[4] = { 16, 20, 28, 32 }; + static const size_t b2s_in_len[6] = { 0, 3, 64, 65, 255, 1024 }; + size_t i, j, outlen, inlen; + byte in[1024], key[32]; + BLAKE2S_CONTEXT ctx; + BLAKE2S_CONTEXT ctx2; + const char *what; + const char *errtxt; + + (void)extended; + + what = "rfc7693 BLAKE2s selftest"; + + /* 256-bit hash for testing */ + if (blake2s_init_ctx(&ctx, 0, NULL, 0, 32 * 8)) + { + errtxt = "init failed"; + goto failed; + } + + for (i = 0; i < 4; i++) + { + outlen = b2s_md_len[i]; + for (j = 0; j < 6; j++) + { + inlen = b2s_in_len[j]; + + selftest_seq(in, inlen, inlen); /* unkeyed hash */ + blake2s_init_ctx(&ctx2, 0, NULL, 0, outlen * 8); + blake2s_write(&ctx2, in, inlen); + blake2s_final(&ctx2); + blake2s_write(&ctx, ctx2.buf, outlen); /* hash the hash */ + + selftest_seq(key, outlen, outlen); /* keyed hash */ + blake2s_init_ctx(&ctx2, 0, key, outlen, outlen * 8); + blake2s_write(&ctx2, in, inlen); + blake2s_final(&ctx2); + blake2s_write(&ctx, ctx2.buf, outlen); /* hash the hash */ + } + } + + /* compute and compare the hash of hashes */ + blake2s_final(&ctx); + for (i = 0; i < 32; i++) + { + if (ctx.buf[i] != blake2s_res[i]) + { + errtxt = "digest mismatch"; + goto failed; + } + } + + return 0; + +failed: + if (report) + report ("digest", algo, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +gcry_err_code_t _gcry_blake2_init_with_key(void *ctx, unsigned int flags, + const unsigned char *key, + size_t keylen, int algo) +{ + gcry_err_code_t rc; + switch (algo) + { + case GCRY_MD_BLAKE2B_512: + rc = blake2b_init_ctx (ctx, flags, key, keylen, 512); + break; + case GCRY_MD_BLAKE2B_384: + rc = blake2b_init_ctx (ctx, flags, key, keylen, 384); + break; + case GCRY_MD_BLAKE2B_256: + rc = blake2b_init_ctx (ctx, flags, key, keylen, 256); + break; + case GCRY_MD_BLAKE2B_160: + rc = blake2b_init_ctx (ctx, flags, key, keylen, 160); + break; + case GCRY_MD_BLAKE2S_256: + rc = blake2s_init_ctx (ctx, flags, key, keylen, 256); + break; + case GCRY_MD_BLAKE2S_224: + rc = blake2s_init_ctx (ctx, flags, key, keylen, 224); + break; + case GCRY_MD_BLAKE2S_160: + rc = blake2s_init_ctx (ctx, flags, key, keylen, 160); + break; + case GCRY_MD_BLAKE2S_128: + rc = blake2s_init_ctx (ctx, flags, key, keylen, 128); + break; + default: + rc = GPG_ERR_DIGEST_ALGO; + break; + } + + return rc; +} + + +#define DEFINE_BLAKE2_VARIANT(bs, BS, dbits, oid_branch) \ + static void blake2##bs##_##dbits##_init(void *ctx, unsigned int flags) \ + { \ + int err = blake2##bs##_init_ctx (ctx, flags, NULL, 0, dbits); \ + gcry_assert (err == 0); \ + } \ + static void \ + _gcry_blake2##bs##_##dbits##_hash_buffer(void *outbuf, \ + const void *buffer, size_t length) \ + { \ + BLAKE2##BS##_CONTEXT hd; \ + blake2##bs##_##dbits##_init (&hd, 0); \ + blake2##bs##_write (&hd, buffer, length); \ + blake2##bs##_final (&hd); \ + memcpy (outbuf, blake2##bs##_read (&hd), dbits / 8); \ + } \ + static void \ + _gcry_blake2##bs##_##dbits##_hash_buffers(void *outbuf, \ + const gcry_buffer_t *iov, int iovcnt) \ + { \ + BLAKE2##BS##_CONTEXT hd; \ + blake2##bs##_##dbits##_init (&hd, 0); \ + for (;iovcnt > 0; iov++, iovcnt--) \ + blake2##bs##_write (&hd, (const char*)iov[0].data + iov[0].off, \ + iov[0].len); \ + blake2##bs##_final (&hd); \ + memcpy (outbuf, blake2##bs##_read (&hd), dbits / 8); \ + } \ + static byte blake2##bs##_##dbits##_asn[] = { 0x30 }; \ + static gcry_md_oid_spec_t oid_spec_blake2##bs##_##dbits[] = \ + { \ + { " 1.3.6.1.4.1.1722.12.2." oid_branch }, \ + { NULL } \ + }; \ + gcry_md_spec_t _gcry_digest_spec_blake2##bs##_##dbits = \ + { \ + GCRY_MD_BLAKE2##BS##_##dbits, {0, 0}, \ + "BLAKE2" #BS "_" #dbits, blake2##bs##_##dbits##_asn, \ + DIM (blake2##bs##_##dbits##_asn), oid_spec_blake2##bs##_##dbits, \ + dbits / 8, blake2##bs##_##dbits##_init, blake2##bs##_write, \ + blake2##bs##_final, blake2##bs##_read, NULL, \ + _gcry_blake2##bs##_##dbits##_hash_buffer, \ + _gcry_blake2##bs##_##dbits##_hash_buffers, \ + sizeof (BLAKE2##BS##_CONTEXT), selftests_blake2##bs \ + }; + +DEFINE_BLAKE2_VARIANT(b, B, 512, "1.16") +DEFINE_BLAKE2_VARIANT(b, B, 384, "1.12") +DEFINE_BLAKE2_VARIANT(b, B, 256, "1.8") +DEFINE_BLAKE2_VARIANT(b, B, 160, "1.5") + +DEFINE_BLAKE2_VARIANT(s, S, 256, "2.8") +DEFINE_BLAKE2_VARIANT(s, S, 224, "2.7") +DEFINE_BLAKE2_VARIANT(s, S, 160, "2.5") +DEFINE_BLAKE2_VARIANT(s, S, 128, "2.4") diff --git a/comm/third_party/libgcrypt/cipher/blake2b-amd64-avx2.S b/comm/third_party/libgcrypt/cipher/blake2b-amd64-avx2.S new file mode 100644 index 0000000000..357e8a5167 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/blake2b-amd64-avx2.S @@ -0,0 +1,300 @@ +/* blake2b-amd64-avx2.S - AVX2 implementation of BLAKE2b + * + * Copyright (C) 2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* The code is based on public-domain/CC0 BLAKE2 reference implementation + * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/sse + * Copyright 2012, Samuel Neves + */ + +#ifdef __x86_64 +#include +#if defined(HAVE_GCC_INLINE_ASM_AVX2) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +#include "asm-common-amd64.h" + +.text + +/* register macros */ +#define RSTATE %rdi +#define RINBLKS %rsi +#define RNBLKS %rdx +#define RIV %rcx + +/* state structure */ +#define STATE_H 0 +#define STATE_T (STATE_H + 8 * 8) +#define STATE_F (STATE_T + 2 * 8) + +/* vector registers */ +#define ROW1 %ymm0 +#define ROW2 %ymm1 +#define ROW3 %ymm2 +#define ROW4 %ymm3 +#define TMP1 %ymm4 +#define TMP1x %xmm4 +#define R16 %ymm5 +#define R24 %ymm6 + +#define MA1 %ymm8 +#define MA2 %ymm9 +#define MA3 %ymm10 +#define MA4 %ymm11 +#define MA1x %xmm8 +#define MA2x %xmm9 +#define MA3x %xmm10 +#define MA4x %xmm11 + +#define MB1 %ymm12 +#define MB2 %ymm13 +#define MB3 %ymm14 +#define MB4 %ymm15 +#define MB1x %xmm12 +#define MB2x %xmm13 +#define MB3x %xmm14 +#define MB4x %xmm15 + +/********************************************************************** + blake2b/AVX2 + **********************************************************************/ + +#define GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + s0, s1, s2, s3, s4, s5, s6, s7, s8, \ + s9, s10, s11, s12, s13, s14, s15) \ + vmovq (s0)*8(RINBLKS), m1x; \ + vmovq (s4)*8(RINBLKS), TMP1x; \ + vpinsrq $1, (s2)*8(RINBLKS), m1x, m1x; \ + vpinsrq $1, (s6)*8(RINBLKS), TMP1x, TMP1x; \ + vinserti128 $1, TMP1x, m1, m1; \ + vmovq (s1)*8(RINBLKS), m2x; \ + vmovq (s5)*8(RINBLKS), TMP1x; \ + vpinsrq $1, (s3)*8(RINBLKS), m2x, m2x; \ + vpinsrq $1, (s7)*8(RINBLKS), TMP1x, TMP1x; \ + vinserti128 $1, TMP1x, m2, m2; \ + vmovq (s8)*8(RINBLKS), m3x; \ + vmovq (s12)*8(RINBLKS), TMP1x; \ + vpinsrq $1, (s10)*8(RINBLKS), m3x, m3x; \ + vpinsrq $1, (s14)*8(RINBLKS), TMP1x, TMP1x; \ + vinserti128 $1, TMP1x, m3, m3; \ + vmovq (s9)*8(RINBLKS), m4x; \ + vmovq (s13)*8(RINBLKS), TMP1x; \ + vpinsrq $1, (s11)*8(RINBLKS), m4x, m4x; \ + vpinsrq $1, (s15)*8(RINBLKS), TMP1x, TMP1x; \ + vinserti128 $1, TMP1x, m4, m4; + +#define LOAD_MSG_0(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) +#define LOAD_MSG_1(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3) +#define LOAD_MSG_2(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4) +#define LOAD_MSG_3(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8) +#define LOAD_MSG_4(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13) +#define LOAD_MSG_5(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9) +#define LOAD_MSG_6(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11) +#define LOAD_MSG_7(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10) +#define LOAD_MSG_8(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5) +#define LOAD_MSG_9(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + GATHER_MSG(m1, m2, m3, m4, m1x, m2x, m3x, m4x, \ + 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0) +#define LOAD_MSG_10(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + LOAD_MSG_0(m1, m2, m3, m4, m1x, m2x, m3x, m4x) +#define LOAD_MSG_11(m1, m2, m3, m4, m1x, m2x, m3x, m4x) \ + LOAD_MSG_1(m1, m2, m3, m4, m1x, m2x, m3x, m4x) + +#define LOAD_MSG(r, m1, m2, m3, m4) \ + LOAD_MSG_##r(m1, m2, m3, m4, m1##x, m2##x, m3##x, m4##x) + +#define ROR_32(in, out) vpshufd $0xb1, in, out; + +#define ROR_24(in, out) vpshufb R24, in, out; + +#define ROR_16(in, out) vpshufb R16, in, out; + +#define ROR_63(in, out) \ + vpsrlq $63, in, TMP1; \ + vpaddq in, in, out; \ + vpxor TMP1, out, out; + +#define G(r1, r2, r3, r4, m, ROR_A, ROR_B) \ + vpaddq m, r1, r1; \ + vpaddq r2, r1, r1; \ + vpxor r1, r4, r4; \ + ROR_A(r4, r4); \ + vpaddq r4, r3, r3; \ + vpxor r3, r2, r2; \ + ROR_B(r2, r2); + +#define G1(r1, r2, r3, r4, m) \ + G(r1, r2, r3, r4, m, ROR_32, ROR_24); + +#define G2(r1, r2, r3, r4, m) \ + G(r1, r2, r3, r4, m, ROR_16, ROR_63); + +#define MM_SHUFFLE(z,y,x,w) \ + (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) + +#define DIAGONALIZE(r1, r2, r3, r4) \ + vpermq $MM_SHUFFLE(0,3,2,1), r2, r2; \ + vpermq $MM_SHUFFLE(1,0,3,2), r3, r3; \ + vpermq $MM_SHUFFLE(2,1,0,3), r4, r4; + +#define UNDIAGONALIZE(r1, r2, r3, r4) \ + vpermq $MM_SHUFFLE(2,1,0,3), r2, r2; \ + vpermq $MM_SHUFFLE(1,0,3,2), r3, r3; \ + vpermq $MM_SHUFFLE(0,3,2,1), r4, r4; + +#define ROUND(r, m1, m2, m3, m4) \ + G1(ROW1, ROW2, ROW3, ROW4, m1); \ + G2(ROW1, ROW2, ROW3, ROW4, m2); \ + DIAGONALIZE(ROW1, ROW2, ROW3, ROW4); \ + G1(ROW1, ROW2, ROW3, ROW4, m3); \ + G2(ROW1, ROW2, ROW3, ROW4, m4); \ + UNDIAGONALIZE(ROW1, ROW2, ROW3, ROW4); + +blake2b_data: +.align 32 +.Liv: + .quad 0x6a09e667f3bcc908, 0xbb67ae8584caa73b + .quad 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1 + .quad 0x510e527fade682d1, 0x9b05688c2b3e6c1f + .quad 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 +.Lshuf_ror16: + .byte 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9 +.Lshuf_ror24: + .byte 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10 + +.align 64 +.globl _gcry_blake2b_transform_amd64_avx2 +ELF(.type _gcry_blake2b_transform_amd64_avx2,@function;) + +_gcry_blake2b_transform_amd64_avx2: + /* input: + * %rdi: state + * %rsi: blks + * %rdx: num_blks + */ + CFI_STARTPROC(); + + vzeroupper; + + addq $128, (STATE_T + 0)(RSTATE); + adcq $0, (STATE_T + 8)(RSTATE); + + vbroadcasti128 .Lshuf_ror16 rRIP, R16; + vbroadcasti128 .Lshuf_ror24 rRIP, R24; + + vmovdqa .Liv+(0 * 8) rRIP, ROW3; + vmovdqa .Liv+(4 * 8) rRIP, ROW4; + + vmovdqu (STATE_H + 0 * 8)(RSTATE), ROW1; + vmovdqu (STATE_H + 4 * 8)(RSTATE), ROW2; + + vpxor (STATE_T)(RSTATE), ROW4, ROW4; + + LOAD_MSG(0, MA1, MA2, MA3, MA4); + LOAD_MSG(1, MB1, MB2, MB3, MB4); + +.Loop: + ROUND(0, MA1, MA2, MA3, MA4); + LOAD_MSG(2, MA1, MA2, MA3, MA4); + ROUND(1, MB1, MB2, MB3, MB4); + LOAD_MSG(3, MB1, MB2, MB3, MB4); + ROUND(2, MA1, MA2, MA3, MA4); + LOAD_MSG(4, MA1, MA2, MA3, MA4); + ROUND(3, MB1, MB2, MB3, MB4); + LOAD_MSG(5, MB1, MB2, MB3, MB4); + ROUND(4, MA1, MA2, MA3, MA4); + LOAD_MSG(6, MA1, MA2, MA3, MA4); + ROUND(5, MB1, MB2, MB3, MB4); + LOAD_MSG(7, MB1, MB2, MB3, MB4); + ROUND(6, MA1, MA2, MA3, MA4); + LOAD_MSG(8, MA1, MA2, MA3, MA4); + ROUND(7, MB1, MB2, MB3, MB4); + LOAD_MSG(9, MB1, MB2, MB3, MB4); + ROUND(8, MA1, MA2, MA3, MA4); + LOAD_MSG(10, MA1, MA2, MA3, MA4); + ROUND(9, MB1, MB2, MB3, MB4); + LOAD_MSG(11, MB1, MB2, MB3, MB4); + sub $1, RNBLKS; + jz .Loop_end; + + lea 128(RINBLKS), RINBLKS; + addq $128, (STATE_T + 0)(RSTATE); + adcq $0, (STATE_T + 8)(RSTATE); + + ROUND(10, MA1, MA2, MA3, MA4); + LOAD_MSG(0, MA1, MA2, MA3, MA4); + ROUND(11, MB1, MB2, MB3, MB4); + LOAD_MSG(1, MB1, MB2, MB3, MB4); + + vpxor ROW3, ROW1, ROW1; + vpxor ROW4, ROW2, ROW2; + + vmovdqa .Liv+(0 * 8) rRIP, ROW3; + vmovdqa .Liv+(4 * 8) rRIP, ROW4; + + vpxor (STATE_H + 0 * 8)(RSTATE), ROW1, ROW1; + vpxor (STATE_H + 4 * 8)(RSTATE), ROW2, ROW2; + + vmovdqu ROW1, (STATE_H + 0 * 8)(RSTATE); + vmovdqu ROW2, (STATE_H + 4 * 8)(RSTATE); + + vpxor (STATE_T)(RSTATE), ROW4, ROW4; + + jmp .Loop; + +.Loop_end: + ROUND(10, MA1, MA2, MA3, MA4); + ROUND(11, MB1, MB2, MB3, MB4); + + vpxor ROW3, ROW1, ROW1; + vpxor ROW4, ROW2, ROW2; + vpxor (STATE_H + 0 * 8)(RSTATE), ROW1, ROW1; + vpxor (STATE_H + 4 * 8)(RSTATE), ROW2, ROW2; + + vmovdqu ROW1, (STATE_H + 0 * 8)(RSTATE); + vmovdqu ROW2, (STATE_H + 4 * 8)(RSTATE); + + xor %eax, %eax; + vzeroall; + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blake2b_transform_amd64_avx2, + .-_gcry_blake2b_transform_amd64_avx2;) + +#endif /*defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/blake2s-amd64-avx.S b/comm/third_party/libgcrypt/cipher/blake2s-amd64-avx.S new file mode 100644 index 0000000000..5b93675871 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/blake2s-amd64-avx.S @@ -0,0 +1,278 @@ +/* blake2s-amd64-avx.S - AVX implementation of BLAKE2s + * + * Copyright (C) 2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* The code is based on public-domain/CC0 BLAKE2 reference implementation + * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/sse + * Copyright 2012, Samuel Neves + */ + +#ifdef __x86_64 +#include +#if defined(HAVE_GCC_INLINE_ASM_AVX) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +#include "asm-common-amd64.h" + +.text + +/* register macros */ +#define RSTATE %rdi +#define RINBLKS %rsi +#define RNBLKS %rdx +#define RIV %rcx + +/* state structure */ +#define STATE_H 0 +#define STATE_T (STATE_H + 8 * 4) +#define STATE_F (STATE_T + 2 * 4) + +/* vector registers */ +#define ROW1 %xmm0 +#define ROW2 %xmm1 +#define ROW3 %xmm2 +#define ROW4 %xmm3 +#define TMP1 %xmm4 +#define TMP1x %xmm4 +#define R16 %xmm5 +#define R8 %xmm6 + +#define MA1 %xmm8 +#define MA2 %xmm9 +#define MA3 %xmm10 +#define MA4 %xmm11 + +#define MB1 %xmm12 +#define MB2 %xmm13 +#define MB3 %xmm14 +#define MB4 %xmm15 + +/********************************************************************** + blake2s/AVX + **********************************************************************/ + +#define GATHER_MSG(m1, m2, m3, m4, \ + s0, s1, s2, s3, s4, s5, s6, s7, s8, \ + s9, s10, s11, s12, s13, s14, s15) \ + vmovd (s0)*4(RINBLKS), m1; \ + vmovd (s1)*4(RINBLKS), m2; \ + vmovd (s8)*4(RINBLKS), m3; \ + vmovd (s9)*4(RINBLKS), m4; \ + vpinsrd $1, (s2)*4(RINBLKS), m1, m1; \ + vpinsrd $1, (s3)*4(RINBLKS), m2, m2; \ + vpinsrd $1, (s10)*4(RINBLKS), m3, m3; \ + vpinsrd $1, (s11)*4(RINBLKS), m4, m4; \ + vpinsrd $2, (s4)*4(RINBLKS), m1, m1; \ + vpinsrd $2, (s5)*4(RINBLKS), m2, m2; \ + vpinsrd $2, (s12)*4(RINBLKS), m3, m3; \ + vpinsrd $2, (s13)*4(RINBLKS), m4, m4; \ + vpinsrd $3, (s6)*4(RINBLKS), m1, m1; \ + vpinsrd $3, (s7)*4(RINBLKS), m2, m2; \ + vpinsrd $3, (s14)*4(RINBLKS), m3, m3; \ + vpinsrd $3, (s15)*4(RINBLKS), m4, m4; + +#define LOAD_MSG_0(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) +#define LOAD_MSG_1(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3) +#define LOAD_MSG_2(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4) +#define LOAD_MSG_3(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8) +#define LOAD_MSG_4(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13) +#define LOAD_MSG_5(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9) +#define LOAD_MSG_6(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11) +#define LOAD_MSG_7(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10) +#define LOAD_MSG_8(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5) +#define LOAD_MSG_9(m1, m2, m3, m4) \ + GATHER_MSG(m1, m2, m3, m4, \ + 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0) + +#define LOAD_MSG(r, m1, m2, m3, m4) LOAD_MSG_##r(m1, m2, m3, m4) + +#define ROR_16(in, out) vpshufb R16, in, out; + +#define ROR_8(in, out) vpshufb R8, in, out; + +#define ROR_12(in, out) \ + vpsrld $12, in, TMP1; \ + vpslld $(32 - 12), in, out; \ + vpxor TMP1, out, out; + +#define ROR_7(in, out) \ + vpsrld $7, in, TMP1; \ + vpslld $(32 - 7), in, out; \ + vpxor TMP1, out, out; + +#define G(r1, r2, r3, r4, m, ROR_A, ROR_B) \ + vpaddd m, r1, r1; \ + vpaddd r2, r1, r1; \ + vpxor r1, r4, r4; \ + ROR_A(r4, r4); \ + vpaddd r4, r3, r3; \ + vpxor r3, r2, r2; \ + ROR_B(r2, r2); + +#define G1(r1, r2, r3, r4, m) \ + G(r1, r2, r3, r4, m, ROR_16, ROR_12); + +#define G2(r1, r2, r3, r4, m) \ + G(r1, r2, r3, r4, m, ROR_8, ROR_7); + +#define MM_SHUFFLE(z,y,x,w) \ + (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) + +#define DIAGONALIZE(r1, r2, r3, r4) \ + vpshufd $MM_SHUFFLE(0,3,2,1), r2, r2; \ + vpshufd $MM_SHUFFLE(1,0,3,2), r3, r3; \ + vpshufd $MM_SHUFFLE(2,1,0,3), r4, r4; + +#define UNDIAGONALIZE(r1, r2, r3, r4) \ + vpshufd $MM_SHUFFLE(2,1,0,3), r2, r2; \ + vpshufd $MM_SHUFFLE(1,0,3,2), r3, r3; \ + vpshufd $MM_SHUFFLE(0,3,2,1), r4, r4; + +#define ROUND(r, m1, m2, m3, m4) \ + G1(ROW1, ROW2, ROW3, ROW4, m1); \ + G2(ROW1, ROW2, ROW3, ROW4, m2); \ + DIAGONALIZE(ROW1, ROW2, ROW3, ROW4); \ + G1(ROW1, ROW2, ROW3, ROW4, m3); \ + G2(ROW1, ROW2, ROW3, ROW4, m4); \ + UNDIAGONALIZE(ROW1, ROW2, ROW3, ROW4); + +blake2s_data: +.align 16 +.Liv: + .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A + .long 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +.Lshuf_ror16: + .byte 2,3,0,1,6,7,4,5,10,11,8,9,14,15,12,13 +.Lshuf_ror8: + .byte 1,2,3,0,5,6,7,4,9,10,11,8,13,14,15,12 + +.align 64 +.globl _gcry_blake2s_transform_amd64_avx +ELF(.type _gcry_blake2s_transform_amd64_avx,@function;) + +_gcry_blake2s_transform_amd64_avx: + /* input: + * %rdi: state + * %rsi: blks + * %rdx: num_blks + */ + CFI_STARTPROC(); + + vzeroupper; + + addq $64, (STATE_T + 0)(RSTATE); + + vmovdqa .Lshuf_ror16 rRIP, R16; + vmovdqa .Lshuf_ror8 rRIP, R8; + + vmovdqa .Liv+(0 * 4) rRIP, ROW3; + vmovdqa .Liv+(4 * 4) rRIP, ROW4; + + vmovdqu (STATE_H + 0 * 4)(RSTATE), ROW1; + vmovdqu (STATE_H + 4 * 4)(RSTATE), ROW2; + + vpxor (STATE_T)(RSTATE), ROW4, ROW4; + + LOAD_MSG(0, MA1, MA2, MA3, MA4); + LOAD_MSG(1, MB1, MB2, MB3, MB4); + +.Loop: + ROUND(0, MA1, MA2, MA3, MA4); + LOAD_MSG(2, MA1, MA2, MA3, MA4); + ROUND(1, MB1, MB2, MB3, MB4); + LOAD_MSG(3, MB1, MB2, MB3, MB4); + ROUND(2, MA1, MA2, MA3, MA4); + LOAD_MSG(4, MA1, MA2, MA3, MA4); + ROUND(3, MB1, MB2, MB3, MB4); + LOAD_MSG(5, MB1, MB2, MB3, MB4); + ROUND(4, MA1, MA2, MA3, MA4); + LOAD_MSG(6, MA1, MA2, MA3, MA4); + ROUND(5, MB1, MB2, MB3, MB4); + LOAD_MSG(7, MB1, MB2, MB3, MB4); + ROUND(6, MA1, MA2, MA3, MA4); + LOAD_MSG(8, MA1, MA2, MA3, MA4); + ROUND(7, MB1, MB2, MB3, MB4); + LOAD_MSG(9, MB1, MB2, MB3, MB4); + sub $1, RNBLKS; + jz .Loop_end; + + lea 64(RINBLKS), RINBLKS; + addq $64, (STATE_T + 0)(RSTATE); + + ROUND(8, MA1, MA2, MA3, MA4); + LOAD_MSG(0, MA1, MA2, MA3, MA4); + ROUND(9, MB1, MB2, MB3, MB4); + LOAD_MSG(1, MB1, MB2, MB3, MB4); + + vpxor ROW3, ROW1, ROW1; + vpxor ROW4, ROW2, ROW2; + + vmovdqa .Liv+(0 * 4) rRIP, ROW3; + vmovdqa .Liv+(4 * 4) rRIP, ROW4; + + vpxor (STATE_H + 0 * 4)(RSTATE), ROW1, ROW1; + vpxor (STATE_H + 4 * 4)(RSTATE), ROW2, ROW2; + + vmovdqu ROW1, (STATE_H + 0 * 4)(RSTATE); + vmovdqu ROW2, (STATE_H + 4 * 4)(RSTATE); + + vpxor (STATE_T)(RSTATE), ROW4, ROW4; + + jmp .Loop; + +.Loop_end: + ROUND(8, MA1, MA2, MA3, MA4); + ROUND(9, MB1, MB2, MB3, MB4); + + vpxor ROW3, ROW1, ROW1; + vpxor ROW4, ROW2, ROW2; + vpxor (STATE_H + 0 * 4)(RSTATE), ROW1, ROW1; + vpxor (STATE_H + 4 * 4)(RSTATE), ROW2, ROW2; + + vmovdqu ROW1, (STATE_H + 0 * 4)(RSTATE); + vmovdqu ROW2, (STATE_H + 4 * 4)(RSTATE); + + xor %eax, %eax; + vzeroall; + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blake2s_transform_amd64_avx, + .-_gcry_blake2s_transform_amd64_avx;) + +#endif /*defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/blowfish-amd64.S b/comm/third_party/libgcrypt/cipher/blowfish-amd64.S new file mode 100644 index 0000000000..bdb361d7eb --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/blowfish-amd64.S @@ -0,0 +1,601 @@ +/* blowfish-amd64.S - AMD64 assembly implementation of Blowfish cipher + * + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifdef __x86_64 +#include +#if defined(USE_BLOWFISH) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +#include "asm-common-amd64.h" + +.text + +/* structure of BLOWFISH_context: */ +#define s0 0 +#define s1 ((s0) + 256 * 4) +#define s2 ((s1) + 256 * 4) +#define s3 ((s2) + 256 * 4) +#define p ((s3) + 256 * 4) + +/* register macros */ +#define CTX %rdi +#define RIO %rsi + +#define RX0 %rax +#define RX1 %rbx +#define RX2 %rcx +#define RX3 %rdx + +#define RX0d %eax +#define RX1d %ebx +#define RX2d %ecx +#define RX3d %edx + +#define RX0bl %al +#define RX1bl %bl +#define RX2bl %cl +#define RX3bl %dl + +#define RX0bh %ah +#define RX1bh %bh +#define RX2bh %ch +#define RX3bh %dh + +#define RT0 %rbp +#define RT1 %rsi +#define RT2 %r8 +#define RT3 %r9 + +#define RT0d %ebp +#define RT1d %esi +#define RT2d %r8d +#define RT3d %r9d + +#define RKEY %r10 + +/*********************************************************************** + * 1-way blowfish + ***********************************************************************/ +#define F() \ + movzbl RX0bh, RT1d; \ + movzbl RX0bl, RT3d; \ + rorq $16, RX0; \ + movzbl RX0bh, RT0d; \ + movzbl RX0bl, RT2d; \ + rorq $16, RX0; \ + movl s0(CTX,RT0,4), RT0d; \ + addl s1(CTX,RT2,4), RT0d; \ + xorl s2(CTX,RT1,4), RT0d; \ + addl s3(CTX,RT3,4), RT0d; \ + xorq RT0, RX0; + +#define load_roundkey_enc(n) \ + movq p+4*(n)(CTX), RX3; + +#define add_roundkey_enc() \ + xorq RX3, RX0; + +#define round_enc(n) \ + add_roundkey_enc(); \ + load_roundkey_enc(n); \ + \ + F(); \ + F(); + +#define load_roundkey_dec(n) \ + movq p+4*(n-1)(CTX), RX3; \ + rorq $32, RX3; + +#define add_roundkey_dec() \ + xorq RX3, RX0; + +#define round_dec(n) \ + add_roundkey_dec(); \ + load_roundkey_dec(n); \ + \ + F(); \ + F(); + +#define read_block() \ + movq (RIO), RX0; \ + rorq $32, RX0; \ + bswapq RX0; + +#define write_block() \ + bswapq RX0; \ + movq RX0, (RIO); + +.align 8 +ELF(.type __blowfish_enc_blk1,@function;) + +__blowfish_enc_blk1: + /* input: + * %rdi: ctx, CTX + * RX0: input plaintext block + * output: + * RX0: output plaintext block + */ + CFI_STARTPROC(); + movq %rbp, %r11; + CFI_REGISTER(%rbp, %r11); + + load_roundkey_enc(0); + round_enc(2); + round_enc(4); + round_enc(6); + round_enc(8); + round_enc(10); + round_enc(12); + round_enc(14); + round_enc(16); + add_roundkey_enc(); + + movq %r11, %rbp; + CFI_RESTORE(%rbp) + + ret; + CFI_ENDPROC(); +ELF(.size __blowfish_enc_blk1,.-__blowfish_enc_blk1;) + +.align 8 +.globl _gcry_blowfish_amd64_do_encrypt +ELF(.type _gcry_blowfish_amd64_do_encrypt,@function;) + +_gcry_blowfish_amd64_do_encrypt: + /* input: + * %rdi: ctx, CTX + * %rsi: u32 *ret_xl + * %rdx: u32 *ret_xr + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + movl (%rdx), RX0d; + shlq $32, RX0; + movl (%rsi), RT3d; + movq %rdx, %r10; + orq RT3, RX0; + movq %rsi, RX2; + + call __blowfish_enc_blk1; + + movl RX0d, (%r10); + shrq $32, RX0; + movl RX0d, (RX2); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blowfish_amd64_do_encrypt,.-_gcry_blowfish_amd64_do_encrypt;) + +.align 8 +.globl _gcry_blowfish_amd64_encrypt_block +ELF(.type _gcry_blowfish_amd64_encrypt_block,@function;) + +_gcry_blowfish_amd64_encrypt_block: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + movq %rsi, %r10; + + movq %rdx, RIO; + read_block(); + + call __blowfish_enc_blk1; + + movq %r10, RIO; + write_block(); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blowfish_amd64_encrypt_block,.-_gcry_blowfish_amd64_encrypt_block;) + +.align 8 +.globl _gcry_blowfish_amd64_decrypt_block +ELF(.type _gcry_blowfish_amd64_decrypt_block,@function;) + +_gcry_blowfish_amd64_decrypt_block: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + movq %rbp, %r11; + CFI_REGISTER(%rbp, %r11); + + movq %rsi, %r10; + movq %rdx, RIO; + + read_block(); + + load_roundkey_dec(17); + round_dec(15); + round_dec(13); + round_dec(11); + round_dec(9); + round_dec(7); + round_dec(5); + round_dec(3); + round_dec(1); + add_roundkey_dec(); + + movq %r10, RIO; + write_block(); + + movq %r11, %rbp; + CFI_RESTORE(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blowfish_amd64_decrypt_block,.-_gcry_blowfish_amd64_decrypt_block;) + +/********************************************************************** + 4-way blowfish, four blocks parallel + **********************************************************************/ +#define F4(x) \ + movzbl x ## bh, RT1d; \ + movzbl x ## bl, RT3d; \ + rorq $16, x; \ + movzbl x ## bh, RT0d; \ + movzbl x ## bl, RT2d; \ + rorq $16, x; \ + movl s0(CTX,RT0,4), RT0d; \ + addl s1(CTX,RT2,4), RT0d; \ + xorl s2(CTX,RT1,4), RT0d; \ + addl s3(CTX,RT3,4), RT0d; \ + xorq RT0, x; + +#define add_preloaded_roundkey4() \ + xorq RKEY, RX0; \ + xorq RKEY, RX1; \ + xorq RKEY, RX2; \ + xorq RKEY, RX3; + +#define preload_roundkey_enc(n) \ + movq p+4*(n)(CTX), RKEY; + +#define add_roundkey_enc4(n) \ + add_preloaded_roundkey4(); \ + preload_roundkey_enc(n + 2); + +#define round_enc4(n) \ + add_roundkey_enc4(n); \ + \ + F4(RX0); \ + F4(RX1); \ + F4(RX2); \ + F4(RX3); \ + \ + F4(RX0); \ + F4(RX1); \ + F4(RX2); \ + F4(RX3); + +#define preload_roundkey_dec(n) \ + movq p+4*((n)-1)(CTX), RKEY; \ + rorq $32, RKEY; + +#define add_roundkey_dec4(n) \ + add_preloaded_roundkey4(); \ + preload_roundkey_dec(n - 2); + +#define round_dec4(n) \ + add_roundkey_dec4(n); \ + \ + F4(RX0); \ + F4(RX1); \ + F4(RX2); \ + F4(RX3); \ + \ + F4(RX0); \ + F4(RX1); \ + F4(RX2); \ + F4(RX3); + +#define inbswap_block4() \ + rorq $32, RX0; \ + bswapq RX0; \ + rorq $32, RX1; \ + bswapq RX1; \ + rorq $32, RX2; \ + bswapq RX2; \ + rorq $32, RX3; \ + bswapq RX3; + +#define inctrswap_block4() \ + rorq $32, RX0; \ + rorq $32, RX1; \ + rorq $32, RX2; \ + rorq $32, RX3; + +#define outbswap_block4() \ + bswapq RX0; \ + bswapq RX1; \ + bswapq RX2; \ + bswapq RX3; + +.align 8 +ELF(.type __blowfish_enc_blk4,@function;) + +__blowfish_enc_blk4: + /* input: + * %rdi: ctx, CTX + * RX0,RX1,RX2,RX3: four input inbswapped plaintext blocks + * output: + * RX0,RX1,RX2,RX3: four output ciphertext blocks + */ + CFI_STARTPROC(); + preload_roundkey_enc(0); + + round_enc4(0); + round_enc4(2); + round_enc4(4); + round_enc4(6); + round_enc4(8); + round_enc4(10); + round_enc4(12); + round_enc4(14); + add_preloaded_roundkey4(); + + outbswap_block4(); + + ret; + CFI_ENDPROC(); +ELF(.size __blowfish_enc_blk4,.-__blowfish_enc_blk4;) + +.align 8 +ELF(.type __blowfish_dec_blk4,@function;) + +__blowfish_dec_blk4: + /* input: + * %rdi: ctx, CTX + * RX0,RX1,RX2,RX3: four input ciphertext blocks + * output: + * RX0,RX1,RX2,RX3: four output plaintext blocks + */ + CFI_STARTPROC(); + preload_roundkey_dec(17); + + inbswap_block4(); + + round_dec4(17); + round_dec4(15); + round_dec4(13); + round_dec4(11); + round_dec4(9); + round_dec4(7); + round_dec4(5); + round_dec4(3); + add_preloaded_roundkey4(); + + outbswap_block4(); + + ret; + CFI_ENDPROC(); +ELF(.size __blowfish_dec_blk4,.-__blowfish_dec_blk4;) + +.align 8 +.globl _gcry_blowfish_amd64_ctr_enc +ELF(.type _gcry_blowfish_amd64_ctr_enc,@function;) +_gcry_blowfish_amd64_ctr_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (4 blocks) + * %rdx: src (4 blocks) + * %rcx: iv (big endian, 64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + + /* %r11-%r13 are not used by __blowfish_enc_blk4 */ + movq %rcx, %r13; /*iv*/ + movq %rdx, %r12; /*src*/ + movq %rsi, %r11; /*dst*/ + + /* load IV and byteswap */ + movq (%r13), RT0; + bswapq RT0; + movq RT0, RX0; + + /* construct IVs */ + leaq 1(RT0), RX1; + leaq 2(RT0), RX2; + leaq 3(RT0), RX3; + leaq 4(RT0), RT0; + bswapq RT0; + + inctrswap_block4(); + + /* store new IV */ + movq RT0, (%r13); + + call __blowfish_enc_blk4; + + /* XOR key-stream with plaintext */ + xorq 0 * 8(%r12), RX0; + xorq 1 * 8(%r12), RX1; + xorq 2 * 8(%r12), RX2; + xorq 3 * 8(%r12), RX3; + movq RX0, 0 * 8(%r11); + movq RX1, 1 * 8(%r11); + movq RX2, 2 * 8(%r11); + movq RX3, 3 * 8(%r11); + + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blowfish_amd64_ctr_enc,.-_gcry_blowfish_amd64_ctr_enc;) + +.align 8 +.globl _gcry_blowfish_amd64_cbc_dec +ELF(.type _gcry_blowfish_amd64_cbc_dec,@function;) +_gcry_blowfish_amd64_cbc_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (4 blocks) + * %rdx: src (4 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + + /* %r11-%r13 are not used by __blowfish_dec_blk4 */ + movq %rsi, %r11; /*dst*/ + movq %rdx, %r12; /*src*/ + movq %rcx, %r13; /*iv*/ + + /* load input */ + movq 0 * 8(%r12), RX0; + movq 1 * 8(%r12), RX1; + movq 2 * 8(%r12), RX2; + movq 3 * 8(%r12), RX3; + + call __blowfish_dec_blk4; + + movq 3 * 8(%r12), RT0; + xorq (%r13), RX0; + xorq 0 * 8(%r12), RX1; + xorq 1 * 8(%r12), RX2; + xorq 2 * 8(%r12), RX3; + movq RT0, (%r13); /* store new IV */ + + movq RX0, 0 * 8(%r11); + movq RX1, 1 * 8(%r11); + movq RX2, 2 * 8(%r11); + movq RX3, 3 * 8(%r11); + + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blowfish_amd64_cbc_dec,.-_gcry_blowfish_amd64_cbc_dec;) + +.align 8 +.globl _gcry_blowfish_amd64_cfb_dec +ELF(.type _gcry_blowfish_amd64_cfb_dec,@function;) +_gcry_blowfish_amd64_cfb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (4 blocks) + * %rdx: src (4 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + + /* %r11-%r13 are not used by __blowfish_enc_blk4 */ + movq %rcx, %r13; /*iv*/ + movq %rdx, %r12; /*src*/ + movq %rsi, %r11; /*dst*/ + + /* Load input */ + movq (%r13), RX0; + movq 0 * 8(%r12), RX1; + movq 1 * 8(%r12), RX2; + movq 2 * 8(%r12), RX3; + + inbswap_block4(); + + /* Update IV */ + movq 3 * 8(%r12), RT0; + movq RT0, (%r13); + + call __blowfish_enc_blk4; + + xorq 0 * 8(%r12), RX0; + xorq 1 * 8(%r12), RX1; + xorq 2 * 8(%r12), RX2; + xorq 3 * 8(%r12), RX3; + movq RX0, 0 * 8(%r11); + movq RX1, 1 * 8(%r11); + movq RX2, 2 * 8(%r11); + movq RX3, 3 * 8(%r11); + + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_blowfish_amd64_cfb_dec,.-_gcry_blowfish_amd64_cfb_dec;) + +#endif /*defined(USE_BLOWFISH)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/blowfish-arm.S b/comm/third_party/libgcrypt/cipher/blowfish-arm.S new file mode 100644 index 0000000000..b30aa31f1d --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/blowfish-arm.S @@ -0,0 +1,743 @@ +/* blowfish-arm.S - ARM assembly implementation of Blowfish cipher + * + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(__ARMEL__) +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +.text + +.syntax unified +.arm + +/* structure of crypto context */ +#define s0 0 +#define s1 (s0 + (1 * 256) * 4) +#define s2 (s0 + (2 * 256) * 4) +#define s3 (s0 + (3 * 256) * 4) +#define p (s3 + (1 * 256) * 4) + +/* register macros */ +#define CTXs0 %r0 +#define CTXs1 %r9 +#define CTXs2 %r8 +#define CTXs3 %r10 +#define RMASK %lr +#define RKEYL %r2 +#define RKEYR %ip + +#define RL0 %r3 +#define RR0 %r4 + +#define RL1 %r9 +#define RR1 %r10 + +#define RT0 %r11 +#define RT1 %r7 +#define RT2 %r5 +#define RT3 %r6 + +/* helper macros */ +#define ldr_unaligned_le(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 0)]; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 3)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 0)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 1)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 2)]; \ + strb rtmp0, [rdst, #((offs) + 3)]; + +#define ldr_unaligned_be(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 3)]; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 0)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 3)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 2)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 1)]; \ + strb rtmp0, [rdst, #((offs) + 0)]; + +#ifdef __ARMEL__ + #define ldr_unaligned_host ldr_unaligned_le + #define str_unaligned_host str_unaligned_le + + /* bswap on little-endian */ +#ifdef HAVE_ARM_ARCH_V6 + #define host_to_be(reg, rtmp) \ + rev reg, reg; + #define be_to_host(reg, rtmp) \ + rev reg, reg; +#else + #define host_to_be(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; + #define be_to_host(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; +#endif +#else + #define ldr_unaligned_host ldr_unaligned_be + #define str_unaligned_host str_unaligned_be + + /* nop on big-endian */ + #define host_to_be(reg, rtmp) /*_*/ + #define be_to_host(reg, rtmp) /*_*/ +#endif + +#define host_to_host(x, y) /*_*/ + +/*********************************************************************** + * 1-way blowfish + ***********************************************************************/ +#define F(l, r) \ + and RT0, RMASK, l, lsr#(24 - 2); \ + and RT1, RMASK, l, lsr#(16 - 2); \ + ldr RT0, [CTXs0, RT0]; \ + and RT2, RMASK, l, lsr#(8 - 2); \ + ldr RT1, [CTXs1, RT1]; \ + and RT3, RMASK, l, lsl#2; \ + ldr RT2, [CTXs2, RT2]; \ + add RT0, RT1; \ + ldr RT3, [CTXs3, RT3]; \ + eor RT0, RT2; \ + add RT0, RT3; \ + eor r, RT0; + +#define load_roundkey_enc(n) \ + ldr RKEYL, [CTXs2, #((p - s2) + (4 * (n) + 0))]; \ + ldr RKEYR, [CTXs2, #((p - s2) + (4 * (n) + 4))]; + +#define add_roundkey_enc() \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; + +#define round_enc(n) \ + add_roundkey_enc(); \ + load_roundkey_enc(n); \ + \ + F(RL0, RR0); \ + F(RR0, RL0); + +#define load_roundkey_dec(n) \ + ldr RKEYL, [CTXs2, #((p - s2) + (4 * ((n) - 1) + 4))]; \ + ldr RKEYR, [CTXs2, #((p - s2) + (4 * ((n) - 1) + 0))]; + +#define add_roundkey_dec() \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; + +#define round_dec(n) \ + add_roundkey_dec(); \ + load_roundkey_dec(n); \ + \ + F(RL0, RR0); \ + F(RR0, RL0); + +#define read_block_aligned(rin, offs, l0, r0, convert, rtmp) \ + ldr l0, [rin, #((offs) + 0)]; \ + ldr r0, [rin, #((offs) + 4)]; \ + convert(l0, rtmp); \ + convert(r0, rtmp); + +#define write_block_aligned(rout, offs, l0, r0, convert, rtmp) \ + convert(l0, rtmp); \ + convert(r0, rtmp); \ + str l0, [rout, #((offs) + 0)]; \ + str r0, [rout, #((offs) + 4)]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads allowed */ + #define read_block(rin, offs, l0, r0, rtmp0) \ + read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0) + + #define write_block(rout, offs, r0, l0, rtmp0, rtmp1) \ + write_block_aligned(rout, offs, r0, l0, be_to_host, rtmp0) + + #define read_block_host(rin, offs, l0, r0, rtmp0) \ + read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0) + + #define write_block_host(rout, offs, r0, l0, rtmp0, rtmp1) \ + write_block_aligned(rout, offs, r0, l0, host_to_host, rtmp0) +#else + /* need to handle unaligned reads by byte reads */ + #define read_block(rin, offs, l0, r0, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(l0, rin, (offs) + 0, rtmp0); \ + ldr_unaligned_be(r0, rin, (offs) + 4, rtmp0); \ + b 2f; \ + 1:;\ + read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0); \ + 2:; + + #define write_block(rout, offs, l0, r0, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(l0, rout, (offs) + 0, rtmp0, rtmp1); \ + str_unaligned_be(r0, rout, (offs) + 4, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block_aligned(rout, offs, l0, r0, be_to_host, rtmp0); \ + 2:; + + #define read_block_host(rin, offs, l0, r0, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_host(l0, rin, (offs) + 0, rtmp0); \ + ldr_unaligned_host(r0, rin, (offs) + 4, rtmp0); \ + b 2f; \ + 1:;\ + read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0); \ + 2:; + + #define write_block_host(rout, offs, l0, r0, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_host(l0, rout, (offs) + 0, rtmp0, rtmp1); \ + str_unaligned_host(r0, rout, (offs) + 4, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block_aligned(rout, offs, l0, r0, host_to_host); \ + 2:; +#endif + +.align 3 +.type __blowfish_enc_blk1,%function; + +__blowfish_enc_blk1: + /* input: + * preloaded: CTX + * [RL0, RR0]: src + * output: + * [RR0, RL0]: dst + */ + push {%lr}; + + add CTXs1, CTXs0, #(s1 - s0); + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + add CTXs3, CTXs1, #(s3 - s1); + + load_roundkey_enc(0); + round_enc(2); + round_enc(4); + round_enc(6); + round_enc(8); + round_enc(10); + round_enc(12); + round_enc(14); + round_enc(16); + add_roundkey_enc(); + + pop {%pc}; +.size __blowfish_enc_blk1,.-__blowfish_enc_blk1; + +.align 8 +.globl _gcry_blowfish_arm_do_encrypt +.type _gcry_blowfish_arm_do_encrypt,%function; + +_gcry_blowfish_arm_do_encrypt: + /* input: + * %r0: ctx, CTX + * %r1: u32 *ret_xl + * %r2: u32 *ret_xr + */ + push {%r2, %r4-%r11, %ip, %lr}; + + ldr RL0, [%r1]; + ldr RR0, [%r2]; + + bl __blowfish_enc_blk1; + + pop {%r2}; + str RR0, [%r1]; + str RL0, [%r2]; + + pop {%r4-%r11, %ip, %pc}; +.size _gcry_blowfish_arm_do_encrypt,.-_gcry_blowfish_arm_do_encrypt; + +.align 3 +.globl _gcry_blowfish_arm_encrypt_block +.type _gcry_blowfish_arm_encrypt_block,%function; + +_gcry_blowfish_arm_encrypt_block: + /* input: + * %r0: ctx, CTX + * %r1: dst + * %r2: src + */ + push {%r4-%r11, %ip, %lr}; + + read_block(%r2, 0, RL0, RR0, RT0); + + bl __blowfish_enc_blk1; + + write_block(%r1, 0, RR0, RL0, RT0, RT1); + + pop {%r4-%r11, %ip, %pc}; +.size _gcry_blowfish_arm_encrypt_block,.-_gcry_blowfish_arm_encrypt_block; + +.align 3 +.globl _gcry_blowfish_arm_decrypt_block +.type _gcry_blowfish_arm_decrypt_block,%function; + +_gcry_blowfish_arm_decrypt_block: + /* input: + * %r0: ctx, CTX + * %r1: dst + * %r2: src + */ + push {%r4-%r11, %ip, %lr}; + + add CTXs1, CTXs0, #(s1 - s0); + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + add CTXs3, CTXs1, #(s3 - s1); + + read_block(%r2, 0, RL0, RR0, RT0); + + load_roundkey_dec(17); + round_dec(15); + round_dec(13); + round_dec(11); + round_dec(9); + round_dec(7); + round_dec(5); + round_dec(3); + round_dec(1); + add_roundkey_dec(); + + write_block(%r1, 0, RR0, RL0, RT0, RT1); + + pop {%r4-%r11, %ip, %pc}; +.size _gcry_blowfish_arm_decrypt_block,.-_gcry_blowfish_arm_decrypt_block; + +/*********************************************************************** + * 2-way blowfish + ***********************************************************************/ +#define F2(n, l0, r0, l1, r1, set_nextk, dec) \ + \ + and RT0, RMASK, l0, lsr#(24 - 2); \ + and RT1, RMASK, l0, lsr#(16 - 2); \ + and RT2, RMASK, l0, lsr#(8 - 2); \ + add RT1, #(s1 - s0); \ + \ + ldr RT0, [CTXs0, RT0]; \ + and RT3, RMASK, l0, lsl#2; \ + ldr RT1, [CTXs0, RT1]; \ + add RT3, #(s3 - s2); \ + ldr RT2, [CTXs2, RT2]; \ + add RT0, RT1; \ + ldr RT3, [CTXs2, RT3]; \ + \ + and RT1, RMASK, l1, lsr#(24 - 2); \ + eor RT0, RT2; \ + and RT2, RMASK, l1, lsr#(16 - 2); \ + add RT0, RT3; \ + add RT2, #(s1 - s0); \ + and RT3, RMASK, l1, lsr#(8 - 2); \ + eor r0, RT0; \ + \ + ldr RT1, [CTXs0, RT1]; \ + and RT0, RMASK, l1, lsl#2; \ + ldr RT2, [CTXs0, RT2]; \ + add RT0, #(s3 - s2); \ + ldr RT3, [CTXs2, RT3]; \ + add RT1, RT2; \ + ldr RT0, [CTXs2, RT0]; \ + \ + and RT2, RMASK, r0, lsr#(24 - 2); \ + eor RT1, RT3; \ + and RT3, RMASK, r0, lsr#(16 - 2); \ + add RT1, RT0; \ + add RT3, #(s1 - s0); \ + and RT0, RMASK, r0, lsr#(8 - 2); \ + eor r1, RT1; \ + \ + ldr RT2, [CTXs0, RT2]; \ + and RT1, RMASK, r0, lsl#2; \ + ldr RT3, [CTXs0, RT3]; \ + add RT1, #(s3 - s2); \ + ldr RT0, [CTXs2, RT0]; \ + add RT2, RT3; \ + ldr RT1, [CTXs2, RT1]; \ + \ + and RT3, RMASK, r1, lsr#(24 - 2); \ + eor RT2, RT0; \ + and RT0, RMASK, r1, lsr#(16 - 2); \ + add RT2, RT1; \ + add RT0, #(s1 - s0); \ + and RT1, RMASK, r1, lsr#(8 - 2); \ + eor l0, RT2; \ + \ + ldr RT3, [CTXs0, RT3]; \ + and RT2, RMASK, r1, lsl#2; \ + ldr RT0, [CTXs0, RT0]; \ + add RT2, #(s3 - s2); \ + ldr RT1, [CTXs2, RT1]; \ + eor l1, RKEYL; \ + ldr RT2, [CTXs2, RT2]; \ + \ + eor r0, RKEYR; \ + add RT3, RT0; \ + eor r1, RKEYR; \ + eor RT3, RT1; \ + eor l0, RKEYL; \ + add RT3, RT2; \ + set_nextk(RKEYL, (p - s2) + (4 * (n) + ((dec) * 4))); \ + eor l1, RT3; \ + set_nextk(RKEYR, (p - s2) + (4 * (n) + (!(dec) * 4))); + +#define load_n_add_roundkey_enc2(n) \ + load_roundkey_enc(n); \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; \ + eor RL1, RKEYL; \ + eor RR1, RKEYR; \ + load_roundkey_enc((n) + 2); + +#define next_key(reg, offs) \ + ldr reg, [CTXs2, #(offs)]; + +#define dummy(x, y) /* do nothing */ + +#define round_enc2(n, load_next_key) \ + F2((n) + 2, RL0, RR0, RL1, RR1, load_next_key, 0); + +#define load_n_add_roundkey_dec2(n) \ + load_roundkey_dec(n); \ + eor RL0, RKEYL; \ + eor RR0, RKEYR; \ + eor RL1, RKEYL; \ + eor RR1, RKEYR; \ + load_roundkey_dec((n) - 2); + +#define round_dec2(n, load_next_key) \ + F2((n) - 3, RL0, RR0, RL1, RR1, load_next_key, 1); + +#define read_block2_aligned(rin, l0, r0, l1, r1, convert, rtmp) \ + ldr l0, [rin, #(0)]; \ + ldr r0, [rin, #(4)]; \ + convert(l0, rtmp); \ + ldr l1, [rin, #(8)]; \ + convert(r0, rtmp); \ + ldr r1, [rin, #(12)]; \ + convert(l1, rtmp); \ + convert(r1, rtmp); + +#define write_block2_aligned(rout, l0, r0, l1, r1, convert, rtmp) \ + convert(l0, rtmp); \ + convert(r0, rtmp); \ + convert(l1, rtmp); \ + str l0, [rout, #(0)]; \ + convert(r1, rtmp); \ + str r0, [rout, #(4)]; \ + str l1, [rout, #(8)]; \ + str r1, [rout, #(12)]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads allowed */ + #define read_block2(rin, l0, r0, l1, r1, rtmp0) \ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0) + + #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0) + + #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0) + + #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0) +#else + /* need to handle unaligned reads by byte reads */ + #define read_block2(rin, l0, r0, l1, r1, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(l0, rin, 0, rtmp0); \ + ldr_unaligned_be(r0, rin, 4, rtmp0); \ + ldr_unaligned_be(l1, rin, 8, rtmp0); \ + ldr_unaligned_be(r1, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0); \ + 2:; + + #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(l0, rout, 0, rtmp0, rtmp1); \ + str_unaligned_be(r0, rout, 4, rtmp0, rtmp1); \ + str_unaligned_be(l1, rout, 8, rtmp0, rtmp1); \ + str_unaligned_be(r1, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0); \ + 2:; + + #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_host(l0, rin, 0, rtmp0); \ + ldr_unaligned_host(r0, rin, 4, rtmp0); \ + ldr_unaligned_host(l1, rin, 8, rtmp0); \ + ldr_unaligned_host(r1, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0); \ + 2:; + + #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_host(l0, rout, 0, rtmp0, rtmp1); \ + str_unaligned_host(r0, rout, 4, rtmp0, rtmp1); \ + str_unaligned_host(l1, rout, 8, rtmp0, rtmp1); \ + str_unaligned_host(r1, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0); \ + 2:; +#endif + +.align 3 +.type _gcry_blowfish_arm_enc_blk2,%function; + +_gcry_blowfish_arm_enc_blk2: + /* input: + * preloaded: CTX + * [RL0, RR0], [RL1, RR1]: src + * output: + * [RR0, RL0], [RR1, RL1]: dst + */ + push {RT0,%lr}; + + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + + load_n_add_roundkey_enc2(0); + round_enc2(2, next_key); + round_enc2(4, next_key); + round_enc2(6, next_key); + round_enc2(8, next_key); + round_enc2(10, next_key); + round_enc2(12, next_key); + round_enc2(14, next_key); + round_enc2(16, dummy); + + host_to_be(RR0, RT0); + host_to_be(RL0, RT0); + host_to_be(RR1, RT0); + host_to_be(RL1, RT0); + + pop {RT0,%pc}; +.size _gcry_blowfish_arm_enc_blk2,.-_gcry_blowfish_arm_enc_blk2; + +.align 3 +.globl _gcry_blowfish_arm_cfb_dec; +.type _gcry_blowfish_arm_cfb_dec,%function; + +_gcry_blowfish_arm_cfb_dec: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit) + */ + push {%r2, %r4-%r11, %ip, %lr}; + + mov %lr, %r3; + + /* Load input (iv/%r3 is aligned, src/%r2 might not be) */ + ldm %r3, {RL0, RR0}; + host_to_be(RL0, RT0); + host_to_be(RR0, RT0); + read_block(%r2, 0, RL1, RR1, RT0); + + /* Update IV, load src[1] and save to iv[0] */ + read_block_host(%r2, 8, %r5, %r6, RT0); + stm %lr, {%r5, %r6}; + + bl _gcry_blowfish_arm_enc_blk2; + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r1: dst, %r0: %src */ + pop {%r0}; + + /* dst = src ^ result */ + read_block2_host(%r0, %r5, %r6, %r7, %r8, %lr); + eor %r5, %r4; + eor %r6, %r3; + eor %r7, %r10; + eor %r8, %r9; + write_block2_host(%r1, %r5, %r6, %r7, %r8, %r9, %r10); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_blowfish_arm_cfb_dec,.-_gcry_blowfish_arm_cfb_dec; + +.align 3 +.globl _gcry_blowfish_arm_ctr_enc; +.type _gcry_blowfish_arm_ctr_enc,%function; + +_gcry_blowfish_arm_ctr_enc: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit, big-endian) + */ + push {%r2, %r4-%r11, %ip, %lr}; + + mov %lr, %r3; + + /* Load IV (big => host endian) */ + read_block_aligned(%lr, 0, RL0, RR0, be_to_host, RT0); + + /* Construct IVs */ + adds RR1, RR0, #1; /* +1 */ + adc RL1, RL0, #0; + adds %r6, RR1, #1; /* +2 */ + adc %r5, RL1, #0; + + /* Store new IV (host => big-endian) */ + write_block_aligned(%lr, 0, %r5, %r6, host_to_be, RT0); + + bl _gcry_blowfish_arm_enc_blk2; + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r1: dst, %r0: %src */ + pop {%r0}; + + /* XOR key-stream with plaintext */ + read_block2_host(%r0, %r5, %r6, %r7, %r8, %lr); + eor %r5, %r4; + eor %r6, %r3; + eor %r7, %r10; + eor %r8, %r9; + write_block2_host(%r1, %r5, %r6, %r7, %r8, %r9, %r10); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_blowfish_arm_ctr_enc,.-_gcry_blowfish_arm_ctr_enc; + +.align 3 +.type _gcry_blowfish_arm_dec_blk2,%function; + +_gcry_blowfish_arm_dec_blk2: + /* input: + * preloaded: CTX + * [RL0, RR0], [RL1, RR1]: src + * output: + * [RR0, RL0], [RR1, RL1]: dst + */ + add CTXs2, CTXs0, #(s2 - s0); + mov RMASK, #(0xff << 2); /* byte mask */ + + load_n_add_roundkey_dec2(17); + round_dec2(15, next_key); + round_dec2(13, next_key); + round_dec2(11, next_key); + round_dec2(9, next_key); + round_dec2(7, next_key); + round_dec2(5, next_key); + round_dec2(3, next_key); + round_dec2(1, dummy); + + host_to_be(RR0, RT0); + host_to_be(RL0, RT0); + host_to_be(RR1, RT0); + host_to_be(RL1, RT0); + + b .Ldec_cbc_tail; +.ltorg +.size _gcry_blowfish_arm_dec_blk2,.-_gcry_blowfish_arm_dec_blk2; + +.align 3 +.globl _gcry_blowfish_arm_cbc_dec; +.type _gcry_blowfish_arm_cbc_dec,%function; + +_gcry_blowfish_arm_cbc_dec: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit) + */ + push {%r2-%r11, %ip, %lr}; + + read_block2(%r2, RL0, RR0, RL1, RR1, RT0); + + /* dec_blk2 is only used by cbc_dec, jump directly in/out instead + * of function call. */ + b _gcry_blowfish_arm_dec_blk2; +.Ldec_cbc_tail: + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r0: %src, %r1: dst, %r2: iv */ + pop {%r0, %r2}; + + /* load IV+1 (src[0]) to %r7:%r8. Might be unaligned. */ + read_block_host(%r0, 0, %r7, %r8, %r5); + /* load IV (iv[0]) to %r5:%r6. 'iv' is aligned. */ + ldm %r2, {%r5, %r6}; + + /* out[1] ^= IV+1 */ + eor %r10, %r7; + eor %r9, %r8; + /* out[0] ^= IV */ + eor %r4, %r5; + eor %r3, %r6; + + /* load IV+2 (src[1]) to %r7:%r8. Might be unaligned. */ + read_block_host(%r0, 8, %r7, %r8, %r5); + /* store IV+2 to iv[0] (aligned). */ + stm %r2, {%r7, %r8}; + + /* store result to dst[0-3]. Might be unaligned. */ + write_block2_host(%r1, %r4, %r3, %r10, %r9, %r5, %r6); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_blowfish_arm_cbc_dec,.-_gcry_blowfish_arm_cbc_dec; + +#endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/ +#endif /*__ARM_ARCH >= 6*/ diff --git a/comm/third_party/libgcrypt/cipher/blowfish.c b/comm/third_party/libgcrypt/cipher/blowfish.c new file mode 100644 index 0000000000..7b001306c7 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/blowfish.c @@ -0,0 +1,1142 @@ +/* blowfish.c - Blowfish encryption + * Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 336 ff. + */ + +/* Test values: + * key "abcdefghijklmnopqrstuvwxyz"; + * plain "BLOWFISH" + * cipher 32 4E D0 FE F4 13 A2 03 + * + */ + +#include +#include +#include +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "cipher-internal.h" +#include "cipher-selftest.h" + +#define BLOWFISH_BLOCKSIZE 8 +#define BLOWFISH_KEY_MIN_BITS 8 +#define BLOWFISH_KEY_MAX_BITS 576 + + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AMD64_ASM 1 +#endif + +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +#undef USE_ARM_ASM +#if defined(__ARMEL__) +# if defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) +# define USE_ARM_ASM 1 +# endif +#endif + +typedef struct { + u32 s0[256]; + u32 s1[256]; + u32 s2[256]; + u32 s3[256]; + u32 p[16+2]; +} BLOWFISH_context; + +static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops); +static unsigned int encrypt_block (void *bc, byte *outbuf, const byte *inbuf); +static unsigned int decrypt_block (void *bc, byte *outbuf, const byte *inbuf); + + +/* precomputed S boxes */ +static const u32 ks0[256] = { + 0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96, + 0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16, + 0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658, + 0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013, + 0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E, + 0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60, + 0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6, + 0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A, + 0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C, + 0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193, + 0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1, + 0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239, + 0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A, + 0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3, + 0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176, + 0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE, + 0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706, + 0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B, + 0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B, + 0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463, + 0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C, + 0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3, + 0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A, + 0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8, + 0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760, + 0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB, + 0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8, + 0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B, + 0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33, + 0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4, + 0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0, + 0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C, + 0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777, + 0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299, + 0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705, + 0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF, + 0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E, + 0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA, + 0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9, + 0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915, + 0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F, + 0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664, + 0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A }; + +static const u32 ks1[256] = { + 0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D, + 0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1, + 0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65, + 0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1, + 0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9, + 0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737, + 0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D, + 0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD, + 0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC, + 0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41, + 0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908, + 0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF, + 0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124, + 0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C, + 0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908, + 0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD, + 0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B, + 0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E, + 0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA, + 0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A, + 0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D, + 0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66, + 0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5, + 0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84, + 0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96, + 0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14, + 0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA, + 0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7, + 0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77, + 0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99, + 0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054, + 0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73, + 0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA, + 0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105, + 0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646, + 0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285, + 0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA, + 0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB, + 0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E, + 0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC, + 0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD, + 0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20, + 0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 }; + +static const u32 ks2[256] = { + 0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7, + 0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF, + 0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF, + 0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504, + 0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4, + 0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE, + 0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC, + 0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B, + 0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332, + 0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527, + 0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58, + 0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C, + 0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22, + 0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17, + 0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60, + 0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115, + 0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99, + 0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0, + 0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74, + 0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D, + 0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3, + 0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3, + 0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979, + 0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C, + 0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA, + 0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A, + 0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086, + 0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC, + 0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24, + 0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2, + 0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84, + 0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C, + 0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09, + 0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10, + 0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE, + 0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027, + 0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0, + 0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634, + 0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188, + 0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC, + 0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8, + 0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837, + 0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 }; + +static const u32 ks3[256] = { + 0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742, + 0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B, + 0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79, + 0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6, + 0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A, + 0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4, + 0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1, + 0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59, + 0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797, + 0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28, + 0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6, + 0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28, + 0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA, + 0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A, + 0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5, + 0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F, + 0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE, + 0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680, + 0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD, + 0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB, + 0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB, + 0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370, + 0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC, + 0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048, + 0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC, + 0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9, + 0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A, + 0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F, + 0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A, + 0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1, + 0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B, + 0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E, + 0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E, + 0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F, + 0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623, + 0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC, + 0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A, + 0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6, + 0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3, + 0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060, + 0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C, + 0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F, + 0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 }; + +static const u32 ps[16+2] = { + 0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0, + 0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C, + 0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B }; + + +#ifdef USE_AMD64_ASM + +/* Assembly implementations of Blowfish. */ +extern void _gcry_blowfish_amd64_do_encrypt(BLOWFISH_context *c, u32 *ret_xl, + u32 *ret_xr); + +extern void _gcry_blowfish_amd64_encrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +extern void _gcry_blowfish_amd64_decrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +/* These assembly implementations process four blocks in parallel. */ +extern void _gcry_blowfish_amd64_ctr_enc(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_blowfish_amd64_cbc_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_blowfish_amd64_cfb_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + _gcry_blowfish_amd64_do_encrypt (bc, ret_xl, ret_xr); +} + +static void +do_encrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_amd64_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_amd64_decrypt_block (context, outbuf, inbuf); +} + +static inline void +blowfish_amd64_ctr_enc(BLOWFISH_context *ctx, byte *out, const byte *in, + byte *ctr) +{ + _gcry_blowfish_amd64_ctr_enc(ctx, out, in, ctr); +} + +static inline void +blowfish_amd64_cbc_dec(BLOWFISH_context *ctx, byte *out, const byte *in, + byte *iv) +{ + _gcry_blowfish_amd64_cbc_dec(ctx, out, in, iv); +} + +static inline void +blowfish_amd64_cfb_dec(BLOWFISH_context *ctx, byte *out, const byte *in, + byte *iv) +{ + _gcry_blowfish_amd64_cfb_dec(ctx, out, in, iv); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +#elif defined(USE_ARM_ASM) + +/* Assembly implementations of Blowfish. */ +extern void _gcry_blowfish_arm_do_encrypt(BLOWFISH_context *c, u32 *ret_xl, + u32 *ret_xr); + +extern void _gcry_blowfish_arm_encrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +extern void _gcry_blowfish_arm_decrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +/* These assembly implementations process two blocks in parallel. */ +extern void _gcry_blowfish_arm_ctr_enc(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_blowfish_arm_cbc_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_blowfish_arm_cfb_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + _gcry_blowfish_arm_do_encrypt (bc, ret_xl, ret_xr); +} + +static void +do_encrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_arm_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_arm_decrypt_block (context, outbuf, inbuf); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +#else /*USE_ARM_ASM*/ + + +#define F(x) ((( s0[(x)>>24] + s1[((x)>>16)&0xff]) \ + ^ s2[((x)>>8)&0xff]) + s3[(x)&0xff] ) +#define R(l,r,i) do { l ^= p[i]; r ^= F(l); } while(0) +#define R3(l,r,i) do { R(l##0,r##0,i);R(l##1,r##1,i);R(l##2,r##2,i);} while(0) + + +static void +do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + u32 xl, xr, *s0, *s1, *s2, *s3, *p; + + xl = *ret_xl; + xr = *ret_xr; + p = bc->p; + s0 = bc->s0; + s1 = bc->s1; + s2 = bc->s2; + s3 = bc->s3; + + R( xl, xr, 0); + R( xr, xl, 1); + R( xl, xr, 2); + R( xr, xl, 3); + R( xl, xr, 4); + R( xr, xl, 5); + R( xl, xr, 6); + R( xr, xl, 7); + R( xl, xr, 8); + R( xr, xl, 9); + R( xl, xr, 10); + R( xr, xl, 11); + R( xl, xr, 12); + R( xr, xl, 13); + R( xl, xr, 14); + R( xr, xl, 15); + + xl ^= p[16]; + xr ^= p[16+1]; + + *ret_xl = xr; + *ret_xr = xl; +} + + +static void +do_encrypt_3 ( BLOWFISH_context *bc, byte *dst, const byte *src ) +{ + u32 xl0, xr0, xl1, xr1, xl2, xr2, *s0, *s1, *s2, *s3, *p; + + xl0 = buf_get_be32(src + 0); + xr0 = buf_get_be32(src + 4); + xl1 = buf_get_be32(src + 8); + xr1 = buf_get_be32(src + 12); + xl2 = buf_get_be32(src + 16); + xr2 = buf_get_be32(src + 20); + p = bc->p; + s0 = bc->s0; + s1 = bc->s1; + s2 = bc->s2; + s3 = bc->s3; + + R3( xl, xr, 0); + R3( xr, xl, 1); + R3( xl, xr, 2); + R3( xr, xl, 3); + R3( xl, xr, 4); + R3( xr, xl, 5); + R3( xl, xr, 6); + R3( xr, xl, 7); + R3( xl, xr, 8); + R3( xr, xl, 9); + R3( xl, xr, 10); + R3( xr, xl, 11); + R3( xl, xr, 12); + R3( xr, xl, 13); + R3( xl, xr, 14); + R3( xr, xl, 15); + + xl0 ^= p[16]; + xr0 ^= p[16+1]; + xl1 ^= p[16]; + xr1 ^= p[16+1]; + xl2 ^= p[16]; + xr2 ^= p[16+1]; + + buf_put_be32(dst + 0, xr0); + buf_put_be32(dst + 4, xl0); + buf_put_be32(dst + 8, xr1); + buf_put_be32(dst + 12, xl1); + buf_put_be32(dst + 16, xr2); + buf_put_be32(dst + 20, xl2); +} + + +static void +decrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + u32 xl, xr, *s0, *s1, *s2, *s3, *p; + + xl = *ret_xl; + xr = *ret_xr; + p = bc->p; + s0 = bc->s0; + s1 = bc->s1; + s2 = bc->s2; + s3 = bc->s3; + + R( xl, xr, 17); + R( xr, xl, 16); + R( xl, xr, 15); + R( xr, xl, 14); + R( xl, xr, 13); + R( xr, xl, 12); + R( xl, xr, 11); + R( xr, xl, 10); + R( xl, xr, 9); + R( xr, xl, 8); + R( xl, xr, 7); + R( xr, xl, 6); + R( xl, xr, 5); + R( xr, xl, 4); + R( xl, xr, 3); + R( xr, xl, 2); + + xl ^= p[1]; + xr ^= p[0]; + + *ret_xl = xr; + *ret_xr = xl; +} + + +static void +do_decrypt_3 ( BLOWFISH_context *bc, byte *dst, const byte *src ) +{ + u32 xl0, xr0, xl1, xr1, xl2, xr2, *s0, *s1, *s2, *s3, *p; + + xl0 = buf_get_be32(src + 0); + xr0 = buf_get_be32(src + 4); + xl1 = buf_get_be32(src + 8); + xr1 = buf_get_be32(src + 12); + xl2 = buf_get_be32(src + 16); + xr2 = buf_get_be32(src + 20); + p = bc->p; + s0 = bc->s0; + s1 = bc->s1; + s2 = bc->s2; + s3 = bc->s3; + + R3( xl, xr, 17); + R3( xr, xl, 16); + R3( xl, xr, 15); + R3( xr, xl, 14); + R3( xl, xr, 13); + R3( xr, xl, 12); + R3( xl, xr, 11); + R3( xr, xl, 10); + R3( xl, xr, 9); + R3( xr, xl, 8); + R3( xl, xr, 7); + R3( xr, xl, 6); + R3( xl, xr, 5); + R3( xr, xl, 4); + R3( xl, xr, 3); + R3( xr, xl, 2); + + xl0 ^= p[1]; + xr0 ^= p[0]; + xl1 ^= p[1]; + xr1 ^= p[0]; + xl2 ^= p[1]; + xr2 ^= p[0]; + + buf_put_be32(dst + 0, xr0); + buf_put_be32(dst + 4, xl0); + buf_put_be32(dst + 8, xr1); + buf_put_be32(dst + 12, xl1); + buf_put_be32(dst + 16, xr2); + buf_put_be32(dst + 20, xl2); +} + +#undef F +#undef R +#undef R3 + +static void +do_encrypt_block ( BLOWFISH_context *bc, byte *outbuf, const byte *inbuf ) +{ + u32 d1, d2; + + d1 = buf_get_be32(inbuf); + d2 = buf_get_be32(inbuf + 4); + do_encrypt( bc, &d1, &d2 ); + buf_put_be32(outbuf, d1); + buf_put_be32(outbuf + 4, d2); +} + +static unsigned int +encrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *bc = (BLOWFISH_context *) context; + do_encrypt_block (bc, outbuf, inbuf); + return /*burn_stack*/ (64); +} + + +static void +do_decrypt_block (BLOWFISH_context *bc, byte *outbuf, const byte *inbuf) +{ + u32 d1, d2; + + d1 = buf_get_be32(inbuf); + d2 = buf_get_be32(inbuf + 4); + decrypt( bc, &d1, &d2 ); + buf_put_be32(outbuf, d1); + buf_put_be32(outbuf + 4, d2); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *bc = (BLOWFISH_context *) context; + do_decrypt_block (bc, outbuf, inbuf); + return /*burn_stack*/ (64); +} + +#endif /*!USE_AMD64_ASM&&!USE_ARM_ASM*/ + + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size BLOWFISH_BLOCKSIZE. */ +static void +_gcry_blowfish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + BLOWFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[BLOWFISH_BLOCKSIZE * 3]; + int burn_stack_depth = (64) + 4 * BLOWFISH_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 5 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + blowfish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 4; + outbuf += 4 * BLOWFISH_BLOCKSIZE; + inbuf += 4 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_blowfish_arm_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 2; + outbuf += 2 * BLOWFISH_BLOCKSIZE; + inbuf += 2 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + for ( ;nblocks >= 3; nblocks -= 3) + { + /* Prepare the counter blocks. */ + cipher_block_cpy (tmpbuf + 0, ctr, BLOWFISH_BLOCKSIZE); + cipher_block_cpy (tmpbuf + 8, ctr, BLOWFISH_BLOCKSIZE); + cipher_block_cpy (tmpbuf + 16, ctr, BLOWFISH_BLOCKSIZE); + cipher_block_add (tmpbuf + 8, 1, BLOWFISH_BLOCKSIZE); + cipher_block_add (tmpbuf + 16, 2, BLOWFISH_BLOCKSIZE); + cipher_block_add (ctr, 3, BLOWFISH_BLOCKSIZE); + /* Encrypt the counter. */ + do_encrypt_3(ctx, tmpbuf, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE * 3); + outbuf += BLOWFISH_BLOCKSIZE * 3; + inbuf += BLOWFISH_BLOCKSIZE * 3; + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + do_encrypt_block(ctx, tmpbuf, ctr); + /* XOR the input with the encrypted counter and store in output. */ + cipher_block_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE); + outbuf += BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + /* Increment the counter. */ + cipher_block_add (ctr, 1, BLOWFISH_BLOCKSIZE); + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_blowfish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + BLOWFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[BLOWFISH_BLOCKSIZE * 3]; + int burn_stack_depth = (64) + 4 * BLOWFISH_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 5 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + blowfish_amd64_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * BLOWFISH_BLOCKSIZE; + inbuf += 4 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_blowfish_arm_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * BLOWFISH_BLOCKSIZE; + inbuf += 2 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + for ( ;nblocks >= 3; nblocks -= 3) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + do_decrypt_3 (ctx, savebuf, inbuf); + + cipher_block_xor_1 (savebuf + 0, iv, BLOWFISH_BLOCKSIZE); + cipher_block_xor_1 (savebuf + 8, inbuf, BLOWFISH_BLOCKSIZE * 2); + cipher_block_cpy (iv, inbuf + 16, BLOWFISH_BLOCKSIZE); + buf_cpy (outbuf, savebuf, BLOWFISH_BLOCKSIZE * 3); + inbuf += BLOWFISH_BLOCKSIZE * 3; + outbuf += BLOWFISH_BLOCKSIZE * 3; + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + do_decrypt_block (ctx, savebuf, inbuf); + + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + inbuf += BLOWFISH_BLOCKSIZE; + outbuf += BLOWFISH_BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_blowfish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + BLOWFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[BLOWFISH_BLOCKSIZE * 3]; + int burn_stack_depth = (64) + 4 * BLOWFISH_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 5 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + blowfish_amd64_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * BLOWFISH_BLOCKSIZE; + inbuf += 4 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_blowfish_arm_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * BLOWFISH_BLOCKSIZE; + inbuf += 2 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + for ( ;nblocks >= 3; nblocks -= 3 ) + { + cipher_block_cpy (tmpbuf + 0, iv, BLOWFISH_BLOCKSIZE); + cipher_block_cpy (tmpbuf + 8, inbuf + 0, BLOWFISH_BLOCKSIZE * 2); + cipher_block_cpy (iv, inbuf + 16, BLOWFISH_BLOCKSIZE); + do_encrypt_3 (ctx, tmpbuf, tmpbuf); + buf_xor (outbuf, inbuf, tmpbuf, BLOWFISH_BLOCKSIZE * 3); + outbuf += BLOWFISH_BLOCKSIZE * 3; + inbuf += BLOWFISH_BLOCKSIZE * 3; + } +#endif + + for ( ;nblocks; nblocks-- ) + { + do_encrypt_block(ctx, iv, iv); + cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + outbuf += BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Run the self-tests for BLOWFISH-CTR, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char * +selftest_ctr (void) +{ + const int nblocks = 4+1; + const int blocksize = BLOWFISH_BLOCKSIZE; + const int context_size = sizeof(BLOWFISH_context); + + return _gcry_selftest_helper_ctr("BLOWFISH", &bf_setkey, + &encrypt_block, nblocks, blocksize, context_size); +} + + +/* Run the self-tests for BLOWFISH-CBC, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cbc (void) +{ + const int nblocks = 4+2; + const int blocksize = BLOWFISH_BLOCKSIZE; + const int context_size = sizeof(BLOWFISH_context); + + return _gcry_selftest_helper_cbc("BLOWFISH", &bf_setkey, + &encrypt_block, nblocks, blocksize, context_size); +} + + +/* Run the self-tests for BLOWFISH-CFB, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cfb (void) +{ + const int nblocks = 4+2; + const int blocksize = BLOWFISH_BLOCKSIZE; + const int context_size = sizeof(BLOWFISH_context); + + return _gcry_selftest_helper_cfb("BLOWFISH", &bf_setkey, + &encrypt_block, nblocks, blocksize, context_size); +} + + +static const char* +selftest(void) +{ + BLOWFISH_context c; + cipher_bulk_ops_t bulk_ops; + byte plain[] = "BLOWFISH"; + byte buffer[8]; + static const byte plain3[] = + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }; + static const byte key3[] = + { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 }; + static const byte cipher3[] = + { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 }; + const char *r; + + bf_setkey( (void *) &c, + (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26, + &bulk_ops ); + encrypt_block( (void *) &c, buffer, plain ); + if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) ) + return "Blowfish selftest failed (1)."; + decrypt_block( (void *) &c, buffer, buffer ); + if( memcmp( buffer, plain, 8 ) ) + return "Blowfish selftest failed (2)."; + + bf_setkey( (void *) &c, key3, 8, &bulk_ops ); + encrypt_block( (void *) &c, buffer, plain3 ); + if( memcmp( buffer, cipher3, 8 ) ) + return "Blowfish selftest failed (3)."; + decrypt_block( (void *) &c, buffer, buffer ); + if( memcmp( buffer, plain3, 8 ) ) + return "Blowfish selftest failed (4)."; + + if ( (r = selftest_cbc ()) ) + return r; + + if ( (r = selftest_cfb ()) ) + return r; + + if ( (r = selftest_ctr ()) ) + return r; + + return NULL; +} + + +struct hashset_elem { + u32 val; + short nidx; + char used; +}; + +static inline byte +val_to_hidx(u32 val) +{ + /* bf sboxes are quite random already. */ + return (val >> 24) ^ (val >> 16) ^ (val >> 8) ^ val; +} + +static inline int +add_val(struct hashset_elem hset[256], u32 val, int *midx, + struct hashset_elem *mpool) +{ + struct hashset_elem *elem; + byte hidx; + + hidx = val_to_hidx(val); + elem = &hset[hidx]; + + /* Check if first is in use. */ + if (elem->used == 0) + { + elem->val = val; + elem->nidx = -1; + elem->used = 1; + return 0; + } + + /* Check if first matches. */ + if (elem->val == val) + return 1; + + for (; elem->nidx >= 0; elem = &mpool[elem->nidx]) + { + /* Check if elem matches. */ + if (elem->val == val) + return 1; + } + + elem->nidx = (*midx)++; + elem = &mpool[elem->nidx]; + + elem->val = val; + elem->nidx = -1; + elem->used = 1; + + return 0; +} + +static gcry_err_code_t +do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen) +{ + struct hashset_elem mempool[4 * 255]; /* Enough entries for the worst case. */ + struct hashset_elem hset[4][256]; + int memidx = 0; + int weak = 0; + int i, j, ret; + u32 data, datal, datar; + static int initialized; + static const char *selftest_failed; + + if( !initialized ) + { + initialized = 1; + selftest_failed = selftest(); + if( selftest_failed ) + log_error ("%s\n", selftest_failed ); + } + if( selftest_failed ) + return GPG_ERR_SELFTEST_FAILED; + + if (keylen < BLOWFISH_KEY_MIN_BITS / 8 || + keylen > BLOWFISH_KEY_MAX_BITS / 8) + return GPG_ERR_INV_KEYLEN; + + memset(hset, 0, sizeof(hset)); + + for(i=0; i < 16+2; i++ ) + c->p[i] = ps[i]; + for(i=0; i < 256; i++ ) + { + c->s0[i] = ks0[i]; + c->s1[i] = ks1[i]; + c->s2[i] = ks2[i]; + c->s3[i] = ks3[i]; + } + + for(i=j=0; i < 16+2; i++ ) + { + data = ((u32)key[j] << 24) | + ((u32)key[(j+1)%keylen] << 16) | + ((u32)key[(j+2)%keylen] << 8) | + ((u32)key[(j+3)%keylen]); + c->p[i] ^= data; + j = (j+4) % keylen; + } + + datal = datar = 0; + for(i=0; i < 16+2; i += 2 ) + { + do_encrypt( c, &datal, &datar ); + c->p[i] = datal; + c->p[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) + { + do_encrypt( c, &datal, &datar ); + c->s0[i] = datal; + c->s0[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[0], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[0], datar, &memidx, mempool); + weak = ret ? 1 : weak; + } + for(i=0; i < 256; i += 2 ) + { + do_encrypt( c, &datal, &datar ); + c->s1[i] = datal; + c->s1[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[1], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[1], datar, &memidx, mempool); + weak = ret ? 1 : weak; + } + for(i=0; i < 256; i += 2 ) + { + do_encrypt( c, &datal, &datar ); + c->s2[i] = datal; + c->s2[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[2], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[2], datar, &memidx, mempool); + weak = ret ? 1 : weak; + } + for(i=0; i < 256; i += 2 ) + { + do_encrypt( c, &datal, &datar ); + c->s3[i] = datal; + c->s3[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[3], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[3], datar, &memidx, mempool); + weak = ret ? 1 : weak; + } + + /* Clear stack. */ + wipememory(hset, sizeof(hset)); + wipememory(mempool, sizeof(mempool[0]) * memidx); + + _gcry_burn_stack (64); + + /* Check for weak key. A weak key is a key in which a value in + the P-array (here c) occurs more than once per table. */ + if (weak) + return GPG_ERR_WEAK_KEY; + + return GPG_ERR_NO_ERROR; +} + + +static gcry_err_code_t +bf_setkey (void *context, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + gcry_err_code_t rc = do_bf_setkey (c, key, keylen); + + /* Setup bulk encryption routines. */ + memset (bulk_ops, 0, sizeof(*bulk_ops)); + bulk_ops->cfb_dec = _gcry_blowfish_cfb_dec; + bulk_ops->cbc_dec = _gcry_blowfish_cbc_dec; + bulk_ops->ctr_enc = _gcry_blowfish_ctr_enc; + + return rc; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_blowfish = + { + GCRY_CIPHER_BLOWFISH, {0, 0}, + "BLOWFISH", NULL, NULL, BLOWFISH_BLOCKSIZE, 128, + sizeof (BLOWFISH_context), + bf_setkey, encrypt_block, decrypt_block + }; diff --git a/comm/third_party/libgcrypt/cipher/bufhelp.h b/comm/third_party/libgcrypt/cipher/bufhelp.h new file mode 100644 index 0000000000..fa5b2e8ece --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/bufhelp.h @@ -0,0 +1,385 @@ +/* bufhelp.h - Some buffer manipulation helpers + * Copyright (C) 2012-2017 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ +#ifndef GCRYPT_BUFHELP_H +#define GCRYPT_BUFHELP_H + + +#include "g10lib.h" +#include "bithelp.h" + + +#undef BUFHELP_UNALIGNED_ACCESS +#if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \ + defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \ + defined(HAVE_GCC_ATTRIBUTE_MAY_ALIAS) +/* Compiler is supports attributes needed for automatically issuing unaligned + memory access instructions. + */ +# define BUFHELP_UNALIGNED_ACCESS 1 +#endif + + +#ifndef BUFHELP_UNALIGNED_ACCESS + +/* Functions for loading and storing unaligned u32 values of different + endianness. */ +static inline u32 buf_get_be32(const void *_buf) +{ + const byte *in = _buf; + return ((u32)in[0] << 24) | ((u32)in[1] << 16) | \ + ((u32)in[2] << 8) | (u32)in[3]; +} + +static inline u32 buf_get_le32(const void *_buf) +{ + const byte *in = _buf; + return ((u32)in[3] << 24) | ((u32)in[2] << 16) | \ + ((u32)in[1] << 8) | (u32)in[0]; +} + +static inline void buf_put_be32(void *_buf, u32 val) +{ + byte *out = _buf; + out[0] = val >> 24; + out[1] = val >> 16; + out[2] = val >> 8; + out[3] = val; +} + +static inline void buf_put_le32(void *_buf, u32 val) +{ + byte *out = _buf; + out[3] = val >> 24; + out[2] = val >> 16; + out[1] = val >> 8; + out[0] = val; +} + + +/* Functions for loading and storing unaligned u64 values of different + endianness. */ +static inline u64 buf_get_be64(const void *_buf) +{ + const byte *in = _buf; + return ((u64)in[0] << 56) | ((u64)in[1] << 48) | \ + ((u64)in[2] << 40) | ((u64)in[3] << 32) | \ + ((u64)in[4] << 24) | ((u64)in[5] << 16) | \ + ((u64)in[6] << 8) | (u64)in[7]; +} + +static inline u64 buf_get_le64(const void *_buf) +{ + const byte *in = _buf; + return ((u64)in[7] << 56) | ((u64)in[6] << 48) | \ + ((u64)in[5] << 40) | ((u64)in[4] << 32) | \ + ((u64)in[3] << 24) | ((u64)in[2] << 16) | \ + ((u64)in[1] << 8) | (u64)in[0]; +} + +static inline void buf_put_be64(void *_buf, u64 val) +{ + byte *out = _buf; + out[0] = val >> 56; + out[1] = val >> 48; + out[2] = val >> 40; + out[3] = val >> 32; + out[4] = val >> 24; + out[5] = val >> 16; + out[6] = val >> 8; + out[7] = val; +} + +static inline void buf_put_le64(void *_buf, u64 val) +{ + byte *out = _buf; + out[7] = val >> 56; + out[6] = val >> 48; + out[5] = val >> 40; + out[4] = val >> 32; + out[3] = val >> 24; + out[2] = val >> 16; + out[1] = val >> 8; + out[0] = val; +} + +#else /*BUFHELP_UNALIGNED_ACCESS*/ + +typedef struct bufhelp_u32_s +{ + u32 a; +} __attribute__((packed, aligned(1), may_alias)) bufhelp_u32_t; + +/* Functions for loading and storing unaligned u32 values of different + endianness. */ +static inline u32 buf_get_be32(const void *_buf) +{ + return be_bswap32(((const bufhelp_u32_t *)_buf)->a); +} + +static inline u32 buf_get_le32(const void *_buf) +{ + return le_bswap32(((const bufhelp_u32_t *)_buf)->a); +} + +static inline void buf_put_be32(void *_buf, u32 val) +{ + bufhelp_u32_t *out = _buf; + out->a = be_bswap32(val); +} + +static inline void buf_put_le32(void *_buf, u32 val) +{ + bufhelp_u32_t *out = _buf; + out->a = le_bswap32(val); +} + + +typedef struct bufhelp_u64_s +{ + u64 a; +} __attribute__((packed, aligned(1), may_alias)) bufhelp_u64_t; + +/* Functions for loading and storing unaligned u64 values of different + endianness. */ +static inline u64 buf_get_be64(const void *_buf) +{ + return be_bswap64(((const bufhelp_u64_t *)_buf)->a); +} + +static inline u64 buf_get_le64(const void *_buf) +{ + return le_bswap64(((const bufhelp_u64_t *)_buf)->a); +} + +static inline void buf_put_be64(void *_buf, u64 val) +{ + bufhelp_u64_t *out = _buf; + out->a = be_bswap64(val); +} + +static inline void buf_put_le64(void *_buf, u64 val) +{ + bufhelp_u64_t *out = _buf; + out->a = le_bswap64(val); +} + +#endif /*BUFHELP_UNALIGNED_ACCESS*/ + + +/* Host-endian get/put macros */ +#ifdef WORDS_BIGENDIAN +# define buf_get_he32 buf_get_be32 +# define buf_put_he32 buf_put_be32 +# define buf_get_he64 buf_get_be64 +# define buf_put_he64 buf_put_be64 +#else +# define buf_get_he32 buf_get_le32 +# define buf_put_he32 buf_put_le32 +# define buf_get_he64 buf_get_le64 +# define buf_put_he64 buf_put_le64 +#endif + + + +/* Optimized function for small buffer copying */ +static inline void +buf_cpy(void *_dst, const void *_src, size_t len) +{ + byte *dst = _dst; + const byte *src = _src; + +#if __GNUC__ >= 4 + if (!__builtin_constant_p (len)) + { + if (UNLIKELY(len == 0)) + return; + memcpy(_dst, _src, len); + return; + } +#endif + + while (len >= sizeof(u64)) + { + buf_put_he64(dst, buf_get_he64(src)); + dst += sizeof(u64); + src += sizeof(u64); + len -= sizeof(u64); + } + + if (len >= sizeof(u32)) + { + buf_put_he32(dst, buf_get_he32(src)); + dst += sizeof(u32); + src += sizeof(u32); + len -= sizeof(u32); + } + + /* Handle tail. */ + for (; len; len--) + *dst++ = *src++; +} + + +/* Optimized function for buffer xoring */ +static inline void +buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len) +{ + byte *dst = _dst; + const byte *src1 = _src1; + const byte *src2 = _src2; + + while (len >= sizeof(u64)) + { + buf_put_he64(dst, buf_get_he64(src1) ^ buf_get_he64(src2)); + dst += sizeof(u64); + src1 += sizeof(u64); + src2 += sizeof(u64); + len -= sizeof(u64); + } + + if (len > sizeof(u32)) + { + buf_put_he32(dst, buf_get_he32(src1) ^ buf_get_he32(src2)); + dst += sizeof(u32); + src1 += sizeof(u32); + src2 += sizeof(u32); + len -= sizeof(u32); + } + + /* Handle tail. */ + for (; len; len--) + *dst++ = *src1++ ^ *src2++; +} + + +/* Optimized function for buffer xoring with two destination buffers. Used + mainly by CFB mode encryption. */ +static inline void +buf_xor_2dst(void *_dst1, void *_dst2, const void *_src, size_t len) +{ + byte *dst1 = _dst1; + byte *dst2 = _dst2; + const byte *src = _src; + + while (len >= sizeof(u64)) + { + u64 temp = buf_get_he64(dst2) ^ buf_get_he64(src); + buf_put_he64(dst2, temp); + buf_put_he64(dst1, temp); + dst2 += sizeof(u64); + dst1 += sizeof(u64); + src += sizeof(u64); + len -= sizeof(u64); + } + + if (len >= sizeof(u32)) + { + u32 temp = buf_get_he32(dst2) ^ buf_get_he32(src); + buf_put_he32(dst2, temp); + buf_put_he32(dst1, temp); + dst2 += sizeof(u32); + dst1 += sizeof(u32); + src += sizeof(u32); + len -= sizeof(u32); + } + + /* Handle tail. */ + for (; len; len--) + *dst1++ = (*dst2++ ^= *src++); +} + + +/* Optimized function for combined buffer xoring and copying. Used by mainly + CBC mode decryption. */ +static inline void +buf_xor_n_copy_2(void *_dst_xor, const void *_src_xor, void *_srcdst_cpy, + const void *_src_cpy, size_t len) +{ + byte *dst_xor = _dst_xor; + byte *srcdst_cpy = _srcdst_cpy; + const byte *src_xor = _src_xor; + const byte *src_cpy = _src_cpy; + + while (len >= sizeof(u64)) + { + u64 temp = buf_get_he64(src_cpy); + buf_put_he64(dst_xor, buf_get_he64(srcdst_cpy) ^ buf_get_he64(src_xor)); + buf_put_he64(srcdst_cpy, temp); + dst_xor += sizeof(u64); + srcdst_cpy += sizeof(u64); + src_xor += sizeof(u64); + src_cpy += sizeof(u64); + len -= sizeof(u64); + } + + if (len >= sizeof(u32)) + { + u32 temp = buf_get_he32(src_cpy); + buf_put_he32(dst_xor, buf_get_he32(srcdst_cpy) ^ buf_get_he32(src_xor)); + buf_put_he32(srcdst_cpy, temp); + dst_xor += sizeof(u32); + srcdst_cpy += sizeof(u32); + src_xor += sizeof(u32); + src_cpy += sizeof(u32); + len -= sizeof(u32); + } + + /* Handle tail. */ + for (; len; len--) + { + byte temp = *src_cpy++; + *dst_xor++ = *srcdst_cpy ^ *src_xor++; + *srcdst_cpy++ = temp; + } +} + + +/* Optimized function for combined buffer xoring and copying. Used by mainly + CFB mode decryption. */ +static inline void +buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len) +{ + buf_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, len); +} + + +/* Constant-time compare of two buffers. Returns 1 if buffers are equal, + and 0 if buffers differ. */ +static inline int +buf_eq_const(const void *_a, const void *_b, size_t len) +{ + const byte *a = _a; + const byte *b = _b; + int ab, ba; + size_t i; + + /* Constant-time compare. */ + for (i = 0, ab = 0, ba = 0; i < len; i++) + { + /* If a[i] != b[i], either ab or ba will be negative. */ + ab |= a[i] - b[i]; + ba |= b[i] - a[i]; + } + + /* 'ab | ba' is negative when buffers are not equal. */ + return (ab | ba) >= 0; +} + + +#endif /*GCRYPT_BUFHELP_H*/ diff --git a/comm/third_party/libgcrypt/cipher/camellia-aarch64.S b/comm/third_party/libgcrypt/cipher/camellia-aarch64.S new file mode 100644 index 0000000000..f498086212 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia-aarch64.S @@ -0,0 +1,586 @@ +/* camellia-aarch64.S - ARMv8/AArch64 assembly implementation of Camellia + * cipher + * + * Copyright (C) 2016 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include "asm-common-aarch64.h" + +#if defined(__AARCH64EL__) +#ifdef HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS + +.text + +/* struct camellia_ctx: */ +#define key_table 0 + +/* register macros */ +#define CTX x0 +#define RDST x1 +#define RSRC x2 +#define RKEYBITS w3 + +#define RTAB1 x4 +#define RTAB2 x5 +#define RTAB3 x6 +#define RTAB4 x7 +#define RMASK w8 + +#define IL w9 +#define IR w10 + +#define xIL x9 +#define xIR x10 + +#define XL w11 +#define XR w12 +#define YL w13 +#define YR w14 + +#define RT0 w15 +#define RT1 w16 +#define RT2 w17 +#define RT3 w19 + +#define xRT0 x15 +#define xRT1 x16 +#define xRT2 x17 +#define xRT3 x19 + +#ifdef __AARCH64EL__ + #define host_to_be(reg, rtmp) \ + rev reg, reg; + #define be_to_host(reg, rtmp) \ + rev reg, reg; +#else + /* nop on big-endian */ + #define host_to_be(reg, rtmp) /*_*/ + #define be_to_host(reg, rtmp) /*_*/ +#endif + +#define ldr_input_aligned_be(rin, a, b, c, d, rtmp) \ + ldr a, [rin, #0]; \ + ldr b, [rin, #4]; \ + be_to_host(a, rtmp); \ + ldr c, [rin, #8]; \ + be_to_host(b, rtmp); \ + ldr d, [rin, #12]; \ + be_to_host(c, rtmp); \ + be_to_host(d, rtmp); + +#define str_output_aligned_be(rout, a, b, c, d, rtmp) \ + be_to_host(a, rtmp); \ + be_to_host(b, rtmp); \ + str a, [rout, #0]; \ + be_to_host(c, rtmp); \ + str b, [rout, #4]; \ + be_to_host(d, rtmp); \ + str c, [rout, #8]; \ + str d, [rout, #12]; + +/* unaligned word reads/writes allowed */ +#define ldr_input_be(rin, ra, rb, rc, rd, rtmp) \ + ldr_input_aligned_be(rin, ra, rb, rc, rd, rtmp) + +#define str_output_be(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + str_output_aligned_be(rout, ra, rb, rc, rd, rtmp0) + +/********************************************************************** + 1-way camellia + **********************************************************************/ +#define roundsm(xl, xr, kl, kr, yl, yr) \ + ldr RT2, [CTX, #(key_table + ((kl) * 4))]; \ + and IR, RMASK, xr, lsl#(4); /*sp1110*/ \ + ldr RT3, [CTX, #(key_table + ((kr) * 4))]; \ + and IL, RMASK, xl, lsr#(24 - 4); /*sp1110*/ \ + and RT0, RMASK, xr, lsr#(16 - 4); /*sp3033*/ \ + ldr IR, [RTAB1, xIR]; \ + and RT1, RMASK, xl, lsr#(8 - 4); /*sp3033*/ \ + eor yl, yl, RT2; \ + ldr IL, [RTAB1, xIL]; \ + eor yr, yr, RT3; \ + \ + ldr RT0, [RTAB3, xRT0]; \ + ldr RT1, [RTAB3, xRT1]; \ + \ + and RT2, RMASK, xr, lsr#(24 - 4); /*sp0222*/ \ + and RT3, RMASK, xl, lsr#(16 - 4); /*sp0222*/ \ + \ + eor IR, IR, RT0; \ + eor IL, IL, RT1; \ + \ + ldr RT2, [RTAB2, xRT2]; \ + and RT0, RMASK, xr, lsr#(8 - 4); /*sp4404*/ \ + ldr RT3, [RTAB2, xRT3]; \ + and RT1, RMASK, xl, lsl#(4); /*sp4404*/ \ + \ + ldr RT0, [RTAB4, xRT0]; \ + ldr RT1, [RTAB4, xRT1]; \ + \ + eor IR, IR, RT2; \ + eor IL, IL, RT3; \ + eor IR, IR, RT0; \ + eor IL, IL, RT1; \ + \ + eor IR, IR, IL; \ + eor yr, yr, IL, ror#8; \ + eor yl, yl, IR; \ + eor yr, yr, IR; + +#define enc_rounds(n) \ + roundsm(XL, XR, ((n) + 2) * 2 + 0, ((n) + 2) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 3) * 2 + 0, ((n) + 3) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 4) * 2 + 0, ((n) + 4) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 5) * 2 + 0, ((n) + 5) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 6) * 2 + 0, ((n) + 6) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 7) * 2 + 0, ((n) + 7) * 2 + 1, XL, XR); + +#define dec_rounds(n) \ + roundsm(XL, XR, ((n) + 7) * 2 + 0, ((n) + 7) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 6) * 2 + 0, ((n) + 6) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 5) * 2 + 0, ((n) + 5) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 4) * 2 + 0, ((n) + 4) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 3) * 2 + 0, ((n) + 3) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 2) * 2 + 0, ((n) + 2) * 2 + 1, XL, XR); + +/* perform FL and FLâ»Â¹ */ +#define fls(ll, lr, rl, rr, kll, klr, krl, krr) \ + ldr RT0, [CTX, #(key_table + ((kll) * 4))]; \ + ldr RT2, [CTX, #(key_table + ((krr) * 4))]; \ + and RT0, RT0, ll; \ + ldr RT3, [CTX, #(key_table + ((krl) * 4))]; \ + orr RT2, RT2, rr; \ + ldr RT1, [CTX, #(key_table + ((klr) * 4))]; \ + eor rl, rl, RT2; \ + eor lr, lr, RT0, ror#31; \ + and RT3, RT3, rl; \ + orr RT1, RT1, lr; \ + eor ll, ll, RT1; \ + eor rr, rr, RT3, ror#31; + +#define enc_fls(n) \ + fls(XL, XR, YL, YR, \ + (n) * 2 + 0, (n) * 2 + 1, \ + (n) * 2 + 2, (n) * 2 + 3); + +#define dec_fls(n) \ + fls(XL, XR, YL, YR, \ + (n) * 2 + 2, (n) * 2 + 3, \ + (n) * 2 + 0, (n) * 2 + 1); + +#define inpack(n) \ + ldr_input_be(RSRC, XL, XR, YL, YR, RT0); \ + ldr RT0, [CTX, #(key_table + ((n) * 8) + 0)]; \ + ldr RT1, [CTX, #(key_table + ((n) * 8) + 4)]; \ + eor XL, XL, RT0; \ + eor XR, XR, RT1; + +#define outunpack(n) \ + ldr RT0, [CTX, #(key_table + ((n) * 8) + 0)]; \ + ldr RT1, [CTX, #(key_table + ((n) * 8) + 4)]; \ + eor YL, YL, RT0; \ + eor YR, YR, RT1; \ + str_output_be(RDST, YL, YR, XL, XR, RT0, RT1); + +.globl _gcry_camellia_arm_encrypt_block +ELF(.type _gcry_camellia_arm_encrypt_block,@function;) + +_gcry_camellia_arm_encrypt_block: + CFI_STARTPROC() + stp x19, x30, [sp, #-16]! + CFI_ADJUST_CFA_OFFSET(16) + CFI_REG_ON_STACK(19, 0) + CFI_REG_ON_STACK(30, 8) + + /* input: + * x0: keytable + * x1: dst + * x2: src + * w3: keybitlen + */ + + adr RTAB1, _gcry_camellia_arm_tables; + mov RMASK, #(0xff<<4); /* byte mask */ + add RTAB2, RTAB1, #(1 * 4); + add RTAB3, RTAB1, #(2 * 4); + add RTAB4, RTAB1, #(3 * 4); + + inpack(0); + + enc_rounds(0); + enc_fls(8); + enc_rounds(8); + enc_fls(16); + enc_rounds(16); + + cmp RKEYBITS, #(16 * 8); + bne .Lenc_256; + + outunpack(24); + + CFI_REMEMBER_STATE() + ldp x19, x30, [sp], #16 + CFI_ADJUST_CFA_OFFSET(-16) + CFI_RESTORE(x19) + CFI_RESTORE(x30) + ret; + CFI_RESTORE_STATE() +.ltorg + +.Lenc_256: + enc_fls(24); + enc_rounds(24); + + outunpack(32); + + ldp x19, x30, [sp], #16 + CFI_ADJUST_CFA_OFFSET(-16) + CFI_RESTORE(x19) + CFI_RESTORE(x30) + ret; + CFI_ENDPROC() +.ltorg +ELF(.size _gcry_camellia_arm_encrypt_block,.-_gcry_camellia_arm_encrypt_block;) + +.globl _gcry_camellia_arm_decrypt_block +ELF(.type _gcry_camellia_arm_decrypt_block,@function;) + +_gcry_camellia_arm_decrypt_block: + CFI_STARTPROC() + stp x19, x30, [sp, #-16]! + CFI_ADJUST_CFA_OFFSET(16) + CFI_REG_ON_STACK(19, 0) + CFI_REG_ON_STACK(30, 8) + + /* input: + * x0: keytable + * x1: dst + * x2: src + * w3: keybitlen + */ + + adr RTAB1, _gcry_camellia_arm_tables; + mov RMASK, #(0xff<<4); /* byte mask */ + add RTAB2, RTAB1, #(1 * 4); + add RTAB3, RTAB1, #(2 * 4); + add RTAB4, RTAB1, #(3 * 4); + + cmp RKEYBITS, #(16 * 8); + bne .Ldec_256; + + inpack(24); + +.Ldec_128: + dec_rounds(16); + dec_fls(16); + dec_rounds(8); + dec_fls(8); + dec_rounds(0); + + outunpack(0); + + CFI_REMEMBER_STATE() + ldp x19, x30, [sp], #16 + CFI_ADJUST_CFA_OFFSET(-16) + CFI_RESTORE(x19) + CFI_RESTORE(x30) + ret; + CFI_RESTORE_STATE() +.ltorg + +.Ldec_256: + inpack(32); + dec_rounds(24); + dec_fls(24); + + b .Ldec_128; + CFI_ENDPROC() +.ltorg +ELF(.size _gcry_camellia_arm_decrypt_block,.-_gcry_camellia_arm_decrypt_block;) + +/* Encryption/Decryption tables */ +ELF(.type _gcry_camellia_arm_tables,@object;) +.balign 32 +_gcry_camellia_arm_tables: +.Lcamellia_sp1110: +.long 0x70707000 +.Lcamellia_sp0222: + .long 0x00e0e0e0 +.Lcamellia_sp3033: + .long 0x38003838 +.Lcamellia_sp4404: + .long 0x70700070 +.long 0x82828200, 0x00050505, 0x41004141, 0x2c2c002c +.long 0x2c2c2c00, 0x00585858, 0x16001616, 0xb3b300b3 +.long 0xececec00, 0x00d9d9d9, 0x76007676, 0xc0c000c0 +.long 0xb3b3b300, 0x00676767, 0xd900d9d9, 0xe4e400e4 +.long 0x27272700, 0x004e4e4e, 0x93009393, 0x57570057 +.long 0xc0c0c000, 0x00818181, 0x60006060, 0xeaea00ea +.long 0xe5e5e500, 0x00cbcbcb, 0xf200f2f2, 0xaeae00ae +.long 0xe4e4e400, 0x00c9c9c9, 0x72007272, 0x23230023 +.long 0x85858500, 0x000b0b0b, 0xc200c2c2, 0x6b6b006b +.long 0x57575700, 0x00aeaeae, 0xab00abab, 0x45450045 +.long 0x35353500, 0x006a6a6a, 0x9a009a9a, 0xa5a500a5 +.long 0xeaeaea00, 0x00d5d5d5, 0x75007575, 0xeded00ed +.long 0x0c0c0c00, 0x00181818, 0x06000606, 0x4f4f004f +.long 0xaeaeae00, 0x005d5d5d, 0x57005757, 0x1d1d001d +.long 0x41414100, 0x00828282, 0xa000a0a0, 0x92920092 +.long 0x23232300, 0x00464646, 0x91009191, 0x86860086 +.long 0xefefef00, 0x00dfdfdf, 0xf700f7f7, 0xafaf00af +.long 0x6b6b6b00, 0x00d6d6d6, 0xb500b5b5, 0x7c7c007c +.long 0x93939300, 0x00272727, 0xc900c9c9, 0x1f1f001f +.long 0x45454500, 0x008a8a8a, 0xa200a2a2, 0x3e3e003e +.long 0x19191900, 0x00323232, 0x8c008c8c, 0xdcdc00dc +.long 0xa5a5a500, 0x004b4b4b, 0xd200d2d2, 0x5e5e005e +.long 0x21212100, 0x00424242, 0x90009090, 0x0b0b000b +.long 0xededed00, 0x00dbdbdb, 0xf600f6f6, 0xa6a600a6 +.long 0x0e0e0e00, 0x001c1c1c, 0x07000707, 0x39390039 +.long 0x4f4f4f00, 0x009e9e9e, 0xa700a7a7, 0xd5d500d5 +.long 0x4e4e4e00, 0x009c9c9c, 0x27002727, 0x5d5d005d +.long 0x1d1d1d00, 0x003a3a3a, 0x8e008e8e, 0xd9d900d9 +.long 0x65656500, 0x00cacaca, 0xb200b2b2, 0x5a5a005a +.long 0x92929200, 0x00252525, 0x49004949, 0x51510051 +.long 0xbdbdbd00, 0x007b7b7b, 0xde00dede, 0x6c6c006c +.long 0x86868600, 0x000d0d0d, 0x43004343, 0x8b8b008b +.long 0xb8b8b800, 0x00717171, 0x5c005c5c, 0x9a9a009a +.long 0xafafaf00, 0x005f5f5f, 0xd700d7d7, 0xfbfb00fb +.long 0x8f8f8f00, 0x001f1f1f, 0xc700c7c7, 0xb0b000b0 +.long 0x7c7c7c00, 0x00f8f8f8, 0x3e003e3e, 0x74740074 +.long 0xebebeb00, 0x00d7d7d7, 0xf500f5f5, 0x2b2b002b +.long 0x1f1f1f00, 0x003e3e3e, 0x8f008f8f, 0xf0f000f0 +.long 0xcecece00, 0x009d9d9d, 0x67006767, 0x84840084 +.long 0x3e3e3e00, 0x007c7c7c, 0x1f001f1f, 0xdfdf00df +.long 0x30303000, 0x00606060, 0x18001818, 0xcbcb00cb +.long 0xdcdcdc00, 0x00b9b9b9, 0x6e006e6e, 0x34340034 +.long 0x5f5f5f00, 0x00bebebe, 0xaf00afaf, 0x76760076 +.long 0x5e5e5e00, 0x00bcbcbc, 0x2f002f2f, 0x6d6d006d +.long 0xc5c5c500, 0x008b8b8b, 0xe200e2e2, 0xa9a900a9 +.long 0x0b0b0b00, 0x00161616, 0x85008585, 0xd1d100d1 +.long 0x1a1a1a00, 0x00343434, 0x0d000d0d, 0x04040004 +.long 0xa6a6a600, 0x004d4d4d, 0x53005353, 0x14140014 +.long 0xe1e1e100, 0x00c3c3c3, 0xf000f0f0, 0x3a3a003a +.long 0x39393900, 0x00727272, 0x9c009c9c, 0xdede00de +.long 0xcacaca00, 0x00959595, 0x65006565, 0x11110011 +.long 0xd5d5d500, 0x00ababab, 0xea00eaea, 0x32320032 +.long 0x47474700, 0x008e8e8e, 0xa300a3a3, 0x9c9c009c +.long 0x5d5d5d00, 0x00bababa, 0xae00aeae, 0x53530053 +.long 0x3d3d3d00, 0x007a7a7a, 0x9e009e9e, 0xf2f200f2 +.long 0xd9d9d900, 0x00b3b3b3, 0xec00ecec, 0xfefe00fe +.long 0x01010100, 0x00020202, 0x80008080, 0xcfcf00cf +.long 0x5a5a5a00, 0x00b4b4b4, 0x2d002d2d, 0xc3c300c3 +.long 0xd6d6d600, 0x00adadad, 0x6b006b6b, 0x7a7a007a +.long 0x51515100, 0x00a2a2a2, 0xa800a8a8, 0x24240024 +.long 0x56565600, 0x00acacac, 0x2b002b2b, 0xe8e800e8 +.long 0x6c6c6c00, 0x00d8d8d8, 0x36003636, 0x60600060 +.long 0x4d4d4d00, 0x009a9a9a, 0xa600a6a6, 0x69690069 +.long 0x8b8b8b00, 0x00171717, 0xc500c5c5, 0xaaaa00aa +.long 0x0d0d0d00, 0x001a1a1a, 0x86008686, 0xa0a000a0 +.long 0x9a9a9a00, 0x00353535, 0x4d004d4d, 0xa1a100a1 +.long 0x66666600, 0x00cccccc, 0x33003333, 0x62620062 +.long 0xfbfbfb00, 0x00f7f7f7, 0xfd00fdfd, 0x54540054 +.long 0xcccccc00, 0x00999999, 0x66006666, 0x1e1e001e +.long 0xb0b0b000, 0x00616161, 0x58005858, 0xe0e000e0 +.long 0x2d2d2d00, 0x005a5a5a, 0x96009696, 0x64640064 +.long 0x74747400, 0x00e8e8e8, 0x3a003a3a, 0x10100010 +.long 0x12121200, 0x00242424, 0x09000909, 0x00000000 +.long 0x2b2b2b00, 0x00565656, 0x95009595, 0xa3a300a3 +.long 0x20202000, 0x00404040, 0x10001010, 0x75750075 +.long 0xf0f0f000, 0x00e1e1e1, 0x78007878, 0x8a8a008a +.long 0xb1b1b100, 0x00636363, 0xd800d8d8, 0xe6e600e6 +.long 0x84848400, 0x00090909, 0x42004242, 0x09090009 +.long 0x99999900, 0x00333333, 0xcc00cccc, 0xdddd00dd +.long 0xdfdfdf00, 0x00bfbfbf, 0xef00efef, 0x87870087 +.long 0x4c4c4c00, 0x00989898, 0x26002626, 0x83830083 +.long 0xcbcbcb00, 0x00979797, 0xe500e5e5, 0xcdcd00cd +.long 0xc2c2c200, 0x00858585, 0x61006161, 0x90900090 +.long 0x34343400, 0x00686868, 0x1a001a1a, 0x73730073 +.long 0x7e7e7e00, 0x00fcfcfc, 0x3f003f3f, 0xf6f600f6 +.long 0x76767600, 0x00ececec, 0x3b003b3b, 0x9d9d009d +.long 0x05050500, 0x000a0a0a, 0x82008282, 0xbfbf00bf +.long 0x6d6d6d00, 0x00dadada, 0xb600b6b6, 0x52520052 +.long 0xb7b7b700, 0x006f6f6f, 0xdb00dbdb, 0xd8d800d8 +.long 0xa9a9a900, 0x00535353, 0xd400d4d4, 0xc8c800c8 +.long 0x31313100, 0x00626262, 0x98009898, 0xc6c600c6 +.long 0xd1d1d100, 0x00a3a3a3, 0xe800e8e8, 0x81810081 +.long 0x17171700, 0x002e2e2e, 0x8b008b8b, 0x6f6f006f +.long 0x04040400, 0x00080808, 0x02000202, 0x13130013 +.long 0xd7d7d700, 0x00afafaf, 0xeb00ebeb, 0x63630063 +.long 0x14141400, 0x00282828, 0x0a000a0a, 0xe9e900e9 +.long 0x58585800, 0x00b0b0b0, 0x2c002c2c, 0xa7a700a7 +.long 0x3a3a3a00, 0x00747474, 0x1d001d1d, 0x9f9f009f +.long 0x61616100, 0x00c2c2c2, 0xb000b0b0, 0xbcbc00bc +.long 0xdedede00, 0x00bdbdbd, 0x6f006f6f, 0x29290029 +.long 0x1b1b1b00, 0x00363636, 0x8d008d8d, 0xf9f900f9 +.long 0x11111100, 0x00222222, 0x88008888, 0x2f2f002f +.long 0x1c1c1c00, 0x00383838, 0x0e000e0e, 0xb4b400b4 +.long 0x32323200, 0x00646464, 0x19001919, 0x78780078 +.long 0x0f0f0f00, 0x001e1e1e, 0x87008787, 0x06060006 +.long 0x9c9c9c00, 0x00393939, 0x4e004e4e, 0xe7e700e7 +.long 0x16161600, 0x002c2c2c, 0x0b000b0b, 0x71710071 +.long 0x53535300, 0x00a6a6a6, 0xa900a9a9, 0xd4d400d4 +.long 0x18181800, 0x00303030, 0x0c000c0c, 0xabab00ab +.long 0xf2f2f200, 0x00e5e5e5, 0x79007979, 0x88880088 +.long 0x22222200, 0x00444444, 0x11001111, 0x8d8d008d +.long 0xfefefe00, 0x00fdfdfd, 0x7f007f7f, 0x72720072 +.long 0x44444400, 0x00888888, 0x22002222, 0xb9b900b9 +.long 0xcfcfcf00, 0x009f9f9f, 0xe700e7e7, 0xf8f800f8 +.long 0xb2b2b200, 0x00656565, 0x59005959, 0xacac00ac +.long 0xc3c3c300, 0x00878787, 0xe100e1e1, 0x36360036 +.long 0xb5b5b500, 0x006b6b6b, 0xda00dada, 0x2a2a002a +.long 0x7a7a7a00, 0x00f4f4f4, 0x3d003d3d, 0x3c3c003c +.long 0x91919100, 0x00232323, 0xc800c8c8, 0xf1f100f1 +.long 0x24242400, 0x00484848, 0x12001212, 0x40400040 +.long 0x08080800, 0x00101010, 0x04000404, 0xd3d300d3 +.long 0xe8e8e800, 0x00d1d1d1, 0x74007474, 0xbbbb00bb +.long 0xa8a8a800, 0x00515151, 0x54005454, 0x43430043 +.long 0x60606000, 0x00c0c0c0, 0x30003030, 0x15150015 +.long 0xfcfcfc00, 0x00f9f9f9, 0x7e007e7e, 0xadad00ad +.long 0x69696900, 0x00d2d2d2, 0xb400b4b4, 0x77770077 +.long 0x50505000, 0x00a0a0a0, 0x28002828, 0x80800080 +.long 0xaaaaaa00, 0x00555555, 0x55005555, 0x82820082 +.long 0xd0d0d000, 0x00a1a1a1, 0x68006868, 0xecec00ec +.long 0xa0a0a000, 0x00414141, 0x50005050, 0x27270027 +.long 0x7d7d7d00, 0x00fafafa, 0xbe00bebe, 0xe5e500e5 +.long 0xa1a1a100, 0x00434343, 0xd000d0d0, 0x85850085 +.long 0x89898900, 0x00131313, 0xc400c4c4, 0x35350035 +.long 0x62626200, 0x00c4c4c4, 0x31003131, 0x0c0c000c +.long 0x97979700, 0x002f2f2f, 0xcb00cbcb, 0x41410041 +.long 0x54545400, 0x00a8a8a8, 0x2a002a2a, 0xefef00ef +.long 0x5b5b5b00, 0x00b6b6b6, 0xad00adad, 0x93930093 +.long 0x1e1e1e00, 0x003c3c3c, 0x0f000f0f, 0x19190019 +.long 0x95959500, 0x002b2b2b, 0xca00caca, 0x21210021 +.long 0xe0e0e000, 0x00c1c1c1, 0x70007070, 0x0e0e000e +.long 0xffffff00, 0x00ffffff, 0xff00ffff, 0x4e4e004e +.long 0x64646400, 0x00c8c8c8, 0x32003232, 0x65650065 +.long 0xd2d2d200, 0x00a5a5a5, 0x69006969, 0xbdbd00bd +.long 0x10101000, 0x00202020, 0x08000808, 0xb8b800b8 +.long 0xc4c4c400, 0x00898989, 0x62006262, 0x8f8f008f +.long 0x00000000, 0x00000000, 0x00000000, 0xebeb00eb +.long 0x48484800, 0x00909090, 0x24002424, 0xcece00ce +.long 0xa3a3a300, 0x00474747, 0xd100d1d1, 0x30300030 +.long 0xf7f7f700, 0x00efefef, 0xfb00fbfb, 0x5f5f005f +.long 0x75757500, 0x00eaeaea, 0xba00baba, 0xc5c500c5 +.long 0xdbdbdb00, 0x00b7b7b7, 0xed00eded, 0x1a1a001a +.long 0x8a8a8a00, 0x00151515, 0x45004545, 0xe1e100e1 +.long 0x03030300, 0x00060606, 0x81008181, 0xcaca00ca +.long 0xe6e6e600, 0x00cdcdcd, 0x73007373, 0x47470047 +.long 0xdadada00, 0x00b5b5b5, 0x6d006d6d, 0x3d3d003d +.long 0x09090900, 0x00121212, 0x84008484, 0x01010001 +.long 0x3f3f3f00, 0x007e7e7e, 0x9f009f9f, 0xd6d600d6 +.long 0xdddddd00, 0x00bbbbbb, 0xee00eeee, 0x56560056 +.long 0x94949400, 0x00292929, 0x4a004a4a, 0x4d4d004d +.long 0x87878700, 0x000f0f0f, 0xc300c3c3, 0x0d0d000d +.long 0x5c5c5c00, 0x00b8b8b8, 0x2e002e2e, 0x66660066 +.long 0x83838300, 0x00070707, 0xc100c1c1, 0xcccc00cc +.long 0x02020200, 0x00040404, 0x01000101, 0x2d2d002d +.long 0xcdcdcd00, 0x009b9b9b, 0xe600e6e6, 0x12120012 +.long 0x4a4a4a00, 0x00949494, 0x25002525, 0x20200020 +.long 0x90909000, 0x00212121, 0x48004848, 0xb1b100b1 +.long 0x33333300, 0x00666666, 0x99009999, 0x99990099 +.long 0x73737300, 0x00e6e6e6, 0xb900b9b9, 0x4c4c004c +.long 0x67676700, 0x00cecece, 0xb300b3b3, 0xc2c200c2 +.long 0xf6f6f600, 0x00ededed, 0x7b007b7b, 0x7e7e007e +.long 0xf3f3f300, 0x00e7e7e7, 0xf900f9f9, 0x05050005 +.long 0x9d9d9d00, 0x003b3b3b, 0xce00cece, 0xb7b700b7 +.long 0x7f7f7f00, 0x00fefefe, 0xbf00bfbf, 0x31310031 +.long 0xbfbfbf00, 0x007f7f7f, 0xdf00dfdf, 0x17170017 +.long 0xe2e2e200, 0x00c5c5c5, 0x71007171, 0xd7d700d7 +.long 0x52525200, 0x00a4a4a4, 0x29002929, 0x58580058 +.long 0x9b9b9b00, 0x00373737, 0xcd00cdcd, 0x61610061 +.long 0xd8d8d800, 0x00b1b1b1, 0x6c006c6c, 0x1b1b001b +.long 0x26262600, 0x004c4c4c, 0x13001313, 0x1c1c001c +.long 0xc8c8c800, 0x00919191, 0x64006464, 0x0f0f000f +.long 0x37373700, 0x006e6e6e, 0x9b009b9b, 0x16160016 +.long 0xc6c6c600, 0x008d8d8d, 0x63006363, 0x18180018 +.long 0x3b3b3b00, 0x00767676, 0x9d009d9d, 0x22220022 +.long 0x81818100, 0x00030303, 0xc000c0c0, 0x44440044 +.long 0x96969600, 0x002d2d2d, 0x4b004b4b, 0xb2b200b2 +.long 0x6f6f6f00, 0x00dedede, 0xb700b7b7, 0xb5b500b5 +.long 0x4b4b4b00, 0x00969696, 0xa500a5a5, 0x91910091 +.long 0x13131300, 0x00262626, 0x89008989, 0x08080008 +.long 0xbebebe00, 0x007d7d7d, 0x5f005f5f, 0xa8a800a8 +.long 0x63636300, 0x00c6c6c6, 0xb100b1b1, 0xfcfc00fc +.long 0x2e2e2e00, 0x005c5c5c, 0x17001717, 0x50500050 +.long 0xe9e9e900, 0x00d3d3d3, 0xf400f4f4, 0xd0d000d0 +.long 0x79797900, 0x00f2f2f2, 0xbc00bcbc, 0x7d7d007d +.long 0xa7a7a700, 0x004f4f4f, 0xd300d3d3, 0x89890089 +.long 0x8c8c8c00, 0x00191919, 0x46004646, 0x97970097 +.long 0x9f9f9f00, 0x003f3f3f, 0xcf00cfcf, 0x5b5b005b +.long 0x6e6e6e00, 0x00dcdcdc, 0x37003737, 0x95950095 +.long 0xbcbcbc00, 0x00797979, 0x5e005e5e, 0xffff00ff +.long 0x8e8e8e00, 0x001d1d1d, 0x47004747, 0xd2d200d2 +.long 0x29292900, 0x00525252, 0x94009494, 0xc4c400c4 +.long 0xf5f5f500, 0x00ebebeb, 0xfa00fafa, 0x48480048 +.long 0xf9f9f900, 0x00f3f3f3, 0xfc00fcfc, 0xf7f700f7 +.long 0xb6b6b600, 0x006d6d6d, 0x5b005b5b, 0xdbdb00db +.long 0x2f2f2f00, 0x005e5e5e, 0x97009797, 0x03030003 +.long 0xfdfdfd00, 0x00fbfbfb, 0xfe00fefe, 0xdada00da +.long 0xb4b4b400, 0x00696969, 0x5a005a5a, 0x3f3f003f +.long 0x59595900, 0x00b2b2b2, 0xac00acac, 0x94940094 +.long 0x78787800, 0x00f0f0f0, 0x3c003c3c, 0x5c5c005c +.long 0x98989800, 0x00313131, 0x4c004c4c, 0x02020002 +.long 0x06060600, 0x000c0c0c, 0x03000303, 0x4a4a004a +.long 0x6a6a6a00, 0x00d4d4d4, 0x35003535, 0x33330033 +.long 0xe7e7e700, 0x00cfcfcf, 0xf300f3f3, 0x67670067 +.long 0x46464600, 0x008c8c8c, 0x23002323, 0xf3f300f3 +.long 0x71717100, 0x00e2e2e2, 0xb800b8b8, 0x7f7f007f +.long 0xbababa00, 0x00757575, 0x5d005d5d, 0xe2e200e2 +.long 0xd4d4d400, 0x00a9a9a9, 0x6a006a6a, 0x9b9b009b +.long 0x25252500, 0x004a4a4a, 0x92009292, 0x26260026 +.long 0xababab00, 0x00575757, 0xd500d5d5, 0x37370037 +.long 0x42424200, 0x00848484, 0x21002121, 0x3b3b003b +.long 0x88888800, 0x00111111, 0x44004444, 0x96960096 +.long 0xa2a2a200, 0x00454545, 0x51005151, 0x4b4b004b +.long 0x8d8d8d00, 0x001b1b1b, 0xc600c6c6, 0xbebe00be +.long 0xfafafa00, 0x00f5f5f5, 0x7d007d7d, 0x2e2e002e +.long 0x72727200, 0x00e4e4e4, 0x39003939, 0x79790079 +.long 0x07070700, 0x000e0e0e, 0x83008383, 0x8c8c008c +.long 0xb9b9b900, 0x00737373, 0xdc00dcdc, 0x6e6e006e +.long 0x55555500, 0x00aaaaaa, 0xaa00aaaa, 0x8e8e008e +.long 0xf8f8f800, 0x00f1f1f1, 0x7c007c7c, 0xf5f500f5 +.long 0xeeeeee00, 0x00dddddd, 0x77007777, 0xb6b600b6 +.long 0xacacac00, 0x00595959, 0x56005656, 0xfdfd00fd +.long 0x0a0a0a00, 0x00141414, 0x05000505, 0x59590059 +.long 0x36363600, 0x006c6c6c, 0x1b001b1b, 0x98980098 +.long 0x49494900, 0x00929292, 0xa400a4a4, 0x6a6a006a +.long 0x2a2a2a00, 0x00545454, 0x15001515, 0x46460046 +.long 0x68686800, 0x00d0d0d0, 0x34003434, 0xbaba00ba +.long 0x3c3c3c00, 0x00787878, 0x1e001e1e, 0x25250025 +.long 0x38383800, 0x00707070, 0x1c001c1c, 0x42420042 +.long 0xf1f1f100, 0x00e3e3e3, 0xf800f8f8, 0xa2a200a2 +.long 0xa4a4a400, 0x00494949, 0x52005252, 0xfafa00fa +.long 0x40404000, 0x00808080, 0x20002020, 0x07070007 +.long 0x28282800, 0x00505050, 0x14001414, 0x55550055 +.long 0xd3d3d300, 0x00a7a7a7, 0xe900e9e9, 0xeeee00ee +.long 0x7b7b7b00, 0x00f6f6f6, 0xbd00bdbd, 0x0a0a000a +.long 0xbbbbbb00, 0x00777777, 0xdd00dddd, 0x49490049 +.long 0xc9c9c900, 0x00939393, 0xe400e4e4, 0x68680068 +.long 0x43434300, 0x00868686, 0xa100a1a1, 0x38380038 +.long 0xc1c1c100, 0x00838383, 0xe000e0e0, 0xa4a400a4 +.long 0x15151500, 0x002a2a2a, 0x8a008a8a, 0x28280028 +.long 0xe3e3e300, 0x00c7c7c7, 0xf100f1f1, 0x7b7b007b +.long 0xadadad00, 0x005b5b5b, 0xd600d6d6, 0xc9c900c9 +.long 0xf4f4f400, 0x00e9e9e9, 0x7a007a7a, 0xc1c100c1 +.long 0x77777700, 0x00eeeeee, 0xbb00bbbb, 0xe3e300e3 +.long 0xc7c7c700, 0x008f8f8f, 0xe300e3e3, 0xf4f400f4 +.long 0x80808000, 0x00010101, 0x40004040, 0xc7c700c7 +.long 0x9e9e9e00, 0x003d3d3d, 0x4f004f4f, 0x9e9e009e +ELF(.size _gcry_camellia_arm_tables,.-_gcry_camellia_arm_tables;) + +#endif /*HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS*/ +#endif /*__AARCH64EL__*/ diff --git a/comm/third_party/libgcrypt/cipher/camellia-aesni-avx-amd64.S b/comm/third_party/libgcrypt/cipher/camellia-aesni-avx-amd64.S new file mode 100644 index 0000000000..64cabaa51b --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia-aesni-avx-amd64.S @@ -0,0 +1,2618 @@ +/* camellia-avx-aesni-amd64.S - AES-NI/AVX implementation of Camellia cipher + * + * Copyright (C) 2013-2015,2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#ifdef __x86_64 +#if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \ + defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT) + +#include "asm-common-amd64.h" + +#define CAMELLIA_TABLE_BYTE_LEN 272 + +/* struct CAMELLIA_context: */ +#define key_table 0 +#define key_bitlength CAMELLIA_TABLE_BYTE_LEN + +/* register macros */ +#define CTX %rdi + +/********************************************************************** + helper macros + **********************************************************************/ +#define filter_8bit(x, lo_t, hi_t, mask4bit, tmp0) \ + vpand x, mask4bit, tmp0; \ + vpandn x, mask4bit, x; \ + vpsrld $4, x, x; \ + \ + vpshufb tmp0, lo_t, tmp0; \ + vpshufb x, hi_t, x; \ + vpxor tmp0, x, x; + +/********************************************************************** + 16-way camellia + **********************************************************************/ + +/* + * IN: + * x0..x7: byte-sliced AB state + * mem_cd: register pointer storing CD state + * key: index for key material + * OUT: + * x0..x7: new byte-sliced CD state + */ +#define roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, t0, t1, t2, t3, t4, t5, t6, \ + t7, mem_cd, key) \ + /* \ + * S-function with AES subbytes \ + */ \ + vmovdqa .Linv_shift_row rRIP, t4; \ + vbroadcastss .L0f0f0f0f rRIP, t7; \ + vmovdqa .Lpre_tf_lo_s1 rRIP, t0; \ + vmovdqa .Lpre_tf_hi_s1 rRIP, t1; \ + \ + /* AES inverse shift rows */ \ + vpshufb t4, x0, x0; \ + vpshufb t4, x7, x7; \ + vpshufb t4, x1, x1; \ + vpshufb t4, x4, x4; \ + vpshufb t4, x2, x2; \ + vpshufb t4, x5, x5; \ + vpshufb t4, x3, x3; \ + vpshufb t4, x6, x6; \ + \ + /* prefilter sboxes 1, 2 and 3 */ \ + vmovdqa .Lpre_tf_lo_s4 rRIP, t2; \ + vmovdqa .Lpre_tf_hi_s4 rRIP, t3; \ + filter_8bit(x0, t0, t1, t7, t6); \ + filter_8bit(x7, t0, t1, t7, t6); \ + filter_8bit(x1, t0, t1, t7, t6); \ + filter_8bit(x4, t0, t1, t7, t6); \ + filter_8bit(x2, t0, t1, t7, t6); \ + filter_8bit(x5, t0, t1, t7, t6); \ + \ + /* prefilter sbox 4 */ \ + vpxor t4, t4, t4; \ + filter_8bit(x3, t2, t3, t7, t6); \ + filter_8bit(x6, t2, t3, t7, t6); \ + \ + /* AES subbytes + AES shift rows */ \ + vmovdqa .Lpost_tf_lo_s1 rRIP, t0; \ + vmovdqa .Lpost_tf_hi_s1 rRIP, t1; \ + vaesenclast t4, x0, x0; \ + vaesenclast t4, x7, x7; \ + vaesenclast t4, x1, x1; \ + vaesenclast t4, x4, x4; \ + vaesenclast t4, x2, x2; \ + vaesenclast t4, x5, x5; \ + vaesenclast t4, x3, x3; \ + vaesenclast t4, x6, x6; \ + \ + /* postfilter sboxes 1 and 4 */ \ + vmovdqa .Lpost_tf_lo_s3 rRIP, t2; \ + vmovdqa .Lpost_tf_hi_s3 rRIP, t3; \ + filter_8bit(x0, t0, t1, t7, t6); \ + filter_8bit(x7, t0, t1, t7, t6); \ + filter_8bit(x3, t0, t1, t7, t6); \ + filter_8bit(x6, t0, t1, t7, t6); \ + \ + /* postfilter sbox 3 */ \ + vmovdqa .Lpost_tf_lo_s2 rRIP, t4; \ + vmovdqa .Lpost_tf_hi_s2 rRIP, t5; \ + filter_8bit(x2, t2, t3, t7, t6); \ + filter_8bit(x5, t2, t3, t7, t6); \ + \ + vpxor t6, t6, t6; \ + vmovq key, t0; \ + \ + /* postfilter sbox 2 */ \ + filter_8bit(x1, t4, t5, t7, t2); \ + filter_8bit(x4, t4, t5, t7, t2); \ + \ + vpsrldq $5, t0, t5; \ + vpsrldq $1, t0, t1; \ + vpsrldq $2, t0, t2; \ + vpsrldq $3, t0, t3; \ + vpsrldq $4, t0, t4; \ + vpshufb t6, t0, t0; \ + vpshufb t6, t1, t1; \ + vpshufb t6, t2, t2; \ + vpshufb t6, t3, t3; \ + vpshufb t6, t4, t4; \ + vpsrldq $2, t5, t7; \ + vpshufb t6, t7, t7; \ + \ + /* P-function */ \ + vpxor x5, x0, x0; \ + vpxor x6, x1, x1; \ + vpxor x7, x2, x2; \ + vpxor x4, x3, x3; \ + \ + vpxor x2, x4, x4; \ + vpxor x3, x5, x5; \ + vpxor x0, x6, x6; \ + vpxor x1, x7, x7; \ + \ + vpxor x7, x0, x0; \ + vpxor x4, x1, x1; \ + vpxor x5, x2, x2; \ + vpxor x6, x3, x3; \ + \ + vpxor x3, x4, x4; \ + vpxor x0, x5, x5; \ + vpxor x1, x6, x6; \ + vpxor x2, x7, x7; /* note: high and low parts swapped */ \ + \ + /* Add key material and result to CD (x becomes new CD) */ \ + \ + vpxor t3, x4, x4; \ + vpxor 0 * 16(mem_cd), x4, x4; \ + \ + vpxor t2, x5, x5; \ + vpxor 1 * 16(mem_cd), x5, x5; \ + \ + vpsrldq $1, t5, t3; \ + vpshufb t6, t5, t5; \ + vpshufb t6, t3, t6; \ + \ + vpxor t1, x6, x6; \ + vpxor 2 * 16(mem_cd), x6, x6; \ + \ + vpxor t0, x7, x7; \ + vpxor 3 * 16(mem_cd), x7, x7; \ + \ + vpxor t7, x0, x0; \ + vpxor 4 * 16(mem_cd), x0, x0; \ + \ + vpxor t6, x1, x1; \ + vpxor 5 * 16(mem_cd), x1, x1; \ + \ + vpxor t5, x2, x2; \ + vpxor 6 * 16(mem_cd), x2, x2; \ + \ + vpxor t4, x3, x3; \ + vpxor 7 * 16(mem_cd), x3, x3; + +/* + * IN/OUT: + * x0..x7: byte-sliced AB state preloaded + * mem_ab: byte-sliced AB state in memory + * mem_cb: byte-sliced CD state in memory + */ +#define two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, i, dir, store_ab) \ + roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_cd, (key_table + (i) * 8)(CTX)); \ + \ + vmovdqu x4, 0 * 16(mem_cd); \ + vmovdqu x5, 1 * 16(mem_cd); \ + vmovdqu x6, 2 * 16(mem_cd); \ + vmovdqu x7, 3 * 16(mem_cd); \ + vmovdqu x0, 4 * 16(mem_cd); \ + vmovdqu x1, 5 * 16(mem_cd); \ + vmovdqu x2, 6 * 16(mem_cd); \ + vmovdqu x3, 7 * 16(mem_cd); \ + \ + roundsm16(x4, x5, x6, x7, x0, x1, x2, x3, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, (key_table + ((i) + (dir)) * 8)(CTX)); \ + \ + store_ab(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab); + +#define dummy_store(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab) /* do nothing */ + +#define store_ab_state(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab) \ + /* Store new AB state */ \ + vmovdqu x0, 0 * 16(mem_ab); \ + vmovdqu x1, 1 * 16(mem_ab); \ + vmovdqu x2, 2 * 16(mem_ab); \ + vmovdqu x3, 3 * 16(mem_ab); \ + vmovdqu x4, 4 * 16(mem_ab); \ + vmovdqu x5, 5 * 16(mem_ab); \ + vmovdqu x6, 6 * 16(mem_ab); \ + vmovdqu x7, 7 * 16(mem_ab); + +#define enc_rounds16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, i) \ + two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 2, 1, store_ab_state); \ + two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 4, 1, store_ab_state); \ + two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 6, 1, dummy_store); + +#define dec_rounds16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, i) \ + two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 7, -1, store_ab_state); \ + two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 5, -1, store_ab_state); \ + two_roundsm16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 3, -1, dummy_store); + +/* + * IN: + * v0..3: byte-sliced 32-bit integers + * OUT: + * v0..3: (IN <<< 1) + */ +#define rol32_1_16(v0, v1, v2, v3, t0, t1, t2, zero) \ + vpcmpgtb v0, zero, t0; \ + vpaddb v0, v0, v0; \ + vpabsb t0, t0; \ + \ + vpcmpgtb v1, zero, t1; \ + vpaddb v1, v1, v1; \ + vpabsb t1, t1; \ + \ + vpcmpgtb v2, zero, t2; \ + vpaddb v2, v2, v2; \ + vpabsb t2, t2; \ + \ + vpor t0, v1, v1; \ + \ + vpcmpgtb v3, zero, t0; \ + vpaddb v3, v3, v3; \ + vpabsb t0, t0; \ + \ + vpor t1, v2, v2; \ + vpor t2, v3, v3; \ + vpor t0, v0, v0; + +/* + * IN: + * r: byte-sliced AB state in memory + * l: byte-sliced CD state in memory + * OUT: + * x0..x7: new byte-sliced CD state + */ +#define fls16(l, l0, l1, l2, l3, l4, l5, l6, l7, r, t0, t1, t2, t3, tt0, \ + tt1, tt2, tt3, kll, klr, krl, krr) \ + /* \ + * t0 = kll; \ + * t0 &= ll; \ + * lr ^= rol32(t0, 1); \ + */ \ + vpxor tt0, tt0, tt0; \ + vmovd kll, t0; \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpand l0, t0, t0; \ + vpand l1, t1, t1; \ + vpand l2, t2, t2; \ + vpand l3, t3, t3; \ + \ + rol32_1_16(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \ + \ + vpxor l4, t0, l4; \ + vmovdqu l4, 4 * 16(l); \ + vpxor l5, t1, l5; \ + vmovdqu l5, 5 * 16(l); \ + vpxor l6, t2, l6; \ + vmovdqu l6, 6 * 16(l); \ + vpxor l7, t3, l7; \ + vmovdqu l7, 7 * 16(l); \ + \ + /* \ + * t2 = krr; \ + * t2 |= rr; \ + * rl ^= t2; \ + */ \ + \ + vmovd krr, t0; \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpor 4 * 16(r), t0, t0; \ + vpor 5 * 16(r), t1, t1; \ + vpor 6 * 16(r), t2, t2; \ + vpor 7 * 16(r), t3, t3; \ + \ + vpxor 0 * 16(r), t0, t0; \ + vpxor 1 * 16(r), t1, t1; \ + vpxor 2 * 16(r), t2, t2; \ + vpxor 3 * 16(r), t3, t3; \ + vmovdqu t0, 0 * 16(r); \ + vmovdqu t1, 1 * 16(r); \ + vmovdqu t2, 2 * 16(r); \ + vmovdqu t3, 3 * 16(r); \ + \ + /* \ + * t2 = krl; \ + * t2 &= rl; \ + * rr ^= rol32(t2, 1); \ + */ \ + vmovd krl, t0; \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpand 0 * 16(r), t0, t0; \ + vpand 1 * 16(r), t1, t1; \ + vpand 2 * 16(r), t2, t2; \ + vpand 3 * 16(r), t3, t3; \ + \ + rol32_1_16(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \ + \ + vpxor 4 * 16(r), t0, t0; \ + vpxor 5 * 16(r), t1, t1; \ + vpxor 6 * 16(r), t2, t2; \ + vpxor 7 * 16(r), t3, t3; \ + vmovdqu t0, 4 * 16(r); \ + vmovdqu t1, 5 * 16(r); \ + vmovdqu t2, 6 * 16(r); \ + vmovdqu t3, 7 * 16(r); \ + \ + /* \ + * t0 = klr; \ + * t0 |= lr; \ + * ll ^= t0; \ + */ \ + \ + vmovd klr, t0; \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpor l4, t0, t0; \ + vpor l5, t1, t1; \ + vpor l6, t2, t2; \ + vpor l7, t3, t3; \ + \ + vpxor l0, t0, l0; \ + vmovdqu l0, 0 * 16(l); \ + vpxor l1, t1, l1; \ + vmovdqu l1, 1 * 16(l); \ + vpxor l2, t2, l2; \ + vmovdqu l2, 2 * 16(l); \ + vpxor l3, t3, l3; \ + vmovdqu l3, 3 * 16(l); + +#define transpose_4x4(x0, x1, x2, x3, t1, t2) \ + vpunpckhdq x1, x0, t2; \ + vpunpckldq x1, x0, x0; \ + \ + vpunpckldq x3, x2, t1; \ + vpunpckhdq x3, x2, x2; \ + \ + vpunpckhqdq t1, x0, x1; \ + vpunpcklqdq t1, x0, x0; \ + \ + vpunpckhqdq x2, t2, x3; \ + vpunpcklqdq x2, t2, x2; + +#define byteslice_16x16b_fast(a0, b0, c0, d0, a1, b1, c1, d1, a2, b2, c2, d2, \ + a3, b3, c3, d3, st0, st1) \ + vmovdqu d2, st0; \ + vmovdqu d3, st1; \ + transpose_4x4(a0, a1, a2, a3, d2, d3); \ + transpose_4x4(b0, b1, b2, b3, d2, d3); \ + vmovdqu st0, d2; \ + vmovdqu st1, d3; \ + \ + vmovdqu a0, st0; \ + vmovdqu a1, st1; \ + transpose_4x4(c0, c1, c2, c3, a0, a1); \ + transpose_4x4(d0, d1, d2, d3, a0, a1); \ + \ + vmovdqu .Lshufb_16x16b rRIP, a0; \ + vmovdqu st1, a1; \ + vpshufb a0, a2, a2; \ + vpshufb a0, a3, a3; \ + vpshufb a0, b0, b0; \ + vpshufb a0, b1, b1; \ + vpshufb a0, b2, b2; \ + vpshufb a0, b3, b3; \ + vpshufb a0, a1, a1; \ + vpshufb a0, c0, c0; \ + vpshufb a0, c1, c1; \ + vpshufb a0, c2, c2; \ + vpshufb a0, c3, c3; \ + vpshufb a0, d0, d0; \ + vpshufb a0, d1, d1; \ + vpshufb a0, d2, d2; \ + vpshufb a0, d3, d3; \ + vmovdqu d3, st1; \ + vmovdqu st0, d3; \ + vpshufb a0, d3, a0; \ + vmovdqu d2, st0; \ + \ + transpose_4x4(a0, b0, c0, d0, d2, d3); \ + transpose_4x4(a1, b1, c1, d1, d2, d3); \ + vmovdqu st0, d2; \ + vmovdqu st1, d3; \ + \ + vmovdqu b0, st0; \ + vmovdqu b1, st1; \ + transpose_4x4(a2, b2, c2, d2, b0, b1); \ + transpose_4x4(a3, b3, c3, d3, b0, b1); \ + vmovdqu st0, b0; \ + vmovdqu st1, b1; \ + /* does not adjust output bytes inside vectors */ + +#define transpose_8x8b(a, b, c, d, e, f, g, h, t0, t1, t2, t3, t4) \ + vpunpcklbw a, b, t0; \ + vpunpckhbw a, b, b; \ + \ + vpunpcklbw c, d, t1; \ + vpunpckhbw c, d, d; \ + \ + vpunpcklbw e, f, t2; \ + vpunpckhbw e, f, f; \ + \ + vpunpcklbw g, h, t3; \ + vpunpckhbw g, h, h; \ + \ + vpunpcklwd t0, t1, g; \ + vpunpckhwd t0, t1, t0; \ + \ + vpunpcklwd b, d, t1; \ + vpunpckhwd b, d, e; \ + \ + vpunpcklwd t2, t3, c; \ + vpunpckhwd t2, t3, t2; \ + \ + vpunpcklwd f, h, t3; \ + vpunpckhwd f, h, b; \ + \ + vpunpcklwd e, b, t4; \ + vpunpckhwd e, b, b; \ + \ + vpunpcklwd t1, t3, e; \ + vpunpckhwd t1, t3, f; \ + \ + vmovdqa .Ltranspose_8x8_shuf rRIP, t3; \ + \ + vpunpcklwd g, c, d; \ + vpunpckhwd g, c, c; \ + \ + vpunpcklwd t0, t2, t1; \ + vpunpckhwd t0, t2, h; \ + \ + vpunpckhqdq b, h, a; \ + vpshufb t3, a, a; \ + vpunpcklqdq b, h, b; \ + vpshufb t3, b, b; \ + \ + vpunpckhqdq e, d, g; \ + vpshufb t3, g, g; \ + vpunpcklqdq e, d, h; \ + vpshufb t3, h, h; \ + \ + vpunpckhqdq f, c, e; \ + vpshufb t3, e, e; \ + vpunpcklqdq f, c, f; \ + vpshufb t3, f, f; \ + \ + vpunpckhqdq t4, t1, c; \ + vpshufb t3, c, c; \ + vpunpcklqdq t4, t1, d; \ + vpshufb t3, d, d; + +/* load blocks to registers and apply pre-whitening */ +#define inpack16_pre(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, rio, key) \ + vmovq key, x0; \ + vpshufb .Lpack_bswap rRIP, x0, x0; \ + \ + vpxor 0 * 16(rio), x0, y7; \ + vpxor 1 * 16(rio), x0, y6; \ + vpxor 2 * 16(rio), x0, y5; \ + vpxor 3 * 16(rio), x0, y4; \ + vpxor 4 * 16(rio), x0, y3; \ + vpxor 5 * 16(rio), x0, y2; \ + vpxor 6 * 16(rio), x0, y1; \ + vpxor 7 * 16(rio), x0, y0; \ + vpxor 8 * 16(rio), x0, x7; \ + vpxor 9 * 16(rio), x0, x6; \ + vpxor 10 * 16(rio), x0, x5; \ + vpxor 11 * 16(rio), x0, x4; \ + vpxor 12 * 16(rio), x0, x3; \ + vpxor 13 * 16(rio), x0, x2; \ + vpxor 14 * 16(rio), x0, x1; \ + vpxor 15 * 16(rio), x0, x0; + +/* byteslice pre-whitened blocks and store to temporary memory */ +#define inpack16_post(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd) \ + byteslice_16x16b_fast(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, \ + y4, y5, y6, y7, (mem_ab), (mem_cd)); \ + \ + vmovdqu x0, 0 * 16(mem_ab); \ + vmovdqu x1, 1 * 16(mem_ab); \ + vmovdqu x2, 2 * 16(mem_ab); \ + vmovdqu x3, 3 * 16(mem_ab); \ + vmovdqu x4, 4 * 16(mem_ab); \ + vmovdqu x5, 5 * 16(mem_ab); \ + vmovdqu x6, 6 * 16(mem_ab); \ + vmovdqu x7, 7 * 16(mem_ab); \ + vmovdqu y0, 0 * 16(mem_cd); \ + vmovdqu y1, 1 * 16(mem_cd); \ + vmovdqu y2, 2 * 16(mem_cd); \ + vmovdqu y3, 3 * 16(mem_cd); \ + vmovdqu y4, 4 * 16(mem_cd); \ + vmovdqu y5, 5 * 16(mem_cd); \ + vmovdqu y6, 6 * 16(mem_cd); \ + vmovdqu y7, 7 * 16(mem_cd); + +/* de-byteslice, apply post-whitening and store blocks */ +#define outunpack16(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, \ + y5, y6, y7, key, stack_tmp0, stack_tmp1) \ + byteslice_16x16b_fast(y0, y4, x0, x4, y1, y5, x1, x5, y2, y6, x2, x6, \ + y3, y7, x3, x7, stack_tmp0, stack_tmp1); \ + \ + vmovdqu x0, stack_tmp0; \ + \ + vmovq key, x0; \ + vpshufb .Lpack_bswap rRIP, x0, x0; \ + \ + vpxor x0, y7, y7; \ + vpxor x0, y6, y6; \ + vpxor x0, y5, y5; \ + vpxor x0, y4, y4; \ + vpxor x0, y3, y3; \ + vpxor x0, y2, y2; \ + vpxor x0, y1, y1; \ + vpxor x0, y0, y0; \ + vpxor x0, x7, x7; \ + vpxor x0, x6, x6; \ + vpxor x0, x5, x5; \ + vpxor x0, x4, x4; \ + vpxor x0, x3, x3; \ + vpxor x0, x2, x2; \ + vpxor x0, x1, x1; \ + vpxor stack_tmp0, x0, x0; + +#define write_output(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, rio) \ + vmovdqu x0, 0 * 16(rio); \ + vmovdqu x1, 1 * 16(rio); \ + vmovdqu x2, 2 * 16(rio); \ + vmovdqu x3, 3 * 16(rio); \ + vmovdqu x4, 4 * 16(rio); \ + vmovdqu x5, 5 * 16(rio); \ + vmovdqu x6, 6 * 16(rio); \ + vmovdqu x7, 7 * 16(rio); \ + vmovdqu y0, 8 * 16(rio); \ + vmovdqu y1, 9 * 16(rio); \ + vmovdqu y2, 10 * 16(rio); \ + vmovdqu y3, 11 * 16(rio); \ + vmovdqu y4, 12 * 16(rio); \ + vmovdqu y5, 13 * 16(rio); \ + vmovdqu y6, 14 * 16(rio); \ + vmovdqu y7, 15 * 16(rio); + +.text +.align 16 + +#define SHUFB_BYTES(idx) \ + 0 + (idx), 4 + (idx), 8 + (idx), 12 + (idx) + +.Lshufb_16x16b: + .byte SHUFB_BYTES(0), SHUFB_BYTES(1), SHUFB_BYTES(2), SHUFB_BYTES(3); + +.Lpack_bswap: + .long 0x00010203 + .long 0x04050607 + .long 0x80808080 + .long 0x80808080 + +/* For CTR-mode IV byteswap */ +.Lbswap128_mask: + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +/* + * pre-SubByte transform + * + * pre-lookup for sbox1, sbox2, sbox3: + * swap_bitendianness( + * isom_map_camellia_to_aes( + * camellia_f( + * swap_bitendianess(in) + * ) + * ) + * ) + * + * (note: '⊕ 0xc5' inside camellia_f()) + */ +.Lpre_tf_lo_s1: + .byte 0x45, 0xe8, 0x40, 0xed, 0x2e, 0x83, 0x2b, 0x86 + .byte 0x4b, 0xe6, 0x4e, 0xe3, 0x20, 0x8d, 0x25, 0x88 +.Lpre_tf_hi_s1: + .byte 0x00, 0x51, 0xf1, 0xa0, 0x8a, 0xdb, 0x7b, 0x2a + .byte 0x09, 0x58, 0xf8, 0xa9, 0x83, 0xd2, 0x72, 0x23 + +/* + * pre-SubByte transform + * + * pre-lookup for sbox4: + * swap_bitendianness( + * isom_map_camellia_to_aes( + * camellia_f( + * swap_bitendianess(in <<< 1) + * ) + * ) + * ) + * + * (note: '⊕ 0xc5' inside camellia_f()) + */ +.Lpre_tf_lo_s4: + .byte 0x45, 0x40, 0x2e, 0x2b, 0x4b, 0x4e, 0x20, 0x25 + .byte 0x14, 0x11, 0x7f, 0x7a, 0x1a, 0x1f, 0x71, 0x74 +.Lpre_tf_hi_s4: + .byte 0x00, 0xf1, 0x8a, 0x7b, 0x09, 0xf8, 0x83, 0x72 + .byte 0xad, 0x5c, 0x27, 0xd6, 0xa4, 0x55, 0x2e, 0xdf + +/* + * post-SubByte transform + * + * post-lookup for sbox1, sbox4: + * swap_bitendianness( + * camellia_h( + * isom_map_aes_to_camellia( + * swap_bitendianness( + * aes_inverse_affine_transform(in) + * ) + * ) + * ) + * ) + * + * (note: '⊕ 0x6e' inside camellia_h()) + */ +.Lpost_tf_lo_s1: + .byte 0x3c, 0xcc, 0xcf, 0x3f, 0x32, 0xc2, 0xc1, 0x31 + .byte 0xdc, 0x2c, 0x2f, 0xdf, 0xd2, 0x22, 0x21, 0xd1 +.Lpost_tf_hi_s1: + .byte 0x00, 0xf9, 0x86, 0x7f, 0xd7, 0x2e, 0x51, 0xa8 + .byte 0xa4, 0x5d, 0x22, 0xdb, 0x73, 0x8a, 0xf5, 0x0c + +/* + * post-SubByte transform + * + * post-lookup for sbox2: + * swap_bitendianness( + * camellia_h( + * isom_map_aes_to_camellia( + * swap_bitendianness( + * aes_inverse_affine_transform(in) + * ) + * ) + * ) + * ) <<< 1 + * + * (note: '⊕ 0x6e' inside camellia_h()) + */ +.Lpost_tf_lo_s2: + .byte 0x78, 0x99, 0x9f, 0x7e, 0x64, 0x85, 0x83, 0x62 + .byte 0xb9, 0x58, 0x5e, 0xbf, 0xa5, 0x44, 0x42, 0xa3 +.Lpost_tf_hi_s2: + .byte 0x00, 0xf3, 0x0d, 0xfe, 0xaf, 0x5c, 0xa2, 0x51 + .byte 0x49, 0xba, 0x44, 0xb7, 0xe6, 0x15, 0xeb, 0x18 + +/* + * post-SubByte transform + * + * post-lookup for sbox3: + * swap_bitendianness( + * camellia_h( + * isom_map_aes_to_camellia( + * swap_bitendianness( + * aes_inverse_affine_transform(in) + * ) + * ) + * ) + * ) >>> 1 + * + * (note: '⊕ 0x6e' inside camellia_h()) + */ +.Lpost_tf_lo_s3: + .byte 0x1e, 0x66, 0xe7, 0x9f, 0x19, 0x61, 0xe0, 0x98 + .byte 0x6e, 0x16, 0x97, 0xef, 0x69, 0x11, 0x90, 0xe8 +.Lpost_tf_hi_s3: + .byte 0x00, 0xfc, 0x43, 0xbf, 0xeb, 0x17, 0xa8, 0x54 + .byte 0x52, 0xae, 0x11, 0xed, 0xb9, 0x45, 0xfa, 0x06 + +/* For isolating SubBytes from AESENCLAST, inverse shift row */ +.Linv_shift_row: + .byte 0x00, 0x0d, 0x0a, 0x07, 0x04, 0x01, 0x0e, 0x0b + .byte 0x08, 0x05, 0x02, 0x0f, 0x0c, 0x09, 0x06, 0x03 + +/* shuffle mask for 8x8 byte transpose */ +.Ltranspose_8x8_shuf: + .byte 0, 1, 4, 5, 2, 3, 6, 7, 8+0, 8+1, 8+4, 8+5, 8+2, 8+3, 8+6, 8+7 + +.align 4 +/* 4-bit mask */ +.L0f0f0f0f: + .long 0x0f0f0f0f + + +.align 8 +ELF(.type __camellia_enc_blk16,@function;) + +__camellia_enc_blk16: + /* input: + * %rdi: ctx, CTX + * %rax: temporary storage, 256 bytes + * %r8d: 24 for 16 byte key, 32 for larger + * %xmm0..%xmm15: 16 plaintext blocks + * output: + * %xmm0..%xmm15: 16 encrypted blocks, order swapped: + * 7, 8, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 + */ + CFI_STARTPROC(); + + leaq 8 * 16(%rax), %rcx; + + leaq (-8 * 8)(CTX, %r8, 8), %r8; + + inpack16_post(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, %rax, %rcx); + +.align 8 +.Lenc_loop: + enc_rounds16(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, %rax, %rcx, 0); + + cmpq %r8, CTX; + je .Lenc_done; + leaq (8 * 8)(CTX), CTX; + + fls16(%rax, %xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %rcx, %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, + ((key_table) + 0)(CTX), + ((key_table) + 4)(CTX), + ((key_table) + 8)(CTX), + ((key_table) + 12)(CTX)); + jmp .Lenc_loop; + +.align 8 +.Lenc_done: + /* load CD for output */ + vmovdqu 0 * 16(%rcx), %xmm8; + vmovdqu 1 * 16(%rcx), %xmm9; + vmovdqu 2 * 16(%rcx), %xmm10; + vmovdqu 3 * 16(%rcx), %xmm11; + vmovdqu 4 * 16(%rcx), %xmm12; + vmovdqu 5 * 16(%rcx), %xmm13; + vmovdqu 6 * 16(%rcx), %xmm14; + vmovdqu 7 * 16(%rcx), %xmm15; + + outunpack16(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, ((key_table) + 8 * 8)(%r8), (%rax), 1 * 16(%rax)); + + ret; + CFI_ENDPROC(); +ELF(.size __camellia_enc_blk16,.-__camellia_enc_blk16;) + +.align 8 +ELF(.type __camellia_dec_blk16,@function;) + +__camellia_dec_blk16: + /* input: + * %rdi: ctx, CTX + * %rax: temporary storage, 256 bytes + * %r8d: 24 for 16 byte key, 32 for larger + * %xmm0..%xmm15: 16 encrypted blocks + * output: + * %xmm0..%xmm15: 16 plaintext blocks, order swapped: + * 7, 8, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 + */ + CFI_STARTPROC(); + + movq %r8, %rcx; + movq CTX, %r8 + leaq (-8 * 8)(CTX, %rcx, 8), CTX; + + leaq 8 * 16(%rax), %rcx; + + inpack16_post(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, %rax, %rcx); + +.align 8 +.Ldec_loop: + dec_rounds16(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, %rax, %rcx, 0); + + cmpq %r8, CTX; + je .Ldec_done; + + fls16(%rax, %xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %rcx, %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, + ((key_table) + 8)(CTX), + ((key_table) + 12)(CTX), + ((key_table) + 0)(CTX), + ((key_table) + 4)(CTX)); + + leaq (-8 * 8)(CTX), CTX; + jmp .Ldec_loop; + +.align 8 +.Ldec_done: + /* load CD for output */ + vmovdqu 0 * 16(%rcx), %xmm8; + vmovdqu 1 * 16(%rcx), %xmm9; + vmovdqu 2 * 16(%rcx), %xmm10; + vmovdqu 3 * 16(%rcx), %xmm11; + vmovdqu 4 * 16(%rcx), %xmm12; + vmovdqu 5 * 16(%rcx), %xmm13; + vmovdqu 6 * 16(%rcx), %xmm14; + vmovdqu 7 * 16(%rcx), %xmm15; + + outunpack16(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, (key_table)(CTX), (%rax), 1 * 16(%rax)); + + ret; + CFI_ENDPROC(); +ELF(.size __camellia_dec_blk16,.-__camellia_dec_blk16;) + +#define inc_le128(x, minus_one, tmp) \ + vpcmpeqq minus_one, x, tmp; \ + vpsubq minus_one, x, x; \ + vpslldq $8, tmp, tmp; \ + vpsubq tmp, x, x; + +.align 8 +.globl _gcry_camellia_aesni_avx_ctr_enc +ELF(.type _gcry_camellia_aesni_avx_ctr_enc,@function;) + +_gcry_camellia_aesni_avx_ctr_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (16 blocks) + * %rdx: src (16 blocks) + * %rcx: iv (big endian, 128bit) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %eax; + cmovel %eax, %r8d; /* max */ + + subq $(16 * 16), %rsp; + andq $~31, %rsp; + movq %rsp, %rax; + + vmovdqa .Lbswap128_mask rRIP, %xmm14; + + /* load IV and byteswap */ + vmovdqu (%rcx), %xmm15; + vmovdqu %xmm15, 15 * 16(%rax); + vpshufb %xmm14, %xmm15, %xmm0; /* be => le */ + + vpcmpeqd %xmm15, %xmm15, %xmm15; + vpsrldq $8, %xmm15, %xmm15; /* low: -1, high: 0 */ + + /* construct IVs */ + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm13; + vmovdqu %xmm13, 14 * 16(%rax); + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm13; + vmovdqu %xmm13, 13 * 16(%rax); + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm12; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm11; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm10; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm9; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm8; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm7; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm6; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm5; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm4; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm3; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm2; + inc_le128(%xmm0, %xmm15, %xmm13); + vpshufb %xmm14, %xmm0, %xmm1; + inc_le128(%xmm0, %xmm15, %xmm13); + vmovdqa %xmm0, %xmm13; + vpshufb %xmm14, %xmm0, %xmm0; + inc_le128(%xmm13, %xmm15, %xmm14); + vpshufb .Lbswap128_mask rRIP, %xmm13, %xmm13; /* le => be */ + vmovdqu %xmm13, (%rcx); + + /* inpack16_pre: */ + vmovq (key_table)(CTX), %xmm15; + vpshufb .Lpack_bswap rRIP, %xmm15, %xmm15; + vpxor %xmm0, %xmm15, %xmm0; + vpxor %xmm1, %xmm15, %xmm1; + vpxor %xmm2, %xmm15, %xmm2; + vpxor %xmm3, %xmm15, %xmm3; + vpxor %xmm4, %xmm15, %xmm4; + vpxor %xmm5, %xmm15, %xmm5; + vpxor %xmm6, %xmm15, %xmm6; + vpxor %xmm7, %xmm15, %xmm7; + vpxor %xmm8, %xmm15, %xmm8; + vpxor %xmm9, %xmm15, %xmm9; + vpxor %xmm10, %xmm15, %xmm10; + vpxor %xmm11, %xmm15, %xmm11; + vpxor %xmm12, %xmm15, %xmm12; + vpxor 13 * 16(%rax), %xmm15, %xmm13; + vpxor 14 * 16(%rax), %xmm15, %xmm14; + vpxor 15 * 16(%rax), %xmm15, %xmm15; + + call __camellia_enc_blk16; + + vpxor 0 * 16(%rdx), %xmm7, %xmm7; + vpxor 1 * 16(%rdx), %xmm6, %xmm6; + vpxor 2 * 16(%rdx), %xmm5, %xmm5; + vpxor 3 * 16(%rdx), %xmm4, %xmm4; + vpxor 4 * 16(%rdx), %xmm3, %xmm3; + vpxor 5 * 16(%rdx), %xmm2, %xmm2; + vpxor 6 * 16(%rdx), %xmm1, %xmm1; + vpxor 7 * 16(%rdx), %xmm0, %xmm0; + vpxor 8 * 16(%rdx), %xmm15, %xmm15; + vpxor 9 * 16(%rdx), %xmm14, %xmm14; + vpxor 10 * 16(%rdx), %xmm13, %xmm13; + vpxor 11 * 16(%rdx), %xmm12, %xmm12; + vpxor 12 * 16(%rdx), %xmm11, %xmm11; + vpxor 13 * 16(%rdx), %xmm10, %xmm10; + vpxor 14 * 16(%rdx), %xmm9, %xmm9; + vpxor 15 * 16(%rdx), %xmm8, %xmm8; + + write_output(%xmm7, %xmm6, %xmm5, %xmm4, %xmm3, %xmm2, %xmm1, %xmm0, + %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, + %xmm8, %rsi); + + vzeroall; + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_ctr_enc,.-_gcry_camellia_aesni_avx_ctr_enc;) + +.align 8 +.globl _gcry_camellia_aesni_avx_cbc_dec +ELF(.type _gcry_camellia_aesni_avx_cbc_dec,@function;) + +_gcry_camellia_aesni_avx_cbc_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (16 blocks) + * %rdx: src (16 blocks) + * %rcx: iv + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + movq %rcx, %r9; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %eax; + cmovel %eax, %r8d; /* max */ + + inpack16_pre(%xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, + %xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, + %xmm15, %rdx, (key_table)(CTX, %r8, 8)); + + subq $(16 * 16), %rsp; + andq $~31, %rsp; + movq %rsp, %rax; + + call __camellia_dec_blk16; + + /* XOR output with IV */ + vpxor (%r9), %xmm7, %xmm7; + vpxor (0 * 16)(%rdx), %xmm6, %xmm6; + vpxor (1 * 16)(%rdx), %xmm5, %xmm5; + vpxor (2 * 16)(%rdx), %xmm4, %xmm4; + vpxor (3 * 16)(%rdx), %xmm3, %xmm3; + vpxor (4 * 16)(%rdx), %xmm2, %xmm2; + vpxor (5 * 16)(%rdx), %xmm1, %xmm1; + vpxor (6 * 16)(%rdx), %xmm0, %xmm0; + vpxor (7 * 16)(%rdx), %xmm15, %xmm15; + vpxor (8 * 16)(%rdx), %xmm14, %xmm14; + vpxor (9 * 16)(%rdx), %xmm13, %xmm13; + vpxor (10 * 16)(%rdx), %xmm12, %xmm12; + vpxor (11 * 16)(%rdx), %xmm11, %xmm11; + vpxor (12 * 16)(%rdx), %xmm10, %xmm10; + vpxor (13 * 16)(%rdx), %xmm9, %xmm9; + vpxor (14 * 16)(%rdx), %xmm8, %xmm8; + movq (15 * 16 + 0)(%rdx), %r10; + movq (15 * 16 + 8)(%rdx), %r11; + + write_output(%xmm7, %xmm6, %xmm5, %xmm4, %xmm3, %xmm2, %xmm1, %xmm0, + %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, + %xmm8, %rsi); + + /* store new IV */ + movq %r10, (0)(%r9); + movq %r11, (8)(%r9); + + vzeroall; + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_cbc_dec,.-_gcry_camellia_aesni_avx_cbc_dec;) + +.align 8 +.globl _gcry_camellia_aesni_avx_cfb_dec +ELF(.type _gcry_camellia_aesni_avx_cfb_dec,@function;) + +_gcry_camellia_aesni_avx_cfb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (16 blocks) + * %rdx: src (16 blocks) + * %rcx: iv + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %eax; + cmovel %eax, %r8d; /* max */ + + subq $(16 * 16), %rsp; + andq $~31, %rsp; + movq %rsp, %rax; + + /* inpack16_pre: */ + vmovq (key_table)(CTX), %xmm0; + vpshufb .Lpack_bswap rRIP, %xmm0, %xmm0; + vpxor (%rcx), %xmm0, %xmm15; + vmovdqu 15 * 16(%rdx), %xmm1; + vmovdqu %xmm1, (%rcx); /* store new IV */ + vpxor 0 * 16(%rdx), %xmm0, %xmm14; + vpxor 1 * 16(%rdx), %xmm0, %xmm13; + vpxor 2 * 16(%rdx), %xmm0, %xmm12; + vpxor 3 * 16(%rdx), %xmm0, %xmm11; + vpxor 4 * 16(%rdx), %xmm0, %xmm10; + vpxor 5 * 16(%rdx), %xmm0, %xmm9; + vpxor 6 * 16(%rdx), %xmm0, %xmm8; + vpxor 7 * 16(%rdx), %xmm0, %xmm7; + vpxor 8 * 16(%rdx), %xmm0, %xmm6; + vpxor 9 * 16(%rdx), %xmm0, %xmm5; + vpxor 10 * 16(%rdx), %xmm0, %xmm4; + vpxor 11 * 16(%rdx), %xmm0, %xmm3; + vpxor 12 * 16(%rdx), %xmm0, %xmm2; + vpxor 13 * 16(%rdx), %xmm0, %xmm1; + vpxor 14 * 16(%rdx), %xmm0, %xmm0; + + call __camellia_enc_blk16; + + vpxor 0 * 16(%rdx), %xmm7, %xmm7; + vpxor 1 * 16(%rdx), %xmm6, %xmm6; + vpxor 2 * 16(%rdx), %xmm5, %xmm5; + vpxor 3 * 16(%rdx), %xmm4, %xmm4; + vpxor 4 * 16(%rdx), %xmm3, %xmm3; + vpxor 5 * 16(%rdx), %xmm2, %xmm2; + vpxor 6 * 16(%rdx), %xmm1, %xmm1; + vpxor 7 * 16(%rdx), %xmm0, %xmm0; + vpxor 8 * 16(%rdx), %xmm15, %xmm15; + vpxor 9 * 16(%rdx), %xmm14, %xmm14; + vpxor 10 * 16(%rdx), %xmm13, %xmm13; + vpxor 11 * 16(%rdx), %xmm12, %xmm12; + vpxor 12 * 16(%rdx), %xmm11, %xmm11; + vpxor 13 * 16(%rdx), %xmm10, %xmm10; + vpxor 14 * 16(%rdx), %xmm9, %xmm9; + vpxor 15 * 16(%rdx), %xmm8, %xmm8; + + write_output(%xmm7, %xmm6, %xmm5, %xmm4, %xmm3, %xmm2, %xmm1, %xmm0, + %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, + %xmm8, %rsi); + + vzeroall; + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_cfb_dec,.-_gcry_camellia_aesni_avx_cfb_dec;) + +.align 8 +.globl _gcry_camellia_aesni_avx_ocb_enc +ELF(.type _gcry_camellia_aesni_avx_ocb_enc,@function;) + +_gcry_camellia_aesni_avx_ocb_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (16 blocks) + * %rdx: src (16 blocks) + * %rcx: offset + * %r8 : checksum + * %r9 : L pointers (void *L[16]) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(16 * 16 + 4 * 8), %rsp; + andq $~31, %rsp; + movq %rsp, %rax; + + movq %r10, (16 * 16 + 0 * 8)(%rsp); + movq %r11, (16 * 16 + 1 * 8)(%rsp); + movq %r12, (16 * 16 + 2 * 8)(%rsp); + movq %r13, (16 * 16 + 3 * 8)(%rsp); + CFI_REG_ON_STACK(r10, 16 * 16 + 0 * 8); + CFI_REG_ON_STACK(r11, 16 * 16 + 1 * 8); + CFI_REG_ON_STACK(r12, 16 * 16 + 2 * 8); + CFI_REG_ON_STACK(r13, 16 * 16 + 3 * 8); + + vmovdqu (%rcx), %xmm14; + vmovdqu (%r8), %xmm15; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + /* Checksum_i = Checksum_{i-1} xor P_i */ + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + +#define OCB_INPUT(n, lreg, xreg) \ + vmovdqu (n * 16)(%rdx), xreg; \ + vpxor (lreg), %xmm14, %xmm14; \ + vpxor xreg, %xmm15, %xmm15; \ + vpxor xreg, %xmm14, xreg; \ + vmovdqu %xmm14, (n * 16)(%rsi); + movq (0 * 8)(%r9), %r10; + movq (1 * 8)(%r9), %r11; + movq (2 * 8)(%r9), %r12; + movq (3 * 8)(%r9), %r13; + OCB_INPUT(0, %r10, %xmm0); + vmovdqu %xmm0, (15 * 16)(%rax); + OCB_INPUT(1, %r11, %xmm0); + vmovdqu %xmm0, (14 * 16)(%rax); + OCB_INPUT(2, %r12, %xmm13); + OCB_INPUT(3, %r13, %xmm12); + movq (4 * 8)(%r9), %r10; + movq (5 * 8)(%r9), %r11; + movq (6 * 8)(%r9), %r12; + movq (7 * 8)(%r9), %r13; + OCB_INPUT(4, %r10, %xmm11); + OCB_INPUT(5, %r11, %xmm10); + OCB_INPUT(6, %r12, %xmm9); + OCB_INPUT(7, %r13, %xmm8); + movq (8 * 8)(%r9), %r10; + movq (9 * 8)(%r9), %r11; + movq (10 * 8)(%r9), %r12; + movq (11 * 8)(%r9), %r13; + OCB_INPUT(8, %r10, %xmm7); + OCB_INPUT(9, %r11, %xmm6); + OCB_INPUT(10, %r12, %xmm5); + OCB_INPUT(11, %r13, %xmm4); + movq (12 * 8)(%r9), %r10; + movq (13 * 8)(%r9), %r11; + movq (14 * 8)(%r9), %r12; + movq (15 * 8)(%r9), %r13; + OCB_INPUT(12, %r10, %xmm3); + OCB_INPUT(13, %r11, %xmm2); + OCB_INPUT(14, %r12, %xmm1); + OCB_INPUT(15, %r13, %xmm0); +#undef OCB_INPUT + + vmovdqu %xmm14, (%rcx); + vmovdqu %xmm15, (%r8); + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %r10d; + cmovel %r10d, %r8d; /* max */ + + /* inpack16_pre: */ + vmovq (key_table)(CTX), %xmm15; + vpshufb .Lpack_bswap rRIP, %xmm15, %xmm15; + vpxor %xmm0, %xmm15, %xmm0; + vpxor %xmm1, %xmm15, %xmm1; + vpxor %xmm2, %xmm15, %xmm2; + vpxor %xmm3, %xmm15, %xmm3; + vpxor %xmm4, %xmm15, %xmm4; + vpxor %xmm5, %xmm15, %xmm5; + vpxor %xmm6, %xmm15, %xmm6; + vpxor %xmm7, %xmm15, %xmm7; + vpxor %xmm8, %xmm15, %xmm8; + vpxor %xmm9, %xmm15, %xmm9; + vpxor %xmm10, %xmm15, %xmm10; + vpxor %xmm11, %xmm15, %xmm11; + vpxor %xmm12, %xmm15, %xmm12; + vpxor %xmm13, %xmm15, %xmm13; + vpxor 14 * 16(%rax), %xmm15, %xmm14; + vpxor 15 * 16(%rax), %xmm15, %xmm15; + + call __camellia_enc_blk16; + + vpxor 0 * 16(%rsi), %xmm7, %xmm7; + vpxor 1 * 16(%rsi), %xmm6, %xmm6; + vpxor 2 * 16(%rsi), %xmm5, %xmm5; + vpxor 3 * 16(%rsi), %xmm4, %xmm4; + vpxor 4 * 16(%rsi), %xmm3, %xmm3; + vpxor 5 * 16(%rsi), %xmm2, %xmm2; + vpxor 6 * 16(%rsi), %xmm1, %xmm1; + vpxor 7 * 16(%rsi), %xmm0, %xmm0; + vpxor 8 * 16(%rsi), %xmm15, %xmm15; + vpxor 9 * 16(%rsi), %xmm14, %xmm14; + vpxor 10 * 16(%rsi), %xmm13, %xmm13; + vpxor 11 * 16(%rsi), %xmm12, %xmm12; + vpxor 12 * 16(%rsi), %xmm11, %xmm11; + vpxor 13 * 16(%rsi), %xmm10, %xmm10; + vpxor 14 * 16(%rsi), %xmm9, %xmm9; + vpxor 15 * 16(%rsi), %xmm8, %xmm8; + + write_output(%xmm7, %xmm6, %xmm5, %xmm4, %xmm3, %xmm2, %xmm1, %xmm0, + %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, + %xmm8, %rsi); + + vzeroall; + + movq (16 * 16 + 0 * 8)(%rsp), %r10; + movq (16 * 16 + 1 * 8)(%rsp), %r11; + movq (16 * 16 + 2 * 8)(%rsp), %r12; + movq (16 * 16 + 3 * 8)(%rsp), %r13; + CFI_RESTORE(%r10); + CFI_RESTORE(%r11); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_ocb_enc,.-_gcry_camellia_aesni_avx_ocb_enc;) + +.align 8 +.globl _gcry_camellia_aesni_avx_ocb_dec +ELF(.type _gcry_camellia_aesni_avx_ocb_dec,@function;) + +_gcry_camellia_aesni_avx_ocb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (16 blocks) + * %rdx: src (16 blocks) + * %rcx: offset + * %r8 : checksum + * %r9 : L pointers (void *L[16]) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(16 * 16 + 4 * 8), %rsp; + andq $~31, %rsp; + movq %rsp, %rax; + + movq %r10, (16 * 16 + 0 * 8)(%rsp); + movq %r11, (16 * 16 + 1 * 8)(%rsp); + movq %r12, (16 * 16 + 2 * 8)(%rsp); + movq %r13, (16 * 16 + 3 * 8)(%rsp); + CFI_REG_ON_STACK(r10, 16 * 16 + 0 * 8); + CFI_REG_ON_STACK(r11, 16 * 16 + 1 * 8); + CFI_REG_ON_STACK(r12, 16 * 16 + 2 * 8); + CFI_REG_ON_STACK(r13, 16 * 16 + 3 * 8); + + vmovdqu (%rcx), %xmm15; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */ + +#define OCB_INPUT(n, lreg, xreg) \ + vmovdqu (n * 16)(%rdx), xreg; \ + vpxor (lreg), %xmm15, %xmm15; \ + vpxor xreg, %xmm15, xreg; \ + vmovdqu %xmm15, (n * 16)(%rsi); + movq (0 * 8)(%r9), %r10; + movq (1 * 8)(%r9), %r11; + movq (2 * 8)(%r9), %r12; + movq (3 * 8)(%r9), %r13; + OCB_INPUT(0, %r10, %xmm0); + vmovdqu %xmm0, (15 * 16)(%rax); + OCB_INPUT(1, %r11, %xmm14); + OCB_INPUT(2, %r12, %xmm13); + OCB_INPUT(3, %r13, %xmm12); + movq (4 * 8)(%r9), %r10; + movq (5 * 8)(%r9), %r11; + movq (6 * 8)(%r9), %r12; + movq (7 * 8)(%r9), %r13; + OCB_INPUT(4, %r10, %xmm11); + OCB_INPUT(5, %r11, %xmm10); + OCB_INPUT(6, %r12, %xmm9); + OCB_INPUT(7, %r13, %xmm8); + movq (8 * 8)(%r9), %r10; + movq (9 * 8)(%r9), %r11; + movq (10 * 8)(%r9), %r12; + movq (11 * 8)(%r9), %r13; + OCB_INPUT(8, %r10, %xmm7); + OCB_INPUT(9, %r11, %xmm6); + OCB_INPUT(10, %r12, %xmm5); + OCB_INPUT(11, %r13, %xmm4); + movq (12 * 8)(%r9), %r10; + movq (13 * 8)(%r9), %r11; + movq (14 * 8)(%r9), %r12; + movq (15 * 8)(%r9), %r13; + OCB_INPUT(12, %r10, %xmm3); + OCB_INPUT(13, %r11, %xmm2); + OCB_INPUT(14, %r12, %xmm1); + OCB_INPUT(15, %r13, %xmm0); +#undef OCB_INPUT + + vmovdqu %xmm15, (%rcx); + + movq %r8, %r10; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %r9d; + cmovel %r9d, %r8d; /* max */ + + /* inpack16_pre: */ + vmovq (key_table)(CTX, %r8, 8), %xmm15; + vpshufb .Lpack_bswap rRIP, %xmm15, %xmm15; + vpxor %xmm0, %xmm15, %xmm0; + vpxor %xmm1, %xmm15, %xmm1; + vpxor %xmm2, %xmm15, %xmm2; + vpxor %xmm3, %xmm15, %xmm3; + vpxor %xmm4, %xmm15, %xmm4; + vpxor %xmm5, %xmm15, %xmm5; + vpxor %xmm6, %xmm15, %xmm6; + vpxor %xmm7, %xmm15, %xmm7; + vpxor %xmm8, %xmm15, %xmm8; + vpxor %xmm9, %xmm15, %xmm9; + vpxor %xmm10, %xmm15, %xmm10; + vpxor %xmm11, %xmm15, %xmm11; + vpxor %xmm12, %xmm15, %xmm12; + vpxor %xmm13, %xmm15, %xmm13; + vpxor %xmm14, %xmm15, %xmm14; + vpxor 15 * 16(%rax), %xmm15, %xmm15; + + call __camellia_dec_blk16; + + vpxor 0 * 16(%rsi), %xmm7, %xmm7; + vpxor 1 * 16(%rsi), %xmm6, %xmm6; + vpxor 2 * 16(%rsi), %xmm5, %xmm5; + vpxor 3 * 16(%rsi), %xmm4, %xmm4; + vpxor 4 * 16(%rsi), %xmm3, %xmm3; + vpxor 5 * 16(%rsi), %xmm2, %xmm2; + vpxor 6 * 16(%rsi), %xmm1, %xmm1; + vpxor 7 * 16(%rsi), %xmm0, %xmm0; + vmovdqu %xmm7, (7 * 16)(%rax); + vpxor 8 * 16(%rsi), %xmm15, %xmm15; + vpxor 9 * 16(%rsi), %xmm14, %xmm14; + vpxor 10 * 16(%rsi), %xmm13, %xmm13; + vpxor 11 * 16(%rsi), %xmm12, %xmm12; + vpxor 12 * 16(%rsi), %xmm11, %xmm11; + vpxor 13 * 16(%rsi), %xmm10, %xmm10; + vpxor 14 * 16(%rsi), %xmm9, %xmm9; + vpxor 15 * 16(%rsi), %xmm8, %xmm8; + + /* Checksum_i = Checksum_{i-1} xor P_i */ + + vpxor (%r10), %xmm7, %xmm7; + vpxor %xmm6, %xmm7, %xmm7; + vpxor %xmm5, %xmm7, %xmm7; + vpxor %xmm4, %xmm7, %xmm7; + vpxor %xmm3, %xmm7, %xmm7; + vpxor %xmm2, %xmm7, %xmm7; + vpxor %xmm1, %xmm7, %xmm7; + vpxor %xmm0, %xmm7, %xmm7; + vpxor %xmm15, %xmm7, %xmm7; + vpxor %xmm14, %xmm7, %xmm7; + vpxor %xmm13, %xmm7, %xmm7; + vpxor %xmm12, %xmm7, %xmm7; + vpxor %xmm11, %xmm7, %xmm7; + vpxor %xmm10, %xmm7, %xmm7; + vpxor %xmm9, %xmm7, %xmm7; + vpxor %xmm8, %xmm7, %xmm7; + vmovdqu %xmm7, (%r10); + vmovdqu (7 * 16)(%rax), %xmm7; + + write_output(%xmm7, %xmm6, %xmm5, %xmm4, %xmm3, %xmm2, %xmm1, %xmm0, + %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9, + %xmm8, %rsi); + + vzeroall; + + movq (16 * 16 + 0 * 8)(%rsp), %r10; + movq (16 * 16 + 1 * 8)(%rsp), %r11; + movq (16 * 16 + 2 * 8)(%rsp), %r12; + movq (16 * 16 + 3 * 8)(%rsp), %r13; + CFI_RESTORE(%r10); + CFI_RESTORE(%r11); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_ocb_dec,.-_gcry_camellia_aesni_avx_ocb_dec;) + +.align 8 +.globl _gcry_camellia_aesni_avx_ocb_auth +ELF(.type _gcry_camellia_aesni_avx_ocb_auth,@function;) + +_gcry_camellia_aesni_avx_ocb_auth: + /* input: + * %rdi: ctx, CTX + * %rsi: abuf (16 blocks) + * %rdx: offset + * %rcx: checksum + * %r8 : L pointers (void *L[16]) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(16 * 16 + 4 * 8), %rsp; + andq $~31, %rsp; + movq %rsp, %rax; + + movq %r10, (16 * 16 + 0 * 8)(%rsp); + movq %r11, (16 * 16 + 1 * 8)(%rsp); + movq %r12, (16 * 16 + 2 * 8)(%rsp); + movq %r13, (16 * 16 + 3 * 8)(%rsp); + CFI_REG_ON_STACK(r10, 16 * 16 + 0 * 8); + CFI_REG_ON_STACK(r11, 16 * 16 + 1 * 8); + CFI_REG_ON_STACK(r12, 16 * 16 + 2 * 8); + CFI_REG_ON_STACK(r13, 16 * 16 + 3 * 8); + + vmovdqu (%rdx), %xmm15; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ + +#define OCB_INPUT(n, lreg, xreg) \ + vmovdqu (n * 16)(%rsi), xreg; \ + vpxor (lreg), %xmm15, %xmm15; \ + vpxor xreg, %xmm15, xreg; + + movq (0 * 8)(%r8), %r10; + movq (1 * 8)(%r8), %r11; + movq (2 * 8)(%r8), %r12; + movq (3 * 8)(%r8), %r13; + OCB_INPUT(0, %r10, %xmm0); + vmovdqu %xmm0, (15 * 16)(%rax); + OCB_INPUT(1, %r11, %xmm14); + OCB_INPUT(2, %r12, %xmm13); + OCB_INPUT(3, %r13, %xmm12); + movq (4 * 8)(%r8), %r10; + movq (5 * 8)(%r8), %r11; + movq (6 * 8)(%r8), %r12; + movq (7 * 8)(%r8), %r13; + OCB_INPUT(4, %r10, %xmm11); + OCB_INPUT(5, %r11, %xmm10); + OCB_INPUT(6, %r12, %xmm9); + OCB_INPUT(7, %r13, %xmm8); + movq (8 * 8)(%r8), %r10; + movq (9 * 8)(%r8), %r11; + movq (10 * 8)(%r8), %r12; + movq (11 * 8)(%r8), %r13; + OCB_INPUT(8, %r10, %xmm7); + OCB_INPUT(9, %r11, %xmm6); + OCB_INPUT(10, %r12, %xmm5); + OCB_INPUT(11, %r13, %xmm4); + movq (12 * 8)(%r8), %r10; + movq (13 * 8)(%r8), %r11; + movq (14 * 8)(%r8), %r12; + movq (15 * 8)(%r8), %r13; + OCB_INPUT(12, %r10, %xmm3); + OCB_INPUT(13, %r11, %xmm2); + OCB_INPUT(14, %r12, %xmm1); + OCB_INPUT(15, %r13, %xmm0); +#undef OCB_INPUT + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %r10d; + cmovel %r10d, %r8d; /* max */ + + vmovdqu %xmm15, (%rdx); + + movq %rcx, %r10; + + /* inpack16_pre: */ + vmovq (key_table)(CTX), %xmm15; + vpshufb .Lpack_bswap rRIP, %xmm15, %xmm15; + vpxor %xmm0, %xmm15, %xmm0; + vpxor %xmm1, %xmm15, %xmm1; + vpxor %xmm2, %xmm15, %xmm2; + vpxor %xmm3, %xmm15, %xmm3; + vpxor %xmm4, %xmm15, %xmm4; + vpxor %xmm5, %xmm15, %xmm5; + vpxor %xmm6, %xmm15, %xmm6; + vpxor %xmm7, %xmm15, %xmm7; + vpxor %xmm8, %xmm15, %xmm8; + vpxor %xmm9, %xmm15, %xmm9; + vpxor %xmm10, %xmm15, %xmm10; + vpxor %xmm11, %xmm15, %xmm11; + vpxor %xmm12, %xmm15, %xmm12; + vpxor %xmm13, %xmm15, %xmm13; + vpxor %xmm14, %xmm15, %xmm14; + vpxor 15 * 16(%rax), %xmm15, %xmm15; + + call __camellia_enc_blk16; + + vpxor %xmm7, %xmm6, %xmm6; + vpxor %xmm5, %xmm4, %xmm4; + vpxor %xmm3, %xmm2, %xmm2; + vpxor %xmm1, %xmm0, %xmm0; + vpxor %xmm15, %xmm14, %xmm14; + vpxor %xmm13, %xmm12, %xmm12; + vpxor %xmm11, %xmm10, %xmm10; + vpxor %xmm9, %xmm8, %xmm8; + + vpxor %xmm6, %xmm4, %xmm4; + vpxor %xmm2, %xmm0, %xmm0; + vpxor %xmm14, %xmm12, %xmm12; + vpxor %xmm10, %xmm8, %xmm8; + + vpxor %xmm4, %xmm0, %xmm0; + vpxor %xmm12, %xmm8, %xmm8; + + vpxor %xmm0, %xmm8, %xmm0; + vpxor (%r10), %xmm0, %xmm0; + vmovdqu %xmm0, (%r10); + + vzeroall; + + movq (16 * 16 + 0 * 8)(%rsp), %r10; + movq (16 * 16 + 1 * 8)(%rsp), %r11; + movq (16 * 16 + 2 * 8)(%rsp), %r12; + movq (16 * 16 + 3 * 8)(%rsp), %r13; + CFI_RESTORE(%r10); + CFI_RESTORE(%r11); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_ocb_auth,.-_gcry_camellia_aesni_avx_ocb_auth;) + +/* + * IN: + * ab: 64-bit AB state + * cd: 64-bit CD state + */ +#define camellia_f(ab, x, t0, t1, t2, t3, t4, inv_shift_row, sbox4mask, \ + _0f0f0f0fmask, pre_s1lo_mask, pre_s1hi_mask, key) \ + vmovq key, t0; \ + vpxor x, x, t3; \ + \ + vpxor ab, t0, x; \ + \ + /* \ + * S-function with AES subbytes \ + */ \ + \ + /* input rotation for sbox4 (<<< 1) */ \ + vpand x, sbox4mask, t0; \ + vpandn x, sbox4mask, x; \ + vpaddw t0, t0, t1; \ + vpsrlw $7, t0, t0; \ + vpor t0, t1, t0; \ + vpand sbox4mask, t0, t0; \ + vpor t0, x, x; \ + \ + vmovdqa .Lpost_tf_lo_s1 rRIP, t0; \ + vmovdqa .Lpost_tf_hi_s1 rRIP, t1; \ + \ + /* prefilter sboxes */ \ + filter_8bit(x, pre_s1lo_mask, pre_s1hi_mask, _0f0f0f0fmask, t2); \ + \ + /* AES subbytes + AES shift rows + AES inv shift rows */ \ + vaesenclast t3, x, x; \ + \ + /* postfilter sboxes */ \ + filter_8bit(x, t0, t1, _0f0f0f0fmask, t2); \ + \ + /* output rotation for sbox2 (<<< 1) */ \ + /* output rotation for sbox3 (>>> 1) */ \ + vpshufb inv_shift_row, x, t1; \ + vpshufb .Lsp0044440444044404mask rRIP, x, t4; \ + vpshufb .Lsp1110111010011110mask rRIP, x, x; \ + vpaddb t1, t1, t2; \ + vpsrlw $7, t1, t0; \ + vpsllw $7, t1, t3; \ + vpor t0, t2, t0; \ + vpsrlw $1, t1, t1; \ + vpshufb .Lsp0222022222000222mask rRIP, t0, t0; \ + vpor t1, t3, t1; \ + \ + vpxor x, t4, t4; \ + vpshufb .Lsp3033303303303033mask rRIP, t1, t1; \ + vpxor t4, t0, t0; \ + vpxor t1, t0, t0; \ + vpsrldq $8, t0, x; \ + vpxor t0, x, x; + +#define vec_rol128(in, out, nrol, t0) \ + vpshufd $0x4e, in, out; \ + vpsllq $(nrol), in, t0; \ + vpsrlq $(64-(nrol)), out, out; \ + vpaddd t0, out, out; + +#define vec_ror128(in, out, nror, t0) \ + vpshufd $0x4e, in, out; \ + vpsrlq $(nror), in, t0; \ + vpsllq $(64-(nror)), out, out; \ + vpaddd t0, out, out; + + +.align 16 +.Linv_shift_row_and_unpcklbw: + .byte 0x00, 0xff, 0x0d, 0xff, 0x0a, 0xff, 0x07, 0xff + .byte 0x04, 0xff, 0x01, 0xff, 0x0e, 0xff, 0x0b, 0xff +.Lsp0044440444044404mask: + .long 0xffff0404, 0x0404ff04; + .long 0x0d0dff0d, 0x0d0dff0d; +.Lsp1110111010011110mask: + .long 0x000000ff, 0x000000ff; + .long 0x0bffff0b, 0x0b0b0bff; +.Lsp0222022222000222mask: + .long 0xff060606, 0xff060606; + .long 0x0c0cffff, 0xff0c0c0c; +.Lsp3033303303303033mask: + .long 0x04ff0404, 0x04ff0404; + .long 0xff0a0aff, 0x0aff0a0a; +.Lsbox4_input_mask: + .byte 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00; +.Lsigma1: + .long 0x3BCC908B, 0xA09E667F; +.Lsigma2: + .long 0x4CAA73B2, 0xB67AE858; +.Lsigma3: + .long 0xE94F82BE, 0xC6EF372F; +.Lsigma4: + .long 0xF1D36F1C, 0x54FF53A5; +.Lsigma5: + .long 0xDE682D1D, 0x10E527FA; +.Lsigma6: + .long 0xB3E6C1FD, 0xB05688C2; + + +.align 8 +ELF(.type __camellia_avx_setup128,@function;) +__camellia_avx_setup128: + /* input: + * %rdi: ctx, CTX; subkey storage at key_table(CTX) + * %xmm0: key + */ + CFI_STARTPROC(); + +#define cmll_sub(n, ctx) (key_table+((n)*8))(ctx) +#define KL128 %xmm0 +#define KA128 %xmm2 + + vpshufb .Lbswap128_mask rRIP, KL128, KL128; + + vmovdqa .Linv_shift_row_and_unpcklbw rRIP, %xmm11; + vmovq .Lsbox4_input_mask rRIP, %xmm12; + vbroadcastss .L0f0f0f0f rRIP, %xmm13; + vmovdqa .Lpre_tf_lo_s1 rRIP, %xmm14; + vmovdqa .Lpre_tf_hi_s1 rRIP, %xmm15; + + /* + * Generate KA + */ + vpsrldq $8, KL128, %xmm2; + vmovdqa KL128, %xmm3; + vpslldq $8, %xmm3, %xmm3; + vpsrldq $8, %xmm3, %xmm3; + + camellia_f(%xmm2, %xmm4, %xmm1, + %xmm5, %xmm6, %xmm7, %xmm8, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma1 rRIP); + vpxor %xmm4, %xmm3, %xmm3; + camellia_f(%xmm3, %xmm2, %xmm1, + %xmm5, %xmm6, %xmm7, %xmm8, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma2 rRIP); + camellia_f(%xmm2, %xmm3, %xmm1, + %xmm5, %xmm6, %xmm7, %xmm8, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma3 rRIP); + vpxor %xmm4, %xmm3, %xmm3; + camellia_f(%xmm3, %xmm4, %xmm1, + %xmm5, %xmm6, %xmm7, %xmm8, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma4 rRIP); + + vpslldq $8, %xmm3, %xmm3; + vpxor %xmm4, %xmm2, %xmm2; + vpsrldq $8, %xmm3, %xmm3; + vpslldq $8, %xmm2, KA128; + vpor %xmm3, KA128, KA128; + + /* + * Generate subkeys + */ + vmovdqu KA128, cmll_sub(24, CTX); + vec_rol128(KL128, %xmm3, 15, %xmm15); + vec_rol128(KA128, %xmm4, 15, %xmm15); + vec_rol128(KA128, %xmm5, 30, %xmm15); + vec_rol128(KL128, %xmm6, 45, %xmm15); + vec_rol128(KA128, %xmm7, 45, %xmm15); + vec_rol128(KL128, %xmm8, 60, %xmm15); + vec_rol128(KA128, %xmm9, 60, %xmm15); + vec_ror128(KL128, %xmm10, 128-77, %xmm15); + + /* absorb kw2 to other subkeys */ + vpslldq $8, KL128, %xmm15; + vpsrldq $8, %xmm15, %xmm15; + vpxor %xmm15, KA128, KA128; + vpxor %xmm15, %xmm3, %xmm3; + vpxor %xmm15, %xmm4, %xmm4; + + /* subl(1) ^= subr(1) & ~subr(9); */ + vpandn %xmm15, %xmm5, %xmm13; + vpslldq $12, %xmm13, %xmm13; + vpsrldq $8, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm5, %xmm14; + vpslld $1, %xmm14, %xmm11; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm11, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpxor %xmm15, %xmm6, %xmm6; + vpxor %xmm15, %xmm8, %xmm8; + vpxor %xmm15, %xmm9, %xmm9; + + /* subl(1) ^= subr(1) & ~subr(17); */ + vpandn %xmm15, %xmm10, %xmm13; + vpslldq $12, %xmm13, %xmm13; + vpsrldq $8, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm10, %xmm14; + vpslld $1, %xmm14, %xmm11; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm11, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpshufd $0x1b, KL128, KL128; + vpshufd $0x1b, KA128, KA128; + vpshufd $0x1b, %xmm3, %xmm3; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm5, %xmm5; + vpshufd $0x1b, %xmm6, %xmm6; + vpshufd $0x1b, %xmm7, %xmm7; + vpshufd $0x1b, %xmm8, %xmm8; + vpshufd $0x1b, %xmm9, %xmm9; + vpshufd $0x1b, %xmm10, %xmm10; + + vmovdqu KL128, cmll_sub(0, CTX); + vpshufd $0x1b, KL128, KL128; + vmovdqu KA128, cmll_sub(2, CTX); + vmovdqu %xmm3, cmll_sub(4, CTX); + vmovdqu %xmm4, cmll_sub(6, CTX); + vmovdqu %xmm5, cmll_sub(8, CTX); + vmovdqu %xmm6, cmll_sub(10, CTX); + vpsrldq $8, %xmm8, %xmm8; + vmovq %xmm7, cmll_sub(12, CTX); + vmovq %xmm8, cmll_sub(13, CTX); + vmovdqu %xmm9, cmll_sub(14, CTX); + vmovdqu %xmm10, cmll_sub(16, CTX); + + vmovdqu cmll_sub(24, CTX), KA128; + + vec_ror128(KL128, %xmm3, 128 - 94, %xmm7); + vec_ror128(KA128, %xmm4, 128 - 94, %xmm7); + vec_ror128(KL128, %xmm5, 128 - 111, %xmm7); + vec_ror128(KA128, %xmm6, 128 - 111, %xmm7); + + vpxor %xmm15, %xmm3, %xmm3; + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm5, %xmm5; + vpslldq $8, %xmm15, %xmm15; + vpxor %xmm15, %xmm6, %xmm6; + + /* absorb kw4 to other subkeys */ + vpslldq $8, %xmm6, %xmm15; + vpxor %xmm15, %xmm5, %xmm5; + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm3, %xmm3; + + /* subl(25) ^= subr(25) & ~subr(16); */ + vpshufd $0x1b, cmll_sub(16, CTX), %xmm10; + vpandn %xmm15, %xmm10, %xmm13; + vpslldq $4, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(25) & subl(16), subr(25) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm10, %xmm14; + vpslld $1, %xmm14, %xmm11; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm11, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpshufd $0x1b, %xmm3, %xmm3; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm5, %xmm5; + vpshufd $0x1b, %xmm6, %xmm6; + + vmovdqu %xmm3, cmll_sub(18, CTX); + vmovdqu %xmm4, cmll_sub(20, CTX); + vmovdqu %xmm5, cmll_sub(22, CTX); + vmovdqu %xmm6, cmll_sub(24, CTX); + + vpshufd $0x1b, cmll_sub(14, CTX), %xmm3; + vpshufd $0x1b, cmll_sub(12, CTX), %xmm4; + vpshufd $0x1b, cmll_sub(10, CTX), %xmm5; + vpshufd $0x1b, cmll_sub(8, CTX), %xmm6; + + vpxor %xmm15, %xmm3, %xmm3; + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm5, %xmm5; + + /* subl(25) ^= subr(25) & ~subr(8); */ + vpandn %xmm15, %xmm6, %xmm13; + vpslldq $4, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(25) & subl(8), subr(25) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm6, %xmm14; + vpslld $1, %xmm14, %xmm11; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm11, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpshufd $0x1b, %xmm3, %xmm3; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm5, %xmm5; + + vmovdqu %xmm3, cmll_sub(14, CTX); + vmovdqu %xmm4, cmll_sub(12, CTX); + vmovdqu %xmm5, cmll_sub(10, CTX); + + vpshufd $0x1b, cmll_sub(6, CTX), %xmm6; + vpshufd $0x1b, cmll_sub(4, CTX), %xmm4; + vpshufd $0x1b, cmll_sub(2, CTX), %xmm2; + vpshufd $0x1b, cmll_sub(0, CTX), %xmm0; + + vpxor %xmm15, %xmm6, %xmm6; + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm2, %xmm2; + vpxor %xmm15, %xmm0, %xmm0; + + vpshufd $0x1b, %xmm6, %xmm6; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm2, %xmm2; + vpshufd $0x1b, %xmm0, %xmm0; + + vpsrldq $8, %xmm2, %xmm3; + vpsrldq $8, %xmm4, %xmm5; + vpsrldq $8, %xmm6, %xmm7; + + /* + * key XOR is end of F-function. + */ + vpxor %xmm2, %xmm0, %xmm0; + vpxor %xmm4, %xmm2, %xmm2; + + vmovq %xmm0, cmll_sub(0, CTX); + vmovq %xmm3, cmll_sub(2, CTX); + vpxor %xmm5, %xmm3, %xmm3; + vpxor %xmm6, %xmm4, %xmm4; + vpxor %xmm7, %xmm5, %xmm5; + vmovq %xmm2, cmll_sub(3, CTX); + vmovq %xmm3, cmll_sub(4, CTX); + vmovq %xmm4, cmll_sub(5, CTX); + vmovq %xmm5, cmll_sub(6, CTX); + + vmovq cmll_sub(7, CTX), %xmm7; + vmovq cmll_sub(8, CTX), %xmm8; + vmovq cmll_sub(9, CTX), %xmm9; + vmovq cmll_sub(10, CTX), %xmm10; + /* tl = subl(10) ^ (subr(10) & ~subr(8)); */ + vpandn %xmm10, %xmm8, %xmm15; + vpsrldq $4, %xmm15, %xmm15; + vpxor %xmm15, %xmm10, %xmm0; + /* dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw); */ + vpand %xmm8, %xmm0, %xmm15; + vpslld $1, %xmm15, %xmm14; + vpsrld $31, %xmm15, %xmm15; + vpaddd %xmm14, %xmm15, %xmm15; + vpslldq $12, %xmm15, %xmm15; + vpsrldq $8, %xmm15, %xmm15; + vpxor %xmm15, %xmm0, %xmm0; + + vpxor %xmm0, %xmm6, %xmm6; + vmovq %xmm6, cmll_sub(7, CTX); + + vmovq cmll_sub(11, CTX), %xmm11; + vmovq cmll_sub(12, CTX), %xmm12; + vmovq cmll_sub(13, CTX), %xmm13; + vmovq cmll_sub(14, CTX), %xmm14; + vmovq cmll_sub(15, CTX), %xmm15; + /* tl = subl(7) ^ (subr(7) & ~subr(9)); */ + vpandn %xmm7, %xmm9, %xmm1; + vpsrldq $4, %xmm1, %xmm1; + vpxor %xmm1, %xmm7, %xmm0; + /* dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw); */ + vpand %xmm9, %xmm0, %xmm1; + vpslld $1, %xmm1, %xmm2; + vpsrld $31, %xmm1, %xmm1; + vpaddd %xmm2, %xmm1, %xmm1; + vpslldq $12, %xmm1, %xmm1; + vpsrldq $8, %xmm1, %xmm1; + vpxor %xmm1, %xmm0, %xmm0; + + vpxor %xmm11, %xmm0, %xmm0; + vpxor %xmm12, %xmm10, %xmm10; + vpxor %xmm13, %xmm11, %xmm11; + vpxor %xmm14, %xmm12, %xmm12; + vpxor %xmm15, %xmm13, %xmm13; + vmovq %xmm0, cmll_sub(10, CTX); + vmovq %xmm10, cmll_sub(11, CTX); + vmovq %xmm11, cmll_sub(12, CTX); + vmovq %xmm12, cmll_sub(13, CTX); + vmovq %xmm13, cmll_sub(14, CTX); + + vmovq cmll_sub(16, CTX), %xmm6; + vmovq cmll_sub(17, CTX), %xmm7; + vmovq cmll_sub(18, CTX), %xmm8; + vmovq cmll_sub(19, CTX), %xmm9; + vmovq cmll_sub(20, CTX), %xmm10; + /* tl = subl(18) ^ (subr(18) & ~subr(16)); */ + vpandn %xmm8, %xmm6, %xmm1; + vpsrldq $4, %xmm1, %xmm1; + vpxor %xmm1, %xmm8, %xmm0; + /* dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw); */ + vpand %xmm6, %xmm0, %xmm1; + vpslld $1, %xmm1, %xmm2; + vpsrld $31, %xmm1, %xmm1; + vpaddd %xmm2, %xmm1, %xmm1; + vpslldq $12, %xmm1, %xmm1; + vpsrldq $8, %xmm1, %xmm1; + vpxor %xmm1, %xmm0, %xmm0; + + vpxor %xmm14, %xmm0, %xmm0; + vmovq %xmm0, cmll_sub(15, CTX); + + /* tl = subl(15) ^ (subr(15) & ~subr(17)); */ + vpandn %xmm15, %xmm7, %xmm1; + vpsrldq $4, %xmm1, %xmm1; + vpxor %xmm1, %xmm15, %xmm0; + /* dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw); */ + vpand %xmm7, %xmm0, %xmm1; + vpslld $1, %xmm1, %xmm2; + vpsrld $31, %xmm1, %xmm1; + vpaddd %xmm2, %xmm1, %xmm1; + vpslldq $12, %xmm1, %xmm1; + vpsrldq $8, %xmm1, %xmm1; + vpxor %xmm1, %xmm0, %xmm0; + + vmovq cmll_sub(21, CTX), %xmm1; + vmovq cmll_sub(22, CTX), %xmm2; + vmovq cmll_sub(23, CTX), %xmm3; + vmovq cmll_sub(24, CTX), %xmm4; + + vpxor %xmm9, %xmm0, %xmm0; + vpxor %xmm10, %xmm8, %xmm8; + vpxor %xmm1, %xmm9, %xmm9; + vpxor %xmm2, %xmm10, %xmm10; + vpxor %xmm3, %xmm1, %xmm1; + vpxor %xmm4, %xmm3, %xmm3; + + vmovq %xmm0, cmll_sub(18, CTX); + vmovq %xmm8, cmll_sub(19, CTX); + vmovq %xmm9, cmll_sub(20, CTX); + vmovq %xmm10, cmll_sub(21, CTX); + vmovq %xmm1, cmll_sub(22, CTX); + vmovq %xmm2, cmll_sub(23, CTX); + vmovq %xmm3, cmll_sub(24, CTX); + + /* kw2 and kw4 are unused now. */ + movq $0, cmll_sub(1, CTX); + movq $0, cmll_sub(25, CTX); + + vzeroall; + + ret; + CFI_ENDPROC(); +ELF(.size __camellia_avx_setup128,.-__camellia_avx_setup128;) + +.align 8 +ELF(.type __camellia_avx_setup256,@function;) + +__camellia_avx_setup256: + /* input: + * %rdi: ctx, CTX; subkey storage at key_table(CTX) + * %xmm0 & %xmm1: key + */ + CFI_STARTPROC(); + +#define KL128 %xmm0 +#define KR128 %xmm1 +#define KA128 %xmm2 +#define KB128 %xmm3 + + vpshufb .Lbswap128_mask rRIP, KL128, KL128; + vpshufb .Lbswap128_mask rRIP, KR128, KR128; + + vmovdqa .Linv_shift_row_and_unpcklbw rRIP, %xmm11; + vmovq .Lsbox4_input_mask rRIP, %xmm12; + vbroadcastss .L0f0f0f0f rRIP, %xmm13; + vmovdqa .Lpre_tf_lo_s1 rRIP, %xmm14; + vmovdqa .Lpre_tf_hi_s1 rRIP, %xmm15; + + /* + * Generate KA + */ + vpxor KL128, KR128, %xmm3; + vpsrldq $8, KR128, %xmm6; + vpsrldq $8, %xmm3, %xmm2; + vpslldq $8, %xmm3, %xmm3; + vpsrldq $8, %xmm3, %xmm3; + + camellia_f(%xmm2, %xmm4, %xmm5, + %xmm7, %xmm8, %xmm9, %xmm10, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma1 rRIP); + vpxor %xmm4, %xmm3, %xmm3; + camellia_f(%xmm3, %xmm2, %xmm5, + %xmm7, %xmm8, %xmm9, %xmm10, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma2 rRIP); + vpxor %xmm6, %xmm2, %xmm2; + camellia_f(%xmm2, %xmm3, %xmm5, + %xmm7, %xmm8, %xmm9, %xmm10, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma3 rRIP); + vpxor %xmm4, %xmm3, %xmm3; + vpxor KR128, %xmm3, %xmm3; + camellia_f(%xmm3, %xmm4, %xmm5, + %xmm7, %xmm8, %xmm9, %xmm10, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma4 rRIP); + + vpslldq $8, %xmm3, %xmm3; + vpxor %xmm4, %xmm2, %xmm2; + vpsrldq $8, %xmm3, %xmm3; + vpslldq $8, %xmm2, KA128; + vpor %xmm3, KA128, KA128; + + /* + * Generate KB + */ + vpxor KA128, KR128, %xmm3; + vpsrldq $8, %xmm3, %xmm4; + vpslldq $8, %xmm3, %xmm3; + vpsrldq $8, %xmm3, %xmm3; + + camellia_f(%xmm4, %xmm5, %xmm6, + %xmm7, %xmm8, %xmm9, %xmm10, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma5 rRIP); + vpxor %xmm5, %xmm3, %xmm3; + + camellia_f(%xmm3, %xmm5, %xmm6, + %xmm7, %xmm8, %xmm9, %xmm10, + %xmm11, %xmm12, %xmm13, %xmm14, %xmm15, .Lsigma6 rRIP); + vpslldq $8, %xmm3, %xmm3; + vpxor %xmm5, %xmm4, %xmm4; + vpsrldq $8, %xmm3, %xmm3; + vpslldq $8, %xmm4, %xmm4; + vpor %xmm3, %xmm4, KB128; + + /* + * Generate subkeys + */ + vmovdqu KB128, cmll_sub(32, CTX); + vec_rol128(KR128, %xmm4, 15, %xmm15); + vec_rol128(KA128, %xmm5, 15, %xmm15); + vec_rol128(KR128, %xmm6, 30, %xmm15); + vec_rol128(KB128, %xmm7, 30, %xmm15); + vec_rol128(KL128, %xmm8, 45, %xmm15); + vec_rol128(KA128, %xmm9, 45, %xmm15); + vec_rol128(KL128, %xmm10, 60, %xmm15); + vec_rol128(KR128, %xmm11, 60, %xmm15); + vec_rol128(KB128, %xmm12, 60, %xmm15); + + /* absorb kw2 to other subkeys */ + vpslldq $8, KL128, %xmm15; + vpsrldq $8, %xmm15, %xmm15; + vpxor %xmm15, KB128, KB128; + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm5, %xmm5; + + /* subl(1) ^= subr(1) & ~subr(9); */ + vpandn %xmm15, %xmm6, %xmm13; + vpslldq $12, %xmm13, %xmm13; + vpsrldq $8, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm6, %xmm14; + vpslld $1, %xmm14, %xmm13; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm13, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpxor %xmm15, %xmm7, %xmm7; + vpxor %xmm15, %xmm8, %xmm8; + vpxor %xmm15, %xmm9, %xmm9; + + vpshufd $0x1b, KL128, KL128; + vpshufd $0x1b, KB128, KB128; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm5, %xmm5; + vpshufd $0x1b, %xmm6, %xmm6; + vpshufd $0x1b, %xmm7, %xmm7; + vpshufd $0x1b, %xmm8, %xmm8; + vpshufd $0x1b, %xmm9, %xmm9; + + vmovdqu KL128, cmll_sub(0, CTX); + vpshufd $0x1b, KL128, KL128; + vmovdqu KB128, cmll_sub(2, CTX); + vmovdqu %xmm4, cmll_sub(4, CTX); + vmovdqu %xmm5, cmll_sub(6, CTX); + vmovdqu %xmm6, cmll_sub(8, CTX); + vmovdqu %xmm7, cmll_sub(10, CTX); + vmovdqu %xmm8, cmll_sub(12, CTX); + vmovdqu %xmm9, cmll_sub(14, CTX); + + vmovdqu cmll_sub(32, CTX), KB128; + + /* subl(1) ^= subr(1) & ~subr(17); */ + vpandn %xmm15, %xmm10, %xmm13; + vpslldq $12, %xmm13, %xmm13; + vpsrldq $8, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm10, %xmm14; + vpslld $1, %xmm14, %xmm13; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm13, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpxor %xmm15, %xmm11, %xmm11; + vpxor %xmm15, %xmm12, %xmm12; + + vec_ror128(KL128, %xmm4, 128-77, %xmm14); + vec_ror128(KA128, %xmm5, 128-77, %xmm14); + vec_ror128(KR128, %xmm6, 128-94, %xmm14); + vec_ror128(KA128, %xmm7, 128-94, %xmm14); + vec_ror128(KL128, %xmm8, 128-111, %xmm14); + vec_ror128(KB128, %xmm9, 128-111, %xmm14); + + vpxor %xmm15, %xmm4, %xmm4; + + vpshufd $0x1b, %xmm10, %xmm10; + vpshufd $0x1b, %xmm11, %xmm11; + vpshufd $0x1b, %xmm12, %xmm12; + vpshufd $0x1b, %xmm4, %xmm4; + + vmovdqu %xmm10, cmll_sub(16, CTX); + vmovdqu %xmm11, cmll_sub(18, CTX); + vmovdqu %xmm12, cmll_sub(20, CTX); + vmovdqu %xmm4, cmll_sub(22, CTX); + + /* subl(1) ^= subr(1) & ~subr(25); */ + vpandn %xmm15, %xmm5, %xmm13; + vpslldq $12, %xmm13, %xmm13; + vpsrldq $8, %xmm13, %xmm13; + vpxor %xmm13, %xmm15, %xmm15; + /* dw = subl(1) & subl(25), subr(1) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm5, %xmm14; + vpslld $1, %xmm14, %xmm13; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm13, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpxor %xmm15, %xmm6, %xmm6; + vpxor %xmm15, %xmm7, %xmm7; + vpxor %xmm15, %xmm8, %xmm8; + vpslldq $8, %xmm15, %xmm15; + vpxor %xmm15, %xmm9, %xmm9; + + /* absorb kw4 to other subkeys */ + vpslldq $8, %xmm9, %xmm15; + vpxor %xmm15, %xmm8, %xmm8; + vpxor %xmm15, %xmm7, %xmm7; + vpxor %xmm15, %xmm6, %xmm6; + + /* subl(33) ^= subr(33) & ~subr(24); */ + vpandn %xmm15, %xmm5, %xmm14; + vpslldq $4, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + /* dw = subl(33) & subl(24), subr(33) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm5, %xmm14; + vpslld $1, %xmm14, %xmm13; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm13, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpshufd $0x1b, %xmm5, %xmm5; + vpshufd $0x1b, %xmm6, %xmm6; + vpshufd $0x1b, %xmm7, %xmm7; + vpshufd $0x1b, %xmm8, %xmm8; + vpshufd $0x1b, %xmm9, %xmm9; + + vmovdqu %xmm5, cmll_sub(24, CTX); + vmovdqu %xmm6, cmll_sub(26, CTX); + vmovdqu %xmm7, cmll_sub(28, CTX); + vmovdqu %xmm8, cmll_sub(30, CTX); + vmovdqu %xmm9, cmll_sub(32, CTX); + + vpshufd $0x1b, cmll_sub(22, CTX), %xmm0; + vpshufd $0x1b, cmll_sub(20, CTX), %xmm1; + vpshufd $0x1b, cmll_sub(18, CTX), %xmm2; + vpshufd $0x1b, cmll_sub(16, CTX), %xmm3; + vpshufd $0x1b, cmll_sub(14, CTX), %xmm4; + vpshufd $0x1b, cmll_sub(12, CTX), %xmm5; + vpshufd $0x1b, cmll_sub(10, CTX), %xmm6; + vpshufd $0x1b, cmll_sub(8, CTX), %xmm7; + + vpxor %xmm15, %xmm0, %xmm0; + vpxor %xmm15, %xmm1, %xmm1; + vpxor %xmm15, %xmm2, %xmm2; + + /* subl(33) ^= subr(33) & ~subr(24); */ + vpandn %xmm15, %xmm3, %xmm14; + vpslldq $4, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + /* dw = subl(33) & subl(24), subr(33) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm3, %xmm14; + vpslld $1, %xmm14, %xmm13; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm13, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm5, %xmm5; + vpxor %xmm15, %xmm6, %xmm6; + + vpshufd $0x1b, %xmm0, %xmm0; + vpshufd $0x1b, %xmm1, %xmm1; + vpshufd $0x1b, %xmm2, %xmm2; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm5, %xmm5; + vpshufd $0x1b, %xmm6, %xmm6; + + vmovdqu %xmm0, cmll_sub(22, CTX); + vmovdqu %xmm1, cmll_sub(20, CTX); + vmovdqu %xmm2, cmll_sub(18, CTX); + vmovdqu %xmm4, cmll_sub(14, CTX); + vmovdqu %xmm5, cmll_sub(12, CTX); + vmovdqu %xmm6, cmll_sub(10, CTX); + + vpshufd $0x1b, cmll_sub(6, CTX), %xmm6; + vpshufd $0x1b, cmll_sub(4, CTX), %xmm4; + vpshufd $0x1b, cmll_sub(2, CTX), %xmm2; + vpshufd $0x1b, cmll_sub(0, CTX), %xmm0; + + /* subl(33) ^= subr(33) & ~subr(24); */ + vpandn %xmm15, %xmm7, %xmm14; + vpslldq $4, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + /* dw = subl(33) & subl(24), subr(33) ^= CAMELLIA_RL1(dw); */ + vpand %xmm15, %xmm7, %xmm14; + vpslld $1, %xmm14, %xmm13; + vpsrld $31, %xmm14, %xmm14; + vpaddd %xmm13, %xmm14, %xmm14; + vpsrldq $12, %xmm14, %xmm14; + vpslldq $8, %xmm14, %xmm14; + vpxor %xmm14, %xmm15, %xmm15; + + vpxor %xmm15, %xmm6, %xmm6; + vpxor %xmm15, %xmm4, %xmm4; + vpxor %xmm15, %xmm2, %xmm2; + vpxor %xmm15, %xmm0, %xmm0; + + vpshufd $0x1b, %xmm6, %xmm6; + vpshufd $0x1b, %xmm4, %xmm4; + vpshufd $0x1b, %xmm2, %xmm2; + vpshufd $0x1b, %xmm0, %xmm0; + + vpsrldq $8, %xmm2, %xmm3; + vpsrldq $8, %xmm4, %xmm5; + vpsrldq $8, %xmm6, %xmm7; + + /* + * key XOR is end of F-function. + */ + vpxor %xmm2, %xmm0, %xmm0; + vpxor %xmm4, %xmm2, %xmm2; + + vmovq %xmm0, cmll_sub(0, CTX); + vmovq %xmm3, cmll_sub(2, CTX); + vpxor %xmm5, %xmm3, %xmm3; + vpxor %xmm6, %xmm4, %xmm4; + vpxor %xmm7, %xmm5, %xmm5; + vmovq %xmm2, cmll_sub(3, CTX); + vmovq %xmm3, cmll_sub(4, CTX); + vmovq %xmm4, cmll_sub(5, CTX); + vmovq %xmm5, cmll_sub(6, CTX); + + vmovq cmll_sub(7, CTX), %xmm7; + vmovq cmll_sub(8, CTX), %xmm8; + vmovq cmll_sub(9, CTX), %xmm9; + vmovq cmll_sub(10, CTX), %xmm10; + /* tl = subl(10) ^ (subr(10) & ~subr(8)); */ + vpandn %xmm10, %xmm8, %xmm15; + vpsrldq $4, %xmm15, %xmm15; + vpxor %xmm15, %xmm10, %xmm0; + /* dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw); */ + vpand %xmm8, %xmm0, %xmm15; + vpslld $1, %xmm15, %xmm14; + vpsrld $31, %xmm15, %xmm15; + vpaddd %xmm14, %xmm15, %xmm15; + vpslldq $12, %xmm15, %xmm15; + vpsrldq $8, %xmm15, %xmm15; + vpxor %xmm15, %xmm0, %xmm0; + + vpxor %xmm0, %xmm6, %xmm6; + vmovq %xmm6, cmll_sub(7, CTX); + + vmovq cmll_sub(11, CTX), %xmm11; + vmovq cmll_sub(12, CTX), %xmm12; + vmovq cmll_sub(13, CTX), %xmm13; + vmovq cmll_sub(14, CTX), %xmm14; + vmovq cmll_sub(15, CTX), %xmm15; + /* tl = subl(7) ^ (subr(7) & ~subr(9)); */ + vpandn %xmm7, %xmm9, %xmm1; + vpsrldq $4, %xmm1, %xmm1; + vpxor %xmm1, %xmm7, %xmm0; + /* dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw); */ + vpand %xmm9, %xmm0, %xmm1; + vpslld $1, %xmm1, %xmm2; + vpsrld $31, %xmm1, %xmm1; + vpaddd %xmm2, %xmm1, %xmm1; + vpslldq $12, %xmm1, %xmm1; + vpsrldq $8, %xmm1, %xmm1; + vpxor %xmm1, %xmm0, %xmm0; + + vpxor %xmm11, %xmm0, %xmm0; + vpxor %xmm12, %xmm10, %xmm10; + vpxor %xmm13, %xmm11, %xmm11; + vpxor %xmm14, %xmm12, %xmm12; + vpxor %xmm15, %xmm13, %xmm13; + vmovq %xmm0, cmll_sub(10, CTX); + vmovq %xmm10, cmll_sub(11, CTX); + vmovq %xmm11, cmll_sub(12, CTX); + vmovq %xmm12, cmll_sub(13, CTX); + vmovq %xmm13, cmll_sub(14, CTX); + + vmovq cmll_sub(16, CTX), %xmm6; + vmovq cmll_sub(17, CTX), %xmm7; + vmovq cmll_sub(18, CTX), %xmm8; + vmovq cmll_sub(19, CTX), %xmm9; + vmovq cmll_sub(20, CTX), %xmm10; + /* tl = subl(18) ^ (subr(18) & ~subr(16)); */ + vpandn %xmm8, %xmm6, %xmm1; + vpsrldq $4, %xmm1, %xmm1; + vpxor %xmm1, %xmm8, %xmm0; + /* dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw); */ + vpand %xmm6, %xmm0, %xmm1; + vpslld $1, %xmm1, %xmm2; + vpsrld $31, %xmm1, %xmm1; + vpaddd %xmm2, %xmm1, %xmm1; + vpslldq $12, %xmm1, %xmm1; + vpsrldq $8, %xmm1, %xmm1; + vpxor %xmm1, %xmm0, %xmm0; + + vpxor %xmm14, %xmm0, %xmm0; + vmovq %xmm0, cmll_sub(15, CTX); + + /* tl = subl(15) ^ (subr(15) & ~subr(17)); */ + vpandn %xmm15, %xmm7, %xmm1; + vpsrldq $4, %xmm1, %xmm1; + vpxor %xmm1, %xmm15, %xmm0; + /* dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw); */ + vpand %xmm7, %xmm0, %xmm1; + vpslld $1, %xmm1, %xmm2; + vpsrld $31, %xmm1, %xmm1; + vpaddd %xmm2, %xmm1, %xmm1; + vpslldq $12, %xmm1, %xmm1; + vpsrldq $8, %xmm1, %xmm1; + vpxor %xmm1, %xmm0, %xmm0; + + vmovq cmll_sub(21, CTX), %xmm1; + vmovq cmll_sub(22, CTX), %xmm2; + vmovq cmll_sub(23, CTX), %xmm3; + vmovq cmll_sub(24, CTX), %xmm4; + + vpxor %xmm9, %xmm0, %xmm0; + vpxor %xmm10, %xmm8, %xmm8; + vpxor %xmm1, %xmm9, %xmm9; + vpxor %xmm2, %xmm10, %xmm10; + vpxor %xmm3, %xmm1, %xmm1; + + vmovq %xmm0, cmll_sub(18, CTX); + vmovq %xmm8, cmll_sub(19, CTX); + vmovq %xmm9, cmll_sub(20, CTX); + vmovq %xmm10, cmll_sub(21, CTX); + vmovq %xmm1, cmll_sub(22, CTX); + + vmovq cmll_sub(25, CTX), %xmm5; + vmovq cmll_sub(26, CTX), %xmm6; + vmovq cmll_sub(27, CTX), %xmm7; + vmovq cmll_sub(28, CTX), %xmm8; + vmovq cmll_sub(29, CTX), %xmm9; + vmovq cmll_sub(30, CTX), %xmm10; + vmovq cmll_sub(31, CTX), %xmm11; + vmovq cmll_sub(32, CTX), %xmm12; + + /* tl = subl(26) ^ (subr(26) & ~subr(24)); */ + vpandn %xmm6, %xmm4, %xmm15; + vpsrldq $4, %xmm15, %xmm15; + vpxor %xmm15, %xmm6, %xmm0; + /* dw = tl & subl(26), tr = subr(24) ^ CAMELLIA_RL1(dw); */ + vpand %xmm4, %xmm0, %xmm15; + vpslld $1, %xmm15, %xmm14; + vpsrld $31, %xmm15, %xmm15; + vpaddd %xmm14, %xmm15, %xmm15; + vpslldq $12, %xmm15, %xmm15; + vpsrldq $8, %xmm15, %xmm15; + vpxor %xmm15, %xmm0, %xmm0; + + vpxor %xmm0, %xmm2, %xmm2; + vmovq %xmm2, cmll_sub(23, CTX); + + /* tl = subl(23) ^ (subr(23) & ~subr(25)); */ + vpandn %xmm3, %xmm5, %xmm15; + vpsrldq $4, %xmm15, %xmm15; + vpxor %xmm15, %xmm3, %xmm0; + /* dw = tl & subl(26), tr = subr(24) ^ CAMELLIA_RL1(dw); */ + vpand %xmm5, %xmm0, %xmm15; + vpslld $1, %xmm15, %xmm14; + vpsrld $31, %xmm15, %xmm15; + vpaddd %xmm14, %xmm15, %xmm15; + vpslldq $12, %xmm15, %xmm15; + vpsrldq $8, %xmm15, %xmm15; + vpxor %xmm15, %xmm0, %xmm0; + + vpxor %xmm7, %xmm0, %xmm0; + vpxor %xmm8, %xmm6, %xmm6; + vpxor %xmm9, %xmm7, %xmm7; + vpxor %xmm10, %xmm8, %xmm8; + vpxor %xmm11, %xmm9, %xmm9; + vpxor %xmm12, %xmm11, %xmm11; + + vmovq %xmm0, cmll_sub(26, CTX); + vmovq %xmm6, cmll_sub(27, CTX); + vmovq %xmm7, cmll_sub(28, CTX); + vmovq %xmm8, cmll_sub(29, CTX); + vmovq %xmm9, cmll_sub(30, CTX); + vmovq %xmm10, cmll_sub(31, CTX); + vmovq %xmm11, cmll_sub(32, CTX); + + /* kw2 and kw4 are unused now. */ + movq $0, cmll_sub(1, CTX); + movq $0, cmll_sub(33, CTX); + + vzeroall; + + ret; + CFI_ENDPROC(); +ELF(.size __camellia_avx_setup256,.-__camellia_avx_setup256;) + +.align 8 +.globl _gcry_camellia_aesni_avx_keygen +ELF(.type _gcry_camellia_aesni_avx_keygen,@function;) + +_gcry_camellia_aesni_avx_keygen: + /* input: + * %rdi: ctx, CTX + * %rsi: key + * %rdx: keylen + */ + CFI_STARTPROC(); + + vzeroupper; + + vmovdqu (%rsi), %xmm0; + cmpl $24, %edx; + jb __camellia_avx_setup128; + je .Lprepare_key192; + + vmovdqu 16(%rsi), %xmm1; + jmp __camellia_avx_setup256; + +.Lprepare_key192: + vpcmpeqd %xmm2, %xmm2, %xmm2; + vmovq 16(%rsi), %xmm1; + + vpxor %xmm1, %xmm2, %xmm2; + vpslldq $8, %xmm2, %xmm2; + vpor %xmm2, %xmm1, %xmm1; + + jmp __camellia_avx_setup256; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx_keygen,.-_gcry_camellia_aesni_avx_keygen;) + +#endif /*defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/camellia-aesni-avx2-amd64.S b/comm/third_party/libgcrypt/cipher/camellia-aesni-avx2-amd64.S new file mode 100644 index 0000000000..f620f04036 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia-aesni-avx2-amd64.S @@ -0,0 +1,1782 @@ +/* camellia-avx2-aesni-amd64.S - AES-NI/AVX2 implementation of Camellia cipher + * + * Copyright (C) 2013-2015,2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#ifdef __x86_64 +#if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \ + defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT) + +#include "asm-common-amd64.h" + +#define CAMELLIA_TABLE_BYTE_LEN 272 + +/* struct CAMELLIA_context: */ +#define key_table 0 +#define key_bitlength CAMELLIA_TABLE_BYTE_LEN + +/* register macros */ +#define CTX %rdi +#define RIO %r8 + +/********************************************************************** + helper macros + **********************************************************************/ +#define filter_8bit(x, lo_t, hi_t, mask4bit, tmp0) \ + vpand x, mask4bit, tmp0; \ + vpandn x, mask4bit, x; \ + vpsrld $4, x, x; \ + \ + vpshufb tmp0, lo_t, tmp0; \ + vpshufb x, hi_t, x; \ + vpxor tmp0, x, x; + +#define ymm0_x xmm0 +#define ymm1_x xmm1 +#define ymm2_x xmm2 +#define ymm3_x xmm3 +#define ymm4_x xmm4 +#define ymm5_x xmm5 +#define ymm6_x xmm6 +#define ymm7_x xmm7 +#define ymm8_x xmm8 +#define ymm9_x xmm9 +#define ymm10_x xmm10 +#define ymm11_x xmm11 +#define ymm12_x xmm12 +#define ymm13_x xmm13 +#define ymm14_x xmm14 +#define ymm15_x xmm15 + +/********************************************************************** + 32-way camellia + **********************************************************************/ + +/* + * IN: + * x0..x7: byte-sliced AB state + * mem_cd: register pointer storing CD state + * key: index for key material + * OUT: + * x0..x7: new byte-sliced CD state + */ +#define roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, t0, t1, t2, t3, t4, t5, t6, \ + t7, mem_cd, key) \ + /* \ + * S-function with AES subbytes \ + */ \ + vbroadcasti128 .Linv_shift_row rRIP, t4; \ + vpbroadcastd .L0f0f0f0f rRIP, t7; \ + vbroadcasti128 .Lpre_tf_lo_s1 rRIP, t5; \ + vbroadcasti128 .Lpre_tf_hi_s1 rRIP, t6; \ + vbroadcasti128 .Lpre_tf_lo_s4 rRIP, t2; \ + vbroadcasti128 .Lpre_tf_hi_s4 rRIP, t3; \ + \ + /* AES inverse shift rows */ \ + vpshufb t4, x0, x0; \ + vpshufb t4, x7, x7; \ + vpshufb t4, x3, x3; \ + vpshufb t4, x6, x6; \ + vpshufb t4, x2, x2; \ + vpshufb t4, x5, x5; \ + vpshufb t4, x1, x1; \ + vpshufb t4, x4, x4; \ + \ + /* prefilter sboxes 1, 2 and 3 */ \ + /* prefilter sbox 4 */ \ + filter_8bit(x0, t5, t6, t7, t4); \ + filter_8bit(x7, t5, t6, t7, t4); \ + vextracti128 $1, x0, t0##_x; \ + vextracti128 $1, x7, t1##_x; \ + filter_8bit(x3, t2, t3, t7, t4); \ + filter_8bit(x6, t2, t3, t7, t4); \ + vextracti128 $1, x3, t3##_x; \ + vextracti128 $1, x6, t2##_x; \ + filter_8bit(x2, t5, t6, t7, t4); \ + filter_8bit(x5, t5, t6, t7, t4); \ + filter_8bit(x1, t5, t6, t7, t4); \ + filter_8bit(x4, t5, t6, t7, t4); \ + \ + vpxor t4##_x, t4##_x, t4##_x; \ + \ + /* AES subbytes + AES shift rows */ \ + vextracti128 $1, x2, t6##_x; \ + vextracti128 $1, x5, t5##_x; \ + vaesenclast t4##_x, x0##_x, x0##_x; \ + vaesenclast t4##_x, t0##_x, t0##_x; \ + vaesenclast t4##_x, x7##_x, x7##_x; \ + vaesenclast t4##_x, t1##_x, t1##_x; \ + vaesenclast t4##_x, x3##_x, x3##_x; \ + vaesenclast t4##_x, t3##_x, t3##_x; \ + vaesenclast t4##_x, x6##_x, x6##_x; \ + vaesenclast t4##_x, t2##_x, t2##_x; \ + vinserti128 $1, t0##_x, x0, x0; \ + vinserti128 $1, t1##_x, x7, x7; \ + vinserti128 $1, t3##_x, x3, x3; \ + vinserti128 $1, t2##_x, x6, x6; \ + vextracti128 $1, x1, t3##_x; \ + vextracti128 $1, x4, t2##_x; \ + vbroadcasti128 .Lpost_tf_lo_s1 rRIP, t0; \ + vbroadcasti128 .Lpost_tf_hi_s1 rRIP, t1; \ + vaesenclast t4##_x, x2##_x, x2##_x; \ + vaesenclast t4##_x, t6##_x, t6##_x; \ + vaesenclast t4##_x, x5##_x, x5##_x; \ + vaesenclast t4##_x, t5##_x, t5##_x; \ + vaesenclast t4##_x, x1##_x, x1##_x; \ + vaesenclast t4##_x, t3##_x, t3##_x; \ + vaesenclast t4##_x, x4##_x, x4##_x; \ + vaesenclast t4##_x, t2##_x, t2##_x; \ + vinserti128 $1, t6##_x, x2, x2; \ + vinserti128 $1, t5##_x, x5, x5; \ + vinserti128 $1, t3##_x, x1, x1; \ + vinserti128 $1, t2##_x, x4, x4; \ + \ + /* postfilter sboxes 1 and 4 */ \ + vbroadcasti128 .Lpost_tf_lo_s3 rRIP, t2; \ + vbroadcasti128 .Lpost_tf_hi_s3 rRIP, t3; \ + filter_8bit(x0, t0, t1, t7, t4); \ + filter_8bit(x7, t0, t1, t7, t4); \ + filter_8bit(x3, t0, t1, t7, t6); \ + filter_8bit(x6, t0, t1, t7, t6); \ + \ + /* postfilter sbox 3 */ \ + vbroadcasti128 .Lpost_tf_lo_s2 rRIP, t4; \ + vbroadcasti128 .Lpost_tf_hi_s2 rRIP, t5; \ + filter_8bit(x2, t2, t3, t7, t6); \ + filter_8bit(x5, t2, t3, t7, t6); \ + \ + vpbroadcastq key, t0; /* higher 64-bit duplicate ignored */ \ + \ + /* postfilter sbox 2 */ \ + filter_8bit(x1, t4, t5, t7, t2); \ + filter_8bit(x4, t4, t5, t7, t2); \ + vpxor t7, t7, t7; \ + \ + vpsrldq $1, t0, t1; \ + vpsrldq $2, t0, t2; \ + vpshufb t7, t1, t1; \ + vpsrldq $3, t0, t3; \ + \ + /* P-function */ \ + vpxor x5, x0, x0; \ + vpxor x6, x1, x1; \ + vpxor x7, x2, x2; \ + vpxor x4, x3, x3; \ + \ + vpshufb t7, t2, t2; \ + vpsrldq $4, t0, t4; \ + vpshufb t7, t3, t3; \ + vpsrldq $5, t0, t5; \ + vpshufb t7, t4, t4; \ + \ + vpxor x2, x4, x4; \ + vpxor x3, x5, x5; \ + vpxor x0, x6, x6; \ + vpxor x1, x7, x7; \ + \ + vpsrldq $6, t0, t6; \ + vpshufb t7, t5, t5; \ + vpshufb t7, t6, t6; \ + \ + vpxor x7, x0, x0; \ + vpxor x4, x1, x1; \ + vpxor x5, x2, x2; \ + vpxor x6, x3, x3; \ + \ + vpxor x3, x4, x4; \ + vpxor x0, x5, x5; \ + vpxor x1, x6, x6; \ + vpxor x2, x7, x7; /* note: high and low parts swapped */ \ + \ + /* Add key material and result to CD (x becomes new CD) */ \ + \ + vpxor t6, x1, x1; \ + vpxor 5 * 32(mem_cd), x1, x1; \ + \ + vpsrldq $7, t0, t6; \ + vpshufb t7, t0, t0; \ + vpshufb t7, t6, t7; \ + \ + vpxor t7, x0, x0; \ + vpxor 4 * 32(mem_cd), x0, x0; \ + \ + vpxor t5, x2, x2; \ + vpxor 6 * 32(mem_cd), x2, x2; \ + \ + vpxor t4, x3, x3; \ + vpxor 7 * 32(mem_cd), x3, x3; \ + \ + vpxor t3, x4, x4; \ + vpxor 0 * 32(mem_cd), x4, x4; \ + \ + vpxor t2, x5, x5; \ + vpxor 1 * 32(mem_cd), x5, x5; \ + \ + vpxor t1, x6, x6; \ + vpxor 2 * 32(mem_cd), x6, x6; \ + \ + vpxor t0, x7, x7; \ + vpxor 3 * 32(mem_cd), x7, x7; + +/* + * IN/OUT: + * x0..x7: byte-sliced AB state preloaded + * mem_ab: byte-sliced AB state in memory + * mem_cb: byte-sliced CD state in memory + */ +#define two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, i, dir, store_ab) \ + roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_cd, (key_table + (i) * 8)(CTX)); \ + \ + vmovdqu x0, 4 * 32(mem_cd); \ + vmovdqu x1, 5 * 32(mem_cd); \ + vmovdqu x2, 6 * 32(mem_cd); \ + vmovdqu x3, 7 * 32(mem_cd); \ + vmovdqu x4, 0 * 32(mem_cd); \ + vmovdqu x5, 1 * 32(mem_cd); \ + vmovdqu x6, 2 * 32(mem_cd); \ + vmovdqu x7, 3 * 32(mem_cd); \ + \ + roundsm32(x4, x5, x6, x7, x0, x1, x2, x3, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, (key_table + ((i) + (dir)) * 8)(CTX)); \ + \ + store_ab(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab); + +#define dummy_store(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab) /* do nothing */ + +#define store_ab_state(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab) \ + /* Store new AB state */ \ + vmovdqu x4, 4 * 32(mem_ab); \ + vmovdqu x5, 5 * 32(mem_ab); \ + vmovdqu x6, 6 * 32(mem_ab); \ + vmovdqu x7, 7 * 32(mem_ab); \ + vmovdqu x0, 0 * 32(mem_ab); \ + vmovdqu x1, 1 * 32(mem_ab); \ + vmovdqu x2, 2 * 32(mem_ab); \ + vmovdqu x3, 3 * 32(mem_ab); + +#define enc_rounds32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, i) \ + two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 2, 1, store_ab_state); \ + two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 4, 1, store_ab_state); \ + two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 6, 1, dummy_store); + +#define dec_rounds32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, i) \ + two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 7, -1, store_ab_state); \ + two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 5, -1, store_ab_state); \ + two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd, (i) + 3, -1, dummy_store); + +/* + * IN: + * v0..3: byte-sliced 32-bit integers + * OUT: + * v0..3: (IN <<< 1) + */ +#define rol32_1_32(v0, v1, v2, v3, t0, t1, t2, zero) \ + vpcmpgtb v0, zero, t0; \ + vpaddb v0, v0, v0; \ + vpabsb t0, t0; \ + \ + vpcmpgtb v1, zero, t1; \ + vpaddb v1, v1, v1; \ + vpabsb t1, t1; \ + \ + vpcmpgtb v2, zero, t2; \ + vpaddb v2, v2, v2; \ + vpabsb t2, t2; \ + \ + vpor t0, v1, v1; \ + \ + vpcmpgtb v3, zero, t0; \ + vpaddb v3, v3, v3; \ + vpabsb t0, t0; \ + \ + vpor t1, v2, v2; \ + vpor t2, v3, v3; \ + vpor t0, v0, v0; + +/* + * IN: + * r: byte-sliced AB state in memory + * l: byte-sliced CD state in memory + * OUT: + * x0..x7: new byte-sliced CD state + */ +#define fls32(l, l0, l1, l2, l3, l4, l5, l6, l7, r, t0, t1, t2, t3, tt0, \ + tt1, tt2, tt3, kll, klr, krl, krr) \ + /* \ + * t0 = kll; \ + * t0 &= ll; \ + * lr ^= rol32(t0, 1); \ + */ \ + vpbroadcastd kll, t0; /* only lowest 32-bit used */ \ + vpxor tt0, tt0, tt0; \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpand l0, t0, t0; \ + vpand l1, t1, t1; \ + vpand l2, t2, t2; \ + vpand l3, t3, t3; \ + \ + rol32_1_32(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \ + \ + vpxor l4, t0, l4; \ + vpbroadcastd krr, t0; /* only lowest 32-bit used */ \ + vmovdqu l4, 4 * 32(l); \ + vpxor l5, t1, l5; \ + vmovdqu l5, 5 * 32(l); \ + vpxor l6, t2, l6; \ + vmovdqu l6, 6 * 32(l); \ + vpxor l7, t3, l7; \ + vmovdqu l7, 7 * 32(l); \ + \ + /* \ + * t2 = krr; \ + * t2 |= rr; \ + * rl ^= t2; \ + */ \ + \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpor 4 * 32(r), t0, t0; \ + vpor 5 * 32(r), t1, t1; \ + vpor 6 * 32(r), t2, t2; \ + vpor 7 * 32(r), t3, t3; \ + \ + vpxor 0 * 32(r), t0, t0; \ + vpxor 1 * 32(r), t1, t1; \ + vpxor 2 * 32(r), t2, t2; \ + vpxor 3 * 32(r), t3, t3; \ + vmovdqu t0, 0 * 32(r); \ + vpbroadcastd krl, t0; /* only lowest 32-bit used */ \ + vmovdqu t1, 1 * 32(r); \ + vmovdqu t2, 2 * 32(r); \ + vmovdqu t3, 3 * 32(r); \ + \ + /* \ + * t2 = krl; \ + * t2 &= rl; \ + * rr ^= rol32(t2, 1); \ + */ \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpand 0 * 32(r), t0, t0; \ + vpand 1 * 32(r), t1, t1; \ + vpand 2 * 32(r), t2, t2; \ + vpand 3 * 32(r), t3, t3; \ + \ + rol32_1_32(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \ + \ + vpxor 4 * 32(r), t0, t0; \ + vpxor 5 * 32(r), t1, t1; \ + vpxor 6 * 32(r), t2, t2; \ + vpxor 7 * 32(r), t3, t3; \ + vmovdqu t0, 4 * 32(r); \ + vpbroadcastd klr, t0; /* only lowest 32-bit used */ \ + vmovdqu t1, 5 * 32(r); \ + vmovdqu t2, 6 * 32(r); \ + vmovdqu t3, 7 * 32(r); \ + \ + /* \ + * t0 = klr; \ + * t0 |= lr; \ + * ll ^= t0; \ + */ \ + \ + vpshufb tt0, t0, t3; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t2; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t1; \ + vpsrldq $1, t0, t0; \ + vpshufb tt0, t0, t0; \ + \ + vpor l4, t0, t0; \ + vpor l5, t1, t1; \ + vpor l6, t2, t2; \ + vpor l7, t3, t3; \ + \ + vpxor l0, t0, l0; \ + vmovdqu l0, 0 * 32(l); \ + vpxor l1, t1, l1; \ + vmovdqu l1, 1 * 32(l); \ + vpxor l2, t2, l2; \ + vmovdqu l2, 2 * 32(l); \ + vpxor l3, t3, l3; \ + vmovdqu l3, 3 * 32(l); + +#define transpose_4x4(x0, x1, x2, x3, t1, t2) \ + vpunpckhdq x1, x0, t2; \ + vpunpckldq x1, x0, x0; \ + \ + vpunpckldq x3, x2, t1; \ + vpunpckhdq x3, x2, x2; \ + \ + vpunpckhqdq t1, x0, x1; \ + vpunpcklqdq t1, x0, x0; \ + \ + vpunpckhqdq x2, t2, x3; \ + vpunpcklqdq x2, t2, x2; + +#define byteslice_16x16b_fast(a0, b0, c0, d0, a1, b1, c1, d1, a2, b2, c2, d2, \ + a3, b3, c3, d3, st0, st1) \ + vmovdqu d2, st0; \ + vmovdqu d3, st1; \ + transpose_4x4(a0, a1, a2, a3, d2, d3); \ + transpose_4x4(b0, b1, b2, b3, d2, d3); \ + vmovdqu st0, d2; \ + vmovdqu st1, d3; \ + \ + vmovdqu a0, st0; \ + vmovdqu a1, st1; \ + transpose_4x4(c0, c1, c2, c3, a0, a1); \ + transpose_4x4(d0, d1, d2, d3, a0, a1); \ + \ + vbroadcasti128 .Lshufb_16x16b rRIP, a0; \ + vmovdqu st1, a1; \ + vpshufb a0, a2, a2; \ + vpshufb a0, a3, a3; \ + vpshufb a0, b0, b0; \ + vpshufb a0, b1, b1; \ + vpshufb a0, b2, b2; \ + vpshufb a0, b3, b3; \ + vpshufb a0, a1, a1; \ + vpshufb a0, c0, c0; \ + vpshufb a0, c1, c1; \ + vpshufb a0, c2, c2; \ + vpshufb a0, c3, c3; \ + vpshufb a0, d0, d0; \ + vpshufb a0, d1, d1; \ + vpshufb a0, d2, d2; \ + vpshufb a0, d3, d3; \ + vmovdqu d3, st1; \ + vmovdqu st0, d3; \ + vpshufb a0, d3, a0; \ + vmovdqu d2, st0; \ + \ + transpose_4x4(a0, b0, c0, d0, d2, d3); \ + transpose_4x4(a1, b1, c1, d1, d2, d3); \ + vmovdqu st0, d2; \ + vmovdqu st1, d3; \ + \ + vmovdqu b0, st0; \ + vmovdqu b1, st1; \ + transpose_4x4(a2, b2, c2, d2, b0, b1); \ + transpose_4x4(a3, b3, c3, d3, b0, b1); \ + vmovdqu st0, b0; \ + vmovdqu st1, b1; \ + /* does not adjust output bytes inside vectors */ + +/* load blocks to registers and apply pre-whitening */ +#define inpack32_pre(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, rio, key) \ + vpbroadcastq key, x0; \ + vpshufb .Lpack_bswap rRIP, x0, x0; \ + \ + vpxor 0 * 32(rio), x0, y7; \ + vpxor 1 * 32(rio), x0, y6; \ + vpxor 2 * 32(rio), x0, y5; \ + vpxor 3 * 32(rio), x0, y4; \ + vpxor 4 * 32(rio), x0, y3; \ + vpxor 5 * 32(rio), x0, y2; \ + vpxor 6 * 32(rio), x0, y1; \ + vpxor 7 * 32(rio), x0, y0; \ + vpxor 8 * 32(rio), x0, x7; \ + vpxor 9 * 32(rio), x0, x6; \ + vpxor 10 * 32(rio), x0, x5; \ + vpxor 11 * 32(rio), x0, x4; \ + vpxor 12 * 32(rio), x0, x3; \ + vpxor 13 * 32(rio), x0, x2; \ + vpxor 14 * 32(rio), x0, x1; \ + vpxor 15 * 32(rio), x0, x0; + +/* byteslice pre-whitened blocks and store to temporary memory */ +#define inpack32_post(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, mem_ab, mem_cd) \ + byteslice_16x16b_fast(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, \ + y4, y5, y6, y7, (mem_ab), (mem_cd)); \ + \ + vmovdqu x0, 0 * 32(mem_ab); \ + vmovdqu x1, 1 * 32(mem_ab); \ + vmovdqu x2, 2 * 32(mem_ab); \ + vmovdqu x3, 3 * 32(mem_ab); \ + vmovdqu x4, 4 * 32(mem_ab); \ + vmovdqu x5, 5 * 32(mem_ab); \ + vmovdqu x6, 6 * 32(mem_ab); \ + vmovdqu x7, 7 * 32(mem_ab); \ + vmovdqu y0, 0 * 32(mem_cd); \ + vmovdqu y1, 1 * 32(mem_cd); \ + vmovdqu y2, 2 * 32(mem_cd); \ + vmovdqu y3, 3 * 32(mem_cd); \ + vmovdqu y4, 4 * 32(mem_cd); \ + vmovdqu y5, 5 * 32(mem_cd); \ + vmovdqu y6, 6 * 32(mem_cd); \ + vmovdqu y7, 7 * 32(mem_cd); + +/* de-byteslice, apply post-whitening and store blocks */ +#define outunpack32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, \ + y5, y6, y7, key, stack_tmp0, stack_tmp1) \ + byteslice_16x16b_fast(y0, y4, x0, x4, y1, y5, x1, x5, y2, y6, x2, x6, \ + y3, y7, x3, x7, stack_tmp0, stack_tmp1); \ + \ + vmovdqu x0, stack_tmp0; \ + \ + vpbroadcastq key, x0; \ + vpshufb .Lpack_bswap rRIP, x0, x0; \ + \ + vpxor x0, y7, y7; \ + vpxor x0, y6, y6; \ + vpxor x0, y5, y5; \ + vpxor x0, y4, y4; \ + vpxor x0, y3, y3; \ + vpxor x0, y2, y2; \ + vpxor x0, y1, y1; \ + vpxor x0, y0, y0; \ + vpxor x0, x7, x7; \ + vpxor x0, x6, x6; \ + vpxor x0, x5, x5; \ + vpxor x0, x4, x4; \ + vpxor x0, x3, x3; \ + vpxor x0, x2, x2; \ + vpxor x0, x1, x1; \ + vpxor stack_tmp0, x0, x0; + +#define write_output(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \ + y6, y7, rio) \ + vmovdqu x0, 0 * 32(rio); \ + vmovdqu x1, 1 * 32(rio); \ + vmovdqu x2, 2 * 32(rio); \ + vmovdqu x3, 3 * 32(rio); \ + vmovdqu x4, 4 * 32(rio); \ + vmovdqu x5, 5 * 32(rio); \ + vmovdqu x6, 6 * 32(rio); \ + vmovdqu x7, 7 * 32(rio); \ + vmovdqu y0, 8 * 32(rio); \ + vmovdqu y1, 9 * 32(rio); \ + vmovdqu y2, 10 * 32(rio); \ + vmovdqu y3, 11 * 32(rio); \ + vmovdqu y4, 12 * 32(rio); \ + vmovdqu y5, 13 * 32(rio); \ + vmovdqu y6, 14 * 32(rio); \ + vmovdqu y7, 15 * 32(rio); + +.text +.align 32 + +#define SHUFB_BYTES(idx) \ + 0 + (idx), 4 + (idx), 8 + (idx), 12 + (idx) + +.Lshufb_16x16b: + .byte SHUFB_BYTES(0), SHUFB_BYTES(1), SHUFB_BYTES(2), SHUFB_BYTES(3) + .byte SHUFB_BYTES(0), SHUFB_BYTES(1), SHUFB_BYTES(2), SHUFB_BYTES(3) + +.Lpack_bswap: + .long 0x00010203, 0x04050607, 0x80808080, 0x80808080 + .long 0x00010203, 0x04050607, 0x80808080, 0x80808080 + +/* For CTR-mode IV byteswap */ +.Lbswap128_mask: + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +/* + * pre-SubByte transform + * + * pre-lookup for sbox1, sbox2, sbox3: + * swap_bitendianness( + * isom_map_camellia_to_aes( + * camellia_f( + * swap_bitendianess(in) + * ) + * ) + * ) + * + * (note: '⊕ 0xc5' inside camellia_f()) + */ +.Lpre_tf_lo_s1: + .byte 0x45, 0xe8, 0x40, 0xed, 0x2e, 0x83, 0x2b, 0x86 + .byte 0x4b, 0xe6, 0x4e, 0xe3, 0x20, 0x8d, 0x25, 0x88 +.Lpre_tf_hi_s1: + .byte 0x00, 0x51, 0xf1, 0xa0, 0x8a, 0xdb, 0x7b, 0x2a + .byte 0x09, 0x58, 0xf8, 0xa9, 0x83, 0xd2, 0x72, 0x23 + +/* + * pre-SubByte transform + * + * pre-lookup for sbox4: + * swap_bitendianness( + * isom_map_camellia_to_aes( + * camellia_f( + * swap_bitendianess(in <<< 1) + * ) + * ) + * ) + * + * (note: '⊕ 0xc5' inside camellia_f()) + */ +.Lpre_tf_lo_s4: + .byte 0x45, 0x40, 0x2e, 0x2b, 0x4b, 0x4e, 0x20, 0x25 + .byte 0x14, 0x11, 0x7f, 0x7a, 0x1a, 0x1f, 0x71, 0x74 +.Lpre_tf_hi_s4: + .byte 0x00, 0xf1, 0x8a, 0x7b, 0x09, 0xf8, 0x83, 0x72 + .byte 0xad, 0x5c, 0x27, 0xd6, 0xa4, 0x55, 0x2e, 0xdf + +/* + * post-SubByte transform + * + * post-lookup for sbox1, sbox4: + * swap_bitendianness( + * camellia_h( + * isom_map_aes_to_camellia( + * swap_bitendianness( + * aes_inverse_affine_transform(in) + * ) + * ) + * ) + * ) + * + * (note: '⊕ 0x6e' inside camellia_h()) + */ +.Lpost_tf_lo_s1: + .byte 0x3c, 0xcc, 0xcf, 0x3f, 0x32, 0xc2, 0xc1, 0x31 + .byte 0xdc, 0x2c, 0x2f, 0xdf, 0xd2, 0x22, 0x21, 0xd1 +.Lpost_tf_hi_s1: + .byte 0x00, 0xf9, 0x86, 0x7f, 0xd7, 0x2e, 0x51, 0xa8 + .byte 0xa4, 0x5d, 0x22, 0xdb, 0x73, 0x8a, 0xf5, 0x0c + +/* + * post-SubByte transform + * + * post-lookup for sbox2: + * swap_bitendianness( + * camellia_h( + * isom_map_aes_to_camellia( + * swap_bitendianness( + * aes_inverse_affine_transform(in) + * ) + * ) + * ) + * ) <<< 1 + * + * (note: '⊕ 0x6e' inside camellia_h()) + */ +.Lpost_tf_lo_s2: + .byte 0x78, 0x99, 0x9f, 0x7e, 0x64, 0x85, 0x83, 0x62 + .byte 0xb9, 0x58, 0x5e, 0xbf, 0xa5, 0x44, 0x42, 0xa3 +.Lpost_tf_hi_s2: + .byte 0x00, 0xf3, 0x0d, 0xfe, 0xaf, 0x5c, 0xa2, 0x51 + .byte 0x49, 0xba, 0x44, 0xb7, 0xe6, 0x15, 0xeb, 0x18 + +/* + * post-SubByte transform + * + * post-lookup for sbox3: + * swap_bitendianness( + * camellia_h( + * isom_map_aes_to_camellia( + * swap_bitendianness( + * aes_inverse_affine_transform(in) + * ) + * ) + * ) + * ) >>> 1 + * + * (note: '⊕ 0x6e' inside camellia_h()) + */ +.Lpost_tf_lo_s3: + .byte 0x1e, 0x66, 0xe7, 0x9f, 0x19, 0x61, 0xe0, 0x98 + .byte 0x6e, 0x16, 0x97, 0xef, 0x69, 0x11, 0x90, 0xe8 +.Lpost_tf_hi_s3: + .byte 0x00, 0xfc, 0x43, 0xbf, 0xeb, 0x17, 0xa8, 0x54 + .byte 0x52, 0xae, 0x11, 0xed, 0xb9, 0x45, 0xfa, 0x06 + +/* For isolating SubBytes from AESENCLAST, inverse shift row */ +.Linv_shift_row: + .byte 0x00, 0x0d, 0x0a, 0x07, 0x04, 0x01, 0x0e, 0x0b + .byte 0x08, 0x05, 0x02, 0x0f, 0x0c, 0x09, 0x06, 0x03 + +.align 4 +/* 4-bit mask */ +.L0f0f0f0f: + .long 0x0f0f0f0f + + +.align 8 +ELF(.type __camellia_enc_blk32,@function;) + +__camellia_enc_blk32: + /* input: + * %rdi: ctx, CTX + * %rax: temporary storage, 512 bytes + * %r8d: 24 for 16 byte key, 32 for larger + * %ymm0..%ymm15: 32 plaintext blocks + * output: + * %ymm0..%ymm15: 32 encrypted blocks, order swapped: + * 7, 8, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 + */ + CFI_STARTPROC(); + + leaq 8 * 32(%rax), %rcx; + + leaq (-8 * 8)(CTX, %r8, 8), %r8; + + inpack32_post(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, %rax, %rcx); + +.align 8 +.Lenc_loop: + enc_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, %rax, %rcx, 0); + + cmpq %r8, CTX; + je .Lenc_done; + leaq (8 * 8)(CTX), CTX; + + fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, + ((key_table) + 0)(CTX), + ((key_table) + 4)(CTX), + ((key_table) + 8)(CTX), + ((key_table) + 12)(CTX)); + jmp .Lenc_loop; + +.align 8 +.Lenc_done: + /* load CD for output */ + vmovdqu 0 * 32(%rcx), %ymm8; + vmovdqu 1 * 32(%rcx), %ymm9; + vmovdqu 2 * 32(%rcx), %ymm10; + vmovdqu 3 * 32(%rcx), %ymm11; + vmovdqu 4 * 32(%rcx), %ymm12; + vmovdqu 5 * 32(%rcx), %ymm13; + vmovdqu 6 * 32(%rcx), %ymm14; + vmovdqu 7 * 32(%rcx), %ymm15; + + outunpack32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, ((key_table) + 8 * 8)(%r8), (%rax), 1 * 32(%rax)); + + ret; + CFI_ENDPROC(); +ELF(.size __camellia_enc_blk32,.-__camellia_enc_blk32;) + +.align 8 +ELF(.type __camellia_dec_blk32,@function;) + +__camellia_dec_blk32: + /* input: + * %rdi: ctx, CTX + * %rax: temporary storage, 512 bytes + * %r8d: 24 for 16 byte key, 32 for larger + * %ymm0..%ymm15: 16 encrypted blocks + * output: + * %ymm0..%ymm15: 16 plaintext blocks, order swapped: + * 7, 8, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 + */ + CFI_STARTPROC(); + + movq %r8, %rcx; + movq CTX, %r8 + leaq (-8 * 8)(CTX, %rcx, 8), CTX; + + leaq 8 * 32(%rax), %rcx; + + inpack32_post(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, %rax, %rcx); + +.align 8 +.Ldec_loop: + dec_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, %rax, %rcx, 0); + + cmpq %r8, CTX; + je .Ldec_done; + + fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, + ((key_table) + 8)(CTX), + ((key_table) + 12)(CTX), + ((key_table) + 0)(CTX), + ((key_table) + 4)(CTX)); + + leaq (-8 * 8)(CTX), CTX; + jmp .Ldec_loop; + +.align 8 +.Ldec_done: + /* load CD for output */ + vmovdqu 0 * 32(%rcx), %ymm8; + vmovdqu 1 * 32(%rcx), %ymm9; + vmovdqu 2 * 32(%rcx), %ymm10; + vmovdqu 3 * 32(%rcx), %ymm11; + vmovdqu 4 * 32(%rcx), %ymm12; + vmovdqu 5 * 32(%rcx), %ymm13; + vmovdqu 6 * 32(%rcx), %ymm14; + vmovdqu 7 * 32(%rcx), %ymm15; + + outunpack32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, (key_table)(CTX), (%rax), 1 * 32(%rax)); + + ret; + CFI_ENDPROC(); +ELF(.size __camellia_dec_blk32,.-__camellia_dec_blk32;) + +#define inc_le128(x, minus_one, tmp) \ + vpcmpeqq minus_one, x, tmp; \ + vpsubq minus_one, x, x; \ + vpslldq $8, tmp, tmp; \ + vpsubq tmp, x, x; + +.align 8 +.globl _gcry_camellia_aesni_avx2_ctr_enc +ELF(.type _gcry_camellia_aesni_avx2_ctr_enc,@function;) + +_gcry_camellia_aesni_avx2_ctr_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (32 blocks) + * %rdx: src (32 blocks) + * %rcx: iv (big endian, 128bit) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + movq 8(%rcx), %r11; + bswapq %r11; + + vzeroupper; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %eax; + cmovel %eax, %r8d; /* max */ + + subq $(16 * 32), %rsp; + andq $~63, %rsp; + movq %rsp, %rax; + + vpcmpeqd %ymm15, %ymm15, %ymm15; + vpsrldq $8, %ymm15, %ymm15; /* ab: -1:0 ; cd: -1:0 */ + + /* load IV and byteswap */ + vmovdqu (%rcx), %xmm0; + vpshufb .Lbswap128_mask rRIP, %xmm0, %xmm0; + vmovdqa %xmm0, %xmm1; + inc_le128(%xmm0, %xmm15, %xmm14); + vbroadcasti128 .Lbswap128_mask rRIP, %ymm14; + vinserti128 $1, %xmm0, %ymm1, %ymm0; + vpshufb %ymm14, %ymm0, %ymm13; + vmovdqu %ymm13, 15 * 32(%rax); + + /* check need for handling 64-bit overflow and carry */ + cmpq $(0xffffffffffffffff - 32), %r11; + ja .Lload_ctr_carry; + + /* construct IVs */ + vpaddq %ymm15, %ymm15, %ymm15; /* ab: -2:0 ; cd: -2:0 */ + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm13; + vmovdqu %ymm13, 14 * 32(%rax); + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm13; + vmovdqu %ymm13, 13 * 32(%rax); + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm12; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm11; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm10; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm9; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm8; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm7; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm6; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm5; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm4; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm3; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm2; + vpsubq %ymm15, %ymm0, %ymm0; + vpshufb %ymm14, %ymm0, %ymm1; + vpsubq %ymm15, %ymm0, %ymm0; /* +30 ; +31 */ + vpsubq %xmm15, %xmm0, %xmm13; /* +32 */ + vpshufb %ymm14, %ymm0, %ymm0; + vpshufb %xmm14, %xmm13, %xmm13; + vmovdqu %xmm13, (%rcx); + + jmp .Lload_ctr_done; + +.align 4 +.Lload_ctr_carry: + /* construct IVs */ + inc_le128(%ymm0, %ymm15, %ymm13); /* ab: le1 ; cd: le2 */ + inc_le128(%ymm0, %ymm15, %ymm13); /* ab: le2 ; cd: le3 */ + vpshufb %ymm14, %ymm0, %ymm13; + vmovdqu %ymm13, 14 * 32(%rax); + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm13; + vmovdqu %ymm13, 13 * 32(%rax); + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm12; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm11; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm10; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm9; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm8; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm7; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm6; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm5; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm4; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm3; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm2; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vpshufb %ymm14, %ymm0, %ymm1; + inc_le128(%ymm0, %ymm15, %ymm13); + inc_le128(%ymm0, %ymm15, %ymm13); + vextracti128 $1, %ymm0, %xmm13; + vpshufb %ymm14, %ymm0, %ymm0; + inc_le128(%xmm13, %xmm15, %xmm14); + vpshufb .Lbswap128_mask rRIP, %xmm13, %xmm13; + vmovdqu %xmm13, (%rcx); + +.align 4 +.Lload_ctr_done: + /* inpack16_pre: */ + vpbroadcastq (key_table)(CTX), %ymm15; + vpshufb .Lpack_bswap rRIP, %ymm15, %ymm15; + vpxor %ymm0, %ymm15, %ymm0; + vpxor %ymm1, %ymm15, %ymm1; + vpxor %ymm2, %ymm15, %ymm2; + vpxor %ymm3, %ymm15, %ymm3; + vpxor %ymm4, %ymm15, %ymm4; + vpxor %ymm5, %ymm15, %ymm5; + vpxor %ymm6, %ymm15, %ymm6; + vpxor %ymm7, %ymm15, %ymm7; + vpxor %ymm8, %ymm15, %ymm8; + vpxor %ymm9, %ymm15, %ymm9; + vpxor %ymm10, %ymm15, %ymm10; + vpxor %ymm11, %ymm15, %ymm11; + vpxor %ymm12, %ymm15, %ymm12; + vpxor 13 * 32(%rax), %ymm15, %ymm13; + vpxor 14 * 32(%rax), %ymm15, %ymm14; + vpxor 15 * 32(%rax), %ymm15, %ymm15; + + call __camellia_enc_blk32; + + vpxor 0 * 32(%rdx), %ymm7, %ymm7; + vpxor 1 * 32(%rdx), %ymm6, %ymm6; + vpxor 2 * 32(%rdx), %ymm5, %ymm5; + vpxor 3 * 32(%rdx), %ymm4, %ymm4; + vpxor 4 * 32(%rdx), %ymm3, %ymm3; + vpxor 5 * 32(%rdx), %ymm2, %ymm2; + vpxor 6 * 32(%rdx), %ymm1, %ymm1; + vpxor 7 * 32(%rdx), %ymm0, %ymm0; + vpxor 8 * 32(%rdx), %ymm15, %ymm15; + vpxor 9 * 32(%rdx), %ymm14, %ymm14; + vpxor 10 * 32(%rdx), %ymm13, %ymm13; + vpxor 11 * 32(%rdx), %ymm12, %ymm12; + vpxor 12 * 32(%rdx), %ymm11, %ymm11; + vpxor 13 * 32(%rdx), %ymm10, %ymm10; + vpxor 14 * 32(%rdx), %ymm9, %ymm9; + vpxor 15 * 32(%rdx), %ymm8, %ymm8; + leaq 32 * 16(%rdx), %rdx; + + write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0, + %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9, + %ymm8, %rsi); + + vzeroall; + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx2_ctr_enc,.-_gcry_camellia_aesni_avx2_ctr_enc;) + +.align 8 +.globl _gcry_camellia_aesni_avx2_cbc_dec +ELF(.type _gcry_camellia_aesni_avx2_cbc_dec,@function;) + +_gcry_camellia_aesni_avx2_cbc_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (32 blocks) + * %rdx: src (32 blocks) + * %rcx: iv + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + movq %rcx, %r9; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %eax; + cmovel %eax, %r8d; /* max */ + + subq $(16 * 32), %rsp; + andq $~63, %rsp; + movq %rsp, %rax; + + inpack32_pre(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7, + %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, + %ymm15, %rdx, (key_table)(CTX, %r8, 8)); + + call __camellia_dec_blk32; + + /* XOR output with IV */ + vmovdqu %ymm8, (%rax); + vmovdqu (%r9), %xmm8; + vinserti128 $1, (%rdx), %ymm8, %ymm8; + vpxor %ymm8, %ymm7, %ymm7; + vmovdqu (%rax), %ymm8; + vpxor (0 * 32 + 16)(%rdx), %ymm6, %ymm6; + vpxor (1 * 32 + 16)(%rdx), %ymm5, %ymm5; + vpxor (2 * 32 + 16)(%rdx), %ymm4, %ymm4; + vpxor (3 * 32 + 16)(%rdx), %ymm3, %ymm3; + vpxor (4 * 32 + 16)(%rdx), %ymm2, %ymm2; + vpxor (5 * 32 + 16)(%rdx), %ymm1, %ymm1; + vpxor (6 * 32 + 16)(%rdx), %ymm0, %ymm0; + vpxor (7 * 32 + 16)(%rdx), %ymm15, %ymm15; + vpxor (8 * 32 + 16)(%rdx), %ymm14, %ymm14; + vpxor (9 * 32 + 16)(%rdx), %ymm13, %ymm13; + vpxor (10 * 32 + 16)(%rdx), %ymm12, %ymm12; + vpxor (11 * 32 + 16)(%rdx), %ymm11, %ymm11; + vpxor (12 * 32 + 16)(%rdx), %ymm10, %ymm10; + vpxor (13 * 32 + 16)(%rdx), %ymm9, %ymm9; + vpxor (14 * 32 + 16)(%rdx), %ymm8, %ymm8; + movq (15 * 32 + 16 + 0)(%rdx), %rax; + movq (15 * 32 + 16 + 8)(%rdx), %rcx; + + write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0, + %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9, + %ymm8, %rsi); + + /* store new IV */ + movq %rax, (0)(%r9); + movq %rcx, (8)(%r9); + + vzeroall; + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx2_cbc_dec,.-_gcry_camellia_aesni_avx2_cbc_dec;) + +.align 8 +.globl _gcry_camellia_aesni_avx2_cfb_dec +ELF(.type _gcry_camellia_aesni_avx2_cfb_dec,@function;) + +_gcry_camellia_aesni_avx2_cfb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (32 blocks) + * %rdx: src (32 blocks) + * %rcx: iv + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %eax; + cmovel %eax, %r8d; /* max */ + + subq $(16 * 32), %rsp; + andq $~63, %rsp; + movq %rsp, %rax; + + /* inpack16_pre: */ + vpbroadcastq (key_table)(CTX), %ymm0; + vpshufb .Lpack_bswap rRIP, %ymm0, %ymm0; + vmovdqu (%rcx), %xmm15; + vinserti128 $1, (%rdx), %ymm15, %ymm15; + vpxor %ymm15, %ymm0, %ymm15; + vmovdqu (15 * 32 + 16)(%rdx), %xmm1; + vmovdqu %xmm1, (%rcx); /* store new IV */ + vpxor (0 * 32 + 16)(%rdx), %ymm0, %ymm14; + vpxor (1 * 32 + 16)(%rdx), %ymm0, %ymm13; + vpxor (2 * 32 + 16)(%rdx), %ymm0, %ymm12; + vpxor (3 * 32 + 16)(%rdx), %ymm0, %ymm11; + vpxor (4 * 32 + 16)(%rdx), %ymm0, %ymm10; + vpxor (5 * 32 + 16)(%rdx), %ymm0, %ymm9; + vpxor (6 * 32 + 16)(%rdx), %ymm0, %ymm8; + vpxor (7 * 32 + 16)(%rdx), %ymm0, %ymm7; + vpxor (8 * 32 + 16)(%rdx), %ymm0, %ymm6; + vpxor (9 * 32 + 16)(%rdx), %ymm0, %ymm5; + vpxor (10 * 32 + 16)(%rdx), %ymm0, %ymm4; + vpxor (11 * 32 + 16)(%rdx), %ymm0, %ymm3; + vpxor (12 * 32 + 16)(%rdx), %ymm0, %ymm2; + vpxor (13 * 32 + 16)(%rdx), %ymm0, %ymm1; + vpxor (14 * 32 + 16)(%rdx), %ymm0, %ymm0; + + call __camellia_enc_blk32; + + vpxor 0 * 32(%rdx), %ymm7, %ymm7; + vpxor 1 * 32(%rdx), %ymm6, %ymm6; + vpxor 2 * 32(%rdx), %ymm5, %ymm5; + vpxor 3 * 32(%rdx), %ymm4, %ymm4; + vpxor 4 * 32(%rdx), %ymm3, %ymm3; + vpxor 5 * 32(%rdx), %ymm2, %ymm2; + vpxor 6 * 32(%rdx), %ymm1, %ymm1; + vpxor 7 * 32(%rdx), %ymm0, %ymm0; + vpxor 8 * 32(%rdx), %ymm15, %ymm15; + vpxor 9 * 32(%rdx), %ymm14, %ymm14; + vpxor 10 * 32(%rdx), %ymm13, %ymm13; + vpxor 11 * 32(%rdx), %ymm12, %ymm12; + vpxor 12 * 32(%rdx), %ymm11, %ymm11; + vpxor 13 * 32(%rdx), %ymm10, %ymm10; + vpxor 14 * 32(%rdx), %ymm9, %ymm9; + vpxor 15 * 32(%rdx), %ymm8, %ymm8; + + write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0, + %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9, + %ymm8, %rsi); + + vzeroall; + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx2_cfb_dec,.-_gcry_camellia_aesni_avx2_cfb_dec;) + +.align 8 +.globl _gcry_camellia_aesni_avx2_ocb_enc +ELF(.type _gcry_camellia_aesni_avx2_ocb_enc,@function;) + +_gcry_camellia_aesni_avx2_ocb_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (32 blocks) + * %rdx: src (32 blocks) + * %rcx: offset + * %r8 : checksum + * %r9 : L pointers (void *L[32]) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(16 * 32 + 4 * 8), %rsp; + andq $~63, %rsp; + movq %rsp, %rax; + + movq %r10, (16 * 32 + 0 * 8)(%rsp); + movq %r11, (16 * 32 + 1 * 8)(%rsp); + movq %r12, (16 * 32 + 2 * 8)(%rsp); + movq %r13, (16 * 32 + 3 * 8)(%rsp); + CFI_REG_ON_STACK(r10, 16 * 32 + 0 * 8); + CFI_REG_ON_STACK(r11, 16 * 32 + 1 * 8); + CFI_REG_ON_STACK(r12, 16 * 32 + 2 * 8); + CFI_REG_ON_STACK(r13, 16 * 32 + 3 * 8); + + vmovdqu (%rcx), %xmm14; + vmovdqu (%r8), %xmm13; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + /* Checksum_i = Checksum_{i-1} xor P_i */ + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + +#define OCB_INPUT(n, l0reg, l1reg, yreg) \ + vmovdqu (n * 32)(%rdx), yreg; \ + vpxor (l0reg), %xmm14, %xmm15; \ + vpxor (l1reg), %xmm15, %xmm14; \ + vinserti128 $1, %xmm14, %ymm15, %ymm15; \ + vpxor yreg, %ymm13, %ymm13; \ + vpxor yreg, %ymm15, yreg; \ + vmovdqu %ymm15, (n * 32)(%rsi); + + movq (0 * 8)(%r9), %r10; + movq (1 * 8)(%r9), %r11; + movq (2 * 8)(%r9), %r12; + movq (3 * 8)(%r9), %r13; + OCB_INPUT(0, %r10, %r11, %ymm0); + vmovdqu %ymm0, (15 * 32)(%rax); + OCB_INPUT(1, %r12, %r13, %ymm0); + vmovdqu %ymm0, (14 * 32)(%rax); + movq (4 * 8)(%r9), %r10; + movq (5 * 8)(%r9), %r11; + movq (6 * 8)(%r9), %r12; + movq (7 * 8)(%r9), %r13; + OCB_INPUT(2, %r10, %r11, %ymm0); + vmovdqu %ymm0, (13 * 32)(%rax); + OCB_INPUT(3, %r12, %r13, %ymm12); + movq (8 * 8)(%r9), %r10; + movq (9 * 8)(%r9), %r11; + movq (10 * 8)(%r9), %r12; + movq (11 * 8)(%r9), %r13; + OCB_INPUT(4, %r10, %r11, %ymm11); + OCB_INPUT(5, %r12, %r13, %ymm10); + movq (12 * 8)(%r9), %r10; + movq (13 * 8)(%r9), %r11; + movq (14 * 8)(%r9), %r12; + movq (15 * 8)(%r9), %r13; + OCB_INPUT(6, %r10, %r11, %ymm9); + OCB_INPUT(7, %r12, %r13, %ymm8); + movq (16 * 8)(%r9), %r10; + movq (17 * 8)(%r9), %r11; + movq (18 * 8)(%r9), %r12; + movq (19 * 8)(%r9), %r13; + OCB_INPUT(8, %r10, %r11, %ymm7); + OCB_INPUT(9, %r12, %r13, %ymm6); + movq (20 * 8)(%r9), %r10; + movq (21 * 8)(%r9), %r11; + movq (22 * 8)(%r9), %r12; + movq (23 * 8)(%r9), %r13; + OCB_INPUT(10, %r10, %r11, %ymm5); + OCB_INPUT(11, %r12, %r13, %ymm4); + movq (24 * 8)(%r9), %r10; + movq (25 * 8)(%r9), %r11; + movq (26 * 8)(%r9), %r12; + movq (27 * 8)(%r9), %r13; + OCB_INPUT(12, %r10, %r11, %ymm3); + OCB_INPUT(13, %r12, %r13, %ymm2); + movq (28 * 8)(%r9), %r10; + movq (29 * 8)(%r9), %r11; + movq (30 * 8)(%r9), %r12; + movq (31 * 8)(%r9), %r13; + OCB_INPUT(14, %r10, %r11, %ymm1); + OCB_INPUT(15, %r12, %r13, %ymm0); +#undef OCB_INPUT + + vextracti128 $1, %ymm13, %xmm15; + vmovdqu %xmm14, (%rcx); + vpxor %xmm13, %xmm15, %xmm15; + vmovdqu %xmm15, (%r8); + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %r10d; + cmovel %r10d, %r8d; /* max */ + + /* inpack16_pre: */ + vpbroadcastq (key_table)(CTX), %ymm15; + vpshufb .Lpack_bswap rRIP, %ymm15, %ymm15; + vpxor %ymm0, %ymm15, %ymm0; + vpxor %ymm1, %ymm15, %ymm1; + vpxor %ymm2, %ymm15, %ymm2; + vpxor %ymm3, %ymm15, %ymm3; + vpxor %ymm4, %ymm15, %ymm4; + vpxor %ymm5, %ymm15, %ymm5; + vpxor %ymm6, %ymm15, %ymm6; + vpxor %ymm7, %ymm15, %ymm7; + vpxor %ymm8, %ymm15, %ymm8; + vpxor %ymm9, %ymm15, %ymm9; + vpxor %ymm10, %ymm15, %ymm10; + vpxor %ymm11, %ymm15, %ymm11; + vpxor %ymm12, %ymm15, %ymm12; + vpxor 13 * 32(%rax), %ymm15, %ymm13; + vpxor 14 * 32(%rax), %ymm15, %ymm14; + vpxor 15 * 32(%rax), %ymm15, %ymm15; + + call __camellia_enc_blk32; + + vpxor 0 * 32(%rsi), %ymm7, %ymm7; + vpxor 1 * 32(%rsi), %ymm6, %ymm6; + vpxor 2 * 32(%rsi), %ymm5, %ymm5; + vpxor 3 * 32(%rsi), %ymm4, %ymm4; + vpxor 4 * 32(%rsi), %ymm3, %ymm3; + vpxor 5 * 32(%rsi), %ymm2, %ymm2; + vpxor 6 * 32(%rsi), %ymm1, %ymm1; + vpxor 7 * 32(%rsi), %ymm0, %ymm0; + vpxor 8 * 32(%rsi), %ymm15, %ymm15; + vpxor 9 * 32(%rsi), %ymm14, %ymm14; + vpxor 10 * 32(%rsi), %ymm13, %ymm13; + vpxor 11 * 32(%rsi), %ymm12, %ymm12; + vpxor 12 * 32(%rsi), %ymm11, %ymm11; + vpxor 13 * 32(%rsi), %ymm10, %ymm10; + vpxor 14 * 32(%rsi), %ymm9, %ymm9; + vpxor 15 * 32(%rsi), %ymm8, %ymm8; + + write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0, + %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9, + %ymm8, %rsi); + + vzeroall; + + movq (16 * 32 + 0 * 8)(%rsp), %r10; + movq (16 * 32 + 1 * 8)(%rsp), %r11; + movq (16 * 32 + 2 * 8)(%rsp), %r12; + movq (16 * 32 + 3 * 8)(%rsp), %r13; + CFI_RESTORE(%r10); + CFI_RESTORE(%r11); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx2_ocb_enc,.-_gcry_camellia_aesni_avx2_ocb_enc;) + +.align 8 +.globl _gcry_camellia_aesni_avx2_ocb_dec +ELF(.type _gcry_camellia_aesni_avx2_ocb_dec,@function;) + +_gcry_camellia_aesni_avx2_ocb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (32 blocks) + * %rdx: src (32 blocks) + * %rcx: offset + * %r8 : checksum + * %r9 : L pointers (void *L[32]) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(16 * 32 + 4 * 8), %rsp; + andq $~63, %rsp; + movq %rsp, %rax; + + movq %r10, (16 * 32 + 0 * 8)(%rsp); + movq %r11, (16 * 32 + 1 * 8)(%rsp); + movq %r12, (16 * 32 + 2 * 8)(%rsp); + movq %r13, (16 * 32 + 3 * 8)(%rsp); + CFI_REG_ON_STACK(r10, 16 * 32 + 0 * 8); + CFI_REG_ON_STACK(r11, 16 * 32 + 1 * 8); + CFI_REG_ON_STACK(r12, 16 * 32 + 2 * 8); + CFI_REG_ON_STACK(r13, 16 * 32 + 3 * 8); + + vmovdqu (%rcx), %xmm14; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */ + +#define OCB_INPUT(n, l0reg, l1reg, yreg) \ + vmovdqu (n * 32)(%rdx), yreg; \ + vpxor (l0reg), %xmm14, %xmm15; \ + vpxor (l1reg), %xmm15, %xmm14; \ + vinserti128 $1, %xmm14, %ymm15, %ymm15; \ + vpxor yreg, %ymm15, yreg; \ + vmovdqu %ymm15, (n * 32)(%rsi); + + movq (0 * 8)(%r9), %r10; + movq (1 * 8)(%r9), %r11; + movq (2 * 8)(%r9), %r12; + movq (3 * 8)(%r9), %r13; + OCB_INPUT(0, %r10, %r11, %ymm0); + vmovdqu %ymm0, (15 * 32)(%rax); + OCB_INPUT(1, %r12, %r13, %ymm0); + vmovdqu %ymm0, (14 * 32)(%rax); + movq (4 * 8)(%r9), %r10; + movq (5 * 8)(%r9), %r11; + movq (6 * 8)(%r9), %r12; + movq (7 * 8)(%r9), %r13; + OCB_INPUT(2, %r10, %r11, %ymm13); + OCB_INPUT(3, %r12, %r13, %ymm12); + movq (8 * 8)(%r9), %r10; + movq (9 * 8)(%r9), %r11; + movq (10 * 8)(%r9), %r12; + movq (11 * 8)(%r9), %r13; + OCB_INPUT(4, %r10, %r11, %ymm11); + OCB_INPUT(5, %r12, %r13, %ymm10); + movq (12 * 8)(%r9), %r10; + movq (13 * 8)(%r9), %r11; + movq (14 * 8)(%r9), %r12; + movq (15 * 8)(%r9), %r13; + OCB_INPUT(6, %r10, %r11, %ymm9); + OCB_INPUT(7, %r12, %r13, %ymm8); + movq (16 * 8)(%r9), %r10; + movq (17 * 8)(%r9), %r11; + movq (18 * 8)(%r9), %r12; + movq (19 * 8)(%r9), %r13; + OCB_INPUT(8, %r10, %r11, %ymm7); + OCB_INPUT(9, %r12, %r13, %ymm6); + movq (20 * 8)(%r9), %r10; + movq (21 * 8)(%r9), %r11; + movq (22 * 8)(%r9), %r12; + movq (23 * 8)(%r9), %r13; + OCB_INPUT(10, %r10, %r11, %ymm5); + OCB_INPUT(11, %r12, %r13, %ymm4); + movq (24 * 8)(%r9), %r10; + movq (25 * 8)(%r9), %r11; + movq (26 * 8)(%r9), %r12; + movq (27 * 8)(%r9), %r13; + OCB_INPUT(12, %r10, %r11, %ymm3); + OCB_INPUT(13, %r12, %r13, %ymm2); + movq (28 * 8)(%r9), %r10; + movq (29 * 8)(%r9), %r11; + movq (30 * 8)(%r9), %r12; + movq (31 * 8)(%r9), %r13; + OCB_INPUT(14, %r10, %r11, %ymm1); + OCB_INPUT(15, %r12, %r13, %ymm0); +#undef OCB_INPUT + + vmovdqu %xmm14, (%rcx); + + movq %r8, %r10; + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %r9d; + cmovel %r9d, %r8d; /* max */ + + /* inpack16_pre: */ + vpbroadcastq (key_table)(CTX, %r8, 8), %ymm15; + vpshufb .Lpack_bswap rRIP, %ymm15, %ymm15; + vpxor %ymm0, %ymm15, %ymm0; + vpxor %ymm1, %ymm15, %ymm1; + vpxor %ymm2, %ymm15, %ymm2; + vpxor %ymm3, %ymm15, %ymm3; + vpxor %ymm4, %ymm15, %ymm4; + vpxor %ymm5, %ymm15, %ymm5; + vpxor %ymm6, %ymm15, %ymm6; + vpxor %ymm7, %ymm15, %ymm7; + vpxor %ymm8, %ymm15, %ymm8; + vpxor %ymm9, %ymm15, %ymm9; + vpxor %ymm10, %ymm15, %ymm10; + vpxor %ymm11, %ymm15, %ymm11; + vpxor %ymm12, %ymm15, %ymm12; + vpxor %ymm13, %ymm15, %ymm13; + vpxor 14 * 32(%rax), %ymm15, %ymm14; + vpxor 15 * 32(%rax), %ymm15, %ymm15; + + call __camellia_dec_blk32; + + vpxor 0 * 32(%rsi), %ymm7, %ymm7; + vpxor 1 * 32(%rsi), %ymm6, %ymm6; + vpxor 2 * 32(%rsi), %ymm5, %ymm5; + vpxor 3 * 32(%rsi), %ymm4, %ymm4; + vpxor 4 * 32(%rsi), %ymm3, %ymm3; + vpxor 5 * 32(%rsi), %ymm2, %ymm2; + vpxor 6 * 32(%rsi), %ymm1, %ymm1; + vpxor 7 * 32(%rsi), %ymm0, %ymm0; + vmovdqu %ymm7, (7 * 32)(%rax); + vmovdqu %ymm6, (6 * 32)(%rax); + vpxor 8 * 32(%rsi), %ymm15, %ymm15; + vpxor 9 * 32(%rsi), %ymm14, %ymm14; + vpxor 10 * 32(%rsi), %ymm13, %ymm13; + vpxor 11 * 32(%rsi), %ymm12, %ymm12; + vpxor 12 * 32(%rsi), %ymm11, %ymm11; + vpxor 13 * 32(%rsi), %ymm10, %ymm10; + vpxor 14 * 32(%rsi), %ymm9, %ymm9; + vpxor 15 * 32(%rsi), %ymm8, %ymm8; + + /* Checksum_i = Checksum_{i-1} xor P_i */ + + vpxor %ymm5, %ymm7, %ymm7; + vpxor %ymm4, %ymm6, %ymm6; + vpxor %ymm3, %ymm7, %ymm7; + vpxor %ymm2, %ymm6, %ymm6; + vpxor %ymm1, %ymm7, %ymm7; + vpxor %ymm0, %ymm6, %ymm6; + vpxor %ymm15, %ymm7, %ymm7; + vpxor %ymm14, %ymm6, %ymm6; + vpxor %ymm13, %ymm7, %ymm7; + vpxor %ymm12, %ymm6, %ymm6; + vpxor %ymm11, %ymm7, %ymm7; + vpxor %ymm10, %ymm6, %ymm6; + vpxor %ymm9, %ymm7, %ymm7; + vpxor %ymm8, %ymm6, %ymm6; + vpxor %ymm7, %ymm6, %ymm7; + + vextracti128 $1, %ymm7, %xmm6; + vpxor %xmm6, %xmm7, %xmm7; + vpxor (%r10), %xmm7, %xmm7; + vmovdqu %xmm7, (%r10); + + vmovdqu 7 * 32(%rax), %ymm7; + vmovdqu 6 * 32(%rax), %ymm6; + + write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0, + %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9, + %ymm8, %rsi); + + vzeroall; + + movq (16 * 32 + 0 * 8)(%rsp), %r10; + movq (16 * 32 + 1 * 8)(%rsp), %r11; + movq (16 * 32 + 2 * 8)(%rsp), %r12; + movq (16 * 32 + 3 * 8)(%rsp), %r13; + CFI_RESTORE(%r10); + CFI_RESTORE(%r11); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx2_ocb_dec,.-_gcry_camellia_aesni_avx2_ocb_dec;) + +.align 8 +.globl _gcry_camellia_aesni_avx2_ocb_auth +ELF(.type _gcry_camellia_aesni_avx2_ocb_auth,@function;) + +_gcry_camellia_aesni_avx2_ocb_auth: + /* input: + * %rdi: ctx, CTX + * %rsi: abuf (16 blocks) + * %rdx: offset + * %rcx: checksum + * %r8 : L pointers (void *L[16]) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(16 * 32 + 4 * 8), %rsp; + andq $~63, %rsp; + movq %rsp, %rax; + + movq %r10, (16 * 32 + 0 * 8)(%rsp); + movq %r11, (16 * 32 + 1 * 8)(%rsp); + movq %r12, (16 * 32 + 2 * 8)(%rsp); + movq %r13, (16 * 32 + 3 * 8)(%rsp); + CFI_REG_ON_STACK(r10, 16 * 32 + 0 * 8); + CFI_REG_ON_STACK(r11, 16 * 32 + 1 * 8); + CFI_REG_ON_STACK(r12, 16 * 32 + 2 * 8); + CFI_REG_ON_STACK(r13, 16 * 32 + 3 * 8); + + vmovdqu (%rdx), %xmm14; + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + /* Checksum_i = Checksum_{i-1} xor P_i */ + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + +#define OCB_INPUT(n, l0reg, l1reg, yreg) \ + vmovdqu (n * 32)(%rsi), yreg; \ + vpxor (l0reg), %xmm14, %xmm15; \ + vpxor (l1reg), %xmm15, %xmm14; \ + vinserti128 $1, %xmm14, %ymm15, %ymm15; \ + vpxor yreg, %ymm15, yreg; + + movq (0 * 8)(%r8), %r10; + movq (1 * 8)(%r8), %r11; + movq (2 * 8)(%r8), %r12; + movq (3 * 8)(%r8), %r13; + OCB_INPUT(0, %r10, %r11, %ymm0); + vmovdqu %ymm0, (15 * 32)(%rax); + OCB_INPUT(1, %r12, %r13, %ymm0); + vmovdqu %ymm0, (14 * 32)(%rax); + movq (4 * 8)(%r8), %r10; + movq (5 * 8)(%r8), %r11; + movq (6 * 8)(%r8), %r12; + movq (7 * 8)(%r8), %r13; + OCB_INPUT(2, %r10, %r11, %ymm13); + OCB_INPUT(3, %r12, %r13, %ymm12); + movq (8 * 8)(%r8), %r10; + movq (9 * 8)(%r8), %r11; + movq (10 * 8)(%r8), %r12; + movq (11 * 8)(%r8), %r13; + OCB_INPUT(4, %r10, %r11, %ymm11); + OCB_INPUT(5, %r12, %r13, %ymm10); + movq (12 * 8)(%r8), %r10; + movq (13 * 8)(%r8), %r11; + movq (14 * 8)(%r8), %r12; + movq (15 * 8)(%r8), %r13; + OCB_INPUT(6, %r10, %r11, %ymm9); + OCB_INPUT(7, %r12, %r13, %ymm8); + movq (16 * 8)(%r8), %r10; + movq (17 * 8)(%r8), %r11; + movq (18 * 8)(%r8), %r12; + movq (19 * 8)(%r8), %r13; + OCB_INPUT(8, %r10, %r11, %ymm7); + OCB_INPUT(9, %r12, %r13, %ymm6); + movq (20 * 8)(%r8), %r10; + movq (21 * 8)(%r8), %r11; + movq (22 * 8)(%r8), %r12; + movq (23 * 8)(%r8), %r13; + OCB_INPUT(10, %r10, %r11, %ymm5); + OCB_INPUT(11, %r12, %r13, %ymm4); + movq (24 * 8)(%r8), %r10; + movq (25 * 8)(%r8), %r11; + movq (26 * 8)(%r8), %r12; + movq (27 * 8)(%r8), %r13; + OCB_INPUT(12, %r10, %r11, %ymm3); + OCB_INPUT(13, %r12, %r13, %ymm2); + movq (28 * 8)(%r8), %r10; + movq (29 * 8)(%r8), %r11; + movq (30 * 8)(%r8), %r12; + movq (31 * 8)(%r8), %r13; + OCB_INPUT(14, %r10, %r11, %ymm1); + OCB_INPUT(15, %r12, %r13, %ymm0); +#undef OCB_INPUT + + vmovdqu %xmm14, (%rdx); + + cmpl $128, key_bitlength(CTX); + movl $32, %r8d; + movl $24, %r10d; + cmovel %r10d, %r8d; /* max */ + + movq %rcx, %r10; + + /* inpack16_pre: */ + vpbroadcastq (key_table)(CTX), %ymm15; + vpshufb .Lpack_bswap rRIP, %ymm15, %ymm15; + vpxor %ymm0, %ymm15, %ymm0; + vpxor %ymm1, %ymm15, %ymm1; + vpxor %ymm2, %ymm15, %ymm2; + vpxor %ymm3, %ymm15, %ymm3; + vpxor %ymm4, %ymm15, %ymm4; + vpxor %ymm5, %ymm15, %ymm5; + vpxor %ymm6, %ymm15, %ymm6; + vpxor %ymm7, %ymm15, %ymm7; + vpxor %ymm8, %ymm15, %ymm8; + vpxor %ymm9, %ymm15, %ymm9; + vpxor %ymm10, %ymm15, %ymm10; + vpxor %ymm11, %ymm15, %ymm11; + vpxor %ymm12, %ymm15, %ymm12; + vpxor %ymm13, %ymm15, %ymm13; + vpxor 14 * 32(%rax), %ymm15, %ymm14; + vpxor 15 * 32(%rax), %ymm15, %ymm15; + + call __camellia_enc_blk32; + + vpxor %ymm7, %ymm6, %ymm6; + vpxor %ymm5, %ymm4, %ymm4; + vpxor %ymm3, %ymm2, %ymm2; + vpxor %ymm1, %ymm0, %ymm0; + vpxor %ymm15, %ymm14, %ymm14; + vpxor %ymm13, %ymm12, %ymm12; + vpxor %ymm11, %ymm10, %ymm10; + vpxor %ymm9, %ymm8, %ymm8; + + vpxor %ymm6, %ymm4, %ymm4; + vpxor %ymm2, %ymm0, %ymm0; + vpxor %ymm14, %ymm12, %ymm12; + vpxor %ymm10, %ymm8, %ymm8; + + vpxor %ymm4, %ymm0, %ymm0; + vpxor %ymm12, %ymm8, %ymm8; + + vpxor %ymm0, %ymm8, %ymm0; + + vextracti128 $1, %ymm0, %xmm1; + vpxor (%r10), %xmm0, %xmm0; + vpxor %xmm0, %xmm1, %xmm0; + vmovdqu %xmm0, (%r10); + + vzeroall; + + movq (16 * 32 + 0 * 8)(%rsp), %r10; + movq (16 * 32 + 1 * 8)(%rsp), %r11; + movq (16 * 32 + 2 * 8)(%rsp), %r12; + movq (16 * 32 + 3 * 8)(%rsp), %r13; + CFI_RESTORE(%r10); + CFI_RESTORE(%r11); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_camellia_aesni_avx2_ocb_auth,.-_gcry_camellia_aesni_avx2_ocb_auth;) + +#endif /*defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/camellia-arm.S b/comm/third_party/libgcrypt/cipher/camellia-arm.S new file mode 100644 index 0000000000..a3d87d1109 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia-arm.S @@ -0,0 +1,626 @@ +/* camellia-arm.S - ARM assembly implementation of Camellia cipher + * + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(__ARMEL__) +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +.text + +.syntax unified +.arm + +#ifdef __PIC__ +# define GET_DATA_POINTER(reg, name, rtmp) \ + ldr reg, 1f; \ + ldr rtmp, 2f; \ + b 3f; \ + 1: .word _GLOBAL_OFFSET_TABLE_-(3f+8); \ + 2: .word name(GOT); \ + 3: add reg, pc, reg; \ + ldr reg, [reg, rtmp]; +#else +# define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name +#endif + +/* struct camellia_ctx: */ +#define key_table 0 + +/* register macros */ +#define CTX %r0 +#define RTAB1 %ip +#define RTAB3 %r1 +#define RMASK %lr + +#define IL %r2 +#define IR %r3 + +#define XL %r4 +#define XR %r5 +#define YL %r6 +#define YR %r7 + +#define RT0 %r8 +#define RT1 %r9 +#define RT2 %r10 +#define RT3 %r11 + +/* helper macros */ +#define ldr_unaligned_be(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 3)]; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 0)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 3)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 2)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 1)]; \ + strb rtmp0, [rdst, #((offs) + 0)]; + +#ifdef __ARMEL__ +#ifdef HAVE_ARM_ARCH_V6 + #define host_to_be(reg, rtmp) \ + rev reg, reg; + #define be_to_host(reg, rtmp) \ + rev reg, reg; +#else + #define host_to_be(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; + #define be_to_host(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; +#endif +#else + /* nop on big-endian */ + #define host_to_be(reg, rtmp) /*_*/ + #define be_to_host(reg, rtmp) /*_*/ +#endif + +#define ldr_input_aligned_be(rin, a, b, c, d, rtmp) \ + ldr a, [rin, #0]; \ + ldr b, [rin, #4]; \ + be_to_host(a, rtmp); \ + ldr c, [rin, #8]; \ + be_to_host(b, rtmp); \ + ldr d, [rin, #12]; \ + be_to_host(c, rtmp); \ + be_to_host(d, rtmp); + +#define str_output_aligned_be(rout, a, b, c, d, rtmp) \ + be_to_host(a, rtmp); \ + be_to_host(b, rtmp); \ + str a, [rout, #0]; \ + be_to_host(c, rtmp); \ + str b, [rout, #4]; \ + be_to_host(d, rtmp); \ + str c, [rout, #8]; \ + str d, [rout, #12]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads/writes allowed */ + #define ldr_input_be(rin, ra, rb, rc, rd, rtmp) \ + ldr_input_aligned_be(rin, ra, rb, rc, rd, rtmp) + + #define str_output_be(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + str_output_aligned_be(rout, ra, rb, rc, rd, rtmp0) +#else + /* need to handle unaligned reads/writes by byte reads */ + #define ldr_input_be(rin, ra, rb, rc, rd, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(ra, rin, 0, rtmp0); \ + ldr_unaligned_be(rb, rin, 4, rtmp0); \ + ldr_unaligned_be(rc, rin, 8, rtmp0); \ + ldr_unaligned_be(rd, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + ldr_input_aligned_be(rin, ra, rb, rc, rd, rtmp0); \ + 2:; + + #define str_output_be(rout, ra, rb, rc, rd, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(ra, rout, 0, rtmp0, rtmp1); \ + str_unaligned_be(rb, rout, 4, rtmp0, rtmp1); \ + str_unaligned_be(rc, rout, 8, rtmp0, rtmp1); \ + str_unaligned_be(rd, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + str_output_aligned_be(rout, ra, rb, rc, rd, rtmp0); \ + 2:; +#endif + +/********************************************************************** + 1-way camellia + **********************************************************************/ +#define roundsm(xl, xr, kl, kr, yl, yr) \ + ldr RT2, [CTX, #(key_table + ((kl) * 4))]; \ + and IR, RMASK, xr, lsl#(4); /*sp1110*/ \ + ldr RT3, [CTX, #(key_table + ((kr) * 4))]; \ + and IL, RMASK, xl, lsr#(24 - 4); /*sp1110*/ \ + and RT0, RMASK, xr, lsr#(16 - 4); /*sp3033*/ \ + ldr IR, [RTAB1, IR]; \ + and RT1, RMASK, xl, lsr#(8 - 4); /*sp3033*/ \ + eor yl, RT2; \ + ldr IL, [RTAB1, IL]; \ + eor yr, RT3; \ + \ + ldr RT0, [RTAB3, RT0]; \ + add RTAB1, #4; \ + ldr RT1, [RTAB3, RT1]; \ + add RTAB3, #4; \ + \ + and RT2, RMASK, xr, lsr#(24 - 4); /*sp0222*/ \ + and RT3, RMASK, xl, lsr#(16 - 4); /*sp0222*/ \ + \ + eor IR, RT0; \ + eor IL, RT1; \ + \ + ldr RT2, [RTAB1, RT2]; \ + and RT0, RMASK, xr, lsr#(8 - 4); /*sp4404*/ \ + ldr RT3, [RTAB1, RT3]; \ + and RT1, RMASK, xl, lsl#(4); /*sp4404*/ \ + \ + ldr RT0, [RTAB3, RT0]; \ + sub RTAB1, #4; \ + ldr RT1, [RTAB3, RT1]; \ + sub RTAB3, #4; \ + \ + eor IR, RT2; \ + eor IL, RT3; \ + eor IR, RT0; \ + eor IL, RT1; \ + \ + eor IR, IL; \ + eor yr, yr, IL, ror#8; \ + eor yl, IR; \ + eor yr, IR; + +#define enc_rounds(n) \ + roundsm(XL, XR, ((n) + 2) * 2 + 0, ((n) + 2) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 3) * 2 + 0, ((n) + 3) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 4) * 2 + 0, ((n) + 4) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 5) * 2 + 0, ((n) + 5) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 6) * 2 + 0, ((n) + 6) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 7) * 2 + 0, ((n) + 7) * 2 + 1, XL, XR); + +#define dec_rounds(n) \ + roundsm(XL, XR, ((n) + 7) * 2 + 0, ((n) + 7) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 6) * 2 + 0, ((n) + 6) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 5) * 2 + 0, ((n) + 5) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 4) * 2 + 0, ((n) + 4) * 2 + 1, XL, XR); \ + roundsm(XL, XR, ((n) + 3) * 2 + 0, ((n) + 3) * 2 + 1, YL, YR); \ + roundsm(YL, YR, ((n) + 2) * 2 + 0, ((n) + 2) * 2 + 1, XL, XR); + +/* perform FL and FLâ»Â¹ */ +#define fls(ll, lr, rl, rr, kll, klr, krl, krr) \ + ldr RT0, [CTX, #(key_table + ((kll) * 4))]; \ + ldr RT2, [CTX, #(key_table + ((krr) * 4))]; \ + and RT0, ll; \ + ldr RT3, [CTX, #(key_table + ((krl) * 4))]; \ + orr RT2, rr; \ + ldr RT1, [CTX, #(key_table + ((klr) * 4))]; \ + eor rl, RT2; \ + eor lr, lr, RT0, ror#31; \ + and RT3, rl; \ + orr RT1, lr; \ + eor ll, RT1; \ + eor rr, rr, RT3, ror#31; + +#define enc_fls(n) \ + fls(XL, XR, YL, YR, \ + (n) * 2 + 0, (n) * 2 + 1, \ + (n) * 2 + 2, (n) * 2 + 3); + +#define dec_fls(n) \ + fls(XL, XR, YL, YR, \ + (n) * 2 + 2, (n) * 2 + 3, \ + (n) * 2 + 0, (n) * 2 + 1); + +#define inpack(n) \ + ldr_input_be(%r2, XL, XR, YL, YR, RT0); \ + ldr RT0, [CTX, #(key_table + ((n) * 8) + 0)]; \ + ldr RT1, [CTX, #(key_table + ((n) * 8) + 4)]; \ + eor XL, RT0; \ + eor XR, RT1; + +#define outunpack(n) \ + ldr RT0, [CTX, #(key_table + ((n) * 8) + 0)]; \ + ldr RT1, [CTX, #(key_table + ((n) * 8) + 4)]; \ + eor YL, RT0; \ + eor YR, RT1; \ + str_output_be(%r1, YL, YR, XL, XR, RT0, RT1); + +.align 3 +.globl _gcry_camellia_arm_encrypt_block +.type _gcry_camellia_arm_encrypt_block,%function; + +_gcry_camellia_arm_encrypt_block: + /* input: + * %r0: keytable + * %r1: dst + * %r2: src + * %r3: keybitlen + */ + push {%r1, %r4-%r11, %ip, %lr}; + + GET_DATA_POINTER(RTAB1, .Lcamellia_sp1110, RTAB3); + mov RMASK, #0xff; + add RTAB3, RTAB1, #(2 * 4); + push {%r3}; + mov RMASK, RMASK, lsl#4 /* byte mask */ + + inpack(0); + + enc_rounds(0); + enc_fls(8); + enc_rounds(8); + enc_fls(16); + enc_rounds(16); + + pop {RT0}; + cmp RT0, #(16 * 8); + bne .Lenc_256; + + pop {%r1}; + outunpack(24); + + pop {%r4-%r11, %ip, %pc}; +.ltorg + +.Lenc_256: + enc_fls(24); + enc_rounds(24); + + pop {%r1}; + outunpack(32); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_camellia_arm_encrypt_block,.-_gcry_camellia_arm_encrypt_block; + +.align 3 +.globl _gcry_camellia_arm_decrypt_block +.type _gcry_camellia_arm_decrypt_block,%function; + +_gcry_camellia_arm_decrypt_block: + /* input: + * %r0: keytable + * %r1: dst + * %r2: src + * %r3: keybitlen + */ + push {%r1, %r4-%r11, %ip, %lr}; + + GET_DATA_POINTER(RTAB1, .Lcamellia_sp1110, RTAB3); + mov RMASK, #0xff; + add RTAB3, RTAB1, #(2 * 4); + mov RMASK, RMASK, lsl#4 /* byte mask */ + + cmp %r3, #(16 * 8); + bne .Ldec_256; + + inpack(24); + +.Ldec_128: + dec_rounds(16); + dec_fls(16); + dec_rounds(8); + dec_fls(8); + dec_rounds(0); + + pop {%r1}; + outunpack(0); + + pop {%r4-%r11, %ip, %pc}; +.ltorg + +.Ldec_256: + inpack(32); + dec_rounds(24); + dec_fls(24); + + b .Ldec_128; +.ltorg +.size _gcry_camellia_arm_decrypt_block,.-_gcry_camellia_arm_decrypt_block; + +.data + +/* Encryption/Decryption tables */ +.align 5 +.Lcamellia_sp1110: +.long 0x70707000 +.Lcamellia_sp0222: + .long 0x00e0e0e0 +.Lcamellia_sp3033: + .long 0x38003838 +.Lcamellia_sp4404: + .long 0x70700070 +.long 0x82828200, 0x00050505, 0x41004141, 0x2c2c002c +.long 0x2c2c2c00, 0x00585858, 0x16001616, 0xb3b300b3 +.long 0xececec00, 0x00d9d9d9, 0x76007676, 0xc0c000c0 +.long 0xb3b3b300, 0x00676767, 0xd900d9d9, 0xe4e400e4 +.long 0x27272700, 0x004e4e4e, 0x93009393, 0x57570057 +.long 0xc0c0c000, 0x00818181, 0x60006060, 0xeaea00ea +.long 0xe5e5e500, 0x00cbcbcb, 0xf200f2f2, 0xaeae00ae +.long 0xe4e4e400, 0x00c9c9c9, 0x72007272, 0x23230023 +.long 0x85858500, 0x000b0b0b, 0xc200c2c2, 0x6b6b006b +.long 0x57575700, 0x00aeaeae, 0xab00abab, 0x45450045 +.long 0x35353500, 0x006a6a6a, 0x9a009a9a, 0xa5a500a5 +.long 0xeaeaea00, 0x00d5d5d5, 0x75007575, 0xeded00ed +.long 0x0c0c0c00, 0x00181818, 0x06000606, 0x4f4f004f +.long 0xaeaeae00, 0x005d5d5d, 0x57005757, 0x1d1d001d +.long 0x41414100, 0x00828282, 0xa000a0a0, 0x92920092 +.long 0x23232300, 0x00464646, 0x91009191, 0x86860086 +.long 0xefefef00, 0x00dfdfdf, 0xf700f7f7, 0xafaf00af +.long 0x6b6b6b00, 0x00d6d6d6, 0xb500b5b5, 0x7c7c007c +.long 0x93939300, 0x00272727, 0xc900c9c9, 0x1f1f001f +.long 0x45454500, 0x008a8a8a, 0xa200a2a2, 0x3e3e003e +.long 0x19191900, 0x00323232, 0x8c008c8c, 0xdcdc00dc +.long 0xa5a5a500, 0x004b4b4b, 0xd200d2d2, 0x5e5e005e +.long 0x21212100, 0x00424242, 0x90009090, 0x0b0b000b +.long 0xededed00, 0x00dbdbdb, 0xf600f6f6, 0xa6a600a6 +.long 0x0e0e0e00, 0x001c1c1c, 0x07000707, 0x39390039 +.long 0x4f4f4f00, 0x009e9e9e, 0xa700a7a7, 0xd5d500d5 +.long 0x4e4e4e00, 0x009c9c9c, 0x27002727, 0x5d5d005d +.long 0x1d1d1d00, 0x003a3a3a, 0x8e008e8e, 0xd9d900d9 +.long 0x65656500, 0x00cacaca, 0xb200b2b2, 0x5a5a005a +.long 0x92929200, 0x00252525, 0x49004949, 0x51510051 +.long 0xbdbdbd00, 0x007b7b7b, 0xde00dede, 0x6c6c006c +.long 0x86868600, 0x000d0d0d, 0x43004343, 0x8b8b008b +.long 0xb8b8b800, 0x00717171, 0x5c005c5c, 0x9a9a009a +.long 0xafafaf00, 0x005f5f5f, 0xd700d7d7, 0xfbfb00fb +.long 0x8f8f8f00, 0x001f1f1f, 0xc700c7c7, 0xb0b000b0 +.long 0x7c7c7c00, 0x00f8f8f8, 0x3e003e3e, 0x74740074 +.long 0xebebeb00, 0x00d7d7d7, 0xf500f5f5, 0x2b2b002b +.long 0x1f1f1f00, 0x003e3e3e, 0x8f008f8f, 0xf0f000f0 +.long 0xcecece00, 0x009d9d9d, 0x67006767, 0x84840084 +.long 0x3e3e3e00, 0x007c7c7c, 0x1f001f1f, 0xdfdf00df +.long 0x30303000, 0x00606060, 0x18001818, 0xcbcb00cb +.long 0xdcdcdc00, 0x00b9b9b9, 0x6e006e6e, 0x34340034 +.long 0x5f5f5f00, 0x00bebebe, 0xaf00afaf, 0x76760076 +.long 0x5e5e5e00, 0x00bcbcbc, 0x2f002f2f, 0x6d6d006d +.long 0xc5c5c500, 0x008b8b8b, 0xe200e2e2, 0xa9a900a9 +.long 0x0b0b0b00, 0x00161616, 0x85008585, 0xd1d100d1 +.long 0x1a1a1a00, 0x00343434, 0x0d000d0d, 0x04040004 +.long 0xa6a6a600, 0x004d4d4d, 0x53005353, 0x14140014 +.long 0xe1e1e100, 0x00c3c3c3, 0xf000f0f0, 0x3a3a003a +.long 0x39393900, 0x00727272, 0x9c009c9c, 0xdede00de +.long 0xcacaca00, 0x00959595, 0x65006565, 0x11110011 +.long 0xd5d5d500, 0x00ababab, 0xea00eaea, 0x32320032 +.long 0x47474700, 0x008e8e8e, 0xa300a3a3, 0x9c9c009c +.long 0x5d5d5d00, 0x00bababa, 0xae00aeae, 0x53530053 +.long 0x3d3d3d00, 0x007a7a7a, 0x9e009e9e, 0xf2f200f2 +.long 0xd9d9d900, 0x00b3b3b3, 0xec00ecec, 0xfefe00fe +.long 0x01010100, 0x00020202, 0x80008080, 0xcfcf00cf +.long 0x5a5a5a00, 0x00b4b4b4, 0x2d002d2d, 0xc3c300c3 +.long 0xd6d6d600, 0x00adadad, 0x6b006b6b, 0x7a7a007a +.long 0x51515100, 0x00a2a2a2, 0xa800a8a8, 0x24240024 +.long 0x56565600, 0x00acacac, 0x2b002b2b, 0xe8e800e8 +.long 0x6c6c6c00, 0x00d8d8d8, 0x36003636, 0x60600060 +.long 0x4d4d4d00, 0x009a9a9a, 0xa600a6a6, 0x69690069 +.long 0x8b8b8b00, 0x00171717, 0xc500c5c5, 0xaaaa00aa +.long 0x0d0d0d00, 0x001a1a1a, 0x86008686, 0xa0a000a0 +.long 0x9a9a9a00, 0x00353535, 0x4d004d4d, 0xa1a100a1 +.long 0x66666600, 0x00cccccc, 0x33003333, 0x62620062 +.long 0xfbfbfb00, 0x00f7f7f7, 0xfd00fdfd, 0x54540054 +.long 0xcccccc00, 0x00999999, 0x66006666, 0x1e1e001e +.long 0xb0b0b000, 0x00616161, 0x58005858, 0xe0e000e0 +.long 0x2d2d2d00, 0x005a5a5a, 0x96009696, 0x64640064 +.long 0x74747400, 0x00e8e8e8, 0x3a003a3a, 0x10100010 +.long 0x12121200, 0x00242424, 0x09000909, 0x00000000 +.long 0x2b2b2b00, 0x00565656, 0x95009595, 0xa3a300a3 +.long 0x20202000, 0x00404040, 0x10001010, 0x75750075 +.long 0xf0f0f000, 0x00e1e1e1, 0x78007878, 0x8a8a008a +.long 0xb1b1b100, 0x00636363, 0xd800d8d8, 0xe6e600e6 +.long 0x84848400, 0x00090909, 0x42004242, 0x09090009 +.long 0x99999900, 0x00333333, 0xcc00cccc, 0xdddd00dd +.long 0xdfdfdf00, 0x00bfbfbf, 0xef00efef, 0x87870087 +.long 0x4c4c4c00, 0x00989898, 0x26002626, 0x83830083 +.long 0xcbcbcb00, 0x00979797, 0xe500e5e5, 0xcdcd00cd +.long 0xc2c2c200, 0x00858585, 0x61006161, 0x90900090 +.long 0x34343400, 0x00686868, 0x1a001a1a, 0x73730073 +.long 0x7e7e7e00, 0x00fcfcfc, 0x3f003f3f, 0xf6f600f6 +.long 0x76767600, 0x00ececec, 0x3b003b3b, 0x9d9d009d +.long 0x05050500, 0x000a0a0a, 0x82008282, 0xbfbf00bf +.long 0x6d6d6d00, 0x00dadada, 0xb600b6b6, 0x52520052 +.long 0xb7b7b700, 0x006f6f6f, 0xdb00dbdb, 0xd8d800d8 +.long 0xa9a9a900, 0x00535353, 0xd400d4d4, 0xc8c800c8 +.long 0x31313100, 0x00626262, 0x98009898, 0xc6c600c6 +.long 0xd1d1d100, 0x00a3a3a3, 0xe800e8e8, 0x81810081 +.long 0x17171700, 0x002e2e2e, 0x8b008b8b, 0x6f6f006f +.long 0x04040400, 0x00080808, 0x02000202, 0x13130013 +.long 0xd7d7d700, 0x00afafaf, 0xeb00ebeb, 0x63630063 +.long 0x14141400, 0x00282828, 0x0a000a0a, 0xe9e900e9 +.long 0x58585800, 0x00b0b0b0, 0x2c002c2c, 0xa7a700a7 +.long 0x3a3a3a00, 0x00747474, 0x1d001d1d, 0x9f9f009f +.long 0x61616100, 0x00c2c2c2, 0xb000b0b0, 0xbcbc00bc +.long 0xdedede00, 0x00bdbdbd, 0x6f006f6f, 0x29290029 +.long 0x1b1b1b00, 0x00363636, 0x8d008d8d, 0xf9f900f9 +.long 0x11111100, 0x00222222, 0x88008888, 0x2f2f002f +.long 0x1c1c1c00, 0x00383838, 0x0e000e0e, 0xb4b400b4 +.long 0x32323200, 0x00646464, 0x19001919, 0x78780078 +.long 0x0f0f0f00, 0x001e1e1e, 0x87008787, 0x06060006 +.long 0x9c9c9c00, 0x00393939, 0x4e004e4e, 0xe7e700e7 +.long 0x16161600, 0x002c2c2c, 0x0b000b0b, 0x71710071 +.long 0x53535300, 0x00a6a6a6, 0xa900a9a9, 0xd4d400d4 +.long 0x18181800, 0x00303030, 0x0c000c0c, 0xabab00ab +.long 0xf2f2f200, 0x00e5e5e5, 0x79007979, 0x88880088 +.long 0x22222200, 0x00444444, 0x11001111, 0x8d8d008d +.long 0xfefefe00, 0x00fdfdfd, 0x7f007f7f, 0x72720072 +.long 0x44444400, 0x00888888, 0x22002222, 0xb9b900b9 +.long 0xcfcfcf00, 0x009f9f9f, 0xe700e7e7, 0xf8f800f8 +.long 0xb2b2b200, 0x00656565, 0x59005959, 0xacac00ac +.long 0xc3c3c300, 0x00878787, 0xe100e1e1, 0x36360036 +.long 0xb5b5b500, 0x006b6b6b, 0xda00dada, 0x2a2a002a +.long 0x7a7a7a00, 0x00f4f4f4, 0x3d003d3d, 0x3c3c003c +.long 0x91919100, 0x00232323, 0xc800c8c8, 0xf1f100f1 +.long 0x24242400, 0x00484848, 0x12001212, 0x40400040 +.long 0x08080800, 0x00101010, 0x04000404, 0xd3d300d3 +.long 0xe8e8e800, 0x00d1d1d1, 0x74007474, 0xbbbb00bb +.long 0xa8a8a800, 0x00515151, 0x54005454, 0x43430043 +.long 0x60606000, 0x00c0c0c0, 0x30003030, 0x15150015 +.long 0xfcfcfc00, 0x00f9f9f9, 0x7e007e7e, 0xadad00ad +.long 0x69696900, 0x00d2d2d2, 0xb400b4b4, 0x77770077 +.long 0x50505000, 0x00a0a0a0, 0x28002828, 0x80800080 +.long 0xaaaaaa00, 0x00555555, 0x55005555, 0x82820082 +.long 0xd0d0d000, 0x00a1a1a1, 0x68006868, 0xecec00ec +.long 0xa0a0a000, 0x00414141, 0x50005050, 0x27270027 +.long 0x7d7d7d00, 0x00fafafa, 0xbe00bebe, 0xe5e500e5 +.long 0xa1a1a100, 0x00434343, 0xd000d0d0, 0x85850085 +.long 0x89898900, 0x00131313, 0xc400c4c4, 0x35350035 +.long 0x62626200, 0x00c4c4c4, 0x31003131, 0x0c0c000c +.long 0x97979700, 0x002f2f2f, 0xcb00cbcb, 0x41410041 +.long 0x54545400, 0x00a8a8a8, 0x2a002a2a, 0xefef00ef +.long 0x5b5b5b00, 0x00b6b6b6, 0xad00adad, 0x93930093 +.long 0x1e1e1e00, 0x003c3c3c, 0x0f000f0f, 0x19190019 +.long 0x95959500, 0x002b2b2b, 0xca00caca, 0x21210021 +.long 0xe0e0e000, 0x00c1c1c1, 0x70007070, 0x0e0e000e +.long 0xffffff00, 0x00ffffff, 0xff00ffff, 0x4e4e004e +.long 0x64646400, 0x00c8c8c8, 0x32003232, 0x65650065 +.long 0xd2d2d200, 0x00a5a5a5, 0x69006969, 0xbdbd00bd +.long 0x10101000, 0x00202020, 0x08000808, 0xb8b800b8 +.long 0xc4c4c400, 0x00898989, 0x62006262, 0x8f8f008f +.long 0x00000000, 0x00000000, 0x00000000, 0xebeb00eb +.long 0x48484800, 0x00909090, 0x24002424, 0xcece00ce +.long 0xa3a3a300, 0x00474747, 0xd100d1d1, 0x30300030 +.long 0xf7f7f700, 0x00efefef, 0xfb00fbfb, 0x5f5f005f +.long 0x75757500, 0x00eaeaea, 0xba00baba, 0xc5c500c5 +.long 0xdbdbdb00, 0x00b7b7b7, 0xed00eded, 0x1a1a001a +.long 0x8a8a8a00, 0x00151515, 0x45004545, 0xe1e100e1 +.long 0x03030300, 0x00060606, 0x81008181, 0xcaca00ca +.long 0xe6e6e600, 0x00cdcdcd, 0x73007373, 0x47470047 +.long 0xdadada00, 0x00b5b5b5, 0x6d006d6d, 0x3d3d003d +.long 0x09090900, 0x00121212, 0x84008484, 0x01010001 +.long 0x3f3f3f00, 0x007e7e7e, 0x9f009f9f, 0xd6d600d6 +.long 0xdddddd00, 0x00bbbbbb, 0xee00eeee, 0x56560056 +.long 0x94949400, 0x00292929, 0x4a004a4a, 0x4d4d004d +.long 0x87878700, 0x000f0f0f, 0xc300c3c3, 0x0d0d000d +.long 0x5c5c5c00, 0x00b8b8b8, 0x2e002e2e, 0x66660066 +.long 0x83838300, 0x00070707, 0xc100c1c1, 0xcccc00cc +.long 0x02020200, 0x00040404, 0x01000101, 0x2d2d002d +.long 0xcdcdcd00, 0x009b9b9b, 0xe600e6e6, 0x12120012 +.long 0x4a4a4a00, 0x00949494, 0x25002525, 0x20200020 +.long 0x90909000, 0x00212121, 0x48004848, 0xb1b100b1 +.long 0x33333300, 0x00666666, 0x99009999, 0x99990099 +.long 0x73737300, 0x00e6e6e6, 0xb900b9b9, 0x4c4c004c +.long 0x67676700, 0x00cecece, 0xb300b3b3, 0xc2c200c2 +.long 0xf6f6f600, 0x00ededed, 0x7b007b7b, 0x7e7e007e +.long 0xf3f3f300, 0x00e7e7e7, 0xf900f9f9, 0x05050005 +.long 0x9d9d9d00, 0x003b3b3b, 0xce00cece, 0xb7b700b7 +.long 0x7f7f7f00, 0x00fefefe, 0xbf00bfbf, 0x31310031 +.long 0xbfbfbf00, 0x007f7f7f, 0xdf00dfdf, 0x17170017 +.long 0xe2e2e200, 0x00c5c5c5, 0x71007171, 0xd7d700d7 +.long 0x52525200, 0x00a4a4a4, 0x29002929, 0x58580058 +.long 0x9b9b9b00, 0x00373737, 0xcd00cdcd, 0x61610061 +.long 0xd8d8d800, 0x00b1b1b1, 0x6c006c6c, 0x1b1b001b +.long 0x26262600, 0x004c4c4c, 0x13001313, 0x1c1c001c +.long 0xc8c8c800, 0x00919191, 0x64006464, 0x0f0f000f +.long 0x37373700, 0x006e6e6e, 0x9b009b9b, 0x16160016 +.long 0xc6c6c600, 0x008d8d8d, 0x63006363, 0x18180018 +.long 0x3b3b3b00, 0x00767676, 0x9d009d9d, 0x22220022 +.long 0x81818100, 0x00030303, 0xc000c0c0, 0x44440044 +.long 0x96969600, 0x002d2d2d, 0x4b004b4b, 0xb2b200b2 +.long 0x6f6f6f00, 0x00dedede, 0xb700b7b7, 0xb5b500b5 +.long 0x4b4b4b00, 0x00969696, 0xa500a5a5, 0x91910091 +.long 0x13131300, 0x00262626, 0x89008989, 0x08080008 +.long 0xbebebe00, 0x007d7d7d, 0x5f005f5f, 0xa8a800a8 +.long 0x63636300, 0x00c6c6c6, 0xb100b1b1, 0xfcfc00fc +.long 0x2e2e2e00, 0x005c5c5c, 0x17001717, 0x50500050 +.long 0xe9e9e900, 0x00d3d3d3, 0xf400f4f4, 0xd0d000d0 +.long 0x79797900, 0x00f2f2f2, 0xbc00bcbc, 0x7d7d007d +.long 0xa7a7a700, 0x004f4f4f, 0xd300d3d3, 0x89890089 +.long 0x8c8c8c00, 0x00191919, 0x46004646, 0x97970097 +.long 0x9f9f9f00, 0x003f3f3f, 0xcf00cfcf, 0x5b5b005b +.long 0x6e6e6e00, 0x00dcdcdc, 0x37003737, 0x95950095 +.long 0xbcbcbc00, 0x00797979, 0x5e005e5e, 0xffff00ff +.long 0x8e8e8e00, 0x001d1d1d, 0x47004747, 0xd2d200d2 +.long 0x29292900, 0x00525252, 0x94009494, 0xc4c400c4 +.long 0xf5f5f500, 0x00ebebeb, 0xfa00fafa, 0x48480048 +.long 0xf9f9f900, 0x00f3f3f3, 0xfc00fcfc, 0xf7f700f7 +.long 0xb6b6b600, 0x006d6d6d, 0x5b005b5b, 0xdbdb00db +.long 0x2f2f2f00, 0x005e5e5e, 0x97009797, 0x03030003 +.long 0xfdfdfd00, 0x00fbfbfb, 0xfe00fefe, 0xdada00da +.long 0xb4b4b400, 0x00696969, 0x5a005a5a, 0x3f3f003f +.long 0x59595900, 0x00b2b2b2, 0xac00acac, 0x94940094 +.long 0x78787800, 0x00f0f0f0, 0x3c003c3c, 0x5c5c005c +.long 0x98989800, 0x00313131, 0x4c004c4c, 0x02020002 +.long 0x06060600, 0x000c0c0c, 0x03000303, 0x4a4a004a +.long 0x6a6a6a00, 0x00d4d4d4, 0x35003535, 0x33330033 +.long 0xe7e7e700, 0x00cfcfcf, 0xf300f3f3, 0x67670067 +.long 0x46464600, 0x008c8c8c, 0x23002323, 0xf3f300f3 +.long 0x71717100, 0x00e2e2e2, 0xb800b8b8, 0x7f7f007f +.long 0xbababa00, 0x00757575, 0x5d005d5d, 0xe2e200e2 +.long 0xd4d4d400, 0x00a9a9a9, 0x6a006a6a, 0x9b9b009b +.long 0x25252500, 0x004a4a4a, 0x92009292, 0x26260026 +.long 0xababab00, 0x00575757, 0xd500d5d5, 0x37370037 +.long 0x42424200, 0x00848484, 0x21002121, 0x3b3b003b +.long 0x88888800, 0x00111111, 0x44004444, 0x96960096 +.long 0xa2a2a200, 0x00454545, 0x51005151, 0x4b4b004b +.long 0x8d8d8d00, 0x001b1b1b, 0xc600c6c6, 0xbebe00be +.long 0xfafafa00, 0x00f5f5f5, 0x7d007d7d, 0x2e2e002e +.long 0x72727200, 0x00e4e4e4, 0x39003939, 0x79790079 +.long 0x07070700, 0x000e0e0e, 0x83008383, 0x8c8c008c +.long 0xb9b9b900, 0x00737373, 0xdc00dcdc, 0x6e6e006e +.long 0x55555500, 0x00aaaaaa, 0xaa00aaaa, 0x8e8e008e +.long 0xf8f8f800, 0x00f1f1f1, 0x7c007c7c, 0xf5f500f5 +.long 0xeeeeee00, 0x00dddddd, 0x77007777, 0xb6b600b6 +.long 0xacacac00, 0x00595959, 0x56005656, 0xfdfd00fd +.long 0x0a0a0a00, 0x00141414, 0x05000505, 0x59590059 +.long 0x36363600, 0x006c6c6c, 0x1b001b1b, 0x98980098 +.long 0x49494900, 0x00929292, 0xa400a4a4, 0x6a6a006a +.long 0x2a2a2a00, 0x00545454, 0x15001515, 0x46460046 +.long 0x68686800, 0x00d0d0d0, 0x34003434, 0xbaba00ba +.long 0x3c3c3c00, 0x00787878, 0x1e001e1e, 0x25250025 +.long 0x38383800, 0x00707070, 0x1c001c1c, 0x42420042 +.long 0xf1f1f100, 0x00e3e3e3, 0xf800f8f8, 0xa2a200a2 +.long 0xa4a4a400, 0x00494949, 0x52005252, 0xfafa00fa +.long 0x40404000, 0x00808080, 0x20002020, 0x07070007 +.long 0x28282800, 0x00505050, 0x14001414, 0x55550055 +.long 0xd3d3d300, 0x00a7a7a7, 0xe900e9e9, 0xeeee00ee +.long 0x7b7b7b00, 0x00f6f6f6, 0xbd00bdbd, 0x0a0a000a +.long 0xbbbbbb00, 0x00777777, 0xdd00dddd, 0x49490049 +.long 0xc9c9c900, 0x00939393, 0xe400e4e4, 0x68680068 +.long 0x43434300, 0x00868686, 0xa100a1a1, 0x38380038 +.long 0xc1c1c100, 0x00838383, 0xe000e0e0, 0xa4a400a4 +.long 0x15151500, 0x002a2a2a, 0x8a008a8a, 0x28280028 +.long 0xe3e3e300, 0x00c7c7c7, 0xf100f1f1, 0x7b7b007b +.long 0xadadad00, 0x005b5b5b, 0xd600d6d6, 0xc9c900c9 +.long 0xf4f4f400, 0x00e9e9e9, 0x7a007a7a, 0xc1c100c1 +.long 0x77777700, 0x00eeeeee, 0xbb00bbbb, 0xe3e300e3 +.long 0xc7c7c700, 0x008f8f8f, 0xe300e3e3, 0xf4f400f4 +.long 0x80808000, 0x00010101, 0x40004040, 0xc7c700c7 +.long 0x9e9e9e00, 0x003d3d3d, 0x4f004f4f, 0x9e9e009e + +#endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/ +#endif /*__ARM_ARCH >= 6*/ diff --git a/comm/third_party/libgcrypt/cipher/camellia-glue.c b/comm/third_party/libgcrypt/cipher/camellia-glue.c new file mode 100644 index 0000000000..6577b6516a --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia-glue.c @@ -0,0 +1,1097 @@ +/* camellia-glue.c - Glue for the Camellia cipher + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* I put all the libgcrypt-specific stuff in this file to keep the + camellia.c/camellia.h files exactly as provided by NTT. If they + update their code, this should make it easier to bring the changes + in. - dshaw + + There is one small change which needs to be done: Include the + following code at the top of camellia.h: */ +#if 0 + +/* To use Camellia with libraries it is often useful to keep the name + * space of the library clean. The following macro is thus useful: + * + * #define CAMELLIA_EXT_SYM_PREFIX foo_ + * + * This prefixes all external symbols with "foo_". + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef CAMELLIA_EXT_SYM_PREFIX +#define CAMELLIA_PREFIX1(x,y) x ## y +#define CAMELLIA_PREFIX2(x,y) CAMELLIA_PREFIX1(x,y) +#define CAMELLIA_PREFIX(x) CAMELLIA_PREFIX2(CAMELLIA_EXT_SYM_PREFIX,x) +#define Camellia_Ekeygen CAMELLIA_PREFIX(Camellia_Ekeygen) +#define Camellia_EncryptBlock CAMELLIA_PREFIX(Camellia_EncryptBlock) +#define Camellia_DecryptBlock CAMELLIA_PREFIX(Camellia_DecryptBlock) +#define camellia_decrypt128 CAMELLIA_PREFIX(camellia_decrypt128) +#define camellia_decrypt256 CAMELLIA_PREFIX(camellia_decrypt256) +#define camellia_encrypt128 CAMELLIA_PREFIX(camellia_encrypt128) +#define camellia_encrypt256 CAMELLIA_PREFIX(camellia_encrypt256) +#define camellia_setup128 CAMELLIA_PREFIX(camellia_setup128) +#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) +#define camellia_setup256 CAMELLIA_PREFIX(camellia_setup256) +#endif /*CAMELLIA_EXT_SYM_PREFIX*/ + +#endif /* Code sample. */ + + +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "camellia.h" +#include "bufhelp.h" +#include "cipher-internal.h" +#include "cipher-selftest.h" + +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + +/* USE_AESNI inidicates whether to compile with Intel AES-NI/AVX code. */ +#undef USE_AESNI_AVX +#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT) +# if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AESNI_AVX 1 +# endif +#endif + +/* USE_AESNI_AVX2 inidicates whether to compile with Intel AES-NI/AVX2 code. */ +#undef USE_AESNI_AVX2 +#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT) +# if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AESNI_AVX2 1 +# endif +#endif + +typedef struct +{ + KEY_TABLE_TYPE keytable; + int keybitlength; +#ifdef USE_AESNI_AVX + unsigned int use_aesni_avx:1; /* AES-NI/AVX implementation shall be used. */ +#endif /*USE_AESNI_AVX*/ +#ifdef USE_AESNI_AVX2 + unsigned int use_aesni_avx2:1;/* AES-NI/AVX2 implementation shall be used. */ +#endif /*USE_AESNI_AVX2*/ +} CAMELLIA_context; + +/* Assembly implementations use SystemV ABI, ABI conversion and additional + * stack to store XMM6-XMM15 needed on Win64. */ +#undef ASM_FUNC_ABI +#undef ASM_EXTRA_STACK +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) +# ifdef HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS +# define ASM_FUNC_ABI __attribute__((sysv_abi)) +# define ASM_EXTRA_STACK (10 * 16) +# else +# define ASM_FUNC_ABI +# define ASM_EXTRA_STACK 0 +# endif +#endif + +#ifdef USE_AESNI_AVX +/* Assembler implementations of Camellia using AES-NI and AVX. Process data + in 16 block same time. + */ +extern void _gcry_camellia_aesni_avx_ctr_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_cbc_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_cfb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_ocb_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[16]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_ocb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[16]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_ocb_auth(CAMELLIA_context *ctx, + const unsigned char *abuf, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[16]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx_keygen(CAMELLIA_context *ctx, + const unsigned char *key, + unsigned int keylen) ASM_FUNC_ABI; +#endif + +#ifdef USE_AESNI_AVX2 +/* Assembler implementations of Camellia using AES-NI and AVX2. Process data + in 32 block same time. + */ +extern void _gcry_camellia_aesni_avx2_ctr_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_cbc_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_cfb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_ocb_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[32]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_ocb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[32]) ASM_FUNC_ABI; + +extern void _gcry_camellia_aesni_avx2_ocb_auth(CAMELLIA_context *ctx, + const unsigned char *abuf, + unsigned char *offset, + unsigned char *checksum, + const u64 Ls[32]) ASM_FUNC_ABI; +#endif + +static const char *selftest(void); + +static void _gcry_camellia_ctr_enc (void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); +static void _gcry_camellia_cbc_dec (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); +static void _gcry_camellia_cfb_dec (void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); +static size_t _gcry_camellia_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, + int encrypt); +static size_t _gcry_camellia_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks); + +static gcry_err_code_t +camellia_setkey(void *c, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops) +{ + CAMELLIA_context *ctx=c; + static int initialized=0; + static const char *selftest_failed=NULL; +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + unsigned int hwf = _gcry_get_hw_features (); +#endif + + if(keylen!=16 && keylen!=24 && keylen!=32) + return GPG_ERR_INV_KEYLEN; + + if(!initialized) + { + initialized=1; + selftest_failed=selftest(); + if(selftest_failed) + log_error("%s\n",selftest_failed); + } + + if(selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + +#ifdef USE_AESNI_AVX + ctx->use_aesni_avx = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX); +#endif +#ifdef USE_AESNI_AVX2 + ctx->use_aesni_avx2 = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX2); +#endif + + ctx->keybitlength=keylen*8; + + /* Setup bulk encryption routines. */ + memset (bulk_ops, 0, sizeof(*bulk_ops)); + bulk_ops->cbc_dec = _gcry_camellia_cbc_dec; + bulk_ops->cfb_dec = _gcry_camellia_cfb_dec; + bulk_ops->ctr_enc = _gcry_camellia_ctr_enc; + bulk_ops->ocb_crypt = _gcry_camellia_ocb_crypt; + bulk_ops->ocb_auth = _gcry_camellia_ocb_auth; + + if (0) + { } +#ifdef USE_AESNI_AVX + else if (ctx->use_aesni_avx) + _gcry_camellia_aesni_avx_keygen(ctx, key, keylen); + else +#endif + { + Camellia_Ekeygen(ctx->keybitlength,key,ctx->keytable); + _gcry_burn_stack + ((19+34+34)*sizeof(u32)+2*sizeof(void*) /* camellia_setup256 */ + +(4+32)*sizeof(u32)+2*sizeof(void*) /* camellia_setup192 */ + +0+sizeof(int)+2*sizeof(void*) /* Camellia_Ekeygen */ + +3*2*sizeof(void*) /* Function calls. */ + ); + } + + return 0; +} + +#ifdef USE_ARM_ASM + +/* Assembly implementations of Camellia. */ +extern void _gcry_camellia_arm_encrypt_block(const KEY_TABLE_TYPE keyTable, + byte *outbuf, const byte *inbuf, + const int keybits); + +extern void _gcry_camellia_arm_decrypt_block(const KEY_TABLE_TYPE keyTable, + byte *outbuf, const byte *inbuf, + const int keybits); + +static void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *cipherText) +{ + _gcry_camellia_arm_encrypt_block(keyTable, cipherText, plaintext, + keyBitLength); +} + +static void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *cipherText, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext) +{ + _gcry_camellia_arm_decrypt_block(keyTable, plaintext, cipherText, + keyBitLength); +} + +#ifdef __aarch64__ +# define CAMELLIA_encrypt_stack_burn_size (0) +# define CAMELLIA_decrypt_stack_burn_size (0) +#else +# define CAMELLIA_encrypt_stack_burn_size (15*4) +# define CAMELLIA_decrypt_stack_burn_size (15*4) +#endif + +static unsigned int +camellia_encrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx = c; + Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size); +} + +static unsigned int +camellia_decrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size); +} + +#else /*USE_ARM_ASM*/ + +static unsigned int +camellia_encrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + + Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + +#define CAMELLIA_encrypt_stack_burn_size \ + (sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \ + +4*sizeof(u32)+4*sizeof(u32) \ + +2*sizeof(u32*)+4*sizeof(u32) \ + +2*2*sizeof(void*) /* Function calls. */ \ + ) + + return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size); +} + +static unsigned int +camellia_decrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + + Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); + +#define CAMELLIA_decrypt_stack_burn_size \ + (sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \ + +4*sizeof(u32)+4*sizeof(u32) \ + +2*sizeof(u32*)+4*sizeof(u32) \ + +2*2*sizeof(void*) /* Function calls. */ \ + ) + + return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size); +} + +#endif /*!USE_ARM_ASM*/ + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size CAMELLIA_BLOCK_SIZE. */ +static void +_gcry_camellia_ctr_enc(void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[CAMELLIA_BLOCK_SIZE]; + int burn_stack_depth = CAMELLIA_encrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + cipher_block_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + /* Increment the counter. */ + cipher_block_add(ctr, 1, CAMELLIA_BLOCK_SIZE); + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_camellia_cbc_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[CAMELLIA_BLOCK_SIZE]; + int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *) + ASM_EXTRA_STACK;; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf); + + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, + CAMELLIA_BLOCK_SIZE); + inbuf += CAMELLIA_BLOCK_SIZE; + outbuf += CAMELLIA_BLOCK_SIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_camellia_cfb_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv); + cipher_block_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk encryption/decryption of complete blocks in OCB mode. */ +static size_t +_gcry_camellia_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt) +{ +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + CAMELLIA_context *ctx = (void *)&c->context.c; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth; + u64 blkn = c->u_mode.ocb.data_nblocks; + + burn_stack_depth = encrypt ? CAMELLIA_encrypt_stack_burn_size : + CAMELLIA_decrypt_stack_burn_size; +#else + (void)c; + (void)outbuf_arg; + (void)inbuf_arg; + (void)encrypt; +#endif + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + u64 Ls[32]; + unsigned int n = 32 - (blkn % 32); + u64 *l; + int i; + + if (nblocks >= 32) + { + for (i = 0; i < 32; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + Ls[(15 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[4]; + Ls[(23 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(31 + n) % 32]; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + blkn += 32; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 32); + + if (encrypt) + _gcry_camellia_aesni_avx2_ocb_enc(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + else + _gcry_camellia_aesni_avx2_ocb_dec(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + u64 Ls[16]; + unsigned int n = 16 - (blkn % 16); + u64 *l; + int i; + + if (nblocks >= 16) + { + for (i = 0; i < 16; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(15 + n) % 16]; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + blkn += 16; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 16); + + if (encrypt) + _gcry_camellia_aesni_avx_ocb_enc(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + else + _gcry_camellia_aesni_avx_ocb_dec(ctx, outbuf, inbuf, c->u_iv.iv, + c->u_ctr.ctr, Ls); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + c->u_mode.ocb.data_nblocks = blkn; + + if (burn_stack_depth) + _gcry_burn_stack (burn_stack_depth + 4 * sizeof(void *)); +#endif + + return nblocks; +} + +/* Bulk authentication of complete blocks in OCB mode. */ +static size_t +_gcry_camellia_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks) +{ +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + CAMELLIA_context *ctx = (void *)&c->context.c; + const unsigned char *abuf = abuf_arg; + int burn_stack_depth; + u64 blkn = c->u_mode.ocb.aad_nblocks; + + burn_stack_depth = CAMELLIA_encrypt_stack_burn_size; +#else + (void)c; + (void)abuf_arg; +#endif + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + u64 Ls[32]; + unsigned int n = 32 - (blkn % 32); + u64 *l; + int i; + + if (nblocks >= 32) + { + for (i = 0; i < 32; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + Ls[(15 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[4]; + Ls[(23 + n) % 32] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(31 + n) % 32]; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + blkn += 32; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 32); + + _gcry_camellia_aesni_avx2_ocb_auth(ctx, abuf, + c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_sum, Ls); + + nblocks -= 32; + abuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + u64 Ls[16]; + unsigned int n = 16 - (blkn % 16); + u64 *l; + int i; + + if (nblocks >= 16) + { + for (i = 0; i < 16; i += 8) + { + /* Use u64 to store pointers for x32 support (assembly function + * assumes 64-bit pointers). */ + Ls[(i + 0 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 1 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 2 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 3 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[2]; + Ls[(i + 4 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + Ls[(i + 5 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[1]; + Ls[(i + 6 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[0]; + } + + Ls[(7 + n) % 16] = (uintptr_t)(void *)c->u_mode.ocb.L[3]; + l = &Ls[(15 + n) % 16]; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + blkn += 16; + *l = (uintptr_t)(void *)ocb_get_l(c, blkn - blkn % 16); + + _gcry_camellia_aesni_avx_ocb_auth(ctx, abuf, + c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_sum, Ls); + + nblocks -= 16; + abuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + } + + if (did_use_aesni_avx) + { + int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + + 2 * sizeof(void *) + ASM_EXTRA_STACK; + + if (burn_stack_depth < avx_burn_stack_depth) + burn_stack_depth = avx_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + c->u_mode.ocb.aad_nblocks = blkn; + + if (burn_stack_depth) + _gcry_burn_stack (burn_stack_depth + 4 * sizeof(void *)); +#endif + + return nblocks; +} + +/* Run the self-tests for CAMELLIA-CTR-128, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char* +selftest_ctr_128 (void) +{ + const int nblocks = 32+16+1; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_ctr("CAMELLIA", &camellia_setkey, + &camellia_encrypt, nblocks, blocksize, context_size); +} + +/* Run the self-tests for CAMELLIA-CBC-128, tests bulk CBC decryption. + Returns NULL on success. */ +static const char* +selftest_cbc_128 (void) +{ + const int nblocks = 32+16+2; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_cbc("CAMELLIA", &camellia_setkey, + &camellia_encrypt, nblocks, blocksize, context_size); +} + +/* Run the self-tests for CAMELLIA-CFB-128, tests bulk CFB decryption. + Returns NULL on success. */ +static const char* +selftest_cfb_128 (void) +{ + const int nblocks = 32+16+2; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_cfb("CAMELLIA", &camellia_setkey, + &camellia_encrypt, nblocks, blocksize, context_size); +} + +static const char * +selftest(void) +{ + CAMELLIA_context ctx; + byte scratch[16]; + cipher_bulk_ops_t bulk_ops; + const char *r; + + /* These test vectors are from RFC-3713 */ + static const byte plaintext[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 + }; + static const byte key_128[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 + }; + static const byte ciphertext_128[]= + { + 0x67,0x67,0x31,0x38,0x54,0x96,0x69,0x73, + 0x08,0x57,0x06,0x56,0x48,0xea,0xbe,0x43 + }; + static const byte key_192[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98, + 0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77 + }; + static const byte ciphertext_192[]= + { + 0xb4,0x99,0x34,0x01,0xb3,0xe9,0x96,0xf8, + 0x4e,0xe5,0xce,0xe7,0xd7,0x9b,0x09,0xb9 + }; + static const byte key_256[]= + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba, + 0x98,0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55, + 0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff + }; + static const byte ciphertext_256[]= + { + 0x9a,0xcc,0x23,0x7d,0xff,0x16,0xd7,0x6c, + 0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09 + }; + + camellia_setkey(&ctx,key_128,sizeof(key_128),&bulk_ops); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_128,sizeof(ciphertext_128))!=0) + return "CAMELLIA-128 test encryption failed."; + camellia_decrypt(&ctx,scratch,scratch); + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-128 test decryption failed."; + + camellia_setkey(&ctx,key_192,sizeof(key_192),&bulk_ops); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_192,sizeof(ciphertext_192))!=0) + return "CAMELLIA-192 test encryption failed."; + camellia_decrypt(&ctx,scratch,scratch); + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-192 test decryption failed."; + + camellia_setkey(&ctx,key_256,sizeof(key_256),&bulk_ops); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_256,sizeof(ciphertext_256))!=0) + return "CAMELLIA-256 test encryption failed."; + camellia_decrypt(&ctx,scratch,scratch); + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-256 test decryption failed."; + + if ( (r = selftest_ctr_128 ()) ) + return r; + + if ( (r = selftest_cbc_128 ()) ) + return r; + + if ( (r = selftest_cfb_128 ()) ) + return r; + + return NULL; +} + +/* These oids are from + , + retrieved May 1, 2007. */ + +static gcry_cipher_oid_spec_t camellia128_oids[] = + { + {"1.2.392.200011.61.1.1.1.2", GCRY_CIPHER_MODE_CBC}, + {"0.3.4401.5.3.1.9.1", GCRY_CIPHER_MODE_ECB}, + {"0.3.4401.5.3.1.9.3", GCRY_CIPHER_MODE_OFB}, + {"0.3.4401.5.3.1.9.4", GCRY_CIPHER_MODE_CFB}, + { NULL } + }; + +static gcry_cipher_oid_spec_t camellia192_oids[] = + { + {"1.2.392.200011.61.1.1.1.3", GCRY_CIPHER_MODE_CBC}, + {"0.3.4401.5.3.1.9.21", GCRY_CIPHER_MODE_ECB}, + {"0.3.4401.5.3.1.9.23", GCRY_CIPHER_MODE_OFB}, + {"0.3.4401.5.3.1.9.24", GCRY_CIPHER_MODE_CFB}, + { NULL } + }; + +static gcry_cipher_oid_spec_t camellia256_oids[] = + { + {"1.2.392.200011.61.1.1.1.4", GCRY_CIPHER_MODE_CBC}, + {"0.3.4401.5.3.1.9.41", GCRY_CIPHER_MODE_ECB}, + {"0.3.4401.5.3.1.9.43", GCRY_CIPHER_MODE_OFB}, + {"0.3.4401.5.3.1.9.44", GCRY_CIPHER_MODE_CFB}, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_camellia128 = + { + GCRY_CIPHER_CAMELLIA128, {0, 0}, + "CAMELLIA128",NULL,camellia128_oids,CAMELLIA_BLOCK_SIZE,128, + sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt + }; + +gcry_cipher_spec_t _gcry_cipher_spec_camellia192 = + { + GCRY_CIPHER_CAMELLIA192, {0, 0}, + "CAMELLIA192",NULL,camellia192_oids,CAMELLIA_BLOCK_SIZE,192, + sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt + }; + +gcry_cipher_spec_t _gcry_cipher_spec_camellia256 = + { + GCRY_CIPHER_CAMELLIA256, {0, 0}, + "CAMELLIA256",NULL,camellia256_oids,CAMELLIA_BLOCK_SIZE,256, + sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt + }; diff --git a/comm/third_party/libgcrypt/cipher/camellia.c b/comm/third_party/libgcrypt/cipher/camellia.c new file mode 100644 index 0000000000..e7085a7ec8 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia.c @@ -0,0 +1,1413 @@ +/* camellia.h ver 1.2.0 + * + * Copyright (C) 2006,2007 + * NTT (Nippon Telegraph and Telephone Corporation). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* + * Algorithm Specification + * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html + */ + +#include +#include +#include + +#include "types.h" +#include "bufhelp.h" +#include "camellia.h" + +typedef byte u8; + +/* key constants */ + +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +/* + * macros + */ + + +#if defined(_MSC_VER) + +# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +# define GETU32(p) SWAP(*((u32 *)(p))) +# define PUTU32(ct, st) {*((u32 *)(ct)) = SWAP((st));} + +#else /* not MS-VC */ + +# define GETU32(pt) buf_get_be32(pt) +# define PUTU32(ct, st) buf_put_be32(ct, st) + +#endif + +#define CamelliaSubkeyL(INDEX) (subkey[(INDEX)*2]) +#define CamelliaSubkeyR(INDEX) (subkey[(INDEX)*2 + 1]) + +/* rotation right shift 1byte */ +#define CAMELLIA_RR8(x) (((x) >> 8) + ((x) << 24)) +/* rotation left shift 1bit */ +#define CAMELLIA_RL1(x) (((x) << 1) + ((x) >> 31)) +/* rotation left shift 1byte */ +#define CAMELLIA_RL8(x) (((x) << 8) + ((x) >> 24)) + +#define CAMELLIA_ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + ll = (ll << bits) + (lr >> (32 - bits)); \ + lr = (lr << bits) + (rl >> (32 - bits)); \ + rl = (rl << bits) + (rr >> (32 - bits)); \ + rr = (rr << bits) + (w0 >> (32 - bits)); \ + } while(0) + +#define CAMELLIA_ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ + do { \ + w0 = ll; \ + w1 = lr; \ + ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ + lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ + rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ + rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ + } while(0) + +#define CAMELLIA_SP1110(INDEX) (camellia_sp1110[(INDEX)]) +#define CAMELLIA_SP0222(INDEX) (camellia_sp0222[(INDEX)]) +#define CAMELLIA_SP3033(INDEX) (camellia_sp3033[(INDEX)]) +#define CAMELLIA_SP4404(INDEX) (camellia_sp4404[(INDEX)]) + +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + il = xl ^ kl; \ + ir = xr ^ kr; \ + t0 = il >> 16; \ + t1 = ir >> 16; \ + yl = CAMELLIA_SP1110(ir & 0xff) \ + ^ CAMELLIA_SP0222((t1 >> 8) & 0xff) \ + ^ CAMELLIA_SP3033(t1 & 0xff) \ + ^ CAMELLIA_SP4404((ir >> 8) & 0xff); \ + yr = CAMELLIA_SP1110((t0 >> 8) & 0xff) \ + ^ CAMELLIA_SP0222(t0 & 0xff) \ + ^ CAMELLIA_SP3033((il >> 8) & 0xff) \ + ^ CAMELLIA_SP4404(il & 0xff); \ + yl ^= yr; \ + yr = CAMELLIA_RR8(yr); \ + yr ^= yl; \ + } while(0) + + +/* + * for speed up + * + */ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ + do { \ + t0 = kll; \ + t0 &= ll; \ + lr ^= CAMELLIA_RL1(t0); \ + t1 = klr; \ + t1 |= lr; \ + ll ^= t1; \ + \ + t2 = krr; \ + t2 |= rr; \ + rl ^= t2; \ + t3 = krl; \ + t3 &= rl; \ + rr ^= CAMELLIA_RL1(t3); \ + } while(0) + +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ + yl ^= kl; \ + yr ^= kr; \ + ir = CAMELLIA_SP1110(xr & 0xff) \ + ^ CAMELLIA_SP0222((xr >> 24) & 0xff) \ + ^ CAMELLIA_SP3033((xr >> 16) & 0xff) \ + ^ CAMELLIA_SP4404((xr >> 8) & 0xff); \ + il = CAMELLIA_SP1110((xl >> 24) & 0xff) \ + ^ CAMELLIA_SP0222((xl >> 16) & 0xff) \ + ^ CAMELLIA_SP3033((xl >> 8) & 0xff) \ + ^ CAMELLIA_SP4404(xl & 0xff); \ + ir ^= il; \ + il = CAMELLIA_RR8(il); \ + il ^= ir; \ + yl ^= ir; \ + yr ^= il; \ + } while(0) + + +static const u32 camellia_sp1110[256] = { + 0x70707000,0x82828200,0x2c2c2c00,0xececec00, + 0xb3b3b300,0x27272700,0xc0c0c000,0xe5e5e500, + 0xe4e4e400,0x85858500,0x57575700,0x35353500, + 0xeaeaea00,0x0c0c0c00,0xaeaeae00,0x41414100, + 0x23232300,0xefefef00,0x6b6b6b00,0x93939300, + 0x45454500,0x19191900,0xa5a5a500,0x21212100, + 0xededed00,0x0e0e0e00,0x4f4f4f00,0x4e4e4e00, + 0x1d1d1d00,0x65656500,0x92929200,0xbdbdbd00, + 0x86868600,0xb8b8b800,0xafafaf00,0x8f8f8f00, + 0x7c7c7c00,0xebebeb00,0x1f1f1f00,0xcecece00, + 0x3e3e3e00,0x30303000,0xdcdcdc00,0x5f5f5f00, + 0x5e5e5e00,0xc5c5c500,0x0b0b0b00,0x1a1a1a00, + 0xa6a6a600,0xe1e1e100,0x39393900,0xcacaca00, + 0xd5d5d500,0x47474700,0x5d5d5d00,0x3d3d3d00, + 0xd9d9d900,0x01010100,0x5a5a5a00,0xd6d6d600, + 0x51515100,0x56565600,0x6c6c6c00,0x4d4d4d00, + 0x8b8b8b00,0x0d0d0d00,0x9a9a9a00,0x66666600, + 0xfbfbfb00,0xcccccc00,0xb0b0b000,0x2d2d2d00, + 0x74747400,0x12121200,0x2b2b2b00,0x20202000, + 0xf0f0f000,0xb1b1b100,0x84848400,0x99999900, + 0xdfdfdf00,0x4c4c4c00,0xcbcbcb00,0xc2c2c200, + 0x34343400,0x7e7e7e00,0x76767600,0x05050500, + 0x6d6d6d00,0xb7b7b700,0xa9a9a900,0x31313100, + 0xd1d1d100,0x17171700,0x04040400,0xd7d7d700, + 0x14141400,0x58585800,0x3a3a3a00,0x61616100, + 0xdedede00,0x1b1b1b00,0x11111100,0x1c1c1c00, + 0x32323200,0x0f0f0f00,0x9c9c9c00,0x16161600, + 0x53535300,0x18181800,0xf2f2f200,0x22222200, + 0xfefefe00,0x44444400,0xcfcfcf00,0xb2b2b200, + 0xc3c3c300,0xb5b5b500,0x7a7a7a00,0x91919100, + 0x24242400,0x08080800,0xe8e8e800,0xa8a8a800, + 0x60606000,0xfcfcfc00,0x69696900,0x50505000, + 0xaaaaaa00,0xd0d0d000,0xa0a0a000,0x7d7d7d00, + 0xa1a1a100,0x89898900,0x62626200,0x97979700, + 0x54545400,0x5b5b5b00,0x1e1e1e00,0x95959500, + 0xe0e0e000,0xffffff00,0x64646400,0xd2d2d200, + 0x10101000,0xc4c4c400,0x00000000,0x48484800, + 0xa3a3a300,0xf7f7f700,0x75757500,0xdbdbdb00, + 0x8a8a8a00,0x03030300,0xe6e6e600,0xdadada00, + 0x09090900,0x3f3f3f00,0xdddddd00,0x94949400, + 0x87878700,0x5c5c5c00,0x83838300,0x02020200, + 0xcdcdcd00,0x4a4a4a00,0x90909000,0x33333300, + 0x73737300,0x67676700,0xf6f6f600,0xf3f3f300, + 0x9d9d9d00,0x7f7f7f00,0xbfbfbf00,0xe2e2e200, + 0x52525200,0x9b9b9b00,0xd8d8d800,0x26262600, + 0xc8c8c800,0x37373700,0xc6c6c600,0x3b3b3b00, + 0x81818100,0x96969600,0x6f6f6f00,0x4b4b4b00, + 0x13131300,0xbebebe00,0x63636300,0x2e2e2e00, + 0xe9e9e900,0x79797900,0xa7a7a700,0x8c8c8c00, + 0x9f9f9f00,0x6e6e6e00,0xbcbcbc00,0x8e8e8e00, + 0x29292900,0xf5f5f500,0xf9f9f900,0xb6b6b600, + 0x2f2f2f00,0xfdfdfd00,0xb4b4b400,0x59595900, + 0x78787800,0x98989800,0x06060600,0x6a6a6a00, + 0xe7e7e700,0x46464600,0x71717100,0xbababa00, + 0xd4d4d400,0x25252500,0xababab00,0x42424200, + 0x88888800,0xa2a2a200,0x8d8d8d00,0xfafafa00, + 0x72727200,0x07070700,0xb9b9b900,0x55555500, + 0xf8f8f800,0xeeeeee00,0xacacac00,0x0a0a0a00, + 0x36363600,0x49494900,0x2a2a2a00,0x68686800, + 0x3c3c3c00,0x38383800,0xf1f1f100,0xa4a4a400, + 0x40404000,0x28282800,0xd3d3d300,0x7b7b7b00, + 0xbbbbbb00,0xc9c9c900,0x43434300,0xc1c1c100, + 0x15151500,0xe3e3e300,0xadadad00,0xf4f4f400, + 0x77777700,0xc7c7c700,0x80808000,0x9e9e9e00, +}; + +static const u32 camellia_sp0222[256] = { + 0x00e0e0e0,0x00050505,0x00585858,0x00d9d9d9, + 0x00676767,0x004e4e4e,0x00818181,0x00cbcbcb, + 0x00c9c9c9,0x000b0b0b,0x00aeaeae,0x006a6a6a, + 0x00d5d5d5,0x00181818,0x005d5d5d,0x00828282, + 0x00464646,0x00dfdfdf,0x00d6d6d6,0x00272727, + 0x008a8a8a,0x00323232,0x004b4b4b,0x00424242, + 0x00dbdbdb,0x001c1c1c,0x009e9e9e,0x009c9c9c, + 0x003a3a3a,0x00cacaca,0x00252525,0x007b7b7b, + 0x000d0d0d,0x00717171,0x005f5f5f,0x001f1f1f, + 0x00f8f8f8,0x00d7d7d7,0x003e3e3e,0x009d9d9d, + 0x007c7c7c,0x00606060,0x00b9b9b9,0x00bebebe, + 0x00bcbcbc,0x008b8b8b,0x00161616,0x00343434, + 0x004d4d4d,0x00c3c3c3,0x00727272,0x00959595, + 0x00ababab,0x008e8e8e,0x00bababa,0x007a7a7a, + 0x00b3b3b3,0x00020202,0x00b4b4b4,0x00adadad, + 0x00a2a2a2,0x00acacac,0x00d8d8d8,0x009a9a9a, + 0x00171717,0x001a1a1a,0x00353535,0x00cccccc, + 0x00f7f7f7,0x00999999,0x00616161,0x005a5a5a, + 0x00e8e8e8,0x00242424,0x00565656,0x00404040, + 0x00e1e1e1,0x00636363,0x00090909,0x00333333, + 0x00bfbfbf,0x00989898,0x00979797,0x00858585, + 0x00686868,0x00fcfcfc,0x00ececec,0x000a0a0a, + 0x00dadada,0x006f6f6f,0x00535353,0x00626262, + 0x00a3a3a3,0x002e2e2e,0x00080808,0x00afafaf, + 0x00282828,0x00b0b0b0,0x00747474,0x00c2c2c2, + 0x00bdbdbd,0x00363636,0x00222222,0x00383838, + 0x00646464,0x001e1e1e,0x00393939,0x002c2c2c, + 0x00a6a6a6,0x00303030,0x00e5e5e5,0x00444444, + 0x00fdfdfd,0x00888888,0x009f9f9f,0x00656565, + 0x00878787,0x006b6b6b,0x00f4f4f4,0x00232323, + 0x00484848,0x00101010,0x00d1d1d1,0x00515151, + 0x00c0c0c0,0x00f9f9f9,0x00d2d2d2,0x00a0a0a0, + 0x00555555,0x00a1a1a1,0x00414141,0x00fafafa, + 0x00434343,0x00131313,0x00c4c4c4,0x002f2f2f, + 0x00a8a8a8,0x00b6b6b6,0x003c3c3c,0x002b2b2b, + 0x00c1c1c1,0x00ffffff,0x00c8c8c8,0x00a5a5a5, + 0x00202020,0x00898989,0x00000000,0x00909090, + 0x00474747,0x00efefef,0x00eaeaea,0x00b7b7b7, + 0x00151515,0x00060606,0x00cdcdcd,0x00b5b5b5, + 0x00121212,0x007e7e7e,0x00bbbbbb,0x00292929, + 0x000f0f0f,0x00b8b8b8,0x00070707,0x00040404, + 0x009b9b9b,0x00949494,0x00212121,0x00666666, + 0x00e6e6e6,0x00cecece,0x00ededed,0x00e7e7e7, + 0x003b3b3b,0x00fefefe,0x007f7f7f,0x00c5c5c5, + 0x00a4a4a4,0x00373737,0x00b1b1b1,0x004c4c4c, + 0x00919191,0x006e6e6e,0x008d8d8d,0x00767676, + 0x00030303,0x002d2d2d,0x00dedede,0x00969696, + 0x00262626,0x007d7d7d,0x00c6c6c6,0x005c5c5c, + 0x00d3d3d3,0x00f2f2f2,0x004f4f4f,0x00191919, + 0x003f3f3f,0x00dcdcdc,0x00797979,0x001d1d1d, + 0x00525252,0x00ebebeb,0x00f3f3f3,0x006d6d6d, + 0x005e5e5e,0x00fbfbfb,0x00696969,0x00b2b2b2, + 0x00f0f0f0,0x00313131,0x000c0c0c,0x00d4d4d4, + 0x00cfcfcf,0x008c8c8c,0x00e2e2e2,0x00757575, + 0x00a9a9a9,0x004a4a4a,0x00575757,0x00848484, + 0x00111111,0x00454545,0x001b1b1b,0x00f5f5f5, + 0x00e4e4e4,0x000e0e0e,0x00737373,0x00aaaaaa, + 0x00f1f1f1,0x00dddddd,0x00595959,0x00141414, + 0x006c6c6c,0x00929292,0x00545454,0x00d0d0d0, + 0x00787878,0x00707070,0x00e3e3e3,0x00494949, + 0x00808080,0x00505050,0x00a7a7a7,0x00f6f6f6, + 0x00777777,0x00939393,0x00868686,0x00838383, + 0x002a2a2a,0x00c7c7c7,0x005b5b5b,0x00e9e9e9, + 0x00eeeeee,0x008f8f8f,0x00010101,0x003d3d3d, +}; + +static const u32 camellia_sp3033[256] = { + 0x38003838,0x41004141,0x16001616,0x76007676, + 0xd900d9d9,0x93009393,0x60006060,0xf200f2f2, + 0x72007272,0xc200c2c2,0xab00abab,0x9a009a9a, + 0x75007575,0x06000606,0x57005757,0xa000a0a0, + 0x91009191,0xf700f7f7,0xb500b5b5,0xc900c9c9, + 0xa200a2a2,0x8c008c8c,0xd200d2d2,0x90009090, + 0xf600f6f6,0x07000707,0xa700a7a7,0x27002727, + 0x8e008e8e,0xb200b2b2,0x49004949,0xde00dede, + 0x43004343,0x5c005c5c,0xd700d7d7,0xc700c7c7, + 0x3e003e3e,0xf500f5f5,0x8f008f8f,0x67006767, + 0x1f001f1f,0x18001818,0x6e006e6e,0xaf00afaf, + 0x2f002f2f,0xe200e2e2,0x85008585,0x0d000d0d, + 0x53005353,0xf000f0f0,0x9c009c9c,0x65006565, + 0xea00eaea,0xa300a3a3,0xae00aeae,0x9e009e9e, + 0xec00ecec,0x80008080,0x2d002d2d,0x6b006b6b, + 0xa800a8a8,0x2b002b2b,0x36003636,0xa600a6a6, + 0xc500c5c5,0x86008686,0x4d004d4d,0x33003333, + 0xfd00fdfd,0x66006666,0x58005858,0x96009696, + 0x3a003a3a,0x09000909,0x95009595,0x10001010, + 0x78007878,0xd800d8d8,0x42004242,0xcc00cccc, + 0xef00efef,0x26002626,0xe500e5e5,0x61006161, + 0x1a001a1a,0x3f003f3f,0x3b003b3b,0x82008282, + 0xb600b6b6,0xdb00dbdb,0xd400d4d4,0x98009898, + 0xe800e8e8,0x8b008b8b,0x02000202,0xeb00ebeb, + 0x0a000a0a,0x2c002c2c,0x1d001d1d,0xb000b0b0, + 0x6f006f6f,0x8d008d8d,0x88008888,0x0e000e0e, + 0x19001919,0x87008787,0x4e004e4e,0x0b000b0b, + 0xa900a9a9,0x0c000c0c,0x79007979,0x11001111, + 0x7f007f7f,0x22002222,0xe700e7e7,0x59005959, + 0xe100e1e1,0xda00dada,0x3d003d3d,0xc800c8c8, + 0x12001212,0x04000404,0x74007474,0x54005454, + 0x30003030,0x7e007e7e,0xb400b4b4,0x28002828, + 0x55005555,0x68006868,0x50005050,0xbe00bebe, + 0xd000d0d0,0xc400c4c4,0x31003131,0xcb00cbcb, + 0x2a002a2a,0xad00adad,0x0f000f0f,0xca00caca, + 0x70007070,0xff00ffff,0x32003232,0x69006969, + 0x08000808,0x62006262,0x00000000,0x24002424, + 0xd100d1d1,0xfb00fbfb,0xba00baba,0xed00eded, + 0x45004545,0x81008181,0x73007373,0x6d006d6d, + 0x84008484,0x9f009f9f,0xee00eeee,0x4a004a4a, + 0xc300c3c3,0x2e002e2e,0xc100c1c1,0x01000101, + 0xe600e6e6,0x25002525,0x48004848,0x99009999, + 0xb900b9b9,0xb300b3b3,0x7b007b7b,0xf900f9f9, + 0xce00cece,0xbf00bfbf,0xdf00dfdf,0x71007171, + 0x29002929,0xcd00cdcd,0x6c006c6c,0x13001313, + 0x64006464,0x9b009b9b,0x63006363,0x9d009d9d, + 0xc000c0c0,0x4b004b4b,0xb700b7b7,0xa500a5a5, + 0x89008989,0x5f005f5f,0xb100b1b1,0x17001717, + 0xf400f4f4,0xbc00bcbc,0xd300d3d3,0x46004646, + 0xcf00cfcf,0x37003737,0x5e005e5e,0x47004747, + 0x94009494,0xfa00fafa,0xfc00fcfc,0x5b005b5b, + 0x97009797,0xfe00fefe,0x5a005a5a,0xac00acac, + 0x3c003c3c,0x4c004c4c,0x03000303,0x35003535, + 0xf300f3f3,0x23002323,0xb800b8b8,0x5d005d5d, + 0x6a006a6a,0x92009292,0xd500d5d5,0x21002121, + 0x44004444,0x51005151,0xc600c6c6,0x7d007d7d, + 0x39003939,0x83008383,0xdc00dcdc,0xaa00aaaa, + 0x7c007c7c,0x77007777,0x56005656,0x05000505, + 0x1b001b1b,0xa400a4a4,0x15001515,0x34003434, + 0x1e001e1e,0x1c001c1c,0xf800f8f8,0x52005252, + 0x20002020,0x14001414,0xe900e9e9,0xbd00bdbd, + 0xdd00dddd,0xe400e4e4,0xa100a1a1,0xe000e0e0, + 0x8a008a8a,0xf100f1f1,0xd600d6d6,0x7a007a7a, + 0xbb00bbbb,0xe300e3e3,0x40004040,0x4f004f4f, +}; + +static const u32 camellia_sp4404[256] = { + 0x70700070,0x2c2c002c,0xb3b300b3,0xc0c000c0, + 0xe4e400e4,0x57570057,0xeaea00ea,0xaeae00ae, + 0x23230023,0x6b6b006b,0x45450045,0xa5a500a5, + 0xeded00ed,0x4f4f004f,0x1d1d001d,0x92920092, + 0x86860086,0xafaf00af,0x7c7c007c,0x1f1f001f, + 0x3e3e003e,0xdcdc00dc,0x5e5e005e,0x0b0b000b, + 0xa6a600a6,0x39390039,0xd5d500d5,0x5d5d005d, + 0xd9d900d9,0x5a5a005a,0x51510051,0x6c6c006c, + 0x8b8b008b,0x9a9a009a,0xfbfb00fb,0xb0b000b0, + 0x74740074,0x2b2b002b,0xf0f000f0,0x84840084, + 0xdfdf00df,0xcbcb00cb,0x34340034,0x76760076, + 0x6d6d006d,0xa9a900a9,0xd1d100d1,0x04040004, + 0x14140014,0x3a3a003a,0xdede00de,0x11110011, + 0x32320032,0x9c9c009c,0x53530053,0xf2f200f2, + 0xfefe00fe,0xcfcf00cf,0xc3c300c3,0x7a7a007a, + 0x24240024,0xe8e800e8,0x60600060,0x69690069, + 0xaaaa00aa,0xa0a000a0,0xa1a100a1,0x62620062, + 0x54540054,0x1e1e001e,0xe0e000e0,0x64640064, + 0x10100010,0x00000000,0xa3a300a3,0x75750075, + 0x8a8a008a,0xe6e600e6,0x09090009,0xdddd00dd, + 0x87870087,0x83830083,0xcdcd00cd,0x90900090, + 0x73730073,0xf6f600f6,0x9d9d009d,0xbfbf00bf, + 0x52520052,0xd8d800d8,0xc8c800c8,0xc6c600c6, + 0x81810081,0x6f6f006f,0x13130013,0x63630063, + 0xe9e900e9,0xa7a700a7,0x9f9f009f,0xbcbc00bc, + 0x29290029,0xf9f900f9,0x2f2f002f,0xb4b400b4, + 0x78780078,0x06060006,0xe7e700e7,0x71710071, + 0xd4d400d4,0xabab00ab,0x88880088,0x8d8d008d, + 0x72720072,0xb9b900b9,0xf8f800f8,0xacac00ac, + 0x36360036,0x2a2a002a,0x3c3c003c,0xf1f100f1, + 0x40400040,0xd3d300d3,0xbbbb00bb,0x43430043, + 0x15150015,0xadad00ad,0x77770077,0x80800080, + 0x82820082,0xecec00ec,0x27270027,0xe5e500e5, + 0x85850085,0x35350035,0x0c0c000c,0x41410041, + 0xefef00ef,0x93930093,0x19190019,0x21210021, + 0x0e0e000e,0x4e4e004e,0x65650065,0xbdbd00bd, + 0xb8b800b8,0x8f8f008f,0xebeb00eb,0xcece00ce, + 0x30300030,0x5f5f005f,0xc5c500c5,0x1a1a001a, + 0xe1e100e1,0xcaca00ca,0x47470047,0x3d3d003d, + 0x01010001,0xd6d600d6,0x56560056,0x4d4d004d, + 0x0d0d000d,0x66660066,0xcccc00cc,0x2d2d002d, + 0x12120012,0x20200020,0xb1b100b1,0x99990099, + 0x4c4c004c,0xc2c200c2,0x7e7e007e,0x05050005, + 0xb7b700b7,0x31310031,0x17170017,0xd7d700d7, + 0x58580058,0x61610061,0x1b1b001b,0x1c1c001c, + 0x0f0f000f,0x16160016,0x18180018,0x22220022, + 0x44440044,0xb2b200b2,0xb5b500b5,0x91910091, + 0x08080008,0xa8a800a8,0xfcfc00fc,0x50500050, + 0xd0d000d0,0x7d7d007d,0x89890089,0x97970097, + 0x5b5b005b,0x95950095,0xffff00ff,0xd2d200d2, + 0xc4c400c4,0x48480048,0xf7f700f7,0xdbdb00db, + 0x03030003,0xdada00da,0x3f3f003f,0x94940094, + 0x5c5c005c,0x02020002,0x4a4a004a,0x33330033, + 0x67670067,0xf3f300f3,0x7f7f007f,0xe2e200e2, + 0x9b9b009b,0x26260026,0x37370037,0x3b3b003b, + 0x96960096,0x4b4b004b,0xbebe00be,0x2e2e002e, + 0x79790079,0x8c8c008c,0x6e6e006e,0x8e8e008e, + 0xf5f500f5,0xb6b600b6,0xfdfd00fd,0x59590059, + 0x98980098,0x6a6a006a,0x46460046,0xbaba00ba, + 0x25250025,0x42420042,0xa2a200a2,0xfafa00fa, + 0x07070007,0x55550055,0xeeee00ee,0x0a0a000a, + 0x49490049,0x68680068,0x38380038,0xa4a400a4, + 0x28280028,0x7b7b007b,0xc9c900c9,0xc1c100c1, + 0xe3e300e3,0xf4f400f4,0xc7c700c7,0x9e9e009e, +}; + + +/** + * Stuff related to the Camellia key schedule + */ +#define subl(x) subL[(x)] +#define subr(x) subR[(x)] + +void camellia_setup128(const unsigned char *key, u32 *subkey) +{ + u32 kll, klr, krl, krr; + u32 il, ir, t0, t1, w0, w1; + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[26]; + u32 subR[26]; + + /** + * k == kll || klr || krl || krr (|| is concatination) + */ + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + /** + * generate KL dependent subkeys + */ + subl(0) = kll; subr(0) = klr; + subl(1) = krl; subr(1) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(4) = kll; subr(4) = klr; + subl(5) = krl; subr(5) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + subl(10) = kll; subr(10) = klr; + subl(11) = krl; subr(11) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(13) = krl; subr(13) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(16) = kll; subr(16) = klr; + subl(17) = krl; subr(17) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(18) = kll; subr(18) = klr; + subl(19) = krl; subr(19) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(22) = kll; subr(22) = klr; + subl(23) = krl; subr(23) = krr; + + /* generate KA */ + kll = subl(0); klr = subr(0); + krl = subl(1); krr = subr(1); + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KA dependent subkeys */ + subl(2) = kll; subr(2) = klr; + subl(3) = krl; subr(3) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(6) = kll; subr(6) = klr; + subl(7) = krl; subr(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(8) = kll; subr(8) = klr; + subl(9) = krl; subr(9) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(12) = kll; subr(12) = klr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(14) = kll; subr(14) = klr; + subl(15) = krl; subr(15) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + subl(20) = kll; subr(20) = klr; + subl(21) = krl; subr(21) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(24) = kll; subr(24) = klr; + subl(25) = krl; subr(25) = krr; + + + /* absorb kw2 to other subkeys */ + subl(3) ^= subl(1); subr(3) ^= subr(1); + subl(5) ^= subl(1); subr(5) ^= subr(1); + subl(7) ^= subl(1); subr(7) ^= subr(1); + subl(1) ^= subr(1) & ~subr(9); + dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw); + subl(11) ^= subl(1); subr(11) ^= subr(1); + subl(13) ^= subl(1); subr(13) ^= subr(1); + subl(15) ^= subl(1); subr(15) ^= subr(1); + subl(1) ^= subr(1) & ~subr(17); + dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw); + subl(19) ^= subl(1); subr(19) ^= subr(1); + subl(21) ^= subl(1); subr(21) ^= subr(1); + subl(23) ^= subl(1); subr(23) ^= subr(1); + subl(24) ^= subl(1); subr(24) ^= subr(1); + + /* absorb kw4 to other subkeys */ + kw4l = subl(25); kw4r = subr(25); + subl(22) ^= kw4l; subr(22) ^= kw4r; + subl(20) ^= kw4l; subr(20) ^= kw4r; + subl(18) ^= kw4l; subr(18) ^= kw4r; + kw4l ^= kw4r & ~subr(16); + dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw); + subl(14) ^= kw4l; subr(14) ^= kw4r; + subl(12) ^= kw4l; subr(12) ^= kw4r; + subl(10) ^= kw4l; subr(10) ^= kw4r; + kw4l ^= kw4r & ~subr(8); + dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw); + subl(6) ^= kw4l; subr(6) ^= kw4r; + subl(4) ^= kw4l; subr(4) ^= kw4r; + subl(2) ^= kw4l; subr(2) ^= kw4r; + subl(0) ^= kw4l; subr(0) ^= kw4r; + + /* key XOR is end of F-function */ + CamelliaSubkeyL(0) = subl(0) ^ subl(2); + CamelliaSubkeyR(0) = subr(0) ^ subr(2); + CamelliaSubkeyL(2) = subl(3); + CamelliaSubkeyR(2) = subr(3); + CamelliaSubkeyL(3) = subl(2) ^ subl(4); + CamelliaSubkeyR(3) = subr(2) ^ subr(4); + CamelliaSubkeyL(4) = subl(3) ^ subl(5); + CamelliaSubkeyR(4) = subr(3) ^ subr(5); + CamelliaSubkeyL(5) = subl(4) ^ subl(6); + CamelliaSubkeyR(5) = subr(4) ^ subr(6); + CamelliaSubkeyL(6) = subl(5) ^ subl(7); + CamelliaSubkeyR(6) = subr(5) ^ subr(7); + tl = subl(10) ^ (subr(10) & ~subr(8)); + dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(7) = subl(6) ^ tl; + CamelliaSubkeyR(7) = subr(6) ^ tr; + CamelliaSubkeyL(8) = subl(8); + CamelliaSubkeyR(8) = subr(8); + CamelliaSubkeyL(9) = subl(9); + CamelliaSubkeyR(9) = subr(9); + tl = subl(7) ^ (subr(7) & ~subr(9)); + dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(10) = tl ^ subl(11); + CamelliaSubkeyR(10) = tr ^ subr(11); + CamelliaSubkeyL(11) = subl(10) ^ subl(12); + CamelliaSubkeyR(11) = subr(10) ^ subr(12); + CamelliaSubkeyL(12) = subl(11) ^ subl(13); + CamelliaSubkeyR(12) = subr(11) ^ subr(13); + CamelliaSubkeyL(13) = subl(12) ^ subl(14); + CamelliaSubkeyR(13) = subr(12) ^ subr(14); + CamelliaSubkeyL(14) = subl(13) ^ subl(15); + CamelliaSubkeyR(14) = subr(13) ^ subr(15); + tl = subl(18) ^ (subr(18) & ~subr(16)); + dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(15) = subl(14) ^ tl; + CamelliaSubkeyR(15) = subr(14) ^ tr; + CamelliaSubkeyL(16) = subl(16); + CamelliaSubkeyR(16) = subr(16); + CamelliaSubkeyL(17) = subl(17); + CamelliaSubkeyR(17) = subr(17); + tl = subl(15) ^ (subr(15) & ~subr(17)); + dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(18) = tl ^ subl(19); + CamelliaSubkeyR(18) = tr ^ subr(19); + CamelliaSubkeyL(19) = subl(18) ^ subl(20); + CamelliaSubkeyR(19) = subr(18) ^ subr(20); + CamelliaSubkeyL(20) = subl(19) ^ subl(21); + CamelliaSubkeyR(20) = subr(19) ^ subr(21); + CamelliaSubkeyL(21) = subl(20) ^ subl(22); + CamelliaSubkeyR(21) = subr(20) ^ subr(22); + CamelliaSubkeyL(22) = subl(21) ^ subl(23); + CamelliaSubkeyR(22) = subr(21) ^ subr(23); + CamelliaSubkeyL(23) = subl(22); + CamelliaSubkeyR(23) = subr(22); + CamelliaSubkeyL(24) = subl(24) ^ subl(23); + CamelliaSubkeyR(24) = subr(24) ^ subr(23); + + return; +} + +void camellia_setup256(const unsigned char *key, u32 *subkey) +{ + u32 kll,klr,krl,krr; /* left half of key */ + u32 krll,krlr,krrl,krrr; /* right half of key */ + u32 il, ir, t0, t1, w0, w1; /* temporary variables */ + u32 kw4l, kw4r, dw, tl, tr; + u32 subL[34]; + u32 subR[34]; + + /** + * key = (kll || klr || krl || krr || krll || krlr || krrl || krrr) + * (|| is concatination) + */ + + kll = GETU32(key ); + klr = GETU32(key + 4); + krl = GETU32(key + 8); + krr = GETU32(key + 12); + krll = GETU32(key + 16); + krlr = GETU32(key + 20); + krrl = GETU32(key + 24); + krrr = GETU32(key + 28); + + /* generate KL dependent subkeys */ + subl(0) = kll; subr(0) = klr; + subl(1) = krl; subr(1) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 45); + subl(12) = kll; subr(12) = klr; + subl(13) = krl; subr(13) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(16) = kll; subr(16) = klr; + subl(17) = krl; subr(17) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 17); + subl(22) = kll; subr(22) = klr; + subl(23) = krl; subr(23) = krr; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 34); + subl(30) = kll; subr(30) = klr; + subl(31) = krl; subr(31) = krr; + + /* generate KR dependent subkeys */ + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + subl(4) = krll; subr(4) = krlr; + subl(5) = krrl; subr(5) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15); + subl(8) = krll; subr(8) = krlr; + subl(9) = krrl; subr(9) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subl(18) = krll; subr(18) = krlr; + subl(19) = krrl; subr(19) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + subl(26) = krll; subr(26) = krlr; + subl(27) = krrl; subr(27) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34); + + /* generate KA */ + kll = subl(0) ^ krll; klr = subr(0) ^ krlr; + krl = subl(1) ^ krrl; krr = subr(1) ^ krrr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, + w0, w1, il, ir, t0, t1); + krl ^= w0; krr ^= w1; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, + kll, klr, il, ir, t0, t1); + kll ^= krll; klr ^= krlr; + CAMELLIA_F(kll, klr, + CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, + krl, krr, il, ir, t0, t1); + krl ^= w0 ^ krrl; krr ^= w1 ^ krrr; + CAMELLIA_F(krl, krr, + CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, + w0, w1, il, ir, t0, t1); + kll ^= w0; klr ^= w1; + + /* generate KB */ + krll ^= kll; krlr ^= klr; + krrl ^= krl; krrr ^= krr; + CAMELLIA_F(krll, krlr, + CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, + w0, w1, il, ir, t0, t1); + krrl ^= w0; krrr ^= w1; + CAMELLIA_F(krrl, krrr, + CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, + w0, w1, il, ir, t0, t1); + krll ^= w0; krlr ^= w1; + + /* generate KA dependent subkeys */ + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 15); + subl(6) = kll; subr(6) = klr; + subl(7) = krl; subr(7) = krr; + CAMELLIA_ROLDQ(kll, klr, krl, krr, w0, w1, 30); + subl(14) = kll; subr(14) = klr; + subl(15) = krl; subr(15) = krr; + subl(24) = klr; subr(24) = krl; + subl(25) = krr; subr(25) = kll; + CAMELLIA_ROLDQo32(kll, klr, krl, krr, w0, w1, 49); + subl(28) = kll; subr(28) = klr; + subl(29) = krl; subr(29) = krr; + + /* generate KB dependent subkeys */ + subl(2) = krll; subr(2) = krlr; + subl(3) = krrl; subr(3) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subl(10) = krll; subr(10) = krlr; + subl(11) = krrl; subr(11) = krrr; + CAMELLIA_ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30); + subl(20) = krll; subr(20) = krlr; + subl(21) = krrl; subr(21) = krrr; + CAMELLIA_ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51); + subl(32) = krll; subr(32) = krlr; + subl(33) = krrl; subr(33) = krrr; + + /* absorb kw2 to other subkeys */ + subl(3) ^= subl(1); subr(3) ^= subr(1); + subl(5) ^= subl(1); subr(5) ^= subr(1); + subl(7) ^= subl(1); subr(7) ^= subr(1); + subl(1) ^= subr(1) & ~subr(9); + dw = subl(1) & subl(9), subr(1) ^= CAMELLIA_RL1(dw); + subl(11) ^= subl(1); subr(11) ^= subr(1); + subl(13) ^= subl(1); subr(13) ^= subr(1); + subl(15) ^= subl(1); subr(15) ^= subr(1); + subl(1) ^= subr(1) & ~subr(17); + dw = subl(1) & subl(17), subr(1) ^= CAMELLIA_RL1(dw); + subl(19) ^= subl(1); subr(19) ^= subr(1); + subl(21) ^= subl(1); subr(21) ^= subr(1); + subl(23) ^= subl(1); subr(23) ^= subr(1); + subl(1) ^= subr(1) & ~subr(25); + dw = subl(1) & subl(25), subr(1) ^= CAMELLIA_RL1(dw); + subl(27) ^= subl(1); subr(27) ^= subr(1); + subl(29) ^= subl(1); subr(29) ^= subr(1); + subl(31) ^= subl(1); subr(31) ^= subr(1); + subl(32) ^= subl(1); subr(32) ^= subr(1); + + /* absorb kw4 to other subkeys */ + kw4l = subl(33); kw4r = subr(33); + subl(30) ^= kw4l; subr(30) ^= kw4r; + subl(28) ^= kw4l; subr(28) ^= kw4r; + subl(26) ^= kw4l; subr(26) ^= kw4r; + kw4l ^= kw4r & ~subr(24); + dw = kw4l & subl(24), kw4r ^= CAMELLIA_RL1(dw); + subl(22) ^= kw4l; subr(22) ^= kw4r; + subl(20) ^= kw4l; subr(20) ^= kw4r; + subl(18) ^= kw4l; subr(18) ^= kw4r; + kw4l ^= kw4r & ~subr(16); + dw = kw4l & subl(16), kw4r ^= CAMELLIA_RL1(dw); + subl(14) ^= kw4l; subr(14) ^= kw4r; + subl(12) ^= kw4l; subr(12) ^= kw4r; + subl(10) ^= kw4l; subr(10) ^= kw4r; + kw4l ^= kw4r & ~subr(8); + dw = kw4l & subl(8), kw4r ^= CAMELLIA_RL1(dw); + subl(6) ^= kw4l; subr(6) ^= kw4r; + subl(4) ^= kw4l; subr(4) ^= kw4r; + subl(2) ^= kw4l; subr(2) ^= kw4r; + subl(0) ^= kw4l; subr(0) ^= kw4r; + + /* key XOR is end of F-function */ + CamelliaSubkeyL(0) = subl(0) ^ subl(2); + CamelliaSubkeyR(0) = subr(0) ^ subr(2); + CamelliaSubkeyL(2) = subl(3); + CamelliaSubkeyR(2) = subr(3); + CamelliaSubkeyL(3) = subl(2) ^ subl(4); + CamelliaSubkeyR(3) = subr(2) ^ subr(4); + CamelliaSubkeyL(4) = subl(3) ^ subl(5); + CamelliaSubkeyR(4) = subr(3) ^ subr(5); + CamelliaSubkeyL(5) = subl(4) ^ subl(6); + CamelliaSubkeyR(5) = subr(4) ^ subr(6); + CamelliaSubkeyL(6) = subl(5) ^ subl(7); + CamelliaSubkeyR(6) = subr(5) ^ subr(7); + tl = subl(10) ^ (subr(10) & ~subr(8)); + dw = tl & subl(8), tr = subr(10) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(7) = subl(6) ^ tl; + CamelliaSubkeyR(7) = subr(6) ^ tr; + CamelliaSubkeyL(8) = subl(8); + CamelliaSubkeyR(8) = subr(8); + CamelliaSubkeyL(9) = subl(9); + CamelliaSubkeyR(9) = subr(9); + tl = subl(7) ^ (subr(7) & ~subr(9)); + dw = tl & subl(9), tr = subr(7) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(10) = tl ^ subl(11); + CamelliaSubkeyR(10) = tr ^ subr(11); + CamelliaSubkeyL(11) = subl(10) ^ subl(12); + CamelliaSubkeyR(11) = subr(10) ^ subr(12); + CamelliaSubkeyL(12) = subl(11) ^ subl(13); + CamelliaSubkeyR(12) = subr(11) ^ subr(13); + CamelliaSubkeyL(13) = subl(12) ^ subl(14); + CamelliaSubkeyR(13) = subr(12) ^ subr(14); + CamelliaSubkeyL(14) = subl(13) ^ subl(15); + CamelliaSubkeyR(14) = subr(13) ^ subr(15); + tl = subl(18) ^ (subr(18) & ~subr(16)); + dw = tl & subl(16), tr = subr(18) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(15) = subl(14) ^ tl; + CamelliaSubkeyR(15) = subr(14) ^ tr; + CamelliaSubkeyL(16) = subl(16); + CamelliaSubkeyR(16) = subr(16); + CamelliaSubkeyL(17) = subl(17); + CamelliaSubkeyR(17) = subr(17); + tl = subl(15) ^ (subr(15) & ~subr(17)); + dw = tl & subl(17), tr = subr(15) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(18) = tl ^ subl(19); + CamelliaSubkeyR(18) = tr ^ subr(19); + CamelliaSubkeyL(19) = subl(18) ^ subl(20); + CamelliaSubkeyR(19) = subr(18) ^ subr(20); + CamelliaSubkeyL(20) = subl(19) ^ subl(21); + CamelliaSubkeyR(20) = subr(19) ^ subr(21); + CamelliaSubkeyL(21) = subl(20) ^ subl(22); + CamelliaSubkeyR(21) = subr(20) ^ subr(22); + CamelliaSubkeyL(22) = subl(21) ^ subl(23); + CamelliaSubkeyR(22) = subr(21) ^ subr(23); + tl = subl(26) ^ (subr(26) & ~subr(24)); + dw = tl & subl(24), tr = subr(26) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(23) = subl(22) ^ tl; + CamelliaSubkeyR(23) = subr(22) ^ tr; + CamelliaSubkeyL(24) = subl(24); + CamelliaSubkeyR(24) = subr(24); + CamelliaSubkeyL(25) = subl(25); + CamelliaSubkeyR(25) = subr(25); + tl = subl(23) ^ (subr(23) & ~subr(25)); + dw = tl & subl(25), tr = subr(23) ^ CAMELLIA_RL1(dw); + CamelliaSubkeyL(26) = tl ^ subl(27); + CamelliaSubkeyR(26) = tr ^ subr(27); + CamelliaSubkeyL(27) = subl(26) ^ subl(28); + CamelliaSubkeyR(27) = subr(26) ^ subr(28); + CamelliaSubkeyL(28) = subl(27) ^ subl(29); + CamelliaSubkeyR(28) = subr(27) ^ subr(29); + CamelliaSubkeyL(29) = subl(28) ^ subl(30); + CamelliaSubkeyR(29) = subr(28) ^ subr(30); + CamelliaSubkeyL(30) = subl(29) ^ subl(31); + CamelliaSubkeyR(30) = subr(29) ^ subr(31); + CamelliaSubkeyL(31) = subl(30); + CamelliaSubkeyR(31) = subr(30); + CamelliaSubkeyL(32) = subl(32) ^ subl(31); + CamelliaSubkeyR(32) = subr(32) ^ subr(31); + + return; +} + +void camellia_setup192(const unsigned char *key, u32 *subkey) +{ + unsigned char kk[32]; + u32 krll, krlr, krrl,krrr; + + memcpy(kk, key, 24); + memcpy((unsigned char *)&krll, key+16,4); + memcpy((unsigned char *)&krlr, key+20,4); + krrl = ~krll; + krrr = ~krlr; + memcpy(kk+24, (unsigned char *)&krrl, 4); + memcpy(kk+28, (unsigned char *)&krrr, 4); + camellia_setup256(kk, subkey); + return; +} + + +#ifndef USE_ARM_ASM +/** + * Stuff related to camellia encryption/decryption + * + * "io" must be 4byte aligned and big-endian data. + */ +void camellia_encrypt128(const u32 *subkey, u32 *blocks) +{ + u32 il, ir, t0, t1; + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(0); + io[1] ^= CamelliaSubkeyR(0); + /* main iteration */ + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(24); + io[3] ^= CamelliaSubkeyR(24); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + + return; +} + +void camellia_decrypt128(const u32 *subkey, u32 *blocks) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(24); + io[1] ^= CamelliaSubkeyR(24); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(0); + io[3] ^= CamelliaSubkeyR(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + + return; +} + +/** + * stuff for 192 and 256bit encryption/decryption + */ +void camellia_encrypt256(const u32 *subkey, u32 *blocks) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(0); + io[1] ^= CamelliaSubkeyR(0); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(24),CamelliaSubkeyR(24), + CamelliaSubkeyL(25),CamelliaSubkeyR(25), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(26),CamelliaSubkeyR(26), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(27),CamelliaSubkeyR(27), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(28),CamelliaSubkeyR(28), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(29),CamelliaSubkeyR(29), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(30),CamelliaSubkeyR(30), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(31),CamelliaSubkeyR(31), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(32); + io[3] ^= CamelliaSubkeyR(32); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + + return; +} + +void camellia_decrypt256(const u32 *subkey, u32 *blocks) +{ + u32 il,ir,t0,t1; /* temporary valiables */ + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; + + /* pre whitening but absorb kw2*/ + io[0] ^= CamelliaSubkeyL(32); + io[1] ^= CamelliaSubkeyR(32); + + /* main iteration */ + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(31),CamelliaSubkeyR(31), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(30),CamelliaSubkeyR(30), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(29),CamelliaSubkeyR(29), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(28),CamelliaSubkeyR(28), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(27),CamelliaSubkeyR(27), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(26),CamelliaSubkeyR(26), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(25),CamelliaSubkeyR(25), + CamelliaSubkeyL(24),CamelliaSubkeyR(24), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(23),CamelliaSubkeyR(23), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(22),CamelliaSubkeyR(22), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(21),CamelliaSubkeyR(21), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(20),CamelliaSubkeyR(20), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(19),CamelliaSubkeyR(19), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(18),CamelliaSubkeyR(18), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(17),CamelliaSubkeyR(17), + CamelliaSubkeyL(16),CamelliaSubkeyR(16), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(15),CamelliaSubkeyR(15), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(14),CamelliaSubkeyR(14), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(13),CamelliaSubkeyR(13), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(12),CamelliaSubkeyR(12), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(11),CamelliaSubkeyR(11), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(10),CamelliaSubkeyR(10), + io[0],io[1],il,ir,t0,t1); + + CAMELLIA_FLS(io[0],io[1],io[2],io[3], + CamelliaSubkeyL(9),CamelliaSubkeyR(9), + CamelliaSubkeyL(8),CamelliaSubkeyR(8), + t0,t1,il,ir); + + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(7),CamelliaSubkeyR(7), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(6),CamelliaSubkeyR(6), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(5),CamelliaSubkeyR(5), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(4),CamelliaSubkeyR(4), + io[0],io[1],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[0],io[1], + CamelliaSubkeyL(3),CamelliaSubkeyR(3), + io[2],io[3],il,ir,t0,t1); + CAMELLIA_ROUNDSM(io[2],io[3], + CamelliaSubkeyL(2),CamelliaSubkeyR(2), + io[0],io[1],il,ir,t0,t1); + + /* post whitening but kw4 */ + io[2] ^= CamelliaSubkeyL(0); + io[3] ^= CamelliaSubkeyR(0); + + t0 = io[0]; + t1 = io[1]; + io[0] = io[2]; + io[1] = io[3]; + io[2] = t0; + io[3] = t1; + + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + + return; +} +#endif /*!USE_ARM_ASM*/ + + +/*** + * + * API for compatibility + */ + +void Camellia_Ekeygen(const int keyBitLength, + const unsigned char *rawKey, + KEY_TABLE_TYPE keyTable) +{ + switch(keyBitLength) { + case 128: + camellia_setup128(rawKey, keyTable); + break; + case 192: + camellia_setup192(rawKey, keyTable); + break; + case 256: + camellia_setup256(rawKey, keyTable); + break; + default: + break; + } +} + + +#ifndef USE_ARM_ASM +void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *ciphertext) +{ + u32 tmp[4]; + + tmp[0] = GETU32(plaintext); + tmp[1] = GETU32(plaintext + 4); + tmp[2] = GETU32(plaintext + 8); + tmp[3] = GETU32(plaintext + 12); + + switch (keyBitLength) { + case 128: + camellia_encrypt128(keyTable, tmp); + break; + case 192: + /* fall through */ + case 256: + camellia_encrypt256(keyTable, tmp); + break; + default: + break; + } + + PUTU32(ciphertext, tmp[0]); + PUTU32(ciphertext + 4, tmp[1]); + PUTU32(ciphertext + 8, tmp[2]); + PUTU32(ciphertext + 12, tmp[3]); +} + +void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *ciphertext, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext) +{ + u32 tmp[4]; + + tmp[0] = GETU32(ciphertext); + tmp[1] = GETU32(ciphertext + 4); + tmp[2] = GETU32(ciphertext + 8); + tmp[3] = GETU32(ciphertext + 12); + + switch (keyBitLength) { + case 128: + camellia_decrypt128(keyTable, tmp); + break; + case 192: + /* fall through */ + case 256: + camellia_decrypt256(keyTable, tmp); + break; + default: + break; + } + PUTU32(plaintext, tmp[0]); + PUTU32(plaintext + 4, tmp[1]); + PUTU32(plaintext + 8, tmp[2]); + PUTU32(plaintext + 12, tmp[3]); +} +#endif /*!USE_ARM_ASM*/ diff --git a/comm/third_party/libgcrypt/cipher/camellia.h b/comm/third_party/libgcrypt/cipher/camellia.h new file mode 100644 index 0000000000..d7a1e6f4a0 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/camellia.h @@ -0,0 +1,95 @@ +/* camellia.h ver 1.2.0 + * + * Copyright (C) 2006,2007 + * NTT (Nippon Telegraph and Telephone Corporation). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef HEADER_CAMELLIA_H +#define HEADER_CAMELLIA_H + +/* To use Camellia with libraries it is often useful to keep the name + * space of the library clean. The following macro is thus useful: + * + * #define CAMELLIA_EXT_SYM_PREFIX foo_ + * + * This prefixes all external symbols with "foo_". + */ +#ifdef HAVE_CONFIG_H +#include +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +# undef USE_ARM_ASM +# if defined(__ARMEL__) +# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS +# define USE_ARM_ASM 1 +# endif +# endif +# if defined(__AARCH64EL__) +# ifdef HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS +# define USE_ARM_ASM 1 +# endif +# endif +#endif +#ifdef CAMELLIA_EXT_SYM_PREFIX +#define CAMELLIA_PREFIX1(x,y) x ## y +#define CAMELLIA_PREFIX2(x,y) CAMELLIA_PREFIX1(x,y) +#define CAMELLIA_PREFIX(x) CAMELLIA_PREFIX2(CAMELLIA_EXT_SYM_PREFIX,x) +#define Camellia_Ekeygen CAMELLIA_PREFIX(Camellia_Ekeygen) +#define Camellia_EncryptBlock CAMELLIA_PREFIX(Camellia_EncryptBlock) +#define Camellia_DecryptBlock CAMELLIA_PREFIX(Camellia_DecryptBlock) +#define camellia_decrypt128 CAMELLIA_PREFIX(camellia_decrypt128) +#define camellia_decrypt256 CAMELLIA_PREFIX(camellia_decrypt256) +#define camellia_encrypt128 CAMELLIA_PREFIX(camellia_encrypt128) +#define camellia_encrypt256 CAMELLIA_PREFIX(camellia_encrypt256) +#define camellia_setup128 CAMELLIA_PREFIX(camellia_setup128) +#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) +#define camellia_setup256 CAMELLIA_PREFIX(camellia_setup256) +#endif /*CAMELLIA_EXT_SYM_PREFIX*/ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 +#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4) + +typedef unsigned int KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; + + +void Camellia_Ekeygen(const int keyBitLength, + const unsigned char *rawKey, + KEY_TABLE_TYPE keyTable); + +#ifndef USE_ARM_ASM +void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *cipherText); + +void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *cipherText, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext); +#endif /*!USE_ARM_ASM*/ + + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_CAMELLIA_H */ diff --git a/comm/third_party/libgcrypt/cipher/cast5-amd64.S b/comm/third_party/libgcrypt/cipher/cast5-amd64.S new file mode 100644 index 0000000000..82f678901d --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cast5-amd64.S @@ -0,0 +1,663 @@ +/* cast5-amd64.S - AMD64 assembly implementation of CAST5 cipher + * + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifdef __x86_64 +#include +#if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && defined(USE_CAST5) + +#include "asm-common-amd64.h" + +.text + +.extern _gcry_cast5_s1to4; + +#define s1 0 +#define s2 (s1 + (4 * 256)) +#define s3 (s2 + (4 * 256)) +#define s4 (s3 + (4 * 256)) + +/* structure of CAST5_context: */ +#define Km 0 +#define Kr (Km + (16 * 4)) + +/* register macros */ +#define CTX %rdi +#define RIO %rsi +#define RTAB %r8 + +#define RLR0 %r9 +#define RLR1 %r10 +#define RLR2 %r11 +#define RLR3 %r12 + +#define RLR0d %r9d +#define RLR1d %r10d +#define RLR2d %r11d +#define RLR3d %r12d + +#define RX0 %rax +#define RX1 %rbx +#define RX2 %rdx + +#define RX0d %eax +#define RX1d %ebx +#define RX2d %edx + +#define RX0bl %al +#define RX1bl %bl +#define RX2bl %dl + +#define RX0bh %ah +#define RX1bh %bh +#define RX2bh %dh + +#define RKR %rcx +#define RKRd %ecx +#define RKRbl %cl + +#define RT0 %rbp +#define RT1 %rsi + +#define RT0d %ebp +#define RT1d %esi + +#define RKM0d %r13d +#define RKM1d %r14d + +/*********************************************************************** + * 1-way cast5 + ***********************************************************************/ +#define dummy(x) + +#define shr_kr(none) \ + shrq $8, RKR; + +#define F(km, load_next_kr, op0, op1, op2, op3) \ + op0 ## l RLR0d, km ## d; \ + roll RKRbl, km ## d; \ + rorq $32, RLR0; \ + movzbl km ## bh, RT0d; \ + movzbl km ## bl, RT1d; \ + roll $16, km ## d; \ + movl s1(RTAB,RT0,4), RT0d; \ + op1 ## l s2(RTAB,RT1,4), RT0d; \ + load_next_kr(kr_next); \ + movzbl km ## bh, RT1d; \ + movzbl km ## bl, km ## d; \ + op2 ## l s3(RTAB,RT1,4), RT0d; \ + op3 ## l s4(RTAB,km,4), RT0d; \ + xorq RT0, RLR0; + +#define F1(km, load_next_kr) \ + F(##km, load_next_kr, add, xor, sub, add) +#define F2(km, load_next_kr) \ + F(##km, load_next_kr, xor, sub, add, xor) +#define F3(km, load_next_kr) \ + F(##km, load_next_kr, sub, add, xor, sub) + +#define get_round_km(n, km) \ + movl Km+4*(n)(CTX), km; + +#define get_round_kr_enc(n) \ + movq $0x1010101010101010, RKR; \ + \ + /* merge rorl rk and rorl $16 */ \ + xorq Kr+(n)(CTX), RKR; + +#define get_round_kr_dec(n) \ + movq $0x1010101010101010, RKR; \ + \ + /* merge rorl rk and rorl $16 */ \ + xorq Kr+(n - 7)(CTX), RKR; \ + bswapq RKR; + +#define round_enc(n, FA, FB, fn1, fn2) \ + get_round_km(n + 1, RX2d); \ + FA(RX0, fn1); \ + get_round_km(n + 2, RX0d); \ + FB(RX2, fn2); + +#define round_enc_last(n, FXA, FXB) \ + get_round_km(n + 1, RX2d); \ + \ + FXA(RX0, shr_kr); \ + FXB(RX2, dummy); + +#define round_enc_1(n, FA, FB) \ + round_enc(n, FA, FB, shr_kr, shr_kr) + +#define round_enc_2(n, FA, FB) \ + round_enc(n, FA, FB, shr_kr, dummy) + +#define round_dec(n, FA, FB, fn1, fn2) \ + get_round_km(n - 1, RX2d); \ + FA(RX0, fn1); \ + get_round_km(n - 2, RX0d); \ + FB(RX2, fn2); + +#define round_dec_last(n, FXA, FXB) \ + get_round_km(n - 1, RX2d); \ + FXA(RX0, shr_kr); \ + FXB(RX2, dummy); + +#define round_dec_1(n, FA, FB) \ + round_dec(n, FA, FB, shr_kr, shr_kr) + +#define round_dec_2(n, FA, FB) \ + round_dec(n, FA, FB, shr_kr, dummy) + +#define read_block() \ + movq (RIO), RLR0; \ + bswapq RLR0; + +#define write_block() \ + bswapq RLR0; \ + rorq $32, RLR0; \ + movq RLR0, (RIO); + +.align 8 +.globl _gcry_cast5_amd64_encrypt_block +ELF(.type _gcry_cast5_amd64_encrypt_block,@function;) + +_gcry_cast5_amd64_encrypt_block: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + + movq %rsi, %r10; + + GET_EXTERN_POINTER(_gcry_cast5_s1to4, RTAB); + + movq %rdx, RIO; + read_block(); + + get_round_km(0, RX0d); + get_round_kr_enc(0); + round_enc_1(0, F1, F2); + round_enc_1(2, F3, F1); + round_enc_1(4, F2, F3); + round_enc_2(6, F1, F2); + get_round_kr_enc(8); + round_enc_1(8, F3, F1); + round_enc_1(10, F2, F3); + round_enc_1(12, F1, F2); + round_enc_last(14, F3, F1); + + movq %r10, RIO; + write_block(); + + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_cast5_amd64_encrypt_block,.-_gcry_cast5_amd64_encrypt_block;) + +.align 8 +.globl _gcry_cast5_amd64_decrypt_block +ELF(.type _gcry_cast5_amd64_decrypt_block,@function;) + +_gcry_cast5_amd64_decrypt_block: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + + movq %rsi, %r10; + + GET_EXTERN_POINTER(_gcry_cast5_s1to4, RTAB); + + movq %rdx, RIO; + read_block(); + + get_round_km(15, RX0d); + get_round_kr_dec(15); + round_dec_1(15, F1, F3); + round_dec_1(13, F2, F1); + round_dec_1(11, F3, F2); + round_dec_2(9, F1, F3); + get_round_kr_dec(7); + round_dec_1(7, F2, F1); + round_dec_1(5, F3, F2); + round_dec_1(3, F1, F3); + round_dec_last(1, F2, F1); + + movq %r10, RIO; + write_block(); + + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_cast5_amd64_decrypt_block,.-_gcry_cast5_amd64_decrypt_block;) + +/********************************************************************** + 4-way cast5, four blocks parallel + **********************************************************************/ +#define F_tail(rlr, rx, op1, op2, op3) \ + movzbl rx ## bh, RT0d; \ + movzbl rx ## bl, RT1d; \ + roll $16, rx ## d; \ + movl s1(RTAB,RT0,4), RT0d; \ + op1 ## l s2(RTAB,RT1,4), RT0d; \ + movzbl rx ## bh, RT1d; \ + movzbl rx ## bl, rx ## d; \ + op2 ## l s3(RTAB,RT1,4), RT0d; \ + op3 ## l s4(RTAB,rx,4), RT0d; \ + xorq RT0, rlr; + +#define F4(km, load_next_kr, op0, op1, op2, op3) \ + movl km, RX0d; \ + op0 ## l RLR0d, RX0d; \ + roll RKRbl, RX0d; \ + rorq $32, RLR0; \ + \ + movl km, RX1d; \ + op0 ## l RLR1d, RX1d; \ + roll RKRbl, RX1d; \ + rorq $32, RLR1; \ + \ + movl km, RX2d; \ + op0 ## l RLR2d, RX2d; \ + roll RKRbl, RX2d; \ + rorq $32, RLR2; \ + \ + F_tail(RLR0, RX0, op1, op2, op3); \ + F_tail(RLR1, RX1, op1, op2, op3); \ + F_tail(RLR2, RX2, op1, op2, op3); \ + \ + movl km, RX0d; \ + op0 ## l RLR3d, RX0d; \ + roll RKRbl, RX0d; \ + load_next_kr(); \ + rorq $32, RLR3; \ + \ + F_tail(RLR3, RX0, op1, op2, op3); + +#define F4_1(km, load_next_kr) \ + F4(km, load_next_kr, add, xor, sub, add) +#define F4_2(km, load_next_kr) \ + F4(km, load_next_kr, xor, sub, add, xor) +#define F4_3(km, load_next_kr) \ + F4(km, load_next_kr, sub, add, xor, sub) + +#define round_enc4(n, FA, FB, fn1, fn2) \ + get_round_km(n + 1, RKM1d); \ + FA(RKM0d, fn1); \ + get_round_km(n + 2, RKM0d); \ + FB(RKM1d, fn2); + +#define round_enc_last4(n, FXA, FXB) \ + get_round_km(n + 1, RKM1d); \ + FXA(RKM0d, shr_kr); \ + FXB(RKM1d, dummy); + +#define round_enc4_1(n, FA, FB) \ + round_enc4(n, FA, FB, shr_kr, shr_kr); + +#define round_enc4_2(n, FA, FB) \ + round_enc4(n, FA, FB, shr_kr, dummy); + +#define round_dec4(n, FA, FB, fn1, fn2) \ + get_round_km(n - 1, RKM1d); \ + FA(RKM0d, fn1); \ + get_round_km(n - 2, RKM0d); \ + FB(RKM1d, fn2); + +#define round_dec_last4(n, FXA, FXB) \ + get_round_km(n - 1, RKM1d); \ + FXA(RKM0d, shr_kr); \ + FXB(RKM1d, dummy); + +#define round_dec4_1(n, FA, FB) \ + round_dec4(n, FA, FB, shr_kr, shr_kr); + +#define round_dec4_2(n, FA, FB) \ + round_dec4(n, FA, FB, shr_kr, dummy); + +#define inbswap_block4(a, b, c, d) \ + bswapq a; \ + bswapq b; \ + bswapq c; \ + bswapq d; + +#define outbswap_block4(a, b, c, d) \ + bswapq a; \ + bswapq b; \ + bswapq c; \ + bswapq d; \ + rorq $32, a; \ + rorq $32, b; \ + rorq $32, c; \ + rorq $32, d; + +.align 8 +ELF(.type __cast5_enc_blk4,@function;) + +__cast5_enc_blk4: + /* input: + * %rdi: ctx, CTX + * RLR0,RLR1,RLR2,RLR3: four input plaintext blocks + * output: + * RLR0,RLR1,RLR2,RLR3: four output ciphertext blocks + */ + CFI_STARTPROC(); + GET_EXTERN_POINTER(_gcry_cast5_s1to4, RTAB); + + get_round_km(0, RKM0d); + get_round_kr_enc(0); + round_enc4_1(0, F4_1, F4_2); + round_enc4_1(2, F4_3, F4_1); + round_enc4_1(4, F4_2, F4_3); + round_enc4_2(6, F4_1, F4_2); + get_round_kr_enc(8); + round_enc4_1(8, F4_3, F4_1); + round_enc4_1(10, F4_2, F4_3); + round_enc4_1(12, F4_1, F4_2); + round_enc_last4(14, F4_3, F4_1); + + outbswap_block4(RLR0, RLR1, RLR2, RLR3); + ret; + CFI_ENDPROC(); +ELF(.size __cast5_enc_blk4,.-__cast5_enc_blk4;) + +.align 8 +ELF(.type __cast5_dec_blk4,@function;) + +__cast5_dec_blk4: + /* input: + * %rdi: ctx, CTX + * RLR0,RLR1,RLR2,RLR3: four input ciphertext blocks + * output: + * RLR0,RLR1,RLR2,RLR3: four output plaintext blocks + */ + CFI_STARTPROC(); + GET_EXTERN_POINTER(_gcry_cast5_s1to4, RTAB); + + inbswap_block4(RLR0, RLR1, RLR2, RLR3); + + get_round_km(15, RKM0d); + get_round_kr_dec(15); + round_dec4_1(15, F4_1, F4_3); + round_dec4_1(13, F4_2, F4_1); + round_dec4_1(11, F4_3, F4_2); + round_dec4_2(9, F4_1, F4_3); + get_round_kr_dec(7); + round_dec4_1(7, F4_2, F4_1); + round_dec4_1(5, F4_3, F4_2); + round_dec4_1(3, F4_1, F4_3); + round_dec_last4(1, F4_2, F4_1); + + outbswap_block4(RLR0, RLR1, RLR2, RLR3); + CFI_ENDPROC(); + ret; +ELF(.size __cast5_dec_blk4,.-__cast5_dec_blk4;) + +.align 8 +.globl _gcry_cast5_amd64_ctr_enc +ELF(.type _gcry_cast5_amd64_ctr_enc,@function;) +_gcry_cast5_amd64_ctr_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (4 blocks) + * %rdx: src (4 blocks) + * %rcx: iv (big endian, 64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + + pushq %rsi; + CFI_PUSH(%rsi); + pushq %rdx; + CFI_PUSH(%rdx); + + /* load IV and byteswap */ + movq (%rcx), RX0; + bswapq RX0; + movq RX0, RLR0; + + /* construct IVs */ + leaq 1(RX0), RLR1; + leaq 2(RX0), RLR2; + leaq 3(RX0), RLR3; + leaq 4(RX0), RX0; + bswapq RX0; + + /* store new IV */ + movq RX0, (%rcx); + + call __cast5_enc_blk4; + + popq %r14; /*src*/ + CFI_POP_TMP_REG(); + popq %r13; /*dst*/ + CFI_POP_TMP_REG(); + + /* XOR key-stream with plaintext */ + xorq 0 * 8(%r14), RLR0; + xorq 1 * 8(%r14), RLR1; + xorq 2 * 8(%r14), RLR2; + xorq 3 * 8(%r14), RLR3; + movq RLR0, 0 * 8(%r13); + movq RLR1, 1 * 8(%r13); + movq RLR2, 2 * 8(%r13); + movq RLR3, 3 * 8(%r13); + + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret + CFI_ENDPROC(); +ELF(.size _gcry_cast5_amd64_ctr_enc,.-_gcry_cast5_amd64_ctr_enc;) + +.align 8 +.globl _gcry_cast5_amd64_cbc_dec +ELF(.type _gcry_cast5_amd64_cbc_dec,@function;) +_gcry_cast5_amd64_cbc_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (4 blocks) + * %rdx: src (4 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + + pushq %rcx; + CFI_PUSH(%rcx); + pushq %rsi; + CFI_PUSH(%rsi); + pushq %rdx; + CFI_PUSH(%rdx); + + /* load input */ + movq 0 * 8(%rdx), RLR0; + movq 1 * 8(%rdx), RLR1; + movq 2 * 8(%rdx), RLR2; + movq 3 * 8(%rdx), RLR3; + + call __cast5_dec_blk4; + + popq RX0; /*src*/ + CFI_POP_TMP_REG(); + popq RX1; /*dst*/ + CFI_POP_TMP_REG(); + popq RX2; /*iv*/ + CFI_POP_TMP_REG(); + + movq 3 * 8(RX0), %r14; + xorq (RX2), RLR0; + xorq 0 * 8(RX0), RLR1; + xorq 1 * 8(RX0), RLR2; + xorq 2 * 8(RX0), RLR3; + movq %r14, (RX2); /* store new IV */ + + movq RLR0, 0 * 8(RX1); + movq RLR1, 1 * 8(RX1); + movq RLR2, 2 * 8(RX1); + movq RLR3, 3 * 8(RX1); + + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_cast5_amd64_cbc_dec,.-_gcry_cast5_amd64_cbc_dec;) + +.align 8 +.globl _gcry_cast5_amd64_cfb_dec +ELF(.type _gcry_cast5_amd64_cfb_dec,@function;) +_gcry_cast5_amd64_cfb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (4 blocks) + * %rdx: src (4 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + + pushq %rsi; + CFI_PUSH(%rsi); + pushq %rdx; + CFI_PUSH(%rdx); + + /* Load input */ + movq (%rcx), RLR0; + movq 0 * 8(%rdx), RLR1; + movq 1 * 8(%rdx), RLR2; + movq 2 * 8(%rdx), RLR3; + + inbswap_block4(RLR0, RLR1, RLR2, RLR3); + + /* Update IV */ + movq 3 * 8(%rdx), %rdx; + movq %rdx, (%rcx); + + call __cast5_enc_blk4; + + popq %rdx; /*src*/ + CFI_POP_TMP_REG(); + popq %rcx; /*dst*/ + CFI_POP_TMP_REG(); + + xorq 0 * 8(%rdx), RLR0; + xorq 1 * 8(%rdx), RLR1; + xorq 2 * 8(%rdx), RLR2; + xorq 3 * 8(%rdx), RLR3; + movq RLR0, 0 * 8(%rcx); + movq RLR1, 1 * 8(%rcx); + movq RLR2, 2 * 8(%rcx); + movq RLR3, 3 * 8(%rcx); + + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_cast5_amd64_cfb_dec,.-_gcry_cast5_amd64_cfb_dec;) + +#endif /*defined(USE_CAST5)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/cast5-arm.S b/comm/third_party/libgcrypt/cipher/cast5-arm.S new file mode 100644 index 0000000000..76ddd2e335 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cast5-arm.S @@ -0,0 +1,728 @@ +/* cast5-arm.S - ARM assembly implementation of CAST5 cipher + * + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(__ARMEL__) +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +.text + +.syntax unified +.arm + +.extern _gcry_cast5_s1to4; + +#ifdef __PIC__ +# define GET_DATA_POINTER(reg, name, rtmp) \ + ldr reg, 1f; \ + ldr rtmp, 2f; \ + b 3f; \ + 1: .word _GLOBAL_OFFSET_TABLE_-(3f+8); \ + 2: .word name(GOT); \ + 3: add reg, pc, reg; \ + ldr reg, [reg, rtmp]; +#else +# define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name +#endif + +/* structure of crypto context */ +#define Km 0 +#define Kr (Km + (16 * 4)) +#define Kr_arm_enc (Kr + (16)) +#define Kr_arm_dec (Kr_arm_enc + (16)) + +/* register macros */ +#define CTX %r0 +#define Rs1 %r7 +#define Rs2 %r8 +#define Rs3 %r9 +#define Rs4 %r10 +#define RMASK %r11 +#define RKM %r1 +#define RKR %r2 + +#define RL0 %r3 +#define RR0 %r4 + +#define RL1 %r9 +#define RR1 %r10 + +#define RT0 %lr +#define RT1 %ip +#define RT2 %r5 +#define RT3 %r6 + +/* helper macros */ +#define ldr_unaligned_le(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 0)]; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 3)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 0)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 1)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 2)]; \ + strb rtmp0, [rdst, #((offs) + 3)]; + +#define ldr_unaligned_be(rout, rsrc, offs, rtmp) \ + ldrb rout, [rsrc, #((offs) + 3)]; \ + ldrb rtmp, [rsrc, #((offs) + 2)]; \ + orr rout, rout, rtmp, lsl #8; \ + ldrb rtmp, [rsrc, #((offs) + 1)]; \ + orr rout, rout, rtmp, lsl #16; \ + ldrb rtmp, [rsrc, #((offs) + 0)]; \ + orr rout, rout, rtmp, lsl #24; + +#define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \ + mov rtmp0, rin, lsr #8; \ + strb rin, [rdst, #((offs) + 3)]; \ + mov rtmp1, rin, lsr #16; \ + strb rtmp0, [rdst, #((offs) + 2)]; \ + mov rtmp0, rin, lsr #24; \ + strb rtmp1, [rdst, #((offs) + 1)]; \ + strb rtmp0, [rdst, #((offs) + 0)]; + +#ifdef __ARMEL__ + #define ldr_unaligned_host ldr_unaligned_le + #define str_unaligned_host str_unaligned_le + + /* bswap on little-endian */ +#ifdef HAVE_ARM_ARCH_V6 + #define host_to_be(reg, rtmp) \ + rev reg, reg; + #define be_to_host(reg, rtmp) \ + rev reg, reg; +#else + #define host_to_be(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; + #define be_to_host(reg, rtmp) \ + eor rtmp, reg, reg, ror #16; \ + mov rtmp, rtmp, lsr #8; \ + bic rtmp, rtmp, #65280; \ + eor reg, rtmp, reg, ror #8; +#endif +#else + #define ldr_unaligned_host ldr_unaligned_be + #define str_unaligned_host str_unaligned_be + + /* nop on big-endian */ + #define host_to_be(reg, rtmp) /*_*/ + #define be_to_host(reg, rtmp) /*_*/ +#endif + +#define host_to_host(x, y) /*_*/ + +/********************************************************************** + 1-way cast5 + **********************************************************************/ + +#define dummy(n) /*_*/ + +#define load_kr(n) \ + ldr RKR, [CTX, #(Kr_arm_enc + (n))]; /* Kr[n] */ + +#define load_dec_kr(n) \ + ldr RKR, [CTX, #(Kr_arm_dec + (n) - 3)]; /* Kr[n] */ + +#define load_km(n) \ + ldr RKM, [CTX, #(Km + (n) * 4)]; /* Km[n] */ + +#define shift_kr(dummy) \ + mov RKR, RKR, lsr #8; + +#define F(n, rl, rr, op1, op2, op3, op4, dec, loadkm, shiftkr, loadkr) \ + op1 RKM, rr; \ + mov RKM, RKM, ror RKR; \ + \ + and RT0, RMASK, RKM, ror #(24); \ + and RT1, RMASK, RKM, lsr #(16); \ + and RT2, RMASK, RKM, lsr #(8); \ + ldr RT0, [Rs1, RT0]; \ + and RT3, RMASK, RKM; \ + ldr RT1, [Rs2, RT1]; \ + shiftkr(RKR); \ + \ + ldr RT2, [Rs3, RT2]; \ + \ + op2 RT0, RT1; \ + ldr RT3, [Rs4, RT3]; \ + op3 RT0, RT2; \ + loadkm((n) + (1 - ((dec) * 2))); \ + op4 RT0, RT3; \ + loadkr((n) + (1 - ((dec) * 2))); \ + eor rl, RT0; + +#define F1(n, rl, rr, dec, loadkm, shiftkr, loadkr) \ + F(n, rl, rr, add, eor, sub, add, dec, loadkm, shiftkr, loadkr) +#define F2(n, rl, rr, dec, loadkm, shiftkr, loadkr) \ + F(n, rl, rr, eor, sub, add, eor, dec, loadkm, shiftkr, loadkr) +#define F3(n, rl, rr, dec, loadkm, shiftkr, loadkr) \ + F(n, rl, rr, sub, add, eor, sub, dec, loadkm, shiftkr, loadkr) + +#define enc_round(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \ + Fx(n, rl, rr, 0, loadkm, shiftkr, loadkr) + +#define dec_round(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \ + Fx(n, rl, rr, 1, loadkm, shiftkr, loadkr) + +#define read_block_aligned(rin, offs, l0, r0, convert, rtmp) \ + ldr l0, [rin, #((offs) + 0)]; \ + ldr r0, [rin, #((offs) + 4)]; \ + convert(l0, rtmp); \ + convert(r0, rtmp); + +#define write_block_aligned(rout, offs, l0, r0, convert, rtmp) \ + convert(l0, rtmp); \ + convert(r0, rtmp); \ + str l0, [rout, #((offs) + 0)]; \ + str r0, [rout, #((offs) + 4)]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads allowed */ + #define read_block(rin, offs, l0, r0, rtmp0) \ + read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0) + + #define write_block(rout, offs, r0, l0, rtmp0, rtmp1) \ + write_block_aligned(rout, offs, r0, l0, be_to_host, rtmp0) + + #define read_block_host(rin, offs, l0, r0, rtmp0) \ + read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0) + + #define write_block_host(rout, offs, r0, l0, rtmp0, rtmp1) \ + write_block_aligned(rout, offs, r0, l0, host_to_host, rtmp0) +#else + /* need to handle unaligned reads by byte reads */ + #define read_block(rin, offs, l0, r0, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(l0, rin, (offs) + 0, rtmp0); \ + ldr_unaligned_be(r0, rin, (offs) + 4, rtmp0); \ + b 2f; \ + 1:;\ + read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0); \ + 2:; + + #define write_block(rout, offs, l0, r0, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(l0, rout, (offs) + 0, rtmp0, rtmp1); \ + str_unaligned_be(r0, rout, (offs) + 4, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block_aligned(rout, offs, l0, r0, be_to_host, rtmp0); \ + 2:; + + #define read_block_host(rin, offs, l0, r0, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_host(l0, rin, (offs) + 0, rtmp0); \ + ldr_unaligned_host(r0, rin, (offs) + 4, rtmp0); \ + b 2f; \ + 1:;\ + read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0); \ + 2:; + + #define write_block_host(rout, offs, l0, r0, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_host(l0, rout, (offs) + 0, rtmp0, rtmp1); \ + str_unaligned_host(r0, rout, (offs) + 4, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block_aligned(rout, offs, l0, r0, host_to_host, rtmp0); \ + 2:; +#endif + +.align 3 +.globl _gcry_cast5_arm_encrypt_block +.type _gcry_cast5_arm_encrypt_block,%function; + +_gcry_cast5_arm_encrypt_block: + /* input: + * %r0: CTX + * %r1: dst + * %r2: src + */ + push {%r1, %r4-%r11, %ip, %lr}; + + GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2); + mov RMASK, #(0xff << 2); + add Rs2, Rs1, #(0x100*4); + add Rs3, Rs1, #(0x100*4*2); + add Rs4, Rs1, #(0x100*4*3); + + read_block(%r2, 0, RL0, RR0, RT0); + + load_km(0); + load_kr(0); + enc_round(0, F1, RL0, RR0, load_km, shift_kr, dummy); + enc_round(1, F2, RR0, RL0, load_km, shift_kr, dummy); + enc_round(2, F3, RL0, RR0, load_km, shift_kr, dummy); + enc_round(3, F1, RR0, RL0, load_km, dummy, load_kr); + enc_round(4, F2, RL0, RR0, load_km, shift_kr, dummy); + enc_round(5, F3, RR0, RL0, load_km, shift_kr, dummy); + enc_round(6, F1, RL0, RR0, load_km, shift_kr, dummy); + enc_round(7, F2, RR0, RL0, load_km, dummy, load_kr); + enc_round(8, F3, RL0, RR0, load_km, shift_kr, dummy); + enc_round(9, F1, RR0, RL0, load_km, shift_kr, dummy); + enc_round(10, F2, RL0, RR0, load_km, shift_kr, dummy); + enc_round(11, F3, RR0, RL0, load_km, dummy, load_kr); + enc_round(12, F1, RL0, RR0, load_km, shift_kr, dummy); + enc_round(13, F2, RR0, RL0, load_km, shift_kr, dummy); + enc_round(14, F3, RL0, RR0, load_km, shift_kr, dummy); + enc_round(15, F1, RR0, RL0, dummy, dummy, dummy); + + ldr %r1, [%sp], #4; + write_block(%r1, 0, RR0, RL0, RT0, RT1); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_cast5_arm_encrypt_block,.-_gcry_cast5_arm_encrypt_block; + +.align 3 +.globl _gcry_cast5_arm_decrypt_block +.type _gcry_cast5_arm_decrypt_block,%function; + +_gcry_cast5_arm_decrypt_block: + /* input: + * %r0: CTX + * %r1: dst + * %r2: src + */ + push {%r1, %r4-%r11, %ip, %lr}; + + GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2); + mov RMASK, #(0xff << 2); + add Rs2, Rs1, #(0x100 * 4); + add Rs3, Rs1, #(0x100 * 4 * 2); + add Rs4, Rs1, #(0x100 * 4 * 3); + + read_block(%r2, 0, RL0, RR0, RT0); + + load_km(15); + load_dec_kr(15); + dec_round(15, F1, RL0, RR0, load_km, shift_kr, dummy); + dec_round(14, F3, RR0, RL0, load_km, shift_kr, dummy); + dec_round(13, F2, RL0, RR0, load_km, shift_kr, dummy); + dec_round(12, F1, RR0, RL0, load_km, dummy, load_dec_kr); + dec_round(11, F3, RL0, RR0, load_km, shift_kr, dummy); + dec_round(10, F2, RR0, RL0, load_km, shift_kr, dummy); + dec_round(9, F1, RL0, RR0, load_km, shift_kr, dummy); + dec_round(8, F3, RR0, RL0, load_km, dummy, load_dec_kr); + dec_round(7, F2, RL0, RR0, load_km, shift_kr, dummy); + dec_round(6, F1, RR0, RL0, load_km, shift_kr, dummy); + dec_round(5, F3, RL0, RR0, load_km, shift_kr, dummy); + dec_round(4, F2, RR0, RL0, load_km, dummy, load_dec_kr); + dec_round(3, F1, RL0, RR0, load_km, shift_kr, dummy); + dec_round(2, F3, RR0, RL0, load_km, shift_kr, dummy); + dec_round(1, F2, RL0, RR0, load_km, shift_kr, dummy); + dec_round(0, F1, RR0, RL0, dummy, dummy, dummy); + + ldr %r1, [%sp], #4; + write_block(%r1, 0, RR0, RL0, RT0, RT1); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_cast5_arm_decrypt_block,.-_gcry_cast5_arm_decrypt_block; + +/********************************************************************** + 2-way cast5 + **********************************************************************/ + +#define F_2w(n, rl0, rr0, rl1, rr1, op1, op2, op3, op4, dec, loadkm, shiftkr, \ + loadkr) \ + op1 RT3, RKM, rr0; \ + op1 RKM, RKM, rr1; \ + mov RT3, RT3, ror RKR; \ + mov RKM, RKM, ror RKR; \ + \ + and RT0, RMASK, RT3, ror #(24); \ + and RT1, RMASK, RT3, lsr #(16); \ + and RT2, RMASK, RT3, lsr #(8); \ + and RT3, RMASK, RT3; \ + \ + ldr RT0, [Rs1, RT0]; \ + add RT2, #(0x100 * 4); \ + ldr RT1, [Rs2, RT1]; \ + add RT3, #(0x100 * 4 * 2); \ + \ + ldr RT2, [Rs2, RT2]; \ + \ + op2 RT0, RT1; \ + ldr RT3, [Rs2, RT3]; \ + and RT1, RMASK, RKM, ror #(24); \ + op3 RT0, RT2; \ + and RT2, RMASK, RKM, lsr #(16); \ + op4 RT0, RT3; \ + and RT3, RMASK, RKM, lsr #(8); \ + eor rl0, RT0; \ + add RT3, #(0x100 * 4); \ + ldr RT1, [Rs1, RT1]; \ + and RT0, RMASK, RKM; \ + ldr RT2, [Rs2, RT2]; \ + add RT0, #(0x100 * 4 * 2); \ + \ + ldr RT3, [Rs2, RT3]; \ + \ + op2 RT1, RT2; \ + ldr RT0, [Rs2, RT0]; \ + op3 RT1, RT3; \ + loadkm((n) + (1 - ((dec) * 2))); \ + op4 RT1, RT0; \ + loadkr((n) + (1 - ((dec) * 2))); \ + shiftkr(RKR); \ + eor rl1, RT1; + +#define F1_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \ + F_2w(n, rl0, rr0, rl1, rr1, add, eor, sub, add, dec, \ + loadkm, shiftkr, loadkr) +#define F2_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \ + F_2w(n, rl0, rr0, rl1, rr1, eor, sub, add, eor, dec, \ + loadkm, shiftkr, loadkr) +#define F3_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \ + F_2w(n, rl0, rr0, rl1, rr1, sub, add, eor, sub, dec, \ + loadkm, shiftkr, loadkr) + +#define enc_round2(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \ + Fx##_2w(n, rl##0, rr##0, rl##1, rr##1, 0, loadkm, shiftkr, loadkr) + +#define dec_round2(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \ + Fx##_2w(n, rl##0, rr##0, rl##1, rr##1, 1, loadkm, shiftkr, loadkr) + +#define read_block2_aligned(rin, l0, r0, l1, r1, convert, rtmp) \ + ldr l0, [rin, #(0)]; \ + ldr r0, [rin, #(4)]; \ + convert(l0, rtmp); \ + ldr l1, [rin, #(8)]; \ + convert(r0, rtmp); \ + ldr r1, [rin, #(12)]; \ + convert(l1, rtmp); \ + convert(r1, rtmp); + +#define write_block2_aligned(rout, l0, r0, l1, r1, convert, rtmp) \ + convert(l0, rtmp); \ + convert(r0, rtmp); \ + convert(l1, rtmp); \ + str l0, [rout, #(0)]; \ + convert(r1, rtmp); \ + str r0, [rout, #(4)]; \ + str l1, [rout, #(8)]; \ + str r1, [rout, #(12)]; + +#ifdef __ARM_FEATURE_UNALIGNED + /* unaligned word reads allowed */ + #define read_block2(rin, l0, r0, l1, r1, rtmp0) \ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0) + + #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0) + + #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0) + + #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0) +#else + /* need to handle unaligned reads by byte reads */ + #define read_block2(rin, l0, r0, l1, r1, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_be(l0, rin, 0, rtmp0); \ + ldr_unaligned_be(r0, rin, 4, rtmp0); \ + ldr_unaligned_be(l1, rin, 8, rtmp0); \ + ldr_unaligned_be(r1, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0); \ + 2:; + + #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_be(l0, rout, 0, rtmp0, rtmp1); \ + str_unaligned_be(r0, rout, 4, rtmp0, rtmp1); \ + str_unaligned_be(l1, rout, 8, rtmp0, rtmp1); \ + str_unaligned_be(r1, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0); \ + 2:; + + #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \ + tst rin, #3; \ + beq 1f; \ + ldr_unaligned_host(l0, rin, 0, rtmp0); \ + ldr_unaligned_host(r0, rin, 4, rtmp0); \ + ldr_unaligned_host(l1, rin, 8, rtmp0); \ + ldr_unaligned_host(r1, rin, 12, rtmp0); \ + b 2f; \ + 1:;\ + read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0); \ + 2:; + + #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \ + tst rout, #3; \ + beq 1f; \ + str_unaligned_host(l0, rout, 0, rtmp0, rtmp1); \ + str_unaligned_host(r0, rout, 4, rtmp0, rtmp1); \ + str_unaligned_host(l1, rout, 8, rtmp0, rtmp1); \ + str_unaligned_host(r1, rout, 12, rtmp0, rtmp1); \ + b 2f; \ + 1:;\ + write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0); \ + 2:; +#endif + +.align 3 +.type _gcry_cast5_arm_enc_blk2,%function; + +_gcry_cast5_arm_enc_blk2: + /* input: + * preloaded: CTX + * [RL0, RR0], [RL1, RR1]: src + * output: + * [RR0, RL0], [RR1, RL1]: dst + */ + push {%lr}; + + GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2); + mov RMASK, #(0xff << 2); + add Rs2, Rs1, #(0x100 * 4); + + load_km(0); + load_kr(0); + enc_round2(0, F1, RL, RR, load_km, shift_kr, dummy); + enc_round2(1, F2, RR, RL, load_km, shift_kr, dummy); + enc_round2(2, F3, RL, RR, load_km, shift_kr, dummy); + enc_round2(3, F1, RR, RL, load_km, dummy, load_kr); + enc_round2(4, F2, RL, RR, load_km, shift_kr, dummy); + enc_round2(5, F3, RR, RL, load_km, shift_kr, dummy); + enc_round2(6, F1, RL, RR, load_km, shift_kr, dummy); + enc_round2(7, F2, RR, RL, load_km, dummy, load_kr); + enc_round2(8, F3, RL, RR, load_km, shift_kr, dummy); + enc_round2(9, F1, RR, RL, load_km, shift_kr, dummy); + enc_round2(10, F2, RL, RR, load_km, shift_kr, dummy); + enc_round2(11, F3, RR, RL, load_km, dummy, load_kr); + enc_round2(12, F1, RL, RR, load_km, shift_kr, dummy); + enc_round2(13, F2, RR, RL, load_km, shift_kr, dummy); + enc_round2(14, F3, RL, RR, load_km, shift_kr, dummy); + enc_round2(15, F1, RR, RL, dummy, dummy, dummy); + + host_to_be(RR0, RT0); + host_to_be(RL0, RT0); + host_to_be(RR1, RT0); + host_to_be(RL1, RT0); + + pop {%pc}; +.ltorg +.size _gcry_cast5_arm_enc_blk2,.-_gcry_cast5_arm_enc_blk2; + +.align 3 +.globl _gcry_cast5_arm_cfb_dec; +.type _gcry_cast5_arm_cfb_dec,%function; + +_gcry_cast5_arm_cfb_dec: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit) + */ + push {%r1, %r2, %r4-%r11, %ip, %lr}; + + mov %lr, %r3; + + /* Load input (iv/%r3 is aligned, src/%r2 might not be) */ + ldm %r3, {RL0, RR0}; + host_to_be(RL0, RT1); + host_to_be(RR0, RT1); + read_block(%r2, 0, RL1, RR1, %ip); + + /* Update IV, load src[1] and save to iv[0] */ + read_block_host(%r2, 8, %r5, %r6, %r7); + stm %lr, {%r5, %r6}; + + bl _gcry_cast5_arm_enc_blk2; + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r0: dst, %r1: %src */ + pop {%r0, %r1}; + + /* dst = src ^ result */ + read_block2_host(%r1, %r5, %r6, %r7, %r8, %lr); + eor %r5, %r4; + eor %r6, %r3; + eor %r7, %r10; + eor %r8, %r9; + write_block2_host(%r0, %r5, %r6, %r7, %r8, %r1, %r2); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_cast5_arm_cfb_dec,.-_gcry_cast5_arm_cfb_dec; + +.align 3 +.globl _gcry_cast5_arm_ctr_enc; +.type _gcry_cast5_arm_ctr_enc,%function; + +_gcry_cast5_arm_ctr_enc: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit, big-endian) + */ + push {%r1, %r2, %r4-%r11, %ip, %lr}; + + mov %lr, %r3; + + /* Load IV (big => host endian) */ + read_block_aligned(%lr, 0, RL0, RR0, be_to_host, RT1); + + /* Construct IVs */ + adds RR1, RR0, #1; /* +1 */ + adc RL1, RL0, #0; + adds %r6, RR1, #1; /* +2 */ + adc %r5, RL1, #0; + + /* Store new IV (host => big-endian) */ + write_block_aligned(%lr, 0, %r5, %r6, host_to_be, RT1); + + bl _gcry_cast5_arm_enc_blk2; + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r0: dst, %r1: %src */ + pop {%r0, %r1}; + + /* XOR key-stream with plaintext */ + read_block2_host(%r1, %r5, %r6, %r7, %r8, %lr); + eor %r5, %r4; + eor %r6, %r3; + eor %r7, %r10; + eor %r8, %r9; + write_block2_host(%r0, %r5, %r6, %r7, %r8, %r1, %r2); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_cast5_arm_ctr_enc,.-_gcry_cast5_arm_ctr_enc; + +.align 3 +.type _gcry_cast5_arm_dec_blk2,%function; + +_gcry_cast5_arm_dec_blk2: + /* input: + * preloaded: CTX + * [RL0, RR0], [RL1, RR1]: src + * output: + * [RR0, RL0], [RR1, RL1]: dst + */ + + GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2); + mov RMASK, #(0xff << 2); + add Rs2, Rs1, #(0x100 * 4); + + load_km(15); + load_dec_kr(15); + dec_round2(15, F1, RL, RR, load_km, shift_kr, dummy); + dec_round2(14, F3, RR, RL, load_km, shift_kr, dummy); + dec_round2(13, F2, RL, RR, load_km, shift_kr, dummy); + dec_round2(12, F1, RR, RL, load_km, dummy, load_dec_kr); + dec_round2(11, F3, RL, RR, load_km, shift_kr, dummy); + dec_round2(10, F2, RR, RL, load_km, shift_kr, dummy); + dec_round2(9, F1, RL, RR, load_km, shift_kr, dummy); + dec_round2(8, F3, RR, RL, load_km, dummy, load_dec_kr); + dec_round2(7, F2, RL, RR, load_km, shift_kr, dummy); + dec_round2(6, F1, RR, RL, load_km, shift_kr, dummy); + dec_round2(5, F3, RL, RR, load_km, shift_kr, dummy); + dec_round2(4, F2, RR, RL, load_km, dummy, load_dec_kr); + dec_round2(3, F1, RL, RR, load_km, shift_kr, dummy); + dec_round2(2, F3, RR, RL, load_km, shift_kr, dummy); + dec_round2(1, F2, RL, RR, load_km, shift_kr, dummy); + dec_round2(0, F1, RR, RL, dummy, dummy, dummy); + + host_to_be(RR0, RT0); + host_to_be(RL0, RT0); + host_to_be(RR1, RT0); + host_to_be(RL1, RT0); + + b .Ldec_cbc_tail; +.ltorg +.size _gcry_cast5_arm_dec_blk2,.-_gcry_cast5_arm_dec_blk2; + +.align 3 +.globl _gcry_cast5_arm_cbc_dec; +.type _gcry_cast5_arm_cbc_dec,%function; + +_gcry_cast5_arm_cbc_dec: + /* input: + * %r0: CTX + * %r1: dst (2 blocks) + * %r2: src (2 blocks) + * %r3: iv (64bit) + */ + push {%r1-%r11, %ip, %lr}; + + read_block2(%r2, RL0, RR0, RL1, RR1, RT0); + + /* dec_blk2 is only used by cbc_dec, jump directly in/out instead + * of function call. */ + b _gcry_cast5_arm_dec_blk2; +.Ldec_cbc_tail: + /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */ + + /* %r0: dst, %r1: %src, %r2: iv */ + pop {%r0-%r2}; + + /* load IV+1 (src[0]) to %r7:%r8. Might be unaligned. */ + read_block_host(%r1, 0, %r7, %r8, %r5); + /* load IV (iv[0]) to %r5:%r6. 'iv' is aligned. */ + ldm %r2, {%r5, %r6}; + + /* out[1] ^= IV+1 */ + eor %r10, %r7; + eor %r9, %r8; + /* out[0] ^= IV */ + eor %r4, %r5; + eor %r3, %r6; + + /* load IV+2 (src[1]) to %r7:%r8. Might be unaligned. */ + read_block_host(%r1, 8, %r7, %r8, %r5); + /* store IV+2 to iv[0] (aligned). */ + stm %r2, {%r7, %r8}; + + /* store result to dst[0-3]. Might be unaligned. */ + write_block2_host(%r0, %r4, %r3, %r10, %r9, %r5, %r6); + + pop {%r4-%r11, %ip, %pc}; +.ltorg +.size _gcry_cast5_arm_cbc_dec,.-_gcry_cast5_arm_cbc_dec; + +#endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/ +#endif /*__ARM_ARCH >= 6*/ diff --git a/comm/third_party/libgcrypt/cipher/cast5.c b/comm/third_party/libgcrypt/cipher/cast5.c new file mode 100644 index 0000000000..837ea0fe57 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cast5.c @@ -0,0 +1,1238 @@ +/* cast5.c - CAST5 cipher (RFC2144) + * Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* Test vectors: + * + * 128-bit key = 01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A + * plaintext = 01 23 45 67 89 AB CD EF + * ciphertext = 23 8B 4F E5 84 7E 44 B2 + * + * 80-bit key = 01 23 45 67 12 34 56 78 23 45 + * = 01 23 45 67 12 34 56 78 23 45 00 00 00 00 00 00 + * plaintext = 01 23 45 67 89 AB CD EF + * ciphertext = EB 6A 71 1A 2C 02 27 1B + * + * 40-bit key = 01 23 45 67 12 + * = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00 + * plaintext = 01 23 45 67 89 AB CD EF + * ciphertext = 7A C8 16 D1 6E 9B 30 2E + */ + +#include +#include +#include +#include +#include "g10lib.h" +#include "types.h" +#include "cipher.h" +#include "bithelp.h" +#include "bufhelp.h" +#include "cipher-internal.h" +#include "cipher-selftest.h" + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AMD64_ASM 1 +#endif + +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +#undef USE_ARM_ASM +#if defined(__ARMEL__) +# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS +# define USE_ARM_ASM 1 +# endif +#endif + +#define CAST5_BLOCKSIZE 8 + +typedef struct { + u32 Km[16]; + byte Kr[16]; +#ifdef USE_ARM_ASM + u32 Kr_arm_enc[16 / sizeof(u32)]; + u32 Kr_arm_dec[16 / sizeof(u32)]; +#endif +} CAST5_context; + +static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops); +static unsigned int encrypt_block (void *c, byte *outbuf, const byte *inbuf); +static unsigned int decrypt_block (void *c, byte *outbuf, const byte *inbuf); + + + +#define s1 _gcry_cast5_s1to4[0] +#define s2 _gcry_cast5_s1to4[1] +#define s3 _gcry_cast5_s1to4[2] +#define s4 _gcry_cast5_s1to4[3] + +const u32 _gcry_cast5_s1to4[4][256] = { { +0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, +0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, +0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, +0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, +0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, +0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, +0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, +0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, +0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, +0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, +0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, +0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, +0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, +0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, +0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, +0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, +0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, +0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, +0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, +0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, +0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, +0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, +0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, +0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, +0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, +0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, +0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, +0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, +0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, +0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, +0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, +0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf +}, { +0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, +0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, +0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, +0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, +0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, +0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, +0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, +0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, +0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, +0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, +0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, +0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, +0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, +0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, +0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, +0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, +0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, +0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, +0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, +0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, +0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, +0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, +0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, +0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, +0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, +0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, +0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, +0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, +0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, +0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, +0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, +0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 +}, { +0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, +0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, +0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, +0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, +0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, +0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, +0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, +0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, +0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, +0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, +0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, +0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, +0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, +0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, +0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, +0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, +0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, +0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, +0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, +0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, +0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, +0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, +0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, +0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, +0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, +0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, +0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, +0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, +0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, +0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, +0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, +0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 +}, { +0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, +0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, +0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, +0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, +0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, +0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, +0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, +0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, +0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, +0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, +0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, +0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, +0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, +0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, +0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, +0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, +0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, +0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, +0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, +0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, +0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, +0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, +0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, +0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, +0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, +0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, +0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, +0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, +0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, +0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, +0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, +0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 +} }; +static const u32 s5[256] = { +0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, +0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, +0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, +0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, +0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, +0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, +0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, +0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, +0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, +0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, +0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, +0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, +0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, +0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, +0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, +0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, +0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, +0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, +0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, +0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, +0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, +0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, +0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, +0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, +0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, +0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, +0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, +0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, +0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, +0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, +0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, +0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 +}; +static const u32 s6[256] = { +0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, +0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, +0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, +0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, +0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, +0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, +0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, +0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, +0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, +0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, +0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, +0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, +0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, +0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, +0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, +0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, +0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, +0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, +0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, +0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, +0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, +0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, +0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, +0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, +0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, +0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, +0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, +0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, +0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, +0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, +0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, +0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f +}; +static const u32 s7[256] = { +0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, +0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, +0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, +0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, +0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, +0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, +0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, +0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, +0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, +0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, +0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, +0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, +0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, +0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, +0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, +0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, +0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, +0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, +0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, +0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, +0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, +0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, +0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, +0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, +0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, +0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, +0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, +0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, +0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, +0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, +0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, +0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 +}; +static const u32 s8[256] = { +0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, +0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, +0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, +0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, +0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, +0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, +0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, +0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, +0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, +0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, +0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, +0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, +0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, +0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, +0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, +0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, +0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, +0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, +0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, +0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, +0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, +0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, +0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, +0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, +0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, +0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, +0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, +0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, +0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, +0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, +0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, +0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e +}; + + +#ifdef USE_AMD64_ASM + +/* Assembly implementations of CAST5. */ +extern void _gcry_cast5_amd64_encrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +extern void _gcry_cast5_amd64_decrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +/* These assembly implementations process four blocks in parallel. */ +extern void _gcry_cast5_amd64_ctr_enc(CAST5_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_cast5_amd64_cbc_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_cast5_amd64_cfb_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_amd64_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_amd64_decrypt_block (context, outbuf, inbuf); +} + +static void +cast5_amd64_ctr_enc(CAST5_context *ctx, byte *out, const byte *in, byte *ctr) +{ + _gcry_cast5_amd64_ctr_enc (ctx, out, in, ctr); +} + +static void +cast5_amd64_cbc_dec(CAST5_context *ctx, byte *out, const byte *in, byte *iv) +{ + _gcry_cast5_amd64_cbc_dec (ctx, out, in, iv); +} + +static void +cast5_amd64_cfb_dec(CAST5_context *ctx, byte *out, const byte *in, byte *iv) +{ + _gcry_cast5_amd64_cfb_dec (ctx, out, in, iv); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +#elif defined(USE_ARM_ASM) + +/* ARM assembly implementations of CAST5. */ +extern void _gcry_cast5_arm_encrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +extern void _gcry_cast5_arm_decrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +/* These assembly implementations process two blocks in parallel. */ +extern void _gcry_cast5_arm_ctr_enc(CAST5_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_cast5_arm_cbc_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_cast5_arm_cfb_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_arm_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_arm_decrypt_block (context, outbuf, inbuf); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +#else /*USE_ARM_ASM*/ + +#define F1(D,m,r) ( (I = ((m) + (D))), (I=rol(I,(r))), \ + (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) ) +#define F2(D,m,r) ( (I = ((m) ^ (D))), (I=rol(I,(r))), \ + (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) ) +#define F3(D,m,r) ( (I = ((m) - (D))), (I=rol(I,(r))), \ + (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) ) + +static void +do_encrypt_block( CAST5_context *c, byte *outbuf, const byte *inbuf ) +{ + u32 l, r, t; + u32 I; /* used by the Fx macros */ + u32 *Km; + u32 Kr; + + Km = c->Km; + Kr = buf_get_le32(c->Kr + 0); + + /* (L0,R0) <-- (m1...m64). (Split the plaintext into left and + * right 32-bit halves L0 = m1...m32 and R0 = m33...m64.) + */ + l = buf_get_be32(inbuf + 0); + r = buf_get_be32(inbuf + 4); + + /* (16 rounds) for i from 1 to 16, compute Li and Ri as follows: + * Li = Ri-1; + * Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2 + * Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1. + * Rounds 2, 5, 8, 11, and 14 use f function Type 2. + * Rounds 3, 6, 9, 12, and 15 use f function Type 3. + */ + + t = l; l = r; r = t ^ F1(r, Km[ 0], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[ 1], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[ 2], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[ 3], Kr & 31); Kr = buf_get_le32(c->Kr + 4); + t = l; l = r; r = t ^ F2(r, Km[ 4], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[ 5], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[ 6], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[ 7], Kr & 31); Kr = buf_get_le32(c->Kr + 8); + t = l; l = r; r = t ^ F3(r, Km[ 8], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[ 9], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[10], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[11], Kr & 31); Kr = buf_get_le32(c->Kr + 12); + t = l; l = r; r = t ^ F1(r, Km[12], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[13], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[14], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[15], Kr & 31); + + /* c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and + * concatenate to form the ciphertext.) */ + buf_put_be32(outbuf + 0, r); + buf_put_be32(outbuf + 4, l); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (20+4*sizeof(void*)); +} + + +static void +do_encrypt_block_3( CAST5_context *c, byte *outbuf, const byte *inbuf ) +{ + u32 l0, r0, t0, l1, r1, t1, l2, r2, t2; + u32 I; /* used by the Fx macros */ + u32 *Km; + u32 Kr; + + Km = c->Km; + Kr = buf_get_le32(c->Kr + 0); + + l0 = buf_get_be32(inbuf + 0); + r0 = buf_get_be32(inbuf + 4); + l1 = buf_get_be32(inbuf + 8); + r1 = buf_get_be32(inbuf + 12); + l2 = buf_get_be32(inbuf + 16); + r2 = buf_get_be32(inbuf + 20); + + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 0], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 0], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 0], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[ 1], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[ 1], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[ 1], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[ 2], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[ 2], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[ 2], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 3], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 3], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 3], Kr & 31); + Kr = buf_get_le32(c->Kr + 4); + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[ 4], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[ 4], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[ 4], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[ 5], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[ 5], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[ 5], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 6], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 6], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 6], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[ 7], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[ 7], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[ 7], Kr & 31); + Kr = buf_get_le32(c->Kr + 8); + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[ 8], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[ 8], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[ 8], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 9], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 9], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 9], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[10], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[10], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[10], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[11], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[11], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[11], Kr & 31); + Kr = buf_get_le32(c->Kr + 12); + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[12], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[12], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[12], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[13], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[13], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[13], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[14], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[14], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[14], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[15], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[15], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[15], Kr & 31); + + buf_put_be32(outbuf + 0, r0); + buf_put_be32(outbuf + 4, l0); + buf_put_be32(outbuf + 8, r1); + buf_put_be32(outbuf + 12, l1); + buf_put_be32(outbuf + 16, r2); + buf_put_be32(outbuf + 20, l2); +} + + +static void +do_decrypt_block (CAST5_context *c, byte *outbuf, const byte *inbuf ) +{ + u32 l, r, t; + u32 I; + u32 *Km; + u32 Kr; + + Km = c->Km; + Kr = buf_get_be32(c->Kr + 12); + + l = buf_get_be32(inbuf + 0); + r = buf_get_be32(inbuf + 4); + + t = l; l = r; r = t ^ F1(r, Km[15], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[14], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[13], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[12], Kr & 31); Kr = buf_get_be32(c->Kr + 8); + t = l; l = r; r = t ^ F3(r, Km[11], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[10], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[ 9], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[ 8], Kr & 31); Kr = buf_get_be32(c->Kr + 4); + t = l; l = r; r = t ^ F2(r, Km[ 7], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[ 6], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[ 5], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[ 4], Kr & 31); Kr = buf_get_be32(c->Kr + 0); + t = l; l = r; r = t ^ F1(r, Km[ 3], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F3(r, Km[ 2], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F2(r, Km[ 1], Kr & 31); Kr >>= 8; + t = l; l = r; r = t ^ F1(r, Km[ 0], Kr & 31); + + buf_put_be32(outbuf + 0, r); + buf_put_be32(outbuf + 4, l); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (20+4*sizeof(void*)); +} + + +static void +do_decrypt_block_3 (CAST5_context *c, byte *outbuf, const byte *inbuf ) +{ + u32 l0, r0, t0, l1, r1, t1, l2, r2, t2; + u32 I; + u32 *Km; + u32 Kr; + + Km = c->Km; + Kr = buf_get_be32(c->Kr + 12); + + l0 = buf_get_be32(inbuf + 0); + r0 = buf_get_be32(inbuf + 4); + l1 = buf_get_be32(inbuf + 8); + r1 = buf_get_be32(inbuf + 12); + l2 = buf_get_be32(inbuf + 16); + r2 = buf_get_be32(inbuf + 20); + + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[15], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[15], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[15], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[14], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[14], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[14], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[13], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[13], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[13], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[12], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[12], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[12], Kr & 31); + Kr = buf_get_be32(c->Kr + 8); + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[11], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[11], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[11], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[10], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[10], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[10], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 9], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 9], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 9], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[ 8], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[ 8], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[ 8], Kr & 31); + Kr = buf_get_be32(c->Kr + 4); + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[ 7], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[ 7], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[ 7], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 6], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 6], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 6], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[ 5], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[ 5], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[ 5], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[ 4], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[ 4], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[ 4], Kr & 31); + Kr = buf_get_be32(c->Kr + 0); + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 3], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 3], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 3], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F3(r0, Km[ 2], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F3(r1, Km[ 2], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F3(r2, Km[ 2], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F2(r0, Km[ 1], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F2(r1, Km[ 1], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F2(r2, Km[ 1], Kr & 31); + Kr >>= 8; + t0 = l0; l0 = r0; r0 = t0 ^ F1(r0, Km[ 0], Kr & 31); + t1 = l1; l1 = r1; r1 = t1 ^ F1(r1, Km[ 0], Kr & 31); + t2 = l2; l2 = r2; r2 = t2 ^ F1(r2, Km[ 0], Kr & 31); + + buf_put_be32(outbuf + 0, r0); + buf_put_be32(outbuf + 4, l0); + buf_put_be32(outbuf + 8, r1); + buf_put_be32(outbuf + 12, l1); + buf_put_be32(outbuf + 16, r2); + buf_put_be32(outbuf + 20, l2); +} + +#endif /*!USE_ARM_ASM*/ + + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size CAST5_BLOCKSIZE. */ +static void +_gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + CAST5_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[CAST5_BLOCKSIZE * 3]; + int burn_stack_depth = (20 + 4 * sizeof(void*)) + 4 * CAST5_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 8 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + cast5_amd64_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 4; + outbuf += 4 * CAST5_BLOCKSIZE; + inbuf += 4 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_cast5_arm_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 2; + outbuf += 2 * CAST5_BLOCKSIZE; + inbuf += 2 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + for ( ;nblocks >= 3; nblocks -= 3) + { + /* Prepare the counter blocks. */ + cipher_block_cpy (tmpbuf + 0, ctr, CAST5_BLOCKSIZE); + cipher_block_cpy (tmpbuf + 8, ctr, CAST5_BLOCKSIZE); + cipher_block_cpy (tmpbuf + 16, ctr, CAST5_BLOCKSIZE); + cipher_block_add (tmpbuf + 8, 1, CAST5_BLOCKSIZE); + cipher_block_add (tmpbuf + 16, 2, CAST5_BLOCKSIZE); + cipher_block_add (ctr, 3, CAST5_BLOCKSIZE); + /* Encrypt the counter. */ + do_encrypt_block_3(ctx, tmpbuf, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE * 3); + outbuf += CAST5_BLOCKSIZE * 3; + inbuf += CAST5_BLOCKSIZE * 3; + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + do_encrypt_block(ctx, tmpbuf, ctr); + /* XOR the input with the encrypted counter and store in output. */ + cipher_block_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE); + outbuf += CAST5_BLOCKSIZE; + inbuf += CAST5_BLOCKSIZE; + /* Increment the counter. */ + cipher_block_add (ctr, 1, CAST5_BLOCKSIZE); + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + CAST5_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[CAST5_BLOCKSIZE * 3]; + int burn_stack_depth = (20 + 4 * sizeof(void*)) + 4 * CAST5_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 8 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + cast5_amd64_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * CAST5_BLOCKSIZE; + inbuf += 4 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_cast5_arm_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * CAST5_BLOCKSIZE; + inbuf += 2 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + for ( ;nblocks >= 3; nblocks -= 3) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + do_decrypt_block_3 (ctx, savebuf, inbuf); + + cipher_block_xor_1 (savebuf + 0, iv, CAST5_BLOCKSIZE); + cipher_block_xor_1 (savebuf + 8, inbuf, CAST5_BLOCKSIZE * 2); + cipher_block_cpy (iv, inbuf + 16, CAST5_BLOCKSIZE); + buf_cpy (outbuf, savebuf, CAST5_BLOCKSIZE * 3); + inbuf += CAST5_BLOCKSIZE * 3; + outbuf += CAST5_BLOCKSIZE * 3; + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + do_decrypt_block (ctx, savebuf, inbuf); + + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE); + inbuf += CAST5_BLOCKSIZE; + outbuf += CAST5_BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + CAST5_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[CAST5_BLOCKSIZE * 3]; + int burn_stack_depth = (20 + 4 * sizeof(void*)) + 4 * CAST5_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 8 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + cast5_amd64_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * CAST5_BLOCKSIZE; + inbuf += 4 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_cast5_arm_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * CAST5_BLOCKSIZE; + inbuf += 2 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + for ( ;nblocks >= 3; nblocks -= 3 ) + { + cipher_block_cpy (tmpbuf + 0, iv, CAST5_BLOCKSIZE); + cipher_block_cpy (tmpbuf + 8, inbuf + 0, CAST5_BLOCKSIZE * 2); + cipher_block_cpy (iv, inbuf + 16, CAST5_BLOCKSIZE); + do_encrypt_block_3 (ctx, tmpbuf, tmpbuf); + buf_xor (outbuf, inbuf, tmpbuf, CAST5_BLOCKSIZE * 3); + outbuf += CAST5_BLOCKSIZE * 3; + inbuf += CAST5_BLOCKSIZE * 3; + } +#endif + + for ( ;nblocks; nblocks-- ) + { + do_encrypt_block(ctx, iv, iv); + cipher_block_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE); + outbuf += CAST5_BLOCKSIZE; + inbuf += CAST5_BLOCKSIZE; + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Run the self-tests for CAST5-CTR, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char * +selftest_ctr (void) +{ + const int nblocks = 4+1; + const int blocksize = CAST5_BLOCKSIZE; + const int context_size = sizeof(CAST5_context); + + return _gcry_selftest_helper_ctr("CAST5", &cast_setkey, + &encrypt_block, nblocks, blocksize, context_size); +} + + +/* Run the self-tests for CAST5-CBC, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cbc (void) +{ + const int nblocks = 4+2; + const int blocksize = CAST5_BLOCKSIZE; + const int context_size = sizeof(CAST5_context); + + return _gcry_selftest_helper_cbc("CAST5", &cast_setkey, + &encrypt_block, nblocks, blocksize, context_size); +} + + +/* Run the self-tests for CAST5-CFB, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cfb (void) +{ + const int nblocks = 4+2; + const int blocksize = CAST5_BLOCKSIZE; + const int context_size = sizeof(CAST5_context); + + return _gcry_selftest_helper_cfb("CAST5", &cast_setkey, + &encrypt_block, nblocks, blocksize, context_size); +} + + +static const char* +selftest(void) +{ + CAST5_context c; + cipher_bulk_ops_t bulk_ops; + static const byte key[16] = + { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, + 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A }; + static const byte plain[8] = + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + static const byte cipher[8] = + { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 }; + byte buffer[8]; + const char *r; + + cast_setkey( &c, key, 16, &bulk_ops ); + encrypt_block( &c, buffer, plain ); + if( memcmp( buffer, cipher, 8 ) ) + return "1"; + decrypt_block( &c, buffer, buffer ); + if( memcmp( buffer, plain, 8 ) ) + return "2"; + +#if 0 /* full maintenance test */ + { + int i; + byte a0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78, + 0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A }; + byte b0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78, + 0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A }; + byte a1[16] = { 0xEE,0xA9,0xD0,0xA2,0x49,0xFD,0x3B,0xA6, + 0xB3,0x43,0x6F,0xB8,0x9D,0x6D,0xCA,0x92 }; + byte b1[16] = { 0xB2,0xC9,0x5E,0xB0,0x0C,0x31,0xAD,0x71, + 0x80,0xAC,0x05,0xB8,0xE8,0x3D,0x69,0x6E }; + + for(i=0; i < 1000000; i++ ) { + cast_setkey( &c, b0, 16, &bulk_ops ); + encrypt_block( &c, a0, a0 ); + encrypt_block( &c, a0+8, a0+8 ); + cast_setkey( &c, a0, 16, &bulk_ops ); + encrypt_block( &c, b0, b0 ); + encrypt_block( &c, b0+8, b0+8 ); + } + if( memcmp( a0, a1, 16 ) || memcmp( b0, b1, 16 ) ) + return "3"; + + } +#endif + + if ( (r = selftest_cbc ()) ) + return r; + + if ( (r = selftest_cfb ()) ) + return r; + + if ( (r = selftest_ctr ()) ) + return r; + + return NULL; +} + + +static void +key_schedule( u32 *x, u32 *z, u32 *k ) +{ + +#define xi(i) ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff) +#define zi(i) ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff) + + z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)]; + z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)]; + z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)]; + z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)]; + k[0] = s5[zi( 8)]^s6[zi( 9)]^s7[zi( 7)]^s8[zi( 6)]^s5[zi( 2)]; + k[1] = s5[zi(10)]^s6[zi(11)]^s7[zi( 5)]^s8[zi( 4)]^s6[zi( 6)]; + k[2] = s5[zi(12)]^s6[zi(13)]^s7[zi( 3)]^s8[zi( 2)]^s7[zi( 9)]; + k[3] = s5[zi(14)]^s6[zi(15)]^s7[zi( 1)]^s8[zi( 0)]^s8[zi(12)]; + + x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)]; + x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)]; + x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)]; + x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)]; + k[4] = s5[xi( 3)]^s6[xi( 2)]^s7[xi(12)]^s8[xi(13)]^s5[xi( 8)]; + k[5] = s5[xi( 1)]^s6[xi( 0)]^s7[xi(14)]^s8[xi(15)]^s6[xi(13)]; + k[6] = s5[xi( 7)]^s6[xi( 6)]^s7[xi( 8)]^s8[xi( 9)]^s7[xi( 3)]; + k[7] = s5[xi( 5)]^s6[xi( 4)]^s7[xi(10)]^s8[xi(11)]^s8[xi( 7)]; + + z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)]; + z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)]; + z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)]; + z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)]; + k[8] = s5[zi( 3)]^s6[zi( 2)]^s7[zi(12)]^s8[zi(13)]^s5[zi( 9)]; + k[9] = s5[zi( 1)]^s6[zi( 0)]^s7[zi(14)]^s8[zi(15)]^s6[zi(12)]; + k[10]= s5[zi( 7)]^s6[zi( 6)]^s7[zi( 8)]^s8[zi( 9)]^s7[zi( 2)]; + k[11]= s5[zi( 5)]^s6[zi( 4)]^s7[zi(10)]^s8[zi(11)]^s8[zi( 6)]; + + x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)]; + x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)]; + x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)]; + x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)]; + k[12]= s5[xi( 8)]^s6[xi( 9)]^s7[xi( 7)]^s8[xi( 6)]^s5[xi( 3)]; + k[13]= s5[xi(10)]^s6[xi(11)]^s7[xi( 5)]^s8[xi( 4)]^s6[xi( 7)]; + k[14]= s5[xi(12)]^s6[xi(13)]^s7[xi( 3)]^s8[xi( 2)]^s7[xi( 8)]; + k[15]= s5[xi(14)]^s6[xi(15)]^s7[xi( 1)]^s8[xi( 0)]^s8[xi(13)]; + +#undef xi +#undef zi +} + + +static gcry_err_code_t +do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen ) +{ + static int initialized; + static const char* selftest_failed; + int i; + u32 x[4]; + u32 z[4]; + u32 k[16]; + + if( !initialized ) + { + initialized = 1; + selftest_failed = selftest(); + if( selftest_failed ) + log_error ("CAST5 selftest failed (%s).\n", selftest_failed ); + } + if( selftest_failed ) + return GPG_ERR_SELFTEST_FAILED; + + if( keylen != 16 ) + return GPG_ERR_INV_KEYLEN; + + x[0] = buf_get_be32(key + 0); + x[1] = buf_get_be32(key + 4); + x[2] = buf_get_be32(key + 8); + x[3] = buf_get_be32(key + 12); + + key_schedule( x, z, k ); + for(i=0; i < 16; i++ ) + c->Km[i] = k[i]; + key_schedule( x, z, k ); + for(i=0; i < 16; i++ ) + c->Kr[i] = k[i] & 0x1f; + +#ifdef USE_ARM_ASM + for (i = 0; i < 4; i++) + { + byte Kr_arm[4]; + + /* Convert rotate left to rotate right and add shift left + * by 2. */ + Kr_arm[0] = ((32 - c->Kr[4 * i + 0]) - 2) & 0x1f; + Kr_arm[1] = ((32 - c->Kr[4 * i + 1]) - 2) & 0x1f; + Kr_arm[2] = ((32 - c->Kr[4 * i + 2]) - 2) & 0x1f; + Kr_arm[3] = ((32 - c->Kr[4 * i + 3]) - 2) & 0x1f; + + /* Endian friendly store. */ + c->Kr_arm_enc[i] = Kr_arm[0] | + (Kr_arm[1] << 8) | + (Kr_arm[2] << 16) | + (Kr_arm[3] << 24); + c->Kr_arm_dec[i] = Kr_arm[3] | + (Kr_arm[2] << 8) | + (Kr_arm[1] << 16) | + (Kr_arm[0] << 24); + + wipememory(Kr_arm, sizeof(Kr_arm)); + } +#endif + + wipememory(x, sizeof x); + wipememory(z, sizeof z); + wipememory(k, sizeof k); + +#undef xi +#undef zi + return GPG_ERR_NO_ERROR; +} + +static gcry_err_code_t +cast_setkey (void *context, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops) +{ + CAST5_context *c = (CAST5_context *) context; + gcry_err_code_t rc = do_cast_setkey (c, key, keylen); + + /* Setup bulk encryption routines. */ + memset (bulk_ops, 0, sizeof(*bulk_ops)); + bulk_ops->cfb_dec = _gcry_cast5_cfb_dec; + bulk_ops->cbc_dec = _gcry_cast5_cbc_dec; + bulk_ops->ctr_enc = _gcry_cast5_ctr_enc; + + return rc; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_cast5 = + { + GCRY_CIPHER_CAST5, {0, 0}, + "CAST5", NULL, NULL, CAST5_BLOCKSIZE, 128, sizeof (CAST5_context), + cast_setkey, encrypt_block, decrypt_block + }; diff --git a/comm/third_party/libgcrypt/cipher/chacha20-aarch64.S b/comm/third_party/libgcrypt/cipher/chacha20-aarch64.S new file mode 100644 index 0000000000..b8f9724a37 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20-aarch64.S @@ -0,0 +1,648 @@ +/* chacha20-aarch64.S - ARMv8/AArch64 accelerated chacha20 blocks function + * + * Copyright (C) 2017-2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* + * Based on D. J. Bernstein reference implementation at + * http://cr.yp.to/chacha.html: + * + * chacha-regs.c version 20080118 + * D. J. Bernstein + * Public domain. + */ + +#include "asm-common-aarch64.h" + +#if defined(__AARCH64EL__) && \ + defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH64_NEON) && \ + defined(USE_CHACHA20) + +.cpu generic+simd + +.text + +#include "asm-poly1305-aarch64.h" + +/* register macros */ +#define INPUT x0 +#define DST x1 +#define SRC x2 +#define NBLKS x3 +#define ROUND x4 +#define INPUT_CTR x5 +#define INPUT_POS x6 +#define CTR x7 + +/* vector registers */ +#define X0 v16 +#define X1 v17 +#define X2 v18 +#define X3 v19 +#define X4 v20 +#define X5 v21 +#define X6 v22 +#define X7 v23 +#define X8 v24 +#define X9 v25 +#define X10 v26 +#define X11 v27 +#define X12 v28 +#define X13 v29 +#define X14 v30 +#define X15 v31 + +#define VCTR v0 +#define VTMP0 v1 +#define VTMP1 v2 +#define VTMP2 v3 +#define VTMP3 v4 +#define X12_TMP v5 +#define X13_TMP v6 +#define ROT8 v7 + +/********************************************************************** + helper macros + **********************************************************************/ + +#define _(...) __VA_ARGS__ + +#define vpunpckldq(s1, s2, dst) \ + zip1 dst.4s, s2.4s, s1.4s; + +#define vpunpckhdq(s1, s2, dst) \ + zip2 dst.4s, s2.4s, s1.4s; + +#define vpunpcklqdq(s1, s2, dst) \ + zip1 dst.2d, s2.2d, s1.2d; + +#define vpunpckhqdq(s1, s2, dst) \ + zip2 dst.2d, s2.2d, s1.2d; + +/* 4x4 32-bit integer matrix transpose */ +#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ + vpunpckhdq(x1, x0, t2); \ + vpunpckldq(x1, x0, x0); \ + \ + vpunpckldq(x3, x2, t1); \ + vpunpckhdq(x3, x2, x2); \ + \ + vpunpckhqdq(t1, x0, x1); \ + vpunpcklqdq(t1, x0, x0); \ + \ + vpunpckhqdq(x2, t2, x3); \ + vpunpcklqdq(x2, t2, x2); + +#define clear(x) \ + eor x.16b, x.16b, x.16b; + +/********************************************************************** + 4-way chacha20 + **********************************************************************/ + +#define XOR(d,s1,s2) \ + eor d.16b, s2.16b, s1.16b; + +#define PLUS(ds,s) \ + add ds.4s, ds.4s, s.4s; + +#define ROTATE4(dst1,dst2,dst3,dst4,c,src1,src2,src3,src4,iop1,iop2,iop3) \ + shl dst1.4s, src1.4s, #(c); \ + shl dst2.4s, src2.4s, #(c); \ + iop1; \ + shl dst3.4s, src3.4s, #(c); \ + shl dst4.4s, src4.4s, #(c); \ + iop2; \ + sri dst1.4s, src1.4s, #(32 - (c)); \ + sri dst2.4s, src2.4s, #(32 - (c)); \ + iop3; \ + sri dst3.4s, src3.4s, #(32 - (c)); \ + sri dst4.4s, src4.4s, #(32 - (c)); + +#define ROTATE4_8(dst1,dst2,dst3,dst4,src1,src2,src3,src4,iop1,iop2,iop3) \ + tbl dst1.16b, {src1.16b}, ROT8.16b; \ + iop1; \ + tbl dst2.16b, {src2.16b}, ROT8.16b; \ + iop2; \ + tbl dst3.16b, {src3.16b}, ROT8.16b; \ + iop3; \ + tbl dst4.16b, {src4.16b}, ROT8.16b; + +#define ROTATE4_16(dst1,dst2,dst3,dst4,src1,src2,src3,src4,iop1) \ + rev32 dst1.8h, src1.8h; \ + rev32 dst2.8h, src2.8h; \ + iop1; \ + rev32 dst3.8h, src3.8h; \ + rev32 dst4.8h, src4.8h; + +#define QUARTERROUND4(a1,b1,c1,d1,a2,b2,c2,d2,a3,b3,c3,d3,a4,b4,c4,d4,ign,tmp1,tmp2,tmp3,tmp4,\ + iop1,iop2,iop3,iop4,iop5,iop6,iop7,iop8,iop9,iop10,iop11,iop12,iop13,iop14,\ + iop15,iop16,iop17,iop18,iop19,iop20,iop21,iop22,iop23,iop24,iop25,iop26,\ + iop27,iop28,iop29) \ + PLUS(a1,b1); PLUS(a2,b2); iop1; \ + PLUS(a3,b3); PLUS(a4,b4); iop2; \ + XOR(tmp1,d1,a1); XOR(tmp2,d2,a2); iop3; \ + XOR(tmp3,d3,a3); XOR(tmp4,d4,a4); iop4; \ + ROTATE4_16(d1, d2, d3, d4, tmp1, tmp2, tmp3, tmp4, _(iop5)); \ + iop6; \ + PLUS(c1,d1); PLUS(c2,d2); iop7; \ + PLUS(c3,d3); PLUS(c4,d4); iop8; \ + XOR(tmp1,b1,c1); XOR(tmp2,b2,c2); iop9; \ + XOR(tmp3,b3,c3); XOR(tmp4,b4,c4); iop10; \ + ROTATE4(b1, b2, b3, b4, 12, tmp1, tmp2, tmp3, tmp4, \ + _(iop11), _(iop12), _(iop13)); iop14; \ + PLUS(a1,b1); PLUS(a2,b2); iop15; \ + PLUS(a3,b3); PLUS(a4,b4); iop16; \ + XOR(tmp1,d1,a1); XOR(tmp2,d2,a2); iop17; \ + XOR(tmp3,d3,a3); XOR(tmp4,d4,a4); iop18; \ + ROTATE4_8(d1, d2, d3, d4, tmp1, tmp2, tmp3, tmp4, \ + _(iop19), _(iop20), _(iop21)); iop22; \ + PLUS(c1,d1); PLUS(c2,d2); iop23; \ + PLUS(c3,d3); PLUS(c4,d4); iop24; \ + XOR(tmp1,b1,c1); XOR(tmp2,b2,c2); iop25; \ + XOR(tmp3,b3,c3); XOR(tmp4,b4,c4); iop26; \ + ROTATE4(b1, b2, b3, b4, 7, tmp1, tmp2, tmp3, tmp4, \ + _(iop27), _(iop28), _(iop29)); + +.align 4 +.globl _gcry_chacha20_aarch64_blocks4_data_inc_counter +_gcry_chacha20_aarch64_blocks4_data_inc_counter: + .long 0,1,2,3 + +.align 4 +.globl _gcry_chacha20_aarch64_blocks4_data_rot8 +_gcry_chacha20_aarch64_blocks4_data_rot8: + .byte 3,0,1,2 + .byte 7,4,5,6 + .byte 11,8,9,10 + .byte 15,12,13,14 + +.align 3 +.globl _gcry_chacha20_aarch64_blocks4 +ELF(.type _gcry_chacha20_aarch64_blocks4,%function;) + +_gcry_chacha20_aarch64_blocks4: + /* input: + * x0: input + * x1: dst + * x2: src + * x3: nblks (multiple of 4) + */ + CFI_STARTPROC() + + GET_DATA_POINTER(CTR, _gcry_chacha20_aarch64_blocks4_data_rot8); + add INPUT_CTR, INPUT, #(12*4); + ld1 {ROT8.16b}, [CTR]; + GET_DATA_POINTER(CTR, _gcry_chacha20_aarch64_blocks4_data_inc_counter); + mov INPUT_POS, INPUT; + ld1 {VCTR.16b}, [CTR]; + +.Loop4: + /* Construct counter vectors X12 and X13 */ + + ld1 {X15.16b}, [INPUT_CTR]; + mov ROUND, #20; + ld1 {VTMP1.16b-VTMP3.16b}, [INPUT_POS]; + + dup X12.4s, X15.s[0]; + dup X13.4s, X15.s[1]; + ldr CTR, [INPUT_CTR]; + add X12.4s, X12.4s, VCTR.4s; + dup X0.4s, VTMP1.s[0]; + dup X1.4s, VTMP1.s[1]; + dup X2.4s, VTMP1.s[2]; + dup X3.4s, VTMP1.s[3]; + dup X14.4s, X15.s[2]; + cmhi VTMP0.4s, VCTR.4s, X12.4s; + dup X15.4s, X15.s[3]; + add CTR, CTR, #4; /* Update counter */ + dup X4.4s, VTMP2.s[0]; + dup X5.4s, VTMP2.s[1]; + dup X6.4s, VTMP2.s[2]; + dup X7.4s, VTMP2.s[3]; + sub X13.4s, X13.4s, VTMP0.4s; + dup X8.4s, VTMP3.s[0]; + dup X9.4s, VTMP3.s[1]; + dup X10.4s, VTMP3.s[2]; + dup X11.4s, VTMP3.s[3]; + mov X12_TMP.16b, X12.16b; + mov X13_TMP.16b, X13.16b; + str CTR, [INPUT_CTR]; + +.Lround2: + subs ROUND, ROUND, #2 + QUARTERROUND4(X0, X4, X8, X12, X1, X5, X9, X13, + X2, X6, X10, X14, X3, X7, X11, X15, + tmp:=,VTMP0,VTMP1,VTMP2,VTMP3, + ,,,,,,,,,,,,,,,,,,,,,,,,,,,,) + QUARTERROUND4(X0, X5, X10, X15, X1, X6, X11, X12, + X2, X7, X8, X13, X3, X4, X9, X14, + tmp:=,VTMP0,VTMP1,VTMP2,VTMP3, + ,,,,,,,,,,,,,,,,,,,,,,,,,,,,) + b.ne .Lround2; + + ld1 {VTMP0.16b, VTMP1.16b}, [INPUT_POS], #32; + + PLUS(X12, X12_TMP); /* INPUT + 12 * 4 + counter */ + PLUS(X13, X13_TMP); /* INPUT + 13 * 4 + counter */ + + dup VTMP2.4s, VTMP0.s[0]; /* INPUT + 0 * 4 */ + dup VTMP3.4s, VTMP0.s[1]; /* INPUT + 1 * 4 */ + dup X12_TMP.4s, VTMP0.s[2]; /* INPUT + 2 * 4 */ + dup X13_TMP.4s, VTMP0.s[3]; /* INPUT + 3 * 4 */ + PLUS(X0, VTMP2); + PLUS(X1, VTMP3); + PLUS(X2, X12_TMP); + PLUS(X3, X13_TMP); + + dup VTMP2.4s, VTMP1.s[0]; /* INPUT + 4 * 4 */ + dup VTMP3.4s, VTMP1.s[1]; /* INPUT + 5 * 4 */ + dup X12_TMP.4s, VTMP1.s[2]; /* INPUT + 6 * 4 */ + dup X13_TMP.4s, VTMP1.s[3]; /* INPUT + 7 * 4 */ + ld1 {VTMP0.16b, VTMP1.16b}, [INPUT_POS]; + mov INPUT_POS, INPUT; + PLUS(X4, VTMP2); + PLUS(X5, VTMP3); + PLUS(X6, X12_TMP); + PLUS(X7, X13_TMP); + + dup VTMP2.4s, VTMP0.s[0]; /* INPUT + 8 * 4 */ + dup VTMP3.4s, VTMP0.s[1]; /* INPUT + 9 * 4 */ + dup X12_TMP.4s, VTMP0.s[2]; /* INPUT + 10 * 4 */ + dup X13_TMP.4s, VTMP0.s[3]; /* INPUT + 11 * 4 */ + dup VTMP0.4s, VTMP1.s[2]; /* INPUT + 14 * 4 */ + dup VTMP1.4s, VTMP1.s[3]; /* INPUT + 15 * 4 */ + PLUS(X8, VTMP2); + PLUS(X9, VTMP3); + PLUS(X10, X12_TMP); + PLUS(X11, X13_TMP); + PLUS(X14, VTMP0); + PLUS(X15, VTMP1); + + transpose_4x4(X0, X1, X2, X3, VTMP0, VTMP1, VTMP2); + transpose_4x4(X4, X5, X6, X7, VTMP0, VTMP1, VTMP2); + transpose_4x4(X8, X9, X10, X11, VTMP0, VTMP1, VTMP2); + transpose_4x4(X12, X13, X14, X15, VTMP0, VTMP1, VTMP2); + + subs NBLKS, NBLKS, #4; + + ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64; + ld1 {X12_TMP.16b-X13_TMP.16b}, [SRC], #32; + eor VTMP0.16b, X0.16b, VTMP0.16b; + eor VTMP1.16b, X4.16b, VTMP1.16b; + eor VTMP2.16b, X8.16b, VTMP2.16b; + eor VTMP3.16b, X12.16b, VTMP3.16b; + eor X12_TMP.16b, X1.16b, X12_TMP.16b; + eor X13_TMP.16b, X5.16b, X13_TMP.16b; + st1 {VTMP0.16b-VTMP3.16b}, [DST], #64; + ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64; + st1 {X12_TMP.16b-X13_TMP.16b}, [DST], #32; + ld1 {X12_TMP.16b-X13_TMP.16b}, [SRC], #32; + eor VTMP0.16b, X9.16b, VTMP0.16b; + eor VTMP1.16b, X13.16b, VTMP1.16b; + eor VTMP2.16b, X2.16b, VTMP2.16b; + eor VTMP3.16b, X6.16b, VTMP3.16b; + eor X12_TMP.16b, X10.16b, X12_TMP.16b; + eor X13_TMP.16b, X14.16b, X13_TMP.16b; + st1 {VTMP0.16b-VTMP3.16b}, [DST], #64; + ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64; + st1 {X12_TMP.16b-X13_TMP.16b}, [DST], #32; + eor VTMP0.16b, X3.16b, VTMP0.16b; + eor VTMP1.16b, X7.16b, VTMP1.16b; + eor VTMP2.16b, X11.16b, VTMP2.16b; + eor VTMP3.16b, X15.16b, VTMP3.16b; + st1 {VTMP0.16b-VTMP3.16b}, [DST], #64; + + b.ne .Loop4; + + /* clear the used vector registers and stack */ + clear(VTMP0); + clear(VTMP1); + clear(VTMP2); + clear(VTMP3); + clear(X12_TMP); + clear(X13_TMP); + clear(X0); + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X8); + clear(X9); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + clear(X14); + clear(X15); + + eor x0, x0, x0 + ret + CFI_ENDPROC() +ELF(.size _gcry_chacha20_aarch64_blocks4, .-_gcry_chacha20_aarch64_blocks4;) + +/********************************************************************** + 4-way stitched chacha20-poly1305 + **********************************************************************/ + +.align 3 +.globl _gcry_chacha20_poly1305_aarch64_blocks4 +ELF(.type _gcry_chacha20_poly1305_aarch64_blocks4,%function;) + +_gcry_chacha20_poly1305_aarch64_blocks4: + /* input: + * x0: input + * x1: dst + * x2: src + * x3: nblks (multiple of 4) + * x4: poly1305-state + * x5: poly1305-src + */ + CFI_STARTPROC() + POLY1305_PUSH_REGS() + + mov POLY_RSTATE, x4; + mov POLY_RSRC, x5; + + GET_DATA_POINTER(CTR, _gcry_chacha20_aarch64_blocks4_data_rot8); + add INPUT_CTR, INPUT, #(12*4); + ld1 {ROT8.16b}, [CTR]; + GET_DATA_POINTER(CTR, _gcry_chacha20_aarch64_blocks4_data_inc_counter); + mov INPUT_POS, INPUT; + ld1 {VCTR.16b}, [CTR]; + + POLY1305_LOAD_STATE() + +.Loop_poly4: + /* Construct counter vectors X12 and X13 */ + + ld1 {X15.16b}, [INPUT_CTR]; + ld1 {VTMP1.16b-VTMP3.16b}, [INPUT_POS]; + + dup X12.4s, X15.s[0]; + dup X13.4s, X15.s[1]; + ldr CTR, [INPUT_CTR]; + add X12.4s, X12.4s, VCTR.4s; + dup X0.4s, VTMP1.s[0]; + dup X1.4s, VTMP1.s[1]; + dup X2.4s, VTMP1.s[2]; + dup X3.4s, VTMP1.s[3]; + dup X14.4s, X15.s[2]; + cmhi VTMP0.4s, VCTR.4s, X12.4s; + dup X15.4s, X15.s[3]; + add CTR, CTR, #4; /* Update counter */ + dup X4.4s, VTMP2.s[0]; + dup X5.4s, VTMP2.s[1]; + dup X6.4s, VTMP2.s[2]; + dup X7.4s, VTMP2.s[3]; + sub X13.4s, X13.4s, VTMP0.4s; + dup X8.4s, VTMP3.s[0]; + dup X9.4s, VTMP3.s[1]; + dup X10.4s, VTMP3.s[2]; + dup X11.4s, VTMP3.s[3]; + mov X12_TMP.16b, X12.16b; + mov X13_TMP.16b, X13.16b; + str CTR, [INPUT_CTR]; + + mov ROUND, #20 +.Lround4_with_poly1305_outer: + mov POLY_CHACHA_ROUND, #6; +.Lround4_with_poly1305_inner1: + POLY1305_BLOCK_PART1(0 * 16) + QUARTERROUND4(X0, X4, X8, X12, X1, X5, X9, X13, + X2, X6, X10, X14, X3, X7, X11, X15, + tmp:=,VTMP0,VTMP1,VTMP2,VTMP3, + POLY1305_BLOCK_PART2(0 * 16), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8(), + POLY1305_BLOCK_PART9(), + POLY1305_BLOCK_PART10(), + POLY1305_BLOCK_PART11(), + POLY1305_BLOCK_PART12(), + POLY1305_BLOCK_PART13(), + POLY1305_BLOCK_PART14(), + POLY1305_BLOCK_PART15(), + POLY1305_BLOCK_PART16(), + POLY1305_BLOCK_PART17(), + POLY1305_BLOCK_PART18(), + POLY1305_BLOCK_PART19(), + POLY1305_BLOCK_PART20(), + POLY1305_BLOCK_PART21(), + POLY1305_BLOCK_PART22(), + POLY1305_BLOCK_PART23(), + POLY1305_BLOCK_PART24(), + POLY1305_BLOCK_PART25(), + POLY1305_BLOCK_PART26(), + POLY1305_BLOCK_PART27(), + POLY1305_BLOCK_PART28(), + POLY1305_BLOCK_PART29(), + POLY1305_BLOCK_PART1(1 * 16)) + POLY1305_BLOCK_PART2(1 * 16) + QUARTERROUND4(X0, X5, X10, X15, X1, X6, X11, X12, + X2, X7, X8, X13, X3, X4, X9, X14, + tmp:=,VTMP0,VTMP1,VTMP2,VTMP3, + _(add POLY_RSRC, POLY_RSRC, #(2*16)), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8(), + POLY1305_BLOCK_PART9(), + POLY1305_BLOCK_PART10(), + POLY1305_BLOCK_PART11(), + POLY1305_BLOCK_PART12(), + POLY1305_BLOCK_PART13(), + POLY1305_BLOCK_PART14(), + POLY1305_BLOCK_PART15(), + POLY1305_BLOCK_PART16(), + POLY1305_BLOCK_PART17(), + POLY1305_BLOCK_PART18(), + POLY1305_BLOCK_PART19(), + POLY1305_BLOCK_PART20(), + POLY1305_BLOCK_PART21(), + POLY1305_BLOCK_PART22(), + POLY1305_BLOCK_PART23(), + POLY1305_BLOCK_PART24(), + POLY1305_BLOCK_PART25(), + POLY1305_BLOCK_PART26(), + POLY1305_BLOCK_PART27(), + POLY1305_BLOCK_PART28(), + POLY1305_BLOCK_PART29(), + _(subs POLY_CHACHA_ROUND, POLY_CHACHA_ROUND, #2)); + b.ne .Lround4_with_poly1305_inner1; + + mov POLY_CHACHA_ROUND, #4; +.Lround4_with_poly1305_inner2: + POLY1305_BLOCK_PART1(0 * 16) + QUARTERROUND4(X0, X4, X8, X12, X1, X5, X9, X13, + X2, X6, X10, X14, X3, X7, X11, X15, + tmp:=,VTMP0,VTMP1,VTMP2,VTMP3,, + POLY1305_BLOCK_PART2(0 * 16),, + _(add POLY_RSRC, POLY_RSRC, #(1*16)),, + POLY1305_BLOCK_PART3(),, + POLY1305_BLOCK_PART4(),, + POLY1305_BLOCK_PART5(),, + POLY1305_BLOCK_PART6(),, + POLY1305_BLOCK_PART7(),, + POLY1305_BLOCK_PART8(),, + POLY1305_BLOCK_PART9(),, + POLY1305_BLOCK_PART10(),, + POLY1305_BLOCK_PART11(),, + POLY1305_BLOCK_PART12(),, + POLY1305_BLOCK_PART13(),, + POLY1305_BLOCK_PART14(),) + POLY1305_BLOCK_PART15() + QUARTERROUND4(X0, X5, X10, X15, X1, X6, X11, X12, + X2, X7, X8, X13, X3, X4, X9, X14, + tmp:=,VTMP0,VTMP1,VTMP2,VTMP3, + POLY1305_BLOCK_PART16(),, + POLY1305_BLOCK_PART17(),, + POLY1305_BLOCK_PART18(),, + POLY1305_BLOCK_PART19(),, + POLY1305_BLOCK_PART20(),, + POLY1305_BLOCK_PART21(),, + POLY1305_BLOCK_PART22(),, + POLY1305_BLOCK_PART23(),, + POLY1305_BLOCK_PART24(),, + POLY1305_BLOCK_PART25(),, + POLY1305_BLOCK_PART26(),, + POLY1305_BLOCK_PART27(),, + POLY1305_BLOCK_PART28(),, + POLY1305_BLOCK_PART29(), + _(subs POLY_CHACHA_ROUND, POLY_CHACHA_ROUND, #2),) + b.ne .Lround4_with_poly1305_inner2; + + subs ROUND, ROUND, #10 + b.ne .Lround4_with_poly1305_outer; + + ld1 {VTMP0.16b, VTMP1.16b}, [INPUT_POS], #32; + + PLUS(X12, X12_TMP); /* INPUT + 12 * 4 + counter */ + PLUS(X13, X13_TMP); /* INPUT + 13 * 4 + counter */ + + dup VTMP2.4s, VTMP0.s[0]; /* INPUT + 0 * 4 */ + dup VTMP3.4s, VTMP0.s[1]; /* INPUT + 1 * 4 */ + dup X12_TMP.4s, VTMP0.s[2]; /* INPUT + 2 * 4 */ + dup X13_TMP.4s, VTMP0.s[3]; /* INPUT + 3 * 4 */ + PLUS(X0, VTMP2); + PLUS(X1, VTMP3); + PLUS(X2, X12_TMP); + PLUS(X3, X13_TMP); + + dup VTMP2.4s, VTMP1.s[0]; /* INPUT + 4 * 4 */ + dup VTMP3.4s, VTMP1.s[1]; /* INPUT + 5 * 4 */ + dup X12_TMP.4s, VTMP1.s[2]; /* INPUT + 6 * 4 */ + dup X13_TMP.4s, VTMP1.s[3]; /* INPUT + 7 * 4 */ + ld1 {VTMP0.16b, VTMP1.16b}, [INPUT_POS]; + mov INPUT_POS, INPUT; + PLUS(X4, VTMP2); + PLUS(X5, VTMP3); + PLUS(X6, X12_TMP); + PLUS(X7, X13_TMP); + + dup VTMP2.4s, VTMP0.s[0]; /* INPUT + 8 * 4 */ + dup VTMP3.4s, VTMP0.s[1]; /* INPUT + 9 * 4 */ + dup X12_TMP.4s, VTMP0.s[2]; /* INPUT + 10 * 4 */ + dup X13_TMP.4s, VTMP0.s[3]; /* INPUT + 11 * 4 */ + dup VTMP0.4s, VTMP1.s[2]; /* INPUT + 14 * 4 */ + dup VTMP1.4s, VTMP1.s[3]; /* INPUT + 15 * 4 */ + PLUS(X8, VTMP2); + PLUS(X9, VTMP3); + PLUS(X10, X12_TMP); + PLUS(X11, X13_TMP); + PLUS(X14, VTMP0); + PLUS(X15, VTMP1); + + transpose_4x4(X0, X1, X2, X3, VTMP0, VTMP1, VTMP2); + transpose_4x4(X4, X5, X6, X7, VTMP0, VTMP1, VTMP2); + transpose_4x4(X8, X9, X10, X11, VTMP0, VTMP1, VTMP2); + transpose_4x4(X12, X13, X14, X15, VTMP0, VTMP1, VTMP2); + + subs NBLKS, NBLKS, #4; + + ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64; + ld1 {X12_TMP.16b-X13_TMP.16b}, [SRC], #32; + eor VTMP0.16b, X0.16b, VTMP0.16b; + eor VTMP1.16b, X4.16b, VTMP1.16b; + eor VTMP2.16b, X8.16b, VTMP2.16b; + eor VTMP3.16b, X12.16b, VTMP3.16b; + eor X12_TMP.16b, X1.16b, X12_TMP.16b; + eor X13_TMP.16b, X5.16b, X13_TMP.16b; + st1 {VTMP0.16b-VTMP3.16b}, [DST], #64; + ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64; + st1 {X12_TMP.16b-X13_TMP.16b}, [DST], #32; + ld1 {X12_TMP.16b-X13_TMP.16b}, [SRC], #32; + eor VTMP0.16b, X9.16b, VTMP0.16b; + eor VTMP1.16b, X13.16b, VTMP1.16b; + eor VTMP2.16b, X2.16b, VTMP2.16b; + eor VTMP3.16b, X6.16b, VTMP3.16b; + eor X12_TMP.16b, X10.16b, X12_TMP.16b; + eor X13_TMP.16b, X14.16b, X13_TMP.16b; + st1 {VTMP0.16b-VTMP3.16b}, [DST], #64; + ld1 {VTMP0.16b-VTMP3.16b}, [SRC], #64; + st1 {X12_TMP.16b-X13_TMP.16b}, [DST], #32; + eor VTMP0.16b, X3.16b, VTMP0.16b; + eor VTMP1.16b, X7.16b, VTMP1.16b; + eor VTMP2.16b, X11.16b, VTMP2.16b; + eor VTMP3.16b, X15.16b, VTMP3.16b; + st1 {VTMP0.16b-VTMP3.16b}, [DST], #64; + + b.ne .Loop_poly4; + + POLY1305_STORE_STATE() + + /* clear the used vector registers and stack */ + clear(VTMP0); + clear(VTMP1); + clear(VTMP2); + clear(VTMP3); + clear(X12_TMP); + clear(X13_TMP); + clear(X0); + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X8); + clear(X9); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + clear(X14); + clear(X15); + + eor x0, x0, x0 + POLY1305_POP_REGS() + ret + CFI_ENDPROC() +ELF(.size _gcry_chacha20_poly1305_aarch64_blocks4, .-_gcry_chacha20_poly1305_aarch64_blocks4;) + +#endif diff --git a/comm/third_party/libgcrypt/cipher/chacha20-amd64-avx2.S b/comm/third_party/libgcrypt/cipher/chacha20-amd64-avx2.S new file mode 100644 index 0000000000..51e107be83 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20-amd64-avx2.S @@ -0,0 +1,601 @@ +/* chacha20-amd64-avx2.S - AVX2 implementation of ChaCha20 cipher + * + * Copyright (C) 2017-2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* + * Based on D. J. Bernstein reference implementation at + * http://cr.yp.to/chacha.html: + * + * chacha-regs.c version 20080118 + * D. J. Bernstein + * Public domain. + */ + +#ifdef __x86_64 +#include +#if defined(HAVE_GCC_INLINE_ASM_AVX2) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +.text + +#include "asm-common-amd64.h" +#include "asm-poly1305-amd64.h" + +/* register macros */ +#define INPUT %rdi +#define DST %rsi +#define SRC %rdx +#define NBLKS %rcx +#define ROUND %eax + +/* stack structure */ +#define STACK_VEC_X12 (32) +#define STACK_VEC_X13 (32 + STACK_VEC_X12) +#define STACK_TMP (32 + STACK_VEC_X13) +#define STACK_TMP1 (32 + STACK_TMP) + +#define STACK_MAX (32 + STACK_TMP1) + +/* vector registers */ +#define X0 %ymm0 +#define X1 %ymm1 +#define X2 %ymm2 +#define X3 %ymm3 +#define X4 %ymm4 +#define X5 %ymm5 +#define X6 %ymm6 +#define X7 %ymm7 +#define X8 %ymm8 +#define X9 %ymm9 +#define X10 %ymm10 +#define X11 %ymm11 +#define X12 %ymm12 +#define X13 %ymm13 +#define X14 %ymm14 +#define X15 %ymm15 + +#define X0h %xmm0 +#define X1h %xmm1 +#define X2h %xmm2 +#define X3h %xmm3 +#define X4h %xmm4 +#define X5h %xmm5 +#define X6h %xmm6 +#define X7h %xmm7 +#define X8h %xmm8 +#define X9h %xmm9 +#define X10h %xmm10 +#define X11h %xmm11 +#define X12h %xmm12 +#define X13h %xmm13 +#define X14h %xmm14 +#define X15h %xmm15 + +/********************************************************************** + helper macros + **********************************************************************/ + +/* 4x4 32-bit integer matrix transpose */ +#define transpose_4x4(x0,x1,x2,x3,t1,t2) \ + vpunpckhdq x1, x0, t2; \ + vpunpckldq x1, x0, x0; \ + \ + vpunpckldq x3, x2, t1; \ + vpunpckhdq x3, x2, x2; \ + \ + vpunpckhqdq t1, x0, x1; \ + vpunpcklqdq t1, x0, x0; \ + \ + vpunpckhqdq x2, t2, x3; \ + vpunpcklqdq x2, t2, x2; + +/* 2x2 128-bit matrix transpose */ +#define transpose_16byte_2x2(x0,x1,t1) \ + vmovdqa x0, t1; \ + vperm2i128 $0x20, x1, x0, x0; \ + vperm2i128 $0x31, x1, t1, x1; + +/* xor register with unaligned src and save to unaligned dst */ +#define xor_src_dst(dst, src, offset, xreg) \ + vpxor offset(src), xreg, xreg; \ + vmovdqu xreg, offset(dst); + +/********************************************************************** + 8-way chacha20 + **********************************************************************/ + +#define ROTATE2(v1,v2,c,tmp) \ + vpsrld $(32 - (c)), v1, tmp; \ + vpslld $(c), v1, v1; \ + vpaddb tmp, v1, v1; \ + vpsrld $(32 - (c)), v2, tmp; \ + vpslld $(c), v2, v2; \ + vpaddb tmp, v2, v2; + +#define ROTATE_SHUF_2(v1,v2,shuf) \ + vpshufb shuf, v1, v1; \ + vpshufb shuf, v2, v2; + +#define XOR(ds,s) \ + vpxor s, ds, ds; + +#define PLUS(ds,s) \ + vpaddd s, ds, ds; + +#define QUARTERROUND2(a1,b1,c1,d1,a2,b2,c2,d2,ign,tmp1,\ + interleave_op1,interleave_op2,\ + interleave_op3,interleave_op4) \ + vbroadcasti128 .Lshuf_rol16 rRIP, tmp1; \ + interleave_op1; \ + PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2); \ + ROTATE_SHUF_2(d1, d2, tmp1); \ + interleave_op2; \ + PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2); \ + ROTATE2(b1, b2, 12, tmp1); \ + vbroadcasti128 .Lshuf_rol8 rRIP, tmp1; \ + interleave_op3; \ + PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2); \ + ROTATE_SHUF_2(d1, d2, tmp1); \ + interleave_op4; \ + PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2); \ + ROTATE2(b1, b2, 7, tmp1); + +.align 32 +chacha20_data: +.Lshuf_rol16: + .byte 2,3,0,1,6,7,4,5,10,11,8,9,14,15,12,13 +.Lshuf_rol8: + .byte 3,0,1,2,7,4,5,6,11,8,9,10,15,12,13,14 +.Linc_counter: + .byte 0,1,2,3,4,5,6,7 +.Lunsigned_cmp: + .long 0x80000000 + +.align 8 +.globl _gcry_chacha20_amd64_avx2_blocks8 +ELF(.type _gcry_chacha20_amd64_avx2_blocks8,@function;) + +_gcry_chacha20_amd64_avx2_blocks8: + /* input: + * %rdi: input + * %rsi: dst + * %rdx: src + * %rcx: nblks (multiple of 8) + */ + CFI_STARTPROC(); + + vzeroupper; + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + subq $STACK_MAX, %rsp; + andq $~31, %rsp; + +.Loop8: + mov $20, ROUND; + + /* Construct counter vectors X12 and X13 */ + vpmovzxbd .Linc_counter rRIP, X0; + vpbroadcastd .Lunsigned_cmp rRIP, X2; + vpbroadcastd (12 * 4)(INPUT), X12; + vpbroadcastd (13 * 4)(INPUT), X13; + vpaddd X0, X12, X12; + vpxor X2, X0, X0; + vpxor X2, X12, X1; + vpcmpgtd X1, X0, X0; + vpsubd X0, X13, X13; + vmovdqa X12, (STACK_VEC_X12)(%rsp); + vmovdqa X13, (STACK_VEC_X13)(%rsp); + + /* Load vectors */ + vpbroadcastd (0 * 4)(INPUT), X0; + vpbroadcastd (1 * 4)(INPUT), X1; + vpbroadcastd (2 * 4)(INPUT), X2; + vpbroadcastd (3 * 4)(INPUT), X3; + vpbroadcastd (4 * 4)(INPUT), X4; + vpbroadcastd (5 * 4)(INPUT), X5; + vpbroadcastd (6 * 4)(INPUT), X6; + vpbroadcastd (7 * 4)(INPUT), X7; + vpbroadcastd (8 * 4)(INPUT), X8; + vpbroadcastd (9 * 4)(INPUT), X9; + vpbroadcastd (10 * 4)(INPUT), X10; + vpbroadcastd (11 * 4)(INPUT), X11; + vpbroadcastd (14 * 4)(INPUT), X14; + vpbroadcastd (15 * 4)(INPUT), X15; + vmovdqa X15, (STACK_TMP)(%rsp); + +.Lround2: + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X15,,,,) + vmovdqa (STACK_TMP)(%rsp), X15; + vmovdqa X8, (STACK_TMP)(%rsp); + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8,,,,) + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8,,,,) + vmovdqa (STACK_TMP)(%rsp), X8; + vmovdqa X15, (STACK_TMP)(%rsp); + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X15,,,,) + sub $2, ROUND; + jnz .Lround2; + + vmovdqa X8, (STACK_TMP1)(%rsp); + + /* tmp := X15 */ + vpbroadcastd (0 * 4)(INPUT), X15; + PLUS(X0, X15); + vpbroadcastd (1 * 4)(INPUT), X15; + PLUS(X1, X15); + vpbroadcastd (2 * 4)(INPUT), X15; + PLUS(X2, X15); + vpbroadcastd (3 * 4)(INPUT), X15; + PLUS(X3, X15); + vpbroadcastd (4 * 4)(INPUT), X15; + PLUS(X4, X15); + vpbroadcastd (5 * 4)(INPUT), X15; + PLUS(X5, X15); + vpbroadcastd (6 * 4)(INPUT), X15; + PLUS(X6, X15); + vpbroadcastd (7 * 4)(INPUT), X15; + PLUS(X7, X15); + transpose_4x4(X0, X1, X2, X3, X8, X15); + transpose_4x4(X4, X5, X6, X7, X8, X15); + vmovdqa (STACK_TMP1)(%rsp), X8; + transpose_16byte_2x2(X0, X4, X15); + transpose_16byte_2x2(X1, X5, X15); + transpose_16byte_2x2(X2, X6, X15); + transpose_16byte_2x2(X3, X7, X15); + vmovdqa (STACK_TMP)(%rsp), X15; + xor_src_dst(DST, SRC, (64 * 0 + 16 * 0), X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 0), X1); + vpbroadcastd (8 * 4)(INPUT), X0; + PLUS(X8, X0); + vpbroadcastd (9 * 4)(INPUT), X0; + PLUS(X9, X0); + vpbroadcastd (10 * 4)(INPUT), X0; + PLUS(X10, X0); + vpbroadcastd (11 * 4)(INPUT), X0; + PLUS(X11, X0); + vmovdqa (STACK_VEC_X12)(%rsp), X0; + PLUS(X12, X0); + vmovdqa (STACK_VEC_X13)(%rsp), X0; + PLUS(X13, X0); + vpbroadcastd (14 * 4)(INPUT), X0; + PLUS(X14, X0); + vpbroadcastd (15 * 4)(INPUT), X0; + PLUS(X15, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 0), X2); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 0), X3); + + /* Update counter */ + addq $8, (12 * 4)(INPUT); + + transpose_4x4(X8, X9, X10, X11, X0, X1); + transpose_4x4(X12, X13, X14, X15, X0, X1); + xor_src_dst(DST, SRC, (64 * 4 + 16 * 0), X4); + xor_src_dst(DST, SRC, (64 * 5 + 16 * 0), X5); + transpose_16byte_2x2(X8, X12, X0); + transpose_16byte_2x2(X9, X13, X0); + transpose_16byte_2x2(X10, X14, X0); + transpose_16byte_2x2(X11, X15, X0); + xor_src_dst(DST, SRC, (64 * 6 + 16 * 0), X6); + xor_src_dst(DST, SRC, (64 * 7 + 16 * 0), X7); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 2), X8); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 2), X9); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 2), X10); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 2), X11); + xor_src_dst(DST, SRC, (64 * 4 + 16 * 2), X12); + xor_src_dst(DST, SRC, (64 * 5 + 16 * 2), X13); + xor_src_dst(DST, SRC, (64 * 6 + 16 * 2), X14); + xor_src_dst(DST, SRC, (64 * 7 + 16 * 2), X15); + + sub $8, NBLKS; + lea (8 * 64)(DST), DST; + lea (8 * 64)(SRC), SRC; + jnz .Loop8; + + /* clear the used vector registers and stack */ + vpxor X0, X0, X0; + vmovdqa X0, (STACK_VEC_X12)(%rsp); + vmovdqa X0, (STACK_VEC_X13)(%rsp); + vmovdqa X0, (STACK_TMP)(%rsp); + vmovdqa X0, (STACK_TMP1)(%rsp); + vzeroall; + + /* eax zeroed by round loop. */ + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_amd64_avx2_blocks8, + .-_gcry_chacha20_amd64_avx2_blocks8;) + +/********************************************************************** + 8-way stitched chacha20-poly1305 + **********************************************************************/ + +#define _ /*_*/ + +.align 8 +.globl _gcry_chacha20_poly1305_amd64_avx2_blocks8 +ELF(.type _gcry_chacha20_poly1305_amd64_avx2_blocks8,@function;) + +_gcry_chacha20_poly1305_amd64_avx2_blocks8: + /* input: + * %rdi: input + * %rsi: dst + * %rdx: src + * %rcx: nblks (multiple of 8) + * %r9: poly1305-state + * %r8: poly1305-src + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + vzeroupper; + + subq $(9 * 8) + STACK_MAX + 32, %rsp; + andq $~31, %rsp; + + movq %rbx, (STACK_MAX + 0 * 8)(%rsp); + movq %r12, (STACK_MAX + 1 * 8)(%rsp); + movq %r13, (STACK_MAX + 2 * 8)(%rsp); + movq %r14, (STACK_MAX + 3 * 8)(%rsp); + movq %r15, (STACK_MAX + 4 * 8)(%rsp); + CFI_REG_ON_STACK(rbx, STACK_MAX + 0 * 8); + CFI_REG_ON_STACK(r12, STACK_MAX + 1 * 8); + CFI_REG_ON_STACK(r13, STACK_MAX + 2 * 8); + CFI_REG_ON_STACK(r14, STACK_MAX + 3 * 8); + CFI_REG_ON_STACK(r15, STACK_MAX + 4 * 8); + + movq %rdx, (STACK_MAX + 5 * 8)(%rsp); # SRC + movq %rsi, (STACK_MAX + 6 * 8)(%rsp); # DST + movq %rcx, (STACK_MAX + 7 * 8)(%rsp); # NBLKS + + /* Load state */ + POLY1305_LOAD_STATE(); + +.Loop_poly8: + + /* Construct counter vectors X12 and X13 */ + vpmovzxbd .Linc_counter rRIP, X0; + vpbroadcastd .Lunsigned_cmp rRIP, X2; + vpbroadcastd (12 * 4)(INPUT), X12; + vpbroadcastd (13 * 4)(INPUT), X13; + vpaddd X0, X12, X12; + vpxor X2, X0, X0; + vpxor X2, X12, X1; + vpcmpgtd X1, X0, X0; + vpsubd X0, X13, X13; + vmovdqa X12, (STACK_VEC_X12)(%rsp); + vmovdqa X13, (STACK_VEC_X13)(%rsp); + + /* Load vectors */ + vpbroadcastd (0 * 4)(INPUT), X0; + vpbroadcastd (1 * 4)(INPUT), X1; + vpbroadcastd (2 * 4)(INPUT), X2; + vpbroadcastd (3 * 4)(INPUT), X3; + vpbroadcastd (4 * 4)(INPUT), X4; + vpbroadcastd (5 * 4)(INPUT), X5; + vpbroadcastd (6 * 4)(INPUT), X6; + vpbroadcastd (7 * 4)(INPUT), X7; + vpbroadcastd (8 * 4)(INPUT), X8; + vpbroadcastd (9 * 4)(INPUT), X9; + vpbroadcastd (10 * 4)(INPUT), X10; + vpbroadcastd (11 * 4)(INPUT), X11; + vpbroadcastd (14 * 4)(INPUT), X14; + vpbroadcastd (15 * 4)(INPUT), X15; + vmovdqa X15, (STACK_TMP)(%rsp); + + /* Process eight ChaCha20 blocks and 32 Poly1305 blocks. */ + + movl $20, (STACK_MAX + 8 * 8 + 4)(%rsp); +.Lround8_with_poly1305_outer: + movl $6, (STACK_MAX + 8 * 8)(%rsp); +.Lround8_with_poly1305_inner1: + /* rounds 0-5 & 10-15 */ + POLY1305_BLOCK_PART1(0 * 16) + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X15, + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5()) + vmovdqa (STACK_TMP)(%rsp), X15; + vmovdqa X8, (STACK_TMP)(%rsp); + POLY1305_BLOCK_PART1(1 * 16) + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8, + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5()) + POLY1305_BLOCK_PART1(2 * 16) + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8, + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5()) + vmovdqa (STACK_TMP)(%rsp), X8; + vmovdqa X15, (STACK_TMP)(%rsp); + POLY1305_BLOCK_PART1(3 * 16) + lea (4 * 16)(POLY_RSRC), POLY_RSRC; + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X15, + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5()) + + subl $2, (STACK_MAX + 8 * 8)(%rsp); + jnz .Lround8_with_poly1305_inner1; + + movl $4, (STACK_MAX + 8 * 8)(%rsp); +.Lround8_with_poly1305_inner2: + /* rounds 6-9 & 16-19 */ + POLY1305_BLOCK_PART1(0 * 16) + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X15, + POLY1305_BLOCK_PART2(), + _, + POLY1305_BLOCK_PART3(), + _) + vmovdqa (STACK_TMP)(%rsp), X15; + vmovdqa X8, (STACK_TMP)(%rsp); + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8, + _, + POLY1305_BLOCK_PART4(), + _, + POLY1305_BLOCK_PART5()) + POLY1305_BLOCK_PART1(1 * 16); + lea (2 * 16)(POLY_RSRC), POLY_RSRC; + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8, + _, + POLY1305_BLOCK_PART2(), + _, + POLY1305_BLOCK_PART3()) + vmovdqa (STACK_TMP)(%rsp), X8; + vmovdqa X15, (STACK_TMP)(%rsp); + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X15, + POLY1305_BLOCK_PART4(), + _, + POLY1305_BLOCK_PART5(), + _) + + subl $2, (STACK_MAX + 8 * 8)(%rsp); + jnz .Lround8_with_poly1305_inner2; + + subl $10, (STACK_MAX + 8 * 8 + 4)(%rsp); + jnz .Lround8_with_poly1305_outer; + + movq (STACK_MAX + 5 * 8)(%rsp), SRC; + movq (STACK_MAX + 6 * 8)(%rsp), DST; + + vmovdqa X8, (STACK_TMP1)(%rsp); + + /* tmp := X15 */ + vpbroadcastd (0 * 4)(INPUT), X15; + PLUS(X0, X15); + vpbroadcastd (1 * 4)(INPUT), X15; + PLUS(X1, X15); + vpbroadcastd (2 * 4)(INPUT), X15; + PLUS(X2, X15); + vpbroadcastd (3 * 4)(INPUT), X15; + PLUS(X3, X15); + vpbroadcastd (4 * 4)(INPUT), X15; + PLUS(X4, X15); + vpbroadcastd (5 * 4)(INPUT), X15; + PLUS(X5, X15); + vpbroadcastd (6 * 4)(INPUT), X15; + PLUS(X6, X15); + vpbroadcastd (7 * 4)(INPUT), X15; + PLUS(X7, X15); + transpose_4x4(X0, X1, X2, X3, X8, X15); + transpose_4x4(X4, X5, X6, X7, X8, X15); + vmovdqa (STACK_TMP1)(%rsp), X8; + transpose_16byte_2x2(X0, X4, X15); + transpose_16byte_2x2(X1, X5, X15); + transpose_16byte_2x2(X2, X6, X15); + transpose_16byte_2x2(X3, X7, X15); + vmovdqa (STACK_TMP)(%rsp), X15; + xor_src_dst(DST, SRC, (64 * 0 + 16 * 0), X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 0), X1); + vpbroadcastd (8 * 4)(INPUT), X0; + PLUS(X8, X0); + vpbroadcastd (9 * 4)(INPUT), X0; + PLUS(X9, X0); + vpbroadcastd (10 * 4)(INPUT), X0; + PLUS(X10, X0); + vpbroadcastd (11 * 4)(INPUT), X0; + PLUS(X11, X0); + vmovdqa (STACK_VEC_X12)(%rsp), X0; + PLUS(X12, X0); + vmovdqa (STACK_VEC_X13)(%rsp), X0; + PLUS(X13, X0); + vpbroadcastd (14 * 4)(INPUT), X0; + PLUS(X14, X0); + vpbroadcastd (15 * 4)(INPUT), X0; + PLUS(X15, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 0), X2); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 0), X3); + + /* Update counter */ + addq $8, (12 * 4)(INPUT); + + transpose_4x4(X8, X9, X10, X11, X0, X1); + transpose_4x4(X12, X13, X14, X15, X0, X1); + xor_src_dst(DST, SRC, (64 * 4 + 16 * 0), X4); + xor_src_dst(DST, SRC, (64 * 5 + 16 * 0), X5); + transpose_16byte_2x2(X8, X12, X0); + transpose_16byte_2x2(X9, X13, X0); + transpose_16byte_2x2(X10, X14, X0); + transpose_16byte_2x2(X11, X15, X0); + xor_src_dst(DST, SRC, (64 * 6 + 16 * 0), X6); + xor_src_dst(DST, SRC, (64 * 7 + 16 * 0), X7); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 2), X8); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 2), X9); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 2), X10); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 2), X11); + xor_src_dst(DST, SRC, (64 * 4 + 16 * 2), X12); + xor_src_dst(DST, SRC, (64 * 5 + 16 * 2), X13); + xor_src_dst(DST, SRC, (64 * 6 + 16 * 2), X14); + xor_src_dst(DST, SRC, (64 * 7 + 16 * 2), X15); + + subq $8, (STACK_MAX + 7 * 8)(%rsp); # NBLKS + + lea (8 * 64)(DST), DST; + lea (8 * 64)(SRC), SRC; + movq SRC, (STACK_MAX + 5 * 8)(%rsp); + movq DST, (STACK_MAX + 6 * 8)(%rsp); + + jnz .Loop_poly8; + + /* Store state */ + POLY1305_STORE_STATE(); + + /* clear the used vector registers and stack */ + vpxor X0, X0, X0; + vmovdqa X0, (STACK_VEC_X12)(%rsp); + vmovdqa X0, (STACK_VEC_X13)(%rsp); + vmovdqa X0, (STACK_TMP)(%rsp); + vmovdqa X0, (STACK_TMP1)(%rsp); + vzeroall; + + movq (STACK_MAX + 0 * 8)(%rsp), %rbx; + movq (STACK_MAX + 1 * 8)(%rsp), %r12; + movq (STACK_MAX + 2 * 8)(%rsp), %r13; + movq (STACK_MAX + 3 * 8)(%rsp), %r14; + movq (STACK_MAX + 4 * 8)(%rsp), %r15; + CFI_RESTORE(%rbx); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + CFI_RESTORE(%r14); + CFI_RESTORE(%r15); + + xorl %eax, %eax; + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_poly1305_amd64_avx2_blocks8, + .-_gcry_chacha20_poly1305_amd64_avx2_blocks8;) + +#endif /*defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/chacha20-amd64-ssse3.S b/comm/third_party/libgcrypt/cipher/chacha20-amd64-ssse3.S new file mode 100644 index 0000000000..9cdb69ae6d --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20-amd64-ssse3.S @@ -0,0 +1,1012 @@ +/* chacha20-amd64-ssse3.S - SSSE3 implementation of ChaCha20 cipher + * + * Copyright (C) 2017-2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* + * Based on D. J. Bernstein reference implementation at + * http://cr.yp.to/chacha.html: + * + * chacha-regs.c version 20080118 + * D. J. Bernstein + * Public domain. + */ + +#ifdef __x86_64 +#include +#if defined(HAVE_GCC_INLINE_ASM_SSSE3) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +.text + +#include "asm-common-amd64.h" +#include "asm-poly1305-amd64.h" + +/* register macros */ +#define INPUT %rdi +#define DST %rsi +#define SRC %rdx +#define NBLKS %rcx +#define ROUND %eax + +/* stack structure */ +#define STACK_VEC_X12 (16) +#define STACK_VEC_X13 (16 + STACK_VEC_X12) +#define STACK_TMP (16 + STACK_VEC_X13) +#define STACK_TMP1 (16 + STACK_TMP) +#define STACK_TMP2 (16 + STACK_TMP1) + +#define STACK_MAX (16 + STACK_TMP2) + +/* vector registers */ +#define X0 %xmm0 +#define X1 %xmm1 +#define X2 %xmm2 +#define X3 %xmm3 +#define X4 %xmm4 +#define X5 %xmm5 +#define X6 %xmm6 +#define X7 %xmm7 +#define X8 %xmm8 +#define X9 %xmm9 +#define X10 %xmm10 +#define X11 %xmm11 +#define X12 %xmm12 +#define X13 %xmm13 +#define X14 %xmm14 +#define X15 %xmm15 + +/********************************************************************** + helper macros + **********************************************************************/ + +/* 4x4 32-bit integer matrix transpose */ +#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ + movdqa x0, t2; \ + punpckhdq x1, t2; \ + punpckldq x1, x0; \ + \ + movdqa x2, t1; \ + punpckldq x3, t1; \ + punpckhdq x3, x2; \ + \ + movdqa x0, x1; \ + punpckhqdq t1, x1; \ + punpcklqdq t1, x0; \ + \ + movdqa t2, x3; \ + punpckhqdq x2, x3; \ + punpcklqdq x2, t2; \ + movdqa t2, x2; + +/* fill xmm register with 32-bit value from memory */ +#define pbroadcastd(mem32, xreg) \ + movd mem32, xreg; \ + pshufd $0, xreg, xreg; + +/* xor with unaligned memory operand */ +#define pxor_u(umem128, xreg, t) \ + movdqu umem128, t; \ + pxor t, xreg; + +/* xor register with unaligned src and save to unaligned dst */ +#define xor_src_dst(dst, src, offset, xreg, t) \ + pxor_u(offset(src), xreg, t); \ + movdqu xreg, offset(dst); + +#define clear(x) pxor x,x; + +/********************************************************************** + 4-way chacha20 + **********************************************************************/ + +#define ROTATE2(v1,v2,c,tmp1,tmp2) \ + movdqa v1, tmp1; \ + movdqa v2, tmp2; \ + psrld $(32 - (c)), v1; \ + pslld $(c), tmp1; \ + paddb tmp1, v1; \ + psrld $(32 - (c)), v2; \ + pslld $(c), tmp2; \ + paddb tmp2, v2; + +#define ROTATE_SHUF_2(v1,v2,shuf) \ + pshufb shuf, v1; \ + pshufb shuf, v2; + +#define XOR(ds,s) \ + pxor s, ds; + +#define PLUS(ds,s) \ + paddd s, ds; + +#define QUARTERROUND2(a1,b1,c1,d1,a2,b2,c2,d2,ign,tmp1,tmp2,\ + interleave_op1,interleave_op2) \ + movdqa .Lshuf_rol16 rRIP, tmp1; \ + interleave_op1; \ + PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2); \ + ROTATE_SHUF_2(d1, d2, tmp1); \ + PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2); \ + ROTATE2(b1, b2, 12, tmp1, tmp2); \ + movdqa .Lshuf_rol8 rRIP, tmp1; \ + interleave_op2; \ + PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2); \ + ROTATE_SHUF_2(d1, d2, tmp1); \ + PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2); \ + ROTATE2(b1, b2, 7, tmp1, tmp2); + +chacha20_data: +.align 16 +.Lshuf_rol16: + .byte 2,3,0,1,6,7,4,5,10,11,8,9,14,15,12,13 +.Lshuf_rol8: + .byte 3,0,1,2,7,4,5,6,11,8,9,10,15,12,13,14 +.Lcounter1: + .long 1,0,0,0 +.Linc_counter: + .long 0,1,2,3 +.Lunsigned_cmp: + .long 0x80000000,0x80000000,0x80000000,0x80000000 + +.align 8 +.globl _gcry_chacha20_amd64_ssse3_blocks4 +ELF(.type _gcry_chacha20_amd64_ssse3_blocks4,@function;) + +_gcry_chacha20_amd64_ssse3_blocks4: + /* input: + * %rdi: input + * %rsi: dst + * %rdx: src + * %rcx: nblks (multiple of 4) + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + subq $STACK_MAX, %rsp; + andq $~15, %rsp; + +.Loop4: + mov $20, ROUND; + + /* Construct counter vectors X12 and X13 */ + movdqa .Linc_counter rRIP, X0; + movdqa .Lunsigned_cmp rRIP, X2; + pbroadcastd((12 * 4)(INPUT), X12); + pbroadcastd((13 * 4)(INPUT), X13); + paddd X0, X12; + movdqa X12, X1; + pxor X2, X0; + pxor X2, X1; + pcmpgtd X1, X0; + psubd X0, X13; + movdqa X12, (STACK_VEC_X12)(%rsp); + movdqa X13, (STACK_VEC_X13)(%rsp); + + /* Load vectors */ + pbroadcastd((0 * 4)(INPUT), X0); + pbroadcastd((1 * 4)(INPUT), X1); + pbroadcastd((2 * 4)(INPUT), X2); + pbroadcastd((3 * 4)(INPUT), X3); + pbroadcastd((4 * 4)(INPUT), X4); + pbroadcastd((5 * 4)(INPUT), X5); + pbroadcastd((6 * 4)(INPUT), X6); + pbroadcastd((7 * 4)(INPUT), X7); + pbroadcastd((8 * 4)(INPUT), X8); + pbroadcastd((9 * 4)(INPUT), X9); + pbroadcastd((10 * 4)(INPUT), X10); + pbroadcastd((11 * 4)(INPUT), X11); + pbroadcastd((14 * 4)(INPUT), X14); + pbroadcastd((15 * 4)(INPUT), X15); + movdqa X11, (STACK_TMP)(%rsp); + movdqa X15, (STACK_TMP1)(%rsp); + +.Lround2_4: + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X11,X15,,) + movdqa (STACK_TMP)(%rsp), X11; + movdqa (STACK_TMP1)(%rsp), X15; + movdqa X8, (STACK_TMP)(%rsp); + movdqa X9, (STACK_TMP1)(%rsp); + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8,X9,,) + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8,X9,,) + movdqa (STACK_TMP)(%rsp), X8; + movdqa (STACK_TMP1)(%rsp), X9; + movdqa X11, (STACK_TMP)(%rsp); + movdqa X15, (STACK_TMP1)(%rsp); + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X11,X15,,) + sub $2, ROUND; + jnz .Lround2_4; + + /* tmp := X15 */ + movdqa (STACK_TMP)(%rsp), X11; + pbroadcastd((0 * 4)(INPUT), X15); + PLUS(X0, X15); + pbroadcastd((1 * 4)(INPUT), X15); + PLUS(X1, X15); + pbroadcastd((2 * 4)(INPUT), X15); + PLUS(X2, X15); + pbroadcastd((3 * 4)(INPUT), X15); + PLUS(X3, X15); + pbroadcastd((4 * 4)(INPUT), X15); + PLUS(X4, X15); + pbroadcastd((5 * 4)(INPUT), X15); + PLUS(X5, X15); + pbroadcastd((6 * 4)(INPUT), X15); + PLUS(X6, X15); + pbroadcastd((7 * 4)(INPUT), X15); + PLUS(X7, X15); + pbroadcastd((8 * 4)(INPUT), X15); + PLUS(X8, X15); + pbroadcastd((9 * 4)(INPUT), X15); + PLUS(X9, X15); + pbroadcastd((10 * 4)(INPUT), X15); + PLUS(X10, X15); + pbroadcastd((11 * 4)(INPUT), X15); + PLUS(X11, X15); + movdqa (STACK_VEC_X12)(%rsp), X15; + PLUS(X12, X15); + movdqa (STACK_VEC_X13)(%rsp), X15; + PLUS(X13, X15); + movdqa X13, (STACK_TMP)(%rsp); + pbroadcastd((14 * 4)(INPUT), X15); + PLUS(X14, X15); + movdqa (STACK_TMP1)(%rsp), X15; + movdqa X14, (STACK_TMP1)(%rsp); + pbroadcastd((15 * 4)(INPUT), X13); + PLUS(X15, X13); + movdqa X15, (STACK_TMP2)(%rsp); + + /* Update counter */ + addq $4, (12 * 4)(INPUT); + + transpose_4x4(X0, X1, X2, X3, X13, X14, X15); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 0), X0, X15); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 0), X1, X15); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 0), X2, X15); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 0), X3, X15); + transpose_4x4(X4, X5, X6, X7, X0, X1, X2); + movdqa (STACK_TMP)(%rsp), X13; + movdqa (STACK_TMP1)(%rsp), X14; + movdqa (STACK_TMP2)(%rsp), X15; + xor_src_dst(DST, SRC, (64 * 0 + 16 * 1), X4, X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 1), X5, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 1), X6, X0); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 1), X7, X0); + transpose_4x4(X8, X9, X10, X11, X0, X1, X2); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 2), X8, X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 2), X9, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 2), X10, X0); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 2), X11, X0); + transpose_4x4(X12, X13, X14, X15, X0, X1, X2); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 3), X12, X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 3), X13, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 3), X14, X0); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 3), X15, X0); + + sub $4, NBLKS; + lea (4 * 64)(DST), DST; + lea (4 * 64)(SRC), SRC; + jnz .Loop4; + + /* clear the used vector registers and stack */ + clear(X0); + movdqa X0, (STACK_VEC_X12)(%rsp); + movdqa X0, (STACK_VEC_X13)(%rsp); + movdqa X0, (STACK_TMP)(%rsp); + movdqa X0, (STACK_TMP1)(%rsp); + movdqa X0, (STACK_TMP2)(%rsp); + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X8); + clear(X9); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + clear(X14); + clear(X15); + + /* eax zeroed by round loop. */ + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_amd64_ssse3_blocks4, + .-_gcry_chacha20_amd64_ssse3_blocks4;) + +/********************************************************************** + 2-way && 1-way chacha20 + **********************************************************************/ + +#define ROTATE_SHUF(v1,shuf) \ + pshufb shuf, v1; + +#define ROTATE(v1,c,tmp1) \ + movdqa v1, tmp1; \ + psrld $(32 - (c)), v1; \ + pslld $(c), tmp1; \ + paddb tmp1, v1; + +#define WORD_SHUF(v1,shuf) \ + pshufd $shuf, v1, v1; + +#define QUARTERROUND4(x0,x1,x2,x3,shuf_rol8,shuf_rol16,tmp1,shuf_x1,\ + shuf_x2,shuf_x3) \ + PLUS(x0, x1); XOR(x3, x0); ROTATE_SHUF(x3, shuf_rol16); \ + PLUS(x2, x3); XOR(x1, x2); ROTATE(x1, 12, tmp1); \ + PLUS(x0, x1); XOR(x3, x0); ROTATE_SHUF(x3, shuf_rol8); \ + PLUS(x2, x3); \ + WORD_SHUF(x3, shuf_x3); \ + XOR(x1, x2); \ + WORD_SHUF(x2, shuf_x2); \ + ROTATE(x1, 7, tmp1); \ + WORD_SHUF(x1, shuf_x1); + +.align 8 +.globl _gcry_chacha20_amd64_ssse3_blocks1 +ELF(.type _gcry_chacha20_amd64_ssse3_blocks1,@function;) + +_gcry_chacha20_amd64_ssse3_blocks1: + /* input: + * %rdi: input + * %rsi: dst + * %rdx: src + * %rcx: nblks + */ + CFI_STARTPROC(); + + /* Load constants */ + movdqa .Lcounter1 rRIP, X4; + movdqa .Lshuf_rol8 rRIP, X5; + movdqa .Lshuf_rol16 rRIP, X6; + + /* Load state */ + movdqu (0 * 4)(INPUT), X10; + movdqu (4 * 4)(INPUT), X11; + movdqu (8 * 4)(INPUT), X12; + movdqu (12 * 4)(INPUT), X13; + + cmp $2, NBLKS; + jb .Loop1; + + mov $20, ROUND; + + movdqa X10, X0; + movdqa X11, X1; + movdqa X12, X2; + movdqa X13, X3; + + movdqa X10, X8; + movdqa X11, X9; + movdqa X12, X14; + movdqa X13, X15; + paddq X4, X15; + +.Lround2_2: + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + QUARTERROUND4(X8, X9, X14, X15, X5, X6, X7, 0x39, 0x4e, 0x93); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + QUARTERROUND4(X8, X9, X14, X15, X5, X6, X7, 0x93, 0x4e, 0x39); + sub $2, ROUND; + jnz .Lround2_2; + + PLUS(X0, X10); + PLUS(X1, X11); + PLUS(X2, X12); + PLUS(X3, X13); + + /* Update counter */ + paddq X4, X13; + + PLUS(X8, X10); + PLUS(X9, X11); + PLUS(X14, X12); + PLUS(X15, X13); + + /* Update counter */ + paddq X4, X13; + + xor_src_dst(DST, SRC, 0 * 4, X0, X7); + xor_src_dst(DST, SRC, 4 * 4, X1, X7); + xor_src_dst(DST, SRC, 8 * 4, X2, X7); + xor_src_dst(DST, SRC, 12 * 4, X3, X7); + xor_src_dst(DST, SRC, 16 * 4, X8, X7); + xor_src_dst(DST, SRC, 20 * 4, X9, X7); + xor_src_dst(DST, SRC, 24 * 4, X14, X7); + xor_src_dst(DST, SRC, 28 * 4, X15, X7); + + lea (2 * 64)(DST), DST; + lea (2 * 64)(SRC), SRC; + + clear(X8); + clear(X9); + clear(X14); + clear(X15); + + sub $2, NBLKS; + jz .Ldone1; + +.Loop1: + mov $20, ROUND; + + movdqa X10, X0; + movdqa X11, X1; + movdqa X12, X2; + movdqa X13, X3; + +.Lround2_1: + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + sub $2, ROUND; + jnz .Lround2_1; + + PLUS(X0, X10); + PLUS(X1, X11); + PLUS(X2, X12); + PLUS(X3, X13); + + /* Update counter */ + paddq X4, X13; + + xor_src_dst(DST, SRC, 0 * 4, X0, X7); + xor_src_dst(DST, SRC, 4 * 4, X1, X7); + xor_src_dst(DST, SRC, 8 * 4, X2, X7); + xor_src_dst(DST, SRC, 12 * 4, X3, X7); + + lea (64)(DST), DST; + lea (64)(SRC), SRC; + + sub $1, NBLKS; + jnz .Loop1; + +.Ldone1: + /* Store counter */ + movdqu X13, (12 * 4)(INPUT); + + /* clear the used vector registers */ + clear(X0); + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + + /* eax zeroed by round loop. */ + ret; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_amd64_ssse3_blocks1, + .-_gcry_chacha20_amd64_ssse3_blocks1;) + +/********************************************************************** + 4-way stitched chacha20-poly1305 + **********************************************************************/ + +#define _ /*_*/ + +.align 8 +.globl _gcry_chacha20_poly1305_amd64_ssse3_blocks4 +ELF(.type _gcry_chacha20_poly1305_amd64_ssse3_blocks4,@function;) + +_gcry_chacha20_poly1305_amd64_ssse3_blocks4: + /* input: + * %rdi: input + * %rsi: dst + * %rdx: src + * %rcx: nblks (multiple of 4) + * %r9: poly1305-state + * %r8: poly1305-src + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + subq $(9 * 8) + STACK_MAX + 16, %rsp; + andq $~15, %rsp; + + movq %rbx, (STACK_MAX + 0 * 8)(%rsp); + movq %r12, (STACK_MAX + 1 * 8)(%rsp); + movq %r13, (STACK_MAX + 2 * 8)(%rsp); + movq %r14, (STACK_MAX + 3 * 8)(%rsp); + movq %r15, (STACK_MAX + 4 * 8)(%rsp); + CFI_REG_ON_STACK(rbx, STACK_MAX + 0 * 8); + CFI_REG_ON_STACK(r12, STACK_MAX + 1 * 8); + CFI_REG_ON_STACK(r13, STACK_MAX + 2 * 8); + CFI_REG_ON_STACK(r14, STACK_MAX + 3 * 8); + CFI_REG_ON_STACK(r15, STACK_MAX + 4 * 8); + + movq %rdx, (STACK_MAX + 5 * 8)(%rsp); # SRC + movq %rsi, (STACK_MAX + 6 * 8)(%rsp); # DST + movq %rcx, (STACK_MAX + 7 * 8)(%rsp); # NBLKS + + /* Load state */ + POLY1305_LOAD_STATE(); + +.Loop_poly4: + + /* Construct counter vectors X12 and X13 */ + movdqa .Linc_counter rRIP, X0; + movdqa .Lunsigned_cmp rRIP, X2; + pbroadcastd((12 * 4)(INPUT), X12); + pbroadcastd((13 * 4)(INPUT), X13); + paddd X0, X12; + movdqa X12, X1; + pxor X2, X0; + pxor X2, X1; + pcmpgtd X1, X0; + psubd X0, X13; + movdqa X12, (STACK_VEC_X12)(%rsp); + movdqa X13, (STACK_VEC_X13)(%rsp); + + /* Load vectors */ + pbroadcastd((0 * 4)(INPUT), X0); + pbroadcastd((1 * 4)(INPUT), X1); + pbroadcastd((2 * 4)(INPUT), X2); + pbroadcastd((3 * 4)(INPUT), X3); + pbroadcastd((4 * 4)(INPUT), X4); + pbroadcastd((5 * 4)(INPUT), X5); + pbroadcastd((6 * 4)(INPUT), X6); + pbroadcastd((7 * 4)(INPUT), X7); + pbroadcastd((8 * 4)(INPUT), X8); + pbroadcastd((9 * 4)(INPUT), X9); + pbroadcastd((10 * 4)(INPUT), X10); + pbroadcastd((11 * 4)(INPUT), X11); + pbroadcastd((14 * 4)(INPUT), X14); + pbroadcastd((15 * 4)(INPUT), X15); + movdqa X11, (STACK_TMP)(%rsp); + movdqa X15, (STACK_TMP1)(%rsp); + + /* Process four ChaCha20 blocks and sixteen Poly1305 blocks. */ + + movl $20, (STACK_MAX + 8 * 8 + 4)(%rsp); +.Lround4_with_poly1305_outer: + movl $6, (STACK_MAX + 8 * 8)(%rsp); +.Lround4_with_poly1305_inner1: + /* rounds 0-5 & 10-15 */ + POLY1305_BLOCK_PART1(0 * 16) + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X11,X15, + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3()) + movdqa (STACK_TMP)(%rsp), X11; + movdqa (STACK_TMP1)(%rsp), X15; + movdqa X8, (STACK_TMP)(%rsp); + movdqa X9, (STACK_TMP1)(%rsp); + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8,X9, + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5()) + POLY1305_BLOCK_PART1(1 * 16) + lea (2 * 16)(POLY_RSRC), POLY_RSRC; + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8,X9, + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3()) + movdqa (STACK_TMP)(%rsp), X8; + movdqa (STACK_TMP1)(%rsp), X9; + movdqa X11, (STACK_TMP)(%rsp); + movdqa X15, (STACK_TMP1)(%rsp); + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X11,X15, + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5()) + + subl $2, (STACK_MAX + 8 * 8)(%rsp); + jnz .Lround4_with_poly1305_inner1; + + movl $4, (STACK_MAX + 8 * 8)(%rsp); +.Lround4_with_poly1305_inner2: + /* rounds 6-9 & 16-19 */ + POLY1305_BLOCK_PART1(0 * 16) + lea (1 * 16)(POLY_RSRC), POLY_RSRC; + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X11,X15, + POLY1305_BLOCK_PART2(), + _) + movdqa (STACK_TMP)(%rsp), X11; + movdqa (STACK_TMP1)(%rsp), X15; + movdqa X8, (STACK_TMP)(%rsp); + movdqa X9, (STACK_TMP1)(%rsp); + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8,X9, + POLY1305_BLOCK_PART3(), + _) + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8,X9, + POLY1305_BLOCK_PART4(), + _) + movdqa (STACK_TMP)(%rsp), X8; + movdqa (STACK_TMP1)(%rsp), X9; + movdqa X11, (STACK_TMP)(%rsp); + movdqa X15, (STACK_TMP1)(%rsp); + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X11,X15, + POLY1305_BLOCK_PART5(), + _) + + subl $2, (STACK_MAX + 8 * 8)(%rsp); + jnz .Lround4_with_poly1305_inner2; + + subl $10, (STACK_MAX + 8 * 8 + 4)(%rsp); + jnz .Lround4_with_poly1305_outer; + + /* tmp := X15 */ + movdqa (STACK_TMP)(%rsp), X11; + pbroadcastd((0 * 4)(INPUT), X15); + PLUS(X0, X15); + pbroadcastd((1 * 4)(INPUT), X15); + PLUS(X1, X15); + pbroadcastd((2 * 4)(INPUT), X15); + PLUS(X2, X15); + pbroadcastd((3 * 4)(INPUT), X15); + PLUS(X3, X15); + pbroadcastd((4 * 4)(INPUT), X15); + PLUS(X4, X15); + pbroadcastd((5 * 4)(INPUT), X15); + PLUS(X5, X15); + pbroadcastd((6 * 4)(INPUT), X15); + PLUS(X6, X15); + pbroadcastd((7 * 4)(INPUT), X15); + PLUS(X7, X15); + pbroadcastd((8 * 4)(INPUT), X15); + PLUS(X8, X15); + pbroadcastd((9 * 4)(INPUT), X15); + PLUS(X9, X15); + pbroadcastd((10 * 4)(INPUT), X15); + PLUS(X10, X15); + pbroadcastd((11 * 4)(INPUT), X15); + PLUS(X11, X15); + movdqa (STACK_VEC_X12)(%rsp), X15; + PLUS(X12, X15); + movdqa (STACK_VEC_X13)(%rsp), X15; + PLUS(X13, X15); + movdqa X13, (STACK_TMP)(%rsp); + pbroadcastd((14 * 4)(INPUT), X15); + PLUS(X14, X15); + movdqa (STACK_TMP1)(%rsp), X15; + movdqa X14, (STACK_TMP1)(%rsp); + pbroadcastd((15 * 4)(INPUT), X13); + PLUS(X15, X13); + movdqa X15, (STACK_TMP2)(%rsp); + + /* Update counter */ + addq $4, (12 * 4)(INPUT); + + movq (STACK_MAX + 5 * 8)(%rsp), SRC; + movq (STACK_MAX + 6 * 8)(%rsp), DST; + + transpose_4x4(X0, X1, X2, X3, X13, X14, X15); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 0), X0, X15); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 0), X1, X15); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 0), X2, X15); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 0), X3, X15); + transpose_4x4(X4, X5, X6, X7, X0, X1, X2); + movdqa (STACK_TMP)(%rsp), X13; + movdqa (STACK_TMP1)(%rsp), X14; + movdqa (STACK_TMP2)(%rsp), X15; + xor_src_dst(DST, SRC, (64 * 0 + 16 * 1), X4, X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 1), X5, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 1), X6, X0); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 1), X7, X0); + transpose_4x4(X8, X9, X10, X11, X0, X1, X2); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 2), X8, X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 2), X9, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 2), X10, X0); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 2), X11, X0); + transpose_4x4(X12, X13, X14, X15, X0, X1, X2); + xor_src_dst(DST, SRC, (64 * 0 + 16 * 3), X12, X0); + xor_src_dst(DST, SRC, (64 * 1 + 16 * 3), X13, X0); + xor_src_dst(DST, SRC, (64 * 2 + 16 * 3), X14, X0); + xor_src_dst(DST, SRC, (64 * 3 + 16 * 3), X15, X0); + + subq $4, (STACK_MAX + 7 * 8)(%rsp); # NBLKS + + lea (4 * 64)(DST), DST; + lea (4 * 64)(SRC), SRC; + movq SRC, (STACK_MAX + 5 * 8)(%rsp); + movq DST, (STACK_MAX + 6 * 8)(%rsp); + + jnz .Loop_poly4; + + /* Store state */ + POLY1305_STORE_STATE(); + + /* clear the used vector registers and stack */ + clear(X0); + movdqa X0, (STACK_VEC_X12)(%rsp); + movdqa X0, (STACK_VEC_X13)(%rsp); + movdqa X0, (STACK_TMP)(%rsp); + movdqa X0, (STACK_TMP1)(%rsp); + movdqa X0, (STACK_TMP2)(%rsp); + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X8); + clear(X9); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + clear(X14); + clear(X15); + + movq (STACK_MAX + 0 * 8)(%rsp), %rbx; + movq (STACK_MAX + 1 * 8)(%rsp), %r12; + movq (STACK_MAX + 2 * 8)(%rsp), %r13; + movq (STACK_MAX + 3 * 8)(%rsp), %r14; + movq (STACK_MAX + 4 * 8)(%rsp), %r15; + CFI_RESTORE(%rbx); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + CFI_RESTORE(%r14); + CFI_RESTORE(%r15); + + xorl %eax, %eax; + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_poly1305_amd64_ssse3_blocks4, + .-_gcry_chacha20_poly1305_amd64_ssse3_blocks4;) + +/********************************************************************** + 2-way && 1-way stitched chacha20-poly1305 + **********************************************************************/ + +.align 8 +.globl _gcry_chacha20_poly1305_amd64_ssse3_blocks1 +ELF(.type _gcry_chacha20_poly1305_amd64_ssse3_blocks1,@function;) + +_gcry_chacha20_poly1305_amd64_ssse3_blocks1: + /* input: + * %rdi: chacha20-state + * %rsi: dst + * %rdx: src + * %rcx: nblks + * %r9: poly1305-state + * %r8: poly1305-src + */ + CFI_STARTPROC(); + + pushq %rbp; + CFI_PUSH(%rbp); + movq %rsp, %rbp; + CFI_DEF_CFA_REGISTER(%rbp); + + subq $(9 * 8), %rsp; + movq %rbx, (0 * 8)(%rsp); + movq %r12, (1 * 8)(%rsp); + movq %r13, (2 * 8)(%rsp); + movq %r14, (3 * 8)(%rsp); + movq %r15, (4 * 8)(%rsp); + CFI_REG_ON_STACK(rbx, 0 * 8); + CFI_REG_ON_STACK(r12, 1 * 8); + CFI_REG_ON_STACK(r13, 2 * 8); + CFI_REG_ON_STACK(r14, 3 * 8); + CFI_REG_ON_STACK(r15, 4 * 8); + + movq %rdx, (5 * 8)(%rsp); # SRC + movq %rsi, (6 * 8)(%rsp); # DST + movq %rcx, (7 * 8)(%rsp); # NBLKS + + /* Load constants */ + movdqa .Lcounter1 rRIP, X4; + movdqa .Lshuf_rol8 rRIP, X5; + movdqa .Lshuf_rol16 rRIP, X6; + + /* Load state */ + movdqu (0 * 4)(INPUT), X10; + movdqu (4 * 4)(INPUT), X11; + movdqu (8 * 4)(INPUT), X12; + movdqu (12 * 4)(INPUT), X13; + + POLY1305_LOAD_STATE(); + + cmpq $2, (7 * 8)(%rsp); #NBLKS + jb .Loop_poly1; + + movdqa X10, X0; + movdqa X11, X1; + movdqa X12, X2; + movdqa X13, X3; + + movdqa X10, X8; + movdqa X11, X9; + movdqa X12, X14; + movdqa X13, X15; + paddq X4, X15; + + /* Process two ChaCha20 blocks and eight Poly1305 blocks. */ + + movl $20, (8 * 8 + 4)(%rsp); +.Lround2_with_poly1305_outer: + movl $8, (8 * 8)(%rsp); +.Lround2_with_poly1305_inner: + POLY1305_BLOCK_PART1(0 * 16); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + lea (1 * 16)(POLY_RSRC), POLY_RSRC; + POLY1305_BLOCK_PART2(); + QUARTERROUND4(X8, X9, X14, X15, X5, X6, X7, 0x39, 0x4e, 0x93); + POLY1305_BLOCK_PART3(); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + POLY1305_BLOCK_PART4(); + QUARTERROUND4(X8, X9, X14, X15, X5, X6, X7, 0x93, 0x4e, 0x39); + POLY1305_BLOCK_PART5(); + + subl $2, (8 * 8)(%rsp); + jnz .Lround2_with_poly1305_inner; + + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + QUARTERROUND4(X8, X9, X14, X15, X5, X6, X7, 0x39, 0x4e, 0x93); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + QUARTERROUND4(X8, X9, X14, X15, X5, X6, X7, 0x93, 0x4e, 0x39); + + subl $10, (8 * 8 + 4)(%rsp); + jnz .Lround2_with_poly1305_outer; + + movq (5 * 8)(%rsp), SRC; + movq (6 * 8)(%rsp), DST; + + PLUS(X0, X10); + PLUS(X1, X11); + PLUS(X2, X12); + PLUS(X3, X13); + + /* Update counter */ + paddq X4, X13; + + PLUS(X8, X10); + PLUS(X9, X11); + PLUS(X14, X12); + PLUS(X15, X13); + + /* Update counter */ + paddq X4, X13; + + xor_src_dst(DST, SRC, 0 * 4, X0, X7); + xor_src_dst(DST, SRC, 4 * 4, X1, X7); + xor_src_dst(DST, SRC, 8 * 4, X2, X7); + xor_src_dst(DST, SRC, 12 * 4, X3, X7); + xor_src_dst(DST, SRC, 16 * 4, X8, X7); + xor_src_dst(DST, SRC, 20 * 4, X9, X7); + xor_src_dst(DST, SRC, 24 * 4, X14, X7); + xor_src_dst(DST, SRC, 28 * 4, X15, X7); + + clear(X8); + clear(X9); + clear(X14); + clear(X15); + + subq $2, (7 * 8)(%rsp); # NBLKS + lea (2 * 64)(SRC), SRC; + lea (2 * 64)(DST), DST; + movq SRC, (5 * 8)(%rsp); + movq DST, (6 * 8)(%rsp); + jz .Ldone_poly1; + +.Loop_poly1: + movdqa X10, X0; + movdqa X11, X1; + movdqa X12, X2; + movdqa X13, X3; + + /* Process one ChaCha20 block and four Poly1305 blocks. */ + + movl $20, (8 * 8 + 4)(%rsp); +.Lround1_with_poly1305_outer: + movl $8, (8 * 8)(%rsp); +.Lround1_with_poly1305_inner: + POLY1305_BLOCK_PART1(0 * 16); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + POLY1305_BLOCK_PART2(); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + lea (1 * 16)(POLY_RSRC), POLY_RSRC; + + POLY1305_BLOCK_PART3(); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + POLY1305_BLOCK_PART4(); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + POLY1305_BLOCK_PART5(); + + subl $4, (8 * 8)(%rsp); + jnz .Lround1_with_poly1305_inner; + + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x39, 0x4e, 0x93); + QUARTERROUND4(X0, X1, X2, X3, X5, X6, X7, 0x93, 0x4e, 0x39); + + subl $10, (8 * 8 + 4)(%rsp); + jnz .Lround1_with_poly1305_outer; + + movq (5 * 8)(%rsp), SRC; + movq (6 * 8)(%rsp), DST; + + PLUS(X0, X10); + PLUS(X1, X11); + PLUS(X2, X12); + PLUS(X3, X13); + + /* Update counter */ + paddq X4, X13; + + xor_src_dst(DST, SRC, 0 * 4, X0, X7); + xor_src_dst(DST, SRC, 4 * 4, X1, X7); + xor_src_dst(DST, SRC, 8 * 4, X2, X7); + xor_src_dst(DST, SRC, 12 * 4, X3, X7); + + subq $1, (7 * 8)(%rsp); # NBLKS + lea (64)(SRC), SRC; + lea (64)(DST), DST; + movq SRC, (5 * 8)(%rsp); + movq DST, (6 * 8)(%rsp); + + jnz .Loop_poly1; + +.Ldone_poly1: + /* Store state */ + POLY1305_STORE_STATE(); + + movdqu X13, (12 * 4)(INPUT); + + /* clear the used vector registers */ + clear(X0); + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + + movq (0 * 8)(%rsp), %rbx; + movq (1 * 8)(%rsp), %r12; + movq (2 * 8)(%rsp), %r13; + movq (3 * 8)(%rsp), %r14; + movq (4 * 8)(%rsp), %r15; + CFI_RESTORE(%rbx); + CFI_RESTORE(%r12); + CFI_RESTORE(%r13); + CFI_RESTORE(%r14); + CFI_RESTORE(%r15); + + xorl %eax, %eax; + leave; + CFI_LEAVE(); + ret; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_poly1305_amd64_ssse3_blocks1, + .-_gcry_chacha20_poly1305_amd64_ssse3_blocks1;) + +#endif /*defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)*/ +#endif /*__x86_64*/ diff --git a/comm/third_party/libgcrypt/cipher/chacha20-armv7-neon.S b/comm/third_party/libgcrypt/cipher/chacha20-armv7-neon.S new file mode 100644 index 0000000000..33a43df1f3 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20-armv7-neon.S @@ -0,0 +1,393 @@ +/* chacha20-armv7-neon.S - ARMv7 NEON implementation of ChaCha20 cipher + * + * Copyright (C) 2017,2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* + * Based on D. J. Bernstein reference implementation at + * http://cr.yp.to/chacha.html: + * + * chacha-regs.c version 20080118 + * D. J. Bernstein + * Public domain. + */ + +#include + +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \ + defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_NEON) + +.syntax unified +.fpu neon +.arm + +.text + +#ifdef __PIC__ +# define GET_DATA_POINTER(reg, name, rtmp) \ + ldr reg, 1f; \ + ldr rtmp, 2f; \ + b 3f; \ + 1: .word _GLOBAL_OFFSET_TABLE_-(3f+8); \ + 2: .word name(GOT); \ + 3: add reg, pc, reg; \ + ldr reg, [reg, rtmp]; +#else +# define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name +#endif + +/* register macros */ +#define INPUT r0 +#define DST r1 +#define SRC r2 +#define NBLKS r3 +#define ROUND r4 + +/* stack structure */ +#define STACK_VEC_X12 (16) +#define STACK_VEC_X13 (STACK_VEC_X12 + 16) +#define STACK_TMP (STACK_VEC_X13 + 16) +#define STACK_TMP1 (16 + STACK_TMP) +#define STACK_TMP2 (16 + STACK_TMP1) + +#define STACK_MAX (16 + STACK_TMP2) + +/* vector registers */ +#define X0 q0 +#define X1 q1 +#define X2 q2 +#define X3 q3 +#define X4 q4 +#define X5 q5 +#define X6 q6 +#define X7 q7 +#define X8 q8 +#define X9 q9 +#define X10 q10 +#define X11 q11 +#define X12 q12 +#define X13 q13 +#define X14 q14 +#define X15 q15 + +#define X0l d0 +#define X1l d2 +#define X2l d4 +#define X3l d6 +#define X4l d8 +#define X5l d10 +#define X6l d12 +#define X7l d14 +#define X8l d16 +#define X9l d18 +#define X10l d20 +#define X11l d22 +#define X12l d24 +#define X13l d26 +#define X14l d28 +#define X15l d30 + +#define X0h d1 +#define X1h d3 +#define X2h d5 +#define X3h d7 +#define X4h d9 +#define X5h d11 +#define X6h d13 +#define X7h d15 +#define X8h d17 +#define X9h d19 +#define X10h d21 +#define X11h d23 +#define X12h d25 +#define X13h d27 +#define X14h d29 +#define X15h d31 + +/********************************************************************** + helper macros + **********************************************************************/ + +/* 4x4 32-bit integer matrix transpose */ +#define transpose_4x4_part1(_q0, _q1, _q2, _q3) \ + vtrn.32 _q0, _q1; \ + vtrn.32 _q2, _q3; +#define transpose_4x4_part2(_q0, _q1, _q2, _q3) \ + vswp _q0##h, _q2##l; \ + vswp _q1##h, _q3##l; + +#define clear(x) veor x,x,x; + +/********************************************************************** + 4-way chacha20 + **********************************************************************/ + +#define ROTATE2(dst1,dst2,c,src1,src2) \ + vshl.u32 dst1, src1, #(c); \ + vshl.u32 dst2, src2, #(c); \ + vsri.u32 dst1, src1, #(32 - (c)); \ + vsri.u32 dst2, src2, #(32 - (c)); + +#define ROTATE2_16(dst1,dst2,src1,src2) \ + vrev32.16 dst1, src1; \ + vrev32.16 dst2, src2; + +#define XOR(d,s1,s2) \ + veor d, s2, s1; + +#define PLUS(ds,s) \ + vadd.u32 ds, ds, s; + +#define QUARTERROUND2(a1,b1,c1,d1,a2,b2,c2,d2,ign,tmp1,tmp2) \ + PLUS(a1,b1); PLUS(a2,b2); XOR(tmp1,d1,a1); XOR(tmp2,d2,a2); \ + ROTATE2_16(d1, d2, tmp1, tmp2); \ + PLUS(c1,d1); PLUS(c2,d2); XOR(tmp1,b1,c1); XOR(tmp2,b2,c2); \ + ROTATE2(b1, b2, 12, tmp1, tmp2); \ + PLUS(a1,b1); PLUS(a2,b2); XOR(tmp1,d1,a1); XOR(tmp2,d2,a2); \ + ROTATE2(d1, d2, 8, tmp1, tmp2); \ + PLUS(c1,d1); PLUS(c2,d2); XOR(tmp1,b1,c1); XOR(tmp2,b2,c2); \ + ROTATE2(b1, b2, 7, tmp1, tmp2); + +chacha20_data: +.align 4 +.Linc_counter: + .long 0,1,2,3 + +.align 3 +.globl _gcry_chacha20_armv7_neon_blocks4 +.type _gcry_chacha20_armv7_neon_blocks4,%function; + +_gcry_chacha20_armv7_neon_blocks4: + /* input: + * r0: input + * r1: dst + * r2: src + * r3: nblks (multiple of 4) + */ + + vpush {q4-q7}; + push {r4-r12,lr}; + + mov r12, sp + + mov r6, sp; + sub r6, r6, #(STACK_MAX); + and r6, r6, #(~15); + mov sp, r6; + GET_DATA_POINTER(r9, .Linc_counter, lr); + add lr, INPUT, #(12*4); + add r8, sp, #STACK_VEC_X12; + +.Loop4: + mov ROUND, #20; + + /* Construct counter vectors X12 and X13 */ + + vld1.8 {X15}, [lr]; + mov lr, INPUT; + vld1.8 {X8}, [r9]; + vdup.32 X12, X15l[0]; + vdup.32 X13, X15l[1]; + vld1.8 {X3}, [lr]!; + vadd.u32 X12, X12, X8; + vdup.32 X0, X3l[0]; + vdup.32 X1, X3l[1]; + vdup.32 X2, X3h[0]; + vcgt.u32 X8, X8, X12; + vdup.32 X3, X3h[1]; + vdup.32 X14, X15h[0]; + vdup.32 X15, X15h[1]; + vsub.u32 X13, X13, X8; + vld1.8 {X7}, [lr]!; + vld1.8 {X11}, [lr]; + vst1.8 {X12, X13}, [r8]; + vdup.32 X4, X7l[0]; + vdup.32 X5, X7l[1]; + vdup.32 X6, X7h[0]; + vdup.32 X7, X7h[1]; + vdup.32 X8, X11l[0]; + vdup.32 X9, X11l[1]; + vdup.32 X10, X11h[0]; + vdup.32 X11, X11h[1]; + + add r7, sp, #STACK_TMP2; + add r6, sp, #STACK_TMP1; + add r5, sp, #STACK_TMP; + vst1.8 {X15}, [r6]; + vst1.8 {X11}, [r5]; + + mov lr, INPUT; +.Lround2: + subs ROUND, ROUND, #2 + QUARTERROUND2(X0, X4, X8, X12, X1, X5, X9, X13, tmp:=,X11,X15) + vld1.8 {X11}, [r5]; + vld1.8 {X15}, [r6]; + vst1.8 {X8}, [r5]; + vst1.8 {X9}, [r6]; + QUARTERROUND2(X2, X6, X10, X14, X3, X7, X11, X15, tmp:=,X8,X9) + QUARTERROUND2(X0, X5, X10, X15, X1, X6, X11, X12, tmp:=,X8,X9) + vld1.8 {X8}, [r5]; + vld1.8 {X9}, [r6]; + vst1.8 {X11}, [r5]; + vst1.8 {X15}, [r6]; + QUARTERROUND2(X2, X7, X8, X13, X3, X4, X9, X14, tmp:=,X11,X15) + bne .Lround2; + + vld1.8 {X11}, [lr]!; + vst1.8 {X14}, [r7]; + + vdup.32 X14, X11l[0]; /* INPUT + 0 * 4 */ + vdup.32 X15, X11l[1]; /* INPUT + 1 * 4 */ + PLUS(X0, X14); + PLUS(X1, X15); + vdup.32 X14, X11h[0]; /* INPUT + 2 * 4 */ + vdup.32 X15, X11h[1]; /* INPUT + 3 * 4 */ + PLUS(X2, X14); + PLUS(X3, X15); + + vld1.8 {X11}, [r5]; + vld1.8 {X15}, [r6]; + vst1.8 {X0}, [r5]; + vld1.8 {X0}, [lr]!; + vst1.8 {X1}, [r6]; + + vdup.32 X14, X0l[0]; /* INPUT + 4 * 4 */ + vdup.32 X1, X0l[1]; /* INPUT + 5 * 4 */ + PLUS(X4, X14); + PLUS(X5, X1); + vdup.32 X14, X0h[0]; /* INPUT + 6 * 4 */ + vdup.32 X1, X0h[1]; /* INPUT + 7 * 4 */ + PLUS(X6, X14); + PLUS(X7, X1); + + vld1.8 {X0}, [lr]!; + + vdup.32 X14, X0l[0]; /* INPUT + 8 * 4 */ + vdup.32 X1, X0l[1]; /* INPUT + 9 * 4 */ + PLUS(X8, X14); + PLUS(X9, X1); + vdup.32 X14, X0h[0]; /* INPUT + 10 * 4 */ + vdup.32 X1, X0h[1]; /* INPUT + 11 * 4 */ + PLUS(X10, X14); + PLUS(X11, X1); + + vld1.8 {X0}, [lr]; + add lr, INPUT, #(12*4) + vld1.8 {X14}, [r7]; + + vdup.32 X1, X0h[0]; /* INPUT + 10 * 4 */ + ldm lr, {r10, r11}; /* Update counter */ + vdup.32 X0, X0h[1]; /* INPUT + 11 * 4 */ + PLUS(X14, X1); + PLUS(X15, X0); + adds r10, r10, #4; /* Update counter */ + vld1.8 {X0, X1}, [r8]; + + PLUS(X12, X0); + vld1.8 {X0}, [r5]; + PLUS(X13, X1); + adc r11, r11, #0; /* Update counter */ + + vld1.8 {X1}, [r6]; + stm lr, {r10, r11}; /* Update counter */ + transpose_4x4_part1(X0, X1, X2, X3); + transpose_4x4_part1(X4, X5, X6, X7); + transpose_4x4_part1(X8, X9, X10, X11); + transpose_4x4_part1(X12, X13, X14, X15); + transpose_4x4_part2(X0, X1, X2, X3); + transpose_4x4_part2(X4, X5, X6, X7); + transpose_4x4_part2(X8, X9, X10, X11); + transpose_4x4_part2(X12, X13, X14, X15); + + subs NBLKS, NBLKS, #4; + + vst1.8 {X10}, [r5]; + add lr, INPUT, #(12*4) + vst1.8 {X11}, [r6]; + vld1.8 {X10, X11}, [SRC]!; + veor X10, X0, X10; + vld1.8 {X0}, [SRC]!; + veor X11, X4, X11; + vld1.8 {X4}, [SRC]!; + vst1.8 {X10, X11}, [DST]!; + vld1.8 {X10, X11}, [SRC]!; + veor X0, X8, X0; + veor X4, X12, X4; + veor X10, X1, X10; + veor X11, X5, X11; + vst1.8 {X0}, [DST]!; + vld1.8 {X0, X1}, [SRC]!; + vst1.8 {X4}, [DST]!; + vld1.8 {X4, X5}, [SRC]!; + vst1.8 {X10, X11}, [DST]!; + vld1.8 {X10}, [r5]; + vld1.8 {X11}, [r6]; + veor X0, X9, X0; + vld1.8 {X8, X9}, [SRC]!; + veor X1, X13, X1; + vld1.8 {X12, X13}, [SRC]!; + veor X4, X2, X4; + veor X5, X6, X5; + vst1.8 {X0, X1}, [DST]!; + vld1.8 {X0, X1}, [SRC]!; + vst1.8 {X4, X5}, [DST]!; + veor X8, X10, X8; + veor X9, X14, X9; + veor X12, X3, X12; + veor X13, X7, X13; + veor X0, X11, X0; + veor X1, X15, X1; + vst1.8 {X8, X9}, [DST]!; + vst1.8 {X12, X13}, [DST]!; + vst1.8 {X0, X1}, [DST]!; + + bne .Loop4; + + /* clear the used vector registers and stack */ + clear(X0); + vst1.8 {X0}, [r5]; + vst1.8 {X0}, [r6]; + vst1.8 {X0}, [r7]; + vst1.8 {X0}, [r8]!; + vst1.8 {X0}, [r8]; + + mov sp, r12 + clear(X1); + clear(X2); + clear(X3); + clear(X4); + clear(X5); + clear(X6); + clear(X7); + clear(X8); + clear(X9); + clear(X10); + clear(X11); + clear(X12); + clear(X13); + clear(X14); + clear(X15); + + pop {r4-r12,lr} + vpop {q4-q7} + eor r0, r0, r0 + bx lr +.size _gcry_chacha20_armv7_neon_blocks4, .-_gcry_chacha20_armv7_neon_blocks4; + +#endif diff --git a/comm/third_party/libgcrypt/cipher/chacha20-ppc.c b/comm/third_party/libgcrypt/cipher/chacha20-ppc.c new file mode 100644 index 0000000000..4a21b837d1 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20-ppc.c @@ -0,0 +1,646 @@ +/* chacha20-ppc.c - PowerPC vector implementation of ChaCha20 + * Copyright (C) 2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(ENABLE_PPC_CRYPTO_SUPPORT) && \ + defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \ + defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC) && \ + defined(USE_CHACHA20) && \ + __GNUC__ >= 4 + +#include +#include "bufhelp.h" +#include "poly1305-internal.h" + +#include "mpi-internal.h" +#include "longlong.h" + + +typedef vector unsigned char vector16x_u8; +typedef vector unsigned int vector4x_u32; +typedef vector unsigned long long vector2x_u64; + + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define NO_INLINE __attribute__((noinline)) +#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function)) + +#define ASM_FUNC_ATTR NO_INSTRUMENT_FUNCTION +#define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE +#define ASM_FUNC_ATTR_NOINLINE ASM_FUNC_ATTR NO_INLINE + + +#ifdef WORDS_BIGENDIAN +static const vector16x_u8 le_bswap_const = + { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 }; +#endif + + +static ASM_FUNC_ATTR_INLINE vector4x_u32 +vec_rol_elems(vector4x_u32 v, unsigned int idx) +{ +#ifndef WORDS_BIGENDIAN + return vec_sld (v, v, (16 - (4 * idx)) & 15); +#else + return vec_sld (v, v, (4 * idx) & 15); +#endif +} + + +static ASM_FUNC_ATTR_INLINE vector4x_u32 +vec_load_le(unsigned long offset, const unsigned char *ptr) +{ + vector4x_u32 vec; + vec = vec_vsx_ld (offset, (const u32 *)ptr); +#ifdef WORDS_BIGENDIAN + vec = (vector4x_u32)vec_perm((vector16x_u8)vec, (vector16x_u8)vec, + le_bswap_const); +#endif + return vec; +} + + +static ASM_FUNC_ATTR_INLINE void +vec_store_le(vector4x_u32 vec, unsigned long offset, unsigned char *ptr) +{ +#ifdef WORDS_BIGENDIAN + vec = (vector4x_u32)vec_perm((vector16x_u8)vec, (vector16x_u8)vec, + le_bswap_const); +#endif + vec_vsx_st (vec, offset, (u32 *)ptr); +} + + +static ASM_FUNC_ATTR_INLINE vector4x_u32 +vec_add_ctr_u64(vector4x_u32 v, vector4x_u32 a) +{ +#ifdef WORDS_BIGENDIAN + static const vector16x_u8 swap32 = + { 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11 }; + vector2x_u64 vec, add, sum; + + vec = (vector2x_u64)vec_perm((vector16x_u8)v, (vector16x_u8)v, swap32); + add = (vector2x_u64)vec_perm((vector16x_u8)a, (vector16x_u8)a, swap32); + sum = vec + add; + return (vector4x_u32)vec_perm((vector16x_u8)sum, (vector16x_u8)sum, swap32); +#else + return (vector4x_u32)((vector2x_u64)(v) + (vector2x_u64)(a)); +#endif +} + + +/********************************************************************** + 2-way && 1-way chacha20 + **********************************************************************/ + +#define ROTATE(v1,rolv) \ + __asm__ ("vrlw %0,%1,%2\n\t" : "=v" (v1) : "v" (v1), "v" (rolv)) + +#define WORD_ROL(v1,c) \ + ((v1) = vec_rol_elems((v1), (c))) + +#define XOR(ds,s) \ + ((ds) ^= (s)) + +#define PLUS(ds,s) \ + ((ds) += (s)) + +#define QUARTERROUND4(x0,x1,x2,x3,rol_x1,rol_x2,rol_x3) \ + PLUS(x0, x1); XOR(x3, x0); ROTATE(x3, rotate_16); \ + PLUS(x2, x3); XOR(x1, x2); ROTATE(x1, rotate_12); \ + PLUS(x0, x1); XOR(x3, x0); ROTATE(x3, rotate_8); \ + PLUS(x2, x3); \ + WORD_ROL(x3, rol_x3); \ + XOR(x1, x2); \ + WORD_ROL(x2, rol_x2); \ + ROTATE(x1, rotate_7); \ + WORD_ROL(x1, rol_x1); + +#define ADD_U64(v,a) \ + (v = vec_add_ctr_u64(v, a)) + +unsigned int ASM_FUNC_ATTR +_gcry_chacha20_ppc8_blocks1(u32 *state, byte *dst, const byte *src, + size_t nblks) +{ + vector4x_u32 counter_1 = { 1, 0, 0, 0 }; + vector4x_u32 rotate_16 = { 16, 16, 16, 16 }; + vector4x_u32 rotate_12 = { 12, 12, 12, 12 }; + vector4x_u32 rotate_8 = { 8, 8, 8, 8 }; + vector4x_u32 rotate_7 = { 7, 7, 7, 7 }; + vector4x_u32 state0, state1, state2, state3; + vector4x_u32 v0, v1, v2, v3; + vector4x_u32 v4, v5, v6, v7; + int i; + + /* force preload of constants to vector registers */ + __asm__ ("": "+v" (counter_1) :: "memory"); + __asm__ ("": "+v" (rotate_16) :: "memory"); + __asm__ ("": "+v" (rotate_12) :: "memory"); + __asm__ ("": "+v" (rotate_8) :: "memory"); + __asm__ ("": "+v" (rotate_7) :: "memory"); + + state0 = vec_vsx_ld(0 * 16, state); + state1 = vec_vsx_ld(1 * 16, state); + state2 = vec_vsx_ld(2 * 16, state); + state3 = vec_vsx_ld(3 * 16, state); + + while (nblks >= 2) + { + v0 = state0; + v1 = state1; + v2 = state2; + v3 = state3; + + v4 = state0; + v5 = state1; + v6 = state2; + v7 = state3; + ADD_U64(v7, counter_1); + + for (i = 20; i > 0; i -= 2) + { + QUARTERROUND4(v0, v1, v2, v3, 1, 2, 3); + QUARTERROUND4(v4, v5, v6, v7, 1, 2, 3); + QUARTERROUND4(v0, v1, v2, v3, 3, 2, 1); + QUARTERROUND4(v4, v5, v6, v7, 3, 2, 1); + } + + v0 += state0; + v1 += state1; + v2 += state2; + v3 += state3; + ADD_U64(state3, counter_1); /* update counter */ + v4 += state0; + v5 += state1; + v6 += state2; + v7 += state3; + ADD_U64(state3, counter_1); /* update counter */ + + v0 ^= vec_load_le(0 * 16, src); + v1 ^= vec_load_le(1 * 16, src); + v2 ^= vec_load_le(2 * 16, src); + v3 ^= vec_load_le(3 * 16, src); + vec_store_le(v0, 0 * 16, dst); + vec_store_le(v1, 1 * 16, dst); + vec_store_le(v2, 2 * 16, dst); + vec_store_le(v3, 3 * 16, dst); + src += 64; + dst += 64; + v4 ^= vec_load_le(0 * 16, src); + v5 ^= vec_load_le(1 * 16, src); + v6 ^= vec_load_le(2 * 16, src); + v7 ^= vec_load_le(3 * 16, src); + vec_store_le(v4, 0 * 16, dst); + vec_store_le(v5, 1 * 16, dst); + vec_store_le(v6, 2 * 16, dst); + vec_store_le(v7, 3 * 16, dst); + src += 64; + dst += 64; + + nblks -= 2; + } + + while (nblks) + { + v0 = state0; + v1 = state1; + v2 = state2; + v3 = state3; + + for (i = 20; i > 0; i -= 2) + { + QUARTERROUND4(v0, v1, v2, v3, 1, 2, 3); + QUARTERROUND4(v0, v1, v2, v3, 3, 2, 1); + } + + v0 += state0; + v1 += state1; + v2 += state2; + v3 += state3; + ADD_U64(state3, counter_1); /* update counter */ + + v0 ^= vec_load_le(0 * 16, src); + v1 ^= vec_load_le(1 * 16, src); + v2 ^= vec_load_le(2 * 16, src); + v3 ^= vec_load_le(3 * 16, src); + vec_store_le(v0, 0 * 16, dst); + vec_store_le(v1, 1 * 16, dst); + vec_store_le(v2, 2 * 16, dst); + vec_store_le(v3, 3 * 16, dst); + src += 64; + dst += 64; + + nblks--; + } + + vec_vsx_st(state3, 3 * 16, state); /* store counter */ + + return 0; +} + + +/********************************************************************** + 4-way chacha20 + **********************************************************************/ + +/* 4x4 32-bit integer matrix transpose */ +#define transpose_4x4(x0, x1, x2, x3) ({ \ + vector4x_u32 t1 = vec_mergeh(x0, x2); \ + vector4x_u32 t2 = vec_mergel(x0, x2); \ + vector4x_u32 t3 = vec_mergeh(x1, x3); \ + x3 = vec_mergel(x1, x3); \ + x0 = vec_mergeh(t1, t3); \ + x1 = vec_mergel(t1, t3); \ + x2 = vec_mergeh(t2, x3); \ + x3 = vec_mergel(t2, x3); \ + }) + +#define QUARTERROUND2(a1,b1,c1,d1,a2,b2,c2,d2) \ + PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2); \ + ROTATE(d1, rotate_16); ROTATE(d2, rotate_16); \ + PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2); \ + ROTATE(b1, rotate_12); ROTATE(b2, rotate_12); \ + PLUS(a1,b1); PLUS(a2,b2); XOR(d1,a1); XOR(d2,a2); \ + ROTATE(d1, rotate_8); ROTATE(d2, rotate_8); \ + PLUS(c1,d1); PLUS(c2,d2); XOR(b1,c1); XOR(b2,c2); \ + ROTATE(b1, rotate_7); ROTATE(b2, rotate_7); + +unsigned int ASM_FUNC_ATTR +_gcry_chacha20_ppc8_blocks4(u32 *state, byte *dst, const byte *src, + size_t nblks) +{ + vector4x_u32 counters_0123 = { 0, 1, 2, 3 }; + vector4x_u32 counter_4 = { 4, 0, 0, 0 }; + vector4x_u32 rotate_16 = { 16, 16, 16, 16 }; + vector4x_u32 rotate_12 = { 12, 12, 12, 12 }; + vector4x_u32 rotate_8 = { 8, 8, 8, 8 }; + vector4x_u32 rotate_7 = { 7, 7, 7, 7 }; + vector4x_u32 state0, state1, state2, state3; + vector4x_u32 v0, v1, v2, v3, v4, v5, v6, v7; + vector4x_u32 v8, v9, v10, v11, v12, v13, v14, v15; + vector4x_u32 tmp; + int i; + + /* force preload of constants to vector registers */ + __asm__ ("": "+v" (counters_0123) :: "memory"); + __asm__ ("": "+v" (counter_4) :: "memory"); + __asm__ ("": "+v" (rotate_16) :: "memory"); + __asm__ ("": "+v" (rotate_12) :: "memory"); + __asm__ ("": "+v" (rotate_8) :: "memory"); + __asm__ ("": "+v" (rotate_7) :: "memory"); + + state0 = vec_vsx_ld(0 * 16, state); + state1 = vec_vsx_ld(1 * 16, state); + state2 = vec_vsx_ld(2 * 16, state); + state3 = vec_vsx_ld(3 * 16, state); + + do + { + v0 = vec_splat(state0, 0); + v1 = vec_splat(state0, 1); + v2 = vec_splat(state0, 2); + v3 = vec_splat(state0, 3); + v4 = vec_splat(state1, 0); + v5 = vec_splat(state1, 1); + v6 = vec_splat(state1, 2); + v7 = vec_splat(state1, 3); + v8 = vec_splat(state2, 0); + v9 = vec_splat(state2, 1); + v10 = vec_splat(state2, 2); + v11 = vec_splat(state2, 3); + v12 = vec_splat(state3, 0); + v13 = vec_splat(state3, 1); + v14 = vec_splat(state3, 2); + v15 = vec_splat(state3, 3); + + v12 += counters_0123; + v13 -= vec_cmplt(v12, counters_0123); + + for (i = 20; i > 0; i -= 2) + { + QUARTERROUND2(v0, v4, v8, v12, v1, v5, v9, v13) + QUARTERROUND2(v2, v6, v10, v14, v3, v7, v11, v15) + QUARTERROUND2(v0, v5, v10, v15, v1, v6, v11, v12) + QUARTERROUND2(v2, v7, v8, v13, v3, v4, v9, v14) + } + + v0 += vec_splat(state0, 0); + v1 += vec_splat(state0, 1); + v2 += vec_splat(state0, 2); + v3 += vec_splat(state0, 3); + v4 += vec_splat(state1, 0); + v5 += vec_splat(state1, 1); + v6 += vec_splat(state1, 2); + v7 += vec_splat(state1, 3); + v8 += vec_splat(state2, 0); + v9 += vec_splat(state2, 1); + v10 += vec_splat(state2, 2); + v11 += vec_splat(state2, 3); + tmp = vec_splat(state3, 0); + tmp += counters_0123; + v12 += tmp; + v13 += vec_splat(state3, 1) - vec_cmplt(tmp, counters_0123); + v14 += vec_splat(state3, 2); + v15 += vec_splat(state3, 3); + ADD_U64(state3, counter_4); /* update counter */ + + transpose_4x4(v0, v1, v2, v3); + transpose_4x4(v4, v5, v6, v7); + transpose_4x4(v8, v9, v10, v11); + transpose_4x4(v12, v13, v14, v15); + + v0 ^= vec_load_le((64 * 0 + 16 * 0), src); + v1 ^= vec_load_le((64 * 1 + 16 * 0), src); + v2 ^= vec_load_le((64 * 2 + 16 * 0), src); + v3 ^= vec_load_le((64 * 3 + 16 * 0), src); + + v4 ^= vec_load_le((64 * 0 + 16 * 1), src); + v5 ^= vec_load_le((64 * 1 + 16 * 1), src); + v6 ^= vec_load_le((64 * 2 + 16 * 1), src); + v7 ^= vec_load_le((64 * 3 + 16 * 1), src); + + v8 ^= vec_load_le((64 * 0 + 16 * 2), src); + v9 ^= vec_load_le((64 * 1 + 16 * 2), src); + v10 ^= vec_load_le((64 * 2 + 16 * 2), src); + v11 ^= vec_load_le((64 * 3 + 16 * 2), src); + + v12 ^= vec_load_le((64 * 0 + 16 * 3), src); + v13 ^= vec_load_le((64 * 1 + 16 * 3), src); + v14 ^= vec_load_le((64 * 2 + 16 * 3), src); + v15 ^= vec_load_le((64 * 3 + 16 * 3), src); + + vec_store_le(v0, (64 * 0 + 16 * 0), dst); + vec_store_le(v1, (64 * 1 + 16 * 0), dst); + vec_store_le(v2, (64 * 2 + 16 * 0), dst); + vec_store_le(v3, (64 * 3 + 16 * 0), dst); + + vec_store_le(v4, (64 * 0 + 16 * 1), dst); + vec_store_le(v5, (64 * 1 + 16 * 1), dst); + vec_store_le(v6, (64 * 2 + 16 * 1), dst); + vec_store_le(v7, (64 * 3 + 16 * 1), dst); + + vec_store_le(v8, (64 * 0 + 16 * 2), dst); + vec_store_le(v9, (64 * 1 + 16 * 2), dst); + vec_store_le(v10, (64 * 2 + 16 * 2), dst); + vec_store_le(v11, (64 * 3 + 16 * 2), dst); + + vec_store_le(v12, (64 * 0 + 16 * 3), dst); + vec_store_le(v13, (64 * 1 + 16 * 3), dst); + vec_store_le(v14, (64 * 2 + 16 * 3), dst); + vec_store_le(v15, (64 * 3 + 16 * 3), dst); + + src += 4*64; + dst += 4*64; + + nblks -= 4; + } + while (nblks); + + vec_vsx_st(state3, 3 * 16, state); /* store counter */ + + return 0; +} + + +#if SIZEOF_UNSIGNED_LONG == 8 + +/********************************************************************** + 4-way stitched chacha20-poly1305 + **********************************************************************/ + +#define ADD_1305_64(A2, A1, A0, B2, B1, B0) \ + __asm__ ("addc %0, %3, %0\n" \ + "adde %1, %4, %1\n" \ + "adde %2, %5, %2\n" \ + : "+r" (A0), "+r" (A1), "+r" (A2) \ + : "r" (B0), "r" (B1), "r" (B2) \ + : "cc" ) + +#define MUL_MOD_1305_64_PART1(H2, H1, H0, R1, R0, R1_MULT5) do { \ + /* x = a * r (partial mod 2^130-5) */ \ + umul_ppmm(x0_hi, x0_lo, H0, R0); /* h0 * r0 */ \ + umul_ppmm(x1_hi, x1_lo, H0, R1); /* h0 * r1 */ \ + \ + umul_ppmm(t0_hi, t0_lo, H1, R1_MULT5); /* h1 * r1 mod 2^130-5 */ \ + } while (0) + +#define MUL_MOD_1305_64_PART2(H2, H1, H0, R1, R0, R1_MULT5) do { \ + add_ssaaaa(x0_hi, x0_lo, x0_hi, x0_lo, t0_hi, t0_lo); \ + umul_ppmm(t1_hi, t1_lo, H1, R0); /* h1 * r0 */ \ + add_ssaaaa(x1_hi, x1_lo, x1_hi, x1_lo, t1_hi, t1_lo); \ + \ + t1_lo = H2 * R1_MULT5; /* h2 * r1 mod 2^130-5 */ \ + t1_hi = H2 * R0; /* h2 * r0 */ \ + add_ssaaaa(H0, H1, x1_hi, x1_lo, t1_hi, t1_lo); \ + \ + /* carry propagation */ \ + H2 = H0 & 3; \ + H0 = (H0 >> 2) * 5; /* msb mod 2^130-5 */ \ + ADD_1305_64(H2, H1, H0, (u64)0, x0_hi, x0_lo); \ + } while (0) + +#define POLY1305_BLOCK_PART1(in_pos) do { \ + m0 = buf_get_le64(poly1305_src + (in_pos) + 0); \ + m1 = buf_get_le64(poly1305_src + (in_pos) + 8); \ + /* a = h + m */ \ + ADD_1305_64(h2, h1, h0, m2, m1, m0); \ + /* h = a * r (partial mod 2^130-5) */ \ + MUL_MOD_1305_64_PART1(h2, h1, h0, r1, r0, r1_mult5); \ + } while (0) + +#define POLY1305_BLOCK_PART2(in_pos) do { \ + MUL_MOD_1305_64_PART2(h2, h1, h0, r1, r0, r1_mult5); \ + } while (0) + +unsigned int ASM_FUNC_ATTR +_gcry_chacha20_poly1305_ppc8_blocks4(u32 *state, byte *dst, const byte *src, + size_t nblks, POLY1305_STATE *st, + const byte *poly1305_src) +{ + vector4x_u32 counters_0123 = { 0, 1, 2, 3 }; + vector4x_u32 counter_4 = { 4, 0, 0, 0 }; + vector4x_u32 rotate_16 = { 16, 16, 16, 16 }; + vector4x_u32 rotate_12 = { 12, 12, 12, 12 }; + vector4x_u32 rotate_8 = { 8, 8, 8, 8 }; + vector4x_u32 rotate_7 = { 7, 7, 7, 7 }; + vector4x_u32 state0, state1, state2, state3; + vector4x_u32 v0, v1, v2, v3, v4, v5, v6, v7; + vector4x_u32 v8, v9, v10, v11, v12, v13, v14, v15; + vector4x_u32 tmp; + u64 r0, r1, r1_mult5; + u64 h0, h1, h2; + u64 m0, m1, m2; + u64 x0_lo, x0_hi, x1_lo, x1_hi; + u64 t0_lo, t0_hi, t1_lo, t1_hi; + unsigned int i, o; + + /* load poly1305 state */ + m2 = 1; + h0 = st->h[0] + ((u64)st->h[1] << 32); + h1 = st->h[2] + ((u64)st->h[3] << 32); + h2 = st->h[4]; + r0 = st->r[0] + ((u64)st->r[1] << 32); + r1 = st->r[2] + ((u64)st->r[3] << 32); + r1_mult5 = (r1 >> 2) + r1; + + /* force preload of constants to vector registers */ + __asm__ ("": "+v" (counters_0123) :: "memory"); + __asm__ ("": "+v" (counter_4) :: "memory"); + __asm__ ("": "+v" (rotate_16) :: "memory"); + __asm__ ("": "+v" (rotate_12) :: "memory"); + __asm__ ("": "+v" (rotate_8) :: "memory"); + __asm__ ("": "+v" (rotate_7) :: "memory"); + + state0 = vec_vsx_ld(0 * 16, state); + state1 = vec_vsx_ld(1 * 16, state); + state2 = vec_vsx_ld(2 * 16, state); + state3 = vec_vsx_ld(3 * 16, state); + + do + { + v0 = vec_splat(state0, 0); + v1 = vec_splat(state0, 1); + v2 = vec_splat(state0, 2); + v3 = vec_splat(state0, 3); + v4 = vec_splat(state1, 0); + v5 = vec_splat(state1, 1); + v6 = vec_splat(state1, 2); + v7 = vec_splat(state1, 3); + v8 = vec_splat(state2, 0); + v9 = vec_splat(state2, 1); + v10 = vec_splat(state2, 2); + v11 = vec_splat(state2, 3); + v12 = vec_splat(state3, 0); + v13 = vec_splat(state3, 1); + v14 = vec_splat(state3, 2); + v15 = vec_splat(state3, 3); + + v12 += counters_0123; + v13 -= vec_cmplt(v12, counters_0123); + + for (o = 20; o; o -= 10) + { + for (i = 8; i; i -= 2) + { + POLY1305_BLOCK_PART1(0 * 16); + QUARTERROUND2(v0, v4, v8, v12, v1, v5, v9, v13) + POLY1305_BLOCK_PART2(); + QUARTERROUND2(v2, v6, v10, v14, v3, v7, v11, v15) + POLY1305_BLOCK_PART1(1 * 16); + poly1305_src += 2 * 16; + QUARTERROUND2(v0, v5, v10, v15, v1, v6, v11, v12) + POLY1305_BLOCK_PART2(); + QUARTERROUND2(v2, v7, v8, v13, v3, v4, v9, v14) + } + + QUARTERROUND2(v0, v4, v8, v12, v1, v5, v9, v13) + QUARTERROUND2(v2, v6, v10, v14, v3, v7, v11, v15) + QUARTERROUND2(v0, v5, v10, v15, v1, v6, v11, v12) + QUARTERROUND2(v2, v7, v8, v13, v3, v4, v9, v14) + } + + v0 += vec_splat(state0, 0); + v1 += vec_splat(state0, 1); + v2 += vec_splat(state0, 2); + v3 += vec_splat(state0, 3); + v4 += vec_splat(state1, 0); + v5 += vec_splat(state1, 1); + v6 += vec_splat(state1, 2); + v7 += vec_splat(state1, 3); + v8 += vec_splat(state2, 0); + v9 += vec_splat(state2, 1); + v10 += vec_splat(state2, 2); + v11 += vec_splat(state2, 3); + tmp = vec_splat(state3, 0); + tmp += counters_0123; + v12 += tmp; + v13 += vec_splat(state3, 1) - vec_cmplt(tmp, counters_0123); + v14 += vec_splat(state3, 2); + v15 += vec_splat(state3, 3); + ADD_U64(state3, counter_4); /* update counter */ + + transpose_4x4(v0, v1, v2, v3); + transpose_4x4(v4, v5, v6, v7); + transpose_4x4(v8, v9, v10, v11); + transpose_4x4(v12, v13, v14, v15); + + v0 ^= vec_load_le((64 * 0 + 16 * 0), src); + v1 ^= vec_load_le((64 * 1 + 16 * 0), src); + v2 ^= vec_load_le((64 * 2 + 16 * 0), src); + v3 ^= vec_load_le((64 * 3 + 16 * 0), src); + + v4 ^= vec_load_le((64 * 0 + 16 * 1), src); + v5 ^= vec_load_le((64 * 1 + 16 * 1), src); + v6 ^= vec_load_le((64 * 2 + 16 * 1), src); + v7 ^= vec_load_le((64 * 3 + 16 * 1), src); + + v8 ^= vec_load_le((64 * 0 + 16 * 2), src); + v9 ^= vec_load_le((64 * 1 + 16 * 2), src); + v10 ^= vec_load_le((64 * 2 + 16 * 2), src); + v11 ^= vec_load_le((64 * 3 + 16 * 2), src); + + v12 ^= vec_load_le((64 * 0 + 16 * 3), src); + v13 ^= vec_load_le((64 * 1 + 16 * 3), src); + v14 ^= vec_load_le((64 * 2 + 16 * 3), src); + v15 ^= vec_load_le((64 * 3 + 16 * 3), src); + + vec_store_le(v0, (64 * 0 + 16 * 0), dst); + vec_store_le(v1, (64 * 1 + 16 * 0), dst); + vec_store_le(v2, (64 * 2 + 16 * 0), dst); + vec_store_le(v3, (64 * 3 + 16 * 0), dst); + + vec_store_le(v4, (64 * 0 + 16 * 1), dst); + vec_store_le(v5, (64 * 1 + 16 * 1), dst); + vec_store_le(v6, (64 * 2 + 16 * 1), dst); + vec_store_le(v7, (64 * 3 + 16 * 1), dst); + + vec_store_le(v8, (64 * 0 + 16 * 2), dst); + vec_store_le(v9, (64 * 1 + 16 * 2), dst); + vec_store_le(v10, (64 * 2 + 16 * 2), dst); + vec_store_le(v11, (64 * 3 + 16 * 2), dst); + + vec_store_le(v12, (64 * 0 + 16 * 3), dst); + vec_store_le(v13, (64 * 1 + 16 * 3), dst); + vec_store_le(v14, (64 * 2 + 16 * 3), dst); + vec_store_le(v15, (64 * 3 + 16 * 3), dst); + + src += 4*64; + dst += 4*64; + + nblks -= 4; + } + while (nblks); + + vec_vsx_st(state3, 3 * 16, state); /* store counter */ + + /* store poly1305 state */ + st->h[0] = h0; + st->h[1] = h0 >> 32; + st->h[2] = h1; + st->h[3] = h1 >> 32; + st->h[4] = h2; + + return 0; +} + +#endif /* SIZEOF_UNSIGNED_LONG == 8 */ + +#endif /* ENABLE_PPC_CRYPTO_SUPPORT */ diff --git a/comm/third_party/libgcrypt/cipher/chacha20-s390x.S b/comm/third_party/libgcrypt/cipher/chacha20-s390x.S new file mode 100644 index 0000000000..9b1d59c6ad --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20-s390x.S @@ -0,0 +1,1561 @@ +/* chacha20-s390x.S - zSeries implementation of ChaCha20 cipher + * + * Copyright (C) 2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#if defined (__s390x__) && __GNUC__ >= 4 && __ARCH__ >= 9 +#include +#if defined(HAVE_GCC_INLINE_ASM_S390X_VX) + +#include "asm-common-s390x.h" +#include "asm-poly1305-s390x.h" + +.machine "z13+vx" +.text + +.balign 16 +.Lconsts: +.Lwordswap: + .byte 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 +.Lbswap128: + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +.Lbswap32: + .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 +.Lone: + .long 0, 0, 0, 1 +.Ladd_counter_0123: + .long 0, 1, 2, 3 +.Ladd_counter_4567: + .long 4, 5, 6, 7 + +/* register macros */ +#define INPUT %r2 +#define DST %r3 +#define SRC %r4 +#define NBLKS %r0 +#define ROUND %r1 + +/* stack structure */ + +#define STACK_FRAME_STD (8 * 16 + 8 * 4) +#define STACK_FRAME_F8_F15 (8 * 8) +#define STACK_FRAME_Y0_Y15 (16 * 16) +#define STACK_FRAME_CTR (4 * 16) +#define STACK_FRAME_PARAMS (6 * 8) + +#define STACK_MAX (STACK_FRAME_STD + STACK_FRAME_F8_F15 + \ + STACK_FRAME_Y0_Y15 + STACK_FRAME_CTR + \ + STACK_FRAME_PARAMS) + +#define STACK_F8 (STACK_MAX - STACK_FRAME_F8_F15) +#define STACK_F9 (STACK_F8 + 8) +#define STACK_F10 (STACK_F9 + 8) +#define STACK_F11 (STACK_F10 + 8) +#define STACK_F12 (STACK_F11 + 8) +#define STACK_F13 (STACK_F12 + 8) +#define STACK_F14 (STACK_F13 + 8) +#define STACK_F15 (STACK_F14 + 8) +#define STACK_Y0_Y15 (STACK_F8 - STACK_FRAME_Y0_Y15) +#define STACK_CTR (STACK_Y0_Y15 - STACK_FRAME_CTR) +#define STACK_INPUT (STACK_CTR - STACK_FRAME_PARAMS) +#define STACK_DST (STACK_INPUT + 8) +#define STACK_SRC (STACK_DST + 8) +#define STACK_NBLKS (STACK_SRC + 8) +#define STACK_POCTX (STACK_NBLKS + 8) +#define STACK_POSRC (STACK_POCTX + 8) + +#define STACK_G0_H3 STACK_Y0_Y15 + +/* vector registers */ +#define A0 %v0 +#define A1 %v1 +#define A2 %v2 +#define A3 %v3 + +#define B0 %v4 +#define B1 %v5 +#define B2 %v6 +#define B3 %v7 + +#define C0 %v8 +#define C1 %v9 +#define C2 %v10 +#define C3 %v11 + +#define D0 %v12 +#define D1 %v13 +#define D2 %v14 +#define D3 %v15 + +#define E0 %v16 +#define E1 %v17 +#define E2 %v18 +#define E3 %v19 + +#define F0 %v20 +#define F1 %v21 +#define F2 %v22 +#define F3 %v23 + +#define G0 %v24 +#define G1 %v25 +#define G2 %v26 +#define G3 %v27 + +#define H0 %v28 +#define H1 %v29 +#define H2 %v30 +#define H3 %v31 + +#define IO0 E0 +#define IO1 E1 +#define IO2 E2 +#define IO3 E3 +#define IO4 F0 +#define IO5 F1 +#define IO6 F2 +#define IO7 F3 + +#define S0 G0 +#define S1 G1 +#define S2 G2 +#define S3 G3 + +#define TMP0 H0 +#define TMP1 H1 +#define TMP2 H2 +#define TMP3 H3 + +#define X0 A0 +#define X1 A1 +#define X2 A2 +#define X3 A3 +#define X4 B0 +#define X5 B1 +#define X6 B2 +#define X7 B3 +#define X8 C0 +#define X9 C1 +#define X10 C2 +#define X11 C3 +#define X12 D0 +#define X13 D1 +#define X14 D2 +#define X15 D3 + +#define Y0 E0 +#define Y1 E1 +#define Y2 E2 +#define Y3 E3 +#define Y4 F0 +#define Y5 F1 +#define Y6 F2 +#define Y7 F3 +#define Y8 G0 +#define Y9 G1 +#define Y10 G2 +#define Y11 G3 +#define Y12 H0 +#define Y13 H1 +#define Y14 H2 +#define Y15 H3 + +/********************************************************************** + helper macros + **********************************************************************/ + +#define _ /*_*/ + +#define CLEAR(x,...) vzero x; + +#define START_STACK(last_r) \ + lgr %r0, %r15; \ + lghi %r1, ~15; \ + stmg %r6, last_r, 6 * 8(%r15); \ + aghi %r0, -STACK_MAX; \ + ngr %r0, %r1; \ + lgr %r1, %r15; \ + CFI_DEF_CFA_REGISTER(1); \ + lgr %r15, %r0; \ + stg %r1, 0(%r15); \ + CFI_CFA_ON_STACK(0, 0); \ + std %f8, STACK_F8(%r15); \ + std %f9, STACK_F9(%r15); \ + std %f10, STACK_F10(%r15); \ + std %f11, STACK_F11(%r15); \ + std %f12, STACK_F12(%r15); \ + std %f13, STACK_F13(%r15); \ + std %f14, STACK_F14(%r15); \ + std %f15, STACK_F15(%r15); + +#define END_STACK(last_r) \ + lg %r1, 0(%r15); \ + ld %f8, STACK_F8(%r15); \ + ld %f9, STACK_F9(%r15); \ + ld %f10, STACK_F10(%r15); \ + ld %f11, STACK_F11(%r15); \ + ld %f12, STACK_F12(%r15); \ + ld %f13, STACK_F13(%r15); \ + ld %f14, STACK_F14(%r15); \ + ld %f15, STACK_F15(%r15); \ + lmg %r6, last_r, 6 * 8(%r1); \ + lgr %r15, %r1; \ + CFI_DEF_CFA_REGISTER(DW_REGNO_SP); + +#define PLUS(dst,src) \ + vaf dst, dst, src; + +#define XOR(dst,src) \ + vx dst, dst, src; + +#define ROTATE(v1,c) \ + verllf v1, v1, (c)(0); + +#define WORD_ROTATE(v1,s) \ + vsldb v1, v1, v1, ((s) * 4); + +#define DST_1(OPER, I, J) \ + OPER(A##I, J); + +#define DST_2(OPER, I, J) \ + OPER(A##I, J); OPER(B##I, J); + +#define DST_4(OPER, I, J) \ + OPER(A##I, J); OPER(B##I, J); OPER(C##I, J); OPER(D##I, J); + +#define DST_8(OPER, I, J) \ + OPER(A##I, J); OPER(B##I, J); OPER(C##I, J); OPER(D##I, J); \ + OPER(E##I, J); OPER(F##I, J); OPER(G##I, J); OPER(H##I, J); + +#define DST_SRC_1(OPER, I, J) \ + OPER(A##I, A##J); + +#define DST_SRC_2(OPER, I, J) \ + OPER(A##I, A##J); OPER(B##I, B##J); + +#define DST_SRC_4(OPER, I, J) \ + OPER(A##I, A##J); OPER(B##I, B##J); OPER(C##I, C##J); \ + OPER(D##I, D##J); + +#define DST_SRC_8(OPER, I, J) \ + OPER(A##I, A##J); OPER(B##I, B##J); OPER(C##I, C##J); \ + OPER(D##I, D##J); OPER(E##I, E##J); OPER(F##I, F##J); \ + OPER(G##I, G##J); OPER(H##I, H##J); + +/********************************************************************** + round macros + **********************************************************************/ + +#define QUARTERROUND4_POLY(wrot_1,wrot_2,wrot_3,op1,op2) \ + op1; DST_SRC_1(PLUS, 0, 1); DST_SRC_1(XOR, 3, 0); DST_1(ROTATE, 3, 16); \ + DST_SRC_1(PLUS, 2, 3); DST_SRC_1(XOR, 1, 2); DST_1(ROTATE, 1, 12); \ + DST_SRC_1(PLUS, 0, 1); DST_SRC_1(XOR, 3, 0); DST_1(ROTATE, 3, 8); \ + op2; DST_SRC_1(PLUS, 2, 3); DST_SRC_1(XOR, 1, 2); DST_1(ROTATE, 1, 7); \ + DST_1(WORD_ROTATE, 3, wrot_3); \ + DST_1(WORD_ROTATE, 2, wrot_2); \ + DST_1(WORD_ROTATE, 1, wrot_1); + +#define QUARTERROUND4(wrot_1,wrot_2,wrot_3) \ + QUARTERROUND4_POLY(wrot_1,wrot_2,wrot_3,,) + +#define QUARTERROUND4_2_POLY(wrot_1,wrot_2,wrot_3,op1,op2,op3,op4) \ + op1; DST_SRC_2(PLUS, 0, 1); DST_SRC_2(XOR, 3, 0); DST_2(ROTATE, 3, 16); \ + DST_SRC_2(PLUS, 2, 3); op2; DST_SRC_2(XOR, 1, 2); DST_2(ROTATE, 1, 12); \ + DST_SRC_2(PLUS, 0, 1); DST_SRC_2(XOR, 3, 0); op3; DST_2(ROTATE, 3, 8); \ + DST_SRC_2(PLUS, 2, 3); DST_SRC_2(XOR, 1, 2); DST_2(ROTATE, 1, 7); op4; \ + DST_2(WORD_ROTATE, 3, wrot_3); \ + DST_2(WORD_ROTATE, 2, wrot_2); \ + DST_2(WORD_ROTATE, 1, wrot_1); + +#define QUARTERROUND4_2(wrot_1,wrot_2,wrot_3) \ + QUARTERROUND4_2_POLY(wrot_1,wrot_2,wrot_3,,,,) + +#define QUARTERROUND4_4_POLY(wrot_1,wrot_2,wrot_3,op1,op2,op3,op4,op5,op6) \ + DST_SRC_4(PLUS, 0, 1); DST_SRC_4(XOR, 3, 0); op1; DST_4(ROTATE, 3, 16); \ + DST_SRC_4(PLUS, 2, 3); op2; DST_SRC_4(XOR, 1, 2); DST_4(ROTATE, 1, 12); \ + op3; DST_SRC_4(PLUS, 0, 1); DST_SRC_4(XOR, 3, 0); op4; DST_4(ROTATE, 3, 8); \ + DST_SRC_4(PLUS, 2, 3); op5; DST_SRC_4(XOR, 1, 2); DST_4(ROTATE, 1, 7); \ + op6; \ + DST_4(WORD_ROTATE, 3, wrot_3); \ + DST_4(WORD_ROTATE, 2, wrot_2); \ + DST_4(WORD_ROTATE, 1, wrot_1); + +#define QUARTERROUND4_4(wrot_1,wrot_2,wrot_3) \ + QUARTERROUND4_4_POLY(wrot_1,wrot_2,wrot_3,,,,,,) + +/********************************************************************** + 4-way && 2-way && 1-way chacha20 ("horizontal") + **********************************************************************/ + +.balign 8 +.globl _gcry_chacha20_s390x_vx_blocks4_2_1 +ELF(.type _gcry_chacha20_s390x_vx_blocks4_2_1,@function;) + +_gcry_chacha20_s390x_vx_blocks4_2_1: + /* input: + * %r2: input + * %r3: dst + * %r4: src + * %r5: nblks + */ + CFI_STARTPROC(); + + START_STACK(%r7); + lgr NBLKS, %r5; + + /* Load constants. */ + larl %r7, .Lconsts; + vl TMP0, (.Lwordswap - .Lconsts)(%r7); + vl TMP1, (.Lone - .Lconsts)(%r7); + vl TMP2, (.Lbswap128 - .Lconsts)(%r7); + + /* Load state. */ + vlm S0, S3, 0(INPUT); + vperm S0, S0, S0, TMP0; + vperm S1, S1, S1, TMP0; + vperm S2, S2, S2, TMP0; + vperm S3, S3, S3, TMP0; + + clgijl NBLKS, 4, .Lloop2; + +.balign 4 +.Lloop4: + /* Process four chacha20 blocks. */ + vlr TMP3, S3; + lghi ROUND, (20 / 2); + vlr A0, S0; + vlr A1, S1; + vlr A2, S2; + vlr A3, TMP3; + vag TMP3, TMP3, TMP1; + vlr B0, S0; + vlr B1, S1; + vlr B2, S2; + vlr B3, TMP3; + vag TMP3, TMP3, TMP1; + vlr C0, S0; + vlr C1, S1; + vlr C2, S2; + vlr C3, TMP3; + vlr D0, S0; + vlr D1, S1; + vlr D2, S2; + vag D3, TMP3, TMP1; + + slgfi NBLKS, 4; + +.balign 4 +.Lround2_4: + QUARTERROUND4_4(3, 2, 1); + QUARTERROUND4_4(1, 2, 3); + brctg ROUND, .Lround2_4; + + vlm IO0, IO7, 0(SRC); + + PLUS(A0, S0); + PLUS(A1, S1); + PLUS(A2, S2); + PLUS(A3, S3); + vag S3, S3, TMP1; /* Update counter. */ + PLUS(B0, S0); + PLUS(B1, S1); + PLUS(B2, S2); + PLUS(B3, S3); + vag S3, S3, TMP1; /* Update counter. */ + vperm A0, A0, A0, TMP2; + vperm A1, A1, A1, TMP2; + vperm A2, A2, A2, TMP2; + vperm A3, A3, A3, TMP2; + vperm B0, B0, B0, TMP2; + vperm B1, B1, B1, TMP2; + vperm B2, B2, B2, TMP2; + vperm B3, B3, B3, TMP2; + PLUS(C0, S0); + PLUS(C1, S1); + PLUS(C2, S2); + PLUS(C3, S3); + vag S3, S3, TMP1; /* Update counter. */ + PLUS(D0, S0); + PLUS(D1, S1); + PLUS(D2, S2); + PLUS(D3, S3); + vag S3, S3, TMP1; /* Update counter. */ + vperm C0, C0, C0, TMP2; + vperm C1, C1, C1, TMP2; + vperm C2, C2, C2, TMP2; + vperm C3, C3, C3, TMP2; + vperm D0, D0, D0, TMP2; + vperm D1, D1, D1, TMP2; + vperm D2, D2, D2, TMP2; + vperm D3, D3, D3, TMP2; + + XOR(IO0, A0); + XOR(IO1, A1); + XOR(IO2, A2); + XOR(IO3, A3); + XOR(IO4, B0); + XOR(IO5, B1); + XOR(IO6, B2); + XOR(IO7, B3); + vlm A0, B3, 128(SRC); + vstm IO0, IO7, 0(DST); + XOR(A0, C0); + XOR(A1, C1); + XOR(A2, C2); + XOR(A3, C3); + XOR(B0, D0); + XOR(B1, D1); + XOR(B2, D2); + XOR(B3, D3); + vstm A0, B3, 128(DST); + + aghi SRC, 256; + aghi DST, 256; + + clgijhe NBLKS, 4, .Lloop4; + + CLEAR(C0); + CLEAR(C1); + CLEAR(C2); + CLEAR(C3); + CLEAR(D0); + CLEAR(D1); + CLEAR(D2); + CLEAR(D3); + +.balign 4 +.Lloop2: + clgijl NBLKS, 2, .Lloop1; + + /* Process two chacha20 blocks. */ + lghi ROUND, (20 / 2); + vlr A0, S0; + vlr A1, S1; + vlr A2, S2; + vlr A3, S3; + vlr B0, S0; + vlr B1, S1; + vlr B2, S2; + vag B3, S3, TMP1; + + slgfi NBLKS, 2; + +.balign 4 +.Lround2_2: + QUARTERROUND4_2(3, 2, 1); + QUARTERROUND4_2(1, 2, 3); + brctg ROUND, .Lround2_2; + + vlm IO0, IO7, 0(SRC); + + PLUS(A0, S0); + PLUS(A1, S1); + PLUS(A2, S2); + PLUS(A3, S3); + vag S3, S3, TMP1; /* Update counter. */ + PLUS(B0, S0); + PLUS(B1, S1); + PLUS(B2, S2); + PLUS(B3, S3); + vag S3, S3, TMP1; /* Update counter. */ + vperm A0, A0, A0, TMP2; + vperm A1, A1, A1, TMP2; + vperm A2, A2, A2, TMP2; + vperm A3, A3, A3, TMP2; + vperm B0, B0, B0, TMP2; + vperm B1, B1, B1, TMP2; + vperm B2, B2, B2, TMP2; + vperm B3, B3, B3, TMP2; + + XOR(IO0, A0); + XOR(IO1, A1); + XOR(IO2, A2); + XOR(IO3, A3); + XOR(IO4, B0); + XOR(IO5, B1); + XOR(IO6, B2); + XOR(IO7, B3); + vstm IO0, IO7, 0(DST); + + aghi SRC, 128; + aghi DST, 128; + + clgijhe NBLKS, 2, .Lloop2; + + CLEAR(B0); + CLEAR(B1); + CLEAR(B2); + CLEAR(B3); + +.balign 4 +.Lloop1: + clgijl NBLKS, 1, .Ldone; + + /* Process one chacha20 block.*/ + lghi ROUND, (20 / 2); + vlr A0, S0; + vlr A1, S1; + vlr A2, S2; + vlr A3, S3; + + slgfi NBLKS, 1; + +.balign 4 +.Lround2_1: + QUARTERROUND4(3, 2, 1); + QUARTERROUND4(1, 2, 3); + brct ROUND, .Lround2_1; + + vlm IO0, IO3, 0(SRC); + + PLUS(A0, S0); + PLUS(A1, S1); + PLUS(A2, S2); + PLUS(A3, S3); + vag S3, S3, TMP1; /* Update counter. */ + + vperm A0, A0, A0, TMP2; + vperm A1, A1, A1, TMP2; + vperm A2, A2, A2, TMP2; + vperm A3, A3, A3, TMP2; + XOR(IO0, A0); + XOR(IO1, A1); + XOR(IO2, A2); + XOR(IO3, A3); + vstm IO0, IO3, 0(DST); + + aghi SRC, 64; + aghi DST, 64; + + clgijhe NBLKS, 1, .Lloop1; + +.balign 4 +.Ldone: + /* Store counter. */ + vperm S3, S3, S3, TMP0; + vst S3, (48)(INPUT); + + /* Clear the used vector registers. */ + CLEAR(A0); + CLEAR(A1); + CLEAR(A2); + CLEAR(A3); + CLEAR(IO0); + CLEAR(IO1); + CLEAR(IO2); + CLEAR(IO3); + CLEAR(IO4); + CLEAR(IO5); + CLEAR(IO6); + CLEAR(IO7); + CLEAR(TMP0); + CLEAR(TMP1); + CLEAR(TMP2); + + END_STACK(%r7); + xgr %r2, %r2; + br %r14; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_s390x_vx_blocks4_2_1, + .-_gcry_chacha20_s390x_vx_blocks4_2_1;) + +/********************************************************************** + 4-way && 2-way && 1-way stitched chacha20-poly1305 ("horizontal") + **********************************************************************/ + +.balign 8 +.globl _gcry_chacha20_poly1305_s390x_vx_blocks4_2_1 +ELF(.type _gcry_chacha20_poly1305_s390x_vx_blocks4_2_1,@function;) + +_gcry_chacha20_poly1305_s390x_vx_blocks4_2_1: + /* input: + * %r2: input + * %r3: dst + * %r4: src + * %r5: nblks + * %r6: poly1305 state + * 160(%r15): poly1305 src + */ + CFI_STARTPROC(); + + START_STACK(%r14); + lgr NBLKS, %r5; + + /* Load constants. */ + larl %r8, .Lconsts; + vl TMP0, (.Lwordswap - .Lconsts)(%r8); + vl TMP1, (.Lone - .Lconsts)(%r8); + vl TMP2, (.Lbswap128 - .Lconsts)(%r8); + + /* Load state. */ + vlm S0, S3, 0(INPUT); + vperm S0, S0, S0, TMP0; + vperm S1, S1, S1, TMP0; + vperm S2, S2, S2, TMP0; + vperm S3, S3, S3, TMP0; + + /* Store parameters to stack. */ + stmg %r2, %r6, STACK_INPUT(%r15); + + lgr POLY_RSTATE, %r6; + lgr NBLKS, %r5; + + lg POLY_RSRC, 0(%r15); + lg POLY_RSRC, 160(POLY_RSRC); + stg POLY_RSRC, STACK_POSRC(%r15); + + /* Load poly1305 state */ + POLY1305_LOAD_STATE(); + + clgijl NBLKS, 4, .Lloop2_poly; + +.balign 4 +.Lloop4_poly: + /* Process four chacha20 blocks and 16 poly1305 blocks. */ + vlr TMP3, S3; + lghi ROUND, (20 / 4); + vlr A0, S0; + vlr A1, S1; + vlr A2, S2; + vlr A3, TMP3; + vag TMP3, TMP3, TMP1; + vlr B0, S0; + vlr B1, S1; + vlr B2, S2; + vlr B3, TMP3; + vag TMP3, TMP3, TMP1; + vlr C0, S0; + vlr C1, S1; + vlr C2, S2; + vlr C3, TMP3; + vlr D0, S0; + vlr D1, S1; + vlr D2, S2; + vag D3, TMP3, TMP1; + + slgfi NBLKS, 4; + +.balign 4 +.Lround4_4_poly: + /* Total 15 poly1305 blocks processed by this loop. */ + QUARTERROUND4_4_POLY(3, 2, 1, + POLY1305_BLOCK_PART1(0 * 16), + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6()); + QUARTERROUND4_4_POLY(1, 2, 3, + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8(), + POLY1305_BLOCK_PART1(1 * 16), + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4()); + QUARTERROUND4_4_POLY(3, 2, 1, + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8(), + POLY1305_BLOCK_PART1(2 * 16); + INC_POLY1305_SRC(3 * 16), + POLY1305_BLOCK_PART2()); + QUARTERROUND4_4_POLY(1, 2, 3, + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8()); + brctg ROUND, .Lround4_4_poly; + + POLY1305_BLOCK_PART1(0 * 16); + INC_POLY1305_SRC(1 * 16); + stg POLY_RSRC, STACK_POSRC(%r15); + + lg %r14, STACK_SRC(%r15); + vlm IO0, IO7, 0(%r14); + + PLUS(A0, S0); + PLUS(A1, S1); + PLUS(A2, S2); + PLUS(A3, S3); + vag S3, S3, TMP1; /* Update counter. */ + POLY1305_BLOCK_PART2(); + PLUS(B0, S0); + PLUS(B1, S1); + PLUS(B2, S2); + PLUS(B3, S3); + vag S3, S3, TMP1; /* Update counter. */ + POLY1305_BLOCK_PART3(); + vperm A0, A0, A0, TMP2; + vperm A1, A1, A1, TMP2; + vperm A2, A2, A2, TMP2; + vperm A3, A3, A3, TMP2; + vperm B0, B0, B0, TMP2; + vperm B1, B1, B1, TMP2; + vperm B2, B2, B2, TMP2; + vperm B3, B3, B3, TMP2; + POLY1305_BLOCK_PART4(); + PLUS(C0, S0); + PLUS(C1, S1); + PLUS(C2, S2); + PLUS(C3, S3); + vag S3, S3, TMP1; /* Update counter. */ + PLUS(D0, S0); + PLUS(D1, S1); + PLUS(D2, S2); + PLUS(D3, S3); + vag S3, S3, TMP1; /* Update counter. */ + POLY1305_BLOCK_PART5(); + vperm C0, C0, C0, TMP2; + vperm C1, C1, C1, TMP2; + vperm C2, C2, C2, TMP2; + vperm C3, C3, C3, TMP2; + vperm D0, D0, D0, TMP2; + vperm D1, D1, D1, TMP2; + vperm D2, D2, D2, TMP2; + vperm D3, D3, D3, TMP2; + + POLY1305_BLOCK_PART6(); + XOR(IO0, A0); + XOR(IO1, A1); + XOR(IO2, A2); + XOR(IO3, A3); + XOR(IO4, B0); + XOR(IO5, B1); + XOR(IO6, B2); + XOR(IO7, B3); + vlm A0, B3, 128(%r14); + aghi %r14, 256; + stg %r14, STACK_SRC(%r15); + + lg %r14, STACK_DST(%r15); + POLY1305_BLOCK_PART7(); + vstm IO0, IO7, 0(%r14); + XOR(A0, C0); + XOR(A1, C1); + XOR(A2, C2); + XOR(A3, C3); + XOR(B0, D0); + XOR(B1, D1); + XOR(B2, D2); + XOR(B3, D3); + POLY1305_BLOCK_PART8(); + vstm A0, B3, 128(%r14); + aghi %r14, 256; + stg %r14, STACK_DST(%r15); + + lg POLY_RSRC, STACK_POSRC(%r15); + + clgijhe NBLKS, 4, .Lloop4_poly; + + CLEAR(C0); + CLEAR(C1); + CLEAR(C2); + CLEAR(C3); + CLEAR(D0); + CLEAR(D1); + CLEAR(D2); + CLEAR(D3); + +.balign 4 +.Lloop2_poly: + clgijl NBLKS, 2, .Lloop1_poly; + + /* Process two chacha20 and eight poly1305 blocks. */ + lghi ROUND, ((20 - 4) / 2); + vlr A0, S0; + vlr A1, S1; + vlr A2, S2; + vlr A3, S3; + vlr B0, S0; + vlr B1, S1; + vlr B2, S2; + vag B3, S3, TMP1; + + slgfi NBLKS, 2; + +.balign 4 +.Lround4_2_poly: + /* Total eight poly1305 blocks processed by this loop. */ + QUARTERROUND4_2_POLY(3, 2, 1, + POLY1305_BLOCK_PART1(0 * 16), + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4()); + INC_POLY1305_SRC(1 * 16); + QUARTERROUND4_2_POLY(1, 2, 3, + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8()); + brctg ROUND, .Lround4_2_poly; + + stg POLY_RSRC, STACK_POSRC(%r15); + lg %r14, STACK_SRC(%r15); + + QUARTERROUND4_2(3, 2, 1); + QUARTERROUND4_2(1, 2, 3); + QUARTERROUND4_2(3, 2, 1); + QUARTERROUND4_2(1, 2, 3); + + vlm IO0, IO7, 0(%r14); + aghi %r14, 128; + stg %r14, STACK_SRC(%r15); + + PLUS(A0, S0); + PLUS(A1, S1); + PLUS(A2, S2); + PLUS(A3, S3); + vag S3, S3, TMP1; /* Update counter. */ + PLUS(B0, S0); + PLUS(B1, S1); + PLUS(B2, S2); + PLUS(B3, S3); + vag S3, S3, TMP1; /* Update counter. */ + vperm A0, A0, A0, TMP2; + vperm A1, A1, A1, TMP2; + vperm A2, A2, A2, TMP2; + vperm A3, A3, A3, TMP2; + vperm B0, B0, B0, TMP2; + vperm B1, B1, B1, TMP2; + vperm B2, B2, B2, TMP2; + vperm B3, B3, B3, TMP2; + + lg %r14, STACK_DST(%r15); + XOR(IO0, A0); + XOR(IO1, A1); + XOR(IO2, A2); + XOR(IO3, A3); + XOR(IO4, B0); + XOR(IO5, B1); + XOR(IO6, B2); + XOR(IO7, B3); + vstm IO0, IO7, 0(%r14); + aghi %r14, 128; + stg %r14, STACK_DST(%r15); + + lg POLY_RSRC, STACK_POSRC(%r15); + + clgijhe NBLKS, 2, .Lloop2_poly; + + CLEAR(B0); + CLEAR(B1); + CLEAR(B2); + CLEAR(B3); + +.balign 4 +.Lloop1_poly: + clgijl NBLKS, 1, .Ldone_poly; + + /* Process one chacha20 block and four poly1305 blocks.*/ + lghi ROUND, ((20 - 4) / 4); + vlr A0, S0; + vlr A1, S1; + vlr A2, S2; + vlr A3, S3; + + slgfi NBLKS, 1; + +.balign 4 +.Lround4_1_poly: + /* Total four poly1305 blocks processed by this loop. */ + QUARTERROUND4_POLY(3, 2, 1, + POLY1305_BLOCK_PART1(0 * 16), + POLY1305_BLOCK_PART2()); + INC_POLY1305_SRC(1 * 16); + QUARTERROUND4_POLY(1, 2, 3, + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4()); + QUARTERROUND4_POLY(3, 2, 1, + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6()); + QUARTERROUND4_POLY(1, 2, 3, + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8()); + brct ROUND, .Lround4_1_poly; + + stg POLY_RSRC, STACK_POSRC(%r15); + lg %r14, STACK_SRC(%r15); + + QUARTERROUND4(3, 2, 1); + QUARTERROUND4(1, 2, 3); + QUARTERROUND4(3, 2, 1); + QUARTERROUND4(1, 2, 3); + + vlm IO0, IO3, 0(%r14); + aghi %r14, 64; + stg %r14, STACK_SRC(%r15); + + PLUS(A0, S0); + PLUS(A1, S1); + PLUS(A2, S2); + PLUS(A3, S3); + vag S3, S3, TMP1; /* Update counter. */ + + lg %r14, STACK_DST(%r15); + vperm A0, A0, A0, TMP2; + vperm A1, A1, A1, TMP2; + vperm A2, A2, A2, TMP2; + vperm A3, A3, A3, TMP2; + XOR(IO0, A0); + XOR(IO1, A1); + XOR(IO2, A2); + XOR(IO3, A3); + vstm IO0, IO3, 0(%r14); + aghi %r14, 64; + stg %r14, STACK_DST(%r15); + + lg POLY_RSRC, STACK_POSRC(%r15); + + clgijhe NBLKS, 1, .Lloop1_poly; + +.balign 4 +.Ldone_poly: + /* Store poly1305 state */ + lg POLY_RSTATE, STACK_POCTX(%r15); + POLY1305_STORE_STATE(); + + /* Store counter. */ + lg INPUT, STACK_INPUT(%r15); + vperm S3, S3, S3, TMP0; + vst S3, (48)(INPUT); + + /* Clear the used vector registers. */ + CLEAR(A0); + CLEAR(A1); + CLEAR(A2); + CLEAR(A3); + CLEAR(IO0); + CLEAR(IO1); + CLEAR(IO2); + CLEAR(IO3); + CLEAR(IO4); + CLEAR(IO5); + CLEAR(IO6); + CLEAR(IO7); + CLEAR(TMP0); + CLEAR(TMP1); + CLEAR(TMP2); + + END_STACK(%r14); + xgr %r2, %r2; + br %r14; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_poly1305_s390x_vx_blocks4_2_1, + .-_gcry_chacha20_poly1305_s390x_vx_blocks4_2_1;) + +/********************************************************************** + 8-way chacha20 ("vertical") + **********************************************************************/ + +#define QUARTERROUND4_V8_POLY(x0,x1,x2,x3,x4,x5,x6,x7,\ + x8,x9,x10,x11,x12,x13,x14,x15,\ + y0,y1,y2,y3,y4,y5,y6,y7,\ + y8,y9,y10,y11,y12,y13,y14,y15,\ + op1,op2,op3,op4,op5,op6,op7,op8,\ + op9,op10,op11,op12) \ + op1; \ + PLUS(x0, x1); PLUS(x4, x5); \ + PLUS(x8, x9); PLUS(x12, x13); \ + PLUS(y0, y1); PLUS(y4, y5); \ + PLUS(y8, y9); PLUS(y12, y13); \ + op2; \ + XOR(x3, x0); XOR(x7, x4); \ + XOR(x11, x8); XOR(x15, x12); \ + XOR(y3, y0); XOR(y7, y4); \ + XOR(y11, y8); XOR(y15, y12); \ + op3; \ + ROTATE(x3, 16); ROTATE(x7, 16); \ + ROTATE(x11, 16); ROTATE(x15, 16); \ + ROTATE(y3, 16); ROTATE(y7, 16); \ + ROTATE(y11, 16); ROTATE(y15, 16); \ + op4; \ + PLUS(x2, x3); PLUS(x6, x7); \ + PLUS(x10, x11); PLUS(x14, x15); \ + PLUS(y2, y3); PLUS(y6, y7); \ + PLUS(y10, y11); PLUS(y14, y15); \ + op5; \ + XOR(x1, x2); XOR(x5, x6); \ + XOR(x9, x10); XOR(x13, x14); \ + XOR(y1, y2); XOR(y5, y6); \ + XOR(y9, y10); XOR(y13, y14); \ + op6; \ + ROTATE(x1,12); ROTATE(x5,12); \ + ROTATE(x9,12); ROTATE(x13,12); \ + ROTATE(y1,12); ROTATE(y5,12); \ + ROTATE(y9,12); ROTATE(y13,12); \ + op7; \ + PLUS(x0, x1); PLUS(x4, x5); \ + PLUS(x8, x9); PLUS(x12, x13); \ + PLUS(y0, y1); PLUS(y4, y5); \ + PLUS(y8, y9); PLUS(y12, y13); \ + op8; \ + XOR(x3, x0); XOR(x7, x4); \ + XOR(x11, x8); XOR(x15, x12); \ + XOR(y3, y0); XOR(y7, y4); \ + XOR(y11, y8); XOR(y15, y12); \ + op9; \ + ROTATE(x3,8); ROTATE(x7,8); \ + ROTATE(x11,8); ROTATE(x15,8); \ + ROTATE(y3,8); ROTATE(y7,8); \ + ROTATE(y11,8); ROTATE(y15,8); \ + op10; \ + PLUS(x2, x3); PLUS(x6, x7); \ + PLUS(x10, x11); PLUS(x14, x15); \ + PLUS(y2, y3); PLUS(y6, y7); \ + PLUS(y10, y11); PLUS(y14, y15); \ + op11; \ + XOR(x1, x2); XOR(x5, x6); \ + XOR(x9, x10); XOR(x13, x14); \ + XOR(y1, y2); XOR(y5, y6); \ + XOR(y9, y10); XOR(y13, y14); \ + op12; \ + ROTATE(x1,7); ROTATE(x5,7); \ + ROTATE(x9,7); ROTATE(x13,7); \ + ROTATE(y1,7); ROTATE(y5,7); \ + ROTATE(y9,7); ROTATE(y13,7); + +#define QUARTERROUND4_V8(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,\ + y0,y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12,y13,y14,y15) \ + QUARTERROUND4_V8_POLY(x0,x1,x2,x3,x4,x5,x6,x7,\ + x8,x9,x10,x11,x12,x13,x14,x15,\ + y0,y1,y2,y3,y4,y5,y6,y7,\ + y8,y9,y10,y11,y12,y13,y14,y15,\ + ,,,,,,,,,,,) + +#define TRANSPOSE_4X4_2(v0,v1,v2,v3,va,vb,vc,vd,tmp0,tmp1,tmp2,tmpa,tmpb,tmpc) \ + vmrhf tmp0, v0, v1; \ + vmrhf tmp1, v2, v3; \ + vmrlf tmp2, v0, v1; \ + vmrlf v3, v2, v3; \ + vmrhf tmpa, va, vb; \ + vmrhf tmpb, vc, vd; \ + vmrlf tmpc, va, vb; \ + vmrlf vd, vc, vd; \ + vpdi v0, tmp0, tmp1, 0; \ + vpdi v1, tmp0, tmp1, 5; \ + vpdi v2, tmp2, v3, 0; \ + vpdi v3, tmp2, v3, 5; \ + vpdi va, tmpa, tmpb, 0; \ + vpdi vb, tmpa, tmpb, 5; \ + vpdi vc, tmpc, vd, 0; \ + vpdi vd, tmpc, vd, 5; + +.balign 8 +.globl _gcry_chacha20_s390x_vx_blocks8 +ELF(.type _gcry_chacha20_s390x_vx_blocks8,@function;) + +_gcry_chacha20_s390x_vx_blocks8: + /* input: + * %r2: input + * %r3: dst + * %r4: src + * %r5: nblks (multiple of 8) + */ + CFI_STARTPROC(); + + START_STACK(%r8); + lgr NBLKS, %r5; + + larl %r7, .Lconsts; + + /* Load counter. */ + lg %r8, (12 * 4)(INPUT); + rllg %r8, %r8, 32; + +.balign 4 + /* Process eight chacha20 blocks per loop. */ +.Lloop8: + vlm Y0, Y3, 0(INPUT); + + slgfi NBLKS, 8; + lghi ROUND, (20 / 2); + + /* Construct counter vectors X12/X13 & Y12/Y13. */ + vl X4, (.Ladd_counter_0123 - .Lconsts)(%r7); + vl Y4, (.Ladd_counter_4567 - .Lconsts)(%r7); + vrepf Y12, Y3, 0; + vrepf Y13, Y3, 1; + vaccf X5, Y12, X4; + vaccf Y5, Y12, Y4; + vaf X12, Y12, X4; + vaf Y12, Y12, Y4; + vaf X13, Y13, X5; + vaf Y13, Y13, Y5; + + vrepf X0, Y0, 0; + vrepf X1, Y0, 1; + vrepf X2, Y0, 2; + vrepf X3, Y0, 3; + vrepf X4, Y1, 0; + vrepf X5, Y1, 1; + vrepf X6, Y1, 2; + vrepf X7, Y1, 3; + vrepf X8, Y2, 0; + vrepf X9, Y2, 1; + vrepf X10, Y2, 2; + vrepf X11, Y2, 3; + vrepf X14, Y3, 2; + vrepf X15, Y3, 3; + + /* Store counters for blocks 0-7. */ + vstm X12, X13, (STACK_CTR + 0 * 16)(%r15); + vstm Y12, Y13, (STACK_CTR + 2 * 16)(%r15); + + vlr Y0, X0; + vlr Y1, X1; + vlr Y2, X2; + vlr Y3, X3; + vlr Y4, X4; + vlr Y5, X5; + vlr Y6, X6; + vlr Y7, X7; + vlr Y8, X8; + vlr Y9, X9; + vlr Y10, X10; + vlr Y11, X11; + vlr Y14, X14; + vlr Y15, X15; + + /* Update and store counter. */ + agfi %r8, 8; + rllg %r5, %r8, 32; + stg %r5, (12 * 4)(INPUT); + +.balign 4 +.Lround2_8: + QUARTERROUND4_V8(X0, X4, X8, X12, X1, X5, X9, X13, + X2, X6, X10, X14, X3, X7, X11, X15, + Y0, Y4, Y8, Y12, Y1, Y5, Y9, Y13, + Y2, Y6, Y10, Y14, Y3, Y7, Y11, Y15); + QUARTERROUND4_V8(X0, X5, X10, X15, X1, X6, X11, X12, + X2, X7, X8, X13, X3, X4, X9, X14, + Y0, Y5, Y10, Y15, Y1, Y6, Y11, Y12, + Y2, Y7, Y8, Y13, Y3, Y4, Y9, Y14); + brctg ROUND, .Lround2_8; + + /* Store blocks 4-7. */ + vstm Y0, Y15, STACK_Y0_Y15(%r15); + + /* Load counters for blocks 0-3. */ + vlm Y0, Y1, (STACK_CTR + 0 * 16)(%r15); + + lghi ROUND, 1; + j .Lfirst_output_4blks_8; + +.balign 4 +.Lsecond_output_4blks_8: + /* Load blocks 4-7. */ + vlm X0, X15, STACK_Y0_Y15(%r15); + + /* Load counters for blocks 4-7. */ + vlm Y0, Y1, (STACK_CTR + 2 * 16)(%r15); + + lghi ROUND, 0; + +.balign 4 + /* Output four chacha20 blocks per loop. */ +.Lfirst_output_4blks_8: + vlm Y12, Y15, 0(INPUT); + PLUS(X12, Y0); + PLUS(X13, Y1); + vrepf Y0, Y12, 0; + vrepf Y1, Y12, 1; + vrepf Y2, Y12, 2; + vrepf Y3, Y12, 3; + vrepf Y4, Y13, 0; + vrepf Y5, Y13, 1; + vrepf Y6, Y13, 2; + vrepf Y7, Y13, 3; + vrepf Y8, Y14, 0; + vrepf Y9, Y14, 1; + vrepf Y10, Y14, 2; + vrepf Y11, Y14, 3; + vrepf Y14, Y15, 2; + vrepf Y15, Y15, 3; + PLUS(X0, Y0); + PLUS(X1, Y1); + PLUS(X2, Y2); + PLUS(X3, Y3); + PLUS(X4, Y4); + PLUS(X5, Y5); + PLUS(X6, Y6); + PLUS(X7, Y7); + PLUS(X8, Y8); + PLUS(X9, Y9); + PLUS(X10, Y10); + PLUS(X11, Y11); + PLUS(X14, Y14); + PLUS(X15, Y15); + + vl Y15, (.Lbswap32 - .Lconsts)(%r7); + TRANSPOSE_4X4_2(X0, X1, X2, X3, X4, X5, X6, X7, + Y9, Y10, Y11, Y12, Y13, Y14); + TRANSPOSE_4X4_2(X8, X9, X10, X11, X12, X13, X14, X15, + Y9, Y10, Y11, Y12, Y13, Y14); + + vlm Y0, Y14, 0(SRC); + vperm X0, X0, X0, Y15; + vperm X1, X1, X1, Y15; + vperm X2, X2, X2, Y15; + vperm X3, X3, X3, Y15; + vperm X4, X4, X4, Y15; + vperm X5, X5, X5, Y15; + vperm X6, X6, X6, Y15; + vperm X7, X7, X7, Y15; + vperm X8, X8, X8, Y15; + vperm X9, X9, X9, Y15; + vperm X10, X10, X10, Y15; + vperm X11, X11, X11, Y15; + vperm X12, X12, X12, Y15; + vperm X13, X13, X13, Y15; + vperm X14, X14, X14, Y15; + vperm X15, X15, X15, Y15; + vl Y15, (15 * 16)(SRC); + + XOR(Y0, X0); + XOR(Y1, X4); + XOR(Y2, X8); + XOR(Y3, X12); + XOR(Y4, X1); + XOR(Y5, X5); + XOR(Y6, X9); + XOR(Y7, X13); + XOR(Y8, X2); + XOR(Y9, X6); + XOR(Y10, X10); + XOR(Y11, X14); + XOR(Y12, X3); + XOR(Y13, X7); + XOR(Y14, X11); + XOR(Y15, X15); + vstm Y0, Y15, 0(DST); + + aghi SRC, 256; + aghi DST, 256; + + clgije ROUND, 1, .Lsecond_output_4blks_8; + + clgijhe NBLKS, 8, .Lloop8; + + /* Clear the used vector registers. */ + DST_8(CLEAR, 0, _); + DST_8(CLEAR, 1, _); + DST_8(CLEAR, 2, _); + DST_8(CLEAR, 3, _); + + /* Clear sensitive data in stack. */ + vlm Y0, Y15, STACK_Y0_Y15(%r15); + vlm Y0, Y3, STACK_CTR(%r15); + + END_STACK(%r8); + xgr %r2, %r2; + br %r14; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_s390x_vx_blocks8, + .-_gcry_chacha20_s390x_vx_blocks8;) + +/********************************************************************** + 8-way stitched chacha20-poly1305 ("vertical") + **********************************************************************/ + +.balign 8 +.globl _gcry_chacha20_poly1305_s390x_vx_blocks8 +ELF(.type _gcry_chacha20_poly1305_s390x_vx_blocks8,@function;) + +_gcry_chacha20_poly1305_s390x_vx_blocks8: + /* input: + * %r2: input + * %r3: dst + * %r4: src + * %r5: nblks (multiple of 8) + * %r6: poly1305 state + * 160(%r15): poly1305 src + */ + CFI_STARTPROC(); + + START_STACK(%r14); + + /* Store parameters to stack. */ + stmg %r2, %r6, STACK_INPUT(%r15); + + lgr POLY_RSTATE, %r6; + lgr NBLKS, %r5; + + lg POLY_RSRC, 0(%r15); + lg POLY_RSRC, 160(POLY_RSRC); + stg POLY_RSRC, STACK_POSRC(%r15); + + /* Load poly1305 state */ + POLY1305_LOAD_STATE(); + +.balign 4 + /* Process eight chacha20 blocks and 32 poly1305 blocks per loop. */ +.Lloop8_poly: + lg INPUT, STACK_INPUT(%r15); + larl %r8, .Lconsts; + + vlm Y0, Y3, 0(INPUT); + + slgfi NBLKS, 8; + lghi ROUND, (20 / 2); + + /* Construct counter vectors X12/X13 & Y12/Y13. */ + vl X4, (.Ladd_counter_0123 - .Lconsts)(%r8); + vl Y4, (.Ladd_counter_4567 - .Lconsts)(%r8); + lg %r8, (12 * 4)(INPUT); /* Update counter. */ + vrepf Y12, Y3, 0; + vrepf Y13, Y3, 1; + vaccf X5, Y12, X4; + vaccf Y5, Y12, Y4; + vaf X12, Y12, X4; + vaf Y12, Y12, Y4; + vaf X13, Y13, X5; + vaf Y13, Y13, Y5; + rllg %r8, %r8, 32; + + vrepf X0, Y0, 0; + vrepf X1, Y0, 1; + vrepf X2, Y0, 2; + vrepf X3, Y0, 3; + vrepf X4, Y1, 0; + vrepf X5, Y1, 1; + vrepf X6, Y1, 2; + vrepf X7, Y1, 3; + vrepf X8, Y2, 0; + vrepf X9, Y2, 1; + vrepf X10, Y2, 2; + vrepf X11, Y2, 3; + vrepf X14, Y3, 2; + vrepf X15, Y3, 3; + agfi %r8, 8; + + /* Store counters for blocks 0-7. */ + vstm X12, X13, (STACK_CTR + 0 * 16)(%r15); + vstm Y12, Y13, (STACK_CTR + 2 * 16)(%r15); + rllg %r8, %r8, 32; + + vlr Y0, X0; + vlr Y1, X1; + vlr Y2, X2; + vlr Y3, X3; + vlr Y4, X4; + vlr Y5, X5; + vlr Y6, X6; + vlr Y7, X7; + vlr Y8, X8; + vlr Y9, X9; + vlr Y10, X10; + vlr Y11, X11; + vlr Y14, X14; + vlr Y15, X15; + stg %r8, (12 * 4)(INPUT); + +.balign 4 +.Lround2_8_poly: + /* Total 30 poly1305 blocks processed by this loop. */ + QUARTERROUND4_V8_POLY(X0, X4, X8, X12, X1, X5, X9, X13, + X2, X6, X10, X14, X3, X7, X11, X15, + Y0, Y4, Y8, Y12, Y1, Y5, Y9, Y13, + Y2, Y6, Y10, Y14, Y3, Y7, Y11, Y15, + POLY1305_BLOCK_PART1(0 * 16), + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8(), + POLY1305_BLOCK_PART1(1 * 16), + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4()); + QUARTERROUND4_V8_POLY(X0, X5, X10, X15, X1, X6, X11, X12, + X2, X7, X8, X13, X3, X4, X9, X14, + Y0, Y5, Y10, Y15, Y1, Y6, Y11, Y12, + Y2, Y7, Y8, Y13, Y3, Y4, Y9, Y14, + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8(), + POLY1305_BLOCK_PART1(2 * 16); + INC_POLY1305_SRC(3 * 16), + POLY1305_BLOCK_PART2(), + POLY1305_BLOCK_PART3(), + POLY1305_BLOCK_PART4(), + POLY1305_BLOCK_PART5(), + POLY1305_BLOCK_PART6(), + POLY1305_BLOCK_PART7(), + POLY1305_BLOCK_PART8()); + brctg ROUND, .Lround2_8_poly; + + POLY1305_BLOCK_PART1(0 * 16); + + /* Store blocks 4-7. */ + vstm Y0, Y15, STACK_Y0_Y15(%r15); + + /* Load counters for blocks 0-3. */ + vlm Y0, Y1, (STACK_CTR + 0 * 16)(%r15); + + stg POLY_RSRC, STACK_POSRC(%r15); /* %r14 used for INPUT/SRC/DST pointer. */ + + lghi ROUND, 1; + j .Lfirst_output_4blks_8_poly; + +.balign 4 +.Lsecond_output_4blks_8_poly: + + POLY1305_BLOCK_PART1(1 * 16); + + /* Load blocks 4-7. */ + vlm X0, X15, STACK_Y0_Y15(%r15); + + /* Load counters for blocks 4-7. */ + vlm Y0, Y1, (STACK_CTR + 2 * 16)(%r15); + + INC_POLY1305_SRC(2 * 16); + stg POLY_RSRC, STACK_POSRC(%r15); /* %r14 used for INPUT/SRC/DST pointer. */ + + lghi ROUND, 0; + +.balign 4 + /* Output four chacha20 blocks and one poly1305 block per loop. */ +.Lfirst_output_4blks_8_poly: + lg %r14, STACK_INPUT(%r15); + vlm Y12, Y15, 0(%r14); + POLY1305_BLOCK_PART2(); + PLUS(X12, Y0); + PLUS(X13, Y1); + vrepf Y0, Y12, 0; + vrepf Y1, Y12, 1; + vrepf Y2, Y12, 2; + vrepf Y3, Y12, 3; + vrepf Y4, Y13, 0; + vrepf Y5, Y13, 1; + vrepf Y6, Y13, 2; + vrepf Y7, Y13, 3; + vrepf Y8, Y14, 0; + vrepf Y9, Y14, 1; + vrepf Y10, Y14, 2; + vrepf Y11, Y14, 3; + vrepf Y14, Y15, 2; + vrepf Y15, Y15, 3; + POLY1305_BLOCK_PART3(); + PLUS(X0, Y0); + PLUS(X1, Y1); + PLUS(X2, Y2); + PLUS(X3, Y3); + PLUS(X4, Y4); + PLUS(X5, Y5); + PLUS(X6, Y6); + PLUS(X7, Y7); + PLUS(X8, Y8); + PLUS(X9, Y9); + PLUS(X10, Y10); + PLUS(X11, Y11); + PLUS(X14, Y14); + PLUS(X15, Y15); + POLY1305_BLOCK_PART4(); + + larl %r14, .Lconsts; + vl Y15, (.Lbswap32 - .Lconsts)(%r14); + TRANSPOSE_4X4_2(X0, X1, X2, X3, X4, X5, X6, X7, + Y9, Y10, Y11, Y12, Y13, Y14); + lg %r14, STACK_SRC(%r15); + POLY1305_BLOCK_PART5(); + TRANSPOSE_4X4_2(X8, X9, X10, X11, X12, X13, X14, X15, + Y9, Y10, Y11, Y12, Y13, Y14); + + vlm Y0, Y14, 0(%r14); + POLY1305_BLOCK_PART6(); + vperm X0, X0, X0, Y15; + vperm X1, X1, X1, Y15; + vperm X2, X2, X2, Y15; + vperm X3, X3, X3, Y15; + vperm X4, X4, X4, Y15; + vperm X5, X5, X5, Y15; + vperm X6, X6, X6, Y15; + vperm X7, X7, X7, Y15; + vperm X8, X8, X8, Y15; + vperm X9, X9, X9, Y15; + vperm X10, X10, X10, Y15; + vperm X11, X11, X11, Y15; + vperm X12, X12, X12, Y15; + vperm X13, X13, X13, Y15; + vperm X14, X14, X14, Y15; + vperm X15, X15, X15, Y15; + vl Y15, (15 * 16)(%r14); + POLY1305_BLOCK_PART7(); + + aghi %r14, 256; + stg %r14, STACK_SRC(%r15); + lg %r14, STACK_DST(%r15); + + XOR(Y0, X0); + XOR(Y1, X4); + XOR(Y2, X8); + XOR(Y3, X12); + XOR(Y4, X1); + XOR(Y5, X5); + XOR(Y6, X9); + XOR(Y7, X13); + XOR(Y8, X2); + XOR(Y9, X6); + XOR(Y10, X10); + XOR(Y11, X14); + XOR(Y12, X3); + XOR(Y13, X7); + XOR(Y14, X11); + XOR(Y15, X15); + POLY1305_BLOCK_PART8(); + vstm Y0, Y15, 0(%r14); + + aghi %r14, 256; + stg %r14, STACK_DST(%r15); + + lg POLY_RSRC, STACK_POSRC(%r15); + + clgije ROUND, 1, .Lsecond_output_4blks_8_poly; + + clgijhe NBLKS, 8, .Lloop8_poly; + + /* Store poly1305 state */ + lg POLY_RSTATE, STACK_POCTX(%r15); + POLY1305_STORE_STATE(); + + /* Clear the used vector registers */ + DST_8(CLEAR, 0, _); + DST_8(CLEAR, 1, _); + DST_8(CLEAR, 2, _); + DST_8(CLEAR, 3, _); + + /* Clear sensitive data in stack. */ + vlm Y0, Y15, STACK_Y0_Y15(%r15); + vlm Y0, Y3, STACK_CTR(%r15); + + END_STACK(%r14); + xgr %r2, %r2; + br %r14; + CFI_ENDPROC(); +ELF(.size _gcry_chacha20_poly1305_s390x_vx_blocks8, + .-_gcry_chacha20_poly1305_s390x_vx_blocks8;) + +#endif /*HAVE_GCC_INLINE_ASM_S390X_VX*/ +#endif /*__s390x__*/ diff --git a/comm/third_party/libgcrypt/cipher/chacha20.c b/comm/third_party/libgcrypt/cipher/chacha20.c new file mode 100644 index 0000000000..497594a0bb --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/chacha20.c @@ -0,0 +1,1306 @@ +/* chacha20.c - Bernstein's ChaCha20 cipher + * Copyright (C) 2014,2017-2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * For a description of the algorithm, see: + * http://cr.yp.to/chacha.html + */ + +/* + * Based on D. J. Bernstein reference implementation at + * http://cr.yp.to/chacha.html: + * + * chacha-regs.c version 20080118 + * D. J. Bernstein + * Public domain. + */ + +#include +#include +#include +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "cipher-internal.h" +#include "bufhelp.h" + + +#define CHACHA20_MIN_KEY_SIZE 16 /* Bytes. */ +#define CHACHA20_MAX_KEY_SIZE 32 /* Bytes. */ +#define CHACHA20_BLOCK_SIZE 64 /* Bytes. */ +#define CHACHA20_MIN_IV_SIZE 8 /* Bytes. */ +#define CHACHA20_MAX_IV_SIZE 12 /* Bytes. */ +#define CHACHA20_CTR_SIZE 16 /* Bytes. */ + + +/* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */ +#undef USE_SSSE3 +#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_SSSE3) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_SSSE3 1 +#endif + +/* USE_AVX2 indicates whether to compile with Intel AVX2 code. */ +#undef USE_AVX2 +#if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_AVX2) && \ + (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AVX2 1 +#endif + +/* USE_ARMV7_NEON indicates whether to enable ARMv7 NEON assembly code. */ +#undef USE_ARMV7_NEON +#ifdef ENABLE_NEON_SUPPORT +# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \ + && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_NEON) +# define USE_ARMV7_NEON 1 +# endif +#endif + +/* USE_AARCH64_SIMD indicates whether to enable ARMv8 SIMD assembly + * code. */ +#undef USE_AARCH64_SIMD +#ifdef ENABLE_NEON_SUPPORT +# if defined(__AARCH64EL__) \ + && defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_AARCH64_NEON) +# define USE_AARCH64_SIMD 1 +# endif +#endif + +/* USE_PPC_VEC indicates whether to enable PowerPC vector + * accelerated code. */ +#undef USE_PPC_VEC +#ifdef ENABLE_PPC_CRYPTO_SUPPORT +# if defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \ + defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC) +# if __GNUC__ >= 4 +# define USE_PPC_VEC 1 +# endif +# endif +#endif + +/* USE_S390X_VX indicates whether to enable zSeries code. */ +#undef USE_S390X_VX +#if defined (__s390x__) && __GNUC__ >= 4 && __ARCH__ >= 9 +# if defined(HAVE_GCC_INLINE_ASM_S390X_VX) +# define USE_S390X_VX 1 +# endif /* USE_S390X_VX */ +#endif + +/* Assembly implementations use SystemV ABI, ABI conversion and additional + * stack to store XMM6-XMM15 needed on Win64. */ +#undef ASM_FUNC_ABI +#undef ASM_EXTRA_STACK +#if defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS) +# define ASM_FUNC_ABI __attribute__((sysv_abi)) +#else +# define ASM_FUNC_ABI +#endif + + +typedef struct CHACHA20_context_s +{ + u32 input[16]; + unsigned char pad[CHACHA20_BLOCK_SIZE]; + unsigned int unused; /* bytes in the pad. */ + unsigned int use_ssse3:1; + unsigned int use_avx2:1; + unsigned int use_neon:1; + unsigned int use_ppc:1; + unsigned int use_s390x:1; +} CHACHA20_context_t; + + +#ifdef USE_SSSE3 + +unsigned int _gcry_chacha20_amd64_ssse3_blocks4(u32 *state, byte *dst, + const byte *src, + size_t nblks) ASM_FUNC_ABI; + +unsigned int _gcry_chacha20_amd64_ssse3_blocks1(u32 *state, byte *dst, + const byte *src, + size_t nblks) ASM_FUNC_ABI; + +unsigned int _gcry_chacha20_poly1305_amd64_ssse3_blocks4( + u32 *state, byte *dst, const byte *src, size_t nblks, + void *poly1305_state, const byte *poly1305_src) ASM_FUNC_ABI; + +unsigned int _gcry_chacha20_poly1305_amd64_ssse3_blocks1( + u32 *state, byte *dst, const byte *src, size_t nblks, + void *poly1305_state, const byte *poly1305_src) ASM_FUNC_ABI; + +#endif /* USE_SSSE3 */ + +#ifdef USE_AVX2 + +unsigned int _gcry_chacha20_amd64_avx2_blocks8(u32 *state, byte *dst, + const byte *src, + size_t nblks) ASM_FUNC_ABI; + +unsigned int _gcry_chacha20_poly1305_amd64_avx2_blocks8( + u32 *state, byte *dst, const byte *src, size_t nblks, + void *poly1305_state, const byte *poly1305_src) ASM_FUNC_ABI; + +#endif /* USE_AVX2 */ + +#ifdef USE_PPC_VEC + +unsigned int _gcry_chacha20_ppc8_blocks4(u32 *state, byte *dst, + const byte *src, + size_t nblks); + +unsigned int _gcry_chacha20_ppc8_blocks1(u32 *state, byte *dst, + const byte *src, + size_t nblks); + +#undef USE_PPC_VEC_POLY1305 +#if SIZEOF_UNSIGNED_LONG == 8 +#define USE_PPC_VEC_POLY1305 1 +unsigned int _gcry_chacha20_poly1305_ppc8_blocks4( + u32 *state, byte *dst, const byte *src, size_t nblks, + POLY1305_STATE *st, const byte *poly1305_src); +#endif /* SIZEOF_UNSIGNED_LONG == 8 */ + +#endif /* USE_PPC_VEC */ + +#ifdef USE_S390X_VX + +unsigned int _gcry_chacha20_s390x_vx_blocks8(u32 *state, byte *dst, + const byte *src, size_t nblks); + +unsigned int _gcry_chacha20_s390x_vx_blocks4_2_1(u32 *state, byte *dst, + const byte *src, size_t nblks); + +#undef USE_S390X_VX_POLY1305 +#if SIZEOF_UNSIGNED_LONG == 8 +#define USE_S390X_VX_POLY1305 1 +unsigned int _gcry_chacha20_poly1305_s390x_vx_blocks8( + u32 *state, byte *dst, const byte *src, size_t nblks, + POLY1305_STATE *st, const byte *poly1305_src); + +unsigned int _gcry_chacha20_poly1305_s390x_vx_blocks4_2_1( + u32 *state, byte *dst, const byte *src, size_t nblks, + POLY1305_STATE *st, const byte *poly1305_src); +#endif /* SIZEOF_UNSIGNED_LONG == 8 */ + +#endif /* USE_S390X_VX */ + +#ifdef USE_ARMV7_NEON + +unsigned int _gcry_chacha20_armv7_neon_blocks4(u32 *state, byte *dst, + const byte *src, + size_t nblks); + +#endif /* USE_ARMV7_NEON */ + +#ifdef USE_AARCH64_SIMD + +unsigned int _gcry_chacha20_aarch64_blocks4(u32 *state, byte *dst, + const byte *src, size_t nblks); + +unsigned int _gcry_chacha20_poly1305_aarch64_blocks4( + u32 *state, byte *dst, const byte *src, size_t nblks, + void *poly1305_state, const byte *poly1305_src); + +#endif /* USE_AARCH64_SIMD */ + + +static const char *selftest (void); + + +#define ROTATE(v,c) (rol(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) ((u32)((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +#define BUF_XOR_LE32(dst, src, offset, x) \ + buf_put_le32((dst) + (offset), buf_get_le32((src) + (offset)) ^ (x)) + +static unsigned int +do_chacha20_blocks (u32 *input, byte *dst, const byte *src, size_t nblks) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + unsigned int i; + + while (nblks) + { + x0 = input[0]; + x1 = input[1]; + x2 = input[2]; + x3 = input[3]; + x4 = input[4]; + x5 = input[5]; + x6 = input[6]; + x7 = input[7]; + x8 = input[8]; + x9 = input[9]; + x10 = input[10]; + x11 = input[11]; + x12 = input[12]; + x13 = input[13]; + x14 = input[14]; + x15 = input[15]; + + for (i = 20; i > 0; i -= 2) + { + QUARTERROUND(x0, x4, x8, x12) + QUARTERROUND(x1, x5, x9, x13) + QUARTERROUND(x2, x6, x10, x14) + QUARTERROUND(x3, x7, x11, x15) + QUARTERROUND(x0, x5, x10, x15) + QUARTERROUND(x1, x6, x11, x12) + QUARTERROUND(x2, x7, x8, x13) + QUARTERROUND(x3, x4, x9, x14) + } + + x0 = PLUS(x0, input[0]); + x1 = PLUS(x1, input[1]); + x2 = PLUS(x2, input[2]); + x3 = PLUS(x3, input[3]); + x4 = PLUS(x4, input[4]); + x5 = PLUS(x5, input[5]); + x6 = PLUS(x6, input[6]); + x7 = PLUS(x7, input[7]); + x8 = PLUS(x8, input[8]); + x9 = PLUS(x9, input[9]); + x10 = PLUS(x10, input[10]); + x11 = PLUS(x11, input[11]); + x12 = PLUS(x12, input[12]); + x13 = PLUS(x13, input[13]); + x14 = PLUS(x14, input[14]); + x15 = PLUS(x15, input[15]); + + input[12] = PLUSONE(input[12]); + input[13] = PLUS(input[13], !input[12]); + + BUF_XOR_LE32(dst, src, 0, x0); + BUF_XOR_LE32(dst, src, 4, x1); + BUF_XOR_LE32(dst, src, 8, x2); + BUF_XOR_LE32(dst, src, 12, x3); + BUF_XOR_LE32(dst, src, 16, x4); + BUF_XOR_LE32(dst, src, 20, x5); + BUF_XOR_LE32(dst, src, 24, x6); + BUF_XOR_LE32(dst, src, 28, x7); + BUF_XOR_LE32(dst, src, 32, x8); + BUF_XOR_LE32(dst, src, 36, x9); + BUF_XOR_LE32(dst, src, 40, x10); + BUF_XOR_LE32(dst, src, 44, x11); + BUF_XOR_LE32(dst, src, 48, x12); + BUF_XOR_LE32(dst, src, 52, x13); + BUF_XOR_LE32(dst, src, 56, x14); + BUF_XOR_LE32(dst, src, 60, x15); + + src += CHACHA20_BLOCK_SIZE; + dst += CHACHA20_BLOCK_SIZE; + nblks--; + } + + /* burn_stack */ + return (17 * sizeof(u32) + 6 * sizeof(void *)); +} + + +static unsigned int +chacha20_blocks (CHACHA20_context_t *ctx, byte *dst, const byte *src, + size_t nblks) +{ +#ifdef USE_SSSE3 + if (ctx->use_ssse3) + { + return _gcry_chacha20_amd64_ssse3_blocks1(ctx->input, dst, src, nblks); + } +#endif + +#ifdef USE_PPC_VEC + if (ctx->use_ppc) + { + return _gcry_chacha20_ppc8_blocks1(ctx->input, dst, src, nblks); + } +#endif + +#ifdef USE_S390X_VX + if (ctx->use_s390x) + { + return _gcry_chacha20_s390x_vx_blocks4_2_1(ctx->input, dst, src, nblks); + } +#endif + + return do_chacha20_blocks (ctx->input, dst, src, nblks); +} + + +static void +chacha20_keysetup (CHACHA20_context_t *ctx, const byte *key, + unsigned int keylen) +{ + static const char sigma[16] = "expand 32-byte k"; + static const char tau[16] = "expand 16-byte k"; + const char *constants; + + ctx->input[4] = buf_get_le32(key + 0); + ctx->input[5] = buf_get_le32(key + 4); + ctx->input[6] = buf_get_le32(key + 8); + ctx->input[7] = buf_get_le32(key + 12); + if (keylen == CHACHA20_MAX_KEY_SIZE) /* 256 bits */ + { + key += 16; + constants = sigma; + } + else /* 128 bits */ + { + constants = tau; + } + ctx->input[8] = buf_get_le32(key + 0); + ctx->input[9] = buf_get_le32(key + 4); + ctx->input[10] = buf_get_le32(key + 8); + ctx->input[11] = buf_get_le32(key + 12); + ctx->input[0] = buf_get_le32(constants + 0); + ctx->input[1] = buf_get_le32(constants + 4); + ctx->input[2] = buf_get_le32(constants + 8); + ctx->input[3] = buf_get_le32(constants + 12); +} + + +static void +chacha20_ivsetup (CHACHA20_context_t * ctx, const byte *iv, size_t ivlen) +{ + if (ivlen == CHACHA20_CTR_SIZE) + { + ctx->input[12] = buf_get_le32 (iv + 0); + ctx->input[13] = buf_get_le32 (iv + 4); + ctx->input[14] = buf_get_le32 (iv + 8); + ctx->input[15] = buf_get_le32 (iv + 12); + } + else if (ivlen == CHACHA20_MAX_IV_SIZE) + { + ctx->input[12] = 0; + ctx->input[13] = buf_get_le32 (iv + 0); + ctx->input[14] = buf_get_le32 (iv + 4); + ctx->input[15] = buf_get_le32 (iv + 8); + } + else if (ivlen == CHACHA20_MIN_IV_SIZE) + { + ctx->input[12] = 0; + ctx->input[13] = 0; + ctx->input[14] = buf_get_le32 (iv + 0); + ctx->input[15] = buf_get_le32 (iv + 4); + } + else + { + ctx->input[12] = 0; + ctx->input[13] = 0; + ctx->input[14] = 0; + ctx->input[15] = 0; + } +} + + +static void +chacha20_setiv (void *context, const byte *iv, size_t ivlen) +{ + CHACHA20_context_t *ctx = (CHACHA20_context_t *) context; + + /* draft-nir-cfrg-chacha20-poly1305-02 defines 96-bit and 64-bit nonce. */ + if (iv && ivlen != CHACHA20_MAX_IV_SIZE && ivlen != CHACHA20_MIN_IV_SIZE + && ivlen != CHACHA20_CTR_SIZE) + log_info ("WARNING: chacha20_setiv: bad ivlen=%u\n", (u32) ivlen); + + if (iv && (ivlen == CHACHA20_MAX_IV_SIZE || ivlen == CHACHA20_MIN_IV_SIZE + || ivlen == CHACHA20_CTR_SIZE)) + chacha20_ivsetup (ctx, iv, ivlen); + else + chacha20_ivsetup (ctx, NULL, 0); + + /* Reset the unused pad bytes counter. */ + ctx->unused = 0; +} + + +static gcry_err_code_t +chacha20_do_setkey (CHACHA20_context_t *ctx, + const byte *key, unsigned int keylen) +{ + static int initialized; + static const char *selftest_failed; + unsigned int features = _gcry_get_hw_features (); + + if (!initialized) + { + initialized = 1; + selftest_failed = selftest (); + if (selftest_failed) + log_error ("CHACHA20 selftest failed (%s)\n", selftest_failed); + } + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + if (keylen != CHACHA20_MAX_KEY_SIZE && keylen != CHACHA20_MIN_KEY_SIZE) + return GPG_ERR_INV_KEYLEN; + +#ifdef USE_SSSE3 + ctx->use_ssse3 = (features & HWF_INTEL_SSSE3) != 0; +#endif +#ifdef USE_AVX2 + ctx->use_avx2 = (features & HWF_INTEL_AVX2) != 0; +#endif +#ifdef USE_ARMV7_NEON + ctx->use_neon = (features & HWF_ARM_NEON) != 0; +#endif +#ifdef USE_AARCH64_SIMD + ctx->use_neon = (features & HWF_ARM_NEON) != 0; +#endif +#ifdef USE_PPC_VEC + ctx->use_ppc = (features & HWF_PPC_ARCH_2_07) != 0; +#endif +#ifdef USE_S390X_VX + ctx->use_s390x = (features & HWF_S390X_VX) != 0; +#endif + + (void)features; + + chacha20_keysetup (ctx, key, keylen); + + /* We default to a zero nonce. */ + chacha20_setiv (ctx, NULL, 0); + + return 0; +} + + +static gcry_err_code_t +chacha20_setkey (void *context, const byte *key, unsigned int keylen, + cipher_bulk_ops_t *bulk_ops) +{ + CHACHA20_context_t *ctx = (CHACHA20_context_t *) context; + gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen); + (void)bulk_ops; + _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *)); + return rc; +} + + +static unsigned int +do_chacha20_encrypt_stream_tail (CHACHA20_context_t *ctx, byte *outbuf, + const byte *inbuf, size_t length) +{ + static const unsigned char zero_pad[CHACHA20_BLOCK_SIZE] = { 0, }; + unsigned int nburn, burn = 0; + +#ifdef USE_AVX2 + if (ctx->use_avx2 && length >= CHACHA20_BLOCK_SIZE * 8) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; + nburn = _gcry_chacha20_amd64_avx2_blocks8(ctx->input, outbuf, inbuf, + nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_SSSE3 + if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE * 4) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + nburn = _gcry_chacha20_amd64_ssse3_blocks4(ctx->input, outbuf, inbuf, + nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_ARMV7_NEON + if (ctx->use_neon && length >= CHACHA20_BLOCK_SIZE * 4) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + nburn = _gcry_chacha20_armv7_neon_blocks4(ctx->input, outbuf, inbuf, + nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_AARCH64_SIMD + if (ctx->use_neon && length >= CHACHA20_BLOCK_SIZE * 4) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + nburn = _gcry_chacha20_aarch64_blocks4(ctx->input, outbuf, inbuf, + nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_PPC_VEC + if (ctx->use_ppc && length >= CHACHA20_BLOCK_SIZE * 4) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + nburn = _gcry_chacha20_ppc8_blocks4(ctx->input, outbuf, inbuf, nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_S390X_VX + if (ctx->use_s390x && length >= CHACHA20_BLOCK_SIZE * 8) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; + nburn = _gcry_chacha20_s390x_vx_blocks8(ctx->input, outbuf, inbuf, + nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + + if (length >= CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nburn = chacha20_blocks(ctx, outbuf, inbuf, nblocks); + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } + + if (length > 0) + { + nburn = chacha20_blocks(ctx, ctx->pad, zero_pad, 1); + burn = nburn > burn ? nburn : burn; + + buf_xor (outbuf, inbuf, ctx->pad, length); + ctx->unused = CHACHA20_BLOCK_SIZE - length; + } + + if (burn) + burn += 5 * sizeof(void *); + + return burn; +} + + +static void +chacha20_encrypt_stream (void *context, byte *outbuf, const byte *inbuf, + size_t length) +{ + CHACHA20_context_t *ctx = (CHACHA20_context_t *) context; + unsigned int nburn, burn = 0; + + if (!length) + return; + + if (ctx->unused) + { + unsigned char *p = ctx->pad; + size_t n; + + gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE); + + n = ctx->unused; + if (n > length) + n = length; + + buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n); + length -= n; + outbuf += n; + inbuf += n; + ctx->unused -= n; + + if (!length) + return; + gcry_assert (!ctx->unused); + } + + nburn = do_chacha20_encrypt_stream_tail (ctx, outbuf, inbuf, length); + burn = nburn > burn ? nburn : burn; + + if (burn) + _gcry_burn_stack (burn); +} + + +gcry_err_code_t +_gcry_chacha20_poly1305_encrypt(gcry_cipher_hd_t c, byte *outbuf, + const byte *inbuf, size_t length) +{ + CHACHA20_context_t *ctx = (void *) &c->context.c; + unsigned int nburn, burn = 0; + byte *authptr = NULL; + + if (!length) + return 0; + + if (ctx->unused) + { + unsigned char *p = ctx->pad; + size_t n; + + gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE); + + n = ctx->unused; + if (n > length) + n = length; + + buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n); + nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, outbuf, n); + burn = nburn > burn ? nburn : burn; + length -= n; + outbuf += n; + inbuf += n; + ctx->unused -= n; + + if (!length) + { + if (burn) + _gcry_burn_stack (burn); + + return 0; + } + gcry_assert (!ctx->unused); + } + + gcry_assert (c->u_mode.poly1305.ctx.leftover == 0); + + if (0) + { } +#ifdef USE_AVX2 + else if (ctx->use_avx2 && length >= CHACHA20_BLOCK_SIZE * 8) + { + nburn = _gcry_chacha20_amd64_avx2_blocks8(ctx->input, outbuf, inbuf, 8); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 8 * CHACHA20_BLOCK_SIZE; + outbuf += 8 * CHACHA20_BLOCK_SIZE; + inbuf += 8 * CHACHA20_BLOCK_SIZE; + } +#endif +#ifdef USE_SSSE3 + else if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE * 4) + { + nburn = _gcry_chacha20_amd64_ssse3_blocks4(ctx->input, outbuf, inbuf, 4); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 4 * CHACHA20_BLOCK_SIZE; + outbuf += 4 * CHACHA20_BLOCK_SIZE; + inbuf += 4 * CHACHA20_BLOCK_SIZE; + } + else if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE * 2) + { + nburn = _gcry_chacha20_amd64_ssse3_blocks1(ctx->input, outbuf, inbuf, 2); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 2 * CHACHA20_BLOCK_SIZE; + outbuf += 2 * CHACHA20_BLOCK_SIZE; + inbuf += 2 * CHACHA20_BLOCK_SIZE; + } + else if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE) + { + nburn = _gcry_chacha20_amd64_ssse3_blocks1(ctx->input, outbuf, inbuf, 1); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 1 * CHACHA20_BLOCK_SIZE; + outbuf += 1 * CHACHA20_BLOCK_SIZE; + inbuf += 1 * CHACHA20_BLOCK_SIZE; + } +#endif +#ifdef USE_AARCH64_SIMD + else if (ctx->use_neon && length >= CHACHA20_BLOCK_SIZE * 4) + { + nburn = _gcry_chacha20_aarch64_blocks4(ctx->input, outbuf, inbuf, 4); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 4 * CHACHA20_BLOCK_SIZE; + outbuf += 4 * CHACHA20_BLOCK_SIZE; + inbuf += 4 * CHACHA20_BLOCK_SIZE; + } +#endif +#ifdef USE_PPC_VEC_POLY1305 + else if (ctx->use_ppc && length >= CHACHA20_BLOCK_SIZE * 4) + { + nburn = _gcry_chacha20_ppc8_blocks4(ctx->input, outbuf, inbuf, 4); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 4 * CHACHA20_BLOCK_SIZE; + outbuf += 4 * CHACHA20_BLOCK_SIZE; + inbuf += 4 * CHACHA20_BLOCK_SIZE; + } +#endif +#ifdef USE_S390X_VX_POLY1305 + else if (ctx->use_s390x && length >= 2 * CHACHA20_BLOCK_SIZE * 8) + { + nburn = _gcry_chacha20_s390x_vx_blocks8(ctx->input, outbuf, inbuf, 8); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 8 * CHACHA20_BLOCK_SIZE; + outbuf += 8 * CHACHA20_BLOCK_SIZE; + inbuf += 8 * CHACHA20_BLOCK_SIZE; + } + else if (ctx->use_s390x && length >= CHACHA20_BLOCK_SIZE * 4) + { + nburn = _gcry_chacha20_s390x_vx_blocks4_2_1(ctx->input, outbuf, inbuf, 4); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 4 * CHACHA20_BLOCK_SIZE; + outbuf += 4 * CHACHA20_BLOCK_SIZE; + inbuf += 4 * CHACHA20_BLOCK_SIZE; + } + else if (ctx->use_s390x && length >= CHACHA20_BLOCK_SIZE * 2) + { + nburn = _gcry_chacha20_s390x_vx_blocks4_2_1(ctx->input, outbuf, inbuf, 2); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 2 * CHACHA20_BLOCK_SIZE; + outbuf += 2 * CHACHA20_BLOCK_SIZE; + inbuf += 2 * CHACHA20_BLOCK_SIZE; + } + else if (ctx->use_s390x && length >= CHACHA20_BLOCK_SIZE) + { + nburn = _gcry_chacha20_s390x_vx_blocks4_2_1(ctx->input, outbuf, inbuf, 1); + burn = nburn > burn ? nburn : burn; + + authptr = outbuf; + length -= 1 * CHACHA20_BLOCK_SIZE; + outbuf += 1 * CHACHA20_BLOCK_SIZE; + inbuf += 1 * CHACHA20_BLOCK_SIZE; + } +#endif + + if (authptr) + { + size_t authoffset = outbuf - authptr; + +#ifdef USE_AVX2 + if (ctx->use_avx2 && + length >= 8 * CHACHA20_BLOCK_SIZE && + authoffset >= 8 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; + + nburn = _gcry_chacha20_poly1305_amd64_avx2_blocks8( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_SSSE3 + if (ctx->use_ssse3) + { + if (length >= 4 * CHACHA20_BLOCK_SIZE && + authoffset >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + + nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks4( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } + + if (length >= CHACHA20_BLOCK_SIZE && + authoffset >= CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + + nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks1( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } + } +#endif + +#ifdef USE_AARCH64_SIMD + if (ctx->use_neon && + length >= 4 * CHACHA20_BLOCK_SIZE && + authoffset >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + + nburn = _gcry_chacha20_poly1305_aarch64_blocks4( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_PPC_VEC_POLY1305 + if (ctx->use_ppc && + length >= 4 * CHACHA20_BLOCK_SIZE && + authoffset >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + + nburn = _gcry_chacha20_poly1305_ppc8_blocks4( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_S390X_VX_POLY1305 + if (ctx->use_s390x) + { + if (length >= 8 * CHACHA20_BLOCK_SIZE && + authoffset >= 8 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; + + burn = _gcry_chacha20_poly1305_s390x_vx_blocks8( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } + + if (length >= CHACHA20_BLOCK_SIZE && + authoffset >= CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + + burn = _gcry_chacha20_poly1305_s390x_vx_blocks4_2_1( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, authptr); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + authptr += nblocks * CHACHA20_BLOCK_SIZE; + } + } +#endif + + if (authoffset > 0) + { + _gcry_poly1305_update (&c->u_mode.poly1305.ctx, authptr, authoffset); + authptr += authoffset; + authoffset = 0; + } + + gcry_assert(authptr == outbuf); + } + + while (length) + { + size_t currlen = length; + + /* Since checksumming is done after encryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for checksumming. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + nburn = do_chacha20_encrypt_stream_tail (ctx, outbuf, inbuf, currlen); + burn = nburn > burn ? nburn : burn; + + nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, outbuf, + currlen); + burn = nburn > burn ? nburn : burn; + + outbuf += currlen; + inbuf += currlen; + length -= currlen; + } + + if (burn) + _gcry_burn_stack (burn); + + return 0; +} + + +gcry_err_code_t +_gcry_chacha20_poly1305_decrypt(gcry_cipher_hd_t c, byte *outbuf, + const byte *inbuf, size_t length) +{ + CHACHA20_context_t *ctx = (void *) &c->context.c; + unsigned int nburn, burn = 0; + + if (!length) + return 0; + + if (ctx->unused) + { + unsigned char *p = ctx->pad; + size_t n; + + gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE); + + n = ctx->unused; + if (n > length) + n = length; + + nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, inbuf, n); + burn = nburn > burn ? nburn : burn; + buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n); + length -= n; + outbuf += n; + inbuf += n; + ctx->unused -= n; + + if (!length) + { + if (burn) + _gcry_burn_stack (burn); + + return 0; + } + gcry_assert (!ctx->unused); + } + + gcry_assert (c->u_mode.poly1305.ctx.leftover == 0); + +#ifdef USE_AVX2 + if (ctx->use_avx2 && length >= 8 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; + + nburn = _gcry_chacha20_poly1305_amd64_avx2_blocks8( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_SSSE3 + if (ctx->use_ssse3) + { + if (length >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + + nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks4( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } + + if (length >= CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + + nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks1( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } + } +#endif + +#ifdef USE_AARCH64_SIMD + if (ctx->use_neon && length >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + + nburn = _gcry_chacha20_poly1305_aarch64_blocks4( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_PPC_VEC_POLY1305 + if (ctx->use_ppc && length >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; + + nburn = _gcry_chacha20_poly1305_ppc8_blocks4( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } +#endif + +#ifdef USE_S390X_VX_POLY1305 + if (ctx->use_s390x) + { + if (length >= 8 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; + + nburn = _gcry_chacha20_poly1305_s390x_vx_blocks8( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } + + if (length >= CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + + nburn = _gcry_chacha20_poly1305_s390x_vx_blocks4_2_1( + ctx->input, outbuf, inbuf, nblocks, + &c->u_mode.poly1305.ctx.state, inbuf); + burn = nburn > burn ? nburn : burn; + + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; + inbuf += nblocks * CHACHA20_BLOCK_SIZE; + } + } +#endif + + while (length) + { + size_t currlen = length; + + /* Since checksumming is done before decryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for decryption. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, inbuf, + currlen); + burn = nburn > burn ? nburn : burn; + + nburn = do_chacha20_encrypt_stream_tail (ctx, outbuf, inbuf, currlen); + burn = nburn > burn ? nburn : burn; + + outbuf += currlen; + inbuf += currlen; + length -= currlen; + } + + if (burn) + _gcry_burn_stack (burn); + + return 0; +} + + +static const char * +selftest (void) +{ + byte ctxbuf[sizeof(CHACHA20_context_t) + 15]; + CHACHA20_context_t *ctx; + byte scratch[127 + 1]; + byte buf[512 + 64 + 4]; + int i; + + /* From draft-strombergson-chacha-test-vectors */ + static byte key_1[] = { + 0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78, + 0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35, + 0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb, + 0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d + }; + static const byte nonce_1[] = + { 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21 }; + static const byte plaintext_1[127] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + static const byte ciphertext_1[127] = { + 0xf6, 0x3a, 0x89, 0xb7, 0x5c, 0x22, 0x71, 0xf9, + 0x36, 0x88, 0x16, 0x54, 0x2b, 0xa5, 0x2f, 0x06, + 0xed, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2b, 0x00, + 0xb5, 0xe8, 0xf8, 0x0a, 0xe9, 0xa4, 0x73, 0xaf, + 0xc2, 0x5b, 0x21, 0x8f, 0x51, 0x9a, 0xf0, 0xfd, + 0xd4, 0x06, 0x36, 0x2e, 0x8d, 0x69, 0xde, 0x7f, + 0x54, 0xc6, 0x04, 0xa6, 0xe0, 0x0f, 0x35, 0x3f, + 0x11, 0x0f, 0x77, 0x1b, 0xdc, 0xa8, 0xab, 0x92, + 0xe5, 0xfb, 0xc3, 0x4e, 0x60, 0xa1, 0xd9, 0xa9, + 0xdb, 0x17, 0x34, 0x5b, 0x0a, 0x40, 0x27, 0x36, + 0x85, 0x3b, 0xf9, 0x10, 0xb0, 0x60, 0xbd, 0xf1, + 0xf8, 0x97, 0xb6, 0x29, 0x0f, 0x01, 0xd1, 0x38, + 0xae, 0x2c, 0x4c, 0x90, 0x22, 0x5b, 0xa9, 0xea, + 0x14, 0xd5, 0x18, 0xf5, 0x59, 0x29, 0xde, 0xa0, + 0x98, 0xca, 0x7a, 0x6c, 0xcf, 0xe6, 0x12, 0x27, + 0x05, 0x3c, 0x84, 0xe4, 0x9a, 0x4a, 0x33 + }; + + /* 16-byte alignment required for amd64 implementation. */ + ctx = (CHACHA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15); + + chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + scratch[sizeof (scratch) - 1] = 0; + chacha20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1); + if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1)) + return "ChaCha20 encryption test 1 failed."; + if (scratch[sizeof (scratch) - 1]) + return "ChaCha20 wrote too much."; + chacha20_setkey (ctx, key_1, sizeof (key_1), NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + chacha20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1); + if (memcmp (scratch, plaintext_1, sizeof plaintext_1)) + return "ChaCha20 decryption test 1 failed."; + + for (i = 0; i < sizeof buf; i++) + buf[i] = i; + chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + /*encrypt */ + chacha20_encrypt_stream (ctx, buf, buf, sizeof buf); + /*decrypt */ + chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + chacha20_encrypt_stream (ctx, buf, buf, 1); + chacha20_encrypt_stream (ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1); + chacha20_encrypt_stream (ctx, buf + (sizeof buf) - 1, + buf + (sizeof buf) - 1, 1); + for (i = 0; i < sizeof buf; i++) + if (buf[i] != (byte) i) + return "ChaCha20 encryption test 2 failed."; + + chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + /* encrypt */ + for (i = 0; i < sizeof buf; i++) + chacha20_encrypt_stream (ctx, &buf[i], &buf[i], 1); + /* decrypt */ + chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + chacha20_encrypt_stream (ctx, buf, buf, sizeof buf); + for (i = 0; i < sizeof buf; i++) + if (buf[i] != (byte) i) + return "ChaCha20 encryption test 3 failed."; + + return NULL; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_chacha20 = { + GCRY_CIPHER_CHACHA20, + {0, 0}, /* flags */ + "CHACHA20", /* name */ + NULL, /* aliases */ + NULL, /* oids */ + 1, /* blocksize in bytes. */ + CHACHA20_MAX_KEY_SIZE * 8, /* standard key length in bits. */ + sizeof (CHACHA20_context_t), + chacha20_setkey, + NULL, + NULL, + chacha20_encrypt_stream, + chacha20_encrypt_stream, + NULL, + NULL, + chacha20_setiv +}; diff --git a/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c b/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c new file mode 100644 index 0000000000..c182657e1f --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-aeswrap.c @@ -0,0 +1,209 @@ +/* cipher-aeswrap.c - Generic AESWRAP mode implementation + * Copyright (C) 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +/* Perform the AES-Wrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +gcry_err_code_t +_gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen ) +{ + int j, x; + size_t n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + unsigned int burn, nburn; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->spec->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data plus one + additional block. */ + if (outbuflen < inbuflen + 8) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least two 64 bit blocks. */ + if (n < 2) + return GPG_ERR_INV_ARG; + + burn = 0; + + r = outbuf; + a = outbuf; /* We store A directly in OUTBUF. */ + b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */ + + /* Copy the inbuf to the outbuf. */ + memmove (r+8, inbuf, inbuflen); + + /* If an IV has been set we use that IV as the Alternative Initial + Value; if it has not been set we use the standard value. */ + if (c->marks.iv) + memcpy (a, c->u_iv.iv, 8); + else + memset (a, 0xa6, 8); + + memset (t, 0, sizeof t); /* t := 0. */ + + for (j = 0; j <= 5; j++) + { + for (i = 1; i <= n; i++) + { + /* B := AES_k( A | R[i] ) */ + memcpy (b, a, 8); + memcpy (b+8, r+i*8, 8); + nburn = c->spec->encrypt (&c->context.c, b, b); + burn = nburn > burn ? nburn : burn; + /* t := t + 1 */ + for (x = 7; x >= 0; x--) + { + t[x]++; + if (t[x]) + break; + } + /* A := MSB_64(B) ^ t */ + cipher_block_xor(a, b, t, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+i*8, b+8, 8); + } + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + +/* Perform the AES-Unwrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +gcry_err_code_t +_gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + int j, x; + size_t n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + unsigned int burn, nburn; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->spec->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data minus one + additional block. Fixme: The caller has more restrictive checks + - we may want to fix them for this mode. */ + if (outbuflen + 8 < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least three 64 bit blocks. */ + if (n < 3) + return GPG_ERR_INV_ARG; + + burn = 0; + + r = outbuf; + a = c->lastiv; /* We use c->LASTIV as buffer for A. */ + b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */ + + /* Copy the inbuf to the outbuf and save A. */ + memcpy (a, inbuf, 8); + memmove (r, inbuf+8, inbuflen-8); + n--; /* Reduce to actual number of data blocks. */ + + /* t := 6 * n */ + i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ + for (x=0; x < 8 && x < sizeof (i); x++) + t[7-x] = i >> (8*x); + for (; x < 8; x++) + t[7-x] = 0; + + for (j = 5; j >= 0; j--) + { + for (i = n; i >= 1; i--) + { + /* B := AES_k^1( (A ^ t)| R[i] ) */ + cipher_block_xor(b, a, t, 8); + memcpy (b+8, r+(i-1)*8, 8); + nburn = c->spec->decrypt (&c->context.c, b, b); + burn = nburn > burn ? nburn : burn; + /* t := t - 1 */ + for (x = 7; x >= 0; x--) + { + t[x]--; + if (t[x] != 0xff) + break; + } + /* A := MSB_64(B) */ + memcpy (a, b, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+(i-1)*8, b+8, 8); + } + } + + /* If an IV has been set we compare against this Alternative Initial + Value; if it has not been set we compare against the standard IV. */ + if (c->marks.iv) + j = memcmp (a, c->u_iv.iv, 8); + else + { + for (j=0, x=0; x < 8; x++) + if (a[x] != 0xa6) + { + j=1; + break; + } + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return j? GPG_ERR_CHECKSUM : 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-cbc.c b/comm/third_party/libgcrypt/cipher/cipher-cbc.c new file mode 100644 index 0000000000..d4df1e72aa --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-cbc.c @@ -0,0 +1,292 @@ +/* cipher-cbc.c - Generic CBC mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "./cipher-internal.h" +#include "bufhelp.h" + + + +static inline unsigned int +cbc_encrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf, + const unsigned char *inbuf, size_t nblocks, size_t blocksize, + int is_cbc_cmac) +{ + + unsigned int burn, nburn; + size_t n; + + burn = 0; + + if (c->bulk.cbc_enc) + { + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, + is_cbc_cmac); + } + else + { + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + unsigned char *ivp; + + ivp = c->u_iv.iv; + + for (n=0; n < nblocks; n++ ) + { + cipher_block_xor (outbuf, inbuf, ivp, blocksize); + nburn = enc_fn ( &c->context.c, outbuf, outbuf ); + burn = nburn > burn ? nburn : burn; + ivp = outbuf; + inbuf += blocksize; + if (!is_cbc_cmac) + outbuf += blocksize; + } + + if (ivp != c->u_iv.iv) + cipher_block_cpy (c->u_iv.iv, ivp, blocksize); + } + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t blocksize_mask = blocksize - 1; + size_t nblocks = inbuflen >> blocksize_shift; + int is_cbc_cmac = !!(c->flags & GCRY_CIPHER_CBC_MAC); + unsigned int burn; + + if (outbuflen < (is_cbc_cmac ? blocksize : inbuflen)) + return GPG_ERR_BUFFER_TOO_SHORT; + + if (inbuflen & blocksize_mask) + return GPG_ERR_INV_LENGTH; + + burn = cbc_encrypt_inner(c, outbuf, inbuf, nblocks, blocksize, is_cbc_cmac); + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cbc_cts_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t blocksize_mask = blocksize - 1; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t nblocks = inbuflen >> blocksize_shift; + unsigned int burn, nburn; + unsigned char *ivp; + int i; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen & blocksize_mask) && !(inbuflen > blocksize)) + return GPG_ERR_INV_LENGTH; + + burn = 0; + + if (inbuflen > blocksize) + { + if ((inbuflen & blocksize_mask) == 0) + nblocks--; + } + + burn = cbc_encrypt_inner(c, outbuf, inbuf, nblocks, blocksize, 0); + inbuf += nblocks << blocksize_shift; + outbuf += nblocks << blocksize_shift; + + if (inbuflen > blocksize) + { + /* We have to be careful here, since outbuf might be equal to + inbuf. */ + size_t restbytes; + unsigned char b; + + if ((inbuflen & blocksize_mask) == 0) + restbytes = blocksize; + else + restbytes = inbuflen & blocksize_mask; + + outbuf -= blocksize; + for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++) + { + b = inbuf[i]; + outbuf[blocksize + i] = outbuf[i]; + outbuf[i] = b ^ *ivp++; + } + for (; i < blocksize; i++) + outbuf[i] = 0 ^ *ivp++; + + nburn = enc_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; + cipher_block_cpy (c->u_iv.iv, outbuf, blocksize); + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +static inline unsigned int +cbc_decrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf, + const unsigned char *inbuf, size_t nblocks, size_t blocksize) +{ + unsigned int burn, nburn; + size_t n; + + burn = 0; + + if (c->bulk.cbc_dec) + { + c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + } + else + { + gcry_cipher_decrypt_t dec_fn = c->spec->decrypt; + + for (n = 0; n < nblocks; n++) + { + /* Because outbuf and inbuf might be the same, we must not overwrite + the original ciphertext block. We use LASTIV as intermediate + storage here because it is not used otherwise. */ + nburn = dec_fn ( &c->context.c, c->lastiv, inbuf ); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_n_copy_2 (outbuf, c->lastiv, c->u_iv.iv, inbuf, + blocksize); + inbuf += blocksize; + outbuf += blocksize; + } + } + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t blocksize_mask = blocksize - 1; + size_t nblocks = inbuflen >> blocksize_shift; + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if (inbuflen & blocksize_mask) + return GPG_ERR_INV_LENGTH; + + burn = cbc_decrypt_inner(c, outbuf, inbuf, nblocks, blocksize); + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cbc_cts_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t blocksize_mask = blocksize - 1; + gcry_cipher_decrypt_t dec_fn = c->spec->decrypt; + size_t nblocks = inbuflen >> blocksize_shift; + unsigned int burn, nburn; + int i; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen & blocksize_mask) && !(inbuflen > blocksize)) + return GPG_ERR_INV_LENGTH; + + burn = 0; + + if (inbuflen > blocksize) + { + nblocks--; + if ((inbuflen & blocksize_mask) == 0) + nblocks--; + cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize); + } + + burn = cbc_decrypt_inner(c, outbuf, inbuf, nblocks, blocksize); + inbuf += nblocks << blocksize_shift; + outbuf += nblocks << blocksize_shift; + + if (inbuflen > blocksize) + { + size_t restbytes; + + if ((inbuflen & blocksize_mask) == 0) + restbytes = blocksize; + else + restbytes = inbuflen & blocksize_mask; + + cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ + buf_cpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ + + nburn = dec_fn ( &c->context.c, outbuf, inbuf ); + burn = nburn > burn ? nburn : burn; + buf_xor(outbuf, outbuf, c->u_iv.iv, restbytes); + + buf_cpy (outbuf + blocksize, outbuf, restbytes); + for(i=restbytes; i < blocksize; i++) + c->u_iv.iv[i] = outbuf[i]; + nburn = dec_fn (&c->context.c, outbuf, c->u_iv.iv); + burn = nburn > burn ? nburn : burn; + cipher_block_xor(outbuf, outbuf, c->lastiv, blocksize); + /* c->lastiv is now really lastlastiv, does this matter? */ + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-ccm.c b/comm/third_party/libgcrypt/cipher/cipher-ccm.c new file mode 100644 index 0000000000..dcb268d084 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-ccm.c @@ -0,0 +1,415 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, + int do_padding) +{ + const unsigned int blocksize = 16; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + unsigned char tmp[blocksize]; + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + size_t nblocks; + size_t n; + + if (inlen == 0 && (unused == 0 || !do_padding)) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + n = (inlen > blocksize - unused) ? blocksize - unused : inlen; + + buf_cpy (&c->u_mode.ccm.macbuf[unused], inbuf, n); + unused += n; + inlen -= n; + inbuf += n; + } + if (!inlen) + { + if (!do_padding) + break; + + n = blocksize - unused; + if (n > 0) + { + memset (&c->u_mode.ccm.macbuf[unused], 0, n); + unused = blocksize; + } + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + cipher_block_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, + blocksize); + set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv )); + + unused = 0; + } + + if (c->bulk.cbc_enc) + { + nblocks = inlen / blocksize; + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (tmp, sizeof(tmp)); + } + else + { + while (inlen >= blocksize) + { + cipher_block_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + unsigned int marks_key; + size_t L = 15 - noncelen; + size_t L_; + + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + marks_key = c->marks.key; + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + c->marks.key = marks_key; + + /* Setup CTR */ + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + /* Setup IV */ + c->u_iv.iv[0] = L_; + memcpy (&c->u_iv.iv[1], nonce, noncelen); + /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later + in set_aad. */ + memset (&c->u_iv.iv[1 + noncelen], 0, L); + + c->u_mode.ccm.nonce = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, u64 encryptlen, u64 aadlen, + u64 taglen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + size_t noncelen = 15 - (c->u_iv.iv[0] + 1); + u64 M = taglen; + u64 M_; + int i; + + M_ = (M - 2) / 2; + + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || c->marks.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.lengths) + return GPG_ERR_INV_STATE; + + c->u_mode.ccm.authlen = taglen; + c->u_mode.ccm.encryptlen = encryptlen; + c->u_mode.ccm.aadlen = aadlen; + + /* Complete IV setup. */ + c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8; + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadlen == 0) + { + /* Do nothing. */ + } + else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff) + { + b0[0] = (aadlen >> 8) & 0xff; + b0[1] = aadlen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + } + else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + } + else if (aadlen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + } + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.lengths = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + unsigned int burn; + + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->marks.tag) + return GPG_ERR_INV_STATE; + if (abuflen > c->u_mode.ccm.aadlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.aadlen -= abuflen; + burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, int check) +{ + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->marks.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + cipher_block_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->marks.tag = 1; + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen) +{ + gcry_err_code_t err = 0; + unsigned int burn = 0; + unsigned int nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Since checksumming is done before encryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for encryption. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + c->u_mode.ccm.encryptlen -= currlen; + nburn = do_cbc_mac (c, inbuf, currlen, 0); + burn = nburn > burn ? nburn : burn; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen); + if (err) + break; + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + return err; +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen) +{ + gcry_err_code_t err = 0; + unsigned int burn = 0; + unsigned int nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Since checksumming is done after decryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for checksumming. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen); + if (err) + break; + + c->u_mode.ccm.encryptlen -= currlen; + nburn = do_cbc_mac (c, outbuf, currlen, 0); + burn = nburn > burn ? nburn : burn; + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + return err; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-cfb.c b/comm/third_party/libgcrypt/cipher/cipher-cfb.c new file mode 100644 index 0000000000..012c6c13c3 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-cfb.c @@ -0,0 +1,317 @@ +/* cipher-cfb.c - Generic CFB mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + unsigned char *ivp; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t blocksize_x_2 = blocksize + blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV and store input into IV. */ + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_2dst(outbuf, ivp, inbuf, inbuflen); + c->unused -= inbuflen; + return 0; + } + + burn = 0; + + if ( c->unused ) + { + /* XOR the input with the IV and store input into IV */ + inbuflen -= c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_2dst(outbuf, ivp, inbuf, c->unused); + outbuf += c->unused; + inbuf += c->unused; + c->unused = 0; + } + + /* Now we can process complete blocks. We use a loop as long as we + have at least 2 blocks and use conditions for the rest. This + also allows to use a bulk encryption function if available. */ + if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc) + { + size_t nblocks = inbuflen >> blocksize_shift; + c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks << blocksize_shift; + inbuf += nblocks << blocksize_shift; + inbuflen -= nblocks << blocksize_shift; + } + else + { + while ( inbuflen >= blocksize_x_2 ) + { + /* Encrypt the IV. */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV. */ + cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + } + + if ( inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ + cipher_block_cpy( c->lastiv, c->u_iv.iv, blocksize ); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV */ + cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + if ( inbuflen ) + { + /* Save the current IV and then encrypt the IV. */ + cipher_block_cpy( c->lastiv, c->u_iv.iv, blocksize ); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + c->unused = blocksize; + /* Apply the XOR. */ + c->unused -= inbuflen; + buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen); + outbuf += inbuflen; + inbuf += inbuflen; + inbuflen = 0; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + unsigned char *ivp; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t blocksize_x_2 = blocksize + blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if (inbuflen <= c->unused) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV and store input into IV. */ + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_n_copy(outbuf, ivp, inbuf, inbuflen); + c->unused -= inbuflen; + return 0; + } + + burn = 0; + + if (c->unused) + { + /* XOR the input with the IV and store input into IV. */ + inbuflen -= c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_n_copy(outbuf, ivp, inbuf, c->unused); + outbuf += c->unused; + inbuf += c->unused; + c->unused = 0; + } + + /* Now we can process complete blocks. We use a loop as long as we + have at least 2 blocks and use conditions for the rest. This + also allows to use a bulk encryption function if available. */ + if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec) + { + size_t nblocks = inbuflen >> blocksize_shift; + c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks << blocksize_shift; + inbuf += nblocks << blocksize_shift; + inbuflen -= nblocks << blocksize_shift; + } + else + { + while (inbuflen >= blocksize_x_2 ) + { + /* Encrypt the IV. */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV. */ + cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + } + + if (inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ + cipher_block_cpy ( c->lastiv, c->u_iv.iv, blocksize); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV */ + cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + + if (inbuflen) + { + /* Save the current IV and then encrypt the IV. */ + cipher_block_cpy ( c->lastiv, c->u_iv.iv, blocksize ); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + c->unused = blocksize; + /* Apply the XOR. */ + c->unused -= inbuflen; + buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, inbuflen); + outbuf += inbuflen; + inbuf += inbuflen; + inbuflen = 0; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cfb8_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize = c->spec->blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + burn = 0; + + while ( inbuflen > 0) + { + int i; + + /* Encrypt the IV. */ + nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + + outbuf[0] = c->lastiv[0] ^ inbuf[0]; + + /* Bitshift iv by 8 bit to the left */ + for (i = 0; i < blocksize-1; i++) + c->u_iv.iv[i] = c->u_iv.iv[i+1]; + + /* append cipher text to iv */ + c->u_iv.iv[blocksize-1] = outbuf[0]; + + outbuf += 1; + inbuf += 1; + inbuflen -= 1; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cfb8_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize = c->spec->blocksize; + unsigned int burn, nburn; + unsigned char appendee; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + burn = 0; + + while (inbuflen > 0) + { + int i; + + /* Encrypt the IV. */ + nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + + /* inbuf might == outbuf, make sure we keep the value + so we can append it later */ + appendee = inbuf[0]; + + outbuf[0] = inbuf[0] ^ c->lastiv[0]; + + /* Bitshift iv by 8 bit to the left */ + for (i = 0; i < blocksize-1; i++) + c->u_iv.iv[i] = c->u_iv.iv[i+1]; + + c->u_iv.iv[blocksize-1] = appendee; + + outbuf += 1; + inbuf += 1; + inbuflen -= 1; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-cmac.c b/comm/third_party/libgcrypt/cipher/cipher-cmac.c new file mode 100644 index 0000000000..4efd1e19b4 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-cmac.c @@ -0,0 +1,292 @@ +/* cmac.c - CMAC, Cipher-based MAC. + * Copyright (C) 2013,2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "cipher-internal.h" +#include "bufhelp.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +gcry_err_code_t +_gcry_cmac_write (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, + const byte * inbuf, size_t inlen) +{ + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + byte outbuf[MAX_BLOCKSIZE]; + unsigned int burn = 0; + unsigned int nblocks; + size_t n; + + if (ctx->tag) + return GPG_ERR_INV_STATE; + + if (!inbuf) + return GPG_ERR_INV_ARG; + + if (inlen == 0) + return 0; + + /* Last block is needed for cmac_final. */ + if (ctx->mac_unused + inlen <= blocksize) + { + buf_cpy (&ctx->macbuf[ctx->mac_unused], inbuf, inlen); + ctx->mac_unused += inlen; + inbuf += inlen; + inlen -= inlen; + + return 0; + } + + if (ctx->mac_unused) + { + n = inlen; + if (n > blocksize - ctx->mac_unused) + n = blocksize - ctx->mac_unused; + + buf_cpy (&ctx->macbuf[ctx->mac_unused], inbuf, n); + ctx->mac_unused += n; + inbuf += n; + inlen -= n; + + cipher_block_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); + set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv)); + + ctx->mac_unused = 0; + } + + if (c->bulk.cbc_enc && inlen > blocksize) + { + nblocks = inlen >> blocksize_shift; + nblocks -= ((nblocks << blocksize_shift) == inlen); + + c->bulk.cbc_enc (&c->context.c, ctx->u_iv.iv, outbuf, inbuf, nblocks, 1); + inbuf += nblocks << blocksize_shift; + inlen -= nblocks << blocksize_shift; + + wipememory (outbuf, sizeof (outbuf)); + } + else + while (inlen > blocksize) + { + cipher_block_xor (ctx->u_iv.iv, ctx->u_iv.iv, inbuf, blocksize); + set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv)); + inlen -= blocksize; + inbuf += blocksize; + } + + /* Make sure that last block is passed to cmac_final. */ + if (inlen == 0) + BUG (); + + n = inlen; + if (n > blocksize - ctx->mac_unused) + n = blocksize - ctx->mac_unused; + + buf_cpy (&ctx->macbuf[ctx->mac_unused], inbuf, n); + ctx->mac_unused += n; + inbuf += n; + inlen -= n; + + if (burn) + _gcry_burn_stack (burn + 4 * sizeof (void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cmac_generate_subkeys (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx) +{ + const unsigned int blocksize = c->spec->blocksize; + byte rb, carry, t, bi; + unsigned int burn; + int i, j; + union + { + size_t _aligned; + byte buf[MAX_BLOCKSIZE]; + } u; + + /* Tell compiler that we require a cipher with a 64bit or 128 bit block + * length, to allow better optimization of this function. */ + if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1)) + return GPG_ERR_INV_CIPHER_MODE; + + if (MAX_BLOCKSIZE < blocksize) + BUG (); + + /* encrypt zero block */ + memset (u.buf, 0, blocksize); + burn = c->spec->encrypt (&c->context.c, u.buf, u.buf); + + /* Currently supported blocksizes are 16 and 8. */ + rb = blocksize == 16 ? 0x87 : 0x1B /* blocksize == 8 */ ; + + for (j = 0; j < 2; j++) + { + /* Generate subkeys K1 and K2 */ + carry = 0; + for (i = blocksize - 1; i >= 0; i--) + { + bi = u.buf[i]; + t = carry | (bi << 1); + carry = bi >> 7; + u.buf[i] = t & 0xff; + ctx->subkeys[j][i] = u.buf[i]; + } + u.buf[blocksize - 1] ^= carry ? rb : 0; + ctx->subkeys[j][blocksize - 1] = u.buf[blocksize - 1]; + } + + wipememory (&u, sizeof (u)); + if (burn) + _gcry_burn_stack (burn + 4 * sizeof (void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cmac_final (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx) +{ + const unsigned int blocksize = c->spec->blocksize; + unsigned int count = ctx->mac_unused; + unsigned int burn; + byte *subkey; + + /* Tell compiler that we require a cipher with a 64bit or 128 bit block + * length, to allow better optimization of this function. */ + if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1)) + return GPG_ERR_INV_CIPHER_MODE; + + if (count == blocksize) + subkey = ctx->subkeys[0]; /* K1 */ + else + { + subkey = ctx->subkeys[1]; /* K2 */ + ctx->macbuf[count++] = 0x80; + while (count < blocksize) + ctx->macbuf[count++] = 0; + } + + cipher_block_xor (ctx->macbuf, ctx->macbuf, subkey, blocksize); + + cipher_block_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); + burn = c->spec->encrypt (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv); + if (burn) + _gcry_burn_stack (burn + 4 * sizeof (void *)); + + ctx->mac_unused = 0; + + return 0; +} + + +static gcry_err_code_t +cmac_tag (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, + unsigned char *tag, size_t taglen, int check) +{ + gcry_err_code_t ret; + + if (!tag || taglen == 0 || taglen > c->spec->blocksize) + return GPG_ERR_INV_ARG; + + if (!ctx->tag) + { + ret = _gcry_cmac_final (c, ctx); + if (ret != 0) + return ret; + + ctx->tag = 1; + } + + if (!check) + { + memcpy (tag, ctx->u_iv.iv, taglen); + return GPG_ERR_NO_ERROR; + } + else + { + return buf_eq_const (tag, ctx->u_iv.iv, taglen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +void +_gcry_cmac_reset (gcry_cmac_context_t *ctx) +{ + char tmp_buf[sizeof(ctx->subkeys)]; + + /* Only keep subkeys when reseting context. */ + + buf_cpy (tmp_buf, ctx->subkeys, sizeof(ctx->subkeys)); + memset (ctx, 0, sizeof(*ctx)); + buf_cpy (ctx->subkeys, tmp_buf, sizeof(ctx->subkeys)); + wipememory (tmp_buf, sizeof(tmp_buf)); +} + + +gcry_err_code_t +_gcry_cipher_cmac_authenticate (gcry_cipher_hd_t c, + const unsigned char *abuf, size_t abuflen) +{ + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + /* To support new blocksize, update cmac_generate_subkeys() then add new + blocksize here. */ + if (c->spec->blocksize != 16 && c->spec->blocksize != 8) + return GPG_ERR_INV_CIPHER_MODE; + + return _gcry_cmac_write (c, &c->u_mode.cmac, abuf, abuflen); +} + + +gcry_err_code_t +_gcry_cipher_cmac_get_tag (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen) +{ + return cmac_tag (c, &c->u_mode.cmac, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_cmac_check_tag (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen) +{ + return cmac_tag (c, &c->u_mode.cmac, (unsigned char *) intag, taglen, 1); +} + +gcry_err_code_t +_gcry_cipher_cmac_set_subkeys (gcry_cipher_hd_t c) +{ + return _gcry_cmac_generate_subkeys (c, &c->u_mode.cmac); +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-ctr.c b/comm/third_party/libgcrypt/cipher/cipher-ctr.c new file mode 100644 index 0000000000..5f0afc2f88 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-ctr.c @@ -0,0 +1,120 @@ +/* cipher-ctr.c - Generic CTR mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t n; + int i; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + size_t nblocks; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + burn = 0; + + /* First process a left over encrypted counter. */ + if (c->unused) + { + gcry_assert (c->unused < blocksize); + i = blocksize - c->unused; + n = c->unused > inbuflen ? inbuflen : c->unused; + buf_xor(outbuf, inbuf, &c->lastiv[i], n); + c->unused -= n; + inbuf += n; + outbuf += n; + inbuflen -= n; + } + + /* Use a bulk method if available. */ + nblocks = inbuflen >> blocksize_shift; + if (nblocks && c->bulk.ctr_enc) + { + c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks); + inbuf += nblocks << blocksize_shift; + outbuf += nblocks << blocksize_shift; + inbuflen -= nblocks << blocksize_shift; + } + + /* If we don't have a bulk method use the standard method. We also + use this method for the a remaining partial block. */ + if (inbuflen) + { + unsigned char tmp[MAX_BLOCKSIZE]; + + n = blocksize; + do + { + nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr); + burn = nburn > burn ? nburn : burn; + + cipher_block_add(c->u_ctr.ctr, 1, blocksize); + + if (inbuflen < blocksize) + break; + cipher_block_xor(outbuf, inbuf, tmp, blocksize); + + inbuflen -= n; + outbuf += n; + inbuf += n; + } + while (inbuflen); + + if (inbuflen) + { + n = inbuflen; + buf_xor(outbuf, inbuf, tmp, inbuflen); + + inbuflen -= n; + outbuf += n; + inbuf += n; + } + + /* Save the unused bytes of the counter. */ + c->unused = blocksize - n; + if (c->unused) + buf_cpy (c->lastiv+n, tmp+n, c->unused); + + wipememory (tmp, sizeof tmp); + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-eax.c b/comm/third_party/libgcrypt/cipher/cipher-eax.c new file mode 100644 index 0000000000..08f815a9e4 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-eax.c @@ -0,0 +1,289 @@ +/* cipher-eax.c - EAX implementation + * Copyright (C) 2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_eax_encrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t err; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->marks.tag) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + { + err = _gcry_cipher_eax_set_nonce (c, NULL, 0); + if (err != 0) + return err; + } + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Since checksumming is done after encryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for checksumming. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen); + if (err != 0) + return err; + + err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, outbuf, + currlen); + if (err != 0) + return err; + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_eax_decrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t err; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->marks.tag) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + { + err = _gcry_cipher_eax_set_nonce (c, NULL, 0); + if (err != 0) + return err; + } + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Since checksumming is done before decryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for decryption. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, inbuf, + currlen); + if (err != 0) + return err; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen); + if (err != 0) + return err; + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_eax_authenticate (gcry_cipher_hd_t c, + const byte * aadbuf, size_t aadbuflen) +{ + gcry_err_code_t err; + + if (c->marks.tag) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + { + err = _gcry_cipher_eax_set_nonce (c, NULL, 0); + if (err != 0) + return err; + } + + return _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, aadbuf, aadbuflen); +} + + +gcry_err_code_t +_gcry_cipher_eax_setkey (gcry_cipher_hd_t c) +{ + gcry_err_code_t err; + + err = _gcry_cmac_generate_subkeys (c, &c->u_mode.eax.cmac_header); + if (err != 0) + return err; + + buf_cpy (c->u_mode.eax.cmac_ciphertext.subkeys, + c->u_mode.eax.cmac_header.subkeys, + sizeof(c->u_mode.eax.cmac_header.subkeys)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_eax_set_nonce (gcry_cipher_hd_t c, const byte *nonce, + size_t noncelen) +{ + gcry_cmac_context_t nonce_cmac; + unsigned char initbuf[MAX_BLOCKSIZE]; + gcry_err_code_t err; + + c->marks.iv = 0; + c->marks.tag = 0; + + _gcry_cmac_reset (&c->u_mode.eax.cmac_header); + _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext); + + /* Calculate nonce CMAC */ + + memset(&nonce_cmac, 0, sizeof(nonce_cmac)); + memset(&initbuf, 0, sizeof(initbuf)); + + buf_cpy (&nonce_cmac.subkeys, c->u_mode.eax.cmac_header.subkeys, + sizeof(c->u_mode.eax.cmac_header.subkeys)); + + err = _gcry_cmac_write (c, &nonce_cmac, initbuf, c->spec->blocksize); + if (err != 0) + return err; + + if (noncelen != 0) + { + err = _gcry_cmac_write (c, &nonce_cmac, nonce, noncelen); + if (err != 0) + return err; + } + + err = _gcry_cmac_final (c, &nonce_cmac); + if (err != 0) + return err; + + cipher_block_cpy (c->u_iv.iv, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE); + cipher_block_cpy (c->u_ctr.ctr, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE); + + wipememory (&nonce_cmac, sizeof(nonce_cmac)); + + /* Prepare header CMAC */ + + initbuf[c->spec->blocksize - 1] = 1; + err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_header, initbuf, + c->spec->blocksize); + if (err != 0) + return err; + + /* Prepare ciphertext CMAC */ + + initbuf[c->spec->blocksize - 1] = 2; + err = _gcry_cmac_write (c, &c->u_mode.eax.cmac_ciphertext, initbuf, + c->spec->blocksize); + if (err != 0) + return err; + + c->marks.iv = 1; + c->marks.tag = 0; + + return 0; +} + + +static gcry_err_code_t +_gcry_cipher_eax_tag (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, int check) +{ + gcry_err_code_t err; + + if (!c->marks.tag) + { + err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_header); + if (err != 0) + return err; + + err = _gcry_cmac_final (c, &c->u_mode.eax.cmac_ciphertext); + if (err != 0) + return err; + + cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_header.u_iv.iv, + MAX_BLOCKSIZE); + cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_ciphertext.u_iv.iv, + MAX_BLOCKSIZE); + + _gcry_cmac_reset (&c->u_mode.eax.cmac_header); + _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext); + + c->marks.tag = 1; + } + + if (!check) + { + if (outbuflen > c->spec->blocksize) + outbuflen = c->spec->blocksize; + + /* NB: We already checked that OUTBUF is large enough to hold + * the result or has valid truncated length. */ + memcpy (outbuf, c->u_iv.iv, outbuflen); + } + else + { + /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF + * and thus we need to compare its length first. */ + if (!(outbuflen <= c->spec->blocksize) + || !buf_eq_const (outbuf, c->u_iv.iv, outbuflen)) + return GPG_ERR_CHECKSUM; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_eax_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_eax_tag (c, outtag, taglen, 0); +} + +gcry_err_code_t +_gcry_cipher_eax_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_eax_tag (c, (unsigned char *) intag, taglen, 1); +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-gcm-armv7-neon.S b/comm/third_party/libgcrypt/cipher/cipher-gcm-armv7-neon.S new file mode 100644 index 0000000000..a801a5e57b --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-gcm-armv7-neon.S @@ -0,0 +1,341 @@ +/* cipher-gcm-armv7-neon.S - ARM/NEON accelerated GHASH + * Copyright (C) 2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \ + defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_NEON) + +.syntax unified +.fpu neon +.arm + +.text + +#ifdef __PIC__ +# define GET_DATA_POINTER(reg, name, rtmp) \ + ldr reg, 1f; \ + ldr rtmp, 2f; \ + b 3f; \ + 1: .word _GLOBAL_OFFSET_TABLE_-(3f+8); \ + 2: .word name(GOT); \ + 3: add reg, pc, reg; \ + ldr reg, [reg, rtmp]; +#else +# define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name +#endif + + +/* Constants */ + +.align 4 +gcry_gcm_reduction_constant: +.Lrconst64: + .quad 0xc200000000000000 + +/* Register macros */ + +#define rhash q0 +#define rhash_l d0 +#define rhash_h d1 + +#define rh1 q1 +#define rh1_l d2 +#define rh1_h d3 + +#define rbuf q2 +#define rbuf_l d4 +#define rbuf_h d5 + +#define rbuf1 q3 +#define rbuf1_l d6 +#define rbuf1_h d7 + +#define t0q q4 +#define t0l d8 +#define t0h d9 + +#define t1q q5 +#define t1l d10 +#define t1h d11 + +#define t2q q6 +#define t2l d12 +#define t2h d13 + +#define t3q q7 +#define t3l d14 +#define t3h d15 + +/* q8 */ +#define k16 d16 +#define k32 d17 + +/* q9 */ +#define k48 d18 + +#define k0 q10 + +#define rr0 q11 +#define rr0_l d22 +#define rr0_h d23 + +#define rr1 q12 +#define rr1_l d24 +#define rr1_h d25 + +#define rt0 q13 +#define rt0_l d26 +#define rt0_h d27 + +#define rt1 q14 +#define rt1_l d28 +#define rt1_h d29 + +#define rrconst q15 +#define rrconst_l d30 +#define rrconst_h d31 + +/* Macro for 64x64=>128 carry-less multiplication using vmull.p8 instruction. + * + * From "Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R. Fast Software + * Polynomial Multiplication on ARM Processors using the NEON Engine. The + * Second International Workshop on Modern Cryptography and Security + * Engineering — MoCrySEn, 2013". */ + +#define vmull_p64(rq, rl, rh, ad, bd) \ + vext.8 t0l, ad, ad, $1; \ + vmull.p8 t0q, t0l, bd; \ + vext.8 rl, bd, bd, $1; \ + vmull.p8 rq, ad, rl; \ + vext.8 t1l, ad, ad, $2; \ + vmull.p8 t1q, t1l, bd; \ + vext.8 t3l, bd, bd, $2; \ + vmull.p8 t3q, ad, t3l; \ + vext.8 t2l, ad, ad, $3; \ + vmull.p8 t2q, t2l, bd; \ + veor t0q, t0q, rq; \ + vext.8 rl, bd, bd, $3; \ + vmull.p8 rq, ad, rl; \ + veor t1q, t1q, t3q; \ + vext.8 t3l, bd, bd, $4; \ + vmull.p8 t3q, ad, t3l; \ + veor t0l, t0l, t0h; \ + vand t0h, t0h, k48; \ + veor t1l, t1l, t1h; \ + vand t1h, t1h, k32; \ + veor t2q, t2q, rq; \ + veor t0l, t0l, t0h; \ + veor t1l, t1l, t1h; \ + veor t2l, t2l, t2h; \ + vand t2h, t2h, k16; \ + veor t3l, t3l, t3h; \ + vmov.i64 t3h, $0; \ + vext.8 t0q, t0q, t0q, $15; \ + veor t2l, t2l, t2h; \ + vext.8 t1q, t1q, t1q, $14; \ + vmull.p8 rq, ad, bd; \ + vext.8 t2q, t2q, t2q, $13; \ + vext.8 t3q, t3q, t3q, $12; \ + veor t0q, t0q, t1q; \ + veor t2q, t2q, t3q; \ + veor rq, rq, t0q; \ + veor rq, rq, t2q; + +/* GHASH macros. + * + * See "Gouvêa, C. P. L. & López, J. Implementing GCM on ARMv8. Topics in + * Cryptology — CT-RSA 2015" for details. + */ + +/* Input: 'a' and 'b', Output: 'r0:r1' (low 128-bits in r0, high in r1) + * Note: 'r1' may be 'a' or 'b', 'r0' must not be either 'a' or 'b'. + */ +#define PMUL_128x128(r0, r1, a, b, t1, t2, interleave_op) \ + veor t1##_h, b##_l, b##_h; \ + veor t1##_l, a##_l, a##_h; \ + vmull_p64( r0, r0##_l, r0##_h, a##_l, b##_l ); \ + vmull_p64( r1, r1##_l, r1##_h, a##_h, b##_h ); \ + vmull_p64( t2, t2##_h, t2##_l, t1##_h, t1##_l ); \ + interleave_op; \ + veor t2, r0; \ + veor t2, r1; \ + veor r0##_h, t2##_l; \ + veor r1##_l, t2##_h; + +/* Reduction using Xor and Shift. + * Input: 'r0:r1', Output: 'a' + * + * See "Shay Gueron, Michael E. Kounavis. Intel Carry-Less Multiplication + * Instruction and its Usage for Computing the GCM Mode" for details. + */ +#define REDUCTION(a, r0, r1, t, interleave_op) \ + vshl.u32 t0q, r0, #31; \ + vshl.u32 t1q, r0, #30; \ + vshl.u32 t2q, r0, #25; \ + veor t0q, t0q, t1q; \ + veor t0q, t0q, t2q; \ + vext.8 t, t0q, k0, #4; \ + vext.8 t0q, k0, t0q, #(16-12); \ + veor r0, r0, t0q; \ + interleave_op; \ + vshr.u32 t0q, r0, #1; \ + vshr.u32 t1q, r0, #2; \ + vshr.u32 t2q, r0, #7; \ + veor t0q, t0q, t1q; \ + veor t0q, t0q, t2q; \ + veor t0q, t0q, t; \ + veor r0, r0, t0q; \ + veor a, r0, r1; + +#define _(...) __VA_ARGS__ +#define __ _() + +/* Other functional macros */ + +#define CLEAR_REG(reg) veor reg, reg; + + +/* + * unsigned int _gcry_ghash_armv7_neon (void *gcm_key, byte *result, + * const byte *buf, size_t nblocks); + */ +.align 3 +.globl _gcry_ghash_armv7_neon +.type _gcry_ghash_armv7_neon,%function; +_gcry_ghash_armv7_neon: + /* input: + * r0: gcm_key + * r1: result/hash + * r2: buf + * r3: nblocks + */ + push {r4-r6, lr} + + cmp r3, #0 + beq .Ldo_nothing + + vpush {q4-q7} + + vld1.64 {rhash}, [r1] + vld1.64 {rh1}, [r0] + + vrev64.8 rhash, rhash /* byte-swap */ + + vmov.i64 k0, #0x0 + vmov.i64 k16, #0xffff + vmov.i64 k32, #0xffffffff + vmov.i64 k48, #0xffffffffffff + + vext.8 rhash, rhash, rhash, #8 + + /* Handle remaining blocks. */ + + vld1.64 {rbuf}, [r2]! + subs r3, r3, #1 + + vrev64.8 rbuf, rbuf /* byte-swap */ + vext.8 rbuf, rbuf, rbuf, #8 + + veor rhash, rhash, rbuf + + beq .Lend + +.Loop: + vld1.64 {rbuf}, [r2]! + PMUL_128x128(rr0, rr1, rhash, rh1, rt0, rt1, _(vrev64.8 rbuf, rbuf)) + REDUCTION(rhash, rr0, rr1, rt0, _(vext.8 rbuf, rbuf, rbuf, #8)) + subs r3, r3, #1 + veor rhash, rhash, rbuf + + bne .Loop + +.Lend: + PMUL_128x128(rr0, rr1, rhash, rh1, rt0, rt1, _(CLEAR_REG(rbuf))) + REDUCTION(rhash, rr0, rr1, rt0, _(CLEAR_REG(rh1))) + +.Ldone: + CLEAR_REG(rr1) + vrev64.8 rhash, rhash /* byte-swap */ + CLEAR_REG(rt0) + CLEAR_REG(rr0) + vext.8 rhash, rhash, rhash, #8 + CLEAR_REG(rt1) + CLEAR_REG(t0q) + CLEAR_REG(t1q) + CLEAR_REG(t2q) + CLEAR_REG(t3q) + vst1.64 {rhash}, [r1] + CLEAR_REG(rhash) + + vpop {q4-q7} + +.Ldo_nothing: + mov r0, #0 + pop {r4-r6, pc} +.size _gcry_ghash_armv7_neon,.-_gcry_ghash_armv7_neon; + + +/* + * void _gcry_ghash_armv7_neon (void *gcm_key); + */ +.align 3 +.globl _gcry_ghash_setup_armv7_neon +.type _gcry_ghash_setup_armv7_neon,%function; +_gcry_ghash_setup_armv7_neon: + /* input: + * r0: gcm_key + */ + + vpush {q4-q7} + + GET_DATA_POINTER(r2, .Lrconst64, r3) + + vld1.64 {rrconst_h}, [r2] + +#define GCM_LSH_1(r_out, ia, ib, const_d, oa, ob, ma) \ + /* H <<< 1 */ \ + vshr.s64 ma, ib, #63; \ + vshr.u64 oa, ib, #63; \ + vshr.u64 ob, ia, #63; \ + vand ma, const_d; \ + vshl.u64 ib, ib, #1; \ + vshl.u64 ia, ia, #1; \ + vorr ob, ib; \ + vorr oa, ia; \ + veor ob, ma; \ + vst1.64 {oa, ob}, [r_out] + + vld1.64 {rhash}, [r0] + vrev64.8 rhash, rhash /* byte-swap */ + vext.8 rhash, rhash, rhash, #8 + + vmov rbuf1, rhash + GCM_LSH_1(r0, rhash_l, rhash_h, rrconst_h, rh1_l, rh1_h, rt1_l) /* H<<<1 */ + + CLEAR_REG(rh1) + CLEAR_REG(rhash) + CLEAR_REG(rbuf1) + CLEAR_REG(rrconst) + vpop {q4-q7} + bx lr +.size _gcry_ghash_setup_armv7_neon,.-_gcry_ghash_setup_armv7_neon; + +#endif diff --git a/comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch32-ce.S b/comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch32-ce.S new file mode 100644 index 0000000000..1de66a1626 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch32-ce.S @@ -0,0 +1,433 @@ +/* cipher-gcm-armv8-aarch32-ce.S - ARM/CE accelerated GHASH + * Copyright (C) 2016 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \ + defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH32_CRYPTO) + +.syntax unified +.arch armv8-a +.fpu crypto-neon-fp-armv8 +.arm + +.text + +#ifdef __PIC__ +# define GET_DATA_POINTER(reg, name, rtmp) \ + ldr reg, 1f; \ + ldr rtmp, 2f; \ + b 3f; \ + 1: .word _GLOBAL_OFFSET_TABLE_-(3f+8); \ + 2: .word name(GOT); \ + 3: add reg, pc, reg; \ + ldr reg, [reg, rtmp]; +#else +# define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name +#endif + + +/* Constants */ + +.align 4 +gcry_gcm_reduction_constant: +.Lrconst64: + .quad 0xc200000000000000 + + +/* Register macros */ + +#define rhash q0 +#define rhash_l d0 +#define rhash_h d1 + +#define rh1 q1 +#define rh1_l d2 +#define rh1_h d3 + +#define rbuf q2 +#define rbuf_l d4 +#define rbuf_h d5 + +#define rbuf1 q3 +#define rbuf1_l d6 +#define rbuf1_h d7 + +#define rbuf2 q4 +#define rbuf2_l d8 +#define rbuf2_h d9 + +#define rbuf3 q5 +#define rbuf3_l d10 +#define rbuf3_h d11 + +#define rh2 q6 +#define rh2_l d12 +#define rh2_h d13 + +#define rh3 q7 +#define rh3_l d14 +#define rh3_h d15 + +#define rh4 q8 +#define rh4_l d16 +#define rh4_h d17 + +#define rr2 q9 +#define rr2_l d18 +#define rr2_h d19 + +#define rr3 q10 +#define rr3_l d20 +#define rr3_h d21 + +#define rr0 q11 +#define rr0_l d22 +#define rr0_h d23 + +#define rr1 q12 +#define rr1_l d24 +#define rr1_h d25 + +#define rt0 q13 +#define rt0_l d26 +#define rt0_h d27 + +#define rt1 q14 +#define rt1_l d28 +#define rt1_h d29 + +#define rrconst q15 +#define rrconst_l d30 +#define rrconst_h d31 + +/* GHASH macros */ + +/* See "Gouvêa, C. P. L. & López, J. Implementing GCM on ARMv8. Topics in + * Cryptology — CT-RSA 2015" for details. + */ + +/* Input: 'a' and 'b', Output: 'r0:r1' (low 128-bits in r0, high in r1) + * Note: 'r1' may be 'a' or 'b', 'r0' must not be either 'a' or 'b'. + */ +#define PMUL_128x128(r0, r1, a, b, t, interleave_op) \ + veor t##_h, b##_l, b##_h; \ + veor t##_l, a##_l, a##_h; \ + vmull.p64 r0, a##_l, b##_l; \ + vmull.p64 r1, a##_h, b##_h; \ + vmull.p64 t, t##_h, t##_l; \ + interleave_op; \ + veor t, r0; \ + veor t, r1; \ + veor r0##_h, t##_l; \ + veor r1##_l, t##_h; + +/* Input: 'aA' and 'bA', Output: 'r0A:r1A' (low 128-bits in r0A, high in r1A) + * Note: 'r1A' may be 'aA' or 'bA', 'r0A' must not be either 'aA' or 'bA'. + * Input: 'aB' and 'bB', Output: 'r0B:r1B' (low 128-bits in r0B, high in r1B) + * Note: 'r1B' may be 'aB' or 'bB', 'r0B' must not be either 'aB' or 'bB'. + */ +#define PMUL_128x128_2(r0A, r1A, aA, bA, r0B, r1B, aB, bB, tA, tB, interleave_op) \ + veor tA##_h, bA##_l, bA##_h; \ + veor tA##_l, aA##_l, aA##_h; \ + veor tB##_h, bB##_l, bB##_h; \ + veor tB##_l, aB##_l, aB##_h; \ + vmull.p64 r0A, aA##_l, bA##_l; \ + vmull.p64 r1A, aA##_h, bA##_h; \ + vmull.p64 tA, tA##_h, tA##_l; \ + vmull.p64 r0B, aB##_l, bB##_l; \ + vmull.p64 r1B, aB##_h, bB##_h; \ + vmull.p64 tB, tB##_h, tB##_l; \ + interleave_op; \ + veor tA, r0A; \ + veor tA, r1A; \ + veor tB, r0B; \ + veor tB, r1B; \ + veor r0A##_h, tA##_l; \ + veor r1A##_l, tA##_h; \ + veor r0B##_h, tB##_l; \ + veor r1B##_l, tB##_h; \ + +/* Input: 'r0:r1', Output: 'a' */ +#define REDUCTION(a, r0, r1, rconst, t, interleave_op) \ + vmull.p64 t, r0##_l, rconst; \ + veor r0##_h, t##_l; \ + veor r1##_l, t##_h; \ + interleave_op; \ + vmull.p64 t, r0##_h, rconst; \ + veor r1, t; \ + veor a, r0, r1; + +#define _(...) __VA_ARGS__ +#define __ _() + +/* Other functional macros */ + +#define CLEAR_REG(reg) veor reg, reg; + + +/* + * unsigned int _gcry_ghash_armv8_ce_pmull (void *gcm_key, byte *result, + * const byte *buf, size_t nblocks, + * void *gcm_table); + */ +.align 3 +.globl _gcry_ghash_armv8_ce_pmull +.type _gcry_ghash_armv8_ce_pmull,%function; +_gcry_ghash_armv8_ce_pmull: + /* input: + * r0: gcm_key + * r1: result/hash + * r2: buf + * r3: nblocks + * %st+0: gcm_table + */ + push {r4-r6, lr} + + cmp r3, #0 + beq .Ldo_nothing + + GET_DATA_POINTER(r4, .Lrconst64, lr) + + vld1.64 {rhash}, [r1] + vld1.64 {rh1}, [r0] + + vrev64.8 rhash, rhash /* byte-swap */ + vld1.64 {rrconst_h}, [r4] + vext.8 rhash, rhash, rhash, #8 + + cmp r3, #4 + blo .Less_than_4 + + /* Bulk processing of 4 blocks per loop iteration. */ + + ldr r5, [sp, #(4*4)]; + add r6, r5, #32 + + vpush {q4-q7} + + vld1.64 {rh2-rh3}, [r5] + vld1.64 {rh4}, [r6] + + vld1.64 {rbuf-rbuf1}, [r2]! + sub r3, r3, #4 + vld1.64 {rbuf2-rbuf3}, [r2]! + + cmp r3, #4 + vrev64.8 rbuf, rbuf /* byte-swap */ + vrev64.8 rbuf1, rbuf1 /* byte-swap */ + vrev64.8 rbuf2, rbuf2 /* byte-swap */ + vrev64.8 rbuf3, rbuf3 /* byte-swap */ + + vext.8 rbuf, rbuf, rbuf, #8 + vext.8 rbuf1, rbuf1, rbuf1, #8 + vext.8 rbuf2, rbuf2, rbuf2, #8 + vext.8 rbuf3, rbuf3, rbuf3, #8 + veor rhash, rhash, rbuf /* in0 ^ hash */ + + blo .Lend_4 + +.Loop_4: + /* (in0 ^ hash) * Hâ´ => rr2:rr3 */ + /* (in1) * H³ => rr0:rr1 */ + PMUL_128x128_2(rr0, rr1, rbuf1, rh3, rr2, rr3, rhash, rh4, rt1, rt0, __) + + vld1.64 {rbuf-rbuf1}, [r2]! + sub r3, r3, #4 + veor rr0, rr0, rr2 + veor rr1, rr1, rr3 + + /* (in2) * H² => rr2:rr3 */ + /* (in3) * H¹ => rhash:rbuf3 */ + PMUL_128x128_2(rr2, rr3, rbuf2, rh2, rhash, rbuf3, rbuf3, rh1, rt0, rt1, + _(vrev64.8 rbuf, rbuf)) + + vld1.64 {rbuf2}, [r2]! + + vrev64.8 rbuf1, rbuf1 + veor rr0, rr0, rr2 + veor rr1, rr1, rr3 + + cmp r3, #4 + vext.8 rbuf, rbuf, rbuf, #8 + vext.8 rbuf1, rbuf1, rbuf1, #8 + + veor rr0, rr0, rhash + veor rr1, rr1, rbuf3 + + vld1.64 {rbuf3}, [r2]! + + REDUCTION(rhash, rr0, rr1, rrconst_h, rt1, + _(vrev64.8 rbuf2, rbuf2; + vrev64.8 rbuf3, rbuf3)) + + vext.8 rbuf2, rbuf2, rbuf2, #8 + vext.8 rbuf3, rbuf3, rbuf3, #8 + veor rhash, rhash, rbuf /* in0 ^ hash */ + + bhs .Loop_4 + +.Lend_4: + /* (in0 ^ hash) * Hâ´ => rr2:rr3 */ + /* (in1) * H³ => rr0:rr1 */ + PMUL_128x128_2(rr0, rr1, rbuf1, rh3, rr2, rr3, rhash, rh4, rt1, rt0, __) + + /* (in2) * H² => rhash:rbuf */ + /* (in3) * H¹ => rbuf1:rbuf2 */ + PMUL_128x128_2(rhash, rbuf, rbuf2, rh2, rbuf1, rbuf2, rbuf3, rh1, rt0, rt1, + _(veor rr0, rr0, rr2; + veor rr1, rr1, rr3)) + + veor rr0, rr0, rhash + veor rr1, rr1, rbuf + + veor rr0, rr0, rbuf1 + veor rr1, rr1, rbuf2 + + REDUCTION(rhash, rr0, rr1, rrconst_h, rt1, + _(CLEAR_REG(rr2); + CLEAR_REG(rr3); + CLEAR_REG(rbuf1); + CLEAR_REG(rbuf2); + CLEAR_REG(rbuf3); + CLEAR_REG(rh2); + CLEAR_REG(rh3); + CLEAR_REG(rh4))) + + vpop {q4-q7} + + cmp r3, #0 + beq .Ldone + +.Less_than_4: + /* Handle remaining blocks. */ + + vld1.64 {rbuf}, [r2]! + subs r3, r3, #1 + + vrev64.8 rbuf, rbuf /* byte-swap */ + vext.8 rbuf, rbuf, rbuf, #8 + + veor rhash, rhash, rbuf + + beq .Lend + +.Loop: + vld1.64 {rbuf}, [r2]! + subs r3, r3, #1 + PMUL_128x128(rr0, rr1, rhash, rh1, rt0, _(vrev64.8 rbuf, rbuf)) + REDUCTION(rhash, rr0, rr1, rrconst_h, rt0, _(vext.8 rbuf, rbuf, rbuf, #8)) + veor rhash, rhash, rbuf + + bne .Loop + +.Lend: + PMUL_128x128(rr0, rr1, rhash, rh1, rt0, _(CLEAR_REG(rbuf))) + REDUCTION(rhash, rr0, rr1, rrconst_h, rt0, _(CLEAR_REG(rh1))) + +.Ldone: + CLEAR_REG(rr1) + vrev64.8 rhash, rhash /* byte-swap */ + CLEAR_REG(rt0) + CLEAR_REG(rr0) + vext.8 rhash, rhash, rhash, #8 + CLEAR_REG(rt1) + vst1.64 {rhash}, [r1] + CLEAR_REG(rhash) + +.Ldo_nothing: + mov r0, #0 + pop {r4-r6, pc} +.size _gcry_ghash_armv8_ce_pmull,.-_gcry_ghash_armv8_ce_pmull; + + +/* + * void _gcry_ghash_setup_armv8_ce_pmull (void *gcm_key, void *gcm_table); + */ +.align 3 +.globl _gcry_ghash_setup_armv8_ce_pmull +.type _gcry_ghash_setup_armv8_ce_pmull,%function; +_gcry_ghash_setup_armv8_ce_pmull: + /* input: + * r0: gcm_key + * r1: gcm_table + */ + + vpush {q4-q7} + + GET_DATA_POINTER(r2, .Lrconst64, r3) + + vld1.64 {rrconst_h}, [r2] + +#define GCM_LSH_1(r_out, ia, ib, const_d, oa, ob, ma) \ + /* H <<< 1 */ \ + vshr.s64 ma, ib, #63; \ + vshr.u64 oa, ib, #63; \ + vshr.u64 ob, ia, #63; \ + vand ma, const_d; \ + vshl.u64 ib, ib, #1; \ + vshl.u64 ia, ia, #1; \ + vorr ob, ib; \ + vorr oa, ia; \ + veor ob, ma; \ + vst1.64 {oa, ob}, [r_out] + + vld1.64 {rhash}, [r0] + vrev64.8 rhash, rhash /* byte-swap */ + vext.8 rhash, rhash, rhash, #8 + + vmov rbuf1, rhash + GCM_LSH_1(r0, rhash_l, rhash_h, rrconst_h, rh1_l, rh1_h, rt1_l) /* H<<<1 */ + + /* H² */ + PMUL_128x128(rr0, rr1, rbuf1, rh1, rt0, __) + REDUCTION(rh2, rr0, rr1, rrconst_h, rt0, __) + vmov rhash, rh2 + GCM_LSH_1(r1, rh2_l, rh2_h, rrconst_h, rbuf1_l, rbuf1_h, rt1_l) /* H²<<<1 */ + add r1, r1, #16 + + /* H³ */ + PMUL_128x128(rr0, rr1, rhash, rh1, rt1, __) + REDUCTION(rh3, rr0, rr1, rrconst_h, rt1, __) + + /* Hâ´ */ + PMUL_128x128(rr0, rr1, rhash, rbuf1, rt0, __) + REDUCTION(rh4, rr0, rr1, rrconst_h, rt0, __) + + GCM_LSH_1(r1, rh3_l, rh3_h, rrconst_h, rt0_l, rt0_h, rt1_l) /* H³<<<1 */ + add r1, r1, #16 + GCM_LSH_1(r1, rh4_l, rh4_h, rrconst_h, rt0_l, rt0_h, rt1_l) /* Hâ´<<<1 */ + + CLEAR_REG(rt0) + CLEAR_REG(rt1) + CLEAR_REG(rr1) + CLEAR_REG(rr0) + CLEAR_REG(rh1) + CLEAR_REG(rh2) + CLEAR_REG(rh3) + CLEAR_REG(rh4) + CLEAR_REG(rhash) + CLEAR_REG(rbuf1) + CLEAR_REG(rrconst) + vpop {q4-q7} + bx lr +.size _gcry_ghash_setup_armv8_ce_pmull,.-_gcry_ghash_setup_armv8_ce_pmull; + +#endif diff --git a/comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch64-ce.S b/comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch64-ce.S new file mode 100644 index 0000000000..877207d3e5 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-gcm-armv8-aarch64-ce.S @@ -0,0 +1,424 @@ +/* cipher-gcm-armv8-aarch64-ce.S - ARM/CE accelerated GHASH + * Copyright (C) 2016 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include "asm-common-aarch64.h" + +#if defined(__AARCH64EL__) && \ + defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO) + +.cpu generic+simd+crypto + +.text + + +/* Constants */ + +.align 4 +gcry_gcm_reduction_constant: +.Lrconst: + .quad 0x87 + + +/* Register macros */ + +#define rhash v0 +#define rr0 v1 +#define rr1 v2 +#define rbuf v3 +#define rbuf1 v4 +#define rbuf2 v5 +#define rbuf3 v6 +#define rbuf4 v7 +#define rbuf5 v8 +#define rr2 v9 +#define rr3 v10 +#define rr4 v11 +#define rr5 v12 +#define rr6 v13 +#define rr7 v14 +#define rr8 v15 +#define rr9 v16 + +#define rrconst v18 +#define rh1 v19 +#define rh2 v20 +#define rh3 v21 +#define rh4 v22 +#define rh5 v23 +#define rh6 v24 +#define t0 v25 +#define t1 v26 +#define t2 v27 +#define t3 v28 +#define t4 v29 +#define t5 v30 +#define vZZ v31 + +/* GHASH macros */ + +/* See "Gouvêa, C. P. L. & López, J. Implementing GCM on ARMv8. Topics in + * Cryptology — CT-RSA 2015" for details. + */ + +/* Input: 'a' and 'b', Output: 'r0:r1' (low 128-bits in r0, high in r1) */ +#define PMUL_128x128(r0, r1, a, b, T0, T1, interleave_op) \ + ext T0.16b, b.16b, b.16b, #8; \ + pmull r0.1q, a.1d, b.1d; \ + pmull2 r1.1q, a.2d, b.2d; \ + pmull T1.1q, a.1d, T0.1d; \ + pmull2 T0.1q, a.2d, T0.2d; \ + interleave_op; \ + eor T0.16b, T0.16b, T1.16b; \ + ext T1.16b, vZZ.16b, T0.16b, #8; \ + ext T0.16b, T0.16b, vZZ.16b, #8; \ + eor r0.16b, r0.16b, T1.16b; \ + eor r1.16b, r1.16b, T0.16b; + +/* Input: 'aA' and 'bA', Output: 'r0A:r1A' (low 128-bits in r0A, high in r1A) + * Input: 'aB' and 'bB', Output: 'r0B:r1B' (low 128-bits in r0B, high in r1B) + * Input: 'aC' and 'bC', Output: 'r0C:r1C' (low 128-bits in r0C, high in r1C) + */ +#define PMUL_128x128_3(r0A, r1A, aA, bA, t0A, t1A, \ + r0B, r1B, aB, bB, t0B, t1B, \ + r0C, r1C, aC, bC, t0C, t1C, interleave_op) \ + ext t0A.16b, bA.16b, bA.16b, #8; \ + pmull r0A.1q, aA.1d, bA.1d; \ + pmull2 r1A.1q, aA.2d, bA.2d; \ + ext t0B.16b, bB.16b, bB.16b, #8; \ + pmull r0B.1q, aB.1d, bB.1d; \ + pmull2 r1B.1q, aB.2d, bB.2d; \ + ext t0C.16b, bC.16b, bC.16b, #8; \ + pmull r0C.1q, aC.1d, bC.1d; \ + pmull2 r1C.1q, aC.2d, bC.2d; \ + pmull t1A.1q, aA.1d, t0A.1d; \ + pmull2 t0A.1q, aA.2d, t0A.2d; \ + pmull t1B.1q, aB.1d, t0B.1d; \ + pmull2 t0B.1q, aB.2d, t0B.2d; \ + pmull t1C.1q, aC.1d, t0C.1d; \ + pmull2 t0C.1q, aC.2d, t0C.2d; \ + eor t0A.16b, t0A.16b, t1A.16b; \ + eor t0B.16b, t0B.16b, t1B.16b; \ + eor t0C.16b, t0C.16b, t1C.16b; \ + interleave_op; \ + ext t1A.16b, vZZ.16b, t0A.16b, #8; \ + ext t0A.16b, t0A.16b, vZZ.16b, #8; \ + ext t1B.16b, vZZ.16b, t0B.16b, #8; \ + ext t0B.16b, t0B.16b, vZZ.16b, #8; \ + ext t1C.16b, vZZ.16b, t0C.16b, #8; \ + ext t0C.16b, t0C.16b, vZZ.16b, #8; \ + eor r0A.16b, r0A.16b, t1A.16b; \ + eor r1A.16b, r1A.16b, t0A.16b; \ + eor r0B.16b, r0B.16b, t1B.16b; \ + eor r1B.16b, r1B.16b, t0B.16b; \ + eor r0C.16b, r0C.16b, t1C.16b; \ + eor r1C.16b, r1C.16b, t0C.16b; \ + +/* Input: 'r0:r1', Output: 'a' */ +#define REDUCTION(a, r0, r1, rconst, T0, T1, interleave_op1, interleave_op2, \ + interleave_op3) \ + pmull2 T0.1q, r1.2d, rconst.2d; \ + interleave_op1; \ + ext T1.16b, T0.16b, vZZ.16b, #8; \ + ext T0.16b, vZZ.16b, T0.16b, #8; \ + interleave_op2; \ + eor r1.16b, r1.16b, T1.16b; \ + eor r0.16b, r0.16b, T0.16b; \ + pmull T0.1q, r1.1d, rconst.1d; \ + interleave_op3; \ + eor a.16b, r0.16b, T0.16b; + +/* Other functional macros */ + +#define _(...) __VA_ARGS__ +#define __ _() + +#define CLEAR_REG(reg) eor reg.16b, reg.16b, reg.16b; + +#define VPUSH_ABI \ + stp d8, d9, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + stp d10, d11, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + stp d12, d13, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); \ + stp d14, d15, [sp, #-16]!; \ + CFI_ADJUST_CFA_OFFSET(16); + +#define VPOP_ABI \ + ldp d14, d15, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + ldp d12, d13, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + ldp d10, d11, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); \ + ldp d8, d9, [sp], #16; \ + CFI_ADJUST_CFA_OFFSET(-16); + +/* + * unsigned int _gcry_ghash_armv8_ce_pmull (void *gcm_key, byte *result, + * const byte *buf, size_t nblocks, + * void *gcm_table); + */ +.align 3 +.globl _gcry_ghash_armv8_ce_pmull +ELF(.type _gcry_ghash_armv8_ce_pmull,%function;) +_gcry_ghash_armv8_ce_pmull: + /* input: + * x0: gcm_key + * x1: result/hash + * x2: buf + * x3: nblocks + * x4: gcm_table + */ + CFI_STARTPROC(); + + cbz x3, .Ldo_nothing; + + GET_DATA_POINTER(x5, .Lrconst) + + eor vZZ.16b, vZZ.16b, vZZ.16b + ld1 {rhash.16b}, [x1] + ld1 {rh1.16b}, [x0] + + rbit rhash.16b, rhash.16b /* bit-swap */ + ld1r {rrconst.2d}, [x5] + + cmp x3, #6 + b.lo .Less_than_6 + + add x6, x4, #64 + VPUSH_ABI + + ld1 {rh2.16b-rh5.16b}, [x4] + ld1 {rh6.16b}, [x6] + + sub x3, x3, #6 + + ld1 {rbuf.16b-rbuf2.16b}, [x2], #(3*16) + ld1 {rbuf3.16b-rbuf5.16b}, [x2], #(3*16) + + rbit rbuf.16b, rbuf.16b /* bit-swap */ + rbit rbuf1.16b, rbuf1.16b /* bit-swap */ + rbit rbuf2.16b, rbuf2.16b /* bit-swap */ + rbit rbuf3.16b, rbuf3.16b /* bit-swap */ + rbit rbuf4.16b, rbuf4.16b /* bit-swap */ + rbit rbuf5.16b, rbuf5.16b /* bit-swap */ + eor rhash.16b, rhash.16b, rbuf.16b + + cmp x3, #6 + b.lo .Lend_6 + +.Loop_6: + + /* (in1) * Hâµ => rr0:rr1 */ + /* (in2) * Hâ´ => rr2:rr3 */ + /* (in0 ^ hash) * Hⶠ=> rr4:rr5 */ + PMUL_128x128_3(rr0, rr1, rbuf1, rh5, t0, t1, + rr2, rr3, rbuf2, rh4, t2, t3, + rr4, rr5, rhash, rh6, t4, t5, + _(sub x3, x3, #6)) + + ld1 {rbuf.16b-rbuf2.16b}, [x2], #(3*16) + cmp x3, #6 + + eor rr0.16b, rr0.16b, rr2.16b + eor rr1.16b, rr1.16b, rr3.16b + + /* (in3) * H³ => rr2:rr3 */ + /* (in4) * H² => rr6:rr7 */ + /* (in5) * H¹ => rr8:rr9 */ + PMUL_128x128_3(rr2, rr3, rbuf3, rh3, t0, t1, + rr6, rr7, rbuf4, rh2, t2, t3, + rr8, rr9, rbuf5, rh1, t4, t5, + _(eor rr0.16b, rr0.16b, rr4.16b; + eor rr1.16b, rr1.16b, rr5.16b)) + + eor rr0.16b, rr0.16b, rr2.16b + eor rr1.16b, rr1.16b, rr3.16b + rbit rbuf.16b, rbuf.16b + eor rr0.16b, rr0.16b, rr6.16b + eor rr1.16b, rr1.16b, rr7.16b + rbit rbuf1.16b, rbuf1.16b + eor rr0.16b, rr0.16b, rr8.16b + eor rr1.16b, rr1.16b, rr9.16b + ld1 {rbuf3.16b-rbuf5.16b}, [x2], #(3*16) + + REDUCTION(rhash, rr0, rr1, rrconst, t0, t1, + _(rbit rbuf2.16b, rbuf2.16b), + _(rbit rbuf3.16b, rbuf3.16b), + _(rbit rbuf4.16b, rbuf4.16b)) + + rbit rbuf5.16b, rbuf5.16b + eor rhash.16b, rhash.16b, rbuf.16b + + b.hs .Loop_6 + +.Lend_6: + + /* (in1) * Hâµ => rr0:rr1 */ + /* (in0 ^ hash) * Hⶠ=> rr2:rr3 */ + /* (in2) * Hâ´ => rr4:rr5 */ + PMUL_128x128_3(rr0, rr1, rbuf1, rh5, t0, t1, + rr2, rr3, rhash, rh6, t2, t3, + rr4, rr5, rbuf2, rh4, t4, t5, + __) + eor rr0.16b, rr0.16b, rr2.16b + eor rr1.16b, rr1.16b, rr3.16b + eor rr0.16b, rr0.16b, rr4.16b + eor rr1.16b, rr1.16b, rr5.16b + + /* (in3) * H³ => rhash:rbuf */ + /* (in4) * H² => rr6:rr7 */ + /* (in5) * H¹ => rr8:rr9 */ + PMUL_128x128_3(rhash, rbuf, rbuf3, rh3, t0, t1, + rr6, rr7, rbuf4, rh2, t2, t3, + rr8, rr9, rbuf5, rh1, t4, t5, + _(CLEAR_REG(rh4); + CLEAR_REG(rh5); + CLEAR_REG(rh6))) + eor rr0.16b, rr0.16b, rhash.16b + eor rr1.16b, rr1.16b, rbuf.16b + eor rr0.16b, rr0.16b, rr6.16b + eor rr1.16b, rr1.16b, rr7.16b + eor rr0.16b, rr0.16b, rr8.16b + eor rr1.16b, rr1.16b, rr9.16b + + REDUCTION(rhash, rr0, rr1, rrconst, t0, t1, + _(CLEAR_REG(rh2); + CLEAR_REG(rh3); + CLEAR_REG(rr2); + CLEAR_REG(rbuf2); + CLEAR_REG(rbuf3)), + _(CLEAR_REG(rr3); + CLEAR_REG(rr4); + CLEAR_REG(rr5); + CLEAR_REG(rr6); + CLEAR_REG(rr7)), + _(CLEAR_REG(rr8); + CLEAR_REG(rr9); + CLEAR_REG(rbuf1); + CLEAR_REG(rbuf2))) + + CLEAR_REG(rbuf4) + CLEAR_REG(rbuf5) + CLEAR_REG(t2) + CLEAR_REG(t3) + CLEAR_REG(t4) + CLEAR_REG(t5) + + VPOP_ABI + + cbz x3, .Ldone + +.Less_than_6: + /* Handle remaining blocks. */ + + ld1 {rbuf.16b}, [x2], #16 + sub x3, x3, #1 + + rbit rbuf.16b, rbuf.16b /* bit-swap */ + + eor rhash.16b, rhash.16b, rbuf.16b + + cbz x3, .Lend + +.Loop: + PMUL_128x128(rr0, rr1, rh1, rhash, t0, t1, _(ld1 {rbuf.16b}, [x2], #16)) + REDUCTION(rhash, rr0, rr1, rrconst, t0, t1, + _(sub x3, x3, #1), + _(rbit rbuf.16b, rbuf.16b), + __) + eor rhash.16b, rhash.16b, rbuf.16b + + cbnz x3, .Loop + +.Lend: + PMUL_128x128(rr0, rr1, rh1, rhash, t0, t1, _(CLEAR_REG(rbuf))) + REDUCTION(rhash, rr0, rr1, rrconst, t0, t1, __, _(CLEAR_REG(rh1)), __) + +.Ldone: + CLEAR_REG(rr1) + CLEAR_REG(rr0) + rbit rhash.16b, rhash.16b /* bit-swap */ + CLEAR_REG(t0) + CLEAR_REG(t1) + + st1 {rhash.2d}, [x1] + CLEAR_REG(rhash) + +.Ldo_nothing: + mov x0, #0 + ret + CFI_ENDPROC() +ELF(.size _gcry_ghash_armv8_ce_pmull,.-_gcry_ghash_armv8_ce_pmull;) + + +/* + * void _gcry_ghash_setup_armv8_ce_pmull (void *gcm_key, void *gcm_table); + */ +.align 3 +.globl _gcry_ghash_setup_armv8_ce_pmull +ELF(.type _gcry_ghash_setup_armv8_ce_pmull,%function;) +_gcry_ghash_setup_armv8_ce_pmull: + /* input: + * x0: gcm_key + * x1: gcm_table + */ + CFI_STARTPROC() + + GET_DATA_POINTER(x2, .Lrconst) + + eor vZZ.16b, vZZ.16b, vZZ.16b + + /* H¹ */ + ld1 {rh1.16b}, [x0] + rbit rh1.16b, rh1.16b + st1 {rh1.16b}, [x0] + + ld1r {rrconst.2d}, [x2] + + /* H² */ + PMUL_128x128(rr0, rr1, rh1, rh1, t0, t1, __) + REDUCTION(rh2, rr0, rr1, rrconst, t0, t1, __, __, __) + + /* H³ */ + PMUL_128x128(rr0, rr1, rh2, rh1, t0, t1, __) + REDUCTION(rh3, rr0, rr1, rrconst, t0, t1, __, __, __) + + /* Hâ´ */ + PMUL_128x128(rr0, rr1, rh2, rh2, t0, t1, __) + REDUCTION(rh4, rr0, rr1, rrconst, t0, t1, __, __, __) + + /* Hâµ */ + PMUL_128x128(rr0, rr1, rh2, rh3, t0, t1, __) + REDUCTION(rh5, rr0, rr1, rrconst, t0, t1, __, __, __) + + /* Hⶠ*/ + PMUL_128x128(rr0, rr1, rh3, rh3, t0, t1, __) + REDUCTION(rh6, rr0, rr1, rrconst, t0, t1, __, __, __) + + st1 {rh2.16b-rh4.16b}, [x1], #(3*16) + st1 {rh5.16b-rh6.16b}, [x1] + + ret + CFI_ENDPROC() +ELF(.size _gcry_ghash_setup_armv8_ce_pmull,.-_gcry_ghash_setup_armv8_ce_pmull;) + +#endif diff --git a/comm/third_party/libgcrypt/cipher/cipher-gcm-intel-pclmul.c b/comm/third_party/libgcrypt/cipher/cipher-gcm-intel-pclmul.c new file mode 100644 index 0000000000..28165c653f --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-gcm-intel-pclmul.c @@ -0,0 +1,712 @@ +/* cipher-gcm-intel-pclmul.c - Intel PCLMUL accelerated Galois Counter Mode + * implementation + * Copyright (C) 2013-2014,2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +#ifdef GCM_USE_INTEL_PCLMUL + + +#if _GCRY_GCC_VERSION >= 40400 /* 4.4 */ +/* Prevent compiler from issuing SSE instructions between asm blocks. */ +# pragma GCC target("no-sse") +#endif +#if __clang__ +# pragma clang attribute push (__attribute__((target("no-sse"))), apply_to = function) +#endif + + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function)) + +#define ASM_FUNC_ATTR NO_INSTRUMENT_FUNCTION +#define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE + + +/* + Intel PCLMUL ghash based on white paper: + "Intel® Carry-Less Multiplication Instruction and its Usage for Computing the + GCM Mode - Rev 2.01"; Shay Gueron, Michael E. Kounavis. + */ +static ASM_FUNC_ATTR_INLINE void reduction(void) +{ + /* input: */ + + asm volatile (/* first phase of the reduction */ + "movdqa %%xmm3, %%xmm6\n\t" + "movdqa %%xmm3, %%xmm5\n\t" + "psllq $1, %%xmm6\n\t" /* packed right shifting << 63 */ + "pxor %%xmm3, %%xmm6\n\t" + "psllq $57, %%xmm5\n\t" /* packed right shifting << 57 */ + "psllq $62, %%xmm6\n\t" /* packed right shifting << 62 */ + "pxor %%xmm5, %%xmm6\n\t" /* xor the shifted versions */ + "pshufd $0x6a, %%xmm6, %%xmm5\n\t" + "pshufd $0xae, %%xmm6, %%xmm6\n\t" + "pxor %%xmm5, %%xmm3\n\t" /* first phase of the reduction + complete */ + + /* second phase of the reduction */ + "pxor %%xmm3, %%xmm1\n\t" /* xor the shifted versions */ + "psrlq $1, %%xmm3\n\t" /* packed left shifting >> 1 */ + "pxor %%xmm3, %%xmm6\n\t" + "psrlq $1, %%xmm3\n\t" /* packed left shifting >> 2 */ + "pxor %%xmm3, %%xmm1\n\t" + "psrlq $5, %%xmm3\n\t" /* packed left shifting >> 7 */ + "pxor %%xmm3, %%xmm6\n\t" + "pxor %%xmm6, %%xmm1\n\t" /* the result is in xmm1 */ + ::: "memory" ); +} + +static ASM_FUNC_ATTR_INLINE void gfmul_pclmul(void) +{ + /* Input: XMM0 and XMM1, Output: XMM1. Input XMM0 stays unmodified. + Input must be converted to little-endian. + */ + asm volatile (/* gfmul, xmm0 has operator a and xmm1 has operator b. */ + "pshufd $78, %%xmm0, %%xmm2\n\t" + "pshufd $78, %%xmm1, %%xmm4\n\t" + "pxor %%xmm0, %%xmm2\n\t" /* xmm2 holds a0+a1 */ + "pxor %%xmm1, %%xmm4\n\t" /* xmm4 holds b0+b1 */ + + "movdqa %%xmm0, %%xmm3\n\t" + "pclmulqdq $0, %%xmm1, %%xmm3\n\t" /* xmm3 holds a0*b0 */ + "pclmulqdq $17, %%xmm0, %%xmm1\n\t" /* xmm6 holds a1*b1 */ + "movdqa %%xmm3, %%xmm5\n\t" + "pclmulqdq $0, %%xmm2, %%xmm4\n\t" /* xmm4 holds (a0+a1)*(b0+b1) */ + + "pxor %%xmm1, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */ + "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */ + "movdqa %%xmm4, %%xmm5\n\t" + "psrldq $8, %%xmm4\n\t" + "pslldq $8, %%xmm5\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm4, %%xmm1\n\t" /* holds the result of the + carry-less multiplication of xmm0 + by xmm1 */ + ::: "memory" ); + + reduction(); +} + +static ASM_FUNC_ATTR_INLINE void +gfmul_pclmul_aggr4(const void *buf, const void *h_1, const void *h_table, + const unsigned char *be_mask) +{ + /* Input: + Hash: XMM1 + Output: + Hash: XMM1 + */ + asm volatile (/* perform clmul and merge results... */ + "movdqu 2*16(%[h_table]), %%xmm2\n\t" /* Load H4 */ + "movdqu 0*16(%[buf]), %%xmm5\n\t" + "pshufb %[be_mask], %%xmm5\n\t" /* be => le */ + "pxor %%xmm5, %%xmm1\n\t" + + "pshufd $78, %%xmm2, %%xmm5\n\t" + "pshufd $78, %%xmm1, %%xmm4\n\t" + "pxor %%xmm2, %%xmm5\n\t" /* xmm5 holds 4:a0+a1 */ + "pxor %%xmm1, %%xmm4\n\t" /* xmm4 holds 4:b0+b1 */ + "movdqa %%xmm2, %%xmm3\n\t" + "pclmulqdq $0, %%xmm1, %%xmm3\n\t" /* xmm3 holds 4:a0*b0 */ + "pclmulqdq $17, %%xmm2, %%xmm1\n\t" /* xmm1 holds 4:a1*b1 */ + "pclmulqdq $0, %%xmm5, %%xmm4\n\t" /* xmm4 holds 4:(a0+a1)*(b0+b1) */ + + "movdqu 1*16(%[h_table]), %%xmm5\n\t" /* Load H3 */ + "movdqu 1*16(%[buf]), %%xmm2\n\t" + "pshufb %[be_mask], %%xmm2\n\t" /* be => le */ + + "pshufd $78, %%xmm5, %%xmm0\n\t" + "pshufd $78, %%xmm2, %%xmm7\n\t" + "pxor %%xmm5, %%xmm0\n\t" /* xmm0 holds 3:a0+a1 */ + "pxor %%xmm2, %%xmm7\n\t" /* xmm7 holds 3:b0+b1 */ + "movdqa %%xmm5, %%xmm6\n\t" + "pclmulqdq $0, %%xmm2, %%xmm6\n\t" /* xmm6 holds 3:a0*b0 */ + "pclmulqdq $17, %%xmm5, %%xmm2\n\t" /* xmm2 holds 3:a1*b1 */ + "pclmulqdq $0, %%xmm0, %%xmm7\n\t" /* xmm7 holds 3:(a0+a1)*(b0+b1) */ + + "movdqu 2*16(%[buf]), %%xmm5\n\t" + "pshufb %[be_mask], %%xmm5\n\t" /* be => le */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 3+4:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 3+4:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 3+4:(a0+a1)*(b0+b1) */ + + "movdqu 0*16(%[h_table]), %%xmm2\n\t" /* Load H2 */ + + "pshufd $78, %%xmm2, %%xmm0\n\t" + "pshufd $78, %%xmm5, %%xmm7\n\t" + "pxor %%xmm2, %%xmm0\n\t" /* xmm0 holds 2:a0+a1 */ + "pxor %%xmm5, %%xmm7\n\t" /* xmm7 holds 2:b0+b1 */ + "movdqa %%xmm2, %%xmm6\n\t" + "pclmulqdq $0, %%xmm5, %%xmm6\n\t" /* xmm6 holds 2:a0*b0 */ + "pclmulqdq $17, %%xmm2, %%xmm5\n\t" /* xmm5 holds 2:a1*b1 */ + "pclmulqdq $0, %%xmm0, %%xmm7\n\t" /* xmm7 holds 2:(a0+a1)*(b0+b1) */ + + "movdqu 3*16(%[buf]), %%xmm2\n\t" + "pshufb %[be_mask], %%xmm2\n\t" /* be => le */ + : + : [buf] "r" (buf), + [h_table] "r" (h_table), + [be_mask] "m" (*be_mask) + : "memory" ); + + asm volatile ("pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 2+3+4:a0*b0 */ + "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 2+3+4:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 2+3+4:(a0+a1)*(b0+b1) */ + + "movdqu %[h_1], %%xmm5\n\t" /* Load H1 */ + + "pshufd $78, %%xmm5, %%xmm0\n\t" + "pshufd $78, %%xmm2, %%xmm7\n\t" + "pxor %%xmm5, %%xmm0\n\t" /* xmm0 holds 1:a0+a1 */ + "pxor %%xmm2, %%xmm7\n\t" /* xmm7 holds 1:b0+b1 */ + "movdqa %%xmm5, %%xmm6\n\t" + "pclmulqdq $0, %%xmm2, %%xmm6\n\t" /* xmm6 holds 1:a0*b0 */ + "pclmulqdq $17, %%xmm5, %%xmm2\n\t" /* xmm2 holds 1:a1*b1 */ + "pclmulqdq $0, %%xmm0, %%xmm7\n\t" /* xmm7 holds 1:(a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 1+2+3+4:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 1+2+3+4:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 1+2+3+4:(a0+a1)*(b0+b1) */ + + /* aggregated reduction... */ + "movdqa %%xmm3, %%xmm5\n\t" + "pxor %%xmm1, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */ + "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */ + "movdqa %%xmm4, %%xmm5\n\t" + "psrldq $8, %%xmm4\n\t" + "pslldq $8, %%xmm5\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm4, %%xmm1\n\t" /* holds the result of the + carry-less multiplication of xmm0 + by xmm1 */ + : + : [h_1] "m" (*(const unsigned char *)h_1) + : "memory" ); + + reduction(); +} + +#ifdef __x86_64__ +static ASM_FUNC_ATTR_INLINE void +gfmul_pclmul_aggr8(const void *buf, const void *h_table) +{ + /* Input: + H¹: XMM0 + bemask: XMM15 + Hash: XMM1 + Output: + Hash: XMM1 + Inputs XMM0 and XMM15 stays unmodified. + */ + asm volatile (/* Load H6, H7, H8. */ + "movdqu 6*16(%[h_table]), %%xmm10\n\t" + "movdqu 5*16(%[h_table]), %%xmm9\n\t" + "movdqu 4*16(%[h_table]), %%xmm8\n\t" + + /* perform clmul and merge results... */ + "movdqu 0*16(%[buf]), %%xmm5\n\t" + "movdqu 1*16(%[buf]), %%xmm2\n\t" + "pshufb %%xmm15, %%xmm5\n\t" /* be => le */ + "pshufb %%xmm15, %%xmm2\n\t" /* be => le */ + "pxor %%xmm5, %%xmm1\n\t" + + "pshufd $78, %%xmm10, %%xmm5\n\t" + "pshufd $78, %%xmm1, %%xmm4\n\t" + "pxor %%xmm10, %%xmm5\n\t" /* xmm5 holds 8:a0+a1 */ + "pxor %%xmm1, %%xmm4\n\t" /* xmm4 holds 8:b0+b1 */ + "movdqa %%xmm10, %%xmm3\n\t" + "pclmulqdq $0, %%xmm1, %%xmm3\n\t" /* xmm3 holds 8:a0*b0 */ + "pclmulqdq $17, %%xmm10, %%xmm1\n\t" /* xmm1 holds 8:a1*b1 */ + "pclmulqdq $0, %%xmm5, %%xmm4\n\t" /* xmm4 holds 8:(a0+a1)*(b0+b1) */ + + "pshufd $78, %%xmm9, %%xmm11\n\t" + "pshufd $78, %%xmm2, %%xmm7\n\t" + "pxor %%xmm9, %%xmm11\n\t" /* xmm11 holds 7:a0+a1 */ + "pxor %%xmm2, %%xmm7\n\t" /* xmm7 holds 7:b0+b1 */ + "movdqa %%xmm9, %%xmm6\n\t" + "pclmulqdq $0, %%xmm2, %%xmm6\n\t" /* xmm6 holds 7:a0*b0 */ + "pclmulqdq $17, %%xmm9, %%xmm2\n\t" /* xmm2 holds 7:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 7:(a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 7+8:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 7+8:(a0+a1)*(b0+b1) */ + + "movdqu 2*16(%[buf]), %%xmm5\n\t" + "movdqu 3*16(%[buf]), %%xmm2\n\t" + "pshufb %%xmm15, %%xmm5\n\t" /* be => le */ + "pshufb %%xmm15, %%xmm2\n\t" /* be => le */ + + "pshufd $78, %%xmm8, %%xmm11\n\t" + "pshufd $78, %%xmm5, %%xmm7\n\t" + "pxor %%xmm8, %%xmm11\n\t" /* xmm11 holds 6:a0+a1 */ + "pxor %%xmm5, %%xmm7\n\t" /* xmm7 holds 6:b0+b1 */ + "movdqa %%xmm8, %%xmm6\n\t" + "pclmulqdq $0, %%xmm5, %%xmm6\n\t" /* xmm6 holds 6:a0*b0 */ + "pclmulqdq $17, %%xmm8, %%xmm5\n\t" /* xmm5 holds 6:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 6:(a0+a1)*(b0+b1) */ + + /* Load H3, H4, H5. */ + "movdqu 3*16(%[h_table]), %%xmm10\n\t" + "movdqu 2*16(%[h_table]), %%xmm9\n\t" + "movdqu 1*16(%[h_table]), %%xmm8\n\t" + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 6+7+8:a0*b0 */ + "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 6+7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 6+7+8:(a0+a1)*(b0+b1) */ + + "pshufd $78, %%xmm10, %%xmm11\n\t" + "pshufd $78, %%xmm2, %%xmm7\n\t" + "pxor %%xmm10, %%xmm11\n\t" /* xmm11 holds 5:a0+a1 */ + "pxor %%xmm2, %%xmm7\n\t" /* xmm7 holds 5:b0+b1 */ + "movdqa %%xmm10, %%xmm6\n\t" + "pclmulqdq $0, %%xmm2, %%xmm6\n\t" /* xmm6 holds 5:a0*b0 */ + "pclmulqdq $17, %%xmm10, %%xmm2\n\t" /* xmm2 holds 5:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 5:(a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 5+6+7+8:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 5+6+7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 5+6+7+8:(a0+a1)*(b0+b1) */ + + "movdqu 4*16(%[buf]), %%xmm5\n\t" + "movdqu 5*16(%[buf]), %%xmm2\n\t" + "pshufb %%xmm15, %%xmm5\n\t" /* be => le */ + "pshufb %%xmm15, %%xmm2\n\t" /* be => le */ + + "pshufd $78, %%xmm9, %%xmm11\n\t" + "pshufd $78, %%xmm5, %%xmm7\n\t" + "pxor %%xmm9, %%xmm11\n\t" /* xmm11 holds 4:a0+a1 */ + "pxor %%xmm5, %%xmm7\n\t" /* xmm7 holds 4:b0+b1 */ + "movdqa %%xmm9, %%xmm6\n\t" + "pclmulqdq $0, %%xmm5, %%xmm6\n\t" /* xmm6 holds 4:a0*b0 */ + "pclmulqdq $17, %%xmm9, %%xmm5\n\t" /* xmm5 holds 4:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 4:(a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 4+5+6+7+8:a0*b0 */ + "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 4+5+6+7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 4+5+6+7+8:(a0+a1)*(b0+b1) */ + + "pshufd $78, %%xmm8, %%xmm11\n\t" + "pshufd $78, %%xmm2, %%xmm7\n\t" + "pxor %%xmm8, %%xmm11\n\t" /* xmm11 holds 3:a0+a1 */ + "pxor %%xmm2, %%xmm7\n\t" /* xmm7 holds 3:b0+b1 */ + "movdqa %%xmm8, %%xmm6\n\t" + "pclmulqdq $0, %%xmm2, %%xmm6\n\t" /* xmm6 holds 3:a0*b0 */ + "pclmulqdq $17, %%xmm8, %%xmm2\n\t" /* xmm2 holds 3:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 3:(a0+a1)*(b0+b1) */ + + "movdqu 0*16(%[h_table]), %%xmm8\n\t" /* Load H2 */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 3+4+5+6+7+8:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 3+4+5+6+7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 3+4+5+6+7+8:(a0+a1)*(b0+b1) */ + + "movdqu 6*16(%[buf]), %%xmm5\n\t" + "movdqu 7*16(%[buf]), %%xmm2\n\t" + "pshufb %%xmm15, %%xmm5\n\t" /* be => le */ + "pshufb %%xmm15, %%xmm2\n\t" /* be => le */ + + "pshufd $78, %%xmm8, %%xmm11\n\t" + "pshufd $78, %%xmm5, %%xmm7\n\t" + "pxor %%xmm8, %%xmm11\n\t" /* xmm11 holds 4:a0+a1 */ + "pxor %%xmm5, %%xmm7\n\t" /* xmm7 holds 4:b0+b1 */ + "movdqa %%xmm8, %%xmm6\n\t" + "pclmulqdq $0, %%xmm5, %%xmm6\n\t" /* xmm6 holds 4:a0*b0 */ + "pclmulqdq $17, %%xmm8, %%xmm5\n\t" /* xmm5 holds 4:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 4:(a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 2+3+4+5+6+7+8:a0*b0 */ + "pxor %%xmm5, %%xmm1\n\t" /* xmm1 holds 2+3+4+5+6+7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 2+3+4+5+6+7+8:(a0+a1)*(b0+b1) */ + + "pshufd $78, %%xmm0, %%xmm11\n\t" + "pshufd $78, %%xmm2, %%xmm7\n\t" + "pxor %%xmm0, %%xmm11\n\t" /* xmm11 holds 3:a0+a1 */ + "pxor %%xmm2, %%xmm7\n\t" /* xmm7 holds 3:b0+b1 */ + "movdqa %%xmm0, %%xmm6\n\t" + "pclmulqdq $0, %%xmm2, %%xmm6\n\t" /* xmm6 holds 3:a0*b0 */ + "pclmulqdq $17, %%xmm0, %%xmm2\n\t" /* xmm2 holds 3:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm7\n\t" /* xmm7 holds 3:(a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm3\n\t" /* xmm3 holds 1+2+3+3+4+5+6+7+8:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 1+2+3+3+4+5+6+7+8:a1*b1 */ + "pxor %%xmm7, %%xmm4\n\t" /* xmm4 holds 1+2+3+3+4+5+6+7+8:(a0+a1)*(b0+b1) */ + + /* aggregated reduction... */ + "movdqa %%xmm3, %%xmm5\n\t" + "pxor %%xmm1, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */ + "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */ + "movdqa %%xmm4, %%xmm5\n\t" + "psrldq $8, %%xmm4\n\t" + "pslldq $8, %%xmm5\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm4, %%xmm1\n\t" /* holds the result of the + carry-less multiplication of xmm0 + by xmm1 */ + : + : [buf] "r" (buf), + [h_table] "r" (h_table) + : "memory" ); + + reduction(); +} +#endif + +static ASM_FUNC_ATTR_INLINE void gcm_lsh(void *h, unsigned int hoffs) +{ + static const u64 pconst[2] __attribute__ ((aligned (16))) = + { U64_C(0x0000000000000001), U64_C(0xc200000000000000) }; + + asm volatile ("movdqu (%[h]), %%xmm2\n\t" + "pshufd $0xff, %%xmm2, %%xmm3\n\t" + "movdqa %%xmm2, %%xmm4\n\t" + "psrad $31, %%xmm3\n\t" + "pslldq $8, %%xmm4\n\t" + "pand %[pconst], %%xmm3\n\t" + "paddq %%xmm2, %%xmm2\n\t" + "psrlq $63, %%xmm4\n\t" + "pxor %%xmm3, %%xmm2\n\t" + "pxor %%xmm4, %%xmm2\n\t" + "movdqu %%xmm2, (%[h])\n\t" + : + : [pconst] "m" (pconst), + [h] "r" ((byte *)h + hoffs) + : "memory" ); +} + +void ASM_FUNC_ATTR +_gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c) +{ + static const unsigned char be_mask[16] __attribute__ ((aligned (16))) = + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; +#if defined(__x86_64__) && defined(__WIN64__) + char win64tmp[10 * 16]; + + /* XMM6-XMM15 need to be restored after use. */ + asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t" + "movdqu %%xmm7, 1*16(%0)\n\t" + "movdqu %%xmm8, 2*16(%0)\n\t" + "movdqu %%xmm9, 3*16(%0)\n\t" + "movdqu %%xmm10, 4*16(%0)\n\t" + "movdqu %%xmm11, 5*16(%0)\n\t" + "movdqu %%xmm12, 6*16(%0)\n\t" + "movdqu %%xmm13, 7*16(%0)\n\t" + "movdqu %%xmm14, 8*16(%0)\n\t" + "movdqu %%xmm15, 9*16(%0)\n\t" + : + : "r" (win64tmp) + : "memory" ); +#endif + + /* Swap endianness of hsub. */ + asm volatile ("movdqu (%[key]), %%xmm0\n\t" + "pshufb %[be_mask], %%xmm0\n\t" + "movdqu %%xmm0, (%[key])\n\t" + : + : [key] "r" (c->u_mode.gcm.u_ghash_key.key), + [be_mask] "m" (*be_mask) + : "memory"); + + gcm_lsh(c->u_mode.gcm.u_ghash_key.key, 0); /* H <<< 1 */ + + asm volatile ("movdqa %%xmm0, %%xmm1\n\t" + "movdqu (%[key]), %%xmm0\n\t" /* load H <<< 1 */ + : + : [key] "r" (c->u_mode.gcm.u_ghash_key.key) + : "memory"); + + gfmul_pclmul (); /* H<<<1•H => H² */ + + asm volatile ("movdqu %%xmm1, 0*16(%[h_table])\n\t" + "movdqa %%xmm1, %%xmm7\n\t" + : + : [h_table] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gcm_lsh(c->u_mode.gcm.gcm_table, 0 * 16); /* H² <<< 1 */ + gfmul_pclmul (); /* H<<<1•H² => H³ */ + + asm volatile ("movdqa %%xmm7, %%xmm0\n\t" + "movdqu %%xmm1, 1*16(%[h_table])\n\t" + "movdqu 0*16(%[h_table]), %%xmm1\n\t" /* load H² <<< 1 */ + : + : [h_table] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gfmul_pclmul (); /* H²<<<1•H² => Hâ´ */ + + asm volatile ("movdqu %%xmm1, 2*16(%[h_table])\n\t" + "movdqa %%xmm1, %%xmm0\n\t" + "movdqu (%[key]), %%xmm1\n\t" /* load H <<< 1 */ + : + : [h_table] "r" (c->u_mode.gcm.gcm_table), + [key] "r" (c->u_mode.gcm.u_ghash_key.key) + : "memory"); + + gcm_lsh(c->u_mode.gcm.gcm_table, 1 * 16); /* H³ <<< 1 */ + gcm_lsh(c->u_mode.gcm.gcm_table, 2 * 16); /* Hâ´ <<< 1 */ + +#ifdef __x86_64__ + gfmul_pclmul (); /* H<<<1•Hâ´ => Hâµ */ + + asm volatile ("movdqu %%xmm1, 3*16(%[h_table])\n\t" + "movdqu 0*16(%[h_table]), %%xmm1\n\t" /* load H² <<< 1 */ + : + : [h_table] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gfmul_pclmul (); /* H²<<<1•Hâ´ => Hⶠ*/ + + asm volatile ("movdqu %%xmm1, 4*16(%[h_table])\n\t" + "movdqu 1*16(%[h_table]), %%xmm1\n\t" /* load H³ <<< 1 */ + : + : [h_table] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gfmul_pclmul (); /* H³<<<1•Hâ´ => Hâ· */ + + asm volatile ("movdqu %%xmm1, 5*16(%[h_table])\n\t" + "movdqu 2*16(%[h_table]), %%xmm1\n\t" /* load Hâ´ <<< 1 */ + : + : [h_table] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gfmul_pclmul (); /* H³<<<1•Hâ´ => H⸠*/ + + asm volatile ("movdqu %%xmm1, 6*16(%[h_table])\n\t" + : + : [h_table] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gcm_lsh(c->u_mode.gcm.gcm_table, 3 * 16); /* Hâµ <<< 1 */ + gcm_lsh(c->u_mode.gcm.gcm_table, 4 * 16); /* Hⶠ<<< 1 */ + gcm_lsh(c->u_mode.gcm.gcm_table, 5 * 16); /* Hâ· <<< 1 */ + gcm_lsh(c->u_mode.gcm.gcm_table, 6 * 16); /* H⸠<<< 1 */ + +#ifdef __WIN64__ + /* Clear/restore used registers. */ + asm volatile( "pxor %%xmm0, %%xmm0\n\t" + "pxor %%xmm1, %%xmm1\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "pxor %%xmm3, %%xmm3\n\t" + "pxor %%xmm4, %%xmm4\n\t" + "pxor %%xmm5, %%xmm5\n\t" + "movdqu 0*16(%0), %%xmm6\n\t" + "movdqu 1*16(%0), %%xmm7\n\t" + "movdqu 2*16(%0), %%xmm8\n\t" + "movdqu 3*16(%0), %%xmm9\n\t" + "movdqu 4*16(%0), %%xmm10\n\t" + "movdqu 5*16(%0), %%xmm11\n\t" + "movdqu 6*16(%0), %%xmm12\n\t" + "movdqu 7*16(%0), %%xmm13\n\t" + "movdqu 8*16(%0), %%xmm14\n\t" + "movdqu 9*16(%0), %%xmm15\n\t" + : + : "r" (win64tmp) + : "memory" ); +#else + /* Clear used registers. */ + asm volatile( "pxor %%xmm0, %%xmm0\n\t" + "pxor %%xmm1, %%xmm1\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "pxor %%xmm3, %%xmm3\n\t" + "pxor %%xmm4, %%xmm4\n\t" + "pxor %%xmm5, %%xmm5\n\t" + "pxor %%xmm6, %%xmm6\n\t" + "pxor %%xmm7, %%xmm7\n\t" + "pxor %%xmm8, %%xmm8\n\t" + "pxor %%xmm9, %%xmm9\n\t" + "pxor %%xmm10, %%xmm10\n\t" + "pxor %%xmm11, %%xmm11\n\t" + "pxor %%xmm12, %%xmm12\n\t" + "pxor %%xmm13, %%xmm13\n\t" + "pxor %%xmm14, %%xmm14\n\t" + "pxor %%xmm15, %%xmm15\n\t" + ::: "memory" ); +#endif +#endif +} + + +unsigned int ASM_FUNC_ATTR +_gcry_ghash_intel_pclmul (gcry_cipher_hd_t c, byte *result, const byte *buf, + size_t nblocks) +{ + static const unsigned char be_mask[16] __attribute__ ((aligned (16))) = + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + const unsigned int blocksize = GCRY_GCM_BLOCK_LEN; +#if defined(__x86_64__) && defined(__WIN64__) + char win64tmp[10 * 16]; +#endif + + if (nblocks == 0) + return 0; + +#if defined(__x86_64__) && defined(__WIN64__) + /* XMM6-XMM15 need to be restored after use. */ + asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t" + "movdqu %%xmm7, 1*16(%0)\n\t" + "movdqu %%xmm8, 2*16(%0)\n\t" + "movdqu %%xmm9, 3*16(%0)\n\t" + "movdqu %%xmm10, 4*16(%0)\n\t" + "movdqu %%xmm11, 5*16(%0)\n\t" + "movdqu %%xmm12, 6*16(%0)\n\t" + "movdqu %%xmm13, 7*16(%0)\n\t" + "movdqu %%xmm14, 8*16(%0)\n\t" + "movdqu %%xmm15, 9*16(%0)\n\t" + : + : "r" (win64tmp) + : "memory" ); +#endif + + /* Preload hash. */ + asm volatile ("movdqa %[be_mask], %%xmm7\n\t" + "movdqu %[hash], %%xmm1\n\t" + "pshufb %%xmm7, %%xmm1\n\t" /* be => le */ + : + : [hash] "m" (*result), + [be_mask] "m" (*be_mask) + : "memory" ); + +#ifdef __x86_64__ + if (nblocks >= 8) + { + /* Preload H1. */ + asm volatile ("movdqa %%xmm7, %%xmm15\n\t" + "movdqa %[h_1], %%xmm0\n\t" + : + : [h_1] "m" (*c->u_mode.gcm.u_ghash_key.key) + : "memory" ); + + while (nblocks >= 8) + { + gfmul_pclmul_aggr8 (buf, c->u_mode.gcm.gcm_table); + + buf += 8 * blocksize; + nblocks -= 8; + } +#ifndef __WIN64__ + /* Clear used x86-64/XMM registers. */ + asm volatile( "pxor %%xmm8, %%xmm8\n\t" + "pxor %%xmm9, %%xmm9\n\t" + "pxor %%xmm10, %%xmm10\n\t" + "pxor %%xmm11, %%xmm11\n\t" + "pxor %%xmm12, %%xmm12\n\t" + "pxor %%xmm13, %%xmm13\n\t" + "pxor %%xmm14, %%xmm14\n\t" + "pxor %%xmm15, %%xmm15\n\t" + ::: "memory" ); +#endif + } +#endif + + while (nblocks >= 4) + { + gfmul_pclmul_aggr4 (buf, c->u_mode.gcm.u_ghash_key.key, + c->u_mode.gcm.gcm_table, be_mask); + + buf += 4 * blocksize; + nblocks -= 4; + } + + if (nblocks) + { + /* Preload H1. */ + asm volatile ("movdqa %[h_1], %%xmm0\n\t" + : + : [h_1] "m" (*c->u_mode.gcm.u_ghash_key.key) + : "memory" ); + + while (nblocks) + { + asm volatile ("movdqu %[buf], %%xmm2\n\t" + "pshufb %[be_mask], %%xmm2\n\t" /* be => le */ + "pxor %%xmm2, %%xmm1\n\t" + : + : [buf] "m" (*buf), [be_mask] "m" (*be_mask) + : "memory" ); + + gfmul_pclmul (); + + buf += blocksize; + nblocks--; + } + } + + /* Store hash. */ + asm volatile ("pshufb %[be_mask], %%xmm1\n\t" /* be => le */ + "movdqu %%xmm1, %[hash]\n\t" + : [hash] "=m" (*result) + : [be_mask] "m" (*be_mask) + : "memory" ); + +#if defined(__x86_64__) && defined(__WIN64__) + /* Clear/restore used registers. */ + asm volatile( "pxor %%xmm0, %%xmm0\n\t" + "pxor %%xmm1, %%xmm1\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "pxor %%xmm3, %%xmm3\n\t" + "pxor %%xmm4, %%xmm4\n\t" + "pxor %%xmm5, %%xmm5\n\t" + "movdqu 0*16(%0), %%xmm6\n\t" + "movdqu 1*16(%0), %%xmm7\n\t" + "movdqu 2*16(%0), %%xmm8\n\t" + "movdqu 3*16(%0), %%xmm9\n\t" + "movdqu 4*16(%0), %%xmm10\n\t" + "movdqu 5*16(%0), %%xmm11\n\t" + "movdqu 6*16(%0), %%xmm12\n\t" + "movdqu 7*16(%0), %%xmm13\n\t" + "movdqu 8*16(%0), %%xmm14\n\t" + "movdqu 9*16(%0), %%xmm15\n\t" + : + : "r" (win64tmp) + : "memory" ); +#else + /* Clear used registers. */ + asm volatile( "pxor %%xmm0, %%xmm0\n\t" + "pxor %%xmm1, %%xmm1\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "pxor %%xmm3, %%xmm3\n\t" + "pxor %%xmm4, %%xmm4\n\t" + "pxor %%xmm5, %%xmm5\n\t" + "pxor %%xmm6, %%xmm6\n\t" + "pxor %%xmm7, %%xmm7\n\t" + ::: "memory" ); +#endif + + return 0; +} + +#if __clang__ +# pragma clang attribute pop +#endif + +#endif /* GCM_USE_INTEL_PCLMUL */ diff --git a/comm/third_party/libgcrypt/cipher/cipher-gcm.c b/comm/third_party/libgcrypt/cipher/cipher-gcm.c new file mode 100644 index 0000000000..7aad12776f --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-gcm.c @@ -0,0 +1,1207 @@ +/* cipher-gcm.c - Generic Galois Counter Mode implementation + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * Copyright (C) 2013, 2018-2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +/* Helper macro to force alignment to 16 or 64 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_64 __attribute__ ((aligned (64))) +#else +# define ATTR_ALIGNED_64 +#endif + + +#ifdef GCM_USE_INTEL_PCLMUL +extern void _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c); + +extern unsigned int _gcry_ghash_intel_pclmul (gcry_cipher_hd_t c, byte *result, + const byte *buf, size_t nblocks); +#endif + +#ifdef GCM_USE_ARM_PMULL +extern void _gcry_ghash_setup_armv8_ce_pmull (void *gcm_key, void *gcm_table); + +extern unsigned int _gcry_ghash_armv8_ce_pmull (void *gcm_key, byte *result, + const byte *buf, size_t nblocks, + void *gcm_table); + +static void +ghash_setup_armv8_ce_pmull (gcry_cipher_hd_t c) +{ + _gcry_ghash_setup_armv8_ce_pmull(c->u_mode.gcm.u_ghash_key.key, + c->u_mode.gcm.gcm_table); +} + +static unsigned int +ghash_armv8_ce_pmull (gcry_cipher_hd_t c, byte *result, const byte *buf, + size_t nblocks) +{ + return _gcry_ghash_armv8_ce_pmull(c->u_mode.gcm.u_ghash_key.key, result, buf, + nblocks, c->u_mode.gcm.gcm_table); +} +#endif /* GCM_USE_ARM_PMULL */ + +#ifdef GCM_USE_ARM_NEON +extern void _gcry_ghash_setup_armv7_neon (void *gcm_key); + +extern unsigned int _gcry_ghash_armv7_neon (void *gcm_key, byte *result, + const byte *buf, size_t nblocks); + +static void +ghash_setup_armv7_neon (gcry_cipher_hd_t c) +{ + _gcry_ghash_setup_armv7_neon(c->u_mode.gcm.u_ghash_key.key); +} + +static unsigned int +ghash_armv7_neon (gcry_cipher_hd_t c, byte *result, const byte *buf, + size_t nblocks) +{ + return _gcry_ghash_armv7_neon(c->u_mode.gcm.u_ghash_key.key, result, buf, + nblocks); +} +#endif /* GCM_USE_ARM_NEON */ + +#ifdef GCM_USE_S390X_CRYPTO +#include "asm-inline-s390x.h" + +static unsigned int +ghash_s390x_kimd (gcry_cipher_hd_t c, byte *result, const byte *buf, + size_t nblocks) +{ + u128_t params[2]; + + memcpy (¶ms[0], result, 16); + memcpy (¶ms[1], c->u_mode.gcm.u_ghash_key.key, 16); + + kimd_execute (KMID_FUNCTION_GHASH, ¶ms, buf, nblocks * 16); + + memcpy (result, ¶ms[0], 16); + wipememory (params, sizeof(params)); + return 0; +} +#endif /* GCM_USE_S390X_CRYPTO*/ + + +#ifdef GCM_USE_TABLES +static struct +{ + volatile u32 counter_head; + u32 cacheline_align[64 / 4 - 1]; + u16 R[256]; + volatile u32 counter_tail; +} gcm_table ATTR_ALIGNED_64 = + { + 0, + { 0, }, + { + 0x0000, 0x01c2, 0x0384, 0x0246, 0x0708, 0x06ca, 0x048c, 0x054e, + 0x0e10, 0x0fd2, 0x0d94, 0x0c56, 0x0918, 0x08da, 0x0a9c, 0x0b5e, + 0x1c20, 0x1de2, 0x1fa4, 0x1e66, 0x1b28, 0x1aea, 0x18ac, 0x196e, + 0x1230, 0x13f2, 0x11b4, 0x1076, 0x1538, 0x14fa, 0x16bc, 0x177e, + 0x3840, 0x3982, 0x3bc4, 0x3a06, 0x3f48, 0x3e8a, 0x3ccc, 0x3d0e, + 0x3650, 0x3792, 0x35d4, 0x3416, 0x3158, 0x309a, 0x32dc, 0x331e, + 0x2460, 0x25a2, 0x27e4, 0x2626, 0x2368, 0x22aa, 0x20ec, 0x212e, + 0x2a70, 0x2bb2, 0x29f4, 0x2836, 0x2d78, 0x2cba, 0x2efc, 0x2f3e, + 0x7080, 0x7142, 0x7304, 0x72c6, 0x7788, 0x764a, 0x740c, 0x75ce, + 0x7e90, 0x7f52, 0x7d14, 0x7cd6, 0x7998, 0x785a, 0x7a1c, 0x7bde, + 0x6ca0, 0x6d62, 0x6f24, 0x6ee6, 0x6ba8, 0x6a6a, 0x682c, 0x69ee, + 0x62b0, 0x6372, 0x6134, 0x60f6, 0x65b8, 0x647a, 0x663c, 0x67fe, + 0x48c0, 0x4902, 0x4b44, 0x4a86, 0x4fc8, 0x4e0a, 0x4c4c, 0x4d8e, + 0x46d0, 0x4712, 0x4554, 0x4496, 0x41d8, 0x401a, 0x425c, 0x439e, + 0x54e0, 0x5522, 0x5764, 0x56a6, 0x53e8, 0x522a, 0x506c, 0x51ae, + 0x5af0, 0x5b32, 0x5974, 0x58b6, 0x5df8, 0x5c3a, 0x5e7c, 0x5fbe, + 0xe100, 0xe0c2, 0xe284, 0xe346, 0xe608, 0xe7ca, 0xe58c, 0xe44e, + 0xef10, 0xeed2, 0xec94, 0xed56, 0xe818, 0xe9da, 0xeb9c, 0xea5e, + 0xfd20, 0xfce2, 0xfea4, 0xff66, 0xfa28, 0xfbea, 0xf9ac, 0xf86e, + 0xf330, 0xf2f2, 0xf0b4, 0xf176, 0xf438, 0xf5fa, 0xf7bc, 0xf67e, + 0xd940, 0xd882, 0xdac4, 0xdb06, 0xde48, 0xdf8a, 0xddcc, 0xdc0e, + 0xd750, 0xd692, 0xd4d4, 0xd516, 0xd058, 0xd19a, 0xd3dc, 0xd21e, + 0xc560, 0xc4a2, 0xc6e4, 0xc726, 0xc268, 0xc3aa, 0xc1ec, 0xc02e, + 0xcb70, 0xcab2, 0xc8f4, 0xc936, 0xcc78, 0xcdba, 0xcffc, 0xce3e, + 0x9180, 0x9042, 0x9204, 0x93c6, 0x9688, 0x974a, 0x950c, 0x94ce, + 0x9f90, 0x9e52, 0x9c14, 0x9dd6, 0x9898, 0x995a, 0x9b1c, 0x9ade, + 0x8da0, 0x8c62, 0x8e24, 0x8fe6, 0x8aa8, 0x8b6a, 0x892c, 0x88ee, + 0x83b0, 0x8272, 0x8034, 0x81f6, 0x84b8, 0x857a, 0x873c, 0x86fe, + 0xa9c0, 0xa802, 0xaa44, 0xab86, 0xaec8, 0xaf0a, 0xad4c, 0xac8e, + 0xa7d0, 0xa612, 0xa454, 0xa596, 0xa0d8, 0xa11a, 0xa35c, 0xa29e, + 0xb5e0, 0xb422, 0xb664, 0xb7a6, 0xb2e8, 0xb32a, 0xb16c, 0xb0ae, + 0xbbf0, 0xba32, 0xb874, 0xb9b6, 0xbcf8, 0xbd3a, 0xbf7c, 0xbebe, + }, + 0 + }; + +#define gcmR gcm_table.R + +static inline +void prefetch_table(const void *tab, size_t len) +{ + const volatile byte *vtab = tab; + size_t i; + + for (i = 0; len - i >= 8 * 32; i += 8 * 32) + { + (void)vtab[i + 0 * 32]; + (void)vtab[i + 1 * 32]; + (void)vtab[i + 2 * 32]; + (void)vtab[i + 3 * 32]; + (void)vtab[i + 4 * 32]; + (void)vtab[i + 5 * 32]; + (void)vtab[i + 6 * 32]; + (void)vtab[i + 7 * 32]; + } + for (; i < len; i += 32) + { + (void)vtab[i]; + } + + (void)vtab[len - 1]; +} + +static inline void +do_prefetch_tables (const void *gcmM, size_t gcmM_size) +{ + /* Modify counters to trigger copy-on-write and unsharing if physical pages + * of look-up table are shared between processes. Modifying counters also + * causes checksums for pages to change and hint same-page merging algorithm + * that these pages are frequently changing. */ + gcm_table.counter_head++; + gcm_table.counter_tail++; + + /* Prefetch look-up tables to cache. */ + prefetch_table(gcmM, gcmM_size); + prefetch_table(&gcm_table, sizeof(gcm_table)); +} + +#ifdef GCM_TABLES_USE_U64 +static void +bshift (u64 * b0, u64 * b1) +{ + u64 t[2], mask; + + t[0] = *b0; + t[1] = *b1; + mask = -(t[1] & 1) & 0xe1; + mask <<= 56; + + *b1 = (t[1] >> 1) ^ (t[0] << 63); + *b0 = (t[0] >> 1) ^ mask; +} + +static void +do_fillM (unsigned char *h, u64 *M) +{ + int i, j; + + M[0 + 0] = 0; + M[0 + 16] = 0; + + M[8 + 0] = buf_get_be64 (h + 0); + M[8 + 16] = buf_get_be64 (h + 8); + + for (i = 4; i > 0; i /= 2) + { + M[i + 0] = M[2 * i + 0]; + M[i + 16] = M[2 * i + 16]; + + bshift (&M[i], &M[i + 16]); + } + + for (i = 2; i < 16; i *= 2) + for (j = 1; j < i; j++) + { + M[(i + j) + 0] = M[i + 0] ^ M[j + 0]; + M[(i + j) + 16] = M[i + 16] ^ M[j + 16]; + } + + for (i = 0; i < 16; i++) + { + M[i + 32] = (M[i + 0] >> 4) ^ ((u64) gcmR[(M[i + 16] & 0xf) << 4] << 48); + M[i + 48] = (M[i + 16] >> 4) ^ (M[i + 0] << 60); + } +} + +static inline unsigned int +do_ghash (unsigned char *result, const unsigned char *buf, const u64 *gcmM) +{ + u64 V[2]; + u64 tmp[2]; + const u64 *M; + u64 T; + u32 A; + int i; + + cipher_block_xor (V, result, buf, 16); + V[0] = be_bswap64 (V[0]); + V[1] = be_bswap64 (V[1]); + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + M = &gcmM[(V[1] & 0xf) + 32]; + V[1] >>= 4; + tmp[0] = M[0]; + tmp[1] = M[16]; + tmp[0] ^= gcmM[(V[1] & 0xf) + 0]; + tmp[1] ^= gcmM[(V[1] & 0xf) + 16]; + V[1] >>= 4; + + i = 6; + while (1) + { + M = &gcmM[(V[1] & 0xf) + 32]; + V[1] >>= 4; + + A = tmp[1] & 0xff; + T = tmp[0]; + tmp[0] = (T >> 8) ^ ((u64) gcmR[A] << 48) ^ gcmM[(V[1] & 0xf) + 0]; + tmp[1] = (T << 56) ^ (tmp[1] >> 8) ^ gcmM[(V[1] & 0xf) + 16]; + + tmp[0] ^= M[0]; + tmp[1] ^= M[16]; + + if (i == 0) + break; + + V[1] >>= 4; + --i; + } + + i = 7; + while (1) + { + M = &gcmM[(V[0] & 0xf) + 32]; + V[0] >>= 4; + + A = tmp[1] & 0xff; + T = tmp[0]; + tmp[0] = (T >> 8) ^ ((u64) gcmR[A] << 48) ^ gcmM[(V[0] & 0xf) + 0]; + tmp[1] = (T << 56) ^ (tmp[1] >> 8) ^ gcmM[(V[0] & 0xf) + 16]; + + tmp[0] ^= M[0]; + tmp[1] ^= M[16]; + + if (i == 0) + break; + + V[0] >>= 4; + --i; + } + + buf_put_be64 (result + 0, tmp[0]); + buf_put_be64 (result + 8, tmp[1]); + + return (sizeof(V) + sizeof(T) + sizeof(tmp) + + sizeof(int)*2 + sizeof(void*)*5); +} + +#else /*!GCM_TABLES_USE_U64*/ + +static void +bshift (u32 * M, int i) +{ + u32 t[4], mask; + + t[0] = M[i * 4 + 0]; + t[1] = M[i * 4 + 1]; + t[2] = M[i * 4 + 2]; + t[3] = M[i * 4 + 3]; + mask = -(t[3] & 1) & 0xe1; + + M[i * 4 + 3] = (t[3] >> 1) ^ (t[2] << 31); + M[i * 4 + 2] = (t[2] >> 1) ^ (t[1] << 31); + M[i * 4 + 1] = (t[1] >> 1) ^ (t[0] << 31); + M[i * 4 + 0] = (t[0] >> 1) ^ (mask << 24); +} + +static void +do_fillM (unsigned char *h, u32 *M) +{ + int i, j; + + M[0 * 4 + 0] = 0; + M[0 * 4 + 1] = 0; + M[0 * 4 + 2] = 0; + M[0 * 4 + 3] = 0; + + M[8 * 4 + 0] = buf_get_be32 (h + 0); + M[8 * 4 + 1] = buf_get_be32 (h + 4); + M[8 * 4 + 2] = buf_get_be32 (h + 8); + M[8 * 4 + 3] = buf_get_be32 (h + 12); + + for (i = 4; i > 0; i /= 2) + { + M[i * 4 + 0] = M[2 * i * 4 + 0]; + M[i * 4 + 1] = M[2 * i * 4 + 1]; + M[i * 4 + 2] = M[2 * i * 4 + 2]; + M[i * 4 + 3] = M[2 * i * 4 + 3]; + + bshift (M, i); + } + + for (i = 2; i < 16; i *= 2) + for (j = 1; j < i; j++) + { + M[(i + j) * 4 + 0] = M[i * 4 + 0] ^ M[j * 4 + 0]; + M[(i + j) * 4 + 1] = M[i * 4 + 1] ^ M[j * 4 + 1]; + M[(i + j) * 4 + 2] = M[i * 4 + 2] ^ M[j * 4 + 2]; + M[(i + j) * 4 + 3] = M[i * 4 + 3] ^ M[j * 4 + 3]; + } + + for (i = 0; i < 4 * 16; i += 4) + { + M[i + 0 + 64] = (M[i + 0] >> 4) + ^ ((u64) gcmR[(M[i + 3] << 4) & 0xf0] << 16); + M[i + 1 + 64] = (M[i + 1] >> 4) ^ (M[i + 0] << 28); + M[i + 2 + 64] = (M[i + 2] >> 4) ^ (M[i + 1] << 28); + M[i + 3 + 64] = (M[i + 3] >> 4) ^ (M[i + 2] << 28); + } +} + +static inline unsigned int +do_ghash (unsigned char *result, const unsigned char *buf, const u32 *gcmM) +{ + byte V[16]; + u32 tmp[4]; + u32 v; + const u32 *M, *m; + u32 T[3]; + int i; + + cipher_block_xor (V, result, buf, 16); /* V is big-endian */ + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + i = 15; + + v = V[i]; + M = &gcmM[(v & 0xf) * 4 + 64]; + v = (v & 0xf0) >> 4; + m = &gcmM[v * 4]; + v = V[--i]; + + tmp[0] = M[0] ^ m[0]; + tmp[1] = M[1] ^ m[1]; + tmp[2] = M[2] ^ m[2]; + tmp[3] = M[3] ^ m[3]; + + while (1) + { + M = &gcmM[(v & 0xf) * 4 + 64]; + v = (v & 0xf0) >> 4; + m = &gcmM[v * 4]; + + T[0] = tmp[0]; + T[1] = tmp[1]; + T[2] = tmp[2]; + tmp[0] = (T[0] >> 8) ^ ((u32) gcmR[tmp[3] & 0xff] << 16) ^ m[0]; + tmp[1] = (T[0] << 24) ^ (tmp[1] >> 8) ^ m[1]; + tmp[2] = (T[1] << 24) ^ (tmp[2] >> 8) ^ m[2]; + tmp[3] = (T[2] << 24) ^ (tmp[3] >> 8) ^ m[3]; + + tmp[0] ^= M[0]; + tmp[1] ^= M[1]; + tmp[2] ^= M[2]; + tmp[3] ^= M[3]; + + if (i == 0) + break; + + v = V[--i]; + } + + buf_put_be32 (result + 0, tmp[0]); + buf_put_be32 (result + 4, tmp[1]); + buf_put_be32 (result + 8, tmp[2]); + buf_put_be32 (result + 12, tmp[3]); + + return (sizeof(V) + sizeof(T) + sizeof(tmp) + + sizeof(int)*2 + sizeof(void*)*6); +} +#endif /*!GCM_TABLES_USE_U64*/ + +#define fillM(c) \ + do_fillM (c->u_mode.gcm.u_ghash_key.key, c->u_mode.gcm.gcm_table) +#define GHASH(c, result, buf) do_ghash (result, buf, c->u_mode.gcm.gcm_table) +#define prefetch_tables(c) \ + do_prefetch_tables(c->u_mode.gcm.gcm_table, sizeof(c->u_mode.gcm.gcm_table)) + +#else + +static unsigned long +bshift (unsigned long *b) +{ + unsigned long c; + int i; + c = b[3] & 1; + for (i = 3; i > 0; i--) + { + b[i] = (b[i] >> 1) | (b[i - 1] << 31); + } + b[i] >>= 1; + return c; +} + +static unsigned int +do_ghash (unsigned char *hsub, unsigned char *result, const unsigned char *buf) +{ + unsigned long V[4]; + int i, j; + byte *p; + +#ifdef WORDS_BIGENDIAN + p = result; +#else + unsigned long T[4]; + + cipher_block_xor (V, result, buf, 16); + for (i = 0; i < 4; i++) + { + V[i] = (V[i] & 0x00ff00ff) << 8 | (V[i] & 0xff00ff00) >> 8; + V[i] = (V[i] & 0x0000ffff) << 16 | (V[i] & 0xffff0000) >> 16; + } + p = (byte *) T; +#endif + + memset (p, 0, 16); + + for (i = 0; i < 16; i++) + { + for (j = 0x80; j; j >>= 1) + { + if (hsub[i] & j) + cipher_block_xor (p, p, V, 16); + if (bshift (V)) + V[0] ^= 0xe1000000; + } + } +#ifndef WORDS_BIGENDIAN + for (i = 0, p = (byte *) T; i < 16; i += 4, p += 4) + { + result[i + 0] = p[3]; + result[i + 1] = p[2]; + result[i + 2] = p[1]; + result[i + 3] = p[0]; + } +#endif + + return (sizeof(V) + sizeof(T) + sizeof(int)*2 + sizeof(void*)*5); +} + +#define fillM(c) do { } while (0) +#define GHASH(c, result, buf) do_ghash (c->u_mode.gcm.u_ghash_key.key, result, buf) +#define prefetch_tables(c) do {} while (0) + +#endif /* !GCM_USE_TABLES */ + + +static unsigned int +ghash_internal (gcry_cipher_hd_t c, byte *result, const byte *buf, + size_t nblocks) +{ + const unsigned int blocksize = GCRY_GCM_BLOCK_LEN; + unsigned int burn = 0; + + prefetch_tables (c); + + while (nblocks) + { + burn = GHASH (c, result, buf); + buf += blocksize; + nblocks--; + } + + return burn + (burn ? 5*sizeof(void*) : 0); +} + + +static void +setupM (gcry_cipher_hd_t c) +{ +#if defined(GCM_USE_INTEL_PCLMUL) || defined(GCM_USE_ARM_PMULL) || \ + defined(GCM_USE_S390X_CRYPTO) + unsigned int features = _gcry_get_hw_features (); +#endif + + c->u_mode.gcm.ghash_fn = NULL; + + if (0) + ; +#ifdef GCM_USE_INTEL_PCLMUL + else if (features & HWF_INTEL_PCLMUL) + { + c->u_mode.gcm.ghash_fn = _gcry_ghash_intel_pclmul; + _gcry_ghash_setup_intel_pclmul (c); + } +#endif +#ifdef GCM_USE_ARM_PMULL + else if (features & HWF_ARM_PMULL) + { + c->u_mode.gcm.ghash_fn = ghash_armv8_ce_pmull; + ghash_setup_armv8_ce_pmull (c); + } +#endif +#ifdef GCM_USE_ARM_NEON + else if (features & HWF_ARM_NEON) + { + c->u_mode.gcm.ghash_fn = ghash_armv7_neon; + ghash_setup_armv7_neon (c); + } +#endif +#ifdef GCM_USE_S390X_CRYPTO + else if (features & HWF_S390X_MSA) + { + if (kimd_query () & km_function_to_mask (KMID_FUNCTION_GHASH)) + { + c->u_mode.gcm.ghash_fn = ghash_s390x_kimd; + } + } +#endif + + if (c->u_mode.gcm.ghash_fn == NULL) + { + c->u_mode.gcm.ghash_fn = ghash_internal; + fillM (c); + } +} + + +static inline void +gcm_bytecounter_add (u32 ctr[2], size_t add) +{ + if (sizeof(add) > sizeof(u32)) + { + u32 high_add = ((add >> 31) >> 1) & 0xffffffff; + ctr[1] += high_add; + } + + ctr[0] += add; + if (ctr[0] >= add) + return; + ++ctr[1]; +} + + +static inline u32 +gcm_add32_be128 (byte *ctr, unsigned int add) +{ + /* 'ctr' must be aligned to four bytes. */ + const unsigned int blocksize = GCRY_GCM_BLOCK_LEN; + u32 *pval = (u32 *)(void *)(ctr + blocksize - sizeof(u32)); + u32 val; + + val = be_bswap32(*pval) + add; + *pval = be_bswap32(val); + + return val; /* return result as host-endian value */ +} + + +static inline int +gcm_check_datalen (u32 ctr[2]) +{ + /* len(plaintext) <= 2^39-256 bits == 2^36-32 bytes == 2^32-2 blocks */ + if (ctr[1] > 0xfU) + return 0; + if (ctr[1] < 0xfU) + return 1; + + if (ctr[0] <= 0xffffffe0U) + return 1; + + return 0; +} + + +static inline int +gcm_check_aadlen_or_ivlen (u32 ctr[2]) +{ + /* len(aad/iv) <= 2^64-1 bits ~= 2^61-1 bytes */ + if (ctr[1] > 0x1fffffffU) + return 0; + if (ctr[1] < 0x1fffffffU) + return 1; + + if (ctr[0] <= 0xffffffffU) + return 1; + + return 0; +} + + +static void +do_ghash_buf(gcry_cipher_hd_t c, byte *hash, const byte *buf, + size_t buflen, int do_padding) +{ + unsigned int blocksize = GCRY_GCM_BLOCK_LEN; + unsigned int unused = c->u_mode.gcm.mac_unused; + ghash_fn_t ghash_fn = c->u_mode.gcm.ghash_fn; + size_t nblocks, n; + unsigned int burn = 0; + + if (buflen == 0 && (unused == 0 || !do_padding)) + return; + + do + { + if (buflen > 0 && (buflen + unused < blocksize || unused > 0)) + { + n = blocksize - unused; + n = n < buflen ? n : buflen; + + buf_cpy (&c->u_mode.gcm.macbuf[unused], buf, n); + + unused += n; + buf += n; + buflen -= n; + } + if (!buflen) + { + if (!do_padding && unused < blocksize) + { + break; + } + + n = blocksize - unused; + if (n > 0) + { + memset (&c->u_mode.gcm.macbuf[unused], 0, n); + unused = blocksize; + } + } + + if (unused > 0) + { + gcry_assert (unused == blocksize); + + /* Process one block from macbuf. */ + burn = ghash_fn (c, hash, c->u_mode.gcm.macbuf, 1); + unused = 0; + } + + nblocks = buflen / blocksize; + + if (nblocks) + { + burn = ghash_fn (c, hash, buf, nblocks); + buf += blocksize * nblocks; + buflen -= blocksize * nblocks; + } + } + while (buflen > 0); + + c->u_mode.gcm.mac_unused = unused; + + if (burn) + _gcry_burn_stack (burn); +} + + +static gcry_err_code_t +gcm_ctr_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t err = 0; + + while (inbuflen) + { + u32 nblocks_to_overflow; + u32 num_ctr_increments; + u32 curr_ctr_low; + size_t currlen = inbuflen; + byte ctr_copy[GCRY_GCM_BLOCK_LEN]; + int fix_ctr = 0; + + /* GCM CTR increments only least significant 32-bits, without carry + * to upper 96-bits of counter. Using generic CTR implementation + * directly would carry 32-bit overflow to upper 96-bit. Detect + * if input length is long enough to cause overflow, and limit + * input length so that CTR overflow happen but updated CTR value is + * not used to encrypt further input. After overflow, upper 96 bits + * of CTR are restored to cancel out modification done by generic CTR + * encryption. */ + + if (inbuflen > c->unused) + { + curr_ctr_low = gcm_add32_be128 (c->u_ctr.ctr, 0); + + /* Number of CTR increments this inbuflen would cause. */ + num_ctr_increments = (inbuflen - c->unused) / GCRY_GCM_BLOCK_LEN + + !!((inbuflen - c->unused) % GCRY_GCM_BLOCK_LEN); + + if ((u32)(num_ctr_increments + curr_ctr_low) < curr_ctr_low) + { + nblocks_to_overflow = 0xffffffffU - curr_ctr_low + 1; + currlen = nblocks_to_overflow * GCRY_GCM_BLOCK_LEN + c->unused; + if (currlen > inbuflen) + { + currlen = inbuflen; + } + + fix_ctr = 1; + cipher_block_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN); + } + } + + err = _gcry_cipher_ctr_encrypt(c, outbuf, outbuflen, inbuf, currlen); + if (err != 0) + return err; + + if (fix_ctr) + { + /* Lower 32-bits of CTR should now be zero. */ + gcry_assert(gcm_add32_be128 (c->u_ctr.ctr, 0) == 0); + + /* Restore upper part of CTR. */ + buf_cpy(c->u_ctr.ctr, ctr_copy, GCRY_GCM_BLOCK_LEN - sizeof(u32)); + + wipememory(ctr_copy, sizeof(ctr_copy)); + } + + inbuflen -= currlen; + inbuf += currlen; + outbuflen -= currlen; + outbuf += currlen; + } + + return err; +} + + +static gcry_err_code_t +gcm_crypt_inner (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen, int encrypt) +{ + gcry_err_code_t err; + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Use a bulk method if available. */ + if (c->bulk.gcm_crypt) + { + /* Bulk method requires that there is no cached data. */ + if (inbuflen >= GCRY_GCM_BLOCK_LEN && c->u_mode.gcm.mac_unused == 0) + { + size_t nblks = inbuflen / GCRY_GCM_BLOCK_LEN; + size_t nleft; + size_t ndone; + + nleft = c->bulk.gcm_crypt (c, outbuf, inbuf, nblks, encrypt); + ndone = nblks - nleft; + + inbuf += ndone * GCRY_GCM_BLOCK_LEN; + outbuf += ndone * GCRY_GCM_BLOCK_LEN; + inbuflen -= ndone * GCRY_GCM_BLOCK_LEN; + outbuflen -= ndone * GCRY_GCM_BLOCK_LEN; + + if (inbuflen == 0) + break; + + currlen = inbuflen; + } + else if (c->u_mode.gcm.mac_unused > 0 + && inbuflen >= GCRY_GCM_BLOCK_LEN + + (16 - c->u_mode.gcm.mac_unused)) + { + /* Handle just enough data so that cache is depleted, and on + * next loop iteration use bulk method. */ + currlen = 16 - c->u_mode.gcm.mac_unused; + + gcry_assert(currlen); + } + } + + /* Since checksumming is done after/before encryption/decryption, + * process input in 24KiB chunks to keep data loaded in L1 cache for + * checksumming/decryption. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + if (!encrypt) + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, inbuf, currlen, 0); + + err = gcm_ctr_encrypt(c, outbuf, outbuflen, inbuf, currlen); + if (err != 0) + return err; + + if (encrypt) + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, outbuf, currlen, 0); + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_gcm_encrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + + if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->marks.tag + || c->u_mode.gcm.ghash_data_finalized + || !c->u_mode.gcm.ghash_fn) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + + if (c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode) + return GPG_ERR_INV_STATE; + + if (!c->u_mode.gcm.ghash_aad_finalized) + { + /* Start of encryption marks end of AAD stream. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, NULL, 0, 1); + c->u_mode.gcm.ghash_aad_finalized = 1; + } + + gcm_bytecounter_add(c->u_mode.gcm.datalen, inbuflen); + if (!gcm_check_datalen(c->u_mode.gcm.datalen)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + return gcm_crypt_inner (c, outbuf, outbuflen, inbuf, inbuflen, 1); +} + + +gcry_err_code_t +_gcry_cipher_gcm_decrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + + if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->marks.tag + || c->u_mode.gcm.ghash_data_finalized + || !c->u_mode.gcm.ghash_fn) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + + if (!c->u_mode.gcm.ghash_aad_finalized) + { + /* Start of decryption marks end of AAD stream. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, NULL, 0, 1); + c->u_mode.gcm.ghash_aad_finalized = 1; + } + + gcm_bytecounter_add(c->u_mode.gcm.datalen, inbuflen); + if (!gcm_check_datalen(c->u_mode.gcm.datalen)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + return gcm_crypt_inner (c, outbuf, outbuflen, inbuf, inbuflen, 0); +} + + +gcry_err_code_t +_gcry_cipher_gcm_authenticate (gcry_cipher_hd_t c, + const byte * aadbuf, size_t aadbuflen) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + + if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->marks.tag + || c->u_mode.gcm.ghash_aad_finalized + || c->u_mode.gcm.ghash_data_finalized + || !c->u_mode.gcm.ghash_fn) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + + gcm_bytecounter_add(c->u_mode.gcm.aadlen, aadbuflen); + if (!gcm_check_aadlen_or_ivlen(c->u_mode.gcm.aadlen)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, aadbuf, aadbuflen, 0); + + return 0; +} + + +void +_gcry_cipher_gcm_setkey (gcry_cipher_hd_t c) +{ + memset (c->u_mode.gcm.u_ghash_key.key, 0, GCRY_GCM_BLOCK_LEN); + + c->spec->encrypt (&c->context.c, c->u_mode.gcm.u_ghash_key.key, + c->u_mode.gcm.u_ghash_key.key); + setupM (c); +} + + +static gcry_err_code_t +_gcry_cipher_gcm_initiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) +{ + memset (c->u_mode.gcm.aadlen, 0, sizeof(c->u_mode.gcm.aadlen)); + memset (c->u_mode.gcm.datalen, 0, sizeof(c->u_mode.gcm.datalen)); + memset (c->u_mode.gcm.u_tag.tag, 0, GCRY_GCM_BLOCK_LEN); + c->u_mode.gcm.datalen_over_limits = 0; + c->u_mode.gcm.ghash_data_finalized = 0; + c->u_mode.gcm.ghash_aad_finalized = 0; + + if (ivlen == 0) + return GPG_ERR_INV_LENGTH; + + if (ivlen != GCRY_GCM_BLOCK_LEN - 4) + { + u32 iv_bytes[2] = {0, 0}; + u32 bitlengths[2][2]; + + if (!c->u_mode.gcm.ghash_fn) + return GPG_ERR_INV_STATE; + + memset(c->u_ctr.ctr, 0, GCRY_GCM_BLOCK_LEN); + + gcm_bytecounter_add(iv_bytes, ivlen); + if (!gcm_check_aadlen_or_ivlen(iv_bytes)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + do_ghash_buf(c, c->u_ctr.ctr, iv, ivlen, 1); + + /* iv length, 64-bit */ + bitlengths[1][1] = be_bswap32(iv_bytes[0] << 3); + bitlengths[1][0] = be_bswap32((iv_bytes[0] >> 29) | + (iv_bytes[1] << 3)); + /* zeros, 64-bit */ + bitlengths[0][1] = 0; + bitlengths[0][0] = 0; + + do_ghash_buf(c, c->u_ctr.ctr, (byte*)bitlengths, GCRY_GCM_BLOCK_LEN, 1); + + wipememory (iv_bytes, sizeof iv_bytes); + wipememory (bitlengths, sizeof bitlengths); + } + else + { + /* 96-bit IV is handled differently. */ + memcpy (c->u_ctr.ctr, iv, ivlen); + c->u_ctr.ctr[12] = c->u_ctr.ctr[13] = c->u_ctr.ctr[14] = 0; + c->u_ctr.ctr[15] = 1; + } + + c->spec->encrypt (&c->context.c, c->u_mode.gcm.tagiv, c->u_ctr.ctr); + + gcm_add32_be128 (c->u_ctr.ctr, 1); + + c->unused = 0; + c->marks.iv = 1; + c->marks.tag = 0; + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_gcm_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) +{ + c->marks.iv = 0; + c->marks.tag = 0; + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 0; + + if (fips_mode ()) + { + /* Direct invocation of GCM setiv in FIPS mode disables encryption. */ + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 1; + } + + return _gcry_cipher_gcm_initiv (c, iv, ivlen); +} + + +#if 0 && TODO +void +_gcry_cipher_gcm_geniv (gcry_cipher_hd_t c, + byte *ivout, size_t ivoutlen, const byte *nonce, + size_t noncelen) +{ + /* nonce: user provided part (might be null) */ + /* noncelen: check if proper length (if nonce not null) */ + /* ivout: iv used to initialize gcm, output to user */ + /* ivoutlen: check correct size */ + byte iv[IVLEN]; + + if (!ivout) + return GPG_ERR_INV_ARG; + if (ivoutlen != IVLEN) + return GPG_ERR_INV_LENGTH; + if (nonce != NULL && !is_nonce_ok_len(noncelen)) + return GPG_ERR_INV_ARG; + + gcm_generate_iv(iv, nonce, noncelen); + + c->marks.iv = 0; + c->marks.tag = 0; + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 0; + + _gcry_cipher_gcm_initiv (c, iv, IVLEN); + + buf_cpy(ivout, iv, IVLEN); + wipememory(iv, sizeof(iv)); +} +#endif + + +static int +is_tag_length_valid(size_t taglen) +{ + switch (taglen) + { + /* Allowed tag lengths from NIST SP 800-38D. */ + case 128 / 8: /* GCRY_GCM_BLOCK_LEN */ + case 120 / 8: + case 112 / 8: + case 104 / 8: + case 96 / 8: + case 64 / 8: + case 32 / 8: + return 1; + + default: + return 0; + } +} + +static gcry_err_code_t +_gcry_cipher_gcm_tag (gcry_cipher_hd_t c, + byte * outbuf, size_t outbuflen, int check) +{ + if (!(is_tag_length_valid (outbuflen) || outbuflen >= GCRY_GCM_BLOCK_LEN)) + return GPG_ERR_INV_LENGTH; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + + if (!c->marks.tag) + { + u32 bitlengths[2][2]; + + if (!c->u_mode.gcm.ghash_fn) + return GPG_ERR_INV_STATE; + + /* aad length */ + bitlengths[0][1] = be_bswap32(c->u_mode.gcm.aadlen[0] << 3); + bitlengths[0][0] = be_bswap32((c->u_mode.gcm.aadlen[0] >> 29) | + (c->u_mode.gcm.aadlen[1] << 3)); + /* data length */ + bitlengths[1][1] = be_bswap32(c->u_mode.gcm.datalen[0] << 3); + bitlengths[1][0] = be_bswap32((c->u_mode.gcm.datalen[0] >> 29) | + (c->u_mode.gcm.datalen[1] << 3)); + + /* Finalize data-stream. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, NULL, 0, 1); + c->u_mode.gcm.ghash_aad_finalized = 1; + c->u_mode.gcm.ghash_data_finalized = 1; + + /* Add bitlengths to tag. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, (byte*)bitlengths, + GCRY_GCM_BLOCK_LEN, 1); + cipher_block_xor (c->u_mode.gcm.u_tag.tag, c->u_mode.gcm.tagiv, + c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN); + c->marks.tag = 1; + + wipememory (bitlengths, sizeof (bitlengths)); + wipememory (c->u_mode.gcm.macbuf, GCRY_GCM_BLOCK_LEN); + wipememory (c->u_mode.gcm.tagiv, GCRY_GCM_BLOCK_LEN); + wipememory (c->u_mode.gcm.aadlen, sizeof (c->u_mode.gcm.aadlen)); + wipememory (c->u_mode.gcm.datalen, sizeof (c->u_mode.gcm.datalen)); + } + + if (!check) + { + if (outbuflen > GCRY_GCM_BLOCK_LEN) + outbuflen = GCRY_GCM_BLOCK_LEN; + + /* NB: We already checked that OUTBUF is large enough to hold + * the result or has valid truncated length. */ + memcpy (outbuf, c->u_mode.gcm.u_tag.tag, outbuflen); + } + else + { + /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF + * and thus we need to compare its length first. */ + if (!is_tag_length_valid (outbuflen) + || !buf_eq_const (outbuf, c->u_mode.gcm.u_tag.tag, outbuflen)) + return GPG_ERR_CHECKSUM; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_gcm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + /* Outputting authentication tag is part of encryption. */ + if (c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode) + return GPG_ERR_INV_STATE; + + return _gcry_cipher_gcm_tag (c, outtag, taglen, 0); +} + +gcry_err_code_t +_gcry_cipher_gcm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_gcm_tag (c, (unsigned char *) intag, taglen, 1); +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-internal.h b/comm/third_party/libgcrypt/cipher/cipher-internal.h new file mode 100644 index 0000000000..59b36ce78b --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-internal.h @@ -0,0 +1,809 @@ +/* cipher-internal.h - Internal defs for cipher.c + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef G10_CIPHER_INTERNAL_H +#define G10_CIPHER_INTERNAL_H + +#include "./poly1305-internal.h" + + +/* The maximum supported size of a block in bytes. */ +#define MAX_BLOCKSIZE 16 + +/* The length for an OCB block. Although OCB supports any block + length it does not make sense to use a 64 bit blocklen (and cipher) + because this reduces the security margin to an unacceptable state. + Thus we require a cipher with 128 bit blocklength. */ +#define OCB_BLOCK_LEN (128/8) + +/* The size of the pre-computed L table for OCB. This takes the same + size as the table used for GCM and thus we don't save anything by + not using such a table. */ +#define OCB_L_TABLE_SIZE 16 + + +/* Check the above constants. */ +#if OCB_BLOCK_LEN > MAX_BLOCKSIZE +# error OCB_BLOCKLEN > MAX_BLOCKSIZE +#endif + + + +/* Magic values for the context structure. */ +#define CTX_MAGIC_NORMAL 0x24091964 +#define CTX_MAGIC_SECURE 0x46919042 + +/* Try to use 16 byte aligned cipher context for better performance. + We use the aligned attribute, thus it is only possible to implement + this with gcc. */ +#undef NEED_16BYTE_ALIGNED_CONTEXT +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define NEED_16BYTE_ALIGNED_CONTEXT 1 +#endif + +/* Undef this symbol to trade GCM speed for 256 bytes of memory per context */ +#define GCM_USE_TABLES 1 + + +/* GCM_USE_INTEL_PCLMUL indicates whether to compile GCM with Intel PCLMUL + code. */ +#undef GCM_USE_INTEL_PCLMUL +#if defined(ENABLE_PCLMUL_SUPPORT) && defined(GCM_USE_TABLES) +# if ((defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)) +# if __GNUC__ >= 4 +# define GCM_USE_INTEL_PCLMUL 1 +# endif +# endif +#endif /* GCM_USE_INTEL_PCLMUL */ + +/* GCM_USE_ARM_PMULL indicates whether to compile GCM with ARMv8 PMULL code. */ +#undef GCM_USE_ARM_PMULL +#if defined(ENABLE_ARM_CRYPTO_SUPPORT) && defined(GCM_USE_TABLES) +# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \ + && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_AARCH32_CRYPTO) +# define GCM_USE_ARM_PMULL 1 +# elif defined(__AARCH64EL__) && \ + defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO) +# define GCM_USE_ARM_PMULL 1 +# endif +#endif /* GCM_USE_ARM_PMULL */ + +/* GCM_USE_ARM_NEON indicates whether to compile GCM with ARMv7 NEON code. */ +#undef GCM_USE_ARM_NEON +#if defined(GCM_USE_TABLES) +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \ + defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_NEON) +# define GCM_USE_ARM_NEON 1 +#endif +#endif /* GCM_USE_ARM_NEON */ + +/* GCM_USE_S390X_CRYPTO indicates whether to enable zSeries code. */ +#undef GCM_USE_S390X_CRYPTO +#if defined(HAVE_GCC_INLINE_ASM_S390X) +# define GCM_USE_S390X_CRYPTO 1 +#endif /* GCM_USE_S390X_CRYPTO */ + +typedef unsigned int (*ghash_fn_t) (gcry_cipher_hd_t c, byte *result, + const byte *buf, size_t nblocks); + + +/* A structure with function pointers for mode operations. */ +typedef struct cipher_mode_ops +{ + gcry_err_code_t (*encrypt)(gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen); + gcry_err_code_t (*decrypt)(gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen); + gcry_err_code_t (*setiv)(gcry_cipher_hd_t c, const unsigned char *iv, + size_t ivlen); + + gcry_err_code_t (*authenticate)(gcry_cipher_hd_t c, + const unsigned char *abuf, size_t abuflen); + gcry_err_code_t (*get_tag)(gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen); + gcry_err_code_t (*check_tag)(gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen); +} cipher_mode_ops_t; + + +/* A structure with function pointers for bulk operations. The cipher + algorithm setkey function initializes them when bulk operations are + available and the actual encryption routines use them if they are + not NULL. */ +typedef struct cipher_bulk_ops +{ + void (*cfb_enc)(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks); + void (*cfb_dec)(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks); + void (*cbc_enc)(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int cbc_mac); + void (*cbc_dec)(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks); + void (*ofb_enc)(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks); + void (*ctr_enc)(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks); + size_t (*ocb_crypt)(gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt); + size_t (*ocb_auth)(gcry_cipher_hd_t c, const void *abuf_arg, size_t nblocks); + void (*xts_crypt)(void *context, unsigned char *tweak, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt); + size_t (*gcm_crypt)(gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt); +} cipher_bulk_ops_t; + + +/* A VIA processor with the Padlock engine as well as the Intel AES_NI + instructions require an alignment of most data on a 16 byte + boundary. Because we trick out the compiler while allocating the + context, the align attribute as used in rijndael.c does not work on + its own. Thus we need to make sure that the entire context + structure is a aligned on that boundary. We achieve this by + defining a new type and use that instead of our usual alignment + type. */ +typedef union +{ + PROPERLY_ALIGNED_TYPE foo; +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + char bar[16] __attribute__ ((aligned (16))); +#endif + char c[1]; +} cipher_context_alignment_t; + + +/* Storage structure for CMAC, for CMAC and EAX modes. */ +typedef struct { + /* The initialization vector. Also contains tag after finalization. */ + union { + cipher_context_alignment_t iv_align; + unsigned char iv[MAX_BLOCKSIZE]; + } u_iv; + + /* Subkeys for tag creation, not cleared by gcry_cipher_reset. */ + unsigned char subkeys[2][MAX_BLOCKSIZE]; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[MAX_BLOCKSIZE]; + + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ +} gcry_cmac_context_t; + + +/* The handle structure. */ +struct gcry_cipher_handle +{ + int magic; + size_t actual_handle_size; /* Allocated size of this handle. */ + size_t handle_offset; /* Offset to the malloced block. */ + gcry_cipher_spec_t *spec; + + /* The algorithm id. This is a hack required because the module + interface does not easily allow to retrieve this value. */ + int algo; + + /* A structure with function pointers for mode operations. */ + cipher_mode_ops_t mode_ops; + + /* A structure with function pointers for bulk operations. Due to + limitations of the module system (we don't want to change the + API) we need to keep these function pointers here. */ + cipher_bulk_ops_t bulk; + + int mode; + unsigned int flags; + + struct { + unsigned int key:1; /* Set to 1 if a key has been set. */ + unsigned int iv:1; /* Set to 1 if a IV has been set. */ + unsigned int tag:1; /* Set to 1 if a tag is finalized. */ + unsigned int finalize:1; /* Next encrypt/decrypt has the final data. */ + unsigned int allow_weak_key:1; /* Set to 1 if weak keys are allowed. */ + } marks; + + /* The initialization vector. For best performance we make sure + that it is properly aligned. In particular some implementations + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. For + OCB mode it is used for the offset value. */ + union { + cipher_context_alignment_t iv_align; + unsigned char iv[MAX_BLOCKSIZE]; + } u_iv; + + /* The counter for CTR mode. This field is also used by AESWRAP and + thus we can't use the U_IV union. For OCB mode it is used for + the checksum. */ + union { + cipher_context_alignment_t iv_align; + unsigned char ctr[MAX_BLOCKSIZE]; + } u_ctr; + + /* Space to save an IV or CTR for chaining operations. */ + unsigned char lastiv[MAX_BLOCKSIZE]; + int unused; /* Number of unused bytes in LASTIV. */ + + union { + /* Mode specific storage for CCM mode. */ + struct { + u64 encryptlen; + u64 aadlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1; /* Set to 1 if nonce has been set. */ + unsigned int lengths:1; /* Set to 1 if CCM length parameters has been + processed. */ + } ccm; + + /* Mode specific storage for Poly1305 mode. */ + struct { + /* byte counter for AAD. */ + u32 aadcount[2]; + + /* byte counter for data. */ + u32 datacount[2]; + + unsigned int aad_finalized:1; + unsigned int bytecount_over_limits:1; + + poly1305_context_t ctx; + } poly1305; + + /* Mode specific storage for CMAC mode. */ + gcry_cmac_context_t cmac; + + /* Mode specific storage for EAX mode. */ + struct { + /* CMAC for header (AAD). */ + gcry_cmac_context_t cmac_header; + + /* CMAC for ciphertext. */ + gcry_cmac_context_t cmac_ciphertext; + } eax; + + /* Mode specific storage for GCM mode. */ + struct { + /* The interim tag for GCM mode. */ + union { + cipher_context_alignment_t iv_align; + unsigned char tag[MAX_BLOCKSIZE]; + } u_tag; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + /* byte counters for GCM */ + u32 aadlen[2]; + u32 datalen[2]; + + /* encrypted tag counter */ + unsigned char tagiv[MAX_BLOCKSIZE]; + + unsigned int ghash_data_finalized:1; + unsigned int ghash_aad_finalized:1; + + unsigned int datalen_over_limits:1; + unsigned int disallow_encryption_because_of_setiv_in_fips_mode:1; + + /* --- Following members are not cleared in gcry_cipher_reset --- */ + + /* GHASH multiplier from key. */ + union { + cipher_context_alignment_t iv_align; + unsigned char key[MAX_BLOCKSIZE]; + } u_ghash_key; + + /* GHASH implementation in use. */ + ghash_fn_t ghash_fn; + + /* Pre-calculated table for GCM. */ +#ifdef GCM_USE_TABLES + #if (SIZEOF_UNSIGNED_LONG == 8 || defined(__x86_64__)) + #define GCM_TABLES_USE_U64 1 + u64 gcm_table[4 * 16]; + #else + #undef GCM_TABLES_USE_U64 + u32 gcm_table[8 * 16]; + #endif +#endif + } gcm; + + /* Mode specific storage for OCB mode. */ + struct { + /* --- Following members are not cleared in gcry_cipher_reset --- */ + + /* Helper variables and pre-computed table of L values. */ + unsigned char L_star[OCB_BLOCK_LEN]; + unsigned char L_dollar[OCB_BLOCK_LEN]; + unsigned char L0L1[OCB_BLOCK_LEN]; + unsigned char L[OCB_L_TABLE_SIZE][OCB_BLOCK_LEN]; + + /* --- Following members are cleared in gcry_cipher_reset --- */ + + /* The tag is valid if marks.tag has been set. */ + unsigned char tag[OCB_BLOCK_LEN]; + + /* A buffer to hold the offset for the AAD processing. */ + unsigned char aad_offset[OCB_BLOCK_LEN]; + + /* A buffer to hold the current sum of AAD processing. We can't + use tag here because tag may already hold the preprocessed + checksum of the data. */ + unsigned char aad_sum[OCB_BLOCK_LEN]; + + /* A buffer to store AAD data not yet processed. */ + unsigned char aad_leftover[OCB_BLOCK_LEN]; + + /* Number of data/aad blocks processed so far. */ + u64 data_nblocks; + u64 aad_nblocks; + + /* Number of valid bytes in AAD_LEFTOVER. */ + unsigned char aad_nleftover; + + /* Length of the tag. Fixed for now but may eventually be + specified using a set of gcry_cipher_flags. */ + unsigned char taglen; + + /* Flags indicating that the final data/aad block has been + processed. */ + unsigned int data_finalized:1; + unsigned int aad_finalized:1; + } ocb; + + /* Mode specific storage for XTS mode. */ + struct { + /* Pointer to tweak cipher context, allocated after actual + * cipher context. */ + char *tweak_context; + } xts; + } u_mode; + + /* What follows are two contexts of the cipher in use. The first + one needs to be aligned well enough for the cipher operation + whereas the second one is a copy created by cipher_setkey and + used by cipher_reset. That second copy has no need for proper + aligment because it is only accessed by memcpy. */ + cipher_context_alignment_t context; +}; + + +/*-- cipher-cbc.c --*/ +gcry_err_code_t _gcry_cipher_cbc_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cbc_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cbc_cts_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cbc_cts_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + +/*-- cipher-cfb.c --*/ +gcry_err_code_t _gcry_cipher_cfb_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cfb_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cfb8_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cfb8_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + + +/*-- cipher-ofb.c --*/ +gcry_err_code_t _gcry_cipher_ofb_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + +/*-- cipher-ctr.c --*/ +gcry_err_code_t _gcry_cipher_ctr_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + + +/*-- cipher-aeswrap.c --*/ +gcry_err_code_t _gcry_cipher_aeswrap_encrypt +/* */ (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_aeswrap_decrypt +/* */ (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen); + + +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +gcry_err_code_t _gcry_cipher_ccm_set_lengths +/* */ (gcry_cipher_hd_t c, u64 encryptedlen, u64 aadlen, u64 taglen); +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + +/*-- cipher-cmac.c --*/ +gcry_err_code_t _gcry_cmac_generate_subkeys +/* */ (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx); +gcry_err_code_t _gcry_cmac_write +/* */ (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, + const byte * inbuf, size_t inlen); +gcry_err_code_t _gcry_cmac_final +/* */ (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx); +void _gcry_cmac_reset (gcry_cmac_context_t *ctx); + + +/*-- cipher-eax.c --*/ +gcry_err_code_t _gcry_cipher_eax_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_eax_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_eax_set_nonce +/* */ (gcry_cipher_hd_t c, + const unsigned char *nonce, size_t noncelen); +gcry_err_code_t _gcry_cipher_eax_authenticate +/* */ (gcry_cipher_hd_t c, + const unsigned char *aadbuf, size_t aadbuflen); +gcry_err_code_t _gcry_cipher_eax_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_eax_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); +gcry_err_code_t _gcry_cipher_eax_setkey +/* */ (gcry_cipher_hd_t c); + + +/*-- cipher-gcm.c --*/ +gcry_err_code_t _gcry_cipher_gcm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_gcm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_gcm_setiv +/* */ (gcry_cipher_hd_t c, + const unsigned char *iv, size_t ivlen); +gcry_err_code_t _gcry_cipher_gcm_authenticate +/* */ (gcry_cipher_hd_t c, + const unsigned char *aadbuf, size_t aadbuflen); +gcry_err_code_t _gcry_cipher_gcm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_gcm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); +void _gcry_cipher_gcm_setkey +/* */ (gcry_cipher_hd_t c); + + +/*-- cipher-poly1305.c --*/ +gcry_err_code_t _gcry_cipher_poly1305_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_poly1305_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_poly1305_setiv +/* */ (gcry_cipher_hd_t c, + const unsigned char *iv, size_t ivlen); +gcry_err_code_t _gcry_cipher_poly1305_authenticate +/* */ (gcry_cipher_hd_t c, + const unsigned char *aadbuf, size_t aadbuflen); +gcry_err_code_t _gcry_cipher_poly1305_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_poly1305_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); +void _gcry_cipher_poly1305_setkey +/* */ (gcry_cipher_hd_t c); + + +/*-- chacha20.c --*/ +gcry_err_code_t _gcry_chacha20_poly1305_encrypt +/* */ (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, + size_t length); +gcry_err_code_t _gcry_chacha20_poly1305_decrypt +/* */ (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, + size_t length); + + +/*-- cipher-ocb.c --*/ +gcry_err_code_t _gcry_cipher_ocb_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_ocb_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_ocb_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ocb_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +gcry_err_code_t _gcry_cipher_ocb_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ocb_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); +void _gcry_cipher_ocb_setkey +/* */ (gcry_cipher_hd_t c); + + +/*-- cipher-xts.c --*/ +gcry_err_code_t _gcry_cipher_xts_encrypt +/* */ (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_xts_decrypt +/* */ (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + + +/* Return the L-value for block N. Note: 'cipher_ocb.c' ensures that N + * will never be multiple of 65536 (1 << OCB_L_TABLE_SIZE), thus N can + * be directly passed to _gcry_ctz() function and resulting index will + * never overflow the table. */ +static inline const unsigned char * +ocb_get_l (gcry_cipher_hd_t c, u64 n) +{ + unsigned long ntz; + +#if ((defined(__i386__) || defined(__x86_64__)) && __GNUC__ >= 4) + /* Assumes that N != 0. */ + asm ("rep;bsfl %k[low], %k[ntz]\n\t" + : [ntz] "=r" (ntz) + : [low] "r" ((unsigned long)n) + : "cc"); +#else + ntz = _gcry_ctz (n); +#endif + + return c->u_mode.ocb.L[ntz]; +} + + +/* Return bit-shift of blocksize. */ +static inline unsigned int _gcry_blocksize_shift(gcry_cipher_hd_t c) +{ + /* Only blocksizes 8 and 16 are used. Return value in such way + * that compiler can optimize calling functions based on this. */ + return c->spec->blocksize == 8 ? 3 : 4; +} + + +/* Optimized function for adding value to cipher block. */ +static inline void +cipher_block_add(void *_dstsrc, unsigned int add, size_t blocksize) +{ + byte *dstsrc = _dstsrc; + u64 s[2]; + + if (blocksize == 8) + { + buf_put_be64(dstsrc + 0, buf_get_be64(dstsrc + 0) + add); + } + else /* blocksize == 16 */ + { + s[0] = buf_get_be64(dstsrc + 8); + s[1] = buf_get_be64(dstsrc + 0); + s[0] += add; + s[1] += (s[0] < add); + buf_put_be64(dstsrc + 8, s[0]); + buf_put_be64(dstsrc + 0, s[1]); + } +} + + +/* Optimized function for cipher block copying */ +static inline void +cipher_block_cpy(void *_dst, const void *_src, size_t blocksize) +{ + byte *dst = _dst; + const byte *src = _src; + u64 s[2]; + + if (blocksize == 8) + { + buf_put_he64(dst + 0, buf_get_he64(src + 0)); + } + else /* blocksize == 16 */ + { + s[0] = buf_get_he64(src + 0); + s[1] = buf_get_he64(src + 8); + buf_put_he64(dst + 0, s[0]); + buf_put_he64(dst + 8, s[1]); + } +} + + +/* Optimized function for cipher block xoring */ +static inline void +cipher_block_xor(void *_dst, const void *_src1, const void *_src2, + size_t blocksize) +{ + byte *dst = _dst; + const byte *src1 = _src1; + const byte *src2 = _src2; + u64 s1[2]; + u64 s2[2]; + + if (blocksize == 8) + { + buf_put_he64(dst + 0, buf_get_he64(src1 + 0) ^ buf_get_he64(src2 + 0)); + } + else /* blocksize == 16 */ + { + s1[0] = buf_get_he64(src1 + 0); + s1[1] = buf_get_he64(src1 + 8); + s2[0] = buf_get_he64(src2 + 0); + s2[1] = buf_get_he64(src2 + 8); + buf_put_he64(dst + 0, s1[0] ^ s2[0]); + buf_put_he64(dst + 8, s1[1] ^ s2[1]); + } +} + + +/* Optimized function for in-place cipher block xoring */ +static inline void +cipher_block_xor_1(void *_dst, const void *_src, size_t blocksize) +{ + cipher_block_xor (_dst, _dst, _src, blocksize); +} + + +/* Optimized function for cipher block xoring with two destination cipher + blocks. Used mainly by CFB mode encryption. */ +static inline void +cipher_block_xor_2dst(void *_dst1, void *_dst2, const void *_src, + size_t blocksize) +{ + byte *dst1 = _dst1; + byte *dst2 = _dst2; + const byte *src = _src; + u64 d2[2]; + u64 s[2]; + + if (blocksize == 8) + { + d2[0] = buf_get_he64(dst2 + 0) ^ buf_get_he64(src + 0); + buf_put_he64(dst2 + 0, d2[0]); + buf_put_he64(dst1 + 0, d2[0]); + } + else /* blocksize == 16 */ + { + s[0] = buf_get_he64(src + 0); + s[1] = buf_get_he64(src + 8); + d2[0] = buf_get_he64(dst2 + 0); + d2[1] = buf_get_he64(dst2 + 8); + d2[0] = d2[0] ^ s[0]; + d2[1] = d2[1] ^ s[1]; + buf_put_he64(dst2 + 0, d2[0]); + buf_put_he64(dst2 + 8, d2[1]); + buf_put_he64(dst1 + 0, d2[0]); + buf_put_he64(dst1 + 8, d2[1]); + } +} + + +/* Optimized function for combined cipher block xoring and copying. + Used by mainly CBC mode decryption. */ +static inline void +cipher_block_xor_n_copy_2(void *_dst_xor, const void *_src_xor, + void *_srcdst_cpy, const void *_src_cpy, + size_t blocksize) +{ + byte *dst_xor = _dst_xor; + byte *srcdst_cpy = _srcdst_cpy; + const byte *src_xor = _src_xor; + const byte *src_cpy = _src_cpy; + u64 sc[2]; + u64 sx[2]; + u64 sdc[2]; + + if (blocksize == 8) + { + sc[0] = buf_get_he64(src_cpy + 0); + buf_put_he64(dst_xor + 0, + buf_get_he64(srcdst_cpy + 0) ^ buf_get_he64(src_xor + 0)); + buf_put_he64(srcdst_cpy + 0, sc[0]); + } + else /* blocksize == 16 */ + { + sc[0] = buf_get_he64(src_cpy + 0); + sc[1] = buf_get_he64(src_cpy + 8); + sx[0] = buf_get_he64(src_xor + 0); + sx[1] = buf_get_he64(src_xor + 8); + sdc[0] = buf_get_he64(srcdst_cpy + 0); + sdc[1] = buf_get_he64(srcdst_cpy + 8); + sx[0] ^= sdc[0]; + sx[1] ^= sdc[1]; + buf_put_he64(dst_xor + 0, sx[0]); + buf_put_he64(dst_xor + 8, sx[1]); + buf_put_he64(srcdst_cpy + 0, sc[0]); + buf_put_he64(srcdst_cpy + 8, sc[1]); + } +} + + +/* Optimized function for combined cipher block xoring and copying. + Used by mainly CFB mode decryption. */ +static inline void +cipher_block_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, + size_t blocksize) +{ + cipher_block_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, blocksize); +} + + +#endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/comm/third_party/libgcrypt/cipher/cipher-ocb.c b/comm/third_party/libgcrypt/cipher/cipher-ocb.c new file mode 100644 index 0000000000..24db6a9e2c --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-ocb.c @@ -0,0 +1,761 @@ +/* cipher-ocb.c - OCB cipher mode + * Copyright (C) 2015, 2016 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * + * OCB is covered by several patents but may be used freely by most + * software. See http://web.cs.ucdavis.edu/~rogaway/ocb/license.htm . + * In particular license 1 is suitable for Libgcrypt: See + * http://web.cs.ucdavis.edu/~rogaway/ocb/license1.pdf for the full + * license document; it basically says: + * + * License 1 — License for Open-Source Software Implementations of OCB + * (Jan 9, 2013) + * + * Under this license, you are authorized to make, use, and + * distribute open-source software implementations of OCB. This + * license terminates for you if you sue someone over their + * open-source software implementation of OCB claiming that you have + * a patent covering their implementation. + */ + + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +/* Double the OCB_BLOCK_LEN sized block B in-place. */ +static inline void +double_block (u64 b[2]) +{ + u64 l_0, l, r; + + l = b[1]; + r = b[0]; + + l_0 = -(l >> 63); + l = (l + l) ^ (r >> 63); + r = (r + r) ^ (l_0 & 135); + + b[1] = l; + b[0] = r; +} + + +/* Copy OCB_BLOCK_LEN from buffer S starting at bit offset BITOFF to + * buffer D. */ +static void +bit_copy (unsigned char d[16], const unsigned char s[24], unsigned int bitoff) +{ + u64 s0l, s1l, s1r, s2r; + unsigned int shift; + unsigned int byteoff; + + byteoff = bitoff / 8; + shift = bitoff % 8; + + s0l = buf_get_be64 (s + byteoff + 0); + s1l = buf_get_be64 (s + byteoff + 8); + s1r = shift ? s1l : 0; + s2r = shift ? buf_get_be64 (s + 16) << (8 * byteoff) : 0; + + buf_put_be64 (d + 0, (s0l << shift) | (s1r >> ((64 - shift) & 63))); + buf_put_be64 (d + 8, (s1l << shift) | (s2r >> ((64 - shift) & 63))); +} + + +/* Get L_big value for block N, where N is multiple of 65536. */ +static void +ocb_get_L_big (gcry_cipher_hd_t c, u64 n, unsigned char *l_buf) +{ + int ntz = _gcry_ctz64 (n); + u64 L[2]; + + gcry_assert(ntz >= OCB_L_TABLE_SIZE); + + L[1] = buf_get_be64 (c->u_mode.ocb.L[OCB_L_TABLE_SIZE - 1]); + L[0] = buf_get_be64 (c->u_mode.ocb.L[OCB_L_TABLE_SIZE - 1] + 8); + + for (ntz -= OCB_L_TABLE_SIZE - 1; ntz; ntz--) + double_block (L); + + buf_put_be64 (l_buf + 0, L[1]); + buf_put_be64 (l_buf + 8, L[0]); +} + + +/* Called after key has been set. Sets up L table. */ +void _gcry_cipher_ocb_setkey (gcry_cipher_hd_t c) +{ + unsigned char ktop[OCB_BLOCK_LEN]; + unsigned int burn = 0; + unsigned int nburn; + u64 L[2]; + int i; + + /* L_star = E(zero_128) */ + memset (ktop, 0, OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, c->u_mode.ocb.L_star, ktop); + burn = nburn > burn ? nburn : burn; + /* L_dollar = double(L_star) */ + L[1] = buf_get_be64 (c->u_mode.ocb.L_star); + L[0] = buf_get_be64 (c->u_mode.ocb.L_star + 8); + double_block (L); + buf_put_be64 (c->u_mode.ocb.L_dollar + 0, L[1]); + buf_put_be64 (c->u_mode.ocb.L_dollar + 8, L[0]); + /* L_0 = double(L_dollar), ... */ + double_block (L); + buf_put_be64 (c->u_mode.ocb.L[0] + 0, L[1]); + buf_put_be64 (c->u_mode.ocb.L[0] + 8, L[0]); + for (i = 1; i < OCB_L_TABLE_SIZE; i++) + { + double_block (L); + buf_put_be64 (c->u_mode.ocb.L[i] + 0, L[1]); + buf_put_be64 (c->u_mode.ocb.L[i] + 8, L[0]); + } + /* Precalculated offset L0+L1 */ + cipher_block_xor (c->u_mode.ocb.L0L1, + c->u_mode.ocb.L[0], c->u_mode.ocb.L[1], OCB_BLOCK_LEN); + + /* Cleanup */ + wipememory (ktop, sizeof ktop); + if (burn > 0) + _gcry_burn_stack (burn + 4*sizeof(void*)); +} + + +/* Set the nonce for OCB. This requires that the key has been set. + Using it again resets start a new encryption cycle using the same + key. */ +gcry_err_code_t +_gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + unsigned char ktop[OCB_BLOCK_LEN]; + unsigned char stretch[OCB_BLOCK_LEN + 8]; + unsigned int bottom; + unsigned int burn = 0; + unsigned int nburn; + + /* Check args. */ + if (!c->marks.key) + return GPG_ERR_INV_STATE; /* Key must have been set first. */ + switch (c->u_mode.ocb.taglen) + { + case 8: + case 12: + case 16: + break; + default: + return GPG_ERR_BUG; /* Invalid tag length. */ + } + + if (c->spec->blocksize != OCB_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (!nonce) + return GPG_ERR_INV_ARG; + /* 120 bit is the allowed maximum. In addition we impose a minimum + of 64 bit. */ + if (noncelen > (120/8) || noncelen < (64/8) || noncelen >= OCB_BLOCK_LEN) + return GPG_ERR_INV_LENGTH; + + /* Prepare the nonce. */ + memset (ktop, 0, OCB_BLOCK_LEN); + buf_cpy (ktop + (OCB_BLOCK_LEN - noncelen), nonce, noncelen); + ktop[0] = ((c->u_mode.ocb.taglen * 8) % 128) << 1; + ktop[OCB_BLOCK_LEN - noncelen - 1] |= 1; + bottom = ktop[OCB_BLOCK_LEN - 1] & 0x3f; + ktop[OCB_BLOCK_LEN - 1] &= 0xc0; /* Zero the bottom bits. */ + nburn = c->spec->encrypt (&c->context.c, ktop, ktop); + burn = nburn > burn ? nburn : burn; + /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */ + cipher_block_cpy (stretch, ktop, OCB_BLOCK_LEN); + cipher_block_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8); + /* Offset_0 = Stretch[1+bottom..128+bottom] + (We use the IV field to store the offset) */ + bit_copy (c->u_iv.iv, stretch, bottom); + c->marks.iv = 1; + + /* Checksum_0 = zeros(128) + (We use the CTR field to store the checksum) */ + memset (c->u_ctr.ctr, 0, OCB_BLOCK_LEN); + + /* Clear AAD buffer. */ + memset (c->u_mode.ocb.aad_offset, 0, OCB_BLOCK_LEN); + memset (c->u_mode.ocb.aad_sum, 0, OCB_BLOCK_LEN); + + /* Setup other values. */ + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + c->marks.tag = 0; + c->marks.finalize = 0; + c->u_mode.ocb.data_nblocks = 0; + c->u_mode.ocb.aad_nblocks = 0; + c->u_mode.ocb.aad_nleftover = 0; + c->u_mode.ocb.data_finalized = 0; + c->u_mode.ocb.aad_finalized = 0; + + /* log_printhex ("L_* ", c->u_mode.ocb.L_star, OCB_BLOCK_LEN); */ + /* log_printhex ("L_$ ", c->u_mode.ocb.L_dollar, OCB_BLOCK_LEN); */ + /* log_printhex ("L_0 ", c->u_mode.ocb.L[0], OCB_BLOCK_LEN); */ + /* log_printhex ("L_1 ", c->u_mode.ocb.L[1], OCB_BLOCK_LEN); */ + /* log_debug ( "bottom : %u (decimal)\n", bottom); */ + /* log_printhex ("Ktop ", ktop, OCB_BLOCK_LEN); */ + /* log_printhex ("Stretch ", stretch, sizeof stretch); */ + /* log_printhex ("Offset_0 ", c->u_iv.iv, OCB_BLOCK_LEN); */ + + /* Cleanup */ + wipememory (ktop, sizeof ktop); + wipememory (stretch, sizeof stretch); + if (burn > 0) + _gcry_burn_stack (burn + 4*sizeof(void*)); + + return 0; +} + + +/* Process additional authentication data. This implementation allows + to add additional authentication data at any time before the final + gcry_cipher_gettag. */ +gcry_err_code_t +_gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + const size_t table_maxblks = 1 << OCB_L_TABLE_SIZE; + const u32 table_size_mask = ((1 << OCB_L_TABLE_SIZE) - 1); + unsigned char l_tmp[OCB_BLOCK_LEN]; + unsigned int burn = 0; + unsigned int nburn; + size_t n; + + /* Check that a nonce and thus a key has been set and that we have + not yet computed the tag. We also return an error if the aad has + been finalized (i.e. a short block has been processed). */ + if (!c->marks.iv || c->marks.tag || c->u_mode.ocb.aad_finalized) + return GPG_ERR_INV_STATE; + + /* Check correct usage and arguments. */ + if (c->spec->blocksize != OCB_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + + /* Process remaining data from the last call first. */ + if (c->u_mode.ocb.aad_nleftover) + { + n = abuflen; + if (n > OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover) + n = OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover; + + buf_cpy (&c->u_mode.ocb.aad_leftover[c->u_mode.ocb.aad_nleftover], + abuf, n); + c->u_mode.ocb.aad_nleftover += n; + abuf += n; + abuflen -= n; + + if (c->u_mode.ocb.aad_nleftover == OCB_BLOCK_LEN) + { + c->u_mode.ocb.aad_nblocks++; + + if ((c->u_mode.ocb.aad_nblocks % table_maxblks) == 0) + { + /* Table overflow, L needs to be generated. */ + ocb_get_L_big(c, c->u_mode.ocb.aad_nblocks + 1, l_tmp); + } + else + { + cipher_block_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks), + OCB_BLOCK_LEN); + } + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ + cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + c->u_mode.ocb.aad_nleftover = 0; + } + } + + if (!abuflen) + { + if (burn > 0) + _gcry_burn_stack (burn + 4*sizeof(void*)); + + return 0; + } + + /* Full blocks handling. */ + while (abuflen >= OCB_BLOCK_LEN) + { + size_t nblks = abuflen / OCB_BLOCK_LEN; + size_t nmaxblks; + + /* Check how many blocks to process till table overflow. */ + nmaxblks = (c->u_mode.ocb.aad_nblocks + 1) % table_maxblks; + nmaxblks = (table_maxblks - nmaxblks) % table_maxblks; + + if (nmaxblks == 0) + { + /* Table overflow, generate L and process one block. */ + c->u_mode.ocb.aad_nblocks++; + ocb_get_L_big(c, c->u_mode.ocb.aad_nblocks, l_tmp); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ + cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, + OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + abuf += OCB_BLOCK_LEN; + abuflen -= OCB_BLOCK_LEN; + nblks--; + + /* With overflow handled, retry loop again. Next overflow will + * happen after 65535 blocks. */ + continue; + } + + nblks = nblks < nmaxblks ? nblks : nmaxblks; + + /* Use a bulk method if available. */ + if (nblks && c->bulk.ocb_auth) + { + size_t nleft; + size_t ndone; + + nleft = c->bulk.ocb_auth (c, abuf, nblks); + ndone = nblks - nleft; + + abuf += ndone * OCB_BLOCK_LEN; + abuflen -= ndone * OCB_BLOCK_LEN; + nblks = nleft; + } + + /* Hash all full blocks. */ + while (nblks) + { + c->u_mode.ocb.aad_nblocks++; + + gcry_assert(c->u_mode.ocb.aad_nblocks & table_size_mask); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, + ocb_get_l (c, c->u_mode.ocb.aad_nblocks), + OCB_BLOCK_LEN); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ + cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, + OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + abuf += OCB_BLOCK_LEN; + abuflen -= OCB_BLOCK_LEN; + nblks--; + } + } + + /* Store away the remaining data. */ + if (abuflen) + { + n = abuflen; + if (n > OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover) + n = OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover; + + buf_cpy (&c->u_mode.ocb.aad_leftover[c->u_mode.ocb.aad_nleftover], + abuf, n); + c->u_mode.ocb.aad_nleftover += n; + abuf += n; + abuflen -= n; + } + + gcry_assert (!abuflen); + + if (burn > 0) + _gcry_burn_stack (burn + 4*sizeof(void*)); + + return 0; +} + + +/* Hash final partial AAD block. */ +static void +ocb_aad_finalize (gcry_cipher_hd_t c) +{ + unsigned char l_tmp[OCB_BLOCK_LEN]; + unsigned int burn = 0; + unsigned int nburn; + + /* Check that a nonce and thus a key has been set and that we have + not yet computed the tag. We also skip this if the aad has been + finalized. */ + if (!c->marks.iv || c->marks.tag || c->u_mode.ocb.aad_finalized) + return; + if (c->spec->blocksize != OCB_BLOCK_LEN) + return; /* Ooops. */ + + /* Hash final partial block if any. */ + if (c->u_mode.ocb.aad_nleftover) + { + /* Offset_* = Offset_m xor L_* */ + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, + c->u_mode.ocb.L_star, OCB_BLOCK_LEN); + /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */ + buf_cpy (l_tmp, c->u_mode.ocb.aad_leftover, c->u_mode.ocb.aad_nleftover); + memset (l_tmp + c->u_mode.ocb.aad_nleftover, 0, + OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover); + l_tmp[c->u_mode.ocb.aad_nleftover] = 0x80; + cipher_block_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN); + /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */ + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + c->u_mode.ocb.aad_nleftover = 0; + } + + /* Mark AAD as finalized so that gcry_cipher_ocb_authenticate can + * return an erro when called again. */ + c->u_mode.ocb.aad_finalized = 1; + + if (burn > 0) + _gcry_burn_stack (burn + 4*sizeof(void*)); +} + + + +/* Checksumming for encrypt and decrypt. */ +static void +ocb_checksum (unsigned char *chksum, const unsigned char *plainbuf, + size_t nblks) +{ + while (nblks > 0) + { + /* Checksum_i = Checksum_{i-1} xor P_i */ + cipher_block_xor_1(chksum, plainbuf, OCB_BLOCK_LEN); + + plainbuf += OCB_BLOCK_LEN; + nblks--; + } +} + + +/* Common code for encrypt and decrypt. */ +static gcry_err_code_t +ocb_crypt (gcry_cipher_hd_t c, int encrypt, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + const size_t table_maxblks = 1 << OCB_L_TABLE_SIZE; + const u32 table_size_mask = ((1 << OCB_L_TABLE_SIZE) - 1); + unsigned char l_tmp[OCB_BLOCK_LEN]; + unsigned int burn = 0; + unsigned int nburn; + gcry_cipher_encrypt_t crypt_fn = + encrypt ? c->spec->encrypt : c->spec->decrypt; + + /* Check that a nonce and thus a key has been set and that we are + not yet in end of data state. */ + if (!c->marks.iv || c->u_mode.ocb.data_finalized) + return GPG_ERR_INV_STATE; + + /* Check correct usage and arguments. */ + if (c->spec->blocksize != OCB_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->marks.finalize) + ; /* Allow arbitarty length. */ + else if ((inbuflen % OCB_BLOCK_LEN)) + return GPG_ERR_INV_LENGTH; /* We support only full blocks for now. */ + + /* Full blocks handling. */ + while (inbuflen >= OCB_BLOCK_LEN) + { + size_t nblks = inbuflen / OCB_BLOCK_LEN; + size_t nmaxblks; + + /* Check how many blocks to process till table overflow. */ + nmaxblks = (c->u_mode.ocb.data_nblocks + 1) % table_maxblks; + nmaxblks = (table_maxblks - nmaxblks) % table_maxblks; + + if (nmaxblks == 0) + { + /* Table overflow, generate L and process one block. */ + c->u_mode.ocb.data_nblocks++; + ocb_get_L_big(c, c->u_mode.ocb.data_nblocks, l_tmp); + + if (encrypt) + { + /* Checksum_i = Checksum_{i-1} xor P_i */ + ocb_checksum (c->u_ctr.ctr, inbuf, 1); + } + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + cipher_block_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN); + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); + + if (!encrypt) + { + /* Checksum_i = Checksum_{i-1} xor P_i */ + ocb_checksum (c->u_ctr.ctr, outbuf, 1); + } + + inbuf += OCB_BLOCK_LEN; + inbuflen -= OCB_BLOCK_LEN; + outbuf += OCB_BLOCK_LEN; + outbuflen =- OCB_BLOCK_LEN; + nblks--; + + /* With overflow handled, retry loop again. Next overflow will + * happen after 65535 blocks. */ + continue; + } + + nblks = nblks < nmaxblks ? nblks : nmaxblks; + + /* Since checksum xoring is done before/after encryption/decryption, + process input in 24KiB chunks to keep data loaded in L1 cache for + checksumming. */ + if (nblks > 24 * 1024 / OCB_BLOCK_LEN) + nblks = 24 * 1024 / OCB_BLOCK_LEN; + + /* Use a bulk method if available. */ + if (nblks && c->bulk.ocb_crypt) + { + size_t nleft; + size_t ndone; + + nleft = c->bulk.ocb_crypt (c, outbuf, inbuf, nblks, encrypt); + ndone = nblks - nleft; + + inbuf += ndone * OCB_BLOCK_LEN; + outbuf += ndone * OCB_BLOCK_LEN; + inbuflen -= ndone * OCB_BLOCK_LEN; + outbuflen -= ndone * OCB_BLOCK_LEN; + nblks = nleft; + } + + if (nblks) + { + size_t nblks_chksum = nblks; + + if (encrypt) + { + /* Checksum_i = Checksum_{i-1} xor P_i */ + ocb_checksum (c->u_ctr.ctr, inbuf, nblks_chksum); + } + + /* Encrypt all full blocks. */ + while (nblks) + { + c->u_mode.ocb.data_nblocks++; + + gcry_assert(c->u_mode.ocb.data_nblocks & table_size_mask); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ + cipher_block_xor_1 (c->u_iv.iv, + ocb_get_l (c, c->u_mode.ocb.data_nblocks), + OCB_BLOCK_LEN); + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ + cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; + cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); + + inbuf += OCB_BLOCK_LEN; + inbuflen -= OCB_BLOCK_LEN; + outbuf += OCB_BLOCK_LEN; + outbuflen =- OCB_BLOCK_LEN; + nblks--; + } + + if (!encrypt) + { + /* Checksum_i = Checksum_{i-1} xor P_i */ + ocb_checksum (c->u_ctr.ctr, + outbuf - nblks_chksum * OCB_BLOCK_LEN, + nblks_chksum); + } + } + } + + /* Encrypt final partial block. Note that we expect INBUFLEN to be + shorter than OCB_BLOCK_LEN (see above). */ + if (inbuflen) + { + unsigned char pad[OCB_BLOCK_LEN]; + + /* Offset_* = Offset_m xor L_* */ + cipher_block_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN); + /* Pad = ENCIPHER(K, Offset_*) */ + nburn = c->spec->encrypt (&c->context.c, pad, c->u_iv.iv); + burn = nburn > burn ? nburn : burn; + + if (encrypt) + { + /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ + /* Note that INBUFLEN is less than OCB_BLOCK_LEN. */ + buf_cpy (l_tmp, inbuf, inbuflen); + memset (l_tmp + inbuflen, 0, OCB_BLOCK_LEN - inbuflen); + l_tmp[inbuflen] = 0x80; + cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); + /* C_* = P_* xor Pad[1..bitlen(P_*)] */ + buf_xor (outbuf, inbuf, pad, inbuflen); + } + else + { + /* P_* = C_* xor Pad[1..bitlen(C_*)] */ + /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ + cipher_block_cpy (l_tmp, pad, OCB_BLOCK_LEN); + buf_cpy (l_tmp, inbuf, inbuflen); + cipher_block_xor_1 (l_tmp, pad, OCB_BLOCK_LEN); + l_tmp[inbuflen] = 0x80; + buf_cpy (outbuf, l_tmp, inbuflen); + + cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); + } + } + + /* Compute the tag if the finalize flag has been set. */ + if (c->marks.finalize) + { + /* Tag = ENCIPHER(K, Checksum xor Offset xor L_$) xor HASH(K,A) */ + cipher_block_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv, + OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar, + OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, + c->u_mode.ocb.tag, c->u_mode.ocb.tag); + burn = nburn > burn ? nburn : burn; + + c->u_mode.ocb.data_finalized = 1; + /* Note that the the final part of the tag computation is done + by _gcry_cipher_ocb_get_tag. */ + } + + if (burn > 0) + _gcry_burn_stack (burn + 4*sizeof(void*)); + + return 0; +} + + +/* Encrypt (INBUF,INBUFLEN) in OCB mode to OUTBUF. OUTBUFLEN gives + the allocated size of OUTBUF. This function accepts only multiples + of a full block unless gcry_cipher_final has been called in which + case the next block may have any length. */ +gcry_err_code_t +_gcry_cipher_ocb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) + +{ + return ocb_crypt (c, 1, outbuf, outbuflen, inbuf, inbuflen); +} + + +/* Decrypt (INBUF,INBUFLEN) in OCB mode to OUTBUF. OUTBUFLEN gives + the allocated size of OUTBUF. This function accepts only multiples + of a full block unless gcry_cipher_final has been called in which + case the next block may have any length. */ +gcry_err_code_t +_gcry_cipher_ocb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + return ocb_crypt (c, 0, outbuf, outbuflen, inbuf, inbuflen); +} + + +/* Compute the tag. The last data operation has already done some + part of it. To allow adding AAD even after having done all data, + we finish the tag computation only here. */ +static void +compute_tag_if_needed (gcry_cipher_hd_t c) +{ + if (!c->marks.tag) + { + ocb_aad_finalize (c); + cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, + OCB_BLOCK_LEN); + c->marks.tag = 1; + } +} + + +/* Copy the already computed tag to OUTTAG. OUTTAGSIZE is the + allocated size of OUTTAG; the function returns an error if that is + too short to hold the tag. */ +gcry_err_code_t +_gcry_cipher_ocb_get_tag (gcry_cipher_hd_t c, + unsigned char *outtag, size_t outtagsize) +{ + if (c->u_mode.ocb.taglen > outtagsize) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ocb.data_finalized) + return GPG_ERR_INV_STATE; /* Data has not yet been finalized. */ + + compute_tag_if_needed (c); + + memcpy (outtag, c->u_mode.ocb.tag, c->u_mode.ocb.taglen); + + return 0; +} + + +/* Check that the tag (INTAG,TAGLEN) matches the computed tag for the + handle C. */ +gcry_err_code_t +_gcry_cipher_ocb_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + size_t n; + + if (!c->u_mode.ocb.data_finalized) + return GPG_ERR_INV_STATE; /* Data has not yet been finalized. */ + + compute_tag_if_needed (c); + + n = c->u_mode.ocb.taglen; + if (taglen < n) + n = taglen; + + if (!buf_eq_const (intag, c->u_mode.ocb.tag, n) + || c->u_mode.ocb.taglen != taglen) + return GPG_ERR_CHECKSUM; + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-ofb.c b/comm/third_party/libgcrypt/cipher/cipher-ofb.c new file mode 100644 index 0000000000..09db397e65 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-ofb.c @@ -0,0 +1,108 @@ +/* cipher-ofb.c - Generic OFB mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + unsigned char *ivp; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize_shift = _gcry_blocksize_shift(c); + size_t blocksize = 1 << blocksize_shift; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV */ + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor(outbuf, ivp, inbuf, inbuflen); + c->unused -= inbuflen; + return 0; + } + + burn = 0; + + if( c->unused ) + { + inbuflen -= c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor(outbuf, ivp, inbuf, c->unused); + outbuf += c->unused; + inbuf += c->unused; + c->unused = 0; + } + + /* Now we can process complete blocks. */ + if (c->bulk.ofb_enc) + { + size_t nblocks = inbuflen >> blocksize_shift; + c->bulk.ofb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks << blocksize_shift; + inbuf += nblocks << blocksize_shift; + inbuflen -= nblocks << blocksize_shift; + } + else + { + while ( inbuflen >= blocksize ) + { + /* Encrypt the IV (and save the current one). */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + cipher_block_xor(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + } + + if ( inbuflen ) + { /* process the remaining bytes */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + c->unused = blocksize; + c->unused -= inbuflen; + buf_xor(outbuf, c->u_iv.iv, inbuf, inbuflen); + outbuf += inbuflen; + inbuf += inbuflen; + inbuflen = 0; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-poly1305.c b/comm/third_party/libgcrypt/cipher/cipher-poly1305.c new file mode 100644 index 0000000000..bb475236b8 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-poly1305.c @@ -0,0 +1,375 @@ +/* cipher-poly1305.c - Poly1305 based AEAD cipher mode, RFC-8439 + * Copyright (C) 2014 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" +#include "./poly1305-internal.h" + + +static inline int +poly1305_bytecounter_add (u32 ctr[2], size_t add) +{ + int overflow = 0; + + if (sizeof(add) > sizeof(u32)) + { + u32 high_add = ((add >> 31) >> 1) & 0xffffffff; + ctr[1] += high_add; + if (ctr[1] < high_add) + overflow = 1; + } + + ctr[0] += add; + if (ctr[0] >= add) + return overflow; + + ctr[1] += 1; + return (ctr[1] < 1) || overflow; +} + + +static void +poly1305_fill_bytecounts (gcry_cipher_hd_t c) +{ + u32 lenbuf[4]; + + lenbuf[0] = le_bswap32(c->u_mode.poly1305.aadcount[0]); + lenbuf[1] = le_bswap32(c->u_mode.poly1305.aadcount[1]); + lenbuf[2] = le_bswap32(c->u_mode.poly1305.datacount[0]); + lenbuf[3] = le_bswap32(c->u_mode.poly1305.datacount[1]); + _gcry_poly1305_update (&c->u_mode.poly1305.ctx, (byte*)lenbuf, + sizeof(lenbuf)); + + wipememory(lenbuf, sizeof(lenbuf)); +} + + +static void +poly1305_do_padding (gcry_cipher_hd_t c, u32 ctr[2]) +{ + static const byte zero_padding_buf[15] = {}; + u32 padding_count; + + /* Padding to 16 byte boundary. */ + if (ctr[0] % 16 > 0) + { + padding_count = 16 - ctr[0] % 16; + + _gcry_poly1305_update (&c->u_mode.poly1305.ctx, zero_padding_buf, + padding_count); + } +} + + +static void +poly1305_aad_finish (gcry_cipher_hd_t c) +{ + /* After AAD, feed padding bytes so we get 16 byte alignment. */ + poly1305_do_padding (c, c->u_mode.poly1305.aadcount); + + /* Start of encryption marks end of AAD stream. */ + c->u_mode.poly1305.aad_finalized = 1; + + c->u_mode.poly1305.datacount[0] = 0; + c->u_mode.poly1305.datacount[1] = 0; +} + + +static gcry_err_code_t +poly1305_set_zeroiv (gcry_cipher_hd_t c) +{ + byte zero[8] = { 0, }; + + return _gcry_cipher_poly1305_setiv (c, zero, sizeof(zero)); +} + + +gcry_err_code_t +_gcry_cipher_poly1305_authenticate (gcry_cipher_hd_t c, + const byte * aadbuf, size_t aadbuflen) +{ + if (c->u_mode.poly1305.bytecount_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->u_mode.poly1305.aad_finalized) + return GPG_ERR_INV_STATE; + if (c->marks.tag) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + poly1305_set_zeroiv(c); + + if (poly1305_bytecounter_add(c->u_mode.poly1305.aadcount, aadbuflen)) + { + c->u_mode.poly1305.bytecount_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + _gcry_poly1305_update (&c->u_mode.poly1305.ctx, aadbuf, aadbuflen); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_poly1305_encrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t err; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->marks.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.poly1305.bytecount_over_limits) + return GPG_ERR_INV_LENGTH; + + if (!c->marks.iv) + { + err = poly1305_set_zeroiv(c); + if (err) + return err; + } + + if (!c->u_mode.poly1305.aad_finalized) + poly1305_aad_finish(c); + + if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen)) + { + c->u_mode.poly1305.bytecount_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + if (LIKELY(inbuflen > 0) && LIKELY(c->spec->algo == GCRY_CIPHER_CHACHA20)) + { + return _gcry_chacha20_poly1305_encrypt (c, outbuf, inbuf, inbuflen); + } + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Since checksumming is done after encryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for checksumming. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + c->spec->stencrypt(&c->context.c, outbuf, (byte*)inbuf, currlen); + + _gcry_poly1305_update (&c->u_mode.poly1305.ctx, outbuf, currlen); + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_poly1305_decrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t err; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->marks.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.poly1305.bytecount_over_limits) + return GPG_ERR_INV_LENGTH; + + if (!c->marks.iv) + { + err = poly1305_set_zeroiv(c); + if (err) + return err; + } + + if (!c->u_mode.poly1305.aad_finalized) + poly1305_aad_finish(c); + + if (poly1305_bytecounter_add(c->u_mode.poly1305.datacount, inbuflen)) + { + c->u_mode.poly1305.bytecount_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + if (LIKELY(inbuflen > 0) && LIKELY(c->spec->algo == GCRY_CIPHER_CHACHA20)) + { + return _gcry_chacha20_poly1305_decrypt (c, outbuf, inbuf, inbuflen); + } + + while (inbuflen) + { + size_t currlen = inbuflen; + + /* Since checksumming is done before decryption, process input in 24KiB + * chunks to keep data loaded in L1 cache for decryption. */ + if (currlen > 24 * 1024) + currlen = 24 * 1024; + + _gcry_poly1305_update (&c->u_mode.poly1305.ctx, inbuf, currlen); + + c->spec->stdecrypt(&c->context.c, outbuf, (byte*)inbuf, currlen); + + outbuf += currlen; + inbuf += currlen; + outbuflen -= currlen; + inbuflen -= currlen; + } + + return 0; +} + + +static gcry_err_code_t +_gcry_cipher_poly1305_tag (gcry_cipher_hd_t c, + byte * outbuf, size_t outbuflen, int check) +{ + gcry_err_code_t err; + + if (outbuflen < POLY1305_TAGLEN) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->u_mode.poly1305.bytecount_over_limits) + return GPG_ERR_INV_LENGTH; + + if (!c->marks.iv) + { + err = poly1305_set_zeroiv(c); + if (err) + return err; + } + + if (!c->u_mode.poly1305.aad_finalized) + poly1305_aad_finish(c); + + if (!c->marks.tag) + { + /* After data, feed padding bytes so we get 16 byte alignment. */ + poly1305_do_padding (c, c->u_mode.poly1305.datacount); + + /* Write byte counts to poly1305. */ + poly1305_fill_bytecounts(c); + + _gcry_poly1305_finish(&c->u_mode.poly1305.ctx, c->u_iv.iv); + + c->marks.tag = 1; + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, POLY1305_TAGLEN); + } + else + { + /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF + * and thus we need to compare its length first. */ + if (outbuflen != POLY1305_TAGLEN + || !buf_eq_const (outbuf, c->u_iv.iv, POLY1305_TAGLEN)) + return GPG_ERR_CHECKSUM; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_poly1305_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_poly1305_tag (c, outtag, taglen, 0); +} + +gcry_err_code_t +_gcry_cipher_poly1305_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_poly1305_tag (c, (unsigned char *) intag, taglen, 1); +} + + +void +_gcry_cipher_poly1305_setkey (gcry_cipher_hd_t c) +{ + c->u_mode.poly1305.aadcount[0] = 0; + c->u_mode.poly1305.aadcount[1] = 0; + + c->u_mode.poly1305.datacount[0] = 0; + c->u_mode.poly1305.datacount[1] = 0; + + c->u_mode.poly1305.bytecount_over_limits = 0; + c->u_mode.poly1305.aad_finalized = 0; + c->marks.tag = 0; + c->marks.iv = 0; +} + + +gcry_err_code_t +_gcry_cipher_poly1305_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) +{ + byte tmpbuf[64]; /* size of ChaCha20 block */ + gcry_err_code_t err; + + /* IV must be 96-bits */ + if (!iv && ivlen != (96 / 8)) + return GPG_ERR_INV_ARG; + + memset(&c->u_mode.poly1305.ctx, 0, sizeof(c->u_mode.poly1305.ctx)); + + c->u_mode.poly1305.aadcount[0] = 0; + c->u_mode.poly1305.aadcount[1] = 0; + + c->u_mode.poly1305.datacount[0] = 0; + c->u_mode.poly1305.datacount[1] = 0; + + c->u_mode.poly1305.bytecount_over_limits = 0; + c->u_mode.poly1305.aad_finalized = 0; + c->marks.tag = 0; + c->marks.iv = 0; + + /* Set up IV for stream cipher. */ + c->spec->setiv (&c->context.c, iv, ivlen); + + /* Get the first block from ChaCha20. */ + memset(tmpbuf, 0, sizeof(tmpbuf)); + c->spec->stencrypt(&c->context.c, tmpbuf, tmpbuf, sizeof(tmpbuf)); + + /* Use the first 32-bytes as Poly1305 key. */ + err = _gcry_poly1305_init (&c->u_mode.poly1305.ctx, tmpbuf, POLY1305_KEYLEN); + + wipememory(tmpbuf, sizeof(tmpbuf)); + + if (err) + return err; + + c->marks.iv = 1; + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-selftest.c b/comm/third_party/libgcrypt/cipher/cipher-selftest.c new file mode 100644 index 0000000000..d7f38a4261 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-selftest.c @@ -0,0 +1,512 @@ +/* cipher-selftest.c - Helper functions for bulk encryption selftests. + * Copyright (C) 2013,2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#ifdef HAVE_SYSLOG +# include +#endif /*HAVE_SYSLOG*/ + +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "cipher-selftest.h" +#include "cipher-internal.h" + +#ifdef HAVE_STDINT_H +# include /* uintptr_t */ +#elif defined(HAVE_INTTYPES_H) +# include +#else +/* In this case, uintptr_t is provided by config.h. */ +#endif + +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + + +/* Return an allocated buffers of size CONTEXT_SIZE with an alignment + of 16. The caller must free that buffer using the address returned + at R_MEM. Returns NULL and sets ERRNO on failure. */ +void * +_gcry_cipher_selftest_alloc_ctx (const int context_size, unsigned char **r_mem) +{ + int offs; + unsigned int ctx_aligned_size, memsize; + + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + 16; + + *r_mem = xtrycalloc (1, memsize); + if (!*r_mem) + return NULL; + + offs = (16 - ((uintptr_t)*r_mem & 15)) & 15; + return (void*)(*r_mem + offs); +} + + +/* Run the self-tests for -CBC-, tests bulk CBC + decryption. Returns NULL on success. */ +const char * +_gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func, + gcry_cipher_encrypt_t encrypt_one, + const int nblocks, const int blocksize, + const int context_size) +{ + cipher_bulk_ops_t bulk_ops = { 0, }; + int i, offs; + unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; + unsigned int ctx_aligned_size, memsize; + + static const unsigned char key[16] ATTR_ALIGNED_16 = { + 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22 + }; + + /* Allocate buffers, align first two elements to 16 bytes and latter to + block size. */ + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16; + + mem = xtrycalloc (1, memsize); + if (!mem) + return "failed to allocate memory"; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + ctx = (void*)(mem + offs); + iv = ctx + ctx_aligned_size; + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + + /* Initialize ctx */ + if (setkey_func (ctx, key, sizeof(key), &bulk_ops) != GPG_ERR_NO_ERROR) + { + xfree(mem); + return "setkey failed"; + } + + /* Test single block code path */ + memset (iv, 0x4e, blocksize); + memset (iv2, 0x4e, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CBC manually. */ + buf_xor (ciphertext, iv, plaintext, blocksize); + encrypt_one (ctx, ciphertext, ciphertext); + memcpy (iv, ciphertext, blocksize); + + /* CBC decrypt. */ + bulk_ops.cbc_dec (ctx, iv2, plaintext2, ciphertext, 1); + if (memcmp (plaintext2, plaintext, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (plaintext mismatch)", cipher, + blocksize * 8); +#else + (void)cipher; /* Not used. */ +#endif + return "selftest for CBC failed - see syslog for details"; + } + + if (memcmp (iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + + /* Test parallelized code paths */ + memset (iv, 0x5f, blocksize); + memset (iv2, 0x5f, blocksize); + + for (i = 0; i < nblocks * blocksize; i++) + plaintext[i] = i; + + /* Create CBC ciphertext manually. */ + for (i = 0; i < nblocks * blocksize; i+=blocksize) + { + buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize); + encrypt_one (ctx, &ciphertext[i], &ciphertext[i]); + memcpy (iv, &ciphertext[i], blocksize); + } + + /* Decrypt using bulk CBC and compare result. */ + bulk_ops.cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks); + + if (memcmp (plaintext2, plaintext, nblocks * blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (plaintext mismatch, parallel path)", + cipher, blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + if (memcmp (iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (IV mismatch, parallel path)", + cipher, blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + + xfree (mem); + return NULL; +} + +/* Run the self-tests for -CFB-, tests bulk CFB + decryption. Returns NULL on success. */ +const char * +_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func, + gcry_cipher_encrypt_t encrypt_one, + const int nblocks, const int blocksize, + const int context_size) +{ + cipher_bulk_ops_t bulk_ops = { 0, }; + int i, offs; + unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; + unsigned int ctx_aligned_size, memsize; + + static const unsigned char key[16] ATTR_ALIGNED_16 = { + 0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33 + }; + + /* Allocate buffers, align first two elements to 16 bytes and latter to + block size. */ + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16; + + mem = xtrycalloc (1, memsize); + if (!mem) + return "failed to allocate memory"; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + ctx = (void*)(mem + offs); + iv = ctx + ctx_aligned_size; + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + + /* Initialize ctx */ + if (setkey_func (ctx, key, sizeof(key), &bulk_ops) != GPG_ERR_NO_ERROR) + { + xfree(mem); + return "setkey failed"; + } + + /* Test single block code path */ + memset(iv, 0xd3, blocksize); + memset(iv2, 0xd3, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CFB manually. */ + encrypt_one (ctx, ciphertext, iv); + buf_xor_2dst (iv, ciphertext, plaintext, blocksize); + + /* CFB decrypt. */ + bulk_ops.cfb_dec (ctx, iv2, plaintext2, ciphertext, 1); + if (memcmp(plaintext2, plaintext, blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (plaintext mismatch)", cipher, + blocksize * 8); +#else + (void)cipher; /* Not used. */ +#endif + return "selftest for CFB failed - see syslog for details"; + } + + if (memcmp(iv2, iv, blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + + /* Test parallelized code paths */ + memset(iv, 0xe6, blocksize); + memset(iv2, 0xe6, blocksize); + + for (i = 0; i < nblocks * blocksize; i++) + plaintext[i] = i; + + /* Create CFB ciphertext manually. */ + for (i = 0; i < nblocks * blocksize; i+=blocksize) + { + encrypt_one (ctx, &ciphertext[i], iv); + buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize); + } + + /* Decrypt using bulk CBC and compare result. */ + bulk_ops.cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks); + + if (memcmp(plaintext2, plaintext, nblocks * blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (plaintext mismatch, parallel path)", + cipher, blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + if (memcmp(iv2, iv, blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher, + blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + + xfree(mem); + return NULL; +} + +/* Run the self-tests for -CTR-, tests IV increment + of bulk CTR encryption. Returns NULL on success. */ +const char * +_gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func, + gcry_cipher_encrypt_t encrypt_one, + const int nblocks, const int blocksize, + const int context_size) +{ + cipher_bulk_ops_t bulk_ops = { 0, }; + int i, j, offs, diff; + unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *ciphertext2, + *iv, *iv2, *mem; + unsigned int ctx_aligned_size, memsize; + + static const unsigned char key[16] ATTR_ALIGNED_16 = { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 + }; + + /* Allocate buffers, align first two elements to 16 bytes and latter to + block size. */ + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16; + + mem = xtrycalloc (1, memsize); + if (!mem) + return "failed to allocate memory"; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + ctx = (void*)(mem + offs); + iv = ctx + ctx_aligned_size; + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + ciphertext2 = ciphertext + nblocks * blocksize; + + /* Initialize ctx */ + if (setkey_func (ctx, key, sizeof(key), &bulk_ops) != GPG_ERR_NO_ERROR) + { + xfree(mem); + return "setkey failed"; + } + + /* Test single block code path */ + memset (iv, 0xff, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CTR manually. */ + encrypt_one (ctx, ciphertext, iv); + for (i = 0; i < blocksize; i++) + ciphertext[i] ^= plaintext[i]; + for (i = blocksize; i > 0; i--) + { + iv[i-1]++; + if (iv[i-1]) + break; + } + + memset (iv2, 0xff, blocksize); + bulk_ops.ctr_enc (ctx, iv2, plaintext2, ciphertext, 1); + + if (memcmp (plaintext2, plaintext, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (plaintext mismatch)", cipher, + blocksize * 8); +#else + (void)cipher; /* Not used. */ +#endif + return "selftest for CTR failed - see syslog for details"; + } + + if (memcmp (iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (IV mismatch)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + + /* Test bulk encryption with typical IV. */ + memset(iv, 0x57, blocksize-4); + iv[blocksize-1] = 1; + iv[blocksize-2] = 0; + iv[blocksize-3] = 0; + iv[blocksize-4] = 0; + memset(iv2, 0x57, blocksize-4); + iv2[blocksize-1] = 1; + iv2[blocksize-2] = 0; + iv2[blocksize-3] = 0; + iv2[blocksize-4] = 0; + + for (i = 0; i < blocksize * nblocks; i++) + plaintext2[i] = plaintext[i] = i; + + /* Create CTR ciphertext manually. */ + for (i = 0; i < blocksize * nblocks; i+=blocksize) + { + encrypt_one (ctx, &ciphertext[i], iv); + for (j = 0; j < blocksize; j++) + ciphertext[i+j] ^= plaintext[i+j]; + for (j = blocksize; j > 0; j--) + { + iv[j-1]++; + if (iv[j-1]) + break; + } + } + + bulk_ops.ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks); + + if (memcmp (ciphertext2, ciphertext, blocksize * nblocks)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (ciphertext mismatch, bulk)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + if (memcmp(iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (IV mismatch, bulk)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + + /* Test parallelized code paths (check counter overflow handling) */ + for (diff = 0; diff < nblocks; diff++) { + memset(iv, 0xff, blocksize); + iv[blocksize-1] -= diff; + iv[0] = iv[1] = 0; + iv[2] = 0x07; + + for (i = 0; i < blocksize * nblocks; i++) + plaintext[i] = i; + + /* Create CTR ciphertext manually. */ + for (i = 0; i < blocksize * nblocks; i+=blocksize) + { + encrypt_one (ctx, &ciphertext[i], iv); + for (j = 0; j < blocksize; j++) + ciphertext[i+j] ^= plaintext[i+j]; + for (j = blocksize; j > 0; j--) + { + iv[j-1]++; + if (iv[j-1]) + break; + } + } + + /* Decrypt using bulk CTR and compare result. */ + memset(iv2, 0xff, blocksize); + iv2[blocksize-1] -= diff; + iv2[0] = iv2[1] = 0; + iv2[2] = 0x07; + + bulk_ops.ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks); + + if (memcmp (plaintext2, plaintext, blocksize * nblocks)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (plaintext mismatch, diff: %d)", cipher, + blocksize * 8, diff); +#endif + return "selftest for CTR failed - see syslog for details"; + } + if (memcmp(iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (IV mismatch, diff: %d)", cipher, + blocksize * 8, diff); +#endif + return "selftest for CTR failed - see syslog for details"; + } + } + + xfree (mem); + return NULL; +} diff --git a/comm/third_party/libgcrypt/cipher/cipher-selftest.h b/comm/third_party/libgcrypt/cipher/cipher-selftest.h new file mode 100644 index 0000000000..c3090ad122 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-selftest.h @@ -0,0 +1,69 @@ +/* cipher-selftest.h - Helper functions for bulk encryption selftests. + * Copyright (C) 2013,2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef G10_SELFTEST_HELP_H +#define G10_SELFTEST_HELP_H + +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" + +typedef void (*gcry_cipher_bulk_cbc_dec_t)(void *context, unsigned char *iv, + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks); + +typedef void (*gcry_cipher_bulk_cfb_dec_t)(void *context, unsigned char *iv, + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks); + +typedef void (*gcry_cipher_bulk_ctr_enc_t)(void *context, unsigned char *iv, + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks); + +/* Helper function to allocate an aligned context for selftests. */ +void *_gcry_cipher_selftest_alloc_ctx (const int context_size, + unsigned char **r_mem); + + +/* Helper function for bulk CBC decryption selftest */ +const char * +_gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey, + gcry_cipher_encrypt_t encrypt_one, + const int nblocks, const int blocksize, + const int context_size); + +/* Helper function for bulk CFB decryption selftest */ +const char * +_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey, + gcry_cipher_encrypt_t encrypt_one, + const int nblocks, const int blocksize, + const int context_size); + +/* Helper function for bulk CTR encryption selftest */ +const char * +_gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey, + gcry_cipher_encrypt_t encrypt_one, + const int nblocks, const int blocksize, + const int context_size); + +#endif /*G10_SELFTEST_HELP_H*/ diff --git a/comm/third_party/libgcrypt/cipher/cipher-xts.c b/comm/third_party/libgcrypt/cipher/cipher-xts.c new file mode 100644 index 0000000000..0522a271a1 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher-xts.c @@ -0,0 +1,189 @@ +/* cipher-xts.c - XTS mode implementation + * Copyright (C) 2017 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +static inline void xts_gfmul_byA (unsigned char *out, const unsigned char *in) +{ + u64 hi = buf_get_le64 (in + 8); + u64 lo = buf_get_le64 (in + 0); + u64 carry = -(hi >> 63) & 0x87; + + hi = (hi << 1) + (lo >> 63); + lo = (lo << 1) ^ carry; + + buf_put_le64 (out + 8, hi); + buf_put_le64 (out + 0, lo); +} + + +static inline void xts_inc128 (unsigned char *seqno) +{ + u64 lo = buf_get_le64 (seqno + 0); + u64 hi = buf_get_le64 (seqno + 8); + + hi += !(++lo); + + buf_put_le64 (seqno + 0, lo); + buf_put_le64 (seqno + 8, hi); +} + + +gcry_err_code_t +_gcry_cipher_xts_crypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen, + int encrypt) +{ + gcry_cipher_encrypt_t tweak_fn = c->spec->encrypt; + gcry_cipher_encrypt_t crypt_fn = + encrypt ? c->spec->encrypt : c->spec->decrypt; + union + { + cipher_context_alignment_t xcx; + byte x1[GCRY_XTS_BLOCK_LEN]; + u64 x64[GCRY_XTS_BLOCK_LEN / sizeof(u64)]; + } tmp; + unsigned int burn, nburn; + size_t nblocks; + + if (c->spec->blocksize != GCRY_XTS_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (inbuflen < GCRY_XTS_BLOCK_LEN) + return GPG_ERR_BUFFER_TOO_SHORT; + + /* Data-unit max length: 2^20 blocks. */ + if (inbuflen > GCRY_XTS_BLOCK_LEN << 20) + return GPG_ERR_INV_LENGTH; + + nblocks = inbuflen / GCRY_XTS_BLOCK_LEN; + nblocks -= !encrypt && (inbuflen % GCRY_XTS_BLOCK_LEN) != 0; + + /* Generate first tweak value. */ + burn = tweak_fn (c->u_mode.xts.tweak_context, c->u_ctr.ctr, c->u_iv.iv); + + /* Use a bulk method if available. */ + if (nblocks && c->bulk.xts_crypt) + { + c->bulk.xts_crypt (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks, + encrypt); + inbuf += nblocks * GCRY_XTS_BLOCK_LEN; + outbuf += nblocks * GCRY_XTS_BLOCK_LEN; + inbuflen -= nblocks * GCRY_XTS_BLOCK_LEN; + nblocks = 0; + } + + /* If we don't have a bulk method use the standard method. We also + use this method for the a remaining partial block. */ + + while (nblocks) + { + /* Xor-Encrypt/Decrypt-Xor block. */ + cipher_block_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1); + burn = nburn > burn ? nburn : burn; + cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + + outbuf += GCRY_XTS_BLOCK_LEN; + inbuf += GCRY_XTS_BLOCK_LEN; + inbuflen -= GCRY_XTS_BLOCK_LEN; + nblocks--; + + /* Generate next tweak. */ + xts_gfmul_byA (c->u_ctr.ctr, c->u_ctr.ctr); + } + + /* Handle remaining data with ciphertext stealing. */ + if (inbuflen) + { + if (!encrypt) + { + gcry_assert (inbuflen > GCRY_XTS_BLOCK_LEN); + gcry_assert (inbuflen < GCRY_XTS_BLOCK_LEN * 2); + + /* Generate last tweak. */ + xts_gfmul_byA (tmp.x1, c->u_ctr.ctr); + + /* Decrypt last block first. */ + cipher_block_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; + cipher_block_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); + + inbuflen -= GCRY_XTS_BLOCK_LEN; + inbuf += GCRY_XTS_BLOCK_LEN; + outbuf += GCRY_XTS_BLOCK_LEN; + } + + gcry_assert (inbuflen < GCRY_XTS_BLOCK_LEN); + outbuf -= GCRY_XTS_BLOCK_LEN; + + /* Steal ciphertext from previous block. */ + cipher_block_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN); + buf_cpy (tmp.x64, inbuf, inbuflen); + buf_cpy (outbuf + GCRY_XTS_BLOCK_LEN, outbuf, inbuflen); + + /* Decrypt/Encrypt last block. */ + cipher_block_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1); + burn = nburn > burn ? nburn : burn; + cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + } + + /* Auto-increment data-unit sequence number */ + xts_inc128 (c->u_iv.iv); + + wipememory (&tmp, sizeof(tmp)); + wipememory (c->u_ctr.ctr, sizeof(c->u_ctr.ctr)); + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_xts_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + return _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 1); +} + + +gcry_err_code_t +_gcry_cipher_xts_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + return _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 0); +} diff --git a/comm/third_party/libgcrypt/cipher/cipher.c b/comm/third_party/libgcrypt/cipher/cipher.c new file mode 100644 index 0000000000..1039dff728 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/cipher.c @@ -0,0 +1,1767 @@ +/* cipher.c - cipher dispatcher + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "../src/gcrypt-testapi.h" +#include "cipher.h" +#include "./cipher-internal.h" + + +/* This is the list of the default ciphers, which are included in + libgcrypt. */ +static gcry_cipher_spec_t * const cipher_list[] = + { +#if USE_BLOWFISH + &_gcry_cipher_spec_blowfish, +#endif +#if USE_DES + &_gcry_cipher_spec_des, + &_gcry_cipher_spec_tripledes, +#endif +#if USE_ARCFOUR + &_gcry_cipher_spec_arcfour, +#endif +#if USE_CAST5 + &_gcry_cipher_spec_cast5, +#endif +#if USE_AES + &_gcry_cipher_spec_aes, + &_gcry_cipher_spec_aes192, + &_gcry_cipher_spec_aes256, +#endif +#if USE_TWOFISH + &_gcry_cipher_spec_twofish, + &_gcry_cipher_spec_twofish128, +#endif +#if USE_SERPENT + &_gcry_cipher_spec_serpent128, + &_gcry_cipher_spec_serpent192, + &_gcry_cipher_spec_serpent256, +#endif +#if USE_RFC2268 + &_gcry_cipher_spec_rfc2268_40, + &_gcry_cipher_spec_rfc2268_128, +#endif +#if USE_SEED + &_gcry_cipher_spec_seed, +#endif +#if USE_CAMELLIA + &_gcry_cipher_spec_camellia128, + &_gcry_cipher_spec_camellia192, + &_gcry_cipher_spec_camellia256, +#endif +#ifdef USE_IDEA + &_gcry_cipher_spec_idea, +#endif +#if USE_SALSA20 + &_gcry_cipher_spec_salsa20, + &_gcry_cipher_spec_salsa20r12, +#endif +#if USE_GOST28147 + &_gcry_cipher_spec_gost28147, + &_gcry_cipher_spec_gost28147_mesh, +#endif +#if USE_CHACHA20 + &_gcry_cipher_spec_chacha20, +#endif +#if USE_SM4 + &_gcry_cipher_spec_sm4, +#endif + NULL + }; + +/* Cipher implementations starting with index 0 (enum gcry_cipher_algos) */ +static gcry_cipher_spec_t * const cipher_list_algo0[] = + { + NULL, /* GCRY_CIPHER_NONE */ +#ifdef USE_IDEA + &_gcry_cipher_spec_idea, +#else + NULL, +#endif +#if USE_DES + &_gcry_cipher_spec_tripledes, +#else + NULL, +#endif +#if USE_CAST5 + &_gcry_cipher_spec_cast5, +#else + NULL, +#endif +#if USE_BLOWFISH + &_gcry_cipher_spec_blowfish, +#else + NULL, +#endif + NULL, /* GCRY_CIPHER_SAFER_SK128 */ + NULL, /* GCRY_CIPHER_DES_SK */ +#if USE_AES + &_gcry_cipher_spec_aes, + &_gcry_cipher_spec_aes192, + &_gcry_cipher_spec_aes256, +#else + NULL, + NULL, + NULL, +#endif +#if USE_TWOFISH + &_gcry_cipher_spec_twofish +#else + NULL +#endif + }; + +/* Cipher implementations starting with index 301 (enum gcry_cipher_algos) */ +static gcry_cipher_spec_t * const cipher_list_algo301[] = + { +#if USE_ARCFOUR + &_gcry_cipher_spec_arcfour, +#else + NULL, +#endif +#if USE_DES + &_gcry_cipher_spec_des, +#else + NULL, +#endif +#if USE_TWOFISH + &_gcry_cipher_spec_twofish128, +#else + NULL, +#endif +#if USE_SERPENT + &_gcry_cipher_spec_serpent128, + &_gcry_cipher_spec_serpent192, + &_gcry_cipher_spec_serpent256, +#else + NULL, + NULL, + NULL, +#endif +#if USE_RFC2268 + &_gcry_cipher_spec_rfc2268_40, + &_gcry_cipher_spec_rfc2268_128, +#else + NULL, + NULL, +#endif +#if USE_SEED + &_gcry_cipher_spec_seed, +#else + NULL, +#endif +#if USE_CAMELLIA + &_gcry_cipher_spec_camellia128, + &_gcry_cipher_spec_camellia192, + &_gcry_cipher_spec_camellia256, +#else + NULL, + NULL, + NULL, +#endif +#if USE_SALSA20 + &_gcry_cipher_spec_salsa20, + &_gcry_cipher_spec_salsa20r12, +#else + NULL, + NULL, +#endif +#if USE_GOST28147 + &_gcry_cipher_spec_gost28147, +#else + NULL, +#endif +#if USE_CHACHA20 + &_gcry_cipher_spec_chacha20, +#else + NULL, +#endif +#if USE_GOST28147 + &_gcry_cipher_spec_gost28147_mesh, +#else + NULL, +#endif +#if USE_SM4 + &_gcry_cipher_spec_sm4, +#else + NULL, +#endif + }; + + +static void _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode); + + +static int +map_algo (int algo) +{ + return algo; +} + + +/* Return the spec structure for the cipher algorithm ALGO. For + an unknown algorithm NULL is returned. */ +static gcry_cipher_spec_t * +spec_from_algo (int algo) +{ + gcry_cipher_spec_t *spec = NULL; + + algo = map_algo (algo); + + if (algo >= 0 && algo < DIM(cipher_list_algo0)) + spec = cipher_list_algo0[algo]; + else if (algo >= 301 && algo < 301 + DIM(cipher_list_algo301)) + spec = cipher_list_algo301[algo - 301]; + + if (spec) + gcry_assert (spec->algo == algo); + + return spec; +} + + +/* Lookup a cipher's spec by its name. */ +static gcry_cipher_spec_t * +spec_from_name (const char *name) +{ + gcry_cipher_spec_t *spec; + int idx; + const char **aliases; + + for (idx=0; (spec = cipher_list[idx]); idx++) + { + if (!stricmp (name, spec->name)) + return spec; + if (spec->aliases) + { + for (aliases = spec->aliases; *aliases; aliases++) + if (!stricmp (name, *aliases)) + return spec; + } + } + + return NULL; +} + + +/* Lookup a cipher's spec by its OID. */ +static gcry_cipher_spec_t * +spec_from_oid (const char *oid) +{ + gcry_cipher_spec_t *spec; + gcry_cipher_oid_spec_t *oid_specs; + int idx, j; + + for (idx=0; (spec = cipher_list[idx]); idx++) + { + oid_specs = spec->oids; + if (oid_specs) + { + for (j = 0; oid_specs[j].oid; j++) + if (!stricmp (oid, oid_specs[j].oid)) + return spec; + } + } + + return NULL; +} + + +/* Locate the OID in the oid table and return the spec or NULL if not + found. An optional "oid." or "OID." prefix in OID is ignored, the + OID is expected to be in standard IETF dotted notation. A pointer + to the OID specification of the module implementing this algorithm + is return in OID_SPEC unless passed as NULL.*/ +static gcry_cipher_spec_t * +search_oid (const char *oid, gcry_cipher_oid_spec_t *oid_spec) +{ + gcry_cipher_spec_t *spec; + int i; + + if (!oid) + return NULL; + + if (!strncmp (oid, "oid.", 4) || !strncmp (oid, "OID.", 4)) + oid += 4; + + spec = spec_from_oid (oid); + if (spec && spec->oids) + { + for (i = 0; spec->oids[i].oid; i++) + if (!stricmp (oid, spec->oids[i].oid)) + { + if (oid_spec) + *oid_spec = spec->oids[i]; + return spec; + } + } + + return NULL; +} + + +/* Map STRING to the cipher algorithm identifier. Returns the + algorithm ID of the cipher for the given name or 0 if the name is + not known. It is valid to pass NULL for STRING which results in a + return value of 0. */ +int +_gcry_cipher_map_name (const char *string) +{ + gcry_cipher_spec_t *spec; + + if (!string) + return 0; + + /* If the string starts with a digit (optionally prefixed with + either "OID." or "oid."), we first look into our table of ASN.1 + object identifiers to figure out the algorithm */ + + spec = search_oid (string, NULL); + if (spec) + return spec->algo; + + spec = spec_from_name (string); + if (spec) + return spec->algo; + + return 0; +} + + +/* Given a STRING with an OID in dotted decimal notation, this + function returns the cipher mode (GCRY_CIPHER_MODE_*) associated + with that OID or 0 if no mode is known. Passing NULL for string + yields a return value of 0. */ +int +_gcry_cipher_mode_from_oid (const char *string) +{ + gcry_cipher_spec_t *spec; + gcry_cipher_oid_spec_t oid_spec; + + if (!string) + return 0; + + spec = search_oid (string, &oid_spec); + if (spec) + return oid_spec.mode; + + return 0; +} + + +/* Map the cipher algorithm identifier ALGORITHM to a string + representing this algorithm. This string is the default name as + used by Libgcrypt. A "?" is returned for an unknown algorithm. + NULL is never returned. */ +const char * +_gcry_cipher_algo_name (int algorithm) +{ + gcry_cipher_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec? spec->name : "?"; +} + + +/* Flag the cipher algorithm with the identifier ALGORITHM as + disabled. There is no error return, the function does nothing for + unknown algorithms. Disabled algorithms are virtually not + available in Libgcrypt. This is not thread safe and should thus be + called early. */ +static void +disable_cipher_algo (int algo) +{ + gcry_cipher_spec_t *spec = spec_from_algo (algo); + + if (spec) + spec->flags.disabled = 1; +} + + +/* Return 0 if the cipher algorithm with identifier ALGORITHM is + available. Returns a basic error code value if it is not + available. */ +static gcry_err_code_t +check_cipher_algo (int algorithm) +{ + gcry_cipher_spec_t *spec; + + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; + + return GPG_ERR_CIPHER_ALGO; +} + + +/* Return the standard length in bits of the key for the cipher + algorithm with the identifier ALGORITHM. */ +static unsigned int +cipher_get_keylen (int algorithm) +{ + gcry_cipher_spec_t *spec; + unsigned len = 0; + + spec = spec_from_algo (algorithm); + if (spec) + { + len = spec->keylen; + if (!len) + log_bug ("cipher %d w/o key length\n", algorithm); + } + + return len; +} + + +/* Return the block length of the cipher algorithm with the identifier + ALGORITHM. This function return 0 for an invalid algorithm. */ +static unsigned int +cipher_get_blocksize (int algorithm) +{ + gcry_cipher_spec_t *spec; + unsigned len = 0; + + spec = spec_from_algo (algorithm); + if (spec) + { + len = spec->blocksize; + if (!len) + log_bug ("cipher %d w/o blocksize\n", algorithm); + } + + return len; +} + + +/* + Open a cipher handle for use with cipher algorithm ALGORITHM, using + the cipher mode MODE (one of the GCRY_CIPHER_MODE_*) and return a + handle in HANDLE. Put NULL into HANDLE and return an error code if + something goes wrong. FLAGS may be used to modify the + operation. The defined flags are: + + GCRY_CIPHER_SECURE: allocate all internal buffers in secure memory. + GCRY_CIPHER_ENABLE_SYNC: Enable the sync operation as used in OpenPGP. + GCRY_CIPHER_CBC_CTS: Enable CTS mode. + GCRY_CIPHER_CBC_MAC: Enable MAC mode. + + Values for these flags may be combined using OR. + */ +gcry_err_code_t +_gcry_cipher_open (gcry_cipher_hd_t *handle, + int algo, int mode, unsigned int flags) +{ + gcry_err_code_t rc; + gcry_cipher_hd_t h = NULL; + + if (mode >= GCRY_CIPHER_MODE_INTERNAL) + rc = GPG_ERR_INV_CIPHER_MODE; + else + rc = _gcry_cipher_open_internal (&h, algo, mode, flags); + + *handle = rc ? NULL : h; + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_open_internal (gcry_cipher_hd_t *handle, + int algo, int mode, unsigned int flags) +{ + int secure = (flags & GCRY_CIPHER_SECURE); + gcry_cipher_spec_t *spec; + gcry_cipher_hd_t h = NULL; + gcry_err_code_t err; + + /* If the application missed to call the random poll function, we do + it here to ensure that it is used once in a while. */ + _gcry_fast_random_poll (); + + spec = spec_from_algo (algo); + if (!spec) + err = GPG_ERR_CIPHER_ALGO; + else if (spec->flags.disabled) + err = GPG_ERR_CIPHER_ALGO; + else + err = 0; + + /* check flags */ + if ((! err) + && ((flags & ~(0 + | GCRY_CIPHER_SECURE + | GCRY_CIPHER_ENABLE_SYNC + | GCRY_CIPHER_CBC_CTS + | GCRY_CIPHER_CBC_MAC)) + || ((flags & GCRY_CIPHER_CBC_CTS) && (flags & GCRY_CIPHER_CBC_MAC)))) + err = GPG_ERR_CIPHER_ALGO; + + /* check that a valid mode has been requested */ + if (! err) + switch (mode) + { + case GCRY_CIPHER_MODE_CCM: + if (spec->blocksize != GCRY_CCM_BLOCK_LEN) + err = GPG_ERR_INV_CIPHER_MODE; + if (!spec->encrypt || !spec->decrypt) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_XTS: + if (spec->blocksize != GCRY_XTS_BLOCK_LEN) + err = GPG_ERR_INV_CIPHER_MODE; + if (!spec->encrypt || !spec->decrypt) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CFB: + case GCRY_CIPHER_MODE_CFB8: + case GCRY_CIPHER_MODE_OFB: + case GCRY_CIPHER_MODE_CTR: + case GCRY_CIPHER_MODE_AESWRAP: + case GCRY_CIPHER_MODE_CMAC: + case GCRY_CIPHER_MODE_EAX: + case GCRY_CIPHER_MODE_GCM: + if (!spec->encrypt || !spec->decrypt) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_POLY1305: + if (!spec->stencrypt || !spec->stdecrypt || !spec->setiv) + err = GPG_ERR_INV_CIPHER_MODE; + else if (spec->algo != GCRY_CIPHER_CHACHA20) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_OCB: + /* Note that our implementation allows only for 128 bit block + length algorithms. Lower block lengths would be possible + but we do not implement them because they limit the + security too much. */ + if (!spec->encrypt || !spec->decrypt) + err = GPG_ERR_INV_CIPHER_MODE; + else if (spec->blocksize != (128/8)) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_STREAM: + if (!spec->stencrypt || !spec->stdecrypt) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_NONE: + /* This mode may be used for debugging. It copies the main + text verbatim to the ciphertext. We do not allow this in + fips mode or if no debug flag has been set. */ + if (fips_mode () || !_gcry_get_debug_flag (0)) + err = GPG_ERR_INV_CIPHER_MODE; + break; + + default: + err = GPG_ERR_INV_CIPHER_MODE; + } + + /* Perform selftest here and mark this with a flag in cipher_table? + No, we should not do this as it takes too long. Further it does + not make sense to exclude algorithms with failing selftests at + runtime: If a selftest fails there is something seriously wrong + with the system and thus we better die immediately. */ + + if (! err) + { + size_t size = (sizeof (*h) + + 2 * spec->contextsize + - sizeof (cipher_context_alignment_t) +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + + 15 /* Space for leading alignment gap. */ +#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ + ); + + /* Space needed per mode. */ + switch (mode) + { + case GCRY_CIPHER_MODE_XTS: + /* Additional cipher context for tweak. */ + size += 2 * spec->contextsize + 15; + break; + + default: + break; + } + + if (secure) + h = xtrycalloc_secure (1, size); + else + h = xtrycalloc (1, size); + + if (! h) + err = gpg_err_code_from_syserror (); + else + { + size_t off = 0; + char *tc; + +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + if ( ((uintptr_t)h & 0x0f) ) + { + /* The malloced block is not aligned on a 16 byte + boundary. Correct for this. */ + off = 16 - ((uintptr_t)h & 0x0f); + h = (void*)((char*)h + off); + } +#endif /*NEED_16BYTE_ALIGNED_CONTEXT*/ + + h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + h->actual_handle_size = size - off; + h->handle_offset = off; + h->spec = spec; + h->algo = algo; + h->mode = mode; + h->flags = flags; + + /* Setup mode routines. */ + _gcry_cipher_setup_mode_ops(h, mode); + + /* Setup defaults depending on the mode. */ + switch (mode) + { + case GCRY_CIPHER_MODE_OCB: + h->u_mode.ocb.taglen = 16; /* Bytes. */ + break; + + case GCRY_CIPHER_MODE_XTS: + tc = h->context.c + spec->contextsize * 2; + tc += (16 - (uintptr_t)tc % 16) % 16; + h->u_mode.xts.tweak_context = tc; + + break; + + default: + break; + } + } + } + + /* Done. */ + + *handle = err ? NULL : h; + + return err; +} + + +/* Release all resources associated with the cipher handle H. H may be + NULL in which case this is a no-operation. */ +void +_gcry_cipher_close (gcry_cipher_hd_t h) +{ + size_t off; + + if (!h) + return; + + if ((h->magic != CTX_MAGIC_SECURE) + && (h->magic != CTX_MAGIC_NORMAL)) + _gcry_fatal_error(GPG_ERR_INTERNAL, + "gcry_cipher_close: already closed/invalid handle"); + else + h->magic = 0; + + /* We always want to wipe out the memory even when the context has + been allocated in secure memory. The user might have disabled + secure memory or is using his own implementation which does not + do the wiping. To accomplish this we need to keep track of the + actual size of this structure because we have no way to known + how large the allocated area was when using a standard malloc. */ + off = h->handle_offset; + wipememory (h, h->actual_handle_size); + + xfree ((char*)h - off); +} + + +/* Set the key to be used for the encryption context C to KEY with + length KEYLEN. The length should match the required length. */ +static gcry_err_code_t +cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen) +{ + gcry_err_code_t rc; + + if (c->mode == GCRY_CIPHER_MODE_XTS) + { + /* XTS uses two keys. */ + if (keylen % 2) + return GPG_ERR_INV_KEYLEN; + keylen /= 2; + + if (fips_mode ()) + { + /* Reject key if subkeys Key_1 and Key_2 are equal. + See "Implementation Guidance for FIPS 140-2, A.9 XTS-AES + Key Generation Requirements" for details. */ + if (buf_eq_const (key, key + keylen, keylen)) + return GPG_ERR_WEAK_KEY; + } + } + + rc = c->spec->setkey (&c->context.c, key, keylen, &c->bulk); + if (!rc || (c->marks.allow_weak_key && rc == GPG_ERR_WEAK_KEY)) + { + /* Duplicate initial context. */ + memcpy ((void *) ((char *) &c->context.c + c->spec->contextsize), + (void *) &c->context.c, + c->spec->contextsize); + c->marks.key = 1; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_CMAC: + rc = _gcry_cipher_cmac_set_subkeys (c); + break; + + case GCRY_CIPHER_MODE_EAX: + rc = _gcry_cipher_eax_setkey (c); + break; + + case GCRY_CIPHER_MODE_GCM: + _gcry_cipher_gcm_setkey (c); + break; + + case GCRY_CIPHER_MODE_OCB: + _gcry_cipher_ocb_setkey (c); + break; + + case GCRY_CIPHER_MODE_POLY1305: + _gcry_cipher_poly1305_setkey (c); + break; + + case GCRY_CIPHER_MODE_XTS: + /* Setup tweak cipher with second part of XTS key. */ + rc = c->spec->setkey (c->u_mode.xts.tweak_context, key + keylen, + keylen, &c->bulk); + if (!rc || (c->marks.allow_weak_key && rc == GPG_ERR_WEAK_KEY)) + { + /* Duplicate initial tweak context. */ + memcpy (c->u_mode.xts.tweak_context + c->spec->contextsize, + c->u_mode.xts.tweak_context, c->spec->contextsize); + } + else + c->marks.key = 0; + break; + + default: + break; + }; + } + else + c->marks.key = 0; + + return rc; +} + + +/* Set the IV to be used for the encryption context C to IV with + length IVLEN. The length should match the required length. */ +static gcry_err_code_t +cipher_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) +{ + /* If the cipher has its own IV handler, we use only this one. This + is currently used for stream ciphers requiring a nonce. */ + if (c->spec->setiv) + { + c->spec->setiv (&c->context.c, iv, ivlen); + return 0; + } + + memset (c->u_iv.iv, 0, c->spec->blocksize); + if (iv) + { + if (ivlen != c->spec->blocksize) + { + log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", + (unsigned int)ivlen, (unsigned int)c->spec->blocksize); + fips_signal_error ("IV length does not match blocklength"); + } + if (ivlen > c->spec->blocksize) + ivlen = c->spec->blocksize; + memcpy (c->u_iv.iv, iv, ivlen); + c->marks.iv = 1; + } + else + c->marks.iv = 0; + c->unused = 0; + + return 0; +} + + +/* Reset the cipher context to the initial context. This is basically + the same as an release followed by a new. */ +static void +cipher_reset (gcry_cipher_hd_t c) +{ + unsigned int marks_key, marks_allow_weak_key; + + marks_key = c->marks.key; + marks_allow_weak_key = c->marks.allow_weak_key; + + memcpy (&c->context.c, + (char *) &c->context.c + c->spec->contextsize, + c->spec->contextsize); + memset (&c->marks, 0, sizeof c->marks); + memset (c->u_iv.iv, 0, c->spec->blocksize); + memset (c->lastiv, 0, c->spec->blocksize); + memset (c->u_ctr.ctr, 0, c->spec->blocksize); + c->unused = 0; + + c->marks.key = marks_key; + c->marks.allow_weak_key = marks_allow_weak_key; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_CMAC: + _gcry_cmac_reset(&c->u_mode.cmac); + break; + + case GCRY_CIPHER_MODE_EAX: + _gcry_cmac_reset(&c->u_mode.eax.cmac_header); + _gcry_cmac_reset(&c->u_mode.eax.cmac_ciphertext); + break; + + case GCRY_CIPHER_MODE_GCM: + /* Only clear head of u_mode, keep ghash_key and gcm_table. */ + { + byte *u_mode_pos = (void *)&c->u_mode; + byte *ghash_key_pos = c->u_mode.gcm.u_ghash_key.key; + size_t u_mode_head_length = ghash_key_pos - u_mode_pos; + + memset (&c->u_mode, 0, u_mode_head_length); + } + break; + + case GCRY_CIPHER_MODE_POLY1305: + memset (&c->u_mode.poly1305, 0, sizeof c->u_mode.poly1305); + break; + + case GCRY_CIPHER_MODE_CCM: + memset (&c->u_mode.ccm, 0, sizeof c->u_mode.ccm); + break; + + case GCRY_CIPHER_MODE_OCB: + /* Do not clear precalculated L-values */ + { + byte *u_mode_head_pos = (void *)&c->u_mode.ocb; + byte *u_mode_tail_pos = (void *)&c->u_mode.ocb.tag; + size_t u_mode_head_length = u_mode_tail_pos - u_mode_head_pos; + size_t u_mode_tail_length = sizeof(c->u_mode.ocb) - u_mode_head_length; + + memset (u_mode_tail_pos, 0, u_mode_tail_length); + + /* Setup default taglen. */ + c->u_mode.ocb.taglen = 16; + } + break; + + case GCRY_CIPHER_MODE_XTS: + memcpy (c->u_mode.xts.tweak_context, + c->u_mode.xts.tweak_context + c->spec->contextsize, + c->spec->contextsize); + break; + + default: + break; /* u_mode unused by other modes. */ + } +} + + + +static gcry_err_code_t +do_ecb_crypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen, + gcry_cipher_encrypt_t crypt_fn) +{ + unsigned int blocksize = c->spec->blocksize; + size_t n, nblocks; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if ((inbuflen % blocksize)) + return GPG_ERR_INV_LENGTH; + + nblocks = inbuflen / blocksize; + burn = 0; + + for (n=0; n < nblocks; n++ ) + { + nburn = crypt_fn (&c->context.c, outbuf, inbuf); + burn = nburn > burn ? nburn : burn; + inbuf += blocksize; + outbuf += blocksize; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + +static gcry_err_code_t +do_ecb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + return do_ecb_crypt (c, outbuf, outbuflen, inbuf, inbuflen, c->spec->encrypt); +} + +static gcry_err_code_t +do_ecb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + return do_ecb_crypt (c, outbuf, outbuflen, inbuf, inbuflen, c->spec->decrypt); +} + + +static gcry_err_code_t +do_stream_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + (void)outbuflen; + c->spec->stencrypt (&c->context.c, outbuf, (void *)inbuf, inbuflen); + return 0; +} + +static gcry_err_code_t +do_stream_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + (void)outbuflen; + c->spec->stdecrypt (&c->context.c, outbuf, (void *)inbuf, inbuflen); + return 0; +} + + +static gcry_err_code_t +do_encrypt_none_unknown (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t rc; + + (void)outbuflen; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_CMAC: + rc = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } + else + { + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + rc = 0; + } + break; + + default: + log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + +static gcry_err_code_t +do_decrypt_none_unknown (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + gcry_err_code_t rc; + + (void)outbuflen; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_CMAC: + rc = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } + else + { + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + rc = 0; + } + break; + + default: + log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + + +/**************** + * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has + * been requested. + */ +gcry_err_code_t +_gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, + const void *in, size_t inlen) +{ + gcry_err_code_t rc; + + if (!in) /* Caller requested in-place encryption. */ + { + in = out; + inlen = outsize; + } + + if (h->mode != GCRY_CIPHER_MODE_NONE && !h->marks.key) + { + log_error ("cipher_encrypt: key not set\n"); + return GPG_ERR_MISSING_KEY; + } + + rc = h->mode_ops.encrypt (h, out, outsize, in, inlen); + + /* Failsafe: Make sure that the plaintext will never make it into + OUT if the encryption returned an error. */ + if (rc && out) + memset (out, 0x42, outsize); + + return rc; +} + + +/**************** + * Decrypt IN and write it to OUT. If IN is NULL, in-place encryption has + * been requested. + */ +gcry_err_code_t +_gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, + const void *in, size_t inlen) +{ + if (!in) /* Caller requested in-place encryption. */ + { + in = out; + inlen = outsize; + } + + if (h->mode != GCRY_CIPHER_MODE_NONE && !h->marks.key) + { + log_error ("cipher_decrypt: key not set\n"); + return GPG_ERR_MISSING_KEY; + } + + return h->mode_ops.decrypt (h, out, outsize, in, inlen); +} + + +/**************** + * Used for PGP's somewhat strange CFB mode. Only works if + * the corresponding flag is set. + */ +static void +cipher_sync (gcry_cipher_hd_t c) +{ + if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused) + { + memmove (c->u_iv.iv + c->unused, + c->u_iv.iv, c->spec->blocksize - c->unused); + memcpy (c->u_iv.iv, + c->lastiv + c->spec->blocksize - c->unused, c->unused); + c->unused = 0; + } +} + + +gcry_err_code_t +_gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) +{ + return cipher_setkey (hd, (void*)key, keylen); +} + + +gcry_err_code_t +_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) +{ + return hd->mode_ops.setiv (hd, iv, ivlen); +} + + +/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of + block size length, or (NULL,0) to set the CTR to the all-zero + block. */ +gpg_err_code_t +_gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) +{ + if (ctr && ctrlen == hd->spec->blocksize) + { + memcpy (hd->u_ctr.ctr, ctr, hd->spec->blocksize); + hd->unused = 0; + } + else if (!ctr || !ctrlen) + { + memset (hd->u_ctr.ctr, 0, hd->spec->blocksize); + hd->unused = 0; + } + else + return GPG_ERR_INV_ARG; + + return 0; +} + +gpg_err_code_t +_gcry_cipher_getctr (gcry_cipher_hd_t hd, void *ctr, size_t ctrlen) +{ + if (ctr && ctrlen == hd->spec->blocksize) + memcpy (ctr, hd->u_ctr.ctr, hd->spec->blocksize); + else + return GPG_ERR_INV_ARG; + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen) +{ + gcry_err_code_t rc; + + if (hd->mode_ops.authenticate) + { + rc = hd->mode_ops.authenticate (hd, abuf, abuflen); + } + else + { + log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + } + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + gcry_err_code_t rc; + + if (hd->mode_ops.get_tag) + { + rc = hd->mode_ops.get_tag (hd, outtag, taglen); + } + else + { + log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + } + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + gcry_err_code_t rc; + + if (hd->mode_ops.check_tag) + { + rc = hd->mode_ops.check_tag (hd, intag, taglen); + } + else + { + log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + } + + return rc; +} + + + +static void +_gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode) +{ + /* Setup encryption and decryption routines. */ + switch (mode) + { + case GCRY_CIPHER_MODE_STREAM: + c->mode_ops.encrypt = do_stream_encrypt; + c->mode_ops.decrypt = do_stream_decrypt; + break; + + case GCRY_CIPHER_MODE_ECB: + c->mode_ops.encrypt = do_ecb_encrypt; + c->mode_ops.decrypt = do_ecb_decrypt; + break; + + case GCRY_CIPHER_MODE_CBC: + if (!(c->flags & GCRY_CIPHER_CBC_CTS)) + { + c->mode_ops.encrypt = _gcry_cipher_cbc_encrypt; + c->mode_ops.decrypt = _gcry_cipher_cbc_decrypt; + } + else + { + c->mode_ops.encrypt = _gcry_cipher_cbc_cts_encrypt; + c->mode_ops.decrypt = _gcry_cipher_cbc_cts_decrypt; + } + break; + + case GCRY_CIPHER_MODE_CFB: + c->mode_ops.encrypt = _gcry_cipher_cfb_encrypt; + c->mode_ops.decrypt = _gcry_cipher_cfb_decrypt; + break; + + case GCRY_CIPHER_MODE_CFB8: + c->mode_ops.encrypt = _gcry_cipher_cfb8_encrypt; + c->mode_ops.decrypt = _gcry_cipher_cfb8_decrypt; + break; + + case GCRY_CIPHER_MODE_OFB: + c->mode_ops.encrypt = _gcry_cipher_ofb_encrypt; + c->mode_ops.decrypt = _gcry_cipher_ofb_encrypt; + break; + + case GCRY_CIPHER_MODE_CTR: + c->mode_ops.encrypt = _gcry_cipher_ctr_encrypt; + c->mode_ops.decrypt = _gcry_cipher_ctr_encrypt; + break; + + case GCRY_CIPHER_MODE_AESWRAP: + c->mode_ops.encrypt = _gcry_cipher_aeswrap_encrypt; + c->mode_ops.decrypt = _gcry_cipher_aeswrap_decrypt; + break; + + case GCRY_CIPHER_MODE_CCM: + c->mode_ops.encrypt = _gcry_cipher_ccm_encrypt; + c->mode_ops.decrypt = _gcry_cipher_ccm_decrypt; + break; + + case GCRY_CIPHER_MODE_EAX: + c->mode_ops.encrypt = _gcry_cipher_eax_encrypt; + c->mode_ops.decrypt = _gcry_cipher_eax_decrypt; + break; + + case GCRY_CIPHER_MODE_GCM: + c->mode_ops.encrypt = _gcry_cipher_gcm_encrypt; + c->mode_ops.decrypt = _gcry_cipher_gcm_decrypt; + break; + + case GCRY_CIPHER_MODE_POLY1305: + c->mode_ops.encrypt = _gcry_cipher_poly1305_encrypt; + c->mode_ops.decrypt = _gcry_cipher_poly1305_decrypt; + break; + + case GCRY_CIPHER_MODE_OCB: + c->mode_ops.encrypt = _gcry_cipher_ocb_encrypt; + c->mode_ops.decrypt = _gcry_cipher_ocb_decrypt; + break; + + case GCRY_CIPHER_MODE_XTS: + c->mode_ops.encrypt = _gcry_cipher_xts_encrypt; + c->mode_ops.decrypt = _gcry_cipher_xts_decrypt; + break; + + default: + c->mode_ops.encrypt = do_encrypt_none_unknown; + c->mode_ops.decrypt = do_decrypt_none_unknown; + break; + } + + /* Setup IV setting routine. */ + switch (mode) + { + case GCRY_CIPHER_MODE_CCM: + c->mode_ops.setiv = _gcry_cipher_ccm_set_nonce; + break; + + case GCRY_CIPHER_MODE_EAX: + c->mode_ops.setiv = _gcry_cipher_eax_set_nonce; + break; + + case GCRY_CIPHER_MODE_GCM: + c->mode_ops.setiv = _gcry_cipher_gcm_setiv; + break; + + case GCRY_CIPHER_MODE_POLY1305: + c->mode_ops.setiv = _gcry_cipher_poly1305_setiv; + break; + + case GCRY_CIPHER_MODE_OCB: + c->mode_ops.setiv = _gcry_cipher_ocb_set_nonce; + break; + + default: + c->mode_ops.setiv = cipher_setiv; + break; + } + + + /* Setup authentication routines for AEAD modes. */ + switch (mode) + { + case GCRY_CIPHER_MODE_CCM: + c->mode_ops.authenticate = _gcry_cipher_ccm_authenticate; + c->mode_ops.get_tag = _gcry_cipher_ccm_get_tag; + c->mode_ops.check_tag = _gcry_cipher_ccm_check_tag; + break; + + case GCRY_CIPHER_MODE_CMAC: + c->mode_ops.authenticate = _gcry_cipher_cmac_authenticate; + c->mode_ops.get_tag = _gcry_cipher_cmac_get_tag; + c->mode_ops.check_tag = _gcry_cipher_cmac_check_tag; + break; + + case GCRY_CIPHER_MODE_EAX: + c->mode_ops.authenticate = _gcry_cipher_eax_authenticate; + c->mode_ops.get_tag = _gcry_cipher_eax_get_tag; + c->mode_ops.check_tag = _gcry_cipher_eax_check_tag; + break; + + case GCRY_CIPHER_MODE_GCM: + c->mode_ops.authenticate = _gcry_cipher_gcm_authenticate; + c->mode_ops.get_tag = _gcry_cipher_gcm_get_tag; + c->mode_ops.check_tag = _gcry_cipher_gcm_check_tag; + break; + + case GCRY_CIPHER_MODE_POLY1305: + c->mode_ops.authenticate = _gcry_cipher_poly1305_authenticate; + c->mode_ops.get_tag = _gcry_cipher_poly1305_get_tag; + c->mode_ops.check_tag = _gcry_cipher_poly1305_check_tag; + break; + + case GCRY_CIPHER_MODE_OCB: + c->mode_ops.authenticate = _gcry_cipher_ocb_authenticate; + c->mode_ops.get_tag = _gcry_cipher_ocb_get_tag; + c->mode_ops.check_tag = _gcry_cipher_ocb_check_tag; + break; + + default: + c->mode_ops.authenticate = NULL; + c->mode_ops.get_tag = NULL; + c->mode_ops.check_tag = NULL; + break; + } +} + + +gcry_err_code_t +_gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = 0; + + switch (cmd) + { + case GCRYCTL_RESET: + cipher_reset (h); + break; + + case GCRYCTL_FINALIZE: + if (!h || buffer || buflen) + return GPG_ERR_INV_ARG; + h->marks.finalize = 1; + break; + + case GCRYCTL_CFB_SYNC: + cipher_sync( h ); + break; + + case GCRYCTL_SET_CBC_CTS: + if (buflen) + if (h->flags & GCRY_CIPHER_CBC_MAC) + rc = GPG_ERR_INV_FLAG; + else + h->flags |= GCRY_CIPHER_CBC_CTS; + else + h->flags &= ~GCRY_CIPHER_CBC_CTS; + break; + + case GCRYCTL_SET_CBC_MAC: + if (buflen) + if (h->flags & GCRY_CIPHER_CBC_CTS) + rc = GPG_ERR_INV_FLAG; + else + h->flags |= GCRY_CIPHER_CBC_MAC; + else + h->flags &= ~GCRY_CIPHER_CBC_MAC; + break; + + case GCRYCTL_SET_CCM_LENGTHS: + { + u64 params[3]; + size_t encryptedlen; + size_t aadlen; + size_t authtaglen; + + if (h->mode != GCRY_CIPHER_MODE_CCM) + return GPG_ERR_INV_CIPHER_MODE; + + if (!buffer || buflen != 3 * sizeof(u64)) + return GPG_ERR_INV_ARG; + + /* This command is used to pass additional length parameters needed + by CCM mode to initialize CBC-MAC. */ + memcpy (params, buffer, sizeof(params)); + encryptedlen = params[0]; + aadlen = params[1]; + authtaglen = params[2]; + + rc = _gcry_cipher_ccm_set_lengths (h, encryptedlen, aadlen, authtaglen); + } + break; + + case GCRYCTL_SET_TAGLEN: + if (!h || !buffer || buflen != sizeof(int) ) + return GPG_ERR_INV_ARG; + switch (h->mode) + { + case GCRY_CIPHER_MODE_OCB: + switch (*(int*)buffer) + { + case 8: case 12: case 16: + h->u_mode.ocb.taglen = *(int*)buffer; + break; + default: + rc = GPG_ERR_INV_LENGTH; /* Invalid tag length. */ + break; + } + break; + + default: + rc =GPG_ERR_INV_CIPHER_MODE; + break; + } + break; + + case GCRYCTL_DISABLE_ALGO: + /* This command expects NULL for H and BUFFER to point to an + integer with the algo number. */ + if( h || !buffer || buflen != sizeof(int) ) + return GPG_ERR_CIPHER_ALGO; + disable_cipher_algo( *(int*)buffer ); + break; + + case PRIV_CIPHERCTL_DISABLE_WEAK_KEY: /* (private) */ + if (h->spec->set_extra_info) + rc = h->spec->set_extra_info + (&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0); + else + rc = GPG_ERR_NOT_SUPPORTED; + break; + + case PRIV_CIPHERCTL_GET_INPUT_VECTOR: /* (private) */ + /* This is the input block as used in CFB and OFB mode which has + initially been set as IV. The returned format is: + 1 byte Actual length of the block in bytes. + n byte The block. + If the provided buffer is too short, an error is returned. */ + if (buflen < (1 + h->spec->blocksize)) + rc = GPG_ERR_TOO_SHORT; + else + { + unsigned char *ivp; + unsigned char *dst = buffer; + int n = h->unused; + + if (!n) + n = h->spec->blocksize; + gcry_assert (n <= h->spec->blocksize); + *dst++ = n; + ivp = h->u_iv.iv + h->spec->blocksize - n; + while (n--) + *dst++ = *ivp++; + } + break; + + case GCRYCTL_SET_SBOX: + if (h->spec->set_extra_info) + rc = h->spec->set_extra_info + (&h->context.c, GCRYCTL_SET_SBOX, buffer, buflen); + else + rc = GPG_ERR_NOT_SUPPORTED; + break; + + case GCRYCTL_SET_ALLOW_WEAK_KEY: + /* Expecting BUFFER to be NULL and buflen to be on/off flag (0 or 1). */ + if (!h || buffer || buflen > 1) + return GPG_ERR_CIPHER_ALGO; + h->marks.allow_weak_key = buflen ? 1 : 0; + break; + + default: + rc = GPG_ERR_INV_OP; + } + + return rc; +} + + +/* Return information about the cipher handle H. CMD is the kind of + * information requested. + * + * CMD may be one of: + * + * GCRYCTL_GET_TAGLEN: + * Return the length of the tag for an AE algorithm mode. An + * error is returned for modes which do not support a tag. + * BUFFER must be given as NULL. On success the result is stored + * at NBYTES. The taglen is returned in bytes. + * + * The function returns 0 on success or an error code. + */ +gcry_err_code_t +_gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) +{ + gcry_err_code_t rc = 0; + + switch (cmd) + { + case GCRYCTL_GET_TAGLEN: + if (!h || buffer || !nbytes) + rc = GPG_ERR_INV_ARG; + else + { + switch (h->mode) + { + case GCRY_CIPHER_MODE_OCB: + *nbytes = h->u_mode.ocb.taglen; + break; + + case GCRY_CIPHER_MODE_CCM: + *nbytes = h->u_mode.ccm.authlen; + break; + + case GCRY_CIPHER_MODE_EAX: + *nbytes = h->spec->blocksize; + break; + + case GCRY_CIPHER_MODE_GCM: + *nbytes = GCRY_GCM_BLOCK_LEN; + break; + + case GCRY_CIPHER_MODE_POLY1305: + *nbytes = POLY1305_TAGLEN; + break; + + default: + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + } + break; + + default: + rc = GPG_ERR_INV_OP; + } + + return rc; +} + +/* Return information about the given cipher algorithm ALGO. + + WHAT select the kind of information returned: + + GCRYCTL_GET_KEYLEN: + Return the length of the key. If the algorithm ALGO + supports multiple key lengths, the maximum supported key length + is returned. The key length is returned as number of octets. + BUFFER and NBYTES must be zero. + + GCRYCTL_GET_BLKLEN: + Return the blocklength of the algorithm ALGO counted in octets. + BUFFER and NBYTES must be zero. + + GCRYCTL_TEST_ALGO: + Returns 0 if the specified algorithm ALGO is available for use. + BUFFER and NBYTES must be zero. + + Note: Because this function is in most cases used to return an + integer value, we can make it easier for the caller to just look at + the return value. The caller will in all cases consult the value + and thereby detecting whether a error occurred or not (i.e. while + checking the block size) + */ +gcry_err_code_t +_gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) +{ + gcry_err_code_t rc = 0; + unsigned int ui; + + switch (what) + { + case GCRYCTL_GET_KEYLEN: + if (buffer || (! nbytes)) + rc = GPG_ERR_CIPHER_ALGO; + else + { + ui = cipher_get_keylen (algo); + if ((ui > 0) && (ui <= 512)) + *nbytes = (size_t) ui / 8; + else + /* The only reason for an error is an invalid algo. */ + rc = GPG_ERR_CIPHER_ALGO; + } + break; + + case GCRYCTL_GET_BLKLEN: + if (buffer || (! nbytes)) + rc = GPG_ERR_CIPHER_ALGO; + else + { + ui = cipher_get_blocksize (algo); + if ((ui > 0) && (ui < 10000)) + *nbytes = ui; + else + { + /* The only reason is an invalid algo or a strange + blocksize. */ + rc = GPG_ERR_CIPHER_ALGO; + } + } + break; + + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + rc = GPG_ERR_INV_ARG; + else + rc = check_cipher_algo (algo); + break; + + default: + rc = GPG_ERR_INV_OP; + } + + return rc; +} + + +/* This function returns length of the key for algorithm ALGO. If the + algorithm supports multiple key lengths, the maximum supported key + length is returned. On error 0 is returned. The key length is + returned as number of octets. + + This is a convenience functions which should be preferred over + gcry_cipher_algo_info because it allows for proper type + checking. */ +size_t +_gcry_cipher_get_algo_keylen (int algo) +{ + size_t n; + + if (_gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n)) + n = 0; + return n; +} + + +/* This functions returns the blocklength of the algorithm ALGO + counted in octets. On error 0 is returned. + + This is a convenience functions which should be preferred over + gcry_cipher_algo_info because it allows for proper type + checking. */ +size_t +_gcry_cipher_get_algo_blklen (int algo) +{ + size_t n; + + if (_gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n)) + n = 0; + return n; +} + + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_cipher_init (void) +{ + if (fips_mode()) + { + /* disable algorithms that are disallowed in fips */ + int idx; + gcry_cipher_spec_t *spec; + + for (idx = 0; (spec = cipher_list[idx]); idx++) + if (!spec->flags.fips) + spec->flags.disabled = 1; + } + + return 0; +} + + +/* Run the selftests for cipher algorithm ALGO with optional reporting + function REPORT. */ +gpg_error_t +_gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_err_code_t ec = 0; + gcry_cipher_spec_t *spec; + + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); + else + { + ec = GPG_ERR_CIPHER_ALGO; + if (report) + report ("cipher", algo, "module", + (spec && !spec->flags.disabled)? + "no selftest available" : + spec? "algorithm disabled" : "algorithm not found"); + } + + return gpg_error (ec); +} diff --git a/comm/third_party/libgcrypt/cipher/crc-armv8-aarch64-ce.S b/comm/third_party/libgcrypt/cipher/crc-armv8-aarch64-ce.S new file mode 100644 index 0000000000..060abdfe9a --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/crc-armv8-aarch64-ce.S @@ -0,0 +1,497 @@ +/* crc-armv8-aarch64-ce.S - ARMv8/CE PMULL accelerated CRC implementation + * Copyright (C) 2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include "asm-common-aarch64.h" + +#if defined(__AARCH64EL__) && \ + defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO) + +.cpu generic+simd+crypto + +.text + + +/* Structure of crc32_consts_s */ + +#define consts_k(idx) ((idx) * 8) +#define consts_my_p(idx) (consts_k(6) + (idx) * 8) + +/* Constants */ + +.align 6 +.Lcrc32_constants: +.Lcrc32_partial_fold_input_mask: + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +.Lcrc32_refl_shuf_shift: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +.Lcrc32_shuf_shift: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +.Lcrc32_bswap_shuf: + .byte 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08 + .byte 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + + +/* + * void _gcry_crc32r_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + * const struct crc32_consts_s *consts); + */ +.align 3 +.globl _gcry_crc32r_armv8_ce_bulk +ELF(.type _gcry_crc32r_armv8_ce_bulk,%function;) +_gcry_crc32r_armv8_ce_bulk: + /* input: + * x0: pcrc + * x1: inbuf + * x2: inlen + * x3: consts + */ + CFI_STARTPROC() + + GET_DATA_POINTER(x7, .Lcrc32_constants) + add x9, x3, #consts_k(5 - 1) + cmp x2, #128 + + b.lo .Lcrc32r_fold_by_one_setup + + eor v4.16b, v4.16b, v4.16b + add x4, x3, #consts_k(1 - 1) + ld1 {v4.s}[0], [x0] /* load pcrc */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* load 64 bytes of input */ + sub x2, x2, #64 + ld1 {v6.16b}, [x4] + eor v0.16b, v0.16b, v4.16b + + add x4, x3, #consts_k(3 - 1) + add x5, x3, #consts_my_p(0) + +.Lcrc32r_fold_by_four: + + /* Fold by 4. */ + ld1 {v16.16b-v19.16b}, [x1], #64 /* load 64 bytes of input */ + sub x2, x2, #64 + pmull v20.1q, v0.1d, v6.1d + pmull v21.1q, v1.1d, v6.1d + pmull v22.1q, v2.1d, v6.1d + pmull v23.1q, v3.1d, v6.1d + cmp x2, #64 + pmull2 v24.1q, v0.2d, v6.2d + pmull2 v25.1q, v1.2d, v6.2d + pmull2 v26.1q, v2.2d, v6.2d + pmull2 v27.1q, v3.2d, v6.2d + eor v0.16b, v20.16b, v16.16b + eor v1.16b, v21.16b, v17.16b + eor v2.16b, v22.16b, v18.16b + eor v3.16b, v23.16b, v19.16b + eor v0.16b, v0.16b, v24.16b + eor v1.16b, v1.16b, v25.16b + eor v2.16b, v2.16b, v26.16b + eor v3.16b, v3.16b, v27.16b + b.hs .Lcrc32r_fold_by_four + + ld1 {v6.16b}, [x4] + ld1 {v5.16b}, [x5] + + cmp x2, #16 + + /* Fold 4 to 1. */ + + pmull v16.1q, v0.1d, v6.1d + pmull2 v4.1q, v0.2d, v6.2d + eor v0.16b, v16.16b, v1.16b + eor v0.16b, v0.16b, v4.16b + + pmull v16.1q, v0.1d, v6.1d + pmull2 v4.1q, v0.2d, v6.2d + eor v0.16b, v16.16b, v2.16b + eor v0.16b, v0.16b, v4.16b + + pmull v16.1q, v0.1d, v6.1d + pmull2 v4.1q, v0.2d, v6.2d + eor v0.16b, v16.16b, v3.16b + eor v0.16b, v0.16b, v4.16b + + b.lo .Lcrc32r_fold_by_one_done + b .Lcrc32r_fold_by_one + +.Lcrc32r_fold_by_one_setup: + + eor v1.16b, v1.16b, v1.16b + add x4, x3, #consts_k(3 - 1) + add x5, x3, #consts_my_p(0) + sub x2, x2, #16 + ld1 {v1.s}[0], [x0] /* load pcrc */ + ld1 {v0.16b}, [x1], #16 /* load 16 bytes of input */ + cmp x2, #16 + ld1 {v6.16b}, [x4] /* load k3k4 */ + ld1 {v5.16b}, [x5] /* load my_p */ + eor v0.16b, v0.16b, v1.16b + b.lo .Lcrc32r_fold_by_one_done + +.Lcrc32r_fold_by_one: + sub x2, x2, #16 + ld1 {v2.16b}, [x1], #16 /* load 16 bytes of input */ + pmull v3.1q, v0.1d, v6.1d + pmull2 v1.1q, v0.2d, v6.2d + cmp x2, #16 + eor v0.16b, v3.16b, v2.16b + eor v0.16b, v0.16b, v1.16b + + b.hs .Lcrc32r_fold_by_one + +.Lcrc32r_fold_by_one_done: + + cmp x2, #0 + b.eq .Lcrc32r_final_fold + + /* Partial fold. */ + + add x4, x7, #.Lcrc32_refl_shuf_shift - .Lcrc32_constants + add x5, x7, #.Lcrc32_refl_shuf_shift - .Lcrc32_constants + 16 + add x6, x7, #.Lcrc32_partial_fold_input_mask - .Lcrc32_constants + sub x8, x2, #16 + add x4, x4, x2 + add x5, x5, x2 + add x6, x6, x2 + add x8, x1, x8 + + /* Load last input and add padding zeros. */ + ld1 {v4.16b}, [x4] + eor x2, x2, x2 + ld1 {v3.16b}, [x5] + ld1 {v2.16b}, [x6] + tbl v30.16b, {v0.16b}, v4.16b + ld1 {v4.16b}, [x8] + tbl v1.16b, {v0.16b}, v3.16b + + pmull v0.1q, v30.1d, v6.1d + and v2.16b, v2.16b, v4.16b + pmull2 v31.1q, v30.2d, v6.2d + orr v2.16b, v2.16b, v1.16b + eor v0.16b, v0.16b, v31.16b + eor v0.16b, v0.16b, v2.16b + +.Lcrc32r_final_fold: + + /* Final fold. */ + + eor v2.16b, v2.16b, v2.16b /* zero reg */ + ld1 {v7.16b}, [x9] + + /* reduce 128-bits to 96-bits */ + ext v6.16b, v6.16b, v6.16b, #8 /* swap high and low parts */ + mov v1.16b, v0.16b + pmull v0.1q, v0.1d, v6.1d + ext v6.16b, v5.16b, v5.16b, #8 /* swap high and low parts */ + ext v1.16b, v1.16b, v2.16b, #8 /* high to low, high zeroed */ + eor v3.16b, v0.16b, v1.16b + + /* reduce 96-bits to 64-bits */ + eor v1.16b, v1.16b, v1.16b + ext v0.16b, v3.16b, v2.16b, #4 /* [00][00][x2][x1] */ + mov v1.s[0], v3.s[0] /* [00][00][00][x0] */ + eor v3.16b, v3.16b, v3.16b + pmull v1.1q, v1.1d, v7.1d /* [00][00][xx][xx] */ + eor v0.16b, v0.16b, v1.16b /* top 64-bit are zero */ + + /* barrett reduction */ + mov v3.s[1], v0.s[0] /* [00][00][x1][00] */ + ext v0.16b, v2.16b, v0.16b, #12 /* [??][x1][??][00] */ + pmull v1.1q, v3.1d, v5.1d /* [00][xx][xx][00] */ + pmull v1.1q, v1.1d, v6.1d /* [00][xx][xx][00] */ + eor v0.16b, v0.16b, v1.16b + + /* store CRC */ + st1 {v0.s}[2], [x0] + + ret + CFI_ENDPROC() +ELF(.size _gcry_crc32r_armv8_ce_bulk,.-_gcry_crc32r_armv8_ce_bulk;) + +/* + * void _gcry_crc32r_armv8_ce_reduction_4 (u32 *pcrc, u32 data, u32 crc, + * const struct crc32_consts_s *consts); + */ +.align 3 +.globl _gcry_crc32r_armv8_ce_reduction_4 +ELF(.type _gcry_crc32r_armv8_ce_reduction_4,%function;) +_gcry_crc32r_armv8_ce_reduction_4: + /* input: + * w0: data + * w1: crc + * x2: crc32 constants + */ + CFI_STARTPROC() + + eor v0.16b, v0.16b, v0.16b + add x2, x2, #consts_my_p(0) + eor v1.16b, v1.16b, v1.16b + ld1 {v5.16b}, [x2] + + mov v0.s[0], w0 + pmull v0.1q, v0.1d, v5.1d /* [00][00][xx][xx] */ + mov v1.s[1], w1 + mov v0.s[2], v0.s[0] /* [00][x0][x1][x0] */ + pmull2 v0.1q, v0.2d, v5.2d /* [00][00][xx][xx] */ + eor v0.16b, v0.16b, v1.16b + + mov w0, v0.s[1] + + ret + CFI_ENDPROC() +ELF(.size _gcry_crc32r_armv8_ce_reduction_4,.-_gcry_crc32r_armv8_ce_reduction_4;) + +/* + * void _gcry_crc32_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + * const struct crc32_consts_s *consts); + */ +.align 3 +.globl _gcry_crc32_armv8_ce_bulk +ELF(.type _gcry_crc32_armv8_ce_bulk,%function;) +_gcry_crc32_armv8_ce_bulk: + /* input: + * x0: pcrc + * x1: inbuf + * x2: inlen + * x3: consts + */ + CFI_STARTPROC() + + GET_DATA_POINTER(x7, .Lcrc32_constants) + add x4, x7, #.Lcrc32_bswap_shuf - .Lcrc32_constants + cmp x2, #128 + ld1 {v7.16b}, [x4] + + b.lo .Lcrc32_fold_by_one_setup + + eor v4.16b, v4.16b, v4.16b + add x4, x3, #consts_k(1 - 1) + ld1 {v4.s}[0], [x0] /* load pcrc */ + ld1 {v0.16b-v3.16b}, [x1], #64 /* load 64 bytes of input */ + sub x2, x2, #64 + ld1 {v6.16b}, [x4] + eor v0.16b, v0.16b, v4.16b + ext v4.16b, v6.16b, v6.16b, #8 + tbl v0.16b, { v0.16b }, v7.16b /* byte swap */ + tbl v1.16b, { v1.16b }, v7.16b /* byte swap */ + tbl v2.16b, { v2.16b }, v7.16b /* byte swap */ + tbl v3.16b, { v3.16b }, v7.16b /* byte swap */ + + add x4, x3, #consts_k(3 - 1) + add x5, x3, #consts_my_p(0) + +.Lcrc32_fold_by_four: + + /* Fold by 4. */ + ld1 {v16.16b-v19.16b}, [x1], #64 /* load 64 bytes of input */ + sub x2, x2, #64 + tbl v16.16b, { v16.16b }, v7.16b /* byte swap */ + tbl v17.16b, { v17.16b }, v7.16b /* byte swap */ + tbl v18.16b, { v18.16b }, v7.16b /* byte swap */ + tbl v19.16b, { v19.16b }, v7.16b /* byte swap */ + cmp x2, #64 + pmull2 v20.1q, v0.2d, v4.2d + pmull2 v21.1q, v1.2d, v4.2d + pmull2 v22.1q, v2.2d, v4.2d + pmull2 v23.1q, v3.2d, v4.2d + pmull v24.1q, v0.1d, v4.1d + pmull v25.1q, v1.1d, v4.1d + pmull v26.1q, v2.1d, v4.1d + pmull v27.1q, v3.1d, v4.1d + eor v0.16b, v20.16b, v16.16b + eor v1.16b, v21.16b, v17.16b + eor v2.16b, v22.16b, v18.16b + eor v3.16b, v23.16b, v19.16b + eor v0.16b, v0.16b, v24.16b + eor v1.16b, v1.16b, v25.16b + eor v2.16b, v2.16b, v26.16b + eor v3.16b, v3.16b, v27.16b + b.hs .Lcrc32_fold_by_four + + ld1 {v6.16b}, [x4] + ld1 {v5.16b}, [x5] + ext v6.16b, v6.16b, v6.16b, #8 + ext v5.16b, v5.16b, v5.16b, #8 + + cmp x2, #16 + + /* Fold 4 to 1. */ + + pmull2 v16.1q, v0.2d, v6.2d + pmull v4.1q, v0.1d, v6.1d + eor v0.16b, v16.16b, v1.16b + eor v0.16b, v0.16b, v4.16b + + pmull2 v16.1q, v0.2d, v6.2d + pmull v4.1q, v0.1d, v6.1d + eor v0.16b, v16.16b, v2.16b + eor v0.16b, v0.16b, v4.16b + + pmull2 v16.1q, v0.2d, v6.2d + pmull v4.1q, v0.1d, v6.1d + eor v0.16b, v16.16b, v3.16b + eor v0.16b, v0.16b, v4.16b + + b.lo .Lcrc32_fold_by_one_done + b .Lcrc32_fold_by_one + +.Lcrc32_fold_by_one_setup: + + eor v1.16b, v1.16b, v1.16b + add x4, x3, #consts_k(3 - 1) + add x5, x3, #consts_my_p(0) + ld1 {v1.s}[0], [x0] /* load pcrc */ + sub x2, x2, #16 + ld1 {v0.16b}, [x1], #16 /* load 16 bytes of input */ + ld1 {v6.16b}, [x4] /* load k3k4 */ + ld1 {v5.16b}, [x5] /* load my_p */ + eor v0.16b, v0.16b, v1.16b + cmp x2, #16 + ext v6.16b, v6.16b, v6.16b, #8 /* swap high and low parts */ + ext v5.16b, v5.16b, v5.16b, #8 /* swap high and low parts */ + tbl v0.16b, { v0.16b }, v7.16b /* byte swap */ + b.lo .Lcrc32_fold_by_one_done + +.Lcrc32_fold_by_one: + sub x2, x2, #16 + ld1 {v2.16b}, [x1], #16 /* load 16 bytes of input */ + pmull2 v3.1q, v0.2d, v6.2d + tbl v2.16b, { v2.16b }, v7.16b /* byte swap */ + pmull v1.1q, v0.1d, v6.1d + cmp x2, #16 + eor v0.16b, v3.16b, v2.16b + eor v0.16b, v0.16b, v1.16b + + b.hs .Lcrc32_fold_by_one + +.Lcrc32_fold_by_one_done: + + cmp x2, #0 + b.eq .Lcrc32_final_fold + + /* Partial fold. */ + + add x4, x7, #.Lcrc32_refl_shuf_shift - .Lcrc32_constants + 32 + add x5, x7, #.Lcrc32_shuf_shift - .Lcrc32_constants + 16 + add x6, x7, #.Lcrc32_partial_fold_input_mask - .Lcrc32_constants + sub x8, x2, #16 + sub x4, x4, x2 + add x5, x5, x2 + add x6, x6, x2 + add x8, x1, x8 + + /* Load last input and add padding zeros. */ + ld1 {v4.16b}, [x4] + eor x2, x2, x2 + ld1 {v3.16b}, [x5] + ld1 {v2.16b}, [x6] + tbl v30.16b, {v0.16b}, v4.16b + ld1 {v4.16b}, [x8] + tbl v1.16b, {v0.16b}, v3.16b + and v2.16b, v2.16b, v4.16b + + pmull2 v0.1q, v30.2d, v6.2d + orr v2.16b, v2.16b, v1.16b + pmull v1.1q, v30.1d, v6.1d + tbl v2.16b, {v2.16b}, v7.16b /* byte swap */ + eor v0.16b, v0.16b, v1.16b + eor v0.16b, v0.16b, v2.16b + +.Lcrc32_final_fold: + + /* Final fold. */ + + eor v2.16b, v2.16b, v2.16b /* zero reg */ + + /* reduce 128-bits to 96-bits */ + add x4, x3, #consts_k(4) + ext v3.16b, v6.16b, v6.16b, #8 /* swap high and low parts */ + eor v6.16b, v6.16b, v6.16b + mov v1.16b, v0.16b + pmull2 v0.1q, v0.2d, v3.2d + ld1 {v6.d}[1], [x4] /* load k4 */ + ext v1.16b, v2.16b, v1.16b, #8 /* low to high, low zeroed */ + eor v3.16b, v0.16b, v1.16b /* bottom 32-bit are zero */ + + /* reduce 96-bits to 64-bits */ + eor v0.16b, v0.16b, v0.16b + eor v1.16b, v1.16b, v1.16b + mov v0.s[1], v3.s[1] /* [00][00][x1][00] */ + mov v1.s[2], v3.s[3] /* [00][x3][00][00] */ + mov v0.s[2], v3.s[2] /* [00][x2][x1][00] */ + eor v3.16b, v3.16b, v3.16b + pmull2 v1.1q, v1.2d, v6.2d /* [00][xx][xx][00] */ + eor v0.16b, v0.16b, v1.16b /* top and bottom 32-bit are zero */ + + /* barrett reduction */ + mov v3.s[0], v0.s[1] /* [00][00][00][x1] */ + pmull2 v0.1q, v0.2d, v5.2d /* [00][xx][xx][xx] */ + ext v0.16b, v0.16b, v2.16b, #4 /* [00][00][xx][xx] */ + pmull v0.1q, v0.1d, v5.1d + eor v0.16b, v0.16b, v3.16b + + /* store CRC in input endian */ + rev32 v0.8b, v0.8b /* byte swap */ + st1 {v0.s}[0], [x0] + + ret + CFI_ENDPROC() +ELF(.size _gcry_crc32_armv8_ce_bulk,.-_gcry_crc32_armv8_ce_bulk;) + +/* + * void _gcry_crc32_armv8_ce_reduction_4 (u32 *pcrc, u32 data, u32 crc, + * const struct crc32_consts_s *consts); + */ +.align 3 +.globl _gcry_crc32_armv8_ce_reduction_4 +ELF(.type _gcry_crc32_armv8_ce_reduction_4,%function;) +_gcry_crc32_armv8_ce_reduction_4: + /* input: + * w0: data + * w1: crc + * x2: crc32 constants + */ + CFI_STARTPROC() + + eor v0.16b, v0.16b, v0.16b + add x2, x2, #consts_my_p(0) + eor v1.16b, v1.16b, v1.16b + ld1 {v5.16b}, [x2] + + mov v0.s[1], w0 + pmull v0.1q, v0.1d, v5.1d /* [00][xx][xx][00] */ + mov v1.s[0], w1 + pmull2 v0.1q, v0.2d, v5.2d /* [00][00][xx][xx] */ + eor v0.16b, v0.16b, v1.16b + + rev32 v0.8b, v0.8b /* Return in input endian */ + mov w0, v0.s[0] + + ret + CFI_ENDPROC() +ELF(.size _gcry_crc32_armv8_ce_reduction_4,.-_gcry_crc32_armv8_ce_reduction_4;) + +#endif diff --git a/comm/third_party/libgcrypt/cipher/crc-armv8-ce.c b/comm/third_party/libgcrypt/cipher/crc-armv8-ce.c new file mode 100644 index 0000000000..17e5554821 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/crc-armv8-ce.c @@ -0,0 +1,229 @@ +/* crc-armv8-ce.c - ARMv8-CE PMULL accelerated CRC implementation + * Copyright (C) 2019 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include +#include +#include +#include + +#include "g10lib.h" + +#include "bithelp.h" +#include "bufhelp.h" + + +#if defined(ENABLE_ARM_CRYPTO_SUPPORT) && defined(__AARCH64EL__) && \ + defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO) + + +#define ALIGNED_16 __attribute__ ((aligned (16))) + + +struct u16_unaligned_s +{ + u16 a; +} __attribute__((packed, aligned (1), may_alias)); + +struct u32_unaligned_s +{ + u32 a; +} __attribute__((packed, aligned (1), may_alias)); + + +/* Constants structure for generic reflected/non-reflected CRC32 PMULL + * functions. */ +struct crc32_consts_s +{ + /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */ + u64 k[6]; + /* my_p: { floor(x^64 / P(x)), P(x) } */ + u64 my_p[2]; +}; + +/* PMULL constants for CRC32 and CRC32RFC1510. */ +static const struct crc32_consts_s crc32_consts ALIGNED_16 = +{ + { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */ + U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */ + U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */ + U64_C(0x163cd6124), 0 /* y = 2 */ + }, + { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */ + U64_C(0x1f7011641), U64_C(0x1db710641) + } +}; + +/* PMULL constants for CRC24RFC2440 (polynomial multiplied with xâ¸). */ +static const struct crc32_consts_s crc24rfc2440_consts ALIGNED_16 = +{ + { /* k[6] = x^(32*y) mod P(x) << 32*/ + U64_C(0x08289a00) << 32, U64_C(0x74b44a00) << 32, /* y = { 17, 15 } */ + U64_C(0xc4b14d00) << 32, U64_C(0xfd7e0c00) << 32, /* y = { 5, 3 } */ + U64_C(0xd9fe8c00) << 32, 0 /* y = 2 */ + }, + { /* my_p[2] = { floor(x^64 / P(x)), P(x) } */ + U64_C(0x1f845fe24), U64_C(0x1864cfb00) + } +}; + + +u32 _gcry_crc32r_armv8_ce_reduction_4 (u32 data, u32 crc, + const struct crc32_consts_s *consts); +void _gcry_crc32r_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts); + +u32 _gcry_crc32_armv8_ce_reduction_4 (u32 data, u32 crc, + const struct crc32_consts_s *consts); +void _gcry_crc32_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts); + + +static inline void +crc32r_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + u32 crc = *pcrc; + u32 data; + + while (inlen >= 4) + { + data = ((const struct u32_unaligned_s *)inbuf)->a; + data ^= crc; + + inlen -= 4; + inbuf += 4; + + crc = _gcry_crc32r_armv8_ce_reduction_4 (data, 0, consts); + } + + switch (inlen) + { + case 0: + break; + case 1: + data = inbuf[0]; + data ^= crc; + data <<= 24; + crc >>= 8; + crc = _gcry_crc32r_armv8_ce_reduction_4 (data, crc, consts); + break; + case 2: + data = ((const struct u16_unaligned_s *)inbuf)->a; + data ^= crc; + data <<= 16; + crc >>= 16; + crc = _gcry_crc32r_armv8_ce_reduction_4 (data, crc, consts); + break; + case 3: + data = ((const struct u16_unaligned_s *)inbuf)->a; + data |= inbuf[2] << 16; + data ^= crc; + data <<= 8; + crc >>= 24; + crc = _gcry_crc32r_armv8_ce_reduction_4 (data, crc, consts); + break; + } + + *pcrc = crc; +} + +static inline void +crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + u32 crc = *pcrc; + u32 data; + + while (inlen >= 4) + { + data = ((const struct u32_unaligned_s *)inbuf)->a; + data ^= crc; + data = _gcry_bswap32(data); + + inlen -= 4; + inbuf += 4; + + crc = _gcry_crc32_armv8_ce_reduction_4 (data, 0, consts); + } + + switch (inlen) + { + case 0: + break; + case 1: + data = inbuf[0]; + data ^= crc; + data = data & 0xffU; + crc = _gcry_bswap32(crc >> 8); + crc = _gcry_crc32_armv8_ce_reduction_4 (data, crc, consts); + break; + case 2: + data = ((const struct u16_unaligned_s *)inbuf)->a; + data ^= crc; + data = _gcry_bswap32(data << 16); + crc = _gcry_bswap32(crc >> 16); + crc = _gcry_crc32_armv8_ce_reduction_4 (data, crc, consts); + break; + case 3: + data = ((const struct u16_unaligned_s *)inbuf)->a; + data |= inbuf[2] << 16; + data ^= crc; + data = _gcry_bswap32(data << 8); + crc = crc & 0xff000000U; + crc = _gcry_crc32_armv8_ce_reduction_4 (data, crc, consts); + break; + } + + *pcrc = crc; +} + +void +_gcry_crc32_armv8_ce_pmull (u32 *pcrc, const byte *inbuf, size_t inlen) +{ + const struct crc32_consts_s *consts = &crc32_consts; + + if (!inlen) + return; + + if (inlen >= 16) + _gcry_crc32r_armv8_ce_bulk (pcrc, inbuf, inlen, consts); + else + crc32r_less_than_16 (pcrc, inbuf, inlen, consts); +} + +void +_gcry_crc24rfc2440_armv8_ce_pmull (u32 *pcrc, const byte *inbuf, size_t inlen) +{ + const struct crc32_consts_s *consts = &crc24rfc2440_consts; + + if (!inlen) + return; + + /* Note: *pcrc in input endian. */ + + if (inlen >= 16) + _gcry_crc32_armv8_ce_bulk (pcrc, inbuf, inlen, consts); + else + crc32_less_than_16 (pcrc, inbuf, inlen, consts); +} + +#endif diff --git a/comm/third_party/libgcrypt/cipher/crc-intel-pclmul.c b/comm/third_party/libgcrypt/cipher/crc-intel-pclmul.c new file mode 100644 index 0000000000..8c8b1915ab --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/crc-intel-pclmul.c @@ -0,0 +1,939 @@ +/* crc-intel-pclmul.c - Intel PCLMUL accelerated CRC implementation + * Copyright (C) 2016 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include +#include +#include +#include + +#include "g10lib.h" + +#include "bithelp.h" +#include "bufhelp.h" + + +#if defined(ENABLE_PCLMUL_SUPPORT) && defined(ENABLE_SSE41_SUPPORT) && \ + __GNUC__ >= 4 && \ + ((defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)) + + +#if _GCRY_GCC_VERSION >= 40400 /* 4.4 */ +/* Prevent compiler from issuing SSE instructions between asm blocks. */ +# pragma GCC target("no-sse") +#endif +#if __clang__ +# pragma clang attribute push (__attribute__((target("no-sse"))), apply_to = function) +#endif + + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function)) + +#define ASM_FUNC_ATTR NO_INSTRUMENT_FUNCTION +#define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE + + +#define ALIGNED_16 __attribute__ ((aligned (16))) + + +struct u16_unaligned_s +{ + u16 a; +} __attribute__((packed, aligned (1), may_alias)); + + +/* Constants structure for generic reflected/non-reflected CRC32 CLMUL + * functions. */ +struct crc32_consts_s +{ + /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */ + u64 k[6]; + /* my_p: { floor(x^64 / P(x)), P(x) } */ + u64 my_p[2]; +}; + + +/* CLMUL constants for CRC32 and CRC32RFC1510. */ +static const struct crc32_consts_s crc32_consts ALIGNED_16 = +{ + { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */ + U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */ + U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */ + U64_C(0x163cd6124), 0 /* y = 2 */ + }, + { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */ + U64_C(0x1f7011641), U64_C(0x1db710641) + } +}; + +/* CLMUL constants for CRC24RFC2440 (polynomial multiplied with xâ¸). */ +static const struct crc32_consts_s crc24rfc2440_consts ALIGNED_16 = +{ + { /* k[6] = x^(32*y) mod P(x) << 32*/ + U64_C(0x08289a00) << 32, U64_C(0x74b44a00) << 32, /* y = { 17, 15 } */ + U64_C(0xc4b14d00) << 32, U64_C(0xfd7e0c00) << 32, /* y = { 5, 3 } */ + U64_C(0xd9fe8c00) << 32, 0 /* y = 2 */ + }, + { /* my_p[2] = { floor(x^64 / P(x)), P(x) } */ + U64_C(0x1f845fe24), U64_C(0x1864cfb00) + } +}; + +/* Common constants for CRC32 algorithms. */ +static const byte crc32_refl_shuf_shift[3 * 16] ALIGNED_16 = + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; +static const byte crc32_shuf_shift[3 * 16] ALIGNED_16 = + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; +static const byte *crc32_bswap_shuf = &crc32_shuf_shift[16]; +static const byte crc32_partial_fold_input_mask[16 + 16] ALIGNED_16 = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; +static const u64 crc32_merge9to15_shuf[15 - 9 + 1][2] ALIGNED_16 = + { + { U64_C(0x0706050403020100), U64_C(0xffffffffffffff0f) }, /* 9 */ + { U64_C(0x0706050403020100), U64_C(0xffffffffffff0f0e) }, + { U64_C(0x0706050403020100), U64_C(0xffffffffff0f0e0d) }, + { U64_C(0x0706050403020100), U64_C(0xffffffff0f0e0d0c) }, + { U64_C(0x0706050403020100), U64_C(0xffffff0f0e0d0c0b) }, + { U64_C(0x0706050403020100), U64_C(0xffff0f0e0d0c0b0a) }, + { U64_C(0x0706050403020100), U64_C(0xff0f0e0d0c0b0a09) }, /* 15 */ + }; +static const u64 crc32_merge5to7_shuf[7 - 5 + 1][2] ALIGNED_16 = + { + { U64_C(0xffffff0703020100), U64_C(0xffffffffffffffff) }, /* 5 */ + { U64_C(0xffff070603020100), U64_C(0xffffffffffffffff) }, + { U64_C(0xff07060503020100), U64_C(0xffffffffffffffff) }, /* 7 */ + }; + +/* PCLMUL functions for reflected CRC32. */ +static ASM_FUNC_ATTR_INLINE void +crc32_reflected_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + if (inlen >= 8 * 16) + { + asm volatile ("movd %[crc], %%xmm4\n\t" + "movdqu %[inbuf_0], %%xmm0\n\t" + "movdqu %[inbuf_1], %%xmm1\n\t" + "movdqu %[inbuf_2], %%xmm2\n\t" + "movdqu %[inbuf_3], %%xmm3\n\t" + "pxor %%xmm4, %%xmm0\n\t" + : + : [inbuf_0] "m" (inbuf[0 * 16]), + [inbuf_1] "m" (inbuf[1 * 16]), + [inbuf_2] "m" (inbuf[2 * 16]), + [inbuf_3] "m" (inbuf[3 * 16]), + [crc] "m" (*pcrc) + ); + + inbuf += 4 * 16; + inlen -= 4 * 16; + + asm volatile ("movdqa %[k1k2], %%xmm4\n\t" + : + : [k1k2] "m" (consts->k[1 - 1]) + ); + + /* Fold by 4. */ + while (inlen >= 4 * 16) + { + asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t" + "movdqa %%xmm0, %%xmm6\n\t" + "pclmulqdq $0x00, %%xmm4, %%xmm0\n\t" + "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm0\n\t" + "pxor %%xmm6, %%xmm0\n\t" + + "movdqu %[inbuf_1], %%xmm5\n\t" + "movdqa %%xmm1, %%xmm6\n\t" + "pclmulqdq $0x00, %%xmm4, %%xmm1\n\t" + "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm1\n\t" + "pxor %%xmm6, %%xmm1\n\t" + + "movdqu %[inbuf_2], %%xmm5\n\t" + "movdqa %%xmm2, %%xmm6\n\t" + "pclmulqdq $0x00, %%xmm4, %%xmm2\n\t" + "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm2\n\t" + "pxor %%xmm6, %%xmm2\n\t" + + "movdqu %[inbuf_3], %%xmm5\n\t" + "movdqa %%xmm3, %%xmm6\n\t" + "pclmulqdq $0x00, %%xmm4, %%xmm3\n\t" + "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm6, %%xmm3\n\t" + : + : [inbuf_0] "m" (inbuf[0 * 16]), + [inbuf_1] "m" (inbuf[1 * 16]), + [inbuf_2] "m" (inbuf[2 * 16]), + [inbuf_3] "m" (inbuf[3 * 16]) + ); + + inbuf += 4 * 16; + inlen -= 4 * 16; + } + + asm volatile ("movdqa %[k3k4], %%xmm6\n\t" + "movdqa %[my_p], %%xmm5\n\t" + : + : [k3k4] "m" (consts->k[3 - 1]), + [my_p] "m" (consts->my_p[0]) + ); + + /* Fold 4 to 1. */ + + asm volatile ("movdqa %%xmm0, %%xmm4\n\t" + "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" + "pxor %%xmm1, %%xmm0\n\t" + "pxor %%xmm4, %%xmm0\n\t" + + "movdqa %%xmm0, %%xmm4\n\t" + "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" + "pxor %%xmm2, %%xmm0\n\t" + "pxor %%xmm4, %%xmm0\n\t" + + "movdqa %%xmm0, %%xmm4\n\t" + "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" + "pxor %%xmm3, %%xmm0\n\t" + "pxor %%xmm4, %%xmm0\n\t" + : + : + ); + } + else + { + asm volatile ("movd %[crc], %%xmm1\n\t" + "movdqu %[inbuf], %%xmm0\n\t" + "movdqa %[k3k4], %%xmm6\n\t" + "pxor %%xmm1, %%xmm0\n\t" + "movdqa %[my_p], %%xmm5\n\t" + : + : [inbuf] "m" (*inbuf), + [crc] "m" (*pcrc), + [k3k4] "m" (consts->k[3 - 1]), + [my_p] "m" (consts->my_p[0]) + ); + + inbuf += 16; + inlen -= 16; + } + + /* Fold by 1. */ + if (inlen >= 16) + { + while (inlen >= 16) + { + /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */ + asm volatile ("movdqu %[inbuf], %%xmm2\n\t" + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t" + "pxor %%xmm2, %%xmm0\n\t" + "pxor %%xmm1, %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf) + ); + + inbuf += 16; + inlen -= 16; + } + } + + /* Partial fold. */ + if (inlen) + { + /* Load last input and add padding zeros. */ + asm volatile ("movdqu %[shr_shuf], %%xmm3\n\t" + "movdqu %[shl_shuf], %%xmm4\n\t" + "movdqu %[mask], %%xmm2\n\t" + + "movdqa %%xmm0, %%xmm1\n\t" + "pshufb %%xmm4, %%xmm0\n\t" + "movdqu %[inbuf], %%xmm4\n\t" + "pshufb %%xmm3, %%xmm1\n\t" + "pand %%xmm4, %%xmm2\n\t" + "por %%xmm1, %%xmm2\n\t" + + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t" + "pxor %%xmm2, %%xmm0\n\t" + "pxor %%xmm1, %%xmm0\n\t" + : + : [inbuf] "m" (*(inbuf - 16 + inlen)), + [mask] "m" (crc32_partial_fold_input_mask[inlen]), + [shl_shuf] "m" (crc32_refl_shuf_shift[inlen]), + [shr_shuf] "m" (crc32_refl_shuf_shift[inlen + 16]) + ); + + inbuf += inlen; + inlen -= inlen; + } + + /* Final fold. */ + asm volatile (/* reduce 128-bits to 96-bits */ + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t" + "psrldq $8, %%xmm1\n\t" + "pxor %%xmm1, %%xmm0\n\t" + + /* reduce 96-bits to 64-bits */ + "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */ + "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */ + "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */ + "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */ + + /* barrett reduction */ + "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */ + "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */ + "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ + "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ + "pxor %%xmm1, %%xmm0\n\t" + + /* store CRC */ + "pextrd $2, %%xmm0, %[out]\n\t" + : [out] "=m" (*pcrc) + : [k5] "m" (consts->k[5 - 1]) + ); +} + +static ASM_FUNC_ATTR_INLINE void +crc32_reflected_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + if (inlen < 4) + { + u32 crc = *pcrc; + u32 data; + + asm volatile ("movdqa %[my_p], %%xmm5\n\t" + : + : [my_p] "m" (consts->my_p[0]) + ); + + if (inlen == 1) + { + data = inbuf[0]; + data ^= crc; + data <<= 24; + crc >>= 8; + } + else if (inlen == 2) + { + data = ((const struct u16_unaligned_s *)inbuf)->a; + data ^= crc; + data <<= 16; + crc >>= 16; + } + else + { + data = ((const struct u16_unaligned_s *)inbuf)->a; + data |= inbuf[2] << 16; + data ^= crc; + data <<= 8; + crc >>= 24; + } + + /* Barrett reduction */ + asm volatile ("movd %[in], %%xmm0\n\t" + "movd %[crc], %%xmm1\n\t" + + "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ + "psllq $32, %%xmm1\n\t" + "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */ + "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ + "pxor %%xmm1, %%xmm0\n\t" + + "pextrd $1, %%xmm0, %[out]\n\t" + : [out] "=m" (*pcrc) + : [in] "rm" (data), + [crc] "rm" (crc) + ); + } + else if (inlen == 4) + { + /* Barrett reduction */ + asm volatile ("movd %[crc], %%xmm1\n\t" + "movd %[in], %%xmm0\n\t" + "movdqa %[my_p], %%xmm5\n\t" + "pxor %%xmm1, %%xmm0\n\t" + + "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ + "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */ + "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ + + "pextrd $1, %%xmm0, %[out]\n\t" + : [out] "=m" (*pcrc) + : [in] "m" (*inbuf), + [crc] "m" (*pcrc), + [my_p] "m" (consts->my_p[0]) + ); + } + else + { + asm volatile ("movdqu %[shuf], %%xmm4\n\t" + "movd %[crc], %%xmm1\n\t" + "movdqa %[my_p], %%xmm5\n\t" + "movdqa %[k3k4], %%xmm6\n\t" + : + : [shuf] "m" (crc32_refl_shuf_shift[inlen]), + [crc] "m" (*pcrc), + [my_p] "m" (consts->my_p[0]), + [k3k4] "m" (consts->k[3 - 1]) + ); + + if (inlen >= 8) + { + asm volatile ("movq %[inbuf], %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf) + ); + if (inlen > 8) + { + asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/ + "movq %[inbuf_tail], %%xmm2\n\t" + "punpcklqdq %%xmm2, %%xmm0\n\t" + "pshufb %[merge_shuf], %%xmm0\n\t" + : + : [inbuf_tail] "m" (inbuf[inlen - 8]), + [merge_shuf] "m" + (*crc32_merge9to15_shuf[inlen - 9]) + ); + } + } + else + { + asm volatile ("movd %[inbuf], %%xmm0\n\t" + "pinsrd $1, %[inbuf_tail], %%xmm0\n\t" + "pshufb %[merge_shuf], %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf), + [inbuf_tail] "m" (inbuf[inlen - 4]), + [merge_shuf] "m" + (*crc32_merge5to7_shuf[inlen - 5]) + ); + } + + /* Final fold. */ + asm volatile ("pxor %%xmm1, %%xmm0\n\t" + "pshufb %%xmm4, %%xmm0\n\t" + + /* reduce 128-bits to 96-bits */ + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t" + "psrldq $8, %%xmm1\n\t" + "pxor %%xmm1, %%xmm0\n\t" /* top 32-bit are zero */ + + /* reduce 96-bits to 64-bits */ + "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */ + "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */ + "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */ + "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */ + + /* barrett reduction */ + "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */ + "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */ + "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ + "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ + "pxor %%xmm1, %%xmm0\n\t" + + /* store CRC */ + "pextrd $2, %%xmm0, %[out]\n\t" + : [out] "=m" (*pcrc) + : [k5] "m" (consts->k[5 - 1]) + ); + } +} + +/* PCLMUL functions for non-reflected CRC32. */ +static ASM_FUNC_ATTR_INLINE void +crc32_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + asm volatile ("movdqa %[bswap], %%xmm7\n\t" + : + : [bswap] "m" (*crc32_bswap_shuf) + ); + + if (inlen >= 8 * 16) + { + asm volatile ("movd %[crc], %%xmm4\n\t" + "movdqu %[inbuf_0], %%xmm0\n\t" + "movdqu %[inbuf_1], %%xmm1\n\t" + "movdqu %[inbuf_2], %%xmm2\n\t" + "pxor %%xmm4, %%xmm0\n\t" + "movdqu %[inbuf_3], %%xmm3\n\t" + "pshufb %%xmm7, %%xmm0\n\t" + "pshufb %%xmm7, %%xmm1\n\t" + "pshufb %%xmm7, %%xmm2\n\t" + "pshufb %%xmm7, %%xmm3\n\t" + : + : [inbuf_0] "m" (inbuf[0 * 16]), + [inbuf_1] "m" (inbuf[1 * 16]), + [inbuf_2] "m" (inbuf[2 * 16]), + [inbuf_3] "m" (inbuf[3 * 16]), + [crc] "m" (*pcrc) + ); + + inbuf += 4 * 16; + inlen -= 4 * 16; + + asm volatile ("movdqa %[k1k2], %%xmm4\n\t" + : + : [k1k2] "m" (consts->k[1 - 1]) + ); + + /* Fold by 4. */ + while (inlen >= 4 * 16) + { + asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t" + "movdqa %%xmm0, %%xmm6\n\t" + "pshufb %%xmm7, %%xmm5\n\t" + "pclmulqdq $0x01, %%xmm4, %%xmm0\n\t" + "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm0\n\t" + "pxor %%xmm6, %%xmm0\n\t" + + "movdqu %[inbuf_1], %%xmm5\n\t" + "movdqa %%xmm1, %%xmm6\n\t" + "pshufb %%xmm7, %%xmm5\n\t" + "pclmulqdq $0x01, %%xmm4, %%xmm1\n\t" + "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm1\n\t" + "pxor %%xmm6, %%xmm1\n\t" + + "movdqu %[inbuf_2], %%xmm5\n\t" + "movdqa %%xmm2, %%xmm6\n\t" + "pshufb %%xmm7, %%xmm5\n\t" + "pclmulqdq $0x01, %%xmm4, %%xmm2\n\t" + "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm2\n\t" + "pxor %%xmm6, %%xmm2\n\t" + + "movdqu %[inbuf_3], %%xmm5\n\t" + "movdqa %%xmm3, %%xmm6\n\t" + "pshufb %%xmm7, %%xmm5\n\t" + "pclmulqdq $0x01, %%xmm4, %%xmm3\n\t" + "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm6, %%xmm3\n\t" + : + : [inbuf_0] "m" (inbuf[0 * 16]), + [inbuf_1] "m" (inbuf[1 * 16]), + [inbuf_2] "m" (inbuf[2 * 16]), + [inbuf_3] "m" (inbuf[3 * 16]) + ); + + inbuf += 4 * 16; + inlen -= 4 * 16; + } + + asm volatile ("movdqa %[k3k4], %%xmm6\n\t" + "movdqa %[my_p], %%xmm5\n\t" + : + : [k3k4] "m" (consts->k[3 - 1]), + [my_p] "m" (consts->my_p[0]) + ); + + /* Fold 4 to 1. */ + + asm volatile ("movdqa %%xmm0, %%xmm4\n\t" + "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t" + "pxor %%xmm1, %%xmm0\n\t" + "pxor %%xmm4, %%xmm0\n\t" + + "movdqa %%xmm0, %%xmm4\n\t" + "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t" + "pxor %%xmm2, %%xmm0\n\t" + "pxor %%xmm4, %%xmm0\n\t" + + "movdqa %%xmm0, %%xmm4\n\t" + "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t" + "pxor %%xmm3, %%xmm0\n\t" + "pxor %%xmm4, %%xmm0\n\t" + : + : + ); + } + else + { + asm volatile ("movd %[crc], %%xmm1\n\t" + "movdqu %[inbuf], %%xmm0\n\t" + "movdqa %[k3k4], %%xmm6\n\t" + "pxor %%xmm1, %%xmm0\n\t" + "movdqa %[my_p], %%xmm5\n\t" + "pshufb %%xmm7, %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf), + [crc] "m" (*pcrc), + [k3k4] "m" (consts->k[3 - 1]), + [my_p] "m" (consts->my_p[0]) + ); + + inbuf += 16; + inlen -= 16; + } + + /* Fold by 1. */ + if (inlen >= 16) + { + while (inlen >= 16) + { + /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */ + asm volatile ("movdqu %[inbuf], %%xmm2\n\t" + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t" + "pshufb %%xmm7, %%xmm2\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm1\n\t" + "pxor %%xmm2, %%xmm0\n\t" + "pxor %%xmm1, %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf) + ); + + inbuf += 16; + inlen -= 16; + } + } + + /* Partial fold. */ + if (inlen) + { + /* Load last input and add padding zeros. */ + asm volatile ("movdqu %[shl_shuf], %%xmm4\n\t" + "movdqu %[shr_shuf], %%xmm3\n\t" + "movdqu %[mask], %%xmm2\n\t" + + "movdqa %%xmm0, %%xmm1\n\t" + "pshufb %%xmm4, %%xmm0\n\t" + "movdqu %[inbuf], %%xmm4\n\t" + "pshufb %%xmm3, %%xmm1\n\t" + "pand %%xmm4, %%xmm2\n\t" + "por %%xmm1, %%xmm2\n\t" + + "pshufb %%xmm7, %%xmm2\n\t" + + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t" + "pclmulqdq $0x10, %%xmm6, %%xmm1\n\t" + "pxor %%xmm2, %%xmm0\n\t" + "pxor %%xmm1, %%xmm0\n\t" + : + : [inbuf] "m" (*(inbuf - 16 + inlen)), + [mask] "m" (crc32_partial_fold_input_mask[inlen]), + [shl_shuf] "m" (crc32_refl_shuf_shift[32 - inlen]), + [shr_shuf] "m" (crc32_shuf_shift[inlen + 16]) + ); + + inbuf += inlen; + inlen -= inlen; + } + + /* Final fold. */ + asm volatile (/* reduce 128-bits to 96-bits */ + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm0\n\t" + "pslldq $8, %%xmm1\n\t" + "pxor %%xmm1, %%xmm0\n\t" /* bottom 32-bit are zero */ + + /* reduce 96-bits to 64-bits */ + "pshufd $0x30, %%xmm0, %%xmm1\n\t" /* [00][x>>96][00][00] */ + "pshufd $0x24, %%xmm0, %%xmm0\n\t" /* [00][xx][xx][00] */ + "pclmulqdq $0x01, %[k5], %%xmm1\n\t" /* [00][xx][xx][00] */ + "pxor %%xmm1, %%xmm0\n\t" /* top and bottom 32-bit are zero */ + + /* barrett reduction */ + "pshufd $0x01, %%xmm0, %%xmm1\n\t" /* [00][00][00][x>>32] */ + "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][xx] */ + "psrldq $4, %%xmm0\n\t" /* [00][00][xx][xx] */ + "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" + "pxor %%xmm1, %%xmm0\n\t" + + /* store CRC in input endian */ + "movd %%xmm0, %%eax\n\t" + "bswapl %%eax\n\t" + "movl %%eax, %[out]\n\t" + : [out] "=m" (*pcrc) + : [k5] "m" (consts->k[5 - 1]) + : "eax" ); +} + +static ASM_FUNC_ATTR_INLINE void +crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + if (inlen < 4) + { + u32 crc = *pcrc; + u32 data; + + asm volatile ("movdqa %[my_p], %%xmm5\n\t" + : + : [my_p] "m" (consts->my_p[0]) + ); + + if (inlen == 1) + { + data = inbuf[0]; + data ^= crc; + data = _gcry_bswap32(data << 24); + crc = _gcry_bswap32(crc >> 8); + } + else if (inlen == 2) + { + data = ((const struct u16_unaligned_s *)inbuf)->a; + data ^= crc; + data = _gcry_bswap32(data << 16); + crc = _gcry_bswap32(crc >> 16); + } + else + { + data = ((const struct u16_unaligned_s *)inbuf)->a; + data |= inbuf[2] << 16; + data ^= crc; + data = _gcry_bswap32(data << 8); + crc = _gcry_bswap32(crc >> 24); + } + + /* Barrett reduction */ + asm volatile ("movd %[in], %%xmm0\n\t" + "psllq $32, %%xmm0\n\t" /* [00][00][xx][00] */ + "movd %[crc], %%xmm1\n\t" + + "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][00] */ + "pclmulqdq $0x11, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ + "pxor %%xmm1, %%xmm0\n\t" + + /* store CRC in input endian */ + "movd %%xmm0, %%eax\n\t" + "bswapl %%eax\n\t" + "movl %%eax, %[out]\n\t" + : [out] "=m" (*pcrc) + : [in] "r" (data), + [crc] "r" (crc) + : "eax" ); + } + else if (inlen == 4) + { + /* Barrett reduction */ + asm volatile ("movd %[crc], %%xmm0\n\t" + "movd %[in], %%xmm1\n\t" + "movdqa %[my_p], %%xmm5\n\t" + : + : [in] "m" (*inbuf), + [crc] "m" (*pcrc), + [my_p] "m" (consts->my_p[0]) + : "cc" ); + + asm volatile ("pxor %%xmm1, %%xmm0\n\t" + "pshufb %[bswap], %%xmm0\n\t" /* [xx][00][00][00] */ + + "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][00] */ + "pclmulqdq $0x11, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ + : + : [bswap] "m" (*crc32_bswap_shuf) + : "cc" ); + + asm volatile (/* store CRC in input endian */ + "movd %%xmm0, %%eax\n\t" + "bswapl %%eax\n\t" + "movl %%eax, %[out]\n\t" + : [out] "=m" (*pcrc) + : + : "eax", "cc" ); + } + else + { + asm volatile ("movdqu %[shuf], %%xmm7\n\t" + "movd %[crc], %%xmm1\n\t" + "movdqa %[my_p], %%xmm5\n\t" + "movdqa %[k3k4], %%xmm6\n\t" + : + : [shuf] "m" (crc32_shuf_shift[32 - inlen]), + [crc] "m" (*pcrc), + [my_p] "m" (consts->my_p[0]), + [k3k4] "m" (consts->k[3 - 1]) + ); + + if (inlen >= 8) + { + asm volatile ("movq %[inbuf], %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf) + ); + if (inlen > 8) + { + asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/ + "movq %[inbuf_tail], %%xmm2\n\t" + "punpcklqdq %%xmm2, %%xmm0\n\t" + "pshufb %[merge_shuf], %%xmm0\n\t" + : + : [inbuf_tail] "m" (inbuf[inlen - 8]), + [merge_shuf] "m" + (*crc32_merge9to15_shuf[inlen - 9]) + ); + } + } + else + { + asm volatile ("movd %[inbuf], %%xmm0\n\t" + "pinsrd $1, %[inbuf_tail], %%xmm0\n\t" + "pshufb %[merge_shuf], %%xmm0\n\t" + : + : [inbuf] "m" (*inbuf), + [inbuf_tail] "m" (inbuf[inlen - 4]), + [merge_shuf] "m" + (*crc32_merge5to7_shuf[inlen - 5]) + ); + } + + /* Final fold. */ + asm volatile ("pxor %%xmm1, %%xmm0\n\t" + "pshufb %%xmm7, %%xmm0\n\t" + + /* reduce 128-bits to 96-bits */ + "movdqa %%xmm0, %%xmm1\n\t" + "pclmulqdq $0x11, %%xmm6, %%xmm0\n\t" + "pslldq $8, %%xmm1\n\t" + "pxor %%xmm1, %%xmm0\n\t" /* bottom 32-bit are zero */ + + /* reduce 96-bits to 64-bits */ + "pshufd $0x30, %%xmm0, %%xmm1\n\t" /* [00][x>>96][00][00] */ + "pshufd $0x24, %%xmm0, %%xmm0\n\t" /* [00][xx][xx][00] */ + "pclmulqdq $0x01, %[k5], %%xmm1\n\t" /* [00][xx][xx][00] */ + "pxor %%xmm1, %%xmm0\n\t" /* top and bottom 32-bit are zero */ + + /* barrett reduction */ + "pshufd $0x01, %%xmm0, %%xmm1\n\t" /* [00][00][00][x>>32] */ + "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][xx] */ + "psrldq $4, %%xmm0\n\t" /* [00][00][xx][xx] */ + "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" + "pxor %%xmm1, %%xmm0\n\t" + + /* store CRC in input endian */ + "movd %%xmm0, %%eax\n\t" + "bswapl %%eax\n\t" + "movl %%eax, %[out]\n\t" + : [out] "=m" (*pcrc) + : [k5] "m" (consts->k[5 - 1]) + : "eax" ); + } +} + +void ASM_FUNC_ATTR +_gcry_crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen) +{ + const struct crc32_consts_s *consts = &crc32_consts; +#if defined(__x86_64__) && defined(__WIN64__) + char win64tmp[2 * 16]; + + /* XMM6-XMM7 need to be restored after use. */ + asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t" + "movdqu %%xmm7, 1*16(%0)\n\t" + : + : "r" (win64tmp) + : "memory"); +#endif + + if (!inlen) + return; + + if (inlen >= 16) + crc32_reflected_bulk(pcrc, inbuf, inlen, consts); + else + crc32_reflected_less_than_16(pcrc, inbuf, inlen, consts); + +#if defined(__x86_64__) && defined(__WIN64__) + /* Restore used registers. */ + asm volatile("movdqu 0*16(%0), %%xmm6\n\t" + "movdqu 1*16(%0), %%xmm7\n\t" + : + : "r" (win64tmp) + : "memory"); +#endif +} + +void ASM_FUNC_ATTR +_gcry_crc24rfc2440_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen) +{ + const struct crc32_consts_s *consts = &crc24rfc2440_consts; +#if defined(__x86_64__) && defined(__WIN64__) + char win64tmp[2 * 16]; + + /* XMM6-XMM7 need to be restored after use. */ + asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t" + "movdqu %%xmm7, 1*16(%0)\n\t" + : + : "r" (win64tmp) + : "memory"); +#endif + + if (!inlen) + return; + + /* Note: *pcrc in input endian. */ + + if (inlen >= 16) + crc32_bulk(pcrc, inbuf, inlen, consts); + else + crc32_less_than_16(pcrc, inbuf, inlen, consts); + +#if defined(__x86_64__) && defined(__WIN64__) + /* Restore used registers. */ + asm volatile("movdqu 0*16(%0), %%xmm6\n\t" + "movdqu 1*16(%0), %%xmm7\n\t" + : + : "r" (win64tmp) + : "memory"); +#endif +} + +#if __clang__ +# pragma clang attribute pop +#endif + +#endif /* USE_INTEL_PCLMUL */ diff --git a/comm/third_party/libgcrypt/cipher/crc-ppc.c b/comm/third_party/libgcrypt/cipher/crc-ppc.c new file mode 100644 index 0000000000..b9a40130ce --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/crc-ppc.c @@ -0,0 +1,656 @@ +/* crc-ppc.c - POWER8 vpmsum accelerated CRC implementation + * Copyright (C) 2019-2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include +#include +#include +#include + +#include "g10lib.h" + +#include "bithelp.h" +#include "bufhelp.h" + + +#if defined(ENABLE_PPC_CRYPTO_SUPPORT) && \ + defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \ + defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC) && \ + __GNUC__ >= 4 + +#include +#include "bufhelp.h" + + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define NO_INLINE __attribute__((noinline)) +#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function)) + +#define ASM_FUNC_ATTR NO_INSTRUMENT_FUNCTION +#define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE +#define ASM_FUNC_ATTR_NOINLINE ASM_FUNC_ATTR NO_INLINE + +#define ALIGNED_64 __attribute__ ((aligned (64))) + + +typedef vector unsigned char vector16x_u8; +typedef vector unsigned int vector4x_u32; +typedef vector unsigned long long vector2x_u64; + + +/* Constants structure for generic reflected/non-reflected CRC32 PMULL + * functions. */ +struct crc32_consts_s +{ + /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */ + unsigned long long k[6]; + /* my_p: { floor(x^64 / P(x)), P(x) } */ + unsigned long long my_p[2]; +}; + +/* PMULL constants for CRC32 and CRC32RFC1510. */ +static const struct crc32_consts_s crc32_consts ALIGNED_64 = +{ + { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */ + U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */ + U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */ + U64_C(0x163cd6124), 0 /* y = 2 */ + }, + { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */ + U64_C(0x1f7011641), U64_C(0x1db710641) + } +}; + +/* PMULL constants for CRC24RFC2440 (polynomial multiplied with xâ¸). */ +static const struct crc32_consts_s crc24rfc2440_consts ALIGNED_64 = +{ + { /* k[6] = x^(32*y) mod P(x) << 32*/ + U64_C(0x08289a00) << 32, U64_C(0x74b44a00) << 32, /* y = { 17, 15 } */ + U64_C(0xc4b14d00) << 32, U64_C(0xfd7e0c00) << 32, /* y = { 5, 3 } */ + U64_C(0xd9fe8c00) << 32, 0 /* y = 2 */ + }, + { /* my_p[2] = { floor(x^64 / P(x)), P(x) } */ + U64_C(0x1f845fe24), U64_C(0x1864cfb00) + } +}; + + +static ASM_FUNC_ATTR_INLINE vector2x_u64 +asm_vpmsumd(vector2x_u64 a, vector2x_u64 b) +{ + __asm__("vpmsumd %0, %1, %2" + : "=v" (a) + : "v" (a), "v" (b)); + return a; +} + + +static ASM_FUNC_ATTR_INLINE vector2x_u64 +asm_swap_u64(vector2x_u64 a) +{ + __asm__("xxswapd %x0, %x1" + : "=wa" (a) + : "wa" (a)); + return a; +} + + +static ASM_FUNC_ATTR_INLINE vector4x_u32 +vec_sld_u32(vector4x_u32 a, vector4x_u32 b, unsigned int idx) +{ + return vec_sld (a, b, (4 * idx) & 15); +} + + +static const byte crc32_partial_fold_input_mask[16 + 16] ALIGNED_64 = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; +static const byte crc32_shuf_shift[3 * 16] ALIGNED_64 = + { + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + }; +static const byte crc32_refl_shuf_shift[3 * 16] ALIGNED_64 = + { + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + }; +static const vector16x_u8 bswap_const ALIGNED_64 = + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + +#define CRC_VEC_SWAP(v) ({ vector2x_u64 __vecu64 = (v); \ + vec_perm(__vecu64, __vecu64, bswap_const); }) + +#ifdef WORDS_BIGENDIAN +# define CRC_VEC_U64_DEF(lo, hi) { (hi), (lo) } +# define CRC_VEC_U64_LOAD(offs, ptr) \ + asm_swap_u64(asm_vec_u64_load(offs, ptr)) +# define CRC_VEC_U64_LOAD_LE(offs, ptr) \ + CRC_VEC_SWAP(asm_vec_u64_load(offs, ptr)) +# define CRC_VEC_U64_LOAD_BE(offs, ptr) \ + asm_vec_u64_load(offs, ptr) +# define CRC_VEC_SWAP_TO_LE(v) CRC_VEC_SWAP(v) +# define CRC_VEC_SWAP_TO_BE(v) (v) +# define VEC_U64_LO 1 +# define VEC_U64_HI 0 + +static ASM_FUNC_ATTR_INLINE vector2x_u64 +asm_vec_u64_load(unsigned long offset, const void *ptr) +{ + vector2x_u64 vecu64; +#if __GNUC__ >= 4 + if (__builtin_constant_p (offset) && offset == 0) + __asm__ volatile ("lxvd2x %x0,0,%1\n\t" + : "=wa" (vecu64) + : "r" ((uintptr_t)ptr) + : "memory"); + else +#endif + __asm__ volatile ("lxvd2x %x0,%1,%2\n\t" + : "=wa" (vecu64) + : "r" (offset), "r" ((uintptr_t)ptr) + : "memory", "r0"); + return vecu64; +} +#else +# define CRC_VEC_U64_DEF(lo, hi) { (lo), (hi) } +# define CRC_VEC_U64_LOAD(offs, ptr) asm_vec_u64_load_le(offs, ptr) +# define CRC_VEC_U64_LOAD_LE(offs, ptr) asm_vec_u64_load_le(offs, ptr) +# define CRC_VEC_U64_LOAD_BE(offs, ptr) asm_vec_u64_load_be(offs, ptr) +# define CRC_VEC_SWAP_TO_LE(v) (v) +# define CRC_VEC_SWAP_TO_BE(v) CRC_VEC_SWAP(v) +# define VEC_U64_LO 0 +# define VEC_U64_HI 1 + +static ASM_FUNC_ATTR_INLINE vector2x_u64 +asm_vec_u64_load_le(unsigned long offset, const void *ptr) +{ + vector2x_u64 vecu64; +#if __GNUC__ >= 4 + if (__builtin_constant_p (offset) && offset == 0) + __asm__ volatile ("lxvd2x %x0,0,%1\n\t" + : "=wa" (vecu64) + : "r" ((uintptr_t)ptr) + : "memory"); + else +#endif + __asm__ volatile ("lxvd2x %x0,%1,%2\n\t" + : "=wa" (vecu64) + : "r" (offset), "r" ((uintptr_t)ptr) + : "memory", "r0"); + return asm_swap_u64(vecu64); +} + +static ASM_FUNC_ATTR_INLINE vector2x_u64 +asm_vec_u64_load_be(unsigned int offset, const void *ptr) +{ + static const vector16x_u8 vec_load_le_const = + { ~7, ~6, ~5, ~4, ~3, ~2, ~1, ~0, ~15, ~14, ~13, ~12, ~11, ~10, ~9, ~8 }; + vector2x_u64 vecu64; + +#if __GNUC__ >= 4 + if (__builtin_constant_p (offset) && offset == 0) + __asm__ ("lxvd2x %%vs32,0,%1\n\t" + "vperm %0,%%v0,%%v0,%2\n\t" + : "=v" (vecu64) + : "r" ((uintptr_t)(ptr)), "v" (vec_load_le_const) + : "memory", "v0"); +#endif + else + __asm__ ("lxvd2x %%vs32,%1,%2\n\t" + "vperm %0,%%v0,%%v0,%3\n\t" + : "=v" (vecu64) + : "r" (offset), "r" ((uintptr_t)(ptr)), + "v" (vec_load_le_const) + : "memory", "r0", "v0"); + + return vecu64; +} +#endif + + +static ASM_FUNC_ATTR_INLINE void +crc32r_ppc8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + vector4x_u32 zero = { 0, 0, 0, 0 }; + vector2x_u64 low_64bit_mask = CRC_VEC_U64_DEF((u64)-1, 0); + vector2x_u64 low_32bit_mask = CRC_VEC_U64_DEF((u32)-1, 0); + vector2x_u64 my_p = CRC_VEC_U64_LOAD(0, &consts->my_p[0]); + vector2x_u64 k1k2 = CRC_VEC_U64_LOAD(0, &consts->k[1 - 1]); + vector2x_u64 k3k4 = CRC_VEC_U64_LOAD(0, &consts->k[3 - 1]); + vector2x_u64 k4lo = CRC_VEC_U64_DEF(k3k4[VEC_U64_HI], 0); + vector2x_u64 k5lo = CRC_VEC_U64_LOAD(0, &consts->k[5 - 1]); + vector2x_u64 crc = CRC_VEC_U64_DEF(*pcrc, 0); + vector2x_u64 crc0, crc1, crc2, crc3; + vector2x_u64 v0; + + if (inlen >= 8 * 16) + { + crc0 = CRC_VEC_U64_LOAD_LE(0 * 16, inbuf); + crc0 ^= crc; + crc1 = CRC_VEC_U64_LOAD_LE(1 * 16, inbuf); + crc2 = CRC_VEC_U64_LOAD_LE(2 * 16, inbuf); + crc3 = CRC_VEC_U64_LOAD_LE(3 * 16, inbuf); + + inbuf += 4 * 16; + inlen -= 4 * 16; + + /* Fold by 4. */ + while (inlen >= 4 * 16) + { + v0 = CRC_VEC_U64_LOAD_LE(0 * 16, inbuf); + crc0 = asm_vpmsumd(crc0, k1k2) ^ v0; + + v0 = CRC_VEC_U64_LOAD_LE(1 * 16, inbuf); + crc1 = asm_vpmsumd(crc1, k1k2) ^ v0; + + v0 = CRC_VEC_U64_LOAD_LE(2 * 16, inbuf); + crc2 = asm_vpmsumd(crc2, k1k2) ^ v0; + + v0 = CRC_VEC_U64_LOAD_LE(3 * 16, inbuf); + crc3 = asm_vpmsumd(crc3, k1k2) ^ v0; + + inbuf += 4 * 16; + inlen -= 4 * 16; + } + + /* Fold 4 to 1. */ + crc1 ^= asm_vpmsumd(crc0, k3k4); + crc2 ^= asm_vpmsumd(crc1, k3k4); + crc3 ^= asm_vpmsumd(crc2, k3k4); + crc = crc3; + } + else + { + v0 = CRC_VEC_U64_LOAD_LE(0, inbuf); + crc ^= v0; + + inbuf += 16; + inlen -= 16; + } + + /* Fold by 1. */ + while (inlen >= 16) + { + v0 = CRC_VEC_U64_LOAD_LE(0, inbuf); + crc = asm_vpmsumd(k3k4, crc); + crc ^= v0; + + inbuf += 16; + inlen -= 16; + } + + /* Partial fold. */ + if (inlen) + { + /* Load last input and add padding zeros. */ + vector2x_u64 mask = CRC_VEC_U64_LOAD_LE(inlen, crc32_partial_fold_input_mask); + vector2x_u64 shl_shuf = CRC_VEC_U64_LOAD_LE(inlen, crc32_refl_shuf_shift); + vector2x_u64 shr_shuf = CRC_VEC_U64_LOAD_LE(inlen + 16, crc32_refl_shuf_shift); + + v0 = CRC_VEC_U64_LOAD_LE(inlen - 16, inbuf); + v0 &= mask; + + crc = CRC_VEC_SWAP_TO_LE(crc); + v0 |= (vector2x_u64)vec_perm((vector16x_u8)crc, (vector16x_u8)zero, + (vector16x_u8)shr_shuf); + crc = (vector2x_u64)vec_perm((vector16x_u8)crc, (vector16x_u8)zero, + (vector16x_u8)shl_shuf); + crc = asm_vpmsumd(k3k4, crc); + crc ^= v0; + + inbuf += inlen; + inlen -= inlen; + } + + /* Final fold. */ + + /* reduce 128-bits to 96-bits */ + v0 = asm_swap_u64(crc); + v0 &= low_64bit_mask; + crc = asm_vpmsumd(k4lo, crc); + crc ^= v0; + + /* reduce 96-bits to 64-bits */ + v0 = (vector2x_u64)vec_sld_u32((vector4x_u32)crc, + (vector4x_u32)crc, 3); /* [x0][x3][x2][x1] */ + v0 &= low_64bit_mask; /* [00][00][x2][x1] */ + crc = crc & low_32bit_mask; /* [00][00][00][x0] */ + crc = v0 ^ asm_vpmsumd(k5lo, crc); /* [00][00][xx][xx] */ + + /* barrett reduction */ + v0 = crc << 32; /* [00][00][x0][00] */ + v0 = asm_vpmsumd(my_p, v0); + v0 = asm_swap_u64(v0); + v0 = asm_vpmsumd(my_p, v0); + crc = (vector2x_u64)vec_sld_u32((vector4x_u32)crc, + zero, 1); /* [00][x1][x0][00] */ + crc ^= v0; + + *pcrc = (u32)crc[VEC_U64_HI]; +} + + +static ASM_FUNC_ATTR_INLINE u32 +crc32r_ppc8_ce_reduction_4 (u32 data, u32 crc, + const struct crc32_consts_s *consts) +{ + vector4x_u32 zero = { 0, 0, 0, 0 }; + vector2x_u64 my_p = CRC_VEC_U64_LOAD(0, &consts->my_p[0]); + vector2x_u64 v0 = CRC_VEC_U64_DEF((u64)data, 0); + v0 = asm_vpmsumd(v0, my_p); /* [00][00][xx][xx] */ + v0 = (vector2x_u64)vec_sld_u32((vector4x_u32)v0, + zero, 3); /* [x0][00][00][00] */ + v0 = (vector2x_u64)vec_sld_u32((vector4x_u32)v0, + (vector4x_u32)v0, 3); /* [00][x0][00][00] */ + v0 = asm_vpmsumd(v0, my_p); /* [00][00][xx][xx] */ + return (v0[VEC_U64_LO] >> 32) ^ crc; +} + + +static ASM_FUNC_ATTR_INLINE void +crc32r_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + u32 crc = *pcrc; + u32 data; + + while (inlen >= 4) + { + data = buf_get_le32(inbuf); + data ^= crc; + + inlen -= 4; + inbuf += 4; + + crc = crc32r_ppc8_ce_reduction_4 (data, 0, consts); + } + + switch (inlen) + { + case 0: + break; + case 1: + data = inbuf[0]; + data ^= crc; + data <<= 24; + crc >>= 8; + crc = crc32r_ppc8_ce_reduction_4 (data, crc, consts); + break; + case 2: + data = inbuf[0] << 0; + data |= inbuf[1] << 8; + data ^= crc; + data <<= 16; + crc >>= 16; + crc = crc32r_ppc8_ce_reduction_4 (data, crc, consts); + break; + case 3: + data = inbuf[0] << 0; + data |= inbuf[1] << 8; + data |= inbuf[2] << 16; + data ^= crc; + data <<= 8; + crc >>= 24; + crc = crc32r_ppc8_ce_reduction_4 (data, crc, consts); + break; + } + + *pcrc = crc; +} + + +static ASM_FUNC_ATTR_INLINE void +crc32_ppc8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + vector4x_u32 zero = { 0, 0, 0, 0 }; + vector2x_u64 low_96bit_mask = CRC_VEC_U64_DEF(~0, ~((u64)(u32)-1 << 32)); + vector2x_u64 p_my = asm_swap_u64(CRC_VEC_U64_LOAD(0, &consts->my_p[0])); + vector2x_u64 p_my_lo, p_my_hi; + vector2x_u64 k2k1 = asm_swap_u64(CRC_VEC_U64_LOAD(0, &consts->k[1 - 1])); + vector2x_u64 k4k3 = asm_swap_u64(CRC_VEC_U64_LOAD(0, &consts->k[3 - 1])); + vector2x_u64 k4hi = CRC_VEC_U64_DEF(0, consts->k[4 - 1]); + vector2x_u64 k5hi = CRC_VEC_U64_DEF(0, consts->k[5 - 1]); + vector2x_u64 crc = CRC_VEC_U64_DEF(0, _gcry_bswap64(*pcrc)); + vector2x_u64 crc0, crc1, crc2, crc3; + vector2x_u64 v0; + + if (inlen >= 8 * 16) + { + crc0 = CRC_VEC_U64_LOAD_BE(0 * 16, inbuf); + crc0 ^= crc; + crc1 = CRC_VEC_U64_LOAD_BE(1 * 16, inbuf); + crc2 = CRC_VEC_U64_LOAD_BE(2 * 16, inbuf); + crc3 = CRC_VEC_U64_LOAD_BE(3 * 16, inbuf); + + inbuf += 4 * 16; + inlen -= 4 * 16; + + /* Fold by 4. */ + while (inlen >= 4 * 16) + { + v0 = CRC_VEC_U64_LOAD_BE(0 * 16, inbuf); + crc0 = asm_vpmsumd(crc0, k2k1) ^ v0; + + v0 = CRC_VEC_U64_LOAD_BE(1 * 16, inbuf); + crc1 = asm_vpmsumd(crc1, k2k1) ^ v0; + + v0 = CRC_VEC_U64_LOAD_BE(2 * 16, inbuf); + crc2 = asm_vpmsumd(crc2, k2k1) ^ v0; + + v0 = CRC_VEC_U64_LOAD_BE(3 * 16, inbuf); + crc3 = asm_vpmsumd(crc3, k2k1) ^ v0; + + inbuf += 4 * 16; + inlen -= 4 * 16; + } + + /* Fold 4 to 1. */ + crc1 ^= asm_vpmsumd(crc0, k4k3); + crc2 ^= asm_vpmsumd(crc1, k4k3); + crc3 ^= asm_vpmsumd(crc2, k4k3); + crc = crc3; + } + else + { + v0 = CRC_VEC_U64_LOAD_BE(0, inbuf); + crc ^= v0; + + inbuf += 16; + inlen -= 16; + } + + /* Fold by 1. */ + while (inlen >= 16) + { + v0 = CRC_VEC_U64_LOAD_BE(0, inbuf); + crc = asm_vpmsumd(k4k3, crc); + crc ^= v0; + + inbuf += 16; + inlen -= 16; + } + + /* Partial fold. */ + if (inlen) + { + /* Load last input and add padding zeros. */ + vector2x_u64 mask = CRC_VEC_U64_LOAD_LE(inlen, crc32_partial_fold_input_mask); + vector2x_u64 shl_shuf = CRC_VEC_U64_LOAD_LE(32 - inlen, crc32_refl_shuf_shift); + vector2x_u64 shr_shuf = CRC_VEC_U64_LOAD_LE(inlen + 16, crc32_shuf_shift); + + v0 = CRC_VEC_U64_LOAD_LE(inlen - 16, inbuf); + v0 &= mask; + + crc = CRC_VEC_SWAP_TO_LE(crc); + crc2 = (vector2x_u64)vec_perm((vector16x_u8)crc, (vector16x_u8)zero, + (vector16x_u8)shr_shuf); + v0 |= crc2; + v0 = CRC_VEC_SWAP(v0); + crc = (vector2x_u64)vec_perm((vector16x_u8)crc, (vector16x_u8)zero, + (vector16x_u8)shl_shuf); + crc = asm_vpmsumd(k4k3, crc); + crc ^= v0; + + inbuf += inlen; + inlen -= inlen; + } + + /* Final fold. */ + + /* reduce 128-bits to 96-bits */ + v0 = (vector2x_u64)vec_sld_u32((vector4x_u32)crc, + (vector4x_u32)zero, 2); + crc = asm_vpmsumd(k4hi, crc); + crc ^= v0; /* bottom 32-bit are zero */ + + /* reduce 96-bits to 64-bits */ + v0 = crc & low_96bit_mask; /* [00][x2][x1][00] */ + crc >>= 32; /* [00][x3][00][x0] */ + crc = asm_vpmsumd(k5hi, crc); /* [00][xx][xx][00] */ + crc ^= v0; /* top and bottom 32-bit are zero */ + + /* barrett reduction */ + p_my_hi = p_my; + p_my_lo = p_my; + p_my_hi[VEC_U64_LO] = 0; + p_my_lo[VEC_U64_HI] = 0; + v0 = crc >> 32; /* [00][00][00][x1] */ + crc = asm_vpmsumd(p_my_hi, crc); /* [00][xx][xx][xx] */ + crc = (vector2x_u64)vec_sld_u32((vector4x_u32)crc, + (vector4x_u32)crc, 3); /* [x0][00][x2][x1] */ + crc = asm_vpmsumd(p_my_lo, crc); /* [00][xx][xx][xx] */ + crc ^= v0; + + *pcrc = _gcry_bswap32(crc[VEC_U64_LO]); +} + + +static ASM_FUNC_ATTR_INLINE u32 +crc32_ppc8_ce_reduction_4 (u32 data, u32 crc, + const struct crc32_consts_s *consts) +{ + vector2x_u64 my_p = CRC_VEC_U64_LOAD(0, &consts->my_p[0]); + vector2x_u64 v0 = CRC_VEC_U64_DEF((u64)data << 32, 0); + v0 = asm_vpmsumd(v0, my_p); /* [00][x1][x0][00] */ + v0[VEC_U64_LO] = 0; /* [00][x1][00][00] */ + v0 = asm_vpmsumd(v0, my_p); /* [00][00][xx][xx] */ + return _gcry_bswap32(v0[VEC_U64_LO]) ^ crc; +} + + +static ASM_FUNC_ATTR_INLINE void +crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, + const struct crc32_consts_s *consts) +{ + u32 crc = *pcrc; + u32 data; + + while (inlen >= 4) + { + data = buf_get_le32(inbuf); + data ^= crc; + data = _gcry_bswap32(data); + + inlen -= 4; + inbuf += 4; + + crc = crc32_ppc8_ce_reduction_4 (data, 0, consts); + } + + switch (inlen) + { + case 0: + break; + case 1: + data = inbuf[0]; + data ^= crc; + data = data & 0xffU; + crc = crc >> 8; + crc = crc32_ppc8_ce_reduction_4 (data, crc, consts); + break; + case 2: + data = inbuf[0] << 0; + data |= inbuf[1] << 8; + data ^= crc; + data = _gcry_bswap32(data << 16); + crc = crc >> 16; + crc = crc32_ppc8_ce_reduction_4 (data, crc, consts); + break; + case 3: + data = inbuf[0] << 0; + data |= inbuf[1] << 8; + data |= inbuf[2] << 16; + data ^= crc; + data = _gcry_bswap32(data << 8); + crc = crc >> 24; + crc = crc32_ppc8_ce_reduction_4 (data, crc, consts); + break; + } + + *pcrc = crc; +} + +void ASM_FUNC_ATTR +_gcry_crc32_ppc8_vpmsum (u32 *pcrc, const byte *inbuf, size_t inlen) +{ + const struct crc32_consts_s *consts = &crc32_consts; + + if (!inlen) + return; + + if (inlen >= 16) + crc32r_ppc8_ce_bulk (pcrc, inbuf, inlen, consts); + else + crc32r_less_than_16 (pcrc, inbuf, inlen, consts); +} + +void ASM_FUNC_ATTR +_gcry_crc24rfc2440_ppc8_vpmsum (u32 *pcrc, const byte *inbuf, size_t inlen) +{ + const struct crc32_consts_s *consts = &crc24rfc2440_consts; + + if (!inlen) + return; + + /* Note: *pcrc in input endian. */ + + if (inlen >= 16) + crc32_ppc8_ce_bulk (pcrc, inbuf, inlen, consts); + else + crc32_less_than_16 (pcrc, inbuf, inlen, consts); +} + +#endif diff --git a/comm/third_party/libgcrypt/cipher/crc.c b/comm/third_party/libgcrypt/cipher/crc.c new file mode 100644 index 0000000000..6d70f644f7 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/crc.c @@ -0,0 +1,955 @@ +/* crc.c - Cyclic redundancy checks. + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" + +#include "bithelp.h" +#include "bufhelp.h" + + +/* USE_INTEL_PCLMUL indicates whether to compile CRC with Intel PCLMUL/SSE4.1 + * code. */ +#undef USE_INTEL_PCLMUL +#if defined(ENABLE_PCLMUL_SUPPORT) && defined(ENABLE_SSE41_SUPPORT) +# if ((defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)) +# if __GNUC__ >= 4 +# define USE_INTEL_PCLMUL 1 +# endif +# endif +#endif /* USE_INTEL_PCLMUL */ + +/* USE_ARM_PMULL indicates whether to compile GCM with ARMv8 PMULL code. */ +#undef USE_ARM_PMULL +#if defined(ENABLE_ARM_CRYPTO_SUPPORT) +# if defined(__AARCH64EL__) && \ + defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO) +# define USE_ARM_PMULL 1 +# endif +#endif /* USE_ARM_PMULL */ + +/* USE_PPC_VPMSUM indicates whether to enable PowerPC vector + * accelerated code. */ +#undef USE_PPC_VPMSUM +#ifdef ENABLE_PPC_CRYPTO_SUPPORT +# if defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \ + defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC) +# if __GNUC__ >= 4 +# define USE_PPC_VPMSUM 1 +# endif +# endif +#endif /* USE_PPC_VPMSUM */ + + +typedef struct +{ + u32 CRC; +#ifdef USE_INTEL_PCLMUL + unsigned int use_pclmul:1; /* Intel PCLMUL shall be used. */ +#endif +#ifdef USE_ARM_PMULL + unsigned int use_pmull:1; /* ARMv8 PMULL shall be used. */ +#endif +#ifdef USE_PPC_VPMSUM + unsigned int use_vpmsum:1; /* POWER vpmsum shall be used. */ +#endif + byte buf[4]; +} +CRC_CONTEXT; + + +#ifdef USE_INTEL_PCLMUL +/*-- crc-intel-pclmul.c --*/ +void _gcry_crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen); +void _gcry_crc24rfc2440_intel_pclmul (u32 *pcrc, const byte *inbuf, + size_t inlen); +#endif + +#ifdef USE_ARM_PMULL +/*-- crc-armv8-ce.c --*/ +void _gcry_crc32_armv8_ce_pmull (u32 *pcrc, const byte *inbuf, size_t inlen); +void _gcry_crc24rfc2440_armv8_ce_pmull (u32 *pcrc, const byte *inbuf, + size_t inlen); +#endif + +#ifdef USE_PPC_VPMSUM +/*-- crc-ppc.c --*/ +void _gcry_crc32_ppc8_vpmsum (u32 *pcrc, const byte *inbuf, size_t inlen); +void _gcry_crc24rfc2440_ppc8_vpmsum (u32 *pcrc, const byte *inbuf, + size_t inlen); +#endif + + +/* + * Code generated by universal_crc by Danjel McGougan + * + * CRC parameters used: + * bits: 32 + * poly: 0x04c11db7 + * init: 0xffffffff + * xor: 0xffffffff + * reverse: true + * non-direct: false + * + * CRC of the string "123456789" is 0xcbf43926 + */ + +static const u32 crc32_table[1024] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + 0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, + 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, + 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, + 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, + 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, + 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, + 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, + 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, + 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, + 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, + 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, + 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, + 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, + 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, + 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, + 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, + 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, + 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, + 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, + 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, + 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, + 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, + 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, + 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, + 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, + 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, + 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, + 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, + 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, + 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, + 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, + 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, + 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, + 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, + 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, + 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, + 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, + 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, + 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, + 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, + 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, + 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, + 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, + 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, + 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, + 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, + 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, + 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, + 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, + 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, + 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, + 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72, + 0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, + 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, + 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, + 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, + 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, + 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, + 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, + 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, + 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, + 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, + 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, + 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, + 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, + 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, + 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, + 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, + 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, + 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, + 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, + 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, + 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, + 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, + 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, + 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, + 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, + 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, + 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, + 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, + 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, + 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, + 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, + 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, + 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, + 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, + 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, + 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, + 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, + 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, + 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, + 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, + 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, + 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, + 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, + 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, + 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, + 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, + 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, + 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, + 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, + 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, + 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, + 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed, + 0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, + 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, + 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, + 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, + 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, + 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, + 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, + 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, + 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, + 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, + 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, + 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, + 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, + 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, + 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, + 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, + 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, + 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, + 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, + 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, + 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, + 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, + 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, + 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, + 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, + 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, + 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, + 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, + 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, + 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, + 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, + 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, + 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, + 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, + 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, + 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, + 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, + 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, + 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, + 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, + 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, + 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, + 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, + 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, + 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, + 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, + 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, + 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, + 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, + 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, + 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, + 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1 +}; + +/* CRC32 */ + +static inline u32 +crc32_next (u32 crc, byte data) +{ + return (crc >> 8) ^ crc32_table[(crc & 0xff) ^ data]; +} + +/* + * Process 4 bytes in one go + */ +static inline u32 +crc32_next4 (u32 crc, u32 data) +{ + crc ^= data; + crc = crc32_table[(crc & 0xff) + 0x300] ^ + crc32_table[((crc >> 8) & 0xff) + 0x200] ^ + crc32_table[((crc >> 16) & 0xff) + 0x100] ^ + crc32_table[(crc >> 24) & 0xff]; + return crc; +} + +static void +crc32_init (void *context, unsigned int flags) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + u32 hwf = _gcry_get_hw_features (); + +#ifdef USE_INTEL_PCLMUL + ctx->use_pclmul = (hwf & HWF_INTEL_SSE4_1) && (hwf & HWF_INTEL_PCLMUL); +#endif +#ifdef USE_ARM_PMULL + ctx->use_pmull = (hwf & HWF_ARM_NEON) && (hwf & HWF_ARM_PMULL); +#endif +#ifdef USE_PPC_VPMSUM + ctx->use_vpmsum = !!(hwf & HWF_PPC_ARCH_2_07); +#endif + + (void)flags; + (void)hwf; + + ctx->CRC = 0 ^ 0xffffffffL; +} + +static void +crc32_write (void *context, const void *inbuf_arg, size_t inlen) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + const byte *inbuf = inbuf_arg; + u32 crc; + +#ifdef USE_INTEL_PCLMUL + if (ctx->use_pclmul) + { + _gcry_crc32_intel_pclmul(&ctx->CRC, inbuf, inlen); + return; + } +#endif +#ifdef USE_ARM_PMULL + if (ctx->use_pmull) + { + _gcry_crc32_armv8_ce_pmull(&ctx->CRC, inbuf, inlen); + return; + } +#endif +#ifdef USE_PPC_VPMSUM + if (ctx->use_vpmsum) + { + _gcry_crc32_ppc8_vpmsum(&ctx->CRC, inbuf, inlen); + return; + } +#endif + + if (!inbuf || !inlen) + return; + + crc = ctx->CRC; + + while (inlen >= 16) + { + inlen -= 16; + crc = crc32_next4(crc, buf_get_le32(&inbuf[0])); + crc = crc32_next4(crc, buf_get_le32(&inbuf[4])); + crc = crc32_next4(crc, buf_get_le32(&inbuf[8])); + crc = crc32_next4(crc, buf_get_le32(&inbuf[12])); + inbuf += 16; + } + + while (inlen >= 4) + { + inlen -= 4; + crc = crc32_next4(crc, buf_get_le32(inbuf)); + inbuf += 4; + } + + while (inlen--) + { + crc = crc32_next(crc, *inbuf++); + } + + ctx->CRC = crc; +} + +static byte * +crc32_read (void *context) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + return ctx->buf; +} + +static void +crc32_final (void *context) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + ctx->CRC ^= 0xffffffffL; + buf_put_be32 (ctx->buf, ctx->CRC); +} + +/* CRC32 a'la RFC 1510 */ +/* CRC of the string "123456789" is 0x2dfd2d88 */ + +static void +crc32rfc1510_init (void *context, unsigned int flags) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + u32 hwf = _gcry_get_hw_features (); + +#ifdef USE_INTEL_PCLMUL + ctx->use_pclmul = (hwf & HWF_INTEL_SSE4_1) && (hwf & HWF_INTEL_PCLMUL); +#endif +#ifdef USE_ARM_PMULL + ctx->use_pmull = (hwf & HWF_ARM_NEON) && (hwf & HWF_ARM_PMULL); +#endif +#ifdef USE_PPC_VPMSUM + ctx->use_vpmsum = !!(hwf & HWF_PPC_ARCH_2_07); +#endif + + (void)flags; + (void)hwf; + + ctx->CRC = 0; +} + +static void +crc32rfc1510_final (void *context) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + buf_put_be32(ctx->buf, ctx->CRC); +} + +/* CRC24 a'la RFC 2440 */ +/* + * Code generated by universal_crc by Danjel McGougan + * + * CRC parameters used: + * bits: 24 + * poly: 0x864cfb + * init: 0xb704ce + * xor: 0x000000 + * reverse: false + * non-direct: false + * + * CRC of the string "123456789" is 0x21cf02 + */ + +static const u32 crc24_table[1024] = +{ + 0x00000000, 0x00fb4c86, 0x000dd58a, 0x00f6990c, + 0x00e1e693, 0x001aaa15, 0x00ec3319, 0x00177f9f, + 0x003981a1, 0x00c2cd27, 0x0034542b, 0x00cf18ad, + 0x00d86732, 0x00232bb4, 0x00d5b2b8, 0x002efe3e, + 0x00894ec5, 0x00720243, 0x00849b4f, 0x007fd7c9, + 0x0068a856, 0x0093e4d0, 0x00657ddc, 0x009e315a, + 0x00b0cf64, 0x004b83e2, 0x00bd1aee, 0x00465668, + 0x005129f7, 0x00aa6571, 0x005cfc7d, 0x00a7b0fb, + 0x00e9d10c, 0x00129d8a, 0x00e40486, 0x001f4800, + 0x0008379f, 0x00f37b19, 0x0005e215, 0x00feae93, + 0x00d050ad, 0x002b1c2b, 0x00dd8527, 0x0026c9a1, + 0x0031b63e, 0x00cafab8, 0x003c63b4, 0x00c72f32, + 0x00609fc9, 0x009bd34f, 0x006d4a43, 0x009606c5, + 0x0081795a, 0x007a35dc, 0x008cacd0, 0x0077e056, + 0x00591e68, 0x00a252ee, 0x0054cbe2, 0x00af8764, + 0x00b8f8fb, 0x0043b47d, 0x00b52d71, 0x004e61f7, + 0x00d2a319, 0x0029ef9f, 0x00df7693, 0x00243a15, + 0x0033458a, 0x00c8090c, 0x003e9000, 0x00c5dc86, + 0x00eb22b8, 0x00106e3e, 0x00e6f732, 0x001dbbb4, + 0x000ac42b, 0x00f188ad, 0x000711a1, 0x00fc5d27, + 0x005beddc, 0x00a0a15a, 0x00563856, 0x00ad74d0, + 0x00ba0b4f, 0x004147c9, 0x00b7dec5, 0x004c9243, + 0x00626c7d, 0x009920fb, 0x006fb9f7, 0x0094f571, + 0x00838aee, 0x0078c668, 0x008e5f64, 0x007513e2, + 0x003b7215, 0x00c03e93, 0x0036a79f, 0x00cdeb19, + 0x00da9486, 0x0021d800, 0x00d7410c, 0x002c0d8a, + 0x0002f3b4, 0x00f9bf32, 0x000f263e, 0x00f46ab8, + 0x00e31527, 0x001859a1, 0x00eec0ad, 0x00158c2b, + 0x00b23cd0, 0x00497056, 0x00bfe95a, 0x0044a5dc, + 0x0053da43, 0x00a896c5, 0x005e0fc9, 0x00a5434f, + 0x008bbd71, 0x0070f1f7, 0x008668fb, 0x007d247d, + 0x006a5be2, 0x00911764, 0x00678e68, 0x009cc2ee, + 0x00a44733, 0x005f0bb5, 0x00a992b9, 0x0052de3f, + 0x0045a1a0, 0x00beed26, 0x0048742a, 0x00b338ac, + 0x009dc692, 0x00668a14, 0x00901318, 0x006b5f9e, + 0x007c2001, 0x00876c87, 0x0071f58b, 0x008ab90d, + 0x002d09f6, 0x00d64570, 0x0020dc7c, 0x00db90fa, + 0x00ccef65, 0x0037a3e3, 0x00c13aef, 0x003a7669, + 0x00148857, 0x00efc4d1, 0x00195ddd, 0x00e2115b, + 0x00f56ec4, 0x000e2242, 0x00f8bb4e, 0x0003f7c8, + 0x004d963f, 0x00b6dab9, 0x004043b5, 0x00bb0f33, + 0x00ac70ac, 0x00573c2a, 0x00a1a526, 0x005ae9a0, + 0x0074179e, 0x008f5b18, 0x0079c214, 0x00828e92, + 0x0095f10d, 0x006ebd8b, 0x00982487, 0x00636801, + 0x00c4d8fa, 0x003f947c, 0x00c90d70, 0x003241f6, + 0x00253e69, 0x00de72ef, 0x0028ebe3, 0x00d3a765, + 0x00fd595b, 0x000615dd, 0x00f08cd1, 0x000bc057, + 0x001cbfc8, 0x00e7f34e, 0x00116a42, 0x00ea26c4, + 0x0076e42a, 0x008da8ac, 0x007b31a0, 0x00807d26, + 0x009702b9, 0x006c4e3f, 0x009ad733, 0x00619bb5, + 0x004f658b, 0x00b4290d, 0x0042b001, 0x00b9fc87, + 0x00ae8318, 0x0055cf9e, 0x00a35692, 0x00581a14, + 0x00ffaaef, 0x0004e669, 0x00f27f65, 0x000933e3, + 0x001e4c7c, 0x00e500fa, 0x001399f6, 0x00e8d570, + 0x00c62b4e, 0x003d67c8, 0x00cbfec4, 0x0030b242, + 0x0027cddd, 0x00dc815b, 0x002a1857, 0x00d154d1, + 0x009f3526, 0x006479a0, 0x0092e0ac, 0x0069ac2a, + 0x007ed3b5, 0x00859f33, 0x0073063f, 0x00884ab9, + 0x00a6b487, 0x005df801, 0x00ab610d, 0x00502d8b, + 0x00475214, 0x00bc1e92, 0x004a879e, 0x00b1cb18, + 0x00167be3, 0x00ed3765, 0x001bae69, 0x00e0e2ef, + 0x00f79d70, 0x000cd1f6, 0x00fa48fa, 0x0001047c, + 0x002ffa42, 0x00d4b6c4, 0x00222fc8, 0x00d9634e, + 0x00ce1cd1, 0x00355057, 0x00c3c95b, 0x003885dd, + 0x00000000, 0x00488f66, 0x00901ecd, 0x00d891ab, + 0x00db711c, 0x0093fe7a, 0x004b6fd1, 0x0003e0b7, + 0x00b6e338, 0x00fe6c5e, 0x0026fdf5, 0x006e7293, + 0x006d9224, 0x00251d42, 0x00fd8ce9, 0x00b5038f, + 0x006cc771, 0x00244817, 0x00fcd9bc, 0x00b456da, + 0x00b7b66d, 0x00ff390b, 0x0027a8a0, 0x006f27c6, + 0x00da2449, 0x0092ab2f, 0x004a3a84, 0x0002b5e2, + 0x00015555, 0x0049da33, 0x00914b98, 0x00d9c4fe, + 0x00d88ee3, 0x00900185, 0x0048902e, 0x00001f48, + 0x0003ffff, 0x004b7099, 0x0093e132, 0x00db6e54, + 0x006e6ddb, 0x0026e2bd, 0x00fe7316, 0x00b6fc70, + 0x00b51cc7, 0x00fd93a1, 0x0025020a, 0x006d8d6c, + 0x00b44992, 0x00fcc6f4, 0x0024575f, 0x006cd839, + 0x006f388e, 0x0027b7e8, 0x00ff2643, 0x00b7a925, + 0x0002aaaa, 0x004a25cc, 0x0092b467, 0x00da3b01, + 0x00d9dbb6, 0x009154d0, 0x0049c57b, 0x00014a1d, + 0x004b5141, 0x0003de27, 0x00db4f8c, 0x0093c0ea, + 0x0090205d, 0x00d8af3b, 0x00003e90, 0x0048b1f6, + 0x00fdb279, 0x00b53d1f, 0x006dacb4, 0x002523d2, + 0x0026c365, 0x006e4c03, 0x00b6dda8, 0x00fe52ce, + 0x00279630, 0x006f1956, 0x00b788fd, 0x00ff079b, + 0x00fce72c, 0x00b4684a, 0x006cf9e1, 0x00247687, + 0x00917508, 0x00d9fa6e, 0x00016bc5, 0x0049e4a3, + 0x004a0414, 0x00028b72, 0x00da1ad9, 0x009295bf, + 0x0093dfa2, 0x00db50c4, 0x0003c16f, 0x004b4e09, + 0x0048aebe, 0x000021d8, 0x00d8b073, 0x00903f15, + 0x00253c9a, 0x006db3fc, 0x00b52257, 0x00fdad31, + 0x00fe4d86, 0x00b6c2e0, 0x006e534b, 0x0026dc2d, + 0x00ff18d3, 0x00b797b5, 0x006f061e, 0x00278978, + 0x002469cf, 0x006ce6a9, 0x00b47702, 0x00fcf864, + 0x0049fbeb, 0x0001748d, 0x00d9e526, 0x00916a40, + 0x00928af7, 0x00da0591, 0x0002943a, 0x004a1b5c, + 0x0096a282, 0x00de2de4, 0x0006bc4f, 0x004e3329, + 0x004dd39e, 0x00055cf8, 0x00ddcd53, 0x00954235, + 0x002041ba, 0x0068cedc, 0x00b05f77, 0x00f8d011, + 0x00fb30a6, 0x00b3bfc0, 0x006b2e6b, 0x0023a10d, + 0x00fa65f3, 0x00b2ea95, 0x006a7b3e, 0x0022f458, + 0x002114ef, 0x00699b89, 0x00b10a22, 0x00f98544, + 0x004c86cb, 0x000409ad, 0x00dc9806, 0x00941760, + 0x0097f7d7, 0x00df78b1, 0x0007e91a, 0x004f667c, + 0x004e2c61, 0x0006a307, 0x00de32ac, 0x0096bdca, + 0x00955d7d, 0x00ddd21b, 0x000543b0, 0x004dccd6, + 0x00f8cf59, 0x00b0403f, 0x0068d194, 0x00205ef2, + 0x0023be45, 0x006b3123, 0x00b3a088, 0x00fb2fee, + 0x0022eb10, 0x006a6476, 0x00b2f5dd, 0x00fa7abb, + 0x00f99a0c, 0x00b1156a, 0x006984c1, 0x00210ba7, + 0x00940828, 0x00dc874e, 0x000416e5, 0x004c9983, + 0x004f7934, 0x0007f652, 0x00df67f9, 0x0097e89f, + 0x00ddf3c3, 0x00957ca5, 0x004ded0e, 0x00056268, + 0x000682df, 0x004e0db9, 0x00969c12, 0x00de1374, + 0x006b10fb, 0x00239f9d, 0x00fb0e36, 0x00b38150, + 0x00b061e7, 0x00f8ee81, 0x00207f2a, 0x0068f04c, + 0x00b134b2, 0x00f9bbd4, 0x00212a7f, 0x0069a519, + 0x006a45ae, 0x0022cac8, 0x00fa5b63, 0x00b2d405, + 0x0007d78a, 0x004f58ec, 0x0097c947, 0x00df4621, + 0x00dca696, 0x009429f0, 0x004cb85b, 0x0004373d, + 0x00057d20, 0x004df246, 0x009563ed, 0x00ddec8b, + 0x00de0c3c, 0x0096835a, 0x004e12f1, 0x00069d97, + 0x00b39e18, 0x00fb117e, 0x002380d5, 0x006b0fb3, + 0x0068ef04, 0x00206062, 0x00f8f1c9, 0x00b07eaf, + 0x0069ba51, 0x00213537, 0x00f9a49c, 0x00b12bfa, + 0x00b2cb4d, 0x00fa442b, 0x0022d580, 0x006a5ae6, + 0x00df5969, 0x0097d60f, 0x004f47a4, 0x0007c8c2, + 0x00042875, 0x004ca713, 0x009436b8, 0x00dcb9de, + 0x00000000, 0x00d70983, 0x00555f80, 0x00825603, + 0x0051f286, 0x0086fb05, 0x0004ad06, 0x00d3a485, + 0x0059a88b, 0x008ea108, 0x000cf70b, 0x00dbfe88, + 0x00085a0d, 0x00df538e, 0x005d058d, 0x008a0c0e, + 0x00491c91, 0x009e1512, 0x001c4311, 0x00cb4a92, + 0x0018ee17, 0x00cfe794, 0x004db197, 0x009ab814, + 0x0010b41a, 0x00c7bd99, 0x0045eb9a, 0x0092e219, + 0x0041469c, 0x00964f1f, 0x0014191c, 0x00c3109f, + 0x006974a4, 0x00be7d27, 0x003c2b24, 0x00eb22a7, + 0x00388622, 0x00ef8fa1, 0x006dd9a2, 0x00bad021, + 0x0030dc2f, 0x00e7d5ac, 0x006583af, 0x00b28a2c, + 0x00612ea9, 0x00b6272a, 0x00347129, 0x00e378aa, + 0x00206835, 0x00f761b6, 0x007537b5, 0x00a23e36, + 0x00719ab3, 0x00a69330, 0x0024c533, 0x00f3ccb0, + 0x0079c0be, 0x00aec93d, 0x002c9f3e, 0x00fb96bd, + 0x00283238, 0x00ff3bbb, 0x007d6db8, 0x00aa643b, + 0x0029a4ce, 0x00fead4d, 0x007cfb4e, 0x00abf2cd, + 0x00785648, 0x00af5fcb, 0x002d09c8, 0x00fa004b, + 0x00700c45, 0x00a705c6, 0x002553c5, 0x00f25a46, + 0x0021fec3, 0x00f6f740, 0x0074a143, 0x00a3a8c0, + 0x0060b85f, 0x00b7b1dc, 0x0035e7df, 0x00e2ee5c, + 0x00314ad9, 0x00e6435a, 0x00641559, 0x00b31cda, + 0x003910d4, 0x00ee1957, 0x006c4f54, 0x00bb46d7, + 0x0068e252, 0x00bfebd1, 0x003dbdd2, 0x00eab451, + 0x0040d06a, 0x0097d9e9, 0x00158fea, 0x00c28669, + 0x001122ec, 0x00c62b6f, 0x00447d6c, 0x009374ef, + 0x001978e1, 0x00ce7162, 0x004c2761, 0x009b2ee2, + 0x00488a67, 0x009f83e4, 0x001dd5e7, 0x00cadc64, + 0x0009ccfb, 0x00dec578, 0x005c937b, 0x008b9af8, + 0x00583e7d, 0x008f37fe, 0x000d61fd, 0x00da687e, + 0x00506470, 0x00876df3, 0x00053bf0, 0x00d23273, + 0x000196f6, 0x00d69f75, 0x0054c976, 0x0083c0f5, + 0x00a9041b, 0x007e0d98, 0x00fc5b9b, 0x002b5218, + 0x00f8f69d, 0x002fff1e, 0x00ada91d, 0x007aa09e, + 0x00f0ac90, 0x0027a513, 0x00a5f310, 0x0072fa93, + 0x00a15e16, 0x00765795, 0x00f40196, 0x00230815, + 0x00e0188a, 0x00371109, 0x00b5470a, 0x00624e89, + 0x00b1ea0c, 0x0066e38f, 0x00e4b58c, 0x0033bc0f, + 0x00b9b001, 0x006eb982, 0x00ecef81, 0x003be602, + 0x00e84287, 0x003f4b04, 0x00bd1d07, 0x006a1484, + 0x00c070bf, 0x0017793c, 0x00952f3f, 0x004226bc, + 0x00918239, 0x00468bba, 0x00c4ddb9, 0x0013d43a, + 0x0099d834, 0x004ed1b7, 0x00cc87b4, 0x001b8e37, + 0x00c82ab2, 0x001f2331, 0x009d7532, 0x004a7cb1, + 0x00896c2e, 0x005e65ad, 0x00dc33ae, 0x000b3a2d, + 0x00d89ea8, 0x000f972b, 0x008dc128, 0x005ac8ab, + 0x00d0c4a5, 0x0007cd26, 0x00859b25, 0x005292a6, + 0x00813623, 0x00563fa0, 0x00d469a3, 0x00036020, + 0x0080a0d5, 0x0057a956, 0x00d5ff55, 0x0002f6d6, + 0x00d15253, 0x00065bd0, 0x00840dd3, 0x00530450, + 0x00d9085e, 0x000e01dd, 0x008c57de, 0x005b5e5d, + 0x0088fad8, 0x005ff35b, 0x00dda558, 0x000aacdb, + 0x00c9bc44, 0x001eb5c7, 0x009ce3c4, 0x004bea47, + 0x00984ec2, 0x004f4741, 0x00cd1142, 0x001a18c1, + 0x009014cf, 0x00471d4c, 0x00c54b4f, 0x001242cc, + 0x00c1e649, 0x0016efca, 0x0094b9c9, 0x0043b04a, + 0x00e9d471, 0x003eddf2, 0x00bc8bf1, 0x006b8272, + 0x00b826f7, 0x006f2f74, 0x00ed7977, 0x003a70f4, + 0x00b07cfa, 0x00677579, 0x00e5237a, 0x00322af9, + 0x00e18e7c, 0x003687ff, 0x00b4d1fc, 0x0063d87f, + 0x00a0c8e0, 0x0077c163, 0x00f59760, 0x00229ee3, + 0x00f13a66, 0x002633e5, 0x00a465e6, 0x00736c65, + 0x00f9606b, 0x002e69e8, 0x00ac3feb, 0x007b3668, + 0x00a892ed, 0x007f9b6e, 0x00fdcd6d, 0x002ac4ee, + 0x00000000, 0x00520936, 0x00a4126c, 0x00f61b5a, + 0x004825d8, 0x001a2cee, 0x00ec37b4, 0x00be3e82, + 0x006b0636, 0x00390f00, 0x00cf145a, 0x009d1d6c, + 0x002323ee, 0x00712ad8, 0x00873182, 0x00d538b4, + 0x00d60c6c, 0x0084055a, 0x00721e00, 0x00201736, + 0x009e29b4, 0x00cc2082, 0x003a3bd8, 0x006832ee, + 0x00bd0a5a, 0x00ef036c, 0x00191836, 0x004b1100, + 0x00f52f82, 0x00a726b4, 0x00513dee, 0x000334d8, + 0x00ac19d8, 0x00fe10ee, 0x00080bb4, 0x005a0282, + 0x00e43c00, 0x00b63536, 0x00402e6c, 0x0012275a, + 0x00c71fee, 0x009516d8, 0x00630d82, 0x003104b4, + 0x008f3a36, 0x00dd3300, 0x002b285a, 0x0079216c, + 0x007a15b4, 0x00281c82, 0x00de07d8, 0x008c0eee, + 0x0032306c, 0x0060395a, 0x00962200, 0x00c42b36, + 0x00111382, 0x00431ab4, 0x00b501ee, 0x00e708d8, + 0x0059365a, 0x000b3f6c, 0x00fd2436, 0x00af2d00, + 0x00a37f36, 0x00f17600, 0x00076d5a, 0x0055646c, + 0x00eb5aee, 0x00b953d8, 0x004f4882, 0x001d41b4, + 0x00c87900, 0x009a7036, 0x006c6b6c, 0x003e625a, + 0x00805cd8, 0x00d255ee, 0x00244eb4, 0x00764782, + 0x0075735a, 0x00277a6c, 0x00d16136, 0x00836800, + 0x003d5682, 0x006f5fb4, 0x009944ee, 0x00cb4dd8, + 0x001e756c, 0x004c7c5a, 0x00ba6700, 0x00e86e36, + 0x005650b4, 0x00045982, 0x00f242d8, 0x00a04bee, + 0x000f66ee, 0x005d6fd8, 0x00ab7482, 0x00f97db4, + 0x00474336, 0x00154a00, 0x00e3515a, 0x00b1586c, + 0x006460d8, 0x003669ee, 0x00c072b4, 0x00927b82, + 0x002c4500, 0x007e4c36, 0x0088576c, 0x00da5e5a, + 0x00d96a82, 0x008b63b4, 0x007d78ee, 0x002f71d8, + 0x00914f5a, 0x00c3466c, 0x00355d36, 0x00675400, + 0x00b26cb4, 0x00e06582, 0x00167ed8, 0x004477ee, + 0x00fa496c, 0x00a8405a, 0x005e5b00, 0x000c5236, + 0x0046ff6c, 0x0014f65a, 0x00e2ed00, 0x00b0e436, + 0x000edab4, 0x005cd382, 0x00aac8d8, 0x00f8c1ee, + 0x002df95a, 0x007ff06c, 0x0089eb36, 0x00dbe200, + 0x0065dc82, 0x0037d5b4, 0x00c1ceee, 0x0093c7d8, + 0x0090f300, 0x00c2fa36, 0x0034e16c, 0x0066e85a, + 0x00d8d6d8, 0x008adfee, 0x007cc4b4, 0x002ecd82, + 0x00fbf536, 0x00a9fc00, 0x005fe75a, 0x000dee6c, + 0x00b3d0ee, 0x00e1d9d8, 0x0017c282, 0x0045cbb4, + 0x00eae6b4, 0x00b8ef82, 0x004ef4d8, 0x001cfdee, + 0x00a2c36c, 0x00f0ca5a, 0x0006d100, 0x0054d836, + 0x0081e082, 0x00d3e9b4, 0x0025f2ee, 0x0077fbd8, + 0x00c9c55a, 0x009bcc6c, 0x006dd736, 0x003fde00, + 0x003cead8, 0x006ee3ee, 0x0098f8b4, 0x00caf182, + 0x0074cf00, 0x0026c636, 0x00d0dd6c, 0x0082d45a, + 0x0057ecee, 0x0005e5d8, 0x00f3fe82, 0x00a1f7b4, + 0x001fc936, 0x004dc000, 0x00bbdb5a, 0x00e9d26c, + 0x00e5805a, 0x00b7896c, 0x00419236, 0x00139b00, + 0x00ada582, 0x00ffacb4, 0x0009b7ee, 0x005bbed8, + 0x008e866c, 0x00dc8f5a, 0x002a9400, 0x00789d36, + 0x00c6a3b4, 0x0094aa82, 0x0062b1d8, 0x0030b8ee, + 0x00338c36, 0x00618500, 0x00979e5a, 0x00c5976c, + 0x007ba9ee, 0x0029a0d8, 0x00dfbb82, 0x008db2b4, + 0x00588a00, 0x000a8336, 0x00fc986c, 0x00ae915a, + 0x0010afd8, 0x0042a6ee, 0x00b4bdb4, 0x00e6b482, + 0x00499982, 0x001b90b4, 0x00ed8bee, 0x00bf82d8, + 0x0001bc5a, 0x0053b56c, 0x00a5ae36, 0x00f7a700, + 0x00229fb4, 0x00709682, 0x00868dd8, 0x00d484ee, + 0x006aba6c, 0x0038b35a, 0x00cea800, 0x009ca136, + 0x009f95ee, 0x00cd9cd8, 0x003b8782, 0x00698eb4, + 0x00d7b036, 0x0085b900, 0x0073a25a, 0x0021ab6c, + 0x00f493d8, 0x00a69aee, 0x005081b4, 0x00028882, + 0x00bcb600, 0x00eebf36, 0x0018a46c, 0x004aad5a +}; + +static inline +u32 crc24_init (void) +{ + /* Transformed to 32-bit CRC by multiplied by x⸠and then byte swapped. */ + return 0xce04b7; /* _gcry_bswap(0xb704ce << 8) */ +} + +static inline +u32 crc24_next (u32 crc, byte data) +{ + return (crc >> 8) ^ crc24_table[(crc & 0xff) ^ data]; +} + +/* + * Process 4 bytes in one go + */ +static inline +u32 crc24_next4 (u32 crc, u32 data) +{ + crc ^= data; + crc = crc24_table[(crc & 0xff) + 0x300] ^ + crc24_table[((crc >> 8) & 0xff) + 0x200] ^ + crc24_table[((crc >> 16) & 0xff) + 0x100] ^ + crc24_table[(data >> 24) & 0xff]; + return crc; +} + +static inline +u32 crc24_final (u32 crc) +{ + return crc & 0xffffff; +} + +static void +crc24rfc2440_init (void *context, unsigned int flags) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + u32 hwf = _gcry_get_hw_features (); + +#ifdef USE_INTEL_PCLMUL + ctx->use_pclmul = (hwf & HWF_INTEL_SSE4_1) && (hwf & HWF_INTEL_PCLMUL); +#endif +#ifdef USE_ARM_PMULL + ctx->use_pmull = (hwf & HWF_ARM_NEON) && (hwf & HWF_ARM_PMULL); +#endif +#ifdef USE_PPC_VPMSUM + ctx->use_vpmsum = !!(hwf & HWF_PPC_ARCH_2_07); +#endif + + (void)hwf; + (void)flags; + + ctx->CRC = crc24_init(); +} + +static void +crc24rfc2440_write (void *context, const void *inbuf_arg, size_t inlen) +{ + const unsigned char *inbuf = inbuf_arg; + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + u32 crc; + +#ifdef USE_INTEL_PCLMUL + if (ctx->use_pclmul) + { + _gcry_crc24rfc2440_intel_pclmul(&ctx->CRC, inbuf, inlen); + return; + } +#endif +#ifdef USE_ARM_PMULL + if (ctx->use_pmull) + { + _gcry_crc24rfc2440_armv8_ce_pmull(&ctx->CRC, inbuf, inlen); + return; + } +#endif +#ifdef USE_PPC_VPMSUM + if (ctx->use_vpmsum) + { + _gcry_crc24rfc2440_ppc8_vpmsum(&ctx->CRC, inbuf, inlen); + return; + } +#endif + + if (!inbuf || !inlen) + return; + + crc = ctx->CRC; + + while (inlen >= 16) + { + inlen -= 16; + crc = crc24_next4(crc, buf_get_le32(&inbuf[0])); + crc = crc24_next4(crc, buf_get_le32(&inbuf[4])); + crc = crc24_next4(crc, buf_get_le32(&inbuf[8])); + crc = crc24_next4(crc, buf_get_le32(&inbuf[12])); + inbuf += 16; + } + + while (inlen >= 4) + { + inlen -= 4; + crc = crc24_next4(crc, buf_get_le32(inbuf)); + inbuf += 4; + } + + while (inlen--) + { + crc = crc24_next(crc, *inbuf++); + } + + ctx->CRC = crc; +} + +static void +crc24rfc2440_final (void *context) +{ + CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + ctx->CRC = crc24_final(ctx->CRC); + buf_put_le32 (ctx->buf, ctx->CRC); +} + +/* We allow the CRC algorithms even in FIPS mode because they are + actually no cryptographic primitives. */ + +gcry_md_spec_t _gcry_digest_spec_crc32 = + { + GCRY_MD_CRC32, {0, 1}, + "CRC32", NULL, 0, NULL, 4, + crc32_init, crc32_write, crc32_final, crc32_read, NULL, + NULL, NULL, + sizeof (CRC_CONTEXT) + }; + +gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510 = + { + GCRY_MD_CRC32_RFC1510, {0, 1}, + "CRC32RFC1510", NULL, 0, NULL, 4, + crc32rfc1510_init, crc32_write, crc32rfc1510_final, crc32_read, NULL, + NULL, NULL, + sizeof (CRC_CONTEXT) + }; + +gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440 = + { + GCRY_MD_CRC24_RFC2440, {0, 1}, + "CRC24RFC2440", NULL, 0, NULL, 3, + crc24rfc2440_init, crc24rfc2440_write, crc24rfc2440_final, crc32_read, NULL, + NULL, NULL, + sizeof (CRC_CONTEXT) + }; diff --git a/comm/third_party/libgcrypt/cipher/des-amd64.S b/comm/third_party/libgcrypt/cipher/des-amd64.S new file mode 100644 index 0000000000..a211dac38a --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/des-amd64.S @@ -0,0 +1,1111 @@ +/* des-amd64.S - AMD64 assembly implementation of 3DES cipher + * + * Copyright (C) 2014 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifdef __x86_64 +#include +#if defined(USE_DES) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) + +#include "asm-common-amd64.h" + +.text + +#define s1 0 +#define s2 ((s1) + (64*8)) +#define s3 ((s2) + (64*8)) +#define s4 ((s3) + (64*8)) +#define s5 ((s4) + (64*8)) +#define s6 ((s5) + (64*8)) +#define s7 ((s6) + (64*8)) +#define s8 ((s7) + (64*8)) + +/* register macros */ +#define CTX %rdi +#define SBOXES %rbp + +#define RL0 %r8 +#define RL1 %r9 +#define RL2 %r10 + +#define RL0d %r8d +#define RL1d %r9d +#define RL2d %r10d + +#define RR0 %r11 +#define RR1 %r12 +#define RR2 %r13 + +#define RR0d %r11d +#define RR1d %r12d +#define RR2d %r13d + +#define RW0 %rax +#define RW1 %rbx +#define RW2 %rcx + +#define RW0d %eax +#define RW1d %ebx +#define RW2d %ecx + +#define RW0bl %al +#define RW1bl %bl +#define RW2bl %cl + +#define RW0bh %ah +#define RW1bh %bh +#define RW2bh %ch + +#define RT0 %r15 +#define RT1 %rsi +#define RT2 %r14 +#define RT3 %rdx + +#define RT0d %r15d +#define RT1d %esi +#define RT2d %r14d +#define RT3d %edx + +/*********************************************************************** + * 1-way 3DES + ***********************************************************************/ +#define do_permutation(a, b, offset, mask) \ + movl a, RT0d; \ + shrl $(offset), RT0d; \ + xorl b, RT0d; \ + andl $(mask), RT0d; \ + xorl RT0d, b; \ + shll $(offset), RT0d; \ + xorl RT0d, a; + +#define expand_to_64bits(val, mask) \ + movl val##d, RT0d; \ + rorl $4, RT0d; \ + shlq $32, RT0; \ + orq RT0, val; \ + andq mask, val; + +#define compress_to_64bits(val) \ + movq val, RT0; \ + shrq $32, RT0; \ + roll $4, RT0d; \ + orl RT0d, val##d; + +#define initial_permutation(left, right) \ + do_permutation(left##d, right##d, 4, 0x0f0f0f0f); \ + do_permutation(left##d, right##d, 16, 0x0000ffff); \ + do_permutation(right##d, left##d, 2, 0x33333333); \ + do_permutation(right##d, left##d, 8, 0x00ff00ff); \ + movabs $0x3f3f3f3f3f3f3f3f, RT3; \ + movl left##d, RW0d; \ + roll $1, right##d; \ + xorl right##d, RW0d; \ + andl $0xaaaaaaaa, RW0d; \ + xorl RW0d, left##d; \ + xorl RW0d, right##d; \ + roll $1, left##d; \ + expand_to_64bits(right, RT3); \ + expand_to_64bits(left, RT3); + +#define final_permutation(left, right) \ + compress_to_64bits(right); \ + compress_to_64bits(left); \ + movl right##d, RW0d; \ + rorl $1, left##d; \ + xorl left##d, RW0d; \ + andl $0xaaaaaaaa, RW0d; \ + xorl RW0d, right##d; \ + xorl RW0d, left##d; \ + rorl $1, right##d; \ + do_permutation(right##d, left##d, 8, 0x00ff00ff); \ + do_permutation(right##d, left##d, 2, 0x33333333); \ + do_permutation(left##d, right##d, 16, 0x0000ffff); \ + do_permutation(left##d, right##d, 4, 0x0f0f0f0f); + +#define round1(n, from, to, load_next_key) \ + xorq from, RW0; \ + \ + movzbl RW0bl, RT0d; \ + movzbl RW0bh, RT1d; \ + shrq $16, RW0; \ + movzbl RW0bl, RT2d; \ + movzbl RW0bh, RT3d; \ + shrq $16, RW0; \ + movq s8(SBOXES, RT0, 8), RT0; \ + xorq s6(SBOXES, RT1, 8), to; \ + movzbl RW0bl, RL1d; \ + movzbl RW0bh, RT1d; \ + shrl $16, RW0d; \ + xorq s4(SBOXES, RT2, 8), RT0; \ + xorq s2(SBOXES, RT3, 8), to; \ + movzbl RW0bl, RT2d; \ + movzbl RW0bh, RT3d; \ + xorq s7(SBOXES, RL1, 8), RT0; \ + xorq s5(SBOXES, RT1, 8), to; \ + xorq s3(SBOXES, RT2, 8), RT0; \ + load_next_key(n, RW0); \ + xorq RT0, to; \ + xorq s1(SBOXES, RT3, 8), to; \ + +#define load_next_key(n, RWx) \ + movq (((n) + 1) * 8)(CTX), RWx; + +#define dummy2(a, b) /*_*/ + +#define read_block(io, left, right) \ + movl (io), left##d; \ + movl 4(io), right##d; \ + bswapl left##d; \ + bswapl right##d; + +#define write_block(io, left, right) \ + bswapl left##d; \ + bswapl right##d; \ + movl left##d, (io); \ + movl right##d, 4(io); + +.align 8 +.globl _gcry_3des_amd64_crypt_block +ELF(.type _gcry_3des_amd64_crypt_block,@function;) + +_gcry_3des_amd64_crypt_block: + /* input: + * %rdi: round keys, CTX + * %rsi: dst + * %rdx: src + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + pushq %r15; + CFI_PUSH(%r15); + pushq %rsi; /*dst*/ + CFI_PUSH(%rsi); + + leaq .L_s1 rRIP, SBOXES; + + read_block(%rdx, RL0, RR0); + initial_permutation(RL0, RR0); + + movq (CTX), RW0; + + round1(0, RR0, RL0, load_next_key); + round1(1, RL0, RR0, load_next_key); + round1(2, RR0, RL0, load_next_key); + round1(3, RL0, RR0, load_next_key); + round1(4, RR0, RL0, load_next_key); + round1(5, RL0, RR0, load_next_key); + round1(6, RR0, RL0, load_next_key); + round1(7, RL0, RR0, load_next_key); + round1(8, RR0, RL0, load_next_key); + round1(9, RL0, RR0, load_next_key); + round1(10, RR0, RL0, load_next_key); + round1(11, RL0, RR0, load_next_key); + round1(12, RR0, RL0, load_next_key); + round1(13, RL0, RR0, load_next_key); + round1(14, RR0, RL0, load_next_key); + round1(15, RL0, RR0, load_next_key); + + round1(16+0, RL0, RR0, load_next_key); + round1(16+1, RR0, RL0, load_next_key); + round1(16+2, RL0, RR0, load_next_key); + round1(16+3, RR0, RL0, load_next_key); + round1(16+4, RL0, RR0, load_next_key); + round1(16+5, RR0, RL0, load_next_key); + round1(16+6, RL0, RR0, load_next_key); + round1(16+7, RR0, RL0, load_next_key); + round1(16+8, RL0, RR0, load_next_key); + round1(16+9, RR0, RL0, load_next_key); + round1(16+10, RL0, RR0, load_next_key); + round1(16+11, RR0, RL0, load_next_key); + round1(16+12, RL0, RR0, load_next_key); + round1(16+13, RR0, RL0, load_next_key); + round1(16+14, RL0, RR0, load_next_key); + round1(16+15, RR0, RL0, load_next_key); + + round1(32+0, RR0, RL0, load_next_key); + round1(32+1, RL0, RR0, load_next_key); + round1(32+2, RR0, RL0, load_next_key); + round1(32+3, RL0, RR0, load_next_key); + round1(32+4, RR0, RL0, load_next_key); + round1(32+5, RL0, RR0, load_next_key); + round1(32+6, RR0, RL0, load_next_key); + round1(32+7, RL0, RR0, load_next_key); + round1(32+8, RR0, RL0, load_next_key); + round1(32+9, RL0, RR0, load_next_key); + round1(32+10, RR0, RL0, load_next_key); + round1(32+11, RL0, RR0, load_next_key); + round1(32+12, RR0, RL0, load_next_key); + round1(32+13, RL0, RR0, load_next_key); + round1(32+14, RR0, RL0, load_next_key); + round1(32+15, RL0, RR0, dummy2); + + popq RW2; /*dst*/ + CFI_POP_TMP_REG(); + final_permutation(RR0, RL0); + write_block(RW2, RR0, RL0); + + popq %r15; + CFI_POP(%r15); + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_3des_amd64_crypt_block,.-_gcry_3des_amd64_crypt_block;) + +/*********************************************************************** + * 3-way 3DES + ***********************************************************************/ +#define expand_to_64bits(val, mask) \ + movl val##d, RT0d; \ + rorl $4, RT0d; \ + shlq $32, RT0; \ + orq RT0, val; \ + andq mask, val; + +#define compress_to_64bits(val) \ + movq val, RT0; \ + shrq $32, RT0; \ + roll $4, RT0d; \ + orl RT0d, val##d; + +#define initial_permutation3(left, right) \ + do_permutation(left##0d, right##0d, 4, 0x0f0f0f0f); \ + do_permutation(left##0d, right##0d, 16, 0x0000ffff); \ + do_permutation(left##1d, right##1d, 4, 0x0f0f0f0f); \ + do_permutation(left##1d, right##1d, 16, 0x0000ffff); \ + do_permutation(left##2d, right##2d, 4, 0x0f0f0f0f); \ + do_permutation(left##2d, right##2d, 16, 0x0000ffff); \ + \ + do_permutation(right##0d, left##0d, 2, 0x33333333); \ + do_permutation(right##0d, left##0d, 8, 0x00ff00ff); \ + do_permutation(right##1d, left##1d, 2, 0x33333333); \ + do_permutation(right##1d, left##1d, 8, 0x00ff00ff); \ + do_permutation(right##2d, left##2d, 2, 0x33333333); \ + do_permutation(right##2d, left##2d, 8, 0x00ff00ff); \ + \ + movabs $0x3f3f3f3f3f3f3f3f, RT3; \ + \ + movl left##0d, RW0d; \ + roll $1, right##0d; \ + xorl right##0d, RW0d; \ + andl $0xaaaaaaaa, RW0d; \ + xorl RW0d, left##0d; \ + xorl RW0d, right##0d; \ + roll $1, left##0d; \ + expand_to_64bits(right##0, RT3); \ + expand_to_64bits(left##0, RT3); \ + movl left##1d, RW1d; \ + roll $1, right##1d; \ + xorl right##1d, RW1d; \ + andl $0xaaaaaaaa, RW1d; \ + xorl RW1d, left##1d; \ + xorl RW1d, right##1d; \ + roll $1, left##1d; \ + expand_to_64bits(right##1, RT3); \ + expand_to_64bits(left##1, RT3); \ + movl left##2d, RW2d; \ + roll $1, right##2d; \ + xorl right##2d, RW2d; \ + andl $0xaaaaaaaa, RW2d; \ + xorl RW2d, left##2d; \ + xorl RW2d, right##2d; \ + roll $1, left##2d; \ + expand_to_64bits(right##2, RT3); \ + expand_to_64bits(left##2, RT3); + +#define final_permutation3(left, right) \ + compress_to_64bits(right##0); \ + compress_to_64bits(left##0); \ + movl right##0d, RW0d; \ + rorl $1, left##0d; \ + xorl left##0d, RW0d; \ + andl $0xaaaaaaaa, RW0d; \ + xorl RW0d, right##0d; \ + xorl RW0d, left##0d; \ + rorl $1, right##0d; \ + compress_to_64bits(right##1); \ + compress_to_64bits(left##1); \ + movl right##1d, RW1d; \ + rorl $1, left##1d; \ + xorl left##1d, RW1d; \ + andl $0xaaaaaaaa, RW1d; \ + xorl RW1d, right##1d; \ + xorl RW1d, left##1d; \ + rorl $1, right##1d; \ + compress_to_64bits(right##2); \ + compress_to_64bits(left##2); \ + movl right##2d, RW2d; \ + rorl $1, left##2d; \ + xorl left##2d, RW2d; \ + andl $0xaaaaaaaa, RW2d; \ + xorl RW2d, right##2d; \ + xorl RW2d, left##2d; \ + rorl $1, right##2d; \ + \ + do_permutation(right##0d, left##0d, 8, 0x00ff00ff); \ + do_permutation(right##0d, left##0d, 2, 0x33333333); \ + do_permutation(right##1d, left##1d, 8, 0x00ff00ff); \ + do_permutation(right##1d, left##1d, 2, 0x33333333); \ + do_permutation(right##2d, left##2d, 8, 0x00ff00ff); \ + do_permutation(right##2d, left##2d, 2, 0x33333333); \ + \ + do_permutation(left##0d, right##0d, 16, 0x0000ffff); \ + do_permutation(left##0d, right##0d, 4, 0x0f0f0f0f); \ + do_permutation(left##1d, right##1d, 16, 0x0000ffff); \ + do_permutation(left##1d, right##1d, 4, 0x0f0f0f0f); \ + do_permutation(left##2d, right##2d, 16, 0x0000ffff); \ + do_permutation(left##2d, right##2d, 4, 0x0f0f0f0f); + +#define round3(n, from, to, load_next_key, do_movq) \ + xorq from##0, RW0; \ + movzbl RW0bl, RT3d; \ + movzbl RW0bh, RT1d; \ + shrq $16, RW0; \ + xorq s8(SBOXES, RT3, 8), to##0; \ + xorq s6(SBOXES, RT1, 8), to##0; \ + movzbl RW0bl, RT3d; \ + movzbl RW0bh, RT1d; \ + shrq $16, RW0; \ + xorq s4(SBOXES, RT3, 8), to##0; \ + xorq s2(SBOXES, RT1, 8), to##0; \ + movzbl RW0bl, RT3d; \ + movzbl RW0bh, RT1d; \ + shrl $16, RW0d; \ + xorq s7(SBOXES, RT3, 8), to##0; \ + xorq s5(SBOXES, RT1, 8), to##0; \ + movzbl RW0bl, RT3d; \ + movzbl RW0bh, RT1d; \ + load_next_key(n, RW0); \ + xorq s3(SBOXES, RT3, 8), to##0; \ + xorq s1(SBOXES, RT1, 8), to##0; \ + xorq from##1, RW1; \ + movzbl RW1bl, RT3d; \ + movzbl RW1bh, RT1d; \ + shrq $16, RW1; \ + xorq s8(SBOXES, RT3, 8), to##1; \ + xorq s6(SBOXES, RT1, 8), to##1; \ + movzbl RW1bl, RT3d; \ + movzbl RW1bh, RT1d; \ + shrq $16, RW1; \ + xorq s4(SBOXES, RT3, 8), to##1; \ + xorq s2(SBOXES, RT1, 8), to##1; \ + movzbl RW1bl, RT3d; \ + movzbl RW1bh, RT1d; \ + shrl $16, RW1d; \ + xorq s7(SBOXES, RT3, 8), to##1; \ + xorq s5(SBOXES, RT1, 8), to##1; \ + movzbl RW1bl, RT3d; \ + movzbl RW1bh, RT1d; \ + do_movq(RW0, RW1); \ + xorq s3(SBOXES, RT3, 8), to##1; \ + xorq s1(SBOXES, RT1, 8), to##1; \ + xorq from##2, RW2; \ + movzbl RW2bl, RT3d; \ + movzbl RW2bh, RT1d; \ + shrq $16, RW2; \ + xorq s8(SBOXES, RT3, 8), to##2; \ + xorq s6(SBOXES, RT1, 8), to##2; \ + movzbl RW2bl, RT3d; \ + movzbl RW2bh, RT1d; \ + shrq $16, RW2; \ + xorq s4(SBOXES, RT3, 8), to##2; \ + xorq s2(SBOXES, RT1, 8), to##2; \ + movzbl RW2bl, RT3d; \ + movzbl RW2bh, RT1d; \ + shrl $16, RW2d; \ + xorq s7(SBOXES, RT3, 8), to##2; \ + xorq s5(SBOXES, RT1, 8), to##2; \ + movzbl RW2bl, RT3d; \ + movzbl RW2bh, RT1d; \ + do_movq(RW0, RW2); \ + xorq s3(SBOXES, RT3, 8), to##2; \ + xorq s1(SBOXES, RT1, 8), to##2; + +#define __movq(src, dst) \ + movq src, dst; + +#define read_block(io, left, right) \ + movl (io), left##d; \ + movl 4(io), right##d; \ + bswapl left##d; \ + bswapl right##d; + +#define write_block(io, left, right) \ + bswapl left##d; \ + bswapl right##d; \ + movl left##d, (io); \ + movl right##d, 4(io); + +.align 8 +ELF(.type _gcry_3des_amd64_crypt_blk3,@function;) +_gcry_3des_amd64_crypt_blk3: + /* input: + * %rdi: round keys, CTX + * RL0d, RR0d, RL1d, RR1d, RL2d, RR2d: 3 input blocks + * RR0d, RL0d, RR1d, RL1d, RR2d, RL2d: 3 output blocks + */ + CFI_STARTPROC(); + + leaq .L_s1 rRIP, SBOXES; + + initial_permutation3(RL, RR); + + movq 0(CTX), RW0; + movq RW0, RW1; + movq RW0, RW2; + + round3(0, RR, RL, load_next_key, __movq); + round3(1, RL, RR, load_next_key, __movq); + round3(2, RR, RL, load_next_key, __movq); + round3(3, RL, RR, load_next_key, __movq); + round3(4, RR, RL, load_next_key, __movq); + round3(5, RL, RR, load_next_key, __movq); + round3(6, RR, RL, load_next_key, __movq); + round3(7, RL, RR, load_next_key, __movq); + round3(8, RR, RL, load_next_key, __movq); + round3(9, RL, RR, load_next_key, __movq); + round3(10, RR, RL, load_next_key, __movq); + round3(11, RL, RR, load_next_key, __movq); + round3(12, RR, RL, load_next_key, __movq); + round3(13, RL, RR, load_next_key, __movq); + round3(14, RR, RL, load_next_key, __movq); + round3(15, RL, RR, load_next_key, __movq); + + round3(16+0, RL, RR, load_next_key, __movq); + round3(16+1, RR, RL, load_next_key, __movq); + round3(16+2, RL, RR, load_next_key, __movq); + round3(16+3, RR, RL, load_next_key, __movq); + round3(16+4, RL, RR, load_next_key, __movq); + round3(16+5, RR, RL, load_next_key, __movq); + round3(16+6, RL, RR, load_next_key, __movq); + round3(16+7, RR, RL, load_next_key, __movq); + round3(16+8, RL, RR, load_next_key, __movq); + round3(16+9, RR, RL, load_next_key, __movq); + round3(16+10, RL, RR, load_next_key, __movq); + round3(16+11, RR, RL, load_next_key, __movq); + round3(16+12, RL, RR, load_next_key, __movq); + round3(16+13, RR, RL, load_next_key, __movq); + round3(16+14, RL, RR, load_next_key, __movq); + round3(16+15, RR, RL, load_next_key, __movq); + + round3(32+0, RR, RL, load_next_key, __movq); + round3(32+1, RL, RR, load_next_key, __movq); + round3(32+2, RR, RL, load_next_key, __movq); + round3(32+3, RL, RR, load_next_key, __movq); + round3(32+4, RR, RL, load_next_key, __movq); + round3(32+5, RL, RR, load_next_key, __movq); + round3(32+6, RR, RL, load_next_key, __movq); + round3(32+7, RL, RR, load_next_key, __movq); + round3(32+8, RR, RL, load_next_key, __movq); + round3(32+9, RL, RR, load_next_key, __movq); + round3(32+10, RR, RL, load_next_key, __movq); + round3(32+11, RL, RR, load_next_key, __movq); + round3(32+12, RR, RL, load_next_key, __movq); + round3(32+13, RL, RR, load_next_key, __movq); + round3(32+14, RR, RL, load_next_key, __movq); + round3(32+15, RL, RR, dummy2, dummy2); + + final_permutation3(RR, RL); + + ret; + CFI_ENDPROC(); +ELF(.size _gcry_3des_amd64_crypt_blk3,.-_gcry_3des_amd64_crypt_blk3;) + +.align 8 +.globl _gcry_3des_amd64_cbc_dec +ELF(.type _gcry_3des_amd64_cbc_dec,@function;) +_gcry_3des_amd64_cbc_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (3 blocks) + * %rdx: src (3 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + pushq %r15; + CFI_PUSH(%r15); + + pushq %rsi; /*dst*/ + CFI_PUSH(%rsi); + pushq %rdx; /*src*/ + CFI_PUSH(%rdx); + pushq %rcx; /*iv*/ + CFI_PUSH(%rcx); + + /* load input */ + movl 0 * 4(%rdx), RL0d; + movl 1 * 4(%rdx), RR0d; + movl 2 * 4(%rdx), RL1d; + movl 3 * 4(%rdx), RR1d; + movl 4 * 4(%rdx), RL2d; + movl 5 * 4(%rdx), RR2d; + + bswapl RL0d; + bswapl RR0d; + bswapl RL1d; + bswapl RR1d; + bswapl RL2d; + bswapl RR2d; + + call _gcry_3des_amd64_crypt_blk3; + + popq %rcx; /*iv*/ + CFI_POP_TMP_REG(); + popq %rdx; /*src*/ + CFI_POP_TMP_REG(); + popq %rsi; /*dst*/ + CFI_POP_TMP_REG(); + + bswapl RR0d; + bswapl RL0d; + bswapl RR1d; + bswapl RL1d; + bswapl RR2d; + bswapl RL2d; + + movq 2 * 8(%rdx), RT0; + xorl 0 * 4(%rcx), RR0d; + xorl 1 * 4(%rcx), RL0d; + xorl 0 * 4(%rdx), RR1d; + xorl 1 * 4(%rdx), RL1d; + xorl 2 * 4(%rdx), RR2d; + xorl 3 * 4(%rdx), RL2d; + movq RT0, (%rcx); /* store new IV */ + + movl RR0d, 0 * 4(%rsi); + movl RL0d, 1 * 4(%rsi); + movl RR1d, 2 * 4(%rsi); + movl RL1d, 3 * 4(%rsi); + movl RR2d, 4 * 4(%rsi); + movl RL2d, 5 * 4(%rsi); + + popq %r15; + CFI_POP(%r15); + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_3des_amd64_cbc_dec,.-_gcry_3des_amd64_cbc_dec;) + +.align 8 +.globl _gcry_3des_amd64_ctr_enc +ELF(.type _gcry_3des_amd64_ctr_enc,@function;) +_gcry_3des_amd64_ctr_enc: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (3 blocks) + * %rdx: src (3 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + pushq %r15; + CFI_PUSH(%r15); + + pushq %rsi; /*dst*/ + CFI_PUSH(%rsi); + pushq %rdx; /*src*/ + CFI_PUSH(%rdx); + movq %rcx, RW2; + + /* load IV and byteswap */ + movq (RW2), RT0; + bswapq RT0; + movq RT0, RR0; + + /* construct IVs */ + leaq 1(RT0), RR1; + leaq 2(RT0), RR2; + leaq 3(RT0), RT0; + movq RR0, RL0; + movq RR1, RL1; + movq RR2, RL2; + bswapq RT0; + shrq $32, RL0; + shrq $32, RL1; + shrq $32, RL2; + + /* store new IV */ + movq RT0, (RW2); + + call _gcry_3des_amd64_crypt_blk3; + + popq %rdx; /*src*/ + CFI_POP_TMP_REG(); + popq %rsi; /*dst*/ + CFI_POP_TMP_REG(); + + bswapl RR0d; + bswapl RL0d; + bswapl RR1d; + bswapl RL1d; + bswapl RR2d; + bswapl RL2d; + + xorl 0 * 4(%rdx), RR0d; + xorl 1 * 4(%rdx), RL0d; + xorl 2 * 4(%rdx), RR1d; + xorl 3 * 4(%rdx), RL1d; + xorl 4 * 4(%rdx), RR2d; + xorl 5 * 4(%rdx), RL2d; + + movl RR0d, 0 * 4(%rsi); + movl RL0d, 1 * 4(%rsi); + movl RR1d, 2 * 4(%rsi); + movl RL1d, 3 * 4(%rsi); + movl RR2d, 4 * 4(%rsi); + movl RL2d, 5 * 4(%rsi); + + popq %r15; + CFI_POP(%r15); + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_3des_amd64_cbc_dec,.-_gcry_3des_amd64_cbc_dec;) + +.align 8 +.globl _gcry_3des_amd64_cfb_dec +ELF(.type _gcry_3des_amd64_cfb_dec,@function;) +_gcry_3des_amd64_cfb_dec: + /* input: + * %rdi: ctx, CTX + * %rsi: dst (3 blocks) + * %rdx: src (3 blocks) + * %rcx: iv (64bit) + */ + CFI_STARTPROC(); + ENTER_SYSV_FUNC_PARAMS_0_4 + + pushq %rbp; + CFI_PUSH(%rbp); + pushq %rbx; + CFI_PUSH(%rbx); + pushq %r12; + CFI_PUSH(%r12); + pushq %r13; + CFI_PUSH(%r13); + pushq %r14; + CFI_PUSH(%r14); + pushq %r15; + CFI_PUSH(%r15); + + pushq %rsi; /*dst*/ + CFI_PUSH(%rsi); + pushq %rdx; /*src*/ + CFI_PUSH(%rdx); + movq %rcx, RW2; + + /* Load input */ + movl 0 * 4(RW2), RL0d; + movl 1 * 4(RW2), RR0d; + movl 0 * 4(%rdx), RL1d; + movl 1 * 4(%rdx), RR1d; + movl 2 * 4(%rdx), RL2d; + movl 3 * 4(%rdx), RR2d; + + bswapl RL0d; + bswapl RR0d; + bswapl RL1d; + bswapl RR1d; + bswapl RL2d; + bswapl RR2d; + + /* Update IV */ + movq 4 * 4(%rdx), RW0; + movq RW0, (RW2); + + call _gcry_3des_amd64_crypt_blk3; + + popq %rdx; /*src*/ + CFI_POP_TMP_REG(); + popq %rsi; /*dst*/ + CFI_POP_TMP_REG(); + + bswapl RR0d; + bswapl RL0d; + bswapl RR1d; + bswapl RL1d; + bswapl RR2d; + bswapl RL2d; + + xorl 0 * 4(%rdx), RR0d; + xorl 1 * 4(%rdx), RL0d; + xorl 2 * 4(%rdx), RR1d; + xorl 3 * 4(%rdx), RL1d; + xorl 4 * 4(%rdx), RR2d; + xorl 5 * 4(%rdx), RL2d; + + movl RR0d, 0 * 4(%rsi); + movl RL0d, 1 * 4(%rsi); + movl RR1d, 2 * 4(%rsi); + movl RL1d, 3 * 4(%rsi); + movl RR2d, 4 * 4(%rsi); + movl RL2d, 5 * 4(%rsi); + + popq %r15; + CFI_POP(%r15); + popq %r14; + CFI_POP(%r14); + popq %r13; + CFI_POP(%r13); + popq %r12; + CFI_POP(%r12); + popq %rbx; + CFI_POP(%rbx); + popq %rbp; + CFI_POP(%rbp); + + EXIT_SYSV_FUNC + ret; + CFI_ENDPROC(); +ELF(.size _gcry_3des_amd64_cfb_dec,.-_gcry_3des_amd64_cfb_dec;) + +.align 16 +.L_s1: + .quad 0x0010100001010400, 0x0000000000000000 + .quad 0x0000100000010000, 0x0010100001010404 + .quad 0x0010100001010004, 0x0000100000010404 + .quad 0x0000000000000004, 0x0000100000010000 + .quad 0x0000000000000400, 0x0010100001010400 + .quad 0x0010100001010404, 0x0000000000000400 + .quad 0x0010000001000404, 0x0010100001010004 + .quad 0x0010000001000000, 0x0000000000000004 + .quad 0x0000000000000404, 0x0010000001000400 + .quad 0x0010000001000400, 0x0000100000010400 + .quad 0x0000100000010400, 0x0010100001010000 + .quad 0x0010100001010000, 0x0010000001000404 + .quad 0x0000100000010004, 0x0010000001000004 + .quad 0x0010000001000004, 0x0000100000010004 + .quad 0x0000000000000000, 0x0000000000000404 + .quad 0x0000100000010404, 0x0010000001000000 + .quad 0x0000100000010000, 0x0010100001010404 + .quad 0x0000000000000004, 0x0010100001010000 + .quad 0x0010100001010400, 0x0010000001000000 + .quad 0x0010000001000000, 0x0000000000000400 + .quad 0x0010100001010004, 0x0000100000010000 + .quad 0x0000100000010400, 0x0010000001000004 + .quad 0x0000000000000400, 0x0000000000000004 + .quad 0x0010000001000404, 0x0000100000010404 + .quad 0x0010100001010404, 0x0000100000010004 + .quad 0x0010100001010000, 0x0010000001000404 + .quad 0x0010000001000004, 0x0000000000000404 + .quad 0x0000100000010404, 0x0010100001010400 + .quad 0x0000000000000404, 0x0010000001000400 + .quad 0x0010000001000400, 0x0000000000000000 + .quad 0x0000100000010004, 0x0000100000010400 + .quad 0x0000000000000000, 0x0010100001010004 +.L_s2: + .quad 0x0801080200100020, 0x0800080000000000 + .quad 0x0000080000000000, 0x0001080200100020 + .quad 0x0001000000100000, 0x0000000200000020 + .quad 0x0801000200100020, 0x0800080200000020 + .quad 0x0800000200000020, 0x0801080200100020 + .quad 0x0801080000100000, 0x0800000000000000 + .quad 0x0800080000000000, 0x0001000000100000 + .quad 0x0000000200000020, 0x0801000200100020 + .quad 0x0001080000100000, 0x0001000200100020 + .quad 0x0800080200000020, 0x0000000000000000 + .quad 0x0800000000000000, 0x0000080000000000 + .quad 0x0001080200100020, 0x0801000000100000 + .quad 0x0001000200100020, 0x0800000200000020 + .quad 0x0000000000000000, 0x0001080000100000 + .quad 0x0000080200000020, 0x0801080000100000 + .quad 0x0801000000100000, 0x0000080200000020 + .quad 0x0000000000000000, 0x0001080200100020 + .quad 0x0801000200100020, 0x0001000000100000 + .quad 0x0800080200000020, 0x0801000000100000 + .quad 0x0801080000100000, 0x0000080000000000 + .quad 0x0801000000100000, 0x0800080000000000 + .quad 0x0000000200000020, 0x0801080200100020 + .quad 0x0001080200100020, 0x0000000200000020 + .quad 0x0000080000000000, 0x0800000000000000 + .quad 0x0000080200000020, 0x0801080000100000 + .quad 0x0001000000100000, 0x0800000200000020 + .quad 0x0001000200100020, 0x0800080200000020 + .quad 0x0800000200000020, 0x0001000200100020 + .quad 0x0001080000100000, 0x0000000000000000 + .quad 0x0800080000000000, 0x0000080200000020 + .quad 0x0800000000000000, 0x0801000200100020 + .quad 0x0801080200100020, 0x0001080000100000 +.L_s3: + .quad 0x0000002000000208, 0x0000202008020200 + .quad 0x0000000000000000, 0x0000200008020008 + .quad 0x0000002008000200, 0x0000000000000000 + .quad 0x0000202000020208, 0x0000002008000200 + .quad 0x0000200000020008, 0x0000000008000008 + .quad 0x0000000008000008, 0x0000200000020000 + .quad 0x0000202008020208, 0x0000200000020008 + .quad 0x0000200008020000, 0x0000002000000208 + .quad 0x0000000008000000, 0x0000000000000008 + .quad 0x0000202008020200, 0x0000002000000200 + .quad 0x0000202000020200, 0x0000200008020000 + .quad 0x0000200008020008, 0x0000202000020208 + .quad 0x0000002008000208, 0x0000202000020200 + .quad 0x0000200000020000, 0x0000002008000208 + .quad 0x0000000000000008, 0x0000202008020208 + .quad 0x0000002000000200, 0x0000000008000000 + .quad 0x0000202008020200, 0x0000000008000000 + .quad 0x0000200000020008, 0x0000002000000208 + .quad 0x0000200000020000, 0x0000202008020200 + .quad 0x0000002008000200, 0x0000000000000000 + .quad 0x0000002000000200, 0x0000200000020008 + .quad 0x0000202008020208, 0x0000002008000200 + .quad 0x0000000008000008, 0x0000002000000200 + .quad 0x0000000000000000, 0x0000200008020008 + .quad 0x0000002008000208, 0x0000200000020000 + .quad 0x0000000008000000, 0x0000202008020208 + .quad 0x0000000000000008, 0x0000202000020208 + .quad 0x0000202000020200, 0x0000000008000008 + .quad 0x0000200008020000, 0x0000002008000208 + .quad 0x0000002000000208, 0x0000200008020000 + .quad 0x0000202000020208, 0x0000000000000008 + .quad 0x0000200008020008, 0x0000202000020200 +.L_s4: + .quad 0x1008020000002001, 0x1000020800002001 + .quad 0x1000020800002001, 0x0000000800000000 + .quad 0x0008020800002000, 0x1008000800000001 + .quad 0x1008000000000001, 0x1000020000002001 + .quad 0x0000000000000000, 0x0008020000002000 + .quad 0x0008020000002000, 0x1008020800002001 + .quad 0x1000000800000001, 0x0000000000000000 + .quad 0x0008000800000000, 0x1008000000000001 + .quad 0x1000000000000001, 0x0000020000002000 + .quad 0x0008000000000000, 0x1008020000002001 + .quad 0x0000000800000000, 0x0008000000000000 + .quad 0x1000020000002001, 0x0000020800002000 + .quad 0x1008000800000001, 0x1000000000000001 + .quad 0x0000020800002000, 0x0008000800000000 + .quad 0x0000020000002000, 0x0008020800002000 + .quad 0x1008020800002001, 0x1000000800000001 + .quad 0x0008000800000000, 0x1008000000000001 + .quad 0x0008020000002000, 0x1008020800002001 + .quad 0x1000000800000001, 0x0000000000000000 + .quad 0x0000000000000000, 0x0008020000002000 + .quad 0x0000020800002000, 0x0008000800000000 + .quad 0x1008000800000001, 0x1000000000000001 + .quad 0x1008020000002001, 0x1000020800002001 + .quad 0x1000020800002001, 0x0000000800000000 + .quad 0x1008020800002001, 0x1000000800000001 + .quad 0x1000000000000001, 0x0000020000002000 + .quad 0x1008000000000001, 0x1000020000002001 + .quad 0x0008020800002000, 0x1008000800000001 + .quad 0x1000020000002001, 0x0000020800002000 + .quad 0x0008000000000000, 0x1008020000002001 + .quad 0x0000000800000000, 0x0008000000000000 + .quad 0x0000020000002000, 0x0008020800002000 +.L_s5: + .quad 0x0000001000000100, 0x0020001002080100 + .quad 0x0020000002080000, 0x0420001002000100 + .quad 0x0000000000080000, 0x0000001000000100 + .quad 0x0400000000000000, 0x0020000002080000 + .quad 0x0400001000080100, 0x0000000000080000 + .quad 0x0020001002000100, 0x0400001000080100 + .quad 0x0420001002000100, 0x0420000002080000 + .quad 0x0000001000080100, 0x0400000000000000 + .quad 0x0020000002000000, 0x0400000000080000 + .quad 0x0400000000080000, 0x0000000000000000 + .quad 0x0400001000000100, 0x0420001002080100 + .quad 0x0420001002080100, 0x0020001002000100 + .quad 0x0420000002080000, 0x0400001000000100 + .quad 0x0000000000000000, 0x0420000002000000 + .quad 0x0020001002080100, 0x0020000002000000 + .quad 0x0420000002000000, 0x0000001000080100 + .quad 0x0000000000080000, 0x0420001002000100 + .quad 0x0000001000000100, 0x0020000002000000 + .quad 0x0400000000000000, 0x0020000002080000 + .quad 0x0420001002000100, 0x0400001000080100 + .quad 0x0020001002000100, 0x0400000000000000 + .quad 0x0420000002080000, 0x0020001002080100 + .quad 0x0400001000080100, 0x0000001000000100 + .quad 0x0020000002000000, 0x0420000002080000 + .quad 0x0420001002080100, 0x0000001000080100 + .quad 0x0420000002000000, 0x0420001002080100 + .quad 0x0020000002080000, 0x0000000000000000 + .quad 0x0400000000080000, 0x0420000002000000 + .quad 0x0000001000080100, 0x0020001002000100 + .quad 0x0400001000000100, 0x0000000000080000 + .quad 0x0000000000000000, 0x0400000000080000 + .quad 0x0020001002080100, 0x0400001000000100 +.L_s6: + .quad 0x0200000120000010, 0x0204000020000000 + .quad 0x0000040000000000, 0x0204040120000010 + .quad 0x0204000020000000, 0x0000000100000010 + .quad 0x0204040120000010, 0x0004000000000000 + .quad 0x0200040020000000, 0x0004040100000010 + .quad 0x0004000000000000, 0x0200000120000010 + .quad 0x0004000100000010, 0x0200040020000000 + .quad 0x0200000020000000, 0x0000040100000010 + .quad 0x0000000000000000, 0x0004000100000010 + .quad 0x0200040120000010, 0x0000040000000000 + .quad 0x0004040000000000, 0x0200040120000010 + .quad 0x0000000100000010, 0x0204000120000010 + .quad 0x0204000120000010, 0x0000000000000000 + .quad 0x0004040100000010, 0x0204040020000000 + .quad 0x0000040100000010, 0x0004040000000000 + .quad 0x0204040020000000, 0x0200000020000000 + .quad 0x0200040020000000, 0x0000000100000010 + .quad 0x0204000120000010, 0x0004040000000000 + .quad 0x0204040120000010, 0x0004000000000000 + .quad 0x0000040100000010, 0x0200000120000010 + .quad 0x0004000000000000, 0x0200040020000000 + .quad 0x0200000020000000, 0x0000040100000010 + .quad 0x0200000120000010, 0x0204040120000010 + .quad 0x0004040000000000, 0x0204000020000000 + .quad 0x0004040100000010, 0x0204040020000000 + .quad 0x0000000000000000, 0x0204000120000010 + .quad 0x0000000100000010, 0x0000040000000000 + .quad 0x0204000020000000, 0x0004040100000010 + .quad 0x0000040000000000, 0x0004000100000010 + .quad 0x0200040120000010, 0x0000000000000000 + .quad 0x0204040020000000, 0x0200000020000000 + .quad 0x0004000100000010, 0x0200040120000010 +.L_s7: + .quad 0x0002000000200000, 0x2002000004200002 + .quad 0x2000000004000802, 0x0000000000000000 + .quad 0x0000000000000800, 0x2000000004000802 + .quad 0x2002000000200802, 0x0002000004200800 + .quad 0x2002000004200802, 0x0002000000200000 + .quad 0x0000000000000000, 0x2000000004000002 + .quad 0x2000000000000002, 0x0000000004000000 + .quad 0x2002000004200002, 0x2000000000000802 + .quad 0x0000000004000800, 0x2002000000200802 + .quad 0x2002000000200002, 0x0000000004000800 + .quad 0x2000000004000002, 0x0002000004200000 + .quad 0x0002000004200800, 0x2002000000200002 + .quad 0x0002000004200000, 0x0000000000000800 + .quad 0x2000000000000802, 0x2002000004200802 + .quad 0x0002000000200800, 0x2000000000000002 + .quad 0x0000000004000000, 0x0002000000200800 + .quad 0x0000000004000000, 0x0002000000200800 + .quad 0x0002000000200000, 0x2000000004000802 + .quad 0x2000000004000802, 0x2002000004200002 + .quad 0x2002000004200002, 0x2000000000000002 + .quad 0x2002000000200002, 0x0000000004000000 + .quad 0x0000000004000800, 0x0002000000200000 + .quad 0x0002000004200800, 0x2000000000000802 + .quad 0x2002000000200802, 0x0002000004200800 + .quad 0x2000000000000802, 0x2000000004000002 + .quad 0x2002000004200802, 0x0002000004200000 + .quad 0x0002000000200800, 0x0000000000000000 + .quad 0x2000000000000002, 0x2002000004200802 + .quad 0x0000000000000000, 0x2002000000200802 + .quad 0x0002000004200000, 0x0000000000000800 + .quad 0x2000000004000002, 0x0000000004000800 + .quad 0x0000000000000800, 0x2002000000200002 +.L_s8: + .quad 0x0100010410001000, 0x0000010000001000 + .quad 0x0000000000040000, 0x0100010410041000 + .quad 0x0100000010000000, 0x0100010410001000 + .quad 0x0000000400000000, 0x0100000010000000 + .quad 0x0000000400040000, 0x0100000010040000 + .quad 0x0100010410041000, 0x0000010000041000 + .quad 0x0100010010041000, 0x0000010400041000 + .quad 0x0000010000001000, 0x0000000400000000 + .quad 0x0100000010040000, 0x0100000410000000 + .quad 0x0100010010001000, 0x0000010400001000 + .quad 0x0000010000041000, 0x0000000400040000 + .quad 0x0100000410040000, 0x0100010010041000 + .quad 0x0000010400001000, 0x0000000000000000 + .quad 0x0000000000000000, 0x0100000410040000 + .quad 0x0100000410000000, 0x0100010010001000 + .quad 0x0000010400041000, 0x0000000000040000 + .quad 0x0000010400041000, 0x0000000000040000 + .quad 0x0100010010041000, 0x0000010000001000 + .quad 0x0000000400000000, 0x0100000410040000 + .quad 0x0000010000001000, 0x0000010400041000 + .quad 0x0100010010001000, 0x0000000400000000 + .quad 0x0100000410000000, 0x0100000010040000 + .quad 0x0100000410040000, 0x0100000010000000 + .quad 0x0000000000040000, 0x0100010410001000 + .quad 0x0000000000000000, 0x0100010410041000 + .quad 0x0000000400040000, 0x0100000410000000 + .quad 0x0100000010040000, 0x0100010010001000 + .quad 0x0100010410001000, 0x0000000000000000 + .quad 0x0100010410041000, 0x0000010000041000 + .quad 0x0000010000041000, 0x0000010400001000 + .quad 0x0000010400001000, 0x0000000400040000 + .quad 0x0100000010000000, 0x0100010010041000 + +#endif +#endif diff --git a/comm/third_party/libgcrypt/cipher/des.c b/comm/third_party/libgcrypt/cipher/des.c new file mode 100644 index 0000000000..1580ea4ec5 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/des.c @@ -0,0 +1,1507 @@ +/* des.c - DES and Triple-DES encryption/decryption Algorithm + * Copyright (C) 1998, 1999, 2001, 2002, 2003, + * 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * For a description of triple encryption, see: + * Bruce Schneier: Applied Cryptography. Second Edition. + * John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff. + * This implementation is according to the definition of DES in FIPS + * PUB 46-2 from December 1993. + */ + + +/* + * Written by Michael Roth , September 1998 + */ + + +/* + * U S A G E + * =========== + * + * For DES or Triple-DES encryption/decryption you must initialize a proper + * encryption context with a key. + * + * A DES key is 64bit wide but only 56bits of the key are used. The remaining + * bits are parity bits and they will _not_ checked in this implementation, but + * simply ignored. + * + * For Triple-DES you could use either two 64bit keys or three 64bit keys. + * The parity bits will _not_ checked, too. + * + * After initializing a context with a key you could use this context to + * encrypt or decrypt data in 64bit blocks in Electronic Codebook Mode. + * + * (In the examples below the slashes at the beginning and ending of comments + * are omitted.) + * + * DES Example + * ----------- + * unsigned char key[8]; + * unsigned char plaintext[8]; + * unsigned char ciphertext[8]; + * unsigned char recoverd[8]; + * des_ctx context; + * + * * Fill 'key' and 'plaintext' with some data * + * .... + * + * * Set up the DES encryption context * + * des_setkey(context, key); + * + * * Encrypt the plaintext * + * des_ecb_encrypt(context, plaintext, ciphertext); + * + * * To recover the original plaintext from ciphertext use: * + * des_ecb_decrypt(context, ciphertext, recoverd); + * + * + * Triple-DES Example + * ------------------ + * unsigned char key1[8]; + * unsigned char key2[8]; + * unsigned char key3[8]; + * unsigned char plaintext[8]; + * unsigned char ciphertext[8]; + * unsigned char recoverd[8]; + * tripledes_ctx context; + * + * * If you would like to use two 64bit keys, fill 'key1' and'key2' + * then setup the encryption context: * + * tripledes_set2keys(context, key1, key2); + * + * * To use three 64bit keys with Triple-DES use: * + * tripledes_set3keys(context, key1, key2, key3); + * + * * Encrypting plaintext with Triple-DES * + * tripledes_ecb_encrypt(context, plaintext, ciphertext); + * + * * Decrypting ciphertext to recover the plaintext with Triple-DES * + * tripledes_ecb_decrypt(context, ciphertext, recoverd); + * + * + * Selftest + * -------- + * char *error_msg; + * + * * To perform a selftest of this DES/Triple-DES implementation use the + * function selftest(). It will return an error string if there are + * some problems with this library. * + * + * if ( (error_msg = selftest()) ) + * { + * fprintf(stderr, "An error in the DES/Triple-DES implementation occurred: %s\n", error_msg); + * abort(); + * } + */ + + +#include +#include +#include /* memcpy, memcmp */ +#include "types.h" /* for byte and u32 typedefs */ +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "cipher-internal.h" +#include "cipher-selftest.h" + + +#define DES_BLOCKSIZE 8 + + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) +# define USE_AMD64_ASM 1 +#endif + +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + +#if defined(__GNUC__) && defined(__GNU_LIBRARY__) +# define working_memcmp memcmp +#else +/* + * According to the SunOS man page, memcmp returns indeterminate sign + * depending on whether characters are signed or not. + */ +static int +working_memcmp( const void *_a, const void *_b, size_t n ) +{ + const char *a = _a; + const char *b = _b; + for( ; n; n--, a++, b++ ) + if( *a != *b ) + return (int)(*(byte*)a) - (int)(*(byte*)b); + return 0; +} +#endif + +/* + * Encryption/Decryption context of DES + */ +typedef struct _des_ctx + { + u32 encrypt_subkeys[32]; + u32 decrypt_subkeys[32]; + } +des_ctx[1]; + +/* + * Encryption/Decryption context of Triple-DES + */ +typedef struct _tripledes_ctx + { + u32 encrypt_subkeys[96]; + u32 decrypt_subkeys[96]; + struct { + int no_weak_key; + } flags; + } +tripledes_ctx[1]; + +static void des_key_schedule (const byte *, u32 *); +static int des_setkey (struct _des_ctx *, const byte *); +static int des_ecb_crypt (struct _des_ctx *, const byte *, byte *, int); +static int tripledes_set2keys (struct _tripledes_ctx *, + const byte *, const byte *); +static int tripledes_set3keys (struct _tripledes_ctx *, + const byte *, const byte *, const byte *); +static int tripledes_ecb_crypt (struct _tripledes_ctx *, + const byte *, byte *, int); +static int is_weak_key ( const byte *key ); +static const char *selftest (void); +static unsigned int do_tripledes_encrypt(void *context, byte *outbuf, + const byte *inbuf ); +static unsigned int do_tripledes_decrypt(void *context, byte *outbuf, + const byte *inbuf ); +static gcry_err_code_t do_tripledes_setkey(void *context, const byte *key, + unsigned keylen, + cipher_bulk_ops_t *bulk_ops); + +static int initialized; + + + + +/* + * The s-box values are permuted according to the 'primitive function P' + * and are rotated one bit to the left. + */ +static u32 sbox1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static u32 sbox2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static u32 sbox3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static u32 sbox4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static u32 sbox5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static u32 sbox6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static u32 sbox7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static u32 sbox8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + + +/* + * These two tables are part of the 'permuted choice 1' function. + * In this implementation several speed improvements are done. + */ +static u32 leftkey_swap[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static u32 rightkey_swap[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + + + +/* + * Numbers of left shifts per round for encryption subkeys. + * To calculate the decryption subkeys we just reverse the + * ordering of the calculated encryption subkeys. So their + * is no need for a decryption rotate tab. + */ +static byte encrypt_rotate_tab[16] = +{ + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + + + +/* + * Table with weak DES keys sorted in ascending order. + * In DES their are 64 known keys which are weak. They are weak + * because they produce only one, two or four different + * subkeys in the subkey scheduling process. + * The keys in this table have all their parity bits cleared. + */ +static byte weak_keys[64][8] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /*w*/ + { 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e }, + { 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0 }, + { 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe }, + { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e }, /*sw*/ + { 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00 }, + { 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe }, + { 0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0 }, + { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0 }, /*sw*/ + { 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe }, + { 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00 }, + { 0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e }, + { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe }, /*sw*/ + { 0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0 }, + { 0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e }, + { 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00 }, + { 0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e }, + { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 }, /*sw*/ + { 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe }, + { 0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0 }, + { 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00 }, + { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e }, /*w*/ + { 0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0 }, + { 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe }, + { 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe }, + { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 }, /*sw*/ + { 0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e }, + { 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00 }, + { 0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0 }, + { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe }, /*sw*/ + { 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00 }, + { 0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e }, + { 0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0 }, + { 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe }, + { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 }, /*sw*/ + { 0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e }, + { 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe }, + { 0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0 }, + { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e }, /*sw*/ + { 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00 }, + { 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00 }, + { 0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e }, + { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 }, /*w*/ + { 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe }, + { 0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e }, + { 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00 }, + { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe }, /*sw*/ + { 0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0 }, + { 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe }, + { 0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0 }, + { 0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e }, + { 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00 }, /*sw*/ + { 0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0 }, + { 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe }, + { 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00 }, + { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e }, /*sw*/ + { 0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e }, + { 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00 }, + { 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe }, + { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 }, /*sw*/ + { 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00 }, + { 0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e }, + { 0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0 }, + { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe } /*w*/ +}; +static unsigned char weak_keys_chksum[20] = { + 0xD0, 0xCF, 0x07, 0x38, 0x93, 0x70, 0x8A, 0x83, 0x7D, 0xD7, + 0x8A, 0x36, 0x65, 0x29, 0x6C, 0x1F, 0x7C, 0x3F, 0xD3, 0x41 +}; + + + +/* + * Macro to swap bits across two words. + */ +#define DO_PERMUTATION(a, temp, b, offset, mask) \ + temp = ((a>>offset) ^ b) & mask; \ + b ^= temp; \ + a ^= temp<> 31); \ + temp = (left ^ right) & 0xaaaaaaaa; \ + right ^= temp; \ + left ^= temp; \ + left = (left << 1) | (left >> 31); + +/* + * The 'inverse initial permutation'. + */ +#define FINAL_PERMUTATION(left, temp, right) \ + left = (left << 31) | (left >> 1); \ + temp = (left ^ right) & 0xaaaaaaaa; \ + left ^= temp; \ + right ^= temp; \ + right = (right << 31) | (right >> 1); \ + DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \ + DO_PERMUTATION(right, temp, left, 2, 0x33333333) \ + DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \ + DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f) + + +/* + * A full DES round including 'expansion function', 'sbox substitution' + * and 'primitive function P' but without swapping the left and right word. + * Please note: The data in 'from' and 'to' is already rotated one bit to + * the left, done in the initial permutation. + */ +#define DES_ROUND(from, to, work, subkey) \ + work = from ^ *subkey++; \ + to ^= sbox8[ work & 0x3f ]; \ + to ^= sbox6[ (work>>8) & 0x3f ]; \ + to ^= sbox4[ (work>>16) & 0x3f ]; \ + to ^= sbox2[ (work>>24) & 0x3f ]; \ + work = ((from << 28) | (from >> 4)) ^ *subkey++; \ + to ^= sbox7[ work & 0x3f ]; \ + to ^= sbox5[ (work>>8) & 0x3f ]; \ + to ^= sbox3[ (work>>16) & 0x3f ]; \ + to ^= sbox1[ (work>>24) & 0x3f ]; + +/* + * Macros to convert 8 bytes from/to 32bit words. + */ +#define READ_64BIT_DATA(data, left, right) \ + left = buf_get_be32(data + 0); \ + right = buf_get_be32(data + 4); + +#define WRITE_64BIT_DATA(data, left, right) \ + buf_put_be32(data + 0, left); \ + buf_put_be32(data + 4, right); + +/* + * Handy macros for encryption and decryption of data + */ +#define des_ecb_encrypt(ctx, from, to) des_ecb_crypt(ctx, from, to, 0) +#define des_ecb_decrypt(ctx, from, to) des_ecb_crypt(ctx, from, to, 1) +#define tripledes_ecb_encrypt(ctx, from, to) tripledes_ecb_crypt(ctx,from,to,0) +#define tripledes_ecb_decrypt(ctx, from, to) tripledes_ecb_crypt(ctx,from,to,1) + + + + + + +/* + * des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for + * 16 encryption rounds. + * To calculate subkeys for decryption the caller + * have to reorder the generated subkeys. + * + * rawkey: 8 Bytes of key data + * subkey: Array of at least 32 u32s. Will be filled + * with calculated subkeys. + * + */ +static void +des_key_schedule (const byte * rawkey, u32 * subkey) +{ + u32 left, right, work; + int round; + + READ_64BIT_DATA (rawkey, left, right) + + DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f) + DO_PERMUTATION (right, work, left, 0, 0x10101010) + + left = ((leftkey_swap[(left >> 0) & 0xf] << 3) + | (leftkey_swap[(left >> 8) & 0xf] << 2) + | (leftkey_swap[(left >> 16) & 0xf] << 1) + | (leftkey_swap[(left >> 24) & 0xf]) + | (leftkey_swap[(left >> 5) & 0xf] << 7) + | (leftkey_swap[(left >> 13) & 0xf] << 6) + | (leftkey_swap[(left >> 21) & 0xf] << 5) + | (leftkey_swap[(left >> 29) & 0xf] << 4)); + + left &= 0x0fffffff; + + right = ((rightkey_swap[(right >> 1) & 0xf] << 3) + | (rightkey_swap[(right >> 9) & 0xf] << 2) + | (rightkey_swap[(right >> 17) & 0xf] << 1) + | (rightkey_swap[(right >> 25) & 0xf]) + | (rightkey_swap[(right >> 4) & 0xf] << 7) + | (rightkey_swap[(right >> 12) & 0xf] << 6) + | (rightkey_swap[(right >> 20) & 0xf] << 5) + | (rightkey_swap[(right >> 28) & 0xf] << 4)); + + right &= 0x0fffffff; + + for (round = 0; round < 16; ++round) + { + left = ((left << encrypt_rotate_tab[round]) + | (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff; + right = ((right << encrypt_rotate_tab[round]) + | (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff; + + *subkey++ = (((left << 4) & 0x24000000) + | ((left << 28) & 0x10000000) + | ((left << 14) & 0x08000000) + | ((left << 18) & 0x02080000) + | ((left << 6) & 0x01000000) + | ((left << 9) & 0x00200000) + | ((left >> 1) & 0x00100000) + | ((left << 10) & 0x00040000) + | ((left << 2) & 0x00020000) + | ((left >> 10) & 0x00010000) + | ((right >> 13) & 0x00002000) + | ((right >> 4) & 0x00001000) + | ((right << 6) & 0x00000800) + | ((right >> 1) & 0x00000400) + | ((right >> 14) & 0x00000200) + | (right & 0x00000100) + | ((right >> 5) & 0x00000020) + | ((right >> 10) & 0x00000010) + | ((right >> 3) & 0x00000008) + | ((right >> 18) & 0x00000004) + | ((right >> 26) & 0x00000002) + | ((right >> 24) & 0x00000001)); + + *subkey++ = (((left << 15) & 0x20000000) + | ((left << 17) & 0x10000000) + | ((left << 10) & 0x08000000) + | ((left << 22) & 0x04000000) + | ((left >> 2) & 0x02000000) + | ((left << 1) & 0x01000000) + | ((left << 16) & 0x00200000) + | ((left << 11) & 0x00100000) + | ((left << 3) & 0x00080000) + | ((left >> 6) & 0x00040000) + | ((left << 15) & 0x00020000) + | ((left >> 4) & 0x00010000) + | ((right >> 2) & 0x00002000) + | ((right << 8) & 0x00001000) + | ((right >> 14) & 0x00000808) + | ((right >> 9) & 0x00000400) + | ((right) & 0x00000200) + | ((right << 7) & 0x00000100) + | ((right >> 7) & 0x00000020) + | ((right >> 3) & 0x00000011) + | ((right << 2) & 0x00000004) + | ((right >> 21) & 0x00000002)); + } +} + + +/* + * Fill a DES context with subkeys calculated from a 64bit key. + * Does not check parity bits, but simply ignore them. + * Does not check for weak keys. + */ +static int +des_setkey (struct _des_ctx *ctx, const byte * key) +{ + static const char *selftest_failed; + int i; + + if (!fips_mode () && !initialized) + { + initialized = 1; + selftest_failed = selftest (); + + if (selftest_failed) + log_error ("%s\n", selftest_failed); + } + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + des_key_schedule (key, ctx->encrypt_subkeys); + _gcry_burn_stack (32); + + for(i=0; i<32; i+=2) + { + ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i]; + ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i]; + } + + return 0; +} + + + +/* + * Electronic Codebook Mode DES encryption/decryption of data according + * to 'mode'. + */ +static int +des_ecb_crypt (struct _des_ctx *ctx, const byte * from, byte * to, int mode) +{ + u32 left, right, work; + u32 *keys; + + keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys; + + READ_64BIT_DATA (from, left, right) + INITIAL_PERMUTATION (left, work, right) + + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + + FINAL_PERMUTATION (right, work, left) + WRITE_64BIT_DATA (to, right, left) + + return 0; +} + + + +/* + * Fill a Triple-DES context with subkeys calculated from two 64bit keys. + * Does not check the parity bits of the keys, but simply ignore them. + * Does not check for weak keys. + */ +static int +tripledes_set2keys (struct _tripledes_ctx *ctx, + const byte * key1, + const byte * key2) +{ + int i; + + des_key_schedule (key1, ctx->encrypt_subkeys); + des_key_schedule (key2, &(ctx->decrypt_subkeys[32])); + _gcry_burn_stack (32); + + for(i=0; i<32; i+=2) + { + ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i]; + ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i]; + + ctx->encrypt_subkeys[i+32] = ctx->decrypt_subkeys[62-i]; + ctx->encrypt_subkeys[i+33] = ctx->decrypt_subkeys[63-i]; + + ctx->encrypt_subkeys[i+64] = ctx->encrypt_subkeys[i]; + ctx->encrypt_subkeys[i+65] = ctx->encrypt_subkeys[i+1]; + + ctx->decrypt_subkeys[i+64] = ctx->decrypt_subkeys[i]; + ctx->decrypt_subkeys[i+65] = ctx->decrypt_subkeys[i+1]; + } + + return 0; +} + + + +/* + * Fill a Triple-DES context with subkeys calculated from three 64bit keys. + * Does not check the parity bits of the keys, but simply ignore them. + * Does not check for weak keys. + */ +static int +tripledes_set3keys (struct _tripledes_ctx *ctx, + const byte * key1, + const byte * key2, + const byte * key3) +{ + static const char *selftest_failed; + int i; + + if (!fips_mode () && !initialized) + { + initialized = 1; + selftest_failed = selftest (); + + if (selftest_failed) + log_error ("%s\n", selftest_failed); + } + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + des_key_schedule (key1, ctx->encrypt_subkeys); + des_key_schedule (key2, &(ctx->decrypt_subkeys[32])); + des_key_schedule (key3, &(ctx->encrypt_subkeys[64])); + _gcry_burn_stack (32); + + for(i=0; i<32; i+=2) + { + ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[94-i]; + ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[95-i]; + + ctx->encrypt_subkeys[i+32] = ctx->decrypt_subkeys[62-i]; + ctx->encrypt_subkeys[i+33] = ctx->decrypt_subkeys[63-i]; + + ctx->decrypt_subkeys[i+64] = ctx->encrypt_subkeys[30-i]; + ctx->decrypt_subkeys[i+65] = ctx->encrypt_subkeys[31-i]; + } + + return 0; +} + + + +#ifdef USE_AMD64_ASM + +/* Assembly implementation of triple-DES. */ +extern void _gcry_3des_amd64_crypt_block(const void *keys, byte *out, + const byte *in); + +/* These assembly implementations process three blocks in parallel. */ +extern void _gcry_3des_amd64_ctr_enc(const void *keys, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_3des_amd64_cbc_dec(const void *keys, byte *out, + const byte *in, byte *iv); + +extern void _gcry_3des_amd64_cfb_dec(const void *keys, byte *out, + const byte *in, byte *iv); + +#define TRIPLEDES_ECB_BURN_STACK (8 * sizeof(void *)) + + +/* + * Electronic Codebook Mode Triple-DES encryption/decryption of data + * according to 'mode'. Sometimes this mode is named 'EDE' mode + * (Encryption-Decryption-Encryption). + */ +static inline int +tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from, + byte * to, int mode) +{ + u32 *keys; + + keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys; + + _gcry_3des_amd64_crypt_block(keys, to, from); + + return 0; +} + +static inline void +tripledes_amd64_ctr_enc(const void *keys, byte *out, const byte *in, byte *ctr) +{ + _gcry_3des_amd64_ctr_enc(keys, out, in, ctr); +} + +static inline void +tripledes_amd64_cbc_dec(const void *keys, byte *out, const byte *in, byte *iv) +{ + _gcry_3des_amd64_cbc_dec(keys, out, in, iv); +} + +static inline void +tripledes_amd64_cfb_dec(const void *keys, byte *out, const byte *in, byte *iv) +{ + _gcry_3des_amd64_cfb_dec(keys, out, in, iv); +} + +#else /*USE_AMD64_ASM*/ + +#define TRIPLEDES_ECB_BURN_STACK 32 + +/* + * Electronic Codebook Mode Triple-DES encryption/decryption of data + * according to 'mode'. Sometimes this mode is named 'EDE' mode + * (Encryption-Decryption-Encryption). + */ +static int +tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from, + byte * to, int mode) +{ + u32 left, right, work; + u32 *keys; + + keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys; + + READ_64BIT_DATA (from, left, right) + INITIAL_PERMUTATION (left, work, right) + + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys) + + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + + FINAL_PERMUTATION (right, work, left) + WRITE_64BIT_DATA (to, right, left) + + return 0; +} + +#endif /*!USE_AMD64_ASM*/ + + + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size DES_BLOCKSIZE. */ +static void +_gcry_3des_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + struct _tripledes_ctx *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[DES_BLOCKSIZE]; + int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK; + +#ifdef USE_AMD64_ASM + { + int asm_burn_depth = 9 * sizeof(void *); + + if (nblocks >= 3 && burn_stack_depth < asm_burn_depth) + burn_stack_depth = asm_burn_depth; + + /* Process data in 3 block chunks. */ + while (nblocks >= 3) + { + tripledes_amd64_ctr_enc(ctx->encrypt_subkeys, outbuf, inbuf, ctr); + + nblocks -= 3; + outbuf += 3 * DES_BLOCKSIZE; + inbuf += 3 * DES_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + tripledes_ecb_encrypt (ctx, ctr, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + cipher_block_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE); + outbuf += DES_BLOCKSIZE; + inbuf += DES_BLOCKSIZE; + /* Increment the counter. */ + cipher_block_add(ctr, 1, DES_BLOCKSIZE); + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_3des_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + struct _tripledes_ctx *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[DES_BLOCKSIZE]; + int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK; + +#ifdef USE_AMD64_ASM + { + int asm_burn_depth = 10 * sizeof(void *); + + if (nblocks >= 3 && burn_stack_depth < asm_burn_depth) + burn_stack_depth = asm_burn_depth; + + /* Process data in 3 block chunks. */ + while (nblocks >= 3) + { + tripledes_amd64_cbc_dec(ctx->decrypt_subkeys, outbuf, inbuf, iv); + + nblocks -= 3; + outbuf += 3 * DES_BLOCKSIZE; + inbuf += 3 * DES_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + tripledes_ecb_decrypt (ctx, inbuf, savebuf); + + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE); + inbuf += DES_BLOCKSIZE; + outbuf += DES_BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +static void +_gcry_3des_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + struct _tripledes_ctx *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = TRIPLEDES_ECB_BURN_STACK; + +#ifdef USE_AMD64_ASM + { + int asm_burn_depth = 9 * sizeof(void *); + + if (nblocks >= 3 && burn_stack_depth < asm_burn_depth) + burn_stack_depth = asm_burn_depth; + + /* Process data in 3 block chunks. */ + while (nblocks >= 3) + { + tripledes_amd64_cfb_dec(ctx->encrypt_subkeys, outbuf, inbuf, iv); + + nblocks -= 3; + outbuf += 3 * DES_BLOCKSIZE; + inbuf += 3 * DES_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + tripledes_ecb_encrypt (ctx, iv, iv); + cipher_block_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE); + outbuf += DES_BLOCKSIZE; + inbuf += DES_BLOCKSIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + + +/* + * Check whether the 8 byte key is weak. + * Does not check the parity bits of the key but simple ignore them. + */ +static int +is_weak_key ( const byte *key ) +{ + byte work[8]; + int i, left, right, middle, cmp_result; + + /* clear parity bits */ + for(i=0; i<8; ++i) + work[i] = key[i] & 0xfe; + + /* binary search in the weak key table */ + left = 0; + right = 63; + while(left <= right) + { + middle = (left + right) / 2; + + if ( !(cmp_result=working_memcmp(work, weak_keys[middle], 8)) ) + return -1; + + if ( cmp_result > 0 ) + left = middle + 1; + else + right = middle - 1; + } + + return 0; +} + + +/* Alternative setkey for selftests; need larger key than default. */ +static gcry_err_code_t +bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen, + cipher_bulk_ops_t *bulk_ops) +{ + static const unsigned char key[24] ATTR_ALIGNED_16 = { + 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22, + 0x18,0x2A,0x39,0x47,0x5E,0x6F,0x75,0x82 + }; + + (void)__key; + (void)__keylen; + + return do_tripledes_setkey(context, key, sizeof(key), bulk_ops); +} + + +/* Run the self-tests for DES-CTR, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char * +selftest_ctr (void) +{ + const int nblocks = 3+1; + const int blocksize = DES_BLOCKSIZE; + const int context_size = sizeof(struct _tripledes_ctx); + + return _gcry_selftest_helper_ctr("3DES", &bulk_selftest_setkey, + &do_tripledes_encrypt, nblocks, blocksize, context_size); +} + + +/* Run the self-tests for DES-CBC, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cbc (void) +{ + const int nblocks = 3+2; + const int blocksize = DES_BLOCKSIZE; + const int context_size = sizeof(struct _tripledes_ctx); + + return _gcry_selftest_helper_cbc("3DES", &bulk_selftest_setkey, + &do_tripledes_encrypt, nblocks, blocksize, context_size); +} + + +/* Run the self-tests for DES-CFB, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cfb (void) +{ + const int nblocks = 3+2; + const int blocksize = DES_BLOCKSIZE; + const int context_size = sizeof(struct _tripledes_ctx); + + return _gcry_selftest_helper_cfb("3DES", &bulk_selftest_setkey, + &do_tripledes_encrypt, nblocks, blocksize, context_size); +} + + +/* + * Performs a selftest of this DES/Triple-DES implementation. + * Returns an string with the error text on failure. + * Returns NULL if all is ok. + */ +static const char * +selftest (void) +{ + const char *r; + + /* + * Check if 'u32' is really 32 bits wide. This DES / 3DES implementation + * need this. + */ + if (sizeof (u32) != 4) + return "Wrong word size for DES configured."; + + /* + * DES Maintenance Test + */ + { + int i; + byte key[8] = + {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; + byte input[8] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + byte result[8] = + {0x24, 0x6e, 0x9d, 0xb9, 0xc5, 0x50, 0x38, 0x1a}; + byte temp1[8], temp2[8], temp3[8]; + des_ctx des; + + for (i = 0; i < 64; ++i) + { + des_setkey (des, key); + des_ecb_encrypt (des, input, temp1); + des_ecb_encrypt (des, temp1, temp2); + des_setkey (des, temp2); + des_ecb_decrypt (des, temp1, temp3); + memcpy (key, temp3, 8); + memcpy (input, temp1, 8); + } + if (memcmp (temp3, result, 8)) + return "DES maintenance test failed."; + } + + + /* + * Self made Triple-DES test (Does somebody know an official test?) + */ + { + int i; + byte input[8] = + {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; + byte key1[8] = + {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}; + byte key2[8] = + {0x11, 0x22, 0x33, 0x44, 0xff, 0xaa, 0xcc, 0xdd}; + byte result[8] = + {0x7b, 0x38, 0x3b, 0x23, 0xa2, 0x7d, 0x26, 0xd3}; + + tripledes_ctx des3; + + for (i = 0; i < 16; ++i) + { + tripledes_set2keys (des3, key1, key2); + tripledes_ecb_encrypt (des3, input, key1); + tripledes_ecb_decrypt (des3, input, key2); + tripledes_set3keys (des3, key1, input, key2); + tripledes_ecb_encrypt (des3, input, input); + } + if (memcmp (input, result, 8)) + return "Triple-DES test failed."; + } + + /* + * More Triple-DES test. These are testvectors as used by SSLeay, + * thanks to Jeroen C. van Gelderen. + */ + { + static const struct { byte key[24]; byte plain[8]; byte cipher[8]; } + testdata[] = { + { { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, + { 0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00 }, + { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } + }, + + { { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, + { 0x9D,0x64,0x55,0x5A,0x9A,0x10,0xB8,0x52, }, + { 0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00 } + }, + { { 0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E, + 0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E, + 0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E }, + { 0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A }, + { 0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A } + }, + { { 0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6, + 0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6, + 0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6 }, + { 0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2 }, + { 0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95 } + }, + { { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF, + 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF, + 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF }, + { 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 }, + { 0x3D,0x12,0x4F,0xE2,0x19,0x8B,0xA3,0x18 } + }, + { { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF, + 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, + 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF }, + { 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 }, + { 0xFB,0xAB,0xA1,0xFF,0x9D,0x05,0xE9,0xB1 } + }, + { { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF, + 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, + 0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10 }, + { 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 }, + { 0x18,0xd7,0x48,0xe5,0x63,0x62,0x05,0x72 } + }, + { { 0x03,0x52,0x02,0x07,0x67,0x20,0x82,0x17, + 0x86,0x02,0x87,0x66,0x59,0x08,0x21,0x98, + 0x64,0x05,0x6A,0xBD,0xFE,0xA9,0x34,0x57 }, + { 0x73,0x71,0x75,0x69,0x67,0x67,0x6C,0x65 }, + { 0xc0,0x7d,0x2a,0x0f,0xa5,0x66,0xfa,0x30 } + }, + { { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x80,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xe6,0xe6,0xdd,0x5b,0x7e,0x72,0x29,0x74 } + }, + { { 0x10,0x46,0x10,0x34,0x89,0x98,0x80,0x20, + 0x91,0x07,0xD0,0x15,0x89,0x19,0x01,0x01, + 0x19,0x07,0x92,0x10,0x98,0x1A,0x01,0x01 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xe1,0xef,0x62,0xc3,0x32,0xfe,0x82,0x5b } + } + }; + + byte result[8]; + int i; + tripledes_ctx des3; + + for (i=0; icbc_dec = _gcry_3des_cbc_dec; + bulk_ops->cfb_dec = _gcry_3des_cfb_dec; + bulk_ops->ctr_enc = _gcry_3des_ctr_enc; + + tripledes_set3keys ( ctx, key, key+8, key+16); + + if (ctx->flags.no_weak_key) + ; /* Detection has been disabled. */ + else if (is_weak_key (key) || is_weak_key (key+8) || is_weak_key (key+16)) + { + _gcry_burn_stack (64); + return GPG_ERR_WEAK_KEY; + } + _gcry_burn_stack (64); + + return GPG_ERR_NO_ERROR; +} + + +static gcry_err_code_t +do_tripledes_set_extra_info (void *context, int what, + const void *buffer, size_t buflen) +{ + struct _tripledes_ctx *ctx = (struct _tripledes_ctx *)context; + gpg_err_code_t ec = 0; + + (void)buffer; + (void)buflen; + + switch (what) + { + case CIPHER_INFO_NO_WEAK_KEY: + ctx->flags.no_weak_key = 1; + break; + + default: + ec = GPG_ERR_INV_OP; + break; + } + return ec; +} + + +static unsigned int +do_tripledes_encrypt( void *context, byte *outbuf, const byte *inbuf ) +{ + struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context; + + tripledes_ecb_encrypt ( ctx, inbuf, outbuf ); + return /*burn_stack*/ TRIPLEDES_ECB_BURN_STACK; +} + +static unsigned int +do_tripledes_decrypt( void *context, byte *outbuf, const byte *inbuf ) +{ + struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context; + tripledes_ecb_decrypt ( ctx, inbuf, outbuf ); + return /*burn_stack*/ TRIPLEDES_ECB_BURN_STACK; +} + +static gcry_err_code_t +do_des_setkey (void *context, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops) +{ + struct _des_ctx *ctx = (struct _des_ctx *) context; + + (void)bulk_ops; + + if (keylen != 8) + return GPG_ERR_INV_KEYLEN; + + des_setkey (ctx, key); + + if (is_weak_key (key)) { + _gcry_burn_stack (64); + return GPG_ERR_WEAK_KEY; + } + _gcry_burn_stack (64); + + return GPG_ERR_NO_ERROR; +} + + +static unsigned int +do_des_encrypt( void *context, byte *outbuf, const byte *inbuf ) +{ + struct _des_ctx *ctx = (struct _des_ctx *) context; + + des_ecb_encrypt ( ctx, inbuf, outbuf ); + return /*burn_stack*/ (32); +} + +static unsigned int +do_des_decrypt( void *context, byte *outbuf, const byte *inbuf ) +{ + struct _des_ctx *ctx = (struct _des_ctx *) context; + + des_ecb_decrypt ( ctx, inbuf, outbuf ); + return /*burn_stack*/ (32); +} + + + + +/* + Self-test section. + */ + + +/* Selftest for TripleDES. */ +static gpg_err_code_t +selftest_fips (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + + (void)extended; /* No extended tests available. */ + + what = "low-level"; + errtxt = selftest (); + if (errtxt) + goto failed; + + /* The low-level self-tests are quite extensive and thus we can do + without high level tests. This is also justified because we have + no custom block code implementation for 3des but always use the + standard high level block code. */ + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("cipher", GCRY_CIPHER_3DES, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + + +/* Run a full self-test for ALGO and return 0 on success. */ +static gpg_err_code_t +run_selftests (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + switch (algo) + { + case GCRY_CIPHER_3DES: + ec = selftest_fips (extended, report); + break; + default: + ec = GPG_ERR_CIPHER_ALGO; + break; + + } + return ec; +} + + + +gcry_cipher_spec_t _gcry_cipher_spec_des = + { + GCRY_CIPHER_DES, {0, 0}, + "DES", NULL, NULL, 8, 64, sizeof (struct _des_ctx), + do_des_setkey, do_des_encrypt, do_des_decrypt + }; + +static gcry_cipher_oid_spec_t oids_tripledes[] = + { + { "1.2.840.113549.3.7", GCRY_CIPHER_MODE_CBC }, + /* Teletrust specific OID for 3DES. */ + { "1.3.36.3.1.3.2.1", GCRY_CIPHER_MODE_CBC }, + /* pbeWithSHAAnd3_KeyTripleDES_CBC */ + { "1.2.840.113549.1.12.1.3", GCRY_CIPHER_MODE_CBC }, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_tripledes = + { + GCRY_CIPHER_3DES, {0, 1}, + "3DES", NULL, oids_tripledes, 8, 192, sizeof (struct _tripledes_ctx), + do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt, + NULL, NULL, + run_selftests, + do_tripledes_set_extra_info + }; diff --git a/comm/third_party/libgcrypt/cipher/dsa-common.c b/comm/third_party/libgcrypt/cipher/dsa-common.c new file mode 100644 index 0000000000..fe49248dd6 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/dsa-common.c @@ -0,0 +1,418 @@ +/* dsa-common.c - Common code for DSA + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +/* + * Modify K, so that computation time difference can be small, + * by making K large enough. + * + * Originally, (EC)DSA computation requires k where 0 < k < q. Here, + * we add q (the order), to keep k in a range: q < k < 2*q (or, + * addming more q, to keep k in a range: 2*q < k < 3*q), so that + * timing difference of the EC multiply (or exponentiation) operation + * can be small. The result of (EC)DSA computation is same. + */ +void +_gcry_dsa_modify_k (gcry_mpi_t k, gcry_mpi_t q, int qbits) +{ + gcry_mpi_t k1 = mpi_new (qbits+2); + + mpi_resize (k, (qbits+2+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB); + k->nlimbs = k->alloced; + mpi_add (k, k, q); + mpi_add (k1, k, q); + mpi_set_cond (k, k1, !mpi_test_bit (k, qbits)); + + mpi_free (k1); +} + +/* + * Generate a random secret exponent K less than Q. + * Note that ECDSA uses this code also to generate D. + */ +gcry_mpi_t +_gcry_dsa_gen_k (gcry_mpi_t q, int security_level) +{ + gcry_mpi_t k = mpi_alloc_secure (mpi_get_nlimbs (q)); + unsigned int nbits = mpi_get_nbits (q); + unsigned int nbytes = (nbits+7)/8; + char *rndbuf = NULL; + + /* To learn why we don't use mpi_mod to get the requested bit size, + read the paper: "The Insecurity of the Digital Signature + Algorithm with Partially Known Nonces" by Nguyen and Shparlinski. + Journal of Cryptology, New York. Vol 15, nr 3 (2003) */ + + if (DBG_CIPHER) + log_debug ("choosing a random k of %u bits at seclevel %d\n", + nbits, security_level); + for (;;) + { + if ( !rndbuf || nbits < 32 ) + { + xfree (rndbuf); + rndbuf = _gcry_random_bytes_secure (nbytes, security_level); + } + else + { /* Change only some of the higher bits. We could improve + this by directly requesting more memory at the first call + to get_random_bytes() and use these extra bytes here. + However the required management code is more complex and + thus we better use this simple method. */ + char *pp = _gcry_random_bytes_secure (4, security_level); + memcpy (rndbuf, pp, 4); + xfree (pp); + } + _gcry_mpi_set_buffer (k, rndbuf, nbytes, 0); + + /* Make sure we have the requested number of bits. This code + looks a bit funny but it is easy to understand if you + consider that mpi_set_highbit clears all higher bits. We + don't have a clear_highbit, thus we first set the high bit + and then clear it again. */ + if (mpi_test_bit (k, nbits-1)) + mpi_set_highbit (k, nbits-1); + else + { + mpi_set_highbit (k, nbits-1); + mpi_clear_bit (k, nbits-1); + } + + if (!(mpi_cmp (k, q) < 0)) /* check: k < q */ + { + if (DBG_CIPHER) + log_debug ("\tk too large - again\n"); + continue; /* no */ + } + if (!(mpi_cmp_ui (k, 0) > 0)) /* check: k > 0 */ + { + if (DBG_CIPHER) + log_debug ("\tk is zero - again\n"); + continue; /* no */ + } + break; /* okay */ + } + xfree (rndbuf); + + return k; +} + + +/* Turn VALUE into an octet string and store it in an allocated buffer + at R_FRAME. If the resulting octet string is shorter than NBYTES + the result will be left padded with zeroes. If VALUE does not fit + into NBYTES an error code is returned. */ +static gpg_err_code_t +int2octets (unsigned char **r_frame, gcry_mpi_t value, size_t nbytes) +{ + gpg_err_code_t rc; + size_t nframe, noff, n; + unsigned char *frame; + + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nframe, value); + if (rc) + return rc; + if (nframe > nbytes) + return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */ + + noff = (nframe < nbytes)? nbytes - nframe : 0; + n = nframe + noff; + frame = mpi_is_secure (value)? xtrymalloc_secure (n) : xtrymalloc (n); + if (!frame) + return gpg_err_code_from_syserror (); + if (noff) + memset (frame, 0, noff); + nframe += noff; + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, frame+noff, nframe-noff, NULL, value); + if (rc) + { + xfree (frame); + return rc; + } + + *r_frame = frame; + return 0; +} + + +/* Connert the bit string BITS of length NBITS into an octet string + with a length of (QBITS+7)/8 bytes. On success store the result at + R_FRAME. */ +static gpg_err_code_t +bits2octets (unsigned char **r_frame, + const void *bits, unsigned int nbits, + gcry_mpi_t q, unsigned int qbits) +{ + gpg_err_code_t rc; + gcry_mpi_t z1; + + /* z1 = bits2int (b) */ + rc = _gcry_mpi_scan (&z1, GCRYMPI_FMT_USG, bits, (nbits+7)/8, NULL); + if (rc) + return rc; + if (nbits > qbits) + mpi_rshift (z1, z1, nbits - qbits); + + /* z2 - z1 mod q */ + if (mpi_cmp (z1, q) >= 0) + mpi_sub (z1, z1, q); + + /* Convert to an octet string. */ + rc = int2octets (r_frame, z1, (qbits+7)/8); + + mpi_free (z1); + return rc; +} + + +/* + * Generate a deterministic secret exponent K less than DSA_Q. H1 is + * the to be signed digest with a length of HLEN bytes. HALGO is the + * algorithm used to create the hash. On success the value for K is + * stored at R_K. + */ +gpg_err_code_t +_gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, + gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, + const unsigned char *h1, unsigned int hlen, + int halgo, unsigned int extraloops) +{ + gpg_err_code_t rc; + unsigned char *V = NULL; + unsigned char *K = NULL; + unsigned char *x_buf = NULL; + unsigned char *h1_buf = NULL; + gcry_md_hd_t hd = NULL; + unsigned char *t = NULL; + gcry_mpi_t k = NULL; + unsigned int tbits, qbits; + int i; + + qbits = mpi_get_nbits (dsa_q); + + if (!qbits || !h1 || !hlen) + return GPG_ERR_EINVAL; + + if (_gcry_md_get_algo_dlen (halgo) != hlen) + return GPG_ERR_DIGEST_ALGO; + + /* Step b: V = 0x01 0x01 0x01 ... 0x01 */ + V = xtrymalloc (hlen); + if (!V) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + for (i=0; i < hlen; i++) + V[i] = 1; + + /* Step c: K = 0x00 0x00 0x00 ... 0x00 */ + K = xtrycalloc (1, hlen); + if (!K) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + + rc = int2octets (&x_buf, dsa_x, (qbits+7)/8); + if (rc) + goto leave; + + rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits); + if (rc) + goto leave; + + /* Create a handle to compute the HMACs. */ + rc = _gcry_md_open (&hd, halgo, (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)); + if (rc) + goto leave; + + /* Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "", 1); + _gcry_md_write (hd, x_buf, (qbits+7)/8); + _gcry_md_write (hd, h1_buf, (qbits+7)/8); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* Step e: V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + /* Step f: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "\x01", 1); + _gcry_md_write (hd, x_buf, (qbits+7)/8); + _gcry_md_write (hd, h1_buf, (qbits+7)/8); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* Step g: V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + /* Step h. */ + t = xtrymalloc_secure ((qbits+7)/8+hlen); + if (!t) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + + again: + for (tbits = 0; tbits < qbits;) + { + /* V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + /* T = T || V */ + memcpy (t+(tbits+7)/8, V, hlen); + tbits += 8*hlen; + } + + /* k = bits2int (T) */ + mpi_free (k); + k = NULL; + rc = _gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL); + if (rc) + goto leave; + if (tbits > qbits) + mpi_rshift (k, k, tbits - qbits); + + /* Check: k < q and k > 1 */ + if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0)) + { + /* K = HMAC_K(V || 0x00) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "", 1); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + goto again; + } + + /* The caller may have requested that we introduce some extra loops. + This is for example useful if the caller wants another value for + K because the last returned one yielded an R of 0. Because this + is very unlikely we implement it in a straightforward way. */ + if (extraloops) + { + extraloops--; + + /* K = HMAC_K(V || 0x00) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "", 1); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + goto again; + } + + /* log_mpidump (" k", k); */ + + leave: + xfree (t); + _gcry_md_close (hd); + xfree (h1_buf); + xfree (x_buf); + xfree (K); + xfree (V); + + if (rc) + mpi_free (k); + else + *r_k = k; + return rc; +} + +/* + * Truncate opaque hash value to qbits for DSA. + * Non-opaque input is not truncated, in hope that user + * knows what is passed. It is not possible to correctly + * trucate non-opaque inputs. + */ +gpg_err_code_t +_gcry_dsa_normalize_hash (gcry_mpi_t input, + gcry_mpi_t *out, + unsigned int qbits) +{ + gpg_err_code_t rc = 0; + const void *abuf; + unsigned int abits; + gcry_mpi_t hash; + + if (mpi_is_opaque (input)) + { + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); + if (rc) + return rc; + if (abits > qbits) + mpi_rshift (hash, hash, abits - qbits); + } + else + hash = input; + + *out = hash; + + return rc; +} diff --git a/comm/third_party/libgcrypt/cipher/dsa.c b/comm/third_party/libgcrypt/cipher/dsa.c new file mode 100644 index 0000000000..d793b9aaf2 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/dsa.c @@ -0,0 +1,1394 @@ +/* dsa.c - DSA signature algorithm + * Copyright (C) 1998, 2000, 2001, 2002, 2003, + * 2006, 2008 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +typedef struct +{ + gcry_mpi_t p; /* prime */ + gcry_mpi_t q; /* group order */ + gcry_mpi_t g; /* group generator */ + gcry_mpi_t y; /* g^x mod p */ +} DSA_public_key; + + +typedef struct +{ + gcry_mpi_t p; /* prime */ + gcry_mpi_t q; /* group order */ + gcry_mpi_t g; /* group generator */ + gcry_mpi_t y; /* g^x mod p */ + gcry_mpi_t x; /* secret exponent */ +} DSA_secret_key; + + +/* A structure used to hold domain parameters. */ +typedef struct +{ + gcry_mpi_t p; /* prime */ + gcry_mpi_t q; /* group order */ + gcry_mpi_t g; /* group generator */ +} dsa_domain_t; + + +static const char *dsa_names[] = + { + "dsa", + "openpgp-dsa", + NULL, + }; + + +/* A sample 1024 bit DSA key used for the selftests. Not anymore + * used, kept only for reference. */ +#if 0 +static const char sample_secret_key_1024[] = +"(private-key" +" (dsa" +" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" +" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" +" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" +" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" +" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" +" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" +" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" +" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" +" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" +" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" +" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" +" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" +" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)" +" (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))"; +/* A sample 1024 bit DSA key used for the selftests (public only). */ +static const char sample_public_key_1024[] = +"(public-key" +" (dsa" +" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" +" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" +" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" +" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" +" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" +" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" +" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" +" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" +" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" +" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" +" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" +" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" +" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)))"; +#endif /*0*/ + +/* 2048 DSA key from RFC 6979 A.2.2 */ +static const char sample_public_key_2048[] = +"(public-key" +" (dsa" +" (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)" +" (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)" +" (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)" +" (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)))"; + +static const char sample_secret_key_2048[] = +"(private-key" +" (dsa" +" (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)" +" (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)" +" (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)" +" (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)" +" (x #69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC#)))"; + + + +static int test_keys (DSA_secret_key *sk, unsigned int qbits); +static int check_secret_key (DSA_secret_key *sk); +static gpg_err_code_t generate (DSA_secret_key *sk, + unsigned int nbits, + unsigned int qbits, + int transient_key, + dsa_domain_t *domain, + gcry_mpi_t **ret_factors); +static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, + DSA_secret_key *skey, int flags, int hashalgo); +static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, + DSA_public_key *pkey); +static unsigned int dsa_get_nbits (gcry_sexp_t parms); + + +static void (*progress_cb) (void *,const char *, int, int, int ); +static void *progress_cb_data; + + +void +_gcry_register_pk_dsa_progress (void (*cb) (void *, const char *, + int, int, int), + void *cb_data) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + + +static void +progress (int c) +{ + if (progress_cb) + progress_cb (progress_cb_data, "pk_dsa", c, 0, 0); +} + + +/* Check that a freshly generated key actually works. Returns 0 on success. */ +static int +test_keys (DSA_secret_key *sk, unsigned int qbits) +{ + int result = -1; /* Default to failure. */ + DSA_public_key pk; + gcry_mpi_t data = mpi_new (qbits); + gcry_mpi_t sig_a = mpi_new (qbits); + gcry_mpi_t sig_b = mpi_new (qbits); + + /* Put the relevant parameters into a public key structure. */ + pk.p = sk->p; + pk.q = sk->q; + pk.g = sk->g; + pk.y = sk->y; + + /* Create a random plaintext. */ + _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); + + /* Sign DATA using the secret key. */ + sign (sig_a, sig_b, data, sk, 0, 0); + + /* Verify the signature using the public key. */ + if ( verify (sig_a, sig_b, data, &pk) ) + goto leave; /* Signature does not match. */ + + /* Modify the data and check that the signing fails. */ + mpi_add_ui (data, data, 1); + if ( !verify (sig_a, sig_b, data, &pk) ) + goto leave; /* Signature matches but should not. */ + + result = 0; /* The test succeeded. */ + + leave: + _gcry_mpi_release (sig_b); + _gcry_mpi_release (sig_a); + _gcry_mpi_release (data); + return result; +} + + + +/* + Generate a DSA key pair with a key of size NBITS. If transient_key + is true the key is generated using the standard RNG and not the + very secure one. + + Returns: 2 structures filled with all needed values + and an array with the n-1 factors of (p-1) + */ +static gpg_err_code_t +generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, + int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors ) +{ + gpg_err_code_t rc; + gcry_mpi_t p; /* the prime */ + gcry_mpi_t q; /* the 160 bit prime factor */ + gcry_mpi_t g; /* the generator */ + gcry_mpi_t y; /* g^x mod p */ + gcry_mpi_t x; /* the secret exponent */ + gcry_mpi_t h, e; /* helper */ + unsigned char *rndbuf; + gcry_random_level_t random_level; + + if (qbits) + ; /* Caller supplied qbits. Use this value. */ + else if ( nbits >= 512 && nbits <= 1024 ) + qbits = 160; + else if ( nbits == 2048 ) + qbits = 224; + else if ( nbits == 3072 ) + qbits = 256; + else if ( nbits == 7680 ) + qbits = 384; + else if ( nbits == 15360 ) + qbits = 512; + else + return GPG_ERR_INV_VALUE; + + if (qbits < 160 || qbits > 512 || (qbits%8) ) + return GPG_ERR_INV_VALUE; + if (nbits < 2*qbits || nbits > 15360) + return GPG_ERR_INV_VALUE; + + if (fips_mode ()) + { + if (nbits < 1024) + return GPG_ERR_INV_VALUE; + if (transient_key) + return GPG_ERR_INV_VALUE; + } + + if (domain->p && domain->q && domain->g) + { + /* Domain parameters are given; use them. */ + p = mpi_copy (domain->p); + q = mpi_copy (domain->q); + g = mpi_copy (domain->g); + gcry_assert (mpi_get_nbits (p) == nbits); + gcry_assert (mpi_get_nbits (q) == qbits); + h = mpi_alloc (0); + e = NULL; + } + else + { + /* Generate new domain parameters. */ + rc = _gcry_generate_elg_prime (1, nbits, qbits, NULL, &p, ret_factors); + if (rc) + return rc; + + /* Get q out of factors. */ + q = mpi_copy ((*ret_factors)[0]); + gcry_assert (mpi_get_nbits (q) == qbits); + + /* Find a generator g (h and e are helpers). + e = (p-1)/q */ + e = mpi_alloc (mpi_get_nlimbs (p)); + mpi_sub_ui (e, p, 1); + mpi_fdiv_q (e, e, q); + g = mpi_alloc (mpi_get_nlimbs (p)); + h = mpi_alloc_set_ui (1); /* (We start with 2.) */ + do + { + mpi_add_ui (h, h, 1); + /* g = h^e mod p */ + mpi_powm (g, h, e, p); + } + while (!mpi_cmp_ui (g, 1)); /* Continue until g != 1. */ + } + + /* Select a random number X with the property: + * 0 < x < q-1 + * + * FIXME: Why do we use the requirement x < q-1 ? It should be + * sufficient to test for x < q. FIPS-186-3 check x < q-1 but it + * does not check for 0 < x because it makes sure that Q is unsigned + * and finally adds one to the result so that 0 will never be + * returned. We should replace the code below with _gcry_dsa_gen_k. + * + * This must be a very good random number because this is the secret + * part. The random quality depends on the transient_key flag. */ + random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; + if (DBG_CIPHER) + log_debug("choosing a random x%s\n", transient_key? " (transient-key)":""); + gcry_assert( qbits >= 160 ); + x = mpi_alloc_secure( mpi_get_nlimbs(q) ); + mpi_sub_ui( h, q, 1 ); /* put q-1 into h */ + rndbuf = NULL; + do + { + if( DBG_CIPHER ) + progress('.'); + if( !rndbuf ) + rndbuf = _gcry_random_bytes_secure ((qbits+7)/8, random_level); + else + { /* Change only some of the higher bits (= 2 bytes)*/ + char *r = _gcry_random_bytes_secure (2, random_level); + memcpy(rndbuf, r, 2 ); + xfree(r); + } + + _gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 ); + mpi_clear_highbit( x, qbits+1 ); + } + while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) ); + xfree(rndbuf); + mpi_free( e ); + mpi_free( h ); + + /* y = g^x mod p */ + y = mpi_alloc( mpi_get_nlimbs(p) ); + mpi_powm (y, g, x, p); + + if( DBG_CIPHER ) + { + progress('\n'); + log_mpidump("dsa p", p ); + log_mpidump("dsa q", q ); + log_mpidump("dsa g", g ); + log_mpidump("dsa y", y ); + log_mpidump("dsa x", x ); + } + + /* Copy the stuff to the key structures. */ + sk->p = p; + sk->q = q; + sk->g = g; + sk->y = y; + sk->x = x; + + /* Now we can test our keys (this should never fail!). */ + if ( test_keys (sk, qbits) ) + { + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->g); sk->g = NULL; + _gcry_mpi_release (sk->y); sk->y = NULL; + _gcry_mpi_release (sk->x); sk->x = NULL; + fips_signal_error ("self-test after key generation failed"); + return GPG_ERR_SELFTEST_FAILED; + } + return 0; +} + + +/* Generate a DSA key pair with a key of size NBITS using the + algorithm given in FIPS-186-3. If USE_FIPS186_2 is true, + FIPS-186-2 is used and thus the length is restricted to 1024/160. + If DERIVEPARMS is not NULL it may contain a seed value. If domain + parameters are specified in DOMAIN, DERIVEPARMS may not be given + and NBITS and QBITS must match the specified domain parameters. */ +static gpg_err_code_t +generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, + gcry_sexp_t deriveparms, int use_fips186_2, + dsa_domain_t *domain, + int *r_counter, void **r_seed, size_t *r_seedlen, + gcry_mpi_t *r_h) +{ + gpg_err_code_t ec; + struct { + gcry_sexp_t sexp; + const void *seed; + size_t seedlen; + } initial_seed = { NULL, NULL, 0 }; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; + gcry_mpi_t value_g = NULL; /* The generator. */ + gcry_mpi_t value_y = NULL; /* g^x mod p */ + gcry_mpi_t value_x = NULL; /* The secret exponent. */ + gcry_mpi_t value_h = NULL; /* Helper. */ + gcry_mpi_t value_e = NULL; /* Helper. */ + gcry_mpi_t value_c = NULL; /* helper for x */ + gcry_mpi_t value_qm2 = NULL; /* q - 2 */ + + /* Preset return values. */ + *r_counter = 0; + *r_seed = NULL; + *r_seedlen = 0; + *r_h = NULL; + + /* Derive QBITS from NBITS if requested */ + if (!qbits) + { + if (nbits == 1024) + qbits = 160; + else if (nbits == 2048) + qbits = 224; + else if (nbits == 3072) + qbits = 256; + } + + /* Check that QBITS and NBITS match the standard. Note that FIPS + 186-3 uses N for QBITS and L for NBITS. */ + if (nbits == 1024 && qbits == 160 && use_fips186_2) + ; /* Allowed in FIPS 186-2 mode. */ + else if (nbits == 2048 && qbits == 224) + ; + else if (nbits == 2048 && qbits == 256) + ; + else if (nbits == 3072 && qbits == 256) + ; + else + return GPG_ERR_INV_VALUE; + + if (domain->p && domain->q && domain->g) + { + /* Domain parameters are given; use them. */ + prime_p = mpi_copy (domain->p); + prime_q = mpi_copy (domain->q); + value_g = mpi_copy (domain->g); + gcry_assert (mpi_get_nbits (prime_p) == nbits); + gcry_assert (mpi_get_nbits (prime_q) == qbits); + gcry_assert (!deriveparms); + ec = 0; + } + else + { + /* Generate new domain parameters. */ + + /* Get an initial seed value. */ + if (deriveparms) + { + initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0); + if (initial_seed.sexp) + initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1, + &initial_seed.seedlen); + } + + if (use_fips186_2) + ec = _gcry_generate_fips186_2_prime (nbits, qbits, + initial_seed.seed, + initial_seed.seedlen, + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen); + else + ec = _gcry_generate_fips186_3_prime (nbits, qbits, + initial_seed.seed, + initial_seed.seedlen, + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen, NULL); + sexp_release (initial_seed.sexp); + if (ec) + goto leave; + + /* Find a generator g (h and e are helpers). + * e = (p-1)/q + */ + value_e = mpi_alloc_like (prime_p); + mpi_sub_ui (value_e, prime_p, 1); + mpi_fdiv_q (value_e, value_e, prime_q ); + value_g = mpi_alloc_like (prime_p); + value_h = mpi_alloc_set_ui (1); + do + { + mpi_add_ui (value_h, value_h, 1); + /* g = h^e mod p */ + mpi_powm (value_g, value_h, value_e, prime_p); + } + while (!mpi_cmp_ui (value_g, 1)); /* Continue until g != 1. */ + } + + value_c = mpi_snew (qbits); + value_x = mpi_snew (qbits); + value_qm2 = mpi_snew (qbits); + mpi_sub_ui (value_qm2, prime_q, 2); + + /* FIPS 186-4 B.1.2 steps 4-6 */ + do + { + if( DBG_CIPHER ) + progress('.'); + _gcry_mpi_randomize (value_c, qbits, GCRY_VERY_STRONG_RANDOM); + mpi_clear_highbit (value_c, qbits+1); + } + while (!(mpi_cmp_ui (value_c, 0) > 0 && mpi_cmp (value_c, value_qm2) < 0)); + /* while (mpi_cmp (value_c, value_qm2) > 0); */ + + /* x = c + 1 */ + mpi_add_ui(value_x, value_c, 1); + + /* y = g^x mod p */ + value_y = mpi_alloc_like (prime_p); + mpi_powm (value_y, value_g, value_x, prime_p); + + if (DBG_CIPHER) + { + progress('\n'); + log_mpidump("dsa p", prime_p ); + log_mpidump("dsa q", prime_q ); + log_mpidump("dsa g", value_g ); + log_mpidump("dsa y", value_y ); + log_mpidump("dsa x", value_x ); + log_mpidump("dsa h", value_h ); + } + + /* Copy the stuff to the key structures. */ + sk->p = prime_p; prime_p = NULL; + sk->q = prime_q; prime_q = NULL; + sk->g = value_g; value_g = NULL; + sk->y = value_y; value_y = NULL; + sk->x = value_x; value_x = NULL; + *r_h = value_h; value_h = NULL; + + leave: + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + _gcry_mpi_release (value_g); + _gcry_mpi_release (value_y); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_h); + _gcry_mpi_release (value_e); + _gcry_mpi_release (value_c); + _gcry_mpi_release (value_qm2); + + /* As a last step test this keys (this should never fail of course). */ + if (!ec && test_keys (sk, qbits) ) + { + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->g); sk->g = NULL; + _gcry_mpi_release (sk->y); sk->y = NULL; + _gcry_mpi_release (sk->x); sk->x = NULL; + fips_signal_error ("self-test after key generation failed"); + ec = GPG_ERR_SELFTEST_FAILED; + } + + if (ec) + { + *r_counter = 0; + xfree (*r_seed); *r_seed = NULL; + *r_seedlen = 0; + _gcry_mpi_release (*r_h); *r_h = NULL; + } + + return ec; +} + + + +/* + Test whether the secret key is valid. + Returns: if this is a valid key. + */ +static int +check_secret_key( DSA_secret_key *sk ) +{ + int rc; + gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); + + mpi_powm( y, sk->g, sk->x, sk->p ); + rc = !mpi_cmp( y, sk->y ); + mpi_free( y ); + return rc; +} + + + +/* + Make a DSA signature from INPUT and put it into r and s. + + INPUT may either be a plain MPI or an opaque MPI which is then + internally converted to a plain MPI. FLAGS and HASHALGO may both + be 0 for standard operation mode. + + The return value is 0 on success or an error code. Note that for + backward compatibility the function will not return any error if + FLAGS and HASHALGO are both 0 and INPUT is a plain MPI. + */ +static gpg_err_code_t +sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, + int flags, int hashalgo) +{ + gpg_err_code_t rc; + gcry_mpi_t hash; + gcry_mpi_t k; + gcry_mpi_t kinv; + gcry_mpi_t tmp; + const void *abuf; + unsigned int abits, qbits; + int extraloops = 0; + + qbits = mpi_get_nbits (skey->q); + + /* Convert the INPUT into an MPI. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + again: + /* Create the K value. */ + if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) + { + /* Use Pornin's method for deterministic DSA. If this flag is + set, it is expected that HASH is an opaque MPI with the to be + signed hash. That hash is also used as h1 from 3.2.a. */ + if (!mpi_is_opaque (input)) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_dsa_gen_rfc6979_k (&k, skey->q, skey->x, + abuf, (abits+7)/8, hashalgo, extraloops); + if (rc) + goto leave; + } + else + { + /* Select a random k with 0 < k < q */ + k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM); + } + + /* kinv = k^(-1) mod q */ + kinv = mpi_alloc( mpi_get_nlimbs(k) ); + mpi_invm(kinv, k, skey->q ); + + _gcry_dsa_modify_k (k, skey->q, qbits); + + /* r = (a^k mod p) mod q */ + mpi_powm( r, skey->g, k, skey->p ); + mpi_fdiv_r( r, r, skey->q ); + + /* s = (kinv * ( hash + x * r)) mod q */ + tmp = mpi_alloc( mpi_get_nlimbs(skey->p) ); + mpi_mul( tmp, skey->x, r ); + mpi_add( tmp, tmp, hash ); + mpi_mulm( s , kinv, tmp, skey->q ); + + mpi_free(k); + mpi_free(kinv); + mpi_free(tmp); + + if (!mpi_cmp_ui (r, 0)) + { + /* This is a highly unlikely code path. */ + extraloops++; + goto again; + } + + rc = 0; + + leave: + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/* + Returns true if the signature composed from R and S is valid. + */ +static gpg_err_code_t +verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey ) +{ + gpg_err_code_t rc = 0; + gcry_mpi_t w, u1, u2, v; + gcry_mpi_t base[3]; + gcry_mpi_t ex[3]; + gcry_mpi_t hash; + unsigned int nbits; + + if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + nbits = mpi_get_nbits (pkey->q); + rc = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (rc) + return rc; + + w = mpi_alloc( mpi_get_nlimbs(pkey->q) ); + u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); + u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); + v = mpi_alloc( mpi_get_nlimbs(pkey->p) ); + + /* w = s^(-1) mod q */ + mpi_invm( w, s, pkey->q ); + + /* u1 = (hash * w) mod q */ + mpi_mulm( u1, hash, w, pkey->q ); + + /* u2 = r * w mod q */ + mpi_mulm( u2, r, w, pkey->q ); + + /* v = g^u1 * y^u2 mod p mod q */ + base[0] = pkey->g; ex[0] = u1; + base[1] = pkey->y; ex[1] = u2; + base[2] = NULL; ex[2] = NULL; + mpi_mulpowm( v, base, ex, pkey->p ); + mpi_fdiv_r( v, v, pkey->q ); + + if (mpi_cmp( v, r )) + { + if (DBG_CIPHER) + { + log_mpidump (" i", input); + log_mpidump (" h", hash); + log_mpidump (" v", v); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + rc = GPG_ERR_BAD_SIGNATURE; + } + + mpi_free(w); + mpi_free(u1); + mpi_free(u2); + mpi_free(v); + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/********************************************* + ************** interface ****************** + *********************************************/ + +static gcry_err_code_t +dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) +{ + gpg_err_code_t rc; + unsigned int nbits; + gcry_sexp_t domainsexp; + DSA_secret_key sk; + gcry_sexp_t l1; + unsigned int qbits = 0; + gcry_sexp_t deriveparms = NULL; + gcry_sexp_t seedinfo = NULL; + gcry_sexp_t misc_info = NULL; + int flags = 0; + dsa_domain_t domain; + gcry_mpi_t *factors = NULL; + + memset (&sk, 0, sizeof sk); + memset (&domain, 0, sizeof domain); + + rc = _gcry_pk_util_get_nbits (genparms, &nbits); + if (rc) + return rc; + + /* Parse the optional flags list. */ + l1 = sexp_find_token (genparms, "flags", 0); + if (l1) + { + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + if (rc) + return rc;\ + } + + /* Parse the optional qbits element. */ + l1 = sexp_find_token (genparms, "qbits", 0); + if (l1) + { + char buf[50]; + const char *s; + size_t n; + + s = sexp_nth_data (l1, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + sexp_release (l1); + return GPG_ERR_INV_OBJ; /* No value or value too large. */ + } + memcpy (buf, s, n); + buf[n] = 0; + qbits = (unsigned int)strtoul (buf, NULL, 0); + sexp_release (l1); + } + + /* Parse the optional transient-key flag. */ + if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) + { + l1 = sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + sexp_release (l1); + } + } + + /* Get the optional derive parameters. */ + deriveparms = sexp_find_token (genparms, "derive-parms", 0); + + /* Parse the optional "use-fips186" flags. */ + if (!(flags & PUBKEY_FLAG_USE_FIPS186)) + { + l1 = sexp_find_token (genparms, "use-fips186", 0); + if (l1) + { + flags |= PUBKEY_FLAG_USE_FIPS186; + sexp_release (l1); + } + } + if (!(flags & PUBKEY_FLAG_USE_FIPS186_2)) + { + l1 = sexp_find_token (genparms, "use-fips186-2", 0); + if (l1) + { + flags |= PUBKEY_FLAG_USE_FIPS186_2; + sexp_release (l1); + } + } + + /* Check whether domain parameters are given. */ + domainsexp = sexp_find_token (genparms, "domain", 0); + if (domainsexp) + { + /* DERIVEPARMS can't be used together with domain parameters. + NBITS abnd QBITS may not be specified because there values + are derived from the domain parameters. */ + if (deriveparms || qbits || nbits) + { + sexp_release (domainsexp); + sexp_release (deriveparms); + return GPG_ERR_INV_VALUE; + } + + /* Put all domain parameters into the domain object. */ + l1 = sexp_find_token (domainsexp, "p", 0); + domain.p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + l1 = sexp_find_token (domainsexp, "q", 0); + domain.q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + l1 = sexp_find_token (domainsexp, "g", 0); + domain.g = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + sexp_release (domainsexp); + + /* Check that all domain parameters are available. */ + if (!domain.p || !domain.q || !domain.g) + { + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); + sexp_release (deriveparms); + return GPG_ERR_MISSING_VALUE; + } + + /* Get NBITS and QBITS from the domain parameters. */ + nbits = mpi_get_nbits (domain.p); + qbits = mpi_get_nbits (domain.q); + } + + if (deriveparms + || (flags & PUBKEY_FLAG_USE_FIPS186) + || (flags & PUBKEY_FLAG_USE_FIPS186_2) + || fips_mode ()) + { + int counter; + void *seed; + size_t seedlen; + gcry_mpi_t h_value; + + rc = generate_fips186 (&sk, nbits, qbits, deriveparms, + !!(flags & PUBKEY_FLAG_USE_FIPS186_2), + &domain, + &counter, &seed, &seedlen, &h_value); + if (!rc && h_value) + { + /* Format the seed-values unless domain parameters are used + for which a H_VALUE of NULL is an indication. */ + rc = sexp_build (&seedinfo, NULL, + "(seed-values(counter %d)(seed %b)(h %m))", + counter, (int)seedlen, seed, h_value); + xfree (seed); + _gcry_mpi_release (h_value); + } + } + else + { + rc = generate (&sk, nbits, qbits, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY), + &domain, &factors); + } + + if (!rc) + { + /* Put the factors into MISC_INFO. Note that the factors are + not confidential thus we can store them in standard memory. */ + int nfactors, i, j; + char *p; + char *format = NULL; + void **arg_list = NULL; + + for (nfactors=0; factors && factors[nfactors]; nfactors++) + ; + /* Allocate space for the format string: + "(misc-key-info%S(pm1-factors%m))" + with one "%m" for each factor and construct it. */ + format = xtrymalloc (50 + 2*nfactors); + if (!format) + rc = gpg_err_code_from_syserror (); + else + { + p = stpcpy (format, "(misc-key-info"); + if (seedinfo) + p = stpcpy (p, "%S"); + if (nfactors) + { + p = stpcpy (p, "(pm1-factors"); + for (i=0; i < nfactors; i++) + p = stpcpy (p, "%m"); + p = stpcpy (p, ")"); + } + p = stpcpy (p, ")"); + + /* Allocate space for the list of factors plus one for the + seedinfo s-exp plus an extra NULL entry for safety and + fill it with the factors. */ + arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list); + if (!arg_list) + rc = gpg_err_code_from_syserror (); + else + { + i = 0; + if (seedinfo) + arg_list[i++] = &seedinfo; + for (j=0; j < nfactors; j++) + arg_list[i++] = factors + j; + arg_list[i] = NULL; + + rc = sexp_build_array (&misc_info, NULL, format, arg_list); + } + } + + xfree (arg_list); + xfree (format); + } + + if (!rc) + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (dsa(p%m)(q%m)(g%m)(y%m)))" + " (private-key" + " (dsa(p%m)(q%m)(g%m)(y%m)(x%m)))" + " %S)", + sk.p, sk.q, sk.g, sk.y, + sk.p, sk.q, sk.g, sk.y, sk.x, + misc_info); + + + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); + + sexp_release (seedinfo); + sexp_release (misc_info); + sexp_release (deriveparms); + if (factors) + { + gcry_mpi_t *mp; + for (mp = factors; *mp; mp++) + mpi_free (*mp); + xfree (factors); + } + return rc; +} + + + +static gcry_err_code_t +dsa_check_secret_key (gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; + + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; + + if (!check_secret_key (&sk)) + rc = GPG_ERR_BAD_SECKEY; + + leave: + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + if (DBG_CIPHER) + log_debug ("dsa_testkey => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, + dsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("dsa_sign data", data); + + /* Extract the key. */ + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_sign p", sk.p); + log_mpidump ("dsa_sign q", sk.q); + log_mpidump ("dsa_sign g", sk.g); + log_mpidump ("dsa_sign y", sk.y); + if (!fips_mode ()) + log_mpidump ("dsa_sign x", sk.x); + } + + sig_r = mpi_new (0); + sig_s = mpi_new (0); + rc = sign (sig_r, sig_s, data, &sk, ctx.flags, ctx.hash_algo); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_sign sig_r", sig_r); + log_mpidump ("dsa_sign sig_s", sig_s); + } + rc = sexp_build (r_sig, NULL, "(sig-val(dsa(r%M)(s%M)))", sig_r, sig_s); + + leave: + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("dsa_sign => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + DSA_public_key pk = { NULL, NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + dsa_get_nbits (s_keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("dsa_verify data", data); + + /* Extract the signature value. */ + rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); + if (rc) + goto leave; + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_verify s_r", sig_r); + log_mpidump ("dsa_verify s_s", sig_s); + } + + /* Extract the key. */ + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", + &pk.p, &pk.q, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_verify p", pk.p); + log_mpidump ("dsa_verify q", pk.q); + log_mpidump ("dsa_verify g", pk.g); + log_mpidump ("dsa_verify y", pk.y); + } + + /* Verify the signature. */ + rc = verify (sig_r, sig_s, data, &pk); + + leave: + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.q); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("dsa_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; +} + + +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (dsa + * (p ) + * (q ) + * (g ) + * (y )) + * + * More parameters may be given but we only need P here. + */ +static unsigned int +dsa_get_nbits (gcry_sexp_t parms) +{ + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + return 0; /* Parameter P not found. */ + + p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + nbits = p? mpi_get_nbits (p) : 0; + _gcry_mpi_release (p); + return nbits; +} + + + +/* + Self-test section. + */ + +static const char * +selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) +{ + /* Sample data from RFC 6979 section A.2.2, hash is of message "sample" */ + static const char sample_data[] = + "(data (flags rfc6979)" + " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))"; + static const char sample_data_bad[] = + "(data (flags rfc6979)" + " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))"; + static const char signature_r[] = + "eace8bdbbe353c432a795d9ec556c6d021f7a03f42c36e9bc87e4ac7932cc809"; + static const char signature_s[] = + "7081e175455f9247b812b74583e9e94f9ea79bd640dc962533b0680793a38d53"; + + const char *errtxt = NULL; + gcry_error_t err; + gcry_sexp_t data = NULL; + gcry_sexp_t data_bad = NULL; + gcry_sexp_t sig = NULL; + gcry_sexp_t l1 = NULL; + gcry_sexp_t l2 = NULL; + gcry_mpi_t r = NULL; + gcry_mpi_t s = NULL; + gcry_mpi_t calculated_r = NULL; + gcry_mpi_t calculated_s = NULL; + int cmp; + + err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); + if (!err) + err = sexp_sscan (&data_bad, NULL, + sample_data_bad, strlen (sample_data_bad)); + if (!err) + err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL); + if (!err) + err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL); + + if (err) + { + errtxt = "converting data failed"; + goto leave; + } + + err = _gcry_pk_sign (&sig, data, skey); + if (err) + { + errtxt = "signing failed"; + goto leave; + } + + /* check against known signature */ + errtxt = "signature validity failed"; + l1 = _gcry_sexp_find_token (sig, "sig-val", 0); + if (!l1) + goto leave; + l2 = _gcry_sexp_find_token (l1, "dsa", 0); + if (!l2) + goto leave; + + sexp_release (l1); + l1 = l2; + + l2 = _gcry_sexp_find_token (l1, "r", 0); + if (!l2) + goto leave; + calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + if (!calculated_r) + goto leave; + + sexp_release (l2); + l2 = _gcry_sexp_find_token (l1, "s", 0); + if (!l2) + goto leave; + calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + if (!calculated_s) + goto leave; + + errtxt = "known sig check failed"; + + cmp = _gcry_mpi_cmp (r, calculated_r); + if (cmp) + goto leave; + cmp = _gcry_mpi_cmp (s, calculated_s); + if (cmp) + goto leave; + + errtxt = NULL; + + + err = _gcry_pk_verify (sig, data, pkey); + if (err) + { + errtxt = "verify failed"; + goto leave; + } + err = _gcry_pk_verify (sig, data_bad, pkey); + if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) + { + errtxt = "bad signature not detected"; + goto leave; + } + + + leave: + _gcry_mpi_release (calculated_s); + _gcry_mpi_release (calculated_r); + _gcry_mpi_release (s); + _gcry_mpi_release (r); + sexp_release (l2); + sexp_release (l1); + sexp_release (sig); + sexp_release (data_bad); + sexp_release (data); + return errtxt; +} + + +static gpg_err_code_t +selftests_dsa_2048 (selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + gcry_error_t err; + gcry_sexp_t skey = NULL; + gcry_sexp_t pkey = NULL; + + /* Convert the S-expressions into the internal representation. */ + what = "convert"; + err = sexp_sscan (&skey, NULL, sample_secret_key_2048, strlen (sample_secret_key_2048)); + if (!err) + err = sexp_sscan (&pkey, NULL, + sample_public_key_2048, strlen (sample_public_key_2048)); + if (err) + { + errtxt = _gcry_strerror (err); + goto failed; + } + + what = "key consistency"; + err = _gcry_pk_testkey (skey); + if (err) + { + errtxt = _gcry_strerror (err); + goto failed; + } + + what = "sign"; + errtxt = selftest_sign (pkey, skey); + if (errtxt) + goto failed; + + sexp_release (pkey); + sexp_release (skey); + return 0; /* Succeeded. */ + + failed: + sexp_release (pkey); + sexp_release (skey); + if (report) + report ("pubkey", GCRY_PK_DSA, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Run a full self-test for ALGO and return 0 on success. */ +static gpg_err_code_t +run_selftests (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + (void)extended; + + switch (algo) + { + case GCRY_PK_DSA: + ec = selftests_dsa_2048 (report); + break; + default: + ec = GPG_ERR_PUBKEY_ALGO; + break; + + } + return ec; +} + + + +gcry_pk_spec_t _gcry_pubkey_spec_dsa = + { + GCRY_PK_DSA, { 0, 1 }, + GCRY_PK_USAGE_SIGN, + "DSA", dsa_names, + "pqgy", "pqgyx", "", "rs", "pqgy", + dsa_generate, + dsa_check_secret_key, + NULL, + NULL, + dsa_sign, + dsa_verify, + dsa_get_nbits, + run_selftests + }; diff --git a/comm/third_party/libgcrypt/cipher/ecc-common.h b/comm/third_party/libgcrypt/cipher/ecc-common.h new file mode 100644 index 0000000000..25c3111263 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-common.h @@ -0,0 +1,140 @@ +/* ecc-common.h - Declarations of common ECC code + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_ECC_COMMON_H +#define GCRY_ECC_COMMON_H + + +/* Definition of a curve. */ +typedef struct +{ + enum gcry_mpi_ec_models model;/* The model descrinbing this curve. */ + enum ecc_dialects dialect; /* The dialect used with the curve. */ + gcry_mpi_t p; /* Prime specifying the field GF(p). */ + gcry_mpi_t a; /* First coefficient of the Weierstrass equation. */ + gcry_mpi_t b; /* Second coefficient of the Weierstrass equation. + or d as used by Twisted Edwards curves. */ + mpi_point_struct G; /* Base point (generator). */ + gcry_mpi_t n; /* Order of G. */ + unsigned int h; /* Cofactor. */ + const char *name; /* Name of the curve or NULL. */ +} elliptic_curve_t; + + + +/* Set the value from S into D. */ +static inline void +point_set (mpi_point_t d, mpi_point_t s) +{ + mpi_set (d->x, s->x); + mpi_set (d->y, s->y); + mpi_set (d->z, s->z); +} + +#define point_init(a) _gcry_mpi_point_init ((a)) +#define point_free(a) _gcry_mpi_point_free_parts ((a)) + + +/*-- ecc-curves.c --*/ +gpg_err_code_t _gcry_ecc_fill_in_curve (unsigned int nbits, + const char *name, + elliptic_curve_t *curve, + unsigned int *r_nbits); +gpg_err_code_t _gcry_ecc_update_curve_param (const char *name, + enum gcry_mpi_ec_models *model, + enum ecc_dialects *dialect, + gcry_mpi_t *p, gcry_mpi_t *a, + gcry_mpi_t *b, gcry_mpi_t *g, + gcry_mpi_t *n); + +const char *_gcry_ecc_get_curve (gcry_sexp_t keyparms, + int iterator, + unsigned int *r_nbits); +gcry_sexp_t _gcry_ecc_get_param_sexp (const char *name); + +/*-- ecc-misc.c --*/ +void _gcry_ecc_curve_free (elliptic_curve_t *E); +elliptic_curve_t _gcry_ecc_curve_copy (elliptic_curve_t E); +const char *_gcry_ecc_model2str (enum gcry_mpi_ec_models model); +const char *_gcry_ecc_dialect2str (enum ecc_dialects dialect); +gcry_mpi_t _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p); + +mpi_point_t _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec); +gpg_err_code_t _gcry_ecc_mont_encodepoint (gcry_mpi_t x, unsigned int nbits, + int with_prefix, + unsigned char **r_buffer, + unsigned int *r_buflen); + + +/*-- ecc.c --*/ + +/*-- ecc-ecdsa.c --*/ +gpg_err_code_t _gcry_ecc_ecdsa_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s, + int flags, int hashalgo); +gpg_err_code_t _gcry_ecc_ecdsa_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s); + +/*-- ecc-eddsa.c --*/ +gpg_err_code_t _gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, + mpi_ec_t ec); +gpg_err_code_t _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ctx, + gcry_mpi_t x, gcry_mpi_t y, + int with_prefix, + unsigned char **r_buffer, + unsigned int *r_buflen); +gpg_err_code_t _gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, + unsigned int nbits); + + +gpg_err_code_t _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, + mpi_ec_t ec); + +gpg_err_code_t _gcry_ecc_eddsa_genkey (mpi_ec_t ec, int flags); +gpg_err_code_t _gcry_ecc_eddsa_sign (gcry_mpi_t input, + mpi_ec_t ec, + gcry_mpi_t r_r, gcry_mpi_t s, + struct pk_encoding_ctx *ctx); +gpg_err_code_t _gcry_ecc_eddsa_verify (gcry_mpi_t input, + mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s, + struct pk_encoding_ctx *ctx); +void reverse_buffer (unsigned char *buffer, unsigned int length); + + +/*-- ecc-gost.c --*/ +gpg_err_code_t _gcry_ecc_gost_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s); +gpg_err_code_t _gcry_ecc_gost_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s); + + +/*-- ecc-sm2.c --*/ +gpg_err_code_t _gcry_ecc_sm2_encrypt (gcry_sexp_t *r_ciph, + gcry_mpi_t input, mpi_ec_t ec); +gpg_err_code_t _gcry_ecc_sm2_decrypt (gcry_sexp_t *r_plain, + gcry_sexp_t data_list, mpi_ec_t ec); +gpg_err_code_t _gcry_ecc_sm2_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s, + int flags, int hashalgo); +gpg_err_code_t _gcry_ecc_sm2_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s); + + +#endif /*GCRY_ECC_COMMON_H*/ diff --git a/comm/third_party/libgcrypt/cipher/ecc-curves.c b/comm/third_party/libgcrypt/cipher/ecc-curves.c new file mode 100644 index 0000000000..900b668aac --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-curves.c @@ -0,0 +1,1603 @@ +/* ecc-curves.c - Elliptic Curve parameter mangement + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "mpi-internal.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" + + +static gpg_err_code_t +point_from_keyparam (gcry_mpi_point_t *r_a, + gcry_sexp_t keyparam, const char *name, mpi_ec_t ec); + +/* This tables defines aliases for curve names. */ +static const struct +{ + const char *name; /* Our name. */ + const char *other; /* Other name. */ +} curve_aliases[] = + { + { "Ed25519", "1.3.6.1.4.1.11591.15.1" }, /* OpenPGP */ + { "Ed25519", "1.3.101.112" }, /* rfc8410 */ + + { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" }, /* OpenPGP */ + { "Curve25519", "1.3.101.110" }, /* rfc8410 */ + { "Curve25519", "X25519" }, /* rfc8410 */ + + { "Ed448", "1.3.101.113" }, /* rfc8410 */ + { "X448", "1.3.101.111" }, /* rfc8410 */ + + { "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID */ + { "NIST P-192", "prime192v1" }, /* X9.62 name. */ + { "NIST P-192", "secp192r1" }, /* SECP name. */ + { "NIST P-192", "nistp192" }, /* rfc5656. */ + + { "NIST P-224", "secp224r1" }, + { "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */ + { "NIST P-224", "nistp224" }, /* rfc5656. */ + + { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */ + { "NIST P-256", "prime256v1" }, + { "NIST P-256", "secp256r1" }, + { "NIST P-256", "nistp256" }, /* rfc5656. */ + + { "NIST P-384", "secp384r1" }, + { "NIST P-384", "1.3.132.0.34" }, + { "NIST P-384", "nistp384" }, /* rfc5656. */ + + { "NIST P-521", "secp521r1" }, + { "NIST P-521", "1.3.132.0.35" }, + { "NIST P-521", "nistp521" }, /* rfc5656. */ + + { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" }, + { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" }, + { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" }, + { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" }, + { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" }, + { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11"}, + { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13"}, + + { "GOST2001-test", "1.2.643.2.2.35.0" }, + { "GOST2001-CryptoPro-A", "1.2.643.2.2.35.1" }, + { "GOST2001-CryptoPro-B", "1.2.643.2.2.35.2" }, + { "GOST2001-CryptoPro-C", "1.2.643.2.2.35.3" }, + { "GOST2001-CryptoPro-A", "GOST2001-CryptoPro-XchA" }, + { "GOST2001-CryptoPro-C", "GOST2001-CryptoPro-XchB" }, + { "GOST2001-CryptoPro-A", "1.2.643.2.2.36.0" }, + { "GOST2001-CryptoPro-C", "1.2.643.2.2.36.1" }, + + { "GOST2012-256-tc26-A", "1.2.643.7.1.2.1.1.1" }, + { "GOST2001-CryptoPro-A", "1.2.643.7.1.2.1.1.2" }, + { "GOST2001-CryptoPro-A", "GOST2012-256-tc26-B" }, + { "GOST2001-CryptoPro-B", "1.2.643.7.1.2.1.1.3" }, + { "GOST2001-CryptoPro-B", "GOST2012-256-tc26-C" }, + { "GOST2001-CryptoPro-C", "1.2.643.7.1.2.1.1.4" }, + { "GOST2001-CryptoPro-C", "GOST2012-256-tc26-D" }, + + { "GOST2012-512-test", "GOST2012-test" }, + { "GOST2012-512-test", "1.2.643.7.1.2.1.2.0" }, + { "GOST2012-512-tc26-A", "GOST2012-tc26-A" }, + { "GOST2012-512-tc26-B", "GOST2012-tc26-B" }, + { "GOST2012-512-tc26-A", "1.2.643.7.1.2.1.2.1" }, + { "GOST2012-512-tc26-B", "1.2.643.7.1.2.1.2.2" }, + { "GOST2012-512-tc26-C", "1.2.643.7.1.2.1.2.3" }, + + { "secp256k1", "1.3.132.0.10" }, + + { "sm2p256v1", "1.2.156.10197.1.301" }, + + { NULL, NULL} + }; + + +typedef struct +{ + const char *desc; /* Description of the curve. */ + unsigned int nbits; /* Number of bits. */ + unsigned int fips:1; /* True if this is a FIPS140-2 approved curve. */ + + /* The model describing this curve. This is mainly used to select + the group equation. */ + enum gcry_mpi_ec_models model; + + /* The actual ECC dialect used. This is used for curve specific + optimizations and to select encodings etc. */ + enum ecc_dialects dialect; + + const char *p; /* The prime defining the field. */ + const char *a, *b; /* The coefficients. For Twisted Edwards + Curves b is used for d. For Montgomery + Curves (a,b) has ((A-2)/4,B^-1). */ + const char *n; /* The order of the base point. */ + const char *g_x, *g_y; /* Base point. */ + unsigned int h; /* Cofactor. */ +} ecc_domain_parms_t; + + +/* This static table defines all available curves. */ +static const ecc_domain_parms_t domain_parms[] = + { + { + /* (-x^2 + y^2 = 1 + dx^2y^2) */ + "Ed25519", 255, 0, + MPI_EC_EDWARDS, ECC_DIALECT_ED25519, + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "-0x01", + "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A", + "0x6666666666666666666666666666666666666666666666666666666666666658", + 8 + }, + { + /* (y^2 = x^3 + 486662*x^2 + x) */ + "Curve25519", 255, 0, + MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD, + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "0x01DB41", + "0x01", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + "0x0000000000000000000000000000000000000000000000000000000000000009", + "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9", + 8 + /* Note: As per RFC-7748 errata eid4730 the g_y value should be + * "0x5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14" + * but that breaks the keygrip. The new value is recovered in + * the function _gcry_ecc_fill_in_curve. See bug #4712. + */ + }, + { + /* (x^2 + y^2 = 1 + dx^2y^2) */ + "Ed448", 448, 0, + MPI_EC_EDWARDS, ECC_DIALECT_SAFECURVE, + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x01", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6756", + "0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3", + "0x4F1970C66BED0DED221D15A622BF36DA9E146570470F1767EA6DE324" + "A3D3A46412AE1AF72AB66511433B80E18B00938E2626A82BC70CC05E", + "0x693F46716EB6BC248876203756C9C7624BEA73736CA3984087789C1E" + "05A0C2D73AD3FF1CE67C39C4FDBD132C4ED7C8AD9808795BF230FA14", + 4, + }, + { + /* (y^2 = x^3 + 156326*x^2 + x) */ + "X448", 448, 0, + MPI_EC_MONTGOMERY, ECC_DIALECT_SAFECURVE, + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x98A9", + "0x01", + "0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3", + "0x00000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000005", + "0x7D235D1295F5B1F66C98AB6E58326FCECBAE5D34F55545D060F75DC2" + "8DF3F6EDB8027E2346430D211312C4B150677AF76FD7223D457B5B1A", + 4, + }, +#if 0 /* No real specs yet found. */ + { + /* x^2 + y^2 = 1 + 3617x^2y^2 mod 2^414 - 17 */ + "Curve3617", + "0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF", + MPI_EC_EDWARDS, 0, + "0x01", + "0x0e21", + "0x07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB3CC92414CF" + "706022B36F1C0338AD63CF181B0E71A5E106AF79", + "0x1A334905141443300218C0631C326E5FCD46369F44C03EC7F57FF35498A4AB4D" + "6D6BA111301A73FAA8537C64C4FD3812F3CBC595", + "0x22", + 8 + }, +#endif /*0*/ + { + "NIST P-192", 192, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffeffffffffffffffff", + "0xfffffffffffffffffffffffffffffffefffffffffffffffc", + "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", + "0xffffffffffffffffffffffff99def836146bc9b1b4d22831", + + "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", + "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811", + 1 + }, + { + "NIST P-224", 224, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffffffffffffffffffffffffffff000000000000000000000001", + "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe", + "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" , + + "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", + 1 + }, + { + "NIST P-256", 256, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + 1 + }, + { + "NIST P-384", 384, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000ffffffff", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000fffffffc", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" + "c656398d8a2ed19d2a85c8edd3ec2aef", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf" + "581a0db248b0a77aecec196accc52973", + + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" + "5502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" + "0a60b1ce1d7e819d7a431d7c90ea0e5f", + 1 + }, + { + "NIST P-521", 521, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", + "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + + "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d" + "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e" + "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", + 1 + }, + + { "brainpoolP160r1", 160, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xe95e4a5f737059dc60dfc7ad95b3d8139515620f", + "0x340e7be2a280eb74e2be61bada745d97e8f7c300", + "0x1e589a8595423412134faa2dbdec95c8d8675e58", + "0xe95e4a5f737059dc60df5991d45029409e60fc09", + "0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3", + "0x1667cb477a1a8ec338f94741669c976316da6321", + 1 + }, + + { "brainpoolP192r1", 192, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xc302f41d932a36cda7a3463093d18db78fce476de1a86297", + "0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef", + "0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9", + "0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1", + "0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6", + "0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f", + 1 + }, + + { "brainpoolP224r1", 224, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff", + "0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43", + "0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b", + "0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f", + "0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d", + "0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd", + 1 + }, + + { "brainpoolP256r1", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377", + "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9", + "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6", + "0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7", + "0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262", + "0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997", + 1 + }, + + { "brainpoolP320r1", 320, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28" + "fcd412b1f1b32e27", + "0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4" + "92f375a97d860eb4", + "0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd88453981" + "6f5eb4ac8fb1f1a6", + "0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e9" + "8691555b44c59311", + "0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c7" + "10af8d0d39e20611", + "0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7" + "d35245d1692e8ee1", + 1 + }, + + { "brainpoolP384r1", 384, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123" + "acd3a729901d1a71874700133107ec53", + "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f" + "8aa5814a503ad4eb04a8c7dd22ce2826", + "0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d5" + "7cb4390295dbc9943ab78696fa504c11", + "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7" + "cf3ab6af6b7fc3103b883202e9046565", + "0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8" + "e826e03436d646aaef87b2e247d4af1e", + "0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff9912928" + "0e4646217791811142820341263c5315", + 1 + }, + + { "brainpoolP512r1", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871" + "7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3", + "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc" + "2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca", + "0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a7" + "2bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723", + "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870" + "553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069", + "0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098e" + "ff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822", + "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111" + "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892", + 1 + }, + { + "GOST2001-test", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000431", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", + "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", + + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", + 1 + }, + { + "GOST2001-CryptoPro-A", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd94", + "0x00000000000000000000000000000000000000000000000000000000000000a6", + "0xffffffffffffffffffffffffffffffff6c611070995ad10045841b09b761b893", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x8d91e471e0989cda27df505a453f2b7635294f2ddf23e3b122acc99c9e9f1e14", + 1 + }, + { + "GOST2001-CryptoPro-B", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000c99", + "0x8000000000000000000000000000000000000000000000000000000000000c96", + "0x3e1af419a269a5f866a7d3c25c3df80ae979259373ff2b182f49d4ce7e1bbc8b", + "0x800000000000000000000000000000015f700cfff1a624e5e497161bcc8a198f", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x3fa8124359f96680b83d1c3eb2c070e5c545c9858d03ecfb744bf8d717717efc", + 1 + }, + { + "GOST2001-CryptoPro-C", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b", + "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598", + "0x000000000000000000000000000000000000000000000000000000000000805a", + "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67", + 1 + }, + { + "GOST2012-256-A", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97", + "0xc2173f1513981673af4892c23035a27ce25e2013bf95aa33b22c656f277e7335", + "0x295f9bae7428ed9ccc20e7c359a9d41a22fccd9108e17bf7ba9337a6f8ae9513", + "0x400000000000000000000000000000000fd8cddfc87b6635c115af556c360c67", + "0x91e38443a5e82c0d880923425712b2bb658b9196932e02c78b2582fe742daa28", + "0x32879423ab1a0375895786c4bb46e9565fde0b5344766740af268adb32322e5c", + 4 + }, + { + "GOST2012-512-test", 511, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4" + "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc", + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df", + + "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762" + "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a", + "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2" + "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e", + 1 + }, + { + "GOST2012-512-tc26-A", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc4", + "0xe8c2505dedfc86ddc1bd0b2b6667f1da34b82574761cb0e879bd081cfd0b6265" + "ee3cb090f30d27614cb4574010da90dd862ef9d4ebee4761503190785a71c760", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "27e69532f48d89116ff22b8d4e0560609b4b38abfad2b85dcacdb1411f10b275", + "0x0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000003", + "0x7503cfe87a836ae3a61b8816e25450e6ce5e1c93acf1abc1778064fdcbefa921" + "df1626be4fd036e93d75e6a50e3a41e98028fe5fc235f5b889a589cb5215f2a4", + 1 + }, + { + "GOST2012-512-tc26-B", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000006f", + "0x8000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000006c", + "0x687d1b459dc841457e3e06cf6f5e2517b97c7d614af138bcbf85dc806c4b289f" + "3e965d2db1416d217f8b276fad1ab69c50f78bee1fa3106efb8ccbc7c5140116", + "0x8000000000000000000000000000000000000000000000000000000000000001" + "49a1ec142565a545acfdb77bd9d40cfa8b996712101bea0ec6346c54374f25bd", + "0x0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000002", + "0x1a8f7eda389b094c2c071e3647a8940f3c123b697578c213be6dd9e6c8ec7335" + "dcb228fd1edf4a39152cbcaaf8c0398828041055f94ceeec7e21340780fe41bd", + 1 + }, + { + "GOST2012-512-tc26-C", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7", + "0xdc9203e514a721875485a529d2c722fb187bc8980eb866644de41c68e1430645" + "46e861c0e2c9edd92ade71f46fcf50ff2ad97f951fda9f2a2eb6546f39689bd3", + "0xb4c4ee28cebc6c2c8ac12952cf37f16ac7efb6a9f69f4b57ffda2e4f0de5ade0" + "38cbc2fff719d2c18de0284b8bfef3b52b8cc7a5f5bf0a3c8d2319a5312557e1", + "0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "c98cdba46506ab004c33a9ff5147502cc8eda9e7a769a12694623cef47f023ed", + "0xe2e31edfc23de7bdebe241ce593ef5de2295b7a9cbaef021d385f7074cea043a" + "a27272a7ae602bf2a7b9033db9ed3610c6fb85487eae97aac5bc7928c1950148", + "0xf5ce40d95b5eb899abbccff5911cb8577939804d6527378b8c108c3d2090ff9be" + "18e2d33e3021ed2ef32d85822423b6304f726aa854bae07d0396e9a9addc40f", + 4 + }, + + { + "secp256k1", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + 1 + }, + + { + "sm2p256v1", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff", + "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc", + "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93", + "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123", + "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7", + "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0", + 1 + }, + + { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } + }; + + + + +/* Return a copy of POINT. */ +static gcry_mpi_point_t +point_copy (gcry_mpi_point_t point) +{ + gcry_mpi_point_t newpoint; + + if (point) + { + newpoint = mpi_point_new (0); + point_set (newpoint, point); + } + else + newpoint = NULL; + return newpoint; +} + + +/* Helper to scan a hex string. */ +static gcry_mpi_t +scanval (const char *string) +{ + gpg_err_code_t rc; + gcry_mpi_t val; + + rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (rc) + log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); + return val; +} + + +/* Return the index of the domain_parms table for a curve with NAME. + Return -1 if not found. */ +static int +find_domain_parms_idx (const char *name) +{ + int idx, aliasno; + + /* First check our native curves. */ + for (idx = 0; domain_parms[idx].desc; idx++) + if (!strcmp (name, domain_parms[idx].desc)) + return idx; + + /* If not found consult the alias table. */ + if (!domain_parms[idx].desc) + { + for (aliasno = 0; curve_aliases[aliasno].name; aliasno++) + if (!strcmp (name, curve_aliases[aliasno].other)) + break; + if (curve_aliases[aliasno].name) + { + for (idx = 0; domain_parms[idx].desc; idx++) + if (!strcmp (curve_aliases[aliasno].name, domain_parms[idx].desc)) + return idx; + } + } + + return -1; +} + + +/* Generate the crypto system setup. This function takes the NAME of + a curve or the desired number of bits and stores at R_CURVE the + parameters of the named curve or those of a suitable curve. If + R_NBITS is not NULL, the chosen number of bits is stored there. + NULL may be given for R_CURVE, if the value is not required and for + example only a quick test for availability is desired. Note that + the curve fields should be initialized to zero because fields which + are not NULL are skipped. */ +gpg_err_code_t +_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name, + elliptic_curve_t *curve, unsigned int *r_nbits) +{ + int idx; + const char *resname = NULL; /* Set to a found curve name. */ + + if (name) + idx = find_domain_parms_idx (name); + else + { + for (idx = 0; domain_parms[idx].desc; idx++) + if (nbits == domain_parms[idx].nbits + && domain_parms[idx].model == MPI_EC_WEIERSTRASS) + break; + if (!domain_parms[idx].desc) + idx = -1; + } + if (idx < 0) + return GPG_ERR_UNKNOWN_CURVE; + + resname = domain_parms[idx].desc; + + /* In fips mode we only support NIST curves. Note that it is + possible to bypass this check by specifying the curve parameters + directly. */ + if (fips_mode () && !domain_parms[idx].fips ) + return GPG_ERR_NOT_SUPPORTED; + + switch (domain_parms[idx].model) + { + case MPI_EC_WEIERSTRASS: + case MPI_EC_EDWARDS: + case MPI_EC_MONTGOMERY: + break; + default: + return GPG_ERR_BUG; + } + + + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + + if (curve) + { + curve->model = domain_parms[idx].model; + curve->dialect = domain_parms[idx].dialect; + if (!curve->p) + curve->p = scanval (domain_parms[idx].p); + if (!curve->a) + { + curve->a = scanval (domain_parms[idx].a); + if (curve->a->sign) + { + mpi_resize (curve->a, curve->p->nlimbs); + _gcry_mpih_sub_n (curve->a->d, curve->p->d, + curve->a->d, curve->p->nlimbs); + curve->a->nlimbs = curve->p->nlimbs; + curve->a->sign = 0; + } + } + if (!curve->b) + { + curve->b = scanval (domain_parms[idx].b); + if (curve->b->sign) + { + mpi_resize (curve->b, curve->p->nlimbs); + _gcry_mpih_sub_n (curve->b->d, curve->p->d, + curve->b->d, curve->p->nlimbs); + curve->b->nlimbs = curve->p->nlimbs; + curve->b->sign = 0; + } + } + if (!curve->n) + curve->n = scanval (domain_parms[idx].n); + if (!curve->G.x) + curve->G.x = scanval (domain_parms[idx].g_x); + if (!curve->G.y) + curve->G.y = scanval (domain_parms[idx].g_y); + curve->h = domain_parms[idx].h; + + /* + * In the constants of domain_parms, we defined Curve25519 + * domain parameters as the ones in RFC-7748 before the errata + * (eid4730). To keep the computation having exact same values, + * we recover the new value of g_y, here. + */ + if (!strcmp (resname, "Curve25519")) + mpi_sub (curve->G.y, curve->p, curve->G.y); + + if (!curve->G.z) + curve->G.z = mpi_alloc_set_ui (1); + if (!curve->name) + curve->name = resname; + } + + return 0; +} + + +/* Give the name of the curve NAME, store the curve parameters into P, + A, B, G, and N if they point to NULL value. Note that G is + returned in standard uncompressed format. Also update MODEL and + DIALECT if they are not NULL. */ +gpg_err_code_t +_gcry_ecc_update_curve_param (const char *name, + enum gcry_mpi_ec_models *model, + enum ecc_dialects *dialect, + gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b, + gcry_mpi_t *g, gcry_mpi_t *n) +{ + int idx; + + idx = find_domain_parms_idx (name); + if (idx < 0) + return GPG_ERR_UNKNOWN_CURVE; + + if (g) + { + char *buf; + size_t len; + + len = 4; + len += strlen (domain_parms[idx].g_x+2); + len += strlen (domain_parms[idx].g_y+2); + len++; + buf = xtrymalloc (len); + if (!buf) + return gpg_err_code_from_syserror (); + strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2), + domain_parms[idx].g_y+2); + _gcry_mpi_release (*g); + *g = scanval (buf); + xfree (buf); + } + if (model) + *model = domain_parms[idx].model; + if (dialect) + *dialect = domain_parms[idx].dialect; + if (p) + { + _gcry_mpi_release (*p); + *p = scanval (domain_parms[idx].p); + } + if (a) + { + _gcry_mpi_release (*a); + *a = scanval (domain_parms[idx].a); + } + if (b) + { + _gcry_mpi_release (*b); + *b = scanval (domain_parms[idx].b); + } + if (n) + { + _gcry_mpi_release (*n); + *n = scanval (domain_parms[idx].n); + } + return 0; +} + + +/* Return the name matching the parameters in PKEY. This works only + with curves described by the Weierstrass equation. */ +const char * +_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits) +{ + gpg_err_code_t rc; + const char *result = NULL; + elliptic_curve_t E; + gcry_mpi_point_t G = NULL; + gcry_mpi_t tmp = NULL; + int idx; + + memset (&E, 0, sizeof E); + + if (r_nbits) + *r_nbits = 0; + + if (!keyparms) + { + idx = iterator; + if (idx >= 0 && idx < DIM (domain_parms)) + { + result = domain_parms[idx].desc; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + } + return result; + } + + + /* + * Extract the curve parameters.. + */ + rc = gpg_err_code (sexp_extract_param (keyparms, NULL, "pabn", + &E.p, &E.a, &E.b, &E.n, NULL)); + if (rc == GPG_ERR_NO_OBJ) + { + /* This might be the second use case of checking whether a + specific curve given by name is supported. */ + gcry_sexp_t l1; + char *name; + + l1 = sexp_find_token (keyparms, "curve", 5); + if (!l1) + goto leave; /* No curve name parameter. */ + + name = sexp_nth_string (l1, 1); + sexp_release (l1); + if (!name) + goto leave; /* Name missing or out of core. */ + + idx = find_domain_parms_idx (name); + xfree (name); + if (idx >= 0) /* Curve found. */ + { + result = domain_parms[idx].desc; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + } + return result; + } + + if (rc) + goto leave; + + rc = point_from_keyparam (&G, keyparms, "g", NULL); + if (rc) + goto leave; + + _gcry_mpi_point_init (&E.G); + _gcry_mpi_point_set (&E.G, G->x, G->y, G->z); + + for (idx = 0; domain_parms[idx].desc; idx++) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].p); + if (mpi_cmp (tmp, E.p)) + continue; + + mpi_free (tmp); + tmp = scanval (domain_parms[idx].a); + if (tmp->sign) + { + if (!mpi_cmpabs (tmp, E.a)) + /* For backward compatibility to <= libgcrypt 1.8, we + allow this match to support existing keys in SEXP. */ + ; + else + { + mpi_resize (tmp, E.p->nlimbs); + _gcry_mpih_sub_n (tmp->d, E.p->d, + tmp->d, E.p->nlimbs); + tmp->nlimbs = E.p->nlimbs; + tmp->sign = 0; + if (mpi_cmp (tmp, E.a)) + continue; + } + } + else if (mpi_cmp (tmp, E.a)) + continue; + + mpi_free (tmp); + tmp = scanval (domain_parms[idx].b); + if (tmp->sign) + { + if (!mpi_cmpabs (tmp, E.b)) + /* Same for backward compatibility, see above. */ + ; + else + { + mpi_resize (tmp, E.p->nlimbs); + _gcry_mpih_sub_n (tmp->d, E.p->d, + tmp->d, E.p->nlimbs); + tmp->nlimbs = E.p->nlimbs; + tmp->sign = 0; + if (mpi_cmp (tmp, E.b)) + continue; + } + } + else if (mpi_cmp (tmp, E.b)) + continue; + + mpi_free (tmp); + tmp = scanval (domain_parms[idx].n); + if (mpi_cmp (tmp, E.n)) + continue; + + mpi_free (tmp); + tmp = scanval (domain_parms[idx].g_x); + if (mpi_cmp (tmp, E.G.x)) + continue; + + mpi_free (tmp); + tmp = scanval (domain_parms[idx].g_y); + if (mpi_cmp (tmp, E.G.y)) + continue; + + result = domain_parms[idx].desc; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + break; + } + + leave: + _gcry_mpi_point_release (G); + _gcry_mpi_release (tmp); + _gcry_mpi_release (E.p); + _gcry_mpi_release (E.a); + _gcry_mpi_release (E.b); + _gcry_mpi_point_free_parts (&E.G); + _gcry_mpi_release (E.n); + return result; +} + + +/* Helper to extract an MPI from key parameters. */ +static gpg_err_code_t +mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name, + int opaque) +{ + gcry_err_code_t ec = 0; + gcry_sexp_t l1; + + l1 = sexp_find_token (keyparam, name, 0); + if (l1) + { + *r_a = sexp_nth_mpi (l1, 1, opaque? GCRYMPI_FMT_OPAQUE : GCRYMPI_FMT_USG); + sexp_release (l1); + if (!*r_a) + ec = GPG_ERR_INV_OBJ; + } + return ec; +} + +/* Helper to extract a point from key parameters. If no parameter + with NAME is found, the functions tries to find a non-encoded point + by appending ".x", ".y" and ".z" to NAME. ".z" is in this case + optional and defaults to 1. EC is the context which at this point + may not be fully initialized. */ +static gpg_err_code_t +point_from_keyparam (gcry_mpi_point_t *r_a, + gcry_sexp_t keyparam, const char *name, mpi_ec_t ec) +{ + gcry_err_code_t rc; + gcry_sexp_t l1; + gcry_mpi_point_t point; + + l1 = sexp_find_token (keyparam, name, 0); + if (l1) + { + gcry_mpi_t a; + + a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE); + sexp_release (l1); + if (!a) + return GPG_ERR_INV_OBJ; + + point = mpi_point_new (0); + rc = _gcry_mpi_ec_decode_point (point, a, ec); + mpi_free (a); + if (rc) + { + mpi_point_release (point); + return rc; + } + } + else + { + char *tmpname; + gcry_mpi_t x = NULL; + gcry_mpi_t y = NULL; + gcry_mpi_t z = NULL; + + tmpname = xtrymalloc (strlen (name) + 2 + 1); + if (!tmpname) + return gpg_err_code_from_syserror (); + strcpy (stpcpy (tmpname, name), ".x"); + rc = mpi_from_keyparam (&x, keyparam, tmpname, 0); + if (rc) + { + xfree (tmpname); + return rc; + } + strcpy (stpcpy (tmpname, name), ".y"); + rc = mpi_from_keyparam (&y, keyparam, tmpname, 0); + if (rc) + { + mpi_free (x); + xfree (tmpname); + return rc; + } + strcpy (stpcpy (tmpname, name), ".z"); + rc = mpi_from_keyparam (&z, keyparam, tmpname, 0); + if (rc) + { + mpi_free (y); + mpi_free (x); + xfree (tmpname); + return rc; + } + if (!z) + z = mpi_set_ui (NULL, 1); + if (x && y) + point = mpi_point_snatch_set (NULL, x, y, z); + else + { + mpi_free (x); + mpi_free (y); + mpi_free (z); + point = NULL; + } + xfree (tmpname); + } + + if (point) + *r_a = point; + return 0; +} + + + +static gpg_err_code_t +mpi_ec_get_elliptic_curve (elliptic_curve_t *E, int *r_flags, + gcry_sexp_t keyparam, const char *curvename) +{ + gpg_err_code_t errc; + unsigned int nbits; + gcry_sexp_t l1; + + errc = _gcry_pk_util_get_nbits (keyparam, &nbits); + if (errc) + return errc; + + E->model = MPI_EC_WEIERSTRASS; + E->dialect = ECC_DIALECT_STANDARD; + E->h = 1; + + if (keyparam) + { + /* Parse an optional flags list. */ + l1 = sexp_find_token (keyparam, "flags", 0); + if (l1) + { + int flags = 0; + + errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + l1 = NULL; + if (errc) + goto leave; + + *r_flags |= flags; + } + + /* Parse the deprecated optional transient-key flag. */ + l1 = sexp_find_token (keyparam, "transient-key", 0); + if (l1) + { + *r_flags |= PUBKEY_FLAG_TRANSIENT_KEY; + sexp_release (l1); + } + + /* Check whether a curve name was given. */ + l1 = sexp_find_token (keyparam, "curve", 5); + + /* If we don't have a curve name or if override parameters have + explicitly been requested, parse them. */ + if (!l1 || (*r_flags & PUBKEY_FLAG_PARAM)) + { + gcry_mpi_point_t G = NULL; + gcry_mpi_t cofactor = NULL; + + errc = mpi_from_keyparam (&E->p, keyparam, "p", 0); + if (errc) + goto leave; + errc = mpi_from_keyparam (&E->a, keyparam, "a", 0); + if (errc) + goto leave; + errc = mpi_from_keyparam (&E->b, keyparam, "b", 0); + if (errc) + goto leave; + errc = point_from_keyparam (&G, keyparam, "g", NULL); + if (errc) + goto leave; + if (G) + { + _gcry_mpi_point_init (&E->G); + mpi_point_set (&E->G, G->x, G->y, G->z); + mpi_point_set (G, NULL, NULL, NULL); + mpi_point_release (G); + } + errc = mpi_from_keyparam (&E->n, keyparam, "n", 0); + if (errc) + goto leave; + errc = mpi_from_keyparam (&cofactor, keyparam, "h", 0); + if (errc) + goto leave; + if (cofactor) + { + mpi_get_ui (&E->h, cofactor); + mpi_free (cofactor); + } + } + } + else + l1 = NULL; /* No curvename. */ + + /* Check whether a curve parameter is available and use that to fill + in missing values. If no curve parameter is available try an + optional provided curvename. If only the curvename has been + given use that one. */ + if (l1 || curvename || nbits) + { + char *name; + + if (l1) + { + name = sexp_nth_string (l1, 1); + sexp_release (l1); + if (!name) + { + errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ + goto leave; + } + } + else + name = NULL; + + errc = _gcry_ecc_fill_in_curve (nbits, name? name : curvename, E, NULL); + xfree (name); + if (errc) + goto leave; + } + + leave: + return errc; +} + +static gpg_err_code_t +mpi_ec_setup_elliptic_curve (mpi_ec_t ec, int flags, + elliptic_curve_t *E, gcry_sexp_t keyparam) +{ + gpg_err_code_t errc = 0; + + ec->G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z); + E->G.x = NULL; + E->G.y = NULL; + E->G.z = NULL; + ec->n = E->n; + E->n = NULL; + ec->h = E->h; + ec->name = E->name; + + /* Now that we know the curve name we can look for the public key + Q. point_from_keyparam needs to know the curve parameters so + that it is able to use the correct decompression. Parsing + the private key D could have been done earlier but it is less + surprising if we do it here as well. */ + if (keyparam) + { + int is_opaque_bytes = ((ec->dialect == ECC_DIALECT_ED25519 + && (flags & PUBKEY_FLAG_EDDSA)) + || (ec->dialect == ECC_DIALECT_SAFECURVE)); + + errc = point_from_keyparam (&ec->Q, keyparam, "q", ec); + if (errc) + return errc; + errc = mpi_from_keyparam (&ec->d, keyparam, "d", is_opaque_bytes); + + /* Size of opaque bytes should match size of P. */ + if (!errc && ec->d && is_opaque_bytes) + { + unsigned int n = mpi_get_nbits (ec->d); + unsigned int len; + + len = (ec->nbits+7)/8; + /* EdDSA requires additional bit for sign. */ + if ((ec->nbits%8) == 0 && ec->model == MPI_EC_EDWARDS) + len++; + + if ((n+7)/8 != len) + { + if (ec->dialect == ECC_DIALECT_ED25519) + { + /* + * GnuPG (<= 2.2) or OpenPGP implementations with no + * SOS support may remove zeros at the beginning. + * Recover those zeros. + */ + /* + * Also, GnuPG (<= 2.2) may add additional zero at + * the beginning, when private key is moved from + * OpenPGP to gpg-agent. Remove such a zero-prefix. + */ + const unsigned char *buf; + unsigned char *value; + + buf = mpi_get_opaque (ec->d, &n); + if (!buf) + return GPG_ERR_INV_OBJ; + + value = xtrymalloc_secure (len); + if (!value) + return gpg_err_code_from_syserror (); + + if ((n+7)/8 < len) + /* Recover zeros. */ + { + memset (value, 0, len - (n+7)/8); + memcpy (value + len - (n+7)/8, buf, (n+7)/8); + } + else if ((n+7)/8 == len + 1) + /* Remove a zero. */ + memcpy (value, buf+1, len); + else + { + xfree (value); + return GPG_ERR_INV_OBJ; + } + + mpi_set_opaque (ec->d, value, len*8); + } + else + { + if (DBG_CIPHER) + log_debug ("scalar size (%d) != prime size (%d)", + (n+7)/8, len); + + errc = GPG_ERR_INV_OBJ; + } + } + } + } + + return errc; +} + +gpg_err_code_t +_gcry_mpi_ec_internal_new (mpi_ec_t *r_ec, int *r_flags, const char *name_op, + gcry_sexp_t keyparam, const char *curvename) +{ + gpg_err_code_t errc; + elliptic_curve_t E; + mpi_ec_t ec; + + *r_ec = NULL; + + memset (&E, 0, sizeof E); + errc = mpi_ec_get_elliptic_curve (&E, r_flags, keyparam, curvename); + if (errc) + goto leave; + + ec = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, *r_flags, + E.p, E.a, E.b); + if (!ec) + goto leave; + + errc = mpi_ec_setup_elliptic_curve (ec, *r_flags, &E, keyparam); + if (errc) + { + _gcry_mpi_ec_free (ec); + goto leave; + } + else + *r_ec = ec; + + if (!errc && DBG_CIPHER) + { + gcry_mpi_t mpi_q = NULL; + gcry_sexp_t l1; + char msg[80]; + + l1 = sexp_find_token (keyparam, "q", 0); + if (l1) + { + mpi_q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE); + sexp_release (l1); + } + + log_debug ("%s info: %s/%s%s\n", name_op, + _gcry_ecc_model2str (ec->model), + _gcry_ecc_dialect2str (ec->dialect), + (*r_flags & PUBKEY_FLAG_EDDSA)? "+EdDSA" : ""); + if (ec->name) + log_debug ("%s name: %s\n", name_op, ec->name); + snprintf (msg, sizeof msg, "%s p", name_op); + log_printmpi (msg, ec->p); + snprintf (msg, sizeof msg, "%s a", name_op); + log_printmpi (msg, ec->a); + snprintf (msg, sizeof msg, "%s b", name_op); + log_printmpi (msg, ec->b); + snprintf (msg, sizeof msg, "%s g", name_op); + log_printpnt (msg, ec->G, NULL); + snprintf (msg, sizeof msg, "%s n", name_op); + log_printmpi (msg, ec->n); + log_debug ("%s h:+%02x\n", name_op, ec->h); + if (mpi_q) + { + snprintf (msg, sizeof msg, "%s q", name_op); + log_printmpi (msg, mpi_q); + mpi_free (mpi_q); + } + if (!fips_mode () && ec->d) + { + snprintf (msg, sizeof msg, "%s d", name_op); + log_printmpi (msg, ec->d); + } + } + + leave: + _gcry_ecc_curve_free (&E); + return errc; +} + +/* This function creates a new context for elliptic curve operations. + Either KEYPARAM or CURVENAME must be given. If both are given and + KEYPARAM has no curve parameter, CURVENAME is used to add missing + parameters. On success 0 is returned and the new context stored at + R_CTX. On error NULL is stored at R_CTX and an error code is + returned. The context needs to be released using + gcry_ctx_release. */ +gpg_err_code_t +_gcry_mpi_ec_new (gcry_ctx_t *r_ctx, + gcry_sexp_t keyparam, const char *curvename) +{ + gpg_err_code_t errc; + elliptic_curve_t E; + gcry_ctx_t ctx = NULL; + int flags = 0; + mpi_ec_t ec; + + *r_ctx = NULL; + + memset (&E, 0, sizeof E); + errc = mpi_ec_get_elliptic_curve (&E, &flags, keyparam, curvename); + if (errc) + goto leave; + + errc = _gcry_mpi_ec_p_new (&ctx, E.model, E.dialect, flags, E.p, E.a, E.b); + if (errc) + goto leave; + + ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); + errc = mpi_ec_setup_elliptic_curve (ec, flags, &E, keyparam); + if (errc) + goto leave; + + *r_ctx = ctx; + ctx = NULL; + + leave: + _gcry_ecc_curve_free (&E); + _gcry_ctx_release (ctx); + return errc; +} + + +/* Return the parameters of the curve NAME as an S-expression. */ +gcry_sexp_t +_gcry_ecc_get_param_sexp (const char *name) +{ + unsigned int nbits; + elliptic_curve_t E; + mpi_ec_t ctx; + gcry_mpi_t g_x, g_y; + gcry_mpi_t pkey[5]; + gcry_sexp_t result; + int i; + + memset (&E, 0, sizeof E); + if (_gcry_ecc_fill_in_curve (0, name, &E, &nbits)) + return NULL; + + g_x = mpi_new (0); + g_y = mpi_new (0); + ctx = _gcry_mpi_ec_p_internal_new (E.model, + E.dialect, + 0, + E.p, E.a, E.b); + if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx)) + log_fatal ("ecc get param: Failed to get affine coordinates\n"); + _gcry_mpi_ec_free (ctx); + _gcry_mpi_point_free_parts (&E.G); + + pkey[0] = E.p; + pkey[1] = E.a; + pkey[2] = E.b; + pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p); + pkey[4] = E.n; + + mpi_free (g_x); + mpi_free (g_y); + + if (sexp_build (&result, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%u)))", + pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], E.h)) + result = NULL; + + for (i=0; i < DIM (pkey); i++) + _gcry_mpi_release (pkey[i]); + + return result; +} + + +/* Return an MPI (or opaque MPI) described by NAME and the context EC. + If COPY is true a copy is returned, if not a const MPI may be + returned. In any case mpi_free must be used. */ +gcry_mpi_t +_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy) +{ + if (!*name) + return NULL; + + if (!strcmp (name, "p") && ec->p) + return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p); + if (!strcmp (name, "a") && ec->a) + return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a); + if (!strcmp (name, "b") && ec->b) + return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b); + if (!strcmp (name, "n") && ec->n) + return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n); + if (!strcmp (name, "h")) + { + gcry_mpi_t h = _gcry_mpi_get_const (ec->h); + + return !copy? h : mpi_set (NULL, h); + } + if (!strcmp (name, "d") && ec->d) + return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d); + + /* Return a requested point coordinate. */ + if (!strcmp (name, "g.x") && ec->G && ec->G->x) + return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x); + if (!strcmp (name, "g.y") && ec->G && ec->G->y) + return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y); + if (!strcmp (name, "q.x") && ec->Q && ec->Q->x) + return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x); + if (!strcmp (name, "q.y") && ec->Q && ec->Q->y) + return mpi_is_const (ec->Q->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y); + + /* If the base point has been requested, return it in standard + encoding. */ + if (!strcmp (name, "g") && ec->G) + return _gcry_mpi_ec_ec2os (ec->G, ec); + + /* If the public key has been requested, return it by default in + standard uncompressed encoding or if requested in other + encodings. */ + if (*name == 'q' && (!name[1] || name[1] == '@')) + { + /* If only the private key is given, compute the public key. */ + if (!ec->Q) + ec->Q = _gcry_ecc_compute_public (NULL, ec); + + if (!ec->Q) + return NULL; + + if (name[1] != '@') + return _gcry_mpi_ec_ec2os (ec->Q, ec); + + if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_EDWARDS) + { + unsigned char *encpk; + unsigned int encpklen; + + if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, + &encpk, &encpklen)) + return mpi_set_opaque (NULL, encpk, encpklen*8); + } + } + + return NULL; +} + + +/* Return a point described by NAME and the context EC. */ +gcry_mpi_point_t +_gcry_ecc_get_point (const char *name, mpi_ec_t ec) +{ + if (!strcmp (name, "g") && ec->G) + return point_copy (ec->G); + if (!strcmp (name, "q")) + { + /* If only the private key is given, compute the public key. */ + if (!ec->Q) + ec->Q = _gcry_ecc_compute_public (NULL, ec); + + if (ec->Q) + return point_copy (ec->Q); + } + + return NULL; +} + + +/* Store the MPI NEWVALUE into the context EC under NAME. */ +gpg_err_code_t +_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec) +{ + gpg_err_code_t rc = 0; + + if (!*name) + ; + else if (!strcmp (name, "p")) + { + mpi_free (ec->p); + ec->p = mpi_copy (newvalue); + _gcry_mpi_ec_get_reset (ec); + } + else if (!strcmp (name, "a")) + { + mpi_free (ec->a); + ec->a = mpi_copy (newvalue); + _gcry_mpi_ec_get_reset (ec); + } + else if (!strcmp (name, "b")) + { + mpi_free (ec->b); + ec->b = mpi_copy (newvalue); + } + else if (!strcmp (name, "n")) + { + mpi_free (ec->n); + ec->n = mpi_copy (newvalue); + } + else if (!strcmp (name, "h")) + { + mpi_get_ui (&ec->h, newvalue); + } + else if (*name == 'q' && (!name[1] || name[1] == '@')) + { + if (newvalue) + { + if (!ec->Q) + ec->Q = mpi_point_new (0); + rc = _gcry_mpi_ec_decode_point (ec->Q, newvalue, ec); + } + if (rc || !newvalue) + { + _gcry_mpi_point_release (ec->Q); + ec->Q = NULL; + } + /* Note: We assume that Q matches d and thus do not reset d. */ + } + else if (!strcmp (name, "d")) + { + mpi_free (ec->d); + ec->d = mpi_copy (newvalue); + if (ec->d) + { + /* We need to reset the public key because it may not + anymore match. */ + _gcry_mpi_point_release (ec->Q); + ec->Q = NULL; + } + } + else + rc = GPG_ERR_UNKNOWN_NAME; + + return rc; +} + + +/* Store the point NEWVALUE into the context EC under NAME. */ +gpg_err_code_t +_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec) +{ + if (!strcmp (name, "g")) + { + _gcry_mpi_point_release (ec->G); + ec->G = point_copy (newvalue); + } + else if (!strcmp (name, "q")) + { + _gcry_mpi_point_release (ec->Q); + ec->Q = point_copy (newvalue); + } + else + return GPG_ERR_UNKNOWN_NAME; + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc-ecdh.c b/comm/third_party/libgcrypt/cipher/ecc-ecdh.c new file mode 100644 index 0000000000..d6b8991af6 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-ecdh.c @@ -0,0 +1,127 @@ +/* ecc-ecdh.c - Elliptic Curve Diffie-Hellman key agreement + * Copyright (C) 2019 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" + +#define ECC_CURVE25519_BYTES 32 +#define ECC_CURVE448_BYTES 56 + +static gpg_err_code_t +prepare_ec (mpi_ec_t *r_ec, const char *name) +{ + int flags = 0; + + if (!strcmp (name, "Curve25519")) + flags = PUBKEY_FLAG_DJB_TWEAK; + + return _gcry_mpi_ec_internal_new (r_ec, &flags, "ecc_mul_point", NULL, name); +} + +unsigned int +_gcry_ecc_get_algo_keylen (int curveid) +{ + unsigned int len = 0; + + if (curveid == GCRY_ECC_CURVE25519) + len = ECC_CURVE25519_BYTES; + else if (curveid == GCRY_ECC_CURVE448) + len = ECC_CURVE448_BYTES; + + return len; +} + +gpg_error_t +_gcry_ecc_mul_point (int curveid, unsigned char *result, + const unsigned char *scalar, const unsigned char *point) +{ + unsigned int nbits; + unsigned int nbytes; + const char *curve; + gpg_err_code_t err; + gcry_mpi_t mpi_k; + mpi_ec_t ec; + mpi_point_struct Q; + gcry_mpi_t x; + unsigned int len; + unsigned char *buf; + + if (curveid == GCRY_ECC_CURVE25519) + curve = "Curve25519"; + else if (curveid == GCRY_ECC_CURVE448) + curve = "X448"; + else + return gpg_error (GPG_ERR_UNKNOWN_CURVE); + + err = prepare_ec (&ec, curve); + if (err) + return err; + + nbits = ec->nbits; + nbytes = (nbits + 7)/8; + + mpi_k = _gcry_mpi_set_opaque_copy (NULL, scalar, nbytes*8); + x = mpi_new (nbits); + point_init (&Q); + + if (point) + { + gcry_mpi_t mpi_u = _gcry_mpi_set_opaque_copy (NULL, point, nbytes*8); + mpi_point_struct P; + + point_init (&P); + err = _gcry_ecc_mont_decodepoint (mpi_u, ec, &P); + _gcry_mpi_release (mpi_u); + if (err) + goto leave; + _gcry_mpi_ec_mul_point (&Q, mpi_k, &P, ec); + point_free (&P); + } + else + _gcry_mpi_ec_mul_point (&Q, mpi_k, ec->G, ec); + + _gcry_mpi_ec_get_affine (x, NULL, &Q, ec); + + buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL); + if (!buf) + err = gpg_error_from_syserror (); + else + { + memcpy (result, buf, nbytes); + xfree (buf); + } + + leave: + _gcry_mpi_release (x); + point_free (&Q); + _gcry_mpi_release (mpi_k); + _gcry_mpi_ec_free (ec); + return err; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc-ecdsa.c b/comm/third_party/libgcrypt/cipher/ecc-ecdsa.c new file mode 100644 index 0000000000..30103f1417 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-ecdsa.c @@ -0,0 +1,248 @@ +/* ecc-ecdsa.c - Elliptic Curve ECDSA signatures + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" + + +/* Compute an ECDSA signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +gpg_err_code_t +_gcry_ecc_ecdsa_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s, + int flags, int hashalgo) +{ + gpg_err_code_t rc = 0; + int extraloops = 0; + gcry_mpi_t k, dr, sum, k_1, x; + mpi_point_struct I; + gcry_mpi_t hash; + const void *abuf; + unsigned int abits, qbits; + gcry_mpi_t b; /* Random number needed for blinding. */ + gcry_mpi_t bi; /* multiplicative inverse of B. */ + + if (DBG_CIPHER) + log_mpidump ("ecdsa sign hash ", input ); + + qbits = mpi_get_nbits (ec->n); + + /* Convert the INPUT into an MPI if needed. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + b = mpi_snew (qbits); + bi = mpi_snew (qbits); + do + { + _gcry_mpi_randomize (b, qbits, GCRY_WEAK_RANDOM); + mpi_mod (b, b, ec->n); + } + while (!mpi_invm (bi, b, ec->n)); + + k = NULL; + dr = mpi_alloc (0); + sum = mpi_alloc (0); + k_1 = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&I); + + /* Two loops to avoid R or S are zero. This is more of a joke than + a real demand because the probability of them being zero is less + than any hardware failure. Some specs however require it. */ + do + { + do + { + mpi_free (k); + k = NULL; + if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) + { + /* Use Pornin's method for deterministic DSA. If this + flag is set, it is expected that HASH is an opaque + MPI with the to be signed hash. That hash is also + used as h1 from 3.2.a. */ + if (!mpi_is_opaque (input)) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_dsa_gen_rfc6979_k (&k, ec->n, ec->d, + abuf, (abits+7)/8, + hashalgo, extraloops); + if (rc) + goto leave; + extraloops++; + } + else + k = _gcry_dsa_gen_k (ec->n, GCRY_STRONG_RANDOM); + + mpi_invm (k_1, k, ec->n); /* k_1 = k^(-1) mod n */ + + _gcry_dsa_modify_k (k, ec->n, qbits); + + _gcry_mpi_ec_mul_point (&I, k, ec->G, ec); + if (_gcry_mpi_ec_get_affine (x, NULL, &I, ec)) + { + if (DBG_CIPHER) + log_debug ("ecc sign: Failed to get affine coordinates\n"); + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (r, x, ec->n); /* r = x mod n */ + } + while (!mpi_cmp_ui (r, 0)); + + /* Computation of dr, sum, and s are blinded with b. */ + mpi_mulm (dr, b, ec->d, ec->n); + mpi_mulm (dr, dr, r, ec->n); /* dr = d*r mod n */ + mpi_mulm (sum, b, hash, ec->n); + mpi_addm (sum, sum, dr, ec->n); /* sum = hash + (d*r) mod n */ + mpi_mulm (s, k_1, sum, ec->n); /* s = k^(-1)*(hash+(d*r)) mod n */ + /* Undo blinding by b^-1 */ + mpi_mulm (s, bi, s, ec->n); + } + while (!mpi_cmp_ui (s, 0)); + + if (DBG_CIPHER) + { + log_mpidump ("ecdsa sign result r ", r); + log_mpidump ("ecdsa sign result s ", s); + } + + leave: + mpi_free (b); + mpi_free (bi); + point_free (&I); + mpi_free (x); + mpi_free (k_1); + mpi_free (sum); + mpi_free (dr); + mpi_free (k); + + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/* Verify an ECDSA signature. + * Check if R and S verifies INPUT. + */ +gpg_err_code_t +_gcry_ecc_ecdsa_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t hash, h, h1, h2, x; + mpi_point_struct Q, Q1, Q2; + unsigned int nbits; + + if (!_gcry_mpi_ec_curve_point (ec->Q, ec)) + return GPG_ERR_BROKEN_PUBKEY; + + if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, ec->n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, ec->n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + nbits = mpi_get_nbits (ec->n); + err = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (err) + return err; + + h = mpi_alloc (0); + h1 = mpi_alloc (0); + h2 = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&Q); + point_init (&Q1); + point_init (&Q2); + + /* h = s^(-1) (mod n) */ + mpi_invm (h, s, ec->n); + /* h1 = hash * s^(-1) (mod n) */ + mpi_mulm (h1, hash, h, ec->n); + /* Q1 = [ hash * s^(-1) ]G */ + _gcry_mpi_ec_mul_point (&Q1, h1, ec->G, ec); + /* h2 = r * s^(-1) (mod n) */ + mpi_mulm (h2, r, h, ec->n); + /* Q2 = [ r * s^(-1) ]Q */ + _gcry_mpi_ec_mul_point (&Q2, h2, ec->Q, ec); + /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */ + _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ec); + + if (!mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Rejected\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ec)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (x, x, ec->n); /* x = x mod E_n */ + if (mpi_cmp (x, r)) /* x != r */ + { + if (DBG_CIPHER) + { + log_mpidump (" x", x); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + leave: + point_free (&Q2); + point_free (&Q1); + point_free (&Q); + mpi_free (x); + mpi_free (h2); + mpi_free (h1); + mpi_free (h); + if (hash != input) + mpi_free (hash); + + return err; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc-eddsa.c b/comm/third_party/libgcrypt/cipher/ecc-eddsa.c new file mode 100644 index 0000000000..2a1a89073c --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-eddsa.c @@ -0,0 +1,1182 @@ +/* ecc-eddsa.c - Elliptic Curve EdDSA signatures + * Copyright (C) 2013, 2014 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" + + + +void +reverse_buffer (unsigned char *buffer, unsigned int length) +{ + unsigned int tmp, i; + + for (i=0; i < length/2; i++) + { + tmp = buffer[i]; + buffer[i] = buffer[length-1-i]; + buffer[length-1-i] = tmp; + } +} + + +/* Helper to scan a hex string. */ +static gcry_mpi_t +scanval (const char *string) +{ + gpg_err_code_t rc; + gcry_mpi_t val; + + rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (rc) + log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); + return val; +} + + + +/* Encode MPI using the EdDSA scheme. MINLEN specifies the required + length of the buffer in bytes. On success 0 is returned an a + malloced buffer with the encoded point is stored at R_BUFFER; the + length of this buffer is stored at R_BUFLEN. */ +static gpg_err_code_t +eddsa_encodempi (gcry_mpi_t mpi, unsigned int nbits, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + unsigned char *rawmpi; + unsigned int rawmpilen; + unsigned int minlen = (nbits%8) == 0 ? (nbits/8 + 1): (nbits+7)/8; + + rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + + *r_buffer = rawmpi; + *r_buflen = rawmpilen; + return 0; +} + + +/* Encode (X,Y) using the EdDSA scheme. NBITS is the number of bits + of the field of the curve. If WITH_PREFIX is set the returned + buffer is prefixed with a 0x40 byte. On success 0 is returned and + a malloced buffer with the encoded point is stored at R_BUFFER; the + length of this buffer is stored at R_BUFLEN. */ +static gpg_err_code_t +eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int nbits, + int with_prefix, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + unsigned char *rawmpi; + unsigned int rawmpilen; + int off = with_prefix? 1:0; + unsigned int minlen = (nbits%8) == 0 ? (nbits/8 + 1): (nbits+7)/8; + + rawmpi = _gcry_mpi_get_buffer_extra (y, minlen, off?-1:0, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + if (mpi_test_bit (x, 0) && rawmpilen) + rawmpi[off + rawmpilen - 1] |= 0x80; /* Set sign bit. */ + if (off) + rawmpi[0] = 0x40; + + *r_buffer = rawmpi; + *r_buflen = rawmpilen + off; + return 0; +} + +/* Encode POINT using the EdDSA scheme. X and Y are either scratch + variables supplied by the caller or NULL. CTX is the usual + context. If WITH_PREFIX is set the returned buffer is prefixed + with a 0x40 byte. On success 0 is returned and a malloced buffer + with the encoded point is stored at R_BUFFER; the length of this + buffer is stored at R_BUFLEN. */ +gpg_err_code_t +_gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec, + gcry_mpi_t x_in, gcry_mpi_t y_in, + int with_prefix, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + gpg_err_code_t rc; + gcry_mpi_t x, y; + + x = x_in? x_in : mpi_new (0); + y = y_in? y_in : mpi_new (0); + + if (_gcry_mpi_ec_get_affine (x, y, point, ec)) + { + log_error ("eddsa_encodepoint: Failed to get affine coordinates\n"); + rc = GPG_ERR_INTERNAL; + } + else + rc = eddsa_encode_x_y (x, y, ec->nbits, with_prefix, r_buffer, r_buflen); + + if (!x_in) + mpi_free (x); + if (!y_in) + mpi_free (y); + return rc; +} + + +/* Make sure that the opaque MPI VALUE is in compact EdDSA format. + This function updates MPI if needed. */ +gpg_err_code_t +_gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, unsigned int nbits) +{ + gpg_err_code_t rc; + const unsigned char *buf; + unsigned int rawmpilen; + gcry_mpi_t x, y; + unsigned char *enc; + unsigned int enclen; + + if (!mpi_is_opaque (value)) + return GPG_ERR_INV_OBJ; + buf = mpi_get_opaque (value, &rawmpilen); + if (!buf) + return GPG_ERR_INV_OBJ; + rawmpilen = (rawmpilen + 7)/8; + + if (rawmpilen > 1 && (rawmpilen%2)) + { + if (buf[0] == 0x04) + { + /* Buffer is in SEC1 uncompressed format. Extract y and + compress. */ + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, + buf+1, (rawmpilen-1)/2, NULL); + if (rc) + return rc; + rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, + buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL); + if (rc) + { + mpi_free (x); + return rc; + } + + rc = eddsa_encode_x_y (x, y, nbits, 0, &enc, &enclen); + mpi_free (x); + mpi_free (y); + if (rc) + return rc; + + mpi_set_opaque (value, enc, 8*enclen); + } + else if (buf[0] == 0x40) + { + /* Buffer is compressed but with our SEC1 alike compression + indicator. Remove that byte. FIXME: We should write and + use a function to manipulate an opaque MPI in place. */ + if (!_gcry_mpi_set_opaque_copy (value, buf + 1, (rawmpilen - 1)*8)) + return gpg_err_code_from_syserror (); + } + } + + return 0; +} + + +static gpg_err_code_t +ecc_ed448_recover_x (gcry_mpi_t x, gcry_mpi_t y, int x_0, mpi_ec_t ec) +{ + gpg_err_code_t rc = 0; + gcry_mpi_t u, v, u3, v3, t; + static gcry_mpi_t p34; /* Hard coded (P-3)/4 */ + + if (mpi_cmp (y, ec->p) >= 0) + rc = GPG_ERR_INV_OBJ; + + if (!p34) + p34 = scanval ("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + u = mpi_new (0); + v = mpi_new (0); + u3 = mpi_new (0); + v3 = mpi_new (0); + t = mpi_new (0); + + /* Compute u and v */ + /* u = y^2 */ + mpi_mulm (u, y, y, ec->p); + /* v = b*y^2 */ + mpi_mulm (v, ec->b, u, ec->p); + /* u = y^2-1 */ + mpi_sub_ui (u, u, 1); + /* v = b*y^2-1 */ + mpi_sub_ui (v, v, 1); + + /* Compute sqrt(u/v) */ + /* u3 = u^3 */ + mpi_powm (u3, u, mpi_const (MPI_C_THREE), ec->p); + mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); + /* t = u^4 * u * v3 = u^5 * v^3 */ + mpi_powm (t, u, mpi_const (MPI_C_FOUR), ec->p); + mpi_mulm (t, t, u, ec->p); + mpi_mulm (t, t, v3, ec->p); + /* t = t^((p-3)/4) = (u^5 * v^3)^((p-3)/4) */ + mpi_powm (t, t, p34, ec->p); + /* x = t * u^3 * v = (u^3 * v) * (u^5 * v^3)^((p-3)/4) */ + mpi_mulm (t, t, u3, ec->p); + mpi_mulm (x, t, v, ec->p); + + /* t = v * x^2 */ + mpi_mulm (t, x, x, ec->p); + mpi_mulm (t, t, v, ec->p); + + if (mpi_cmp (t, u) != 0) + rc = GPG_ERR_INV_OBJ; + else + { + if (!mpi_cmp_ui (x, 0) && x_0) + rc = GPG_ERR_INV_OBJ; + + /* Choose the desired square root according to parity */ + if (mpi_test_bit (x, 0) != !!x_0) + mpi_sub (x, ec->p, x); + } + + mpi_free (t); + mpi_free (u3); + mpi_free (v3); + mpi_free (v); + mpi_free (u); + + return rc; +} + + +/* Recover X from Y and SIGN (which actually is a parity bit). */ +gpg_err_code_t +_gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) +{ + gpg_err_code_t rc = 0; + gcry_mpi_t u, v, v3, t; + static gcry_mpi_t p58, seven; + + /* + * This routine is actually curve specific. Now, only supports + * Ed25519 and Ed448. + */ + + if (ec->dialect != ECC_DIALECT_ED25519) + /* For now, it's only Ed448. */ + return ecc_ed448_recover_x (x, y, sign, ec); + + /* It's Ed25519. */ + + if (!p58) + p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD"); + if (!seven) + seven = mpi_set_ui (NULL, 7); + + u = mpi_new (0); + v = mpi_new (0); + v3 = mpi_new (0); + t = mpi_new (0); + + /* Compute u and v */ + /* u = y^2 */ + mpi_mulm (u, y, y, ec->p); + /* v = b*y^2 */ + mpi_mulm (v, ec->b, u, ec->p); + /* u = y^2-1 */ + mpi_sub_ui (u, u, 1); + /* v = b*y^2+1 */ + mpi_add_ui (v, v, 1); + + /* Compute sqrt(u/v) */ + /* v3 = v^3 */ + mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); + /* t = v3 * v3 * u * v = u * v^7 */ + mpi_powm (t, v, seven, ec->p); + mpi_mulm (t, t, u, ec->p); + /* t = t^((p-5)/8) = (u * v^7)^((p-5)/8) */ + mpi_powm (t, t, p58, ec->p); + /* x = t * u * v^3 = (u * v^3) * (u * v^7)^((p-5)/8) */ + mpi_mulm (t, t, u, ec->p); + mpi_mulm (x, t, v3, ec->p); + + /* Adjust if needed. */ + /* t = v * x^2 */ + mpi_mulm (t, x, x, ec->p); + mpi_mulm (t, t, v, ec->p); + /* -t == u ? x = x * sqrt(-1) */ + mpi_sub (t, ec->p, t); + if (!mpi_cmp (t, u)) + { + static gcry_mpi_t m1; /* Fixme: this is not thread-safe. */ + if (!m1) + m1 = scanval ("2B8324804FC1DF0B2B4D00993DFBD7A7" + "2F431806AD2FE478C4EE1B274A0EA0B0"); + mpi_mulm (x, x, m1, ec->p); + /* t = v * x^2 */ + mpi_mulm (t, x, x, ec->p); + mpi_mulm (t, t, v, ec->p); + /* -t == u ? x = x * sqrt(-1) */ + mpi_sub (t, ec->p, t); + if (!mpi_cmp (t, u)) + rc = GPG_ERR_INV_OBJ; + } + + /* Choose the desired square root according to parity */ + if (mpi_test_bit (x, 0) != !!sign) + mpi_sub (x, ec->p, x); + + mpi_free (t); + mpi_free (v3); + mpi_free (v); + mpi_free (u); + + return rc; +} + + +/* Decode the EdDSA style encoded PK and set it into RESULT. CTX is + the usual curve context. If R_ENCPK is not NULL, the encoded PK is + stored at that address; this is a new copy to be released by the + caller. In contrast to the supplied PK, this is not an MPI and + thus guaranteed to be properly padded. R_ENCPKLEN receives the + length of that encoded key. */ +gpg_err_code_t +_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result, + unsigned char **r_encpk, unsigned int *r_encpklen) +{ + gpg_err_code_t rc; + unsigned char *rawmpi; + unsigned int rawmpilen; + int sign; + + if (mpi_is_opaque (pk)) + { + const unsigned char *buf; + unsigned int len; + + len = (ctx->nbits%8) == 0 ? (ctx->nbits/8 + 1): (ctx->nbits+7)/8; + + buf = mpi_get_opaque (pk, &rawmpilen); + if (!buf) + return GPG_ERR_INV_OBJ; + rawmpilen = (rawmpilen + 7)/8; + + if (!(rawmpilen == len + || rawmpilen == len + 1 + || rawmpilen == len * 2 + 1)) + return GPG_ERR_INV_OBJ; + + /* Handle compression prefixes. The size of the buffer will be + odd in this case. */ + if (rawmpilen > 1 && (rawmpilen == len + 1 || rawmpilen == len * 2 + 1)) + { + /* First check whether the public key has been given in + standard uncompressed format (SEC1). No need to recover + x in this case. */ + if (buf[0] == 0x04) + { + gcry_mpi_t x, y; + + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, + buf+1, (rawmpilen-1)/2, NULL); + if (rc) + return rc; + rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, + buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2,NULL); + if (rc) + { + mpi_free (x); + return rc; + } + + if (r_encpk) + { + rc = eddsa_encode_x_y (x, y, ctx->nbits, 0, + r_encpk, r_encpklen); + if (rc) + { + mpi_free (x); + mpi_free (y); + return rc; + } + } + mpi_snatch (result->x, x); + mpi_snatch (result->y, y); + mpi_set_ui (result->z, 1); + return 0; + } + + /* Check whether the public key has been prefixed with a 0x40 + byte to explicitly indicate compressed format using a SEC1 + alike prefix byte. This is a Libgcrypt extension. */ + if (buf[0] == 0x40) + { + rawmpilen--; + buf++; + } + } + + /* EdDSA compressed point. */ + rawmpi = xtrymalloc (rawmpilen); + if (!rawmpi) + return gpg_err_code_from_syserror (); + memcpy (rawmpi, buf, rawmpilen); + reverse_buffer (rawmpi, rawmpilen); + } + else + { + /* Note: Without using an opaque MPI it is not reliable possible + to find out whether the public key has been given in + uncompressed format. Thus we expect native EdDSA format. */ + rawmpi = _gcry_mpi_get_buffer (pk, (ctx->nbits+7)/8, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + } + + if (rawmpilen) + { + sign = !!(rawmpi[0] & 0x80); + rawmpi[0] &= 0x7f; + } + else + sign = 0; + _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0); + if (r_encpk) + { + /* Revert to little endian. */ + if (sign && rawmpilen) + rawmpi[0] |= 0x80; + reverse_buffer (rawmpi, rawmpilen); + *r_encpk = rawmpi; + if (r_encpklen) + *r_encpklen = rawmpilen; + } + else + xfree (rawmpi); + + rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx); + mpi_set_ui (result->z, 1); + + return rc; +} + + +/* Compute the A value as used by EdDSA. The caller needs to provide + the context EC and the actual secret D as an MPI. The function + returns a newly allocated 64 byte buffer at r_digest; the first 32 + bytes represent the A value. NULL is returned on error and NULL + stored at R_DIGEST. */ +gpg_err_code_t +_gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec) +{ + gpg_err_code_t rc; + unsigned char *rawmpi = NULL; + unsigned int rawmpilen; + unsigned char *digest; + int hashalgo, b; + + *r_digest = NULL; + + b = (ec->nbits+7)/8; + + /* + * Choice of hashalgo is curve specific. + * For now, it's determine by the bit size of the field. + */ + if (ec->nbits == 255) + hashalgo = GCRY_MD_SHA512; + else if (ec->nbits == 448) + { + b++; + hashalgo = GCRY_MD_SHAKE256; + } + else + return GPG_ERR_NOT_IMPLEMENTED; + + /* Note that we clear DIGEST so we can use it as input to left pad + the key with zeroes for hashing. */ + digest = xtrycalloc_secure (2, b); + if (!digest) + return gpg_err_code_from_syserror (); + + rawmpi = _gcry_mpi_get_buffer (ec->d, 0, &rawmpilen, NULL); + if (!rawmpi) + { + xfree (digest); + return gpg_err_code_from_syserror (); + } + + if (hashalgo == GCRY_MD_SHAKE256) + { + gcry_error_t err; + gcry_md_hd_t hd; + + err = _gcry_md_open (&hd, hashalgo, 0); + if (err) + rc = gcry_err_code (err); + else + { + _gcry_md_write (hd, rawmpi, rawmpilen); + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); + _gcry_md_close (hd); + rc = 0; + } + } + else + { + gcry_buffer_t hvec[2]; + + memset (hvec, 0, sizeof hvec); + + hvec[0].data = digest; + hvec[0].len = b > rawmpilen? b - rawmpilen : 0; + hvec[1].data = rawmpi; + hvec[1].len = rawmpilen; + rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); + } + + xfree (rawmpi); + if (rc) + { + xfree (digest); + return rc; + } + + /* Compute the A value. */ + reverse_buffer (digest, b); /* Only the first half of the hash. */ + + /* Field specific handling of clearing/setting bits. */ + if (ec->nbits == 255) + { + digest[0] = (digest[0] & 0x7f) | 0x40; + digest[31] &= 0xf8; + } + else + { + digest[0] = 0; + digest[1] |= 0x80; + digest[56] &= 0xfc; + } + + *r_digest = digest; + return 0; +} + + +/** + * _gcry_ecc_eddsa_genkey - EdDSA version of the key generation. + * + * @ec: Elliptic curve computation context. + * @flags: Flags controlling aspects of the creation. + * + * Return: An error code. + * + * The only @flags bit used by this function is %PUBKEY_FLAG_TRANSIENT + * to use a faster RNG. + */ +gpg_err_code_t +_gcry_ecc_eddsa_genkey (mpi_ec_t ec, int flags) +{ + gpg_err_code_t rc; + int b; + gcry_mpi_t a, x, y; + mpi_point_struct Q; + gcry_random_level_t random_level; + char *dbuf; + size_t dlen; + unsigned char *hash_d = NULL; + + point_init (&Q); + + if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) + random_level = GCRY_STRONG_RANDOM; + else + random_level = GCRY_VERY_STRONG_RANDOM; + + b = (ec->nbits+7)/8; + + if (ec->nbits == 255) + ; + else if (ec->nbits == 448) + b++; + else + return GPG_ERR_NOT_IMPLEMENTED; + + dlen = b; + + a = mpi_snew (0); + x = mpi_new (0); + y = mpi_new (0); + + /* Generate a secret. */ + dbuf = _gcry_random_bytes_secure (dlen, random_level); + ec->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8); + rc = _gcry_ecc_eddsa_compute_h_d (&hash_d, ec); + if (rc) + goto leave; + + _gcry_mpi_set_buffer (a, hash_d, b, 0); + xfree (hash_d); + /* log_printmpi ("ecgen a", a); */ + + /* Compute Q. */ + _gcry_mpi_ec_mul_point (&Q, a, ec->G, ec); + if (DBG_CIPHER) + log_printpnt ("ecgen pk", &Q, ec); + + ec->Q = mpi_point_snatch_set (NULL, Q.x, Q.y, Q.z); + Q.x = NULL; + Q.y = NULL; + Q.x = NULL; + + leave: + _gcry_mpi_release (a); + _gcry_mpi_release (x); + _gcry_mpi_release (y); + return rc; +} + + +/* Compute an EdDSA signature. See: + * [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja + * Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security + * signatures. Journal of Cryptographic Engineering 2 (2012), 77-89. + * Document ID: a1a62a2f76d23f65d622484ddd09caf8. + * URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. + * + * Despite that this function requires the specification of a hash + * algorithm, we only support what has been specified by the paper. + * This may change in the future. + * + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R_R and S. + */ + +/* String to be used with Ed448 */ +#define DOM25519 "SigEd25519 no Ed25519 collisions" +#define DOM25519_LEN 32 +#define DOM448 "SigEd448" +#define DOM448_LEN 8 + +gpg_err_code_t +_gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r_r, gcry_mpi_t s, + struct pk_encoding_ctx *ctx) +{ + int rc; + unsigned int tmp; + unsigned char *digest = NULL; + const void *mbuf; + size_t mlen; + unsigned char *rawmpi = NULL; + unsigned int rawmpilen; + unsigned char *encpk = NULL; /* Encoded public key. */ + unsigned int encpklen; + mpi_point_struct I; /* Intermediate value. */ + gcry_mpi_t a, x, y, r; + int b; + unsigned char x_olen[2]; + unsigned char prehashed_msg[64]; + + b = (ec->nbits+7)/8; + + if (ec->nbits == 255) + ; + else if (ec->nbits == 448) + b++; + else + return GPG_ERR_NOT_IMPLEMENTED; + + if (!mpi_is_opaque (input)) + return GPG_ERR_INV_DATA; + + /* Initialize some helpers. */ + point_init (&I); + a = mpi_snew (0); + x = mpi_new (0); + y = mpi_new (0); + r = mpi_snew (0); + + rc = _gcry_ecc_eddsa_compute_h_d (&digest, ec); + if (rc) + goto leave; + _gcry_mpi_set_buffer (a, digest, b, 0); + + /* Compute the public key if it's not available (only secret part). */ + if (ec->Q == NULL) + { + mpi_point_struct Q; + + point_init (&Q); + _gcry_mpi_ec_mul_point (&Q, a, ec->G, ec); + ec->Q = mpi_point_snatch_set (NULL, Q.x, Q.y, Q.z); + } + rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, x, y, 0, &encpk, &encpklen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex (" e_pk", encpk, encpklen); + + /* Compute R. */ + mbuf = mpi_get_opaque (input, &tmp); + mlen = (tmp +7)/8; + if (DBG_CIPHER) + log_printhex (" m", mbuf, mlen); + + if (ctx->hash_algo == GCRY_MD_SHAKE256) + { + gcry_error_t err; + gcry_md_hd_t hd; + + err = _gcry_md_open (&hd, ctx->hash_algo, 0); + if (err) + rc = gcry_err_code (err); + else + { + _gcry_md_write (hd, DOM448, DOM448_LEN); + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + _gcry_md_write (hd, x_olen, 2); + if (ctx->labellen) + _gcry_md_write (hd, ctx->label, ctx->labellen); + _gcry_md_write (hd, digest+b, b); + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + gcry_md_hd_t hd2; + + err = _gcry_md_open (&hd2, ctx->hash_algo, 0); + if (err) + { + rc = gcry_err_code (err); + _gcry_md_close (hd); + goto leave; + } + _gcry_md_write (hd2, mbuf, mlen); + _gcry_md_ctl (hd2, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_extract (hd2, GCRY_MD_SHAKE256, prehashed_msg, 64); + _gcry_md_close (hd2); + _gcry_md_write (hd, prehashed_msg, 64); + } + else + _gcry_md_write (hd, mbuf, mlen); + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); + _gcry_md_close (hd); + rc = 0; + } + } + else + { + gcry_buffer_t hvec[6]; + int i = 0; + + memset (hvec, 0, sizeof hvec); + + if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen) + { + hvec[i].data = (void *)DOM25519; + hvec[i].len = DOM25519_LEN; + i++; + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + hvec[i].data = x_olen; + hvec[i].len = 2; + i++; + if (ctx->labellen) + { + hvec[i].data = ctx->label; + hvec[i].len = ctx->labellen; + i++; + } + } + + hvec[i].data = digest; + hvec[i].off = b; + hvec[i].len = b; + i++; + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + _gcry_md_hash_buffer (ctx->hash_algo, prehashed_msg, mbuf, mlen); + hvec[i].data = (char*)prehashed_msg; + hvec[i].len = 64; + } + else + { + hvec[i].data = (char*)mbuf; + hvec[i].len = mlen; + } + i++; + rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i); + } + + if (rc) + goto leave; + reverse_buffer (digest, 2*b); + if (DBG_CIPHER) + log_printhex (" r", digest, 2*b); + _gcry_mpi_set_buffer (r, digest, 2*b, 0); + mpi_mod (r, r, ec->n); + _gcry_mpi_ec_mul_point (&I, r, ec->G, ec); + if (DBG_CIPHER) + log_printpnt (" r", &I, ec); + + /* Convert R into affine coordinates and apply encoding. */ + rc = _gcry_ecc_eddsa_encodepoint (&I, ec, x, y, 0, &rawmpi, &rawmpilen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex (" e_r", rawmpi, rawmpilen); + + if (ctx->hash_algo == GCRY_MD_SHAKE256) + { + gcry_error_t err; + gcry_md_hd_t hd; + + err = _gcry_md_open (&hd, ctx->hash_algo, 0); + if (err) + rc = gcry_err_code (err); + else + { + _gcry_md_write (hd, DOM448, DOM448_LEN); + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + _gcry_md_write (hd, x_olen, 2); + if (ctx->labellen) + _gcry_md_write (hd, ctx->label, ctx->labellen); + _gcry_md_write (hd, rawmpi, rawmpilen); + _gcry_md_write (hd, encpk, encpklen); + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + _gcry_md_write (hd, prehashed_msg, 64); + else + _gcry_md_write (hd, mbuf, mlen); + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); + _gcry_md_close (hd); + rc = 0; + } + } + else + { + gcry_buffer_t hvec[6]; + int i = 0; + + memset (hvec, 0, sizeof hvec); + + if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen) + { + hvec[i].data = (void *)DOM25519; + hvec[i].len = DOM25519_LEN; + i++; + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + hvec[i].data = x_olen; + hvec[i].len = 2; + i++; + if (ctx->labellen) + { + hvec[i].data = ctx->label; + hvec[i].len = ctx->labellen; + i++; + } + } + + /* S = r + a * H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) mod n */ + hvec[i].data = rawmpi; /* (this is R) */ + hvec[i].len = rawmpilen; + i++; + hvec[i].data = encpk; + hvec[i].len = encpklen; + i++; + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + hvec[i].data = (char*)prehashed_msg; + hvec[i].len = 64; + } + else + { + hvec[i].data = (char*)mbuf; + hvec[i].len = mlen; + } + i++; + rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i); + } + + if (rc) + goto leave; + + /* No more need for RAWMPI thus we now transfer it to R_R. */ + mpi_set_opaque (r_r, rawmpi, rawmpilen*8); + rawmpi = NULL; + + reverse_buffer (digest, 2*b); + if (DBG_CIPHER) + log_printhex (" H(R+)", digest, 2*b); + _gcry_mpi_set_buffer (s, digest, 2*b, 0); + mpi_mulm (s, s, a, ec->n); + mpi_addm (s, s, r, ec->n); + rc = eddsa_encodempi (s, ec->nbits, &rawmpi, &rawmpilen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex (" e_s", rawmpi, rawmpilen); + mpi_set_opaque (s, rawmpi, rawmpilen*8); + rawmpi = NULL; + + rc = 0; + + leave: + _gcry_mpi_release (a); + _gcry_mpi_release (x); + _gcry_mpi_release (y); + _gcry_mpi_release (r); + xfree (digest); + point_free (&I); + xfree (encpk); + xfree (rawmpi); + return rc; +} + + +/* Verify an EdDSA signature. See sign_eddsa for the reference. + * Check if R_IN and S_IN verifies INPUT. + */ +gpg_err_code_t +_gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r_in, gcry_mpi_t s_in, + struct pk_encoding_ctx *ctx) +{ + int rc; + int b; + unsigned int tmp; + unsigned char *encpk = NULL; /* Encoded public key. */ + unsigned int encpklen; + const void *mbuf, *rbuf; + unsigned char *tbuf = NULL; + size_t mlen, rlen; + unsigned int tlen; + unsigned char digest[114]; + gcry_mpi_t h, s; + mpi_point_struct Ia, Ib; + unsigned char x_olen[2]; + unsigned char prehashed_msg[64]; + + if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in)) + return GPG_ERR_INV_DATA; + + point_init (&Ia); + point_init (&Ib); + h = mpi_new (0); + s = mpi_new (0); + + b = (ec->nbits+7)/8; + + if (ec->nbits == 255) + ; + else if (ec->nbits == 448) + b++; + else + return GPG_ERR_NOT_IMPLEMENTED; + + /* Encode and check the public key. */ + rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, + &encpk, &encpklen); + if (rc) + goto leave; + if (!_gcry_mpi_ec_curve_point (ec->Q, ec)) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + if (DBG_CIPHER) + log_printhex (" e_pk", encpk, encpklen); + if (encpklen != b) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + + /* Convert the other input parameters. */ + mbuf = mpi_get_opaque (input, &tmp); + mlen = (tmp +7)/8; + if (DBG_CIPHER) + log_printhex (" m", mbuf, mlen); + rbuf = mpi_get_opaque (r_in, &tmp); + rlen = (tmp +7)/8; + if (DBG_CIPHER) + log_printhex (" r", rbuf, rlen); + if (rlen != b) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + + if (ctx->hash_algo == GCRY_MD_SHAKE256) + { + gcry_error_t err; + gcry_md_hd_t hd; + + err = _gcry_md_open (&hd, ctx->hash_algo, 0); + if (err) + rc = gcry_err_code (err); + else + { + _gcry_md_write (hd, DOM448, DOM448_LEN); + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + _gcry_md_write (hd, x_olen, 2); + if (ctx->labellen) + _gcry_md_write (hd, ctx->label, ctx->labellen); + _gcry_md_write (hd, rbuf, rlen); + _gcry_md_write (hd, encpk, encpklen); + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + gcry_md_hd_t hd2; + + err = _gcry_md_open (&hd2, ctx->hash_algo, 0); + if (err) + { + rc = gcry_err_code (err); + _gcry_md_close (hd); + goto leave; + } + _gcry_md_write (hd2, mbuf, mlen); + _gcry_md_ctl (hd2, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_extract (hd2, GCRY_MD_SHAKE256, prehashed_msg, 64); + _gcry_md_close (hd2); + _gcry_md_write (hd, prehashed_msg, 64); + } + else + _gcry_md_write (hd, mbuf, mlen); + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); + _gcry_md_close (hd); + rc = 0; + } + } + else + { + gcry_buffer_t hvec[6]; + int i = 0; + + memset (hvec, 0, sizeof hvec); + + /* h = H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) */ + if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen) + { + hvec[i].data = (void *)DOM25519; + hvec[i].len = DOM25519_LEN; + i++; + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + hvec[i].data = x_olen; + hvec[i].len = 2; + i++; + if (ctx->labellen) + { + hvec[i].data = ctx->label; + hvec[i].len = ctx->labellen; + i++; + } + } + + hvec[i].data = (char*)rbuf; + hvec[i].len = rlen; + i++; + hvec[i].data = encpk; + hvec[i].len = encpklen; + i++; + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + _gcry_md_hash_buffer (ctx->hash_algo, prehashed_msg, mbuf, mlen); + hvec[i].data = (char*)prehashed_msg; + hvec[i].len = 64; + } + else + { + hvec[i].data = (char*)mbuf; + hvec[i].len = mlen; + } + i++; + rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i); + } + + if (rc) + goto leave; + reverse_buffer (digest, 2*b); + if (DBG_CIPHER) + log_printhex (" H(R+)", digest, 2*b); + _gcry_mpi_set_buffer (h, digest, 2*b, 0); + + /* According to the paper the best way for verification is: + encodepoint(sG - h·Q) = encodepoint(r) + because we don't need to decode R. */ + { + void *sbuf; + unsigned int slen; + + sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp); + slen = (tmp +7)/8; + reverse_buffer (sbuf, slen); + if (DBG_CIPHER) + log_printhex (" s", sbuf, slen); + _gcry_mpi_set_buffer (s, sbuf, slen, 0); + xfree (sbuf); + if (slen != b) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + } + + _gcry_mpi_ec_mul_point (&Ia, s, ec->G, ec); + _gcry_mpi_ec_mul_point (&Ib, h, ec->Q, ec); + _gcry_mpi_sub (Ib.x, ec->p, Ib.x); + _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ec); + rc = _gcry_ecc_eddsa_encodepoint (&Ia, ec, s, h, 0, &tbuf, &tlen); + if (rc) + goto leave; + if (tlen != rlen || memcmp (tbuf, rbuf, tlen)) + { + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + rc = 0; + + leave: + xfree (encpk); + xfree (tbuf); + _gcry_mpi_release (s); + _gcry_mpi_release (h); + point_free (&Ia); + point_free (&Ib); + return rc; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc-gost.c b/comm/third_party/libgcrypt/cipher/ecc-gost.c new file mode 100644 index 0000000000..36230f8a32 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-gost.c @@ -0,0 +1,218 @@ +/* ecc-gots.c - Elliptic Curve GOST signatures + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" +#include "pubkey-internal.h" + + +/* Compute an GOST R 34.10-01/-12 signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +gpg_err_code_t +_gcry_ecc_gost_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t rc = 0; + gcry_mpi_t k, dr, sum, ke, x, e; + mpi_point_struct I; + gcry_mpi_t hash; + unsigned int qbits; + + if (DBG_CIPHER) + log_mpidump ("gost sign hash ", input ); + + qbits = mpi_get_nbits (ec->n); + + /* Convert the INPUT into an MPI if needed. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + k = NULL; + dr = mpi_alloc (0); + sum = mpi_alloc (0); + ke = mpi_alloc (0); + e = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&I); + + mpi_mod (e, input, ec->n); /* e = hash mod n */ + + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + + /* Two loops to avoid R or S are zero. This is more of a joke than + a real demand because the probability of them being zero is less + than any hardware failure. Some specs however require it. */ + do + { + do + { + mpi_free (k); + k = _gcry_dsa_gen_k (ec->n, GCRY_STRONG_RANDOM); + + _gcry_dsa_modify_k (k, ec->n, qbits); + + _gcry_mpi_ec_mul_point (&I, k, ec->G, ec); + if (_gcry_mpi_ec_get_affine (x, NULL, &I, ec)) + { + if (DBG_CIPHER) + log_debug ("ecc sign: Failed to get affine coordinates\n"); + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (r, x, ec->n); /* r = x mod n */ + } + while (!mpi_cmp_ui (r, 0)); + mpi_mulm (dr, ec->d, r, ec->n); /* dr = d*r mod n */ + mpi_mulm (ke, k, e, ec->n); /* ke = k*e mod n */ + mpi_addm (s, ke, dr, ec->n); /* sum = (k*e+ d*r) mod n */ + } + while (!mpi_cmp_ui (s, 0)); + + if (DBG_CIPHER) + { + log_mpidump ("gost sign result r ", r); + log_mpidump ("gost sign result s ", s); + } + + leave: + point_free (&I); + mpi_free (x); + mpi_free (e); + mpi_free (ke); + mpi_free (sum); + mpi_free (dr); + mpi_free (k); + + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/* Verify a GOST R 34.10-01/-12 signature. + * Check if R and S verifies INPUT. + */ +gpg_err_code_t +_gcry_ecc_gost_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t e, x, z1, z2, v, rv, zero; + mpi_point_struct Q, Q1, Q2; + + if (!_gcry_mpi_ec_curve_point (ec->Q, ec)) + return GPG_ERR_BROKEN_PUBKEY; + + if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, ec->n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, ec->n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + x = mpi_alloc (0); + e = mpi_alloc (0); + z1 = mpi_alloc (0); + z2 = mpi_alloc (0); + v = mpi_alloc (0); + rv = mpi_alloc (0); + zero = mpi_alloc (0); + + point_init (&Q); + point_init (&Q1); + point_init (&Q2); + + mpi_mod (e, input, ec->n); /* e = hash mod n */ + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + mpi_invm (v, e, ec->n); /* v = e^(-1) (mod n) */ + mpi_mulm (z1, s, v, ec->n); /* z1 = s*v (mod n) */ + mpi_mulm (rv, r, v, ec->n); /* rv = r*v (mod n) */ + mpi_subm (z2, zero, rv, ec->n); /* z2 = -r*v (mod n) */ + + _gcry_mpi_ec_mul_point (&Q1, z1, ec->G, ec); +/* log_mpidump ("Q1.x", Q1.x); */ +/* log_mpidump ("Q1.y", Q1.y); */ +/* log_mpidump ("Q1.z", Q1.z); */ + _gcry_mpi_ec_mul_point (&Q2, z2, ec->Q, ec); +/* log_mpidump ("Q2.x", Q2.x); */ +/* log_mpidump ("Q2.y", Q2.y); */ +/* log_mpidump ("Q2.z", Q2.z); */ + _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ec); +/* log_mpidump (" Q.x", Q.x); */ +/* log_mpidump (" Q.y", Q.y); */ +/* log_mpidump (" Q.z", Q.z); */ + + if (!mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Rejected\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ec)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (x, x, ec->n); /* x = x mod E_n */ + if (mpi_cmp (x, r)) /* x != r */ + { + if (DBG_CIPHER) + { + log_mpidump (" x", x); + log_mpidump (" r", r); + log_mpidump (" s", s); + log_debug ("ecc verify: Not verified\n"); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (DBG_CIPHER) + log_debug ("ecc verify: Accepted\n"); + + leave: + point_free (&Q2); + point_free (&Q1); + point_free (&Q); + mpi_free (zero); + mpi_free (rv); + mpi_free (v); + mpi_free (z2); + mpi_free (z1); + mpi_free (x); + mpi_free (e); + return err; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc-misc.c b/comm/third_party/libgcrypt/cipher/ecc-misc.c new file mode 100644 index 0000000000..6470a83bf4 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-misc.c @@ -0,0 +1,438 @@ +/* ecc-misc.c - Elliptic Curve miscellaneous functions + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" + + +/* + * Release a curve object. + */ +void +_gcry_ecc_curve_free (elliptic_curve_t *E) +{ + mpi_free (E->p); E->p = NULL; + mpi_free (E->a); E->a = NULL; + mpi_free (E->b); E->b = NULL; + _gcry_mpi_point_free_parts (&E->G); + mpi_free (E->n); E->n = NULL; +} + + +/* + * Return a copy of a curve object. + */ +elliptic_curve_t +_gcry_ecc_curve_copy (elliptic_curve_t E) +{ + elliptic_curve_t R; + + R.model = E.model; + R.dialect = E.dialect; + R.name = E.name; + R.p = mpi_copy (E.p); + R.a = mpi_copy (E.a); + R.b = mpi_copy (E.b); + _gcry_mpi_point_init (&R.G); + point_set (&R.G, &E.G); + R.n = mpi_copy (E.n); + R.h = E.h; + + return R; +} + + +/* + * Return a description of the curve model. + */ +const char * +_gcry_ecc_model2str (enum gcry_mpi_ec_models model) +{ + const char *str = "?"; + switch (model) + { + case MPI_EC_WEIERSTRASS: str = "Weierstrass"; break; + case MPI_EC_MONTGOMERY: str = "Montgomery"; break; + case MPI_EC_EDWARDS: str = "Edwards"; break; + } + return str; +} + + +/* + * Return a description of the curve dialect. + */ +const char * +_gcry_ecc_dialect2str (enum ecc_dialects dialect) +{ + const char *str = "?"; + switch (dialect) + { + case ECC_DIALECT_STANDARD: str = "Standard"; break; + case ECC_DIALECT_ED25519: str = "Ed25519"; break; + case ECC_DIALECT_SAFECURVE: str = "SafeCurve"; break; + } + return str; +} + + +gcry_mpi_t +_gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p) +{ + gpg_err_code_t rc; + int pbytes = (mpi_get_nbits (p)+7)/8; + size_t n; + unsigned char *buf, *ptr; + + buf = xmalloc ( 1 + 2*pbytes ); + *buf = 04; /* Uncompressed point. */ + ptr = buf+1; + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x); + if (rc) + log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc)); + if (n < pbytes) + { + memmove (ptr+(pbytes-n), ptr, n); + memset (ptr, 0, (pbytes-n)); + } + ptr += pbytes; + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y); + if (rc) + log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc)); + if (n < pbytes) + { + memmove (ptr+(pbytes-n), ptr, n); + memset (ptr, 0, (pbytes-n)); + } + + return mpi_set_opaque (NULL, buf, (1+2*pbytes)*8); +} + + +/* Convert POINT into affine coordinates using the context CTX and + return a newly allocated MPI. If the conversion is not possible + NULL is returned. This function won't print an error message. */ +gcry_mpi_t +_gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ec) +{ + gcry_mpi_t g_x, g_y, result; + + g_x = mpi_new (0); + g_y = mpi_new (0); + if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ec)) + result = NULL; + else + result = _gcry_ecc_ec2os (g_x, g_y, ec->p); + mpi_free (g_x); + mpi_free (g_y); + + return result; +} + + +/* Decode octet string in VALUE into RESULT, in the format defined by SEC 1. + RESULT must have been initialized and is set on success to the + point given by VALUE. */ +gpg_err_code_t +_gcry_ecc_sec_decodepoint (gcry_mpi_t value, mpi_ec_t ec, mpi_point_t result) +{ + gpg_err_code_t rc; + size_t n; + const unsigned char *buf; + unsigned char *buf_memory; + gcry_mpi_t x, y; + + if (mpi_is_opaque (value)) + { + unsigned int nbits; + + buf = mpi_get_opaque (value, &nbits); + if (!buf) + return GPG_ERR_INV_OBJ; + n = (nbits + 7)/8; + buf_memory = NULL; + } + else + { + n = (mpi_get_nbits (value)+7)/8; + buf_memory = xmalloc (n); + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value); + if (rc) + { + xfree (buf_memory); + return rc; + } + buf = buf_memory; + } + + if (n < 1) + { + xfree (buf_memory); + return GPG_ERR_INV_OBJ; + } + + if (*buf == 2 || *buf == 3) + { + gcry_mpi_t x3; + gcry_mpi_t t; + gcry_mpi_t p1_4; + int y_bit = (*buf == 3); + + if (!mpi_test_bit (ec->p, 1)) + { + xfree (buf_memory); + return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ + } + + n = n - 1; + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); + xfree (buf_memory); + if (rc) + return rc; + + /* + * Recover Y. The Weierstrass curve: y^2 = x^3 + a*x + b + */ + + x3 = mpi_new (0); + t = mpi_new (0); + p1_4 = mpi_new (0); + y = mpi_new (0); + + /* Compute right hand side. */ + mpi_powm (x3, x, mpi_const (MPI_C_THREE), ec->p); + mpi_mul (t, ec->a, x); + mpi_mod (t, t, ec->p); + mpi_add (t, t, ec->b); + mpi_mod (t, t, ec->p); + mpi_add (t, t, x3); + mpi_mod (t, t, ec->p); + + /* + * When p mod 4 = 3, modular square root of A can be computed by + * A^((p+1)/4) mod p + */ + + /* Compute (p+1)/4 into p1_4 */ + mpi_rshift (p1_4, ec->p, 2); + _gcry_mpi_add_ui (p1_4, p1_4, 1); + + mpi_powm (y, t, p1_4, ec->p); + + if (y_bit != mpi_test_bit (y, 0)) + mpi_sub (y, ec->p, y); + + mpi_free (p1_4); + mpi_free (t); + mpi_free (x3); + } + else if (*buf == 4) + { + if ( ((n-1)%2) ) + { + xfree (buf_memory); + return GPG_ERR_INV_OBJ; + } + n = (n-1)/2; + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); + if (rc) + { + xfree (buf_memory); + return rc; + } + rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); + xfree (buf_memory); + if (rc) + { + mpi_free (x); + return rc; + } + } + else + { + xfree (buf_memory); + return GPG_ERR_INV_OBJ; + } + + mpi_set (result->x, x); + mpi_set (result->y, y); + mpi_set_ui (result->z, 1); + + mpi_free (x); + mpi_free (y); + + return 0; +} + + +/* Compute the public key from the the context EC. Obviously a + requirement is that the secret key is available in EC. On success + Q is returned; on error NULL. If Q is NULL a newly allocated point + is returned. If G or D are given they override the values taken + from EC. */ +mpi_point_t +_gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec) +{ + if (!ec->d || !ec->G || !ec->p || !ec->a) + return NULL; + if (ec->model == MPI_EC_EDWARDS && !ec->b) + return NULL; + + if ((ec->dialect == ECC_DIALECT_ED25519 && (ec->flags & PUBKEY_FLAG_EDDSA)) + || (ec->model == MPI_EC_EDWARDS && ec->dialect == ECC_DIALECT_SAFECURVE)) + { + gcry_mpi_t a; + unsigned char *digest; + + if (_gcry_ecc_eddsa_compute_h_d (&digest, ec)) + return NULL; + + a = mpi_snew (0); + _gcry_mpi_set_buffer (a, digest, 32, 0); + xfree (digest); + + /* And finally the public key. */ + if (!Q) + Q = mpi_point_new (0); + if (Q) + _gcry_mpi_ec_mul_point (Q, a, ec->G, ec); + mpi_free (a); + } + else + { + if (!Q) + Q = mpi_point_new (0); + if (Q) + _gcry_mpi_ec_mul_point (Q, ec->d, ec->G, ec); + } + + return Q; +} + + +gpg_err_code_t +_gcry_ecc_mont_encodepoint (gcry_mpi_t x, unsigned int nbits, + int with_prefix, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + unsigned char *rawmpi; + unsigned int rawmpilen; + + rawmpi = _gcry_mpi_get_buffer_extra (x, (nbits+7)/8, + with_prefix? -1 : 0, &rawmpilen, NULL); + if (rawmpi == NULL) + return gpg_err_code_from_syserror (); + + if (with_prefix) + { + rawmpi[0] = 0x40; + rawmpilen++; + } + + *r_buffer = rawmpi; + *r_buflen = rawmpilen; + return 0; +} + + +gpg_err_code_t +_gcry_ecc_mont_decodepoint (gcry_mpi_t pk, mpi_ec_t ec, mpi_point_t result) +{ + unsigned char *rawmpi; + unsigned int rawmpilen; + unsigned int nbytes = (ec->nbits+7)/8; + + /* + * It is not reliable to assume that the first byte of 0x40 + * means the prefix. + * + * For newer implementation, it is reliable since we always put + * 0x40 for x-only coordinate. + * + * For data by older implementation (non-released development + * version in 2015), there is no 0x40 prefix added. + * + * So, it is possible to have shorter length of data when it was + * handled as MPI, removing preceding zeros. + * + * Besides, when data was parsed as MPI, we might have 0x00 + * prefix (when the MSB in the first byte is set). + */ + + if (mpi_is_opaque (pk)) + { + const unsigned char *buf; + unsigned char *p; + + buf = mpi_get_opaque (pk, &rawmpilen); + if (!buf) + return GPG_ERR_INV_OBJ; + rawmpilen = (rawmpilen + 7)/8; + + if (rawmpilen > nbytes + && (buf[0] == 0x00 || buf[0] == 0x40)) + { + rawmpilen--; + buf++; + } + + rawmpi = xtrymalloc (nbytes); + if (!rawmpi) + return gpg_err_code_from_syserror (); + + p = rawmpi + rawmpilen; + while (p > rawmpi) + *--p = *buf++; + + if (rawmpilen < nbytes) + memset (rawmpi + nbytes - rawmpilen, 0, nbytes - rawmpilen); + } + else + { + rawmpi = _gcry_mpi_get_buffer (pk, nbytes, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + /* + * When we have the prefix (0x40 or 0x00), it comes at the end, + * since it is taken by _gcry_mpi_get_buffer with little endian. + * Just setting RAWMPILEN to NBYTES is enough in this case. + * Othewise, RAWMPILEN is NBYTES already. + */ + rawmpilen = nbytes; + } + + if ((ec->nbits % 8)) + rawmpi[0] &= (1 << (ec->nbits % 8)) - 1; + _gcry_mpi_set_buffer (result->x, rawmpi, rawmpilen, 0); + xfree (rawmpi); + mpi_set_ui (result->z, 1); + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc-sm2.c b/comm/third_party/libgcrypt/cipher/ecc-sm2.c new file mode 100644 index 0000000000..c52629fd3f --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc-sm2.c @@ -0,0 +1,569 @@ +/* ecc-sm2.c - Elliptic Curve SM2 implementation + * Copyright (C) 2020 Tianjia Zhang + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "bithelp.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" + +#define MPI_NBYTES(m) ((mpi_get_nbits(m) + 7) / 8) + + +/* Key derivation function from X9.63/SECG */ +static gpg_err_code_t +kdf_x9_63 (int algo, const void *in, size_t inlen, void *out, size_t outlen) +{ + gpg_err_code_t rc; + gcry_md_hd_t hd; + int mdlen; + u32 counter = 1; + u32 counter_be; + unsigned char *dgst; + unsigned char *pout = out; + size_t rlen = outlen; + size_t len; + + rc = _gcry_md_open (&hd, algo, 0); + if (rc) + return rc; + + mdlen = _gcry_md_get_algo_dlen (algo); + + while (rlen > 0) + { + counter_be = be_bswap32 (counter); /* cpu_to_be32 */ + counter++; + + _gcry_md_write (hd, in, inlen); + _gcry_md_write (hd, &counter_be, sizeof(counter_be)); + + dgst = _gcry_md_read (hd, algo); + if (dgst == NULL) + { + rc = GPG_ERR_DIGEST_ALGO; + break; + } + + len = mdlen < rlen ? mdlen : rlen; /* min(mdlen, rlen) */ + memcpy (pout, dgst, len); + rlen -= len; + pout += len; + + _gcry_md_reset (hd); + } + + _gcry_md_close (hd); + return rc; +} + + +/* _gcry_ecc_sm2_encrypt description: + * input: + * data[0] : octet string + * output: A new S-expression with the parameters: + * a: c1 : generated ephemeral public key (kG) + * b: c3 : Hash(x2 || IN || y2) + * c: c2 : cipher + * + * sm2_decrypt description: + * in contrast to encrypt + */ +gpg_err_code_t +_gcry_ecc_sm2_encrypt (gcry_sexp_t *r_ciph, gcry_mpi_t input, mpi_ec_t ec) +{ + gpg_err_code_t rc; + const int algo = GCRY_MD_SM3; + gcry_md_hd_t md = NULL; + int mdlen; + unsigned char *dgst; + gcry_mpi_t k = NULL; + mpi_point_struct kG, kP; + gcry_mpi_t x1, y1; + gcry_mpi_t x2, y2; + gcry_mpi_t x2y2 = NULL; + unsigned char *in = NULL; + unsigned int inlen; + unsigned char *raw; + unsigned int rawlen; + unsigned char *cipher = NULL; + int i; + + point_init (&kG); + point_init (&kP); + x1 = mpi_new (0); + y1 = mpi_new (0); + x2 = mpi_new (0); + y2 = mpi_new (0); + + in = _gcry_mpi_get_buffer (input, 0, &inlen, NULL); + if (!in) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + + cipher = xtrymalloc (inlen); + if (!cipher) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + + /* rand k in [1, n-1] */ + k = _gcry_dsa_gen_k (ec->n, GCRY_VERY_STRONG_RANDOM); + + /* [k]G = (x1, y1) */ + _gcry_mpi_ec_mul_point (&kG, k, ec->G, ec); + if (_gcry_mpi_ec_get_affine (x1, y1, &kG, ec)) + { + if (DBG_CIPHER) + log_debug ("Bad check: kG can not be a Point at Infinity!\n"); + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* [k]P = (x2, y2) */ + _gcry_mpi_ec_mul_point (&kP, k, ec->Q, ec); + if (_gcry_mpi_ec_get_affine (x2, y2, &kP, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* t = KDF(x2 || y2, klen) */ + x2y2 = _gcry_mpi_ec_ec2os (&kP, ec); + raw = mpi_get_opaque (x2y2, &rawlen); + rawlen = (rawlen + 7) / 8; + + /* skip the prefix '0x04' */ + raw += 1; + rawlen -= 1; + rc = kdf_x9_63 (algo, raw, rawlen, cipher, inlen); + if (rc) + goto leave; + + /* cipher = t xor in */ + for (i = 0; i < inlen; i++) + cipher[i] ^= in[i]; + + /* hash(x2 || IN || y2) */ + mdlen = _gcry_md_get_algo_dlen (algo); + rc = _gcry_md_open (&md, algo, 0); + if (rc) + goto leave; + _gcry_md_write (md, raw, MPI_NBYTES(x2)); + _gcry_md_write (md, in, inlen); + _gcry_md_write (md, raw + MPI_NBYTES(x2), MPI_NBYTES(y2)); + dgst = _gcry_md_read (md, algo); + if (dgst == NULL) + { + rc = GPG_ERR_DIGEST_ALGO; + goto leave; + } + + if (!rc) + { + gcry_mpi_t c1; + gcry_mpi_t c3; + gcry_mpi_t c2; + + c3 = mpi_new (0); + c2 = mpi_new (0); + + c1 = _gcry_ecc_ec2os (x1, y1, ec->p); + _gcry_mpi_set_opaque_copy (c3, dgst, mdlen * 8); + _gcry_mpi_set_opaque_copy (c2, cipher, inlen * 8); + + rc = sexp_build (r_ciph, NULL, + "(enc-val(flags sm2)(sm2(a%M)(b%M)(c%M)))", + c1, c3, c2); + + mpi_free (c1); + mpi_free (c3); + mpi_free (c2); + } + +leave: + _gcry_md_close (md); + mpi_free (x2y2); + mpi_free (k); + + point_free (&kG); + point_free (&kP); + mpi_free (x1); + mpi_free (y1); + mpi_free (x2); + mpi_free (y2); + + xfree (cipher); + xfree (in); + + return rc; +} + + +gpg_err_code_t +_gcry_ecc_sm2_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t data_list, mpi_ec_t ec) +{ + gpg_err_code_t rc; + gcry_mpi_t data_c1 = NULL; + gcry_mpi_t data_c3 = NULL; + gcry_mpi_t data_c2 = NULL; + + /* + * Extract the data. + */ + rc = sexp_extract_param (data_list, NULL, "/a/b/c", + &data_c1, &data_c3, &data_c2, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_printmpi ("ecc_decrypt d_c1", data_c1); + log_printmpi ("ecc_decrypt d_c3", data_c3); + log_printmpi ("ecc_decrypt d_c2", data_c2); + } + + { + const int algo = GCRY_MD_SM3; + gcry_md_hd_t md = NULL; + int mdlen; + unsigned char *dgst; + mpi_point_struct c1; + mpi_point_struct kP; + gcry_mpi_t x2, y2; + gcry_mpi_t x2y2 = NULL; + unsigned char *in = NULL; + unsigned int inlen; + unsigned char *plain = NULL; + unsigned char *raw; + unsigned int rawlen; + unsigned char *c3 = NULL; + unsigned int c3_len; + int i; + + point_init (&c1); + point_init (&kP); + x2 = mpi_new (0); + y2 = mpi_new (0); + + in = mpi_get_opaque (data_c2, &inlen); + inlen = (inlen + 7) / 8; + plain = xtrymalloc (inlen); + if (!plain) + { + rc = gpg_err_code_from_syserror (); + goto leave_main; + } + + rc = _gcry_ecc_sec_decodepoint (data_c1, ec, &c1); + if (rc) + goto leave_main; + + if (!_gcry_mpi_ec_curve_point (&c1, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave_main; + } + + /* [d]C1 = (x2, y2), C1 = [k]G */ + _gcry_mpi_ec_mul_point (&kP, ec->d, &c1, ec); + if (_gcry_mpi_ec_get_affine (x2, y2, &kP, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave_main; + } + + /* t = KDF(x2 || y2, inlen) */ + x2y2 = _gcry_mpi_ec_ec2os (&kP, ec); + raw = mpi_get_opaque (x2y2, &rawlen); + rawlen = (rawlen + 7) / 8; + /* skip the prefix '0x04' */ + raw += 1; + rawlen -= 1; + rc = kdf_x9_63 (algo, raw, rawlen, plain, inlen); + if (rc) + goto leave_main; + + /* plain = C2 xor t */ + for (i = 0; i < inlen; i++) + plain[i] ^= in[i]; + + /* Hash(x2 || IN || y2) == C3 */ + mdlen = _gcry_md_get_algo_dlen (algo); + rc = _gcry_md_open (&md, algo, 0); + if (rc) + goto leave_main; + _gcry_md_write (md, raw, MPI_NBYTES(x2)); + _gcry_md_write (md, plain, inlen); + _gcry_md_write (md, raw + MPI_NBYTES(x2), MPI_NBYTES(y2)); + dgst = _gcry_md_read (md, algo); + if (dgst == NULL) + { + memset (plain, 0, inlen); + rc = GPG_ERR_DIGEST_ALGO; + goto leave_main; + } + c3 = mpi_get_opaque (data_c3, &c3_len); + c3_len = (c3_len + 7) / 8; + if (c3_len != mdlen || memcmp (dgst, c3, c3_len) != 0) + { + memset (plain, 0, inlen); + rc = GPG_ERR_INV_DATA; + goto leave_main; + } + + if (!rc) + { + gcry_mpi_t r; + + r = mpi_new (inlen * 8); + _gcry_mpi_set_buffer (r, plain, inlen, 0); + + rc = sexp_build (r_plain, NULL, "(value %m)", r); + + mpi_free (r); + } + + leave_main: + _gcry_md_close (md); + mpi_free (x2y2); + xfree (plain); + + point_free (&c1); + point_free (&kP); + mpi_free (x2); + mpi_free (y2); + } + + leave: + _gcry_mpi_release (data_c1); + _gcry_mpi_release (data_c3); + _gcry_mpi_release (data_c2); + + return rc; +} + + +/* Compute an SM2 signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +gpg_err_code_t +_gcry_ecc_sm2_sign (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s, + int flags, int hashalgo) +{ + gpg_err_code_t rc = 0; + int extraloops = 0; + gcry_mpi_t hash; + const void *abuf; + unsigned int abits, qbits; + gcry_mpi_t tmp = NULL; + gcry_mpi_t k = NULL; + gcry_mpi_t rk = NULL; + mpi_point_struct kG; + gcry_mpi_t x1; + + if (DBG_CIPHER) + log_mpidump ("sm2 sign hash ", input); + + qbits = mpi_get_nbits (ec->n); + + /* Convert the INPUT into an MPI if needed. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + point_init (&kG); + x1 = mpi_new (0); + rk = mpi_new (0); + tmp = mpi_new (0); + + for (;;) + { + /* rand k in [1, n-1] */ + if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) + { + /* Use Pornin's method for deterministic DSA. If this + flag is set, it is expected that HASH is an opaque + MPI with the to be signed hash. That hash is also + used as h1 from 3.2.a. */ + if (!mpi_is_opaque (input)) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_dsa_gen_rfc6979_k (&k, ec->n, ec->d, + abuf, (abits+7)/8, + hashalgo, extraloops); + if (rc) + goto leave; + extraloops++; + } + else + k = _gcry_dsa_gen_k (ec->n, GCRY_VERY_STRONG_RANDOM); + + _gcry_dsa_modify_k (k, ec->n, qbits); + + /* [k]G = (x1, y1) */ + _gcry_mpi_ec_mul_point (&kG, k, ec->G, ec); + if (_gcry_mpi_ec_get_affine (x1, NULL, &kG, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* r = (e + x1) % n */ + mpi_addm (r, hash, x1, ec->n); + + /* r != 0 && r + k != n */ + if (mpi_cmp_ui (r, 0) == 0) + continue; + mpi_add (rk, r, k); + if (mpi_cmp (rk, ec->n) == 0) + continue; + + /* s = ((d + 1)^-1 * (k - rd)) % n */ + mpi_addm (s, ec->d, GCRYMPI_CONST_ONE, ec->n); + mpi_invm (s, s, ec->n); + mpi_mulm (tmp, r, ec->d, ec->n); + mpi_subm (tmp, k, tmp, ec->n); + mpi_mulm (s, s, tmp, ec->n); + + /* s != 0 */ + if (mpi_cmp_ui (s, 0) == 0) + continue; + + break; /* Okay */ + } + + if (DBG_CIPHER) + { + log_mpidump ("sm2 sign result r ", r); + log_mpidump ("sm2 sign result s ", s); + } + +leave: + point_free (&kG); + mpi_free (k); + mpi_free (x1); + mpi_free (rk); + mpi_free (tmp); + + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/* Verify an SM2 signature. + * Check if R and S verifies INPUT. + */ +gpg_err_code_t +_gcry_ecc_sm2_verify (gcry_mpi_t input, mpi_ec_t ec, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t hash = NULL; + gcry_mpi_t t = NULL; + mpi_point_struct sG, tP; + gcry_mpi_t x1, y1; + unsigned int nbits; + + if (!_gcry_mpi_ec_curve_point (ec->Q, ec)) + return GPG_ERR_BROKEN_PUBKEY; + + /* r, s within [1, n-1] */ + if (mpi_cmp_ui (r, 1) < 0 || mpi_cmp (r, ec->n) > 0) + return GPG_ERR_BAD_SIGNATURE; + if (mpi_cmp_ui (s, 1) < 0 || mpi_cmp (s, ec->n) > 0) + return GPG_ERR_BAD_SIGNATURE; + + nbits = mpi_get_nbits (ec->n); + err = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (err) + return err; + + point_init (&sG); + point_init (&tP); + x1 = mpi_new (0); + y1 = mpi_new (0); + t = mpi_new (0); + + /* t = (r + s) % n, t != 0 */ + mpi_addm (t, r, s, ec->n); + if (mpi_cmp_ui (t, 0) == 0) + { + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + /* sG + tP = (x1, y1) */ + _gcry_mpi_ec_mul_point (&sG, s, ec->G, ec); + _gcry_mpi_ec_mul_point (&tP, t, ec->Q, ec); + _gcry_mpi_ec_add_points (&sG, &sG, &tP, ec); + if (_gcry_mpi_ec_get_affine (x1, y1, &sG, ec)) + { + err = GPG_ERR_INV_DATA; + goto leave; + } + + /* R = (e + x1) % n */ + mpi_addm (t, hash, x1, ec->n); + + /* check R == r */ + if (mpi_cmp (t, r)) + { + if (DBG_CIPHER) + { + log_mpidump (" R", t); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (DBG_CIPHER) + log_debug ("sm2 verify: Accepted\n"); + + leave: + point_free (&sG); + point_free (&tP); + mpi_free (x1); + mpi_free (y1); + mpi_free (t); + if (hash != input) + mpi_free (hash); + + return err; +} diff --git a/comm/third_party/libgcrypt/cipher/ecc.c b/comm/third_party/libgcrypt/cipher/ecc.c new file mode 100644 index 0000000000..5d8c7607ab --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/ecc.c @@ -0,0 +1,1779 @@ +/* ecc.c - Elliptic Curve Cryptography + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013, 2015 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* This code is originally based on the Patch 0.1.6 for the gnupg + 1.4.x branch as retrieved on 2007-03-21 from + http://www.calcurco.cat/eccGnuPG/src/gnupg-1.4.6-ecc0.2.0beta1.diff.bz2 + The original authors are: + Written by + Sergi Blanch i Torne , + Ramiro Moreno Chiral + Maintainers + Sergi Blanch i Torne + Ramiro Moreno Chiral + Mikael Mylnikov (mmr) + For use in Libgcrypt the code has been heavily modified and cleaned + up. In fact there is not much left of the originally code except for + some variable names and the text book implementaion of the sign and + verification algorithms. The arithmetic functions have entirely + been rewritten and moved to mpi/ec.c. + + ECDH encrypt and decrypt code written by Andrey Jivsov. +*/ + + +/* TODO: + + - In mpi/ec.c we use mpi_powm for x^2 mod p: Either implement a + special case in mpi_powm or check whether mpi_mulm is faster. + +*/ + + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" + + +static const char *ecc_names[] = + { + "ecc", + "ecdsa", + "ecdh", + "eddsa", + "gost", + "sm2", + NULL, + }; + + +/* Sample NIST P-256 key from RFC 6979 A.2.5 */ +static const char sample_public_key_secp256[] = + "(public-key" + " (ecc" + " (curve secp256r1)" + " (q #04" + /**/ "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6" + /**/ "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299#)))"; + +static const char sample_secret_key_secp256[] = + "(private-key" + " (ecc" + " (curve secp256r1)" + " (d #C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721#)" + " (q #04" + /**/ "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6" + /**/ "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299#)))"; + + +/* Registered progress function and its callback value. */ +static void (*progress_cb) (void *, const char*, int, int, int); +static void *progress_cb_data; + + + +/* Local prototypes. */ +static void test_keys (mpi_ec_t ec, unsigned int nbits); +static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags); +static unsigned int ecc_get_nbits (gcry_sexp_t parms); + + + + +void +_gcry_register_pk_ecc_progress (void (*cb) (void *, const char *, + int, int, int), + void *cb_data) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + +/* static void */ +/* progress (int c) */ +/* { */ +/* if (progress_cb) */ +/* progress_cb (progress_cb_data, "pk_ecc", c, 0, 0); */ +/* } */ + + + +/** + * nist_generate_key - Standard version of the ECC key generation. + * @ec: Elliptic curve computation context. + * @flags: Flags controlling aspects of the creation. + * @r_x: On success this receives an allocated MPI with the affine + * x-coordinate of the poblic key. On error NULL is stored. + * @r_y: Ditto for the y-coordinate. + * + * Return: An error code. + * + * The @flags bits used by this function are %PUBKEY_FLAG_TRANSIENT to + * use a faster RNG, and %PUBKEY_FLAG_NO_KEYTEST to skip the assertion + * that the key works as expected. + * + * FIXME: Check whether N is needed. + */ +static gpg_err_code_t +nist_generate_key (mpi_ec_t ec, int flags, + gcry_mpi_t *r_x, gcry_mpi_t *r_y) +{ + mpi_point_struct Q; + gcry_random_level_t random_level; + gcry_mpi_t x, y; + const unsigned int pbits = ec->nbits; + + point_init (&Q); + + if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) + random_level = GCRY_STRONG_RANDOM; + else + random_level = GCRY_VERY_STRONG_RANDOM; + + /* Generate a secret. */ + if (ec->dialect == ECC_DIALECT_ED25519 + || ec->dialect == ECC_DIALECT_SAFECURVE + || (flags & PUBKEY_FLAG_DJB_TWEAK)) + { + char *rndbuf; + int len = (pbits+7)/8; + + rndbuf = _gcry_random_bytes_secure (len, random_level); + if (ec->dialect == ECC_DIALECT_SAFECURVE) + ec->d = mpi_set_opaque (NULL, rndbuf, len*8); + else + { + ec->d = mpi_snew (pbits); + if ((pbits % 8)) + rndbuf[0] &= (1 << (pbits % 8)) - 1; + rndbuf[0] |= (1 << ((pbits + 7) % 8)); + rndbuf[len-1] &= (256 - ec->h); + _gcry_mpi_set_buffer (ec->d, rndbuf, len, 0); + xfree (rndbuf); + } + } + else + ec->d = _gcry_dsa_gen_k (ec->n, random_level); + + /* Compute Q. */ + _gcry_mpi_ec_mul_point (&Q, ec->d, ec->G, ec); + + x = mpi_new (pbits); + if (r_y == NULL) + y = NULL; + else + y = mpi_new (pbits); + if (_gcry_mpi_ec_get_affine (x, y, &Q, ec)) + log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q"); + + /* We want the Q=(x,y) be a "compliant key" in terms of the + * http://tools.ietf.org/html/draft-jivsov-ecc-compact, which simply + * means that we choose either Q=(x,y) or -Q=(x,p-y) such that we + * end up with the min(y,p-y) as the y coordinate. Such a public + * key allows the most efficient compression: y can simply be + * dropped because we know that it's a minimum of the two + * possibilities without any loss of security. Note that we don't + * do that for Ed25519 so that we do not violate the special + * construction of the secret key. */ + if (r_y == NULL || ec->dialect == ECC_DIALECT_ED25519) + ec->Q = mpi_point_set (NULL, Q.x, Q.y, Q.z); + else + { + gcry_mpi_t negative; + + negative = mpi_new (pbits); + + if (ec->model == MPI_EC_WEIERSTRASS) + mpi_sub (negative, ec->p, y); /* negative = p - y */ + else + mpi_sub (negative, ec->p, x); /* negative = p - x */ + + if (mpi_cmp (negative, y) < 0) /* p - y < p */ + { + /* We need to end up with -Q; this assures that new Q's y is + the smallest one */ + if (ec->model == MPI_EC_WEIERSTRASS) + { + mpi_free (y); + y = negative; + } + else + { + mpi_free (x); + x = negative; + } + mpi_sub (ec->d, ec->n, ec->d); /* d = order - d */ + ec->Q = mpi_point_set (NULL, x, y, mpi_const (MPI_C_ONE)); + + if (DBG_CIPHER) + log_debug ("ecgen converted Q to a compliant point\n"); + } + else /* p - y >= p */ + { + /* No change is needed exactly 50% of the time: just copy. */ + mpi_free (negative); + ec->Q = mpi_point_set (NULL, Q.x, Q.y, Q.z); + if (DBG_CIPHER) + log_debug ("ecgen didn't need to convert Q to a compliant point\n"); + } + } + + *r_x = x; + if (r_y) + *r_y = y; + + point_free (&Q); + /* Now we can test our keys (this should never fail!). */ + if ((flags & PUBKEY_FLAG_NO_KEYTEST)) + ; /* User requested to skip the test. */ + else if (ec->model == MPI_EC_MONTGOMERY) + test_ecdh_only_keys (ec, ec->nbits - 63, flags); + else + test_keys (ec, ec->nbits - 64); + + return 0; +} + + +/* + * To verify correct skey it use a random information. + * First, encrypt and decrypt this dummy value, + * test if the information is recuperated. + * Second, test with the sign and verify functions. + */ +static void +test_keys (mpi_ec_t ec, unsigned int nbits) +{ + gcry_mpi_t test = mpi_new (nbits); + mpi_point_struct R_; + gcry_mpi_t c = mpi_new (nbits); + gcry_mpi_t out = mpi_new (nbits); + gcry_mpi_t r = mpi_new (nbits); + gcry_mpi_t s = mpi_new (nbits); + + if (DBG_CIPHER) + log_debug ("Testing key.\n"); + + point_init (&R_); + + _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM); + + if (_gcry_ecc_ecdsa_sign (test, ec, r, s, 0, 0) ) + log_fatal ("ECDSA operation: sign failed\n"); + + if (_gcry_ecc_ecdsa_verify (test, ec, r, s)) + { + log_fatal ("ECDSA operation: sign, verify failed\n"); + } + + if (DBG_CIPHER) + log_debug ("ECDSA operation: sign, verify ok.\n"); + + point_free (&R_); + mpi_free (s); + mpi_free (r); + mpi_free (out); + mpi_free (c); + mpi_free (test); +} + + +static void +test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags) +{ + gcry_mpi_t test; + mpi_point_struct R_; + gcry_mpi_t x0, x1; + + if (DBG_CIPHER) + log_debug ("Testing ECDH only key.\n"); + + point_init (&R_); + + if (ec->dialect == ECC_DIALECT_SAFECURVE || (flags & PUBKEY_FLAG_DJB_TWEAK)) + { + char *rndbuf; + const unsigned int pbits = ec->nbits; + int len = (pbits+7)/8; + + rndbuf = _gcry_random_bytes (len, GCRY_WEAK_RANDOM); + if (ec->dialect == ECC_DIALECT_SAFECURVE) + test = mpi_set_opaque (NULL, rndbuf, len*8); + else + { + test = mpi_new (pbits); + if ((pbits % 8)) + rndbuf[0] &= (1 << (pbits % 8)) - 1; + rndbuf[0] |= (1 << ((pbits + 7) % 8)); + rndbuf[len-1] &= (256 - ec->h); + _gcry_mpi_set_buffer (test, rndbuf, len, 0); + xfree (rndbuf); + } + } + else + { + test = mpi_new (nbits); + _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM); + } + + x0 = mpi_new (0); + x1 = mpi_new (0); + + /* R_ = hkQ <=> R_ = hkdG */ + _gcry_mpi_ec_mul_point (&R_, test, ec->Q, ec); + if (ec->dialect == ECC_DIALECT_STANDARD && !(flags & PUBKEY_FLAG_DJB_TWEAK)) + _gcry_mpi_ec_mul_point (&R_, _gcry_mpi_get_const (ec->h), &R_, ec); + if (_gcry_mpi_ec_get_affine (x0, NULL, &R_, ec)) + log_fatal ("ecdh: Failed to get affine coordinates for hkQ\n"); + + _gcry_mpi_ec_mul_point (&R_, test, ec->G, ec); + _gcry_mpi_ec_mul_point (&R_, ec->d, &R_, ec); + /* R_ = hdkG */ + if (ec->dialect == ECC_DIALECT_STANDARD && !(flags & PUBKEY_FLAG_DJB_TWEAK)) + _gcry_mpi_ec_mul_point (&R_, _gcry_mpi_get_const (ec->h), &R_, ec); + + if (_gcry_mpi_ec_get_affine (x1, NULL, &R_, ec)) + log_fatal ("ecdh: Failed to get affine coordinates for hdkG\n"); + + if (mpi_cmp (x0, x1)) + { + log_fatal ("ECDH test failed.\n"); + } + + mpi_free (x0); + mpi_free (x1); + + point_free (&R_); + mpi_free (test); +} + + +/* + * To check the validity of the value, recalculate the correspondence + * between the public value and the secret one. + */ +static int +check_secret_key (mpi_ec_t ec, int flags) +{ + int rc = 1; + mpi_point_struct Q; + gcry_mpi_t x1, y1; + gcry_mpi_t x2 = NULL; + gcry_mpi_t y2 = NULL; + + point_init (&Q); + x1 = mpi_new (0); + if (ec->model == MPI_EC_MONTGOMERY) + y1 = NULL; + else + y1 = mpi_new (0); + + /* G in E(F_p) */ + if (!_gcry_mpi_ec_curve_point (ec->G, ec)) + { + if (DBG_CIPHER) + log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n"); + goto leave; + } + + /* G != PaI */ + if (!mpi_cmp_ui (ec->G->z, 0)) + { + if (DBG_CIPHER) + log_debug ("Bad check: 'G' cannot be Point at Infinity!\n"); + goto leave; + } + + /* Check order of curve. */ + if (ec->dialect == ECC_DIALECT_STANDARD && !(flags & PUBKEY_FLAG_DJB_TWEAK)) + { + _gcry_mpi_ec_mul_point (&Q, ec->n, ec->G, ec); + if (mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("check_secret_key: E is not a curve of order n\n"); + goto leave; + } + } + + /* Pubkey cannot be PaI */ + if (!mpi_cmp_ui (ec->Q->z, 0)) + { + if (DBG_CIPHER) + log_debug ("Bad check: Q can not be a Point at Infinity!\n"); + goto leave; + } + + /* pubkey = [d]G over E */ + if (!_gcry_ecc_compute_public (&Q, ec)) + { + if (DBG_CIPHER) + log_debug ("Bad check: computation of dG failed\n"); + goto leave; + } + if (_gcry_mpi_ec_get_affine (x1, y1, &Q, ec)) + { + if (DBG_CIPHER) + log_debug ("Bad check: Q can not be a Point at Infinity!\n"); + goto leave; + } + + if ((flags & PUBKEY_FLAG_EDDSA) + || (ec->model == MPI_EC_EDWARDS && ec->dialect == ECC_DIALECT_SAFECURVE)) + ; /* Fixme: EdDSA is special. */ + else if (!mpi_cmp_ui (ec->Q->z, 1)) + { + /* Fast path if Q is already in affine coordinates. */ + if (mpi_cmp (x1, ec->Q->x) || (y1 && mpi_cmp (y1, ec->Q->y))) + { + if (DBG_CIPHER) + log_debug + ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); + goto leave; + } + } + else + { + x2 = mpi_new (0); + y2 = mpi_new (0); + if (_gcry_mpi_ec_get_affine (x2, y2, ec->Q, ec)) + { + if (DBG_CIPHER) + log_debug ("Bad check: Q can not be a Point at Infinity!\n"); + goto leave; + } + + if (mpi_cmp (x1, x2) || mpi_cmp (y1, y2)) + { + if (DBG_CIPHER) + log_debug + ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); + goto leave; + } + } + rc = 0; /* Okay. */ + + leave: + mpi_free (x2); + mpi_free (x1); + mpi_free (y1); + mpi_free (y2); + point_free (&Q); + return rc; +} + + + +/********************************************* + ************** interface ****************** + *********************************************/ + +static gcry_err_code_t +ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) +{ + gpg_err_code_t rc; + gcry_mpi_t Gx = NULL; + gcry_mpi_t Gy = NULL; + gcry_mpi_t Qx = NULL; + gcry_mpi_t Qy = NULL; + mpi_ec_t ec = NULL; + gcry_sexp_t curve_info = NULL; + gcry_sexp_t curve_flags = NULL; + gcry_mpi_t base = NULL; + gcry_mpi_t public = NULL; + int flags = 0; + + rc = _gcry_mpi_ec_internal_new (&ec, &flags, "ecgen curve", genparms, NULL); + if (rc) + goto leave; + + if ((flags & PUBKEY_FLAG_EDDSA) + || (ec->model == MPI_EC_EDWARDS && ec->dialect == ECC_DIALECT_SAFECURVE)) + rc = _gcry_ecc_eddsa_genkey (ec, flags); + else if (ec->model == MPI_EC_MONTGOMERY) + rc = nist_generate_key (ec, flags, &Qx, NULL); + else + rc = nist_generate_key (ec, flags, &Qx, &Qy); + if (rc) + goto leave; + + /* Copy data to the result. */ + Gx = mpi_new (0); + Gy = mpi_new (0); + if (ec->model != MPI_EC_MONTGOMERY) + { + if (_gcry_mpi_ec_get_affine (Gx, Gy, ec->G, ec)) + log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G"); + base = _gcry_ecc_ec2os (Gx, Gy, ec->p); + } + if (((ec->dialect == ECC_DIALECT_SAFECURVE && ec->model == MPI_EC_EDWARDS) + || ec->dialect == ECC_DIALECT_ED25519 || ec->model == MPI_EC_MONTGOMERY) + && !(flags & PUBKEY_FLAG_NOCOMP)) + { + unsigned char *encpk; + unsigned int encpklen; + + if (ec->model == MPI_EC_MONTGOMERY) + rc = _gcry_ecc_mont_encodepoint (Qx, ec->nbits, + ec->dialect != ECC_DIALECT_SAFECURVE, + &encpk, &encpklen); + else + /* (Gx and Gy are used as scratch variables) */ + rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, Gx, Gy, + (ec->dialect != ECC_DIALECT_SAFECURVE + && !!(flags & PUBKEY_FLAG_COMP)), + &encpk, &encpklen); + if (rc) + goto leave; + public = mpi_new (0); + mpi_set_opaque (public, encpk, encpklen*8); + } + else + { + if (!Qx) + { + /* This is the case for a key from _gcry_ecc_eddsa_generate + with no compression. */ + Qx = mpi_new (0); + Qy = mpi_new (0); + if (_gcry_mpi_ec_get_affine (Qx, Qy, ec->Q, ec)) + log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q"); + } + public = _gcry_ecc_ec2os (Qx, Qy, ec->p); + } + if (ec->name) + { + rc = sexp_build (&curve_info, NULL, "(curve %s)", ec->name); + if (rc) + goto leave; + } + + if ((flags & PUBKEY_FLAG_PARAM) || (flags & PUBKEY_FLAG_EDDSA) + || (flags & PUBKEY_FLAG_DJB_TWEAK)) + { + rc = sexp_build + (&curve_flags, NULL, + ((flags & PUBKEY_FLAG_PARAM) && (flags & PUBKEY_FLAG_EDDSA))? + "(flags param eddsa)" : + ((flags & PUBKEY_FLAG_PARAM) && (flags & PUBKEY_FLAG_DJB_TWEAK))? + "(flags param djb-tweak)" : + ((flags & PUBKEY_FLAG_PARAM))? + "(flags param)" : ((flags & PUBKEY_FLAG_EDDSA))? + "(flags eddsa)" : "(flags djb-tweak)" ); + if (rc) + goto leave; + } + + if ((flags & PUBKEY_FLAG_PARAM) && ec->name) + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(h%u)(q%m)))" + " (private-key" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(h%u)(q%m)(d%m)))" + " )", + curve_info, curve_flags, + ec->p, ec->a, ec->b, base, ec->n, ec->h, public, + curve_info, curve_flags, + ec->p, ec->a, ec->b, base, ec->n, ec->h, public, + ec->d); + else + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (ecc%S%S(q%m)))" + " (private-key" + " (ecc%S%S(q%m)(d%m)))" + " )", + curve_info, curve_flags, + public, + curve_info, curve_flags, + public, ec->d); + if (rc) + goto leave; + + if (DBG_CIPHER) + { + log_printmpi ("ecgen result p", ec->p); + log_printmpi ("ecgen result a", ec->a); + log_printmpi ("ecgen result b", ec->b); + log_printmpi ("ecgen result G", base); + log_printmpi ("ecgen result n", ec->n); + log_debug ("ecgen result h:+%02x\n", ec->h); + log_printmpi ("ecgen result Q", public); + log_printmpi ("ecgen result d", ec->d); + if ((flags & PUBKEY_FLAG_EDDSA)) + log_debug ("ecgen result using Ed25519+EdDSA\n"); + } + + leave: + mpi_free (public); + mpi_free (base); + mpi_free (Gx); + mpi_free (Gy); + mpi_free (Qx); + mpi_free (Qy); + _gcry_mpi_ec_free (ec); + sexp_release (curve_flags); + sexp_release (curve_info); + return rc; +} + + +static gcry_err_code_t +ecc_check_secret_key (gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + int flags = 0; + mpi_ec_t ec = NULL; + + /* + * Extract the key. + */ + rc = _gcry_mpi_ec_internal_new (&ec, &flags, "ecc_testkey", keyparms, NULL); + if (rc) + goto leave; + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->Q || !ec->d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + if (check_secret_key (ec, flags)) + rc = GPG_ERR_BAD_SECKEY; + + leave: + _gcry_mpi_ec_free (ec); + if (DBG_CIPHER) + log_debug ("ecc_testkey => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + mpi_ec_t ec = NULL; + int flags = 0; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, 0); + + /* + * Extract the key. + */ + rc = _gcry_mpi_ec_internal_new (&ec, &flags, "ecc_sign", keyparms, NULL); + if (rc) + goto leave; + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + ctx.flags |= flags; + if (ec->model == MPI_EC_EDWARDS && ec->dialect == ECC_DIALECT_SAFECURVE) + ctx.flags |= PUBKEY_FLAG_EDDSA; + /* Clear hash algo for EdDSA. */ + if ((ctx.flags & PUBKEY_FLAG_EDDSA)) + ctx.hash_algo = GCRY_MD_NONE; + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("ecc_sign data", data); + + /* Hash algo is determined by curve in EdDSA. Fill it if not specified. */ + if ((ctx.flags & PUBKEY_FLAG_EDDSA) && !ctx.hash_algo) + { + if (ec->dialect == ECC_DIALECT_ED25519) + ctx.hash_algo = GCRY_MD_SHA512; + else if (ec->dialect == ECC_DIALECT_SAFECURVE) + ctx.hash_algo = GCRY_MD_SHAKE256; + } + + sig_r = mpi_new (0); + sig_s = mpi_new (0); + if ((ctx.flags & PUBKEY_FLAG_EDDSA)) + { + /* EdDSA requires the public key. */ + rc = _gcry_ecc_eddsa_sign (data, ec, sig_r, sig_s, &ctx); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s); + } + else if ((ctx.flags & PUBKEY_FLAG_GOST)) + { + rc = _gcry_ecc_gost_sign (data, ec, sig_r, sig_s); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(gost(r%M)(s%M)))", sig_r, sig_s); + } + else if ((ctx.flags & PUBKEY_FLAG_SM2)) + { + rc = _gcry_ecc_sm2_sign (data, ec, sig_r, sig_s, + ctx.flags, ctx.hash_algo); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(sm2(r%M)(s%M)))", sig_r, sig_s); + } + else + { + rc = _gcry_ecc_ecdsa_sign (data, ec, sig_r, sig_s, + ctx.flags, ctx.hash_algo); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s); + } + + leave: + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_release (data); + _gcry_mpi_ec_free (ec); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_sign => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + int sigflags; + mpi_ec_t ec = NULL; + int flags = 0; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + ecc_get_nbits (s_keyparms)); + + /* + * Extract the key. + */ + rc = _gcry_mpi_ec_internal_new (&ec, &flags, "ecc_verify", + s_keyparms, NULL); + if (rc) + goto leave; + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->Q) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + if (ec->model == MPI_EC_MONTGOMERY) + { + if (DBG_CIPHER) + log_debug ("ecc_verify: Can't use a Montgomery curve\n"); + rc = GPG_ERR_INTERNAL; + goto leave; + } + + ctx.flags |= flags; + if (ec->model == MPI_EC_EDWARDS && ec->dialect == ECC_DIALECT_SAFECURVE) + ctx.flags |= PUBKEY_FLAG_EDDSA; + /* Clear hash algo for EdDSA. */ + if ((ctx.flags & PUBKEY_FLAG_EDDSA)) + ctx.hash_algo = GCRY_MD_NONE; + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("ecc_verify data", data); + + /* Hash algo is determined by curve in EdDSA. Fill it if not specified. */ + if ((ctx.flags & PUBKEY_FLAG_EDDSA) && !ctx.hash_algo) + { + if (ec->dialect == ECC_DIALECT_ED25519) + ctx.hash_algo = GCRY_MD_SHA512; + else if (ec->dialect == ECC_DIALECT_SAFECURVE) + ctx.hash_algo = GCRY_MD_SHAKE256; + } + + /* + * Extract the signature value. + */ + rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs", + &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("ecc_verify s_r", sig_r); + log_mpidump ("ecc_verify s_s", sig_s); + } + if ((ctx.flags & PUBKEY_FLAG_EDDSA) ^ (sigflags & PUBKEY_FLAG_EDDSA)) + { + rc = GPG_ERR_CONFLICT; /* Inconsistent use of flag/algoname. */ + goto leave; + } + + /* + * Verify the signature. + */ + if ((sigflags & PUBKEY_FLAG_EDDSA)) + { + rc = _gcry_ecc_eddsa_verify (data, ec, sig_r, sig_s, &ctx); + } + else if ((sigflags & PUBKEY_FLAG_GOST)) + { + rc = _gcry_ecc_gost_verify (data, ec, sig_r, sig_s); + } + else if ((sigflags & PUBKEY_FLAG_SM2)) + { + rc = _gcry_ecc_sm2_verify (data, ec, sig_r, sig_s); + } + else + { + rc = _gcry_ecc_ecdsa_verify (data, ec, sig_r, sig_s); + } + + leave: + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_ec_free (ec); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; +} + + +/* ecdh raw is classic 2-round DH protocol published in 1976. + * + * Overview of ecc_encrypt_raw and ecc_decrypt_raw. + * + * As with any PK operation, encrypt version uses a public key and + * decrypt -- private. + * + * Symbols used below: + * G - field generator point + * d - private long-term scalar + * dG - public long-term key + * k - ephemeral scalar + * kG - ephemeral public key + * dkG - shared secret + * + * ecc_encrypt_raw description: + * input: + * data[0] : private scalar (k) + * output: A new S-expression with the parameters: + * s : shared point (kdG) + * e : generated ephemeral public key (kG) + * + * ecc_decrypt_raw description: + * input: + * data[0] : a point kG (ephemeral public key) + * output: + * result[0] : shared point (kdG) + */ +static gcry_err_code_t +ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + unsigned int nbits; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t mpi_s = NULL; + gcry_mpi_t mpi_e = NULL; + gcry_mpi_t data = NULL; + mpi_ec_t ec = NULL; + int flags = 0; + int no_error_on_infinity; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, + (nbits = ecc_get_nbits (keyparms))); + + /* + * Extract the key. + */ + rc = _gcry_mpi_ec_internal_new (&ec, &flags, "ecc_encrypt", keyparms, NULL); + if (rc) + goto leave; + + if (ec->dialect == ECC_DIALECT_SAFECURVE) + { + ctx.flags |= PUBKEY_FLAG_RAW_FLAG; + no_error_on_infinity = 1; + } + else if ((flags & PUBKEY_FLAG_DJB_TWEAK)) + no_error_on_infinity = 1; + else + no_error_on_infinity = 0; + + /* + * Extract the data. + */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + + /* + * Tweak the scalar bits by cofactor and number of bits of the field. + * It assumes the cofactor is a power of 2. + */ + if ((flags & PUBKEY_FLAG_DJB_TWEAK)) + { + int i; + + for (i = 0; (ec->h & (1 << i)) == 0; i++) + mpi_clear_bit (data, i); + mpi_set_highbit (data, ec->nbits - 1); + } + if (DBG_CIPHER) + log_mpidump ("ecc_encrypt data", data); + + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->Q) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + if ((ctx.flags & PUBKEY_FLAG_SM2)) + { + /* All encryption will be done, return it. */ + rc = _gcry_ecc_sm2_encrypt (r_ciph, data, ec); + goto leave; + } + + /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */ + { + mpi_point_struct R; /* Result that we return. */ + gcry_mpi_t x, y; + unsigned char *rawmpi; + unsigned int rawmpilen; + + rc = 0; + x = mpi_new (0); + if (ec->model == MPI_EC_MONTGOMERY) + y = NULL; + else + y = mpi_new (0); + + point_init (&R); + + /* R = kQ <=> R = kdG */ + _gcry_mpi_ec_mul_point (&R, data, ec->Q, ec); + + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) + { + /* + * Here, X is 0. In the X25519 computation on Curve25519, X0 + * function maps infinity to zero. So, when PUBKEY_FLAG_DJB_TWEAK + * is enabled, return the result of 0 not raising an error. + * + * This is a corner case. It never occurs with properly + * generated public keys, but it might happen with blindly + * imported public key which might not follow the key + * generation procedure. + */ + if (!no_error_on_infinity) + { /* It's not for X25519, then, the input data was simply wrong. */ + rc = GPG_ERR_INV_DATA; + goto leave_main; + } + } + if (y) + mpi_s = _gcry_ecc_ec2os (x, y, ec->p); + else + { + rc = _gcry_ecc_mont_encodepoint (x, nbits, + ec->dialect != ECC_DIALECT_SAFECURVE, + &rawmpi, &rawmpilen); + if (rc) + goto leave_main; + mpi_s = mpi_new (0); + mpi_set_opaque (mpi_s, rawmpi, rawmpilen*8); + } + + /* R = kG */ + _gcry_mpi_ec_mul_point (&R, data, ec->G, ec); + + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave_main; + } + if (y) + mpi_e = _gcry_ecc_ec2os (x, y, ec->p); + else + { + rc = _gcry_ecc_mont_encodepoint (x, nbits, + ec->dialect != ECC_DIALECT_SAFECURVE, + &rawmpi, &rawmpilen); + if (!rc) + { + mpi_e = mpi_new (0); + mpi_set_opaque (mpi_e, rawmpi, rawmpilen*8); + } + } + + leave_main: + mpi_free (x); + mpi_free (y); + point_free (&R); + if (rc) + goto leave; + } + + if (!rc) + rc = sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))", mpi_s, mpi_e); + + leave: + _gcry_mpi_release (data); + _gcry_mpi_release (mpi_s); + _gcry_mpi_release (mpi_e); + _gcry_mpi_ec_free (ec); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_encrypt => %s\n", gpg_strerror (rc)); + return rc; +} + + +/* input: + * data[0] : a point kG (ephemeral public key) + * output: + * resaddr[0] : shared point kdG + * + * see ecc_encrypt_raw for details. + */ +static gcry_err_code_t +ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + unsigned int nbits; + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data_e = NULL; + mpi_ec_t ec = NULL; + mpi_point_struct kG; + mpi_point_struct R; + gcry_mpi_t r = NULL; + int flags = 0; + int enable_specific_point_validation; + + point_init (&kG); + point_init (&R); + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + (nbits = ecc_get_nbits (keyparms))); + + /* + * Extract the key. + */ + rc = _gcry_mpi_ec_internal_new (&ec, &flags, "ecc_decrypt", keyparms, NULL); + if (rc) + goto leave; + + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n || !ec->d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + /* + * Extract the data. + */ + rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx); + if (rc) + goto leave; + if ((ctx.flags & PUBKEY_FLAG_SM2)) + { + /* All decryption will be done, return it. */ + rc = _gcry_ecc_sm2_decrypt (r_plain, l1, ec); + goto leave; + } + else + { + rc = sexp_extract_param (l1, NULL, "/e", &data_e, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("ecc_decrypt d_e", data_e); + } + + if (ec->dialect == ECC_DIALECT_SAFECURVE || (flags & PUBKEY_FLAG_DJB_TWEAK)) + enable_specific_point_validation = 1; + else + enable_specific_point_validation = 0; + + /* + * Compute the plaintext. + */ + if (ec->model == MPI_EC_MONTGOMERY) + rc = _gcry_ecc_mont_decodepoint (data_e, ec, &kG); + else + rc = _gcry_ecc_sec_decodepoint (data_e, ec, &kG); + if (rc) + goto leave; + + if (DBG_CIPHER) + log_printpnt ("ecc_decrypt kG", &kG, NULL); + + if (enable_specific_point_validation) + { + /* For X25519, by its definition, validation should not be done. */ + /* (Instead, we do output check.) + * + * However, to mitigate secret key leak from our implementation, + * we also do input validation here. For constant-time + * implementation, we can remove this input validation. + */ + if (_gcry_mpi_ec_bad_point (&kG, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + } + else if (!_gcry_mpi_ec_curve_point (&kG, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* R = dkG */ + _gcry_mpi_ec_mul_point (&R, ec->d, &kG, ec); + + /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so: */ + { + gcry_mpi_t x, y; + + x = mpi_new (0); + if (ec->model == MPI_EC_MONTGOMERY) + y = NULL; + else + y = mpi_new (0); + + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + /* + * Note for X25519. + * + * By the definition of X25519, this is the case where X25519 + * returns 0, mapping infinity to zero. However, we + * deliberately let it return an error. + * + * For X25519 ECDH, comming here means that it might be + * decrypted by anyone with the shared secret of 0 (the result + * of this function could be always 0 by other scalar values, + * other than the private key of D). + * + * So, it looks like an encrypted message but it can be + * decrypted by anyone, or at least something wrong + * happens. Recipient should not proceed as if it were + * properly encrypted message. + * + * This handling is needed for our major usage of GnuPG, + * where it does the One-Pass Diffie-Hellman method, + * C(1, 1, ECC CDH), with an ephemeral key. + */ + } + + if (y) + r = _gcry_ecc_ec2os (x, y, ec->p); + else + { + + unsigned char *rawmpi; + unsigned int rawmpilen; + + rc = _gcry_ecc_mont_encodepoint (x, nbits, + ec->dialect != ECC_DIALECT_SAFECURVE, + &rawmpi, &rawmpilen); + if (rc) + goto leave; + + r = mpi_new (0); + mpi_set_opaque (r, rawmpi, rawmpilen*8); + } + if (!r) + rc = gpg_err_code_from_syserror (); + else + rc = 0; + mpi_free (x); + mpi_free (y); + } + if (DBG_CIPHER) + log_printmpi ("ecc_decrypt res", r); + + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %m)", r); + + leave: + point_free (&R); + point_free (&kG); + _gcry_mpi_release (r); + _gcry_mpi_release (data_e); + sexp_release (l1); + _gcry_mpi_ec_free (ec); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_decrypt => %s\n", gpg_strerror (rc)); + return rc; +} + + +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (ecc + * (curve ) + * (p ) + * (a ) + * (b ) + * (g ) + * (n ) + * (q )) + * + * More parameters may be given. Either P or CURVE is needed. + */ +static unsigned int +ecc_get_nbits (gcry_sexp_t parms) +{ + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits = 0; + char *curve; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + { /* Parameter P not found - check whether we have "curve". */ + l1 = sexp_find_token (parms, "curve", 5); + if (!l1) + return 0; /* Neither P nor CURVE found. */ + + curve = sexp_nth_string (l1, 1); + sexp_release (l1); + if (!curve) + return 0; /* No curve name given (or out of core). */ + + if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits)) + nbits = 0; + xfree (curve); + } + else + { + p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + if (p) + { + nbits = mpi_get_nbits (p); + _gcry_mpi_release (p); + } + } + return nbits; +} + + +/* See rsa.c for a description of this function. */ +static gpg_err_code_t +compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms) +{ +#define N_COMPONENTS 6 + static const char names[N_COMPONENTS] = "pabgnq"; + gpg_err_code_t rc; + gcry_sexp_t l1; + gcry_mpi_t values[N_COMPONENTS]; + int idx; + char *curvename = NULL; + int flags = 0; + enum gcry_mpi_ec_models model = 0; + enum ecc_dialects dialect = 0; + const unsigned char *raw; + unsigned int n; + + /* Clear the values first. */ + for (idx=0; idx < N_COMPONENTS; idx++) + values[idx] = NULL; + + + /* Look for flags. */ + l1 = sexp_find_token (keyparms, "flags", 0); + if (l1) + { + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + if (rc) + goto leave; + } + + /* Extract the parameters. */ + if ((flags & PUBKEY_FLAG_PARAM)) + rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?/q", + &values[0], &values[1], &values[2], + &values[3], &values[4], &values[5], + NULL); + else + rc = sexp_extract_param (keyparms, NULL, "/q", &values[5], NULL); + if (rc) + goto leave; + + /* Check whether a curve parameter is available and use that to fill + in missing values. */ + sexp_release (l1); + l1 = sexp_find_token (keyparms, "curve", 5); + if (l1) + { + curvename = sexp_nth_string (l1, 1); + if (curvename) + { + rc = _gcry_ecc_update_curve_param (curvename, + &model, &dialect, + &values[0], &values[1], &values[2], + &values[3], &values[4]); + if (rc) + goto leave; + } + } + + /* Guess required fields if a curve parameter has not been given. + FIXME: This is a crude hacks. We need to fix that. */ + if (!curvename) + { + model = ((flags & PUBKEY_FLAG_EDDSA) + ? MPI_EC_EDWARDS + : MPI_EC_WEIERSTRASS); + dialect = ((flags & PUBKEY_FLAG_EDDSA) + ? ECC_DIALECT_ED25519 + : ECC_DIALECT_STANDARD); + } + + /* Check that all parameters are known and normalize all MPIs (that + should not be required but we use an internal function later and + thus we better make 100% sure that they are normalized). */ + for (idx = 0; idx < N_COMPONENTS; idx++) + if (!values[idx]) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + else + _gcry_mpi_normalize (values[idx]); + + /* Uncompress the public key with the exception of EdDSA where + compression is the default and we thus compute the keygrip using + the compressed version. Because we don't support any non-eddsa + compression, the only thing we need to do is to compress + EdDSA. */ + if ((flags & PUBKEY_FLAG_EDDSA) && dialect == ECC_DIALECT_ED25519) + { + const unsigned int pbits = mpi_get_nbits (values[0]); + + rc = _gcry_ecc_eddsa_ensure_compact (values[5], pbits); + if (rc) + goto leave; + } + else if ((flags & PUBKEY_FLAG_DJB_TWEAK)) + { + /* Remove the prefix 0x40 for keygrip computation. */ + raw = mpi_get_opaque (values[5], &n); + if (raw) + { + n = (n + 7)/8; + + if (n > 1 && (n%2) && raw[0] == 0x40) + if (!_gcry_mpi_set_opaque_copy (values[5], raw + 1, (n - 1)*8)) + rc = gpg_err_code_from_syserror (); + } + else + { + rc = GPG_ERR_INV_OBJ; + goto leave; + } + } + + /* Hash them all. */ + for (idx = 0; idx < N_COMPONENTS; idx++) + { + char buf[30]; + + if (mpi_is_opaque (values[idx])) + { + raw = mpi_get_opaque (values[idx], &n); + n = (n + 7)/8; + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], n); + _gcry_md_write (md, buf, strlen (buf)); + _gcry_md_write (md, raw, n); + _gcry_md_write (md, ")", 1); + } + else + { + unsigned char *rawmpi; + unsigned int rawmpilen; + + rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL); + if (!rawmpi) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen); + _gcry_md_write (md, buf, strlen (buf)); + _gcry_md_write (md, rawmpi, rawmpilen); + _gcry_md_write (md, ")", 1); + xfree (rawmpi); + } + } + + leave: + xfree (curvename); + sexp_release (l1); + for (idx = 0; idx < N_COMPONENTS; idx++) + _gcry_mpi_release (values[idx]); + + return rc; +#undef N_COMPONENTS +} + + + +/* + Low-level API helper functions. + */ + +/* This is the worker function for gcry_pubkey_get_sexp for ECC + algorithms. Note that the caller has already stored NULL at + R_SEXP. */ +gpg_err_code_t +_gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec) +{ + gpg_err_code_t rc; + gcry_mpi_t mpi_G = NULL; + gcry_mpi_t mpi_Q = NULL; + + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n) + return GPG_ERR_BAD_CRYPT_CTX; + + if (mode == GCRY_PK_GET_SECKEY && !ec->d) + return GPG_ERR_NO_SECKEY; + + /* Compute the public point if it is missing. */ + if (!ec->Q && ec->d) + ec->Q = _gcry_ecc_compute_public (NULL, ec); + + /* Encode G and Q. */ + mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec); + if (!mpi_G) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + if (!ec->Q) + { + rc = GPG_ERR_BAD_CRYPT_CTX; + goto leave; + } + + if (ec->dialect == ECC_DIALECT_ED25519) + { + unsigned char *encpk; + unsigned int encpklen; + + rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, + &encpk, &encpklen); + if (rc) + goto leave; + mpi_Q = mpi_set_opaque (NULL, encpk, encpklen*8); + encpk = NULL; + } + else if (ec->model == MPI_EC_MONTGOMERY) + { + unsigned char *encpk; + unsigned int encpklen; + + rc = _gcry_ecc_mont_encodepoint (ec->Q->x, ec->nbits, + ec->dialect != ECC_DIALECT_SAFECURVE, + &encpk, &encpklen); + if (rc) + goto leave; + mpi_Q = mpi_set_opaque (NULL, encpk, encpklen*8); + } + else + { + mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec); + } + if (!mpi_Q) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + + /* Fixme: We should return a curve name instead of the parameters if + if know that they match a curve. */ + + if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY)) + { + /* Let's return a private key. */ + rc = sexp_build (r_sexp, NULL, + "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%u)(q%m)(d%m)))", + ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q, ec->d); + } + else if (ec->Q) + { + /* Let's return a public key. */ + rc = sexp_build (r_sexp, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%u)(q%m)))", + ec->p, ec->a, ec->b, mpi_G, ec->n, ec->h, mpi_Q); + } + else + rc = GPG_ERR_BAD_CRYPT_CTX; + + leave: + mpi_free (mpi_Q); + mpi_free (mpi_G); + return rc; +} + + + +/* + Self-test section. + */ + +static const char * +selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) +{ + /* Sample data from RFC 6979 section A.2.5, hash is of message "sample" */ + static const char sample_data[] = + "(data (flags rfc6979)" + " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915" + /**/ "62113d8a62add1bf#))"; + static const char sample_data_bad[] = + "(data (flags rfc6979)" + " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915" + /**/ "62113d8a62add1bf#))"; + static const char signature_r[] = + "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716"; + static const char signature_s[] = + "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8"; + + const char *errtxt = NULL; + gcry_error_t err; + gcry_sexp_t data = NULL; + gcry_sexp_t data_bad = NULL; + gcry_sexp_t sig = NULL; + gcry_sexp_t l1 = NULL; + gcry_sexp_t l2 = NULL; + gcry_mpi_t r = NULL; + gcry_mpi_t s = NULL; + gcry_mpi_t calculated_r = NULL; + gcry_mpi_t calculated_s = NULL; + int cmp; + + err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); + if (!err) + err = sexp_sscan (&data_bad, NULL, + sample_data_bad, strlen (sample_data_bad)); + if (!err) + err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL); + if (!err) + err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL); + + if (err) + { + errtxt = "converting data failed"; + goto leave; + } + + err = _gcry_pk_sign (&sig, data, skey); + if (err) + { + errtxt = "signing failed"; + goto leave; + } + + /* check against known signature */ + errtxt = "signature validity failed"; + l1 = _gcry_sexp_find_token (sig, "sig-val", 0); + if (!l1) + goto leave; + l2 = _gcry_sexp_find_token (l1, "ecdsa", 0); + if (!l2) + goto leave; + + sexp_release (l1); + l1 = l2; + + l2 = _gcry_sexp_find_token (l1, "r", 0); + if (!l2) + goto leave; + calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + if (!calculated_r) + goto leave; + + sexp_release (l2); + l2 = _gcry_sexp_find_token (l1, "s", 0); + if (!l2) + goto leave; + calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + if (!calculated_s) + goto leave; + + errtxt = "known sig check failed"; + + cmp = _gcry_mpi_cmp (r, calculated_r); + if (cmp) + goto leave; + cmp = _gcry_mpi_cmp (s, calculated_s); + if (cmp) + goto leave; + + errtxt = NULL; + + /* verify generated signature */ + err = _gcry_pk_verify (sig, data, pkey); + if (err) + { + errtxt = "verify failed"; + goto leave; + } + err = _gcry_pk_verify (sig, data_bad, pkey); + if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) + { + errtxt = "bad signature not detected"; + goto leave; + } + + + leave: + sexp_release (sig); + sexp_release (data_bad); + sexp_release (data); + sexp_release (l1); + sexp_release (l2); + mpi_release (r); + mpi_release (s); + mpi_release (calculated_r); + mpi_release (calculated_s); + return errtxt; +} + + +static gpg_err_code_t +selftests_ecdsa (selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + gcry_error_t err; + gcry_sexp_t skey = NULL; + gcry_sexp_t pkey = NULL; + + what = "convert"; + err = sexp_sscan (&skey, NULL, sample_secret_key_secp256, + strlen (sample_secret_key_secp256)); + if (!err) + err = sexp_sscan (&pkey, NULL, sample_public_key_secp256, + strlen (sample_public_key_secp256)); + if (err) + { + errtxt = _gcry_strerror (err); + goto failed; + } + + what = "key consistency"; + err = ecc_check_secret_key(skey); + if (err) + { + errtxt = _gcry_strerror (err); + goto failed; + } + + what = "sign"; + errtxt = selftest_sign (pkey, skey); + if (errtxt) + goto failed; + + sexp_release(pkey); + sexp_release(skey); + return 0; /* Succeeded. */ + + failed: + sexp_release(pkey); + sexp_release(skey); + if (report) + report ("pubkey", GCRY_PK_ECC, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Run a full self-test for ALGO and return 0 on success. */ +static gpg_err_code_t +run_selftests (int algo, int extended, selftest_report_func_t report) +{ + (void)extended; + + if (algo != GCRY_PK_ECC) + return GPG_ERR_PUBKEY_ALGO; + + return selftests_ecdsa (report); +} + + + + +gcry_pk_spec_t _gcry_pubkey_spec_ecc = + { + GCRY_PK_ECC, { 0, 1 }, + (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR), + "ECC", ecc_names, + "pabgnhq", "pabgnhqd", "se", "rs", "pabgnhq", + ecc_generate, + ecc_check_secret_key, + ecc_encrypt_raw, + ecc_decrypt_raw, + ecc_sign, + ecc_verify, + ecc_get_nbits, + run_selftests, + compute_keygrip, + _gcry_ecc_get_curve, + _gcry_ecc_get_param_sexp + }; diff --git a/comm/third_party/libgcrypt/cipher/elgamal.c b/comm/third_party/libgcrypt/cipher/elgamal.c new file mode 100644 index 0000000000..4eb52d620b --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/elgamal.c @@ -0,0 +1,1149 @@ +/* Elgamal.c - Elgamal Public Key encryption + * Copyright (C) 1998, 2000, 2001, 2002, 2003, + * 2008 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 476 ff. + */ + +#include +#include +#include +#include +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +/* Blinding is used to mitigate side-channel attacks. You may undef + this to speed up the operation in case the system is secured + against physical and network mounted side-channel attacks. */ +#define USE_BLINDING 1 + + +typedef struct +{ + gcry_mpi_t p; /* prime */ + gcry_mpi_t g; /* group generator */ + gcry_mpi_t y; /* g^x mod p */ +} ELG_public_key; + + +typedef struct +{ + gcry_mpi_t p; /* prime */ + gcry_mpi_t g; /* group generator */ + gcry_mpi_t y; /* g^x mod p */ + gcry_mpi_t x; /* secret exponent */ +} ELG_secret_key; + + +static const char *elg_names[] = + { + "elg", + "openpgp-elg", + "openpgp-elg-sig", + NULL, + }; + + +static int test_keys (ELG_secret_key *sk, unsigned int nbits, int nodie); +static gcry_mpi_t gen_k (gcry_mpi_t p, int small_k); +static gcry_err_code_t generate (ELG_secret_key *sk, unsigned nbits, + gcry_mpi_t **factors); +static int check_secret_key (ELG_secret_key *sk); +static void do_encrypt (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, + ELG_public_key *pkey); +static void decrypt (gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, + ELG_secret_key *skey); +static void sign (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, + ELG_secret_key *skey); +static int verify (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, + ELG_public_key *pkey); +static unsigned int elg_get_nbits (gcry_sexp_t parms); + + +static void (*progress_cb) (void *, const char *, int, int, int); +static void *progress_cb_data; + +void +_gcry_register_pk_elg_progress (void (*cb) (void *, const char *, + int, int, int), + void *cb_data) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + + +static void +progress (int c) +{ + if (progress_cb) + progress_cb (progress_cb_data, "pk_elg", c, 0, 0); +} + + +/**************** + * Michael Wiener's table on subgroup sizes to match field sizes. + * (floating around somewhere, probably based on the paper from + * Eurocrypt 96, page 332) + */ +static unsigned int +wiener_map( unsigned int n ) +{ + static struct { unsigned int p_n, q_n; } t[] = + { /* p q attack cost */ + { 512, 119 }, /* 9 x 10^17 */ + { 768, 145 }, /* 6 x 10^21 */ + { 1024, 165 }, /* 7 x 10^24 */ + { 1280, 183 }, /* 3 x 10^27 */ + { 1536, 198 }, /* 7 x 10^29 */ + { 1792, 212 }, /* 9 x 10^31 */ + { 2048, 225 }, /* 8 x 10^33 */ + { 2304, 237 }, /* 5 x 10^35 */ + { 2560, 249 }, /* 3 x 10^37 */ + { 2816, 259 }, /* 1 x 10^39 */ + { 3072, 269 }, /* 3 x 10^40 */ + { 3328, 279 }, /* 8 x 10^41 */ + { 3584, 288 }, /* 2 x 10^43 */ + { 3840, 296 }, /* 4 x 10^44 */ + { 4096, 305 }, /* 7 x 10^45 */ + { 4352, 313 }, /* 1 x 10^47 */ + { 4608, 320 }, /* 2 x 10^48 */ + { 4864, 328 }, /* 2 x 10^49 */ + { 5120, 335 }, /* 3 x 10^50 */ + { 0, 0 } + }; + int i; + + for(i=0; t[i].p_n; i++ ) + { + if( n <= t[i].p_n ) + return t[i].q_n; + } + /* Not in table - use an arbitrary high number. */ + return n / 8 + 200; +} + +static int +test_keys ( ELG_secret_key *sk, unsigned int nbits, int nodie ) +{ + ELG_public_key pk; + gcry_mpi_t test = mpi_new ( 0 ); + gcry_mpi_t out1_a = mpi_new ( nbits ); + gcry_mpi_t out1_b = mpi_new ( nbits ); + gcry_mpi_t out2 = mpi_new ( nbits ); + int failed = 0; + + pk.p = sk->p; + pk.g = sk->g; + pk.y = sk->y; + + _gcry_mpi_randomize ( test, nbits, GCRY_WEAK_RANDOM ); + + do_encrypt ( out1_a, out1_b, test, &pk ); + decrypt ( out2, out1_a, out1_b, sk ); + if ( mpi_cmp( test, out2 ) ) + failed |= 1; + + sign ( out1_a, out1_b, test, sk ); + if ( !verify( out1_a, out1_b, test, &pk ) ) + failed |= 2; + + _gcry_mpi_release ( test ); + _gcry_mpi_release ( out1_a ); + _gcry_mpi_release ( out1_b ); + _gcry_mpi_release ( out2 ); + + if (failed && !nodie) + log_fatal ("Elgamal test key for %s %s failed\n", + (failed & 1)? "encrypt+decrypt":"", + (failed & 2)? "sign+verify":""); + if (failed && DBG_CIPHER) + log_debug ("Elgamal test key for %s %s failed\n", + (failed & 1)? "encrypt+decrypt":"", + (failed & 2)? "sign+verify":""); + + return failed; +} + + +/**************** + * Generate a random secret exponent k from prime p, so that k is + * relatively prime to p-1. With SMALL_K set, k will be selected for + * better encryption performance - this must never be used signing! + */ +static gcry_mpi_t +gen_k( gcry_mpi_t p, int small_k ) +{ + gcry_mpi_t k = mpi_alloc_secure( 0 ); + gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(p) ); + gcry_mpi_t p_1 = mpi_copy(p); + unsigned int orig_nbits = mpi_get_nbits(p); + unsigned int nbits, nbytes; + char *rndbuf = NULL; + + if (small_k) + { + /* Using a k much lesser than p is sufficient for encryption and + * it greatly improves the encryption performance. We use + * Wiener's table and add a large safety margin. */ + nbits = wiener_map( orig_nbits ) * 3 / 2; + if( nbits >= orig_nbits ) + BUG(); + } + else + nbits = orig_nbits; + + + nbytes = (nbits+7)/8; + if( DBG_CIPHER ) + log_debug("choosing a random k\n"); + mpi_sub_ui( p_1, p, 1); + for(;;) + { + if( !rndbuf || nbits < 32 ) + { + xfree(rndbuf); + rndbuf = _gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM ); + } + else + { + /* Change only some of the higher bits. We could improve + this by directly requesting more memory at the first call + to get_random_bytes() and use this the here maybe it is + easier to do this directly in random.c Anyway, it is + highly inlikely that we will ever reach this code. */ + char *pp = _gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM ); + memcpy( rndbuf, pp, 4 ); + xfree(pp); + } + _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 ); + + for(;;) + { + if( !(mpi_cmp( k, p_1 ) < 0) ) /* check: k < (p-1) */ + { + if( DBG_CIPHER ) + progress('+'); + break; /* no */ + } + if( !(mpi_cmp_ui( k, 0 ) > 0) ) /* check: k > 0 */ + { + if( DBG_CIPHER ) + progress('-'); + break; /* no */ + } + if (mpi_gcd( temp, k, p_1 )) + goto found; /* okay, k is relative prime to (p-1) */ + mpi_add_ui( k, k, 1 ); + if( DBG_CIPHER ) + progress('.'); + } + } + found: + xfree (rndbuf); + if( DBG_CIPHER ) + progress('\n'); + mpi_free(p_1); + mpi_free(temp); + + return k; +} + +/**************** + * Generate a key pair with a key of size NBITS + * Returns: 2 structures filled with all needed values + * and an array with n-1 factors of (p-1) + */ +static gcry_err_code_t +generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) +{ + gcry_err_code_t rc; + gcry_mpi_t p; /* the prime */ + gcry_mpi_t p_min1; + gcry_mpi_t g; + gcry_mpi_t x; /* the secret exponent */ + gcry_mpi_t y; + unsigned int qbits; + unsigned int xbits; + byte *rndbuf; + + p_min1 = mpi_new ( nbits ); + qbits = wiener_map( nbits ); + if( qbits & 1 ) /* better have a even one */ + qbits++; + g = mpi_alloc(1); + rc = _gcry_generate_elg_prime (0, nbits, qbits, g, &p, ret_factors); + if (rc) + { + mpi_free (p_min1); + mpi_free (g); + return rc; + } + mpi_sub_ui(p_min1, p, 1); + + + /* Select a random number which has these properties: + * 0 < x < p-1 + * This must be a very good random number because this is the + * secret part. The prime is public and may be shared anyway, + * so a random generator level of 1 is used for the prime. + * + * I don't see a reason to have a x of about the same size + * as the p. It should be sufficient to have one about the size + * of q or the later used k plus a large safety margin. Decryption + * will be much faster with such an x. + */ + xbits = qbits * 3 / 2; + if( xbits >= nbits ) + BUG(); + x = mpi_snew ( xbits ); + if( DBG_CIPHER ) + log_debug("choosing a random x of size %u\n", xbits ); + rndbuf = NULL; + do + { + if( DBG_CIPHER ) + progress('.'); + if( rndbuf ) + { /* Change only some of the higher bits */ + if( xbits < 16 ) /* should never happen ... */ + { + xfree(rndbuf); + rndbuf = _gcry_random_bytes_secure ((xbits+7)/8, + GCRY_VERY_STRONG_RANDOM); + } + else + { + char *r = _gcry_random_bytes_secure (2, GCRY_VERY_STRONG_RANDOM); + memcpy(rndbuf, r, 2 ); + xfree (r); + } + } + else + { + rndbuf = _gcry_random_bytes_secure ((xbits+7)/8, + GCRY_VERY_STRONG_RANDOM ); + } + _gcry_mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 ); + mpi_clear_highbit( x, xbits+1 ); + } + while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) ); + xfree(rndbuf); + + y = mpi_new (nbits); + mpi_powm( y, g, x, p ); + + if( DBG_CIPHER ) + { + progress ('\n'); + log_mpidump ("elg p", p ); + log_mpidump ("elg g", g ); + log_mpidump ("elg y", y ); + log_mpidump ("elg x", x ); + } + + /* Copy the stuff to the key structures */ + sk->p = p; + sk->g = g; + sk->y = y; + sk->x = x; + + _gcry_mpi_release ( p_min1 ); + + /* Now we can test our keys (this should never fail!) */ + test_keys ( sk, nbits - 64, 0 ); + + return 0; +} + + +/* Generate a key pair with a key of size NBITS not using a random + value for the secret key but the one given as X. This is useful to + implement a passphrase based decryption for a public key based + encryption. It has appliactions in backup systems. + + Returns: A structure filled with all needed values and an array + with n-1 factors of (p-1). */ +static gcry_err_code_t +generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x, + gcry_mpi_t **ret_factors ) +{ + gcry_err_code_t rc; + gcry_mpi_t p; /* The prime. */ + gcry_mpi_t p_min1; /* The prime minus 1. */ + gcry_mpi_t g; /* The generator. */ + gcry_mpi_t y; /* g^x mod p. */ + unsigned int qbits; + unsigned int xbits; + + sk->p = NULL; + sk->g = NULL; + sk->y = NULL; + sk->x = NULL; + + /* Do a quick check to see whether X is suitable. */ + xbits = mpi_get_nbits (x); + if ( xbits < 64 || xbits >= nbits ) + return GPG_ERR_INV_VALUE; + + p_min1 = mpi_new ( nbits ); + qbits = wiener_map ( nbits ); + if ( (qbits & 1) ) /* Better have an even one. */ + qbits++; + g = mpi_alloc (1); + rc = _gcry_generate_elg_prime (0, nbits, qbits, g, &p, ret_factors ); + if (rc) + { + mpi_free (p_min1); + mpi_free (g); + return rc; + } + mpi_sub_ui (p_min1, p, 1); + + if (DBG_CIPHER) + log_debug ("using a supplied x of size %u", xbits ); + if ( !(mpi_cmp_ui ( x, 0 ) > 0 && mpi_cmp ( x, p_min1 ) <0 ) ) + { + _gcry_mpi_release ( p_min1 ); + _gcry_mpi_release ( p ); + _gcry_mpi_release ( g ); + return GPG_ERR_INV_VALUE; + } + + y = mpi_new (nbits); + mpi_powm ( y, g, x, p ); + + if ( DBG_CIPHER ) + { + progress ('\n'); + log_mpidump ("elg p", p ); + log_mpidump ("elg g", g ); + log_mpidump ("elg y", y ); + log_mpidump ("elg x", x ); + } + + /* Copy the stuff to the key structures */ + sk->p = p; + sk->g = g; + sk->y = y; + sk->x = mpi_copy (x); + + _gcry_mpi_release ( p_min1 ); + + /* Now we can test our keys. */ + if ( test_keys ( sk, nbits - 64, 1 ) ) + { + _gcry_mpi_release ( sk->p ); sk->p = NULL; + _gcry_mpi_release ( sk->g ); sk->g = NULL; + _gcry_mpi_release ( sk->y ); sk->y = NULL; + _gcry_mpi_release ( sk->x ); sk->x = NULL; + return GPG_ERR_BAD_SECKEY; + } + + return 0; +} + + +/**************** + * Test whether the secret key is valid. + * Returns: if this is a valid key. + */ +static int +check_secret_key( ELG_secret_key *sk ) +{ + int rc; + gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); + + mpi_powm (y, sk->g, sk->x, sk->p); + rc = !mpi_cmp( y, sk->y ); + mpi_free( y ); + return rc; +} + + +static void +do_encrypt(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) +{ + gcry_mpi_t k; + + /* Note: maybe we should change the interface, so that it + * is possible to check that input is < p and return an + * error code. + */ + + k = gen_k( pkey->p, 1 ); + mpi_powm (a, pkey->g, k, pkey->p); + + /* b = (y^k * input) mod p + * = ((y^k mod p) * (input mod p)) mod p + * and because input is < p + * = ((y^k mod p) * input) mod p + */ + mpi_powm (b, pkey->y, k, pkey->p); + mpi_mulm (b, b, input, pkey->p); +#if 0 + if( DBG_CIPHER ) + { + log_mpidump("elg encrypted y", pkey->y); + log_mpidump("elg encrypted p", pkey->p); + log_mpidump("elg encrypted k", k); + log_mpidump("elg encrypted M", input); + log_mpidump("elg encrypted a", a); + log_mpidump("elg encrypted b", b); + } +#endif + mpi_free(k); +} + + + + +static void +decrypt (gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, ELG_secret_key *skey ) +{ + gcry_mpi_t t1, t2, r; + unsigned int nbits = mpi_get_nbits (skey->p); + + mpi_normalize (a); + mpi_normalize (b); + + t1 = mpi_snew (nbits); + +#ifdef USE_BLINDING + + t2 = mpi_snew (nbits); + r = mpi_new (nbits); + + /* We need a random number of about the prime size. The random + number merely needs to be unpredictable; thus we use level 0. */ + _gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM); + + /* t1 = r^x mod p */ + mpi_powm (t1, r, skey->x, skey->p); + /* t2 = (a * r)^-x mod p */ + mpi_mulm (t2, a, r, skey->p); + mpi_powm (t2, t2, skey->x, skey->p); + mpi_invm (t2, t2, skey->p); + /* t1 = (t1 * t2) mod p*/ + mpi_mulm (t1, t1, t2, skey->p); + + mpi_free (r); + mpi_free (t2); + +#else /*!USE_BLINDING*/ + + /* output = b/(a^x) mod p */ + mpi_powm (t1, a, skey->x, skey->p); + mpi_invm (t1, t1, skey->p); + +#endif /*!USE_BLINDING*/ + + mpi_mulm (output, b, t1, skey->p); + +#if 0 + if( DBG_CIPHER ) + { + log_mpidump ("elg decrypted x", skey->x); + log_mpidump ("elg decrypted p", skey->p); + log_mpidump ("elg decrypted a", a); + log_mpidump ("elg decrypted b", b); + log_mpidump ("elg decrypted M", output); + } +#endif + mpi_free (t1); +} + + +/**************** + * Make an Elgamal signature out of INPUT + */ + +static void +sign(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey ) +{ + gcry_mpi_t k; + gcry_mpi_t t = mpi_alloc( mpi_get_nlimbs(a) ); + gcry_mpi_t inv = mpi_alloc( mpi_get_nlimbs(a) ); + gcry_mpi_t p_1 = mpi_copy(skey->p); + + /* + * b = (t * inv) mod (p-1) + * b = (t * inv(k,(p-1),(p-1)) mod (p-1) + * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1) + * + */ + mpi_sub_ui(p_1, p_1, 1); + k = gen_k( skey->p, 0 /* no small K ! */ ); + mpi_powm( a, skey->g, k, skey->p ); + mpi_mul(t, skey->x, a ); + mpi_subm(t, input, t, p_1 ); + mpi_invm(inv, k, p_1 ); + mpi_mulm(b, t, inv, p_1 ); + +#if 0 + if( DBG_CIPHER ) + { + log_mpidump ("elg sign p", skey->p); + log_mpidump ("elg sign g", skey->g); + log_mpidump ("elg sign y", skey->y); + log_mpidump ("elg sign x", skey->x); + log_mpidump ("elg sign k", k); + log_mpidump ("elg sign M", input); + log_mpidump ("elg sign a", a); + log_mpidump ("elg sign b", b); + } +#endif + mpi_free(k); + mpi_free(t); + mpi_free(inv); + mpi_free(p_1); +} + + +/**************** + * Returns true if the signature composed of A and B is valid. + */ +static int +verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) +{ + int rc; + gcry_mpi_t t1; + gcry_mpi_t t2; + gcry_mpi_t base[4]; + gcry_mpi_t ex[4]; + + if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) ) + return 0; /* assertion 0 < a < p failed */ + + t1 = mpi_alloc( mpi_get_nlimbs(a) ); + t2 = mpi_alloc( mpi_get_nlimbs(a) ); + +#if 0 + /* t1 = (y^a mod p) * (a^b mod p) mod p */ + gcry_mpi_powm( t1, pkey->y, a, pkey->p ); + gcry_mpi_powm( t2, a, b, pkey->p ); + mpi_mulm( t1, t1, t2, pkey->p ); + + /* t2 = g ^ input mod p */ + gcry_mpi_powm( t2, pkey->g, input, pkey->p ); + + rc = !mpi_cmp( t1, t2 ); +#elif 0 + /* t1 = (y^a mod p) * (a^b mod p) mod p */ + base[0] = pkey->y; ex[0] = a; + base[1] = a; ex[1] = b; + base[2] = NULL; ex[2] = NULL; + mpi_mulpowm( t1, base, ex, pkey->p ); + + /* t2 = g ^ input mod p */ + gcry_mpi_powm( t2, pkey->g, input, pkey->p ); + + rc = !mpi_cmp( t1, t2 ); +#else + /* t1 = g ^ - input * y ^ a * a ^ b mod p */ + mpi_invm(t2, pkey->g, pkey->p ); + base[0] = t2 ; ex[0] = input; + base[1] = pkey->y; ex[1] = a; + base[2] = a; ex[2] = b; + base[3] = NULL; ex[3] = NULL; + mpi_mulpowm( t1, base, ex, pkey->p ); + rc = !mpi_cmp_ui( t1, 1 ); + +#endif + + mpi_free(t1); + mpi_free(t2); + return rc; +} + +/********************************************* + ************** interface ****************** + *********************************************/ + +static gpg_err_code_t +elg_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) +{ + gpg_err_code_t rc; + unsigned int nbits; + ELG_secret_key sk; + gcry_mpi_t xvalue = NULL; + gcry_sexp_t l1; + gcry_mpi_t *factors = NULL; + gcry_sexp_t misc_info = NULL; + + memset (&sk, 0, sizeof sk); + + rc = _gcry_pk_util_get_nbits (genparms, &nbits); + if (rc) + return rc; + + /* Parse the optional xvalue element. */ + l1 = sexp_find_token (genparms, "xvalue", 0); + if (l1) + { + xvalue = sexp_nth_mpi (l1, 1, 0); + sexp_release (l1); + if (!xvalue) + return GPG_ERR_BAD_MPI; + } + + if (xvalue) + { + rc = generate_using_x (&sk, nbits, xvalue, &factors); + mpi_free (xvalue); + } + else + { + rc = generate (&sk, nbits, &factors); + } + if (rc) + goto leave; + + if (factors && factors[0]) + { + int nfac; + void **arg_list; + char *buffer, *p; + + for (nfac = 0; factors[nfac]; nfac++) + ; + arg_list = xtrycalloc (nfac+1, sizeof *arg_list); + if (!arg_list) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + buffer = xtrymalloc (30 + nfac*2 + 2 + 1); + if (!buffer) + { + rc = gpg_err_code_from_syserror (); + xfree (arg_list); + goto leave; + } + p = stpcpy (buffer, "(misc-key-info(pm1-factors"); + for(nfac = 0; factors[nfac]; nfac++) + { + p = stpcpy (p, "%m"); + arg_list[nfac] = factors + nfac; + } + p = stpcpy (p, "))"); + rc = sexp_build_array (&misc_info, NULL, buffer, arg_list); + xfree (arg_list); + xfree (buffer); + if (rc) + goto leave; + } + + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (elg(p%m)(g%m)(y%m)))" + " (private-key" + " (elg(p%m)(g%m)(y%m)(x%m)))" + " %S)", + sk.p, sk.g, sk.y, + sk.p, sk.g, sk.y, sk.x, + misc_info); + + leave: + mpi_free (sk.p); + mpi_free (sk.g); + mpi_free (sk.y); + mpi_free (sk.x); + sexp_release (misc_info); + if (factors) + { + gcry_mpi_t *mp; + for (mp = factors; *mp; mp++) + mpi_free (*mp); + xfree (factors); + } + + return rc; +} + + +static gcry_err_code_t +elg_check_secret_key (gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + + rc = sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; + + if (!check_secret_key (&sk)) + rc = GPG_ERR_BAD_SECKEY; + + leave: + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + if (DBG_CIPHER) + log_debug ("elg_testkey => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t mpi_a = NULL; + gcry_mpi_t mpi_b = NULL; + gcry_mpi_t data = NULL; + ELG_public_key pk = { NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, + elg_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("elg_encrypt data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("elg_encrypt p", pk.p); + log_mpidump ("elg_encrypt g", pk.g); + log_mpidump ("elg_encrypt y", pk.y); + } + + /* Do Elgamal computation and build result. */ + mpi_a = mpi_new (0); + mpi_b = mpi_new (0); + do_encrypt (mpi_a, mpi_b, data, &pk); + rc = sexp_build (r_ciph, NULL, "(enc-val(elg(a%m)(b%m)))", mpi_a, mpi_b); + + leave: + _gcry_mpi_release (mpi_a); + _gcry_mpi_release (mpi_b); + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_encrypt => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data_a = NULL; + gcry_mpi_t data_b = NULL; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + gcry_mpi_t plain = NULL; + unsigned char *unpad = NULL; + size_t unpadlen = 0; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + elg_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "ab", &data_a, &data_b, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_printmpi ("elg_decrypt d_a", data_a); + log_printmpi ("elg_decrypt d_b", data_b); + } + if (mpi_is_opaque (data_a) || mpi_is_opaque (data_b)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_printmpi ("elg_decrypt p", sk.p); + log_printmpi ("elg_decrypt g", sk.g); + log_printmpi ("elg_decrypt y", sk.y); + if (!fips_mode ()) + log_printmpi ("elg_decrypt x", sk.x); + } + + plain = mpi_snew (ctx.nbits); + decrypt (plain, data_a, data_b, &sk); + if (DBG_CIPHER) + log_printmpi ("elg_decrypt res", plain); + + /* Reverse the encoding and build the s-expression. */ + switch (ctx.encoding) + { + case PUBKEY_ENC_PKCS1: + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); + mpi_free (plain); plain = NULL; + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad); + break; + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + ctx.nbits, ctx.hash_algo, plain, + ctx.label, ctx.labellen); + mpi_free (plain); plain = NULL; + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad); + break; + + default: + /* Raw format. For backward compatibility we need to assume a + signed mpi by using the sexp format string "%m". */ + rc = sexp_build (r_plain, NULL, + (ctx.flags & PUBKEY_FLAG_LEGACYRESULT) + ? "%m" : "(value %m)", + plain); + break; + } + + + leave: + xfree (unpad); + _gcry_mpi_release (plain); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data_a); + _gcry_mpi_release (data_b); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_decrypt => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +elg_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, + elg_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("elg_sign data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("elg_sign p", sk.p); + log_mpidump ("elg_sign g", sk.g); + log_mpidump ("elg_sign y", sk.y); + if (!fips_mode ()) + log_mpidump ("elg_sign x", sk.x); + } + + sig_r = mpi_new (0); + sig_s = mpi_new (0); + sign (sig_r, sig_s, data, &sk); + if (DBG_CIPHER) + { + log_mpidump ("elg_sign sig_r", sig_r); + log_mpidump ("elg_sign sig_s", sig_s); + } + rc = sexp_build (r_sig, NULL, "(sig-val(elg(r%M)(s%M)))", sig_r, sig_s); + + leave: + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_sign => %s\n", gpg_strerror (rc)); + return rc; +} + + +static gcry_err_code_t +elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) +{ + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + ELG_public_key pk = { NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + elg_get_nbits (s_keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("elg_verify data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* Extract the signature value. */ + rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("elg_verify s_r", sig_r); + log_mpidump ("elg_verify s_s", sig_s); + } + + /* Extract the key. */ + rc = sexp_extract_param (s_keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("elg_verify p", pk.p); + log_mpidump ("elg_verify g", pk.g); + log_mpidump ("elg_verify y", pk.y); + } + + /* Verify the signature. */ + if (!verify (sig_r, sig_s, data, &pk)) + rc = GPG_ERR_BAD_SIGNATURE; + + leave: + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; +} + + +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (dsa + * (p ) + * (g ) + * (y )) + * + * More parameters may be given but we only need P here. + */ +static unsigned int +elg_get_nbits (gcry_sexp_t parms) +{ + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + return 0; /* Parameter P not found. */ + + p= sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + nbits = p? mpi_get_nbits (p) : 0; + _gcry_mpi_release (p); + return nbits; +} + + + +gcry_pk_spec_t _gcry_pubkey_spec_elg = + { + GCRY_PK_ELG, { 0, 0 }, + (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR), + "ELG", elg_names, + "pgy", "pgyx", "ab", "rs", "pgy", + elg_generate, + elg_check_secret_key, + elg_encrypt, + elg_decrypt, + elg_sign, + elg_verify, + elg_get_nbits, + }; diff --git a/comm/third_party/libgcrypt/cipher/gost-s-box.c b/comm/third_party/libgcrypt/cipher/gost-s-box.c new file mode 100644 index 0000000000..5d5ed7dc44 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/gost-s-box.c @@ -0,0 +1,266 @@ +/* gost-s-box.c - GOST 28147-89 S-Box expander + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include + +#define DIM(v) (sizeof(v)/sizeof((v)[0])) + +struct gost_sbox +{ + const char *name; + const char *oid; + unsigned int keymeshing; + unsigned char sbox[16*8]; +} gost_sboxes[] = { + { "test_3411", "1.2.643.2.2.30.0", 0, + { + 0x4, 0xE, 0x5, 0x7, 0x6, 0x4, 0xD, 0x1, + 0xA, 0xB, 0x8, 0xD, 0xC, 0xB, 0xB, 0xF, + 0x9, 0x4, 0x1, 0xA, 0x7, 0xA, 0x4, 0xD, + 0x2, 0xC, 0xD, 0x1, 0x1, 0x0, 0x1, 0x0, + + 0xD, 0x6, 0xA, 0x0, 0x5, 0x7, 0x3, 0x5, + 0x8, 0xD, 0x3, 0x8, 0xF, 0x2, 0xF, 0x7, + 0x0, 0xF, 0x4, 0x9, 0xD, 0x1, 0x5, 0xA, + 0xE, 0xA, 0x2, 0xF, 0x8, 0xD, 0x9, 0x4, + + 0x6, 0x2, 0xE, 0xE, 0x4, 0x3, 0x0, 0x9, + 0xB, 0x3, 0xF, 0x4, 0xA, 0x6, 0xA, 0x2, + 0x1, 0x8, 0xC, 0x6, 0x9, 0x8, 0xE, 0x3, + 0xC, 0x1, 0x7, 0xC, 0xE, 0x5, 0x7, 0xE, + + 0x7, 0x0, 0x6, 0xB, 0x0, 0x9, 0x6, 0x6, + 0xF, 0x7, 0x0, 0x2, 0x3, 0xC, 0x8, 0xB, + 0x5, 0x5, 0x9, 0x5, 0xB, 0xF, 0x2, 0x8, + 0x3, 0x9, 0xB, 0x3, 0x2, 0xE, 0xC, 0xC, + } + }, + { "CryptoPro_3411", "1.2.643.2.2.30.1", 0, + { + 0xA, 0x5, 0x7, 0x4, 0x7, 0x7, 0xD, 0x1, + 0x4, 0xF, 0xF, 0xA, 0x6, 0x6, 0xE, 0x3, + 0x5, 0x4, 0xC, 0x7, 0x4, 0x2, 0x4, 0xA, + 0x6, 0x0, 0xE, 0xC, 0xB, 0x4, 0x1, 0x9, + + 0x8, 0x2, 0x9, 0x0, 0x9, 0xD, 0x7, 0x5, + 0x1, 0xD, 0x4, 0xF, 0xC, 0x9, 0x0, 0xB, + 0x3, 0xB, 0x1, 0x2, 0x2, 0xF, 0x5, 0x4, + 0x7, 0x9, 0x0, 0x8, 0xA, 0x0, 0xA, 0xF, + + 0xD, 0x1, 0x3, 0xE, 0x1, 0xA, 0x3, 0x8, + 0xC, 0x7, 0xB, 0x1, 0x8, 0x1, 0xC, 0x6, + 0xE, 0x6, 0x5, 0x6, 0x0, 0x5, 0x8, 0x7, + 0x0, 0x3, 0x2, 0x5, 0xE, 0xB, 0xF, 0xE, + + 0x9, 0xC, 0x6, 0xD, 0xF, 0x8, 0x6, 0xD, + 0x2, 0xE, 0xA, 0xB, 0xD, 0xE, 0x2, 0x0, + 0xB, 0xA, 0x8, 0x9, 0x3, 0xC, 0x9, 0x2, + 0xF, 0x8, 0xD, 0x3, 0x5, 0x3, 0xB, 0xC, + } + }, + { "Test_89", "1.2.643.2.2.31.0", 0, + { + 0x4, 0xC, 0xD, 0xE, 0x3, 0x8, 0x9, 0xC, + 0x2, 0x9, 0x8, 0x9, 0xE, 0xF, 0xB, 0x6, + 0xF, 0xF, 0xE, 0xB, 0x5, 0x6, 0xC, 0x5, + 0x5, 0xE, 0xC, 0x2, 0x9, 0xB, 0x0, 0x2, + + 0x9, 0x8, 0x7, 0x5, 0x6, 0x1, 0x3, 0xB, + 0x1, 0x1, 0x3, 0xF, 0x8, 0x9, 0x6, 0x0, + 0x0, 0x3, 0x9, 0x7, 0x0, 0xC, 0x7, 0x9, + 0x8, 0xA, 0xA, 0x1, 0xD, 0x5, 0x5, 0xD, + + 0xE, 0x2, 0x1, 0x0, 0xA, 0xD, 0x4, 0x3, + 0x3, 0x7, 0x5, 0xD, 0xB, 0x3, 0x8, 0xE, + 0xB, 0x4, 0x2, 0xC, 0x7, 0x7, 0xE, 0x7, + 0xC, 0xD, 0x4, 0x6, 0xC, 0xA, 0xF, 0xA, + + 0xD, 0x6, 0x6, 0xA, 0x2, 0x0, 0x1, 0xF, + 0x7, 0x0, 0xF, 0x4, 0x1, 0xE, 0xA, 0x4, + 0xA, 0xB, 0x0, 0x3, 0xF, 0x2, 0x2, 0x1, + 0x6, 0x5, 0xB, 0x8, 0x4, 0x4, 0xD, 0x8, + } + }, + { "CryptoPro_A", "1.2.643.2.2.31.1", 1, + { + 0x9, 0x3, 0xE, 0xE, 0xB, 0x3, 0x1, 0xB, + 0x6, 0x7, 0x4, 0x7, 0x5, 0xA, 0xD, 0xA, + 0x3, 0xE, 0x6, 0xA, 0x1, 0xD, 0x2, 0xF, + 0x2, 0x9, 0x2, 0xC, 0x9, 0xC, 0x9, 0x5, + + 0x8, 0x8, 0xB, 0xD, 0x8, 0x1, 0x7, 0x0, + 0xB, 0xA, 0x3, 0x1, 0xD, 0x2, 0xA, 0xC, + 0x1, 0xF, 0xD, 0x3, 0xF, 0x0, 0x6, 0xE, + 0x7, 0x0, 0x8, 0x9, 0x0, 0xB, 0x0, 0x8, + + 0xA, 0x5, 0xC, 0x0, 0xE, 0x7, 0x8, 0x6, + 0x4, 0x2, 0xF, 0x2, 0x4, 0x5, 0xC, 0x2, + 0xE, 0x6, 0x5, 0xB, 0x2, 0x9, 0x4, 0x3, + 0xF, 0xC, 0xA, 0x4, 0x3, 0x4, 0x5, 0x9, + + 0xC, 0xB, 0x0, 0xF, 0xC, 0x8, 0xF, 0x1, + 0x0, 0x4, 0x7, 0x8, 0x7, 0xF, 0x3, 0x7, + 0xD, 0xD, 0x1, 0x5, 0xA, 0xE, 0xB, 0xD, + 0x5, 0x1, 0x9, 0x6, 0x6, 0x6, 0xE, 0x4, + } + }, + { "CryptoPro_B", "1.2.643.2.2.31.2", 1, + { + 0x8, 0x0, 0xE, 0x7, 0x2, 0x8, 0x5, 0x0, + 0x4, 0x1, 0xC, 0x5, 0x7, 0x3, 0x2, 0x4, + 0xB, 0x2, 0x0, 0x0, 0xC, 0x2, 0xA, 0xB, + 0x1, 0xA, 0xA, 0xD, 0xF, 0x6, 0xB, 0xE, + + 0x3, 0x4, 0x9, 0xB, 0x9, 0x4, 0x9, 0x8, + 0x5, 0xD, 0x2, 0x6, 0x5, 0xD, 0x1, 0x3, + 0x0, 0x5, 0xD, 0x1, 0xA, 0xE, 0xC, 0x7, + 0x9, 0xC, 0xB, 0x2, 0xB, 0xB, 0x3, 0x1, + + 0x2, 0x9, 0x7, 0x3, 0x1, 0xC, 0x7, 0xA, + 0xE, 0x7, 0x5, 0xA, 0x4, 0x1, 0x4, 0x2, + 0xA, 0x3, 0x8, 0xC, 0x0, 0x7, 0xD, 0x9, + 0xC, 0xF, 0xF, 0xF, 0xD, 0xF, 0x0, 0x6, + + 0xD, 0xB, 0x3, 0x4, 0x6, 0xA, 0x6, 0xF, + 0x6, 0x8, 0x6, 0xE, 0x8, 0x0, 0xF, 0xD, + 0x7, 0x6, 0x1, 0x9, 0xE, 0x9, 0x8, 0x5, + 0xF, 0xE, 0x4, 0x8, 0x3, 0x5, 0xE, 0xC, + } + }, + { "CryptoPro_C", "1.2.643.2.2.31.3", 1, + { + 0x1, 0x0, 0x8, 0x3, 0x8, 0xC, 0xA, 0x7, + 0xB, 0x1, 0x2, 0x6, 0xD, 0x9, 0x9, 0x4, + 0xC, 0x7, 0x5, 0x0, 0xB, 0xB, 0x6, 0x0, + 0x2, 0xD, 0x0, 0x1, 0x0, 0x1, 0x8, 0x5, + + 0x9, 0xB, 0x4, 0x5, 0x4, 0x8, 0xD, 0xA, + 0xD, 0x4, 0x9, 0xD, 0x5, 0xE, 0xE, 0x2, + 0x0, 0x5, 0xF, 0xA, 0x1, 0x2, 0x2, 0xF, + 0xF, 0x2, 0xA, 0x8, 0x2, 0x4, 0x0, 0xE, + + 0x4, 0x8, 0x3, 0xB, 0x9, 0x7, 0xF, 0xC, + 0x5, 0xE, 0x7, 0x2, 0x3, 0x3, 0x3, 0x6, + 0x8, 0xF, 0xC, 0x9, 0xC, 0x6, 0x5, 0x1, + 0xE, 0xC, 0xD, 0x7, 0xE, 0x5, 0xB, 0xB, + + 0xA, 0x9, 0x6, 0xE, 0x6, 0xA, 0x4, 0xD, + 0x7, 0xA, 0xE, 0xF, 0xF, 0x0, 0x1, 0x9, + 0x6, 0x6, 0x1, 0xC, 0xA, 0xF, 0xC, 0x3, + 0x3, 0x3, 0xB, 0x4, 0x7, 0xD, 0x7, 0x8, + } + }, + { "CryptoPro_D", "1.2.643.2.2.31.4", 1, + { + 0xF, 0xB, 0x1, 0x1, 0x0, 0x8, 0x3, 0x1, + 0xC, 0x6, 0xC, 0x5, 0xC, 0x0, 0x0, 0xA, + 0x2, 0x3, 0xB, 0xE, 0x8, 0xF, 0x6, 0x6, + 0xA, 0x4, 0x0, 0xC, 0x9, 0x3, 0xF, 0x8, + + 0x6, 0xC, 0xF, 0xA, 0xD, 0x2, 0x1, 0xF, + 0x4, 0xF, 0xE, 0x7, 0x2, 0x5, 0xE, 0xB, + 0x5, 0xE, 0x6, 0x0, 0xA, 0xE, 0x9, 0x0, + 0x0, 0x2, 0x5, 0xD, 0xB, 0xB, 0x2, 0x4, + + 0x7, 0x7, 0xA, 0x6, 0x7, 0x1, 0xD, 0xC, + 0x9, 0xD, 0xD, 0x2, 0x3, 0xA, 0x8, 0x3, + 0xE, 0x8, 0x4, 0xB, 0x6, 0x4, 0xC, 0x5, + 0xD, 0x0, 0x8, 0x4, 0x5, 0x7, 0x4, 0x9, + + 0x1, 0x5, 0x9, 0x9, 0x4, 0xC, 0xB, 0x7, + 0xB, 0xA, 0x3, 0x3, 0xE, 0x9, 0xA, 0xD, + 0x8, 0x9, 0x7, 0xF, 0xF, 0xD, 0x5, 0x2, + 0x3, 0x1, 0x2, 0x8, 0x1, 0x6, 0x7, 0xE, + } + }, + { "TC26_Z", "1.2.643.7.1.2.5.1.1", 1, + { + 0xc, 0x6, 0xb, 0xc, 0x7, 0x5, 0x8, 0x1, + 0x4, 0x8, 0x3, 0x8, 0xf, 0xd, 0xe, 0x7, + 0x6, 0x2, 0x5, 0x2, 0x5, 0xf, 0x2, 0xe, + 0x2, 0x3, 0x8, 0x1, 0xa, 0x6, 0x5, 0xd, + + 0xa, 0x9, 0x2, 0xd, 0x8, 0x9, 0x6, 0x0, + 0x5, 0xa, 0xf, 0x4, 0x1, 0x2, 0x9, 0x5, + 0xb, 0x5, 0xa, 0xf, 0x6, 0xc, 0x1, 0x8, + 0x9, 0xc, 0xd, 0x6, 0xd, 0xa, 0xc, 0x3, + + 0xe, 0x1, 0xe, 0x7, 0x0, 0xb, 0xf, 0x4, + 0x8, 0xe, 0x1, 0x0, 0x9, 0x7, 0x4, 0xf, + 0xd, 0x4, 0x7, 0xa, 0x3, 0x8, 0xb, 0xa, + 0x7, 0x7, 0x4, 0x5, 0xe, 0x1, 0x0, 0x6, + + 0x0, 0xb, 0xc, 0x3, 0xb, 0x4, 0xd, 0x9, + 0x3, 0xd, 0x9, 0xe, 0x4, 0x3, 0xa, 0xc, + 0xf, 0x0, 0x6, 0x9, 0x2, 0xe, 0x3, 0xb, + 0x1, 0xf, 0x0, 0xb, 0xc, 0x0, 0x7, 0x2, + } + }, +}; + +int main(int argc, char **argv) +{ + unsigned int i, j, s; + FILE *f; + + if (argc == 1) + f = stdin; + else + f = fopen(argv[1], "w"); + + if (!f) + { + perror("fopen"); + exit(1); + } + + for (s = 0; s < DIM(gost_sboxes); s++) + { + unsigned char *sbox = gost_sboxes[s].sbox; + fprintf (f, "static const u32 sbox_%s[4*256] =\n {", gost_sboxes[s].name); + for (i = 0; i < 4; i++) { + fprintf (f, "\n /* %d */\n ", i); + for (j = 0; j < 256; j++) { + unsigned int val; + if (j % 4 == 0 && j != 0) + fprintf (f, "\n "); + val = sbox[ (j & 0xf) * 8 + 2 * i + 0] | + (sbox[ (j >> 4) * 8 + 2 * i + 1] << 4); + val <<= (8*i); + val = (val << 11) | (val >> 21); + fprintf (f, " 0x%08x,", val); + } + } + fprintf (f, "\n };\n\n"); + } + + fprintf (f, "static struct\n{\n const char *oid;\n const u32 *sbox;\n const int keymeshing;\n} gost_oid_map[] = {\n"); + + for (s = 0; s < DIM(gost_sboxes); s++) + { + fprintf (f, " { \"%s\", sbox_%s, %d },\n", gost_sboxes[s].oid, gost_sboxes[s].name, gost_sboxes[s].keymeshing ); + } + + fprintf(f, " { NULL, NULL, 0 }\n};\n"); + + fclose (f); + + return 0; +} diff --git a/comm/third_party/libgcrypt/cipher/gost.h b/comm/third_party/libgcrypt/cipher/gost.h new file mode 100644 index 0000000000..53a4050503 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/gost.h @@ -0,0 +1,34 @@ +/* gost.h - GOST 28147-89 implementation + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef _GCRY_GOST_H +#define _GCRY_GOST_H + +typedef struct { + u32 key[8]; + const u32 *sbox; + unsigned int mesh_counter; + unsigned int mesh_limit; +} GOST28147_context; + +/* This is a simple interface that will be used by GOST R 34.11-94 */ +unsigned int _gcry_gost_enc_data (const u32 *key, + u32 *o1, u32 *o2, u32 n1, u32 n2, int cryptopro); + +#endif diff --git a/comm/third_party/libgcrypt/cipher/gost28147.c b/comm/third_party/libgcrypt/cipher/gost28147.c new file mode 100644 index 0000000000..9445b378c4 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/gost28147.c @@ -0,0 +1,553 @@ +/* gost28147.c - GOST 28147-89 implementation for Libgcrypt + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* GOST 28147-89 defines several modes of encryption: + * - ECB which should be used only for key transfer + * - CFB mode + * - OFB-like mode with additional transformation on keystream + * RFC 5830 names this 'counter encryption' mode + * Original GOST text uses the term 'gammirovanie' + * - MAC mode ('imitovstavka') + * + * This implementation handles ECB and CFB modes via usual libgcrypt handling. + * OFB-like modes are unsupported. + */ + +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "mac-internal.h" +#include "bufhelp.h" +#include "cipher-internal.h" + +#include "gost.h" +#include "gost-sb.h" + +static void +gost_do_set_sbox (GOST28147_context *ctx, unsigned int index) +{ + ctx->sbox = gost_oid_map[index].sbox; + ctx->mesh_limit = gost_oid_map[index].keymeshing ? 1024 : 0; +} + +static gcry_err_code_t +gost_setkey (void *c, const byte *key, unsigned keylen, + cipher_bulk_ops_t *bulk_ops) +{ + int i; + GOST28147_context *ctx = c; + + (void)bulk_ops; + + if (keylen != 256 / 8) + return GPG_ERR_INV_KEYLEN; + + if (!ctx->sbox) + gost_do_set_sbox (ctx, 0); + + for (i = 0; i < 8; i++) + { + ctx->key[i] = buf_get_le32(&key[4*i]); + } + + ctx->mesh_counter = 0; + + return GPG_ERR_NO_ERROR; +} + +static inline u32 +gost_val (u32 subkey, u32 cm1, const u32 *sbox) +{ + cm1 += subkey; + cm1 = sbox[0*256 + ((cm1 >> 0) & 0xff)] | + sbox[1*256 + ((cm1 >> 8) & 0xff)] | + sbox[2*256 + ((cm1 >> 16) & 0xff)] | + sbox[3*256 + ((cm1 >> 24) & 0xff)]; + return cm1; +} + +static unsigned int +_gost_encrypt_data (const u32 *sbox, const u32 *key, u32 *o1, u32 *o2, u32 n1, u32 n2) +{ + n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); + n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); + n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); + n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); + + n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); + n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); + n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); + n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); + + n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); + n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); + n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); + n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); + + n2 ^= gost_val (key[7], n1, sbox); n1 ^= gost_val (key[6], n2, sbox); + n2 ^= gost_val (key[5], n1, sbox); n1 ^= gost_val (key[4], n2, sbox); + n2 ^= gost_val (key[3], n1, sbox); n1 ^= gost_val (key[2], n2, sbox); + n2 ^= gost_val (key[1], n1, sbox); n1 ^= gost_val (key[0], n2, sbox); + + *o1 = n2; + *o2 = n1; + + return /* burn_stack */ 4*sizeof(void*) /* func call */ + + 3*sizeof(void*) /* stack */ + + 4*sizeof(void*) /* gost_val call */; +} + +static unsigned int +gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf) +{ + GOST28147_context *ctx = c; + u32 n1, n2; + unsigned int burn; + + n1 = buf_get_le32 (inbuf); + n2 = buf_get_le32 (inbuf+4); + + burn = _gost_encrypt_data(ctx->sbox, ctx->key, &n1, &n2, n1, n2); + + buf_put_le32 (outbuf+0, n1); + buf_put_le32 (outbuf+4, n2); + + return /* burn_stack */ burn + 6*sizeof(void*) /* func call */; +} + +unsigned int _gcry_gost_enc_data (const u32 *key, + u32 *o1, u32 *o2, u32 n1, u32 n2, int cryptopro) +{ + const u32 *sbox; + if (cryptopro) + sbox = sbox_CryptoPro_3411; + else + sbox = sbox_test_3411; + return _gost_encrypt_data (sbox, key, o1, o2, n1, n2) + 7 * sizeof(void *); +} + +static unsigned int +gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf) +{ + GOST28147_context *ctx = c; + u32 n1, n2; + const u32 *sbox = ctx->sbox; + + n1 = buf_get_le32 (inbuf); + n2 = buf_get_le32 (inbuf+4); + + n2 ^= gost_val (ctx->key[0], n1, sbox); n1 ^= gost_val (ctx->key[1], n2, sbox); + n2 ^= gost_val (ctx->key[2], n1, sbox); n1 ^= gost_val (ctx->key[3], n2, sbox); + n2 ^= gost_val (ctx->key[4], n1, sbox); n1 ^= gost_val (ctx->key[5], n2, sbox); + n2 ^= gost_val (ctx->key[6], n1, sbox); n1 ^= gost_val (ctx->key[7], n2, sbox); + + n2 ^= gost_val (ctx->key[7], n1, sbox); n1 ^= gost_val (ctx->key[6], n2, sbox); + n2 ^= gost_val (ctx->key[5], n1, sbox); n1 ^= gost_val (ctx->key[4], n2, sbox); + n2 ^= gost_val (ctx->key[3], n1, sbox); n1 ^= gost_val (ctx->key[2], n2, sbox); + n2 ^= gost_val (ctx->key[1], n1, sbox); n1 ^= gost_val (ctx->key[0], n2, sbox); + + n2 ^= gost_val (ctx->key[7], n1, sbox); n1 ^= gost_val (ctx->key[6], n2, sbox); + n2 ^= gost_val (ctx->key[5], n1, sbox); n1 ^= gost_val (ctx->key[4], n2, sbox); + n2 ^= gost_val (ctx->key[3], n1, sbox); n1 ^= gost_val (ctx->key[2], n2, sbox); + n2 ^= gost_val (ctx->key[1], n1, sbox); n1 ^= gost_val (ctx->key[0], n2, sbox); + + n2 ^= gost_val (ctx->key[7], n1, sbox); n1 ^= gost_val (ctx->key[6], n2, sbox); + n2 ^= gost_val (ctx->key[5], n1, sbox); n1 ^= gost_val (ctx->key[4], n2, sbox); + n2 ^= gost_val (ctx->key[3], n1, sbox); n1 ^= gost_val (ctx->key[2], n2, sbox); + n2 ^= gost_val (ctx->key[1], n1, sbox); n1 ^= gost_val (ctx->key[0], n2, sbox); + + buf_put_le32 (outbuf+0, n2); + buf_put_le32 (outbuf+4, n1); + + return /* burn_stack */ 4*sizeof(void*) /* func call */ + + 3*sizeof(void*) /* stack */ + + 4*sizeof(void*) /* gost_val call */; +} + +static gpg_err_code_t +gost_set_sbox (GOST28147_context *ctx, const char *oid) +{ + int i; + + for (i = 0; gost_oid_map[i].oid; i++) + { + if (!strcmp(gost_oid_map[i].oid, oid)) + { + gost_do_set_sbox (ctx, i); + return 0; + } + } + return GPG_ERR_VALUE_NOT_FOUND; +} + +static gpg_err_code_t +gost_set_extra_info (void *c, int what, const void *buffer, size_t buflen) +{ + GOST28147_context *ctx = c; + gpg_err_code_t ec = 0; + + (void)buffer; + (void)buflen; + + switch (what) + { + case GCRYCTL_SET_SBOX: + ec = gost_set_sbox (ctx, buffer); + break; + + default: + ec = GPG_ERR_INV_OP; + break; + } + return ec; +} + +static const byte CryptoProKeyMeshingKey[] = { + 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23, + 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4, + 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12, + 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B +}; + +/* Implements key meshing algorithm by modifing ctx and returning new IV. + Thanks to Dmitry Belyavskiy. */ +static void +cryptopro_key_meshing (GOST28147_context *ctx) +{ + unsigned char newkey[32]; + unsigned int i; + + /* "Decrypt" the static keymeshing key */ + for (i = 0; i < 4; i++) + { + gost_decrypt_block (ctx, newkey + i*8, CryptoProKeyMeshingKey + i*8); + } + + /* Set new key */ + for (i = 0; i < 8; i++) + { + ctx->key[i] = buf_get_le32(&newkey[4*i]); + } + + ctx->mesh_counter = 0; +} + +static unsigned int +gost_encrypt_block_mesh (void *c, byte *outbuf, const byte *inbuf) +{ + GOST28147_context *ctx = c; + u32 n1, n2; + unsigned int burn; + + n1 = buf_get_le32 (inbuf); + n2 = buf_get_le32 (inbuf+4); + + if (ctx->mesh_limit && (ctx->mesh_counter == ctx->mesh_limit)) + { + cryptopro_key_meshing (ctx); + /* Yes, encrypt twice: once for KeyMeshing procedure per RFC 4357, + * once for block encryption */ + _gost_encrypt_data(ctx->sbox, ctx->key, &n1, &n2, n1, n2); + } + + burn = _gost_encrypt_data(ctx->sbox, ctx->key, &n1, &n2, n1, n2); + + ctx->mesh_counter += 8; + + buf_put_le32 (outbuf+0, n1); + buf_put_le32 (outbuf+4, n2); + + return /* burn_stack */ burn + 6*sizeof(void*) /* func call */; +} + +static gcry_cipher_oid_spec_t oids_gost28147_mesh[] = + { + { "1.2.643.2.2.21", GCRY_CIPHER_MODE_CFB }, + /* { "1.2.643.2.2.31.0", GCRY_CIPHER_MODE_CNTGOST }, */ + { "1.2.643.2.2.31.1", GCRY_CIPHER_MODE_CFB }, + { "1.2.643.2.2.31.2", GCRY_CIPHER_MODE_CFB }, + { "1.2.643.2.2.31.3", GCRY_CIPHER_MODE_CFB }, + { "1.2.643.2.2.31.4", GCRY_CIPHER_MODE_CFB }, + { NULL } + }; + +gcry_cipher_spec_t _gcry_cipher_spec_gost28147 = + { + GCRY_CIPHER_GOST28147, {0, 0}, + "GOST28147", NULL, NULL, 8, 256, + sizeof (GOST28147_context), + gost_setkey, + gost_encrypt_block, + gost_decrypt_block, + NULL, NULL, NULL, gost_set_extra_info, + }; + +/* Meshing is used only for CFB, so no need to have separate + * gost_decrypt_block_mesh. + * Moreover key meshing is specified as encrypting the block (IV). Decrypting + * it afterwards would be meaningless. */ +gcry_cipher_spec_t _gcry_cipher_spec_gost28147_mesh = + { + GCRY_CIPHER_GOST28147_MESH, {0, 0}, + "GOST28147_MESH", NULL, oids_gost28147_mesh, 8, 256, + sizeof (GOST28147_context), + gost_setkey, + gost_encrypt_block_mesh, + gost_decrypt_block, + NULL, NULL, NULL, gost_set_extra_info, + }; + +static gcry_err_code_t +gost_imit_open (gcry_mac_hd_t h) +{ + memset(&h->u.imit, 0, sizeof(h->u.imit)); + return 0; +} + +static void +gost_imit_close (gcry_mac_hd_t h) +{ + (void) h; +} + +static gcry_err_code_t +gost_imit_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + int i; + + if (keylen != 256 / 8) + return GPG_ERR_INV_KEYLEN; + + if (!h->u.imit.ctx.sbox) + h->u.imit.ctx.sbox = sbox_CryptoPro_A; + + for (i = 0; i < 8; i++) + { + h->u.imit.ctx.key[i] = buf_get_le32(&key[4*i]); + } + + return 0; +} + +static gcry_err_code_t +gost_imit_setiv (gcry_mac_hd_t h, + const unsigned char *iv, + size_t ivlen) +{ + if (ivlen != 8) + return GPG_ERR_INV_LENGTH; + + h->u.imit.n1 = buf_get_le32 (iv + 0); + h->u.imit.n2 = buf_get_le32 (iv + 4); + + return 0; +} + +static gcry_err_code_t +gost_imit_reset (gcry_mac_hd_t h) +{ + h->u.imit.n1 = h->u.imit.n2 = 0; + h->u.imit.unused = 0; + return 0; +} + +static unsigned int +_gost_imit_block (const u32 *sbox, const u32 *key, u32 *o1, u32 *o2, u32 n1, u32 n2) +{ + n1 ^= *o1; + n2 ^= *o2; + + n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); + n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); + n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); + n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); + + n2 ^= gost_val (key[0], n1, sbox); n1 ^= gost_val (key[1], n2, sbox); + n2 ^= gost_val (key[2], n1, sbox); n1 ^= gost_val (key[3], n2, sbox); + n2 ^= gost_val (key[4], n1, sbox); n1 ^= gost_val (key[5], n2, sbox); + n2 ^= gost_val (key[6], n1, sbox); n1 ^= gost_val (key[7], n2, sbox); + + *o1 = n1; + *o2 = n2; + + return /* burn_stack */ 4*sizeof(void*) /* func call */ + + 3*sizeof(void*) /* stack */ + + 4*sizeof(void*) /* gost_val call */; +} + +static inline unsigned int +gost_imit_block (GOST28147_context *ctx, u32 *n1, u32 *n2, const unsigned char *buf) +{ + if (ctx->mesh_limit && (ctx->mesh_counter == ctx->mesh_limit)) + cryptopro_key_meshing (ctx); + + return _gost_imit_block (ctx->sbox, ctx->key, + n1, n2, + buf_get_le32 (buf+0), + buf_get_le32 (buf+4)); +} + +static gcry_err_code_t +gost_imit_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + const int blocksize = 8; + unsigned int burn = 0; + if (!buflen || !buf) + return GPG_ERR_NO_ERROR; + + if (h->u.imit.unused) + { + for (; buflen && h->u.imit.unused < blocksize; buflen --) + h->u.imit.lastiv[h->u.imit.unused++] = *buf++; + + if (h->u.imit.unused < blocksize) + return GPG_ERR_NO_ERROR; + + h->u.imit.count ++; + burn = gost_imit_block (&h->u.imit.ctx, + &h->u.imit.n1, &h->u.imit.n2, + h->u.imit.lastiv); + + h->u.imit.unused = 0; + } + + while (buflen >= blocksize) + { + h->u.imit.count ++; + burn = gost_imit_block (&h->u.imit.ctx, + &h->u.imit.n1, &h->u.imit.n2, + buf); + buf += blocksize; + buflen -= blocksize; + } + + for (; buflen; buflen--) + h->u.imit.lastiv[h->u.imit.unused++] = *buf++; + + _gcry_burn_stack (burn); + + return GPG_ERR_NO_ERROR; +} + +static void +gost_imit_finish (gcry_mac_hd_t h) +{ + static const unsigned char zero[8] = {0}; + + /* Fill till full block */ + if (h->u.imit.unused) + gost_imit_write(h, zero, 8 - h->u.imit.unused); + + if (h->u.imit.count == 1) + gost_imit_write(h, zero, 8); +} + +static gcry_err_code_t +gost_imit_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + unsigned int dlen = 8; + unsigned char digest[8]; + + gost_imit_finish (h); + + buf_put_le32 (digest+0, h->u.imit.n1); + buf_put_le32 (digest+4, h->u.imit.n2); + + if (*outlen <= dlen) + buf_cpy (outbuf, digest, *outlen); + else + { + buf_cpy (outbuf, digest, dlen); + *outlen = dlen; + } + return 0; +} + +static gcry_err_code_t +gost_imit_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + unsigned char tbuf[8]; + + gost_imit_finish (h); + + buf_put_le32 (tbuf+0, h->u.imit.n1); + buf_put_le32 (tbuf+4, h->u.imit.n2); + + return buf_eq_const(tbuf, buf, buflen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; +} + +static unsigned int +gost_imit_get_maclen (int algo) +{ + (void) algo; + return 4; /* or 8 */ +} + + +static unsigned int +gost_imit_get_keylen (int algo) +{ + (void) algo; + return 256 / 8; +} + +static gpg_err_code_t +gost_imit_set_extra_info (gcry_mac_hd_t hd, int what, const void *buffer, size_t buflen) +{ + gpg_err_code_t ec = 0; + + (void)buffer; + (void)buflen; + + switch (what) + { + case GCRYCTL_SET_SBOX: + ec = gost_set_sbox (&hd->u.imit.ctx, buffer); + break; + + default: + ec = GPG_ERR_INV_OP; + break; + } + return ec; +} + + +static gcry_mac_spec_ops_t gost_imit_ops = { + gost_imit_open, + gost_imit_close, + gost_imit_setkey, + gost_imit_setiv, + gost_imit_reset, + gost_imit_write, + gost_imit_read, + gost_imit_verify, + gost_imit_get_maclen, + gost_imit_get_keylen, + gost_imit_set_extra_info, + NULL +}; + +gcry_mac_spec_t _gcry_mac_type_spec_gost28147_imit = + { + GCRY_MAC_GOST28147_IMIT, {0, 0}, "GOST28147_IMIT", + &gost_imit_ops + }; diff --git a/comm/third_party/libgcrypt/cipher/gostr3411-94.c b/comm/third_party/libgcrypt/cipher/gostr3411-94.c new file mode 100644 index 0000000000..7cf0637e26 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/gostr3411-94.c @@ -0,0 +1,383 @@ +/* gostr3411-94.c - GOST R 34.11-94 hash function + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + + +#include +#include +#include +#include + +#include "g10lib.h" +#include "bithelp.h" +#include "bufhelp.h" +#include "cipher.h" +#include "hash-common.h" + +#include "gost.h" + +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +typedef struct { + gcry_md_block_ctx_t bctx; + union { + u32 h[8]; + byte result[32]; + }; + u32 sigma[8]; + u32 len; + int cryptopro; +} GOSTR3411_CONTEXT; + +static unsigned int +transform (void *c, const unsigned char *data, size_t nblks); + +static void +gost3411_init (void *context, unsigned int flags) +{ + GOSTR3411_CONTEXT *hd = context; + + (void)flags; + + memset (hd->h, 0, 32); + memset (hd->sigma, 0, 32); + + hd->bctx.nblocks = 0; + hd->bctx.count = 0; + hd->bctx.blocksize_shift = _gcry_ctz(32); + hd->bctx.bwrite = transform; + hd->cryptopro = 0; +} + +static void +gost3411_cp_init (void *context, unsigned int flags) +{ + GOSTR3411_CONTEXT *hd = context; + gost3411_init (context, flags); + hd->cryptopro = 1; +} + +static void +do_p (u32 *p, u32 *u, u32 *v) +{ + int k; + u32 t[8]; + + for (k = 0; k < 8; k++) + t[k] = u[k] ^ v[k]; + + k = 0; + p[k+0] = ((t[0] >> (8*k)) & 0xff) << 0 | + ((t[2] >> (8*k)) & 0xff) << 8 | + ((t[4] >> (8*k)) & 0xff) << 16 | + ((t[6] >> (8*k)) & 0xff) << 24; + p[k+4] = ((t[1] >> (8*k)) & 0xff) << 0 | + ((t[3] >> (8*k)) & 0xff) << 8 | + ((t[5] >> (8*k)) & 0xff) << 16 | + ((t[7] >> (8*k)) & 0xff) << 24; + + k = 1; + p[k+0] = ((t[0] >> (8*k)) & 0xff) << 0 | + ((t[2] >> (8*k)) & 0xff) << 8 | + ((t[4] >> (8*k)) & 0xff) << 16 | + ((t[6] >> (8*k)) & 0xff) << 24; + p[k+4] = ((t[1] >> (8*k)) & 0xff) << 0 | + ((t[3] >> (8*k)) & 0xff) << 8 | + ((t[5] >> (8*k)) & 0xff) << 16 | + ((t[7] >> (8*k)) & 0xff) << 24; + + k = 2; + p[k+0] = ((t[0] >> (8*k)) & 0xff) << 0 | + ((t[2] >> (8*k)) & 0xff) << 8 | + ((t[4] >> (8*k)) & 0xff) << 16 | + ((t[6] >> (8*k)) & 0xff) << 24; + p[k+4] = ((t[1] >> (8*k)) & 0xff) << 0 | + ((t[3] >> (8*k)) & 0xff) << 8 | + ((t[5] >> (8*k)) & 0xff) << 16 | + ((t[7] >> (8*k)) & 0xff) << 24; + + k = 3; + p[k+0] = ((t[0] >> (8*k)) & 0xff) << 0 | + ((t[2] >> (8*k)) & 0xff) << 8 | + ((t[4] >> (8*k)) & 0xff) << 16 | + ((t[6] >> (8*k)) & 0xff) << 24; + p[k+4] = ((t[1] >> (8*k)) & 0xff) << 0 | + ((t[3] >> (8*k)) & 0xff) << 8 | + ((t[5] >> (8*k)) & 0xff) << 16 | + ((t[7] >> (8*k)) & 0xff) << 24; +} + +static void +do_a (u32 *u) +{ + u32 t[2]; + int i; + memcpy(t, u, 2*4); + for (i = 0; i < 6; i++) + u[i] = u[i+2]; + u[6] = u[0] ^ t[0]; + u[7] = u[1] ^ t[1]; +} +/* apply do_a twice: 1 2 3 4 -> 3 4 1^2 2^3 */ +static void +do_a2 (u32 *u) +{ + u32 t[4]; + int i; + memcpy (t, u, 16); + memcpy (u, u + 4, 16); + for (i = 0; i < 2; i++) + { + u[4+i] = t[i] ^ t[i + 2]; + u[6+i] = u[i] ^ t[i + 2]; + } +} + +static void +do_apply_c2 (u32 *u) +{ + u[ 0] ^= 0xff00ff00; + u[ 1] ^= 0xff00ff00; + u[ 2] ^= 0x00ff00ff; + u[ 3] ^= 0x00ff00ff; + u[ 4] ^= 0x00ffff00; + u[ 5] ^= 0xff0000ff; + u[ 6] ^= 0x000000ff; + u[ 7] ^= 0xff00ffff; +} + +#define do_chi_step12(e) \ + e[6] ^= ((e[6] >> 16) ^ e[7] ^ (e[7] >> 16) ^ e[4] ^ (e[5] >>16)) & 0xffff; + +#define do_chi_step13(e) \ + e[6] ^= ((e[7] ^ (e[7] >> 16) ^ e[0] ^ (e[4] >> 16) ^ e[6]) & 0xffff) << 16; + +#define do_chi_doublestep(e, i) \ + e[i] ^= (e[i] >> 16) ^ (e[(i+1)%8] << 16) ^ e[(i+1)%8] ^ (e[(i+1)%8] >> 16) ^ (e[(i+2)%8] << 16) ^ e[(i+6)%8] ^ (e[(i+7)%8] >> 16); \ + e[i] ^= (e[i] << 16); + +static void +do_chi_submix12 (u32 *e, u32 *x) +{ + e[6] ^= x[0]; + e[7] ^= x[1]; + e[0] ^= x[2]; + e[1] ^= x[3]; + e[2] ^= x[4]; + e[3] ^= x[5]; + e[4] ^= x[6]; + e[5] ^= x[7]; +} + +static void +do_chi_submix13 (u32 *e, u32 *x) +{ + e[6] ^= (x[0] << 16) | (x[7] >> 16); + e[7] ^= (x[1] << 16) | (x[0] >> 16); + e[0] ^= (x[2] << 16) | (x[1] >> 16); + e[1] ^= (x[3] << 16) | (x[2] >> 16); + e[2] ^= (x[4] << 16) | (x[3] >> 16); + e[3] ^= (x[5] << 16) | (x[4] >> 16); + e[4] ^= (x[6] << 16) | (x[5] >> 16); + e[5] ^= (x[7] << 16) | (x[6] >> 16); +} + +static void +do_add (u32 *s, u32 *a) +{ + u32 carry = 0; + int i; + + for (i = 0; i < 8; i++) + { + u32 op = carry + a[i]; + s[i] += op; + carry = (a[i] > op) || (op > s[i]); + } +} + +static unsigned int +do_hash_step (GOSTR3411_CONTEXT *hd, u32 *h, u32 *m) +{ + u32 u[8], v[8]; + u32 s[8]; + u32 k[8]; + unsigned int burn; + int i; + + memcpy (u, h, 32); + memcpy (v, m, 32); + + for (i = 0; i < 4; i++) { + do_p (k, u, v); + + burn = _gcry_gost_enc_data (k, &s[2*i], &s[2*i+1], h[2*i], h[2*i+1], hd->cryptopro); + + do_a (u); + if (i == 1) + do_apply_c2 (u); + do_a2 (v); + } + + for (i = 0; i < 5; i++) + { + do_chi_doublestep (s, 0); + do_chi_doublestep (s, 1); + do_chi_doublestep (s, 2); + do_chi_doublestep (s, 3); + do_chi_doublestep (s, 4); + /* That is in total 12 + 1 + 61 = 74 = 16 * 4 + 10 rounds */ + if (i == 4) + break; + do_chi_doublestep (s, 5); + if (i == 0) + do_chi_submix12(s, m); + do_chi_step12 (s); + if (i == 0) + do_chi_submix13(s, h); + do_chi_step13 (s); + do_chi_doublestep (s, 7); + } + + memcpy (h, s+5, 12); + memcpy (h+3, s, 20); + + return /* burn_stack */ 4 * sizeof(void*) /* func call (ret addr + args) */ + + 4 * 32 + 2 * sizeof(int) /* stack */ + + max(burn /* _gcry_gost_enc_one */, + sizeof(void*) * 2 /* do_a2 call */ + + 16 + sizeof(int) /* do_a2 stack */ ); +} + +static unsigned int +transform_blk (void *ctx, const unsigned char *data) +{ + GOSTR3411_CONTEXT *hd = ctx; + u32 m[8]; + unsigned int burn; + int i; + + for (i = 0; i < 8; i++) + m[i] = buf_get_le32(data + i*4); + burn = do_hash_step (hd, hd->h, m); + do_add (hd->sigma, m); + + return /* burn_stack */ burn + 3 * sizeof(void*) + 32 + 2 * sizeof(void*); +} + + +static unsigned int +transform ( void *c, const unsigned char *data, size_t nblks ) +{ + unsigned int burn; + + do + { + burn = transform_blk (c, data); + data += 32; + } + while (--nblks); + + return burn; +} + + +/* + The routine finally terminates the computation and returns the + digest. The handle is prepared for a new cycle, but adding bytes + to the handle will the destroy the returned buffer. Returns: 32 + bytes with the message the digest. */ +static void +gost3411_final (void *context) +{ + GOSTR3411_CONTEXT *hd = context; + size_t padlen = 0; + u32 l[8]; + int i; + MD_NBLOCKS_TYPE nblocks; + + if (hd->bctx.count > 0) + { + padlen = 32 - hd->bctx.count; + memset (hd->bctx.buf + hd->bctx.count, 0, padlen); + hd->bctx.count += padlen; + _gcry_md_block_write (hd, NULL, 0); /* flush */; + } + + if (hd->bctx.count != 0) + return; /* Something went wrong */ + + memset (l, 0, 32); + + nblocks = hd->bctx.nblocks; + if (padlen) + { + nblocks --; + l[0] = 256 - padlen * 8; + } + l[0] |= nblocks << 8; + nblocks >>= 24; + + for (i = 1; i < 8 && nblocks != 0; i++) + { + l[i] = nblocks; + nblocks >>= 24; + } + + do_hash_step (hd, hd->h, l); + do_hash_step (hd, hd->h, hd->sigma); + for (i = 0; i < 8; i++) + hd->h[i] = le_bswap32(hd->h[i]); +} + +static byte * +gost3411_read (void *context) +{ + GOSTR3411_CONTEXT *hd = context; + + return hd->result; +} + +static unsigned char asn[6] = /* Object ID is 1.2.643.2.2.3 */ + { 0x2a, 0x85, 0x03, 0x02, 0x02, 0x03 }; + +static gcry_md_oid_spec_t oid_spec_gostr3411[] = + { + /* iso.member-body.ru.rans.cryptopro.3 (gostR3411-94-with-gostR3410-2001) */ + { "1.2.643.2.2.3" }, + /* iso.member-body.ru.rans.cryptopro.9 (gostR3411-94) */ + { "1.2.643.2.2.9" }, + {NULL}, + }; + +gcry_md_spec_t _gcry_digest_spec_gost3411_94 = + { + GCRY_MD_GOSTR3411_94, {0, 0}, + "GOSTR3411_94", NULL, 0, NULL, 32, + gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read, NULL, + NULL, NULL, + sizeof (GOSTR3411_CONTEXT) + }; +gcry_md_spec_t _gcry_digest_spec_gost3411_cp = + { + GCRY_MD_GOSTR3411_CP, {0, 0}, + "GOSTR3411_CP", asn, DIM (asn), oid_spec_gostr3411, 32, + gost3411_cp_init, _gcry_md_block_write, gost3411_final, gost3411_read, NULL, + NULL, NULL, + sizeof (GOSTR3411_CONTEXT) + }; diff --git a/comm/third_party/libgcrypt/cipher/hash-common.c b/comm/third_party/libgcrypt/cipher/hash-common.c new file mode 100644 index 0000000000..ed2d7cacd1 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/hash-common.c @@ -0,0 +1,193 @@ +/* hash-common.c - Common code for hash algorithms + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +# include +#endif + +#include "g10lib.h" +#include "bufhelp.h" +#include "hash-common.h" + + +/* Run a selftest for hash algorithm ALGO. If the resulting digest + matches EXPECT/EXPECTLEN and everything else is fine as well, + return NULL. If an error occurs, return a static text string + describing the error. + + DATAMODE controls what will be hashed according to this table: + + 0 - Hash the supplied DATA of DATALEN. + 1 - Hash one million times a 'a'. DATA and DATALEN are ignored. + +*/ +const char * +_gcry_hash_selftest_check_one (int algo, + int datamode, const void *data, size_t datalen, + const void *expect, size_t expectlen) +{ + const char *result = NULL; + gcry_error_t err = 0; + gcry_md_hd_t hd; + unsigned char *digest; + char aaa[1000]; + int xof = 0; + + if (_gcry_md_get_algo_dlen (algo) == 0) + xof = 1; + else if (_gcry_md_get_algo_dlen (algo) != expectlen) + return "digest size does not match expected size"; + + err = _gcry_md_open (&hd, algo, 0); + if (err) + return "gcry_md_open failed"; + + switch (datamode) + { + case 0: + _gcry_md_write (hd, data, datalen); + break; + + case 1: /* Hash one million times an "a". */ + { + int i; + + /* Write in odd size chunks so that we test the buffering. */ + memset (aaa, 'a', 1000); + for (i = 0; i < 1000; i++) + _gcry_md_write (hd, aaa, 1000); + } + break; + + default: + result = "invalid DATAMODE"; + } + + if (!result) + { + if (!xof) + { + digest = _gcry_md_read (hd, algo); + + if ( memcmp (digest, expect, expectlen) ) + result = "digest mismatch"; + } + else + { + gcry_assert(expectlen <= sizeof(aaa)); + + err = _gcry_md_extract (hd, algo, aaa, expectlen); + if (err) + result = "error extracting output from XOF"; + else if ( memcmp (aaa, expect, expectlen) ) + result = "digest mismatch"; + } + } + + _gcry_md_close (hd); + + return result; +} + + +/* Common function to write a chunk of data to the transform function + of a hash algorithm. Note that the use of the term "block" does + not imply a fixed size block. Note that we explicitly allow to use + this function after the context has been finalized; the result does + not have any meaning but writing after finalize is sometimes + helpful to mitigate timing attacks. */ +void +_gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen) +{ + const unsigned char *inbuf = inbuf_arg; + gcry_md_block_ctx_t *hd = context; + unsigned int stack_burn = 0; + unsigned int nburn; + const unsigned int blocksize_shift = hd->blocksize_shift; + const unsigned int blocksize = 1 << blocksize_shift; + size_t inblocks; + size_t copylen; + + if (sizeof(hd->buf) < blocksize) + BUG(); + + if (!hd->bwrite) + return; + + if (hd->count > blocksize) + { + /* This happens only when gcry_md_write is called after final. + * Writing after final is used for mitigating timing attacks. */ + hd->count = 0; + } + + while (hd->count) + { + if (hd->count == blocksize) /* Flush the buffer. */ + { + nburn = hd->bwrite (hd, hd->buf, 1); + stack_burn = nburn > stack_burn ? nburn : stack_burn; + hd->count = 0; + if (!++hd->nblocks) + hd->nblocks_high++; + } + else + { + copylen = inlen; + if (copylen > blocksize - hd->count) + copylen = blocksize - hd->count; + + if (copylen == 0) + break; + + buf_cpy (&hd->buf[hd->count], inbuf, copylen); + hd->count += copylen; + inbuf += copylen; + inlen -= copylen; + } + } + + if (inlen == 0) + return; + + if (inlen >= blocksize) + { + inblocks = inlen >> blocksize_shift; + nburn = hd->bwrite (hd, inbuf, inblocks); + stack_burn = nburn > stack_burn ? nburn : stack_burn; + hd->count = 0; + hd->nblocks_high += (hd->nblocks + inblocks < inblocks); + hd->nblocks += inblocks; + inlen -= inblocks << blocksize_shift; + inbuf += inblocks << blocksize_shift; + } + + if (inlen) + { + buf_cpy (hd->buf, inbuf, inlen); + hd->count = inlen; + } + + if (stack_burn > 0) + _gcry_burn_stack (stack_burn); +} diff --git a/comm/third_party/libgcrypt/cipher/hash-common.h b/comm/third_party/libgcrypt/cipher/hash-common.h new file mode 100644 index 0000000000..561e77a7e5 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/hash-common.h @@ -0,0 +1,62 @@ +/* hash-common.h - Declarations of common code for hash algorithms. + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_HASH_COMMON_H +#define GCRY_HASH_COMMON_H + +#include "types.h" + + +const char * _gcry_hash_selftest_check_one +/**/ (int algo, + int datamode, const void *data, size_t datalen, + const void *expect, size_t expectlen); + +/* Type for the md_write helper function. */ +typedef unsigned int (*_gcry_md_block_write_t) (void *c, + const unsigned char *blks, + size_t nblks); + +#if (defined(USE_SHA512) || defined(USE_WHIRLPOOL)) +/* SHA-512 and Whirlpool needs u64. SHA-512 needs larger buffer. */ +# define MD_BLOCK_MAX_BLOCKSIZE 128 +# define MD_NBLOCKS_TYPE u64 +#else +# define MD_BLOCK_MAX_BLOCKSIZE 64 +# define MD_NBLOCKS_TYPE u32 +#endif + +/* SHA1 needs 2x64 bytes and SHA-512 needs 128 bytes. */ +#define MD_BLOCK_CTX_BUFFER_SIZE 128 + +typedef struct gcry_md_block_ctx +{ + byte buf[MD_BLOCK_CTX_BUFFER_SIZE]; + MD_NBLOCKS_TYPE nblocks; + MD_NBLOCKS_TYPE nblocks_high; + int count; + unsigned int blocksize_shift; + _gcry_md_block_write_t bwrite; +} gcry_md_block_ctx_t; + + +void +_gcry_md_block_write( void *context, const void *inbuf_arg, size_t inlen); + +#endif /*GCRY_HASH_COMMON_H*/ diff --git a/comm/third_party/libgcrypt/cipher/idea.c b/comm/third_party/libgcrypt/cipher/idea.c new file mode 100644 index 0000000000..0a81081810 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/idea.c @@ -0,0 +1,382 @@ +/* idea.c - IDEA function + * Copyright 1997, 1998, 1999, 2001 Werner Koch (dd9jn) + * Copyright 2013 g10 Code GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * WERNER KOCH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Werner Koch shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Werner Koch. + * + * Patents on IDEA have expired: + * Europe: EP0482154 on 2011-05-16, + * Japan: JP3225440 on 2011-05-16, + * U.S.: 5,214,703 on 2012-01-07. + */ + +/* + * Please see http://www.noepatents.org/ to learn why software patents + * are bad for society and what you can do to fight them. + * + * The code herein is based on the one from: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. + */ + + +#include +#include +#include +#include +#include + +#include "types.h" /* for byte and u32 typedefs */ +#include "g10lib.h" +#include "cipher.h" +#include "cipher-internal.h" + + +#define IDEA_KEYSIZE 16 +#define IDEA_BLOCKSIZE 8 +#define IDEA_ROUNDS 8 +#define IDEA_KEYLEN (6*IDEA_ROUNDS+4) + +typedef struct { + u16 ek[IDEA_KEYLEN]; + u16 dk[IDEA_KEYLEN]; + int have_dk; +} IDEA_context; + +static const char *selftest(void); + + +static u16 +mul_inv( u16 x ) +{ + u16 t0, t1; + u16 q, y; + + if( x < 2 ) + return x; + t1 = 0x10001UL / x; + y = 0x10001UL % x; + if( y == 1 ) + return (1-t1) & 0xffff; + + t0 = 1; + do { + q = x / y; + x = x % y; + t0 += q * t1; + if( x == 1 ) + return t0; + q = y / x; + y = y % x; + t1 += q * t0; + } while( y != 1 ); + return (1-t1) & 0xffff; +} + + + +static void +expand_key( const byte *userkey, u16 *ek ) +{ + int i,j; + + for(j=0; j < 8; j++ ) { + ek[j] = (*userkey << 8) + userkey[1]; + userkey += 2; + } + for(i=0; j < IDEA_KEYLEN; j++ ) { + i++; + ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7; + ek += i & 8; + i &= 7; + } +} + + +static void +invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] ) +{ + int i; + u16 t1, t2, t3; + u16 temp[IDEA_KEYLEN]; + u16 *p = temp + IDEA_KEYLEN; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + + for(i=0; i < IDEA_ROUNDS-1; i++ ) { + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t2; + *--p = t3; + *--p = t1; + } + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + memcpy(dk, temp, sizeof(temp) ); + wipememory(temp, sizeof(temp)); +} + + +static void +cipher( byte *outbuf, const byte *inbuf, u16 *key ) +{ + u16 s2, s3; + u16 in[4]; + int r = IDEA_ROUNDS; +#define x1 (in[0]) +#define x2 (in[1]) +#define x3 (in[2]) +#define x4 (in[3]) +#define MUL(x,y) \ + do {u16 _t16; u32 _t32; \ + if( (_t16 = (y)) ) { \ + if( (x = (x)&0xffff) ) { \ + _t32 = (u32)x * _t16; \ + x = _t32 & 0xffff; \ + _t16 = _t32 >> 16; \ + x = ((x)-_t16) + (x<_t16?1:0); \ + } \ + else { \ + x = 1 - _t16; \ + } \ + } \ + else { \ + x = 1 - x; \ + } \ + } while(0) + + memcpy (in, inbuf, sizeof in); +#ifndef WORDS_BIGENDIAN + x1 = (x1>>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); +#endif + do { + MUL(x1, *key++); + x2 += *key++; + x3 += *key++; + MUL(x4, *key++ ); + + s3 = x3; + x3 ^= x1; + MUL(x3, *key++); + s2 = x2; + x2 ^=x4; + x2 += x3; + MUL(x2, *key++); + x3 += x2; + + x1 ^= x2; + x4 ^= x3; + + x2 ^= s3; + x3 ^= s2; + } while( --r ); + MUL(x1, *key++); + x3 += *key++; + x2 += *key++; + MUL(x4, *key); + +#ifndef WORDS_BIGENDIAN + x1 = (x1>>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); +#endif + memcpy (outbuf+0, &x1, 2); + memcpy (outbuf+2, &x3, 2); + memcpy (outbuf+4, &x2, 2); + memcpy (outbuf+6, &x4, 2); +#undef MUL +#undef x1 +#undef x2 +#undef x3 +#undef x4 +} + + +static int +do_setkey( IDEA_context *c, const byte *key, unsigned int keylen ) +{ + static int initialized = 0; + static const char *selftest_failed = 0; + + if( !initialized ) { + initialized = 1; + selftest_failed = selftest(); + if( selftest_failed ) + log_error( "%s\n", selftest_failed ); + } + if( selftest_failed ) + return GPG_ERR_SELFTEST_FAILED; + + assert(keylen == 16); + c->have_dk = 0; + expand_key( key, c->ek ); + invert_key( c->ek, c->dk ); + return 0; +} + +static gcry_err_code_t +idea_setkey (void *context, const byte *key, unsigned int keylen, + cipher_bulk_ops_t *bulk_ops) +{ + IDEA_context *ctx = context; + int rc = do_setkey (ctx, key, keylen); + (void)bulk_ops; + _gcry_burn_stack (23+6*sizeof(void*)); + return rc; +} + +static void +encrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf ) +{ + cipher( outbuf, inbuf, c->ek ); +} + +static unsigned int +idea_encrypt (void *context, byte *out, const byte *in) +{ + IDEA_context *ctx = context; + encrypt_block (ctx, out, in); + return /*burn_stack*/ (24+3*sizeof (void*)); +} + +static void +decrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf ) +{ + if( !c->have_dk ) { + c->have_dk = 1; + invert_key( c->ek, c->dk ); + } + cipher( outbuf, inbuf, c->dk ); +} + +static unsigned int +idea_decrypt (void *context, byte *out, const byte *in) +{ + IDEA_context *ctx = context; + decrypt_block (ctx, out, in); + return /*burn_stack*/ (24+3*sizeof (void*)); +} + + +static const char * +selftest( void ) +{ +static struct { + byte key[16]; + byte plain[8]; + byte cipher[8]; +} test_vectors[] = { + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 }, + { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }, + { 0x54, 0x0E, 0x5F, 0xEA, 0x18, 0xC2, 0xF8, 0xB1 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x00, 0x19, 0x32, 0x4B, 0x64, 0x7D, 0x96, 0xAF }, + { 0x9F, 0x0A, 0x0A, 0xB6, 0xE1, 0x0C, 0xED, 0x78 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0xF5, 0x20, 0x2D, 0x5B, 0x9C, 0x67, 0x1B, 0x08 }, + { 0xCF, 0x18, 0xFD, 0x73, 0x55, 0xE2, 0xC5, 0xC5 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0xFA, 0xE6, 0xD2, 0xBE, 0xAA, 0x96, 0x82, 0x6E }, + { 0x85, 0xDF, 0x52, 0x00, 0x56, 0x08, 0x19, 0x3D } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x0A, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x46, 0x50 }, + { 0x2F, 0x7D, 0xE7, 0x50, 0x21, 0x2F, 0xB7, 0x34 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x05, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x23, 0x28 }, + { 0x7B, 0x73, 0x14, 0x92, 0x5D, 0xE5, 0x9C, 0x09 } }, + { { 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x14, + 0x00, 0x19, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x28 }, + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }, + { 0x3E, 0xC0, 0x47, 0x80, 0xBE, 0xFF, 0x6E, 0x20 } }, + { { 0x3A, 0x98, 0x4E, 0x20, 0x00, 0x19, 0x5D, 0xB3, + 0x2E, 0xE5, 0x01, 0xC8, 0xC4, 0x7C, 0xEA, 0x60 }, + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }, + { 0x97, 0xBC, 0xD8, 0x20, 0x07, 0x80, 0xDA, 0x86 } }, + { { 0x00, 0x64, 0x00, 0xC8, 0x01, 0x2C, 0x01, 0x90, + 0x01, 0xF4, 0x02, 0x58, 0x02, 0xBC, 0x03, 0x20 }, + { 0x05, 0x32, 0x0A, 0x64, 0x14, 0xC8, 0x19, 0xFA }, + { 0x65, 0xBE, 0x87, 0xE7, 0xA2, 0x53, 0x8A, 0xED } }, + { { 0x9D, 0x40, 0x75, 0xC1, 0x03, 0xBC, 0x32, 0x2A, + 0xFB, 0x03, 0xE7, 0xBE, 0x6A, 0xB3, 0x00, 0x06 }, + { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, + { 0xF5, 0xDB, 0x1A, 0xC4, 0x5E, 0x5E, 0xF9, 0xF9 } } +}; + IDEA_context c; + byte buffer[8]; + int i; + + for(i=0; i < DIM(test_vectors); i++ ) { + do_setkey( &c, test_vectors[i].key, 16 ); + encrypt_block( &c, buffer, test_vectors[i].plain ); + if( memcmp( buffer, test_vectors[i].cipher, 8 ) ) + return "IDEA test encryption failed."; + decrypt_block( &c, buffer, test_vectors[i].cipher ); + if( memcmp( buffer, test_vectors[i].plain, 8 ) ) + return "IDEA test decryption failed."; + } + + return NULL; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_idea = + { + GCRY_CIPHER_IDEA, {0, 0}, + "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128, + sizeof (IDEA_context), + idea_setkey, idea_encrypt, idea_decrypt + }; diff --git a/comm/third_party/libgcrypt/cipher/kdf-internal.h b/comm/third_party/libgcrypt/cipher/kdf-internal.h new file mode 100644 index 0000000000..7079860e99 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/kdf-internal.h @@ -0,0 +1,40 @@ +/* kdf-internal.h - Internal defs for kdf.c + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_KDF_INTERNAL_H +#define GCRY_KDF_INTERNAL_H + +/*-- kdf.c --*/ +gpg_err_code_t +_gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen, + int hashalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer); + +/*-- scrypt.c --*/ +gcry_err_code_t +_gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen, + int algo, int subalgo, + const unsigned char *salt, size_t saltlen, + unsigned long iterations, + size_t dklen, unsigned char *dk); + + +#endif /*GCRY_KDF_INTERNAL_H*/ diff --git a/comm/third_party/libgcrypt/cipher/kdf.c b/comm/third_party/libgcrypt/cipher/kdf.c new file mode 100644 index 0000000000..93c2c9f65e --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/kdf.c @@ -0,0 +1,503 @@ +/* kdf.c - Key Derivation Functions + * Copyright (C) 1998, 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "kdf-internal.h" + + +/* Transform a passphrase into a suitable key of length KEYSIZE and + store this key in the caller provided buffer KEYBUFFER. The caller + must provide an HASHALGO, a valid ALGO and depending on that algo a + SALT of 8 bytes and the number of ITERATIONS. Code taken from + gnupg/agent/protect.c:hash_passphrase. */ +static gpg_err_code_t +openpgp_s2k (const void *passphrase, size_t passphraselen, + int algo, int hashalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer) +{ + gpg_err_code_t ec; + gcry_md_hd_t md; + char *key = keybuffer; + int pass, i; + int used = 0; + int secmode; + + if ((algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K) + && (!salt || saltlen != 8)) + return GPG_ERR_INV_VALUE; + + secmode = _gcry_is_secure (passphrase) || _gcry_is_secure (keybuffer); + + ec = _gcry_md_open (&md, hashalgo, secmode? GCRY_MD_FLAG_SECURE : 0); + if (ec) + return ec; + + for (pass=0; used < keysize; pass++) + { + if (pass) + { + _gcry_md_reset (md); + for (i=0; i < pass; i++) /* Preset the hash context. */ + _gcry_md_putc (md, 0); + } + + if (algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K) + { + int len2 = passphraselen + 8; + unsigned long count = len2; + + if (algo == GCRY_KDF_ITERSALTED_S2K) + { + count = iterations; + if (count < len2) + count = len2; + } + + while (count > len2) + { + _gcry_md_write (md, salt, saltlen); + _gcry_md_write (md, passphrase, passphraselen); + count -= len2; + } + if (count < saltlen) + _gcry_md_write (md, salt, count); + else + { + _gcry_md_write (md, salt, saltlen); + count -= saltlen; + _gcry_md_write (md, passphrase, count); + } + } + else + _gcry_md_write (md, passphrase, passphraselen); + + _gcry_md_final (md); + i = _gcry_md_get_algo_dlen (hashalgo); + if (i > keysize - used) + i = keysize - used; + memcpy (key+used, _gcry_md_read (md, hashalgo), i); + used += i; + } + _gcry_md_close (md); + return 0; +} + + +/* Transform a passphrase into a suitable key of length KEYSIZE and + store this key in the caller provided buffer KEYBUFFER. The caller + must provide PRFALGO which indicates the pseudorandom function to + use: This shall be the algorithms id of a hash algorithm; it is + used in HMAC mode. SALT is a salt of length SALTLEN and ITERATIONS + gives the number of iterations. */ +gpg_err_code_t +_gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen, + int hashalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer) +{ + gpg_err_code_t ec; + gcry_md_hd_t md; + int secmode; + unsigned long dklen = keysize; + char *dk = keybuffer; + unsigned int hlen; /* Output length of the digest function. */ + unsigned int l; /* Rounded up number of blocks. */ + unsigned int r; /* Number of octets in the last block. */ + char *sbuf; /* Malloced buffer to concatenate salt and iter + as well as space to hold TBUF and UBUF. */ + char *tbuf; /* Buffer for T; ptr into SBUF, size is HLEN. */ + char *ubuf; /* Buffer for U; ptr into SBUF, size is HLEN. */ + unsigned int lidx; /* Current block number. */ + unsigned long iter; /* Current iteration number. */ + unsigned int i; + + /* We allow for a saltlen of 0 here to support scrypt. It is not + clear whether rfc2898 allows for this this, thus we do a test on + saltlen > 0 only in gcry_kdf_derive. */ + if (!salt || !iterations || !dklen) + return GPG_ERR_INV_VALUE; + + hlen = _gcry_md_get_algo_dlen (hashalgo); + if (!hlen) + return GPG_ERR_DIGEST_ALGO; + + secmode = _gcry_is_secure (passphrase) || _gcry_is_secure (keybuffer); + + /* Step 1 */ + /* If dkLen > (2^32 - 1) * hLen, output "derived key too long" and + * stop. We use a stronger inequality but only if our type can hold + * a larger value. */ + +#if SIZEOF_UNSIGNED_LONG > 4 + if (dklen > 0xffffffffU) + return GPG_ERR_INV_VALUE; +#endif + + + /* Step 2 */ + l = ((dklen - 1)/ hlen) + 1; + r = dklen - (l - 1) * hlen; + + /* Setup buffers and prepare a hash context. */ + sbuf = (secmode + ? xtrymalloc_secure (saltlen + 4 + hlen + hlen) + : xtrymalloc (saltlen + 4 + hlen + hlen)); + if (!sbuf) + return gpg_err_code_from_syserror (); + tbuf = sbuf + saltlen + 4; + ubuf = tbuf + hlen; + + ec = _gcry_md_open (&md, hashalgo, (GCRY_MD_FLAG_HMAC + | (secmode?GCRY_MD_FLAG_SECURE:0))); + if (ec) + { + xfree (sbuf); + return ec; + } + + ec = _gcry_md_setkey (md, passphrase, passphraselen); + if (ec) + { + _gcry_md_close (md); + xfree (sbuf); + return ec; + } + + /* Step 3 and 4. */ + memcpy (sbuf, salt, saltlen); + for (lidx = 1; lidx <= l; lidx++) + { + for (iter = 0; iter < iterations; iter++) + { + _gcry_md_reset (md); + if (!iter) /* Compute U_1: */ + { + sbuf[saltlen] = (lidx >> 24); + sbuf[saltlen + 1] = (lidx >> 16); + sbuf[saltlen + 2] = (lidx >> 8); + sbuf[saltlen + 3] = lidx; + _gcry_md_write (md, sbuf, saltlen + 4); + memcpy (ubuf, _gcry_md_read (md, 0), hlen); + memcpy (tbuf, ubuf, hlen); + } + else /* Compute U_(2..c): */ + { + _gcry_md_write (md, ubuf, hlen); + memcpy (ubuf, _gcry_md_read (md, 0), hlen); + for (i=0; i < hlen; i++) + tbuf[i] ^= ubuf[i]; + } + } + if (lidx == l) /* Last block. */ + memcpy (dk, tbuf, r); + else + { + memcpy (dk, tbuf, hlen); + dk += hlen; + } + } + + _gcry_md_close (md); + xfree (sbuf); + return 0; +} + + +/* Derive a key from a passphrase. KEYSIZE gives the requested size + of the keys in octets. KEYBUFFER is a caller provided buffer + filled on success with the derived key. The input passphrase is + taken from (PASSPHRASE,PASSPHRASELEN) which is an arbitrary memory + buffer. ALGO specifies the KDF algorithm to use; these are the + constants GCRY_KDF_*. SUBALGO specifies an algorithm used + internally by the KDF algorithms; this is usually a hash algorithm + but certain KDF algorithm may use it differently. {SALT,SALTLEN} + is a salt as needed by most KDF algorithms. ITERATIONS is a + positive integer parameter to most KDFs. 0 is returned on success, + or an error code on failure. */ +gpg_err_code_t +_gcry_kdf_derive (const void *passphrase, size_t passphraselen, + int algo, int subalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer) +{ + gpg_err_code_t ec; + + if (!passphrase) + { + ec = GPG_ERR_INV_DATA; + goto leave; + } + + if (!keybuffer || !keysize) + { + ec = GPG_ERR_INV_VALUE; + goto leave; + } + + + switch (algo) + { + case GCRY_KDF_SIMPLE_S2K: + case GCRY_KDF_SALTED_S2K: + case GCRY_KDF_ITERSALTED_S2K: + if (!passphraselen) + ec = GPG_ERR_INV_DATA; + else + ec = openpgp_s2k (passphrase, passphraselen, algo, subalgo, + salt, saltlen, iterations, keysize, keybuffer); + break; + + case GCRY_KDF_PBKDF1: + ec = GPG_ERR_UNSUPPORTED_ALGORITHM; + break; + + case GCRY_KDF_PBKDF2: + if (!saltlen) + ec = GPG_ERR_INV_VALUE; + else + ec = _gcry_kdf_pkdf2 (passphrase, passphraselen, subalgo, + salt, saltlen, iterations, keysize, keybuffer); + break; + + case 41: + case GCRY_KDF_SCRYPT: +#if USE_SCRYPT + ec = _gcry_kdf_scrypt (passphrase, passphraselen, algo, subalgo, + salt, saltlen, iterations, keysize, keybuffer); +#else + ec = GPG_ERR_UNSUPPORTED_ALGORITHM; +#endif /*USE_SCRYPT*/ + break; + + default: + ec = GPG_ERR_UNKNOWN_ALGORITHM; + break; + } + + leave: + return ec; +} + + +/* Check one KDF call with ALGO and HASH_ALGO using the regular KDF + * API. (passphrase,passphraselen) is the password to be derived, + * (salt,saltlen) the salt for the key derivation, + * iterations is the number of the kdf iterations, + * and (expect,expectlen) the expected result. Returns NULL on + * success or a string describing the failure. */ + +static const char * +check_one (int algo, int hash_algo, + const void *passphrase, size_t passphraselen, + const void *salt, size_t saltlen, + unsigned long iterations, + const void *expect, size_t expectlen) +{ + unsigned char key[512]; /* hardcoded to avoid allocation */ + size_t keysize = expectlen; + + if (keysize > sizeof(key)) + return "invalid tests data"; + + if (_gcry_kdf_derive (passphrase, passphraselen, algo, + hash_algo, salt, saltlen, iterations, + keysize, key)) + return "gcry_kdf_derive failed"; + + if (memcmp (key, expect, expectlen)) + return "does not match"; + + return NULL; +} + + +static gpg_err_code_t +selftest_pbkdf2 (int extended, selftest_report_func_t report) +{ + static const struct { + const char *desc; + const char *p; /* Passphrase. */ + size_t plen; /* Length of P. */ + const char *salt; + size_t saltlen; + int hashalgo; + unsigned long c; /* Iterations. */ + int dklen; /* Requested key length. */ + const char *dk; /* Derived key. */ + int disabled; + } tv[] = { +#if USE_SHA1 +#define NUM_TEST_VECTORS 9 + /* SHA1 test vectors are from RFC-6070. */ + { + "Basic PBKDF2 SHA1 #1", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 1, + 20, + "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9" + "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6" + }, + { + "Basic PBKDF2 SHA1 #2", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 2, + 20, + "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e" + "\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57" + }, + { + "Basic PBKDF2 SHA1 #3", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 4096, + 20, + "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad" + "\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1" + }, + { + "Basic PBKDF2 SHA1 #4", + "password", 8, + "salt", 4, + GCRY_MD_SHA1, + 16777216, + 20, + "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94" + "\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", + 1 /* This test takes too long. */ + }, + { + "Basic PBKDF2 SHA1 #5", + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_SHA1, + 4096, + 25, + "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8" + "\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96" + "\x4c\xf2\xf0\x70\x38" + }, + { + "Basic PBKDF2 SHA1 #6", + "pass\0word", 9, + "sa\0lt", 5, + GCRY_MD_SHA1, + 4096, + 16, + "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37" + "\xd7\xf0\x34\x25\xe0\xc3" + }, + { /* empty password test, not in RFC-6070 */ + "Basic PBKDF2 SHA1 #7", + "", 0, + "salt", 4, + GCRY_MD_SHA1, + 2, + 20, + "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2" + "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97" + }, +#else +#define NUM_TEST_VECTORS 2 +#endif + { + "Basic PBKDF2 SHA256", + "password", 8, + "salt", 4, + GCRY_MD_SHA256, + 2, + 32, + "\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9\x28\xf0\x6d\xd0" + "\x2a\x30\x3f\x8e\xf3\xc2\x51\xdf\xd6\xe2\xd8\x5a\x95\x47\x4c\x43" + }, + { + "Extended PBKDF2 SHA256", + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_SHA256, + 4096, + 40, + "\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11\x6e\x84\xcf" + "\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c\x4e\x2a\x1f\xb8\xdd\x53\xe1" + "\xc6\x35\x51\x8c\x7d\xac\x47\xe9" + }, + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + if (tv[tvidx].disabled) + continue; + errtxt = check_one (GCRY_KDF_PBKDF2, tv[tvidx].hashalgo, + tv[tvidx].p, tv[tvidx].plen, + tv[tvidx].salt, tv[tvidx].saltlen, + tv[tvidx].c, + tv[tvidx].dk, tv[tvidx].dklen); + if (errtxt) + goto failed; + if (tvidx >= NUM_TEST_VECTORS - 1 && !extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("kdf", GCRY_KDF_PBKDF2, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Run the selftests for KDF with KDF algorithm ALGO with optional + reporting function REPORT. */ +gpg_error_t +_gcry_kdf_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_err_code_t ec = 0; + + if (algo == GCRY_KDF_PBKDF2) + ec = selftest_pbkdf2 (extended, report); + else + { + ec = GPG_ERR_UNSUPPORTED_ALGORITHM; + if (report) + report ("kdf", algo, "module", "algorithm not available"); + } + return gpg_error (ec); +} diff --git a/comm/third_party/libgcrypt/cipher/keccak-armv7-neon.S b/comm/third_party/libgcrypt/cipher/keccak-armv7-neon.S new file mode 100644 index 0000000000..0bec8d50a9 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/keccak-armv7-neon.S @@ -0,0 +1,945 @@ +/* keccak-armv7-neon.S - ARMv7/NEON implementation of Keccak + * + * Copyright (C) 2015 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) && \ + defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_NEON) + +/* Based on public-domain/CC0 implementation from SUPERCOP package + * (keccakc1024/inplace-armv7a-neon/keccak2.s) + * + * Original copyright header follows: + */ + +@ The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +@ Michaël Peeters and Gilles Van Assche. For more information, feedback or +@ questions, please refer to our website: http://keccak.noekeon.org/ +@ +@ Implementation by Ronny Van Keer, hereby denoted as "the implementer". +@ +@ To the extent possible under law, the implementer has waived all copyright +@ and related or neighboring rights to the source code in this file. +@ http://creativecommons.org/publicdomain/zero/1.0/ + +.text + +.syntax unified +.fpu neon +.arm + + +.extern _gcry_keccak_round_consts_64bit; + +#ifdef __PIC__ +# define GET_DATA_POINTER(reg, name, rtmp) \ + ldr reg, 1f; \ + ldr rtmp, 2f; \ + b 3f; \ + 1: .word _GLOBAL_OFFSET_TABLE_-(3f+8); \ + 2: .word name(GOT); \ + 3: add reg, pc, reg; \ + ldr reg, [reg, rtmp]; +#else +# define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name +#endif + + +@// --- offsets in state +.equ Aba, 0*8 +.equ Aga, 1*8 +.equ Aka, 2*8 +.equ Ama, 3*8 +.equ Asa, 4*8 + +@// --- macros + +.macro KeccakThetaRhoPiChiIota argA1, argA2, argA3, argA4, argA5 + + @Prepare Theta + @Ca = Aba^Aga^Aka^Ama^Asa@ + @Ce = Abe^Age^Ake^Ame^Ase@ + @Ci = Abi^Agi^Aki^Ami^Asi@ + @Co = Abo^Ago^Ako^Amo^Aso@ + @Cu = Abu^Agu^Aku^Amu^Asu@ + @De = Ca^ROL64(Ci, 1)@ + @Di = Ce^ROL64(Co, 1)@ + @Do = Ci^ROL64(Cu, 1)@ + @Du = Co^ROL64(Ca, 1)@ + @Da = Cu^ROL64(Ce, 1)@ + + veor.64 q4, q6, q7 + veor.64 q5, q9, q10 + veor.64 d8, d8, d9 + veor.64 d10, d10, d11 + veor.64 d1, d8, d16 + veor.64 d2, d10, d17 + + veor.64 q4, q11, q12 + veor.64 q5, q14, q15 + veor.64 d8, d8, d9 + veor.64 d10, d10, d11 + veor.64 d3, d8, d26 + + vadd.u64 q4, q1, q1 + veor.64 d4, d10, d27 + vmov.64 d0, d5 + vsri.64 q4, q1, #63 + + vadd.u64 q5, q2, q2 + veor.64 q4, q4, q0 + vsri.64 q5, q2, #63 + vadd.u64 d7, d1, d1 + veor.64 \argA2, \argA2, d8 + veor.64 q5, q5, q1 + + vsri.64 d7, d1, #63 + vshl.u64 d1, \argA2, #44 + veor.64 \argA3, \argA3, d9 + veor.64 d7, d7, d4 + + @Ba = argA1^Da@ + @Be = ROL64((argA2^De), 44)@ + @Bi = ROL64((argA3^Di), 43)@ + @Bo = ROL64((argA4^Do), 21)@ + @Bu = ROL64((argA5^Du), 14)@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + @argA1 = Ba ^((~Be)& Bi )@ argA1 ^= KeccakF1600RoundConstants[i+round]@ + vsri.64 d1, \argA2, #64-44 + vshl.u64 d2, \argA3, #43 + vldr.64 d0, [sp, #\argA1] + veor.64 \argA4, \argA4, d10 + vsri.64 d2, \argA3, #64-43 + vshl.u64 d3, \argA4, #21 + veor.64 \argA5, \argA5, d11 + veor.64 d0, d0, d7 + vsri.64 d3, \argA4, #64-21 + vbic.64 d5, d2, d1 + vshl.u64 d4, \argA5, #14 + vbic.64 \argA2, d3, d2 + vld1.64 d6, [ip]! + veor.64 d5, d0 + vsri.64 d4, \argA5, #64-14 + veor.64 d5, d6 + vbic.64 \argA5, d1, d0 + vbic.64 \argA3, d4, d3 + vbic.64 \argA4, d0, d4 + veor.64 \argA2, d1 + vstr.64 d5, [sp, #\argA1] + veor.64 \argA3, d2 + veor.64 \argA4, d3 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi1 argA1, argA2, argA3, argA4, argA5 + + @d2 = ROL64((argA1^Da), 3)@ + @d3 = ROL64((argA2^De), 45)@ + @d4 = ROL64((argA3^Di), 61)@ + @d0 = ROL64((argA4^Do), 28)@ + @d1 = ROL64((argA5^Du), 20)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA2, \argA2, d8 + veor.64 \argA3, \argA3, d9 + vshl.u64 d3, \argA2, #45 + vldr.64 d6, [sp, #\argA1] + vshl.u64 d4, \argA3, #61 + veor.64 \argA4, \argA4, d10 + vsri.64 d3, \argA2, #64-45 + veor.64 \argA5, \argA5, d11 + vsri.64 d4, \argA3, #64-61 + vshl.u64 d0, \argA4, #28 + veor.64 d6, d6, d7 + vshl.u64 d1, \argA5, #20 + vbic.64 \argA3, d4, d3 + vsri.64 d0, \argA4, #64-28 + vbic.64 \argA4, d0, d4 + vshl.u64 d2, d6, #3 + vsri.64 d1, \argA5, #64-20 + veor.64 \argA4, d3 + vsri.64 d2, d6, #64-3 + vbic.64 \argA5, d1, d0 + vbic.64 d6, d2, d1 + vbic.64 \argA2, d3, d2 + veor.64 d6, d0 + veor.64 \argA2, d1 + vstr.64 d6, [sp, #\argA1] + veor.64 \argA3, d2 + veor.64 d5, d6 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi2 argA1, argA2, argA3, argA4, argA5 + + @d4 = ROL64((argA1^Da), 18)@ + @d0 = ROL64((argA2^De), 1)@ + @d1 = ROL64((argA3^Di), 6)@ + @d2 = ROL64((argA4^Do), 25)@ + @d3 = ROL64((argA5^Du), 8)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA3, \argA3, d9 + veor.64 \argA4, \argA4, d10 + vshl.u64 d1, \argA3, #6 + vldr.64 d6, [sp, #\argA1] + vshl.u64 d2, \argA4, #25 + veor.64 \argA5, \argA5, d11 + vsri.64 d1, \argA3, #64-6 + veor.64 \argA2, \argA2, d8 + vsri.64 d2, \argA4, #64-25 + vext.8 d3, \argA5, \argA5, #7 + veor.64 d6, d6, d7 + vbic.64 \argA3, d2, d1 + vadd.u64 d0, \argA2, \argA2 + vbic.64 \argA4, d3, d2 + vsri.64 d0, \argA2, #64-1 + vshl.u64 d4, d6, #18 + veor.64 \argA2, d1, \argA4 + veor.64 \argA3, d0 + vsri.64 d4, d6, #64-18 + vstr.64 \argA3, [sp, #\argA1] + veor.64 d5, \argA3 + vbic.64 \argA5, d1, d0 + vbic.64 \argA3, d4, d3 + vbic.64 \argA4, d0, d4 + veor.64 \argA3, d2 + veor.64 \argA4, d3 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi3 argA1, argA2, argA3, argA4, argA5 + + @d1 = ROL64((argA1^Da), 36)@ + @d2 = ROL64((argA2^De), 10)@ + @d3 = ROL64((argA3^Di), 15)@ + @d4 = ROL64((argA4^Do), 56)@ + @d0 = ROL64((argA5^Du), 27)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA2, \argA2, d8 + veor.64 \argA3, \argA3, d9 + vshl.u64 d2, \argA2, #10 + vldr.64 d6, [sp, #\argA1] + vshl.u64 d3, \argA3, #15 + veor.64 \argA4, \argA4, d10 + vsri.64 d2, \argA2, #64-10 + vsri.64 d3, \argA3, #64-15 + veor.64 \argA5, \argA5, d11 + vext.8 d4, \argA4, \argA4, #1 + vbic.64 \argA2, d3, d2 + vshl.u64 d0, \argA5, #27 + veor.64 d6, d6, d7 + vbic.64 \argA3, d4, d3 + vsri.64 d0, \argA5, #64-27 + vshl.u64 d1, d6, #36 + veor.64 \argA3, d2 + vbic.64 \argA4, d0, d4 + vsri.64 d1, d6, #64-36 + + veor.64 \argA4, d3 + vbic.64 d6, d2, d1 + vbic.64 \argA5, d1, d0 + veor.64 d6, d0 + veor.64 \argA2, d1 + vstr.64 d6, [sp, #\argA1] + veor.64 d5, d6 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi4 argA1, argA2, argA3, argA4, argA5 + + @d3 = ROL64((argA1^Da), 41)@ + @d4 = ROL64((argA2^De), 2)@ + @d0 = ROL64((argA3^Di), 62)@ + @d1 = ROL64((argA4^Do), 55)@ + @d2 = ROL64((argA5^Du), 39)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA2, \argA2, d8 + veor.64 \argA3, \argA3, d9 + vshl.u64 d4, \argA2, #2 + veor.64 \argA5, \argA5, d11 + vshl.u64 d0, \argA3, #62 + vldr.64 d6, [sp, #\argA1] + vsri.64 d4, \argA2, #64-2 + veor.64 \argA4, \argA4, d10 + vsri.64 d0, \argA3, #64-62 + + vshl.u64 d1, \argA4, #55 + veor.64 d6, d6, d7 + vshl.u64 d2, \argA5, #39 + vsri.64 d1, \argA4, #64-55 + vbic.64 \argA4, d0, d4 + vsri.64 d2, \argA5, #64-39 + vbic.64 \argA2, d1, d0 + vshl.u64 d3, d6, #41 + veor.64 \argA5, d4, \argA2 + vbic.64 \argA2, d2, d1 + vsri.64 d3, d6, #64-41 + veor.64 d6, d0, \argA2 + + vbic.64 \argA2, d3, d2 + vbic.64 \argA3, d4, d3 + veor.64 \argA2, d1 + vstr.64 d6, [sp, #\argA1] + veor.64 d5, d6 + veor.64 \argA3, d2 + veor.64 \argA4, d3 + + .endm + + +@// --- code + +@not callable from C! +.p2align 3 +.type KeccakF_armv7a_neon_asm,%function; +KeccakF_armv7a_neon_asm: @ + +.LroundLoop: + + KeccakThetaRhoPiChiIota Aba, d13, d19, d25, d31 + KeccakThetaRhoPiChi1 Aka, d15, d21, d22, d28 + KeccakThetaRhoPiChi2 Asa, d12, d18, d24, d30 + KeccakThetaRhoPiChi3 Aga, d14, d20, d26, d27 + KeccakThetaRhoPiChi4 Ama, d16, d17, d23, d29 + + KeccakThetaRhoPiChiIota Aba, d15, d18, d26, d29 + KeccakThetaRhoPiChi1 Asa, d14, d17, d25, d28 + KeccakThetaRhoPiChi2 Ama, d13, d21, d24, d27 + KeccakThetaRhoPiChi3 Aka, d12, d20, d23, d31 + KeccakThetaRhoPiChi4 Aga, d16, d19, d22, d30 + + KeccakThetaRhoPiChiIota Aba, d14, d21, d23, d30 + KeccakThetaRhoPiChi1 Ama, d12, d19, d26, d28 + KeccakThetaRhoPiChi2 Aga, d15, d17, d24, d31 + KeccakThetaRhoPiChi3 Asa, d13, d20, d22, d29 + KeccakThetaRhoPiChi4 Aka, d16, d18, d25, d27 + + KeccakThetaRhoPiChiIota Aba, d12, d17, d22, d27 + KeccakThetaRhoPiChi1 Aga, d13, d18, d23, d28 + KeccakThetaRhoPiChi2 Aka, d14, d19, d24, d29 + ldr r0, [ip] + KeccakThetaRhoPiChi3 Ama, d15, d20, d25, d30 + cmp r0, #0xFFFFFFFF + KeccakThetaRhoPiChi4 Asa, d16, d21, d26, d31 + + bne .LroundLoop + sub ip, #(8*24) + bx lr +.p2align 2 +.ltorg +.size KeccakF_armv7a_neon_asm,.-KeccakF_armv7a_neon_asm; + + +@//unsigned _gcry_keccak_permute_armv7_neon(u64 *state) callable from C +.p2align 3 +.global _gcry_keccak_permute_armv7_neon +.type _gcry_keccak_permute_armv7_neon,%function; +_gcry_keccak_permute_armv7_neon: + + push {ip, lr} + vpush {q4-q7} + sub sp,sp, #5*8 + + vldr.64 d0, [r0, #0*8] + vldr.64 d12, [r0, #1*8] + vldr.64 d17, [r0, #2*8] + vldr.64 d22, [r0, #3*8] + vldr.64 d27, [r0, #4*8] + + GET_DATA_POINTER(ip, _gcry_keccak_round_consts_64bit, lr); + + vldr.64 d1, [r0, #5*8] + vldr.64 d13, [r0, #6*8] + vldr.64 d18, [r0, #7*8] + vldr.64 d23, [r0, #8*8] + vldr.64 d28, [r0, #9*8] + + vldr.64 d2, [r0, #10*8] + vldr.64 d14, [r0, #11*8] + vldr.64 d19, [r0, #12*8] + vldr.64 d24, [r0, #13*8] + vldr.64 d29, [r0, #14*8] + + vldr.64 d3, [r0, #15*8] + vldr.64 d15, [r0, #16*8] + vldr.64 d20, [r0, #17*8] + vldr.64 d25, [r0, #18*8] + vldr.64 d30, [r0, #19*8] + + vldr.64 d4, [r0, #20*8] + vldr.64 d16, [r0, #21*8] + vldr.64 d21, [r0, #22*8] + vldr.64 d26, [r0, #23*8] + vldr.64 d31, [r0, #24*8] + + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + mov r1, r0 + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + vpop.64 { d0- d4 } + + vstr.64 d0, [r1, #0*8] + vstr.64 d12, [r1, #1*8] + vstr.64 d17, [r1, #2*8] + vstr.64 d22, [r1, #3*8] + vstr.64 d27, [r1, #4*8] + + vstr.64 d1, [r1, #5*8] + vstr.64 d13, [r1, #6*8] + vstr.64 d18, [r1, #7*8] + vstr.64 d23, [r1, #8*8] + vstr.64 d28, [r1, #9*8] + + vstr.64 d2, [r1, #10*8] + vstr.64 d14, [r1, #11*8] + vstr.64 d19, [r1, #12*8] + vstr.64 d24, [r1, #13*8] + vstr.64 d29, [r1, #14*8] + + vstr.64 d3, [r1, #15*8] + vstr.64 d15, [r1, #16*8] + vstr.64 d20, [r1, #17*8] + vstr.64 d25, [r1, #18*8] + vstr.64 d30, [r1, #19*8] + + vstr.64 d4, [r1, #20*8] + vstr.64 d16, [r1, #21*8] + vstr.64 d21, [r1, #22*8] + vstr.64 d26, [r1, #23*8] + vstr.64 d31, [r1, #24*8] + + mov r0, #112 + vpop {q4-q7} + pop {ip, pc} +.p2align 2 +.ltorg +.size _gcry_keccak_permute_armv7_neon,.-_gcry_keccak_permute_armv7_neon; + +@//unsigned _gcry_keccak_permute_armv7_neon(u64 *state, @r4 +@ int pos, @r1 +@ const byte *lanes, @r2 +@ unsigned int nlanes, @r3 +@ int blocklanes) @ r5 callable from C +.p2align 3 +.global _gcry_keccak_absorb_lanes64_armv7_neon +.type _gcry_keccak_absorb_lanes64_armv7_neon,%function; +_gcry_keccak_absorb_lanes64_armv7_neon: + + cmp r3, #0 @ nlanes == 0 + itt eq + moveq r0, #0 + bxeq lr + + push {r4-r5, ip, lr} + beq .Lout + mov r4, r0 + ldr r5, [sp, #(4*4)] + vpush {q4-q7} + + @ load state + vldr.64 d0, [r4, #0*8] + vldr.64 d12, [r4, #1*8] + vldr.64 d17, [r4, #2*8] + vldr.64 d22, [r4, #3*8] + vldr.64 d27, [r4, #4*8] + + GET_DATA_POINTER(ip, _gcry_keccak_round_consts_64bit, lr); + + vldr.64 d1, [r4, #5*8] + vldr.64 d13, [r4, #6*8] + vldr.64 d18, [r4, #7*8] + vldr.64 d23, [r4, #8*8] + vldr.64 d28, [r4, #9*8] + + vldr.64 d2, [r4, #10*8] + vldr.64 d14, [r4, #11*8] + vldr.64 d19, [r4, #12*8] + vldr.64 d24, [r4, #13*8] + vldr.64 d29, [r4, #14*8] + + vldr.64 d3, [r4, #15*8] + vldr.64 d15, [r4, #16*8] + vldr.64 d20, [r4, #17*8] + vldr.64 d25, [r4, #18*8] + vldr.64 d30, [r4, #19*8] + + vldr.64 d4, [r4, #20*8] + vldr.64 d16, [r4, #21*8] + vldr.64 d21, [r4, #22*8] + vldr.64 d26, [r4, #23*8] + vldr.64 d31, [r4, #24*8] + +.Lmain_loop: + + @ detect absorb mode (full blocks vs lanes) + + cmp r1, #0 @ pos != 0 + bne .Llanes_loop + +.Lmain_loop_pos0: + + @ full blocks mode + + @ switch (blocksize) + cmp r5, #21 + beq .Lfull_block_21 + cmp r5, #18 + beq .Lfull_block_18 + cmp r5, #17 + beq .Lfull_block_17 + cmp r5, #13 + beq .Lfull_block_13 + cmp r5, #9 + beq .Lfull_block_9 + + @ unknown blocksize + b .Llanes_loop + +.Lfull_block_21: + + @ SHAKE128 + + cmp r3, #21 @ nlanes < blocklanes + blo .Llanes_loop + + sub sp,sp, #5*8 + + vld1.64 {d5-d8}, [r2]! + veor d0, d5 + vld1.64 {d9-d11}, [r2]! + veor d12, d6 + veor d17, d7 + veor d22, d8 + vld1.64 {d5-d8}, [r2]! + veor d27, d9 + + veor d1, d10 + veor d13, d11 + vld1.64 {d9-d11}, [r2]! + veor d18, d5 + veor d23, d6 + veor d28, d7 + + veor d2, d8 + vld1.64 {d5-d8}, [r2]! + veor d14, d9 + veor d19, d10 + veor d24, d11 + vld1.64 {d9-d11}, [r2]! + veor d29, d5 + + veor d3, d6 + veor d15, d7 + veor d20, d8 + veor d25, d9 + veor d30, d10 + + veor d4, d11 + + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + subs r3, #21 @ nlanes -= 21 + vpop.64 { d0-d4 } + + beq .Ldone + + b .Lfull_block_21 + +.Lfull_block_18: + + @ SHA3-224 + + cmp r3, #18 @ nlanes < blocklanes + blo .Llanes_loop + + sub sp,sp, #5*8 + + vld1.64 {d5-d8}, [r2]! + veor d0, d5 + vld1.64 {d9-d11}, [r2]! + veor d12, d6 + veor d17, d7 + veor d22, d8 + vld1.64 {d5-d8}, [r2]! + veor d27, d9 + + veor d1, d10 + veor d13, d11 + vld1.64 {d9-d11}, [r2]! + veor d18, d5 + veor d23, d6 + veor d28, d7 + + veor d2, d8 + vld1.64 {d5-d8}, [r2]! + veor d14, d9 + veor d19, d10 + veor d24, d11 + veor d29, d5 + + veor d3, d6 + veor d15, d7 + veor d20, d8 + + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + subs r3, #18 @ nlanes -= 18 + vpop.64 { d0-d4 } + + beq .Ldone + + b .Lfull_block_18 + +.Lfull_block_17: + + @ SHA3-256 & SHAKE256 + + cmp r3, #17 @ nlanes < blocklanes + blo .Llanes_loop + + sub sp,sp, #5*8 + + vld1.64 {d5-d8}, [r2]! + veor d0, d5 + vld1.64 {d9-d11}, [r2]! + veor d12, d6 + veor d17, d7 + veor d22, d8 + vld1.64 {d5-d8}, [r2]! + veor d27, d9 + + veor d1, d10 + veor d13, d11 + vld1.64 {d9-d11}, [r2]! + veor d18, d5 + veor d23, d6 + veor d28, d7 + + veor d2, d8 + vld1.64 {d5-d7}, [r2]! + veor d14, d9 + veor d19, d10 + veor d24, d11 + veor d29, d5 + + veor d3, d6 + veor d15, d7 + + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + subs r3, #17 @ nlanes -= 17 + vpop.64 { d0-d4 } + + beq .Ldone + + b .Lfull_block_17 + +.Lfull_block_13: + + @ SHA3-384 + + cmp r3, #13 @ nlanes < blocklanes + blo .Llanes_loop + + sub sp,sp, #5*8 + + vld1.64 {d5-d8}, [r2]! + veor d0, d5 + vld1.64 {d9-d11}, [r2]! + veor d12, d6 + veor d17, d7 + veor d22, d8 + vld1.64 {d5-d8}, [r2]! + veor d27, d9 + + veor d1, d10 + veor d13, d11 + vld1.64 {d9-d10}, [r2]! + veor d18, d5 + veor d23, d6 + veor d28, d7 + + veor d2, d8 + veor d14, d9 + veor d19, d10 + + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + subs r3, #13 @ nlanes -= 13 + vpop.64 { d0-d4 } + + beq .Ldone + + b .Lfull_block_13 + +.Lfull_block_9: + + @ SHA3-512 + + cmp r3, #9 @ nlanes < blocklanes + blo .Llanes_loop + + sub sp,sp, #5*8 + + vld1.64 {d5-d8}, [r2]! + veor d0, d5 + vld1.64 {d9-d11}, [r2]! + veor d12, d6 + veor d17, d7 + veor d22, d8 + vld1.64 {d5-d6}, [r2]! + veor d27, d9 + + veor d1, d10 + veor d13, d11 + veor d18, d5 + veor d23, d6 + + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + subs r3, #9 @ nlanes -= 9 + vpop.64 { d0-d4 } + + beq .Ldone + + b .Lfull_block_9 + +.Llanes_loop: + + @ per-lane mode + + @ switch (pos) + ldrb r0, [pc, r1] + add pc, pc, r0, lsl #2 +.Lswitch_table: + .byte (.Llane0-.Lswitch_table-4)/4 + .byte (.Llane1-.Lswitch_table-4)/4 + .byte (.Llane2-.Lswitch_table-4)/4 + .byte (.Llane3-.Lswitch_table-4)/4 + .byte (.Llane4-.Lswitch_table-4)/4 + .byte (.Llane5-.Lswitch_table-4)/4 + .byte (.Llane6-.Lswitch_table-4)/4 + .byte (.Llane7-.Lswitch_table-4)/4 + .byte (.Llane8-.Lswitch_table-4)/4 + .byte (.Llane9-.Lswitch_table-4)/4 + .byte (.Llane10-.Lswitch_table-4)/4 + .byte (.Llane11-.Lswitch_table-4)/4 + .byte (.Llane12-.Lswitch_table-4)/4 + .byte (.Llane13-.Lswitch_table-4)/4 + .byte (.Llane14-.Lswitch_table-4)/4 + .byte (.Llane15-.Lswitch_table-4)/4 + .byte (.Llane16-.Lswitch_table-4)/4 + .byte (.Llane17-.Lswitch_table-4)/4 + .byte (.Llane18-.Lswitch_table-4)/4 + .byte (.Llane19-.Lswitch_table-4)/4 + .byte (.Llane20-.Lswitch_table-4)/4 + .byte (.Llane21-.Lswitch_table-4)/4 + .byte (.Llane22-.Lswitch_table-4)/4 + .byte (.Llane23-.Lswitch_table-4)/4 + .byte (.Llane24-.Lswitch_table-4)/4 +.p2align 2 + +#define ABSORB_LANE(label, vreg) \ + label: \ + add r1, #1; \ + vld1.64 d5, [r2]!; \ + cmp r1, r5; /* pos == blocklanes */ \ + veor vreg, vreg, d5; \ + beq .Llanes_permute; \ + subs r3, #1; \ + beq .Ldone; + + ABSORB_LANE(.Llane0, d0) + ABSORB_LANE(.Llane1, d12) + ABSORB_LANE(.Llane2, d17) + ABSORB_LANE(.Llane3, d22) + ABSORB_LANE(.Llane4, d27) + + ABSORB_LANE(.Llane5, d1) + ABSORB_LANE(.Llane6, d13) + ABSORB_LANE(.Llane7, d18) + ABSORB_LANE(.Llane8, d23) + ABSORB_LANE(.Llane9, d28) + + ABSORB_LANE(.Llane10, d2) + ABSORB_LANE(.Llane11, d14) + ABSORB_LANE(.Llane12, d19) + ABSORB_LANE(.Llane13, d24) + ABSORB_LANE(.Llane14, d29) + + ABSORB_LANE(.Llane15, d3) + ABSORB_LANE(.Llane16, d15) + ABSORB_LANE(.Llane17, d20) + ABSORB_LANE(.Llane18, d25) + ABSORB_LANE(.Llane19, d30) + + ABSORB_LANE(.Llane20, d4) + ABSORB_LANE(.Llane21, d16) + ABSORB_LANE(.Llane22, d21) + ABSORB_LANE(.Llane23, d26) + ABSORB_LANE(.Llane24, d31) + + b .Llanes_loop + +.Llanes_permute: + + sub sp,sp, #5*8 + vstr.64 d0, [sp, #Aba] + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + mov r1, #0 @ pos <= 0 + subs r3, #1 + + vpop.64 { d0-d4 } + + beq .Ldone + + b .Lmain_loop_pos0 + +.Ldone: + + @ save state + vstr.64 d0, [r4, #0*8] + vstr.64 d12, [r4, #1*8] + vstr.64 d17, [r4, #2*8] + vstr.64 d22, [r4, #3*8] + vstr.64 d27, [r4, #4*8] + + vstr.64 d1, [r4, #5*8] + vstr.64 d13, [r4, #6*8] + vstr.64 d18, [r4, #7*8] + vstr.64 d23, [r4, #8*8] + vstr.64 d28, [r4, #9*8] + + vstr.64 d2, [r4, #10*8] + vstr.64 d14, [r4, #11*8] + vstr.64 d19, [r4, #12*8] + vstr.64 d24, [r4, #13*8] + vstr.64 d29, [r4, #14*8] + + vstr.64 d3, [r4, #15*8] + vstr.64 d15, [r4, #16*8] + vstr.64 d20, [r4, #17*8] + vstr.64 d25, [r4, #18*8] + vstr.64 d30, [r4, #19*8] + + vstr.64 d4, [r4, #20*8] + vstr.64 d16, [r4, #21*8] + vstr.64 d21, [r4, #22*8] + vstr.64 d26, [r4, #23*8] + vstr.64 d31, [r4, #24*8] + + mov r0, #120 + vpop {q4-q7} +.Lout: + pop {r4-r5, ip, pc} +.p2align 2 +.ltorg +.size _gcry_keccak_absorb_lanes64_armv7_neon,.-_gcry_keccak_absorb_lanes64_armv7_neon; + +#endif diff --git a/comm/third_party/libgcrypt/cipher/keccak.c b/comm/third_party/libgcrypt/cipher/keccak.c new file mode 100644 index 0000000000..795a02e5b9 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/keccak.c @@ -0,0 +1,1577 @@ +/* keccak.c - SHA3 hash functions + * Copyright (C) 2015 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + + +#include +#include +#include "g10lib.h" +#include "bithelp.h" +#include "bufhelp.h" +#include "cipher.h" +#include "hash-common.h" + + + +/* USE_64BIT indicates whether to use 64-bit generic implementation. + * USE_32BIT indicates whether to use 32-bit generic implementation. */ +#undef USE_64BIT +#if defined(__x86_64__) || SIZEOF_UNSIGNED_LONG == 8 +# define USE_64BIT 1 +#else +# define USE_32BIT 1 +#endif + + +/* USE_64BIT_BMI2 indicates whether to compile with 64-bit Intel BMI2 code. */ +#undef USE_64BIT_BMI2 +#if defined(USE_64BIT) && defined(HAVE_GCC_INLINE_ASM_BMI2) && \ + defined(HAVE_CPU_ARCH_X86) +# define USE_64BIT_BMI2 1 +#endif + + +/* USE_64BIT_SHLD indicates whether to compile with 64-bit Intel SHLD code. */ +#undef USE_64BIT_SHLD +#if defined(USE_64BIT) && defined (__GNUC__) && defined(__x86_64__) && \ + defined(HAVE_CPU_ARCH_X86) +# define USE_64BIT_SHLD 1 +#endif + + +/* USE_32BIT_BMI2 indicates whether to compile with 32-bit Intel BMI2 code. */ +#undef USE_32BIT_BMI2 +#if defined(USE_32BIT) && defined(HAVE_GCC_INLINE_ASM_BMI2) && \ + defined(HAVE_CPU_ARCH_X86) +# define USE_32BIT_BMI2 1 +#endif + + +/* USE_64BIT_ARM_NEON indicates whether to enable 64-bit ARM/NEON assembly + * code. */ +#undef USE_64BIT_ARM_NEON +#ifdef ENABLE_NEON_SUPPORT +# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \ + && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_NEON) +# define USE_64BIT_ARM_NEON 1 +# endif +#endif /*ENABLE_NEON_SUPPORT*/ + + +/* USE_S390X_CRYPTO indicates whether to enable zSeries code. */ +#undef USE_S390X_CRYPTO +#if defined(HAVE_GCC_INLINE_ASM_S390X) +# define USE_S390X_CRYPTO 1 +#endif /* USE_S390X_CRYPTO */ + + +#if defined(USE_64BIT) || defined(USE_64BIT_ARM_NEON) +# define NEED_COMMON64 1 +#endif + +#ifdef USE_32BIT +# define NEED_COMMON32BI 1 +#endif + + +#define SHA3_DELIMITED_SUFFIX 0x06 +#define SHAKE_DELIMITED_SUFFIX 0x1F + + +typedef struct +{ + union { +#ifdef NEED_COMMON64 + u64 state64[25]; +#endif +#ifdef NEED_COMMON32BI + u32 state32bi[50]; +#endif + } u; +} KECCAK_STATE; + + +typedef struct +{ + unsigned int (*permute)(KECCAK_STATE *hd); + unsigned int (*absorb)(KECCAK_STATE *hd, int pos, const byte *lanes, + unsigned int nlanes, int blocklanes); + unsigned int (*extract) (KECCAK_STATE *hd, unsigned int pos, byte *outbuf, + unsigned int outlen); +} keccak_ops_t; + + +typedef struct KECCAK_CONTEXT_S +{ + KECCAK_STATE state; + unsigned int outlen; + unsigned int blocksize; + unsigned int count; + unsigned int suffix; + const keccak_ops_t *ops; +#ifdef USE_S390X_CRYPTO + unsigned int kimd_func; + unsigned int buf_pos; + byte buf[1344 / 8]; /* SHAKE128 requires biggest buffer, 1344 bits. */ +#endif +} KECCAK_CONTEXT; + + + +#ifdef NEED_COMMON64 + +const u64 _gcry_keccak_round_consts_64bit[24 + 1] = +{ + U64_C(0x0000000000000001), U64_C(0x0000000000008082), + U64_C(0x800000000000808A), U64_C(0x8000000080008000), + U64_C(0x000000000000808B), U64_C(0x0000000080000001), + U64_C(0x8000000080008081), U64_C(0x8000000000008009), + U64_C(0x000000000000008A), U64_C(0x0000000000000088), + U64_C(0x0000000080008009), U64_C(0x000000008000000A), + U64_C(0x000000008000808B), U64_C(0x800000000000008B), + U64_C(0x8000000000008089), U64_C(0x8000000000008003), + U64_C(0x8000000000008002), U64_C(0x8000000000000080), + U64_C(0x000000000000800A), U64_C(0x800000008000000A), + U64_C(0x8000000080008081), U64_C(0x8000000000008080), + U64_C(0x0000000080000001), U64_C(0x8000000080008008), + U64_C(0xFFFFFFFFFFFFFFFF) +}; + +static unsigned int +keccak_extract64(KECCAK_STATE *hd, unsigned int pos, byte *outbuf, + unsigned int outlen) +{ + unsigned int i; + + /* NOTE: when pos == 0, hd and outbuf may point to same memory (SHA-3). */ + + for (i = pos; i < pos + outlen / 8 + !!(outlen % 8); i++) + { + u64 tmp = hd->u.state64[i]; + buf_put_le64(outbuf, tmp); + outbuf += 8; + } + + return 0; +} + +#endif /* NEED_COMMON64 */ + + +#ifdef NEED_COMMON32BI + +static const u32 round_consts_32bit[2 * 24] = +{ + 0x00000001UL, 0x00000000UL, 0x00000000UL, 0x00000089UL, + 0x00000000UL, 0x8000008bUL, 0x00000000UL, 0x80008080UL, + 0x00000001UL, 0x0000008bUL, 0x00000001UL, 0x00008000UL, + 0x00000001UL, 0x80008088UL, 0x00000001UL, 0x80000082UL, + 0x00000000UL, 0x0000000bUL, 0x00000000UL, 0x0000000aUL, + 0x00000001UL, 0x00008082UL, 0x00000000UL, 0x00008003UL, + 0x00000001UL, 0x0000808bUL, 0x00000001UL, 0x8000000bUL, + 0x00000001UL, 0x8000008aUL, 0x00000001UL, 0x80000081UL, + 0x00000000UL, 0x80000081UL, 0x00000000UL, 0x80000008UL, + 0x00000000UL, 0x00000083UL, 0x00000000UL, 0x80008003UL, + 0x00000001UL, 0x80008088UL, 0x00000000UL, 0x80000088UL, + 0x00000001UL, 0x00008000UL, 0x00000000UL, 0x80008082UL +}; + +static unsigned int +keccak_extract32bi(KECCAK_STATE *hd, unsigned int pos, byte *outbuf, + unsigned int outlen) +{ + unsigned int i; + u32 x0; + u32 x1; + u32 t; + + /* NOTE: when pos == 0, hd and outbuf may point to same memory (SHA-3). */ + + for (i = pos; i < pos + outlen / 8 + !!(outlen % 8); i++) + { + x0 = hd->u.state32bi[i * 2 + 0]; + x1 = hd->u.state32bi[i * 2 + 1]; + + t = (x0 & 0x0000FFFFUL) + (x1 << 16); + x1 = (x0 >> 16) + (x1 & 0xFFFF0000UL); + x0 = t; + t = (x0 ^ (x0 >> 8)) & 0x0000FF00UL; x0 = x0 ^ t ^ (t << 8); + t = (x0 ^ (x0 >> 4)) & 0x00F000F0UL; x0 = x0 ^ t ^ (t << 4); + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0CUL; x0 = x0 ^ t ^ (t << 2); + t = (x0 ^ (x0 >> 1)) & 0x22222222UL; x0 = x0 ^ t ^ (t << 1); + t = (x1 ^ (x1 >> 8)) & 0x0000FF00UL; x1 = x1 ^ t ^ (t << 8); + t = (x1 ^ (x1 >> 4)) & 0x00F000F0UL; x1 = x1 ^ t ^ (t << 4); + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0CUL; x1 = x1 ^ t ^ (t << 2); + t = (x1 ^ (x1 >> 1)) & 0x22222222UL; x1 = x1 ^ t ^ (t << 1); + + buf_put_le32(&outbuf[0], x0); + buf_put_le32(&outbuf[4], x1); + outbuf += 8; + } + + return 0; +} + +static inline void +keccak_absorb_lane32bi(u32 *lane, u32 x0, u32 x1) +{ + u32 t; + + t = (x0 ^ (x0 >> 1)) & 0x22222222UL; x0 = x0 ^ t ^ (t << 1); + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0CUL; x0 = x0 ^ t ^ (t << 2); + t = (x0 ^ (x0 >> 4)) & 0x00F000F0UL; x0 = x0 ^ t ^ (t << 4); + t = (x0 ^ (x0 >> 8)) & 0x0000FF00UL; x0 = x0 ^ t ^ (t << 8); + t = (x1 ^ (x1 >> 1)) & 0x22222222UL; x1 = x1 ^ t ^ (t << 1); + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0CUL; x1 = x1 ^ t ^ (t << 2); + t = (x1 ^ (x1 >> 4)) & 0x00F000F0UL; x1 = x1 ^ t ^ (t << 4); + t = (x1 ^ (x1 >> 8)) & 0x0000FF00UL; x1 = x1 ^ t ^ (t << 8); + lane[0] ^= (x0 & 0x0000FFFFUL) + (x1 << 16); + lane[1] ^= (x0 >> 16) + (x1 & 0xFFFF0000UL); +} + +#endif /* NEED_COMMON32BI */ + + +/* Construct generic 64-bit implementation. */ +#ifdef USE_64BIT + +#if __GNUC__ >= 4 && defined(__x86_64__) + +static inline void absorb_lanes64_8(u64 *dst, const byte *in) +{ + asm ("movdqu 0*16(%[dst]), %%xmm0\n\t" + "movdqu 0*16(%[in]), %%xmm4\n\t" + "movdqu 1*16(%[dst]), %%xmm1\n\t" + "movdqu 1*16(%[in]), %%xmm5\n\t" + "movdqu 2*16(%[dst]), %%xmm2\n\t" + "movdqu 3*16(%[dst]), %%xmm3\n\t" + "pxor %%xmm4, %%xmm0\n\t" + "pxor %%xmm5, %%xmm1\n\t" + "movdqu 2*16(%[in]), %%xmm4\n\t" + "movdqu 3*16(%[in]), %%xmm5\n\t" + "movdqu %%xmm0, 0*16(%[dst])\n\t" + "pxor %%xmm4, %%xmm2\n\t" + "movdqu %%xmm1, 1*16(%[dst])\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "movdqu %%xmm2, 2*16(%[dst])\n\t" + "movdqu %%xmm3, 3*16(%[dst])\n\t" + : + : [dst] "r" (dst), [in] "r" (in) + : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "memory"); +} + +static inline void absorb_lanes64_4(u64 *dst, const byte *in) +{ + asm ("movdqu 0*16(%[dst]), %%xmm0\n\t" + "movdqu 0*16(%[in]), %%xmm4\n\t" + "movdqu 1*16(%[dst]), %%xmm1\n\t" + "movdqu 1*16(%[in]), %%xmm5\n\t" + "pxor %%xmm4, %%xmm0\n\t" + "pxor %%xmm5, %%xmm1\n\t" + "movdqu %%xmm0, 0*16(%[dst])\n\t" + "movdqu %%xmm1, 1*16(%[dst])\n\t" + : + : [dst] "r" (dst), [in] "r" (in) + : "xmm0", "xmm1", "xmm4", "xmm5", "memory"); +} + +static inline void absorb_lanes64_2(u64 *dst, const byte *in) +{ + asm ("movdqu 0*16(%[dst]), %%xmm0\n\t" + "movdqu 0*16(%[in]), %%xmm4\n\t" + "pxor %%xmm4, %%xmm0\n\t" + "movdqu %%xmm0, 0*16(%[dst])\n\t" + : + : [dst] "r" (dst), [in] "r" (in) + : "xmm0", "xmm4", "memory"); +} + +#else /* __x86_64__ */ + +static inline void absorb_lanes64_8(u64 *dst, const byte *in) +{ + dst[0] ^= buf_get_le64(in + 8 * 0); + dst[1] ^= buf_get_le64(in + 8 * 1); + dst[2] ^= buf_get_le64(in + 8 * 2); + dst[3] ^= buf_get_le64(in + 8 * 3); + dst[4] ^= buf_get_le64(in + 8 * 4); + dst[5] ^= buf_get_le64(in + 8 * 5); + dst[6] ^= buf_get_le64(in + 8 * 6); + dst[7] ^= buf_get_le64(in + 8 * 7); +} + +static inline void absorb_lanes64_4(u64 *dst, const byte *in) +{ + dst[0] ^= buf_get_le64(in + 8 * 0); + dst[1] ^= buf_get_le64(in + 8 * 1); + dst[2] ^= buf_get_le64(in + 8 * 2); + dst[3] ^= buf_get_le64(in + 8 * 3); +} + +static inline void absorb_lanes64_2(u64 *dst, const byte *in) +{ + dst[0] ^= buf_get_le64(in + 8 * 0); + dst[1] ^= buf_get_le64(in + 8 * 1); +} + +#endif /* !__x86_64__ */ + +static inline void absorb_lanes64_1(u64 *dst, const byte *in) +{ + dst[0] ^= buf_get_le64(in + 8 * 0); +} + + +# define ANDN64(x, y) (~(x) & (y)) +# define ROL64(x, n) (((x) << ((unsigned int)n & 63)) | \ + ((x) >> ((64 - (unsigned int)(n)) & 63))) + +# define KECCAK_F1600_PERMUTE_FUNC_NAME keccak_f1600_state_permute64 +# define KECCAK_F1600_ABSORB_FUNC_NAME keccak_absorb_lanes64 +# include "keccak_permute_64.h" + +# undef ANDN64 +# undef ROL64 +# undef KECCAK_F1600_PERMUTE_FUNC_NAME +# undef KECCAK_F1600_ABSORB_FUNC_NAME + +static const keccak_ops_t keccak_generic64_ops = +{ + .permute = keccak_f1600_state_permute64, + .absorb = keccak_absorb_lanes64, + .extract = keccak_extract64, +}; + +#endif /* USE_64BIT */ + + +/* Construct 64-bit Intel SHLD implementation. */ +#ifdef USE_64BIT_SHLD + +# define ANDN64(x, y) (~(x) & (y)) +# define ROL64(x, n) ({ \ + u64 tmp = (x); \ + asm ("shldq %1, %0, %0" \ + : "+r" (tmp) \ + : "J" ((n) & 63) \ + : "cc"); \ + tmp; }) + +# define KECCAK_F1600_PERMUTE_FUNC_NAME keccak_f1600_state_permute64_shld +# define KECCAK_F1600_ABSORB_FUNC_NAME keccak_absorb_lanes64_shld +# include "keccak_permute_64.h" + +# undef ANDN64 +# undef ROL64 +# undef KECCAK_F1600_PERMUTE_FUNC_NAME +# undef KECCAK_F1600_ABSORB_FUNC_NAME + +static const keccak_ops_t keccak_shld_64_ops = +{ + .permute = keccak_f1600_state_permute64_shld, + .absorb = keccak_absorb_lanes64_shld, + .extract = keccak_extract64, +}; + +#endif /* USE_64BIT_SHLD */ + + +/* Construct 64-bit Intel BMI2 implementation. */ +#ifdef USE_64BIT_BMI2 + +# define ANDN64(x, y) ({ \ + u64 tmp; \ + asm ("andnq %2, %1, %0" \ + : "=r" (tmp) \ + : "r0" (x), "rm" (y)); \ + tmp; }) + +# define ROL64(x, n) ({ \ + u64 tmp; \ + asm ("rorxq %2, %1, %0" \ + : "=r" (tmp) \ + : "rm0" (x), "J" (64 - ((n) & 63))); \ + tmp; }) + +# define KECCAK_F1600_PERMUTE_FUNC_NAME keccak_f1600_state_permute64_bmi2 +# define KECCAK_F1600_ABSORB_FUNC_NAME keccak_absorb_lanes64_bmi2 +# include "keccak_permute_64.h" + +# undef ANDN64 +# undef ROL64 +# undef KECCAK_F1600_PERMUTE_FUNC_NAME +# undef KECCAK_F1600_ABSORB_FUNC_NAME + +static const keccak_ops_t keccak_bmi2_64_ops = +{ + .permute = keccak_f1600_state_permute64_bmi2, + .absorb = keccak_absorb_lanes64_bmi2, + .extract = keccak_extract64, +}; + +#endif /* USE_64BIT_BMI2 */ + + +/* 64-bit ARMv7/NEON implementation. */ +#ifdef USE_64BIT_ARM_NEON + +unsigned int _gcry_keccak_permute_armv7_neon(u64 *state); +unsigned int _gcry_keccak_absorb_lanes64_armv7_neon(u64 *state, int pos, + const byte *lanes, + unsigned int nlanes, + int blocklanes); + +static unsigned int keccak_permute64_armv7_neon(KECCAK_STATE *hd) +{ + return _gcry_keccak_permute_armv7_neon(hd->u.state64); +} + +static unsigned int +keccak_absorb_lanes64_armv7_neon(KECCAK_STATE *hd, int pos, const byte *lanes, + unsigned int nlanes, int blocklanes) +{ + if (blocklanes < 0) + { + /* blocklanes == -1, permutationless absorb from keccak_final. */ + + while (nlanes) + { + hd->u.state64[pos] ^= buf_get_le64(lanes); + lanes += 8; + nlanes--; + } + + return 0; + } + else + { + return _gcry_keccak_absorb_lanes64_armv7_neon(hd->u.state64, pos, lanes, + nlanes, blocklanes); + } +} + +static const keccak_ops_t keccak_armv7_neon_64_ops = +{ + .permute = keccak_permute64_armv7_neon, + .absorb = keccak_absorb_lanes64_armv7_neon, + .extract = keccak_extract64, +}; + +#endif /* USE_64BIT_ARM_NEON */ + + +/* Construct generic 32-bit implementation. */ +#ifdef USE_32BIT + +# define ANDN32(x, y) (~(x) & (y)) +# define ROL32(x, n) (((x) << ((unsigned int)n & 31)) | \ + ((x) >> ((32 - (unsigned int)(n)) & 31))) + +# define KECCAK_F1600_PERMUTE_FUNC_NAME keccak_f1600_state_permute32bi +# include "keccak_permute_32.h" + +# undef ANDN32 +# undef ROL32 +# undef KECCAK_F1600_PERMUTE_FUNC_NAME + +static unsigned int +keccak_absorb_lanes32bi(KECCAK_STATE *hd, int pos, const byte *lanes, + unsigned int nlanes, int blocklanes) +{ + unsigned int burn = 0; + + while (nlanes) + { + keccak_absorb_lane32bi(&hd->u.state32bi[pos * 2], + buf_get_le32(lanes + 0), + buf_get_le32(lanes + 4)); + lanes += 8; + nlanes--; + + if (++pos == blocklanes) + { + burn = keccak_f1600_state_permute32bi(hd); + pos = 0; + } + } + + return burn; +} + +static const keccak_ops_t keccak_generic32bi_ops = +{ + .permute = keccak_f1600_state_permute32bi, + .absorb = keccak_absorb_lanes32bi, + .extract = keccak_extract32bi, +}; + +#endif /* USE_32BIT */ + + +/* Construct 32-bit Intel BMI2 implementation. */ +#ifdef USE_32BIT_BMI2 + +# define ANDN32(x, y) ({ \ + u32 tmp; \ + asm ("andnl %2, %1, %0" \ + : "=r" (tmp) \ + : "r0" (x), "rm" (y)); \ + tmp; }) + +# define ROL32(x, n) ({ \ + u32 tmp; \ + asm ("rorxl %2, %1, %0" \ + : "=r" (tmp) \ + : "rm0" (x), "J" (32 - ((n) & 31))); \ + tmp; }) + +# define KECCAK_F1600_PERMUTE_FUNC_NAME keccak_f1600_state_permute32bi_bmi2 +# include "keccak_permute_32.h" + +# undef ANDN32 +# undef ROL32 +# undef KECCAK_F1600_PERMUTE_FUNC_NAME + +static inline u32 pext(u32 x, u32 mask) +{ + u32 tmp; + asm ("pextl %2, %1, %0" : "=r" (tmp) : "r0" (x), "rm" (mask)); + return tmp; +} + +static inline u32 pdep(u32 x, u32 mask) +{ + u32 tmp; + asm ("pdepl %2, %1, %0" : "=r" (tmp) : "r0" (x), "rm" (mask)); + return tmp; +} + +static inline void +keccak_absorb_lane32bi_bmi2(u32 *lane, u32 x0, u32 x1) +{ + x0 = pdep(pext(x0, 0x55555555), 0x0000ffff) | (pext(x0, 0xaaaaaaaa) << 16); + x1 = pdep(pext(x1, 0x55555555), 0x0000ffff) | (pext(x1, 0xaaaaaaaa) << 16); + + lane[0] ^= (x0 & 0x0000FFFFUL) + (x1 << 16); + lane[1] ^= (x0 >> 16) + (x1 & 0xFFFF0000UL); +} + +static unsigned int +keccak_absorb_lanes32bi_bmi2(KECCAK_STATE *hd, int pos, const byte *lanes, + unsigned int nlanes, int blocklanes) +{ + unsigned int burn = 0; + + while (nlanes) + { + keccak_absorb_lane32bi_bmi2(&hd->u.state32bi[pos * 2], + buf_get_le32(lanes + 0), + buf_get_le32(lanes + 4)); + lanes += 8; + nlanes--; + + if (++pos == blocklanes) + { + burn = keccak_f1600_state_permute32bi_bmi2(hd); + pos = 0; + } + } + + return burn; +} + +static unsigned int +keccak_extract32bi_bmi2(KECCAK_STATE *hd, unsigned int pos, byte *outbuf, + unsigned int outlen) +{ + unsigned int i; + u32 x0; + u32 x1; + u32 t; + + /* NOTE: when pos == 0, hd and outbuf may point to same memory (SHA-3). */ + + for (i = pos; i < pos + outlen / 8 + !!(outlen % 8); i++) + { + x0 = hd->u.state32bi[i * 2 + 0]; + x1 = hd->u.state32bi[i * 2 + 1]; + + t = (x0 & 0x0000FFFFUL) + (x1 << 16); + x1 = (x0 >> 16) + (x1 & 0xFFFF0000UL); + x0 = t; + + x0 = pdep(pext(x0, 0xffff0001), 0xaaaaaaab) | pdep(x0 >> 1, 0x55555554); + x1 = pdep(pext(x1, 0xffff0001), 0xaaaaaaab) | pdep(x1 >> 1, 0x55555554); + + buf_put_le32(&outbuf[0], x0); + buf_put_le32(&outbuf[4], x1); + outbuf += 8; + } + + return 0; +} + +static const keccak_ops_t keccak_bmi2_32bi_ops = +{ + .permute = keccak_f1600_state_permute32bi_bmi2, + .absorb = keccak_absorb_lanes32bi_bmi2, + .extract = keccak_extract32bi_bmi2, +}; + +#endif /* USE_32BIT_BMI2 */ + + +#ifdef USE_S390X_CRYPTO +#include "asm-inline-s390x.h" + +static inline void +keccak_bwrite_s390x (void *context, const byte *in, size_t inlen) +{ + KECCAK_CONTEXT *ctx = context; + + /* Write full-blocks. */ + kimd_execute (ctx->kimd_func, &ctx->state, in, inlen); + return; +} + +static inline void +keccak_final_s390x (void *context) +{ + KECCAK_CONTEXT *ctx = context; + + if (ctx->suffix == SHA3_DELIMITED_SUFFIX) + { + klmd_execute (ctx->kimd_func, &ctx->state, ctx->buf, ctx->count); + } + else + { + klmd_shake_execute (ctx->kimd_func, &ctx->state, NULL, 0, ctx->buf, + ctx->count); + ctx->count = 0; + ctx->buf_pos = 0; + } + + return; +} + +static inline void +keccak_bextract_s390x (void *context, byte *out, size_t outlen) +{ + KECCAK_CONTEXT *ctx = context; + + /* Extract full-blocks. */ + klmd_shake_execute (ctx->kimd_func | KLMD_PADDING_STATE, &ctx->state, + out, outlen, NULL, 0); + return; +} + +static void +keccak_write_s390x (void *context, const byte *inbuf, size_t inlen) +{ + KECCAK_CONTEXT *hd = context; + const size_t blocksize = hd->blocksize; + size_t inblocks; + size_t copylen; + + while (hd->count) + { + if (hd->count == blocksize) /* Flush the buffer. */ + { + keccak_bwrite_s390x (hd, hd->buf, blocksize); + hd->count = 0; + } + else + { + copylen = inlen; + if (copylen > blocksize - hd->count) + copylen = blocksize - hd->count; + + if (copylen == 0) + break; + + buf_cpy (&hd->buf[hd->count], inbuf, copylen); + hd->count += copylen; + inbuf += copylen; + inlen -= copylen; + } + } + + if (inlen == 0) + return; + + if (inlen >= blocksize) + { + inblocks = inlen / blocksize; + keccak_bwrite_s390x (hd, inbuf, inblocks * blocksize); + hd->count = 0; + inlen -= inblocks * blocksize; + inbuf += inblocks * blocksize; + } + + if (inlen) + { + buf_cpy (hd->buf, inbuf, inlen); + hd->count = inlen; + } +} + +static void +keccak_extract_s390x (void *context, void *outbuf_arg, size_t outlen) +{ + KECCAK_CONTEXT *hd = context; + const size_t blocksize = hd->blocksize; + byte *outbuf = outbuf_arg; + + while (outlen) + { + gcry_assert(hd->count == 0 || hd->buf_pos < hd->count); + + if (hd->buf_pos < hd->count && outlen) + { + size_t copylen = hd->count - hd->buf_pos; + + if (copylen > outlen) + copylen = outlen; + + buf_cpy (outbuf, &hd->buf[hd->buf_pos], copylen); + + outbuf += copylen; + outlen -= copylen; + hd->buf_pos += copylen; + } + + if (hd->buf_pos == hd->count) + { + hd->buf_pos = 0; + hd->count = 0; + } + + if (outlen == 0) + return; + + if (outlen >= blocksize) + { + size_t outblocks = outlen / blocksize; + + keccak_bextract_s390x (context, outbuf, outblocks * blocksize); + + outlen -= outblocks * blocksize; + outbuf += outblocks * blocksize; + + if (outlen == 0) + return; + } + + keccak_bextract_s390x (context, hd->buf, blocksize); + hd->count = blocksize; + } +} +#endif /* USE_S390X_CRYPTO */ + + +static void +keccak_write (void *context, const void *inbuf_arg, size_t inlen) +{ + KECCAK_CONTEXT *ctx = context; + const size_t bsize = ctx->blocksize; + const size_t blocklanes = bsize / 8; + const byte *inbuf = inbuf_arg; + unsigned int nburn, burn = 0; + unsigned int count, i; + unsigned int pos, nlanes; + +#ifdef USE_S390X_CRYPTO + if (ctx->kimd_func) + { + keccak_write_s390x (context, inbuf, inlen); + return; + } +#endif + + count = ctx->count; + + if (inlen && (count % 8)) + { + byte lane[8] = { 0, }; + + /* Complete absorbing partial input lane. */ + + pos = count / 8; + + for (i = count % 8; inlen && i < 8; i++) + { + lane[i] = *inbuf++; + inlen--; + count++; + } + + if (count == bsize) + count = 0; + + nburn = ctx->ops->absorb(&ctx->state, pos, lane, 1, + (count % 8) ? -1 : blocklanes); + burn = nburn > burn ? nburn : burn; + } + + /* Absorb full input lanes. */ + + pos = count / 8; + nlanes = inlen / 8; + if (nlanes > 0) + { + nburn = ctx->ops->absorb(&ctx->state, pos, inbuf, nlanes, blocklanes); + burn = nburn > burn ? nburn : burn; + inlen -= nlanes * 8; + inbuf += nlanes * 8; + count += nlanes * 8; + count = count % bsize; + } + + if (inlen) + { + byte lane[8] = { 0, }; + + /* Absorb remaining partial input lane. */ + + pos = count / 8; + + for (i = count % 8; inlen && i < 8; i++) + { + lane[i] = *inbuf++; + inlen--; + count++; + } + + nburn = ctx->ops->absorb(&ctx->state, pos, lane, 1, -1); + burn = nburn > burn ? nburn : burn; + + gcry_assert(count < bsize); + } + + ctx->count = count; + + if (burn) + _gcry_burn_stack (burn); +} + + +static void +keccak_init (int algo, void *context, unsigned int flags) +{ + KECCAK_CONTEXT *ctx = context; + KECCAK_STATE *hd = &ctx->state; + unsigned int features = _gcry_get_hw_features (); + + (void)flags; + (void)features; + + memset (hd, 0, sizeof *hd); + + ctx->count = 0; + + /* Select generic implementation. */ +#ifdef USE_64BIT + ctx->ops = &keccak_generic64_ops; +#elif defined USE_32BIT + ctx->ops = &keccak_generic32bi_ops; +#endif + + /* Select optimized implementation based in hw features. */ + if (0) {} +#ifdef USE_64BIT_ARM_NEON + else if (features & HWF_ARM_NEON) + ctx->ops = &keccak_armv7_neon_64_ops; +#endif +#ifdef USE_64BIT_BMI2 + else if (features & HWF_INTEL_BMI2) + ctx->ops = &keccak_bmi2_64_ops; +#endif +#ifdef USE_32BIT_BMI2 + else if (features & HWF_INTEL_BMI2) + ctx->ops = &keccak_bmi2_32bi_ops; +#endif +#ifdef USE_64BIT_SHLD + else if (features & HWF_INTEL_FAST_SHLD) + ctx->ops = &keccak_shld_64_ops; +#endif + + /* Set input block size, in Keccak terms this is called 'rate'. */ + + switch (algo) + { + case GCRY_MD_SHA3_224: + ctx->suffix = SHA3_DELIMITED_SUFFIX; + ctx->blocksize = 1152 / 8; + ctx->outlen = 224 / 8; + break; + case GCRY_MD_SHA3_256: + ctx->suffix = SHA3_DELIMITED_SUFFIX; + ctx->blocksize = 1088 / 8; + ctx->outlen = 256 / 8; + break; + case GCRY_MD_SHA3_384: + ctx->suffix = SHA3_DELIMITED_SUFFIX; + ctx->blocksize = 832 / 8; + ctx->outlen = 384 / 8; + break; + case GCRY_MD_SHA3_512: + ctx->suffix = SHA3_DELIMITED_SUFFIX; + ctx->blocksize = 576 / 8; + ctx->outlen = 512 / 8; + break; + case GCRY_MD_SHAKE128: + ctx->suffix = SHAKE_DELIMITED_SUFFIX; + ctx->blocksize = 1344 / 8; + ctx->outlen = 0; + break; + case GCRY_MD_SHAKE256: + ctx->suffix = SHAKE_DELIMITED_SUFFIX; + ctx->blocksize = 1088 / 8; + ctx->outlen = 0; + break; + default: + BUG(); + } + +#ifdef USE_S390X_CRYPTO + ctx->kimd_func = 0; + if ((features & HWF_S390X_MSA) != 0) + { + unsigned int kimd_func = 0; + + switch (algo) + { + case GCRY_MD_SHA3_224: + kimd_func = KMID_FUNCTION_SHA3_224; + break; + case GCRY_MD_SHA3_256: + kimd_func = KMID_FUNCTION_SHA3_256; + break; + case GCRY_MD_SHA3_384: + kimd_func = KMID_FUNCTION_SHA3_384; + break; + case GCRY_MD_SHA3_512: + kimd_func = KMID_FUNCTION_SHA3_512; + break; + case GCRY_MD_SHAKE128: + kimd_func = KMID_FUNCTION_SHAKE128; + break; + case GCRY_MD_SHAKE256: + kimd_func = KMID_FUNCTION_SHAKE256; + break; + } + + if ((kimd_query () & km_function_to_mask (kimd_func)) && + (klmd_query () & km_function_to_mask (kimd_func))) + { + ctx->kimd_func = kimd_func; + } + } +#endif +} + +static void +sha3_224_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_SHA3_224, context, flags); +} + +static void +sha3_256_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_SHA3_256, context, flags); +} + +static void +sha3_384_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_SHA3_384, context, flags); +} + +static void +sha3_512_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_SHA3_512, context, flags); +} + +static void +shake128_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_SHAKE128, context, flags); +} + +static void +shake256_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_SHAKE256, context, flags); +} + +/* The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 64 bytes representing the digest. When used for sha384, + * we take the leftmost 48 of those bytes. + */ +static void +keccak_final (void *context) +{ + KECCAK_CONTEXT *ctx = context; + KECCAK_STATE *hd = &ctx->state; + const size_t bsize = ctx->blocksize; + const byte suffix = ctx->suffix; + unsigned int nburn, burn = 0; + unsigned int lastbytes; + byte lane[8]; + +#ifdef USE_S390X_CRYPTO + if (ctx->kimd_func) + { + keccak_final_s390x (context); + return; + } +#endif + + lastbytes = ctx->count; + + /* Do the padding and switch to the squeezing phase */ + + /* Absorb the last few bits and add the first bit of padding (which + coincides with the delimiter in delimited suffix) */ + buf_put_le64(lane, (u64)suffix << ((lastbytes % 8) * 8)); + nburn = ctx->ops->absorb(&ctx->state, lastbytes / 8, lane, 1, -1); + burn = nburn > burn ? nburn : burn; + + /* Add the second bit of padding. */ + buf_put_le64(lane, (u64)0x80 << (((bsize - 1) % 8) * 8)); + nburn = ctx->ops->absorb(&ctx->state, (bsize - 1) / 8, lane, 1, -1); + burn = nburn > burn ? nburn : burn; + + if (suffix == SHA3_DELIMITED_SUFFIX) + { + /* Switch to the squeezing phase. */ + nburn = ctx->ops->permute(hd); + burn = nburn > burn ? nburn : burn; + + /* Squeeze out the SHA3 digest. */ + nburn = ctx->ops->extract(hd, 0, (void *)hd, ctx->outlen); + burn = nburn > burn ? nburn : burn; + } + else + { + /* Output for SHAKE can now be read with md_extract(). */ + + ctx->count = 0; + } + + wipememory(lane, sizeof(lane)); + if (burn) + _gcry_burn_stack (burn); +} + + +static byte * +keccak_read (void *context) +{ + KECCAK_CONTEXT *ctx = (KECCAK_CONTEXT *) context; + KECCAK_STATE *hd = &ctx->state; + return (byte *)&hd->u; +} + + +static void +keccak_extract (void *context, void *out, size_t outlen) +{ + KECCAK_CONTEXT *ctx = context; + KECCAK_STATE *hd = &ctx->state; + const size_t bsize = ctx->blocksize; + unsigned int nburn, burn = 0; + byte *outbuf = out; + unsigned int nlanes; + unsigned int nleft; + unsigned int count; + unsigned int i; + byte lane[8]; + +#ifdef USE_S390X_CRYPTO + if (ctx->kimd_func) + { + keccak_extract_s390x (context, out, outlen); + return; + } +#endif + + count = ctx->count; + + while (count && outlen && (outlen < 8 || count % 8)) + { + /* Extract partial lane. */ + nburn = ctx->ops->extract(hd, count / 8, lane, 8); + burn = nburn > burn ? nburn : burn; + + for (i = count % 8; outlen && i < 8; i++) + { + *outbuf++ = lane[i]; + outlen--; + count++; + } + + gcry_assert(count <= bsize); + + if (count == bsize) + count = 0; + } + + if (outlen >= 8 && count) + { + /* Extract tail of partial block. */ + nlanes = outlen / 8; + nleft = (bsize - count) / 8; + nlanes = nlanes < nleft ? nlanes : nleft; + + nburn = ctx->ops->extract(hd, count / 8, outbuf, nlanes * 8); + burn = nburn > burn ? nburn : burn; + outlen -= nlanes * 8; + outbuf += nlanes * 8; + count += nlanes * 8; + + gcry_assert(count <= bsize); + + if (count == bsize) + count = 0; + } + + while (outlen >= bsize) + { + gcry_assert(count == 0); + + /* Squeeze more. */ + nburn = ctx->ops->permute(hd); + burn = nburn > burn ? nburn : burn; + + /* Extract full block. */ + nburn = ctx->ops->extract(hd, 0, outbuf, bsize); + burn = nburn > burn ? nburn : burn; + + outlen -= bsize; + outbuf += bsize; + } + + if (outlen) + { + gcry_assert(outlen < bsize); + + if (count == 0) + { + /* Squeeze more. */ + nburn = ctx->ops->permute(hd); + burn = nburn > burn ? nburn : burn; + } + + if (outlen >= 8) + { + /* Extract head of partial block. */ + nlanes = outlen / 8; + nburn = ctx->ops->extract(hd, count / 8, outbuf, nlanes * 8); + burn = nburn > burn ? nburn : burn; + outlen -= nlanes * 8; + outbuf += nlanes * 8; + count += nlanes * 8; + + gcry_assert(count < bsize); + } + + if (outlen) + { + /* Extract head of partial lane. */ + nburn = ctx->ops->extract(hd, count / 8, lane, 8); + burn = nburn > burn ? nburn : burn; + + for (i = count % 8; outlen && i < 8; i++) + { + *outbuf++ = lane[i]; + outlen--; + count++; + } + + gcry_assert(count < bsize); + } + } + + ctx->count = count; + + if (burn) + _gcry_burn_stack (burn); +} + + +/* Shortcut functions which puts the hash value of the supplied buffer + * into outbuf which must have a size of 'spec->mdlen' bytes. */ +static void +_gcry_sha3_hash_buffer (void *outbuf, const void *buffer, size_t length, + const gcry_md_spec_t *spec) +{ + KECCAK_CONTEXT hd; + + spec->init (&hd, 0); + keccak_write (&hd, buffer, length); + keccak_final (&hd); + memcpy (outbuf, keccak_read (&hd), spec->mdlen); +} + + +/* Variant of the above shortcut function using multiple buffers. */ +static void +_gcry_sha3_hash_buffers (void *outbuf, const gcry_buffer_t *iov, int iovcnt, + const gcry_md_spec_t *spec) +{ + KECCAK_CONTEXT hd; + + spec->init (&hd, 0); + for (;iovcnt > 0; iov++, iovcnt--) + keccak_write (&hd, (const char*)iov[0].data + iov[0].off, iov[0].len); + keccak_final (&hd); + memcpy (outbuf, keccak_read (&hd), spec->mdlen); +} + + +static void +_gcry_sha3_224_hash_buffer (void *outbuf, const void *buffer, size_t length) +{ + _gcry_sha3_hash_buffer (outbuf, buffer, length, &_gcry_digest_spec_sha3_224); +} + +static void +_gcry_sha3_256_hash_buffer (void *outbuf, const void *buffer, size_t length) +{ + _gcry_sha3_hash_buffer (outbuf, buffer, length, &_gcry_digest_spec_sha3_256); +} + +static void +_gcry_sha3_384_hash_buffer (void *outbuf, const void *buffer, size_t length) +{ + _gcry_sha3_hash_buffer (outbuf, buffer, length, &_gcry_digest_spec_sha3_384); +} + +static void +_gcry_sha3_512_hash_buffer (void *outbuf, const void *buffer, size_t length) +{ + _gcry_sha3_hash_buffer (outbuf, buffer, length, &_gcry_digest_spec_sha3_512); +} + +static void +_gcry_sha3_224_hash_buffers (void *outbuf, const gcry_buffer_t *iov, + int iovcnt) +{ + _gcry_sha3_hash_buffers (outbuf, iov, iovcnt, &_gcry_digest_spec_sha3_224); +} + +static void +_gcry_sha3_256_hash_buffers (void *outbuf, const gcry_buffer_t *iov, + int iovcnt) +{ + _gcry_sha3_hash_buffers (outbuf, iov, iovcnt, &_gcry_digest_spec_sha3_256); +} + +static void +_gcry_sha3_384_hash_buffers (void *outbuf, const gcry_buffer_t *iov, + int iovcnt) +{ + _gcry_sha3_hash_buffers (outbuf, iov, iovcnt, &_gcry_digest_spec_sha3_384); +} + +static void +_gcry_sha3_512_hash_buffers (void *outbuf, const gcry_buffer_t *iov, + int iovcnt) +{ + _gcry_sha3_hash_buffers (outbuf, iov, iovcnt, &_gcry_digest_spec_sha3_512); +} + + +/* + Self-test section. + */ + + +static gpg_err_code_t +selftests_keccak (int algo, int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + const char *short_hash; + const char *long_hash; + const char *one_million_a_hash; + int hash_len; + + switch (algo) + { + default: + BUG(); + + case GCRY_MD_SHA3_224: + short_hash = + "\xe6\x42\x82\x4c\x3f\x8c\xf2\x4a\xd0\x92\x34\xee\x7d\x3c\x76\x6f" + "\xc9\xa3\xa5\x16\x8d\x0c\x94\xad\x73\xb4\x6f\xdf"; + long_hash = + "\x54\x3e\x68\x68\xe1\x66\x6c\x1a\x64\x36\x30\xdf\x77\x36\x7a\xe5" + "\xa6\x2a\x85\x07\x0a\x51\xc1\x4c\xbf\x66\x5c\xbc"; + one_million_a_hash = + "\xd6\x93\x35\xb9\x33\x25\x19\x2e\x51\x6a\x91\x2e\x6d\x19\xa1\x5c" + "\xb5\x1c\x6e\xd5\xc1\x52\x43\xe7\xa7\xfd\x65\x3c"; + hash_len = 28; + break; + + case GCRY_MD_SHA3_256: + short_hash = + "\x3a\x98\x5d\xa7\x4f\xe2\x25\xb2\x04\x5c\x17\x2d\x6b\xd3\x90\xbd" + "\x85\x5f\x08\x6e\x3e\x9d\x52\x5b\x46\xbf\xe2\x45\x11\x43\x15\x32"; + long_hash = + "\x91\x6f\x60\x61\xfe\x87\x97\x41\xca\x64\x69\xb4\x39\x71\xdf\xdb" + "\x28\xb1\xa3\x2d\xc3\x6c\xb3\x25\x4e\x81\x2b\xe2\x7a\xad\x1d\x18"; + one_million_a_hash = + "\x5c\x88\x75\xae\x47\x4a\x36\x34\xba\x4f\xd5\x5e\xc8\x5b\xff\xd6" + "\x61\xf3\x2a\xca\x75\xc6\xd6\x99\xd0\xcd\xcb\x6c\x11\x58\x91\xc1"; + hash_len = 32; + break; + + case GCRY_MD_SHA3_384: + short_hash = + "\xec\x01\x49\x82\x88\x51\x6f\xc9\x26\x45\x9f\x58\xe2\xc6\xad\x8d" + "\xf9\xb4\x73\xcb\x0f\xc0\x8c\x25\x96\xda\x7c\xf0\xe4\x9b\xe4\xb2" + "\x98\xd8\x8c\xea\x92\x7a\xc7\xf5\x39\xf1\xed\xf2\x28\x37\x6d\x25"; + long_hash = + "\x79\x40\x7d\x3b\x59\x16\xb5\x9c\x3e\x30\xb0\x98\x22\x97\x47\x91" + "\xc3\x13\xfb\x9e\xcc\x84\x9e\x40\x6f\x23\x59\x2d\x04\xf6\x25\xdc" + "\x8c\x70\x9b\x98\xb4\x3b\x38\x52\xb3\x37\x21\x61\x79\xaa\x7f\xc7"; + one_million_a_hash = + "\xee\xe9\xe2\x4d\x78\xc1\x85\x53\x37\x98\x34\x51\xdf\x97\xc8\xad" + "\x9e\xed\xf2\x56\xc6\x33\x4f\x8e\x94\x8d\x25\x2d\x5e\x0e\x76\x84" + "\x7a\xa0\x77\x4d\xdb\x90\xa8\x42\x19\x0d\x2c\x55\x8b\x4b\x83\x40"; + hash_len = 48; + break; + + case GCRY_MD_SHA3_512: + short_hash = + "\xb7\x51\x85\x0b\x1a\x57\x16\x8a\x56\x93\xcd\x92\x4b\x6b\x09\x6e" + "\x08\xf6\x21\x82\x74\x44\xf7\x0d\x88\x4f\x5d\x02\x40\xd2\x71\x2e" + "\x10\xe1\x16\xe9\x19\x2a\xf3\xc9\x1a\x7e\xc5\x76\x47\xe3\x93\x40" + "\x57\x34\x0b\x4c\xf4\x08\xd5\xa5\x65\x92\xf8\x27\x4e\xec\x53\xf0"; + long_hash = + "\xaf\xeb\xb2\xef\x54\x2e\x65\x79\xc5\x0c\xad\x06\xd2\xe5\x78\xf9" + "\xf8\xdd\x68\x81\xd7\xdc\x82\x4d\x26\x36\x0f\xee\xbf\x18\xa4\xfa" + "\x73\xe3\x26\x11\x22\x94\x8e\xfc\xfd\x49\x2e\x74\xe8\x2e\x21\x89" + "\xed\x0f\xb4\x40\xd1\x87\xf3\x82\x27\x0c\xb4\x55\xf2\x1d\xd1\x85"; + one_million_a_hash = + "\x3c\x3a\x87\x6d\xa1\x40\x34\xab\x60\x62\x7c\x07\x7b\xb9\x8f\x7e" + "\x12\x0a\x2a\x53\x70\x21\x2d\xff\xb3\x38\x5a\x18\xd4\xf3\x88\x59" + "\xed\x31\x1d\x0a\x9d\x51\x41\xce\x9c\xc5\xc6\x6e\xe6\x89\xb2\x66" + "\xa8\xaa\x18\xac\xe8\x28\x2a\x0e\x0d\xb5\x96\xc9\x0b\x0a\x7b\x87"; + hash_len = 64; + break; + + case GCRY_MD_SHAKE128: + short_hash = + "\x58\x81\x09\x2d\xd8\x18\xbf\x5c\xf8\xa3\xdd\xb7\x93\xfb\xcb\xa7" + "\x40\x97\xd5\xc5\x26\xa6\xd3\x5f\x97\xb8\x33\x51\x94\x0f\x2c\xc8"; + long_hash = + "\x7b\x6d\xf6\xff\x18\x11\x73\xb6\xd7\x89\x8d\x7f\xf6\x3f\xb0\x7b" + "\x7c\x23\x7d\xaf\x47\x1a\x5a\xe5\x60\x2a\xdb\xcc\xef\x9c\xcf\x4b"; + one_million_a_hash = + "\x9d\x22\x2c\x79\xc4\xff\x9d\x09\x2c\xf6\xca\x86\x14\x3a\xa4\x11" + "\xe3\x69\x97\x38\x08\xef\x97\x09\x32\x55\x82\x6c\x55\x72\xef\x58"; + hash_len = 32; + break; + + case GCRY_MD_SHAKE256: + short_hash = + "\x48\x33\x66\x60\x13\x60\xa8\x77\x1c\x68\x63\x08\x0c\xc4\x11\x4d" + "\x8d\xb4\x45\x30\xf8\xf1\xe1\xee\x4f\x94\xea\x37\xe7\x8b\x57\x39"; + long_hash = + "\x98\xbe\x04\x51\x6c\x04\xcc\x73\x59\x3f\xef\x3e\xd0\x35\x2e\xa9" + "\xf6\x44\x39\x42\xd6\x95\x0e\x29\xa3\x72\xa6\x81\xc3\xde\xaf\x45"; + one_million_a_hash = + "\x35\x78\xa7\xa4\xca\x91\x37\x56\x9c\xdf\x76\xed\x61\x7d\x31\xbb" + "\x99\x4f\xca\x9c\x1b\xbf\x8b\x18\x40\x13\xde\x82\x34\xdf\xd1\x3a"; + hash_len = 32; + break; + } + + what = "short string"; + errtxt = _gcry_hash_selftest_check_one (algo, 0, "abc", 3, short_hash, + hash_len); + if (errtxt) + goto failed; + + if (extended) + { + what = "long string"; + errtxt = _gcry_hash_selftest_check_one + (algo, 0, + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, + long_hash, hash_len); + if (errtxt) + goto failed; + + what = "one million \"a\""; + errtxt = _gcry_hash_selftest_check_one (algo, 1, NULL, 0, + one_million_a_hash, hash_len); + if (errtxt) + goto failed; + } + + return 0; /* Succeeded. */ + +failed: + if (report) + report ("digest", algo, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +/* Run a full self-test for ALGO and return 0 on success. */ +static gpg_err_code_t +run_selftests (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + switch (algo) + { + case GCRY_MD_SHA3_224: + case GCRY_MD_SHA3_256: + case GCRY_MD_SHA3_384: + case GCRY_MD_SHA3_512: + case GCRY_MD_SHAKE128: + case GCRY_MD_SHAKE256: + ec = selftests_keccak (algo, extended, report); + break; + default: + ec = GPG_ERR_DIGEST_ALGO; + break; + } + + return ec; +} + + + + +static byte sha3_224_asn[] = { 0x30 }; +static gcry_md_oid_spec_t oid_spec_sha3_224[] = + { + { "2.16.840.1.101.3.4.2.7" }, + /* PKCS#1 sha3_224WithRSAEncryption */ + { "?" }, + { NULL } + }; +static byte sha3_256_asn[] = { 0x30 }; +static gcry_md_oid_spec_t oid_spec_sha3_256[] = + { + { "2.16.840.1.101.3.4.2.8" }, + /* PKCS#1 sha3_256WithRSAEncryption */ + { "?" }, + { NULL } + }; +static byte sha3_384_asn[] = { 0x30 }; +static gcry_md_oid_spec_t oid_spec_sha3_384[] = + { + { "2.16.840.1.101.3.4.2.9" }, + /* PKCS#1 sha3_384WithRSAEncryption */ + { "?" }, + { NULL } + }; +static byte sha3_512_asn[] = { 0x30 }; +static gcry_md_oid_spec_t oid_spec_sha3_512[] = + { + { "2.16.840.1.101.3.4.2.10" }, + /* PKCS#1 sha3_512WithRSAEncryption */ + { "?" }, + { NULL } + }; +static byte shake128_asn[] = { 0x30 }; +static gcry_md_oid_spec_t oid_spec_shake128[] = + { + { "2.16.840.1.101.3.4.2.11" }, + /* PKCS#1 shake128WithRSAEncryption */ + { "?" }, + { NULL } + }; +static byte shake256_asn[] = { 0x30 }; +static gcry_md_oid_spec_t oid_spec_shake256[] = + { + { "2.16.840.1.101.3.4.2.12" }, + /* PKCS#1 shake256WithRSAEncryption */ + { "?" }, + { NULL } + }; + +gcry_md_spec_t _gcry_digest_spec_sha3_224 = + { + GCRY_MD_SHA3_224, {0, 1}, + "SHA3-224", sha3_224_asn, DIM (sha3_224_asn), oid_spec_sha3_224, 28, + sha3_224_init, keccak_write, keccak_final, keccak_read, NULL, + _gcry_sha3_224_hash_buffer, _gcry_sha3_224_hash_buffers, + sizeof (KECCAK_CONTEXT), + run_selftests + }; +gcry_md_spec_t _gcry_digest_spec_sha3_256 = + { + GCRY_MD_SHA3_256, {0, 1}, + "SHA3-256", sha3_256_asn, DIM (sha3_256_asn), oid_spec_sha3_256, 32, + sha3_256_init, keccak_write, keccak_final, keccak_read, NULL, + _gcry_sha3_256_hash_buffer, _gcry_sha3_256_hash_buffers, + sizeof (KECCAK_CONTEXT), + run_selftests + }; +gcry_md_spec_t _gcry_digest_spec_sha3_384 = + { + GCRY_MD_SHA3_384, {0, 1}, + "SHA3-384", sha3_384_asn, DIM (sha3_384_asn), oid_spec_sha3_384, 48, + sha3_384_init, keccak_write, keccak_final, keccak_read, NULL, + _gcry_sha3_384_hash_buffer, _gcry_sha3_384_hash_buffers, + sizeof (KECCAK_CONTEXT), + run_selftests + }; +gcry_md_spec_t _gcry_digest_spec_sha3_512 = + { + GCRY_MD_SHA3_512, {0, 1}, + "SHA3-512", sha3_512_asn, DIM (sha3_512_asn), oid_spec_sha3_512, 64, + sha3_512_init, keccak_write, keccak_final, keccak_read, NULL, + _gcry_sha3_512_hash_buffer, _gcry_sha3_512_hash_buffers, + sizeof (KECCAK_CONTEXT), + run_selftests + }; +gcry_md_spec_t _gcry_digest_spec_shake128 = + { + GCRY_MD_SHAKE128, {0, 1}, + "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 0, + shake128_init, keccak_write, keccak_final, NULL, keccak_extract, + NULL, NULL, + sizeof (KECCAK_CONTEXT), + run_selftests + }; +gcry_md_spec_t _gcry_digest_spec_shake256 = + { + GCRY_MD_SHAKE256, {0, 1}, + "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 0, + shake256_init, keccak_write, keccak_final, NULL, keccak_extract, + NULL, NULL, + sizeof (KECCAK_CONTEXT), + run_selftests + }; diff --git a/comm/third_party/libgcrypt/cipher/keccak_permute_32.h b/comm/third_party/libgcrypt/cipher/keccak_permute_32.h new file mode 100644 index 0000000000..1ce42a42fc --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/keccak_permute_32.h @@ -0,0 +1,536 @@ +/* keccak_permute_32.h - Keccak permute function (simple 32bit bit-interleaved) + * Copyright (C) 2015 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* The code is based on public-domain/CC0 "keccakc1024/simple32bi/ + * Keccak-simple32BI.c" implementation by Ronny Van Keer from SUPERCOP toolkit + * package. + */ + +/* Function that computes the Keccak-f[1600] permutation on the given state. */ +static unsigned int +KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd) +{ + const u32 *round_consts = round_consts_32bit; + const u32 *round_consts_end = round_consts_32bit + 2 * 24; + u32 Aba0, Abe0, Abi0, Abo0, Abu0; + u32 Aba1, Abe1, Abi1, Abo1, Abu1; + u32 Aga0, Age0, Agi0, Ago0, Agu0; + u32 Aga1, Age1, Agi1, Ago1, Agu1; + u32 Aka0, Ake0, Aki0, Ako0, Aku0; + u32 Aka1, Ake1, Aki1, Ako1, Aku1; + u32 Ama0, Ame0, Ami0, Amo0, Amu0; + u32 Ama1, Ame1, Ami1, Amo1, Amu1; + u32 Asa0, Ase0, Asi0, Aso0, Asu0; + u32 Asa1, Ase1, Asi1, Aso1, Asu1; + u32 BCa0, BCe0, BCi0, BCo0, BCu0; + u32 BCa1, BCe1, BCi1, BCo1, BCu1; + u32 Da0, De0, Di0, Do0, Du0; + u32 Da1, De1, Di1, Do1, Du1; + u32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; + u32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; + u32 Ega0, Ege0, Egi0, Ego0, Egu0; + u32 Ega1, Ege1, Egi1, Ego1, Egu1; + u32 Eka0, Eke0, Eki0, Eko0, Eku0; + u32 Eka1, Eke1, Eki1, Eko1, Eku1; + u32 Ema0, Eme0, Emi0, Emo0, Emu0; + u32 Ema1, Eme1, Emi1, Emo1, Emu1; + u32 Esa0, Ese0, Esi0, Eso0, Esu0; + u32 Esa1, Ese1, Esi1, Eso1, Esu1; + u32 *state = hd->u.state32bi; + + Aba0 = state[0]; + Aba1 = state[1]; + Abe0 = state[2]; + Abe1 = state[3]; + Abi0 = state[4]; + Abi1 = state[5]; + Abo0 = state[6]; + Abo1 = state[7]; + Abu0 = state[8]; + Abu1 = state[9]; + Aga0 = state[10]; + Aga1 = state[11]; + Age0 = state[12]; + Age1 = state[13]; + Agi0 = state[14]; + Agi1 = state[15]; + Ago0 = state[16]; + Ago1 = state[17]; + Agu0 = state[18]; + Agu1 = state[19]; + Aka0 = state[20]; + Aka1 = state[21]; + Ake0 = state[22]; + Ake1 = state[23]; + Aki0 = state[24]; + Aki1 = state[25]; + Ako0 = state[26]; + Ako1 = state[27]; + Aku0 = state[28]; + Aku1 = state[29]; + Ama0 = state[30]; + Ama1 = state[31]; + Ame0 = state[32]; + Ame1 = state[33]; + Ami0 = state[34]; + Ami1 = state[35]; + Amo0 = state[36]; + Amo1 = state[37]; + Amu0 = state[38]; + Amu1 = state[39]; + Asa0 = state[40]; + Asa1 = state[41]; + Ase0 = state[42]; + Ase1 = state[43]; + Asi0 = state[44]; + Asi1 = state[45]; + Aso0 = state[46]; + Aso1 = state[47]; + Asu0 = state[48]; + Asu1 = state[49]; + + do + { + /* prepareTheta */ + BCa0 = Aba0 ^ Aga0 ^ Aka0 ^ Ama0 ^ Asa0; + BCa1 = Aba1 ^ Aga1 ^ Aka1 ^ Ama1 ^ Asa1; + BCe0 = Abe0 ^ Age0 ^ Ake0 ^ Ame0 ^ Ase0; + BCe1 = Abe1 ^ Age1 ^ Ake1 ^ Ame1 ^ Ase1; + BCi0 = Abi0 ^ Agi0 ^ Aki0 ^ Ami0 ^ Asi0; + BCi1 = Abi1 ^ Agi1 ^ Aki1 ^ Ami1 ^ Asi1; + BCo0 = Abo0 ^ Ago0 ^ Ako0 ^ Amo0 ^ Aso0; + BCo1 = Abo1 ^ Ago1 ^ Ako1 ^ Amo1 ^ Aso1; + BCu0 = Abu0 ^ Agu0 ^ Aku0 ^ Amu0 ^ Asu0; + BCu1 = Abu1 ^ Agu1 ^ Aku1 ^ Amu1 ^ Asu1; + + /* thetaRhoPiChiIota(round , A, E) */ + Da0 = BCu0 ^ ROL32(BCe1, 1); + Da1 = BCu1 ^ BCe0; + De0 = BCa0 ^ ROL32(BCi1, 1); + De1 = BCa1 ^ BCi0; + Di0 = BCe0 ^ ROL32(BCo1, 1); + Di1 = BCe1 ^ BCo0; + Do0 = BCi0 ^ ROL32(BCu1, 1); + Do1 = BCi1 ^ BCu0; + Du0 = BCo0 ^ ROL32(BCa1, 1); + Du1 = BCo1 ^ BCa0; + + Aba0 ^= Da0; + BCa0 = Aba0; + Age0 ^= De0; + BCe0 = ROL32(Age0, 22); + Aki1 ^= Di1; + BCi0 = ROL32(Aki1, 22); + Amo1 ^= Do1; + BCo0 = ROL32(Amo1, 11); + Asu0 ^= Du0; + BCu0 = ROL32(Asu0, 7); + Eba0 = BCa0 ^ ANDN32(BCe0, BCi0); + Eba0 ^= *(round_consts++); + Ebe0 = BCe0 ^ ANDN32(BCi0, BCo0); + Ebi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Ebo0 = BCo0 ^ ANDN32(BCu0, BCa0); + Ebu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Aba1 ^= Da1; + BCa1 = Aba1; + Age1 ^= De1; + BCe1 = ROL32(Age1, 22); + Aki0 ^= Di0; + BCi1 = ROL32(Aki0, 21); + Amo0 ^= Do0; + BCo1 = ROL32(Amo0, 10); + Asu1 ^= Du1; + BCu1 = ROL32(Asu1, 7); + Eba1 = BCa1 ^ ANDN32(BCe1, BCi1); + Eba1 ^= *(round_consts++); + Ebe1 = BCe1 ^ ANDN32(BCi1, BCo1); + Ebi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Ebo1 = BCo1 ^ ANDN32(BCu1, BCa1); + Ebu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Abo0 ^= Do0; + BCa0 = ROL32(Abo0, 14); + Agu0 ^= Du0; + BCe0 = ROL32(Agu0, 10); + Aka1 ^= Da1; + BCi0 = ROL32(Aka1, 2); + Ame1 ^= De1; + BCo0 = ROL32(Ame1, 23); + Asi1 ^= Di1; + BCu0 = ROL32(Asi1, 31); + Ega0 = BCa0 ^ ANDN32(BCe0, BCi0); + Ege0 = BCe0 ^ ANDN32(BCi0, BCo0); + Egi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Ego0 = BCo0 ^ ANDN32(BCu0, BCa0); + Egu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Abo1 ^= Do1; + BCa1 = ROL32(Abo1, 14); + Agu1 ^= Du1; + BCe1 = ROL32(Agu1, 10); + Aka0 ^= Da0; + BCi1 = ROL32(Aka0, 1); + Ame0 ^= De0; + BCo1 = ROL32(Ame0, 22); + Asi0 ^= Di0; + BCu1 = ROL32(Asi0, 30); + Ega1 = BCa1 ^ ANDN32(BCe1, BCi1); + Ege1 = BCe1 ^ ANDN32(BCi1, BCo1); + Egi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Ego1 = BCo1 ^ ANDN32(BCu1, BCa1); + Egu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Abe1 ^= De1; + BCa0 = ROL32(Abe1, 1); + Agi0 ^= Di0; + BCe0 = ROL32(Agi0, 3); + Ako1 ^= Do1; + BCi0 = ROL32(Ako1, 13); + Amu0 ^= Du0; + BCo0 = ROL32(Amu0, 4); + Asa0 ^= Da0; + BCu0 = ROL32(Asa0, 9); + Eka0 = BCa0 ^ ANDN32(BCe0, BCi0); + Eke0 = BCe0 ^ ANDN32(BCi0, BCo0); + Eki0 = BCi0 ^ ANDN32(BCo0, BCu0); + Eko0 = BCo0 ^ ANDN32(BCu0, BCa0); + Eku0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Abe0 ^= De0; + BCa1 = Abe0; + Agi1 ^= Di1; + BCe1 = ROL32(Agi1, 3); + Ako0 ^= Do0; + BCi1 = ROL32(Ako0, 12); + Amu1 ^= Du1; + BCo1 = ROL32(Amu1, 4); + Asa1 ^= Da1; + BCu1 = ROL32(Asa1, 9); + Eka1 = BCa1 ^ ANDN32(BCe1, BCi1); + Eke1 = BCe1 ^ ANDN32(BCi1, BCo1); + Eki1 = BCi1 ^ ANDN32(BCo1, BCu1); + Eko1 = BCo1 ^ ANDN32(BCu1, BCa1); + Eku1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Abu1 ^= Du1; + BCa0 = ROL32(Abu1, 14); + Aga0 ^= Da0; + BCe0 = ROL32(Aga0, 18); + Ake0 ^= De0; + BCi0 = ROL32(Ake0, 5); + Ami1 ^= Di1; + BCo0 = ROL32(Ami1, 8); + Aso0 ^= Do0; + BCu0 = ROL32(Aso0, 28); + Ema0 = BCa0 ^ ANDN32(BCe0, BCi0); + Eme0 = BCe0 ^ ANDN32(BCi0, BCo0); + Emi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Emo0 = BCo0 ^ ANDN32(BCu0, BCa0); + Emu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Abu0 ^= Du0; + BCa1 = ROL32(Abu0, 13); + Aga1 ^= Da1; + BCe1 = ROL32(Aga1, 18); + Ake1 ^= De1; + BCi1 = ROL32(Ake1, 5); + Ami0 ^= Di0; + BCo1 = ROL32(Ami0, 7); + Aso1 ^= Do1; + BCu1 = ROL32(Aso1, 28); + Ema1 = BCa1 ^ ANDN32(BCe1, BCi1); + Eme1 = BCe1 ^ ANDN32(BCi1, BCo1); + Emi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Emo1 = BCo1 ^ ANDN32(BCu1, BCa1); + Emu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Abi0 ^= Di0; + BCa0 = ROL32(Abi0, 31); + Ago1 ^= Do1; + BCe0 = ROL32(Ago1, 28); + Aku1 ^= Du1; + BCi0 = ROL32(Aku1, 20); + Ama1 ^= Da1; + BCo0 = ROL32(Ama1, 21); + Ase0 ^= De0; + BCu0 = ROL32(Ase0, 1); + Esa0 = BCa0 ^ ANDN32(BCe0, BCi0); + Ese0 = BCe0 ^ ANDN32(BCi0, BCo0); + Esi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Eso0 = BCo0 ^ ANDN32(BCu0, BCa0); + Esu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Abi1 ^= Di1; + BCa1 = ROL32(Abi1, 31); + Ago0 ^= Do0; + BCe1 = ROL32(Ago0, 27); + Aku0 ^= Du0; + BCi1 = ROL32(Aku0, 19); + Ama0 ^= Da0; + BCo1 = ROL32(Ama0, 20); + Ase1 ^= De1; + BCu1 = ROL32(Ase1, 1); + Esa1 = BCa1 ^ ANDN32(BCe1, BCi1); + Ese1 = BCe1 ^ ANDN32(BCi1, BCo1); + Esi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Eso1 = BCo1 ^ ANDN32(BCu1, BCa1); + Esu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + /* prepareTheta */ + BCa0 = Eba0 ^ Ega0 ^ Eka0 ^ Ema0 ^ Esa0; + BCa1 = Eba1 ^ Ega1 ^ Eka1 ^ Ema1 ^ Esa1; + BCe0 = Ebe0 ^ Ege0 ^ Eke0 ^ Eme0 ^ Ese0; + BCe1 = Ebe1 ^ Ege1 ^ Eke1 ^ Eme1 ^ Ese1; + BCi0 = Ebi0 ^ Egi0 ^ Eki0 ^ Emi0 ^ Esi0; + BCi1 = Ebi1 ^ Egi1 ^ Eki1 ^ Emi1 ^ Esi1; + BCo0 = Ebo0 ^ Ego0 ^ Eko0 ^ Emo0 ^ Eso0; + BCo1 = Ebo1 ^ Ego1 ^ Eko1 ^ Emo1 ^ Eso1; + BCu0 = Ebu0 ^ Egu0 ^ Eku0 ^ Emu0 ^ Esu0; + BCu1 = Ebu1 ^ Egu1 ^ Eku1 ^ Emu1 ^ Esu1; + + /* thetaRhoPiChiIota(round+1, E, A) */ + Da0 = BCu0 ^ ROL32(BCe1, 1); + Da1 = BCu1 ^ BCe0; + De0 = BCa0 ^ ROL32(BCi1, 1); + De1 = BCa1 ^ BCi0; + Di0 = BCe0 ^ ROL32(BCo1, 1); + Di1 = BCe1 ^ BCo0; + Do0 = BCi0 ^ ROL32(BCu1, 1); + Do1 = BCi1 ^ BCu0; + Du0 = BCo0 ^ ROL32(BCa1, 1); + Du1 = BCo1 ^ BCa0; + + Eba0 ^= Da0; + BCa0 = Eba0; + Ege0 ^= De0; + BCe0 = ROL32(Ege0, 22); + Eki1 ^= Di1; + BCi0 = ROL32(Eki1, 22); + Emo1 ^= Do1; + BCo0 = ROL32(Emo1, 11); + Esu0 ^= Du0; + BCu0 = ROL32(Esu0, 7); + Aba0 = BCa0 ^ ANDN32(BCe0, BCi0); + Aba0 ^= *(round_consts++); + Abe0 = BCe0 ^ ANDN32(BCi0, BCo0); + Abi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Abo0 = BCo0 ^ ANDN32(BCu0, BCa0); + Abu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Eba1 ^= Da1; + BCa1 = Eba1; + Ege1 ^= De1; + BCe1 = ROL32(Ege1, 22); + Eki0 ^= Di0; + BCi1 = ROL32(Eki0, 21); + Emo0 ^= Do0; + BCo1 = ROL32(Emo0, 10); + Esu1 ^= Du1; + BCu1 = ROL32(Esu1, 7); + Aba1 = BCa1 ^ ANDN32(BCe1, BCi1); + Aba1 ^= *(round_consts++); + Abe1 = BCe1 ^ ANDN32(BCi1, BCo1); + Abi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Abo1 = BCo1 ^ ANDN32(BCu1, BCa1); + Abu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Ebo0 ^= Do0; + BCa0 = ROL32(Ebo0, 14); + Egu0 ^= Du0; + BCe0 = ROL32(Egu0, 10); + Eka1 ^= Da1; + BCi0 = ROL32(Eka1, 2); + Eme1 ^= De1; + BCo0 = ROL32(Eme1, 23); + Esi1 ^= Di1; + BCu0 = ROL32(Esi1, 31); + Aga0 = BCa0 ^ ANDN32(BCe0, BCi0); + Age0 = BCe0 ^ ANDN32(BCi0, BCo0); + Agi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Ago0 = BCo0 ^ ANDN32(BCu0, BCa0); + Agu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Ebo1 ^= Do1; + BCa1 = ROL32(Ebo1, 14); + Egu1 ^= Du1; + BCe1 = ROL32(Egu1, 10); + Eka0 ^= Da0; + BCi1 = ROL32(Eka0, 1); + Eme0 ^= De0; + BCo1 = ROL32(Eme0, 22); + Esi0 ^= Di0; + BCu1 = ROL32(Esi0, 30); + Aga1 = BCa1 ^ ANDN32(BCe1, BCi1); + Age1 = BCe1 ^ ANDN32(BCi1, BCo1); + Agi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Ago1 = BCo1 ^ ANDN32(BCu1, BCa1); + Agu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Ebe1 ^= De1; + BCa0 = ROL32(Ebe1, 1); + Egi0 ^= Di0; + BCe0 = ROL32(Egi0, 3); + Eko1 ^= Do1; + BCi0 = ROL32(Eko1, 13); + Emu0 ^= Du0; + BCo0 = ROL32(Emu0, 4); + Esa0 ^= Da0; + BCu0 = ROL32(Esa0, 9); + Aka0 = BCa0 ^ ANDN32(BCe0, BCi0); + Ake0 = BCe0 ^ ANDN32(BCi0, BCo0); + Aki0 = BCi0 ^ ANDN32(BCo0, BCu0); + Ako0 = BCo0 ^ ANDN32(BCu0, BCa0); + Aku0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Ebe0 ^= De0; + BCa1 = Ebe0; + Egi1 ^= Di1; + BCe1 = ROL32(Egi1, 3); + Eko0 ^= Do0; + BCi1 = ROL32(Eko0, 12); + Emu1 ^= Du1; + BCo1 = ROL32(Emu1, 4); + Esa1 ^= Da1; + BCu1 = ROL32(Esa1, 9); + Aka1 = BCa1 ^ ANDN32(BCe1, BCi1); + Ake1 = BCe1 ^ ANDN32(BCi1, BCo1); + Aki1 = BCi1 ^ ANDN32(BCo1, BCu1); + Ako1 = BCo1 ^ ANDN32(BCu1, BCa1); + Aku1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Ebu1 ^= Du1; + BCa0 = ROL32(Ebu1, 14); + Ega0 ^= Da0; + BCe0 = ROL32(Ega0, 18); + Eke0 ^= De0; + BCi0 = ROL32(Eke0, 5); + Emi1 ^= Di1; + BCo0 = ROL32(Emi1, 8); + Eso0 ^= Do0; + BCu0 = ROL32(Eso0, 28); + Ama0 = BCa0 ^ ANDN32(BCe0, BCi0); + Ame0 = BCe0 ^ ANDN32(BCi0, BCo0); + Ami0 = BCi0 ^ ANDN32(BCo0, BCu0); + Amo0 = BCo0 ^ ANDN32(BCu0, BCa0); + Amu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Ebu0 ^= Du0; + BCa1 = ROL32(Ebu0, 13); + Ega1 ^= Da1; + BCe1 = ROL32(Ega1, 18); + Eke1 ^= De1; + BCi1 = ROL32(Eke1, 5); + Emi0 ^= Di0; + BCo1 = ROL32(Emi0, 7); + Eso1 ^= Do1; + BCu1 = ROL32(Eso1, 28); + Ama1 = BCa1 ^ ANDN32(BCe1, BCi1); + Ame1 = BCe1 ^ ANDN32(BCi1, BCo1); + Ami1 = BCi1 ^ ANDN32(BCo1, BCu1); + Amo1 = BCo1 ^ ANDN32(BCu1, BCa1); + Amu1 = BCu1 ^ ANDN32(BCa1, BCe1); + + Ebi0 ^= Di0; + BCa0 = ROL32(Ebi0, 31); + Ego1 ^= Do1; + BCe0 = ROL32(Ego1, 28); + Eku1 ^= Du1; + BCi0 = ROL32(Eku1, 20); + Ema1 ^= Da1; + BCo0 = ROL32(Ema1, 21); + Ese0 ^= De0; + BCu0 = ROL32(Ese0, 1); + Asa0 = BCa0 ^ ANDN32(BCe0, BCi0); + Ase0 = BCe0 ^ ANDN32(BCi0, BCo0); + Asi0 = BCi0 ^ ANDN32(BCo0, BCu0); + Aso0 = BCo0 ^ ANDN32(BCu0, BCa0); + Asu0 = BCu0 ^ ANDN32(BCa0, BCe0); + + Ebi1 ^= Di1; + BCa1 = ROL32(Ebi1, 31); + Ego0 ^= Do0; + BCe1 = ROL32(Ego0, 27); + Eku0 ^= Du0; + BCi1 = ROL32(Eku0, 19); + Ema0 ^= Da0; + BCo1 = ROL32(Ema0, 20); + Ese1 ^= De1; + BCu1 = ROL32(Ese1, 1); + Asa1 = BCa1 ^ ANDN32(BCe1, BCi1); + Ase1 = BCe1 ^ ANDN32(BCi1, BCo1); + Asi1 = BCi1 ^ ANDN32(BCo1, BCu1); + Aso1 = BCo1 ^ ANDN32(BCu1, BCa1); + Asu1 = BCu1 ^ ANDN32(BCa1, BCe1); + } + while (round_consts < round_consts_end); + + state[0] = Aba0; + state[1] = Aba1; + state[2] = Abe0; + state[3] = Abe1; + state[4] = Abi0; + state[5] = Abi1; + state[6] = Abo0; + state[7] = Abo1; + state[8] = Abu0; + state[9] = Abu1; + state[10] = Aga0; + state[11] = Aga1; + state[12] = Age0; + state[13] = Age1; + state[14] = Agi0; + state[15] = Agi1; + state[16] = Ago0; + state[17] = Ago1; + state[18] = Agu0; + state[19] = Agu1; + state[20] = Aka0; + state[21] = Aka1; + state[22] = Ake0; + state[23] = Ake1; + state[24] = Aki0; + state[25] = Aki1; + state[26] = Ako0; + state[27] = Ako1; + state[28] = Aku0; + state[29] = Aku1; + state[30] = Ama0; + state[31] = Ama1; + state[32] = Ame0; + state[33] = Ame1; + state[34] = Ami0; + state[35] = Ami1; + state[36] = Amo0; + state[37] = Amo1; + state[38] = Amu0; + state[39] = Amu1; + state[40] = Asa0; + state[41] = Asa1; + state[42] = Ase0; + state[43] = Ase1; + state[44] = Asi0; + state[45] = Asi1; + state[46] = Aso0; + state[47] = Aso1; + state[48] = Asu0; + state[49] = Asu1; + + return sizeof(void *) * 4 + sizeof(u32) * 12 * 5 * 2; +} diff --git a/comm/third_party/libgcrypt/cipher/keccak_permute_64.h b/comm/third_party/libgcrypt/cipher/keccak_permute_64.h new file mode 100644 index 0000000000..b28c871ec1 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/keccak_permute_64.h @@ -0,0 +1,385 @@ +/* keccak_permute_64.h - Keccak permute function (simple 64bit) + * Copyright (C) 2015 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* The code is based on public-domain/CC0 "keccakc1024/simple/Keccak-simple.c" + * implementation by Ronny Van Keer from SUPERCOP toolkit package. + */ + +/* Function that computes the Keccak-f[1600] permutation on the given state. */ +static unsigned int +KECCAK_F1600_PERMUTE_FUNC_NAME(KECCAK_STATE *hd) +{ + const u64 *round_consts = _gcry_keccak_round_consts_64bit; + const u64 *round_consts_end = _gcry_keccak_round_consts_64bit + 24; + u64 Aba, Abe, Abi, Abo, Abu; + u64 Aga, Age, Agi, Ago, Agu; + u64 Aka, Ake, Aki, Ako, Aku; + u64 Ama, Ame, Ami, Amo, Amu; + u64 Asa, Ase, Asi, Aso, Asu; + u64 BCa, BCe, BCi, BCo, BCu; + u64 Da, De, Di, Do, Du; + u64 Eba, Ebe, Ebi, Ebo, Ebu; + u64 Ega, Ege, Egi, Ego, Egu; + u64 Eka, Eke, Eki, Eko, Eku; + u64 Ema, Eme, Emi, Emo, Emu; + u64 Esa, Ese, Esi, Eso, Esu; + u64 *state = hd->u.state64; + + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + do + { + /* prepareTheta */ + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + /* thetaRhoPiChiIotaPrepareTheta(round , A, E) */ + Da = BCu ^ ROL64(BCe, 1); + De = BCa ^ ROL64(BCi, 1); + Di = BCe ^ ROL64(BCo, 1); + Do = BCi ^ ROL64(BCu, 1); + Du = BCo ^ ROL64(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = ROL64(Age, 44); + Aki ^= Di; + BCi = ROL64(Aki, 43); + Amo ^= Do; + BCo = ROL64(Amo, 21); + Asu ^= Du; + BCu = ROL64(Asu, 14); + Eba = BCa ^ ANDN64(BCe, BCi); + Eba ^= *(round_consts++); + Ebe = BCe ^ ANDN64(BCi, BCo); + Ebi = BCi ^ ANDN64(BCo, BCu); + Ebo = BCo ^ ANDN64(BCu, BCa); + Ebu = BCu ^ ANDN64(BCa, BCe); + + Abo ^= Do; + BCa = ROL64(Abo, 28); + Agu ^= Du; + BCe = ROL64(Agu, 20); + Aka ^= Da; + BCi = ROL64(Aka, 3); + Ame ^= De; + BCo = ROL64(Ame, 45); + Asi ^= Di; + BCu = ROL64(Asi, 61); + Ega = BCa ^ ANDN64(BCe, BCi); + Ege = BCe ^ ANDN64(BCi, BCo); + Egi = BCi ^ ANDN64(BCo, BCu); + Ego = BCo ^ ANDN64(BCu, BCa); + Egu = BCu ^ ANDN64(BCa, BCe); + + Abe ^= De; + BCa = ROL64(Abe, 1); + Agi ^= Di; + BCe = ROL64(Agi, 6); + Ako ^= Do; + BCi = ROL64(Ako, 25); + Amu ^= Du; + BCo = ROL64(Amu, 8); + Asa ^= Da; + BCu = ROL64(Asa, 18); + Eka = BCa ^ ANDN64(BCe, BCi); + Eke = BCe ^ ANDN64(BCi, BCo); + Eki = BCi ^ ANDN64(BCo, BCu); + Eko = BCo ^ ANDN64(BCu, BCa); + Eku = BCu ^ ANDN64(BCa, BCe); + + Abu ^= Du; + BCa = ROL64(Abu, 27); + Aga ^= Da; + BCe = ROL64(Aga, 36); + Ake ^= De; + BCi = ROL64(Ake, 10); + Ami ^= Di; + BCo = ROL64(Ami, 15); + Aso ^= Do; + BCu = ROL64(Aso, 56); + Ema = BCa ^ ANDN64(BCe, BCi); + Eme = BCe ^ ANDN64(BCi, BCo); + Emi = BCi ^ ANDN64(BCo, BCu); + Emo = BCo ^ ANDN64(BCu, BCa); + Emu = BCu ^ ANDN64(BCa, BCe); + + Abi ^= Di; + BCa = ROL64(Abi, 62); + Ago ^= Do; + BCe = ROL64(Ago, 55); + Aku ^= Du; + BCi = ROL64(Aku, 39); + Ama ^= Da; + BCo = ROL64(Ama, 41); + Ase ^= De; + BCu = ROL64(Ase, 2); + Esa = BCa ^ ANDN64(BCe, BCi); + Ese = BCe ^ ANDN64(BCi, BCo); + Esi = BCi ^ ANDN64(BCo, BCu); + Eso = BCo ^ ANDN64(BCu, BCa); + Esu = BCu ^ ANDN64(BCa, BCe); + + /* prepareTheta */ + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + /* thetaRhoPiChiIotaPrepareTheta(round+1, E, A) */ + Da = BCu ^ ROL64(BCe, 1); + De = BCa ^ ROL64(BCi, 1); + Di = BCe ^ ROL64(BCo, 1); + Do = BCi ^ ROL64(BCu, 1); + Du = BCo ^ ROL64(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = ROL64(Ege, 44); + Eki ^= Di; + BCi = ROL64(Eki, 43); + Emo ^= Do; + BCo = ROL64(Emo, 21); + Esu ^= Du; + BCu = ROL64(Esu, 14); + Aba = BCa ^ ANDN64(BCe, BCi); + Aba ^= *(round_consts++); + Abe = BCe ^ ANDN64(BCi, BCo); + Abi = BCi ^ ANDN64(BCo, BCu); + Abo = BCo ^ ANDN64(BCu, BCa); + Abu = BCu ^ ANDN64(BCa, BCe); + + Ebo ^= Do; + BCa = ROL64(Ebo, 28); + Egu ^= Du; + BCe = ROL64(Egu, 20); + Eka ^= Da; + BCi = ROL64(Eka, 3); + Eme ^= De; + BCo = ROL64(Eme, 45); + Esi ^= Di; + BCu = ROL64(Esi, 61); + Aga = BCa ^ ANDN64(BCe, BCi); + Age = BCe ^ ANDN64(BCi, BCo); + Agi = BCi ^ ANDN64(BCo, BCu); + Ago = BCo ^ ANDN64(BCu, BCa); + Agu = BCu ^ ANDN64(BCa, BCe); + + Ebe ^= De; + BCa = ROL64(Ebe, 1); + Egi ^= Di; + BCe = ROL64(Egi, 6); + Eko ^= Do; + BCi = ROL64(Eko, 25); + Emu ^= Du; + BCo = ROL64(Emu, 8); + Esa ^= Da; + BCu = ROL64(Esa, 18); + Aka = BCa ^ ANDN64(BCe, BCi); + Ake = BCe ^ ANDN64(BCi, BCo); + Aki = BCi ^ ANDN64(BCo, BCu); + Ako = BCo ^ ANDN64(BCu, BCa); + Aku = BCu ^ ANDN64(BCa, BCe); + + Ebu ^= Du; + BCa = ROL64(Ebu, 27); + Ega ^= Da; + BCe = ROL64(Ega, 36); + Eke ^= De; + BCi = ROL64(Eke, 10); + Emi ^= Di; + BCo = ROL64(Emi, 15); + Eso ^= Do; + BCu = ROL64(Eso, 56); + Ama = BCa ^ ANDN64(BCe, BCi); + Ame = BCe ^ ANDN64(BCi, BCo); + Ami = BCi ^ ANDN64(BCo, BCu); + Amo = BCo ^ ANDN64(BCu, BCa); + Amu = BCu ^ ANDN64(BCa, BCe); + + Ebi ^= Di; + BCa = ROL64(Ebi, 62); + Ego ^= Do; + BCe = ROL64(Ego, 55); + Eku ^= Du; + BCi = ROL64(Eku, 39); + Ema ^= Da; + BCo = ROL64(Ema, 41); + Ese ^= De; + BCu = ROL64(Ese, 2); + Asa = BCa ^ ANDN64(BCe, BCi); + Ase = BCe ^ ANDN64(BCi, BCo); + Asi = BCi ^ ANDN64(BCo, BCu); + Aso = BCo ^ ANDN64(BCu, BCa); + Asu = BCu ^ ANDN64(BCa, BCe); + } + while (round_consts < round_consts_end); + + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; + + return sizeof(void *) * 4 + sizeof(u64) * 12 * 5; +} + +static unsigned int +KECCAK_F1600_ABSORB_FUNC_NAME(KECCAK_STATE *hd, int pos, const byte *lanes, + unsigned int nlanes, int blocklanes) +{ + unsigned int burn = 0; + + while (nlanes) + { + switch (blocklanes) + { + case 21: + /* SHAKE128 */ + while (pos == 0 && nlanes >= 21) + { + nlanes -= 21; + absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8; + absorb_lanes64_8(&hd->u.state64[8], lanes); lanes += 8 * 8; + absorb_lanes64_4(&hd->u.state64[16], lanes); lanes += 8 * 4; + absorb_lanes64_1(&hd->u.state64[20], lanes); lanes += 8 * 1; + + burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd); + } + break; + + case 18: + /* SHA3-224 */ + while (pos == 0 && nlanes >= 18) + { + nlanes -= 18; + absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8; + absorb_lanes64_8(&hd->u.state64[8], lanes); lanes += 8 * 8; + absorb_lanes64_2(&hd->u.state64[16], lanes); lanes += 8 * 2; + + burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd); + } + break; + + case 17: + /* SHA3-256 & SHAKE256 */ + while (pos == 0 && nlanes >= 17) + { + nlanes -= 17; + absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8; + absorb_lanes64_8(&hd->u.state64[8], lanes); lanes += 8 * 8; + absorb_lanes64_1(&hd->u.state64[16], lanes); lanes += 8 * 1; + + burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd); + } + break; + + case 13: + /* SHA3-384 */ + while (pos == 0 && nlanes >= 13) + { + nlanes -= 13; + absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8; + absorb_lanes64_4(&hd->u.state64[8], lanes); lanes += 8 * 4; + absorb_lanes64_1(&hd->u.state64[12], lanes); lanes += 8 * 1; + + burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd); + } + break; + + case 9: + /* SHA3-512 */ + while (pos == 0 && nlanes >= 9) + { + nlanes -= 9; + absorb_lanes64_8(&hd->u.state64[0], lanes); lanes += 8 * 8; + absorb_lanes64_1(&hd->u.state64[8], lanes); lanes += 8 * 1; + + burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd); + } + break; + } + + while (nlanes) + { + hd->u.state64[pos] ^= buf_get_le64(lanes); + lanes += 8; + nlanes--; + + if (++pos == blocklanes) + { + burn = KECCAK_F1600_PERMUTE_FUNC_NAME(hd); + pos = 0; + break; + } + } + } + + return burn; +} diff --git a/comm/third_party/libgcrypt/cipher/mac-cmac.c b/comm/third_party/libgcrypt/cipher/mac-cmac.c new file mode 100644 index 0000000000..8d5d5ca304 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac-cmac.c @@ -0,0 +1,524 @@ +/* mac-cmac.c - CMAC glue for MAC API + * Copyright (C) 2013 Jussi Kivilinna + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "./mac-internal.h" + + +static int +map_mac_algo_to_cipher (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_CIPHER_NONE; + case GCRY_MAC_CMAC_AES: + return GCRY_CIPHER_AES; + case GCRY_MAC_CMAC_3DES: + return GCRY_CIPHER_3DES; + case GCRY_MAC_CMAC_CAMELLIA: + return GCRY_CIPHER_CAMELLIA128; + case GCRY_MAC_CMAC_IDEA: + return GCRY_CIPHER_IDEA; + case GCRY_MAC_CMAC_CAST5: + return GCRY_CIPHER_CAST5; + case GCRY_MAC_CMAC_BLOWFISH: + return GCRY_CIPHER_BLOWFISH; + case GCRY_MAC_CMAC_TWOFISH: + return GCRY_CIPHER_TWOFISH; + case GCRY_MAC_CMAC_SERPENT: + return GCRY_CIPHER_SERPENT128; + case GCRY_MAC_CMAC_SEED: + return GCRY_CIPHER_SEED; + case GCRY_MAC_CMAC_RFC2268: + return GCRY_CIPHER_RFC2268_128; + case GCRY_MAC_CMAC_GOST28147: + return GCRY_CIPHER_GOST28147; + case GCRY_MAC_CMAC_SM4: + return GCRY_CIPHER_SM4; + } +} + + +static gcry_err_code_t +cmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_cipher_hd_t hd; + int secure = (h->magic == CTX_MAC_MAGIC_SECURE); + int cipher_algo; + unsigned int flags; + + cipher_algo = map_mac_algo_to_cipher (h->spec->algo); + flags = (secure ? GCRY_CIPHER_SECURE : 0); + + err = _gcry_cipher_open_internal (&hd, cipher_algo, GCRY_CIPHER_MODE_CMAC, + flags); + if (err) + return err; + + h->u.cmac.cipher_algo = cipher_algo; + h->u.cmac.ctx = hd; + h->u.cmac.blklen = _gcry_cipher_get_algo_blklen (cipher_algo); + return 0; +} + + +static void +cmac_close (gcry_mac_hd_t h) +{ + _gcry_cipher_close (h->u.cmac.ctx); + h->u.cmac.ctx = NULL; +} + + +static gcry_err_code_t +cmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return _gcry_cipher_setkey (h->u.cmac.ctx, key, keylen); +} + + +static gcry_err_code_t +cmac_reset (gcry_mac_hd_t h) +{ + return _gcry_cipher_reset (h->u.cmac.ctx); +} + + +static gcry_err_code_t +cmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_cmac_authenticate (h->u.cmac.ctx, buf, buflen); +} + + +static gcry_err_code_t +cmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + if (*outlen > h->u.cmac.blklen) + *outlen = h->u.cmac.blklen; + return _gcry_cipher_cmac_get_tag (h->u.cmac.ctx, outbuf, *outlen); +} + + +static gcry_err_code_t +cmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_cmac_check_tag (h->u.cmac.ctx, buf, buflen); +} + + +static unsigned int +cmac_get_maclen (int algo) +{ + return _gcry_cipher_get_algo_blklen (map_mac_algo_to_cipher (algo)); +} + + +static unsigned int +cmac_get_keylen (int algo) +{ + return _gcry_cipher_get_algo_keylen (map_mac_algo_to_cipher (algo)); +} + + +/* Check one CMAC with MAC ALGO using the regular MAC + * API. (DATA,DATALEN) is the data to be MACed, (KEY,KEYLEN) the key + * and (EXPECT,EXPECTLEN) the expected result. Returns NULL on + * success or a string describing the failure. */ +static const char * +check_one (int algo, const char *data, size_t datalen, + const char *key, size_t keylen, + const char *expect, size_t expectlen) +{ + gcry_mac_hd_t hd; + unsigned char mac[512]; /* hardcoded to avoid allocation */ + unsigned int maclen; + size_t macoutlen; + int i; + gcry_error_t err = 0; + + err = _gcry_mac_open (&hd, algo, 0, NULL); + if (err) + return "gcry_mac_open failed"; + + i = _gcry_mac_get_algo (hd); + if (i != algo) + return "gcry_mac_get_algo failed"; + + maclen = _gcry_mac_get_algo_maclen (algo); + if (maclen < 1 || maclen > 500) + return "gcry_mac_get_algo_maclen failed"; + + if (maclen != expectlen) + return "invalid tests data"; + + err = _gcry_mac_setkey (hd, key, keylen); + if (err) + { + _gcry_mac_close (hd); + return "gcry_mac_setkey failed"; + } + + err = _gcry_mac_write (hd, data, datalen); + if (err) + { + _gcry_mac_close (hd); + return "gcry_mac_write failed"; + } + + err = _gcry_mac_verify (hd, expect, maclen); + if (err) + { + _gcry_mac_close (hd); + return "gcry_mac_verify failed"; + } + + macoutlen = maclen; + err = _gcry_mac_read (hd, mac, &macoutlen); + _gcry_mac_close (hd); + if (err) + return "gcry_mac_read failed"; + + if (memcmp (mac, expect, maclen)) + return "does not match"; + + return NULL; +} + + +/* + * CMAC AES and DES test vectors are from + * http://web.archive.org/web/20130930212819/http://csrc.nist.gov/publica \ + * tions/nistpubs/800-38B/Updated_CMAC_Examples.pdf + */ + +static gpg_err_code_t +selftests_cmac_3des (int extended, selftest_report_func_t report) +{ + static const struct + { + const char *desc; + const char *data; + const char *key; + const char *expect; + } tv[] = + { + { "Basic 3DES", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57", + "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" + "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", + "\x74\x3d\xdb\xe0\xce\x2d\xc2\xed" }, + { "Extended 3DES #1", + "", + "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" + "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", + "\xb7\xa6\x88\xe1\x22\xff\xaf\x95" }, + { "Extended 3DES #2", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96", + "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" + "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", + "\x8e\x8f\x29\x31\x36\x28\x37\x97" }, + { "Extended 3DES #3", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51", + "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" + "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", + "\x33\xe6\xb1\x09\x24\x00\xea\xe5" }, + { "Extended 3DES #4", + "", + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38" + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5", + "\xbd\x2e\xbf\x9a\x3b\xa0\x03\x61" }, + { "Extended 3DES #5", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96", + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38" + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5", + "\x4f\xf2\xab\x81\x3c\x53\xce\x83" }, + { "Extended 3DES #6", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57", + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38" + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5", + "\x62\xdd\x1b\x47\x19\x02\xbd\x4e" }, + { "Extended 3DES #7", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51", + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5\x8a\x3d\x10\xba\x80\x57\x0d\x38" + "\x4c\xf1\x51\x34\xa2\x85\x0d\xd5", + "\x31\xb1\xe4\x31\xda\xbc\x4e\xb8" }, + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + errtxt = check_one (GCRY_MAC_CMAC_3DES, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + tv[tvidx].expect, 8); + if (errtxt) + goto failed; + if (!extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("cmac", GCRY_MAC_CMAC_3DES, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + + +static gpg_err_code_t +selftests_cmac_aes (int extended, selftest_report_func_t report) +{ + static const struct + { + const char *desc; + const char *data; + const char *key; + const char *expect; + } tv[] = + { + { "Basic AES128", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", + "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + "\xdf\xa6\x67\x47\xde\x9a\xe6\x30\x30\xca\x32\x61\x14\x97\xc8\x27" }, + { "Basic AES192", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", + "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + "\x8a\x1d\xe5\xbe\x2e\xb3\x1a\xad\x08\x9a\x82\xe6\xee\x90\x8b\x0e" }, + { "Basic AES256", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", + "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + "\xaa\xf3\xd8\xf1\xde\x56\x40\xc2\x32\xf5\xb1\x69\xb9\xc9\x11\xe6" }, + { "Extended AES #1", + "", + "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + "\xbb\x1d\x69\x29\xe9\x59\x37\x28\x7f\xa3\x7d\x12\x9b\x75\x67\x46" }, + { "Extended AES #2", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a", + "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + "\x9e\x99\xa7\xbf\x31\xe7\x10\x90\x06\x62\xf6\x5e\x61\x7c\x51\x84" }, + { "Extended AES #3", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + "\xe1\x99\x21\x90\x54\x9f\x6e\xd5\x69\x6a\x2c\x05\x6c\x31\x54\x10" }, + { "Extended AES #4", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a", + "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + "\x07\x0a\x16\xb4\x6b\x4d\x41\x44\xf7\x9b\xdd\x9d\xd0\x4a\x28\x7c" }, + { "Extended AES #5", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + "\x51\xf0\xbe\xbf\x7e\x3b\x9d\x92\xfc\x49\x74\x17\x79\x36\x3c\xfe" }, + { "Extended AES #6", + "", + "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + "\xd1\x7d\xdf\x46\xad\xaa\xcd\xe5\x31\xca\xc4\x83\xde\x7a\x93\x67" }, + { "Extended AES #7", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + "\xa1\xd5\xdf\x0e\xed\x79\x0f\x79\x4d\x77\x58\x96\x59\xf3\x9a\x11" }, + { "Extended AES #8", + "", + "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + "\x02\x89\x62\xf6\x1b\x7b\xf8\x9e\xfc\x6b\x55\x1f\x46\x67\xd9\x83" }, + { "Extended AES #9", + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a", + "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + "\x28\xa7\x02\x3f\x45\x2e\x8f\x82\xbd\x4b\xf2\x8d\x8c\x37\xc3\x5c" }, + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + errtxt = check_one (GCRY_MAC_CMAC_AES, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + tv[tvidx].expect, strlen (tv[tvidx].expect)); + if (errtxt) + goto failed; + if (tvidx >= 2 && !extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("cmac", GCRY_MAC_CMAC_AES, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + +static gpg_err_code_t +cmac_selftest (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + switch (algo) + { + case GCRY_MAC_CMAC_3DES: + ec = selftests_cmac_3des (extended, report); + break; + case GCRY_MAC_CMAC_AES: + ec = selftests_cmac_aes (extended, report); + break; + + default: + ec = GPG_ERR_MAC_ALGO; + break; + } + + return ec; +} + + +static gcry_mac_spec_ops_t cmac_ops = { + cmac_open, + cmac_close, + cmac_setkey, + NULL, + cmac_reset, + cmac_write, + cmac_read, + cmac_verify, + cmac_get_maclen, + cmac_get_keylen, + NULL, + cmac_selftest +}; + + +#if USE_BLOWFISH +gcry_mac_spec_t _gcry_mac_type_spec_cmac_blowfish = { + GCRY_MAC_CMAC_BLOWFISH, {0, 0}, "CMAC_BLOWFISH", + &cmac_ops +}; +#endif +#if USE_DES +gcry_mac_spec_t _gcry_mac_type_spec_cmac_tripledes = { + GCRY_MAC_CMAC_3DES, {0, 1}, "CMAC_3DES", + &cmac_ops +}; +#endif +#if USE_CAST5 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_cast5 = { + GCRY_MAC_CMAC_CAST5, {0, 0}, "CMAC_CAST5", + &cmac_ops +}; +#endif +#if USE_AES +gcry_mac_spec_t _gcry_mac_type_spec_cmac_aes = { + GCRY_MAC_CMAC_AES, {0, 1}, "CMAC_AES", + &cmac_ops +}; +#endif +#if USE_TWOFISH +gcry_mac_spec_t _gcry_mac_type_spec_cmac_twofish = { + GCRY_MAC_CMAC_TWOFISH, {0, 0}, "CMAC_TWOFISH", + &cmac_ops +}; +#endif +#if USE_SERPENT +gcry_mac_spec_t _gcry_mac_type_spec_cmac_serpent = { + GCRY_MAC_CMAC_SERPENT, {0, 0}, "CMAC_SERPENT", + &cmac_ops +}; +#endif +#if USE_RFC2268 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_rfc2268 = { + GCRY_MAC_CMAC_RFC2268, {0, 0}, "CMAC_RFC2268", + &cmac_ops +}; +#endif +#if USE_SEED +gcry_mac_spec_t _gcry_mac_type_spec_cmac_seed = { + GCRY_MAC_CMAC_SEED, {0, 0}, "CMAC_SEED", + &cmac_ops +}; +#endif +#if USE_CAMELLIA +gcry_mac_spec_t _gcry_mac_type_spec_cmac_camellia = { + GCRY_MAC_CMAC_CAMELLIA, {0, 0}, "CMAC_CAMELLIA", + &cmac_ops +}; +#endif +#ifdef USE_IDEA +gcry_mac_spec_t _gcry_mac_type_spec_cmac_idea = { + GCRY_MAC_CMAC_IDEA, {0, 0}, "CMAC_IDEA", + &cmac_ops +}; +#endif +#if USE_GOST28147 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_gost28147 = { + GCRY_MAC_CMAC_GOST28147, {0, 0}, "CMAC_GOST28147", + &cmac_ops +}; +#endif +#if USE_SM4 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_sm4 = { + GCRY_MAC_CMAC_SM4, {0, 0}, "CMAC_SM4", + &cmac_ops +}; +#endif diff --git a/comm/third_party/libgcrypt/cipher/mac-gmac.c b/comm/third_party/libgcrypt/cipher/mac-gmac.c new file mode 100644 index 0000000000..e04c6d1ef0 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac-gmac.c @@ -0,0 +1,187 @@ +/* mac-gmac.c - GMAC glue for MAC API + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" +#include "./mac-internal.h" + + +static int +map_mac_algo_to_cipher (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_CIPHER_NONE; + case GCRY_MAC_GMAC_AES: + return GCRY_CIPHER_AES; + case GCRY_MAC_GMAC_CAMELLIA: + return GCRY_CIPHER_CAMELLIA128; + case GCRY_MAC_GMAC_TWOFISH: + return GCRY_CIPHER_TWOFISH; + case GCRY_MAC_GMAC_SERPENT: + return GCRY_CIPHER_SERPENT128; + case GCRY_MAC_GMAC_SEED: + return GCRY_CIPHER_SEED; + } +} + + +static gcry_err_code_t +gmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_cipher_hd_t hd; + int secure = (h->magic == CTX_MAC_MAGIC_SECURE); + int cipher_algo; + unsigned int flags; + + cipher_algo = map_mac_algo_to_cipher (h->spec->algo); + flags = (secure ? GCRY_CIPHER_SECURE : 0); + + err = _gcry_cipher_open_internal (&hd, cipher_algo, GCRY_CIPHER_MODE_GCM, + flags); + if (err) + return err; + + h->u.gmac.cipher_algo = cipher_algo; + h->u.gmac.ctx = hd; + return 0; +} + + +static void +gmac_close (gcry_mac_hd_t h) +{ + _gcry_cipher_close (h->u.gmac.ctx); + h->u.gmac.ctx = NULL; +} + + +static gcry_err_code_t +gmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return _gcry_cipher_setkey (h->u.gmac.ctx, key, keylen); +} + + +static gcry_err_code_t +gmac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen) +{ + return _gcry_cipher_setiv (h->u.gmac.ctx, iv, ivlen); +} + + +static gcry_err_code_t +gmac_reset (gcry_mac_hd_t h) +{ + return _gcry_cipher_reset (h->u.gmac.ctx); +} + + +static gcry_err_code_t +gmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_authenticate (h->u.gmac.ctx, buf, buflen); +} + + +static gcry_err_code_t +gmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + if (*outlen > GCRY_GCM_BLOCK_LEN) + *outlen = GCRY_GCM_BLOCK_LEN; + return _gcry_cipher_gettag (h->u.gmac.ctx, outbuf, *outlen); +} + + +static gcry_err_code_t +gmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_checktag (h->u.gmac.ctx, buf, buflen); +} + + +static unsigned int +gmac_get_maclen (int algo) +{ + (void)algo; + return GCRY_GCM_BLOCK_LEN; +} + + +static unsigned int +gmac_get_keylen (int algo) +{ + return _gcry_cipher_get_algo_keylen (map_mac_algo_to_cipher (algo)); +} + + +static gcry_mac_spec_ops_t gmac_ops = { + gmac_open, + gmac_close, + gmac_setkey, + gmac_setiv, + gmac_reset, + gmac_write, + gmac_read, + gmac_verify, + gmac_get_maclen, + gmac_get_keylen, + NULL, + NULL +}; + + +#if USE_AES +gcry_mac_spec_t _gcry_mac_type_spec_gmac_aes = { + GCRY_MAC_GMAC_AES, {0, 1}, "GMAC_AES", + &gmac_ops +}; +#endif +#if USE_TWOFISH +gcry_mac_spec_t _gcry_mac_type_spec_gmac_twofish = { + GCRY_MAC_GMAC_TWOFISH, {0, 0}, "GMAC_TWOFISH", + &gmac_ops +}; +#endif +#if USE_SERPENT +gcry_mac_spec_t _gcry_mac_type_spec_gmac_serpent = { + GCRY_MAC_GMAC_SERPENT, {0, 0}, "GMAC_SERPENT", + &gmac_ops +}; +#endif +#if USE_SEED +gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed = { + GCRY_MAC_GMAC_SEED, {0, 0}, "GMAC_SEED", + &gmac_ops +}; +#endif +#if USE_CAMELLIA +gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia = { + GCRY_MAC_GMAC_CAMELLIA, {0, 0}, "GMAC_CAMELLIA", + &gmac_ops +}; +#endif diff --git a/comm/third_party/libgcrypt/cipher/mac-hmac.c b/comm/third_party/libgcrypt/cipher/mac-hmac.c new file mode 100644 index 0000000000..4e10dd2c9e --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac-hmac.c @@ -0,0 +1,1495 @@ +/* mac-hmac.c - HMAC glue for MAC API + * Copyright (C) 2013 Jussi Kivilinna + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "./mac-internal.h" +#include "bufhelp.h" +#include "cipher.h" +#include "hmac256.h" + + +static int +map_mac_algo_to_md (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_MD_NONE; + case GCRY_MAC_HMAC_MD2: + return GCRY_MD_MD2; + case GCRY_MAC_HMAC_MD4: + return GCRY_MD_MD4; + case GCRY_MAC_HMAC_MD5: + return GCRY_MD_MD5; + case GCRY_MAC_HMAC_SHA1: + return GCRY_MD_SHA1; + case GCRY_MAC_HMAC_SHA224: + return GCRY_MD_SHA224; + case GCRY_MAC_HMAC_SHA256: + return GCRY_MD_SHA256; + case GCRY_MAC_HMAC_SHA384: + return GCRY_MD_SHA384; + case GCRY_MAC_HMAC_SHA512: + return GCRY_MD_SHA512; + case GCRY_MAC_HMAC_SHA512_256: + return GCRY_MD_SHA512_256; + case GCRY_MAC_HMAC_SHA512_224: + return GCRY_MD_SHA512_224; + case GCRY_MAC_HMAC_SHA3_224: + return GCRY_MD_SHA3_224; + case GCRY_MAC_HMAC_SHA3_256: + return GCRY_MD_SHA3_256; + case GCRY_MAC_HMAC_SHA3_384: + return GCRY_MD_SHA3_384; + case GCRY_MAC_HMAC_SHA3_512: + return GCRY_MD_SHA3_512; + case GCRY_MAC_HMAC_RMD160: + return GCRY_MD_RMD160; + case GCRY_MAC_HMAC_TIGER1: + return GCRY_MD_TIGER1; + case GCRY_MAC_HMAC_WHIRLPOOL: + return GCRY_MD_WHIRLPOOL; + case GCRY_MAC_HMAC_GOSTR3411_94: + return GCRY_MD_GOSTR3411_94; + case GCRY_MAC_HMAC_GOSTR3411_CP: + return GCRY_MD_GOSTR3411_CP; + case GCRY_MAC_HMAC_STRIBOG256: + return GCRY_MD_STRIBOG256; + case GCRY_MAC_HMAC_STRIBOG512: + return GCRY_MD_STRIBOG512; + case GCRY_MAC_HMAC_BLAKE2B_512: + return GCRY_MD_BLAKE2B_512; + case GCRY_MAC_HMAC_BLAKE2B_384: + return GCRY_MD_BLAKE2B_384; + case GCRY_MAC_HMAC_BLAKE2B_256: + return GCRY_MD_BLAKE2B_256; + case GCRY_MAC_HMAC_BLAKE2B_160: + return GCRY_MD_BLAKE2B_160; + case GCRY_MAC_HMAC_BLAKE2S_256: + return GCRY_MD_BLAKE2S_256; + case GCRY_MAC_HMAC_BLAKE2S_224: + return GCRY_MD_BLAKE2S_224; + case GCRY_MAC_HMAC_BLAKE2S_160: + return GCRY_MD_BLAKE2S_160; + case GCRY_MAC_HMAC_BLAKE2S_128: + return GCRY_MD_BLAKE2S_128; + case GCRY_MAC_HMAC_SM3: + return GCRY_MD_SM3; + } +} + + +static gcry_err_code_t +hmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_md_hd_t hd; + int secure = (h->magic == CTX_MAC_MAGIC_SECURE); + unsigned int flags; + int md_algo; + + md_algo = map_mac_algo_to_md (h->spec->algo); + + flags = GCRY_MD_FLAG_HMAC; + flags |= (secure ? GCRY_MD_FLAG_SECURE : 0); + + err = _gcry_md_open (&hd, md_algo, flags); + if (err) + return err; + + h->u.hmac.md_algo = md_algo; + h->u.hmac.md_ctx = hd; + return 0; +} + + +static void +hmac_close (gcry_mac_hd_t h) +{ + _gcry_md_close (h->u.hmac.md_ctx); + h->u.hmac.md_ctx = NULL; +} + + +static gcry_err_code_t +hmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return _gcry_md_setkey (h->u.hmac.md_ctx, key, keylen); +} + + +static gcry_err_code_t +hmac_reset (gcry_mac_hd_t h) +{ + _gcry_md_reset (h->u.hmac.md_ctx); + return 0; +} + + +static gcry_err_code_t +hmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + _gcry_md_write (h->u.hmac.md_ctx, buf, buflen); + return 0; +} + + +static gcry_err_code_t +hmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + unsigned int dlen; + const unsigned char *digest; + + dlen = _gcry_md_get_algo_dlen (h->u.hmac.md_algo); + digest = _gcry_md_read (h->u.hmac.md_ctx, h->u.hmac.md_algo); + + if (*outlen <= dlen) + buf_cpy (outbuf, digest, *outlen); + else + { + buf_cpy (outbuf, digest, dlen); + *outlen = dlen; + } + + return 0; +} + + +static gcry_err_code_t +hmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + unsigned int dlen; + const unsigned char *digest; + + dlen = _gcry_md_get_algo_dlen (h->u.hmac.md_algo); + digest = _gcry_md_read (h->u.hmac.md_ctx, h->u.hmac.md_algo); + + if (buflen > dlen) + return GPG_ERR_INV_LENGTH; + + return buf_eq_const (buf, digest, buflen) ? 0 : GPG_ERR_CHECKSUM; +} + + +static unsigned int +hmac_get_maclen (int algo) +{ + return _gcry_md_get_algo_dlen (map_mac_algo_to_md (algo)); +} + + +static unsigned int +hmac_get_keylen (int algo) +{ + /* Return blocksize for default key length. */ + switch (algo) + { + case GCRY_MD_SHA3_224: + return 1152 / 8; + case GCRY_MD_SHA3_256: + return 1088 / 8; + case GCRY_MD_SHA3_384: + return 832 / 8; + case GCRY_MD_SHA3_512: + return 576 / 8; + case GCRY_MAC_HMAC_SHA384: + case GCRY_MAC_HMAC_SHA512: + return 128; + case GCRY_MAC_HMAC_GOSTR3411_94: + return 32; + default: + return 64; + } +} + + +/* Check one HMAC with digest ALGO using the regualr HAMC + * API. (DATA,DATALEN) is the data to be MACed, (KEY,KEYLEN) the key + * and (EXPECT,EXPECTLEN) the expected result. If TRUNC is set, the + * EXPECTLEN may be less than the digest length. Returns NULL on + * success or a string describing the failure. */ +static const char * +check_one (int algo, + const void *data, size_t datalen, + const void *key, size_t keylen, + const void *expect, size_t expectlen, int trunc) +{ + gcry_md_hd_t hd; + const unsigned char *digest; + +/* printf ("HMAC algo %d\n", algo); */ + if (trunc) + { + if (_gcry_md_get_algo_dlen (algo) < expectlen) + return "invalid tests data"; + } + else + { + if (_gcry_md_get_algo_dlen (algo) != expectlen) + return "invalid tests data"; + } + if (_gcry_md_open (&hd, algo, GCRY_MD_FLAG_HMAC)) + return "gcry_md_open failed"; + if (_gcry_md_setkey (hd, key, keylen)) + { + _gcry_md_close (hd); + return "gcry_md_setkey failed"; + } + _gcry_md_write (hd, data, datalen); + digest = _gcry_md_read (hd, algo); + if (!digest) + { + _gcry_md_close (hd); + return "gcry_md_read failed"; + } + if (memcmp (digest, expect, expectlen)) + { +/* int i; */ + +/* fputs (" {", stdout); */ +/* for (i=0; i < expectlen-1; i++) */ +/* { */ +/* if (i && !(i % 8)) */ +/* fputs ("\n ", stdout); */ +/* printf (" 0x%02x,", digest[i]); */ +/* } */ +/* printf (" 0x%02x } },\n", digest[i]); */ + + _gcry_md_close (hd); + return "does not match"; + } + _gcry_md_close (hd); + return NULL; +} + + +static gpg_err_code_t +selftests_sha1 (int extended, selftest_report_func_t report) +{ + const char *what; + const char *errtxt; + unsigned char key[128]; + int i, j; + + what = "FIPS-198a, A.1"; + for (i=0; i < 64; i++) + key[i] = i; + errtxt = check_one (GCRY_MD_SHA1, + "Sample #1", 9, + key, 64, + "\x4f\x4c\xa3\xd5\xd6\x8b\xa7\xcc\x0a\x12" + "\x08\xc9\xc6\x1e\x9c\x5d\xa0\x40\x3c\x0a", 20, 0); + if (errtxt) + goto failed; + + if (extended) + { + what = "FIPS-198a, A.2"; + for (i=0, j=0x30; i < 20; i++) + key[i] = j++; + errtxt = check_one (GCRY_MD_SHA1, + "Sample #2", 9, + key, 20, + "\x09\x22\xd3\x40\x5f\xaa\x3d\x19\x4f\x82" + "\xa4\x58\x30\x73\x7d\x5c\xc6\xc7\x5d\x24", 20, 0); + if (errtxt) + goto failed; + + what = "FIPS-198a, A.3"; + for (i=0, j=0x50; i < 100; i++) + key[i] = j++; + errtxt = check_one (GCRY_MD_SHA1, + "Sample #3", 9, + key, 100, + "\xbc\xf4\x1e\xab\x8b\xb2\xd8\x02\xf3\xd0" + "\x5c\xaf\x7c\xb0\x92\xec\xf8\xd1\xa3\xaa", 20, 0); + if (errtxt) + goto failed; + + what = "FIPS-198a, A.4"; + for (i=0, j=0x70; i < 49; i++) + key[i] = j++; + errtxt = check_one (GCRY_MD_SHA1, + "Sample #4", 9, + key, 49, + "\x9e\xa8\x86\xef\xe2\x68\xdb\xec\xce\x42" + "\x0c\x75\x24\xdf\x32\xe0\x75\x1a\x2a\x26", 20, 0); + if (errtxt) + goto failed; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("hmac", GCRY_MD_SHA1, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + + +static gpg_err_code_t +selftests_sha224 (int extended, selftest_report_func_t report) +{ + static struct + { + const char * const desc; + const char * const data; + const char * const key; + const char expect[28]; + } tv[] = + { + { "data-28 key-4", + "what do ya want for nothing?", + "Jefe", + { 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, + 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e, 0x6d, 0x0f, + 0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00, + 0x8f, 0xd0, 0x5e, 0x44 } }, + + { "data-9 key-20", + "Hi There", + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b", + { 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, + 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, 0xf3, 0x3f, + 0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f, + 0x53, 0x68, 0x4b, 0x22 } }, + + { "data-50 key-20", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa", + { 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, + 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a, 0xd2, 0x64, + 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, + 0xec, 0x83, 0x33, 0xea } }, + + { "data-50 key-26", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19", + { 0x6c, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3c, 0xac, + 0x6a, 0x2a, 0xbc, 0x1b, 0xb3, 0x82, 0x62, 0x7c, + 0xec, 0x6a, 0x90, 0xd8, 0x6e, 0xfc, 0x01, 0x2d, + 0xe7, 0xaf, 0xec, 0x5a } }, + + { "data-54 key-131", + "Test Using Larger Than Block-Size Key - Hash Key First", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, + 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d, 0xbc, 0xe2, + 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, + 0x3f, 0xa6, 0x87, 0x0e } }, + + { "data-152 key-131", + "This is a test using a larger than block-size key and a larger " + "than block-size data. The key needs to be hashed before being " + "used by the HMAC algorithm.", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, + 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3, 0x9d, 0xbd, + 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, + 0xf6, 0xf5, 0x65, 0xd1 } }, + + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + errtxt = check_one (GCRY_MD_SHA224, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + tv[tvidx].expect, DIM (tv[tvidx].expect), 0); + if (errtxt) + goto failed; + if (!extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("hmac", GCRY_MD_SHA224, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +static gpg_err_code_t +selftests_sha256 (int extended, selftest_report_func_t report) +{ + static struct + { + const char * const desc; + const char * const data; + const char * const key; + const char expect[32]; + } tv[] = + { + { "data-28 key-4", + "what do ya want for nothing?", + "Jefe", + { 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, + 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 } }, + + { "data-9 key-20", + "Hi There", + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b", + { 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, + 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, + 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 } }, + + { "data-50 key-20", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa", + { 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, + 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, + 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, + 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe } }, + + { "data-50 key-26", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19", + { 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, + 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, + 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, + 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b } }, + + { "data-54 key-131", + "Test Using Larger Than Block-Size Key - Hash Key First", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, + 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, + 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 } }, + + { "data-152 key-131", + "This is a test using a larger than block-size key and a larger " + "than block-size data. The key needs to be hashed before being " + "used by the HMAC algorithm.", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, + 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, + 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 } }, + + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + hmac256_context_t hmachd; + const unsigned char *digest; + size_t dlen; + + what = tv[tvidx].desc; + errtxt = check_one (GCRY_MD_SHA256, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + tv[tvidx].expect, DIM (tv[tvidx].expect), 0); + if (errtxt) + goto failed; + + hmachd = _gcry_hmac256_new (tv[tvidx].key, strlen (tv[tvidx].key)); + if (!hmachd) + { + errtxt = "_gcry_hmac256_new failed"; + goto failed; + } + _gcry_hmac256_update (hmachd, tv[tvidx].data, strlen (tv[tvidx].data)); + digest = _gcry_hmac256_finalize (hmachd, &dlen); + if (!digest) + { + errtxt = "_gcry_hmac256_finalize failed"; + _gcry_hmac256_release (hmachd); + goto failed; + } + if (dlen != DIM (tv[tvidx].expect) + || memcmp (digest, tv[tvidx].expect, DIM (tv[tvidx].expect))) + { + errtxt = "does not match in second implementation"; + _gcry_hmac256_release (hmachd); + goto failed; + } + _gcry_hmac256_release (hmachd); + + if (!extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("hmac", GCRY_MD_SHA256, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +static gpg_err_code_t +selftests_sha384 (int extended, selftest_report_func_t report) +{ + static struct + { + const char * const desc; + const char * const data; + const char * const key; + const char expect[48]; + } tv[] = + { + { "data-28 key-4", + "what do ya want for nothing?", + "Jefe", + { 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, + 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b, + 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, + 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, + 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7, + 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 } }, + + { "data-9 key-20", + "Hi There", + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b", + { 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, + 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f, + 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, + 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f, + 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 } }, + + { "data-50 key-20", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa", + { 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, + 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f, + 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb, + 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, + 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9, + 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27 } }, + + { "data-50 key-26", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19", + { 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, + 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7, + 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c, + 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, + 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79, + 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb } }, + + { "data-54 key-131", + "Test Using Larger Than Block-Size Key - Hash Key First", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, + 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4, + 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, + 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, + 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82, + 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 } }, + + { "data-152 key-131", + "This is a test using a larger than block-size key and a larger " + "than block-size data. The key needs to be hashed before being " + "used by the HMAC algorithm.", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, + 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c, + 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, + 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, + 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d, + 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e } }, + + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + errtxt = check_one (GCRY_MD_SHA384, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + tv[tvidx].expect, DIM (tv[tvidx].expect), 0); + if (errtxt) + goto failed; + if (!extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("hmac", GCRY_MD_SHA384, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +static gpg_err_code_t +selftests_sha512 (int extended, selftest_report_func_t report) +{ + static struct + { + const char * const desc; + const char * const data; + const char * const key; + const char expect[64]; + } tv[] = + { + { "data-28 key-4", + "what do ya want for nothing?", + "Jefe", + { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, + 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, + 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, + 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, + 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a, + 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, + 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, + 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 } }, + + { "data-9 key-20", + "Hi There", + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b", + { 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, + 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, + 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, + 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, + 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, + 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, + 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, + 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 } }, + + { "data-50 key-20", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa", + { 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, + 0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9, + 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, + 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, + 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, 0xc8, + 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, + 0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26, + 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb } }, + + { "data-50 key-26", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19", + { 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, + 0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7, + 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, + 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, + 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e, 0xb4, + 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, + 0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d, + 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd } }, + + { "data-54 key-131", + "Test Using Larger Than Block-Size Key - Hash Key First", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, + 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4, + 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, + 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, + 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98, + 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, + 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, + 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 } }, + + { "data-152 key-131", + "This is a test using a larger than block-size key and a larger " + "than block-size data. The key needs to be hashed before being " + "used by the HMAC algorithm.", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + { 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, + 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd, + 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, + 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, + 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1, + 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, + 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, + 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58 } }, + + { NULL } + }; + const char *what; + const char *errtxt; + int tvidx; + + for (tvidx=0; tv[tvidx].desc; tvidx++) + { + what = tv[tvidx].desc; + errtxt = check_one (GCRY_MD_SHA512, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + tv[tvidx].expect, DIM (tv[tvidx].expect), 0); + if (errtxt) + goto failed; + if (!extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("hmac", GCRY_MD_SHA512, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + + +/* Test for the SHA3 algorithms. Vectors taken on 2017-07-18 from + * http://www.wolfgang-ehrhardt.de/hmac-sha3-testvectors.html */ +static gpg_err_code_t +selftests_sha3 (int hashalgo, int extended, selftest_report_func_t report) +{ + static struct + { + const char * const desc; + const char * const data; + const char * const key; + const char expect_224[28]; + const char expect_256[32]; + const char expect_384[48]; + const char expect_512[64]; + unsigned char trunc; + } tv[] = + { + { "data-9 key-20", /* Test 1 */ + "Hi There", + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b", + + { 0x3b, 0x16, 0x54, 0x6b, 0xbc, 0x7b, 0xe2, 0x70, + 0x6a, 0x03, 0x1d, 0xca, 0xfd, 0x56, 0x37, 0x3d, + 0x98, 0x84, 0x36, 0x76, 0x41, 0xd8, 0xc5, 0x9a, + 0xf3, 0xc8, 0x60, 0xf7 }, + { 0xba, 0x85, 0x19, 0x23, 0x10, 0xdf, 0xfa, 0x96, + 0xe2, 0xa3, 0xa4, 0x0e, 0x69, 0x77, 0x43, 0x51, + 0x14, 0x0b, 0xb7, 0x18, 0x5e, 0x12, 0x02, 0xcd, + 0xcc, 0x91, 0x75, 0x89, 0xf9, 0x5e, 0x16, 0xbb }, + { 0x68, 0xd2, 0xdc, 0xf7, 0xfd, 0x4d, 0xdd, 0x0a, + 0x22, 0x40, 0xc8, 0xa4, 0x37, 0x30, 0x5f, 0x61, + 0xfb, 0x73, 0x34, 0xcf, 0xb5, 0xd0, 0x22, 0x6e, + 0x1b, 0xc2, 0x7d, 0xc1, 0x0a, 0x2e, 0x72, 0x3a, + 0x20, 0xd3, 0x70, 0xb4, 0x77, 0x43, 0x13, 0x0e, + 0x26, 0xac, 0x7e, 0x3d, 0x53, 0x28, 0x86, 0xbd }, + { 0xeb, 0x3f, 0xbd, 0x4b, 0x2e, 0xaa, 0xb8, 0xf5, + 0xc5, 0x04, 0xbd, 0x3a, 0x41, 0x46, 0x5a, 0xac, + 0xec, 0x15, 0x77, 0x0a, 0x7c, 0xab, 0xac, 0x53, + 0x1e, 0x48, 0x2f, 0x86, 0x0b, 0x5e, 0xc7, 0xba, + 0x47, 0xcc, 0xb2, 0xc6, 0xf2, 0xaf, 0xce, 0x8f, + 0x88, 0xd2, 0x2b, 0x6d, 0xc6, 0x13, 0x80, 0xf2, + 0x3a, 0x66, 0x8f, 0xd3, 0x88, 0x8b, 0xb8, 0x05, + 0x37, 0xc0, 0xa0, 0xb8, 0x64, 0x07, 0x68, 0x9e } + }, + + { "data-28 key-4", /* Test 2 */ + /* Test with a key shorter than the length of the HMAC output. */ + "what do ya want for nothing?", + "Jefe", + + { 0x7f, 0xdb, 0x8d, 0xd8, 0x8b, 0xd2, 0xf6, 0x0d, + 0x1b, 0x79, 0x86, 0x34, 0xad, 0x38, 0x68, 0x11, + 0xc2, 0xcf, 0xc8, 0x5b, 0xfa, 0xf5, 0xd5, 0x2b, + 0xba, 0xce, 0x5e, 0x66 }, + { 0xc7, 0xd4, 0x07, 0x2e, 0x78, 0x88, 0x77, 0xae, + 0x35, 0x96, 0xbb, 0xb0, 0xda, 0x73, 0xb8, 0x87, + 0xc9, 0x17, 0x1f, 0x93, 0x09, 0x5b, 0x29, 0x4a, + 0xe8, 0x57, 0xfb, 0xe2, 0x64, 0x5e, 0x1b, 0xa5 }, + { 0xf1, 0x10, 0x1f, 0x8c, 0xbf, 0x97, 0x66, 0xfd, + 0x67, 0x64, 0xd2, 0xed, 0x61, 0x90, 0x3f, 0x21, + 0xca, 0x9b, 0x18, 0xf5, 0x7c, 0xf3, 0xe1, 0xa2, + 0x3c, 0xa1, 0x35, 0x08, 0xa9, 0x32, 0x43, 0xce, + 0x48, 0xc0, 0x45, 0xdc, 0x00, 0x7f, 0x26, 0xa2, + 0x1b, 0x3f, 0x5e, 0x0e, 0x9d, 0xf4, 0xc2, 0x0a }, + { 0x5a, 0x4b, 0xfe, 0xab, 0x61, 0x66, 0x42, 0x7c, + 0x7a, 0x36, 0x47, 0xb7, 0x47, 0x29, 0x2b, 0x83, + 0x84, 0x53, 0x7c, 0xdb, 0x89, 0xaf, 0xb3, 0xbf, + 0x56, 0x65, 0xe4, 0xc5, 0xe7, 0x09, 0x35, 0x0b, + 0x28, 0x7b, 0xae, 0xc9, 0x21, 0xfd, 0x7c, 0xa0, + 0xee, 0x7a, 0x0c, 0x31, 0xd0, 0x22, 0xa9, 0x5e, + 0x1f, 0xc9, 0x2b, 0xa9, 0xd7, 0x7d, 0xf8, 0x83, + 0x96, 0x02, 0x75, 0xbe, 0xb4, 0xe6, 0x20, 0x24 } + }, + + { "data-50 key-20", /* Test 3 */ + /* Test with a combined length of key and data that is larger + * than 64 bytes (= block-size of SHA-224 and SHA-256). */ + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa", + + { 0x67, 0x6c, 0xfc, 0x7d, 0x16, 0x15, 0x36, 0x38, + 0x78, 0x03, 0x90, 0x69, 0x2b, 0xe1, 0x42, 0xd2, + 0xdf, 0x7c, 0xe9, 0x24, 0xb9, 0x09, 0xc0, 0xc0, + 0x8d, 0xbf, 0xdc, 0x1a }, + { 0x84, 0xec, 0x79, 0x12, 0x4a, 0x27, 0x10, 0x78, + 0x65, 0xce, 0xdd, 0x8b, 0xd8, 0x2d, 0xa9, 0x96, + 0x5e, 0x5e, 0xd8, 0xc3, 0x7b, 0x0a, 0xc9, 0x80, + 0x05, 0xa7, 0xf3, 0x9e, 0xd5, 0x8a, 0x42, 0x07 }, + { 0x27, 0x5c, 0xd0, 0xe6, 0x61, 0xbb, 0x8b, 0x15, + 0x1c, 0x64, 0xd2, 0x88, 0xf1, 0xf7, 0x82, 0xfb, + 0x91, 0xa8, 0xab, 0xd5, 0x68, 0x58, 0xd7, 0x2b, + 0xab, 0xb2, 0xd4, 0x76, 0xf0, 0x45, 0x83, 0x73, + 0xb4, 0x1b, 0x6a, 0xb5, 0xbf, 0x17, 0x4b, 0xec, + 0x42, 0x2e, 0x53, 0xfc, 0x31, 0x35, 0xac, 0x6e }, + { 0x30, 0x9e, 0x99, 0xf9, 0xec, 0x07, 0x5e, 0xc6, + 0xc6, 0xd4, 0x75, 0xed, 0xa1, 0x18, 0x06, 0x87, + 0xfc, 0xf1, 0x53, 0x11, 0x95, 0x80, 0x2a, 0x99, + 0xb5, 0x67, 0x74, 0x49, 0xa8, 0x62, 0x51, 0x82, + 0x85, 0x1c, 0xb3, 0x32, 0xaf, 0xb6, 0xa8, 0x9c, + 0x41, 0x13, 0x25, 0xfb, 0xcb, 0xcd, 0x42, 0xaf, + 0xcb, 0x7b, 0x6e, 0x5a, 0xab, 0x7e, 0xa4, 0x2c, + 0x66, 0x0f, 0x97, 0xfd, 0x85, 0x84, 0xbf, 0x03 } + }, + + { "data-50 key-25", /* Test 4 */ + /* Test with a combined length of key and data that is larger + * than 64 bytes (= block-size of SHA-224 and SHA-256). */ + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19", + + { 0xa9, 0xd7, 0x68, 0x5a, 0x19, 0xc4, 0xe0, 0xdb, + 0xd9, 0xdf, 0x25, 0x56, 0xcc, 0x8a, 0x7d, 0x2a, + 0x77, 0x33, 0xb6, 0x76, 0x25, 0xce, 0x59, 0x4c, + 0x78, 0x27, 0x0e, 0xeb }, + { 0x57, 0x36, 0x6a, 0x45, 0xe2, 0x30, 0x53, 0x21, + 0xa4, 0xbc, 0x5a, 0xa5, 0xfe, 0x2e, 0xf8, 0xa9, + 0x21, 0xf6, 0xaf, 0x82, 0x73, 0xd7, 0xfe, 0x7b, + 0xe6, 0xcf, 0xed, 0xb3, 0xf0, 0xae, 0xa6, 0xd7 }, + { 0x3a, 0x5d, 0x7a, 0x87, 0x97, 0x02, 0xc0, 0x86, + 0xbc, 0x96, 0xd1, 0xdd, 0x8a, 0xa1, 0x5d, 0x9c, + 0x46, 0x44, 0x6b, 0x95, 0x52, 0x13, 0x11, 0xc6, + 0x06, 0xfd, 0xc4, 0xe3, 0x08, 0xf4, 0xb9, 0x84, + 0xda, 0x2d, 0x0f, 0x94, 0x49, 0xb3, 0xba, 0x84, + 0x25, 0xec, 0x7f, 0xb8, 0xc3, 0x1b, 0xc1, 0x36 }, + { 0xb2, 0x7e, 0xab, 0x1d, 0x6e, 0x8d, 0x87, 0x46, + 0x1c, 0x29, 0xf7, 0xf5, 0x73, 0x9d, 0xd5, 0x8e, + 0x98, 0xaa, 0x35, 0xf8, 0xe8, 0x23, 0xad, 0x38, + 0xc5, 0x49, 0x2a, 0x20, 0x88, 0xfa, 0x02, 0x81, + 0x99, 0x3b, 0xbf, 0xff, 0x9a, 0x0e, 0x9c, 0x6b, + 0xf1, 0x21, 0xae, 0x9e, 0xc9, 0xbb, 0x09, 0xd8, + 0x4a, 0x5e, 0xba, 0xc8, 0x17, 0x18, 0x2e, 0xa9, + 0x74, 0x67, 0x3f, 0xb1, 0x33, 0xca, 0x0d, 0x1d } + }, + + { "data-20 key-20 trunc", /* Test 5 */ + /* Test with a truncation of output to 128 bits. */ + "Test With Truncation", + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c", + + { 0x49, 0xfd, 0xd3, 0xab, 0xd0, 0x05, 0xeb, 0xb8, + 0xae, 0x63, 0xfe, 0xa9, 0x46, 0xd1, 0x88, 0x3c }, + { 0x6e, 0x02, 0xc6, 0x45, 0x37, 0xfb, 0x11, 0x80, + 0x57, 0xab, 0xb7, 0xfb, 0x66, 0xa2, 0x3b, 0x3c }, + { 0x47, 0xc5, 0x1a, 0xce, 0x1f, 0xfa, 0xcf, 0xfd, + 0x74, 0x94, 0x72, 0x46, 0x82, 0x61, 0x57, 0x83 }, + { 0x0f, 0xa7, 0x47, 0x59, 0x48, 0xf4, 0x3f, 0x48, + 0xca, 0x05, 0x16, 0x67, 0x1e, 0x18, 0x97, 0x8c }, + 16 + }, + + { "data-54 key-131", /* Test 6 */ + /* Test with a key larger than 128 bytes (= block-size of + * SHA-384 and SHA-512). */ + "Test Using Larger Than Block-Size Key - Hash Key First", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + + { 0xb4, 0xa1, 0xf0, 0x4c, 0x00, 0x28, 0x7a, 0x9b, + 0x7f, 0x60, 0x75, 0xb3, 0x13, 0xd2, 0x79, 0xb8, + 0x33, 0xbc, 0x8f, 0x75, 0x12, 0x43, 0x52, 0xd0, + 0x5f, 0xb9, 0x99, 0x5f }, + { 0xed, 0x73, 0xa3, 0x74, 0xb9, 0x6c, 0x00, 0x52, + 0x35, 0xf9, 0x48, 0x03, 0x2f, 0x09, 0x67, 0x4a, + 0x58, 0xc0, 0xce, 0x55, 0x5c, 0xfc, 0x1f, 0x22, + 0x3b, 0x02, 0x35, 0x65, 0x60, 0x31, 0x2c, 0x3b }, + { 0x0f, 0xc1, 0x95, 0x13, 0xbf, 0x6b, 0xd8, 0x78, + 0x03, 0x70, 0x16, 0x70, 0x6a, 0x0e, 0x57, 0xbc, + 0x52, 0x81, 0x39, 0x83, 0x6b, 0x9a, 0x42, 0xc3, + 0xd4, 0x19, 0xe4, 0x98, 0xe0, 0xe1, 0xfb, 0x96, + 0x16, 0xfd, 0x66, 0x91, 0x38, 0xd3, 0x3a, 0x11, + 0x05, 0xe0, 0x7c, 0x72, 0xb6, 0x95, 0x3b, 0xcc }, + { 0x00, 0xf7, 0x51, 0xa9, 0xe5, 0x06, 0x95, 0xb0, + 0x90, 0xed, 0x69, 0x11, 0xa4, 0xb6, 0x55, 0x24, + 0x95, 0x1c, 0xdc, 0x15, 0xa7, 0x3a, 0x5d, 0x58, + 0xbb, 0x55, 0x21, 0x5e, 0xa2, 0xcd, 0x83, 0x9a, + 0xc7, 0x9d, 0x2b, 0x44, 0xa3, 0x9b, 0xaf, 0xab, + 0x27, 0xe8, 0x3f, 0xde, 0x9e, 0x11, 0xf6, 0x34, + 0x0b, 0x11, 0xd9, 0x91, 0xb1, 0xb9, 0x1b, 0xf2, + 0xee, 0xe7, 0xfc, 0x87, 0x24, 0x26, 0xc3, 0xa4 } + }, + + { "data-54 key-147", /* Test 6a */ + /* Test with a key larger than 144 bytes (= block-size of + * SHA3-224). */ + "Test Using Larger Than Block-Size Key - Hash Key First", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + + { 0xb9, 0x6d, 0x73, 0x0c, 0x14, 0x8c, 0x2d, 0xaa, + 0xd8, 0x64, 0x9d, 0x83, 0xde, 0xfa, 0xa3, 0x71, + 0x97, 0x38, 0xd3, 0x47, 0x75, 0x39, 0x7b, 0x75, + 0x71, 0xc3, 0x85, 0x15 }, + { 0xa6, 0x07, 0x2f, 0x86, 0xde, 0x52, 0xb3, 0x8b, + 0xb3, 0x49, 0xfe, 0x84, 0xcd, 0x6d, 0x97, 0xfb, + 0x6a, 0x37, 0xc4, 0xc0, 0xf6, 0x2a, 0xae, 0x93, + 0x98, 0x11, 0x93, 0xa7, 0x22, 0x9d, 0x34, 0x67 }, + { 0x71, 0x3d, 0xff, 0x03, 0x02, 0xc8, 0x50, 0x86, + 0xec, 0x5a, 0xd0, 0x76, 0x8d, 0xd6, 0x5a, 0x13, + 0xdd, 0xd7, 0x90, 0x68, 0xd8, 0xd4, 0xc6, 0x21, + 0x2b, 0x71, 0x2e, 0x41, 0x64, 0x94, 0x49, 0x11, + 0x14, 0x80, 0x23, 0x00, 0x44, 0x18, 0x5a, 0x99, + 0x10, 0x3e, 0xd8, 0x20, 0x04, 0xdd, 0xbf, 0xcc }, + { 0xb1, 0x48, 0x35, 0xc8, 0x19, 0xa2, 0x90, 0xef, + 0xb0, 0x10, 0xac, 0xe6, 0xd8, 0x56, 0x8d, 0xc6, + 0xb8, 0x4d, 0xe6, 0x0b, 0xc4, 0x9b, 0x00, 0x4c, + 0x3b, 0x13, 0xed, 0xa7, 0x63, 0x58, 0x94, 0x51, + 0xe5, 0xdd, 0x74, 0x29, 0x28, 0x84, 0xd1, 0xbd, + 0xce, 0x64, 0xe6, 0xb9, 0x19, 0xdd, 0x61, 0xdc, + 0x9c, 0x56, 0xa2, 0x82, 0xa8, 0x1c, 0x0b, 0xd1, + 0x4f, 0x1f, 0x36, 0x5b, 0x49, 0xb8, 0x3a, 0x5b } + }, + + { "data-152 key-131", /* Test 7 */ + /* Test with a key and data that is larger than 128 bytes (= + * block-size of SHA-384 and SHA-512). */ + "This is a test using a larger than block-size key and a larger " + "than block-size data. The key needs to be hashed before being " + "used by the HMAC algorithm.", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + + { 0x05, 0xd8, 0xcd, 0x6d, 0x00, 0xfa, 0xea, 0x8d, + 0x1e, 0xb6, 0x8a, 0xde, 0x28, 0x73, 0x0b, 0xbd, + 0x3c, 0xba, 0xb6, 0x92, 0x9f, 0x0a, 0x08, 0x6b, + 0x29, 0xcd, 0x62, 0xa0 }, + { 0x65, 0xc5, 0xb0, 0x6d, 0x4c, 0x3d, 0xe3, 0x2a, + 0x7a, 0xef, 0x87, 0x63, 0x26, 0x1e, 0x49, 0xad, + 0xb6, 0xe2, 0x29, 0x3e, 0xc8, 0xe7, 0xc6, 0x1e, + 0x8d, 0xe6, 0x17, 0x01, 0xfc, 0x63, 0xe1, 0x23 }, + { 0x02, 0x6f, 0xdf, 0x6b, 0x50, 0x74, 0x1e, 0x37, + 0x38, 0x99, 0xc9, 0xf7, 0xd5, 0x40, 0x6d, 0x4e, + 0xb0, 0x9f, 0xc6, 0x66, 0x56, 0x36, 0xfc, 0x1a, + 0x53, 0x00, 0x29, 0xdd, 0xf5, 0xcf, 0x3c, 0xa5, + 0xa9, 0x00, 0xed, 0xce, 0x01, 0xf5, 0xf6, 0x1e, + 0x2f, 0x40, 0x8c, 0xdf, 0x2f, 0xd3, 0xe7, 0xe8 }, + { 0x38, 0xa4, 0x56, 0xa0, 0x04, 0xbd, 0x10, 0xd3, + 0x2c, 0x9a, 0xb8, 0x33, 0x66, 0x84, 0x11, 0x28, + 0x62, 0xc3, 0xdb, 0x61, 0xad, 0xcc, 0xa3, 0x18, + 0x29, 0x35, 0x5e, 0xaf, 0x46, 0xfd, 0x5c, 0x73, + 0xd0, 0x6a, 0x1f, 0x0d, 0x13, 0xfe, 0xc9, 0xa6, + 0x52, 0xfb, 0x38, 0x11, 0xb5, 0x77, 0xb1, 0xb1, + 0xd1, 0xb9, 0x78, 0x9f, 0x97, 0xae, 0x5b, 0x83, + 0xc6, 0xf4, 0x4d, 0xfc, 0xf1, 0xd6, 0x7e, 0xba } + }, + + { "data-152 key-147", /* Test 7a */ + /* Test with a key larger than 144 bytes (= block-size of + * SHA3-224). */ + "This is a test using a larger than block-size key and a larger " + "than block-size data. The key needs to be hashed before being " + "used by the HMAC algorithm.", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa", + + { 0xc7, 0x9c, 0x9b, 0x09, 0x34, 0x24, 0xe5, 0x88, + 0xa9, 0x87, 0x8b, 0xbc, 0xb0, 0x89, 0xe0, 0x18, + 0x27, 0x00, 0x96, 0xe9, 0xb4, 0xb1, 0xa9, 0xe8, + 0x22, 0x0c, 0x86, 0x6a }, + { 0xe6, 0xa3, 0x6d, 0x9b, 0x91, 0x5f, 0x86, 0xa0, + 0x93, 0xca, 0xc7, 0xd1, 0x10, 0xe9, 0xe0, 0x4c, + 0xf1, 0xd6, 0x10, 0x0d, 0x30, 0x47, 0x55, 0x09, + 0xc2, 0x47, 0x5f, 0x57, 0x1b, 0x75, 0x8b, 0x5a }, + { 0xca, 0xd1, 0x8a, 0x8f, 0xf6, 0xc4, 0xcc, 0x3a, + 0xd4, 0x87, 0xb9, 0x5f, 0x97, 0x69, 0xe9, 0xb6, + 0x1c, 0x06, 0x2a, 0xef, 0xd6, 0x95, 0x25, 0x69, + 0xe6, 0xe6, 0x42, 0x18, 0x97, 0x05, 0x4c, 0xfc, + 0x70, 0xb5, 0xfd, 0xc6, 0x60, 0x5c, 0x18, 0x45, + 0x71, 0x12, 0xfc, 0x6a, 0xaa, 0xd4, 0x55, 0x85 }, + { 0xdc, 0x03, 0x0e, 0xe7, 0x88, 0x70, 0x34, 0xf3, + 0x2c, 0xf4, 0x02, 0xdf, 0x34, 0x62, 0x2f, 0x31, + 0x1f, 0x3e, 0x6c, 0xf0, 0x48, 0x60, 0xc6, 0xbb, + 0xd7, 0xfa, 0x48, 0x86, 0x74, 0x78, 0x2b, 0x46, + 0x59, 0xfd, 0xbd, 0xf3, 0xfd, 0x87, 0x78, 0x52, + 0x88, 0x5c, 0xfe, 0x6e, 0x22, 0x18, 0x5f, 0xe7, + 0xb2, 0xee, 0x95, 0x20, 0x43, 0x62, 0x9b, 0xc9, + 0xd5, 0xf3, 0x29, 0x8a, 0x41, 0xd0, 0x2c, 0x66 } + }/*,*/ + + /* Our API does not allow to specify a bit count and thus we + * can't use the following test. */ + /* { "data-5bit key-4", /\* Test 8 *\/ */ + /* /\* Test with data bit size no multiple of 8, the data bits are */ + /* * '11001' from the NIST example using SHA-3 order (= 5 bits */ + /* * from LSB hex byte 13 or 5 bits from MSB hex byte c8). *\/ */ + /* "\xc8", */ + /* "Jefe", */ + + /* { 0x5f, 0x8c, 0x0e, 0xa7, 0xfa, 0xfe, 0xcd, 0x0c, */ + /* 0x34, 0x63, 0xaa, 0xd0, 0x97, 0x42, 0xce, 0xce, */ + /* 0xb1, 0x42, 0xfe, 0x0a, 0xb6, 0xf4, 0x53, 0x94, */ + /* 0x38, 0xc5, 0x9d, 0xe8 }, */ + /* { 0xec, 0x82, 0x22, 0x77, 0x3f, 0xac, 0x68, 0xb3, */ + /* 0xd3, 0xdc, 0xb1, 0x82, 0xae, 0xc8, 0xb0, 0x50, */ + /* 0x7a, 0xce, 0x44, 0x48, 0xd2, 0x0a, 0x11, 0x47, */ + /* 0xe6, 0x82, 0x11, 0x8d, 0xa4, 0xe3, 0xf4, 0x4c }, */ + /* { 0x21, 0xfb, 0xd3, 0xbf, 0x3e, 0xbb, 0xa3, 0xcf, */ + /* 0xc9, 0xef, 0x64, 0xc0, 0x59, 0x1c, 0x92, 0xc5, */ + /* 0xac, 0xb2, 0x65, 0xe9, 0x2d, 0x87, 0x61, 0xd1, */ + /* 0xf9, 0x1a, 0x52, 0xa1, 0x03, 0xa6, 0xc7, 0x96, */ + /* 0x94, 0xcf, 0xd6, 0x7a, 0x9a, 0x2a, 0xc1, 0x32, */ + /* 0x4f, 0x02, 0xfe, 0xa6, 0x3b, 0x81, 0xef, 0xfc }, */ + /* { 0x27, 0xf9, 0x38, 0x8c, 0x15, 0x67, 0xef, 0x4e, */ + /* 0xf2, 0x00, 0x60, 0x2a, 0x6c, 0xf8, 0x71, 0xd6, */ + /* 0x8a, 0x6f, 0xb0, 0x48, 0xd4, 0x73, 0x7a, 0xc4, */ + /* 0x41, 0x8a, 0x2f, 0x02, 0x12, 0x89, 0xd1, 0x3d, */ + /* 0x1f, 0xd1, 0x12, 0x0f, 0xec, 0xb9, 0xcf, 0x96, */ + /* 0x4c, 0x5b, 0x11, 0x7a, 0xb5, 0xb1, 0x1c, 0x61, */ + /* 0x4b, 0x2d, 0xa3, 0x9d, 0xad, 0xd5, 0x1f, 0x2f, */ + /* 0x5e, 0x22, 0xaa, 0xcc, 0xec, 0x7d, 0x57, 0x6e } */ + /* } */ + + }; + const char *what; + const char *errtxt; + int tvidx; + const char *expect; + int nexpect; + + for (tvidx=0; tvidx < DIM(tv); tvidx++) + { + what = tv[tvidx].desc; + if (hashalgo == GCRY_MD_SHA3_224) + { + expect = tv[tvidx].expect_224; + nexpect = DIM (tv[tvidx].expect_224); + } + else if (hashalgo == GCRY_MD_SHA3_256) + { + expect = tv[tvidx].expect_256; + nexpect = DIM (tv[tvidx].expect_256); + } + else if (hashalgo == GCRY_MD_SHA3_384) + { + expect = tv[tvidx].expect_384; + nexpect = DIM (tv[tvidx].expect_384); + } + else if (hashalgo == GCRY_MD_SHA3_512) + { + expect = tv[tvidx].expect_512; + nexpect = DIM (tv[tvidx].expect_512); + } + else + BUG(); + + if (tv[tvidx].trunc && tv[tvidx].trunc < nexpect) + nexpect = tv[tvidx].trunc; + + errtxt = check_one (hashalgo, + tv[tvidx].data, strlen (tv[tvidx].data), + tv[tvidx].key, strlen (tv[tvidx].key), + expect, nexpect, !!tv[tvidx].trunc); + if (errtxt) + goto failed; + if (!extended) + break; + } + + return 0; /* Succeeded. */ + + failed: + if (report) + report ("hmac", hashalgo, what, errtxt); + return GPG_ERR_SELFTEST_FAILED; +} + + +static gpg_err_code_t +hmac_selftest (int algo, int extended, selftest_report_func_t report) +{ + gpg_err_code_t ec; + + switch (algo) + { + case GCRY_MAC_HMAC_SHA1: + ec = selftests_sha1 (extended, report); + break; + case GCRY_MAC_HMAC_SHA224: + ec = selftests_sha224 (extended, report); + break; + case GCRY_MAC_HMAC_SHA256: + ec = selftests_sha256 (extended, report); + break; + case GCRY_MAC_HMAC_SHA384: + ec = selftests_sha384 (extended, report); + break; + case GCRY_MAC_HMAC_SHA512: + ec = selftests_sha512 (extended, report); + break; + + case GCRY_MAC_HMAC_SHA3_224: + case GCRY_MAC_HMAC_SHA3_256: + case GCRY_MAC_HMAC_SHA3_384: + case GCRY_MAC_HMAC_SHA3_512: + { + int md_algo = map_mac_algo_to_md (algo); + ec = selftests_sha3 (md_algo, extended, report); + } + break; + + default: + ec = GPG_ERR_MAC_ALGO; + break; + } + + return ec; +} + + +static const gcry_mac_spec_ops_t hmac_ops = { + hmac_open, + hmac_close, + hmac_setkey, + NULL, + hmac_reset, + hmac_write, + hmac_read, + hmac_verify, + hmac_get_maclen, + hmac_get_keylen, + NULL, + hmac_selftest +}; + + +#if USE_SHA1 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha1 = { + GCRY_MAC_HMAC_SHA1, {0, 1}, "HMAC_SHA1", + &hmac_ops +}; +#endif +#if USE_SHA256 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha256 = { + GCRY_MAC_HMAC_SHA256, {0, 1}, "HMAC_SHA256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha224 = { + GCRY_MAC_HMAC_SHA224, {0, 1}, "HMAC_SHA224", + &hmac_ops +}; +#endif +#if USE_SHA512 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512 = { + GCRY_MAC_HMAC_SHA512, {0, 1}, "HMAC_SHA512", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha384 = { + GCRY_MAC_HMAC_SHA384, {0, 1}, "HMAC_SHA384", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512_256 = { + GCRY_MAC_HMAC_SHA512_256, {0, 1}, "HMAC_SHA512_256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512_224 = { + GCRY_MAC_HMAC_SHA512_224, {0, 1}, "HMAC_SHA512_224", + &hmac_ops +}; + +#endif +#if USE_SHA3 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_224 = { + GCRY_MAC_HMAC_SHA3_224, {0, 1}, "HMAC_SHA3_224", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_256 = { + GCRY_MAC_HMAC_SHA3_256, {0, 1}, "HMAC_SHA3_256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_384 = { + GCRY_MAC_HMAC_SHA3_384, {0, 1}, "HMAC_SHA3_384", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_512 = { + GCRY_MAC_HMAC_SHA3_512, {0, 1}, "HMAC_SHA3_512", + &hmac_ops +}; +#endif +#ifdef USE_GOST_R_3411_94 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_94 = { + GCRY_MAC_HMAC_GOSTR3411_94, {0, 0}, "HMAC_GOSTR3411_94", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_cp = { + GCRY_MAC_HMAC_GOSTR3411_CP, {0, 0}, "HMAC_GOSTR3411_CP", + &hmac_ops +}; +#endif +#ifdef USE_GOST_R_3411_12 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog256 = { + GCRY_MAC_HMAC_STRIBOG256, {0, 0}, "HMAC_STRIBOG256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog512 = { + GCRY_MAC_HMAC_STRIBOG512, {0, 0}, "HMAC_STRIBOG512", + &hmac_ops +}; +#endif +#if USE_WHIRLPOOL +gcry_mac_spec_t _gcry_mac_type_spec_hmac_whirlpool = { + GCRY_MAC_HMAC_WHIRLPOOL, {0, 0}, "HMAC_WHIRLPOOL", + &hmac_ops +}; +#endif +#if USE_RMD160 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_rmd160 = { + GCRY_MAC_HMAC_RMD160, {0, 0}, "HMAC_RIPEMD160", + &hmac_ops +}; +#endif +#if USE_TIGER +gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1 = { + GCRY_MAC_HMAC_TIGER1, {0, 0}, "HMAC_TIGER", + &hmac_ops +}; +#endif +#if USE_MD5 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5 = { + GCRY_MAC_HMAC_MD5, {0, 0}, "HMAC_MD5", + &hmac_ops +}; +#endif +#if USE_MD4 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md4 = { + GCRY_MAC_HMAC_MD4, {0, 0}, "HMAC_MD4", + &hmac_ops +}; +#endif +#if USE_MD2 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md2 = { + GCRY_MAC_HMAC_MD2, {0, 0}, "HMAC_MD2", + &hmac_ops +}; +#endif +#if USE_BLAKE2 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_512 = { + GCRY_MAC_HMAC_BLAKE2B_512, {0, 0}, "HMAC_BLAKE2B_512", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_384 = { + GCRY_MAC_HMAC_BLAKE2B_384, {0, 0}, "HMAC_BLAKE2B_384", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_256 = { + GCRY_MAC_HMAC_BLAKE2B_256, {0, 0}, "HMAC_BLAKE2B_256", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_160 = { + GCRY_MAC_HMAC_BLAKE2B_160, {0, 0}, "HMAC_BLAKE2B_160", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_256 = { + GCRY_MAC_HMAC_BLAKE2S_256, {0, 0}, "HMAC_BLAKE2S_256", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_224 = { + GCRY_MAC_HMAC_BLAKE2S_224, {0, 0}, "HMAC_BLAKE2S_224", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_160 = { + GCRY_MAC_HMAC_BLAKE2S_160, {0, 0}, "HMAC_BLAKE2S_160", + &hmac_ops +}; +gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_128 = { + GCRY_MAC_HMAC_BLAKE2S_128, {0, 0}, "HMAC_BLAKE2S_128", + &hmac_ops +}; +#endif +#if USE_SM3 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sm3 = { + GCRY_MAC_HMAC_SM3, {0, 0}, "HMAC_SM3", + &hmac_ops +}; +#endif diff --git a/comm/third_party/libgcrypt/cipher/mac-internal.h b/comm/third_party/libgcrypt/cipher/mac-internal.h new file mode 100644 index 0000000000..e49885beec --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac-internal.h @@ -0,0 +1,275 @@ +/* mac-internal.h - Internal defs for mac.c + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#include "g10lib.h" +#include "cipher-proto.h" +#include "gost.h" + + +/* The data object used to hold a handle to an encryption object. */ +struct gcry_mac_handle; + +/* The data object used to hold poly1305-mac context. */ +struct poly1305mac_context_s; + + +/* + * + * Message authentication code related definitions. + * + */ + + +/* Magic values for the context structure. */ +#define CTX_MAC_MAGIC_NORMAL 0x59d9b8af +#define CTX_MAC_MAGIC_SECURE 0x12c27cd0 + + +/* MAC module functions. */ +typedef gcry_err_code_t (*gcry_mac_open_func_t)(gcry_mac_hd_t h); +typedef void (*gcry_mac_close_func_t)(gcry_mac_hd_t h); +typedef gcry_err_code_t (*gcry_mac_setkey_func_t)(gcry_mac_hd_t h, + const unsigned char *key, + size_t keylen); +typedef gcry_err_code_t (*gcry_mac_setiv_func_t)(gcry_mac_hd_t h, + const unsigned char *iv, + size_t ivlen); +typedef gcry_err_code_t (*gcry_mac_reset_func_t)(gcry_mac_hd_t h); +typedef gcry_err_code_t (*gcry_mac_write_func_t)(gcry_mac_hd_t h, + const unsigned char *inbuf, + size_t inlen); +typedef gcry_err_code_t (*gcry_mac_read_func_t)(gcry_mac_hd_t h, + unsigned char *outbuf, + size_t *outlen); +typedef gcry_err_code_t (*gcry_mac_verify_func_t)(gcry_mac_hd_t h, + const unsigned char *inbuf, + size_t inlen); +typedef unsigned int (*gcry_mac_get_maclen_func_t)(int algo); +typedef unsigned int (*gcry_mac_get_keylen_func_t)(int algo); + +/* The type used to convey additional information to a MAC. */ +typedef gpg_err_code_t (*gcry_mac_set_extra_info_t) + (gcry_mac_hd_t h, int what, const void *buffer, size_t buflen); + +typedef struct gcry_mac_spec_ops +{ + gcry_mac_open_func_t open; + gcry_mac_close_func_t close; + gcry_mac_setkey_func_t setkey; + gcry_mac_setiv_func_t setiv; + gcry_mac_reset_func_t reset; + gcry_mac_write_func_t write; + gcry_mac_read_func_t read; + gcry_mac_verify_func_t verify; + gcry_mac_get_maclen_func_t get_maclen; + gcry_mac_get_keylen_func_t get_keylen; + gcry_mac_set_extra_info_t set_extra_info; + selftest_func_t selftest; +} gcry_mac_spec_ops_t; + + +/* Module specification structure for message authentication codes. */ +typedef struct gcry_mac_spec +{ + int algo; + struct { + unsigned int disabled:1; + unsigned int fips:1; + } flags; + const char *name; + const gcry_mac_spec_ops_t *ops; +} gcry_mac_spec_t; + +/* The handle structure. */ +struct gcry_mac_handle +{ + int magic; + int algo; + const gcry_mac_spec_t *spec; + gcry_ctx_t gcry_ctx; + union { + struct { + gcry_md_hd_t md_ctx; + int md_algo; + } hmac; + struct { + gcry_cipher_hd_t ctx; + int cipher_algo; + unsigned int blklen; + } cmac; + struct { + gcry_cipher_hd_t ctx; + int cipher_algo; + } gmac; + struct { + struct poly1305mac_context_s *ctx; + } poly1305mac; + struct { + GOST28147_context ctx; + u32 n1, n2; + unsigned int unused; + unsigned int count; + unsigned char lastiv[8]; /* IMIT blocksize */ + } imit; + } u; +}; + + +/* + * The HMAC algorithm specifications (mac-hmac.c). + */ +#if USE_SHA1 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha1; +#endif +#if USE_SHA256 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha224; +#endif +#if USE_SHA512 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha384; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512_224; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512_256; +#endif +#if USE_SHA3 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_224; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_384; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha3_512; +#endif +#ifdef USE_GOST_R_3411_94 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_94; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_cp; +#endif +#ifdef USE_GOST_R_3411_12 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog512; +#endif +#if USE_WHIRLPOOL +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_whirlpool; +#endif +#if USE_RMD160 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_rmd160; +#endif +#if USE_TIGER +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1; +#endif +#if USE_MD5 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5; +#endif +#if USE_MD4 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_md4; +#endif +#if USE_BLAKE2 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_512; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_384; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2b_160; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_224; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_160; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_blake2s_128; +#endif +#if USE_SM3 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sm3; +#endif + +/* + * The CMAC algorithm specifications (mac-cmac.c). + */ +#if USE_BLOWFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_blowfish; +#endif +#if USE_DES +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_tripledes; +#endif +#if USE_CAST5 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_cast5; +#endif +#if USE_AES +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_aes; +#endif +#if USE_TWOFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_twofish; +#endif +#if USE_SERPENT +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_serpent; +#endif +#if USE_RFC2268 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_rfc2268; +#endif +#if USE_SEED +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_seed; +#endif +#if USE_CAMELLIA +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_camellia; +#endif +#ifdef USE_IDEA +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_idea; +#endif +#if USE_GOST28147 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_gost28147; +#endif +#if USE_GOST28147 +extern gcry_mac_spec_t _gcry_mac_type_spec_gost28147_imit; +#endif +#if USE_SM4 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_sm4; +#endif + +/* + * The GMAC algorithm specifications (mac-gmac.c). + */ +#if USE_AES +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_aes; +#endif +#if USE_TWOFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_twofish; +#endif +#if USE_SERPENT +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_serpent; +#endif +#if USE_SEED +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed; +#endif +#if USE_CAMELLIA +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia; +#endif + +/* + * The Poly1305 MAC algorithm specifications (mac-poly1305.c). + */ +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac; +#if USE_AES +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes; +#endif +#if USE_CAMELLIA +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia; +#endif +#if USE_TWOFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish; +#endif +#if USE_SERPENT +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent; +#endif +#if USE_SEED +extern gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed; +#endif diff --git a/comm/third_party/libgcrypt/cipher/mac-poly1305.c b/comm/third_party/libgcrypt/cipher/mac-poly1305.c new file mode 100644 index 0000000000..46ea735f89 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac-poly1305.c @@ -0,0 +1,364 @@ +/* mac-poly1305.c - Poly1305 based MACs + * Copyright (C) 2014 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mac-internal.h" +#include "poly1305-internal.h" + + +struct poly1305mac_context_s { + poly1305_context_t ctx; + gcry_cipher_hd_t hd; + struct { + unsigned int key_set:1; + unsigned int nonce_set:1; + unsigned int tag:1; + } marks; + byte tag[POLY1305_TAGLEN]; + byte key[POLY1305_KEYLEN]; +}; + + +static gcry_err_code_t +poly1305mac_open (gcry_mac_hd_t h) +{ + struct poly1305mac_context_s *mac_ctx; + int secure = (h->magic == CTX_MAC_MAGIC_SECURE); + unsigned int flags = (secure ? GCRY_CIPHER_SECURE : 0); + gcry_err_code_t err; + int cipher_algo; + + if (secure) + mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx)); + else + mac_ctx = xtrycalloc (1, sizeof(*mac_ctx)); + + if (!mac_ctx) + return gpg_err_code_from_syserror (); + + h->u.poly1305mac.ctx = mac_ctx; + + switch (h->spec->algo) + { + default: + /* already checked. */ + case GCRY_MAC_POLY1305: + /* plain Poly1305. */ + cipher_algo = -1; + return 0; + case GCRY_MAC_POLY1305_AES: + cipher_algo = GCRY_CIPHER_AES; + break; + case GCRY_MAC_POLY1305_CAMELLIA: + cipher_algo = GCRY_CIPHER_CAMELLIA128; + break; + case GCRY_MAC_POLY1305_TWOFISH: + cipher_algo = GCRY_CIPHER_TWOFISH; + break; + case GCRY_MAC_POLY1305_SERPENT: + cipher_algo = GCRY_CIPHER_SERPENT128; + break; + case GCRY_MAC_POLY1305_SEED: + cipher_algo = GCRY_CIPHER_SEED; + break; + } + + err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo, + GCRY_CIPHER_MODE_ECB, flags); + if (err) + goto err_free; + + return 0; + +err_free: + xfree(h->u.poly1305mac.ctx); + return err; +} + + +static void +poly1305mac_close (gcry_mac_hd_t h) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + + if (h->spec->algo != GCRY_MAC_POLY1305) + _gcry_cipher_close (mac_ctx->hd); + + xfree(mac_ctx); +} + + +static gcry_err_code_t +poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + size_t block_keylen = keylen - 16; + + /* Need at least 16 + 1 byte key. */ + if (keylen <= 16) + return GPG_ERR_INV_KEYLEN; + + /* For Poly1305-AES, first part of key is passed to Poly1305 as is. */ + memcpy (mac_ctx->key, key + block_keylen, 16); + + /* Remaining part is used as key for the block cipher. */ + return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen); +} + + +static gcry_err_code_t +poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + gcry_err_code_t err; + + memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); + memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); + memset(&mac_ctx->key, 0, sizeof(mac_ctx->key)); + + mac_ctx->marks.key_set = 0; + mac_ctx->marks.nonce_set = 0; + mac_ctx->marks.tag = 0; + + if (h->spec->algo != GCRY_MAC_POLY1305) + { + err = poly1305mac_prepare_key (h, key, keylen); + if (err) + return err; + + /* Poly1305-AES/etc also need nonce. */ + mac_ctx->marks.key_set = 1; + mac_ctx->marks.nonce_set = 0; + } + else + { + /* For plain Poly1305, key is the nonce and setup is complete now. */ + + if (keylen != POLY1305_KEYLEN) + return GPG_ERR_INV_KEYLEN; + + memcpy (mac_ctx->key, key, keylen); + + err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); + if (err) + { + memset(&mac_ctx->key, 0, sizeof(mac_ctx->key)); + return err; + } + + mac_ctx->marks.key_set = 1; + mac_ctx->marks.nonce_set = 1; + } + + return 0; +} + + +static gcry_err_code_t +poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + gcry_err_code_t err; + + if (h->spec->algo == GCRY_MAC_POLY1305) + return GPG_ERR_INV_ARG; + + if (ivlen != 16) + return GPG_ERR_INV_ARG; + + if (!mac_ctx->marks.key_set) + return 0; + + memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); + memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); + mac_ctx->marks.nonce_set = 0; + mac_ctx->marks.tag = 0; + + /* Prepare second part of the poly1305 key. */ + + err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16); + if (err) + return err; + + err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); + if (err) + return err; + + mac_ctx->marks.nonce_set = 1; + return 0; +} + + +static gcry_err_code_t +poly1305mac_reset (gcry_mac_hd_t h) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + + if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set) + return GPG_ERR_INV_STATE; + + memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); + memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); + + mac_ctx->marks.key_set = 1; + mac_ctx->marks.nonce_set = 1; + mac_ctx->marks.tag = 0; + + return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); +} + + +static gcry_err_code_t +poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + + if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set || + mac_ctx->marks.tag) + return GPG_ERR_INV_STATE; + + _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen); + return 0; +} + + +static gcry_err_code_t +poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + + if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set) + return GPG_ERR_INV_STATE; + + if (!mac_ctx->marks.tag) + { + _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag); + + memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); + mac_ctx->marks.tag = 1; + } + + if (*outlen == 0) + return 0; + + if (*outlen <= POLY1305_TAGLEN) + buf_cpy (outbuf, mac_ctx->tag, *outlen); + else + { + buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN); + *outlen = POLY1305_TAGLEN; + } + + return 0; +} + + +static gcry_err_code_t +poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; + gcry_err_code_t err; + size_t outlen = 0; + + /* Check and finalize tag. */ + err = poly1305mac_read(h, NULL, &outlen); + if (err) + return err; + + if (buflen > POLY1305_TAGLEN) + return GPG_ERR_INV_LENGTH; + + return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM; +} + + +static unsigned int +poly1305mac_get_maclen (int algo) +{ + (void)algo; + + return POLY1305_TAGLEN; +} + + +static unsigned int +poly1305mac_get_keylen (int algo) +{ + (void)algo; + + return POLY1305_KEYLEN; +} + + +static gcry_mac_spec_ops_t poly1305mac_ops = { + poly1305mac_open, + poly1305mac_close, + poly1305mac_setkey, + poly1305mac_setiv, + poly1305mac_reset, + poly1305mac_write, + poly1305mac_read, + poly1305mac_verify, + poly1305mac_get_maclen, + poly1305mac_get_keylen, + NULL, + NULL, +}; + + +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = { + GCRY_MAC_POLY1305, {0, 0}, "POLY1305", + &poly1305mac_ops +}; +#if USE_AES +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = { + GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES", + &poly1305mac_ops +}; +#endif +#if USE_CAMELLIA +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = { + GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA", + &poly1305mac_ops +}; +#endif +#if USE_TWOFISH +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = { + GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH", + &poly1305mac_ops +}; +#endif +#if USE_SERPENT +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = { + GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT", + &poly1305mac_ops +}; +#endif +#if USE_SEED +gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = { + GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED", + &poly1305mac_ops +}; +#endif diff --git a/comm/third_party/libgcrypt/cipher/mac.c b/comm/third_party/libgcrypt/cipher/mac.c new file mode 100644 index 0000000000..babe99e3a8 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/mac.c @@ -0,0 +1,808 @@ +/* mac.c - message authentication code dispatcher + * Copyright (C) 2013 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "mac-internal.h" + + +/* This is the list of the digest implementations included in + libgcrypt. */ +static gcry_mac_spec_t * const mac_list[] = { +#if USE_SHA1 + &_gcry_mac_type_spec_hmac_sha1, +#endif +#if USE_SHA256 + &_gcry_mac_type_spec_hmac_sha256, + &_gcry_mac_type_spec_hmac_sha224, +#endif +#if USE_SHA512 + &_gcry_mac_type_spec_hmac_sha512, + &_gcry_mac_type_spec_hmac_sha384, + &_gcry_mac_type_spec_hmac_sha512_256, + &_gcry_mac_type_spec_hmac_sha512_224, +#endif +#if USE_SHA3 + &_gcry_mac_type_spec_hmac_sha3_224, + &_gcry_mac_type_spec_hmac_sha3_256, + &_gcry_mac_type_spec_hmac_sha3_384, + &_gcry_mac_type_spec_hmac_sha3_512, +#endif +#ifdef USE_GOST_R_3411_94 + &_gcry_mac_type_spec_hmac_gost3411_94, + &_gcry_mac_type_spec_hmac_gost3411_cp, +#endif +#ifdef USE_GOST_R_3411_12 + &_gcry_mac_type_spec_hmac_stribog256, + &_gcry_mac_type_spec_hmac_stribog512, +#endif +#if USE_WHIRLPOOL + &_gcry_mac_type_spec_hmac_whirlpool, +#endif +#if USE_RMD160 + &_gcry_mac_type_spec_hmac_rmd160, +#endif +#if USE_TIGER + &_gcry_mac_type_spec_hmac_tiger1, +#endif +#if USE_MD5 + &_gcry_mac_type_spec_hmac_md5, +#endif +#if USE_MD4 + &_gcry_mac_type_spec_hmac_md4, +#endif +#if USE_BLAKE2 + &_gcry_mac_type_spec_hmac_blake2b_512, + &_gcry_mac_type_spec_hmac_blake2b_384, + &_gcry_mac_type_spec_hmac_blake2b_256, + &_gcry_mac_type_spec_hmac_blake2b_160, + &_gcry_mac_type_spec_hmac_blake2s_256, + &_gcry_mac_type_spec_hmac_blake2s_224, + &_gcry_mac_type_spec_hmac_blake2s_160, + &_gcry_mac_type_spec_hmac_blake2s_128, +#endif +#if USE_SM3 + &_gcry_mac_type_spec_hmac_sm3, +#endif +#if USE_BLOWFISH + &_gcry_mac_type_spec_cmac_blowfish, +#endif +#if USE_DES + &_gcry_mac_type_spec_cmac_tripledes, +#endif +#if USE_CAST5 + &_gcry_mac_type_spec_cmac_cast5, +#endif +#if USE_AES + &_gcry_mac_type_spec_cmac_aes, + &_gcry_mac_type_spec_gmac_aes, + &_gcry_mac_type_spec_poly1305mac_aes, +#endif +#if USE_TWOFISH + &_gcry_mac_type_spec_cmac_twofish, + &_gcry_mac_type_spec_gmac_twofish, + &_gcry_mac_type_spec_poly1305mac_twofish, +#endif +#if USE_SERPENT + &_gcry_mac_type_spec_cmac_serpent, + &_gcry_mac_type_spec_gmac_serpent, + &_gcry_mac_type_spec_poly1305mac_serpent, +#endif +#if USE_RFC2268 + &_gcry_mac_type_spec_cmac_rfc2268, +#endif +#if USE_SEED + &_gcry_mac_type_spec_cmac_seed, + &_gcry_mac_type_spec_gmac_seed, + &_gcry_mac_type_spec_poly1305mac_seed, +#endif +#if USE_CAMELLIA + &_gcry_mac_type_spec_cmac_camellia, + &_gcry_mac_type_spec_gmac_camellia, + &_gcry_mac_type_spec_poly1305mac_camellia, +#endif +#ifdef USE_IDEA + &_gcry_mac_type_spec_cmac_idea, +#endif +#if USE_GOST28147 + &_gcry_mac_type_spec_cmac_gost28147, + &_gcry_mac_type_spec_gost28147_imit, +#endif + &_gcry_mac_type_spec_poly1305mac, +#if USE_SM4 + &_gcry_mac_type_spec_cmac_sm4, +#endif + NULL, +}; + +/* HMAC implementations start with index 101 (enum gcry_mac_algos) */ +static gcry_mac_spec_t * const mac_list_algo101[] = + { +#if USE_SHA256 + &_gcry_mac_type_spec_hmac_sha256, + &_gcry_mac_type_spec_hmac_sha224, +#else + NULL, + NULL, +#endif +#if USE_SHA512 + &_gcry_mac_type_spec_hmac_sha512, + &_gcry_mac_type_spec_hmac_sha384, +#else + NULL, + NULL, +#endif +#if USE_SHA1 + &_gcry_mac_type_spec_hmac_sha1, +#else + NULL, +#endif +#if USE_MD5 + &_gcry_mac_type_spec_hmac_md5, +#else + NULL, +#endif +#if USE_MD4 + &_gcry_mac_type_spec_hmac_md4, +#else + NULL, +#endif +#if USE_RMD160 + &_gcry_mac_type_spec_hmac_rmd160, +#else + NULL, +#endif +#if USE_TIGER + &_gcry_mac_type_spec_hmac_tiger1, +#else + NULL, +#endif +#if USE_WHIRLPOOL + &_gcry_mac_type_spec_hmac_whirlpool, +#else + NULL, +#endif +#ifdef USE_GOST_R_3411_94 + &_gcry_mac_type_spec_hmac_gost3411_94, +#else + NULL, +#endif +#ifdef USE_GOST_R_3411_12 + &_gcry_mac_type_spec_hmac_stribog256, + &_gcry_mac_type_spec_hmac_stribog512, +#else + NULL, + NULL, +#endif +#if USE_MD2 + &_gcry_mac_type_spec_hmac_md2, +#else + NULL, +#endif +#if USE_SHA3 + &_gcry_mac_type_spec_hmac_sha3_224, + &_gcry_mac_type_spec_hmac_sha3_256, + &_gcry_mac_type_spec_hmac_sha3_384, + &_gcry_mac_type_spec_hmac_sha3_512, +#else + NULL, + NULL, + NULL, + NULL, +#endif +#ifdef USE_GOST_R_3411_94 + &_gcry_mac_type_spec_hmac_gost3411_cp, +#else + NULL, +#endif +#if USE_BLAKE2 + &_gcry_mac_type_spec_hmac_blake2b_512, + &_gcry_mac_type_spec_hmac_blake2b_384, + &_gcry_mac_type_spec_hmac_blake2b_256, + &_gcry_mac_type_spec_hmac_blake2b_160, + &_gcry_mac_type_spec_hmac_blake2s_256, + &_gcry_mac_type_spec_hmac_blake2s_224, + &_gcry_mac_type_spec_hmac_blake2s_160, + &_gcry_mac_type_spec_hmac_blake2s_128, +#else + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif +#if USE_SM3 + &_gcry_mac_type_spec_hmac_sm3, +#else + NULL, +#endif +#if USE_SHA512 + &_gcry_mac_type_spec_hmac_sha512_256, + &_gcry_mac_type_spec_hmac_sha512_224, +#else + NULL, + NULL, +#endif + }; + +/* CMAC implementations start with index 201 (enum gcry_mac_algos) */ +static gcry_mac_spec_t * const mac_list_algo201[] = + { +#if USE_AES + &_gcry_mac_type_spec_cmac_aes, +#else + NULL, +#endif +#if USE_DES + &_gcry_mac_type_spec_cmac_tripledes, +#else + NULL, +#endif +#if USE_CAMELLIA + &_gcry_mac_type_spec_cmac_camellia, +#else + NULL, +#endif +#if USE_CAST5 + &_gcry_mac_type_spec_cmac_cast5, +#else + NULL, +#endif +#if USE_BLOWFISH + &_gcry_mac_type_spec_cmac_blowfish, +#else + NULL, +#endif +#if USE_TWOFISH + &_gcry_mac_type_spec_cmac_twofish, +#else + NULL, +#endif +#if USE_SERPENT + &_gcry_mac_type_spec_cmac_serpent, +#else + NULL, +#endif +#if USE_SEED + &_gcry_mac_type_spec_cmac_seed, +#else + NULL, +#endif +#if USE_RFC2268 + &_gcry_mac_type_spec_cmac_rfc2268, +#else + NULL, +#endif +#ifdef USE_IDEA + &_gcry_mac_type_spec_cmac_idea, +#else + NULL, +#endif +#if USE_GOST28147 + &_gcry_mac_type_spec_cmac_gost28147, +#else + NULL, +#endif +#if USE_SM4 + &_gcry_mac_type_spec_cmac_sm4 +#else + NULL +#endif + }; + +/* GMAC implementations start with index 401 (enum gcry_mac_algos) */ +static gcry_mac_spec_t * const mac_list_algo401[] = + { +#if USE_AES + &_gcry_mac_type_spec_gmac_aes, +#else + NULL, +#endif +#if USE_CAMELLIA + &_gcry_mac_type_spec_gmac_camellia, +#else + NULL, +#endif +#if USE_TWOFISH + &_gcry_mac_type_spec_gmac_twofish, +#else + NULL, +#endif +#if USE_SERPENT + &_gcry_mac_type_spec_gmac_serpent, +#else + NULL, +#endif +#if USE_SEED + &_gcry_mac_type_spec_gmac_seed +#else + NULL +#endif + }; + +/* Poly1305-MAC implementations start with index 501 (enum gcry_mac_algos) */ +static gcry_mac_spec_t * const mac_list_algo501[] = + { + &_gcry_mac_type_spec_poly1305mac, +#if USE_AES + &_gcry_mac_type_spec_poly1305mac_aes, +#else + NULL, +#endif +#if USE_CAMELLIA + &_gcry_mac_type_spec_poly1305mac_camellia, +#else + NULL, +#endif +#if USE_TWOFISH + &_gcry_mac_type_spec_poly1305mac_twofish, +#else + NULL, +#endif +#if USE_SERPENT + &_gcry_mac_type_spec_poly1305mac_serpent, +#else + NULL, +#endif +#if USE_SEED + &_gcry_mac_type_spec_poly1305mac_seed +#else + NULL +#endif + }; + + + + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_mac_init (void) +{ + if (fips_mode()) + { + /* disable algorithms that are disallowed in fips */ + int idx; + gcry_mac_spec_t *spec; + + for (idx = 0; (spec = mac_list[idx]); idx++) + if (!spec->flags.fips) + spec->flags.disabled = 1; + } + + return 0; +} + + +/* Return the spec structure for the MAC algorithm ALGO. For an + unknown algorithm NULL is returned. */ +static gcry_mac_spec_t * +spec_from_algo (int algo) +{ + gcry_mac_spec_t *spec = NULL; + + if (algo >= 101 && algo < 101 + DIM(mac_list_algo101)) + spec = mac_list_algo101[algo - 101]; + else if (algo >= 201 && algo < 201 + DIM(mac_list_algo201)) + spec = mac_list_algo201[algo - 201]; + else if (algo >= 401 && algo < 401 + DIM(mac_list_algo401)) + spec = mac_list_algo401[algo - 401]; + else if (algo >= 501 && algo < 501 + DIM(mac_list_algo501)) + spec = mac_list_algo501[algo - 501]; +#ifdef USE_GOST28147 + else if (algo == GCRY_MAC_GOST28147_IMIT) + spec = &_gcry_mac_type_spec_gost28147_imit; +#endif + + if (spec) + gcry_assert (spec->algo == algo); + + return spec; +} + + +/* Lookup a mac's spec by its name. */ +static gcry_mac_spec_t * +spec_from_name (const char *name) +{ + gcry_mac_spec_t *spec; + int idx; + + for (idx = 0; (spec = mac_list[idx]); idx++) + if (!stricmp (name, spec->name)) + return spec; + + return NULL; +} + + +/**************** + * Map a string to the mac algo + */ +int +_gcry_mac_map_name (const char *string) +{ + gcry_mac_spec_t *spec; + + if (!string) + return 0; + + /* Not found, search a matching mac name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; + + return 0; +} + + +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + * Use the macro gcry_mac_test_algo() to check whether the algorithm + * is valid. + */ +const char * +_gcry_mac_algo_name (int algorithm) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec ? spec->name : "?"; +} + + +static gcry_err_code_t +check_mac_algo (int algorithm) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; + + return GPG_ERR_MAC_ALGO; +} + + +/**************** + * Open a message digest handle for use with algorithm ALGO. + */ +static gcry_err_code_t +mac_open (gcry_mac_hd_t * hd, int algo, int secure, gcry_ctx_t ctx) +{ + gcry_mac_spec_t *spec; + gcry_err_code_t err; + gcry_mac_hd_t h; + + spec = spec_from_algo (algo); + if (!spec) + return GPG_ERR_MAC_ALGO; + else if (spec->flags.disabled) + return GPG_ERR_MAC_ALGO; + else if (!spec->ops) + return GPG_ERR_MAC_ALGO; + else if (!spec->ops->open || !spec->ops->write || !spec->ops->setkey || + !spec->ops->read || !spec->ops->verify || !spec->ops->reset) + return GPG_ERR_MAC_ALGO; + + if (secure) + h = xtrycalloc_secure (1, sizeof (*h)); + else + h = xtrycalloc (1, sizeof (*h)); + + if (!h) + return gpg_err_code_from_syserror (); + + h->magic = secure ? CTX_MAC_MAGIC_SECURE : CTX_MAC_MAGIC_NORMAL; + h->spec = spec; + h->algo = algo; + h->gcry_ctx = ctx; + + err = h->spec->ops->open (h); + if (err) + xfree (h); + else + *hd = h; + + return err; +} + + +static gcry_err_code_t +mac_reset (gcry_mac_hd_t hd) +{ + if (hd->spec->ops->reset) + return hd->spec->ops->reset (hd); + + return 0; +} + + +static void +mac_close (gcry_mac_hd_t hd) +{ + if (hd->spec->ops->close) + hd->spec->ops->close (hd); + + wipememory (hd, sizeof (*hd)); + + xfree (hd); +} + + +static gcry_err_code_t +mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) +{ + if (!hd->spec->ops->setkey) + return GPG_ERR_INV_ARG; + if (keylen > 0 && !key) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->setkey (hd, key, keylen); +} + + +static gcry_err_code_t +mac_setiv (gcry_mac_hd_t hd, const void *iv, size_t ivlen) +{ + if (!hd->spec->ops->setiv) + return GPG_ERR_INV_ARG; + if (ivlen > 0 && !iv) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->setiv (hd, iv, ivlen); +} + + +static gcry_err_code_t +mac_write (gcry_mac_hd_t hd, const void *inbuf, size_t inlen) +{ + if (!hd->spec->ops->write) + return GPG_ERR_INV_ARG; + if (inlen > 0 && !inbuf) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->write (hd, inbuf, inlen); +} + + +static gcry_err_code_t +mac_read (gcry_mac_hd_t hd, void *outbuf, size_t * outlen) +{ + if (!outbuf || !outlen || *outlen == 0 || !hd->spec->ops->read) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->read (hd, outbuf, outlen); +} + + +static gcry_err_code_t +mac_verify (gcry_mac_hd_t hd, const void *buf, size_t buflen) +{ + if (!buf || buflen == 0 || !hd->spec->ops->verify) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->verify (hd, buf, buflen); +} + + +/* Create a MAC object for algorithm ALGO. FLAGS may be + given as an bitwise OR of the gcry_mac_flags values. + H is guaranteed to be a valid handle or NULL on error. */ +gpg_err_code_t +_gcry_mac_open (gcry_mac_hd_t * h, int algo, unsigned int flags, + gcry_ctx_t ctx) +{ + gcry_err_code_t rc; + gcry_mac_hd_t hd = NULL; + + if ((flags & ~GCRY_MAC_FLAG_SECURE)) + rc = GPG_ERR_INV_ARG; + else + rc = mac_open (&hd, algo, !!(flags & GCRY_MAC_FLAG_SECURE), ctx); + + *h = rc ? NULL : hd; + return rc; +} + + +void +_gcry_mac_close (gcry_mac_hd_t hd) +{ + if (hd) + mac_close (hd); +} + + +gcry_err_code_t +_gcry_mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) +{ + return mac_setkey (hd, key, keylen); +} + + +gcry_err_code_t +_gcry_mac_setiv (gcry_mac_hd_t hd, const void *iv, size_t ivlen) +{ + return mac_setiv (hd, iv, ivlen); +} + + +gcry_err_code_t +_gcry_mac_write (gcry_mac_hd_t hd, const void *inbuf, size_t inlen) +{ + return mac_write (hd, inbuf, inlen); +} + + +gcry_err_code_t +_gcry_mac_read (gcry_mac_hd_t hd, void *outbuf, size_t * outlen) +{ + return mac_read (hd, outbuf, outlen); +} + + +gcry_err_code_t +_gcry_mac_verify (gcry_mac_hd_t hd, const void *buf, size_t buflen) +{ + return mac_verify (hd, buf, buflen); +} + + +int +_gcry_mac_get_algo (gcry_mac_hd_t hd) +{ + return hd->algo; +} + + +unsigned int +_gcry_mac_get_algo_maclen (int algo) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec || !spec->ops || !spec->ops->get_maclen) + return 0; + + return spec->ops->get_maclen (algo); +} + + +unsigned int +_gcry_mac_get_algo_keylen (int algo) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec || !spec->ops || !spec->ops->get_keylen) + return 0; + + return spec->ops->get_keylen (algo); +} + + +gcry_err_code_t +_gcry_mac_ctl (gcry_mac_hd_t hd, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc; + + /* Currently not used. */ + (void) hd; + (void) buffer; + (void) buflen; + + switch (cmd) + { + case GCRYCTL_RESET: + rc = mac_reset (hd); + break; + case GCRYCTL_SET_SBOX: + if (hd->spec->ops->set_extra_info) + rc = hd->spec->ops->set_extra_info + (hd, GCRYCTL_SET_SBOX, buffer, buflen); + else + rc = GPG_ERR_NOT_SUPPORTED; + break; + default: + rc = GPG_ERR_INV_OP; + } + return rc; +} + + +/* Return information about the given MAC algorithm ALGO. + + GCRYCTL_TEST_ALGO: + Returns 0 if the specified algorithm ALGO is available for use. + BUFFER and NBYTES must be zero. + + Note: Because this function is in most cases used to return an + integer value, we can make it easier for the caller to just look at + the return value. The caller will in all cases consult the value + and thereby detecting whether a error occurred or not (i.e. while + checking the block size) + */ +gcry_err_code_t +_gcry_mac_algo_info (int algo, int what, void *buffer, size_t * nbytes) +{ + gcry_err_code_t rc = 0; + unsigned int ui; + + switch (what) + { + case GCRYCTL_GET_KEYLEN: + if (buffer || (!nbytes)) + rc = GPG_ERR_INV_ARG; + else + { + ui = _gcry_mac_get_algo_keylen (algo); + if (ui > 0) + *nbytes = (size_t) ui; + else + /* The only reason for an error is an invalid algo. */ + rc = GPG_ERR_MAC_ALGO; + } + break; + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + rc = GPG_ERR_INV_ARG; + else + rc = check_mac_algo (algo); + break; + + default: + rc = GPG_ERR_INV_OP; + } + + return rc; +} + + +/* Run the self-tests for the MAC. */ +gpg_error_t +_gcry_mac_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_err_code_t ec; + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->ops && spec->ops->selftest) + ec = spec->ops->selftest (algo, extended, report); + else + { + ec = GPG_ERR_MAC_ALGO; + if (report) + report ("mac", algo, "module", + spec && !spec->flags.disabled? + "no selftest available" : + spec? "algorithm disabled" : + "algorithm not found"); + } + + return gpg_error (ec); +} diff --git a/comm/third_party/libgcrypt/cipher/md.c b/comm/third_party/libgcrypt/cipher/md.c new file mode 100644 index 0000000000..efb7376a1a --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/md.c @@ -0,0 +1,1639 @@ +/* md.c - message digest dispatcher + * Copyright (C) 1998, 1999, 2002, 2003, 2006, + * 2008 Free Software Foundation, Inc. + * Copyright (C) 2013, 2014 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" + + +/* This is the list of the digest implementations included in + libgcrypt. */ +static gcry_md_spec_t * const digest_list[] = + { +#if USE_CRC + &_gcry_digest_spec_crc32, + &_gcry_digest_spec_crc32_rfc1510, + &_gcry_digest_spec_crc24_rfc2440, +#endif +#if USE_SHA1 + &_gcry_digest_spec_sha1, +#endif +#if USE_SHA256 + &_gcry_digest_spec_sha256, + &_gcry_digest_spec_sha224, +#endif +#if USE_SHA512 + &_gcry_digest_spec_sha512, + &_gcry_digest_spec_sha384, + &_gcry_digest_spec_sha512_256, + &_gcry_digest_spec_sha512_224, +#endif +#if USE_SHA3 + &_gcry_digest_spec_sha3_224, + &_gcry_digest_spec_sha3_256, + &_gcry_digest_spec_sha3_384, + &_gcry_digest_spec_sha3_512, + &_gcry_digest_spec_shake128, + &_gcry_digest_spec_shake256, +#endif +#if USE_GOST_R_3411_94 + &_gcry_digest_spec_gost3411_94, + &_gcry_digest_spec_gost3411_cp, +#endif +#if USE_GOST_R_3411_12 + &_gcry_digest_spec_stribog_256, + &_gcry_digest_spec_stribog_512, +#endif +#if USE_WHIRLPOOL + &_gcry_digest_spec_whirlpool, +#endif +#if USE_RMD160 + &_gcry_digest_spec_rmd160, +#endif +#if USE_TIGER + &_gcry_digest_spec_tiger, + &_gcry_digest_spec_tiger1, + &_gcry_digest_spec_tiger2, +#endif +#if USE_MD5 + &_gcry_digest_spec_md5, +#endif +#if USE_MD4 + &_gcry_digest_spec_md4, +#endif +#if USE_MD2 + &_gcry_digest_spec_md2, +#endif +#if USE_BLAKE2 + &_gcry_digest_spec_blake2b_512, + &_gcry_digest_spec_blake2b_384, + &_gcry_digest_spec_blake2b_256, + &_gcry_digest_spec_blake2b_160, + &_gcry_digest_spec_blake2s_256, + &_gcry_digest_spec_blake2s_224, + &_gcry_digest_spec_blake2s_160, + &_gcry_digest_spec_blake2s_128, +#endif +#if USE_SM3 + &_gcry_digest_spec_sm3, +#endif + NULL + }; + +/* Digest implementations starting with index 0 (enum gcry_md_algos) */ +static gcry_md_spec_t * const digest_list_algo0[] = + { + NULL, /* GCRY_MD_NONE */ +#if USE_MD5 + &_gcry_digest_spec_md5, +#else + NULL, +#endif +#if USE_SHA1 + &_gcry_digest_spec_sha1, +#else + NULL, +#endif +#if USE_RMD160 + &_gcry_digest_spec_rmd160, +#else + NULL, +#endif + NULL, /* Unused index 4 */ +#if USE_MD2 + &_gcry_digest_spec_md2, +#else + NULL, +#endif +#if USE_TIGER + &_gcry_digest_spec_tiger, +#else + NULL, +#endif + NULL, /* GCRY_MD_HAVAL */ +#if USE_SHA256 + &_gcry_digest_spec_sha256, +#else + NULL, +#endif +#if USE_SHA512 + &_gcry_digest_spec_sha384, + &_gcry_digest_spec_sha512, +#else + NULL, + NULL, +#endif +#if USE_SHA256 + &_gcry_digest_spec_sha224 +#else + NULL +#endif + }; + +/* Digest implementations starting with index 301 (enum gcry_md_algos) */ +static gcry_md_spec_t * const digest_list_algo301[] = + { +#if USE_MD4 + &_gcry_digest_spec_md4, +#else + NULL, +#endif +#if USE_CRC + &_gcry_digest_spec_crc32, + &_gcry_digest_spec_crc32_rfc1510, + &_gcry_digest_spec_crc24_rfc2440, +#else + NULL, + NULL, + NULL, +#endif +#if USE_WHIRLPOOL + &_gcry_digest_spec_whirlpool, +#else + NULL, +#endif +#if USE_TIGER + &_gcry_digest_spec_tiger1, + &_gcry_digest_spec_tiger2, +#else + NULL, + NULL, +#endif +#if USE_GOST_R_3411_94 + &_gcry_digest_spec_gost3411_94, +#else + NULL, +#endif +#if USE_GOST_R_3411_12 + &_gcry_digest_spec_stribog_256, + &_gcry_digest_spec_stribog_512, +#else + NULL, + NULL, +#endif +#if USE_GOST_R_3411_94 + &_gcry_digest_spec_gost3411_cp, +#else + NULL, +#endif +#if USE_SHA3 + &_gcry_digest_spec_sha3_224, + &_gcry_digest_spec_sha3_256, + &_gcry_digest_spec_sha3_384, + &_gcry_digest_spec_sha3_512, + &_gcry_digest_spec_shake128, + &_gcry_digest_spec_shake256, +#else + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif +#if USE_BLAKE2 + &_gcry_digest_spec_blake2b_512, + &_gcry_digest_spec_blake2b_384, + &_gcry_digest_spec_blake2b_256, + &_gcry_digest_spec_blake2b_160, + &_gcry_digest_spec_blake2s_256, + &_gcry_digest_spec_blake2s_224, + &_gcry_digest_spec_blake2s_160, + &_gcry_digest_spec_blake2s_128, +#else + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif +#if USE_SM3 + &_gcry_digest_spec_sm3, +#else + NULL, +#endif +#if USE_SHA512 + &_gcry_digest_spec_sha512_256, + &_gcry_digest_spec_sha512_224, +#else + NULL, + NULL, +#endif + }; + + +typedef struct gcry_md_list +{ + gcry_md_spec_t *spec; + struct gcry_md_list *next; + size_t actual_struct_size; /* Allocated size of this structure. */ + PROPERLY_ALIGNED_TYPE context[1]; +} GcryDigestEntry; + +/* This structure is put right after the gcry_md_hd_t buffer, so that + * only one memory block is needed. */ +struct gcry_md_context +{ + int magic; + size_t actual_handle_size; /* Allocated size of this handle. */ + FILE *debug; + struct { + unsigned int secure:1; + unsigned int finalized:1; + unsigned int bugemu1:1; + unsigned int hmac:1; + } flags; + GcryDigestEntry *list; +}; + + +#define CTX_MAGIC_NORMAL 0x11071961 +#define CTX_MAGIC_SECURE 0x16917011 + +static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); +static void md_close (gcry_md_hd_t a); +static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen); +static byte *md_read( gcry_md_hd_t a, int algo ); +static int md_get_algo( gcry_md_hd_t a ); +static int md_digest_length( int algo ); +static void md_start_debug ( gcry_md_hd_t a, const char *suffix ); +static void md_stop_debug ( gcry_md_hd_t a ); + + + +static int +map_algo (int algo) +{ + return algo; +} + + +/* Return the spec structure for the hash algorithm ALGO. For an + unknown algorithm NULL is returned. */ +static gcry_md_spec_t * +spec_from_algo (int algo) +{ + gcry_md_spec_t *spec = NULL; + + algo = map_algo (algo); + + if (algo >= 0 && algo < DIM(digest_list_algo0)) + spec = digest_list_algo0[algo]; + else if (algo >= 301 && algo < 301 + DIM(digest_list_algo301)) + spec = digest_list_algo301[algo - 301]; + + if (spec) + gcry_assert (spec->algo == algo); + + return spec; +} + + +/* Lookup a hash's spec by its name. */ +static gcry_md_spec_t * +spec_from_name (const char *name) +{ + gcry_md_spec_t *spec; + int idx; + + for (idx=0; (spec = digest_list[idx]); idx++) + { + if (!stricmp (name, spec->name)) + return spec; + } + + return NULL; +} + + +/* Lookup a hash's spec by its OID. */ +static gcry_md_spec_t * +spec_from_oid (const char *oid) +{ + gcry_md_spec_t *spec; + gcry_md_oid_spec_t *oid_specs; + int idx, j; + + for (idx=0; (spec = digest_list[idx]); idx++) + { + oid_specs = spec->oids; + if (oid_specs) + { + for (j = 0; oid_specs[j].oidstring; j++) + if (!stricmp (oid, oid_specs[j].oidstring)) + return spec; + } + } + + return NULL; +} + + +static gcry_md_spec_t * +search_oid (const char *oid, gcry_md_oid_spec_t *oid_spec) +{ + gcry_md_spec_t *spec; + int i; + + if (!oid) + return NULL; + + if (!strncmp (oid, "oid.", 4) || !strncmp (oid, "OID.", 4)) + oid += 4; + + spec = spec_from_oid (oid); + if (spec && spec->oids) + { + for (i = 0; spec->oids[i].oidstring; i++) + if (!stricmp (oid, spec->oids[i].oidstring)) + { + if (oid_spec) + *oid_spec = spec->oids[i]; + return spec; + } + } + + return NULL; +} + + +/**************** + * Map a string to the digest algo + */ +int +_gcry_md_map_name (const char *string) +{ + gcry_md_spec_t *spec; + + if (!string) + return 0; + + /* If the string starts with a digit (optionally prefixed with + either "OID." or "oid."), we first look into our table of ASN.1 + object identifiers to figure out the algorithm */ + spec = search_oid (string, NULL); + if (spec) + return spec->algo; + + /* Not found, search a matching digest name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; + + return 0; +} + + +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + * Use the macro gcry_md_test_algo() to check whether the algorithm + * is valid. + */ +const char * +_gcry_md_algo_name (int algorithm) +{ + gcry_md_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec ? spec->name : "?"; +} + + +static gcry_err_code_t +check_digest_algo (int algorithm) +{ + gcry_md_spec_t *spec; + + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; + + return GPG_ERR_DIGEST_ALGO; + +} + + +/**************** + * Open a message digest handle for use with algorithm ALGO. + * More algorithms may be added by md_enable(). The initial algorithm + * may be 0. + */ +static gcry_err_code_t +md_open (gcry_md_hd_t *h, int algo, unsigned int flags) +{ + gcry_err_code_t err = 0; + int secure = !!(flags & GCRY_MD_FLAG_SECURE); + int hmac = !!(flags & GCRY_MD_FLAG_HMAC); + int bufsize = secure ? 512 : 1024; + struct gcry_md_context *ctx; + gcry_md_hd_t hd; + size_t n; + + /* Allocate a memory area to hold the caller visible buffer with it's + * control information and the data required by this module. Set the + * context pointer at the beginning to this area. + * We have to use this strange scheme because we want to hide the + * internal data but have a variable sized buffer. + * + * +---+------+---........------+-------------+ + * !ctx! bctl ! buffer ! private ! + * +---+------+---........------+-------------+ + * ! ^ + * !---------------------------! + * + * We have to make sure that private is well aligned. + */ + n = sizeof (struct gcry_md_handle) + bufsize; + n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1) + / sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE); + + /* Allocate and set the Context pointer to the private data */ + if (secure) + hd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); + else + hd = xtrymalloc (n + sizeof (struct gcry_md_context)); + + if (! hd) + err = gpg_err_code_from_errno (errno); + + if (! err) + { + hd->ctx = ctx = (void *) ((char *) hd + n); + /* Setup the globally visible data (bctl in the diagram).*/ + hd->bufsize = n - sizeof (struct gcry_md_handle) + 1; + hd->bufpos = 0; + + /* Initialize the private data. */ + memset (hd->ctx, 0, sizeof *hd->ctx); + ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + ctx->actual_handle_size = n + sizeof (struct gcry_md_context); + ctx->flags.secure = secure; + ctx->flags.hmac = hmac; + ctx->flags.bugemu1 = !!(flags & GCRY_MD_FLAG_BUGEMU1); + } + + if (! err) + { + /* Hmmm, should we really do that? - yes [-wk] */ + _gcry_fast_random_poll (); + + if (algo) + { + err = md_enable (hd, algo); + if (err) + md_close (hd); + } + } + + if (! err) + *h = hd; + + return err; +} + +/* Create a message digest object for algorithm ALGO. FLAGS may be + given as an bitwise OR of the gcry_md_flags values. ALGO may be + given as 0 if the algorithms to be used are later set using + gcry_md_enable. H is guaranteed to be a valid handle or NULL on + error. */ +gcry_err_code_t +_gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) +{ + gcry_err_code_t rc; + gcry_md_hd_t hd; + + if ((flags & ~(GCRY_MD_FLAG_SECURE + | GCRY_MD_FLAG_HMAC + | GCRY_MD_FLAG_BUGEMU1))) + rc = GPG_ERR_INV_ARG; + else + rc = md_open (&hd, algo, flags); + + *h = rc? NULL : hd; + return rc; +} + + + +static gcry_err_code_t +md_enable (gcry_md_hd_t hd, int algorithm) +{ + struct gcry_md_context *h = hd->ctx; + gcry_md_spec_t *spec; + GcryDigestEntry *entry; + gcry_err_code_t err = 0; + + for (entry = h->list; entry; entry = entry->next) + if (entry->spec->algo == algorithm) + return 0; /* Already enabled */ + + spec = spec_from_algo (algorithm); + if (!spec) + { + log_debug ("md_enable: algorithm %d not available\n", algorithm); + err = GPG_ERR_DIGEST_ALGO; + } + + + if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) + { + _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { + /* We should never get to here because we do not register + MD5 in enforced fips mode. But better throw an error. */ + err = GPG_ERR_DIGEST_ALGO; + } + } + + if (!err && h->flags.hmac && spec->read == NULL) + { + /* Expandable output function cannot act as part of HMAC. */ + err = GPG_ERR_DIGEST_ALGO; + } + + if (!err) + { + size_t size = (sizeof (*entry) + + spec->contextsize * (h->flags.hmac? 3 : 1) + - sizeof (entry->context)); + + /* And allocate a new list entry. */ + if (h->flags.secure) + entry = xtrymalloc_secure (size); + else + entry = xtrymalloc (size); + + if (! entry) + err = gpg_err_code_from_errno (errno); + else + { + entry->spec = spec; + entry->next = h->list; + entry->actual_struct_size = size; + h->list = entry; + + /* And init this instance. */ + entry->spec->init (entry->context, + h->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); + } + } + + return err; +} + + +gcry_err_code_t +_gcry_md_enable (gcry_md_hd_t hd, int algorithm) +{ + return md_enable (hd, algorithm); +} + + +static gcry_err_code_t +md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) +{ + gcry_err_code_t err = 0; + struct gcry_md_context *a = ahd->ctx; + struct gcry_md_context *b; + GcryDigestEntry *ar, *br; + gcry_md_hd_t bhd; + size_t n; + + if (ahd->bufpos) + md_write (ahd, NULL, 0); + + n = (char *) ahd->ctx - (char *) ahd; + if (a->flags.secure) + bhd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); + else + bhd = xtrymalloc (n + sizeof (struct gcry_md_context)); + + if (!bhd) + { + err = gpg_err_code_from_syserror (); + goto leave; + } + + bhd->ctx = b = (void *) ((char *) bhd + n); + /* No need to copy the buffer due to the write above. */ + gcry_assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1)); + bhd->bufsize = ahd->bufsize; + bhd->bufpos = 0; + gcry_assert (! ahd->bufpos); + memcpy (b, a, sizeof *a); + b->list = NULL; + b->debug = NULL; + + /* Copy the complete list of algorithms. The copied list is + reversed, but that doesn't matter. */ + for (ar = a->list; ar; ar = ar->next) + { + if (a->flags.secure) + br = xtrymalloc_secure (ar->actual_struct_size); + else + br = xtrymalloc (ar->actual_struct_size); + if (!br) + { + err = gpg_err_code_from_syserror (); + md_close (bhd); + goto leave; + } + + memcpy (br, ar, ar->actual_struct_size); + br->next = b->list; + b->list = br; + } + + if (a->debug) + md_start_debug (bhd, "unknown"); + + *b_hd = bhd; + + leave: + return err; +} + + +gcry_err_code_t +_gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) +{ + gcry_err_code_t rc; + + rc = md_copy (hd, handle); + if (rc) + *handle = NULL; + return rc; +} + + +/* + * Reset all contexts and discard any buffered stuff. This may be used + * instead of a md_close(); md_open(). + */ +void +_gcry_md_reset (gcry_md_hd_t a) +{ + GcryDigestEntry *r; + + /* Note: We allow this even in fips non operational mode. */ + + a->bufpos = a->ctx->flags.finalized = 0; + + if (a->ctx->flags.hmac) + for (r = a->ctx->list; r; r = r->next) + { + memcpy (r->context, (char *)r->context + r->spec->contextsize, + r->spec->contextsize); + } + else + for (r = a->ctx->list; r; r = r->next) + { + memset (r->context, 0, r->spec->contextsize); + (*r->spec->init) (r->context, + a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); + } +} + + +static void +md_close (gcry_md_hd_t a) +{ + GcryDigestEntry *r, *r2; + + if (! a) + return; + if (a->ctx->debug) + md_stop_debug (a); + for (r = a->ctx->list; r; r = r2) + { + r2 = r->next; + wipememory (r, r->actual_struct_size); + xfree (r); + } + + wipememory (a, a->ctx->actual_handle_size); + xfree(a); +} + + +void +_gcry_md_close (gcry_md_hd_t hd) +{ + /* Note: We allow this even in fips non operational mode. */ + md_close (hd); +} + + +static void +md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) +{ + GcryDigestEntry *r; + + if (a->ctx->debug) + { + if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1) + BUG(); + if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1) + BUG(); + } + + for (r = a->ctx->list; r; r = r->next) + { + if (a->bufpos) + (*r->spec->write) (r->context, a->buf, a->bufpos); + (*r->spec->write) (r->context, inbuf, inlen); + } + a->bufpos = 0; +} + + +/* Note that this function may be used after finalize and read to keep + on writing to the transform function so to mitigate timing + attacks. */ +void +_gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) +{ + md_write (hd, inbuf, inlen); +} + + +static void +md_final (gcry_md_hd_t a) +{ + GcryDigestEntry *r; + + if (a->ctx->flags.finalized) + return; + + if (a->bufpos) + md_write (a, NULL, 0); + + for (r = a->ctx->list; r; r = r->next) + (*r->spec->final) (r->context); + + a->ctx->flags.finalized = 1; + + if (!a->ctx->flags.hmac) + return; + + for (r = a->ctx->list; r; r = r->next) + { + byte *p; + size_t dlen = r->spec->mdlen; + byte *hash; + gcry_err_code_t err; + + if (r->spec->read == NULL) + continue; + + p = r->spec->read (r->context); + + if (a->ctx->flags.secure) + hash = xtrymalloc_secure (dlen); + else + hash = xtrymalloc (dlen); + if (!hash) + { + err = gpg_err_code_from_errno (errno); + _gcry_fatal_error (err, NULL); + } + + memcpy (hash, p, dlen); + memcpy (r->context, (char *)r->context + r->spec->contextsize * 2, + r->spec->contextsize); + (*r->spec->write) (r->context, hash, dlen); + (*r->spec->final) (r->context); + xfree (hash); + } +} + + +static gcry_err_code_t +md_setkey (gcry_md_hd_t h, const unsigned char *key, size_t keylen) +{ + gcry_err_code_t rc = 0; + GcryDigestEntry *r; + int algo_had_setkey = 0; + + if (!h->ctx->list) + return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ + + if (h->ctx->flags.hmac) + return GPG_ERR_DIGEST_ALGO; /* Tried md_setkey for HMAC md. */ + + for (r = h->ctx->list; r; r = r->next) + { + switch (r->spec->algo) + { +#if USE_BLAKE2 + /* TODO? add spec->init_with_key? */ + case GCRY_MD_BLAKE2B_512: + case GCRY_MD_BLAKE2B_384: + case GCRY_MD_BLAKE2B_256: + case GCRY_MD_BLAKE2B_160: + case GCRY_MD_BLAKE2S_256: + case GCRY_MD_BLAKE2S_224: + case GCRY_MD_BLAKE2S_160: + case GCRY_MD_BLAKE2S_128: + algo_had_setkey = 1; + memset (r->context, 0, r->spec->contextsize); + rc = _gcry_blake2_init_with_key (r->context, + h->ctx->flags.bugemu1 + ? GCRY_MD_FLAG_BUGEMU1:0, + key, keylen, r->spec->algo); + break; +#endif + default: + rc = GPG_ERR_DIGEST_ALGO; + break; + } + + if (rc) + break; + } + + if (rc && !algo_had_setkey) + { + /* None of algorithms had setkey implementation, so contexts were not + * modified. Just return error. */ + return rc; + } + else if (rc && algo_had_setkey) + { + /* Some of the contexts have been modified, but got error. Reset + * all contexts. */ + _gcry_md_reset (h); + return rc; + } + + /* Successful md_setkey implies reset. */ + h->bufpos = h->ctx->flags.finalized = 0; + + return 0; +} + + +static gcry_err_code_t +prepare_macpads (gcry_md_hd_t a, const unsigned char *key, size_t keylen) +{ + GcryDigestEntry *r; + + if (!a->ctx->list) + return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ + + if (!a->ctx->flags.hmac) + return GPG_ERR_DIGEST_ALGO; /* Tried prepare_macpads for non-HMAC md. */ + + for (r = a->ctx->list; r; r = r->next) + { + const unsigned char *k; + size_t k_len; + unsigned char *key_allocated = NULL; + int macpad_Bsize; + int i; + + switch (r->spec->algo) + { + /* TODO: add spec->blocksize */ + case GCRY_MD_SHA3_224: + macpad_Bsize = 1152 / 8; + break; + case GCRY_MD_SHA3_256: + macpad_Bsize = 1088 / 8; + break; + case GCRY_MD_SHA3_384: + macpad_Bsize = 832 / 8; + break; + case GCRY_MD_SHA3_512: + macpad_Bsize = 576 / 8; + break; + case GCRY_MD_SHA384: + case GCRY_MD_SHA512: + case GCRY_MD_SHA512_256: + case GCRY_MD_SHA512_224: + case GCRY_MD_BLAKE2B_512: + case GCRY_MD_BLAKE2B_384: + case GCRY_MD_BLAKE2B_256: + case GCRY_MD_BLAKE2B_160: + macpad_Bsize = 128; + break; + case GCRY_MD_GOSTR3411_94: + case GCRY_MD_GOSTR3411_CP: + macpad_Bsize = 32; + break; + default: + macpad_Bsize = 64; + break; + } + + if ( keylen > macpad_Bsize ) + { + k = key_allocated = xtrymalloc_secure (r->spec->mdlen); + if (!k) + return gpg_err_code_from_errno (errno); + _gcry_md_hash_buffer (r->spec->algo, key_allocated, key, keylen); + k_len = r->spec->mdlen; + gcry_assert ( k_len <= macpad_Bsize ); + } + else + { + k = key; + k_len = keylen; + } + + (*r->spec->init) (r->context, + a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); + a->bufpos = 0; + for (i=0; i < k_len; i++ ) + _gcry_md_putc (a, k[i] ^ 0x36); + for (; i < macpad_Bsize; i++ ) + _gcry_md_putc (a, 0x36); + (*r->spec->write) (r->context, a->buf, a->bufpos); + memcpy ((char *)r->context + r->spec->contextsize, r->context, + r->spec->contextsize); + + (*r->spec->init) (r->context, + a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); + a->bufpos = 0; + for (i=0; i < k_len; i++ ) + _gcry_md_putc (a, k[i] ^ 0x5c); + for (; i < macpad_Bsize; i++ ) + _gcry_md_putc (a, 0x5c); + (*r->spec->write) (r->context, a->buf, a->bufpos); + memcpy ((char *)r->context + r->spec->contextsize*2, r->context, + r->spec->contextsize); + + xfree (key_allocated); + } + + a->bufpos = 0; + return 0; +} + + +gcry_err_code_t +_gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = 0; + + (void)buflen; /* Currently not used. */ + + switch (cmd) + { + case GCRYCTL_FINALIZE: + md_final (hd); + break; + case GCRYCTL_START_DUMP: + md_start_debug (hd, buffer); + break; + case GCRYCTL_STOP_DUMP: + md_stop_debug ( hd ); + break; + default: + rc = GPG_ERR_INV_OP; + } + return rc; +} + + +gcry_err_code_t +_gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) +{ + gcry_err_code_t rc; + + if (hd->ctx->flags.hmac) + { + rc = prepare_macpads (hd, key, keylen); + if (!rc) + _gcry_md_reset (hd); + } + else + { + rc = md_setkey (hd, key, keylen); + } + + return rc; +} + + +/* The new debug interface. If SUFFIX is a string it creates an debug + file for the context HD. IF suffix is NULL, the file is closed and + debugging is stopped. */ +void +_gcry_md_debug (gcry_md_hd_t hd, const char *suffix) +{ + if (suffix) + md_start_debug (hd, suffix); + else + md_stop_debug (hd); +} + + +/**************** + * If ALGO is null get the digest for the used algo (which should be + * only one) + */ +static byte * +md_read( gcry_md_hd_t a, int algo ) +{ + GcryDigestEntry *r = a->ctx->list; + + if (! algo) + { + /* Return the first algorithm */ + if (r) + { + if (r->next) + log_debug ("more than one algorithm in md_read(0)\n"); + if (r->spec->read) + return r->spec->read (r->context); + } + } + else + { + for (r = a->ctx->list; r; r = r->next) + if (r->spec->algo == algo) + { + if (r->spec->read) + return r->spec->read (r->context); + break; + } + } + + if (r && !r->spec->read) + _gcry_fatal_error (GPG_ERR_DIGEST_ALGO, + "requested algo has no fixed digest length"); + else + _gcry_fatal_error (GPG_ERR_DIGEST_ALGO, "requested algo not in md context"); + return NULL; +} + + +/* + * Read out the complete digest, this function implictly finalizes + * the hash. + */ +byte * +_gcry_md_read (gcry_md_hd_t hd, int algo) +{ + /* This function is expected to always return a digest, thus we + can't return an error which we actually should do in + non-operational state. */ + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + return md_read (hd, algo); +} + + +/**************** + * If ALGO is null get the digest for the used algo (which should be + * only one) + */ +static gcry_err_code_t +md_extract(gcry_md_hd_t a, int algo, void *out, size_t outlen) +{ + GcryDigestEntry *r = a->ctx->list; + + if (!algo) + { + /* Return the first algorithm */ + if (r && r->spec->extract) + { + if (r->next) + log_debug ("more than one algorithm in md_extract(0)\n"); + r->spec->extract (r->context, out, outlen); + return 0; + } + } + else + { + for (r = a->ctx->list; r; r = r->next) + if (r->spec->algo == algo && r->spec->extract) + { + r->spec->extract (r->context, out, outlen); + return 0; + } + } + + return GPG_ERR_DIGEST_ALGO; +} + + +/* + * Expand the output from XOF class digest, this function implictly finalizes + * the hash. + */ +gcry_err_code_t +_gcry_md_extract (gcry_md_hd_t hd, int algo, void *out, size_t outlen) +{ + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + return md_extract (hd, algo, out, outlen); +} + + +/* + * Read out an intermediate digest. Not yet functional. + */ +gcry_err_code_t +_gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) +{ + (void)hd; + (void)algo; + (void)buffer; + (void)buflen; + + /*md_digest ... */ + fips_signal_error ("unimplemented function called"); + return GPG_ERR_INTERNAL; +} + + +/* + * Shortcut function to hash a buffer with a given algo. The only + * guaranteed supported algorithms are RIPE-MD160 and SHA-1. The + * supplied digest buffer must be large enough to store the resulting + * hash. No error is returned, the function will abort on an invalid + * algo. DISABLED_ALGOS are ignored here. */ +void +_gcry_md_hash_buffer (int algo, void *digest, + const void *buffer, size_t length) +{ + gcry_md_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec) + { + log_debug ("md_hash_buffer: algorithm %d not available\n", algo); + return; + } + + if (algo == GCRY_MD_MD5 && fips_mode ()) + { + _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { + /* We should never get to here because we do not register + MD5 in enforced fips mode. */ + _gcry_fips_noreturn (); + } + } + + if (spec->hash_buffer != NULL) + { + spec->hash_buffer (digest, buffer, length); + } + else if (spec->hash_buffers != NULL) + { + gcry_buffer_t iov; + + iov.size = 0; + iov.data = (void *)buffer; + iov.off = 0; + iov.len = length; + + spec->hash_buffers (digest, &iov, 1); + } + else + { + /* For the others we do not have a fast function, so we use the + normal functions. */ + gcry_md_hd_t h; + gpg_err_code_t err; + + err = md_open (&h, algo, 0); + if (err) + log_bug ("gcry_md_open failed for algo %d: %s", + algo, gpg_strerror (gcry_error(err))); + md_write (h, (byte *) buffer, length); + md_final (h); + memcpy (digest, md_read (h, algo), md_digest_length (algo)); + md_close (h); + } +} + + +/* Shortcut function to hash multiple buffers with a given algo. In + contrast to gcry_md_hash_buffer, this function returns an error on + invalid arguments or on other problems; disabled algorithms are + _not_ ignored but flagged as an error. + + The data to sign is taken from the array IOV which has IOVCNT items. + + The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns + this function into a HMAC function; the first item in IOV is then + used as the key. + + On success 0 is returned and resulting hash or HMAC is stored at + DIGEST which must have been provided by the caller with an + appropriate length. */ +gpg_err_code_t +_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, + const gcry_buffer_t *iov, int iovcnt) +{ + gcry_md_spec_t *spec; + int hmac; + + if (!iov || iovcnt < 0) + return GPG_ERR_INV_ARG; + if (flags & ~(GCRY_MD_FLAG_HMAC)) + return GPG_ERR_INV_ARG; + + hmac = !!(flags & GCRY_MD_FLAG_HMAC); + if (hmac && iovcnt < 1) + return GPG_ERR_INV_ARG; + + spec = spec_from_algo (algo); + if (!spec) + { + log_debug ("md_hash_buffers: algorithm %d not available\n", algo); + return GPG_ERR_DIGEST_ALGO; + } + + if (algo == GCRY_MD_MD5 && fips_mode ()) + { + _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { + /* We should never get to here because we do not register + MD5 in enforced fips mode. */ + _gcry_fips_noreturn (); + } + } + + if (!hmac && spec->hash_buffers) + { + spec->hash_buffers (digest, iov, iovcnt); + } + else + { + /* For the others we do not have a fast function, so we use the + normal functions. */ + gcry_md_hd_t h; + gpg_err_code_t rc; + int dlen; + + /* Detect SHAKE128 like algorithms which we can't use because + * our API does not allow for a variable length digest. */ + dlen = md_digest_length (algo); + if (!dlen) + return GPG_ERR_DIGEST_ALGO; + + rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0)); + if (rc) + return rc; + + if (hmac) + { + rc = _gcry_md_setkey (h, + (const char*)iov[0].data + iov[0].off, + iov[0].len); + if (rc) + { + md_close (h); + return rc; + } + iov++; iovcnt--; + } + for (;iovcnt; iov++, iovcnt--) + md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len); + md_final (h); + memcpy (digest, md_read (h, algo), dlen); + md_close (h); + } + + return 0; +} + + +static int +md_get_algo (gcry_md_hd_t a) +{ + GcryDigestEntry *r = a->ctx->list; + + if (r && r->next) + { + fips_signal_error ("possible usage error"); + log_error ("WARNING: more than one algorithm in md_get_algo()\n"); + } + return r ? r->spec->algo : 0; +} + + +int +_gcry_md_get_algo (gcry_md_hd_t hd) +{ + return md_get_algo (hd); +} + + +/**************** + * Return the length of the digest + */ +static int +md_digest_length (int algorithm) +{ + gcry_md_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec? spec->mdlen : 0; +} + + +/**************** + * Return the length of the digest in bytes. + * This function will return 0 in case of errors. + */ +unsigned int +_gcry_md_get_algo_dlen (int algorithm) +{ + return md_digest_length (algorithm); +} + + +/* Hmmm: add a mode to enumerate the OIDs + * to make g10/sig-check.c more portable */ +static const byte * +md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) +{ + gcry_md_spec_t *spec; + const byte *asnoid = NULL; + + spec = spec_from_algo (algorithm); + if (spec) + { + if (asnlen) + *asnlen = spec->asnlen; + if (mdlen) + *mdlen = spec->mdlen; + asnoid = spec->asnoid; + } + else + log_bug ("no ASN.1 OID for md algo %d\n", algorithm); + + return asnoid; +} + + +/**************** + * Return information about the given cipher algorithm + * WHAT select the kind of information returned: + * GCRYCTL_TEST_ALGO: + * Returns 0 when the specified algorithm is available for use. + * buffer and nbytes must be zero. + * GCRYCTL_GET_ASNOID: + * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only + * the required length is returned. + * GCRYCTL_SELFTEST + * Helper for the regression tests - shall not be used by applications. + * + * Note: Because this function is in most cases used to return an + * integer value, we can make it easier for the caller to just look at + * the return value. The caller will in all cases consult the value + * and thereby detecting whether a error occurred or not (i.e. while checking + * the block size) + */ +gcry_err_code_t +_gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) +{ + gcry_err_code_t rc; + + switch (what) + { + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + rc = GPG_ERR_INV_ARG; + else + rc = check_digest_algo (algo); + break; + + case GCRYCTL_GET_ASNOID: + /* We need to check that the algo is available because + md_asn_oid would otherwise raise an assertion. */ + rc = check_digest_algo (algo); + if (!rc) + { + const char unsigned *asn; + size_t asnlen; + + asn = md_asn_oid (algo, &asnlen, NULL); + if (buffer && (*nbytes >= asnlen)) + { + memcpy (buffer, asn, asnlen); + *nbytes = asnlen; + } + else if (!buffer && nbytes) + *nbytes = asnlen; + else + { + if (buffer) + rc = GPG_ERR_TOO_SHORT; + else + rc = GPG_ERR_INV_ARG; + } + } + break; + + case GCRYCTL_SELFTEST: + /* Helper function for the regression tests. */ + rc = gpg_err_code (_gcry_md_selftest (algo, nbytes? (int)*nbytes : 0, + NULL)); + break; + + default: + rc = GPG_ERR_INV_OP; + break; + } + + return rc; +} + + +static void +md_start_debug ( gcry_md_hd_t md, const char *suffix ) +{ + static int idx=0; + char buf[50]; + + if (fips_mode ()) + return; + + if ( md->ctx->debug ) + { + log_debug("Oops: md debug already started\n"); + return; + } + idx++; + snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix ); + md->ctx->debug = fopen(buf, "w"); + if ( !md->ctx->debug ) + log_debug("md debug: can't open %s\n", buf ); +} + + +static void +md_stop_debug( gcry_md_hd_t md ) +{ + if ( md->ctx->debug ) + { + if ( md->bufpos ) + md_write ( md, NULL, 0 ); + fclose (md->ctx->debug); + md->ctx->debug = NULL; + } + + { /* a kludge to pull in the __muldi3 for Solaris */ + volatile u32 a = (u32)(uintptr_t)md; + volatile u64 b = 42; + volatile u64 c; + c = a * b; + (void)c; + } +} + + + +/* + * Return information about the digest handle. + * GCRYCTL_IS_SECURE: + * Returns 1 when the handle works on secured memory + * otherwise 0 is returned. There is no error return. + * GCRYCTL_IS_ALGO_ENABLED: + * Returns 1 if the algo is enabled for that handle. + * The algo must be passed as the address of an int. + */ +gcry_err_code_t +_gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) +{ + gcry_err_code_t rc = 0; + + switch (cmd) + { + case GCRYCTL_IS_SECURE: + *nbytes = h->ctx->flags.secure; + break; + + case GCRYCTL_IS_ALGO_ENABLED: + { + GcryDigestEntry *r; + int algo; + + if ( !buffer || !nbytes || *nbytes != sizeof (int)) + rc = GPG_ERR_INV_ARG; + else + { + algo = *(int*)buffer; + + *nbytes = 0; + for(r=h->ctx->list; r; r = r->next ) { + if (r->spec->algo == algo) + { + *nbytes = 1; + break; + } + } + } + break; + } + + default: + rc = GPG_ERR_INV_OP; + } + + return rc; +} + + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_md_init (void) +{ + if (fips_mode()) + { + /* disable algorithms that are disallowed in fips */ + int idx; + gcry_md_spec_t *spec; + + for (idx = 0; (spec = digest_list[idx]); idx++) + if (!spec->flags.fips) + spec->flags.disabled = 1; + } + + return 0; +} + + +int +_gcry_md_is_secure (gcry_md_hd_t a) +{ + size_t value; + + if (_gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value)) + value = 1; /* It seems to be better to assume secure memory on + error. */ + return value; +} + + +int +_gcry_md_is_enabled (gcry_md_hd_t a, int algo) +{ + size_t value; + + value = sizeof algo; + if (_gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) + value = 0; + return value; +} + + +/* Run the selftests for digest algorithm ALGO with optional reporting + function REPORT. */ +gpg_error_t +_gcry_md_selftest (int algo, int extended, selftest_report_func_t report) +{ + gcry_err_code_t ec = 0; + gcry_md_spec_t *spec; + + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); + else + { + ec = (spec && spec->selftest) ? GPG_ERR_DIGEST_ALGO + /* */ : GPG_ERR_NOT_IMPLEMENTED; + if (report) + report ("digest", algo, "module", + (spec && !spec->flags.disabled)? + "no selftest available" : + spec? "algorithm disabled" : "algorithm not found"); + } + + return gpg_error (ec); +} diff --git a/comm/third_party/libgcrypt/cipher/md4.c b/comm/third_party/libgcrypt/cipher/md4.c new file mode 100644 index 0000000000..b55443a8aa --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/md4.c @@ -0,0 +1,296 @@ +/* md4.c - MD4 Message-Digest Algorithm + * Copyright (C) 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * Based on md5.c in libgcrypt, but rewritten to compute md4 checksums + * using a public domain md4 implementation with the following comments: + * + * Modified by Wei Dai from Andrew M. Kuchling's md4.c + * The original code and all modifications are in the public domain. + * + * This is the original introductory comment: + * + * md4.c : MD4 hash algorithm. + * + * Part of the Python Cryptography Toolkit, version 1.1 + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + */ + +/* MD4 test suite: + * MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0 + * MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24 + * MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d + * MD4 ("message digest") = d9130a8164549fe818874806e1c7014b + * MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 + * MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = + * 043f8582f241db351ce627e153e7f0e4 + * MD4 ("123456789012345678901234567890123456789012345678901234567890123456 + * 78901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" + +#include "bithelp.h" +#include "bufhelp.h" +#include "hash-common.h" + + +typedef struct { + gcry_md_block_ctx_t bctx; + u32 A,B,C,D; /* chaining variables */ +} MD4_CONTEXT; + +static unsigned int +transform ( void *c, const unsigned char *data, size_t nblks ); + +static void +md4_init (void *context, unsigned int flags) +{ + MD4_CONTEXT *ctx = context; + + (void)flags; + + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize_shift = _gcry_ctz(64); + ctx->bctx.bwrite = transform; +} + +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + + +/**************** + * transform 64 bytes + */ +static unsigned int +transform_blk ( void *c, const unsigned char *data ) +{ + MD4_CONTEXT *ctx = c; + u32 in[16]; + register u32 A = ctx->A; + register u32 B = ctx->B; + register u32 C = ctx->C; + register u32 D = ctx->D; + int i; + + for ( i = 0; i < 16; i++ ) + in[i] = buf_get_le32(data + i * 4); + + /* Round 1. */ +#define function(a,b,c,d,k,s) a=rol(a+F(b,c,d)+in[k],s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 1, 7); + function(C,D,A,B, 2,11); + function(B,C,D,A, 3,19); + function(A,B,C,D, 4, 3); + function(D,A,B,C, 5, 7); + function(C,D,A,B, 6,11); + function(B,C,D,A, 7,19); + function(A,B,C,D, 8, 3); + function(D,A,B,C, 9, 7); + function(C,D,A,B,10,11); + function(B,C,D,A,11,19); + function(A,B,C,D,12, 3); + function(D,A,B,C,13, 7); + function(C,D,A,B,14,11); + function(B,C,D,A,15,19); + +#undef function + + /* Round 2. */ +#define function(a,b,c,d,k,s) a=rol(a+G(b,c,d)+in[k]+0x5a827999,s); + + function(A,B,C,D, 0, 3); + function(D,A,B,C, 4, 5); + function(C,D,A,B, 8, 9); + function(B,C,D,A,12,13); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 5, 5); + function(C,D,A,B, 9, 9); + function(B,C,D,A,13,13); + function(A,B,C,D, 2, 3); + function(D,A,B,C, 6, 5); + function(C,D,A,B,10, 9); + function(B,C,D,A,14,13); + function(A,B,C,D, 3, 3); + function(D,A,B,C, 7, 5); + function(C,D,A,B,11, 9); + function(B,C,D,A,15,13); + +#undef function + + /* Round 3. */ +#define function(a,b,c,d,k,s) a=rol(a+H(b,c,d)+in[k]+0x6ed9eba1,s); + + function(A,B,C,D, 0, 3); + function(D,A,B,C, 8, 9); + function(C,D,A,B, 4,11); + function(B,C,D,A,12,15); + function(A,B,C,D, 2, 3); + function(D,A,B,C,10, 9); + function(C,D,A,B, 6,11); + function(B,C,D,A,14,15); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 9, 9); + function(C,D,A,B, 5,11); + function(B,C,D,A,13,15); + function(A,B,C,D, 3, 3); + function(D,A,B,C,11, 9); + function(C,D,A,B, 7,11); + function(B,C,D,A,15,15); + + + /* Put checksum in context given as argument. */ + ctx->A += A; + ctx->B += B; + ctx->C += C; + ctx->D += D; + + return /*burn_stack*/ 80+6*sizeof(void*); +} + + +static unsigned int +transform ( void *c, const unsigned char *data, size_t nblks ) +{ + unsigned int burn; + + do + { + burn = transform_blk (c, data); + data += 64; + } + while (--nblks); + + return burn; +} + + +/* The routine final terminates the message-digest computation and + * ends with the desired message digest in mdContext->digest[0...15]. + * The handle is prepared for a new MD4 cycle. + * Returns 16 bytes representing the digest. + */ + +static void +md4_final( void *context ) +{ + MD4_CONTEXT *hd = context; + u32 t, th, msb, lsb; + byte *p; + unsigned int burn; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; + + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = (th << 6) | (t >> 26); + /* add the count */ + t = lsb; + if( (lsb += hd->bctx.count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if (hd->bctx.count < 56) /* enough room */ + { + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + if (hd->bctx.count < 56) + memset (&hd->bctx.buf[hd->bctx.count], 0, 56 - hd->bctx.count); + + /* append the 64 bit count */ + buf_put_le32(hd->bctx.buf + 56, lsb); + buf_put_le32(hd->bctx.buf + 60, msb); + burn = transform (hd, hd->bctx.buf, 1); + } + else /* need one extra block */ + { + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + /* fill pad and next block with zeroes */ + memset (&hd->bctx.buf[hd->bctx.count], 0, 64 - hd->bctx.count + 56); + + /* append the 64 bit count */ + buf_put_le32(hd->bctx.buf + 64 + 56, lsb); + buf_put_le32(hd->bctx.buf + 64 + 60, msb); + burn = transform (hd, hd->bctx.buf, 2); + } + + p = hd->bctx.buf; +#define X(a) do { buf_put_le32(p, hd->a); p += 4; } while(0) + X(A); + X(B); + X(C); + X(D); +#undef X + + hd->bctx.count = 0; + + _gcry_burn_stack (burn); +} + +static byte * +md4_read (void *context) +{ + MD4_CONTEXT *hd = context; + return hd->bctx.buf; +} + +static byte asn[18] = /* Object ID is 1.2.840.113549.2.4 */ + { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x04, 0x05, 0x00, 0x04, 0x10 }; + +static gcry_md_oid_spec_t oid_spec_md4[] = + { + /* iso.member-body.us.rsadsi.digestAlgorithm.md4 */ + { "1.2.840.113549.2.4" }, + { NULL }, + }; + +gcry_md_spec_t _gcry_digest_spec_md4 = + { + GCRY_MD_MD4, {0, 0}, + "MD4", asn, DIM (asn), oid_spec_md4,16, + md4_init, _gcry_md_block_write, md4_final, md4_read, NULL, + NULL, NULL, + sizeof (MD4_CONTEXT) + }; diff --git a/comm/third_party/libgcrypt/cipher/md5.c b/comm/third_party/libgcrypt/cipher/md5.c new file mode 100644 index 0000000000..32cb535aaa --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/md5.c @@ -0,0 +1,322 @@ +/* md5.c - MD5 Message-Digest Algorithm + * Copyright (C) 1995,1996,1998,1999,2001,2002, + * 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * According to the definition of MD5 in RFC 1321 from April 1992. + * NOTE: This is *not* the same file as the one from glibc. + * Written by Ulrich Drepper , 1995. + * heavily modified for GnuPG by Werner Koch + */ + +/* Test values: + * "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E + * "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61 + * "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72 + * "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0 + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "cipher.h" + +#include "bithelp.h" +#include "bufhelp.h" +#include "hash-common.h" + + +typedef struct { + gcry_md_block_ctx_t bctx; + u32 A,B,C,D; /* chaining variables */ +} MD5_CONTEXT; + +static unsigned int +transform ( void *ctx, const unsigned char *data, size_t datalen ); + +static void +md5_init( void *context, unsigned int flags) +{ + MD5_CONTEXT *ctx = context; + + (void)flags; + + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize_shift = _gcry_ctz(64); + ctx->bctx.bwrite = transform; +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + + +/**************** + * transform 64 bytes + */ +static unsigned int +transform_blk ( void *c, const unsigned char *data ) +{ + MD5_CONTEXT *ctx = c; + u32 correct_words[16]; + register u32 A = ctx->A; + register u32 B = ctx->B; + register u32 C = ctx->C; + register u32 D = ctx->D; + u32 *cwp = correct_words; + int i; + + for ( i = 0; i < 16; i++ ) + correct_words[i] = buf_get_le32(data + i * 4); + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++) + T; \ + a = rol(a, s); \ + a += b; \ + } \ + while (0) + + /* Before we start, one word about the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + a = rol(a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Put checksum in context given as argument. */ + ctx->A += A; + ctx->B += B; + ctx->C += C; + ctx->D += D; + + return /*burn_stack*/ 80+6*sizeof(void*); +} + + +static unsigned int +transform ( void *c, const unsigned char *data, size_t nblks ) +{ + unsigned int burn; + + do + { + burn = transform_blk (c, data); + data += 64; + } + while (--nblks); + + return burn; +} + + +/* The routine final terminates the message-digest computation and + * ends with the desired message digest in mdContext->digest[0...15]. + * The handle is prepared for a new MD5 cycle. + * Returns 16 bytes representing the digest. + */ + +static void +md5_final( void *context) +{ + MD5_CONTEXT *hd = context; + u32 t, th, msb, lsb; + byte *p; + unsigned int burn; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; + + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = (th << 6) | (t >> 26); + /* add the count */ + t = lsb; + if( (lsb += hd->bctx.count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if (hd->bctx.count < 56) /* enough room */ + { + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + if (hd->bctx.count < 56) + memset (&hd->bctx.buf[hd->bctx.count], 0, 56 - hd->bctx.count); + + /* append the 64 bit count */ + buf_put_le32(hd->bctx.buf + 56, lsb); + buf_put_le32(hd->bctx.buf + 60, msb); + burn = transform (hd, hd->bctx.buf, 1); + } + else /* need one extra block */ + { + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + /* fill pad and next block with zeroes */ + memset (&hd->bctx.buf[hd->bctx.count], 0, 64 - hd->bctx.count + 56); + + /* append the 64 bit count */ + buf_put_le32(hd->bctx.buf + 64 + 56, lsb); + buf_put_le32(hd->bctx.buf + 64 + 60, msb); + burn = transform (hd, hd->bctx.buf, 2); + } + + p = hd->bctx.buf; +#define X(a) do { buf_put_le32(p, hd->a); p += 4; } while(0) + X(A); + X(B); + X(C); + X(D); +#undef X + + hd->bctx.count = 0; + + _gcry_burn_stack (burn); +} + +static byte * +md5_read( void *context ) +{ + MD5_CONTEXT *hd = (MD5_CONTEXT *) context; + return hd->bctx.buf; +} + +static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 */ + { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + +static gcry_md_oid_spec_t oid_spec_md5[] = + { + /* iso.member-body.us.rsadsi.pkcs.pkcs-1.4 (md5WithRSAEncryption) */ + { "1.2.840.113549.1.1.4" }, + /* RSADSI digestAlgorithm MD5 */ + { "1.2.840.113549.2.5" }, + { NULL }, + }; + +gcry_md_spec_t _gcry_digest_spec_md5 = + { + GCRY_MD_MD5, {0, 0}, + "MD5", asn, DIM (asn), oid_spec_md5, 16, + md5_init, _gcry_md_block_write, md5_final, md5_read, NULL, + NULL, NULL, + sizeof (MD5_CONTEXT) + }; diff --git a/comm/third_party/libgcrypt/cipher/poly1305-internal.h b/comm/third_party/libgcrypt/cipher/poly1305-internal.h new file mode 100644 index 0000000000..19cee5f6f3 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/poly1305-internal.h @@ -0,0 +1,64 @@ +/* poly1305-internal.h - Poly1305 internals + * Copyright (C) 2014 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef G10_POLY1305_INTERNAL_H +#define G10_POLY1305_INTERNAL_H + +#include +#include +#include +#include +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" + +#define POLY1305_TAGLEN 16 +#define POLY1305_KEYLEN 32 +#define POLY1305_BLOCKSIZE 16 + + +typedef struct +{ + u32 k[4]; + u32 r[4]; + u32 h[5]; +} POLY1305_STATE; + +typedef struct poly1305_context_s +{ + POLY1305_STATE state; + byte buffer[POLY1305_BLOCKSIZE]; + unsigned int leftover; +} poly1305_context_t; + + +gcry_err_code_t _gcry_poly1305_init (poly1305_context_t *ctx, const byte *key, + size_t keylen); + +void _gcry_poly1305_finish (poly1305_context_t *ctx, + byte mac[POLY1305_TAGLEN]); + +void _gcry_poly1305_update (poly1305_context_t *ctx, const byte *buf, + size_t buflen); + +unsigned int _gcry_poly1305_update_burn (poly1305_context_t *ctx, + const byte *m, size_t bytes); + +#endif /* G10_POLY1305_INTERNAL_H */ diff --git a/comm/third_party/libgcrypt/cipher/poly1305-s390x.S b/comm/third_party/libgcrypt/cipher/poly1305-s390x.S new file mode 100644 index 0000000000..844245f6ad --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/poly1305-s390x.S @@ -0,0 +1,87 @@ +/* poly1305-s390x.S - zSeries implementation of Poly1305 + * + * Copyright (C) 2020 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#if defined (__s390x__) && __GNUC__ >= 4 && __ARCH__ >= 9 +#include +#if defined(HAVE_GCC_INLINE_ASM_S390X) + +#include "asm-poly1305-s390x.h" + +.text + +.balign 8 +.globl _gcry_poly1305_s390x_blocks1 +ELF(.type _gcry_poly1305_s390x_blocks1,@function;) + +_gcry_poly1305_s390x_blocks1: + /* input: + * %r2: poly1305-state + * %r3: src + * %r4: len + * %r5: high_pad + */ + CFI_STARTPROC(); + + stmg %r6, %r14, 6 * 8(%r15); + + lgr POLY_RSTATE, %r2; + lgr POLY_RSRC, %r3; + srlg %r0, %r4, 4; + + cgije %r5, 0, .Lpoly_high0; + + POLY1305_LOAD_STATE(); + +.balign 4 +.Lpoly_loop_high1: + POLY1305_BLOCK_PART1(0 * 16); + INC_POLY1305_SRC(1 * 16); +.Lpoly_block_part2: + POLY1305_BLOCK_PART2(); + POLY1305_BLOCK_PART3(); + POLY1305_BLOCK_PART4(); + POLY1305_BLOCK_PART5(); + POLY1305_BLOCK_PART6(); + POLY1305_BLOCK_PART7(); + POLY1305_BLOCK_PART8(); + + brctg %r0, .Lpoly_loop_high1; + +.balign 4 +.Lpoly_done: + POLY1305_STORE_STATE(); + + lmg %r6, %r14, 6 * 8(%r15); + xgr %r2, %r2; + br %r14; + +.balign 4 +.Lpoly_high0: + lghi %r0, 1; + POLY1305_LOAD_STATE(); + POLY1305_BLOCK_PART1_HB(0 * 16, 0); + j .Lpoly_block_part2; + + CFI_ENDPROC(); +ELF(.size _gcry_poly1305_s390x_blocks1, + .-_gcry_poly1305_s390x_blocks1;) + +#endif /*HAVE_GCC_INLINE_ASM_S390X*/ +#endif /*__s390x__*/ diff --git a/comm/third_party/libgcrypt/cipher/poly1305.c b/comm/third_party/libgcrypt/cipher/poly1305.c new file mode 100644 index 0000000000..6cb4d2b72d --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/poly1305.c @@ -0,0 +1,740 @@ +/* poly1305.c - Poly1305 internals and generic implementation + * Copyright (C) 2014,2017,2018 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "poly1305-internal.h" + +#include "mpi-internal.h" +#include "longlong.h" + + +static const char *selftest (void); + + +#undef HAVE_ASM_POLY1305_BLOCKS + + +#undef USE_MPI_64BIT +#undef USE_MPI_32BIT +#if BYTES_PER_MPI_LIMB == 8 && defined(HAVE_TYPE_U64) +# define USE_MPI_64BIT 1 +#elif BYTES_PER_MPI_LIMB == 4 +# define USE_MPI_32BIT 1 +#else +# error please implement for this limb size. +#endif + + +/* USE_S390X_ASM indicates whether to enable zSeries code. */ +#undef USE_S390X_ASM +#if BYTES_PER_MPI_LIMB == 8 +# if defined (__s390x__) && __GNUC__ >= 4 && __ARCH__ >= 9 +# if defined(HAVE_GCC_INLINE_ASM_S390X) +# define USE_S390X_ASM 1 +# endif /* USE_S390X_ASM */ +# endif +#endif + + +#ifdef USE_S390X_ASM + +#define HAVE_ASM_POLY1305_BLOCKS 1 + +extern unsigned int _gcry_poly1305_s390x_blocks1(void *state, + const byte *buf, size_t len, + byte high_pad); + +static unsigned int +poly1305_blocks (poly1305_context_t *ctx, const byte *buf, size_t len, + byte high_pad) +{ + return _gcry_poly1305_s390x_blocks1(&ctx->state, buf, len, high_pad); +} + +#endif /* USE_S390X_ASM */ + + +static void poly1305_init (poly1305_context_t *ctx, + const byte key[POLY1305_KEYLEN]) +{ + POLY1305_STATE *st = &ctx->state; + + ctx->leftover = 0; + + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + st->r[0] = buf_get_le32(key + 0) & 0x0fffffff; + st->r[1] = buf_get_le32(key + 4) & 0x0ffffffc; + st->r[2] = buf_get_le32(key + 8) & 0x0ffffffc; + st->r[3] = buf_get_le32(key + 12) & 0x0ffffffc; + + st->k[0] = buf_get_le32(key + 16); + st->k[1] = buf_get_le32(key + 20); + st->k[2] = buf_get_le32(key + 24); + st->k[3] = buf_get_le32(key + 28); +} + + +#ifdef USE_MPI_64BIT + +#if defined (__aarch64__) && __GNUC__ >= 4 + +/* A += B (armv8/aarch64) */ +#define ADD_1305_64(A2, A1, A0, B2, B1, B0) \ + __asm__ ("adds %0, %3, %0\n" \ + "adcs %1, %4, %1\n" \ + "adc %2, %5, %2\n" \ + : "+r" (A0), "+r" (A1), "+r" (A2) \ + : "r" (B0), "r" (B1), "r" (B2) \ + : "cc" ) + +#endif /* __aarch64__ */ + +#if defined (__x86_64__) && __GNUC__ >= 4 + +/* A += B (x86-64) */ +#define ADD_1305_64(A2, A1, A0, B2, B1, B0) \ + __asm__ ("addq %3, %0\n" \ + "adcq %4, %1\n" \ + "adcq %5, %2\n" \ + : "+r" (A0), "+r" (A1), "+r" (A2) \ + : "g" (B0), "g" (B1), "g" (B2) \ + : "cc" ) + +#endif /* __x86_64__ */ + +#if defined (__powerpc__) && __GNUC__ >= 4 + +/* A += B (ppc64) */ +#define ADD_1305_64(A2, A1, A0, B2, B1, B0) \ + __asm__ ("addc %0, %3, %0\n" \ + "adde %1, %4, %1\n" \ + "adde %2, %5, %2\n" \ + : "+r" (A0), "+r" (A1), "+r" (A2) \ + : "r" (B0), "r" (B1), "r" (B2) \ + : "cc" ) + +#endif /* __powerpc__ */ + +#ifndef ADD_1305_64 +/* A += B (generic, mpi) */ +# define ADD_1305_64(A2, A1, A0, B2, B1, B0) do { \ + u64 carry; \ + add_ssaaaa(carry, A0, 0, A0, 0, B0); \ + add_ssaaaa(A2, A1, A2, A1, B2, B1); \ + add_ssaaaa(A2, A1, A2, A1, 0, carry); \ + } while (0) +#endif + +/* H = H * R mod 2¹³â°-5 */ +#define MUL_MOD_1305_64(H2, H1, H0, R1, R0, R1_MULT5) do { \ + u64 x0_lo, x0_hi, x1_lo, x1_hi; \ + u64 t0_lo, t0_hi, t1_lo, t1_hi; \ + \ + /* x = a * r (partial mod 2^130-5) */ \ + umul_ppmm(x0_hi, x0_lo, H0, R0); /* h0 * r0 */ \ + umul_ppmm(x1_hi, x1_lo, H0, R1); /* h0 * r1 */ \ + \ + umul_ppmm(t0_hi, t0_lo, H1, R1_MULT5); /* h1 * r1 mod 2^130-5 */ \ + add_ssaaaa(x0_hi, x0_lo, x0_hi, x0_lo, t0_hi, t0_lo); \ + umul_ppmm(t1_hi, t1_lo, H1, R0); /* h1 * r0 */ \ + add_ssaaaa(x1_hi, x1_lo, x1_hi, x1_lo, t1_hi, t1_lo); \ + \ + t1_lo = H2 * R1_MULT5; /* h2 * r1 mod 2^130-5 */ \ + t1_hi = H2 * R0; /* h2 * r0 */ \ + add_ssaaaa(H0, H1, x1_hi, x1_lo, t1_hi, t1_lo); \ + \ + /* carry propagation */ \ + H2 = H0 & 3; \ + H0 = (H0 >> 2) * 5; /* msb mod 2^130-5 */ \ + ADD_1305_64(H2, H1, H0, (u64)0, x0_hi, x0_lo); \ + } while (0) + +#ifndef HAVE_ASM_POLY1305_BLOCKS + +static unsigned int +poly1305_blocks (poly1305_context_t *ctx, const byte *buf, size_t len, + byte high_pad) +{ + POLY1305_STATE *st = &ctx->state; + u64 r0, r1, r1_mult5; + u64 h0, h1, h2; + u64 m0, m1, m2; + + m2 = high_pad; + + h0 = st->h[0] + ((u64)st->h[1] << 32); + h1 = st->h[2] + ((u64)st->h[3] << 32); + h2 = st->h[4]; + + r0 = st->r[0] + ((u64)st->r[1] << 32); + r1 = st->r[2] + ((u64)st->r[3] << 32); + + r1_mult5 = (r1 >> 2) + r1; + + m0 = buf_get_le64(buf + 0); + m1 = buf_get_le64(buf + 8); + buf += POLY1305_BLOCKSIZE; + len -= POLY1305_BLOCKSIZE; + + while (len >= POLY1305_BLOCKSIZE) + { + /* a = h + m */ + ADD_1305_64(h2, h1, h0, m2, m1, m0); + + m0 = buf_get_le64(buf + 0); + m1 = buf_get_le64(buf + 8); + + /* h = a * r (partial mod 2^130-5) */ + MUL_MOD_1305_64(h2, h1, h0, r1, r0, r1_mult5); + + buf += POLY1305_BLOCKSIZE; + len -= POLY1305_BLOCKSIZE; + } + + /* a = h + m */ + ADD_1305_64(h2, h1, h0, m2, m1, m0); + + /* h = a * r (partial mod 2^130-5) */ + MUL_MOD_1305_64(h2, h1, h0, r1, r0, r1_mult5); + + st->h[0] = h0; + st->h[1] = h0 >> 32; + st->h[2] = h1; + st->h[3] = h1 >> 32; + st->h[4] = h2; + + return 6 * sizeof (void *) + 18 * sizeof (u64); +} + +#endif /* !HAVE_ASM_POLY1305_BLOCKS */ + +static unsigned int poly1305_final (poly1305_context_t *ctx, + byte mac[POLY1305_TAGLEN]) +{ + POLY1305_STATE *st = &ctx->state; + unsigned int burn = 0; + u64 u, carry; + u64 k0, k1; + u64 h0, h1; + u64 h2; + + /* process the remaining block */ + if (ctx->leftover) + { + ctx->buffer[ctx->leftover++] = 1; + if (ctx->leftover < POLY1305_BLOCKSIZE) + { + memset (&ctx->buffer[ctx->leftover], 0, + POLY1305_BLOCKSIZE - ctx->leftover); + ctx->leftover = POLY1305_BLOCKSIZE; + } + burn = poly1305_blocks (ctx, ctx->buffer, POLY1305_BLOCKSIZE, 0); + } + + h0 = st->h[0] + ((u64)st->h[1] << 32); + h1 = st->h[2] + ((u64)st->h[3] << 32); + h2 = st->h[4]; + + k0 = st->k[0] + ((u64)st->k[1] << 32); + k1 = st->k[2] + ((u64)st->k[3] << 32); + + /* check if h is more than 2^130-5, by adding 5. */ + add_ssaaaa(carry, u, 0, h0, 0, 5); + add_ssaaaa(carry, u, 0, carry, 0, h1); + u = (carry + h2) >> 2; /* u == 0 or 1 */ + + /* minus 2^130-5 ... (+5) */ + u = (-u) & 5; + add_ssaaaa(h1, h0, h1, h0, 0, u); + + /* add high part of key + h */ + add_ssaaaa(h1, h0, h1, h0, k1, k0); + buf_put_le64(mac + 0, h0); + buf_put_le64(mac + 8, h1); + + /* burn_stack */ + return 4 * sizeof (void *) + 7 * sizeof (u64) + burn; +} + +#endif /* USE_MPI_64BIT */ + +#ifdef USE_MPI_32BIT + +#ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS + +/* HI:LO += A * B (arm) */ +#define UMUL_ADD_32(HI, LO, A, B) \ + __asm__ ("umlal %1, %0, %4, %5" \ + : "=r" (HI), "=r" (LO) \ + : "0" (HI), "1" (LO), "r" (A), "r" (B) ) + +/* A += B (arm) */ +#define ADD_1305_32(A4, A3, A2, A1, A0, B4, B3, B2, B1, B0) \ + __asm__ ("adds %0, %0, %5\n" \ + "adcs %1, %1, %6\n" \ + "adcs %2, %2, %7\n" \ + "adcs %3, %3, %8\n" \ + "adc %4, %4, %9\n" \ + : "+r" (A0), "+r" (A1), "+r" (A2), "+r" (A3), "+r" (A4) \ + : "r" (B0), "r" (B1), "r" (B2), "r" (B3), "r" (B4) \ + : "cc" ) + +#endif /* HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS */ + +#if defined (__i386__) && __GNUC__ >= 4 + +/* A += B (i386) */ +#define ADD_1305_32(A4, A3, A2, A1, A0, B4, B3, B2, B1, B0) \ + __asm__ ("addl %5, %0\n" \ + "adcl %6, %1\n" \ + "adcl %7, %2\n" \ + "adcl %8, %3\n" \ + "adcl %9, %4\n" \ + : "+r" (A0), "+r" (A1), "+r" (A2), "+r" (A3), "+r" (A4) \ + : "g" (B0), "g" (B1), "g" (B2), "g" (B3), "g" (B4) \ + : "cc" ) + +#endif /* __i386__ */ + +#ifndef UMUL_ADD_32 +/* HI:LO += A * B (generic, mpi) */ +# define UMUL_ADD_32(HI, LO, A, B) do { \ + u32 t_lo, t_hi; \ + umul_ppmm(t_hi, t_lo, A, B); \ + add_ssaaaa(HI, LO, HI, LO, t_hi, t_lo); \ + } while (0) +#endif + +#ifndef ADD_1305_32 +/* A += B (generic, mpi) */ +# define ADD_1305_32(A4, A3, A2, A1, A0, B4, B3, B2, B1, B0) do { \ + u32 carry0, carry1, carry2; \ + add_ssaaaa(carry0, A0, 0, A0, 0, B0); \ + add_ssaaaa(carry1, A1, 0, A1, 0, B1); \ + add_ssaaaa(carry1, A1, carry1, A1, 0, carry0); \ + add_ssaaaa(carry2, A2, 0, A2, 0, B2); \ + add_ssaaaa(carry2, A2, carry2, A2, 0, carry1); \ + add_ssaaaa(A4, A3, A4, A3, B4, B3); \ + add_ssaaaa(A4, A3, A4, A3, 0, carry2); \ + } while (0) +#endif + +/* H = H * R mod 2¹³â°-5 */ +#define MUL_MOD_1305_32(H4, H3, H2, H1, H0, R3, R2, R1, R0, \ + R3_MULT5, R2_MULT5, R1_MULT5) do { \ + u32 x0_lo, x0_hi, x1_lo, x1_hi, x2_lo, x2_hi, x3_lo, x3_hi; \ + u32 t0_lo, t0_hi; \ + \ + /* x = a * r (partial mod 2^130-5) */ \ + umul_ppmm(x0_hi, x0_lo, H0, R0); /* h0 * r0 */ \ + umul_ppmm(x1_hi, x1_lo, H0, R1); /* h0 * r1 */ \ + umul_ppmm(x2_hi, x2_lo, H0, R2); /* h0 * r2 */ \ + umul_ppmm(x3_hi, x3_lo, H0, R3); /* h0 * r3 */ \ + \ + UMUL_ADD_32(x0_hi, x0_lo, H1, R3_MULT5); /* h1 * r3 mod 2^130-5 */ \ + UMUL_ADD_32(x1_hi, x1_lo, H1, R0); /* h1 * r0 */ \ + UMUL_ADD_32(x2_hi, x2_lo, H1, R1); /* h1 * r1 */ \ + UMUL_ADD_32(x3_hi, x3_lo, H1, R2); /* h1 * r2 */ \ + \ + UMUL_ADD_32(x0_hi, x0_lo, H2, R2_MULT5); /* h2 * r2 mod 2^130-5 */ \ + UMUL_ADD_32(x1_hi, x1_lo, H2, R3_MULT5); /* h2 * r3 mod 2^130-5 */ \ + UMUL_ADD_32(x2_hi, x2_lo, H2, R0); /* h2 * r0 */ \ + UMUL_ADD_32(x3_hi, x3_lo, H2, R1); /* h2 * r1 */ \ + \ + UMUL_ADD_32(x0_hi, x0_lo, H3, R1_MULT5); /* h3 * r1 mod 2^130-5 */ \ + H1 = x0_hi; \ + UMUL_ADD_32(x1_hi, x1_lo, H3, R2_MULT5); /* h3 * r2 mod 2^130-5 */ \ + UMUL_ADD_32(x2_hi, x2_lo, H3, R3_MULT5); /* h3 * r3 mod 2^130-5 */ \ + UMUL_ADD_32(x3_hi, x3_lo, H3, R0); /* h3 * r0 */ \ + \ + t0_lo = H4 * R1_MULT5; /* h4 * r1 mod 2^130-5 */ \ + t0_hi = H4 * R2_MULT5; /* h4 * r2 mod 2^130-5 */ \ + add_ssaaaa(H2, x1_lo, x1_hi, x1_lo, 0, t0_lo); \ + add_ssaaaa(H3, x2_lo, x2_hi, x2_lo, 0, t0_hi); \ + t0_lo = H4 * R3_MULT5; /* h4 * r3 mod 2^130-5 */ \ + t0_hi = H4 * R0; /* h4 * r0 */ \ + add_ssaaaa(H4, x3_lo, x3_hi, x3_lo, t0_hi, t0_lo); \ + \ + /* carry propagation */ \ + H0 = (H4 >> 2) * 5; /* msb mod 2^130-5 */ \ + H4 = H4 & 3; \ + ADD_1305_32(H4, H3, H2, H1, H0, 0, x3_lo, x2_lo, x1_lo, x0_lo); \ + } while (0) + +#ifndef HAVE_ASM_POLY1305_BLOCKS + +static unsigned int +poly1305_blocks (poly1305_context_t *ctx, const byte *buf, size_t len, + byte high_pad) +{ + POLY1305_STATE *st = &ctx->state; + u32 r1_mult5, r2_mult5, r3_mult5; + u32 h0, h1, h2, h3, h4; + u32 m0, m1, m2, m3, m4; + + m4 = high_pad; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + r1_mult5 = (st->r[1] >> 2) + st->r[1]; + r2_mult5 = (st->r[2] >> 2) + st->r[2]; + r3_mult5 = (st->r[3] >> 2) + st->r[3]; + + while (len >= POLY1305_BLOCKSIZE) + { + m0 = buf_get_le32(buf + 0); + m1 = buf_get_le32(buf + 4); + m2 = buf_get_le32(buf + 8); + m3 = buf_get_le32(buf + 12); + + /* a = h + m */ + ADD_1305_32(h4, h3, h2, h1, h0, m4, m3, m2, m1, m0); + + /* h = a * r (partial mod 2^130-5) */ + MUL_MOD_1305_32(h4, h3, h2, h1, h0, + st->r[3], st->r[2], st->r[1], st->r[0], + r3_mult5, r2_mult5, r1_mult5); + + buf += POLY1305_BLOCKSIZE; + len -= POLY1305_BLOCKSIZE; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; + + return 6 * sizeof (void *) + 28 * sizeof (u32); +} + +#endif /* !HAVE_ASM_POLY1305_BLOCKS */ + +static unsigned int poly1305_final (poly1305_context_t *ctx, + byte mac[POLY1305_TAGLEN]) +{ + POLY1305_STATE *st = &ctx->state; + unsigned int burn = 0; + u32 carry, tmp0, tmp1, tmp2, u; + u32 h4, h3, h2, h1, h0; + + /* process the remaining block */ + if (ctx->leftover) + { + ctx->buffer[ctx->leftover++] = 1; + if (ctx->leftover < POLY1305_BLOCKSIZE) + { + memset (&ctx->buffer[ctx->leftover], 0, + POLY1305_BLOCKSIZE - ctx->leftover); + ctx->leftover = POLY1305_BLOCKSIZE; + } + burn = poly1305_blocks (ctx, ctx->buffer, POLY1305_BLOCKSIZE, 0); + } + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + /* check if h is more than 2^130-5, by adding 5. */ + add_ssaaaa(carry, tmp0, 0, h0, 0, 5); + add_ssaaaa(carry, tmp0, 0, carry, 0, h1); + add_ssaaaa(carry, tmp0, 0, carry, 0, h2); + add_ssaaaa(carry, tmp0, 0, carry, 0, h3); + u = (carry + h4) >> 2; /* u == 0 or 1 */ + + /* minus 2^130-5 ... (+5) */ + u = (-u) & 5; + add_ssaaaa(carry, h0, 0, h0, 0, u); + add_ssaaaa(carry, h1, 0, h1, 0, carry); + add_ssaaaa(carry, h2, 0, h2, 0, carry); + add_ssaaaa(carry, h3, 0, h3, 0, carry); + + /* add high part of key + h */ + add_ssaaaa(tmp0, h0, 0, h0, 0, st->k[0]); + add_ssaaaa(tmp1, h1, 0, h1, 0, st->k[1]); + add_ssaaaa(tmp1, h1, tmp1, h1, 0, tmp0); + add_ssaaaa(tmp2, h2, 0, h2, 0, st->k[2]); + add_ssaaaa(tmp2, h2, tmp2, h2, 0, tmp1); + add_ssaaaa(carry, h3, 0, h3, 0, st->k[3]); + h3 += tmp2; + + buf_put_le32(mac + 0, h0); + buf_put_le32(mac + 4, h1); + buf_put_le32(mac + 8, h2); + buf_put_le32(mac + 12, h3); + + /* burn_stack */ + return 4 * sizeof (void *) + 10 * sizeof (u32) + burn; +} + +#endif /* USE_MPI_32BIT */ + + +unsigned int +_gcry_poly1305_update_burn (poly1305_context_t *ctx, const byte *m, + size_t bytes) +{ + unsigned int burn = 0; + + /* handle leftover */ + if (ctx->leftover) + { + size_t want = (POLY1305_BLOCKSIZE - ctx->leftover); + if (want > bytes) + want = bytes; + buf_cpy (ctx->buffer + ctx->leftover, m, want); + bytes -= want; + m += want; + ctx->leftover += want; + if (ctx->leftover < POLY1305_BLOCKSIZE) + return 0; + burn = poly1305_blocks (ctx, ctx->buffer, POLY1305_BLOCKSIZE, 1); + ctx->leftover = 0; + } + + /* process full blocks */ + if (bytes >= POLY1305_BLOCKSIZE) + { + size_t nblks = bytes / POLY1305_BLOCKSIZE; + burn = poly1305_blocks (ctx, m, nblks * POLY1305_BLOCKSIZE, 1); + m += nblks * POLY1305_BLOCKSIZE; + bytes -= nblks * POLY1305_BLOCKSIZE; + } + + /* store leftover */ + if (bytes) + { + buf_cpy (ctx->buffer + ctx->leftover, m, bytes); + ctx->leftover += bytes; + } + + return burn; +} + + +void +_gcry_poly1305_update (poly1305_context_t *ctx, const byte *m, size_t bytes) +{ + unsigned int burn; + + burn = _gcry_poly1305_update_burn (ctx, m, bytes); + + if (burn) + _gcry_burn_stack (burn); +} + + +void +_gcry_poly1305_finish (poly1305_context_t *ctx, byte mac[POLY1305_TAGLEN]) +{ + unsigned int burn; + + burn = poly1305_final (ctx, mac); + + _gcry_burn_stack (burn); +} + + +gcry_err_code_t +_gcry_poly1305_init (poly1305_context_t * ctx, const byte * key, + size_t keylen) +{ + static int initialized; + static const char *selftest_failed; + + if (!initialized) + { + initialized = 1; + selftest_failed = selftest (); + if (selftest_failed) + log_error ("Poly1305 selftest failed (%s)\n", selftest_failed); + } + + if (keylen != POLY1305_KEYLEN) + return GPG_ERR_INV_KEYLEN; + + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + poly1305_init (ctx, key); + + return 0; +} + + +static void +poly1305_auth (byte mac[POLY1305_TAGLEN], const byte * m, size_t bytes, + const byte * key) +{ + poly1305_context_t ctx; + + memset (&ctx, 0, sizeof (ctx)); + + _gcry_poly1305_init (&ctx, key, POLY1305_KEYLEN); + _gcry_poly1305_update (&ctx, m, bytes); + _gcry_poly1305_finish (&ctx, mac); + + wipememory (&ctx, sizeof (ctx)); +} + + +static const char * +selftest (void) +{ + /* example from nacl */ + static const byte nacl_key[POLY1305_KEYLEN] = { + 0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91, + 0x6d, 0x11, 0xc2, 0xcb, 0x21, 0x4d, 0x3c, 0x25, + 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, + 0x2d, 0x65, 0x1f, 0xa4, 0xc8, 0xcf, 0xf8, 0x80, + }; + + static const byte nacl_msg[131] = { + 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, + 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce, + 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, + 0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a, + 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, + 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72, + 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, + 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, + 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a, + 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, + 0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea, + 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, + 0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, + 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3, + 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, + 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, + 0xe3, 0x55, 0xa5 + }; + + static const byte nacl_mac[16] = { + 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, + 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9 + }; + + /* generates a final value of (2^130 - 2) == 3 */ + static const byte wrap_key[POLY1305_KEYLEN] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static const byte wrap_msg[16] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + static const byte wrap_mac[16] = { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + /* mac of the macs of messages of length 0 to 256, where the key and messages + * have all their values set to the length + */ + static const byte total_key[POLY1305_KEYLEN] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + static const byte total_mac[16] = { + 0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd, + 0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39 + }; + + poly1305_context_t ctx; + poly1305_context_t total_ctx; + byte all_key[POLY1305_KEYLEN]; + byte all_msg[256]; + byte mac[16]; + size_t i, j; + + memset (&ctx, 0, sizeof (ctx)); + memset (&total_ctx, 0, sizeof (total_ctx)); + + memset (mac, 0, sizeof (mac)); + poly1305_auth (mac, nacl_msg, sizeof (nacl_msg), nacl_key); + if (memcmp (nacl_mac, mac, sizeof (nacl_mac)) != 0) + return "Poly1305 test 1 failed."; + + /* SSE2/AVX have a 32 byte block size, but also support 64 byte blocks, so + * make sure everything still works varying between them */ + memset (mac, 0, sizeof (mac)); + _gcry_poly1305_init (&ctx, nacl_key, POLY1305_KEYLEN); + _gcry_poly1305_update (&ctx, nacl_msg + 0, 32); + _gcry_poly1305_update (&ctx, nacl_msg + 32, 64); + _gcry_poly1305_update (&ctx, nacl_msg + 96, 16); + _gcry_poly1305_update (&ctx, nacl_msg + 112, 8); + _gcry_poly1305_update (&ctx, nacl_msg + 120, 4); + _gcry_poly1305_update (&ctx, nacl_msg + 124, 2); + _gcry_poly1305_update (&ctx, nacl_msg + 126, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 127, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 128, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 129, 1); + _gcry_poly1305_update (&ctx, nacl_msg + 130, 1); + _gcry_poly1305_finish (&ctx, mac); + if (memcmp (nacl_mac, mac, sizeof (nacl_mac)) != 0) + return "Poly1305 test 2 failed."; + + memset (mac, 0, sizeof (mac)); + poly1305_auth (mac, wrap_msg, sizeof (wrap_msg), wrap_key); + if (memcmp (wrap_mac, mac, sizeof (nacl_mac)) != 0) + return "Poly1305 test 3 failed."; + + _gcry_poly1305_init (&total_ctx, total_key, POLY1305_KEYLEN); + for (i = 0; i < 256; i++) + { + /* set key and message to 'i,i,i..' */ + for (j = 0; j < sizeof (all_key); j++) + all_key[j] = i; + for (j = 0; j < i; j++) + all_msg[j] = i; + poly1305_auth (mac, all_msg, i, all_key); + _gcry_poly1305_update (&total_ctx, mac, 16); + } + _gcry_poly1305_finish (&total_ctx, mac); + if (memcmp (total_mac, mac, sizeof (total_mac)) != 0) + return "Poly1305 test 4 failed."; + + return NULL; +} diff --git a/comm/third_party/libgcrypt/cipher/primegen.c b/comm/third_party/libgcrypt/cipher/primegen.c new file mode 100644 index 0000000000..e24de4dc7c --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/primegen.c @@ -0,0 +1,1878 @@ +/* primegen.c - prime number generator + * Copyright (C) 1998, 2000, 2001, 2002, 2003 + * 2004, 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" + +static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, + int (*extra_check)(void *, gcry_mpi_t), + void *extra_check_arg); +static int check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, + gcry_prime_check_func_t cb_func, void *cb_arg ); +static int is_prime (gcry_mpi_t n, int steps, unsigned int *count); +static void m_out_of_n( char *array, int m, int n ); + +static void (*progress_cb) (void *,const char*,int,int, int ); +static void *progress_cb_data; + +/* Note: 2 is not included because it can be tested more easily by + looking at bit 0. The last entry in this list is marked by a zero */ +static ushort small_prime_numbers[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, + 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, + 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, + 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, + 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, + 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, + 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, + 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, + 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, + 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, + 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, + 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, + 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, + 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, + 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, + 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, + 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, + 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, + 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999, + 0 +}; +static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; + + + +/* An object and a list to build up a global pool of primes. See + save_pool_prime and get_pool_prime. */ +struct primepool_s +{ + struct primepool_s *next; + gcry_mpi_t prime; /* If this is NULL the entry is not used. */ + unsigned int nbits; + gcry_random_level_t randomlevel; +}; +struct primepool_s *primepool; +/* Mutex used to protect access to the primepool. */ +GPGRT_LOCK_DEFINE (primepool_lock); + + +gcry_err_code_t +_gcry_primegen_init (void) +{ + /* This function was formerly used to initialize the primepool + Mutex. This has been replace by a static initialization. */ + return 0; +} + + +/* Save PRIME which has been generated at RANDOMLEVEL for later + use. Needs to be called while primepool_lock is being hold. Note + that PRIME should be considered released after calling this + function. */ +static void +save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) +{ + struct primepool_s *item, *item2; + size_t n; + + for (n=0, item = primepool; item; item = item->next, n++) + if (!item->prime) + break; + if (!item && n > 100) + { + /* Remove some of the entries. Our strategy is removing + the last third from the list. */ + int i; + + for (i=0, item2 = primepool; item2; item2 = item2->next) + { + if (i >= n/3*2) + { + _gcry_mpi_release (item2->prime); + item2->prime = NULL; + if (!item) + item = item2; + } + } + } + if (!item) + { + item = xtrycalloc (1, sizeof *item); + if (!item) + { + /* Out of memory. Silently giving up. */ + _gcry_mpi_release (prime); + return; + } + item->next = primepool; + primepool = item; + } + item->prime = prime; + item->nbits = mpi_get_nbits (prime); + item->randomlevel = randomlevel; +} + + +/* Return a prime for the prime pool or NULL if none has been found. + The prime needs to match NBITS and randomlevel. This function needs + to be called with the primepool_look is being hold. */ +static gcry_mpi_t +get_pool_prime (unsigned int nbits, gcry_random_level_t randomlevel) +{ + struct primepool_s *item; + + for (item = primepool; item; item = item->next) + if (item->prime + && item->nbits == nbits && item->randomlevel == randomlevel) + { + gcry_mpi_t prime = item->prime; + item->prime = NULL; + gcry_assert (nbits == mpi_get_nbits (prime)); + return prime; + } + return NULL; +} + + + + + + +void +_gcry_register_primegen_progress ( void (*cb)(void *,const char*,int,int,int), + void *cb_data ) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + + +static void +progress( int c ) +{ + if ( progress_cb ) + progress_cb ( progress_cb_data, "primegen", c, 0, 0 ); +} + + +/**************** + * Generate a prime number (stored in secure memory) + */ +gcry_mpi_t +_gcry_generate_secret_prime (unsigned int nbits, + gcry_random_level_t random_level, + int (*extra_check)(void*, gcry_mpi_t), + void *extra_check_arg) +{ + gcry_mpi_t prime; + + prime = gen_prime (nbits, 1, random_level, extra_check, extra_check_arg); + progress('\n'); + return prime; +} + + +/* Generate a prime number which may be public, i.e. not allocated in + secure memory. */ +gcry_mpi_t +_gcry_generate_public_prime (unsigned int nbits, + gcry_random_level_t random_level, + int (*extra_check)(void*, gcry_mpi_t), + void *extra_check_arg) +{ + gcry_mpi_t prime; + + prime = gen_prime (nbits, 0, random_level, extra_check, extra_check_arg); + progress('\n'); + return prime; +} + + +/* Core prime generation function. The algorithm used to generate + practically save primes is due to Lim and Lee as described in the + CRYPTO '97 proceedings (ISBN3540633847) page 260. + + NEED_Q_FACTOR: If true make sure that at least one factor is of + size qbits. This is for example required for DSA. + PRIME_GENERATED: Adresss of a variable where the resulting prime + number will be stored. + PBITS: Requested size of the prime number. At least 48. + QBITS: One factor of the prime needs to be of this size. Maybe 0 + if this is not required. See also MODE. + G: If not NULL an MPI which will receive a generator for the prime + for use with Elgamal. + RET_FACTORS: if not NULL, an array with all factors are stored at + that address. + ALL_FACTORS: If set to true all factors of prime-1 are returned. + RANDOMLEVEL: How strong should the random numers be. + FLAGS: Prime generation bit flags. Currently supported: + GCRY_PRIME_FLAG_SECRET - The prime needs to be kept secret. + CB_FUNC, CB_ARG: Callback to be used for extra checks. + + */ +static gcry_err_code_t +prime_generate_internal (int need_q_factor, + gcry_mpi_t *prime_generated, unsigned int pbits, + unsigned int qbits, gcry_mpi_t g, + gcry_mpi_t **ret_factors, + gcry_random_level_t randomlevel, unsigned int flags, + int all_factors, + gcry_prime_check_func_t cb_func, void *cb_arg) +{ + gcry_err_code_t err = 0; + gcry_mpi_t *factors_new = NULL; /* Factors to return to the + caller. */ + gcry_mpi_t *factors = NULL; /* Current factors. */ + gcry_random_level_t poolrandomlevel; /* Random level used for pool primes. */ + gcry_mpi_t *pool = NULL; /* Pool of primes. */ + int *pool_in_use = NULL; /* Array with currently used POOL elements. */ + unsigned char *perms = NULL; /* Permutations of POOL. */ + gcry_mpi_t q_factor = NULL; /* Used if QBITS is non-zero. */ + unsigned int fbits = 0; /* Length of prime factors. */ + unsigned int n = 0; /* Number of factors. */ + unsigned int m = 0; /* Number of primes in pool. */ + gcry_mpi_t q = NULL; /* First prime factor. */ + gcry_mpi_t prime = NULL; /* Prime candidate. */ + unsigned int nprime = 0; /* Bits of PRIME. */ + unsigned int req_qbits; /* The original QBITS value. */ + gcry_mpi_t val_2; /* For check_prime(). */ + int is_locked = 0; /* Flag to help unlocking the primepool. */ + unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET); + unsigned int count1 = 0, count2 = 0; + unsigned int i = 0, j = 0; + + if (pbits < 48) + return GPG_ERR_INV_ARG; + + /* We won't use a too strong random elvel for the pooled subprimes. */ + poolrandomlevel = (randomlevel > GCRY_STRONG_RANDOM? + GCRY_STRONG_RANDOM : randomlevel); + + + /* If QBITS is not given, assume a reasonable value. */ + if (!qbits) + qbits = pbits / 3; + + req_qbits = qbits; + + /* Find number of needed prime factors N. */ + for (n = 1; (pbits - qbits - 1) / n >= qbits; n++) + ; + n--; + + val_2 = mpi_alloc_set_ui (2); + + if ((! n) || ((need_q_factor) && (n < 2))) + { + err = GPG_ERR_INV_ARG; + goto leave; + } + + if (need_q_factor) + { + n--; /* Need one factor less because we want a specific Q-FACTOR. */ + fbits = (pbits - 2 * req_qbits -1) / n; + qbits = pbits - req_qbits - n * fbits; + } + else + { + fbits = (pbits - req_qbits -1) / n; + qbits = pbits - n * fbits; + } + + if (DBG_CIPHER) + log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", + pbits, req_qbits, qbits, fbits, n); + + /* Allocate an integer to old the new prime. */ + prime = mpi_new (pbits); + + /* Generate first prime factor. */ + q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); + + /* Generate a specific Q-Factor if requested. */ + if (need_q_factor) + q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); + + /* Allocate an array to hold all factors + 2 for later usage. */ + factors = xtrycalloc (n + 2, sizeof (*factors)); + if (!factors) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + /* Allocate an array to track pool usage. */ + pool_in_use = xtrymalloc (n * sizeof *pool_in_use); + if (!pool_in_use) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + for (i=0; i < n; i++) + pool_in_use[i] = -1; + + /* Make a pool of 3n+5 primes (this is an arbitrary value). We + require at least 30 primes for are useful selection process. + + Fixme: We need to research the best formula for sizing the pool. + */ + m = n * 3 + 5; + if (need_q_factor) /* Need some more in this case. */ + m += 5; + if (m < 30) + m = 30; + pool = xtrycalloc (m , sizeof (*pool)); + if (! pool) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + /* Permutate over the pool of primes until we find a prime of the + requested length. */ + do + { + next_try: + for (i=0; i < n; i++) + pool_in_use[i] = -1; + + if (!perms) + { + /* Allocate new primes. This is done right at the beginning + of the loop and if we have later run out of primes. */ + for (i = 0; i < m; i++) + { + mpi_free (pool[i]); + pool[i] = NULL; + } + + /* Init m_out_of_n(). */ + perms = xtrycalloc (1, m); + if (!perms) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + err = gpgrt_lock_lock (&primepool_lock); + if (err) + goto leave; + is_locked = 1; + + for (i = 0; i < n; i++) + { + perms[i] = 1; + /* At a maximum we use strong random for the factors. + This saves us a lot of entropy. Given that Q and + possible Q-factor are also used in the final prime + this should be acceptable. We also don't allocate in + secure memory to save on that scare resource too. If + Q has been allocated in secure memory, the final + prime will be saved there anyway. This is because + our MPI routines take care of that. GnuPG has worked + this way ever since. */ + pool[i] = NULL; + if (is_locked) + { + pool[i] = get_pool_prime (fbits, poolrandomlevel); + if (!pool[i]) + { + err = gpgrt_lock_unlock (&primepool_lock); + if (err) + goto leave; + is_locked = 0; + } + } + if (!pool[i]) + pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); + pool_in_use[i] = i; + factors[i] = pool[i]; + } + + if (is_locked && (err = gpgrt_lock_unlock (&primepool_lock))) + goto leave; + is_locked = 0; + } + else + { + /* Get next permutation. */ + m_out_of_n ( (char*)perms, n, m); + + if ((err = gpgrt_lock_lock (&primepool_lock))) + goto leave; + is_locked = 1; + + for (i = j = 0; (i < m) && (j < n); i++) + if (perms[i]) + { + /* If the subprime has not yet beed generated do it now. */ + if (!pool[i] && is_locked) + { + pool[i] = get_pool_prime (fbits, poolrandomlevel); + if (!pool[i]) + { + if ((err = gpgrt_lock_unlock (&primepool_lock))) + goto leave; + is_locked = 0; + } + } + if (!pool[i]) + pool[i] = gen_prime (fbits, 0, poolrandomlevel, NULL, NULL); + pool_in_use[j] = i; + factors[j++] = pool[i]; + } + + if (is_locked && (err = gpgrt_lock_unlock (&primepool_lock))) + goto leave; + is_locked = 0; + + if (i == n) + { + /* Ran out of permutations: Allocate new primes. */ + xfree (perms); + perms = NULL; + progress ('!'); + goto next_try; + } + } + + /* Generate next prime candidate: + p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. + */ + mpi_set (prime, q); + mpi_mul_ui (prime, prime, 2); + if (need_q_factor) + mpi_mul (prime, prime, q_factor); + for(i = 0; i < n; i++) + mpi_mul (prime, prime, factors[i]); + mpi_add_ui (prime, prime, 1); + nprime = mpi_get_nbits (prime); + + if (nprime < pbits) + { + if (++count1 > 20) + { + count1 = 0; + qbits++; + progress('>'); + mpi_free (q); + q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); + goto next_try; + } + } + else + count1 = 0; + + if (nprime > pbits) + { + if (++count2 > 20) + { + count2 = 0; + qbits--; + progress('<'); + mpi_free (q); + q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); + goto next_try; + } + } + else + count2 = 0; + } + while (! ((nprime == pbits) && check_prime (prime, val_2, 5, + cb_func, cb_arg))); + + if (DBG_CIPHER) + { + progress ('\n'); + log_mpidump ("prime ", prime); + log_mpidump ("factor q", q); + if (need_q_factor) + log_mpidump ("factor q0", q_factor); + for (i = 0; i < n; i++) + log_mpidump ("factor pi", factors[i]); + log_debug ("bit sizes: prime=%u, q=%u", + mpi_get_nbits (prime), mpi_get_nbits (q)); + if (need_q_factor) + log_printf (", q0=%u", mpi_get_nbits (q_factor)); + for (i = 0; i < n; i++) + log_printf (", p%d=%u", i, mpi_get_nbits (factors[i])); + log_printf ("\n"); + } + + if (ret_factors) + { + /* Caller wants the factors. */ + factors_new = xtrycalloc (n + 4, sizeof (*factors_new)); + if (! factors_new) + { + err = gpg_err_code_from_errno (errno); + goto leave; + } + + if (all_factors) + { + i = 0; + factors_new[i++] = mpi_set_ui (NULL, 2); + factors_new[i++] = mpi_copy (q); + if (need_q_factor) + factors_new[i++] = mpi_copy (q_factor); + for(j=0; j < n; j++) + factors_new[i++] = mpi_copy (factors[j]); + } + else + { + i = 0; + if (need_q_factor) + { + factors_new[i++] = mpi_copy (q_factor); + for (; i <= n; i++) + factors_new[i] = mpi_copy (factors[i]); + } + else + for (; i < n; i++ ) + factors_new[i] = mpi_copy (factors[i]); + } + } + + if (g && need_q_factor) + err = GPG_ERR_NOT_IMPLEMENTED; + else if (g) + { + /* Create a generator (start with 3). */ + gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); + gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); + gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); + + factors[n] = q; + factors[n + 1] = mpi_alloc_set_ui (2); + mpi_sub_ui (pmin1, prime, 1); + mpi_set_ui (g, 2); + do + { + mpi_add_ui (g, g, 1); + if (DBG_CIPHER) + log_printmpi ("checking g", g); + else + progress('^'); + for (i = 0; i < n + 2; i++) + { + mpi_fdiv_q (tmp, pmin1, factors[i]); + /* No mpi_pow(), but it is okay to use this with mod + prime. */ + mpi_powm (b, g, tmp, prime); + if (! mpi_cmp_ui (b, 1)) + break; + } + if (DBG_CIPHER) + progress('\n'); + } + while (i < n + 2); + + mpi_free (factors[n+1]); + mpi_free (tmp); + mpi_free (b); + mpi_free (pmin1); + } + + if (! DBG_CIPHER) + progress ('\n'); + + + leave: + if (pool) + { + is_locked = !gpgrt_lock_lock (&primepool_lock); + for(i = 0; i < m; i++) + { + if (pool[i]) + { + for (j=0; j < n; j++) + if (pool_in_use[j] == i) + break; + if (j == n && is_locked) + { + /* This pooled subprime has not been used. */ + save_pool_prime (pool[i], poolrandomlevel); + } + else + mpi_free (pool[i]); + } + } + if (is_locked) + err = gpgrt_lock_unlock (&primepool_lock); + is_locked = 0; + xfree (pool); + } + xfree (pool_in_use); + if (factors) + xfree (factors); /* Factors are shallow copies. */ + if (perms) + xfree (perms); + + mpi_free (val_2); + mpi_free (q); + mpi_free (q_factor); + + if (! err) + { + *prime_generated = prime; + if (ret_factors) + *ret_factors = factors_new; + } + else + { + if (factors_new) + { + for (i = 0; factors_new[i]; i++) + mpi_free (factors_new[i]); + xfree (factors_new); + } + mpi_free (prime); + } + + return err; +} + + +/* Generate a prime used for discrete logarithm algorithms; i.e. this + prime will be public and no strong random is required. On success + R_PRIME receives a new MPI with the prime. On error R_PRIME is set + to NULL and an error code is returned. If RET_FACTORS is not NULL + it is set to an allocated array of factors on success or to NULL on + error. */ +gcry_err_code_t +_gcry_generate_elg_prime (int mode, unsigned pbits, unsigned qbits, + gcry_mpi_t g, + gcry_mpi_t *r_prime, gcry_mpi_t **ret_factors) +{ + *r_prime = NULL; + if (ret_factors) + *ret_factors = NULL; + return prime_generate_internal ((mode == 1), r_prime, pbits, qbits, g, + ret_factors, GCRY_WEAK_RANDOM, 0, 0, + NULL, NULL); +} + + +static gcry_mpi_t +gen_prime (unsigned int nbits, int secret, int randomlevel, + int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg) +{ + gcry_mpi_t prime, ptest, pminus1, val_2, val_3, result; + int i; + unsigned int x, step; + unsigned int count1, count2; + int *mods; + +/* if ( DBG_CIPHER ) */ +/* log_debug ("generate a prime of %u bits ", nbits ); */ + + if (nbits < 16) + log_fatal ("can't generate a prime with less than %d bits\n", 16); + + mods = (secret? xmalloc_secure (no_of_small_prime_numbers * sizeof *mods) + /* */ : xmalloc (no_of_small_prime_numbers * sizeof *mods)); + /* Make nbits fit into gcry_mpi_t implementation. */ + val_2 = mpi_alloc_set_ui( 2 ); + val_3 = mpi_alloc_set_ui( 3); + prime = secret? mpi_snew (nbits): mpi_new (nbits); + result = mpi_alloc_like( prime ); + pminus1= mpi_alloc_like( prime ); + ptest = mpi_alloc_like( prime ); + count1 = count2 = 0; + for (;;) + { /* try forvever */ + int dotcount=0; + + /* generate a random number */ + _gcry_mpi_randomize( prime, nbits, randomlevel ); + + /* Set high order bit to 1, set low order bit to 1. If we are + generating a secret prime we are most probably doing that + for RSA, to make sure that the modulus does have the + requested key size we set the 2 high order bits. */ + mpi_set_highbit (prime, nbits-1); + if (secret) + mpi_set_bit (prime, nbits-2); + mpi_set_bit(prime, 0); + + /* Calculate all remainders. */ + for (i=0; (x = small_prime_numbers[i]); i++ ) + mods[i] = mpi_fdiv_r_ui(NULL, prime, x); + + /* Now try some primes starting with prime. */ + for(step=0; step < 20000; step += 2 ) + { + /* Check against all the small primes we have in mods. */ + count1++; + for (i=0; (x = small_prime_numbers[i]); i++ ) + { + while ( mods[i] + step >= x ) + mods[i] -= x; + if ( !(mods[i] + step) ) + break; + } + if ( x ) + continue; /* Found a multiple of an already known prime. */ + + mpi_add_ui( ptest, prime, step ); + + /* Do a fast Fermat test now. */ + count2++; + mpi_sub_ui( pminus1, ptest, 1); + mpi_powm( result, val_2, pminus1, ptest ); + if ( !mpi_cmp_ui( result, 1 ) ) + { + /* Not composite, perform stronger tests */ + if (is_prime(ptest, 5, &count2 )) + { + if (!mpi_test_bit( ptest, nbits-1-secret )) + { + progress('\n'); + log_debug ("overflow in prime generation\n"); + break; /* Stop loop, continue with a new prime. */ + } + + if (extra_check && extra_check (extra_check_arg, ptest)) + { + /* The extra check told us that this prime is + not of the caller's taste. */ + progress ('/'); + } + else + { + /* Got it. */ + mpi_free(val_2); + mpi_free(val_3); + mpi_free(result); + mpi_free(pminus1); + mpi_free(prime); + xfree(mods); + return ptest; + } + } + } + if (++dotcount == 10 ) + { + progress('.'); + dotcount = 0; + } + } + progress(':'); /* restart with a new random value */ + } +} + +/**************** + * Returns: true if this may be a prime + * RM_ROUNDS gives the number of Rabin-Miller tests to run. + */ +static int +check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, + gcry_prime_check_func_t cb_func, void *cb_arg) +{ + int i; + unsigned int x; + unsigned int count=0; + + /* Check against small primes. */ + for (i=0; (x = small_prime_numbers[i]); i++ ) + { + if ( mpi_divisible_ui( prime, x ) ) + return !mpi_cmp_ui (prime, x); + } + + /* A quick Fermat test. */ + { + gcry_mpi_t result = mpi_alloc_like( prime ); + gcry_mpi_t pminus1 = mpi_alloc_like( prime ); + mpi_sub_ui( pminus1, prime, 1); + mpi_powm( result, val_2, pminus1, prime ); + mpi_free( pminus1 ); + if ( mpi_cmp_ui( result, 1 ) ) + { + /* Is composite. */ + mpi_free( result ); + progress('.'); + return 0; + } + mpi_free( result ); + } + + if (!cb_func || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_MAYBE_PRIME, prime)) + { + /* Perform stronger tests. */ + if ( is_prime( prime, rm_rounds, &count ) ) + { + if (!cb_func + || cb_func (cb_arg, GCRY_PRIME_CHECK_AT_GOT_PRIME, prime)) + return 1; /* Probably a prime. */ + } + } + progress('.'); + return 0; +} + + +/* + * Return true if n is probably a prime + */ +static int +is_prime (gcry_mpi_t n, int steps, unsigned int *count) +{ + gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t z = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t nminus1 = mpi_alloc( mpi_get_nlimbs( n ) ); + gcry_mpi_t a2 = mpi_alloc_set_ui( 2 ); + gcry_mpi_t q; + unsigned i, j, k; + int rc = 0; + unsigned nbits = mpi_get_nbits( n ); + + if (steps < 5) /* Make sure that we do at least 5 rounds. */ + steps = 5; + + mpi_sub_ui( nminus1, n, 1 ); + + /* Find q and k, so that n = 1 + 2^k * q . */ + q = mpi_copy ( nminus1 ); + k = mpi_trailing_zeros ( q ); + mpi_tdiv_q_2exp (q, q, k); + + for (i=0 ; i < steps; i++ ) + { + ++*count; + if( !i ) + { + mpi_set_ui( x, 2 ); + } + else + { + /* We need to loop to avoid an X with value 0 or 1. */ + do + { + _gcry_mpi_randomize (x, nbits, GCRY_WEAK_RANDOM); + + /* Make sure that the number is smaller than the prime + * and keep the randomness of the high bit. */ + if (mpi_test_bit (x, nbits-2)) + { + mpi_set_highbit (x, nbits-2); /* Clear all higher bits. */ + } + else + { + mpi_set_highbit (x, nbits-2); + mpi_clear_bit (x, nbits-2); + } + } + while (mpi_cmp_ui (x, 1) <= 0); + gcry_assert (mpi_cmp (x, nminus1) < 0); + } + mpi_powm ( y, x, q, n); + if ( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) + { + for ( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) + { + mpi_powm(y, y, a2, n); + if( !mpi_cmp_ui( y, 1 ) ) + goto leave; /* Not a prime. */ + } + if (mpi_cmp( y, nminus1 ) ) + goto leave; /* Not a prime. */ + } + progress('+'); + } + rc = 1; /* May be a prime. */ + + leave: + mpi_free( x ); + mpi_free( y ); + mpi_free( z ); + mpi_free( nminus1 ); + mpi_free( q ); + mpi_free( a2 ); + + return rc; +} + + +/* Given ARRAY of size N with M elements set to true produce a + modified array with the next permutation of M elements. Note, that + ARRAY is used in a one-bit-per-byte approach. To detected the last + permutation it is useful to initialize the array with the first M + element set to true and use this test: + m_out_of_n (array, m, n); + for (i = j = 0; i < n && j < m; i++) + if (array[i]) + j++; + if (j == m) + goto ready; + + This code is based on the algorithm 452 from the "Collected + Algorithms From ACM, Volume II" by C. N. Liu and D. T. Tang. +*/ +static void +m_out_of_n ( char *array, int m, int n ) +{ + int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0; + + if( !m || m >= n ) + return; + + /* Need to handle this simple case separately. */ + if( m == 1 ) + { + for (i=0; i < n; i++ ) + { + if ( array[i] ) + { + array[i++] = 0; + if( i >= n ) + i = 0; + array[i] = 1; + return; + } + } + BUG(); + } + + + for (j=1; j < n; j++ ) + { + if ( array[n-1] == array[n-j-1]) + continue; + j1 = j; + break; + } + + if ( (m & 1) ) + { + /* M is odd. */ + if( array[n-1] ) + { + if( j1 & 1 ) + { + k1 = n - j1; + k2 = k1+2; + if( k2 > n ) + k2 = n; + goto leave; + } + goto scan; + } + k2 = n - j1 - 1; + if( k2 == 0 ) + { + k1 = i; + k2 = n - j1; + } + else if( array[k2] && array[k2-1] ) + k1 = n; + else + k1 = k2 + 1; + } + else + { + /* M is even. */ + if( !array[n-1] ) + { + k1 = n - j1; + k2 = k1 + 1; + goto leave; + } + + if( !(j1 & 1) ) + { + k1 = n - j1; + k2 = k1+2; + if( k2 > n ) + k2 = n; + goto leave; + } + scan: + jp = n - j1 - 1; + for (i=1; i <= jp; i++ ) + { + i1 = jp + 2 - i; + if( array[i1-1] ) + { + if( array[i1-2] ) + { + k1 = i1 - 1; + k2 = n - j1; + } + else + { + k1 = i1 - 1; + k2 = n + 1 - j1; + } + goto leave; + } + } + k1 = 1; + k2 = n + 1 - m; + } + leave: + /* Now complement the two selected bits. */ + array[k1-1] = !array[k1-1]; + array[k2-1] = !array[k2-1]; +} + + +/* Generate a new prime number of PRIME_BITS bits and store it in + PRIME. If FACTOR_BITS is non-zero, one of the prime factors of + (prime - 1) / 2 must be FACTOR_BITS bits long. If FACTORS is + non-zero, allocate a new, NULL-terminated array holding the prime + factors and store it in FACTORS. FLAGS might be used to influence + the prime number generation process. */ +gcry_err_code_t +_gcry_prime_generate (gcry_mpi_t *prime, unsigned int prime_bits, + unsigned int factor_bits, gcry_mpi_t **factors, + gcry_prime_check_func_t cb_func, void *cb_arg, + gcry_random_level_t random_level, + unsigned int flags) +{ + gcry_err_code_t rc = 0; + gcry_mpi_t *factors_generated = NULL; + gcry_mpi_t prime_generated = NULL; + unsigned int mode = 0; + + if (!prime) + return GPG_ERR_INV_ARG; + *prime = NULL; + + if (flags & GCRY_PRIME_FLAG_SPECIAL_FACTOR) + mode = 1; + + /* Generate. */ + rc = prime_generate_internal ((mode==1), &prime_generated, prime_bits, + factor_bits, NULL, + factors? &factors_generated : NULL, + random_level, flags, 1, + cb_func, cb_arg); + + if (!rc && cb_func) + { + /* Additional check. */ + if ( !cb_func (cb_arg, GCRY_PRIME_CHECK_AT_FINISH, prime_generated)) + { + /* Failed, deallocate resources. */ + unsigned int i; + + mpi_free (prime_generated); + if (factors) + { + for (i = 0; factors_generated[i]; i++) + mpi_free (factors_generated[i]); + xfree (factors_generated); + } + rc = GPG_ERR_GENERAL; + } + } + + if (!rc) + { + if (factors) + *factors = factors_generated; + *prime = prime_generated; + } + + return rc; +} + +/* Check whether the number X is prime. */ +gcry_err_code_t +_gcry_prime_check (gcry_mpi_t x, unsigned int flags) +{ + (void)flags; + + switch (mpi_cmp_ui (x, 2)) + { + case 0: return 0; /* 2 is a prime */ + case -1: return GPG_ERR_NO_PRIME; /* Only numbers > 1 are primes. */ + } + + /* We use 64 rounds because the prime we are going to test is not + guaranteed to be a random one. */ + if (check_prime (x, mpi_const (MPI_C_TWO), 64, NULL, NULL)) + return 0; + + return GPG_ERR_NO_PRIME; +} + + +/* Check whether the number X is prime according to FIPS 186-4 table C.2. */ +gcry_err_code_t +_gcry_fips186_4_prime_check (gcry_mpi_t x, unsigned int bits) +{ + gcry_err_code_t ec = GPG_ERR_NO_ERROR; + + switch (mpi_cmp_ui (x, 2)) + { + case 0: return ec; /* 2 is a prime */ + case -1: return GPG_ERR_NO_PRIME; /* Only numbers > 1 are primes. */ + } + + /* We use 5 or 4 rounds as specified in table C.2 */ + if (! check_prime (x, mpi_const (MPI_C_TWO), bits > 1024 ? 4 : 5, NULL, NULL)) + ec = GPG_ERR_NO_PRIME; + + return ec; +} + + +/* Find a generator for PRIME where the factorization of (prime-1) is + in the NULL terminated array FACTORS. Return the generator as a + newly allocated MPI in R_G. If START_G is not NULL, use this as s + atart for the search. Returns 0 on success.*/ +gcry_err_code_t +_gcry_prime_group_generator (gcry_mpi_t *r_g, + gcry_mpi_t prime, gcry_mpi_t *factors, + gcry_mpi_t start_g) +{ + gcry_mpi_t tmp, b, pmin1, g; + int first, i, n; + + if (!r_g) + return GPG_ERR_INV_ARG; + *r_g = NULL; + if (!factors || !prime) + return GPG_ERR_INV_ARG; + + for (n=0; factors[n]; n++) + ; + if (n < 2) + return GPG_ERR_INV_ARG; + + tmp = mpi_new (0); + b = mpi_new (0); + pmin1 = mpi_new (0); + g = start_g? mpi_copy (start_g) : mpi_set_ui (NULL, 3); + + /* Extra sanity check - usually disabled. */ +/* mpi_set (tmp, factors[0]); */ +/* for(i = 1; i < n; i++) */ +/* mpi_mul (tmp, tmp, factors[i]); */ +/* mpi_add_ui (tmp, tmp, 1); */ +/* if (mpi_cmp (prime, tmp)) */ +/* return gpg_error (GPG_ERR_INV_ARG); */ + + mpi_sub_ui (pmin1, prime, 1); + first = 1; + do + { + if (first) + first = 0; + else + mpi_add_ui (g, g, 1); + + if (DBG_CIPHER) + log_printmpi ("checking g", g); + else + progress('^'); + + for (i = 0; i < n; i++) + { + mpi_fdiv_q (tmp, pmin1, factors[i]); + mpi_powm (b, g, tmp, prime); + if (! mpi_cmp_ui (b, 1)) + break; + } + if (DBG_CIPHER) + progress('\n'); + } + while (i < n); + + _gcry_mpi_release (tmp); + _gcry_mpi_release (b); + _gcry_mpi_release (pmin1); + *r_g = g; + + return 0; +} + +/* Convenience function to release the factors array. */ +void +_gcry_prime_release_factors (gcry_mpi_t *factors) +{ + if (factors) + { + int i; + + for (i=0; factors[i]; i++) + mpi_free (factors[i]); + xfree (factors); + } +} + + + +/* Helper for _gcry_derive_x931_prime. */ +static gcry_mpi_t +find_x931_prime (const gcry_mpi_t pfirst) +{ + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t prime; + + prime = mpi_copy (pfirst); + /* If P is even add 1. */ + mpi_set_bit (prime, 0); + + /* We use 64 Rabin-Miller rounds which is better and thus + sufficient. We do not have a Lucas test implementation thus we + can't do it in the X9.31 preferred way of running a few + Rabin-Miller followed by one Lucas test. */ + while ( !check_prime (prime, val_2, 64, NULL, NULL) ) + mpi_add_ui (prime, prime, 2); + + mpi_free (val_2); + + return prime; +} + + +/* Generate a prime using the algorithm from X9.31 appendix B.4. + + This function requires that the provided public exponent E is odd. + XP, XP1 and XP2 are the seed values. All values are mandatory. + + On success the prime is returned. If R_P1 or R_P2 are given the + internal values P1 and P2 are saved at these addresses. On error + NULL is returned. */ +gcry_mpi_t +_gcry_derive_x931_prime (const gcry_mpi_t xp, + const gcry_mpi_t xp1, const gcry_mpi_t xp2, + const gcry_mpi_t e, + gcry_mpi_t *r_p1, gcry_mpi_t *r_p2) +{ + gcry_mpi_t p1, p2, p1p2, yp0; + + if (!xp || !xp1 || !xp2) + return NULL; + if (!e || !mpi_test_bit (e, 0)) + return NULL; /* We support only odd values for E. */ + + p1 = find_x931_prime (xp1); + p2 = find_x931_prime (xp2); + p1p2 = mpi_alloc_like (xp); + mpi_mul (p1p2, p1, p2); + + { + gcry_mpi_t r1, tmp; + + /* r1 = (p2^{-1} mod p1)p2 - (p1^{-1} mod p2) */ + tmp = mpi_alloc_like (p1); + mpi_invm (tmp, p2, p1); + mpi_mul (tmp, tmp, p2); + r1 = tmp; + + tmp = mpi_alloc_like (p2); + mpi_invm (tmp, p1, p2); + mpi_mul (tmp, tmp, p1); + mpi_sub (r1, r1, tmp); + + /* Fixup a negative value. */ + if (mpi_has_sign (r1)) + mpi_add (r1, r1, p1p2); + + /* yp0 = xp + (r1 - xp mod p1*p2) */ + yp0 = tmp; tmp = NULL; + mpi_subm (yp0, r1, xp, p1p2); + mpi_add (yp0, yp0, xp); + mpi_free (r1); + + /* Fixup a negative value. */ + if (mpi_cmp (yp0, xp) < 0 ) + mpi_add (yp0, yp0, p1p2); + } + + /* yp0 is now the first integer greater than xp with p1 being a + large prime factor of yp0-1 and p2 a large prime factor of yp0+1. */ + + /* Note that the first example from X9.31 (D.1.1) which uses + (Xq1 #1A5CF72EE770DE50CB09ACCEA9#) + (Xq2 #134E4CAA16D2350A21D775C404#) + (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325 + 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34 + 321DE34A#)))) + returns an yp0 of + #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC4E3 + BF20CB896EE37E098A906313271422162CB6C642 + 75C1201F# + and not + #CC1092495D867E64065DEE3E7955F2EBC7D47A2D + 7C9953388F97DDDC3E1CA19C35CA659EDC2FC2E6 + C88FE299D52D78BE405A97E01FD71DD7819ECB91 + FA85A076# + as stated in the standard. This seems to be a bug in X9.31. + */ + + { + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t gcdtmp = mpi_alloc_like (yp0); + int gcdres; + + mpi_sub_ui (p1p2, p1p2, 1); /* Adjust for loop body. */ + mpi_sub_ui (yp0, yp0, 1); /* Ditto. */ + for (;;) + { + gcdres = mpi_gcd (gcdtmp, e, yp0); + mpi_add_ui (yp0, yp0, 1); + if (!gcdres) + progress ('/'); /* gcd (e, yp0-1) != 1 */ + else if (check_prime (yp0, val_2, 64, NULL, NULL)) + break; /* Found. */ + /* We add p1p2-1 because yp0 is incremented after the gcd test. */ + mpi_add (yp0, yp0, p1p2); + } + mpi_free (gcdtmp); + mpi_free (val_2); + } + + mpi_free (p1p2); + + progress('\n'); + if (r_p1) + *r_p1 = p1; + else + mpi_free (p1); + if (r_p2) + *r_p2 = p2; + else + mpi_free (p2); + return yp0; +} + + + +/* Generate the two prime used for DSA using the algorithm specified + in FIPS 186-2. PBITS is the desired length of the prime P and a + QBITS the length of the prime Q. If SEED is not supplied and + SEEDLEN is 0 the function generates an appropriate SEED. On + success the generated primes are stored at R_Q and R_P, the counter + value is stored at R_COUNTER and the seed actually used for + generation is stored at R_SEED and R_SEEDVALUE. */ +gpg_err_code_t +_gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, + const void *seed, size_t seedlen, + gcry_mpi_t *r_q, gcry_mpi_t *r_p, + int *r_counter, + void **r_seed, size_t *r_seedlen) +{ + gpg_err_code_t ec; + unsigned char seed_help_buffer[160/8]; /* Used to hold a generated SEED. */ + unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ + unsigned char digest[160/8]; /* Helper buffer for SHA-1 digest. */ + gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ + gcry_mpi_t tmpval = NULL; /* Helper variable. */ + int i; + + unsigned char value_u[160/8]; + int value_n, value_b, value_k; + int counter; + gcry_mpi_t value_w = NULL; + gcry_mpi_t value_x = NULL; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; + + /* FIPS 186-2 allows only for 1024/160 bit. */ + if (pbits != 1024 || qbits != 160) + return GPG_ERR_INV_KEYLEN; + + if (!seed && !seedlen) + ; /* No seed value given: We are asked to generate it. */ + else if (!seed || seedlen < qbits/8) + return GPG_ERR_INV_ARG; + + /* Allocate a buffer to later compute SEED+some_increment. */ + seed_plus = xtrymalloc (seedlen < 20? 20:seedlen); + if (!seed_plus) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + + val_2 = mpi_alloc_set_ui (2); + value_n = (pbits - 1) / qbits; + value_b = (pbits - 1) - value_n * qbits; + value_w = mpi_new (pbits); + value_x = mpi_new (pbits); + + restart: + /* Generate Q. */ + for (;;) + { + /* Step 1: Generate a (new) seed unless one has been supplied. */ + if (!seed) + { + seedlen = sizeof seed_help_buffer; + _gcry_create_nonce (seed_help_buffer, seedlen); + seed = seed_help_buffer; + } + + /* Step 2: U = sha1(seed) ^ sha1((seed+1) mod 2^{qbits}) */ + memcpy (seed_plus, seed, seedlen); + for (i=seedlen-1; i >= 0; i--) + { + seed_plus[i]++; + if (seed_plus[i]) + break; + } + _gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen); + _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + for (i=0; i < sizeof value_u; i++) + value_u[i] ^= digest[i]; + + /* Step 3: Form q from U */ + _gcry_mpi_release (prime_q); prime_q = NULL; + ec = _gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, + value_u, sizeof value_u, NULL); + if (ec) + goto leave; + mpi_set_highbit (prime_q, qbits-1 ); + mpi_set_bit (prime_q, 0); + + /* Step 4: Test whether Q is prime using 64 round of Rabin-Miller. */ + if (check_prime (prime_q, val_2, 64, NULL, NULL)) + break; /* Yes, Q is prime. */ + + /* Step 5. */ + seed = NULL; /* Force a new seed at Step 1. */ + } + + /* Step 6. Note that we do no use an explicit offset but increment + SEED_PLUS accordingly. SEED_PLUS is currently SEED+1. */ + counter = 0; + + /* Generate P. */ + prime_p = mpi_new (pbits); + for (;;) + { + /* Step 7: For k = 0,...n let + V_k = sha1(seed+offset+k) mod 2^{qbits} + Step 8: W = V_0 + V_1*2^160 + + ... + + V_{n-1}*2^{(n-1)*160} + + (V_{n} mod 2^b)*2^{n*160} + */ + mpi_set_ui (value_w, 0); + for (value_k=0; value_k <= value_n; value_k++) + { + /* There is no need to have an explicit offset variable: In + the first round we shall have an offset of 2, this is + achieved by using SEED_PLUS which is already at SEED+1, + thus we just need to increment it once again. The + requirement for the next round is to update offset by N, + which we implictly did at the end of this loop, and then + to add one; this one is the same as in the first round. */ + for (i=seedlen-1; i >= 0; i--) + { + seed_plus[i]++; + if (seed_plus[i]) + break; + } + _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + + _gcry_mpi_release (tmpval); tmpval = NULL; + ec = _gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, + digest, sizeof digest, NULL); + if (ec) + goto leave; + if (value_k == value_n) + mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ + mpi_lshift (tmpval, tmpval, value_k*qbits); + mpi_add (value_w, value_w, tmpval); + } + + /* Step 8 continued: X = W + 2^{L-1} */ + mpi_set_ui (value_x, 0); + mpi_set_highbit (value_x, pbits-1); + mpi_add (value_x, value_x, value_w); + + /* Step 9: c = X mod 2q, p = X - (c - 1) */ + mpi_mul_2exp (tmpval, prime_q, 1); + mpi_mod (tmpval, value_x, tmpval); + mpi_sub_ui (tmpval, tmpval, 1); + mpi_sub (prime_p, value_x, tmpval); + + /* Step 10: If p < 2^{L-1} skip the primality test. */ + /* Step 11 and 12: Primality test. */ + if (mpi_get_nbits (prime_p) >= pbits-1 + && check_prime (prime_p, val_2, 64, NULL, NULL) ) + break; /* Yes, P is prime, continue with Step 15. */ + + /* Step 13: counter = counter + 1, offset = offset + n + 1. */ + counter++; + + /* Step 14: If counter >= 2^12 goto Step 1. */ + if (counter >= 4096) + goto restart; + } + + /* Step 15: Save p, q, counter and seed. */ +/* log_debug ("fips186-2 pbits p=%u q=%u counter=%d\n", */ +/* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */ +/* log_printhex("fips186-2 seed:", seed, seedlen); */ +/* log_mpidump ("fips186-2 prime p", prime_p); */ +/* log_mpidump ("fips186-2 prime q", prime_q); */ + if (r_q) + { + *r_q = prime_q; + prime_q = NULL; + } + if (r_p) + { + *r_p = prime_p; + prime_p = NULL; + } + if (r_counter) + *r_counter = counter; + if (r_seed && r_seedlen) + { + memcpy (seed_plus, seed, seedlen); + *r_seed = seed_plus; + seed_plus = NULL; + *r_seedlen = seedlen; + } + + + leave: + _gcry_mpi_release (tmpval); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_w); + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + xfree (seed_plus); + _gcry_mpi_release (val_2); + return ec; +} + + + +/* WARNING: The code below has not yet been tested! + * + * Generate the two prime used for DSA using the algorithm specified + * in FIPS 186-3, A.1.1.2. PBITS is the desired length of the prime P + * and a QBITS the length of the prime Q. If SEED is not supplied and + * SEEDLEN is 0 the function generates an appropriate SEED. On + * success the generated primes are stored at R_Q and R_P, the counter + * value is stored at R_COUNTER and the seed actually used for + * generation is stored at R_SEED and R_SEEDVALUE. The hash algorithm + * used is stored at R_HASHALGO. + * + * Note that this function is very similar to the fips186_2 code. Due + * to the minor differences, other buffer sizes and for documentarion, + * we use a separate function. + */ +gpg_err_code_t +_gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, + const void *seed, size_t seedlen, + gcry_mpi_t *r_q, gcry_mpi_t *r_p, + int *r_counter, + void **r_seed, size_t *r_seedlen, + int *r_hashalgo) +{ + gpg_err_code_t ec; + unsigned char seed_help_buffer[256/8]; /* Used to hold a generated SEED. */ + unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ + unsigned char digest[256/8]; /* Helper buffer for SHA-2 digest. */ + gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ + gcry_mpi_t tmpval = NULL; /* Helper variable. */ + int hashalgo; /* The id of the Approved Hash Function. */ + int i; + + unsigned char value_u[256/8]; + int value_n, value_b, value_j; + int counter; + gcry_mpi_t value_w = NULL; + gcry_mpi_t value_x = NULL; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; + + gcry_assert (sizeof seed_help_buffer == sizeof digest + && sizeof seed_help_buffer == sizeof value_u); + + /* Step 1: Check the requested prime lengths. */ + /* Note that due to the size of our buffers QBITS is limited to 256. */ + if (pbits == 2048 && qbits == 224) + hashalgo = GCRY_MD_SHA224; + else if (pbits == 2048 && qbits == 256) + hashalgo = GCRY_MD_SHA256; + else if (pbits == 3072 && qbits == 256) + hashalgo = GCRY_MD_SHA256; + else + return GPG_ERR_INV_KEYLEN; + + /* Also check that the hash algorithm is available. */ + ec = _gcry_md_test_algo (hashalgo); + if (ec) + return ec; + gcry_assert (qbits/8 <= sizeof digest); + gcry_assert (_gcry_md_get_algo_dlen (hashalgo) == qbits/8); + + + /* Step 2: Check seedlen. */ + if (!seed && !seedlen) + ; /* No seed value given: We are asked to generate it. */ + else if (!seed || seedlen < qbits/8) + return GPG_ERR_INV_ARG; + + /* Allocate a buffer to later compute SEED+some_increment and a few + helper variables. */ + seed_plus = xtrymalloc (seedlen < sizeof seed_help_buffer? + sizeof seed_help_buffer : seedlen); + if (!seed_plus) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + val_2 = mpi_alloc_set_ui (2); + value_w = mpi_new (pbits); + value_x = mpi_new (pbits); + + /* Step 3: n = \lceil L / outlen \rceil - 1 */ + value_n = (pbits + qbits - 1) / qbits - 1; + /* Step 4: b = L - 1 - (n * outlen) */ + value_b = pbits - 1 - (value_n * qbits); + + restart: + /* Generate Q. */ + for (;;) + { + /* Step 5: Generate a (new) seed unless one has been supplied. */ + if (!seed) + { + seedlen = qbits/8; + gcry_assert (seedlen <= sizeof seed_help_buffer); + _gcry_create_nonce (seed_help_buffer, seedlen); + seed = seed_help_buffer; + } + + /* Step 6: U = hash(seed) */ + _gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen); + + /* Step 7: q = 2^{N-1} + U + 1 - (U mod 2) */ + if ( !(value_u[qbits/8-1] & 0x01) ) + { + for (i=qbits/8-1; i >= 0; i--) + { + value_u[i]++; + if (value_u[i]) + break; + } + } + _gcry_mpi_release (prime_q); prime_q = NULL; + ec = _gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, + value_u, qbits/8, NULL); + if (ec) + goto leave; + mpi_set_highbit (prime_q, qbits-1 ); + + /* Step 8: Test whether Q is prime using 64 round of Rabin-Miller. + According to table C.1 this is sufficient for all + supported prime sizes (i.e. up 3072/256). */ + if (check_prime (prime_q, val_2, 64, NULL, NULL)) + break; /* Yes, Q is prime. */ + + /* Step 8. */ + seed = NULL; /* Force a new seed at Step 5. */ + } + + /* Step 11. Note that we do no use an explicit offset but increment + SEED_PLUS accordingly. */ + memcpy (seed_plus, seed, seedlen); + counter = 0; + + /* Generate P. */ + prime_p = mpi_new (pbits); + for (;;) + { + /* Step 11.1: For j = 0,...n let + V_j = hash(seed+offset+j) + Step 11.2: W = V_0 + V_1*2^outlen + + ... + + V_{n-1}*2^{(n-1)*outlen} + + (V_{n} mod 2^b)*2^{n*outlen} + */ + mpi_set_ui (value_w, 0); + for (value_j=0; value_j <= value_n; value_j++) + { + /* There is no need to have an explicit offset variable: In + the first round we shall have an offset of 1 and a j of + 0. This is achieved by incrementing SEED_PLUS here. For + the next round offset is implicitly updated by using + SEED_PLUS again. */ + for (i=seedlen-1; i >= 0; i--) + { + seed_plus[i]++; + if (seed_plus[i]) + break; + } + _gcry_md_hash_buffer (hashalgo, digest, seed_plus, seedlen); + + _gcry_mpi_release (tmpval); tmpval = NULL; + ec = _gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, + digest, qbits/8, NULL); + if (ec) + goto leave; + if (value_j == value_n) + mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */ + mpi_lshift (tmpval, tmpval, value_j*qbits); + mpi_add (value_w, value_w, tmpval); + } + + /* Step 11.3: X = W + 2^{L-1} */ + mpi_set_ui (value_x, 0); + mpi_set_highbit (value_x, pbits-1); + mpi_add (value_x, value_x, value_w); + + /* Step 11.4: c = X mod 2q */ + mpi_mul_2exp (tmpval, prime_q, 1); + mpi_mod (tmpval, value_x, tmpval); + + /* Step 11.5: p = X - (c - 1) */ + mpi_sub_ui (tmpval, tmpval, 1); + mpi_sub (prime_p, value_x, tmpval); + + /* Step 11.6: If p < 2^{L-1} skip the primality test. */ + /* Step 11.7 and 11.8: Primality test. */ + if (mpi_get_nbits (prime_p) >= pbits-1 + && check_prime (prime_p, val_2, 64, NULL, NULL) ) + break; /* Yes, P is prime, continue with Step 15. */ + + /* Step 11.9: counter = counter + 1, offset = offset + n + 1. + If counter >= 4L goto Step 5. */ + counter++; + if (counter >= 4*pbits) + goto restart; + } + + /* Step 12: Save p, q, counter and seed. */ + /* log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", */ + /* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */ + /* log_printhex ("fips186-3 seed", seed, seedlen); */ + /* log_printmpi ("fips186-3 p", prime_p); */ + /* log_printmpi ("fips186-3 q", prime_q); */ + + if (r_q) + { + *r_q = prime_q; + prime_q = NULL; + } + if (r_p) + { + *r_p = prime_p; + prime_p = NULL; + } + if (r_counter) + *r_counter = counter; + if (r_seed && r_seedlen) + { + memcpy (seed_plus, seed, seedlen); + *r_seed = seed_plus; + seed_plus = NULL; + *r_seedlen = seedlen; + } + if (r_hashalgo) + *r_hashalgo = hashalgo; + + leave: + _gcry_mpi_release (tmpval); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_w); + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + xfree (seed_plus); + _gcry_mpi_release (val_2); + return ec; +} diff --git a/comm/third_party/libgcrypt/cipher/pubkey-internal.h b/comm/third_party/libgcrypt/cipher/pubkey-internal.h new file mode 100644 index 0000000000..d31e26f392 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/pubkey-internal.h @@ -0,0 +1,105 @@ +/* pubkey-internal.h - Internal defs for pubkey.c + * Copyright (C) 2013 g10 code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifndef GCRY_PUBKEY_INTERNAL_H +#define GCRY_PUBKEY_INTERNAL_H + +/*-- pubkey-util.c --*/ +gpg_err_code_t _gcry_pk_util_parse_flaglist (gcry_sexp_t list, + int *r_flags, + enum pk_encoding *r_encoding); +gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, + unsigned int *r_nbits); +gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, + unsigned long *r_e); +gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, + const char **algo_names, + gcry_sexp_t *r_parms, + int *r_eccflags); +gpg_err_code_t _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, + const char **algo_names, + gcry_sexp_t *r_parms, + struct pk_encoding_ctx *ctx); +void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx, + enum pk_operation op, + unsigned int nbits); +void _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx); +gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, + gcry_mpi_t *ret_mpi, + struct pk_encoding_ctx *ctx); + + + +/*-- rsa-common.c --*/ +gpg_err_code_t +_gcry_rsa_pkcs1_encode_for_enc (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen, + const unsigned char *random_override, + size_t random_override_len); +gpg_err_code_t +_gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen, + unsigned int nbits, gcry_mpi_t value); +gpg_err_code_t +_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen); + +gpg_err_code_t +_gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen, + int algo); +gpg_err_code_t +_gcry_rsa_oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, + const unsigned char *value, size_t valuelen, + const unsigned char *label, size_t labellen, + const void *random_override, size_t random_override_len); +gpg_err_code_t +_gcry_rsa_oaep_decode (unsigned char **r_result, size_t *r_resultlen, + unsigned int nbits, int algo, + gcry_mpi_t value, + const unsigned char *label, size_t labellen); +gpg_err_code_t +_gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, + const unsigned char *value, size_t valuelen, int saltlen, + const void *random_override, size_t random_override_len); +gpg_err_code_t +_gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, + unsigned int nbits, int algo, size_t saltlen); + + + +/*-- dsa-common.c --*/ +void _gcry_dsa_modify_k (gcry_mpi_t k, gcry_mpi_t q, int qbits); +gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level); +gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, + gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, + const unsigned char *h1, + unsigned int h1len, + int halgo, + unsigned int extraloops); + +gpg_err_code_t _gcry_dsa_normalize_hash (gcry_mpi_t input, + gcry_mpi_t *out, + unsigned int qbits); + +/*-- ecc.c --*/ +gpg_err_code_t _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, + mpi_ec_t ec); + + +#endif /*GCRY_PUBKEY_INTERNAL_H*/ diff --git a/comm/third_party/libgcrypt/cipher/pubkey-util.c b/comm/third_party/libgcrypt/cipher/pubkey-util.c new file mode 100644 index 0000000000..7ddef7dc31 --- /dev/null +++ b/comm/third_party/libgcrypt/cipher/pubkey-util.c @@ -0,0 +1,1160 @@ +/* pubkey-util.c - Supporting functions for all pubkey modules. + * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, + * 2007, 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013, 2015 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +/* Callback for the pubkey algorithm code to verify PSS signatures. + OPAQUE is the data provided by the actual caller. The meaning of + TMP depends on the actual algorithm (but there is only RSA); now + for RSA it is the output of running the public key function on the + input. */ +static int +pss_verify_cmp (void *opaque, gcry_mpi_t tmp) +{ + struct pk_encoding_ctx *ctx = opaque; + gcry_mpi_t hash = ctx->verify_arg; + + return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1, + ctx->hash_algo, ctx->saltlen); +} + + +/* Parser for a flag list. On return the encoding is stored at + R_ENCODING and the flags are stored at R_FLAGS. If any of them is + not needed, NULL may be passed. The function returns 0 on success + or an error code. */ +gpg_err_code_t +_gcry_pk_util_parse_flaglist (gcry_sexp_t list, + int *r_flags, enum pk_encoding *r_encoding) +{ + gpg_err_code_t rc = 0; + const char *s; + size_t n; + int i; + int encoding = PUBKEY_ENC_UNKNOWN; + int flags = 0; + int igninvflag = 0; + + for (i = list ? sexp_length (list)-1 : 0; i > 0; i--) + { + s = sexp_nth_data (list, i, &n); + if (!s) + continue; /* Not a data element. */ + + switch (n) + { + case 3: + if (!memcmp (s, "pss", 3) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PSS; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_RAW_FLAG; /* Explicitly given. */ + } + else if (!memcmp (s, "sm2", 3)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_SM2 | PUBKEY_FLAG_RAW_FLAG; + } + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 4: + if (!memcmp (s, "comp", 4)) + flags |= PUBKEY_FLAG_COMP; + else if (!memcmp (s, "oaep", 4) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_OAEP; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "gost", 4)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_GOST; + } + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 5: + if (!memcmp (s, "eddsa", 5)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_EDDSA; + flags |= PUBKEY_FLAG_DJB_TWEAK; + } + else if (!memcmp (s, "pkcs1", 5) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PKCS1; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "param", 5)) + flags |= PUBKEY_FLAG_PARAM; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 6: + if (!memcmp (s, "nocomp", 6)) + flags |= PUBKEY_FLAG_NOCOMP; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 7: + if (!memcmp (s, "rfc6979", 7)) + flags |= PUBKEY_FLAG_RFC6979; + else if (!memcmp (s, "noparam", 7)) + ; /* Ignore - it is the default. */ + else if (!memcmp (s, "prehash", 7)) + flags |= PUBKEY_FLAG_PREHASH; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 8: + if (!memcmp (s, "use-x931", 8)) + flags |= PUBKEY_FLAG_USE_X931; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 9: + if (!memcmp (s, "pkcs1-raw", 9) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PKCS1_RAW; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "djb-tweak", 9)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_DJB_TWEAK; + } + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 10: + if (!memcmp (s, "igninvflag", 10)) + igninvflag = 1; + else if (!memcmp (s, "no-keytest", 10)) + flags |= PUBKEY_FLAG_NO_KEYTEST; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 11: + if (!memcmp (s, "no-blinding", 11)) + flags |= PUBKEY_FLAG_NO_BLINDING; + else if (!memcmp (s, "use-fips186", 11)) + flags |= PUBKEY_FLAG_USE_FIPS186; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 13: + if (!memcmp (s, "use-fips186-2", 13)) + flags |= PUBKEY_FLAG_USE_FIPS186_2; + else if (!memcmp (s, "transient-key", 13)) + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + default: + if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + } + } + + if (r_flags) + *r_flags = flags; + if (r_encoding) + *r_encoding = encoding; + + return rc; +} + + +static int +get_hash_algo (const char *s, size_t n) +{ + static const struct { const char *name; int algo; } hashnames[] = { + { "sha1", GCRY_MD_SHA1 }, + { "md5", GCRY_MD_MD5 }, + { "sha256", GCRY_MD_SHA256 }, + { "ripemd160", GCRY_MD_RMD160 }, + { "rmd160", GCRY_MD_RMD160 }, + { "sha384", GCRY_MD_SHA384 }, + { "sha512", GCRY_MD_SHA512 }, + { "sha224", GCRY_MD_SHA224 }, + { "md2", GCRY_MD_MD2 }, + { "md4", GCRY_MD_MD4 }, + { "tiger", GCRY_MD_TIGER }, + { "haval", GCRY_MD_HAVAL }, + { "sha3-224", GCRY_MD_SHA3_224 }, + { "sha3-256", GCRY_MD_SHA3_256 }, + { "sha3-384", GCRY_MD_SHA3_384 }, + { "sha3-512", GCRY_MD_SHA3_512 }, + { "sm3", GCRY_MD_SM3 }, + { "shake128", GCRY_MD_SHAKE128 }, + { "shake256", GCRY_MD_SHAKE256 }, + { NULL, 0 } + }; + int algo; + int i; + + for (i=0; hashnames[i].name; i++) + { + if ( strlen (hashnames[i].name) == n + && !memcmp (hashnames[i].name, s, n)) + break; + } + if (hashnames[i].name) + algo = hashnames[i].algo; + else + { + /* In case of not listed or dynamically allocated hash + algorithm we fall back to this somewhat slower + method. Further, it also allows to use OIDs as + algorithm names. */ + char *tmpname; + + tmpname = xtrymalloc (n+1); + if (!tmpname) + algo = 0; /* Out of core - silently give up. */ + else + { + memcpy (tmpname, s, n); + tmpname[n] = 0; + algo = _gcry_md_map_name (tmpname); + xfree (tmpname); + } + } + return algo; +} + + +/* Get the "nbits" parameter from an s-expression of the format: + * + * (algo + * (parameter_name_1 ....) + * .... + * (parameter_name_n ....)) + * + * Example: + * + * (rsa + * (nbits 4:2048)) + * + * On success the value for nbits is stored at R_NBITS. If no nbits + * parameter is found, the function returns success and stores 0 at + * R_NBITS. For parsing errors the function returns an error code and + * stores 0 at R_NBITS. + */ +gpg_err_code_t +_gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits) +{ + char buf[50]; + const char *s; + size_t n; + + *r_nbits = 0; + + list = sexp_find_token (list, "nbits", 0); + if (!list) + return 0; /* No NBITS found. */ + + s = sexp_nth_data (list, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + /* NBITS given without a cdr. */ + sexp_release (list); + return GPG_ERR_INV_OBJ; + } + memcpy (buf, s, n); + buf[n] = 0; + *r_nbits = (unsigned int)strtoul (buf, NULL, 0); + sexp_release (list); + return 0; +} + + +/* Get the optional "rsa-use-e" parameter from an s-expression of the + * format: + * + * (algo + * (parameter_name_1 ....) + * .... + * (parameter_name_n ....)) + * + * Example: + * + * (rsa + * (nbits 4:2048) + * (rsa-use-e 2:41)) + * + * On success the value for nbits is stored at R_E. If no rsa-use-e + * parameter is found, the function returns success and stores 65537 at + * R_E. For parsing errors the function returns an error code and + * stores 0 at R_E. + */ +gpg_err_code_t +_gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e) +{ + char buf[50]; + const char *s; + size_t n; + + *r_e = 0; + + list = sexp_find_token (list, "rsa-use-e", 0); + if (!list) + { + *r_e = 65537; /* Not given, use the value generated by old versions. */ + return 0; + } + + s = sexp_nth_data (list, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + /* No value or value too large. */ + sexp_release (list); + return GPG_ERR_INV_OBJ; + } + memcpy (buf, s, n); + buf[n] = 0; + *r_e = strtoul (buf, NULL, 0); + sexp_release (list); + return 0; +} + + +/* Parse a "sig-val" s-expression and store the inner parameter list at + R_PARMS. ALGO_NAMES is used to verify that the algorithm in + "sig-val" is valid. Returns 0 on success and stores a new list at + R_PARMS which must be freed by the caller. On error R_PARMS is set + to NULL and an error code returned. If R_ECCFLAGS is not NULL flag + values are set into it; as of now they are only used with ecc + algorithms. */ +gpg_err_code_t +_gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, + gcry_sexp_t *r_parms, int *r_eccflags) +{ + gpg_err_code_t rc; + gcry_sexp_t l1 = NULL; + gcry_sexp_t l2 = NULL; + char *name = NULL; + int i; + + *r_parms = NULL; + if (r_eccflags) + *r_eccflags = 0; + + /* Extract the signature value. */ + l1 = sexp_find_token (s_sig, "sig-val", 0); + if (!l1) + { + rc = GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */ + goto leave; + } + + l2 = sexp_nth (l1, 1); + if (!l2) + { + rc = GPG_ERR_NO_OBJ; /* No cadr for the sig object. */ + goto leave; + } + name = sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + else if (!strcmp (name, "flags")) + { + /* Skip a "flags" parameter and look again for the algorithm + name. This is not used but here just for the sake of + consistent S-expressions we need to handle it. */ + sexp_release (l2); + l2 = sexp_nth (l1, 2); + if (!l2) + { + rc = GPG_ERR_INV_OBJ; + goto leave; + } + xfree (name); + name = sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + } + + for (i=0; algo_names[i]; i++) + if (!stricmp (name, algo_names[i])) + break; + if (!algo_names[i]) + { + rc = GPG_ERR_CONFLICT; /* "sig-val" uses an unexpected algo. */ + goto leave; + } + if (r_eccflags) + { + if (!strcmp (name, "eddsa")) + *r_eccflags = PUBKEY_FLAG_EDDSA; + if (!strcmp (name, "gost")) + *r_eccflags = PUBKEY_FLAG_GOST; + if (!strcmp (name, "sm2")) + *r_eccflags = PUBKEY_FLAG_SM2; + } + + *r_parms = l2; + l2 = NULL; + rc = 0; + + leave: + xfree (name); + sexp_release (l2); + sexp_release (l1); + return rc; +} + + +/* Parse a "enc-val" s-expression and store the inner parameter list + at R_PARMS. ALGO_NAMES is used to verify that the algorithm in + "enc-val" is valid. Returns 0 on success and stores a new list at + R_PARMS which must be freed by the caller. On error R_PARMS is set + to NULL and an error code returned. If R_ECCFLAGS is not NULL flag + values are set into it; as of now they are only used with ecc + algorithms. + + (enc-val + [(flags [raw, pkcs1, oaep, no-blinding])] + [(hash-algo )] + [(label
\n", fp); + } + else if (n >= 12 && !memcmp (s, "smallexample", 12) + && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n')) + { + writestr (".fi\n.RE\n", "\n", fp); + } + else if (n >= 9 && !memcmp (s, "quotation", 9) + && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n')) + { + writestr ("\\fR\n.RE\n", "xx", fp); + } + /* Now throw away the entire line. */ + s = memchr (rest, '\n', len); + return s? (s-rest)+1 : len; + case 5: /* Handle special comments. */ + for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--) + ; + if (n >= 4 && !memcmp (s, "man:", 4)) + { + s += 4; + n -= 4; + if (htmlmode) + { + if (!strncmp (s, ".RE\n", 4) + || !strncmp (s, ".RS\n", 4)) + ; + else + inf ("unknown special comment \"man:\""); + } + else + { + for (; n && *s != '\n'; n--, s++) + writechr (*s, fp); + writechr ('\n', fp); + } + } + /* Now throw away the entire line. */ + s = memchr (rest, '\n', len); + return s? (s-rest)+1 : len; + case 6: + *eol_action = 1; + break; + case 7: + ignore_args = 1; + break; + case 8: + ignore_args = 1; + if (*rest != '{') + { + err ("opening brace for command '%s' missing", command); + return len; + } + else + { + /* Find closing brace. */ + for (s=rest+1, n=1; *s && n < len; s++, n++) + if (*s == '}') + break; + if (*s != '}') + { + err ("closing brace for command '%s' not found", command); + return len; + } + else + { + size_t rlen = s - (rest + 1); + macro_t m; + + for (m = variablelist; m; m = m->next) + { + if (strlen (m->name) == rlen + && !strncmp (m->name, rest+1, rlen)) + break; + } + if (m) + writestr (m->value, m->value, fp); + else + inf ("texinfo variable '%.*s' is not set", + (int)rlen, rest+1); + } + } + break; + default: + break; + } + } + else /* macro */ + { + macro_t m; + + for (m = macrolist; m ; m = m->next) + if (!strcmp (m->name, command)) + break; + if (m) + { + proc_texi_buffer (fp, m->value, strlen (m->value), + table_level, eol_action); + ignore_args = 1; /* Parameterized macros are not yet supported. */ + } + else + inf ("texinfo command '%s' not supported (%.*s)", command, + (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest); + } + + if (*rest == '{') + { + /* Find matching closing brace. */ + for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++) + if (*s == '{') + i++; + else if (*s == '}') + i--; + if (i) + { + err ("closing brace for command '%s' not found", command); + return len; + } + if (n > 2 && !ignore_args) + proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action); + } + else + n = 0; + + writestr (lead_out, html_out, fp); + + return n; +} + + + +/* Process the string LINE with LEN bytes of Texinfo content. */ +static void +proc_texi_buffer (FILE *fp, const char *line, size_t len, + int *table_level, int *eol_action) +{ + const char *s; + char cmdbuf[256]; + int cmdidx = 0; + int in_cmd = 0; + size_t n; + + for (s=line; *s && len; s++, len--) + { + if (in_cmd) + { + if (in_cmd == 1) + { + switch (*s) + { + case '@': case '{': case '}': + writechr (*s, fp); in_cmd = 0; + break; + case ':': /* Not ending a sentence flag. */ + in_cmd = 0; + break; + case '.': case '!': case '?': /* Ending a sentence. */ + writechr (*s, fp); in_cmd = 0; + break; + case ' ': case '\t': case '\n': /* Non collapsing spaces. */ + writechr (*s, fp); in_cmd = 0; + break; + default: + cmdidx = 0; + cmdbuf[cmdidx++] = *s; + in_cmd++; + break; + } + } + else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n') + { + cmdbuf[cmdidx] = 0; + n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action); + assert (n <= len); + s += n; len -= n; + s--; len++; + in_cmd = 0; + } + else if (cmdidx < sizeof cmdbuf -1) + cmdbuf[cmdidx++] = *s; + else + { + err ("texinfo command too long - ignored"); + in_cmd = 0; + } + } + else if (*s == '@') + in_cmd = 1; + else if (*s == '\n') + { + switch (*eol_action) + { + case 1: /* Create a dummy paragraph. */ + writestr ("\n\\ \n", "\n<-- dummy par -->\n", fp); + break; + default: + writechr (*s, fp); + } + *eol_action = 0; + } + else if (*s == '\\') + writestr ("\\\\", "\\\\", fp); + else + writechr (*s, fp); + } + + if (in_cmd > 1) + { + cmdbuf[cmdidx] = 0; + n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action); + assert (n <= len); + s += n; len -= n; + s--; len++; + /* in_cmd = 0; -- doc only */ + } +} + + +/* Do something with the Texinfo line LINE. */ +static void +parse_texi_line (FILE *fp, const char *line, int *table_level) +{ + int eol_action = 0; + + /* A quick test whether there are any texinfo commands. */ + if (!strchr (line, '@')) + { + /* FIXME: In html mode escape HTML stuff. */ + writestr (line, line, fp); + writechr ('\n', fp); + return; + } + proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action); + writechr ('\n', fp); +} + + +/* Write all the lines LINES to FP. */ +static void +write_content (FILE *fp, line_buffer_t lines) +{ + line_buffer_t line; + int table_level = 0; + + for (line = lines; line; line = line->next) + { + if (line->verbatim) + { + /* FIXME: IN HTML mode we need to employ a parser for roff + * markup. */ + writestr (line->line, line->line, fp); + writechr ('\n', fp); + } + else + { +/* fputs ("TEXI---", fp); */ +/* fputs (line->line, fp); */ +/* fputs ("---\n", fp); */ + parse_texi_line (fp, line->line, &table_level); + } + } +} + + + +static int +is_standard_section (const char *name) +{ + int i; + const char *s; + + for (i=0; (s=standard_sections[i]); i++) + if (!strcmp (s, name)) + return 1; + return 0; +} + + +/* Finish a page; that is sort the data and write it out to the file. */ +static void +finish_page (void) +{ + FILE *fp; + section_buffer_t sect = NULL; + int idx; + const char *s; + int i; + + if (!thepage.name) + return; /* No page active. */ + + if (verbose) + inf ("finishing page '%s'", thepage.name); + + if (opt_select) + { + if (!strcmp (opt_select, thepage.name)) + { + inf ("selected '%s'", thepage.name ); + fp = stdout; + } + else + { + fp = fopen ( "/dev/null", "w" ); + if (!fp) + die ("failed to open /dev/null: %s\n", strerror (errno)); + } + } + else if (opt_store) + { + inf ("writing '%s'", thepage.name ); + fp = fopen ( thepage.name, "w" ); + if (!fp) + die ("failed to create '%s': %s\n", thepage.name, strerror (errno)); + } + else + fp = stdout; + + if (write_th (fp)) + goto leave; + + for (idx=0; (s=standard_sections[idx]); idx++) + { + for (i=0; i < thepage.n_sections; i++) + { + sect = thepage.sections + i; + if (sect->name && !strcmp (s, sect->name)) + break; + } + if (i == thepage.n_sections) + sect = NULL; + + if (sect) + { + write_sh (fp, sect->name); + write_content (fp, sect->lines); + /* Now continue with all non standard sections directly + following this one. */ + for (i++; i < thepage.n_sections; i++) + { + sect = thepage.sections + i; + if (sect->name && is_standard_section (sect->name)) + break; + if (sect->name) + { + write_sh (fp, sect->name); + write_content (fp, sect->lines); + } + } + + } + } + + write_sh (fp, NULL); + if (write_bottom (fp)) + goto leave; + + leave: + if (fp != stdout) + fclose (fp); + free (thepage.name); + thepage.name = NULL; + /* FIXME: Cleanup the content. */ +} + + + + +/* Parse one Texinfo file and create manpages according to the + embedded instructions. */ +static void +parse_file (const char *fname, FILE *fp, char **section_name, int in_pause) +{ + char *line; + int lnr = 0; + /* Fixme: The following state variables don't carry over to include + files. */ + int skip_to_end = 0; /* Used to skip over menu entries. */ + int skip_sect_line = 0; /* Skip after @mansect. */ + int item_indent = 0; /* How far is the current @item indented. */ + + /* Helper to define a macro. */ + char *macroname = NULL; + char *macrovalue = NULL; + size_t macrovaluesize = 0; + size_t macrovalueused = 0; + + line = xmalloc (LINESIZE); + while (fgets (line, LINESIZE, fp)) + { + size_t n = strlen (line); + int got_line = 0; + char *p, *pend; + + lnr++; + if (!n || line[n-1] != '\n') + { + err ("%s:%d: trailing linefeed missing, line too long or " + "embedded Nul character", fname, lnr); + break; + } + line[--n] = 0; + + /* Kludge to allow indentation of tables. */ + for (p=line; *p == ' ' || *p == '\t'; p++) + ; + if (*p) + { + if (*p == '@' && !strncmp (p+1, "item", 4)) + item_indent = p - line; /* Set a new indent level. */ + else if (p - line < item_indent) + item_indent = 0; /* Switch off indention. */ + + if (item_indent) + { + memmove (line, line+item_indent, n - item_indent + 1); + n -= item_indent; + } + } + + + if (*line == '@') + { + for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++) + n++; + while (*p == ' ' || *p == '\t') + p++; + } + else + p = line; + + /* Take action on macro. */ + if (macroname) + { + if (n == 4 && !memcmp (line, "@end", 4) + && (line[4]==' '||line[4]=='\t'||!line[4]) + && !strncmp (p, "macro", 5) + && (p[5]==' '||p[5]=='\t'||!p[5])) + { + if (macrovalueused) + macrovalue[--macrovalueused] = 0; /* Kill the last LF. */ + macrovalue[macrovalueused] = 0; /* Terminate macro. */ + macrovalue = xrealloc (macrovalue, macrovalueused+1); + + set_macro (macroname, macrovalue); + macrovalue = NULL; + free (macroname); + macroname = NULL; + } + else + { + if (macrovalueused + strlen (line) + 2 >= macrovaluesize) + { + macrovaluesize += strlen (line) + 256; + macrovalue = xrealloc (macrovalue, macrovaluesize); + } + strcpy (macrovalue+macrovalueused, line); + macrovalueused += strlen (line); + macrovalue[macrovalueused++] = '\n'; + } + continue; + } + + + if (n >= 5 && !memcmp (line, "@node", 5) + && (line[5]==' '||line[5]=='\t'||!line[5])) + { + /* Completey ignore @node lines. */ + continue; + } + + + if (skip_sect_line) + { + skip_sect_line = 0; + if (!strncmp (line, "@section", 8) + || !strncmp (line, "@subsection", 11) + || !strncmp (line, "@chapheading", 12)) + continue; + } + + /* We only parse lines we need and ignore the rest. There are a + few macros used to control this as well as one @ifset + command. Parts we know about are saved away into containers + separate for each section. */ + + /* First process ifset/ifclear commands. */ + if (*line == '@') + { + if (n == 6 && !memcmp (line, "@ifset", 6) + && (line[6]==' '||line[6]=='\t')) + { + for (p=line+7; *p == ' ' || *p == '\t'; p++) + ; + if (!*p) + { + err ("%s:%d: name missing after \"@ifset\"", fname, lnr); + continue; + } + for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++) + ; + *pend = 0; /* Ignore rest of the line. */ + push_condition (p, 1, fname, lnr); + continue; + } + else if (n == 8 && !memcmp (line, "@ifclear", 8) + && (line[8]==' '||line[8]=='\t')) + { + for (p=line+9; *p == ' ' || *p == '\t'; p++) + ; + if (!*p) + { + err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr); + continue; + } + for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++) + ; + *pend = 0; /* Ignore rest of the line. */ + push_condition (p, 0, fname, lnr); + continue; + } + else if (n == 4 && !memcmp (line, "@end", 4) + && (line[4]==' '||line[4]=='\t') + && !strncmp (p, "ifset", 5) + && (p[5]==' '||p[5]=='\t'||!p[5])) + { + pop_condition (1, fname, lnr); + continue; + } + else if (n == 4 && !memcmp (line, "@end", 4) + && (line[4]==' '||line[4]=='\t') + && !strncmp (p, "ifclear", 7) + && (p[7]==' '||p[7]=='\t'||!p[7])) + { + pop_condition (0, fname, lnr); + continue; + } + } + + /* Take action on ifset/ifclear. */ + if (!cond_is_active) + continue; + + /* Process commands. */ + if (*line == '@') + { + if (skip_to_end + && n == 4 && !memcmp (line, "@end", 4) + && (line[4]==' '||line[4]=='\t'||!line[4])) + { + skip_to_end = 0; + } + else if (cond_in_verbatim) + { + got_line = 1; + } + else if (n == 6 && !memcmp (line, "@macro", 6)) + { + macroname = xstrdup (p); + macrovalue = xmalloc ((macrovaluesize = 1024)); + macrovalueused = 0; + } + else if (n == 4 && !memcmp (line, "@set", 4)) + { + set_variable (p); + } + else if (n == 8 && !memcmp (line, "@manpage", 8)) + { + free (*section_name); + *section_name = NULL; + finish_page (); + start_page (p); + in_pause = 0; + } + else if (n == 8 && !memcmp (line, "@mansect", 8)) + { + if (!thepage.name) + err ("%s:%d: section outside of a man page", fname, lnr); + else + { + free (*section_name); + *section_name = ascii_strupr (xstrdup (p)); + in_pause = 0; + skip_sect_line = 1; + } + } + else if (n == 9 && !memcmp (line, "@manpause", 9)) + { + if (!*section_name) + err ("%s:%d: pausing outside of a man section", fname, lnr); + else if (in_pause) + err ("%s:%d: already pausing", fname, lnr); + else + in_pause = 1; + } + else if (n == 8 && !memcmp (line, "@mancont", 8)) + { + if (!*section_name) + err ("%s:%d: continue outside of a man section", fname, lnr); + else if (!in_pause) + err ("%s:%d: continue while not pausing", fname, lnr); + else + in_pause = 0; + } + else if (n == 5 && !memcmp (line, "@menu", 5) + && (line[5]==' '||line[5]=='\t'||!line[5])) + { + skip_to_end = 1; + } + else if (n == 8 && !memcmp (line, "@include", 8) + && (line[8]==' '||line[8]=='\t'||!line[8])) + { + char *incname = xstrdup (p); + FILE *incfp = fopen (incname, "r"); + + if (!incfp && opt_include && *opt_include && *p != '/') + { + free (incname); + incname = xmalloc (strlen (opt_include) + 1 + + strlen (p) + 1); + strcpy (incname, opt_include); + if ( incname[strlen (incname)-1] != '/' ) + strcat (incname, "/"); + strcat (incname, p); + incfp = fopen (incname, "r"); + } + + if (!incfp) + err ("can't open include file '%s': %s", + incname, strerror (errno)); + else + { + parse_file (incname, incfp, section_name, in_pause); + fclose (incfp); + } + free (incname); + } + else if (n == 4 && !memcmp (line, "@bye", 4) + && (line[4]==' '||line[4]=='\t'||!line[4])) + { + break; + } + else if (!skip_to_end) + got_line = 1; + } + else if (!skip_to_end) + got_line = 1; + + if (got_line && cond_in_verbatim) + add_content (*section_name, line, 1); + else if (got_line && thepage.name && *section_name && !in_pause) + add_content (*section_name, line, 0); + + } + if (ferror (fp)) + err ("%s:%d: read error: %s", fname, lnr, strerror (errno)); + free (macroname); + free (macrovalue); + free (line); +} + + +static void +top_parse_file (const char *fname, FILE *fp) +{ + char *section_name = NULL; /* Name of the current section or NULL + if not in a section. */ + macro_t m; + + while (macrolist) + { + macro_t next = macrolist->next; + free (macrolist->value); + free (macrolist); + macrolist = next; + } + while (variablelist) + { + macro_t next = variablelist->next; + free (variablelist->value); + free (variablelist); + variablelist = next; + } + for (m=predefinedmacrolist; m; m = m->next) + set_macro (m->name, xstrdup ("1")); + cond_is_active = 1; + cond_in_verbatim = 0; + + parse_file (fname, fp, §ion_name, 0); + free (section_name); + finish_page (); +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + const char *s; + + opt_source = "GNU"; + opt_release = ""; + + /* Define default macros. The trick is that these macros are not + defined when using the actual texinfo renderer. */ + add_predefined_macro ("isman"); + add_predefined_macro ("manverb"); + + /* Option parsing. */ + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + puts ( + "Usage: " PGM " [OPTION] [FILE]\n" + "Extract man pages from a Texinfo source.\n\n" + " --html render output as HTML\n" + " --source NAME use NAME as source field\n" + " --release STRING use STRING as the release field\n" + " --date EPOCH use EPOCH as publication date\n" + " --store write output using @manpage name\n" + " --select NAME only output pages with @manpage NAME\n" + " --verbose enable extra informational output\n" + " --debug enable additional debug output\n" + " --help display this help and exit\n" + " -I DIR also search in include DIR\n" + " -D MACRO define MACRO to 1\n\n" + "With no FILE, or when FILE is -, read standard input.\n\n" + "Report bugs to ."); + exit (0); + } + else if (!strcmp (*argv, "--version")) + { + puts (PGM " " VERSION "\n" + "Copyright (C) 2005, 2017 g10 Code GmbH\n" + "This program comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions. See the file COPYING for details."); + exit (0); + } + else if (!strcmp (*argv, "--html")) + { + htmlmode = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--quiet")) + { + quiet = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--source")) + { + argc--; argv++; + if (argc) + { + opt_source = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "--release")) + { + argc--; argv++; + if (argc) + { + opt_release = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "--date")) + { + argc--; argv++; + if (argc) + { + opt_date = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "--store")) + { + opt_store = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--select")) + { + argc--; argv++; + if (argc) + { + opt_select = strrchr (*argv, '/'); + if (opt_select) + opt_select++; + else + opt_select = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "-I")) + { + argc--; argv++; + if (argc) + { + opt_include = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "-D")) + { + argc--; argv++; + if (argc) + { + add_predefined_macro (*argv); + argc--; argv++; + } + } + } + + if (argc > 1) + die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n"); + + /* Take care of supplied timestamp for reproducible builds. See + * https://reproducible-builds.org/specs/source-date-epoch/ */ + if (!opt_date && (s = getenv ("SOURCE_DATE_EPOCH")) && *s) + opt_date = s; + + /* Start processing. */ + if (argc && strcmp (*argv, "-")) + { + FILE *fp = fopen (*argv, "rb"); + if (!fp) + die ("%s:0: can't open file: %s", *argv, strerror (errno)); + top_parse_file (*argv, fp); + fclose (fp); + } + else + top_parse_file ("-", stdin); + + return !!any_error; +} + + +/* +Local Variables: +compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c" +End: +*/ diff --git a/comm/third_party/libgpg-error/lang/Makefile.am b/comm/third_party/libgpg-error/lang/Makefile.am new file mode 100644 index 0000000000..3e380d5df9 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/Makefile.am @@ -0,0 +1,22 @@ +# Makefile.am for libgpg-error. +# Copyright (C) 2003, 2006 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +SUBDIRS = cl + +EXTRA_DIST = README diff --git a/comm/third_party/libgpg-error/lang/Makefile.in b/comm/third_party/libgpg-error/lang/Makefile.in new file mode 100644 index 0000000000..0510d18161 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/Makefile.in @@ -0,0 +1,691 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for libgpg-error. +# Copyright (C) 2003, 2006 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lang +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ + $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/estream.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnupg-misc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/threadlib.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in README +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GPG_ERROR_CONFIG_CFLAGS = @GPG_ERROR_CONFIG_CFLAGS@ +GPG_ERROR_CONFIG_HOST = @GPG_ERROR_CONFIG_HOST@ +GPG_ERROR_CONFIG_LIBS = @GPG_ERROR_CONFIG_LIBS@ +GPG_ERROR_CONFIG_LIBS_PRIVATE = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +GPG_ERROR_CONFIG_MT_CFLAGS = @GPG_ERROR_CONFIG_MT_CFLAGS@ +GPG_ERROR_CONFIG_MT_LIBS = @GPG_ERROR_CONFIG_MT_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALLSHELLPATH = @INSTALLSHELLPATH@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGPG_ERROR_LT_AGE = @LIBGPG_ERROR_LT_AGE@ +LIBGPG_ERROR_LT_CURRENT = @LIBGPG_ERROR_LT_CURRENT@ +LIBGPG_ERROR_LT_REVISION = @LIBGPG_ERROR_LT_REVISION@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBREADLINE = @LIBREADLINE@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_NETWORK = @LIB_NETWORK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = cl +EXTRA_DIST = README +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu lang/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgpg-error/lang/README b/comm/third_party/libgpg-error/lang/README new file mode 100644 index 0000000000..2d13e21b93 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/README @@ -0,0 +1,8 @@ +Language Support for libgpg-error +--------------------------------- + +This directory contains support for other languages than C. + +Directory Language + +cl Common Lisp diff --git a/comm/third_party/libgpg-error/lang/cl/Makefile.am b/comm/third_party/libgpg-error/lang/cl/Makefile.am new file mode 100644 index 0000000000..0535feec08 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/Makefile.am @@ -0,0 +1,40 @@ +# Makefile.am for libgpg-error. +# Copyright (C) 2003, 2006 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +distributed_clfiles = gpg-error.asd \ + gpg-error-package.lisp gpg-error.lisp + +generated_clfiles = gpg-error-codes.lisp + +clfiles = $(distributed_clfiles) $(generated_clfiles) + +# FIXME: Should be configurable. +clfilesdir = $(datadir)/common-lisp/source/gpg-error +dist_clfiles_DATA = $(distributed_clfiles) +nodist_clfiles_DATA = $(generated_clfiles) + +EXTRA_DIST = README mkerrcodes.awk +CLEANFILES = gpg-error-codes.lisp + +codes_file = $(top_srcdir)/src/err-codes.h.in +errno_file = $(top_srcdir)/src/errnos.in + +gpg-error-codes.lisp: Makefile mkerrcodes.awk $(codes_file) $(errno_file) + echo '@errnos@' | cat $(codes_file) - $(errno_file) \ + | $(AWK) -f $(srcdir)/mkerrcodes.awk >$@ diff --git a/comm/third_party/libgpg-error/lang/cl/Makefile.in b/comm/third_party/libgpg-error/lang/cl/Makefile.in new file mode 100644 index 0000000000..f183b4b4df --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/Makefile.in @@ -0,0 +1,610 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for libgpg-error. +# Copyright (C) 2003, 2006 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lang/cl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ + $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/estream.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnupg-misc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/threadlib.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_clfiles_DATA) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = gpg-error.asd +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(clfilesdir)" "$(DESTDIR)$(clfilesdir)" +DATA = $(dist_clfiles_DATA) $(nodist_clfiles_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/gpg-error.asd.in \ + README +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GPG_ERROR_CONFIG_CFLAGS = @GPG_ERROR_CONFIG_CFLAGS@ +GPG_ERROR_CONFIG_HOST = @GPG_ERROR_CONFIG_HOST@ +GPG_ERROR_CONFIG_LIBS = @GPG_ERROR_CONFIG_LIBS@ +GPG_ERROR_CONFIG_LIBS_PRIVATE = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +GPG_ERROR_CONFIG_MT_CFLAGS = @GPG_ERROR_CONFIG_MT_CFLAGS@ +GPG_ERROR_CONFIG_MT_LIBS = @GPG_ERROR_CONFIG_MT_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALLSHELLPATH = @INSTALLSHELLPATH@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGPG_ERROR_LT_AGE = @LIBGPG_ERROR_LT_AGE@ +LIBGPG_ERROR_LT_CURRENT = @LIBGPG_ERROR_LT_CURRENT@ +LIBGPG_ERROR_LT_REVISION = @LIBGPG_ERROR_LT_REVISION@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBREADLINE = @LIBREADLINE@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_NETWORK = @LIB_NETWORK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +distributed_clfiles = gpg-error.asd \ + gpg-error-package.lisp gpg-error.lisp + +generated_clfiles = gpg-error-codes.lisp +clfiles = $(distributed_clfiles) $(generated_clfiles) + +# FIXME: Should be configurable. +clfilesdir = $(datadir)/common-lisp/source/gpg-error +dist_clfiles_DATA = $(distributed_clfiles) +nodist_clfiles_DATA = $(generated_clfiles) +EXTRA_DIST = README mkerrcodes.awk +CLEANFILES = gpg-error-codes.lisp +codes_file = $(top_srcdir)/src/err-codes.h.in +errno_file = $(top_srcdir)/src/errnos.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/cl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu lang/cl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +gpg-error.asd: $(top_builddir)/config.status $(srcdir)/gpg-error.asd.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_clfilesDATA: $(dist_clfiles_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_clfiles_DATA)'; test -n "$(clfilesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(clfilesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(clfilesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(clfilesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(clfilesdir)" || exit $$?; \ + done + +uninstall-dist_clfilesDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_clfiles_DATA)'; test -n "$(clfilesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(clfilesdir)'; $(am__uninstall_files_from_dir) +install-nodist_clfilesDATA: $(nodist_clfiles_DATA) + @$(NORMAL_INSTALL) + @list='$(nodist_clfiles_DATA)'; test -n "$(clfilesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(clfilesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(clfilesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(clfilesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(clfilesdir)" || exit $$?; \ + done + +uninstall-nodist_clfilesDATA: + @$(NORMAL_UNINSTALL) + @list='$(nodist_clfiles_DATA)'; test -n "$(clfilesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(clfilesdir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(clfilesdir)" "$(DESTDIR)$(clfilesdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_clfilesDATA install-nodist_clfilesDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_clfilesDATA uninstall-nodist_clfilesDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_clfilesDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man \ + install-nodist_clfilesDATA install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am uninstall-dist_clfilesDATA \ + uninstall-nodist_clfilesDATA + +.PRECIOUS: Makefile + + +gpg-error-codes.lisp: Makefile mkerrcodes.awk $(codes_file) $(errno_file) + echo '@errnos@' | cat $(codes_file) - $(errno_file) \ + | $(AWK) -f $(srcdir)/mkerrcodes.awk >$@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgpg-error/lang/cl/README b/comm/third_party/libgpg-error/lang/cl/README new file mode 100644 index 0000000000..660508bd51 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/README @@ -0,0 +1,22 @@ +Common Lisp Support for libgpg-error +------------------------------------ + +Requirements: + +ASDF Packaging Support +CFFI Foreign Function Interface + +Use with: + +> (asdf:operate 'asdf:load-op ':gpg-error) +> (use-package :gpg-error) + + +TODO +---- + +* We probably should define a condition base class. Currently, we do + this in the user code only (eg in GPGME). + +* Some lispy convenience functions as need arises, for example for + output. diff --git a/comm/third_party/libgpg-error/lang/cl/gpg-error-package.lisp b/comm/third_party/libgpg-error/lang/cl/gpg-error-package.lisp new file mode 100644 index 0000000000..73adca0d7e --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/gpg-error-package.lisp @@ -0,0 +1,64 @@ +;;;; libgpg-error-package.lisp + +;;; Copyright (C) 2006 g10 Code GmbH +;;; +;;; This file is part of libgpg-error. +;;; +;;; libgpg-error is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU Lesser General Public License +;;; as published by the Free Software Foundation; either version 2.1 of +;;; the License, or (at your option) any later version. +;;; +;;; libgpg-error is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; Lesser General Public License for more details. +;;; +;;; You should have received a copy of the GNU Lesser General Public +;;; License along with libgpg-error; if not, write to the Free +;;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;;; 02111-1307, USA. + +;;; Conventions +;;; +;;; Error sources and codes are represented as keywords like +;;; :gpg-err-source-gpg and :gpg-err-unknown-packet. +;;; +;;; Errors are represented as lists '(SOURCE CODE). Other +;;; representations are also accepted in some places. +;;; +;;; The following functions are defined which are not defined in the C API: +;;; gpg-err-source-as-key, gpg-err-source-as-value +;;; gpg-err-code-as-key, gpg-err-code-as-value +;;; gpg-err-canonicalize, gpg-err-as-value +;;; Conversion between keywords and values for error sources and codes. +;;; +;;; The following functions from the C API are omitted: +;;; gpg-strerror-r +;;; +;;; The following features work slightly differently: +;;; *gpg-err-source-default* is a dynamic variable that can be set to +;;; change the default for gpg-error. + +(defpackage #:gpg-error + (:use #:common-lisp #:cffi) + + (:export :gpg-err-code-as-key + :gpg-err-code-as-value + :gpg-err-source-as-key + :gpg-err-source-as-value + :gpg-err-canonicalize + :gpg-err-as-value + :gpg-err-make + :*gpg-err-source-default* + :gpg-error + :gpg-err-code + :gpg-err-source + :gpg-strerror + :gpg-strsource + :gpg-err-code-from-errno + :gpg-err-code-to-errno + :gpg-err-code-from-syserror + :gpg-err-make-from-errno + :gpg-error-from-errno + :gpg-error-from-syserror)) diff --git a/comm/third_party/libgpg-error/lang/cl/gpg-error.asd b/comm/third_party/libgpg-error/lang/cl/gpg-error.asd new file mode 100644 index 0000000000..8fa8d9e81b --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/gpg-error.asd @@ -0,0 +1,36 @@ +;;; -*- Mode: lisp -*- + +;;; Copyright (C) 2006 g10 Code GmbH +;;; +;;; This file is part of libgpg-error. +;;; +;;; libgpg-error is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU Lesser General Public License +;;; as published by the Free Software Foundation; either version 2.1 of +;;; the License, or (at your option) any later version. +;;; +;;; libgpg-error is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; Lesser General Public License for more details. +;;; +;;; You should have received a copy of the GNU Lesser General Public +;;; License along with libgpg-error; if not, write to the Free +;;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;;; 02111-1307, USA. + +(defpackage #:gpg-error-system + (:use #:common-lisp #:asdf)) + +(in-package #:gpg-error-system) + +(defsystem gpg-error + :description "Common error values for all GnuPG components." + :author "g10 Code GmbH" + :version "1.42" + :licence "LGPL" + :depends-on ("cffi") + :components ((:file "gpg-error-package") + (:file "gpg-error-codes" + :depends-on ("gpg-error-package")) + (:file "gpg-error" :depends-on ("gpg-error-codes")))) diff --git a/comm/third_party/libgpg-error/lang/cl/gpg-error.asd.in b/comm/third_party/libgpg-error/lang/cl/gpg-error.asd.in new file mode 100644 index 0000000000..3cb7e96b76 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/gpg-error.asd.in @@ -0,0 +1,36 @@ +;;; -*- Mode: lisp -*- + +;;; Copyright (C) 2006 g10 Code GmbH +;;; +;;; This file is part of libgpg-error. +;;; +;;; libgpg-error is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU Lesser General Public License +;;; as published by the Free Software Foundation; either version 2.1 of +;;; the License, or (at your option) any later version. +;;; +;;; libgpg-error is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; Lesser General Public License for more details. +;;; +;;; You should have received a copy of the GNU Lesser General Public +;;; License along with libgpg-error; if not, write to the Free +;;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;;; 02111-1307, USA. + +(defpackage #:gpg-error-system + (:use #:common-lisp #:asdf)) + +(in-package #:gpg-error-system) + +(defsystem gpg-error + :description "Common error values for all GnuPG components." + :author "g10 Code GmbH" + :version "@VERSION@" + :licence "LGPL" + :depends-on ("cffi") + :components ((:file "gpg-error-package") + (:file "gpg-error-codes" + :depends-on ("gpg-error-package")) + (:file "gpg-error" :depends-on ("gpg-error-codes")))) diff --git a/comm/third_party/libgpg-error/lang/cl/gpg-error.lisp b/comm/third_party/libgpg-error/lang/cl/gpg-error.lisp new file mode 100644 index 0000000000..cad2532dec --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/gpg-error.lisp @@ -0,0 +1,233 @@ +;;;; libgpg-error.lisp + +;;; Copyright (C) 2006 g10 Code GmbH +;;; +;;; This file is part of libgpg-error. +;;; +;;; libgpg-error is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU Lesser General Public License +;;; as published by the Free Software Foundation; either version 2.1 of +;;; the License, or (at your option) any later version. +;;; +;;; libgpg-error is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; Lesser General Public License for more details. +;;; +;;; You should have received a copy of the GNU Lesser General Public +;;; License along with libgpg-error; if not, write to the Free +;;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;;; 02111-1307, USA. + +;;; Set up the library. + +(in-package :gpg-error) + +(define-foreign-library libgpg-error + (:unix "libgpg-error.so") + (t (:default "libgpg-error"))) + +(use-foreign-library libgpg-error) + +;;; System dependencies. + +(defctype size-t :unsigned-int "The system size_t type.") + +;;; Error sources. + +(defcenum gpg-err-source-t + "The GPG error source type." + (:gpg-err-source-unknown 0) + (:gpg-err-source-gcrypt 1) + (:gpg-err-source-gpg 2) + (:gpg-err-source-gpgsm 3) + (:gpg-err-source-gpgagent 4) + (:gpg-err-source-pinentry 5) + (:gpg-err-source-scd 6) + (:gpg-err-source-gpgme 7) + (:gpg-err-source-keybox 8) + (:gpg-err-source-ksba 9) + (:gpg-err-source-dirmngr 10) + (:gpg-err-source-gsti 11) + (:gpg-err-source-any 31) + (:gpg-err-source-user-1 32) + (:gpg-err-source-user-2 33) + (:gpg-err-source-user-3 34) + (:gpg-err-source-user-4 35)) + +(defconstant +gpg-err-source-dim+ 256) + +;;; The error code type gpg-err-code-t. + +;;; libgpg-error-codes.lisp is loaded by ASDF. + +(defctype gpg-error-t :unsigned-int "The GPG error code type.") + +;;; Bit mask manipulation constants. + +(defconstant +gpg-err-code-mask+ (- +gpg-err-code-dim+ 1)) + +(defconstant +gpg-err-source-mask+ (- +gpg-err-source-dim+ 1)) +(defconstant +gpg-err-source-shift+ 24) + +;;; Constructor and accessor functions. + +;;; If we had in-library versions of our static inlines, we wouldn't +;;; need to replicate them here. Oh well. + +(defun c-gpg-err-make (source code) + "Construct an error value from an error code and source. + Within a subsystem, use gpg-error instead." + (logior + (ash (logand source +gpg-err-source-mask+) + +gpg-err-source-shift+) + (logand code +gpg-err-code-mask+))) + +(defun c-gpg-err-code (err) + "retrieve the error code from an error value." + (logand err +gpg-err-code-mask+)) + +(defun c-gpg-err-source (err) + "retrieve the error source from an error value." + (logand (ash err (- +gpg-err-source-shift+)) + +gpg-err-source-mask+)) + +;;; String functions. + +(defcfun ("gpg_strerror" c-gpg-strerror) :string + (err gpg-error-t)) + +(defcfun ("gpg_strsource" c-gpg-strsource) :string + (err gpg-error-t)) + +;;; Mapping of system errors (errno). + +(defcfun ("gpg_err_code_from_errno" c-gpg-err-code-from-errno) gpg-err-code-t + (err :int)) + +(defcfun ("gpg_err_code_to_errno" c-gpg-err-code-to-errno) :int + (code gpg-err-code-t)) + +(defcfun ("gpg_err_code_from_syserror" + c-gpg-err-code-from-syserror) gpg-err-code-t) + +;;; Self-documenting convenience functions. + +;;; See below. + +;;; +;;; +;;; Lispy interface. +;;; +;;; + +;;; Low-level support functions. + +(defun gpg-err-code-as-value (code-key) + (foreign-enum-value 'gpg-err-code-t code-key)) + +(defun gpg-err-code-as-key (code) + (foreign-enum-keyword 'gpg-err-code-t code)) + +(defun gpg-err-source-as-value (source-key) + (foreign-enum-value 'gpg-err-source-t source-key)) + +(defun gpg-err-source-as-key (source) + (foreign-enum-keyword 'gpg-err-source-t source)) + +(defun gpg-err-canonicalize (err) + "Canonicalize the error value err." + (gpg-err-make (gpg-err-source err) (gpg-err-code err))) + +(defun gpg-err-as-value (err) + "Get the integer representation of the error value ERR." + (let ((error (gpg-err-canonicalize err))) + (c-gpg-err-make (gpg-err-source-as-value (gpg-err-source error)) + (gpg-err-code-as-value (gpg-err-code error))))) + +;;; Constructor and accessor functions. + +(defun gpg-err-make (source code) + "Construct an error value from an error code and source. + Within a subsystem, use gpg-error instead." + ;; As an exception to the rule, the function gpg-err-make will use + ;; the error source value as is when provided as integer, instead of + ;; parsing it as an error value. + (list (if (integerp source) + (gpg-err-source-as-key source) + (gpg-err-source source)) + (gpg-err-code code))) + +(defvar *gpg-err-source-default* :gpg-err-source-unknown + "define this to specify a default source for gpg-error.") + +(defun gpg-error (code) + "Construct an error value from an error code, using the default source." + (gpg-err-make *gpg-err-source-default* code)) + +(defun gpg-err-code (err) + "Retrieve an error code from the error value ERR." + (cond ((listp err) (second err)) + ((keywordp err) err) ; FIXME + (t (gpg-err-code-as-key (c-gpg-err-code err))))) + +(defun gpg-err-source (err) + "Retrieve an error source from the error value ERR." + (cond ((listp err) (first err)) + ((keywordp err) err) ; FIXME + (t (gpg-err-source-as-key (c-gpg-err-source err))))) + +;;; String functions. + +(defun gpg-strerror (err) + "Return a string containig a description of the error code." + (c-gpg-strerror (gpg-err-as-value err))) + +;;; FIXME: maybe we should use this as the actual implementation for +;;; gpg-strerror. + +;; (defcfun ("gpg_strerror_r" c-gpg-strerror-r) :int +;; (err gpg-error-t) +;; (buf :string) +;; (buflen size-t)) + +;; (defun gpg-strerror-r (err) +;; "Return a string containig a description of the error code." +;; (with-foreign-pointer-as-string (errmsg 256 errmsg-size) +;; (c-gpg-strerror-r (gpg-err-code-as-value (gpg-err-code err)) +;; errmsg errmsg-size))) + +(defun gpg-strsource (err) + "Return a string containig a description of the error source." + (c-gpg-strsource (gpg-err-as-value err))) + +;;; Mapping of system errors (errno). + +(defun gpg-err-code-from-errno (err) + "Retrieve the error code for the system error. If the system error + is not mapped, :gpg-err-unknown-errno is returned." + (gpg-err-code-as-key (c-gpg-err-code-from-errno err))) + +(defun gpg-err-code-to-errno (code) + "Retrieve the system error for the error code. If this is not a + system error, 0 is returned." + (c-gpg-err-code-to-errno (gpg-err-code code))) + +(defun gpg-err-code-from-syserror () + "Retrieve the error code directly from the system ERRNO. If the system error + is not mapped, :gpg-err-unknown-errno is returned and + :gpg-err-missing-errno if ERRNO has the value 0." + (gpg-err-code-as-key (c-gpg-err-code-from-syserror))) + + +;;; Self-documenting convenience functions. + +(defun gpg-err-make-from-errno (source err) + (gpg-err-make source (gpg-err-code-from-errno err))) + +(defun gpg-error-from-errno (err) + (gpg-error (gpg-err-code-from-errno err))) + +(defun gpg-error-from-syserror () + (gpg-error (gpg-err-code-from-syserror))) + diff --git a/comm/third_party/libgpg-error/lang/cl/mkerrcodes.awk b/comm/third_party/libgpg-error/lang/cl/mkerrcodes.awk new file mode 100644 index 0000000000..9a1fc18c55 --- /dev/null +++ b/comm/third_party/libgpg-error/lang/cl/mkerrcodes.awk @@ -0,0 +1,154 @@ +# mkerrcodes.awk +# Copyright (C) 2004, 2005, 2006 g10 Code GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# As a special exception, g10 Code GmbH gives unlimited permission to +# copy, distribute and modify the lisp source files that are the output +# of mkerrcodes.awk. You need not follow the terms of the GNU General +# Public License when using or distributing such scripts, even though +# portions of the text of mkerrcodes.awk appear in them. The GNU +# General Public License (GPL) does govern all other use of the material +# that constitutes the mkerrcodes.awk program. +# +# Certain portions of the mkerrcodes.awk source text are designed to be +# copied (in certain cases, depending on the input) into the output of +# mkerrcodes.awk. We call these the "data" portions. The rest of the +# mkerrcodes.awk source text consists of comments plus executable code +# that decides which of the data portions to output in any given case. +# We call these comments and executable code the "non-data" portions. +# mkerrcodes.awk never copies any of the non-data portions into its output. +# +# This special exception to the GPL applies to versions of mkerrcodes.awk +# released by g10 Code GmbH. When you make and distribute a modified version +# of mkerrcodes.awk, you may extend this special exception to the GPL to +# apply to your modified version as well, *unless* your modified version +# has the potential to copy into its output some of the text that was the +# non-data portion of the version that you started with. (In other words, +# unless your change moves or copies text from the non-data portions to the +# data portions.) If your modification has such potential, you must delete +# any notice of this special exception to the GPL from your modified version. + +# The input file is in the following format: +# [CODE SYMBOL...] +# @errnos@ +# [CODE SYMBOL...] +# +# The difference between the sections is how symbol is transformed. +# The second section gets GPG_ERR_ prepended before processing. +# +# Comments (starting with # and ending at the end of the line) are removed, +# as is trailing whitespace. + +BEGIN { + FS="[ \t]+"; + print ";;;; Output of mkerrcodes.awk. DO NOT EDIT."; + print ""; + print ";;; Copyright (C) 2006 g10 Code GmbH"; + print ";;;"; + print ";;; This file is part of libgpg-error."; + print ";;;"; + print ";;; libgpg-error is free software; you can redistribute it and/or"; + print ";;; modify it under the terms of the GNU Lesser General Public License"; + print ";;; as published by the Free Software Foundation; either version 2.1 of"; + print ";;; the License, or (at your option) any later version."; + print ";;;"; + print ";;; libgpg-error is distributed in the hope that it will be useful, but"; + print ";;; WITHOUT ANY WARRANTY; without even the implied warranty of"; + print ";;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU"; + print ";;; Lesser General Public License for more details."; + print ";;;"; + print ";;; You should have received a copy of the GNU Lesser General Public"; + print ";;; License along with libgpg-error; if not, write to the Free"; + print ";;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA"; + print ";;; 02111-1307, USA."; + print ""; + + header = 1; + errnos = 0; +} + +/^#/ { next; } + +header { + if (errnos) + { + if ($1 ~ /^[0123456789]+$/) + { + header = 0; + + print ""; + print " ;; The following error codes map system errors."; + } + } + else + { + if ($1 ~ /^[0123456789]+$/) + { + header = 0; + + print "(in-package :gpg-error)"; + print ""; + print ";;; The error code type gpg-err-code-t."; + print ""; + print ";;; This is used for system error codes."; + print "(defconstant +gpg-err-system-error+ (ash 1 15))"; + print ""; + print ";;; This is one more than the largest allowed entry."; + print "(defconstant +gpg-err-code-dim+ 65536)"; + print ""; + print ";;; A helper macro to have the keyword values evaluated."; + print "(defmacro defcenum-eval (type doc &rest vals)"; + print " `(defcenum ,type ,doc"; + print " ,@(loop for v in vals"; + print " collect `(,(first v) ,(eval (second v))))))"; + print ""; + print "(defcenum-eval gpg-err-code-t"; + print " \"The GPG error code type.\""; + } + } +} + +!header { + sub (/#.+/, ""); + sub (/[ ]+$/, ""); # Strip trailing space and tab characters. + + if (/^$/) + next; + + # The following can happen for GPG_ERR_CODE_DIM. + if ($1 == "") + next; + + if (/^@errnos@$/) + { + header = 1; + errnos = 1; + next; + } + + $2 = tolower($2); + gsub ("_", "-", $2); + + if (errnos) + print " (:gpg-err-" $2 " (logior +gpg-err-system-error+ " $1 "))"; + else + print " (:" $2 " " $1 ")"; +} + +END { + # I am very sorry to break lisp coding style here. + print ")"; +} diff --git a/comm/third_party/libgpg-error/libgpg-error.spec b/comm/third_party/libgpg-error/libgpg-error.spec new file mode 100644 index 0000000000..6486c28850 --- /dev/null +++ b/comm/third_party/libgpg-error/libgpg-error.spec @@ -0,0 +1,57 @@ +# This is a template. The dist target uses it to create the real file. +Summary: libgpg-error +Name: libgpg-error +Version: 1.42 +Release: 1 +URL: ftp://ftp.gnupg.org/gcrypt/alpha/libgpg-error/ +Source: ftp://ftp.gnupg.org/gcrypt/alpha/libgpg-error/%{name}-%{version}.tar.gz +Group: Development/Libraries +Copyright: LGPL +BuildRoot: %{_tmppath}/%{name}-%{version} +BuildRequires: make +Prereq: /sbin/ldconfig + +%description +This is a library that defines common error values for all GnuPG +components. Among these are GPG, GPGSM, GPGME, GPG-Agent, libgcrypt, +pinentry, SmartCard Daemon and possibly more in the future. + +%prep +%setup -q + +%build +CFLAGS="$RPM_OPT_FLAGS"; export CFLAGS +./configure --prefix=/usr +make + +%install +rm -fr $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT +make install prefix=$RPM_BUILD_ROOT/usr + +%clean +rm -fr $RPM_BUILD_ROOT +make distclean + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-,root,root) +%doc COPYING COPYING.LIB AUTHORS README INSTALL NEWS ChangeLog +%attr(0755,root,root) %{_bindir}/gpg-error-config +%attr(0755,root,root) %{_bindir}/gpg-error +%attr(0755,root,root) %{_libdir}/*gpg-error.so* +%attr(0755,root,root) %{_libdir}/*gpg-error.la +%attr(0644,root,root) %{_libdir}/*gpg-error.a +%{_includedir}/gpg-error.h +%{_datadir}/aclocal/gpg-error.m4 + +%changelog +* Wed Sep 3 2003 Robert Schiele +- initial specfile. + +# EOF diff --git a/comm/third_party/libgpg-error/libgpg-error.spec.in b/comm/third_party/libgpg-error/libgpg-error.spec.in new file mode 100644 index 0000000000..abbf24e45f --- /dev/null +++ b/comm/third_party/libgpg-error/libgpg-error.spec.in @@ -0,0 +1,57 @@ +# This is a template. The dist target uses it to create the real file. +Summary: libgpg-error +Name: libgpg-error +Version: @pkg_version@ +Release: 1 +URL: ftp://ftp.gnupg.org/gcrypt/alpha/libgpg-error/ +Source: ftp://ftp.gnupg.org/gcrypt/alpha/libgpg-error/%{name}-%{version}.tar.gz +Group: Development/Libraries +Copyright: LGPL +BuildRoot: %{_tmppath}/%{name}-%{version} +BuildRequires: make +Prereq: /sbin/ldconfig + +%description +This is a library that defines common error values for all GnuPG +components. Among these are GPG, GPGSM, GPGME, GPG-Agent, libgcrypt, +pinentry, SmartCard Daemon and possibly more in the future. + +%prep +%setup -q + +%build +CFLAGS="$RPM_OPT_FLAGS"; export CFLAGS +./configure --prefix=/usr +make + +%install +rm -fr $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT +make install prefix=$RPM_BUILD_ROOT/usr + +%clean +rm -fr $RPM_BUILD_ROOT +make distclean + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-,root,root) +%doc COPYING COPYING.LIB AUTHORS README INSTALL NEWS ChangeLog +%attr(0755,root,root) %{_bindir}/gpg-error-config +%attr(0755,root,root) %{_bindir}/gpg-error +%attr(0755,root,root) %{_libdir}/*gpg-error.so* +%attr(0755,root,root) %{_libdir}/*gpg-error.la +%attr(0644,root,root) %{_libdir}/*gpg-error.a +%{_includedir}/gpg-error.h +%{_datadir}/aclocal/gpg-error.m4 + +%changelog +* Wed Sep 3 2003 Robert Schiele +- initial specfile. + +# EOF diff --git a/comm/third_party/libgpg-error/m4/ChangeLog-2011 b/comm/third_party/libgpg-error/m4/ChangeLog-2011 new file mode 100644 index 0000000000..d803b60b07 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/ChangeLog-2011 @@ -0,0 +1,113 @@ +2011-12-01 Werner Koch + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2010-09-16 gettextize + + * gettext.m4: Upgrade to gettext-0.17. + * iconv.m4: Upgrade to gettext-0.17. + * lib-link.m4: Upgrade to gettext-0.17. + * po.m4: Upgrade to gettext-0.17. + +2006-11-23 gettextize + + * gettext.m4: Upgrade to gettext-0.15. + * inttypes-h.m4: New file, from gettext-0.15. + * inttypes-pri.m4: Upgrade to gettext-0.15. + * lib-link.m4: Upgrade to gettext-0.15. + * lib-prefix.m4: Upgrade to gettext-0.15. + * lock.m4: New file, from gettext-0.15. + * longdouble.m4: Upgrade to gettext-0.15. + * nls.m4: Upgrade to gettext-0.15. + * po.m4: Upgrade to gettext-0.15. + * size_max.m4: Upgrade to gettext-0.15. + * visibility.m4: New file, from gettext-0.15. + * Makefile.am (EXTRA_DIST): Add the new files. + +2006-09-14 Werner Koch + + * autobuild.m4: New. + +2006-03-14 gettextize + + * codeset.m4: Upgrade to gettext-0.14.5. + * gettext.m4: Upgrade to gettext-0.14.5. + * glibc2.m4: New file, from gettext-0.14.5. + * glibc21.m4: Upgrade to gettext-0.14.5. + * iconv.m4: Upgrade to gettext-0.14.5. + * intdiv0.m4: Upgrade to gettext-0.14.5. + * intmax.m4: New file, from gettext-0.14.5. + * inttypes.m4: Upgrade to gettext-0.14.5. + * inttypes_h.m4: Upgrade to gettext-0.14.5. + * inttypes-pri.m4: Upgrade to gettext-0.14.5. + * isc-posix.m4: Upgrade to gettext-0.14.5. + * lcmessage.m4: Upgrade to gettext-0.14.5. + * lib-ld.m4: Upgrade to gettext-0.14.5. + * lib-link.m4: Upgrade to gettext-0.14.5. + * lib-prefix.m4: Upgrade to gettext-0.14.5. + * longdouble.m4: New file, from gettext-0.14.5. + * longlong.m4: New file, from gettext-0.14.5. + * nls.m4: Upgrade to gettext-0.14.5. + * po.m4: Upgrade to gettext-0.14.5. + * printf-posix.m4: New file, from gettext-0.14.5. + * progtest.m4: Upgrade to gettext-0.14.5. + * signed.m4: New file, from gettext-0.14.5. + * size_max.m4: New file, from gettext-0.14.5. + * stdint_h.m4: Upgrade to gettext-0.14.5. + * uintmax_t.m4: Upgrade to gettext-0.14.5. + * ulonglong.m4: Upgrade to gettext-0.14.5. + * wchar_t.m4: New file, from gettext-0.14.5. + * wint_t.m4: New file, from gettext-0.14.5. + * xsize.m4: New file, from gettext-0.14.5. + * Makefile.am (EXTRA_DIST): Add the new files. + +2005-10-02 Marcus Brinkmann + + * libtool.m4: Update. + +2004-03-01 Marcus Brinkmann + + * Makefile.am (EXTRA_DIST): Add ac_prog_cc_for_build.m4. + * ac_prog_cc_for_build.m4: New file. + +2003-12-08 Werner Koch + + * libtool.m4: Added (CVS only). + +2003-12-08 gettextize + + * gettext.m4: Upgrade to gettext-0.12.1. + * inttypes_h.m4: Upgrade to gettext-0.12.1. + * lib-ld.m4: Upgrade to gettext-0.12.1. + * lib-link.m4: Upgrade to gettext-0.12.1. + * lib-prefix.m4: Upgrade to gettext-0.12.1. + * nls.m4: New file, from gettext-0.12.1. + * po.m4: New file, from gettext-0.12.1. + * progtest.m4: Upgrade to gettext-0.12.1. + * stdint_h.m4: Upgrade to gettext-0.12.1. + * uintmax_t.m4: Upgrade to gettext-0.12.1. + * Makefile.am (EXTRA_DIST): Add the new files. + +2003-05-15 gettextize + + * codeset.m4: New file, from gettext-0.11.5. + * gettext.m4: New file, from gettext-0.11.5. + * glibc21.m4: New file, from gettext-0.11.5. + * iconv.m4: New file, from gettext-0.11.5. + * intdiv0.m4: New file, from gettext-0.11.5. + * inttypes.m4: New file, from gettext-0.11.5. + * inttypes_h.m4: New file, from gettext-0.11.5. + * inttypes-pri.m4: New file, from gettext-0.11.5. + * isc-posix.m4: New file, from gettext-0.11.5. + * lcmessage.m4: New file, from gettext-0.11.5. + * lib-ld.m4: New file, from gettext-0.11.5. + * lib-link.m4: New file, from gettext-0.11.5. + * lib-prefix.m4: New file, from gettext-0.11.5. + * progtest.m4: New file, from gettext-0.11.5. + * stdint_h.m4: New file, from gettext-0.11.5. + * uintmax_t.m4: New file, from gettext-0.11.5. + * ulonglong.m4: New file, from gettext-0.11.5. + * Makefile.am: New file. diff --git a/comm/third_party/libgpg-error/m4/Makefile.am b/comm/third_party/libgpg-error/m4/Makefile.am new file mode 100644 index 0000000000..a82737df1b --- /dev/null +++ b/comm/third_party/libgpg-error/m4/Makefile.am @@ -0,0 +1,5 @@ +EXTRA_DIST = inttypes-h.m4 lock.m4 visibility.m4 glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 nls.m4 po.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 + +EXTRA_DIST += ax_cc_for_build.m4 + +EXTRA_DIST += autobuild.m4 estream.m4 readline.m4 gnupg-misc.m4 diff --git a/comm/third_party/libgpg-error/m4/Makefile.in b/comm/third_party/libgpg-error/m4/Makefile.in new file mode 100644 index 0000000000..619d2a77ef --- /dev/null +++ b/comm/third_party/libgpg-error/m4/Makefile.in @@ -0,0 +1,498 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = m4 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ + $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/estream.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnupg-misc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/threadlib.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GPG_ERROR_CONFIG_CFLAGS = @GPG_ERROR_CONFIG_CFLAGS@ +GPG_ERROR_CONFIG_HOST = @GPG_ERROR_CONFIG_HOST@ +GPG_ERROR_CONFIG_LIBS = @GPG_ERROR_CONFIG_LIBS@ +GPG_ERROR_CONFIG_LIBS_PRIVATE = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +GPG_ERROR_CONFIG_MT_CFLAGS = @GPG_ERROR_CONFIG_MT_CFLAGS@ +GPG_ERROR_CONFIG_MT_LIBS = @GPG_ERROR_CONFIG_MT_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALLSHELLPATH = @INSTALLSHELLPATH@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGPG_ERROR_LT_AGE = @LIBGPG_ERROR_LT_AGE@ +LIBGPG_ERROR_LT_CURRENT = @LIBGPG_ERROR_LT_CURRENT@ +LIBGPG_ERROR_LT_REVISION = @LIBGPG_ERROR_LT_REVISION@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBREADLINE = @LIBREADLINE@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_NETWORK = @LIB_NETWORK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = inttypes-h.m4 lock.m4 visibility.m4 glibc2.m4 intmax.m4 \ + longdouble.m4 longlong.m4 printf-posix.m4 signed.m4 \ + size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 nls.m4 po.m4 \ + codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 \ + inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 \ + lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 \ + stdint_h.m4 uintmax_t.m4 ulonglong.m4 ax_cc_for_build.m4 \ + autobuild.m4 estream.m4 readline.m4 gnupg-misc.m4 +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu m4/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgpg-error/m4/autobuild.m4 b/comm/third_party/libgpg-error/m4/autobuild.m4 new file mode 100644 index 0000000000..bd1f4dc1b0 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/autobuild.m4 @@ -0,0 +1,34 @@ +# autobuild.m4 serial 2 (autobuild-3.3) +# Copyright (C) 2004 Simon Josefsson +# +# This file is free software, distributed under the terms of the GNU +# General Public License. As a special exception to the GNU General +# Public License, this file may be distributed as part of a program +# that contains a configuration script generated by Autoconf, under +# the same distribution terms as the rest of that program. +# +# This file can can be used in projects which are not available under +# the GNU General Public License or the GNU Library General Public +# License but which still want to provide support for Autobuild. + +# Usage: AB_INIT([MODE]). +AC_DEFUN([AB_INIT], +[ + AC_REQUIRE([AC_CANONICAL_BUILD]) + AC_REQUIRE([AC_CANONICAL_HOST]) + + AC_MSG_NOTICE([autobuild project... ${PACKAGE_NAME:-$PACKAGE}]) + AC_MSG_NOTICE([autobuild revision... ${PACKAGE_VERSION:-$VERSION}]) + hostname=`hostname` + if test "$hostname"; then + AC_MSG_NOTICE([autobuild hostname... $hostname]) + fi + ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])]) + date=`date +%Y%m%d-%H%M%S` + if test "$?" != 0; then + date=`date` + fi + if test "$date"; then + AC_MSG_NOTICE([autobuild timestamp... $date]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/ax_cc_for_build.m4 b/comm/third_party/libgpg-error/m4/ax_cc_for_build.m4 new file mode 100644 index 0000000000..c62ffadbc0 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/ax_cc_for_build.m4 @@ -0,0 +1,77 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CC_FOR_BUILD +# +# DESCRIPTION +# +# Find a build-time compiler. Sets CC_FOR_BUILD and EXEEXT_FOR_BUILD. +# +# LICENSE +# +# Copyright (c) 2010 Reuben Thomas +# Copyright (c) 1999 Richard Henderson +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 3 + +dnl Get a default for CC_FOR_BUILD to put into Makefile. +AC_DEFUN([AX_CC_FOR_BUILD], +[# Put a plausible default for CC_FOR_BUILD in Makefile. +if test -z "$CC_FOR_BUILD"; then + if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' + else + CC_FOR_BUILD=gcc + fi +fi +AC_SUBST(CC_FOR_BUILD) +# Also set EXEEXT_FOR_BUILD. +if test "x$cross_compiling" = "xno"; then + EXEEXT_FOR_BUILD='$(EXEEXT)' +else + AC_CACHE_CHECK([for build system executable suffix], bfd_cv_build_exeext, + [rm -f conftest* + echo 'int main () { return 0; }' > conftest.c + bfd_cv_build_exeext= + ${CC_FOR_BUILD} -o conftest conftest.c 1>&5 2>&5 + for file in conftest.*; do + case $file in + *.c | *.o | *.obj | *.ilk | *.pdb) ;; + *) bfd_cv_build_exeext=`echo $file | sed -e s/conftest//` ;; + esac + done + rm -f conftest* + test x"${bfd_cv_build_exeext}" = x && bfd_cv_build_exeext=no]) + EXEEXT_FOR_BUILD="" + test x"${bfd_cv_build_exeext}" != xno && EXEEXT_FOR_BUILD=${bfd_cv_build_exeext} +fi +AC_SUBST(EXEEXT_FOR_BUILD)])dnl diff --git a/comm/third_party/libgpg-error/m4/codeset.m4 b/comm/third_party/libgpg-error/m4/codeset.m4 new file mode 100644 index 0000000000..a6e67ec498 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/codeset.m4 @@ -0,0 +1,21 @@ +# codeset.m4 serial AM1 (gettext-0.10.40) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, + [AC_TRY_LINK([#include ], + [char* cs = nl_langinfo(CODESET);], + am_cv_langinfo_codeset=yes, + am_cv_langinfo_codeset=no) + ]) + if test $am_cv_langinfo_codeset = yes; then + AC_DEFINE(HAVE_LANGINFO_CODESET, 1, + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/estream.m4 b/comm/third_party/libgpg-error/m4/estream.m4 new file mode 100644 index 0000000000..deb972dc75 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/estream.m4 @@ -0,0 +1,50 @@ +dnl Autoconf macros for libestream +dnl Copyright (C) 2007 g10 Code GmbH +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This file is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +dnl estream_PRINTF_INIT +dnl Prepare build of source included estream-printf.c +dnl +AC_DEFUN([estream_PRINTF_INIT], +[ + AC_MSG_NOTICE([checking system features for estream-printf]) + AC_CHECK_HEADERS(stdint.h) + AC_TYPE_LONG_LONG_INT + AC_TYPE_LONG_DOUBLE + AC_TYPE_INTMAX_T + AC_TYPE_UINTMAX_T + AC_CHECK_TYPES([ptrdiff_t]) + AC_CHECK_SIZEOF([unsigned long]) + AC_CHECK_SIZEOF([void *]) + AC_CACHE_CHECK([for nl_langinfo and THOUSEP], + estream_cv_langinfo_thousep, + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include ]], + [[char* cs = nl_langinfo(THOUSEP); return !cs;]])], + estream_cv_langinfo_thousep=yes, + estream_cv_langinfo_thousep=no) + ]) + if test $estream_cv_langinfo_thousep = yes; then + AC_DEFINE(HAVE_LANGINFO_THOUSEP, 1, + [Define if you have and nl_langinfo(THOUSEP).]) + fi +]) + + +dnl estream_INIT +dnl Prepare build of source included estream.c +dnl +AC_DEFUN([estream_INIT], +[ + AC_REQUIRE([estream_PRINTF_INIT]) + AC_MSG_NOTICE([checking system features for estream]) + AC_CHECK_FUNCS([memrchr]) +]) diff --git a/comm/third_party/libgpg-error/m4/gettext.m4 b/comm/third_party/libgpg-error/m4/gettext.m4 new file mode 100644 index 0000000000..be247bf7b8 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/gettext.m4 @@ -0,0 +1,401 @@ +# gettext.m4 serial 66 (gettext-0.18.2) +dnl Copyright (C) 1995-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2006, 2008-2010. + +dnl Macro to add for using GNU gettext. + +dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). +dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The +dnl default (if it is not specified or empty) is 'no-libtool'. +dnl INTLSYMBOL should be 'external' for packages with no intl directory, +dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. +dnl If INTLSYMBOL is 'use-libtool', then a libtool library +dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, +dnl depending on --{enable,disable}-{shared,static} and on the presence of +dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library +dnl $(top_builddir)/intl/libintl.a will be created. +dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext +dnl implementations (in libc or libintl) without the ngettext() function +dnl will be ignored. If NEEDSYMBOL is specified and is +dnl 'need-formatstring-macros', then GNU gettext implementations that don't +dnl support the ISO C 99 formatstring macros will be ignored. +dnl INTLDIR is used to find the intl libraries. If empty, +dnl the value '$(top_builddir)/intl/' is used. +dnl +dnl The result of the configuration is one of three cases: +dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled +dnl and used. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 2) GNU gettext has been found in the system's C library. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 3) No internationalization, always use English msgid. +dnl Catalog format: none +dnl Catalog extension: none +dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. +dnl The use of .gmo is historical (it was needed to avoid overwriting the +dnl GNU format catalogs when building on a platform with an X/Open gettext), +dnl but we keep it in order not to force irrelevant filename changes on the +dnl maintainers. +dnl +AC_DEFUN([AM_GNU_GETTEXT], +[ + dnl Argument checking. + ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , + [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT +])])])])]) + ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old], + [AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])]) + ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , + [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT +])])])]) + define([gt_included_intl], + ifelse([$1], [external], + ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), + [yes])) + define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) + gt_NEEDS_INIT + AM_GNU_GETTEXT_NEED([$2]) + + AC_REQUIRE([AM_PO_SUBDIRS])dnl + ifelse(gt_included_intl, yes, [ + AC_REQUIRE([AM_INTL_SUBDIR])dnl + ]) + + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Sometimes libintl requires libiconv, so first search for libiconv. + dnl Ideally we would do this search only after the + dnl if test "$USE_NLS" = "yes"; then + dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT + dnl the configure script would need to contain the same shell code + dnl again, outside any 'if'. There are two solutions: + dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. + dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. + dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not + dnl documented, we avoid it. + ifelse(gt_included_intl, yes, , [ + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + ]) + + dnl Sometimes, on Mac OS X, libintl requires linking with CoreFoundation. + gt_INTL_MACOSX + + dnl Set USE_NLS. + AC_REQUIRE([AM_NLS]) + + ifelse(gt_included_intl, yes, [ + BUILD_INCLUDED_LIBINTL=no + USE_INCLUDED_LIBINTL=no + ]) + LIBINTL= + LTLIBINTL= + POSUB= + + dnl Add a version number to the cache macros. + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + ifelse(gt_included_intl, yes, [ + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH([included-gettext], + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext]) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + ]) + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If GNU gettext is available we use this. Else we have + dnl to fall back to GNU NLS library. + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings; + ]], + [[ +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings + ]])], + [eval "$gt_func_gnugettext_libc=yes"], + [eval "$gt_func_gnugettext_libc=no"])]) + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + dnl Sometimes libintl requires libiconv, so first search for libiconv. + ifelse(gt_included_intl, yes, , [ + AM_ICONV_LINK + ]) + dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL + dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) + dnl because that would add "-liconv" to LIBINTL and LTLIBINTL + dnl even if libiconv doesn't exist. + AC_LIB_LINKFLAGS_BODY([intl]) + AC_CACHE_CHECK([for GNU gettext in libintl], + [$gt_func_gnugettext_libintl], + [gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + dnl Now see whether libintl exists and does not depend on libiconv. + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); + ]], + [[ +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") + ]])], + [eval "$gt_func_gnugettext_libintl=yes"], + [eval "$gt_func_gnugettext_libintl=no"]) + dnl Now see whether libintl exists and depends on libiconv. + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +$gt_revision_test_code +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); + ]], + [[ +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") + ]])], + [LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + ]) + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS"]) + fi + + dnl If an already present or preinstalled GNU gettext() is found, + dnl use it. But if this macro is used in GNU gettext, and GNU + dnl gettext is already preinstalled in libintl, we update this + dnl libintl. (Cf. the install rule in intl/Makefile.in.) + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + dnl Reset the values set by searching for libintl. + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + ifelse(gt_included_intl, yes, [ + if test "$gt_use_preinstalled_gnugettext" != "yes"; then + dnl GNU gettext is not found in the C library. + dnl Fall back on included GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + BUILD_INCLUDED_LIBINTL=yes + USE_INCLUDED_LIBINTL=yes + LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" + LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" + LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` + fi + + CATOBJEXT= + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions to use GNU gettext tools. + CATOBJEXT=.gmo + fi + ]) + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Some extra flags are needed during linking. + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + AC_DEFINE([ENABLE_NLS], [1], + [Define to 1 if translation of program messages to the user's native language + is requested.]) + else + USE_NLS=no + fi + fi + + AC_MSG_CHECKING([whether to use NLS]) + AC_MSG_RESULT([$USE_NLS]) + if test "$USE_NLS" = "yes"; then + AC_MSG_CHECKING([where the gettext function comes from]) + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + AC_MSG_RESULT([$gt_source]) + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + AC_MSG_CHECKING([how to link with libintl]) + AC_MSG_RESULT([$LIBINTL]) + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) + fi + + dnl For backward compatibility. Some packages may be using this. + AC_DEFINE([HAVE_GETTEXT], [1], + [Define if the GNU gettext() function is already present or preinstalled.]) + AC_DEFINE([HAVE_DCGETTEXT], [1], + [Define if the GNU dcgettext() function is already present or preinstalled.]) + fi + + dnl We need to process the po/ directory. + POSUB=po + fi + + ifelse(gt_included_intl, yes, [ + dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL + dnl to 'yes' because some of the testsuite requires it. + if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then + BUILD_INCLUDED_LIBINTL=yes + fi + + dnl Make all variables we use known to autoconf. + AC_SUBST([BUILD_INCLUDED_LIBINTL]) + AC_SUBST([USE_INCLUDED_LIBINTL]) + AC_SUBST([CATOBJEXT]) + + dnl For backward compatibility. Some configure.ins may be using this. + nls_cv_header_intl= + nls_cv_header_libgt= + + dnl For backward compatibility. Some Makefiles may be using this. + DATADIRNAME=share + AC_SUBST([DATADIRNAME]) + + dnl For backward compatibility. Some Makefiles may be using this. + INSTOBJEXT=.mo + AC_SUBST([INSTOBJEXT]) + + dnl For backward compatibility. Some Makefiles may be using this. + GENCAT=gencat + AC_SUBST([GENCAT]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLOBJS= + if test "$USE_INCLUDED_LIBINTL" = yes; then + INTLOBJS="\$(GETTOBJS)" + fi + AC_SUBST([INTLOBJS]) + + dnl Enable libtool support if the surrounding package wishes it. + INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix + AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) + ]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLLIBS="$LIBINTL" + AC_SUBST([INTLLIBS]) + + dnl Make all documented variables known to autoconf. + AC_SUBST([LIBINTL]) + AC_SUBST([LTLIBINTL]) + AC_SUBST([POSUB]) +]) + + +dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. +m4_define([gt_NEEDS_INIT], +[ + m4_divert_text([DEFAULTS], [gt_needs=]) + m4_define([gt_NEEDS_INIT], []) +]) + + +dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) +AC_DEFUN([AM_GNU_GETTEXT_NEED], +[ + m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) +]) + + +dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) +AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/comm/third_party/libgpg-error/m4/glibc2.m4 b/comm/third_party/libgpg-error/m4/glibc2.m4 new file mode 100644 index 0000000000..e8f5bfe6ed --- /dev/null +++ b/comm/third_party/libgpg-error/m4/glibc2.m4 @@ -0,0 +1,30 @@ +# glibc2.m4 serial 1 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.0 or newer. +# From Bruno Haible. + +AC_DEFUN([gt_GLIBC2], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, + ac_cv_gnu_library_2, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ >= 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2=yes, + ac_cv_gnu_library_2=no) + ] + ) + AC_SUBST(GLIBC2) + GLIBC2="$ac_cv_gnu_library_2" + ] +) diff --git a/comm/third_party/libgpg-error/m4/glibc21.m4 b/comm/third_party/libgpg-error/m4/glibc21.m4 new file mode 100644 index 0000000000..d95fd98613 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/glibc21.m4 @@ -0,0 +1,30 @@ +# glibc21.m4 serial 3 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.1 or newer. +# From Bruno Haible. + +AC_DEFUN([gl_GLIBC21], + [ + AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, + ac_cv_gnu_library_2_1, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2_1=yes, + ac_cv_gnu_library_2_1=no) + ] + ) + AC_SUBST(GLIBC21) + GLIBC21="$ac_cv_gnu_library_2_1" + ] +) diff --git a/comm/third_party/libgpg-error/m4/gnupg-misc.m4 b/comm/third_party/libgpg-error/m4/gnupg-misc.m4 new file mode 100644 index 0000000000..c707b35ec4 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/gnupg-misc.m4 @@ -0,0 +1,35 @@ +dnl gnupg-misc.m4 - Autoconf macros originally from GnuPG +dnl Copyright (C) 2017 g10 Code GmbH +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This file is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +dnl SPDX-License-Identifier: FSFULLR + + +dnl Define MKDIR_TAKES_ONE_ARG if mkdir accepts only one argument instead +dnl of the usual 2. +AC_DEFUN([GNUPG_FUNC_MKDIR_TAKES_ONE_ARG], +[AC_CHECK_HEADERS(sys/stat.h unistd.h direct.h) +AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg, +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_DIRECT_H +# include +#endif]], [[mkdir ("foo", 0);]])], + gnupg_cv_mkdir_takes_one_arg=no, gnupg_cv_mkdir_takes_one_arg=yes)]) +if test $gnupg_cv_mkdir_takes_one_arg = yes ; then + AC_DEFINE(MKDIR_TAKES_ONE_ARG,1, + [Defined if mkdir() does not take permission flags]) +fi +]) diff --git a/comm/third_party/libgpg-error/m4/iconv.m4 b/comm/third_party/libgpg-error/m4/iconv.m4 new file mode 100644 index 0000000000..a285e9daa5 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/iconv.m4 @@ -0,0 +1,288 @@ +# iconv.m4 serial 21 +dnl Copyright (C) 2000-2002, 2007-2014, 2016-2019 Free Software Foundation, +dnl Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_func_iconv=yes]) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_lib_iconv=yes] + [am_cv_func_iconv=yes]) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ + dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, + dnl Solaris 10. + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + ]], + [[int result = 0; + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 1; + iconv_close (cd_utf8_to_88591); + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\263"; + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 2; + iconv_close (cd_ascii_to_88591); + } + } + /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304"; + static char buf[2] = { (char)0xDE, (char)0xAD }; + ICONV_CONST char *inptr = input; + size_t inbytesleft = 1; + char *outptr = buf; + size_t outbytesleft = 1; + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) + result |= 4; + iconv_close (cd_88591_to_utf8); + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + result |= 8; + iconv_close (cd_88591_to_utf8); + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + { + /* Try standardized names. */ + iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP"); + /* Try IRIX, OSF/1 names. */ + iconv_t cd2 = iconv_open ("UTF-8", "eucJP"); + /* Try AIX names. */ + iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP"); + /* Try HP-UX names. */ + iconv_t cd4 = iconv_open ("utf8", "eucJP"); + if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1) + && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1)) + result |= 16; + if (cd1 != (iconv_t)(-1)) + iconv_close (cd1); + if (cd2 != (iconv_t)(-1)) + iconv_close (cd2); + if (cd3 != (iconv_t)(-1)) + iconv_close (cd3); + if (cd4 != (iconv_t)(-1)) + iconv_close (cd4); + } + return result; +]])], + [am_cv_func_iconv_works=yes], , + [case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac]) + test "$am_cv_func_iconv_works" = no || break + done + LIBS="$am_save_LIBS" + ]) + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + AC_DEFINE([HAVE_ICONV], [1], + [Define if you have the iconv() function and it works.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST([LIBICONV]) + AC_SUBST([LTLIBICONV]) +]) + +dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to +dnl avoid warnings like +dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". +dnl This is tricky because of the way 'aclocal' is implemented: +dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. +dnl Otherwise aclocal's initial scan pass would miss the macro definition. +dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. +dnl Otherwise aclocal would emit many "Use of uninitialized value $1" +dnl warnings. +m4_define([gl_iconv_AC_DEFUN], + m4_version_prereq([2.64], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [m4_ifdef([gl_00GNULIB], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [[AC_DEFUN( + [$1], [$2])]])])) +gl_iconv_AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL([am_cv_proto_iconv], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + ]], + [[]])], + [am_cv_proto_iconv_arg1=""], + [am_cv_proto_iconv_arg1="const"]) + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([ + $am_cv_proto_iconv]) + else + dnl When compiling GNU libiconv on a system that does not have iconv yet, + dnl pick the POSIX compliant declaration without 'const'. + am_cv_proto_iconv_arg1="" + fi + AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], + [Define as const if the declaration of iconv() needs const.]) + dnl Also substitute ICONV_CONST in the gnulib generated . + m4_ifdef([gl_ICONV_H_DEFAULTS], + [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) + if test -n "$am_cv_proto_iconv_arg1"; then + ICONV_CONST="const" + fi + ]) +]) diff --git a/comm/third_party/libgpg-error/m4/intdiv0.m4 b/comm/third_party/libgpg-error/m4/intdiv0.m4 new file mode 100644 index 0000000000..b8d78176a6 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/intdiv0.m4 @@ -0,0 +1,70 @@ +# intdiv0.m4 serial 1 (gettext-0.11.3) +dnl Copyright (C) 2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gt_INTDIV0], +[ + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + + AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], + gt_cv_int_divbyzero_sigfpe, + [ + AC_TRY_RUN([ +#include +#include + +static void +#ifdef __cplusplus +sigfpe_handler (int sig) +#else +sigfpe_handler (sig) int sig; +#endif +{ + /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ + exit (sig != SIGFPE); +} + +int x = 1; +int y = 0; +int z; +int nan; + +int main () +{ + signal (SIGFPE, sigfpe_handler); +/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ +#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) + signal (SIGTRAP, sigfpe_handler); +#endif +/* Linux/SPARC yields signal SIGILL. */ +#if defined (__sparc__) && defined (__linux__) + signal (SIGILL, sigfpe_handler); +#endif + + z = x / y; + nan = y / y; + exit (1); +} +], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, + [ + # Guess based on the CPU. + case "$host_cpu" in + alpha* | i[34567]86 | m68k | s390*) + gt_cv_int_divbyzero_sigfpe="guessing yes";; + *) + gt_cv_int_divbyzero_sigfpe="guessing no";; + esac + ]) + ]) + case "$gt_cv_int_divbyzero_sigfpe" in + *yes) value=1;; + *) value=0;; + esac + AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, + [Define if integer division by zero raises signal SIGFPE.]) +]) diff --git a/comm/third_party/libgpg-error/m4/intmax.m4 b/comm/third_party/libgpg-error/m4/intmax.m4 new file mode 100644 index 0000000000..d99c999fdb --- /dev/null +++ b/comm/third_party/libgpg-error/m4/intmax.m4 @@ -0,0 +1,30 @@ +# intmax.m4 serial 2 (gettext-0.14.2) +dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether the system has the 'intmax_t' type, but don't attempt to +dnl find a replacement if it is lacking. + +AC_DEFUN([gt_TYPE_INTMAX_T], +[ + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, + [AC_TRY_COMPILE([ +#include +#include +#if HAVE_STDINT_H_WITH_UINTMAX +#include +#endif +#if HAVE_INTTYPES_H_WITH_UINTMAX +#include +#endif +], [intmax_t x = -1;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)]) + if test $gt_cv_c_intmax_t = yes; then + AC_DEFINE(HAVE_INTMAX_T, 1, + [Define if you have the 'intmax_t' type in or .]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/inttypes-h.m4 b/comm/third_party/libgpg-error/m4/inttypes-h.m4 new file mode 100644 index 0000000000..d7ec94c5a4 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/inttypes-h.m4 @@ -0,0 +1,25 @@ +# inttypes-h.m4 serial 1 (gettext-0.15) +dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H if exists and doesn't clash with +# . + +AC_DEFUN([gl_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, + [ + AC_TRY_COMPILE( + [#include +#include ], + [], gl_cv_header_inttypes_h=yes, gl_cv_header_inttypes_h=no) + ]) + if test $gl_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, + [Define if exists and doesn't clash with .]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/inttypes-pri.m4 b/comm/third_party/libgpg-error/m4/inttypes-pri.m4 new file mode 100644 index 0000000000..ef00da7420 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/inttypes-pri.m4 @@ -0,0 +1,30 @@ +# inttypes-pri.m4 serial 2 (gettext-0.15) +dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +# Define PRI_MACROS_BROKEN if exists and defines the PRI* +# macros to non-string values. This is the case on AIX 4.3.3. + +AC_DEFUN([gt_INTTYPES_PRI], +[ + AC_REQUIRE([gl_HEADER_INTTYPES_H]) + if test $gl_cv_header_inttypes_h = yes; then + AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], + gt_cv_inttypes_pri_broken, + [ + AC_TRY_COMPILE([#include +#ifdef PRId32 +char *p = PRId32; +#endif +], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) + ]) + fi + if test "$gt_cv_inttypes_pri_broken" = yes; then + AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, + [Define if exists and defines unusable PRI* macros.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/inttypes.m4 b/comm/third_party/libgpg-error/m4/inttypes.m4 new file mode 100644 index 0000000000..779bcea059 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/inttypes.m4 @@ -0,0 +1,25 @@ +# inttypes.m4 serial 1 (gettext-0.11.4) +dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H if exists and doesn't clash with +# . + +AC_DEFUN([gt_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, + [ + AC_TRY_COMPILE( + [#include +#include ], + [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) + ]) + if test $gt_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, + [Define if exists and doesn't clash with .]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/inttypes_h.m4 b/comm/third_party/libgpg-error/m4/inttypes_h.m4 new file mode 100644 index 0000000000..a5d075d968 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/inttypes_h.m4 @@ -0,0 +1,26 @@ +# inttypes_h.m4 serial 6 +dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, +# doesn't clash with , and declares uintmax_t. + +AC_DEFUN([gl_AC_HEADER_INTTYPES_H], +[ + AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1;], + gl_cv_header_inttypes_h=yes, + gl_cv_header_inttypes_h=no)]) + if test $gl_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, + [Define if exists, doesn't clash with , + and declares uintmax_t. ]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/isc-posix.m4 b/comm/third_party/libgpg-error/m4/isc-posix.m4 new file mode 100644 index 0000000000..74dc8f26d8 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/isc-posix.m4 @@ -0,0 +1,24 @@ +# isc-posix.m4 serial 2 (gettext-0.11.2) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# This file is not needed with autoconf-2.53 and newer. Remove it in 2005. + +# This test replaces the one in autoconf. +# Currently this macro should have the same name as the autoconf macro +# because gettext's gettext.m4 (distributed in the automake package) +# still uses it. Otherwise, the use in gettext.m4 makes autoheader +# give these diagnostics: +# configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX +# configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX + +undefine([AC_ISC_POSIX]) + +AC_DEFUN([AC_ISC_POSIX], + [ + dnl This test replaces the obsolescent AC_ISC_POSIX kludge. + AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) + ] +) diff --git a/comm/third_party/libgpg-error/m4/lcmessage.m4 b/comm/third_party/libgpg-error/m4/lcmessage.m4 new file mode 100644 index 0000000000..19aa77e4f7 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/lcmessage.m4 @@ -0,0 +1,30 @@ +# lcmessage.m4 serial 4 (gettext-0.14.2) +dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995. + +# Check whether LC_MESSAGES is available in . + +AC_DEFUN([gt_LC_MESSAGES], +[ + AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) + if test $gt_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/lib-ld.m4 b/comm/third_party/libgpg-error/m4/lib-ld.m4 new file mode 100644 index 0000000000..ddc569f736 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/lib-ld.m4 @@ -0,0 +1,119 @@ +# lib-ld.m4 serial 6 +dnl Copyright (C) 1996-2003, 2009-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid +dnl collision with libtool.m4. + +dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], +[# I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 /dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` + while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL([acl_cv_path_LD], +[if test -z "$LD"; then + acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$acl_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 = 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE([rpath], + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_FROMPACKAGE(name, package) +dnl declares that libname comes from the given package. The configure file +dnl will then not have a --with-libname-prefix option but a +dnl --with-package-prefix option. Several libraries can come from the same +dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar +dnl macro call that searches for libname. +AC_DEFUN([AC_LIB_FROMPACKAGE], +[ + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + define([acl_frompackage_]NAME, [$2]) + popdef([NAME]) + pushdef([PACK],[$2]) + pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + define([acl_libsinpackage_]PACKUP, + m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1]) + popdef([PACKUP]) + popdef([PACK]) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found +dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) + pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) + dnl Autoconf >= 2.61 supports dots in --with options. + pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_ARG_WITH(P_A_C_K[-prefix], +[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib + --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + LIB[]NAME[]_PREFIX= + dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been + dnl computed. So it has to be reset here. + HAVE_LIB[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + dnl The same code as in the loop below: + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$acl_hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi + popdef([P_A_C_K]) + popdef([PACKLIBS]) + popdef([PACKUP]) + popdef([PACK]) + popdef([NAME]) +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) diff --git a/comm/third_party/libgpg-error/m4/lib-prefix.m4 b/comm/third_party/libgpg-error/m4/lib-prefix.m4 new file mode 100644 index 0000000000..31f49e40aa --- /dev/null +++ b/comm/third_party/libgpg-error/m4/lib-prefix.m4 @@ -0,0 +1,224 @@ +# lib-prefix.m4 serial 7 (gettext-0.18) +dnl Copyright (C) 2001-2005, 2008-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates +dnl - a variable acl_libdirstem, containing the basename of the libdir, either +dnl "lib" or "lib64" or "lib/64", +dnl - a variable acl_libdirstem2, as a secondary possible value for +dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or +dnl "lib/amd64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. + dnl On glibc systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine + dnl the compiler's default mode by looking at the compiler's library search + dnl path. If at least one of its elements ends in /lib64 or points to a + dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. + dnl Otherwise we use the default, namely "lib". + dnl On Solaris systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or + dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. + AC_REQUIRE([AC_CANONICAL_HOST]) + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment + dnl . + dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." + dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the + dnl symlink is missing, so we set acl_libdirstem2 too. + AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], + [AC_EGREP_CPP([sixtyfour bits], [ +#ifdef _LP64 +sixtyfour bits +#endif + ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) + ]) + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" +]) diff --git a/comm/third_party/libgpg-error/m4/libtool.m4 b/comm/third_party/libgpg-error/m4/libtool.m4 new file mode 100644 index 0000000000..8795701e4c --- /dev/null +++ b/comm/third_party/libgpg-error/m4/libtool.m4 @@ -0,0 +1,8031 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from https://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED \"$sed_uncomment_deffile\" $export_symbols | $SED 1q`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED \"$sed_uncomment_deffile\" $export_symbols | $SED 1q`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED \"$sed_uncomment_deffile\" $export_symbols | $SED 1q`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED \"$sed_uncomment_deffile\" $export_symbols | $SED 1q`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_PUSH([Java]) + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_POP + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_PUSH([Go]) + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_POP + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl + +dnl Here, something like AC_LANG_PUSH([RC]) is expected. +dnl But Resource Compiler is not supported as a language by autoconf + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +dnl Here, AC_LANG_POP is expected. +GCC=$lt_save_GCC +dnl Back to C +AC_LANG([C]) +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/comm/third_party/libgpg-error/m4/lock.m4 b/comm/third_party/libgpg-error/m4/lock.m4 new file mode 100644 index 0000000000..73a3c54cee --- /dev/null +++ b/comm/third_party/libgpg-error/m4/lock.m4 @@ -0,0 +1,42 @@ +# lock.m4 serial 13 (gettext-0.18.2) +dnl Copyright (C) 2005-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gl_LOCK], +[ + AC_REQUIRE([gl_THREADLIB]) + if test "$gl_threads_api" = posix; then + # OSF/1 4.0 and Mac OS X 10.1 lack the pthread_rwlock_t type and the + # pthread_rwlock_* functions. + AC_CHECK_TYPE([pthread_rwlock_t], + [AC_DEFINE([HAVE_PTHREAD_RWLOCK], [1], + [Define if the POSIX multithreading library has read/write locks.])], + [], + [#include ]) + # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [[#include ]], + [[ +#if __FreeBSD__ == 4 +error "No, in FreeBSD 4.0 recursive mutexes actually don't work." +#elif (defined __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ \ + && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) +error "No, in Mac OS X < 10.7 recursive mutexes actually don't work." +#else +int x = (int)PTHREAD_MUTEX_RECURSIVE; +return !x; +#endif + ]])], + [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], [1], + [Define if the defines PTHREAD_MUTEX_RECURSIVE.])]) + fi + gl_PREREQ_LOCK +]) + +# Prerequisites of lib/glthread/lock.c. +AC_DEFUN([gl_PREREQ_LOCK], [:]) diff --git a/comm/third_party/libgpg-error/m4/longdouble.m4 b/comm/third_party/libgpg-error/m4/longdouble.m4 new file mode 100644 index 0000000000..25590f4704 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/longdouble.m4 @@ -0,0 +1,31 @@ +# longdouble.m4 serial 2 (gettext-0.15) +dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether the compiler supports the 'long double' type. +dnl Prerequisite: AC_PROG_CC + +dnl This file is only needed in autoconf <= 2.59. Newer versions of autoconf +dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics. + +AC_DEFUN([gt_TYPE_LONGDOUBLE], +[ + AC_CACHE_CHECK([for long double], gt_cv_c_long_double, + [if test "$GCC" = yes; then + gt_cv_c_long_double=yes + else + AC_TRY_COMPILE([ + /* The Stardent Vistra knows sizeof(long double), but does not support it. */ + long double foo = 0.0; + /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ + int array [2*(sizeof(long double) >= sizeof(double)) - 1]; + ], , + gt_cv_c_long_double=yes, gt_cv_c_long_double=no) + fi]) + if test $gt_cv_c_long_double = yes; then + AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/longlong.m4 b/comm/third_party/libgpg-error/m4/longlong.m4 new file mode 100644 index 0000000000..7b399e0128 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/longlong.m4 @@ -0,0 +1,23 @@ +# longlong.m4 serial 5 +dnl Copyright (C) 1999-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_LONG_LONG if 'long long' works. + +AC_DEFUN([gl_AC_TYPE_LONG_LONG], +[ + AC_CACHE_CHECK([for long long], ac_cv_type_long_long, + [AC_TRY_LINK([long long ll = 1LL; int i = 63;], + [long long llmax = (long long) -1; + return ll << i | ll >> i | llmax / ll | llmax % ll;], + ac_cv_type_long_long=yes, + ac_cv_type_long_long=no)]) + if test $ac_cv_type_long_long = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, + [Define if you have the 'long long' type.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/ltoptions.m4 b/comm/third_party/libgpg-error/m4/ltoptions.m4 new file mode 100644 index 0000000000..5d9acd8e23 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/ltoptions.m4 @@ -0,0 +1,384 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/comm/third_party/libgpg-error/m4/ltsugar.m4 b/comm/third_party/libgpg-error/m4/ltsugar.m4 new file mode 100644 index 0000000000..9000a057d3 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/comm/third_party/libgpg-error/m4/ltversion.m4 b/comm/third_party/libgpg-error/m4/ltversion.m4 new file mode 100644 index 0000000000..07a8602d48 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/comm/third_party/libgpg-error/m4/lt~obsolete.m4 b/comm/third_party/libgpg-error/m4/lt~obsolete.m4 new file mode 100644 index 0000000000..c573da90c5 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/lt~obsolete.m4 @@ -0,0 +1,98 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/comm/third_party/libgpg-error/m4/nls.m4 b/comm/third_party/libgpg-error/m4/nls.m4 new file mode 100644 index 0000000000..53cdc8be8b --- /dev/null +++ b/comm/third_party/libgpg-error/m4/nls.m4 @@ -0,0 +1,32 @@ +# nls.m4 serial 5 (gettext-0.18) +dnl Copyright (C) 1995-2003, 2005-2006, 2008-2014 Free Software Foundation, +dnl Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ([2.50]) + +AC_DEFUN([AM_NLS], +[ + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE([nls], + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT([$USE_NLS]) + AC_SUBST([USE_NLS]) +]) diff --git a/comm/third_party/libgpg-error/m4/po.m4 b/comm/third_party/libgpg-error/m4/po.m4 new file mode 100644 index 0000000000..84659ea531 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/po.m4 @@ -0,0 +1,453 @@ +# po.m4 serial 22 (gettext-0.19) +dnl Copyright (C) 1995-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2003. + +AC_PREREQ([2.60]) + +dnl Checks for all prerequisites of the po subdirectory. +AC_DEFUN([AM_PO_SUBDIRS], +[ + AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AC_PROG_MKDIR_P])dnl + AC_REQUIRE([AC_PROG_SED])dnl + AC_REQUIRE([AM_NLS])dnl + + dnl Release version of the gettext macros. This is used to ensure that + dnl the gettext macros and po/Makefile.in.in are in sync. + AC_SUBST([GETTEXT_MACRO_VERSION], [0.19]) + + dnl Perform the following tests also if --disable-nls has been given, + dnl because they are needed for "make dist" to work. + + dnl Search for GNU msgfmt in the PATH. + dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. + dnl The second test excludes FreeBSD msgfmt. + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + AC_PATH_PROG([GMSGFMT], [gmsgfmt], [$MSGFMT]) + + dnl Test whether it is GNU msgfmt >= 0.15. +changequote(,)dnl + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([MSGFMT_015]) +changequote(,)dnl + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac +changequote([,])dnl + AC_SUBST([GMSGFMT_015]) + + dnl Search for GNU xgettext 0.12 or newer in the PATH. + dnl The first test excludes Solaris xgettext and early GNU xgettext versions. + dnl The second test excludes FreeBSD xgettext. + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + + dnl Test whether it is GNU xgettext >= 0.15. +changequote(,)dnl + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac +changequote([,])dnl + AC_SUBST([XGETTEXT_015]) + + dnl Search for GNU msgmerge 0.11 or newer in the PATH. + AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, + [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) + + dnl Installation directories. + dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we + dnl have to define it here, so that it can be used in po/Makefile. + test -n "$localedir" || localedir='${datadir}/locale' + AC_SUBST([localedir]) + + dnl Support for AM_XGETTEXT_OPTION. + test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= + AC_SUBST([XGETTEXT_EXTRA_OPTIONS]) + + AC_CONFIG_COMMANDS([po-directories], [[ + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + gt_tab=`printf '\t'` + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ${gt_tab}]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done]], + [# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + ]) +]) + +dnl Postprocesses a Makefile in a directory containing PO files. +AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], +[ + # When this code is run, in config.status, two variables have already been + # set: + # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, + # - LINGUAS is the value of the environment variable LINGUAS at configure + # time. + +changequote(,)dnl + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + # Find a way to echo strings without interpreting backslash. + if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='echo' + else + if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then + gt_echo='printf %s\n' + else + echo_func () { + cat < "$ac_file.tmp" + tab=`printf '\t'` + if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` + cat >> "$ac_file.tmp" < /dev/null; then + # Add dependencies that cannot be formulated as a simple suffix rule. + for lang in $ALL_LINGUAS; do + frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` + cat >> "$ac_file.tmp" <> "$ac_file.tmp" < +#include +/* The string "%2$d %1$d", with dollar characters protected from the shell's + dollar expansion (possibly an autoconf bug). */ +static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; +static char buf[100]; +int main () +{ + sprintf (buf, format, 33, 55); + return (strcmp (buf, "55 33") != 0); +}], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, + [ + AC_EGREP_CPP(notposix, [ +#if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ + notposix +#endif + ], gt_cv_func_printf_posix="guessing no", + gt_cv_func_printf_posix="guessing yes") + ]) + ]) + case $gt_cv_func_printf_posix in + *yes) + AC_DEFINE(HAVE_POSIX_PRINTF, 1, + [Define if your printf() function supports format strings with positions.]) + ;; + esac +]) diff --git a/comm/third_party/libgpg-error/m4/progtest.m4 b/comm/third_party/libgpg-error/m4/progtest.m4 new file mode 100644 index 0000000000..b499f79cf3 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/progtest.m4 @@ -0,0 +1,91 @@ +# progtest.m4 serial 7 (gettext-0.18.2) +dnl Copyright (C) 1996-2003, 2005, 2008-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1996. + +AC_PREREQ([2.50]) + +# Search path for a program which passes the given test. + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST], +[ +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL([ac_cv_path_$1], +[case "[$]$1" in + [[\\/]]* | ?:[[\\/]]*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in ifelse([$5], , $PATH, [$5]); do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$][$1]) +else + AC_MSG_RESULT([no]) +fi +AC_SUBST([$1])dnl +]) diff --git a/comm/third_party/libgpg-error/m4/readline.m4 b/comm/third_party/libgpg-error/m4/readline.m4 new file mode 100644 index 0000000000..2ffbc7bade --- /dev/null +++ b/comm/third_party/libgpg-error/m4/readline.m4 @@ -0,0 +1,66 @@ +dnl Check for readline and dependencies +dnl Copyright (C) 2004, 2005 Free Software Foundation, Inc. +dnl +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl Defines HAVE_LIBREADLINE to 1 if a working readline setup is +dnl found, and sets @LIBREADLINE@ to the necessary libraries. + + +AC_DEFUN([GNUPG_CHECK_READLINE], +[ + AC_ARG_WITH(readline, + AS_HELP_STRING([--with-readline=DIR], + [look for the readline library in DIR]), + [_do_readline=$withval],[_do_readline=yes]) + + gnupg_cv_have_readline=no + if test "$_do_readline" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + for _termcap in "" "-ltermcap" "-lcurses" "-lncurses" ; do + _readline_save_libs=$LIBS + _combo="-lreadline${_termcap:+ $_termcap}" + LIBS="$LIBS $_combo" + + AC_MSG_CHECKING([whether readline via "$_combo" is present and sane]) + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +]],[[ +rl_completion_func_t *completer; +add_history("foobar"); +rl_catch_signals=0; +rl_inhibit_completion=0; +rl_attempted_completion_function=NULL; +rl_completion_matches(NULL,NULL); +]])],[_found_readline=yes],[_found_readline=no]) + + AC_MSG_RESULT([$_found_readline]) + + LIBS=$_readline_save_libs + + if test $_found_readline = yes ; then + AC_DEFINE(HAVE_LIBREADLINE,1, + [Define to 1 if you have a fully functional readline library.]) + AC_SUBST(LIBREADLINE,$_combo) + gnupg_cv_have_readline=yes + break + fi + done + + unset _termcap + unset _readline_save_libs + unset _combo + unset _found_readline + fi +])dnl diff --git a/comm/third_party/libgpg-error/m4/signed.m4 b/comm/third_party/libgpg-error/m4/signed.m4 new file mode 100644 index 0000000000..048f593698 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/signed.m4 @@ -0,0 +1,17 @@ +# signed.m4 serial 1 (gettext-0.10.40) +dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([bh_C_SIGNED], +[ + AC_CACHE_CHECK([for signed], bh_cv_c_signed, + [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)]) + if test $bh_cv_c_signed = no; then + AC_DEFINE(signed, , + [Define to empty if the C compiler doesn't support this keyword.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/size_max.m4 b/comm/third_party/libgpg-error/m4/size_max.m4 new file mode 100644 index 0000000000..029e471950 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/size_max.m4 @@ -0,0 +1,60 @@ +# size_max.m4 serial 4 +dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([gl_SIZE_MAX], +[ + AC_CHECK_HEADERS(stdint.h) + dnl First test whether the system already has SIZE_MAX. + AC_MSG_CHECKING([for SIZE_MAX]) + result= + AC_EGREP_CPP([Found it], [ +#include +#if HAVE_STDINT_H +#include +#endif +#ifdef SIZE_MAX +Found it +#endif +], result=yes) + if test -z "$result"; then + dnl Define it ourselves. Here we assume that the type 'size_t' is not wider + dnl than the type 'unsigned long'. Try hard to find a definition that can + dnl be used in a preprocessor #if, i.e. doesn't contain a cast. + _AC_COMPUTE_INT([sizeof (size_t) * CHAR_BIT - 1], size_t_bits_minus_1, + [#include +#include ], size_t_bits_minus_1=) + _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, + [#include ], fits_in_uint=) + if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then + if test $fits_in_uint = 1; then + dnl Even though SIZE_MAX fits in an unsigned int, it must be of type + dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. + AC_TRY_COMPILE([#include + extern size_t foo; + extern unsigned long foo; + ], [], fits_in_uint=0) + fi + dnl We cannot use 'expr' to simplify this expression, because 'expr' + dnl works only with 'long' integers in the host environment, while we + dnl might be cross-compiling from a 32-bit platform to a 64-bit platform. + if test $fits_in_uint = 1; then + result="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" + else + result="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" + fi + else + dnl Shouldn't happen, but who knows... + result='((size_t)~(size_t)0)' + fi + fi + AC_MSG_RESULT([$result]) + if test "$result" != yes; then + AC_DEFINE_UNQUOTED([SIZE_MAX], [$result], + [Define as the maximum value of type 'size_t', if the system doesn't define it.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/stdint_h.m4 b/comm/third_party/libgpg-error/m4/stdint_h.m4 new file mode 100644 index 0000000000..3355f35aa3 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/stdint_h.m4 @@ -0,0 +1,26 @@ +# stdint_h.m4 serial 5 +dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_STDINT_H_WITH_UINTMAX if exists, +# doesn't clash with , and declares uintmax_t. + +AC_DEFUN([gl_AC_HEADER_STDINT_H], +[ + AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, + [AC_TRY_COMPILE( + [#include +#include ], + [uintmax_t i = (uintmax_t) -1;], + gl_cv_header_stdint_h=yes, + gl_cv_header_stdint_h=no)]) + if test $gl_cv_header_stdint_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, + [Define if exists, doesn't clash with , + and declares uintmax_t. ]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/threadlib.m4 b/comm/third_party/libgpg-error/m4/threadlib.m4 new file mode 100644 index 0000000000..b486395002 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/threadlib.m4 @@ -0,0 +1,349 @@ +# threadlib.m4 serial 10 (gettext-0.18.2) modified by wk 2014-01-24. +dnl Copyright (C) 2005-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl gl_THREADLIB +dnl ------------ +dnl Tests for a multithreading library to be used. +dnl If the configure.ac contains a definition of the gl_THREADLIB_DEFAULT_NO +dnl (it must be placed before the invocation of gl_THREADLIB_EARLY!), then the +dnl default is 'no', otherwise it is system dependent. In both cases, the user +dnl can change the choice through the options --enable-threads=choice or +dnl --disable-threads. +dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, +dnl USE_WINDOWS_THREADS +dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use +dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with +dnl libtool). +dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for +dnl programs that really need multithread functionality. The difference +dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak +dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". +dnl Sets THREADLIB_CPPFLAGS to -D_REENTRANT or -D_THREAD_SAFE if needed for +dnl multithread-safe programs and adds THREADLIB_CPPFLAGS to CPPFLAGS. + +AC_DEFUN([gl_THREADLIB_EARLY], +[ + AC_REQUIRE([gl_THREADLIB_EARLY_BODY]) +]) + +dnl The guts of gl_THREADLIB_EARLY. Needs to be expanded only once. + +AC_DEFUN([gl_THREADLIB_EARLY_BODY], +[ + dnl Ordering constraints: This macro modifies CPPFLAGS in a way that + dnl influences the result of the autoconf tests that test for *_unlocked + dnl declarations, on AIX 5 at least. Therefore it must come early. + AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl + AC_BEFORE([$0], [gl_ARGP])dnl + + AC_REQUIRE([AC_CANONICAL_HOST]) + dnl _GNU_SOURCE is needed for pthread_rwlock_t on glibc systems. + dnl AC_USE_SYSTEM_EXTENSIONS was introduced in autoconf 2.60 and obsoletes + dnl AC_GNU_SOURCE. + m4_ifdef([AC_USE_SYSTEM_EXTENSIONS], + [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])], + [AC_REQUIRE([AC_GNU_SOURCE])]) + dnl Check for multithreading. + THREADLIB_CPPFLAGS="" + m4_ifdef([gl_THREADLIB_DEFAULT_NO], + [m4_divert_text([DEFAULTS], [gl_use_threads_default=no])], + [m4_divert_text([DEFAULTS], [gl_use_threads_default=])]) + AC_ARG_ENABLE([threads], +AS_HELP_STRING([--enable-threads={posix|solaris|windows}], [specify multithreading API])m4_ifdef([gl_THREADLIB_DEFAULT_NO], [], [ +AS_HELP_STRING([--disable-threads], [build without multithread safety])]), + [gl_use_threads=$enableval], + [if test -n "$gl_use_threads_default"; then + gl_use_threads="$gl_use_threads_default" + else +changequote(,)dnl + case "$host_os" in + dnl Disable multithreading by default on OSF/1, because it interferes + dnl with fork()/exec(): When msgexec is linked with -lpthread, its + dnl child process gets an endless segmentation fault inside execvp(). + dnl Disable multithreading by default on Cygwin 1.5.x, because it has + dnl bugs that lead to endless loops or crashes. See + dnl . + osf*) gl_use_threads=no ;; + cygwin*) + case `uname -r` in + 1.[0-5].*) gl_use_threads=no ;; + *) gl_use_threads=yes ;; + esac + ;; + *) gl_use_threads=yes ;; + esac +changequote([,])dnl + fi + ]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # For using : + case "$host_os" in + osf*) + # On OSF/1, the compiler needs the flag -D_REENTRANT so that it + # groks . cc also understands the flag -pthread, but + # we don't use it because 1. gcc-2.95 doesn't understand -pthread, + # 2. putting a flag into CPPFLAGS that has an effect on the linker + # causes the AC_LINK_IFELSE test below to succeed unexpectedly, + # leading to wrong values of LIBTHREAD and LTLIBTHREAD. + THREADLIB_CPPFLAGS="$THREADLIB_CPPFLAGS -D_REENTRANT" + ;; + esac + # Some systems optimize for single-threaded programs by default, and + # need special flags to disable these optimizations. For example, the + # definition of 'errno' in . + case "$host_os" in + aix* | freebsd*) + THREADLIB_CPPFLAGS="$THREADLIB_CPPFLAGS -D_THREAD_SAFE" + ;; + solaris*) + THREADLIB_CPPFLAGS="$THREADLIB_CPPFLAGS -D_REENTRANT" + ;; + esac + fi + if test x"$THREADLIB_CPPFLAGS" != x ; then + CPPFLAGS="$CPPFLAGS $THREADLIB_CPPFLAGS" + fi +]) + +dnl The guts of gl_THREADLIB. Needs to be expanded only once. + +AC_DEFUN([gl_THREADLIB_BODY], +[ + AC_REQUIRE([gl_THREADLIB_EARLY_BODY]) + gl_threads_api=none + LIBTHREAD= + LTLIBTHREAD= + LIBMULTITHREAD= + LTLIBMULTITHREAD= + if test "$gl_use_threads" != no; then + dnl Check whether the compiler and linker support weak declarations. + AC_CACHE_CHECK([whether imported symbols can be declared weak], + [gl_cv_have_weak], + [gl_cv_have_weak=no + dnl First, test whether the compiler accepts it syntactically. + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[extern void xyzzy (); +#pragma weak xyzzy]], + [[xyzzy();]])], + [gl_cv_have_weak=maybe]) + if test $gl_cv_have_weak = maybe; then + dnl Second, test whether it actually works. On Cygwin 1.7.2, with + dnl gcc 4.3, symbols declared weak always evaluate to the address 0. + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#pragma weak fputs +int main () +{ + return (fputs == NULL); +}]])], + [gl_cv_have_weak=yes], + [gl_cv_have_weak=no], + [dnl When cross-compiling, assume that only ELF platforms support + dnl weak symbols. + AC_EGREP_CPP([Extensible Linking Format], + [#ifdef __ELF__ + Extensible Linking Format + #endif + ], + [gl_cv_have_weak="guessing yes"], + [gl_cv_have_weak="guessing no"]) + ]) + fi + ]) + if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then + # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that + # it groks . It's added above, in gl_THREADLIB_EARLY_BODY. + AC_CHECK_HEADER([pthread.h], + [gl_have_pthread_h=yes], [gl_have_pthread_h=no]) + if test "$gl_have_pthread_h" = yes; then + # Other possible tests: + # -lpthreads (FSU threads, PCthreads) + # -lgthreads + gl_have_pthread= + # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist + # in libc. IRIX 6.5 has the first one in both libc and libpthread, but + # the second one only in libpthread, and lock.c needs it. + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[pthread_mutex_lock((pthread_mutex_t*)0); + pthread_mutexattr_init((pthread_mutexattr_t*)0);]])], + [gl_have_pthread=yes]) + # Test for libpthread by looking for pthread_kill. (Not pthread_self, + # since it is defined as a macro on OSF/1.) + if test -n "$gl_have_pthread"; then + # The program links fine without libpthread. But it may actually + # need to link with libpthread in order to create multiple threads. + AC_CHECK_LIB([pthread], [pthread_kill], + [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread + # On Solaris and HP-UX, most pthread functions exist also in libc. + # Therefore pthread_in_use() needs to actually try to create a + # thread: pthread_create from libc will fail, whereas + # pthread_create will actually create a thread. + case "$host_os" in + solaris* | hpux*) + AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], [1], + [Define if the pthread_in_use() detection is hard.]) + esac + ]) + else + # Some library is needed. Try libpthread and libc_r. + AC_CHECK_LIB([pthread], [pthread_kill], + [gl_have_pthread=yes + LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread + LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) + if test -z "$gl_have_pthread"; then + # For FreeBSD 4. + AC_CHECK_LIB([c_r], [pthread_kill], + [gl_have_pthread=yes + LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r + LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) + fi + fi + if test -n "$gl_have_pthread"; then + gl_threads_api=posix + AC_DEFINE([USE_POSIX_THREADS], [1], + [Define if the POSIX multithreading library can be used.]) + if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then + if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then + AC_DEFINE([USE_POSIX_THREADS_WEAK], [1], + [Define if references to the POSIX multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + fi + fi + fi + if test -z "$gl_have_pthread"; then + if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then + gl_have_solaristhread= + gl_save_LIBS="$LIBS" + LIBS="$LIBS -lthread" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include + ]], + [[thr_self();]])], + [gl_have_solaristhread=yes]) + LIBS="$gl_save_LIBS" + if test -n "$gl_have_solaristhread"; then + gl_threads_api=solaris + LIBTHREAD=-lthread + LTLIBTHREAD=-lthread + LIBMULTITHREAD="$LIBTHREAD" + LTLIBMULTITHREAD="$LTLIBTHREAD" + AC_DEFINE([USE_SOLARIS_THREADS], [1], + [Define if the old Solaris multithreading library can be used.]) + if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then + AC_DEFINE([USE_SOLARIS_THREADS_WEAK], [1], + [Define if references to the old Solaris multithreading library should be made weak.]) + LIBTHREAD= + LTLIBTHREAD= + fi + fi + fi + fi + if test -z "$gl_have_pthread"; then + case "$gl_use_threads" in + yes | windows | win32) # The 'win32' is for backward compatibility. + if { case "$host_os" in + mingw*) true;; + *) false;; + esac + }; then + gl_threads_api=windows + AC_DEFINE([USE_WINDOWS_THREADS], [1], + [Define if the native Windows multithreading API can be used.]) + fi + ;; + esac + fi + fi + AC_MSG_CHECKING([for multithread API to use]) + AC_MSG_RESULT([$gl_threads_api]) + AC_SUBST([LIBTHREAD]) + AC_SUBST([LTLIBTHREAD]) + AC_SUBST([LIBMULTITHREAD]) + AC_SUBST([LTLIBMULTITHREAD]) +]) + +AC_DEFUN([gl_THREADLIB], +[ + AC_REQUIRE([gl_THREADLIB_EARLY]) + AC_REQUIRE([gl_THREADLIB_BODY]) +]) + + +dnl gl_DISABLE_THREADS +dnl ------------------ +dnl Sets the gl_THREADLIB default so that threads are not used by default. +dnl The user can still override it at installation time, by using the +dnl configure option '--enable-threads'. + +AC_DEFUN([gl_DISABLE_THREADS], [ + m4_divert_text([INIT_PREPARE], [gl_use_threads_default=no]) +]) + + +dnl Survey of platforms: +dnl +dnl Platform Available Compiler Supports test-lock +dnl flavours option weak result +dnl --------------- --------- --------- -------- --------- +dnl Linux 2.4/glibc posix -lpthread Y OK +dnl +dnl GNU Hurd/glibc posix +dnl +dnl FreeBSD 5.3 posix -lc_r Y +dnl posix -lkse ? Y +dnl posix -lpthread ? Y +dnl posix -lthr Y +dnl +dnl FreeBSD 5.2 posix -lc_r Y +dnl posix -lkse Y +dnl posix -lthr Y +dnl +dnl FreeBSD 4.0,4.10 posix -lc_r Y OK +dnl +dnl NetBSD 1.6 -- +dnl +dnl OpenBSD 3.4 posix -lpthread Y OK +dnl +dnl Mac OS X 10.[123] posix -lpthread Y OK +dnl +dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK +dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK +dnl +dnl HP-UX 11 posix -lpthread N (cc) OK +dnl Y (gcc) +dnl +dnl IRIX 6.5 posix -lpthread Y 0.5 +dnl +dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK +dnl +dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK +dnl -lpthread (gcc) Y +dnl +dnl Cygwin posix -lpthread Y OK +dnl +dnl Any of the above pth -lpth 0.0 +dnl +dnl Mingw windows N OK +dnl +dnl BeOS 5 -- +dnl +dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is +dnl turned off: +dnl OK if all three tests terminate OK, +dnl 0.5 if the first test terminates OK but the second one loops endlessly, +dnl 0.0 if the first test already loops endlessly. diff --git a/comm/third_party/libgpg-error/m4/uintmax_t.m4 b/comm/third_party/libgpg-error/m4/uintmax_t.m4 new file mode 100644 index 0000000000..bf83ed7464 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/uintmax_t.m4 @@ -0,0 +1,30 @@ +# uintmax_t.m4 serial 9 +dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +AC_PREREQ(2.13) + +# Define uintmax_t to 'unsigned long' or 'unsigned long long' +# if it is not already defined in or . + +AC_DEFUN([gl_AC_TYPE_UINTMAX_T], +[ + AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([gl_AC_HEADER_STDINT_H]) + if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then + AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) + test $ac_cv_type_unsigned_long_long = yes \ + && ac_type='unsigned long long' \ + || ac_type='unsigned long' + AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, + [Define to unsigned long or unsigned long long + if and don't define.]) + else + AC_DEFINE(HAVE_UINTMAX_T, 1, + [Define if you have the 'uintmax_t' type in or .]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/ulonglong.m4 b/comm/third_party/libgpg-error/m4/ulonglong.m4 new file mode 100644 index 0000000000..dee10ccc3e --- /dev/null +++ b/comm/third_party/libgpg-error/m4/ulonglong.m4 @@ -0,0 +1,23 @@ +# ulonglong.m4 serial 4 +dnl Copyright (C) 1999-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_UNSIGNED_LONG_LONG if 'unsigned long long' works. + +AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], +[ + AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long, + [AC_TRY_LINK([unsigned long long ull = 1ULL; int i = 63;], + [unsigned long long ullmax = (unsigned long long) -1; + return ull << i | ull >> i | ullmax / ull | ullmax % ull;], + ac_cv_type_unsigned_long_long=yes, + ac_cv_type_unsigned_long_long=no)]) + if test $ac_cv_type_unsigned_long_long = yes; then + AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, + [Define if you have the 'unsigned long long' type.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/visibility.m4 b/comm/third_party/libgpg-error/m4/visibility.m4 new file mode 100644 index 0000000000..2ff6330aa4 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/visibility.m4 @@ -0,0 +1,52 @@ +# visibility.m4 serial 1 (gettext-0.15) +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Tests whether the compiler supports the command-line option +dnl -fvisibility=hidden and the function and variable attributes +dnl __attribute__((__visibility__("hidden"))) and +dnl __attribute__((__visibility__("default"))). +dnl Does *not* test for __visibility__("protected") - which has tricky +dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on +dnl MacOS X. +dnl Does *not* test for __visibility__("internal") - which has processor +dnl dependent semantics. +dnl Does *not* test for #pragma GCC visibility push(hidden) - which is +dnl "really only recommended for legacy code". +dnl Set the variable CFLAG_VISIBILITY. +dnl Defines and sets the variable HAVE_VISIBILITY. + +AC_DEFUN([gl_VISIBILITY], +[ + AC_REQUIRE([AC_PROG_CC]) + CFLAG_VISIBILITY= + HAVE_VISIBILITY=0 + if test -n "$GCC"; then + AC_MSG_CHECKING([for simple visibility declarations]) + AC_CACHE_VAL(gl_cv_cc_visibility, [ + gl_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + AC_TRY_COMPILE( + [extern __attribute__((__visibility__("hidden"))) int hiddenvar; + extern __attribute__((__visibility__("default"))) int exportedvar; + extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); + extern __attribute__((__visibility__("default"))) int exportedfunc (void);], + [], + gl_cv_cc_visibility=yes, + gl_cv_cc_visibility=no) + CFLAGS="$gl_save_CFLAGS"]) + AC_MSG_RESULT([$gl_cv_cc_visibility]) + if test $gl_cv_cc_visibility = yes; then + CFLAG_VISIBILITY="-fvisibility=hidden" + HAVE_VISIBILITY=1 + fi + fi + AC_SUBST([CFLAG_VISIBILITY]) + AC_SUBST([HAVE_VISIBILITY]) + AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], + [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) +]) diff --git a/comm/third_party/libgpg-error/m4/wchar_t.m4 b/comm/third_party/libgpg-error/m4/wchar_t.m4 new file mode 100644 index 0000000000..cde2129a97 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/wchar_t.m4 @@ -0,0 +1,20 @@ +# wchar_t.m4 serial 1 (gettext-0.12) +dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wchar_t' type. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WCHAR_T], +[ + AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, + [AC_TRY_COMPILE([#include + wchar_t foo = (wchar_t)'\0';], , + gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) + if test $gt_cv_c_wchar_t = yes; then + AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/wint_t.m4 b/comm/third_party/libgpg-error/m4/wint_t.m4 new file mode 100644 index 0000000000..b8fff9c86f --- /dev/null +++ b/comm/third_party/libgpg-error/m4/wint_t.m4 @@ -0,0 +1,20 @@ +# wint_t.m4 serial 1 (gettext-0.12) +dnl Copyright (C) 2003 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wint_t' type. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WINT_T], +[ + AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, + [AC_TRY_COMPILE([#include + wint_t foo = (wchar_t)'\0';], , + gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) + if test $gt_cv_c_wint_t = yes; then + AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) + fi +]) diff --git a/comm/third_party/libgpg-error/m4/xsize.m4 b/comm/third_party/libgpg-error/m4/xsize.m4 new file mode 100644 index 0000000000..85bb721e43 --- /dev/null +++ b/comm/third_party/libgpg-error/m4/xsize.m4 @@ -0,0 +1,13 @@ +# xsize.m4 serial 3 +dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_XSIZE], +[ + dnl Prerequisites of lib/xsize.h. + AC_REQUIRE([gl_SIZE_MAX]) + AC_REQUIRE([AC_C_INLINE]) + AC_CHECK_HEADERS(stdint.h) +]) diff --git a/comm/third_party/libgpg-error/mkinstalldirs b/comm/third_party/libgpg-error/mkinstalldirs new file mode 100755 index 0000000000..55d537f872 --- /dev/null +++ b/comm/third_party/libgpg-error/mkinstalldirs @@ -0,0 +1,162 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2009-04-28.21; # UTC + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' +IFS=" "" $nl" +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the 'mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because '.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libgpg-error/po/ChangeLog-2011 b/comm/third_party/libgpg-error/po/ChangeLog-2011 new file mode 100644 index 0000000000..ddc40f9718 --- /dev/null +++ b/comm/third_party/libgpg-error/po/ChangeLog-2011 @@ -0,0 +1,146 @@ +2011-12-01 Werner Koch + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2010-09-16 Jakub Bogusz (wk) + + * pl.po: Update. + +2010-09-16 gettextize + + * Makefile.in.in: Upgrade to gettext-0.17. + +2010-05-06 Freek de Kruijf (wk) + + * nl.po: New. + +2010-05-06 Clytie Siddall (wk) + + * vi.po: Update + +2009-08-20 Werner Koch + + * LINGUAS: Add zh_CN, cs and it. + * cs.po: New. + * it.po: New. + +2009-08-20 Daniel Nylander (wk) + + * sv.po: Update + +2009-08-20 Aron Xu (wk) + + * zh_CN.po: New. + +2009-03-29 Moritz + + * de.po: Fixed typo. + +2008-11-12 Werner Koch + + * de.po: Fixed typo. + +2007-10-29 Daniel Nylander (wk) + + * sv.po: Update. + +2007-10-29 Clytie Siddall (wk) + + * vi.po: Update. + +2007-10-29 Jakub Bogusz (wk) + + * pl.po: Update. + +2007-08-23 Werner Koch + + * de.po: Typo fix [bug#828]. + +2007-02-26 Werner Koch + + * sv.po: Update from Daniel. + +2006-12-22 Werner Koch + + * LINGUAS, sv.po: Installed Swedish translation by Daniel Nylander. + +2006-11-23 gettextize + + * Makefile.in.in: Upgrade to gettext-0.15. + +2006-09-14 Werner Koch + + * de.po: Updated. + +2006-09-08 Werner Koch + + * pl.po: Updated. + +2006-03-14 gettextize + + * Makefile.in.in: Upgrade to gettext-0.14.5. + * Rules-quot: Upgrade to gettext-0.14.5. + +2006-01-11 Werner Koch + + * vi.po: New. + * LINGUAS: Add vi. + +2005-09-29 Marcus Brinkmann + + * fr.po: New file. + * LINGUAS: Add fr. + +2005-07-04 Werner Koch + + * ro.po: New. + +2005-06-16 Marcus Brinkmann + + * de.po: Apply typo fixes from Debian #313977. + +2004-04-22 Marcus Brinkmann + + * POTFILES.in: Add src/gpg-error.c. + * pl.po: Add messages for gpg-error.c. + * de.po: Likewise. + + * pl.po: Update. + +2004-04-20 Marcus Brinkmann + + * LINGUAS: Add pl. + * pl.po: New file. + +2003-12-08 gettextize + + * Makefile.in.in: Upgrade to gettext-0.12.1. + +2003-11-14 Werner Koch + + * de.po: New. + +2003-05-15 gettextize + + * Makefile.in.in: New file, from gettext-0.11.5. + * boldquot.sed: New file, from gettext-0.11.5. + * en@boldquot.header: New file, from gettext-0.11.5. + * en@quot.header: New file, from gettext-0.11.5. + * insert-header.sin: New file, from gettext-0.11.5. + * quot.sed: New file, from gettext-0.11.5. + * remove-potcdate.sin: New file, from gettext-0.11.5. + * Rules-quot: New file, from gettext-0.11.5. + + + Copyright 2003, 2010 g10 Code GmbH + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/comm/third_party/libgpg-error/po/LINGUAS b/comm/third_party/libgpg-error/po/LINGUAS new file mode 100644 index 0000000000..33a80b72ac --- /dev/null +++ b/comm/third_party/libgpg-error/po/LINGUAS @@ -0,0 +1,21 @@ +# Set of available languages. +cs +da +de +eo +es +fr +hu +it +ja +nl +pl +pt +ro +ru +sr +sv +uk +vi +zh_CN +zh_TW diff --git a/comm/third_party/libgpg-error/po/Makefile.in.in b/comm/third_party/libgpg-error/po/Makefile.in.in new file mode 100644 index 0000000000..65184f65c7 --- /dev/null +++ b/comm/third_party/libgpg-error/po/Makefile.in.in @@ -0,0 +1,475 @@ +# Makefile for PO directory in any package using GNU gettext. +# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU General Public +# License but which still want to provide support for the GNU gettext +# functionality. +# Please note that the actual code of GNU gettext is covered by the GNU +# General Public License and is *not* in the public domain. +# +# Origin: gettext-0.19 +GETTEXT_MACRO_VERSION = 0.19 + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ + +SED = @SED@ +SHELL = /bin/sh +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +localedir = @localedir@ +gettextsrcdir = $(datadir)/gettext/po + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# We use $(mkdir_p). +# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as +# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, +# @install_sh@ does not start with $(SHELL), so we add it. +# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined +# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake +# versions, $(mkinstalldirs) and $(install_sh) are unused. +mkinstalldirs = $(SHELL) @install_sh@ -d +install_sh = $(SHELL) @install_sh@ +MKDIR_P = @MKDIR_P@ +mkdir_p = @mkdir_p@ + +GMSGFMT_ = @GMSGFMT@ +GMSGFMT_no = @GMSGFMT@ +GMSGFMT_yes = @GMSGFMT_015@ +GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) +MSGFMT_ = @MSGFMT@ +MSGFMT_no = @MSGFMT@ +MSGFMT_yes = @MSGFMT_015@ +MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) +XGETTEXT_ = @XGETTEXT@ +XGETTEXT_no = @XGETTEXT@ +XGETTEXT_yes = @XGETTEXT_015@ +XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) +MSGMERGE = msgmerge +MSGMERGE_UPDATE = @MSGMERGE@ --update +MSGINIT = msginit +MSGCONV = msgconv +MSGFILTER = msgfilter + +POFILES = @POFILES@ +GMOFILES = @GMOFILES@ +UPDATEPOFILES = @UPDATEPOFILES@ +DUMMYPOFILES = @DUMMYPOFILES@ +DISTFILES.common = Makefile.in.in remove-potcdate.sin \ +$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) +DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ +$(POFILES) $(GMOFILES) \ +$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) + +POTFILES = \ + +CATALOGS = @CATALOGS@ + +POFILESDEPS_ = $(srcdir)/$(DOMAIN).pot +POFILESDEPS_yes = $(POFILESDEPS_) +POFILESDEPS_no = +POFILESDEPS = $(POFILESDEPS_$(PO_DEPENDS_ON_POT)) + +DISTFILESDEPS_ = update-po +DISTFILESDEPS_yes = $(DISTFILESDEPS_) +DISTFILESDEPS_no = +DISTFILESDEPS = $(DISTFILESDEPS_$(DIST_DEPENDS_ON_UPDATE_PO)) + +# Makevars gets inserted here. (Don't remove this line!) + +.SUFFIXES: +.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update + +.po.mo: + @echo "$(MSGFMT) -c -o $@ $<"; \ + $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ + +.po.gmo: + @lang=`echo $* | sed -e 's,.*/,,'`; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \ + cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo + +.sin.sed: + sed -e '/^#/d' $< > t-$@ + mv t-$@ $@ + + +all: all-@USE_NLS@ + +all-yes: stamp-po +all-no: + +# Ensure that the gettext macros and this Makefile.in.in are in sync. +CHECK_MACRO_VERSION = \ + test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \ + || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \ + exit 1; \ + } + +# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no +# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because +# we don't want to bother translators with empty POT files). We assume that +# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. +# In this case, stamp-po is a nop (i.e. a phony target). + +# stamp-po is a timestamp denoting the last time at which the CATALOGS have +# been loosely updated. Its purpose is that when a developer or translator +# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, +# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent +# invocations of "make" will do nothing. This timestamp would not be necessary +# if updating the $(CATALOGS) would always touch them; however, the rule for +# $(POFILES) has been designed to not touch files that don't need to be +# changed. +stamp-po: $(srcdir)/$(DOMAIN).pot + @$(CHECK_MACRO_VERSION) + test ! -f $(srcdir)/$(DOMAIN).pot || \ + test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) + @test ! -f $(srcdir)/$(DOMAIN).pot || { \ + echo "touch stamp-po" && \ + echo timestamp > stamp-poT && \ + mv stamp-poT stamp-po; \ + } + +# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', +# otherwise packages like GCC can not be built if only parts of the source +# have been downloaded. + +# This target rebuilds $(DOMAIN).pot; it is an expensive operation. +# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. +# The determination of whether the package xyz is a GNU one is based on the +# heuristic whether some file in the top level directory mentions "GNU xyz". +# If GNU 'find' is available, we avoid grepping through monster files. +$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed + package_gnu="$(PACKAGE_GNU)"; \ + test -n "$$package_gnu" || { \ + if { if (LC_ALL=C find --version) 2>/dev/null | grep GNU >/dev/null; then \ + LC_ALL=C find -L $(top_srcdir) -maxdepth 1 -type f \ + -size -10000000c -exec grep 'GNU @PACKAGE@' \ + /dev/null '{}' ';' 2>/dev/null; \ + else \ + LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null; \ + fi; \ + } | grep -v 'libtool:' >/dev/null; then \ + package_gnu=yes; \ + else \ + package_gnu=no; \ + fi; \ + }; \ + if test "$$package_gnu" = "yes"; then \ + package_prefix='GNU '; \ + else \ + package_prefix=''; \ + fi; \ + if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ + msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ + else \ + msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ + fi; \ + case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + --msgid-bugs-address="$$msgid_bugs_address" \ + ;; \ + *) \ + $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ + --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \ + --files-from=$(srcdir)/POTFILES.in \ + --copyright-holder='$(COPYRIGHT_HOLDER)' \ + --package-name="$${package_prefix}@PACKAGE@" \ + --package-version='@VERSION@' \ + --msgid-bugs-address="$$msgid_bugs_address" \ + ;; \ + esac + test ! -f $(DOMAIN).po || { \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ + sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ + if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ + else \ + rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + else \ + mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ + fi; \ + } + +# This rule has no dependencies: we don't need to update $(DOMAIN).pot at +# every "make" invocation, only create it when it is missing. +# Only "make $(DOMAIN).pot-update" or "make dist" will force an update. +$(srcdir)/$(DOMAIN).pot: + $(MAKE) $(DOMAIN).pot-update + +# This target rebuilds a PO file if $(DOMAIN).pot has changed. +# Note that a PO file is not touched if it doesn't need to be changed. +$(POFILES): $(POFILESDEPS) + @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ + if test -f "$(srcdir)/$${lang}.po"; then \ + test -f $(srcdir)/$(DOMAIN).pot || $(MAKE) $(srcdir)/$(DOMAIN).pot; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \ + cd $(srcdir) \ + && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ + $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \ + *) \ + $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \ + esac; \ + }; \ + else \ + $(MAKE) $${lang}.po-create; \ + fi + + +install: install-exec install-data +install-exec: +install-data: install-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + for file in $(DISTFILES.common) Makevars.template; do \ + $(INSTALL_DATA) $(srcdir)/$$file \ + $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + for file in Makevars; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +install-data-no: all +install-data-yes: all + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ + $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ + echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ + cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ + fi; \ + done; \ + done + +install-strip: install + +installdirs: installdirs-exec installdirs-data +installdirs-exec: +installdirs-data: installdirs-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ + else \ + : ; \ + fi +installdirs-data-no: +installdirs-data-yes: + @catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + dir=$(localedir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $(DESTDIR)$$dir; \ + for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ + if test -n "$$lc"; then \ + if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ + link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ + mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ + for file in *; do \ + if test -f $$file; then \ + ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ + fi; \ + done); \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ + else \ + if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ + :; \ + else \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ + mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ + fi; \ + fi; \ + fi; \ + done; \ + done + +# Define this as empty until I found a useful application. +installcheck: + +uninstall: uninstall-exec uninstall-data +uninstall-exec: +uninstall-data: uninstall-data-@USE_NLS@ + if test "$(PACKAGE)" = "gettext-tools"; then \ + for file in $(DISTFILES.common) Makevars.template; do \ + rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ + done; \ + else \ + : ; \ + fi +uninstall-data-no: +uninstall-data-yes: + catalogs='$(CATALOGS)'; \ + for cat in $$catalogs; do \ + cat=`basename $$cat`; \ + lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ + for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ + rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ + done; \ + done + +check: all + +info dvi ps pdf html tags TAGS ctags CTAGS ID: + +mostlyclean: + rm -f remove-potcdate.sed + rm -f stamp-poT + rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po + rm -fr *.o + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES *.mo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f stamp-po $(GMOFILES) + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: + test -z "$(DISTFILESDEPS)" || $(MAKE) $(DISTFILESDEPS) + @$(MAKE) dist2 +# This is a separate target because 'update-po' must be executed before. +dist2: stamp-po $(DISTFILES) + dists="$(DISTFILES)"; \ + if test "$(PACKAGE)" = "gettext-tools"; then \ + dists="$$dists Makevars.template"; \ + fi; \ + if test -f $(srcdir)/$(DOMAIN).pot; then \ + dists="$$dists $(DOMAIN).pot stamp-po"; \ + fi; \ + if test -f $(srcdir)/ChangeLog; then \ + dists="$$dists ChangeLog"; \ + fi; \ + for i in 0 1 2 3 4 5 6 7 8 9; do \ + if test -f $(srcdir)/ChangeLog.$$i; then \ + dists="$$dists ChangeLog.$$i"; \ + fi; \ + done; \ + if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ + for file in $$dists; do \ + if test -f $$file; then \ + cp -p $$file $(distdir) || exit 1; \ + else \ + cp -p $(srcdir)/$$file $(distdir) || exit 1; \ + fi; \ + done + +update-po: Makefile + $(MAKE) $(DOMAIN).pot-update + test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) + $(MAKE) update-gmo + +# General rule for creating PO files. + +.nop.po-create: + @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ + echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ + exit 1 + +# General rule for updating PO files. + +.nop.po-update: + @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ + echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ + cd $(srcdir); \ + if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ + *) \ + $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \ + esac; \ + }; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +$(DUMMYPOFILES): + +update-gmo: Makefile $(GMOFILES) + @: + +# Recreate Makefile by invoking config.status. Explicitly invoke the shell, +# because execution permission bits may not work on the current file system. +# Use @SHELL@, which is the shell determined by autoconf for the use by its +# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient. +Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ + cd $(top_builddir) \ + && @SHELL@ ./config.status $(subdir)/$@.in po-directories + +force: + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgpg-error/po/Makevars b/comm/third_party/libgpg-error/po/Makevars new file mode 100644 index 0000000000..758523779d --- /dev/null +++ b/comm/third_party/libgpg-error/po/Makevars @@ -0,0 +1,79 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = g10 Code GmbH + +# This tells whether or not to prepend "GNU " prefix to the package +# name that gets inserted into the header of the $(DOMAIN).pot file. +# Possible values are "yes", "no", or empty. If it is empty, try to +# detect it automatically by scanning the files in $(top_srcdir) for +# "GNU packagename" string. +PACKAGE_GNU = no + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = translations@gnupg.org + + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = + +# This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt' +# context. Possible values are "yes" and "no". Set this to yes if the +# package uses functions taking also a message context, like pgettext(), or +# if in $(XGETTEXT_OPTIONS) you define keywords with a context argument. +USE_MSGCTXT = no + +# These options get passed to msgmerge. +# Useful options are in particular: +# --previous to keep previous msgids of translated messages, +# --quiet to reduce the verbosity. +MSGMERGE_OPTIONS = --previous + +# These options get passed to msginit. +# If you want to disable line wrapping when writing PO files, add +# --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and +# MSGINIT_OPTIONS. +MSGINIT_OPTIONS = + +# This tells whether or not to regenerate a PO file when $(DOMAIN).pot +# has changed. Possible values are "yes" and "no". Set this to no if +# the POT file is checked in the repository and the version control +# program ignores timestamps. +PO_DEPENDS_ON_POT = yes + +# This tells whether or not to forcibly update $(DOMAIN).pot and +# regenerate PO files on "make dist". Possible values are "yes" and +# "no". Set this to no if the POT file and PO files are maintained +# externally. +DIST_DEPENDS_ON_UPDATE_PO = yes diff --git a/comm/third_party/libgpg-error/po/POTFILES.in b/comm/third_party/libgpg-error/po/POTFILES.in new file mode 100644 index 0000000000..0932c980fc --- /dev/null +++ b/comm/third_party/libgpg-error/po/POTFILES.in @@ -0,0 +1,15 @@ +# List of source files containing translatable strings. +# Copyright 2003 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +src/err-sources.h +src/err-codes.h +src/argparse.c +src/gpg-error.c diff --git a/comm/third_party/libgpg-error/po/Rules-quot b/comm/third_party/libgpg-error/po/Rules-quot new file mode 100644 index 0000000000..9dc963076f --- /dev/null +++ b/comm/third_party/libgpg-error/po/Rules-quot @@ -0,0 +1,58 @@ +# This file, Rules-quot, can be copied and used freely without restrictions. +# Special Makefile rules for English message catalogs with quotation marks. + +DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot + +.SUFFIXES: .insert-header .po-update-en + +en@quot.po-create: + $(MAKE) en@quot.po-update +en@boldquot.po-create: + $(MAKE) en@boldquot.po-update + +en@quot.po-update: en@quot.po-update-en +en@boldquot.po-update: en@boldquot.po-update-en + +.insert-header.po-update-en: + @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ + if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ + tmpdir=`pwd`; \ + echo "$$lang:"; \ + ll=`echo $$lang | sed -e 's/@.*//'`; \ + LC_ALL=C; export LC_ALL; \ + cd $(srcdir); \ + if $(MSGINIT) $(MSGINIT_OPTIONS) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null \ + | $(SED) -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | \ + { case `$(MSGFILTER) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-8] | 0.1[0-8].*) \ + $(MSGFILTER) $(SED) -f `echo $$lang | sed -e 's/.*@//'`.sed \ + ;; \ + *) \ + $(MSGFILTER) `echo $$lang | sed -e 's/.*@//'` \ + ;; \ + esac } 2>/dev/null > $$tmpdir/$$lang.new.po \ + ; then \ + if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "creation of $$lang.po failed!" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi + +en@quot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header + +en@boldquot.insert-header: insert-header.sin + sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header + +mostlyclean: mostlyclean-quot +mostlyclean-quot: + rm -f *.insert-header diff --git a/comm/third_party/libgpg-error/po/boldquot.sed b/comm/third_party/libgpg-error/po/boldquot.sed new file mode 100644 index 0000000000..4b937aa517 --- /dev/null +++ b/comm/third_party/libgpg-error/po/boldquot.sed @@ -0,0 +1,10 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g +s/“/“/g +s/â€/â€/g +s/‘/‘/g +s/’/’/g diff --git a/comm/third_party/libgpg-error/po/cs.gmo b/comm/third_party/libgpg-error/po/cs.gmo new file mode 100644 index 0000000000..52861aeed5 Binary files /dev/null and b/comm/third_party/libgpg-error/po/cs.gmo differ diff --git a/comm/third_party/libgpg-error/po/cs.po b/comm/third_party/libgpg-error/po/cs.po new file mode 100644 index 0000000000..fe3ba27af7 --- /dev/null +++ b/comm/third_party/libgpg-error/po/cs.po @@ -0,0 +1,2198 @@ +# Czech translation of libgpg-error. +# Copyright (C) 2009 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Petr Pisar , 2009, 2012, 2014. +# +# certificate chain → Å™etÄ›zec (posloupnost) certifikátů +# keybox → schránka (na klíÄe) +# keyring → klíÄenka (jen na PGP klíÄe) +# armor → ASCII (podoba) +# encoding → kódování +# encryption → Å¡ifrování +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.18\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:24+0100\n" +"Last-Translator: Petr Pisar \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Zdroj nezadán" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +# XXX: Konzistentní s gnupg2 +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Schránka" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Nespecifikovaný zdroj" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Uživatelem definovaný zdroj 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Uživatelem definovaný zdroj 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Uživatelem definovaný zdroj 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Uživatelem definovaný zdroj 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Neznámý zdroj" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "ÚspÄ›ch" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Obecná chyba" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Neznámý packet" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Neznámá verze v packetu" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Neplatný algoritmus veÅ™ejného klíÄe" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Neplatný hashovací algoritmus" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Chybný veÅ™ejný klíÄ" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Chybný tajný klíÄ" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Chybný podpis" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Žádný veÅ™ejný klíÄ" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Chyba kontrolního souÄtu" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Chybné heslo" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Neplatný Å¡ifrovací algoritmus" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "KlíÄenka otevÅ™ena" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Neplatný packet" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Neplatný ASCII zápis" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Žádný identifikátor uživatele" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Žádný tajný klíÄ" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Použit Å¡patný tajný klíÄ" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Chybný klÃ­Ä relace" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Neznámý kompresní algoritmus" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Číslo není prvoÄíslo" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Neplatná kódovací metoda" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Neplatné Å¡ifrovací schéma" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Neplatné podpisové schéma" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Neplatný atribut" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Žádná hodnota" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Nenalezeno" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Hodnota nenalezena" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Chyba syntaxe" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Chybná hodnota MPI" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Neplatné heslo" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Neplatní podpisová třída" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Zdroje vyÄerpány" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Neplatná klíÄenka" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Chyba databáze důvÄ›ry" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Chybný certifikát" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Neplatné ID uživatele" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "NeoÄekávaná chyba" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Rozpor v Äasu" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Chyba serveru s klíÄi" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Å patný algoritmus veÅ™ejného klíÄe" + +# This is errror nuber 42 :) +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Pocta D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Slabý Å¡ifrovací klíÄ" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Neplatná délka klíÄe" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Neplatný argument" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Chyba syntaxe v URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Neplatné URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Chyba sítÄ›" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Neznámý stroj" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Sebetestování selhalo" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Data neÅ¡ifrována" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Data nezpracována" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Nepoužitelný veÅ™ejný klíÄ" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Nepoužitelný tajný klíÄ" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Neplatná hodnota" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Chybný Å™etÄ›zec certifikátů" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Chybí certifikát" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Žádná data" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Chyba" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Nepodporováno" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Neplatný kód operace" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "ÄŒas vyprÅ¡el" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "VnitÅ™ní chyba" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Neplatný objekt" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Dodaný objekt je příliÅ¡ krátký" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Dodaný objekt je příliÅ¡ dlouhý" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "V objektu chybí položka" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Neimplementováno" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "NesluÄitelné použití" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Neplatný režim Å¡ifry" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Neplatný příznak" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Neplatný deskriptor" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Výsledek zkrácen" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Neúplný řádek" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Neplatná odpovÄ›Ä" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Agent neběží" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Chyba agenta" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Neplatná data" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "NeurÄená porucha serveru Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Obecná chyba Assuanu" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Neplatný klÃ­Ä relace" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Neplatný S-výraz" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Nepodporovaný algoritmus" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Žádný pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "chyba pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Å patný PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Neplatné jméno" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Chybná data" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Neplatný parametr" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Å patná karta" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Žádný dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "chyba dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certifikát odvolán" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Není znám žádný CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "PříliÅ¡ starý CRL" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "PříliÅ¡ dlouhý řádek" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Nedůvěřuje se" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Operace zruÅ¡ena" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Chybný certifikát autority" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certifikátu vyprÅ¡ela platnost" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certifikát je příliÅ¡ mladý" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Nepodporovaný certifikát" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Neznámý S-výraz" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Nepodporovaná ochrana" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "PoÅ¡kozená ochrana" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "NejednoznaÄné jméno" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Chyba karty" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Vyžadován reset karty" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Karta odstranÄ›na" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Neplatná karta" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Karta není přítomna" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Žádná aplikace PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Nepotvrzeno" + +# Nastavení nebo nastavování? +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Chyba konfigurace" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Politika se neshoduje" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Neplatný index" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Neplatné ID" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Žádný démon pro Äipové karty" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Chyba démona pro Äipové karty" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Nepodporovaný protokol" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Chybná metoda PINu" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Karta neinicializovaná" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Nepodporovaná operace" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Å patné použití karty" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Nic nenalezeno" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Å patný typ blobu" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Chybí hodnota" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Hardwarový problém" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN blokován" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Podmínky použití nesplnÄ›ny" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PINy nejsou synchronizovány" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Neplatný CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Chyba BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Neplatné BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Prvek nenalezen" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identifikátor nenalezen" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Neplatná znaÄka" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Neplatná délka" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Neplatné informace o klíÄi" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "NeoÄekávaná znaÄka" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Nekódováno v DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Žádný objekt CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Neplatný objekt CMS" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Neznámý objekt CMS" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Nepodporovaný objekty CMS" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Nepodporované kódování" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Nepodporovaná verze CMS" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Neznámý algoritmus" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Neplatná kryptografická jednotka" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "VeÅ™ejnému klíÄi se nedůvěřuje" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "DeÅ¡ifrování selhalo" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "KlíÄi vyprÅ¡ela platnost" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Podpisu vyprÅ¡ela platnost" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Chyba kódování" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Neplatná stav" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Zdvojená hodnota" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Chybí akce" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Modul ASN.1 nenalezen" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Neplatný Å™etÄ›zec OID" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Neplatný Äas" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Neplatný objekt CRL" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Nepodporovaná verze CRL" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Neplatný objekt certifikátu" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Neznámé jméno" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Funkce locale selhala" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "NeuzamÄeno" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "NaruÅ¡ení protokolu" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Neplatný MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Neplatný požadavek" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Neznámé rozšíření" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Neznámé kritické rozšíření" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "ZamÄeno" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Neznámý parametr" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Neznámý příkaz" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "NefunkÄní" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Heslo nezadáno" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "PIN nezadán" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Nezapnuto" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Chybí kryptografická jednotka" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Chybí klíÄ" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "PříliÅ¡ mnoho objektů" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Dosažen limit" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Neinicializováno" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Chybí certifikát vydavatele" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Není dostupný žádný server klíÄů" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Neplatná eliptická kÅ™ivka" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Neznámá eliptická kÅ™ivka" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Zdvojený klíÄ" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "NejednoznaÄný výsledek" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Chybí kryptografický kontext" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Chybný kryptografický kontext" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Å patný kryptografický kontext" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Rozpor v kryptografickém kontextu" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Rozbitý veÅ™ejný klíÄ" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Rozbitý tajný klíÄ" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Neplatný algoritmus MAC" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Operace zcela zruÅ¡ena" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Operace jeÅ¡tÄ› neskonÄila" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Vyrovnávací paměť je příliÅ¡ malá" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Neplatné urÄení délky v S-výrazu" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "ŘetÄ›zec v S-výrazu je příliÅ¡ dlouhý" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Nepárové závorky v S-výrazu" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-výraz není kanonický" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Chybný znak v S-výrazu" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Chybné uzavÅ™ení do uvozovek v S-výrazu" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Nulová pÅ™edpona v S-výrazu" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "VnoÅ™ené pokyny pro zobrazení v S-výrazu" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Neodpovídající pokyny pro zobrazení" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "NeoÄekávaná vyhrazená interpunkce v S-výrazu" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Chybný Å¡estnáctkový znak v S-výrazu" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Lichá Å¡estnáctková Äísla v S-výrazu" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Chybný osmiÄkový znak v S-výrazu" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Data neÅ¡ifrována" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Neznámé jméno" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Žádný veÅ™ejný klíÄ" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Vyrovnávací paměť je příliÅ¡ malá" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "PříliÅ¡ dlouhý řádek" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Chybí Å™etÄ›zec certifikátů" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Certifikát je příliÅ¡ velký" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Neplatný záznam" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "Ověření MAC selhalo" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "NeoÄekávaná zpráva" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Komprese nebo dekomprese selhala" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "PoÄítadlo by pÅ™eteklo" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "PÅ™ijata nepÅ™ekonatelná chybová zpráva" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Žádný Å¡ifrovací algoritmus" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Chybí certifikát klienta" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "PÅ™ijato oznámení o uzavÅ™ení" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Lístku vyprÅ¡ela platnost" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Chybný lístek" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Neznámá totožnost" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Chybná zpráva s certifikátem v zahájení" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Chybná zpráva s požadavkem na certifikát v zahájení" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Chybná zpráva o ověření certifikátu v zahájení" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Chybná zpráva se zmÄ›nou Å¡ifry v zahájení" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Chybná zpráva s pozdravem klienta v zahájení" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Chybná zpráva s pozdravem serveru v zahájení" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Chybná zpráva o dokonÄení pozdravu serveru v zahájení" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Chybná zpráva o dokonÄení v zahájení" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Chybná zpráva o výmÄ›nÄ› klíÄe serveru v zahájení" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Chybná zpráva o výmÄ›nÄ› klíÄe klienta v zahájení" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Chybný Å™etÄ›zec" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "KlÃ­Ä zakázán" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Nelze provést s klíÄem na kartÄ›" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Neplatný objekt" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Obecná chyba IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC volání accept (pÅ™ijmout) selhalo" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC volání connect (pÅ™ipojit) selhalo" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Neplatná odpovÄ›Ä IPC" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Neplatná hodnota pÅ™edaná do IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Neúplný řádek pÅ™edán do IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Řádek pÅ™edaný do IPC je příliÅ¡ dlouhý" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "VnoÅ™ené příkazy IPC" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Žádná data zpÄ›tného volání v IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Žádné dotazovací zpÄ›tné volání v IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Není serverem IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Není klientem IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problém se spuÅ¡tÄ›ním serveru IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Chyba Ätení IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Chyba zápisu IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "PříliÅ¡ mnoho data pro vrstvu IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "NeoÄekávaný příkaz IPC" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Neznámý příkaz IPC" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Chyba syntaxe IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Volání IPC bylo zruÅ¡eno" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Žádný zdroj vstupu pro IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Žádný zdroj výstupu pro IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Chyba parametru IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Neznámý dotaz IPC" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "No crypto engine" +msgid "Crypto engine too old" +msgstr "Chybí kryptografická jednotka" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Zdvojená hodnota" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certifikát je příliÅ¡ mladý" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "Dodaný objekt je příliÅ¡ krátký" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Neznámé jméno" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Neplatný kód operace" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Neznámé jméno" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Nezapnuto" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Nepodporovaná ochrana" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Agent neběží" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Chyba démona pro Äipové karty" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Chyba serveru s klíÄi" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Neznámá chyba systému" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Neplatný Å™etÄ›zec OID" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Neplatný S-výraz" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing issuer certificate" +msgid "Missing DNS query packet" +msgstr "Chybí certifikát vydavatele" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "DeÅ¡ifrování selhalo" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "ÄŒas vyprÅ¡el" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Obecná chyba IPC" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Obecná chyba" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Obecná chyba" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Obecná chyba Assuanu" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Obecná chyba" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Obecná chyba Assuanu" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Chyba zápisu IPC" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Obecná chyba IPC" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "IPC volání connect (pÅ™ipojit) selhalo" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Obecná chyba" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Vyžadován reset karty" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Prvek nenalezen" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Nepodporováno" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "NeoÄekávaná chyba" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Nepodporovaná operace" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Chybný certifikát" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Neznámé rozšíření" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "ÄŒas vyprÅ¡el" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "chyba dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "chyba dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Chyba Ätení IPC" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Není serverem IPC" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "ÚspÄ›ch" + +# Nastavení nebo nastavování? +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Chyba konfigurace" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "NaruÅ¡ení protokolu" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Neznámé rozšíření" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +#, fuzzy +#| msgid "Fatal alert message received" +msgid "Partial LDAP results+referral received" +msgstr "PÅ™ijata nepÅ™ekonatelná chybová zpráva" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Obecná chyba" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Vyžadován reset karty" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Neplatný atribut" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Nepodporovaná ochrana" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "NaruÅ¡ení protokolu" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Neplatná stav" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Žádný objekt CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Hardwarový problém" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Neplatná stav" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Chyba kódování" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Nepodporovaná ochrana" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Neplatná karta" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +#, fuzzy +#| msgid "No keyserver available" +msgid "LDAP server is unavailable" +msgstr "Není dostupný žádný server klíÄů" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Chybí akce" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "NaruÅ¡ení protokolu" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Operace jeÅ¡tÄ› neskonÄila" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Operace zruÅ¡ena" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "PříliÅ¡ dlouhý řádek" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Operace zruÅ¡ena" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Obecná chyba IPC" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Zdroje vyÄerpány" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "NaruÅ¡ení protokolu" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Neplatná stav" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Nepodporovaný certifikát" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Vyžadován reset karty" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "ÚspÄ›ch" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "NefunkÄní" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "NefunkÄní" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Není serverem IPC" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "DeÅ¡ifrování selhalo" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Uživatelem definovaný chybový kód 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Uživatelem definovaný chybový kód 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Uživatelem definovaný chybový kód 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Uživatelem definovaný chybový kód 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Uživatelem definovaný chybový kód 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Uživatelem definovaný chybový kód 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Uživatelem definovaný chybový kód 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Uživatelem definovaný chybový kód 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Uživatelem definovaný chybový kód 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Uživatelem definovaný chybový kód 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Uživatelem definovaný chybový kód 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Uživatelem definovaný chybový kód 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Uživatelem definovaný chybový kód 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Uživatelem definovaný chybový kód 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Uživatelem definovaný chybový kód 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Uživatelem definovaný chybový kód 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "ÚspÄ›ch" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Chyba syntaxe" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "NaruÅ¡ení protokolu" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Chyba systému bez Äísla chyby (errno)" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Neznámá chyba systému" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Konec souboru" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Neznámý kód chyby" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "argument nebyl oÄekáván" + +#: src/argparse.c:470 +msgid "read error" +msgstr "chyba pÅ™i Ätení" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "klíÄové slovo je příliÅ¡ dlouhé" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "postrádám argument" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "neplatný argument" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "neplatný příkaz" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "neplatný definice aliasu" + +# Nastavení nebo nastavování? +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Chyba konfigurace" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "nedostatek pamÄ›ti" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "neplatný příkaz" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Neznámý příkaz" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "NeoÄekávaný příkaz IPC" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "neplatný parametr" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "postrádám argument u volby „%.50s“\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "neplatný argument u volby „%.50s“\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "volba „%.50s“ neÄeká argument\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "neplatný příkaz „%.50s“\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "volba „%.50s“ není jednoznaÄná\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "příkaz „%.50s“ není jednoznaÄný\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "neplatný parametr „%.50s“\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "pozor: %s nebylo možné rozpoznat\n" + +# Yet another expression for `not enough memory' :) +#~ msgid "out of core\n" +#~ msgstr "nedostatek pamÄ›ti\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Použití: %s CHYBA_GPG […]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Zdroje vyÄerpány" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Neplatná data" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Obecná chyba" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "chyba dirmngr" diff --git a/comm/third_party/libgpg-error/po/da.gmo b/comm/third_party/libgpg-error/po/da.gmo new file mode 100644 index 0000000000..6ecf85029f Binary files /dev/null and b/comm/third_party/libgpg-error/po/da.gmo differ diff --git a/comm/third_party/libgpg-error/po/da.po b/comm/third_party/libgpg-error/po/da.po new file mode 100644 index 0000000000..781a485d07 --- /dev/null +++ b/comm/third_party/libgpg-error/po/da.po @@ -0,0 +1,2194 @@ +# Danish translation libgpg-error. +# Copyright (C) 2014 g10 Code GmbH og nedenstÃ¥ende oversættere. +# This file is distributed under the same license as the libgpg-error package. +# Joe Hansen , 2012, 2014. +# +# invalid -> ugyldig +# bad -> ødelagt +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.10\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:24+0100\n" +"Last-Translator: Joe Hansen \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Uspecificeret kilde" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG-agent" + +# pinentry is a small collection of dialog programs that allow GnuPG to read passphrases and PIN numbers in a secure manner. There are versions for the common GTK and Qt toolkits as well as for the text terminal (Curses). +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Enhver kilde" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Brugerdefineret kilde 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Brugerdefineret kilde 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Brugerdefineret kilde 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Brugerdefineret kilde 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Ukendt kilde" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Lykkedes" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Generel fejl" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Ukendt pakke" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Ukendt version i pakke" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Ugyldig offentlig nøglealgoritme" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Ugyldig sammendragsalgoritme" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Ødelagt offentlig nøgle" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Ødelagt hemmelig nøgle" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Ødelagt underskrift" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Ingen offentlig nøgle" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Kontrolsumsfejl" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Ødelagt adgangsfrase" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Ugyldig chifferalgoritme" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Nøglering Ã¥ben" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Ugyldig pakke" + +# armering eller pansring? +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Ugyldig pansring" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Ingen bruger-id" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Ingen hemmelig nøgle" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Der blev brugt forkert hemmelig nøgle" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Ødelagt sessionnøgle" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Ukendt komprimeringsalgoritme" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Tal er ikke et primtal" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Ugyldig kodningsmetode" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Ugyldig krypteringsskema" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Ugyldig underskriftsskema" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Ugyldig attribut" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Ingen værdi" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Ikke fundet" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Værdi blev ikke fundet" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Syntaksfejl" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Ugyldig MPI-værdi" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Ugyldig adgangsfrase" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Ugyldig underskriftklasse" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Ressourcer opbrugt" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Ugyldig nøglering" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Trust DB-fejl" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Ødelagt certifikat" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Ugyldig bruger-id" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Uventet fejl" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Tidskonflikt" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Nøgleserverfejl" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Forkert offentlig nøglealgoritme" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Tribut til D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Svag krypteringsnøgle" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Ugyldig nøglelængde" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Ugyldigt argument" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Syntaksfejl i URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Ugyldig URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Netværksfejl" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Ukendt vært" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Egentest mislykkedes" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Data er ikke krypteret" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Data er ikke behandlet" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Ubrugelig offentlig nøgle" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Ubrugelig hemmelig nøgle" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Ugyldig værdi" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Ødelagt certifikatkæde" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Manglende certifikat" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Ingen data" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Fejl" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Ikke understøttet" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Ugyldig handlingskode" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Tidsudløb" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Intern fejl" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Ugyldigt objekt" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Angivet objekt er for kort" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Angivet objekt er for stort" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Manglende punkt i objekt" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Ikke implementeret" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Konfliktende brug" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Ugyldig ciffertilstand" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Ugyldigt flag" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Ugyldigt hÃ¥ndtag" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Resultat afkortet" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Ufuldstændig linje" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Ugyldigt svar" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Ingen agent kører" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Agentfejl" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Ugyldige data" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Uspecificeret Assuan-serverfejl" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Generel Assuanfejl" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Ugyldig sessionsnøgle" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Ugyldigt S-udtryk" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Ej understøttet algoritme" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Ingen pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "pinentry-fejl" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Ødelagt PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Ugyldigt navn" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Ødelagte data" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Ugyldig parameter" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Forkert kort" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Ingen dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr-fejl" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certifikat tilbagekaldt" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Ingen kendt CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL er for gammel" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Linje er for lang" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Ikke troværdig" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Handling afbrudt" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Ødelagt CA-certifikat" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certifikat udløbet" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certifikat for ungt" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Ej understøttet certifikat" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Ukendt S-udtryk" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Ej understøttet beskyttelse" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Ødelagt beskyttelse" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Tvetydigt navn" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Kortfejl" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Kortnulstilling krævet" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Kort fjernet" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Ugyldigt kort" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Kort er ikke til stede" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Intet PKCS15-program" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Ikke bekræftet" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Konfigurationsfejl" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Ingen politikmatch" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ugyldigt indeks" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Ugyldigt id" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Ingen SmartCard-dæmon" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "SmartCard-dæmonfejl" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Ej understøttet protokol" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Ødelagt PIN-metode" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Kort er ikke initialiseret" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Ej understøttet handling" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Forkert nøglebrug" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Intet fundet" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Forkert blobtype" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Manglende værdi" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Maskinelt problem" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN blokeret" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Betingelser for brug er ikke overholdt" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN'er er ikke synkroniserede" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Ugyldig CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER-fejl" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Ugyldig BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Element er ikke fundet" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identifikator er ikke fundet" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Ugyldigt mærke" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Ugyldig længde" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Ugyldig nøgleinformation" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Uventet mærke" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Ikke DER-kodet" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Intet CMS-objekt" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Ugyldigt CMS-objekt" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Ukendt CMS-objekt" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Ej understøttet CMS-objekt" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Ej understøttet kodning" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Ej understøttet CMS-version" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Ukendt algoritme" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Ugyldig cryptomotor" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Offentlig nøgle er ikke troværdig" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Afkryptering mislykkedes" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Nøgle udløbet" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Underskrift udløbet" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Kodningsproblem" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Ugyldig tilstand" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Duplikeret værdi" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Manglende handling" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ASN.1-modul er ikke fundet" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Ugyldig OID-streng" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Ugyldig tid" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Ugyldigt CRL-objekt" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Ej understøttet CRL-version" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Ugyldigt certifikatobjekt" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Ukendt navn" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "En lokal funktion mislykkedes" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Ikke lÃ¥st" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Protokolovertrædelse" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Ugyldig MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Ugyldig forespørgsel" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Ukendt udvidelse" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Ukendt kritisk udvidelse" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "LÃ¥st" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Ukendt indstilling" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Ukendt kommando" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Ikke funktionsdygtig" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Ingen adgangsfrase angivet" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Ingen PIN angivet" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Ikke aktiveret" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Ingen cryptomotor" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Manglende nøgle" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "For mange objekter" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Begrænsning nÃ¥et" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Ikke initialiseret" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Manglende udstedercertfikat" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Ingen nøgleserver tilgængelig" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Ugyldig elliptisk kurve" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Ukendt elliptisk kurve" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Duplikeret nøgle" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Tvetydigt resultat" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Ingen cryptokontekst" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Forkert cryptokontekst" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Ugyldig cryptokontekst" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Konflikt i cryptokonteksten" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Ødelagt offentlig nøgle" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Ødelagt hemmelig nøgle" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Ugyldig MAC-algoritme" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Handling fuldt afbrudt" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Handling ikke færdig endnu" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffer for kort" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Ugyldig længdeangiver i S-udtryk" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Streng for kort i S-udtryk" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Ej matchende parenteser i S-udtryk" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-udtryk er ikke kanonisk" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Ødelagt tegn i S-udtryk" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Ødelagt citation i S-udtryk" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Nulpræfiks i S-udtryk" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Indlejrede visningsfif i S-udtryk" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Ej matchende visningsfif" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Uventet reserveret punktum i S-udtryk" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Ødelagt hexadecimalt tegn i S-udtryk" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Ulige hexadecimalt tal i S-udtryk" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Ødelagt oktalt tegn i S-udtryk" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Data er ikke krypteret" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Ukendt navn" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Ingen offentlig nøgle" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Buffer for kort" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Linje er for lang" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Ingen certifikatkæde" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Certifikatet er for stort" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Ugyldig post" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "MAC'en verificerer ikke" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Uventet besked" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Pakning eller udpakning mislykkedes" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "En tæller ville pakke ind" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Modtog »fatal alarm«-besked" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Ingen chifferalgoritme" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Manglende klientcertfikat" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Luk modtaget pÃ¥mindelse" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Billetten udløbet" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Ødelagt billet" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Ukendt identitet" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Besked om ødelagt certifikat i hÃ¥ndtrykket" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Besked om ødelagt certifikatforespørgsel i hÃ¥ndtrykket" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Besked om ødelagt certifikatforespørgsel i hÃ¥ndtrykket" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Ødelagt Ⱦndr chiffer«-besked i hÃ¥ndtrykket" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Besked om ødelagt klienthilsen i hÃ¥ndtrykket" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Besked om ødelagt serverhilsen i hÃ¥ndtrykket" + +# engelsk fejl +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Ødelagt »afsluttet serverhilsen«-besked i hÃ¥ndtrykket" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Ødelagt »afsluttet«-besked i hÃ¥ndtrykket" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Besked om ødelagt udveksling af servernøgle i hÃ¥ndtrykket" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Besked om ødelagt udveksling af klientnøgle i hÃ¥ndtrykket" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Fejlbehæftet streng" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Nøglen er deaktiveret" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Ikke muligt med en kortbaseret nøgle" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Ugyldigt lÃ¥seobjekt" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Generel IPC-fejl" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC-acceptkald mislykkedes" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC-forbindelseskald mislykkedes" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Ugyldigt IPC-svar" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Ugyldig værdi sendt til IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Ufuldstændig linje sendt til IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Linje sendt til IPC er for lang" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Indlejrede IPC-kommandoer" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Ingen datatilbagekald i IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Ingen inquire-tilbagekald i IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Ikke en IPC-server" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Ikke en IPC-klient" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problem med at starte IPC-server" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC-læsefejl" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC-skrivefejl" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "For mange data for IPC-lag" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Uventet IPC-kommando" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Ukendt IPC-kommando" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC-syntaksfejl" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC-kald er blevet afbrudt" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Ingen inddatakilde for IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Ingen uddatakilde for IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC-parameterfejl" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Ukendt IPC-inquire" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "No crypto engine" +msgid "Crypto engine too old" +msgstr "Ingen cryptomotor" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Duplikeret værdi" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certifikat for ungt" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "Angivet objekt er for kort" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Ukendt navn" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Ugyldig handlingskode" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Ukendt navn" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Ikke aktiveret" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Ej understøttet beskyttelse" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Ingen agent kører" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "SmartCard-dæmonfejl" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Nøgleserverfejl" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Ukendt systemfejl" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Ugyldig OID-streng" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Ugyldigt S-udtryk" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing issuer certificate" +msgid "Missing DNS query packet" +msgstr "Manglende udstedercertfikat" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Afkryptering mislykkedes" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Tidsudløb" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Generel IPC-fejl" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Generel fejl" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Generel fejl" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Generel Assuanfejl" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Generel fejl" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Generel Assuanfejl" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "IPC-skrivefejl" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Generel IPC-fejl" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "IPC-forbindelseskald mislykkedes" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Generel fejl" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Kortnulstilling krævet" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Element er ikke fundet" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Ikke understøttet" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Uventet fejl" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Ej understøttet handling" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Ødelagt certifikat" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Ukendt udvidelse" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Tidsudløb" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "dirmngr-fejl" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "dirmngr-fejl" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "IPC-læsefejl" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Ikke en IPC-server" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Lykkedes" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Konfigurationsfejl" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Protokolovertrædelse" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Ukendt udvidelse" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +#, fuzzy +#| msgid "Fatal alert message received" +msgid "Partial LDAP results+referral received" +msgstr "Modtog »fatal alarm«-besked" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Generel fejl" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Kortnulstilling krævet" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Ugyldig attribut" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Ej understøttet beskyttelse" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Protokolovertrædelse" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Ugyldig tilstand" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Intet CMS-objekt" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Maskinelt problem" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Ugyldig tilstand" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Kodningsproblem" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Ej understøttet beskyttelse" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Ugyldigt kort" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +#, fuzzy +#| msgid "No keyserver available" +msgid "LDAP server is unavailable" +msgstr "Ingen nøgleserver tilgængelig" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Manglende handling" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Protokolovertrædelse" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Handling ikke færdig endnu" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Handling afbrudt" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Linje er for lang" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Handling afbrudt" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Generel IPC-fejl" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Ressourcer opbrugt" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Protokolovertrædelse" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Ugyldig tilstand" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Ej understøttet certifikat" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Kortnulstilling krævet" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Lykkedes" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Ikke funktionsdygtig" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Ikke funktionsdygtig" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Ikke en IPC-server" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Afkryptering mislykkedes" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Brugerdefineret fejlkode 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Brugerdefineret fejlkode 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Brugerdefineret fejlkode 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Brugerdefineret fejlkode 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Brugerdefineret fejlkode 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Brugerdefineret fejlkode 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Brugerdefineret fejlkode 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Brugerdefineret fejlkode 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Brugerdefineret fejlkode 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Brugerdefineret fejlkode 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Brugerdefineret fejlkode 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Brugerdefineret fejlkode 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Brugerdefineret fejlkode 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Brugerdefineret fejlkode 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Brugerdefineret fejlkode 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Brugerdefineret fejlkode 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Lykkedes" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Syntaksfejl" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Protokolovertrædelse" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Systemfejl w/o errno" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Ukendt systemfejl" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Slutning pÃ¥ fil" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Ukendt fejlkode" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "parameter var ikke forventet" + +#: src/argparse.c:470 +msgid "read error" +msgstr "læsefejl" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "nøgleord er for langt" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "manglende parameter" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid value\n" +msgid "invalid argument" +msgstr "ugyldig værdi\n" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "ugyldig kommando" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "ugyldig aliasdefinition" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Konfigurationsfejl" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "ikke nok kerne" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "ugyldig kommando" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Ukendt kommando" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Uventet IPC-kommando" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "ugyldig indstilling" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "manglende parameter for indstilling »%.50s«\n" + +#: src/argparse.c:506 +#, fuzzy, c-format +#| msgid "missing argument for option \"%.50s\"\n" +msgid "invalid argument for option \"%.50s\"\n" +msgstr "manglende parameter for indstilling »%.50s«\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "tilvalg »%.50s« forventer ikke et argument\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "ugyldig kommando »%.50s«\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "tilvalg »%.50s« er tvetydigt\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "kommando »%.50s« er tvetydig\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "ugyldigt tilvalg »%.50s«\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "advarsel: kunne ikke genkende %s\n" + +#~ msgid "out of core\n" +#~ msgstr "uden for kerne\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Brug: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Ressourcer opbrugt" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Ugyldige data" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Generel fejl" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "dirmngr-fejl" diff --git a/comm/third_party/libgpg-error/po/de.gmo b/comm/third_party/libgpg-error/po/de.gmo new file mode 100644 index 0000000000..81bbefa14f Binary files /dev/null and b/comm/third_party/libgpg-error/po/de.gmo differ diff --git a/comm/third_party/libgpg-error/po/de.po b/comm/third_party/libgpg-error/po/de.po new file mode 100644 index 0000000000..5374caaf99 --- /dev/null +++ b/comm/third_party/libgpg-error/po/de.po @@ -0,0 +1,2014 @@ +# de.po - German strings for libgpg-error +# Copyright (C) 2003 g10 Code GmbH +# This file is distributed under the terms of the GNU LGPL v2.1 or later. +# Werner Koch , 2003. +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error-1.19\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:25+0100\n" +"Last-Translator: Werner Koch \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Quelle nicht angegeben" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GPGSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Unspezifische Quelle" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Benutzerdefinierte Quelle 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Benutzerdefinierte Quelle 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Benutzerdefinierte Quelle 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Benutzerdefinierte Quelle 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Unbekannte Quelle" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Erfolg" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Allgemeiner Fehler" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Unbekanntes Paket" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Unbekannte Version im Paket" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Ungültiges Public-Key-Verfahren" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Ungültige Hashmethode" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Fehlerhafter öffentlicher Schlüssel" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Fehlerhafter geheimer Schlüssel" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Falsche Unterschrift" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Kein öffentlicher Schlüssel" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Prüfsummenfehler" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Falsche Passphrase" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Ungültiges Verschlüsselungsverfahren" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Schlüsselbund kann nicht geöffnet werden" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Ungültiges Paket" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Ungültige ASCII-Hülle" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Keine User-ID" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Kein geheimer Schlüssel" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Falscher geheimer Schlüssel benutzt" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Fehlerhafte Sitzungsschlüssel" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Unbekanntes Komprimierungsverfahren" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Zahl ist nicht prim" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Ungültiges Kodierungsverfahren" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Ungültiges Verschlüsselungsschema" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Ungültiges Signaturschema" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Ungültiges Attribut" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Kein Wert" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Nicht gefunden" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Wert nicht gefunden" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Syntaxfehler" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Fehlerhafter MPI Wert" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Ungültige Passphrase" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Ungültige Signaturklasse" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Ressourcen erschöpft" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Ungültiger Schlüsselbund" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Fehler in der 'Trust'-Datenbank" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Fehlerhaftes Zertifikat" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Ungültige User-ID" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Unerwarteter Fehler" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Zeitangaben differieren" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Schlüsselserverfehler" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Falsches Public-Key-Verfahren" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Tribut an D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Unsicherer Schlüssel" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Ungültige Schlüssellänge" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Ungültiges Argument" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Syntaxfehler im URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Ungültiger URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Netzwerkfehler" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Unbekannter Rechner" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Selbstprüfung fehlgeschlagen" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Daten sind nicht verschlüsselt" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Daten wurden nicht verarbeitet" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Unbrauchbarer öffentlicher Schlüssel" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Unbrauchbarer geheimer Schlüssel" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Ungültiger Wert" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Fehlerhafte Zertifikatkette" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Fehlendes Zertifikat" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Keine Daten" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Bug (Programmfehler)" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Nicht unterstützt" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Ungültiger Verarbeitungscode" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Zeitüberschreitung" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Interner Fehler" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (in gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Ungültiges Objekt" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Objekt ist zu kurz" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Objekt ist zu groß" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Fehlendes Feld im Objekt" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Nich implementiert" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Widersprüchliche Benutzung" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Ungültiger Verschlüsselungsmodus" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Ungültige Flagge" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Ungültiger Handle" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Ausgabe abgeschnitten" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Unvollständige Zeile" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Ungültige Antwort" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Agent läuft nicht" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Fehler beim Agenten" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Ungültige Daten" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Unspezifischer Assuan Serverfehler" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Allgemeiner Assuan Fehler" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Ungültiger Sitzungsschlüssel" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Ungültige S-expression" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Nicht unterstütztes Verfahren" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Kein Pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Fehler in der Pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Falsche PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Ungültiger Name" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Fehlerhafte Daten" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Ungültiger Parameter" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Falsche Karte" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Kein Dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Fehler im Dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Zertifikat ist widerrufen" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Keine CRL bekannt" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL ist zu alt" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Zeile ist zu lang" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Nicht vertrauenswürdig" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Verarbeitung wurde abgebrochen" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Fehlerhaftes CA-Zertifikat" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Zertifikat abgelaufen" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Zertifikat ist noch nicht gültig" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Nicht unterstütztes Zertifikat" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Unbekannte S-expression" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Nicht unterstütztes Schutzverfahren" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Beschädigter Schutz" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Mehrdeutiger Name" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Kartenfehler" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Karte wurde zurückgesetzt" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Karte wurde entfernt" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Ungültige Karte" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Karte nicht vorhanden" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Kein PKCS#15 Anwendung" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Nicht bestätigt" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Konfigurationsfehler" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Richtlinien stimmen nicht überein" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ungültiger Index" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Ungültige ID" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Kein Karten-Daemon" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Fehler im Karten-Daemon" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Nicht unterstütztes Protokoll" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Falsche PIN Methode" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Karte ist nicht initialisiert" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Nicht unterstützte Verarbeitungsaufgabe" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Falsche Schlüsselnutzung" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Nichts gefunden" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Falscher BLOB-Typ" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Fehlender Wert" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problem mit der Hardware" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN ist blockiert" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Nutzungsvorraussetzungen nicht erfüllt" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PINs sind nicht syncronsiert" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Ungültige CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER Fehler" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Ungültige BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Element nicht gefunden" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Indentifier nicht gefunden" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Ungültiges \"Tag\"" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Ungültige Länge" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Ungültige Key-Info" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Unerwartetes \"Tag\"" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Nicht DER kodiert" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Kein CMS Objekt" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Ungültiges CMS Objekt" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Unbekanntes CMS Objekt" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Nicht unterstütztes CMS Objekt" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Nicht unterstützte Kodierung" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Nicht unterstützte CMS Version" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Unbekanntes Verfahren" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Ungültige Krypto-Engine" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Öffentlicher Schlüssel ist nicht vertrauenswürdig" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Entschlüsselung fehlgeschlagen" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Schlüssel abgelaufen" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Unterschrift abgelaufen" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Kodierungsproblem" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Ungültiger Status" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Doppelter Wert" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Aktion fehlt" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ASN.1 Modul nicht gefunden" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Ungültige OID Zeichenkette" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Ungültige Zeit" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Ungültiges CRL Objekt" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Nicht unterstützte CRL Version" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Ungültiges Zertifikatsobjekt" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Unbekannter Name" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Eine \"locale\" Funktion ist fehlgeschlagen" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Nicht gesperrt" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Protokollverletzung" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Ungültiger MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Ungültiger Request" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Unbekannte Erweiterung" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Unbekannte kritische Erweiterung" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Gesperrt" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Unbekannte Option" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Unbekanntes Kommando" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Nicht betriebsbereit" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Keine Passphrase angegeben" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Keine PIN angegeben" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Nicht engeschaltet" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Keine Krypto-Engine" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Fehlender Schlüssel" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Zu viele Objekte" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Limit erreicht" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Initialisierung nicht durchgeführt" + +# "in der Kette" ist part of the message because many users know about +# certificate chains and thus that keyword might give them a good hint +# what might be wrong. +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Fehlendes Herausgeberzertifikat in der Kette" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Kein Schlüsselserver verfügbar" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Ungültige elliptische Kurve" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Unbekannte elliptische Kurve" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Doppelter Schlüssel" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Uneindeutiges Ergebiss" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Fehlender Crypto Context" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Falscher Crypto Context" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Fehlerhafter Crypto Context" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Widersprüchliche Benutzung des Crypto Context" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Defekter öffentlicher Schlüssel" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Defekter geheimer Schlüssel" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Ungültige MAC-Methode" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Verarbeitung wurde vollständig abgebrochen" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Verarbeitung ist noch nicht beendet" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Datenpuffer zu kurz" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Ungültige Längeangabe in der S-expression" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Zeichenkette in S-expression zu lang" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Nich übereinstimmende Klammern in S-expression" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-expression ist nicht kanonisch" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Fehlerhaftes Zeichen in S-expression" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Fehlerhafte Zitierung in S-expression" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Null-Präfix in S-expression" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Verschachtelte \"Hints\" in S-expression" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Nicht übereinstimmende \"Hints\"" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Unerwartetes reserviertes Zeichen in S-expression" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Falsches Hex-Zeichen in S-expression" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Ungerade Anzahl von Hex-Zeichen in S-expression" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Falsches Oktal-Zeichen in S-expression" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "Alle Unterschlüssel sind abgelaufen oder widerrufen" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "Beschädigte Datenbank" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "Server zeigt einen unbestimmten Fehler an" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "Kein Name" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "Kein Schlüssel" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "Veralteter Schlüssel" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "Anfrage zu kurz" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "Zeile ist zu lang" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "Objekt befindet sich im \"Termination\" Status" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Fehlende Zertifikatkette" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Zertifikat ist zu gross" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Ungültiger Datensatz" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "Der MAC ist nicht gültig" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Unerwartete Nachricht" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "(De-)Komprimierung fehlgeschlagen" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Ein Zähler würde überlaufen" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Fatale \"Alert\" Nachricht erhalten" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Kein Verschlüsselungsverfahren" + +# "in der Kette" ist part of the message because many users know about +# certificate chains and thus that keyword might give them a good hint +# what might be wrong. +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Fehlendes Benutzerzertifikat" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "\"Close\" Benachrichtigung erhalten" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Ticket abgelaufen" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Fehlerhaftes Ticket" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Unbekannte Indentität" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Fehlerhafte Zertifikatnachricht im Handshake" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Fehlerhafte Zertifikatsanforderungsnachricht im Handshake" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Fehlerhafte Zertifikatsüberprüfungsnachricht im Handshake" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Fehlerhafte Verschlüsselungsalgorithmuswechselnachricht im Handshake" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Fehlerhafte \"Client Hello\" Nachricht im Handshake" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Fehlerhafte \"Server Hello\" Nachricht im Handshake" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Fehlerhafte \"Server Hello Done\" Nachricht im Handshake" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Fehlerhafte \"Finished\" Nachricht im Handshake" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Fehlerhafte \"Server Key Exchange\" Nachricht im Handshake" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Fehlerhafte \"Client Key Exchange\" Nachricht im Handshake" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Fehlerhafter String" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "Verboten" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Schlüssel abgeschaltet" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Nicht möglich mit einem kartenbasierten Schlüssel" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Ungültiges Sperr-Objekt" + +#: src/err-codes.h:280 +msgid "True" +msgstr "Wahr" + +#: src/err-codes.h:281 +msgid "False" +msgstr "Falsch" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Allgemeiner IPC Fehler" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC \"accept\" Aufruf fehlgeschlagen" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC \"connect\" Aufruf fehlgeschlagen" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Ungültige IPC Antwort" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Ungültiger Wert an IPC übergeben" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Unvollständige Zeile an IPC übergeben" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "An die IPC übergebene Zeile ist zu lang" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Verschachtelte IPC Kommandos" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Kein Daten vom IPC \"Callback\"" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Kein \"Inquire\" \"Callback\" für IPC gesetzt" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Kein IPC Server" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Kein IPC Client" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problem beim Starten des IPC Servers" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC Lesefehler" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC Schreibfehler" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Zu viele Daten für das IPC Ebene" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Unerwartetes IPC Kommando" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Unbekanntes IPC Kommando" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC Syntaxfehler" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Der IPC Aufruf wurde abgebrochen" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Eingabequelle für IPC fehlt" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Ausgabesenke für IPC fehlt" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC Parameterfehler" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Unbekanntes IPC \"Inquire\"" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "Die Krypto-Engine ist zu alt" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "Bildschirmfenster ist zu klein" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "Bildschirmfenster ist zu groß" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "Eine notwendige Umgebungsvariable ist nicht gesetzt" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "Die User-ID existiert bereits" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "Der Name existiert bereits" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "Doppelter Name" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "Objekt zu jung" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "Objekt zu alt" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "Unbekannte Flagge" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "Ungültige Verarbeitungsreihenfolge" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "Bereits geholt" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "Später erneut versuchen" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "Falscher Name" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "Nicht authentifiziert" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "Falsche Authentifizierung" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "Keybox-Daemon läuft nicht" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "Fehler im Keybox-Daemon" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "Service ist nicht aktiv" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "Fehler im Service" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "Fehler im System entdeckt" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "Unbekannter DNS Fehler" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "Ungültige DNS \"Section\"" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "Ungültige Textadressenformat" + +# "in der Kette" ist part of the message because many users know about +# certificate chains and thus that keyword might give them a good hint +# what might be wrong. +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "Fehlendes DNS Anfragepaket" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "Fehlendes DNS Antwortpaket" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "Verbindung im DNS geschlossen" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "Prüfung im DNS fehlgeschlagen" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "DNS Zeitüberschreitung" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "Allgemeiner LDAP Fehler" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "Allgemeiner LDAP Attributfehler" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "Allgemeiner LDAP Namensfehler" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "Allgemeiner LDAP Sicherheitsfehler" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "Allgemeiner LDAP Servicefehler" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "Allgemeiner LDAP \"Update\" Fehler" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "Experimenteller LDAP Fehlercode" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "Privater LDAP Fehlercode" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "Sonstiger allgemeiner LDAP Fehler" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "Fehler beim LDAP Verbindungsaufbau (X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "Grenze für LDAP Verweise überschritten" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "Schleife im LDAP Client entdeckt" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "Keine LDAP Ergebnisse" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "LDAP \"Control\" nicht gefunden" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "Von LDAP nicht unterstützt" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "LDAP Verbindungsfehler" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "Nicht genügend Speicher für LDAP Operation" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "Ungültiger Parameter an LDAP Funktion übergeben" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "LDAP Verarbeitung durch Benutzer abgebrochen" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "Fehlerhaftes LDAP Suchfilter" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "Unbekanntes LDAP Authentifizierungsverfahren" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "Zeitüberschreitung (LDAP)" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "LDAP Dekodierungsfehler" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "LDAP Kodierungsfehler" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "Lokaler LDAP Fehler" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "Verbindung zum LDAP Server nicht möglich" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "LDAP erfolgreich" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "LDAP Konfigurationsfehler" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "LDAP Protokollverletzung" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "Zeitgrenze von LDAP überschritten" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "Größengrenze von LDAP überschritten" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "LDAP Vergleich falsch" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "LDAP Vergleich richtig" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "LDAP Authentifizierungsverfahren nicht unterstützt" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "Starke LDAP Authentifizierung benötigt" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "Partielle LDAP Ergebnisse und Verweise erhalten" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "LDAP Verweise" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "Administrative LDAP Grenze überschritten" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "Kritische LDAP Erweiterung nicht vorhanden" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "Vertraulichkeit von LDAP angefordert" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "LDAP SALS \"bind\" wird durchgeführt" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "Kein solches LDAP Attribut" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "Ungültiger LDAP Attributtyp" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "Unpassende Zusammenstellung in LDAP" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "Bedingung nicht eingehalten in LDAP" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "LDAP Typ oder Wert existiert" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "Ungültiger Status in LDAP" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "Kein solches LDAP Objekt" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "Problem mit LDAP Alias" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "Ungültiger DN Synatx in LDAP" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "LDAP Element ist ein \"leaf\"" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "Problem bei der Auflösung eines LDAP Aliases" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "LDAP Proxy Authentifizierung fehlgeschlagen (X)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "Unpassende LDAP Authentifizierung" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "Ungültige LDAP Credentials" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "Ungenügende Zugriffsrechte für LDAP" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "LDAP Server ist beschäftigt" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "LDAP Server nicht verfügbar" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "LDAP Server weigert sich etwas durchzuführen" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "LDAP hat eine Schleife erkannt" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "LDAP Benennungsverletzung" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "Verletzung der LDAP Objektklasse" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "LDAP Operation auf einem Nicht-\"Leaf\" ist nicht erlaubt" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "LDAP Operation nicht erlaubt auf einem RDN" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "Existiert bereits (LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "Die LDAP Objektklasse kann nicht geändert werden" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "LDAP Ergebnisse sind zu lang" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "LDAP Operation betrifft mehrere DSAs" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "Fehler in virtueller LDAP \"list view\"" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "Sonstiger allgemeiner LDAP Fehler" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "Ressourcen erschöpft in LCUP" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "Sicherheitsverletzung in LCUP" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "Ungültige Daten in LDAP" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "Nicht unterstütztes Schema in LCUP" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "\"Reload\" notwendig in LCUP" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAP wurde abgebrochen" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "Fehlende LDAP Operation zum abbrechen" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "Zu spät um LDAP Operation abzubrechen" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "LDAP Operation kann nicht abgebrochen werden" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "LDAP \"Assertion\" fehlgeschlagen" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "LDAP Authentifizierung via Proxy wurde verweigert" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Benutzerdefinierter Fehlercode 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Benutzerdefinierter Fehlercode 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Benutzerdefinierter Fehlercode 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Benutzerdefinierter Fehlercode 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Benutzerdefinierter Fehlercode 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Benutzerdefinierter Fehlercode 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Benutzerdefinierter Fehlercode 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Benutzerdefinierter Fehlercode 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Benutzerdefinierter Fehlercode 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Benutzerdefinierter Fehlercode 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Benutzerdefinierter Fehlercode 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Benutzerdefinierter Fehlercode 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Benutzerdefinierter Fehlercode 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Benutzerdefinierter Fehlercode 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Benutzerdefinierter Fehlercode 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Benutzerdefinierter Fehlercode 16" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "SQL erfolgreich" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "SQL Fehler" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "Interner Logikfehler in der SQL Bibliothek" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "Zugriff verweigert (SQL)" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "SQL Abbruch wurde angefordert" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "SQL Datenbank ist gesperrt" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "Eine SQL Tabelle in der Datenbank ist gesperrt" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "SQL Bibliothek hat nicht mehr genügend Hauptspeicher" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "Versuch auf einen read-only SQL Datenbank zu schreiben" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "SQL Operation durch einen Interrupt beendet" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "I/O Fehler während einer SQL Operation" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "Dateiabbild der SQL Datenbank ist fehlerhaft" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "Unbekannter \"opcode\" in der SQL Dateisteuerung" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "Einfügen in SQL Datenbank fehlgeschlagen da die Platte voll ist" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "Die Datei der SQL Datenbank konnte nicht geöffnet werden" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "SQL Dateisperren Protokollverletzung" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "(Interner SQL Code: leer)" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "SQL Datenbankschema hat sich geändert" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "String oder Blob ist zu gross (SQL)" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "SQL Abbruch wg. einer nicht eingehaltenen Zwangsbedingung" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "Datentyp stimmt nicht überein (SQL)" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "SQL Bibliothek wurde falsch verwendet" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "SQL Bibliothek benutzt vom OS nicht unterstützte Funktionen" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "Authentifizierung verweigert (SQL)" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "(unused SQL code: format)" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "SQL Bind-Parameter ausserhalb der Grenzwerte" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "Geöffnete Datei ist keine SQL Datenbank" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "Benachrichtigungen vom SQL Logger" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "Warnungen vom SQL Logger" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "SQL hält eine neue \"Row\" bereit" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "SQL Ausführung ist beendet" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Systemfehler ohne gesetzten Systemfehlercode" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Unbekannter Systemfehler" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Dateiende" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Unbekannter Fehlercode" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "Argument nicht erwartet" + +#: src/argparse.c:470 +msgid "read error" +msgstr "Lesefehler" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "Schlüsselwort ist zu lang" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "Fehlendes Argument" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "Ungültiges Argument" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "Ungültiger Befehl" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "Ungültige Alias-Definition" + +#: src/argparse.c:482 src/argparse.c:519 +msgid "permission error" +msgstr "Zugriffsrechte nicht ausreichend" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "Nicht genügend Speicher" + +#: src/argparse.c:488 src/argparse.c:523 +msgid "invalid meta command" +msgstr "Ungültige Meta-Anweisung" + +#: src/argparse.c:490 src/argparse.c:525 +msgid "unknown meta command" +msgstr "Unbekannte Meta-Anweisung" + +#: src/argparse.c:492 src/argparse.c:527 +msgid "unexpected meta command" +msgstr "Unerwartete Meta-Anweisung" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "Ungültige Option" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "Fehlendes Argument für Option \"%.50s\"\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "Ungültiges Argument für Option \"%.50s\"\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "Option \"%.50s\" erwartet kein Argument\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "Ungültiger Befehl \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "Option \"%.50s\" ist mehrdeutig\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "Befehl \"%.50s\" ist mehrdeutig\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "Ungültige Option \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "Hinweis: Keine voreingestellte Optionendatei '%s' vorhanden\n" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "Optionen werden aus '%s' gelesen\n" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "Optionendatei '%s': %s\n" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" +"Hinweis: Option \"--%s\" aufgrund der globalen Konfiguration ignoriert\n" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" +"Berichte über Programmfehler bitte in englisch an .\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "Warnung: %s konnte nicht erkannt werden\n" + +#~ msgid "out of core\n" +#~ msgstr "Nicht genügend Speicher\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Aufruf: %s GPG-FEHLER [...]\n" + +#~ msgid "LCUP Resources exhausted" +#~ msgstr "LCUP Ressourcen erschöpft" + +#~ msgid "LCUP Invalid data" +#~ msgstr "LCUP Ungültige Daten" + +#~ msgid "LDAP Other general error" +#~ msgstr "Sonstiger allgemeiner LDAP Fehler" + +#~ msgid "Encoding error" +#~ msgstr "Kodierungsfehler" diff --git a/comm/third_party/libgpg-error/po/en@boldquot.header b/comm/third_party/libgpg-error/po/en@boldquot.header new file mode 100644 index 0000000000..506ca9e9ec --- /dev/null +++ b/comm/third_party/libgpg-error/po/en@boldquot.header @@ -0,0 +1,25 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# +# This catalog furthermore displays the text between the quotation marks in +# bold face, assuming the VT100/XTerm escape sequences. +# diff --git a/comm/third_party/libgpg-error/po/en@quot.header b/comm/third_party/libgpg-error/po/en@quot.header new file mode 100644 index 0000000000..6522f0ce01 --- /dev/null +++ b/comm/third_party/libgpg-error/po/en@quot.header @@ -0,0 +1,22 @@ +# All this catalog "translates" are quotation characters. +# The msgids must be ASCII and therefore cannot contain real quotation +# characters, only substitutes like grave accent (0x60), apostrophe (0x27) +# and double quote (0x22). These substitutes look strange; see +# https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html +# +# This catalog translates grave accent (0x60) and apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019). +# It also translates pairs of apostrophe (0x27) to +# left single quotation mark (U+2018) and right single quotation mark (U+2019) +# and pairs of quotation mark (0x22) to +# left double quotation mark (U+201C) and right double quotation mark (U+201D). +# +# When output to an UTF-8 terminal, the quotation characters appear perfectly. +# When output to an ISO-8859-1 terminal, the single quotation marks are +# transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to +# grave/acute accent (by libiconv), and the double quotation marks are +# transliterated to 0x22. +# When output to an ASCII terminal, the single quotation marks are +# transliterated to apostrophes, and the double quotation marks are +# transliterated to 0x22. +# diff --git a/comm/third_party/libgpg-error/po/eo.gmo b/comm/third_party/libgpg-error/po/eo.gmo new file mode 100644 index 0000000000..5eb1671417 Binary files /dev/null and b/comm/third_party/libgpg-error/po/eo.gmo differ diff --git a/comm/third_party/libgpg-error/po/eo.po b/comm/third_party/libgpg-error/po/eo.po new file mode 100644 index 0000000000..27ef94f82b --- /dev/null +++ b/comm/third_party/libgpg-error/po/eo.po @@ -0,0 +1,2255 @@ +# Esperanto translation of Libgpg-error +# Copyright (C) 2013 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Felipe Castro , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.7\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:25+0100\n" +"Last-Translator: Felipe Castro \n" +"Language-Team: Esperanto \n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Neindikita fonto" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agento" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Iu ajn fonto" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Uzant-difinita fonto 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Uzant-difinita fonto 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Uzant-difinita fonto 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Uzant-difinita fonto 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Nekonata fonto" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Sukceso" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Äœenerala eraro" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Nekonata paketo" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Nekonata versio en paketo" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Malvalida publika Ålosila algoritmo" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Malvalida resuma algoritmo" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "MalÄusta publika Ålosilo" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "MalÄusta sekreta Ålosilo" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "malÄusta subskribo" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Neniu publika Ålosilo" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Eraro en kontrolsumo" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "MalÄusta pasfrazo" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Malvalida ĉifra algoritmo" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Malfermo de Ålosilringo" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Malvalida paketo" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Malvalida kiraso" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Neniu ID de uzanto" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Neniu sekreta Ålosilo" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "MalÄusta sekreta Ålosilo uzata" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "MalÄusta seanca Ålosilo" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Nekonata densiga algoritmo" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Numero ne estas primo" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Malvalida enkodiga metodo" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Malvalida ĉifriga skemo" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Malvalida subskriba skemo" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Malvalida atributo" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Neniu valoro" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Ne trovita" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Valoro ne estas trovita" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Sintaks-eraro" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "MalÄusta valoro MPI" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Malvalida pasfrazo" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Malvalida subskriba klaso" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Rimedoj estas plenuzitaj" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Malvalida Ålosilringo" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Eraro de fidinda DB" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "MalÄusta atestilo" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Malvalida ID de uzanto" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Neatendita eraro" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Konflikto de tempo" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Åœlosilservila eraro" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Malkorekta publika Ålosila algoritmo" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "OmaÄo al D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Malforta ĉifra Ålosilo" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Malvalida Ålosila longo" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Malvalida argumento" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Sintaks-eraro en URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Malvalida URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Ret-eraro" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Nekonata retnodo" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Memtesto fiaskis" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Datumaro ne ĉifrita" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Datumaro ne procezita" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Neuzebla publika Ålosilo" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Neuzebla sekreta Ålosilo" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Malvalida valoro" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "MalÄusta atestila ĉeno" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Mankas atestilo" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Neniu datumaro" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Program-miso" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Ne subtenata" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Malvalida operacia kodo" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Tempofino" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Interna eraro" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Malvalida objekto" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Provizita objekto tro mallongas" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Provizita objekto tro larÄas" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Mankas ero en objekto" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Ne realigita" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Konflikta uzo" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Malvalida ĉifra reÄimo" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Malvalida flago" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Malvalida traktilo" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Rezulto estas tranĉita" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Malkompleta linio" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Malvalida respondo" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Neniu agento rulas" + +#: src/err-codes.h:106 +#, fuzzy +#| msgid "agent error" +msgid "Agent error" +msgstr "agent-eraro" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Malvalida datumaro" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Nespecifa paneo de servilo Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Äœenerala eraro de Assuan" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Malvalida seanca Ålosilo" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Malvalida S-esprimo" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Nesubtenata algoritmo" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Neniu pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Eraro de pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "MalÄusta PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Malvalida nomo" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "MalÄusta datumaro" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Malvalida parametro" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Malkorekta karto" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Neniu dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "eraro de dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Atestilo estas senvalidita" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Neniu konata CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL tro malnovas" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Linio tro longas" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Ne fidinda" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Operacio estas nuligita" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "MalÄusta atestilo CA" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Atestilo malvalidiÄis" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Atestilo tro novas" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Nesubtenata atestilo" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Nekonata S-esprimo" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Nesubtenata protekto" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Rompita protekto" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Plursenca nomo" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Kart-eraro" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Kart-reekigo estas postulata" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Karto estas demetita" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Malvalida karto" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Karto ne ĉeestas" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Neniu aplikaĵo PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Ne konfirmita" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Agord-eraro" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Neniu kongruo de politiko" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Malvalida indekso" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Malvalida ID" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Neniu demono SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Eraro de la demono SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Nesubtenata protokolo" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "MalÄusta PIN-metodo" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Karto ne estas ekigita" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Nesubtenata operacio" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Malkorekta uzmaniero de Ålosilo" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Nenio trovita" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Malkorekta tipo de blob" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Mankas valoro" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problemo de aparataro" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN estas blokita" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Uzkondiĉoj ne estas kontentigitaj" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN-oj ne estas sinkronigitaj" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Malvalida CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Eraro de BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Malvalida BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Elemento ne estas trovita" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identiganto ne estas trovita" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Malvalida marko" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Malvalida longo" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Malvalida Ålosil-informo" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Neatentida marko" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Neniu enkodita DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Neniu objekto CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Malvalida objekto CMS" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Nekonata objekto CMS" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Nesubtenata objekto CMS" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Nesubtenata enkodigo" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Nesubtenata versio CMS" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Nekonata algoritmo" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Malvalida ĉifra maÅino" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Publika Ålosilo ne estas fidinda" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Malĉifro fiaskis" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Åœlosilo malvalidiÄis" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Subskribo malvalidiÄis" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Ekodiga problemo" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Malvalida stato" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Duobligita valoro" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Mankas ago" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Modulo ASN.1 ne estas trovita" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Malvalida ĉeno OID" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Malvalida tempo" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Malvalida objekto CRL" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Nesubtenata versio CRL" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Malvalida atestila objekto" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nekonata nomo" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Lokaĵara funkcio fiaskis" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Ne Ålosita" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Perforto de protokolo" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Malvalida MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Malvalida peto" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Nekonata aldono" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Nekonata grava aldono" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Åœlosita" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Nekonata modifilo" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Nekonata komando" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Ne operaciebla" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Neniu pasfrazo estis donata" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Neniu PIN estis donata" + +#: src/err-codes.h:207 +#, fuzzy +#| msgid "Not locked" +msgid "Not enabled" +msgstr "Ne Ålosita" + +#: src/err-codes.h:208 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "No crypto engine" +msgstr "Malvalida ĉifra maÅino" + +#: src/err-codes.h:209 +#, fuzzy +#| msgid "Missing value" +msgid "Missing key" +msgstr "Mankas valoro" + +#: src/err-codes.h:210 +#, fuzzy +#| msgid "No CMS object" +msgid "Too many objects" +msgstr "Neniu objekto CMS" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +#, fuzzy +#| msgid "Card not initialized" +msgid "Not initialized" +msgstr "Karto ne estas ekigita" + +#: src/err-codes.h:213 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing issuer certificate" +msgstr "Mankas atestilo" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +#, fuzzy +#| msgid "Invalid time" +msgid "Invalid elliptic curve" +msgstr "Malvalida tempo" + +#: src/err-codes.h:216 +#, fuzzy +#| msgid "Unknown source" +msgid "Unknown elliptic curve" +msgstr "Nekonata fonto" + +#: src/err-codes.h:217 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated key" +msgstr "Duobligita valoro" + +#: src/err-codes.h:218 +#, fuzzy +#| msgid "Ambiguous name" +msgid "Ambiguous result" +msgstr "Plursenca nomo" + +#: src/err-codes.h:219 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "No crypto context" +msgstr "Malvalida ĉifra maÅino" + +#: src/err-codes.h:220 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Wrong crypto context" +msgstr "Malvalida ĉifra maÅino" + +#: src/err-codes.h:221 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Bad crypto context" +msgstr "Malvalida ĉifra maÅino" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +#, fuzzy +#| msgid "No public key" +msgid "Broken public key" +msgstr "Neniu publika Ålosilo" + +#: src/err-codes.h:224 +#, fuzzy +#| msgid "No secret key" +msgid "Broken secret key" +msgstr "Neniu sekreta Ålosilo" + +#: src/err-codes.h:225 +#, fuzzy +#| msgid "Invalid digest algorithm" +msgid "Invalid MAC algorithm" +msgstr "Malvalida resuma algoritmo" + +#: src/err-codes.h:226 +#, fuzzy +#| msgid "Operation cancelled" +msgid "Operation fully cancelled" +msgstr "Operacio estas nuligita" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "La operacio ankoraÅ­ ne finiÄis" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Bufro tro mallongas" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Malvalida long-indikilo en S-esprimo" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Ĉeno tro longa en S-esprimo" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Senpara kurbkrampo en S-esprimo" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-esprimo ne estas kanona" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "MalÄusta signo en S-esprimo" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "MalÄusta citigo en S-esprimo" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Nul-prefikso en S-esprimo" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Nestitaj montraj konsiletoj en S-esprimo" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Nekongruaj montraj konsiletoj" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Neatendita rezervita interpunkcio en S-esprimo" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "MalÄusta deksesuma signo en S-esprimo" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Malparaj deksesumaj numeroj en S-esprimo" + +#: src/err-codes.h:241 +#, fuzzy +#| msgid "Bad octadecimal character in S-expression" +msgid "Bad octal character in S-expression" +msgstr "MalÄusta okuma signo en S-esprimo" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Datumaro ne ĉifrita" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Nekonata nomo" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Neniu publika Ålosilo" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Bufro tro mallongas" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Linio tro longas" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "No certificate chain" +msgstr "MalÄusta atestila ĉeno" + +#: src/err-codes.h:252 +#, fuzzy +#| msgid "Certificate too young" +msgid "Certificate is too large" +msgstr "Atestilo tro novas" + +#: src/err-codes.h:253 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid record" +msgstr "Malvalida karto" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +#, fuzzy +#| msgid "Unexpected tag" +msgid "Unexpected message" +msgstr "Neatentida marko" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +#, fuzzy +#| msgid "Invalid cipher algorithm" +msgid "No cipher algorithm" +msgstr "Malvalida ĉifra algoritmo" + +#: src/err-codes.h:260 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing client certificate" +msgstr "Mankas atestilo" + +#: src/err-codes.h:261 +#, fuzzy +#| msgid "Certificate revoked" +msgid "Close notification received" +msgstr "Atestilo estas senvalidita" + +#: src/err-codes.h:262 +#, fuzzy +#| msgid "Key expired" +msgid "Ticket expired" +msgstr "Åœlosilo malvalidiÄis" + +#: src/err-codes.h:263 +#, fuzzy +#| msgid "Bad public key" +msgid "Bad ticket" +msgstr "MalÄusta publika Ålosilo" + +#: src/err-codes.h:264 +#, fuzzy +#| msgid "Unknown packet" +msgid "Unknown identity" +msgstr "Nekonata paketo" + +#: src/err-codes.h:265 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "Bad certificate message in handshake" +msgstr "MalÄusta atestila ĉeno" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +#, fuzzy +#| msgid "Key expired" +msgid "Key disabled" +msgstr "Åœlosilo malvalidiÄis" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +#, fuzzy +#| msgid "Invalid object" +msgid "Invalid lock object" +msgstr "Malvalida objekto" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Äœenerala eraro de IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Akcepta voko de IPC fiaskis" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Konekta voko de IPC fiaskis" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Malvalida respondo de IPC" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Malvalida valoro estis pasata al IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Nekompleta linio estis pasata al IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Pasita linio al IPC tro longas" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Nestitaj komandoj IPC" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Neniu datumar funkcivoko en IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Neniu enketa funkcivoko en IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Ne estas servilo IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Ne estas kliento IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problemo dum ekigo de servilo IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Leg-eraro de IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Skrib-eraro de IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Tro multa datumaro por tavolo IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Neatendita komando IPC" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Nekonata komando IPC" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Sintaks-eraro de IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC-voko estas nuligita" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Neniu enig-fonto por IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Neniu elig-fonto por IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Parametra eraro de IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Nekonata enketo de IPC" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Crypto engine too old" +msgstr "Malvalida ĉifra maÅino" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Duobligita valoro" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Atestilo tro novas" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "Provizita objekto tro mallongas" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Nekonata nomo" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Malvalida operacia kodo" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Nekonata nomo" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not locked" +msgid "Not authenticated" +msgstr "Ne Ålosita" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Nesubtenata protekto" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Neniu agento rulas" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Eraro de la demono SmartCard" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Åœlosilservila eraro" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Nekonata sistem-eraro" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Malvalida ĉeno OID" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Malvalida S-esprimo" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing DNS query packet" +msgstr "Mankas atestilo" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Malĉifro fiaskis" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Tempofino" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Äœenerala eraro de IPC" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Äœenerala eraro" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Äœenerala eraro" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Äœenerala eraro de Assuan" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Äœenerala eraro" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Äœenerala eraro de Assuan" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Skrib-eraro de IPC" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Äœenerala eraro de IPC" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Konekta voko de IPC fiaskis" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Äœenerala eraro" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Kart-reekigo estas postulata" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Elemento ne estas trovita" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Ne subtenata" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Neatendita eraro" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Nesubtenata operacio" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "MalÄusta atestilo" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Nekonata aldono" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Tempofino" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "eraro de dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "eraro de dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Leg-eraro de IPC" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Ne estas servilo IPC" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Sukceso" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Agord-eraro" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Perforto de protokolo" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Nekonata aldono" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Äœenerala eraro" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Kart-reekigo estas postulata" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Malvalida atributo" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Nesubtenata protekto" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Perforto de protokolo" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Malvalida stato" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Neniu objekto CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Problemo de aparataro" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Malvalida stato" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Ekodiga problemo" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Nesubtenata protekto" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Malvalida karto" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Mankas ago" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Perforto de protokolo" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "La operacio ankoraÅ­ ne finiÄis" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Operacio estas nuligita" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Linio tro longas" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Operacio estas nuligita" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Äœenerala eraro de IPC" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Rimedoj estas plenuzitaj" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Perforto de protokolo" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Malvalida stato" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Nesubtenata atestilo" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Kart-reekigo estas postulata" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Sukceso" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Ne operaciebla" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Ne operaciebla" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Ne estas servilo IPC" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Malĉifro fiaskis" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Uzant-difinita erarkodo 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Uzant-difinita erarkodo 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Uzant-difinita erarkodo 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Uzant-difinita erarkodo 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Uzant-difinita erarkodo 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Uzant-difinita erarkodo 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Uzant-difinita erarkodo 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Uzant-difinita erarkodo 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Uzant-difinita erarkodo 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Uzant-difinita erarkodo 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Uzant-difinita erarkodo 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Uzant-difinita erarkodo 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Uzant-difinita erarkodo 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Uzant-difinita erarkodo 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Uzant-difinita erarkodo 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Uzant-difinita erarkodo 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Sukceso" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Sintaks-eraro" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Perforto de protokolo" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Sistem-eraro sen errno" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Nekonata sistem-eraro" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Fino de dosiero" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Nekonata erar-kodo" + +#: src/argparse.c:468 +#, fuzzy +msgid "argument not expected" +msgstr "skribas sekretan Ålosilon al '%s'\n" + +#: src/argparse.c:470 +#, fuzzy +msgid "read error" +msgstr "legeraro ĉe dosiero" + +#: src/argparse.c:472 +#, fuzzy +msgid "keyword too long" +msgstr "pasfrazo estas tro longa\n" + +#: src/argparse.c:474 +#, fuzzy +msgid "missing argument" +msgstr "nevalida argumento" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid armor" +msgid "invalid argument" +msgstr "nevalida kiraso" + +#: src/argparse.c:478 +#, fuzzy +msgid "invalid command" +msgstr "malkongruaj komandoj\n" + +#: src/argparse.c:480 +#, fuzzy +msgid "invalid alias definition" +msgstr "nevalida kiraso" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Agord-eraro" + +#: src/argparse.c:484 src/argparse.c:517 +#, fuzzy +msgid "out of core" +msgstr "ne traktita" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +msgid "invalid meta command" +msgstr "malkongruaj komandoj\n" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Nekonata komando" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Neatendita komando IPC" + +#: src/argparse.c:494 +#, fuzzy +msgid "invalid option" +msgstr "nevalida kiraso" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, fuzzy, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "nevalida kiraso" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, fuzzy, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "Nevalida komando (provu per \"helpo\")\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "nevalida kiraso" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "averto: ne eblis rekoni %s\n" + +#, fuzzy +#~ msgid "out of core\n" +#~ msgstr "ne traktita" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Uzmaniero: %s GPG-ERARO [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Rimedoj estas plenuzitaj" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Malvalida datumaro" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Äœenerala eraro" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "eraro de dirmngr" diff --git a/comm/third_party/libgpg-error/po/es.gmo b/comm/third_party/libgpg-error/po/es.gmo new file mode 100644 index 0000000000..3909cc5167 Binary files /dev/null and b/comm/third_party/libgpg-error/po/es.gmo differ diff --git a/comm/third_party/libgpg-error/po/es.po b/comm/third_party/libgpg-error/po/es.po new file mode 100644 index 0000000000..d08c3df99f --- /dev/null +++ b/comm/third_party/libgpg-error/po/es.po @@ -0,0 +1,2017 @@ +# +# Copyright (C) 2018 g10 Code GmbH +# This file is distributed under the same license as the libgpg-error package. +# emma peel , 2018 +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.30-beta4\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:25+0100\n" +"Last-Translator: Tails translators \n" +"Language-Team: es \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.11\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Fuente no especificada" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Cualquier origen" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Origen determinado por el usuario 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Origen determinado por el usuario 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Origen determinado por el usuario 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Origen determinado por el usuario 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Origen desconocido" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Éxito" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Error general" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Paquete desconocido" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Versión desconocida en el paquete" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Algoritmo de clave pública no válido" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Algoritmo de resumen seleccionado no válido" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Clave pública incorrecta" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Clave secreta incorrecta" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Firma incorrecta" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "No hay clave pública" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Error de checksum" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Frase contraseña errónea" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "El algoritmo de cifrado seleccionado no es correcto" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "No se puede abrir el anillo de claves" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Paquete incorrecto" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Armadura incorrecta" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "No hay identificador de usuario" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "No tenemos la clave secreta" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Clave secreta" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Clave incorrecta de sesión" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Algoritmo de compresión desconocido" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "El número no es primo" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Método de codificación incorrecto" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Esquema de cifrado incorrecto" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Esquema de firmado incorrecto" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Atributo incorrecto" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "No hay valor" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "No hallado" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Valor no encontrado" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Error de sintaxis" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Valor MPI incorrecto" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Frase contraseña errónea" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Clase de firma incorrecta" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Recursos agotados" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Anillo de claves incorrecto" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Error de la base de datos de confianza" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Certficado incorrecto" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Identificador de usuario no válido" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Error inesperado" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Conflicto de tiempo" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Error del servidor de claves" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Algoritmo de clave pública equivocado" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Tributo a D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Clave de cifrado débil" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Longitud incorrecta de clave" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Argumento incorrecto" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Error de sintaxis en la URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "URI incorrecta" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Error de red" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Host desconocido" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Ha fallado el auto-test" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Los datos no están cifrados" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Los datos no han sido procesados" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Clave pública no se puede usar" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Clave secreta no se puede usar" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Valor incorrecto" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Cadena de certificados incorrecta" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Certificado faltante" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "No hay datos" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Bug" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "No disponible" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Código de operación desconocido" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Vida máxima" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Error interno" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "Fin de fichero (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Objecto incorrecto" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "El objeto es demasiado corto" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "El objeto es demasiado grande" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Falta un item en el objeto" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "No está implementado" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Uso incompatible" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Modo de cifrado incorrecto" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Etiqueta incorrecta" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Resultado truncado" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Línea incompleta" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Respuesta no válida" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "No hay ningún agente en ejecución" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Error del agente" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Datos no válidos" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Error no especificado del servidor Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Error general de Assuan" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Clave de sesión no válida" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "S-expression no válida" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Algoritmo no soportado" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "No hay Pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "error de pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "PIN incorrecto" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Nombre no válido" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Datos corruptos" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Parámetro incorrecto" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Tarjeta incorrecta" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "No existe dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Error de dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certificado revocado" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "No hay ningún CRL conocido." + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL es demasiado antiguo" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Línea demasiado larga" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "No confiable" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Operación cancelada" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Certificado CA incorrecto" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certificado caducado" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Cadena de certificados demasiado joven" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Certificado no soportado" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "S-expression desconocida" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Protección no soportada" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Protección corrompida" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Nombre ambiguo" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Error de tarjeta" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Hay que resetear la tarjeta" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Tarjeta removida" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Tarjeta no válida" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "La tarjeta no está" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "No hay aplicación PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Sin confirmar" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Error de configuración" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "No coincide ninguna política" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ãndice incorrecto" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Identificador no válido" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "No hay agente de SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Error del agente SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Protocolo no soportado" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Método de PIN incorrecto" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Tarjeta no arrancada" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Operación no soportada" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Uso de clave incorrecto" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "No se ha encontrado nada" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Tipo de blob incorrecto" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Falta un valor" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problema de hardware" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN bloqueado" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Condiciones de uso no satisfechas" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "Los PINs no están sincronizados" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "CRL no válido" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Error BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "BER no válido" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "No se ha encontrado el elemento" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "No se ha encontrado el identificador" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Etiqueta no válida" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Longitud incorrecta" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Información de clave incorrecta" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Etiqueta inesperada" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "No está encodeado en DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "No hay objeto CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Objeto CMS no válido" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Objeto CMS desconocido" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Objeto CMS no soportado" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Encoding no soportado" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Versión CMS no soportada" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Algoritmo desconocido" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Motor de cifrado no válido" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Clave pública no confiable" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Descifrado fallido" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Clave caducada" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Firma caducada" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Problema de codificación" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Estado no válido" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Valor duplicado" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Acción faltante" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "No se ha encontrado el Módulo ASN.1" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Cadena OID no válida" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Hora equivocada" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Objecto CRL incorrecto" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Versión CRL no soportada" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Certificado de objeto incorrecto" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nombre desconocido" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Una función locale ha fallado" + +# What is not locked? the translation depends on the gender of the thing locked (bloqueado/bloqueada) +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "No está bloqueada" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Violación de protocolo" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Mac incorrecta" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Consulta no válida" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Extensión desconocida" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Extensión crítica desconocida" + +# needs information about the subject, because it has gender in Spanish and probably other languages too +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Bloqueada" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Opción desconocida" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Orden desconocida" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "No operativo" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "No se ha dado ninguna frase contraseña" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "No se ha dado ningún PIN" + +# gender information missing +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "No habilitado" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "No hay ningún motor de cifrado" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Falta la clave" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Demasiados objetos" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Se ha alcanzado el límite" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Sin inicializar" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Falta el certificado del emisor" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "No hay ningún servidor de claves disponible" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Curva elíptica incorrecta" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Curva elíptica desconocida" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Clave duplicada" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Resultado ambiguo" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "No hay contexto de cifrado" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Contexto de cifrado incorrecto" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Contexto de cifrado equivocado" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Conflicto en el contexto de cifrado" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Clave pública rota" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Clave secreta rota" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Algoritmo MAC no válido" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Operación cancelada definitivamente" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Operación aún no terminada" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffer demasiado corto" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Especificador de largo no válido en S-expression" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Cadena demasiado larga en S-expression" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Paréntesis incompleto en S-expression" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-expression no canónica" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Caracter erróneo en la S-expression" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Comillas mal puestas en la S-expression" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Prefijo cero en S-expression" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Sugerencias de exhibición anidadas en S-expression" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Sugerencias de exhibición no concordadas" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Caracter hexadecimal equivocado en la S-expression" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Caracteres hexadecimales pares en la S-expression" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Caracter octal equivocado en la S-expression" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "Todas las subclaves están caducadas o revocadas" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "La base de datos está corrompida" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "El servidor ha indicado un fallo" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "Sin nombre" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "Sin clave" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "Clave heredada" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "Consulta demasiado corta" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "Consulta demasiado larga" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "No hay cadena de certificados" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Certificado demasiado grande" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Mensaje inesperado" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Han fallado la compresión o la descompresión" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "No hay algoritmo de cifrado" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Falta el certificado de cliente" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Recibida notificación de cierre" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Ticket caducado" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Ticket erróneo" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Identidad desconocida" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Mensaje erróneo de certificado en el handshake" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Mensaje erróneo de pedido de certificado en el handshake" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Mensaje erróneo de verificación de certificado en el handshake" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Mensaje erróneo de cambio de cifrado en el handshake" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Mensaje erróneo de hola del cliente en el handshake" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Mensaje erróneo de hola del servidor en el handshake" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Mensaje mal terminado en el handshake" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Cadena errónea" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "Prohibido" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Clave deshabilitada" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "La operación no es posible con una clave basada en tarjeta" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Objecto de bloqueo incorrecto" + +#: src/err-codes.h:280 +msgid "True" +msgstr "Verdadero" + +#: src/err-codes.h:281 +msgid "False" +msgstr "Falso" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Error general de IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Fallo al aceptar la llamada IPC" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Falló la llamada de conexión IPC" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Respuesta IPC no válida" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Valor no válido pasado a IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Línea incompleta pasada a IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "La línea pasada a IPC es demasiado larga" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Órdenes IPC anidadas" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "No es un servidor IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "No es un cliente IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problema al iniciar el servidor IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "error de lectura IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "error de escritura IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Demasiados datos para la capa IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Orden IPC inesperada" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Orden IPC desconocida" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Error de sintaxis IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Se ha cancelado IPC" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "No hay fuente de entrada para IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "No hay fuente de salida para IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Error de parámetro IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "Motor de cifrado demasiado antiguo" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "La ventana o la pantalla son demasiado pequeñas." + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "La ventana o pantalla son demasiado grandes" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "No se ha configurado la variable de entorno requerida" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "Esa ID de usuario ya existe" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "El nombre ya existe" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "Nombre duplicado" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "El objeto es demasiado joven" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "El objeto es demasiado antiguo" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "Orden de ejecución no válido" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "Ya se ha descargado" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "Nombre incorrecto" + +# gender information missing +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "No habilitado" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Inappropriate LDAP authentication" +msgid "Bad authentication" +msgstr "Autentificación LDAP inapropiada" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "No hay ningún agente en ejecución" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Error del agente SmartCard" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Error del servidor de claves" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "Detectado error del sistema" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "Error DNS desconocido" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "Sección DNS incorrecta" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "Conexión cerrada en DNS" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "Fallo de verificación en DNS" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "Tiempo excedido para DNS" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "Error general de LDAP" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "Error general de atributo de LDAP" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "Error general de nombre de LDAP" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "Error general de seguridad de LDAP" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "Error general de servicio de LDAP" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "Error general de actualización de LDAP" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "Código de error experimental de LDAP" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "Código de error privado de LDAP" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "Otro error general de LDAP" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "Ha fallado la conexión LDAP (X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "Límite de referrals de LDAP excedido" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "Bucle del cliente LDAP" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "No se devolvió ningún resultado LDAP" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "Control de LDAP no encontrado" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "No soportado por LDAP" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "Error de conexión de LDAP" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "Sin memoria suficiente para LDAP" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "Parámetro incorrecto para una rutina de LDAP" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "Operación LDAP cancelada por el usuario" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "Filtro de búsqueda de LDAP incorrecto" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "Método de autentificación de LDAP desconocido" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "Tiempo excedido para LDAP" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "Error de decoding de LDAP" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "Error de encoding de LDAP" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "Error local de LDAP" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "No se puede conectar al servidor LDAP" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "Éxito LDAP" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "Error de operación de LDAP" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "Error de protocolo de LDAP" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "Límite de tiempo excedido en LDAP" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "Límite de tamaño excedido en LDAP" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "Método de autentificación LDAP no soportado" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "Se requiere una autentificación LDAP (más) fuerte" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "Excedido el límite administrativo de LDAP" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "Extensión crítica LDAP no disponible" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "Confidencialidad requerida por LDAP" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "Ese atributo LDAP no existe" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "No existe ese objeto LDAP" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "La entrada de LDAP es una hoja" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "Autentificación LDAP inapropiada" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "Credenciales LDAP no válidas" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "Acceso insuficiente para LDAP" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "El servidor LDAP está ocupado" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "El servidor LDAP no está disponible" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "El servidor LDAP no quiere funcionar" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "Bucle detectado por LDAP" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "Violación de nombre de LDAP" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "Violación de clase de objeto de LDAP" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "Ya existe (LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "Error diferente de LDAP" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "Recursos agotados en LCUP" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "Violación de seguridad en LCUP" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "Datos no válidos en LCUP" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "Esquema no soportado en LCUP" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "Se requiere un reload en LCUP" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAP cancelado" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "Lo hay ninguna operación de LDAP que cancelar" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "Demasiado tarde para cancelar LDAP" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "No se puede cancelar LDAP" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "Falló de declaración de LDAP" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Origen determinado por el usuario 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Origen determinado por el usuario 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Origen determinado por el usuario 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Origen determinado por el usuario 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "LDAP success" +msgid "SQL success" +msgstr "Éxito LDAP" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Error de sintaxis" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "LDAP protocol error" +msgid "SQL database lock protocol error" +msgstr "Error de protocolo de LDAP" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Error desconocido del sistema" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Fin del fichero" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Código de error desconocido" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "parámetro inesperado" + +#: src/argparse.c:470 +msgid "read error" +msgstr "error de lectura" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "palabra clave demasiado larga" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "falta el parámetro" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "parámetro incorrecto" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "orden inválida" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "definición de alias inválida" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "LDAP operations error" +msgid "permission error" +msgstr "Error de operación de LDAP" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "memoria desbordada" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "orden inválida" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Orden desconocida" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Orden IPC inesperada" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "opción inválida" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "falta parámetro para la opción \"%.50s\"\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "parámetro incorrecto para la opción \"%.50s\"\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "la opción \"%.50s\" no necesita parámetros\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "orden inválida \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "la opción \"%.50s\" es ambigua\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "la orden \"%.50s\" es ambigua\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "opción inválida \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "Reporta los problemas encontrados en .\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "advertencia: no se pudo entender %s\n" + +#~ msgid "out of core\n" +#~ msgstr "memoria desbordada\n" diff --git a/comm/third_party/libgpg-error/po/fr.gmo b/comm/third_party/libgpg-error/po/fr.gmo new file mode 100644 index 0000000000..d3b83ac4dd Binary files /dev/null and b/comm/third_party/libgpg-error/po/fr.gmo differ diff --git a/comm/third_party/libgpg-error/po/fr.po b/comm/third_party/libgpg-error/po/fr.po new file mode 100644 index 0000000000..6bb01b399f --- /dev/null +++ b/comm/third_party/libgpg-error/po/fr.po @@ -0,0 +1,2188 @@ +# French translation of Libgpg-error +# Copyright (C) 2005, 2011, 2012, 2014 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# +# Stephane Roy , 2005. +# David Prévot , 2011, 2012, 2014. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error-1.17\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:26+0100\n" +"Last-Translator: David Prévot \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Source non indiquée" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "Agent GPG" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "N'importe quelle source" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Source 1 définie par l'utilisateur" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Source 2 définie par l'utilisateur" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Source 3 définie par l'utilisateur" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Source 4 définie par l'utilisateur" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Source inconnue" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Réussite" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Erreur générale" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Paquet inconnu" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Version inconnue dans le paquet" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Algorithme à clef publique incorrect" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Algorithme de hachage incorrect" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Mauvaise clef publique" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Mauvaise clef secrète" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Mauvaise signature" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Pas de clef publique" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Erreur de somme de contrôle" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Mauvaise phrase secrète" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Algorithme de chiffrement incorrect" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Porte-clefs ouvert" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Paquet incorrect" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Armure incorrecte" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Pas d'identité" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Pas de clef secrète" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Mauvaise clef secrète utilisée" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Mauvaise clef de session" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Algorithme de compression inconnu" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Ce nombre n'est pas premier" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Méthode d'encodage incorrecte" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Schéma de chiffrement incorrect" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Schéma de signature incorrect" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Attribut incorrect" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Pas de valeur" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Non trouvé" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Valeur non trouvée" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Erreur de syntaxe" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Mauvaise valeur MPI" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Phrase secrète incorrecte" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Classe de signature incorrecte" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Ressources épuisées" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Porte-clefs incorrect" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Erreur de la base de confiance" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Mauvais certificat" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Identité incorrecte" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Erreur inattendue" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Conflit temporel" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Erreur du serveur de clefs" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Mauvais algorithme à clef publique" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Hommage à D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Clef de chiffrement faible" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Longueur de clef incorrecte" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Argument incorrect" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Erreur de syntaxe dans l'URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "URI incorrecte" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Erreur réseau" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Hôte inconnu" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Échec de l'autotest" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Données non chiffrées" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Données non traitées" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Clef publique inutilisable" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Clef privée inutilisable" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Valeur incorrecte" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Mauvaise chaîne de certificat" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Certificat manquant" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Pas de données" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Bogue" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Non pris en charge" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Code d'opération incorrect" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Délai d'attente dépassé" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Erreur interne" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Objet incorrect" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "L'objet fourni est trop petit" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "L'objet fourni est trop grand" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Élément manquant dans l'objet" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Non implémenté" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Utilisation conflictuelle" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Mode de chiffrement incorrect" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Option incorrecte" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Gestion incorrecte" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Résultat tronqué" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Ligne incomplète" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Réponse incorrecte" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Pas d'agent en cours d'exécution" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Erreur d'agent" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Données incorrectes" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Erreur générale du serveur Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Erreur générale Assuan" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Clef de session incorrecte" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Expression symbolique incorrecte" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Algorithme non pris en charge" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Pas de pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Erreur de pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Mauvais code personnel" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Nom incorrect" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Mauvaises données" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Paramètre incorrect" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Mauvaise carte" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Pas de dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Erreur de dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certificat révoqué" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Pas de CRL connu" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL trop ancien" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Ligne trop longue" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Pas de confiance" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Opération annulée" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Mauvais certificat de l'autorité de certification" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certificat expiré" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certificat trop récent" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Certificat non pris en charge" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Expression symbolique inconnue" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Protection non prise en charge" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Protection corrompue" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Nom ambigu" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Erreur de carte" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Réinitialisation de la carte nécessaire" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Carte enlevée" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Carte incorrecte" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Carte absente" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Application non PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Non confirmé" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Erreur de configuration" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Aucune correspondance de politique" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Indice incorrect" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Identifiant incorrect" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Pas de démon SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Erreur de démon SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Protocole non pris en charge" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Mauvaise méthode de code personnel" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Carte non initialisée" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Opération non prise en charge" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Mauvaise utilisation de la clef" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Rien de trouvé" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Mauvais type de blob" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Valeur manquante" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problème matériel" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "Code personnel bloqué" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Conditions d'utilisation non satisfaites" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "Les codes personnels ne sont pas synchrones" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "CRL incorrect" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Erreur de BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "BER incorrect" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Élément non trouvé" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identifiant non trouvé" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Balise incorrecte" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Longueur incorrecte" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Informations de clef incorrectes" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Balise inattendue" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Non encodé DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Pas d'objet CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Objet CMS incorrect" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Objet CMS inconnu" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Objet CMS non pris en charge" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Codage non pris en charge" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Version de CMS non prise en charge" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Algorithme inconnu" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Moteur de chiffrement incorrect" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Pas de confiance dans la clef publique" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Échec de déchiffrement" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Clef expirée" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Signature expirée" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Problème d'encodage" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "État incorrect" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Valeur dupliquée" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Action manquante" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Module ASN.1 non trouvé" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Chaîne OID incorrecte" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Date incorrecte" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Objet CRL incorrect" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Version de CRL non prise en charge" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Objet de certificat incorrect" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nom inconnu" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Échec d'une fonction de paramètres régionaux (locale)" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Non verrouillé" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Violation de protocole" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "MAC incorrect" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Requête incorrecte" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Extension inconnue" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Extension critique inconnue" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Verrouillé" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Option inconnue" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Commande inconnue" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Non opérationnel" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Aucune phrase secrète fournie" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Aucun code personnel fourni" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Non activé" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Aucun moteur de chiffrement" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Clef manquante" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Trop d'objets" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Limite atteinte" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Non initialisé" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Certificat de l'émetteur manquant" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Aucun serveur de clefs disponible" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Courbe elliptique incorrecte" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Courbe elliptique inconnue" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Clef dupliquée" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Résultat ambigu" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Aucun contexte de chiffrement" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Contexte de chiffrement incorrect" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Mauvais contexte de chiffrement" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Conflit dans le contexte de chiffrement" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Clef publique cassée" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Clef secrète cassée" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Algorithme MAC incorrect" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Opération complètement annulée" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "L'opération n'est pas encore terminée" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Tampon trop court" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Longueur de spécificateur incorrecte dans l'expression symbolique" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Chaîne trop longue dans l'expression symbolique" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Parenthèses non correspondantes dans l'expression symbolique" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "Expression symbolique non canonique" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Mauvais caractère dans l'expression symbolique" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Erreur de guillemets dans l'expression symbolique" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Préfixe nul dans l'expression symbolique" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Affichage imbriqué d'indications dans l'expression symbolique" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Affichage d'indications non correspondantes" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Ponctuation réservée inattendue dans l'expression symbolique" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Mauvais caractère hexadécimal dans l'expression symbolique" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Nombre hexadécimal impair dans l'expression symbolique" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Mauvais caractère octal dans l'expression symbolique" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Données non chiffrées" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Nom inconnu" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Pas de clef publique" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Tampon trop court" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Ligne trop longue" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Aucune chaîne de certificat" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Le certificat est trop grand" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Enregistrement incorrect" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "Le MAC ne peut pas être vérifié" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Message inattendu" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Échec de compression ou décompression" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Un compteur devrait envelopper" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Message d’alerte fatale reçu" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Aucun algorithme de chiffrement" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Certificat de client manquant" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Notification de fermeture reçue" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Ticket expiré" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Mauvais ticket" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Identité inconnue" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Mauvais message de certificat dans l’initialisation" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Mauvais message de demande de certificat dans l’initialisation" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Mauvais message de vérification de certificat dans l’initialisation" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Mauvais message de modification d’algorithme dans l’initialisation" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Mauvais message de salut du client dans l’initialisation" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Mauvais message de salut du serveur dans l’initialisation" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Mauvais message de fin de salut du serveur dans l’initialisation" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Mauvais message fini dans l’initialisation" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Mauvais message d’échange de clef du serveur dans l’initialisation" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Mauvais message d’échange de clef du client dans l’initialisation" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Chaîne erronée" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Clef désactivée" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Impossible avec une clef basée sur carte" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Objet de verrouillage incorrect" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Erreur générale IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Échec de l'appel IPC accept" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Échec de l'appel IPC connect" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Réponse IPC incorrecte" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Valeur incorrecte passée à IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Ligne incomplète transmise à IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Ligne trop longue transmise à IPC" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Commandes IPC imbriquées" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Aucune donnée de rappel dans IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Aucune requête de rappel dans IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Pas un serveur IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Pas un client IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problème au démarrage du serveur IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Erreur de lecture IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Erreur d'écriture IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Trop de données pour la couche IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Commande IPC inattendue" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Commande IPC inconnue" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Erreur de syntaxe IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "L'appel IPC a été annulé" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Aucune source d'entrée pour IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Aucune source de sortie pour IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Erreur de paramètre IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Requête IPC inconnue" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "No crypto engine" +msgid "Crypto engine too old" +msgstr "Aucun moteur de chiffrement" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Valeur dupliquée" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certificat trop récent" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "L'objet fourni est trop petit" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Nom inconnu" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Code d'opération incorrect" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Nom inconnu" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Non activé" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Protection non prise en charge" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Pas d'agent en cours d'exécution" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Erreur de démon SmartCard" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Erreur du serveur de clefs" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Erreur système inconnue" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Chaîne OID incorrecte" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Expression symbolique incorrecte" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing issuer certificate" +msgid "Missing DNS query packet" +msgstr "Certificat de l'émetteur manquant" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Échec de déchiffrement" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Délai d'attente dépassé" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Erreur générale IPC" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Erreur générale" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Erreur générale" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Erreur générale Assuan" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Erreur générale" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Erreur générale Assuan" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Erreur d'écriture IPC" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Erreur générale IPC" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Échec de l'appel IPC connect" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Erreur générale" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Réinitialisation de la carte nécessaire" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Élément non trouvé" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Non pris en charge" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Erreur inattendue" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Opération non prise en charge" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Mauvais certificat" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Extension inconnue" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Délai d'attente dépassé" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "Erreur de dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "Erreur de dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Erreur de lecture IPC" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Pas un serveur IPC" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Réussite" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Erreur de configuration" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Violation de protocole" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Extension inconnue" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +#, fuzzy +#| msgid "Fatal alert message received" +msgid "Partial LDAP results+referral received" +msgstr "Message d’alerte fatale reçu" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Erreur générale" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Réinitialisation de la carte nécessaire" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Attribut incorrect" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Protection non prise en charge" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Violation de protocole" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "État incorrect" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Pas d'objet CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Problème matériel" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "État incorrect" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Problème d'encodage" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Protection non prise en charge" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Carte incorrecte" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +#, fuzzy +#| msgid "No keyserver available" +msgid "LDAP server is unavailable" +msgstr "Aucun serveur de clefs disponible" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Action manquante" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Violation de protocole" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "L'opération n'est pas encore terminée" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Opération annulée" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Ligne trop longue" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Opération annulée" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Erreur générale IPC" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Ressources épuisées" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Violation de protocole" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "État incorrect" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Certificat non pris en charge" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Réinitialisation de la carte nécessaire" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Réussite" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Non opérationnel" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Non opérationnel" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Pas un serveur IPC" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Échec de déchiffrement" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Code d'erreur 1 défini par l'utilisateur" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Code d'erreur 2 défini par l'utilisateur" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Code d'erreur 3 défini par l'utilisateur" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Code d'erreur 4 défini par l'utilisateur" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Code d'erreur 5 défini par l'utilisateur" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Code d'erreur 6 défini par l'utilisateur" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Code d'erreur 7 défini par l'utilisateur" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Code d'erreur 8 défini par l'utilisateur" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Code d'erreur 9 défini par l'utilisateur" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Code d'erreur 10 défini par l'utilisateur" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Code d'erreur 11 défini par l'utilisateur" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Code d'erreur 12 défini par l'utilisateur" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Code d'erreur 13 défini par l'utilisateur" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Code d'erreur 14 défini par l'utilisateur" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Code d'erreur 15 défini par l'utilisateur" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Code d'erreur 16 défini par l'utilisateur" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Réussite" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Erreur de syntaxe" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Violation de protocole" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Erreur système sans numéro" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Erreur système inconnue" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Fin de fichier" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Code d'erreur inconnu" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "argument inattendu" + +#: src/argparse.c:470 +msgid "read error" +msgstr "erreur de lecture" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "mot-clef trop long" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "argument manquant" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "argument incorrect" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "commande incorrecte" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "définition d'alias incorrecte" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Erreur de configuration" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "hors limite" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "commande incorrecte" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Commande inconnue" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Commande IPC inattendue" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "option incorrecte" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "argument manquant pour l'option « %.50s »\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "argument incorrect pour l'option « %.50s »\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "l'option « %.50s » n'attend pas d'argument\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "commande « %.50s » incorrecte\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "l'option « %.50s » est ambiguë\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "la commande « %.50s » est ambiguë\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "option « %.50s » incorrecte\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "attention : impossible de reconnaître %s\n" + +#~ msgid "out of core\n" +#~ msgstr "hors limite\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Utilisation : %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Ressources épuisées" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Données incorrectes" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Erreur générale" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "Erreur de dirmngr" diff --git a/comm/third_party/libgpg-error/po/hu.gmo b/comm/third_party/libgpg-error/po/hu.gmo new file mode 100644 index 0000000000..edc28b4048 Binary files /dev/null and b/comm/third_party/libgpg-error/po/hu.gmo differ diff --git a/comm/third_party/libgpg-error/po/hu.po b/comm/third_party/libgpg-error/po/hu.po new file mode 100644 index 0000000000..b63f26c033 --- /dev/null +++ b/comm/third_party/libgpg-error/po/hu.po @@ -0,0 +1,2253 @@ +# Hungarian translations of libgpg-error. +# Copyright (C) 2015 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# +# Balázs Úr , 2015. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error-1.7\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:26+0100\n" +"Last-Translator: Balázs Úr \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Meghatározatlan forrás" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG ügynök" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Bármilyen forrás" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "1. felhasználó által megadott forrás" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "2. felhasználó által megadott forrás" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "3. felhasználó által megadott forrás" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "4. felhasználó által megadott forrás" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Ismeretlen forrás" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Sikeres" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Ãltalános hiba" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Ismeretlen csomag" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Ismeretlen verzió a csomagban" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Érvénytelen nyilvános kulcs algoritmus" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Érvénytelen kivonat algoritmus" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Rossz nyilvános kulcs" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Rossz titkos kulcs" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Rossz aláírás" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Nincs nyilvános kulcs" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "EllenÅ‘rzőösszeg hiba" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Rossz jelmondat" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Érvénytelen titkosító algoritmus" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Kulcstartó nyitva" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Érvénytelen csomag" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Érvénytelen páncél" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Nincs felhasználóazonosító" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Nincs titkos kulcs" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Hibás titkos kulcs lett használva" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Rossz munkamenet kulcs" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Ismeretlen tömörítÅ‘ algoritmus" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "A szám nem prím" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Érvénytelen kódolási módszer" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Érvénytelen titkosítás séma" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Érvénytelen aláírás séma" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Érvénytelen attribútum" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Nincs érték" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Nem található" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Nem található érték" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Szintaktikai hiba" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Rossz MPI érték" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Érvénytelen jelmondat" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Érvénytelen aláírás osztály" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Az erÅ‘források kimerültek" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Érvénytelen kulcstartó" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Megbízhatósági adatbázis hiba" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Rossz tanúsítvány" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Érvénytelen felhasználóazonosító" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Váratlan hiba" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Időütközés" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Kulcskiszolgáló hiba" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Hibás nyilvános kulcs algoritmus" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Sarc a D. A. részére" + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Gyenge titkosítási kulcs" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Érvénytelen kulcshossz" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Érvénytelen argumentum" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Szintaktikai hiba az URI-ban" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Érvénytelen URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Hálózati hiba" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Ismeretlen gép" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "ÖnellenÅ‘rzés sikertelen" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Az adatok nincsenek titkosítva" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Az adatok nincsenek feldolgozva" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Használhatatlan nyilvános kulcs" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Használhatatlan titkos kulcs" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Érvénytelen érték" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Rossz tanúsítványlánc" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Hiányzó tanúsítvány" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Nincsenek adatok" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Hiba" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Nem támogatott" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Érvénytelen műveletkód" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "IdÅ‘túllépés" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "BelsÅ‘ hiba" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Érvénytelen objektum" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "A megadott objektum túl kicsi" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "A megadott objektum túl nagy" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Hiányzó elem az objektumban" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Nincs megvalósítva" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "ÃœtközÅ‘ használat" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Érvénytelen titkosító mód" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Érvénytelen jelzÅ‘" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Érvénytelen leíró" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Az eredmény csonkított" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Befejezetlen sor" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Érvénytelen válasz" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Nincs futó ügynök" + +#: src/err-codes.h:106 +#, fuzzy +#| msgid "agent error" +msgid "Agent error" +msgstr "ügynökhiba" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Érvénytelen adatok" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Nem specifikus Assuan kiszolgáló hiba" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Ãltalános Assuan hiba" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Érvénytelen munkamenet kulcs" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Érvénytelen S-kifejezés" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Nem támogatott algoritmus " + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Nincs pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "pinentry hiba" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Rossz PIN-kód" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Érvénytelen név" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Rossz adatok" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Érvénytelen paraméter" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Hibás kártya" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Nincs dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr hiba" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Tanúsítvány visszavonva" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Nincs ismert CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "Túl régi CRL" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Túl hosszú sor" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Nem megbízható" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "A művelet megszakítva" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Rossz CA tanúsítvány" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "A tanúsítvány lejárt" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Túl fiatal tanúsítvány" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Nem támogatott tanúsítvány" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Ismeretlen S-kifejezés" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Nem támogatott védelem" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Sérült védelem" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Nem egyértelmű név" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Kártyahiba" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Kártya visszaállítás szükséges" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Kártya eltávolítva" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Érvénytelen kártya" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "A kártya nincs jelen" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Nincs PKCS15 alkalmazás" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Nem megerÅ‘sített" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Beállítási hiba" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Nincs egyezÅ‘ házirend" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Érvénytelen index" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Érvénytelen azonosító" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Nincs SmartCard démon" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "SmartCard démon hiba" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Nem támogatott protokoll" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Rossz PIN-kód módszer" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "A kártya nincs elÅ‘készítve" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Nem támogatott művelet" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Hibás kulcshasználat" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Semmi sem található" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Hibás blob típus" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Hiányzó érték" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Hardverprobléma" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN-kód blokkolva" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "A használati feltételek nem teljesülnek" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "A PIN-kódok nincsenek szinkronizálva" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Érvénytelen CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER hiba" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Érvénytelen BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Az elem nem található" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Az azonosító nem található" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Érvénytelen címke" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Érvénytelen hossz" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Érvénytelen kulcsinformációk" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Váratlan címke" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Nem DER kódolású" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Nincs CMS objektum" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Érvénytelen CMS objektum" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Ismeretlen CMS objektum" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Nem támogatott CMS objektum" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Nem támogatott kódolás" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Nem támogatott CMS verzió" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Ismeretlen algoritmus" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Érvénytelen titkosítási motor" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "A nyilvános kulcs nem megbízható" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Visszafejtés sikertelen" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "A kulcs lejárt" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Az aláírás lejárt" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Kódolási probléma" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Érvénytelen állapot" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "KettÅ‘zött érték" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Hiányzó művelet" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Nem található ASN.1 modul" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Érvénytelen OID karakterlánc" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Érvénytelen idÅ‘pont" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Érvénytelen CRL objektum" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Nem támogatott CRL verzió" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Érvénytelen tanúsítványobjektum" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Ismeretlen név" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Egy területi beállítás függvény meghiúsult" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Nincs zárolva" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Protokollsértés" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Érvénytelen MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Érvénytelen kérés" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Ismeretlen kiterjesztés" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Ismeretlen kritikus kiterjesztés" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Zárolva" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Ismeretlen kapcsoló" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Ismeretlen parancs" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Nem működik" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Nincs jelmondat megadva" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Nincs PIN-kód megadva" + +#: src/err-codes.h:207 +#, fuzzy +#| msgid "Not locked" +msgid "Not enabled" +msgstr "Nincs zárolva" + +#: src/err-codes.h:208 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "No crypto engine" +msgstr "Érvénytelen titkosítási motor" + +#: src/err-codes.h:209 +#, fuzzy +#| msgid "Missing value" +msgid "Missing key" +msgstr "Hiányzó érték" + +#: src/err-codes.h:210 +#, fuzzy +#| msgid "No CMS object" +msgid "Too many objects" +msgstr "Nincs CMS objektum" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +#, fuzzy +#| msgid "Card not initialized" +msgid "Not initialized" +msgstr "A kártya nincs elÅ‘készítve" + +#: src/err-codes.h:213 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing issuer certificate" +msgstr "Hiányzó tanúsítvány" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +#, fuzzy +#| msgid "Invalid time" +msgid "Invalid elliptic curve" +msgstr "Érvénytelen idÅ‘pont" + +#: src/err-codes.h:216 +#, fuzzy +#| msgid "Unknown source" +msgid "Unknown elliptic curve" +msgstr "Ismeretlen forrás" + +#: src/err-codes.h:217 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated key" +msgstr "KettÅ‘zött érték" + +#: src/err-codes.h:218 +#, fuzzy +#| msgid "Ambiguous name" +msgid "Ambiguous result" +msgstr "Nem egyértelmű név" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "" + +#: src/err-codes.h:221 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Bad crypto context" +msgstr "Érvénytelen titkosítási motor" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +#, fuzzy +#| msgid "No public key" +msgid "Broken public key" +msgstr "Nincs nyilvános kulcs" + +#: src/err-codes.h:224 +#, fuzzy +#| msgid "No secret key" +msgid "Broken secret key" +msgstr "Nincs titkos kulcs" + +#: src/err-codes.h:225 +#, fuzzy +#| msgid "Invalid digest algorithm" +msgid "Invalid MAC algorithm" +msgstr "Érvénytelen kivonat algoritmus" + +#: src/err-codes.h:226 +#, fuzzy +#| msgid "Operation cancelled" +msgid "Operation fully cancelled" +msgstr "A művelet megszakítva" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "A művelet még nem fejezÅ‘dött be" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Túl rövid puffer" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Érvénytelen hosszmegadó az S-kifejezésben" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Túl hosszú karakterlánc az S-kifejezésben" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Lezáratlan zárójelek az S-kifejezésben" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "Az S-kifejezés nem hitelesnek elismert" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Rossz karakter az S-kifejezésben" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Rossz idézés az S-kifejezésben" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Nulla elÅ‘tag az S-kifejezésben" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Beágyazott megjelenítési tippek az S-kifejezésben" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Nem egyezÅ‘ megjelenítési tippek" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Váratlan fenntartott központozás az S-kifejezésben" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Rossz hexadecimális karakter az S-kifejezésben" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Páratlan hexadecimális számok az S-kifejezésben" + +#: src/err-codes.h:241 +#, fuzzy +#| msgid "Bad octadecimal character in S-expression" +msgid "Bad octal character in S-expression" +msgstr "Rossz oktadecimális karakter az S-kifejezésben" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Az adatok nincsenek titkosítva" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Ismeretlen név" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Nincs nyilvános kulcs" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Túl rövid puffer" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Túl hosszú sor" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "No certificate chain" +msgstr "Rossz tanúsítványlánc" + +#: src/err-codes.h:252 +#, fuzzy +#| msgid "Certificate too young" +msgid "Certificate is too large" +msgstr "Túl fiatal tanúsítvány" + +#: src/err-codes.h:253 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid record" +msgstr "Érvénytelen kártya" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +#, fuzzy +#| msgid "Unexpected tag" +msgid "Unexpected message" +msgstr "Váratlan címke" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +#, fuzzy +#| msgid "Invalid cipher algorithm" +msgid "No cipher algorithm" +msgstr "Érvénytelen titkosító algoritmus" + +#: src/err-codes.h:260 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing client certificate" +msgstr "Hiányzó tanúsítvány" + +#: src/err-codes.h:261 +#, fuzzy +#| msgid "Certificate revoked" +msgid "Close notification received" +msgstr "Tanúsítvány visszavonva" + +#: src/err-codes.h:262 +#, fuzzy +#| msgid "Key expired" +msgid "Ticket expired" +msgstr "A kulcs lejárt" + +#: src/err-codes.h:263 +#, fuzzy +#| msgid "Bad public key" +msgid "Bad ticket" +msgstr "Rossz nyilvános kulcs" + +#: src/err-codes.h:264 +#, fuzzy +#| msgid "Unknown packet" +msgid "Unknown identity" +msgstr "Ismeretlen csomag" + +#: src/err-codes.h:265 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "Bad certificate message in handshake" +msgstr "Rossz tanúsítványlánc" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +#, fuzzy +#| msgid "Key expired" +msgid "Key disabled" +msgstr "A kulcs lejárt" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +#, fuzzy +#| msgid "Invalid object" +msgid "Invalid lock object" +msgstr "Érvénytelen objektum" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Ãltalános IPC hiba" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Az IPC elfogadási hívás meghiúsult" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Az IPC kapcsolódási hívás meghiúsult" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Érvénytelen IPC válasz" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Érvénytelen érték került átadásra az IPC-nek" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Befejezetlen sor került átadásra az IPC-nek" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Az IPC-nek átadott sor túl hosszú" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Beágyazott IPC parancsok" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Nincs adatvisszahívás az IPC-ben" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Nincs érdeklÅ‘dés visszahívás az IPC-ben" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Nem IPC kiszolgáló" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Nem IPC kliens" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Probléma adódott az IPC kiszolgáló indításakor" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC olvasási hiba" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC írási hiba" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Túl sok adat az IPC réteghez" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Váratlan IPC parancs" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Ismeretlen IPC parancs" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC szintaktikai hiba" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Az IPC hívás megszakításra került" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Nincs bemeneti forrás az IPC-hez" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Nincs kimeneti forrás az IPC-hez" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC paraméterhiba" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Ismeretlen IPC érdeklÅ‘dés" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Crypto engine too old" +msgstr "Érvénytelen titkosítási motor" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "KettÅ‘zött érték" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Túl fiatal tanúsítvány" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "A megadott objektum túl kicsi" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Ismeretlen név" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Érvénytelen műveletkód" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Ismeretlen név" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not locked" +msgid "Not authenticated" +msgstr "Nincs zárolva" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Nem támogatott védelem" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Nincs futó ügynök" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "SmartCard démon hiba" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Kulcskiszolgáló hiba" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Ismeretlen rendszerhiba" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Érvénytelen OID karakterlánc" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Érvénytelen S-kifejezés" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing DNS query packet" +msgstr "Hiányzó tanúsítvány" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Visszafejtés sikertelen" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "IdÅ‘túllépés" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Ãltalános IPC hiba" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Ãltalános hiba" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Ãltalános hiba" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Ãltalános Assuan hiba" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Ãltalános hiba" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Ãltalános Assuan hiba" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "IPC írási hiba" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Ãltalános IPC hiba" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Az IPC kapcsolódási hívás meghiúsult" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Ãltalános hiba" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Kártya visszaállítás szükséges" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Az elem nem található" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Nem támogatott" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Váratlan hiba" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Nem támogatott művelet" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Rossz tanúsítvány" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Ismeretlen kiterjesztés" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "IdÅ‘túllépés" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "dirmngr hiba" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "dirmngr hiba" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "IPC olvasási hiba" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Nem IPC kiszolgáló" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Sikeres" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Beállítási hiba" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Protokollsértés" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Ismeretlen kiterjesztés" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Ãltalános hiba" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Kártya visszaállítás szükséges" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Érvénytelen attribútum" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Nem támogatott védelem" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Protokollsértés" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Érvénytelen állapot" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Nincs CMS objektum" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Hardverprobléma" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Érvénytelen állapot" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Kódolási probléma" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Nem támogatott védelem" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Érvénytelen kártya" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Hiányzó művelet" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Protokollsértés" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "A művelet még nem fejezÅ‘dött be" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "A művelet megszakítva" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Túl hosszú sor" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "A művelet megszakítva" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Ãltalános IPC hiba" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Az erÅ‘források kimerültek" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Protokollsértés" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Érvénytelen állapot" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Nem támogatott tanúsítvány" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Kártya visszaállítás szükséges" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Sikeres" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Nem működik" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Nem működik" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Nem IPC kiszolgáló" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Visszafejtés sikertelen" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "1. felhasználó által megadott hibakód" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "2. felhasználó által megadott hibakód" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "3. felhasználó által megadott hibakód" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "4. felhasználó által megadott hibakód" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "5. felhasználó által megadott hibakód" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "6. felhasználó által megadott hibakód" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "7. felhasználó által megadott hibakód" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "8. felhasználó által megadott hibakód" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "9. felhasználó által megadott hibakód" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "10. felhasználó által megadott hibakód" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "11. felhasználó által megadott hibakód" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "12. felhasználó által megadott hibakód" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "13. felhasználó által megadott hibakód" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "14. felhasználó által megadott hibakód" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "15. felhasználó által megadott hibakód" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "16. felhasználó által megadott hibakód" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Sikeres" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Szintaktikai hiba" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Protokollsértés" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Rendszerhiba w/o hibaszám" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Ismeretlen rendszerhiba" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Fájl vége" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Ismeretlen hibakód" + +#: src/argparse.c:468 +#, fuzzy +msgid "argument not expected" +msgstr "Ãrom a titkos kulcsot a %s állományba.\n" + +#: src/argparse.c:470 +#, fuzzy +msgid "read error" +msgstr "állományolvasási hiba" + +#: src/argparse.c:472 +#, fuzzy +msgid "keyword too long" +msgstr "A sor túl hosszú!\n" + +#: src/argparse.c:474 +#, fuzzy +msgid "missing argument" +msgstr "érvénytelen argumentum" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid armor" +msgid "invalid argument" +msgstr "érvénytelen páncél" + +#: src/argparse.c:478 +#, fuzzy +msgid "invalid command" +msgstr "Egymásnak ellentmondó parancsok!\n" + +#: src/argparse.c:480 +#, fuzzy +msgid "invalid alias definition" +msgstr "Érvénytelen import opciók!\n" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Beállítási hiba" + +#: src/argparse.c:484 src/argparse.c:517 +#, fuzzy +msgid "out of core" +msgstr "nem feldolgozott" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +msgid "invalid meta command" +msgstr "Egymásnak ellentmondó parancsok!\n" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Ismeretlen parancs" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Váratlan IPC parancs" + +#: src/argparse.c:494 +#, fuzzy +msgid "invalid option" +msgstr "Érvénytelen import opciók!\n" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, fuzzy, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "Érvénytelen import opciók!\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, fuzzy, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "Érvénytelen parancs! (Próbálja a súgót: \"help\".)\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "Érvénytelen import opciók!\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "figyelmeztetés: nem sikerült felismerni: %s\n" + +#, fuzzy +#~ msgid "out of core\n" +#~ msgstr "nem feldolgozott" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Használat: %s GPG-ERROR […]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Az erÅ‘források kimerültek" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Érvénytelen adatok" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Ãltalános hiba" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "dirmngr hiba" diff --git a/comm/third_party/libgpg-error/po/insert-header.sin b/comm/third_party/libgpg-error/po/insert-header.sin new file mode 100644 index 0000000000..b26de01f6c --- /dev/null +++ b/comm/third_party/libgpg-error/po/insert-header.sin @@ -0,0 +1,23 @@ +# Sed script that inserts the file called HEADER before the header entry. +# +# At each occurrence of a line starting with "msgid ", we execute the following +# commands. At the first occurrence, insert the file. At the following +# occurrences, do nothing. The distinction between the first and the following +# occurrences is achieved by looking at the hold space. +/^msgid /{ +x +# Test if the hold space is empty. +s/m/m/ +ta +# Yes it was empty. First occurrence. Read the file. +r HEADER +# Output the file's contents by reading the next line. But don't lose the +# current line while doing this. +g +N +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/comm/third_party/libgpg-error/po/it.gmo b/comm/third_party/libgpg-error/po/it.gmo new file mode 100644 index 0000000000..a8b98bdf3a Binary files /dev/null and b/comm/third_party/libgpg-error/po/it.gmo differ diff --git a/comm/third_party/libgpg-error/po/it.po b/comm/third_party/libgpg-error/po/it.po new file mode 100644 index 0000000000..484d496aa7 --- /dev/null +++ b/comm/third_party/libgpg-error/po/it.po @@ -0,0 +1,2198 @@ +# Italian messages for libgpg-error. +# Copyright (C) 2009, 2014 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Francesco Groccia , 2009. +# Milo Casagrande , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:26+0100\n" +"Last-Translator: Milo Casagrande \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Sorgente non specificata" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Qualsiasi fonte" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Fonte 1 definita dall'utente" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Fonte 2 definita dall'utente" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Fonte 3 definita dall'utente" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Fonte 4 definita dall'utente" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Fonte sconosciuta" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Eseguito" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Errore generale" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Pacchetto sconosciuto" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Versione sconosciuta nel pacchetto" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Algoritmo a chiave pubblica non valido" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Algoritmo di digest non valido" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Chiave pubblica errata" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Chiave segreta errata" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Firma digitale errata" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Nessuna chiave pubblica" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Errore nel codice di controllo" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Passphrase errata" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Algoritmo di cifratura non valido" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Apertura del portachiavi" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Pacchetto non valido" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Armatura non valida" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Nessun identificativo utente" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Nessuna chiave segreta" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "È stata usata una chiave segreta errata" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Chiave di sessione errata" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Algoritmo di compressione sconosciuto" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Non è un numero primo" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Metodo di codifica non valido" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Schema di cifratura non valido" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Schema di firma digitale non valido" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Attributo non valido" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Nessun valore" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Non trovato" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Valore non trovato" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Errore di sintassi" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Valore MPI errato" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Passphrase non valida" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Classe di firma non valida" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Risorse esaurite" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Portachiavi non valido" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Errore nel database della fiducia" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Certificato errato" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Identificativo utente non valido" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Errore inaspettato" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Data e ora in conflitto" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Errore del server delle chiavi" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Algoritmo a chiave pubblica errato" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Tributo a D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Chiave di cifratura debole" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Lunghezza chiave non valida" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Argomento non valido" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Errore di sintassi nell'URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "URI non valido" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Errore di rete" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Host sconosciuto" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Autodiagnosi non riuscito" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Dati non cifrati" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Dati non elaborati" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Chiave pubblica non utilizzabile" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Chiave segreta non utilizzabile" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Valore non valido" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Catena del certificato errata" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Certificato mancante" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Dati assenti" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Bug" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Non supportato" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Codice di operazione non valido" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Tempo scaduto" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Errore interno" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Oggetto non valido" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "L'oggetto fornito è troppo piccolo" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "L'oggetto fornito è troppo grande" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Voce mancante nell'oggetto" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Non implementato" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Uso in conflitto" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Modo di cifratura non valido" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Indicatore non valido" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Handle non valido" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Risultato troncato" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Riga incompleta" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Risposta non valida" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Nessun agente in esecuzione" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Errore dell'agente" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Dati non validi" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Fallimento non specificato del server Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Errore generale per Assuan" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Chiave di sessione non valida" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "S-expression non valida" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Algoritmo non supportato" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "pinentry non è installato" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Errore di pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "PIN errato" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Nome non valido" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Dati errati" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Parametro non valido" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Scheda errata" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "dirmngr non è installato" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Errore di dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certificato revocato" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Nessun CRL conosciuto" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL troppo vecchio" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Riga troppo lunga" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Non affidabile" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Operazione annullata" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Certificato CA errato" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certificato scaduto" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certificato troppo nuovo" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Certificato non supportato" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "S-expression sconosciuta" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Protezione non supportata" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Protezione danneggiata" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Nome ambiguo" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Errore della scheda" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "È richiesto il riavvio della scheda" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Scheda rimossa" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Scheda non valida" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Scheda non presente" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Non esiste un'applicazione per PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Non confermato" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Errore di configurazione" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Nessuna politica corrispondente" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Indice non valido" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Identificativo non valido" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Nessun demone per la SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Errore del demone della SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Protocollo non supportato" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Sistema personale di identificazione non valido" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "La scheda non è stata inizializzata" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Operazione non supportata" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Uso errato della chiave" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Non è stato trovato nulla" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Tipo blob errato" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Valore assente" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problema hardware" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN bloccato" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Le condizioni d'uso non sono state soddisfatte" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "I PIN non sono stati sincronizzati" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "CRL non valido" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Errore BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "BER non valido" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Elemento non trovato" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identificatore non trovato" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Etichetta non valida" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Lunghezza non valida" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Informazioni della chiave non valide" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Etichetta inaspettata" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Non è un codificato DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Non esiste alcun oggetto CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Oggetto CMS non valido" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Oggetto CMS sconosciuto" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Oggetto CMS non supportato" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Codifica non supportata" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Versione CMS non supportata" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Algoritmo sconosciuto" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Motore crittografico non valido" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Chiave pubblica non affidabile" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Decifratura non riuscita" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Chiave scaduta" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Firma scaduta" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Problema nella codifica" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Stato non valido" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Valore duplicato" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Azione mancante" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Modulo ASN.1 non trovato" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Testo per l'OID non valido" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Data non valida" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Oggetto CRL non valido" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Versione CRL non supportata" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Certificato dell'oggetto non valido" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nome sconosciuto" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Funzione locale ha fallito" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Non bloccato" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Violazione del protocollo" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "MAC non valido" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Richiesta non valida" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Estensione sconosciuta" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Estensione critica sconosciuta" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Bloccato" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Opzione sconosciuta" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Comando sconosciuto" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Non è in funzione" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Nessuna passphrase fornita" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Nessun PIN fornito" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Disabilitato" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Nessun motore di cifratura" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Chiave mancate" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Troppi oggetti" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Raggiunto limite" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Non inizializzato" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Manca il certificato dell'emittente" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Nessun server di chiavi disponibile" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Curva ellittica non valida" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Curva ellittica sconosciuta" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Chiave duplicata" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Risultato ambiguo" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Nessun contesto di cifratura" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Contesto di cifratura errato" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Contesto di cifratura rovinato" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Conflitto nel contesto di cifratura" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Chiave pubblica danneggiata" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Chiave segreta danneggiata" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Algoritmo MAC non valido" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Operazione annullata completamente" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Operazione non ancora terminata" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffer troppo breve" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Lunghezza dello specificatore in S-expression non valida" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Testo troppo lungo in S-expression" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Parentesi non corrispondenti in S-expression" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-expression non canonica" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Carattere errato in S-expression" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Citazione errata in S-expression" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Prefisso zero in S-expression" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Suggerimenti mostrati nidificati in S-expression" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Suggerimenti mostrati non corrispondenti" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Punteggiatura riservata inaspettata in S-expression" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Carattere esadecimale errato in S-expression" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Numeri esadecimali dispari in S-expression" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Carattere ottale errato in S-expression" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Dati non cifrati" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Nome sconosciuto" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Nessuna chiave pubblica" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Buffer troppo breve" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Riga troppo lunga" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Nessuna catena di certificazione" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Il certificato è troppo grande" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Record non valido" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "Impossibile verificare il MAC" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Messaggio inaspettato" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Compressione o estrazione non riuscita" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Un contatore si azzererebbe (troppi messaggi...)" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Ricevuto un messaggio di avviso fatale" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Nessun algoritmo di cifratura" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Certificato client mancante" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Ricevuta notifica di chiusura" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Ticket scaduto" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Ticket errato" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Identità sconosciuta" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Messaggio del certificato errato nell'handshake" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Messaggio di richiesta del certificato errato nell'handshake" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Messaggio di verifica del certificato errato nell'handshake" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Messaggi di modifica cifrario errato nell'handshake" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Messaggio client hello errato nell'handshake" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Messaggio server hello errato nell'handshake" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Messaggio server hello completato errato nell'handshake" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Messaggio completato errato nell'handshake" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Messaggio server scambio di chiavi errato nell'handshake" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Messaggio client scambio di chiavi errato nell'handshake" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Stringa fasulla" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Chiave disabilitata" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Non possibile con una chiave su scheda" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Oggetto di blocco non valido" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Errore IPC generale" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Chiamata \"accept\" IPC non riuscita" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Chiamata \"connect\" IPC non riuscita" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Risposta IPC non valida" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Valore non valido passato a IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Riga incompleta passata a IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Riga passata a IPC troppo lunga" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Comandi IPC nidificati" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Nessun callback \"data\" in IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Nessun callback \"inquire\" in IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Non è un server IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Non è un client IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problema nell'avviare il server IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Errore di lettura IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Errore di scrittura IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Troppi dati per il livello IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Comando IPC inaspettato" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Comando IPC sconosciuto" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Errore di sintassi IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "La chiamata IPC è stata annullata" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Nessuna sorgente in entrata per IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Nessuna sorgente in uscita per IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Errore per il parametro IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Richiesta IPC sconosciuta" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "No crypto engine" +msgid "Crypto engine too old" +msgstr "Nessun motore di cifratura" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Valore duplicato" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certificato troppo nuovo" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "L'oggetto fornito è troppo piccolo" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Nome sconosciuto" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Codice di operazione non valido" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Nome sconosciuto" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Disabilitato" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Protezione non supportata" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Nessun agente in esecuzione" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Errore del demone della SmartCard" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Errore del server delle chiavi" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Errore di sistema sconosciuto" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Testo per l'OID non valido" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "S-expression non valida" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing issuer certificate" +msgid "Missing DNS query packet" +msgstr "Manca il certificato dell'emittente" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Decifratura non riuscita" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Tempo scaduto" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Errore IPC generale" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Errore generale" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Errore generale" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Errore generale per Assuan" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Errore generale" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Errore generale per Assuan" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Errore di scrittura IPC" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Errore IPC generale" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Chiamata \"connect\" IPC non riuscita" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Errore generale" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "È richiesto il riavvio della scheda" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Elemento non trovato" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Non supportato" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Errore inaspettato" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Operazione non supportata" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Certificato errato" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Estensione sconosciuta" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Tempo scaduto" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "Errore di dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "Errore di dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Errore di lettura IPC" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Non è un server IPC" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Eseguito" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Errore di configurazione" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Violazione del protocollo" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Estensione sconosciuta" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +#, fuzzy +#| msgid "Fatal alert message received" +msgid "Partial LDAP results+referral received" +msgstr "Ricevuto un messaggio di avviso fatale" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Errore generale" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "È richiesto il riavvio della scheda" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Attributo non valido" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Protezione non supportata" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Violazione del protocollo" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Stato non valido" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Non esiste alcun oggetto CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Problema hardware" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Stato non valido" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Problema nella codifica" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Protezione non supportata" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Scheda non valida" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +#, fuzzy +#| msgid "No keyserver available" +msgid "LDAP server is unavailable" +msgstr "Nessun server di chiavi disponibile" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Azione mancante" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Violazione del protocollo" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Operazione non ancora terminata" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Operazione annullata" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Riga troppo lunga" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Operazione annullata" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Errore IPC generale" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Risorse esaurite" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Violazione del protocollo" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Stato non valido" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Certificato non supportato" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "È richiesto il riavvio della scheda" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Eseguito" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Non è in funzione" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Non è in funzione" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Non è un server IPC" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Decifratura non riuscita" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Codice errore 1 definito dall'utente" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Codice errore 2 definito dall'utente" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Codice errore 3 definito dall'utente" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Codice errore 4 definito dall'utente" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Codice errore 5 definito dall'utente" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Codice errore 6 definito dall'utente" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Codice errore 7 definito dall'utente" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Codice errore 8 definito dall'utente" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Codice errore 9 definito dall'utente" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Codice errore 10 definito dall'utente" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Codice errore 11 definito dall'utente" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Codice errore 12 definito dall'utente" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Codice errore 13 definito dall'utente" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Codice errore 14 definito dall'utente" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Codice errore 15 definito dall'utente" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Codice errore 16 definito dall'utente" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Eseguito" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Errore di sintassi" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Violazione del protocollo" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Errore di sistema senza errno" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Errore di sistema sconosciuto" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Fine del file" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Codice di errore sconosciuto" + +#: src/argparse.c:468 +#, fuzzy +msgid "argument not expected" +msgstr "scrittura della chiave segreta in `%s'\n" + +#: src/argparse.c:470 +#, fuzzy +msgid "read error" +msgstr "errore durante la lettura del file" + +#: src/argparse.c:472 +#, fuzzy +msgid "keyword too long" +msgstr "riga troppo lunga\n" + +#: src/argparse.c:474 +#, fuzzy +msgid "missing argument" +msgstr "argomento non valido" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid armor" +msgid "invalid argument" +msgstr "armatura non valida" + +#: src/argparse.c:478 +#, fuzzy +msgid "invalid command" +msgstr "comandi in conflitto\n" + +#: src/argparse.c:480 +#, fuzzy +msgid "invalid alias definition" +msgstr "opzioni di importazione non valide\n" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Errore di configurazione" + +# ??? (Md) +#: src/argparse.c:484 src/argparse.c:517 +#, fuzzy +msgid "out of core" +msgstr "non esaminato" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +msgid "invalid meta command" +msgstr "comandi in conflitto\n" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Comando sconosciuto" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Comando IPC inaspettato" + +#: src/argparse.c:494 +#, fuzzy +msgid "invalid option" +msgstr "opzioni di importazione non valide\n" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, fuzzy, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "opzioni di importazione non valide\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, fuzzy, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "Comando non valido (prova \"help\")\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "opzioni di importazione non valide\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "avviso: impossibile riconoscere %s\n" + +# ??? (Md) +#, fuzzy +#~ msgid "out of core\n" +#~ msgstr "non esaminato" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Uso: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Risorse esaurite" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Dati non validi" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Errore generale" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "Errore di dirmngr" diff --git a/comm/third_party/libgpg-error/po/ja.gmo b/comm/third_party/libgpg-error/po/ja.gmo new file mode 100644 index 0000000000..53242d671c Binary files /dev/null and b/comm/third_party/libgpg-error/po/ja.gmo differ diff --git a/comm/third_party/libgpg-error/po/ja.po b/comm/third_party/libgpg-error/po/ja.po new file mode 100644 index 0000000000..9aa0f90d1d --- /dev/null +++ b/comm/third_party/libgpg-error/po/ja.po @@ -0,0 +1,1996 @@ +# Japanese messages for GnuPG libgpg-error +# Copyright (C) 2010, 2012, 2014, 2015, 2016 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Yasuaki Taniguchi , 2010. +# Takeshi Hamasaki , 2012. +# NIIBE Yutaka , 2014, 2015, 2016, 2017, 2019, 2020. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.39\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:26+0100\n" +"Last-Translator: NIIBE Yutaka \n" +"Language-Team: none\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "指定ã•ã‚Œã¦ã„ãªã„ソース" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "指定ãªã—ã®ã‚½ãƒ¼ã‚¹" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "ユーザ定義ソース 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "ユーザ定義ソース 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "ユーザ定義ソース 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "ユーザ定義ソース 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "ä¸æ˜Žãªã‚½ãƒ¼ã‚¹" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "æˆåŠŸã§ã™" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "一般エラーã§ã™" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "ä¸æ˜Žãªãƒ‘ケットã§ã™" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "パケット内ã®ä¸æ˜Žãªãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "無効ãªå…¬é–‹éµã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ã§ã™" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "無効ãªãƒ€ã‚¤ã‚¸ã‚§ã‚¹ãƒˆãƒ»ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ã§ã™" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "誤ã£ãŸå…¬é–‹éµã§ã™" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "誤ã£ãŸç§˜å¯†éµã§ã™" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "誤ã£ãŸç½²åã§ã™" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "公開éµãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "ãƒã‚§ãƒƒã‚¯ã‚µãƒ ã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "誤ã£ãŸãƒ‘スフレーズã§ã™" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "無効ãªæš—å·ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ã§ã™" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "éµãƒªãƒ³ã‚°ãŒé–‹ã‘ã¾ã›ã‚“" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "無効ãªãƒ‘ケットã§ã™" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "無効ãªã‚¢ã‚¹ã‚­ãƒ¼ä¿è­·å½¢å¼ã§ã™" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "ユーザ ID ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "秘密éµãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "é–“é•ã£ãŸç§˜å¯†éµãŒä½¿ç”¨ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "誤ã£ãŸã‚»ãƒƒã‚·ãƒ§ãƒ³éµã§ã™" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "ä¸æ˜Žãªåœ§ç¸®ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ã§ã™" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "æ•°ãŒç´ æ•°ã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "無効ãªç¬¦å·åŒ–方法ã§ã™" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "無効ãªæš—å·ç³»ã§ã™" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "無効ãªç½²åç³»ã§ã™" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "無効ãªå±žæ€§ã§ã™" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "値ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "見ã¤ã‹ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "値ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "構文エラーã§ã™" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "誤ã£ãŸ MPI ã®å€¤ã§ã™" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "無効ãªãƒ‘スフレーズã§ã™" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "無効ãªç½²åクラスã§ã™" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "資æºã‚’使ã„æžœãŸã—ã¾ã—ãŸ" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "無効ãªéµãƒªãƒ³ã‚°ã§ã™" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "信用 DB エラーã§ã™" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "誤ã£ãŸè¨¼æ˜Žæ›¸ã§ã™" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "無効ãªãƒ¦ãƒ¼ã‚¶ ID ã§ã™" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "予期ã—ãªã„エラーã§ã™" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "時間ã®ä¸ä¸€è‡´ã§ã™" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "éµã‚µãƒ¼ãƒãƒ¼ã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "誤ã£ãŸå…¬é–‹éµã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ã§ã™" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "ダグラス・アダムスã«æ§ã" + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "å¼±ã„æš—å·éµã§ã™" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "無効ãªéµé•·ã§ã™" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "無効ãªå¼•æ•°ã§ã™" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "URIã®æ§‹æ–‡ã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "無効㪠URI ã§ã™" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "ä¸æ˜Žãªãƒ›ã‚¹ãƒˆã§ã™" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "セルフテストã«å¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "データã¯æš—å·åŒ–ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "データã¯å‡¦ç†ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "使用ã§ããªã„公開éµã§ã™" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "使用ã§ããªã„秘密éµã§ã™" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "無効ãªå€¤ã§ã™" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "誤ã£ãŸè¨¼æ˜Žæ›¸é€£éŽ–ã§ã™" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "証明書ãŒæ¬ å¦‚ã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "データãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "ãƒã‚°ã§ã™" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "無効ãªæ“作コードã§ã™" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "タイムアウトã§ã™" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "内部エラーã§ã™" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)ã§ã™" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "無効ãªã‚ªãƒ–ジェクトã§ã™" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "与ãˆã‚‰ã‚ŒãŸã‚ªãƒ–ジェクトãŒå°ã•ã™ãŽã¾ã™" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "与ãˆã‚‰ã‚ŒãŸã‚ªãƒ–ジェクトãŒå¤§ãã™ãŽã¾ã™" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "オブジェクト内ã«é …ç›®ãŒæ¬ å¦‚ã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "実装ã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "対立ã™ã‚‹ä½¿ç”¨ã§ã™" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "無効ãªæš—å·ãƒ¢ãƒ¼ãƒ‰ã§ã™" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "無効ãªãƒ•ãƒ©ã‚°ã§ã™" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "無効ãªãƒãƒ³ãƒ‰ãƒ«ã§ã™" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "çµæžœãŒåˆ‡ã‚Šè©°ã‚られã¾ã—ãŸ" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "ä¸å®Œå…¨ãªè¡Œã§ã™" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "無効ãªå¿œç­”ã§ã™" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "エージェントãŒå‹•ã„ã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "エージェントエラーã§ã™" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "無効ãªãƒ‡ãƒ¼ã‚¿ã§ã™" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "ä¸ç‰¹å®šãª Assuan サーãƒå¤±æ•—ã§ã™" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "一般Assuan エラーã§ã™" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "無効ãªã‚»ãƒƒã‚·ãƒ§ãƒ³éµã§ã™" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "無効㪠S-å¼ã§ã™" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„アルゴリズムã§ã™" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "PinentryãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Pinentryエラー" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "誤ã£ãŸ PIN ã§ã™" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "無効ãªåå‰ã§ã™" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "誤ã£ãŸãƒ‡ãƒ¼ã‚¿ã§ã™" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "無効ãªãƒ‘ラメータã§ã™" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "誤ã£ãŸã‚«ãƒ¼ãƒ‰ã§ã™" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "dirmngrãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr ã®ã‚¨ãƒ©ãƒ¼" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "証明書ãŒå»ƒæ­¢ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "既知㮠CRL ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL ãŒå¤ã™ãŽã¾ã™" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "è¡ŒãŒé•·ã™ãŽã¾ã™" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "信用ã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "æ“作ãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "誤ã£ãŸ CA 証明書ã§ã™" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "証明書ãŒæœŸé™åˆ‡ã‚Œã§ã™" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "証明書ãŒè‹¥ã™ãŽã¾ã™" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„証明書ã§ã™" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "ä¸æ˜Žãª S-å¼ã§ã™" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„防護ã§ã™" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "ç ´æã—ãŸé˜²è­·ã§ã™" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "曖昧ãªåå‰ã§ã™" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "カードエラー" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "カードリセットãŒå¿…è¦ã§ã™" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "カードãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "無効ãªã‚«ãƒ¼ãƒ‰ã§ã™" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "カードãŒå­˜åœ¨ã—ã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "PKCS15 アプリケーションãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "確èªã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "設定ã®ã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "一致ã™ã‚‹ãƒãƒªã‚·ãƒ¼ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "無効ãªç´¢å¼•ã§ã™" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "無効㪠ID ã§ã™" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "スマートカードデーモンãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "スマートカードデーモンエラーã§ã™" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„プロトコルã§ã™" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "誤ã£ãŸ PIN 方法ã§ã™" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "カードãŒåˆæœŸåŒ–ã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„æ“作ã§ã™" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "誤ã£ãŸéµã®ä½¿ç”¨æ³•ã§ã™" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "見ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "誤ã£ãŸ blog åž‹ã§ã™" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "値ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®å•é¡Œã§ã™" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN ãŒãƒ–ロックã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "使用æ¡ä»¶ãŒæº€ãŸã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN ãŒåŒæœŸã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "無効㪠CRL ã§ã™" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER エラーã§ã™" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "無効㪠BER ã§ã™" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "è¦ç´ ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "識別å­ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "無効ãªã‚¿ã‚°ã§ã™" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "無効ãªé•·ã•ã§ã™" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "無効ãªéµæƒ…å ±ã§ã™" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "予期ã—ãªã„ã‚¿ã‚°ã§ã™" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "DER 符å·åŒ–ã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "CMS オブジェクトã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "無効㪠CMS オブジェクトã§ã™" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "ä¸æ˜Žãª CMS オブジェクトã§ã™" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ CMS オブジェクトã§ã™" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„符å·åŒ–ã§ã™" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ CMS ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "ä¸æ˜Žãªã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ã§ã™" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "無効ãªæš—å·ã‚¨ãƒ³ã‚¸ãƒ³ã§ã™" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "信用ã•ã‚Œã¦ã„ãªã„公開éµã§ã™" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "復å·ã«å¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "éµãŒæœŸé™åˆ‡ã‚Œã§ã™" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "ç½²åãŒæœŸé™åˆ‡ã‚Œã§ã™" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "符å·åŒ–ã«å•é¡ŒãŒã‚ã‚Šã¾ã™" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "無効ãªçŠ¶æ…‹ã§ã™" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "é‡è¤‡ã—ãŸå€¤ã§ã™" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "アクションãŒæ¬ å¦‚ã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ASN.1 モジュールãŒã¿ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "無効㪠OID 文字列ã§ã™" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "無効ãªæ™‚é–“ã§ã™" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "無効㪠CRL オブジェクトã§ã™" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ CRL ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "無効ãªè¨¼æ˜Žæ›¸ã‚ªãƒ–ジェクトã§ã™" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "ä¸æ˜Žãªåå‰ã§ã™" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "ロケール関数 失敗" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "ロックã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "プロトコルé•å" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "無効㪠MACã§ã™" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "無効ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "未知ã®æ‹¡å¼µå­" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "ä¸æ˜Žã®ã‚¯ãƒªãƒã‚«ãƒ«æ‹¡å¼µã§ã™" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "ロックã•ã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "未知ã®ã‚ªãƒ—ションã§ã™" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "未知ã®ã‚³ãƒžãƒ³ãƒ‰ã§ã™" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "æ“作ã§ãã¾ã›ã‚“" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "パスフレーズãŒä¸Žãˆã‚‰ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "PINãŒä¸Žãˆã‚‰ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "有効ã¨ãªã£ã¦ã¾ã›ã‚“" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "æš—å·ã‚¨ãƒ³ã‚¸ãƒ³ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "éµãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "オブジェクトãŒå¤šã™ãŽã¾ã™" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "é™ç•Œã«é”ã—ã¾ã—ãŸ" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "åˆæœŸåŒ–ã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "発行元証明書ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "キーサーãƒãŒåˆ©ç”¨å¯èƒ½ã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "無効ãªæ¥•å††é–¢æ•°ã§ã™" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "ä¸æ˜Žã®æ¥•å††é–¢æ•°ã§ã™" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "é‡è¤‡ã—ãŸéµã§ã™" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "曖昧ãªçµæžœã§ã™" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "æš—å·ã‚³ãƒ³ãƒ†ã‚¯ã‚¹ãƒˆãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "誤ã£ãŸæš—å·ã‚³ãƒ³ãƒ†ã‚¯ã‚¹ãƒˆã§ã™" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "誤ã£ãŸæš—å·ã‚³ãƒ³ãƒ†ã‚¯ã‚¹ãƒˆã§ã™" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "æš—å·ã‚³ãƒ³ãƒ†ã‚¯ã‚¹ãƒˆãŒç«¶åˆã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "公開éµãŒå£Šã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "秘密éµãŒå£Šã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "無効ãªMACアルゴリズムã§ã™" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "æ“作ãŒå®Œå…¨ã«ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "æ“作ãŒã¾ã çµ‚了ã—ã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "ãƒãƒƒãƒ•ã‚¡ãŒçŸ­ã™ãŽã¾ã™" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Så¼ã®ä¸­ã®é•·ã•æŒ‡å®šãŒç„¡åŠ¹ã§ã™" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Så¼ã®ä¸­ã®æ–‡å­—列ãŒé•·ã™ãŽã¾ã™" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Så¼ã®æ‹¬å¼§ãŒä¸€è‡´ã—ã¾ã›ã‚“" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "カノニカルãªSå¼ã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Så¼ã«èª¤ã£ãŸã‚­ãƒ£ãƒ©ã‚¯ã‚¿ãŒã‚ã‚Šã¾ã™" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Så¼ã®èª¤ã£ãŸã‚¯ã‚ªãƒ¼ãƒ†ãƒ¼ã‚·ãƒ§ãƒ³ã§ã™" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Så¼ã®ã‚¼ãƒ­ãƒ»ãƒ—レフィックスã§ã™" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Så¼ã«è¡¨ç¤ºãƒ’ントãŒå…¥ã‚Œå­ã«ãªã£ã¦ã„ã¾ã™" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "表示ヒントãŒä¸€è‡´ã—ã¾ã›ã‚“" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Så¼ã«äºˆæœŸã—ãªã„予約ã•ã‚ŒãŸå¥èª­ç‚¹ãŒã‚ã‚Šã¾ã™" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Så¼ã«é–“é•ã£ãŸ16進キャラクタãŒã‚ã‚Šã¾ã™" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Så¼ã«ãŠã‹ã—ãª16進キャラクタãŒã‚ã‚Šã¾ã™" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Så¼ã«é–“é•ã£ãŸ8進キャラクタãŒã‚ã‚Šã¾ã™" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "ã™ã¹ã¦ã®å‰¯éµãŒæœŸé™åˆ‡ã‚Œã‹å¤±åŠ¹ã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "データベースãŒãŠã‹ã—ããªã£ã¦ã¾ã™" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "サーãƒãŒå¤±æ•—を示ã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "åå‰ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "éµãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "レガシーãªéµ" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "リクエストãŒçŸ­ã™ãŽã¾ã™" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "リクエストãŒé•·ã™ãŽã¾ã™" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "オブジェクトã¯çµ‚了状態ã§ã™" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "証明書連鎖ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "証明書ãŒå¤§ãã™ãŽã§ã™" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "無効ãªãƒ¬ã‚³ãƒ¼ãƒ‰ã§ã™" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "MACãŒæ¤œè¨¼ã§ãã¾ã›ã‚“" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "予期ã—ãªã„メッセージã§ã™" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "圧縮/伸長ãŒå¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "カウンタãŒä¸€å›žã‚Šã™ã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "致命的ãªè­¦å‘Šãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’å—ä¿¡ã—ã¾ã—ãŸ" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "æš—å·ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "クライアント証明書ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "クローズã®çŸ¥ã‚‰ã›ã‚’å—ä¿¡ã—ã¾ã—ãŸ" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "ãƒã‚±ãƒƒãƒˆãŒæœŸé™åˆ‡ã‚Œã§ã™" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "誤ã£ãŸãƒã‚±ãƒƒãƒˆã§ã™" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "ä¸æ˜Žãªã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ãƒ†ã‚£ã§ã™" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸè¨¼æ˜Žæ›¸ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸè¨¼æ˜Žæ›¸è¦æ±‚メッセージã§ã™" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸè¨¼æ˜Žæ›¸æ¤œè¨¼ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸæš—å·å¤‰æ›´ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãƒãƒ­ãƒ¼ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸã‚µãƒ¼ãƒãƒãƒ­ãƒ¼ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸã‚µãƒ¼ãƒãƒãƒ­ãƒ¼äº†è§£ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸçµ‚了メッセージã§ã™" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸã‚µãƒ¼ãƒéµäº¤æ›ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "ãƒãƒ³ãƒ‰ã‚·ã‚§ãƒ¼ã‚¯ã§èª¤ã£ãŸã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆéµäº¤æ›ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "ãŠã‹ã—ãªæ–‡å­—列ã§ã™" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "ç¦æ­¢" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "éµãŒåœæ­¢ã•ã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "カードã®éµã§ã¯ä¸å¯èƒ½ã§ã™" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "無効ãªãƒ­ãƒƒã‚¯ãƒ»ã‚ªãƒ–ジェクトã§ã™" + +#: src/err-codes.h:280 +msgid "True" +msgstr "真" + +#: src/err-codes.h:281 +msgid "False" +msgstr "å½" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "一般IPCエラーã§ã™" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC accept呼ã³å‡ºã—ã«å¤±æ•—" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC connect呼ã³å‡ºã—ã«å¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "無効ãªIPC応答ã§ã™" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "無効ãªå€¤ãŒIPCã«æ¸¡ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "ä¸å®Œå…¨ãªè¡ŒãŒIPCã«æ¸¡ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "IPCã«æ¸¡ã•ã‚ŒãŸè¡ŒãŒé•·ã™ãŽã¾ã™" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "IPCコマンドãŒå…¥ã‚Œå­ã«ãªã£ã¦ã„ã¾ã™" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "IPCã§ãƒ‡ãƒ¼ã‚¿ã®ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "IPCã§å•ã„åˆã‚ã›ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "IPCサーãƒã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "IPCクライアントã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "IPCサーãƒã®é–‹å§‹ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC読ã¿å–りエラー" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC書ãè¾¼ã¿ã‚¨ãƒ©ãƒ¼" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "IPCレイヤã«ãƒ‡ãƒ¼ã‚¿ãŒå¤šã™ãŽã§ã™" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "予期ã—ãªã„IPCコマンドã§ã™" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "ä¸æ˜ŽãªIPCコマンドã§ã™" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC構文エラーã§ã™" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC呼ã³å‡ºã—ãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "IPCã«å¯¾ã™ã‚‹å…¥åŠ›ã‚½ãƒ¼ã‚¹ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "IPCã«å¯¾ã™ã‚‹å‡ºåŠ›ã‚½ãƒ¼ã‚¹ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPCパラメータエラーã§ã™" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "ä¸æ˜ŽãªIPCå•ã„åˆã‚ã›ã§ã™" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "æš—å·ã‚¨ãƒ³ã‚¸ãƒ³ãŒå¤ã™ãŽã¾ã™" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "スクリーンã¾ãŸã¯ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒå°ã•ã™ãŽã¾ã™" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "スクリーンã¾ãŸã¯ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒå¤§ãã™ãŽã¾ã™" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "å¿…è¦ãªç’°å¢ƒå¤‰æ•°ãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "User IDãŒæ—¢ã«å­˜åœ¨ã—ã¾ã™" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "åå‰ãŒæ—¢ã«å­˜åœ¨ã—ã¾ã™" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "é‡è¤‡ã—ãŸåå‰ã§ã™" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "オブジェクトãŒè‹¥ã™ãŽã¾ã™" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "オブジェクトãŒå¤ã™ãŽã¾ã™" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "ä¸æ˜Žãªãƒ•ãƒ©ã‚°ã§ã™" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "無効ãªå®ŸåŠ¹é †ã§ã™" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "ã™ã§ã«ãƒ•ã‚§ãƒƒãƒã•ã‚Œã¦ã¾ã™" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "後ã§å†åº¦è©¦ã—ã¦ãã ã•ã„" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "é–“é•ã£ãŸåå‰ã§ã™" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "èªè¨¼ã•ã‚Œã¦ã¾ã›ã‚“" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "誤ã£ãŸèªè¨¼ã§ã™" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "KeyboxデーモンãŒå‹•ã„ã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "Keyboxデーモンエラーã§ã™" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "サービスãŒå‹•ã„ã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "サービスエラーã§ã™" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "システムã®ãƒã‚°ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "ä¸æ˜ŽãªDNSエラー" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "無効㪠DNS セクションã§ã™" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "無効ãªãƒ†ã‚¯ã‚¹ãƒˆã®ã‚¢ãƒ‰ãƒ¬ã‚¹å½¢å¼ã§ã™" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "DNSクエリã®ãƒ‘ケットãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "DNSã®è¿”答パケットãŒæ¬ å¦‚ã—ã¦ã„ã¾ã™" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "DNSã®æŽ¥ç¶šãŒé–‰ã˜ã‚‰ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "DNSã§æ¤œè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "DNSタイムアウトã§ã™" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "一般LDAPエラーã§ã™" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "一般LDAP属性エラーã§ã™" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "一般LDAPエラーã§ã™" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "一般Assuanエラーã§ã™" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "一般LDAPサーãƒã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "一般LDAP更新エラーã§ã™" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "実験的LDAPエラーコード" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "プライベートLDAPエラーコード" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "ãã®ä»–ã®ä¸€èˆ¬LDAPエラーã§ã™" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "LDAP接続ãŒå¤±æ•—ã—ã¾ã—㟠(X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "LDAPå‚照制é™ã‚’越ãˆã¾ã—ãŸ" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "LDAPクライアントã®ãƒ«ãƒ¼ãƒ—" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "LDAPã®çµæžœãŒè¿”ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "LDAP制御ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "LDAPã§ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "LDAP connectエラーã§ã™" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "LDAPã§ãƒ¡ãƒ¢ãƒªãŒãªããªã‚Šã¾ã—ãŸ" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "LDAPルーãƒãƒ³ã«å¯¾ã™ã‚‹ä¸æ­£ãªãƒ‘ラメータã§ã™" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "ユーザãŒLDAPæ“作をキャンセルã—ã¾ã—ãŸ" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "誤ã£ãŸLDAP検索フィルタã§ã™" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "ä¸æ˜Žã®LDAPèªè¨¼æ–¹å¼ã§ã™" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "LDAPã§ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã§ã™" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "LDAPデコードã®ã‚¨ãƒ©ãƒ¼" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "LDAPエンコードã®ã‚¨ãƒ©ãƒ¼" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "LDAPローカルエラー" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "LDAPサーãƒã«é€£çµ¡ã§ãã¾ã›ã‚“" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "LDAPæˆåŠŸã§ã™" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "LDAPæ“作エラーã§ã™" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "LDAPプロトコルエラー" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "LDAPã§æ™‚間制é™ã‚’越ãˆã¾ã—ãŸ" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "LDAPã§ã‚µã‚¤ã‚ºåˆ¶é™ã‚’越ãˆã¾ã—ãŸ" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "LDAP比較 å½" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "LDAP比較 真" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "LDAPèªè¨¼æ–¹å¼ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "å¼·ã„LDAPèªè¨¼ãŒå¿…è¦ã§ã™" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "部分的LDAPçµæžœ/å‚照をå—ä¿¡ã—ã¾ã—ãŸ" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "LDAPå‚ç…§" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "管ç†LDAP制é™ã‚’越ãˆã¾ã—ãŸ" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "クリティカルãªLDAPæ‹¡å¼µãŒåˆ©ç”¨å¯èƒ½ã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "LDAPã«ã‚ˆã‚Šç§˜åŒ¿æ€§ãŒå¿…è¦ã§ã™" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "LDAP SASLãƒã‚¤ãƒ³ãƒ‰ãŒé€²ã‚“ã§ã„ã¾ã™" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "ãã®ã‚ˆã†ãªLDAP属性ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "未定義ã®LDAP属性型ã§ã™" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "LDAPã®ä¸é©åˆ‡ãªãƒžãƒƒãƒãƒ³ã‚°ã§ã™" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "LDAP制約é•åã§ã™" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "LDAPåž‹ã‚ã‚‹ã„ã¯å€¤ãŒå­˜åœ¨ã—ã¾ã™" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "LDAPã®ç„¡åŠ¹ãªæ§‹æ–‡ã§ã™" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "ãã®ã‚ˆã†ãªLDAPオブジェクトã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "LDAPエイリアスã®å•é¡Œã§ã™" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "LDAPã®ç„¡åŠ¹ãªDN構文状態ã§ã™" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "LDAPエントリãŒãƒªãƒ¼ãƒ•ã§ã™" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "LDAPエイリアスã®ãƒ‡ãƒ¬ãƒ•ã‚¡ãƒ¬ãƒ³ã‚¹å•é¡Œã§ã™" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "LDAPプロキシã®èªè¨¼å¤±æ•—ã§ã™(X)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "ä¸é©åˆ‡ãªLDAPèªè¨¼ã§ã™" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "無効ãªLDAPクレデンシャルã§ã™" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "LDAPã®ä¸å分ãªã‚¢ã‚¯ã‚»ã‚¹ã§ã™" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "LDAPサーãƒãŒãƒ“ジーã§ã™" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "LDAPサーãƒãŒåˆ©ç”¨å¯èƒ½ã§ã¯ã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "LDAPサーãƒãŒå®Ÿè¡Œã‚’進ã‚ãŸãã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "LDAPã§ãƒ«ãƒ¼ãƒ—ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "LDAPåå‰é•åã§ã™" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "LDAPオブジェクトクラスé•åã§ã™" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "LDAPæ“作ã¯éžãƒªãƒ¼ãƒ•ã«ã¯è¨±ã•ã‚Œã¾ã›ã‚“" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "LDAPæ“作ã¯RDNã«ã¯è¨±ã•ã‚Œã¾ã›ã‚“" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "æ—¢ã«å­˜åœ¨ã—ã¾ã™ (LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "LDAPオブジェクト・クラスを修正ã§ãã¾ã›ã‚“" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "LDAPçµæžœãŒå¤§ãã™ãŽã¾ã™" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "LDAPæ“作ã¯è¤‡æ•°ã®DSAã«é–¢ä¸Žã—ã¾ã™" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "ãƒãƒ¼ãƒãƒ£ãƒ«LDAPリストviewエラー" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "ãã®ä»–ã®LDAPエラーã§ã™" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "LCUPã§è³‡æºã‚’使ã„æžœãŸã—ã¾ã—ãŸ" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "LCUPã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£é•å" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "LCUPã®ç„¡åŠ¹ãªãƒ‡ãƒ¼ã‚¿ã§ã™" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "LCUPã®ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„スキームã§ã™" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "LCUPã§ãƒªãƒ­ãƒ¼ãƒ‰ãŒå¿…è¦ã§ã™" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAPãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "キャンセルã™ã‚‹LDAPæ“作ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "LDAPをキャンセルã™ã‚‹ã«ã¯é…ã™ãŽã¾ã™" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "LDAPをキャンセルã§ãã¾ã›ã‚“" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "LDAPアサーションã«å¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "LDAPã§ãƒ—ロキシã®èªè¨¼ãŒæ‹’å¦ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "ユーザ定義エラーコード 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "ユーザ定義エラーコード 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "ユーザ定義エラーコード 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "ユーザ定義エラーコード 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "ユーザ定義エラーコード 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "ユーザ定義エラーコード 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "ユーザ定義エラーコード 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "ユーザ定義エラーコード 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "ユーザ定義エラーコード 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "ユーザ定義エラーコード 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "ユーザ定義エラーコード 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "ユーザ定義エラーコード 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "ユーザ定義エラーコード 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "ユーザ定義エラーコード 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "ユーザ定義エラーコード 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "ユーザ定義エラーコード 16" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "SQL æˆåŠŸã§ã™" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "SQLエラーã§ã™" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "SQLライブラリã®å†…部論ç†ã‚¨ãƒ©ãƒ¼" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "アクセス許å¯ãŒæ‹’å¦ã•ã‚Œã¾ã—㟠(SQL)" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "SQL中止ãŒè¦æ±‚ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "SQLデータベースãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "データベースã§SQLテーブルãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "SQLライブラリãŒã‚³ã‚¢ã‚’使ã„æžœãŸã—ã¾ã—ãŸ" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "読ã¿å‡ºã—ã®ã¿ã®SQLデータベースã«æ›¸ã込もã†ã¨ã—ã¾ã—ãŸ" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "割り込ã¿ã§SQLæ“作ãŒçµ‚了ã—ã¾ã—ãŸ" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "SQLæ“作中ã«I/Oエラー" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "SQLデータベースã®ãƒ‡ã‚£ã‚¹ã‚¯ã‚¤ãƒ¡ãƒ¼ã‚¸ãŒå£Šã‚Œã¦ã„ã¾ã™" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "SQLファイルコントロールã«ä¸æ˜Žã®ã‚ªãƒšã‚³ãƒ¼ãƒ‰ã§ã™" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "SQLデータベースãŒã„ã£ã±ã„ã§æŒ¿å…¥ãŒå¤±æ•—ã—ã¾ã—ãŸ" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "SQLデータベースをオープンã§ãã¾ã›ã‚“" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "SQLデータベース・ロック・プロトコルエラー" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "(内部SQLコード: empty)" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "SQLデータベースã®ã‚¹ã‚­ãƒ¼ãƒžãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "文字列ã‹ãƒ–ロブãŒã‚µã‚¤ã‚ºä¸Šé™ã‚’超ãˆã¾ã—㟠(SQL)" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "制約ã®é•åã®ãŸã‚ SQL 中止ã§ã™" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "データ型ã®ä¸ä¸€è‡´ (SQL)" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "SQLライブラリãŒèª¤ã£ã¦ä½¿ã‚ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "SQLライブラリãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„OSã®æ©Ÿèƒ½ã‚’使ã„ã¾ã™" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "èªè¨¼ãŒæ‹’å¦ã•ã‚Œã¾ã—㟠(SQL)" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "(使ã‚ã‚Œã¦ã„ãªã„SQLコード: format)" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "SQLã®ãƒã‚¤ãƒ³ãƒ‰ãƒ»ãƒ‘ラメータãŒç¯„囲外ã§ã™" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "SQLデータベース・ファイルã§ã¯ãªã„ファイルãŒã‚ªãƒ¼ãƒ—ンã•ã‚Œã¾ã—ãŸ" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "SQLロガーã‹ã‚‰ã®é€šçŸ¥" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "SQLロガーã‹ã‚‰ã®è­¦å‘Š" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "SQLã§åˆ¥ã®è¡ŒãŒæº–å‚™ã§ãã¦ã„ã¾ã™" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "SQL実行ãŒçµ‚ã‚ã‚Šã¾ã—ãŸ" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "errno ãŒç„¡ã„システムエラー" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "ä¸æ˜Žãªã‚·ã‚¹ãƒ†ãƒ ã‚¨ãƒ©ãƒ¼" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "ファイル終端" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "ä¸æ˜Žãªã‚¨ãƒ©ãƒ¼ã‚³ãƒ¼ãƒ‰" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "引数ã¯æœŸå¾…ã•ã‚Œã¦ã„ã¾ã›ã‚“" + +#: src/argparse.c:470 +msgid "read error" +msgstr "読ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "キーワードãŒé•·ã™ãŽã¾ã™" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "引数ãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "無効ãªå¼•æ•°" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "無効ãªã‚³ãƒžãƒ³ãƒ‰" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "無効ãªã‚¨ã‚¤ãƒªã‚¢ã‚¹å®šç¾©ã§ã™" + +#: src/argparse.c:482 src/argparse.c:519 +msgid "permission error" +msgstr "許å¯ã‚¨ãƒ©ãƒ¼ã§ã™" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "メモリãŒã‚ã‚Šã¾ã›ã‚“" + +#: src/argparse.c:488 src/argparse.c:523 +msgid "invalid meta command" +msgstr "無効ãªãƒ¡ã‚¿ã‚³ãƒžãƒ³ãƒ‰" + +#: src/argparse.c:490 src/argparse.c:525 +msgid "unknown meta command" +msgstr "未知ã®ãƒ¡ã‚¿ã‚³ãƒžãƒ³ãƒ‰ã§ã™" + +#: src/argparse.c:492 src/argparse.c:527 +msgid "unexpected meta command" +msgstr "予期ã—ãªã„メタコマンドã§ã™" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "無効ãªã‚ªãƒ—ション" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "オプション\"%.50s\"ã«å¼•æ•°ãŒã‚ã‚Šã¾ã›ã‚“\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "オプション\"%.50s\"ã«ã¯ç„¡åŠ¹ãªå¼•æ•°ã§ã™\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "オプション\"%.50s\"ã¯å¼•æ•°ã‚’ã¨ã‚Šã¾ã›ã‚“\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "無効ãªã‚³ãƒžãƒ³ãƒ‰ \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "オプション\"%.50s\"ã¯ã‚ã„ã¾ã„ã§ã™\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "コマンド\"%.50s\"ã¯ã‚ã„ã¾ã„ã§ã™\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "無効ãªã‚ªãƒ—ション \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "注: デフォルトオプションファイル '%s' ãŒã‚ã‚Šã¾ã›ã‚“\n" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "オプションを'%s'ã‹ã‚‰èª­ã¿ã¾ã™\n" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "オプションファイル '%s': %s\n" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "注: グローãƒãƒ«ã‚³ãƒ³ãƒ•ã‚£ã‚°ã®ãŸã‚ã€ã‚ªãƒ—ション \"--%s\" を無視ã—ã¾ã™\n" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "ãƒã‚°ã¯ã«å ±å‘Šã—ã¦ãã ã•ã„。\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "警告: %s ã‚’èªè­˜ã§ãã¾ã›ã‚“ã§ã—ãŸ\n" + +#~ msgid "out of core\n" +#~ msgstr "メモリãŒã‚ã‚Šã¾ã›ã‚“\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "使用法: %s GPG-ERROR [...]\n" + +#~ msgid "Keyring open" +#~ msgstr "éµãƒªãƒ³ã‚°ã‚ªãƒ¼ãƒ—ン" diff --git a/comm/third_party/libgpg-error/po/libgpg-error.pot b/comm/third_party/libgpg-error/po/libgpg-error.pot new file mode 100644 index 0000000000..1b731cd144 --- /dev/null +++ b/comm/third_party/libgpg-error/po/libgpg-error.pot @@ -0,0 +1,1986 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR g10 Code GmbH +# This file is distributed under the same license as the libgpg-error package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.42\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "" + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "" + +#: src/argparse.c:470 +msgid "read error" +msgstr "" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "" + +#: src/argparse.c:482 src/argparse.c:519 +msgid "permission error" +msgstr "" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "" + +#: src/argparse.c:488 src/argparse.c:523 +msgid "invalid meta command" +msgstr "" + +#: src/argparse.c:490 src/argparse.c:525 +msgid "unknown meta command" +msgstr "" + +#: src/argparse.c:492 src/argparse.c:527 +msgid "unexpected meta command" +msgstr "" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "" diff --git a/comm/third_party/libgpg-error/po/nl.gmo b/comm/third_party/libgpg-error/po/nl.gmo new file mode 100644 index 0000000000..d60ec67e9a Binary files /dev/null and b/comm/third_party/libgpg-error/po/nl.gmo differ diff --git a/comm/third_party/libgpg-error/po/nl.po b/comm/third_party/libgpg-error/po/nl.po new file mode 100644 index 0000000000..c5180c3cc7 --- /dev/null +++ b/comm/third_party/libgpg-error/po/nl.po @@ -0,0 +1,2201 @@ +# translation of libgpg-error-1.10.nl.po to Dutch +# Copyright (C) 2008 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# +# Freek de Kruijf , 2009, 2010, 2012, 2014. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.10\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:27+0100\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Niet-gespecificeerde bron" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG-agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Elke bron" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Gebruikergedefinieerde bron 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Gebruikergedefinieerde bron 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Gebruikergedefinieerde bron 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Gebruikergedefinieerde bron 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Onbekende bron" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Succes" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Algemene fout" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Onbekend pakket" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Onbekende versie in pakket" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Ongeldig algoritme voor publieke sleutel" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Ongeldig digest-algoritme" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Foute publieke sleutel" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Foute geheime sleutel" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Onjuiste ondertekening" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Geen publieke sleutel" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Fout in controlesom" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Ongeldige wachtwoordzin" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Ongeldig versleutelingsalgoritme" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Sleutelring open" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Ongeldig pakket" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Ongeldige bepantsering" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Geen gebruiker-ID" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Geen geheime sleutel" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Foute geheime sleutel gebruikt" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Foute sessiesleutel" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Onbekend compressie-algoritme" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Nummer is geen priemgetal" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Ongeldige coderingsmethode" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Ongeldig versleutelingsschema" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Ongeldig ondertekeningsschema" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Ongeldig attribuut" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Geen waarde" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Niet gevonden" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Waarde niet gevonden" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Syntaxfout" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Foute MPI-waarde" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Ongeldige wachtwoordzin" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Ongeldige ondertekeningsklasse" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Hulpbronnen uitgeput" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Ongeldige sleutelring" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Fout in vertrouwensDB" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Fout certificaat" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Ongeldig gebruiker-ID" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Onverwachte fout" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Tijdconflict" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Fout in sleutelserver" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Ongeldig algoritme voor publieke sleutel" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Eerbetoon aan D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Zwakke cryptografische sleutel" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Ongeldige sleutellengte" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Ongeldig argument" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Syntaxfout in URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Ongeldige URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Netwerkfout" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Onbekende host" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Zelftest is mislukt" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Gegevens niet versleuteld" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Gegevens niet verwerkt" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Onbruikbare publieke sleutel" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Onbruikbare geheime sleutel" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Ongeldige waarde" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Foute certificaatketting" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Ontbrekend certificaat" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Geen gegevens" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Bug" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Niet ondersteund" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Ongeldige bewerkingscode" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Tijdslimiet" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Interne fout" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Ongeldig object" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Geleverd object is te kort" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Geleverd object is te groot" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Ontbrekend item in object" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Niet geïmplementeerd" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Conflicterend gebruik" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Ongeldige versleutelingsmodus" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Ongeldige vlag" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Ongeldige handel" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Resultaat is afgekapt" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Onvolledige regel" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Ongeldige reactie" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Er draait geen agent" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Fout met agent" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Ongeldige gegevens" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Ongespecificeerde fout in de Assuan-server" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Algemene Assuan-fout" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Ongeldige sessiesleutel" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Ongeldige S-expressie" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Niet ondersteund algoritme" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Geen pin-item" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "pin-item-fout" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Verkeerde PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Ongeldige naam" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Slechte gegevens" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Ongeldige parameter " + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Verkeerde kaart" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Geen dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr-fout" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certificaat is ingetrokken" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Geen CRL bekend" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL te oud" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Regel te lang" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Niet vertrouwd" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Bewerking geannuleerd" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Fout CA-certificaat" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certificaat verlopen" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certificaat te jong" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Niet ondersteund certificaat" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Onbekende S-expressie" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Niet ondersteunde bescherming" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Doorbroken bescherming" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Dubbelzinnige naam" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Kaartfout" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Reset van kaart vereist" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Kaart verwijderd" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Ongeldige kaart" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Kaart niet aanwezig" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Geen PKCS15-toepassing" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Niet bevestigd" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Configuratiefout" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Geen overeenkomst met beleid" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ongeldige index" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Ongeldige ID" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Geen SmartCard-daemon" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "SmartCard-daemon-fout" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Niet ondersteund protocol" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Verkeerde PIN-methode" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Kaart niet geïnitialiseerd" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Niet-ondersteunde operatie" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Verkeerd gebruik van sleutel" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Niets gevonden" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Verkeerde blob-type" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Ontbrekende waarde" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Hardwareprobleem" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN geblokkeerd" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Aan voorwaarden voor gebruik wordt niet voldaan" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN's zijn niet gesynchroniseerd" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Ongeldige CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER-fout" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Ongeldige BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Element niet gevonden" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identifier niet gevonden" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Ongeldige tag" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Ongeldige lengte" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Ongeldige sleutelinformatie" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Onverwachte tag" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Niet met DER gecodeerd" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Geen CMS-object" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Ongeldig CMS-object" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Onbekend CMS-object" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Niet-ondersteund CMS-object" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Niet-ondersteunde codering" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Niet-ondersteunde CMS-versie" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Onbekend algoritme" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Ongeldige crypto-engine" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Publieke sleutel wordt niet vertrouwd" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Ontcijfering is mislukt" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Sleutel is verlopen" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Handtekening verlopen" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Coderingsprobleem" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Ongeldige status" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Gedupliceerde waarde" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Ontbrekende actie" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ASN.1-module niet gevonden" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Ongeldige OID-tekenreeks" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Ongeldige tijd" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Ongeldig CRL-object" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Niet-ondersteunde CRL-versie" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Ongeldig certificaatobject" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Onbekende naam" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Een lokale functie is mislukt" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Niet vergrendeld" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "In strijd met protocol" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Ongeldige MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Ongeldig verzoek" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Onbekende extensie" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Onbekende kritische extensie" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Vergrendeld" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Onbekende optie" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Onbekend commando" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Niet in werking" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Geen wachtwoordzin ingegeven" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Geen PIN ingegeven" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Niet ingeschakeld" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Geen crypto-engine" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Ontbrekende sleutel" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Te veel objecten" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Limiet bereikt" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Niet geïnitialiseerd" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Ontbrekend certificaat van uitgever" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Geen sleutelserver beschikbaar" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Ongeldige elliptische kromme" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Onbekende elliptische kromme" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Dubbele sleutel" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Dubbelzinnig resultaat" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Geen crypto-context" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Verkeerde crypto-context" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Slechte crypto-context" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Conflict in de crypto-context" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Gebroken publieke sleutel" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Gebroken geheime sleutel" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Ongeldig MAC-algoritme" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Bewerking volledig geannuleerd" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Bewerking is nog niet beëindigd" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffer is te kort" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Ongeldige lengtespecificatie in S-expressie" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Tekenreeks is te lang in S-expressie" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Niet overeenkomende haakjes in S-expressie" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-expressie is niet canoniek" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Fout teken in S-expressie" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Foute aanhalingstekens in S-expressie" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Nul-prefix in S-expressie" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Geneste weergavetips in S-expressie" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Niet overeenkomende weergavetips" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Onverwachte gereserveerde punctuatie in S-expressie" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Fout hexadecimaal teken in S-expressie" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Vreemde hexadecimale getallen in S-expressie" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Fout octaal teken in S-expressie" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Gegevens niet versleuteld" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Onbekende naam" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Geen publieke sleutel" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Buffer is te kort" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Regel te lang" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Geen certificaatketting" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Certificaat te groot" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Ongeldig record" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "De MAC komt niet overeen" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Onverwacht bericht" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Compressie of decompressie is mislukt" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Een teller loopt rond" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Een alarmeringsbericht over iets fataal ontvangen " + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Geen versleutelingsalgoritme" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Ontbrekend certificaat van client" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Melding over sluiten ontvangen" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Ticket is verlopen" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Slecht ticket" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Onbekende identiteit" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Slecht certificaatbericht in uitwisseling" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Slecht verzoek om certificaatbericht in uitwisseling" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Slecht certificaatbericht over verificatie in uitwisseling" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Slecht wijzigingsbericht over vercijfering in uitwisseling" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Slecht hello-bericht van client in uitwisseling" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Slecht hello-bericht van server in uitwisseling" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Slecht hello-gedaan-bericht van server in uitwisseling" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Slecht bericht over beëindiging in uitwisseling" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Slecht sleuteluitwisselingsbericht van server in uitwisseling" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Slecht sleuteluitwisselingsbericht van client in uitwisseling" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Onzintekenreeks" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Sleutel uitgeschakeld" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Niet mogelijk met een sleutel van een kaart" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Ongeldig vergrendelobject" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Algemene IPC-fout" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC acceptatie-aanroep is mislukt" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC verbindingsoproep is mislukt" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Ongeldige IPC-reactie" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Ongeldige waarde naar IPC gestuurd" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Onvolledige regel naar IPC gestuurd" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Naar IPC gestuurde regel is te lang" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Geneste IPC-commando's" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Geen gegevens terugroep in IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Geen afvraagterugroep in IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Geen IPC-server" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Geen IPC-client" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Probleem met opstarten van IPC-server" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC-leesfout" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC-schrijffout" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Te veel gegevens voor IPC=laag" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Onverwacht IPC-commando" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Onbekend IPC-commando" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC-syntaxfout" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC-oproep is geannuleerd" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Geen invoerbron voor IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Geen uitvoerbron voor IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC-parameterfout" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Onbekende IPC-afvraging" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "No crypto engine" +msgid "Crypto engine too old" +msgstr "Geen crypto-engine" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Gedupliceerde waarde" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certificaat te jong" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "Geleverd object is te kort" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Onbekende naam" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Ongeldige bewerkingscode" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Onbekende naam" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Niet ingeschakeld" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Niet ondersteunde bescherming" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Er draait geen agent" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "SmartCard-daemon-fout" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Fout in sleutelserver" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Onbekende systeemfout" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Ongeldige OID-tekenreeks" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Ongeldige S-expressie" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing issuer certificate" +msgid "Missing DNS query packet" +msgstr "Ontbrekend certificaat van uitgever" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Ontcijfering is mislukt" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Tijdslimiet" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Algemene IPC-fout" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Algemene fout" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Algemene fout" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Algemene Assuan-fout" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Algemene fout" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Algemene Assuan-fout" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "IPC-schrijffout" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Algemene IPC-fout" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "IPC verbindingsoproep is mislukt" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Algemene fout" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Reset van kaart vereist" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Element niet gevonden" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Niet ondersteund" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Onverwachte fout" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Niet-ondersteunde operatie" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Fout certificaat" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Onbekende extensie" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Tijdslimiet" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "dirmngr-fout" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "dirmngr-fout" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "IPC-leesfout" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Geen IPC-server" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Succes" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Configuratiefout" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "In strijd met protocol" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Onbekende extensie" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +#, fuzzy +#| msgid "Fatal alert message received" +msgid "Partial LDAP results+referral received" +msgstr "Een alarmeringsbericht over iets fataal ontvangen " + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Algemene fout" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Reset van kaart vereist" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Ongeldig attribuut" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Niet ondersteunde bescherming" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "In strijd met protocol" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Ongeldige status" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Geen CMS-object" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Hardwareprobleem" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Ongeldige status" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Coderingsprobleem" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Niet ondersteunde bescherming" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Ongeldige kaart" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +#, fuzzy +#| msgid "No keyserver available" +msgid "LDAP server is unavailable" +msgstr "Geen sleutelserver beschikbaar" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Ontbrekende actie" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "In strijd met protocol" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Bewerking is nog niet beëindigd" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Bewerking geannuleerd" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Regel te lang" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Bewerking geannuleerd" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Algemene IPC-fout" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Hulpbronnen uitgeput" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "In strijd met protocol" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Ongeldige status" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Niet ondersteund certificaat" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Reset van kaart vereist" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Succes" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Niet in werking" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Niet in werking" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Geen IPC-server" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Ontcijfering is mislukt" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Gebruikergedefinieerde foutcode 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Gebruikergedefinieerde foutcode 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Gebruikergedefinieerde foutcode 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Gebruikergedefinieerde foutcode 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Gebruikergedefinieerde foutcode 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Gebruikergedefinieerde foutcode 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Gebruikergedefinieerde foutcode 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Gebruikergedefinieerde foutcode 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Gebruikergedefinieerde foutcode 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Gebruikergedefinieerde foutcode 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Gebruikergedefinieerde foutcode 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Gebruikergedefinieerde foutcode 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Gebruikergedefinieerde foutcode 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Gebruikergedefinieerde foutcode 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Gebruikergedefinieerde foutcode 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Gebruikergedefinieerde foutcode 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Succes" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Syntaxfout" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "In strijd met protocol" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Systeemfout zonder foutnr." + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Onbekende systeemfout" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Einde van bestand" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Onbekende foutcode" + +#: src/argparse.c:468 +#, fuzzy +#| msgid "Data not encrypted" +msgid "argument not expected" +msgstr "Gegevens niet versleuteld" + +#: src/argparse.c:470 +#, fuzzy +#| msgid "IPC read error" +msgid "read error" +msgstr "IPC-leesfout" + +#: src/argparse.c:472 +#, fuzzy +#| msgid "Line too long" +msgid "keyword too long" +msgstr "Regel te lang" + +#: src/argparse.c:474 +#, fuzzy +#| msgid "Missing value" +msgid "missing argument" +msgstr "Ontbrekende waarde" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "Invalid argument" +msgid "invalid argument" +msgstr "Ongeldig argument" + +#: src/argparse.c:478 +#, fuzzy +#| msgid "Invalid card" +msgid "invalid command" +msgstr "Ongeldige kaart" + +#: src/argparse.c:480 +#, fuzzy +#| msgid "Invalid OID string" +msgid "invalid alias definition" +msgstr "Ongeldige OID-tekenreeks" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Configuratiefout" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "Invalid card" +msgid "invalid meta command" +msgstr "Ongeldige kaart" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Onbekend commando" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Onverwacht IPC-commando" + +#: src/argparse.c:494 +#, fuzzy +#| msgid "Invalid operation code" +msgid "invalid option" +msgstr "Ongeldige bewerkingscode" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +#| msgid "Invalid operation code" +msgid "invalid option \"%.50s\"\n" +msgstr "Ongeldige bewerkingscode" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, fuzzy, c-format +msgid "warning: could not recognize %s\n" +msgstr "waarschuwing: kon %s niet herkennen\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Gebruik: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Hulpbronnen uitgeput" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Ongeldige gegevens" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Algemene fout" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "dirmngr-fout" diff --git a/comm/third_party/libgpg-error/po/pl.gmo b/comm/third_party/libgpg-error/po/pl.gmo new file mode 100644 index 0000000000..d9ef305bde Binary files /dev/null and b/comm/third_party/libgpg-error/po/pl.gmo differ diff --git a/comm/third_party/libgpg-error/po/pl.po b/comm/third_party/libgpg-error/po/pl.po new file mode 100644 index 0000000000..860ed4ca23 --- /dev/null +++ b/comm/third_party/libgpg-error/po/pl.po @@ -0,0 +1,1987 @@ +# Polish translation for libgpg-error. +# Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Jakub Bogusz , 2004-2020. +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.38\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:42+0100\n" +"Last-Translator: Jakub Bogusz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Nie podane źródÅ‚o" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "Agent GPG" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Dowolne źródÅ‚o" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Zdefiniowane przez użytkownika źródÅ‚o 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Zdefiniowane przez użytkownika źródÅ‚o 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Zdefiniowane przez użytkownika źródÅ‚o 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Zdefiniowane przez użytkownika źródÅ‚o 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Nieznane źródÅ‚o" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Sukces" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "BÅ‚Ä…d ogólny" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Nieznany pakiet" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Nieznana wersja w pakiecie" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Niepoprawny algorytm klucza publicznego" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Niepoprawny algorytm skrótu" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "BÅ‚Ä™dny klucz publiczny" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "BÅ‚Ä™dny klucz tajny" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "BÅ‚Ä™dna sygnatura" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Brak klucza publicznego" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "BÅ‚Ä…d sumy kontrolnej" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "BÅ‚Ä™dne hasÅ‚o" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Niepoprawny algorytm szyfru" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Zbiór kluczy otwarty" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Niepoprawny pakiet" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Niepoprawne opakowanie" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Brak identyfikatora użytkownika" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Brak klucza tajnego" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Użyto niewÅ‚aÅ›ciwego klucza tajnego" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "BÅ‚Ä™dny klucz sesji" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Nieznany algorytm kompresji" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Liczba nie jest pierwsza" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Niepoprawna metoda kodowania" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Niepoprawny ukÅ‚ad szyfrowania" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Niepoprawny ukÅ‚ad sygnatury" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Niepoprawny atrybut" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Brak wartoÅ›ci" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Nie znaleziono" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Wartość nie znaleziona" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "BÅ‚Ä…d skÅ‚adni" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "BÅ‚Ä™dna wartość MPI" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Niepoprawne hasÅ‚o" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Niepoprawna klasa sygnatury" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Zasoby wyczerpane" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Niepoprawny zbiór kluczy" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "BÅ‚Ä…d bazy zaufania" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "BÅ‚Ä™dny certyfikat" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Niepoprawny identyfikator użytkownika" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Nieoczekiwany bÅ‚Ä…d" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Konflikt czasu" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "BÅ‚Ä…d serwera kluczy" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "NiewÅ‚aÅ›ciwy algorytm klucza publicznego" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "PamiÄ™ci D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "SÅ‚aby klucz szyfrowania" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Niepoprawna dÅ‚ugość klucza" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Niepoprawny argument" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "BÅ‚Ä…d skÅ‚adni w URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "BÅ‚Ä™dne URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "BÅ‚Ä…d sieci" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Nieznany host" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Test wewnÄ™trzny nie powiódÅ‚ siÄ™" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Dane nie zaszyfrowane" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Dane nie przetworzone" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Bezużyteczny klucz publiczny" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Bezużyteczny klucz tajny" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Niepoprawna wartość" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "BÅ‚Ä™dny Å‚aÅ„cuch certyfikatów" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "BrakujÄ…cy certyfikat" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Brak danych" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "BÅ‚Ä…d w kodzie" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Nie obsÅ‚ugiwane" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Niepoprawny kod operacji" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "UpÅ‚ynÄ…Å‚ limit czasu" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "BÅ‚Ä…d wewnÄ™trzny" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "Koniec pliku (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Niepoprawny obiekt" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Dostarczony obiekt jest zbyt maÅ‚y" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Dostarczony obiekt jest zbyt duży" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Brak elementu w obiekcie" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Nie zaimplementowane" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Konflikt użycia" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Niepoprawny tryb szyfru" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Niepoprawna flaga" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Niepoprawny uchwyt" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Wynik skrócony" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Niekompletna linia" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Niepoprawna odpowiedź" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Agent nie uruchomiony" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "BÅ‚Ä…d agenta" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Niepoprawne dane" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "NieokreÅ›lone niepowodzenie serwera Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "BÅ‚Ä…d ogólny Assuana" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Niepoprawny klucz sesji" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Niepoprawne S-wyrażenie" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "NieobsÅ‚ugiwany algorytn" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Brak pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "BÅ‚Ä…d pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "BÅ‚Ä™dny PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Niepoprawna nazwa" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "BÅ‚Ä™dne dane" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Niepoprawny parametr" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "NiewÅ‚aÅ›ciwa karta" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Brak dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "BÅ‚Ä…d dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certyfikat anulowany" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Nieznane CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL zbyt stare" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Linia zbyt dÅ‚uga" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Nie zaufany" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Operacja anulowana" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "BÅ‚Ä™dny certyfikat CA" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certyfikat wygasÅ‚" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certyfikat zbyt mÅ‚ody" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "NieobsÅ‚ugiwany certyfikat" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Nieznane S-wyrażenie" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "NieobsÅ‚ugiwane zabezpieczenie" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Uszkodzone zabezpieczenie" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Niejednoznaczna nazwa" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "BÅ‚Ä…d karty" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Wymagany reset karty" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Karta wyciÄ…gniÄ™ta" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Niepoprawna karta" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Karta nieobecna" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Brak aplikacji PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Brak potwierdzenia" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "BÅ‚Ä…d konfiguracji" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Brak zgodnoÅ›ci polityki" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Niepoprawny indeks" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Niepoprawny identyfikator" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Brak demona SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "BÅ‚Ä…d demona SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "NieobsÅ‚ugiwany protokół" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "BÅ‚Ä™dna metoda PIN-u" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Karta nie zainicjowana" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "NieobsÅ‚ugiwana operacja" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "NiewÅ‚aÅ›ciwe użycie klucza" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Nic nie znaleziono" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "NiewÅ‚aÅ›ciwy typ blob" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Brak wartoÅ›ci" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problem sprzÄ™towy" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN zablokowany" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Warunki użycia nie speÅ‚nione" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN-y nie zsynchronizowane" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Niepoprawne CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BÅ‚Ä…d BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Niepoprawne BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Element nie znaleziony" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identyfikator nie znaleziony" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Niepoprawny znacznik" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Niepoprawna dÅ‚ugość" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Niepoprawna informacja klucza" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Nieoczekiwany znacznik" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Nie zakodowane DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Brak obiektu CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Niepoprawny obiekt CMS" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Nieznany obiekt CMS" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "NieobsÅ‚ugiwany obiekt CMS" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "NieobsÅ‚ugiwane kodowanie" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "NieobsÅ‚ugiwana wersja CMS" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Nieznany algorytm" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Niepoprawny silnik kryptograficzny" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Klucz publiczny nie zaufany" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Odszyfrowywanie nie powiodÅ‚o siÄ™" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Klucz wygasÅ‚" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Sygnatura wygasÅ‚a" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Problem z kodowaniem" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Niepoprawny stan" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Powtórzona wartość" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Brak akcji" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Nie znaleziono moduÅ‚u ASN.1" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Niepoprawny Å‚aÅ„cuch OID" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Niepoprawny czas" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Niepoprawny obiekt CRL" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "NieobsÅ‚ugiwana wersja CRL" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Niepoprawny obiekt certyfikatu" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nieznana nazwa" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Funkcja lokalizacji nie powiodÅ‚a siÄ™" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Nie zablokowany" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Naruszenie protokoÅ‚u" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Niepoprawny MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Niepoprawne żądanie" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Nieznane rozszerzenie" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Nieznane rozszerzenie krytyczne" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Zablokowany" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Nieznana opcja" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Nieznane polecenie" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Nie gotowy" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Nie podano hasÅ‚a" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Nie podano PIN-u" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Nie wÅ‚Ä…czony" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Brak silnika kryptograficznego" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Brak klucza" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Zbyt dużo obiektów" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "OsiÄ…gniÄ™to limit" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Nie zainicjowano" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Brak certyfikatu wystawcy" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Brak dostÄ™pnego serwera kluczy" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "BÅ‚Ä™dna krzywa eliptyczna" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Nieznana krzywa eliptyczna" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Powtórzony klucz" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Niejednoznaczny wynik" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Brak kontekstu kryptograficznego" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "NiewÅ‚aÅ›ciwy kontekst kryptograficzny" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "BÅ‚Ä™dny kontekst kryptograficzny" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Konflikt w kontekÅ›cie kryptograficznym" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Uszkodzony klucz publiczny" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Uszkodzony klucz tajny" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Niepoprawny algorytm MAC" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Operacja caÅ‚kowicie anulowana" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Operacja jeszcze nie zakoÅ„czona" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Bufor zbyt maÅ‚y" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Niepoprawne okreÅ›lenie dÅ‚ugoÅ›ci w S-wyrażeniu" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Zbyt dÅ‚ugi Å‚aÅ„cuch w S-wyrażeniu" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Niedopasowane nawiasy w S-wyrażeniu" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-wyrażenie nie kanoniczne" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "BÅ‚Ä™dny znak w S-wyrażeniu" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "BÅ‚Ä™dne cytowanie w S-wyrażeniu" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Zerowy prefiks w S-wyrażeniu" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Zagnieżdżone podpowiedzi wyÅ›wietlania w S-wyrażeniu" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Niedopasowane podpowiedzi wyÅ›wietlania" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Nieoczekiwany zarezerwowany znak w S-wyrażeniu" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "BÅ‚Ä™dny znak szesnastkowy w S-wyrażeniu" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Nieparzysta liczba cyfr szesnastkowych w S-wyrażeniu" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "BÅ‚Ä™dny znak ósemkowy w S-wyrażeniu" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "Wszystkie podklucze wygasÅ‚y lub zostaÅ‚y anulowane" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "Baza danych jest uszkodzona" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "Serwer wskazaÅ‚ niepowodzenie" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "Brak nazwy" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "Brak klucza" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "Stary typ klucza" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "Żądanie za krótkie" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "Żądanie za dÅ‚ugie" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "Obiekt jest w stanie koÅ„cowym" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Brak Å‚aÅ„cucha certyfikatów" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Certyfikat jest zbyt duży" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Niepoprawny rekord" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "NiepomyÅ›lna weryfikacja MAC" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Nieoczekiwany komunikat" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Kompresja lub dekompresja nie powiodÅ‚a siÄ™" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Licznik by siÄ™ przekrÄ™ciÅ‚" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Otrzymano komunikat alarmu krytycznego" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Brak algorytmu szyfru" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Brak certyfikatu klienta" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Otrzymano powiadomienie o zamkniÄ™ciu" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Bilet wygasÅ‚" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "BÅ‚Ä™dny bilet" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Nieznana tożsamość" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "BÅ‚Ä™dny komunikat certyfikatu przy powitaniu" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "BÅ‚Ä™dny komunikat żądania certyfikatu przy powitaniu" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "BÅ‚Ä™dny komunikat weryfikacji certyfikatu przy powitaniu" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "BÅ‚Ä™dny komunikat zmiany szyfru przy powitaniu" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "BÅ‚Ä™dny komunikat przywitania klienta w powitaniu" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "BÅ‚Ä™dny komunikat przywitania serwera w powitaniu" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "BÅ‚Ä™dny komunikat zakoÅ„czenia przywitania serwera w powitaniu" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "BÅ‚Ä™dny komunikat zakoÅ„czenia w powitaniu" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "BÅ‚Ä™dny komunikat wymiany klucza serwera w powitaniu" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "BÅ‚Ä™dny komunikat wymiany klucza klienta w powitaniu" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "FaÅ‚szywy Å‚aÅ„cuch" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "Zabronione" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Klucz dezaktywowany" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Niemożliwe przy użyciu klucza opartego na karcie" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Niepoprawny obiekt blokady" + +#: src/err-codes.h:280 +msgid "True" +msgstr "Prawda" + +#: src/err-codes.h:281 +msgid "False" +msgstr "FaÅ‚sz" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "BÅ‚Ä…d ogólny IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "WywoÅ‚anie accept dla IPC nie powiodÅ‚o siÄ™" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "WywoÅ‚anie connect dla IPC nie powiodÅ‚o siÄ™" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Niepoprawna odpowiedź IPC" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Niepoprawna wartość przekazana do IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Niekompletna linia przekazana do IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Linia przekazana do IPC zbyt dÅ‚uga" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Zagnieżdżone polecenia IPC" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Brak wywoÅ‚ania zwrotnego dla danych w IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Brak wywoÅ‚ania wstecznego dla zapytaÅ„ w IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "To nie jest serwer IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "To nie jest klient IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problem z uruchomieniem serwera IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "BÅ‚Ä…d odczytu IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "BÅ‚Ä…d zapisu IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Zbyt dużo danych dla warstwy IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Nieoczekiwane polecenie IPC" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Nieznane polecenie IPC" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "BÅ‚Ä…d skÅ‚adni IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "WywoÅ‚anie IPC zostaÅ‚o anulowane" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Brak źródÅ‚a wejÅ›ciowego dla IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Brak źródÅ‚a wyjÅ›ciowego dla IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "BÅ‚Ä…d parametru IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Nieznane zapytanie IPC" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "Silnik kryptograficzny zbyt stary" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "Ekran lub okno zbyt maÅ‚e" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "Ekran lub okno zbyt duże" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "Wymagana zmienna Å›rodowiskowa nie jest ustawiona" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "Identyfikator użytkownika już istnieje" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "Nazwa już istnieje" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "Powtórzona nazwa" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "Obiekt zbyt mÅ‚ody" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "Obiekt zbyt stary" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "Nieznana flaga" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "BÅ‚Ä™dna kolejność wykonywania" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "Już pobrano" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "ProszÄ™ spróbować później" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "ZÅ‚a nazwa" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "Brak uwierzytelnienia" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "NiewÅ‚aÅ›ciwe uwierzytelnienie" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "Demon Keybox nie uruchomiony" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "BÅ‚Ä…d demona Keybox" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "UsÅ‚uga nie jest uruchomiona" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "BÅ‚Ä…d usÅ‚ugi" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "Wykryto bÅ‚Ä…d systemu" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "Nieznany bÅ‚Ä…d DNS" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "BÅ‚Ä™dna sekcja DNS" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "BÅ‚Ä™dna postać tekstowa adresu" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "Brak pakietu zapytania DNS" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "Brak pakietu odpowiedzi DNS" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "PoÅ‚Ä…czenie zamkniÄ™te przez DNS" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "Weryfikacja przez DNS nie powiodÅ‚a siÄ™" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "UpÅ‚ynÄ…Å‚ limit czasu DNS" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "BÅ‚Ä…d ogólny LDAP" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "BÅ‚Ä…d ogólny atrybutu LDAP" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "BÅ‚Ä…d ogólny nazwy LDAP" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "BÅ‚Ä…d ogólny bezpieczeÅ„stwa LDAP" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "BÅ‚Ä…d ogólny usÅ‚ugi LDAP" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "BÅ‚Ä…d ogólny aktualizacji LDAP" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "Eksperymentalny kod bÅ‚Ä™du LDAP" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "Prywatny kod bÅ‚Ä™du LDAP" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "Inny bÅ‚Ä…d ogólny LDAP" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "PoÅ‚Ä…czenie z LDAP nie powiodÅ‚o siÄ™ (X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "Przekroczony limit odniesieÅ„ LDAP" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "PÄ™tla klienta LDAP" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "Nie zwrócono wyników LDAP" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "Nie znaleziono sterowania LDAP" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "Nie obsÅ‚ugiwane przez LDAP" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "BÅ‚Ä…d poÅ‚Ä…czenia z LDAP" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "Brak pamiÄ™ci w LDAP" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "BÅ‚Ä™dny parametr procedury LDAP" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "Operacja LDAP anulowana przez użytkownika" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "BÅ‚Ä™dny filtr wyszukiwania LDAP" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "Nieznana metoda uwierzytelnienia LDAP" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "Limit czasu w LDAP" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "BÅ‚Ä…d dekodowania LDAP" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "BÅ‚Ä…d kodowania LDAP" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "BÅ‚Ä…d lokalny LDAP" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "Nie można poÅ‚Ä…czyć siÄ™ z serwerem LDAP" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "Sukces LDAP" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "BÅ‚Ä…d operacji LDAP" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "BÅ‚Ä…d protokoÅ‚u LDAP" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "Przekroczony limit czasu w LDAP" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "Przekroczony limit rozmiaru w LDAP" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "Porównanie LDAP faÅ‚szywe" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "Porównanie LDAP prawdziwe" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "NieobsÅ‚ugiwana metoda uwierzytelnienia LDAP" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "Wymagana silniejsze uwierzytelnienie LDAP" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "Otrzymano częściowe wyniki+odniesienie LDAP" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "Odniesienie LDAP" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "Przekroczony limit administracyjny LDAP" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "Krytyczne rozszerzenie LDAP jest niedostÄ™pne" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "Zaufanie wymagane przez LDAP" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "WiÄ…zanie LDAP SASL w trakcie" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "Nie ma takiego atrybutu LDAP" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "Niezdefiniowany typ atrybutu LDAP" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "NiewÅ‚aÅ›ciwe dopasowanie w LDAP" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "Naruszenie ograniczenia w LDAP" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "Typ lub wartość LDAP istnieje" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "BÅ‚Ä™dna skÅ‚adnia w LDAP" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "Nie ma takiego obiektu LDAP" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "Problem z aliasem LDAP" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "BÅ‚Ä™dna skÅ‚adnia DN w LDAP" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "Wpis LDAP jest liÅ›ciem" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "Problem z rozwiniÄ™ciem aliasu LDAP" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "BÅ‚Ä…d autoryzacji do proxy LDAP (X)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "NiewÅ‚aÅ›ciwe uwierzytelnienie LDAP" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "BÅ‚Ä™dne dane uwierzytelniajÄ…ce LDAP" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "NiewystarczajÄ…cy dostÄ™p dla LDAP" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "Serwer LDAP jest zajÄ™ty" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "Serwer LDAP jest niedostÄ™pny" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "Serwer LDAP nie zamierza wykonać żądania" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "PÄ™tla wykryta przez LDAP" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "Naruszenie nazw LDAP" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "Naruszenie klasy obiektu LDAP" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "Operacja LDAP nie jest dozwolona na nie-liÅ›ciu" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "Operacja LDAP nie jest dozwolona na RDN" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "Już istnieje (LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "Nie można zmodyfikować klasy obiektu LDAP" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "Wyniki LDAP zbyt duże" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "Operacja LDAP obejmuje wiele DSA" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "BÅ‚Ä…d widoku wirtualnej listy LDAP" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "Inny bÅ‚Ä…d LDAP" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "Zasoby wyczerpane w LCUP" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "Naruszenie bezpieczeÅ„stwa w LCUP" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "BÅ‚Ä™dne dane w LCUP" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "NieobsÅ‚ugiwany schemat w LCUP" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "Wymagane przeÅ‚adowanie w LCUP" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAP anulowane" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "Brak operacji LDAP do anulowania" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "Za późno na anulowanie LDAP" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "Nie można anulować LDAP" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "Zapewnienie LDAP nie powiodÅ‚o siÄ™" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "Autoryzacja przez proxy odrzucona przez LDAP" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Zdefiniowany przez użytkownika kod bÅ‚Ä™du 16" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "Sukces SQL" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "BÅ‚Ä…d SQL" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "WewnÄ™trzny bÅ‚Ä…d logiczny w bibliotece SQL" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "Brak uprawnieÅ„ (SQL)" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "Zapytanie SQL przerwane na żądanie" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "Plik bazy danych SQL jest zablokowany" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "Tabela SQL w bazie danych jest zablokowana" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "Pamięć wyczerpana w bibliotece SQL" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "Próba zapisu do bazy danych SQL tylko do odczytu" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "Operacja SQL zakoÅ„czona przez przerwanie" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "BÅ‚Ä…d we/wy podczas operacji SQL" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "Obraz dysku bazy danych SQL jest uszkodzony" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "Nieznany kod operacji w pliku sterujÄ…cym SQL" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "Wstawianie nie powiodÅ‚o siÄ™, ponieważ baza danych SQL jest peÅ‚na" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "Nie udaÅ‚o siÄ™ otworzyć pliku bazy danych SQL" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "BÅ‚Ä…d protokoÅ‚u blokowania bazy danych SQL" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "(wewnÄ™trzny kod SQL: pusty)" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "Schemat bazy danych SQL ulegÅ‚ zmianie" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "ÅaÅ„cuch lub blok danych przekracza limit rozmiaru (SQL)" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "Operacja SQL przerwana z powodu naruszenia ograniczeÅ„" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "Niezgodność typów danych (SQL)" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "Biblioteka SQL użyta niepoprawnie" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" +"Biblioteka SQL wykorzystuje nie obsÅ‚ugiwane funkcje systemu operacyjnego" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "Autoryzacja odrzucona (SQL)" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "(nie używany kod SQL: format)" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "Parametr dowiÄ…zania SQL spoza zakresu" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "Otwarty plik nie jest bazÄ… danych SQL" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "Powiadomienia z loggera SQL" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "Ostrzeżenia z loggera SQL" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "Baza SQL ma gotowy kolejny wiersz" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "Baza SQL zakoÅ„czyÅ‚a wykonywanie" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "BÅ‚Ä…d systemowy bez errno" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Nieznany bÅ‚Ä…d systemu" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Koniec pliku" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Nieznany kod bÅ‚Ä™du" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "nieoczekiwany argument" + +#: src/argparse.c:470 +msgid "read error" +msgstr "bÅ‚Ä…d odczytu" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "sÅ‚owo kluczowe zbyt dÅ‚ugie" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "brak argumentu" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "nÅ‚Ä™dny argument" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "bÅ‚Ä™dne polecenie" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "bÅ‚Ä™dna definicja aliasu" + +#: src/argparse.c:482 src/argparse.c:519 +msgid "permission error" +msgstr "bÅ‚Ä…d uprawnieÅ„" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "brak pamiÄ™ci" + +#: src/argparse.c:488 src/argparse.c:523 +msgid "invalid meta command" +msgstr "bÅ‚Ä™dne polecenie meta" + +#: src/argparse.c:490 src/argparse.c:525 +msgid "unknown meta command" +msgstr "nieznane polecenie meta" + +#: src/argparse.c:492 src/argparse.c:527 +msgid "unexpected meta command" +msgstr "nieoczekiwane polecenie meta" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "bÅ‚Ä™dna opcja" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "brak argumentu dla opcji ,,%.50s''\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "bÅ‚Ä™dny argumentu dla opcji ,,%.50s''\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "opcja ,,%.50s'' nie może mieć argumentów\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "bÅ‚Ä™dne polecenie ,,%.50s''\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "opcja ,,%.50s'' jest niejednoznaczna\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "polecenie ,,%.50s'' jest niejednoznaczne\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "bÅ‚Ä™dna opcja ,,%.50s''\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "Uwaga: brak domyÅ›lnego pliku opcji ,,%s''\n" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "odczyt opcji z ,,%s''\n" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "plik opcji ,,%s'': %s\n" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" +"Uwaga: ignorowanie opcji ,,--%s'' ze wzglÄ™du na konfiguracjÄ™ globalnÄ…\n" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "BÅ‚Ä™dy prosimy zgÅ‚aszać pod .\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "uwaga: nie rozpoznano %s\n" diff --git a/comm/third_party/libgpg-error/po/pt.gmo b/comm/third_party/libgpg-error/po/pt.gmo new file mode 100644 index 0000000000..998a446585 Binary files /dev/null and b/comm/third_party/libgpg-error/po/pt.gmo differ diff --git a/comm/third_party/libgpg-error/po/pt.po b/comm/third_party/libgpg-error/po/pt.po new file mode 100644 index 0000000000..7b30590097 --- /dev/null +++ b/comm/third_party/libgpg-error/po/pt.po @@ -0,0 +1,2197 @@ +# Portuguese translations for libgpg-error package. +# Copyright (C) 2014 g10 Code GmbH +# This file is distributed under the same license as the libgpg-error package. +# +# paulo , 2014. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.17\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:42+0100\n" +"Last-Translator: Paulo Tomé \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 1.4\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Fonte não especificada" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "Agente GPG" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Qualquer fonte" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Fonte definida pelo utilizador 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Fonte definida pelo utilizador 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Fonte definida pelo utilizador 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Fonte definida pelo utilizador 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Fonte não conhecida" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Sucesso" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Erro genérico" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Pacote desconhecido" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Versão desconhecida no pacote" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Algoritmo de chave pública inválido" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Algoritmo de resumo inválido" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Chave pública errada" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Chave secreta errada" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Assinatura errada" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Sem chave pública" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Soma de verificação errada" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Senha errada" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Algoritmo de cifra inválido" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Chaveiro aberto" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Pacote inválido" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Armadura inválida" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Sem identificador de utilizador" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Sem chave secreta" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Utilizada chave secreta errada" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Chave de sessão errada" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Algoritmo de compressão desconhecido" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "O número não é primo" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Método de codificação errado" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Esquema de encriptação errado" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Esquema de assinatura inválido" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Atributo inválido" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Sem valor" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Não encontrado" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Valor não encontrado" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Erro de sintaxe" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Valor de MPI errado" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Senha inválida" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Classe de assinatura inválida" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Recursos esgotados" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Chaveiro inválido" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Erro na Base de Dados de confiança" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Certificado errado" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Identificador de utilizador errado" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Erro inesperado" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Conflito temporal" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Erro no servidor de chaves" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Algoritmo da chave pública errado" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Tributo a D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Chave de encriptação fraca" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Comprimento da chave inválido" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Argumento inválido" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Erro de sintaxe no URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "URI inválido" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Erro de rede" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Anfitrião desconhecido" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Auto teste falhou" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Dados não encriptados" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Dados não processados" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Chave pública inutilizável" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Chave secreta inutilizável" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Valor inválido" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Cadeia de certificados errada" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Certificado em falta" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Não existem dados" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Erro" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Não suportado" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Código de operação inválido" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Tempo limite" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Erro interno" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Objecto inválido" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "O objecto fornecido é demasiado curto" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "O objecto fornecido é demasiado grande" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Item em falta no objecto" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Não implementado" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Utilização em conflito" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Modo de cifra inválido" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Flag inválido" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Identificador inválido" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Resultado truncado" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Linha incompleta" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Resposta inválida" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Nenhum agente em execução" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Erro no agente" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Dados inválidos" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Falha não especificada no servidor Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Erro Assuan genérico" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Chave de sessão inválida" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Expressão simbólica inválida" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Algoritmo não suportado" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Sem pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Erro no pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "PIN errado" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Nome inválido" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Dados errados" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Parâmetro inválido" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Cartão errado" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Sem dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Erro no dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certificado revogado" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Sem CRL conhecido" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL muito velho" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Linha demasiado longa" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Não é de confiança" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Operação cancelada" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Certificado BA errado" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certificado expirou" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certificado demasiado novo" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Certificado não suportado" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Expressão simbólica desconhecida" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Protecção não suportada" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Protecção corrompida" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Nome ambíguo" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Erro de cartão" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Reinicialização de cartão necessária" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Cartão removido" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Cartão inválido" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Cartão não presente" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Sem aplicação PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Não confirmado" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Erro de configuração" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Sem correspondência de política" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ãndice inválido" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Identificador inválido" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Sem demónio de SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Erro no demónio de SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Protocolo não suportado" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Método de PIN errado" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Cartão não inicializado" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Operação não suportada" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Utilização de chave errada" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Nada encontrado" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Tipo de blob errado" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Valor em falta" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problema de hardware" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN bloqueado" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Condições de utilização não satisfeitas" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PINs não estão sincronizados" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "CRL inválido" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Erro de BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "BER inválido" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Elemento não encontrado" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identificador não encontrado" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Etiqueta inválida" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Comprimento inválido" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Informação de chave errada" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Etiqueta inesperada" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Não codificado através de DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Sem objecto CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Objecto CMS inválido" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Objecto CMS desconhecido" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Objecto CMS não suportado" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Codificação não suportada" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Versão de CMS não suportada" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Algoritmo desconhecido" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Motor de encriptação inválido" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Chave pública não é de confiança" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Desencriptação falhada" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Chave expirada" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Assinatura expirada" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Problema de codificação" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Estado inválido" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Valor duplicado" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Acção em falta" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Módulo ASN.1 não encontrado" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Sequência OID inválida" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Tempo inválido" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Objecto CRL inválido" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Versão CRL não suportada" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Objecto de certificado inválido" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nome desconhecido" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Uma função de localização falhou" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Não trancado" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Violação de protocolo" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "MAC inválido" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Pedido inválido" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Extensão desconhecida" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Extensão crítica desconhecida" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Trancado" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Opção desconhecida" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Comando desconhecido" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Não operacional" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Nenhuma senha dada" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Sem PIN dado" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Não habilitado" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Sem motor de encriptação" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Chave em falta" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Demasiados objectos" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "Limite atingido" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Não inicializado" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Certificado do emissor em falta" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Sem servidor de chaves disponível" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Curva elíptica inválida" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Curva elíptica desconhecida" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Chave duplicada" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Resultado ambíguo" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Sem contexto de encriptação" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Contexto de encriptação errado" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Contexto de encriptação inválido" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Conflito no contexto de encriptação" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Chave pública quebrada" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Chave secreta quebrada" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Algoritmo MAC inválido" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Operação totalmente cancelada" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Operação ainda não completada" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffer demasiado curto" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Especificador de comprimento inválido na expressão simbólica" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Sequência de caracteres demasiado longa na expressão simbólica" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Parênteses não correspondidos na expressão simbólica" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "Expressão simbólica não canónica" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Carácter errado na expressão simbólica" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Plicas erradas na expressão simbólica" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Prefixo zero na expressão simbólica" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Dicas de exibição aninhadas na expressão simbólica" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Dicas de exibição não correspondidas" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Pontuação reservada não esperada na expressão simbólica" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Carácter hexadecimal errado na expressão simbólica" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Números hexadecimais ímpares na expressão simbólica" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Carácter octal errado na expressão simbólica" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Dados não encriptados" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Nome desconhecido" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Sem chave pública" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Buffer demasiado curto" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Linha demasiado longa" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Sem cadeia de certificados" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Certificado é demasiado grande" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Registo inválido" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "O MAC não se verifica" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Mensagem inesperada" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Compressão ou descompressão falhada" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Um contador daria a volta" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Mensagem de alerta fatal recebida" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Algoritmo de criptografia inexistente" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Certificado cliente em falta" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Notificação de encerramento recebida" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Ticket expirou" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Ticket errado" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Identidade desconhecida" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Mensagem de certificado errada no handshake" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Mensagem de pedido de certificado errada no handshake" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Mensagem de verificação de certificado errada no handshake" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Mensagem de alteração de certificado errada no handshake" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Mensagem de hello do cliente errada no handshake" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Mensagem de hello do servidor errada no handshake" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "Mensagem de hello done do servidor errada no handshake" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Mensagem de conclusão errada no handshake" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Mensagem de troca de chaves do servidor errada no handshake" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Mensagem de troca de chaves do cliente errada no handshake" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Sequência de caracteres adulterada" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Chave desabilitada" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Não possível com uma chave baseada num cartão" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Objecto de tranca inválido" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Erro genérico de IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Chamada de aceitação de IPC falhada" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Chamada de conexão de IPC falhada" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Resposta de IPC inválida" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Valor inválido passado ao IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Linha inválida passada ao IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Linha passada ao IPC demasiado longa" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Comandos IPC aninhados" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Sem retorno de chamada de dados no IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Sem retorno de chamada de inquirição no IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Não é um servidor IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Não é um cliente IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problema na iniciação do servidor IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Erro de leitura de IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Erro de escrita de IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Demasiados dados para a camada IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Comando IPC inesperado" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Comando IPC desconhecido" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Erro de sintaxe IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Chamada de IPC foi cancelada" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Sem fonte de entrada para o IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Nenhuma fonte de saída para IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Erro de parâmetro IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Inquirição IPC desconhecida" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "No crypto engine" +msgid "Crypto engine too old" +msgstr "Sem motor de encriptação" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Valor duplicado" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certificado demasiado novo" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "O objecto fornecido é demasiado curto" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Nome desconhecido" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Código de operação inválido" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Nome desconhecido" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Não habilitado" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Protecção não suportada" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Nenhum agente em execução" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Erro no demónio de SmartCard" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Erro no servidor de chaves" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Erro de sistema desconhecido" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Sequência OID inválida" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Expressão simbólica inválida" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing issuer certificate" +msgid "Missing DNS query packet" +msgstr "Certificado do emissor em falta" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Desencriptação falhada" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Tempo limite" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Erro genérico de IPC" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Erro genérico" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Erro genérico" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Erro Assuan genérico" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Erro genérico" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Erro Assuan genérico" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Erro de escrita de IPC" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Erro genérico de IPC" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Chamada de conexão de IPC falhada" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Erro genérico" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Reinicialização de cartão necessária" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Elemento não encontrado" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Não suportado" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Erro inesperado" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Operação não suportada" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Certificado errado" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Extensão desconhecida" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Tempo limite" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "Erro no dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "Erro no dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Erro de leitura de IPC" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Não é um servidor IPC" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Sucesso" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Erro de configuração" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Violação de protocolo" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Extensão desconhecida" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +#, fuzzy +#| msgid "Fatal alert message received" +msgid "Partial LDAP results+referral received" +msgstr "Mensagem de alerta fatal recebida" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Erro genérico" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Reinicialização de cartão necessária" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Atributo inválido" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Protecção não suportada" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Violação de protocolo" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Estado inválido" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Sem objecto CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Problema de hardware" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Estado inválido" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Problema de codificação" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Protecção não suportada" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Cartão inválido" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +#, fuzzy +#| msgid "No keyserver available" +msgid "LDAP server is unavailable" +msgstr "Sem servidor de chaves disponível" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Acção em falta" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Violação de protocolo" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Operação ainda não completada" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Operação cancelada" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Linha demasiado longa" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Operação cancelada" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Erro genérico de IPC" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Recursos esgotados" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Violação de protocolo" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Estado inválido" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Certificado não suportado" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Reinicialização de cartão necessária" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Sucesso" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Não operacional" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Não operacional" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Não é um servidor IPC" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Desencriptação falhada" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Código de erro definido pelo utilizador 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Código de erro definido pelo utilizador 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Código de erro definido pelo utilizador 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Código de erro definido pelo utilizador 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Código de erro definido pelo utilizador 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Código de erro definido pelo utilizador 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Código de erro definido pelo utilizador 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Código de erro definido pelo utilizador 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Código de erro definido pelo utilizador 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Código de erro definido pelo utilizador 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Código de erro definido pelo utilizador 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Código de erro definido pelo utilizador 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Código de erro definido pelo utilizador 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Código de erro definido pelo utilizador 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Código de erro definido pelo utilizador 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Código de erro definido pelo utilizador 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Sucesso" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Erro de sintaxe" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Violação de protocolo" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Erro de sistema sem errno" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Erro de sistema desconhecido" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Fim do ficheiro" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Código de erro desconhecido" + +#: src/argparse.c:468 +#, fuzzy +msgid "argument not expected" +msgstr "a escrever chave privada para `%s'\n" + +#: src/argparse.c:470 +#, fuzzy +msgid "read error" +msgstr "erro de leitura" + +#: src/argparse.c:472 +#, fuzzy +msgid "keyword too long" +msgstr "frase secreta demasiado longa\n" + +#: src/argparse.c:474 +#, fuzzy +msgid "missing argument" +msgstr "argumento inválido" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid armor" +msgid "invalid argument" +msgstr "armadura inválida" + +#: src/argparse.c:478 +#, fuzzy +msgid "invalid command" +msgstr "comandos em conflito\n" + +#: src/argparse.c:480 +#, fuzzy +msgid "invalid alias definition" +msgstr "opções de importação inválidas\n" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Erro de configuração" + +#: src/argparse.c:484 src/argparse.c:517 +#, fuzzy +msgid "out of core" +msgstr "não processado" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +msgid "invalid meta command" +msgstr "comandos em conflito\n" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Comando desconhecido" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Comando IPC inesperado" + +#: src/argparse.c:494 +#, fuzzy +msgid "invalid option" +msgstr "opções de importação inválidas\n" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, fuzzy, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "opções de importação inválidas\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, fuzzy, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "Comando inválido (tente \"help\")\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "opções de importação inválidas\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "aviso: não consegui reconhecer %s\n" + +#, fuzzy +#~ msgid "out of core\n" +#~ msgstr "não processado" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Utilização: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Recursos esgotados" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Dados inválidos" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Erro genérico" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "Erro no dirmngr" diff --git a/comm/third_party/libgpg-error/po/quot.sed b/comm/third_party/libgpg-error/po/quot.sed new file mode 100644 index 0000000000..0122c46318 --- /dev/null +++ b/comm/third_party/libgpg-error/po/quot.sed @@ -0,0 +1,6 @@ +s/"\([^"]*\)"/“\1â€/g +s/`\([^`']*\)'/‘\1’/g +s/ '\([^`']*\)' / ‘\1’ /g +s/ '\([^`']*\)'$/ ‘\1’/g +s/^'\([^`']*\)' /‘\1’ /g +s/“â€/""/g diff --git a/comm/third_party/libgpg-error/po/remove-potcdate.sin b/comm/third_party/libgpg-error/po/remove-potcdate.sin new file mode 100644 index 0000000000..2436c49e78 --- /dev/null +++ b/comm/third_party/libgpg-error/po/remove-potcdate.sin @@ -0,0 +1,19 @@ +# Sed script that remove the POT-Creation-Date line in the header entry +# from a POT file. +# +# The distinction between the first and the following occurrences of the +# pattern is achieved by looking at the hold space. +/^"POT-Creation-Date: .*"$/{ +x +# Test if the hold space is empty. +s/P/P/ +ta +# Yes it was empty. First occurrence. Remove the line. +g +d +bb +:a +# The hold space was nonempty. Following occurrences. Do nothing. +x +:b +} diff --git a/comm/third_party/libgpg-error/po/ro.gmo b/comm/third_party/libgpg-error/po/ro.gmo new file mode 100644 index 0000000000..945ae69253 Binary files /dev/null and b/comm/third_party/libgpg-error/po/ro.gmo differ diff --git a/comm/third_party/libgpg-error/po/ro.po b/comm/third_party/libgpg-error/po/ro.po new file mode 100644 index 0000000000..3e4774b41e --- /dev/null +++ b/comm/third_party/libgpg-error/po/ro.po @@ -0,0 +1,2246 @@ +# Mesajele în limba română pentru libgpg-error. +# Copyright (C) 2005 Free Software Foundation, Inc. +# Acest fiÅŸier este distribuit sub aceeaÅŸi licenţă ca ÅŸi pachetul libgpg-error. +# Laurentiu Buzdugan , 2005. +# +# +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.1\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:42+0100\n" +"Last-Translator: Laurentiu Buzdugan \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Sursă nespecificată" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Introducere pin (pinentry)" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +#, fuzzy +msgid "Any source" +msgstr "Sursă necunoscută" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Sursă definită de utilizator 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Sursă definită de utilizator 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Sursă definită de utilizator 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Sursă definită de utilizator 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Sursă necunoscută" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Succes" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Eroare generală" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Pachet necunoscut" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "versiune necunoscută în pachet" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Algoritm cu cheie publică invalid" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Algoritm rezumat invalid" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Cheie publică incorectă" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Cheie secretă incorectă" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Semnătură incorectă" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Nici o cheie publică" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Eroare checksum" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Frază-parolă incorectă" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Algoritm cifrare invalid" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Inel de chei deschis" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Pachet invalid" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Armură invalidă" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Nici un ID utilizator." + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Nici o cheie secretă" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "A fost folosită o cheie secretă greÅŸită" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Cheie de sesiune incorectă" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Algoritm compresie necunoscut" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Numărul nu este prim" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Valoare de encodare invalidă" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Schemă de cifrare invalidă" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Schemă de semnături invalidă" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Argument invalid" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Nici o valoare" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Nu a fost găsit(ă)" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Valoarea nu a fost găsită" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Eroare de sintaxă" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Valoare MPI incorectă" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Frază-parolă invalidă" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Clasă semnături invalidă" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Resurse epuizate" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Inel de chei invalid" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Eroare bază de date încredere" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Certificat incorect" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "ID utilizator invalid" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Eroare neaÅŸteptată" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Conflict de timp" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Eroare server de chei" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Algoritm cheie publică greÅŸit" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Tribut lui D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Cheie de cifrare slabă" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Lungime cheie invalidă" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Argument invalid" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Eroare de sintaxă în URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "URI incorect" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Eroare reÅ£ea" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Gazdă necunoscută" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Auto-test eÅŸuat" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Date necifrate" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Date neprocesate" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Cheie publică de nefolosit" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "cheie secretă de nefolosit" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Valoare invalidă" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "LanÅ£ certificate incorect" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Certificat lipsă" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Nici o dată" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Bug" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Nu este suportat(ă)" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Cod operaÅ£ie invalid" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Pauză" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Eroare internă" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Obiect invalid" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Obiectul furnizat e prea scurt" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Obiectul furnizat e prea larg" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Articol lipsă în obiect" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Nu a fost implementat(ă)" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Folosire în conflict" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Mod cifru invalid" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Atribut invalid" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Handle invalid" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Rezultat invalid" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Linie incompletă" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Răspuns invalid" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Nu rulează nici un agent" + +#: src/err-codes.h:106 +#, fuzzy +#| msgid "agent error" +msgid "Agent error" +msgstr "eroare agent" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Date invalide" + +#: src/err-codes.h:108 +#, fuzzy +msgid "Unspecific Assuan server fault" +msgstr "Eroare server Assuan" + +#: src/err-codes.h:109 +#, fuzzy +msgid "General Assuan error" +msgstr "Eroare generală" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Cheie de sesiune invalidă" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Expresie-S invalidă" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Algoritm nesuportat" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Nici introducere pin (pinentry)" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "eroare introducere pin (pinentry) " + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "PIN incorect" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Nume invalid" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Date incorecte" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Parametru invalid" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Card greÅŸit" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Nici un dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "eroare dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certificat revocat" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Nici un CRL cunoscut" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL prea vechi" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Linie prea lungă" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Nu este de încredere" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "OperaÅ£iune anulată" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Certificat CA incorect" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certificat expirat" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certificat prea recent" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Certificat nesuportat" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Expresie-S necunoscută" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "ProtecÅ£ie nesuportată" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "ProtecÅ£ie coruptă" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Nume ambiguu" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Eroare card" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Este necesară resetarea cardului" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Card scos" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Card invalid" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Cardul nu este prezent" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Nici o aplicaÅ£ie PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Neconfirmat(ă)" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Eroare de configurare" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Nici o potrivire de politici" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Index invalid" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "ID invalid" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Nici un daemon SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Eroare daemon SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Protocol nesuportat" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Metodă PIN incorectă" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Card neiniÅ£ializat" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "OperaÅ£ie nesuportată" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Folosire cheie greÅŸită" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Nu a fost găsit nimic" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Tip de blob incorect" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Valoare lipsă" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Problemă hardware" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN blocat" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "CondiÅ£ii de folosire nesatisfăcute" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN-urile nu sunt sincronizate" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "CRL invalid" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Eroare BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "BER invalid" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Elementul nu a fost găsit" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identificator nu a fost găsit" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Etichetă invalidă" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Lungime invalidă" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "InformaÅ£ii cheie invalide" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Etichetă neaÅŸteptată" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Nu e encodat DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Nici un obiect CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Obiect CMS invalid" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Obiect CMS necunoscut" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Obiect CMS nesuportat" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Encodare nesuportată" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Versiune CMS nesuportată" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Algoritm necunoscut" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Motor cifrare invalid" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Cheia publică nu este de încredere" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Decriptarea a eÅŸuat" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Cheie expirată" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Semnătură expirată" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Problemă de encodare" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Stare invalidă" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Valoare dublă" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "AcÅ£iune lipsă" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Modulul ASN.1 nu a fost găsit" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Åžir OID invalid" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Timp invalid" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Obiect CRL invalid" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Versiune CRL nesuportată" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Obiect certificat incorect" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Nume necunoscut" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "O funcÅ£ie locale a eÅŸuat" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "NeforÅ£at(ă)" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Violare de protocol" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "MAC invalid" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Cerere invalidă" + +#: src/err-codes.h:199 +#, fuzzy +msgid "Unknown extension" +msgstr "Expresie-S necunoscută" + +#: src/err-codes.h:200 +#, fuzzy +msgid "Unknown critical extension" +msgstr "Expresie-S necunoscută" + +#: src/err-codes.h:201 +#, fuzzy +msgid "Locked" +msgstr "NeforÅ£at(ă)" + +#: src/err-codes.h:202 +#, fuzzy +msgid "Unknown option" +msgstr "Expresie-S necunoscută" + +#: src/err-codes.h:203 +#, fuzzy +msgid "Unknown command" +msgstr "Cod de eroare necunoscut" + +#: src/err-codes.h:204 +#, fuzzy +msgid "Not operational" +msgstr "OperaÅ£ie nesuportată" + +#: src/err-codes.h:205 +#, fuzzy +msgid "No passphrase given" +msgstr "Frază-parolă incorectă" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "" + +#: src/err-codes.h:207 +#, fuzzy +msgid "Not enabled" +msgstr "NeforÅ£at(ă)" + +#: src/err-codes.h:208 +#, fuzzy +msgid "No crypto engine" +msgstr "Motor cifrare invalid" + +#: src/err-codes.h:209 +#, fuzzy +msgid "Missing key" +msgstr "Valoare lipsă" + +#: src/err-codes.h:210 +#, fuzzy +msgid "Too many objects" +msgstr "Nici un obiect CMS" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +#, fuzzy +msgid "Not initialized" +msgstr "Card neiniÅ£ializat" + +#: src/err-codes.h:213 +#, fuzzy +msgid "Missing issuer certificate" +msgstr "Certificat lipsă" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +#, fuzzy +msgid "Invalid elliptic curve" +msgstr "Timp invalid" + +#: src/err-codes.h:216 +#, fuzzy +msgid "Unknown elliptic curve" +msgstr "Sursă necunoscută" + +#: src/err-codes.h:217 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated key" +msgstr "Valoare dublă" + +#: src/err-codes.h:218 +#, fuzzy +#| msgid "Ambiguous name" +msgid "Ambiguous result" +msgstr "Nume ambiguu" + +#: src/err-codes.h:219 +#, fuzzy +msgid "No crypto context" +msgstr "Motor cifrare invalid" + +#: src/err-codes.h:220 +#, fuzzy +msgid "Wrong crypto context" +msgstr "Motor cifrare invalid" + +#: src/err-codes.h:221 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Bad crypto context" +msgstr "Motor cifrare invalid" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +#, fuzzy +#| msgid "No public key" +msgid "Broken public key" +msgstr "Nici o cheie publică" + +#: src/err-codes.h:224 +#, fuzzy +#| msgid "No secret key" +msgid "Broken secret key" +msgstr "Nici o cheie secretă" + +#: src/err-codes.h:225 +#, fuzzy +#| msgid "Invalid digest algorithm" +msgid "Invalid MAC algorithm" +msgstr "Algoritm rezumat invalid" + +#: src/err-codes.h:226 +#, fuzzy +msgid "Operation fully cancelled" +msgstr "OperaÅ£iune anulată" + +#: src/err-codes.h:227 +#, fuzzy +msgid "Operation not yet finished" +msgstr "OperaÅ£iune anulată" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffer prea scurt" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Specificarea lungimii invalidă în expresia-S" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Åžir prea lung în expresia-S" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Paranteză fără pereche în expresia-S" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "Expresia-S nu este canonică" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Caracter invalid în expresia-S" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Ghilimele incorecte în expresia-S" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Prefix zero în expresia-S" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "IndicaÅ£ii de afiÅŸare încuibărite în expresia-S" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "IndicaÅ£ii de afiÅŸare fără pereche" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "PunctuaÅ£ie rezervată neaÅŸteptată în expresia-S" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Caracter hexazecimal incorect în expresia-S" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Numere hexazecimale ciudate în expresia-S" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Caracter octal incorect în expresia-S" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Date necifrate" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Nume necunoscut" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Nici o cheie publică" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Buffer prea scurt" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Linie prea lungă" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "No certificate chain" +msgstr "LanÅ£ certificate incorect" + +#: src/err-codes.h:252 +#, fuzzy +#| msgid "Certificate too young" +msgid "Certificate is too large" +msgstr "Certificat prea recent" + +#: src/err-codes.h:253 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid record" +msgstr "Card invalid" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +#, fuzzy +#| msgid "Unexpected tag" +msgid "Unexpected message" +msgstr "Etichetă neaÅŸteptată" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +#, fuzzy +#| msgid "Invalid cipher algorithm" +msgid "No cipher algorithm" +msgstr "Algoritm cifrare invalid" + +#: src/err-codes.h:260 +#, fuzzy +msgid "Missing client certificate" +msgstr "Certificat lipsă" + +#: src/err-codes.h:261 +#, fuzzy +#| msgid "Certificate revoked" +msgid "Close notification received" +msgstr "Certificat revocat" + +#: src/err-codes.h:262 +#, fuzzy +#| msgid "Key expired" +msgid "Ticket expired" +msgstr "Cheie expirată" + +#: src/err-codes.h:263 +#, fuzzy +#| msgid "Bad public key" +msgid "Bad ticket" +msgstr "Cheie publică incorectă" + +#: src/err-codes.h:264 +#, fuzzy +#| msgid "Unknown packet" +msgid "Unknown identity" +msgstr "Pachet necunoscut" + +#: src/err-codes.h:265 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "Bad certificate message in handshake" +msgstr "LanÅ£ certificate incorect" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +#, fuzzy +#| msgid "Key expired" +msgid "Key disabled" +msgstr "Cheie expirată" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +#, fuzzy +#| msgid "Invalid object" +msgid "Invalid lock object" +msgstr "Obiect invalid" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +#, fuzzy +msgid "General IPC error" +msgstr "Eroare generală" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "" + +#: src/err-codes.h:285 +#, fuzzy +msgid "Invalid IPC response" +msgstr "Răspuns invalid" + +#: src/err-codes.h:286 +#, fuzzy +msgid "Invalid value passed to IPC" +msgstr "Valoare invalidă" + +#: src/err-codes.h:287 +#, fuzzy +msgid "Incomplete line passed to IPC" +msgstr "Linie incompletă" + +#: src/err-codes.h:288 +#, fuzzy +msgid "Line passed to IPC too long" +msgstr "Linie prea lungă" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "" + +#: src/err-codes.h:295 +#, fuzzy +msgid "IPC read error" +msgstr "Eroare card" + +#: src/err-codes.h:296 +#, fuzzy +msgid "IPC write error" +msgstr "Eroare card" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "" + +#: src/err-codes.h:298 +#, fuzzy +msgid "Unexpected IPC command" +msgstr "Etichetă neaÅŸteptată" + +#: src/err-codes.h:299 +#, fuzzy +msgid "Unknown IPC command" +msgstr "Cod de eroare necunoscut" + +#: src/err-codes.h:300 +#, fuzzy +msgid "IPC syntax error" +msgstr "Eroare de sintaxă" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "" + +#: src/err-codes.h:304 +#, fuzzy +msgid "IPC parameter error" +msgstr "Eroare card" + +#: src/err-codes.h:305 +#, fuzzy +msgid "Unknown IPC inquire" +msgstr "Sursă necunoscută" + +#: src/err-codes.h:306 +#, fuzzy +msgid "Crypto engine too old" +msgstr "Motor cifrare invalid" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Valoare dublă" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certificat prea recent" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "Obiectul furnizat e prea scurt" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Nume necunoscut" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Cod operaÅ£ie invalid" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Nume necunoscut" + +#: src/err-codes.h:320 +#, fuzzy +msgid "Not authenticated" +msgstr "NeforÅ£at(ă)" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "ProtecÅ£ie nesuportată" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Nu rulează nici un agent" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Eroare daemon SmartCard" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Eroare server de chei" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Eroare de sistem necunoscută" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Åžir OID invalid" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Expresie-S invalidă" + +#: src/err-codes.h:330 +#, fuzzy +msgid "Missing DNS query packet" +msgstr "Certificat lipsă" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Decriptarea a eÅŸuat" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Pauză" + +#: src/err-codes.h:335 +#, fuzzy +msgid "General LDAP error" +msgstr "Eroare generală" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Eroare generală" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Eroare generală" + +#: src/err-codes.h:338 +#, fuzzy +msgid "General LDAP security error" +msgstr "Eroare generală" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Eroare generală" + +#: src/err-codes.h:340 +#, fuzzy +msgid "General LDAP update error" +msgstr "Eroare generală" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +msgid "Private LDAP error code" +msgstr "Eroare card" + +#: src/err-codes.h:343 +#, fuzzy +msgid "Other general LDAP error" +msgstr "Eroare generală" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP connecting failed (X)" +msgstr "Decriptarea a eÅŸuat" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Eroare generală" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Este necesară resetarea cardului" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Elementul nu a fost găsit" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Nu este suportat(ă)" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Eroare neaÅŸteptată" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "OperaÅ£ie nesuportată" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Certificat incorect" + +#: src/err-codes.h:355 +#, fuzzy +msgid "Unknown LDAP authentication method" +msgstr "Expresie-S necunoscută" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Pauză" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "eroare dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "eroare dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +msgid "LDAP local error" +msgstr "Eroare card" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Succes" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Eroare de configurare" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Violare de protocol" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +msgid "LDAP authentication method not supported" +msgstr "Expresie-S necunoscută" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Eroare generală" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Este necesară resetarea cardului" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Argument invalid" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "ProtecÅ£ie nesuportată" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Violare de protocol" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Stare invalidă" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Nici un obiect CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Problemă hardware" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Stare invalidă" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Problemă de encodare" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "ProtecÅ£ie nesuportată" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Card invalid" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "AcÅ£iune lipsă" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Violare de protocol" + +#: src/err-codes.h:397 +#, fuzzy +msgid "LDAP operation not allowed on non-leaf" +msgstr "OperaÅ£iune anulată" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "OperaÅ£iune anulată" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Linie prea lungă" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "OperaÅ£iune anulată" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +msgid "Other LDAP error" +msgstr "Eroare generală" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Resurse epuizate" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Violare de protocol" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Stare invalidă" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Certificat nesuportat" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Este necesară resetarea cardului" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Succes" + +#: src/err-codes.h:411 +#, fuzzy +msgid "No LDAP operation to cancel" +msgstr "OperaÅ£ie nesuportată" + +#: src/err-codes.h:412 +#, fuzzy +msgid "Too late to cancel LDAP" +msgstr "OperaÅ£ie nesuportată" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Decriptarea a eÅŸuat" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Cod de eroare definit de utilizator 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Cod de eroare definit de utilizator 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Cod de eroare definit de utilizator 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Cod de eroare definit de utilizator 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Cod de eroare definit de utilizator 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Cod de eroare definit de utilizator 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Cod de eroare definit de utilizator 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Cod de eroare definit de utilizator 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Cod de eroare definit de utilizator 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Cod de eroare definit de utilizator 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Cod de eroare definit de utilizator 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Cod de eroare definit de utilizator 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Cod de eroare definit de utilizator 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Cod de eroare definit de utilizator 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Cod de eroare definit de utilizator 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Cod de eroare definit de utilizator 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Succes" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Eroare de sintaxă" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Violare de protocol" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Eroare de sistem necunoscută" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "SfârÅŸit de fiÅŸier" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Cod de eroare necunoscut" + +#: src/argparse.c:468 +#, fuzzy +msgid "argument not expected" +msgstr "Nu sunt permise comenzi administrare\n" + +#: src/argparse.c:470 +#, fuzzy +msgid "read error" +msgstr "eroare citire fiÅŸier" + +#: src/argparse.c:472 +#, fuzzy +msgid "keyword too long" +msgstr "linie prea lungă" + +#: src/argparse.c:474 +#, fuzzy +msgid "missing argument" +msgstr "argument invalid" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid armor" +msgid "invalid argument" +msgstr "armură invalidă" + +#: src/argparse.c:478 +#, fuzzy +msgid "invalid command" +msgstr "Comandă numai-administrare\n" + +#: src/argparse.c:480 +#, fuzzy +msgid "invalid alias definition" +msgstr "opÅ£iuni enumerare invalide\n" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Eroare de configurare" + +#: src/argparse.c:484 src/argparse.c:517 +#, fuzzy +msgid "out of core" +msgstr "neforÅ£at(ă)" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +msgid "invalid meta command" +msgstr "Comandă numai-administrare\n" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +msgid "unknown meta command" +msgstr "Cod de eroare necunoscut" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +msgid "unexpected meta command" +msgstr "Etichetă neaÅŸteptată" + +#: src/argparse.c:494 +#, fuzzy +msgid "invalid option" +msgstr "opÅ£iuni enumerare invalide\n" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, fuzzy, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "opÅ£iuni enumerare invalide\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, fuzzy, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "Comandă invalidă (încercaÅ£i \"ajutor\")\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "opÅ£iuni enumerare invalide\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "avertisment: nu am putut recunoaÅŸte %s\n" + +#, fuzzy +#~ msgid "out of core\n" +#~ msgstr "neforÅ£at(ă)" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Folosire: %s EROARE-GPG [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Resurse epuizate" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Date invalide" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Eroare generală" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "eroare dirmngr" diff --git a/comm/third_party/libgpg-error/po/ru.gmo b/comm/third_party/libgpg-error/po/ru.gmo new file mode 100644 index 0000000000..85a4bec806 Binary files /dev/null and b/comm/third_party/libgpg-error/po/ru.gmo differ diff --git a/comm/third_party/libgpg-error/po/ru.po b/comm/third_party/libgpg-error/po/ru.po new file mode 100644 index 0000000000..c11fe83819 --- /dev/null +++ b/comm/third_party/libgpg-error/po/ru.po @@ -0,0 +1,2016 @@ +# Russian translation for libgpg-error. +# Copyright (C) 2020 Free Software Foundation, Inc. +# This file is distributed under the same license as the original package. +# Ineiev , 2014, 2015, 2018, 2019, 2020 +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:43+0100\n" +"Last-Translator: Ineiev \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Ðеуказанный иÑточник" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "Ðгент GPG" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Программа ввода паролÑ" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Щит Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡ÐµÐ¹" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Любой иÑточник" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "ПользовательÑкий иÑточник 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "ПользовательÑкий иÑточник 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "ПользовательÑкий иÑточник 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "ПользовательÑкий иÑточник 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "ÐеизвеÑтный иÑточник" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "УÑпешное завершение" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "ÐеизвеÑтный пакет" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð² пакете" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "ÐедопуÑтимый алгоритм ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ ключом" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñ…ÐµÑˆ-функциÑ" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Плохой открытый ключ" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Плохой Ñекретный ключ" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "ÐŸÐ»Ð¾Ñ…Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Ðет открытого ключа" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Ошибка контрольной Ñуммы" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "ÐŸÐ»Ð¾Ñ…Ð°Ñ Ñ„Ñ€Ð°Ð·Ð°-пароль" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "ÐедопуÑтимый алгоритм Ñимметричного шифрованиÑ" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Таблица ключей не открываетÑÑ" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "ÐедопуÑтимый пакет" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñ‚ÐµÐºÑÑ‚Ð¾Ð²Ð°Ñ Ð¾Ð±Ð¾Ð»Ð¾Ñ‡ÐºÐ°" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Ðет идентификатора пользователÑ" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Ðет Ñекретного ключа" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "ИÑпользован неверный Ñекретный ключ" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Плохой ÑеанÑовый ключ" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "ÐеизвеÑтный алгоритм ÑжатиÑ" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "ЧиÑло не проÑтое" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "ÐедопуÑтимый метод кодированиÑ" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñхема шифрованиÑ" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñхема подпиÑи" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "ÐедопуÑтимый атрибут" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Ðет значениÑ" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Ðе найдено" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Значение не найдено" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "СинтакÑичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Плохое значение MPI" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñ„Ñ€Ð°Ð·Ð°-пароль" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "ÐедопуÑтимый клаÑÑ Ð¿Ð¾Ð´Ð¿Ð¸Ñи" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Ðехватка реÑурÑов" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° ключей" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Ошибка таблицы довериÑ" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Плохой Ñертификат" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "ÐедопуÑтимый идентификатор пользователÑ" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "ÐÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Противоречие времен" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Ошибка Ñервера ключей" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Ðеверный алгоритм ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ ключом" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Ð‘Ð»Ð°Ð³Ð¾Ð´Ð°Ñ€Ñ D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Слабый ключ шифрованиÑ" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð´Ð»Ð¸Ð½Ð° ключа" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "ÐедопуÑтимый аргумент" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "СинтакÑичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° в URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "ÐедопуÑтимый URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Ошибка Ñети" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "ÐеизвеÑтный хоÑÑ‚" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Сбой при Ñамопроверке" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Данные не зашифрованы" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Данные не обработаны" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Ðепригодный открытый ключ" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Ðепригодный Ñекретный ключ" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "ÐедопуÑтимое значение" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "ÐŸÐ»Ð¾Ñ…Ð°Ñ Ñ†ÐµÐ¿ÑŒ Ñертификатов" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Ðе хватает Ñертификата" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Ðет данных" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Ошибка в программе" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Ðе поддерживаетÑÑ" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "ÐедопуÑтимый код операции" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð¸Ñчерпано" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "Конец файла (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "ÐедопуÑтимый объект" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Введенный объект Ñлишком мал" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Введенный объект Ñлишком велик" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Ð’ объекте недоÑтает Ñлемента" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Ðе реализовано" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Противоречивое иÑпользование" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "ÐедопуÑтимый решим шифрованиÑ" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "ÐедопуÑтимый признак" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "ÐедопуÑтимый указатель" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Результат уÑечен" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "ÐÐµÐ¿Ð¾Ð»Ð½Ð°Ñ Ñтрока" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "ÐедопуÑтимый ответ" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Ðгент не работает" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Ошибка агента" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "ÐедопуÑтимые данные" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Ðеуточненный отказ Ñервера Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° Assuan" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "ÐедопуÑтимый ÑеанÑовый ключ" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "ÐедопуÑтимое S-выражение" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Ðлгоритм не поддерживаетÑÑ" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Ðет программы ввода паролÑ" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "ошибка при вводе паролÑ" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Плохой пароль" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "ÐедопуÑтимое имÑ" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Плохие данные" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "ÐедопуÑтимый параметр" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð°" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Ðет dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "ошибка dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Сертификат отозван" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "ОтÑутÑтвует ÑпиÑок отозванных Ñертификатов" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "СпиÑок отозванных Ñертификатов Ñлишком Ñтар" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Слишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñтрока" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Ðе доверенный" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ð¼ÐµÐ½ÐµÐ½Ð°" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Плохой Ñертификат центра Ñертификации" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Срок дейÑÑ‚Ð²Ð¸Ñ Ñертификата иÑтек" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Сертификат Ñлишком новый" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Сертификат не поддерживаетÑÑ" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "ÐеизвеÑтное S-выражение" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Защита не поддерживаетÑÑ" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Повреждение защиты" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Ðеоднозначное имÑ" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Ошибка карты" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "ТребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑк карты" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Карта вынута" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "ÐÐµÐ¿Ñ€Ð¸Ð³Ð¾Ð´Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð°" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Карта отÑутÑтвует" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Ðет Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Ðет подтверждениÑ" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Ошибка конфигурации" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Ðет ÑоответÑтвующего правила" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "ÐедопуÑтимый индекÑ" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "ÐедопуÑтимый идентификатор" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Ðет демона криптографичеÑких карт" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Ошибка демона криптографичеÑких карт" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Протокол не поддерживаетÑÑ" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Плохой метод PIN" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Карта не инициализирована" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð½Ðµ поддерживаетÑÑ" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Ðеверное применение ключей" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Ðичего не найдено" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Данные неподходÑщего типа" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Ðе хватает значениÑ" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "ÐÐ¿Ð¿Ð°Ñ€Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð°" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN заблокирован" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Ðарушены уÑÐ»Ð¾Ð²Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "Разные PIN не Ñинхронизированы" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "ÐедопуÑтимый ÑпиÑок отозванных Ñертификатов" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Ошибка BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "ÐедопуÑтимый BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Элемент не найден" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Идентификатор не найден" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "ÐедопуÑтимый тег" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð´Ð»Ð¸Ð½Ð°" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð°" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Ðеожиданный тег" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Ðе закодировано по DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Ðет объекта CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "ÐедопуÑтимый объект CMS" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "ÐеизвеÑтный объект CMS" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Объект CMS не поддерживаетÑÑ" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Кодировка не поддерживаетÑÑ" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "ВерÑÐ¸Ñ CMS не поддерживаетÑÑ" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "ÐеизвеÑтный алгоритм" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "ÐедопуÑтимый криптомеханизм" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Открытый ключ не доверенный" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Сбой раÑшифрованиÑ" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð° иÑтек" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Срок дейÑÑ‚Ð²Ð¸Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñи иÑтек" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Проблема Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ¾Ð¹" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "ÐедопуÑтимое ÑоÑтоÑние" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Величина продублирована" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Ðе хватает дейÑтвиÑ" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Модуль ASN.1 не найден" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñтрока OID" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "ÐедопуÑтимое времÑ" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "ÐедопуÑтимый объект ÑпиÑка отозванных Ñертификатов" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "ВерÑÐ¸Ñ ÑпиÑка отозванных Ñертификатов не поддерживаетÑÑ" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "ÐедопуÑтимый объект Ñертификата" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "ÐеизвеÑтное имÑ" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Сбой функции локализации" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Ðет блокировки" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Ðарушение протокола" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "ÐедопуÑтимый MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "ÐедопуÑтимый запроÑ" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "ÐеизвеÑтное раÑширение" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "ÐеизвеÑтное критичеÑкое раÑширение" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Заблокировано" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "ÐеизвеÑтный параметр" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Ðе работоÑпоÑобно" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Фраза-пароль не задана" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "PIN не задан" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Отключено" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Ðет криптомеханизма" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Ðе хватает ключа" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Слишком много объектов" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "ДоÑтигнут предел" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Ðе инициализировано" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Ðе хватает Ñертификата издателÑ" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Серверы ключей недоÑтупны" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ ÑллиптичеÑÐºÐ°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÑллиптичеÑÐºÐ°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Ключ продублирован" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Ðеоднозначный результат" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Ðет криптоконтекÑта" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Ðеверный криптоконтекÑÑ‚" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Плохой криптоконтекÑÑ‚" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Противоречивый криптоконтекÑÑ‚" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Открытый ключ поврежден" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Секретный ключ поврежден" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "ÐедопуÑтимый алгоритм MAC" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð»Ð½Ð¾Ñтью отменена" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ ÐµÑ‰Ðµ не завершена" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Слишком короткий буфер" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "ÐедопуÑтимый Ñпецификатор длины в S-выражении" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Слишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñтрока в S-выражении" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Ðепарные Ñкобки в S-выражении" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-выражение неканонично" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Плохой Ñимвол в S-выражении" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Плохие кавычки в S-выражении" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Ðулевой Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ Ð² S-выражении" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Вложенные квадратные Ñкобки в S-выражении" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Ðепарные квадратные Ñкобки" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "ÐÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð·Ð°Ñ€ÐµÐ·ÐµÑ€Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¿ÑƒÐ½ÐºÑ‚ÑƒÐ°Ñ†Ð¸Ñ Ð² S-выражении" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Плохой шеÑтнадцатеричный Ñимвол в S-выражении" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Ðечетные шеÑтнадцатеричные чиÑла в S-выражении" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Плохой воÑьмеричный Ñимвол в S-выражении" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "Ð’Ñе подключи проÑрочены или отозваны" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "База данных повреждена" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "Сервер указал на Ñбой" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "Ðет имени" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "Ðет ключа" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "Старый ключ" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "Слишком короткий запроÑ" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "Слишком длинный запроÑ" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "Объект в Ñтадии завершениÑ" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Ðет цепи Ñертификатов" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Сертификат Ñлишком велик" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "MAC не проходит проверку" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Ðеожиданное Ñообщение" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Сбой ÑÐ¶Ð°Ñ‚Ð¸Ñ Ð¸Ð»Ð¸ извлечениÑ" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Было бы переполнение Ñчетчика" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Получено критичеÑкое предупреждение" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Ðет алгоритма Ñимметричного шифрованиÑ" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Ðе хватает Ñертификата клиента" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Получено уведомление о завершении" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ²Ð¸Ñ‚Ð°Ð½Ñ†Ð¸Ð¸ иÑтек" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "ÐŸÐ»Ð¾Ñ…Ð°Ñ ÐºÐ²Ð¸Ñ‚Ð°Ð½Ñ†Ð¸Ñ" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "ЛичноÑÑ‚ÑŒ неизвеÑтна" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Плохое Ñертификатное Ñообщение при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "Плохое Ñообщение запроÑа Ñертификата при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "Плохое Ñообщение проверки Ñертификата при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Плохое Ñообщение Ñмены шифра при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Плохое начальное Ñообщение клиента при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Плохое начальное Ñообщение Ñервера при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "ÐŸÐ»Ð¾Ñ…Ð°Ñ ÐºÐ²Ð¸Ñ‚Ð°Ð½Ñ†Ð¸Ñ Ñервера на начальное Ñообщение при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Плохое завершающее Ñообщение при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "Плохое Ñообщение обмена ключами Ñервера при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "Плохое Ñообщение обмена ключами клиента при уÑтановлении ÑвÑзи" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "ÐеÑÑƒÑ€Ð°Ð·Ð½Ð°Ñ Ñтрока" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "Запрещено" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Ключ отключен" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Ðевозможно Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð° на карте" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "ÐедопуÑтимый объект блокировки" + +#: src/err-codes.h:280 +msgid "True" +msgstr "ИÑтина" + +#: src/err-codes.h:281 +msgid "False" +msgstr "Ложь" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Сбой принÑÑ‚Ð¸Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð° IPC" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Сбой вызова ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ IPC" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "ÐедопуÑтимый ответ IPC" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Ð’ IPC передано недопуÑтимое значение" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Ð’ IPC передана Ð½ÐµÐ¿Ð¾Ð»Ð½Ð°Ñ Ñтрока" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Ð’ IPC передана Ñлишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñтрока" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Вложенные команды IPC" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Ð’ IPC нет функции обработки данных" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Ð’ IPC нет функции обработки запроÑа" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Ðе Ñервер IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Ðе клиент IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Проблема запуÑка Ñервера IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Ошибка запиÑи IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Слишком много данных Ð´Ð»Ñ ÑƒÑ€Ð¾Ð²Ð½Ñ IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "ÐÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° IPC" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° IPC" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "СинтакÑичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Вызов IPC отменен" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Ðет иÑточника входа Ð´Ð»Ñ IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Ðет иÑточника выхода Ð´Ð»Ñ IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Ошибка в параметре IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "ÐеизвеÑтный Ð·Ð°Ð¿Ñ€Ð¾Ñ IPC" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "Криптомеханизм Ñлишком Ñтар" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "Экран или окно Ñлишком мало" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "Экран или окно Ñлишком велико" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "Ð¢Ñ€ÐµÐ±ÑƒÐµÐ¼Ð°Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñреды не уÑтановлена" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "Идентификатор Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ ÑƒÐ¶Ðµ ÑущеÑтвует" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "Ð˜Ð¼Ñ ÑƒÐ¶Ðµ ÑущеÑтвует" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "Ð˜Ð¼Ñ Ð¿Ñ€Ð¾Ð´ÑƒÐ±Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¾" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "Объект Ñлишком нов" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "Объект Ñлишком Ñтар" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "ÐеизвеÑтный признак" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "ÐедопуÑтимый порÑдок выполнениÑ" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "Уже доÑтавлено" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "Повторите попытку позднее" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "No name" +msgid "Wrong name" +msgstr "Ðет имени" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not enabled" +msgid "Not authenticated" +msgstr "Отключено" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Inappropriate LDAP authentication" +msgid "Bad authentication" +msgstr "ÐеподходÑщее удоÑтоверение LDAP" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Ðгент не работает" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Ошибка демона криптографичеÑких карт" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Ошибка Ñервера ключей" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "Обнаружена ошибка в ÑиÑтеме" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° DNS" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "ÐедопуÑтимый раздел DNS" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "ÐедопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñ‚ÐµÐºÑÑ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ñ„Ð¾Ñ€Ð¼Ð° адреÑа" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "Ðе хватает пакета запроÑа DNS" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "Ðе хватает ответного пакета DNS" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "Ð’ DNS прервано Ñоединение" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "Сбой проверки в DNS" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "Лимит времени DNS" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° LDAP" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° в атрибуте LDAP" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° в имени LDAP" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° безопаÑноÑти LDAP" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° Ñлужбы LDAP" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "ÐžÐ±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ LDAP" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "ЭкÑпериментальный код ошибки LDAP" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "Внутренний код ошибки LDAP" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "Ð”Ñ€ÑƒÐ³Ð°Ñ Ð¾Ð±Ñ‰Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° LDAP" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "Отказ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ LDAP (X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "Слишком много ÑÑылок LDAP" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "Цикл клиента LDAP" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "Ðет результатов LDAP" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "Элемент ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ LDAP не найден" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "Ðе поддерживаетÑÑ Ñ„ÑƒÐ½ÐºÑ†Ð¸ÐµÐ¹ LDAP" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "Ошибка ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ LDAP" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "ИÑчерпана памÑÑ‚ÑŒ в LDAP" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "Ðеверный параметр процедуры LDAP" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "Пользователь отменил операцию LDAP" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "Плохой фильтр поиÑка LDAP" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "ÐеизвеÑтный метод удоÑÑ‚Ð¾Ð²ÐµÑ€ÐµÐ½Ð¸Ñ LDAP" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "Лимит времени в LDAP" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "Ошибка Ð´ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ LDAP" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "Ошибка ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ LDAP" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "Ð›Ð¾ÐºÐ°Ð»ÑŒÐ½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° LDAP" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "Ðе удалоÑÑŒ ÑвÑзатьÑÑ Ñ Ñервером LDAP" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "УÑпешное выполнение LDAP" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "Ошибка операций LDAP" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "Ошибка протокола LDAP" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "ИÑчерпан лимит времени в LDAP" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "ИÑчерпан лимит размера в LDAP" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "Сравнение LDAP: ложь" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "Сравнение LDAP: иÑтина" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "Метод удоÑÑ‚Ð¾Ð²ÐµÑ€ÐµÐ½Ð¸Ñ LDAP не поддерживаетÑÑ" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "ТребуетÑÑ (более) Ñильное удоÑтоверение LDAP" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "Получены чаÑтичные результаты LDAP Ñо ÑÑылкой" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "СÑылка LDAP" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "ИÑчерпан админиÑтративный лимит LDAP" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "ÐедоÑтупно критичное раÑширение LDAP" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "КонфиденциальноÑÑ‚ÑŒ, Ñ‚Ñ€ÐµÐ±ÑƒÐµÐ¼Ð°Ñ LDAP" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "ВыполнÑетÑÑ ÑвÑзка SASL LDAP" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "Такого атрибута LDAP нет" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "Ðеопределенный тип атрибута LDAP" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "ÐеподходÑщее ÑоответÑтвие в LDAP" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "Ðарушение ограничений в LDAP" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "Тип или значение LDAP ÑущеÑтвует" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "Ошибка ÑинтакÑиÑа в LDAP" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "Такого объекта LDAP нет" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "Проблема Ñинонима LDAP" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "Ошибка ÑинтакÑиÑа DN в LDAP" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "Элемент LDAP - лиÑÑ‚" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "Проблема Ñ€Ð°Ð·Ñ‹Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð¸Ñ Ñинонима LDAP" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "Отказ авторизации промежуточного Ñервера (X)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "ÐеподходÑщее удоÑтоверение LDAP" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "Ðеверные верительные данные LDAP" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "ÐедоÑтаточный доÑтуп Ð´Ð»Ñ LDAP" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "Сервер LDAP занÑÑ‚" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "Сервер LDAP недоÑтупен" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "Сервер LDAP отказываетÑÑ Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ñ‚ÑŒ" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "Функцией LDAP обнаружен цикл" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "Ðарушение в именах LDAP" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "Ðарушение в клаÑÑе объекта LDAP" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ LDAP допуÑтима только Ð´Ð»Ñ Ð»Ð¸Ñтов" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ LDAP над RDN не разрешена" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "Уже еÑÑ‚ÑŒ (LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "Ðевозможно изменить клаÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° LDAP" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "Слишком большой объем результатов LDAP" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ LDAP влиÑет на многие DSA" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "Ошибка проÑмотра виртуального ÑпиÑка LDAP" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "Ð”Ñ€ÑƒÐ³Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° LDAP" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "Ðехватка реÑурÑов в LCUP" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "Ðарушение безопаÑноÑти в LCUP" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "ÐедопуÑтимые данные в LCUP" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "Схема не поддерживаетÑÑ Ð² LCUP" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "ТребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑк в LCUP" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "Отбой LDAP" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "Ðет операции LDAP Ð´Ð»Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ñ‹" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "ОтменÑÑ‚ÑŒ LDAP Ñлишком поздно" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "Ðе удаетÑÑ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ LDAP" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "Ðе выполнено уÑловие в LDAP" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "LDAP отказал в опоÑредованной авторизации" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "ПользовательÑкий код ошибки 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "ПользовательÑкий код ошибки 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "ПользовательÑкий код ошибки 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "ПользовательÑкий код ошибки 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "ПользовательÑкий код ошибки 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "ПользовательÑкий код ошибки 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "ПользовательÑкий код ошибки 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "ПользовательÑкий код ошибки 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "ПользовательÑкий код ошибки 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "ПользовательÑкий код ошибки 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "ПользовательÑкий код ошибки 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "ПользовательÑкий код ошибки 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "ПользовательÑкий код ошибки 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "ПользовательÑкий код ошибки 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "ПользовательÑкий код ошибки 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "ПользовательÑкий код ошибки 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "LDAP success" +msgid "SQL success" +msgstr "УÑпешное выполнение LDAP" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "СинтакÑичеÑÐºÐ°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "LDAP protocol error" +msgid "SQL database lock protocol error" +msgstr "Ошибка протокола LDAP" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +#, fuzzy +#| msgid "Proxied authorization denied by LDAP" +msgid "Authorization denied (SQL)" +msgstr "LDAP отказал в опоÑредованной авторизации" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "СиÑÑ‚ÐµÐ¼Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° без номера" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÑиÑÑ‚ÐµÐ¼Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Конец файла" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "ÐеизвеÑтный код ошибки" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "неожиданный параметр" + +#: src/argparse.c:470 +msgid "read error" +msgstr "ошибка чтениÑ" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "Ñлишком длинное ключевое Ñлово" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "пропущен аргумент" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "недопуÑтимый аргумент" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "недопуÑÑ‚Ð¸Ð¼Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "недопуÑтимое определение Ñинонима" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "LDAP operations error" +msgid "permission error" +msgstr "Ошибка операций LDAP" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "нехватка выделенной памÑти" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "недопуÑÑ‚Ð¸Ð¼Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "ÐÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° IPC" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "недопуÑтимый параметр" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "не хватает аргумента Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° \"%.50s\"\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "недопуÑтимый аргумент Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° \"%.50s\"\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "у параметра \"%.50s\" не должно быть аргумента\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "недопуÑÑ‚Ð¸Ð¼Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "параметр \"%.50s\" неоднозначен\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "команда \"%.50s\" неоднозначна\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "недопуÑтимый параметр \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "Об ошибках Ñообщайте по адреÑу .\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "внимание: не раÑпознано %s\n" + +#~ msgid "out of core\n" +#~ msgstr "нехватка выделенной памÑти\n" diff --git a/comm/third_party/libgpg-error/po/sr.gmo b/comm/third_party/libgpg-error/po/sr.gmo new file mode 100644 index 0000000000..0749c2c11a Binary files /dev/null and b/comm/third_party/libgpg-error/po/sr.gmo differ diff --git a/comm/third_party/libgpg-error/po/sr.po b/comm/third_party/libgpg-error/po/sr.po new file mode 100644 index 0000000000..e14aa2e767 --- /dev/null +++ b/comm/third_party/libgpg-error/po/sr.po @@ -0,0 +1,2256 @@ +# Serbian translation for libgpg-error. +# Copyright (C) 2014 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# МироÑлав Ðиколић , 2014. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error-1.7\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:43+0100\n" +"Last-Translator: МироÑлав Ðиколић \n" +"Language-Team: Serbian <(nothing)>\n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Ðенаведени извор" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "гкрипт" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "ГнуПГ" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "ГпгСМ" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "ГПГ агент" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Ð£Ð½Ð¾Ñ Ð¿Ð¸Ð½Ð°" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "СЦД" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "ГПГМЕ" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Поље кључа" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "КСБÐ" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Управник директоријума" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "ГСТИ" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "ГПÐ" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Клеопатра" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Било који извор" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "1. кориÑников извор" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "2. кориÑников извор" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "3. кориÑников извор" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "4. кориÑников извор" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Ðепознат извор" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "УÑпешно" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Општа грешка" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Ðепознат пакет" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Ðепознато издање у пакету" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "ÐеиÑправан алгоритам јавног кључа" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Ðепознат алгоритам апÑорпције" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Лош јавни кључ" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Лош тајни кључ" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Лош потпиÑ" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Ðема јавног кључа" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Грешка провере Ñуме" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Лоша пропуÑна реч" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "ÐеиÑправан алгоритам шифровања" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Привезак кључева је отворен" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "ÐеиÑправан пакет" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "ÐеиÑправан штит" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Ðема ИБ-а кориÑника" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Ðема тајног кључа" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Коришћен је погрешан тајни кључ" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Лош кључ ÑеÑије" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Ðепознат алгоритам Ñажимања" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Број није проÑÑ‚" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "ÐеиÑправан начин кодирања" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "ÐеиÑправна шема шифровања" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "ÐеиÑправна шема потпиÑа" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "ÐеиÑправна оÑобина" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Ðема вредноÑти" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "ÐиÑам пронашао" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "ÐиÑам пронашао вредноÑÑ‚" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Садржајна грешка" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Лоша МПИ вредноÑÑ‚" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "ÐеиÑправна пропуÑна реч" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "ÐеиÑправан разред потпиÑа" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Изворишта Ñу иÑтрошена" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "ÐеиÑправан прÑтен кључа" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Грешка поверења БП-а" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Лош уверење" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "ÐеиÑправан ИБ-а кориÑника" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Ðеочекивана грешка" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Сукоб времена" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Грешка Ñервера кључа" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Погрешан алгоритам јавног кључа" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "У чаÑÑ‚ Д. Ð." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Слаб кључ шифровања" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "ÐеиÑправна дужина кључа" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "ÐеиÑправан аргумент" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Грешка израза у путањи" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "ÐеиÑправна путања" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Грешка мреже" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Ðепознат домаћин" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Самопроба није уÑпела" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Подаци ниÑу шифровани" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Подаци ниÑу обрађени" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Ðеупотребљив јавни кључ" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Ðеупотребљив тајни кључ" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "ÐеиÑправна вредноÑÑ‚" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Лош ланац уверења" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "ÐедоÑтаје уверење" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Ðема података" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Грешка" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Ðије подржано" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "ÐеиÑправна шифра радње" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Време је иÑтекло" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Унутрашња грешка" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "КРД (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "ÐеиÑправан предмет" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "ДоÑтављени предмет је прекратак" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "ДоÑтављени предмет је предуг" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "ÐедоÑтаје Ñтавка у предмету" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Ðије примењено" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Противна употреба" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "ÐеиÑправан код шифрера" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "ÐеиÑправна опција" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "ÐеиÑправна ручка" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Резултат је Ñкраћен" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Ðепотпун ред" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "ÐеиÑправан одговор" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Ðема покренутог агента" + +#: src/err-codes.h:106 +#, fuzzy +#| msgid "agent error" +msgid "Agent error" +msgstr "грешка агента" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "ÐеиÑправни подаци" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Ðеобичан неуÑпех ÐÑуан Ñервера" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Општа грешка ÐÑуана" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "ÐеиÑправан кључ ÑеÑије" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "ÐеиÑправан С-израз" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Ðеподржани алгоритам" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Ðема уноÑа пина" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "грешка уноÑа пина" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Лош ПИÐ" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "ÐеиÑправан назив" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Лоши подаци" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "ÐеиÑправан параметар" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Лоша картица" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Ðема управника директоријумом" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "грешка управника директоријумом" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Уверење је опозвано" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Ðема познатог ЦРЛ-а" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "ЦРЛ је преÑтар" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Ред је предуг" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Ðије од поверења" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Радња је отказана" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Лоше уверење издавача" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Уверење је иÑтекло" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Уверење је превише ново" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Ðеподржано уверење" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Ðепознат С-израз" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Ðеподржана заштита" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Оштећена заштита" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "ÐејаÑан назив" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Грешка картице" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Потребно је поновно поÑтављање картице" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Картица је уклоњена" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "ÐеиÑправна картица" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Картица није приÑутна" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Ðема ПКЦС15 програма" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Ðије потврђено" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Грешка подешавања" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Ðема одговарајуће политике" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "ÐеиÑправан индекÑ" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "ÐеиÑправан ИБ" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Ðема позадинца паметне картице" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Грешка позадинца паметне картице" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Ðеподржан протокол" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Лош начин ПИÐ-а" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Картица није покренута" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Ðеподржана радња" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Погрешна употреба кључа" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "ÐиÑам нашао ништа" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Погрешна врÑта бвоб-а" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "ÐедоÑтаје вредноÑÑ‚" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "ХардверÑки проблем" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "ПИРје блокиран" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "УÑлови коришћења ниÑу задовољени" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "ПИÐ-ови ниÑу уÑаглашени" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "ÐеиÑправан ЦРЛ" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Грешка БЕР-а" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "ÐеиÑправан БЕР" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "ÐиÑам пронашао елемент" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "ÐиÑам пронашао одредника" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "ÐеиÑправна ознака" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "ÐеиÑправна дужина" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "ÐеиÑправни подаци кључа" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Ðеочекивана ознака" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Ðије кодирано ДЕР-ом" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Ðије ЦМС предмет" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "ÐеиÑправан ЦМС предмет" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Ðепознат ЦМС предмет" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Ðеподржан ЦМС предмет" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Ðеподржано кодирање" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Ðеподржано ЦМС издање" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Ðепознат алгоритам" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "ÐеиÑправан погон шифровања" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Јавни кључ није поверљив" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Дешифровање није уÑпело" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Кључ је иÑтекао" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "ÐŸÐ¾Ñ‚Ð¿Ð¸Ñ Ñ˜Ðµ иÑтекао" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Проблем кодирања" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "ÐеиÑправно Ñтање" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "УдвоÑтручена вредноÑÑ‚" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "ÐедоÑтаје радња" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ÐиÑам пронашао модул ÐСÐ.1" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "ÐеиÑправна ОИД ниÑка" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "ÐеиÑправно време" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "ÐеиÑправан ЦРЛ предмет" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Ðеподржано ЦРЛ издање" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "ÐеиÑправан предмет уверења" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Ðепознат назив" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Језичка функција није уÑпела" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Ðије закључано" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Кршење протокола" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "ÐеиÑправан ÐœÐК" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "ÐеиÑправан захтев" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Ðепознато проширење" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Ðепознат критичан израз" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Закључано" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Ðепозната опција" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Ðепозната наредба" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Ðије делотворно" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Ðије дата пропуÑна реч" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Ðије дат ПИÐ" + +#: src/err-codes.h:207 +#, fuzzy +#| msgid "Not locked" +msgid "Not enabled" +msgstr "Ðије закључано" + +#: src/err-codes.h:208 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "No crypto engine" +msgstr "ÐеиÑправан погон шифровања" + +#: src/err-codes.h:209 +#, fuzzy +#| msgid "Missing value" +msgid "Missing key" +msgstr "ÐедоÑтаје вредноÑÑ‚" + +#: src/err-codes.h:210 +#, fuzzy +#| msgid "No CMS object" +msgid "Too many objects" +msgstr "Ðије ЦМС предмет" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +#, fuzzy +#| msgid "Card not initialized" +msgid "Not initialized" +msgstr "Картица није покренута" + +#: src/err-codes.h:213 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing issuer certificate" +msgstr "ÐедоÑтаје уверење" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +#, fuzzy +#| msgid "Invalid time" +msgid "Invalid elliptic curve" +msgstr "ÐеиÑправно време" + +#: src/err-codes.h:216 +#, fuzzy +#| msgid "Unknown source" +msgid "Unknown elliptic curve" +msgstr "Ðепознат извор" + +#: src/err-codes.h:217 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated key" +msgstr "УдвоÑтручена вредноÑÑ‚" + +#: src/err-codes.h:218 +#, fuzzy +#| msgid "Ambiguous name" +msgid "Ambiguous result" +msgstr "ÐејаÑан назив" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "" + +#: src/err-codes.h:221 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Bad crypto context" +msgstr "ÐеиÑправан погон шифровања" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +#, fuzzy +#| msgid "No public key" +msgid "Broken public key" +msgstr "Ðема јавног кључа" + +#: src/err-codes.h:224 +#, fuzzy +#| msgid "No secret key" +msgid "Broken secret key" +msgstr "Ðема тајног кључа" + +#: src/err-codes.h:225 +#, fuzzy +#| msgid "Invalid digest algorithm" +msgid "Invalid MAC algorithm" +msgstr "Ðепознат алгоритам апÑорпције" + +#: src/err-codes.h:226 +#, fuzzy +#| msgid "Operation cancelled" +msgid "Operation fully cancelled" +msgstr "Радња је отказана" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Радња није још завршена" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Међумеморија је прекратка" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "ÐеиÑправан одредник дужине у С-изразу" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "ÐиÑка је предуга у С-изразу" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Ðеодговарајуће заграде у С-изразу" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "С-израз није правилан" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Лош знак у С-изразу" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Лоше цитирање у С-изразу" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Ðулти Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ Ñƒ С-изразу" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Уграђени Ñавети приказа у С-изразу" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Ðеодговарајући Ñавети приказа" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Ðеочекивана резервиÑана тачка у С-изразу" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Лош хекÑадецимални знак у С-изразу" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Ðепарни хекÑадецимални бројеви у С-изразу" + +#: src/err-codes.h:241 +#, fuzzy +#| msgid "Bad octadecimal character in S-expression" +msgid "Bad octal character in S-expression" +msgstr "Лош октадецимални знак у С-изразу" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Подаци ниÑу шифровани" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Ðепознат назив" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Ðема јавног кључа" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Међумеморија је прекратка" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Ред је предуг" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "No certificate chain" +msgstr "Лош ланац уверења" + +#: src/err-codes.h:252 +#, fuzzy +#| msgid "Certificate too young" +msgid "Certificate is too large" +msgstr "Уверење је превише ново" + +#: src/err-codes.h:253 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid record" +msgstr "ÐеиÑправна картица" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +#, fuzzy +#| msgid "Unexpected tag" +msgid "Unexpected message" +msgstr "Ðеочекивана ознака" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +#, fuzzy +#| msgid "Invalid cipher algorithm" +msgid "No cipher algorithm" +msgstr "ÐеиÑправан алгоритам шифровања" + +#: src/err-codes.h:260 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing client certificate" +msgstr "ÐедоÑтаје уверење" + +#: src/err-codes.h:261 +#, fuzzy +#| msgid "Certificate revoked" +msgid "Close notification received" +msgstr "Уверење је опозвано" + +#: src/err-codes.h:262 +#, fuzzy +#| msgid "Key expired" +msgid "Ticket expired" +msgstr "Кључ је иÑтекао" + +#: src/err-codes.h:263 +#, fuzzy +#| msgid "Bad public key" +msgid "Bad ticket" +msgstr "Лош јавни кључ" + +#: src/err-codes.h:264 +#, fuzzy +#| msgid "Unknown packet" +msgid "Unknown identity" +msgstr "Ðепознат пакет" + +#: src/err-codes.h:265 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "Bad certificate message in handshake" +msgstr "Лош ланац уверења" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +#, fuzzy +#| msgid "Key expired" +msgid "Key disabled" +msgstr "Кључ је иÑтекао" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +#, fuzzy +#| msgid "Invalid object" +msgid "Invalid lock object" +msgstr "ÐеиÑправан предмет" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Општа грешка ИПЦ-а" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Прихватање позива ИПЦ-а није уÑпело" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Повезивање позива ИПЦ-а није уÑпело" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "ÐеиÑправан ИПЦ одговор" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "ÐеиÑправна вредноÑÑ‚ проÑлеђена ИПЦ-у" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Ðепотпун ред је проÑлеђен ИПЦ-у" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Ред проÑлеђен ИПЦ-у је предуг" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Уграђене ИПЦ наредбе" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Ðема опозива података у ИПЦ-у" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Ðема опозива раÑпитивања у ИПЦ-у" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Ðије ИПЦ Ñервер" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Ðије ИПЦ клијент" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Проблем покретања ИПЦ Ñервера" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Грешка читања ИПЦ-а" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Грешка пиÑања ИПЦ-а" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Превише података за ИПЦ Ñлој" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Ðеочекивана ИПЦ наредба" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Ðепозната ИПЦ наредба" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Садржајна грешка ИПЦ-а" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "ИПЦ позив је отказан" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Ðема извора улаза за ИПЦ" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Ðема извора излаза за ИПЦ" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Грешка параметра ИПЦ-а" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Ðепознато раÑпитивање ИПЦ-а" + +#: src/err-codes.h:306 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Crypto engine too old" +msgstr "ÐеиÑправан погон шифровања" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "УдвоÑтручена вредноÑÑ‚" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Уверење је превише ново" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "ДоÑтављени предмет је прекратак" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Ðепознат назив" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "ÐеиÑправна шифра радње" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Ðепознат назив" + +#: src/err-codes.h:320 +#, fuzzy +#| msgid "Not locked" +msgid "Not authenticated" +msgstr "Ðије закључано" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Ðеподржана заштита" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Ðема покренутог агента" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Грешка позадинца паметне картице" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Грешка Ñервера кључа" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Ðепозната грешка ÑиÑтема" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "ÐеиÑправна ОИД ниÑка" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "ÐеиÑправан С-израз" + +#: src/err-codes.h:330 +#, fuzzy +#| msgid "Missing certificate" +msgid "Missing DNS query packet" +msgstr "ÐедоÑтаје уверење" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Дешифровање није уÑпело" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Време је иÑтекло" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Општа грешка ИПЦ-а" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Општа грешка" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Општа грешка" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Општа грешка ÐÑуана" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Општа грешка" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Општа грешка ÐÑуана" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Грешка пиÑања ИПЦ-а" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Општа грешка ИПЦ-а" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Повезивање позива ИПЦ-а није уÑпело" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Општа грешка" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Потребно је поновно поÑтављање картице" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "ÐиÑам пронашао елемент" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Ðије подржано" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Ðеочекивана грешка" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Ðеподржана радња" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Лош уверење" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Ðепознато проширење" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Време је иÑтекло" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "грешка управника директоријумом" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "грешка управника директоријумом" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Грешка читања ИПЦ-а" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Ðије ИПЦ Ñервер" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "УÑпешно" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Грешка подешавања" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Кршење протокола" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Ðепознато проширење" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Општа грешка" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Потребно је поновно поÑтављање картице" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "ÐеиÑправна оÑобина" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Ðеподржана заштита" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Кршење протокола" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "ÐеиÑправно Ñтање" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Ðије ЦМС предмет" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "ХардверÑки проблем" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "ÐеиÑправно Ñтање" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Проблем кодирања" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Ðеподржана заштита" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "ÐеиÑправна картица" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "ÐедоÑтаје радња" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Кршење протокола" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Радња није још завршена" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Радња је отказана" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Ред је предуг" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Радња је отказана" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Општа грешка ИПЦ-а" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Изворишта Ñу иÑтрошена" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Кршење протокола" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "ÐеиÑправно Ñтање" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Ðеподржано уверење" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Потребно је поновно поÑтављање картице" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "УÑпешно" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Ðије делотворно" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Ðије делотворно" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Ðије ИПЦ Ñервер" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Дешифровање није уÑпело" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "1. код грешке који је одредио кориÑник" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "2. код грешке који је одредио кориÑник" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "3. код грешке који је одредио кориÑник" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "4. код грешке који је одредио кориÑник" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "5. код грешке који је одредио кориÑник" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "6. код грешке који је одредио кориÑник" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "7. код грешке који је одредио кориÑник" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "8. код грешке који је одредио кориÑник" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "9. код грешке који је одредио кориÑник" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "10. код грешке који је одредио кориÑник" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "11. код грешке који је одредио кориÑник" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "12. код грешке који је одредио кориÑник" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "13. код грешке који је одредио кориÑник" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "14. код грешке који је одредио кориÑник" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "15. код грешке који је одредио кориÑник" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "16. код грешке који је одредио кориÑник" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "УÑпешно" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Садржајна грешка" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Кршење протокола" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Број в/о грешке ÑиÑтемÑке грешке" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Ðепозната грешка ÑиÑтема" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Крај датотеке" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Ðепознат код грешке" + +#: src/argparse.c:468 +#, fuzzy +#| msgid "Data not encrypted" +msgid "argument not expected" +msgstr "Подаци ниÑу шифровани" + +#: src/argparse.c:470 +#, fuzzy +#| msgid "IPC read error" +msgid "read error" +msgstr "Грешка читања ИПЦ-а" + +#: src/argparse.c:472 +#, fuzzy +#| msgid "Line too long" +msgid "keyword too long" +msgstr "Ред је предуг" + +#: src/argparse.c:474 +#, fuzzy +#| msgid "Missing value" +msgid "missing argument" +msgstr "ÐедоÑтаје вредноÑÑ‚" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "Invalid argument" +msgid "invalid argument" +msgstr "ÐеиÑправан аргумент" + +#: src/argparse.c:478 +#, fuzzy +#| msgid "Invalid card" +msgid "invalid command" +msgstr "ÐеиÑправна картица" + +#: src/argparse.c:480 +#, fuzzy +#| msgid "Invalid OID string" +msgid "invalid alias definition" +msgstr "ÐеиÑправна ОИД ниÑка" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Грешка подешавања" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "Invalid card" +msgid "invalid meta command" +msgstr "ÐеиÑправна картица" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Ðепозната наредба" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Ðеочекивана ИПЦ наредба" + +#: src/argparse.c:494 +#, fuzzy +#| msgid "Invalid operation code" +msgid "invalid option" +msgstr "ÐеиÑправна шифра радње" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +#| msgid "Invalid operation code" +msgid "invalid option \"%.50s\"\n" +msgstr "ÐеиÑправна шифра радње" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "упозорење: не могу да препознам „%s“\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Употреба: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Изворишта Ñу иÑтрошена" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "ÐеиÑправни подаци" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Општа грешка" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "грешка управника директоријумом" diff --git a/comm/third_party/libgpg-error/po/stamp-po b/comm/third_party/libgpg-error/po/stamp-po new file mode 100644 index 0000000000..9788f70238 --- /dev/null +++ b/comm/third_party/libgpg-error/po/stamp-po @@ -0,0 +1 @@ +timestamp diff --git a/comm/third_party/libgpg-error/po/sv.gmo b/comm/third_party/libgpg-error/po/sv.gmo new file mode 100644 index 0000000000..6d2930eb05 Binary files /dev/null and b/comm/third_party/libgpg-error/po/sv.gmo differ diff --git a/comm/third_party/libgpg-error/po/sv.po b/comm/third_party/libgpg-error/po/sv.po new file mode 100644 index 0000000000..d528835303 --- /dev/null +++ b/comm/third_party/libgpg-error/po/sv.po @@ -0,0 +1,2232 @@ +# Swedish translation for libgpg-error. +# Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Daniel Nylander , 2006, 2007, 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.7\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:43+0100\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Ospecificerad källa" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "PIN-inmatning" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "NyckellÃ¥da" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Alla källor" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Användardefinierad källa 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Användardefinierad källa 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Användardefinierad källa 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Användardefinierad källa 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Okänd källa" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Lyckades" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Allmänt fel" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Okänt paket" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Okänd version i paket" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Ogiltig publik nyckel-algoritm" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Ogiltig sammandragsalgoritm" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Felaktig publik nyckel" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Felaktig hemlig nyckel" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Felaktig signatur" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Ingen publik nyckel" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Kontrollsummefel" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Felaktig lösenfras" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Ogiltig chifferalgoritm" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Nyckelring är öppnad" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Ogiltigt paket" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Ogiltigt ASCII-skal" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Inget användar-id" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Ingen hemlig nyckel" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Fel hemlig nyckel använd" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Felaktig sessionsnyckel" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Okänd komprimeringsalgoritm" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Tal är inte ett primtal" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Ogiltig kodningsmetod" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Ogiltigt krypteringsschema" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Ogiltigt signaturschema" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Ogiltigt attribut" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Inget värde" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Hittades inte" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Värdet hittades inte" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Syntaxfel" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Felaktigt MPI-värde" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Ogiltig lösenfras" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Ogiltig signaturklass" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Resurser överansträngda" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Ogiltig nyckelring" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Fel i tillitsdatabas" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Felaktigt certifikat" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Ogiltig användaridentitet" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Oväntat fel" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Tidskonflikt" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Fel i nyckelserver" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Fel publik nyckel-algoritm" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Hyllning till D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Svag krypteringsnyckel" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Ogiltig nyckellängd" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Ogiltigt argument" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Syntaxfel i uri" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Ogiltig uri" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Nätverksfel" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Okänd värd" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Självtestning misslyckades" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Data är inte krypterat" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Data inte behandlat" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Oanvändbar publik nyckel" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Oanvändbar hemlig nyckel" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Ogiltigt värde" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Felaktig certifikatkedja" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Saknar certifikat" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Inget data" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Fel" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Stöds inte" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Ogiltig Ã¥tgärdskod" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Tidsgräns" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Internt fel" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "Slut pÃ¥ filen (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Ogiltigt objekt" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "TillhandahÃ¥llet objekt är för kort" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "TillhandahÃ¥llet objekt är för stort" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Saknar post i objekt" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Inte implementerad" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Konflikt i användningen" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Ogiltigt chifferläge" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Ogiltig flagga" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Ogiltig hanterare" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Resultat nerskalat" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Ofullständig rad" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Ogiltigt svar" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Ingen agent kör" + +#: src/err-codes.h:106 +#, fuzzy +#| msgid "agent error" +msgid "Agent error" +msgstr "agentfel" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Ogiltig data" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Ospecificerat Assuan-serverfel" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Allmänt Assuan-fel" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Ogiltig sessionsnyckel" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Ogiltigt S-uttryck" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Algoritmen stöds inte" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Ingen PIN-inmatning" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "PIN-inmatningsfel" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Felaktig PIN-kod" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Ogiltigt namn" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Felaktigt data" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Ogiltig parameter" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Fel kort" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Ingen dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr-fel" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Certifikatet är spärrat" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Ingen känd CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL för gammal" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Raden är för lÃ¥ng" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Inte betrodd" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Ã…tgärden avbröts" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Felaktigt CA-certifikat" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Certifikatet har gÃ¥tt ut" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Certifikatet är för ungt" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Certifikatet stöds inte" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Okänt S-uttryck" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Skyddet stöds inte" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Skadat skydd" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Tvetydigt namn" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Kortfel" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Nollställning av kort krävs" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Kort borttaget" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Ogiltigt kort" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Kortet inte inmatat" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Inget PKCS15-program" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Inte bekräftad" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Konfigurationsfel" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Ingen policyträff" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ogiltigt index" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Ogiltigt id" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Ingen SmartCard-demon" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Fel i SmartCard-demon" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Protokollet stöds inte" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Felaktig PIN-metod" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Kortet är inte initierat" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Ã…tgärden stöds inte" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Fel nyckelanvändning" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Ingenting hittades" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Felaktig blob-typ" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Saknar värde" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "HÃ¥rdvaruproblem" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN-kod blockerad" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Användningsvillkoren tillfredsställs inte" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PIN-koderna är inte synkroniserade" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Ogiltig CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER-fel" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Ogiltg BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Elementet hittades inte" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Identifieraren hittades inte" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Ogiltig tagg" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Ogiltig längd" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Ogiltig nyckelinformation" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Oväntad tagg" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Inte DER-kodat" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Inget CMS-objekt" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Ogiltigt CMS-objekt" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Okänt CMS-objekt" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "CMS-objektet stöds inte" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Kodningen stöds inte" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "CMS-versionen stöds inte" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Okänd algoritm" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Ogiltig krypteringsmotor" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Publika nyckeln inte betrodd" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Dekryptering misslyckades" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Nyckeln har gÃ¥tt ut" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Signaturen har gÃ¥tt ut" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Kodningsproblem" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Ogiltigt tillstÃ¥nd" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Dubblettvärde" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Saknar Ã¥tgärd" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ASN.1-modulen hittades inte" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Ogiltig OID-sträng" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Ogiltig tid" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Ogiltigt CRL-objekt" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "CRL-versionen stöds inte" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Ogiltigt certifikatobjekt" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Okänt namn" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "En lokalfunktion misslyckades" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Inte lÃ¥st" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Protokollöverträdelse" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Ogiltig MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Ogiltig begäran" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Okänd utökning" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Okänd kritiskt tillägg" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "LÃ¥st" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Okänd flagga" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Okänt kommando" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Fungerar inte" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Ingen lösenfras angiven" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Ingen pinkod angiven" + +#: src/err-codes.h:207 +#, fuzzy +msgid "Not enabled" +msgstr "Inte lÃ¥st" + +#: src/err-codes.h:208 +#, fuzzy +msgid "No crypto engine" +msgstr "Ogiltig krypteringsmotor" + +#: src/err-codes.h:209 +#, fuzzy +msgid "Missing key" +msgstr "Saknar värde" + +#: src/err-codes.h:210 +#, fuzzy +msgid "Too many objects" +msgstr "Inget CMS-objekt" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +#, fuzzy +msgid "Not initialized" +msgstr "Kortet är inte initierat" + +#: src/err-codes.h:213 +#, fuzzy +msgid "Missing issuer certificate" +msgstr "Saknar certifikat" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +#, fuzzy +msgid "Invalid elliptic curve" +msgstr "Ogiltig tid" + +#: src/err-codes.h:216 +#, fuzzy +msgid "Unknown elliptic curve" +msgstr "Okänd källa" + +#: src/err-codes.h:217 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated key" +msgstr "Dubblettvärde" + +#: src/err-codes.h:218 +#, fuzzy +#| msgid "Ambiguous name" +msgid "Ambiguous result" +msgstr "Tvetydigt namn" + +#: src/err-codes.h:219 +#, fuzzy +msgid "No crypto context" +msgstr "Ogiltig krypteringsmotor" + +#: src/err-codes.h:220 +#, fuzzy +msgid "Wrong crypto context" +msgstr "Ogiltig krypteringsmotor" + +#: src/err-codes.h:221 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Bad crypto context" +msgstr "Ogiltig krypteringsmotor" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +#, fuzzy +#| msgid "No public key" +msgid "Broken public key" +msgstr "Ingen publik nyckel" + +#: src/err-codes.h:224 +#, fuzzy +#| msgid "No secret key" +msgid "Broken secret key" +msgstr "Ingen hemlig nyckel" + +#: src/err-codes.h:225 +#, fuzzy +#| msgid "Invalid digest algorithm" +msgid "Invalid MAC algorithm" +msgstr "Ogiltig sammandragsalgoritm" + +#: src/err-codes.h:226 +#, fuzzy +msgid "Operation fully cancelled" +msgstr "Ã…tgärden avbröts" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Ã…tgärden är ännu inte färdig" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Buffert för liten" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Ogiltig längdangivare i S-uttryck" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Sträng för lÃ¥ng i S-uttryck" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Omatchad parentes i S-uttryck" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-uttryck inte korrekt" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Felaktigt tecken i S-uttryck" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Fel citering i S-uttryck" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Nollprefix i S-uttryck" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Nästlade visningstips i S-uttryck" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Omatchade visningstips" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Oväntat reserverat skiljetecken i S-uttryck" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Felaktigt hexadecimalt tecken i S-uttryck" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Udda hexadecimala tal i S-uttryck" + +#: src/err-codes.h:241 +#, fuzzy +msgid "Bad octal character in S-expression" +msgstr "Felaktigt oktadecimalt tecken i S-uttryck" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "Data är inte krypterat" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Okänt namn" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Ingen publik nyckel" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Buffert för liten" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Raden är för lÃ¥ng" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "No certificate chain" +msgstr "Felaktig certifikatkedja" + +#: src/err-codes.h:252 +#, fuzzy +#| msgid "Certificate too young" +msgid "Certificate is too large" +msgstr "Certifikatet är för ungt" + +#: src/err-codes.h:253 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid record" +msgstr "Ogiltigt kort" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +#, fuzzy +#| msgid "Unexpected tag" +msgid "Unexpected message" +msgstr "Oväntad tagg" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +#, fuzzy +#| msgid "Invalid cipher algorithm" +msgid "No cipher algorithm" +msgstr "Ogiltig chifferalgoritm" + +#: src/err-codes.h:260 +#, fuzzy +msgid "Missing client certificate" +msgstr "Saknar certifikat" + +#: src/err-codes.h:261 +#, fuzzy +#| msgid "Certificate revoked" +msgid "Close notification received" +msgstr "Certifikatet är spärrat" + +#: src/err-codes.h:262 +#, fuzzy +#| msgid "Key expired" +msgid "Ticket expired" +msgstr "Nyckeln har gÃ¥tt ut" + +#: src/err-codes.h:263 +#, fuzzy +#| msgid "Bad public key" +msgid "Bad ticket" +msgstr "Felaktig publik nyckel" + +#: src/err-codes.h:264 +#, fuzzy +#| msgid "Unknown packet" +msgid "Unknown identity" +msgstr "Okänt paket" + +#: src/err-codes.h:265 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "Bad certificate message in handshake" +msgstr "Felaktig certifikatkedja" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +#, fuzzy +#| msgid "Key expired" +msgid "Key disabled" +msgstr "Nyckeln har gÃ¥tt ut" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +#, fuzzy +#| msgid "Invalid object" +msgid "Invalid lock object" +msgstr "Ogiltigt objekt" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Allmänt IPC-fel" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC-acceptanrop misslyckades" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC-anslutningsanrop misslyckades" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Ogiltigt IPC-svar" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Ogiltigt värde skickat till IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Ofullständig rad skickad till IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Raden skickad till IPC är för lÃ¥ng" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Nästlade IPC-kommandon" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Inget datasvarsanrop i IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Inget datafrÃ¥geanrop i IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Inte en IPC-server" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Inte en IPC-klient" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Problem med att starta IPC-server" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC-läsfel" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC-skrivfel" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "För mycket data för IPC-lager" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Oväntat IPC-kommando" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Okänt IPC-kommando" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC-syntaxfel" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC-anropet har avbrutits" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Ingen inmatningskälla för IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Ingen utmatningskälla för IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC-parameterfel" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Okänd IPC-frÃ¥ga" + +#: src/err-codes.h:306 +#, fuzzy +msgid "Crypto engine too old" +msgstr "Ogiltig krypteringsmotor" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Dubblettvärde" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Certifikatet är för ungt" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "TillhandahÃ¥llet objekt är för kort" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Okänt namn" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Ogiltig Ã¥tgärdskod" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Okänt namn" + +#: src/err-codes.h:320 +#, fuzzy +msgid "Not authenticated" +msgstr "Inte lÃ¥st" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Skyddet stöds inte" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Ingen agent kör" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Fel i SmartCard-demon" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Fel i nyckelserver" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Okänt systemfel" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Ogiltig OID-sträng" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Ogiltigt S-uttryck" + +#: src/err-codes.h:330 +#, fuzzy +msgid "Missing DNS query packet" +msgstr "Saknar certifikat" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Dekryptering misslyckades" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Tidsgräns" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Allmänt IPC-fel" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Allmänt fel" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Allmänt fel" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Allmänt Assuan-fel" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Allmänt fel" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Allmänt Assuan-fel" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "IPC-skrivfel" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Allmänt IPC-fel" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "IPC-anslutningsanrop misslyckades" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Allmänt fel" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Nollställning av kort krävs" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Elementet hittades inte" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Stöds inte" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Oväntat fel" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Ã…tgärden stöds inte" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Felaktigt certifikat" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Okänd utökning" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Tidsgräns" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "dirmngr-fel" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "dirmngr-fel" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "IPC-läsfel" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Inte en IPC-server" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Lyckades" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Konfigurationsfel" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Protokollöverträdelse" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Okänd utökning" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Allmänt fel" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Nollställning av kort krävs" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Ogiltigt attribut" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Skyddet stöds inte" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Protokollöverträdelse" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Ogiltigt tillstÃ¥nd" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Inget CMS-objekt" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "HÃ¥rdvaruproblem" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Ogiltigt tillstÃ¥nd" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Kodningsproblem" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Skyddet stöds inte" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Ogiltigt kort" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Saknar Ã¥tgärd" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Protokollöverträdelse" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Ã…tgärden är ännu inte färdig" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Ã…tgärden avbröts" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Raden är för lÃ¥ng" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Ã…tgärden avbröts" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Allmänt IPC-fel" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Resurser överansträngda" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Protokollöverträdelse" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Ogiltigt tillstÃ¥nd" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Certifikatet stöds inte" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Nollställning av kort krävs" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Lyckades" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Fungerar inte" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Fungerar inte" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Inte en IPC-server" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Dekryptering misslyckades" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Användardefinierad felkod 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Användardefinierad felkod 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Användardefinierad felkod 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Användardefinierad felkod 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Användardefinierad felkod 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Användardefinierad felkod 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Användardefinierad felkod 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Användardefinierad felkod 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Användardefinierad felkod 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Användardefinierad felkod 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Användardefinierad felkod 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Användardefinierad felkod 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Användardefinierad felkod 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Användardefinierad felkod 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Användardefinierad felkod 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Användardefinierad felkod 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Lyckades" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Syntaxfel" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Protokollöverträdelse" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Systemfel utan felnummer" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Okänt systemfel" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Slut pÃ¥ fil" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Okänd felkod" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "argument förväntades inte" + +#: src/argparse.c:470 +msgid "read error" +msgstr "läsfel" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "nyckelordet är för lÃ¥ngt" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "argument saknas" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "invalid value\n" +msgid "invalid argument" +msgstr "ogiltigt värde\n" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "ogiltigt kommando" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "ogiltig aliasdefinition" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Konfigurationsfel" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "slut pÃ¥ minne" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "ogiltigt kommando" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Okänt kommando" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Oväntat IPC-kommando" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "ogiltig flagga" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "argument för flaggan \"%.50s\" saknas\n" + +#: src/argparse.c:506 +#, fuzzy, c-format +#| msgid "missing argument for option \"%.50s\"\n" +msgid "invalid argument for option \"%.50s\"\n" +msgstr "argument för flaggan \"%.50s\" saknas\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "flaggan \"%.50s\" förväntar sig inte ett argument\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "ogiltigt kommando \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "flagga \"%.50s\" är tvetydig\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "kommandot \"%.50s\" är tvetydigt\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "ogiltig flagga \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "varning: kände inte igen %s\n" + +#~ msgid "out of core\n" +#~ msgstr "slut pÃ¥ minne\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Användning: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Resurser överansträngda" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Ogiltig data" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Allmänt fel" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "dirmngr-fel" diff --git a/comm/third_party/libgpg-error/po/uk.gmo b/comm/third_party/libgpg-error/po/uk.gmo new file mode 100644 index 0000000000..e5e0a42ea6 Binary files /dev/null and b/comm/third_party/libgpg-error/po/uk.gmo differ diff --git a/comm/third_party/libgpg-error/po/uk.po b/comm/third_party/libgpg-error/po/uk.po new file mode 100644 index 0000000000..b415e31f74 --- /dev/null +++ b/comm/third_party/libgpg-error/po/uk.po @@ -0,0 +1,2007 @@ +# Translation of libgpg-error to Ukrainian +# Copyright (C) 2012 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# +# Yuri Chornoivan , 2012, 2014, 2015, 2018, 2020. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.7\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:44+0100\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 20.03.70\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Ðевказане джерело" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "Ðгент GPG" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Будь-Ñке джерело" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Визначене кориÑтувачем джерело 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Визначене кориÑтувачем джерело 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Визначене кориÑтувачем джерело 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Визначене кориÑтувачем джерело 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Ðевідоме джерело" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Виконано" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Загальна помилка" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Ðевідомий пакет" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Ðевідома верÑÑ–Ñ Ñƒ пакеті" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Ðекоректний алгоритм відкритого ключа" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Ðекоректний алгоритм контрольної Ñуми" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Помилковий відкритий ключ" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Помилковий закритий ключ" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Ðепридатний підпиÑ" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Ðемає відкритого ключа" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Помилка у контрольній Ñумі" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Помилковий пароль" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Ðекоректний алгоритм шифруваннÑ" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Ð’Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñховища ключів" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Ðекоректний пакет" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Ðекоректний код ASCII" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Ðемає ідентифікатора кориÑтувача" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Ðемає закритого ключа" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "ВикориÑтано помилковий закритий код" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Помилковий ключ ÑеанÑу" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Ðевідомий алгоритм ÑтиÑканнÑ" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "ЧиÑло не Ñ” проÑтим" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "Ðекоректний алгоритм кодуваннÑ" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Ðекоректна Ñхема шифруваннÑ" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Ðекоректна Ñхема підпиÑуваннÑ" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Ðекоректний атрибут" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Ðемає значеннÑ" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Ðе знайдено" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ðµ знайдено" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "СинтакÑична помилка" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Помилкове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ MPI" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Ðекоректний пароль" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Ðекоректний ÐºÐ»Ð°Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñу" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Вичерпано реÑурÑи" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Ðекоректне Ñховище ключів" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Помилка бази даних щодо надійноÑÑ‚Ñ–" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Помилковий Ñертифікат" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Ðекоректний ідентифікатор кориÑтувача" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Ðеочікувана помилка" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Суперечливі дані щодо чаÑу" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Помилка Ñервера ключів" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Помилковий алгоритм відкритого ключа" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "ПриÑвÑчуєтьÑÑ D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Слабкий ключ шифруваннÑ" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Ðекоректна довжина ключа" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Ðекоректний аргумент" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "СинтакÑична помилку у адреÑÑ–" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "Ðекоректна адреÑа" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Помилка мережі" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Ðевідомий вузол" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Помилка під Ñ‡Ð°Ñ Ñамоперевірки" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "Дані не зашифровано" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "Дані не оброблено" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Ðепридатний до викориÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸Ð¹ ключ" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Ðепридатний до викориÑÑ‚Ð°Ð½Ð½Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸Ð¹ ключ" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Ðекоректне значеннÑ" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Помилковий ланцюжок Ñертифікації" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Ðе виÑтачає Ñертифіката" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Ðемає даних" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Вада" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Ðе підтримуєтьÑÑ" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Ðекоректний код дії" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Ð§Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Ðекоректний об’єкт" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Ðаданий об’єкт Ñ” надто коротким" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Ðаданий об’єкт Ñ” надто довгим" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "У об’єкті не виÑтачає елемента" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Ðе реалізовано" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Суперечливе викориÑтаннÑ" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Ðекоректний режим шифруваннÑ" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Ðекоректний прапорець" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Ðекоректний обробник" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "СпиÑок результатів обрізано" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Ðезавершений Ñ€Ñдок" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Ðекоректна відповідь" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Ðгент не запущено" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Помилка агента" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Ðекоректні дані" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Ðевизначена помилка Ñервера Assuan" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Загальна помилка бібліотеки Assuan" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Ðекоректний ключ ÑеанÑу" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Ðекоректний S-вираз" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Ðепідтримуваний алгоритм" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Ðемає pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Помилка pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "Помилковий пінкод" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Ðекоректне назва" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Помилкові дані" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Ðекоректний параметр" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Помилкова картка" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Ðемає dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Помилка dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Сертифікат відкликано" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Ðемає жодної відомої CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL заÑтарий" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "РÑдок надто довгий" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Ðенадійний" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Дію ÑкаÑовано" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Помилковий Ñертифікат CA" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Термін дії Ñертифіката минув" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Сертифікат Ñ” надто новим" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Ðепідтримуваний Ñертифікат" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Ðевідомий S-вираз" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Ðепідтримуваний захиÑÑ‚" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "ЗахиÑÑ‚ пошкоджено" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Ðеоднозначна назва" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Помилка під Ñ‡Ð°Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ з карткою" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "ÐадіÑлано запит на ÑÐºÐ¸Ð´Ð°Ð½Ð½Ñ ÐºÐ°Ñ€Ñ‚ÐºÐ¸" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Картку вилучено" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Ðекоректна картка" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Ðемає картки" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Ðемає програми обробки PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "Ðе підтверджено" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Помилка налаштуваннÑ" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Ðемає відповідного правила" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Ðекоректний індекÑ" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Ðекоректний ідентифікатор" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Ðемає фонової Ñлужби SmartCard" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Помилка фонової Ñлужби SmartCard" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Ðепідтримуваний протокол" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "Помилковий метод обробки пінкоду" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "Картку не ініціалізовано" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Ðепідтримувана діÑ" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Помилкове викориÑÑ‚Ð°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð°" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Ðічого не знайдено" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Помилковий тип бінарного коду" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Ðе виÑтачає значеннÑ" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Ðпаратні проблеми" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "Пінкод заблоковано" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "Ðе задоволено умови кориÑтуваннÑ" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "Пінкоди не Ñинхронізовано" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Помилка BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Елемента не знайдено" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Ðе знайдено ідентифікатора" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Ðекоректний теґ" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Ðекоректна довжина" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Ðекоректні дані щодо ключа" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Ðеочікуваний теґ" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Ðе закодовано DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Ðемає об’єкта CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Ðекоректний об’єкт CMS" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Ðевідомий об’єкт CMS" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Ðепідтримуваний об’єкт CMS" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Ðепідтримуване кодуваннÑ" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Ðепідтримувана верÑÑ–Ñ CMS" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Ðевідомий алгоритм" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "Ðекоректний рушій шифруваннÑ" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Відкритий ключ не Ñ” надійним" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Спроба Ñ€Ð¾Ð·ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð·Ð½Ð°Ð»Ð° невдачі" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Строк дії ключа вичерпано" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Строк дії підпиÑу вичерпано" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Проблема з кодуваннÑм" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Ðекоректний Ñтан" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Ð”ÑƒÐ±Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Ðе виÑтачає дії" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Ðе знайдено Ð¼Ð¾Ð´ÑƒÐ»Ñ ASN.1" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Ðекоректний Ñ€Ñдок OID" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Ðекоректний чаÑ" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Ðекоректний об’єкт CRL" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Ðепідтримувана верÑÑ–Ñ CRL" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Ðекоректний об’єкт Ñертифікації" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Ðевідома назва" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Помилка функції локалізації" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Ðе заблоковано" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "Ðекоректна MAC-адреÑа" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Ðекоректний запит" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Ðевідоме розширеннÑ" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Ðевідоме критичне розширеннÑ" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Заблоковано" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Ðевідомий параметр" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Ðевідома команда" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ðµ" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "Ðе вказано паролÑ" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "Ðе вказано пінкоду" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "Ðе увімкнено" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "Ðемає Ñ€ÑƒÑˆÑ–Ñ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "Пропущено ключ" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "Забагато об’єктів" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "ДоÑÑгнуто обмеженнÑ" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "Ðе ініціалізовано" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "Ðе виÑтачає Ñертифіката видавцÑ" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "Ðемає доÑтупних Ñерверів ключів" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "Ðекоректна еліптична крива" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "Ðевідома еліптична крива" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "Ð”ÑƒÐ±Ð»ÑŽÐ²Ð°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð°" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "Ðеоднозначний результат" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "Ðемає контекÑту шифруваннÑ" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "Помилковий контекÑÑ‚ шифруваннÑ" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "Ðекоректний контекÑÑ‚ шифруваннÑ" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "Конфлікт у контекÑÑ‚Ñ– шифруваннÑ" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "Пошкоджений відкритий ключ" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "Пошкоджений закритий ключ" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "Ðекоректний алгоритм MAC" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "Дію повніÑÑ‚ÑŽ ÑкаÑовано" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð´Ñ–Ñ— ще не завершено" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Занадто короткий буфер" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Ðекоректний Ñпецифікатор довжини у S-виразі" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Занадто довгий Ñ€Ñдок у S-виразі" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Ðезакриті дужки у S-виразі" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-вираз не Ñ” канонічним" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Помилковий Ñимвол у S-виразі" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Помилкові лапки у S-виразі" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Ðульовий Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ñƒ S-виразі" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Вкладені наÑтанови щодо показу у S-виразі" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Ðевідповідні наÑтанови щодо показу" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Ðеочікувана зарезервована Ð¿ÑƒÐ½ÐºÑ‚ÑƒÐ°Ñ†Ñ–Ñ Ñƒ S-виразі" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Помилковий шіÑтнадцÑтковий Ñимвол у S-виразі" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Дивні шіÑтнадцÑткові чиÑла у S-виразі" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "Помилковий віÑімковий Ñимвол у S-виразі" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "Строк дії уÑÑ–Ñ… підключів вичерпано або Ñ—Ñ… відкликано" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "Базу даних пошкоджено" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "Сервер Ñигналізує про помилку" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "Ðемає назви" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "Ðемає ключа" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "ЗаÑтарілий ключ" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "Занадто короткий запит" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "Ðадто довгий запит" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "Об’єкт перебуває у Ñтані перериваннÑ" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "Ðемає ланцюжка Ñертифікації" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "Сертифікат Ñ” надто великим" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "Ðекоректний запиÑ" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "MAC не пройшов перевірку" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "Ðеочікуване повідомленнÑ" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "Помилка під Ñ‡Ð°Ñ ÑтиÑÐºÐ°Ð½Ð½Ñ Ð°Ð±Ð¾ видобуваннÑ" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "Відлік буде автоматично розпочато з початку" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "Отримано критичне попереджувальне повідомленнÑ" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "Ðемає алгоритму шифруваннÑ" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "Ðе виÑтачає Ñертифіката клієнта" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "Отримано ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ закриттÑ" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "Строк дії квитка вичерпано" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "Помилковий квиток" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "Ðевідомий профіль" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ Ñертифікації під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" +"Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ запиту Ñертифікації під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" +"Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ перевірки Ñертифікації під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ " +"зв’Ñзку" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ зміни шифру під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "Помилкове вітальне Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ ÐºÐ»Ñ–Ñ”Ð½Ñ‚Ð° під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "Помилкове вітальне Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñервера під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" +"Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð²Ñ–Ñ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð´ Ñервера під Ñ‡Ð°Ñ " +"Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "Помилкове завершальне Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзку" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" +"Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ обміну ключами із Ñервером під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ " +"зв’Ñзку" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" +"Помилкове Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ обміну ключами із клієнтом під Ñ‡Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ " +"зв’Ñзку" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "Фіктивний Ñ€Ñдок" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "Заборонено" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "Ключ вимкнено" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "Ðеможливе Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð°, заÑнованого на картці" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "Ðекоректний об’єкт блокуваннÑ" + +#: src/err-codes.h:280 +msgid "True" +msgstr "Так" + +#: src/err-codes.h:281 +msgid "False" +msgstr "ÐÑ–" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Загальна помилка IPC" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Помилка виклику прийнÑÑ‚Ñ‚Ñ IPC" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Помилка з’єднувального виклику IPC" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Ðекоректна відповідь IPC" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "IPC передано некоректне значеннÑ" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "IPC передано незавершений Ñ€Ñдок" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "РÑдок, переданий IPC, Ñ” надто довгим" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Вкладені команди IPC" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Ðемає зворотного виклику щодо даних у IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Ðемає інформаційного зворотного виклику у IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Ðе Ñ” Ñервером IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Ðе Ñ” клієнтом IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Проблеми із запуÑком Ñервера IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Помилка запиÑу IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Забагато даних Ð´Ð»Ñ ÑˆÐ°Ñ€Ñƒ IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Ðеочікувана команда IPC" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Ðевідома команда IPC" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "СинтакÑична помилка IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Виклик IPC було ÑкаÑовано" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Ðемає джерела вхідних даних Ð´Ð»Ñ IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Ðемає міÑÑ†Ñ Ð²Ð¸Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… Ð´Ð»Ñ IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Помилка у параметрі IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Ðевідомий запит IPC" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "Рушій ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ” надто Ñтарим" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "Екран або вікно Ñ” надто малим" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "Екран або вікно Ñ” надто великим" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "Ðе вÑтановлено обов'Ñзкової змінної Ñередовища" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "Ідентифікатор кориÑтувача вже Ñ–Ñнує" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "Ðазва вже Ñ–Ñнує" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "Ð”ÑƒÐ±Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "Об'єкт Ñ” надто новим" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "Об'єкт Ñ” надто Ñтарим" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "Ðевідомий прапорець" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "Ðекоректна поÑлідовніÑÑ‚ÑŒ виконаннÑ" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "Вже отримано" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "Повторіть Ñпробу пізніше" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "Помилкова назва" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "Ð Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ðµ пройдено" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "Помилка розпізнаваннÑ" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "Фонову Ñлужбу Keybox не запущено" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "Помилка фонової Ñлужби Keybox" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "Службу не запущено" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "Помилка Ñлужби" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "ВиÑвлено ваду у ÑиÑтемі" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "Ðевідома помилка DNS" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "Ðекоректний розділ DNS" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "Ðекоректний текÑтовий формат адреÑи" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "Ðе виÑтачає пакета запиту до DNS" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "Ðе виÑтачає пакета із відповіддю DNS" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¾ у DNS" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "Ðе пройдено перевірку на DNS" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "Перевищено Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° DNS" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "Загальна помилка LDAP" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "Загальна помилка атрибута LDAP" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "Загальна помилка назви LDAP" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "Загальна помилка захиÑту LDAP" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "Загальна помилка Ñлужби LDAP" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "Загальна помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ LDAP" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "ЕкÑпериментальний код помилки LDAP" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "Код конфіденційної помилки LDAP" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "Інша загальна помилка LDAP" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "Ðе вдалоÑÑ Ð·â€™Ñ”Ð´Ð½Ð°Ñ‚Ð¸ÑÑ Ñ–Ð· LDAP (X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "ÐŸÐµÑ€ÐµÐ²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½ÑŒ щодо ÑпрÑÐ¼Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ LDAP" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "Циклічний клієнт LDAP" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "Ðе повернуто результатів LDAP" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "Ðе знайдено ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "Ðе підтримуєтьÑÑ LDAP" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "Помилка Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "Ðе виÑтачає пам’ÑÑ‚Ñ– у LDAP" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "Помилковий параметр підпрограми LDAP" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "Дію LDAP ÑкаÑовано кориÑтувачем" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "Помилковий фільтр пошуку LDAP" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "Ðевідомий ÑпоÑіб Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "ÐŸÐµÑ€ÐµÐ²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ LDAP" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "Помилка Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "Помилка ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "Локальна помилка LDAP" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "Ðе вдалоÑÑ Ð²Ñтановити зв’Ñзок із Ñервером LDAP" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "УÑпіх LDAP" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "Помилка дій LDAP" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "Помилка протоколу LDAP" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "Перевищено Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ LDAP" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "Перевищено Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° розмір у LDAP" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "ПорівнÑÐ½Ð½Ñ LDAP: не збігаютьÑÑ" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "ПорівнÑÐ½Ð½Ñ LDAP: збігаютьÑÑ" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "Підтримки методу Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ LDAP не передбачено" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "Потрібен потужніший ÑпоÑіб Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "Отримано чаÑткові результати Ñ– ÑпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "СпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "Перевищено адмініÑтративне Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ LDAP" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "ÐедоÑтупне критичне Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ LDAP" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "Конфіденційно потрібне LDAP" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "Виконуємо прив’ÑÐ·ÑƒÐ²Ð°Ð½Ð½Ñ SASL LDAP" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "Ðемає такого атрибута LDAP" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "Ðевизначний тип атрибута LDAP" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "ÐеприйнÑтна відповідніÑÑ‚ÑŒ у LDAP" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½ÑŒ у LDAP" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "Тип або Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ LDAP Ñ–Ñнує" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "Ðекоректний ÑинтакÑÐ¸Ñ Ñƒ LDAP" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "Ðемає такого об’єкта LDAP" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "Проблема пÑевдоніма LDAP" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "Ðекоректний ÑинтакÑÐ¸Ñ DN у LDAP" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "Ð—Ð°Ð¿Ð¸Ñ LDAP Ñ” лиÑтком" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "Проблемі з ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ð²â€™Ñзки пÑевдоніма LDAP" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "Помилка ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– LDAP (X)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "ÐеприйнÑтне Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "Ðекоректні реєÑтраційні дані LDAP" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "ÐедоÑтатні права доÑтупу до LDAP" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "Сервер LDAP зайнÑто виконаннÑм завданнÑ" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "Сервер LDAP недоÑтупний" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "Сервер LDAP не бажає працювати" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "LDAP виÑвлено цикл" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ñ–Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ ÐºÐ»Ð°Ñу об’єктів LDAP" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "Дію LDAP не дозволено Ð´Ð»Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð², Ñкі не Ñ” лиÑтками" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "Дію LDAP не дозволено над RDN" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "Вже Ñ–Ñнує (LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ ÐºÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ð° LDAP" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "Результати LDAP Ñ” надто великими" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "Ð”Ñ–Ñ LDAP ÑтоÑуєтьÑÑ Ð´ÐµÐºÑ–Ð»ÑŒÐºÐ¾Ñ… DSA" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "Помилка переглÑду ÑпиÑку віртуальної LDAP" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "Інша помилка LDAP" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "Вичерпано реÑурÑи у LCUP" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ð·Ð°Ñ…Ð¸Ñту у LCUP" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "Ðекоректні дані у LCUP" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "Ðепідтримувана Ñхема у LCUP" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "Потрібне Ð¿ÐµÑ€ÐµÐ·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñƒ LCUP" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAP ÑкаÑовано" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "Ðемає дії LDAP Ð´Ð»Ñ ÑкаÑовуваннÑ" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "Запізно Ð´Ð»Ñ ÑкаÑÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ LDAP" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "Ðе вдалоÑÑ ÑкаÑувати LDAP" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "Помилка оцінки LDAP" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð° допомогою прокÑÑ– заборонено LDAP" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Визначений кориÑтувачем код помилки 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Визначений кориÑтувачем код помилки 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Визначений кориÑтувачем код помилки 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Визначений кориÑтувачем код помилки 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Визначений кориÑтувачем код помилки 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Визначений кориÑтувачем код помилки 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Визначений кориÑтувачем код помилки 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Визначений кориÑтувачем код помилки 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Визначений кориÑтувачем код помилки 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Визначений кориÑтувачем код помилки 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Визначений кориÑтувачем код помилки 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Визначений кориÑтувачем код помилки 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Визначений кориÑтувачем код помилки 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Визначений кориÑтувачем код помилки 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Визначений кориÑтувачем код помилки 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Визначений кориÑтувачем код помилки 16" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "УÑпіх SQL" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "Помилка SQL" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° логіки у бібліотеці SQL" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "Заборонено доÑтуп за правами (SQL)" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "Ðадійшов запит на Ð¿ÐµÑ€ÐµÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ SQL" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "Файл бази даних SQL заблоковано" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "Таблицю SQL у базі даних заблоковано" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "Вихід за межі облаÑÑ‚Ñ– пам'ÑÑ‚Ñ– у бібліотеці SQL" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "Спроба запиÑу до придатної лише до Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних SQL" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "SQL operation terminated by interrupt" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "Помилка введеннÑ-Ð²Ð¸Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð´Ñ–Ñ— SQL" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "Образ диÑка бази даних SQL має помилкове форматуваннÑ" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "Ðевідомий код дії у ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð°Ð¼Ð¸ SQL" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "Ðе вдалоÑÑ Ð²Ñтавити запиÑ, оÑкільки базу даних SQL переповнено" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл бази даних SQL" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "Помилка протоколу Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних SQL" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "(внутрішній код SQL: порожньо)" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "Змінено Ñтруктуру бази даних SQL" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "ÐŸÐµÑ€ÐµÐ²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° розмір Ñ€Ñдка або двійкового об'єкта (SQL)" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "ÐŸÐµÑ€ÐµÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ SQL через Ð¿ÐµÑ€ÐµÐ²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½ÑŒ" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "ÐевідповідніÑÑ‚ÑŒ типів даних (SQL)" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "Ðеправильне викориÑÑ‚Ð°Ð½Ð½Ñ Ð±Ñ–Ð±Ð»Ñ–Ð¾Ñ‚ÐµÐºÐ¸ SQL" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "Бібліотека SQL намагаєтьÑÑ Ð²Ð¸ÐºÐ¾Ñ€Ð¸Ñтати непідтримувані можливоÑÑ‚Ñ– ОС" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "Відмовлено в уповноваженні (SQL)" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "(невикориÑтаний код SQL: формат)" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "Параметр прив'Ñзки SQL має Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð¾Ð·Ð° межами припуÑтимого діапазону" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "Відкрито файл, Ñкий не Ñ” файлом бази даних SQL" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ заÑобу Ð¶ÑƒÑ€Ð½Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ SQL" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ заÑобу Ð¶ÑƒÑ€Ð½Ð°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ SQL" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "У SQL готовий ще один Ñ€Ñдок" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñƒ SQL завершено" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "СиÑтемна помилка без номера" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Ðевідома ÑиÑтемна помилка" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Кінець файла" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Помилка з невідомим кодом" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "неочікуваний аргумент" + +#: src/argparse.c:470 +msgid "read error" +msgstr "помилка читаннÑ" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "занадто довге ключове Ñлово" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "не виÑтачає аргументу" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "некоректний аргумент" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "некоректна команда" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "некоректне Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð¼Ñ–Ð½Ð½Ð¸ÐºÐ°" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "LDAP operations error" +msgid "permission error" +msgstr "Помилка дій LDAP" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "вихід за межі облаÑÑ‚Ñ– пам’ÑÑ‚Ñ–" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "invalid command" +msgid "invalid meta command" +msgstr "некоректна команда" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Ðевідома команда" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Ðеочікувана команда IPC" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "некоректний параметр" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "не вказано аргументу до параметра «%.50s»\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "некоректний аргумент параметра «%.50s»\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° «%.50s» аргументи не потрібно вказувати\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "некоректна команда «%.50s»\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "параметр «%.50s» Ñ” неоднозначним\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "команда «%.50s» Ñ” неоднозначною\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "некоректний параметр «%.50s»\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "Будь лаÑка, повідомлÑйте про помилки тут: .\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "попередженнÑ: не вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ñ‚Ð¸ %s\n" + +#~ msgid "out of core\n" +#~ msgstr "вихід за межі облаÑÑ‚Ñ– пам’ÑÑ‚Ñ–\n" diff --git a/comm/third_party/libgpg-error/po/vi.gmo b/comm/third_party/libgpg-error/po/vi.gmo new file mode 100644 index 0000000000..bf68e9ddaf Binary files /dev/null and b/comm/third_party/libgpg-error/po/vi.gmo differ diff --git a/comm/third_party/libgpg-error/po/vi.po b/comm/third_party/libgpg-error/po/vi.po new file mode 100644 index 0000000000..d1ae3787fd --- /dev/null +++ b/comm/third_party/libgpg-error/po/vi.po @@ -0,0 +1,2245 @@ +# Vietnamese translation for Lib. GPG Error. +# Copyright © 2009 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Clytie Siddall , 2006-2009. +# +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.7\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:44+0100\n" +"Last-Translator: Clytie Siddall \n" +"Language-Team: Vietnamese \n" +"Language: vi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: LocFactoryEditor 1.8\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "Nguồn chÆ°a ghi rõ" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "Tác nhân GPG" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "Bất cứ nguồn nào" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "Nguồn tá»± xác định 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "Nguồn tá»± xác định 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "Nguồn tá»± xác định 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "Nguồn tá»± xác định 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "Nguồn không rõ" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "Thành công" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "Lá»—i chung" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "Gói tin không rõ" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "Gặp phiên bản không rõ trong gói tin" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "Thuật toán khoá công không hợp lệ" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "Thuật toán bá»™ tóm tắt (digest) không hợp lệ" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "Khoá công sai" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "Khoá bí mật sai" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "Chữ ký sai" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "Không có khoá công" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "Lá»—i tổng kiểm tra" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "Cụm từ mật khẩu sai" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "Thuật toán mật mã không hợp lệ" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "Vòng khoá đã mở" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "Gói tin không hợp lệ" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "Bá»c sắt không hợp lệ" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "Không có mã số ngÆ°á»i dùng" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "Không có khoá bí mật" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "Äã dùng khoá bí mật không đúng" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "Khoá buổi hợp sai" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "Thuật toán nén không rõ" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "Số không phải nguyên tố" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "PhÆ°Æ¡ng pháp mã hoá không hợp lệ" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "Lược đồ mật mã hoá không hợp lệ" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "Lược đồ chữ ký không hợp lệ" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "Thuá»™c tính không hợp lệ" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "Không có giá trị" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "Không tìm thấy" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "Không tìm thấy giá trị" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "Lá»—i cú pháp" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "Giá trị MPI sai" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "Cụm từ mật khẩu không hợp lệ" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "Hạng chữ ký không hợp lệ" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "Cạn tài nguyên" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "Vòng khoá không hợp lệ" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "Lá»—i CSDL tin cậy" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "Chứng nhận sai" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "Mã số ngÆ°á»i dùng không hợp lệ" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "Gặp lá»—i bất thÆ°á»ng" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "Giá» xung Ä‘á»™t" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "Lá»—i máy phục vụ khoá" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "Thuật toán khoá công không đúng" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "Cống cho D. A." + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "Khoá mật mã yếu" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "Chiá»u dài khoá không hợp lệ" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "Äối số không hợp lệ" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "Lá»—i cú pháp trong URI" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "URI không hợp lệ" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "Lá»—i chạy mạng" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "Không nhận ra máy chủ" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "Lá»—i tá»± thá»­" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "ChÆ°a mật mã dữ liệu" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "ChÆ°a xá»­ lý dữ liệu" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "Khoá công vô ích" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "Khoá bí mật vô ích" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "Giá trị không hợp lệ" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "Dây chứng nhận sai" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "Chứng nhận còn thiếu" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "Không có dữ liệu" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "Lá»—i" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "Không được há»— trợ" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "Mã thao tác không hợp lệ" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "Quá giá»" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "Lá»—i ná»™i bá»™" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "Kết thúc tập tin (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "Äối tượng không hợp lệ" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "Äã cung cấp má»™t đối tượng quá ngắn" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "Äã cung cấp má»™t đối tượng quá lá»›n" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "Thiếu mục trong đối tượng" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "Không được thá»±c hiện" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "Cách sá»­ dụng xung Ä‘á»™t" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "Chế Ä‘á»™ mật mã không hợp lệ" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "Cá» không hợp lệ" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "Bá»™ quản lý không hợp lệ" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "Kết quả bị cắt ngắn" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "Dòng không hoàn toàn" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "Äáp ứng không hợp lệ" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "Không có tác nhân Ä‘ang chạy" + +#: src/err-codes.h:106 +#, fuzzy +#| msgid "agent error" +msgid "Agent error" +msgstr "lá»—i tác nhân" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "Dữ liệu không hợp lệ" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "Lá»—i máy phục vụ Assuan chung" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "Lá»—i Assuan chung" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "Khoá buổi hợp không hợp lệ" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "Biểu thức S không hợp lệ" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "Thuật toán không được há»— trợ" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "Không có pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "Lá»—i pinentry" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "PIN sai" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "Tên không hợp lệ" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "Dữ liệu sai" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "Tham số không hợp lệ" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "Thẻ không đúng" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "Không có dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "Lá»—i dirmngr" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "Chứng nhận bị thu hồi" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "Không co CRL đã biết" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL quá cÅ©" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "Dòng quá dài" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "Không tin cậy" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "Thao tác bị hủy bá»" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "Chứng nhận CA (nhà cầm quyá»n chứng nhận) sai" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "Chứng nhận đã hết hạn" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "Chứng nhận quá má»›i" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "Chứng nhận không được há»— trợ" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "Biểu thức S không rõ" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "Sá»± bảo vệ không được há»— trợ" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "Sá»± bảo vệ bị há»ng" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "Tên má» hồ" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "Lá»—i thẻ" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "Cần thiết lập lại thẻ" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "Thẻ bị gỡ bá»" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "Thẻ không hợp lệ" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "Không có thẻ" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "Không có ứng dụng PKCS15" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "ChÆ°a xác nhận" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "Lá»—i cấu hình" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "Không có chính sách tÆ°Æ¡ng ứng" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "Chỉ mục không hợp lệ" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "Mã số không hợp lệ" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "Không có trình ná»n Thẻ Khéo" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "Lá»—i trình ná»n Thẻ Khéo" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "Giao thức không được há»— trợ" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "PhÆ°Æ¡ng pháp PIN sai" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "ChÆ°a sÆ¡ khởi thẻ" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "Thao tác không được há»— trợ" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "Sai dùng khoá" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "Không tìm thấy" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "Sai kiểu blob" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "Thiếu giá trị" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "Lá»—i phần cứng" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN bị chặn" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "ChÆ°a thá»a mãn các Ä‘iá»u kiện dùng" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "Các PIN chÆ°a đồng bá»™" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "CRL không hợp lệ" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "Lá»—i BER" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "BER không hợp lệ" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "Không tìm thấy phần tá»­" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "Không tìm thấy bá»™ nhận diện" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "Thẻ (tag) không hợp lệ" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "Chiá»u dài không hợp lệ" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "Thông tin khoá không hợp lệ" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "Thẻ (tag) bất thÆ°á»ng" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "Không phải mã hoá DER" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "Không có đối tượng CMS" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "Äối tượng CMS không hợp lệ" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "Äối tượng CMS không rõ" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "Äối tượng CMS không được há»— trợ" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "Bảng mã không được há»— trợ" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "Phiên bản CMS không được há»— trợ" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "Thuật toán không rõ" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "CÆ¡ chế mật mã không hợp lệ" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "Khoá công không tin cậy" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "Lá»—i giải mật mã" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "Khoá hết hạn" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "Chữ ký hết hạn" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "Lá»—i mã hoá" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "Tình trạng không hợp lệ" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "Giá trị trùng" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "Thiếu hành Ä‘á»™ng" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "Không tìm thấy mô-Ä‘un ASN.1" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "Chuá»—i OID không hợp lệ" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "Thá»i gian không hợp lệ" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "Äối tượng CRL không hợp lệ" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "Phiên bản CRL không được há»— trợ" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "Äối tượng chứng nhận không hợp lệ" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "Tên không rõ" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "Má»™t hàm miá»n địa phÆ°Æ¡ng bị lá»—i" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "Không phải bị khoá" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "Vi phạm giao thức" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "MAC không hợp lệ" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "Yêu cầu không hợp lệ" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "Phần mở rá»™ng không rõ" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "Phần mở rá»™ng nghiêm trá»ng không rõ" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "Bị khoá" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "Tùy chá»n không rõ" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "Lệnh không rõ" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "Không hoạt Ä‘á»™ng được" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "ChÆ°a Ä‘Æ°a ra cụm từ mật khẩu" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "ChÆ°a Ä‘Æ°a ra số cá nhân PIN" + +#: src/err-codes.h:207 +#, fuzzy +msgid "Not enabled" +msgstr "Không phải bị khoá" + +#: src/err-codes.h:208 +#, fuzzy +msgid "No crypto engine" +msgstr "CÆ¡ chế mật mã không hợp lệ" + +#: src/err-codes.h:209 +#, fuzzy +msgid "Missing key" +msgstr "Thiếu giá trị" + +#: src/err-codes.h:210 +#, fuzzy +msgid "Too many objects" +msgstr "Không có đối tượng CMS" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "" + +#: src/err-codes.h:212 +#, fuzzy +msgid "Not initialized" +msgstr "ChÆ°a sÆ¡ khởi thẻ" + +#: src/err-codes.h:213 +#, fuzzy +msgid "Missing issuer certificate" +msgstr "Chứng nhận còn thiếu" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "" + +#: src/err-codes.h:215 +#, fuzzy +msgid "Invalid elliptic curve" +msgstr "Thá»i gian không hợp lệ" + +#: src/err-codes.h:216 +#, fuzzy +msgid "Unknown elliptic curve" +msgstr "Nguồn không rõ" + +#: src/err-codes.h:217 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated key" +msgstr "Giá trị trùng" + +#: src/err-codes.h:218 +#, fuzzy +#| msgid "Ambiguous name" +msgid "Ambiguous result" +msgstr "Tên má» hồ" + +#: src/err-codes.h:219 +#, fuzzy +msgid "No crypto context" +msgstr "CÆ¡ chế mật mã không hợp lệ" + +#: src/err-codes.h:220 +#, fuzzy +msgid "Wrong crypto context" +msgstr "CÆ¡ chế mật mã không hợp lệ" + +#: src/err-codes.h:221 +#, fuzzy +#| msgid "Invalid crypto engine" +msgid "Bad crypto context" +msgstr "CÆ¡ chế mật mã không hợp lệ" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "" + +#: src/err-codes.h:223 +#, fuzzy +#| msgid "No public key" +msgid "Broken public key" +msgstr "Không có khoá công" + +#: src/err-codes.h:224 +#, fuzzy +#| msgid "No secret key" +msgid "Broken secret key" +msgstr "Không có khoá bí mật" + +#: src/err-codes.h:225 +#, fuzzy +#| msgid "Invalid digest algorithm" +msgid "Invalid MAC algorithm" +msgstr "Thuật toán bá»™ tóm tắt (digest) không hợp lệ" + +#: src/err-codes.h:226 +#, fuzzy +msgid "Operation fully cancelled" +msgstr "Thao tác bị hủy bá»" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "Thao tác chÆ°a kết thúc" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "Vùng đệm quá ngắn" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "Chỉ thị chiá»u dài không hợp lệ trong biểu thức S" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "Chuá»—i quá dài trong biểu thức S" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "Có dấu ngoặc chÆ°a khá»›p trong biểu thức S" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "Biểu thức S không phải chuẩn tắc" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "Ký tá»± sai trong biểu thức S" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "Äoạn trích dẫn sai trong biểu thức S" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "Tiá»n tố số không trong biểu thức S" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "Có mẹo trình bày lồng nhau trong biểu thức S" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "Có mẹo trình bày chÆ°a khá»›p" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "Có dấu chấm câu dành riêng bất thÆ°á»ng trong biểu thức S" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "Ký tá»± thập lục sai trong biểu thức S" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "Có số thập lục lẻ trong biểu thức S" + +#: src/err-codes.h:241 +#, fuzzy +msgid "Bad octal character in S-expression" +msgstr "Ký tá»± bát phân sai trong biểu thức S" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "" + +#: src/err-codes.h:243 +#, fuzzy +#| msgid "Data not encrypted" +msgid "Database is corrupted" +msgstr "ChÆ°a mật mã dữ liệu" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "" + +#: src/err-codes.h:245 +#, fuzzy +#| msgid "Unknown name" +msgid "No name" +msgstr "Tên không rõ" + +#: src/err-codes.h:246 +#, fuzzy +#| msgid "No public key" +msgid "No key" +msgstr "Không có khoá công" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "" + +#: src/err-codes.h:248 +#, fuzzy +#| msgid "Buffer too short" +msgid "Request too short" +msgstr "Vùng đệm quá ngắn" + +#: src/err-codes.h:249 +#, fuzzy +#| msgid "Line too long" +msgid "Request too long" +msgstr "Dòng quá dài" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "" + +#: src/err-codes.h:251 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "No certificate chain" +msgstr "Dây chứng nhận sai" + +#: src/err-codes.h:252 +#, fuzzy +#| msgid "Certificate too young" +msgid "Certificate is too large" +msgstr "Chứng nhận quá má»›i" + +#: src/err-codes.h:253 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid record" +msgstr "Thẻ không hợp lệ" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "" + +#: src/err-codes.h:255 +#, fuzzy +#| msgid "Unexpected tag" +msgid "Unexpected message" +msgstr "Thẻ (tag) bất thÆ°á»ng" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "" + +#: src/err-codes.h:259 +#, fuzzy +#| msgid "Invalid cipher algorithm" +msgid "No cipher algorithm" +msgstr "Thuật toán mật mã không hợp lệ" + +#: src/err-codes.h:260 +#, fuzzy +msgid "Missing client certificate" +msgstr "Chứng nhận còn thiếu" + +#: src/err-codes.h:261 +#, fuzzy +#| msgid "Certificate revoked" +msgid "Close notification received" +msgstr "Chứng nhận bị thu hồi" + +#: src/err-codes.h:262 +#, fuzzy +#| msgid "Key expired" +msgid "Ticket expired" +msgstr "Khoá hết hạn" + +#: src/err-codes.h:263 +#, fuzzy +#| msgid "Bad public key" +msgid "Bad ticket" +msgstr "Khoá công sai" + +#: src/err-codes.h:264 +#, fuzzy +#| msgid "Unknown packet" +msgid "Unknown identity" +msgstr "Gói tin không rõ" + +#: src/err-codes.h:265 +#, fuzzy +#| msgid "Bad certificate chain" +msgid "Bad certificate message in handshake" +msgstr "Dây chứng nhận sai" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "" + +#: src/err-codes.h:277 +#, fuzzy +#| msgid "Key expired" +msgid "Key disabled" +msgstr "Khoá hết hạn" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "" + +#: src/err-codes.h:279 +#, fuzzy +#| msgid "Invalid object" +msgid "Invalid lock object" +msgstr "Äối tượng không hợp lệ" + +#: src/err-codes.h:280 +msgid "True" +msgstr "" + +#: src/err-codes.h:281 +msgid "False" +msgstr "" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "Lá»—i IPC chung" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "Lá»i gá»i chấp nhận IPC bị lá»—i" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "Lá»i gá»i kết nối IPC bị lá»—i" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "Äáp ứng IPC không hợp lệ" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "Giá trị không hợp lệ được gá»­i cho IPC" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "Dòng không hoàn toàn được gá»­i cho IPC" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "Dòng quá dài được gá»­i cho IPC" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "Các câu lệnh IPC lồng nhau" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "Không có lá»i gá»i ngược lại dữ liệu trong IPC" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "Không có lá»i gá»i ngược lại yêu cầu trong IPC" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "Không phải trình phục vụ IPC" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "Không phải ứng dụng khách IPC" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "Gặp khó khăn trong việc khởi chạy trình phục vụ IPC" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "Lá»—i Ä‘á»c IPC" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "Lá»—i ghi IPC" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "Quá nhiá»u dữ liệu cho lá»›p IPC" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "Câu lệnh IPC bất thÆ°á»ng" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "Câu lệnh IPC không rõ" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "Lá»—i cú pháp IPC" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "Lá»i gá»i IPC bị thôi" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "Không có nguồn nhập vào cho IPC" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "Không có nguồn kết xuất cho IPC" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "Lá»—i tham số IPC" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "Yêu cầu IPC không rõ" + +#: src/err-codes.h:306 +#, fuzzy +msgid "Crypto engine too old" +msgstr "CÆ¡ chế mật mã không hợp lệ" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "" + +#: src/err-codes.h:312 +#, fuzzy +#| msgid "Duplicated value" +msgid "Duplicated name" +msgstr "Giá trị trùng" + +#: src/err-codes.h:313 +#, fuzzy +#| msgid "Certificate too young" +msgid "Object is too young" +msgstr "Chứng nhận quá má»›i" + +#: src/err-codes.h:314 +#, fuzzy +#| msgid "Provided object is too short" +msgid "Object is too old" +msgstr "Äã cung cấp má»™t đối tượng quá ngắn" + +#: src/err-codes.h:315 +#, fuzzy +#| msgid "Unknown name" +msgid "Unknown flag" +msgstr "Tên không rõ" + +#: src/err-codes.h:316 +#, fuzzy +#| msgid "Invalid operation code" +msgid "Invalid execution order" +msgstr "Mã thao tác không hợp lệ" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "" + +#: src/err-codes.h:319 +#, fuzzy +#| msgid "Unknown name" +msgid "Wrong name" +msgstr "Tên không rõ" + +#: src/err-codes.h:320 +#, fuzzy +msgid "Not authenticated" +msgstr "Không phải bị khoá" + +#: src/err-codes.h:321 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Bad authentication" +msgstr "Sá»± bảo vệ không được há»— trợ" + +#: src/err-codes.h:322 +#, fuzzy +#| msgid "No agent running" +msgid "No Keybox daemon running" +msgstr "Không có tác nhân Ä‘ang chạy" + +#: src/err-codes.h:323 +#, fuzzy +#| msgid "SmartCard daemon error" +msgid "Keybox daemon error" +msgstr "Lá»—i trình ná»n Thẻ Khéo" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "" + +#: src/err-codes.h:325 +#, fuzzy +#| msgid "Keyserver error" +msgid "Service error" +msgstr "Lá»—i máy phục vụ khoá" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "" + +#: src/err-codes.h:327 +#, fuzzy +#| msgid "Unknown system error" +msgid "Unknown DNS error" +msgstr "Gặp lá»—i hệ thống không rõ" + +#: src/err-codes.h:328 +#, fuzzy +#| msgid "Invalid OID string" +msgid "Invalid DNS section" +msgstr "Chuá»—i OID không hợp lệ" + +#: src/err-codes.h:329 +#, fuzzy +#| msgid "Invalid S-expression" +msgid "Invalid textual address form" +msgstr "Biểu thức S không hợp lệ" + +#: src/err-codes.h:330 +#, fuzzy +msgid "Missing DNS query packet" +msgstr "Chứng nhận còn thiếu" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "" + +#: src/err-codes.h:333 +#, fuzzy +#| msgid "Decryption failed" +msgid "Verification failed in DNS" +msgstr "Lá»—i giải mật mã" + +#: src/err-codes.h:334 +#, fuzzy +#| msgid "Timeout" +msgid "DNS Timeout" +msgstr "Quá giá»" + +#: src/err-codes.h:335 +#, fuzzy +#| msgid "General IPC error" +msgid "General LDAP error" +msgstr "Lá»—i IPC chung" + +#: src/err-codes.h:336 +#, fuzzy +#| msgid "General error" +msgid "General LDAP attribute error" +msgstr "Lá»—i chung" + +#: src/err-codes.h:337 +#, fuzzy +#| msgid "General error" +msgid "General LDAP name error" +msgstr "Lá»—i chung" + +#: src/err-codes.h:338 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP security error" +msgstr "Lá»—i Assuan chung" + +#: src/err-codes.h:339 +#, fuzzy +#| msgid "General error" +msgid "General LDAP service error" +msgstr "Lá»—i chung" + +#: src/err-codes.h:340 +#, fuzzy +#| msgid "General Assuan error" +msgid "General LDAP update error" +msgstr "Lá»—i Assuan chung" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "" + +#: src/err-codes.h:342 +#, fuzzy +#| msgid "IPC write error" +msgid "Private LDAP error code" +msgstr "Lá»—i ghi IPC" + +#: src/err-codes.h:343 +#, fuzzy +#| msgid "General IPC error" +msgid "Other general LDAP error" +msgstr "Lá»—i IPC chung" + +#: src/err-codes.h:344 +#, fuzzy +#| msgid "IPC connect call failed" +msgid "LDAP connecting failed (X)" +msgstr "Lá»i gá»i kết nối IPC bị lá»—i" + +#: src/err-codes.h:345 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral limit exceeded" +msgstr "Lá»—i chung" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "" + +#: src/err-codes.h:347 +#, fuzzy +#| msgid "Card reset required" +msgid "No LDAP results returned" +msgstr "Cần thiết lập lại thẻ" + +#: src/err-codes.h:348 +#, fuzzy +#| msgid "Element not found" +msgid "LDAP control not found" +msgstr "Không tìm thấy phần tá»­" + +#: src/err-codes.h:349 +#, fuzzy +#| msgid "Not supported" +msgid "Not supported by LDAP" +msgstr "Không được há»— trợ" + +#: src/err-codes.h:350 +#, fuzzy +#| msgid "Unexpected error" +msgid "LDAP connect error" +msgstr "Gặp lá»—i bất thÆ°á»ng" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "" + +#: src/err-codes.h:353 +#, fuzzy +#| msgid "Unsupported operation" +msgid "User cancelled LDAP operation" +msgstr "Thao tác không được há»— trợ" + +#: src/err-codes.h:354 +#, fuzzy +#| msgid "Bad certificate" +msgid "Bad LDAP search filter" +msgstr "Chứng nhận sai" + +#: src/err-codes.h:355 +#, fuzzy +#| msgid "Unknown extension" +msgid "Unknown LDAP authentication method" +msgstr "Phần mở rá»™ng không rõ" + +#: src/err-codes.h:356 +#, fuzzy +#| msgid "Timeout" +msgid "Timeout in LDAP" +msgstr "Quá giá»" + +#: src/err-codes.h:357 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP decoding error" +msgstr "Lá»—i dirmngr" + +#: src/err-codes.h:358 +#, fuzzy +#| msgid "dirmngr error" +msgid "LDAP encoding error" +msgstr "Lá»—i dirmngr" + +#: src/err-codes.h:359 +#, fuzzy +#| msgid "IPC read error" +msgid "LDAP local error" +msgstr "Lá»—i Ä‘á»c IPC" + +#: src/err-codes.h:360 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot contact LDAP server" +msgstr "Không phải trình phục vụ IPC" + +#: src/err-codes.h:361 +#, fuzzy +#| msgid "Success" +msgid "LDAP success" +msgstr "Thành công" + +#: src/err-codes.h:362 +#, fuzzy +#| msgid "Configuration error" +msgid "LDAP operations error" +msgstr "Lá»—i cấu hình" + +#: src/err-codes.h:363 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP protocol error" +msgstr "Vi phạm giao thức" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "" + +#: src/err-codes.h:368 +#, fuzzy +#| msgid "Unknown extension" +msgid "LDAP authentication method not supported" +msgstr "Phần mở rá»™ng không rõ" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "" + +#: src/err-codes.h:371 +#, fuzzy +#| msgid "General error" +msgid "LDAP referral" +msgstr "Lá»—i chung" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "" + +#: src/err-codes.h:374 +#, fuzzy +#| msgid "Card reset required" +msgid "Confidentiality required by LDAP" +msgstr "Cần thiết lập lại thẻ" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "" + +#: src/err-codes.h:377 +#, fuzzy +#| msgid "Invalid attribute" +msgid "Undefined LDAP attribute type" +msgstr "Thuá»™c tính không hợp lệ" + +#: src/err-codes.h:378 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate matching in LDAP" +msgstr "Sá»± bảo vệ không được há»— trợ" + +#: src/err-codes.h:379 +#, fuzzy +#| msgid "Protocol violation" +msgid "Constraint violation in LDAP" +msgstr "Vi phạm giao thức" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "" + +#: src/err-codes.h:381 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid syntax in LDAP" +msgstr "Tình trạng không hợp lệ" + +#: src/err-codes.h:382 +#, fuzzy +#| msgid "No CMS object" +msgid "No such LDAP object" +msgstr "Không có đối tượng CMS" + +#: src/err-codes.h:383 +#, fuzzy +#| msgid "Hardware problem" +msgid "LDAP alias problem" +msgstr "Lá»—i phần cứng" + +#: src/err-codes.h:384 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid DN syntax in LDAP" +msgstr "Tình trạng không hợp lệ" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "" + +#: src/err-codes.h:386 +#, fuzzy +#| msgid "Encoding problem" +msgid "LDAP alias dereferencing problem" +msgstr "Lá»—i mã hoá" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "" + +#: src/err-codes.h:388 +#, fuzzy +#| msgid "Unsupported protection" +msgid "Inappropriate LDAP authentication" +msgstr "Sá»± bảo vệ không được há»— trợ" + +#: src/err-codes.h:389 +#, fuzzy +#| msgid "Invalid card" +msgid "Invalid LDAP credentials" +msgstr "Thẻ không hợp lệ" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "" + +#: src/err-codes.h:395 +#, fuzzy +#| msgid "Missing action" +msgid "LDAP naming violation" +msgstr "Thiếu hành Ä‘á»™ng" + +#: src/err-codes.h:396 +#, fuzzy +#| msgid "Protocol violation" +msgid "LDAP object class violation" +msgstr "Vi phạm giao thức" + +#: src/err-codes.h:397 +#, fuzzy +#| msgid "Operation not yet finished" +msgid "LDAP operation not allowed on non-leaf" +msgstr "Thao tác chÆ°a kết thúc" + +#: src/err-codes.h:398 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation not allowed on RDN" +msgstr "Thao tác bị hủy bá»" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "" + +#: src/err-codes.h:401 +#, fuzzy +#| msgid "Line too long" +msgid "LDAP results too large" +msgstr "Dòng quá dài" + +#: src/err-codes.h:402 +#, fuzzy +#| msgid "Operation cancelled" +msgid "LDAP operation affects multiple DSAs" +msgstr "Thao tác bị hủy bá»" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "" + +#: src/err-codes.h:404 +#, fuzzy +#| msgid "General IPC error" +msgid "Other LDAP error" +msgstr "Lá»—i IPC chung" + +#: src/err-codes.h:405 +#, fuzzy +#| msgid "Resources exhausted" +msgid "Resources exhausted in LCUP" +msgstr "Cạn tài nguyên" + +#: src/err-codes.h:406 +#, fuzzy +#| msgid "Protocol violation" +msgid "Security violation in LCUP" +msgstr "Vi phạm giao thức" + +#: src/err-codes.h:407 +#, fuzzy +#| msgid "Invalid state" +msgid "Invalid data in LCUP" +msgstr "Tình trạng không hợp lệ" + +#: src/err-codes.h:408 +#, fuzzy +#| msgid "Unsupported certificate" +msgid "Unsupported scheme in LCUP" +msgstr "Chứng nhận không được há»— trợ" + +#: src/err-codes.h:409 +#, fuzzy +#| msgid "Card reset required" +msgid "Reload required in LCUP" +msgstr "Cần thiết lập lại thẻ" + +#: src/err-codes.h:410 +#, fuzzy +#| msgid "Success" +msgid "LDAP cancelled" +msgstr "Thành công" + +#: src/err-codes.h:411 +#, fuzzy +#| msgid "Not operational" +msgid "No LDAP operation to cancel" +msgstr "Không hoạt Ä‘á»™ng được" + +#: src/err-codes.h:412 +#, fuzzy +#| msgid "Not operational" +msgid "Too late to cancel LDAP" +msgstr "Không hoạt Ä‘á»™ng được" + +#: src/err-codes.h:413 +#, fuzzy +#| msgid "Not an IPC server" +msgid "Cannot cancel LDAP" +msgstr "Không phải trình phục vụ IPC" + +#: src/err-codes.h:414 +#, fuzzy +#| msgid "Decryption failed" +msgid "LDAP assertion failed" +msgstr "Lá»—i giải mật mã" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "Mã lá»—i tá»± xác định 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "Mã lá»—i tá»± xác định 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "Mã lá»—i tá»± xác định 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "Mã lá»—i tá»± xác định 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "Mã lá»—i tá»± xác định 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "Mã lá»—i tá»± xác định 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "Mã lá»—i tá»± xác định 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "Mã lá»—i tá»± xác định 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "Mã lá»—i tá»± xác định 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "Mã lá»—i tá»± xác định 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "Mã lá»—i tá»± xác định 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "Mã lá»—i tá»± xác định 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "Mã lá»—i tá»± xác định 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "Mã lá»—i tá»± xác định 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "Mã lá»—i tá»± xác định 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "Mã lá»—i tá»± xác định 16" + +#: src/err-codes.h:432 +#, fuzzy +#| msgid "Success" +msgid "SQL success" +msgstr "Thành công" + +#: src/err-codes.h:433 +#, fuzzy +#| msgid "Syntax error" +msgid "SQL error" +msgstr "Lá»—i cú pháp" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "" + +#: src/err-codes.h:447 +#, fuzzy +#| msgid "Protocol violation" +msgid "SQL database lock protocol error" +msgstr "Vi phạm giao thức" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "Lá»—i hệ thống không có số thứ tá»± lá»—i" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "Gặp lá»—i hệ thống không rõ" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "Kết thúc tập tin" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "Mã lá»—i không rõ" + +#: src/argparse.c:468 +#, fuzzy +#| msgid "Data not encrypted" +msgid "argument not expected" +msgstr "ChÆ°a mật mã dữ liệu" + +#: src/argparse.c:470 +#, fuzzy +#| msgid "IPC read error" +msgid "read error" +msgstr "Lá»—i Ä‘á»c IPC" + +#: src/argparse.c:472 +#, fuzzy +#| msgid "Line too long" +msgid "keyword too long" +msgstr "Dòng quá dài" + +#: src/argparse.c:474 +#, fuzzy +#| msgid "Missing value" +msgid "missing argument" +msgstr "Thiếu giá trị" + +#: src/argparse.c:476 +#, fuzzy +#| msgid "Invalid argument" +msgid "invalid argument" +msgstr "Äối số không hợp lệ" + +#: src/argparse.c:478 +#, fuzzy +#| msgid "Invalid card" +msgid "invalid command" +msgstr "Thẻ không hợp lệ" + +#: src/argparse.c:480 +#, fuzzy +#| msgid "Invalid OID string" +msgid "invalid alias definition" +msgstr "Chuá»—i OID không hợp lệ" + +#: src/argparse.c:482 src/argparse.c:519 +#, fuzzy +#| msgid "Configuration error" +msgid "permission error" +msgstr "Lá»—i cấu hình" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "" + +#: src/argparse.c:488 src/argparse.c:523 +#, fuzzy +#| msgid "Invalid card" +msgid "invalid meta command" +msgstr "Thẻ không hợp lệ" + +#: src/argparse.c:490 src/argparse.c:525 +#, fuzzy +#| msgid "Unknown command" +msgid "unknown meta command" +msgstr "Lệnh không rõ" + +#: src/argparse.c:492 src/argparse.c:527 +#, fuzzy +#| msgid "Unexpected IPC command" +msgid "unexpected meta command" +msgstr "Câu lệnh IPC bất thÆ°á»ng" + +#: src/argparse.c:494 +#, fuzzy +#| msgid "Invalid operation code" +msgid "invalid option" +msgstr "Mã thao tác không hợp lệ" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "" + +#: src/argparse.c:529 +#, fuzzy, c-format +#| msgid "Invalid operation code" +msgid "invalid option \"%.50s\"\n" +msgstr "Mã thao tác không hợp lệ" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "cảnh báo : không thể nhận ra %s\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "Sá»­ dụng: %s GPG-ERROR [...]\n" + +#, fuzzy +#~| msgid "Resources exhausted" +#~ msgid "LCUP Resources exhausted" +#~ msgstr "Cạn tài nguyên" + +#, fuzzy +#~| msgid "Invalid data" +#~ msgid "LCUP Invalid data" +#~ msgstr "Dữ liệu không hợp lệ" + +#, fuzzy +#~| msgid "General error" +#~ msgid "LDAP Other general error" +#~ msgstr "Lá»—i chung" + +#, fuzzy +#~| msgid "dirmngr error" +#~ msgid "Encoding error" +#~ msgstr "Lá»—i dirmngr" diff --git a/comm/third_party/libgpg-error/po/zh_CN.gmo b/comm/third_party/libgpg-error/po/zh_CN.gmo new file mode 100644 index 0000000000..9304154390 Binary files /dev/null and b/comm/third_party/libgpg-error/po/zh_CN.gmo differ diff --git a/comm/third_party/libgpg-error/po/zh_CN.po b/comm/third_party/libgpg-error/po/zh_CN.po new file mode 100644 index 0000000000..0f717d11bd --- /dev/null +++ b/comm/third_party/libgpg-error/po/zh_CN.po @@ -0,0 +1,1996 @@ +# Simplified Chinese translation to libgpg-error. +# Copyright (C) 2009 Free Software Foundation, Inc. +# This file is distributed under the same license as the libgpg-error package. +# Aron Xu , 2009. +# Chinese (simplified) , 2009. +# bobwxc , 2020. +# 请注æ„secret key在此处请译为ç§é’¥ï¼Œå¯†é’¥æ³›æŒ‡key +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.39\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:44+0100\n" +"Last-Translator: bobwxc \n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 2.2.1\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "未指定æº" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG Agent代ç†" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "Pinentry" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox钥匙盒" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "任何æ¥æº" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "用户定义的æ¥æº 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "用户定义的æ¥æº 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "用户定义的æ¥æº 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "用户定义的æ¥æº 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "未知æ¥æº" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "æˆåŠŸ" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "常规错误" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "未知的包" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "包中未知的版本" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "无效的公钥算法" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "无效的摘è¦ç®—法" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "æŸå的公钥" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "æŸåçš„ç§é’¥" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "æŸåçš„ç­¾å" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "缺少公钥" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "校验错误" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "æŸå的密ç " + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "无效的密ç ç®—法" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "无法打开钥匙环" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "无效的数æ®åŒ…" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "无效的ä¿æŠ¤å£³" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "缺少用户标识" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "缺少ç§é’¥" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "使用了错误的ç§é’¥" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "æŸå的会è¯å¯†é’¥" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "未知的压缩算法" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "ä¸æ˜¯ç´ æ•°" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "无效的编ç æ–¹æ³•" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "无效的加密方案" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "无效的签å方案" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "无效的属性" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "没有值" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "未找到" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "没有å‘现值" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "语法错误" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "æŸåçš„ MPI 值" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "无效的密ç " + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "无效的签åç±»" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "内存耗尽" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "无效的密钥环" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "信任数æ®åº“错误" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "æŸåçš„è¯ä¹¦" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "无效的用户标识" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "æ„外错误" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "时间冲çª" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "密钥æœåŠ¡å™¨é”™è¯¯" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "错误的公开密钥算法" + +# é“格拉斯·亚当斯(Douglas Adams 1952å¹´3月11æ—¥ -- 2001å¹´5月11日) +# 生于英国剑桥,英国广播剧作家ã€éŸ³ä¹å®¶ï¼Œå°¤å…¶ä»¥ã€Šé“¶æ²³ç³»æ¼«æ¸¸æŒ‡å—》 +# 系列作å“出å。这部作å“以广播剧起家,åŽæ¥å‘展æˆåŒ…括五本书的“三 +# 部曲â€ï¼Œæ‹æˆç”µè§†è¿žç»­å‰§ã€‚亚当斯é€ä¸–åŽè¿˜æ‹æˆç”µå½±ã€‚äºšå½“æ–¯è‡ªç§°ä¸ºâ€œæž +# 端无神论者â€ã€‚在去世以å‰ï¼Œä»–是一ä½éžå¸¸å—欢迎的演讲者,尤其是在 +# 科技和环ä¿ç­‰é¢˜ææ–¹é¢ã€‚他在49å²æ—¶çš„æ—©é€åœ¨ç§‘幻和奇幻社群中引起了 +# æžå¤§çš„哀悼。 +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "å‘é“格拉斯·亚当斯致敬" + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "弱加密密钥" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "无效的密钥长度" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "无效的å‚æ•°" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "以下 URI 中语法错误" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "无效的 URI" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "网络错误" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "未知的主机" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "自测失败" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "æ•°æ®æœªåŠ å¯†" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "æ•°æ®æœªå¤„ç†" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "ä¸å¯ç”¨å…¬é’¥" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "ä¸å¯ç”¨ç§é’¥" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "无效值" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "æŸåçš„è¯ä¹¦é“¾" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "缺失è¯ä¹¦" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "æ— æ•°æ®" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "错误" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "ä¸æ”¯æŒ" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "无效的æ“作ç " + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "超时" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "内部错误" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "无效的对象" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "æ供的对象太短" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "æ供的对象太大" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "对象中缺少项目" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "未实现" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "冲çªçš„用法" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "无效的加密模å¼" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "无效标志" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "无效å¥æŸ„" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "结果已截断" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "ä¸å®Œæ•´è¡Œ" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "无效的å“应" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "未è¿è¡Œä»£ç†" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "Agent 代ç†é”™è¯¯" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "无效的数æ®" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "ä¸æ˜Žçš„ Assuan æœåŠ¡å™¨é”™è¯¯" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "常规 Assuan 错误" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "无效的会è¯å¯†é’¥" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "无效的 S-表达å¼" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "ä¸æ”¯æŒçš„算法" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "缺少 pinentry" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "pinentry 错误" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "æŸåçš„ PIN" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "无效的å称" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "ä¸è‰¯æ•°æ®" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "无效的å‚æ•°" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "错误的å¡" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "缺少 dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr 错误" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "è¯ä¹¦å·²åŠé”€" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "无已知的 CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL 过于陈旧" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "行太长" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "ä¸ä¿¡ä»»" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "æ“作已å–消" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "æŸåçš„ CA è¯ä¹¦" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "è¯ä¹¦å·²è¿‡æœŸ" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "è¯ä¹¦å¤ªæ–°" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "ä¸æ”¯æŒçš„凭è¯" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "未知的 S-表达å¼" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "ä¸å—支æŒçš„ä¿æŠ¤" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "æŸåçš„ä¿æŠ¤" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "å称ä¸æ˜Žç¡®" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "å¡é”™è¯¯" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "è¦æ±‚é‡ç½®å¡" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "å¡å·²åˆ é™¤" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "无效的å¡" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "å¡ä¸å­˜åœ¨" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "没有 PKCS15 应用程åº" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "未确认" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "é…置错误" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "没有匹é…的规则" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "无效的索引" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "无效的 ID" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "没有智能å¡å®ˆæŠ¤è¿›ç¨‹" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "智能å¡å®ˆæŠ¤ç¨‹åºé”™è¯¯" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "ä¸æ”¯æŒçš„åè®®" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "无效的 PIN 方法" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "å¡æœªåˆå§‹åŒ–" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "ä¸æ”¯æŒçš„æ“作" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "错误的密钥用法" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "未找到" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "错误的 blob 类型" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "缺失值" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "硬件问题" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "PIN å·²å±è”½" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "使用æ¡ä»¶ä¸æ»¡è¶³" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "PINs ä¸åŒæ­¥" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "无效的 CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER 错误" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "无效的 BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "未找到元素" + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "未找到标识符" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "无效的标签" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "无效的长度" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "无效的密钥信æ¯" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "æ„外的标记" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "éž DER ç¼–ç " + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "没有 CMS 对象" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "无效的 CMS 对象" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "未知的 CMS 对象" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "ä¸æ”¯æŒçš„ CMS 对象" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "ä¸æ”¯æŒçš„ç¼–ç " + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "ä¸æ”¯æŒçš„ CMS 版本" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "未知的算法" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "无效的加密引擎" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "公钥ä¸è¢«ä¿¡ä»»" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "解密失败" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "密钥已过期" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "ç­¾å过期" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "ç¼–ç é—®é¢˜" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "无效状æ€" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "é‡å¤å€¼" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "动作缺失" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "ASN.1 模å—未找到" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "无效的 OID 字符串" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "无效的时间" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "无效的 CRL 对象" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "ä¸æ”¯æŒçš„ CRL 版本" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "无效的è¯ä¹¦å¯¹è±¡" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "未知å称" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "区域设置功能失败" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "未é”定" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "è¿ååè®®" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "无效的 MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "无效的请求" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "未知的扩展å" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "未知的关键扩展" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "å·²é”定" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "未知的选项" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "未知命令" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "ä¸å¯æ“作" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "没有给出密ç " + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "没有给出 PIN" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "ä¸å¯ç”¨" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "无效的加密引擎" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "密钥缺失" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "对象过多" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "已达æžé™" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "未åˆå§‹åŒ–" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "缺少é¢å‘者è¯ä¹¦" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "æ— å¯ç”¨å¯†é’¥æœåŠ¡å™¨" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "无效椭圆曲线" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "æ¥æºä¸æ˜Žçš„椭圆曲线" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "é‡å¤çš„密钥" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "结果ä¸æ˜Žç¡®" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "无加密上下文" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "错误的加密上下文" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "错误的的加密上下文" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "冲çªçš„加密上下文" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "æŸå的公钥" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "æŸåçš„ç§é’¥" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "无效的 MAC 算法" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "æ“作已å–消" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "æ“作尚未完æˆ" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "缓冲区太短" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "S-表达å¼çš„长度标志符无效" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "S-表达å¼çš„字符串太长" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "S-表达å¼ä¸­æ‹¬å·ä¸åŒ¹é…" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "ä¸è§„范的 S-表达å¼" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "S-表达å¼ä¸­å­—符错误" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "S-表达å¼ä¸­å¼•å·é”™è¯¯" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "S-表达å¼é›¶å‰ç¼€" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "S-表达å¼åµŒå¥—显示æ示" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "ä¸åŒ¹é…的嵌套显示æ示" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "S-表达å¼ä¸­å‡ºçŽ°æ„外的ä¿ç•™æ ‡ç‚¹" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "S-表达å¼ä¸­å六进制字符错误" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "S-表达å¼ä¸­å六进制数异常" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "S-表达å¼ä¸­å…«è¿›åˆ¶å­—符错误" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "所有å­å¯†é’¥å‡å·²è¿‡æœŸæˆ–åŠé”€" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "æ•°æ®åº“å·²æŸå" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "æœåŠ¡å™¨æ•…éšœ" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "æ— å称" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "没有密钥" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "é—留密钥" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "请求过短" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "请求过长" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "对象处于终止状æ€" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "æ— è¯ä¹¦é“¾" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "è¯ä¹¦è¿‡å¤§" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "无效记录" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "MAC 未ç»éªŒè¯" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "æ„外消æ¯" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "压缩或解压失败" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "计数器将更新" + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "收到致命错误消æ¯" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "无密ç ç®—法" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "缺少客户端è¯ä¹¦" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "收到关闭通知" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "凭è¯å·²è¿‡æœŸ" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "æŸå的凭è¯" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "未知身份" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "æ¡æ‰‹è¯ä¹¦æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "æ¡æ‰‹è¯ä¹¦è¯·æ±‚消æ¯é”™è¯¯" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "æ¡æ‰‹è¯ä¹¦éªŒè¯æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "æ¡æ‰‹æ›´æ”¹å¯†ç æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "æ¡æ‰‹å®¢æˆ·ç«¯é—®å€™æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "æ¡æ‰‹æœåŠ¡ç«¯é—®å€™æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "æ¡æ‰‹æœåŠ¡ç«¯é—®å€™å®Œæˆæ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "æ¡æ‰‹å®Œæˆæ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "æ¡æ‰‹æœåŠ¡ç«¯å¯†é’¥äº¤æ¢æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "æ¡æ‰‹å®¢æˆ·ç«¯å¯†é’¥äº¤æ¢æ¶ˆæ¯é”™è¯¯" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "伪造的字符串" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "ç¦æ­¢" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "密钥ä¸å¯ç”¨" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "无法使用基于å¡çš„密钥" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "é”定对象无效" + +#: src/err-codes.h:280 +msgid "True" +msgstr "正确" + +#: src/err-codes.h:281 +msgid "False" +msgstr "错误" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "常规 IPC 错误" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC 接å—调用失败" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC 连接调用失败" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "无效 IPC å“应" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "传递给 IPC 的值无效" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "传递给 IPC çš„è¡Œä¸å®Œæ•´" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "传递给 IPC 的行过长" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "嵌套的 IPC 命令" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "IPC æ— æ•°æ®å›žè°ƒ" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "IPC 无查询回调" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "ä¸æ˜¯ IPC æœåŠ¡å™¨" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "ä¸æ˜¯ IPC 客户端" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "å¯åŠ¨ IPC æœåŠ¡å™¨æ—¶å‡ºçŽ°é—®é¢˜" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC 读å–错误" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC 写入错误" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "IPC 层数æ®è¿‡å¤š" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "æ„外的 IPC 命令" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "未知 IPC 命令" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC 语法错误" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC 调用已å–消" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "IPC 无输入æº" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "IPC 无输出æº" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC å‚数错误" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "未知 IPC 查询" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "加密引擎太旧" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "å±å¹•æˆ–窗å£è¿‡å°" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "å±å¹•æˆ–窗å£è¿‡å¤§" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "未设置所需的环境å˜é‡" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "用户标志已存在" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "å称已存在" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "é‡å¤çš„å称" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "对象太新" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "对象太旧" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "未知标志" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "无效的执行顺åº" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "å·²æå–" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "ç¨åŽå†è¯•" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "错误å称" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "未验è¯" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "无效验è¯" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "æ— è¿è¡Œçš„ Keybox 守护进程" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "Keybox 守护进程错误" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "æœåŠ¡æœªè¿è¡Œ" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "æœåŠ¡é”™è¯¯" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "检测到系统错误" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "未知的 DNS 错误" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "无效的 DNS 部分" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "无效的文本地å€å½¢å¼" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "缺少 DNS 查询数æ®åŒ…" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "缺少 DNS 答应数æ®åŒ…" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "DNS 连接关闭" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "DNS 验è¯å¤±è´¥" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "DNS 超时" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "常规 LDAP 错误" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "常规 LDAP 属性错误" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "常规 LDAP å称错误" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "常规 LDAP 安全错误" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "常规 LDAP æœåŠ¡é”™è¯¯" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "常规 LDAP å‡çº§é”™è¯¯" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "实验性 LDAP 错误代ç " + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "专用 LDAP 错误代ç " + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "其他常规 LDAP 错误" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "LDAP 连接失败(X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "超过 LDAP 引用é™åˆ¶" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "LDAP 客户端循环" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "æ—  LDAP 结果返回" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "未找到 LDAP 控件" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "ä¸å— LDAP 支æŒ" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "LDAP 连接错误" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "LDAP 内存ä¸è¶³" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "LDAP 事务å‚数错误" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "用户å–消 LDAP æ“作" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "错误的 LDAP æœç´¢è¿‡æ»¤å™¨" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "未知的 LDAP 身份验è¯æ–¹æ³•" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "LDAP 超时" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "LDAP 解ç é”™è¯¯" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "LDAP ç¼–ç é”™è¯¯" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "LDAP 本地错误" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "无法è”络 LDAP æœåŠ¡å™¨" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "LDAP æˆåŠŸ" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "LDAP æ“作错误" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "LDAP å议错误" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "超过 LDAP 时间é™åˆ¶" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "超过 LDAP 大å°é™åˆ¶" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "LDAP 比较错误" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "LDAP 比较正确" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "ä¸æ”¯æŒçš„ LDAP 身份验è¯æ–¹æ³•" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "需è¦å¢žå¼ºçš„ LDAP 身份验è¯" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "收到部分 LDAP 结果与引用" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "LDAP 转é€" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "è¶…è¿‡ç®¡ç† LDAP é™åˆ¶" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "关键 LDAP 扩展ä¸å¯ç”¨" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "LDAP è¦æ±‚ä¿å¯†" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "正在进行 LDAP SASL 绑定" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "没有此 LDAP 属性" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "未定义的 LDAP 属性类型" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "LDAP ä¸å½“匹é…" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "LDAP 约æŸå†²çª" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "LDAP 类型或值存在" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "LDAP 语法无效" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "æ— æ­¤ LDAP 对象" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "LDAP 别å问题" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "LDAP 无效的 DN 语法" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "LDAP å¶çŠ¶å…¥å£" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "LDAP 别å引用å–消问题" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "LDAP 代ç†æŽˆæƒå¤±è´¥ï¼ˆX)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "ä¸å½“ LDAP 身份验è¯" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "无效 LDAP 凭æ®" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "æ—  LDAP 访问æƒé™" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "LDAP æœåŠ¡å™¨å¿™" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "LDAP æœåŠ¡å™¨ä¸å¯ç”¨" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "LDAP æœåŠ¡å™¨æ‹’ç»æ‰§è¡Œ" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "LDAP 检测到循环" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "LDAP 命å冲çª" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "LDAP 对象类冲çª" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "ä¸å…许在éžå¶ä¸Šæ‰§è¡Œ LDAP æ“作" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "RDN 上ä¸å…许 LDAP æ“作" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "已存在(LDAP)" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "无法修改 LDAP 对象类" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "LDAP 结果过大" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "LDAP æ“作影å“多个 DSA" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "虚拟 LDAP 列表æµè§ˆé”™è¯¯" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "其他 LDAP 错误" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "LCUP 内存耗尽" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "LCUP 安全冲çª" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "LCUP æ•°æ®æ— æ•ˆ" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "LCUP ä¸æ”¯æŒçš„方案" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "LCUP 需è¦é‡æ–°åŠ è½½" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAP å·²å–消" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "没有è¦å–消的 LDAP æ“作" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "LDAP å·²ä¸èƒ½å–消" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "无法å–消 LDAP" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "LDAP 断言失败" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "LDAP æ‹’ç»ä»£ç†æŽˆæƒ" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "ç”¨æˆ·å®šä¹‰çš„é”™è¯¯ä»£ç  16" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "SQL æˆåŠŸ" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "SQL 错误" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "SQL 库存在内部逻辑错误" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "SQL 无访问æƒé™" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "SQL 请求中止" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "SQL æ•°æ®åº“文件已é”定" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "æ•°æ®åº“中的表被é”定" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "SQL 库耗尽核心资æº" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "å°è¯•å†™å…¥åªè¯» SQL æ•°æ®åº“" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "SQL æ“作被中断终止" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "SQL æ“作I/O错误" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "SQL æ•°æ®åº“ç£ç›˜æ˜ åƒæ ¼å¼é”™è¯¯" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "SQL 文件未知æ“作ç " + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "æ’入失败,因为 SQL æ•°æ®åº“已满" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "无法打开 SQL æ•°æ®åº“文件" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "SQL æ•°æ®åº“é”定å议错误" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "(内部 SQL 代ç ï¼šempty 空)" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "SQL æ•°æ®åº“架构已更改" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "SQL 字符串或blob超出大å°é™åˆ¶" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "SQL 约æŸå†²çªå¯¼è‡´ä¸­æ­¢" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "SQL æ•°æ®ç±»åž‹ä¸åŒ¹é…" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "SQL 库使用错误" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "SQL 库使用了ä¸æ”¯æŒçš„æ“作系统功能" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "SQL 授æƒæ‹’ç»" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "(未使用的SQL代ç ï¼šformat æ ¼å¼ï¼‰" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "SQL 绑定å‚数越界" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "打开的文件ä¸æ˜¯ SQL æ•°æ®åº“文件" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "æ¥è‡ª SQL 日志记录的通知" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "æ¥è‡ª SQL 日志记录的警告" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "SQL 已准备好å¦ä¸€è¡Œ" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "SQL 已执行完æˆ" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "系统错误,无错误å·" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "未知的系统错误" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "文件结尾" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "未知的错误代ç " + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "éžæœŸæœ›å‚æ•°" + +#: src/argparse.c:470 +msgid "read error" +msgstr "读å–错误" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "关键字太长" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "缺少å‚æ•°" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "无效å‚æ•°" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "无效命令" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "无效别å定义" + +#: src/argparse.c:482 src/argparse.c:519 +msgid "permission error" +msgstr "æƒé™é”™è¯¯" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "核心外" + +#: src/argparse.c:488 src/argparse.c:523 +msgid "invalid meta command" +msgstr "无效元命令" + +#: src/argparse.c:490 src/argparse.c:525 +msgid "unknown meta command" +msgstr "未知元命令" + +#: src/argparse.c:492 src/argparse.c:527 +msgid "unexpected meta command" +msgstr "æ„外元命令" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "无效的列表选项" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "选项\"%.50s\"缺少å‚æ•°\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "选项\"%.50s\"å‚数无效\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "选项\"%.50s\"å‚数多余\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "无效指令 \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "选项 \"%.50s\" ä¸æ˜Žç¡®\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "命令 \"%.50s\" ä¸æ˜Žç¡®\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "无效的选项 \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "注æ„:文件 '%s' 中无默认选项\n" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "从 '%s' 中读å–选项\n" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "选项文件 '%s': %s\n" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "注æ„: 由于整体é…置,选项 \"--%s\" 被忽视\n" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "è¯·å‘ æŠ¥å‘Šè½¯ä»¶é”™è¯¯ã€‚\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "警告:无法识别 %s\n" diff --git a/comm/third_party/libgpg-error/po/zh_TW.gmo b/comm/third_party/libgpg-error/po/zh_TW.gmo new file mode 100644 index 0000000000..cf73d800cb Binary files /dev/null and b/comm/third_party/libgpg-error/po/zh_TW.gmo differ diff --git a/comm/third_party/libgpg-error/po/zh_TW.po b/comm/third_party/libgpg-error/po/zh_TW.po new file mode 100644 index 0000000000..03ed21890c --- /dev/null +++ b/comm/third_party/libgpg-error/po/zh_TW.po @@ -0,0 +1,1997 @@ +# zh_TW.po - Chinese traditional translations for libgpg-error +# Copyright (C) 2014 Jedi Lin +# This file is distributed under the same license as the libngpg-error package. +# Chinese (traditional) , 2014. +# Jedi Lin , 2014. +# +# bobwxc , 2020. +msgid "" +msgstr "" +"Project-Id-Version: libgpg-error 1.39\n" +"Report-Msgid-Bugs-To: translations@gnupg.org\n" +"POT-Creation-Date: 2021-03-22 11:49+0100\n" +"PO-Revision-Date: 2021-03-22 10:45+0100\n" +"Last-Translator: bobwxc \n" +"Language-Team: None\n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-Basepath: libgpg-error-1.39\n" + +#: src/err-sources.h:28 +msgid "Unspecified source" +msgstr "未指定的來æº" + +#: src/err-sources.h:29 +msgid "gcrypt" +msgstr "gcrypt" + +#: src/err-sources.h:30 +msgid "GnuPG" +msgstr "GnuPG" + +#: src/err-sources.h:31 +msgid "GpgSM" +msgstr "GpgSM" + +#: src/err-sources.h:32 +msgid "GPG Agent" +msgstr "GPG 代ç†" + +#: src/err-sources.h:33 +msgid "Pinentry" +msgstr "個人識別碼項目" + +#: src/err-sources.h:34 +msgid "SCD" +msgstr "SCD" + +#: src/err-sources.h:35 +msgid "GPGME" +msgstr "GPGME" + +#: src/err-sources.h:36 +msgid "Keybox" +msgstr "Keybox" + +#: src/err-sources.h:37 +msgid "KSBA" +msgstr "KSBA" + +#: src/err-sources.h:38 +msgid "Dirmngr" +msgstr "Dirmngr" + +#: src/err-sources.h:39 +msgid "GSTI" +msgstr "GSTI" + +#: src/err-sources.h:40 +msgid "GPA" +msgstr "GPA" + +#: src/err-sources.h:41 +msgid "Kleopatra" +msgstr "Kleopatra" + +#: src/err-sources.h:42 +msgid "G13" +msgstr "G13" + +#: src/err-sources.h:43 +msgid "Assuan" +msgstr "Assuan" + +#: src/err-sources.h:44 +msgid "TPM2d" +msgstr "TPM2d" + +#: src/err-sources.h:45 +msgid "TLS" +msgstr "TLS" + +#: src/err-sources.h:46 +msgid "Any source" +msgstr "任何來æº" + +#: src/err-sources.h:47 +msgid "User defined source 1" +msgstr "ä½¿ç”¨è€…å®šç¾©ä¾†æº 1" + +#: src/err-sources.h:48 +msgid "User defined source 2" +msgstr "ä½¿ç”¨è€…å®šç¾©ä¾†æº 2" + +#: src/err-sources.h:49 +msgid "User defined source 3" +msgstr "ä½¿ç”¨è€…å®šç¾©ä¾†æº 3" + +#: src/err-sources.h:50 +msgid "User defined source 4" +msgstr "ä½¿ç”¨è€…å®šç¾©ä¾†æº 4" + +#: src/err-sources.h:51 +msgid "Unknown source" +msgstr "未知的來æº" + +#: src/err-codes.h:28 +msgid "Success" +msgstr "æˆåŠŸ" + +#: src/err-codes.h:29 +msgid "General error" +msgstr "一般錯誤" + +#: src/err-codes.h:30 +msgid "Unknown packet" +msgstr "未知的å°åŒ…" + +#: src/err-codes.h:31 +msgid "Unknown version in packet" +msgstr "å°åŒ…中的未知版本" + +#: src/err-codes.h:32 +msgid "Invalid public key algorithm" +msgstr "無效的公鑰演算法" + +#: src/err-codes.h:33 +msgid "Invalid digest algorithm" +msgstr "無效的摘è¦æ¼”算法" + +#: src/err-codes.h:34 +msgid "Bad public key" +msgstr "ä¸è‰¯çš„公鑰" + +#: src/err-codes.h:35 +msgid "Bad secret key" +msgstr "ä¸è‰¯çš„ç§é‘°" + +#: src/err-codes.h:36 +msgid "Bad signature" +msgstr "ä¸è‰¯çš„簽章" + +#: src/err-codes.h:37 +msgid "No public key" +msgstr "沒有公鑰" + +#: src/err-codes.h:38 +msgid "Checksum error" +msgstr "檢核碼錯誤" + +#: src/err-codes.h:39 +msgid "Bad passphrase" +msgstr "ä¸è‰¯çš„密語" + +#: src/err-codes.h:40 +msgid "Invalid cipher algorithm" +msgstr "無效的編密演算法" + +#: src/err-codes.h:41 +msgid "Cannot open keyring" +msgstr "金鑰éˆé–‹å•Ÿ" + +#: src/err-codes.h:42 +msgid "Invalid packet" +msgstr "無效的å°åŒ…" + +#: src/err-codes.h:43 +msgid "Invalid armor" +msgstr "無效的å°è£" + +#: src/err-codes.h:44 +msgid "No user ID" +msgstr "沒有使用者 ID" + +#: src/err-codes.h:45 +msgid "No secret key" +msgstr "沒有ç§é‘°" + +#: src/err-codes.h:46 +msgid "Wrong secret key used" +msgstr "使用錯誤的ç§é‘°" + +#: src/err-codes.h:47 +msgid "Bad session key" +msgstr "ä¸è‰¯çš„階段金鑰" + +#: src/err-codes.h:48 +msgid "Unknown compression algorithm" +msgstr "未知的壓縮演算法" + +#: src/err-codes.h:49 +msgid "Number is not prime" +msgstr "數值並éžè³ªæ•¸" + +#: src/err-codes.h:50 +msgid "Invalid encoding method" +msgstr "無效的編碼方法" + +#: src/err-codes.h:51 +msgid "Invalid encryption scheme" +msgstr "無效的加密框架" + +#: src/err-codes.h:52 +msgid "Invalid signature scheme" +msgstr "無效的簽署框架" + +#: src/err-codes.h:53 +msgid "Invalid attribute" +msgstr "無效的屬性" + +#: src/err-codes.h:54 +msgid "No value" +msgstr "沒有值" + +#: src/err-codes.h:55 +msgid "Not found" +msgstr "找ä¸åˆ°" + +#: src/err-codes.h:56 +msgid "Value not found" +msgstr "找ä¸åˆ°å€¼" + +#: src/err-codes.h:57 +msgid "Syntax error" +msgstr "語法錯誤" + +#: src/err-codes.h:58 +msgid "Bad MPI value" +msgstr "ä¸è‰¯çš„ MPI 值" + +#: src/err-codes.h:59 +msgid "Invalid passphrase" +msgstr "無效的密語" + +#: src/err-codes.h:60 +msgid "Invalid signature class" +msgstr "無效的簽章類別" + +#: src/err-codes.h:61 +msgid "Resources exhausted" +msgstr "資æºå·²è€—盡" + +#: src/err-codes.h:62 +msgid "Invalid keyring" +msgstr "無效的鑰匙圈" + +#: src/err-codes.h:63 +msgid "Trust DB error" +msgstr "信任資料庫錯誤" + +#: src/err-codes.h:64 +msgid "Bad certificate" +msgstr "ä¸è‰¯çš„憑證" + +#: src/err-codes.h:65 +msgid "Invalid user ID" +msgstr "無效的使用者 ID" + +#: src/err-codes.h:66 +msgid "Unexpected error" +msgstr "未é æœŸçš„錯誤" + +#: src/err-codes.h:67 +msgid "Time conflict" +msgstr "時間è¡çª" + +#: src/err-codes.h:68 +msgid "Keyserver error" +msgstr "金鑰伺æœå™¨éŒ¯èª¤" + +#: src/err-codes.h:69 +msgid "Wrong public key algorithm" +msgstr "錯誤的公鑰演算法" + +#: src/err-codes.h:70 +msgid "Tribute to D. A." +msgstr "å‘ Douglas Adams 致æ„" + +#: src/err-codes.h:71 +msgid "Weak encryption key" +msgstr "弱加密金鑰" + +#: src/err-codes.h:72 +msgid "Invalid key length" +msgstr "無效的金鑰長度" + +#: src/err-codes.h:73 +msgid "Invalid argument" +msgstr "無效的引數" + +#: src/err-codes.h:74 +msgid "Syntax error in URI" +msgstr "網å€ä¸­çš„語法錯誤" + +#: src/err-codes.h:75 +msgid "Invalid URI" +msgstr "無效的網å€" + +#: src/err-codes.h:76 +msgid "Network error" +msgstr "網路錯誤" + +#: src/err-codes.h:77 +msgid "Unknown host" +msgstr "未知的主機" + +#: src/err-codes.h:78 +msgid "Selftest failed" +msgstr "自我測試失敗" + +#: src/err-codes.h:79 +msgid "Data not encrypted" +msgstr "資料未經加密" + +#: src/err-codes.h:80 +msgid "Data not processed" +msgstr "資料未處ç†" + +#: src/err-codes.h:81 +msgid "Unusable public key" +msgstr "無法使用的公鑰" + +#: src/err-codes.h:82 +msgid "Unusable secret key" +msgstr "無法使用的ç§é‘°" + +#: src/err-codes.h:83 +msgid "Invalid value" +msgstr "無效的值" + +#: src/err-codes.h:84 +msgid "Bad certificate chain" +msgstr "ä¸è‰¯çš„憑證éˆ" + +#: src/err-codes.h:85 +msgid "Missing certificate" +msgstr "éºå¤±æ†‘è­‰" + +#: src/err-codes.h:86 +msgid "No data" +msgstr "沒有資料" + +#: src/err-codes.h:87 +msgid "Bug" +msgstr "ç‘•ç–µ" + +#: src/err-codes.h:88 +msgid "Not supported" +msgstr "未支æ´" + +#: src/err-codes.h:89 +msgid "Invalid operation code" +msgstr "無效的æ“作碼" + +#: src/err-codes.h:90 +msgid "Timeout" +msgstr "逾時" + +#: src/err-codes.h:91 +msgid "Internal error" +msgstr "內部錯誤" + +#: src/err-codes.h:92 +msgid "EOF (gcrypt)" +msgstr "EOF 文件çµå°¾ (gcrypt)" + +#: src/err-codes.h:93 +msgid "Invalid object" +msgstr "無效的物件" + +#: src/err-codes.h:94 +msgid "Provided object is too short" +msgstr "æ供的物件太短" + +#: src/err-codes.h:95 +msgid "Provided object is too large" +msgstr "æ供的物件太大" + +#: src/err-codes.h:96 +msgid "Missing item in object" +msgstr "物件中éºå¤±é …ç›®" + +#: src/err-codes.h:97 +msgid "Not implemented" +msgstr "未實作" + +#: src/err-codes.h:98 +msgid "Conflicting use" +msgstr "彼此è¡çªçš„用法" + +#: src/err-codes.h:99 +msgid "Invalid cipher mode" +msgstr "無效的密碼法模å¼" + +#: src/err-codes.h:100 +msgid "Invalid flag" +msgstr "無效的旗標" + +#: src/err-codes.h:101 +msgid "Invalid handle" +msgstr "無效的代號" + +#: src/err-codes.h:102 +msgid "Result truncated" +msgstr "çµæžœå·²æˆªå‰©éƒ¨åˆ†" + +#: src/err-codes.h:103 +msgid "Incomplete line" +msgstr "ä¸å®Œæ•´åˆ—" + +#: src/err-codes.h:104 +msgid "Invalid response" +msgstr "無效的回應" + +#: src/err-codes.h:105 +msgid "No agent running" +msgstr "沒有執行中的代ç†ç¨‹å¼" + +#: src/err-codes.h:106 +msgid "Agent error" +msgstr "代ç†ç¨‹å¼éŒ¯èª¤" + +#: src/err-codes.h:107 +msgid "Invalid data" +msgstr "無效的資料" + +#: src/err-codes.h:108 +msgid "Unspecific Assuan server fault" +msgstr "未指定的 Assuan 伺æœå™¨å‡ºéŒ¯" + +#: src/err-codes.h:109 +msgid "General Assuan error" +msgstr "一般性的 Assuan 錯誤" + +#: src/err-codes.h:110 +msgid "Invalid session key" +msgstr "無效的階段金鑰" + +#: src/err-codes.h:111 +msgid "Invalid S-expression" +msgstr "無效的 S-表示å¼" + +#: src/err-codes.h:112 +msgid "Unsupported algorithm" +msgstr "未支æ´çš„演算法" + +#: src/err-codes.h:113 +msgid "No pinentry" +msgstr "沒有個人識別碼項目" + +#: src/err-codes.h:114 +msgid "pinentry error" +msgstr "個人識別碼錯誤" + +#: src/err-codes.h:115 +msgid "Bad PIN" +msgstr "ä¸è‰¯çš„個人識別碼" + +#: src/err-codes.h:116 +msgid "Invalid name" +msgstr "無效的å稱" + +#: src/err-codes.h:117 +msgid "Bad data" +msgstr "無效的資料" + +#: src/err-codes.h:118 +msgid "Invalid parameter" +msgstr "無效的åƒæ•¸" + +#: src/err-codes.h:119 +msgid "Wrong card" +msgstr "錯誤的å¡ç‰‡" + +#: src/err-codes.h:120 +msgid "No dirmngr" +msgstr "沒有 dirmngr" + +#: src/err-codes.h:121 +msgid "dirmngr error" +msgstr "dirmngr 錯誤" + +#: src/err-codes.h:122 +msgid "Certificate revoked" +msgstr "憑證已撤銷" + +#: src/err-codes.h:123 +msgid "No CRL known" +msgstr "沒有已知的 CRL" + +#: src/err-codes.h:124 +msgid "CRL too old" +msgstr "CRL 太è€èˆŠ" + +#: src/err-codes.h:125 +msgid "Line too long" +msgstr "列太長" + +#: src/err-codes.h:126 +msgid "Not trusted" +msgstr "未信任" + +#: src/err-codes.h:127 +msgid "Operation cancelled" +msgstr "æ“作已å–消" + +#: src/err-codes.h:128 +msgid "Bad CA certificate" +msgstr "ä¸è‰¯çš„ CA 憑證" + +#: src/err-codes.h:129 +msgid "Certificate expired" +msgstr "憑證已逾期" + +#: src/err-codes.h:130 +msgid "Certificate too young" +msgstr "憑證太年輕" + +#: src/err-codes.h:131 +msgid "Unsupported certificate" +msgstr "未支æ´çš„憑證" + +#: src/err-codes.h:132 +msgid "Unknown S-expression" +msgstr "未知的 S-表示å¼" + +#: src/err-codes.h:133 +msgid "Unsupported protection" +msgstr "未支æ´çš„ä¿è­·" + +#: src/err-codes.h:134 +msgid "Corrupted protection" +msgstr "æ毀的ä¿è­·" + +#: src/err-codes.h:135 +msgid "Ambiguous name" +msgstr "模糊曖昧的å稱" + +#: src/err-codes.h:136 +msgid "Card error" +msgstr "å¡ç‰‡éŒ¯èª¤" + +#: src/err-codes.h:137 +msgid "Card reset required" +msgstr "å¡ç‰‡éœ€è¦é‡è¨­" + +#: src/err-codes.h:138 +msgid "Card removed" +msgstr "å¡ç‰‡å·²ç§»é™¤" + +#: src/err-codes.h:139 +msgid "Invalid card" +msgstr "無效的å¡ç‰‡" + +#: src/err-codes.h:140 +msgid "Card not present" +msgstr "å¡ç‰‡ä¸å­˜åœ¨" + +#: src/err-codes.h:141 +msgid "No PKCS15 application" +msgstr "沒有 PKCS15 應用程å¼" + +#: src/err-codes.h:142 +msgid "Not confirmed" +msgstr "未確èª" + +#: src/err-codes.h:143 +msgid "Configuration error" +msgstr "組態錯誤" + +#: src/err-codes.h:144 +msgid "No policy match" +msgstr "沒有相符的政策" + +#: src/err-codes.h:145 +msgid "Invalid index" +msgstr "無效的索引" + +#: src/err-codes.h:146 +msgid "Invalid ID" +msgstr "無效的 ID" + +#: src/err-codes.h:147 +msgid "No SmartCard daemon" +msgstr "沒有智慧å¡æœå‹™" + +#: src/err-codes.h:148 +msgid "SmartCard daemon error" +msgstr "智慧å¡æœå‹™éŒ¯èª¤" + +#: src/err-codes.h:149 +msgid "Unsupported protocol" +msgstr "未支æ´çš„å”定" + +#: src/err-codes.h:150 +msgid "Bad PIN method" +msgstr "ä¸è‰¯çš„個人識別碼方法" + +#: src/err-codes.h:151 +msgid "Card not initialized" +msgstr "å¡ç‰‡ç„¡æ³•åˆå§‹åŒ–" + +#: src/err-codes.h:152 +msgid "Unsupported operation" +msgstr "未支æ´çš„æ“作" + +#: src/err-codes.h:153 +msgid "Wrong key usage" +msgstr "錯誤的金鑰用法" + +#: src/err-codes.h:154 +msgid "Nothing found" +msgstr "找ä¸åˆ°ä»»ä½•æ±è¥¿" + +#: src/err-codes.h:155 +msgid "Wrong blob type" +msgstr "錯誤的二進ä½å¤§åž‹ç‰©ä»¶é¡žåž‹" + +#: src/err-codes.h:156 +msgid "Missing value" +msgstr "éºå¤±å€¼" + +#: src/err-codes.h:157 +msgid "Hardware problem" +msgstr "硬體å•é¡Œ" + +#: src/err-codes.h:158 +msgid "PIN blocked" +msgstr "個人識別碼已擋掉" + +#: src/err-codes.h:159 +msgid "Conditions of use not satisfied" +msgstr "使用æ¢ä»¶æœªæ»¿è¶³" + +#: src/err-codes.h:160 +msgid "PINs are not synced" +msgstr "個人識別碼未åŒæ­¥" + +#: src/err-codes.h:161 +msgid "Invalid CRL" +msgstr "無效的 CRL" + +#: src/err-codes.h:162 +msgid "BER error" +msgstr "BER 錯誤" + +#: src/err-codes.h:163 +msgid "Invalid BER" +msgstr "無效的 BER" + +#: src/err-codes.h:164 +msgid "Element not found" +msgstr "找ä¸åˆ°å…ƒç´ " + +#: src/err-codes.h:165 +msgid "Identifier not found" +msgstr "找ä¸åˆ°è­˜åˆ¥ç¬¦" + +#: src/err-codes.h:166 +msgid "Invalid tag" +msgstr "無效的標籤" + +#: src/err-codes.h:167 +msgid "Invalid length" +msgstr "無效的長度" + +#: src/err-codes.h:168 +msgid "Invalid key info" +msgstr "無效的金鑰資訊" + +#: src/err-codes.h:169 +msgid "Unexpected tag" +msgstr "未é æœŸçš„標籤" + +#: src/err-codes.h:170 +msgid "Not DER encoded" +msgstr "未經 DER 編碼" + +#: src/err-codes.h:171 +msgid "No CMS object" +msgstr "ä¸æ˜¯ CMS 物件" + +#: src/err-codes.h:172 +msgid "Invalid CMS object" +msgstr "無效的 CMS 物件" + +#: src/err-codes.h:173 +msgid "Unknown CMS object" +msgstr "未知的 CMS 物件" + +#: src/err-codes.h:174 +msgid "Unsupported CMS object" +msgstr "未支æ´çš„ CMS 物件" + +#: src/err-codes.h:175 +msgid "Unsupported encoding" +msgstr "未支æ´çš„編碼" + +#: src/err-codes.h:176 +msgid "Unsupported CMS version" +msgstr "未支æ´çš„ CMS 版本" + +#: src/err-codes.h:177 +msgid "Unknown algorithm" +msgstr "未知的演算法" + +#: src/err-codes.h:178 +msgid "Invalid crypto engine" +msgstr "無效的密碼法引擎" + +#: src/err-codes.h:179 +msgid "Public key not trusted" +msgstr "公鑰未信任" + +#: src/err-codes.h:180 +msgid "Decryption failed" +msgstr "解密失敗" + +#: src/err-codes.h:181 +msgid "Key expired" +msgstr "金鑰已逾期" + +#: src/err-codes.h:182 +msgid "Signature expired" +msgstr "簽章已逾期" + +#: src/err-codes.h:183 +msgid "Encoding problem" +msgstr "編碼å•é¡Œ" + +#: src/err-codes.h:184 +msgid "Invalid state" +msgstr "無效的狀態" + +#: src/err-codes.h:185 +msgid "Duplicated value" +msgstr "é‡è¤‡çš„值" + +#: src/err-codes.h:186 +msgid "Missing action" +msgstr "éºå¤±è¡Œå‹•" + +#: src/err-codes.h:187 +msgid "ASN.1 module not found" +msgstr "找ä¸åˆ° ASN.1 模組" + +#: src/err-codes.h:188 +msgid "Invalid OID string" +msgstr "無效的 OID 字串" + +#: src/err-codes.h:189 +msgid "Invalid time" +msgstr "無效的時間" + +#: src/err-codes.h:190 +msgid "Invalid CRL object" +msgstr "無效的 CRL 物件" + +#: src/err-codes.h:191 +msgid "Unsupported CRL version" +msgstr "未支æ´çš„ CRL 版本" + +#: src/err-codes.h:192 +msgid "Invalid certificate object" +msgstr "無效的憑證物件" + +#: src/err-codes.h:193 +msgid "Unknown name" +msgstr "無效的å稱" + +#: src/err-codes.h:194 +msgid "A locale function failed" +msgstr "本地化函數功能失敗" + +#: src/err-codes.h:195 +msgid "Not locked" +msgstr "未鎖定" + +#: src/err-codes.h:196 +msgid "Protocol violation" +msgstr "未ä¾å”定進行" + +#: src/err-codes.h:197 +msgid "Invalid MAC" +msgstr "無效的 MAC" + +#: src/err-codes.h:198 +msgid "Invalid request" +msgstr "無效的請求" + +#: src/err-codes.h:199 +msgid "Unknown extension" +msgstr "未知的擴充" + +#: src/err-codes.h:200 +msgid "Unknown critical extension" +msgstr "未知的關éµæ“´å……" + +#: src/err-codes.h:201 +msgid "Locked" +msgstr "已鎖定" + +#: src/err-codes.h:202 +msgid "Unknown option" +msgstr "未知的é¸é …" + +#: src/err-codes.h:203 +msgid "Unknown command" +msgstr "未知的指令" + +#: src/err-codes.h:204 +msgid "Not operational" +msgstr "無法æ“作" + +#: src/err-codes.h:205 +msgid "No passphrase given" +msgstr "沒有給定密語" + +#: src/err-codes.h:206 +msgid "No PIN given" +msgstr "沒有給定個人識別碼" + +#: src/err-codes.h:207 +msgid "Not enabled" +msgstr "未啟用" + +#: src/err-codes.h:208 +msgid "No crypto engine" +msgstr "沒有密碼法引擎" + +#: src/err-codes.h:209 +msgid "Missing key" +msgstr "éºå¤±é‡‘é‘°" + +#: src/err-codes.h:210 +msgid "Too many objects" +msgstr "太多物件" + +#: src/err-codes.h:211 +msgid "Limit reached" +msgstr "å·²é”極é™" + +#: src/err-codes.h:212 +msgid "Not initialized" +msgstr "尚未åˆå§‹åŒ–" + +#: src/err-codes.h:213 +msgid "Missing issuer certificate" +msgstr "éºå¤±ç™¼è¡Œè€…憑證" + +#: src/err-codes.h:214 +msgid "No keyserver available" +msgstr "沒有å¯ç”¨çš„金鑰伺æœå™¨" + +#: src/err-codes.h:215 +msgid "Invalid elliptic curve" +msgstr "無效的橢圓曲線" + +#: src/err-codes.h:216 +msgid "Unknown elliptic curve" +msgstr "未知的橢圓曲線" + +#: src/err-codes.h:217 +msgid "Duplicated key" +msgstr "é‡è¤‡çš„金鑰" + +#: src/err-codes.h:218 +msgid "Ambiguous result" +msgstr "模糊曖昧的çµæžœ" + +#: src/err-codes.h:219 +msgid "No crypto context" +msgstr "沒有密碼法脈絡" + +#: src/err-codes.h:220 +msgid "Wrong crypto context" +msgstr "錯誤的密碼法脈絡" + +#: src/err-codes.h:221 +msgid "Bad crypto context" +msgstr "ä¸è‰¯çš„密碼法脈絡" + +#: src/err-codes.h:222 +msgid "Conflict in the crypto context" +msgstr "密碼法脈絡è¡çª" + +#: src/err-codes.h:223 +msgid "Broken public key" +msgstr "æ毀的公鑰" + +#: src/err-codes.h:224 +msgid "Broken secret key" +msgstr "æ毀的ç§é‘°" + +#: src/err-codes.h:225 +msgid "Invalid MAC algorithm" +msgstr "無效的 MAC 演算法" + +#: src/err-codes.h:226 +msgid "Operation fully cancelled" +msgstr "æ“作已完全å–消" + +#: src/err-codes.h:227 +msgid "Operation not yet finished" +msgstr "æ“作尚未完æˆ" + +#: src/err-codes.h:228 +msgid "Buffer too short" +msgstr "ç·©è¡å€å¤ªçŸ­" + +#: src/err-codes.h:229 +msgid "Invalid length specifier in S-expression" +msgstr "S-表示å¼ä¸­çš„無效長度指定符" + +#: src/err-codes.h:230 +msgid "String too long in S-expression" +msgstr "S-表示å¼ä¸­çš„字串太長" + +#: src/err-codes.h:231 +msgid "Unmatched parentheses in S-expression" +msgstr "S-表示å¼ä¸­çš„括號未æˆå°" + +#: src/err-codes.h:232 +msgid "S-expression not canonical" +msgstr "S-表示å¼ä¸¦éžæ¨™æº–åž‹" + +#: src/err-codes.h:233 +msgid "Bad character in S-expression" +msgstr "S-表示å¼ä¸­æœ‰ä¸è‰¯çš„字符" + +#: src/err-codes.h:234 +msgid "Bad quotation in S-expression" +msgstr "S-表示å¼ä¸­æœ‰ä¸è‰¯çš„引號" + +#: src/err-codes.h:235 +msgid "Zero prefix in S-expression" +msgstr "S-表示å¼ä¸­é›¶å‰ç¶´" + +#: src/err-codes.h:236 +msgid "Nested display hints in S-expression" +msgstr "S-表示å¼ä¸­å·¢ç‹€ä½¿ç”¨é¡¯ç¤ºæ示符號" + +#: src/err-codes.h:237 +msgid "Unmatched display hints" +msgstr "未æˆå°çš„顯示æ示符號" + +#: src/err-codes.h:238 +msgid "Unexpected reserved punctuation in S-expression" +msgstr "S-表示å¼ä¸­æœ‰æœªé æœŸçš„ä¿ç•™ç¬¦è™Ÿ" + +#: src/err-codes.h:239 +msgid "Bad hexadecimal character in S-expression" +msgstr "S-表示å¼ä¸­æœ‰ä¸è‰¯çš„å六進制字符" + +#: src/err-codes.h:240 +msgid "Odd hexadecimal numbers in S-expression" +msgstr "S-表示å¼ä¸­æœ‰å¥‡æ€ªçš„å六進制數字" + +#: src/err-codes.h:241 +msgid "Bad octal character in S-expression" +msgstr "S-表示å¼ä¸­æœ‰ä¸è‰¯çš„八進制字符" + +#: src/err-codes.h:242 +msgid "All subkeys are expired or revoked" +msgstr "所有å­é‡‘鑰都已éŽæœŸæˆ–åŠéŠ·" + +#: src/err-codes.h:243 +msgid "Database is corrupted" +msgstr "資料庫已æ壞" + +#: src/err-codes.h:244 +msgid "Server indicated a failure" +msgstr "伺æœå™¨æ•…éšœ" + +#: src/err-codes.h:245 +msgid "No name" +msgstr "ç„¡å稱" + +#: src/err-codes.h:246 +msgid "No key" +msgstr "沒有金鑰" + +#: src/err-codes.h:247 +msgid "Legacy key" +msgstr "éºç•™çš„金鑰" + +#: src/err-codes.h:248 +msgid "Request too short" +msgstr "請求éŽçŸ­" + +#: src/err-codes.h:249 +msgid "Request too long" +msgstr "請求éŽé•·" + +#: src/err-codes.h:250 +msgid "Object is in termination state" +msgstr "å°è±¡è™•æ–¼çµ‚止狀態" + +#: src/err-codes.h:251 +msgid "No certificate chain" +msgstr "沒有憑證éˆ" + +#: src/err-codes.h:252 +msgid "Certificate is too large" +msgstr "憑證太大" + +#: src/err-codes.h:253 +msgid "Invalid record" +msgstr "無效的紀錄" + +#: src/err-codes.h:254 +msgid "The MAC does not verify" +msgstr "MAC 未驗證" + +#: src/err-codes.h:255 +msgid "Unexpected message" +msgstr "未é æœŸçš„訊æ¯" + +#: src/err-codes.h:256 +msgid "Compression or decompression failed" +msgstr "壓縮或解壓縮失敗" + +#: src/err-codes.h:257 +msgid "A counter would wrap" +msgstr "計數程å¼æœƒç–ŠåŠ " + +#: src/err-codes.h:258 +msgid "Fatal alert message received" +msgstr "已收到嚴é‡è­¦å‘Šè¨Šæ¯" + +#: src/err-codes.h:259 +msgid "No cipher algorithm" +msgstr "沒有密碼演算法" + +#: src/err-codes.h:260 +msgid "Missing client certificate" +msgstr "éºå¤±ç”¨æˆ¶ç«¯æ†‘è­‰" + +#: src/err-codes.h:261 +msgid "Close notification received" +msgstr "已收到關閉通知" + +#: src/err-codes.h:262 +msgid "Ticket expired" +msgstr "進入權已逾期" + +#: src/err-codes.h:263 +msgid "Bad ticket" +msgstr "ä¸è‰¯çš„進入權" + +#: src/err-codes.h:264 +msgid "Unknown identity" +msgstr "未知的身分" + +#: src/err-codes.h:265 +msgid "Bad certificate message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯æ†‘證訊æ¯" + +#: src/err-codes.h:266 +msgid "Bad certificate request message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯æ†‘證請求訊æ¯" + +#: src/err-codes.h:267 +msgid "Bad certificate verify message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯æ†‘證驗證訊æ¯" + +#: src/err-codes.h:268 +msgid "Bad change cipher message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯è®Šæ›´å¯†ç¢¼æ³•è¨Šæ¯" + +#: src/err-codes.h:269 +msgid "Bad client hello message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯ç”¨æˆ¶ç«¯å•å€™è¨Šæ¯" + +#: src/err-codes.h:270 +msgid "Bad server hello message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯ä¼ºæœå™¨å•å€™è¨Šæ¯" + +#: src/err-codes.h:271 +msgid "Bad server hello done message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯ä¼ºæœå™¨å•å€™å®Œæˆè¨Šæ¯" + +#: src/err-codes.h:272 +msgid "Bad finished message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯å·²å®Œæˆè¨Šæ¯" + +#: src/err-codes.h:273 +msgid "Bad server key exchange message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯ä¼ºæœå™¨é‡‘鑰交æ›è¨Šæ¯" + +#: src/err-codes.h:274 +msgid "Bad client key exchange message in handshake" +msgstr "交æ¡ä¸­çš„ä¸è‰¯ç”¨æˆ¶ç«¯é‡‘鑰交æ›è¨Šæ¯" + +#: src/err-codes.h:275 +msgid "Bogus string" +msgstr "å‡é€ çš„字串" + +#: src/err-codes.h:276 +msgid "Forbidden" +msgstr "ç¦æ­¢" + +#: src/err-codes.h:277 +msgid "Key disabled" +msgstr "金鑰已åœç”¨" + +#: src/err-codes.h:278 +msgid "Not possible with a card based key" +msgstr "ä¸å¯èƒ½ä»¥å¡ç‰‡å¼é‡‘鑰進行" + +#: src/err-codes.h:279 +msgid "Invalid lock object" +msgstr "無效的鎖定物件" + +#: src/err-codes.h:280 +msgid "True" +msgstr "正確" + +#: src/err-codes.h:281 +msgid "False" +msgstr "錯誤" + +#: src/err-codes.h:282 +msgid "General IPC error" +msgstr "一般性的 IPC 錯誤" + +#: src/err-codes.h:283 +msgid "IPC accept call failed" +msgstr "IPC 接å—å«ç”¨å¤±æ•—" + +#: src/err-codes.h:284 +msgid "IPC connect call failed" +msgstr "IPC 連線å«ç”¨å¤±æ•—" + +#: src/err-codes.h:285 +msgid "Invalid IPC response" +msgstr "無效的 IPC 回應" + +#: src/err-codes.h:286 +msgid "Invalid value passed to IPC" +msgstr "éžé€è‡³ IPC 的值無效" + +#: src/err-codes.h:287 +msgid "Incomplete line passed to IPC" +msgstr "éžé€è‡³ IPC 的列ä¸å®Œæ•´" + +#: src/err-codes.h:288 +msgid "Line passed to IPC too long" +msgstr "éžé€è‡³ IPC 的列太長" + +#: src/err-codes.h:289 +msgid "Nested IPC commands" +msgstr "巢狀 IPC 指令" + +#: src/err-codes.h:290 +msgid "No data callback in IPC" +msgstr "IPC 中沒有資料回呼" + +#: src/err-codes.h:291 +msgid "No inquire callback in IPC" +msgstr "IPC 中沒有查詢回呼" + +#: src/err-codes.h:292 +msgid "Not an IPC server" +msgstr "ä¸æ˜¯ IPC 伺æœå™¨" + +#: src/err-codes.h:293 +msgid "Not an IPC client" +msgstr "ä¸æ˜¯ IPC 用戶端" + +#: src/err-codes.h:294 +msgid "Problem starting IPC server" +msgstr "å•Ÿå‹• IPC 伺æœå™¨æ™‚發生å•é¡Œ" + +#: src/err-codes.h:295 +msgid "IPC read error" +msgstr "IPC 讀å–錯誤" + +#: src/err-codes.h:296 +msgid "IPC write error" +msgstr "IPC 寫入錯誤" + +#: src/err-codes.h:297 +msgid "Too much data for IPC layer" +msgstr "IPC 層有太多資料" + +#: src/err-codes.h:298 +msgid "Unexpected IPC command" +msgstr "未é æœŸçš„ IPC 指令" + +#: src/err-codes.h:299 +msgid "Unknown IPC command" +msgstr "未知的 IPC 指令" + +#: src/err-codes.h:300 +msgid "IPC syntax error" +msgstr "IPC 語法錯誤" + +#: src/err-codes.h:301 +msgid "IPC call has been cancelled" +msgstr "IPC å«ç”¨å·²å–消" + +#: src/err-codes.h:302 +msgid "No input source for IPC" +msgstr "沒有 IPC 的輸入來æº" + +#: src/err-codes.h:303 +msgid "No output source for IPC" +msgstr "沒有 IPC 的輸出來æº" + +#: src/err-codes.h:304 +msgid "IPC parameter error" +msgstr "IPC åƒæ•¸éŒ¯èª¤" + +#: src/err-codes.h:305 +msgid "Unknown IPC inquire" +msgstr "未知的 IPC 查詢" + +#: src/err-codes.h:306 +msgid "Crypto engine too old" +msgstr "加密引擎太舊" + +#: src/err-codes.h:307 +msgid "Screen or window too small" +msgstr "螢幕或窗å£éŽå°" + +#: src/err-codes.h:308 +msgid "Screen or window too large" +msgstr "螢幕或窗å£éŽå¤§" + +#: src/err-codes.h:309 +msgid "Required environment variable not set" +msgstr "需è¦çš„環境變數未設定" + +#: src/err-codes.h:310 +msgid "User ID already exists" +msgstr "用戶 ID 已存在" + +#: src/err-codes.h:311 +msgid "Name already exists" +msgstr "å字已存在" + +#: src/err-codes.h:312 +msgid "Duplicated name" +msgstr "é‡è¤‡çš„å稱" + +#: src/err-codes.h:313 +msgid "Object is too young" +msgstr "å°è±¡å¤ªæ–°" + +#: src/err-codes.h:314 +msgid "Object is too old" +msgstr "å°è±¡å¤ªèˆŠ" + +#: src/err-codes.h:315 +msgid "Unknown flag" +msgstr "未知標誌" + +#: src/err-codes.h:316 +msgid "Invalid execution order" +msgstr "無效的執行順åº" + +#: src/err-codes.h:317 +msgid "Already fetched" +msgstr "已經ç²å¾—" + +#: src/err-codes.h:318 +msgid "Try again later" +msgstr "ç¨å¾Œå†è©¦" + +#: src/err-codes.h:319 +msgid "Wrong name" +msgstr "錯誤å稱" + +#: src/err-codes.h:320 +msgid "Not authenticated" +msgstr "未驗證" + +#: src/err-codes.h:321 +msgid "Bad authentication" +msgstr "無效驗證" + +#: src/err-codes.h:322 +msgid "No Keybox daemon running" +msgstr "ç„¡é‹è¡Œçš„ Keybox 守護進程" + +#: src/err-codes.h:323 +msgid "Keybox daemon error" +msgstr "Keybox 守護進程錯誤" + +#: src/err-codes.h:324 +msgid "Service is not running" +msgstr "æœå‹™æœªé‹è¡Œ" + +#: src/err-codes.h:325 +msgid "Service error" +msgstr "æœå‹™éŒ¯èª¤" + +#: src/err-codes.h:326 +msgid "System bug detected" +msgstr "系統錯誤" + +#: src/err-codes.h:327 +msgid "Unknown DNS error" +msgstr "未知的 DNS 錯誤" + +#: src/err-codes.h:328 +msgid "Invalid DNS section" +msgstr "無效的 DNS 部分" + +#: src/err-codes.h:329 +msgid "Invalid textual address form" +msgstr "無效的文本地å€å½¢å¼" + +#: src/err-codes.h:330 +msgid "Missing DNS query packet" +msgstr "缺少 DNS 查詢å°åŒ…" + +#: src/err-codes.h:331 +msgid "Missing DNS answer packet" +msgstr "ç„¡ DNS 迴應å°åŒ…" + +#: src/err-codes.h:332 +msgid "Connection closed in DNS" +msgstr "DNS 連接關閉" + +#: src/err-codes.h:333 +msgid "Verification failed in DNS" +msgstr "DNS 驗證失敗" + +#: src/err-codes.h:334 +msgid "DNS Timeout" +msgstr "DNS 逾時" + +#: src/err-codes.h:335 +msgid "General LDAP error" +msgstr "一般 LDAP 錯誤" + +#: src/err-codes.h:336 +msgid "General LDAP attribute error" +msgstr "一般 LDAP 屬性錯誤" + +#: src/err-codes.h:337 +msgid "General LDAP name error" +msgstr "一般 LDAP å稱錯誤" + +#: src/err-codes.h:338 +msgid "General LDAP security error" +msgstr "一般 LDAP 安全錯誤" + +#: src/err-codes.h:339 +msgid "General LDAP service error" +msgstr "一般 LDAP æœå‹™éŒ¯èª¤" + +#: src/err-codes.h:340 +msgid "General LDAP update error" +msgstr "一般 LDAP å‡ç´šéŒ¯èª¤" + +#: src/err-codes.h:341 +msgid "Experimental LDAP error code" +msgstr "試驗性 LDAP 錯誤代碼" + +#: src/err-codes.h:342 +msgid "Private LDAP error code" +msgstr "專用 LDAP 錯誤代碼" + +#: src/err-codes.h:343 +msgid "Other general LDAP error" +msgstr "其他一般 LDAP 錯誤" + +#: src/err-codes.h:344 +msgid "LDAP connecting failed (X)" +msgstr "LDAP 連接失敗(X)" + +#: src/err-codes.h:345 +msgid "LDAP referral limit exceeded" +msgstr "è¶…éŽ LDAP 引用é™åˆ¶" + +#: src/err-codes.h:346 +msgid "LDAP client loop" +msgstr "LDAP 客戶端循環" + +#: src/err-codes.h:347 +msgid "No LDAP results returned" +msgstr "ç„¡ LDAP çµæžœè¿”回" + +#: src/err-codes.h:348 +msgid "LDAP control not found" +msgstr "未找到 LDAP 元件" + +#: src/err-codes.h:349 +msgid "Not supported by LDAP" +msgstr "ä¸å— LDAP 支æ´" + +#: src/err-codes.h:350 +msgid "LDAP connect error" +msgstr "LDAP 連接錯誤" + +#: src/err-codes.h:351 +msgid "Out of memory in LDAP" +msgstr "LDAP 記憶體耗盡" + +#: src/err-codes.h:352 +msgid "Bad parameter to an LDAP routine" +msgstr "LDAP 事務åƒæ•¸éŒ¯èª¤" + +#: src/err-codes.h:353 +msgid "User cancelled LDAP operation" +msgstr "用戶å–消 LDAP æ“作" + +#: src/err-codes.h:354 +msgid "Bad LDAP search filter" +msgstr "ä¸è‰¯çš„憑證" + +#: src/err-codes.h:355 +msgid "Unknown LDAP authentication method" +msgstr "未知的 LDAP 身份驗證方法" + +#: src/err-codes.h:356 +msgid "Timeout in LDAP" +msgstr "LDAP 逾時" + +#: src/err-codes.h:357 +msgid "LDAP decoding error" +msgstr "dirmngr 解碼錯誤" + +#: src/err-codes.h:358 +msgid "LDAP encoding error" +msgstr "dirmngr 編碼錯誤" + +#: src/err-codes.h:359 +msgid "LDAP local error" +msgstr "LDAP 本地錯誤" + +#: src/err-codes.h:360 +msgid "Cannot contact LDAP server" +msgstr "無法è¯çµ¡ LDAP 伺æœå™¨" + +#: src/err-codes.h:361 +msgid "LDAP success" +msgstr "LDAP æˆåŠŸ" + +#: src/err-codes.h:362 +msgid "LDAP operations error" +msgstr "LDAP æ“作錯誤" + +#: src/err-codes.h:363 +msgid "LDAP protocol error" +msgstr "LDAP å”定錯誤" + +#: src/err-codes.h:364 +msgid "Time limit exceeded in LDAP" +msgstr "LDAP 逾時" + +#: src/err-codes.h:365 +msgid "Size limit exceeded in LDAP" +msgstr "LDAP 大å°è¶…é™" + +#: src/err-codes.h:366 +msgid "LDAP compare false" +msgstr "LDAP 比較錯誤" + +#: src/err-codes.h:367 +msgid "LDAP compare true" +msgstr "LDAP 比較正確" + +#: src/err-codes.h:368 +msgid "LDAP authentication method not supported" +msgstr "未支æ´çš„ LDAP 身份驗證方法" + +#: src/err-codes.h:369 +msgid "Strong(er) LDAP authentication required" +msgstr "LDAP 需è¦å¢žå¼·åž‹èº«ä»½é©—è­‰" + +#: src/err-codes.h:370 +msgid "Partial LDAP results+referral received" +msgstr "收到部分 LDAP çµæžœèˆ‡å¼•ç”¨" + +#: src/err-codes.h:371 +msgid "LDAP referral" +msgstr "LDAP 轉é€" + +#: src/err-codes.h:372 +msgid "Administrative LDAP limit exceeded" +msgstr "è¶…éŽ LDAP 管ç†é™åˆ¶" + +#: src/err-codes.h:373 +msgid "Critical LDAP extension is unavailable" +msgstr "é—œéµ LDAP 擴展ä¸å¯ç”¨" + +#: src/err-codes.h:374 +msgid "Confidentiality required by LDAP" +msgstr "LDAP è¦æ±‚ä¿å¯†" + +#: src/err-codes.h:375 +msgid "LDAP SASL bind in progress" +msgstr "正在進行 LDAP SASL ç¶å®š" + +#: src/err-codes.h:376 +msgid "No such LDAP attribute" +msgstr "沒有此 LDAP 屬性" + +#: src/err-codes.h:377 +msgid "Undefined LDAP attribute type" +msgstr "未定義的 LDAP 屬性類型" + +#: src/err-codes.h:378 +msgid "Inappropriate matching in LDAP" +msgstr "LDAP ä¸ç•¶åŒ¹é…" + +#: src/err-codes.h:379 +msgid "Constraint violation in LDAP" +msgstr "LDAP ç´„æŸæ²–çª" + +#: src/err-codes.h:380 +msgid "LDAP type or value exists" +msgstr "LDAP 類型或值存在" + +#: src/err-codes.h:381 +msgid "Invalid syntax in LDAP" +msgstr "LDAP 語法無效" + +#: src/err-codes.h:382 +msgid "No such LDAP object" +msgstr "ç„¡æ­¤ LDAP å°è±¡" + +#: src/err-codes.h:383 +msgid "LDAP alias problem" +msgstr "LDAP 別åå•é¡Œ" + +#: src/err-codes.h:384 +msgid "Invalid DN syntax in LDAP" +msgstr "LDAP 無效的 DN 語法" + +#: src/err-codes.h:385 +msgid "LDAP entry is a leaf" +msgstr "LDAP 葉狀入å£" + +#: src/err-codes.h:386 +msgid "LDAP alias dereferencing problem" +msgstr "LDAP 別å引用å–消å•é¡Œ" + +#: src/err-codes.h:387 +msgid "LDAP proxy authorization failure (X)" +msgstr "LDAP 代ç†æŽˆæ¬Šå¤±æ•—(X)" + +#: src/err-codes.h:388 +msgid "Inappropriate LDAP authentication" +msgstr "ä¸ç•¶ LDAP 身份驗證" + +#: src/err-codes.h:389 +msgid "Invalid LDAP credentials" +msgstr "無效 LDAP 憑據" + +#: src/err-codes.h:390 +msgid "Insufficient access for LDAP" +msgstr "ç„¡ LDAP 訪å•æ¬Šé™" + +#: src/err-codes.h:391 +msgid "LDAP server is busy" +msgstr "LDAP 伺æœå™¨å¿™" + +#: src/err-codes.h:392 +msgid "LDAP server is unavailable" +msgstr "LDAP 伺æœå™¨ä¸å¯ç”¨" + +#: src/err-codes.h:393 +msgid "LDAP server is unwilling to perform" +msgstr "LDAP 伺æœå™¨æ‹’絕處ç†" + +#: src/err-codes.h:394 +msgid "Loop detected by LDAP" +msgstr "LDAP 檢測到循環" + +#: src/err-codes.h:395 +msgid "LDAP naming violation" +msgstr "LDAP 命åæ²–çª" + +#: src/err-codes.h:396 +msgid "LDAP object class violation" +msgstr "LDAP å°è±¡é¡žæ²–çª" + +#: src/err-codes.h:397 +msgid "LDAP operation not allowed on non-leaf" +msgstr "ä¸å…許在éžè‘‰ä¸ŠåŸ·è¡Œ LDAP æ“作" + +#: src/err-codes.h:398 +msgid "LDAP operation not allowed on RDN" +msgstr "RDN 上ä¸å…許 LDAP æ“作" + +#: src/err-codes.h:399 +msgid "Already exists (LDAP)" +msgstr "LDAP 已經存在" + +#: src/err-codes.h:400 +msgid "Cannot modify LDAP object class" +msgstr "無法修改 LDAP å°è±¡é¡ž" + +#: src/err-codes.h:401 +msgid "LDAP results too large" +msgstr "LDAP çµæžœéŽå¤§" + +#: src/err-codes.h:402 +msgid "LDAP operation affects multiple DSAs" +msgstr "LDAP æ“作影響多個 DSA" + +#: src/err-codes.h:403 +msgid "Virtual LDAP list view error" +msgstr "虛擬 LDAP 列表視圖錯誤" + +#: src/err-codes.h:404 +msgid "Other LDAP error" +msgstr "其他 LDAP 錯誤" + +#: src/err-codes.h:405 +msgid "Resources exhausted in LCUP" +msgstr "LCUP 資æºè€—盡" + +#: src/err-codes.h:406 +msgid "Security violation in LCUP" +msgstr "LCUP 安全沖çª" + +#: src/err-codes.h:407 +msgid "Invalid data in LCUP" +msgstr "LCUP 數據無效" + +#: src/err-codes.h:408 +msgid "Unsupported scheme in LCUP" +msgstr "LCUP 未支æ´çš„方案" + +#: src/err-codes.h:409 +msgid "Reload required in LCUP" +msgstr "LCUP 需è¦é‡æ–°åŠ è¼‰" + +#: src/err-codes.h:410 +msgid "LDAP cancelled" +msgstr "LDAP å·²å–消" + +#: src/err-codes.h:411 +msgid "No LDAP operation to cancel" +msgstr "沒有è¦å–消的 LDAP æ“作" + +#: src/err-codes.h:412 +msgid "Too late to cancel LDAP" +msgstr "LDAP å·²ä¸èƒ½å–消" + +#: src/err-codes.h:413 +msgid "Cannot cancel LDAP" +msgstr "無法å–消 LDAP" + +#: src/err-codes.h:414 +msgid "LDAP assertion failed" +msgstr "LDAP 斷言失敗" + +#: src/err-codes.h:415 +msgid "Proxied authorization denied by LDAP" +msgstr "LDAP ç¦æ­¢ä»£ç†é©—è­‰" + +#: src/err-codes.h:416 +msgid "User defined error code 1" +msgstr "使用者定義錯誤代碼 1" + +#: src/err-codes.h:417 +msgid "User defined error code 2" +msgstr "使用者定義錯誤代碼 2" + +#: src/err-codes.h:418 +msgid "User defined error code 3" +msgstr "使用者定義錯誤代碼 3" + +#: src/err-codes.h:419 +msgid "User defined error code 4" +msgstr "使用者定義錯誤代碼 4" + +#: src/err-codes.h:420 +msgid "User defined error code 5" +msgstr "使用者定義錯誤代碼 5" + +#: src/err-codes.h:421 +msgid "User defined error code 6" +msgstr "使用者定義錯誤代碼 6" + +#: src/err-codes.h:422 +msgid "User defined error code 7" +msgstr "使用者定義錯誤代碼 7" + +#: src/err-codes.h:423 +msgid "User defined error code 8" +msgstr "使用者定義錯誤代碼 8" + +#: src/err-codes.h:424 +msgid "User defined error code 9" +msgstr "使用者定義錯誤代碼 9" + +#: src/err-codes.h:425 +msgid "User defined error code 10" +msgstr "使用者定義錯誤代碼 10" + +#: src/err-codes.h:426 +msgid "User defined error code 11" +msgstr "使用者定義錯誤代碼 11" + +#: src/err-codes.h:427 +msgid "User defined error code 12" +msgstr "使用者定義錯誤代碼 12" + +#: src/err-codes.h:428 +msgid "User defined error code 13" +msgstr "使用者定義錯誤代碼 13" + +#: src/err-codes.h:429 +msgid "User defined error code 14" +msgstr "使用者定義錯誤代碼 14" + +#: src/err-codes.h:430 +msgid "User defined error code 15" +msgstr "使用者定義錯誤代碼 15" + +#: src/err-codes.h:431 +msgid "User defined error code 16" +msgstr "使用者定義錯誤代碼 16" + +#: src/err-codes.h:432 +msgid "SQL success" +msgstr "SQL æˆåŠŸ" + +#: src/err-codes.h:433 +msgid "SQL error" +msgstr "SQL 錯誤" + +#: src/err-codes.h:434 +msgid "Internal logic error in SQL library" +msgstr "SQL 庫內部é‚輯錯誤" + +#: src/err-codes.h:435 +msgid "Access permission denied (SQL)" +msgstr "SQL 無訪å•æ¬Šé™" + +#: src/err-codes.h:436 +msgid "SQL abort was requested" +msgstr "SQL 請求中止" + +#: src/err-codes.h:437 +msgid "SQL database file is locked" +msgstr "SQL 資料庫文件被鎖定" + +#: src/err-codes.h:438 +msgid "An SQL table in the database is locked" +msgstr "資料庫中 SLQ 表被鎖定" + +#: src/err-codes.h:439 +msgid "SQL library ran out of core" +msgstr "SQL 庫耗盡核心資æº" + +#: src/err-codes.h:440 +msgid "Attempt to write a readonly SQL database" +msgstr "嘗試寫入唯讀 SQL 資料庫" + +#: src/err-codes.h:441 +msgid "SQL operation terminated by interrupt" +msgstr "SQL æ“作被中斷終止" + +#: src/err-codes.h:442 +msgid "I/O error during SQL operation" +msgstr "SQL æ“作 I/O 錯誤" + +#: src/err-codes.h:443 +msgid "SQL database disk image is malformed" +msgstr "SQL 資料庫ç£ç¢Ÿé¡åƒæ ¼å¼éŒ¯èª¤" + +#: src/err-codes.h:444 +msgid "Unknown opcode in SQL file control" +msgstr "SQL 文件未知æ“作碼" + +#: src/err-codes.h:445 +msgid "Insertion failed because SQL database is full" +msgstr "æ’入失敗,因為 SQL 資料庫已滿" + +#: src/err-codes.h:446 +msgid "Unable to open the SQL database file" +msgstr "無法打開 SQL 資料庫文件" + +#: src/err-codes.h:447 +msgid "SQL database lock protocol error" +msgstr "SQL 資料庫鎖定å”定錯誤" + +#: src/err-codes.h:448 +msgid "(internal SQL code: empty)" +msgstr "(內部 SQL 代碼:empty 空)" + +#: src/err-codes.h:449 +msgid "SQL database schema changed" +msgstr "SQL 資料庫架構已更改" + +#: src/err-codes.h:450 +msgid "String or blob exceeds size limit (SQL)" +msgstr "SQL 字串或blob超出大å°é™åˆ¶" + +#: src/err-codes.h:451 +msgid "SQL abort due to constraint violation" +msgstr "SQL ç´„æŸæ²–çªå°Žè‡´ä¸­æ­¢" + +#: src/err-codes.h:452 +msgid "Data type mismatch (SQL)" +msgstr "SQL 數據類型ä¸åŒ¹é…" + +#: src/err-codes.h:453 +msgid "SQL library used incorrectly" +msgstr "SQL 庫使用錯誤" + +#: src/err-codes.h:454 +msgid "SQL library uses unsupported OS features" +msgstr "SQL 庫使用了未支æ´çš„æ“作系統功能" + +#: src/err-codes.h:455 +msgid "Authorization denied (SQL)" +msgstr "SQL 授權拒絕" + +#: src/err-codes.h:456 +msgid "(unused SQL code: format)" +msgstr "(未使用的SQL代碼:format æ ¼å¼ï¼‰" + +#: src/err-codes.h:457 +msgid "SQL bind parameter out of range" +msgstr "SQL ç¶å®šå‚數越界" + +#: src/err-codes.h:458 +msgid "File opened that is not an SQL database file" +msgstr "打開的文件ä¸æ˜¯ SQL 資料庫文件" + +#: src/err-codes.h:459 +msgid "Notifications from SQL logger" +msgstr "來自 SQL 日誌記錄的通知" + +#: src/err-codes.h:460 +msgid "Warnings from SQL logger" +msgstr "來自 SQL 日誌記錄的警告" + +#: src/err-codes.h:461 +msgid "SQL has another row ready" +msgstr "SQL 已準備好å¦ä¸€è¡Œ" + +#: src/err-codes.h:462 +msgid "SQL has finished executing" +msgstr "SQL 已執行完æˆ" + +#: src/err-codes.h:463 +msgid "System error w/o errno" +msgstr "系統錯誤但是沒有 errno" + +#: src/err-codes.h:464 +msgid "Unknown system error" +msgstr "未知的系統錯誤" + +#: src/err-codes.h:465 +msgid "End of file" +msgstr "檔案çµå°¾" + +#: src/err-codes.h:466 +msgid "Unknown error code" +msgstr "未知的錯誤代碼" + +#: src/argparse.c:468 +msgid "argument not expected" +msgstr "沒料到有引數" + +#: src/argparse.c:470 +msgid "read error" +msgstr "讀å–錯誤" + +#: src/argparse.c:472 +msgid "keyword too long" +msgstr "é—œéµå­—太長" + +#: src/argparse.c:474 +msgid "missing argument" +msgstr "無效的引數" + +#: src/argparse.c:476 +msgid "invalid argument" +msgstr "無效的引數" + +#: src/argparse.c:478 +msgid "invalid command" +msgstr "無效的指令" + +#: src/argparse.c:480 +msgid "invalid alias definition" +msgstr "無效的別å定義" + +#: src/argparse.c:482 src/argparse.c:519 +msgid "permission error" +msgstr "權é™éŒ¯èª¤" + +#: src/argparse.c:484 src/argparse.c:517 +msgid "out of core" +msgstr "超出核心" + +#: src/argparse.c:488 src/argparse.c:523 +msgid "invalid meta command" +msgstr "無效元命令" + +#: src/argparse.c:490 src/argparse.c:525 +msgid "unknown meta command" +msgstr "未知元命令" + +#: src/argparse.c:492 src/argparse.c:527 +msgid "unexpected meta command" +msgstr "æ„外元命令" + +#: src/argparse.c:494 +msgid "invalid option" +msgstr "無效的é¸é …" + +#: src/argparse.c:504 +#, c-format +msgid "missing argument for option \"%.50s\"\n" +msgstr "\"%.50s\" é¸é …éºå¤±äº†å¼•æ•¸\n" + +#: src/argparse.c:506 +#, c-format +msgid "invalid argument for option \"%.50s\"\n" +msgstr "é¸é … \"%.50s\" 的引數無效\n" + +#: src/argparse.c:508 +#, c-format +msgid "option \"%.50s\" does not expect an argument\n" +msgstr "\"%.50s\" é¸é …沒料到會有引數\n" + +#: src/argparse.c:511 +#, c-format +msgid "invalid command \"%.50s\"\n" +msgstr "無效的指令 \"%.50s\"\n" + +#: src/argparse.c:513 +#, c-format +msgid "option \"%.50s\" is ambiguous\n" +msgstr "\"%.50s\" é¸é …ä¸æ˜Žç¢º\n" + +#: src/argparse.c:515 +#, c-format +msgid "command \"%.50s\" is ambiguous\n" +msgstr "\"%.50s\" 指令ä¸æ˜Žç¢º\n" + +#: src/argparse.c:529 +#, c-format +msgid "invalid option \"%.50s\"\n" +msgstr "無效的é¸é … \"%.50s\"\n" + +#: src/argparse.c:1694 src/argparse.c:1789 +#, c-format +msgid "Note: no default option file '%s'\n" +msgstr "注æ„:文件 '%s' 中無缺çœé¸é …\n" + +#: src/argparse.c:1704 src/argparse.c:1796 +#, c-format +msgid "reading options from '%s'\n" +msgstr "從 '%s' 中讀å–é¸é …\n" + +#: src/argparse.c:1781 +#, c-format +msgid "option file '%s': %s\n" +msgstr "é¸é …文件 '%s': %s\n" + +#: src/argparse.c:2218 +#, c-format +msgid "Note: ignoring option \"--%s\" due to global config\n" +msgstr "注æ„: 由於整體設定,é¸é … \"--%s\" 被忽視\n" + +#: src/gpg-error.c:522 +msgid "Please report bugs to .\n" +msgstr "è«‹å‘ å ±å‘ŠéŒ¯èª¤ã€‚\n" + +#: src/gpg-error.c:762 +#, c-format +msgid "warning: could not recognize %s\n" +msgstr "警告: 無法辨識 %s\n" + +#~ msgid "out of core\n" +#~ msgstr "內存耗盡\n" + +#~ msgid "Usage: %s GPG-ERROR [...]\n" +#~ msgstr "用法: %s GPG-ERROR [...]\n" diff --git a/comm/third_party/libgpg-error/potomo b/comm/third_party/libgpg-error/potomo new file mode 100755 index 0000000000..20617288e5 --- /dev/null +++ b/comm/third_party/libgpg-error/potomo @@ -0,0 +1,64 @@ +#!/bin/sh +# potomo - Convert a .po file to an utf-8 encoded .mo file. +# Copyright 2008 g10 Code GmbH +# Copyright 2010 Free Software Foundation, Inc. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# This script is used to create the mo files for applications using +# the simple gettext implementation provided by libgpg-error. That +# gettext can only cope with utf-8 encoded mo files; thus we make this +# sure while creating the mo. A conversion is not done if the source +# file does not exist or if it is not newer than the mo file. + +if [ "$1" = "--get-linguas" -a $# -eq 2 ]; then + if [ ! -f "$2/LINGUAS" ]; then + echo "potomo: directory '$2' has no LINGUAS file" >&2 + exit 1 + fi + echo $(sed -e "/^#/d" -e "s/#.*//" "$2"/LINGUAS) + exit 0 +fi + +if [ $# -ne 2 ]; then + echo "usage: potomo INFILE.PO OUTFILE.MO" >&2 + echo " potomo --get-linguas DIR" >&2 + exit 1 +fi +infile="$1" +outfile="$2" + +if [ ! -f "$infile" ]; then + echo "potomo: '$infile' not found - ignored" 2>&1 + exit 0 +fi + +if [ "$outfile" -nt "$infile" ]; then + echo "potomo: '$outfile' is newer than source - keeping" 2>&1 + exit 0 +fi + +# Note that we could use the newer msgconv. However this tool was not +# widely available back in 2008. + +fromset=`sed -n '/^"Content-Type:/ s/.*charset=\([a-zA-Z0-9_-]*\).*/\1/p' \ + "$infile"` + +case "$fromset" in + utf8|utf-8|UTF8|UTF-8) + echo "potomo: '$infile' keeping $fromset" >&2 + msgfmt --output-file="$outfile" "$infile" + ;; + *) + echo "potomo: '$infile' converting from $fromset to utf-8" >&2 + iconv --silent --from-code=$fromset --to-code=utf-8 < "$infile" |\ + sed "/^\"Content-Type:/ s/charset=[a-zA-Z0-9_-]*/charset=utf-8/"|\ + msgfmt --output-file="$outfile" - + ;; +esac diff --git a/comm/third_party/libgpg-error/src/Makefile.am b/comm/third_party/libgpg-error/src/Makefile.am new file mode 100644 index 0000000000..fc3acc3f60 --- /dev/null +++ b/comm/third_party/libgpg-error/src/Makefile.am @@ -0,0 +1,367 @@ +# Makefile.am for libgpg-error. +# Copyright (C) 2003, 2004, 2014 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +# SPDX-License-Identifier: LGPL-2.1+ + + +# +# We distribute the generated sources err-sources.h and err-codes.h, +# because they are needed to build the po directory, and they don't +# depend on the configuration anyway. +# + +if HAVE_W32CE_SYSTEM +gpg_extra_headers = gpg-extra/errno.h +extra_cppflags = -idirafter gpg-extra +else +gpg_extra_headers = +extra_cppflags = +endif + +localedir = $(datadir)/locale + +bin_PROGRAMS = gpg-error + +if HAVE_W32_SYSTEM +noinst_PROGRAMS = gen-w32-lock-obj +else +noinst_PROGRAMS = gen-posix-lock-obj +endif + +# Distributed lock object definitions for cross compilation. +lock_obj_pub = \ + syscfg/lock-obj-pub.aarch64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h \ + syscfg/lock-obj-pub.aarch64-apple-darwin.h \ + syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.arm-unknown-linux-androideabi.h \ + syscfg/lock-obj-pub.arm-unknown-linux-gnueabi.h \ + syscfg/lock-obj-pub.arm-apple-darwin.h \ + syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.i386-apple-darwin.h \ + syscfg/lock-obj-pub.i686-unknown-gnu.h \ + syscfg/lock-obj-pub.i686-unknown-kfreebsd-gnu.h \ + syscfg/lock-obj-pub.i686-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.mips-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.mips64el-unknown-linux-gnuabi64.h \ + syscfg/lock-obj-pub.mips64-unknown-linux-gnuabi64.h \ + syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc64le-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc-unknown-linux-gnuspe.h \ + syscfg/lock-obj-pub.riscv64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.riscv32-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sparc64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.x86_64-apple-darwin.h \ + syscfg/lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h \ + syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.x86_64-unknown-linux-gnux32.h \ + syscfg/lock-obj-pub.x86_64-unknown-linux-musl.h \ + syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.mingw32.h + + +lib_LTLIBRARIES = libgpg-error.la +nodist_include_HEADERS = gpg-error.h gpgrt.h +dist_bin_SCRIPTS = gpgrt-config +bin_SCRIPTS = gpg-error-config +m4datadir = $(datadir)/aclocal +m4data_DATA = gpg-error.m4 gpgrt.m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gpg-error.pc + +EXTRA_DIST = mkstrtable.awk err-sources.h.in err-codes.h.in \ + mkerrnos.awk errnos.in README \ + mkerrcodes.awk mkerrcodes1.awk mkerrcodes2.awk mkerrcodes.c \ + mkheader.c gpg-error.h.in mkw32errmap.c w32-add.h w32ce-add.h \ + err-sources.h err-codes.h gpg-error-config.in gpg-error.m4 gpgrt.m4 \ + gpg-error.vers gpg-error.def.in \ + versioninfo.rc.in gpg-error.w32-manifest.in \ + gpg-error-config-test.sh gpg-error.pc.in \ + gen-lock-obj.sh $(lock_obj_pub) + +BUILT_SOURCES = $(srcdir)/err-sources.h $(srcdir)/err-codes.h \ + code-to-errno.h code-from-errno.h \ + err-sources-sym.h err-codes-sym.h errnos-sym.h gpg-error.h gpgrt.h \ + gpg-error.def mkw32errmap.map.c + +tmp_files = _mkerrcodes.h _gpg-error.def.h mkw32errmap.tab.h mkw32errmap.map.c + +CLEANFILES = code-to-errno.h code-from-errno.h \ + gpg-error.h gpgrt.h \ + mkerrcodes$(EXEEXT_FOR_BUILD) mkerrcodes.h gpg-error.def mkw32errmap.tab.h \ + mkw32errmap.map.c err-sources-sym.h err-codes-sym.h errnos-sym.h \ + gpg-extra/errno.h mkheader$(EXEEXT_FOR_BUILD) \ + gpg-error-config gpg-error-config-test.log \ + $(tmp_files) lock-obj-pub.native.h + +MAINTAINERCLEANFILES = $(srcdir)/err-sources.h $(srcdir)/err-codes.h + +TESTS = gpg-error-config-test.sh + +# +# {{{ Begin Windows part +# +if HAVE_W32_SYSTEM +arch_sources = w32-gettext.c w32-lock.c w32-lock-obj.h w32-thread.c \ + w32-iconv.c w32-estream.c w32-reg.c spawn-w32.c +RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) $(CPPFLAGS) +LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE) + +SUFFIXES = .rc .lo + +.rc.lo: + $(LTRCCOMPILE) -i "$<" -o "$@" + +gpg_error_res = versioninfo.lo +export_symbols = -export-symbols gpg-error.def +# i686-w64-mingw32.gcc version 4.9.1 takes the long long helper +# functions from libgcc_s_sjlj-1.dll and not from a static libgcc. As +# a plain C program we do not use exception handler and thus there is +# no need to use this DLL. Thus we force gcc to link that statically. +extra_ltoptions = -XCClinker -static-libgcc + +versioninfo.lo : gpg-error.w32-manifest + +install-def-file: gpg-error.def + -$(INSTALL) -d $(DESTDIR)$(libdir) + $(INSTALL) gpg-error.def $(DESTDIR)$(libdir)/gpg-error.def + +uninstall-def-file: + -rm $(DESTDIR)$(libdir)/gpg-error.def + +libgpg_error_la_DEPENDENCIES = $(gpg_error_res) gpg-error.def +intllibs = + +# +# }}} End Windows part +# +else +# +# {{{ Begin Unix part +# +arch_sources = posix-lock.c posix-lock-obj.h posix-thread.c spawn-posix.c +gpg_error_res = +export_symbols = +extra_ltoptions = + +install-def-file: +uninstall-def-file: + +intllibs = @LTLIBINTL@ + +endif +# +# }}} End Unix part +# + +socklibs = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ + +if HAVE_LD_VERSION_SCRIPT + libgpg_error_vers_opt = -Wl,--version-script=$(srcdir)/gpg-error.vers +else + libgpg_error_vers_opt = +endif + +libgpg_error_la_LDFLAGS = \ + -no-undefined $(export_symbols) $(libgpg_error_vers_opt) \ + $(extra_ltoptions) -version-info \ + @LIBGPG_ERROR_LT_CURRENT@:@LIBGPG_ERROR_LT_REVISION@:@LIBGPG_ERROR_LT_AGE@ + +libgpg_error_la_SOURCES = gettext.h $(arch_sources) \ + gpgrt-int.h protos.h init.c init.h version.c lock.h thread.h \ + estream.c estream-printf.c estream-printf.h \ + strsource.c strerror.c code-to-errno.c code-from-errno.c \ + visibility.c visibility.h \ + sysutils.c \ + stringutils.c \ + syscall-clamp.c \ + logging.c \ + b64dec.c b64enc.c \ + argparse.c + + +nodist_libgpg_error_la_SOURCES = gpg-error.h + +# libgpg_error_la_DEPENDENCIES = \ +# $(srcdir)/gpg-error.vers + +# Note that RCCOMPILE needs the same defines as ..._la_CPPFLAGS but +# without the extra_cppflags because they may include am -idirafter +# which is not supported by the RC compiler. +libgpg_error_la_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(extra_cppflags) +libgpg_error_la_LIBADD = $(gpg_error_res) $(intllibs) $(socklibs) $(LIBTHREAD) + +gpg_error_SOURCES = strsource-sym.c strerror-sym.c gpg-error.c +gpg_error_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ + -DLOCALEDIR=\"$(localedir)\" $(extra_cppflags) +gpg_error_LDADD = libgpg-error.la $(LTLIBINTL) + +# We build err-sources.h and err-codes.h in the source directory. +# This is needed because gettext does only look into the source +# directory to find the files listed in po/POTFILE.in. To make these +# rules work we also need to depend on Makefile.am and not on the +# generated files Makefile.in or Makefile. +$(srcdir)/err-sources.h: Makefile.am mkstrtable.awk err-sources.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 \ + $(srcdir)/err-sources.h.in >$@ + +err-sources-sym.h: Makefile mkstrtable.awk err-sources.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ + $(srcdir)/err-sources.h.in >$@ + +$(srcdir)/err-codes.h: Makefile.am mkstrtable.awk err-codes.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 \ + $(srcdir)/err-codes.h.in >$@ + +err-codes-sym.h: Makefile mkstrtable.awk err-codes.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ + $(srcdir)/err-codes.h.in >$@ + +code-to-errno.h: Makefile mkerrnos.awk errnos.in + $(AWK) -f $(srcdir)/mkerrnos.awk $(srcdir)/errnos.in >$@ + +# It is correct to use $(CPP). We want the host's idea of the error codes. +mkerrcodes.h: Makefile mkerrcodes.awk $(gpg_extra_headers) + $(AWK) -f $(srcdir)/mkerrcodes1.awk $(srcdir)/errnos.in >_$@ + $(CPP) $(CPPFLAGS) $(extra_cppflags) -P _$@ | grep GPG_ERR_ | \ + $(AWK) -f $(srcdir)/mkerrcodes.awk >$@ + -rm _$@ + +if HAVE_W32CE_SYSTEM +# It is correct to use $(CPP). We want the host's idea of the error codes. +mkw32errmap.tab.h: Makefile mkw32errmap.c + $(CPP) -DRESOLVE_MACROS $(srcdir)/mkw32errmap.c | \ + grep '{&mkw32errmap_marker' >$@ +mkw32errmap.map.c: mkw32errmap$(EXEEXT_FOR_BUILD) + ./mkw32errmap$(EXEEXT_FOR_BUILD) --map > $@ +gpg-extra/errno.h: mkw32errmap$(EXEEXT_FOR_BUILD) + -$(MKDIR_P) gpg-extra + ./mkw32errmap$(EXEEXT_FOR_BUILD) > $@ +else +mkw32errmap.map.c: + echo "/*dummy*/" > $@ +endif + +# We use CC proper for preprocessing thus we have to convince it that +# the data is really to be preprocessed. +gpg-error.def: Makefile gpg-error.def.in + cat $(srcdir)/gpg-error.def.in >_$@.h + $(CPP) $(DEFAULT_INCLUDES) $(INCLUDES) $(extra_cppflags) _$@.h | \ + grep -v '^#' >$@ + -rm _$@.h + +# It is correct to use $(CC_FOR_BUILD) here. We want to run the +# program at build time. +mkerrcodes$(EXEEXT_FOR_BUILD): mkerrcodes.c mkerrcodes.h Makefile + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkerrcodes.c + +if HAVE_W32CE_SYSTEM +# It is correct to use $(CC_FOR_BUILD) here. We want to run the +# program at build time. +mkw32errmap$(EXEEXT_FOR_BUILD): mkw32errmap.c mkw32errmap.tab.h Makefile + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkw32errmap.c +endif + +code-from-errno.h: mkerrcodes$(EXEEXT_FOR_BUILD) Makefile + ./mkerrcodes$(EXEEXT_FOR_BUILD) | $(AWK) -f $(srcdir)/mkerrcodes2.awk >$@ + +errnos-sym.h: Makefile mkstrtable.awk errnos.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ + -v prefix=GPG_ERR_ -v pkg_namespace=errnos_ \ + $(srcdir)/errnos.in >$@ + + +mkheader$(EXEEXT_FOR_BUILD): mkheader.c Makefile + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD) -g -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c + +parts_of_gpg_error_h = \ + gpg-error.h.in \ + err-sources.h.in \ + err-codes.h.in \ + errnos.in \ + w32-add.h \ + w32ce-add.h \ + $(lock_obj_pub) + +# If we are cross-compiling or building on Windows we better make sure +# that no stale native lock include file will be found by mkheader. +if FORCE_USE_SYSCFG +pre_mkheader_cmds = if test -f lock-obj-pub.native.h; \ + then rm lock-obj-pub.native.h; fi +mkheader_opts = --cross +else +if HAVE_GENERATED_LOCK_OBJ_H +# lock-obj-pub.native.h is generated at configure time +pre_mkheader_cmds = : +mkheader_opts = +parts_of_gpg_error_h += ./lock-obj-pub.native.h +else +pre_mkheader_cmds = : +mkheader_opts = +parts_of_gpg_error_h += ./lock-obj-pub.native.h + +./lock-obj-pub.native.h: Makefile gen-posix-lock-obj$(EXEEXT) posix-lock-obj.h + ./gen-posix-lock-obj >$@ +endif +endif + +# We also depend on versioninfo.rc because that is build by +# config.status and thus has up-to-date version numbers. +gpg-error.h: Makefile mkheader$(EXEEXT_FOR_BUILD) $(parts_of_gpg_error_h) \ + versioninfo.rc ../config.h + $(pre_mkheader_cmds) + ./mkheader$(EXEEXT_FOR_BUILD) $(mkheader_opts) \ + $(host_triplet) $(srcdir)/gpg-error.h.in \ + ../config.h $(PACKAGE_VERSION) $(VERSION_NUMBER) >$@ + +gpgrt.h: gpg-error.h + cp gpg-error.h gpgrt.h + +gpg-error-config: gpgrt-config gpg-error-config-old + @echo $(ECHO_N) "Confirm gpg-error-config works... $(ECHO_C)" + @if ./gpg-error-config-test.sh --old-new; then \ + echo "good"; \ + else \ + echo "no"; \ + echo "*** Please report to with gpg-error-config-test.log"; \ + exit 1; \ + fi + cp gpg-error-config-old $@ + +install-data-local: +if HAVE_W32CE_SYSTEM + -$(MKDIR_P) "$(DESTDIR)$(includedir)/gpg-extra" + $(INSTALL_DATA) gpg-extra/errno.h \ + "$(DESTDIR)$(includedir)/gpg-extra/errno.h" +else + : +endif diff --git a/comm/third_party/libgpg-error/src/Makefile.in b/comm/third_party/libgpg-error/src/Makefile.in new file mode 100644 index 0000000000..cf5cf8d98a --- /dev/null +++ b/comm/third_party/libgpg-error/src/Makefile.in @@ -0,0 +1,1784 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for libgpg-error. +# Copyright (C) 2003, 2004, 2014 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +# SPDX-License-Identifier: LGPL-2.1+ + +# +# We distribute the generated sources err-sources.h and err-codes.h, +# because they are needed to build the po directory, and they don't +# depend on the configuration anyway. +# + + + + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = gpg-error$(EXEEXT) +@HAVE_W32_SYSTEM_FALSE@noinst_PROGRAMS = gen-posix-lock-obj$(EXEEXT) +@HAVE_W32_SYSTEM_TRUE@noinst_PROGRAMS = gen-w32-lock-obj$(EXEEXT) +@HAVE_W32_SYSTEM_FALSE@libgpg_error_la_DEPENDENCIES = \ +@HAVE_W32_SYSTEM_FALSE@ $(am__DEPENDENCIES_1) \ +@HAVE_W32_SYSTEM_FALSE@ $(am__DEPENDENCIES_2) \ +@HAVE_W32_SYSTEM_FALSE@ $(am__DEPENDENCIES_2) \ +@HAVE_W32_SYSTEM_FALSE@ $(am__DEPENDENCIES_2) +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_TRUE@am__append_1 = ./lock-obj-pub.native.h +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_FALSE@am__append_2 = ./lock-obj-pub.native.h +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ + $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/estream.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnupg-misc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/threadlib.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_bin_SCRIPTS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = versioninfo.rc gpg-error.w32-manifest \ + gpg-error.pc gpg-error-config-old gpgrt-config \ + gpg-error-config-test.sh +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgconfigdir)" \ + "$(DESTDIR)$(includedir)" +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +LTLIBRARIES = $(lib_LTLIBRARIES) +@HAVE_W32_SYSTEM_TRUE@am__DEPENDENCIES_1 = versioninfo.lo +am__DEPENDENCIES_2 = +am__libgpg_error_la_SOURCES_DIST = gettext.h posix-lock.c \ + posix-lock-obj.h posix-thread.c spawn-posix.c w32-gettext.c \ + w32-lock.c w32-lock-obj.h w32-thread.c w32-iconv.c \ + w32-estream.c w32-reg.c spawn-w32.c gpgrt-int.h protos.h \ + init.c init.h version.c lock.h thread.h estream.c \ + estream-printf.c estream-printf.h strsource.c strerror.c \ + code-to-errno.c code-from-errno.c visibility.c visibility.h \ + sysutils.c stringutils.c syscall-clamp.c logging.c b64dec.c \ + b64enc.c argparse.c +@HAVE_W32_SYSTEM_FALSE@am__objects_1 = libgpg_error_la-posix-lock.lo \ +@HAVE_W32_SYSTEM_FALSE@ libgpg_error_la-posix-thread.lo \ +@HAVE_W32_SYSTEM_FALSE@ libgpg_error_la-spawn-posix.lo +@HAVE_W32_SYSTEM_TRUE@am__objects_1 = libgpg_error_la-w32-gettext.lo \ +@HAVE_W32_SYSTEM_TRUE@ libgpg_error_la-w32-lock.lo \ +@HAVE_W32_SYSTEM_TRUE@ libgpg_error_la-w32-thread.lo \ +@HAVE_W32_SYSTEM_TRUE@ libgpg_error_la-w32-iconv.lo \ +@HAVE_W32_SYSTEM_TRUE@ libgpg_error_la-w32-estream.lo \ +@HAVE_W32_SYSTEM_TRUE@ libgpg_error_la-w32-reg.lo \ +@HAVE_W32_SYSTEM_TRUE@ libgpg_error_la-spawn-w32.lo +am_libgpg_error_la_OBJECTS = $(am__objects_1) libgpg_error_la-init.lo \ + libgpg_error_la-version.lo libgpg_error_la-estream.lo \ + libgpg_error_la-estream-printf.lo libgpg_error_la-strsource.lo \ + libgpg_error_la-strerror.lo libgpg_error_la-code-to-errno.lo \ + libgpg_error_la-code-from-errno.lo \ + libgpg_error_la-visibility.lo libgpg_error_la-sysutils.lo \ + libgpg_error_la-stringutils.lo \ + libgpg_error_la-syscall-clamp.lo libgpg_error_la-logging.lo \ + libgpg_error_la-b64dec.lo libgpg_error_la-b64enc.lo \ + libgpg_error_la-argparse.lo +nodist_libgpg_error_la_OBJECTS = +libgpg_error_la_OBJECTS = $(am_libgpg_error_la_OBJECTS) \ + $(nodist_libgpg_error_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libgpg_error_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgpg_error_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +gen_posix_lock_obj_SOURCES = gen-posix-lock-obj.c +gen_posix_lock_obj_OBJECTS = gen-posix-lock-obj.$(OBJEXT) +gen_posix_lock_obj_LDADD = $(LDADD) +gen_w32_lock_obj_SOURCES = gen-w32-lock-obj.c +gen_w32_lock_obj_OBJECTS = gen-w32-lock-obj.$(OBJEXT) +gen_w32_lock_obj_LDADD = $(LDADD) +am_gpg_error_OBJECTS = gpg_error-strsource-sym.$(OBJEXT) \ + gpg_error-strerror-sym.$(OBJEXT) gpg_error-gpg-error.$(OBJEXT) +gpg_error_OBJECTS = $(am_gpg_error_OBJECTS) +gpg_error_DEPENDENCIES = libgpg-error.la $(am__DEPENDENCIES_2) +SCRIPTS = $(bin_SCRIPTS) $(dist_bin_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/gen-posix-lock-obj.Po \ + ./$(DEPDIR)/gen-w32-lock-obj.Po \ + ./$(DEPDIR)/gpg_error-gpg-error.Po \ + ./$(DEPDIR)/gpg_error-strerror-sym.Po \ + ./$(DEPDIR)/gpg_error-strsource-sym.Po \ + ./$(DEPDIR)/libgpg_error_la-argparse.Plo \ + ./$(DEPDIR)/libgpg_error_la-b64dec.Plo \ + ./$(DEPDIR)/libgpg_error_la-b64enc.Plo \ + ./$(DEPDIR)/libgpg_error_la-code-from-errno.Plo \ + ./$(DEPDIR)/libgpg_error_la-code-to-errno.Plo \ + ./$(DEPDIR)/libgpg_error_la-estream-printf.Plo \ + ./$(DEPDIR)/libgpg_error_la-estream.Plo \ + ./$(DEPDIR)/libgpg_error_la-init.Plo \ + ./$(DEPDIR)/libgpg_error_la-logging.Plo \ + ./$(DEPDIR)/libgpg_error_la-posix-lock.Plo \ + ./$(DEPDIR)/libgpg_error_la-posix-thread.Plo \ + ./$(DEPDIR)/libgpg_error_la-spawn-posix.Plo \ + ./$(DEPDIR)/libgpg_error_la-spawn-w32.Plo \ + ./$(DEPDIR)/libgpg_error_la-strerror.Plo \ + ./$(DEPDIR)/libgpg_error_la-stringutils.Plo \ + ./$(DEPDIR)/libgpg_error_la-strsource.Plo \ + ./$(DEPDIR)/libgpg_error_la-syscall-clamp.Plo \ + ./$(DEPDIR)/libgpg_error_la-sysutils.Plo \ + ./$(DEPDIR)/libgpg_error_la-version.Plo \ + ./$(DEPDIR)/libgpg_error_la-visibility.Plo \ + ./$(DEPDIR)/libgpg_error_la-w32-estream.Plo \ + ./$(DEPDIR)/libgpg_error_la-w32-gettext.Plo \ + ./$(DEPDIR)/libgpg_error_la-w32-iconv.Plo \ + ./$(DEPDIR)/libgpg_error_la-w32-lock.Plo \ + ./$(DEPDIR)/libgpg_error_la-w32-reg.Plo \ + ./$(DEPDIR)/libgpg_error_la-w32-thread.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libgpg_error_la_SOURCES) $(nodist_libgpg_error_la_SOURCES) \ + gen-posix-lock-obj.c gen-w32-lock-obj.c $(gpg_error_SOURCES) +DIST_SOURCES = $(am__libgpg_error_la_SOURCES_DIST) \ + gen-posix-lock-obj.c gen-w32-lock-obj.c $(gpg_error_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(m4data_DATA) $(pkgconfig_DATA) +HEADERS = $(nodist_include_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(srcdir)/gpg-error-config-test.sh.in \ + $(srcdir)/gpg-error-config.in $(srcdir)/gpg-error.pc.in \ + $(srcdir)/gpg-error.w32-manifest.in $(srcdir)/gpgrt-config.in \ + $(srcdir)/versioninfo.rc.in $(top_srcdir)/build-aux/depcomp \ + README +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GPG_ERROR_CONFIG_CFLAGS = @GPG_ERROR_CONFIG_CFLAGS@ +GPG_ERROR_CONFIG_HOST = @GPG_ERROR_CONFIG_HOST@ +GPG_ERROR_CONFIG_LIBS = @GPG_ERROR_CONFIG_LIBS@ +GPG_ERROR_CONFIG_LIBS_PRIVATE = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +GPG_ERROR_CONFIG_MT_CFLAGS = @GPG_ERROR_CONFIG_MT_CFLAGS@ +GPG_ERROR_CONFIG_MT_LIBS = @GPG_ERROR_CONFIG_MT_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALLSHELLPATH = @INSTALLSHELLPATH@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGPG_ERROR_LT_AGE = @LIBGPG_ERROR_LT_AGE@ +LIBGPG_ERROR_LT_CURRENT = @LIBGPG_ERROR_LT_CURRENT@ +LIBGPG_ERROR_LT_REVISION = @LIBGPG_ERROR_LT_REVISION@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBREADLINE = @LIBREADLINE@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_NETWORK = @LIB_NETWORK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = $(datadir)/locale +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@HAVE_W32CE_SYSTEM_FALSE@gpg_extra_headers = +@HAVE_W32CE_SYSTEM_TRUE@gpg_extra_headers = gpg-extra/errno.h +@HAVE_W32CE_SYSTEM_FALSE@extra_cppflags = +@HAVE_W32CE_SYSTEM_TRUE@extra_cppflags = -idirafter gpg-extra + +# Distributed lock object definitions for cross compilation. +lock_obj_pub = \ + syscfg/lock-obj-pub.aarch64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h \ + syscfg/lock-obj-pub.aarch64-apple-darwin.h \ + syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.arm-unknown-linux-androideabi.h \ + syscfg/lock-obj-pub.arm-unknown-linux-gnueabi.h \ + syscfg/lock-obj-pub.arm-apple-darwin.h \ + syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.i386-apple-darwin.h \ + syscfg/lock-obj-pub.i686-unknown-gnu.h \ + syscfg/lock-obj-pub.i686-unknown-kfreebsd-gnu.h \ + syscfg/lock-obj-pub.i686-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.mips-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.mips64el-unknown-linux-gnuabi64.h \ + syscfg/lock-obj-pub.mips64-unknown-linux-gnuabi64.h \ + syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc64le-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.powerpc-unknown-linux-gnuspe.h \ + syscfg/lock-obj-pub.riscv64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.riscv32-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.sparc64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.x86_64-apple-darwin.h \ + syscfg/lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h \ + syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.x86_64-unknown-linux-gnux32.h \ + syscfg/lock-obj-pub.x86_64-unknown-linux-musl.h \ + syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h \ + syscfg/lock-obj-pub.mingw32.h + +lib_LTLIBRARIES = libgpg-error.la +nodist_include_HEADERS = gpg-error.h gpgrt.h +dist_bin_SCRIPTS = gpgrt-config +bin_SCRIPTS = gpg-error-config +m4datadir = $(datadir)/aclocal +m4data_DATA = gpg-error.m4 gpgrt.m4 +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gpg-error.pc +EXTRA_DIST = mkstrtable.awk err-sources.h.in err-codes.h.in \ + mkerrnos.awk errnos.in README \ + mkerrcodes.awk mkerrcodes1.awk mkerrcodes2.awk mkerrcodes.c \ + mkheader.c gpg-error.h.in mkw32errmap.c w32-add.h w32ce-add.h \ + err-sources.h err-codes.h gpg-error-config.in gpg-error.m4 gpgrt.m4 \ + gpg-error.vers gpg-error.def.in \ + versioninfo.rc.in gpg-error.w32-manifest.in \ + gpg-error-config-test.sh gpg-error.pc.in \ + gen-lock-obj.sh $(lock_obj_pub) + +BUILT_SOURCES = $(srcdir)/err-sources.h $(srcdir)/err-codes.h \ + code-to-errno.h code-from-errno.h \ + err-sources-sym.h err-codes-sym.h errnos-sym.h gpg-error.h gpgrt.h \ + gpg-error.def mkw32errmap.map.c + +tmp_files = _mkerrcodes.h _gpg-error.def.h mkw32errmap.tab.h mkw32errmap.map.c +CLEANFILES = code-to-errno.h code-from-errno.h \ + gpg-error.h gpgrt.h \ + mkerrcodes$(EXEEXT_FOR_BUILD) mkerrcodes.h gpg-error.def mkw32errmap.tab.h \ + mkw32errmap.map.c err-sources-sym.h err-codes-sym.h errnos-sym.h \ + gpg-extra/errno.h mkheader$(EXEEXT_FOR_BUILD) \ + gpg-error-config gpg-error-config-test.log \ + $(tmp_files) lock-obj-pub.native.h + +MAINTAINERCLEANFILES = $(srcdir)/err-sources.h $(srcdir)/err-codes.h +TESTS = gpg-error-config-test.sh + +# +# }}} End Windows part +# +# +# {{{ Begin Unix part +# +@HAVE_W32_SYSTEM_FALSE@arch_sources = posix-lock.c posix-lock-obj.h posix-thread.c spawn-posix.c + +# +# {{{ Begin Windows part +# +@HAVE_W32_SYSTEM_TRUE@arch_sources = w32-gettext.c w32-lock.c w32-lock-obj.h w32-thread.c \ +@HAVE_W32_SYSTEM_TRUE@ w32-iconv.c w32-estream.c w32-reg.c spawn-w32.c + +@HAVE_W32_SYSTEM_TRUE@RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +@HAVE_W32_SYSTEM_TRUE@ -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) $(CPPFLAGS) + +@HAVE_W32_SYSTEM_TRUE@LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE) +@HAVE_W32_SYSTEM_TRUE@SUFFIXES = .rc .lo +@HAVE_W32_SYSTEM_FALSE@gpg_error_res = +@HAVE_W32_SYSTEM_TRUE@gpg_error_res = versioninfo.lo +@HAVE_W32_SYSTEM_FALSE@export_symbols = +@HAVE_W32_SYSTEM_TRUE@export_symbols = -export-symbols gpg-error.def +@HAVE_W32_SYSTEM_FALSE@extra_ltoptions = +# i686-w64-mingw32.gcc version 4.9.1 takes the long long helper +# functions from libgcc_s_sjlj-1.dll and not from a static libgcc. As +# a plain C program we do not use exception handler and thus there is +# no need to use this DLL. Thus we force gcc to link that statically. +@HAVE_W32_SYSTEM_TRUE@extra_ltoptions = -XCClinker -static-libgcc +@HAVE_W32_SYSTEM_TRUE@libgpg_error_la_DEPENDENCIES = $(gpg_error_res) gpg-error.def +@HAVE_W32_SYSTEM_FALSE@intllibs = @LTLIBINTL@ +@HAVE_W32_SYSTEM_TRUE@intllibs = + +# +# }}} End Unix part +# +socklibs = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +@HAVE_LD_VERSION_SCRIPT_FALSE@libgpg_error_vers_opt = +@HAVE_LD_VERSION_SCRIPT_TRUE@libgpg_error_vers_opt = -Wl,--version-script=$(srcdir)/gpg-error.vers +libgpg_error_la_LDFLAGS = \ + -no-undefined $(export_symbols) $(libgpg_error_vers_opt) \ + $(extra_ltoptions) -version-info \ + @LIBGPG_ERROR_LT_CURRENT@:@LIBGPG_ERROR_LT_REVISION@:@LIBGPG_ERROR_LT_AGE@ + +libgpg_error_la_SOURCES = gettext.h $(arch_sources) \ + gpgrt-int.h protos.h init.c init.h version.c lock.h thread.h \ + estream.c estream-printf.c estream-printf.h \ + strsource.c strerror.c code-to-errno.c code-from-errno.c \ + visibility.c visibility.h \ + sysutils.c \ + stringutils.c \ + syscall-clamp.c \ + logging.c \ + b64dec.c b64enc.c \ + argparse.c + +nodist_libgpg_error_la_SOURCES = gpg-error.h + +# libgpg_error_la_DEPENDENCIES = \ +# $(srcdir)/gpg-error.vers + +# Note that RCCOMPILE needs the same defines as ..._la_CPPFLAGS but +# without the extra_cppflags because they may include am -idirafter +# which is not supported by the RC compiler. +libgpg_error_la_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(extra_cppflags) +libgpg_error_la_LIBADD = $(gpg_error_res) $(intllibs) $(socklibs) $(LIBTHREAD) +gpg_error_SOURCES = strsource-sym.c strerror-sym.c gpg-error.c +gpg_error_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" \ + -DLOCALEDIR=\"$(localedir)\" $(extra_cppflags) + +gpg_error_LDADD = libgpg-error.la $(LTLIBINTL) +parts_of_gpg_error_h = gpg-error.h.in err-sources.h.in err-codes.h.in \ + errnos.in w32-add.h w32ce-add.h $(lock_obj_pub) \ + $(am__append_1) $(am__append_2) +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_FALSE@pre_mkheader_cmds = : +# lock-obj-pub.native.h is generated at configure time +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_TRUE@pre_mkheader_cmds = : + +# If we are cross-compiling or building on Windows we better make sure +# that no stale native lock include file will be found by mkheader. +@FORCE_USE_SYSCFG_TRUE@pre_mkheader_cmds = if test -f lock-obj-pub.native.h; \ +@FORCE_USE_SYSCFG_TRUE@ then rm lock-obj-pub.native.h; fi + +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_FALSE@mkheader_opts = +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_TRUE@mkheader_opts = +@FORCE_USE_SYSCFG_TRUE@mkheader_opts = --cross +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .rc .lo .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +versioninfo.rc: $(top_builddir)/config.status $(srcdir)/versioninfo.rc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpg-error.w32-manifest: $(top_builddir)/config.status $(srcdir)/gpg-error.w32-manifest.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpg-error.pc: $(top_builddir)/config.status $(srcdir)/gpg-error.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpg-error-config-old: $(top_builddir)/config.status $(srcdir)/gpg-error-config.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpgrt-config: $(top_builddir)/config.status $(srcdir)/gpgrt-config.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpg-error-config-test.sh: $(top_builddir)/config.status $(srcdir)/gpg-error-config-test.sh.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libgpg-error.la: $(libgpg_error_la_OBJECTS) $(libgpg_error_la_DEPENDENCIES) $(EXTRA_libgpg_error_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgpg_error_la_LINK) -rpath $(libdir) $(libgpg_error_la_OBJECTS) $(libgpg_error_la_LIBADD) $(LIBS) + +gen-posix-lock-obj$(EXEEXT): $(gen_posix_lock_obj_OBJECTS) $(gen_posix_lock_obj_DEPENDENCIES) $(EXTRA_gen_posix_lock_obj_DEPENDENCIES) + @rm -f gen-posix-lock-obj$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gen_posix_lock_obj_OBJECTS) $(gen_posix_lock_obj_LDADD) $(LIBS) + +gen-w32-lock-obj$(EXEEXT): $(gen_w32_lock_obj_OBJECTS) $(gen_w32_lock_obj_DEPENDENCIES) $(EXTRA_gen_w32_lock_obj_DEPENDENCIES) + @rm -f gen-w32-lock-obj$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gen_w32_lock_obj_OBJECTS) $(gen_w32_lock_obj_LDADD) $(LIBS) + +gpg-error$(EXEEXT): $(gpg_error_OBJECTS) $(gpg_error_DEPENDENCIES) $(EXTRA_gpg_error_DEPENDENCIES) + @rm -f gpg-error$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gpg_error_OBJECTS) $(gpg_error_LDADD) $(LIBS) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) +install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-dist_binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen-posix-lock-obj.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen-w32-lock-obj.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_error-gpg-error.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_error-strerror-sym.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpg_error-strsource-sym.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-argparse.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-b64dec.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-b64enc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-code-from-errno.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-code-to-errno.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-estream-printf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-estream.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-init.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-logging.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-posix-lock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-posix-thread.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-spawn-posix.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-spawn-w32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-strerror.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-stringutils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-strsource.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-syscall-clamp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-sysutils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-version.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-visibility.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-w32-estream.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-w32-gettext.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-w32-iconv.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-w32-lock.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-w32-reg.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgpg_error_la-w32-thread.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libgpg_error_la-posix-lock.lo: posix-lock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-posix-lock.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-posix-lock.Tpo -c -o libgpg_error_la-posix-lock.lo `test -f 'posix-lock.c' || echo '$(srcdir)/'`posix-lock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-posix-lock.Tpo $(DEPDIR)/libgpg_error_la-posix-lock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='posix-lock.c' object='libgpg_error_la-posix-lock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-posix-lock.lo `test -f 'posix-lock.c' || echo '$(srcdir)/'`posix-lock.c + +libgpg_error_la-posix-thread.lo: posix-thread.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-posix-thread.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-posix-thread.Tpo -c -o libgpg_error_la-posix-thread.lo `test -f 'posix-thread.c' || echo '$(srcdir)/'`posix-thread.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-posix-thread.Tpo $(DEPDIR)/libgpg_error_la-posix-thread.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='posix-thread.c' object='libgpg_error_la-posix-thread.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-posix-thread.lo `test -f 'posix-thread.c' || echo '$(srcdir)/'`posix-thread.c + +libgpg_error_la-spawn-posix.lo: spawn-posix.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-spawn-posix.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-spawn-posix.Tpo -c -o libgpg_error_la-spawn-posix.lo `test -f 'spawn-posix.c' || echo '$(srcdir)/'`spawn-posix.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-spawn-posix.Tpo $(DEPDIR)/libgpg_error_la-spawn-posix.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spawn-posix.c' object='libgpg_error_la-spawn-posix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-spawn-posix.lo `test -f 'spawn-posix.c' || echo '$(srcdir)/'`spawn-posix.c + +libgpg_error_la-w32-gettext.lo: w32-gettext.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-w32-gettext.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-w32-gettext.Tpo -c -o libgpg_error_la-w32-gettext.lo `test -f 'w32-gettext.c' || echo '$(srcdir)/'`w32-gettext.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-w32-gettext.Tpo $(DEPDIR)/libgpg_error_la-w32-gettext.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-gettext.c' object='libgpg_error_la-w32-gettext.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-w32-gettext.lo `test -f 'w32-gettext.c' || echo '$(srcdir)/'`w32-gettext.c + +libgpg_error_la-w32-lock.lo: w32-lock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-w32-lock.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-w32-lock.Tpo -c -o libgpg_error_la-w32-lock.lo `test -f 'w32-lock.c' || echo '$(srcdir)/'`w32-lock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-w32-lock.Tpo $(DEPDIR)/libgpg_error_la-w32-lock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-lock.c' object='libgpg_error_la-w32-lock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-w32-lock.lo `test -f 'w32-lock.c' || echo '$(srcdir)/'`w32-lock.c + +libgpg_error_la-w32-thread.lo: w32-thread.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-w32-thread.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-w32-thread.Tpo -c -o libgpg_error_la-w32-thread.lo `test -f 'w32-thread.c' || echo '$(srcdir)/'`w32-thread.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-w32-thread.Tpo $(DEPDIR)/libgpg_error_la-w32-thread.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-thread.c' object='libgpg_error_la-w32-thread.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-w32-thread.lo `test -f 'w32-thread.c' || echo '$(srcdir)/'`w32-thread.c + +libgpg_error_la-w32-iconv.lo: w32-iconv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-w32-iconv.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-w32-iconv.Tpo -c -o libgpg_error_la-w32-iconv.lo `test -f 'w32-iconv.c' || echo '$(srcdir)/'`w32-iconv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-w32-iconv.Tpo $(DEPDIR)/libgpg_error_la-w32-iconv.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-iconv.c' object='libgpg_error_la-w32-iconv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-w32-iconv.lo `test -f 'w32-iconv.c' || echo '$(srcdir)/'`w32-iconv.c + +libgpg_error_la-w32-estream.lo: w32-estream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-w32-estream.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-w32-estream.Tpo -c -o libgpg_error_la-w32-estream.lo `test -f 'w32-estream.c' || echo '$(srcdir)/'`w32-estream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-w32-estream.Tpo $(DEPDIR)/libgpg_error_la-w32-estream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-estream.c' object='libgpg_error_la-w32-estream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-w32-estream.lo `test -f 'w32-estream.c' || echo '$(srcdir)/'`w32-estream.c + +libgpg_error_la-w32-reg.lo: w32-reg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-w32-reg.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-w32-reg.Tpo -c -o libgpg_error_la-w32-reg.lo `test -f 'w32-reg.c' || echo '$(srcdir)/'`w32-reg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-w32-reg.Tpo $(DEPDIR)/libgpg_error_la-w32-reg.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-reg.c' object='libgpg_error_la-w32-reg.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-w32-reg.lo `test -f 'w32-reg.c' || echo '$(srcdir)/'`w32-reg.c + +libgpg_error_la-spawn-w32.lo: spawn-w32.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-spawn-w32.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-spawn-w32.Tpo -c -o libgpg_error_la-spawn-w32.lo `test -f 'spawn-w32.c' || echo '$(srcdir)/'`spawn-w32.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-spawn-w32.Tpo $(DEPDIR)/libgpg_error_la-spawn-w32.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spawn-w32.c' object='libgpg_error_la-spawn-w32.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-spawn-w32.lo `test -f 'spawn-w32.c' || echo '$(srcdir)/'`spawn-w32.c + +libgpg_error_la-init.lo: init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-init.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-init.Tpo -c -o libgpg_error_la-init.lo `test -f 'init.c' || echo '$(srcdir)/'`init.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-init.Tpo $(DEPDIR)/libgpg_error_la-init.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='init.c' object='libgpg_error_la-init.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-init.lo `test -f 'init.c' || echo '$(srcdir)/'`init.c + +libgpg_error_la-version.lo: version.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-version.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-version.Tpo -c -o libgpg_error_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-version.Tpo $(DEPDIR)/libgpg_error_la-version.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='version.c' object='libgpg_error_la-version.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c + +libgpg_error_la-estream.lo: estream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-estream.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-estream.Tpo -c -o libgpg_error_la-estream.lo `test -f 'estream.c' || echo '$(srcdir)/'`estream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-estream.Tpo $(DEPDIR)/libgpg_error_la-estream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='estream.c' object='libgpg_error_la-estream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-estream.lo `test -f 'estream.c' || echo '$(srcdir)/'`estream.c + +libgpg_error_la-estream-printf.lo: estream-printf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-estream-printf.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-estream-printf.Tpo -c -o libgpg_error_la-estream-printf.lo `test -f 'estream-printf.c' || echo '$(srcdir)/'`estream-printf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-estream-printf.Tpo $(DEPDIR)/libgpg_error_la-estream-printf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='estream-printf.c' object='libgpg_error_la-estream-printf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-estream-printf.lo `test -f 'estream-printf.c' || echo '$(srcdir)/'`estream-printf.c + +libgpg_error_la-strsource.lo: strsource.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-strsource.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-strsource.Tpo -c -o libgpg_error_la-strsource.lo `test -f 'strsource.c' || echo '$(srcdir)/'`strsource.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-strsource.Tpo $(DEPDIR)/libgpg_error_la-strsource.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strsource.c' object='libgpg_error_la-strsource.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-strsource.lo `test -f 'strsource.c' || echo '$(srcdir)/'`strsource.c + +libgpg_error_la-strerror.lo: strerror.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-strerror.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-strerror.Tpo -c -o libgpg_error_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-strerror.Tpo $(DEPDIR)/libgpg_error_la-strerror.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strerror.c' object='libgpg_error_la-strerror.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c + +libgpg_error_la-code-to-errno.lo: code-to-errno.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-code-to-errno.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-code-to-errno.Tpo -c -o libgpg_error_la-code-to-errno.lo `test -f 'code-to-errno.c' || echo '$(srcdir)/'`code-to-errno.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-code-to-errno.Tpo $(DEPDIR)/libgpg_error_la-code-to-errno.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='code-to-errno.c' object='libgpg_error_la-code-to-errno.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-code-to-errno.lo `test -f 'code-to-errno.c' || echo '$(srcdir)/'`code-to-errno.c + +libgpg_error_la-code-from-errno.lo: code-from-errno.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-code-from-errno.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-code-from-errno.Tpo -c -o libgpg_error_la-code-from-errno.lo `test -f 'code-from-errno.c' || echo '$(srcdir)/'`code-from-errno.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-code-from-errno.Tpo $(DEPDIR)/libgpg_error_la-code-from-errno.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='code-from-errno.c' object='libgpg_error_la-code-from-errno.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-code-from-errno.lo `test -f 'code-from-errno.c' || echo '$(srcdir)/'`code-from-errno.c + +libgpg_error_la-visibility.lo: visibility.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-visibility.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-visibility.Tpo -c -o libgpg_error_la-visibility.lo `test -f 'visibility.c' || echo '$(srcdir)/'`visibility.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-visibility.Tpo $(DEPDIR)/libgpg_error_la-visibility.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='visibility.c' object='libgpg_error_la-visibility.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-visibility.lo `test -f 'visibility.c' || echo '$(srcdir)/'`visibility.c + +libgpg_error_la-sysutils.lo: sysutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-sysutils.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-sysutils.Tpo -c -o libgpg_error_la-sysutils.lo `test -f 'sysutils.c' || echo '$(srcdir)/'`sysutils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-sysutils.Tpo $(DEPDIR)/libgpg_error_la-sysutils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sysutils.c' object='libgpg_error_la-sysutils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-sysutils.lo `test -f 'sysutils.c' || echo '$(srcdir)/'`sysutils.c + +libgpg_error_la-stringutils.lo: stringutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-stringutils.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-stringutils.Tpo -c -o libgpg_error_la-stringutils.lo `test -f 'stringutils.c' || echo '$(srcdir)/'`stringutils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-stringutils.Tpo $(DEPDIR)/libgpg_error_la-stringutils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringutils.c' object='libgpg_error_la-stringutils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-stringutils.lo `test -f 'stringutils.c' || echo '$(srcdir)/'`stringutils.c + +libgpg_error_la-syscall-clamp.lo: syscall-clamp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-syscall-clamp.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-syscall-clamp.Tpo -c -o libgpg_error_la-syscall-clamp.lo `test -f 'syscall-clamp.c' || echo '$(srcdir)/'`syscall-clamp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-syscall-clamp.Tpo $(DEPDIR)/libgpg_error_la-syscall-clamp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='syscall-clamp.c' object='libgpg_error_la-syscall-clamp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-syscall-clamp.lo `test -f 'syscall-clamp.c' || echo '$(srcdir)/'`syscall-clamp.c + +libgpg_error_la-logging.lo: logging.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-logging.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-logging.Tpo -c -o libgpg_error_la-logging.lo `test -f 'logging.c' || echo '$(srcdir)/'`logging.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-logging.Tpo $(DEPDIR)/libgpg_error_la-logging.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logging.c' object='libgpg_error_la-logging.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-logging.lo `test -f 'logging.c' || echo '$(srcdir)/'`logging.c + +libgpg_error_la-b64dec.lo: b64dec.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-b64dec.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-b64dec.Tpo -c -o libgpg_error_la-b64dec.lo `test -f 'b64dec.c' || echo '$(srcdir)/'`b64dec.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-b64dec.Tpo $(DEPDIR)/libgpg_error_la-b64dec.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64dec.c' object='libgpg_error_la-b64dec.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-b64dec.lo `test -f 'b64dec.c' || echo '$(srcdir)/'`b64dec.c + +libgpg_error_la-b64enc.lo: b64enc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-b64enc.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-b64enc.Tpo -c -o libgpg_error_la-b64enc.lo `test -f 'b64enc.c' || echo '$(srcdir)/'`b64enc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-b64enc.Tpo $(DEPDIR)/libgpg_error_la-b64enc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64enc.c' object='libgpg_error_la-b64enc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-b64enc.lo `test -f 'b64enc.c' || echo '$(srcdir)/'`b64enc.c + +libgpg_error_la-argparse.lo: argparse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgpg_error_la-argparse.lo -MD -MP -MF $(DEPDIR)/libgpg_error_la-argparse.Tpo -c -o libgpg_error_la-argparse.lo `test -f 'argparse.c' || echo '$(srcdir)/'`argparse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgpg_error_la-argparse.Tpo $(DEPDIR)/libgpg_error_la-argparse.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='argparse.c' object='libgpg_error_la-argparse.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgpg_error_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgpg_error_la-argparse.lo `test -f 'argparse.c' || echo '$(srcdir)/'`argparse.c + +gpg_error-strsource-sym.o: strsource-sym.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gpg_error-strsource-sym.o -MD -MP -MF $(DEPDIR)/gpg_error-strsource-sym.Tpo -c -o gpg_error-strsource-sym.o `test -f 'strsource-sym.c' || echo '$(srcdir)/'`strsource-sym.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_error-strsource-sym.Tpo $(DEPDIR)/gpg_error-strsource-sym.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strsource-sym.c' object='gpg_error-strsource-sym.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gpg_error-strsource-sym.o `test -f 'strsource-sym.c' || echo '$(srcdir)/'`strsource-sym.c + +gpg_error-strsource-sym.obj: strsource-sym.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gpg_error-strsource-sym.obj -MD -MP -MF $(DEPDIR)/gpg_error-strsource-sym.Tpo -c -o gpg_error-strsource-sym.obj `if test -f 'strsource-sym.c'; then $(CYGPATH_W) 'strsource-sym.c'; else $(CYGPATH_W) '$(srcdir)/strsource-sym.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_error-strsource-sym.Tpo $(DEPDIR)/gpg_error-strsource-sym.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strsource-sym.c' object='gpg_error-strsource-sym.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gpg_error-strsource-sym.obj `if test -f 'strsource-sym.c'; then $(CYGPATH_W) 'strsource-sym.c'; else $(CYGPATH_W) '$(srcdir)/strsource-sym.c'; fi` + +gpg_error-strerror-sym.o: strerror-sym.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gpg_error-strerror-sym.o -MD -MP -MF $(DEPDIR)/gpg_error-strerror-sym.Tpo -c -o gpg_error-strerror-sym.o `test -f 'strerror-sym.c' || echo '$(srcdir)/'`strerror-sym.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_error-strerror-sym.Tpo $(DEPDIR)/gpg_error-strerror-sym.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strerror-sym.c' object='gpg_error-strerror-sym.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gpg_error-strerror-sym.o `test -f 'strerror-sym.c' || echo '$(srcdir)/'`strerror-sym.c + +gpg_error-strerror-sym.obj: strerror-sym.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gpg_error-strerror-sym.obj -MD -MP -MF $(DEPDIR)/gpg_error-strerror-sym.Tpo -c -o gpg_error-strerror-sym.obj `if test -f 'strerror-sym.c'; then $(CYGPATH_W) 'strerror-sym.c'; else $(CYGPATH_W) '$(srcdir)/strerror-sym.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_error-strerror-sym.Tpo $(DEPDIR)/gpg_error-strerror-sym.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strerror-sym.c' object='gpg_error-strerror-sym.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gpg_error-strerror-sym.obj `if test -f 'strerror-sym.c'; then $(CYGPATH_W) 'strerror-sym.c'; else $(CYGPATH_W) '$(srcdir)/strerror-sym.c'; fi` + +gpg_error-gpg-error.o: gpg-error.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gpg_error-gpg-error.o -MD -MP -MF $(DEPDIR)/gpg_error-gpg-error.Tpo -c -o gpg_error-gpg-error.o `test -f 'gpg-error.c' || echo '$(srcdir)/'`gpg-error.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_error-gpg-error.Tpo $(DEPDIR)/gpg_error-gpg-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gpg-error.c' object='gpg_error-gpg-error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gpg_error-gpg-error.o `test -f 'gpg-error.c' || echo '$(srcdir)/'`gpg-error.c + +gpg_error-gpg-error.obj: gpg-error.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gpg_error-gpg-error.obj -MD -MP -MF $(DEPDIR)/gpg_error-gpg-error.Tpo -c -o gpg_error-gpg-error.obj `if test -f 'gpg-error.c'; then $(CYGPATH_W) 'gpg-error.c'; else $(CYGPATH_W) '$(srcdir)/gpg-error.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpg_error-gpg-error.Tpo $(DEPDIR)/gpg_error-gpg-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gpg-error.c' object='gpg_error-gpg-error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpg_error_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gpg_error-gpg-error.obj `if test -f 'gpg-error.c'; then $(CYGPATH_W) 'gpg-error.c'; else $(CYGPATH_W) '$(srcdir)/gpg-error.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-m4dataDATA: $(m4data_DATA) + @$(NORMAL_INSTALL) + @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(m4datadir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(m4datadir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4datadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(m4datadir)" || exit $$?; \ + done + +uninstall-m4dataDATA: + @$(NORMAL_UNINSTALL) + @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(m4datadir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) +install-nodist_includeHEADERS: $(nodist_include_HEADERS) + @$(NORMAL_INSTALL) + @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-nodist_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) $(DATA) \ + $(HEADERS) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gen-posix-lock-obj.Po + -rm -f ./$(DEPDIR)/gen-w32-lock-obj.Po + -rm -f ./$(DEPDIR)/gpg_error-gpg-error.Po + -rm -f ./$(DEPDIR)/gpg_error-strerror-sym.Po + -rm -f ./$(DEPDIR)/gpg_error-strsource-sym.Po + -rm -f ./$(DEPDIR)/libgpg_error_la-argparse.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-b64dec.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-b64enc.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-code-from-errno.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-code-to-errno.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-estream-printf.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-estream.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-init.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-logging.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-posix-lock.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-posix-thread.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-spawn-posix.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-spawn-w32.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-strerror.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-stringutils.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-strsource.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-syscall-clamp.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-sysutils.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-version.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-visibility.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-estream.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-gettext.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-iconv.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-lock.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-reg.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-thread.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local install-m4dataDATA \ + install-nodist_includeHEADERS install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS \ + install-dist_binSCRIPTS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gen-posix-lock-obj.Po + -rm -f ./$(DEPDIR)/gen-w32-lock-obj.Po + -rm -f ./$(DEPDIR)/gpg_error-gpg-error.Po + -rm -f ./$(DEPDIR)/gpg_error-strerror-sym.Po + -rm -f ./$(DEPDIR)/gpg_error-strsource-sym.Po + -rm -f ./$(DEPDIR)/libgpg_error_la-argparse.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-b64dec.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-b64enc.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-code-from-errno.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-code-to-errno.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-estream-printf.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-estream.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-init.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-logging.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-posix-lock.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-posix-thread.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-spawn-posix.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-spawn-w32.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-strerror.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-stringutils.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-strsource.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-syscall-clamp.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-sysutils.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-version.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-visibility.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-estream.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-gettext.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-iconv.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-lock.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-reg.Plo + -rm -f ./$(DEPDIR)/libgpg_error_la-w32-thread.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-dist_binSCRIPTS uninstall-libLTLIBRARIES \ + uninstall-m4dataDATA uninstall-nodist_includeHEADERS \ + uninstall-pkgconfigDATA + +.MAKE: all check check-am install install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \ + check-am clean clean-binPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-binSCRIPTS install-data \ + install-data-am install-data-local install-dist_binSCRIPTS \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-m4dataDATA install-man \ + install-nodist_includeHEADERS install-pdf install-pdf-am \ + install-pkgconfigDATA install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-binSCRIPTS uninstall-dist_binSCRIPTS \ + uninstall-libLTLIBRARIES uninstall-m4dataDATA \ + uninstall-nodist_includeHEADERS uninstall-pkgconfigDATA + +.PRECIOUS: Makefile + + +@HAVE_W32_SYSTEM_TRUE@.rc.lo: +@HAVE_W32_SYSTEM_TRUE@ $(LTRCCOMPILE) -i "$<" -o "$@" + +@HAVE_W32_SYSTEM_TRUE@versioninfo.lo : gpg-error.w32-manifest + +@HAVE_W32_SYSTEM_TRUE@install-def-file: gpg-error.def +@HAVE_W32_SYSTEM_TRUE@ -$(INSTALL) -d $(DESTDIR)$(libdir) +@HAVE_W32_SYSTEM_TRUE@ $(INSTALL) gpg-error.def $(DESTDIR)$(libdir)/gpg-error.def + +@HAVE_W32_SYSTEM_TRUE@uninstall-def-file: +@HAVE_W32_SYSTEM_TRUE@ -rm $(DESTDIR)$(libdir)/gpg-error.def + +@HAVE_W32_SYSTEM_FALSE@install-def-file: +@HAVE_W32_SYSTEM_FALSE@uninstall-def-file: + +# We build err-sources.h and err-codes.h in the source directory. +# This is needed because gettext does only look into the source +# directory to find the files listed in po/POTFILE.in. To make these +# rules work we also need to depend on Makefile.am and not on the +# generated files Makefile.in or Makefile. +$(srcdir)/err-sources.h: Makefile.am mkstrtable.awk err-sources.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 \ + $(srcdir)/err-sources.h.in >$@ + +err-sources-sym.h: Makefile mkstrtable.awk err-sources.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ + $(srcdir)/err-sources.h.in >$@ + +$(srcdir)/err-codes.h: Makefile.am mkstrtable.awk err-codes.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 \ + $(srcdir)/err-codes.h.in >$@ + +err-codes-sym.h: Makefile mkstrtable.awk err-codes.h.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ + $(srcdir)/err-codes.h.in >$@ + +code-to-errno.h: Makefile mkerrnos.awk errnos.in + $(AWK) -f $(srcdir)/mkerrnos.awk $(srcdir)/errnos.in >$@ + +# It is correct to use $(CPP). We want the host's idea of the error codes. +mkerrcodes.h: Makefile mkerrcodes.awk $(gpg_extra_headers) + $(AWK) -f $(srcdir)/mkerrcodes1.awk $(srcdir)/errnos.in >_$@ + $(CPP) $(CPPFLAGS) $(extra_cppflags) -P _$@ | grep GPG_ERR_ | \ + $(AWK) -f $(srcdir)/mkerrcodes.awk >$@ + -rm _$@ + +# It is correct to use $(CPP). We want the host's idea of the error codes. +@HAVE_W32CE_SYSTEM_TRUE@mkw32errmap.tab.h: Makefile mkw32errmap.c +@HAVE_W32CE_SYSTEM_TRUE@ $(CPP) -DRESOLVE_MACROS $(srcdir)/mkw32errmap.c | \ +@HAVE_W32CE_SYSTEM_TRUE@ grep '{&mkw32errmap_marker' >$@ +@HAVE_W32CE_SYSTEM_TRUE@mkw32errmap.map.c: mkw32errmap$(EXEEXT_FOR_BUILD) +@HAVE_W32CE_SYSTEM_TRUE@ ./mkw32errmap$(EXEEXT_FOR_BUILD) --map > $@ +@HAVE_W32CE_SYSTEM_TRUE@gpg-extra/errno.h: mkw32errmap$(EXEEXT_FOR_BUILD) +@HAVE_W32CE_SYSTEM_TRUE@ -$(MKDIR_P) gpg-extra +@HAVE_W32CE_SYSTEM_TRUE@ ./mkw32errmap$(EXEEXT_FOR_BUILD) > $@ +@HAVE_W32CE_SYSTEM_FALSE@mkw32errmap.map.c: +@HAVE_W32CE_SYSTEM_FALSE@ echo "/*dummy*/" > $@ + +# We use CC proper for preprocessing thus we have to convince it that +# the data is really to be preprocessed. +gpg-error.def: Makefile gpg-error.def.in + cat $(srcdir)/gpg-error.def.in >_$@.h + $(CPP) $(DEFAULT_INCLUDES) $(INCLUDES) $(extra_cppflags) _$@.h | \ + grep -v '^#' >$@ + -rm _$@.h + +# It is correct to use $(CC_FOR_BUILD) here. We want to run the +# program at build time. +mkerrcodes$(EXEEXT_FOR_BUILD): mkerrcodes.c mkerrcodes.h Makefile + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkerrcodes.c + +# It is correct to use $(CC_FOR_BUILD) here. We want to run the +# program at build time. +@HAVE_W32CE_SYSTEM_TRUE@mkw32errmap$(EXEEXT_FOR_BUILD): mkw32errmap.c mkw32errmap.tab.h Makefile +@HAVE_W32CE_SYSTEM_TRUE@ $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ +@HAVE_W32CE_SYSTEM_TRUE@ $(CPPFLAGS_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkw32errmap.c + +code-from-errno.h: mkerrcodes$(EXEEXT_FOR_BUILD) Makefile + ./mkerrcodes$(EXEEXT_FOR_BUILD) | $(AWK) -f $(srcdir)/mkerrcodes2.awk >$@ + +errnos-sym.h: Makefile mkstrtable.awk errnos.in + $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ + -v prefix=GPG_ERR_ -v pkg_namespace=errnos_ \ + $(srcdir)/errnos.in >$@ + +mkheader$(EXEEXT_FOR_BUILD): mkheader.c Makefile + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \ + $(CPPFLAGS_FOR_BUILD) -g -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c + +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_FALSE@./lock-obj-pub.native.h: Makefile gen-posix-lock-obj$(EXEEXT) posix-lock-obj.h +@FORCE_USE_SYSCFG_FALSE@@HAVE_GENERATED_LOCK_OBJ_H_FALSE@ ./gen-posix-lock-obj >$@ + +# We also depend on versioninfo.rc because that is build by +# config.status and thus has up-to-date version numbers. +gpg-error.h: Makefile mkheader$(EXEEXT_FOR_BUILD) $(parts_of_gpg_error_h) \ + versioninfo.rc ../config.h + $(pre_mkheader_cmds) + ./mkheader$(EXEEXT_FOR_BUILD) $(mkheader_opts) \ + $(host_triplet) $(srcdir)/gpg-error.h.in \ + ../config.h $(PACKAGE_VERSION) $(VERSION_NUMBER) >$@ + +gpgrt.h: gpg-error.h + cp gpg-error.h gpgrt.h + +gpg-error-config: gpgrt-config gpg-error-config-old + @echo $(ECHO_N) "Confirm gpg-error-config works... $(ECHO_C)" + @if ./gpg-error-config-test.sh --old-new; then \ + echo "good"; \ + else \ + echo "no"; \ + echo "*** Please report to with gpg-error-config-test.log"; \ + exit 1; \ + fi + cp gpg-error-config-old $@ + +install-data-local: +@HAVE_W32CE_SYSTEM_TRUE@ -$(MKDIR_P) "$(DESTDIR)$(includedir)/gpg-extra" +@HAVE_W32CE_SYSTEM_TRUE@ $(INSTALL_DATA) gpg-extra/errno.h \ +@HAVE_W32CE_SYSTEM_TRUE@ "$(DESTDIR)$(includedir)/gpg-extra/errno.h" +@HAVE_W32CE_SYSTEM_FALSE@ : + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgpg-error/src/README b/comm/third_party/libgpg-error/src/README new file mode 100644 index 0000000000..c415983598 --- /dev/null +++ b/comm/third_party/libgpg-error/src/README @@ -0,0 +1,47 @@ +Notes on the source code +======================== + +The mechanism to generate the system error codes is delicate and +fragile, but it's the best I could come up with that supports +cross-compilation and dynamic self-configuration. Here is how it +works: + +1. Generate list of supported system error codes. + +mkerrcodes1.awk generates a list of supported system error codes from +errnos.in. Each entry in the list is protected with #ifdef/#endif, +and contains a GPG_ERR_* marker. The list is stored in "_mkerrcodes.h". + +2. The HOST cpp is run on _mkerrcodes.h. This evaluates the known +system error macros to something (may be a number, maybe a constant +expression as on the GNU/Hurd), suppressing the unknown ones. The +output is piped into step 3. + +3. The cpp output is filtered with grep for only those lines which +contain a GPG_ERR_* marker. The output is piped into step 4. + +4. The filtered output is processed by mkerrcodes.awk, which produces +a table of constant expressions plus GPG_ERR_* code string symbols in +a format suitable for the C program mkerrcodes.c. At this point we +are crossing our fingers that the constant expressions produced by the +system do not contain GPG_ERR_* markers. The output is stored in +mkerrcodes.h. + +5. The file mkerrcodes.h is included by mkerrcodes.c, which is +compiled to a binary executable on the BUILD system. At this point we +are crossing our fingers that the constant expressions produced by the +system do not depend on the build platform anymore. The output is +post-processed by mkerrcodes2.awk and stored in "code-from-errno.h", +which is subsequently used in the library. + +-- Marcus + + Copyright 2006 g10 Code GmbH + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/comm/third_party/libgpg-error/src/argparse.c b/comm/third_party/libgpg-error/src/argparse.c new file mode 100644 index 0000000000..cb5c58ce4c --- /dev/null +++ b/comm/third_party/libgpg-error/src/argparse.c @@ -0,0 +1,2852 @@ +/* argparse.c - Argument Parser for option handling + * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 2015-2020 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This file was originally a part of GnuPG. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpgrt-int.h" + +#ifdef HAVE_W32_SYSTEM +# define PATHSEP_C ';' +# define DIRSEP_C '\\' +#else +# define PATHSEP_C ':' +# define DIRSEP_C '/' +#endif + + +/* The malloced configuration directories or NULL. */ +static struct +{ + char *user; + char *sys; +} confdir; + + +/* Hidden argparse flag used to mark the object as initialized. */ +#define ARGPARSE_FLAG__INITIALIZED (1u << ((8*SIZEOF_INT)-1)) + +/* Special short options which are auto-inserterd. Must fit into an + * unsigned short. */ +#define ARGPARSE_SHORTOPT_HELP 32768 +#define ARGPARSE_SHORTOPT_VERSION 32769 +#define ARGPARSE_SHORTOPT_WARRANTY 32770 +#define ARGPARSE_SHORTOPT_DUMP_OPTIONS 32771 +#define ARGPARSE_SHORTOPT_DUMP_OPTTBL 32772 + + +/* The states for the gpgrt_argparser machinery. */ +enum argparser_states + { + STATE_init = 0, + STATE_open_sys, + STATE_open_user, + STATE_open_cmdline, + STATE_read_sys, + STATE_read_user, + STATE_read_cmdline, + STATE_finished + }; + + +/* An internal object used to store the user provided option table and + * some meta information. */ +typedef struct +{ + unsigned short short_opt; + unsigned short ordinal; /* (for --help) */ + unsigned int flags; + const char *long_opt; /* Points into the user provided table. */ + const char *description; /* Points into the user provided table. */ + unsigned int forced:1; /* Forced to use the sysconf value. */ + unsigned int ignore:1; /* Ignore this option everywhere but in + * the sysconf file. */ + unsigned int explicit_ignore:1; /* Ignore was explicitly set. */ +} opttable_t; + + +/* Internal object of the public gpgrt_argparse_t object. */ +struct _gpgrt_argparse_internal_s +{ + int idx; /* Note that this is saved and restored in _gpgrt_argparser. */ + int inarg; /* (index into args) */ + unsigned int verbose:1; /* Print diagnostics. */ + unsigned int stopped:1; /* Option processing has stopped. */ + unsigned int in_sysconf:1; /* Processing global config file. */ + unsigned int mark_forced:1; /* Mark options as forced. */ + unsigned int mark_ignore:1; /* Mark options as to be ignored. */ + unsigned int explicit_ignore:1; /* Option has explicitly been set + * to ignore or unignore. */ + unsigned int ignore_all_seen:1; /* [ignore-all] has been seen. */ + unsigned int user_seen:1; /* A [user] has been seen. */ + unsigned int user_wildcard:1; /* A [user *] has been seen. */ + unsigned int user_any_active:1; /* Any user section was active. */ + unsigned int user_active:1; /* User section active. */ + unsigned int explicit_confopt:1; /* A conffile option has been given. */ + char *explicit_conffile; /* Malloced name of an explicit + * conffile. */ + char *username; /* Malloced current user name. */ + unsigned int opt_flags; /* Current option flags. */ + enum argparser_states state; /* State of the gpgrt_argparser. */ + const char *last; + void *aliases; + const void *cur_alias; + void *iio_list; + estream_t conffp; + char *confname; + opttable_t *opts; /* Malloced option table. */ + unsigned int nopts; /* Number of items in OPTS. */ +}; + + +typedef struct alias_def_s *ALIAS_DEF; +struct alias_def_s { + ALIAS_DEF next; + char *name; /* malloced buffer with name, \0, value */ + const char *value; /* ptr into name */ +}; + + +/* Object to store the names for the --ignore-invalid-option option. + This is a simple linked list. */ +typedef struct iio_item_def_s *IIO_ITEM_DEF; +struct iio_item_def_s +{ + IIO_ITEM_DEF next; + char name[1]; /* String with the long option name. */ +}; + + +/* The almost always needed user handler for strusage. */ +static const char *(*strusage_handler)( int ) = NULL; +/* Optional handler to write strings. See _gpgrt_set_usage_outfnc. */ +static int (*custom_outfnc) (int, const char *); +/* Optional handler to map strings. See _gpgrt_set_fixed_string_mapper. */ +static const char *(*fixed_string_mapper)(const char*); + +static int set_opt_arg (gpgrt_argparse_t *arg, unsigned int flags, char *s); +static void show_help (opttable_t *opts, unsigned int nopts,unsigned int flags); +static void show_version (void); +static void dump_option_table (gpgrt_argparse_t *arg); +static int writestrings (int is_error, const char *string, + ...) GPGRT_ATTR_SENTINEL(0); +static int arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, int no_init); + + + + + +/* Return true if the native charset is utf-8. */ +static int +is_native_utf8 (void) +{ + static char result; + + if (!result) + { + const char *p = _gpgrt_strusage (8); + if (!p || !*p || !strcmp (p, "utf-8")) + result = 1; + result |= 128; + } + + return (result & 1); +} + + +static char * +trim_spaces (char *str) +{ + char *string, *p, *mark; + + string = str; + /* Find first non space character. */ + for (p=string; *p && isspace (*(unsigned char*)p) ; p++) + ; + /* Move characters. */ + for ((mark = NULL); (*string = *p); string++, p++) + if (isspace (*(unsigned char*)p)) + { + if (!mark) + mark = string; + } + else + mark = NULL; + if (mark) + *mark = '\0' ; /* Remove trailing spaces. */ + + return str ; +} + + +static const char * +map_fixed_string (const char *string) +{ + return fixed_string_mapper? fixed_string_mapper (string) : string; +} + + +/* Write STRING and all following const char * arguments either to + stdout or, if IS_ERROR is set, to stderr. The list of strings must + be terminated by a NULL. */ +static int +writestrings (int is_error, const char *string, ...) +{ + va_list arg_ptr; + const char *s; + int count = 0; + + if (string) + { + s = string; + va_start (arg_ptr, string); + do + { + if (custom_outfnc) + custom_outfnc (is_error? 2:1, s); + else + _gpgrt_fputs (s, is_error? es_stderr : es_stdout); + count += strlen (s); + } + while ((s = va_arg (arg_ptr, const char *))); + va_end (arg_ptr); + } + return count; +} + + +static void +flushstrings (int is_error) +{ + if (custom_outfnc) + custom_outfnc (is_error? 2:1, NULL); + else + _gpgrt_fflush (is_error? es_stderr : es_stdout); +} + + +static void +deinitialize (gpgrt_argparse_t *arg) +{ + if (arg->internal) + { + xfree (arg->internal->username); + xfree (arg->internal->explicit_conffile); + xfree (arg->internal->opts); + xfree (arg->internal); + arg->internal = NULL; + } + + arg->flags &= ARGPARSE_FLAG__INITIALIZED; + arg->lineno = 0; + arg->err = 0; +} + +/* Our own exit handler to clean up used memory. */ +static void +my_exit (gpgrt_argparse_t *arg, int code) +{ + deinitialize (arg); + exit (code); +} + + +static gpg_err_code_t +initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) +{ + /* We use a dedicated flag to detect whether *ARG has been + * initialized. This is because the old version of that struct, as + * used in GnuPG, had no requirement to zero out all fields of the + * object and existing code still sets only argc,argv and flags. */ + if (!(arg->flags & ARGPARSE_FLAG__INITIALIZED) + || (arg->flags & ARGPARSE_FLAG_RESET) + || !arg->internal) + { + /* Allocate internal data. */ + if (!(arg->flags & ARGPARSE_FLAG__INITIALIZED) || !arg->internal) + { + arg->internal = xtrymalloc (sizeof *arg->internal); + if (!arg->internal) + return _gpg_err_code_from_syserror (); + arg->flags |= ARGPARSE_FLAG__INITIALIZED; /* Mark as initialized. */ + } + else if (arg->internal->opts) + xfree (arg->internal->opts); + arg->internal->opts = NULL; + arg->internal->nopts = 0; + + /* Initialize this instance. */ + arg->internal->idx = 0; + arg->internal->last = NULL; + arg->internal->inarg = 0; + arg->internal->stopped = 0; + arg->internal->in_sysconf = 0; + arg->internal->user_seen = 0; + arg->internal->user_wildcard = 0; + arg->internal->user_any_active = 0; + arg->internal->user_active = 0; + arg->internal->username = NULL; + arg->internal->mark_forced = 0; + arg->internal->mark_ignore = 0; + arg->internal->explicit_ignore = 0; + arg->internal->ignore_all_seen = 0; + arg->internal->explicit_confopt = 0; + arg->internal->explicit_conffile = NULL; + arg->internal->opt_flags = 0; + arg->internal->state = STATE_init; + arg->internal->aliases = NULL; + arg->internal->cur_alias = NULL; + arg->internal->iio_list = NULL; + arg->internal->conffp = NULL; + arg->internal->confname = NULL; + + /* Clear the copy of the option list. */ + /* Clear the error indicator. */ + arg->err = 0; + + /* Usually an option file will be parsed from the start. + * However, we do not open the stream and thus we have no way to + * know the current lineno. Using this flag we can allow the + * user to provide a lineno which we don't reset. */ + if (fp || arg->internal->conffp || !(arg->flags & ARGPARSE_FLAG_NOLINENO)) + arg->lineno = 0; + + /* Need to clear the reset request. */ + arg->flags &= ~ARGPARSE_FLAG_RESET; + + /* Check initial args. */ + if ( *arg->argc < 0 ) + _gpgrt_log_bug ("invalid argument passed to gpgrt_argparse\n"); + + } + + /* Create an array with pointers to the provided list of options. + * Keeping a copy is useful to sort that array and thus do a binary + * search and to allow for extra space at the end to insert the + * hidden options. An ARGPARSE_FLAG_RESET can be used to reinit + * this array. */ + if (!arg->internal->opts) + { + int seen_help = 0; + int seen_version = 0; + int seen_warranty = 0; + int seen_dump_options = 0; + int seen_dump_option_table = 0; + int i; + + for (i=0; opts[i].short_opt; i++) + { + if (opts[i].long_opt) + { + if (!strcmp(opts[i].long_opt, "help")) + seen_help = 1; + else if (!strcmp(opts[i].long_opt, "version")) + seen_version = 1; + else if (!strcmp(opts[i].long_opt, "warranty")) + seen_warranty = 1; + else if (!strcmp(opts[i].long_opt, "dump-options")) + seen_dump_options = 1; + else if (!strcmp(opts[i].long_opt, "dump-option-table")) + seen_dump_option_table = 1; + } + } + i += 5; /* The number of the above internal options. */ + i++; /* End of list marker. */ + arg->internal->opts = xtrycalloc (i, sizeof *arg->internal->opts); + if (!arg->internal->opts) + return _gpg_err_code_from_syserror (); + for(i=0; opts[i].short_opt; i++) + { + arg->internal->opts[i].short_opt = opts[i].short_opt; + arg->internal->opts[i].flags = opts[i].flags; + arg->internal->opts[i].long_opt = opts[i].long_opt; + arg->internal->opts[i].description = opts[i].description; + arg->internal->opts[i].ordinal = i; + } + + if (!seen_help) + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_HELP; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "help"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + if (!seen_version) + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_VERSION; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "version"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + + if (!seen_warranty) + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_WARRANTY; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "warranty"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + + if (!seen_dump_option_table) + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTTBL; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "dump-option-table"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + + if (!seen_dump_options) + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTIONS; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "dump-options"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + /* Take care: When adding new options remember to increase the + * size of the array. */ + + arg->internal->opts[i].short_opt = 0; + + /* Note that we do not count the end marker but keep it in the + * table anyway as an extra item. */ + arg->internal->nopts = i; + } + + if (arg->err) + { + /* Last option was erroneous. */ + const char *s; + + if (!fp && arg->internal->conffp) + fp = arg->internal->conffp; + + if (fp) + { + if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG ) + s = _("argument not expected"); + else if ( arg->r_opt == ARGPARSE_READ_ERROR ) + s = _("read error"); + else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG ) + s = _("keyword too long"); + else if ( arg->r_opt == ARGPARSE_MISSING_ARG ) + s = _("missing argument"); + else if ( arg->r_opt == ARGPARSE_INVALID_ARG ) + s = _("invalid argument"); + else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND ) + s = _("invalid command"); + else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS ) + s = _("invalid alias definition"); + else if ( arg->r_opt == ARGPARSE_PERMISSION_ERROR ) + s = _("permission error"); + else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE ) + s = _("out of core"); + else if ( arg->r_opt == ARGPARSE_NO_CONFFILE ) + s = NULL; /* Error has already been printed. */ + else if ( arg->r_opt == ARGPARSE_INVALID_META ) + s = _("invalid meta command"); + else if ( arg->r_opt == ARGPARSE_UNKNOWN_META ) + s = _("unknown meta command"); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_META ) + s = _("unexpected meta command"); + else + s = _("invalid option"); + if (s) + _gpgrt_log_error ("%s:%u: %s\n", + _gpgrt_fname_get (fp), arg->lineno, s); + } + else + { + s = arg->internal->last? arg->internal->last:"[??]"; + + if ( arg->r_opt == ARGPARSE_MISSING_ARG ) + _gpgrt_log_error (_("missing argument for option \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_INVALID_ARG ) + _gpgrt_log_error (_("invalid argument for option \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG ) + _gpgrt_log_error (_("option \"%.50s\" does not expect " + "an argument\n"), s); + else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND ) + _gpgrt_log_error (_("invalid command \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION ) + _gpgrt_log_error (_("option \"%.50s\" is ambiguous\n"), s); + else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND ) + _gpgrt_log_error (_("command \"%.50s\" is ambiguous\n"),s ); + else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE ) + _gpgrt_log_error ("%s\n", _("out of core")); + else if ( arg->r_opt == ARGPARSE_PERMISSION_ERROR ) + _gpgrt_log_error ("%s\n", _("permission error")); + else if ( arg->r_opt == ARGPARSE_NO_CONFFILE) + ; /* Error has already been printed. */ + else if ( arg->r_opt == ARGPARSE_INVALID_META ) + _gpgrt_log_error ("%s\n", _("invalid meta command")); + else if ( arg->r_opt == ARGPARSE_UNKNOWN_META ) + _gpgrt_log_error ("%s\n", _("unknown meta command")); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_META ) + _gpgrt_log_error ("%s\n",_("unexpected meta command")); + else + _gpgrt_log_error (_("invalid option \"%.50s\"\n"), s); + } + if (arg->err != ARGPARSE_PRINT_WARNING) + my_exit (arg, 2); + arg->err = 0; + } + + /* Zero out the return value union. */ + arg->r.ret_str = NULL; + arg->r.ret_long = 0; + + return 0; +} + + +static void +store_alias( gpgrt_argparse_t *arg, char *name, char *value ) +{ + /* TODO: replace this dummy function with a rea one + * and fix the probelms IRIX has with (ALIAS_DEV)arg.. + * used as lvalue + */ + (void)arg; + (void)name; + (void)value; +#if 0 + ALIAS_DEF a = xmalloc( sizeof *a ); + a->name = name; + a->value = value; + a->next = (ALIAS_DEF)arg->internal->aliases; + (ALIAS_DEF)arg->internal->aliases = a; +#endif +} + + +/* Return true if KEYWORD is in the ignore-invalid-option list. */ +static int +ignore_invalid_option_p (gpgrt_argparse_t *arg, const char *keyword) +{ + IIO_ITEM_DEF item = arg->internal->iio_list; + + for (; item; item = item->next) + if (!strcmp (item->name, keyword)) + return 1; + return 0; +} + + +/* Add the keywords up to the next LF to the list of to be ignored + options. After returning FP will either be at EOF or the next + character read wll be the first of a new line. The function + returns 0 on success or true on malloc failure. */ +static int +ignore_invalid_option_add (gpgrt_argparse_t *arg, estream_t fp) +{ + IIO_ITEM_DEF item; + int c; + char name[100]; + int namelen = 0; + int ready = 0; + enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS; + + while (!ready) + { + c = _gpgrt_fgetc (fp); + if (c == '\n') + ready = 1; + else if (c == EOF) + { + c = '\n'; + ready = 1; + } + again: + switch (state) + { + case skipWS: + if (!isascii (c) || !isspace(c)) + { + namelen = 0; + state = collectNAME; + goto again; + } + break; + + case collectNAME: + if (isspace (c)) + { + state = addNAME; + goto again; + } + else if (namelen < DIM(name)-1) + name[namelen++] = c; + else /* Too long. */ + state = skipNAME; + break; + + case skipNAME: + if (isspace (c)) + { + state = skipWS; + goto again; + } + break; + + case addNAME: + name[namelen] = 0; + if (!ignore_invalid_option_p (arg, name)) + { + item = xtrymalloc (sizeof *item + namelen); + if (!item) + return 1; + strcpy (item->name, name); + item->next = (IIO_ITEM_DEF)arg->internal->iio_list; + arg->internal->iio_list = item; + } + state = skipWS; + goto again; + } + } + return 0; +} + + +/* Clear the entire ignore-invalid-option list. */ +static void +ignore_invalid_option_clear (gpgrt_argparse_t *arg) +{ + IIO_ITEM_DEF item, tmpitem; + + for (item = arg->internal->iio_list; item; item = tmpitem) + { + tmpitem = item->next; + xfree (item); + } + arg->internal->iio_list = NULL; +} + + +/* Make sure the username field is filled. Return 0 on success. */ +static int +assure_username (gpgrt_argparse_t *arg) +{ + if (!arg->internal->username) + { + arg->internal->username = _gpgrt_getusername (); + if (!arg->internal->username) + { + _gpgrt_log_error ("%s:%u: error getting current user's name: %s\n", + arg->internal->confname, arg->lineno, + _gpg_strerror (gpg_error_from_syserror ())); + /* Not necessary the correct error code but given that we + * either have a malloc error or some internal system error, + * it is the best we can do. */ + return ARGPARSE_PERMISSION_ERROR; + } + } + return 0; +} + + +/* Implementation of the "user" command. ARG is the context. ARGS is + * a non-empty string which this function is allowed to modify. */ +static int +handle_meta_user (gpgrt_argparse_t *arg, unsigned int alternate, char *args) +{ + int rc; + + (void)alternate; + + rc = assure_username (arg); + if (rc) + return rc; + + arg->internal->user_seen = 1; + if (*args == '*' && !args[1]) + { + arg->internal->user_wildcard = 1; + arg->internal->user_active = !arg->internal->user_any_active; + } + else if (arg->internal->user_wildcard) + { + /* All other user statements are ignored after a wildcard. */ + arg->internal->user_active = 0; + } + else if (!strcasecmp (args, arg->internal->username)) + { + arg->internal->user_any_active = 1; + arg->internal->user_active = 1; + } + else + { + arg->internal->user_active = 0; + } + + return 0; +} + + +/* Implementation of the "force" command. ARG is the context. A + * value of 0 for ALTERNATE is "force", a value of 1 requests an + * unforce". ARGS is the empty string and not used. */ +static int +handle_meta_force (gpgrt_argparse_t *arg, unsigned int alternate, char *args) +{ + (void)args; + + arg->internal->mark_forced = alternate? 0 : 1; + + return 0; +} + + +/* Implementation of the "ignore" command. ARG is the context. A + * value of 0 for ALTERNATE is a plain "ignore", a value of 1 request + * an "unignore, a value of 2 requests an "ignore-all". ARGS is the + * empty string and not used. */ +static int +handle_meta_ignore (gpgrt_argparse_t *arg, unsigned int alternate, char *args) +{ + (void)args; + + if (!alternate) + { + arg->internal->mark_ignore = 1; + arg->internal->explicit_ignore = 1; + } + else if (alternate == 1) + { + arg->internal->mark_ignore = 0; + arg->internal->explicit_ignore = 1; + } + else + arg->internal->ignore_all_seen = 1; + + return 0; +} + + +/* Implementation of the "echo" command. ARG is the context. If + * ALTERNATE is true the filename is not printed. ARGS is the string + * to log. */ +static int +handle_meta_echo (gpgrt_argparse_t *arg, unsigned int alternate, char *args) +{ + int rc = 0; + char *p, *pend; + + if (alternate) + _gpgrt_log_info ("%s", ""); + else + _gpgrt_log_info ("%s:%u: ", arg->internal->confname, arg->lineno); + + while (*args) + { + p = strchr (args, '$'); + if (!p) + { + _gpgrt_log_printf ("%s", args); + break; + } + *p = 0; + _gpgrt_log_printf ("%s", args); + if (p[1] == '$') + { + _gpgrt_log_printf ("$"); + args = p+2; + continue; + } + if (p[1] != '{') + { + _gpgrt_log_printf ("$"); + args = p+1; + continue; + } + pend = strchr (p+2, '}'); + if (!pend) /* No closing brace. */ + { + _gpgrt_log_printf ("$"); + args = p+1; + continue; + } + p += 2; + *pend = 0; + args = pend+1; + if (!strcmp (p, "user")) + { + rc = assure_username (arg); + if (rc) + goto leave; + _gpgrt_log_printf ("%s", arg->internal->username); + } + else if (!strcmp (p, "file")) + _gpgrt_log_printf ("%s", arg->internal->confname); + else if (!strcmp (p, "line")) + _gpgrt_log_printf ("%u", arg->lineno); + else if (!strcmp (p, "epoch")) + _gpgrt_log_printf ("%lu", (unsigned long)time (NULL)); + } + + leave: + _gpgrt_log_printf ("\n"); + return rc; +} + + +/* Implementation of the "verbose" command. ARG is the context. If + * ALTERNATE is true the verbosity is disabled. ARGS is not used. */ +static int +handle_meta_verbose (gpgrt_argparse_t *arg, unsigned int alternate, char *args) +{ + (void)args; + + if (alternate) + arg->internal->verbose = 0; + else + arg->internal->verbose = 1; + return 0; +} + +/* Handle a meta command. KEYWORD has the content inside the brackets + * with leading and trailing spaces removed. The function may modify + * KEYWORD. On success 0 is returned, on error an ARGPARSE_ error + * code is returned. */ +static int +handle_metacmd (gpgrt_argparse_t *arg, char *keyword) +{ + static struct { + const char *name; /* Name of the command. */ + unsigned short alternate; /* Use alternate version of the command. */ + unsigned short needarg:1; /* Command requires an argument. */ + unsigned short always:1; /* Command allowed in all conf files. */ + unsigned short noskip:1; /* Even done in non-active [user] mode. */ + int (*func)(gpgrt_argparse_t *arg, + unsigned int alternate, char *args); /*handler*/ + } cmds[] = + {{ "user", 0, 1, 0, 1, handle_meta_user }, + { "force", 0, 0, 0, 0, handle_meta_force }, + { "+force", 0, 0, 0, 0, handle_meta_force }, + { "-force", 1, 0, 0, 0, handle_meta_force }, + { "ignore", 0, 0, 0, 0, handle_meta_ignore }, + { "+ignore", 0, 0, 0, 0, handle_meta_ignore }, + { "-ignore", 1, 0, 0, 0, handle_meta_ignore }, + { "ignore-all", 2, 0, 0, 0, handle_meta_ignore }, + { "+ignore-all", 2, 0, 0, 0, handle_meta_ignore }, + { "verbose", 0, 0, 1, 1, handle_meta_verbose }, + { "+verbose", 0, 0, 1, 1, handle_meta_verbose }, + { "-verbose", 1, 0, 1, 1, handle_meta_verbose }, + { "echo", 0, 1, 1, 1, handle_meta_echo }, + { "-echo", 1, 1, 1, 1, handle_meta_echo }, + { "info", 0, 1, 1, 0, handle_meta_echo }, + { "-info", 1, 1, 1, 0, handle_meta_echo } + }; + char *rest; + int i; + + for (rest = keyword; *rest && !(isascii (*rest) && isspace (*rest)); rest++) + ; + if (*rest) + { + *rest++ = 0; + trim_spaces (rest); + } + + for (i=0; i < DIM (cmds); i++) + if (!strcmp (cmds[i].name, keyword)) + break; + if (!(i < DIM (cmds))) + return ARGPARSE_UNKNOWN_META; + if (cmds[i].needarg && !*rest) + return ARGPARSE_MISSING_ARG; + if (!cmds[i].needarg && *rest) + return ARGPARSE_UNEXPECTED_ARG; + if (!arg->internal->in_sysconf && !cmds[i].always) + return ARGPARSE_UNEXPECTED_META; + + if (!cmds[i].noskip + && arg->internal->in_sysconf + && arg->internal->user_seen + && !arg->internal->user_active) + return 0; /* Skip this meta command. */ + + return cmds[i].func (arg, cmds[i].alternate, rest); +} + + +/* Helper for _gpgrt_argparse. */ +static void +prepare_arg_return (gpgrt_argparse_t *arg, opttable_t *opts, + int idx, int in_alias, int set_ignore) +{ + /* No argument found at the end of the line. */ + if (in_alias) + arg->r_opt = ARGPARSE_MISSING_ARG; + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_type = ARGPARSE_TYPE_NONE; /* Does not take an arg. */ + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) + arg->r_type = ARGPARSE_TYPE_NONE; /* No optional argument. */ + else if (!(opts[idx].ignore && !opts[idx].forced) && !set_ignore) + arg->r_opt = ARGPARSE_MISSING_ARG; + + /* If the caller wants us to return the attributes or + * ignored options, or these flags in. */ + if ((arg->flags & ARGPARSE_FLAG_WITHATTR)) + { + if (opts[idx].ignore) + arg->r_type |= ARGPARSE_ATTR_IGNORE; + if (opts[idx].forced) + arg->r_type |= ARGPARSE_ATTR_FORCE; + if (set_ignore) + arg->r_type |= ARGPARSE_OPT_IGNORE; + } +} + +/**************** + * Get options from a file. + * Lines starting with '#' are comment lines. + * Syntax is simply a keyword and the argument. + * Valid keywords are all keywords from the long_opt list without + * the leading dashes. The special keywords "help", "warranty" and "version" + * are not valid here. + * The special keyword "alias" may be used to store alias definitions, + * which are later expanded like long options. + * The option + * ignore-invalid-option OPTIONNAMEs + * is recognized and updates a list of option which should be ignored if they + * are not defined. + * Caller must free returned strings. + * If called with FP set to NULL command line args are parse instead. + * + * Q: Should we allow the syntax + * keyword = value + * and accept for boolean options a value of 1/0, yes/no or true/false? + * Note: Abbreviation of options is here not allowed. + */ +int +_gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) +{ + enum { Ainit, + Acomment, /* In a comment line. */ + Acopykeyword, /* Collecting a keyword. */ + Awaitarg, /* Wait for an argument. */ + Acopyarg, /* Copy the argument. */ + Akeyword_eol, /* Got keyword at end of line. */ + Akeyword_spc, /* Got keyword at space. */ + Acopymetacmd, /* Copy a meta command. */ + Askipmetacmd, /* Skip spaces after metacmd. */ + Askipmetacmd2,/* Skip comment after metacmd. */ + Ametacmd, /* Process the metacmd. */ + Askipandleave /* Skip the rest of the line and then leave. */ + } state; + opttable_t *opts; + unsigned int nopts; + int i, c; + int idx = 0; + char keyword[100]; + char *buffer = NULL; + size_t buflen = 0; + int in_alias=0; + int set_ignore = 0; + int unread_buf[3]; /* We use an int so that we can store EOF. */ + int unread_buf_count = 0; + + if (arg && !opts_orig) + { + deinitialize (arg); + return 0; + } + + if (!fp) /* Divert to arg_parse() in this case. */ + return arg_parse (arg, opts_orig, 0); + + if (initialize (arg, opts_orig, fp)) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + + opts = arg->internal->opts; + nopts = arg->internal->nopts; + + /* If the LINENO is zero we assume that we are at the start of a + * file and we skip over a possible Byte Order Mark. */ + if (!arg->lineno) + { + unread_buf[0] = _gpgrt_fgetc (fp); + unread_buf[1] = _gpgrt_fgetc (fp); + unread_buf[2] = _gpgrt_fgetc (fp); + if (unread_buf[0] != 0xef + || unread_buf[1] != 0xbb + || unread_buf[2] != 0xbf) + unread_buf_count = 3; + } + + arg->internal->opt_flags = 0; + + /* Find the next keyword. */ + state = Ainit; + i = 0; + for (;;) + { + nextstate: + /* Before scanning the next char handle the keyword seen states. */ + if (state == Akeyword_eol || state == Akeyword_spc) + { + /* We are either at the end of a line or right after a + * keyword. In the latter case we need to find the keyword + * so that we can decide whether an argument is required. */ + + /* Check the keyword. */ + for (idx=0; idx < nopts; idx++ ) + { + if (opts[idx].long_opt && !strcmp (opts[idx].long_opt, keyword)) + break; + } + arg->r_opt = opts[idx].short_opt; + if (!(idx < nopts)) + { + /* The option (keyword) is not known - check for + * internal keywords before returning an error. */ + if (state == Akeyword_spc && !strcmp (keyword, "alias")) + { + in_alias = 1; + state = Awaitarg; + } + else if (!strcmp (keyword, "ignore-invalid-option")) + { + /* We might have keywords as argument - add them to + * the list of ignored keywords. Note that we + * ignore empty argument lists and thus do not to + * call the function in the Akeyword_eol state. */ + if (state == Akeyword_spc) + { + if (ignore_invalid_option_add (arg, fp)) + { + arg->r_opt = ARGPARSE_OUT_OF_CORE; + goto leave; + } + arg->lineno++; + } + state = Ainit; + i = 0; + } + else if (ignore_invalid_option_p (arg, keyword)) + { + /* This invalid option is already in the iio list. */ + state = state == Akeyword_eol? Ainit : Acomment; + i = 0; + } + else + { + arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) + ? ARGPARSE_INVALID_COMMAND + : ARGPARSE_INVALID_OPTION); + if (state == Akeyword_spc) + state = Askipandleave; + else + goto leave; + } + } + else if (state != Akeyword_spc + && arg->internal->in_sysconf + && arg->internal->user_seen + && !arg->internal->user_active) + { + /* We are in a [user] meta command and it is not active. + * Skip the command. */ + state = state == Akeyword_eol? Ainit : Acomment; + i = 0; + } + else if (state != Akeyword_spc + && (opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + /* Known option is configured to be ignored. Start from + * scratch (new line) or process like a comment. */ + state = state == Akeyword_eol? Ainit : Acomment; + i = 0; + } + else /* Known option */ + { + set_ignore = 0; + + if (arg->internal->in_sysconf) + { + /* Set the current forced and ignored attributes. */ + if (arg->internal->mark_forced) + opts[idx].forced = 1; + if (arg->internal->mark_ignore) + opts[idx].ignore = 1; + if (arg->internal->explicit_ignore) + opts[idx].explicit_ignore = 1; + + if (opts[idx].ignore && !opts[idx].forced) + { + if (arg->internal->verbose) + _gpgrt_log_info ("%s:%u: ignoring option \"--%s\"\n", + arg->internal->confname, + arg->lineno, + opts[idx].long_opt); + if ((arg->flags & ARGPARSE_FLAG_WITHATTR)) + set_ignore = 1; + else + { + state = state == Akeyword_eol? Ainit : Acomment; + i = 0; + goto nextstate; /* Ignore this one. */ + } + } + } + else /* Non-sysconf file */ + { /* Act upon the forced and ignored attributes. */ + if (opts[idx].ignore || opts[idx].forced) + { + if (arg->internal->verbose) + _gpgrt_log_info ("%s:%u: ignoring option \"--%s\"" + " due to attributes:%s%s\n", + arg->internal->confname, + arg->lineno, + opts[idx].long_opt, + opts[idx].forced? " forced":"", + opts[idx].ignore? " ignore":""); + if ((arg->flags & ARGPARSE_FLAG_WITHATTR)) + set_ignore = 1; + else + { + state = state == Akeyword_eol? Ainit : Acomment; + i = 0; + goto nextstate; /* Ignore this one. */ + } + } + } + + if (state == Akeyword_spc) + { + /* If we shall ignore but not set the option we skip + * the argument. Otherwise we would need to use a + * made-up but not used args in the conf file. */ + if (set_ignore || (opts[idx].ignore && !opts[idx].forced)) + { + prepare_arg_return (arg, opts, idx, 0, set_ignore); + set_ignore = 0; + state = Askipandleave; + } + else + state = Awaitarg; + } + else + { + prepare_arg_return (arg, opts, idx, 0, set_ignore); + set_ignore = 0; + goto leave; + } + + } + } /* (end state Akeyword_eol/Akeyword_spc) */ + else if (state == Ametacmd) + { + /* We are at the end of a line. */ + gpgrt_assert (*keyword == '['); + trim_spaces (keyword+1); + if (!keyword[1]) + { + arg->r_opt = ARGPARSE_INVALID_META; /* Empty. */ + goto leave; + } + c = handle_metacmd (arg, keyword+1); + if (c) + { + arg->r_opt = c; /* Return error. */ + goto leave; + } + state = Ainit; + i = 0; + } + + /* Get the next character from the line. */ + if (unread_buf_count) + c = unread_buf[3 - unread_buf_count--]; + else + c = _gpgrt_fgetc (fp); + + if (c == '\n' || c== EOF ) + { /* Handle end of line. */ + if ( c != EOF ) + arg->lineno++; + if (state == Askipandleave) + goto leave; + else if (state == Acopykeyword) + { + keyword[i] = 0; + state = Akeyword_eol; + goto nextstate; + } + else if (state == Acopymetacmd) + { + arg->r_opt = ARGPARSE_INVALID_META; /* "]" missing */ + goto leave; + } + else if (state == Askipmetacmd || state == Askipmetacmd2) + { + state = Ametacmd; + goto nextstate; + } + else if (state == Awaitarg) + { + /* No argument found at the end of the line. */ + prepare_arg_return (arg, opts, idx, in_alias, set_ignore); + set_ignore = 0; + goto leave; + } + else if (state == Acopyarg) + { + /* Has an argument at the end of a line. */ + if (in_alias) + { + if (!buffer) + arg->r_opt = ARGPARSE_UNEXPECTED_ARG; + else + { + char *p; + + buffer[i] = 0; + p = strpbrk (buffer, " \t"); + if (p) + { + *p++ = 0; + trim_spaces (p); + } + if (!p || !*p) + { + xfree (buffer); + arg->r_opt = ARGPARSE_INVALID_ALIAS; + } + else + { + store_alias (arg, buffer, p); + } + } + } + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_opt = ARGPARSE_UNEXPECTED_ARG; + else + { + char *p; + + if (!buffer) + { + keyword[i] = 0; + buffer = xtrystrdup (keyword); + if (!buffer) + arg->r_opt = ARGPARSE_OUT_OF_CORE; + } + else + buffer[i] = 0; + + if (buffer) + { + trim_spaces (buffer); + p = buffer; + if (*p == '"') + { + /* Remove quotes. */ + p++; + if (*p && p[strlen(p)-1] == '\"' ) + p[strlen(p)-1] = 0; + } + if (!set_opt_arg (arg, opts[idx].flags, p)) + xfree (buffer); + else + gpgrt_annotate_leaked_object (buffer); + } + } + goto leave; + } + else if (c == EOF) + { + ignore_invalid_option_clear (arg); + if (_gpgrt_ferror (fp)) + arg->r_opt = ARGPARSE_READ_ERROR; + else + arg->r_opt = 0; /* EOF. */ + goto leave; + } + state = Ainit; + i = 0; + } /* (end handle end of line) */ + else if (state == Askipandleave) + ; /* Skip. */ + else if (state == Ainit && isascii (c) && isspace(c)) + ; /* Skip leading white space. */ + else if (state == Ainit && c == '#' ) + state = Acomment; /* Start of a comment. */ + else if (state == Acomment || state == Askipmetacmd2) + ; /* Skip comments. */ + else if (state == Askipmetacmd) + { + if (c == '#') + state = Askipmetacmd2; + else if (!(isascii (c) && isspace(c))) + { + arg->r_opt = ARGPARSE_INVALID_META; + state = Askipandleave; + } + } + else if (state == Acopykeyword && isascii (c) && isspace(c)) + { + keyword[i] = 0; + state = Akeyword_spc; + goto nextstate; + } + else if (state == Acopymetacmd && c == ']') + { + keyword[i] = 0; + state = Askipmetacmd; + goto nextstate; + } + else if (state == Awaitarg) + { + /* Skip leading spaces of the argument. */ + if (!isascii (c) || !isspace(c)) + { + i = 0; + keyword[i++] = c; + state = Acopyarg; + } + } + else if (state == Acopyarg) + { + /* Collect the argument. */ + if (buffer) + { + if (i < buflen-1) + buffer[i++] = c; + else + { + char *tmp; + size_t tmplen = buflen + 50; + + tmp = xtryrealloc (buffer, tmplen); + if (tmp) + { + buflen = tmplen; + buffer = tmp; + buffer[i++] = c; + } + else + { + xfree (buffer); + arg->r_opt = ARGPARSE_OUT_OF_CORE; + goto leave; + } + } + } + else if (i < DIM(keyword)-1) + keyword[i++] = c; + else + { + size_t tmplen = DIM(keyword) + 50; + buffer = xtrymalloc (tmplen); + if (buffer) + { + buflen = tmplen; + memcpy(buffer, keyword, i); + buffer[i++] = c; + } + else + { + arg->r_opt = ARGPARSE_OUT_OF_CORE; + goto leave; + } + } + } + else if (i >= DIM(keyword)-1) + { + arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG; + state = Askipandleave; /* Skip rest of line and leave. */ + } + else if (!i) + { + state = c == '[' ? Acopymetacmd : Acopykeyword; + keyword[i++] = c; + } + else + { + keyword[i++] = c; + } + } + + leave: + return arg->r_opt; +} + + +/* Return true if the list of options OPTS has any option marked with + * ARGPARSE_OPT_CONFFILE. */ +static int +any_opt_conffile (opttable_t *opts, unsigned int nopts) +{ + int i; + + for (i=0; i < nopts; i++ ) + if ((opts[i].flags & ARGPARSE_OPT_CONFFILE)) + return 1; + return 0; +} + + +/* Return true if FNAME is an absoluete filename. */ +static int +is_absfname (const char *fname) +{ + const char *s; + +#ifdef HAVE_W32_SYSTEM + s = strchr (fname, ':'); + if (s) + s++; + else + s = fname; +#else + s = fname; +#endif + + return (*s == '/' +#ifdef HAVE_W32_SYSTEM + || *s == DIRSEP_C +#endif + ); +} + + +/* If FNAME specifies two files of the form + * NAME1:/NAME2 (Unix) + * or + * NAME1;[x:]/NAME2 (Windows) + * return a pointer to the delimiter or NULL if there is none. + */ +static const char * +is_twopartfname (const char *fname) +{ + const char *s; + + if ((s = strchr (fname, PATHSEP_C)) && is_absfname (s+1) && s != fname) + return s; + return NULL; +} + + +/* Try to use a version-ed config file name. A version-ed config file + * name is one which has the packages version number appended. For + * example if the standard config file name is "foo.conf" and the + * version of the foo program is 1.2.3-beta1 the following config + * files are tried in order until one is readable: + * + * foo.conf-1.2.3-beta1 + * foo.conf-1.2.3 + * foo.conf-1.2 + * foo.conf-1 + * foo.conf + * + * The argument CONFIGNAME should already be expanded. On success a + * newly allocated file name is returned. On error NULL is returned. + */ +static char * +try_versioned_conffile (const char *configname) +{ + const char *version = _gpgrt_strusage (13); + char *name; + char *dash, *endp; + + if (!version || !*version) + return NULL; /* No program version known. */ + + name = _gpgrt_strconcat (configname, "-", version, NULL); + if (!name) + return NULL; /* Oops: Out of core - ignore. */ + dash = name + strlen (configname); + + endp = dash + strlen (dash) - 1; + while (endp > dash) + { + if (!_gpgrt_access (name, R_OK)) + { + return name; + } + for (; endp > dash; endp--) + { + if (*endp == '-' || *endp == '.') + { + *endp = 0; + break; + } + } + } + + _gpgrt_free (name); + return NULL; +} + + +/* This function is called after a sysconf file has been read. */ +static void +finish_read_sys (gpgrt_argparse_t *arg) +{ + opttable_t *opts = arg->internal->opts; + unsigned int nopts = arg->internal->nopts; + int i; + + if (arg->internal->ignore_all_seen) + { + /* [ignore-all] was used: Set all options which have not + * explictly been set as ignore or not ignore to ignore. */ + for (i = 0; i < nopts; i++) + { + if (!opts[i].explicit_ignore) + opts[i].ignore = 1; + } + } + + /* Reset all flags which pertain only to sysconf files. */ + arg->internal->in_sysconf = 0; + arg->internal->user_active = 0; + arg->internal->mark_forced = 0; + arg->internal->mark_ignore = 0; + arg->internal->explicit_ignore = 0; + arg->internal->ignore_all_seen = 0; +} + + +/* The full arg parser which handles option files and command line + * arguments. The behaviour depends on the combinations of CONFNAME + * and the ARGPARSE_FLAG_xxx values: + * + * | CONFNAME | SYS | USER | Action | + * |----------+-----+------+--------------------| + * | NULL | - | - | cmdline | + * | string | 0 | 1 | user, cmdline | + * | string | 1 | 0 | sys, cmdline | + * | string | 1 | 1 | sys, user, cmdline | + * + * Note that if an option has been flagged with ARGPARSE_OPT_CONFFILE + * and a type of ARGPARSE_TYPE_STRING that option is not returned but + * the specified configuration file is processed directly; if + * ARGPARSE_TYPE_NONE is used no user configuration files are + * processed and from the system configuration files only those which + * are immutable are processed. The string values for CONFNAME shall + * not include a directory part because that is taken from the values + * set by gpgrt_set_confdir. However, if CONFNAME is a twopart + * filename delimited by a colon (semicolon on Windows) with the + * second part being an absolute filename, the first part is used for + * the SYS file and the the entire second part for the USER file. + */ +int +_gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, + const char *confname) +{ + /* First check whether releasing the resources has been requested. */ + if (arg && !opts) + { + deinitialize (arg); + return 0; + } + + /* Make sure that the internal data object is ready and also print + * warnings or errors from the last iteration. */ + if (initialize (arg, opts, NULL)) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + + next_state: + switch (arg->internal->state) + { + case STATE_init: + if (arg->argc && arg->argv && *arg->argc + && any_opt_conffile (arg->internal->opts, arg->internal->nopts)) + { + /* The list of option allow for conf files + * (e.g. gpg's "--option FILE" and "--no-options") + * Now check whether one was really given on the command + * line. Note that we don't need to run this code if no + * argument array was provided. */ + int save_argc = *arg->argc; + char **save_argv = *arg->argv; + unsigned int save_flags = arg->flags; + int save_idx = arg->internal->idx; + int any_no_conffile = 0; + + arg->flags = (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION + | ARGPARSE_FLAG__INITIALIZED); + while (arg_parse (arg, opts, 1)) + { + if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE)) + { + arg->internal->explicit_confopt = 1; + if ((arg->r_type & ARGPARSE_TYPE_MASK) == ARGPARSE_TYPE_STRING + && !arg->internal->explicit_conffile) + { + /* Store the first conffile name. All further + * conf file options are not handled. */ + arg->internal->explicit_conffile + = xtrystrdup (arg->r.ret_str); + if (!arg->internal->explicit_conffile) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + + } + else if ((arg->r_type & ARGPARSE_TYPE_MASK) + == ARGPARSE_TYPE_NONE) + any_no_conffile = 1; + } + } + if (any_no_conffile) + { + /* A NoConffile option overrides any other conf file option. */ + xfree (arg->internal->explicit_conffile); + arg->internal->explicit_conffile = NULL; + } + /* Restore parser. */ + *arg->argc = save_argc; + *arg->argv = save_argv; + arg->flags = save_flags; + arg->internal->idx = save_idx; + } + + if (confname && *confname) + { + if ((arg->flags & ARGPARSE_FLAG_SYS)) + arg->internal->state = STATE_open_sys; + else if ((arg->flags & ARGPARSE_FLAG_USER)) + arg->internal->state = STATE_open_user; + else + return (arg->r_opt = ARGPARSE_INVALID_ARG); + } + else + arg->internal->state = STATE_open_cmdline; + goto next_state; + + case STATE_open_sys: + { + /* If it is a two part name take the first part. */ + const char *s; + char *tmpname = NULL; + + if ((s = is_twopartfname (confname))) + { + tmpname = xtrymalloc (s - confname + 1); + if (!tmpname) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + memcpy (tmpname, confname, s-confname); + tmpname[s-confname] = 0; + s = tmpname; + } + else + s = confname; + xfree (arg->internal->confname); + arg->internal->confname = _gpgrt_fnameconcat + (confdir.sys? confdir.sys : "/etc", s, NULL); + _gpgrt_free (tmpname); + if (!arg->internal->confname) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + } + arg->lineno = 0; + arg->internal->idx = 0; + arg->internal->verbose = 0; + arg->internal->stopped = 0; + arg->internal->inarg = 0; + _gpgrt_fclose (arg->internal->conffp); + arg->internal->conffp = _gpgrt_fopen (arg->internal->confname, "r"); + if (!arg->internal->conffp) + { + if ((arg->flags & ARGPARSE_FLAG_VERBOSE) || arg->internal->verbose) + _gpgrt_log_info (_("Note: no default option file '%s'\n"), + arg->internal->confname); + if ((arg->flags & ARGPARSE_FLAG_USER)) + arg->internal->state = STATE_open_user; + else + arg->internal->state = STATE_open_cmdline; + goto next_state; + } + + if ((arg->flags & ARGPARSE_FLAG_VERBOSE) || arg->internal->verbose) + _gpgrt_log_info (_("reading options from '%s'\n"), + arg->internal->confname); + arg->internal->state = STATE_read_sys; + arg->internal->in_sysconf = 1; + arg->r.ret_str = xtrystrdup (arg->internal->confname); + if (!arg->r.ret_str) + arg->r_opt = ARGPARSE_OUT_OF_CORE; + else + { + gpgrt_annotate_leaked_object (arg->r.ret_str); + arg->r_opt = ARGPARSE_CONFFILE; + arg->r_type = ARGPARSE_TYPE_STRING; + } + break; + + case STATE_open_user: + if (arg->internal->explicit_confopt + && arg->internal->explicit_conffile) + { + /* An explict option to use a specific configuration file + * has been given - use that one. */ + xfree (arg->internal->confname); + arg->internal->confname + = xtrystrdup (arg->internal->explicit_conffile); + if (!arg->internal->confname) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + } + else if (arg->internal->explicit_confopt) + { + /* An explict option not to use a configuration file has + * been given - leap direct to command line reading. */ + arg->internal->state = STATE_open_cmdline; + goto next_state; + } + else + { + /* Use the standard configure file. If it is a two part + * name take the second part. If it is the standard name + * and ARGPARSE_FLAG_USERVERS is set try versioned config + * files. */ + const char *s; + char *nconf; + + xfree (arg->internal->confname); + if ((s = is_twopartfname (confname))) + { + arg->internal->confname = _gpgrt_fnameconcat (s + 1, NULL); + if (!arg->internal->confname) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + } + else + { + arg->internal->confname = _gpgrt_fnameconcat + (confdir.user? confdir.user : "~/.config", confname, NULL); + if (!arg->internal->confname) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + if ((arg->flags & ARGPARSE_FLAG_USERVERS) + && (nconf = try_versioned_conffile (arg->internal->confname))) + { + xfree (arg->internal->confname); + arg->internal->confname = nconf; + } + } + } + arg->lineno = 0; + arg->internal->idx = 0; + arg->internal->verbose = 0; + arg->internal->stopped = 0; + arg->internal->inarg = 0; + arg->internal->in_sysconf = 0; + _gpgrt_fclose (arg->internal->conffp); + arg->internal->conffp = _gpgrt_fopen (arg->internal->confname, "r"); + if (!arg->internal->conffp) + { + arg->internal->state = STATE_open_cmdline; + if (arg->internal->explicit_confopt) + { + _gpgrt_log_error (_("option file '%s': %s\n"), + arg->internal->confname, strerror (errno)); + return (arg->r_opt = ARGPARSE_NO_CONFFILE); + } + else + { + if ((arg->flags & ARGPARSE_FLAG_VERBOSE) + || arg->internal->verbose) + _gpgrt_log_info (_("Note: no default option file '%s'\n"), + arg->internal->confname); + goto next_state; + } + } + + if ((arg->flags & ARGPARSE_FLAG_VERBOSE) || arg->internal->verbose) + _gpgrt_log_info (_("reading options from '%s'\n"), + arg->internal->confname); + arg->internal->state = STATE_read_user; + arg->r.ret_str = xtrystrdup (arg->internal->confname); + if (!arg->r.ret_str) + arg->r_opt = ARGPARSE_OUT_OF_CORE; + else + { + gpgrt_annotate_leaked_object (arg->r.ret_str); + arg->r_opt = ARGPARSE_CONFFILE; + arg->r_type = ARGPARSE_TYPE_STRING; + } + break; + + case STATE_open_cmdline: + _gpgrt_fclose (arg->internal->conffp); + arg->internal->conffp = NULL; + xfree (arg->internal->confname); + arg->internal->confname = NULL; + arg->internal->idx = 0; + arg->internal->verbose = 0; + arg->internal->stopped = 0; + arg->internal->inarg = 0; + arg->internal->in_sysconf = 0; + if (!arg->argc || !arg->argv || !*arg->argv) + { + /* No or empty argument vector - don't bother to parse things. */ + arg->internal->state = STATE_finished; + goto next_state; + } + arg->r_opt = ARGPARSE_CONFFILE; + arg->r_type = ARGPARSE_TYPE_NONE; + arg->r.ret_str = NULL; + arg->internal->state = STATE_read_cmdline; + break; + + case STATE_read_sys: + arg->r_opt = _gpgrt_argparse (arg->internal->conffp, arg, opts); + if (!arg->r_opt) + { + finish_read_sys (arg); + arg->internal->state = STATE_open_user; + goto next_state; + } + if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE)) + goto next_state; /* Already handled - again. */ + break; + + case STATE_read_user: + arg->r_opt = _gpgrt_argparse (arg->internal->conffp, arg, opts); + if (!arg->r_opt) + { + arg->internal->state = STATE_open_cmdline; + goto next_state; + } + if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE)) + goto next_state; /* Already handled - again. */ + break; + + case STATE_read_cmdline: + arg->r_opt = arg_parse (arg, opts, 1); + if (!arg->r_opt) + { + arg->internal->state = STATE_finished; + goto next_state; + } + if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE)) + goto next_state; /* Already handled - again. */ + break; + + case STATE_finished: + arg->r_opt = 0; + break; + } + + return arg->r_opt; +} + + +/* Given the list of options in ARG and a keyword, return the index of + * the long option matching KEYWORD. On error -1 is returned for not + * found or -2 for ambigious keyword. */ +static int +find_long_option (gpgrt_argparse_t *arg, const char *keyword) +{ + int i; + size_t n; + opttable_t *opts = arg->internal->opts; + unsigned int nopts = arg->internal->nopts; + + /* Would be better if we can do a binary search, but it is not + * possible to reorder our option table because we would mess up our + * help strings. What we can do is: Build an option lookup table + * when this function is first invoked. The latter has already been + * done. */ + if (!*keyword) + return -1; + for (i=0; i < nopts; i++ ) + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) + return i; +#if 0 + { + ALIAS_DEF a; + /* see whether it is an alias */ + for (a = args->internal->aliases; a; a = a->next) + { + if (!strcmp( a->name, keyword)) + { + /* todo: must parse the alias here */ + args->internal->cur_alias = a; + return -3; /* alias available */ + } + } + } +#endif + /* Not found. See whether it is an abbreviation. Aliases may not + * be abbreviated, though. */ + n = strlen (keyword); + for (i=0; i < nopts; i++) + { + if (opts[i].long_opt && !strncmp (opts[i].long_opt, keyword, n)) + { + int j; + for (j=i+1; j < nopts; j++) + { + if (opts[j].long_opt + && !strncmp (opts[j].long_opt, keyword, n) + && !(opts[j].short_opt == opts[i].short_opt + && opts[j].flags == opts[i].flags ) ) + return -2; /* Abbreviation is ambiguous. */ + } + return i; + } + } + return -1; /* Not found. */ +} + + +/* The option parser for command line options. */ +static int +arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) +{ + int idx; + opttable_t *opts; + unsigned int nopts; + int argc; + char **argv; + char *s, *s2; + int i; + + if (no_init) + ; + else if (initialize (arg, opts_orig, NULL)) + return (arg->r_opt = ARGPARSE_OUT_OF_CORE); + + opts = arg->internal->opts; + nopts = arg->internal->nopts; + argc = *arg->argc; + argv = *arg->argv; + idx = arg->internal->idx; + + if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0)) + { + /* Skip the first argument. */ + argc--; argv++; idx++; + } + + next_one: + if (!argc || (s = *argv) == NULL) + { + /* No more args. */ + arg->r_opt = 0; + goto leave; /* Ready. */ + } + + arg->internal->last = s; + arg->internal->opt_flags = 0; + + if (arg->internal->stopped && (arg->flags & ARGPARSE_FLAG_ALL)) + { + arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */ + arg->r_type = ARGPARSE_TYPE_STRING; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else if (arg->internal->stopped) + { + arg->r_opt = 0; + goto leave; /* Ready. */ + } + else if ( *s == '-' && s[1] == '-' ) + { + /* Long option. */ + char *argpos; + + arg->internal->inarg = 0; + if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP)) + { + /* Stop option processing. */ + arg->internal->stopped = 1; + arg->flags |= ARGPARSE_FLAG_STOP_SEEN; + argc--; argv++; idx++; + goto next_one; + } + + argpos = strchr( s+2, '=' ); + if ( argpos ) + *argpos = 0; + i = find_long_option (arg, s+2); + if ( argpos ) + *argpos = '='; + + if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_HELP) + { + show_help (opts, nopts, arg->flags); + my_exit (arg, 0); + } + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_VERSION) + { + if (!(arg->flags & ARGPARSE_FLAG_NOVERSION)) + { + show_version (); + my_exit (arg, 0); + } + } + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY) + { + writestrings (0, _gpgrt_strusage (16), "\n", NULL); + my_exit (arg, 0); + } + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTTBL) + dump_option_table (arg); + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS) + { + for (i=0; i < nopts; i++ ) + { + if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE)) + writestrings (0, "--", opts[i].long_opt, "\n", NULL); + } + my_exit (arg, 0); + } + + if ( i == -2 ) + arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION; + else if ( i == -1 ) + { + arg->r_opt = ARGPARSE_INVALID_OPTION; + arg->r.ret_str = s+2; + } + else + arg->r_opt = opts[i].short_opt; + + if ( i < 0 ) + ; + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) + { + if ( argpos ) + { + s2 = argpos+1; + if ( !*s2 ) + s2 = NULL; + } + else + s2 = argv[1]; + + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */ + } + else if ( !s2 ) + { + arg->r_opt = ARGPARSE_MISSING_ARG; + } + else if ( !argpos && *s2 == '-' + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + /* The argument is optional and the next seems to be an + option. We do not check this possible option but + assume no argument */ + arg->r_type = ARGPARSE_TYPE_NONE; + } + else + { + set_opt_arg (arg, opts[i].flags, s2); + if ( !argpos ) + { + argc--; argv++; idx++; /* Skip one. */ + } + } + } + else + { + /* Does not take an argument. */ + if ( argpos ) + arg->r_type = ARGPARSE_UNEXPECTED_ARG; + else + { + arg->internal->opt_flags = opts[i].flags; + arg->r_type = ARGPARSE_TYPE_NONE; + } + } + argc--; argv++; idx++; /* Set to next one. */ + } + else if ( (*s == '-' && s[1]) || arg->internal->inarg ) + { + /* Short option. */ + int dash_kludge = 0; + + i = 0; + if ( !arg->internal->inarg ) + { + arg->internal->inarg++; + if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) ) + { + for (i=0; i < nopts; i++ ) + if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1)) + { + dash_kludge = 1; + break; + } + } + } + s += arg->internal->inarg; + + if (!dash_kludge ) + { + for (i=0; i < nopts; i++ ) + if ( opts[i].short_opt == *s ) + break; + } + + if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) + { + show_help (opts, nopts, arg->flags); + my_exit (arg, 0); + } + + arg->r_opt = opts[i].short_opt; + if (!opts[i].short_opt ) + { + arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)? + ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION; + arg->internal->inarg++; /* Point to the next arg. */ + arg->r.ret_str = s; + } + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) + { + if ( s[1] && !dash_kludge ) + { + s2 = s+1; + set_opt_arg (arg, opts[i].flags, s2); + } + else + { + s2 = argv[1]; + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + arg->r_type = ARGPARSE_TYPE_NONE; + arg->internal->opt_flags = opts[i].flags; + } + else if ( !s2 ) + { + arg->r_opt = ARGPARSE_MISSING_ARG; + } + else if ( *s2 == '-' && s2[1] + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + /* The argument is optional and the next seems to + be an option. We do not check this possible + option but assume no argument. */ + arg->r_type = ARGPARSE_TYPE_NONE; + arg->internal->opt_flags = opts[i].flags; + } + else + { + set_opt_arg (arg, opts[i].flags, s2); + argc--; argv++; idx++; /* Skip one. */ + } + } + s = "x"; /* This is so that !s[1] yields false. */ + } + else + { + /* Does not take an argument. */ + arg->r_type = ARGPARSE_TYPE_NONE; + arg->internal->opt_flags = opts[i].flags; + arg->internal->inarg++; /* Point to the next arg. */ + } + if ( !s[1] || dash_kludge ) + { + /* No more concatenated short options. */ + arg->internal->inarg = 0; + argc--; argv++; idx++; + } + } + else if ( arg->flags & ARGPARSE_FLAG_MIXED ) + { + arg->r_opt = ARGPARSE_IS_ARG; + arg->r_type = ARGPARSE_TYPE_STRING; + arg->r.ret_str = s; + argc--; argv++; idx++; /* Set to next one. */ + } + else + { + arg->internal->stopped = 1; /* Stop option processing. */ + goto next_one; + } + + if (arg->r_opt > 0 && i >= 0 && i < nopts + && ((opts[i].ignore && opts[i].explicit_ignore) || opts[i].forced)) + { + + if ((arg->flags & ARGPARSE_FLAG_WITHATTR)) + { + if (opts[i].ignore) + arg->r_type |= ARGPARSE_ATTR_IGNORE; + if (opts[i].forced) + arg->r_type |= ARGPARSE_ATTR_FORCE; + arg->r_type |= ARGPARSE_OPT_IGNORE; + } + else + { + _gpgrt_log_info (_("Note: ignoring option \"--%s\"" + " due to global config\n"), + opts[i].long_opt); + goto next_one; /* Skip ignored/forced option. */ + } + } + + leave: + *arg->argc = argc; + *arg->argv = argv; + arg->internal->idx = idx; + return arg->r_opt; +} + + +/* Returns: -1 on error, 0 for an integer type and 1 for a non integer + type argument. */ +static int +set_opt_arg (gpgrt_argparse_t *arg, unsigned flags, char *s) +{ + int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10; + long l; + + arg->internal->opt_flags = flags; + switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) ) + { + case ARGPARSE_TYPE_LONG: + case ARGPARSE_TYPE_INT: + errno = 0; + l = strtol (s, NULL, base); + if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + if (arg->r_type == ARGPARSE_TYPE_LONG) + arg->r.ret_long = l; + else if ( (l < 0 && l < INT_MIN) || l > INT_MAX ) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + else + arg->r.ret_int = (int)l; + return 0; + + case ARGPARSE_TYPE_ULONG: + while (isascii (*s) && isspace(*s)) + s++; + if (*s == '-') + { + arg->r.ret_ulong = 0; + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + errno = 0; + arg->r.ret_ulong = strtoul (s, NULL, base); + if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + return 0; + + case ARGPARSE_TYPE_STRING: + default: + arg->r.ret_str = s; + return 1; + } +} + + +/* Return the length of the option O. This needs to consider the + * description as well as the option name. */ +static size_t +long_opt_strlen (opttable_t *o) +{ + size_t n = strlen (o->long_opt); + + if ( o->description && *o->description == '|' ) + { + const char *s; + int is_utf8 = is_native_utf8 (); + + s=o->description+1; + if ( *s != '=' ) + n++; + /* For a (mostly) correct length calculation we exclude + * continuation bytes (10xxxxxx) if we are on a native utf8 + * terminal. */ + for (; *s && *s != '|'; s++ ) + if ( is_utf8 && (*s&0xc0) != 0x80 ) + n++; + } + return n; +} + + + +/* Qsort compare for show_help. */ +static int +cmp_ordtbl (const void *a_v, const void *b_v) +{ + const unsigned short *a = a_v; + const unsigned short *b = b_v; + + return *a - *b; +} + + +/**************** + * Print formatted help. The description string has some special + * meanings: + * - A description string which is "@" suppresses help output for + * this option + * - a description which starts with a '@' and is followed by + * any other characters is printed as is; this may be used for examples + * and such. This is a legacy methiod, moder codes uses the flags + * ARGPARSE_OPT_VERBATIM or ARGPARSE_OPT_HEADER. + * - A description which starts with a '|' outputs the string between this + * bar and the next one as arguments of the long option. + */ +static void +show_help (opttable_t *opts, unsigned int nopts, unsigned int flags) +{ + const char *s; + char tmp[2]; + unsigned int *ordtbl = NULL; + + show_version (); + writestrings (0, "\n", NULL); + s = _gpgrt_strusage (42); + if (s && *s == '1') + { + s = _gpgrt_strusage (40); + writestrings (1, s, NULL); + if (*s && s[strlen(s)] != '\n') + writestrings (1, "\n", NULL); + } + s = _gpgrt_strusage(41); + writestrings (0, s, "\n", NULL); + if ( nopts ) + { + /* Auto format the option description. */ + int i,j,indent; + const char *last_header = NULL; + + ordtbl = xtrycalloc (nopts, sizeof *ordtbl); + if (!ordtbl) + { + writestrings (1, "\nOoops: Out of memory whilst printing the help.\n", + NULL); + goto leave; + } + + /* Get max. length of long options. */ + for (i=indent=0; i < nopts; i++ ) + { + if ( opts[i].long_opt ) + if ( !opts[i].description || *opts[i].description != '@' ) + if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 ) + indent = j; + ordtbl[i] = opts[i].ordinal; + } + + qsort (ordtbl, nopts, sizeof *ordtbl, cmp_ordtbl); + + /* The first option needs to have a description; if not do not + * print the help at all. */ + if (!opts[ordtbl[0]].description) + goto leave; + + /* Example: " -v, --verbose Viele Sachen ausgeben" */ + indent += 10; + if ( *opts[ordtbl[0]].description != '@' + && !(opts[ordtbl[0]].flags + & (ARGPARSE_OPT_VERBATIM|ARGPARSE_OPT_HEADER))) + writestrings (0, "Options:", "\n", NULL); + for (i=0; i < nopts; i++ ) + { + s = map_fixed_string (_( opts[ordtbl[i]].description )); + if ( s && *s== '@' && !s[1] ) /* Hide this line. */ + continue; + if ( s && (opts[ordtbl[i]].flags & ARGPARSE_OPT_HEADER)) + { + /* We delay printing until we have found one real output + * line. This avoids having a header above an empty + * section. */ + last_header = s; + continue; + } + if (last_header) + { + if (*last_header) + writestrings (0, "\n", last_header, ":\n", NULL); + last_header = NULL; + } + if ( s && (opts[ordtbl[i]].flags & ARGPARSE_OPT_VERBATIM)) + { + writestrings (0, s, NULL); + continue; + } + if ( s && *s == '@' ) /* Unindented legacy comment only line. */ + { + for (s++; *s; s++ ) + { + if ( *s == '\n' ) + { + if( s[1] ) + writestrings (0, "\n", NULL); + } + else + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + } + writestrings (0, "\n", NULL); + continue; + } + + j = 3; + if ( opts[ordtbl[i]].short_opt < 256 ) + { + tmp[0] = opts[ordtbl[i]].short_opt; + tmp[1] = 0; + writestrings (0, " -", tmp, NULL ); + if ( !opts[ordtbl[i]].long_opt ) + { + if (s && *s == '|' ) + { + writestrings (0, " ", NULL); j++; + for (s++ ; *s && *s != '|'; s++, j++ ) + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + if ( *s ) + s++; + } + } + } + else + writestrings (0, " ", NULL); + if ( opts[ordtbl[i]].long_opt ) + { + tmp[0] = opts[ordtbl[i]].short_opt < 256?',':' '; + tmp[1] = 0; + j += writestrings (0, tmp, " --", opts[ordtbl[i]].long_opt, NULL); + if (s && *s == '|' ) + { + if ( *++s != '=' ) + { + writestrings (0, " ", NULL); + j++; + } + for ( ; *s && *s != '|'; s++, j++ ) + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + if ( *s ) + s++; + } + writestrings (0, " ", NULL); + j += 3; + } + for (;j < indent; j++ ) + writestrings (0, " ", NULL); + if ( s ) + { + if ( *s && j > indent ) + { + writestrings (0, "\n", NULL); + for (j=0;j < indent; j++ ) + writestrings (0, " ", NULL); + } + for (; *s; s++ ) + { + if ( *s == '\n' ) + { + if ( s[1] ) + { + writestrings (0, "\n", NULL); + for (j=0; j < indent; j++ ) + writestrings (0, " ", NULL); + } + } + else + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + } + } + writestrings (0, "\n", NULL); + } + if ( (flags & ARGPARSE_FLAG_ONEDASH) ) + writestrings (0, "\n(A single dash may be used " + "instead of the double ones)\n", NULL); + } + if ( (s=_gpgrt_strusage(19)) ) + { + writestrings (0, "\n", NULL); + writestrings (0, s, NULL); + } + + leave: + flushstrings (0); + xfree (ordtbl); +} + + +static void +show_version () +{ + const char *s; + int i; + + /* Version line. */ + writestrings (0, _gpgrt_strusage (11), NULL); + if ((s=_gpgrt_strusage (12))) + writestrings (0, " (", s, ")", NULL); + writestrings (0, " ", _gpgrt_strusage (13), "\n", NULL); + /* Additional version lines. */ + for (i=20; i < 30; i++) + if ((s=_gpgrt_strusage (i))) + writestrings (0, s, "\n", NULL); + /* Copyright string. */ + if ((s=_gpgrt_strusage (14))) + writestrings (0, s, "\n", NULL); + /* Licence string. */ + if( (s=_gpgrt_strusage (10)) ) + writestrings (0, s, "\n", NULL); + /* Copying conditions. */ + if ( (s=_gpgrt_strusage(15)) ) + writestrings (0, s, NULL); + /* Thanks. */ + if ((s=_gpgrt_strusage(18))) + writestrings (0, s, NULL); + /* Additional program info. */ + for (i=30; i < 40; i++ ) + if ( (s=_gpgrt_strusage (i)) ) + writestrings (0, s, NULL); + flushstrings (0); +} + + +/* Print the table of options with flags etc. */ +static void +dump_option_table (gpgrt_argparse_t *arg) +{ + opttable_t *opts; + unsigned int nopts; + const char *s; + char tmp[50]; + unsigned int *ordtbl = NULL; + int i; + + opts = arg->internal->opts; + nopts = arg->internal->nopts; + if (!nopts) + return; + + ordtbl = xtrycalloc (nopts, sizeof *ordtbl); + if (!ordtbl) + { + writestrings (1, "\nOoops: Out of memory whilst dumping the table.\n", + NULL); + flushstrings (1); + my_exit (arg, 2); + } + for (i=0; i < nopts; i++ ) + ordtbl[i] = opts[i].ordinal; + qsort (ordtbl, nopts, sizeof *ordtbl, cmp_ordtbl); + for (i=0; i < nopts; i++ ) + { + if (!opts[ordtbl[i]].long_opt) + continue; + writestrings (0, opts[ordtbl[i]].long_opt, ":", NULL); + snprintf (tmp, sizeof tmp, "%u:%u:", + opts[ordtbl[i]].short_opt, + opts[ordtbl[i]].flags); + writestrings (0, tmp, NULL); + s = opts[ordtbl[i]].description; + if (s) + { + for (; *s; s++) + { + if (*s == '%' || *s == ':' || *s == '\n') + snprintf (tmp, sizeof tmp, "%%%02X", *s); + else + { + tmp[0] = *s; + tmp[1] = 0; + } + writestrings (0, tmp, NULL); + } + } + writestrings (0, ":\n", NULL); + } + + flushstrings (0); + xfree (ordtbl); + my_exit (arg, 0); +} + + +void +_gpgrt_usage (int level) +{ + const char *p; + + if (!level) + { + writestrings (1, _gpgrt_strusage(11), " ", _gpgrt_strusage(13), "; ", + _gpgrt_strusage (14), "\n", NULL); + flushstrings (1); + } + else if (level == 1) + { + p = _gpgrt_strusage (40); + writestrings (1, p, NULL); + if (*p && p[strlen(p)] != '\n') + writestrings (1, "\n", NULL); + exit (2); + } + else if (level == 2) + { + p = _gpgrt_strusage (42); + if (p && *p == '1') + { + p = _gpgrt_strusage (40); + writestrings (1, p, NULL); + if (*p && p[strlen(p)] != '\n') + writestrings (1, "\n", NULL); + } + writestrings (0, _gpgrt_strusage(41), "\n", NULL); + exit (0); + } +} + +/* Level + * 0: Print copyright string to stderr + * 1: Print a short usage hint to stderr and terminate + * 2: Print a long usage hint to stdout and terminate + * 8: Return NULL for UTF-8 or string with the native charset. + * 9: Return the SPDX License tag. + * 10: Return license info string + * 11: Return the name of the program + * 12: Return optional name of package which includes this program. + * 13: version string + * 14: copyright string + * 15: Short copying conditions (with LFs) + * 16: Long copying conditions (with LFs) + * 17: Optional printable OS name + * 18: Optional thanks list (with LFs) + * 19: Bug report info + *20..29: Additional lib version strings. + *30..39: Additional program info (with LFs) + * 40: short usage note (with LF) + * 41: long usage note (with LF) + * 42: Flag string: + * First char is '1': + * The short usage notes needs to be printed + * before the long usage note. + * 95: Application flag string + * First character is '1': + * On Windows enable argument globbing + */ +const char * +_gpgrt_strusage (int level) +{ + const char *p = strusage_handler? strusage_handler(level) : NULL; + const char *tmp; + + if ( p ) + return map_fixed_string (p); + + switch ( level ) + { + + case 8: break; /* Default to utf-8. */ + case 9: + p = "GPL-3.0-or-later"; /* Suggested license. */ + break; + + case 10: + tmp = _gpgrt_strusage (9); + if (tmp && !strcmp (tmp, "GPL-2.0-or-later")) + p = ("License GNU GPL-2.0-or-later "); + else if (tmp && !strcmp (tmp, "LGPL-2.1-or-later")) + p = ("License GNU LGPL-2.1-or-later "); + else /* Default to GPLv3+. */ + p = ("License GNU GPL-3.0-or-later "); + break; + case 11: p = "foo"; break; + case 13: p = "0.0"; break; + case 14: p = "Copyright (C) YEAR NAME"; break; + case 15: p = +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n"; + break; + case 16: + tmp = _gpgrt_strusage (9); + if (tmp && !strcmp (tmp, "GPL-2.0-or-later")) + p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"You should have received a copy of the GNU General Public License\n" +"along with this software. If not, see .\n"; + else if (tmp && !strcmp (tmp, "LGPL-2.1-or-later")) + p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU Lesser General Public License as\n" +"published by the Free Software Foundation; either version 2.1 of\n" +"the License, or (at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU Lesser General Public License for more details.\n\n" +"You should have received a copy of the GNU Lesser General Public License\n" +"along with this software. If not, see .\n"; + else /* Default */ + p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 3 of the License, or\n" +"(at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"You should have received a copy of the GNU General Public License\n" +"along with this software. If not, see .\n"; + break; + case 40: /* short and long usage */ + case 41: p = ""; break; + } + + return p; +} + + +/* Set the usage handler. This function is basically a constructor. */ +void +_gpgrt_set_strusage (const char *(*f)(int) ) +{ + strusage_handler = f; +} + + +/* Set a function to write strings which is then used instead of + * estream. The first arg of that function is MODE and the second the + * STRING to write. A mode of 1 is used for writing to stdout and a + * mode of 2 to write to stderr. Other modes are reserved and should + * not output anything. A NULL for STRING requests a flush. */ +void +_gpgrt_set_usage_outfnc (int (*f)(int, const char *)) +{ + custom_outfnc = f; +} + + +/* Register function F as a string mapper which takes a string as + * argument, replaces known "@FOO@" style macros and returns a new + * fixed string. Warning: The input STRING must have been allocated + * statically. */ +void +_gpgrt_set_fixed_string_mapper (const char *(*f)(const char*)) +{ + fixed_string_mapper = f; +} + + +/* Register a configuration directory for use by the argparse + * functions. The defined values for WHAT are: + * + * GPGRT_CONFDIR_SYS The systems's configuration dir. + * The default is /etc + * + * GPGRT_CONFDIR_USER The user's configuration directory. + * The default is $HOME. + * + * A trailing slash is ignored; to have the function lookup + * configuration files in the current directory, use ".". There is no + * error return; more configuraion values may be added in future + * revisions of this library. + */ +void +_gpgrt_set_confdir (int what, const char *name) +{ + char *buf, *p; + + if (what == GPGRT_CONFDIR_SYS) + { + _gpgrt_free (confdir.sys); + buf = confdir.sys = _gpgrt_strdup (name); + } + else if (what == GPGRT_CONFDIR_USER) + { + _gpgrt_free (confdir.user); + buf = confdir.user = _gpgrt_strdup (name); + } + else + return; + + if (!buf) + _gpgrt_log_fatal ("out of core in %s\n", __func__); +#ifdef HAVE_W32_SYSTEM + for (p=buf; *p; p++) + if (*p == '\\') + *p = '/'; +#endif + /* Strip trailing slashes unless buf is "/" or any other single char + * string. */ + if (*buf) + { + for (p=buf + strlen (buf)-1; p > buf; p--) + if (*p == '/') + *p = 0; + else + break; + } +} diff --git a/comm/third_party/libgpg-error/src/b64dec.c b/comm/third_party/libgpg-error/src/b64dec.c new file mode 100644 index 0000000000..868d985685 --- /dev/null +++ b/comm/third_party/libgpg-error/src/b64dec.c @@ -0,0 +1,279 @@ +/* b64dec.c - Simple Base64 decoder. + * Copyright (C) 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2008, 2011, 2016 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This file was originally a part of GnuPG. + */ + +#include +#include +#include +#include + +#include "gpgrt-int.h" + + +/* The reverse base-64 list used for base-64 decoding. */ +static unsigned char const asctobin[128] = + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff + }; + +enum decoder_states + { + s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin, + s_b64_0, s_b64_1, s_b64_2, s_b64_3, + s_waitendtitle, s_waitend + }; + + + +/* Allocate and initialize the context for the base64 decoder. If + TITLE is NULL a plain base64 decoding is done. If it is the empty + string the decoder will skip everything until a "-----BEGIN " line + has been seen, decoding ends at a "----END " line. */ +gpgrt_b64state_t +_gpgrt_b64dec_start (const char *title) +{ + gpgrt_b64state_t state; + char *t = NULL; + + if (title) + { + t = xtrystrdup (title); + if (!t) + return NULL; + } + + state = xtrycalloc (1, sizeof (struct _gpgrt_b64state)); + if (!state) + { + xfree (t); + return NULL; + } + + if (t) + { + state->title = t; + state->idx = s_init; + } + else + state->idx = s_b64_0; + + state->using_decoder = 1; + + return state; +} + + +/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the + new length of the buffer at R_NBYTES. */ +gpg_err_code_t +_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length, + size_t *r_nbytes) +{ + enum decoder_states ds = state->idx; + unsigned char val = state->radbuf[0]; + int pos = state->quad_count; + char *d, *s; + + if (state->lasterr) + return state->lasterr; + + if (state->stop_seen) + { + *r_nbytes = 0; + state->lasterr = GPG_ERR_EOF; + xfree (state->title); + state->title = NULL; + return state->lasterr; + } + + for (s=d=buffer; length && !state->stop_seen; length--, s++) + { + again: + switch (ds) + { + case s_idle: + if (*s == '\n') + { + ds = s_lfseen; + pos = 0; + } + break; + case s_init: + ds = s_lfseen; + /* Fall through */ + case s_lfseen: + if (*s != "-----BEGIN "[pos]) + { + ds = s_idle; + goto again; + } + else if (pos == 10) + { + pos = 0; + ds = s_beginseen; + } + else + pos++; + break; + case s_beginseen: + if (*s != "PGP "[pos]) + ds = s_begin; /* Not a PGP armor. */ + else if (pos == 3) + ds = s_waitheader; + else + pos++; + break; + case s_waitheader: + if (*s == '\n') + ds = s_waitblank; + break; + case s_waitblank: + if (*s == '\n') + ds = s_b64_0; /* blank line found. */ + else if (*s == ' ' || *s == '\r' || *s == '\t') + ; /* Ignore spaces. */ + else + { + /* Armor header line. Note that we don't care that our + * FSM accepts a header prefixed with spaces. */ + ds = s_waitheader; /* Wait for next header. */ + } + break; + case s_begin: + if (*s == '\n') + ds = s_b64_0; + break; + case s_b64_0: + case s_b64_1: + case s_b64_2: + case s_b64_3: + { + int c; + + if (*s == '-' && state->title) + { + /* Not a valid Base64 character: assume end + header. */ + ds = s_waitend; + } + else if (*s == '=') + { + /* Pad character: stop */ + if (ds == s_b64_1) + *d++ = val; + ds = state->title? s_waitendtitle : s_waitend; + } + else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t') + ; /* Skip white spaces. */ + else if ( (*s & 0x80) + || (c = asctobin[*(unsigned char *)s]) == 255) + { + /* Skip invalid encodings. */ + state->invalid_encoding = 1; + } + else if (ds == s_b64_0) + { + val = c << 2; + ds = s_b64_1; + } + else if (ds == s_b64_1) + { + val |= (c>>4)&3; + *d++ = val; + val = (c<<4)&0xf0; + ds = s_b64_2; + } + else if (ds == s_b64_2) + { + val |= (c>>2)&15; + *d++ = val; + val = (c<<6)&0xc0; + ds = s_b64_3; + } + else + { + val |= c&0x3f; + *d++ = val; + ds = s_b64_0; + } + } + break; + case s_waitendtitle: + if (*s == '-') + ds = s_waitend; + break; + case s_waitend: + if ( *s == '\n') + state->stop_seen = 1; + break; + default: + gpgrt_assert (!"invalid state"); + } + } + + + state->idx = ds; + state->radbuf[0] = val; + state->quad_count = pos; + *r_nbytes = (d -(char*) buffer); + return 0; +} + + +/* Return an error code in case an encoding error has been found + during decoding. */ +gpg_err_code_t +_gpgrt_b64dec_finish (gpgrt_b64state_t state) +{ + gpg_error_t err; + + if (!state) + return 0; /* Already released. */ + + if (!state->using_decoder) + err = GPG_ERR_CONFLICT; /* State was allocated for the encoder. */ + else if (state->lasterr) + err = state->lasterr; + else + { + xfree (state->title); + err = state->invalid_encoding? GPG_ERR_BAD_DATA : 0; + } + xfree (state); + + return err; +} diff --git a/comm/third_party/libgpg-error/src/b64enc.c b/comm/third_party/libgpg-error/src/b64enc.c new file mode 100644 index 0000000000..571f4ec792 --- /dev/null +++ b/comm/third_party/libgpg-error/src/b64enc.c @@ -0,0 +1,386 @@ +/* b64enc.c - Simple Base64 encoder. + * Copyright (C) 2001, 2003, 2004, 2008, 2010, + * 2011 Free Software Foundation, Inc. + * Copyright (C) 2001, 2003, 2004, 2008, 2010, + * 2011, 2018 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This file was originally a part of GnuPG. + */ + +#include +#include +#include +#include +#include +#include + +#include "gpgrt-int.h" + + +#define B64ENC_DID_HEADER 1 +#define B64ENC_DID_TRAILER 2 +#define B64ENC_NO_LINEFEEDS 16 +#define B64ENC_USE_PGPCRC 32 + +/* The base-64 character list */ +static unsigned char const bintoasc[64] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"); + +/* Stuff required to create the OpenPGP CRC. This crc_table has been + created using this code: + + #include + #include + + #define CRCPOLY 0x864CFB + + int + main (void) + { + int i, j; + uint32_t t; + uint32_t crc_table[256]; + + crc_table[0] = 0; + for (i=j=0; j < 128; j++ ) + { + t = crc_table[j]; + if ( (t & 0x00800000) ) + { + t <<= 1; + crc_table[i++] = t ^ CRCPOLY; + crc_table[i++] = t; + } + else + { + t <<= 1; + crc_table[i++] = t; + crc_table[i++] = t ^ CRCPOLY; + } + } + + puts ("static const u32 crc_table[256] = {"); + for (i=j=0; i < 256; i++) + { + printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]); + if (i != 255) + { + putchar (','); + if ( ++j > 5) + { + j = 0; + putchar ('\n'); + } + } + } + puts ("\n};"); + return 0; + } +*/ +#define CRCINIT 0xB704CE +static const uint32_t crc_table[256] = { + 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, + 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, + 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, + 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, + 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, + 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, + 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, + 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, + 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, + 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, + 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, + 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, + 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, + 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad, + 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, + 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, + 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, + 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, + 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, + 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, + 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, + 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, + 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, + 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, + 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, + 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, + 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, + 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, + 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, + 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, + 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, + 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, + 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, + 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, + 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, + 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, + 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, + 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, + 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, + 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, + 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c, + 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, + 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538 +}; + + +/* Prepare for Base-64 writing to STREAM. If TITLE is not NULL and + * not an empty string, that string will be used as the title for the + * armor lines, with TITLE being an empty string, we don't write the + * header lines and furthermore even don't write any linefeeds. If + * TITLE starts with "PGP " the OpenPGP CRC checksum will be written + * as well. With TITLE being NULL, we merely don't write header but + * make sure that lines are not too long. Note, that we don't write + * anything unless at least one byte is written using b64enc_write. + * On success an enoder object is returned which needs to be released + * using _gpgrt_b64dec_finish. On error NULL is returned an ERRNO is + * set. + */ +gpgrt_b64state_t +_gpgrt_b64enc_start (estream_t stream, const char *title) +{ + gpgrt_b64state_t state; + + state = xtrycalloc (1, sizeof *state); + if (!state) + return NULL; + + state->stream = stream; + if (title && !*title) + state->flags |= B64ENC_NO_LINEFEEDS; + else if (title) + { + if (!strncmp (title, "PGP ", 4)) + { + state->flags |= B64ENC_USE_PGPCRC; + state->crc = CRCINIT; + } + state->title = xtrystrdup (title); + if (!state->title) + { + xfree (state); + return NULL; + } + } + + return state; +} + + +/* Write NBYTES from BUFFER to the Base 64 stream identified by STATE. + * With BUFFER and NBYTES being 0, merely do a fflush on the stream. + */ +gpg_err_code_t +_gpgrt_b64enc_write (gpgrt_b64state_t state, const void *buffer, size_t nbytes) +{ + unsigned char radbuf[4]; + int idx, quad_count; + const unsigned char *p; + + if (state->lasterr) + return state->lasterr; + + if (!nbytes) + { + if (buffer) + if (_gpgrt_fflush (state->stream)) + goto write_error; + return 0; + } + + if (!(state->flags & B64ENC_DID_HEADER)) + { + if (state->title) + { + if ( _gpgrt_fputs ("-----BEGIN ", state->stream) == EOF + || _gpgrt_fputs (state->title, state->stream) == EOF + || _gpgrt_fputs ("-----\n", state->stream) == EOF) + goto write_error; + if ( (state->flags & B64ENC_USE_PGPCRC) + && _gpgrt_fputs ("\n", state->stream) == EOF) + goto write_error; + } + + state->flags |= B64ENC_DID_HEADER; + } + + idx = state->idx; + quad_count = state->quad_count; + gpgrt_assert (idx < 4); + memcpy (radbuf, state->radbuf, idx); + + if ( (state->flags & B64ENC_USE_PGPCRC) ) + { + size_t n; + uint32_t crc = state->crc; + + for (p=buffer, n=nbytes; n; p++, n-- ) + crc = ((uint32_t)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p]; + state->crc = (crc & 0x00ffffff); + } + + for (p=buffer; nbytes; p++, nbytes--) + { + radbuf[idx++] = *p; + if (idx > 2) + { + char tmp[4]; + + tmp[0] = bintoasc[(*radbuf >> 2) & 077]; + tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; + tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; + tmp[3] = bintoasc[radbuf[2]&077]; + for (idx=0; idx < 4; idx++) + _gpgrt_fputc (tmp[idx], state->stream); + idx = 0; + if (_gpgrt_ferror (state->stream)) + goto write_error; + + if (++quad_count >= (64/4)) + { + quad_count = 0; + if (!(state->flags & B64ENC_NO_LINEFEEDS) + && _gpgrt_fputs ("\n", state->stream) == EOF) + goto write_error; + } + } + } + memcpy (state->radbuf, radbuf, idx); + state->idx = idx; + state->quad_count = quad_count; + return 0; + + write_error: + state->lasterr = _gpg_err_code_from_syserror (); + if (state->title) + { + xfree (state->title); + state->title = NULL; + } + return state->lasterr; +} + + +gpg_err_code_t +_gpgrt_b64enc_finish (gpgrt_b64state_t state) +{ + gpg_err_code_t err = 0; + unsigned char radbuf[4]; + int idx, quad_count; + char tmp[4]; + + if (!state) + return 0; /* Already released. */ + + if (state->using_decoder) + { + err = GPG_ERR_CONFLICT; /* State was created for the decoder. */ + goto cleanup; + } + + if (state->lasterr) + { + err = state->lasterr; + goto cleanup; + } + + if (!(state->flags & B64ENC_DID_HEADER)) + goto cleanup; + + /* Flush the base64 encoding */ + idx = state->idx; + quad_count = state->quad_count; + gpgrt_assert (idx < 4); + memcpy (radbuf, state->radbuf, idx); + + if (idx) + { + tmp[0] = bintoasc[(*radbuf>>2)&077]; + if (idx == 1) + { + tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077]; + tmp[2] = '='; + tmp[3] = '='; + } + else + { + tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; + tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077]; + tmp[3] = '='; + } + for (idx=0; idx < 4; idx++) + _gpgrt_fputc (tmp[idx], state->stream); + if (_gpgrt_ferror (state->stream)) + goto write_error; + + if (++quad_count >= (64/4)) + { + quad_count = 0; + if (!(state->flags & B64ENC_NO_LINEFEEDS) + && _gpgrt_fputs ("\n", state->stream) == EOF) + goto write_error; + } + } + + /* Finish the last line and write the trailer. */ + if (quad_count + && !(state->flags & B64ENC_NO_LINEFEEDS) + && _gpgrt_fputs ("\n", state->stream) == EOF) + goto write_error; + + if ( (state->flags & B64ENC_USE_PGPCRC) ) + { + /* Write the CRC. */ + _gpgrt_fputs ("=", state->stream); + radbuf[0] = state->crc >>16; + radbuf[1] = state->crc >> 8; + radbuf[2] = state->crc; + tmp[0] = bintoasc[(*radbuf>>2)&077]; + tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; + tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; + tmp[3] = bintoasc[radbuf[2]&077]; + for (idx=0; idx < 4; idx++) + _gpgrt_fputc (tmp[idx], state->stream); + if (_gpgrt_ferror (state->stream)) + goto write_error; + + if (!(state->flags & B64ENC_NO_LINEFEEDS) + && _gpgrt_fputs ("\n", state->stream) == EOF) + goto write_error; + } + + if (state->title) + { + if ( _gpgrt_fputs ("-----END ", state->stream) == EOF + || _gpgrt_fputs (state->title, state->stream) == EOF + || _gpgrt_fputs ("-----\n", state->stream) == EOF) + goto write_error; + } + + cleanup: + xfree (state->title); + xfree (state); + return err; + + write_error: + err = gpg_error_from_syserror (); + goto cleanup; +} diff --git a/comm/third_party/libgpg-error/src/code-from-errno.c b/comm/third_party/libgpg-error/src/code-from-errno.c new file mode 100644 index 0000000000..6064270594 --- /dev/null +++ b/comm/third_party/libgpg-error/src/code-from-errno.c @@ -0,0 +1,69 @@ +/* code-from-errno.c - Mapping errnos to error codes. + Copyright (C) 2003 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "code-from-errno.h" + +/* Retrieve the error code for the system error ERR. This returns + GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report + this). */ +gpg_err_code_t +_gpg_err_code_from_errno (int err) +{ + int idx; + + if (!err) + return GPG_ERR_NO_ERROR; + + idx = errno_to_idx (err); + + if (idx < 0) + return GPG_ERR_UNKNOWN_ERRNO; + + return GPG_ERR_SYSTEM_ERROR | err_code_from_index[idx]; +} + + +/* Retrieve the error code directly from the ERRNO variable. This + returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped + (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */ +gpg_err_code_t +_gpg_err_code_from_syserror (void) +{ + int err = errno; + int idx; + + if (!err) + return GPG_ERR_MISSING_ERRNO; + + idx = errno_to_idx (err); + + if (idx < 0) + return GPG_ERR_UNKNOWN_ERRNO; + + return GPG_ERR_SYSTEM_ERROR | err_code_from_index[idx]; +} diff --git a/comm/third_party/libgpg-error/src/code-to-errno.c b/comm/third_party/libgpg-error/src/code-to-errno.c new file mode 100644 index 0000000000..6ba6d8788d --- /dev/null +++ b/comm/third_party/libgpg-error/src/code-to-errno.c @@ -0,0 +1,42 @@ +/* code-to-errno.c - Mapping error codes to errnos. + Copyright (C) 2003 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include "code-to-errno.h" + +/* Retrieve the system error for the error code CODE. This returns 0 + if CODE is not a system error code. */ +int +_gpg_err_code_to_errno (gpg_err_code_t code) +{ + if (!(code & GPG_ERR_SYSTEM_ERROR)) + return 0; + code &= ~GPG_ERR_SYSTEM_ERROR; + + if (code < sizeof (err_code_to_errno) / sizeof (err_code_to_errno[0])) + return err_code_to_errno[code]; + else + return 0; +} diff --git a/comm/third_party/libgpg-error/src/err-codes.h b/comm/third_party/libgpg-error/src/err-codes.h new file mode 100644 index 0000000000..c4786c91c8 --- /dev/null +++ b/comm/third_party/libgpg-error/src/err-codes.h @@ -0,0 +1,936 @@ +/* Output of mkstrtable.awk. DO NOT EDIT. */ + +/* err-codes.h - List of error codes and their description. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +/* The purpose of this complex string table is to produce + optimal code with a minimum of relocations. */ + +static const char msgstr[] = + gettext_noop ("Success") "\0" + gettext_noop ("General error") "\0" + gettext_noop ("Unknown packet") "\0" + gettext_noop ("Unknown version in packet") "\0" + gettext_noop ("Invalid public key algorithm") "\0" + gettext_noop ("Invalid digest algorithm") "\0" + gettext_noop ("Bad public key") "\0" + gettext_noop ("Bad secret key") "\0" + gettext_noop ("Bad signature") "\0" + gettext_noop ("No public key") "\0" + gettext_noop ("Checksum error") "\0" + gettext_noop ("Bad passphrase") "\0" + gettext_noop ("Invalid cipher algorithm") "\0" + gettext_noop ("Cannot open keyring") "\0" + gettext_noop ("Invalid packet") "\0" + gettext_noop ("Invalid armor") "\0" + gettext_noop ("No user ID") "\0" + gettext_noop ("No secret key") "\0" + gettext_noop ("Wrong secret key used") "\0" + gettext_noop ("Bad session key") "\0" + gettext_noop ("Unknown compression algorithm") "\0" + gettext_noop ("Number is not prime") "\0" + gettext_noop ("Invalid encoding method") "\0" + gettext_noop ("Invalid encryption scheme") "\0" + gettext_noop ("Invalid signature scheme") "\0" + gettext_noop ("Invalid attribute") "\0" + gettext_noop ("No value") "\0" + gettext_noop ("Not found") "\0" + gettext_noop ("Value not found") "\0" + gettext_noop ("Syntax error") "\0" + gettext_noop ("Bad MPI value") "\0" + gettext_noop ("Invalid passphrase") "\0" + gettext_noop ("Invalid signature class") "\0" + gettext_noop ("Resources exhausted") "\0" + gettext_noop ("Invalid keyring") "\0" + gettext_noop ("Trust DB error") "\0" + gettext_noop ("Bad certificate") "\0" + gettext_noop ("Invalid user ID") "\0" + gettext_noop ("Unexpected error") "\0" + gettext_noop ("Time conflict") "\0" + gettext_noop ("Keyserver error") "\0" + gettext_noop ("Wrong public key algorithm") "\0" + gettext_noop ("Tribute to D. A.") "\0" + gettext_noop ("Weak encryption key") "\0" + gettext_noop ("Invalid key length") "\0" + gettext_noop ("Invalid argument") "\0" + gettext_noop ("Syntax error in URI") "\0" + gettext_noop ("Invalid URI") "\0" + gettext_noop ("Network error") "\0" + gettext_noop ("Unknown host") "\0" + gettext_noop ("Selftest failed") "\0" + gettext_noop ("Data not encrypted") "\0" + gettext_noop ("Data not processed") "\0" + gettext_noop ("Unusable public key") "\0" + gettext_noop ("Unusable secret key") "\0" + gettext_noop ("Invalid value") "\0" + gettext_noop ("Bad certificate chain") "\0" + gettext_noop ("Missing certificate") "\0" + gettext_noop ("No data") "\0" + gettext_noop ("Bug") "\0" + gettext_noop ("Not supported") "\0" + gettext_noop ("Invalid operation code") "\0" + gettext_noop ("Timeout") "\0" + gettext_noop ("Internal error") "\0" + gettext_noop ("EOF (gcrypt)") "\0" + gettext_noop ("Invalid object") "\0" + gettext_noop ("Provided object is too short") "\0" + gettext_noop ("Provided object is too large") "\0" + gettext_noop ("Missing item in object") "\0" + gettext_noop ("Not implemented") "\0" + gettext_noop ("Conflicting use") "\0" + gettext_noop ("Invalid cipher mode") "\0" + gettext_noop ("Invalid flag") "\0" + gettext_noop ("Invalid handle") "\0" + gettext_noop ("Result truncated") "\0" + gettext_noop ("Incomplete line") "\0" + gettext_noop ("Invalid response") "\0" + gettext_noop ("No agent running") "\0" + gettext_noop ("Agent error") "\0" + gettext_noop ("Invalid data") "\0" + gettext_noop ("Unspecific Assuan server fault") "\0" + gettext_noop ("General Assuan error") "\0" + gettext_noop ("Invalid session key") "\0" + gettext_noop ("Invalid S-expression") "\0" + gettext_noop ("Unsupported algorithm") "\0" + gettext_noop ("No pinentry") "\0" + gettext_noop ("pinentry error") "\0" + gettext_noop ("Bad PIN") "\0" + gettext_noop ("Invalid name") "\0" + gettext_noop ("Bad data") "\0" + gettext_noop ("Invalid parameter") "\0" + gettext_noop ("Wrong card") "\0" + gettext_noop ("No dirmngr") "\0" + gettext_noop ("dirmngr error") "\0" + gettext_noop ("Certificate revoked") "\0" + gettext_noop ("No CRL known") "\0" + gettext_noop ("CRL too old") "\0" + gettext_noop ("Line too long") "\0" + gettext_noop ("Not trusted") "\0" + gettext_noop ("Operation cancelled") "\0" + gettext_noop ("Bad CA certificate") "\0" + gettext_noop ("Certificate expired") "\0" + gettext_noop ("Certificate too young") "\0" + gettext_noop ("Unsupported certificate") "\0" + gettext_noop ("Unknown S-expression") "\0" + gettext_noop ("Unsupported protection") "\0" + gettext_noop ("Corrupted protection") "\0" + gettext_noop ("Ambiguous name") "\0" + gettext_noop ("Card error") "\0" + gettext_noop ("Card reset required") "\0" + gettext_noop ("Card removed") "\0" + gettext_noop ("Invalid card") "\0" + gettext_noop ("Card not present") "\0" + gettext_noop ("No PKCS15 application") "\0" + gettext_noop ("Not confirmed") "\0" + gettext_noop ("Configuration error") "\0" + gettext_noop ("No policy match") "\0" + gettext_noop ("Invalid index") "\0" + gettext_noop ("Invalid ID") "\0" + gettext_noop ("No SmartCard daemon") "\0" + gettext_noop ("SmartCard daemon error") "\0" + gettext_noop ("Unsupported protocol") "\0" + gettext_noop ("Bad PIN method") "\0" + gettext_noop ("Card not initialized") "\0" + gettext_noop ("Unsupported operation") "\0" + gettext_noop ("Wrong key usage") "\0" + gettext_noop ("Nothing found") "\0" + gettext_noop ("Wrong blob type") "\0" + gettext_noop ("Missing value") "\0" + gettext_noop ("Hardware problem") "\0" + gettext_noop ("PIN blocked") "\0" + gettext_noop ("Conditions of use not satisfied") "\0" + gettext_noop ("PINs are not synced") "\0" + gettext_noop ("Invalid CRL") "\0" + gettext_noop ("BER error") "\0" + gettext_noop ("Invalid BER") "\0" + gettext_noop ("Element not found") "\0" + gettext_noop ("Identifier not found") "\0" + gettext_noop ("Invalid tag") "\0" + gettext_noop ("Invalid length") "\0" + gettext_noop ("Invalid key info") "\0" + gettext_noop ("Unexpected tag") "\0" + gettext_noop ("Not DER encoded") "\0" + gettext_noop ("No CMS object") "\0" + gettext_noop ("Invalid CMS object") "\0" + gettext_noop ("Unknown CMS object") "\0" + gettext_noop ("Unsupported CMS object") "\0" + gettext_noop ("Unsupported encoding") "\0" + gettext_noop ("Unsupported CMS version") "\0" + gettext_noop ("Unknown algorithm") "\0" + gettext_noop ("Invalid crypto engine") "\0" + gettext_noop ("Public key not trusted") "\0" + gettext_noop ("Decryption failed") "\0" + gettext_noop ("Key expired") "\0" + gettext_noop ("Signature expired") "\0" + gettext_noop ("Encoding problem") "\0" + gettext_noop ("Invalid state") "\0" + gettext_noop ("Duplicated value") "\0" + gettext_noop ("Missing action") "\0" + gettext_noop ("ASN.1 module not found") "\0" + gettext_noop ("Invalid OID string") "\0" + gettext_noop ("Invalid time") "\0" + gettext_noop ("Invalid CRL object") "\0" + gettext_noop ("Unsupported CRL version") "\0" + gettext_noop ("Invalid certificate object") "\0" + gettext_noop ("Unknown name") "\0" + gettext_noop ("A locale function failed") "\0" + gettext_noop ("Not locked") "\0" + gettext_noop ("Protocol violation") "\0" + gettext_noop ("Invalid MAC") "\0" + gettext_noop ("Invalid request") "\0" + gettext_noop ("Unknown extension") "\0" + gettext_noop ("Unknown critical extension") "\0" + gettext_noop ("Locked") "\0" + gettext_noop ("Unknown option") "\0" + gettext_noop ("Unknown command") "\0" + gettext_noop ("Not operational") "\0" + gettext_noop ("No passphrase given") "\0" + gettext_noop ("No PIN given") "\0" + gettext_noop ("Not enabled") "\0" + gettext_noop ("No crypto engine") "\0" + gettext_noop ("Missing key") "\0" + gettext_noop ("Too many objects") "\0" + gettext_noop ("Limit reached") "\0" + gettext_noop ("Not initialized") "\0" + gettext_noop ("Missing issuer certificate") "\0" + gettext_noop ("No keyserver available") "\0" + gettext_noop ("Invalid elliptic curve") "\0" + gettext_noop ("Unknown elliptic curve") "\0" + gettext_noop ("Duplicated key") "\0" + gettext_noop ("Ambiguous result") "\0" + gettext_noop ("No crypto context") "\0" + gettext_noop ("Wrong crypto context") "\0" + gettext_noop ("Bad crypto context") "\0" + gettext_noop ("Conflict in the crypto context") "\0" + gettext_noop ("Broken public key") "\0" + gettext_noop ("Broken secret key") "\0" + gettext_noop ("Invalid MAC algorithm") "\0" + gettext_noop ("Operation fully cancelled") "\0" + gettext_noop ("Operation not yet finished") "\0" + gettext_noop ("Buffer too short") "\0" + gettext_noop ("Invalid length specifier in S-expression") "\0" + gettext_noop ("String too long in S-expression") "\0" + gettext_noop ("Unmatched parentheses in S-expression") "\0" + gettext_noop ("S-expression not canonical") "\0" + gettext_noop ("Bad character in S-expression") "\0" + gettext_noop ("Bad quotation in S-expression") "\0" + gettext_noop ("Zero prefix in S-expression") "\0" + gettext_noop ("Nested display hints in S-expression") "\0" + gettext_noop ("Unmatched display hints") "\0" + gettext_noop ("Unexpected reserved punctuation in S-expression") "\0" + gettext_noop ("Bad hexadecimal character in S-expression") "\0" + gettext_noop ("Odd hexadecimal numbers in S-expression") "\0" + gettext_noop ("Bad octal character in S-expression") "\0" + gettext_noop ("All subkeys are expired or revoked") "\0" + gettext_noop ("Database is corrupted") "\0" + gettext_noop ("Server indicated a failure") "\0" + gettext_noop ("No name") "\0" + gettext_noop ("No key") "\0" + gettext_noop ("Legacy key") "\0" + gettext_noop ("Request too short") "\0" + gettext_noop ("Request too long") "\0" + gettext_noop ("Object is in termination state") "\0" + gettext_noop ("No certificate chain") "\0" + gettext_noop ("Certificate is too large") "\0" + gettext_noop ("Invalid record") "\0" + gettext_noop ("The MAC does not verify") "\0" + gettext_noop ("Unexpected message") "\0" + gettext_noop ("Compression or decompression failed") "\0" + gettext_noop ("A counter would wrap") "\0" + gettext_noop ("Fatal alert message received") "\0" + gettext_noop ("No cipher algorithm") "\0" + gettext_noop ("Missing client certificate") "\0" + gettext_noop ("Close notification received") "\0" + gettext_noop ("Ticket expired") "\0" + gettext_noop ("Bad ticket") "\0" + gettext_noop ("Unknown identity") "\0" + gettext_noop ("Bad certificate message in handshake") "\0" + gettext_noop ("Bad certificate request message in handshake") "\0" + gettext_noop ("Bad certificate verify message in handshake") "\0" + gettext_noop ("Bad change cipher message in handshake") "\0" + gettext_noop ("Bad client hello message in handshake") "\0" + gettext_noop ("Bad server hello message in handshake") "\0" + gettext_noop ("Bad server hello done message in handshake") "\0" + gettext_noop ("Bad finished message in handshake") "\0" + gettext_noop ("Bad server key exchange message in handshake") "\0" + gettext_noop ("Bad client key exchange message in handshake") "\0" + gettext_noop ("Bogus string") "\0" + gettext_noop ("Forbidden") "\0" + gettext_noop ("Key disabled") "\0" + gettext_noop ("Not possible with a card based key") "\0" + gettext_noop ("Invalid lock object") "\0" + gettext_noop ("True") "\0" + gettext_noop ("False") "\0" + gettext_noop ("General IPC error") "\0" + gettext_noop ("IPC accept call failed") "\0" + gettext_noop ("IPC connect call failed") "\0" + gettext_noop ("Invalid IPC response") "\0" + gettext_noop ("Invalid value passed to IPC") "\0" + gettext_noop ("Incomplete line passed to IPC") "\0" + gettext_noop ("Line passed to IPC too long") "\0" + gettext_noop ("Nested IPC commands") "\0" + gettext_noop ("No data callback in IPC") "\0" + gettext_noop ("No inquire callback in IPC") "\0" + gettext_noop ("Not an IPC server") "\0" + gettext_noop ("Not an IPC client") "\0" + gettext_noop ("Problem starting IPC server") "\0" + gettext_noop ("IPC read error") "\0" + gettext_noop ("IPC write error") "\0" + gettext_noop ("Too much data for IPC layer") "\0" + gettext_noop ("Unexpected IPC command") "\0" + gettext_noop ("Unknown IPC command") "\0" + gettext_noop ("IPC syntax error") "\0" + gettext_noop ("IPC call has been cancelled") "\0" + gettext_noop ("No input source for IPC") "\0" + gettext_noop ("No output source for IPC") "\0" + gettext_noop ("IPC parameter error") "\0" + gettext_noop ("Unknown IPC inquire") "\0" + gettext_noop ("Crypto engine too old") "\0" + gettext_noop ("Screen or window too small") "\0" + gettext_noop ("Screen or window too large") "\0" + gettext_noop ("Required environment variable not set") "\0" + gettext_noop ("User ID already exists") "\0" + gettext_noop ("Name already exists") "\0" + gettext_noop ("Duplicated name") "\0" + gettext_noop ("Object is too young") "\0" + gettext_noop ("Object is too old") "\0" + gettext_noop ("Unknown flag") "\0" + gettext_noop ("Invalid execution order") "\0" + gettext_noop ("Already fetched") "\0" + gettext_noop ("Try again later") "\0" + gettext_noop ("Wrong name") "\0" + gettext_noop ("Not authenticated") "\0" + gettext_noop ("Bad authentication") "\0" + gettext_noop ("No Keybox daemon running") "\0" + gettext_noop ("Keybox daemon error") "\0" + gettext_noop ("Service is not running") "\0" + gettext_noop ("Service error") "\0" + gettext_noop ("System bug detected") "\0" + gettext_noop ("Unknown DNS error") "\0" + gettext_noop ("Invalid DNS section") "\0" + gettext_noop ("Invalid textual address form") "\0" + gettext_noop ("Missing DNS query packet") "\0" + gettext_noop ("Missing DNS answer packet") "\0" + gettext_noop ("Connection closed in DNS") "\0" + gettext_noop ("Verification failed in DNS") "\0" + gettext_noop ("DNS Timeout") "\0" + gettext_noop ("General LDAP error") "\0" + gettext_noop ("General LDAP attribute error") "\0" + gettext_noop ("General LDAP name error") "\0" + gettext_noop ("General LDAP security error") "\0" + gettext_noop ("General LDAP service error") "\0" + gettext_noop ("General LDAP update error") "\0" + gettext_noop ("Experimental LDAP error code") "\0" + gettext_noop ("Private LDAP error code") "\0" + gettext_noop ("Other general LDAP error") "\0" + gettext_noop ("LDAP connecting failed (X)") "\0" + gettext_noop ("LDAP referral limit exceeded") "\0" + gettext_noop ("LDAP client loop") "\0" + gettext_noop ("No LDAP results returned") "\0" + gettext_noop ("LDAP control not found") "\0" + gettext_noop ("Not supported by LDAP") "\0" + gettext_noop ("LDAP connect error") "\0" + gettext_noop ("Out of memory in LDAP") "\0" + gettext_noop ("Bad parameter to an LDAP routine") "\0" + gettext_noop ("User cancelled LDAP operation") "\0" + gettext_noop ("Bad LDAP search filter") "\0" + gettext_noop ("Unknown LDAP authentication method") "\0" + gettext_noop ("Timeout in LDAP") "\0" + gettext_noop ("LDAP decoding error") "\0" + gettext_noop ("LDAP encoding error") "\0" + gettext_noop ("LDAP local error") "\0" + gettext_noop ("Cannot contact LDAP server") "\0" + gettext_noop ("LDAP success") "\0" + gettext_noop ("LDAP operations error") "\0" + gettext_noop ("LDAP protocol error") "\0" + gettext_noop ("Time limit exceeded in LDAP") "\0" + gettext_noop ("Size limit exceeded in LDAP") "\0" + gettext_noop ("LDAP compare false") "\0" + gettext_noop ("LDAP compare true") "\0" + gettext_noop ("LDAP authentication method not supported") "\0" + gettext_noop ("Strong(er) LDAP authentication required") "\0" + gettext_noop ("Partial LDAP results+referral received") "\0" + gettext_noop ("LDAP referral") "\0" + gettext_noop ("Administrative LDAP limit exceeded") "\0" + gettext_noop ("Critical LDAP extension is unavailable") "\0" + gettext_noop ("Confidentiality required by LDAP") "\0" + gettext_noop ("LDAP SASL bind in progress") "\0" + gettext_noop ("No such LDAP attribute") "\0" + gettext_noop ("Undefined LDAP attribute type") "\0" + gettext_noop ("Inappropriate matching in LDAP") "\0" + gettext_noop ("Constraint violation in LDAP") "\0" + gettext_noop ("LDAP type or value exists") "\0" + gettext_noop ("Invalid syntax in LDAP") "\0" + gettext_noop ("No such LDAP object") "\0" + gettext_noop ("LDAP alias problem") "\0" + gettext_noop ("Invalid DN syntax in LDAP") "\0" + gettext_noop ("LDAP entry is a leaf") "\0" + gettext_noop ("LDAP alias dereferencing problem") "\0" + gettext_noop ("LDAP proxy authorization failure (X)") "\0" + gettext_noop ("Inappropriate LDAP authentication") "\0" + gettext_noop ("Invalid LDAP credentials") "\0" + gettext_noop ("Insufficient access for LDAP") "\0" + gettext_noop ("LDAP server is busy") "\0" + gettext_noop ("LDAP server is unavailable") "\0" + gettext_noop ("LDAP server is unwilling to perform") "\0" + gettext_noop ("Loop detected by LDAP") "\0" + gettext_noop ("LDAP naming violation") "\0" + gettext_noop ("LDAP object class violation") "\0" + gettext_noop ("LDAP operation not allowed on non-leaf") "\0" + gettext_noop ("LDAP operation not allowed on RDN") "\0" + gettext_noop ("Already exists (LDAP)") "\0" + gettext_noop ("Cannot modify LDAP object class") "\0" + gettext_noop ("LDAP results too large") "\0" + gettext_noop ("LDAP operation affects multiple DSAs") "\0" + gettext_noop ("Virtual LDAP list view error") "\0" + gettext_noop ("Other LDAP error") "\0" + gettext_noop ("Resources exhausted in LCUP") "\0" + gettext_noop ("Security violation in LCUP") "\0" + gettext_noop ("Invalid data in LCUP") "\0" + gettext_noop ("Unsupported scheme in LCUP") "\0" + gettext_noop ("Reload required in LCUP") "\0" + gettext_noop ("LDAP cancelled") "\0" + gettext_noop ("No LDAP operation to cancel") "\0" + gettext_noop ("Too late to cancel LDAP") "\0" + gettext_noop ("Cannot cancel LDAP") "\0" + gettext_noop ("LDAP assertion failed") "\0" + gettext_noop ("Proxied authorization denied by LDAP") "\0" + gettext_noop ("User defined error code 1") "\0" + gettext_noop ("User defined error code 2") "\0" + gettext_noop ("User defined error code 3") "\0" + gettext_noop ("User defined error code 4") "\0" + gettext_noop ("User defined error code 5") "\0" + gettext_noop ("User defined error code 6") "\0" + gettext_noop ("User defined error code 7") "\0" + gettext_noop ("User defined error code 8") "\0" + gettext_noop ("User defined error code 9") "\0" + gettext_noop ("User defined error code 10") "\0" + gettext_noop ("User defined error code 11") "\0" + gettext_noop ("User defined error code 12") "\0" + gettext_noop ("User defined error code 13") "\0" + gettext_noop ("User defined error code 14") "\0" + gettext_noop ("User defined error code 15") "\0" + gettext_noop ("User defined error code 16") "\0" + gettext_noop ("SQL success") "\0" + gettext_noop ("SQL error") "\0" + gettext_noop ("Internal logic error in SQL library") "\0" + gettext_noop ("Access permission denied (SQL)") "\0" + gettext_noop ("SQL abort was requested") "\0" + gettext_noop ("SQL database file is locked") "\0" + gettext_noop ("An SQL table in the database is locked") "\0" + gettext_noop ("SQL library ran out of core") "\0" + gettext_noop ("Attempt to write a readonly SQL database") "\0" + gettext_noop ("SQL operation terminated by interrupt") "\0" + gettext_noop ("I/O error during SQL operation") "\0" + gettext_noop ("SQL database disk image is malformed") "\0" + gettext_noop ("Unknown opcode in SQL file control") "\0" + gettext_noop ("Insertion failed because SQL database is full") "\0" + gettext_noop ("Unable to open the SQL database file") "\0" + gettext_noop ("SQL database lock protocol error") "\0" + gettext_noop ("(internal SQL code: empty)") "\0" + gettext_noop ("SQL database schema changed") "\0" + gettext_noop ("String or blob exceeds size limit (SQL)") "\0" + gettext_noop ("SQL abort due to constraint violation") "\0" + gettext_noop ("Data type mismatch (SQL)") "\0" + gettext_noop ("SQL library used incorrectly") "\0" + gettext_noop ("SQL library uses unsupported OS features") "\0" + gettext_noop ("Authorization denied (SQL)") "\0" + gettext_noop ("(unused SQL code: format)") "\0" + gettext_noop ("SQL bind parameter out of range") "\0" + gettext_noop ("File opened that is not an SQL database file") "\0" + gettext_noop ("Notifications from SQL logger") "\0" + gettext_noop ("Warnings from SQL logger") "\0" + gettext_noop ("SQL has another row ready") "\0" + gettext_noop ("SQL has finished executing") "\0" + gettext_noop ("System error w/o errno") "\0" + gettext_noop ("Unknown system error") "\0" + gettext_noop ("End of file") "\0" + gettext_noop ("Unknown error code"); + +static const int msgidx[] = + { + 0, + 8, + 22, + 37, + 63, + 92, + 117, + 132, + 147, + 161, + 175, + 190, + 205, + 230, + 250, + 265, + 279, + 290, + 304, + 326, + 342, + 372, + 392, + 416, + 442, + 467, + 485, + 494, + 504, + 520, + 533, + 547, + 566, + 590, + 610, + 626, + 641, + 657, + 673, + 690, + 704, + 720, + 747, + 764, + 784, + 803, + 820, + 840, + 852, + 866, + 879, + 895, + 914, + 933, + 953, + 973, + 987, + 1009, + 1029, + 1037, + 1041, + 1055, + 1078, + 1086, + 1101, + 1114, + 1129, + 1158, + 1187, + 1210, + 1226, + 1242, + 1262, + 1275, + 1290, + 1307, + 1323, + 1340, + 1357, + 1369, + 1382, + 1413, + 1434, + 1454, + 1475, + 1497, + 1509, + 1524, + 1532, + 1545, + 1554, + 1572, + 1583, + 1594, + 1608, + 1628, + 1641, + 1653, + 1667, + 1679, + 1699, + 1718, + 1738, + 1760, + 1784, + 1805, + 1828, + 1849, + 1864, + 1875, + 1895, + 1908, + 1921, + 1938, + 1960, + 1974, + 1994, + 2010, + 2024, + 2035, + 2055, + 2078, + 2099, + 2114, + 2135, + 2157, + 2173, + 2187, + 2203, + 2217, + 2234, + 2246, + 2278, + 2298, + 2310, + 2320, + 2332, + 2350, + 2371, + 2383, + 2398, + 2415, + 2430, + 2446, + 2460, + 2479, + 2498, + 2521, + 2542, + 2566, + 2584, + 2606, + 2629, + 2647, + 2659, + 2677, + 2694, + 2708, + 2725, + 2740, + 2763, + 2782, + 2795, + 2814, + 2838, + 2865, + 2878, + 2903, + 2914, + 2933, + 2945, + 2961, + 2979, + 3006, + 3013, + 3028, + 3044, + 3060, + 3080, + 3093, + 3105, + 3122, + 3134, + 3151, + 3165, + 3181, + 3208, + 3231, + 3254, + 3277, + 3292, + 3309, + 3327, + 3348, + 3367, + 3398, + 3416, + 3434, + 3456, + 3482, + 3509, + 3526, + 3567, + 3599, + 3637, + 3664, + 3694, + 3724, + 3752, + 3789, + 3813, + 3861, + 3903, + 3943, + 3979, + 4014, + 4036, + 4063, + 4071, + 4078, + 4089, + 4107, + 4124, + 4155, + 4176, + 4201, + 4216, + 4240, + 4259, + 4295, + 4316, + 4345, + 4365, + 4392, + 4420, + 4435, + 4446, + 4463, + 4500, + 4545, + 4589, + 4628, + 4666, + 4704, + 4747, + 4781, + 4826, + 4871, + 4884, + 4894, + 4907, + 4942, + 4962, + 4967, + 4973, + 4991, + 5014, + 5038, + 5059, + 5087, + 5117, + 5145, + 5165, + 5189, + 5216, + 5234, + 5252, + 5280, + 5295, + 5311, + 5339, + 5362, + 5382, + 5399, + 5427, + 5451, + 5476, + 5496, + 5516, + 5538, + 5565, + 5592, + 5630, + 5653, + 5673, + 5689, + 5709, + 5727, + 5740, + 5764, + 5780, + 5796, + 5807, + 5825, + 5844, + 5869, + 5889, + 5912, + 5926, + 5946, + 5964, + 5984, + 6013, + 6038, + 6064, + 6089, + 6116, + 6128, + 6147, + 6176, + 6200, + 6228, + 6255, + 6281, + 6310, + 6334, + 6359, + 6386, + 6415, + 6432, + 6457, + 6480, + 6502, + 6521, + 6543, + 6576, + 6606, + 6629, + 6664, + 6680, + 6700, + 6720, + 6737, + 6764, + 6777, + 6799, + 6819, + 6847, + 6875, + 6894, + 6912, + 6953, + 6993, + 7032, + 7046, + 7081, + 7120, + 7153, + 7180, + 7203, + 7233, + 7264, + 7293, + 7319, + 7342, + 7362, + 7381, + 7407, + 7428, + 7461, + 7498, + 7532, + 7557, + 7586, + 7606, + 7633, + 7669, + 7691, + 7713, + 7741, + 7780, + 7814, + 7836, + 7868, + 7891, + 7928, + 7957, + 7974, + 8002, + 8029, + 8050, + 8077, + 8101, + 8116, + 8144, + 8168, + 8187, + 8209, + 8246, + 8272, + 8298, + 8324, + 8350, + 8376, + 8402, + 8428, + 8454, + 8480, + 8507, + 8534, + 8561, + 8588, + 8615, + 8642, + 8669, + 8681, + 8691, + 8727, + 8758, + 8782, + 8810, + 8849, + 8877, + 8918, + 8956, + 8987, + 9024, + 9059, + 9105, + 9142, + 9175, + 9202, + 9230, + 9270, + 9308, + 9333, + 9362, + 9403, + 9430, + 9456, + 9488, + 9533, + 9563, + 9588, + 9614, + 9641, + 9664, + 9685, + 9697 + }; + +static GPG_ERR_INLINE int +msgidxof (int code) +{ + return (0 ? 0 + : ((code >= 0) && (code <= 213)) ? (code - 0) + : ((code >= 217) && (code <= 271)) ? (code - 3) + : ((code >= 273) && (code <= 281)) ? (code - 4) + : ((code >= 300) && (code <= 319)) ? (code - 22) + : ((code >= 666) && (code <= 666)) ? (code - 368) + : ((code >= 711) && (code <= 718)) ? (code - 412) + : ((code >= 721) && (code <= 729)) ? (code - 414) + : ((code >= 750) && (code <= 752)) ? (code - 434) + : ((code >= 754) && (code <= 782)) ? (code - 435) + : ((code >= 784) && (code <= 789)) ? (code - 436) + : ((code >= 800) && (code <= 804)) ? (code - 446) + : ((code >= 815) && (code <= 822)) ? (code - 456) + : ((code >= 832) && (code <= 839)) ? (code - 465) + : ((code >= 844) && (code <= 844)) ? (code - 469) + : ((code >= 848) && (code <= 848)) ? (code - 472) + : ((code >= 881) && (code <= 891)) ? (code - 504) + : ((code >= 1024) && (code <= 1039)) ? (code - 636) + : ((code >= 1500) && (code <= 1528)) ? (code - 1096) + : ((code >= 1600) && (code <= 1601)) ? (code - 1167) + : ((code >= 16381) && (code <= 16383)) ? (code - 15946) + : 16384 - 15946); +} diff --git a/comm/third_party/libgpg-error/src/err-codes.h.in b/comm/third_party/libgpg-error/src/err-codes.h.in new file mode 100644 index 0000000000..c65775f72c --- /dev/null +++ b/comm/third_party/libgpg-error/src/err-codes.h.in @@ -0,0 +1,527 @@ +# err-codes.h.in - List of error codes and their description input file. +/* err-codes.h - List of error codes and their description. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +# Everything up to the first line that starts with a number in the +# first column is copied into the output verbatim. Then, empty lines +# are ignored. Other lines must have an error code number, followed +# by one or more characters, followed by the error code symbol, +# followed by one or more characters, followed by the error +# message. Trailing whitespace is removed. The error codes should be +# sorted. The last line should not have a number, but only a , +# followed by a dummy field, followed by a , followed by a +# description for error codes that are not in the list. + +0 GPG_ERR_NO_ERROR Success +1 GPG_ERR_GENERAL General error +2 GPG_ERR_UNKNOWN_PACKET Unknown packet +3 GPG_ERR_UNKNOWN_VERSION Unknown version in packet +4 GPG_ERR_PUBKEY_ALGO Invalid public key algorithm +5 GPG_ERR_DIGEST_ALGO Invalid digest algorithm +6 GPG_ERR_BAD_PUBKEY Bad public key +7 GPG_ERR_BAD_SECKEY Bad secret key +8 GPG_ERR_BAD_SIGNATURE Bad signature +9 GPG_ERR_NO_PUBKEY No public key +10 GPG_ERR_CHECKSUM Checksum error +11 GPG_ERR_BAD_PASSPHRASE Bad passphrase +12 GPG_ERR_CIPHER_ALGO Invalid cipher algorithm +13 GPG_ERR_KEYRING_OPEN Cannot open keyring +14 GPG_ERR_INV_PACKET Invalid packet +15 GPG_ERR_INV_ARMOR Invalid armor +16 GPG_ERR_NO_USER_ID No user ID +17 GPG_ERR_NO_SECKEY No secret key +18 GPG_ERR_WRONG_SECKEY Wrong secret key used +19 GPG_ERR_BAD_KEY Bad session key +20 GPG_ERR_COMPR_ALGO Unknown compression algorithm +21 GPG_ERR_NO_PRIME Number is not prime +22 GPG_ERR_NO_ENCODING_METHOD Invalid encoding method +23 GPG_ERR_NO_ENCRYPTION_SCHEME Invalid encryption scheme +24 GPG_ERR_NO_SIGNATURE_SCHEME Invalid signature scheme +25 GPG_ERR_INV_ATTR Invalid attribute +26 GPG_ERR_NO_VALUE No value +27 GPG_ERR_NOT_FOUND Not found +28 GPG_ERR_VALUE_NOT_FOUND Value not found +29 GPG_ERR_SYNTAX Syntax error +30 GPG_ERR_BAD_MPI Bad MPI value +31 GPG_ERR_INV_PASSPHRASE Invalid passphrase +32 GPG_ERR_SIG_CLASS Invalid signature class +33 GPG_ERR_RESOURCE_LIMIT Resources exhausted +34 GPG_ERR_INV_KEYRING Invalid keyring +35 GPG_ERR_TRUSTDB Trust DB error +36 GPG_ERR_BAD_CERT Bad certificate +37 GPG_ERR_INV_USER_ID Invalid user ID +38 GPG_ERR_UNEXPECTED Unexpected error +39 GPG_ERR_TIME_CONFLICT Time conflict +40 GPG_ERR_KEYSERVER Keyserver error +41 GPG_ERR_WRONG_PUBKEY_ALGO Wrong public key algorithm +42 GPG_ERR_TRIBUTE_TO_D_A Tribute to D. A. +43 GPG_ERR_WEAK_KEY Weak encryption key +44 GPG_ERR_INV_KEYLEN Invalid key length +45 GPG_ERR_INV_ARG Invalid argument +46 GPG_ERR_BAD_URI Syntax error in URI +47 GPG_ERR_INV_URI Invalid URI +48 GPG_ERR_NETWORK Network error +49 GPG_ERR_UNKNOWN_HOST Unknown host +50 GPG_ERR_SELFTEST_FAILED Selftest failed +51 GPG_ERR_NOT_ENCRYPTED Data not encrypted +52 GPG_ERR_NOT_PROCESSED Data not processed +53 GPG_ERR_UNUSABLE_PUBKEY Unusable public key +54 GPG_ERR_UNUSABLE_SECKEY Unusable secret key +55 GPG_ERR_INV_VALUE Invalid value +56 GPG_ERR_BAD_CERT_CHAIN Bad certificate chain +57 GPG_ERR_MISSING_CERT Missing certificate +58 GPG_ERR_NO_DATA No data +59 GPG_ERR_BUG Bug +60 GPG_ERR_NOT_SUPPORTED Not supported +61 GPG_ERR_INV_OP Invalid operation code +62 GPG_ERR_TIMEOUT Timeout +63 GPG_ERR_INTERNAL Internal error +64 GPG_ERR_EOF_GCRYPT EOF (gcrypt) +65 GPG_ERR_INV_OBJ Invalid object +66 GPG_ERR_TOO_SHORT Provided object is too short +67 GPG_ERR_TOO_LARGE Provided object is too large +68 GPG_ERR_NO_OBJ Missing item in object +69 GPG_ERR_NOT_IMPLEMENTED Not implemented +70 GPG_ERR_CONFLICT Conflicting use +71 GPG_ERR_INV_CIPHER_MODE Invalid cipher mode +72 GPG_ERR_INV_FLAG Invalid flag +73 GPG_ERR_INV_HANDLE Invalid handle +74 GPG_ERR_TRUNCATED Result truncated +75 GPG_ERR_INCOMPLETE_LINE Incomplete line +76 GPG_ERR_INV_RESPONSE Invalid response +77 GPG_ERR_NO_AGENT No agent running +78 GPG_ERR_AGENT Agent error +79 GPG_ERR_INV_DATA Invalid data +80 GPG_ERR_ASSUAN_SERVER_FAULT Unspecific Assuan server fault +81 GPG_ERR_ASSUAN General Assuan error +82 GPG_ERR_INV_SESSION_KEY Invalid session key +83 GPG_ERR_INV_SEXP Invalid S-expression +84 GPG_ERR_UNSUPPORTED_ALGORITHM Unsupported algorithm +85 GPG_ERR_NO_PIN_ENTRY No pinentry +86 GPG_ERR_PIN_ENTRY pinentry error +87 GPG_ERR_BAD_PIN Bad PIN +88 GPG_ERR_INV_NAME Invalid name +89 GPG_ERR_BAD_DATA Bad data +90 GPG_ERR_INV_PARAMETER Invalid parameter +91 GPG_ERR_WRONG_CARD Wrong card +92 GPG_ERR_NO_DIRMNGR No dirmngr +93 GPG_ERR_DIRMNGR dirmngr error +94 GPG_ERR_CERT_REVOKED Certificate revoked +95 GPG_ERR_NO_CRL_KNOWN No CRL known +96 GPG_ERR_CRL_TOO_OLD CRL too old +97 GPG_ERR_LINE_TOO_LONG Line too long +98 GPG_ERR_NOT_TRUSTED Not trusted +99 GPG_ERR_CANCELED Operation cancelled +100 GPG_ERR_BAD_CA_CERT Bad CA certificate +101 GPG_ERR_CERT_EXPIRED Certificate expired +102 GPG_ERR_CERT_TOO_YOUNG Certificate too young +103 GPG_ERR_UNSUPPORTED_CERT Unsupported certificate +104 GPG_ERR_UNKNOWN_SEXP Unknown S-expression +105 GPG_ERR_UNSUPPORTED_PROTECTION Unsupported protection +106 GPG_ERR_CORRUPTED_PROTECTION Corrupted protection +107 GPG_ERR_AMBIGUOUS_NAME Ambiguous name +108 GPG_ERR_CARD Card error +109 GPG_ERR_CARD_RESET Card reset required +110 GPG_ERR_CARD_REMOVED Card removed +111 GPG_ERR_INV_CARD Invalid card +112 GPG_ERR_CARD_NOT_PRESENT Card not present +113 GPG_ERR_NO_PKCS15_APP No PKCS15 application +114 GPG_ERR_NOT_CONFIRMED Not confirmed +115 GPG_ERR_CONFIGURATION Configuration error +116 GPG_ERR_NO_POLICY_MATCH No policy match +117 GPG_ERR_INV_INDEX Invalid index +118 GPG_ERR_INV_ID Invalid ID +119 GPG_ERR_NO_SCDAEMON No SmartCard daemon +120 GPG_ERR_SCDAEMON SmartCard daemon error +121 GPG_ERR_UNSUPPORTED_PROTOCOL Unsupported protocol +122 GPG_ERR_BAD_PIN_METHOD Bad PIN method +123 GPG_ERR_CARD_NOT_INITIALIZED Card not initialized +124 GPG_ERR_UNSUPPORTED_OPERATION Unsupported operation +125 GPG_ERR_WRONG_KEY_USAGE Wrong key usage +126 GPG_ERR_NOTHING_FOUND Nothing found +127 GPG_ERR_WRONG_BLOB_TYPE Wrong blob type +128 GPG_ERR_MISSING_VALUE Missing value +129 GPG_ERR_HARDWARE Hardware problem +130 GPG_ERR_PIN_BLOCKED PIN blocked +131 GPG_ERR_USE_CONDITIONS Conditions of use not satisfied +132 GPG_ERR_PIN_NOT_SYNCED PINs are not synced +133 GPG_ERR_INV_CRL Invalid CRL +134 GPG_ERR_BAD_BER BER error +135 GPG_ERR_INV_BER Invalid BER +136 GPG_ERR_ELEMENT_NOT_FOUND Element not found +137 GPG_ERR_IDENTIFIER_NOT_FOUND Identifier not found +138 GPG_ERR_INV_TAG Invalid tag +139 GPG_ERR_INV_LENGTH Invalid length +140 GPG_ERR_INV_KEYINFO Invalid key info +141 GPG_ERR_UNEXPECTED_TAG Unexpected tag +142 GPG_ERR_NOT_DER_ENCODED Not DER encoded +143 GPG_ERR_NO_CMS_OBJ No CMS object +144 GPG_ERR_INV_CMS_OBJ Invalid CMS object +145 GPG_ERR_UNKNOWN_CMS_OBJ Unknown CMS object +146 GPG_ERR_UNSUPPORTED_CMS_OBJ Unsupported CMS object +147 GPG_ERR_UNSUPPORTED_ENCODING Unsupported encoding +148 GPG_ERR_UNSUPPORTED_CMS_VERSION Unsupported CMS version +149 GPG_ERR_UNKNOWN_ALGORITHM Unknown algorithm +150 GPG_ERR_INV_ENGINE Invalid crypto engine +151 GPG_ERR_PUBKEY_NOT_TRUSTED Public key not trusted +152 GPG_ERR_DECRYPT_FAILED Decryption failed +153 GPG_ERR_KEY_EXPIRED Key expired +154 GPG_ERR_SIG_EXPIRED Signature expired +155 GPG_ERR_ENCODING_PROBLEM Encoding problem +156 GPG_ERR_INV_STATE Invalid state +157 GPG_ERR_DUP_VALUE Duplicated value +158 GPG_ERR_MISSING_ACTION Missing action +159 GPG_ERR_MODULE_NOT_FOUND ASN.1 module not found +160 GPG_ERR_INV_OID_STRING Invalid OID string +161 GPG_ERR_INV_TIME Invalid time +162 GPG_ERR_INV_CRL_OBJ Invalid CRL object +163 GPG_ERR_UNSUPPORTED_CRL_VERSION Unsupported CRL version +164 GPG_ERR_INV_CERT_OBJ Invalid certificate object +165 GPG_ERR_UNKNOWN_NAME Unknown name +166 GPG_ERR_LOCALE_PROBLEM A locale function failed +167 GPG_ERR_NOT_LOCKED Not locked +168 GPG_ERR_PROTOCOL_VIOLATION Protocol violation +169 GPG_ERR_INV_MAC Invalid MAC +170 GPG_ERR_INV_REQUEST Invalid request +171 GPG_ERR_UNKNOWN_EXTN Unknown extension +172 GPG_ERR_UNKNOWN_CRIT_EXTN Unknown critical extension +173 GPG_ERR_LOCKED Locked +174 GPG_ERR_UNKNOWN_OPTION Unknown option +175 GPG_ERR_UNKNOWN_COMMAND Unknown command +176 GPG_ERR_NOT_OPERATIONAL Not operational +177 GPG_ERR_NO_PASSPHRASE No passphrase given +178 GPG_ERR_NO_PIN No PIN given +179 GPG_ERR_NOT_ENABLED Not enabled +180 GPG_ERR_NO_ENGINE No crypto engine +181 GPG_ERR_MISSING_KEY Missing key +182 GPG_ERR_TOO_MANY Too many objects +183 GPG_ERR_LIMIT_REACHED Limit reached +184 GPG_ERR_NOT_INITIALIZED Not initialized +185 GPG_ERR_MISSING_ISSUER_CERT Missing issuer certificate +186 GPG_ERR_NO_KEYSERVER No keyserver available +187 GPG_ERR_INV_CURVE Invalid elliptic curve +188 GPG_ERR_UNKNOWN_CURVE Unknown elliptic curve +189 GPG_ERR_DUP_KEY Duplicated key +190 GPG_ERR_AMBIGUOUS Ambiguous result +191 GPG_ERR_NO_CRYPT_CTX No crypto context +192 GPG_ERR_WRONG_CRYPT_CTX Wrong crypto context +193 GPG_ERR_BAD_CRYPT_CTX Bad crypto context +194 GPG_ERR_CRYPT_CTX_CONFLICT Conflict in the crypto context +195 GPG_ERR_BROKEN_PUBKEY Broken public key +196 GPG_ERR_BROKEN_SECKEY Broken secret key +197 GPG_ERR_MAC_ALGO Invalid MAC algorithm +198 GPG_ERR_FULLY_CANCELED Operation fully cancelled +199 GPG_ERR_UNFINISHED Operation not yet finished +200 GPG_ERR_BUFFER_TOO_SHORT Buffer too short + +# Error codes pertaining to S-expressions. + +201 GPG_ERR_SEXP_INV_LEN_SPEC Invalid length specifier in S-expression +202 GPG_ERR_SEXP_STRING_TOO_LONG String too long in S-expression +203 GPG_ERR_SEXP_UNMATCHED_PAREN Unmatched parentheses in S-expression +204 GPG_ERR_SEXP_NOT_CANONICAL S-expression not canonical +205 GPG_ERR_SEXP_BAD_CHARACTER Bad character in S-expression +206 GPG_ERR_SEXP_BAD_QUOTATION Bad quotation in S-expression +207 GPG_ERR_SEXP_ZERO_PREFIX Zero prefix in S-expression +208 GPG_ERR_SEXP_NESTED_DH Nested display hints in S-expression +209 GPG_ERR_SEXP_UNMATCHED_DH Unmatched display hints +210 GPG_ERR_SEXP_UNEXPECTED_PUNC Unexpected reserved punctuation in S-expression +211 GPG_ERR_SEXP_BAD_HEX_CHAR Bad hexadecimal character in S-expression +212 GPG_ERR_SEXP_ODD_HEX_NUMBERS Odd hexadecimal numbers in S-expression +213 GPG_ERR_SEXP_BAD_OCT_CHAR Bad octal character in S-expression + +# 214 to 216 are free to be used. +217 GPG_ERR_SUBKEYS_EXP_OR_REV All subkeys are expired or revoked +218 GPG_ERR_DB_CORRUPTED Database is corrupted +219 GPG_ERR_SERVER_FAILED Server indicated a failure +220 GPG_ERR_NO_NAME No name +221 GPG_ERR_NO_KEY No key +222 GPG_ERR_LEGACY_KEY Legacy key +223 GPG_ERR_REQUEST_TOO_SHORT Request too short +224 GPG_ERR_REQUEST_TOO_LONG Request too long +225 GPG_ERR_OBJ_TERM_STATE Object is in termination state +226 GPG_ERR_NO_CERT_CHAIN No certificate chain +227 GPG_ERR_CERT_TOO_LARGE Certificate is too large +228 GPG_ERR_INV_RECORD Invalid record +229 GPG_ERR_BAD_MAC The MAC does not verify +230 GPG_ERR_UNEXPECTED_MSG Unexpected message +231 GPG_ERR_COMPR_FAILED Compression or decompression failed +232 GPG_ERR_WOULD_WRAP A counter would wrap +233 GPG_ERR_FATAL_ALERT Fatal alert message received +234 GPG_ERR_NO_CIPHER No cipher algorithm +235 GPG_ERR_MISSING_CLIENT_CERT Missing client certificate +236 GPG_ERR_CLOSE_NOTIFY Close notification received +237 GPG_ERR_TICKET_EXPIRED Ticket expired +238 GPG_ERR_BAD_TICKET Bad ticket +239 GPG_ERR_UNKNOWN_IDENTITY Unknown identity +240 GPG_ERR_BAD_HS_CERT Bad certificate message in handshake +241 GPG_ERR_BAD_HS_CERT_REQ Bad certificate request message in handshake +242 GPG_ERR_BAD_HS_CERT_VER Bad certificate verify message in handshake +243 GPG_ERR_BAD_HS_CHANGE_CIPHER Bad change cipher message in handshake +244 GPG_ERR_BAD_HS_CLIENT_HELLO Bad client hello message in handshake +245 GPG_ERR_BAD_HS_SERVER_HELLO Bad server hello message in handshake +246 GPG_ERR_BAD_HS_SERVER_HELLO_DONE Bad server hello done message in handshake +247 GPG_ERR_BAD_HS_FINISHED Bad finished message in handshake +248 GPG_ERR_BAD_HS_SERVER_KEX Bad server key exchange message in handshake +249 GPG_ERR_BAD_HS_CLIENT_KEX Bad client key exchange message in handshake +250 GPG_ERR_BOGUS_STRING Bogus string +251 GPG_ERR_FORBIDDEN Forbidden +252 GPG_ERR_KEY_DISABLED Key disabled +253 GPG_ERR_KEY_ON_CARD Not possible with a card based key +254 GPG_ERR_INV_LOCK_OBJ Invalid lock object + +255 GPG_ERR_TRUE True +256 GPG_ERR_FALSE False + +# Error codes pertaining to the Assuan IPC interface +257 GPG_ERR_ASS_GENERAL General IPC error +258 GPG_ERR_ASS_ACCEPT_FAILED IPC accept call failed +259 GPG_ERR_ASS_CONNECT_FAILED IPC connect call failed +260 GPG_ERR_ASS_INV_RESPONSE Invalid IPC response +261 GPG_ERR_ASS_INV_VALUE Invalid value passed to IPC +262 GPG_ERR_ASS_INCOMPLETE_LINE Incomplete line passed to IPC +263 GPG_ERR_ASS_LINE_TOO_LONG Line passed to IPC too long +264 GPG_ERR_ASS_NESTED_COMMANDS Nested IPC commands +265 GPG_ERR_ASS_NO_DATA_CB No data callback in IPC +266 GPG_ERR_ASS_NO_INQUIRE_CB No inquire callback in IPC +267 GPG_ERR_ASS_NOT_A_SERVER Not an IPC server +268 GPG_ERR_ASS_NOT_A_CLIENT Not an IPC client +269 GPG_ERR_ASS_SERVER_START Problem starting IPC server +270 GPG_ERR_ASS_READ_ERROR IPC read error +271 GPG_ERR_ASS_WRITE_ERROR IPC write error +# reserved +273 GPG_ERR_ASS_TOO_MUCH_DATA Too much data for IPC layer +274 GPG_ERR_ASS_UNEXPECTED_CMD Unexpected IPC command +275 GPG_ERR_ASS_UNKNOWN_CMD Unknown IPC command +276 GPG_ERR_ASS_SYNTAX IPC syntax error +277 GPG_ERR_ASS_CANCELED IPC call has been cancelled +278 GPG_ERR_ASS_NO_INPUT No input source for IPC +279 GPG_ERR_ASS_NO_OUTPUT No output source for IPC +280 GPG_ERR_ASS_PARAMETER IPC parameter error +281 GPG_ERR_ASS_UNKNOWN_INQUIRE Unknown IPC inquire + +# 282 to 299 are reserved for future assuan codes. + +300 GPG_ERR_ENGINE_TOO_OLD Crypto engine too old +301 GPG_ERR_WINDOW_TOO_SMALL Screen or window too small +302 GPG_ERR_WINDOW_TOO_LARGE Screen or window too large +303 GPG_ERR_MISSING_ENVVAR Required environment variable not set +304 GPG_ERR_USER_ID_EXISTS User ID already exists +305 GPG_ERR_NAME_EXISTS Name already exists +306 GPG_ERR_DUP_NAME Duplicated name +307 GPG_ERR_TOO_YOUNG Object is too young +308 GPG_ERR_TOO_OLD Object is too old +309 GPG_ERR_UNKNOWN_FLAG Unknown flag +310 GPG_ERR_INV_ORDER Invalid execution order +311 GPG_ERR_ALREADY_FETCHED Already fetched +312 GPG_ERR_TRY_LATER Try again later +313 GPG_ERR_WRONG_NAME Wrong name +314 GPG_ERR_NO_AUTH Not authenticated +315 GPG_ERR_BAD_AUTH Bad authentication +316 GPG_ERR_NO_KEYBOXD No Keybox daemon running +317 GPG_ERR_KEYBOXD Keybox daemon error +318 GPG_ERR_NO_SERVICE Service is not running +319 GPG_ERR_SERVICE Service error +# This range is free for use. + +666 GPG_ERR_SYSTEM_BUG System bug detected + +# +# Mapping of some error codes from libdns and other DNS specific error codes +# +711 GPG_ERR_DNS_UNKNOWN Unknown DNS error +712 GPG_ERR_DNS_SECTION Invalid DNS section +713 GPG_ERR_DNS_ADDRESS Invalid textual address form +714 GPG_ERR_DNS_NO_QUERY Missing DNS query packet +715 GPG_ERR_DNS_NO_ANSWER Missing DNS answer packet +716 GPG_ERR_DNS_CLOSED Connection closed in DNS +717 GPG_ERR_DNS_VERIFY Verification failed in DNS +718 GPG_ERR_DNS_TIMEOUT DNS Timeout + +# +# Mapping of LDAP error codes +# +# The numbers reflect the OpenLDAP code with an offset of 768. +# Some error names are shortened +# +721 GPG_ERR_LDAP_GENERAL General LDAP error +722 GPG_ERR_LDAP_ATTR_GENERAL General LDAP attribute error +723 GPG_ERR_LDAP_NAME_GENERAL General LDAP name error +724 GPG_ERR_LDAP_SECURITY_GENERAL General LDAP security error +725 GPG_ERR_LDAP_SERVICE_GENERAL General LDAP service error +726 GPG_ERR_LDAP_UPDATE_GENERAL General LDAP update error +727 GPG_ERR_LDAP_E_GENERAL Experimental LDAP error code +728 GPG_ERR_LDAP_X_GENERAL Private LDAP error code +729 GPG_ERR_LDAP_OTHER_GENERAL Other general LDAP error +# 730 to 749 not used +750 GPG_ERR_LDAP_X_CONNECTING LDAP connecting failed (X) +751 GPG_ERR_LDAP_REFERRAL_LIMIT LDAP referral limit exceeded +752 GPG_ERR_LDAP_CLIENT_LOOP LDAP client loop +# 753 is an obsolete error code +754 GPG_ERR_LDAP_NO_RESULTS No LDAP results returned +755 GPG_ERR_LDAP_CONTROL_NOT_FOUND LDAP control not found +756 GPG_ERR_LDAP_NOT_SUPPORTED Not supported by LDAP +757 GPG_ERR_LDAP_CONNECT LDAP connect error +758 GPG_ERR_LDAP_NO_MEMORY Out of memory in LDAP +759 GPG_ERR_LDAP_PARAM Bad parameter to an LDAP routine +760 GPG_ERR_LDAP_USER_CANCELLED User cancelled LDAP operation +761 GPG_ERR_LDAP_FILTER Bad LDAP search filter +762 GPG_ERR_LDAP_AUTH_UNKNOWN Unknown LDAP authentication method +763 GPG_ERR_LDAP_TIMEOUT Timeout in LDAP +764 GPG_ERR_LDAP_DECODING LDAP decoding error +765 GPG_ERR_LDAP_ENCODING LDAP encoding error +766 GPG_ERR_LDAP_LOCAL LDAP local error +767 GPG_ERR_LDAP_SERVER_DOWN Cannot contact LDAP server +768 GPG_ERR_LDAP_SUCCESS LDAP success +769 GPG_ERR_LDAP_OPERATIONS LDAP operations error +770 GPG_ERR_LDAP_PROTOCOL LDAP protocol error +771 GPG_ERR_LDAP_TIMELIMIT Time limit exceeded in LDAP +772 GPG_ERR_LDAP_SIZELIMIT Size limit exceeded in LDAP +773 GPG_ERR_LDAP_COMPARE_FALSE LDAP compare false +774 GPG_ERR_LDAP_COMPARE_TRUE LDAP compare true +775 GPG_ERR_LDAP_UNSUPPORTED_AUTH LDAP authentication method not supported +776 GPG_ERR_LDAP_STRONG_AUTH_RQRD Strong(er) LDAP authentication required +777 GPG_ERR_LDAP_PARTIAL_RESULTS Partial LDAP results+referral received +778 GPG_ERR_LDAP_REFERRAL LDAP referral +779 GPG_ERR_LDAP_ADMINLIMIT Administrative LDAP limit exceeded +780 GPG_ERR_LDAP_UNAVAIL_CRIT_EXTN Critical LDAP extension is unavailable +781 GPG_ERR_LDAP_CONFIDENT_RQRD Confidentiality required by LDAP +782 GPG_ERR_LDAP_SASL_BIND_INPROG LDAP SASL bind in progress +# 783 not used +784 GPG_ERR_LDAP_NO_SUCH_ATTRIBUTE No such LDAP attribute +785 GPG_ERR_LDAP_UNDEFINED_TYPE Undefined LDAP attribute type +786 GPG_ERR_LDAP_BAD_MATCHING Inappropriate matching in LDAP +787 GPG_ERR_LDAP_CONST_VIOLATION Constraint violation in LDAP +788 GPG_ERR_LDAP_TYPE_VALUE_EXISTS LDAP type or value exists +789 GPG_ERR_LDAP_INV_SYNTAX Invalid syntax in LDAP +# 790 to 799 not used +800 GPG_ERR_LDAP_NO_SUCH_OBJ No such LDAP object +801 GPG_ERR_LDAP_ALIAS_PROBLEM LDAP alias problem +802 GPG_ERR_LDAP_INV_DN_SYNTAX Invalid DN syntax in LDAP +803 GPG_ERR_LDAP_IS_LEAF LDAP entry is a leaf +804 GPG_ERR_LDAP_ALIAS_DEREF LDAP alias dereferencing problem +# 805 to 814 not used +815 GPG_ERR_LDAP_X_PROXY_AUTH_FAIL LDAP proxy authorization failure (X) +816 GPG_ERR_LDAP_BAD_AUTH Inappropriate LDAP authentication +817 GPG_ERR_LDAP_INV_CREDENTIALS Invalid LDAP credentials +818 GPG_ERR_LDAP_INSUFFICIENT_ACC Insufficient access for LDAP +819 GPG_ERR_LDAP_BUSY LDAP server is busy +820 GPG_ERR_LDAP_UNAVAILABLE LDAP server is unavailable +821 GPG_ERR_LDAP_UNWILL_TO_PERFORM LDAP server is unwilling to perform +822 GPG_ERR_LDAP_LOOP_DETECT Loop detected by LDAP +# 823 to 831 not used +832 GPG_ERR_LDAP_NAMING_VIOLATION LDAP naming violation +833 GPG_ERR_LDAP_OBJ_CLS_VIOLATION LDAP object class violation +834 GPG_ERR_LDAP_NOT_ALLOW_NONLEAF LDAP operation not allowed on non-leaf +835 GPG_ERR_LDAP_NOT_ALLOW_ON_RDN LDAP operation not allowed on RDN +836 GPG_ERR_LDAP_ALREADY_EXISTS Already exists (LDAP) +837 GPG_ERR_LDAP_NO_OBJ_CLASS_MODS Cannot modify LDAP object class +838 GPG_ERR_LDAP_RESULTS_TOO_LARGE LDAP results too large +839 GPG_ERR_LDAP_AFFECTS_MULT_DSAS LDAP operation affects multiple DSAs +# 840 to 843 not used +844 GPG_ERR_LDAP_VLV Virtual LDAP list view error +# 845 to 847 not used +848 GPG_ERR_LDAP_OTHER Other LDAP error +# 849 to 880 not used +881 GPG_ERR_LDAP_CUP_RESOURCE_LIMIT Resources exhausted in LCUP +882 GPG_ERR_LDAP_CUP_SEC_VIOLATION Security violation in LCUP +883 GPG_ERR_LDAP_CUP_INV_DATA Invalid data in LCUP +884 GPG_ERR_LDAP_CUP_UNSUP_SCHEME Unsupported scheme in LCUP +885 GPG_ERR_LDAP_CUP_RELOAD Reload required in LCUP +886 GPG_ERR_LDAP_CANCELLED LDAP cancelled +887 GPG_ERR_LDAP_NO_SUCH_OPERATION No LDAP operation to cancel +888 GPG_ERR_LDAP_TOO_LATE Too late to cancel LDAP +889 GPG_ERR_LDAP_CANNOT_CANCEL Cannot cancel LDAP +890 GPG_ERR_LDAP_ASSERTION_FAILED LDAP assertion failed +891 GPG_ERR_LDAP_PROX_AUTH_DENIED Proxied authorization denied by LDAP + +# 892 to 950 are reserved for future LDAP codes. + +# 951 to 1023 are free to be used. + +# For free use by non-GnuPG components: +1024 GPG_ERR_USER_1 User defined error code 1 +1025 GPG_ERR_USER_2 User defined error code 2 +1026 GPG_ERR_USER_3 User defined error code 3 +1027 GPG_ERR_USER_4 User defined error code 4 +1028 GPG_ERR_USER_5 User defined error code 5 +1029 GPG_ERR_USER_6 User defined error code 6 +1030 GPG_ERR_USER_7 User defined error code 7 +1031 GPG_ERR_USER_8 User defined error code 8 +1032 GPG_ERR_USER_9 User defined error code 9 +1033 GPG_ERR_USER_10 User defined error code 10 +1034 GPG_ERR_USER_11 User defined error code 11 +1035 GPG_ERR_USER_12 User defined error code 12 +1036 GPG_ERR_USER_13 User defined error code 13 +1037 GPG_ERR_USER_14 User defined error code 14 +1038 GPG_ERR_USER_15 User defined error code 15 +1039 GPG_ERR_USER_16 User defined error code 16 + +# 1040 to 1499 are free to be used. + +# 1500 to 1755 are mapped SQLite primary error codes. +1500 GPG_ERR_SQL_OK SQL success +1501 GPG_ERR_SQL_ERROR SQL error +1502 GPG_ERR_SQL_INTERNAL Internal logic error in SQL library +1503 GPG_ERR_SQL_PERM Access permission denied (SQL) +1504 GPG_ERR_SQL_ABORT SQL abort was requested +1505 GPG_ERR_SQL_BUSY SQL database file is locked +1506 GPG_ERR_SQL_LOCKED An SQL table in the database is locked +1507 GPG_ERR_SQL_NOMEM SQL library ran out of core +1508 GPG_ERR_SQL_READONLY Attempt to write a readonly SQL database +1509 GPG_ERR_SQL_INTERRUPT SQL operation terminated by interrupt +1510 GPG_ERR_SQL_IOERR I/O error during SQL operation +1511 GPG_ERR_SQL_CORRUPT SQL database disk image is malformed +1512 GPG_ERR_SQL_NOTFOUND Unknown opcode in SQL file control +1513 GPG_ERR_SQL_FULL Insertion failed because SQL database is full +1514 GPG_ERR_SQL_CANTOPEN Unable to open the SQL database file +1515 GPG_ERR_SQL_PROTOCOL SQL database lock protocol error +1516 GPG_ERR_SQL_EMPTY (internal SQL code: empty) +1517 GPG_ERR_SQL_SCHEMA SQL database schema changed +1518 GPG_ERR_SQL_TOOBIG String or blob exceeds size limit (SQL) +1519 GPG_ERR_SQL_CONSTRAINT SQL abort due to constraint violation +1520 GPG_ERR_SQL_MISMATCH Data type mismatch (SQL) +1521 GPG_ERR_SQL_MISUSE SQL library used incorrectly +1522 GPG_ERR_SQL_NOLFS SQL library uses unsupported OS features +1523 GPG_ERR_SQL_AUTH Authorization denied (SQL) +1524 GPG_ERR_SQL_FORMAT (unused SQL code: format) +1525 GPG_ERR_SQL_RANGE SQL bind parameter out of range +1526 GPG_ERR_SQL_NOTADB File opened that is not an SQL database file +1527 GPG_ERR_SQL_NOTICE Notifications from SQL logger +1528 GPG_ERR_SQL_WARNING Warnings from SQL logger + +# 1529 to 1599 are reserved for newer SQLite primary error codes. + +1600 GPG_ERR_SQL_ROW SQL has another row ready +1601 GPG_ERR_SQL_DONE SQL has finished executing + +# 1602 to 1755 are reserved for newer SQLite primary error codes. + +# 1756 to 16380 are free to be used. + +16381 GPG_ERR_MISSING_ERRNO System error w/o errno +16382 GPG_ERR_UNKNOWN_ERRNO Unknown system error +16383 GPG_ERR_EOF End of file + +# 16384 - 32767 are reserved for future extensions. + +# GPG_SYSTEM_ERROR | (141 to 32767) are to be used for system errors. + + GPG_ERR_CODE_DIM Unknown error code diff --git a/comm/third_party/libgpg-error/src/err-sources.h b/comm/third_party/libgpg-error/src/err-sources.h new file mode 100644 index 0000000000..08be48da01 --- /dev/null +++ b/comm/third_party/libgpg-error/src/err-sources.h @@ -0,0 +1,88 @@ +/* Output of mkstrtable.awk. DO NOT EDIT. */ + +/* err-sources.h - List of error sources and their description. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +/* The purpose of this complex string table is to produce + optimal code with a minimum of relocations. */ + +static const char msgstr[] = + gettext_noop ("Unspecified source") "\0" + gettext_noop ("gcrypt") "\0" + gettext_noop ("GnuPG") "\0" + gettext_noop ("GpgSM") "\0" + gettext_noop ("GPG Agent") "\0" + gettext_noop ("Pinentry") "\0" + gettext_noop ("SCD") "\0" + gettext_noop ("GPGME") "\0" + gettext_noop ("Keybox") "\0" + gettext_noop ("KSBA") "\0" + gettext_noop ("Dirmngr") "\0" + gettext_noop ("GSTI") "\0" + gettext_noop ("GPA") "\0" + gettext_noop ("Kleopatra") "\0" + gettext_noop ("G13") "\0" + gettext_noop ("Assuan") "\0" + gettext_noop ("TPM2d") "\0" + gettext_noop ("TLS") "\0" + gettext_noop ("Any source") "\0" + gettext_noop ("User defined source 1") "\0" + gettext_noop ("User defined source 2") "\0" + gettext_noop ("User defined source 3") "\0" + gettext_noop ("User defined source 4") "\0" + gettext_noop ("Unknown source"); + +static const int msgidx[] = + { + 0, + 19, + 26, + 32, + 38, + 48, + 57, + 61, + 67, + 74, + 79, + 87, + 92, + 96, + 106, + 110, + 117, + 123, + 127, + 138, + 160, + 182, + 204, + 226 + }; + +static GPG_ERR_INLINE int +msgidxof (int code) +{ + return (0 ? 0 + : ((code >= 0) && (code <= 17)) ? (code - 0) + : ((code >= 31) && (code <= 35)) ? (code - 13) + : 36 - 13); +} diff --git a/comm/third_party/libgpg-error/src/err-sources.h.in b/comm/third_party/libgpg-error/src/err-sources.h.in new file mode 100644 index 0000000000..f6e3f1de52 --- /dev/null +++ b/comm/third_party/libgpg-error/src/err-sources.h.in @@ -0,0 +1,61 @@ +# err-sources.h.in - List of error sources and their description input file. +/* err-sources.h - List of error sources and their description. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +# Everything up to the first line that starts with a number in the +# first column is copied into the output verbatim. Then, empty lines +# are ignored. Other lines must have an error source number, followed +# by one or more characters, followed by the error source +# symbol, followed by one or more characters, followed by the +# error source name. Trailing whitespace is removed. The error +# sources should be sorted. The last line should not have a number, +# but only a , followed by a description for error sources that +# are not in the list. + +0 GPG_ERR_SOURCE_UNKNOWN Unspecified source +1 GPG_ERR_SOURCE_GCRYPT gcrypt +2 GPG_ERR_SOURCE_GPG GnuPG +3 GPG_ERR_SOURCE_GPGSM GpgSM +4 GPG_ERR_SOURCE_GPGAGENT GPG Agent +5 GPG_ERR_SOURCE_PINENTRY Pinentry +6 GPG_ERR_SOURCE_SCD SCD +7 GPG_ERR_SOURCE_GPGME GPGME +8 GPG_ERR_SOURCE_KEYBOX Keybox +9 GPG_ERR_SOURCE_KSBA KSBA +10 GPG_ERR_SOURCE_DIRMNGR Dirmngr +11 GPG_ERR_SOURCE_GSTI GSTI +12 GPG_ERR_SOURCE_GPA GPA +13 GPG_ERR_SOURCE_KLEO Kleopatra +14 GPG_ERR_SOURCE_G13 G13 +15 GPG_ERR_SOURCE_ASSUAN Assuan +16 GPG_ERR_SOURCE_TPM2D TPM2d +17 GPG_ERR_SOURCE_TLS TLS + +# 18 to 30 are free to be used. + +31 GPG_ERR_SOURCE_ANY Any source +32 GPG_ERR_SOURCE_USER_1 User defined source 1 +33 GPG_ERR_SOURCE_USER_2 User defined source 2 +34 GPG_ERR_SOURCE_USER_3 User defined source 3 +35 GPG_ERR_SOURCE_USER_4 User defined source 4 + +# 36 to 255 are free to be used. + + GPG_ERR_SOURCE_DIM Unknown source diff --git a/comm/third_party/libgpg-error/src/errnos.in b/comm/third_party/libgpg-error/src/errnos.in new file mode 100644 index 0000000000..018fb9ad57 --- /dev/null +++ b/comm/third_party/libgpg-error/src/errnos.in @@ -0,0 +1,172 @@ +# errnos.in - List of system error values input file. +/* errnos.in - List of system error values. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +# Everything up to the first line that starts with a number in the +# first column is copied into the output verbatim. Then, empty lines +# are ignored. Other lines must have an error code number, followed +# by one or more characters, followed by the error name. +# +# IMPORTANT: For now, the numbering must be consecutive. Some of the +# scripts (notably mkerrnos.h) do not deal correctly with a numbering +# that is out of order or has gaps. + + +0 E2BIG +1 EACCES +2 EADDRINUSE +3 EADDRNOTAVAIL +4 EADV +5 EAFNOSUPPORT +6 EAGAIN +7 EALREADY +8 EAUTH +9 EBACKGROUND +10 EBADE +11 EBADF +12 EBADFD +13 EBADMSG +14 EBADR +15 EBADRPC +16 EBADRQC +17 EBADSLT +18 EBFONT +19 EBUSY +20 ECANCELED +21 ECHILD +22 ECHRNG +23 ECOMM +24 ECONNABORTED +25 ECONNREFUSED +26 ECONNRESET +27 ED +28 EDEADLK +29 EDEADLOCK +30 EDESTADDRREQ +31 EDIED +32 EDOM +33 EDOTDOT +34 EDQUOT +35 EEXIST +36 EFAULT +37 EFBIG +38 EFTYPE +39 EGRATUITOUS +40 EGREGIOUS +41 EHOSTDOWN +42 EHOSTUNREACH +43 EIDRM +44 EIEIO +45 EILSEQ +46 EINPROGRESS +47 EINTR +48 EINVAL +49 EIO +50 EISCONN +51 EISDIR +52 EISNAM +53 EL2HLT +54 EL2NSYNC +55 EL3HLT +56 EL3RST +57 ELIBACC +58 ELIBBAD +59 ELIBEXEC +60 ELIBMAX +61 ELIBSCN +62 ELNRNG +63 ELOOP +64 EMEDIUMTYPE +65 EMFILE +66 EMLINK +67 EMSGSIZE +68 EMULTIHOP +69 ENAMETOOLONG +70 ENAVAIL +71 ENEEDAUTH +72 ENETDOWN +73 ENETRESET +74 ENETUNREACH +75 ENFILE +76 ENOANO +77 ENOBUFS +78 ENOCSI +79 ENODATA +80 ENODEV +81 ENOENT +82 ENOEXEC +83 ENOLCK +84 ENOLINK +85 ENOMEDIUM +86 ENOMEM +87 ENOMSG +88 ENONET +89 ENOPKG +90 ENOPROTOOPT +91 ENOSPC +92 ENOSR +93 ENOSTR +94 ENOSYS +95 ENOTBLK +96 ENOTCONN +97 ENOTDIR +98 ENOTEMPTY +99 ENOTNAM +100 ENOTSOCK +101 ENOTSUP +102 ENOTTY +103 ENOTUNIQ +104 ENXIO +105 EOPNOTSUPP +106 EOVERFLOW +107 EPERM +108 EPFNOSUPPORT +109 EPIPE +110 EPROCLIM +111 EPROCUNAVAIL +112 EPROGMISMATCH +113 EPROGUNAVAIL +114 EPROTO +115 EPROTONOSUPPORT +116 EPROTOTYPE +117 ERANGE +118 EREMCHG +119 EREMOTE +120 EREMOTEIO +121 ERESTART +122 EROFS +123 ERPCMISMATCH +124 ESHUTDOWN +125 ESOCKTNOSUPPORT +126 ESPIPE +127 ESRCH +128 ESRMNT +129 ESTALE +130 ESTRPIPE +131 ETIME +132 ETIMEDOUT +133 ETOOMANYREFS +134 ETXTBSY +135 EUCLEAN +136 EUNATCH +137 EUSERS +138 EWOULDBLOCK +139 EXDEV +140 EXFULL diff --git a/comm/third_party/libgpg-error/src/estream-printf.c b/comm/third_party/libgpg-error/src/estream-printf.c new file mode 100644 index 0000000000..fe25657d1b --- /dev/null +++ b/comm/third_party/libgpg-error/src/estream-printf.c @@ -0,0 +1,1904 @@ +/* estream-printf.c - Versatile mostly C-99 compliant printf formatting + * Copyright (C) 2007, 2008, 2009, 2010, 2012, 2014 g10 Code GmbH + * + * This file is part of Libestream. + * + * Libestream is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libestream is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libestream; if not, see . + * + * ALTERNATIVELY, Libestream may be distributed under the terms of the + * following license, in which case the provisions of this license are + * required INSTEAD OF the GNU General Public License. If you wish to + * allow use of your version of this file only under the terms of the + * GNU General Public License, and not to allow others to use your + * version of this file under the terms of the following license, + * indicate your decision by deleting this paragraph and the license + * below. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Required autoconf tests: + + AC_TYPE_LONG_LONG_INT defines HAVE_LONG_LONG_INT + AC_TYPE_LONG_DOUBLE defines HAVE_LONG_DOUBLE + AC_TYPE_INTMAX_T defines HAVE_INTMAX_T + AC_TYPE_UINTMAX_T defines HAVE_UINTMAX_T + AC_CHECK_TYPES([ptrdiff_t]) defines HAVE_PTRDIFF_T + AC_CHECK_SIZEOF([unsigned long]) defines SIZEOF_UNSIGNED_LONG + AC_CHECK_SIZEOF([void *]) defines SIZEOF_VOID_P + HAVE_LANGINFO_THOUSEP + + Note that the file estream.m4 provides the autoconf macro + ESTREAM_PRINTF_INIT which runs all required checks. + See estream-printf.h for ways to tune this code. + + Missing stuff: wchar and wint_t + thousep in pr_float. + +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM) +# define HAVE_W32_SYSTEM 1 +# if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM) +# define HAVE_W32CE_SYSTEM +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#if defined(HAVE_INTMAX_T) || defined(HAVE_UINTMAX_T) +# ifdef HAVE_STDINT_H +# include +# endif +#endif +#ifdef HAVE_LANGINFO_THOUSEP +#include +#endif +#ifdef HAVE_W32CE_SYSTEM +#include /* ERRNO replacement. */ +#endif +#ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE +# include _ESTREAM_PRINTF_EXTRA_INCLUDE +#endif +#include "estream-printf.h" + +/* #define DEBUG 1 */ + + +/* Allow redefinition of asprintf used realloc function. */ +#if defined(_ESTREAM_PRINTF_REALLOC) +#define my_printf_realloc(a,b) _ESTREAM_PRINTF_REALLOC((a),(b)) +#else +#define my_printf_realloc(a,b) fixed_realloc((a),(b)) +#endif + +/* A wrapper to set ERRNO. */ +#ifdef HAVE_W32CE_SYSTEM +# define _set_errno(a) gpg_err_set_errno ((a)) +#else +# define _set_errno(a) do { errno = (a); } while (0) +#endif + + +/* Calculate array dimension. */ +#ifndef DIM +#define DIM(array) (sizeof (array) / sizeof (*array)) +#endif + + +/* We allow for that many args without requiring malloced memory. */ +#define DEFAULT_MAX_ARGSPECS 5 + +/* We allow for that many values without requiring malloced memory. */ +#define DEFAULT_MAX_VALUES 8 + +/* We allocate this many new array argspec elements each time. */ +#define ARGSPECS_BUMP_VALUE 10 + +/* Special values for the field width and the precision. */ +#define NO_FIELD_VALUE (-1) +#define STAR_FIELD_VALUE (-2) + +/* Bit valuues used for the conversion flags. */ +#define FLAG_GROUPING 1 +#define FLAG_LEFT_JUST 2 +#define FLAG_PLUS_SIGN 4 +#define FLAG_SPACE_PLUS 8 +#define FLAG_ALT_CONV 16 +#define FLAG_ZERO_PAD 32 + +/* Constants used the length modifiers. */ +typedef enum + { + LENMOD_NONE = 0, + LENMOD_CHAR, /* "hh" */ + LENMOD_SHORT, /* "h" */ + LENMOD_LONG, /* "l" */ + LENMOD_LONGLONG, /* "ll" */ + LENMOD_INTMAX, /* "j" */ + LENMOD_SIZET, /* "z" */ + LENMOD_PTRDIFF, /* "t" */ + LENMOD_LONGDBL /* "L" */ + } lenmod_t; + +/* All the conversion specifiers. */ +typedef enum + { + CONSPEC_UNKNOWN = 0, + CONSPEC_DECIMAL, + CONSPEC_OCTAL, + CONSPEC_UNSIGNED, + CONSPEC_HEX, + CONSPEC_HEX_UP, + CONSPEC_FLOAT, + CONSPEC_FLOAT_UP, + CONSPEC_EXP, + CONSPEC_EXP_UP, + CONSPEC_F_OR_G, + CONSPEC_F_OR_G_UP, + CONSPEC_HEX_EXP, + CONSPEC_HEX_EXP_UP, + CONSPEC_CHAR, + CONSPEC_STRING, + CONSPEC_POINTER, + CONSPEC_STRERROR, + CONSPEC_BYTES_SO_FAR + } conspec_t; + + +/* Constants describing all the suppoorted types. Note that we list + all the types we know about even if certain types are not available + on this system. */ +typedef enum + { + VALTYPE_UNSUPPORTED = 0, /* Artificial type for error detection. */ + VALTYPE_CHAR, + VALTYPE_SCHAR, + VALTYPE_UCHAR, + VALTYPE_SHORT, + VALTYPE_USHORT, + VALTYPE_INT, + VALTYPE_UINT, + VALTYPE_LONG, + VALTYPE_ULONG, + VALTYPE_LONGLONG, + VALTYPE_ULONGLONG, + VALTYPE_DOUBLE, + VALTYPE_LONGDOUBLE, + VALTYPE_STRING, + VALTYPE_INTMAX, + VALTYPE_UINTMAX, + VALTYPE_SIZE, + VALTYPE_PTRDIFF, + VALTYPE_POINTER, + VALTYPE_CHAR_PTR, + VALTYPE_SCHAR_PTR, + VALTYPE_SHORT_PTR, + VALTYPE_INT_PTR, + VALTYPE_LONG_PTR, + VALTYPE_LONGLONG_PTR, + VALTYPE_INTMAX_PTR, + VALTYPE_SIZE_PTR, + VALTYPE_PTRDIFF_PTR + } valtype_t; + + +/* A union used to store the actual values. */ +typedef union +{ + char a_char; + signed char a_schar; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long int a_long; + unsigned long int a_ulong; +#ifdef HAVE_LONG_LONG_INT + long long int a_longlong; + unsigned long long int a_ulonglong; +#endif + double a_double; +#ifdef HAVE_LONG_DOUBLE + long double a_longdouble; +#endif + const char *a_string; +#ifdef HAVE_INTMAX_T + intmax_t a_intmax; +#endif +#ifdef HAVE_UINTMAX_T + intmax_t a_uintmax; +#endif + size_t a_size; +#ifdef HAVE_PTRDIFF_T + ptrdiff_t a_ptrdiff; +#endif + void *a_void_ptr; + char *a_char_ptr; + signed char *a_schar_ptr; + short *a_short_ptr; + int *a_int_ptr; + long *a_long_ptr; +#ifdef HAVE_LONG_LONG_INT + long long int *a_longlong_ptr; +#endif +#ifdef HAVE_INTMAX_T + intmax_t *a_intmax_ptr; +#endif + size_t *a_size_ptr; +#ifdef HAVE_PTRDIFF_T + ptrdiff_t *a_ptrdiff_ptr; +#endif +} value_t; + +/* An object used to keep track of a format option and arguments. */ +struct argspec_s +{ + size_t length; /* The length of these args including the percent. */ + unsigned int flags; /* The conversion flags (bits defined by FLAG_foo). */ + int width; /* The field width. */ + int precision; /* The precision. */ + lenmod_t lenmod; /* The length modifier. */ + conspec_t conspec; /* The conversion specifier. */ + int arg_pos; /* The position of the argument. This one may + be -1 to indicate that no value is expected + (e.g. for "%m"). */ + int width_pos; /* The position of the argument for a field + width star's value. 0 for not used. */ + int precision_pos; /* The position of the argument for the a + precision star's value. 0 for not used. */ + valtype_t vt; /* The type of the corresponding argument. */ +}; +typedef struct argspec_s *argspec_t; + +/* An object to build up a table of values and their types. */ +struct valueitem_s +{ + valtype_t vt; /* The type of the value. */ + value_t value; /* The value. */ +}; +typedef struct valueitem_s *valueitem_t; + + +/* Not all systems have a C-90 compliant realloc. To cope with this + we use this simple wrapper. */ +#ifndef _ESTREAM_PRINTF_REALLOC +static void * +fixed_realloc (void *a, size_t n) +{ + if (!a) + return malloc (n); + + if (!n) + { + free (a); + return NULL; + } + + return realloc (a, n); +} +#endif /*!_ESTREAM_PRINTF_REALLOC*/ + + +#ifdef DEBUG +static void +dump_argspecs (argspec_t arg, size_t argcount) +{ + int idx; + + for (idx=0; argcount; argcount--, arg++, idx++) + fprintf (stderr, + "%2d: len=%u flags=%u width=%d prec=%d mod=%d " + "con=%d vt=%d pos=%d-%d-%d\n", + idx, + (unsigned int)arg->length, + arg->flags, + arg->width, + arg->precision, + arg->lenmod, + arg->conspec, + arg->vt, + arg->arg_pos, + arg->width_pos, + arg->precision_pos); +} +#endif /*DEBUG*/ + + +/* Set the vt field for ARG. */ +static void +compute_type (argspec_t arg) +{ + switch (arg->conspec) + { + case CONSPEC_UNKNOWN: + arg->vt = VALTYPE_UNSUPPORTED; + break; + + case CONSPEC_DECIMAL: + switch (arg->lenmod) + { + case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR; break; + case LENMOD_SHORT: arg->vt = VALTYPE_SHORT; break; + case LENMOD_LONG: arg->vt = VALTYPE_LONG; break; + case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG; break; + case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX; break; + case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break; + case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break; + default: arg->vt = VALTYPE_INT; break; + } + break; + + case CONSPEC_OCTAL: + case CONSPEC_UNSIGNED: + case CONSPEC_HEX: + case CONSPEC_HEX_UP: + switch (arg->lenmod) + { + case LENMOD_CHAR: arg->vt = VALTYPE_UCHAR; break; + case LENMOD_SHORT: arg->vt = VALTYPE_USHORT; break; + case LENMOD_LONG: arg->vt = VALTYPE_ULONG; break; + case LENMOD_LONGLONG: arg->vt = VALTYPE_ULONGLONG; break; + case LENMOD_INTMAX: arg->vt = VALTYPE_UINTMAX; break; + case LENMOD_SIZET: arg->vt = VALTYPE_SIZE; break; + case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF; break; + default: arg->vt = VALTYPE_UINT; break; + } + break; + + case CONSPEC_FLOAT: + case CONSPEC_FLOAT_UP: + case CONSPEC_EXP: + case CONSPEC_EXP_UP: + case CONSPEC_F_OR_G: + case CONSPEC_F_OR_G_UP: + case CONSPEC_HEX_EXP: + case CONSPEC_HEX_EXP_UP: + switch (arg->lenmod) + { + case LENMOD_LONGDBL: arg->vt = VALTYPE_LONGDOUBLE; break; + case LENMOD_LONG: arg->vt = VALTYPE_DOUBLE; break; + default: arg->vt = VALTYPE_DOUBLE; break; + } + break; + + case CONSPEC_CHAR: + arg->vt = VALTYPE_INT; + break; + + case CONSPEC_STRING: + arg->vt = VALTYPE_STRING; + break; + + case CONSPEC_POINTER: + arg->vt = VALTYPE_POINTER; + break; + + case CONSPEC_STRERROR: + arg->vt = VALTYPE_STRING; + break; + + case CONSPEC_BYTES_SO_FAR: + switch (arg->lenmod) + { + case LENMOD_CHAR: arg->vt = VALTYPE_SCHAR_PTR; break; + case LENMOD_SHORT: arg->vt = VALTYPE_SHORT_PTR; break; + case LENMOD_LONG: arg->vt = VALTYPE_LONG_PTR; break; + case LENMOD_LONGLONG: arg->vt = VALTYPE_LONGLONG_PTR; break; + case LENMOD_INTMAX: arg->vt = VALTYPE_INTMAX_PTR; break; + case LENMOD_SIZET: arg->vt = VALTYPE_SIZE_PTR; break; + case LENMOD_PTRDIFF: arg->vt = VALTYPE_PTRDIFF_PTR; break; + default: arg->vt = VALTYPE_INT_PTR; break; + } + break; + + } +} + + + +/* Parse the FORMAT string and populate the specification array stored + at the address ARGSPECS_ADDR. The caller has provided enough space + to store up to MAX_ARGSPECS in that buffer. The function may + however ignore the provided buffer and malloc a larger one. On + success the address of that larger buffer will be stored at + ARGSPECS_ADDR. The actual number of specifications will be + returned at R_ARGSPECS_COUNT. */ +static int +parse_format (const char *format, + argspec_t *argspecs_addr, size_t max_argspecs, + size_t *r_argspecs_count) +{ + const char *s; + argspec_t argspecs = *argspecs_addr; + argspec_t arg; + size_t argcount = 0; + + if (!format) + goto leave_einval; + + for (; *format; format++) + { + unsigned int flags; + int width, precision; + lenmod_t lenmod; + conspec_t conspec; + int arg_pos, width_pos, precision_pos; + + if (*format != '%') + continue; + s = ++format; + if (!*s) + goto leave_einval; + if (*s == '%') + continue; /* Just a quoted percent. */ + + /* First check whether there is a positional argument. */ + arg_pos = 0; /* No positional argument given. */ + if (*s >= '1' && *s <= '9') + { + const char *save_s = s; + + arg_pos = (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; s++) + arg_pos = 10*arg_pos + (*s - '0'); + if (arg_pos < 0) + goto leave_einval; /* Overflow during conversion. */ + if (*s == '$') + s++; + else + { + arg_pos = 0; + s = save_s; + } + } + + /* Parse the flags. */ + flags = 0; + for ( ; *s; s++) + { + switch (*s) + { + case '\'': flags |= FLAG_GROUPING; break; + case '-': flags |= FLAG_LEFT_JUST; break; + case '+': flags |= FLAG_PLUS_SIGN; break; + case ' ': flags |= FLAG_SPACE_PLUS; break; + case '#': flags |= FLAG_ALT_CONV; break; + case '0': flags |= FLAG_ZERO_PAD; break; + default: + goto flags_parsed; + } + } + flags_parsed: + + /* Parse the field width. */ + width_pos = 0; + if (*s == '*') + { + width = STAR_FIELD_VALUE; + s++; + /* If we have a positional argument, another one might also + be used to give the position of the star's value. */ + if (arg_pos && *s >= '1' && *s <= '9') + { + width_pos = (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; s++) + width_pos = 10*width_pos + (*s - '0'); + if (width_pos < 1) + goto leave_einval; /* Overflow during conversion. */ + if (*s != '$') + goto leave_einval; /* Not followed by $. */ + s++; + } + } + else if ( *s >= '0' && *s <= '9') + { + width = (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; s++) + { + if (!width && *s == '0') + goto leave_einval; /* Leading zeroes are not allowed. + Fixme: check what other + implementations do. */ + width = 10*width + (*s - '0'); + } + if (width < 0) + goto leave_einval; /* Overflow during conversion. */ + } + else + width = NO_FIELD_VALUE; + + /* Parse the precision. */ + precision_pos = 0; + precision = NO_FIELD_VALUE; + if (*s == '.') + { + int ignore_value = (s[1] == '-'); + + s++; + if (*s == '*') + { + precision = STAR_FIELD_VALUE; + s++; + /* If we have a positional argument, another one might also + be used to give the position of the star's value. */ + if (arg_pos && *s >= '1' && *s <= '9') + { + precision_pos = (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; s++) + precision_pos = 10*precision_pos + (*s - '0'); + if (precision_pos < 1) + goto leave_einval; /* Overflow during conversion. */ + if (*s != '$') + goto leave_einval; /* Not followed by $. */ + s++; + } + } + else if ( *s >= '0' && *s <= '9') + { + precision = (*s++ - '0'); + for (; *s >= '0' && *s <= '9'; s++) + { + if (!precision && *s == '0') + goto leave_einval; /* Leading zeroes are not allowed. + Fixme: check what other + implementations do. */ + precision = 10*precision + (*s - '0'); + } + if (precision < 0) + goto leave_einval; /* Overflow during conversion. */ + } + else + precision = 0; + if (ignore_value) + precision = NO_FIELD_VALUE; + } + + /* Parse the length modifiers. */ + switch (*s) + { + case 'h': + if (s[1] == 'h') + { + lenmod = LENMOD_CHAR; + s++; + } + else + lenmod = LENMOD_SHORT; + s++; + break; + case 'l': + if (s[1] == 'l') + { + lenmod = LENMOD_LONGLONG; + s++; + } + else + lenmod = LENMOD_LONG; + s++; + break; + case 'j': lenmod = LENMOD_INTMAX; s++; break; + case 'z': lenmod = LENMOD_SIZET; s++; break; + case 't': lenmod = LENMOD_PTRDIFF; s++; break; + case 'L': lenmod = LENMOD_LONGDBL; s++; break; + default: lenmod = LENMOD_NONE; break; + } + + /* Parse the conversion specifier. */ + switch (*s) + { + case 'd': + case 'i': conspec = CONSPEC_DECIMAL; break; + case 'o': conspec = CONSPEC_OCTAL; break; + case 'u': conspec = CONSPEC_UNSIGNED; break; + case 'x': conspec = CONSPEC_HEX; break; + case 'X': conspec = CONSPEC_HEX_UP; break; + case 'f': conspec = CONSPEC_FLOAT; break; + case 'F': conspec = CONSPEC_FLOAT_UP; break; + case 'e': conspec = CONSPEC_EXP; break; + case 'E': conspec = CONSPEC_EXP_UP; break; + case 'g': conspec = CONSPEC_F_OR_G; break; + case 'G': conspec = CONSPEC_F_OR_G_UP; break; + case 'a': conspec = CONSPEC_HEX_EXP; break; + case 'A': conspec = CONSPEC_HEX_EXP_UP; break; + case 'c': conspec = CONSPEC_CHAR; break; + case 's': conspec = CONSPEC_STRING; break; + case 'p': conspec = CONSPEC_POINTER; break; + case 'n': conspec = CONSPEC_BYTES_SO_FAR; break; + case 'C': conspec = CONSPEC_CHAR; lenmod = LENMOD_LONG; break; + case 'S': conspec = CONSPEC_STRING; lenmod = LENMOD_LONG; break; + case 'm': conspec = CONSPEC_STRERROR; arg_pos = -1; break; + default: conspec = CONSPEC_UNKNOWN; + } + + /* Save the args. */ + if (argcount >= max_argspecs) + { + /* We either need to allocate a new array instead of the + caller provided one or realloc the array. Instead of + using realloc we allocate a new one and release the + original one then. */ + size_t n, newmax; + argspec_t newarg; + + newmax = max_argspecs + ARGSPECS_BUMP_VALUE; + if (newmax <= max_argspecs) + goto leave_einval; /* Too many arguments. */ + newarg = calloc (newmax, sizeof *newarg); + if (!newarg) + goto leave; + for (n=0; n < argcount; n++) + newarg[n] = argspecs[n]; + if (argspecs != *argspecs_addr) + free (argspecs); + argspecs = newarg; + max_argspecs = newmax; + } + + arg = argspecs + argcount; + arg->length = s - format + 2; + arg->flags = flags; + arg->width = width; + arg->precision = precision; + arg->lenmod = lenmod; + arg->conspec = conspec; + arg->arg_pos = arg_pos; + arg->width_pos = width_pos; + arg->precision_pos = precision_pos; + compute_type (arg); + argcount++; + format = s; + } + + *argspecs_addr = argspecs; + *r_argspecs_count = argcount; + return 0; /* Success. */ + + leave_einval: + _set_errno (EINVAL); + leave: + if (argspecs != *argspecs_addr) + free (argspecs); + *argspecs_addr = NULL; + return -1; +} + + +/* This function reads all the values as specified by VALUETABLE into + VALUETABLE. The values are expected in VAARGS. The function + returns -1 if a specified type is not supported. */ +static int +read_values (valueitem_t valuetable, size_t valuetable_len, va_list vaargs) +{ + int validx; + + for (validx=0; validx < valuetable_len; validx++) + { + value_t *value = &valuetable[validx].value; + valtype_t vt = valuetable[validx].vt; + + switch (vt) + { + case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break; + case VALTYPE_CHAR_PTR: + value->a_char_ptr = va_arg (vaargs, char *); + break; + case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break; + case VALTYPE_SCHAR_PTR: + value->a_schar_ptr = va_arg (vaargs, signed char *); + break; + case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break; + case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break; + case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break; + case VALTYPE_SHORT_PTR: + value->a_short_ptr = va_arg (vaargs, short *); + break; + case VALTYPE_INT: + value->a_int = va_arg (vaargs, int); + break; + case VALTYPE_INT_PTR: + value->a_int_ptr = va_arg (vaargs, int *); + break; + case VALTYPE_UINT: + value->a_uint = va_arg (vaargs, unsigned int); + break; + case VALTYPE_LONG: + value->a_long = va_arg (vaargs, long); + break; + case VALTYPE_ULONG: + value->a_ulong = va_arg (vaargs, unsigned long); + break; + case VALTYPE_LONG_PTR: + value->a_long_ptr = va_arg (vaargs, long *); + break; +#ifdef HAVE_LONG_LONG_INT + case VALTYPE_LONGLONG: + value->a_longlong = va_arg (vaargs, long long int); + break; + case VALTYPE_ULONGLONG: + value->a_ulonglong = va_arg (vaargs, unsigned long long int); + break; + case VALTYPE_LONGLONG_PTR: + value->a_longlong_ptr = va_arg (vaargs, long long *); + break; +#endif + case VALTYPE_DOUBLE: + value->a_double = va_arg (vaargs, double); + break; +#ifdef HAVE_LONG_DOUBLE + case VALTYPE_LONGDOUBLE: + value->a_longdouble = va_arg (vaargs, long double); + break; +#endif + case VALTYPE_STRING: + value->a_string = va_arg (vaargs, const char *); + break; + case VALTYPE_POINTER: + value->a_void_ptr = va_arg (vaargs, void *); + break; +#ifdef HAVE_INTMAX_T + case VALTYPE_INTMAX: + value->a_intmax = va_arg (vaargs, intmax_t); + break; + case VALTYPE_INTMAX_PTR: + value->a_intmax_ptr = va_arg (vaargs, intmax_t *); + break; +#endif +#ifdef HAVE_UINTMAX_T + case VALTYPE_UINTMAX: + value->a_uintmax = va_arg (vaargs, uintmax_t); + break; +#endif + case VALTYPE_SIZE: + value->a_size = va_arg (vaargs, size_t); + break; + case VALTYPE_SIZE_PTR: + value->a_size_ptr = va_arg (vaargs, size_t *); + break; +#ifdef HAVE_PTRDIFF_T + case VALTYPE_PTRDIFF: + value->a_ptrdiff = va_arg (vaargs, ptrdiff_t); + break; + case VALTYPE_PTRDIFF_PTR: + value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *); + break; +#endif + default: /* Unsupported type. */ + return -1; + } + } + return 0; +} + + + +/* Output COUNT padding characters PADCHAR and update NBYTES by the + number of bytes actually written. */ +static int +pad_out (estream_printf_out_t outfnc, void *outfncarg, + int padchar, int count, size_t *nbytes) +{ + char buf[32]; + size_t n; + int rc; + + while (count > 0) + { + n = (count <= sizeof buf)? count : sizeof buf; + memset (buf, padchar, n); + rc = outfnc (outfncarg, buf, n); + if (rc) + return rc; + *nbytes += n; + count -= n; + } + + return 0; +} + + +/* "d,i,o,u,x,X" formatting. OUTFNC and OUTFNCARG describes the + output routine, ARG gives the argument description and VALUE the + actual value (its type is available through arg->vt). */ +static int +pr_integer (estream_printf_out_t outfnc, void *outfncarg, + argspec_t arg, value_t value, size_t *nbytes) +{ + int rc; +#ifdef HAVE_LONG_LONG_INT + unsigned long long aulong; +#else + unsigned long aulong; +#endif + char numbuf[100]; + char *p, *pend; + size_t n; + char signchar = 0; + int n_prec; /* Number of extra precision digits required. */ + int n_extra; /* Extra number of prefix or sign characters. */ + + if (arg->conspec == CONSPEC_DECIMAL) + { +#ifdef HAVE_LONG_LONG_INT + long long along; +#else + long along; +#endif + + switch (arg->vt) + { + case VALTYPE_SHORT: along = value.a_short; break; + case VALTYPE_INT: along = value.a_int; break; + case VALTYPE_LONG: along = value.a_long; break; +#ifdef HAVE_LONG_LONG_INT + case VALTYPE_LONGLONG: along = value.a_longlong; break; + case VALTYPE_SIZE: along = value.a_size; break; +# ifdef HAVE_INTMAX_T + case VALTYPE_INTMAX: along = value.a_intmax; break; +# endif +# ifdef HAVE_PTRDIFF_T + case VALTYPE_PTRDIFF: along = value.a_ptrdiff; break; +# endif +#endif /*HAVE_LONG_LONG_INT*/ + default: + return -1; + } + if (along < 0) + { + aulong = -along; + signchar = '-'; + } + else + aulong = along; + } + else + { + switch (arg->vt) + { + case VALTYPE_USHORT: aulong = value.a_ushort; break; + case VALTYPE_UINT: aulong = value.a_uint; break; + case VALTYPE_ULONG: aulong = value.a_ulong; break; +#ifdef HAVE_LONG_LONG_INT + case VALTYPE_ULONGLONG: aulong = value.a_ulonglong; break; + case VALTYPE_SIZE: aulong = value.a_size; break; +# ifdef HAVE_UINTMAX_T + case VALTYPE_UINTMAX: aulong = value.a_uintmax; break; +# endif +# ifdef HAVE_PTRDIFF_T + case VALTYPE_PTRDIFF: aulong = value.a_ptrdiff; break; +# endif +#endif /*HAVE_LONG_LONG_INT*/ + default: + return -1; + } + } + + if (signchar == '-') + ; + else if ((arg->flags & FLAG_PLUS_SIGN)) + signchar = '+'; + else if ((arg->flags & FLAG_SPACE_PLUS)) + signchar = ' '; + + n_extra = !!signchar; + + /* We build the string up backwards. */ + p = pend = numbuf + DIM(numbuf); + if ((!aulong && !arg->precision)) + ; + else if (arg->conspec == CONSPEC_DECIMAL + || arg->conspec == CONSPEC_UNSIGNED) + { + int grouping = -1; + const char * grouping_string = +#ifdef HAVE_LANGINFO_THOUSEP + nl_langinfo(THOUSEP); +#else + "'"; +#endif + + do + { + if ((arg->flags & FLAG_GROUPING) + && (++grouping == 3) && *grouping_string) + { + *--p = *grouping_string; + grouping = 0; + } + *--p = '0' + (aulong % 10); + aulong /= 10; + } + while (aulong); + } + else if (arg->conspec == CONSPEC_OCTAL) + { + do + { + *--p = '0' + (aulong % 8); + aulong /= 8; + } + while (aulong); + if ((arg->flags & FLAG_ALT_CONV) && *p != '0') + *--p = '0'; + } + else /* HEX or HEXUP */ + { + const char *digits = ((arg->conspec == CONSPEC_HEX) + ? "0123456789abcdef" : "0123456789ABCDEF"); + do + { + *--p = digits[(aulong % 16)]; + aulong /= 16; + } + while (aulong); + if ((arg->flags & FLAG_ALT_CONV)) + n_extra += 2; + } + + n = pend - p; + + if ((arg->flags & FLAG_ZERO_PAD) + && arg->precision == NO_FIELD_VALUE && !(arg->flags & FLAG_LEFT_JUST) + && n && arg->width - n_extra > n ) + n_prec = arg->width - n_extra - n; + else if (arg->precision > 0 && arg->precision > n) + n_prec = arg->precision - n; + else + n_prec = 0; + + if (!(arg->flags & FLAG_LEFT_JUST) + && arg->width >= 0 && arg->width - n_extra > n + && arg->width - n_extra - n >= n_prec ) + { + rc = pad_out (outfnc, outfncarg, ' ', + arg->width - n_extra - n - n_prec, nbytes); + if (rc) + return rc; + } + + if (signchar) + { + rc = outfnc (outfncarg, &signchar, 1); + if (rc) + return rc; + *nbytes += 1; + } + + if ((arg->flags & FLAG_ALT_CONV) + && (arg->conspec == CONSPEC_HEX || arg->conspec == CONSPEC_HEX_UP)) + { + rc = outfnc (outfncarg, arg->conspec == CONSPEC_HEX? "0x": "0X", 2); + if (rc) + return rc; + *nbytes += 2; + } + + if (n_prec) + { + rc = pad_out (outfnc, outfncarg, '0', n_prec, nbytes); + if (rc) + return rc; + } + + rc = outfnc (outfncarg, p, pend - p); + if (rc) + return rc; + *nbytes += pend - p; + + if ((arg->flags & FLAG_LEFT_JUST) + && arg->width >= 0 && arg->width - n_extra - n_prec > n) + { + rc = pad_out (outfnc, outfncarg, ' ', + arg->width - n_extra - n_prec - n, nbytes); + if (rc) + return rc; + } + + return 0; +} + + +/* "e,E,f,F,g,G,a,A" formatting. OUTFNC and OUTFNCARG describes the + output routine, ARG gives the argument description and VALUE the + actual value (its type is available through arg->vt). For + portability reasons sprintf is used for the actual formatting. + This is useful because sprint is the only standard function to + convert a floating number into its ascii representation. To avoid + using malloc we just pass the precision to sprintf and do the final + formatting with our own code. */ +static int +pr_float (estream_printf_out_t outfnc, void *outfncarg, + argspec_t arg, value_t value, size_t *nbytes) +{ + int rc; +#ifdef HAVE_LONG_DOUBLE + long double adblfloat = 0; /* Just to please gcc. */ + int use_dbl = 0; +#endif + double afloat; + char numbuf[350]; + char formatstr[20]; + char *p, *pend; + size_t n; + char signchar = 0; + int n_extra; /* Extra number of prefix or sign characters. */ + + switch (arg->vt) + { + case VALTYPE_DOUBLE: afloat = value.a_double; break; +#ifdef HAVE_LONG_DOUBLE + case VALTYPE_LONGDOUBLE: + afloat = 0; /* Just to please gcc. */ + adblfloat = value.a_longdouble; + use_dbl=1; break; +#endif + default: + return -1; + } + + /* We build the string using sprint. */ + p = formatstr + sizeof formatstr; + *--p = 0; + switch (arg->conspec) + { + case CONSPEC_FLOAT: *--p = 'f'; break; + case CONSPEC_FLOAT_UP: *--p = 'F'; break; + case CONSPEC_EXP: *--p = 'e'; break; + case CONSPEC_EXP_UP: *--p = 'E'; break; + case CONSPEC_F_OR_G: *--p = 'g'; break; + case CONSPEC_F_OR_G_UP: *--p = 'G'; break; + case CONSPEC_HEX_EXP: *--p = 'a'; break; + case CONSPEC_HEX_EXP_UP: *--p = 'A'; break; + default: + return -1; /* Actually a bug. */ + } +#ifdef HAVE_LONG_DOUBLE + if (use_dbl) + *--p = 'L'; +#endif + if (arg->precision != NO_FIELD_VALUE) + { + /* Limit it to a meaningful value so that even a stupid sprintf + won't overflow our buffer. */ + n = arg->precision <= 100? arg->precision : 100; + do + { + *--p = '0' + (n % 10); + n /= 10; + } + while (n); + *--p = '.'; + } + if ((arg->flags & FLAG_ALT_CONV)) + *--p = '#'; + *--p = '%'; +#ifdef HAVE_LONG_DOUBLE + if (use_dbl) + sprintf (numbuf, p, adblfloat); + else +#endif /*HAVE_LONG_DOUBLE*/ + sprintf (numbuf, p, afloat); + p = numbuf; + n = strlen (numbuf); + pend = p + n; + + if (*p =='-') + { + signchar = '-'; + p++; + n--; + } + else if ((arg->flags & FLAG_PLUS_SIGN)) + signchar = '+'; + else if ((arg->flags & FLAG_SPACE_PLUS)) + signchar = ' '; + + n_extra = !!signchar; + + if (!(arg->flags & FLAG_LEFT_JUST) + && arg->width >= 0 && arg->width - n_extra > n) + { + rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes); + if (rc) + return rc; + } + + if (signchar) + { + rc = outfnc (outfncarg, &signchar, 1); + if (rc) + return rc; + *nbytes += 1; + } + + rc = outfnc (outfncarg, p, pend - p); + if (rc) + return rc; + *nbytes += pend - p; + + if ((arg->flags & FLAG_LEFT_JUST) + && arg->width >= 0 && arg->width - n_extra > n) + { + rc = pad_out (outfnc, outfncarg, ' ', arg->width - n_extra - n, nbytes); + if (rc) + return rc; + } + + return 0; +} + + +/* "c" formatting. */ +static int +pr_char (estream_printf_out_t outfnc, void *outfncarg, + argspec_t arg, value_t value, size_t *nbytes) +{ + int rc; + char buf[1]; + + if (arg->vt != VALTYPE_INT) + return -1; + buf[0] = (unsigned int)value.a_int; + rc = outfnc (outfncarg, buf, 1); + if(rc) + return rc; + *nbytes += 1; + + return 0; +} + + +/* "s" formatting. */ +static int +pr_string (estream_printf_out_t outfnc, void *outfncarg, + argspec_t arg, value_t value, size_t *nbytes, + gpgrt_string_filter_t sf, void *sfvalue, int string_no) +{ + int rc; + size_t n; + const char *string, *s; + + if (arg->vt != VALTYPE_STRING) + return -1; + if (sf) + string = sf (value.a_string, string_no, sfvalue); + else + string = value.a_string; + + if (!string) + string = "(null)"; + if (arg->precision >= 0) + { + /* Test for nul after N so that we can pass a non-nul terminated + string. */ + for (n=0,s=string; n < arg->precision && *s; s++) + n++; + } + else + n = strlen (string); + + if (!(arg->flags & FLAG_LEFT_JUST) + && arg->width >= 0 && arg->width > n ) + { + rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes); + if (rc) + goto leave; + } + + rc = outfnc (outfncarg, string, n); + if (rc) + goto leave; + *nbytes += n; + + if ((arg->flags & FLAG_LEFT_JUST) + && arg->width >= 0 && arg->width > n) + { + rc = pad_out (outfnc, outfncarg, ' ', arg->width - n, nbytes); + if (rc) + goto leave; + } + + rc = 0; + + leave: + if (sf) /* Tell the filter to release resources. */ + sf (value.a_string, -1, sfvalue); + + return rc; +} + + +/* "p" formatting. */ +static int +pr_pointer (estream_printf_out_t outfnc, void *outfncarg, + argspec_t arg, value_t value, size_t *nbytes) +{ + int rc; +#if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P) + unsigned long long aulong; +#else + unsigned long aulong; +#endif + char numbuf[100]; + char *p, *pend; + + if (arg->vt != VALTYPE_POINTER) + return -1; + /* We assume that a pointer can be converted to an unsigned long. + That is not correct for a 64 bit Windows, but then we assume that + long long is supported and usable for storing a pointer. */ +#if defined(HAVE_LONG_LONG_INT) && (SIZEOF_UNSIGNED_LONG < SIZEOF_VOID_P) + aulong = (unsigned long long)value.a_void_ptr; +#else + aulong = (unsigned long)value.a_void_ptr; +#endif + + p = pend = numbuf + DIM(numbuf); + do + { + *--p = "0123456789abcdefx"[(aulong % 16)]; + aulong /= 16; + } + while (aulong); + while ((pend-p) < 2*sizeof (aulong)) + *--p = '0'; + *--p = 'x'; + *--p = '0'; + + rc = outfnc (outfncarg, p, pend - p); + if (rc) + return rc; + *nbytes += pend - p; + + return 0; +} + +/* "n" pesudo format operation. */ +static int +pr_bytes_so_far (estream_printf_out_t outfnc, void *outfncarg, + argspec_t arg, value_t value, size_t *nbytes) +{ + (void)outfnc; + (void)outfncarg; + + switch (arg->vt) + { + case VALTYPE_SCHAR_PTR: + *value.a_schar_ptr = (signed char)(unsigned int)(*nbytes); + break; + case VALTYPE_SHORT_PTR: + *value.a_short_ptr = (short)(unsigned int)(*nbytes); + break; + case VALTYPE_LONG_PTR: + *value.a_long_ptr = (long)(*nbytes); + break; +#ifdef HAVE_LONG_LONG_INT + case VALTYPE_LONGLONG_PTR: + *value.a_longlong_ptr = (long long)(*nbytes); + break; +#endif +#ifdef HAVE_INTMAX_T + case VALTYPE_INTMAX_PTR: + *value.a_intmax_ptr = (intmax_t)(*nbytes); + break; +#endif + case VALTYPE_SIZE_PTR: + *value.a_size_ptr = (*nbytes); + break; +#ifdef HAVE_PTRDIFF_T + case VALTYPE_PTRDIFF_PTR: + *value.a_ptrdiff_ptr = (ptrdiff_t)(*nbytes); + break; +#endif + case VALTYPE_INT_PTR: + *value.a_int_ptr = (int)(*nbytes); + break; + default: + return -1; /* An unsupported type has been used. */ + } + + return 0; +} + + + +/* Run the actual formatting. OUTFNC and OUTFNCARG are the output + * functions. FORMAT is format string ARGSPECS is the parsed format + * string, ARGSPECS_LEN the number of items in ARGSPECS. + * STRING_FILTER is an optional function to filter string (%s) args; + * it is called with the original string and the count of already + * processed %s arguments. Its return value will be used instead of + * the original string. VALUETABLE holds the values and may be + * directly addressed using the position arguments given by ARGSPECS. + * MYERRNO is used for the "%m" conversion. NBYTES well be updated to + * reflect the number of bytes send to the output function. */ +static int +do_format (estream_printf_out_t outfnc, void *outfncarg, + gpgrt_string_filter_t sf, void *sfvalue, + const char *format, argspec_t argspecs, size_t argspecs_len, + valueitem_t valuetable, int myerrno, size_t *nbytes) +{ + int rc = 0; + const char *s; + argspec_t arg = argspecs; + int argidx = 0; /* Only used for assertion. */ + size_t n; + value_t value; + int string_no = 0; /* Number of processed "%s" args. */ + + s = format; + while ( *s ) + { + if (*s != '%') + { + s++; + continue; + } + if (s != format) + { + rc = outfnc (outfncarg, format, (n=s-format)); + if (rc) + return rc; + *nbytes += n; + } + if (s[1] == '%') + { + /* Note that this code ignores one trailing percent escape - + this is however okay as the args parser must have + detected this already. */ + rc = outfnc (outfncarg, s, 1); + if (rc) + return rc; + *nbytes += 1; + s += 2; + format = s; + continue; + } + + /* Save the next start. */ + s += arg->length; + format = s; + + gpgrt_assert (argidx < argspecs_len); + argidx++; + + /* Apply indirect field width and precision values. */ + if (arg->width == STAR_FIELD_VALUE) + { + gpgrt_assert (valuetable[arg->width_pos-1].vt == VALTYPE_INT); + arg->width = valuetable[arg->width_pos-1].value.a_int; + if (arg->width < 0) + { + arg->width = -arg->width; + arg->flags |= FLAG_LEFT_JUST; + } + } + if (arg->precision == STAR_FIELD_VALUE) + { + gpgrt_assert (valuetable[arg->precision_pos-1].vt == VALTYPE_INT); + arg->precision = valuetable[arg->precision_pos-1].value.a_int; + if (arg->precision < 0) + arg->precision = NO_FIELD_VALUE; + } + + if (arg->arg_pos == -1 && arg->conspec == CONSPEC_STRERROR) + value.a_string = strerror (myerrno); + else + { + gpgrt_assert (arg->vt == valuetable[arg->arg_pos-1].vt); + value = valuetable[arg->arg_pos-1].value; + } + + switch (arg->conspec) + { + case CONSPEC_UNKNOWN: gpgrt_assert (!"bug"); break; + + case CONSPEC_DECIMAL: + case CONSPEC_UNSIGNED: + case CONSPEC_OCTAL: + case CONSPEC_HEX: + case CONSPEC_HEX_UP: + rc = pr_integer (outfnc, outfncarg, arg, value, nbytes); + break; + case CONSPEC_FLOAT: + case CONSPEC_FLOAT_UP: + case CONSPEC_EXP: + case CONSPEC_EXP_UP: + case CONSPEC_F_OR_G: + case CONSPEC_F_OR_G_UP: + case CONSPEC_HEX_EXP: + case CONSPEC_HEX_EXP_UP: + rc = pr_float (outfnc, outfncarg, arg, value, nbytes); + break; + case CONSPEC_CHAR: + rc = pr_char (outfnc, outfncarg, arg, value, nbytes); + break; + case CONSPEC_STRING: + rc = pr_string (outfnc, outfncarg, arg, value, nbytes, + sf, sfvalue, string_no++); + break; + case CONSPEC_STRERROR: + rc = pr_string (outfnc, outfncarg, arg, value, nbytes, + NULL, NULL, 0); + break; + case CONSPEC_POINTER: + rc = pr_pointer (outfnc, outfncarg, arg, value, nbytes); + break; + case CONSPEC_BYTES_SO_FAR: + rc = pr_bytes_so_far (outfnc, outfncarg, arg, value, nbytes); + break; + } + if (rc) + return rc; + arg++; + } + + /* Print out any trailing stuff. */ + n = s - format; + rc = n? outfnc (outfncarg, format, n) : 0; + if (!rc) + *nbytes += n; + + return rc; +} + + + + +/* The versatile printf formatting routine. It expects a callback + function OUTFNC and an opaque argument OUTFNCARG used for actual + output of the formatted stuff. FORMAT is the format specification + and VAARGS a variable argumemt list matching the arguments of + FORMAT. */ +int +_gpgrt_estream_format (estream_printf_out_t outfnc, + void *outfncarg, + gpgrt_string_filter_t sf, void *sfvalue, + const char *format, va_list vaargs) +{ + /* Buffer to hold the argspecs and a pointer to it.*/ + struct argspec_s argspecs_buffer[DEFAULT_MAX_ARGSPECS]; + argspec_t argspecs = argspecs_buffer; + size_t argspecs_len; /* Number of specifications in ARGSPECS. */ + + /* Buffer to hold the description for the values. */ + struct valueitem_s valuetable_buffer[DEFAULT_MAX_VALUES]; + valueitem_t valuetable = valuetable_buffer; + + int rc; /* Return code. */ + size_t argidx; /* Used to index the argspecs array. */ + size_t validx; /* Used to index the valuetable. */ + int max_pos; /* Highest argument position. */ + + size_t nbytes = 0; /* Keep track of the number of bytes passed to + the output function. */ + + int myerrno = errno; /* Save the errno for use with "%m". */ + + + /* Parse the arguments to come up with descriptive list. We can't + do this on the fly because we need to support positional + arguments. */ + rc = parse_format (format, &argspecs, DIM(argspecs_buffer), &argspecs_len); + if (rc) + goto leave; + + /* Check that all ARG_POS fields are set. */ + for (argidx=0,max_pos=0; argidx < argspecs_len; argidx++) + { + if (argspecs[argidx].arg_pos != -1 + && argspecs[argidx].arg_pos > max_pos) + max_pos = argspecs[argidx].arg_pos; + if (argspecs[argidx].width_pos > max_pos) + max_pos = argspecs[argidx].width_pos; + if (argspecs[argidx].precision_pos > max_pos) + max_pos = argspecs[argidx].precision_pos; + } + if (!max_pos) + { + /* Fill in all the positions. */ + for (argidx=0; argidx < argspecs_len; argidx++) + { + if (argspecs[argidx].width == STAR_FIELD_VALUE) + argspecs[argidx].width_pos = ++max_pos; + if (argspecs[argidx].precision == STAR_FIELD_VALUE) + argspecs[argidx].precision_pos = ++max_pos; + if (argspecs[argidx].arg_pos != -1 ) + argspecs[argidx].arg_pos = ++max_pos; + } + } + else + { + /* Check that they are all filled. More test are done later. */ + for (argidx=0; argidx < argspecs_len; argidx++) + { + if (!argspecs[argidx].arg_pos + || (argspecs[argidx].width == STAR_FIELD_VALUE + && !argspecs[argidx].width_pos) + || (argspecs[argidx].precision == STAR_FIELD_VALUE + && !argspecs[argidx].precision_pos)) + goto leave_einval; + } + } + /* Check that there is no overflow in max_pos and that it has a + reasonable length. There may never be more elements than the + number of characters in FORMAT. */ + if (max_pos < 0 || max_pos >= strlen (format)) + goto leave_einval; + +#ifdef DEBUG + dump_argspecs (argspecs, argspecs_len); +#endif + + /* Allocate a table to hold the values. If it is small enough we + use a stack allocated buffer. */ + if (max_pos > DIM(valuetable_buffer)) + { + valuetable = calloc (max_pos, sizeof *valuetable); + if (!valuetable) + goto leave_error; + } + else + { + for (validx=0; validx < DIM(valuetable_buffer); validx++) + { + valuetable[validx].vt = VALTYPE_UNSUPPORTED; + memset (&valuetable[validx].value, 0, + sizeof valuetable[validx].value); + } + } + for (argidx=0; argidx < argspecs_len; argidx++) + { + if (argspecs[argidx].arg_pos != - 1) + { + validx = argspecs[argidx].arg_pos - 1; + if (valuetable[validx].vt) + goto leave_einval; /* Already defined. */ + valuetable[validx].vt = argspecs[argidx].vt; + } + if (argspecs[argidx].width == STAR_FIELD_VALUE) + { + validx = argspecs[argidx].width_pos - 1; + if (valuetable[validx].vt) + goto leave_einval; /* Already defined. */ + valuetable[validx].vt = VALTYPE_INT; + } + if (argspecs[argidx].precision == STAR_FIELD_VALUE) + { + validx = argspecs[argidx].precision_pos - 1; + if (valuetable[validx].vt) + goto leave_einval; /* Already defined. */ + valuetable[validx].vt = VALTYPE_INT; + } + } + + /* Read all the arguments. This will error out for unsupported + types and for not given positional arguments. */ + rc = read_values (valuetable, max_pos, vaargs); + if (rc) + goto leave_einval; + +/* for (validx=0; validx < max_pos; validx++) */ +/* fprintf (stderr, "%2d: vt=%d\n", validx, valuetable[validx].vt); */ + + /* Everything has been collected, go ahead with the formatting. */ + rc = do_format (outfnc, outfncarg, sf, sfvalue, format, + argspecs, argspecs_len, valuetable, myerrno, &nbytes); + + goto leave; + + leave_einval: + _set_errno (EINVAL); + leave_error: + rc = -1; + leave: + if (valuetable != valuetable_buffer) + free (valuetable); + if (argspecs != argspecs_buffer) + free (argspecs); + return rc; +} + + + + +/* A simple output handler utilizing stdio. */ +static int +plain_stdio_out (void *outfncarg, const char *buf, size_t buflen) +{ + FILE *fp = (FILE*)outfncarg; + + if ( fwrite (buf, buflen, 1, fp) != 1 ) + return -1; + return 0; +} + + +/* A replacement for printf. */ +int +_gpgrt_estream_printf (const char *format, ...) +{ + int rc; + va_list arg_ptr; + + va_start (arg_ptr, format); + rc = _gpgrt_estream_format (plain_stdio_out, stderr, NULL, NULL, + format, arg_ptr); + va_end (arg_ptr); + + return rc; +} + +/* A replacement for fprintf. */ +int +_gpgrt_estream_fprintf (FILE *fp, const char *format, ...) +{ + int rc; + va_list arg_ptr; + + va_start (arg_ptr, format); + rc = _gpgrt_estream_format (plain_stdio_out, fp, NULL, NULL, + format, arg_ptr); + va_end (arg_ptr); + + return rc; +} + +/* A replacement for vfprintf. */ +int +_gpgrt_estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr) +{ + return _gpgrt_estream_format (plain_stdio_out, fp, NULL, NULL, + format, arg_ptr); +} + + + +/* Communication object used between estream_snprintf and + fixed_buffer_out. */ +struct fixed_buffer_parm_s +{ + size_t size; /* Size of the buffer. */ + size_t count; /* Number of bytes requested for output. */ + size_t used; /* Used size of the buffer. */ + char *buffer; /* Provided buffer. */ +}; + +/* A simple malloced buffer output handler. */ +static int +fixed_buffer_out (void *outfncarg, const char *buf, size_t buflen) +{ + struct fixed_buffer_parm_s *parm = outfncarg; + + parm->count += buflen; + + if (!parm->buffer) + ; + else if (parm->used + buflen < parm->size) + { + /* Handle the common case that everything fits into the buffer + separately. */ + memcpy (parm->buffer + parm->used, buf, buflen); + parm->used += buflen; + } + else + { + /* The slow version of above. */ + for ( ;buflen && parm->used < parm->size; buflen--) + parm->buffer[parm->used++] = *buf++; + } + + return 0; +} + + +/* A replacement for vsnprintf. */ +int +_gpgrt_estream_vsnprintf (char *buf, size_t bufsize, + const char *format, va_list arg_ptr) +{ + struct fixed_buffer_parm_s parm; + int rc; + + parm.size = bufsize; + parm.count = 0; + parm.used = 0; + parm.buffer = bufsize?buf:NULL; + rc = _gpgrt_estream_format (fixed_buffer_out, &parm, NULL, NULL, + format, arg_ptr); + if (!rc) + rc = fixed_buffer_out (&parm, "", 1); /* Print terminating Nul. */ + if (rc == -1) + return -1; + if (bufsize && buf && parm.size && parm.count >= parm.size) + buf[parm.size-1] = 0; + + parm.count--; /* Do not count the trailing nul. */ + return (int)parm.count; /* Return number of bytes which would have + been written. */ +} + +/* A replacement for snprintf. */ +int +_gpgrt_estream_snprintf (char *buf, size_t bufsize, const char *format, ...) +{ + int rc; + va_list arg_ptr; + + va_start (arg_ptr, format); + rc = _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr); + va_end (arg_ptr); + + return rc; +} + + + +/* Communication object used between estream_asprintf and + dynamic_buffer_out. */ +struct dynamic_buffer_parm_s +{ + int error_flag; /* Internal helper. */ + size_t alloced; /* Allocated size of the buffer. */ + size_t used; /* Used size of the buffer. */ + char *buffer; /* Malloced buffer. */ +}; + +/* A simple malloced buffer output handler. */ +static int +dynamic_buffer_out (void *outfncarg, const char *buf, size_t buflen) +{ + struct dynamic_buffer_parm_s *parm = outfncarg; + + if (parm->error_flag) + { + /* Just in case some formatting routine did not checked for an + error. */ + _set_errno (parm->error_flag); + return -1; + } + + if (parm->used + buflen >= parm->alloced) + { + char *p; + + parm->alloced += buflen + 512; + p = my_printf_realloc (parm->buffer, parm->alloced); + if (!p) + { + parm->error_flag = errno ? errno : ENOMEM; + /* Wipe out what we already accumulated. This is useful in + case sensitive data is formatted. */ + memset (parm->buffer, 0, parm->used); + return -1; + } + parm->buffer = p; + } + memcpy (parm->buffer + parm->used, buf, buflen); + parm->used += buflen; + + return 0; +} + + +/* A replacement for vasprintf. As with the BSD version of vasprintf + -1 will be returned on error and NULL stored at BUFP. On success + the number of bytes printed will be returned. */ +int +_gpgrt_estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) +{ + struct dynamic_buffer_parm_s parm; + int rc; + + parm.error_flag = 0; + parm.alloced = 512; + parm.used = 0; + parm.buffer = my_printf_realloc (NULL, parm.alloced); + if (!parm.buffer) + { + *bufp = NULL; + return -1; + } + + rc = _gpgrt_estream_format (dynamic_buffer_out, &parm, NULL, NULL, + format, arg_ptr); + if (!rc) + rc = dynamic_buffer_out (&parm, "", 1); /* Print terminating Nul. */ + /* Fixme: Should we shrink the resulting buffer? */ + if (rc != -1 && parm.error_flag) + { + rc = -1; + _set_errno (parm.error_flag); + } + if (rc == -1) + { + memset (parm.buffer, 0, parm.used); + if (parm.buffer) + my_printf_realloc (parm.buffer, 0); + *bufp = NULL; + return -1; + } + gpgrt_assert (parm.used); /* We have at least the terminating Nul. */ + *bufp = parm.buffer; + return parm.used - 1; /* Do not include that Nul. */ +} + +/* A replacement for asprintf. As with the BSD of asprintf version -1 + will be returned on error and NULL stored at BUFP. On success the + number of bytes printed will be returned. */ +int +_gpgrt_estream_asprintf (char **bufp, const char *format, ...) +{ + int rc; + va_list arg_ptr; + + va_start (arg_ptr, format); + rc = _gpgrt_estream_vasprintf (bufp, format, arg_ptr); + va_end (arg_ptr); + + return rc; +} + +/* A variant of asprintf. The function returns the allocated buffer + or NULL on error; ERRNO is set in the error case. The caller + should use es_free to release the buffer. This function actually + belongs into estream-printf but we put it here as a convenience + and because es_free is required anyway. */ +char * +_gpgrt_estream_bsprintf (const char *format, ...) +{ + int rc; + va_list ap; + char *buf; + + va_start (ap, format); + rc = _gpgrt_estream_vasprintf (&buf, format, ap); + va_end (ap); + if (rc < 0) + return NULL; + return buf; +} diff --git a/comm/third_party/libgpg-error/src/estream-printf.h b/comm/third_party/libgpg-error/src/estream-printf.h new file mode 100644 index 0000000000..69c70520f3 --- /dev/null +++ b/comm/third_party/libgpg-error/src/estream-printf.h @@ -0,0 +1,153 @@ +/* estream-printf.h - Versatile mostly C-99 compliant printf formatting. + * Copyright (C) 2007, 2010, 2012 g10 Code GmbH + * + * This file is part of Libestream. + * + * Libestream is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libestream is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libestream; if not, see . + * + * ALTERNATIVELY, Libestream may be distributed under the terms of the + * following license, in which case the provisions of this license are + * required INSTEAD OF the GNU General Public License. If you wish to + * allow use of your version of this file only under the terms of the + * GNU General Public License, and not to allow others to use your + * version of this file under the terms of the following license, + * indicate your decision by deleting this paragraph and the license + * below. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ESTREAM_PRINTF_H +#define ESTREAM_PRINTF_H + +#include +#include + +/* To use this file with libraries the following macro is useful: + + #define _ESTREAM_EXT_SYM_PREFIX _foo_ + + This prefixes all external symbols with "_foo_". + + For the implementation of the code (estream-printf.c) the following + macros may be used to tune the implementation for certain systems: + + #define _ESTREAM_PRINTF_REALLOC foo_realloc + + Make estream_asprintf and estream_vasprintf use foo_realloc + instead of the standard realloc to allocate memory returned to + the caller. Note that foo_realloc needs to be C-90 compliant: + foo_realloc (NULL,n) is the same as a call to malloc(n) and + foo_realloc (a, 0) is the same as a call to free (a). + + #define _ESTREAM_PRINTF_EXTRA_INCLUDE "foo.h" + + This includes the file "foo.h" which may provide prototypes for + the custom memory allocation functions. + */ + + +#ifdef _ESTREAM_EXT_SYM_PREFIX +#ifndef _ESTREAM_PREFIX +#define _ESTREAM_PREFIX1(x,y) x ## y +#define _ESTREAM_PREFIX2(x,y) _ESTREAM_PREFIX1(x,y) +#define _ESTREAM_PREFIX(x) _ESTREAM_PREFIX2(_ESTREAM_EXT_SYM_PREFIX,x) +#endif /*_ESTREAM_PREFIX*/ +#define estream_printf_out_t _ESTREAM_PREFIX(estream_printf_out_t) +#define estream_format _ESTREAM_PREFIX(estream_format) +#define estream_printf _ESTREAM_PREFIX(estream_printf) +#define estream_fprintf _ESTREAM_PREFIX(estream_fprintf) +#define estream_vfprintf _ESTREAM_PREFIX(estream_vfprintf) +#define estream_snprintf _ESTREAM_PREFIX(estream_snprintf) +#define estream_vsnprintf _ESTREAM_PREFIX(estream_vsnprintf) +#define estream_asprintf _ESTREAM_PREFIX(estream_asprintf) +#define estream_vasprintf _ESTREAM_PREFIX(estream_vasprintf) +#endif /*_ESTREAM_EXT_SYM_PREFIX*/ + +#ifndef _ESTREAM_GCC_A_PRINTF +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) +# define _ESTREAM_GCC_A_PRINTF( f, a ) \ + __attribute__ ((format (__gnu_printf__,f,a))) +# elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) +# define _ESTREAM_GCC_A_PRINTF( f, a ) \ + __attribute__ ((format (printf,f,a))) +# else +# define _ESTREAM_GCC_A_PRINTF( f, a ) +# endif +#endif /*_ESTREAM_GCC_A_PRINTF*/ + + +#ifdef __cplusplus +extern "C" +{ +#if 0 +} +#endif +#endif + + +typedef int (*estream_printf_out_t) + (void *outfncarg, const char *buf, size_t buflen); + +int _gpgrt_estream_format (estream_printf_out_t outfnc, void *outfncarg, + char *(*string_filter)(const char *s,int n,void*st), + void *string_filter_state, + const char *format, va_list vaargs) + _ESTREAM_GCC_A_PRINTF(5,0); +int _gpgrt_estream_printf (const char *format, ...) + _ESTREAM_GCC_A_PRINTF(1,2); +int _gpgrt_estream_fprintf (FILE *fp, const char *format, ... ) + _ESTREAM_GCC_A_PRINTF(2,3); +int _gpgrt_estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr) + _ESTREAM_GCC_A_PRINTF(2,0); +int _gpgrt_estream_snprintf (char *buf, size_t bufsize, const char *format, ...) + _ESTREAM_GCC_A_PRINTF(3,4); +int _gpgrt_estream_vsnprintf (char *buf,size_t bufsize, + const char *format, va_list arg_ptr) + _ESTREAM_GCC_A_PRINTF(3,0); +int _gpgrt_estream_asprintf (char **bufp, const char *format, ...) + _ESTREAM_GCC_A_PRINTF(2,3); +int _gpgrt_estream_vasprintf (char **bufp, const char *format, va_list arg_ptr) + _ESTREAM_GCC_A_PRINTF(2,0); +char *_gpgrt_estream_bsprintf (const char *format, ...) + _ESTREAM_GCC_A_PRINTF(1,2); + + +#ifdef __cplusplus +} +#endif +#endif /*ESTREAM_PRINTF_H*/ diff --git a/comm/third_party/libgpg-error/src/estream.c b/comm/third_party/libgpg-error/src/estream.c new file mode 100644 index 0000000000..f75e05210e --- /dev/null +++ b/comm/third_party/libgpg-error/src/estream.c @@ -0,0 +1,5414 @@ +/* estream.c - Extended Stream I/O Library + * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011, + * 2014, 2015, 2016, 2017 g10 Code GmbH + * + * This file is part of Libestream. + * + * Libestream is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libestream is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libestream; if not, see . + * + * ALTERNATIVELY, Libestream may be distributed under the terms of the + * following license, in which case the provisions of this license are + * required INSTEAD OF the GNU General Public License. If you wish to + * allow use of your version of this file only under the terms of the + * GNU General Public License, and not to allow others to use your + * version of this file under the terms of the following license, + * indicate your decision by deleting this paragraph and the license + * below. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef USE_ESTREAM_SUPPORT_H +# include +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(_WIN32) && !defined(HAVE_W32_SYSTEM) +# define HAVE_W32_SYSTEM 1 +# if defined(__MINGW32CE__) && !defined (HAVE_W32CE_SYSTEM) +# define HAVE_W32CE_SYSTEM +# endif +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_W32_SYSTEM +# ifdef HAVE_WINSOCK2_H +# include +# endif +# include +#else +# ifdef HAVE_POLL_H +# include +# endif +#endif + +/* Enable tracing. The value is the module name to be printed. */ +/*#define ENABLE_TRACING "estream"*/ + +#include "gpgrt-int.h" +#include "estream-printf.h" +#include "thread.h" +#include "lock.h" + + +#ifndef O_BINARY +# define O_BINARY 0 +#endif +#ifndef HAVE_DOSISH_SYSTEM +# ifdef HAVE_W32_SYSTEM +# define HAVE_DOSISH_SYSTEM 1 +# endif +#endif + + +#ifdef HAVE_W32_SYSTEM +# ifndef S_IRGRP +# define S_IRGRP S_IRUSR +# endif +# ifndef S_IROTH +# define S_IROTH S_IRUSR +# endif +# ifndef S_IWGRP +# define S_IWGRP S_IWUSR +# endif +# ifndef S_IWOTH +# define S_IWOTH S_IWUSR +# endif +# ifndef S_IXGRP +# define S_IXGRP S_IXUSR +# endif +# ifndef S_IXOTH +# define S_IXOTH S_IXUSR +# endif +#endif + +#if !defined (EWOULDBLOCK) && defined (HAVE_W32_SYSTEM) +/* Compatibility with errno.h from mingw-2.0 */ +# define EWOULDBLOCK 140 +#endif + +#ifndef EAGAIN +# define EAGAIN EWOULDBLOCK +#endif + + +#ifdef HAVE_W32CE_SYSTEM +# define _set_errno(a) gpg_err_set_errno ((a)) +/* Setmode is missing in cegcc but available since CE 5.0. */ +int _setmode (int handle, int mode); +# define setmode(a,b) _setmode ((a),(b)) +#else +# define _set_errno(a) do { errno = (a); } while (0) +#endif + +#define IS_INVALID_FD(a) ((a) == -1) + +/* Calculate array dimension. */ +#ifndef DIM +#define DIM(array) (sizeof (array) / sizeof (*array)) +#endif + +/* A helper macro used to convert to a hex string. */ +#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A')) + + +/* Generally used types. */ + +typedef void *(*func_realloc_t) (void *mem, size_t size); +typedef void (*func_free_t) (void *mem); + + + + +/* + * A linked list to hold active stream objects. + * Protected by ESTREAM_LIST_LOCK. + */ +struct estream_list_s +{ + struct estream_list_s *next; + estream_t stream; /* Entry is not used if NULL. */ +}; +typedef struct estream_list_s *estream_list_t; +static estream_list_t estream_list; + +/* + * File descriptors registered for use as the standard file handles. + * Protected by ESTREAM_LIST_LOCK. + */ +static int custom_std_fds[3]; +static unsigned char custom_std_fds_valid[3]; + +/* + * A lock object to protect ESTREAM LIST, CUSTOM_STD_FDS and + * CUSTOM_STD_FDS_VALID. Used by lock_list() and unlock_list(). + */ +GPGRT_LOCK_DEFINE (estream_list_lock); + + +/* + * Error code replacements. + */ +#ifndef EOPNOTSUPP +# define EOPNOTSUPP ENOSYS +#endif + + +/* Local prototypes. */ +static void fname_set_internal (estream_t stream, const char *fname, int quote); + + + + +/* + * Memory allocation wrappers used in this file. + */ +static void * +mem_alloc (size_t n) +{ + return _gpgrt_malloc (n); +} + +static void * +mem_realloc (void *p, size_t n) +{ + return _gpgrt_realloc (p, n); +} + +static void +mem_free (void *p) +{ + if (p) + _gpgrt_free (p); +} + + +/* + * A Windows helper function to map a W32 API error code to a standard + * system error code. That actually belong into sysutils but to allow + * standalone use of estream we keep it here. + */ +#ifdef HAVE_W32_SYSTEM +static int +map_w32_to_errno (DWORD w32_err) +{ + switch (w32_err) + { + case 0: + return 0; + + case ERROR_FILE_NOT_FOUND: + return ENOENT; + + case ERROR_PATH_NOT_FOUND: + return ENOENT; + + case ERROR_ACCESS_DENIED: + return EPERM; /* ReactOS uses EACCES ("Permission denied") and + * is likely right because they used an + * undocumented function to associate the error + * codes. However we have always used EPERM + * ("Operation not permitted", e.g. function is + * required to be called by root) and we better + * stick to that to avoid surprising bugs. */ + + case ERROR_INVALID_HANDLE: + return EBADF; + + case ERROR_INVALID_BLOCK: + return ENOMEM; + + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + + case ERROR_NO_DATA: + return EPIPE; + + case ERROR_ALREADY_EXISTS: + return EEXIST; + + /* This mapping has been taken from reactOS. */ + case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; + case ERROR_ARENA_TRASHED: return ENOMEM; + case ERROR_BAD_ENVIRONMENT: return E2BIG; + case ERROR_BAD_FORMAT: return ENOEXEC; + case ERROR_INVALID_DRIVE: return ENOENT; + case ERROR_CURRENT_DIRECTORY: return EACCES; + case ERROR_NOT_SAME_DEVICE: return EXDEV; + case ERROR_NO_MORE_FILES: return ENOENT; + case ERROR_WRITE_PROTECT: return EACCES; + case ERROR_BAD_UNIT: return EACCES; + case ERROR_NOT_READY: return EACCES; + case ERROR_BAD_COMMAND: return EACCES; + case ERROR_CRC: return EACCES; + case ERROR_BAD_LENGTH: return EACCES; + case ERROR_SEEK: return EACCES; + case ERROR_NOT_DOS_DISK: return EACCES; + case ERROR_SECTOR_NOT_FOUND: return EACCES; + case ERROR_OUT_OF_PAPER: return EACCES; + case ERROR_WRITE_FAULT: return EACCES; + case ERROR_READ_FAULT: return EACCES; + case ERROR_GEN_FAILURE: return EACCES; + case ERROR_SHARING_VIOLATION: return EACCES; + case ERROR_LOCK_VIOLATION: return EACCES; + case ERROR_WRONG_DISK: return EACCES; + case ERROR_SHARING_BUFFER_EXCEEDED: return EACCES; + case ERROR_BAD_NETPATH: return ENOENT; + case ERROR_NETWORK_ACCESS_DENIED: return EACCES; + case ERROR_BAD_NET_NAME: return ENOENT; + case ERROR_FILE_EXISTS: return EEXIST; + case ERROR_CANNOT_MAKE: return EACCES; + case ERROR_FAIL_I24: return EACCES; + case ERROR_NO_PROC_SLOTS: return EAGAIN; + case ERROR_DRIVE_LOCKED: return EACCES; + case ERROR_BROKEN_PIPE: return EPIPE; + case ERROR_DISK_FULL: return ENOSPC; + case ERROR_INVALID_TARGET_HANDLE: return EBADF; + case ERROR_WAIT_NO_CHILDREN: return ECHILD; + case ERROR_CHILD_NOT_COMPLETE: return ECHILD; + case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; + case ERROR_SEEK_ON_DEVICE: return EACCES; + case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY; + case ERROR_NOT_LOCKED: return EACCES; + case ERROR_BAD_PATHNAME: return ENOENT; + case ERROR_MAX_THRDS_REACHED: return EAGAIN; + case ERROR_LOCK_FAILED: return EACCES; + case ERROR_INVALID_STARTING_CODESEG: return ENOEXEC; + case ERROR_INVALID_STACKSEG: return ENOEXEC; + case ERROR_INVALID_MODULETYPE: return ENOEXEC; + case ERROR_INVALID_EXE_SIGNATURE: return ENOEXEC; + case ERROR_EXE_MARKED_INVALID: return ENOEXEC; + case ERROR_BAD_EXE_FORMAT: return ENOEXEC; + case ERROR_ITERATED_DATA_EXCEEDS_64k: return ENOEXEC; + case ERROR_INVALID_MINALLOCSIZE: return ENOEXEC; + case ERROR_DYNLINK_FROM_INVALID_RING: return ENOEXEC; + case ERROR_IOPL_NOT_ENABLED: return ENOEXEC; + case ERROR_INVALID_SEGDPL: return ENOEXEC; + case ERROR_AUTODATASEG_EXCEEDS_64k: return ENOEXEC; + case ERROR_RING2SEG_MUST_BE_MOVABLE: return ENOEXEC; + case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: return ENOEXEC; + case ERROR_INFLOOP_IN_RELOC_CHAIN: return ENOEXEC; + case ERROR_FILENAME_EXCED_RANGE: return ENOENT; + case ERROR_NESTING_NOT_ALLOWED: return EAGAIN; + case ERROR_NOT_ENOUGH_QUOTA: return ENOMEM; + + default: + return EIO; + } +} + +/* Wrapper to be used by other modules to set ERRNO from the Windows + * error. EC may be -1 to get the last error. */ +void +_gpgrt_w32_set_errno (int ec) +{ + if (ec == -1) + ec = GetLastError (); + _set_errno (map_w32_to_errno (ec)); +} + + +#endif /*HAVE_W32_SYSTEM*/ + +/* + * Replacement for a missing memrchr. + */ +#ifndef HAVE_MEMRCHR +static void * +memrchr (const void *buffer, int c, size_t n) +{ + const unsigned char *p = buffer; + + for (p += n; n ; n--) + if (*--p == c) + return (void *)p; + return NULL; +} +#endif /*HAVE_MEMRCHR*/ + + + +/* + * Wrappers to lock a stream or the list of streams. + */ +#if 0 +# define dbg_lock_0(f) fprintf (stderr, "estream: " f); +# define dbg_lock_1(f, a) fprintf (stderr, "estream: " f, (a)); +# define dbg_lock_2(f, a, b) fprintf (stderr, "estream: " f, (a), (b)); +#else +# define dbg_lock_0(f) +# define dbg_lock_1(f, a) +# define dbg_lock_2(f, a, b) +#endif + +static int +init_stream_lock (estream_t _GPGRT__RESTRICT stream) +{ + int rc; + + if (!stream->intern->samethread) + { + dbg_lock_1 ("enter init_stream_lock for %p\n", stream); + memset (&stream->intern->lock, 0 , sizeof stream->intern->lock); + rc = _gpgrt_lock_init (&stream->intern->lock); + dbg_lock_2 ("leave init_stream_lock for %p: rc=%d\n", stream, rc); + } + else + rc = 0; + return rc; +} + + +static void +destroy_stream_lock (estream_t _GPGRT__RESTRICT stream) +{ + if (!stream->intern->samethread) + { + dbg_lock_1 ("enter destroy_stream_lock for %p\n", stream); + _gpgrt_lock_destroy (&stream->intern->lock); + dbg_lock_1 ("leave destroy_stream_lock for %p\n", stream); + } +} + + +static void +lock_stream (estream_t _GPGRT__RESTRICT stream) +{ + if (!stream->intern->samethread) + { + dbg_lock_1 ("enter lock_stream for %p\n", stream); + _gpgrt_lock_lock (&stream->intern->lock); + dbg_lock_1 ("leave lock_stream for %p\n", stream); + } +} + + +static int +trylock_stream (estream_t _GPGRT__RESTRICT stream) +{ + int rc; + + if (!stream->intern->samethread) + { + dbg_lock_1 ("enter trylock_stream for %p\n", stream); + rc = _gpgrt_lock_trylock (&stream->intern->lock)? 0 : -1; + dbg_lock_2 ("leave trylock_stream for %p: rc=%d\n", stream, rc); + } + else + rc = 0; + return rc; +} + + +static void +unlock_stream (estream_t _GPGRT__RESTRICT stream) +{ + if (!stream->intern->samethread) + { + dbg_lock_1 ("enter unlock_stream for %p\n", stream); + _gpgrt_lock_unlock (&stream->intern->lock); + dbg_lock_1 ("leave unlock_stream for %p\n", stream); + } +} + + +static void +lock_list (void) +{ + dbg_lock_0 ("enter lock_list\n"); + _gpgrt_lock_lock (&estream_list_lock); + dbg_lock_0 ("leave lock_list\n"); +} + + +static void +unlock_list (void) +{ + dbg_lock_0 ("enter unlock_list\n"); + _gpgrt_lock_unlock (&estream_list_lock); + dbg_lock_0 ("leave unlock_list\n"); +} + + +#undef dbg_lock_0 +#undef dbg_lock_1 +#undef dbg_lock_2 + + + +/* + * Manipulation of the list of stream. + */ + +/* + * Add STREAM to the list of registered stream objects. If + * WITH_LOCKED_LIST is true it is assumed that the list of streams is + * already locked. The implementation is straightforward: We first + * look for an unused entry in the list and use that; if none is + * available we put a new item at the head. We drawback of the + * strategy never to shorten the list is that a one time allocation of + * many streams will lead to scanning unused entries later. If that + * turns out to be a problem, we may either free some items from the + * list or append new entries at the end; or use a table. Returns 0 + * on success; on error or non-zero is returned and ERRNO set. + */ +static int +do_list_add (estream_t stream, int with_locked_list) +{ + estream_list_t item; + + if (!with_locked_list) + lock_list (); + + for (item = estream_list; item && item->stream; item = item->next) + ; + if (!item) + { + item = mem_alloc (sizeof *item); + if (item) + { + item->next = estream_list; + estream_list = item; + } + } + if (item) + item->stream = stream; + + if (!with_locked_list) + unlock_list (); + + return item? 0 : -1; +} + +/* + * Remove STREAM from the list of registered stream objects. + */ +static void +do_list_remove (estream_t stream, int with_locked_list) +{ + estream_list_t item, item_prev = NULL; + + if (!with_locked_list) + lock_list (); + + for (item = estream_list; item; item = item->next) + if (item->stream == stream) + break; + else + item_prev = item; + + if (item) + { + if (item_prev) + item_prev->next = item->next; + else + estream_list = item->next; + mem_free (item); + } + + if (!with_locked_list) + unlock_list (); +} + + + +/* + * The atexit handler for the entire gpgrt. + */ +static void +do_deinit (void) +{ + /* Flush all streams. */ + _gpgrt_fflush (NULL); + + /* We should release the estream_list. However there is one + problem: That list is also used to search for the standard + estream file descriptors. If we would remove the entire list, + any use of es_foo in another atexit function may re-create the + list and the streams with possible undesirable effects. Given + that we don't close the stream either, it should not matter that + we keep the list and let the OS clean it up at process end. */ + + /* Reset the syscall clamp. */ + _gpgrt_set_syscall_clamp (NULL, NULL); +} + + +/* + * Initialization of the estream module. + */ +int +_gpgrt_estream_init (void) +{ + static int initialized; + + if (!initialized) + { + initialized = 1; + atexit (do_deinit); + } + return 0; +} + + +/* + * Implementation of memory based I/O. + */ + +/* Cookie for memory objects. */ +typedef struct estream_cookie_mem +{ + unsigned int modeflags; /* Open flags. */ + unsigned char *memory; /* Allocated data buffer. */ + size_t memory_size; /* Allocated size of MEMORY. */ + size_t memory_limit; /* Caller supplied maximum allowed + allocation size or 0 for no limit. */ + size_t offset; /* Current offset in MEMORY. */ + size_t data_len; /* Used length of data in MEMORY. */ + size_t block_size; /* Block size. */ + struct { + unsigned int grow: 1; /* MEMORY is allowed to grow. */ + } flags; + func_realloc_t func_realloc; + func_free_t func_free; +} *estream_cookie_mem_t; + + +/* + * Create function for memory objects. DATA is either NULL or a user + * supplied buffer with the initial conetnt of the memory buffer. If + * DATA is NULL, DATA_N and DATA_LEN need to be 0 as well. If DATA is + * not NULL, DATA_N gives the allocated size of DATA and DATA_LEN the + * used length in DATA. If this function succeeds DATA is now owned + * by this function. If GROW is false FUNC_REALLOC is not + * required. + */ +static int +func_mem_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie, + unsigned char *_GPGRT__RESTRICT data, size_t data_n, + size_t data_len, + size_t block_size, unsigned int grow, + func_realloc_t func_realloc, func_free_t func_free, + unsigned int modeflags, + size_t memory_limit) +{ + estream_cookie_mem_t mem_cookie; + int err; + + if (!data && (data_n || data_len)) + { + _set_errno (EINVAL); + return -1; + } + if (grow && func_free && !func_realloc) + { + _set_errno (EINVAL); + return -1; + } + + /* Round a memory limit up to the next block length. */ + if (memory_limit && block_size) + { + memory_limit += block_size - 1; + memory_limit /= block_size; + memory_limit *= block_size; + } + + mem_cookie = mem_alloc (sizeof (*mem_cookie)); + if (!mem_cookie) + err = -1; + else + { + mem_cookie->modeflags = modeflags; + mem_cookie->memory = data; + mem_cookie->memory_size = data_n; + mem_cookie->memory_limit = memory_limit; + mem_cookie->offset = 0; + mem_cookie->data_len = data_len; + mem_cookie->block_size = block_size; + mem_cookie->flags.grow = !!grow; + mem_cookie->func_realloc + = grow? (func_realloc ? func_realloc : mem_realloc) : NULL; + mem_cookie->func_free = func_free ? func_free : mem_free; + *cookie = mem_cookie; + err = 0; + } + + return err; +} + + +/* + * Read function for memory objects. + */ +static gpgrt_ssize_t +func_mem_read (void *cookie, void *buffer, size_t size) +{ + estream_cookie_mem_t mem_cookie = cookie; + gpgrt_ssize_t ret; + + if (!size) /* Just the pending data check. */ + return (mem_cookie->data_len - mem_cookie->offset)? 0 : -1; + + if (size > mem_cookie->data_len - mem_cookie->offset) + size = mem_cookie->data_len - mem_cookie->offset; + + if (size) + { + memcpy (buffer, mem_cookie->memory + mem_cookie->offset, size); + mem_cookie->offset += size; + } + + ret = size; + return ret; +} + + +/* + * Write function for memory objects. + */ +static gpgrt_ssize_t +func_mem_write (void *cookie, const void *buffer, size_t size) +{ + estream_cookie_mem_t mem_cookie = cookie; + gpgrt_ssize_t ret; + size_t nleft; + + if (!size) + return 0; /* A flush is a NOP for memory objects. */ + + if (mem_cookie->modeflags & O_APPEND) + { + /* Append to data. */ + mem_cookie->offset = mem_cookie->data_len; + } + + gpgrt_assert (mem_cookie->memory_size >= mem_cookie->offset); + nleft = mem_cookie->memory_size - mem_cookie->offset; + + /* If we are not allowed to grow the buffer, limit the size to the + left space. */ + if (!mem_cookie->flags.grow && size > nleft) + size = nleft; + + /* Enlarge the memory buffer if needed. */ + if (size > nleft) + { + unsigned char *newbuf; + size_t newsize; + + if (!mem_cookie->memory_size) + newsize = size; /* Not yet allocated. */ + else + newsize = mem_cookie->memory_size + (size - nleft); + if (newsize < mem_cookie->offset) + { + _set_errno (EINVAL); + return -1; + } + + /* Round up to the next block length. BLOCK_SIZE should always + be set; we check anyway. */ + if (mem_cookie->block_size) + { + newsize += mem_cookie->block_size - 1; + if (newsize < mem_cookie->offset) + { + _set_errno (EINVAL); + return -1; + } + newsize /= mem_cookie->block_size; + newsize *= mem_cookie->block_size; + } + + /* Check for a total limit. */ + if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit) + { + _set_errno (ENOSPC); + return -1; + } + + gpgrt_assert (mem_cookie->func_realloc); + newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize); + if (!newbuf) + return -1; + + mem_cookie->memory = newbuf; + mem_cookie->memory_size = newsize; + + gpgrt_assert (mem_cookie->memory_size >= mem_cookie->offset); + nleft = mem_cookie->memory_size - mem_cookie->offset; + + gpgrt_assert (size <= nleft); + } + + memcpy (mem_cookie->memory + mem_cookie->offset, buffer, size); + if (mem_cookie->offset + size > mem_cookie->data_len) + mem_cookie->data_len = mem_cookie->offset + size; + mem_cookie->offset += size; + + ret = size; + return ret; +} + + +/* + * Seek function for memory objects. + */ +static int +func_mem_seek (void *cookie, gpgrt_off_t *offset, int whence) +{ + estream_cookie_mem_t mem_cookie = cookie; + gpgrt_off_t pos_new; + + switch (whence) + { + case SEEK_SET: + pos_new = *offset; + break; + + case SEEK_CUR: + pos_new = mem_cookie->offset += *offset; + break; + + case SEEK_END: + pos_new = mem_cookie->data_len += *offset; + break; + + default: + _set_errno (EINVAL); + return -1; + } + + if (pos_new > mem_cookie->memory_size) + { + size_t newsize; + void *newbuf; + + if (!mem_cookie->flags.grow) + { + _set_errno (ENOSPC); + return -1; + } + + newsize = pos_new + mem_cookie->block_size - 1; + if (newsize < pos_new) + { + _set_errno (EINVAL); + return -1; + } + newsize /= mem_cookie->block_size; + newsize *= mem_cookie->block_size; + + if (mem_cookie->memory_limit && newsize > mem_cookie->memory_limit) + { + _set_errno (ENOSPC); + return -1; + } + + gpgrt_assert (mem_cookie->func_realloc); + newbuf = mem_cookie->func_realloc (mem_cookie->memory, newsize); + if (!newbuf) + return -1; + + mem_cookie->memory = newbuf; + mem_cookie->memory_size = newsize; + } + + if (pos_new > mem_cookie->data_len) + { + /* Fill spare space with zeroes. */ + memset (mem_cookie->memory + mem_cookie->data_len, + 0, pos_new - mem_cookie->data_len); + mem_cookie->data_len = pos_new; + } + + mem_cookie->offset = pos_new; + *offset = pos_new; + + return 0; +} + + +/* + * The IOCTL function for memory objects. + */ +static int +func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len) +{ + estream_cookie_mem_t mem_cookie = cookie; + int ret; + + if (cmd == COOKIE_IOCTL_SNATCH_BUFFER) + { + /* Return the internal buffer of the stream to the caller and + invalidate it for the stream. */ + *(void**)ptr = mem_cookie->memory; + *len = mem_cookie->data_len; + mem_cookie->memory = NULL; + mem_cookie->memory_size = 0; + mem_cookie->offset = 0; + ret = 0; + } + else if (cmd == COOKIE_IOCTL_TRUNCATE) + { + gpgrt_off_t length = *(gpgrt_off_t *)ptr; + + ret = func_mem_seek (cookie, &length, SEEK_SET); + if (ret != -1) + mem_cookie->data_len = mem_cookie->offset; + } + else + { + _set_errno (EINVAL); + ret = -1; + } + + return ret; +} + + +/* + * The destroy function for memory objects. + */ +static int +func_mem_destroy (void *cookie) +{ + estream_cookie_mem_t mem_cookie = cookie; + + if (cookie) + { + mem_cookie->func_free (mem_cookie->memory); + mem_free (mem_cookie); + } + return 0; +} + +/* + * Access object for the memory functions. + */ +static struct cookie_io_functions_s estream_functions_mem = + { + { + func_mem_read, + func_mem_write, + func_mem_seek, + func_mem_destroy, + }, + func_mem_ioctl, + }; + + + +/* + * Implementation of file descriptor based I/O. + */ + +/* Cookie for fd objects. */ +typedef struct estream_cookie_fd +{ + int fd; /* The file descriptor we are using for actual output. */ + int no_close; /* If set we won't close the file descriptor. */ + int nonblock; /* Non-blocking mode is enabled. */ +} *estream_cookie_fd_t; + + +/* + * Create function for objects indentified by a libc file descriptor. + */ +static int +func_fd_create (void **cookie, int fd, unsigned int modeflags, int no_close) +{ + estream_cookie_fd_t fd_cookie; + int err; + + trace (("enter: fd=%d mf=%x nc=%d", fd, modeflags, no_close)); + + fd_cookie = mem_alloc (sizeof (*fd_cookie)); + if (! fd_cookie) + err = -1; + else + { +#ifdef HAVE_DOSISH_SYSTEM + /* Make sure it is in binary mode if requested. */ + if ( (modeflags & O_BINARY) ) + setmode (fd, O_BINARY); +#endif + fd_cookie->fd = fd; + fd_cookie->no_close = no_close; + fd_cookie->nonblock = !!(modeflags & O_NONBLOCK); + *cookie = fd_cookie; + err = 0; + } + + trace_errno (err, ("leave: cookie=%p err=%d", *cookie, err)); + return err; +} + + +/* + * Read function for fd objects. + */ +static gpgrt_ssize_t +func_fd_read (void *cookie, void *buffer, size_t size) + +{ + estream_cookie_fd_t file_cookie = cookie; + gpgrt_ssize_t bytes_read; + + trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size)); + + if (!size) + bytes_read = -1; /* We don't know whether anything is pending. */ + else if (IS_INVALID_FD (file_cookie->fd)) + { + _gpgrt_yield (); + bytes_read = 0; + } + else + { + _gpgrt_pre_syscall (); + do + { + bytes_read = read (file_cookie->fd, buffer, size); + } + while (bytes_read == -1 && errno == EINTR); + _gpgrt_post_syscall (); + } + + trace_errno (bytes_read == -1, ("leave: bytes_read=%d", (int)bytes_read)); + return bytes_read; +} + + +/* + * Write function for fd objects. + */ +static gpgrt_ssize_t +func_fd_write (void *cookie, const void *buffer, size_t size) +{ + estream_cookie_fd_t file_cookie = cookie; + gpgrt_ssize_t bytes_written; + + trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size)); + + if (IS_INVALID_FD (file_cookie->fd)) + { + _gpgrt_yield (); + bytes_written = size; /* Yeah: Success writing to the bit bucket. */ + } + else if (buffer) + { + _gpgrt_pre_syscall (); + do + { + bytes_written = write (file_cookie->fd, buffer, size); + } + while (bytes_written == -1 && errno == EINTR); + _gpgrt_post_syscall (); + } + else + bytes_written = size; /* Note that for a flush SIZE should be 0. */ + + trace_errno (bytes_written == -1, + ("leave: bytes_written=%d", (int)bytes_written)); + return bytes_written; +} + + +/* + * Seek function for fd objects. + */ +static int +func_fd_seek (void *cookie, gpgrt_off_t *offset, int whence) +{ + estream_cookie_fd_t file_cookie = cookie; + gpgrt_off_t offset_new; + int err; + + if (IS_INVALID_FD (file_cookie->fd)) + { + _set_errno (ESPIPE); + err = -1; + } + else + { + _gpgrt_pre_syscall (); + offset_new = lseek (file_cookie->fd, *offset, whence); + _gpgrt_post_syscall (); + if (offset_new == -1) + err = -1; + else + { + *offset = offset_new; + err = 0; + } + } + + return err; +} + + +/* + * The IOCTL function for fd objects. + */ +static int +func_fd_ioctl (void *cookie, int cmd, void *ptr, size_t *len) +{ + estream_cookie_fd_t fd_cookie = cookie; + int ret; + + if (cmd == COOKIE_IOCTL_NONBLOCK && !len) + { + fd_cookie->nonblock = !!ptr; + if (IS_INVALID_FD (fd_cookie->fd)) + { + _set_errno (EINVAL); + ret = -1; + } + else + { +#ifdef _WIN32 + _set_errno (EOPNOTSUPP); /* FIXME: Implement for Windows. */ + ret = -1; +#else + _set_errno (0); + ret = fcntl (fd_cookie->fd, F_GETFL, 0); + if (ret == -1 && errno) + ; + else if (fd_cookie->nonblock) + ret = fcntl (fd_cookie->fd, F_SETFL, (ret | O_NONBLOCK)); + else + ret = fcntl (fd_cookie->fd, F_SETFL, (ret & ~O_NONBLOCK)); +#endif + } + } + else + { + _set_errno (EINVAL); + ret = -1; + } + + return ret; +} + +/* + * The destroy function for fd objects. + */ +static int +func_fd_destroy (void *cookie) +{ + estream_cookie_fd_t fd_cookie = cookie; + int err; + + trace (("enter: cookie=%p", cookie)); + + if (fd_cookie) + { + if (IS_INVALID_FD (fd_cookie->fd)) + err = 0; + else + err = fd_cookie->no_close? 0 : close (fd_cookie->fd); + mem_free (fd_cookie); + } + else + err = 0; + + trace_errno (err,("leave: err=%d", err)); + return err; +} + + +/* + * Access object for the fd functions. + */ +static struct cookie_io_functions_s estream_functions_fd = + { + { + func_fd_read, + func_fd_write, + func_fd_seek, + func_fd_destroy, + }, + func_fd_ioctl, + }; + + + + +/* + * Implementation of W32 handle based I/O. + */ +#ifdef HAVE_W32_SYSTEM + +/* Cookie for fd objects. */ +typedef struct estream_cookie_w32 +{ + HANDLE hd; /* The handle we are using for actual output. */ + int no_close; /* If set we won't close the handle. */ + int no_syscall_clamp; /* Do not use the syscall clamp. */ +} *estream_cookie_w32_t; + + +/* + * Create function for w32 handle objects. + */ +static int +func_w32_create (void **cookie, HANDLE hd, + unsigned int modeflags, int no_close, int no_syscall_clamp) +{ + estream_cookie_w32_t w32_cookie; + int err; + + trace (("enter: hd=%p mf=%x nc=%d nsc=%d", + hd, modeflags, no_close, no_syscall_clamp)); + w32_cookie = mem_alloc (sizeof (*w32_cookie)); + if (!w32_cookie) + err = -1; + else + { + /* CR/LF translations are not supported when using the bare W32 + API. If that is really required we need to implemented that + in the upper layer. */ + (void)modeflags; + + w32_cookie->hd = hd; + w32_cookie->no_close = no_close; + w32_cookie->no_syscall_clamp = no_syscall_clamp; + *cookie = w32_cookie; + err = 0; + } + + trace_errno (err, ("leave: cookie=%p err=%d", *cookie, err)); + return err; +} + +/* + * Read function for W32 handle objects. + * + * Note that this function may also be used by the reader thread of + * w32-stream. In that case the NO_SYSCALL_CLAMP is set. + */ +static gpgrt_ssize_t +func_w32_read (void *cookie, void *buffer, size_t size) +{ + estream_cookie_w32_t w32_cookie = cookie; + gpgrt_ssize_t bytes_read; + + trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size)); + + if (!size) + bytes_read = -1; /* We don't know whether anything is pending. */ + else if (w32_cookie->hd == INVALID_HANDLE_VALUE) + { + _gpgrt_yield (); + bytes_read = 0; + } + else + { + if (!w32_cookie->no_syscall_clamp) + _gpgrt_pre_syscall (); + do + { + DWORD nread, ec; + + trace (("cookie=%p calling ReadFile", cookie)); + if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL)) + { + ec = GetLastError (); + trace (("cookie=%p ReadFile failed: ec=%ld", cookie,ec)); + if (ec == ERROR_BROKEN_PIPE) + bytes_read = 0; /* Like our pth_read we handle this as EOF. */ + else + { + _set_errno (map_w32_to_errno (ec)); + bytes_read = -1; + } + } + else + bytes_read = (int)nread; + } + while (bytes_read == -1 && errno == EINTR); + if (!w32_cookie->no_syscall_clamp) + _gpgrt_post_syscall (); + } + + trace_errno (bytes_read==-1,("leave: bytes_read=%d", (int)bytes_read)); + return bytes_read; +} + + +/* + * Write function for W32 handle objects. + * + * Note that this function may also be used by the writer thread of + * w32-stream. In that case the NO_SYSCALL_CLAMP is set. + */ +static gpgrt_ssize_t +func_w32_write (void *cookie, const void *buffer, size_t size) +{ + estream_cookie_w32_t w32_cookie = cookie; + gpgrt_ssize_t bytes_written; + + trace (("enter: cookie=%p buffer=%p size=%d", cookie, buffer, (int)size)); + + if (w32_cookie->hd == INVALID_HANDLE_VALUE) + { + _gpgrt_yield (); + bytes_written = size; /* Yeah: Success writing to the bit bucket. */ + } + else if (buffer) + { + if (!w32_cookie->no_syscall_clamp) + _gpgrt_pre_syscall (); + do + { + DWORD nwritten; + + trace (("cookie=%p calling WriteFile", cookie)); + if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL)) + { + DWORD ec = GetLastError (); + trace (("cookie=%p WriteFile failed: ec=%ld", cookie, ec)); + _set_errno (map_w32_to_errno (ec)); + bytes_written = -1; + } + else + bytes_written = (int)nwritten; + } + while (bytes_written == -1 && errno == EINTR); + if (!w32_cookie->no_syscall_clamp) + _gpgrt_post_syscall (); + } + else + bytes_written = size; /* Note that for a flush SIZE should be 0. */ + + trace_errno (bytes_written==-1, + ("leave: bytes_written=%d", (int)bytes_written)); + return bytes_written; +} + + +/* + * Seek function for W32 handle objects. + */ +static int +func_w32_seek (void *cookie, gpgrt_off_t *offset, int whence) +{ + estream_cookie_w32_t w32_cookie = cookie; + DWORD method; + LARGE_INTEGER distance, newoff; + + if (w32_cookie->hd == INVALID_HANDLE_VALUE) + { + _set_errno (ESPIPE); + return -1; + } + + if (whence == SEEK_SET) + { + method = FILE_BEGIN; + distance.QuadPart = (unsigned long long)(*offset); + } + else if (whence == SEEK_CUR) + { + method = FILE_CURRENT; + distance.QuadPart = (long long)(*offset); + } + else if (whence == SEEK_END) + { + method = FILE_END; + distance.QuadPart = (long long)(*offset); + } + else + { + _set_errno (EINVAL); + return -1; + } +#ifdef HAVE_W32CE_SYSTEM +# warning need to use SetFilePointer +#else + if (!w32_cookie->no_syscall_clamp) + _gpgrt_pre_syscall (); + if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method)) + { + _set_errno (map_w32_to_errno (GetLastError ())); + _gpgrt_post_syscall (); + return -1; + } + if (!w32_cookie->no_syscall_clamp) + _gpgrt_post_syscall (); +#endif + /* Note that gpgrt_off_t is always 64 bit. */ + *offset = (gpgrt_off_t)newoff.QuadPart; + return 0; +} + + +/* + * Destroy function for W32 handle objects. + */ +static int +func_w32_destroy (void *cookie) +{ + estream_cookie_w32_t w32_cookie = cookie; + int err; + + trace (("enter: cookie=%p", cookie)); + + if (w32_cookie) + { + if (w32_cookie->hd == INVALID_HANDLE_VALUE) + err = 0; + else if (w32_cookie->no_close) + err = 0; + else + { + trace (("cookie=%p closing handle %p", cookie, w32_cookie->hd)); + if (!CloseHandle (w32_cookie->hd)) + { + DWORD ec = GetLastError (); + trace (("cookie=%p CloseHandle failed: ec=%ld", cookie,ec)); + _set_errno (map_w32_to_errno (ec)); + err = -1; + } + else + err = 0; + } + mem_free (w32_cookie); + } + else + err = 0; + + trace_errno (err, ("leave: err=%d", err)); + return err; +} + + +/* + * Access object for the W32 handle based objects. + */ +static struct cookie_io_functions_s estream_functions_w32 = + { + { + func_w32_read, + func_w32_write, + func_w32_seek, + func_w32_destroy, + }, + NULL, + }; +#endif /*HAVE_W32_SYSTEM*/ + + + + +/* + * Implementation of stdio based I/O. + */ + +/* Cookie for fp objects. */ +typedef struct estream_cookie_fp +{ + FILE *fp; /* The file pointer we are using for actual output. */ + int no_close; /* If set we won't close the file pointer. */ +} *estream_cookie_fp_t; + + +/* + * Create function for stdio based objects. + */ +static int +func_fp_create (void **cookie, FILE *fp, + unsigned int modeflags, int no_close) +{ + estream_cookie_fp_t fp_cookie; + int err; + + fp_cookie = mem_alloc (sizeof *fp_cookie); + if (!fp_cookie) + err = -1; + else + { +#ifdef HAVE_DOSISH_SYSTEM + /* Make sure it is in binary mode if requested. */ + if ( (modeflags & O_BINARY) ) + setmode (fileno (fp), O_BINARY); +#else + (void)modeflags; +#endif + fp_cookie->fp = fp; + fp_cookie->no_close = no_close; + *cookie = fp_cookie; + err = 0; + } + + return err; +} + + +/* + * Read function for stdio based objects. + */ +static gpgrt_ssize_t +func_fp_read (void *cookie, void *buffer, size_t size) + +{ + estream_cookie_fp_t file_cookie = cookie; + gpgrt_ssize_t bytes_read; + + if (!size) + return -1; /* We don't know whether anything is pending. */ + + if (file_cookie->fp) + { + _gpgrt_pre_syscall (); + bytes_read = fread (buffer, 1, size, file_cookie->fp); + _gpgrt_post_syscall (); + } + else + bytes_read = 0; + if (!bytes_read && ferror (file_cookie->fp)) + return -1; + return bytes_read; +} + + +/* + * Write function for stdio bases objects. + */ +static gpgrt_ssize_t +func_fp_write (void *cookie, const void *buffer, size_t size) +{ + estream_cookie_fp_t file_cookie = cookie; + size_t bytes_written; + + if (file_cookie->fp) + { + _gpgrt_pre_syscall (); + if (buffer) + { +#ifdef HAVE_W32_SYSTEM + /* Using an fwrite to stdout connected to the console fails + with the error "Not enough space" for an fwrite size of + >= 52KB (tested on Windows XP SP2). To solve this we + always chunk the writes up into smaller blocks. */ + bytes_written = 0; + while (bytes_written < size) + { + size_t cnt = size - bytes_written; + + if (cnt > 32*1024) + cnt = 32*1024; + if (fwrite ((const char*)buffer + bytes_written, + cnt, 1, file_cookie->fp) != 1) + break; /* Write error. */ + bytes_written += cnt; + } +#else + bytes_written = fwrite (buffer, 1, size, file_cookie->fp); +#endif + } + else /* Only flush requested. */ + bytes_written = size; + + fflush (file_cookie->fp); + _gpgrt_post_syscall (); + } + else + bytes_written = size; /* Successfully written to the bit bucket. */ + + if (bytes_written != size) + return -1; + return bytes_written; +} + + +/* + * Seek function for stdio based objects. + */ +static int +func_fp_seek (void *cookie, gpgrt_off_t *offset, int whence) +{ + estream_cookie_fp_t file_cookie = cookie; + long int offset_new; + + if (!file_cookie->fp) + { + _set_errno (ESPIPE); + return -1; + } + + _gpgrt_pre_syscall (); + if ( fseek (file_cookie->fp, (long int)*offset, whence) ) + { + /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */ + /* errno,strerror (errno)); */ + _gpgrt_post_syscall (); + return -1; + } + + offset_new = ftell (file_cookie->fp); + _gpgrt_post_syscall (); + if (offset_new == -1) + { + /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n", */ + /* errno,strerror (errno)); */ + return -1; + } + *offset = offset_new; + return 0; +} + + +/* + * Destroy function for stdio based objects. + */ +static int +func_fp_destroy (void *cookie) +{ + estream_cookie_fp_t fp_cookie = cookie; + int err; + + if (fp_cookie) + { + if (fp_cookie->fp) + { + _gpgrt_pre_syscall (); + fflush (fp_cookie->fp); + _gpgrt_post_syscall (); + err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp); + } + else + err = 0; + mem_free (fp_cookie); + } + else + err = 0; + + return err; +} + + +/* + * Access object for stdio based objects. + */ +static struct cookie_io_functions_s estream_functions_fp = + { + { + func_fp_read, + func_fp_write, + func_fp_seek, + func_fp_destroy, + }, + NULL, + }; + + + + +/* + * Implementation of file name based I/O. + * + * Note that only a create function is required because the other + * operations ares handled by file descriptor based I/O. + */ + +#ifdef HAVE_W32_SYSTEM +static int +any8bitchar (const char *string) +{ + if (string) + for ( ; *string; string++) + if ((*string & 0x80)) + return 1; + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + +/* Create function for objects identified by a file name. */ +static int +func_file_create (void **cookie, int *filedes, + const char *path, unsigned int modeflags, unsigned int cmode) +{ + estream_cookie_fd_t file_cookie; + int err; + int fd; + + err = 0; + + file_cookie = mem_alloc (sizeof (*file_cookie)); + if (! file_cookie) + { + err = -1; + goto out; + } + +#ifdef HAVE_W32_SYSTEM + if (any8bitchar (path)) + { + wchar_t *wpath; + + wpath = _gpgrt_utf8_to_wchar (path); + if (!wpath) + fd = -1; + else + { + fd = _wopen (wpath, modeflags, cmode); + _gpgrt_free_wchar (wpath); + } + } + else /* Avoid unnecessary conversion. */ + fd = open (path, modeflags, cmode); +#else + fd = open (path, modeflags, cmode); +#endif + if (fd == -1) + { + err = -1; + goto out; + } +#ifdef HAVE_DOSISH_SYSTEM + /* Make sure it is in binary mode if requested. */ + if ( (modeflags & O_BINARY) ) + setmode (fd, O_BINARY); +#endif + + file_cookie->fd = fd; + file_cookie->no_close = 0; + *cookie = file_cookie; + *filedes = fd; + + out: + + if (err) + mem_free (file_cookie); + + return err; +} + + + +/* Flags used by parse_mode and friends. */ +#define X_SAMETHREAD (1 << 0) +#define X_SYSOPEN (1 << 1) +#define X_POLLABLE (1 << 2) + +/* Parse the mode flags of fopen et al. In addition to the POSIX + * defined mode flags keyword parameters are supported. These are + * key/value pairs delimited by comma and optional white spaces. + * Keywords and values may not contain a comma or white space; unknown + * keywords are skipped. Supported keywords are: + * + * mode= + * + * Creates a file and gives the new file read and write permissions + * for the user and read permission for the group. The format of + * the string is the same as shown by the -l option of the ls(1) + * command. However the first letter must be a dash and it is + * allowed to leave out trailing dashes. If this keyword parameter + * is not given the default mode for creating files is "-rw-rw-r--" + * (664). Note that the system still applies the current umask to + * the mode when creating a file. Example: + * + * "wb,mode=-rw-r--" + * + * samethread + * + * Assumes that the object is only used by the creating thread and + * disables any internal locking. This keyword is also found on + * IBM systems. + * + * nonblock + * + * The object is opened in non-blocking mode. This is the same as + * calling gpgrt_set_nonblock on the file. + * + * sysopen + * + * The object is opened in sysmode. On POSIX this is a NOP but + * under Windows the direct W32 API functions (HANDLE) are used + * instead of their libc counterparts (fd). + * FIXME: The functionality is not yet implemented. + * + * pollable + * + * The object is opened in a way suitable for use with es_poll. On + * POSIX this is a NOP but under Windows we create up to two + * threads, one for reading and one for writing, do any I/O there, + * and synchronize with them in order to support es_poll. + * + * Note: R_CMODE is optional because is only required by functions + * which are able to creat a file. + */ +static int +parse_mode (const char *modestr, + unsigned int *modeflags, + unsigned int *r_xmode, + unsigned int *r_cmode) +{ + unsigned int omode, oflags, cmode; + int got_cmode = 0; + + *r_xmode = 0; + + switch (*modestr) + { + case 'r': + omode = O_RDONLY; + oflags = 0; + break; + case 'w': + omode = O_WRONLY; + oflags = O_TRUNC | O_CREAT; + break; + case 'a': + omode = O_WRONLY; + oflags = O_APPEND | O_CREAT; + break; + default: + _set_errno (EINVAL); + return -1; + } + for (modestr++; *modestr; modestr++) + { + switch (*modestr) + { + case '+': + omode = O_RDWR; + break; + case 'b': + oflags |= O_BINARY; + break; + case 'x': + oflags |= O_EXCL; + break; + case ',': + goto keyvalue; + default: /* Ignore unknown flags. */ + break; + } + } + + keyvalue: + /* Parse key/value pairs (similar to fopen on mainframes). */ + for (cmode=0; *modestr == ','; modestr += strcspn (modestr, ",")) + { + modestr++; + modestr += strspn (modestr, " \t"); + if (!strncmp (modestr, "mode=", 5)) + { + static struct { + char letter; + unsigned int value; + } table[] = { { '-', 0 }, + { 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR }, + { 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP }, + { 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH }}; + int idx; + + got_cmode = 1; + modestr += 5; + /* For now we only support a string as used by ls(1) and no + octal numbers. The first character must be a dash. */ + for (idx=0; idx < 10 && *modestr; idx++, modestr++) + { + if (*modestr == table[idx].letter) + cmode |= table[idx].value; + else if (*modestr != '-') + break; + } + if (*modestr && !strchr (" \t,", *modestr)) + { + _set_errno (EINVAL); + return -1; + } + } + else if (!strncmp (modestr, "samethread", 10)) + { + modestr += 10; + if (*modestr && !strchr (" \t,", *modestr)) + { + _set_errno (EINVAL); + return -1; + } + *r_xmode |= X_SAMETHREAD; + } + else if (!strncmp (modestr, "nonblock", 8)) + { + modestr += 8; + if (*modestr && !strchr (" \t,", *modestr)) + { + _set_errno (EINVAL); + return -1; + } + oflags |= O_NONBLOCK; +#if HAVE_W32_SYSTEM + /* Currently, nonblock implies pollable on Windows. */ + *r_xmode |= X_POLLABLE; +#endif + } + else if (!strncmp (modestr, "sysopen", 7)) + { + modestr += 7; + if (*modestr && !strchr (" \t,", *modestr)) + { + _set_errno (EINVAL); + return -1; + } + *r_xmode |= X_SYSOPEN; + } + else if (!strncmp (modestr, "pollable", 8)) + { + modestr += 8; + if (*modestr && !strchr (" \t,", *modestr)) + { + _set_errno (EINVAL); + return -1; + } + *r_xmode |= X_POLLABLE; + } + } + if (!got_cmode) + cmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + + *modeflags = (omode | oflags); + if (r_cmode) + *r_cmode = cmode; + return 0; +} + + + +/* + * Low level stream functionality. + */ + +static int +fill_stream (estream_t stream) +{ + size_t bytes_read = 0; + int err; + + if (!stream->intern->func_read) + { + _set_errno (EOPNOTSUPP); + err = -1; + } + else if (!stream->buffer_size) + err = 0; + else + { + gpgrt_cookie_read_function_t func_read = stream->intern->func_read; + gpgrt_ssize_t ret; + + ret = (*func_read) (stream->intern->cookie, + stream->buffer, stream->buffer_size); + if (ret == -1) + { + bytes_read = 0; + err = -1; +#if EWOULDBLOCK != EAGAIN + if (errno == EWOULDBLOCK) + _set_errno (EAGAIN); +#endif + } + else + { + bytes_read = ret; + err = 0; + } + } + + if (err) + { + if (errno != EAGAIN) + { + if (errno == EPIPE) + stream->intern->indicators.hup = 1; + stream->intern->indicators.err = 1; + } + } + else if (!bytes_read) + stream->intern->indicators.eof = 1; + + stream->intern->offset += stream->data_len; + stream->data_len = bytes_read; + stream->data_offset = 0; + + return err; +} + +static int +flush_stream (estream_t stream) +{ + gpgrt_cookie_write_function_t func_write = stream->intern->func_write; + int err; + + gpgrt_assert (stream->flags.writing); + + if (stream->data_offset) + { + size_t bytes_written; + size_t data_flushed; + gpgrt_ssize_t ret; + + if (! func_write) + { + _set_errno (EOPNOTSUPP); + err = -1; + goto out; + } + + /* Note: to prevent an endless loop caused by user-provided + write-functions that pretend to have written more bytes than + they were asked to write, we have to check for + "(stream->data_offset - data_flushed) > 0" instead of + "stream->data_offset - data_flushed". */ + + data_flushed = 0; + err = 0; + + while ((((gpgrt_ssize_t) (stream->data_offset - data_flushed)) > 0) + && !err) + { + ret = (*func_write) (stream->intern->cookie, + stream->buffer + data_flushed, + stream->data_offset - data_flushed); + if (ret == -1) + { + bytes_written = 0; + err = -1; +#if EWOULDBLOCK != EAGAIN + if (errno == EWOULDBLOCK) + _set_errno (EAGAIN); +#endif + } + else + bytes_written = ret; + + data_flushed += bytes_written; + if (err) + break; + } + + stream->data_flushed += data_flushed; + if (stream->data_offset == data_flushed) + { + stream->intern->offset += stream->data_offset; + stream->data_offset = 0; + stream->data_flushed = 0; + } + } + else + err = 0; + + /* Always propagate flush event in case gpgrt_fflush was called + * explictly to do flush buffers in caller's cookie functions. */ + (*func_write) (stream->intern->cookie, NULL, 0); + + out: + + if (err && errno != EAGAIN) + { + if (errno == EPIPE) + stream->intern->indicators.hup = 1; + stream->intern->indicators.err = 1; + } + + return err; +} + + +/* + * Discard buffered data for STREAM. + */ +static void +es_empty (estream_t stream) +{ + gpgrt_assert (!stream->flags.writing); + stream->data_len = 0; + stream->data_offset = 0; + stream->unread_data_len = 0; +} + + +/* + * Initialize STREAM. + */ +static void +init_stream_obj (estream_t stream, + void *cookie, es_syshd_t *syshd, + gpgrt_stream_backend_kind_t kind, + struct cookie_io_functions_s functions, + unsigned int modeflags, unsigned int xmode) +{ + stream->intern->kind = kind; + stream->intern->cookie = cookie; + stream->intern->opaque = NULL; + stream->intern->offset = 0; + stream->intern->func_read = functions.public.func_read; + stream->intern->func_write = functions.public.func_write; + stream->intern->func_seek = functions.public.func_seek; + stream->intern->func_ioctl = functions.func_ioctl; + stream->intern->func_close = functions.public.func_close; + stream->intern->strategy = _IOFBF; + stream->intern->syshd = *syshd; + stream->intern->print_ntotal = 0; + stream->intern->indicators.err = 0; + stream->intern->indicators.eof = 0; + stream->intern->indicators.hup = 0; + stream->intern->is_stdstream = 0; + stream->intern->stdstream_fd = 0; + stream->intern->deallocate_buffer = 0; + stream->intern->printable_fname = NULL; + stream->intern->printable_fname_inuse = 0; + stream->intern->samethread = !! (xmode & X_SAMETHREAD); + stream->intern->onclose = NULL; + + stream->data_len = 0; + stream->data_offset = 0; + stream->data_flushed = 0; + stream->unread_data_len = 0; + /* Depending on the modeflags we set whether we start in writing or + reading mode. This is required in case we are working on a + stream which is not seeekable (like stdout). Without this + pre-initialization we would do a seek at the first write call and + as this will fail no output will be delivered. */ + if ((modeflags & O_WRONLY) || (modeflags & O_RDWR) ) + stream->flags.writing = 1; + else + stream->flags.writing = 0; +} + + +/* + * Deinitialize the STREAM object. This does _not_ free the memory, + * destroys the lock, or closes the underlying descriptor. + */ +static int +deinit_stream_obj (estream_t stream) +{ + gpgrt_cookie_close_function_t func_close; + int err, tmp_err; + + trace (("enter: stream %p", stream)); + func_close = stream->intern->func_close; + + err = 0; + if (stream->flags.writing) + { + tmp_err = flush_stream (stream); + if (!err) + err = tmp_err; + } + if (func_close) + { + trace (("stream %p calling func_close", stream)); + tmp_err = func_close (stream->intern->cookie); + if (!err) + err = tmp_err; + } + + mem_free (stream->intern->printable_fname); + stream->intern->printable_fname = NULL; + stream->intern->printable_fname_inuse = 0; + while (stream->intern->onclose) + { + notify_list_t tmp = stream->intern->onclose->next; + mem_free (stream->intern->onclose); + stream->intern->onclose = tmp; + } + + trace_errno (err, ("leave: stream %p err=%d", stream, err)); + return err; +} + + +/* + * Create a new stream and initialize it. On success the new stream + * handle is tsored at R_STREAM. On failure NULL is stored at + * R_STREAM. + */ +static int +create_stream (estream_t *r_stream, void *cookie, es_syshd_t *syshd, + gpgrt_stream_backend_kind_t kind, + struct cookie_io_functions_s functions, unsigned int modeflags, + unsigned int xmode, int with_locked_list) +{ + estream_internal_t stream_internal_new; + estream_t stream_new; + int err; +#if HAVE_W32_SYSTEM + void *old_cookie = NULL; +#endif + + stream_new = NULL; + stream_internal_new = NULL; + +#if HAVE_W32_SYSTEM + if ((xmode & X_POLLABLE) && kind != BACKEND_W32) + { + /* We require the W32 backend, because only that allows us to + * write directly using the native W32 API and to disable the + * system clamp. Note that func_w32_create has already been + * called with the flag to disable the system call clamp. */ + _set_errno (EINVAL); + err = -1; + goto out; + } +#endif /*HAVE_W32_SYSTEM*/ + + stream_new = mem_alloc (sizeof (*stream_new)); + if (! stream_new) + { + err = -1; + goto out; + } + + stream_internal_new = mem_alloc (sizeof (*stream_internal_new)); + if (! stream_internal_new) + { + err = -1; + goto out; + } + + stream_new->buffer = stream_internal_new->buffer; + stream_new->buffer_size = sizeof (stream_internal_new->buffer); + stream_new->unread_buffer = stream_internal_new->unread_buffer; + stream_new->unread_buffer_size = sizeof (stream_internal_new->unread_buffer); + stream_new->intern = stream_internal_new; + +#if HAVE_W32_SYSTEM + if ((xmode & X_POLLABLE)) + { + void *new_cookie; + + err = _gpgrt_w32_pollable_create (&new_cookie, modeflags, + functions, cookie); + if (err) + goto out; + + modeflags &= ~O_NONBLOCK; + old_cookie = cookie; + cookie = new_cookie; + kind = BACKEND_W32_POLLABLE; + functions = _gpgrt_functions_w32_pollable; + } +#endif /*HAVE_W32_SYSTEM*/ + + init_stream_obj (stream_new, cookie, syshd, kind, functions, modeflags, + xmode); + init_stream_lock (stream_new); + + err = do_list_add (stream_new, with_locked_list); + if (err) + goto out; + + *r_stream = stream_new; + + out: + + if (err) + { + trace_errno (err, ("leave: err=%d", err)); + if (stream_new) + { + deinit_stream_obj (stream_new); + destroy_stream_lock (stream_new); + mem_free (stream_new->intern); + mem_free (stream_new); + } + } +#if HAVE_W32_SYSTEM + else if (old_cookie) + trace (("leave: success stream=%p cookie=%p,%p", + *r_stream, old_cookie, cookie)); +#endif + else + trace (("leave: success stream=%p cookie=%p", *r_stream, cookie)); + + return err; +} + + +/* + * Deinitialize a stream object and destroy it. With CANCEL_MODE set + * try to cancel as much as possible (see _gpgrt_fcancel). + */ +static int +do_close (estream_t stream, int cancel_mode, int with_locked_list) +{ + int err; + + trace (("stream %p %s", stream, with_locked_list? "(with locked list)":"")); + + if (stream) + { + do_list_remove (stream, with_locked_list); + if (cancel_mode) + { + stream->flags.writing = 0; + es_empty (stream); + } + while (stream->intern->onclose) + { + notify_list_t tmp = stream->intern->onclose->next; + + if (stream->intern->onclose->fnc) + stream->intern->onclose->fnc (stream, + stream->intern->onclose->fnc_value); + mem_free (stream->intern->onclose); + stream->intern->onclose = tmp; + } + err = deinit_stream_obj (stream); + destroy_stream_lock (stream); + if (stream->intern->deallocate_buffer) + mem_free (stream->buffer); + mem_free (stream->intern); + mem_free (stream); + } + else + err = 0; + + trace_errno (err, ("stream %p err=%d", stream, err)); + return err; +} + + +/* + * The onclose worker function which is called with a locked + * stream. + */ +static int +do_onclose (estream_t stream, int mode, + void (*fnc) (estream_t, void*), void *fnc_value) +{ + notify_list_t item; + + if (!mode) + { + for (item = stream->intern->onclose; item; item = item->next) + if (item->fnc && item->fnc == fnc && item->fnc_value == fnc_value) + item->fnc = NULL; /* Disable this notification. */ + } + else + { + item = mem_alloc (sizeof *item); + if (!item) + return -1; + item->fnc = fnc; + item->fnc_value = fnc_value; + item->next = stream->intern->onclose; + stream->intern->onclose = item; + } + return 0; +} + + +/* + * Try to read BYTES_TO_READ bytes from STREAM into BUFFER in + * unbuffered-mode, storing the amount of bytes read at BYTES_READ. + */ +static int +do_read_nbf (estream_t _GPGRT__RESTRICT stream, + unsigned char *_GPGRT__RESTRICT buffer, + size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read) +{ + gpgrt_cookie_read_function_t func_read = stream->intern->func_read; + size_t data_read; + gpgrt_ssize_t ret; + int err; + + data_read = 0; + err = 0; + + while (bytes_to_read - data_read) + { + ret = (*func_read) (stream->intern->cookie, + buffer + data_read, bytes_to_read - data_read); + if (ret == -1) + { + err = -1; +#if EWOULDBLOCK != EAGAIN + if (errno == EWOULDBLOCK) + _set_errno (EAGAIN); +#endif + break; + } + else if (ret) + data_read += ret; + else + break; + } + + stream->intern->offset += data_read; + *bytes_read = data_read; + + return err; +} + + +/* + * Helper for check_pending. + */ +static int +check_pending_nbf (estream_t _GPGRT__RESTRICT stream) +{ + gpgrt_cookie_read_function_t func_read = stream->intern->func_read; + char buffer[1]; + + if (!(*func_read) (stream->intern->cookie, buffer, 0)) + return 1; /* Pending bytes. */ + return 0; /* No pending bytes or error. */ +} + + +/* + * Try to read BYTES_TO_READ bytes from STREAM into BUFFER in + * fully-buffered-mode, storing the amount of bytes read at + * BYTES_READ. + */ +static int +do_read_fbf (estream_t _GPGRT__RESTRICT stream, + unsigned char *_GPGRT__RESTRICT buffer, + size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read) +{ + size_t data_available; + size_t data_to_read; + size_t data_read; + int err; + + data_read = 0; + err = 0; + + while ((bytes_to_read - data_read) && (! err)) + { + if (stream->data_offset == stream->data_len) + { + /* Nothing more to read in current container, try to + fill container with new data. */ + err = fill_stream (stream); + if (! err) + if (! stream->data_len) + /* Filling did not result in any data read. */ + break; + } + + if (! err) + { + /* Filling resulted in some new data. */ + + data_to_read = bytes_to_read - data_read; + data_available = stream->data_len - stream->data_offset; + if (data_to_read > data_available) + data_to_read = data_available; + + memcpy (buffer + data_read, + stream->buffer + stream->data_offset, data_to_read); + stream->data_offset += data_to_read; + data_read += data_to_read; + } + } + + *bytes_read = data_read; + + return err; +} + + +/* + * Helper for check_pending. + */ +static int +check_pending_fbf (estream_t _GPGRT__RESTRICT stream) +{ + gpgrt_cookie_read_function_t func_read = stream->intern->func_read; + char buffer[1]; + + if (stream->data_offset == stream->data_len) + { + /* Nothing more to read in current container, check whether it + would be possible to fill the container with new data. */ + if (!(*func_read) (stream->intern->cookie, buffer, 0)) + return 1; /* Pending bytes. */ + } + else + return 1; + return 0; +} + + +/* + * Try to read BYTES_TO_READ bytes from STREAM into BUFFER in + * line-buffered-mode, storing the amount of bytes read at BYTES_READ. + */ +static int +do_read_lbf (estream_t _GPGRT__RESTRICT stream, + unsigned char *_GPGRT__RESTRICT buffer, + size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read) +{ + int err; + + err = do_read_fbf (stream, buffer, bytes_to_read, bytes_read); + + return err; +} + + +/* + * Try to read BYTES_TO_READ bytes from STREAM into BUFFER, storing + * the amount of bytes read at BYTES_READ. + */ +static int +es_readn (estream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT buffer_arg, + size_t bytes_to_read, size_t *_GPGRT__RESTRICT bytes_read) +{ + unsigned char *buffer = (unsigned char *)buffer_arg; + size_t data_read_unread, data_read; + int err; + + data_read_unread = 0; + data_read = 0; + err = 0; + + if (stream->flags.writing) + { + /* Switching to reading mode -> flush output. */ + err = flush_stream (stream); + if (err) + goto out; + stream->flags.writing = 0; + } + + /* Read unread data first. */ + while ((bytes_to_read - data_read_unread) && stream->unread_data_len) + { + buffer[data_read_unread] + = stream->unread_buffer[stream->unread_data_len - 1]; + stream->unread_data_len--; + data_read_unread++; + } + + switch (stream->intern->strategy) + { + case _IONBF: + err = do_read_nbf (stream, + buffer + data_read_unread, + bytes_to_read - data_read_unread, &data_read); + break; + case _IOLBF: + err = do_read_lbf (stream, + buffer + data_read_unread, + bytes_to_read - data_read_unread, &data_read); + break; + case _IOFBF: + err = do_read_fbf (stream, + buffer + data_read_unread, + bytes_to_read - data_read_unread, &data_read); + break; + } + + out: + + if (bytes_read) + *bytes_read = data_read_unread + data_read; + + return err; +} + + +/* + * Return true if at least one byte is pending for read. This is a + * best effort check and it it possible that bytes are still pending + * even if false is returned. If the stream is in writing mode it is + * switched to read mode. + */ +static int +check_pending (estream_t _GPGRT__RESTRICT stream) +{ + if (stream->flags.writing) + { + /* Switching to reading mode -> flush output. */ + if (flush_stream (stream)) + return 0; /* Better return 0 on error. */ + stream->flags.writing = 0; + } + + /* Check unread data first. */ + if (stream->unread_data_len) + return 1; + + switch (stream->intern->strategy) + { + case _IONBF: + return check_pending_nbf (stream); + case _IOLBF: + case _IOFBF: + return check_pending_fbf (stream); + } + + return 0; +} + + +/* + * Try to unread DATA_N bytes from DATA into STREAM, storing the + * amount of bytes successfully unread at BYTES_UNREAD. + */ +static void +es_unreadn (estream_t _GPGRT__RESTRICT stream, + const unsigned char *_GPGRT__RESTRICT data, size_t data_n, + size_t *_GPGRT__RESTRICT bytes_unread) +{ + size_t space_left; + + space_left = stream->unread_buffer_size - stream->unread_data_len; + + if (data_n > space_left) + data_n = space_left; + + if (! data_n) + goto out; + + memcpy (stream->unread_buffer + stream->unread_data_len, data, data_n); + stream->unread_data_len += data_n; + stream->intern->indicators.eof = 0; + + out: + + if (bytes_unread) + *bytes_unread = data_n; +} + + +/* + * Seek in STREAM. + */ +static int +es_seek (estream_t _GPGRT__RESTRICT stream, gpgrt_off_t offset, int whence, + gpgrt_off_t *_GPGRT__RESTRICT offset_new) +{ + gpgrt_cookie_seek_function_t func_seek = stream->intern->func_seek; + int err, ret; + gpgrt_off_t off; + + if (! func_seek) + { + _set_errno (EOPNOTSUPP); + err = -1; + goto out; + } + + if (stream->flags.writing) + { + /* Flush data first in order to prevent flushing it to the wrong + offset. */ + err = flush_stream (stream); + if (err) + goto out; + stream->flags.writing = 0; + } + + off = offset; + if (whence == SEEK_CUR) + { + off = off - stream->data_len + stream->data_offset; + off -= stream->unread_data_len; + } + + ret = (*func_seek) (stream->intern->cookie, &off, whence); + if (ret == -1) + { + err = -1; +#if EWOULDBLOCK != EAGAIN + if (errno == EWOULDBLOCK) + _set_errno (EAGAIN); +#endif + goto out; + } + + err = 0; + es_empty (stream); + + if (offset_new) + *offset_new = off; + + stream->intern->indicators.eof = 0; + stream->intern->offset = off; + + out: + + if (err) + { + if (errno == EPIPE) + stream->intern->indicators.hup = 1; + stream->intern->indicators.err = 1; + } + + return err; +} + + +/* + * Write BYTES_TO_WRITE bytes from BUFFER into STREAM in + * unbuffered-mode, storing the amount of bytes written at + * BYTES_WRITTEN. + */ +static int +es_write_nbf (estream_t _GPGRT__RESTRICT stream, + const unsigned char *_GPGRT__RESTRICT buffer, + size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written) +{ + gpgrt_cookie_write_function_t func_write = stream->intern->func_write; + size_t data_written; + gpgrt_ssize_t ret; + int err; + + if (bytes_to_write && (! func_write)) + { + _set_errno (EOPNOTSUPP); + err = -1; + goto out; + } + + data_written = 0; + err = 0; + + while (bytes_to_write - data_written) + { + ret = (*func_write) (stream->intern->cookie, + buffer + data_written, + bytes_to_write - data_written); + if (ret == -1) + { + err = -1; +#if EWOULDBLOCK != EAGAIN + if (errno == EWOULDBLOCK) + _set_errno (EAGAIN); +#endif + break; + } + else + data_written += ret; + } + + stream->intern->offset += data_written; + *bytes_written = data_written; + + out: + + return err; +} + + +/* + * Write BYTES_TO_WRITE bytes from BUFFER into STREAM in + * fully-buffered-mode, storing the amount of bytes written at + * BYTES_WRITTEN. + */ +static int +es_write_fbf (estream_t _GPGRT__RESTRICT stream, + const unsigned char *_GPGRT__RESTRICT buffer, + size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written) +{ + size_t space_available; + size_t data_to_write; + size_t data_written; + int err; + + data_written = 0; + err = 0; + + while ((bytes_to_write - data_written) && (! err)) + { + if (stream->data_offset == stream->buffer_size) + /* Container full, flush buffer. */ + err = flush_stream (stream); + + if (! err) + { + /* Flushing resulted in empty container. */ + + data_to_write = bytes_to_write - data_written; + space_available = stream->buffer_size - stream->data_offset; + if (data_to_write > space_available) + data_to_write = space_available; + + memcpy (stream->buffer + stream->data_offset, + buffer + data_written, data_to_write); + stream->data_offset += data_to_write; + data_written += data_to_write; + } + } + + *bytes_written = data_written; + + return err; +} + + +/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in + line-buffered-mode, storing the amount of bytes written in + *BYTES_WRITTEN. */ +static int +es_write_lbf (estream_t _GPGRT__RESTRICT stream, + const unsigned char *_GPGRT__RESTRICT buffer, + size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written) +{ + size_t data_flushed = 0; + size_t data_buffered = 0; + unsigned char *nlp; + int err = 0; + + nlp = memrchr (buffer, '\n', bytes_to_write); + if (nlp) + { + /* Found a newline, directly write up to (including) this + character. */ + err = flush_stream (stream); + if (!err) + err = es_write_nbf (stream, buffer, nlp - buffer + 1, &data_flushed); + } + + if (!err) + { + /* Write remaining data fully buffered. */ + err = es_write_fbf (stream, buffer + data_flushed, + bytes_to_write - data_flushed, &data_buffered); + } + + *bytes_written = data_flushed + data_buffered; + return err; +} + + +/* Write BYTES_TO_WRITE bytes from BUFFER into STREAM in, storing the + amount of bytes written in BYTES_WRITTEN. */ +static int +es_writen (estream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, + size_t bytes_to_write, size_t *_GPGRT__RESTRICT bytes_written) +{ + size_t data_written; + int err; + + data_written = 0; + err = 0; + + if (!stream->flags.writing) + { + /* Switching to writing mode -> discard input data and seek to + position at which reading has stopped. We can do this only + if a seek function has been registered. */ + if (stream->intern->func_seek) + { + err = es_seek (stream, 0, SEEK_CUR, NULL); + if (err) + { + if (errno == ESPIPE) + err = 0; + else + goto out; + } + stream->flags.writing = 1; + } + } + + switch (stream->intern->strategy) + { + case _IONBF: + err = es_write_nbf (stream, buffer, bytes_to_write, &data_written); + break; + + case _IOLBF: + err = es_write_lbf (stream, buffer, bytes_to_write, &data_written); + break; + + case _IOFBF: + err = es_write_fbf (stream, buffer, bytes_to_write, &data_written); + break; + } + + out: + + if (bytes_written) + *bytes_written = data_written; + + return err; +} + + +static int +peek_stream (estream_t _GPGRT__RESTRICT stream, + unsigned char **_GPGRT__RESTRICT data, + size_t *_GPGRT__RESTRICT data_len) +{ + int err; + + if (stream->flags.writing) + { + /* Switching to reading mode -> flush output. */ + err = flush_stream (stream); + if (err) + goto out; + stream->flags.writing = 0; + } + + if (stream->data_offset == stream->data_len) + { + /* Refill container. */ + err = fill_stream (stream); + if (err) + goto out; + } + + if (data) + *data = stream->buffer + stream->data_offset; + if (data_len) + *data_len = stream->data_len - stream->data_offset; + err = 0; + + out: + + return err; +} + + +/* Skip SIZE bytes of input data contained in buffer. */ +static int +skip_stream (estream_t stream, size_t size) +{ + int err; + + if (stream->data_offset + size > stream->data_len) + { + _set_errno (EINVAL); + err = -1; + } + else + { + stream->data_offset += size; + err = 0; + } + + return err; +} + + +static int +doreadline (estream_t _GPGRT__RESTRICT stream, size_t max_length, + char *_GPGRT__RESTRICT *_GPGRT__RESTRICT line, + size_t *_GPGRT__RESTRICT line_length) +{ + size_t line_size; + estream_t line_stream; + char *line_new; + void *line_stream_cookie; + char *newline; + unsigned char *data; + size_t data_len; + int err; + es_syshd_t syshd; + + line_new = NULL; + line_stream = NULL; + line_stream_cookie = NULL; + + err = func_mem_create (&line_stream_cookie, NULL, 0, 0, + BUFFER_BLOCK_SIZE, 1, + mem_realloc, mem_free, + O_RDWR, + 0); + if (err) + goto out; + + memset (&syshd, 0, sizeof syshd); + err = create_stream (&line_stream, line_stream_cookie, + &syshd, BACKEND_MEM, + estream_functions_mem, O_RDWR, 1, 0); + if (err) + goto out; + + { + size_t space_left = max_length; + + line_size = 0; + for (;;) + { + if (max_length && (space_left == 1)) + break; + + err = peek_stream (stream, &data, &data_len); + if (err || (! data_len)) + break; + + if (data_len > (space_left - 1)) + data_len = space_left - 1; + + newline = memchr (data, '\n', data_len); + if (newline) + { + data_len = (newline - (char *) data) + 1; + err = _gpgrt_write (line_stream, data, data_len, NULL); + if (! err) + { + /* Not needed: space_left -= data_len */ + line_size += data_len; + skip_stream (stream, data_len); + break; /* endless loop */ + } + } + else + { + err = _gpgrt_write (line_stream, data, data_len, NULL); + if (! err) + { + space_left -= data_len; + line_size += data_len; + skip_stream (stream, data_len); + } + } + if (err) + break; + } + } + if (err) + goto out; + + /* Complete line has been written to line_stream. */ + + if ((max_length > 1) && (! line_size)) + { + stream->intern->indicators.eof = 1; + goto out; + } + + err = es_seek (line_stream, 0, SEEK_SET, NULL); + if (err) + goto out; + + if (! *line) + { + line_new = mem_alloc (line_size + 1); + if (! line_new) + { + err = -1; + goto out; + } + } + else + line_new = *line; + + err = _gpgrt_read (line_stream, line_new, line_size, NULL); + if (err) + goto out; + + line_new[line_size] = '\0'; + + if (! *line) + *line = line_new; + if (line_length) + *line_length = line_size; + + out: + + if (line_stream) + do_close (line_stream, 0, 0); + else if (line_stream_cookie) + func_mem_destroy (line_stream_cookie); + + if (err) + { + if (! *line) + mem_free (line_new); + stream->intern->indicators.err = 1; + } + + return err; +} + + +/* Output function used by estream_format. */ +static int +print_writer (void *outfncarg, const char *buf, size_t buflen) +{ + estream_t stream = outfncarg; + size_t nwritten; + int rc; + + nwritten = 0; + rc = es_writen (stream, buf, buflen, &nwritten); + stream->intern->print_ntotal += nwritten; + return rc; +} + + +/* The core of our printf function. This is called in locked state. */ +static int +do_print_stream (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, va_list ap) +{ + int rc; + + stream->intern->print_ntotal = 0; + rc = _gpgrt_estream_format (print_writer, stream, sf, sfvalue, format, ap); + if (rc) + return -1; + return (int)stream->intern->print_ntotal; +} + + +static int +es_set_buffering (estream_t _GPGRT__RESTRICT stream, + char *_GPGRT__RESTRICT buffer, int mode, size_t size) +{ + int err; + + /* Flush or empty buffer depending on mode. */ + if (stream->flags.writing) + { + err = flush_stream (stream); + if (err) + goto out; + } + else + es_empty (stream); + + stream->intern->indicators.eof = 0; + + /* Free old buffer in case that was allocated by this function. */ + if (stream->intern->deallocate_buffer) + { + stream->intern->deallocate_buffer = 0; + mem_free (stream->buffer); + stream->buffer = NULL; + } + + if (mode == _IONBF) + stream->buffer_size = 0; + else + { + void *buffer_new; + + if (buffer) + buffer_new = buffer; + else + { + if (!size) + size = BUFSIZ; + buffer_new = mem_alloc (size); + if (! buffer_new) + { + err = -1; + goto out; + } + } + + stream->buffer = buffer_new; + stream->buffer_size = size; + if (! buffer) + stream->intern->deallocate_buffer = 1; + } + stream->intern->strategy = mode; + err = 0; + + out: + + return err; +} + + +static gpgrt_off_t +es_offset_calculate (estream_t stream) +{ + gpgrt_off_t offset; + + offset = stream->intern->offset + stream->data_offset; + if (offset < stream->unread_data_len) + /* Offset undefined. */ + offset = 0; + else + offset -= stream->unread_data_len; + + return offset; +} + + +static void +es_opaque_ctrl (estream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT opaque_new, + void **_GPGRT__RESTRICT opaque_old) +{ + if (opaque_old) + *opaque_old = stream->intern->opaque; + if (opaque_new) + stream->intern->opaque = opaque_new; +} + + +/* API. */ + +estream_t +_gpgrt_fopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode) +{ + unsigned int modeflags, cmode, xmode; + int create_called; + estream_t stream; + void *cookie; + int err; + int fd; + es_syshd_t syshd; + + stream = NULL; + cookie = NULL; + create_called = 0; + + err = parse_mode (mode, &modeflags, &xmode, &cmode); + if (err) + goto out; + + err = func_file_create (&cookie, &fd, path, modeflags, cmode); + if (err) + goto out; + + syshd.type = ES_SYSHD_FD; + syshd.u.fd = fd; + create_called = 1; + err = create_stream (&stream, cookie, &syshd, BACKEND_FD, + estream_functions_fd, modeflags, xmode, 0); + if (err) + goto out; + + if (stream && path) + fname_set_internal (stream, path, 1); + + out: + + if (err && create_called) + (*estream_functions_fd.public.func_close) (cookie); + + return stream; +} + + + +/* Create a new estream object in memory. If DATA is not NULL this + buffer will be used as the memory buffer; thus after this functions + returns with the success the the memory at DATA belongs to the new + estream. The allocated length of DATA is given by DATA_LEN and its + used length by DATA_N. Usually this is malloced buffer; if a + static buffer is provided, the caller must pass false for GROW and + provide a dummy function for FUNC_FREE. FUNC_FREE and FUNC_REALLOC + allow the caller to provide custom functions for realloc and free + to be used by the new estream object. Note that the realloc + function is also used for initial allocation. If DATA is NULL a + buffer is internally allocated; either using internal function or + those provide by the caller. It is an error to provide a realloc + function but no free function. Providing only a free function is + allowed as long as GROW is false. */ +estream_t +_gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len, + unsigned int grow, + func_realloc_t func_realloc, func_free_t func_free, + const char *_GPGRT__RESTRICT mode) +{ + int create_called = 0; + estream_t stream = NULL; + void *cookie = NULL; + unsigned int modeflags, xmode; + int err; + es_syshd_t syshd; + + err = parse_mode (mode, &modeflags, &xmode, NULL); + if (err) + goto out; + + err = func_mem_create (&cookie, data, data_n, data_len, + BUFFER_BLOCK_SIZE, grow, + func_realloc, func_free, modeflags, 0); + if (err) + goto out; + + memset (&syshd, 0, sizeof syshd); + create_called = 1; + err = create_stream (&stream, cookie, &syshd, BACKEND_MEM, + estream_functions_mem, modeflags, xmode, 0); + + out: + + if (err && create_called) + (*estream_functions_mem.public.func_close) (cookie); + + return stream; +} + + + +estream_t +_gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode) +{ + unsigned int modeflags, xmode; + estream_t stream = NULL; + void *cookie = NULL; + es_syshd_t syshd; + + /* Memory streams are always read/write. We use MODE only to get + the append flag. */ + if (parse_mode (mode, &modeflags, &xmode, NULL)) + return NULL; + modeflags |= O_RDWR; + + if (func_mem_create (&cookie, NULL, 0, 0, + BUFFER_BLOCK_SIZE, 1, + mem_realloc, mem_free, modeflags, + memlimit)) + return NULL; + + memset (&syshd, 0, sizeof syshd); + if (create_stream (&stream, cookie, &syshd, BACKEND_MEM, + estream_functions_mem, modeflags, xmode, 0)) + (*estream_functions_mem.public.func_close) (cookie); + + return stream; +} + + +/* This is the same as es_fopenmem but intializes the memory with a + copy of (DATA,DATALEN). The stream is initially set to the + beginning. If MEMLIMIT is not 0 but shorter than DATALEN it + DATALEN will be used as the value for MEMLIMIT. */ +estream_t +_gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode, + const void *data, size_t datalen) +{ + estream_t stream; + + if (memlimit && memlimit < datalen) + memlimit = datalen; + + stream = _gpgrt_fopenmem (memlimit, mode); + if (stream && data && datalen) + { + if (es_writen (stream, data, datalen, NULL)) + { + int saveerrno = errno; + _gpgrt_fclose (stream); + stream = NULL; + _set_errno (saveerrno); + } + else + { + es_seek (stream, 0L, SEEK_SET, NULL); + stream->intern->indicators.eof = 0; + stream->intern->indicators.err = 0; + } + } + return stream; +} + + + +estream_t +_gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie, + const char *_GPGRT__RESTRICT mode, + gpgrt_cookie_io_functions_t functions) +{ + unsigned int modeflags, xmode; + estream_t stream; + int err; + es_syshd_t syshd; + struct cookie_io_functions_s io_functions = { functions, NULL }; + + stream = NULL; + modeflags = 0; + + err = parse_mode (mode, &modeflags, &xmode, NULL); + if (err) + goto out; + + memset (&syshd, 0, sizeof syshd); + err = create_stream (&stream, cookie, &syshd, BACKEND_USER, io_functions, + modeflags, xmode, 0); + if (err) + goto out; + + out: + return stream; +} + + + +static estream_t +do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list) +{ + int create_called = 0; + estream_t stream = NULL; + void *cookie = NULL; + unsigned int modeflags, xmode; + int err; + es_syshd_t syshd; + + err = parse_mode (mode, &modeflags, &xmode, NULL); + if (err) + goto out; + if ((xmode & X_SYSOPEN)) + { + /* Not allowed for fdopen. */ + _set_errno (EINVAL); + err = -1; + goto out; + } + + err = func_fd_create (&cookie, filedes, modeflags, no_close); + if (err) + goto out; + + syshd.type = ES_SYSHD_FD; + syshd.u.fd = filedes; + create_called = 1; + err = create_stream (&stream, cookie, &syshd, + BACKEND_FD, estream_functions_fd, + modeflags, xmode, with_locked_list); + + if (!err && stream) + { + if ((modeflags & O_NONBLOCK)) + err = stream->intern->func_ioctl (cookie, COOKIE_IOCTL_NONBLOCK, + "", NULL); + } + + out: + if (err && create_called) + (*estream_functions_fd.public.func_close) (cookie); + + return stream; +} + +estream_t +_gpgrt_fdopen (int filedes, const char *mode) +{ + return do_fdopen (filedes, mode, 0, 0); +} + +/* A variant of es_fdopen which does not close FILEDES at the end. */ +estream_t +_gpgrt_fdopen_nc (int filedes, const char *mode) +{ + return do_fdopen (filedes, mode, 1, 0); +} + + + +static estream_t +do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list) +{ + unsigned int modeflags, cmode, xmode; + int create_called = 0; + estream_t stream = NULL; + void *cookie = NULL; + int err; + es_syshd_t syshd; + + err = parse_mode (mode, &modeflags, &xmode, &cmode); + if (err) + goto out; + if ((xmode & X_SYSOPEN)) + { + /* Not allowed for fpopen. */ + _set_errno (EINVAL); + err = -1; + goto out; + } + + if (fp) + fflush (fp); + err = func_fp_create (&cookie, fp, modeflags, no_close); + if (err) + goto out; + + syshd.type = ES_SYSHD_FD; + syshd.u.fd = fp? fileno (fp): -1; + create_called = 1; + err = create_stream (&stream, cookie, &syshd, + BACKEND_FP, estream_functions_fp, + modeflags, xmode, with_locked_list); + + out: + if (err && create_called) + (*estream_functions_fp.public.func_close) (cookie); + + return stream; +} + + +/* Create an estream from the stdio stream FP. This mechanism is + useful in case the stdio streams have special properties and may + not be mixed with fd based functions. This is for example the case + under Windows where the 3 standard streams are associated with the + console whereas a duped and fd-opened stream of one of this stream + won't be associated with the console. As this messes things up it + is easier to keep on using the standard I/O stream as a backend for + estream. */ +estream_t +_gpgrt_fpopen (FILE *fp, const char *mode) +{ + return do_fpopen (fp, mode, 0, 0); +} + + +/* Same as es_fpopen but does not close FP at the end. */ +estream_t +_gpgrt_fpopen_nc (FILE *fp, const char *mode) +{ + return do_fpopen (fp, mode, 1, 0); +} + + + +#ifdef HAVE_W32_SYSTEM +estream_t +do_w32open (HANDLE hd, const char *mode, + int no_close, int with_locked_list) +{ + unsigned int modeflags, cmode, xmode; + int create_called = 0; + estream_t stream = NULL; + void *cookie = NULL; + int err; + es_syshd_t syshd; + + /* For obvious reasons we ignore sysmode here. */ + err = parse_mode (mode, &modeflags, &xmode, &cmode); + if (err) + goto leave; + + /* If we are pollable we create the function cookie with syscall + * clamp disabled. This is because functions are called from + * separatre reader and writer threads in w32-stream. */ + err = func_w32_create (&cookie, hd, modeflags, + no_close, !!(xmode & X_POLLABLE)); + if (err) + goto leave; + + syshd.type = ES_SYSHD_HANDLE; + syshd.u.handle = hd; + create_called = 1; + err = create_stream (&stream, cookie, &syshd, + BACKEND_W32, estream_functions_w32, + modeflags, xmode, with_locked_list); + + leave: + if (err && create_called) + (*estream_functions_w32.public.func_close) (cookie); + + return stream; +} +#endif /*HAVE_W32_SYSTEM*/ + +static estream_t +do_sysopen (es_syshd_t *syshd, const char *mode, int no_close) +{ + estream_t stream; + + switch (syshd->type) + { + case ES_SYSHD_FD: + case ES_SYSHD_SOCK: + stream = do_fdopen (syshd->u.fd, mode, no_close, 0); + break; + +#ifdef HAVE_W32_SYSTEM + case ES_SYSHD_HANDLE: + stream = do_w32open (syshd->u.handle, mode, no_close, 0); + break; +#endif + + /* FIXME: Support RVIDs under Wince? */ + + default: + _set_errno (EINVAL); + stream = NULL; + } + return stream; +} + +/* On POSIX systems this function is an alias for es_fdopen. Under + Windows it uses the bare W32 API and thus a HANDLE instead of a + file descriptor. */ +estream_t +_gpgrt_sysopen (es_syshd_t *syshd, const char *mode) +{ + return do_sysopen (syshd, mode, 0); +} + +/* Same as es_sysopen but the handle/fd will not be closed by + es_fclose. */ +estream_t +_gpgrt_sysopen_nc (es_syshd_t *syshd, const char *mode) +{ + return do_sysopen (syshd, mode, 1); +} + + + +/* Set custom standard descriptors to be used for stdin, stdout and + stderr. This function needs to be called before any of the + standard streams are accessed. This internal version uses a double + dash inside its name. */ +void +_gpgrt__set_std_fd (int no, int fd) +{ + /* fprintf (stderr, "es_set_std_fd(%d, %d)\n", no, fd); */ + lock_list (); + if (no >= 0 && no < 3 && !custom_std_fds_valid[no]) + { + custom_std_fds[no] = fd; + custom_std_fds_valid[no] = 1; + } + unlock_list (); +} + + +/* Return the stream used for stdin, stdout or stderr. + This internal version uses a double dash inside its name. */ +estream_t +_gpgrt__get_std_stream (int fd) +{ + estream_list_t list_obj; + estream_t stream = NULL; + + fd %= 3; /* We only allow 0, 1 or 2 but we don't want to return an error. */ + + lock_list (); + + for (list_obj = estream_list; list_obj; list_obj = list_obj->next) + if (list_obj->stream && list_obj->stream->intern->is_stdstream + && list_obj->stream->intern->stdstream_fd == fd) + { + stream = list_obj->stream; + break; + } + if (!stream) + { + /* Standard stream not yet created. We first try to create them + from registered file descriptors. */ + if (!fd && custom_std_fds_valid[0]) + stream = do_fdopen (custom_std_fds[0], "r", 1, 1); + else if (fd == 1 && custom_std_fds_valid[1]) + stream = do_fdopen (custom_std_fds[1], "a", 1, 1); + else if (custom_std_fds_valid[2]) + stream = do_fdopen (custom_std_fds[2], "a", 1, 1); + + if (!stream) + { + /* Second try is to use the standard C streams. */ + if (!fd) + stream = do_fpopen (stdin, "r", 1, 1); + else if (fd == 1) + stream = do_fpopen (stdout, "a", 1, 1); + else + stream = do_fpopen (stderr, "a", 1, 1); + } + + if (!stream) + { + /* Last try: Create a bit bucket. */ + stream = do_fpopen (NULL, fd? "a":"r", 0, 1); + if (!stream) + { + fprintf (stderr, "fatal: error creating a dummy estream" + " for %d: %s\n", fd, strerror (errno)); + _gpgrt_abort(); + } + } + + stream->intern->is_stdstream = 1; + stream->intern->stdstream_fd = fd; + if (fd == 2) + es_set_buffering (stream, NULL, _IOLBF, 0); + fname_set_internal (stream, + fd == 0? "[stdin]" : + fd == 1? "[stdout]" : "[stderr]", 0); + } + + unlock_list (); + return stream; +} + +/* Note: A "samethread" keyword given in "mode" is ignored and the + * value used by STREAM is used instead. Note that this function is + * the reasons why some of the init and deinit code is split up into + * several functions. */ +estream_t +_gpgrt_freopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode, + estream_t _GPGRT__RESTRICT stream) +{ + int err; + + if (path) + { + unsigned int modeflags, cmode, xmode, dummy; + int create_called; + void *cookie; + int fd; + es_syshd_t syshd; + + cookie = NULL; + create_called = 0; + + xmode = stream->intern->samethread ? X_SAMETHREAD : 0; + + lock_stream (stream); + + deinit_stream_obj (stream); + + err = parse_mode (mode, &modeflags, &dummy, &cmode); + if (err) + goto leave; + (void)dummy; + + err = func_file_create (&cookie, &fd, path, modeflags, cmode); + if (err) + goto leave; + + syshd.type = ES_SYSHD_FD; + syshd.u.fd = fd; + create_called = 1; + init_stream_obj (stream, cookie, &syshd, BACKEND_FD, + estream_functions_fd, modeflags, xmode); + + leave: + + if (err) + { + if (create_called) + func_fd_destroy (cookie); + + do_close (stream, 0, 0); + stream = NULL; + } + else + { + if (path) + fname_set_internal (stream, path, 1); + unlock_stream (stream); + } + } + else + { + /* FIXME? We don't support re-opening at the moment. */ + _set_errno (EINVAL); + deinit_stream_obj (stream); + do_close (stream, 0, 0); + stream = NULL; + } + + return stream; +} + + +int +_gpgrt_fclose (estream_t stream) +{ + int err; + + err = do_close (stream, 0, 0); + + return err; +} + + +/* gpgrt_fcancel does the same as gpgrt_fclose but tries to avoid + * flushing out any data still held in internal buffers. It may or + * may not remove a new file created for that stream by the open + * function. */ +int +_gpgrt_fcancel (estream_t stream) +{ + int err; + + err = do_close (stream, 1, 0); + + return err; +} + + +/* This is a special version of es_fclose which can be used with + es_fopenmem to return the memory buffer. This is feature is useful + to write to a memory buffer using estream. Note that the function + does not close the stream if the stream does not support snatching + the buffer. On error NULL is stored at R_BUFFER. Note that if no + write operation has happened, NULL may also be stored at BUFFER on + success. The caller needs to release the returned memory using + gpgrt_free. */ +int +_gpgrt_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen) +{ + int err; + + /* Note: There is no need to lock the stream in a close call. The + object will be destroyed after the close and thus any other + contender for the lock would work on a closed stream. */ + + if (r_buffer) + { + cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl; + size_t buflen; + + *r_buffer = NULL; + + if (!func_ioctl) + { + _set_errno (EOPNOTSUPP); + err = -1; + goto leave; + } + + if (stream->flags.writing) + { + err = flush_stream (stream); + if (err) + goto leave; + stream->flags.writing = 0; + } + + err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER, + r_buffer, &buflen); + if (err) + goto leave; + if (r_buflen) + *r_buflen = buflen; + } + + err = do_close (stream, 0, 0); + + leave: + if (err && r_buffer) + { + mem_free (*r_buffer); + *r_buffer = NULL; + } + return err; +} + + +/* Register or unregister a close notification function for STREAM. + FNC is the function to call and FNC_VALUE the value passed as + second argument. To register the notification the value for MODE + must be 1. If mode is 0 the function tries to remove or disable an + already registered notification; for this to work the value of FNC + and FNC_VALUE must be the same as with the registration and + FNC_VALUE must be a unique value. No error will be returned if + MODE is 0. + + FIXME: I think the next comment is not anymore correct: + Unregister should only be used in the error case because it may not + be able to remove memory internally allocated for the onclose + handler. + + FIXME: Unregister is not thread safe. + + The notification will be called right before the stream is + closed. If gpgrt_fcancel is used, the cancellation of internal + buffers is done before the notifications. The notification handler + may not call any estream function for STREAM, neither direct nor + indirectly. */ +int +_gpgrt_onclose (estream_t stream, int mode, + void (*fnc) (estream_t, void*), void *fnc_value) +{ + int err; + + lock_stream (stream); + err = do_onclose (stream, mode, fnc, fnc_value); + unlock_stream (stream); + + return err; +} + + +int +_gpgrt_fileno_unlocked (estream_t stream) +{ + es_syshd_t syshd; + + if (_gpgrt_syshd_unlocked (stream, &syshd)) + return -1; + switch (syshd.type) + { + case ES_SYSHD_FD: return syshd.u.fd; + case ES_SYSHD_SOCK: return syshd.u.sock; + default: + _set_errno (EINVAL); + return -1; + } +} + + +/* Return the handle of a stream which has been opened by es_sysopen. + The caller needs to pass a structure which will be filled with the + sys handle. Return 0 on success or true on error and sets errno. + This is the unlocked version. */ +int +_gpgrt_syshd_unlocked (estream_t stream, es_syshd_t *syshd) +{ + if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE) + { + if (syshd) + syshd->type = ES_SYSHD_NONE; + _set_errno (EINVAL); + return -1; + } + + *syshd = stream->intern->syshd; + return 0; +} + + +void +_gpgrt_flockfile (estream_t stream) +{ + lock_stream (stream); +} + + +int +_gpgrt_ftrylockfile (estream_t stream) +{ + return trylock_stream (stream); +} + + +void +_gpgrt_funlockfile (estream_t stream) +{ + unlock_stream (stream); +} + + +int +_gpgrt_fileno (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_fileno_unlocked (stream); + unlock_stream (stream); + + return ret; +} + + +/* Return the handle of a stream which has been opened by es_sysopen. + The caller needs to pass a structure which will be filled with the + sys handle. Return 0 on success or true on error and sets errno. + This is the unlocked version. */ +int +_gpgrt_syshd (estream_t stream, es_syshd_t *syshd) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_syshd_unlocked (stream, syshd); + unlock_stream (stream); + + return ret; +} + + +int +_gpgrt__pending_unlocked (estream_t stream) +{ + return check_pending (stream); +} + + +/* Return true if there is at least one byte pending for read on + STREAM. This does only work if the backend supports checking for + pending bytes and is thus mostly useful with cookie based backends. + + Note that if this function is used with cookie based functions, the + read cookie may be called with 0 for the SIZE argument. If bytes + are pending the function is expected to return -1 in this case and + thus deviates from the standard behavior of read(2). */ +int +_gpgrt__pending (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt__pending_unlocked (stream); + unlock_stream (stream); + + return ret; +} + + +int +_gpgrt_feof_unlocked (estream_t stream) +{ + return stream->intern->indicators.eof; +} + + +int +_gpgrt_feof (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_feof_unlocked (stream); + unlock_stream (stream); + + return ret; +} + + +int +_gpgrt_ferror_unlocked (estream_t stream) +{ + return stream->intern->indicators.err; +} + + +int +_gpgrt_ferror (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_ferror_unlocked (stream); + unlock_stream (stream); + + return ret; +} + + +void +_gpgrt_clearerr_unlocked (estream_t stream) +{ + stream->intern->indicators.eof = 0; + stream->intern->indicators.err = 0; + /* We do not reset the HUP indicator because there is no way to + get out of this state. */ +} + + +void +_gpgrt_clearerr (estream_t stream) +{ + lock_stream (stream); + _gpgrt_clearerr_unlocked (stream); + unlock_stream (stream); +} + + +static int +do_fflush (estream_t stream) +{ + int err; + + if (stream->flags.writing) + err = flush_stream (stream); + else + { + es_empty (stream); + err = 0; + } + + return err; +} + + +int +_gpgrt_fflush (estream_t stream) +{ + int err; + + if (stream) + { + lock_stream (stream); + err = do_fflush (stream); + unlock_stream (stream); + } + else + { + estream_list_t item; + + err = 0; + lock_list (); + for (item = estream_list; item; item = item->next) + if (item->stream) + { + lock_stream (item->stream); + err |= do_fflush (item->stream); + unlock_stream (item->stream); + } + unlock_list (); + } + return err ? EOF : 0; +} + + +int +_gpgrt_fseek (estream_t stream, long int offset, int whence) +{ + int err; + + lock_stream (stream); + err = es_seek (stream, offset, whence, NULL); + unlock_stream (stream); + + return err; +} + + +int +_gpgrt_fseeko (estream_t stream, gpgrt_off_t offset, int whence) +{ + int err; + + lock_stream (stream); + err = es_seek (stream, offset, whence, NULL); + unlock_stream (stream); + + return err; +} + + +long int +_gpgrt_ftell (estream_t stream) +{ + long int ret; + + lock_stream (stream); + ret = es_offset_calculate (stream); + unlock_stream (stream); + + return ret; +} + + +gpgrt_off_t +_gpgrt_ftello (estream_t stream) +{ + gpgrt_off_t ret = -1; + + lock_stream (stream); + ret = es_offset_calculate (stream); + unlock_stream (stream); + + return ret; +} + + +void +_gpgrt_rewind (estream_t stream) +{ + lock_stream (stream); + es_seek (stream, 0L, SEEK_SET, NULL); + /* Note that es_seek already cleared the EOF flag. */ + stream->intern->indicators.err = 0; + unlock_stream (stream); +} + + +int +_gpgrt_ftruncate (estream_t stream, gpgrt_off_t length) +{ + cookie_ioctl_function_t func_ioctl; + int ret; + + lock_stream (stream); + func_ioctl = stream->intern->func_ioctl; + if (!func_ioctl) + { + _set_errno (EOPNOTSUPP); + ret = -1; + } + else + { + ret = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_TRUNCATE, + &length, NULL); + } + unlock_stream (stream); + return ret; +} + + +int +_gpgrt__getc_underflow (estream_t stream) +{ + int err; + unsigned char c; + size_t bytes_read; + + err = es_readn (stream, &c, 1, &bytes_read); + + return (err || (! bytes_read)) ? EOF : c; +} + + +int +_gpgrt__putc_overflow (int c, estream_t stream) +{ + unsigned char d = c; + int err; + + err = es_writen (stream, &d, 1, NULL); + + return err ? EOF : c; +} + + +int +_gpgrt_fgetc (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_getc_unlocked (stream); + unlock_stream (stream); + + return ret; +} + + +int +_gpgrt_fputc (int c, estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = _gpgrt_putc_unlocked (c, stream); + unlock_stream (stream); + + return ret; +} + + +int +_gpgrt_ungetc (int c, estream_t stream) +{ + unsigned char data = (unsigned char) c; + size_t data_unread; + + lock_stream (stream); + es_unreadn (stream, &data, 1, &data_unread); + unlock_stream (stream); + + return data_unread ? c : EOF; +} + + +int +_gpgrt_read (estream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT buffer, size_t bytes_to_read, + size_t *_GPGRT__RESTRICT bytes_read) +{ + int err; + + if (bytes_to_read) + { + lock_stream (stream); + err = es_readn (stream, buffer, bytes_to_read, bytes_read); + unlock_stream (stream); + } + else + err = 0; + + return err; +} + + +int +_gpgrt_write (estream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write, + size_t *_GPGRT__RESTRICT bytes_written) +{ + int err; + + if (bytes_to_write) + { + lock_stream (stream); + err = es_writen (stream, buffer, bytes_to_write, bytes_written); + unlock_stream (stream); + } + else + err = 0; + + return err; +} + + +size_t +_gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, + estream_t _GPGRT__RESTRICT stream) +{ + size_t ret, bytes; + + if (size && nitems) + { + lock_stream (stream); + es_readn (stream, ptr, size * nitems, &bytes); + unlock_stream (stream); + + ret = bytes / size; + } + else + ret = 0; + + return ret; +} + + +size_t +_gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, + estream_t _GPGRT__RESTRICT stream) +{ + size_t ret, bytes; + + if (size && nitems) + { + lock_stream (stream); + es_writen (stream, ptr, size * nitems, &bytes); + unlock_stream (stream); + + ret = bytes / size; + } + else + ret = 0; + + return ret; +} + + +char * +_gpgrt_fgets (char *_GPGRT__RESTRICT buffer, int length, + estream_t _GPGRT__RESTRICT stream) +{ + unsigned char *s = (unsigned char*)buffer; + int c; + + if (!length) + return NULL; + + c = EOF; + lock_stream (stream); + while (length > 1 && (c = _gpgrt_getc_unlocked (stream)) != EOF && c != '\n') + { + *s++ = c; + length--; + } + unlock_stream (stream); + + if (c == EOF && s == (unsigned char*)buffer) + return NULL; /* Nothing read. */ + + if (c != EOF && length > 1) + *s++ = c; + + *s = 0; + return buffer; +} + + +int +_gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s, + estream_t _GPGRT__RESTRICT stream) +{ + size_t length; + int err; + + length = strlen (s); + err = es_writen (stream, s, length, NULL); + return err ? EOF : 0; +} + +int +_gpgrt_fputs (const char *_GPGRT__RESTRICT s, estream_t _GPGRT__RESTRICT stream) +{ + size_t length; + int err; + + length = strlen (s); + lock_stream (stream); + err = es_writen (stream, s, length, NULL); + unlock_stream (stream); + + return err ? EOF : 0; +} + + +gpgrt_ssize_t +_gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr, + size_t *_GPGRT__RESTRICT n, estream_t _GPGRT__RESTRICT stream) +{ + char *line = NULL; + size_t line_n = 0; + int err; + + lock_stream (stream); + err = doreadline (stream, 0, &line, &line_n); + unlock_stream (stream); + if (err) + goto out; + + if (*n) + { + /* Caller wants us to use his buffer. */ + + if (*n < (line_n + 1)) + { + /* Provided buffer is too small -> resize. */ + + void *p; + + p = mem_realloc (*lineptr, line_n + 1); + if (! p) + err = -1; + else + { + if (*lineptr != p) + *lineptr = p; + } + } + + if (! err) + { + memcpy (*lineptr, line, line_n + 1); + if (*n != line_n) + *n = line_n; + } + mem_free (line); + } + else + { + /* Caller wants new buffers. */ + *lineptr = line; + *n = line_n; + } + + out: + + return err ? err : (gpgrt_ssize_t)line_n; +} + + + +/* Same as fgets() but if the provided buffer is too short a larger + one will be allocated. This is similar to getline. A line is + considered a byte stream ending in a LF. + + If MAX_LENGTH is not NULL, it shall point to a value with the + maximum allowed allocation. + + Returns the length of the line. EOF is indicated by a line of + length zero. A truncated line is indicated my setting the value at + MAX_LENGTH to 0. If the returned value is less then 0 not enough + memory was available or another error occurred; ERRNO is then set + accordingly. + + If a line has been truncated, the file pointer is moved forward to + the end of the line so that the next read starts with the next + line. Note that MAX_LENGTH must be re-initialized in this case. + + The caller initially needs to provide the address of a variable, + initialized to NULL, at ADDR_OF_BUFFER and don't change this value + anymore with the following invocations. LENGTH_OF_BUFFER should be + the address of a variable, initialized to 0, which is also + maintained by this function. Thus, both paramaters should be + considered the state of this function. + + Note: The returned buffer is allocated with enough extra space to + allow the caller to append a CR,LF,Nul. The buffer should be + released using gpgrt_free. + */ +gpgrt_ssize_t +_gpgrt_read_line (estream_t stream, + char **addr_of_buffer, size_t *length_of_buffer, + size_t *max_length) +{ + int c; + char *buffer = *addr_of_buffer; + size_t length = *length_of_buffer; + size_t nbytes = 0; + size_t maxlen = max_length? *max_length : 0; + char *p; + + if (!buffer) + { + /* No buffer given - allocate a new one. */ + length = 256; + buffer = mem_alloc (length); + *addr_of_buffer = buffer; + if (!buffer) + { + *length_of_buffer = 0; + if (max_length) + *max_length = 0; + return -1; + } + *length_of_buffer = length; + } + + if (length < 4) + { + /* This should never happen. If it does, the function has been + called with wrong arguments. */ + _set_errno (EINVAL); + return -1; + } + length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */ + + lock_stream (stream); + p = buffer; + while ((c = _gpgrt_getc_unlocked (stream)) != EOF) + { + if (nbytes == length) + { + /* Enlarge the buffer. */ + if (maxlen && length > maxlen) + { + /* We are beyond our limit: Skip the rest of the line. */ + while (c != '\n' && (c=_gpgrt_getc_unlocked (stream)) != EOF) + ; + *p++ = '\n'; /* Always append a LF (we reserved some space). */ + nbytes++; + if (max_length) + *max_length = 0; /* Indicate truncation. */ + break; /* the while loop. */ + } + length += 3; /* Adjust for the reserved bytes. */ + length += length < 1024? 256 : 1024; + *addr_of_buffer = mem_realloc (buffer, length); + if (!*addr_of_buffer) + { + int save_errno = errno; + mem_free (buffer); + *length_of_buffer = 0; + if (max_length) + *max_length = 0; + unlock_stream (stream); + _set_errno (save_errno); + return -1; + } + buffer = *addr_of_buffer; + *length_of_buffer = length; + length -= 3; + p = buffer + nbytes; + } + *p++ = c; + nbytes++; + if (c == '\n') + break; + } + *p = 0; /* Make sure the line is a string. */ + unlock_stream (stream); + + return nbytes; +} + +/* Wrapper around free() to match the memory allocation system used by + estream. Should be used for all buffers returned to the caller by + libestream. If a custom allocation handler has been set with + gpgrt_set_alloc_func that register function may be used + instead. This function has been moved to init.c. */ +/* void */ +/* _gpgrt_free (void *a) */ +/* { */ +/* mem_free (a); */ +/* } */ + + +int +_gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, + va_list ap) +{ + return do_print_stream (stream, sf, sfvalue, format, ap); +} + + +int +_gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, + va_list ap) +{ + int ret; + + lock_stream (stream); + ret = do_print_stream (stream, sf, sfvalue, format, ap); + unlock_stream (stream); + + return ret; +} + + +int +_gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) +{ + int ret; + + va_list ap; + va_start (ap, format); + ret = do_print_stream (stream, NULL, NULL, format, ap); + va_end (ap); + + return ret; +} + + +int +_gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) +{ + int ret; + + va_list ap; + va_start (ap, format); + lock_stream (stream); + ret = do_print_stream (stream, NULL, NULL, format, ap); + unlock_stream (stream); + va_end (ap); + + return ret; +} + + +static int +tmpfd (void) +{ +#ifdef HAVE_W32_SYSTEM + int attempts, n; +#ifdef HAVE_W32CE_SYSTEM + wchar_t buffer[MAX_PATH+9+12+1]; +# define mystrlen(a) wcslen (a) + wchar_t *name, *p; +#else + char buffer[MAX_PATH+9+12+1]; +# define mystrlen(a) strlen (a) + char *name, *p; +#endif + HANDLE file; + int pid = GetCurrentProcessId (); + unsigned int value; + int i; + + n = GetTempPath (MAX_PATH+1, buffer); + if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH) + { + _set_errno (ENOENT); + return -1; + } + p = buffer + mystrlen (buffer); +#ifdef HAVE_W32CE_SYSTEM + wcscpy (p, L"_estream"); +#else + strcpy (p, "_estream"); +#endif + p += 8; + /* We try to create the directory but don't care about an error as + it may already exist and the CreateFile would throw an error + anyway. */ + CreateDirectory (buffer, NULL); + *p++ = '\\'; + name = p; + for (attempts=0; attempts < 10; attempts++) + { + p = name; + value = (GetTickCount () ^ ((pid<<16) & 0xffff0000)); + for (i=0; i < 8; i++) + { + *p++ = tohex (((value >> 28) & 0x0f)); + value <<= 4; + } +#ifdef HAVE_W32CE_SYSTEM + wcscpy (p, L".tmp"); +#else + strcpy (p, ".tmp"); +#endif + file = CreateFile (buffer, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (file != INVALID_HANDLE_VALUE) + { +#ifdef HAVE_W32CE_SYSTEM + int fd = (int)file; +#else + int fd = _open_osfhandle ((intptr_t)file, 0); + if (fd == -1) + { + CloseHandle (file); + return -1; + } +#endif + return fd; + } + Sleep (1); /* One ms as this is the granularity of GetTickCount. */ + } + _set_errno (ENOENT); + return -1; +#else /*!HAVE_W32_SYSTEM*/ + FILE *fp; + int fp_fd; + int fd; + + fp = NULL; + fd = -1; + + fp = tmpfile (); + if (! fp) + goto out; + + fp_fd = fileno (fp); + fd = dup (fp_fd); + + out: + + if (fp) + fclose (fp); + + return fd; +#endif /*!HAVE_W32_SYSTEM*/ +} + +estream_t +_gpgrt_tmpfile (void) +{ + unsigned int modeflags; + int create_called = 0; + estream_t stream = NULL; + void *cookie = NULL; + int err; + int fd; + es_syshd_t syshd; + + modeflags = O_RDWR | O_TRUNC | O_CREAT; + + fd = tmpfd (); + if (fd == -1) + { + err = -1; + goto out; + } + + err = func_fd_create (&cookie, fd, modeflags, 0); + if (err) + goto out; + + syshd.type = ES_SYSHD_FD; + syshd.u.fd = fd; + create_called = 1; + err = create_stream (&stream, cookie, &syshd, + BACKEND_FD, estream_functions_fd, + modeflags, 0, 0); + + out: + if (err) + { + if (create_called) + func_fd_destroy (cookie); + else if (fd != -1) + close (fd); + stream = NULL; + } + + return stream; +} + + +int +_gpgrt_setvbuf (estream_t _GPGRT__RESTRICT stream, + char *_GPGRT__RESTRICT buf, int type, size_t size) +{ + int err; + + if ((type == _IOFBF || type == _IOLBF || type == _IONBF) + && (!buf || size || type == _IONBF)) + { + lock_stream (stream); + err = es_set_buffering (stream, buf, type, size); + unlock_stream (stream); + } + else + { + _set_errno (EINVAL); + err = -1; + } + + return err; +} + + +/* Put a stream into binary mode. This is only needed for the + standard streams if they are to be used in a binary way. On Unix + systems it is never needed but MSDOS based systems require such a + call. It needs to be called before any I/O is done on STREAM. */ +void +_gpgrt_set_binary (estream_t stream) +{ + lock_stream (stream); + if (!(stream->intern->modeflags & O_BINARY)) + { + stream->intern->modeflags |= O_BINARY; +#ifdef HAVE_DOSISH_SYSTEM + if (stream->intern->func_read == func_fd_read) + { + estream_cookie_fd_t fd_cookie = stream->intern->cookie; + + if (!IS_INVALID_FD (fd_cookie->fd)) + setmode (fd_cookie->fd, O_BINARY); + } + else if (stream->intern->func_read == func_fp_read) + { + estream_cookie_fp_t fp_cookie = stream->intern->cookie; + + if (fp_cookie->fp) + setmode (fileno (fp_cookie->fp), O_BINARY); + } +#endif + } + unlock_stream (stream); +} + + +/* Set non-blocking mode for STREAM. Use true for ONOFF to enable and + false to disable non-blocking mode. Returns 0 on success or -1 on + error and sets ERRNO. Note that not all backends support + non-blocking mode. + + In non-blocking mode a system call will not block but return an + error and set errno to EAGAIN. The estream API always uses EAGAIN + and not EWOULDBLOCK. If a buffered function like es_fgetc() or + es_fgets() returns an error and both, feof() and ferror() return + false the caller may assume that the error condition was EAGAIN. + + Switching back from non-blocking to blocking may raise problems + with buffering, thus care should be taken. Although read+write + sockets are supported in theory, switching from write to read may + result into problems because estream may first flush the write + buffers and there is no way to handle that non-blocking (EAGAIN) + case. Explicit flushing should thus be done before before + switching to read. */ +int +_gpgrt_set_nonblock (estream_t stream, int onoff) +{ + cookie_ioctl_function_t func_ioctl; + int ret; + + lock_stream (stream); + func_ioctl = stream->intern->func_ioctl; + if (!func_ioctl) + { + _set_errno (EOPNOTSUPP); + ret = -1; + } + else + { + unsigned int save_flags = stream->intern->modeflags; + + if (onoff) + stream->intern->modeflags |= O_NONBLOCK; + else + stream->intern->modeflags &= ~O_NONBLOCK; + + ret = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_NONBLOCK, + onoff?"":NULL, NULL); + if (ret) + stream->intern->modeflags = save_flags; + } + unlock_stream (stream); + return ret; +} + + +/* Return true if STREAM is in non-blocking mode. */ +int +_gpgrt_get_nonblock (estream_t stream) +{ + int ret; + + lock_stream (stream); + ret = !!(stream->intern->modeflags & O_NONBLOCK); + unlock_stream (stream); + return ret; +} + + +/* A version of poll(2) working on estream handles. Note that not all + estream types work with this function. In contrast to the standard + poll function the gpgrt_poll_t object uses a set of bit flags + instead of the EVENTS and REVENTS members. An item with the IGNORE + flag set is entirely ignored. The TIMEOUT values is given in + milliseconds, a value of -1 waits indefinitely, and a value of 0 + returns immediately. + + A positive return value gives the number of fds with new + information. A return value of 0 indicates a timeout and -1 + indicates an error in which case ERRNO is set. */ +int +_gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout) +{ + gpgrt_poll_t *item; + int count = 0; + int idx; +#ifndef HAVE_W32_SYSTEM +# ifdef HAVE_POLL_H + struct pollfd *poll_fds = NULL; + nfds_t poll_nfds; +# else + fd_set readfds, writefds, exceptfds; + int any_readfd, any_writefd, any_exceptfd; + int max_fd; +#endif + int fd, ret, any; +#endif /*HAVE_W32_SYSTEM*/ + + trace (("enter: nfds=%u timeout=%d", nfds, timeout)); + + if (!fds) + { + _set_errno (EINVAL); + count = -1; + goto leave; + } + + /* Clear all response fields (even for ignored items). */ + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + item->got_read = 0; + item->got_write = 0; + item->got_oob = 0; + item->got_rdhup = 0; + item->got_err = 0; + item->got_hup = 0; + item->got_nval = 0; + } + + /* Check for pending reads. */ + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + if (item->ignore) + continue; + if (!item->want_read) + continue; + if (_gpgrt__pending (item->stream)) + { + item->got_read = 1; + count++; + } + } + + /* Check for space in the write buffers. */ + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + if (item->ignore) + continue; + if (!item->want_write) + continue; + /* FIXME */ + } + + if (count) + goto leave; + + /* Now do the real select. */ +#ifdef HAVE_W32_SYSTEM + + _gpgrt_pre_syscall (); + count = _gpgrt_w32_poll (fds, nfds, timeout); + _gpgrt_post_syscall (); + +#else /*!HAVE_W32_SYSTEM*/ +# ifdef HAVE_POLL_H + poll_fds = xtrymalloc (sizeof (*poll_fds)*nfds); + if (!poll_fds) + { + count = -1; + goto leave; + } + poll_nfds = 0; + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + if (item->ignore) + continue; + fd = _gpgrt_fileno (item->stream); + if (fd == -1) + continue; /* Stream does not support polling. */ + + if (item->want_read || item->want_write || item->want_oob) + { + poll_fds[poll_nfds].fd = fd; + poll_fds[poll_nfds].events = ((item->want_read ? POLLIN : 0) + |(item->want_write ? POLLOUT : 0) + |(item->want_oob ? POLLPRI : 0)); + poll_fds[poll_nfds].revents = 0; + poll_nfds++; + } + } + + _gpgrt_pre_syscall (); + do + ret = poll (poll_fds, poll_nfds, timeout); + while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + _gpgrt_post_syscall (); +# else /* !HAVE_POLL_H */ + any_readfd = any_writefd = any_exceptfd = 0; + max_fd = 0; + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + if (item->ignore) + continue; + fd = _gpgrt_fileno (item->stream); + if (fd == -1) + continue; /* Stream does not support polling. */ + + if (item->want_read) + { + if (!any_readfd) + { + FD_ZERO (&readfds); + any_readfd = 1; + } + FD_SET (fd, &readfds); + if (fd > max_fd) + max_fd = fd; + } + if (item->want_write) + { + if (!any_writefd) + { + FD_ZERO (&writefds); + any_writefd = 1; + } + FD_SET (fd, &writefds); + if (fd > max_fd) + max_fd = fd; + } + if (item->want_oob) + { + if (!any_exceptfd) + { + FD_ZERO (&exceptfds); + any_exceptfd = 1; + } + FD_SET (fd, &exceptfds); + if (fd > max_fd) + max_fd = fd; + } + } + + _gpgrt_pre_syscall (); + do + { + struct timeval timeout_val; + + timeout_val.tv_sec = timeout / 1000; + timeout_val.tv_usec = (timeout % 1000) * 1000; + ret = select (max_fd+1, + any_readfd? &readfds : NULL, + any_writefd? &writefds : NULL, + any_exceptfd? &exceptfds : NULL, + timeout == -1 ? NULL : &timeout_val); + } + while (ret == -1 && errno == EINTR); + _gpgrt_post_syscall (); +# endif + + if (ret == -1) + { +# ifdef HAVE_POLL_H + trace_errno (1, ("poll failed: ")); +# else + trace_errno (1, ("select failed: ")); +# endif + count = -1; + goto leave; + } + if (!ret) + { + /* Timeout. Note that in this case we can't return got_err for + * an invalid stream. */ + count = 0; + goto leave; + } + +# ifdef HAVE_POLL_H + poll_nfds = 0; + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + if (item->ignore) + continue; + fd = _gpgrt_fileno (item->stream); + if (fd == -1) + { + item->got_err = 1; /* Stream does not support polling. */ + count++; + continue; + } + + any = 0; + if (item->stream->intern->indicators.hup) + { + item->got_hup = 1; + any = 1; + } + if (item->want_read && (poll_fds[poll_nfds].revents & (POLLIN|POLLHUP))) + { + item->got_read = 1; + any = 1; + } + if (item->want_write && (poll_fds[poll_nfds].revents & POLLOUT)) + { + item->got_write = 1; + any = 1; + } + if (item->want_oob && (poll_fds[poll_nfds].revents & ~(POLLIN|POLLOUT))) + { + item->got_oob = 1; + any = 1; + } + + if (item->want_read || item->want_write || item->want_oob) + poll_nfds++; + if (any) + count++; + } +# else + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + if (item->ignore) + continue; + fd = _gpgrt_fileno (item->stream); + if (fd == -1) + { + item->got_err = 1; /* Stream does not support polling. */ + count++; + continue; + } + + any = 0; + if (item->stream->intern->indicators.hup) + { + item->got_hup = 1; + any = 1; + } + if (item->want_read && FD_ISSET (fd, &readfds)) + { + item->got_read = 1; + any = 1; + } + if (item->want_write && FD_ISSET (fd, &writefds)) + { + item->got_write = 1; + any = 1; + } + if (item->want_oob && FD_ISSET (fd, &exceptfds)) + { + item->got_oob = 1; + any = 1; + } + + if (any) + count++; + } +# endif +#endif /*!HAVE_W32_SYSTEM*/ + + leave: +#ifndef HAVE_W32_SYSTEM +# ifdef HAVE_POLL_H + xfree (poll_fds); +# endif +#endif +#ifdef ENABLE_TRACING + trace (("leave: count=%d", count)); + if (count > 0) + { + for (item = fds, idx = 0; idx < nfds; item++, idx++) + { + trace ((" %3d %c%c%c%c%c %c%c%c%c%c%c%c", + idx, + fds[idx].want_read? 'r':'-', + fds[idx].want_write? 'w':'-', + fds[idx].want_oob? 'o':'-', + fds[idx].want_rdhup? 'h':'-', + fds[idx].ignore? 'i':'-', + fds[idx].got_read? 'r':'-', + fds[idx].got_write? 'w':'-', + fds[idx].got_oob? 'o':'-', + fds[idx].got_rdhup? 'h':'-', + fds[idx].got_hup? 'H':'-', + fds[idx].got_err? 'e':'-', + fds[idx].got_nval? 'n':'-' + )); + } + } +#endif /*ENABLE_TRACING*/ + return count; +} + + +void +_gpgrt_opaque_set (estream_t stream, void *opaque) +{ + lock_stream (stream); + es_opaque_ctrl (stream, opaque, NULL); + unlock_stream (stream); +} + + +void * +_gpgrt_opaque_get (estream_t stream) +{ + void *opaque; + + lock_stream (stream); + es_opaque_ctrl (stream, NULL, &opaque); + unlock_stream (stream); + + return opaque; +} + + +static void +fname_set_internal (estream_t stream, const char *fname, int quote) +{ + if (stream->intern->printable_fname + && !stream->intern->printable_fname_inuse) + { + mem_free (stream->intern->printable_fname); + stream->intern->printable_fname = NULL; + } + if (stream->intern->printable_fname) + return; /* Can't change because it is in use. */ + + if (*fname != '[') + quote = 0; + else + quote = !!quote; + + stream->intern->printable_fname = mem_alloc (strlen (fname) + quote + 1); + if (quote) + stream->intern->printable_fname[0] = '\\'; + strcpy (stream->intern->printable_fname+quote, fname); +} + + +/* Set the filename attribute of STREAM. There is no error return. + as long as STREAM is valid. This function is called internally by + functions which open a filename. */ +void +_gpgrt_fname_set (estream_t stream, const char *fname) +{ + if (fname) + { + lock_stream (stream); + fname_set_internal (stream, fname, 1); + unlock_stream (stream); + } +} + + +/* Return the filename attribute of STREAM. In case no filename has + been set, "[?]" will be returned. The returned file name is valid + as long as STREAM is valid. */ +const char * +_gpgrt_fname_get (estream_t stream) +{ + const char *fname; + + lock_stream (stream); + fname = stream->intern->printable_fname; + if (fname) + stream->intern->printable_fname_inuse = 1; + unlock_stream (stream); + if (!fname) + fname = "[?]"; + return fname; +} + + + +/* Print a BUFFER to STREAM while replacing all control characters and + the characters in DELIMITERS by standard C escape sequences. + Returns 0 on success or -1 on error. If BYTES_WRITTEN is not NULL + the number of bytes actually written are stored at this + address. */ +int +_gpgrt_write_sanitized (estream_t _GPGRT__RESTRICT stream, + const void * _GPGRT__RESTRICT buffer, size_t length, + const char * delimiters, + size_t * _GPGRT__RESTRICT bytes_written) +{ + const unsigned char *p = buffer; + size_t count = 0; + int ret; + + lock_stream (stream); + for (; length; length--, p++, count++) + { + if (*p < 0x20 + || *p == 0x7f + || (delimiters + && (strchr (delimiters, *p) || *p == '\\'))) + { + _gpgrt_putc_unlocked ('\\', stream); + count++; + if (*p == '\n') + { + _gpgrt_putc_unlocked ('n', stream); + count++; + } + else if (*p == '\r') + { + _gpgrt_putc_unlocked ('r', stream); + count++; + } + else if (*p == '\f') + { + _gpgrt_putc_unlocked ('f', stream); + count++; + } + else if (*p == '\v') + { + _gpgrt_putc_unlocked ('v', stream); + count++; + } + else if (*p == '\b') + { + _gpgrt_putc_unlocked ('b', stream); + count++; + } + else if (!*p) + { + _gpgrt_putc_unlocked('0', stream); + count++; + } + else + { + _gpgrt_fprintf_unlocked (stream, "x%02x", *p); + count += 3; + } + } + else + { + _gpgrt_putc_unlocked (*p, stream); + count++; + } + } + + if (bytes_written) + *bytes_written = count; + ret = _gpgrt_ferror_unlocked (stream)? -1 : 0; + unlock_stream (stream); + + return ret; +} + + +/* Write LENGTH bytes of BUFFER to STREAM as a hex encoded string. + RESERVED must be 0. Returns 0 on success or -1 on error. If + BYTES_WRITTEN is not NULL the number of bytes actually written are + stored at this address. */ +int +_gpgrt_write_hexstring (estream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t length, + int reserved, size_t *_GPGRT__RESTRICT bytes_written ) +{ + int ret; + const unsigned char *s; + size_t count = 0; + + (void)reserved; + +#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A')) + + if (!length) + return 0; + + lock_stream (stream); + + for (s = buffer; length; s++, length--) + { + _gpgrt_putc_unlocked ( tohex ((*s>>4)&15), stream); + _gpgrt_putc_unlocked ( tohex (*s&15), stream); + count += 2; + } + + if (bytes_written) + *bytes_written = count; + ret = _gpgrt_ferror_unlocked (stream)? -1 : 0; + + unlock_stream (stream); + + return ret; + +#undef tohex +} diff --git a/comm/third_party/libgpg-error/src/gen-lock-obj.sh b/comm/third_party/libgpg-error/src/gen-lock-obj.sh new file mode 100755 index 0000000000..a710f0ccee --- /dev/null +++ b/comm/third_party/libgpg-error/src/gen-lock-obj.sh @@ -0,0 +1,136 @@ +#! /bin/sh +# +# gen-lock-obj.sh - Build tool to construct the lock object. +# +# Copyright (C) 2020, 2021 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +# + +# +# Following variables should be defined to invoke this script +# +# CC +# OBJDUMP +# AWK +# ac_ext +# ac_object +# host +# LOCK_ABI_VERSION +# +# An example: +# +# LOCK_ABI_VERSION=1 host=x86_64-pc-linux-gnu host_alias=x86_64-linux-gnu \ +# CC=$host_alias-gcc OBJDUMP=$host_alias-objdump ac_ext=c ac_objext=o \ +# AWK=gawk ./gen-lock-obj.sh +# + +if test -n `echo -n`; then + ECHO_C='\c' + ECHO_N='' +else + ECHO_C='' + ECHO_N='-n' +fi + +if test "$1" = --disable-threads; then + cat <conftest.$ac_ext +#include +pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; +EOF + +if $CC -c conftest.$ac_ext; then : + ac_mtx_size=$($OBJDUMP -j .bss -t conftest.$ac_objext \ + | $AWK $AWK_OPTION ' +/mtx$/ { mtx_size = int("0x" $5) } +END { print mtx_size }') +else + echo "Can't determine mutex size" + exit 1 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +cat <. + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_W32_SYSTEM +# error This module may not be build for Windows. +#endif + +#include +#include +#include +#include +#ifdef USE_POSIX_THREADS +# include +#endif + +#include "posix-lock-obj.h" + +#define PGM "gen-posix-lock-obj" + +/* Check that configure did its job. */ +#ifdef USE_POSIX_THREADS +#if SIZEOF_PTHREAD_MUTEX_T < 4 +# error sizeof pthread_mutex_t is not known. +#endif +#endif + +/* Special requirements for certain platforms. */ +# define USE_LONG_DOUBLE_FOR_ALIGNMENT 0 +#if defined(__sun) && !defined (__LP64__) && !defined(_LP64) +/* Solaris on 32-bit architecture. */ +# define USE_DOUBLE_FOR_ALIGNMENT 1 +#else +# define USE_DOUBLE_FOR_ALIGNMENT 0 +#endif +#if defined(__hppa__) +# define USE_16BYTE_ALIGNMENT 1 +#else +# define USE_16BYTE_ALIGNMENT 0 +#endif + +#if USE_16BYTE_ALIGNMENT && !HAVE_GCC_ATTRIBUTE_ALIGNED +# error compiler is not able to enforce a 16 byte alignment +#endif + +#ifdef USE_POSIX_THREADS +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; +#endif + +int +main (void) +{ +#ifdef USE_POSIX_THREADS + unsigned char *p; + int i; +#endif + struct { + long vers; +#ifdef USE_POSIX_THREADS + pthread_mutex_t mtx; +#endif + } dummyobj; + + +#ifdef USE_POSIX_THREADS + if (sizeof mtx != SIZEOF_PTHREAD_MUTEX_T) + { + fprintf (stderr, PGM ": pthread_mutex_t mismatch\n"); + exit (1); + } +#endif /*USE_POSIX_THREADS*/ + + if (sizeof (dummyobj) != sizeof (_gpgrt_lock_t)) + { + fprintf (stderr, PGM ": internal and external lock object mismatch\n"); + exit (1); + } + + printf ("## lock-obj-pub.%s.h%s\n" + "## File created by " PGM " - DO NOT EDIT\n" + "## To be included by mkheader into gpg-error.h\n" + "\n", + HOST_TRIPLET_STRING, +#ifdef USE_POSIX_THREADS + "" +#else + " - NO LOCK SUPPORT" +#endif + ); + +#ifdef USE_POSIX_THREADS + + /* To force a probably suitable alignment of the structure we use a + union and include a long and a pointer to a long. */ + printf ("typedef struct\n" + "{\n" + " long _vers;\n" + " union {\n" + " volatile char _priv[%d];\n" + "%s" + " long _x_align;\n" + " long *_xp_align;\n" + " } u;\n" + "} gpgrt_lock_t;\n" + "\n" + "#define GPGRT_LOCK_INITIALIZER {%d,{{", + SIZEOF_PTHREAD_MUTEX_T, +# if USE_16BYTE_ALIGNMENT + " int _x16_align __attribute__ ((aligned (16)));\n", +# elif USE_DOUBLE_FOR_ALIGNMENT + " double _xd_align;\n", +# elif USE_LONG_DOUBLE_FOR_ALIGNMENT + " long double _xld_align;\n", +# else + "", +# endif + LOCK_ABI_VERSION); + p = (unsigned char *)&mtx; + for (i=0; i < sizeof mtx; i++) + { + if (i && !(i % 8)) + printf (" \\\n%*s", 36, ""); + printf ("%u", p[i]); + if (i < sizeof mtx - 1) + putchar (','); + } + fputs ("}}}\n", stdout); + +#else /*!USE_POSIX_THREADS*/ + + printf ("/* Dummy object - no locking available. */\n" + "typedef struct\n" + "{\n" + " long _vers;\n" + "} gpgrt_lock_t;\n" + "\n" + "#define GPGRT_LOCK_INITIALIZER {%d}\n", + LOCK_ABI_VERSION); + +#endif /*!USE_POSIX_THREADS*/ + + fputs ("##\n" + "## Loc" "al Variables:\n" + "## mode: c\n" + "## buffer-read-only: t\n" + "## End:\n" + "##\n", stdout); + + if (ferror (stdout)) + { + fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno)); + return 1; + } + + return 0; +} diff --git a/comm/third_party/libgpg-error/src/gen-w32-lock-obj.c b/comm/third_party/libgpg-error/src/gen-w32-lock-obj.c new file mode 100644 index 0000000000..f8da67f53a --- /dev/null +++ b/comm/third_party/libgpg-error/src/gen-w32-lock-obj.c @@ -0,0 +1,55 @@ +/* gen-w32-lock-obj.c - Build tool to get the size of the lock object. + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_W32_SYSTEM +# error This module may only be build for Windows. +#endif + +#include +#include +#include + +#include "w32-lock-obj.h" + + +int +main (void) +{ + _gpgrt_lock_t lk; + unsigned char *p; + int i; + + printf ("sizeof CRITICAL_SECTION = %u\n", (int)sizeof (CRITICAL_SECTION)); + printf ("sizeof _gpgrt_lock_t = %u\n", (int)sizeof lk); + + memset (&lk, 0, sizeof lk); + lk.vers = LOCK_ABI_VERSION; + lk.started = -1; + printf ("#define GPGRT_LOCK_INITIALIZER {"); + p = (unsigned char *)&lk; + for (i=0; i < sizeof lk - 1; i++) + printf ("%u,", p[i]); + printf ("%u}\n", p[sizeof(lk)-1]); + + return 0; +} diff --git a/comm/third_party/libgpg-error/src/gettext.h b/comm/third_party/libgpg-error/src/gettext.h new file mode 100644 index 0000000000..aba29db6dd --- /dev/null +++ b/comm/third_party/libgpg-error/src/gettext.h @@ -0,0 +1,76 @@ +/* Convenience header for conditional use of GNU . + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +#if HAVE_W32_SYSTEM + /* We have a gettext implementation in gpg-error.h which get + included anyway. */ +#else /*!HAVE_W32_SYSTEM*/ + /* Get declarations of GNU message catalog functions. */ +# include +#endif /*!HAVE_W32_SYSTEM*/ + +#else /*!ENABLE_NLS*/ + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of a NOP. We don't include + as well because people using "gettext.h" will not include , + and also including would fail on SunOS 4, whereas + is OK. */ +#if defined(__sun) +# include +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif /*!ENABLE_NLS*/ + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + + + +#endif /* _LIBGETTEXT_H */ diff --git a/comm/third_party/libgpg-error/src/gpg-error-config-test.sh b/comm/third_party/libgpg-error/src/gpg-error-config-test.sh new file mode 100755 index 0000000000..081358c914 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error-config-test.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +srcdir=${0%/*} + +PKG_CONFIG_PATH="." + +export PKG_CONFIG_PATH + +if [ "$1" = --old-new ]; then + PKG_CONFIG_CMD=./gpg-error-config-old + # Old gpg-error-config never supports PKG_CONFIG_SYSROOT_DIR + unset PKG_CONFIG_SYSROOT_DIR +else + pkg_config_min_version=0.29 + PKG_CONFIG_SYSROOT_DIR="/var/example-target" + export PKG_CONFIG_SYSROOT_DIR + PKG_CONFIG_CMD="pkg-config gpg-error" + check_ver=$( ($PKG_CONFIG_CMD --version; echo $pkg_config_min_version) | \ + sort -t '.' -n -k1,1 -k2,2 -k3,3 | sed 1q ) + if [ $check_ver != $pkg_config_min_version ]; then + exit 77 # Skip tests, because it's too old + fi + if ! $PKG_CONFIG_CMD --exists >/dev/null; then + exit 77 # Skip tests + fi +fi + +test_failed="" + +failure () { + ( + echo "Test result: $*" + echo "====================: $PKG_CONFIG_CMD" + echo "$OUTPUT_OLD" + echo "====================: gpgrt-config" + echo "$OUTPUT_NEW" + echo "====================" + ) >> gpg-error-config-test.log + test_failed=yes +} + +rm -f gpg-error-config-test.log + +OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --libs)) +OUTPUT_NEW=$($srcdir/gpgrt-config --libs) +[ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --libs + +OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --cflags)) +OUTPUT_NEW=$($srcdir/gpgrt-config --cflags) +[ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --cflags + +OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --cflags --libs)) +OUTPUT_NEW=$($srcdir/gpgrt-config --cflags --libs) +[ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --cflags --libs + +if [ "$PKG_CONFIG_CMD" = ./gpg-error-config-old ]; then + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --version)) + OUTPUT_NEW=$($srcdir/gpgrt-config --version) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --version + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --mt --libs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --mt --libs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --mt --libs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --mt --cflags)) + OUTPUT_NEW=$($srcdir/gpgrt-config --mt --cflags) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --mt --cflags + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --cflags --libs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --cflags --libs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --cflags --libs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --mt --cflags --libs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --mt --cflags --libs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --mt --cflags --libs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --variable=mtcflags)) + OUTPUT_NEW=$($srcdir/gpgrt-config --variable=mtcflags) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --variable=mtcflags + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --variable=mtlibs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --variable=mtlibs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --variable=mtlibs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --variable=host)) + OUTPUT_NEW=$($srcdir/gpgrt-config --variable=host) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --variable=host +fi + +if [ -n "$test_failed" ]; then + OUTPUT_OLD=$($PKG_CONFIG_CMD --version) + OUTPUT_NEW=$($srcdir/gpgrt-config --version) + failure --version + + exit 99 +fi + +exit 0 diff --git a/comm/third_party/libgpg-error/src/gpg-error-config-test.sh.in b/comm/third_party/libgpg-error/src/gpg-error-config-test.sh.in new file mode 100644 index 0000000000..b888aa2097 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error-config-test.sh.in @@ -0,0 +1,98 @@ +#!@INSTALLSHELLPATH@ + +srcdir=${0%/*} + +PKG_CONFIG_PATH="." + +export PKG_CONFIG_PATH + +if [ "$1" = --old-new ]; then + PKG_CONFIG_CMD=./gpg-error-config-old + # Old gpg-error-config never supports PKG_CONFIG_SYSROOT_DIR + unset PKG_CONFIG_SYSROOT_DIR +else + pkg_config_min_version=0.29 + PKG_CONFIG_SYSROOT_DIR="/var/example-target" + export PKG_CONFIG_SYSROOT_DIR + PKG_CONFIG_CMD="pkg-config gpg-error" + check_ver=$( ($PKG_CONFIG_CMD --version; echo $pkg_config_min_version) | \ + sort -t '.' -n -k1,1 -k2,2 -k3,3 | sed 1q ) + if [ $check_ver != $pkg_config_min_version ]; then + exit 77 # Skip tests, because it's too old + fi + if ! $PKG_CONFIG_CMD --exists >/dev/null; then + exit 77 # Skip tests + fi +fi + +test_failed="" + +failure () { + ( + echo "Test result: $*" + echo "====================: $PKG_CONFIG_CMD" + echo "$OUTPUT_OLD" + echo "====================: gpgrt-config" + echo "$OUTPUT_NEW" + echo "====================" + ) >> gpg-error-config-test.log + test_failed=yes +} + +rm -f gpg-error-config-test.log + +OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --libs)) +OUTPUT_NEW=$($srcdir/gpgrt-config --libs) +[ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --libs + +OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --cflags)) +OUTPUT_NEW=$($srcdir/gpgrt-config --cflags) +[ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --cflags + +OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --cflags --libs)) +OUTPUT_NEW=$($srcdir/gpgrt-config --cflags --libs) +[ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --cflags --libs + +if [ "$PKG_CONFIG_CMD" = ./gpg-error-config-old ]; then + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --version)) + OUTPUT_NEW=$($srcdir/gpgrt-config --version) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --version + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --mt --libs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --mt --libs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --mt --libs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --mt --cflags)) + OUTPUT_NEW=$($srcdir/gpgrt-config --mt --cflags) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --mt --cflags + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --cflags --libs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --cflags --libs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --cflags --libs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --mt --cflags --libs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --mt --cflags --libs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --mt --cflags --libs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --variable=mtcflags)) + OUTPUT_NEW=$($srcdir/gpgrt-config --variable=mtcflags) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --variable=mtcflags + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --variable=mtlibs)) + OUTPUT_NEW=$($srcdir/gpgrt-config --variable=mtlibs) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --variable=mtlibs + + OUTPUT_OLD=$(echo $($PKG_CONFIG_CMD --variable=host)) + OUTPUT_NEW=$($srcdir/gpgrt-config --variable=host) + [ "$OUTPUT_OLD" = "$OUTPUT_NEW" ] || failure --variable=host +fi + +if [ -n "$test_failed" ]; then + OUTPUT_OLD=$($PKG_CONFIG_CMD --version) + OUTPUT_NEW=$($srcdir/gpgrt-config --version) + failure --version + + exit 99 +fi + +exit 0 diff --git a/comm/third_party/libgpg-error/src/gpg-error-config.in b/comm/third_party/libgpg-error/src/gpg-error-config.in new file mode 100644 index 0000000000..3b45928cfc --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error-config.in @@ -0,0 +1,103 @@ +#!@INSTALLSHELLPATH@ +# Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# SPDX-License-Identifier: FSFULLR + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ + +if echo "$0" | grep gpg-error-config 2>/dev/null >/dev/null; then + myname="gpg-error-config" +else + myname="gpgrt-config" +fi + +output="" +mt=no + +usage() +{ + cat <&2 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) + optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` + ;; + *) + optarg= + ;; + esac + + case $1 in + --mt) + mt=yes + ;; + --prefix) + output="$output $prefix" + ;; + --exec-prefix) + output="$output $exec_prefix" + ;; + --modversion|--version) + echo "@PACKAGE_VERSION@" + exit 0 + ;; + --variable=*) + case "${1#*=}" in + prefix) echo "$prefix" ;; + exec_prefix) echo "$exec_prefix" ;; + host) echo "@GPG_ERROR_CONFIG_HOST@" ;; + mtcflags) echo "@GPG_ERROR_CONFIG_MT_CFLAGS@" ;; + mtlibs) echo "@GPG_ERROR_CONFIG_MT_LIBS@";; + esac + exit 0 + ;; + --cflags) + output="$output @GPG_ERROR_CONFIG_CFLAGS@" + if test $mt = yes ; then + output="$output @GPG_ERROR_CONFIG_MT_CFLAGS@" + fi + ;; + --libs) + output="$output @GPG_ERROR_CONFIG_LIBS@" + if test $mt = yes ; then + output="$output @GPG_ERROR_CONFIG_MT_LIBS@" + fi + ;; + --host) + echo "@GPG_ERROR_CONFIG_HOST@" + exit 0 + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +echo $output diff --git a/comm/third_party/libgpg-error/src/gpg-error.c b/comm/third_party/libgpg-error/src/gpg-error.c new file mode 100644 index 0000000000..4e8bd8b836 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.c @@ -0,0 +1,767 @@ +/* gpg-error.c - Determining gpg-error error codes. + Copyright (C) 2004, 2016 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LOCALE_H +# include +#endif +#ifdef ENABLE_NLS +#ifdef HAVE_W32_SYSTEM +# include "gettext.h" +#else +# include +#endif +# define _(a) gettext (a) +# ifdef gettext_noop +# define N_(a) gettext_noop (a) +# else +# define N_(a) (a) +# endif +#else +# define _(a) (a) +# define N_(a) (a) +#endif + +#include + + +#if HAVE_W32_SYSTEM +/* The implementation follows below. */ +static char *get_locale_dir (void); +static void drop_locale_dir (char *locale_dir); +#else +#define get_locale_dir() LOCALEDIR +#define drop_locale_dir(dir) +#endif + +static void +i18n_init (void) +{ +#ifdef ENABLE_NLS + char *locale_dir; + +#ifdef HAVE_LC_MESSAGES + setlocale (LC_TIME, ""); + setlocale (LC_MESSAGES, ""); +#else +# ifndef HAVE_W32_SYSTEM + setlocale (LC_ALL, "" ); +# endif +#endif + + /* Note that for this program we would only need the textdomain call + because libgpg-error already initializes itself to its locale dir + (via gpg_err_init or a constructor). However this is only done + for the static standard locale and thus if the above setlocale + calls select a different locale the bindtext below will do + something else. */ + + locale_dir = get_locale_dir (); + if (locale_dir) + { + bindtextdomain (PACKAGE, locale_dir); + drop_locale_dir (locale_dir); + } + textdomain (PACKAGE); +#endif +} + + +#ifdef HAVE_W32_SYSTEM + +#include + + +static char * +get_locale_dir (void) +{ + static wchar_t moddir[MAX_PATH+5]; + char *result, *p; + int nbytes; + + if (!GetModuleFileNameW (NULL, moddir, MAX_PATH)) + *moddir = 0; + +#define SLDIR "\\share\\locale" + if (*moddir) + { + nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL); + if (nbytes < 0) + return NULL; + + result = malloc (nbytes + strlen (SLDIR) + 1); + if (result) + { + nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, + result, nbytes, NULL, NULL); + if (nbytes < 0) + { + free (result); + result = NULL; + } + else + { + p = strrchr (result, '\\'); + if (p) + *p = 0; + /* If we are installed below "bin" strip that part and + use the top directory instead. */ + p = strrchr (result, '\\'); + if (p && !strcmp (p+1, "bin")) + *p = 0; + /* Append the static part. */ + strcat (result, SLDIR); + } + } + } + else /* Use the old default value. */ + { + result = malloc (10 + strlen (SLDIR) + 1); + if (result) + { + strcpy (result, "c:\\gnupg"); + strcat (result, SLDIR); + } + } +#undef SLDIR + return result; +} + + +static void +drop_locale_dir (char *locale_dir) +{ + free (locale_dir); +} + +#endif /* HAVE_W32_SYSTEM */ + + +const char *gpg_strerror_sym (gpg_error_t err); +const char *gpg_strsource_sym (gpg_error_t err); + + +/* Parse string STR assuming it is either a single number N or in the + * form K.N to denote an error source code K and and error code N. + * Returns false on error (e.g. invalid number) or true for valid + * codes; if true is returned a full error code is stored at ERR. */ +static int +get_err_from_number (char *str, gpg_error_t *err) +{ + unsigned long nr; + char *tail; + + gpg_err_set_errno (0); + nr = strtoul (str, &tail, 0); + if (errno) + return 0; + + if (nr > UINT_MAX) + return 0; + + if (*tail) + { + unsigned long cnr = strtoul (tail + 1, &tail, 0); + if (errno || *tail) + return 0; + + if (nr >= GPG_ERR_SOURCE_DIM || cnr >= GPG_ERR_CODE_DIM) + return 0; + + nr = gpg_err_make (nr, cnr); + } + + *err = (unsigned int) nr; + return 1; +} + + +/* Helper function to parse a symbol either with a "GPG_ERR_SOURCE_" + * or "GPG_ERR_" prefix. If the symbol is not available false is + * return; else the symbols value is ORed into the value at ERR + * (shifted for a GPG_ERR_SOURCE_) and true returned. HAVE_SOURCE and + * HAVE_CODE are expected to be addresses where a 0 is stored; a 1 is + * stored at the respective address to mark whether a code or source + * value was found. If one of those state variables already point to + * a true value the function will return 0 and not change the value at + * ERR. */ +static int +get_err_from_symbol_one (char *str, gpg_error_t *err, + int *have_source, int *have_code) +{ + static const char src_prefix[] = "GPG_ERR_SOURCE_"; + static const char code_prefix[] = "GPG_ERR_"; + + if (!strncasecmp (src_prefix, str, sizeof (src_prefix) - 1)) + { + gpg_err_source_t src; + + if (*have_source) + return 0; + *have_source = 1; + str += sizeof (src_prefix) - 1; + + for (src = 0; src < GPG_ERR_SOURCE_DIM; src++) + { + const char *src_sym; + + src_sym = gpg_strsource_sym (src << GPG_ERR_SOURCE_SHIFT); + if (src_sym && !strcasecmp (str, src_sym + sizeof (src_prefix) - 1)) + { + *err |= src << GPG_ERR_SOURCE_SHIFT; + return 1; + } + } + } + else if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1)) + { + gpg_err_code_t code; + + if (*have_code) + return 0; + *have_code = 1; + str += sizeof (code_prefix) - 1; + + for (code = 0; code < GPG_ERR_CODE_DIM; code++) + { + const char *code_sym = gpg_strerror_sym (code); + if (code_sym + && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1)) + { + *err |= code; + return 1; + } + } + } + return 0; +} + + +/* Parse string STR assuming it is either a single symbol C or in the + * form S.C to denote an error source symbold S and and error code + * symbold C. Returns false on error (e.g. invalid number) or true + * for valid codes; if true is returned a full error code is stored at + * ERR. */ +static int +get_err_from_symbol (char *str, gpg_error_t *err) +{ + char *str2 = str; + int have_source = 0; + int have_code = 0; + int ret; + char *saved_pos = NULL; + char saved_char; + + *err = 0; + while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z') + || (*str2 >= '0' && *str2 <= '9') + || *str2 == '_')) + str2++; + if (*str2) + { + saved_pos = str2; + saved_char = *str2; + *str2 = '\0'; + str2++; + } + else + str2 = NULL; + + ret = get_err_from_symbol_one (str, err, &have_source, &have_code); + if (ret && str2) + ret = get_err_from_symbol_one (str2, err, &have_source, &have_code); + + if (saved_pos) + *saved_pos = saved_char; + return ret; +} + + +/* Parse string STR assuming it partial code symbol and store its + * value at ERR and return true. */ +static int +get_err_from_codesymbol (char *str, gpg_error_t *err) +{ + static const char code_prefix[] = "GPG_ERR_"; + gpg_err_code_t code; + + *err = 0; + + /* Skip an optional prefix. */ + if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1)) + str += sizeof (code_prefix) - 1; + + for (code = 0; code < GPG_ERR_CODE_DIM; code++) + { + const char *code_sym = gpg_strerror_sym (code); + if (code_sym + && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1)) + { + *err |= code; + return 1; + } + } + return 0; +} + + +/* Helper function to parse a string which maps back to a source or + * code value. If no source or code for the symbold is available + * false is return; else the source or code value is ORed into the + * value at ERR (shifted for a GPG_ERR_SOURCE_) and true returned. + * The match is first tried on source values and then on code values. + * HAVE_SOURCE and HAVE_CODE are expected to be addresses where a 0 is + * stored; a 1 is stored at the respective address to mark whether a + * code or source value was found. If one of those state variables + * already point to a true value the function will return 0 and not + * change the value at ERR. */ +static int +get_err_from_str_one (char *str, gpg_error_t *err, + int *have_source, int *have_code) +{ + gpg_err_source_t src; + gpg_err_code_t code; + + for (src = 0; src < GPG_ERR_SOURCE_DIM; src++) + { + const char *src_str = gpg_strsource (src << GPG_ERR_SOURCE_SHIFT); + if (src_str && !strcasecmp (str, src_str)) + { + if (*have_source) + return 0; + + *have_source = 1; + *err |= src << GPG_ERR_SOURCE_SHIFT; + return 1; + } + } + + for (code = 0; code < GPG_ERR_CODE_DIM; code++) + { + const char *code_str = gpg_strerror (code); + if (code_str && !strcasecmp (str, code_str)) + { + if (*have_code) + return 0; + + *have_code = 1; + *err |= code; + return 1; + } + } + + return 0; +} + + +/* Parse string STR assuming it is either a single desription string C + * or in the form S.C to denote an error source descrition S and and + * error code description C. Returns false on error (e.g. invalid + * symbol) or true for valid codes; if true is returned a full error + * code is stored at ERR. */ +static int +get_err_from_str (char *str, gpg_error_t *err) +{ + char *str2 = str; + int have_source = 0; + int have_code = 0; + int ret; + char *saved_pos = NULL; + char saved_char = 0; /* (avoid warning) */ + + *err = 0; + /* First match on the entire string to handle the case that it is + * code description with spaces. */ + ret = get_err_from_str_one (str, err, &have_source, &have_code); + if (ret) + return ret; + + /* Then figure out whether the first string is a simple word. */ + while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z') + || (*str2 >= 'a' && *str2 <= 'z') + || (*str2 >= '0' && *str2 <= '9') + || *str2 == '_')) + str2++; + if (*str2) + { + saved_pos = str2; + saved_char = *str2; + *((char *) str2) = '\0'; + str2++; + while (*str2 && !((*str2 >= 'A' && *str2 <= 'Z') + || (*str2 >= 'a' && *str2 <= 'z') + || (*str2 >= '0' && *str2 <= '9') + || *str2 == '_')) + str2++; + } + else + str2 = NULL; + + ret = get_err_from_str_one (str, err, &have_source, &have_code); + if (ret && str2) + ret = get_err_from_str_one (str2, err, &have_source, &have_code); + + if (saved_pos) + *saved_pos = saved_char; + return ret; +} + + +static void +print_desc (const char *symbol) +{ + static int initialized; + static FILE *fp; + char line[512]; + char *p; + int indesc = 0; + int blanklines = 0; + int last_was_keyword = 0; + + if (!symbol) + return; + + if (!initialized) + { + initialized = 1; + fp = fopen (PKGDATADIR "/errorref.txt", "r"); + } + if (!fp) + return; + rewind (fp); + while (fgets (line, sizeof line, fp)) + { + if (*line == '#') + continue; + if (*line && line[strlen(line)-1] == '\n') + line[strlen(line)-1] = 0; + + if (!strncmp (line, "GPG_ERR_", 8)) + { + if (indesc == 1 && last_was_keyword) + continue; /* Skip keywords immediately following a matched + * keyword. */ + last_was_keyword = 1; + + indesc = 0; + p = strchr (line, ' '); + if (!p) + continue; + *p = 0; + if (!strcmp (line, symbol)) + { + indesc = 1; + continue; /* Skip this line. */ + } + } + else + last_was_keyword = 0; + if (!indesc) + continue; + if (indesc == 1 && !*line) + continue; /* Skip leading empty lines in a description. */ + if (indesc == 1) + putchar ('\n'); /* One leading empty line. */ + indesc = 2; + if (!*line) + { + blanklines++; + continue; + } + for (; blanklines; blanklines--) + putchar ('\n'); + printf ("%s\n", line); + } + putchar ('\n'); /* One trailing blank line. */ +} + + + + + +static const char * +my_strusage (int level) +{ + const char *p; + + switch (level) + { + case 9: p = "LGPL-2.1-or-later"; break; + + case 11: p = "gpg-error"; break; + case 12: p = PACKAGE_NAME; break; + case 13: p = PACKAGE_VERSION; break; + case 14: p = "Copyright (C) 2019 g10 Code GmbH"; break; + case 19: p = _("Please report bugs to .\n"); break; + + case 1: + case 40: + p = ("Usage: gpg-error [options] error-numbers"); + break; + case 41: + p = ("Map error numbers to strings and vice versa.\n"); + break; + + case 42: + p = "1"; /* Flag: print 40 as part of 41. */ + break; + + default: p = NULL; break; + } + return p; +} + + + +int +main (int argc, char *argv[]) +{ + enum { CMD_DEFAULT = 0, + CMD_LIB_VERSION = 501, + CMD_LIST, + CMD_DEFINES, + CMD_LOCALE, + OPT_DESC + }; + static gpgrt_opt_t opts[] = { + ARGPARSE_c (CMD_LIB_VERSION, "lib-version", + "Print library version"), + ARGPARSE_c (CMD_LIST, "list", + "Print all error codes"), + ARGPARSE_c (CMD_DEFINES, "defines", + "Print all error codes as #define lines"), +#if HAVE_W32_SYSTEM + ARGPARSE_c (CMD_LOCALE, "locale", + "Return the locale used for gettext"), +#else + ARGPARSE_c (CMD_LOCALE, "locale", + "@"), +#endif + ARGPARSE_s_n (OPT_DESC, "desc", + "Print with error description"), + ARGPARSE_end() + }; + gpgrt_argparse_t pargs = { &argc, &argv }; + + int i; + int libversion = 0; + int listmode = 0; + int localemode = 0; + int desc = 0; + const char *s, *s2; + const char *source_sym; + const char *error_sym; + gpg_error_t err; + + gpgrt_init (); + i18n_init (); + gpgrt_set_strusage (my_strusage); + gpgrt_log_set_prefix (gpgrt_strusage (11), GPGRT_LOG_WITH_PREFIX); + + + while (gpgrt_argparse (NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case CMD_LIB_VERSION: libversion = 1; break; + case CMD_LIST: listmode = 1; break; + case CMD_DEFINES: listmode = 2; break; + case CMD_LOCALE: localemode = 1; break; + case OPT_DESC: desc = 1; break; + default: pargs.err = ARGPARSE_PRINT_WARNING; break; + } + } + gpgrt_argparse (NULL, &pargs, NULL); /* Free internal memory. */ + + if (libversion) + { + if (argc) + gpgrt_usage (1); + } + else if (localemode) + { + if (argc > 1) + gpgrt_usage (1); + } + else if ((argc && listmode) || (!argc && !listmode)) + gpgrt_usage (1); + + + if (libversion) + { + argc--; argv++; + printf ("Version from header: %s (0x%06x)\n", + GPG_ERROR_VERSION, GPG_ERROR_VERSION_NUMBER); + printf ("Version from binary: %s\n", gpg_error_check_version (NULL)); + s = gpg_error_check_version ("\x01\x01"); + while (*s && *s == '\n') + s++; + fputs ("Copyright blurb ...: ", stdout); + for (; *s; s++) + { + if (*s == '\n') + { + for (s2=s+1; *s2 == '\n'; s2++) + ; + if (!*s2) + break; /* Cut off trailing LFs. */ + fputs ("\n ", stdout); + } + else + putc (*s, stdout); + } + putc ('\n', stdout); + } + else if (localemode) + { +#if HAVE_W32_SYSTEM + if (argc) + { + /* Warning: What we do here is not allowed because + * gpgrt_w32_override_locale needs to be called as early as + * possible. However for this very purpose it is okay. */ + if (**argv >= '0' && **argv <= '9') + gpgrt_w32_override_locale (NULL, strtoul (*argv, NULL, 0)); + else + gpgrt_w32_override_locale (*argv, 0); + } + + printf ("%s\n", gettext_localename ()); +#else + log_info ("this command is only useful on Windows\n"); +#endif + } + else if (listmode == 1) + { + for (i=0; i < GPG_ERR_SOURCE_DIM; i++) + { + /* We use error code 1 because gpg_err_make requires a + non-zero error code. */ + err = gpg_err_make (i, 1); + err -= 1; + source_sym = gpg_strsource_sym (err); + if (source_sym) + { + printf ("%u = (%u, -) = (%s, -) = (%s, -)\n", + err, gpg_err_source (err), + source_sym, gpg_strsource (err)); + if (desc) + print_desc (source_sym); + } + } + for (i=0; i < GPG_ERR_CODE_DIM; i++) + { + err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); + error_sym = gpg_strerror_sym (err); + if (error_sym) + { + printf ("%u = (-, %u) = (-, %s) = (-, %s)\n", + err, gpg_err_code (err), + error_sym, gpg_strerror (err)); + if (desc) + print_desc (error_sym); + } + } + } + else if (listmode == 2) + { + int n, nmax; + + for (i=0, nmax=0; i < GPG_ERR_SOURCE_DIM; i++) + { + err = gpg_err_make (i, 1); + source_sym = gpg_strsource_sym (err); + if (source_sym) + { + n = strlen (source_sym); + if (n > nmax) + nmax = n; + } + } + for (i=0; i < GPG_ERR_SOURCE_DIM; i++) + { + err = gpg_err_make (i, 1); + source_sym = gpg_strsource_sym (err); + if (source_sym) + printf ("#define %-*s %3u\n", nmax,source_sym,gpg_err_source (err)); + } + + + for (i=0, nmax = 0; i < GPG_ERR_CODE_DIM; i++) + { + err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); + error_sym = gpg_strerror_sym (err); + if (error_sym) + { + n = strlen (error_sym); + if (n > nmax) + nmax = n; + } + } + for (i=0; i < GPG_ERR_CODE_DIM; i++) + { + err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); + error_sym = gpg_strerror_sym (err); + if (error_sym) + printf ("#define %-*s %5u\n", nmax, error_sym, gpg_err_code (err)); + } + } + else /* Standard mode. */ + { + for (i=0; i < argc; i++) + { + /* First check the arg is a number N or K.N, + * then check the arg for CODESYM or SOURCESYM.CODESYM, + * then check the arg for CODESYM or CODESYM w/o GPG_ERR_ prefix, + * then check the arg for code description + * or symbol dot code description. + */ + if (get_err_from_number (argv[i], &err) + || get_err_from_symbol (argv[i], &err) + || get_err_from_codesymbol (argv[i], &err) + || get_err_from_str (argv[i], &err)) + { + source_sym = gpg_strsource_sym (err); + error_sym = gpg_strerror_sym (err); + + printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n", + err, gpg_err_source (err), gpg_err_code (err), + source_sym ? source_sym : "-", error_sym ? error_sym:"-", + gpg_strsource (err), gpg_strerror (err)); + if (desc) + print_desc (error_sym); + } + else + log_error (_("warning: could not recognize %s\n"), argv[i]); + } + } + + exit (0); +} diff --git a/comm/third_party/libgpg-error/src/gpg-error.def.in b/comm/third_party/libgpg-error/src/gpg-error.def.in new file mode 100644 index 0000000000..769be1bbc8 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.def.in @@ -0,0 +1,245 @@ +/* libgpg-error.def - Exported symbols for W32 + * Copyright (C) 2014 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + * + * Note: This file should be updated manually and the ordinals shall + * never be changed. Also check gpg-error.vers and visibility.h. + * + * This file needs to be pre-processed. + */ + +#include + +EXPORTS + gpg_strerror @1 + gpg_strerror_r @2 + gpg_strsource @3 + gpg_err_code_from_errno @4 + gpg_err_code_to_errno @5 + /* @6 - Not anymore used. */ + gpg_err_code_from_syserror @7 + gpg_err_set_errno @8 +#ifdef HAVE_W32CE_SYSTEM + _gpg_w32ce_get_errno @9 + _gpg_w32ce_strerror @10 +#endif +#ifdef HAVE_W32_SYSTEM + _gpg_w32_bindtextdomain @11 + _gpg_w32_textdomain @12 + _gpg_w32_gettext @13 + _gpg_w32_dgettext @14 + _gpg_w32_dngettext @15 + _gpg_w32_gettext_localename @16 + _gpg_w32_gettext_use_utf8 @17 +#endif + /* @18 - Not anymore used. */ + gpg_error_check_version @19 + + gpgrt_lock_init @20 + gpgrt_lock_lock @21 + gpgrt_lock_unlock @22 + gpgrt_lock_destroy @23 + gpgrt_yield @24 + gpgrt_lock_trylock @25 + + gpgrt_set_syscall_clamp @26 + + gpgrt_fopen @27 + gpgrt_mopen @28 + gpgrt_fopenmem @29 + gpgrt_fopenmem_init @30 + gpgrt_fdopen @31 + gpgrt_fdopen_nc @32 + gpgrt_sysopen @33 + gpgrt_sysopen_nc @34 + gpgrt_fpopen @35 + gpgrt_fpopen_nc @36 + gpgrt_freopen @37 + gpgrt_fopencookie @38 + gpgrt_fclose @39 + gpgrt_fclose_snatch @40 + gpgrt_onclose @41 + gpgrt_fileno @42 + gpgrt_fileno_unlocked @43 + gpgrt_syshd @44 + gpgrt_syshd_unlocked @45 + _gpgrt_set_std_fd @46 + _gpgrt_get_std_stream @47 + gpgrt_flockfile @48 + gpgrt_ftrylockfile @49 + gpgrt_funlockfile @50 + gpgrt_feof @51 + gpgrt_feof_unlocked @52 + gpgrt_ferror @53 + gpgrt_ferror_unlocked @54 + gpgrt_clearerr @55 + gpgrt_clearerr_unlocked @56 + gpgrt_fflush @57 + gpgrt_fseek @58 + gpgrt_fseeko @59 + gpgrt_ftell @60 + gpgrt_ftello @61 + gpgrt_rewind @62 + gpgrt_fgetc @63 + _gpgrt_getc_underflow @64 + gpgrt_fputc @65 + _gpgrt_putc_overflow @66 + gpgrt_ungetc @67 + gpgrt_read @68 + gpgrt_write @69 + gpgrt_write_sanitized @70 + gpgrt_write_hexstring @71 + gpgrt_fread @72 + gpgrt_fwrite @73 + gpgrt_fgets @74 + gpgrt_fputs @75 + gpgrt_fputs_unlocked @76 + gpgrt_getline @77 + gpgrt_read_line @78 + gpgrt_free @79 + gpgrt_fprintf @80 + gpgrt_fprintf_unlocked @81 + gpgrt_printf @82 + gpgrt_printf_unlocked @83 + gpgrt_vfprintf @84 + gpgrt_vfprintf_unlocked @85 + gpgrt_setvbuf @86 + gpgrt_setbuf @87 + gpgrt_set_binary @88 + gpgrt_tmpfile @89 + gpgrt_opaque_set @90 + gpgrt_opaque_get @91 + gpgrt_fname_set @92 + gpgrt_fname_get @93 + gpgrt_asprintf @94 + gpgrt_vasprintf @95 + gpgrt_bsprintf @96 + gpgrt_vbsprintf @97 + gpgrt_snprintf @98 + gpgrt_vsnprintf @99 + + gpgrt_check_version @100 + gpg_err_init @101 + gpg_err_deinit @102 + gpgrt_set_alloc_func @103 + + _gpgrt_pending @104 + _gpgrt_pending_unlocked @105 + + gpgrt_set_nonblock @106 + gpgrt_get_nonblock @107 + gpgrt_poll @108 + +#ifdef HAVE_W32_SYSTEM + gpgrt_w32_iconv_open @109 + gpgrt_w32_iconv_close @110 + gpgrt_w32_iconv @111 +#endif + + gpgrt_get_syscall_clamp @112 + + gpgrt_b64dec_start @113 + gpgrt_b64dec_proc @114 + gpgrt_b64dec_finish @115 + + gpgrt_get_errorcount @116 + gpgrt_inc_errorcount @117 + gpgrt_log_set_sink @118 + gpgrt_log_set_socket_dir_cb @119 + gpgrt_log_set_pid_suffix_cb @120 + gpgrt_log_set_prefix @121 + gpgrt_log_get_prefix @122 + gpgrt_log_test_fd @123 + gpgrt_log_get_fd @124 + gpgrt_log_get_stream @125 + gpgrt_log @126 + gpgrt_logv @127 + gpgrt_logv_prefix @128 + gpgrt_log_string @129 + gpgrt_log_bug @130 + gpgrt_log_fatal @131 + gpgrt_log_error @132 + gpgrt_log_info @133 + gpgrt_log_debug @134 + gpgrt_log_debug_string @135 + gpgrt_log_printf @136 + gpgrt_log_printhex @137 + gpgrt_log_clock @138 + gpgrt_log_flush @139 + _gpgrt_log_assert @140 + + gpgrt_realloc @141 + gpgrt_malloc @142 + gpgrt_calloc @143 + gpgrt_strdup @144 + gpgrt_strconcat @145 + + gpgrt_w32_reg_query_string @146 + + gpgrt_getenv @147 + gpgrt_setenv @148 + gpgrt_mkdir @149 + gpgrt_chdir @150 + gpgrt_getcwd @151 + +;; API not yet finished for: +;; gpgrt_make_pipe @152 +;; gpgrt_spawn_process @153 +;; gpgrt_spawn_process_fd @154 +;; gpgrt_spawn_process_detached @155 +;; gpgrt_wait_process @156 +;; gpgrt_wait_processes @157 +;; gpgrt_kill_process @158 +;; gpgrt_release_process @159 + + gpgrt_argparse @160 + gpgrt_usage @161 + gpgrt_strusage @162 + gpgrt_set_strusage @163 + gpgrt_set_usage_outfnc @164 + gpgrt_set_fixed_string_mapper @165 + + gpgrt_b64enc_start @166 + gpgrt_b64enc_write @167 + gpgrt_b64enc_finish @168 + + gpgrt_cmp_version @169 + + gpgrt_ftruncate @170 + gpgrt_fprintf_sf @171 + gpgrt_fprintf_sf_unlocked @172 + + gpgrt_w32_override_locale @173 + + gpgrt_add_emergency_cleanup @174 + gpgrt_abort @175 + + gpgrt_set_confdir @176 + gpgrt_argparser @177 + + gpgrt_fnameconcat @178 + gpgrt_absfnameconcat @179 + + gpgrt_reallocarray @180 + gpgrt_fclose @181 + + gpgrt_fcancel @182 + + gpgrt_access @183 + +;; end of file with public symbols for Windows. diff --git a/comm/third_party/libgpg-error/src/gpg-error.h.in b/comm/third_party/libgpg-error/src/gpg-error.h.in new file mode 100644 index 0000000000..d2c3b8d3a1 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.h.in @@ -0,0 +1,1378 @@ +/* gpg-error.h or gpgrt.h - Common code for GnuPG and others. -*- c -*- + * Copyright (C) 2001-2020 g10 Code GmbH + * + * This file is part of libgpg-error (aka libgpgrt). + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + * + * @configure_input@ + */ + +/* The GnuPG project consists of many components. Error codes are + * exchanged between all components. The common error codes and their + * user-presentable descriptions are kept into a shared library to + * allow adding new error codes and components without recompiling any + * of the other components. In addition to error codes this library + * also features several other groups of functions which are common to + * all GnuPG components. They may be used by independet project as + * well. The interfaces will not change in a backward incompatible way. + * + * An error code together with an error source build up an error + * value. As the error value is been passed from one component to + * another, it preserves the information about the source and nature + * of the error. + * + * A component of the GnuPG project can define the following macros to + * tune the behaviour of the library: + * + * GPG_ERR_SOURCE_DEFAULT: Define to an error source of type + * gpg_err_source_t to make that source the default for gpg_error(). + * Otherwise GPG_ERR_SOURCE_UNKNOWN is used as default. + * + * GPG_ERR_ENABLE_GETTEXT_MACROS: Define to provide macros to map the + * internal gettext API to standard names. This has only an effect on + * Windows platforms. + * + * GPGRT_ENABLE_ES_MACROS: Define to provide "es_" macros for the + * estream functions. + * + * GPGRT_ENABLE_LOG_MACROS: Define to provide short versions of the + * log functions. + * + * GPGRT_ENABLE_ARGPARSE_MACROS: Needs to be defined to provide the + * mandatory macros of the argparse interface. + */ + +#ifndef GPG_ERROR_H +#define GPG_ERROR_H 1 +#ifndef GPGRT_H +#define GPGRT_H 1 + +#include +#include +#include + +/* The version string of this header. */ +#define GPG_ERROR_VERSION @version@ +#define GPGRT_VERSION @version@ + +/* The version number of this header. */ +#define GPG_ERROR_VERSION_NUMBER @version-number@ +#define GPGRT_VERSION_NUMBER @version-number@ + + +#ifdef __GNUC__ +# define GPG_ERR_INLINE __inline__ +#elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define GPG_ERR_INLINE __inline +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define GPG_ERR_INLINE inline +#else +# ifndef GPG_ERR_INLINE +# define GPG_ERR_INLINE +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#if 0 /* just to make Emacs auto-indent happy */ +} +#endif +#endif /* __cplusplus */ + + + +/* The error source type gpg_err_source_t. + * + * Where as the Poo out of a welle small + * Taketh his firste springing and his sours. + * --Chaucer. + */ + +/* Only use free slots, never change or reorder the existing + * entries. */ +typedef enum + { +@include:err-sources@ + /* This is one more than the largest allowed entry. */ + GPG_ERR_SOURCE_DIM = 128 + } gpg_err_source_t; + + +/* The error code type gpg_err_code_t. */ + +/* Only use free slots, never change or reorder the existing + * entries. */ +typedef enum + { +@include:err-codes@ + /* The following error codes are used to map system errors. */ +#define GPG_ERR_SYSTEM_ERROR (1 << 15) +@include:errnos@ + /* This is one more than the largest allowed entry. */ + GPG_ERR_CODE_DIM = 65536 + } gpg_err_code_t; + + +/* The error value type gpg_error_t. */ + +/* We would really like to use bit-fields in a struct, but using + * structs as return values can cause binary compatibility issues, in + * particular if you want to do it efficiently (also see + * -freg-struct-return option to GCC). */ +typedef unsigned int gpg_error_t; + +/* We use the lowest 16 bits of gpg_error_t for error codes. The 16th + * bit indicates system errors. */ +#define GPG_ERR_CODE_MASK (GPG_ERR_CODE_DIM - 1) + +/* Bits 17 to 24 are reserved. */ + +/* We use the upper 7 bits of gpg_error_t for error sources. */ +#define GPG_ERR_SOURCE_MASK (GPG_ERR_SOURCE_DIM - 1) +#define GPG_ERR_SOURCE_SHIFT 24 + +/* The highest bit is reserved. It shouldn't be used to prevent + * potential negative numbers when transmitting error values as + * text. */ + + +/* + * GCC feature test. + */ +#if __GNUC__ +# define _GPG_ERR_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#else +# define _GPG_ERR_GCC_VERSION 0 +#endif + +#undef _GPG_ERR_HAVE_CONSTRUCTOR +#if _GPG_ERR_GCC_VERSION > 30100 +# define _GPG_ERR_CONSTRUCTOR __attribute__ ((__constructor__)) +# define _GPG_ERR_HAVE_CONSTRUCTOR +#else +# define _GPG_ERR_CONSTRUCTOR +#endif + +#define GPGRT_GCC_VERSION _GPG_ERR_GCC_VERSION + +#if _GPG_ERR_GCC_VERSION >= 29200 +# define _GPGRT__RESTRICT __restrict__ +#else +# define _GPGRT__RESTRICT +#endif + +/* The noreturn attribute. */ +#if _GPG_ERR_GCC_VERSION >= 20500 +# define GPGRT_ATTR_NORETURN __attribute__ ((__noreturn__)) +#else +# define GPGRT_ATTR_NORETURN +#endif + +/* The printf attributes. */ +#if _GPG_ERR_GCC_VERSION >= 40400 +# define GPGRT_ATTR_PRINTF(f, a) \ + __attribute__ ((format(__gnu_printf__,f,a))) +# define GPGRT_ATTR_NR_PRINTF(f, a) \ + __attribute__ ((__noreturn__, format(__gnu_printf__,f,a))) +#elif _GPG_ERR_GCC_VERSION >= 20500 +# define GPGRT_ATTR_PRINTF(f, a) \ + __attribute__ ((format(printf,f,a))) +# define GPGRT_ATTR_NR_PRINTF(f, a) \ + __attribute__ ((__noreturn__, format(printf,f,a))) +#else +# define GPGRT_ATTR_PRINTF(f, a) +# define GPGRT_ATTR_NR_PRINTF(f, a) +#endif +#if _GPG_ERR_GCC_VERSION >= 20800 +# define GPGRT_ATTR_FORMAT_ARG(a) __attribute__ ((__format_arg__ (a))) +#else +# define GPGRT_ATTR_FORMAT_ARG(a) +#endif + +/* The sentinel attribute. */ +#if _GPG_ERR_GCC_VERSION >= 40000 +# define GPGRT_ATTR_SENTINEL(a) __attribute__ ((sentinel(a))) +#else +# define GPGRT_ATTR_SENTINEL(a) +#endif + +/* The used and unused attributes. + * I am not sure since when the unused attribute is really supported. + * In any case it it only needed for gcc versions which print a + * warning. Thus let us require gcc >= 3.5. */ +#if _GPG_ERR_GCC_VERSION >= 40000 +# define GPGRT_ATTR_USED __attribute__ ((used)) +#else +# define GPGRT_ATTR_USED +#endif +#if _GPG_ERR_GCC_VERSION >= 30500 +# define GPGRT_ATTR_UNUSED __attribute__ ((unused)) +#else +# define GPGRT_ATTR_UNUSED +#endif + +/* The deprecated attribute. */ +#if _GPG_ERR_GCC_VERSION >= 30100 +# define GPGRT_ATTR_DEPRECATED __attribute__ ((__deprecated__)) +#else +# define GPGRT_ATTR_DEPRECATED +#endif + +/* The pure attribute. */ +#if _GPG_ERR_GCC_VERSION >= 29600 +# define GPGRT_ATTR_PURE __attribute__ ((__pure__)) +#else +# define GPGRT_ATTR_PURE +#endif + +/* The malloc attribute. */ +#if _GPG_ERR_GCC_VERSION >= 30200 +# define GPGRT_ATTR_MALLOC __attribute__ ((__malloc__)) +#else +# define GPGRT_ATTR_MALLOC +#endif + +/* A macro defined if a GCC style __FUNCTION__ macro is available. */ +#undef GPGRT_HAVE_MACRO_FUNCTION +#if _GPG_ERR_GCC_VERSION >= 20500 +# define GPGRT_HAVE_MACRO_FUNCTION 1 +#endif + +/* A macro defined if the pragma GCC push_options is available. */ +#undef GPGRT_HAVE_PRAGMA_GCC_PUSH +#if _GPG_ERR_GCC_VERSION >= 40400 +# define GPGRT_HAVE_PRAGMA_GCC_PUSH 1 +#endif + +/* Detect LeakSanitizer (LSan) support for GCC and Clang based on + * whether AddressSanitizer (ASAN) is enabled via -fsanitize=address). + * Note that -fsanitize=leak just affect the linker options which + * cannot be detected here. In that case you have to define the + * GPGRT_HAVE_LEAK_SANITIZER macro manually. */ +#ifdef __GNUC__ +# ifdef __SANITIZE_ADDRESS__ +# define GPGRT_HAVE_LEAK_SANITIZER +# elif defined(__has_feature) +# if __has_feature(address_sanitizer) +# define GPGRT_HAVE_LEAK_SANITIZER +# endif +# endif +#endif + + +/* The new name for the inline macro. */ +#define GPGRT_INLINE GPG_ERR_INLINE + +#ifdef GPGRT_HAVE_LEAK_SANITIZER +# include +#endif + +/* Mark heap objects as non-leaked memory. */ +static GPGRT_INLINE void +gpgrt_annotate_leaked_object (const void *p) +{ +#ifdef GPGRT_HAVE_LEAK_SANITIZER + __lsan_ignore_object(p); +#else + (void)p; +#endif +} + + +/* + * Initialization function. + */ + +/* Initialize the library. This function should be run early. */ +gpg_error_t gpg_err_init (void) _GPG_ERR_CONSTRUCTOR; + +/* If this is defined, the library is already initialized by the + constructor and does not need to be initialized explicitely. */ +#undef GPG_ERR_INITIALIZED +#ifdef _GPG_ERR_HAVE_CONSTRUCTOR +# define GPG_ERR_INITIALIZED 1 +# define gpgrt_init() do { gpg_err_init (); } while (0) +#else +# define gpgrt_init() do { ; } while (0) +#endif + +/* See the source on how to use the deinit function; it is usually not + required. */ +void gpg_err_deinit (int mode); + +/* Register blocking system I/O clamping functions. */ +void gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void)); + +/* Get current I/O clamping functions. */ +void gpgrt_get_syscall_clamp (void (**r_pre)(void), void (**r_post)(void)); + +/* Register a custom malloc/realloc/free function. */ +void gpgrt_set_alloc_func (void *(*f)(void *a, size_t n)); + +/* Register an emergency cleanup handler. */ +void gpgrt_add_emergency_cleanup (void (*f)(void)); + +/* Wrapper around abort to make sure emergency cleanups are run. */ +void gpgrt_abort (void) GPGRT_ATTR_NORETURN; + + + +/* + * Constructor and accessor functions. + */ + +/* Construct an error value from an error code and source. Within a + * subsystem, use gpg_error. */ +static GPG_ERR_INLINE gpg_error_t +gpg_err_make (gpg_err_source_t source, gpg_err_code_t code) +{ + return code == GPG_ERR_NO_ERROR ? GPG_ERR_NO_ERROR + : (((source & GPG_ERR_SOURCE_MASK) << GPG_ERR_SOURCE_SHIFT) + | (code & GPG_ERR_CODE_MASK)); +} + + +/* The user should define GPG_ERR_SOURCE_DEFAULT before including this + * file to specify a default source for gpg_error. */ +#ifndef GPG_ERR_SOURCE_DEFAULT +#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_UNKNOWN +#endif + +static GPG_ERR_INLINE gpg_error_t +gpg_error (gpg_err_code_t code) +{ + return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, code); +} + + +/* Retrieve the error code from an error value. */ +static GPG_ERR_INLINE gpg_err_code_t +gpg_err_code (gpg_error_t err) +{ + return (gpg_err_code_t) (err & GPG_ERR_CODE_MASK); +} + + +/* Retrieve the error source from an error value. */ +static GPG_ERR_INLINE gpg_err_source_t +gpg_err_source (gpg_error_t err) +{ + return (gpg_err_source_t) ((err >> GPG_ERR_SOURCE_SHIFT) + & GPG_ERR_SOURCE_MASK); +} + + +/* String functions. */ + +/* Return a pointer to a string containing a description of the error + * code in the error value ERR. This function is not thread-safe. */ +const char *gpg_strerror (gpg_error_t err); + +/* Return the error string for ERR in the user-supplied buffer BUF of + * size BUFLEN. This function is, in contrast to gpg_strerror, + * thread-safe if a thread-safe strerror_r() function is provided by + * the system. If the function succeeds, 0 is returned and BUF + * contains the string describing the error. If the buffer was not + * large enough, ERANGE is returned and BUF contains as much of the + * beginning of the error string as fits into the buffer. */ +int gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen); + +/* Return a pointer to a string containing a description of the error + * source in the error value ERR. */ +const char *gpg_strsource (gpg_error_t err); + + +/* + * Mapping of system errors (errno). + */ + +/* Retrieve the error code for the system error ERR. This returns + * GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report + * this). */ +gpg_err_code_t gpg_err_code_from_errno (int err); + +/* Retrieve the system error for the error code CODE. This returns 0 + * if CODE is not a system error code. */ +int gpg_err_code_to_errno (gpg_err_code_t code); + +/* Retrieve the error code directly from the ERRNO variable. This + * returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped + * (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */ +gpg_err_code_t gpg_err_code_from_syserror (void); + +/* Mapper for SQLite primary error codes. */ +static GPG_ERR_INLINE gpg_error_t +gpg_err_code_from_sqlite (int sqlres) +{ + return sqlres? GPG_ERR_SQL_OK + (sqlres & 0xff) : 0; +} + + +/* Set the ERRNO variable. This function is the preferred way to set + * ERRNO due to peculiarities on WindowsCE. */ +void gpg_err_set_errno (int err); + +/* Return or check the version. Both functions are identical. */ +const char *gpgrt_check_version (const char *req_version); +const char *gpg_error_check_version (const char *req_version); + +/* System specific type definitions. */ +@define:pid_t@ +@define:gpgrt_ssize_t@ +@define:gpgrt_off_t@ + +@include:os-add@ + +/* Self-documenting convenience functions. */ + +static GPG_ERR_INLINE gpg_error_t +gpg_err_make_from_errno (gpg_err_source_t source, int err) +{ + return gpg_err_make (source, gpg_err_code_from_errno (err)); +} + + +static GPG_ERR_INLINE gpg_error_t +gpg_error_from_errno (int err) +{ + return gpg_error (gpg_err_code_from_errno (err)); +} + +static GPG_ERR_INLINE gpg_error_t +gpg_error_from_syserror (void) +{ + return gpg_error (gpg_err_code_from_syserror ()); +} + + + +/* + * Malloc and friends + */ + +void *gpgrt_realloc (void *a, size_t n); +void *gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size); +void *gpgrt_malloc (size_t n); +void *gpgrt_calloc (size_t n, size_t m); +char *gpgrt_strdup (const char *string); +char *gpgrt_strconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0); +void gpgrt_free (void *a); + + +/* + * System specific function wrappers. + */ + +/* A getenv replacement which mallocs the returned string. */ +char *gpgrt_getenv (const char *name); + +/* A setenv and a unsetenv replacement.*/ +gpg_err_code_t gpgrt_setenv (const char *name, + const char *value, int overwrite); +#define gpgrt_unsetenv(n) gpgrt_setenv ((n), NULL, 1) + +/* A wrapper around mkdir using a string for the mode. */ +gpg_err_code_t gpgrt_mkdir (const char *name, const char *modestr); + +/* A simple wrapper around chdir. */ +gpg_err_code_t gpgrt_chdir (const char *name); + +/* Return the current WD as a malloced string. */ +char *gpgrt_getcwd (void); + +/* A wrapper around access to handle UTF-8 on Windows. */ +gpg_err_code_t gpgrt_access (const char *fname, int mode); + + + + +/* + * Lock functions. + */ + +@include:lock-obj@ + +#define GPGRT_LOCK_DEFINE(name) \ + static gpgrt_lock_t name = GPGRT_LOCK_INITIALIZER + +/* NB: If GPGRT_LOCK_DEFINE is not used, zero out the lock variable + before passing it to gpgrt_lock_init. */ +gpg_err_code_t gpgrt_lock_init (gpgrt_lock_t *lockhd); +gpg_err_code_t gpgrt_lock_lock (gpgrt_lock_t *lockhd); +gpg_err_code_t gpgrt_lock_trylock (gpgrt_lock_t *lockhd); +gpg_err_code_t gpgrt_lock_unlock (gpgrt_lock_t *lockhd); +gpg_err_code_t gpgrt_lock_destroy (gpgrt_lock_t *lockhd); + + + +/* + * Thread functions. + */ + +gpg_err_code_t gpgrt_yield (void); + + + + +/* + * Estream + */ + +/* The definition of this struct is entirely private. You must not + use it for anything. It is only here so some functions can be + implemented as macros. */ +struct _gpgrt_stream_internal; +struct _gpgrt__stream +{ + /* The layout of this struct must never change. It may be grown, + but only if all functions which access the new members are + versioned. */ + + /* Various flags. */ + struct { + unsigned int magic: 16; + unsigned int writing: 1; + unsigned int reserved: 15; + } flags; + + /* A pointer to the stream buffer. */ + unsigned char *buffer; + + /* The size of the buffer in bytes. */ + size_t buffer_size; + + /* The length of the usable data in the buffer, only valid when in + read mode (see flags). */ + size_t data_len; + + /* The current position of the offset pointer, valid in read and + write mode. */ + size_t data_offset; + + size_t data_flushed; + unsigned char *unread_buffer; + size_t unread_buffer_size; + + /* The number of unread bytes. */ + size_t unread_data_len; + + /* A pointer to our internal data for this stream. */ + struct _gpgrt_stream_internal *intern; +}; + +/* The opaque type for an estream. */ +typedef struct _gpgrt__stream *gpgrt_stream_t; +#ifdef GPGRT_ENABLE_ES_MACROS +typedef struct _gpgrt__stream *estream_t; +#endif + +typedef @api_ssize_t@ (*gpgrt_cookie_read_function_t) (void *cookie, + void *buffer, size_t size); +typedef @api_ssize_t@ (*gpgrt_cookie_write_function_t) (void *cookie, + const void *buffer, + size_t size); +typedef int (*gpgrt_cookie_seek_function_t) (void *cookie, + gpgrt_off_t *pos, int whence); +typedef int (*gpgrt_cookie_close_function_t) (void *cookie); + +struct _gpgrt_cookie_io_functions +{ + gpgrt_cookie_read_function_t func_read; + gpgrt_cookie_write_function_t func_write; + gpgrt_cookie_seek_function_t func_seek; + gpgrt_cookie_close_function_t func_close; +}; +typedef struct _gpgrt_cookie_io_functions gpgrt_cookie_io_functions_t; +#ifdef GPGRT_ENABLE_ES_MACROS +typedef struct _gpgrt_cookie_io_functions es_cookie_io_functions_t; +#define es_cookie_read_function_t gpgrt_cookie_read_function_t +#define es_cookie_write_function_t gpgrt_cookie_read_function_t +#define es_cookie_seek_function_t gpgrt_cookie_read_function_t +#define es_cookie_close_function_t gpgrt_cookie_read_function_t +#endif + +enum gpgrt_syshd_types + { + GPGRT_SYSHD_NONE = 0, /* No system handle available. */ + GPGRT_SYSHD_FD = 1, /* A file descriptor as returned by open(). */ + GPGRT_SYSHD_SOCK = 2, /* A socket as returned by socket(). */ + GPGRT_SYSHD_RVID = 3, /* A rendezvous id (see libassuan's gpgcedev.c). */ + GPGRT_SYSHD_HANDLE = 4 /* A HANDLE object (Windows). */ + }; + +struct _gpgrt_syshd +{ + enum gpgrt_syshd_types type; + union { + int fd; + int sock; + int rvid; + void *handle; + } u; +}; +typedef struct _gpgrt_syshd gpgrt_syshd_t; +#ifdef GPGRT_ENABLE_ES_MACROS +typedef struct _gpgrt_syshd es_syshd_t; +#define ES_SYSHD_NONE GPGRT_SYSHD_NONE +#define ES_SYSHD_FD GPGRT_SYSHD_FD +#define ES_SYSHD_SOCK GPGRT_SYSHD_SOCK +#define ES_SYSHD_RVID GPGRT_SYSHD_RVID +#define ES_SYSHD_HANDLE GPGRT_SYSHD_HANDLE +#endif + +/* The object used with gpgrt_poll. */ +struct _gpgrt_poll_s +{ + gpgrt_stream_t stream; + unsigned int want_read:1; + unsigned int want_write:1; + unsigned int want_oob:1; + unsigned int want_rdhup:1; + unsigned int _reserv1:4; + unsigned int got_read:1; + unsigned int got_write:1; + unsigned int got_oob:1; + unsigned int got_rdhup:1; + unsigned int _reserv2:4; + unsigned int got_err:1; + unsigned int got_hup:1; + unsigned int got_nval:1; + unsigned int _reserv3:4; + unsigned int ignore:1; + unsigned int user:8; /* For application use. */ +}; +typedef struct _gpgrt_poll_s gpgrt_poll_t; +#ifdef GPGRT_ENABLE_ES_MACROS +typedef struct _gpgrt_poll_s es_poll_t; +#endif + +/* The type of the string filter function as used by fprintf_sf et al. */ +typedef char *(*gpgrt_string_filter_t) (const char *s, int n, void *opaque); + + + +gpgrt_stream_t gpgrt_fopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode); +gpgrt_stream_t gpgrt_mopen (void *_GPGRT__RESTRICT data, + size_t data_n, size_t data_len, + unsigned int grow, + void *(*func_realloc) (void *mem, size_t size), + void (*func_free) (void *mem), + const char *_GPGRT__RESTRICT mode); +gpgrt_stream_t gpgrt_fopenmem (size_t memlimit, + const char *_GPGRT__RESTRICT mode); +gpgrt_stream_t gpgrt_fopenmem_init (size_t memlimit, + const char *_GPGRT__RESTRICT mode, + const void *data, size_t datalen); +gpgrt_stream_t gpgrt_fdopen (int filedes, const char *mode); +gpgrt_stream_t gpgrt_fdopen_nc (int filedes, const char *mode); +gpgrt_stream_t gpgrt_sysopen (gpgrt_syshd_t *syshd, const char *mode); +gpgrt_stream_t gpgrt_sysopen_nc (gpgrt_syshd_t *syshd, const char *mode); +gpgrt_stream_t gpgrt_fpopen (FILE *fp, const char *mode); +gpgrt_stream_t gpgrt_fpopen_nc (FILE *fp, const char *mode); +gpgrt_stream_t gpgrt_freopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode, + gpgrt_stream_t _GPGRT__RESTRICT stream); +gpgrt_stream_t gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie, + const char *_GPGRT__RESTRICT mode, + gpgrt_cookie_io_functions_t functions); +int gpgrt_fclose (gpgrt_stream_t stream); +int gpgrt_fcancel (gpgrt_stream_t stream); +int gpgrt_fclose_snatch (gpgrt_stream_t stream, + void **r_buffer, size_t *r_buflen); +int gpgrt_onclose (gpgrt_stream_t stream, int mode, + void (*fnc) (gpgrt_stream_t, void*), void *fnc_value); +int gpgrt_fileno (gpgrt_stream_t stream); +int gpgrt_fileno_unlocked (gpgrt_stream_t stream); +int gpgrt_syshd (gpgrt_stream_t stream, gpgrt_syshd_t *syshd); +int gpgrt_syshd_unlocked (gpgrt_stream_t stream, gpgrt_syshd_t *syshd); + +void _gpgrt_set_std_fd (int no, int fd); +gpgrt_stream_t _gpgrt_get_std_stream (int fd); + +#define gpgrt_stdin _gpgrt_get_std_stream (0) +#define gpgrt_stdout _gpgrt_get_std_stream (1) +#define gpgrt_stderr _gpgrt_get_std_stream (2) + + +void gpgrt_flockfile (gpgrt_stream_t stream); +int gpgrt_ftrylockfile (gpgrt_stream_t stream); +void gpgrt_funlockfile (gpgrt_stream_t stream); + +int gpgrt_feof (gpgrt_stream_t stream); +int gpgrt_feof_unlocked (gpgrt_stream_t stream); +int gpgrt_ferror (gpgrt_stream_t stream); +int gpgrt_ferror_unlocked (gpgrt_stream_t stream); +void gpgrt_clearerr (gpgrt_stream_t stream); +void gpgrt_clearerr_unlocked (gpgrt_stream_t stream); + +int _gpgrt_pending (gpgrt_stream_t stream); /* (private) */ +int _gpgrt_pending_unlocked (gpgrt_stream_t stream); /* (private) */ + +#define gpgrt_pending(stream) _gpgrt_pending (stream) + +#define gpgrt_pending_unlocked(stream) \ + (((!(stream)->flags.writing) \ + && (((stream)->data_offset < (stream)->data_len) \ + || ((stream)->unread_data_len))) \ + ? 1 : _gpgrt_pending_unlocked ((stream))) + +int gpgrt_fflush (gpgrt_stream_t stream); +int gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence); +int gpgrt_fseeko (gpgrt_stream_t stream, gpgrt_off_t offset, int whence); +int gpgrt_ftruncate (gpgrt_stream_t stream, gpgrt_off_t length); +long int gpgrt_ftell (gpgrt_stream_t stream); +gpgrt_off_t gpgrt_ftello (gpgrt_stream_t stream); +void gpgrt_rewind (gpgrt_stream_t stream); + +int gpgrt_fgetc (gpgrt_stream_t stream); +int gpgrt_fputc (int c, gpgrt_stream_t stream); + +int _gpgrt_getc_underflow (gpgrt_stream_t stream); /* (private) */ +int _gpgrt_putc_overflow (int c, gpgrt_stream_t stream); /* (private) */ + +#define gpgrt_getc_unlocked(stream) \ + (((!(stream)->flags.writing) \ + && ((stream)->data_offset < (stream)->data_len) \ + && (! (stream)->unread_data_len)) \ + ? ((int) (stream)->buffer[((stream)->data_offset)++]) \ + : _gpgrt_getc_underflow ((stream))) + +#define gpgrt_putc_unlocked(c, stream) \ + (((stream)->flags.writing \ + && ((stream)->data_offset < (stream)->buffer_size) \ + && (c != '\n')) \ + ? ((int) ((stream)->buffer[((stream)->data_offset)++] = (c))) \ + : _gpgrt_putc_overflow ((c), (stream))) + +#define gpgrt_getc(stream) gpgrt_fgetc (stream) +#define gpgrt_putc(c, stream) gpgrt_fputc (c, stream) + +int gpgrt_ungetc (int c, gpgrt_stream_t stream); + +int gpgrt_read (gpgrt_stream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT buffer, size_t bytes_to_read, + size_t *_GPGRT__RESTRICT bytes_read); +int gpgrt_write (gpgrt_stream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write, + size_t *_GPGRT__RESTRICT bytes_written); +int gpgrt_write_sanitized (gpgrt_stream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t length, + const char *delimiters, + size_t *_GPGRT__RESTRICT bytes_written); +int gpgrt_write_hexstring (gpgrt_stream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t length, + int reserved, + size_t *_GPGRT__RESTRICT bytes_written); + +size_t gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, + gpgrt_stream_t _GPGRT__RESTRICT stream); +size_t gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, + size_t nitems, gpgrt_stream_t _GPGRT__RESTRICT stream); + +char *gpgrt_fgets (char *_GPGRT__RESTRICT s, int n, + gpgrt_stream_t _GPGRT__RESTRICT stream); +int gpgrt_fputs (const char *_GPGRT__RESTRICT s, + gpgrt_stream_t _GPGRT__RESTRICT stream); +int gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s, + gpgrt_stream_t _GPGRT__RESTRICT stream); + +@api_ssize_t@ gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr, + size_t *_GPGRT__RESTRICT n, + gpgrt_stream_t stream); +@api_ssize_t@ gpgrt_read_line (gpgrt_stream_t stream, + char **addr_of_buffer, size_t *length_of_buffer, + size_t *max_length); + +int gpgrt_fprintf (gpgrt_stream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(2,3); +int gpgrt_fprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(2,3); + +int gpgrt_fprintf_sf (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, + ...) GPGRT_ATTR_PRINTF(4,5); +int gpgrt_fprintf_sf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, + ...) GPGRT_ATTR_PRINTF(4,5); + +int gpgrt_printf (const char *_GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(1,2); +int gpgrt_printf_unlocked (const char *_GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(1,2); + +int gpgrt_vfprintf (gpgrt_stream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, va_list ap) + GPGRT_ATTR_PRINTF(2,0); +int gpgrt_vfprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, va_list ap) + GPGRT_ATTR_PRINTF(2,0); + +int gpgrt_setvbuf (gpgrt_stream_t _GPGRT__RESTRICT stream, + char *_GPGRT__RESTRICT buf, int mode, size_t size); +void gpgrt_setbuf (gpgrt_stream_t _GPGRT__RESTRICT stream, + char *_GPGRT__RESTRICT buf); + +void gpgrt_set_binary (gpgrt_stream_t stream); +int gpgrt_set_nonblock (gpgrt_stream_t stream, int onoff); +int gpgrt_get_nonblock (gpgrt_stream_t stream); + +int gpgrt_poll (gpgrt_poll_t *fdlist, unsigned int nfds, int timeout); + +gpgrt_stream_t gpgrt_tmpfile (void); + +void gpgrt_opaque_set (gpgrt_stream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT opaque); +void *gpgrt_opaque_get (gpgrt_stream_t stream); + +void gpgrt_fname_set (gpgrt_stream_t stream, const char *fname); +const char *gpgrt_fname_get (gpgrt_stream_t stream); + +int gpgrt_asprintf (char **r_buf, const char * _GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(2,3); +int gpgrt_vasprintf (char **r_buf, const char * _GPGRT__RESTRICT format, + va_list ap) + GPGRT_ATTR_PRINTF(2,0); +char *gpgrt_bsprintf (const char * _GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(1,2); +char *gpgrt_vbsprintf (const char * _GPGRT__RESTRICT format, va_list ap) + GPGRT_ATTR_PRINTF(1,0); +int gpgrt_snprintf (char *buf, size_t bufsize, + const char * _GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(3,4); +int gpgrt_vsnprintf (char *buf,size_t bufsize, + const char * _GPGRT__RESTRICT format, va_list arg_ptr) + GPGRT_ATTR_PRINTF(3,0); + + +#ifdef GPGRT_ENABLE_ES_MACROS +# define es_fopen gpgrt_fopen +# define es_mopen gpgrt_mopen +# define es_fopenmem gpgrt_fopenmem +# define es_fopenmem_init gpgrt_fopenmem_init +# define es_fdopen gpgrt_fdopen +# define es_fdopen_nc gpgrt_fdopen_nc +# define es_sysopen gpgrt_sysopen +# define es_sysopen_nc gpgrt_sysopen_nc +# define es_fpopen gpgrt_fpopen +# define es_fpopen_nc gpgrt_fpopen_nc +# define es_freopen gpgrt_freopen +# define es_fopencookie gpgrt_fopencookie +# define es_fclose gpgrt_fclose +# define es_fclose_snatch gpgrt_fclose_snatch +# define es_onclose gpgrt_onclose +# define es_fileno gpgrt_fileno +# define es_fileno_unlocked gpgrt_fileno_unlocked +# define es_syshd gpgrt_syshd +# define es_syshd_unlocked gpgrt_syshd_unlocked +# define es_stdin _gpgrt_get_std_stream (0) +# define es_stdout _gpgrt_get_std_stream (1) +# define es_stderr _gpgrt_get_std_stream (2) +# define es_flockfile gpgrt_flockfile +# define es_ftrylockfile gpgrt_ftrylockfile +# define es_funlockfile gpgrt_funlockfile +# define es_feof gpgrt_feof +# define es_feof_unlocked gpgrt_feof_unlocked +# define es_ferror gpgrt_ferror +# define es_ferror_unlocked gpgrt_ferror_unlocked +# define es_clearerr gpgrt_clearerr +# define es_clearerr_unlocked gpgrt_clearerr_unlocked +# define es_pending gpgrt_pending +# define es_pending_unlocked gpgrt_pending_unlocked +# define es_fflush gpgrt_fflush +# define es_fseek gpgrt_fseek +# define es_fseeko gpgrt_fseeko +# define es_ftruncate gpgrt_ftruncate +# define es_ftell gpgrt_ftell +# define es_ftello gpgrt_ftello +# define es_rewind gpgrt_rewind +# define es_fgetc gpgrt_fgetc +# define es_fputc gpgrt_fputc +# define es_getc_unlocked gpgrt_getc_unlocked +# define es_putc_unlocked gpgrt_putc_unlocked +# define es_getc gpgrt_getc +# define es_putc gpgrt_putc +# define es_ungetc gpgrt_ungetc +# define es_read gpgrt_read +# define es_write gpgrt_write +# define es_write_sanitized gpgrt_write_sanitized +# define es_write_hexstring gpgrt_write_hexstring +# define es_fread gpgrt_fread +# define es_fwrite gpgrt_fwrite +# define es_fgets gpgrt_fgets +# define es_fputs gpgrt_fputs +# define es_fputs_unlocked gpgrt_fputs_unlocked +# define es_getline gpgrt_getline +# define es_read_line gpgrt_read_line +# define es_free gpgrt_free +# define es_fprintf gpgrt_fprintf +# define es_fprintf_unlocked gpgrt_fprintf_unlocked +# define es_printf gpgrt_printf +# define es_printf_unlocked gpgrt_printf_unlocked +# define es_vfprintf gpgrt_vfprintf +# define es_vfprintf_unlocked gpgrt_vfprintf_unlocked +# define es_setvbuf gpgrt_setvbuf +# define es_setbuf gpgrt_setbuf +# define es_set_binary gpgrt_set_binary +# define es_set_nonblock gpgrt_set_nonblock +# define es_get_nonblock gpgrt_get_nonblock +# define es_poll gpgrt_poll +# define es_tmpfile gpgrt_tmpfile +# define es_opaque_set gpgrt_opaque_set +# define es_opaque_get gpgrt_opaque_get +# define es_fname_set gpgrt_fname_set +# define es_fname_get gpgrt_fname_get +# define es_asprintf gpgrt_asprintf +# define es_vasprintf gpgrt_vasprintf +# define es_bsprintf gpgrt_bsprintf +# define es_vbsprintf gpgrt_vbsprintf +#endif /*GPGRT_ENABLE_ES_MACROS*/ + + + +/* + * Base64 encode and decode functions. + */ + +struct _gpgrt_b64state; +typedef struct _gpgrt_b64state *gpgrt_b64state_t; + +gpgrt_b64state_t gpgrt_b64enc_start (gpgrt_stream_t stream, const char *title); +gpg_err_code_t gpgrt_b64enc_write (gpgrt_b64state_t state, + const void *buffer, size_t nbytes); +gpg_err_code_t gpgrt_b64enc_finish (gpgrt_b64state_t state); + +gpgrt_b64state_t gpgrt_b64dec_start (const char *title); +gpg_error_t gpgrt_b64dec_proc (gpgrt_b64state_t state, + void *buffer, size_t length, + size_t *r_nbytes); +gpg_error_t gpgrt_b64dec_finish (gpgrt_b64state_t state); + + + +/* + * Logging functions + */ + +/* Flag values for gpgrt_log_set_prefix. */ +#define GPGRT_LOG_WITH_PREFIX 1 +#define GPGRT_LOG_WITH_TIME 2 +#define GPGRT_LOG_WITH_PID 4 +#define GPGRT_LOG_RUN_DETACHED 256 +#define GPGRT_LOG_NO_REGISTRY 512 + +/* Log levels as used by gpgrt_log. */ +enum gpgrt_log_levels + { + GPGRT_LOGLVL_BEGIN, + GPGRT_LOGLVL_CONT, + GPGRT_LOGLVL_INFO, + GPGRT_LOGLVL_WARN, + GPGRT_LOGLVL_ERROR, + GPGRT_LOGLVL_FATAL, + GPGRT_LOGLVL_BUG, + GPGRT_LOGLVL_DEBUG + }; + + +/* The next 4 functions are not thread-safe - call them early. */ +void gpgrt_log_set_sink (const char *name, gpgrt_stream_t stream, int fd); +void gpgrt_log_set_socket_dir_cb (const char *(*fnc)(void)); +void gpgrt_log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)); +void gpgrt_log_set_prefix (const char *text, unsigned int flags); + +int gpgrt_get_errorcount (int clear); +void gpgrt_inc_errorcount (void); +const char *gpgrt_log_get_prefix (unsigned int *flags); +int gpgrt_log_test_fd (int fd); +int gpgrt_log_get_fd (void); +gpgrt_stream_t gpgrt_log_get_stream (void); + +void gpgrt_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3); +void gpgrt_logv (int level, const char *fmt, va_list arg_ptr); +void gpgrt_logv_prefix (int level, const char *prefix, + const char *fmt, va_list arg_ptr); +void gpgrt_log_string (int level, const char *string); +void gpgrt_log_bug (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); +void gpgrt_log_fatal (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); +void gpgrt_log_error (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void gpgrt_log_info (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void gpgrt_log_debug (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void gpgrt_log_debug_string (const char *string, + const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3); +void gpgrt_log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void gpgrt_log_printhex (const void *buffer, size_t length, + const char *fmt, ...) GPGRT_ATTR_PRINTF(3,4); +void gpgrt_log_clock (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void gpgrt_log_flush (void); +void _gpgrt_log_assert (const char *expr, const char *file, int line, + const char *func) GPGRT_ATTR_NORETURN; + +#ifdef GPGRT_HAVE_MACRO_FUNCTION +# define gpgrt_assert(expr) \ + ((expr) \ + ? (void) 0 \ + : _gpgrt_log_assert (#expr, __FILE__, __LINE__, __FUNCTION__)) +#else /*!GPGRT_HAVE_MACRO_FUNCTION*/ +# define gpgrt_assert(expr) \ + ((expr) \ + ? (void) 0 \ + : _gpgrt_log_assert (#expr, __FILE__, __LINE__, NULL)) +#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + +#ifdef GPGRT_ENABLE_LOG_MACROS +# define log_get_errorcount gpgrt_get_errorcount +# define log_inc_errorcount gpgrt_inc_errorcount +# define log_set_file(a) gpgrt_log_set_sink ((a), NULL, -1) +# define log_set_fd(a) gpgrt_log_set_sink (NULL, NULL, (a)) +# define log_set_stream(a) gpgrt_log_set_sink (NULL, (a), -1) +# define log_set_socket_dir_cb gpgrt_log_set_socket_dir_cb +# define log_set_pid_suffix_cb gpgrt_log_set_pid_suffix_cb +# define log_set_prefix gpgrt_log_set_prefix +# define log_get_prefix gpgrt_log_get_prefix +# define log_test_fd gpgrt_log_test_fd +# define log_get_fd gpgrt_log_get_fd +# define log_get_stream gpgrt_log_get_stream +# define log_log gpgrt_log +# define log_logv gpgrt_logv +# define log_logv_prefix gpgrt_logv_prefix +# define log_string gpgrt_log_string +# define log_bug gpgrt_log_bug +# define log_fatal gpgrt_log_fatal +# define log_error gpgrt_log_error +# define log_info gpgrt_log_info +# define log_debug gpgrt_log_debug +# define log_debug_string gpgrt_log_debug_string +# define log_printf gpgrt_log_printf +# define log_printhex gpgrt_log_printhex +# define log_clock gpgrt_log_clock +# define log_flush gpgrt_log_flush +# ifdef GPGRT_HAVE_MACRO_FUNCTION +# define log_assert(expr) \ + ((expr) \ + ? (void) 0 \ + : _gpgrt_log_assert (#expr, __FILE__, __LINE__, __FUNCTION__)) +# else /*!GPGRT_HAVE_MACRO_FUNCTION*/ +# define log_assert(expr) \ + ((expr) \ + ? (void) 0 \ + : _gpgrt_log_assert (#expr, __FILE__, __LINE__, NULL)) +# endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + +#endif /*GPGRT_ENABLE_LOG_MACROS*/ + + +/* + * Spawn functions (Not yet available) + */ +#define GPGRT_SPAWN_NONBLOCK 16 /* Set the streams to non-blocking. */ +#define GPGRT_SPAWN_RUN_ASFW 64 /* Use AllowSetForegroundWindow on W32. */ +#define GPGRT_SPAWN_DETACHED 128 /* Start the process in the background. */ + +#if 0 + +/* Function and convenience macros to create pipes. */ +gpg_err_code_t gpgrt_make_pipe (int filedes[2], gpgrt_stream_t *r_fp, + int direction, int nonblock); +#define gpgrt_create_pipe(a) gpgrt_make_pipe ((a),NULL, 0, 0); +#define gpgrt_create_inbound_pipe(a,b,c) gpgrt_make_pipe ((a), (b), -1,(c)); +#define gpgrt_create_outbound_pipe(a,b,c) gpgrt_make_pipe ((a), (b), 1,(c)); + + +/* Fork and exec PGMNAME. */ +gpg_err_code_t gpgrt_spawn_process (const char *pgmname, const char *argv[], + int *execpt, void (*preexec)(void), + unsigned int flags, + gpgrt_stream_t *r_infp, + gpgrt_stream_t *r_outfp, + gpgrt_stream_t *r_errfp, + pid_t *pid); + +/* Fork and exec PGNNAME and connect the process to the given FDs. */ +gpg_err_code_t gpgrt_spawn_process_fd (const char *pgmname, const char *argv[], + int infd, int outfd, int errfd, + pid_t *pid); + +/* Fork and exec PGMNAME as a detached process. */ +gpg_err_code_t gpgrt_spawn_process_detached (const char *pgmname, + const char *argv[], + const char *envp[] ); + +/* Wait for a single process. */ +gpg_err_code_t gpgrt_wait_process (const char *pgmname, pid_t pid, int hang, + int *r_exitcode); + +/* Wait for a multiple processes. */ +gpg_err_code_t gpgrt_wait_processes (const char **pgmnames, pid_t *pids, + size_t count, int hang, int *r_exitcodes); + +/* Kill the process identified by PID. */ +void gpgrt_kill_process (pid_t pid); + +/* Release process resources identified by PID. */ +void gpgrt_release_process (pid_t pid); + +#endif /*0*/ + + + +/* + * Option parsing. + */ + +struct _gpgrt_argparse_internal_s; +typedef struct +{ + int *argc; /* Pointer to ARGC (value subject to change). */ + char ***argv; /* Pointer to ARGV (value subject to change). */ + unsigned int flags; /* Global flags. May be set prior to calling the + parser. The parser may change the value. */ + int err; /* Print error description for last option. + Either 0, ARGPARSE_PRINT_WARNING or + ARGPARSE_PRINT_ERROR. */ + unsigned int lineno;/* The current line number. */ + int r_opt; /* Returns option code. */ + int r_type; /* Returns type of option value. */ + union { + int ret_int; + long ret_long; + unsigned long ret_ulong; + char *ret_str; + } r; /* Return values */ + + struct _gpgrt_argparse_internal_s *internal; +} gpgrt_argparse_t; + + +typedef struct +{ + int short_opt; + const char *long_opt; + unsigned int flags; + const char *description; /* Optional description. */ +} gpgrt_opt_t; + + +#ifdef GPGRT_ENABLE_ARGPARSE_MACROS + +/* Global flags for (gpgrt_argparse_t).flags. */ +#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */ +#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return + remaining args with R_OPT set to -1. */ +#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */ +#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */ +#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */ +#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */ +#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */ +#define ARGPARSE_FLAG_RESET 128 /* Request to reset the internal state. */ +#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */ +#define ARGPARSE_FLAG_NOLINENO 512 /* Do not zero the lineno field. */ +#define ARGPARSE_FLAG_SYS 1024 /* Use system config file. */ +#define ARGPARSE_FLAG_USER 2048 /* Use user config file. */ +#define ARGPARSE_FLAG_VERBOSE 4096 /* Print additional argparser info. */ +#define ARGPARSE_FLAG_USERVERS 8192 /* Try version-ed user config files. */ +#define ARGPARSE_FLAG_WITHATTR 16384 /* Return attribute bits. */ + +/* Constants for (gpgrt_argparse_t).err. */ +#define ARGPARSE_PRINT_WARNING 1 /* Print a diagnostic. */ +#define ARGPARSE_PRINT_ERROR 2 /* Print a diagnostic and call exit. */ + +/* Special return values of gpgrt_argparse. */ +#define ARGPARSE_IS_ARG (-1) +#define ARGPARSE_INVALID_OPTION (-2) +#define ARGPARSE_MISSING_ARG (-3) +#define ARGPARSE_KEYWORD_TOO_LONG (-4) +#define ARGPARSE_READ_ERROR (-5) +#define ARGPARSE_UNEXPECTED_ARG (-6) +#define ARGPARSE_INVALID_COMMAND (-7) +#define ARGPARSE_AMBIGUOUS_OPTION (-8) +#define ARGPARSE_AMBIGUOUS_COMMAND (-9) +#define ARGPARSE_INVALID_ALIAS (-10) +#define ARGPARSE_OUT_OF_CORE (-11) +#define ARGPARSE_INVALID_ARG (-12) +#define ARGPARSE_PERMISSION_ERROR (-13) +#define ARGPARSE_NO_CONFFILE (-14) +#define ARGPARSE_CONFFILE (-15) +#define ARGPARSE_INVALID_META (-16) +#define ARGPARSE_UNKNOWN_META (-17) +#define ARGPARSE_UNEXPECTED_META (-18) + +/* Flags for the option descriptor (gpgrt_opt_t)->flags. Note that a + * TYPE constant may be or-ed with the OPT constants but when used as + * return value in r_type these OPT constants are normally not + * included. However with ARGPARSE_FLAG_WITHATTR used and an option + * would normally not be returned, it is returned but + * ARGPARSE_OPT_IGNORE is then set; further ARPARSE_ATTR_* are set. + */ +#define ARGPARSE_TYPE_MASK 0x0007 /* Mask for the type bits. */ +#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */ +#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */ +#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */ +#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */ +#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */ +#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */ +#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */ +#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */ +#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */ +#define ARGPARSE_OPT_CONFFILE (1<<8) /* The value is a conffile. */ +#define ARGPARSE_OPT_HEADER (1<<9) /* The value is printed as a header. */ +#define ARGPARSE_OPT_VERBATIM (1<<10)/* The value is printed verbatim. */ +#define ARGPARSE_ATTR_FORCE (1<<14)/* Attribute force is set. */ +#define ARGPARSE_ATTR_IGNORE (1<<15)/* Attribute ignore is set. */ + +/* A set of macros to make option definitions easier to read. */ +#define ARGPARSE_x(s,l,t,f,d) \ + { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) } + +#define ARGPARSE_s(s,l,t,d) \ + { (s), (l), ARGPARSE_TYPE_ ## t, (d) } +#define ARGPARSE_s_n(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_NONE, (d) } +#define ARGPARSE_s_i(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_INT, (d) } +#define ARGPARSE_s_s(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_STRING, (d) } +#define ARGPARSE_s_l(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_LONG, (d) } +#define ARGPARSE_s_u(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_ULONG, (d) } + +#define ARGPARSE_o(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) } + +#define ARGPARSE_p(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) } + +#define ARGPARSE_op(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } + +#define ARGPARSE_c(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) } + +#define ARGPARSE_conffile(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING|ARGPARSE_OPT_CONFFILE), (d) } + +#define ARGPARSE_noconffile(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE|ARGPARSE_OPT_CONFFILE), (d) } + +/* This macro is for stub or obsolete options. */ +#define ARGPARSE_ignore(s,l) \ + { (s), (l), (ARGPARSE_OPT_IGNORE), "@" } + +/* This is a legacy version of ARGPARSE_verbatim which really does + * verbatim printing. */ +#define ARGPARSE_group(s,d) \ + { (s), NULL, 0, (d) } + +/* Verbatim print the string D in the help output. It does not make + * use of the "@" hack as ARGPARSE_group does. */ +#define ARGPARSE_verbatim(d) \ + { 1, NULL, (ARGPARSE_OPT_VERBATIM), (d) } + +/* Same as ARGPARSE_verbatim but also print a colon and a LF. N can + * be used give a symbolic name to the header. Nothing is printed if + * D is the empty string. */ +#define ARGPARSE_header(n,d) \ + { 1, (n), (ARGPARSE_OPT_HEADER), (d) } + +/* Mark the end of the list (mandatory). */ +#define ARGPARSE_end() \ + { 0, NULL, 0, NULL } + +#endif /* GPGRT_ENABLE_ARGPARSE_MACROS */ + +/* Values used for gpgrt_set_confdir. */ +#define GPGRT_CONFDIR_USER 1 /* The user's configuration dir. */ +#define GPGRT_CONFDIR_SYS 2 /* The systems's configuration dir. */ + +/* Take care: gpgrt_argparse keeps state in ARG and requires that + * either ARGPARSE_FLAG_RESET is used after OPTS has been changed or + * gpgrt_argparse (NULL, ARG, NULL) is called first. */ +int gpgrt_argparse (gpgrt_stream_t fp, + gpgrt_argparse_t *arg, gpgrt_opt_t *opts); +int gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, + const char *confname); +void gpgrt_usage (int level); +const char *gpgrt_strusage (int level); +void gpgrt_set_strusage (const char *(*f)(int)); +void gpgrt_set_usage_outfnc (int (*f)(int, const char *)); +void gpgrt_set_fixed_string_mapper (const char *(*f)(const char*)); +void gpgrt_set_confdir (int what, const char *name); + + +/* + * Various helper functions + */ + +/* Compare arbitrary version strings. For the standard m.n.o version + * numbering scheme a LEVEL of 3 is suitable; see the manual. */ +int gpgrt_cmp_version (const char *a, const char *b, int level); + +/* Construct a filename from the NULL terminated list of parts. Tilde + * expansion is done for the first argument. The caller must release + * the result using gpgrt_free; on error ERRNO is set and NULL + * returned. The second function returns an absolute filename. */ +char *gpgrt_fnameconcat (const char *first, ...) GPGRT_ATTR_SENTINEL(0); +char *gpgrt_absfnameconcat (const char *first, ...) GPGRT_ATTR_SENTINEL(0); + + +#ifdef __cplusplus +} +#endif +#endif /* GPGRT_H */ +#endif /* GPG_ERROR_H */ diff --git a/comm/third_party/libgpg-error/src/gpg-error.m4 b/comm/third_party/libgpg-error/src/gpg-error.m4 new file mode 100644 index 0000000000..d910754e8d --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.m4 @@ -0,0 +1,206 @@ +# gpg-error.m4 - autoconf macro to detect libgpg-error. +# Copyright (C) 2002, 2003, 2004, 2011, 2014, 2018, 2020, 2021 +# g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Last-changed: 2021-02-16 + + +dnl AM_PATH_GPG_ERROR([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl +dnl Test for libgpg-error and define GPG_ERROR_CFLAGS, GPG_ERROR_LIBS, +dnl GPG_ERROR_MT_CFLAGS, and GPG_ERROR_MT_LIBS. The _MT_ variants are +dnl used for programs requireing real multi thread support. +dnl +dnl If a prefix option is not used, the config script is first +dnl searched in $SYSROOT/bin and then along $PATH. If the used +dnl config script does not match the host specification the script +dnl is added to the gpg_config_script_warn variable. +dnl +AC_DEFUN([AM_PATH_GPG_ERROR], +[ AC_REQUIRE([AC_CANONICAL_HOST]) + gpg_error_config_prefix="" + dnl --with-libgpg-error-prefix=PFX is the preferred name for this option, + dnl since that is consistent with how our three siblings use the directory/ + dnl package name in --with-$dir_name-prefix=PFX. + AC_ARG_WITH(libgpg-error-prefix, + AS_HELP_STRING([--with-libgpg-error-prefix=PFX], + [prefix where GPG Error is installed (optional)]), + [gpg_error_config_prefix="$withval"]) + + dnl Accept --with-gpg-error-prefix and make it work the same as + dnl --with-libgpg-error-prefix above, for backwards compatibility, + dnl but do not document this old, inconsistently-named option. + AC_ARG_WITH(gpg-error-prefix,, + [gpg_error_config_prefix="$withval"]) + + if test x"${GPG_ERROR_CONFIG}" = x ; then + if test x"${gpg_error_config_prefix}" != x ; then + GPG_ERROR_CONFIG="${gpg_error_config_prefix}/bin/gpg-error-config" + else + case "${SYSROOT}" in + /*) + if test -x "${SYSROOT}/bin/gpg-error-config" ; then + GPG_ERROR_CONFIG="${SYSROOT}/bin/gpg-error-config" + fi + ;; + '') + ;; + *) + AC_MSG_WARN([Ignoring \$SYSROOT as it is not an absolute path.]) + ;; + esac + fi + fi + + AC_PATH_PROG(GPG_ERROR_CONFIG, gpg-error-config, no) + min_gpg_error_version=ifelse([$1], ,1.33,$1) + ok=no + + AC_PATH_PROG(GPGRT_CONFIG, gpgrt-config, no) + if test "$GPGRT_CONFIG" != "no"; then + # Determine gpgrt_libdir + # + # Get the prefix of gpgrt-config assuming it's something like: + # /bin/gpgrt-config + gpgrt_prefix=${GPGRT_CONFIG%/*/*} + possible_libdir1=${gpgrt_prefix}/lib + # Determine by using system libdir-format with CC, it's like: + # Normal style: /usr/lib + # GNU cross style: /usr//lib + # Debian style: /usr/lib/ + # Fedora/openSUSE style: /usr/lib, /usr/lib32 or /usr/lib64 + # It is assumed that CC is specified to the one of host on cross build. + if libdir_candidates=$(${CC:-cc} -print-search-dirs | \ + sed -n -e "/^libraries/{s/libraries: =//;s/:/\n/gp}"); then + # From the output of -print-search-dirs, select valid pkgconfig dirs. + libdir_candidates=$(for dir in $libdir_candidates; do + if p=$(cd $dir 2>/dev/null && pwd); then + test -d "$p/pkgconfig" && echo $p; + fi + done) + + for possible_libdir0 in $libdir_candidates; do + # possible_libdir0: + # Fallback candidate, the one of system-installed (by $CC) + # (/usr//lib, /usr/lib/ or /usr/lib32) + # possible_libdir1: + # Another candidate, user-locally-installed + # (/lib) + # possible_libdir2 + # Most preferred + # (//lib, + # /lib/ or /lib32) + if test "${possible_libdir0##*/}" = "lib"; then + possible_prefix0=${possible_libdir0%/lib} + possible_prefix0_triplet=${possible_prefix0##*/} + if test -z "$possible_prefix0_triplet"; then + continue + fi + possible_libdir2=${gpgrt_prefix}/$possible_prefix0_triplet/lib + else + possible_prefix0=${possible_libdir0%%/lib*} + possible_libdir2=${gpgrt_prefix}${possible_libdir0#$possible_prefix0} + fi + if test -f ${possible_libdir2}/pkgconfig/gpg-error.pc; then + gpgrt_libdir=${possible_libdir2} + elif test -f ${possible_libdir1}/pkgconfig/gpg-error.pc; then + gpgrt_libdir=${possible_libdir1} + elif test -f ${possible_libdir0}/pkgconfig/gpg-error.pc; then + gpgrt_libdir=${possible_libdir0} + fi + if test -n "$gpgrt_libdir"; then break; fi + done + else + # When we cannot determine system libdir-format, use this: + gpgrt_libdir=${possible_libdir1} + fi + else + unset GPGRT_CONFIG + fi + + if test -n "$gpgrt_libdir"; then + GPGRT_CONFIG="$GPGRT_CONFIG --libdir=$gpgrt_libdir" + if $GPGRT_CONFIG gpg-error >/dev/null 2>&1; then + GPG_ERROR_CONFIG="$GPGRT_CONFIG gpg-error" + AC_MSG_NOTICE([Use gpgrt-config with $gpgrt_libdir as gpg-error-config]) + gpg_error_config_version=`$GPG_ERROR_CONFIG --modversion` + else + unset GPGRT_CONFIG + fi + elif test "$GPG_ERROR_CONFIG" != "no"; then + gpg_error_config_version=`$GPG_ERROR_CONFIG --version` + fi + if test "$GPG_ERROR_CONFIG" != "no"; then + req_major=`echo $min_gpg_error_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpg_error_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + major=`echo $gpg_error_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $gpg_error_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -ge "$req_minor"; then + ok=yes + fi + fi + fi + fi + AC_MSG_CHECKING(for GPG Error - version >= $min_gpg_error_version) + if test $ok = yes; then + GPG_ERROR_CFLAGS=`$GPG_ERROR_CONFIG --cflags` + GPG_ERROR_LIBS=`$GPG_ERROR_CONFIG --libs` + if test -z "$GPGRT_CONFIG"; then + GPG_ERROR_MT_CFLAGS=`$GPG_ERROR_CONFIG --mt --cflags 2>/dev/null` + GPG_ERROR_MT_LIBS=`$GPG_ERROR_CONFIG --mt --libs 2>/dev/null` + else + GPG_ERROR_MT_CFLAGS=`$GPG_ERROR_CONFIG --variable=mtcflags 2>/dev/null` + GPG_ERROR_MT_CFLAGS="$GPG_ERROR_CFLAGS${GPG_ERROR_CFLAGS:+ }$GPG_ERROR_MT_CFLAGS" + GPG_ERROR_MT_LIBS=`$GPG_ERROR_CONFIG --variable=mtlibs 2>/dev/null` + GPG_ERROR_MT_LIBS="$GPG_ERROR_LIBS${GPG_ERROR_LIBS:+ }$GPG_ERROR_MT_LIBS" + fi + AC_MSG_RESULT([yes ($gpg_error_config_version)]) + ifelse([$2], , :, [$2]) + if test -z "$GPGRT_CONFIG"; then + gpg_error_config_host=`$GPG_ERROR_CONFIG --host 2>/dev/null || echo none` + else + gpg_error_config_host=`$GPG_ERROR_CONFIG --variable=host 2>/dev/null || echo none` + fi + if test x"$gpg_error_config_host" != xnone ; then + if test x"$gpg_error_config_host" != x"$host" ; then + AC_MSG_WARN([[ +*** +*** The config script "$GPG_ERROR_CONFIG" was +*** built for $gpg_error_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-libgpg-error-prefix +*** to specify a matching config script or use \$SYSROOT. +***]]) + gpg_config_script_warn="$gpg_config_script_warn libgpg-error" + fi + fi + else + GPG_ERROR_CFLAGS="" + GPG_ERROR_LIBS="" + GPG_ERROR_MT_CFLAGS="" + GPG_ERROR_MT_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPG_ERROR_CFLAGS) + AC_SUBST(GPG_ERROR_LIBS) + AC_SUBST(GPG_ERROR_MT_CFLAGS) + AC_SUBST(GPG_ERROR_MT_LIBS) +]) diff --git a/comm/third_party/libgpg-error/src/gpg-error.pc.in b/comm/third_party/libgpg-error/src/gpg-error.pc.in new file mode 100644 index 0000000000..970bb6c31e --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.pc.in @@ -0,0 +1,15 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ +host=@GPG_ERROR_CONFIG_HOST@ +mtcflags=@GPG_ERROR_CONFIG_MT_CFLAGS@ +mtlibs=@GPG_ERROR_CONFIG_MT_LIBS@ + +Name: gpg-error +Description: GPG Runtime +Version: @PACKAGE_VERSION@ +Cflags: @GPG_ERROR_CONFIG_CFLAGS@ +Libs: @GPG_ERROR_CONFIG_LIBS@ +Libs.private: @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +URL: https://www.gnupg.org/software/libgpg-error/index.html diff --git a/comm/third_party/libgpg-error/src/gpg-error.vers b/comm/third_party/libgpg-error/src/gpg-error.vers new file mode 100644 index 0000000000..aaea22a968 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.vers @@ -0,0 +1,213 @@ +# libgpg-error.vers - What symbols to export -*- std -*- +# Copyright (C) 2014 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +# SPDX-License-Identifier: LGPL-2.1+ +# +# NOTE: When adding new functions, please make sure to add them to +# visibility.h and gpg-error.def.in as well. + + +GPG_ERROR_1.0 { + global: + gpg_strerror; + gpg_strerror_r; + gpg_strsource; + gpg_err_code_from_errno; + gpg_err_code_to_errno; + gpg_err_code_from_syserror; + gpg_err_set_errno; + gpg_error_check_version; + + gpgrt_lock_init; + gpgrt_lock_lock; + gpgrt_lock_unlock; + gpgrt_lock_destroy; + gpgrt_yield; + gpgrt_lock_trylock; + + gpgrt_set_syscall_clamp; + gpgrt_get_syscall_clamp; + + gpgrt_fopen; + gpgrt_mopen; + gpgrt_fopenmem; + gpgrt_fopenmem_init; + gpgrt_fdopen; + gpgrt_fdopen_nc; + gpgrt_sysopen; + gpgrt_sysopen_nc; + gpgrt_fpopen; + gpgrt_fpopen_nc; + gpgrt_freopen; + gpgrt_fopencookie; + gpgrt_fclose; + gpgrt_fcancel; + gpgrt_fclose_snatch; + gpgrt_onclose; + gpgrt_fileno; + gpgrt_fileno_unlocked; + gpgrt_syshd; + gpgrt_syshd_unlocked; + _gpgrt_set_std_fd; + _gpgrt_get_std_stream; + gpgrt_flockfile; + gpgrt_ftrylockfile; + gpgrt_funlockfile; + _gpgrt_pending; + _gpgrt_pending_unlocked; + gpgrt_feof; + gpgrt_feof_unlocked; + gpgrt_ferror; + gpgrt_ferror_unlocked; + gpgrt_clearerr; + gpgrt_clearerr_unlocked; + gpgrt_fflush; + gpgrt_fseek; + gpgrt_fseeko; + gpgrt_ftell; + gpgrt_ftello; + gpgrt_rewind; + gpgrt_fgetc; + _gpgrt_getc_underflow; + gpgrt_fputc; + _gpgrt_putc_overflow; + gpgrt_ungetc; + gpgrt_read; + gpgrt_write; + gpgrt_write_sanitized; + gpgrt_write_hexstring; + gpgrt_fread; + gpgrt_fwrite; + gpgrt_fgets; + gpgrt_fputs; + gpgrt_fputs_unlocked; + gpgrt_getline; + gpgrt_read_line; + gpgrt_free; + gpgrt_fprintf; + gpgrt_fprintf_unlocked; + gpgrt_printf; + gpgrt_printf_unlocked; + gpgrt_vfprintf; + gpgrt_vfprintf_unlocked; + gpgrt_setvbuf; + gpgrt_setbuf; + gpgrt_set_binary; + gpgrt_set_nonblock; + gpgrt_get_nonblock; + gpgrt_poll; + gpgrt_tmpfile; + gpgrt_opaque_set; + gpgrt_opaque_get; + gpgrt_fname_set; + gpgrt_fname_get; + + gpgrt_asprintf; + gpgrt_vasprintf; + gpgrt_bsprintf; + gpgrt_vbsprintf; + gpgrt_snprintf; + gpgrt_vsnprintf; + + gpgrt_check_version; + gpg_err_init; + gpg_err_deinit; + gpgrt_set_alloc_func; + + gpgrt_b64dec_start; + gpgrt_b64dec_proc; + gpgrt_b64dec_finish; + + gpgrt_get_errorcount; + gpgrt_inc_errorcount; + gpgrt_log_set_sink; + gpgrt_log_set_socket_dir_cb; + gpgrt_log_set_pid_suffix_cb; + gpgrt_log_set_prefix; + gpgrt_log_get_prefix; + gpgrt_log_test_fd; + gpgrt_log_get_fd; + gpgrt_log_get_stream; + gpgrt_log; + gpgrt_logv; + gpgrt_logv_prefix; + gpgrt_log_string; + gpgrt_log_bug; + gpgrt_log_fatal; + gpgrt_log_error; + gpgrt_log_info; + gpgrt_log_debug; + gpgrt_log_debug_string; + gpgrt_log_printf; + gpgrt_log_printhex; + gpgrt_log_clock; + gpgrt_log_flush; + _gpgrt_log_assert; + + gpgrt_realloc; + gpgrt_reallocarray; + gpgrt_malloc; + gpgrt_calloc; + gpgrt_strdup; + gpgrt_strconcat; + + gpgrt_getenv; + gpgrt_setenv; + gpgrt_mkdir; + gpgrt_chdir; + gpgrt_getcwd; + +## API not yet finished for: +# gpgrt_make_pipe; +# gpgrt_spawn_process; +# gpgrt_spawn_process_fd; +# gpgrt_spawn_process_detached; +# gpgrt_wait_process; +# gpgrt_wait_processes; +# gpgrt_kill_process; +# gpgrt_release_process; + + gpgrt_argparse; + gpgrt_argparser; + gpgrt_usage; + gpgrt_strusage; + gpgrt_set_strusage; + gpgrt_set_usage_outfnc; + gpgrt_set_fixed_string_mapper; + gpgrt_set_confdir; + + gpgrt_b64enc_start; + gpgrt_b64enc_write; + gpgrt_b64enc_finish; + + gpgrt_cmp_version; + + gpgrt_ftruncate; + gpgrt_fprintf_sf; + gpgrt_fprintf_sf_unlocked; + + gpgrt_add_emergency_cleanup; + gpgrt_abort; + + gpgrt_fnameconcat; + gpgrt_absfnameconcat; + + gpgrt_access; + + local: + *; +}; diff --git a/comm/third_party/libgpg-error/src/gpg-error.w32-manifest.in b/comm/third_party/libgpg-error/src/gpg-error.w32-manifest.in new file mode 100644 index 0000000000..07f6891b45 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpg-error.w32-manifest.in @@ -0,0 +1,17 @@ + + +Error codes and shared functions for GnuPG and others + + + + + + + + + + diff --git a/comm/third_party/libgpg-error/src/gpgrt-config b/comm/third_party/libgpg-error/src/gpgrt-config new file mode 100755 index 0000000000..226465ef82 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpgrt-config @@ -0,0 +1,646 @@ +#!/bin/sh +# Copyright (C) 2018, 2021 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# SPDX-License-Identifier: FSFULLR + +#### start of functions for this script + +# +# Bourne shell functions for config file in pkg-config style, so that +# we can share such a config file between pkg-config and script +# + +# +# get_var: Get the variable value of NAME +# +# Variables are recorded in the shell variables named "VAR_" +# +get_var () { + ___name=$1 + + eval echo \$VAR_$___name +} + +# +# get_attr: Get the attribute value of KEY +# +# Attributes are recorded in the shell variables named "ATTR_" +# +get_attr () { + ___name=$1 + + eval echo \$ATTR_$___name +} + +# variant of get_attr for list (separated by ',') +get_attr_l () { + (IFS=', '; for x in "$(get_attr $1)"; do echo $x; done) +} + +# Remove ${varname} part in the beginning of a string. +remove_var_expr () { + ___varname=$1 + shift + + expr "$*" : "\${$___varname}\\(.*\\)" +} + +# Given a string, substitute variables. +substitute_vars () { + __string="$1" + __varname="" + __result="" + + while [ -n "$__string" ]; do + case "$__string" in + \$\$*) + __result="$__result\$" + __string="${__string#\$\$}" + ;; + \${*}*) + __varname="${__string#\$\{}" + __varname="${__varname%%\}*}" + __result="$__result$(get_var $__varname)" + __string=$(remove_var_expr $__varname $__string) + ;; + *) + __result="$__result$(printf %c "$__string")" + __string="${__string#$(printf %c "$__string")}" + ;; + esac + done + + echo "$__result" +} + +# +# Read a config from stdin +# +# Variables: +# For VAR=VALUE, value is stored in the shell variable VAR_*. +# +# Attributes: +# For KEY: VALUE, value is stored in the shell variable ATTR_*. +# +read_config_from_stdin () { + _filename=$1 + _line="" + _varname="" + _value="" + _key="" + _reading_attrs="" + + while read _line; do + if [ -z "$_line" ]; then + _reading_attrs=yes + continue + elif [ -z "$_reading_attrs" ]; then + case "$_line" in + *=*) + _varname="${_line%%=*}" + _value="${_line#*=}" + VAR_list="$VAR_list${VAR_list:+ }VAR_$_varname" + read VAR_$_varname </dev/null; then + _key="${_key%.*}_${_key#*.}" + fi + ATTR_list="$ATTR_list${ATTR_list:+ }ATTR_$_key" + read ATTR_$_key <&2 + exit 1 + ;; + esac + fi + done +} + + +find_file_in_path () { + _f=$1 + _p=$2 + _saved_IFS="$IFS" + _arg="" + IFS=":" # On Windows it should be ";"??? + + for _arg in $_p; do + if [ -r $_arg/$_f ]; then + RESULT="$_arg/$_f" + IFS="$_saved_IFS" + return 0 + fi + done + IFS="$_saved_IFS" + RESULT="" + return 1 +} + +read_config_file () { + if ! find_file_in_path $1.pc $2; then + if [ -z "$want_exists" ]; then + echo "Can't find $1.pc" 1>&2 + fi + exit 1 + fi + read_config_from_stdin $RESULT < $RESULT +} + +cleanup_vars_attrs () { + eval unset $VAR_list VAR_list + eval unset $ATTR_list ATTR_list +} + +not_listed_yet () { + ___m=$1 + ___arg="" + shift + + for ___arg; do + if [ $___m = $___arg ]; then + return 1 + fi + done + + return 0 +} + +list_only_once () { + __result="" + __arg="" + + for __arg; do + if not_listed_yet $__arg $__result; then + __result="$__result${__result:+ }$__arg" + fi + done + + echo $__result +} + +list_only_once_for_libs () { + __result="" + __rev_list="" + __arg="" + + # Scan the list and eliminate duplicates for non-"-lxxx" + # the resulted list is in reverse order + for __arg; do + case "$__arg" in + -l*) + # As-is + __rev_list="$__arg${__rev_list:+ }$__rev_list" + ;; + *) + if not_listed_yet $__arg $__rev_list; then + __rev_list="$__arg${__rev_list:+ }$__rev_list" + fi + ;; + esac + done + + # Scan again + for __arg in $__rev_list; do + case "$__arg" in + -l*) + if not_listed_yet $__arg $__result; then + __result="$__arg${__result:+ }$__result" + fi + ;; + *) + # As-is + __result="$__arg${__result:+ }$__result" + ;; + esac + done + + echo $__result +} + +arg1_is_same () { + [ "$1" = "=" -o "$1" = ">=" -o "$1" = "<=" ] +} + +arg1_is_less () { + [ "$1" = "!=" -o "$1" = "<" -o "$1" = "<=" ] +} + +arg1_is_great () { + [ "$1" = "!=" -o "$1" = ">" -o "$1" = ">=" ] +} + +# +# Evaluate comparison between versions in RPM way +# +eval_compare_version () { + ___str1="$1" + ___cmp="$2" + ___str2="$3" + ___char1="" + ___char2="" + ___chunk1="" + ___chunk2="" + + while [ -n "$___str1" -a -n "$___str2" ]; do + # Trim anything that's not alnum or tilde from the front + ___str1="$(expr "$___str1" : '[^0-9A-Za-z~]*\(.*\)')" + ___str2="$(expr "$___str2" : '[^0-9A-Za-z~]*\(.*\)')" + + # Get the first character + ___char1=${___str1%${___str1#?}} + ___char2=${___str2%${___str2#?}} + + if [ "$___char1" = ~ -o "$___char2" = ~ ]; then + if [ "$___char1" != ~ ]; then + arg1_is_great $___cmp + return + fi + if [ "$___char2" != ~ ]; then + arg1_is_less $___cmp + return + fi + ___str1=${___str1#~} + ___str2=${___str2#~} + continue + fi + + if [ -z "$___char1" -o -z "$___char2" ]; then + break + fi + + case "$___char1$___char2" in + [0-9][A-Za-z]) + arg1_is_great $___cmp + return + ;; + [A-Za-z][0-9]) + arg1_is_less $___cmp + return + ;; + [0-9][0-9]) + ___chunk1="$(expr "$___str1" : '\([0-9]*\)')" + ___chunk2="$(expr "$___str2" : '\([0-9]*\)')" + ;; + [A-Za-z][A-Za-z]) + ___chunk1="$(expr "$___str1" : '\([A-Za-z]*\)')" + ___chunk2="$(expr "$___str2" : '\([A-Za-z]*\)')" + ;; + esac + + # Compare chunks numerically if digits, or lexicographically + if expr "$___chunk1" "!=" "$___chunk2" >/dev/null; then + if expr "$___chunk1" ">" "$___chunk2" >/dev/null; then + arg1_is_great $___cmp + return + else + arg1_is_less $___cmp + return + fi + fi + + # Remove the chunk + ___str1="${___str1#$___chunk1}" + ___str2="${___str2#$___chunk2}" + done + + # Either STR1, STR2 or both is empty here + if [ -n "$___str1" ]; then + case "$___str1" in + ~*) arg1_is_less $___cmp ;; + *) arg1_is_great $___cmp ;; + esac + elif [ -n "$___str2" ]; then + case "$___str2" in + ~*) arg1_is_great $___cmp ;; + *) arg1_is_less $___cmp ;; + esac + else + arg1_is_same $___cmp + fi +} + +# +# Recursively solve package dependencies +# +# Result is in the PKG_LIST variable +# +all_required_config_files () { + all_list="" + new_list="" + p="" + pkg="" + cmp="" + + list=$* + while [ -n "$list" ]; do + for p in $list; do + if [ -z "$pkg" ]; then + pkg=$p + elif [ -z "$cmp" ]; then + case "$p" in + "="|"!="|"<"|">"|"<="|">=") cmp=$p ;; + *) + read_config_file $pkg $PKG_CONFIG_PATH + all_list="$all_list${all_list:+ }$pkg" + new_list="$new_list${new_list:+ }$(get_attr_l Requires)" + if [ -n "$enable_static" ]; then + new_list="$new_list${new_list:+ }$(get_attr_l Requires_private)" + fi + cleanup_vars_attrs + pkg=$p + ;; + esac + else + read_config_file $pkg $PKG_CONFIG_PATH + if ! eval_compare_version "$(get_attr Version)" $cmp $p; then + echo "Version mismatch for $pkg $cmp $p: $(get_attr Version)" 1>&2 + exit 1 + fi + all_list="$all_list${all_list:+ }$pkg" + new_list="$new_list${new_list:+ }$(get_attr_l Requires)" + if [ -n "$enable_static" ]; then + new_list="$new_list${new_list:+ }$(get_attr_l Requires_private)" + fi + cleanup_vars_attrs + pkg="" + cmp="" + fi + done + if [ -n "$cmp" ]; then + echo "No version after comparison operator ($cmp): $pkg" 1>&2 + exit 1 + elif [ -n "$pkg" ]; then + read_config_file $pkg $PKG_CONFIG_PATH + all_list="$all_list${all_list:+ }$pkg" + new_list="$new_list${new_list:+ }$(get_attr_l Requires)" + if [ -n "$enable_static" ]; then + new_list="$new_list${new_list:+ }$(get_attr_l Requires_private)" + fi + cleanup_vars_attrs + fi + + list="$new_list" + new_list="" + done + + PKG_LIST=$(list_only_once $all_list) +} + +# +# Modify -I or -L by PKG_CONFIG_SYSROOT_DIR variable +# +sysroot () { + _opt="$1" + _result="" + shift + + while [ $# -gt 0 ]; do + if [ $1 = $_opt ]; then + _result="$_result${_result:+ }$_opt" + shift + _result="$_result $PKG_CONFIG_SYSROOT_DIR$1" + elif expr "x$1" : "^x$_opt" >/dev/null; then + _result="$_result${_result:+ }$_opt$PKG_CONFIG_SYSROOT_DIR$(expr "x$1" : "^x$_opt\(.*\)")" + else + _result="$_result${_result:+ }$1" + fi + shift + done + echo "$_result" +} + +# Show usage +usage () { + cat <&2 + exit 1 + fi +else + if [ -n "$libdir" ]; then + # --libdir option is available, it overrides existing PKG_CONFIG_LIBDIR + PKG_CONFIG_LIBDIR=$libdir/pkgconfig + fi + if [ -z "$PKG_CONFIG_LIBDIR" ]; then + if [ -z "$PKG_CONFIG_PATH" ]; then + echo "Please use --libdir=LIBDIR option or set PKG_CONFIG_LIBDIR" 1>&2 + echo "Or set PKG_CONFIG_PATH" 1>&2 + exit 1 + fi + else + # PKG_CONFIG_LIBDIR is available here + # Modify PKG_CONFIG_PATH, prepending PKG_CONFIG_LIBDIR + PKG_CONFIG_PATH="$PKG_CONFIG_LIBDIR${PKG_CONFIG_PATH:+:}$PKG_CONFIG_PATH" + fi +fi +# PKG_CONFIG_PATH is ready here + +# + +if test $# -eq 0; then + usage 1 1>&2 +fi + + +# Second stage to do the main functionality + +module_list="" +want_var="" +want_attr="" +want_cflags="" +want_libs="" +want_exists="" +enable_static="" + +cflags="" +libs="" +mtcflags="" +mtlibs="" + +output="" + +mt="no" + +VAR_list=VAR_pc_sysrootdir +if [ -z "$PKG_CONFIG_SYSROOT_DIR" ]; then + VAR_pc_sysrootdir="/" +else + VAR_pc_sysrootdir="$PKG_CONFIG_SYSROOT_DIR" +fi + +while test $# -gt 0; do + case $1 in + #### pkg-config incompatible options: begin + --prefix) + # In future, use --variable=prefix instead. + want_var=prefix + ;; + --exec-prefix) + # In future, use --variable=exec_prefix instead. + want_var=exec_prefix + ;; + --version) + # In future, use --modversion instead. + want_attr=Version + ;; + --api-version) + # In future, use --variable=api_version instead. + want_var=api_version + ;; + --host) + # In future, use --variable=host instead. + want_var=host + ;; + --mt) + # In future, use --variable=mtcflags or --variable=mtlibs. + mt=yes + ;; + #### pkg-config incompatible options: end + --modversion) + want_attr=Version + ;; + --exists) + want_exists=yes + ;; + --cflags) + want_cflags=yes + ;; + --libs) + want_libs=yes + ;; + --static) + enable_static=yes + ;; + --variable=*) + want_var=${1#*=} + ;; + --help) + usage 0 + ;; + --*) + usage 1 1>&2 + ;; + *) + # Modules + module_list="$module_list${module_list:+ }$1" + ;; + esac + + shift +done + + +if [ -z "$module_list" ]; then + module_list=$default_module +elif expr "$module_list" : "=\|!=\|<\|>\|<=\|>=" >/dev/null; then + module_list="$default_module $module_list" +fi + +all_required_config_files $module_list + +for p in $PKG_LIST; do + read_config_file $p $PKG_CONFIG_PATH + # For want_var or want_attr, get it from the first package + if [ -n "$want_var" ]; then + output="$(get_var $want_var)" + break + elif [ -n "$want_attr" ]; then + output="$(get_attr $want_attr)" + break + else + cflags="$cflags${cflags:+ }$(get_attr Cflags)" + libs="$libs${libs:+ }$(get_attr Libs)" + if [ -n "$enable_static" ]; then + libs="$libs${libs:+ }$(get_attr Libs_private)" + fi + + if [ $p = "gpg-error" ]; then + mtcflags="$(get_var mtcflags)" + mtlibs="$(get_var mtlibs)" + fi + fi + cleanup_vars_attrs +done + +if [ -z "$want_var" -a -z "$want_attr" ]; then + if [ -n "$want_cflags" ]; then + output="$output${output:+ }$(sysroot -I $(list_only_once $cflags))" + # Backward compatibility to old gpg-error-config + if [ $mt = yes -a -n "$mtcflags" ]; then + output="$output${output:+ }$mtcflags" + fi + fi + if [ -n "$want_libs" ]; then + output="$output${output:+ }$(sysroot -L $(list_only_once_for_libs $libs))" + # Backward compatibility to old gpg-error-config + if [ $mt = yes -a -n "$mtlibs" ]; then + output="$output${output:+ }$mtlibs" + fi + fi +fi + +if [ -z "$want_exists" ]; then + echo "$output" +fi + +exit 0 diff --git a/comm/third_party/libgpg-error/src/gpgrt-config.in b/comm/third_party/libgpg-error/src/gpgrt-config.in new file mode 100644 index 0000000000..0fe14e8bf2 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpgrt-config.in @@ -0,0 +1,646 @@ +#!@INSTALLSHELLPATH@ +# Copyright (C) 2018, 2021 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# SPDX-License-Identifier: FSFULLR + +#### start of functions for this script + +# +# Bourne shell functions for config file in pkg-config style, so that +# we can share such a config file between pkg-config and script +# + +# +# get_var: Get the variable value of NAME +# +# Variables are recorded in the shell variables named "VAR_" +# +get_var () { + ___name=$1 + + eval echo \$VAR_$___name +} + +# +# get_attr: Get the attribute value of KEY +# +# Attributes are recorded in the shell variables named "ATTR_" +# +get_attr () { + ___name=$1 + + eval echo \$ATTR_$___name +} + +# variant of get_attr for list (separated by ',') +get_attr_l () { + (IFS=', '; for x in "$(get_attr $1)"; do echo $x; done) +} + +# Remove ${varname} part in the beginning of a string. +remove_var_expr () { + ___varname=$1 + shift + + expr "$*" : "\${$___varname}\\(.*\\)" +} + +# Given a string, substitute variables. +substitute_vars () { + __string="$1" + __varname="" + __result="" + + while [ -n "$__string" ]; do + case "$__string" in + \$\$*) + __result="$__result\$" + __string="${__string#\$\$}" + ;; + \${*}*) + __varname="${__string#\$\{}" + __varname="${__varname%%\}*}" + __result="$__result$(get_var $__varname)" + __string=$(remove_var_expr $__varname $__string) + ;; + *) + __result="$__result$(printf %c "$__string")" + __string="${__string#$(printf %c "$__string")}" + ;; + esac + done + + echo "$__result" +} + +# +# Read a config from stdin +# +# Variables: +# For VAR=VALUE, value is stored in the shell variable VAR_*. +# +# Attributes: +# For KEY: VALUE, value is stored in the shell variable ATTR_*. +# +read_config_from_stdin () { + _filename=$1 + _line="" + _varname="" + _value="" + _key="" + _reading_attrs="" + + while read _line; do + if [ -z "$_line" ]; then + _reading_attrs=yes + continue + elif [ -z "$_reading_attrs" ]; then + case "$_line" in + *=*) + _varname="${_line%%=*}" + _value="${_line#*=}" + VAR_list="$VAR_list${VAR_list:+ }VAR_$_varname" + read VAR_$_varname </dev/null; then + _key="${_key%.*}_${_key#*.}" + fi + ATTR_list="$ATTR_list${ATTR_list:+ }ATTR_$_key" + read ATTR_$_key <&2 + exit 1 + ;; + esac + fi + done +} + + +find_file_in_path () { + _f=$1 + _p=$2 + _saved_IFS="$IFS" + _arg="" + IFS=":" # On Windows it should be ";"??? + + for _arg in $_p; do + if [ -r $_arg/$_f ]; then + RESULT="$_arg/$_f" + IFS="$_saved_IFS" + return 0 + fi + done + IFS="$_saved_IFS" + RESULT="" + return 1 +} + +read_config_file () { + if ! find_file_in_path $1.pc $2; then + if [ -z "$want_exists" ]; then + echo "Can't find $1.pc" 1>&2 + fi + exit 1 + fi + read_config_from_stdin $RESULT < $RESULT +} + +cleanup_vars_attrs () { + eval unset $VAR_list VAR_list + eval unset $ATTR_list ATTR_list +} + +not_listed_yet () { + ___m=$1 + ___arg="" + shift + + for ___arg; do + if [ $___m = $___arg ]; then + return 1 + fi + done + + return 0 +} + +list_only_once () { + __result="" + __arg="" + + for __arg; do + if not_listed_yet $__arg $__result; then + __result="$__result${__result:+ }$__arg" + fi + done + + echo $__result +} + +list_only_once_for_libs () { + __result="" + __rev_list="" + __arg="" + + # Scan the list and eliminate duplicates for non-"-lxxx" + # the resulted list is in reverse order + for __arg; do + case "$__arg" in + -l*) + # As-is + __rev_list="$__arg${__rev_list:+ }$__rev_list" + ;; + *) + if not_listed_yet $__arg $__rev_list; then + __rev_list="$__arg${__rev_list:+ }$__rev_list" + fi + ;; + esac + done + + # Scan again + for __arg in $__rev_list; do + case "$__arg" in + -l*) + if not_listed_yet $__arg $__result; then + __result="$__arg${__result:+ }$__result" + fi + ;; + *) + # As-is + __result="$__arg${__result:+ }$__result" + ;; + esac + done + + echo $__result +} + +arg1_is_same () { + [ "$1" = "=" -o "$1" = ">=" -o "$1" = "<=" ] +} + +arg1_is_less () { + [ "$1" = "!=" -o "$1" = "<" -o "$1" = "<=" ] +} + +arg1_is_great () { + [ "$1" = "!=" -o "$1" = ">" -o "$1" = ">=" ] +} + +# +# Evaluate comparison between versions in RPM way +# +eval_compare_version () { + ___str1="$1" + ___cmp="$2" + ___str2="$3" + ___char1="" + ___char2="" + ___chunk1="" + ___chunk2="" + + while [ -n "$___str1" -a -n "$___str2" ]; do + # Trim anything that's not alnum or tilde from the front + ___str1="$(expr "$___str1" : '[^0-9A-Za-z~]*\(.*\)')" + ___str2="$(expr "$___str2" : '[^0-9A-Za-z~]*\(.*\)')" + + # Get the first character + ___char1=${___str1%${___str1#?}} + ___char2=${___str2%${___str2#?}} + + if [ "$___char1" = ~ -o "$___char2" = ~ ]; then + if [ "$___char1" != ~ ]; then + arg1_is_great $___cmp + return + fi + if [ "$___char2" != ~ ]; then + arg1_is_less $___cmp + return + fi + ___str1=${___str1#~} + ___str2=${___str2#~} + continue + fi + + if [ -z "$___char1" -o -z "$___char2" ]; then + break + fi + + case "$___char1$___char2" in + [0-9][A-Za-z]) + arg1_is_great $___cmp + return + ;; + [A-Za-z][0-9]) + arg1_is_less $___cmp + return + ;; + [0-9][0-9]) + ___chunk1="$(expr "$___str1" : '\([0-9]*\)')" + ___chunk2="$(expr "$___str2" : '\([0-9]*\)')" + ;; + [A-Za-z][A-Za-z]) + ___chunk1="$(expr "$___str1" : '\([A-Za-z]*\)')" + ___chunk2="$(expr "$___str2" : '\([A-Za-z]*\)')" + ;; + esac + + # Compare chunks numerically if digits, or lexicographically + if expr "$___chunk1" "!=" "$___chunk2" >/dev/null; then + if expr "$___chunk1" ">" "$___chunk2" >/dev/null; then + arg1_is_great $___cmp + return + else + arg1_is_less $___cmp + return + fi + fi + + # Remove the chunk + ___str1="${___str1#$___chunk1}" + ___str2="${___str2#$___chunk2}" + done + + # Either STR1, STR2 or both is empty here + if [ -n "$___str1" ]; then + case "$___str1" in + ~*) arg1_is_less $___cmp ;; + *) arg1_is_great $___cmp ;; + esac + elif [ -n "$___str2" ]; then + case "$___str2" in + ~*) arg1_is_great $___cmp ;; + *) arg1_is_less $___cmp ;; + esac + else + arg1_is_same $___cmp + fi +} + +# +# Recursively solve package dependencies +# +# Result is in the PKG_LIST variable +# +all_required_config_files () { + all_list="" + new_list="" + p="" + pkg="" + cmp="" + + list=$* + while [ -n "$list" ]; do + for p in $list; do + if [ -z "$pkg" ]; then + pkg=$p + elif [ -z "$cmp" ]; then + case "$p" in + "="|"!="|"<"|">"|"<="|">=") cmp=$p ;; + *) + read_config_file $pkg $PKG_CONFIG_PATH + all_list="$all_list${all_list:+ }$pkg" + new_list="$new_list${new_list:+ }$(get_attr_l Requires)" + if [ -n "$enable_static" ]; then + new_list="$new_list${new_list:+ }$(get_attr_l Requires_private)" + fi + cleanup_vars_attrs + pkg=$p + ;; + esac + else + read_config_file $pkg $PKG_CONFIG_PATH + if ! eval_compare_version "$(get_attr Version)" $cmp $p; then + echo "Version mismatch for $pkg $cmp $p: $(get_attr Version)" 1>&2 + exit 1 + fi + all_list="$all_list${all_list:+ }$pkg" + new_list="$new_list${new_list:+ }$(get_attr_l Requires)" + if [ -n "$enable_static" ]; then + new_list="$new_list${new_list:+ }$(get_attr_l Requires_private)" + fi + cleanup_vars_attrs + pkg="" + cmp="" + fi + done + if [ -n "$cmp" ]; then + echo "No version after comparison operator ($cmp): $pkg" 1>&2 + exit 1 + elif [ -n "$pkg" ]; then + read_config_file $pkg $PKG_CONFIG_PATH + all_list="$all_list${all_list:+ }$pkg" + new_list="$new_list${new_list:+ }$(get_attr_l Requires)" + if [ -n "$enable_static" ]; then + new_list="$new_list${new_list:+ }$(get_attr_l Requires_private)" + fi + cleanup_vars_attrs + fi + + list="$new_list" + new_list="" + done + + PKG_LIST=$(list_only_once $all_list) +} + +# +# Modify -I or -L by PKG_CONFIG_SYSROOT_DIR variable +# +sysroot () { + _opt="$1" + _result="" + shift + + while [ $# -gt 0 ]; do + if [ $1 = $_opt ]; then + _result="$_result${_result:+ }$_opt" + shift + _result="$_result $PKG_CONFIG_SYSROOT_DIR$1" + elif expr "x$1" : "^x$_opt" >/dev/null; then + _result="$_result${_result:+ }$_opt$PKG_CONFIG_SYSROOT_DIR$(expr "x$1" : "^x$_opt\(.*\)")" + else + _result="$_result${_result:+ }$1" + fi + shift + done + echo "$_result" +} + +# Show usage +usage () { + cat <&2 + exit 1 + fi +else + if [ -n "$libdir" ]; then + # --libdir option is available, it overrides existing PKG_CONFIG_LIBDIR + PKG_CONFIG_LIBDIR=$libdir/pkgconfig + fi + if [ -z "$PKG_CONFIG_LIBDIR" ]; then + if [ -z "$PKG_CONFIG_PATH" ]; then + echo "Please use --libdir=LIBDIR option or set PKG_CONFIG_LIBDIR" 1>&2 + echo "Or set PKG_CONFIG_PATH" 1>&2 + exit 1 + fi + else + # PKG_CONFIG_LIBDIR is available here + # Modify PKG_CONFIG_PATH, prepending PKG_CONFIG_LIBDIR + PKG_CONFIG_PATH="$PKG_CONFIG_LIBDIR${PKG_CONFIG_PATH:+:}$PKG_CONFIG_PATH" + fi +fi +# PKG_CONFIG_PATH is ready here + +# + +if test $# -eq 0; then + usage 1 1>&2 +fi + + +# Second stage to do the main functionality + +module_list="" +want_var="" +want_attr="" +want_cflags="" +want_libs="" +want_exists="" +enable_static="" + +cflags="" +libs="" +mtcflags="" +mtlibs="" + +output="" + +mt="no" + +VAR_list=VAR_pc_sysrootdir +if [ -z "$PKG_CONFIG_SYSROOT_DIR" ]; then + VAR_pc_sysrootdir="/" +else + VAR_pc_sysrootdir="$PKG_CONFIG_SYSROOT_DIR" +fi + +while test $# -gt 0; do + case $1 in + #### pkg-config incompatible options: begin + --prefix) + # In future, use --variable=prefix instead. + want_var=prefix + ;; + --exec-prefix) + # In future, use --variable=exec_prefix instead. + want_var=exec_prefix + ;; + --version) + # In future, use --modversion instead. + want_attr=Version + ;; + --api-version) + # In future, use --variable=api_version instead. + want_var=api_version + ;; + --host) + # In future, use --variable=host instead. + want_var=host + ;; + --mt) + # In future, use --variable=mtcflags or --variable=mtlibs. + mt=yes + ;; + #### pkg-config incompatible options: end + --modversion) + want_attr=Version + ;; + --exists) + want_exists=yes + ;; + --cflags) + want_cflags=yes + ;; + --libs) + want_libs=yes + ;; + --static) + enable_static=yes + ;; + --variable=*) + want_var=${1#*=} + ;; + --help) + usage 0 + ;; + --*) + usage 1 1>&2 + ;; + *) + # Modules + module_list="$module_list${module_list:+ }$1" + ;; + esac + + shift +done + + +if [ -z "$module_list" ]; then + module_list=$default_module +elif expr "$module_list" : "=\|!=\|<\|>\|<=\|>=" >/dev/null; then + module_list="$default_module $module_list" +fi + +all_required_config_files $module_list + +for p in $PKG_LIST; do + read_config_file $p $PKG_CONFIG_PATH + # For want_var or want_attr, get it from the first package + if [ -n "$want_var" ]; then + output="$(get_var $want_var)" + break + elif [ -n "$want_attr" ]; then + output="$(get_attr $want_attr)" + break + else + cflags="$cflags${cflags:+ }$(get_attr Cflags)" + libs="$libs${libs:+ }$(get_attr Libs)" + if [ -n "$enable_static" ]; then + libs="$libs${libs:+ }$(get_attr Libs_private)" + fi + + if [ $p = "gpg-error" ]; then + mtcflags="$(get_var mtcflags)" + mtlibs="$(get_var mtlibs)" + fi + fi + cleanup_vars_attrs +done + +if [ -z "$want_var" -a -z "$want_attr" ]; then + if [ -n "$want_cflags" ]; then + output="$output${output:+ }$(sysroot -I $(list_only_once $cflags))" + # Backward compatibility to old gpg-error-config + if [ $mt = yes -a -n "$mtcflags" ]; then + output="$output${output:+ }$mtcflags" + fi + fi + if [ -n "$want_libs" ]; then + output="$output${output:+ }$(sysroot -L $(list_only_once_for_libs $libs))" + # Backward compatibility to old gpg-error-config + if [ $mt = yes -a -n "$mtlibs" ]; then + output="$output${output:+ }$mtlibs" + fi + fi +fi + +if [ -z "$want_exists" ]; then + echo "$output" +fi + +exit 0 diff --git a/comm/third_party/libgpg-error/src/gpgrt-int.h b/comm/third_party/libgpg-error/src/gpgrt-int.h new file mode 100644 index 0000000000..fde5ee4e86 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpgrt-int.h @@ -0,0 +1,844 @@ +/* gpgrt-int.h - Internal definitions + * Copyright (C) 2014, 2017 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef _GPGRT_GPGRT_INT_H +#define _GPGRT_GPGRT_INT_H + +#include "gpg-error.h" +#include "visibility.h" +#include "protos.h" + +/* + * Internal i18n macros. + */ +#ifdef ENABLE_NLS +# ifdef HAVE_W32_SYSTEM +# include "gettext.h" +# else +# include +# endif +# define _(a) gettext (a) +# ifdef gettext_noop +# define N_(a) gettext_noop (a) +# else +# define N_(a) (a) +# endif +#else /*!ENABLE_NLS*/ +# define _(a) (a) +# define N_(a) (a) +#endif /*!ENABLE_NLS */ + + +/* + * Hacks mainly required for Slowaris. + */ +#ifdef _GPGRT_NEED_AFLOCAL +# ifndef HAVE_W32_SYSTEM +# include +# include +# else +# ifdef HAVE_WINSOCK2_H +# include +# endif +# include +# endif + +# ifndef PF_LOCAL +# ifdef PF_UNIX +# define PF_LOCAL PF_UNIX +# else +# define PF_LOCAL AF_UNIX +# endif +# endif /*PF_LOCAL*/ +# ifndef AF_LOCAL +# define AF_LOCAL AF_UNIX +# endif /*AF_UNIX*/ + +/* We used to avoid this macro in GnuPG and inlined the AF_LOCAL name + * length computation directly with the little twist of adding 1 extra + * byte. It seems that this was needed once on an old HP/UX box and + * there are also rumours that 4.3 Reno and DEC systems need it. This + * one-off buglet did not harm any current system until it came to Mac + * OS X where the kernel (as of May 2009) exhibited a strange bug: The + * systems basically froze in the connect call if the passed name + * contained an invalid directory part. Ignore the old Unices. */ +# ifndef SUN_LEN +# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +# endif /*SUN_LEN*/ +#endif /*_GPGRT_NEED_AFLOCAL*/ + + +/* + * Common helper macros. + */ +#ifndef DIM +# define DIM(array) (sizeof (array) / sizeof (*array)) +#endif + + + +/* + * Local error function prototypes. + */ +const char *_gpg_strerror (gpg_error_t err); +int _gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen); +const char *_gpg_strsource (gpg_error_t err); +gpg_err_code_t _gpg_err_code_from_errno (int err); +int _gpg_err_code_to_errno (gpg_err_code_t code); +gpg_err_code_t _gpg_err_code_from_syserror (void); +void _gpg_err_set_errno (int err); + +gpg_error_t _gpg_err_init (void); +void _gpg_err_deinit (int mode); + +void _gpgrt_add_emergency_cleanup (void (*f)(void)); +void _gpgrt_abort (void) GPGRT_ATTR_NORETURN; + +void _gpgrt_set_alloc_func (void *(*f)(void *a, size_t n)); + +void *_gpgrt_realloc (void *a, size_t n); +void *_gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size); +void *_gpgrt_malloc (size_t n); +void *_gpgrt_calloc (size_t n, size_t m); +char *_gpgrt_strdup (const char *string); +char *_gpgrt_strconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0); +void _gpgrt_free (void *a); +/* The next is only to be used by visibility.c. */ +char *_gpgrt_strconcat_core (const char *s1, va_list arg_ptr); + +#define xfree(a) _gpgrt_free ((a)) +#define xtrymalloc(a) _gpgrt_malloc ((a)) +#define xtrycalloc(a,b) _gpgrt_calloc ((a),(b)) +#define xtryrealloc(a,b) _gpgrt_realloc ((a),(b)) +#define xtryreallocarray(a,b,c,d) _gpgrt_reallocarray ((a),(b),(c),(d)) +#define xtrystrdup(a) _gpgrt_strdup ((a)) + +void _gpgrt_pre_syscall (void); +void _gpgrt_post_syscall (void); + +const char *_gpg_error_check_version (const char *req_version); + +gpg_err_code_t _gpgrt_lock_init (gpgrt_lock_t *lockhd); +gpg_err_code_t _gpgrt_lock_lock (gpgrt_lock_t *lockhd); +gpg_err_code_t _gpgrt_lock_trylock (gpgrt_lock_t *lockhd); +gpg_err_code_t _gpgrt_lock_unlock (gpgrt_lock_t *lockhd); +gpg_err_code_t _gpgrt_lock_destroy (gpgrt_lock_t *lockhd); +gpg_err_code_t _gpgrt_yield (void); + + + +/* + * Tracing + */ + +/* The trace macro is used this way: + * trace (("enter - foo=%d bar=%s", foo, bar)); + * Note the double parenthesis, they are important. + * To append the current errno to the output, use + * trace_errno (EXTPR,("leave - baz=%d", faz)); + * If EXPR evaluates to true the output of strerror (errno) + * is appended to the output. Note that the trace function does + * not modify ERRNO. To enable tracing you need to have this + * #define ENABLE_TRACING "modulename" + * before you include gpgrt-int.h. + */ +#ifdef ENABLE_TRACING +# define trace(X) do { \ + _gpgrt_internal_trace_begin \ + (ENABLE_TRACING, __func__, __LINE__, 0); \ + _gpgrt_internal_trace X; \ + _gpgrt_internal_trace_end (); \ + } while (0) +# define trace_errno(C,X) do { \ + _gpgrt_internal_trace_begin \ + (ENABLE_TRACING, __func__, __LINE__, (C)); \ + _gpgrt_internal_trace X; \ + _gpgrt_internal_trace_end (); \ + } while (0) +# define trace_start(X) do { \ + _gpgrt_internal_trace_begin \ + (ENABLE_TRACING, __func__, __LINE__, 0); \ + _gpgrt_internal_trace_printf X; \ + } while (0) +# define trace_append(X) do { \ + _gpgrt_internal_trace_printf X; \ + } while (0) +# define trace_finish(X) do { \ + _gpgrt_internal_trace_printf X; \ + _gpgrt_internal_trace_end (); \ + } while (0) +#else +# define trace(X) do { } while (0) +# define trace_errno(C,X) do { } while (0) +# define trace_start(X) do { } while (0) +# define trace_append(X) do { } while (0) +# define trace_finish(X) do { } while (0) +#endif /*!ENABLE_TRACING*/ + +void _gpgrt_internal_trace_begin (const char *mod, const char *file, int line, + int with_errno); +void _gpgrt_internal_trace (const char *format, + ...) GPGRT_ATTR_PRINTF(1,2); +void _gpgrt_internal_trace_printf (const char *format, + ...) GPGRT_ATTR_PRINTF(1,2); +void _gpgrt_internal_trace_end (void); + + + +/* + * Local definitions for estream. + */ + +#if HAVE_W32_SYSTEM +# ifndef O_NONBLOCK +# define O_NONBLOCK 0x40000000 /* FIXME: Is that safe? */ +# endif +#endif + +/* + * A private cookie function to implement an internal IOCTL service. + */ +typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd, + void *ptr, size_t *len); +#define COOKIE_IOCTL_SNATCH_BUFFER 1 +#define COOKIE_IOCTL_NONBLOCK 2 +#define COOKIE_IOCTL_TRUNCATE 3 + +/* An internal variant of gpgrt_cookie_close_function_t with a slot + * for the ioctl function. */ +struct cookie_io_functions_s +{ + struct _gpgrt_cookie_io_functions public; + cookie_ioctl_function_t func_ioctl; +}; + +typedef enum + { + BACKEND_MEM, + BACKEND_FD, + BACKEND_W32, + BACKEND_FP, + BACKEND_USER, + BACKEND_W32_POLLABLE + } gpgrt_stream_backend_kind_t; + + +/* + * A type to hold notification functions. + */ +struct notify_list_s +{ + struct notify_list_s *next; + void (*fnc) (estream_t, void*); /* The notification function. */ + void *fnc_value; /* The value to be passed to FNC. */ +}; +typedef struct notify_list_s *notify_list_t; + + +/* + * Buffer management layer. + */ + +/* BUFSIZ on Windows is 512 but on current Linux it is 8k. We better + * use the 8k for Windows as well. */ +#ifdef HAVE_W32_SYSTEM +# define BUFFER_BLOCK_SIZE 8192 +#else +# define BUFFER_BLOCK_SIZE BUFSIZ +#endif +#define BUFFER_UNREAD_SIZE 16 + + +/* + * The private object describing a stream. + */ +struct _gpgrt_stream_internal +{ + unsigned char buffer[BUFFER_BLOCK_SIZE]; + unsigned char unread_buffer[BUFFER_UNREAD_SIZE]; + + gpgrt_lock_t lock; /* Lock. Used by *_stream_lock(). */ + + gpgrt_stream_backend_kind_t kind; + void *cookie; /* Cookie. */ + void *opaque; /* Opaque data. */ + unsigned int modeflags; /* Flags for the backend. */ + char *printable_fname; /* Malloced filename for es_fname_get. */ + gpgrt_off_t offset; + gpgrt_cookie_read_function_t func_read; + gpgrt_cookie_write_function_t func_write; + gpgrt_cookie_seek_function_t func_seek; + gpgrt_cookie_close_function_t func_close; + cookie_ioctl_function_t func_ioctl; + int strategy; + es_syshd_t syshd; /* A copy of the system handle. */ + struct + { + unsigned int err: 1; + unsigned int eof: 1; + unsigned int hup: 1; + } indicators; + unsigned int deallocate_buffer: 1; + unsigned int is_stdstream:1; /* This is a standard stream. */ + unsigned int stdstream_fd:2; /* 0, 1 or 2 for a standard stream. */ + unsigned int printable_fname_inuse: 1; /* es_fname_get has been used. */ + unsigned int samethread: 1; /* The "samethread" mode keyword. */ + size_t print_ntotal; /* Bytes written from in print_writer. */ + notify_list_t onclose; /* On close notify function list. */ +}; +typedef struct _gpgrt_stream_internal *estream_internal_t; + + +/* + * Local prototypes for estream. + */ +int _gpgrt_estream_init (void); +void _gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void)); +void _gpgrt_get_syscall_clamp (void (**r_pre)(void), void (**r_post)(void)); + +gpgrt_stream_t _gpgrt_fopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode); +gpgrt_stream_t _gpgrt_mopen (void *_GPGRT__RESTRICT data, + size_t data_n, size_t data_len, + unsigned int grow, + void *(*func_realloc) (void *mem, size_t size), + void (*func_free) (void *mem), + const char *_GPGRT__RESTRICT mode); +gpgrt_stream_t _gpgrt_fopenmem (size_t memlimit, + const char *_GPGRT__RESTRICT mode); +gpgrt_stream_t _gpgrt_fopenmem_init (size_t memlimit, + const char *_GPGRT__RESTRICT mode, + const void *data, size_t datalen); +gpgrt_stream_t _gpgrt_fdopen (int filedes, const char *mode); +gpgrt_stream_t _gpgrt_fdopen_nc (int filedes, const char *mode); +gpgrt_stream_t _gpgrt_sysopen (gpgrt_syshd_t *syshd, const char *mode); +gpgrt_stream_t _gpgrt_sysopen_nc (gpgrt_syshd_t *syshd, const char *mode); +gpgrt_stream_t _gpgrt_fpopen (FILE *fp, const char *mode); +gpgrt_stream_t _gpgrt_fpopen_nc (FILE *fp, const char *mode); +gpgrt_stream_t _gpgrt_freopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode, + gpgrt_stream_t _GPGRT__RESTRICT stream); +gpgrt_stream_t _gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie, + const char *_GPGRT__RESTRICT mode, + gpgrt_cookie_io_functions_t functions); +int _gpgrt_fclose (gpgrt_stream_t stream); +int _gpgrt_fcancel (gpgrt_stream_t stream); +int _gpgrt_fclose_snatch (gpgrt_stream_t stream, + void **r_buffer, size_t *r_buflen); +int _gpgrt_onclose (gpgrt_stream_t stream, int mode, + void (*fnc) (gpgrt_stream_t, void*), void *fnc_value); +int _gpgrt_fileno (gpgrt_stream_t stream); +int _gpgrt_fileno_unlocked (gpgrt_stream_t stream); +int _gpgrt_syshd (gpgrt_stream_t stream, gpgrt_syshd_t *syshd); +int _gpgrt_syshd_unlocked (gpgrt_stream_t stream, gpgrt_syshd_t *syshd); + +void _gpgrt__set_std_fd (int no, int fd); +gpgrt_stream_t _gpgrt__get_std_stream (int fd); +/* The es_stderr et al macros are pretty common so that we want to use + * them too. This requires that we redefine them. */ +#undef es_stdin +#define es_stdin _gpgrt__get_std_stream (0) +#undef es_stdout +#define es_stdout _gpgrt__get_std_stream (1) +#undef es_stderr +#define es_stderr _gpgrt__get_std_stream (2) + +void _gpgrt_flockfile (gpgrt_stream_t stream); +int _gpgrt_ftrylockfile (gpgrt_stream_t stream); +void _gpgrt_funlockfile (gpgrt_stream_t stream); + +int _gpgrt_feof (gpgrt_stream_t stream); +int _gpgrt_feof_unlocked (gpgrt_stream_t stream); +int _gpgrt_ferror (gpgrt_stream_t stream); +int _gpgrt_ferror_unlocked (gpgrt_stream_t stream); +void _gpgrt_clearerr (gpgrt_stream_t stream); +void _gpgrt_clearerr_unlocked (gpgrt_stream_t stream); +int _gpgrt__pending (gpgrt_stream_t stream); +int _gpgrt__pending_unlocked (gpgrt_stream_t stream); + +int _gpgrt_fflush (gpgrt_stream_t stream); +int _gpgrt_fseek (gpgrt_stream_t stream, long int offset, int whence); +int _gpgrt_fseeko (gpgrt_stream_t stream, gpgrt_off_t offset, int whence); +long int _gpgrt_ftell (gpgrt_stream_t stream); +gpgrt_off_t _gpgrt_ftello (gpgrt_stream_t stream); +void _gpgrt_rewind (gpgrt_stream_t stream); +int _gpgrt_ftruncate (estream_t stream, gpgrt_off_t length); + +int _gpgrt_fgetc (gpgrt_stream_t stream); +int _gpgrt_fputc (int c, gpgrt_stream_t stream); + +int _gpgrt__getc_underflow (gpgrt_stream_t stream); +int _gpgrt__putc_overflow (int c, gpgrt_stream_t stream); + +/* Note: Keeps the next two macros in sync + with their counterparts in gpg-error.h. */ +#define _gpgrt_getc_unlocked(stream) \ + (((!(stream)->flags.writing) \ + && ((stream)->data_offset < (stream)->data_len) \ + && (! (stream)->unread_data_len)) \ + ? ((int) (stream)->buffer[((stream)->data_offset)++]) \ + : _gpgrt__getc_underflow ((stream))) + +#define _gpgrt_putc_unlocked(c, stream) \ + (((stream)->flags.writing \ + && ((stream)->data_offset < (stream)->buffer_size) \ + && (c != '\n')) \ + ? ((int) ((stream)->buffer[((stream)->data_offset)++] = (c))) \ + : _gpgrt__putc_overflow ((c), (stream))) + +int _gpgrt_ungetc (int c, gpgrt_stream_t stream); + +int _gpgrt_read (gpgrt_stream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT buffer, size_t bytes_to_read, + size_t *_GPGRT__RESTRICT bytes_read); +int _gpgrt_write (gpgrt_stream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write, + size_t *_GPGRT__RESTRICT bytes_written); +int _gpgrt_write_sanitized (gpgrt_stream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t length, + const char *delimiters, + size_t *_GPGRT__RESTRICT bytes_written); +int _gpgrt_write_hexstring (gpgrt_stream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t length, + int reserved, + size_t *_GPGRT__RESTRICT bytes_written); + +size_t _gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, + gpgrt_stream_t _GPGRT__RESTRICT stream); +size_t _gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, + size_t size, size_t memb, + gpgrt_stream_t _GPGRT__RESTRICT stream); + +char *_gpgrt_fgets (char *_GPGRT__RESTRICT s, int n, + gpgrt_stream_t _GPGRT__RESTRICT stream); +int _gpgrt_fputs (const char *_GPGRT__RESTRICT s, + gpgrt_stream_t _GPGRT__RESTRICT stream); +int _gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s, + gpgrt_stream_t _GPGRT__RESTRICT stream); + +gpgrt_ssize_t _gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr, + size_t *_GPGRT__RESTRICT n, + gpgrt_stream_t stream); +gpgrt_ssize_t _gpgrt_read_line (gpgrt_stream_t stream, + char **addr_of_buffer, size_t *length_of_buffer, + size_t *max_length); + +int _gpgrt_fprintf (gpgrt_stream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(2,3); +int _gpgrt_fprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) + GPGRT_ATTR_PRINTF(2,3); + +int _gpgrt_vfprintf (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, va_list ap) + GPGRT_ATTR_PRINTF(4,0); +int _gpgrt_vfprintf_unlocked (gpgrt_stream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, va_list ap) + GPGRT_ATTR_PRINTF(4,0); + +int _gpgrt_setvbuf (gpgrt_stream_t _GPGRT__RESTRICT stream, + char *_GPGRT__RESTRICT buf, int mode, size_t size); + +void _gpgrt_set_binary (gpgrt_stream_t stream); +int _gpgrt_set_nonblock (gpgrt_stream_t stream, int onoff); +int _gpgrt_get_nonblock (gpgrt_stream_t stream); + +int _gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout); + +gpgrt_stream_t _gpgrt_tmpfile (void); + +void _gpgrt_opaque_set (gpgrt_stream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT opaque); +void *_gpgrt_opaque_get (gpgrt_stream_t stream); + +void _gpgrt_fname_set (gpgrt_stream_t stream, const char *fname); +const char *_gpgrt_fname_get (gpgrt_stream_t stream); + +#include "estream-printf.h" + +/* Make sure we always use our snprintf */ +#undef snprintf +#define snprintf _gpgrt_estream_snprintf + + +#if HAVE_W32_SYSTEM +/* Prototypes for w32-estream.c. */ +extern struct cookie_io_functions_s _gpgrt_functions_w32_pollable; +int _gpgrt_w32_pollable_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie, + unsigned int modeflags, + struct cookie_io_functions_s next_functions, + void *next_cookie); +int _gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout); +#endif /*HAVE_W32_SYSTEM*/ + + + +/* + * Local prototypes for the encoders. + */ + +struct _gpgrt_b64state +{ + int idx; + int quad_count; + estream_t stream; + char *title; + unsigned char radbuf[4]; + unsigned int crc; + gpg_err_code_t lasterr; + unsigned int flags; + unsigned int stop_seen:1; + unsigned int invalid_encoding:1; + unsigned int using_decoder:1; +}; + +gpgrt_b64state_t _gpgrt_b64enc_start (estream_t stream, const char *title); +gpg_err_code_t _gpgrt_b64enc_write (gpgrt_b64state_t state, + const void *buffer, size_t nbytes); +gpg_err_code_t _gpgrt_b64enc_finish (gpgrt_b64state_t state); + +gpgrt_b64state_t _gpgrt_b64dec_start (const char *title); +gpg_err_code_t _gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, + size_t length, size_t *r_nbytes); +gpg_err_code_t _gpgrt_b64dec_finish (gpgrt_b64state_t state); + + + +/* + * Local prototypes for logging + */ +int _gpgrt_get_errorcount (int clear); +void _gpgrt_inc_errorcount (void); +void _gpgrt_log_set_sink (const char *name, estream_t stream, int fd); +void _gpgrt_log_set_socket_dir_cb (const char *(*fnc)(void)); +void _gpgrt_log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)); +void _gpgrt_log_set_prefix (const char *text, unsigned int flags); +const char *_gpgrt_log_get_prefix (unsigned int *flags); +int _gpgrt_log_test_fd (int fd); +int _gpgrt_log_get_fd (void); +estream_t _gpgrt_log_get_stream (void); + +void _gpgrt_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3); +void _gpgrt_logv (int level, const char *fmt, va_list arg_ptr); +void _gpgrt_logv_prefix (int level, const char *prefix, + const char *fmt, va_list arg_ptr); + +void _gpgrt_log_string (int level, const char *string); + +void _gpgrt_log_bug (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); +void _gpgrt_log_fatal (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2); +void _gpgrt_log_error (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void _gpgrt_log_info (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void _gpgrt_log_debug (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); +void _gpgrt_log_debug_string (const char *string, const char *fmt, + ...) GPGRT_ATTR_PRINTF(2,3); + +void _gpgrt_log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); + +void _gpgrt_log_flush (void); + +void _gpgrt_logv_printhex (const void *buffer, size_t length, + const char *fmt, va_list arg_ptr); +void _gpgrt_log_printhex (const void *buffer, size_t length, + const char *fmt, ...) GPGRT_ATTR_PRINTF(3,4);; + +void _gpgrt_logv_clock (const char *fmt, va_list arg_ptr); +void _gpgrt_log_clock (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); + +void _gpgrt__log_assert (const char *expr, const char *file, int line, + const char *func) GPGRT_ATTR_NORETURN; + +/* Redefine the assert macro to use our internal function. */ +#undef gpgrt_assert +#ifdef GPGRT_HAVE_MACRO_FUNCTION +#define gpgrt_assert(expr) \ + ((expr) \ + ? (void) 0 \ + : _gpgrt__log_assert (#expr, __FILE__, __LINE__, __FUNCTION__)) +#else /*!GPGRT_HAVE_MACRO_FUNCTION*/ +/* # define BUG() bug_at( __FILE__ , __LINE__ ) */ +#define gpgrt_assert(expr) \ + ((expr) \ + ? (void) 0 \ + : _gpgrt__log_assert (#expr, __FILE__, __LINE__, NULL)) +#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + +/* Note: The next function is only to be used by visibility.c. */ +int _gpgrt_logv_internal (int level, int ignore_arg_ptr, + const char *extrastring, + const char *prefmt, const char *fmt, + va_list arg_ptr); + + +/* + * Local prototypes for the spawn functions. + * + * We put the docs here because we have separate implementations in + * the files spawn-posix.c and spawn-w32.c + */ + +/* Return the maximum number of currently allowed file descriptors. + * Only useful on POSIX systems. */ +/* int get_max_fds (void); */ + + +/* Close all file descriptors starting with descriptor FIRST. If + * EXCEPT is not NULL, it is expected to be a list of file descriptors + * which are not to close. This list shall be sorted in ascending + * order with its end marked by -1. */ +/* void close_all_fds (int first, int *except); */ + + +/* Returns an array with all currently open file descriptors. The end + * of the array is marked by -1. The caller needs to release this + * array using the *standard free* and not with xfree. This allow the + * use of this function right at startup even before libgcrypt has + * been initialized. Returns NULL on error and sets ERRNO accordingly. */ +/* int *get_all_open_fds (void); */ + +/* Create a pipe. The DIRECTION parameter gives the type of the created pipe: + * DIRECTION < 0 := Inbound pipe: On Windows the write end is inheritable. + * DIRECTION > 0 := Outbound pipe: On Windows the read end is inheritable. + * If R_FP is NULL a standard pipe and no stream is created, DIRECTION + * should then be 0. */ +gpg_err_code_t _gpgrt_make_pipe (int filedes[2], estream_t *r_fp, + int direction, int nonblock); + +/* Convenience macros to create a pipe. */ +#define _gpgrt_create_pipe(a) _gpgrt_make_pipe ((a),NULL, 0, 0); +#define _gpgrt_create_inbound_pipe(a,b,c) _gpgrt_make_pipe ((a), (b), -1, (c)); +#define _gpgrt_create_outbound_pipe(a,b,c) _gpgrt_make_pipe ((a), (b), 1, (c)); + + +/* Fork and exec the program PGMNAME. + * + * If R_INFP is NULL connect stdin of the new process to /dev/null; if + * it is not NULL store the address of a pointer to a new estream + * there. If R_OUTFP is NULL connect stdout of the new process to + * /dev/null; if it is not NULL store the address of a pointer to a + * new estream there. If R_ERRFP is NULL connect stderr of the new + * process to /dev/null; if it is not NULL store the address of a + * pointer to a new estream there. On success the pid of the new + * process is stored at PID. On error -1 is stored at PID and if + * R_OUTFP or R_ERRFP are not NULL, NULL is stored there. + * + * The arguments for the process are expected in the NULL terminated + * array ARGV. The program name itself should not be included there. + * If PREEXEC is not NULL, the given function will be called right + * before the exec. + * + * IF EXCEPT is not NULL, it is expected to be an ordered list of file + * descriptors, terminated by an entry with the value (-1). These + * file descriptors won't be closed before spawning a new program. + * + * Returns 0 on success or an error code. Calling gpgrt_wait_process + * and gpgrt_release_process is required if the function succeeded. + * + * FLAGS is a bit vector: + * + * GPGRT_SPAWN_NONBLOCK + * If set the two output streams are created in non-blocking + * mode and the input stream is switched to non-blocking mode. + * This is merely a convenience feature because the caller + * could do the same with gpgrt_set_nonblock. Does not yet + * work for Windows. + * + * GPGRT_SPAWN_DETACHED + * If set the process will be started as a background process. + * This flag is only useful under W32 (but not W32CE) systems, + * so that no new console is created and pops up a console + * window when starting the server. Does not work on W32CE. + * + * GPGRT_SPAWN_RUN_ASFW + * On W32 (but not on W32CE) run AllowSetForegroundWindow for + * the child. Note that due to unknown problems this actually + * allows SetForegroundWindow for all children of this process. + */ +gpg_err_code_t +_gpgrt_spawn_process (const char *pgmname, const char *argv[], + int *execpt, void (*preexec)(void), unsigned int flags, + estream_t *r_infp, + estream_t *r_outfp, + estream_t *r_errfp, + pid_t *pid); + + +/* Simplified version of gpgrt_spawn_process. This function forks and + * then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout + * and ERRFD to stderr (any of them may be -1 to connect them to + * /dev/null). The arguments for the process are expected in the NULL + * terminated array ARGV. The program name itself should not be + * included there. Calling gpgrt_wait_process and + * gpgrt_release_process is required. Returns 0 on success or an + * error code. */ +gpg_err_code_t _gpgrt_spawn_process_fd (const char *pgmname, + const char *argv[], + int infd, int outfd, int errfd, + pid_t *pid); + +/* Spawn a new process and immediately detach from it. The name of + * the program to exec is PGMNAME and its arguments are in ARGV (the + * programname is automatically passed as first argument). + * Environment strings in ENVP are set. An error is returned if + * pgmname is not executable; to make this work it is necessary to + * provide an absolute file name. */ +gpg_err_code_t _gpgrt_spawn_process_detached (const char *pgmname, + const char *argv[], + const char *envp[] ); + +/* If HANG is true, waits for the process identified by PID to exit; + * if HANG is false, checks whether the process has terminated. + * PGMNAME should be the same as supplied to the spawn function and is + * only used for diagnostics. Return values: + * + * 0 + * The process exited successful. 0 is stored at R_EXITCODE. + * + * GPG_ERR_GENERAL + * The process exited without success. The exit code of process + * is then stored at R_EXITCODE. An exit code of -1 indicates + * that the process terminated abnormally (e.g. due to a signal). + * + * GPG_ERR_TIMEOUT + * The process is still running (returned only if HANG is false). + * + * GPG_ERR_INV_VALUE + * An invalid PID has been specified. + * + * Other error codes may be returned as well. Unless otherwise noted, + * -1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL + * if the exit code is not required (in that case an error message will + * be printed). Note that under Windows PID is not the process id but + * the handle of the process. */ +gpg_err_code_t _gpgrt_wait_process (const char *pgmname, pid_t pid, int hang, + int *r_exitcode); + +/* Like _gpgrt_wait_process, but for COUNT processes. */ +gpg_err_code_t _gpgrt_wait_processes (const char **pgmnames, pid_t *pids, + size_t count, int hang, int *r_exitcodes); + +/* Kill a process; that is send an appropriate signal to the process. + * gpgrt_wait_process must be called to actually remove the process + * from the system. An invalid PID is ignored. */ +void _gpgrt_kill_process (pid_t pid); + +/* Release the process identified by PID. This function is actually + * only required for Windows but it does not harm to always call it. + * It is a nop if PID is invalid. */ +void _gpgrt_release_process (pid_t pid); + + +/* + * Local prototypes for argparse. + */ +int _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts); +int _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, + const char *confname); +void _gpgrt_usage (int level); +const char *_gpgrt_strusage (int level); +void _gpgrt_set_strusage (const char *(*f)(int)); +void _gpgrt_set_usage_outfnc (int (*fnc)(int, const char *)); +void _gpgrt_set_fixed_string_mapper (const char *(*f)(const char*)); +void _gpgrt_set_confdir (int what, const char *name); + + +/* + * Various helper functions + */ +int _gpgrt_cmp_version (const char *a, const char *b, int level); + + + +/* + * Internal platform abstraction functions (sysutils.c) + */ + +/* Return true if FD is valid. */ +int _gpgrt_fd_valid_p (int fd); + +/* A getenv variant which returns a malloced copy. */ +char *_gpgrt_getenv (const char *name); + +/* A setenv variant which can be used for unsetenv by setting VALUE to + * NULL and OVERRIDE to true. */ +gpg_err_code_t _gpgrt_setenv (const char *name, + const char *value, int overwrite); + +/* A wrapper around mkdir using a string for the mode (permissions). */ +gpg_err_code_t _gpgrt_mkdir (const char *name, const char *modestr); + +/* A simple wrapper around chdir. */ +gpg_err_code_t _gpgrt_chdir (const char *name); + +/* Return the current WD as a malloced string. */ +char *_gpgrt_getcwd (void); + +/* Wrapper for Windows to allow utf8 file names. */ +gpg_err_code_t _gpgrt_access (const char *fname, int mode); + +/* Return the home directory of user NAME. */ +char *_gpgrt_getpwdir (const char *name); + +/* Return the account name of the current user. */ +char *_gpgrt_getusername (void); + +/* Expand and concat file name parts. */ +char *_gpgrt_vfnameconcat (int want_abs, const char *first_part, + va_list arg_ptr); +char *_gpgrt_fnameconcat (const char *first_part, + ... ) GPGRT_ATTR_SENTINEL(0); +char *_gpgrt_absfnameconcat (const char *first_part, + ... ) GPGRT_ATTR_SENTINEL(0); + + +/* + * Platform specific functions (Windows) + */ +#ifdef HAVE_W32_SYSTEM + +char *_gpgrt_w32_reg_query_string (const char *root, + const char *dir, + const char *name); + + +#endif /*HAVE_W32_SYSTEM*/ + +/* + * Missing functions implemented inline. + */ + +#ifndef HAVE_STPCPY +static GPG_ERR_INLINE char * +_gpgrt_stpcpy (char *a, const char *b) +{ + while (*b) + *a++ = *b++; + *a = 0; + return a; +} +#define stpcpy(a,b) _gpgrt_stpcpy ((a), (b)) +#endif /*!HAVE_STPCPY*/ + + +#endif /*_GPGRT_GPGRT_INT_H*/ diff --git a/comm/third_party/libgpg-error/src/gpgrt.m4 b/comm/third_party/libgpg-error/src/gpgrt.m4 new file mode 100644 index 0000000000..40fcd1f801 --- /dev/null +++ b/comm/third_party/libgpg-error/src/gpgrt.m4 @@ -0,0 +1,112 @@ +# gpgrt.m4 - autoconf macro to detect libgpgrt +# Copyright (C) 2002, 2003, 2004, 2011, 2014, 2017, 2018 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# SPDX-License-Identifier: FSFULLR +# +# Last-changed: 2018-11-13 +# Note: This is a kind of duplicate of gpg-error.m4 which uses the +# future name of libgpg-error to prepare for a smooth migration in +# some distant time. + +dnl AM_PATH_GPGRT([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl +dnl Test for libgpgrt and define GPGRT_CFLAGS, GPGRT_LIBS, +dnl GPGRT_MT_CFLAGS, and GPGRT_MT_LIBS. The _MT_ variants are +dnl used for programs requiring real multi thread support. +dnl +AC_DEFUN([AM_PATH_GPGRT], +[ AC_REQUIRE([AC_CANONICAL_HOST]) + if test "$prefix" = NONE ; then + prefix_option_expanded=/usr/local + else + prefix_option_expanded="$prefix" + fi + if test "$exec_prefix" = NONE ; then + exec_prefix_option_expanded=$prefix_option_expanded + else + exec_prefix_option_expanded=$(prefix=$prefix_option_expanded eval echo $exec_prefix) + fi + libdir_option_expanded=$(prefix=$prefix_option_expanded exec_prefix=$exec_prefix_option_expanded eval echo $libdir) + + if test -f $libdir_option_expanded/pkgconfig/gpg-error.pc; then + gpgrt_libdir=$libdir_option_expanded + else + if crt1_path=$(${CC:-cc} -print-file-name=crt1.o 2>/dev/null); then + if possible_libdir=$(cd ${crt1_path%/*} && pwd 2>/dev/null); then + if test -f $possible_libdir/pkgconfig/gpg-error.pc; then + gpgrt_libdir=$possible_libdir + fi + fi + fi + fi + + if test -n "$gpgrt_libdir"; then + AC_PATH_PROG(GPGRT_CONFIG, gpgrt-config, no) + if test "$GPGRT_CONFIG" != "no"; then + GPGRT_CONFIG="$GPGRT_CONFIG --libdir=$gpgrt_libdir" + fi + fi + min_gpgrt_version=ifelse([$1], ,1.33,$1) + AC_MSG_CHECKING(for GPG Runtime - version >= $min_gpgrt_version) + ok=no + if test x"$GPGRT_CONFIG" != x -a "$GPGRT_CONFIG" != "no" ; then + req_major=`echo $min_gpgrt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgrt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + gpgrt_config_version=`$GPGRT_CONFIG --version` + major=`echo $gpgrt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $gpgrt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -ge "$req_minor"; then + ok=yes + fi + fi + fi + fi + if test $ok = yes; then + GPGRT_CFLAGS=`$GPGRT_CONFIG --cflags` + GPGRT_LIBS=`$GPGRT_CONFIG --libs` + GPGRT_MT_CFLAGS=`$GPGRT_CONFIG --variable=mtcflags 2>/dev/null` + GPGRT_MT_CFLAGS="$GPGRT_CFLAGS${GPGRT_CFLAGS:+ }$GPGRT_MT_CFLAGS" + GPGRT_MT_LIBS=`$GPGRT_CONFIG --variable=mtlibs 2>/dev/null` + GPGRT_MT_LIBS="$GPGRT_LIBS${GPGRT_LIBS:+ }$GPGRT_MT_LIBS" + AC_MSG_RESULT([yes ($gpgrt_config_version)]) + ifelse([$2], , :, [$2]) + gpgrt_config_host=`$GPGRT_CONFIG --variable=host 2>/dev/null || echo none` + if test x"$gpgrt_config_host" != xnone ; then + if test x"$gpgrt_config_host" != x"$host" ; then + AC_MSG_WARN([[ +*** +*** The config script "$GPGRT_CONFIG" is for $gpgrt_config_host +*** and thus may not match the used host $host. +***]]) + gpg_config_script_warn="$gpg_config_script_warn libgpgrt" + fi + fi + else + GPGRT_CFLAGS="" + GPGRT_LIBS="" + GPGRT_MT_CFLAGS="" + GPGRT_MT_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGRT_CFLAGS) + AC_SUBST(GPGRT_LIBS) + AC_SUBST(GPGRT_MT_CFLAGS) + AC_SUBST(GPGRT_MT_LIBS) +]) diff --git a/comm/third_party/libgpg-error/src/init.c b/comm/third_party/libgpg-error/src/init.c new file mode 100644 index 0000000000..623968219f --- /dev/null +++ b/comm/third_party/libgpg-error/src/init.c @@ -0,0 +1,741 @@ +/* init.c - Initialize the GnuPG error library. + Copyright (C) 2005, 2010 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "gpgrt-int.h" +#include "gettext.h" +#include "init.h" + +#ifdef HAVE_W32CE_SYSTEM +# include "mkw32errmap.map.c" /* Generated map_w32codes () */ +# ifndef TLS_OUT_OF_INDEXES +# define TLS_OUT_OF_INDEXES 0xFFFFFFFF +# endif +# ifndef __MINGW32CE__ +# /* Replace the Mingw32CE provided abort function. */ +# define abort() do { TerminateProcess (GetCurrentProcess(), 8); } while (0) +# endif +#endif + + +/* Locale directory support. */ + +#if HAVE_W32_SYSTEM + +#include + +static int tls_index = TLS_OUT_OF_INDEXES; /* Index for the TLS functions. */ + +static char *get_locale_dir (void); +static void drop_locale_dir (char *locale_dir); + +#else /*!HAVE_W32_SYSTEM*/ + +#define get_locale_dir() LOCALEDIR +#define drop_locale_dir(dir) + +#endif /*!HAVE_W32_SYSTEM*/ + + +/* The list of emergency cleanup functions; see _gpgrt_abort and + * _gpgrt_add_emergency_cleanup. */ +struct emergency_cleanup_item_s; +typedef struct emergency_cleanup_item_s *emergency_cleanup_item_t; +struct emergency_cleanup_item_s +{ + emergency_cleanup_item_t next; + void (*func) (void); +}; +static emergency_cleanup_item_t emergency_cleanup_list; + + + + +/* The realloc function as set by gpgrt_set_alloc_func. */ +static void *(*custom_realloc)(void *a, size_t n); + + + +static void +real_init (void) +{ +#ifdef ENABLE_NLS + char *locale_dir; + + /* We only have to bind our locale directory to our text domain. */ + locale_dir = get_locale_dir (); + if (locale_dir) + { + bindtextdomain (PACKAGE, locale_dir); + drop_locale_dir (locale_dir); + } +#endif + _gpgrt_estream_init (); +} + +/* Initialize the library. This function should be run early. */ +gpg_error_t +_gpg_err_init (void) +{ +#ifdef HAVE_W32_SYSTEM +# ifdef DLL_EXPORT + /* We always have a constructor and thus this function is called + automatically. Due to the way the C init code of mingw works, + the constructors are called before our DllMain function is + called. The problem with that is that the TLS has not been setup + and w32-gettext.c requires TLS. To solve this we do nothing here + but call the actual init code from our DllMain. */ +# else /*!DLL_EXPORT*/ + /* Note that if the TLS is actually used, we can't release the TLS + as there is no way to know when a thread terminates (i.e. no + thread-specific-atexit). You are really better off to use the + DLL! */ + if (tls_index == TLS_OUT_OF_INDEXES) + { + tls_index = TlsAlloc (); + if (tls_index == TLS_OUT_OF_INDEXES) + { + /* No way to continue - commit suicide. */ + _gpgrt_abort (); + } + _gpg_w32__init_gettext_module (); + real_init (); + } +# endif /*!DLL_EXPORT*/ +#else + real_init (); +#endif + return 0; +} + + +/* Deinitialize libgpg-error. This function is only used in special + circumstances. No gpg-error function should be used after this + function has been called. A value of 0 passed for MODE + deinitializes the entire libgpg-error, a value of 1 releases + resources allocated for the current thread and only that thread may + not anymore access libgpg-error after such a call. Under Windows + this function may be called from the DllMain function of a DLL + which statically links to libgpg-error. */ +void +_gpg_err_deinit (int mode) +{ +#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT) + struct tls_space_s *tls; + + tls = TlsGetValue (tls_index); + if (tls) + { + TlsSetValue (tls_index, NULL); + LocalFree (tls); + } + + if (mode == 0) + { + TlsFree (tls_index); + tls_index = TLS_OUT_OF_INDEXES; + } +#else + (void)mode; +#endif +} + + +/* Add the emergency cleanup function F to the list of those function. + * If the a function with that address has already been registered, it + * is not added a second time. These emergency functions are called + * whenever gpgrt_abort is called and at no other place. Like signal + * handles the emergency cleanup functions shall not call any + * non-trivial functions and return as soon as possible. They allow + * to cleanup internal states which should not go into a core dumps or + * similar. This is independent of any atexit functions. We don't + * use locks here because in an emergency case we can't use them + * anyway. */ +void +_gpgrt_add_emergency_cleanup (void (*f)(void)) +{ + emergency_cleanup_item_t item; + + for (item = emergency_cleanup_list; item; item = item->next) + if (item->func == f) + return; /* Function has already been registered. */ + + /* We use a standard malloc here. */ + item = malloc (sizeof *item); + if (item) + { + item->func = f; + item->next = emergency_cleanup_list; + emergency_cleanup_list = item; + } + else + _gpgrt_log_fatal ("out of core in gpgrt_add_emergency_cleanup\n"); +} + + +/* Run the emergency handlers. No locks are used because we are anyway + * in an emergency state. We also can't release any memory. */ +static void +run_emergency_cleanup (void) +{ + emergency_cleanup_item_t next; + void (*f)(void); + + while (emergency_cleanup_list) + { + next = emergency_cleanup_list->next; + f = emergency_cleanup_list->func; + emergency_cleanup_list->func = NULL; + emergency_cleanup_list = next; + if (f) + f (); + } +} + + +/* Wrapper around abort to be able to run all emergency cleanup + * functions. */ +void +_gpgrt_abort (void) +{ + run_emergency_cleanup (); + abort (); +} + + + +/* Register F as allocation function. This function is used for all + APIs which return an allocated buffer. F needs to have standard + realloc semantics. It should be called as early as possible and + not changed later. */ +void +_gpgrt_set_alloc_func (void *(*f)(void *a, size_t n)) +{ + custom_realloc = f; +} + + +/* The realloc to be used for data returned by the public API. */ +void * +_gpgrt_realloc (void *a, size_t n) +{ + if (custom_realloc) + return custom_realloc (a, n); + + if (!n) + { + free (a); + return NULL; + } + + if (!a) + return malloc (n); + + return realloc (a, n); +} + + +/* This is safe version of realloc useful for reallocing a calloced + * array. There are two ways to call it: The first example + * reallocates the array A to N elements each of SIZE but does not + * clear the newly allocated elements: + * + * p = gpgrt_reallocarray (a, n, n, nsize); + * + * Note that when NOLD is larger than N no cleaning is needed anyway. + * The second example reallocates an array of size NOLD to N elements + * each of SIZE but clear the newly allocated elements: + * + * p = gpgrt_reallocarray (a, nold, n, nsize); + * + * Note that gpgrt_reallocarray (NULL, 0, n, nsize) is equivalent to + * _gpgrt_calloc (n, nsize). + * + */ +void * +_gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size) +{ + size_t oldbytes, bytes; + char *p; + + bytes = nmemb * size; /* size_t is unsigned so the behavior on overflow + * is defined. */ + if (size && bytes / size != nmemb) + { + _gpg_err_set_errno (ENOMEM); + return NULL; + } + + p = _gpgrt_realloc (a, bytes); + if (p && oldnmemb < nmemb) + { + /* OLDNMEMBS is lower than NMEMB thus the user asked for a + calloc. Clear all newly allocated members. */ + oldbytes = oldnmemb * size; + if (size && oldbytes / size != oldnmemb) + { + xfree (p); + _gpg_err_set_errno (ENOMEM); + return NULL; + } + memset (p + oldbytes, 0, bytes - oldbytes); + } + return p; +} + + +/* The malloc to be used for data returned by the public API. */ +void * +_gpgrt_malloc (size_t n) +{ + if (!n) + n++; + return _gpgrt_realloc (NULL, n); +} + + +void * +_gpgrt_calloc (size_t n, size_t m) +{ + size_t bytes; + void *p; + + bytes = n * m; /* size_t is unsigned so the behavior on overflow is + defined. */ + if (m && bytes / m != n) + { + _gpg_err_set_errno (ENOMEM); + return NULL; + } + + p = _gpgrt_realloc (NULL, bytes); + if (p) + memset (p, 0, bytes); + return p; +} + + +char * +_gpgrt_strdup (const char *string) +{ + size_t len = strlen (string); + char *p; + + p = _gpgrt_realloc (NULL, len + 1); + if (p) + strcpy (p, string); + return p; +} + + +/* Helper for _gpgrt_strconcat and gpgrt_strconcat. */ +char * +_gpgrt_strconcat_core (const char *s1, va_list arg_ptr) +{ + const char *argv[48]; + size_t argc; + size_t needed; + char *buffer, *p; + + argc = 0; + argv[argc++] = s1; + needed = strlen (s1); + while (((argv[argc] = va_arg (arg_ptr, const char *)))) + { + needed += strlen (argv[argc]); + if (argc >= DIM (argv)-1) + { + _gpg_err_set_errno (EINVAL); + return NULL; + } + argc++; + } + needed++; + buffer = _gpgrt_malloc (needed); + if (buffer) + { + for (p = buffer, argc=0; argv[argc]; argc++) + p = stpcpy (p, argv[argc]); + } + return buffer; +} + + +char * +_gpgrt_strconcat (const char *s1, ...) +{ + va_list arg_ptr; + char *result; + + if (!s1) + result = _gpgrt_strdup (""); + else + { + va_start (arg_ptr, s1); + result = _gpgrt_strconcat_core (s1, arg_ptr); + va_end (arg_ptr); + } + return result; +} + + +/* The free to be used for data returned by the public API. */ +void +_gpgrt_free (void *a) +{ + _gpgrt_realloc (a, 0); +} + + +void +_gpg_err_set_errno (int err) +{ +#ifdef HAVE_W32CE_SYSTEM + SetLastError (err); +#else /*!HAVE_W32CE_SYSTEM*/ + errno = err; +#endif /*!HAVE_W32CE_SYSTEM*/ +} + + + +/* Internal tracing functions. Except for TRACE_FP we use flockfile + * and funlockfile to protect their use. + * + * Warning: Take care with the trace functions - they may not use any + * of our services, in particular not the syscall clamp mechanism for + * reasons explained in w32-stream.c:create_reader. */ +static FILE *trace_fp; +static int trace_save_errno; +static int trace_with_errno; +static const char *trace_arg_module; +static const char *trace_arg_file; +static int trace_arg_line; +static int trace_missing_lf; +static int trace_prefix_done; + +void +_gpgrt_internal_trace_begin (const char *module, const char *file, int line, + int with_errno) +{ + int save_errno = errno; + + if (!trace_fp) + { + FILE *fp; + const char *s = getenv ("GPGRT_TRACE_FILE"); + + if (!s || !(fp = fopen (s, "wb"))) + fp = stderr; + trace_fp = fp; + } + +#ifdef HAVE_FLOCKFILE + flockfile (trace_fp); +#endif + trace_save_errno = save_errno; + trace_with_errno = with_errno; + trace_arg_module = module; + trace_arg_file = file; + trace_arg_line = line; + trace_missing_lf = 0; + trace_prefix_done = 0; +} + +static void +print_internal_trace_prefix (void) +{ + if (!trace_prefix_done) + { + trace_prefix_done = 1; + fprintf (trace_fp, "%s:%s:%d: ", + trace_arg_module,/* npth_is_protected ()?"":"^",*/ + trace_arg_file, trace_arg_line); + } +} + +static void +do_internal_trace (const char *format, va_list arg_ptr) +{ + print_internal_trace_prefix (); + vfprintf (trace_fp, format, arg_ptr); + if (trace_with_errno) + fprintf (trace_fp, " errno=%s", strerror (trace_save_errno)); + if (*format && format[strlen(format)-1] != '\n') + fputc ('\n', trace_fp); +} + +void +_gpgrt_internal_trace_printf (const char *format, ...) +{ + va_list arg_ptr; + + print_internal_trace_prefix (); + va_start (arg_ptr, format) ; + vfprintf (trace_fp, format, arg_ptr); + va_end (arg_ptr); + trace_missing_lf = (*format && format[strlen(format)-1] != '\n'); +} + + +void +_gpgrt_internal_trace (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format) ; + do_internal_trace (format, arg_ptr); + va_end (arg_ptr); +} + + +void +_gpgrt_internal_trace_end (void) +{ + int save_errno = trace_save_errno; + + if (trace_missing_lf) + fputc ('\n', trace_fp); +#ifdef HAVE_FLOCKFILE + funlockfile (trace_fp); +#endif + errno = save_errno; +} + + + +#ifdef HAVE_W32_SYSTEM +/***************************************** + ******** Below is only Windows code. **** + *****************************************/ + +static char * +get_locale_dir (void) +{ + static wchar_t moddir[MAX_PATH+5]; + char *result, *p; + int nbytes; + + if (!GetModuleFileNameW (NULL, moddir, MAX_PATH)) + *moddir = 0; + +#define SLDIR "\\share\\locale" + if (*moddir) + { + nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL); + if (nbytes < 0) + return NULL; + + result = malloc (nbytes + strlen (SLDIR) + 1); + if (result) + { + nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, + result, nbytes, NULL, NULL); + if (nbytes < 0) + { + free (result); + result = NULL; + } + else + { + p = strrchr (result, '\\'); + if (p) + *p = 0; + /* If we are installed below "bin" strip that part and + use the top directory instead. + + Background: Under Windows we don't install GnuPG + below bin/ but in the top directory with only share/, + lib/, and etc/ below it. One of the reasons is to + keep the the length of the filenames at bay so not to + increase the limited length of the PATH envvar. + Another and more important reason, however, is that + the very first GPG versions on W32 were installed + into a flat directory structure and for best + compatibility with these versions we didn't changed + that later. For WindowsCE we can right away install + it under bin, though. The hack with detection of the + bin directory part allows us to eventually migrate to + such a directory layout under plain Windows without + the need to change libgpg-error. */ + p = strrchr (result, '\\'); + if (p && !strcmp (p+1, "bin")) + *p = 0; + /* Append the static part. */ + strcat (result, SLDIR); + } + } + } + else /* Use the old default value. */ + { + result = malloc (10 + strlen (SLDIR) + 1); + if (result) + { + strcpy (result, "c:\\gnupg"); + strcat (result, SLDIR); + } + } +#undef SLDIR + return result; +} + + +static void +drop_locale_dir (char *locale_dir) +{ + free (locale_dir); +} + + +/* Return the tls object. This function is guaranteed to return a + valid non-NULL object. */ +struct tls_space_s * +get_tls (void) +{ + struct tls_space_s *tls; + + tls = TlsGetValue (tls_index); + if (!tls) + { + /* Called by a thread which existed before this DLL was loaded. + Allocate the space. */ + tls = LocalAlloc (LPTR, sizeof *tls); + if (!tls) + { + /* No way to continue - commit suicide. */ + _gpgrt_abort (); + } + tls->gt_use_utf8 = 0; + TlsSetValue (tls_index, tls); + } + + return tls; +} + + +/* Return the value of the ERRNO variable. This needs to be a + function so that we can have a per-thread ERRNO. This is used only + on WindowsCE because that OS misses an errno. */ +#ifdef HAVE_W32CE_SYSTEM +int +_gpg_w32ce_get_errno (void) +{ + return map_w32codes ( GetLastError () ); +} +#endif /*HAVE_W32CE_SYSTEM*/ + + +/* Replacement strerror function for WindowsCE. */ +#ifdef HAVE_W32CE_SYSTEM +char * +_gpg_w32ce_strerror (int err) +{ + struct tls_space_s *tls = get_tls (); + wchar_t tmpbuf[STRBUFFER_SIZE]; + int n; + + if (err == -1) + err = _gpg_w32ce_get_errno (); + + /* Note: On a German HTC Touch Pro2 device I also tried + LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned + English messages. */ + if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + tmpbuf, STRBUFFER_SIZE -1, + NULL)) + { + n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1, + tls->strerror_buffer, + sizeof tls->strerror_buffer -1, + NULL, NULL); + } + else + n = -1; + + if (n < 0) + snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1, + "[w32err=%d]", err); + return tls->strerror_buffer; +} +#endif /*HAVE_W32CE_SYSTEM*/ + + +/* Entry point called by the DLL loader. */ +#ifdef DLL_EXPORT +int WINAPI +DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved) +{ + struct tls_space_s *tls; + (void)reserved; + (void)hinst; + + switch (reason) + { + case DLL_PROCESS_ATTACH: + tls_index = TlsAlloc (); + if (tls_index == TLS_OUT_OF_INDEXES) + return FALSE; +#ifndef _GPG_ERR_HAVE_CONSTRUCTOR + /* If we have not constructors (e.g. MSC) we call it here. */ + _gpg_w32__init_gettext_module (); +#endif + /* fallthru. */ + case DLL_THREAD_ATTACH: + tls = LocalAlloc (LPTR, sizeof *tls); + if (!tls) + return FALSE; + tls->gt_use_utf8 = 0; + TlsSetValue (tls_index, tls); + if (reason == DLL_PROCESS_ATTACH) + { + real_init (); + } + break; + + case DLL_THREAD_DETACH: + tls = TlsGetValue (tls_index); + if (tls) + LocalFree (tls); + break; + + case DLL_PROCESS_DETACH: + tls = TlsGetValue (tls_index); + if (tls) + LocalFree (tls); + TlsFree (tls_index); + break; + + default: + break; + } + + return TRUE; +} +#endif /*DLL_EXPORT*/ + +#endif /*HAVE_W32_SYSTEM*/ diff --git a/comm/third_party/libgpg-error/src/init.h b/comm/third_party/libgpg-error/src/init.h new file mode 100644 index 0000000000..90a716a17d --- /dev/null +++ b/comm/third_party/libgpg-error/src/init.h @@ -0,0 +1,70 @@ +/* init.h - Declarations for init.c + Copyright (C) 2010 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#ifndef INIT_H +#define INIT_H + +#if HAVE_W32_SYSTEM + +/* Forward declaration - defined in w32-gettext.c. */ +struct loaded_domain; + +/* An item for a linked list of loaded domains. */ +struct domainlist_s +{ + struct domainlist_s *next; + char *dname; /* Directory name for the mo file. */ + char *fname; /* File name for the MO file. */ + int load_failed; /* True if loading the domain failed. */ + struct loaded_domain *domain; /* NULL if not loaded. Never changed + once set to non-NULL. */ + char name[1]; /* Name of the domain. Never changed + once set. */ +}; + + + +/* 119 bytes for an error message should be enough. With this size we + can assume that the allocation does not take up more than 128 bytes + per thread. Note that this is only used for W32CE. */ +#define STRBUFFER_SIZE 120 + +/* The TLS space definition. */ +struct tls_space_s +{ + /* Flag used by w32-gettext. */ + int gt_use_utf8; + +#ifdef HAVE_W32CE_SYSTEM + char strerror_buffer[STRBUFFER_SIZE]; +#endif +}; + +/* Return the TLS. */ +struct tls_space_s *get_tls (void); + + +/* Explicit constructor for w32-gettext.c */ +#ifndef DLL_EXPORT +void _gpg_w32__init_gettext_module (void); +#endif + +#endif /*HAVE_W32_SYSTEM*/ + +#endif /*INIT_H*/ diff --git a/comm/third_party/libgpg-error/src/lock.h b/comm/third_party/libgpg-error/src/lock.h new file mode 100644 index 0000000000..a830b36b07 --- /dev/null +++ b/comm/third_party/libgpg-error/src/lock.h @@ -0,0 +1,24 @@ +/* lock.h - Declarations for *-lock.c + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#ifndef LOCK_H +#define LOCK_H + + +#endif /*LOCK_H*/ diff --git a/comm/third_party/libgpg-error/src/logging.c b/comm/third_party/libgpg-error/src/logging.c new file mode 100644 index 0000000000..e4b7e401d0 --- /dev/null +++ b/comm/third_party/libgpg-error/src/logging.c @@ -0,0 +1,1341 @@ +/* logging.c - Useful logging functions + * Copyright (C) 1998-2001, 2003-2006, 2009-2010, + * 2017 Free Software Foundation, Inc. + * Copyright (C) 1998-1999, 2001-2006, 2008-2017 Werner Koch + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + * + * This file was originally a part of GnuPG. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_W32_SYSTEM +# ifdef HAVE_WINSOCK2_H +# include +# endif +# include +#else /*!HAVE_W32_SYSTEM*/ +# include +# include +# include +# include +#endif /*!HAVE_W32_SYSTEM*/ +#include +#include +/* #include */ + +#define _GPGRT_NEED_AFLOCAL 1 +#include "gpgrt-int.h" + + +#ifdef HAVE_W32_SYSTEM +# ifndef S_IRWXG +# define S_IRGRP S_IRUSR +# define S_IWGRP S_IWUSR +# endif +# ifndef S_IRWXO +# define S_IROTH S_IRUSR +# define S_IWOTH S_IWUSR +# endif +#endif + + +#ifdef HAVE_W32CE_SYSTEM +# define isatty(a) (0) +#endif + +#undef WITH_IPV6 +#if defined (AF_INET6) && defined(PF_INET) \ + && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON) +# define WITH_IPV6 1 +#endif + +#ifndef EAFNOSUPPORT +# define EAFNOSUPPORT EINVAL +#endif +#ifndef INADDR_NONE /* Slowaris is missing that. */ +#define INADDR_NONE ((unsigned long)(-1)) +#endif /*INADDR_NONE*/ + +#ifdef HAVE_W32_SYSTEM +#define sock_close(a) closesocket(a) +#else +#define sock_close(a) close(a) +#endif + + +static estream_t logstream; +static int log_socket = -1; +static char prefix_buffer[80]; +static int with_time; +static int with_prefix; +static int with_pid; +#ifdef HAVE_W32_SYSTEM +static int no_registry; +#endif +static int (*get_pid_suffix_cb)(unsigned long *r_value); +static const char * (*socket_dir_cb)(void); +static int running_detached; +static int force_prefixes; + +static int missing_lf; +static int errorcount; + + +/* An object to convey data to the fmt_string_filter. */ +struct fmt_string_filter_s +{ + char *last_result; +}; + + + +/* Get the error count as maintained by the log fucntions. With CLEAR + * set reset the counter. */ +int +_gpgrt_get_errorcount (int clear) +{ + int n = errorcount; + if (clear) + errorcount = 0; + return n; +} + + +/* Increment the error count as maintained by the log functions. */ +void +_gpgrt_inc_errorcount (void) +{ + /* Protect against counter overflow. */ + if (errorcount < 30000) + errorcount++; +} + + +/* The following 3 functions are used by _gpgrt_fopencookie to write logs + to a socket. */ +struct fun_cookie_s +{ + int fd; + int quiet; + int want_socket; + int is_socket; +#ifdef HAVE_W32CE_SYSTEM + int use_writefile; +#endif + char name[1]; +}; + + +/* Write NBYTES of BUFFER to file descriptor FD. */ +static int +writen (int fd, const void *buffer, size_t nbytes, int is_socket) +{ + const char *buf = buffer; + size_t nleft = nbytes; + int nwritten; +#ifndef HAVE_W32_SYSTEM + (void)is_socket; /* Not required. */ +#endif + + while (nleft > 0) + { +#ifdef HAVE_W32_SYSTEM + if (is_socket) + nwritten = send (fd, buf, nleft, 0); + else +#endif + nwritten = write (fd, buf, nleft); + + if (nwritten < 0 && errno == EINTR) + continue; + if (nwritten < 0) + return -1; + nleft -= nwritten; + buf = buf + nwritten; + } + + return 0; +} + + +/* Returns true if STR represents a valid port number in decimal + notation and no garbage is following. */ +static int +parse_portno (const char *str, unsigned short *r_port) +{ + unsigned int value; + + for (value=0; *str && (*str >= '0' && *str <= '9'); str++) + { + value = value * 10 + (*str - '0'); + if (value > 65535) + return 0; + } + if (*str || !value) + return 0; + + *r_port = value; + return 1; +} + + +static gpgrt_ssize_t +fun_writer (void *cookie_arg, const void *buffer, size_t size) +{ + struct fun_cookie_s *cookie = cookie_arg; + + /* FIXME: Use only estream with a callback for socket writing. This + avoids the ugly mix of fd and estream code. */ + + /* Note that we always try to reconnect to the socket but print + error messages only the first time an error occurred. If + RUNNING_DETACHED is set we don't fall back to stderr and even do + not print any error messages. This is needed because detached + processes often close stderr and by writing to file descriptor 2 + we might send the log message to a file not intended for logging + (e.g. a pipe or network connection). */ + if (cookie->want_socket && cookie->fd == -1) + { +#ifdef WITH_IPV6 + struct sockaddr_in6 srvr_addr_in6; +#endif + struct sockaddr_in srvr_addr_in; +#ifndef HAVE_W32_SYSTEM + struct sockaddr_un srvr_addr_un; +#endif + const char *name_for_err = ""; + size_t addrlen; + struct sockaddr *srvr_addr = NULL; + unsigned short port = 0; + int af = AF_LOCAL; + int pf = PF_LOCAL; + const char *name = cookie->name; + + /* Not yet open or meanwhile closed due to an error. */ + cookie->is_socket = 0; + + /* Check whether this is a TCP socket or a local socket. */ + if (!strncmp (name, "tcp://", 6) && name[6]) + { + name += 6; + af = AF_INET; + pf = PF_INET; + } +#ifndef HAVE_W32_SYSTEM + else if (!strncmp (name, "socket://", 9)) + name += 9; +#endif + + if (af == AF_LOCAL) + { + addrlen = 0; +#ifndef HAVE_W32_SYSTEM + memset (&srvr_addr, 0, sizeof srvr_addr); + srvr_addr_un.sun_family = af; + if (!*name) + { + if ((name = socket_dir_cb ()) && *name + && strlen (name) + 7 < sizeof (srvr_addr_un.sun_path)-1) + { + strncpy (srvr_addr_un.sun_path, + name, sizeof (srvr_addr_un.sun_path)-1); + strcat (srvr_addr_un.sun_path, "/S.log"); + srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0; + srvr_addr = (struct sockaddr *)&srvr_addr_un; + addrlen = SUN_LEN (&srvr_addr_un); + name_for_err = srvr_addr_un.sun_path; + } + } + else + { + if (strlen (name) < sizeof (srvr_addr_un.sun_path)-1) + { + strncpy (srvr_addr_un.sun_path, + name, sizeof (srvr_addr_un.sun_path)-1); + srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0; + srvr_addr = (struct sockaddr *)&srvr_addr_un; + addrlen = SUN_LEN (&srvr_addr_un); + } + } +#endif /*!HAVE_W32SYSTEM*/ + } + else + { + char *addrstr, *p; +#ifdef HAVE_INET_PTON + void *addrbuf = NULL; +#endif /*HAVE_INET_PTON*/ + + addrstr = _gpgrt_malloc (strlen (name) + 1); + if (!addrstr) + addrlen = 0; /* This indicates an error. */ + else if (*name == '[') + { + /* Check for IPv6 literal address. */ + strcpy (addrstr, name+1); + p = strchr (addrstr, ']'); + if (!p || p[1] != ':' || !parse_portno (p+2, &port)) + { + _gpg_err_set_errno (EINVAL); + addrlen = 0; + } + else + { + *p = 0; +#ifdef WITH_IPV6 + af = AF_INET6; + pf = PF_INET6; + memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6); + srvr_addr_in6.sin6_family = af; + srvr_addr_in6.sin6_port = htons (port); +#ifdef HAVE_INET_PTON + addrbuf = &srvr_addr_in6.sin6_addr; +#endif /*HAVE_INET_PTON*/ + srvr_addr = (struct sockaddr *)&srvr_addr_in6; + addrlen = sizeof srvr_addr_in6; +#else + _gpg_err_set_errno (EAFNOSUPPORT); + addrlen = 0; +#endif + } + } + else + { + /* Check for IPv4 literal address. */ + strcpy (addrstr, name); + p = strchr (addrstr, ':'); + if (!p || !parse_portno (p+1, &port)) + { + _gpg_err_set_errno (EINVAL); + addrlen = 0; + } + else + { + *p = 0; + memset (&srvr_addr_in, 0, sizeof srvr_addr_in); + srvr_addr_in.sin_family = af; + srvr_addr_in.sin_port = htons (port); +#ifdef HAVE_INET_PTON + addrbuf = &srvr_addr_in.sin_addr; +#endif /*HAVE_INET_PTON*/ + srvr_addr = (struct sockaddr *)&srvr_addr_in; + addrlen = sizeof srvr_addr_in; + } + } + + if (addrlen) + { +#ifdef HAVE_INET_PTON + if (inet_pton (af, addrstr, addrbuf) != 1) + addrlen = 0; +#else /*!HAVE_INET_PTON*/ + /* We need to use the old function. If we are here v6 + support isn't enabled anyway and thus we can do fine + without. Note that Windows has a compatible inet_pton + function named inetPton, but only since Vista. */ + srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr); + if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE) + addrlen = 0; +#endif /*!HAVE_INET_PTON*/ + } + + _gpgrt_free (addrstr); + } + + cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1; + if (cookie->fd == -1) + { + if (!cookie->quiet && !running_detached + && isatty (_gpgrt_fileno (es_stderr))) + _gpgrt_fprintf (es_stderr, + "failed to create socket for logging: %s\n", + strerror (errno)); + } + else + { + if (connect (cookie->fd, srvr_addr, addrlen) == -1) + { + if (!cookie->quiet && !running_detached + && isatty (_gpgrt_fileno (es_stderr))) + _gpgrt_fprintf (es_stderr, "can't connect to '%s%s': %s\n", + cookie->name, name_for_err, strerror(errno)); + sock_close (cookie->fd); + cookie->fd = -1; + } + } + + if (cookie->fd == -1) + { + if (!running_detached) + { + /* Due to all the problems with apps not running + detached but being called with stderr closed or used + for a different purposes, it does not make sense to + switch to stderr. We therefore disable it. */ + if (!cookie->quiet) + { + /* fputs ("switching logging to stderr\n", stderr);*/ + cookie->quiet = 1; + } + cookie->fd = -1; /*fileno (stderr);*/ + } + } + else /* Connection has been established. */ + { + cookie->quiet = 0; + cookie->is_socket = 1; + } + } + + log_socket = cookie->fd; + if (cookie->fd != -1) + { +#ifdef HAVE_W32CE_SYSTEM + if (cookie->use_writefile) + { + DWORD nwritten; + + WriteFile ((HANDLE)cookie->fd, buffer, size, &nwritten, NULL); + return (gpgrt_ssize_t)size; /* Okay. */ + } +#endif + if (!writen (cookie->fd, buffer, size, cookie->is_socket)) + return (gpgrt_ssize_t)size; /* Okay. */ + } + + if (!running_detached && cookie->fd != -1 + && isatty (_gpgrt_fileno (es_stderr))) + { + if (*cookie->name) + _gpgrt_fprintf (es_stderr, "error writing to '%s': %s\n", + cookie->name, strerror(errno)); + else + _gpgrt_fprintf (es_stderr, "error writing to file descriptor %d: %s\n", + cookie->fd, strerror(errno)); + } + if (cookie->is_socket && cookie->fd != -1) + { + sock_close (cookie->fd); + cookie->fd = -1; + log_socket = -1; + } + + return (gpgrt_ssize_t)size; +} + + +static int +fun_closer (void *cookie_arg) +{ + struct fun_cookie_s *cookie = cookie_arg; + + if (cookie->fd != -1 && cookie->fd != 2) + sock_close (cookie->fd); + _gpgrt_free (cookie); + log_socket = -1; + return 0; +} + + +/* Common function to either set the logging to a file or a file + descriptor. */ +static void +set_file_fd (const char *name, int fd, estream_t stream) +{ + estream_t fp; + int want_socket = 0; +#ifdef HAVE_W32CE_SYSTEM + int use_writefile = 0; +#endif + struct fun_cookie_s *cookie; + + /* Close an open log stream. */ + if (logstream) + { + if (logstream != es_stderr) + _gpgrt_fclose (logstream); + logstream = NULL; + } + + if (stream) + { + /* We don't use a cookie to log directly to a stream. */ + fp = stream; + goto leave; + } + + /* Figure out what kind of logging we want. */ + if (name && !strcmp (name, "-")) + { + name = NULL; + fd = _gpgrt_fileno (es_stderr); + } + + if (name && !strncmp (name, "tcp://", 6) && name[6]) + want_socket = 1; +#ifndef HAVE_W32_SYSTEM + else if (name && !strncmp (name, "socket://", 9)) + want_socket = 2; +#endif /*HAVE_W32_SYSTEM*/ +#ifdef HAVE_W32CE_SYSTEM + else if (name && !strcmp (name, "GPG2:")) + { + HANDLE hd; + + ActivateDevice (L"Drivers\\"GNUPG_NAME"_Log", 0); + /* Ignore a filename and write the debug output to the GPG2: + device. */ + hd = CreateFile (L"GPG2:", GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + fd = (hd == INVALID_HANDLE_VALUE)? -1 : (int)hd; + name = NULL; + force_prefixes = 1; + use_writefile = 1; + } +#endif /*HAVE_W32CE_SYSTEM*/ + + /* Setup a new stream. */ + + cookie = _gpgrt_malloc (sizeof *cookie + (name? strlen (name):0)); + if (!cookie) + return; /* oops */ + strcpy (cookie->name, name? name:""); + cookie->quiet = 0; + cookie->is_socket = 0; + cookie->want_socket = want_socket; +#ifdef HAVE_W32CE_SYSTEM + cookie->use_writefile = use_writefile; +#endif + if (!name) + cookie->fd = fd; + else if (want_socket) + cookie->fd = -1; + else + { + do + cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT, + (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)); + while (cookie->fd == -1 && errno == EINTR); + } + log_socket = cookie->fd; + + { + es_cookie_io_functions_t io = { NULL }; + io.func_write = fun_writer; + io.func_close = fun_closer; + + fp = _gpgrt_fopencookie (cookie, "w", io); + } + + /* On error default to a stderr based estream. */ + if (!fp) + fp = es_stderr; + + leave: + _gpgrt_setvbuf (fp, NULL, _IOLBF, 0); + + logstream = fp; + + /* We always need to print the prefix and the pid for socket mode, + so that the server reading the socket can do something + meaningful. */ + force_prefixes = want_socket; + + missing_lf = 0; +} + + +/* Set the file to write log to. The special names NULL and "-" may + * be used to select stderr and names formatted like + * "socket:///home/foo/mylogs" may be used to write the logging to the + * socket "/home/foo/mylogs". If the connection to the socket fails + * or a write error is detected, the function writes to stderr and + * tries the next time again to connect the socket. Calling this + * function with (NULL, NULL, -1) sets the default sink. + * Warning: This function is not thread-safe. + */ +void +_gpgrt_log_set_sink (const char *name, estream_t stream, int fd) +{ + if (name && !stream && fd == -1) + set_file_fd (name, -1, NULL); + else if (!name && !stream && fd != -1) + { + if (!_gpgrt_fd_valid_p (fd)) + _gpgrt_log_fatal ("gpgrt_log_set_sink: fd is invalid: %s\n", + strerror (errno)); + set_file_fd (NULL, fd, NULL); + } + else if (!name && stream && fd == -1) + { + set_file_fd (NULL, -1, stream); + } + else /* default */ + set_file_fd ("-", -1, NULL); +} + + +/* Set a function to retrieve the directory name of a socket if + * only "socket://" has been given to log_set_file. + * Warning: This function is not thread-safe. */ +void +_gpgrt_log_set_socket_dir_cb (const char *(*fnc)(void)) +{ + socket_dir_cb = fnc; +} + + +/* Warning: This function is not thread-safe. */ +void +_gpgrt_log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)) +{ + get_pid_suffix_cb = cb; +} + + +/* Warning: Changing TEXT is not thread-safe. Changing only flags + * might be thread-safe. */ +void +_gpgrt_log_set_prefix (const char *text, unsigned int flags) +{ + if (text) + { + strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1); + prefix_buffer[sizeof (prefix_buffer)-1] = 0; + } + + with_prefix = (flags & GPGRT_LOG_WITH_PREFIX); + with_time = (flags & GPGRT_LOG_WITH_TIME); + with_pid = (flags & GPGRT_LOG_WITH_PID); + running_detached = (flags & GPGRT_LOG_RUN_DETACHED); +#ifdef HAVE_W32_SYSTEM + no_registry = (flags & GPGRT_LOG_NO_REGISTRY); +#endif +} + + +const char * +_gpgrt_log_get_prefix (unsigned int *flags) +{ + if (flags) + { + *flags = 0; + if (with_prefix) + *flags |= GPGRT_LOG_WITH_PREFIX; + if (with_time) + *flags |= GPGRT_LOG_WITH_TIME; + if (with_pid) + *flags |= GPGRT_LOG_WITH_PID; + if (running_detached) + *flags |= GPGRT_LOG_RUN_DETACHED; +#ifdef HAVE_W32_SYSTEM + if (no_registry) + *flags |= GPGRT_LOG_NO_REGISTRY; +#endif + } + return prefix_buffer; +} + +/* This function returns true if the file descriptor FD is in use for + * logging. This is preferable over a test using log_get_fd in that + * it allows the logging code to use more then one file descriptor. */ +int +_gpgrt_log_test_fd (int fd) +{ + if (logstream) + { + int tmp = _gpgrt_fileno (logstream); + if ( tmp != -1 && tmp == fd) + return 1; + } + if (log_socket != -1 && log_socket == fd) + return 1; + return 0; +} + +int +_gpgrt_log_get_fd () +{ + return logstream? _gpgrt_fileno (logstream) : -1; +} + +estream_t +_gpgrt_log_get_stream () +{ + if (!logstream) + { + /* Make sure a log stream has been set. */ + _gpgrt_log_set_sink (NULL, NULL, -1); + if (!logstream) + { + fputs ("gpgrt fatal: failed to init log stream\n", stderr); + _gpgrt_abort (); + } + } + return logstream; +} + + +/* A filter used with the fprintf_sf function to sanitize the args for + * "%s" format specifiers. */ +static char * +fmt_string_filter (const char *string, int no, void *opaque) +{ + struct fmt_string_filter_s *state = opaque; + const unsigned char *p; + size_t buflen; + char *d; + int any; + + if (no == -1) + { + /* The printf engine asked us to release resources. */ + if (state->last_result) + { + _gpgrt_free (state->last_result); + state->last_result = NULL; + } + return NULL; + } + + if (!string) + return NULL; /* Nothing to filter - printf handles NULL nicely. */ + + /* Check whether escaping is needed and count needed length. */ + any = 0; + buflen = 1; + for (p = (const unsigned char *)string; *p; p++) + { + switch (*p) + { + case '\n': + case '\r': + case '\f': + case '\v': + case '\b': + case '\t': + case '\a': + case '\\': + buflen += 2; + any = 1; + break; + default: + if (*p < 0x20 || *p == 0x7f) + { + buflen += 5; + any = 1; + } + else + buflen++; + } + } + if (!any) + return (char*)string; /* Nothing to escape. */ + + /* Create a buffer and escape the input. */ + _gpgrt_free (state->last_result); + state->last_result = _gpgrt_malloc (buflen); + if (!state->last_result) + return "[out_of_core_in_format_string_filter]"; + + d = state->last_result; + for (p = (const unsigned char *)string; *p; p++) + { + switch (*p) + { + case '\n': *d++ = '\\'; *d++ = 'n'; break; + case '\r': *d++ = '\\'; *d++ = 'r'; break; + case '\f': *d++ = '\\'; *d++ = 'f'; break; + case '\v': *d++ = '\\'; *d++ = 'v'; break; + case '\b': *d++ = '\\'; *d++ = 'b'; break; + case '\t': *d++ = '\\'; *d++ = 't'; break; + case '\a': *d++ = '\\'; *d++ = 'a'; break; + case '\\': *d++ = '\\'; *d++ = '\\'; break; + + default: + if (*p < 0x20 || *p == 0x7f) + { + snprintf (d, 5, "\\x%02x", *p); + d += 4; + } + else + *d++ = *p; + } + } + *d = 0; + return state->last_result; +} + + +/* Note: LOGSTREAM is expected to be locked. */ +static int +print_prefix (int level, int leading_backspace) +{ + int rc; + int length = 0; + + if (level != GPGRT_LOGLVL_CONT) + { /* Note this does not work for multiple line logging as we would + * need to print to a buffer first */ + if (with_time && !force_prefixes) + { + struct tm *tp; + time_t atime = time (NULL); + + tp = localtime (&atime); + rc = _gpgrt_fprintf_unlocked (logstream, + "%04d-%02d-%02d %02d:%02d:%02d ", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec ); + if (rc > 0) + length += rc; + } + if (with_prefix || force_prefixes) + { + _gpgrt_fputs_unlocked (prefix_buffer, logstream); + length += strlen (prefix_buffer); + } + if (with_pid || force_prefixes) + { + unsigned long pidsuf; + int pidfmt; + + if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf))) + rc = _gpgrt_fprintf_unlocked (logstream, + pidfmt == 1? "[%u.%lu]":"[%u.%lx]", + (unsigned int)getpid (), pidsuf); + else + rc = _gpgrt_fprintf_unlocked (logstream, "[%u]", + (unsigned int)getpid ()); + if (rc > 0) + length += rc; + } + if ((!with_time && (with_prefix || with_pid)) || force_prefixes) + { + _gpgrt_putc_unlocked (':', logstream); + length++; + } + /* A leading backspace suppresses the extra space so that we can + correctly output, programname, filename and linenumber. */ + if (!leading_backspace + && (with_time || with_prefix || with_pid || force_prefixes)) + { + _gpgrt_putc_unlocked (' ', logstream); + length++; + } + } + + switch (level) + { + case GPGRT_LOGLVL_BEGIN: break; + case GPGRT_LOGLVL_CONT: break; + case GPGRT_LOGLVL_INFO: break; + case GPGRT_LOGLVL_WARN: break; + case GPGRT_LOGLVL_ERROR: break; + case GPGRT_LOGLVL_FATAL: + _gpgrt_fputs_unlocked ("Fatal: ", logstream); + length += 7; + break; + case GPGRT_LOGLVL_BUG: + _gpgrt_fputs_unlocked ("Ohhhh jeeee: ", logstream); + length += 13; + break; + case GPGRT_LOGLVL_DEBUG: + _gpgrt_fputs_unlocked ("DBG: ", logstream); + length += 5; + break; + default: + rc = _gpgrt_fprintf_unlocked (logstream, + "[Unknown log level %d]: ", level); + if (rc > 0) + length += rc; + break; + } + + return length; +} + + +/* Internal worker function. Exported so that we can use it in + * visibility.c. Returs the number of characters printed or 0 if the + * line ends in a LF. */ +int +_gpgrt_logv_internal (int level, int ignore_arg_ptr, const char *extrastring, + const char *prefmt, const char *fmt, va_list arg_ptr) +{ + int leading_backspace = (fmt && *fmt == '\b'); + int length; + int rc; + + if (!logstream) + { +#ifdef HAVE_W32_SYSTEM + char *tmp; + + tmp = (no_registry + ? NULL + : _gpgrt_w32_reg_query_string (NULL, "Software\\\\GNU\\\\GnuPG", + "DefaultLogFile")); + _gpgrt_log_set_sink (tmp && *tmp? tmp : NULL, NULL, -1); + _gpgrt_free (tmp); +#else + /* Make sure a log stream has been set. */ + _gpgrt_log_set_sink (NULL, NULL, -1); +#endif + if (!logstream) + { + fputs ("gpgrt fatal: failed to init log stream\n", stderr); + _gpgrt_abort (); + } + } + + _gpgrt_flockfile (logstream); + if (missing_lf && level != GPGRT_LOGLVL_CONT) + _gpgrt_putc_unlocked ('\n', logstream ); + missing_lf = 0; + + length = print_prefix (level, leading_backspace); + if (leading_backspace) + fmt++; + + if (fmt) + { + if (prefmt) + { + _gpgrt_fputs_unlocked (prefmt, logstream); + length += strlen (prefmt); + } + + if (ignore_arg_ptr) + { /* This is used by log_string and comes with the extra + * feature that after a LF the next line is indent at the + * length of the prefix. Note that we do not yet include + * the length of the timestamp and pid in the indent + * computation. */ + const char *p, *pend; + + for (p = fmt; (pend = strchr (p, '\n')); p = pend+1) + { + rc = _gpgrt_fprintf_unlocked (logstream, "%*s%.*s", + (int)((p != fmt + && (with_prefix || force_prefixes)) + ?strlen (prefix_buffer)+2:0), "", + (int)(pend - p)+1, p); + if (rc > 0) + length += rc; + } + _gpgrt_fputs_unlocked (p, logstream); + length += strlen (p); + } + else + { + struct fmt_string_filter_s sf = {NULL}; + + rc = _gpgrt_vfprintf_unlocked (logstream, fmt_string_filter, &sf, + fmt, arg_ptr); + if (rc > 0) + length += rc; + } + + if (*fmt && fmt[strlen(fmt)-1] != '\n') + missing_lf = 1; + } + + /* If we have an EXTRASTRING print it now while we still hold the + * lock on the logstream. */ + if (extrastring) + { + int c; + + if (missing_lf) + { + _gpgrt_putc_unlocked ('\n', logstream); + missing_lf = 0; + length = 0; + } + length += print_prefix (level, leading_backspace); + _gpgrt_fputs_unlocked (">> ", logstream); + length += 3; + missing_lf = 1; + while ((c = *extrastring++)) + { + missing_lf = 1; + if (c == '\\') + { + _gpgrt_fputs_unlocked ("\\\\", logstream); + length += 2; + } + else if (c == '\r') + { + _gpgrt_fputs_unlocked ("\\r", logstream); + length += 2; + } + else if (c == '\n') + { + _gpgrt_fputs_unlocked ("\\n\n", logstream); + length = 0; + if (*extrastring) + { + length += print_prefix (level, leading_backspace); + _gpgrt_fputs_unlocked (">> ", logstream); + length += 3; + } + else + missing_lf = 0; + } + else + { + _gpgrt_putc_unlocked (c, logstream); + length++; + } + } + if (missing_lf) + { + _gpgrt_putc_unlocked ('\n', logstream); + length = 0; + missing_lf = 0; + } + } + + if (level == GPGRT_LOGLVL_FATAL) + { + if (missing_lf) + _gpgrt_putc_unlocked ('\n', logstream); + _gpgrt_funlockfile (logstream); + exit (2); + } + else if (level == GPGRT_LOGLVL_BUG) + { + if (missing_lf) + _gpgrt_putc_unlocked ('\n', logstream ); + _gpgrt_funlockfile (logstream); + /* Using backtrace requires a configure test and to pass + * -rdynamic to gcc. Thus we do not enable it now. */ + /* { */ + /* void *btbuf[20]; */ + /* int btidx, btlen; */ + /* char **btstr; */ + + /* btlen = backtrace (btbuf, DIM (btbuf)); */ + /* btstr = backtrace_symbols (btbuf, btlen); */ + /* if (btstr) */ + /* for (btidx=0; btidx < btlen; btidx++) */ + /* log_debug ("[%d] %s\n", btidx, btstr[btidx]); */ + /* } */ + _gpgrt_abort (); + } + else + _gpgrt_funlockfile (logstream); + + /* Bumb the error counter for log_error. */ + if (level == GPGRT_LOGLVL_ERROR) + _gpgrt_inc_errorcount (); + + return length; +} + + +void +_gpgrt_log (int level, const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt) ; + _gpgrt_logv_internal (level, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + + +void +_gpgrt_logv (int level, const char *fmt, va_list arg_ptr) +{ + _gpgrt_logv_internal (level, 0, NULL, NULL, fmt, arg_ptr); +} + + +/* Same as log_logv but PREFIX is printed immediately before FMT. + * Note that PREFIX is an additional string and independent of the + * prefix set by gpgrt_log_set_prefix. */ +void +_gpgrt_logv_prefix (int level, const char *prefix, + const char *fmt, va_list arg_ptr) +{ + _gpgrt_logv_internal (level, 0, NULL, prefix, fmt, arg_ptr); +} + + +static void +do_log_ignore_arg (int level, const char *str, ...) +{ + va_list arg_ptr; + va_start (arg_ptr, str); + _gpgrt_logv_internal (level, 1, NULL, NULL, str, arg_ptr); + va_end (arg_ptr); +} + + +/* Log STRING at LEVEL but indent from the second line on by the + * length of the prefix. */ +void +_gpgrt_log_string (int level, const char *string) +{ + /* We need a dummy arg_ptr, but there is no portable way to create + * one. So we call the _gpgrt_logv_internal function through a + * variadic wrapper. */ + do_log_ignore_arg (level, string); +} + + +void +_gpgrt_log_info (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_INFO, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + + +void +_gpgrt_log_error (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_ERROR, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + + +void +_gpgrt_log_fatal (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_FATAL, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); + _gpgrt_abort (); /* Never called; just to make the compiler happy. */ +} + + +void +_gpgrt_log_bug (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_BUG, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); + _gpgrt_abort (); /* Never called; just to make the compiler happy. */ +} + + +void +_gpgrt_log_debug (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + + +/* The same as log_debug but at the end of the output STRING is + * printed with LFs expanded to include the prefix and a final --end-- + * marker. */ +void +_gpgrt_log_debug_string (const char *string, const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, string, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + + +void +_gpgrt_log_printf (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (fmt ? GPGRT_LOGLVL_CONT : GPGRT_LOGLVL_BEGIN, + 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + + +/* Flush the log - this is useful to make sure that the trailing + linefeed has been printed. */ +void +_gpgrt_log_flush (void) +{ + do_log_ignore_arg (GPGRT_LOGLVL_CONT, NULL); +} + + +/* Print a hexdump of (BUFFER,LENGTH). With FMT passed as NULL print + * just the raw dump (in this case ARG_PTR is not used), with FMT + * being an empty string, print a trailing linefeed, otherwise print + * an entire debug line with the expanded FMT followed by a possible + * wrapped hexdump and a final LF. */ +void +_gpgrt_logv_printhex (const void *buffer, size_t length, + const char *fmt, va_list arg_ptr) +{ + int wrap = 0; + int cnt = 0; + const unsigned char *p; + + /* FIXME: This printing is not yet protected by _gpgrt_flockfile. */ + if (fmt && *fmt) + { + _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, NULL, NULL, fmt, arg_ptr); + wrap = 1; + } + + if (length) + { + if (wrap) + _gpgrt_log_printf (" "); + + for (p = buffer; length--; p++) + { + _gpgrt_log_printf ("%02x", *p); + if (wrap && ++cnt == 32 && length) + { + cnt = 0; + /* (we indicate continuations with a backslash) */ + _gpgrt_log_printf (" \\\n"); + _gpgrt_log_debug ("%s", ""); + if (fmt && *fmt) + _gpgrt_log_printf (" "); + } + } + } + + if (fmt) + _gpgrt_log_printf ("\n"); +} + + +/* Print a hexdump of (BUFFER,LENGTH). With FMT passed as NULL print + * just the raw dump, with FMT being an empty string, print a trailing + * linefeed, otherwise print an entire debug line with the expanded + * FMT followed by the hexdump and a final LF. */ +void +_gpgrt_log_printhex (const void *buffer, size_t length, + const char *fmt, ...) +{ + va_list arg_ptr; + + if (fmt) + { + va_start (arg_ptr, fmt); + _gpgrt_logv_printhex (buffer, length, fmt, arg_ptr); + va_end (arg_ptr); + } + else + { + /* va_list is not necessary a pointer and thus we can't use NULL + * because that would conflict with platforms using a straight + * struct for it (e.g. arm64). We use a dummy variable instead; + * the static is a simple way zero it out so to not get + * complains about uninitialized use. */ + static va_list dummy_argptr; + + _gpgrt_logv_printhex (buffer, length, NULL, dummy_argptr); + } +} + + +/* Print a microsecond timestamp followed by FMT. */ +void +_gpgrt_logv_clock (const char *fmt, va_list arg_ptr) +{ +#if ENABLE_LOG_CLOCK + static unsigned long long initial; + struct timespec tv; + unsigned long long now; + char clockbuf[50]; + + if (clock_gettime (CLOCK_REALTIME, &tv)) + { + _gpgrt_log_debug ("error getting the realtime clock value\n"); + return; + } + now = tv.tv_sec * 1000000000ull; + now += tv.tv_nsec; + + if (!initial) + initial = now; + + snprintf (clockbuf, sizeof clockbuf, "[%6llu] ", (now - initial)/1000); + _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, NULL, clockbuf, fmt, arg_ptr); + +#else /*!ENABLE_LOG_CLOCK*/ + + /* You may need to link with -ltr to use the above code. */ + + _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, + 0, NULL, "[no clock] ", fmt, arg_ptr); + +#endif /*!ENABLE_LOG_CLOCK*/ +} + + +/* Print a microsecond timestamp followed by FMT. */ +void +_gpgrt_log_clock (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv_clock (fmt, arg_ptr); + va_end (arg_ptr); +} + + +void +_gpgrt__log_assert (const char *expr, const char *file, + int line, const char *func) +{ +#ifdef GPGRT_HAVE_MACRO_FUNCTION + _gpgrt_log (GPGRT_LOGLVL_BUG, "Assertion \"%s\" in %s failed (%s:%d)\n", + expr, func, file, line); +#else /*!GPGRT_HAVE_MACRO_FUNCTION*/ + _gpgrt_log (GPGRT_LOGLVL_BUG, "Assertion \"%s\" failed (%s:%d)\n", + expr, file, line); +#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ + _gpgrt_abort (); /* Never called; just to make the compiler happy. */ +} diff --git a/comm/third_party/libgpg-error/src/mkerrcodes.awk b/comm/third_party/libgpg-error/src/mkerrcodes.awk new file mode 100644 index 0000000000..e9c857c62f --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkerrcodes.awk @@ -0,0 +1,99 @@ +# mkerrcodes.awk +# Copyright (C) 2004, 2005 g10 Code GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# As a special exception, g10 Code GmbH gives unlimited permission to +# copy, distribute and modify the C source files that are the output +# of mkerrcodes.awk. You need not follow the terms of the GNU General +# Public License when using or distributing such scripts, even though +# portions of the text of mkerrcodes.awk appear in them. The GNU +# General Public License (GPL) does govern all other use of the material +# that constitutes the mkerrcodes.awk program. +# +# Certain portions of the mkerrcodes.awk source text are designed to be +# copied (in certain cases, depending on the input) into the output of +# mkerrcodes.awk. We call these the "data" portions. The rest of the +# mkerrcodes.awk source text consists of comments plus executable code +# that decides which of the data portions to output in any given case. +# We call these comments and executable code the "non-data" portions. +# mkerrcodes.h never copies any of the non-data portions into its output. +# +# This special exception to the GPL applies to versions of mkerrcodes.awk +# released by g10 Code GmbH. When you make and distribute a modified version +# of mkerrcodes.awk, you may extend this special exception to the GPL to +# apply to your modified version as well, *unless* your modified version +# has the potential to copy into its output some of the text that was the +# non-data portion of the version that you started with. (In other words, +# unless your change moves or copies text from the non-data portions to the +# data portions.) If your modification has such potential, you must delete +# any notice of this special exception to the GPL from your modified version. + +# This script outputs an intermediate file that contains the following output: +# static struct +# { +# int err; +# const char *err_sym; +# } err_table[] = +# { +# { 7, "GPG_ERR_E2BIG" }, +# [...] +# }; +# +# The input file is a list of possible system errors, followed by a GPG_ERR_* name: +# +# 7 GPG_ERR_E2BIG +# +# Comments (starting with # and ending at the end of the line) are removed, +# as is trailing whitespace. + +BEGIN { + FS="[ \t]+GPG_ERR_"; + print "/* Output of mkerrcodes.awk. DO NOT EDIT. */"; + print ""; + header = 1; +} + +/^#/ { next; } + +header { + if (! /^[ \t]*$/) + { + header = 0; + + print "static struct"; + print " {"; + print " int err;"; + print " const char *err_sym;"; + print " } err_table[] = "; + print "{"; + } + else + print; +} + +!header { + sub (/#.+/, ""); + sub (/[ ]+$/, ""); # Strip trailing space and tab characters. + + if (/^$/) + next; + + print " { " $1 ", \"GPG_ERR_" $2 "\" },"; +} + +END { + print "};"; +} diff --git a/comm/third_party/libgpg-error/src/mkerrcodes.c b/comm/third_party/libgpg-error/src/mkerrcodes.c new file mode 100644 index 0000000000..29c1cc270b --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkerrcodes.c @@ -0,0 +1,78 @@ +/* mkerrcodes.c - Generate list of system error values. + Copyright (C) 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file must not include config.h, as that is for the host + system, while this file will be run on the build system. */ + +#include + +#include "mkerrcodes.h" + +static const char header[] = +"/* errnos.h - List of system error values.\n" +" Copyright (C) 2004 g10 Code GmbH\n" +" This file is part of libgpg-error.\n" +"\n" +" libgpg-error is free software; you can redistribute it and/or\n" +" modify it under the terms of the GNU Lesser General Public License\n" +" as published by the Free Software Foundation; either version 2.1 of\n" +" the License, or (at your option) any later version.\n" +"\n" +" libgpg-error is distributed in the hope that it will be useful, but\n" +" WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" +" Lesser General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU Lesser General Public\n" +" License along with libgpg-error; if not, write to the Free\n" +" Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n" +" 02111-1307, USA. */\n" +"\n"; + +int +main (int argc, char **argv) +{ + int sorted; + int i; + + printf ("%s", header); + do + { + sorted = 1; + for (i = 0; i < sizeof (err_table) / sizeof (err_table[0]) - 1; i++) + if (err_table[i].err > err_table[i + 1].err) + { + int err = err_table[i].err; + const char *err_sym = err_table[i].err_sym; + + err_table[i].err = err_table[i + 1].err; + err_table[i].err_sym = err_table[i + 1].err_sym; + err_table[i + 1].err = err; + err_table[i + 1].err_sym = err_sym; + sorted = 0; + } + } + while (!sorted); + + for (i = 0; i < sizeof (err_table) / sizeof (err_table[0]); i++) + printf ("%i\t%s\n", err_table[i].err, err_table[i].err_sym); + + return 0; +} diff --git a/comm/third_party/libgpg-error/src/mkerrcodes1.awk b/comm/third_party/libgpg-error/src/mkerrcodes1.awk new file mode 100644 index 0000000000..4578e290ca --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkerrcodes1.awk @@ -0,0 +1,96 @@ +# mkerrcodes.awk +# Copyright (C) 2003, 2004 g10 Code GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# As a special exception, g10 Code GmbH gives unlimited permission to +# copy, distribute and modify the C source files that are the output +# of mkerrcodes.awk. You need not follow the terms of the GNU General +# Public License when using or distributing such scripts, even though +# portions of the text of mkerrcodes.awk appear in them. The GNU +# General Public License (GPL) does govern all other use of the material +# that constitutes the mkerrcodes.awk program. +# +# Certain portions of the mkerrcodes.awk source text are designed to be +# copied (in certain cases, depending on the input) into the output of +# mkerrcodes.awk. We call these the "data" portions. The rest of the +# mkerrcodes.awk source text consists of comments plus executable code +# that decides which of the data portions to output in any given case. +# We call these comments and executable code the "non-data" portions. +# mkerrcodes.h never copies any of the non-data portions into its output. +# +# This special exception to the GPL applies to versions of mkerrcodes.awk +# released by g10 Code GmbH. When you make and distribute a modified version +# of mkerrcodes.awk, you may extend this special exception to the GPL to +# apply to your modified version as well, *unless* your modified version +# has the potential to copy into its output some of the text that was the +# non-data portion of the version that you started with. (In other words, +# unless your change moves or copies text from the non-data portions to the +# data portions.) If your modification has such potential, you must delete +# any notice of this special exception to the GPL from your modified version. + +# This script outputs an intermediate file that contains the following block +# for each error value symbol in the input file (example for EINVAL): +# +# #ifdef EINVAL +# EINVAL GPG_ERR_EINVAL +# #endif +# +# The input file is a list of possible system errors in the column errnoidx +# (defaults to 2). +# +# Comments (starting with # and ending at the end of the line) are removed, +# as is trailing whitespace. + +BEGIN { + FS="[\t]+"; + header = 1; + if (errnoidx == 0) + errnoidx = 2; + + print "/* Output of mkerrcodes.awk. DO NOT EDIT. */"; + print ""; +} + +/^#/ { next; } + +header { + if ($1 ~ /^[0-9]/) + { + print "#include "; + print "#ifdef _WIN32"; + print "#include "; + print "#endif"; + print ""; + header = 0; + } + else + print; +} + +!header { + sub (/#.+/, ""); + sub (/[ ]+$/, ""); # Strip trailing space and tab characters. + + if (/^$/) + next; + + print "#ifdef " $errnoidx; + print $errnoidx "\tGPG_ERR_" $errnoidx; + print "#endif"; + print "#ifdef WSA" $errnoidx; + print "WSA" $errnoidx "\tGPG_ERR_" $errnoidx; + print "#endif"; +} diff --git a/comm/third_party/libgpg-error/src/mkerrcodes2.awk b/comm/third_party/libgpg-error/src/mkerrcodes2.awk new file mode 100644 index 0000000000..188f7a48e3 --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkerrcodes2.awk @@ -0,0 +1,134 @@ +# mkstrtable.awk +# Copyright (C) 2003 g10 Code GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# As a special exception, g10 Code GmbH gives unlimited permission to +# copy, distribute and modify the C source files that are the output +# of mkerrcodes2.awk. You need not follow the terms of the GNU General +# Public License when using or distributing such scripts, even though +# portions of the text of mkerrcodes2.awk appear in them. The GNU +# General Public License (GPL) does govern all other use of the material +# that constitutes the mkerrcodes2.awk program. +# +# Certain portions of the mkerrcodes2.awk source text are designed to be +# copied (in certain cases, depending on the input) into the output of +# mkerrcodes2.awk. We call these the "data" portions. The rest of the +# mkerrcodes2.awk source text consists of comments plus executable code +# that decides which of the data portions to output in any given case. +# We call these comments and executable code the "non-data" portions. +# mkstrtable.h never copies any of the non-data portions into its output. +# +# This special exception to the GPL applies to versions of mkerrcodes2.awk +# released by g10 Code GmbH. When you make and distribute a modified version +# of mkerrcodes2.awk, you may extend this special exception to the GPL to +# apply to your modified version as well, *unless* your modified version +# has the potential to copy into its output some of the text that was the +# non-data portion of the version that you started with. (In other words, +# unless your change moves or copies text from the non-data portions to the +# data portions.) If your modification has such potential, you must delete +# any notice of this special exception to the GPL from your modified version. + +# This script outputs a source file that does define the following +# symbols: +# +# static const char msgstr[]; +# A string containing all messages in the list. +# +# static const int msgidx[]; +# A list of index numbers, one for each message, that points to the +# beginning of the string in msgstr. +# +# msgidxof (code); +# A macro that maps code numbers to idx numbers. If a DEFAULT MESSAGE +# is provided (see below), its index will be returned for unknown codes. +# Otherwise -1 is returned for codes that do not appear in the list. +# You can lookup the message with code CODE with: +# msgstr + msgidx[msgidxof (code)]. +# +# The input file has the following format: +# CODE1 MESSAGE1 (Code number, , message string) +# CODE2 MESSAGE2 (Code number, , message string) +# ... +# CODEn MESSAGEn (Code number, , message string) +# DEFAULT MESSAGE (, fall-back message string) +# +# Comments (starting with # and ending at the end of the line) are removed, +# as is trailing whitespace. The last line is optional; if no DEFAULT +# MESSAGE is given, msgidxof will return the number -1 for unknown +# index numbers. + +BEGIN { +# msg holds the number of messages. + msg = 0; + print "/* Output of mkerrcodes2.awk. DO NOT EDIT. */"; + print ""; + header = 1; +} + +/^#/ { next; } + +header { + if ($1 ~ /^[0123456789]+$/) + { + print "static const int err_code_from_index[] = {"; + header = 0; + } + else + print; +} + +!header { + sub (/#.+/, ""); + sub (/[ ]+$/, ""); # Strip trailing space and tab characters. + + if (/^$/) + next; + +# Print the string msgstr line by line. We delay output by one line to be able +# to treat the last line differently (see END). + print " " $2 ","; + +# Remember the error value and index of each error code. + code[msg] = $1; + pos[msg] = $2; + msg++; +} +END { + print "};"; + print ""; + print "#define errno_to_idx(code) (0 ? -1 \\"; + +# Gather the ranges. + skip = code[0]; + start = code[0]; + stop = code[0]; + for (i = 1; i < msg; i++) + { + if (code[i] == stop + 1) + stop++; + else + { + print " : ((code >= " start ") && (code <= " stop ")) ? (code - " \ + skip ") \\"; + skip += code[i] - stop - 1; + start = code[i]; + stop = code[i]; + } + } + print " : ((code >= " start ") && (code <= " stop ")) ? (code - " \ + skip ") \\"; + print " : -1)"; +} diff --git a/comm/third_party/libgpg-error/src/mkerrnos.awk b/comm/third_party/libgpg-error/src/mkerrnos.awk new file mode 100644 index 0000000000..15b1aad225 --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkerrnos.awk @@ -0,0 +1,104 @@ +# mkerrnos.awk +# Copyright (C) 2003, 2004 g10 Code GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# As a special exception, g10 Code GmbH gives unlimited permission to +# copy, distribute and modify the C source files that are the output +# of mkerrnos.awk. You need not follow the terms of the GNU General +# Public License when using or distributing such scripts, even though +# portions of the text of mkerrnos.awk appear in them. The GNU +# General Public License (GPL) does govern all other use of the material +# that constitutes the mkerrnos.awk program. +# +# Certain portions of the mkerrnos.awk source text are designed to be +# copied (in certain cases, depending on the input) into the output of +# mkerrnos.awk. We call these the "data" portions. The rest of the +# mkerrnos.awk source text consists of comments plus executable code +# that decides which of the data portions to output in any given case. +# We call these comments and executable code the "non-data" portions. +# mkerrnos.h never copies any of the non-data portions into its output. +# +# This special exception to the GPL applies to versions of mkerrnos.awk +# released by g10 Code GmbH. When you make and distribute a modified version +# of mkerrnos.awk, you may extend this special exception to the GPL to +# apply to your modified version as well, *unless* your modified version +# has the potential to copy into its output some of the text that was the +# non-data portion of the version that you started with. (In other words, +# unless your change moves or copies text from the non-data portions to the +# data portions.) If your modification has such potential, you must delete +# any notice of this special exception to the GPL from your modified version. + +# This script outputs a source file that does define the following +# symbols: +# +# static const int err_code_to_errno[]; +# A mapping of gpg_err_code_t numbers to system errno. The index of an +# error code in the table can be obtained after removing the system error +# code indication bit. +# +# The input file is a list of possible system errors in the column errnoidx +# (defaults to 2). +# +# Comments (starting with # and ending at the end of the line) are removed, +# as is trailing whitespace. + +BEGIN { + FS="[\t]+"; + header = 1; + if (errnoidx == 0) + errnoidx = 2; + + print "/* Output of mkerrnos.awk. DO NOT EDIT. */"; + print ""; +} + +/^#/ { next; } + +header { + if ($1 ~ /^[0-9]/) + { + print "#include "; + print "#ifdef _WIN32"; + print "#include "; + print "#endif"; + print ""; + print "static const int err_code_to_errno [] = {"; + header = 0; + } + else + print; +} + +!header { + sub (/#.+/, ""); + sub (/[ ]+$/, ""); # Strip trailing space and tab characters. + + if (/^$/) + next; + + print "#ifdef " $errnoidx; + print " " $errnoidx ","; + print "#else"; + print "#ifdef WSA" $errnoidx; + print " WSA" $errnoidx ","; + print "#else"; + print " 0,"; + print "#endif"; + print "#endif"; +} +END { + print "};"; +} diff --git a/comm/third_party/libgpg-error/src/mkheader.c b/comm/third_party/libgpg-error/src/mkheader.c new file mode 100644 index 0000000000..77826da543 --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkheader.c @@ -0,0 +1,779 @@ +/* mkheader.c - Create a header file for libgpg-error + * Copyright (C) 2010 Free Software Foundation, Inc. + * Copyright (C) 2014 g10 Code GmbH + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include +#include +#include +#include +#include + +#define PGM "mkheader" + +#define LINESIZE 1024 + +static char *host_triplet; /* malloced. */ +static char *host_os; /* points into host_triplet. */ +static char *srcdir; +static const char *hdr_version; +static const char *hdr_version_number; +static int cross_building; /* Command line flag. */ + +/* Values take from the supplied config.h. */ +static int have_stdint_h; +static int have_sys_types_h; +static int have_w32_system; +static int have_w64_system; +static char *replacement_for_off_type; +static int use_posix_threads; + +/* Various state flags. */ +static int stdint_h_included; +static int sys_types_h_included; + + +/* The usual free wrapper. */ +static void +xfree (void *a) +{ + if (a) + free (a); +} + + +static char * +xmalloc (size_t n) +{ + char *p; + + p = malloc (n); + if (!p) + { + fputs (PGM ": out of core\n", stderr); + exit (1); + } + return p; +} + + +static char * +xstrdup (const char *string) +{ + char *p; + size_t len = strlen (string) + 1; + + p = xmalloc (len); + memcpy (p, string, len); + return p; +} + + +/* Return a malloced string with TRIPLET. If TRIPLET has an alias + * return that instead. In general build-aux/config.sub should do the + * aliasing but some returned triplets are anyway identical and thus + * we use this function to map it to the canonical form. A pointer to + * the OS part of the returned value is stored at R_OS. + * NO_VENDOR_HACK is for internal use; caller must call with 0. */ +static char * +canon_host_triplet (const char *triplet, int no_vendor_hack, char **r_os) +{ + struct { + const char *name; + const char *alias; + } tbl[] = { + {"i486-pc-linux-gnu", "i686-unknown-linux-gnu" }, + {"i586-pc-linux-gnu" }, + {"i686-pc-linux-gnu" }, + {"arc-oe-linux-gnu" }, /* Other CPU but same struct. */ + {"arc-oe-linux-uclibc" }, /* and uclibc is also the same. */ + + {"i486-pc-gnu", "i686-unknown-gnu"}, + {"i586-pc-gnu"}, + {"i686-pc-gnu"}, + + {"i486-pc-kfreebsd-gnu", "i686-unknown-kfreebsd-gnu"}, + {"i586-pc-kfreebsd-gnu"}, + {"i686-pc-kfreebsd-gnu"}, + + {"x86_64-pc-linux-gnuhardened1", "x86_64-unknown-linux-gnu" }, + {"x86_64-pc-linux-gnu" }, + + {"powerpc-unknown-linux-gnuspe", "powerpc-unknown-linux-gnu" }, + + {"arm-unknown-linux-gnueabihf", "arm-unknown-linux-gnueabi" }, + {"armv7-unknown-linux-gnueabihf" }, + {"armv7a-unknown-linux-gnueabihf" }, + {"armv5-unknown-linux-musleabi" }, + {"armv6-unknown-linux-musleabihf" }, + + { NULL } + }; + int i; + const char *lastalias = NULL; + const char *s; + char *p; + char *result; + + for (i=0; tbl[i].name; i++) + { + if (tbl[i].alias) + lastalias = tbl[i].alias; + if (!strcmp (tbl[i].name, triplet)) + { + if (!lastalias) + break; /* Ooops: first entry has no alias. */ + result = xstrdup (lastalias); + goto leave; + } + } + for (i=0, s=triplet; *s; s++) + if (*s == '-') + i++; + if (i > 2 && !no_vendor_hack) + { + /* We have a 4 part "triplet": CPU-VENDOR-KERNEL-SYSTEM where + * the last two parts replace the OS part of a real triplet. + * The VENDOR part is then in general useless because + * KERNEL-SYSTEM is specific enough. We now do a second pass by + * replacing VENDOR with "unknown". */ + char *buf = xmalloc (strlen (triplet) + 7 + 1); + + for (p=buf,s=triplet,i=0; *s; s++) + { + *p++ = *s; + if (*s == '-' && ++i == 1) + { + memcpy (p, "unknown-",8); + p += 8; + for (s++; *s != '-'; s++) + ; + } + } + *p = 0; + result = canon_host_triplet (buf, 1, NULL); + xfree (buf); + goto leave; + } + + result = xstrdup (triplet); + leave: + /* Find the OS part. */ + if (r_os) + { + *r_os = result + strlen (result); /* Default to the empty string. */ + for (i=0, p=result; *p; p++) + if (*p == '-' && ++i == 2) + { + *r_os = p+1; + break; + } + } + + return result; +} + + +/* Parse the supplied config.h file and extract required info. + Returns 0 on success. */ +static int +parse_config_h (const char *fname) +{ + FILE *fp; + char line[LINESIZE]; + int lnr = 0; + char *p1; + + fp = fopen (fname, "r"); + if (!fp) + { + fprintf (stderr, "%s:%d: can't open file: %s\n", + fname, lnr, strerror (errno)); + return 1; + } + + while (fgets (line, LINESIZE, fp)) + { + size_t n = strlen (line); + + lnr++; + if (!n || line[n-1] != '\n') + { + fprintf (stderr, + "%s:%d: trailing linefeed missing, line too long or " + "embedded nul character\n", fname, lnr); + break; + } + line[--n] = 0; + + if (strncmp (line, "#define ", 8)) + continue; /* We are only interested in define lines. */ + p1 = strtok (line + 8, " \t"); + if (!*p1) + continue; /* oops */ + if (!strcmp (p1, "HAVE_STDINT_H")) + have_stdint_h = 1; + else if (!strcmp (p1, "HAVE_SYS_TYPES_H")) + have_sys_types_h = 1; + else if (!strcmp (p1, "HAVE_W32_SYSTEM")) + have_w32_system = 1; + else if (!strcmp (p1, "HAVE_W64_SYSTEM")) + have_w64_system = 1; + else if (!strcmp (p1, "REPLACEMENT_FOR_OFF_T")) + { + p1 = strtok (NULL, "\""); + if (!*p1) + continue; /* oops */ + xfree (replacement_for_off_type); + replacement_for_off_type = xstrdup (p1); + } + else if (!strcmp (p1, "USE_POSIX_THREADS")) + use_posix_threads = 1; + } + + if (ferror (fp)) + { + fprintf (stderr, "%s:%d: error reading file: %s\n", + fname, lnr, strerror (errno)); + return 1; + } + + fclose (fp); + return 0; +} + + +/* Write LINE to stdout. The function is allowed to modify LINE. */ +static void +write_str (char *line) +{ + if (fputs (line, stdout) == EOF) + { + fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno)); + exit (1); + } +} + +static void +write_line (char *line) +{ + if (puts (line) == EOF) + { + fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno)); + exit (1); + } +} + + +/* Write SOURCE or CODES line to stdout. The function is allowed to + modify LINE. Trailing white space is already removed. Passing + NULL resets the internal state. */ +static void +write_sources_or_codes (char *line) +{ + static int in_intro; + char *p1, *p2; + + if (!line) + { + in_intro = 1; + return; + } + + if (!*line) + return; + + if (in_intro) + { + if (!strchr ("0123456789", *line)) + return; + in_intro = 0; + } + + p1 = strtok (line, " \t"); + p2 = p1? strtok (NULL, " \t") : NULL; + + if (p1 && p2 && strchr ("0123456789", *p1) && *p2) + { + write_str (" "); + write_str (p2); + write_str (" = "); + write_str (p1); + write_str (",\n"); + } +} + + +/* Write system errnos to stdout. The function is allowed to + modify LINE. Trailing white space is already removed. Passing + NULL resets the internal state. */ +static void +write_errnos_in (char *line) +{ + static int state; + char *p1, *p2; + + if (!line) + { + state = 0; + return; + } + + if (!*line) + return; + + if (!state && strchr ("0123456789", *line)) + state = 1; + else if (state == 1 && !strchr ("0123456789", *line)) + state = 2; + + if (state != 1) + return; + + p1 = strtok (line, " \t"); + p2 = p1? strtok (NULL, " \t") : NULL; + + if (p1 && p2 && strchr ("0123456789", *p1) && *p2) + { + write_str (" GPG_ERR_"); + write_str (p2); + write_str (" = GPG_ERR_SYSTEM_ERROR | "); + write_str (p1); + write_str (",\n"); + } +} + + +/* Create the full file name for NAME and return a newly allocated + string with it. If name contains a '&' and REPL is not NULL + replace '&' with REPL. */ +static char * +mk_include_name (const char *name, const char *repl) +{ + FILE *fp; + char *incfname, *p; + const char *s; + + incfname = malloc (strlen (srcdir) + strlen (name) + + (repl?strlen (repl):0) + 1); + if (!incfname) + { + fputs (PGM ": out of core\n", stderr); + exit (1); + } + + if (*name == '.' && name[1] == '/') + *incfname = 0; + else + strcpy (incfname, srcdir); + p = incfname + strlen (incfname); + for (s=name; *s; s++) + { + if (*s == '&' && repl) + { + while (*repl) + *p++ = *repl++; + repl = NULL; /* Replace only once. */ + } + else + *p++ = *s; + } + *p = 0; + return incfname; +} + + +/* Include the file NAME from the source directory. The included file + is not further expanded. It may have comments indicated by a + double hash mark at the begin of a line. OUTF is called for each + read line and passed a buffer with the content of line sans line + line endings. If NAME is prefixed with "./" it is included from + the current directory and not from the source directory. */ +static void +include_file (const char *fname, int lnr, const char *name, void (*outf)(char*)) +{ + FILE *fp; + char *incfname; + int inclnr; + char line[LINESIZE]; + int repl_flag; + + repl_flag = !!strchr (name, '&'); + incfname = mk_include_name (name, repl_flag? host_triplet : NULL); + fp = fopen (incfname, "r"); + if (!fp && repl_flag) + { + /* Try again using the OS string. */ + free (incfname); + incfname = mk_include_name (name, host_os); + fp = fopen (incfname, "r"); + } + if (!fp) + { + fprintf (stderr, "%s:%d: error including `%s': %s\n", + fname, lnr, incfname, strerror (errno)); + exit (1); + } + + if (repl_flag) + fprintf (stderr,"%s:%d: note: including '%s'\n", + fname, lnr, incfname); + + inclnr = 0; + while (fgets (line, LINESIZE, fp)) + { + size_t n = strlen (line); + + inclnr++; + if (!n || line[n-1] != '\n') + { + fprintf (stderr, + "%s:%d: trailing linefeed missing, line too long or " + "embedded nul character\n", incfname, inclnr); + fprintf (stderr,"%s:%d: note: file '%s' included from here\n", + fname, lnr, incfname); + exit (1); + } + line[--n] = 0; + while (line[n] == ' ' || line[n] == '\t' || line[n] == '\r') + { + line[n] = 0; + if (!n) + break; + n--; + } + + if (line[0] == '#' && line[1] == '#') + { + if (!strncmp (line+2, "EOF##", 5)) + break; /* Forced EOF. */ + } + else + outf (line); + } + if (ferror (fp)) + { + fprintf (stderr, "%s:%d: error reading `%s': %s\n", + fname, lnr, incfname, strerror (errno)); + exit (1); + } + fclose (fp); + free (incfname); +} + + +/* Try to include the file NAME. Returns true if it does not + exist. */ +static int +try_include_file (const char *fname, int lnr, const char *name, + void (*outf)(char*)) +{ + int rc; + char *incfname; + int repl_flag; + + repl_flag = !!strchr (name, '&'); + incfname = mk_include_name (name, repl_flag? host_triplet : NULL); + rc = access (incfname, R_OK); + if (rc && repl_flag) + { + free (incfname); + incfname = mk_include_name (name, host_os); + rc = access (incfname, R_OK); + } + if (!rc) + include_file (fname, lnr, name, outf); + + free (incfname); + return rc; +} + + +static int +write_special (const char *fname, int lnr, const char *tag) +{ + if (!strcmp (tag, "version")) + { + putchar ('\"'); + fputs (hdr_version, stdout); + putchar ('\"'); + } + else if (!strcmp (tag, "version-number")) + { + fputs (hdr_version_number, stdout); + } + else if (!strcmp (tag, "define:gpgrt_off_t")) + { + if (!replacement_for_off_type) + { + fprintf (stderr, "%s:%d: replacement for off_t not defined\n", + fname, lnr); + exit (1); + } + else + { + if (!strcmp (replacement_for_off_type, "int64_t") + && !stdint_h_included && have_stdint_h) + { + fputs ("#include \n\n", stdout); + stdint_h_included = 1; + } + printf ("typedef %s gpgrt_off_t;\n", replacement_for_off_type); + } + } + else if (!strcmp (tag, "define:gpgrt_ssize_t")) + { + if (have_w64_system) + { + if (!stdint_h_included && have_stdint_h) + { + fputs ("# include \n", stdout); + stdint_h_included = 1; + } + fputs ("typedef int64_t gpgrt_ssize_t;\n", stdout); + } + else if (have_w32_system) + { + fputs ("typedef long gpgrt_ssize_t;\n", stdout); + } + else + { + if (!sys_types_h_included) + { + fputs ("#include \n", stdout); + sys_types_h_included = 1; + } + fputs ("typedef ssize_t gpgrt_ssize_t;\n", stdout); + } + } + else if (!strcmp (tag, "api_ssize_t")) + { + if (have_w32_system) + fputs ("gpgrt_ssize_t", stdout); + else + fputs ("ssize_t", stdout); + } + else if (!strcmp (tag, "define:pid_t")) + { + if (have_sys_types_h) + { + if (!sys_types_h_included) + { + fputs ("#include \n", stdout); + sys_types_h_included = 1; + } + } + else if (have_w64_system) + { + if (!stdint_h_included && have_stdint_h) + { + fputs ("#include \n", stdout); + stdint_h_included = 1; + } + fputs ("typedef int64_t pid_t\n", stdout); + } + else + { + fputs ("typedef int pid_t\n", stdout); + } + } + else if (!strcmp (tag, "include:err-sources")) + { + write_sources_or_codes (NULL); + include_file (fname, lnr, "err-sources.h.in", write_sources_or_codes); + } + else if (!strcmp (tag, "include:err-codes")) + { + write_sources_or_codes (NULL); + include_file (fname, lnr, "err-codes.h.in", write_sources_or_codes); + } + else if (!strcmp (tag, "include:errnos")) + { + include_file (fname, lnr, "errnos.in", write_errnos_in); + } + else if (!strcmp (tag, "include:os-add")) + { + if (!strcmp (host_os, "mingw32")) + { + include_file (fname, lnr, "w32-add.h", write_line); + } + else if (!strcmp (host_os, "mingw32ce")) + { + include_file (fname, lnr, "w32-add.h", write_line); + include_file (fname, lnr, "w32ce-add.h", write_line); + } + } + else if (!strcmp (tag, "include:lock-obj")) + { + /* If we are not cross compiling and the native file exists we + * prefer that over one from syscfg. */ + if (cross_building + || try_include_file (fname, lnr, + "./lock-obj-pub.native.h", write_line)) + include_file (fname, lnr, "syscfg/lock-obj-pub.&.h", write_line); + } + else + return 0; /* Unknown tag. */ + + return 1; /* Tag processed. */ +} + + +int +main (int argc, char **argv) +{ + FILE *fp = NULL; + char line[LINESIZE]; + int lnr = 0; + const char *fname, *s; + char *p1, *p2; + const char *config_h; + const char *host_triplet_raw; + + if (argc) + { + argc--; argv++; + } + if (argc && !strcmp (argv[0], "--cross")) + { + cross_building = 1; + argc--; argv++; + } + + if (argc == 1) + { + /* Print just the canonicalized host triplet. */ + host_triplet = canon_host_triplet (argv[0], 0, &host_os); + printf ("%s\n", host_triplet); + goto leave; + } + else if (argc == 5) + ; /* Standard operation. */ + else + { + fputs ("usage: " PGM + " host_triplet template.h config.h version version_number\n" + " " PGM + " host_triplet\n", + stderr); + return 1; + } + host_triplet_raw = argv[0]; + fname = argv[1]; + config_h = argv[2]; + hdr_version = argv[3]; + hdr_version_number = argv[4]; + + host_triplet = canon_host_triplet (host_triplet_raw, 0, &host_os); + + srcdir = malloc (strlen (fname) + 2 + 1); + if (!srcdir) + { + fputs (PGM ": out of core\n", stderr); + return 1; + } + strcpy (srcdir, fname); + p1 = strrchr (srcdir, '/'); + if (p1) + p1[1] = 0; + else + strcpy (srcdir, "./"); + + if (parse_config_h (config_h)) + return 1; + + fp = fopen (fname, "r"); + if (!fp) + { + fprintf (stderr, "%s:%d: can't open file: %s\n", + fname, lnr, strerror (errno)); + return 1; + } + + while (fgets (line, LINESIZE, fp)) + { + size_t n = strlen (line); + + lnr++; + if (!n || line[n-1] != '\n') + { + fprintf (stderr, + "%s:%d: trailing linefeed missing, line too long or " + "embedded nul character\n", fname, lnr); + break; + } + line[--n] = 0; + + p1 = strchr (line, '@'); + p2 = p1? strchr (p1+1, '@') : NULL; + if (!p1 || !p2 || p2-p1 == 1) + { + puts (line); + continue; + } + *p1++ = 0; + *p2++ = 0; + fputs (line, stdout); + + if (!strcmp (p1, "configure_input")) + { + s = strrchr (fname, '/'); + printf ("Do not edit. Generated from %s for:\n%*s", + s? s+1 : fname, (int)(p1 - line) + 13, ""); + if (!strcmp (host_triplet, host_triplet_raw)) + printf ("%s", host_triplet); + else + printf ("%s (%s)", host_triplet, host_triplet_raw); + if (!use_posix_threads && !have_w32_system && !have_w64_system) + fputs (" NO-THREADS", stdout); + fputs (p2, stdout); + } + else if (!write_special (fname, lnr, p1)) + { + putchar ('@'); + fputs (p1, stdout); + putchar ('@'); + fputs (p2, stdout); + } + else if (*p2) + { + fputs (p2, stdout); + } + putchar ('\n'); + } + + if (ferror (fp)) + { + fprintf (stderr, "%s:%d: error reading file: %s\n", + fname, lnr, strerror (errno)); + return 1; + } + + fputs ("/*\n" + "Loc" "al Variables:\n" + "buffer-read-only: t\n" + "End:\n" + "*/\n", stdout); + + leave: + if (ferror (stdout)) + { + fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno)); + return 1; + } + + if (fp) + fclose (fp); + + xfree (host_triplet); + return 0; +} diff --git a/comm/third_party/libgpg-error/src/mkstrtable.awk b/comm/third_party/libgpg-error/src/mkstrtable.awk new file mode 100644 index 0000000000..285e45f24c --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkstrtable.awk @@ -0,0 +1,189 @@ +# mkstrtable.awk +# Copyright (C) 2003, 2004, 2008 g10 Code GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +# +# As a special exception, g10 Code GmbH gives unlimited permission to +# copy, distribute and modify the C source files that are the output +# of mkstrtable.awk. You need not follow the terms of the GNU General +# Public License when using or distributing such scripts, even though +# portions of the text of mkstrtable.awk appear in them. The GNU +# General Public License (GPL) does govern all other use of the material +# that constitutes the mkstrtable.awk program. +# +# Certain portions of the mkstrtable.awk source text are designed to be +# copied (in certain cases, depending on the input) into the output of +# mkstrtable.awk. We call these the "data" portions. The rest of the +# mkstrtable.awk source text consists of comments plus executable code +# that decides which of the data portions to output in any given case. +# We call these comments and executable code the "non-data" portions. +# mkstrtable.h never copies any of the non-data portions into its output. +# +# This special exception to the GPL applies to versions of mkstrtable.awk +# released by g10 Code GmbH. When you make and distribute a modified version +# of mkstrtable.awk, you may extend this special exception to the GPL to +# apply to your modified version as well, *unless* your modified version +# has the potential to copy into its output some of the text that was the +# non-data portion of the version that you started with. (In other words, +# unless your change moves or copies text from the non-data portions to the +# data portions.) If your modification has such potential, you must delete +# any notice of this special exception to the GPL from your modified version. + +# This script outputs a source file that does define the following +# symbols: +# +# static const char msgstr[]; +# A string containing all messages in the list. +# +# static const int msgidx[]; +# A list of index numbers, one for each message, that points to the +# beginning of the string in msgstr. +# +# msgidxof (code); +# A macro that maps code numbers to idx numbers. If a DEFAULT MESSAGE +# is provided (see below), its index will be returned for unknown codes. +# Otherwise -1 is returned for codes that do not appear in the list. +# You can lookup the message with code CODE with: +# msgstr + msgidx[msgidxof (code)]. +# +# The input file has the following format: +# CODE1 ... MESSAGE1 (code nr, , something, , msg) +# CODE2 ... MESSAGE2 (code nr, , something, , msg) +# ... +# CODEn ... MESSAGEn (code nr, , something, , msg) +# ... DEFAULT-MESSAGE (, something, , fall-back msg) +# +# Comments (starting with # and ending at the end of the line) are removed, +# as is trailing whitespace. The last line is optional; if no DEFAULT +# MESSAGE is given, msgidxof will return the number -1 for unknown +# index numbers. +# +# The field to be used is specified with the variable "textidx" on +# the command line. It defaults to 2. +# +# The variable nogettext can be set to 1 to suppress gettext markers. +# +# The variable prefix can be used to prepend a string to each message. +# +# The variable pkg_namespace can be used to prepend a string to each +# variable and macro name. + +BEGIN { + FS = "[\t]+"; +# cpos holds the current position in the message string. + cpos = 0; +# msg holds the number of messages. + msg = 0; + print "/* Output of mkstrtable.awk. DO NOT EDIT. */"; + print ""; + header = 1; + if (textidx == 0) + textidx = 2; +# nogettext can be set to 1 to suppress gettext noop markers. +} + +/^#/ { next; } + +header { + if ($1 ~ /^[0123456789]+$/) + { + print "/* The purpose of this complex string table is to produce"; + print " optimal code with a minimum of relocations. */"; + print ""; + print "static const char " pkg_namespace "msgstr[] = "; + header = 0; + } + else + print; +} + +!header { + sub (/#.+/, ""); + sub (/[ ]+$/, ""); # Strip trailing space and tab characters. + + if (/^$/) + next; + +# Print the string msgstr line by line. We delay output by one line to be able +# to treat the last line differently (see END). + if (last_msgstr) + { + if (nogettext) + print " \"" last_msgstr "\" \"\\0\""; + else + print " gettext_noop (\"" last_msgstr "\") \"\\0\""; + } + last_msgstr = prefix $textidx; + +# Remember the error code and msgidx of each error message. + code[msg] = $1; + pos[msg] = cpos; + cpos += length (last_msgstr) + 1; + msg++; + + if ($1 == "") + { + has_default = 1; + exit; + } +} +END { + if (has_default) + coded_msgs = msg - 1; + else + coded_msgs = msg; + + if (nogettext) + print " \"" last_msgstr "\";"; + else + print " gettext_noop (\"" last_msgstr "\");"; + print ""; + print "static const int " pkg_namespace "msgidx[] ="; + print " {"; + for (i = 0; i < coded_msgs; i++) + print " " pos[i] ","; + print " " pos[coded_msgs]; + print " };"; + print ""; + print "static GPG_ERR_INLINE int"; + print pkg_namespace "msgidxof (int code)"; + print "{"; + print " return (0 ? 0"; + +# Gather the ranges. + skip = code[0]; + start = code[0]; + stop = code[0]; + for (i = 1; i < coded_msgs; i++) + { + if (code[i] == stop + 1) + stop++; + else + { + print " : ((code >= " start ") && (code <= " stop ")) ? (code - " \ + skip ")"; + skip += code[i] - stop - 1; + start = code[i]; + stop = code[i]; + } + } + print " : ((code >= " start ") && (code <= " stop ")) ? (code - " \ + skip ")"; + if (has_default) + print " : " stop + 1 " - " skip ");"; + else + print " : -1);"; + print "}"; +} diff --git a/comm/third_party/libgpg-error/src/mkw32errmap.c b/comm/third_party/libgpg-error/src/mkw32errmap.c new file mode 100644 index 0000000000..508a51302d --- /dev/null +++ b/comm/third_party/libgpg-error/src/mkw32errmap.c @@ -0,0 +1,178 @@ +/* mkw32errmap.c - Generate mapping sources for Windows. + Copyright (C) 2010 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#ifdef RESOLVE_MACROS +# include +#endif +#include +#include + +static const char header_gpg_extra_errno_h[] = + "/* errno.h - WindowsCE errno.h substitute\n" + " Copyright (C) 2010 g10 Code GmbH\n" + "\n" + " This file is free software; as a special exception the author gives\n" + " unlimited permission to copy and/or distribute it, with or without\n" + " modifications, as long as this notice is preserved.\n" + "\n" + " This file is distributed in the hope that it will be useful, but\n" + " WITHOUT ANY WARRANTY, to the extent permitted by law; without even\n" + " the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n" + " PURPOSE.\n" + "\n" + " +++ Do not edit! File has been generated by mkw32errmap.c +++\n" + "\n" + " This file is intended to be used with ming32ce-gcc to implement an\n" + " errno substitute under WindowsCE. It must be included via gcc's\n" + " -idirafter option. The gpg-error-config script emits the\n" + " appropriate option snippet. The actual implementation of the errno\n" + " related functions are part of libgpg-error. A separate header file\n" + " is required because errno.h is often included before gpg-error.h.\n" + " */\n" + "\n" + "#ifndef _GPG_ERROR_EXTRA_ERRNO_H\n" + "#define _GPG_ERROR_EXTRA_ERRNO_H\n" + "\n" + "/* Due to peculiarities in W32 we can't implement ERRNO as an\n" + " writable lvalue. This also allows us to easily find places\n" + " where ERRNO is being written to. See also gpg_err_set_errno. */\n" + "int _gpg_w32ce_get_errno (void);\n" + "#define errno (_gpg_w32ce_get_errno ())\n" + "\n"; +static const char footer_gpg_extra_errno_h[] = + "\n" + "#endif /*_GPG_ERROR_EXTRA_ERRNO_H*/\n"; + + +/* The table below is used in two modes. First we run the host + preprocessor over it to generate a new include file. This include + file has the same content but the Windows error macros are + resolved. This is so that we don't need to include winerror.h into + the generated errno.h. The mkw32errmap_marker variable is only + here to have something to grep for after preprocessing. */ +static int mkw32errmap_marker; +struct table_s +{ + int *dummy; + const char *name; + int w32code; + int w32code2; +}; + +struct table_s table[] = + { +#ifdef RESOLVE_MACROS +#define X(a,b,c) \ + {&mkw32errmap_marker, (a), (b), (c)} + X( "EPERM", ERROR_CANNOT_MAKE , 0 ), + X( "ENOENT", ERROR_FILE_NOT_FOUND , ERROR_PATH_NOT_FOUND ), + X( "EINTR", ERROR_INVALID_AT_INTERRUPT_TIME , 0 ), + X( "EIO", ERROR_IO_DEVICE , 0 ), + X( "ENXIO", ERROR_FILE_INVALID , 0 ), + X( "EBADF", ERROR_INVALID_HANDLE , 0 ), + X( "EAGAIN", ERROR_MORE_DATA , WSAEWOULDBLOCK ), + + X( "ENOMEM", ERROR_NOT_ENOUGH_MEMORY , 0 ), + X( "EACCES", ERROR_ACCESS_DENIED , 0 ), + X( "EFAULT", ERROR_PROCESS_ABORTED , 0 ), + X( "EBUSY", ERROR_BUSY , 0 ), + X( "EEXIST", ERROR_FILE_EXISTS , WSAEADDRINUSE ), + + X( "EXDEV", ERROR_NOT_SAME_DEVICE , 0 ), + X( "ENODEV", ERROR_BAD_DEVICE , ERROR_DEV_NOT_EXIST ), + + X( "ENOTDIR",ERROR_DIRECTORY , 0 ), + X( "EINVAL", ERROR_INVALID_PARAMETER , 0 ), + X( "ENFILE", ERROR_NO_MORE_FILES , 0 ), + X( "EMFILE", ERROR_TOO_MANY_OPEN_FILES , 0 ), + X( "ENOSPC", ERROR_DISK_FULL , 0 ), + X( "EROFS", ERROR_WRITE_PROTECT , 0 ), + X( "EPIPE", ERROR_BROKEN_PIPE , 0 ), + X( "ERANGE", ERROR_ARITHMETIC_OVERFLOW , 0 ), + X( "EDEADLOCK",ERROR_POSSIBLE_DEADLOCK , 0 ), + X( "ENAMETOOLONG", ERROR_FILENAME_EXCED_RANGE, 0 ), + X( "ENOLCK", ERROR_SHARING_BUFFER_EXCEEDED , 0 ), + X( "ENOSYS", ERROR_NOT_SUPPORTED , 0 ), + X( "ENOTEMPTY",ERROR_DIR_NOT_EMPTY , 0 ), + X( "ESPIPE", ERROR_SEEK_ON_DEVICE , 0 ), +#if 0 /* FIXME: Find appropriate mappings. */ + X( "EILSEQ", ), + X( "EDOM", ), + X( "EMLINK", ), + X( "ESRCH", ), /* No such process */ + X( "E2BIG", ), /* Arg list too long */ + X( "ENOEXEC", ), /* Exec format error */ + X( "ECHILD", ), /* No child processes */ + X( "EISDIR", ), /* Is a directory */ + X( "ENOTTY", ), /* Inappropriate I/O control operation */ + X( "EFBIG", ), /* File too large */ +#endif +#undef X +#else /*!RESOLVE_MACROS*/ +# include "mkw32errmap.tab.h" +#endif /*!RESOLVE_MACROS*/ + { NULL, 0 } + }; + + + +static int +compare_table (const void *a_v, const void *b_v) +{ + const struct table_s *a = a_v; + const struct table_s *b = b_v; + + return (a->w32code - b->w32code); +} + + +int +main (int argc, char **argv) +{ + int idx; + + for (idx=0; table[idx].name; idx++) + ; + qsort (table, idx, sizeof *table, compare_table); + + if (argc == 2 && !strcmp (argv[1], "--map")) + { + fputs ("static int\n" + "map_w32codes (int err)\n" + "{\n" + " switch (err)\n" + " {\n", stdout ); + for (idx=0; table[idx].name; idx++) + if (table[idx].w32code2) + printf (" case %d: return %d;\n", + table[idx].w32code2, table[idx].w32code); + fputs (" default: return err;\n" + " }\n" + "}\n", stdout); + } + else + { + fputs (header_gpg_extra_errno_h, stdout); + for (idx=0; table[idx].name; idx++) + printf ("#define %-12s %5d\n", table[idx].name, table[idx].w32code); + fputs (footer_gpg_extra_errno_h, stdout); + } + + return 0; +} diff --git a/comm/third_party/libgpg-error/src/posix-lock-obj.h b/comm/third_party/libgpg-error/src/posix-lock-obj.h new file mode 100644 index 0000000000..08e0bace07 --- /dev/null +++ b/comm/third_party/libgpg-error/src/posix-lock-obj.h @@ -0,0 +1,42 @@ +/* posic-lock-obj.h - Declaration of the POSIX lock object + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#ifndef POSIX_LOCK_OBJ_H +#define POSIX_LOCK_OBJ_H + +#define LOCK_ABI_NOT_AVAILABLE (-1) +#if USE_POSIX_THREADS +# define LOCK_ABI_VERSION 1 +#else +# define LOCK_ABI_VERSION LOCK_ABI_NOT_AVAILABLE +#endif + +typedef struct +{ + long vers; +#if USE_POSIX_THREADS + union { + pthread_mutex_t mtx; + long *dummy; + } u; +#endif +} _gpgrt_lock_t; + + +#endif /*POSIX_LOCK_OBJ_H*/ diff --git a/comm/third_party/libgpg-error/src/posix-lock.c b/comm/third_party/libgpg-error/src/posix-lock.c new file mode 100644 index 0000000000..be4cc27559 --- /dev/null +++ b/comm/third_party/libgpg-error/src/posix-lock.c @@ -0,0 +1,263 @@ +/* posix-lock.c - GPGRT lock functions for POSIX systems + Copyright (C) 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + + Parts of the code, in particular use_pthreads_p, are based on code + from gettext, written by Bruno Haible , 2005. + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_W32_SYSTEM +# error This module may not be build for Windows. +#endif + +#include +#include +#include +#include + +#if USE_POSIX_THREADS +# include +#endif + +#include "gpgrt-int.h" +#include "lock.h" +#include "posix-lock-obj.h" + + +#if USE_POSIX_THREADS +# if USE_POSIX_THREADS_WEAK + /* On ELF systems it is easy to use pthreads using weak + references. Take care not to test the address of a weak + referenced function we actually use; some GCC versions have a + bug were &foo != NULL is always evaluated to true in PIC mode. */ +# pragma weak pthread_cancel +# pragma weak pthread_mutex_init +# pragma weak pthread_mutex_lock +# pragma weak pthread_mutex_trylock +# pragma weak pthread_mutex_unlock +# pragma weak pthread_mutex_destroy +# if ! PTHREAD_IN_USE_DETECTION_HARD +# define use_pthread_p() (!!pthread_cancel) +# endif +# else /*!USE_POSIX_THREADS_WEAK*/ +# if ! PTHREAD_IN_USE_DETECTION_HARD +# define use_pthread_p() (1) +# endif +# endif /*!USE_POSIX_THREADS_WEAK*/ +# if PTHREAD_IN_USE_DETECTION_HARD +/* The function to be executed by a dummy thread. */ +static void * +dummy_thread_func (void *arg) +{ + return arg; +} + +static int +use_pthread_p (void) +{ + static int tested; + static int result; /* 1: linked with -lpthread, 0: only with libc */ + + if (!tested) + { + pthread_t thread; + + if (pthread_create (&thread, NULL, dummy_thread_func, NULL)) + result = 0; /* Thread creation failed. */ + else + { + /* Thread creation works. */ + void *retval; + if (pthread_join (thread, &retval) != 0) + { + fputs ("gpgrt fatal: pthread_join in use_pthread_p failed\n", + stderr); + _gpgrt_abort (); + } + result = 1; + } + tested = 1; + } + return result; +} +#endif /*PTHREAD_IN_USE_DETECTION_HARD*/ +#endif /*USE_POSIX_THREADS*/ + + +static _gpgrt_lock_t * +get_lock_object (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd; + + if (lock->vers != LOCK_ABI_VERSION) + { + fputs ("gpgrt fatal: lock ABI version mismatch\n", stderr); + _gpgrt_abort (); + } + if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t)) + { + fputs ("gpgrt fatal: sizeof lock obj\n", stderr); + _gpgrt_abort (); + } + + return lock; +} + + +gpg_err_code_t +_gpgrt_lock_init (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd; + int rc; + + /* If VERS is zero we assume that no static initialization has been + done, so we setup our ABI version right here. The caller might + have called us to test whether lock support is at all available. */ + if (!lock->vers) + { + if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t)) + { + fputs ("gpgrt fatal: sizeof lock obj\n", stderr); + _gpgrt_abort (); + } + lock->vers = LOCK_ABI_VERSION; + } + else /* Run the usual check. */ + lock = get_lock_object (lockhd); + +#if USE_POSIX_THREADS + if (use_pthread_p()) + { + rc = pthread_mutex_init (&lock->u.mtx, NULL); + if (rc) + rc = _gpg_err_code_from_errno (rc); + } + else + rc = 0; /* Threads are not used. */ +#else /* Unknown thread system. */ + rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED; +#endif /* Unknown thread system. */ + + return rc; +} + + +gpg_err_code_t +_gpgrt_lock_lock (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + int rc; + +#if USE_POSIX_THREADS + if (use_pthread_p()) + { + _gpgrt_pre_syscall (); + rc = pthread_mutex_lock (&lock->u.mtx); + if (rc) + rc = _gpg_err_code_from_errno (rc); + _gpgrt_post_syscall (); + } + else + rc = 0; /* Threads are not used. */ +#else /* Unknown thread system. */ + rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED; +#endif /* Unknown thread system. */ + + return rc; +} + + +gpg_err_code_t +_gpgrt_lock_trylock (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + int rc; + +#if USE_POSIX_THREADS + if (use_pthread_p()) + { + rc = pthread_mutex_trylock (&lock->u.mtx); + if (rc) + rc = _gpg_err_code_from_errno (rc); + } + else + rc = 0; /* Threads are not used. */ +#else /* Unknown thread system. */ + rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED; +#endif /* Unknown thread system. */ + + return rc; +} + + +gpg_err_code_t +_gpgrt_lock_unlock (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + int rc; + +#if USE_POSIX_THREADS + if (use_pthread_p()) + { + rc = pthread_mutex_unlock (&lock->u.mtx); + if (rc) + rc = _gpg_err_code_from_errno (rc); + } + else + rc = 0; /* Threads are not used. */ +#else /* Unknown thread system. */ + rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED; +#endif /* Unknown thread system. */ + + return rc; +} + + +/* Note: Use this function only if no other thread holds or waits for + this lock. */ +gpg_err_code_t +_gpgrt_lock_destroy (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + int rc; + +#if USE_POSIX_THREADS + if (use_pthread_p()) + { + rc = pthread_mutex_destroy (&lock->u.mtx); + if (rc) + rc = _gpg_err_code_from_errno (rc); + else + { + /* Re-init the mutex so that it can be re-used. */ + gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER; + memcpy (lockhd, &tmp, sizeof tmp); + } + } + else + rc = 0; /* Threads are not used. */ +#else /* Unknown thread system. */ + rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED; +#endif /* Unknown thread system. */ + + return rc; +} diff --git a/comm/third_party/libgpg-error/src/posix-thread.c b/comm/third_party/libgpg-error/src/posix-thread.c new file mode 100644 index 0000000000..36c81ba6f8 --- /dev/null +++ b/comm/third_party/libgpg-error/src/posix-thread.c @@ -0,0 +1,68 @@ +/* posix-thread.c - GPGRT thread functions for POSIX systems + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_W32_SYSTEM +# error This module may not be build for Windows. +#endif + +#include +#include +#include +#include +#include /* Get posix option macros. */ + +#if USE_POSIX_THREADS +# ifdef _POSIX_PRIORITY_SCHEDULING +# include +# endif +#elif USE_SOLARIS_THREADS +# include +#endif + +#include "gpgrt-int.h" + +#include "thread.h" + + + +gpg_err_code_t +_gpgrt_yield (void) +{ +#if USE_POSIX_THREADS +# ifdef _POSIX_PRIORITY_SCHEDULING + _gpgrt_pre_syscall (); + sched_yield (); + _gpgrt_post_syscall (); +# else + return GPG_ERR_NOT_SUPPORTED; +# endif +#elif USE_SOLARIS_THREADS + _gpgrt_pre_syscall (); + thr_yield (); + _gpgrt_post_syscall (); +#else + return GPG_ERR_NOT_SUPPORTED; +#endif + + return 0; +} diff --git a/comm/third_party/libgpg-error/src/protos.h b/comm/third_party/libgpg-error/src/protos.h new file mode 100644 index 0000000000..7cc3489e33 --- /dev/null +++ b/comm/third_party/libgpg-error/src/protos.h @@ -0,0 +1,31 @@ +/* protos.h - Miscellaneous prototypes + * Copyright (C) 2020 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef _GPGRT_PROTOS_H +#define _GPGRT_PROTOS_H + +/*-- w32-gettext.c --*/ +wchar_t *_gpgrt_utf8_to_wchar (const char *string); +void _gpgrt_free_wchar (wchar_t *wstring); +char *_gpgrt_wchar_to_utf8 (const wchar_t *string, size_t length); +void _gpgrt_w32_set_errno (int ec); + + +#endif /*_GPGRT_PROTOS_H*/ diff --git a/comm/third_party/libgpg-error/src/spawn-posix.c b/comm/third_party/libgpg-error/src/spawn-posix.c new file mode 100644 index 0000000000..ac4c4ce8ae --- /dev/null +++ b/comm/third_party/libgpg-error/src/spawn-posix.c @@ -0,0 +1,886 @@ +/* exechelp.c - Fork and exec helpers for POSIX + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + * + * This file was originally a part of GnuPG. + */ + +#include + +#if defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM) +#error This code is only used on POSIX +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_SIGNAL_H +# include +#endif +#include +#include + +#include + +#ifdef HAVE_GETRLIMIT +#include +#include +#endif /*HAVE_GETRLIMIT*/ + +#ifdef HAVE_STAT +# include +#endif + +#if __linux__ +# include +# include +#endif /*__linux__ */ + +#include "gpgrt-int.h" + + +static void +out_of_core (int line) +{ + _gpgrt_log_fatal ("malloc failed at line %d: %s\n", + line, _gpg_strerror (_gpg_err_code_from_syserror ())); + /*NOTREACHED*/ +} + + +/* Return the maximum number of currently allowed open file + * descriptors. Only useful on POSIX systems but returns a value on + * other systems too. */ +static int +get_max_fds (void) +{ + int max_fds = -1; +#ifdef HAVE_GETRLIMIT + struct rlimit rl; + + /* Under Linux we can figure out the highest used file descriptor by + * reading /proc/PID/fd. This is in the common cases much fast than + * for example doing 4096 close calls where almost all of them will + * fail. On a system with a limit of 4096 files and only 8 files + * open with the highest number being 10, we speedup close_all_fds + * from 125ms to 0.4ms including readdir. + * + * Another option would be to close the file descriptors as returned + * from reading that directory - however then we need to snapshot + * that list before starting to close them. */ +#ifdef __linux__ + { + DIR *dir = NULL; + struct dirent *dir_entry; + const char *s; + int x; + + /* FIXME: Check gpgme on how to do this right on Linux. */ + dir = opendir ("/proc/self/fd"); + if (dir) + { + while ((dir_entry = readdir (dir))) + { + s = dir_entry->d_name; + if ( *s < '0' || *s > '9') + continue; + x = atoi (s); + if (x > max_fds) + max_fds = x; + } + closedir (dir); + } + if (max_fds != -1) + return max_fds + 1; + } +#endif /* __linux__ */ + + +# ifdef RLIMIT_NOFILE + if (!getrlimit (RLIMIT_NOFILE, &rl)) + max_fds = rl.rlim_max; +# endif + +# ifdef RLIMIT_OFILE + if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl)) + max_fds = rl.rlim_max; + +# endif +#endif /*HAVE_GETRLIMIT*/ + +#ifdef _SC_OPEN_MAX + if (max_fds == -1) + { + long int scres = sysconf (_SC_OPEN_MAX); + if (scres >= 0) + max_fds = scres; + } +#endif + +#ifdef _POSIX_OPEN_MAX + if (max_fds == -1) + max_fds = _POSIX_OPEN_MAX; +#endif + +#ifdef OPEN_MAX + if (max_fds == -1) + max_fds = OPEN_MAX; +#endif + + if (max_fds == -1) + max_fds = 256; /* Arbitrary limit. */ + + /* AIX returns INT32_MAX instead of a proper value. We assume that + this is always an error and use an arbitrary limit. */ +#ifdef INT32_MAX + if (max_fds == INT32_MAX) + max_fds = 256; +#endif + + return max_fds; +} + + +/* Close all file descriptors starting with descriptor FIRST. If + * EXCEPT is not NULL, it is expected to be a list of file descriptors + * which shall not be closed. This list shall be sorted in ascending + * order with the end marked by -1. */ +static void +close_all_fds (int first, int *except) +{ + int max_fd = get_max_fds (); + int fd, i, except_start; + + if (except) + { + except_start = 0; + for (fd=first; fd < max_fd; fd++) + { + for (i=except_start; except[i] != -1; i++) + { + if (except[i] == fd) + { + /* If we found the descriptor in the exception list + we can start the next compare run at the next + index because the exception list is ordered. */ + except_start = i + 1; + break; + } + } + if (except[i] == -1) + close (fd); + } + } + else + { + for (fd=first; fd < max_fd; fd++) + close (fd); + } + + _gpg_err_set_errno (0); +} + + +/* Returns an array with all currently open file descriptors. The end + * of the array is marked by -1. The caller needs to release this + * array using the *standard free* and not with xfree. This allow the + * use of this function right at startup even before libgcrypt has + * been initialized. Returns NULL on error and sets ERRNO + * accordingly. + * + * FIXME: Needs to be adjusted for use here. + */ +#if 0 +int * +get_all_open_fds (void) +{ + int *array; + size_t narray; + int fd, max_fd, idx; +#ifndef HAVE_STAT + array = calloc (1, sizeof *array); + if (array) + array[0] = -1; +#else /*HAVE_STAT*/ + struct stat statbuf; + + max_fd = get_max_fds (); + narray = 32; /* If you change this change also t-exechelp.c. */ + array = calloc (narray, sizeof *array); + if (!array) + return NULL; + + /* Note: The list we return is ordered. */ + for (idx=0, fd=0; fd < max_fd; fd++) + if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) + { + if (idx+1 >= narray) + { + int *tmp; + + narray += (narray < 256)? 32:256; + tmp = realloc (array, narray * sizeof *array); + if (!tmp) + { + free (array); + return NULL; + } + array = tmp; + } + array[idx++] = fd; + } + array[idx] = -1; +#endif /*HAVE_STAT*/ + return array; +} +#endif /*0*/ + + +/* The exec core used right after the fork. This will never return. */ +static void +do_exec (const char *pgmname, const char *argv[], + int fd_in, int fd_out, int fd_err, + int *except, void (*preexec)(void) ) +{ + char **arg_list; + int i, j; + int fds[3]; + + fds[0] = fd_in; + fds[1] = fd_out; + fds[2] = fd_err; + + /* Create the command line argument array. */ + i = 0; + if (argv) + while (argv[i]) + i++; + arg_list = xtrycalloc (i+2, sizeof *arg_list); + if (!arg_list) + out_of_core (__LINE__); + arg_list[0] = strrchr (pgmname, '/'); + if (arg_list[0]) + arg_list[0]++; + else + { + arg_list[0] = xtrystrdup (pgmname); + if (!arg_list[0]) + out_of_core (__LINE__); + } + if (argv) + for (i=0,j=1; argv[i]; i++, j++) + arg_list[j] = (char*)argv[i]; + + /* Assign /dev/null to unused FDs. */ + for (i=0; i <= 2; i++) + { + if (fds[i] == -1 ) + { + fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY); + if (fds[i] == -1) + _gpgrt_log_fatal ("failed to open '%s': %s\n", + "/dev/null", strerror (errno)); + } + } + + /* Connect the standard files. */ + for (i=0; i <= 2; i++) + { + if (fds[i] != i && dup2 (fds[i], i) == -1) + _gpgrt_log_fatal ("dup2 std%s failed: %s\n", + i==0?"in":i==1?"out":"err", strerror (errno)); + } + + /* Close all other files. */ + close_all_fds (3, except); + + if (preexec) + preexec (); + execv (pgmname, arg_list); + /* No way to print anything, as we have may have closed all streams. */ + _exit (127); +} + + +/* Helper for _gpgrt_make_pipe. */ +static gpg_err_code_t +do_create_pipe (int filedes[2]) +{ + gpg_error_t err = 0; + + _gpgrt_pre_syscall (); + if (pipe (filedes) == -1) + { + err = _gpg_err_code_from_syserror (); + filedes[0] = filedes[1] = -1; + } + _gpgrt_post_syscall (); + + return err; +} + + +/* Helper for _gpgrt_make_pipe. */ +static gpg_err_code_t +do_create_pipe_and_estream (int filedes[2], estream_t *r_fp, + int outbound, int nonblock) +{ + gpg_err_code_t err; + + _gpgrt_pre_syscall (); + if (pipe (filedes) == -1) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error creating a pipe: %s\n"), _gpg_strerror (err)); + filedes[0] = filedes[1] = -1; + *r_fp = NULL; + return err; + } + _gpgrt_post_syscall (); + + if (!outbound) + *r_fp = _gpgrt_fdopen (filedes[0], nonblock? "r,nonblock" : "r"); + else + *r_fp = _gpgrt_fdopen (filedes[1], nonblock? "w,nonblock" : "w"); + if (!*r_fp) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error creating a stream for a pipe: %s\n"), + _gpg_strerror (err)); + close (filedes[0]); + close (filedes[1]); + filedes[0] = filedes[1] = -1; + return err; + } + return 0; +} + + +/* Create a pipe. The DIRECTION parameter gives the type of the created pipe: + * DIRECTION < 0 := Inbound pipe: On Windows the write end is inheritable. + * DIRECTION > 0 := Outbound pipe: On Windows the read end is inheritable. + * If R_FP is NULL a standard pipe and no stream is created, DIRECTION + * should then be 0. */ +gpg_err_code_t +_gpgrt_make_pipe (int filedes[2], estream_t *r_fp, int direction, + int nonblock) +{ + if (r_fp && direction) + return do_create_pipe_and_estream (filedes, r_fp, + (direction > 0), nonblock); + else + return do_create_pipe (filedes); +} + + +/* Fork and exec the PGMNAME, see gpgrt-int.h for details. */ +gpg_err_code_t +_gpgrt_spawn_process (const char *pgmname, const char *argv[], + int *except, void (*preexec)(void), unsigned int flags, + estream_t *r_infp, + estream_t *r_outfp, + estream_t *r_errfp, + pid_t *pid) +{ + gpg_error_t err; + int inpipe[2] = {-1, -1}; + int outpipe[2] = {-1, -1}; + int errpipe[2] = {-1, -1}; + estream_t infp = NULL; + estream_t outfp = NULL; + estream_t errfp = NULL; + int nonblock = !!(flags & GPGRT_SPAWN_NONBLOCK); + + if (r_infp) + *r_infp = NULL; + if (r_outfp) + *r_outfp = NULL; + if (r_errfp) + *r_errfp = NULL; + *pid = (pid_t)(-1); /* Always required. */ + + if (r_infp) + { + err = _gpgrt_create_outbound_pipe (inpipe, &infp, nonblock); + if (err) + return err; + } + + if (r_outfp) + { + err = _gpgrt_create_inbound_pipe (outpipe, &outfp, nonblock); + if (err) + { + if (infp) + _gpgrt_fclose (infp); + else if (inpipe[1] != -1) + close (inpipe[1]); + if (inpipe[0] != -1) + close (inpipe[0]); + + return err; + } + } + + if (r_errfp) + { + err = _gpgrt_create_inbound_pipe (errpipe, &errfp, nonblock); + if (err) + { + if (infp) + _gpgrt_fclose (infp); + else if (inpipe[1] != -1) + close (inpipe[1]); + if (inpipe[0] != -1) + close (inpipe[0]); + + if (outfp) + _gpgrt_fclose (outfp); + else if (outpipe[0] != -1) + close (outpipe[0]); + if (outpipe[1] != -1) + close (outpipe[1]); + + return err; + } + } + + _gpgrt_pre_syscall (); + *pid = fork (); + _gpgrt_post_syscall (); + if (*pid == (pid_t)(-1)) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error forking process: %s\n"), _gpg_strerror (err)); + + if (infp) + _gpgrt_fclose (infp); + else if (inpipe[1] != -1) + close (inpipe[1]); + if (inpipe[0] != -1) + close (inpipe[0]); + + if (outfp) + _gpgrt_fclose (outfp); + else if (outpipe[0] != -1) + close (outpipe[0]); + if (outpipe[1] != -1) + close (outpipe[1]); + + if (errfp) + _gpgrt_fclose (errfp); + else if (errpipe[0] != -1) + close (errpipe[0]); + if (errpipe[1] != -1) + close (errpipe[1]); + return err; + } + + if (!*pid) + { + /* This is the child. */ + /* FIXME: Needs to be done by preexec: + gcry_control (GCRYCTL_TERM_SECMEM); */ + _gpgrt_fclose (infp); + _gpgrt_fclose (outfp); + _gpgrt_fclose (errfp); + do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1], + except, preexec); + /*NOTREACHED*/ + } + + /* This is the parent. */ + if (inpipe[0] != -1) + close (inpipe[0]); + if (outpipe[1] != -1) + close (outpipe[1]); + if (errpipe[1] != -1) + close (errpipe[1]); + + if (r_infp) + *r_infp = infp; + if (r_outfp) + *r_outfp = outfp; + if (r_errfp) + *r_errfp = errfp; + + return 0; +} + + +/* Fork and exec the PGMNAME using FDs, see gpgrt-int.h for details. */ +gpg_err_code_t +_gpgrt_spawn_process_fd (const char *pgmname, const char *argv[], + int infd, int outfd, int errfd, pid_t *pid) +{ + gpg_error_t err; + + _gpgrt_pre_syscall (); + *pid = fork (); + _gpgrt_post_syscall (); + if (*pid == (pid_t)(-1)) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error forking process: %s\n"), _gpg_strerror (err)); + return err; + } + + if (!*pid) + { + /* FIXME: We need to add a preexec so that a + gcry_control (GCRYCTL_TERM_SECMEM); + can be done. */ + /* Run child. */ + do_exec (pgmname, argv, infd, outfd, errfd, NULL, NULL); + /*NOTREACHED*/ + } + + return 0; +} + + +/* Waiting for child processes. + * + * waitpid(2) may return information about terminated children that we + * did not yet request, and there is no portable way to wait for a + * specific set of children. + * + * As a workaround, we store the results of children for later use. + * + * XXX: This assumes that PIDs are not reused too quickly. + * FIXME: This is not thread-safe. + */ + +struct terminated_child +{ + pid_t pid; + int exitcode; + struct terminated_child *next; +}; + +static struct terminated_child *terminated_children; + + +static gpg_err_code_t +store_result (pid_t pid, int exitcode) +{ + struct terminated_child *c; + + c = xtrymalloc (sizeof *c); + if (c == NULL) + return _gpg_err_code_from_syserror (); + + c->pid = pid; + c->exitcode = exitcode; + c->next = terminated_children; + terminated_children = c; + + return 0; +} + + +static int +get_result (pid_t pid, int *r_exitcode) +{ + struct terminated_child *c, **prevp; + + for (prevp = &terminated_children, c = terminated_children; + c; + prevp = &c->next, c = c->next) + if (c->pid == pid) + { + *prevp = c->next; + *r_exitcode = c->exitcode; + xfree (c); + return 1; + } + + return 0; +} + + +/* See gpgrt-int.h for a description. */ +gpg_err_code_t +_gpgrt_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode) +{ + gpg_err_code_t ec; + int i, status; + + if (r_exitcode) + *r_exitcode = -1; + + if (pid == (pid_t)(-1)) + return GPG_ERR_INV_VALUE; + + _gpgrt_pre_syscall (); + while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1) + && errno == EINTR); + _gpgrt_post_syscall (); + + if (i == (pid_t)(-1)) + { + ec = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("waiting for process %d to terminate failed: %s\n"), + (int)pid, _gpg_strerror (ec)); + } + else if (!i) + { + ec = GPG_ERR_TIMEOUT; /* Still running. */ + } + else if (WIFEXITED (status) && WEXITSTATUS (status) == 127) + { + /* FIXME: This is GnuPG specific. */ + _gpgrt_log_error (_("error running '%s': probably not installed\n"), + pgmname); + ec = GPG_ERR_CONFIGURATION; + } + else if (WIFEXITED (status) && WEXITSTATUS (status)) + { + if (!r_exitcode) + _gpgrt_log_error (_("error running '%s': exit status %d\n"), pgmname, + WEXITSTATUS (status)); + else + *r_exitcode = WEXITSTATUS (status); + ec = GPG_ERR_GENERAL; + } + else if (!WIFEXITED (status)) + { + _gpgrt_log_error (_("error running '%s': terminated\n"), pgmname); + ec = GPG_ERR_GENERAL; + } + else + { + if (r_exitcode) + *r_exitcode = 0; + ec = 0; + } + + return ec; +} + + +/* See gpgrt-int.h for a description. + * + * FIXME: What about using a poll like data structure for the pids and + * their exit codes? The whole thing is anyway problematic in a + * threaded processs because waitpid has no association between PIDS + * and threads. + */ +gpg_err_code_t +_gpgrt_wait_processes (const char **pgmnames, pid_t *pids, size_t count, + int hang, int *r_exitcodes) +{ + gpg_err_code_t ec = 0; + size_t i, left; + int *dummy = NULL; + + if (!r_exitcodes) + { + dummy = r_exitcodes = xtrymalloc (sizeof *r_exitcodes * count); + if (!dummy) + return _gpg_err_code_from_syserror (); + } + + for (i = 0, left = count; i < count; i++) + { + int status = -1; + + if (pids[i] == (pid_t)(-1)) + return GPG_ERR_INV_VALUE; + + /* See if there was a previously stored result for this pid. */ + if (get_result (pids[i], &status)) + left -= 1; + + r_exitcodes[i] = status; + } + + while (left > 0) + { + pid_t pid; + int status; + + _gpgrt_pre_syscall (); + while ((pid = waitpid (-1, &status, hang ? 0 : WNOHANG)) == (pid_t)(-1) + && errno == EINTR); + _gpgrt_post_syscall (); + + if (pid == (pid_t)(-1)) + { + ec = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("waiting for processes to terminate" + " failed: %s\n"), _gpg_strerror (ec)); + break; + } + else if (!pid) + { + ec = GPG_ERR_TIMEOUT; /* Still running. */ + break; + } + else + { + for (i = 0; i < count; i++) + if (pid == pids[i]) + break; + + if (i == count) + { + /* No match, store this result. */ + ec = store_result (pid, status); + if (ec) + break; + continue; + } + + /* Process PIDS[i] died. */ + if (r_exitcodes[i] != (pid_t) -1) + { + _gpgrt_log_error ("PID %d was reused", (int)pid); + ec = GPG_ERR_GENERAL; + break; + } + + left -= 1; + r_exitcodes[i] = status; + } + } + + for (i = 0; i < count; i++) + { + if (r_exitcodes[i] == -1) + continue; + + if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127) + { + _gpgrt_log_error (_("error running '%s': probably not installed\n"), + pgmnames[i]); + ec = GPG_ERR_CONFIGURATION; + } + else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i])) + { + if (dummy) + _gpgrt_log_error (_("error running '%s': exit status %d\n"), + pgmnames[i], WEXITSTATUS (r_exitcodes[i])); + else + r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]); + ec = GPG_ERR_GENERAL; + } + else if (!WIFEXITED (r_exitcodes[i])) + { + _gpgrt_log_error (_("error running '%s': terminated\n"), pgmnames[i]); + ec = GPG_ERR_GENERAL; + } + } + + xfree (dummy); + return ec; +} + + +/* See gpgrt-int.h for a description. FIXME: We should add a prexec + * callback. */ +gpg_err_code_t +_gpgrt_spawn_process_detached (const char *pgmname, const char *argv[], + const char *envp[] ) +{ + gpg_err_code_t ec; + pid_t pid; + int i; + + /* FIXME: Is this GnuPG specific or should we keep it. */ + if (getuid() != geteuid()) + return GPG_ERR_BUG; + + if (access (pgmname, X_OK)) + return _gpg_err_code_from_syserror (); + + _gpgrt_pre_syscall (); + pid = fork (); + _gpgrt_post_syscall (); + if (pid == (pid_t)(-1)) + { + ec = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error forking process: %s\n"), _gpg_strerror (ec)); + return ec; + } + + if (!pid) + { + pid_t pid2; + + /* gcry_control (GCRYCTL_TERM_SECMEM); */ + if (setsid() == -1 || chdir ("/")) + _exit (1); + + pid2 = fork (); /* Double fork to let init take over the new child. */ + if (pid2 == (pid_t)(-1)) + _exit (1); + if (pid2) + _exit (0); /* Let the parent exit immediately. */ + + for (i=0; envp && envp[i]; i++) + { + char *p = xtrystrdup (envp[i]); + if (!p) + out_of_core (__LINE__); + putenv (p); + } + + do_exec (pgmname, argv, -1, -1, -1, NULL, NULL); + /*NOTREACHED*/ + } + + _gpgrt_pre_syscall (); + if (waitpid (pid, NULL, 0) == -1) + { + _gpgrt_post_syscall (); + ec = _gpg_err_code_from_syserror (); + _gpgrt_log_error ("waitpid failed in gpgrt_spawn_process_detached: %s", + _gpg_strerror (ec)); + return ec; + } + else + _gpgrt_post_syscall (); + + return 0; +} + + +/* Kill a process; that is send an appropriate signal to the process. + * gnupg_wait_process must be called to actually remove the process + from the system. An invalid PID is ignored. */ +void +_gpgrt_kill_process (pid_t pid) +{ + if (pid != (pid_t)(-1)) + { + _gpgrt_pre_syscall (); + kill (pid, SIGTERM); + _gpgrt_post_syscall (); + } +} + + +void +_gpgrt_release_process (pid_t pid) +{ + (void)pid; +} diff --git a/comm/third_party/libgpg-error/src/spawn-w32.c b/comm/third_party/libgpg-error/src/spawn-w32.c new file mode 100644 index 0000000000..3ede1f2149 --- /dev/null +++ b/comm/third_party/libgpg-error/src/spawn-w32.c @@ -0,0 +1,920 @@ +/* spawn-w32.c - Fork and exec helpers for W32. + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc. + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + * + * This file was originally a part of GnuPG. + */ + +#include + +#if !defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM) +#error This code is only used on W32. +#endif + +#include +#include +#include +#include +#ifdef HAVE_SIGNAL_H +# include +#endif +#include +#include +#ifdef HAVE_STAT +# include +#endif +#define WIN32_LEAN_AND_MEAN /* We only need the OS core stuff. */ +#include + +#include "gpgrt-int.h" + +/* Define to 1 do enable debugging. */ +#define DEBUG_W32_SPAWN 0 + + +/* It seems Vista doesn't grok X_OK and so fails access() tests. + * Previous versions interpreted X_OK as F_OK anyway, so we'll just + * use F_OK directly. */ +#undef X_OK +#define X_OK F_OK + +/* For HANDLE and the internal file descriptor (fd) of this module: + * HANDLE can be represented by an intptr_t which should be true for + * all systems (HANDLE is defined as void *). Further, we assume that + * -1 denotes an invalid handle. + * + * Note that a C run-time file descriptor (the exposed one to API) is + * always represented by an int. + */ +#define fd_to_handle(a) ((HANDLE)(a)) +#define handle_to_fd(a) ((intptr_t)(a)) + +/* For pid_t and HANDLE: + + * We assume that a HANDLE can be represented by an int which should + * be true for all i386 systems. + * + * On 64-bit machine, it is no longer true, as a type, however, as + * long as the range of the value in the type HANDLE can be + * represented by an int, it works. + * + * FIXME: Breaking ABI for pid_t will be needed when the value won't + * fit within 32-bit range on 64-bit machine. + */ +#define pid_to_handle(a) ((HANDLE)(a)) +#define handle_to_pid(a) ((int)(a)) + + +/* Return the maximum number of currently allowed open file + * descriptors. Only useful on POSIX systems but returns a value on + * other systems too. */ +int +get_max_fds (void) +{ + int max_fds = -1; + +#ifdef OPEN_MAX + if (max_fds == -1) + max_fds = OPEN_MAX; +#endif + + if (max_fds == -1) + max_fds = 256; /* Arbitrary limit. */ + + return max_fds; +} + + +/* Under Windows this is a dummy function. */ +/* static void */ +/* close_all_fds (int first, int *except) */ +/* { */ +/* (void)first; */ +/* (void)except; */ +/* } */ + + +/* Returns an array with all currently open file descriptors. The end + * of the array is marked by -1. The caller needs to release this + * array using the *standard free* and not with xfree. This allow the + * use of this function right at startup even before libgcrypt has + * been initialized. Returns NULL on error and sets ERRNO + * accordingly. Note that fstat prints a warning to DebugView for all + * invalid fds which is a bit annoying. We actually do not need this + * function in real code (close_all_fds is a dummy anyway) but we keep + * it for use by t-exechelp.c. */ +#if 0 +int * +get_all_open_fds (void) +{ + int *array; + size_t narray; + int fd, max_fd, idx; +#ifndef HAVE_STAT + array = calloc (1, sizeof *array); + if (array) + array[0] = -1; +#else /*HAVE_STAT*/ + struct stat statbuf; + + max_fd = get_max_fds (); + narray = 32; /* If you change this change also t-exechelp.c. */ + array = calloc (narray, sizeof *array); + if (!array) + return NULL; + + /* Note: The list we return is ordered. */ + for (idx=0, fd=0; fd < max_fd; fd++) + if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) + { + if (idx+1 >= narray) + { + int *tmp; + + narray += (narray < 256)? 32:256; + tmp = realloc (array, narray * sizeof *array); + if (!tmp) + { + free (array); + return NULL; + } + array = tmp; + } + array[idx++] = fd; + } + array[idx] = -1; +#endif /*HAVE_STAT*/ + return array; +} +#endif + + +/* Helper function to build_w32_commandline. */ +static char * +build_w32_commandline_copy (char *buffer, const char *string) +{ + char *p = buffer; + const char *s; + + if (!*string) /* Empty string. */ + p = stpcpy (p, "\"\""); + else if (strpbrk (string, " \t\n\v\f\"")) + { + /* Need to do some kind of quoting. */ + p = stpcpy (p, "\""); + for (s=string; *s; s++) + { + *p++ = *s; + if (*s == '\"') + *p++ = *s; + } + *p++ = '\"'; + *p = 0; + } + else + p = stpcpy (p, string); + + return p; +} + + +/* Build a command line for use with W32's CreateProcess. On success + * CMDLINE gets the address of a newly allocated string. */ +static gpg_err_code_t +build_w32_commandline (const char *pgmname, const char * const *argv, + char **cmdline) +{ + int i, n; + const char *s; + char *buf, *p; + + *cmdline = NULL; + n = 0; + s = pgmname; + n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ + for (; *s; s++) + if (*s == '\"') + n++; /* Need to double inner quotes. */ + for (i=0; (s=argv[i]); i++) + { + n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ + for (; *s; s++) + if (*s == '\"') + n++; /* Need to double inner quotes. */ + } + n++; + + buf = p = xtrymalloc (n); + if (!buf) + return _gpg_err_code_from_syserror (); + + p = build_w32_commandline_copy (p, pgmname); + for (i=0; argv[i]; i++) + { + *p++ = ' '; + p = build_w32_commandline_copy (p, argv[i]); + } + + *cmdline= buf; + return 0; +} + + +#define INHERIT_READ 1 +#define INHERIT_WRITE 2 +#define INHERIT_BOTH (INHERIT_READ|INHERIT_WRITE) + +/* Create pipe. FLAGS indicates which ends are inheritable. */ +static int +create_inheritable_pipe (HANDLE filedes[2], int flags) +{ + HANDLE r, w; + SECURITY_ATTRIBUTES sec_attr; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = TRUE; + + _gpgrt_pre_syscall (); + if (!CreatePipe (&r, &w, &sec_attr, 0)) + { + _gpgrt_post_syscall (); + return -1; + } + _gpgrt_post_syscall (); + + if ((flags & INHERIT_READ) == 0) + if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0)) + goto fail; + + if ((flags & INHERIT_WRITE) == 0) + if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0)) + goto fail; + + filedes[0] = r; + filedes[1] = w; + return 0; + + fail: + _gpgrt_log_error ("SetHandleInformation failed: ec=%d\n", + (int)GetLastError ()); + CloseHandle (r); + CloseHandle (w); + return -1; +} + + +static HANDLE +w32_open_null (int for_write) +{ + HANDLE hfile; + + hfile = CreateFileW (L"nul", + for_write? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (hfile == INVALID_HANDLE_VALUE) + _gpgrt_log_debug ("can't open 'nul': ec=%d\n", (int)GetLastError ()); + return hfile; +} + + +static gpg_err_code_t +do_create_pipe_and_estream (int filedes[2], + estream_t *r_fp, int direction, int nonblock) +{ + gpg_err_code_t err = 0; + int flags; + HANDLE fds[2]; + gpgrt_syshd_t syshd; + + if (direction < 0) + flags = INHERIT_WRITE; + else if (direction > 0) + flags = INHERIT_READ; + else + flags = INHERIT_BOTH; + + filedes[0] = filedes[1] = -1; + err = GPG_ERR_GENERAL; + if (!create_inheritable_pipe (fds, flags)) + { + filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY); + if (filedes[0] == -1) + { + _gpgrt_log_error ("failed to translate osfhandle %p\n", fds[0]); + CloseHandle (fds[1]); + } + else + { + filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND); + if (filedes[1] == -1) + { + _gpgrt_log_error ("failed to translate osfhandle %p\n", fds[1]); + close (filedes[0]); + filedes[0] = -1; + CloseHandle (fds[1]); + } + else + err = 0; + } + } + + if (! err && r_fp) + { + syshd.type = ES_SYSHD_HANDLE; + if (direction < 0) + { + syshd.u.handle = fds[0]; + *r_fp = _gpgrt_sysopen (&syshd, nonblock? "r,nonblock" : "r"); + } + else + { + syshd.u.handle = fds[1]; + *r_fp = _gpgrt_sysopen (&syshd, nonblock? "w,nonblock" : "w"); + } + if (!*r_fp) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error creating a stream for a pipe: %s\n"), + _gpg_strerror (err)); + close (filedes[0]); + close (filedes[1]); + filedes[0] = filedes[1] = -1; + return err; + } + } + + return err; +} + + +/* Create a pipe. The DIRECTION parameter gives the type of the created pipe: + * DIRECTION < 0 := Inbound pipe: On Windows the write end is inheritable. + * DIRECTION > 0 := Outbound pipe: On Windows the read end is inheritable. + * If R_FP is NULL a standard pipe and no stream is created, DIRECTION + * should then be 0. */ +gpg_err_code_t +_gpgrt_make_pipe (int filedes[2], estream_t *r_fp, int direction, int nonblock) +{ + if (r_fp && direction) + return do_create_pipe_and_estream (filedes, r_fp, direction, nonblock); + else + return do_create_pipe_and_estream (filedes, NULL, 0, 0); +} + + +/* Fork and exec the PGMNAME, see gpgrt-int.h for details. */ +gpg_err_code_t +_gpgrt_spawn_process (const char *pgmname, const char *argv[], + int *except, void (*preexec)(void), unsigned int flags, + estream_t *r_infp, estream_t *r_outfp, estream_t *r_errfp, + pid_t *pid) +{ + gpg_err_code_t err; + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = + { + NULL, /* Returns process handle. */ + 0, /* Returns primary thread handle. */ + 0, /* Returns pid. */ + 0 /* Returns tid. */ + }; + STARTUPINFO si; + int cr_flags; + char *cmdline; + HANDLE inpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + estream_t infp = NULL; + estream_t outfp = NULL; + estream_t errfp = NULL; + HANDLE nullhd[3] = {INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE}; + int i; + es_syshd_t syshd; + int nonblock = !!(flags & GPGRT_SPAWN_NONBLOCK); + int ret; + + (void)except; /* Not yet used. */ + + if (r_infp) + *r_infp = NULL; + if (r_outfp) + *r_outfp = NULL; + if (r_errfp) + *r_errfp = NULL; + *pid = (pid_t)(-1); /* Always required. */ + + if (r_infp) + { + if (create_inheritable_pipe (inpipe, INHERIT_READ)) + { + err = GPG_ERR_GENERAL; + _gpgrt_log_error (_("error creating a pipe: %s\n"), + _gpg_strerror (err)); + return err; + } + + syshd.type = ES_SYSHD_HANDLE; + syshd.u.handle = inpipe[1]; + infp = _gpgrt_sysopen (&syshd, nonblock? "w,nonblock" : "w"); + if (!infp) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error creating a stream for a pipe: %s\n"), + _gpg_strerror (err)); + CloseHandle (inpipe[0]); + CloseHandle (inpipe[1]); + inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE; + return err; + } + } + + if (r_outfp) + { + if (create_inheritable_pipe (outpipe, INHERIT_WRITE)) + { + err = GPG_ERR_GENERAL; + _gpgrt_log_error (_("error creating a pipe: %s\n"), + _gpg_strerror (err)); + return err; + } + + syshd.type = ES_SYSHD_HANDLE; + syshd.u.handle = outpipe[0]; + outfp = _gpgrt_sysopen (&syshd, nonblock? "r,nonblock" : "r"); + if (!outfp) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error creating a stream for a pipe: %s\n"), + _gpg_strerror (err)); + CloseHandle (outpipe[0]); + CloseHandle (outpipe[1]); + outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE; + if (infp) + _gpgrt_fclose (infp); + else if (inpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (inpipe[1]); + if (inpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (inpipe[0]); + return err; + } + } + + if (r_errfp) + { + if (create_inheritable_pipe (errpipe, INHERIT_WRITE)) + { + err = GPG_ERR_GENERAL; + _gpgrt_log_error (_("error creating a pipe: %s\n"), + _gpg_strerror (err)); + return err; + } + + syshd.type = ES_SYSHD_HANDLE; + syshd.u.handle = errpipe[0]; + errfp = _gpgrt_sysopen (&syshd, nonblock? "r,nonblock" : "r"); + if (!errfp) + { + err = _gpg_err_code_from_syserror (); + _gpgrt_log_error (_("error creating a stream for a pipe: %s\n"), + _gpg_strerror (err)); + CloseHandle (errpipe[0]); + CloseHandle (errpipe[1]); + errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE; + if (outfp) + _gpgrt_fclose (outfp); + else if (outpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[0]); + if (outpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + if (infp) + _gpgrt_fclose (infp); + else if (inpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (inpipe[1]); + if (inpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (inpipe[0]); + return err; + } + } + + /* Prepare security attributes. */ + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + /* Build the command line. */ + err = build_w32_commandline (pgmname, argv, &cmdline); + if (err) + return err; + + if (inpipe[0] == INVALID_HANDLE_VALUE) + nullhd[0] = w32_open_null (0); + if (outpipe[1] == INVALID_HANDLE_VALUE) + nullhd[1] = w32_open_null (1); + if (errpipe[1] == INVALID_HANDLE_VALUE) + nullhd[2] = w32_open_null (1); + + /* Start the process. Note that we can't run the PREEXEC function + because this might change our own environment. */ + (void)preexec; + + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; + si.hStdInput = inpipe[0] == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0]; + si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1]; + si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1]; + + cr_flags = (CREATE_DEFAULT_ERROR_MODE + | ((flags & GPGRT_SPAWN_DETACHED)? DETACHED_PROCESS : 0) + | GetPriorityClass (GetCurrentProcess ()) + | CREATE_SUSPENDED); + _gpgrt_log_debug ("CreateProcess, path='%s' cmdline='%s'\n", + pgmname, cmdline); + ret = CreateProcess (pgmname, /* Program to start. */ + cmdline, /* Command line arguments. */ + &sec_attr, /* Process security attributes. */ + &sec_attr, /* Thread security attributes. */ + TRUE, /* Inherit handles. */ + cr_flags, /* Creation flags. */ + NULL, /* Environment. */ + NULL, /* Use current drive/directory. */ + &si, /* Startup information. */ + &pi /* Returns process information. */ + ); + if (!ret) + { + _gpgrt_log_error ("CreateProcess failed: ec=%d\n", (int)GetLastError ()); + xfree (cmdline); + if (infp) + _gpgrt_fclose (infp); + else if (inpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + if (inpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (inpipe[0]); + if (outfp) + _gpgrt_fclose (outfp); + else if (outpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[0]); + if (outpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + if (errfp) + _gpgrt_fclose (errfp); + else if (errpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (errpipe[0]); + if (errpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (errpipe[1]); + return GPG_ERR_GENERAL; + } + xfree (cmdline); + cmdline = NULL; + + /* Close the inherited handles to /dev/null. */ + for (i=0; i < DIM (nullhd); i++) + if (nullhd[i] != INVALID_HANDLE_VALUE) + CloseHandle (nullhd[i]); + + /* Close the inherited ends of the pipes. */ + if (inpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (inpipe[0]); + if (outpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + if (errpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (errpipe[1]); + + _gpgrt_log_debug ("CreateProcess ready: hProcess=%p hThread=%p" + " dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId); + _gpgrt_log_debug (" outfp=%p errfp=%p\n", outfp, errfp); + + if ((flags & GPGRT_SPAWN_RUN_ASFW)) + { + /* Fixme: For unknown reasons AllowSetForegroundWindow returns + * an invalid argument error if we pass it the correct + * processID. As a workaround we use -1 (ASFW_ANY). */ + if (!AllowSetForegroundWindow (ASFW_ANY /*pi.dwProcessId*/)) + _gpgrt_log_info ("AllowSetForegroundWindow() failed: ec=%d\n", + (int)GetLastError ()); + } + + /* Process has been created suspended; resume it now. */ + _gpgrt_pre_syscall (); + ResumeThread (pi.hThread); + CloseHandle (pi.hThread); + _gpgrt_post_syscall (); + + if (r_infp) + *r_infp = infp; + if (r_outfp) + *r_outfp = outfp; + if (r_errfp) + *r_errfp = errfp; + + *pid = handle_to_pid (pi.hProcess); + return 0; +} + + +/* Fork and exec the PGMNAME using FDs, see gpgrt-int.h for details. */ +gpg_err_code_t +_gpgrt_spawn_process_fd (const char *pgmname, const char *argv[], + int infd, int outfd, int errfd, pid_t *pid) +{ + gpg_err_code_t err; + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; + STARTUPINFO si; + char *cmdline; + int ret, i; + HANDLE stdhd[3]; + + /* Setup return values. */ + *pid = (pid_t)(-1); + + /* Prepare security attributes. */ + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + /* Build the command line. */ + err = build_w32_commandline (pgmname, argv, &cmdline); + if (err) + return err; + + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; + stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE; + stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE; + stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE; + si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd); + si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd); + si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd); + + _gpgrt_log_debug ("CreateProcess, path='%s' cmdline='%s'\n", + pgmname, cmdline); + ret = CreateProcess (pgmname, /* Program to start. */ + cmdline, /* Command line arguments. */ + &sec_attr, /* Process security attributes. */ + &sec_attr, /* Thread security attributes. */ + TRUE, /* Inherit handles. */ + (CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ()) + | CREATE_SUSPENDED | DETACHED_PROCESS), + NULL, /* Environment. */ + NULL, /* Use current drive/directory. */ + &si, /* Startup information. */ + &pi /* Returns process information. */ + ); + if (!ret) + { + _gpgrt_log_error ("CreateProcess failed: ec=%d\n", (int)GetLastError ()); + err = GPG_ERR_GENERAL; + } + else + err = 0; + + xfree (cmdline); + + for (i=0; i < 3; i++) + if (stdhd[i] != INVALID_HANDLE_VALUE) + CloseHandle (stdhd[i]); + + if (err) + return err; + + _gpgrt_log_debug ("CreateProcess ready: hProcess=%p hThread=%p" + " dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId); + + /* Process has been created suspended; resume it now. */ + ResumeThread (pi.hThread); + CloseHandle (pi.hThread); + + *pid = handle_to_pid (pi.hProcess); + return 0; +} + + +/* See gpgrt-int.h for a description. */ +gpg_err_code_t +_gpgrt_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode) +{ + return _gpgrt_wait_processes (&pgmname, &pid, 1, hang, r_exitcode); +} + + +/* See gpgrt-int.h for a description. */ +gpg_err_code_t +_gpgrt_wait_processes (const char **pgmnames, pid_t *pids, size_t count, + int hang, int *r_exitcodes) +{ + gpg_err_code_t ec = 0; + size_t i; + HANDLE *procs; + int code; + + procs = xtrycalloc (count, sizeof *procs); + if (procs == NULL) + return _gpg_err_code_from_syserror (); + + for (i = 0; i < count; i++) + { + if (r_exitcodes) + r_exitcodes[i] = -1; + + if (pids[i] == (pid_t)(-1)) + return GPG_ERR_INV_VALUE; + + procs[i] = pid_to_handle (pids[i]); + } + + _gpgrt_pre_syscall (); + code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0); + _gpgrt_post_syscall (); + switch (code) + { + case WAIT_TIMEOUT: + ec = GPG_ERR_TIMEOUT; + goto leave; + + case WAIT_FAILED: + _gpgrt_log_error (_("waiting for processes to terminate failed: ec=%d\n"), + (int)GetLastError ()); + ec = GPG_ERR_GENERAL; + goto leave; + + case WAIT_OBJECT_0: + for (i = 0; i < count; i++) + { + DWORD exc; + + if (! GetExitCodeProcess (procs[i], &exc)) + { + _gpgrt_log_error (_("error getting exit code of process %d:" + " ec=%d\n"), + (int) pids[i], (int)GetLastError ()); + ec = GPG_ERR_GENERAL; + } + else if (exc) + { + if (!r_exitcodes) + _gpgrt_log_error (_("error running '%s': exit status %d\n"), + pgmnames[i], (int)exc); + else + r_exitcodes[i] = (int)exc; + ec = GPG_ERR_GENERAL; + } + else + { + if (r_exitcodes) + r_exitcodes[i] = 0; + } + } + break; + + default: + _gpgrt_log_debug ("WaitForMultipleObjects returned unexpected code %d\n", + code); + ec = GPG_ERR_GENERAL; + break; + } + + leave: + return ec; +} + + +/* See gpgrt-int.h for a description. */ +gpg_err_code_t +_gpgrt_spawn_process_detached (const char *pgmname, const char *argv[], + const char *envp[] ) +{ + gpg_err_code_t err; + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = + { + NULL, /* Returns process handle. */ + 0, /* Returns primary thread handle. */ + 0, /* Returns pid. */ + 0 /* Returns tid. */ + }; + STARTUPINFO si; + int cr_flags; + char *cmdline; + int ret; + gpg_err_code_t ec; + + /* We don't use ENVP. */ + (void)envp; + + ec = _gpgrt_access (pgmname, X_OK); + if (ec) + return ec; + + /* Prepare security attributes. */ + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + /* Build the command line. */ + err = build_w32_commandline (pgmname, argv, &cmdline); + if (err) + return err; + + /* Start the process. */ + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; + + cr_flags = (CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ()) + | CREATE_NEW_PROCESS_GROUP + | DETACHED_PROCESS); + _gpgrt_log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", + pgmname, cmdline); + ret = CreateProcess (pgmname, /* Program to start. */ + cmdline, /* Command line arguments. */ + &sec_attr, /* Process security attributes. */ + &sec_attr, /* Thread security attributes. */ + FALSE, /* Inherit handles. */ + cr_flags, /* Creation flags. */ + NULL, /* Environment. */ + NULL, /* Use current drive/directory. */ + &si, /* Startup information. */ + &pi /* Returns process information. */ + ); + if (!ret) + { + _gpgrt_log_error ("CreateProcess(detached) failed: ec=%d\n", + (int)GetLastError ()); + xfree (cmdline); + return GPG_ERR_GENERAL; + } + xfree (cmdline); + cmdline = NULL; + + _gpgrt_log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" + " dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId); + + CloseHandle (pi.hThread); + CloseHandle (pi.hProcess); + + return 0; +} + + +/* Kill a process; that is send an appropriate signal to the process. + gnupg_wait_process must be called to actually remove the process + from the system. An invalid PID is ignored. */ +void +_gpgrt_kill_process (pid_t pid) +{ + if (pid != (pid_t) INVALID_HANDLE_VALUE) + { + HANDLE process = (HANDLE) pid; + + /* Arbitrary error code. */ + _gpgrt_pre_syscall (); + TerminateProcess (process, 1); + _gpgrt_post_syscall (); + } +} + + +void +_gpgrt_release_process (pid_t pid) +{ + if (pid != (pid_t)INVALID_HANDLE_VALUE) + { + HANDLE process = (HANDLE)pid; + + CloseHandle (process); + } +} diff --git a/comm/third_party/libgpg-error/src/strerror-sym.c b/comm/third_party/libgpg-error/src/strerror-sym.c new file mode 100644 index 0000000000..3d79f40bb5 --- /dev/null +++ b/comm/third_party/libgpg-error/src/strerror-sym.c @@ -0,0 +1,56 @@ +/* strerror-sym.c - Describing an error code with its symbol name. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "err-codes-sym.h" +#include "errnos-sym.h" + +/* Return a pointer to a string containing the name of the symbol of + the error code in the error value ERR. Returns NULL if the error + code is not known. */ +const char * +gpg_strerror_sym (gpg_error_t err) +{ + gpg_err_code_t code = gpg_err_code (err); + + if (code & GPG_ERR_SYSTEM_ERROR) + { + int idx; + + code &= ~GPG_ERR_SYSTEM_ERROR; + idx = errnos_msgidxof (code); + if (idx >= 0) + return errnos_msgstr + errnos_msgidx[idx]; + else + return NULL; + } + + if (msgidxof (code) == msgidxof (GPG_ERR_CODE_DIM)) + return NULL; + + return msgstr + msgidx[msgidxof (code)]; +} diff --git a/comm/third_party/libgpg-error/src/strerror.c b/comm/third_party/libgpg-error/src/strerror.c new file mode 100644 index 0000000000..4cce17f189 --- /dev/null +++ b/comm/third_party/libgpg-error/src/strerror.c @@ -0,0 +1,177 @@ +/* strerror.c - Describing an error code. + Copyright (C) 2003 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "gettext.h" +#include "err-codes.h" + +/* Return a pointer to a string containing a description of the error + code in the error value ERR. This function is not thread-safe. */ +const char * +_gpg_strerror (gpg_error_t err) +{ + gpg_err_code_t code = gpg_err_code (err); + + if (code & GPG_ERR_SYSTEM_ERROR) + { + int no = gpg_err_code_to_errno (code); + if (no) + return strerror (no); + else + code = GPG_ERR_UNKNOWN_ERRNO; + } + return dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]); +} + + +#ifdef HAVE_STRERROR_R +#ifdef STRERROR_R_CHAR_P +/* The GNU C library and probably some other systems have this weird + variant of strerror_r. */ + +/* Return a dynamically allocated string in *STR describing the system + error NO. If this call succeeds, return 1. If this call fails due + to a resource shortage, set *STR to NULL and return 1. If this + call fails because the error number is not valid, don't set *STR + and return 0. */ +static int +system_strerror_r (int no, char *buf, size_t buflen) +{ + char *errstr; + + errstr = strerror_r (no, buf, buflen); + if (errstr != buf) + { + size_t errstr_len = strlen (errstr) + 1; + size_t cpy_len = errstr_len < buflen ? errstr_len : buflen; + memcpy (buf, errstr, cpy_len); + + return cpy_len == errstr_len ? 0 : ERANGE; + } + else + { + /* We can not tell if the buffer was large enough, but we can + try to make a guess. */ + if (strlen (buf) + 1 >= buflen) + return ERANGE; + + return 0; + } +} + +#else /* STRERROR_R_CHAR_P */ +/* Now the POSIX version. */ + +static int +system_strerror_r (int no, char *buf, size_t buflen) +{ + return strerror_r (no, buf, buflen); +} + +#endif /* STRERROR_R_CHAR_P */ +#elif defined (HAVE_STRERROR_S) +/* Now the Windows version. */ + +static int +system_strerror_r (int no, char *buf, size_t buflen) +{ + return strerror_s (buf, buflen, no); +} + +#else /* ! HAVE_STRERROR_R && ! HAVE_STRERROR_S */ +/* Without strerror_r(), we can still provide a non-thread-safe + version. Maybe we are even lucky and the system's strerror() is + already thread-safe. */ + +static int +system_strerror_r (int no, char *buf, size_t buflen) +{ + char *errstr = strerror (no); + + if (!errstr) + { + int saved_errno = errno; + + if (saved_errno != EINVAL) + snprintf (buf, buflen, "strerror failed: %i\n", errno); + return saved_errno; + } + else + { + size_t errstr_len = strlen (errstr) + 1; + size_t cpy_len = errstr_len < buflen ? errstr_len : buflen; + memcpy (buf, errstr, cpy_len); + return cpy_len == errstr_len ? 0 : ERANGE; + } +} +#endif + + +/* Return the error string for ERR in the user-supplied buffer BUF of + size BUFLEN. This function is, in contrast to gpg_strerror, + thread-safe if a thread-safe strerror_r() function is provided by + the system. If the function succeeds, 0 is returned and BUF + contains the string describing the error. If the buffer was not + large enough, ERANGE is returned and BUF contains as much of the + beginning of the error string as fits into the buffer. */ +int +_gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen) +{ + gpg_err_code_t code = gpg_err_code (err); + const char *errstr; + size_t errstr_len; + size_t cpy_len; + + if (code & GPG_ERR_SYSTEM_ERROR) + { + int no = gpg_err_code_to_errno (code); + if (no) + { + int system_err = system_strerror_r (no, buf, buflen); + + if (system_err != EINVAL) + { + if (buflen) + buf[buflen - 1] = '\0'; + return system_err; + } + } + code = GPG_ERR_UNKNOWN_ERRNO; + } + + errstr = dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]); + errstr_len = strlen (errstr) + 1; + cpy_len = errstr_len < buflen ? errstr_len : buflen; + memcpy (buf, errstr, cpy_len); + if (buflen) + buf[buflen - 1] = '\0'; + + return cpy_len == errstr_len ? 0 : ERANGE; +} diff --git a/comm/third_party/libgpg-error/src/stringutils.c b/comm/third_party/libgpg-error/src/stringutils.c new file mode 100644 index 0000000000..0be876959c --- /dev/null +++ b/comm/third_party/libgpg-error/src/stringutils.c @@ -0,0 +1,224 @@ +/* stringutils.c - String helper functions. + * Copyright (C) 1997, 2014 Werner Koch + * Copyright (C) 2020 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STAT +# include +#endif +#include +#ifdef HAVE_PWD_H +# include +#endif + +#include "gpgrt-int.h" + + +/* Helper for _gpgrt_fnameconcat. The additional flag WANT_ABS tells + * whether an absolute file name is requested. */ +char * +_gpgrt_vfnameconcat (int want_abs, const char *first_part, va_list arg_ptr) +{ + const char *argv[32]; + int argc; + size_t n; + int skip = 1; /* Characters to skip from FIRST_PART. */ + char *home_buffer = NULL; + char *name, *home, *p; + + /* Put all args into an array because we need to scan them twice. */ + n = strlen (first_part) + 1; + argc = 0; + while ((argv[argc] = va_arg (arg_ptr, const char *))) + { + n += strlen (argv[argc]) + 1; + if (argc >= DIM (argv)-1) + { + _gpg_err_set_errno (EINVAL); + return NULL; + } + argc++; + } + n++; + + home = NULL; + if (*first_part == '~') + { + if (first_part[1] == '/' || !first_part[1]) + { + /* This is the "~/" or "~" case. */ + home_buffer = _gpgrt_getenv ("HOME"); + if (!home_buffer) + home_buffer = _gpgrt_getpwdir (NULL); + home = home_buffer; + if (home && *home) + n += strlen (home); + } + else + { + /* This is the "~username/" or "~username" case. */ + char *user; + + user = _gpgrt_strdup (first_part+1); + if (!user) + return NULL; + + p = strchr (user, '/'); + if (p) + *p = 0; + skip = 1 + strlen (user); + + home = home_buffer = _gpgrt_getpwdir (user); + xfree (user); + if (home) + n += strlen (home); + else + skip = 1; + } + } + + name = xtrymalloc (n); + if (!name) + { + _gpgrt_free (home_buffer); + return NULL; + } + + if (home) + p = stpcpy (stpcpy (name, home), first_part + skip); + else + p = stpcpy (name, first_part); + + xfree (home_buffer); + home_buffer = NULL; + + for (argc=0; argv[argc]; argc++) + { + /* Avoid a leading double slash if the first part was "/". */ + if (!argc && name[0] == '/' && !name[1]) + p = stpcpy (p, argv[argc]); + else + p = stpcpy (stpcpy (p, "/"), argv[argc]); + } + + if (want_abs) + { +#ifdef HAVE_W32_SYSTEM + p = strchr (name, ':'); + if (p) + p++; + else + p = name; +#else + p = name; +#endif + if (*p != '/' +#ifdef HAVE_W32_SYSTEM + && *p != '\\' +#endif + ) + { + home = _gpgrt_getcwd (); + if (!home) + { + xfree (name); + return NULL; + } + + n = strlen (home) + 1 + strlen (name) + 1; + home_buffer = xtrymalloc (n); + if (!home_buffer) + { + xfree (home); + xfree (name); + return NULL; + } + + if (p == name) + p = home_buffer; + else /* Windows case. */ + { + memcpy (home_buffer, p, p - name + 1); + p = home_buffer + (p - name + 1); + } + + /* Avoid a leading double slash if the cwd is "/". */ + if (home[0] == '/' && !home[1]) + strcpy (stpcpy (p, "/"), name); + else + strcpy (stpcpy (stpcpy (p, home), "/"), name); + + xfree (home); + xfree (name); + name = home_buffer; + /* Let's do a simple compression to catch the common case of + * a trailing "/.". */ + n = strlen (name); + if (n > 2 && name[n-2] == '/' && name[n-1] == '.') + name[n-2] = 0; + } + } + +#ifdef HAVE_W32_SYSTEM + for (p=name; *p; p++) + if (*p == '\\') + *p = '/'; +#endif + return name; +} + + +/* Construct a filename from the NULL terminated list of parts. Tilde + * expansion is done for the first argument. The caller must release + * the result using gpgrt_free; on error ERRNO is set and NULL + * returned. */ +char * +_gpgrt_fnameconcat (const char *first_part, ... ) +{ + va_list arg_ptr; + char *result; + + va_start (arg_ptr, first_part); + result = _gpgrt_vfnameconcat (0, first_part, arg_ptr); + va_end (arg_ptr); + return result; +} + + +/* Construct a filename from the NULL terminated list of parts. Tilde + * expansion is done for the first argument. The caller must release + * the result using gpgrt_free; on error ERRNO is set and NULL + * returned. This version returns an absolute filename. */ +char * +_gpgrt_absfnameconcat (const char *first_part, ... ) +{ + va_list arg_ptr; + char *result; + + va_start (arg_ptr, first_part); + result = _gpgrt_vfnameconcat (1, first_part, arg_ptr); + va_end (arg_ptr); + return result; +} diff --git a/comm/third_party/libgpg-error/src/strsource-sym.c b/comm/third_party/libgpg-error/src/strsource-sym.c new file mode 100644 index 0000000000..a191310e95 --- /dev/null +++ b/comm/third_party/libgpg-error/src/strsource-sym.c @@ -0,0 +1,43 @@ +/* strsource-sym.c - Describing an error source with its symbol name. + Copyright (C) 2003, 2004 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "err-sources-sym.h" + +/* Return a pointer to a string containing the name of the symbol of + the error source in the error value ERR. Returns NULL if the error + code is not known. */ +const char * +gpg_strsource_sym (gpg_error_t err) +{ + gpg_err_source_t source = gpg_err_source (err); + + if (msgidxof (source) == msgidxof (GPG_ERR_SOURCE_DIM)) + return NULL; + + return msgstr + msgidx[msgidxof (source)]; +} diff --git a/comm/third_party/libgpg-error/src/strsource.c b/comm/third_party/libgpg-error/src/strsource.c new file mode 100644 index 0000000000..6604eb0a80 --- /dev/null +++ b/comm/third_party/libgpg-error/src/strsource.c @@ -0,0 +1,37 @@ +/* strsource.c - Describing an error source. + Copyright (C) 2003 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpg-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include "gettext.h" +#include "err-sources.h" + +/* Return a pointer to a string containing a description of the error + source in the error value ERR. */ +const char * +_gpg_strsource (gpg_error_t err) +{ + gpg_err_source_t source = gpg_err_source (err); + return dgettext (PACKAGE, msgstr + msgidx[msgidxof (source)]); +} diff --git a/comm/third_party/libgpg-error/src/syscall-clamp.c b/comm/third_party/libgpg-error/src/syscall-clamp.c new file mode 100644 index 0000000000..99748f4e4c --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscall-clamp.c @@ -0,0 +1,80 @@ +/* syscall-clamp.c - Syscall clamp related stuff + * Copyright (C) 2016, 2017 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include + +#include "gpgrt-int.h" + +/* + * Functions called before and after blocking syscalls. + * gpgrt_set_syscall_clamp is used to set them. + */ +static void (*pre_syscall_func)(void); +static void (*post_syscall_func)(void); + + +/* + * Register the syscall clamp. These two functions are called + * immediately before and after a possible blocking system call. This + * should be used before any I/O happens. The function is commonly + * used with the nPth library: + * + * gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); + * + * These functions may not modify ERRNO. + * + * Setting the clamp is not thread-safe and should thus be done as + * early as possible. + */ +void +_gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void)) +{ + pre_syscall_func = pre; + post_syscall_func = post; +} + +/* + * Return the current sycall clamp functions. This can be used by + * other libraries which have blocking functions. + */ +void +_gpgrt_get_syscall_clamp (void (**r_pre)(void), void (**r_post)(void)) +{ + *r_pre = pre_syscall_func; + *r_post = post_syscall_func; +} + + +/* Call this function before a blocking system or libc call. */ +void +_gpgrt_pre_syscall (void) +{ + if (pre_syscall_func) + pre_syscall_func (); +} + + +/* Call this function after a blocking system or libc call. */ +void +_gpgrt_post_syscall (void) +{ + if (post_syscall_func) + post_syscall_func (); +} diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-apple-darwin.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-apple-darwin.h new file mode 100644 index 0000000000..3eeadfe2f0 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-apple-darwin.h @@ -0,0 +1,28 @@ +## lock-obj-pub.aarch64-apple-darwin.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[64]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{167,171,170,50,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu.h new file mode 100644 index 0000000000..adf10fc305 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu.h @@ -0,0 +1,26 @@ +## lock-obj-pub.aarch64-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[48]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h new file mode 100644 index 0000000000..61239c36ed --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h @@ -0,0 +1,24 @@ +## lock-obj-pub.aarch64-unknown-linux-gnu_ilp32.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[32]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h new file mode 100644 index 0000000000..80ddf01ab1 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.alpha-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.alpha-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-apple-darwin.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-apple-darwin.h new file mode 100644 index 0000000000..4e9f63028a --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-apple-darwin.h @@ -0,0 +1,26 @@ +## lock-obj-pub.arm-apple-darwin.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[44]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{167,171,170,50,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-androideabi.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-androideabi.h new file mode 100644 index 0000000000..56319f5eba --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-androideabi.h @@ -0,0 +1,21 @@ +## lock-obj-pub.arm-unknown-linux-androideabi.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[4]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-gnueabi.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-gnueabi.h new file mode 100644 index 0000000000..7a92276dc6 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.arm-unknown-linux-gnueabi.h @@ -0,0 +1,23 @@ +## lock-obj-pub.arm-unknown-linux-gnueabi.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h new file mode 100644 index 0000000000..b57bb76d5b --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.hppa-unknown-linux-gnu.h @@ -0,0 +1,27 @@ +## lock-obj-pub.hppa-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[48]; + int _x16_align __attribute__ ((aligned (16))); + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i386-apple-darwin.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i386-apple-darwin.h new file mode 100644 index 0000000000..a5963c48c1 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i386-apple-darwin.h @@ -0,0 +1,26 @@ +## lock-obj-pub.i386-apple-darwin.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[44]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{167,171,170,50,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-gnu.h new file mode 100644 index 0000000000..0522462a95 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-gnu.h @@ -0,0 +1,24 @@ +## lock-obj-pub.i686-pc-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[32]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-kfreebsd-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-kfreebsd-gnu.h new file mode 100644 index 0000000000..4cf12fcbd6 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-kfreebsd-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.i686-pc-kfreebsd-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-linux-gnu.h new file mode 100644 index 0000000000..b97273b40a --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.i686-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.i686-pc-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h new file mode 100644 index 0000000000..7cf980ab8f --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.ia64-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.ia64-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h new file mode 100644 index 0000000000..3788797a09 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.m68k-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.m68k-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mingw32.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mingw32.h new file mode 100644 index 0000000000..f35aee15f6 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mingw32.h @@ -0,0 +1,44 @@ +## w32-lock-obj-pub.in - Include fragment for gpg-error.h -*- c-*- +## Copyright (C) 2014 g10 Code GmbH +## +## This file is free software; as a special exception the author gives +## unlimited permission to copy and/or distribute it, with or without +## modifications, as long as this notice is preserved. +## +## This file is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +## +## +## This file defines the public version of the lock object for 32 bit +## Windows. The actual used version is in w32-lock-obj.h. This file +## is inserted into gpg-error.h by mkheader.c. The tool +## gen-w32-lock-obj.c has been used to construct it. + +#ifdef _WIN64 + +#pragma pack(push, 8) +typedef struct +{ + volatile unsigned char priv[56]; +} gpgrt_lock_t; +#pragma pack(pop) + +#define GPGRT_LOCK_INITIALIZER {{1,0,0,0,0,0,0,0,255,255,255,255, \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0,0,0,0,0}} + +#else + +#pragma pack(push, 8) +typedef struct +{ + volatile unsigned char priv[36]; +} gpgrt_lock_t; +#pragma pack(pop) + +#define GPGRT_LOCK_INITIALIZER {{1,0,0,0,0,0,0,0,255,255,255,255, \ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}} +#endif diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips-unknown-linux-gnu.h new file mode 100644 index 0000000000..b31206ea0a --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.mips-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64-unknown-linux-gnuabi64.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64-unknown-linux-gnuabi64.h new file mode 100644 index 0000000000..f571c4bb29 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64-unknown-linux-gnuabi64.h @@ -0,0 +1,25 @@ +## lock-obj-pub.mips64-unknown-linux-gnuabi64.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64el-unknown-linux-gnuabi64.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64el-unknown-linux-gnuabi64.h new file mode 100644 index 0000000000..8a81e3faac --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mips64el-unknown-linux-gnuabi64.h @@ -0,0 +1,25 @@ +## lock-obj-pub.mips64el-unknown-linux-gnuabi64.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h new file mode 100644 index 0000000000..3a24571659 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.mipsel-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.mipsel-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h new file mode 100644 index 0000000000..dbd46da792 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.nios2-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.nios2-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h new file mode 100644 index 0000000000..60eadab8e7 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.or1k-unknown-linux-gnu.h @@ -0,0 +1,24 @@ +## lock-obj-pub.or1k-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[32]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnu.h new file mode 100644 index 0000000000..6601bc9636 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.powerpc-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnuspe.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnuspe.h new file mode 100644 index 0000000000..c53413bee8 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc-unknown-linux-gnuspe.h @@ -0,0 +1,23 @@ +## lock-obj-pub.powerpc-unknown-linux-gnuspe.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64-unknown-linux-gnu.h new file mode 100644 index 0000000000..635e6eb0c2 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.powerpc64-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64le-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64le-unknown-linux-gnu.h new file mode 100644 index 0000000000..79073d4c51 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.powerpc64le-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.powerpc64le-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv32-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv32-unknown-linux-gnu.h new file mode 100644 index 0000000000..b5bdaf57ef --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv32-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.riscv32-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv64-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv64-unknown-linux-gnu.h new file mode 100644 index 0000000000..8aab9d6667 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.riscv64-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.riscv64-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h new file mode 100644 index 0000000000..70f6e33d8d --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.s390x-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.s390x-ibm-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h new file mode 100644 index 0000000000..a2ff11f96c --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh3-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.sh3-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h new file mode 100644 index 0000000000..eb62ba3d8b --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sh4-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.sh4-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h new file mode 100644 index 0000000000..2748b26881 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc-unknown-linux-gnu.h @@ -0,0 +1,23 @@ +## lock-obj-pub.sparc-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[24]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc64-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc64-unknown-linux-gnu.h new file mode 100644 index 0000000000..ee309a9f49 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.sparc64-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.sparc64-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h new file mode 100644 index 0000000000..b99ea32003 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.tilegx-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.tilegx-unknown-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-apple-darwin.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-apple-darwin.h new file mode 100644 index 0000000000..eaf8689f98 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-apple-darwin.h @@ -0,0 +1,28 @@ +## lock-obj-pub.x86_64-apple-darwin.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[64]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{167,171,170,50,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0, \ +0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h new file mode 100644 index 0000000000..7fb596c4a9 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-kfreebsd-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.x86_64-pc-kfreebsd-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h new file mode 100644 index 0000000000..0dd6431d28 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h @@ -0,0 +1,25 @@ +## lock-obj-pub.x86_64-pc-linux-gnu.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnux32.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnux32.h new file mode 100644 index 0000000000..e85bd308b0 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnux32.h @@ -0,0 +1,24 @@ +## lock-obj-pub.x86_64-pc-linux-gnux32.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[32]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-musl.h b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-musl.h new file mode 100644 index 0000000000..1b059f4260 --- /dev/null +++ b/comm/third_party/libgpg-error/src/syscfg/lock-obj-pub.x86_64-unknown-linux-musl.h @@ -0,0 +1,25 @@ +## lock-obj-pub.x86_64-pc-linux-musl.h +## File created by gen-posix-lock-obj - DO NOT EDIT +## To be included by mkheader into gpg-error.h + +typedef struct +{ + long _vers; + union { + volatile char _priv[40]; + long _x_align; + long *_xp_align; + } u; +} gpgrt_lock_t; + +#define GPGRT_LOCK_INITIALIZER {1,{{0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0, \ + 0,0,0,0,0,0,0,0}}} +## +## Local Variables: +## mode: c +## buffer-read-only: t +## End: +## diff --git a/comm/third_party/libgpg-error/src/sysutils.c b/comm/third_party/libgpg-error/src/sysutils.c new file mode 100644 index 0000000000..8f70a6694e --- /dev/null +++ b/comm/third_party/libgpg-error/src/sysutils.c @@ -0,0 +1,524 @@ +/* sysutils.c - Platform specific helper functions + * Copyright (C) 2017 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_W32_SYSTEM +# include +#endif +#ifdef HAVE_STAT +# include +#endif +#include +#include +#ifdef HAVE_PWD_H +# include +#endif + +#include "gpgrt-int.h" + + +#ifdef HAVE_W32_SYSTEM +/* Return true if STRING has any 8 bit character. */ +static int +any8bitchar (const char *string) +{ + if (string) + for ( ; *string; string++) + if ((*string & 0x80)) + return 1; + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +/* Return true if FD is valid. */ +int +_gpgrt_fd_valid_p (int fd) +{ + int d = dup (fd); + if (d < 0) + return 0; + close (d); + return 1; +} + + +/* Our variant of getenv. The returned string must be freed. If the + * environment variable does not exists NULL is returned and ERRNO set + * to 0. */ +char * +_gpgrt_getenv (const char *name) +{ + if (!name || !*name || strchr (name, '=')) + { + _gpg_err_set_errno (EINVAL); + return NULL; + } + +#ifdef HAVE_W32_SYSTEM + { + int len, size; + char *result; + + len = GetEnvironmentVariable (name, NULL, 0); + if (!len && GetLastError () == ERROR_ENVVAR_NOT_FOUND) + { + _gpg_err_set_errno (0); + return NULL; + } + again: + size = len; + result = _gpgrt_malloc (size); + if (!result) + return NULL; + len = GetEnvironmentVariable (name, result, size); + if (len >= size) + { + /* Changed in the meantime - retry. */ + _gpgrt_free (result); + goto again; + } + if (!len && GetLastError () == ERROR_ENVVAR_NOT_FOUND) + { + /* Deleted in the meantime. */ + _gpgrt_free (result); + _gpg_err_set_errno (0); + return NULL; + } + if (!len) + { + /* Other error. FIXME: We need mapping fucntion. */ + _gpgrt_free (result); + _gpg_err_set_errno (EIO); + return NULL; + } + + return result; + } +#else /*!HAVE_W32_SYSTEM*/ + { + const char *s = getenv (name); + if (!s) + { + _gpg_err_set_errno (0); + return NULL; + } + return _gpgrt_strdup (s); + } +#endif /*!HAVE_W32_SYSTEM*/ +} + + +/* Wrapper around setenv so that we can have the same function in + * Windows and Unix. In contrast to the standard setenv passing a + * VALUE as NULL and setting OVERWRITE will remove the envvar. */ +gpg_err_code_t +_gpgrt_setenv (const char *name, const char *value, int overwrite) +{ + if (!name || !*name || strchr (name, '=')) + return GPG_ERR_EINVAL; + +#ifdef HAVE_W32_SYSTEM + /* Windows maintains (at least) two sets of environment variables. + * One set can be accessed by GetEnvironmentVariable and + * SetEnvironmentVariable. This set is inherited by the children. + * The other set is maintained in the C runtime, and is accessed + * using getenv and putenv. We try to keep them in sync by + * modifying both sets. Note that gpgrt_getenv ignores the libc + * values - however, too much existing code still uses getenv. */ + { + int exists; + char tmpbuf[10]; + char *buf; + + if (!value && overwrite) + { + if (!SetEnvironmentVariable (name, NULL)) + return GPG_ERR_EINVAL; + if (getenv (name)) + { + /* Ugly: Leaking memory. */ + buf = _gpgrt_strdup (name); + if (!buf) + return _gpg_err_code_from_syserror (); + if (putenv (buf)) + return _gpg_err_code_from_syserror (); + } + return 0; + } + + exists = GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf); + if ((! exists || overwrite) && !SetEnvironmentVariable (name, value)) + return GPG_ERR_EINVAL; /* (Might also be ENOMEM.) */ + if (overwrite || !getenv (name)) + { + /* Ugly: Leaking memory. */ + buf = _gpgrt_strconcat (name, "=", value, NULL); + if (!buf) + return _gpg_err_code_from_syserror (); + if (putenv (buf)) + return _gpg_err_code_from_syserror (); + } + return 0; + } + +#else /*!HAVE_W32_SYSTEM*/ + +# ifdef HAVE_SETENV + + { + if (!value && overwrite) + { + if (unsetenv (name)) + return _gpg_err_code_from_syserror (); + } + else + { + if (setenv (name, value ? value : "", overwrite)) + return _gpg_err_code_from_syserror (); + } + + return 0; + } + +# else /*!HAVE_SETENV*/ + +# if __GNUC__ +# warning no setenv - using putenv but leaking memory. +# endif + { + char *buf; + + if (!value && overwrite) + { + if (getenv (name)) + { + buf = _gpgrt_strdup (name); + if (!buf) + return _gpg_err_code_from_syserror (); + if (putenv (buf)) + return -1; + } + } + else if (overwrite || !getenv (name)) + { + buf = _gpgrt_strconcat (name, "=", value, NULL); + if (!buf) + return _gpg_err_code_from_syserror (); + if (putenv (buf)) + return _gpg_err_code_from_syserror (); + } + + return 0; + } +# endif /*!HAVE_SETENV*/ +#endif /*!HAVE_W32_SYSTEM*/ +} + + +#ifndef HAVE_W32_SYSTEM +static mode_t +modestr_to_mode (const char *modestr) +{ + mode_t mode = 0; + + if (modestr && *modestr) + { + modestr++; + if (*modestr && *modestr++ == 'r') + mode |= S_IRUSR; + if (*modestr && *modestr++ == 'w') + mode |= S_IWUSR; + if (*modestr && *modestr++ == 'x') + mode |= S_IXUSR; + if (*modestr && *modestr++ == 'r') + mode |= S_IRGRP; + if (*modestr && *modestr++ == 'w') + mode |= S_IWGRP; + if (*modestr && *modestr++ == 'x') + mode |= S_IXGRP; + if (*modestr && *modestr++ == 'r') + mode |= S_IROTH; + if (*modestr && *modestr++ == 'w') + mode |= S_IWOTH; + if (*modestr && *modestr++ == 'x') + mode |= S_IXOTH; + } + + return mode; +} +#endif + + +/* A wrapper around mkdir which takes a string for the mode argument. + * This makes it easier to handle the mode argument which is not + * defined on all systems. The format of the modestring is + * + * "-rwxrwxrwx" + * + * '-' is a don't care or not set. 'r', 'w', 'x' are read allowed, + * write allowed, execution allowed with the first group for the user, + * the second for the group and the third for all others. If the + * string is shorter than above the missing mode characters are meant + * to be not set. + * + * Note that in addition to returning an gpg-error error code ERRNO is + * also set by this function. + */ +gpg_err_code_t +_gpgrt_mkdir (const char *name, const char *modestr) +{ +#ifdef HAVE_W32_SYSTEM + wchar_t *wname; + gpg_err_code_t ec; + (void)modestr; + + /* Note: Fixme: We should set appropriate permissions. */ + wname = _gpgrt_utf8_to_wchar (name); + if (!wname) + return _gpg_err_code_from_syserror (); + if (!CreateDirectoryW (wname, NULL)) + { + _gpgrt_w32_set_errno (-1); + ec = _gpg_err_code_from_syserror (); + } + else + ec = 0; + _gpgrt_free_wchar (wname); + return ec; +#elif MKDIR_TAKES_ONE_ARG + (void)modestr; + if (mkdir (name)) + return _gpg_err_code_from_syserror (); + return 0; +#else + if (mkdir (name, modestr_to_mode (modestr))) + return _gpg_err_code_from_syserror (); + return 0; +#endif +} + + +/* A simple wrapper around chdir. NAME is expected to be utf8 + * encoded. + * Note that in addition to returning an gpg-error error code ERRNO is + * also set by this function. */ +gpg_err_code_t +_gpgrt_chdir (const char *name) +{ +#ifdef HAVE_W32_SYSTEM + wchar_t *wname; + gpg_err_code_t ec; + + wname = _gpgrt_utf8_to_wchar (name); + if (!wname) + return _gpg_err_code_from_syserror (); + if (!SetCurrentDirectoryW (wname)) + { + _gpgrt_w32_set_errno (-1); + ec = _gpg_err_code_from_syserror (); + } + else + ec = 0; + _gpgrt_free_wchar (wname); + return ec; + +#else /*!HAVE_W32_SYSTEM*/ + if (chdir (name)) + return _gpg_err_code_from_syserror (); + return 0; +#endif /*!HAVE_W32_SYSTEM*/ +} + + +/* Return the current working directory as a malloced string. Return + * NULL and sets ERRNO on error. */ +char * +_gpgrt_getcwd (void) +{ +#ifdef HAVE_W32CE_SYSTEM + + return xtrystrdup ("/"); + +#elif defined(HAVE_W32_SYSTEM) + wchar_t wbuffer[MAX_PATH + sizeof(wchar_t)]; + DWORD wlen; + char *buf, *p; + + wlen = GetCurrentDirectoryW (MAX_PATH, wbuffer); + if (!wlen) + { + _gpgrt_w32_set_errno (-1); + return NULL; + + } + else if (wlen > MAX_PATH) + { + _gpg_err_set_errno (ENAMETOOLONG); + return NULL; + } + buf = _gpgrt_wchar_to_utf8 (wbuffer, wlen); + if (buf) + { + for (p=buf; *p; p++) + if (*p == '\\') + *p = '/'; + } + return buf; + +#else /*Unix*/ + char *buffer; + size_t size = 100; + + for (;;) + { + buffer = xtrymalloc (size+1); + if (!buffer) + return NULL; + if (getcwd (buffer, size) == buffer) + return buffer; + xfree (buffer); + if (errno != ERANGE) + return NULL; + size *= 2; + } +#endif /*Unix*/ +} + + +/* Wrapper around access to handle file name encoding under Windows. + * Returns 0 if FNAME can be accessed in MODE or an error code. ERRNO + * is also set on error. */ +gpg_err_code_t +_gpgrt_access (const char *fname, int mode) +{ + gpg_err_code_t ec; + +#ifdef HAVE_W32_SYSTEM + if (any8bitchar (fname)) + { + wchar_t *wfname; + + wfname = _gpgrt_utf8_to_wchar (fname); + if (!wfname) + ec = _gpg_err_code_from_syserror (); + else + { + ec = _waccess (wfname, mode)? _gpg_err_code_from_syserror () : 0; + _gpgrt_free_wchar (wfname); + } + } + else +#endif /*HAVE_W32_SYSTEM*/ + ec = access (fname, mode)? _gpg_err_code_from_syserror () : 0; + + return ec; +} + + + +/* Get the standard home directory for user NAME. If NAME is NULL the + * directory for the current user is returned. Caller must release + * the returned string. */ +char * +_gpgrt_getpwdir (const char *name) +{ + char *result = NULL; +#ifdef HAVE_PWD_H + struct passwd *pwd = NULL; + + if (name) + { +#ifdef HAVE_GETPWNAM + /* Fixme: We should use getpwnam_r if available. */ + pwd = getpwnam (name); +#endif + } + else + { +#ifdef HAVE_GETPWUID + /* Fixme: We should use getpwuid_r if available. */ + pwd = getpwuid (getuid()); +#endif + } + if (pwd) + { + result = _gpgrt_strdup (pwd->pw_dir); + } +#else /*!HAVE_PWD_H*/ + /* No support at all. */ + (void)name; +#endif /*HAVE_PWD_H*/ + return result; +} + + +/* Return a malloced copy of the current user's account name; this may + * return NULL on memory failure. */ +char * +_gpgrt_getusername (void) +{ + char *result = NULL; + +#ifdef HAVE_W32_SYSTEM + wchar_t wtmp[1]; + wchar_t *wbuf; + DWORD wsize = 1; + char *buf; + + GetUserNameW (wtmp, &wsize); + wbuf = _gpgrt_malloc (wsize * sizeof *wbuf); + if (!wbuf) + { + _gpgrt_w32_set_errno (-1); + return NULL; + } + if (!GetUserNameW (wbuf, &wsize)) + { + _gpgrt_w32_set_errno (-1); + xfree (wbuf); + return NULL; + } + buf = _gpgrt_wchar_to_utf8 (wbuf, wsize); + xfree (wbuf); + return buf; + +#else /* !HAVE_W32_SYSTEM */ + +# if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) + struct passwd *pwd; + + pwd = getpwuid (getuid()); + if (pwd) + { + result = _gpgrt_strdup (pwd->pw_name); + } + +# endif /*HAVE_PWD_H*/ + +#endif /* !HAVE_W32_SYSTEM */ + + return result; +} diff --git a/comm/third_party/libgpg-error/src/thread.h b/comm/third_party/libgpg-error/src/thread.h new file mode 100644 index 0000000000..c650a991f3 --- /dev/null +++ b/comm/third_party/libgpg-error/src/thread.h @@ -0,0 +1,24 @@ +/* thread.h - Declarations for *-thread.c + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#ifndef THREAD_H +#define THREAD_H + + +#endif /*THREAD_H*/ diff --git a/comm/third_party/libgpg-error/src/version.c b/comm/third_party/libgpg-error/src/version.c new file mode 100644 index 0000000000..276ee04447 --- /dev/null +++ b/comm/third_party/libgpg-error/src/version.c @@ -0,0 +1,246 @@ +/* version.c - Version checking + * Copyright (C) 2001, 2002, 2012, 2013, 2014 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + + +#define digitp(a) ((a) >= '0' && (a) <= '9') + + +/* This is actually a dummy function to make sure that is module is + not empty. Some compilers barf on empty modules. */ +static const char * +cright_blurb (void) +{ + static const char blurb[] = + "\n\n" + "This is Libgpg-error " PACKAGE_VERSION " - A runtime library\n" + "Copyright 2001-2020 g10 Code GmbH\n" + "\n" + "(" BUILD_REVISION " " BUILD_TIMESTAMP ")\n" + "\n\n"; + return blurb; +} + + +/* This function parses the first portion of the version number S and + * stores it at NUMBER. On success, this function returns a pointer + * into S starting with the first character, which is not part of the + * initial number portion; on failure, NULL is returned. */ +static const char* +parse_version_number (const char *s, int *number) +{ + int val = 0; + + if (*s == '0' && digitp (s[1])) + return NULL; /* Leading zeros are not allowed. */ + for (; digitp (*s); s++) + { + val *= 10; + val += *s - '0'; + } + *number = val; + return val < 0 ? NULL : s; +} + + +/* This function breaks up the complete string-representation of the + * version number S, which is of the following struture: ... The major, + * minor and micro number components will be stored in *MAJOR, *MINOR + * and *MICRO. If MINOR or MICRO is NULL the version number is + * assumed to have just 1 respective 2 parts. + * + * On success, the last component, the patch level, will be returned; + * in failure, NULL will be returned. */ +static const char * +parse_version_string (const char *s, int *major, int *minor, int *micro) +{ + s = parse_version_number (s, major); + if (!s) + return NULL; + if (!minor) + { + if (*s == '.') + s++; + } + else + { + if (*s != '.') + return NULL; + s++; + s = parse_version_number (s, minor); + if (!s) + return NULL; + if (!micro) + { + if (*s == '.') + s++; + } + else + { + if (*s != '.') + return NULL; + s++; + s = parse_version_number (s, micro); + if (!s) + return NULL; + } + } + return s; /* patchlevel */ +} + + +/* Helper for _gpgrt_cmp_version. */ +static int +do_cmp_version (const char *a, const char *b, int level) +{ + int a_major, a_minor, a_micro; + int b_major, b_minor, b_micro; + const char *a_plvl, *b_plvl; + int r; + int ignore_plvl; + int positive, negative; + + if (level < 0) + { + positive = -1; + negative = 1; + level = 0 - level; + } + else + { + positive = 1; + negative = -1; + } + if ((ignore_plvl = (level > 9))) + level %= 10; + + a_major = a_minor = a_micro = 0; + a_plvl = parse_version_string (a, &a_major, + level > 1? &a_minor : NULL, + level > 2? &a_micro : NULL); + if (!a_plvl) + a_major = a_minor = a_micro = 0; /* Error. */ + + b_major = b_minor = b_micro = 0; + b_plvl = parse_version_string (b, &b_major, + level > 1? &b_minor : NULL, + level > 2? &b_micro : NULL); + if (!b_plvl) + b_major = b_minor = b_micro = 0; + + if (!ignore_plvl) + { + if (!a_plvl && !b_plvl) + return negative; /* Put invalid strings at the end. */ + if (a_plvl && !b_plvl) + return positive; + if (!a_plvl && b_plvl) + return negative; + } + + if (a_major > b_major) + return positive; + if (a_major < b_major) + return negative; + + if (a_minor > b_minor) + return positive; + if (a_minor < b_minor) + return negative; + + if (a_micro > b_micro) + return positive; + if (a_micro < b_micro) + return negative; + + if (ignore_plvl) + return 0; + + for (; *a_plvl && *b_plvl; a_plvl++, b_plvl++) + { + if (*a_plvl == '.' && *b_plvl == '.') + { + r = strcmp (a_plvl, b_plvl); + if (!r) + return 0; + else if ( r > 0 ) + return positive; + else + return negative; + } + else if (*a_plvl == '.') + return negative; /* B is larger. */ + else if (*b_plvl == '.') + return positive; /* A is larger. */ + else if (*a_plvl != *b_plvl) + break; + } + if (*a_plvl == *b_plvl) + return 0; + else if ((*(signed char *)a_plvl - *(signed char *)b_plvl) > 0) + return positive; + else + return negative; +} + + +/* Compare function for version strings. The return value is + * like strcmp(). LEVEL may be + * 0 - reserved + * 1 - format is "". + * 2 - format is ".". + * 3 - format is "..". + * To ignore the patchlevel in the comparison add 10 to LEVEL. To get + * a reverse sorting order use a negative number. + */ +int +_gpgrt_cmp_version (const char *a, const char *b, int level) +{ + return do_cmp_version (a, b, level); +} + + +/* + * Check that the the version of the library is at minimum REQ_VERSION + * and return the actual version string; return NULL if the condition + * is not met. If NULL is passed to this function, no check is done + * and the version string is simply returned. + */ +const char * +_gpg_error_check_version (const char *req_version) +{ + const char *my_version = PACKAGE_VERSION; + + if (req_version && req_version[0] == 1 && req_version[1] == 1) + return cright_blurb (); + if (!req_version) + return my_version; + return _gpgrt_cmp_version + (my_version, req_version, 12) >= 0 ? my_version : NULL; +} diff --git a/comm/third_party/libgpg-error/src/versioninfo.rc.in b/comm/third_party/libgpg-error/src/versioninfo.rc.in new file mode 100644 index 0000000000..d42d8fe3e5 --- /dev/null +++ b/comm/third_party/libgpg-error/src/versioninfo.rc.in @@ -0,0 +1,54 @@ +/* versioninfo.rc.in - for libgpg-error + * Copyright (C) 2005 g10 Code GmbH + * + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * SPDX-License-Identifier: FSFULLR + */ + +/* This file is processed by configure to create versioninfo.rc */ + +#line __LINE__ "versioninfo.rc.in" + +#include + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @BUILD_FILEVERSION@ + PRODUCTVERSION @BUILD_FILEVERSION@ + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Provided under the terms of the GNU Lesser General Public License.\0" + VALUE "CompanyName", "g10 Code GmbH\0" + VALUE "FileDescription", "libgpg-error - Common error codes\0" + VALUE "FileVersion", "@LIBGPG_ERROR_LT_CURRENT@.@LIBGPG_ERROR_LT_AGE@.@LIBGPG_ERROR_LT_REVISION@.@BUILD_REVISION@\0" + VALUE "InternalName", "libgpg-error\0" + VALUE "LegalCopyright", "Copyright © 2020 g10 Code GmbH\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "libgpg-error.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "libgpg-error\0" + VALUE "ProductVersion", "@PACKAGE_VERSION@\0" + VALUE "SpecialBuild", "@BUILD_TIMESTAMP@\0" + END + END +END + +1 RT_MANIFEST "gpg-error.w32-manifest" diff --git a/comm/third_party/libgpg-error/src/visibility.c b/comm/third_party/libgpg-error/src/visibility.c new file mode 100644 index 0000000000..03a6c45b07 --- /dev/null +++ b/comm/third_party/libgpg-error/src/visibility.c @@ -0,0 +1,1250 @@ +/* visibility.c - Wrapper for all public functions. + * Copyright (C) 2014 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include +#include +#include /* For abort(). */ + +#define _GPGRT_INCL_BY_VISIBILITY_C 1 +#include "gpgrt-int.h" + +const char * +gpg_strerror (gpg_error_t err) +{ + return _gpg_strerror (err); +} + +int +gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen) +{ + return _gpg_strerror_r (err, buf, buflen); +} + +const char * +gpg_strsource (gpg_error_t err) +{ + return _gpg_strsource (err); +} + +gpg_err_code_t +gpg_err_code_from_errno (int err) +{ + return _gpg_err_code_from_errno (err); +} + +int +gpg_err_code_to_errno (gpg_err_code_t code) +{ + return _gpg_err_code_to_errno (code); +} + +gpg_err_code_t +gpg_err_code_from_syserror (void) +{ + return _gpg_err_code_from_syserror (); +} + +void +gpg_err_set_errno (int err) +{ + _gpg_err_set_errno (err); +} + + +gpg_error_t +gpg_err_init (void) +{ + return _gpg_err_init (); +} + +void +gpg_err_deinit (int mode) +{ + _gpg_err_deinit (mode); +} + +void +gpgrt_add_emergency_cleanup (void (*f)(void)) +{ + _gpgrt_add_emergency_cleanup (f); +} + +void +gpgrt_abort (void) +{ + _gpgrt_abort (); +} + +const char * +gpg_error_check_version (const char *req_version) +{ + return _gpg_error_check_version (req_version); +} + +const char * +gpgrt_check_version (const char *req_version) +{ + return _gpg_error_check_version (req_version); +} + +void +gpgrt_set_syscall_clamp (void (*pre)(void), void (*post)(void)) +{ + _gpgrt_set_syscall_clamp (pre, post); +} + +void +gpgrt_get_syscall_clamp (void (**r_pre)(void), void (**r_post)(void)) +{ + _gpgrt_get_syscall_clamp (r_pre, r_post); +} + +void +gpgrt_set_alloc_func (void *(*f)(void *a, size_t n)) +{ + _gpgrt_set_alloc_func (f); +} + + +gpg_err_code_t +gpgrt_lock_init (gpgrt_lock_t *lockhd) +{ + return _gpgrt_lock_init (lockhd); +} + +gpg_err_code_t +gpgrt_lock_lock (gpgrt_lock_t *lockhd) +{ + return _gpgrt_lock_lock (lockhd); +} + +gpg_err_code_t +gpgrt_lock_trylock (gpgrt_lock_t *lockhd) +{ + return _gpgrt_lock_trylock (lockhd); +} + +gpg_err_code_t +gpgrt_lock_unlock (gpgrt_lock_t *lockhd) +{ + return _gpgrt_lock_unlock (lockhd); +} + +gpg_err_code_t +gpgrt_lock_destroy (gpgrt_lock_t *lockhd) +{ + return _gpgrt_lock_destroy (lockhd); +} + +gpg_err_code_t +gpgrt_yield (void) +{ + return _gpgrt_yield (); +} + + + +estream_t +gpgrt_fopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode) +{ + return _gpgrt_fopen (path, mode); +} + +estream_t +gpgrt_mopen (void *_GPGRT__RESTRICT data, size_t data_n, size_t data_len, + unsigned int grow, + void *(*func_realloc) (void *mem, size_t size), + void (*func_free) (void *mem), + const char *_GPGRT__RESTRICT mode) +{ + return _gpgrt_mopen (data, data_n, data_len, grow, func_realloc, func_free, + mode); +} + +estream_t +gpgrt_fopenmem (size_t memlimit, const char *_GPGRT__RESTRICT mode) +{ + return _gpgrt_fopenmem (memlimit, mode); +} + +estream_t +gpgrt_fopenmem_init (size_t memlimit, const char *_GPGRT__RESTRICT mode, + const void *data, size_t datalen) +{ + return _gpgrt_fopenmem_init (memlimit, mode, data, datalen); +} + +estream_t +gpgrt_fdopen (int filedes, const char *mode) +{ + return _gpgrt_fdopen (filedes, mode); +} + +estream_t +gpgrt_fdopen_nc (int filedes, const char *mode) +{ + return _gpgrt_fdopen_nc (filedes, mode); +} + +estream_t +gpgrt_sysopen (es_syshd_t *syshd, const char *mode) +{ + return _gpgrt_sysopen (syshd, mode); +} + +estream_t +gpgrt_sysopen_nc (es_syshd_t *syshd, const char *mode) +{ + return _gpgrt_sysopen_nc (syshd, mode); +} + +estream_t +gpgrt_fpopen (FILE *fp, const char *mode) +{ + return _gpgrt_fpopen (fp, mode); +} + +estream_t +gpgrt_fpopen_nc (FILE *fp, const char *mode) +{ + return _gpgrt_fpopen_nc (fp, mode); +} + +estream_t +gpgrt_freopen (const char *_GPGRT__RESTRICT path, + const char *_GPGRT__RESTRICT mode, + estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_freopen (path, mode, stream); +} + +estream_t +gpgrt_fopencookie (void *_GPGRT__RESTRICT cookie, + const char *_GPGRT__RESTRICT mode, + gpgrt_cookie_io_functions_t functions) +{ + return _gpgrt_fopencookie (cookie, mode, functions); +} + +int +gpgrt_fclose (estream_t stream) +{ + return _gpgrt_fclose (stream); +} + +int +gpgrt_fcancel (estream_t stream) +{ + return _gpgrt_fcancel (stream); +} + +int +gpgrt_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen) +{ + return _gpgrt_fclose_snatch (stream, r_buffer, r_buflen); +} + +int +gpgrt_onclose (estream_t stream, int mode, + void (*fnc) (estream_t, void*), void *fnc_value) +{ + return _gpgrt_onclose (stream, mode, fnc, fnc_value); +} + +int +gpgrt_fileno (estream_t stream) +{ + return _gpgrt_fileno (stream); +} + +int +gpgrt_fileno_unlocked (estream_t stream) +{ + return _gpgrt_fileno_unlocked (stream); +} + +int +gpgrt_syshd (estream_t stream, es_syshd_t *syshd) +{ + return _gpgrt_syshd (stream, syshd); +} + +int +gpgrt_syshd_unlocked (estream_t stream, es_syshd_t *syshd) +{ + return _gpgrt_syshd_unlocked (stream, syshd); +} + +void +_gpgrt_set_std_fd (int no, int fd) +{ + _gpgrt__set_std_fd (no, fd); /* (double dash in name) */ +} + +estream_t +_gpgrt_get_std_stream (int fd) +{ + return _gpgrt__get_std_stream (fd); /* (double dash in name) */ +} + +void +gpgrt_flockfile (estream_t stream) +{ + _gpgrt_flockfile (stream); +} + +int +gpgrt_ftrylockfile (estream_t stream) +{ + return _gpgrt_ftrylockfile (stream); +} + +void +gpgrt_funlockfile (estream_t stream) +{ + _gpgrt_funlockfile (stream); +} + +int +_gpgrt_pending (estream_t stream) +{ + return _gpgrt__pending (stream); +} + +int +_gpgrt_pending_unlocked (estream_t stream) +{ + return _gpgrt__pending_unlocked (stream); +} + +int +gpgrt_feof (estream_t stream) +{ + return _gpgrt_feof (stream); +} + +int +gpgrt_feof_unlocked (estream_t stream) +{ + return _gpgrt_feof_unlocked (stream); +} + +int +gpgrt_ferror (estream_t stream) +{ + return _gpgrt_ferror (stream); +} + +int +gpgrt_ferror_unlocked (estream_t stream) +{ + return _gpgrt_ferror_unlocked (stream); +} + +void +gpgrt_clearerr (estream_t stream) +{ + _gpgrt_clearerr (stream); +} + +void +gpgrt_clearerr_unlocked (estream_t stream) +{ + _gpgrt_clearerr_unlocked (stream); +} + +int +gpgrt_fflush (estream_t stream) +{ + return _gpgrt_fflush (stream); +} + +int +gpgrt_fseek (estream_t stream, long int offset, int whence) +{ + return _gpgrt_fseek (stream, offset, whence); +} + +int +gpgrt_fseeko (estream_t stream, gpgrt_off_t offset, int whence) +{ + return _gpgrt_fseeko (stream, offset, whence); +} + +long int +gpgrt_ftell (estream_t stream) +{ + return _gpgrt_ftell (stream); +} + +gpgrt_off_t +gpgrt_ftello (estream_t stream) +{ + return _gpgrt_ftello (stream); +} + +void +gpgrt_rewind (estream_t stream) +{ + _gpgrt_rewind (stream); +} + +int +gpgrt_ftruncate (estream_t stream, gpgrt_off_t length) +{ + return _gpgrt_ftruncate (stream, length); +} + +int +gpgrt_fgetc (estream_t stream) +{ + return _gpgrt_fgetc (stream); +} + +int +_gpgrt_getc_underflow (estream_t stream) +{ + return _gpgrt__getc_underflow (stream); +} + +int +gpgrt_fputc (int c, estream_t stream) +{ + return _gpgrt_fputc (c, stream); +} + +int +_gpgrt_putc_overflow (int c, estream_t stream) +{ + return _gpgrt__putc_overflow (c, stream); +} + +int +gpgrt_ungetc (int c, estream_t stream) +{ + return _gpgrt_ungetc (c, stream); +} + +int +gpgrt_read (estream_t _GPGRT__RESTRICT stream, + void *_GPGRT__RESTRICT buffer, size_t bytes_to_read, + size_t *_GPGRT__RESTRICT bytes_read) +{ + return _gpgrt_read (stream, buffer, bytes_to_read, bytes_read); +} + +int +gpgrt_write (estream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t bytes_to_write, + size_t *_GPGRT__RESTRICT bytes_written) +{ + return _gpgrt_write (stream, buffer, bytes_to_write, bytes_written); +} + +int +gpgrt_write_sanitized (estream_t _GPGRT__RESTRICT stream, + const void * _GPGRT__RESTRICT buffer, size_t length, + const char * delimiters, + size_t * _GPGRT__RESTRICT bytes_written) +{ + return _gpgrt_write_sanitized (stream, buffer, length, delimiters, + bytes_written); +} + +int +gpgrt_write_hexstring (estream_t _GPGRT__RESTRICT stream, + const void *_GPGRT__RESTRICT buffer, size_t length, + int reserved, size_t *_GPGRT__RESTRICT bytes_written ) +{ + return _gpgrt_write_hexstring (stream, buffer, length, reserved, + bytes_written); +} + +size_t +gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, + estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_fread (ptr, size, nitems, stream); +} + +size_t +gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, + estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_fwrite (ptr, size, nitems, stream); +} + +char * +gpgrt_fgets (char *_GPGRT__RESTRICT buffer, int length, + estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_fgets (buffer, length, stream); +} + +int +gpgrt_fputs (const char *_GPGRT__RESTRICT s, estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_fputs (s, stream); +} + +int +gpgrt_fputs_unlocked (const char *_GPGRT__RESTRICT s, + estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_fputs_unlocked (s, stream); +} + +gpgrt_ssize_t +gpgrt_getline (char *_GPGRT__RESTRICT *_GPGRT__RESTRICT lineptr, + size_t *_GPGRT__RESTRICT n, estream_t _GPGRT__RESTRICT stream) +{ + return _gpgrt_getline (lineptr, n, stream); +} + +gpgrt_ssize_t +gpgrt_read_line (estream_t stream, + char **addr_of_buffer, size_t *length_of_buffer, + size_t *max_length) +{ + return _gpgrt_read_line (stream, addr_of_buffer, length_of_buffer, + max_length); +} + +int +gpgrt_vfprintf (estream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, + va_list ap) +{ + return _gpgrt_vfprintf (stream, NULL, NULL, format, ap); +} + +int +gpgrt_vfprintf_unlocked (estream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, + va_list ap) +{ + return _gpgrt_vfprintf_unlocked (stream, NULL, NULL, format, ap); +} + +int +gpgrt_printf (const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf (es_stdout, NULL, NULL, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_printf_unlocked (const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf_unlocked (es_stdout, NULL, NULL, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_fprintf (estream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf (stream, NULL, NULL, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_fprintf_unlocked (estream_t _GPGRT__RESTRICT stream, + const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf_unlocked (stream, NULL, NULL, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_fprintf_sf (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf (stream, sf, sfvalue, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_fprintf_sf_unlocked (estream_t _GPGRT__RESTRICT stream, + gpgrt_string_filter_t sf, void *sfvalue, + const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_vfprintf_unlocked (stream, sf, sfvalue, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_setvbuf (estream_t _GPGRT__RESTRICT stream, + char *_GPGRT__RESTRICT buf, int type, size_t size) +{ + return _gpgrt_setvbuf (stream, buf, type, size); +} + +void +gpgrt_setbuf (estream_t _GPGRT__RESTRICT stream, char *_GPGRT__RESTRICT buf) +{ + _gpgrt_setvbuf (stream, buf, buf? _IOFBF : _IONBF, BUFSIZ); +} + +void +gpgrt_set_binary (estream_t stream) +{ + _gpgrt_set_binary (stream); +} + +int +gpgrt_set_nonblock (estream_t stream, int onoff) +{ + return _gpgrt_set_nonblock (stream, onoff); +} + +int +gpgrt_get_nonblock (estream_t stream) +{ + return _gpgrt_get_nonblock (stream); +} + +int +gpgrt_poll (gpgrt_poll_t *fds, unsigned int nfds, int timeout) +{ + return _gpgrt_poll (fds, nfds, timeout); +} + +estream_t +gpgrt_tmpfile (void) +{ + return _gpgrt_tmpfile (); +} + +void +gpgrt_opaque_set (estream_t stream, void *opaque) +{ + _gpgrt_opaque_set (stream, opaque); +} + +void * +gpgrt_opaque_get (estream_t stream) +{ + return _gpgrt_opaque_get (stream); +} + +void +gpgrt_fname_set (estream_t stream, const char *fname) +{ + _gpgrt_fname_set (stream, fname); +} + +const char * +gpgrt_fname_get (estream_t stream) +{ + return _gpgrt_fname_get (stream); +} + +int +gpgrt_asprintf (char **r_buf, const char *_GPGRT__RESTRICT format, ...) +{ + va_list ap; + int rc; + + va_start (ap, format); + rc = _gpgrt_estream_vasprintf (r_buf, format, ap); + va_end (ap); + + return rc; +} + +int +gpgrt_vasprintf (char **r_buf, const char *_GPGRT__RESTRICT format, va_list ap) +{ + return _gpgrt_estream_vasprintf (r_buf, format, ap); +} + +char * +gpgrt_bsprintf (const char *_GPGRT__RESTRICT format, ...) +{ + int rc; + va_list ap; + char *buf; + + va_start (ap, format); + rc = _gpgrt_estream_vasprintf (&buf, format, ap); + va_end (ap); + if (rc < 0) + return NULL; + return buf; +} + +char * +gpgrt_vbsprintf (const char *_GPGRT__RESTRICT format, va_list ap) +{ + int rc; + char *buf; + + rc = _gpgrt_estream_vasprintf (&buf, format, ap); + if (rc < 0) + return NULL; + return buf; +} + +int +gpgrt_snprintf (char *buf, size_t bufsize, const char *format, ...) +{ + int rc; + va_list arg_ptr; + + va_start (arg_ptr, format); + rc = _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr); + va_end (arg_ptr); + + return rc; +} + +int +gpgrt_vsnprintf (char *buf, size_t bufsize, + const char *format, va_list arg_ptr) +{ + return _gpgrt_estream_vsnprintf (buf, bufsize, format, arg_ptr); +} + + + +void * +gpgrt_realloc (void *a, size_t n) +{ + return _gpgrt_realloc (a, n); +} + +void * +gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size) +{ + return _gpgrt_reallocarray (a, oldnmemb, nmemb, size); +} + +void * +gpgrt_malloc (size_t n) +{ + return _gpgrt_malloc (n); +} + +void * +gpgrt_calloc (size_t n, size_t m) +{ + return _gpgrt_calloc (n, m); +} + +char * +gpgrt_strdup (const char *string) +{ + return _gpgrt_strdup (string); +} + +char * +gpgrt_strconcat (const char *s1, ...) +{ + va_list arg_ptr; + char *result; + + if (!s1) + result = _gpgrt_strdup (""); + else + { + va_start (arg_ptr, s1); + result = _gpgrt_strconcat_core (s1, arg_ptr); + va_end (arg_ptr); + } + return result; +} + +void +gpgrt_free (void *a) +{ + if (a) + _gpgrt_free (a); +} + +char * +gpgrt_getenv (const char *name) +{ + return _gpgrt_getenv (name); +} + +gpg_err_code_t +gpgrt_setenv (const char *name, const char *value, int overwrite) +{ + return _gpgrt_setenv (name, value, overwrite); +} + +gpg_err_code_t +gpgrt_mkdir (const char *name, const char *modestr) +{ + return _gpgrt_mkdir (name, modestr); +} + +gpg_err_code_t +gpgrt_chdir (const char *name) +{ + return _gpgrt_chdir (name); +} + +char * +gpgrt_getcwd (void) +{ + return _gpgrt_getcwd (); +} + +gpg_err_code_t +gpgrt_access (const char *fname, int mode) +{ + return _gpgrt_access (fname, mode); +} + + + +gpgrt_b64state_t +gpgrt_b64enc_start (estream_t stream, const char *title) +{ + return _gpgrt_b64enc_start (stream, title); +} + +gpg_err_code_t +gpgrt_b64enc_write (gpgrt_b64state_t state, const void *buffer, size_t nbytes) +{ + return _gpgrt_b64enc_write (state, buffer, nbytes); +} + +gpg_err_code_t +gpgrt_b64enc_finish (gpgrt_b64state_t state) +{ + return _gpgrt_b64enc_finish (state); +} + +gpgrt_b64state_t +gpgrt_b64dec_start (const char *title) +{ + return _gpgrt_b64dec_start (title); +} + +gpg_error_t +gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, + size_t length, size_t *r_nbytes) +{ + return _gpgrt_b64dec_proc (state, buffer, length, r_nbytes); +} + +gpg_error_t +gpgrt_b64dec_finish (gpgrt_b64state_t state) +{ + return _gpgrt_b64dec_finish (state); +} + + + +int +gpgrt_get_errorcount (int clear) +{ + return _gpgrt_get_errorcount (clear); +} + +void +gpgrt_inc_errorcount (void) +{ + _gpgrt_inc_errorcount (); +} + +void +gpgrt_log_set_sink (const char *name, estream_t stream, int fd) +{ + _gpgrt_log_set_sink (name, stream, fd); +} + +void +gpgrt_log_set_socket_dir_cb (const char *(*fnc)(void)) +{ + _gpgrt_log_set_socket_dir_cb (fnc); +} + +void +gpgrt_log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)) +{ + _gpgrt_log_set_pid_suffix_cb (cb); +} + +void +gpgrt_log_set_prefix (const char *text, unsigned int flags) +{ + _gpgrt_log_set_prefix (text, flags); +} + +const char * +gpgrt_log_get_prefix (unsigned int *flags) +{ + return _gpgrt_log_get_prefix (flags); +} + +int +gpgrt_log_test_fd (int fd) +{ + return _gpgrt_log_test_fd (fd); +} + +int +gpgrt_log_get_fd (void) +{ + return _gpgrt_log_get_fd (); +} + +estream_t +gpgrt_log_get_stream (void) +{ + return _gpgrt_log_get_stream (); +} + +void +gpgrt_log (int level, const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt) ; + _gpgrt_logv (level, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_logv (int level, const char *fmt, va_list arg_ptr) +{ + _gpgrt_logv (level, fmt, arg_ptr); +} + +void +gpgrt_logv_prefix (int level, const char *prefix, + const char *fmt, va_list arg_ptr) +{ + _gpgrt_logv_prefix (level, prefix, fmt, arg_ptr); +} + +void +gpgrt_log_string (int level, const char *string) +{ + _gpgrt_log_string (level, string); +} + +void +gpgrt_log_info (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv (GPGRT_LOGLVL_INFO, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_log_error (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv (GPGRT_LOGLVL_ERROR, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_log_fatal (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv (GPGRT_LOGLVL_FATAL, fmt, arg_ptr); + va_end (arg_ptr); + _gpgrt_abort (); /* Never called; just to make the compiler happy. */ +} + +void +gpgrt_log_bug (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv (GPGRT_LOGLVL_BUG, fmt, arg_ptr); + va_end (arg_ptr); + _gpgrt_abort (); /* Never called; just to make the compiler happy. */ +} + +void +gpgrt_log_debug (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + _gpgrt_logv (GPGRT_LOGLVL_DEBUG, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_log_debug_string (const char *string, const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, string, NULL, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_log_printf (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv (fmt ? GPGRT_LOGLVL_CONT : GPGRT_LOGLVL_BEGIN, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_log_flush (void) +{ + _gpgrt_log_flush (); +} + +void +gpgrt_log_printhex (const void *buffer, size_t length, const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv_printhex (buffer, length, fmt, arg_ptr); + va_end (arg_ptr); +} + +void +gpgrt_log_clock (const char *fmt, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, fmt); + _gpgrt_logv_clock (fmt, arg_ptr); + va_end (arg_ptr); +} + +void +_gpgrt_log_assert (const char *expr, const char *file, + int line, const char *func) +{ +#ifdef GPGRT_HAVE_MACRO_FUNCTION + _gpgrt__log_assert (expr, file, line, func); +#else + _gpgrt__log_assert (expr, file, line); +#endif +} + + +#if 0 +gpg_err_code_t +gpgrt_make_pipe (int filedes[2], estream_t *r_fp, int direction, int nonblock) +{ + return _gpgrt_make_pipe (filedes, r_fp, direction, nonblock); +} + +gpg_err_code_t +gpgrt_spawn_process (const char *pgmname, const char *argv[], + int *except, void (*preexec)(void), unsigned int flags, + estream_t *r_infp, estream_t *r_outfp, estream_t *r_errfp, + pid_t *pid) +{ + return _gpgrt_spawn_process (pgmname, argv, except, preexec, flags, + r_infp, r_outfp, r_errfp, pid); +} + +gpg_err_code_t +gpgrt_spawn_process_fd (const char *pgmname, const char *argv[], + int infd, int outfd, int errfd, pid_t *pid) +{ + return _gpgrt_spawn_process_fd (pgmname, argv, infd, outfd, errfd, pid); +} + +gpg_err_code_t +gpgrt_spawn_process_detached (const char *pgmname, const char *argv[], + const char *envp[]) +{ + return _gpgrt_spawn_process_detached (pgmname, argv, envp); +} + +gpg_err_code_t +gpgrt_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode) +{ + return _gpgrt_wait_process (pgmname, pid, hang, r_exitcode); +} + +gpg_err_code_t +gpgrt_wait_processes (const char **pgmnames, pid_t *pids, + size_t count, int hang, int *r_exitcodes) +{ + return _gpgrt_wait_processes (pgmnames, pids, count, hang, r_exitcodes); +} + +void +gpgrt_kill_process (pid_t pid) +{ + _gpgrt_kill_process (pid); +} + +void +gpgrt_release_process (pid_t pid) +{ + _gpgrt_release_process (pid); +} +#endif /*0*/ + + +int +gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts) +{ + return _gpgrt_argparse (fp, arg, opts); +} + +int +gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, const char *name) +{ + return _gpgrt_argparser (arg, opts, name); +} + +void +gpgrt_usage (int level) +{ + _gpgrt_usage (level); +} + +const char * +gpgrt_strusage (int level) +{ + return _gpgrt_strusage (level); +} + +void +gpgrt_set_strusage (const char *(*f)(int)) +{ + _gpgrt_set_strusage (f); +} + +void +gpgrt_set_usage_outfnc (int (*f)(int, const char *)) +{ + _gpgrt_set_usage_outfnc (f); +} + +void +gpgrt_set_fixed_string_mapper (const char *(*f)(const char*)) +{ + _gpgrt_set_fixed_string_mapper (f); +} + +void +gpgrt_set_confdir (int what, const char *name) +{ + _gpgrt_set_confdir (what, name); +} + + + +/* Compare program versions. */ +int +gpgrt_cmp_version (const char *a, const char *b, int level) +{ + return _gpgrt_cmp_version (a, b, level); +} + + + +/* String utilities. */ +char * +gpgrt_fnameconcat (const char *first, ... ) +{ + va_list arg_ptr; + char *result; + + va_start (arg_ptr, first); + result = _gpgrt_vfnameconcat (0, first, arg_ptr); + va_end (arg_ptr); + return result; +} + +char * +gpgrt_absfnameconcat (const char *first, ... ) +{ + va_list arg_ptr; + char *result; + + va_start (arg_ptr, first); + result = _gpgrt_vfnameconcat (1, first, arg_ptr); + va_end (arg_ptr); + return result; +} + + + +/* For consistency reasons we use function wrappers also for Windows + * specific function despite that they are technically not needed. */ +#ifdef HAVE_W32_SYSTEM + +char * +gpgrt_w32_reg_query_string (const char *root, const char *dir, const char *name) +{ + return _gpgrt_w32_reg_query_string (root, dir, name); +} + +#endif /*HAVE_W32_SYSTEM*/ diff --git a/comm/third_party/libgpg-error/src/visibility.h b/comm/third_party/libgpg-error/src/visibility.h new file mode 100644 index 0000000000..f9218b5558 --- /dev/null +++ b/comm/third_party/libgpg-error/src/visibility.h @@ -0,0 +1,419 @@ +/* visibility.h - Set visibility attribute + * Copyright (C) 2014 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef _GPGRT_VISIBILITY_H +#define _GPGRT_VISIBILITY_H + +/* Include the main header here so that public symbols are mapped to + the internal underscored ones. */ +#ifdef _GPGRT_INCL_BY_VISIBILITY_C +# include "gpgrt-int.h" +#endif + + +/* Our use of the ELF visibility feature works by passing + -fvisibiliy=hidden on the command line and by explicitly marking + all exported functions as visible. + + NOTE: When adding new functions, please make sure to add them to + gpg-error.vers and gpg-error.def.in as well. */ + +#ifdef _GPGRT_INCL_BY_VISIBILITY_C + +# ifdef GPGRT_USE_VISIBILITY +# define MARK_VISIBLE(name) \ + extern __typeof__ (name) name __attribute__ ((visibility("default"))); +# else +# define MARK_VISIBLE(name) /* */ +# endif + +MARK_VISIBLE (gpg_strerror) +MARK_VISIBLE (gpg_strerror_r) +MARK_VISIBLE (gpg_strsource) +MARK_VISIBLE (gpg_err_code_from_errno) +MARK_VISIBLE (gpg_err_code_to_errno) +MARK_VISIBLE (gpg_err_code_from_syserror) +MARK_VISIBLE (gpg_err_set_errno) + +MARK_VISIBLE (gpg_err_init) +MARK_VISIBLE (gpg_err_deinit) +MARK_VISIBLE (gpgrt_add_emergency_cleanup) +MARK_VISIBLE (gpgrt_abort) +MARK_VISIBLE (gpg_error_check_version) +MARK_VISIBLE (gpgrt_check_version) + +MARK_VISIBLE (gpgrt_lock_init) +MARK_VISIBLE (gpgrt_lock_lock) +MARK_VISIBLE (gpgrt_lock_unlock) +MARK_VISIBLE (gpgrt_lock_destroy) +MARK_VISIBLE (gpgrt_yield) +MARK_VISIBLE (gpgrt_lock_trylock) + +MARK_VISIBLE (gpgrt_fopen) +MARK_VISIBLE (gpgrt_mopen) +MARK_VISIBLE (gpgrt_fopenmem) +MARK_VISIBLE (gpgrt_fopenmem_init) +MARK_VISIBLE (gpgrt_fdopen) +MARK_VISIBLE (gpgrt_fdopen_nc) +MARK_VISIBLE (gpgrt_sysopen) +MARK_VISIBLE (gpgrt_sysopen_nc) +MARK_VISIBLE (gpgrt_fpopen) +MARK_VISIBLE (gpgrt_fpopen_nc) +MARK_VISIBLE (gpgrt_freopen) +MARK_VISIBLE (gpgrt_fopencookie) +MARK_VISIBLE (gpgrt_fclose) +MARK_VISIBLE (gpgrt_fcancel) +MARK_VISIBLE (gpgrt_fclose_snatch) +MARK_VISIBLE (gpgrt_onclose) +MARK_VISIBLE (gpgrt_fileno) +MARK_VISIBLE (gpgrt_fileno_unlocked) +MARK_VISIBLE (gpgrt_syshd) +MARK_VISIBLE (gpgrt_syshd_unlocked) +MARK_VISIBLE (_gpgrt_set_std_fd) +MARK_VISIBLE (_gpgrt_get_std_stream) +MARK_VISIBLE (gpgrt_flockfile) +MARK_VISIBLE (gpgrt_ftrylockfile) +MARK_VISIBLE (gpgrt_funlockfile) +MARK_VISIBLE (_gpgrt_pending) +MARK_VISIBLE (_gpgrt_pending_unlocked) +MARK_VISIBLE (gpgrt_feof) +MARK_VISIBLE (gpgrt_feof_unlocked) +MARK_VISIBLE (gpgrt_ferror) +MARK_VISIBLE (gpgrt_ferror_unlocked) +MARK_VISIBLE (gpgrt_clearerr) +MARK_VISIBLE (gpgrt_clearerr_unlocked) +MARK_VISIBLE (gpgrt_fflush) +MARK_VISIBLE (gpgrt_fseek) +MARK_VISIBLE (gpgrt_fseeko) +MARK_VISIBLE (gpgrt_ftell) +MARK_VISIBLE (gpgrt_ftello) +MARK_VISIBLE (gpgrt_rewind) +MARK_VISIBLE (gpgrt_ftruncate) +MARK_VISIBLE (gpgrt_fgetc) +MARK_VISIBLE (_gpgrt_getc_underflow) +MARK_VISIBLE (gpgrt_fputc) +MARK_VISIBLE (_gpgrt_putc_overflow) +MARK_VISIBLE (gpgrt_ungetc) +MARK_VISIBLE (gpgrt_read) +MARK_VISIBLE (gpgrt_write) +MARK_VISIBLE (gpgrt_write_sanitized) +MARK_VISIBLE (gpgrt_write_hexstring) +MARK_VISIBLE (gpgrt_fread) +MARK_VISIBLE (gpgrt_fwrite) +MARK_VISIBLE (gpgrt_fgets) +MARK_VISIBLE (gpgrt_fputs) +MARK_VISIBLE (gpgrt_fputs_unlocked) +MARK_VISIBLE (gpgrt_getline) +MARK_VISIBLE (gpgrt_read_line) +MARK_VISIBLE (gpgrt_fprintf) +MARK_VISIBLE (gpgrt_fprintf_unlocked) +MARK_VISIBLE (gpgrt_fprintf_sf) +MARK_VISIBLE (gpgrt_fprintf_sf_unlocked) +MARK_VISIBLE (gpgrt_printf) +MARK_VISIBLE (gpgrt_printf_unlocked) +MARK_VISIBLE (gpgrt_vfprintf) +MARK_VISIBLE (gpgrt_vfprintf_unlocked) +MARK_VISIBLE (gpgrt_setvbuf) +MARK_VISIBLE (gpgrt_setbuf) +MARK_VISIBLE (gpgrt_set_binary) +MARK_VISIBLE (gpgrt_set_nonblock) +MARK_VISIBLE (gpgrt_get_nonblock) +MARK_VISIBLE (gpgrt_poll) +MARK_VISIBLE (gpgrt_tmpfile) +MARK_VISIBLE (gpgrt_opaque_set) +MARK_VISIBLE (gpgrt_opaque_get) +MARK_VISIBLE (gpgrt_fname_set) +MARK_VISIBLE (gpgrt_fname_get) +MARK_VISIBLE (gpgrt_asprintf) +MARK_VISIBLE (gpgrt_vasprintf) +MARK_VISIBLE (gpgrt_bsprintf) +MARK_VISIBLE (gpgrt_vbsprintf) +MARK_VISIBLE (gpgrt_snprintf) +MARK_VISIBLE (gpgrt_vsnprintf) + +MARK_VISIBLE (gpgrt_set_syscall_clamp) +MARK_VISIBLE (gpgrt_get_syscall_clamp) +MARK_VISIBLE (gpgrt_set_alloc_func) + +MARK_VISIBLE (gpgrt_realloc) +MARK_VISIBLE (gpgrt_reallocarray) +MARK_VISIBLE (gpgrt_malloc) +MARK_VISIBLE (gpgrt_calloc) +MARK_VISIBLE (gpgrt_strdup) +MARK_VISIBLE (gpgrt_strconcat) +MARK_VISIBLE (gpgrt_free) +MARK_VISIBLE (gpgrt_getenv) +MARK_VISIBLE (gpgrt_setenv) +MARK_VISIBLE (gpgrt_mkdir) +MARK_VISIBLE (gpgrt_chdir) +MARK_VISIBLE (gpgrt_getcwd) +MARK_VISIBLE (gpgrt_access); + +MARK_VISIBLE (gpgrt_b64dec_start) +MARK_VISIBLE (gpgrt_b64dec_proc) +MARK_VISIBLE (gpgrt_b64dec_finish) +MARK_VISIBLE (gpgrt_b64enc_start) +MARK_VISIBLE (gpgrt_b64enc_write) +MARK_VISIBLE (gpgrt_b64enc_finish) + +MARK_VISIBLE (gpgrt_get_errorcount) +MARK_VISIBLE (gpgrt_inc_errorcount) +MARK_VISIBLE (gpgrt_log_set_sink) +MARK_VISIBLE (gpgrt_log_set_socket_dir_cb) +MARK_VISIBLE (gpgrt_log_set_pid_suffix_cb) +MARK_VISIBLE (gpgrt_log_set_prefix) +MARK_VISIBLE (gpgrt_log_get_prefix) +MARK_VISIBLE (gpgrt_log_test_fd) +MARK_VISIBLE (gpgrt_log_get_fd) +MARK_VISIBLE (gpgrt_log_get_stream) +MARK_VISIBLE (gpgrt_log) +MARK_VISIBLE (gpgrt_logv) +MARK_VISIBLE (gpgrt_logv_prefix) +MARK_VISIBLE (gpgrt_log_string) +MARK_VISIBLE (gpgrt_log_bug) +MARK_VISIBLE (gpgrt_log_fatal) +MARK_VISIBLE (gpgrt_log_error) +MARK_VISIBLE (gpgrt_log_info) +MARK_VISIBLE (gpgrt_log_debug) +MARK_VISIBLE (gpgrt_log_debug_string) +MARK_VISIBLE (gpgrt_log_printf) +MARK_VISIBLE (gpgrt_log_printhex) +MARK_VISIBLE (gpgrt_log_clock) +MARK_VISIBLE (gpgrt_log_flush) +MARK_VISIBLE (_gpgrt_log_assert) + +#if 0 +MARK_VISIBLE (gpgrt_make_pipe) +MARK_VISIBLE (gpgrt_spawn_process) +MARK_VISIBLE (gpgrt_spawn_process_fd) +MARK_VISIBLE (gpgrt_spawn_process_detached) +MARK_VISIBLE (gpgrt_wait_process) +MARK_VISIBLE (gpgrt_wait_processes) +MARK_VISIBLE (gpgrt_kill_process) +MARK_VISIBLE (gpgrt_release_process) +#endif + +MARK_VISIBLE (gpgrt_argparse) +MARK_VISIBLE (gpgrt_argparser) +MARK_VISIBLE (gpgrt_usage) +MARK_VISIBLE (gpgrt_strusage) +MARK_VISIBLE (gpgrt_set_strusage) +MARK_VISIBLE (gpgrt_set_fixed_string_mapper); +MARK_VISIBLE (gpgrt_set_usage_outfnc); +MARK_VISIBLE (gpgrt_set_confdir); + +MARK_VISIBLE (gpgrt_cmp_version); + +MARK_VISIBLE (gpgrt_fnameconcat); +MARK_VISIBLE (gpgrt_absfnameconcat); + + + +#undef MARK_VISIBLE + +#else /*!_GPGRT_INCL_BY_VISIBILITY_C*/ + +/* To avoid accidental use of the public functions inside Libgpg-error, + we redefine them to catch such errors. */ + +#define gpg_strerror _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_strerror_r _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_strsource _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_err_code_from_errno _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_err_code_to_errno _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_err_code_from_syserror _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_err_set_errno _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpg_err_init _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_err_deinit _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_add_emergency_cleanup _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_abort _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpg_error_check_version _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_check_version _gpgrt_USE_OTHER_FUNCTION + +#define gpgrt_lock_init _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_lock_lock _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_lock_unlock _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_lock_destroy _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_yield _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_lock_trylock _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_fopen _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_mopen _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fopenmem _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fopenmem_init _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fdopen _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fdopen_nc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_sysopen _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_sysopen_nc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fpopen _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fpopen_nc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_freopen _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fopencookie _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fclose _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fcancel _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fclose_snatch _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_onclose _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fileno _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fileno_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_syshd _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_syshd_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_set_std_fd _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_get_std_stream _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_flockfile _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_ftrylockfile _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_funlockfile _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_pending _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_pending_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_feof _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_feof_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_ferror _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_ferror_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_clearerr _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_clearerr_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fflush _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fseek _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fseeko _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_ftell _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_ftello _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_rewind _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_ftruncate _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fgetc _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_getc_underflow _gpgrt_USE_DBLUNDERSCO_FUNCTION +#define gpgrt_fputc _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_putc_overflow _gpgrt_USE_DBLUNDERSCO_FUNCTION +#define gpgrt_ungetc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_read _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_write _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_write_sanitized _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_write_hexstring _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fread _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fwrite _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fgets _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fputs _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fputs_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_getline _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_read_line _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fprintf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fprintf_sf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fprintf_sf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_printf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_printf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_vfprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_vfprintf_unlocked _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_setvbuf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_setbuf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_binary _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_nonblock _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_get_nonblock _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_poll _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_tmpfile _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_opaque_set _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_opaque_get _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fname_set _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fname_get _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_asprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_vasprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_bsprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_vbsprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_snprintf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_vsnprintf _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_realloc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_reallocarray _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_malloc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_calloc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_strdup _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_strconcat _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_free _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_getenv _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_setenv _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_mkdir _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_chdir _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_getcwd _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_access _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_set_syscall_clamp _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_get_syscall_clamp _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_alloc_func _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_b64enc_start _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_b64enc_write _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_b64enc_finish _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_b64dec_start _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_b64dec_proc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_b64dec_finish _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_get_errorcount _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_inc_errorcount _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_set_sink _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_set_socket_dir_cb _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_set_pid_suffix_cb _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_set_prefix _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_get_prefix _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_test_fd _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_get_fd _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_get_stream _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_logv _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_logv_prefix _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_string _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_bug _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_fatal _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_error _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_info _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_debug _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_debug_string _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_printf _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_printhex _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_clock _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_log_flush _gpgrt_USE_UNDERSCORED_FUNCTION +#define _gpgrt_log_assert _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_make_pipe _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_spawn_process _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_spawn_process_fd _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_spawn_process_detached _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_wait_process _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_wait_processes _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_kill_process _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_release_process _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_argparse _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_argparser _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_usage _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_strusage _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_strusage _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_usage_outfnc _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_fixed_string_mapper _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_set_confdir _gpgrt_USE_UNDERSCORED_FUNCTION + +#define gpgrt_cmp_version _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_fnameconcat _gpgrt_USE_UNDERSCORED_FUNCTION +#define gpgrt_absfnameconcat _gpgrt_USE_UNDERSCORED_FUNCTION + +/* Windows specific functions. */ +#define gpgrt_w32_reg_query_string _gpgrt_USE_UNDERSCORED_FUNCTION + + +#endif /*!_GPGRT_INCL_BY_VISIBILITY_C*/ + +#endif /*_GPGRT_VISIBILITY_H*/ diff --git a/comm/third_party/libgpg-error/src/w32-add.h b/comm/third_party/libgpg-error/src/w32-add.h new file mode 100644 index 0000000000..34289615f4 --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-add.h @@ -0,0 +1,67 @@ +## w32-add.h - Snippet to be be included into gpg-error.h. +## Comments are indicated by a double hash mark. Due to a +## peculiarity of the script the first used line must not +## start with a hash mark. + +/* Decide whether to use the format_arg attribute. */ +#if _GPG_ERR_GCC_VERSION > 20800 +# define _GPG_ERR_ATTR_FORMAT_ARG(a) __attribute__ ((__format_arg__ (a))) +#else +# define _GPG_ERR_ATTR_FORMAT_ARG(a) +#endif + +/* A lean gettext implementation based on GNU style mo files which are + required to be encoded in UTF-8. There is a limit on 65534 entries + to save some RAM. Only Germanic plural rules are supported. */ +const char *_gpg_w32_bindtextdomain (const char *domainname, + const char *dirname); +const char *_gpg_w32_textdomain (const char *domainname); +const char *_gpg_w32_gettext (const char *msgid) + _GPG_ERR_ATTR_FORMAT_ARG (1); +const char *_gpg_w32_dgettext (const char *domainname, const char *msgid) + _GPG_ERR_ATTR_FORMAT_ARG (2); +const char *_gpg_w32_dngettext (const char *domainname, const char *msgid1, + const char *msgid2, unsigned long int n) + _GPG_ERR_ATTR_FORMAT_ARG (2) _GPG_ERR_ATTR_FORMAT_ARG (3); +const char *_gpg_w32_gettext_localename (void); +int _gpg_w32_gettext_use_utf8 (int value); + +#ifdef GPG_ERR_ENABLE_GETTEXT_MACROS +# define bindtextdomain(a,b) _gpg_w32_bindtextdomain ((a), (b)) +# define textdomain(a) _gpg_w32_textdomain ((a)) +# define gettext(a) _gpg_w32_gettext ((a)) +# define dgettext(a,b) _gpg_w32_dgettext ((a), (b)) +# define ngettext(a,b,c) _gpg_w32_dngettext (NULL, (a), (b), (c)) +# define dngettext(a,b,c,d) _gpg_w32_dngettext ((a), (b), (c), (d)) +# define gettext_localename() _gpg_w32_gettext_localename () +# define gettext_use_utf8(a) _gpg_w32_gettext_use_utf8 (a) +#endif /*GPG_ERR_ENABLE_GETTEXT_MACROS*/ + +/* Force the use of the locale NAME or if NAME is NULL the one derived + * from LANGID. This function must be used early and is not thread-safe. */ +void gpgrt_w32_override_locale (const char *name, unsigned short langid); + + +/* A simple iconv implementation w/o the need for an extra DLL. */ +struct _gpgrt_w32_iconv_s; +typedef struct _gpgrt_w32_iconv_s *gpgrt_w32_iconv_t; + +gpgrt_w32_iconv_t gpgrt_w32_iconv_open (const char *tocode, + const char *fromcode); +int gpgrt_w32_iconv_close (gpgrt_w32_iconv_t cd); +size_t gpgrt_w32_iconv (gpgrt_w32_iconv_t cd, + const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft); + +#ifdef GPGRT_ENABLE_W32_ICONV_MACROS +# define ICONV_CONST const +# define iconv_t gpgrt_w32_iconv_t +# define iconv_open(a,b) gpgrt_w32_iconv_open ((a), (b)) +# define iconv_close(a) gpgrt_w32_iconv_close ((a)) +# define iconv(a,b,c,d,e) gpgrt_w32_iconv ((a),(b),(c),(d),(e)) +#endif /*GPGRT_ENABLE_W32_ICONV_MACROS*/ + +/* Query a string in the registry. */ +char *gpgrt_w32_reg_query_string (const char *root, + const char *dir, + const char *name); diff --git a/comm/third_party/libgpg-error/src/w32-estream.c b/comm/third_party/libgpg-error/src/w32-estream.c new file mode 100644 index 0000000000..5bb1bcf56c --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-estream.c @@ -0,0 +1,1078 @@ +/* w32-estream.c - es_poll support on W32. + * Copyright (C) 2000 Werner Koch (dd9jn) + * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2010, 2016 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* + * This file is based on GPGME's w32-io.c started in 2001. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +#include + +/* Enable tracing. The value is the module name to be printed. */ +/*#define ENABLE_TRACING "estream" */ + +#include "gpgrt-int.h" + +/* + * In order to support es_poll on Windows, we create a proxy shim that + * we use as the estream I/O functions. This shim creates reader and + * writer threads that use the original I/O functions. + */ + + +/* Calculate array dimension. */ +#ifndef DIM +#define DIM(array) (sizeof (array) / sizeof (*array)) +#endif + +#define READBUF_SIZE 8192 +#define WRITEBUF_SIZE 8192 + + +typedef struct estream_cookie_w32_pollable *estream_cookie_w32_pollable_t; + +struct reader_context_s +{ + estream_cookie_w32_pollable_t pcookie; + HANDLE thread_hd; + + CRITICAL_SECTION mutex; + + int stop_me; + int eof; + int eof_shortcut; + int error; + int error_code; + + /* This is manually reset. */ + HANDLE have_data_ev; + /* This is automatically reset. */ + HANDLE have_space_ev; + /* This is manually reset but actually only triggered once. */ + HANDLE close_ev; + + size_t readpos, writepos; + char buffer[READBUF_SIZE]; +}; + +struct writer_context_s +{ + estream_cookie_w32_pollable_t pcookie; + HANDLE thread_hd; + + CRITICAL_SECTION mutex; + + int stop_me; + int error; + int error_code; + + /* This is manually reset. */ + HANDLE have_data; + HANDLE is_empty; + HANDLE close_ev; + size_t nbytes; + char buffer[WRITEBUF_SIZE]; +}; + +/* Cookie for pollable objects. */ +struct estream_cookie_w32_pollable +{ + unsigned int modeflags; + + struct cookie_io_functions_s next_functions; + void *next_cookie; + + struct reader_context_s *reader; + struct writer_context_s *writer; +}; + + +static DWORD CALLBACK +reader (void *arg) +{ + struct reader_context_s *ctx = arg; + int nbytes; + ssize_t nread; + + trace (("%p: reader starting", ctx)); + + for (;;) + { + EnterCriticalSection (&ctx->mutex); + /* Leave a 1 byte gap so that we can see whether it is empty or + full. */ + while ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos) + { + /* Wait for space. */ + if (!ResetEvent (ctx->have_space_ev)) + trace (("%p: ResetEvent failed: ec=%d", ctx, (int)GetLastError())); + LeaveCriticalSection (&ctx->mutex); + trace (("%p: waiting for space", ctx)); + WaitForSingleObject (ctx->have_space_ev, INFINITE); + trace (("%p: got space", ctx)); + EnterCriticalSection (&ctx->mutex); + } + gpgrt_assert (((ctx->writepos + 1) % READBUF_SIZE != ctx->readpos)); + if (ctx->stop_me) + { + LeaveCriticalSection (&ctx->mutex); + break; + } + nbytes = (ctx->readpos + READBUF_SIZE + - ctx->writepos - 1) % READBUF_SIZE; + gpgrt_assert (nbytes); + if (nbytes > READBUF_SIZE - ctx->writepos) + nbytes = READBUF_SIZE - ctx->writepos; + LeaveCriticalSection (&ctx->mutex); + + trace (("%p: reading up to %d bytes", ctx, nbytes)); + + nread = ctx->pcookie->next_functions.public.func_read + (ctx->pcookie->next_cookie, ctx->buffer + ctx->writepos, nbytes); + trace (("%p: got %d bytes", ctx, nread)); + if (nread < 0) + { + ctx->error_code = (int) errno; + /* NOTE (W32CE): Do not ignore ERROR_BUSY! Check at + least stop_me if that happens. */ + if (ctx->error_code == ERROR_BROKEN_PIPE) + { + ctx->eof = 1; + trace (("%p: got EOF (broken pipe)", ctx)); + } + else + { + ctx->error = 1; + trace (("%p: read error: ec=%d", ctx, ctx->error_code)); + } + break; + } + + EnterCriticalSection (&ctx->mutex); + if (ctx->stop_me) + { + LeaveCriticalSection (&ctx->mutex); + break; + } + if (!nread) + { + ctx->eof = 1; + trace (("%p: got eof", ctx)); + LeaveCriticalSection (&ctx->mutex); + break; + } + + ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE; + if (!SetEvent (ctx->have_data_ev)) + trace (("%p: SetEvent (%p) failed: ec=%d", + ctx, ctx->have_data_ev, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + } + /* Indicate that we have an error or EOF. */ + if (!SetEvent (ctx->have_data_ev)) + trace (("%p: SetEvent (%p) failed: ec=%d", + ctx, ctx->have_data_ev, (int)GetLastError ())); + + trace (("%p: waiting for close", ctx)); + WaitForSingleObject (ctx->close_ev, INFINITE); + + CloseHandle (ctx->close_ev); + CloseHandle (ctx->have_data_ev); + CloseHandle (ctx->have_space_ev); + CloseHandle (ctx->thread_hd); + DeleteCriticalSection (&ctx->mutex); + free (ctx); /* Standard free! See comment in create_reader. */ + + return 0; +} + + +static struct reader_context_s * +create_reader (estream_cookie_w32_pollable_t pcookie) +{ + struct reader_context_s *ctx; + SECURITY_ATTRIBUTES sec_attr; + DWORD tid; + + memset (&sec_attr, 0, sizeof sec_attr); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + /* The CTX must be allocated in standard system memory so that we + * won't use any custom allocation handler which may use our lock + * primitives for its implementation. The problem here is that the + * syscall clamp mechanism (e.g. nPth) would be called recursively: + * 1. For example by the caller of _gpgrt_w32_poll and 2. by + * gpgrt_lock_lock on behalf of the the custom allocation and free + * functions. */ + ctx = calloc (1, sizeof *ctx); + if (!ctx) + { + return NULL; + } + + ctx->pcookie = pcookie; + + ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + if (ctx->have_data_ev) + ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL); + if (ctx->have_space_ev) + ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->close_ev) + { + trace (("%p: CreateEvent failed: ec=%d", ctx, (int)GetLastError ())); + if (ctx->have_data_ev) + CloseHandle (ctx->have_data_ev); + if (ctx->have_space_ev) + CloseHandle (ctx->have_space_ev); + if (ctx->close_ev) + CloseHandle (ctx->close_ev); + _gpgrt_free (ctx); + return NULL; + } + + InitializeCriticalSection (&ctx->mutex); + +#ifdef HAVE_W32CE_SYSTEM + ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, reader, ctx, + STACK_SIZE_PARAM_IS_A_RESERVATION, &tid); +#else + ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid); +#endif + + if (!ctx->thread_hd) + { + trace (("%p: CreateThread failed: ec=%d", ctx, (int)GetLastError ())); + DeleteCriticalSection (&ctx->mutex); + if (ctx->have_data_ev) + CloseHandle (ctx->have_data_ev); + if (ctx->have_space_ev) + CloseHandle (ctx->have_space_ev); + if (ctx->close_ev) + CloseHandle (ctx->close_ev); + _gpgrt_free (ctx); + return NULL; + } + else + { +#if 0 + /* We set the priority of the thread higher because we know that + it only runs for a short time. This greatly helps to + increase the performance of the I/O. */ + SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ()); +#endif + } + + return ctx; +} + + +/* Prepare destruction of the reader thread for CTX. Returns 0 if a + call to this function is sufficient and destroy_reader_finish shall + not be called. */ +static void +destroy_reader (struct reader_context_s *ctx) +{ + EnterCriticalSection (&ctx->mutex); + ctx->stop_me = 1; + if (ctx->have_space_ev) + SetEvent (ctx->have_space_ev); + LeaveCriticalSection (&ctx->mutex); + +#ifdef HAVE_W32CE_SYSTEM + /* Scenario: We never create a full pipe, but already started + reading. Then we need to unblock the reader in the pipe driver + to make our reader thread notice that we want it to go away. */ + + if (ctx->file_hd != INVALID_HANDLE_VALUE) + { + if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, + NULL, 0, NULL, 0, NULL, NULL)) + { + trace (("%p: unblock control call failed: ec=%d", + ctx, (int)GetLastError ())); + } + } +#endif + + /* XXX is it feasible to unblock the thread? */ + + /* After setting this event CTX is void. */ + SetEvent (ctx->close_ev); +} + + +/* + * Read function for pollable objects. + */ +static gpgrt_ssize_t +func_w32_pollable_read (void *cookie, void *buffer, size_t count) +{ + estream_cookie_w32_pollable_t pcookie = cookie; + gpgrt_ssize_t nread; + struct reader_context_s *ctx; + + trace (("%p: enter buffer=%p count=%u", cookie, buffer, count)); + + /* FIXME: implement pending check if COUNT==0 */ + + ctx = pcookie->reader; + if (ctx == NULL) + { + pcookie->reader = ctx = create_reader (pcookie); + if (!ctx) + { + _gpg_err_set_errno (EBADF); + nread = -1; + goto leave; + } + trace (("%p: new reader %p", cookie, pcookie->reader)); + } + + if (ctx->eof_shortcut) + { + nread = 0; + goto leave; + } + + EnterCriticalSection (&ctx->mutex); + trace (("%p: readpos: %d, writepos %d", cookie, ctx->readpos, ctx->writepos)); + if (ctx->readpos == ctx->writepos && !ctx->error) + { + /* No data available. */ + int eof = ctx->eof; + + LeaveCriticalSection (&ctx->mutex); + + if (pcookie->modeflags & O_NONBLOCK && ! eof) + { + _gpg_err_set_errno (EAGAIN); + nread = -1; + goto leave; + } + + trace (("%p: waiting for data", cookie)); + WaitForSingleObject (ctx->have_data_ev, INFINITE); + trace (("%p: data available", cookie)); + EnterCriticalSection (&ctx->mutex); + } + + if (ctx->readpos == ctx->writepos || ctx->error) + { + LeaveCriticalSection (&ctx->mutex); + ctx->eof_shortcut = 1; + if (ctx->eof) + return 0; + if (!ctx->error) + { + trace (("%p: EOF but ctx->eof flag not set", cookie)); + nread = 0; + goto leave; + } + _gpg_err_set_errno (ctx->error_code); + return -1; + } + + nread = ctx->readpos < ctx->writepos + ? ctx->writepos - ctx->readpos + : READBUF_SIZE - ctx->readpos; + if (nread > count) + nread = count; + memcpy (buffer, ctx->buffer + ctx->readpos, nread); + ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE; + if (ctx->readpos == ctx->writepos && !ctx->eof) + { + if (!ResetEvent (ctx->have_data_ev)) + { + trace (("%p: ResetEvent failed: ec=%d", + cookie, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + nread = -1; + goto leave; + } + } + if (!SetEvent (ctx->have_space_ev)) + { + trace (("%p: SetEvent (%p) failed: ec=%d", + cookie, ctx->have_space_ev, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + nread = -1; + goto leave; + } + LeaveCriticalSection (&ctx->mutex); + + leave: + trace_errno (nread==-1,("%p: leave nread=%d", cookie, (int)nread)); + return nread; +} + + +/* The writer does use a simple buffering strategy so that we are + informed about write errors as soon as possible (i. e. with the the + next call to the write function. */ +static DWORD CALLBACK +writer (void *arg) +{ + struct writer_context_s *ctx = arg; + ssize_t nwritten; + + trace (("%p: writer starting", ctx)); + + for (;;) + { + EnterCriticalSection (&ctx->mutex); + if (ctx->stop_me && !ctx->nbytes) + { + LeaveCriticalSection (&ctx->mutex); + break; + } + if (!ctx->nbytes) + { + if (!SetEvent (ctx->is_empty)) + trace (("%p: SetEvent failed: ec=%d", ctx, (int)GetLastError ())); + if (!ResetEvent (ctx->have_data)) + trace (("%p: ResetEvent failed: ec=%d", ctx, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + trace (("%p: idle", ctx)); + WaitForSingleObject (ctx->have_data, INFINITE); + trace (("%p: got data to write", ctx)); + EnterCriticalSection (&ctx->mutex); + } + if (ctx->stop_me && !ctx->nbytes) + { + LeaveCriticalSection (&ctx->mutex); + break; + } + LeaveCriticalSection (&ctx->mutex); + + trace (("%p: writing up to %d bytes", ctx, ctx->nbytes)); + + nwritten = ctx->pcookie->next_functions.public.func_write + (ctx->pcookie->next_cookie, ctx->buffer, ctx->nbytes); + trace (("%p: wrote %d bytes", ctx, nwritten)); + if (nwritten < 1) + { + /* XXX */ + if (errno == ERROR_BUSY) + { + /* Probably stop_me is set now. */ + trace (("%p: pipe busy (unblocked?)", ctx)); + continue; + } + + ctx->error_code = errno; + ctx->error = 1; + trace (("%p: write error: ec=%d", ctx, ctx->error_code)); + break; + } + + EnterCriticalSection (&ctx->mutex); + ctx->nbytes -= nwritten; + LeaveCriticalSection (&ctx->mutex); + } + /* Indicate that we have an error. */ + if (!SetEvent (ctx->is_empty)) + trace (("%p: SetEvent failed: ec=%d", ctx, (int)GetLastError ())); + + trace (("%p: waiting for close", ctx)); + WaitForSingleObject (ctx->close_ev, INFINITE); + + if (ctx->nbytes) + trace (("%p: still %d bytes in buffer at close time", ctx, ctx->nbytes)); + + CloseHandle (ctx->close_ev); + CloseHandle (ctx->have_data); + CloseHandle (ctx->is_empty); + CloseHandle (ctx->thread_hd); + DeleteCriticalSection (&ctx->mutex); + trace (("%p: writer is destroyed", ctx)); + free (ctx); /* Standard free! See comment in create_writer. */ + + return 0; +} + + +static struct writer_context_s * +create_writer (estream_cookie_w32_pollable_t pcookie) +{ + struct writer_context_s *ctx; + SECURITY_ATTRIBUTES sec_attr; + DWORD tid; + + memset (&sec_attr, 0, sizeof sec_attr); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + /* See comment at create_reader. */ + ctx = calloc (1, sizeof *ctx); + if (!ctx) + { + return NULL; + } + + ctx->pcookie = pcookie; + + ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + if (ctx->have_data) + ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL); + if (ctx->is_empty) + ctx->close_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + if (!ctx->have_data || !ctx->is_empty || !ctx->close_ev) + { + trace (("%p: CreateEvent failed: ec=%d", ctx, (int)GetLastError ())); + if (ctx->have_data) + CloseHandle (ctx->have_data); + if (ctx->is_empty) + CloseHandle (ctx->is_empty); + if (ctx->close_ev) + CloseHandle (ctx->close_ev); + _gpgrt_free (ctx); + return NULL; + } + + InitializeCriticalSection (&ctx->mutex); + +#ifdef HAVE_W32CE_SYSTEM + ctx->thread_hd = CreateThread (&sec_attr, 64 * 1024, writer, ctx, + STACK_SIZE_PARAM_IS_A_RESERVATION, &tid); +#else + ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid ); +#endif + + if (!ctx->thread_hd) + { + trace (("%p: CreateThread failed: ec=%d", ctx, (int)GetLastError ())); + DeleteCriticalSection (&ctx->mutex); + if (ctx->have_data) + CloseHandle (ctx->have_data); + if (ctx->is_empty) + CloseHandle (ctx->is_empty); + if (ctx->close_ev) + CloseHandle (ctx->close_ev); + _gpgrt_free (ctx); + return NULL; + } + else + { +#if 0 + /* We set the priority of the thread higher because we know + that it only runs for a short time. This greatly helps to + increase the performance of the I/O. */ + SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ()); +#endif + } + + return ctx; +} + + +static void +destroy_writer (struct writer_context_s *ctx) +{ + trace (("%p: enter pollable_destroy_writer", ctx)); + EnterCriticalSection (&ctx->mutex); + trace (("%p: setting stopme", ctx)); + ctx->stop_me = 1; + if (ctx->have_data) + SetEvent (ctx->have_data); + LeaveCriticalSection (&ctx->mutex); + + trace (("%p: waiting for empty", ctx)); + + /* Give the writer a chance to flush the buffer. */ + WaitForSingleObject (ctx->is_empty, INFINITE); + +#ifdef HAVE_W32CE_SYSTEM + /* Scenario: We never create a full pipe, but already started + writing more than the pipe buffer. Then we need to unblock the + writer in the pipe driver to make our writer thread notice that + we want it to go away. */ + + if (!DeviceIoControl (ctx->file_hd, GPGCEDEV_IOCTL_UNBLOCK, + NULL, 0, NULL, 0, NULL, NULL)) + { + trace (("%p: unblock control call failed: ec=%d", + ctx, (int)GetLastError ())); + } +#endif + + /* After setting this event CTX is void. */ + trace (("%p: set close_ev", ctx)); + SetEvent (ctx->close_ev); + trace (("%p: leave pollable_destroy_writer", ctx)); +} + + +/* + * Write function for pollable objects. + */ +static gpgrt_ssize_t +func_w32_pollable_write (void *cookie, const void *buffer, size_t count) +{ + estream_cookie_w32_pollable_t pcookie = cookie; + struct writer_context_s *ctx = pcookie->writer; + int nwritten; + + trace (("%p: enter buffer: %p count: %d", cookie, buffer, count)); + if (count == 0) + { + nwritten = 0; + goto leave; + } + + if (ctx == NULL) + { + pcookie->writer = ctx = create_writer (pcookie); + if (!ctx) + { + nwritten = -1; + goto leave; + } + trace (("%p: new writer %p", cookie, pcookie->writer)); + } + + EnterCriticalSection (&ctx->mutex); + trace (("%p: buffer: %p, count: %d, nbytes: %d", + cookie, buffer, count, ctx->nbytes)); + if (!ctx->error && ctx->nbytes) + { + /* Bytes are pending for send. */ + + /* Reset the is_empty event. Better safe than sorry. */ + if (!ResetEvent (ctx->is_empty)) + { + trace (("%p: ResetEvent failed: ec=%d", + cookie, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + nwritten = -1; + goto leave; + } + LeaveCriticalSection (&ctx->mutex); + + if (pcookie->modeflags & O_NONBLOCK) + { + trace (("%p: would block", cookie)); + _gpg_err_set_errno (EAGAIN); + nwritten = -1; + goto leave; + } + + trace (("%p: waiting for empty buffer", cookie)); + WaitForSingleObject (ctx->is_empty, INFINITE); + trace (("%p: buffer is empty", cookie)); + EnterCriticalSection (&ctx->mutex); + } + + if (ctx->error) + { + LeaveCriticalSection (&ctx->mutex); + if (ctx->error_code == ERROR_NO_DATA) + _gpg_err_set_errno (EPIPE); + else + _gpg_err_set_errno (EIO); + nwritten = -1; + goto leave; + } + + /* If no error occurred, the number of bytes in the buffer must be + zero. */ + gpgrt_assert (!ctx->nbytes); + + if (count > WRITEBUF_SIZE) + count = WRITEBUF_SIZE; + memcpy (ctx->buffer, buffer, count); + ctx->nbytes = count; + + /* We have to reset the is_empty event early, because it is also + used by the select() implementation to probe the channel. */ + if (!ResetEvent (ctx->is_empty)) + { + trace (("%p: ResetEvent failed: ec=%d", cookie, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + nwritten = -1; + goto leave; + } + if (!SetEvent (ctx->have_data)) + { + trace (("%p: SetEvent failed: ec=%d", cookie, (int)GetLastError ())); + LeaveCriticalSection (&ctx->mutex); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + nwritten = -1; + goto leave; + } + LeaveCriticalSection (&ctx->mutex); + + nwritten = count; + + leave: + trace_errno (nwritten==-1,("%p: leave nwritten=%d", cookie, nwritten)); + return nwritten; +} + + +/* This is the core of _gpgrt_poll. The caller needs to make sure that + * the syscall clamp has been engaged. */ +int +_gpgrt_w32_poll (gpgrt_poll_t *fds, size_t nfds, int timeout) +{ + HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; + int waitidx[MAXIMUM_WAIT_OBJECTS]; +#ifdef ENABLE_TRACING + char waitinfo[MAXIMUM_WAIT_OBJECTS]; +#endif + unsigned int code; + int nwait; + int i; + int any; + int count; + +#if 0 + restart: +#endif + + any = 0; + nwait = 0; + count = 0; + for (i = 0; i < nfds; i++) + { + struct estream_cookie_w32_pollable *pcookie; + + if (fds[i].ignore) + continue; + + if (fds[i].stream->intern->kind != BACKEND_W32_POLLABLE) + { + /* This stream does not support polling. */ + fds[i].got_err = 1; + continue; + } + + pcookie = fds[i].stream->intern->cookie; + + if (fds[i].want_read || fds[i].want_write) + { + /* XXX: What if one wants read and write, is that supported? */ + if (fds[i].want_read) + { + struct reader_context_s *ctx = pcookie->reader; + if (ctx == NULL) + { + pcookie->reader = ctx = create_reader (pcookie); + if (!ctx) + { + /* FIXME: Is the error code appropriate? */ + _gpg_err_set_errno (EBADF); + return -1; + } + trace (("%p: new reader %p", pcookie, pcookie->reader)); + } + trace (("%p: using reader %p", pcookie, pcookie->reader)); + + if (nwait >= DIM (waitbuf)) + { + trace (("oops: too many objects for WFMO")); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + return -1; + } + waitidx[nwait] = i; +#ifdef ENABLE_TRACING + waitinfo[nwait] = 'r'; +#endif /*ENABLE_TRACING*/ + waitbuf[nwait++] = ctx->have_data_ev; + any = 1; + } + else if (fds[i].want_write) + { + struct writer_context_s *ctx = pcookie->writer; + if (ctx == NULL) + { + pcookie->writer = ctx = create_writer (pcookie); + if (!ctx) + { + trace (("oops: create writer failed")); + /* FIXME: Is the error code appropriate? */ + _gpg_err_set_errno (EBADF); + return -1; + } + trace (("%p: new writer %p", pcookie, pcookie->writer)); + } + trace (("%p: using writer %p", pcookie, pcookie->writer)); + + if (nwait >= DIM (waitbuf)) + { + trace (("oops: Too many objects for WFMO")); + /* FIXME: Should translate the error code. */ + _gpg_err_set_errno (EIO); + return -1; + } + waitidx[nwait] = i; +#ifdef ENABLE_TRACING + waitinfo[nwait] = 'w'; +#endif /*ENABLE_TRACING*/ + waitbuf[nwait++] = ctx->is_empty; + any = 1; + } + } + } +#ifdef ENABLE_TRACING + trace_start (("poll on [ ")); + for (i = 0; i < nwait; i++) + trace_append (("%d/%c ", waitidx[i], waitinfo[i])); + trace_finish (("]")); +#endif /*ENABLE_TRACING*/ + + if (!any) + { + /* WFMO needs at least one object, thus we use use sleep here. + * INFINITE wait does not make any sense in this case, so we + * error out. */ + if (timeout == -1) + { + _gpg_err_set_errno (EINVAL); + return -1; + } + if (timeout) + Sleep (timeout); + code = WAIT_TIMEOUT; + } + else + code = WaitForMultipleObjects (nwait, waitbuf, 0, + timeout == -1 ? INFINITE : timeout); + + if (code < WAIT_OBJECT_0 + nwait) + { + /* This WFMO is a really silly function: It does return either + the index of the signaled object or if 2 objects have been + signalled at the same time, the index of the object with the + lowest object is returned - so and how do we find out how + many objects have been signaled???. The only solution I can + imagine is to test each object starting with the returned + index individually - how dull. */ + any = 0; + for (i = code - WAIT_OBJECT_0; i < nwait; i++) + { + if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) + { + gpgrt_assert (waitidx[i] >=0 && waitidx[i] < nfds); + /* XXX: What if one wants read and write, is that + supported? */ + if (fds[waitidx[i]].want_read) + fds[waitidx[i]].got_read = 1; + else if (fds[waitidx[i]].want_write) + fds[waitidx[i]].got_write = 1; + any = 1; + count++; + } + } + if (!any) + { + trace (("no signaled objects found after WFMO")); + count = -1; + } + } + else if (code == WAIT_TIMEOUT) + trace (("WFMO timed out")); + else if (code == WAIT_FAILED) + { + trace (("WFMO failed: ec=%d", (int)GetLastError ())); +#if 0 + if (GetLastError () == ERROR_INVALID_HANDLE) + { + int k; + int j = handle_to_fd (waitbuf[i]); + + trace (("WFMO invalid handle %d removed", j)); + for (k = 0 ; k < nfds; k++) + { + if (fds[k].fd == j) + { + fds[k].want_read = fds[k].want_write = 0; + goto restart; + } + } + trace ((" oops, or not???")); + } +#endif + count = -1; + } + else + { + trace (("WFMO returned %u", code)); + count = -1; + } + + if (count > 0) + { + trace_start (("poll OK [ ")); + for (i = 0; i < nfds; i++) + { + if (fds[i].ignore) + continue; + if (fds[i].got_read || fds[i].got_write) + trace_append (("%c%d ", fds[i].want_read ? 'r' : 'w', i)); + } + trace_finish (("]")); + } + + if (count < 0) + { + /* FIXME: Should determine a proper error code. */ + _gpg_err_set_errno (EIO); + } + + return count; +} + + + +/* + * Implementation of pollable I/O on Windows. + */ + +/* + * Constructor for pollable objects. + */ +int +_gpgrt_w32_pollable_create (void *_GPGRT__RESTRICT *_GPGRT__RESTRICT cookie, + unsigned int modeflags, + struct cookie_io_functions_s next_functions, + void *next_cookie) +{ + estream_cookie_w32_pollable_t pcookie; + int err; + + pcookie = _gpgrt_malloc (sizeof *pcookie); + if (!pcookie) + err = -1; + else + { + pcookie->modeflags = modeflags; + pcookie->next_functions = next_functions; + pcookie->next_cookie = next_cookie; + pcookie->reader = NULL; + pcookie->writer = NULL; + *cookie = pcookie; + err = 0; + } + + trace_errno (err,("cookie=%p", *cookie)); + return err; +} + + +/* + * Seek function for pollable objects. + */ +static int +func_w32_pollable_seek (void *cookie, gpgrt_off_t *offset, int whence) +{ + estream_cookie_w32_pollable_t pcookie = cookie; + (void) pcookie; + (void) offset; + (void) whence; + /* XXX */ + _gpg_err_set_errno (EOPNOTSUPP); + return -1; +} + + +/* + * The IOCTL function for pollable objects. + */ +static int +func_w32_pollable_ioctl (void *cookie, int cmd, void *ptr, size_t *len) +{ + estream_cookie_w32_pollable_t pcookie = cookie; + cookie_ioctl_function_t func_ioctl = pcookie->next_functions.func_ioctl; + + if (cmd == COOKIE_IOCTL_NONBLOCK) + { + if (ptr) + pcookie->modeflags |= O_NONBLOCK; + else + pcookie->modeflags &= ~O_NONBLOCK; + return 0; + } + + if (func_ioctl) + return func_ioctl (pcookie->next_cookie, cmd, ptr, len); + + _gpg_err_set_errno (EOPNOTSUPP); + return -1; +} + + +/* + * The destroy function for pollable objects. + */ +static int +func_w32_pollable_destroy (void *cookie) +{ + estream_cookie_w32_pollable_t pcookie = cookie; + + if (cookie) + { + if (pcookie->reader) + destroy_reader (pcookie->reader); + if (pcookie->writer) + destroy_writer (pcookie->writer); + pcookie->next_functions.public.func_close (pcookie->next_cookie); + _gpgrt_free (pcookie); + } + return 0; +} + +/* + * Access object for the pollable functions. + */ +struct cookie_io_functions_s _gpgrt_functions_w32_pollable = + { + { + func_w32_pollable_read, + func_w32_pollable_write, + func_w32_pollable_seek, + func_w32_pollable_destroy, + }, + func_w32_pollable_ioctl, + }; diff --git a/comm/third_party/libgpg-error/src/w32-gettext.c b/comm/third_party/libgpg-error/src/w32-gettext.c new file mode 100644 index 0000000000..7c4c9b058d --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-gettext.c @@ -0,0 +1,2016 @@ +/* w32-gettext.h - A simple gettext implementation for Windows targets. + Copyright (C) 1995, 1996, 1997, 1999, 2005, 2007, + 2008, 2010 Free Software Foundation, Inc. + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif +#if !defined (_WIN32) && !defined (__CYGWIN32__) +# error This module may only be build for Windows or Cygwin32 +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include +#include +#include + +#ifdef JNLIB_IN_JNLIB +#include "libjnlib-config.h" +#endif + +#ifndef jnlib_malloc +# define jnlib_malloc(a) malloc ((a)) +# define jnlib_calloc(a,b) calloc ((a), (b)) +# define jnlib_free(a) free ((a)) +# define jnlib_xstrdup(a) not_used +#endif /*!jnlib_malloc*/ + +#include "init.h" +#include "gpgrt-int.h" +#include "protos.h" + +/* Override values initialized by gpgrt_w32_override_locale. If NAME + * is not the empty string LANGID will be used. */ +static struct +{ + unsigned short active; /* If not zero this override is active. */ + unsigned short langid; + char name[28]; +} override_locale; + + + + +/* localname.c from gettext BEGIN. */ + +/* Determine the current selected locale. + Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Written by Ulrich Drepper , 1995. */ +/* Win32 code written by Tor Lillqvist . */ +/* Renamed _nl_locale_name, removed unused args, removed include files, + non-W32 code and changed comments . */ + +/* Mingw headers don't have latest language and sublanguage codes. */ +#ifndef LANG_AFRIKAANS +#define LANG_AFRIKAANS 0x36 +#endif +#ifndef LANG_ALBANIAN +#define LANG_ALBANIAN 0x1c +#endif +#ifndef LANG_AMHARIC +#define LANG_AMHARIC 0x5e +#endif +#ifndef LANG_ARABIC +#define LANG_ARABIC 0x01 +#endif +#ifndef LANG_ARMENIAN +#define LANG_ARMENIAN 0x2b +#endif +#ifndef LANG_ASSAMESE +#define LANG_ASSAMESE 0x4d +#endif +#ifndef LANG_AZERI +#define LANG_AZERI 0x2c +#endif +#ifndef LANG_BASQUE +#define LANG_BASQUE 0x2d +#endif +#ifndef LANG_BELARUSIAN +#define LANG_BELARUSIAN 0x23 +#endif +#ifndef LANG_BENGALI +#define LANG_BENGALI 0x45 +#endif +#ifndef LANG_BURMESE +#define LANG_BURMESE 0x55 +#endif +#ifndef LANG_CAMBODIAN +#define LANG_CAMBODIAN 0x53 +#endif +#ifndef LANG_CATALAN +#define LANG_CATALAN 0x03 +#endif +#ifndef LANG_CHEROKEE +#define LANG_CHEROKEE 0x5c +#endif +#ifndef LANG_DIVEHI +#define LANG_DIVEHI 0x65 +#endif +#ifndef LANG_EDO +#define LANG_EDO 0x66 +#endif +#ifndef LANG_ESTONIAN +#define LANG_ESTONIAN 0x25 +#endif +#ifndef LANG_FAEROESE +#define LANG_FAEROESE 0x38 +#endif +#ifndef LANG_FARSI +#define LANG_FARSI 0x29 +#endif +#ifndef LANG_FRISIAN +#define LANG_FRISIAN 0x62 +#endif +#ifndef LANG_FULFULDE +#define LANG_FULFULDE 0x67 +#endif +#ifndef LANG_GAELIC +#define LANG_GAELIC 0x3c +#endif +#ifndef LANG_GALICIAN +#define LANG_GALICIAN 0x56 +#endif +#ifndef LANG_GEORGIAN +#define LANG_GEORGIAN 0x37 +#endif +#ifndef LANG_GUARANI +#define LANG_GUARANI 0x74 +#endif +#ifndef LANG_GUJARATI +#define LANG_GUJARATI 0x47 +#endif +#ifndef LANG_HAUSA +#define LANG_HAUSA 0x68 +#endif +#ifndef LANG_HAWAIIAN +#define LANG_HAWAIIAN 0x75 +#endif +#ifndef LANG_HEBREW +#define LANG_HEBREW 0x0d +#endif +#ifndef LANG_HINDI +#define LANG_HINDI 0x39 +#endif +#ifndef LANG_IBIBIO +#define LANG_IBIBIO 0x69 +#endif +#ifndef LANG_IGBO +#define LANG_IGBO 0x70 +#endif +#ifndef LANG_INDONESIAN +#define LANG_INDONESIAN 0x21 +#endif +#ifndef LANG_INUKTITUT +#define LANG_INUKTITUT 0x5d +#endif +#ifndef LANG_KANNADA +#define LANG_KANNADA 0x4b +#endif +#ifndef LANG_KANURI +#define LANG_KANURI 0x71 +#endif +#ifndef LANG_KASHMIRI +#define LANG_KASHMIRI 0x60 +#endif +#ifndef LANG_KAZAK +#define LANG_KAZAK 0x3f +#endif +#ifndef LANG_KONKANI +#define LANG_KONKANI 0x57 +#endif +#ifndef LANG_KYRGYZ +#define LANG_KYRGYZ 0x40 +#endif +#ifndef LANG_LAO +#define LANG_LAO 0x54 +#endif +#ifndef LANG_LATIN +#define LANG_LATIN 0x76 +#endif +#ifndef LANG_LATVIAN +#define LANG_LATVIAN 0x26 +#endif +#ifndef LANG_LITHUANIAN +#define LANG_LITHUANIAN 0x27 +#endif +#ifndef LANG_MACEDONIAN +#define LANG_MACEDONIAN 0x2f +#endif +#ifndef LANG_MALAY +#define LANG_MALAY 0x3e +#endif +#ifndef LANG_MALAYALAM +#define LANG_MALAYALAM 0x4c +#endif +#ifndef LANG_MALTESE +#define LANG_MALTESE 0x3a +#endif +#ifndef LANG_MANIPURI +#define LANG_MANIPURI 0x58 +#endif +#ifndef LANG_MARATHI +#define LANG_MARATHI 0x4e +#endif +#ifndef LANG_MONGOLIAN +#define LANG_MONGOLIAN 0x50 +#endif +#ifndef LANG_NEPALI +#define LANG_NEPALI 0x61 +#endif +#ifndef LANG_ORIYA +#define LANG_ORIYA 0x48 +#endif +#ifndef LANG_OROMO +#define LANG_OROMO 0x72 +#endif +#ifndef LANG_PAPIAMENTU +#define LANG_PAPIAMENTU 0x79 +#endif +#ifndef LANG_PASHTO +#define LANG_PASHTO 0x63 +#endif +#ifndef LANG_PUNJABI +#define LANG_PUNJABI 0x46 +#endif +#ifndef LANG_RHAETO_ROMANCE +#define LANG_RHAETO_ROMANCE 0x17 +#endif +#ifndef LANG_SAAMI +#define LANG_SAAMI 0x3b +#endif +#ifndef LANG_SANSKRIT +#define LANG_SANSKRIT 0x4f +#endif +#ifndef LANG_SERBIAN +#define LANG_SERBIAN 0x1a +#endif +#ifndef LANG_SINDHI +#define LANG_SINDHI 0x59 +#endif +#ifndef LANG_SINHALESE +#define LANG_SINHALESE 0x5b +#endif +#ifndef LANG_SLOVAK +#define LANG_SLOVAK 0x1b +#endif +#ifndef LANG_SOMALI +#define LANG_SOMALI 0x77 +#endif +#ifndef LANG_SORBIAN +#define LANG_SORBIAN 0x2e +#endif +#ifndef LANG_SUTU +#define LANG_SUTU 0x30 +#endif +#ifndef LANG_SWAHILI +#define LANG_SWAHILI 0x41 +#endif +#ifndef LANG_SYRIAC +#define LANG_SYRIAC 0x5a +#endif +#ifndef LANG_TAGALOG +#define LANG_TAGALOG 0x64 +#endif +#ifndef LANG_TAJIK +#define LANG_TAJIK 0x28 +#endif +#ifndef LANG_TAMAZIGHT +#define LANG_TAMAZIGHT 0x5f +#endif +#ifndef LANG_TAMIL +#define LANG_TAMIL 0x49 +#endif +#ifndef LANG_TATAR +#define LANG_TATAR 0x44 +#endif +#ifndef LANG_TELUGU +#define LANG_TELUGU 0x4a +#endif +#ifndef LANG_THAI +#define LANG_THAI 0x1e +#endif +#ifndef LANG_TIBETAN +#define LANG_TIBETAN 0x51 +#endif +#ifndef LANG_TIGRINYA +#define LANG_TIGRINYA 0x73 +#endif +#ifndef LANG_TSONGA +#define LANG_TSONGA 0x31 +#endif +#ifndef LANG_TSWANA +#define LANG_TSWANA 0x32 +#endif +#ifndef LANG_TURKMEN +#define LANG_TURKMEN 0x42 +#endif +#ifndef LANG_UKRAINIAN +#define LANG_UKRAINIAN 0x22 +#endif +#ifndef LANG_URDU +#define LANG_URDU 0x20 +#endif +#ifndef LANG_UZBEK +#define LANG_UZBEK 0x43 +#endif +#ifndef LANG_VENDA +#define LANG_VENDA 0x33 +#endif +#ifndef LANG_VIETNAMESE +#define LANG_VIETNAMESE 0x2a +#endif +#ifndef LANG_WELSH +#define LANG_WELSH 0x52 +#endif +#ifndef LANG_XHOSA +#define LANG_XHOSA 0x34 +#endif +#ifndef LANG_YI +#define LANG_YI 0x78 +#endif +#ifndef LANG_YIDDISH +#define LANG_YIDDISH 0x3d +#endif +#ifndef LANG_YORUBA +#define LANG_YORUBA 0x6a +#endif +#ifndef LANG_ZULU +#define LANG_ZULU 0x35 +#endif +#ifndef SUBLANG_ARABIC_SAUDI_ARABIA +#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 +#endif +#ifndef SUBLANG_ARABIC_IRAQ +#define SUBLANG_ARABIC_IRAQ 0x02 +#endif +#ifndef SUBLANG_ARABIC_EGYPT +#define SUBLANG_ARABIC_EGYPT 0x03 +#endif +#ifndef SUBLANG_ARABIC_LIBYA +#define SUBLANG_ARABIC_LIBYA 0x04 +#endif +#ifndef SUBLANG_ARABIC_ALGERIA +#define SUBLANG_ARABIC_ALGERIA 0x05 +#endif +#ifndef SUBLANG_ARABIC_MOROCCO +#define SUBLANG_ARABIC_MOROCCO 0x06 +#endif +#ifndef SUBLANG_ARABIC_TUNISIA +#define SUBLANG_ARABIC_TUNISIA 0x07 +#endif +#ifndef SUBLANG_ARABIC_OMAN +#define SUBLANG_ARABIC_OMAN 0x08 +#endif +#ifndef SUBLANG_ARABIC_YEMEN +#define SUBLANG_ARABIC_YEMEN 0x09 +#endif +#ifndef SUBLANG_ARABIC_SYRIA +#define SUBLANG_ARABIC_SYRIA 0x0a +#endif +#ifndef SUBLANG_ARABIC_JORDAN +#define SUBLANG_ARABIC_JORDAN 0x0b +#endif +#ifndef SUBLANG_ARABIC_LEBANON +#define SUBLANG_ARABIC_LEBANON 0x0c +#endif +#ifndef SUBLANG_ARABIC_KUWAIT +#define SUBLANG_ARABIC_KUWAIT 0x0d +#endif +#ifndef SUBLANG_ARABIC_UAE +#define SUBLANG_ARABIC_UAE 0x0e +#endif +#ifndef SUBLANG_ARABIC_BAHRAIN +#define SUBLANG_ARABIC_BAHRAIN 0x0f +#endif +#ifndef SUBLANG_ARABIC_QATAR +#define SUBLANG_ARABIC_QATAR 0x10 +#endif +#ifndef SUBLANG_AZERI_LATIN +#define SUBLANG_AZERI_LATIN 0x01 +#endif +#ifndef SUBLANG_AZERI_CYRILLIC +#define SUBLANG_AZERI_CYRILLIC 0x02 +#endif +#ifndef SUBLANG_BENGALI_INDIA +#define SUBLANG_BENGALI_INDIA 0x01 +#endif +#ifndef SUBLANG_BENGALI_BANGLADESH +#define SUBLANG_BENGALI_BANGLADESH 0x02 +#endif +#ifndef SUBLANG_CHINESE_MACAU +#define SUBLANG_CHINESE_MACAU 0x05 +#endif +#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA +#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 +#endif +#ifndef SUBLANG_ENGLISH_JAMAICA +#define SUBLANG_ENGLISH_JAMAICA 0x08 +#endif +#ifndef SUBLANG_ENGLISH_CARIBBEAN +#define SUBLANG_ENGLISH_CARIBBEAN 0x09 +#endif +#ifndef SUBLANG_ENGLISH_BELIZE +#define SUBLANG_ENGLISH_BELIZE 0x0a +#endif +#ifndef SUBLANG_ENGLISH_TRINIDAD +#define SUBLANG_ENGLISH_TRINIDAD 0x0b +#endif +#ifndef SUBLANG_ENGLISH_ZIMBABWE +#define SUBLANG_ENGLISH_ZIMBABWE 0x0c +#endif +#ifndef SUBLANG_ENGLISH_PHILIPPINES +#define SUBLANG_ENGLISH_PHILIPPINES 0x0d +#endif +#ifndef SUBLANG_ENGLISH_INDONESIA +#define SUBLANG_ENGLISH_INDONESIA 0x0e +#endif +#ifndef SUBLANG_ENGLISH_HONGKONG +#define SUBLANG_ENGLISH_HONGKONG 0x0f +#endif +#ifndef SUBLANG_ENGLISH_INDIA +#define SUBLANG_ENGLISH_INDIA 0x10 +#endif +#ifndef SUBLANG_ENGLISH_MALAYSIA +#define SUBLANG_ENGLISH_MALAYSIA 0x11 +#endif +#ifndef SUBLANG_ENGLISH_SINGAPORE +#define SUBLANG_ENGLISH_SINGAPORE 0x12 +#endif +#ifndef SUBLANG_FRENCH_LUXEMBOURG +#define SUBLANG_FRENCH_LUXEMBOURG 0x05 +#endif +#ifndef SUBLANG_FRENCH_MONACO +#define SUBLANG_FRENCH_MONACO 0x06 +#endif +#ifndef SUBLANG_FRENCH_WESTINDIES +#define SUBLANG_FRENCH_WESTINDIES 0x07 +#endif +#ifndef SUBLANG_FRENCH_REUNION +#define SUBLANG_FRENCH_REUNION 0x08 +#endif +#ifndef SUBLANG_FRENCH_CONGO +#define SUBLANG_FRENCH_CONGO 0x09 +#endif +#ifndef SUBLANG_FRENCH_SENEGAL +#define SUBLANG_FRENCH_SENEGAL 0x0a +#endif +#ifndef SUBLANG_FRENCH_CAMEROON +#define SUBLANG_FRENCH_CAMEROON 0x0b +#endif +#ifndef SUBLANG_FRENCH_COTEDIVOIRE +#define SUBLANG_FRENCH_COTEDIVOIRE 0x0c +#endif +#ifndef SUBLANG_FRENCH_MALI +#define SUBLANG_FRENCH_MALI 0x0d +#endif +#ifndef SUBLANG_FRENCH_MOROCCO +#define SUBLANG_FRENCH_MOROCCO 0x0e +#endif +#ifndef SUBLANG_FRENCH_HAITI +#define SUBLANG_FRENCH_HAITI 0x0f +#endif +#ifndef SUBLANG_GERMAN_LUXEMBOURG +#define SUBLANG_GERMAN_LUXEMBOURG 0x04 +#endif +#ifndef SUBLANG_GERMAN_LIECHTENSTEIN +#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 +#endif +#ifndef SUBLANG_KASHMIRI_INDIA +#define SUBLANG_KASHMIRI_INDIA 0x02 +#endif +#ifndef SUBLANG_MALAY_MALAYSIA +#define SUBLANG_MALAY_MALAYSIA 0x01 +#endif +#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 +#endif +#ifndef SUBLANG_NEPALI_INDIA +#define SUBLANG_NEPALI_INDIA 0x02 +#endif +#ifndef SUBLANG_PUNJABI_INDIA +#define SUBLANG_PUNJABI_INDIA 0x01 +#endif +#ifndef SUBLANG_ROMANIAN_ROMANIA +#define SUBLANG_ROMANIAN_ROMANIA 0x01 +#endif +#ifndef SUBLANG_SERBIAN_LATIN +#define SUBLANG_SERBIAN_LATIN 0x02 +#endif +#ifndef SUBLANG_SERBIAN_CYRILLIC +#define SUBLANG_SERBIAN_CYRILLIC 0x03 +#endif +#ifndef SUBLANG_SINDHI_INDIA +#define SUBLANG_SINDHI_INDIA 0x00 +#endif +#ifndef SUBLANG_SINDHI_PAKISTAN +#define SUBLANG_SINDHI_PAKISTAN 0x01 +#endif +#ifndef SUBLANG_SPANISH_GUATEMALA +#define SUBLANG_SPANISH_GUATEMALA 0x04 +#endif +#ifndef SUBLANG_SPANISH_COSTA_RICA +#define SUBLANG_SPANISH_COSTA_RICA 0x05 +#endif +#ifndef SUBLANG_SPANISH_PANAMA +#define SUBLANG_SPANISH_PANAMA 0x06 +#endif +#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 +#endif +#ifndef SUBLANG_SPANISH_VENEZUELA +#define SUBLANG_SPANISH_VENEZUELA 0x08 +#endif +#ifndef SUBLANG_SPANISH_COLOMBIA +#define SUBLANG_SPANISH_COLOMBIA 0x09 +#endif +#ifndef SUBLANG_SPANISH_PERU +#define SUBLANG_SPANISH_PERU 0x0a +#endif +#ifndef SUBLANG_SPANISH_ARGENTINA +#define SUBLANG_SPANISH_ARGENTINA 0x0b +#endif +#ifndef SUBLANG_SPANISH_ECUADOR +#define SUBLANG_SPANISH_ECUADOR 0x0c +#endif +#ifndef SUBLANG_SPANISH_CHILE +#define SUBLANG_SPANISH_CHILE 0x0d +#endif +#ifndef SUBLANG_SPANISH_URUGUAY +#define SUBLANG_SPANISH_URUGUAY 0x0e +#endif +#ifndef SUBLANG_SPANISH_PARAGUAY +#define SUBLANG_SPANISH_PARAGUAY 0x0f +#endif +#ifndef SUBLANG_SPANISH_BOLIVIA +#define SUBLANG_SPANISH_BOLIVIA 0x10 +#endif +#ifndef SUBLANG_SPANISH_EL_SALVADOR +#define SUBLANG_SPANISH_EL_SALVADOR 0x11 +#endif +#ifndef SUBLANG_SPANISH_HONDURAS +#define SUBLANG_SPANISH_HONDURAS 0x12 +#endif +#ifndef SUBLANG_SPANISH_NICARAGUA +#define SUBLANG_SPANISH_NICARAGUA 0x13 +#endif +#ifndef SUBLANG_SPANISH_PUERTO_RICO +#define SUBLANG_SPANISH_PUERTO_RICO 0x14 +#endif +#ifndef SUBLANG_SWEDISH_FINLAND +#define SUBLANG_SWEDISH_FINLAND 0x02 +#endif +#ifndef SUBLANG_TAMAZIGHT_ARABIC +#define SUBLANG_TAMAZIGHT_ARABIC 0x01 +#endif +#ifndef SUBLANG_TAMAZIGHT_LATIN +#define SUBLANG_TAMAZIGHT_LATIN 0x02 +#endif +#ifndef SUBLANG_TIGRINYA_ETHIOPIA +#define SUBLANG_TIGRINYA_ETHIOPIA 0x00 +#endif +#ifndef SUBLANG_TIGRINYA_ERITREA +#define SUBLANG_TIGRINYA_ERITREA 0x01 +#endif +#ifndef SUBLANG_URDU_PAKISTAN +#define SUBLANG_URDU_PAKISTAN 0x01 +#endif +#ifndef SUBLANG_URDU_INDIA +#define SUBLANG_URDU_INDIA 0x02 +#endif +#ifndef SUBLANG_UZBEK_LATIN +#define SUBLANG_UZBEK_LATIN 0x01 +#endif +#ifndef SUBLANG_UZBEK_CYRILLIC +#define SUBLANG_UZBEK_CYRILLIC 0x02 +#endif + +/* Return an XPG style locale name + language[_territory[.codeset]][@modifier]. + Don't even bother determining the codeset; it's not useful in this + context, because message catalogs are not specific to a single + codeset. The result must not be freed; it is statically + allocated. */ +static const char * +my_nl_locale_name (const char *categoryname) +{ + const char *retval; + LANGID langid; + int primary, sub; + + if (override_locale.active) + { + if (*override_locale.name) + return override_locale.name; + langid = override_locale.langid; + } + else + { + LCID lcid; + + /* Let the user override the system settings through environment + * variables, as on POSIX systems. */ + retval = getenv ("LC_ALL"); + if (retval != NULL && retval[0] != '\0') + return retval; + retval = getenv (categoryname); + if (retval != NULL && retval[0] != '\0') + return retval; + retval = getenv ("LANG"); + if (retval != NULL && retval[0] != '\0') + return retval; + + /* Use native Win32 API locale ID. */ + lcid = GetThreadLocale (); + /* Strip off the sorting rules, keep only the language part. */ + langid = LANGIDFROMLCID (lcid); + } + + /* Split into language and territory part. */ + primary = PRIMARYLANGID (langid); + sub = SUBLANGID (langid); + + /* Dispatch on language. + For details about languages, see https://www.ethnologue.com/ . */ + switch (primary) + { + case LANG_AFRIKAANS: return "af_ZA"; + case LANG_ALBANIAN: return "sq_AL"; + case LANG_AMHARIC: return "am_ET"; + case LANG_ARABIC: + switch (sub) + { + case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA"; + case SUBLANG_ARABIC_IRAQ: return "ar_IQ"; + case SUBLANG_ARABIC_EGYPT: return "ar_EG"; + case SUBLANG_ARABIC_LIBYA: return "ar_LY"; + case SUBLANG_ARABIC_ALGERIA: return "ar_DZ"; + case SUBLANG_ARABIC_MOROCCO: return "ar_MA"; + case SUBLANG_ARABIC_TUNISIA: return "ar_TN"; + case SUBLANG_ARABIC_OMAN: return "ar_OM"; + case SUBLANG_ARABIC_YEMEN: return "ar_YE"; + case SUBLANG_ARABIC_SYRIA: return "ar_SY"; + case SUBLANG_ARABIC_JORDAN: return "ar_JO"; + case SUBLANG_ARABIC_LEBANON: return "ar_LB"; + case SUBLANG_ARABIC_KUWAIT: return "ar_KW"; + case SUBLANG_ARABIC_UAE: return "ar_AE"; + case SUBLANG_ARABIC_BAHRAIN: return "ar_BH"; + case SUBLANG_ARABIC_QATAR: return "ar_QA"; + } + return "ar"; + case LANG_ARMENIAN: return "hy_AM"; + case LANG_ASSAMESE: return "as_IN"; + case LANG_AZERI: + switch (sub) + { + /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */ + case SUBLANG_AZERI_LATIN: return "az_AZ@latin"; + case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic"; + } + return "az"; + case LANG_BASQUE: + return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */ + case LANG_BELARUSIAN: return "be_BY"; + case LANG_BENGALI: + switch (sub) + { + case SUBLANG_BENGALI_INDIA: return "bn_IN"; + case SUBLANG_BENGALI_BANGLADESH: return "bn_BD"; + } + return "bn"; + case LANG_BULGARIAN: return "bg_BG"; + case LANG_BURMESE: return "my_MM"; + case LANG_CAMBODIAN: return "km_KH"; + case LANG_CATALAN: return "ca_ES"; + case LANG_CHEROKEE: return "chr_US"; + case LANG_CHINESE: + switch (sub) + { + case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW"; + case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN"; + case SUBLANG_CHINESE_HONGKONG: return "zh_HK"; + case SUBLANG_CHINESE_SINGAPORE: return "zh_SG"; + case SUBLANG_CHINESE_MACAU: return "zh_MO"; + } + return "zh"; + case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN + * What used to be called Serbo-Croatian + * should really now be two separate + * languages because of political reasons. + * (Says tml, who knows nothing about Serbian + * or Croatian.) + * (I can feel those flames coming already.) + */ + switch (sub) + { + case SUBLANG_DEFAULT: return "hr_HR"; + case SUBLANG_SERBIAN_LATIN: return "sr_CS"; + case SUBLANG_SERBIAN_CYRILLIC: return "sr_CS@cyrillic"; + } + return "hr"; + case LANG_CZECH: return "cs_CZ"; + case LANG_DANISH: return "da_DK"; + case LANG_DIVEHI: return "div_MV"; + case LANG_DUTCH: + switch (sub) + { + case SUBLANG_DUTCH: return "nl_NL"; + case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE"; + } + return "nl"; + case LANG_EDO: return "bin_NG"; + case LANG_ENGLISH: + switch (sub) + { + /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought + * English was the language spoken in England. + * Oh well. + */ + case SUBLANG_ENGLISH_US: return "en_US"; + case SUBLANG_ENGLISH_UK: return "en_GB"; + case SUBLANG_ENGLISH_AUS: return "en_AU"; + case SUBLANG_ENGLISH_CAN: return "en_CA"; + case SUBLANG_ENGLISH_NZ: return "en_NZ"; + case SUBLANG_ENGLISH_EIRE: return "en_IE"; + case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA"; + case SUBLANG_ENGLISH_JAMAICA: return "en_JM"; + case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */ + case SUBLANG_ENGLISH_BELIZE: return "en_BZ"; + case SUBLANG_ENGLISH_TRINIDAD: return "en_TT"; + case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW"; + case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH"; + case SUBLANG_ENGLISH_INDONESIA: return "en_ID"; + case SUBLANG_ENGLISH_HONGKONG: return "en_HK"; + case SUBLANG_ENGLISH_INDIA: return "en_IN"; + case SUBLANG_ENGLISH_MALAYSIA: return "en_MY"; + case SUBLANG_ENGLISH_SINGAPORE: return "en_SG"; + } + return "en"; + case LANG_ESTONIAN: return "et_EE"; + case LANG_FAEROESE: return "fo_FO"; + case LANG_FARSI: return "fa_IR"; + case LANG_FINNISH: return "fi_FI"; + case LANG_FRENCH: + switch (sub) + { + case SUBLANG_FRENCH: return "fr_FR"; + case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE"; + case SUBLANG_FRENCH_CANADIAN: return "fr_CA"; + case SUBLANG_FRENCH_SWISS: return "fr_CH"; + case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU"; + case SUBLANG_FRENCH_MONACO: return "fr_MC"; + case SUBLANG_FRENCH_WESTINDIES: return "fr"; /* Caribbean? */ + case SUBLANG_FRENCH_REUNION: return "fr_RE"; + case SUBLANG_FRENCH_CONGO: return "fr_CG"; + case SUBLANG_FRENCH_SENEGAL: return "fr_SN"; + case SUBLANG_FRENCH_CAMEROON: return "fr_CM"; + case SUBLANG_FRENCH_COTEDIVOIRE: return "fr_CI"; + case SUBLANG_FRENCH_MALI: return "fr_ML"; + case SUBLANG_FRENCH_MOROCCO: return "fr_MA"; + case SUBLANG_FRENCH_HAITI: return "fr_HT"; + } + return "fr"; + case LANG_FRISIAN: return "fy_NL"; + case LANG_FULFULDE: return "ful_NG"; + case LANG_GAELIC: + switch (sub) + { + case 0x01: /* SCOTTISH */ return "gd_GB"; + case 0x02: /* IRISH */ return "ga_IE"; + } + return "C"; + case LANG_GALICIAN: return "gl_ES"; + case LANG_GEORGIAN: return "ka_GE"; + case LANG_GERMAN: + switch (sub) + { + case SUBLANG_GERMAN: return "de_DE"; + case SUBLANG_GERMAN_SWISS: return "de_CH"; + case SUBLANG_GERMAN_AUSTRIAN: return "de_AT"; + case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU"; + case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI"; + } + return "de"; + case LANG_GREEK: return "el_GR"; + case LANG_GUARANI: return "gn_PY"; + case LANG_GUJARATI: return "gu_IN"; + case LANG_HAUSA: return "ha_NG"; + case LANG_HAWAIIAN: + /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers) + or Hawaii Creole English ("cpe_US", 600000 speakers)? */ + return "cpe_US"; + case LANG_HEBREW: return "he_IL"; + case LANG_HINDI: return "hi_IN"; + case LANG_HUNGARIAN: return "hu_HU"; + case LANG_IBIBIO: return "nic_NG"; + case LANG_ICELANDIC: return "is_IS"; + case LANG_IGBO: return "ibo_NG"; + case LANG_INDONESIAN: return "id_ID"; + case LANG_INUKTITUT: return "iu_CA"; + case LANG_ITALIAN: + switch (sub) + { + case SUBLANG_ITALIAN: return "it_IT"; + case SUBLANG_ITALIAN_SWISS: return "it_CH"; + } + return "it"; + case LANG_JAPANESE: return "ja_JP"; + case LANG_KANNADA: return "kn_IN"; + case LANG_KANURI: return "kau_NG"; + case LANG_KASHMIRI: + switch (sub) + { + case SUBLANG_DEFAULT: return "ks_PK"; + case SUBLANG_KASHMIRI_INDIA: return "ks_IN"; + } + return "ks"; + case LANG_KAZAK: return "kk_KZ"; + case LANG_KONKANI: + /* FIXME: Adjust this when such locales appear on Unix. */ + return "kok_IN"; + case LANG_KOREAN: return "ko_KR"; + case LANG_KYRGYZ: return "ky_KG"; + case LANG_LAO: return "lo_LA"; + case LANG_LATIN: return "la_VA"; + case LANG_LATVIAN: return "lv_LV"; + case LANG_LITHUANIAN: return "lt_LT"; + case LANG_MACEDONIAN: return "mk_MK"; + case LANG_MALAY: + switch (sub) + { + case SUBLANG_MALAY_MALAYSIA: return "ms_MY"; + case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN"; + } + return "ms"; + case LANG_MALAYALAM: return "ml_IN"; + case LANG_MALTESE: return "mt_MT"; + case LANG_MANIPURI: + /* FIXME: Adjust this when such locales appear on Unix. */ + return "mni_IN"; + case LANG_MARATHI: return "mr_IN"; + case LANG_MONGOLIAN: + return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */ + case LANG_NEPALI: + switch (sub) + { + case SUBLANG_DEFAULT: return "ne_NP"; + case SUBLANG_NEPALI_INDIA: return "ne_IN"; + } + return "ne"; + case LANG_NORWEGIAN: + switch (sub) + { + case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO"; + case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO"; + } + return "no"; + case LANG_ORIYA: return "or_IN"; + case LANG_OROMO: return "om_ET"; + case LANG_PAPIAMENTU: return "pap_AN"; + case LANG_PASHTO: + return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */ + case LANG_POLISH: return "pl_PL"; + case LANG_PORTUGUESE: + switch (sub) + { + case SUBLANG_PORTUGUESE: return "pt_PT"; + /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT. + Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */ + case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR"; + } + return "pt"; + case LANG_PUNJABI: + switch (sub) + { + case SUBLANG_PUNJABI_INDIA: return "pa_IN"; /* Gurmukhi script */ + } + return "pa"; + case LANG_RHAETO_ROMANCE: return "rm_CH"; + case LANG_ROMANIAN: + switch (sub) + { + case SUBLANG_ROMANIAN_ROMANIA: return "ro_RO"; + } + return "ro"; + case LANG_RUSSIAN: + return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA" or "ru_MD". */ + case LANG_SAAMI: /* actually Northern Sami */ return "se_NO"; + case LANG_SANSKRIT: return "sa_IN"; + case LANG_SINDHI: + switch (sub) + { + case SUBLANG_SINDHI_INDIA: return "sd_IN"; + case SUBLANG_SINDHI_PAKISTAN: return "sd_PK"; + } + return "sd"; + case LANG_SINHALESE: return "si_LK"; + case LANG_SLOVAK: return "sk_SK"; + case LANG_SLOVENIAN: return "sl_SI"; + case LANG_SOMALI: return "so_SO"; + case LANG_SORBIAN: + /* FIXME: Adjust this when such locales appear on Unix. */ + return "wen_DE"; + case LANG_SPANISH: + switch (sub) + { + case SUBLANG_SPANISH: return "es_ES"; + case SUBLANG_SPANISH_MEXICAN: return "es_MX"; + case SUBLANG_SPANISH_MODERN: + return "es_ES@modern"; /* not seen on Unix */ + case SUBLANG_SPANISH_GUATEMALA: return "es_GT"; + case SUBLANG_SPANISH_COSTA_RICA: return "es_CR"; + case SUBLANG_SPANISH_PANAMA: return "es_PA"; + case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO"; + case SUBLANG_SPANISH_VENEZUELA: return "es_VE"; + case SUBLANG_SPANISH_COLOMBIA: return "es_CO"; + case SUBLANG_SPANISH_PERU: return "es_PE"; + case SUBLANG_SPANISH_ARGENTINA: return "es_AR"; + case SUBLANG_SPANISH_ECUADOR: return "es_EC"; + case SUBLANG_SPANISH_CHILE: return "es_CL"; + case SUBLANG_SPANISH_URUGUAY: return "es_UY"; + case SUBLANG_SPANISH_PARAGUAY: return "es_PY"; + case SUBLANG_SPANISH_BOLIVIA: return "es_BO"; + case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV"; + case SUBLANG_SPANISH_HONDURAS: return "es_HN"; + case SUBLANG_SPANISH_NICARAGUA: return "es_NI"; + case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR"; + } + return "es"; + case LANG_SUTU: return "bnt_TZ"; /* or "st_LS" or "nso_ZA"? */ + case LANG_SWAHILI: return "sw_KE"; + case LANG_SWEDISH: + switch (sub) + { + case SUBLANG_DEFAULT: return "sv_SE"; + case SUBLANG_SWEDISH_FINLAND: return "sv_FI"; + } + return "sv"; + case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */ + case LANG_TAGALOG: return "tl_PH"; + case LANG_TAJIK: return "tg_TJ"; + case LANG_TAMAZIGHT: + switch (sub) + { + /* FIXME: Adjust this when Tamazight locales appear on Unix. */ + case SUBLANG_TAMAZIGHT_ARABIC: return "ber_MA@arabic"; + case SUBLANG_TAMAZIGHT_LATIN: return "ber_MA@latin"; + } + return "ber_MA"; + case LANG_TAMIL: + return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */ + case LANG_TATAR: return "tt_RU"; + case LANG_TELUGU: return "te_IN"; + case LANG_THAI: return "th_TH"; + case LANG_TIBETAN: return "bo_CN"; + case LANG_TIGRINYA: + switch (sub) + { + case SUBLANG_TIGRINYA_ETHIOPIA: return "ti_ET"; + case SUBLANG_TIGRINYA_ERITREA: return "ti_ER"; + } + return "ti"; + case LANG_TSONGA: return "ts_ZA"; + case LANG_TSWANA: return "tn_BW"; + case LANG_TURKISH: return "tr_TR"; + case LANG_TURKMEN: return "tk_TM"; + case LANG_UKRAINIAN: return "uk_UA"; + case LANG_URDU: + switch (sub) + { + case SUBLANG_URDU_PAKISTAN: return "ur_PK"; + case SUBLANG_URDU_INDIA: return "ur_IN"; + } + return "ur"; + case LANG_UZBEK: + switch (sub) + { + case SUBLANG_UZBEK_LATIN: return "uz_UZ"; + case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic"; + } + return "uz"; + case LANG_VENDA: + return "ve_ZA"; + case LANG_VIETNAMESE: return "vi_VN"; + case LANG_WELSH: return "cy_GB"; + case LANG_XHOSA: return "xh_ZA"; + case LANG_YI: return "sit_CN"; + case LANG_YIDDISH: return "yi_IL"; + case LANG_YORUBA: return "yo_NG"; + case LANG_ZULU: return "zu_ZA"; + default: return "C"; + } +} + +/* localname.c from gettext END. */ + + + +/* Support functions. */ + +static GPG_ERR_INLINE uint32_t +do_swap_u32 (uint32_t i) +{ + return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); +} + +#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data)) + + +/* We assume to have `unsigned long int' value with at least 32 bits. */ +#define HASHWORDBITS 32 + +/* The so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +static GPG_ERR_INLINE unsigned long +hash_string (const char *str_param) +{ + unsigned long int hval, g; + const char *str = str_param; + + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned long int) *str++; + g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + + +/* Generic message catalog and gettext stuff. */ + +/* The magic number of the GNU message catalog format. */ +#define MAGIC 0x950412de +#define MAGIC_SWAPPED 0xde120495 + +/* Revision number of the currently used .mo (binary) file format. */ +#define MO_REVISION_NUMBER 0 + + +/* Header for binary .mo file format. */ +struct mo_file_header +{ + /* The magic number. */ + uint32_t magic; + /* The revision number of the file format. */ + uint32_t revision; + /* The number of strings pairs. */ + uint32_t nstrings; + /* Offset of table with start offsets of original strings. */ + uint32_t orig_tab_offset; + /* Offset of table with start offsets of translation strings. */ + uint32_t trans_tab_offset; + /* Size of hashing table. */ + uint32_t hash_tab_size; + /* Offset of first hashing entry. */ + uint32_t hash_tab_offset; +}; + + +struct string_desc +{ + /* Length of addressed string. */ + uint32_t length; + /* Offset of string in file. */ + uint32_t offset; +}; + + +struct overflow_space_s +{ + struct overflow_space_s *next; + uint32_t idx; + uint32_t length; + char d[1]; +}; + +struct loaded_domain +{ + char *data; + char *data_native; /* Data mapped to the native version of the + string. (Allocated along with DATA). */ + int must_swap; + uint16_t nstrings; /* Number of strings. */ + uint16_t *mapped; /* Array of mapping indicators: + 0 := Not mapped (original utf8). + 1 := Mapped to native encoding in overflow space. + >=2 := Mapped to native encoding. The value + gives the length of the mapped string. + Because the terminating nul is included + in the length and an empty string is + not allowed, values are always > 1. */ + struct overflow_space_s *overflow_space; + struct string_desc *orig_tab; + struct string_desc *trans_tab; + uint32_t hash_size; + uint32_t *hash_tab; +}; + + +/* The list of domains we we are aware of. This list is protected by + the criticla section DOMAINLIST_ACCESS_CS. */ +static struct domainlist_s *domainlist; + +/* A critical section to guard access to the domainlist. */ +static CRITICAL_SECTION domainlist_access_cs; + +/* The name of the current domain. This is a malloced string. This + is a gobal variable which is not thread-safe. */ +static char *current_domainname; + + + +/* Constructor for this module. This can only be used if we are a + DLL. If used as a static lib we can't control the process set; for + example it might be used with a main module which is not build with + mingw and thus does not know how to call the constructors. */ +#ifdef DLL_EXPORT +static void module_init (void) _GPG_ERR_CONSTRUCTOR; +#endif +static void +module_init (void) +{ + static int init_done; + + if (!init_done) + { + InitializeCriticalSection (&domainlist_access_cs); + init_done = 1; + } +} + +#if !defined(DLL_EXPORT) || !defined(_GPG_ERR_HAVE_CONSTRUCTOR) +void +_gpg_w32__init_gettext_module (void) +{ + module_init (); +} +#endif + + +/* Free the domain data. */ +static void +free_domain (struct loaded_domain *domain) +{ + struct overflow_space_s *os, *os2; + + jnlib_free (domain->data); + jnlib_free (domain->mapped); + for (os = domain->overflow_space; os; os = os2) + { + os2 = os->next; + jnlib_free (os); + } + jnlib_free (domain); +} + + +static struct loaded_domain * +load_domain (const char *filename) +{ + HANDLE fh; + DWORD size; + struct mo_file_header *data = NULL; + struct loaded_domain *domain = NULL; + size_t to_read; + char *read_ptr; + + { + wchar_t *wfilename = _gpgrt_utf8_to_wchar (filename); + + if (!wfilename) + fh = INVALID_HANDLE_VALUE; + else + fh = CreateFileW (wfilename, GENERIC_READ, FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + xfree (wfilename); + } + if (fh == INVALID_HANDLE_VALUE) + return NULL; + + size = GetFileSize (fh, NULL); + if (size == INVALID_FILE_SIZE) + { + CloseHandle (fh); + return NULL; + } + + data = (2*size <= size)? NULL : jnlib_malloc (2*size); + if (!data) + { + CloseHandle (fh); + return NULL; + } + + to_read = size; + read_ptr = (char *) data; + do + { + BOOL res; + DWORD nb; + + res = ReadFile (fh, read_ptr, to_read, &nb, NULL); + if (! res || nb < to_read) + { + CloseHandle (fh); + jnlib_free (data); + return NULL; + } + read_ptr += nb; + to_read -= nb; + } + while (to_read > 0); + CloseHandle (fh); + + /* Using the magic number we can test whether it really is a message + catalog file. */ + if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED) + { + /* The magic number is wrong: not a message catalog file. */ + jnlib_free (data); + return NULL; + } + + domain = jnlib_calloc (1, sizeof *domain); + if (!domain) + { + jnlib_free (data); + return NULL; + } + domain->data = (char *) data; + domain->data_native = (char *) data + size; + domain->must_swap = data->magic != MAGIC; + + /* Fill in the information about the available tables. */ + switch (SWAPIT (domain->must_swap, data->revision)) + { + case MO_REVISION_NUMBER: + { + uint32_t nstrings; + + /* Because we use 16 bit values for the mapping array, we + can't support more that 65534 strings (65535 would be okay, + but it is often used as a special value). A PO file with + that many translations is very unlikely given that GnuPG + with its very large number of strings has only about 1600 + strings + variants. */ + nstrings = SWAPIT (domain->must_swap, data->nstrings); + if (nstrings > 65534) + goto bailout; + domain->nstrings = nstrings; + domain->orig_tab = (struct string_desc *) + ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset)); + domain->trans_tab = (struct string_desc *) + ((char *) data + SWAPIT (domain->must_swap, data->trans_tab_offset)); + domain->hash_size = SWAPIT (domain->must_swap, data->hash_tab_size); + domain->hash_tab = (uint32_t *) + ((char *) data + SWAPIT (domain->must_swap, data->hash_tab_offset)); + } + break; + + default: /* This is an invalid revision. */ + goto bailout; + } + + /* Allocate an array to keep track of code page mappings. */ + domain->mapped = jnlib_calloc (domain->nstrings, sizeof *domain->mapped); + if (domain->mapped) + return domain; /* Okay. */ + + bailout: + jnlib_free (data); + jnlib_free (domain); + return NULL; +} + + +/* Return a malloced wide char string from an UTF-8 encoded input + string STRING. Caller must free this value. On failure returns + NULL. The result of calling this function with STRING set to NULL + is not defined. If LENGTH is zero and RETLEN NULL the fucntion + assumes that STRING is a nul-terminated string and returns a + (wchar_t)0-terminated string. */ +static wchar_t * +utf8_to_wchar (const char *string, size_t length, size_t *retlen) +{ + int n; + wchar_t *result; + size_t nbytes; + int cbmultibyte; + + if (!length && !retlen) + cbmultibyte = -1; + else + cbmultibyte = length; + + n = MultiByteToWideChar (CP_UTF8, 0, string, cbmultibyte, NULL, 0); + if (n < 0 || (n+1) <= 0) + return NULL; + + nbytes = (size_t)(n+1) * sizeof(*result); + if (nbytes / sizeof(*result) != (n+1)) + { + _gpg_err_set_errno (ENOMEM); + return NULL; + } + result = jnlib_malloc (nbytes); + if (!result) + return NULL; + + n = MultiByteToWideChar (CP_UTF8, 0, string, cbmultibyte, result, n); + if (n < 0) + { + jnlib_free (result); + return NULL; + } + if (retlen) + *retlen = n; + return result; +} + + +/* Convert an UTF8 string to a WCHAR string. Caller should use + * _gpgrt_free_wchar to release the result. */ +wchar_t * +_gpgrt_utf8_to_wchar (const char *string) +{ + return utf8_to_wchar (string, 0, NULL); +} + + +/* We provide a dedicated release function to be sure that we don't + * use a somehow mapped free function but the one which matches the + * used alloc. */ +void +_gpgrt_free_wchar (wchar_t *wstring) +{ + if (wstring) + jnlib_free (wstring); +} + + +/* Helper for wchar_to_native and wchar_to_utf8. */ +static char * +wchar_to_cp (const wchar_t *string, size_t length, size_t *retlen, + unsigned int cpno) +{ + int n; + char *result; + + n = WideCharToMultiByte (cpno, 0, string, length, NULL, 0, NULL, NULL); + if (n < 0 || (n+1) <= 0) + { + _gpgrt_w32_set_errno (-1); + return NULL; + } + + result = jnlib_malloc (n+1); + if (!result) + return NULL; + + n = WideCharToMultiByte (cpno, 0, string, length, result, n, NULL, NULL); + if (n < 0) + { + _gpgrt_w32_set_errno (-1); + jnlib_free (result); + return NULL; + } + result[n] = 0; + if (retlen) + *retlen = n; + return result; +} + + +/* Return a malloced string encoded in the native console codepage + from the wide char input string STRING. + Caller must free this value. On failure returns NULL. + The result of calling this function with STRING set to NULL + is not defined. */ +static char * +wchar_to_native (const wchar_t *string, size_t length, size_t *retlen) +{ + unsigned int cpno = GetConsoleOutputCP (); + + /* GetConsoleOutputCP returns the 8-Bit codepage that should be used + for console output. If the codepage is not returned we fall back + to the codepage GUI programs should use (CP_ACP). */ + if (!cpno) + cpno = GetACP (); + + return wchar_to_cp (string, length, retlen, cpno); +} + + +/* Convert a WCHAR string to UTF-8. Caller should use xfree to + * release the result. Returns NULL on error and sets ERRNO. */ +char * +_gpgrt_wchar_to_utf8 (const wchar_t *string, size_t length) +{ + return wchar_to_cp (string, length, NULL, CP_UTF8); +} + + +/* Convert UTF8 to the native codepage. Caller must free the return value. */ +static char * +utf8_to_native (const char *string, size_t length, size_t *retlen) +{ + wchar_t *wstring; + char *result; + size_t newlen; + + wstring = utf8_to_wchar (string, length, &newlen); + if (wstring) + { + result = wchar_to_native (wstring, newlen, &newlen); + jnlib_free (wstring); + } + else + result = NULL; + *retlen = result? newlen : 0; + return result; +} + + + +/* Specify that the DOMAINNAME message catalog will be found + in DIRNAME rather than in the system locale data base. */ +const char * +_gpg_w32_bindtextdomain (const char *domainname, const char *dirname) +{ + const char *catval_full; + char *catval; + char *fname; + const char *retvalue; + + if (!dirname) + { + struct domainlist_s *dl; + + retvalue = NULL; + EnterCriticalSection (&domainlist_access_cs); + { + for (dl = domainlist; dl; dl = dl->next) + if (!strcmp (dl->name, domainname)) + { + retvalue = dl->dname; + break; + } + } + LeaveCriticalSection (&domainlist_access_cs); + return retvalue; + } + + /* DIRNAME is "$INSTALLDIR\share\locale". */ + + /* First find out the category value. */ + catval = NULL; + catval_full = my_nl_locale_name ("LC_MESSAGES"); + + /* Normally we would have to loop over all returned locales and + search for the right file. See gettext intl/dcigettext.c for all + the gory details. Here, we only support the basic category, and + ignore everything else. */ + if (catval_full) + { + char *p; + + catval = jnlib_malloc (strlen (catval_full) + 1); + if (catval) + { + strcpy (catval, catval_full); + p = strchr (catval, '_'); + if (p) + *p = '\0'; + } + } + if (!catval) + return NULL; + + /* Now build the filename string. The complete filename is this: + DIRNAME + \ + CATVAL + \LC_MESSAGES\ + DOMAINNAME + .mo */ + { + int len = (strlen (dirname) + 1 + strlen (catval) + 13 + + strlen (domainname) + 3 + 1); + char *p; + + fname = jnlib_malloc (len); + if (!fname) + { + jnlib_free (catval); + return NULL; + } + + p = fname; + strcpy (p, dirname); + p += strlen (dirname); + *(p++) = '\\'; + strcpy (p, catval); + p += strlen (catval); + strcpy (p, "\\LC_MESSAGES\\"); + p += 13; + strcpy (p, domainname); + p += strlen (domainname); + strcpy (p, ".mo"); + } + + jnlib_free (catval); + + /* Store the domain information in the domainlist. */ + { + struct domainlist_s *item, *dl; + char *rel_ptr1 = NULL; + char *rel_ptr2 = NULL; + + item = jnlib_calloc (1, sizeof *dl + strlen (domainname)); + if (!item) + { + jnlib_free (fname); + return NULL; + } + strcpy (item->name, domainname); + item->dname = jnlib_malloc (strlen (dirname) +1); + if(!item->dname) + { + jnlib_free (item); + jnlib_free (fname); + return NULL; + } + strcpy (item->dname, dirname); + retvalue = item->dname; + + EnterCriticalSection (&domainlist_access_cs); + { + for (dl = domainlist; dl; dl = dl->next) + if (!strcmp (dl->name, domainname)) + break; + if (!dl) /* First time called for this domainname. */ + { + item->fname = fname; + fname = NULL; + item->next = domainlist; + domainlist = item; + item = NULL; + } + else /* Update only. */ + { + rel_ptr1 = dl->fname; + dl->fname = fname; + fname = NULL; + rel_ptr2 = dl->dname; + dl->dname = item->dname; + item->dname = NULL; + } + } + LeaveCriticalSection (&domainlist_access_cs); + + jnlib_free (item); + jnlib_free (rel_ptr1); + jnlib_free (rel_ptr2); + } + + return retvalue; +} + + + + +static const char * +get_plural (const char *data, size_t datalen, unsigned long nplural) +{ + const char *p; + int idx; + + /* We only support the Germanic rule. */ + idx = (nplural == 1? 0 : 1); + + for (; idx; idx--) + { + p = strchr (data, 0) + 1; + if (p >= data+datalen) + return "ERROR in GETTEXT (bad plural entry)"; + datalen -= (p-data); + data = p; + } + return data; +} + + +static const char* +get_string (struct loaded_domain *domain, uint32_t idx, + int use_plural, unsigned long nplural) +{ + struct tls_space_s *tls = get_tls (); + struct overflow_space_s *os; + const char *trans; /* Pointer to the translated entry. */ + size_t translen; /* Length of that entry. */ + + if (idx > 65534) + return "ERROR in GETTEXT (too many strings)"; + + if (tls->gt_use_utf8) + { + trans = (domain->data + + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset)); + translen = SWAPIT(domain->must_swap, domain->trans_tab[idx].length); + } + else if (!domain->mapped[idx]) + { + /* Not yet mapped. Map from utf-8 to native encoding now. */ + const char *p_utf8; + size_t plen_utf8, buflen; + char *buf; + + p_utf8 = (domain->data + + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset)); + plen_utf8 = SWAPIT(domain->must_swap, domain->trans_tab[idx].length); + + /* We need to include the nul, so that the utf8->wchar->native + conversion chain works correctly and the nul is stored after + the conversion. */ + if (p_utf8[plen_utf8]) + { + trans = "ERROR in MO file"; /* Terminating zero is missing. */ + translen = 0; + goto leave; + } + plen_utf8++; + + buf = utf8_to_native (p_utf8, plen_utf8, &buflen); + if (!buf) + { + trans = "ERROR in GETTEXT MALLOC"; + translen = 0; + } + else if (buflen <= plen_utf8 && buflen > 1) + { + /* Copy into the DATA_NATIVE area. */ + char *p_tmp; + + p_tmp = (domain->data_native + + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset)); + memcpy (p_tmp, buf, buflen); + domain->mapped[idx] = buflen; + trans = p_tmp; + translen = buflen; + } + else + { + /* There is not enough space for the translation (or for + whatever reason an empty string is used): Store it in the + overflow_space and mark that in the mapped array. + Because UTF-8 strings are in general longer than the + Windows native encoding, we expect that this won't happen + too often and thus we use a linked list to manage this + space. */ + os = jnlib_malloc (sizeof *os + buflen); + if (os) + { + os->idx = idx; + memcpy (os->d, buf, buflen); + os->length = buflen; + os->next = domain->overflow_space; + domain->overflow_space = os; + domain->mapped[idx] = 1; + trans = os->d; + translen = os->length; + } + else + { + trans = "ERROR in GETTEXT MALLOC"; + translen = 0; + } + } + if (translen) + translen--; /* TRANSLEN shall be the size without the nul. */ + jnlib_free (buf); + } + else if (domain->mapped[idx] == 1) + { + /* The translated string is in the overflow_space. */ + for (os=domain->overflow_space; os; os = os->next) + if (os->idx == idx) + break; + if (os) + { + trans = os->d; + translen = os->length; + } + else + { + trans = "ERROR in GETTEXT (overflow space)\n"; + translen = 0; + } + } + else + { + trans = (domain->data_native + + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset)); + translen = domain->mapped[idx]; + } + + leave: + if (use_plural && translen) + return get_plural (trans, translen, nplural); + else + return trans; +} + + +static const char * +do_gettext (const char *domainname, + const char *msgid, const char *msgid2, unsigned long nplural) +{ + struct domainlist_s *dl; + struct loaded_domain *domain; + int load_failed; + uint32_t top, bottom, nstr; + char *filename; + + if (!domainname) + domainname = current_domainname? current_domainname : ""; + + /* FIXME: The whole locking stuff is a bit questionable because + gettext does not claim to be thread-safe. We need to investigate + this further. */ + + load_failed = 0; + domain = NULL; + filename = NULL; + EnterCriticalSection (&domainlist_access_cs); + { + for (dl = domainlist; dl; dl = dl->next) + if (!strcmp (dl->name, domainname)) + { + load_failed = dl->load_failed; + domain = dl->domain; + break; + } + if (dl && !domain && !load_failed && dl->fname) + { + filename = jnlib_malloc (strlen (dl->fname) + 1); + if (filename) + strcpy (filename, dl->fname); + } + } + LeaveCriticalSection (&domainlist_access_cs); + if (!dl) + goto not_found; /* DOMAINNAME not bound. */ + if (filename) + { + /* No attempt so far to load the MO file. Try now. */ + int updated = 0; + + domain = load_domain (filename); + jnlib_free (filename); + filename = NULL; + EnterCriticalSection (&domainlist_access_cs); + { + for (dl = domainlist; dl; dl = dl->next) + if (!strcmp (dl->name, domainname)) + { + if (domain) + dl->domain = domain; + else + dl->load_failed = 1; + updated = 1; + break; + } + } + LeaveCriticalSection (&domainlist_access_cs); + if (!updated) + { + /* Ooops - lost the domain. */ + free_domain (domain); + domain = NULL; + } + } + + if (!domain) + goto not_found; /* No MO file. */ + + /* First try to use the hash table. */ + if (domain->hash_size > 2 && domain->hash_tab) + { + /* Use the hashing table. */ + uint32_t len = strlen (msgid); + uint32_t hash_val = hash_string (msgid); + uint32_t idx = hash_val % domain->hash_size; + uint32_t incr = 1 + (hash_val % (domain->hash_size - 2)); + + while ( (nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx])) ) + { + nstr--; + if (nstr < domain->nstrings + && SWAPIT(domain->must_swap, + domain->orig_tab[nstr].length) >= len + && !strcmp (msgid, (domain->data + + SWAPIT(domain->must_swap, + domain->orig_tab[nstr].offset)))) + { + return get_string (domain, nstr, !!msgid2, nplural); + } + + if (idx >= domain->hash_size - incr) + idx -= domain->hash_size - incr; + else + idx += incr; + } + } + + /* Now we try the default method: binary search in the sorted array + of messages. */ + bottom = 0; + top = domain->nstrings; + while (bottom < top) + { + int cmp_val; + + nstr = (bottom + top) / 2; + cmp_val = strcmp (msgid, (domain->data + + SWAPIT(domain->must_swap, + domain->orig_tab[nstr].offset))); + if (cmp_val < 0) + top = nstr; + else if (cmp_val > 0) + bottom = nstr + 1; + else + { + return get_string (domain, nstr, !!msgid2, nplural); + } + } + + not_found: + /* We use the standard Germanic rule if plural has been requested. */ + return msgid2? (nplural == 1? msgid : msgid2) : msgid; +} + + +const char * +_gpg_w32_textdomain (const char *domainname) +{ + char *string; + + if (!domainname) + { + if (!current_domainname) + _gpg_err_set_errno (0); + } + else + { + string = malloc (strlen (domainname) + 1); + if (!string) + return NULL; + strcpy (string, domainname); + current_domainname = string; + } + return current_domainname; +} + + +/* A direct implementation of gettext instead of a macro calling + dngettext. This is so that the caller does not need to push dummy + values on the stack. The used domain is the first one registered + with bindtextdomain. */ +const char * +_gpg_w32_gettext (const char *msgid) +{ + return do_gettext (NULL, msgid, NULL, 0); +} + + +/* A direct implementation of dgettext instead of a macro calling + dngettext. This is so that the caller does not need to push dummy + values on the stack. */ +const char * +_gpg_w32_dgettext (const char *domainname, const char *msgid) +{ + return do_gettext (domainname, msgid, NULL, 0); +} + + +/* Our implementation of dngettext. This is the most genereic + function we have; a macro implements ngettext. */ +const char * +_gpg_w32_dngettext (const char *domainname, const char *msgid1, + const char *msgid2, unsigned long int n) +{ + /* We use the simple Germanic plural rule. */ + return do_gettext (domainname, msgid1, msgid2, n); +} + + +/* Return the locale name as used by gettext. The return value will + never be NULL. */ +const char * +_gpg_w32_gettext_localename (void) +{ + const char *s; + + s = my_nl_locale_name ("LC_MESSAGES"); + return s? s:""; +} + + +/* With a VALUE of 1 switch the gettext functions into utf8 mode. + That is the strings are returned without translation to the native + charset. A VALUE of 0 switches back to translated strings. A VALUE + of -1 returns the current value. */ +int +_gpg_w32_gettext_use_utf8 (int value) +{ + struct tls_space_s *tls = get_tls (); + int last = tls->gt_use_utf8; + if (value != -1) + tls->gt_use_utf8 = value; + return last; +} + + +/* Force the use of the locale NAME or if NAME is NULL the locale + * derived from LANGID will be used. This function is not thread-safe + * and must be used early - even before gpgrt_check_version. */ +void +gpgrt_w32_override_locale (const char *name, unsigned short langid) +{ + if (name) + { + strncpy (override_locale.name, name, sizeof (override_locale.name) - 1); + override_locale.name[sizeof (override_locale.name) - 1] = 0; + } + else + *override_locale.name = 0; + override_locale.langid = langid; + override_locale.active = 1; +} + + +#ifdef TEST +int +main (int argc, char **argv) +{ + const char atext1[] = + "Warning: You have entered an insecure passphrase.%%0A" + "A passphrase should be at least %u character long."; + const char atext2[] = + "Warning: You have entered an insecure passphrase.%%0A" + "A passphrase should be at least %u characters long."; + + if (argc) + { + argc--; + argv++; + } + + _gpg_err_w32_bindtextdomain ("gnupg2", "c:/programme/gnu/gnupg/share/locale"); + + printf ("locale is `%s'\n", _gpg_err_w32_gettext_localename ()); + fputs ("text with N=1:\n", stdout); + fputs (_gpg_err_w32_ngettext (atext1, atext2, 1), stdout); + fputs ("\n\ntext with N=2:\n", stdout); + fputs (_gpg_err_w32_ngettext (atext1, atext2, 2), stdout); + fputs ("\nready\n", stdout); + + return 0; +} +/* + *No-Local Variables: + * compile-command: "i586-mingw32msvc-gcc -DTEST -Wall -g w32-gettext.c" + * End: + */ +#endif /*TEST*/ diff --git a/comm/third_party/libgpg-error/src/w32-iconv.c b/comm/third_party/libgpg-error/src/w32-iconv.c new file mode 100644 index 0000000000..888b72209c --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-iconv.c @@ -0,0 +1,1795 @@ +/* w32-iconv.c - iconv implementation for Windows. + * Copyright (C) 2016 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + ************************************************************** + * This code code is based on the file win_iconv.c as found + * at https://github.com/win-iconv/win-iconv with the commit id + * 8c23784e35327c9d85d22810b9e4a2cbd06ffe90, dated 2016-03-18. + * Yukihiro Nakadaira is the + * original author. The file win_iconv.c carried this notice: + *-------------------------------------------------------------- + * iconv implementation using Win32 API to convert. + * + * This file is placed in the public domain. + *--------------------------------------------------- + */ + +#if HAVE_CONFIG_H +#include +#endif +#if !defined (_WIN32) && !defined (__CYGWIN32__) +# error This module may only be build for Windows or Cygwin32 +#endif + +/* for WC_NO_BEST_FIT_CHARS */ +#ifndef WINVER +# define WINVER 0x0500 +#endif + +#include +#include +#include +#include + +#include "gpgrt-int.h" + +#undef USE_MLANG_DLL + +#define MB_CHAR_MAX 16 + +#define UNICODE_MODE_BOM_DONE 1 +#define UNICODE_MODE_SWAPPED 2 + +#define FLAG_USE_BOM 1 +#define FLAG_TRANSLIT 2 /* //TRANSLIT */ +#define FLAG_IGNORE 4 /* //IGNORE */ + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +typedef struct compat_t compat_t; +typedef struct csconv_t csconv_t; + +typedef int* (*f_errno)(void); +typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize); +typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize); + +#define COMPAT_IN 1 +#define COMPAT_OUT 2 + +/* unicode mapping for compatibility with other conversion table. */ +struct compat_t { + uint in; + uint out; + uint flag; +}; + +struct csconv_t { + int codepage; + int flags; + f_mbtowc mbtowc; + f_wctomb wctomb; + f_mblen mblen; + f_flush flush; + DWORD mode; + compat_t *compat; +}; + +struct _gpgrt_w32_iconv_s { + f_errno _errno; + csconv_t from; + csconv_t to; +}; + +#if USE_MLANG_DLL +static int load_mlang(void); +#endif /*USE_MLANG_DLL*/ + +static int make_csconv(const char *name, csconv_t *cv); +static int name_to_codepage(const char *name); +static uint utf16_to_ucs4(const ushort *wbuf); +static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize); +static int mbtowc_flags(int codepage); +static int must_use_null_useddefaultchar(int codepage); +static char *strrstr(const char *str, const char *token); +static char *xstrndup(const char *s, size_t n); +static int seterror(int err); + +static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize); +#if USE_MLANG_DLL +static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize); +#endif /*USE_MLANG_DLL*/ + +static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); + +#if USE_MLANG_DLL +static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +#endif /*USE_MLANG_DLL*/ + +static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); + +#if USE_MLANG_DLL +static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize); +#endif /*USE_MLANG_DLL*/ + +static struct { + int codepage; + const char *name; +} codepage_alias[] = { + {65001, "CP65001"}, + {65001, "UTF8"}, + {65001, "UTF-8"}, + + {1200, "CP1200"}, + {1200, "UTF16LE"}, + {1200, "UTF-16LE"}, + {1200, "UCS2LE"}, + {1200, "UCS-2LE"}, + {1200, "UCS-2-INTERNAL"}, + + {1201, "CP1201"}, + {1201, "UTF16BE"}, + {1201, "UTF-16BE"}, + {1201, "UCS2BE"}, + {1201, "UCS-2BE"}, + {1201, "unicodeFFFE"}, + + {12000, "CP12000"}, + {12000, "UTF32LE"}, + {12000, "UTF-32LE"}, + {12000, "UCS4LE"}, + {12000, "UCS-4LE"}, + + {12001, "CP12001"}, + {12001, "UTF32BE"}, + {12001, "UTF-32BE"}, + {12001, "UCS4BE"}, + {12001, "UCS-4BE"}, + + /* + * Default is big endian. + * See rfc2781 4.3 Interpreting text labelled as UTF-16. + */ + {1201, "UTF16"}, + {1201, "UTF-16"}, + {1201, "UCS2"}, + {1201, "UCS-2"}, + {12001, "UTF32"}, + {12001, "UTF-32"}, + {12001, "UCS-4"}, + {12001, "UCS4"}, + + /* copy from libiconv `iconv -l` */ + /* !IsValidCodePage(367) */ + {20127, "ANSI_X3.4-1968"}, + {20127, "ANSI_X3.4-1986"}, + {20127, "ASCII"}, + {20127, "CP367"}, + {20127, "IBM367"}, + {20127, "ISO-IR-6"}, + {20127, "ISO646-US"}, + {20127, "ISO_646.IRV:1991"}, + {20127, "US"}, + {20127, "US-ASCII"}, + {20127, "CSASCII"}, + + /* !IsValidCodePage(819) */ + {1252, "CP819"}, + {1252, "IBM819"}, + {28591, "ISO-8859-1"}, + {28591, "ISO-IR-100"}, + {28591, "ISO8859-1"}, + {28591, "ISO_8859-1"}, + {28591, "ISO_8859-1:1987"}, + {28591, "L1"}, + {28591, "LATIN1"}, + {28591, "CSISOLATIN1"}, + + {1250, "CP1250"}, + {1250, "MS-EE"}, + {1250, "WINDOWS-1250"}, + + {1251, "CP1251"}, + {1251, "MS-CYRL"}, + {1251, "WINDOWS-1251"}, + + {1252, "CP1252"}, + {1252, "MS-ANSI"}, + {1252, "WINDOWS-1252"}, + + {1253, "CP1253"}, + {1253, "MS-GREEK"}, + {1253, "WINDOWS-1253"}, + + {1254, "CP1254"}, + {1254, "MS-TURK"}, + {1254, "WINDOWS-1254"}, + + {1255, "CP1255"}, + {1255, "MS-HEBR"}, + {1255, "WINDOWS-1255"}, + + {1256, "CP1256"}, + {1256, "MS-ARAB"}, + {1256, "WINDOWS-1256"}, + + {1257, "CP1257"}, + {1257, "WINBALTRIM"}, + {1257, "WINDOWS-1257"}, + + {1258, "CP1258"}, + {1258, "WINDOWS-1258"}, + + {850, "850"}, + {850, "CP850"}, + {850, "IBM850"}, + {850, "CSPC850MULTILINGUAL"}, + + /* !IsValidCodePage(862) */ + {862, "862"}, + {862, "CP862"}, + {862, "IBM862"}, + {862, "CSPC862LATINHEBREW"}, + + {866, "866"}, + {866, "CP866"}, + {866, "IBM866"}, + {866, "CSIBM866"}, + + /* !IsValidCodePage(154) */ + {154, "CP154"}, + {154, "CYRILLIC-ASIAN"}, + {154, "PT154"}, + {154, "PTCP154"}, + {154, "CSPTCP154"}, + + /* !IsValidCodePage(1133) */ + {1133, "CP1133"}, + {1133, "IBM-CP1133"}, + + {874, "CP874"}, + {874, "WINDOWS-874"}, + + /* !IsValidCodePage(51932) */ + {51932, "CP51932"}, + {51932, "MS51932"}, + {51932, "WINDOWS-51932"}, + {51932, "EUC-JP"}, + + {932, "CP932"}, + {932, "MS932"}, + {932, "SHIFFT_JIS"}, + {932, "SHIFFT_JIS-MS"}, + {932, "SJIS"}, + {932, "SJIS-MS"}, + {932, "SJIS-OPEN"}, + {932, "SJIS-WIN"}, + {932, "WINDOWS-31J"}, + {932, "WINDOWS-932"}, + {932, "CSWINDOWS31J"}, + + {50221, "CP50221"}, + {50221, "ISO-2022-JP"}, + {50221, "ISO-2022-JP-MS"}, + {50221, "ISO2022-JP"}, + {50221, "ISO2022-JP-MS"}, + {50221, "MS50221"}, + {50221, "WINDOWS-50221"}, + + {936, "CP936"}, + {936, "GBK"}, + {936, "MS936"}, + {936, "WINDOWS-936"}, + + {950, "CP950"}, + {950, "BIG5"}, + {950, "BIG5HKSCS"}, + {950, "BIG5-HKSCS"}, + + {949, "CP949"}, + {949, "UHC"}, + {949, "EUC-KR"}, + + {1361, "CP1361"}, + {1361, "JOHAB"}, + + {437, "437"}, + {437, "CP437"}, + {437, "IBM437"}, + {437, "CSPC8CODEPAGE437"}, + + {737, "CP737"}, + + {775, "CP775"}, + {775, "IBM775"}, + {775, "CSPC775BALTIC"}, + + {852, "852"}, + {852, "CP852"}, + {852, "IBM852"}, + {852, "CSPCP852"}, + + /* !IsValidCodePage(853) */ + {853, "CP853"}, + + {855, "855"}, + {855, "CP855"}, + {855, "IBM855"}, + {855, "CSIBM855"}, + + {857, "857"}, + {857, "CP857"}, + {857, "IBM857"}, + {857, "CSIBM857"}, + + /* !IsValidCodePage(858) */ + {858, "CP858"}, + + {860, "860"}, + {860, "CP860"}, + {860, "IBM860"}, + {860, "CSIBM860"}, + + {861, "861"}, + {861, "CP-IS"}, + {861, "CP861"}, + {861, "IBM861"}, + {861, "CSIBM861"}, + + {863, "863"}, + {863, "CP863"}, + {863, "IBM863"}, + {863, "CSIBM863"}, + + {864, "CP864"}, + {864, "IBM864"}, + {864, "CSIBM864"}, + + {865, "865"}, + {865, "CP865"}, + {865, "IBM865"}, + {865, "CSIBM865"}, + + {869, "869"}, + {869, "CP-GR"}, + {869, "CP869"}, + {869, "IBM869"}, + {869, "CSIBM869"}, + + /* !IsValidCodePage(1152) */ + {1125, "CP1125"}, + + /* + * Code Page Identifiers + * https://msdn.microsoft.com/en-us/library/dd317756.aspx + */ + {37, "IBM037"}, /* IBM EBCDIC US-Canada */ + {437, "IBM437"}, /* OEM United States */ + {500, "IBM500"}, /* IBM EBCDIC International */ + {708, "ASMO-708"}, /* Arabic (ASMO 708) */ + /* 709 Arabic (ASMO-449+, BCON V4) */ + /* 710 Arabic - Transparent Arabic */ + {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */ + {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */ + {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */ + {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */ + {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */ + {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */ + {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */ + {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */ + {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */ + {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */ + {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */ + {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */ + {864, "IBM864"}, /* OEM Arabic; Arabic (864) */ + {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */ + {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */ + {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */ + {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */ + {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */ + {875, "cp875"}, /* IBM EBCDIC Greek Modern */ + {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */ + {932, "shift-jis"}, /* alternative name for it */ + {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */ + {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */ + {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */ + {950, "big5hkscs"}, /* ANSI/OEM Traditional Chinese (Hong Kong SAR); Chinese Traditional (Big5-HKSCS) */ + {950, "big5-hkscs"}, /* alternative name for it */ + {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */ + {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */ + {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */ + {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */ + {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */ + {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */ + {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */ + {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */ + {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */ + {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */ + {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */ + {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */ + {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */ + {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */ + {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */ + {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */ + {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */ + {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */ + {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */ + {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */ + {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */ + {1361, "Johab"}, /* Korean (Johab) */ + {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */ + {10001, "x-mac-japanese"}, /* Japanese (Mac) */ + {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */ + {10003, "x-mac-korean"}, /* Korean (Mac) */ + {10004, "x-mac-arabic"}, /* Arabic (Mac) */ + {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */ + {10006, "x-mac-greek"}, /* Greek (Mac) */ + {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */ + {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */ + {10010, "x-mac-romanian"}, /* Romanian (Mac) */ + {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */ + {10021, "x-mac-thai"}, /* Thai (Mac) */ + {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */ + {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */ + {10081, "x-mac-turkish"}, /* Turkish (Mac) */ + {10082, "x-mac-croatian"}, /* Croatian (Mac) */ + {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */ + {20001, "x-cp20001"}, /* TCA Taiwan */ + {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */ + {20003, "x-cp20003"}, /* IBM5550 Taiwan */ + {20004, "x-cp20004"}, /* TeleText Taiwan */ + {20005, "x-cp20005"}, /* Wang Taiwan */ + {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */ + {20106, "x-IA5-German"}, /* IA5 German (7-bit) */ + {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */ + {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */ + {20127, "us-ascii"}, /* US-ASCII (7-bit) */ + {20261, "x-cp20261"}, /* T.61 */ + {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */ + {20273, "IBM273"}, /* IBM EBCDIC Germany */ + {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */ + {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */ + {20280, "IBM280"}, /* IBM EBCDIC Italy */ + {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */ + {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */ + {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */ + {20297, "IBM297"}, /* IBM EBCDIC France */ + {20420, "IBM420"}, /* IBM EBCDIC Arabic */ + {20423, "IBM423"}, /* IBM EBCDIC Greek */ + {20424, "IBM424"}, /* IBM EBCDIC Hebrew */ + {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */ + {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */ + {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */ + {20871, "IBM871"}, /* IBM EBCDIC Icelandic */ + {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */ + {20905, "IBM905"}, /* IBM EBCDIC Turkish */ + {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */ + {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */ + {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */ + {20949, "x-cp20949"}, /* Korean Wansung */ + {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */ + /* 21027 (deprecated) */ + {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */ + {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */ + {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */ + {28591, "iso_8859-1"}, + {28591, "iso_8859_1"}, + {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */ + {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */ + {28592, "iso_8859-2"}, + {28592, "iso_8859_2"}, + {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */ + {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */ + {28593, "iso_8859-3"}, + {28593, "iso_8859_3"}, + {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */ + {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */ + {28594, "iso_8859-4"}, + {28594, "iso_8859_4"}, + {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */ + {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */ + {28595, "iso_8859-5"}, + {28595, "iso_8859_5"}, + {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */ + {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */ + {28596, "iso_8859-6"}, + {28596, "iso_8859_6"}, + {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */ + {28597, "iso8859-7"}, /* ISO 8859-7 Greek */ + {28597, "iso_8859-7"}, + {28597, "iso_8859_7"}, + {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ + {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ + {28598, "iso_8859-8"}, + {28598, "iso_8859_8"}, + {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */ + {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */ + {28599, "iso_8859-9"}, + {28599, "iso_8859_9"}, + {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */ + {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */ + {28603, "iso_8859-13"}, + {28603, "iso_8859_13"}, + {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */ + {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */ + {28605, "iso_8859-15"}, + {28605, "iso_8859_15"}, + {29001, "x-Europa"}, /* Europa 3 */ + {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ + {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ + {38598, "iso_8859-8-i"}, + {38598, "iso_8859_8-i"}, + {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */ + {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */ + {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */ + {50225, "iso-2022-kr"}, /* ISO 2022 Korean */ + {50225, "iso2022-kr"}, /* ISO 2022 Korean */ + {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */ + /* 50229 ISO 2022 Traditional Chinese */ + /* 50930 EBCDIC Japanese (Katakana) Extended */ + /* 50931 EBCDIC US-Canada and Japanese */ + /* 50933 EBCDIC Korean Extended and Korean */ + /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */ + /* 50936 EBCDIC Simplified Chinese */ + /* 50937 EBCDIC US-Canada and Traditional Chinese */ + /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */ + {51932, "euc-jp"}, /* EUC Japanese */ + {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */ + {51949, "euc-kr"}, /* EUC Korean */ + /* 51950 EUC Traditional Chinese */ + {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */ + {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */ + {57002, "x-iscii-de"}, /* ISCII Devanagari */ + {57003, "x-iscii-be"}, /* ISCII Bengali */ + {57004, "x-iscii-ta"}, /* ISCII Tamil */ + {57005, "x-iscii-te"}, /* ISCII Telugu */ + {57006, "x-iscii-as"}, /* ISCII Assamese */ + {57007, "x-iscii-or"}, /* ISCII Oriya */ + {57008, "x-iscii-ka"}, /* ISCII Kannada */ + {57009, "x-iscii-ma"}, /* ISCII Malayalam */ + {57010, "x-iscii-gu"}, /* ISCII Gujarati */ + {57011, "x-iscii-pa"}, /* ISCII Punjabi */ + + {0, NULL} +}; + +/* + * SJIS SHIFTJIS table CP932 table + * ---- --------------------------- -------------------------------- + * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS + * 7E U+203E OVERLINE U+007E TILDE + * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR + * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS + * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE + * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO + * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS + * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN + * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN + * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN + * + * EUC-JP and ISO-2022-JP should be compatible with CP932. + * + * Kernel and MLang have different Unicode mapping table. Make sure + * which API is used. + */ +static compat_t cp932_compat[] = { + {0x00A5, 0x005C, COMPAT_OUT}, + {0x203E, 0x007E, COMPAT_OUT}, + {0x2014, 0x2015, COMPAT_OUT}, + {0x301C, 0xFF5E, COMPAT_OUT}, + {0x2016, 0x2225, COMPAT_OUT}, + {0x2212, 0xFF0D, COMPAT_OUT}, + {0x00A2, 0xFFE0, COMPAT_OUT}, + {0x00A3, 0xFFE1, COMPAT_OUT}, + {0x00AC, 0xFFE2, COMPAT_OUT}, + {0, 0, 0} +}; + +static compat_t cp20932_compat[] = { + {0x00A5, 0x005C, COMPAT_OUT}, + {0x203E, 0x007E, COMPAT_OUT}, + {0x2014, 0x2015, COMPAT_OUT}, + {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN}, + {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN}, + {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN}, + {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN}, + {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN}, + {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN}, + {0, 0, 0} +}; + +static compat_t *cp51932_compat = cp932_compat; + +/* cp20932_compat for kernel. cp932_compat for mlang. */ +static compat_t *cp5022x_compat = cp932_compat; + +#if USE_MLANG_DLL +typedef HRESULT (WINAPI *CONVERTINETSTRING)( + LPDWORD lpdwMode, + DWORD dwSrcEncoding, + DWORD dwDstEncoding, + LPCSTR lpSrcStr, + LPINT lpnSrcSize, + LPBYTE lpDstStr, + LPINT lpnDstSize +); +typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)( + LPDWORD lpdwMode, + DWORD dwSrcEncoding, + LPCSTR lpSrcStr, + LPINT lpnMultiCharCount, + LPWSTR lpDstStr, + LPINT lpnWideCharCount +); +typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)( + LPDWORD lpdwMode, + DWORD dwEncoding, + LPCWSTR lpSrcStr, + LPINT lpnWideCharCount, + LPSTR lpDstStr, + LPINT lpnMultiCharCount +); +typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)( + DWORD dwSrcEncoding, + DWORD dwDstEncoding +); +typedef HRESULT (WINAPI *LCIDTORFC1766A)( + LCID Locale, + LPSTR pszRfc1766, + int nChar +); +typedef HRESULT (WINAPI *LCIDTORFC1766W)( + LCID Locale, + LPWSTR pszRfc1766, + int nChar +); +typedef HRESULT (WINAPI *RFC1766TOLCIDA)( + LCID *pLocale, + LPSTR pszRfc1766 +); +typedef HRESULT (WINAPI *RFC1766TOLCIDW)( + LCID *pLocale, + LPWSTR pszRfc1766 +); +static CONVERTINETSTRING ConvertINetString; +static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode; +static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte; +static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable; +static LCIDTORFC1766A LcidToRfc1766A; +static RFC1766TOLCIDA Rfc1766ToLcidA; +#endif /*USE_MLANG_DLL*/ + +#if USE_MLANG_DLL +static int +load_mlang(void) +{ + HMODULE h; + if (ConvertINetString != NULL) + return TRUE; + h = LoadLibrary(TEXT("mlang.dll")); + if (!h) + return FALSE; + ConvertINetString = (CONVERTINETSTRING)GetProcAddressA(h, "ConvertINetString"); + ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddressA(h, "ConvertINetMultiByteToUnicode"); + ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddressA(h, "ConvertINetUnicodeToMultiByte"); + IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddressA(h, "IsConvertINetStringAvailable"); + LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddressA(h, "LcidToRfc1766A"); + Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddressA(h, "Rfc1766ToLcidA"); + return TRUE; +} +#endif + + +static int +win_iconv_open(gpgrt_w32_iconv_t cd, const char *tocode, const char *fromcode) +{ + if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to)) + return FALSE; + cd->_errno = _errno; + return TRUE; +} + +static size_t +win_iconv (gpgrt_w32_iconv_t cd, + const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft) +{ + ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */ + int insize; + int outsize; + int wsize; + DWORD frommode; + DWORD tomode; + uint wc; + compat_t *cp; + int i; + + if (inbuf == NULL || *inbuf == NULL) + { + if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL) + { + tomode = cd->to.mode; + outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft); + if (outsize == -1) + { + if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG) + { + outsize = 0; + } + else + { + cd->to.mode = tomode; + return (size_t)(-1); + } + } + *outbuf += outsize; + *outbytesleft -= outsize; + } + cd->from.mode = 0; + cd->to.mode = 0; + return 0; + } + + while (*inbytesleft != 0) + { + frommode = cd->from.mode; + tomode = cd->to.mode; + wsize = MB_CHAR_MAX; + + insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize); + if (insize == -1) + { + if (cd->to.flags & FLAG_IGNORE) + { + cd->from.mode = frommode; + insize = 1; + wsize = 0; + } + else + { + cd->from.mode = frommode; + return (size_t)(-1); + } + } + + if (wsize == 0) + { + *inbuf += insize; + *inbytesleft -= insize; + continue; + } + + if (cd->from.compat != NULL) + { + wc = utf16_to_ucs4(wbuf); + cp = cd->from.compat; + for (i = 0; cp[i].in != 0; ++i) + { + if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc) + { + ucs4_to_utf16(cp[i].in, wbuf, &wsize); + break; + } + } + } + + if (cd->to.compat != NULL) + { + wc = utf16_to_ucs4(wbuf); + cp = cd->to.compat; + for (i = 0; cp[i].in != 0; ++i) + { + if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc) + { + ucs4_to_utf16(cp[i].out, wbuf, &wsize); + break; + } + } + } + + outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft); + if (outsize == -1) + { + if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG) + { + cd->to.mode = tomode; + outsize = 0; + } + else + { + cd->from.mode = frommode; + cd->to.mode = tomode; + return (size_t)(-1); + } + } + + *inbuf += insize; + *outbuf += outsize; + *inbytesleft -= insize; + *outbytesleft -= outsize; + } + + return 0; +} + +static int +make_csconv(const char *_name, csconv_t *cv) +{ + CPINFO cpinfo; + int use_compat = TRUE; + int flag = 0; + char *name; + char *p; + + name = xstrndup(_name, strlen(_name)); + if (name == NULL) + return FALSE; + + /* check for option "enc_name//opt1//opt2" */ + while ((p = strrstr(name, "//")) != NULL) + { + if (_stricmp(p + 2, "nocompat") == 0) + use_compat = FALSE; + else if (_stricmp(p + 2, "translit") == 0) + flag |= FLAG_TRANSLIT; + else if (_stricmp(p + 2, "ignore") == 0) + flag |= FLAG_IGNORE; + *p = 0; + } + + cv->mode = 0; + cv->flags = flag; + cv->mblen = NULL; + cv->flush = NULL; + cv->compat = NULL; + cv->codepage = name_to_codepage(name); + if (cv->codepage == 1200 || cv->codepage == 1201) + { + cv->mbtowc = utf16_mbtowc; + cv->wctomb = utf16_wctomb; + if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0 || + _stricmp(name, "UCS-2") == 0 || _stricmp(name, "UCS2") == 0 || + _stricmp(name,"UCS-2-INTERNAL") == 0) + cv->flags |= FLAG_USE_BOM; + } + else if (cv->codepage == 12000 || cv->codepage == 12001) + { + cv->mbtowc = utf32_mbtowc; + cv->wctomb = utf32_wctomb; + if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0 || + _stricmp(name, "UCS-4") == 0 || _stricmp(name, "UCS4") == 0) + cv->flags |= FLAG_USE_BOM; + } + else if (cv->codepage == 65001) + { + cv->mbtowc = kernel_mbtowc; + cv->wctomb = kernel_wctomb; + cv->mblen = utf8_mblen; + } +#if USE_MLANG_DLL + else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang()) + { + cv->mbtowc = iso2022jp_mbtowc; + cv->wctomb = iso2022jp_wctomb; + cv->flush = iso2022jp_flush; + } + else if (cv->codepage == 51932 && load_mlang()) + { + cv->mbtowc = mlang_mbtowc; + cv->wctomb = mlang_wctomb; + cv->mblen = eucjp_mblen; + } +#endif /*USE_MLANG_DLL*/ + else if (IsValidCodePage(cv->codepage) + && GetCPInfo(cv->codepage, &cpinfo) != 0) + { + cv->mbtowc = kernel_mbtowc; + cv->wctomb = kernel_wctomb; + if (cpinfo.MaxCharSize == 1) + cv->mblen = sbcs_mblen; + else if (cpinfo.MaxCharSize == 2) + cv->mblen = dbcs_mblen; + else + cv->mblen = mbcs_mblen; + } + else + { + /* not supported */ + free(name); + errno = EINVAL; + return FALSE; + } + + if (use_compat) + { + switch (cv->codepage) + { + case 932: cv->compat = cp932_compat; break; + case 20932: cv->compat = cp20932_compat; break; + case 51932: cv->compat = cp51932_compat; break; + case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break; + } + } + + free(name); + + return TRUE; +} + +static int +name_to_codepage(const char *name) +{ + int i; + + if (*name == '\0' || + strcmp(name, "char") == 0) + return GetACP(); + else if (strcmp(name, "wchar_t") == 0) + return 1200; + else if (_strnicmp(name, "cp", 2) == 0) + return atoi(name + 2); /* CP123 */ + else if ('0' <= name[0] && name[0] <= '9') + return atoi(name); /* 123 */ + else if (_strnicmp(name, "xx", 2) == 0) + return atoi(name + 2); /* XX123 for debug */ + + for (i = 0; codepage_alias[i].name != NULL; ++i) + if (_stricmp(name, codepage_alias[i].name) == 0) + return codepage_alias[i].codepage; + return -1; +} + +/* + * https://tools.ietf.org/html/rfc2781 + */ +static uint +utf16_to_ucs4(const ushort *wbuf) +{ + uint wc = wbuf[0]; + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000; + return wc; +} + +static void +ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize) +{ + if (wc < 0x10000) + { + wbuf[0] = wc; + *wbufsize = 1; + } + else + { + wc -= 0x10000; + wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF); + wbuf[1] = 0xDC00 | (wc & 0x3FF); + *wbufsize = 2; + } +} + +/* + * Check if codepage is one of those for which the dwFlags parameter + * to MultiByteToWideChar() must be zero. Return zero or + * MB_ERR_INVALID_CHARS. The docs in Platform SDK for Windows + * Server 2003 R2 claims that also codepage 65001 is one of these, but + * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave + * out 65001 (UTF-8), and that indeed seems to be the case on XP, it + * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting + * from UTF-8. + */ +static int +mbtowc_flags(int codepage) +{ + return (codepage == 50220 || codepage == 50221 || + codepage == 50222 || codepage == 50225 || + codepage == 50227 || codepage == 50229 || + codepage == 52936 || codepage == 54936 || + (codepage >= 57002 && codepage <= 57011) || + codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS; +} + +/* + * Check if codepage is one those for which the lpUsedDefaultChar + * parameter to WideCharToMultiByte() must be NULL. The docs in + * Platform SDK for Windows Server 2003 R2 claims that this is the + * list below, while the MSDN docs for MSVS2008 claim that it is only + * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform + * SDK seems to be correct, at least for XP. + */ +static int +must_use_null_useddefaultchar(int codepage) +{ + return (codepage == 65000 || codepage == 65001 || + codepage == 50220 || codepage == 50221 || + codepage == 50222 || codepage == 50225 || + codepage == 50227 || codepage == 50229 || + codepage == 52936 || codepage == 54936 || + (codepage >= 57002 && codepage <= 57011) || + codepage == 42); +} + +static char * +strrstr(const char *str, const char *token) +{ + int len = strlen(token); + const char *p = str + strlen(str); + + while (str <= --p) + if (p[0] == token[0] && strncmp(p, token, len) == 0) + return (char *)p; + return NULL; +} + +static char * +xstrndup(const char *s, size_t n) +{ + char *p; + + p = (char *)malloc(n + 1); + if (p == NULL) + return NULL; + memcpy(p, s, n); + p[n] = '\0'; + return p; +} + +static int +seterror(int err) +{ + _gpg_err_set_errno (err); + return -1; +} + + +static int +sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + (void)cv; + (void)buf; + (void)bufsize; + return 1; +} + +static int +dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1; + if (bufsize < len) + return seterror(EINVAL); + return len; +} + +static int +mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = 0; + + if (cv->codepage == 54936) { + if (buf[0] <= 0x7F) len = 1; + else if (buf[0] >= 0x81 && buf[0] <= 0xFE && + bufsize >= 2 && + ((buf[1] >= 0x40 && buf[1] <= 0x7E) || + (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2; + else if (buf[0] >= 0x81 && buf[0] <= 0xFE && + bufsize >= 4 && + buf[1] >= 0x30 && buf[1] <= 0x39) len = 4; + else + return seterror(EINVAL); + return len; + } + else + return seterror(EINVAL); +} + +static int +utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = 0; + + (void) cv; + + if (buf[0] < 0x80) len = 1; + else if ((buf[0] & 0xE0) == 0xC0) len = 2; + else if ((buf[0] & 0xF0) == 0xE0) len = 3; + else if ((buf[0] & 0xF8) == 0xF0) len = 4; + else if ((buf[0] & 0xFC) == 0xF8) len = 5; + else if ((buf[0] & 0xFE) == 0xFC) len = 6; + + if (len == 0) + return seterror(EILSEQ); + else if (bufsize < len) + return seterror(EINVAL); + return len; +} + +#if USE_MLANG_DLL +static int +eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + (void) cv; + + if (buf[0] < 0x80) /* ASCII */ + return 1; + else if (buf[0] == 0x8E) /* JIS X 0201 */ + { + if (bufsize < 2) + return seterror(EINVAL); + else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF)) + return seterror(EILSEQ); + return 2; + } + else if (buf[0] == 0x8F) /* JIS X 0212 */ + { + if (bufsize < 3) + return seterror(EINVAL); + else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE) + || !(0xA1 <= buf[2] && buf[2] <= 0xFE)) + return seterror(EILSEQ); + return 3; + } + else /* JIS X 0208 */ + { + if (bufsize < 2) + return seterror(EINVAL); + else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE) + || !(0xA1 <= buf[1] && buf[1] <= 0xFE)) + return seterror(EILSEQ); + return 2; + } +} +#endif /*USE_MLANG_DLL*/ + +static int +kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int len; + + len = cv->mblen(cv, buf, bufsize); + if (len == -1) + return -1; + /* If converting from ASCII, reject 8bit + * chars. MultiByteToWideChar() doesn't. Note that for ASCII we + * know that the mblen function is sbcs_mblen() so len is 1. + */ + if (cv->codepage == 20127 && buf[0] >= 0x80) + return seterror(EILSEQ); + *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage), + (const char *)buf, len, (wchar_t *)wbuf, *wbufsize); + if (*wbufsize == 0) + return seterror(EILSEQ); + return len; +} + +static int +kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + BOOL usedDefaultChar = 0; + BOOL *p = NULL; + int flags = 0; + int len; + + if (bufsize == 0) + return seterror(E2BIG); + if (!must_use_null_useddefaultchar(cv->codepage)) + { + p = &usedDefaultChar; +#ifdef WC_NO_BEST_FIT_CHARS + if (!(cv->flags & FLAG_TRANSLIT)) + flags |= WC_NO_BEST_FIT_CHARS; +#endif + } + len = WideCharToMultiByte(cv->codepage, flags, + (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p); + if (len == 0) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + return seterror(E2BIG); + return seterror(EILSEQ); + } + else if (usedDefaultChar && !(cv->flags & FLAG_TRANSLIT)) + return seterror(EILSEQ); + else if (cv->mblen(cv, buf, len) != len) /* validate result */ + return seterror(EILSEQ); + return len; +} + +/* + * It seems that the mode (cv->mode) is fixnum. + * For example, when converting iso-2022-jp(cp50221) to unicode: + * in ascii sequence: mode=0xC42C0000 + * in jisx0208 sequence: mode=0xC42C0001 + * "C42C" is same for each convert session. + * It should be: ((codepage-1)<<16)|state + */ +#if USE_MLANG_DLL +static int +mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int len; + int insize; + HRESULT hr; + + len = cv->mblen(cv, buf, bufsize); + if (len == -1) + return -1; + insize = len; + hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage, + (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize); + if (hr != S_OK || insize != len) + return seterror(EILSEQ); + return len; +} + +static int +mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */ + int tmpsize = MB_CHAR_MAX; + int insize = wbufsize; + HRESULT hr; + + hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage, + (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize); + if (hr != S_OK || insize != wbufsize) + return seterror(EILSEQ); + else if (bufsize < tmpsize) + return seterror(E2BIG); + else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize) + return seterror(EILSEQ); + memcpy(buf, tmpbuf, tmpsize); + return tmpsize; +} +#endif /*USE_MLANG_DLL*/ + +static int +utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int codepage = cv->codepage; + + /* swap endian: 1200 <-> 1201 */ + if (cv->mode & UNICODE_MODE_SWAPPED) + codepage ^= 1; + + if (bufsize < 2) + return seterror(EINVAL); + if (codepage == 1200) /* little endian */ + wbuf[0] = (buf[1] << 8) | buf[0]; + else if (codepage == 1201) /* big endian */ + wbuf[0] = (buf[0] << 8) | buf[1]; + + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + cv->mode |= UNICODE_MODE_BOM_DONE; + if (wbuf[0] == 0xFFFE) + { + cv->mode |= UNICODE_MODE_SWAPPED; + *wbufsize = 0; + return 2; + } + else if (wbuf[0] == 0xFEFF) + { + *wbufsize = 0; + return 2; + } + } + + if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF) + return seterror(EILSEQ); + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + { + if (bufsize < 4) + return seterror(EINVAL); + if (codepage == 1200) /* little endian */ + wbuf[1] = (buf[3] << 8) | buf[2]; + else if (codepage == 1201) /* big endian */ + wbuf[1] = (buf[2] << 8) | buf[3]; + if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF)) + return seterror(EILSEQ); + *wbufsize = 2; + return 4; + } + *wbufsize = 1; + return 2; +} + +static int +utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + int r; + + cv->mode |= UNICODE_MODE_BOM_DONE; + if (bufsize < 2) + return seterror(E2BIG); + if (cv->codepage == 1200) /* little endian */ + memcpy(buf, "\xFF\xFE", 2); + else if (cv->codepage == 1201) /* big endian */ + memcpy(buf, "\xFE\xFF", 2); + + r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2); + if (r == -1) + return -1; + return r + 2; + } + + if (bufsize < 2) + return seterror(E2BIG); + if (cv->codepage == 1200) /* little endian */ + { + buf[0] = (wbuf[0] & 0x00FF); + buf[1] = (wbuf[0] & 0xFF00) >> 8; + } + else if (cv->codepage == 1201) /* big endian */ + { + buf[0] = (wbuf[0] & 0xFF00) >> 8; + buf[1] = (wbuf[0] & 0x00FF); + } + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + { + if (bufsize < 4) + return seterror(E2BIG); + if (cv->codepage == 1200) /* little endian */ + { + buf[2] = (wbuf[1] & 0x00FF); + buf[3] = (wbuf[1] & 0xFF00) >> 8; + } + else if (cv->codepage == 1201) /* big endian */ + { + buf[2] = (wbuf[1] & 0xFF00) >> 8; + buf[3] = (wbuf[1] & 0x00FF); + } + return 4; + } + return 2; +} + +static int +utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int codepage = cv->codepage; + uint wc = 0xD800; + + /* swap endian: 12000 <-> 12001 */ + if (cv->mode & UNICODE_MODE_SWAPPED) + codepage ^= 1; + + if (bufsize < 4) + return seterror(EINVAL); + if (codepage == 12000) /* little endian */ + wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + else if (codepage == 12001) /* big endian */ + wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + cv->mode |= UNICODE_MODE_BOM_DONE; + if (wc == 0xFFFE0000) + { + cv->mode |= UNICODE_MODE_SWAPPED; + *wbufsize = 0; + return 4; + } + else if (wc == 0x0000FEFF) + { + *wbufsize = 0; + return 4; + } + } + + if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc) + return seterror(EILSEQ); + ucs4_to_utf16(wc, wbuf, wbufsize); + return 4; +} + +static int +utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + uint wc; + + if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE)) + { + int r; + + cv->mode |= UNICODE_MODE_BOM_DONE; + if (bufsize < 4) + return seterror(E2BIG); + if (cv->codepage == 12000) /* little endian */ + memcpy(buf, "\xFF\xFE\x00\x00", 4); + else if (cv->codepage == 12001) /* big endian */ + memcpy(buf, "\x00\x00\xFE\xFF", 4); + + r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4); + if (r == -1) + return -1; + return r + 4; + } + + if (bufsize < 4) + return seterror(E2BIG); + wc = utf16_to_ucs4(wbuf); + if (cv->codepage == 12000) /* little endian */ + { + buf[0] = wc & 0x000000FF; + buf[1] = (wc & 0x0000FF00) >> 8; + buf[2] = (wc & 0x00FF0000) >> 16; + buf[3] = (wc & 0xFF000000) >> 24; + } + else if (cv->codepage == 12001) /* big endian */ + { + buf[0] = (wc & 0xFF000000) >> 24; + buf[1] = (wc & 0x00FF0000) >> 16; + buf[2] = (wc & 0x0000FF00) >> 8; + buf[3] = wc & 0x000000FF; + } + return 4; +} + +/* + * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) + * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow + * 1 byte Kana) + * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte + * Kana - SO/SI) + * + * MultiByteToWideChar() and WideCharToMultiByte() behave differently + * depending on Windows version. On XP, WideCharToMultiByte() doesn't + * terminate result sequence with ascii escape. But Vista does. + * Use MLang instead. + */ + +#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift)) +#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF) +#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF) + +#define ISO2022_SI 0 +#define ISO2022_SO 1 + +#if USE_MLANG_DLL +/* shift in */ +static const char iso2022_SI_seq[] = "\x0F"; +/* shift out */ +static const char iso2022_SO_seq[] = "\x0E"; + +typedef struct iso2022_esc_t iso2022_esc_t; +struct iso2022_esc_t { + const char *esc; + int esc_len; + int len; + int cs; +}; +#endif + +#define ISO2022JP_CS_ASCII 0 +#define ISO2022JP_CS_JISX0201_ROMAN 1 +#define ISO2022JP_CS_JISX0201_KANA 2 +#define ISO2022JP_CS_JISX0208_1978 3 +#define ISO2022JP_CS_JISX0208_1983 4 +#define ISO2022JP_CS_JISX0212 5 + +#if USE_MLANG_DLL +static iso2022_esc_t iso2022jp_esc[] = { + {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII}, + {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN}, + {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA}, + {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */ + {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983}, + {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212}, + {NULL, 0, 0, 0} +}; +#endif /*USE_MLANG_DLL*/ + +#if USE_MLANG_DLL +static int +iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, + ushort *wbuf, int *wbufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + char tmp[MB_CHAR_MAX]; + int insize; + HRESULT hr; + DWORD dummy = 0; + int len; + int esc_len; + int cs; + int shift; + int i; + + if (buf[0] == 0x1B) + { + for (i = 0; iesc[i].esc != NULL; ++i) + { + esc_len = iesc[i].esc_len; + if (bufsize < esc_len) + { + if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0) + return seterror(EINVAL); + } + else + { + if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0) + { + cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI); + *wbufsize = 0; + return esc_len; + } + } + } + /* not supported escape sequence */ + return seterror(EILSEQ); + } + else if (buf[0] == iso2022_SO_seq[0]) + { + cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO); + *wbufsize = 0; + return 1; + } + else if (buf[0] == iso2022_SI_seq[0]) + { + cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI); + *wbufsize = 0; + return 1; + } + + cs = ISO2022_MODE_CS(cv->mode); + shift = ISO2022_MODE_SHIFT(cv->mode); + + /* reset the mode for informal sequence */ + if (buf[0] < 0x20) + { + cs = ISO2022JP_CS_ASCII; + shift = ISO2022_SI; + } + + len = iesc[cs].len; + if (bufsize < len) + return seterror(EINVAL); + for (i = 0; i < len; ++i) + if (!(buf[i] < 0x80)) + return seterror(EILSEQ); + esc_len = iesc[cs].esc_len; + memcpy(tmp, iesc[cs].esc, esc_len); + if (shift == ISO2022_SO) + { + memcpy(tmp + esc_len, iso2022_SO_seq, 1); + esc_len += 1; + } + memcpy(tmp + esc_len, buf, len); + + if ((cv->codepage == 50220 || cv->codepage == 50221 + || cv->codepage == 50222) && shift == ISO2022_SO) + { + /* XXX: shift-out cannot be used for mbtowc (both kernel and + * mlang) */ + esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len; + memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len); + memcpy(tmp + esc_len, buf, len); + } + + insize = len + esc_len; + hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage, + (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize); + if (hr != S_OK || insize != len + esc_len) + return seterror(EILSEQ); + + /* Check for conversion error. Assuming defaultChar is 0x3F. */ + /* ascii should be converted from ascii */ + if (wbuf[0] == buf[0] + && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI)) + return seterror(EILSEQ); + + /* reset the mode for informal sequence */ + if (cv->mode != ISO2022_MODE(cs, shift)) + cv->mode = ISO2022_MODE(cs, shift); + + return len; +} +#endif /*USE_MLANG_DLL*/ + + +#if USE_MLANG_DLL +static int +iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + char tmp[MB_CHAR_MAX]; + int tmpsize = MB_CHAR_MAX; + int insize = wbufsize; + HRESULT hr; + DWORD dummy = 0; + int len; + int esc_len; + int cs; + int shift; + int i; + + /* + * MultiByte = [escape sequence] + character + [escape sequence] + * + * Whether trailing escape sequence is added depends on which API is + * used (kernel or MLang, and its version). + */ + hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage, + (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize); + if (hr != S_OK || insize != wbufsize) + return seterror(EILSEQ); + else if (bufsize < tmpsize) + return seterror(E2BIG); + + if (tmpsize == 1) + { + cs = ISO2022JP_CS_ASCII; + esc_len = 0; + } + else + { + for (i = 1; iesc[i].esc != NULL; ++i) + { + esc_len = iesc[i].esc_len; + if (strncmp(tmp, iesc[i].esc, esc_len) == 0) + { + cs = iesc[i].cs; + break; + } + } + if (iesc[i].esc == NULL) + /* not supported escape sequence */ + return seterror(EILSEQ); + } + + shift = ISO2022_SI; + if (tmp[esc_len] == iso2022_SO_seq[0]) + { + shift = ISO2022_SO; + esc_len += 1; + } + + len = iesc[cs].len; + + /* Check for converting error. Assuming defaultChar is 0x3F. */ + /* ascii should be converted from ascii */ + if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80)) + return seterror(EILSEQ); + else if (tmpsize < esc_len + len) + return seterror(EILSEQ); + + if (cv->mode == ISO2022_MODE(cs, shift)) + { + /* remove escape sequence */ + if (esc_len != 0) + memmove(tmp, tmp + esc_len, len); + esc_len = 0; + } + else + { + if (cs == ISO2022JP_CS_ASCII) + { + esc_len = iesc[ISO2022JP_CS_ASCII].esc_len; + memmove(tmp + esc_len, tmp, len); + memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len); + } + if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO) + { + /* shift-in before changing to other mode */ + memmove(tmp + 1, tmp, len + esc_len); + memcpy(tmp, iso2022_SI_seq, 1); + esc_len += 1; + } + } + + if (bufsize < len + esc_len) + return seterror(E2BIG); + memcpy(buf, tmp, len + esc_len); + cv->mode = ISO2022_MODE(cs, shift); + return len + esc_len; +} +#endif /*USE_MLANG_DLL*/ + +#if USE_MLANG_DLL +static int +iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + int esc_len; + + if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI)) + { + esc_len = 0; + if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI) + esc_len += 1; + if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII) + esc_len += iesc[ISO2022JP_CS_ASCII].esc_len; + if (bufsize < esc_len) + return seterror(E2BIG); + + esc_len = 0; + if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI) + { + memcpy(buf, iso2022_SI_seq, 1); + esc_len += 1; + } + if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII) + { + memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc, + iesc[ISO2022JP_CS_ASCII].esc_len); + esc_len += iesc[ISO2022JP_CS_ASCII].esc_len; + } + return esc_len; + } + return 0; +} +#endif /*USE_MLANG_DLL*/ + + +gpgrt_w32_iconv_t +gpgrt_w32_iconv_open (const char *tocode, const char *fromcode) +{ + gpgrt_w32_iconv_t cd; + + cd = calloc(1, sizeof *cd); + if (!cd) + return (gpgrt_w32_iconv_t)(-1); + + /* reset the errno to prevent reporting wrong error code. + * 0 for unsorted error. */ + _gpg_err_set_errno (0); + if (win_iconv_open(cd, tocode, fromcode)) + return cd; + + free(cd); + + return (gpgrt_w32_iconv_t)(-1); +} + +int +gpgrt_w32_iconv_close (gpgrt_w32_iconv_t cd) +{ + if (cd) + { + free (cd); + } + + return 0; +} + +size_t +gpgrt_w32_iconv (gpgrt_w32_iconv_t cd, + const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft) +{ + size_t r; + + r = win_iconv (cd, inbuf, inbytesleft, outbuf, outbytesleft); + _gpg_err_set_errno (*(cd->_errno())); + return r; +} diff --git a/comm/third_party/libgpg-error/src/w32-lock-obj.h b/comm/third_party/libgpg-error/src/w32-lock-obj.h new file mode 100644 index 0000000000..8ed3084054 --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-lock-obj.h @@ -0,0 +1,38 @@ +/* w32-lock-obj.h - Declaration of the Windows lock object + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#ifndef W32_LOCK_OBJ_H +#define W32_LOCK_OBJ_H + +#define LOCK_ABI_VERSION 1 + +/* The real definition of our lock object. The public definition is + named gpgrt_lock_t and hides this internal structure. */ +#pragma pack(push, 8) +typedef struct +{ + long vers; + volatile long initdone; + volatile long started; + CRITICAL_SECTION csec; +} _gpgrt_lock_t; +#pragma pack(pop) + + +#endif /*W32_LOCK_OBJ_H*/ diff --git a/comm/third_party/libgpg-error/src/w32-lock.c b/comm/third_party/libgpg-error/src/w32-lock.c new file mode 100644 index 0000000000..feed1e6338 --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-lock.c @@ -0,0 +1,161 @@ +/* w32-lock.c - GPGRT lock functions for Windows + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_W32_SYSTEM +# error This module may only be build for Windows. +#endif + +#include +#include +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + +#include "gpgrt-int.h" +#include "lock.h" +#include "w32-lock-obj.h" + + + +static _gpgrt_lock_t * +get_lock_object (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd; + + if (lock->vers != LOCK_ABI_VERSION) + _gpgrt_abort (); + + return lock; +} + + +gpg_err_code_t +_gpgrt_lock_init (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd; + + /* If VERS is zero we assume that no static initialization has been + done, so we setup our ABI version right here. The caller might + have called us to test whether lock support is at all available. */ + if (!lock->vers) + { + if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t)) + _gpgrt_abort (); + lock->vers = LOCK_ABI_VERSION; + } + else /* Run the usual check. */ + { + lock = get_lock_object (lockhd); + if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t)) + _gpgrt_abort (); + } + + InitializeCriticalSection (&lock->csec); + lock->initdone = 1; + return 0; +} + + +gpg_err_code_t +_gpgrt_lock_lock (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + + if (!lock->initdone) + { + if (!InterlockedIncrement (&lock->started)) + { + /* The new value of started is 0. Because the initial value + if the variable was -1 we known that this thread is the + first who needs this lock. Thus we initialize now. All + other threads won't get 0 back from InterlockedIncrement + and thus fall into the wait loop below. We ignore that + STARTED may in theory overflow if this thread starves for + too long. */ + _gpgrt_lock_init (lockhd); + } + else + { + while (!lock->initdone) + Sleep (0); + } + } + + _gpgrt_pre_syscall (); + EnterCriticalSection (&lock->csec); + _gpgrt_post_syscall (); + return 0; +} + + +gpg_err_code_t +_gpgrt_lock_trylock (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + + if (!lock->initdone) + { + if (!InterlockedIncrement (&lock->started)) + { + _gpgrt_lock_init (lockhd); + } + else + { + while (!lock->initdone) + Sleep (0); + } + } + + if (!TryEnterCriticalSection (&lock->csec)) + return GPG_ERR_EBUSY; + return 0; +} + + +gpg_err_code_t +_gpgrt_lock_unlock (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + + if (!lock->initdone) + return GPG_ERR_INV_LOCK_OBJ; + LeaveCriticalSection (&lock->csec); + return 0; +} + + +/* Note: Use this function only if no other thread holds or waits for + this lock. */ +gpg_err_code_t +_gpgrt_lock_destroy (gpgrt_lock_t *lockhd) +{ + _gpgrt_lock_t *lock = get_lock_object (lockhd); + + if (!lock->initdone) + return GPG_ERR_INV_LOCK_OBJ; + DeleteCriticalSection (&lock->csec); + lock->initdone = 0; + lock->started = -1; + return 0; +} diff --git a/comm/third_party/libgpg-error/src/w32-reg.c b/comm/third_party/libgpg-error/src/w32-reg.c new file mode 100644 index 0000000000..8b1bf8a6aa --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-reg.c @@ -0,0 +1,154 @@ +/* w32-reg.c - Windows registry support + * Copyright (C) 2002, 2005, 2010, 2012, 2017 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_W32_SYSTEM +# error This module may only be build for Windows. +#endif + +#include +#include +#include +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + +#include "gpgrt-int.h" + + +/* Return a string from the W32 Registry or NULL in case of error. + * Caller must release the return value. A NULL for root is an alias + * for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. The returned + * string is UTF-8 encoded; ROOT, DIR, and NAME must be plain + * ASCII. */ +char * +_gpgrt_w32_reg_query_string (const char *root, const char *dir, + const char *name) +{ + HKEY root_key, key_handle; + DWORD n1, nbytes, type; + char *result = NULL; + + if (!root) + root_key = HKEY_CURRENT_USER; + else if (!strcmp( root, "HKEY_CLASSES_ROOT")) + root_key = HKEY_CLASSES_ROOT; + else if (!strcmp( root, "HKEY_CURRENT_USER")) + root_key = HKEY_CURRENT_USER; + else if (!strcmp( root, "HKEY_LOCAL_MACHINE")) + root_key = HKEY_LOCAL_MACHINE; + else if (!strcmp( root, "HKEY_USERS")) + root_key = HKEY_USERS; + else if (!strcmp( root, "HKEY_PERFORMANCE_DATA")) + root_key = HKEY_PERFORMANCE_DATA; + else if (!strcmp( root, "HKEY_CURRENT_CONFIG")) + root_key = HKEY_CURRENT_CONFIG; + else + return NULL; + + if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle)) + { + if (root) + return NULL; /* No need for a RegClose, so return direct. */ + /* It seems to be common practise to fall back to HKLM. */ + if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) + return NULL; /* still no need for a RegClose, so return direct */ + } + + + /* FIXME: Use wide functions and convert to utf-8. */ + nbytes = 1; + if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes)) + { + if (root) + goto leave; + /* Try to fallback to HKLM also for a missing value. */ + RegCloseKey (key_handle); + if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) + return NULL; /* Nope. */ + if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes)) + goto leave; + } + n1 = nbytes + 1; + result = xtrymalloc (n1); + if (!result) + goto leave; + if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1)) + { + xfree (result); + result = NULL; + goto leave; + } + result[nbytes] = 0; /* Make sure it is really a string. */ + +#ifndef HAVE_W32CE_SYSTEM /* (Windows CE has no environment.) */ + if (type == REG_EXPAND_SZ && strchr (result, '%')) + { + char *tmp; + + n1 += 1000; + tmp = xtrymalloc (n1 + 1); + if (!tmp) + goto leave; + nbytes = ExpandEnvironmentStrings (result, tmp, n1); + if (nbytes && nbytes > n1) + { + xfree (tmp); + n1 = nbytes; + tmp = xtrymalloc (n1 + 1); + if (!tmp) + goto leave; + nbytes = ExpandEnvironmentStrings (result, tmp, n1); + if (nbytes && nbytes > n1) { + xfree (tmp); /* Oops - truncated, better don't expand at all. */ + goto leave; + } + tmp[nbytes] = 0; + xfree (result); + result = tmp; + } + else if (nbytes) /* Okay, reduce the length. */ + { + tmp[nbytes] = 0; + xfree (result); + result = xtrymalloc (strlen (tmp)+1); + if (!result) + result = tmp; + else + { + strcpy (result, tmp); + xfree (tmp); + } + } + else /* Error - don't expand. */ + { + xfree (tmp); + } + } +#endif + + leave: + RegCloseKey (key_handle); + return result; +} diff --git a/comm/third_party/libgpg-error/src/w32-thread.c b/comm/third_party/libgpg-error/src/w32-thread.c new file mode 100644 index 0000000000..c389635493 --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32-thread.c @@ -0,0 +1,46 @@ +/* w32-thread.c - GPGRT thread functions for Windows + Copyright (C) 2014 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_W32_SYSTEM +# error This module may only be build for Windows. +#endif + +#include +#include +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + +#include "gpgrt-int.h" +#include "thread.h" + + +gpg_err_code_t +_gpgrt_yield (void) +{ + _gpgrt_pre_syscall (); + Sleep (0); + _gpgrt_post_syscall (); + return 0; +} diff --git a/comm/third_party/libgpg-error/src/w32ce-add.h b/comm/third_party/libgpg-error/src/w32ce-add.h new file mode 100644 index 0000000000..c6207bb2bb --- /dev/null +++ b/comm/third_party/libgpg-error/src/w32ce-add.h @@ -0,0 +1,8 @@ +## w32ce-add.h - Snippet to be be included into gpg-error.h. +## (Comments are indicated by a double hash mark) + +/* Substitute for strerror - this one is thread safe. */ +char *_gpg_w32ce_strerror (int err); +#ifdef GPG_ERR_ENABLE_ERRNO_MACROS +# define strerror(a) _gpg_w32ce_strerror (a) +#endif diff --git a/comm/third_party/libgpg-error/tests/Makefile.am b/comm/third_party/libgpg-error/tests/Makefile.am new file mode 100644 index 0000000000..be04df3ccd --- /dev/null +++ b/comm/third_party/libgpg-error/tests/Makefile.am @@ -0,0 +1,44 @@ +# Makefile.am for libgpg-error/tests. +# Copyright (C) 2003 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +## Process this file with automake to produce Makefile.in + +if HAVE_W32CE_SYSTEM +extra_includes = -idirafter $(top_builddir)/src/gpg-extra +else +extra_includes = +endif + +EXTRA_DIST = t-argparse.conf etc/t-argparse.conf + +gpg_error_lib = ../src/libgpg-error.la + +TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64 \ + t-argparse t-logging t-stringutils t-malloc + +AM_CPPFLAGS = -I$(top_builddir)/src $(extra_includes) + +AM_LDFLAGS = -no-install +LDADD = $(gpg_error_lib) @LDADD_FOR_TESTS_KLUDGE@ + +noinst_PROGRAMS = $(TESTS) +noinst_HEADERS = t-common.h + +t_lock_LDADD = $(LDADD) $(LIBMULTITHREAD) +t_poll_LDADD = $(LDADD) $(LIBMULTITHREAD) diff --git a/comm/third_party/libgpg-error/tests/Makefile.in b/comm/third_party/libgpg-error/tests/Makefile.in new file mode 100644 index 0000000000..2640a2bf05 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/Makefile.in @@ -0,0 +1,920 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for libgpg-error/tests. +# Copyright (C) 2003 g10 Code GmbH +# +# This file is part of libgpg-error. +# +# libgpg-error is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# libgpg-error is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +TESTS = t-version$(EXEEXT) t-strerror$(EXEEXT) t-syserror$(EXEEXT) \ + t-lock$(EXEEXT) t-printf$(EXEEXT) t-poll$(EXEEXT) \ + t-b64$(EXEEXT) t-argparse$(EXEEXT) t-logging$(EXEEXT) \ + t-stringutils$(EXEEXT) t-malloc$(EXEEXT) +noinst_PROGRAMS = $(am__EXEEXT_1) +subdir = tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ + $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/estream.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gnupg-misc.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/lock.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/threadlib.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__EXEEXT_1 = t-version$(EXEEXT) t-strerror$(EXEEXT) \ + t-syserror$(EXEEXT) t-lock$(EXEEXT) t-printf$(EXEEXT) \ + t-poll$(EXEEXT) t-b64$(EXEEXT) t-argparse$(EXEEXT) \ + t-logging$(EXEEXT) t-stringutils$(EXEEXT) t-malloc$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +t_argparse_SOURCES = t-argparse.c +t_argparse_OBJECTS = t-argparse.$(OBJEXT) +t_argparse_LDADD = $(LDADD) +t_argparse_DEPENDENCIES = $(gpg_error_lib) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +t_b64_SOURCES = t-b64.c +t_b64_OBJECTS = t-b64.$(OBJEXT) +t_b64_LDADD = $(LDADD) +t_b64_DEPENDENCIES = $(gpg_error_lib) +t_lock_SOURCES = t-lock.c +t_lock_OBJECTS = t-lock.$(OBJEXT) +am__DEPENDENCIES_1 = $(gpg_error_lib) +am__DEPENDENCIES_2 = +t_lock_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +t_logging_SOURCES = t-logging.c +t_logging_OBJECTS = t-logging.$(OBJEXT) +t_logging_LDADD = $(LDADD) +t_logging_DEPENDENCIES = $(gpg_error_lib) +t_malloc_SOURCES = t-malloc.c +t_malloc_OBJECTS = t-malloc.$(OBJEXT) +t_malloc_LDADD = $(LDADD) +t_malloc_DEPENDENCIES = $(gpg_error_lib) +t_poll_SOURCES = t-poll.c +t_poll_OBJECTS = t-poll.$(OBJEXT) +t_poll_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +t_printf_SOURCES = t-printf.c +t_printf_OBJECTS = t-printf.$(OBJEXT) +t_printf_LDADD = $(LDADD) +t_printf_DEPENDENCIES = $(gpg_error_lib) +t_strerror_SOURCES = t-strerror.c +t_strerror_OBJECTS = t-strerror.$(OBJEXT) +t_strerror_LDADD = $(LDADD) +t_strerror_DEPENDENCIES = $(gpg_error_lib) +t_stringutils_SOURCES = t-stringutils.c +t_stringutils_OBJECTS = t-stringutils.$(OBJEXT) +t_stringutils_LDADD = $(LDADD) +t_stringutils_DEPENDENCIES = $(gpg_error_lib) +t_syserror_SOURCES = t-syserror.c +t_syserror_OBJECTS = t-syserror.$(OBJEXT) +t_syserror_LDADD = $(LDADD) +t_syserror_DEPENDENCIES = $(gpg_error_lib) +t_version_SOURCES = t-version.c +t_version_OBJECTS = t-version.$(OBJEXT) +t_version_LDADD = $(LDADD) +t_version_DEPENDENCIES = $(gpg_error_lib) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/t-argparse.Po ./$(DEPDIR)/t-b64.Po \ + ./$(DEPDIR)/t-lock.Po ./$(DEPDIR)/t-logging.Po \ + ./$(DEPDIR)/t-malloc.Po ./$(DEPDIR)/t-poll.Po \ + ./$(DEPDIR)/t-printf.Po ./$(DEPDIR)/t-strerror.Po \ + ./$(DEPDIR)/t-stringutils.Po ./$(DEPDIR)/t-syserror.Po \ + ./$(DEPDIR)/t-version.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = t-argparse.c t-b64.c t-lock.c t-logging.c t-malloc.c \ + t-poll.c t-printf.c t-strerror.c t-stringutils.c t-syserror.c \ + t-version.c +DIST_SOURCES = t-argparse.c t-b64.c t-lock.c t-logging.c t-malloc.c \ + t-poll.c t-printf.c t-strerror.c t-stringutils.c t-syserror.c \ + t-version.c +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GPG_ERROR_CONFIG_CFLAGS = @GPG_ERROR_CONFIG_CFLAGS@ +GPG_ERROR_CONFIG_HOST = @GPG_ERROR_CONFIG_HOST@ +GPG_ERROR_CONFIG_LIBS = @GPG_ERROR_CONFIG_LIBS@ +GPG_ERROR_CONFIG_LIBS_PRIVATE = @GPG_ERROR_CONFIG_LIBS_PRIVATE@ +GPG_ERROR_CONFIG_MT_CFLAGS = @GPG_ERROR_CONFIG_MT_CFLAGS@ +GPG_ERROR_CONFIG_MT_LIBS = @GPG_ERROR_CONFIG_MT_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALLSHELLPATH = @INSTALLSHELLPATH@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGPG_ERROR_LT_AGE = @LIBGPG_ERROR_LT_AGE@ +LIBGPG_ERROR_LT_CURRENT = @LIBGPG_ERROR_LT_CURRENT@ +LIBGPG_ERROR_LT_REVISION = @LIBGPG_ERROR_LT_REVISION@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBREADLINE = @LIBREADLINE@ +LIBS = @LIBS@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_NETWORK = @LIB_NETWORK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@HAVE_W32CE_SYSTEM_FALSE@extra_includes = +@HAVE_W32CE_SYSTEM_TRUE@extra_includes = -idirafter $(top_builddir)/src/gpg-extra +EXTRA_DIST = t-argparse.conf etc/t-argparse.conf +gpg_error_lib = ../src/libgpg-error.la +AM_CPPFLAGS = -I$(top_builddir)/src $(extra_includes) +AM_LDFLAGS = -no-install +LDADD = $(gpg_error_lib) @LDADD_FOR_TESTS_KLUDGE@ +noinst_HEADERS = t-common.h +t_lock_LDADD = $(LDADD) $(LIBMULTITHREAD) +t_poll_LDADD = $(LDADD) $(LIBMULTITHREAD) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +t-argparse$(EXEEXT): $(t_argparse_OBJECTS) $(t_argparse_DEPENDENCIES) $(EXTRA_t_argparse_DEPENDENCIES) + @rm -f t-argparse$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_argparse_OBJECTS) $(t_argparse_LDADD) $(LIBS) + +t-b64$(EXEEXT): $(t_b64_OBJECTS) $(t_b64_DEPENDENCIES) $(EXTRA_t_b64_DEPENDENCIES) + @rm -f t-b64$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_b64_OBJECTS) $(t_b64_LDADD) $(LIBS) + +t-lock$(EXEEXT): $(t_lock_OBJECTS) $(t_lock_DEPENDENCIES) $(EXTRA_t_lock_DEPENDENCIES) + @rm -f t-lock$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_lock_OBJECTS) $(t_lock_LDADD) $(LIBS) + +t-logging$(EXEEXT): $(t_logging_OBJECTS) $(t_logging_DEPENDENCIES) $(EXTRA_t_logging_DEPENDENCIES) + @rm -f t-logging$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_logging_OBJECTS) $(t_logging_LDADD) $(LIBS) + +t-malloc$(EXEEXT): $(t_malloc_OBJECTS) $(t_malloc_DEPENDENCIES) $(EXTRA_t_malloc_DEPENDENCIES) + @rm -f t-malloc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_malloc_OBJECTS) $(t_malloc_LDADD) $(LIBS) + +t-poll$(EXEEXT): $(t_poll_OBJECTS) $(t_poll_DEPENDENCIES) $(EXTRA_t_poll_DEPENDENCIES) + @rm -f t-poll$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_poll_OBJECTS) $(t_poll_LDADD) $(LIBS) + +t-printf$(EXEEXT): $(t_printf_OBJECTS) $(t_printf_DEPENDENCIES) $(EXTRA_t_printf_DEPENDENCIES) + @rm -f t-printf$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_printf_OBJECTS) $(t_printf_LDADD) $(LIBS) + +t-strerror$(EXEEXT): $(t_strerror_OBJECTS) $(t_strerror_DEPENDENCIES) $(EXTRA_t_strerror_DEPENDENCIES) + @rm -f t-strerror$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_strerror_OBJECTS) $(t_strerror_LDADD) $(LIBS) + +t-stringutils$(EXEEXT): $(t_stringutils_OBJECTS) $(t_stringutils_DEPENDENCIES) $(EXTRA_t_stringutils_DEPENDENCIES) + @rm -f t-stringutils$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_stringutils_OBJECTS) $(t_stringutils_LDADD) $(LIBS) + +t-syserror$(EXEEXT): $(t_syserror_OBJECTS) $(t_syserror_DEPENDENCIES) $(EXTRA_t_syserror_DEPENDENCIES) + @rm -f t-syserror$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_syserror_OBJECTS) $(t_syserror_LDADD) $(LIBS) + +t-version$(EXEEXT): $(t_version_OBJECTS) $(t_version_DEPENDENCIES) $(EXTRA_t_version_DEPENDENCIES) + @rm -f t-version$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(t_version_OBJECTS) $(t_version_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-argparse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-b64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-lock.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-logging.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-malloc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-poll.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-printf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-strerror.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-stringutils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-syserror.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-version.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/t-argparse.Po + -rm -f ./$(DEPDIR)/t-b64.Po + -rm -f ./$(DEPDIR)/t-lock.Po + -rm -f ./$(DEPDIR)/t-logging.Po + -rm -f ./$(DEPDIR)/t-malloc.Po + -rm -f ./$(DEPDIR)/t-poll.Po + -rm -f ./$(DEPDIR)/t-printf.Po + -rm -f ./$(DEPDIR)/t-strerror.Po + -rm -f ./$(DEPDIR)/t-stringutils.Po + -rm -f ./$(DEPDIR)/t-syserror.Po + -rm -f ./$(DEPDIR)/t-version.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/t-argparse.Po + -rm -f ./$(DEPDIR)/t-b64.Po + -rm -f ./$(DEPDIR)/t-lock.Po + -rm -f ./$(DEPDIR)/t-logging.Po + -rm -f ./$(DEPDIR)/t-malloc.Po + -rm -f ./$(DEPDIR)/t-poll.Po + -rm -f ./$(DEPDIR)/t-printf.Po + -rm -f ./$(DEPDIR)/t-strerror.Po + -rm -f ./$(DEPDIR)/t-stringutils.Po + -rm -f ./$(DEPDIR)/t-syserror.Po + -rm -f ./$(DEPDIR)/t-version.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \ + check-am clean clean-generic clean-libtool \ + clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgpg-error/tests/etc/t-argparse.conf b/comm/third_party/libgpg-error/tests/etc/t-argparse.conf new file mode 100644 index 0000000000..6559266317 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/etc/t-argparse.conf @@ -0,0 +1,80 @@ +# Global test config file for t-argparse + +# Options applied to all user's config files +#verbose + + +# The meta command echo simply prints the argument. With a dash +# prefix it does not prepend the file name and line number. +[-echo Begin global config] + +[-echo use $${user} to echo the current user (${user})] +[-echo use $${file} to echo the current file (${file})] +[-echo use $${line} to echo the current line (${line})] +[-echo use $${epoch} to echo a timestamp (${epoch})] + +[verbose] + +[user joy] +# All the following options are applied only if the current user's +# account name is "joy" (case-insensitive). This ends with the next +# user statement. This does not affect "echo" and "verbose". + +# info is an alias for echo but only executed if a user secion is active. +# For future compatibility do not use percent or dollar signs. +[-info In user Joy but real user id ${user}] + +[-verbose] +[+force] +# All following option are forced and thus ignored when set in user +# config files. Valid until the next [user] statement. Take care +# that there are often "no-", "disable-", or "enable-" versions of +# options; these should be explictly marked as ignored so that they +# can't be used to override the force attribute. + +[ignore] + +# The compliance is set immutable for these users +verbose + +[-force] +not-my-option + +# If uncommented The next shall raise an error due to the garbage at the end. +#[+ignore] fooo + + +[+ignore-all] +# All options are ignored. + + +[-ignore] # Comment at line end +# Options wich shall not be ignored. */ +#no-verbose + + +# Options applied only for user joy end here. +[user wk ] +[-info Options applied only for user wk follow] + +[ignore] +output +[-ignore] + + +# Change the immutable attribute back to mutable. +[-force] +#compliance gnupg + +# Default key for user john +my-option 42 + +# Options applied only for user joy end here. +[user *] +[-info All the following options are applied only if the] +[-info current user has no specific section above.] + +# The default algorithm for new keys is set to this. +a-long-option + +[-echo End global config] diff --git a/comm/third_party/libgpg-error/tests/t-argparse.c b/comm/third_party/libgpg-error/tests/t-argparse.c new file mode 100644 index 0000000000..8ba5841dbb --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-argparse.c @@ -0,0 +1,168 @@ +/* t-argparse.c - Check the argparse API + * Copyright (C) 2018, 2020 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#define PGM "t-argparse" +#include "t-common.h" + + +static struct { + int verbose; + int debug; + char *outfile; + char *crf; + int myopt; + int echo; + int a_long_one; +} opt; + + + +static const char * +my_strusage (int level) +{ + const char *p; + + switch (level) + { + case 9: p = "LGPL-2.1-or-later"; break; + + case 11: p = "t-argparse"; break; + + default: p = NULL; + } + return p; +} + + + +int +main (int argc, char **argv) +{ + gpgrt_opt_t opts[] = { + ARGPARSE_verbatim("Now for the options:\n"), + ARGPARSE_x ('v', "verbose", NONE, 0, "Laut sein"), + ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, " + "was wir eingegeben haben")), + ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"), + ARGPARSE_s_s('o', "output", 0 ), + ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ), + /* Note that on a non-utf8 terminal the ß might garble the output. */ + ARGPARSE_header("extra-options", "List of extra options"), + ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"), + ARGPARSE_o_i('m', "my-option", 0), + ARGPARSE_o_i('M', "not-my-option", 0), + ARGPARSE_s_n(500, "a-long-option", 0 ), + ARGPARSE_conffile(501, "options", "|FILE|read options from FILE"), + ARGPARSE_noconffile(502, "no-options", "Ignore conf files"), + ARGPARSE_verbatim("This epilog consists\nof only 2 lines\n"), + ARGPARSE_end() + }; + gpgrt_argparse_t pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL + | ARGPARSE_FLAG_MIXED + | ARGPARSE_FLAG_ONEDASH + | ARGPARSE_FLAG_SYS + | ARGPARSE_FLAG_USER + /* | ARGPARSE_FLAG_VERBOSE */ + /* | ARGPARSE_FLAG_WITHATTR */ + ) }; + int i; + const char *srcdir; + int any_warn = 0; + + gpgrt_set_strusage (my_strusage); + srcdir = getenv ("srcdir"); + if (!srcdir) + srcdir = "."; + gpgrt_set_confdir (GPGRT_CONFDIR_USER, srcdir); + { + char *p = gpgrt_fnameconcat (srcdir, "etc", NULL); + gpgrt_set_confdir (GPGRT_CONFDIR_SYS, p); + xfree (p); + } + + while (gpgrt_argparser (&pargs, opts, PGM".conf")) + { + /* printf ("got option %3d type %0x04x\n", pargs.r_opt, pargs.r_type); */ + /* if (pargs.r_type & (ARGPARSE_ATTR_IGNORE|ARGPARSE_ATTR_FORCE)) */ + /* printf ("attributes:%s%s\n", */ + /* (pargs.r_type & ARGPARSE_ATTR_IGNORE)? " ignore":"", */ + /* (pargs.r_type & ARGPARSE_ATTR_FORCE)? " force":""); */ + /* if (pargs.r_type & ARGPARSE_OPT_IGNORE) */ + /* { */ + /* printf ("ignored\n"); */ + /* continue; */ + /* } */ + switch (pargs.r_opt) + { + case ARGPARSE_CONFFILE: + printf ("current conffile='%s'\n", + pargs.r_type? pargs.r.ret_str: "[cmdline]"); + break; + case ARGPARSE_IS_ARG : + printf ("arg='%s'\n", pargs.r.ret_str); + break; + + case 'v': opt.verbose++; break; + case 'e': opt.echo++; break; + case 'd': opt.debug++; debug=1;break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 'M': opt.myopt = 0; break; + case 500: opt.a_long_one++; break; + default : pargs.err = ARGPARSE_PRINT_WARNING; any_warn = 1; break; + } + } + for (i=0; i < argc; i++ ) + printf ("%3d -> (%s)\n", i, argv[i] ); + if (opt.verbose) + puts ("Options:"); + if (opt.verbose) + printf (" verbose=%d\n", opt.verbose ); + if (opt.debug) + printf (" debug=%d\n", opt.debug ); + if (opt.outfile) + printf (" outfile='%s'\n", opt.outfile ); + if (opt.crf) + printf (" crffile='%s'\n", opt.crf ); + if (opt.myopt) + printf (" myopt=%d\n", opt.myopt ); + if (opt.a_long_one) + printf (" a-long-one=%d\n", opt.a_long_one ); + if (opt.echo) + printf (" echo=%d\n", opt.echo ); + + gpgrt_argparse (NULL, &pargs, NULL); + + (void)show; + (void)fail; + (void)die; + + return !!any_warn; +} diff --git a/comm/third_party/libgpg-error/tests/t-argparse.conf b/comm/third_party/libgpg-error/tests/t-argparse.conf new file mode 100644 index 0000000000..431ee7d23a --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-argparse.conf @@ -0,0 +1,16 @@ +# User test config file for t-argparse + +[-echo begin of user config (user=${user})] +[+verbose] +# Options applied to all user's config files +echo + +# The next should be flagged as unexpected meta command. +#[ignore] + +my-option 4711 + +not-my-option + +verbose +[-echo end of user config] diff --git a/comm/third_party/libgpg-error/tests/t-b64.c b/comm/third_party/libgpg-error/tests/t-b64.c new file mode 100644 index 0000000000..0171909a04 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-b64.c @@ -0,0 +1,374 @@ +/* t-b64.c - b64dec tests. + * Copyright (C) 2017, 2018 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#if HAVE_STDLIB_H +#include +#endif + +#define PGM "t-b64" +#include "t-common.h" + +static const char *test_string = "libgpg-error is free software; " + "you can redistribute it and/or modify it under the terms of " + "the GNU Lesser General Public License as published by the Free " + "Software Foundation; either version 2.1 of the License, or " + "(at your option) any later version."; + +static const char *test_string_b64_0 = "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29" + "mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgd" + "W5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIEx" + "pY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb" + "247IGVpdGhlciB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXI" + "gb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4="; + +static const char *test_string_b64_1 = + "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli\n" + "dXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH\n" + "TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5\n" + "IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIu\n" + "MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg\n" + "dmVyc2lvbi4=\n"; + +static const char *test_string_b64_2 = + "-----BEGIN DATA-----\n" + "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli\n" + "dXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH\n" + "TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5\n" + "IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIu\n" + "MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg\n" + "dmVyc2lvbi4=\n" + "-----END DATA-----\n"; + +static const char *test_string_b64_3 = + "-----BEGIN PGP ARMORED FILE-----\n" + "\n" + "bGliZ3BnLWVycm9yIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli\n" + "dXRlIGl0IGFuZC9vciBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBH\n" + "TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5\n" + "IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIu\n" + "MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg\n" + "dmVyc2lvbi4=\n" + "=4BMJ\n" + "-----END PGP ARMORED FILE-----\n"; + +static const char *test_blob_1 = "\x01\x03\x04\xff"; +static const char *test_blob_1_b64_0 = "AQME/w=="; +static const char *test_blob_2 = "\x01\x03\x04\xff""A"; +static const char *test_blob_2_b64_0 = "AQME/0E="; +static const char *test_blob_3 = "\x01\x03\x04\xff""AB"; +static const char *test_blob_3_b64_0 = "AQME/0FC"; + + +#define FAIL(a) do { fail ("line %d: test %d failed\n", __LINE__, (a)); \ + } while(0) + +static gpg_error_t +test_b64enc_string (const char *string, const char *expected, const char *title) +{ + gpg_err_code_t err; + estream_t fp; + gpgrt_b64state_t state; + char *result; + + fp = es_fopenmem (0, "rwb"); + if (!fp) + die ("es_fopenmem failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); + + state = gpgrt_b64enc_start (fp, title); + if (!state) + { + err = gpg_err_code_from_syserror (); + fail ("gpgrt_b64enc_start failed: %s\n", gpg_strerror (err)); + return err; + } + + err = gpgrt_b64enc_write (state, string, strlen (string)); + if (err) + { + fail ("gpgrt_b64enc_write failed: %s\n", gpg_strerror (err)); + return err; + } + + err = gpgrt_b64enc_finish (state); + if (err) + { + fail ("gpgrt_b64enc_finish failed: %s\n", gpg_strerror (err)); + return err; + } + + es_fputc (0, fp); + if (es_fclose_snatch (fp, (void**)&result, NULL)) + die ("es_fclose_snatch failed: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + + if (strcmp (result, expected)) + { + if (verbose) + { + gpgrt_log_debug_string (result, "result: "); + gpgrt_log_debug_string (expected, "expect: "); + } + return GPG_ERR_FALSE; + } + + es_free (result); + return 0; +} + + +static gpg_error_t +test_b64dec_string (const char *string, const char *expected, const char *title) +{ + gpg_error_t err; + gpgrt_b64state_t state; + char *buffer; + size_t len; + + len = strlen (string); + buffer = malloc (strlen (string) + 1); + if (!buffer) + { + err = gpg_error_from_syserror (); + return err; + } + strcpy (buffer, string); + + state = gpgrt_b64dec_start (title); + if (!state) + { + err = gpg_err_code_from_syserror (); + fail ("gpgrt_b64dec_start failed: %s\n", gpg_strerror (err)); + free (buffer); + return err; + } + + err = gpgrt_b64dec_proc (state, buffer, len, &len); + if (err) + { + if (gpg_err_code (err) != GPG_ERR_EOF) + { + free (buffer); + free (state); + return err; + } + } + + err = gpgrt_b64dec_finish (state); + if (err) + { + free (buffer); + return err; + } + + if (len != strlen (expected) || strncmp (buffer, expected, len)) + { + if (verbose) + { + gpgrt_log_debug_string (buffer, "result(len=%zu): ", len); + gpgrt_log_debug_string (expected, "expect(len=%zu): ", + strlen (expected)); + } + return GPG_ERR_FALSE; + } + + free (buffer); + return 0; +} + + +static void +encoder_tests (void) +{ + gpg_err_code_t err; + + if (verbose) + show ("running encoder tests\n"); + + err = test_b64enc_string (test_string, test_string_b64_0, ""); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string (test_string, test_string_b64_1, NULL); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string (test_string, test_string_b64_2, "DATA"); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string (test_string, test_string_b64_3, "PGP ARMORED FILE"); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + + /* Note that the _test_ function dows not allow to provide a string + * with an empdded Nul. */ + err = test_b64enc_string (test_blob_1, test_blob_1_b64_0, ""); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string (test_blob_2, test_blob_2_b64_0, ""); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string (test_blob_3, test_blob_3_b64_0, ""); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + + err = test_b64enc_string ("@", "QA==", ""); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string ("@", "QA==\n", NULL); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string ("@", + "-----BEGIN PGP SOMETHING-----\n" + "\n" + "QA==\n" + "=eMoB\n" + "-----END PGP SOMETHING-----\n", + "PGP SOMETHING"); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + + err = test_b64enc_string ("", "", ""); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string ("", "", NULL); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + err = test_b64enc_string ("", "", "PGP SOMETHING"); + if (err) + fail ("encoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); +} + + +static void +decoder_tests (void) +{ + gpg_err_code_t err; + + if (verbose) + show ("running decoder tests\n"); + + err = test_b64dec_string (test_string_b64_0, test_string, NULL); + if (err) + fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + + err = test_b64dec_string (test_string_b64_1, test_string, NULL); + if (err) + fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + + err = test_b64dec_string (test_string_b64_2, test_string, ""); + if (err) + fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + + err = test_b64dec_string (test_string_b64_2, test_string, NULL); + if (err != GPG_ERR_BAD_DATA) + fail ("decoder test at line %d failed: %s\n", __LINE__, gpg_strerror (err)); + +} + + +static gpg_error_t +extra_tests (void) +{ + gpg_err_code_t err; + gpgrt_b64state_t state; + + if (verbose) + show ("running extra tests\n"); + + /* Check that we detect mismacthed use of enc and dec functions. */ + state = gpgrt_b64enc_start (es_stdout, NULL); + if (!state) + { + err = gpg_err_code_from_syserror (); + fail ("gpgrt_b64enc_start failed: %s\n", gpg_strerror (err)); + return err; + } + + err = gpgrt_b64dec_finish (state); + if (err != GPG_ERR_CONFLICT) + { + fail ("gpgrt_b64dec_finish failed: %s\n", gpg_strerror (err)); + return err; + } + + state = gpgrt_b64dec_start (NULL); + if (!state) + { + err = gpg_err_code_from_syserror (); + fail ("gpgrt_b64dec_start failed: %s\n", gpg_strerror (err)); + return err; + } + + err = gpgrt_b64enc_finish (state); + if (err != GPG_ERR_CONFLICT) + { + fail ("gpgrt_b64enc_finish failed: %s\n", gpg_strerror (err)); + return err; + } + + return 0; +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--help")) + { + puts ( +"usage: ./" PGM " [options]\n" +"\n" +"Options:\n" +" --verbose Show what is going on\n" +" --debug Flyswatter\n" +); + exit (0); + } + if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + } + + encoder_tests (); + decoder_tests (); + extra_tests (); + + return !!errorcount; +} diff --git a/comm/third_party/libgpg-error/tests/t-common.h b/comm/third_party/libgpg-error/tests/t-common.h new file mode 100644 index 0000000000..db496e20fc --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-common.h @@ -0,0 +1,136 @@ +/* t-common.h - Common code for the tests. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include + +#include "../src/gpgrt.h" + +#ifndef PGM +# error Macro PGM not defined. +#endif +#ifndef DIM +# define DIM(array) (sizeof (array) / sizeof (*array)) +#endif + + +static int verbose; +static int debug; +static int errorcount; + + +static void die (const char *format, ...) GPGRT_ATTR_NR_PRINTF(1,2); +static void fail (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); +static void show (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); + + +static void * +xmalloc (size_t n) +{ + char *p = gpgrt_malloc (n); + if (!p) + die ("out of core\n"); + return p; +} + +static char * +xstrdup (const char *s) +{ + char *p = gpgrt_strdup (s); + if (!p) + die ("out of core\n"); + return p; +} + +static void +xfree (void *p) +{ + if (p) + gpgrt_free (p); +} + + + +static void +die (const char *format, ...) +{ + va_list arg_ptr ; + + fflush (stdout); +#ifdef HAVE_FLOCKFILE + flockfile (stderr); +#endif + fprintf (stderr, "%s: ", PGM); + va_start (arg_ptr, format) ; + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); +#ifdef HAVE_FLOCKFILE + funlockfile (stderr); +#endif + xfree (xstrdup ("")); /* To avoid compiler warnings. */ + xfree (xmalloc (16)); /* To avoid compiler warnings. */ + exit (1); +} + + +static void +fail (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); +#ifdef HAVE_FLOCKFILE + flockfile (stderr); +#endif + fprintf (stderr, "%s: ", PGM); + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); +#ifdef HAVE_FLOCKFILE + funlockfile (stderr); +#endif + errorcount++; + if (errorcount >= 50) + die ("stopped after 50 errors."); +} + + +static void +show (const char *format, ...) +{ + va_list arg_ptr; + + if (!verbose) + return; +#ifdef HAVE_FLOCKFILE + flockfile (stderr); +#endif + fprintf (stderr, "%s: ", PGM); + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + if (*format && format[strlen(format)-1] != '\n') + putc ('\n', stderr); + va_end (arg_ptr); +#ifdef HAVE_FLOCKFILE + funlockfile (stderr); +#endif +} diff --git a/comm/third_party/libgpg-error/tests/t-lock.c b/comm/third_party/libgpg-error/tests/t-lock.c new file mode 100644 index 0000000000..6add18b8ca --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-lock.c @@ -0,0 +1,333 @@ +/* t-lock.c - Check the lock functions + * Copyright (C) 2013, 2015 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +# include +#else +# ifdef USE_POSIX_THREADS +# include +# endif +#endif + +#define PGM "t-lock" + +#include "t-common.h" + +#ifdef _WIN32 +# define THREAD_RET_TYPE DWORD WINAPI +# define THREAD_RET_VALUE 0 +#else +# define THREAD_RET_TYPE void * +# define THREAD_RET_VALUE NULL +#endif + + +/* Our tests works by having a a couple of accountant threads which do + random transactions between accounts and a revision threads which + checks that the balance of all accounts is invariant. The idea for + this check is due to Bruno Haible. */ +#define N_ACCOUNT 8 +#define ACCOUNT_VALUE 42 +static int account[N_ACCOUNT]; +GPGRT_LOCK_DEFINE (accounts_lock); + +/* Number of transactions done by each accountant. */ +#define N_TRANSACTIONS 1000 + +/* Number of accountants to run. */ +#define N_ACCOUNTANTS 5 + +/* Maximum transaction value. A quite low value is used so that we + would get an integer overflow. */ +#define MAX_TRANSACTION_VALUE 50 + +/* Flag to tell the revision thread to finish. */ +static volatile int stop_revision_thread; + + +/* Initialze all accounts. */ +static void +init_accounts (void) +{ + int i; + + for (i=0; i < N_ACCOUNT; i++) + account[i] = ACCOUNT_VALUE; +} + + +/* Check that the sum of all accounts matches the initial sum. */ +static void +check_accounts (void) +{ + int i, sum; + + sum = 0; + for (i = 0; i < N_ACCOUNT; i++) + sum += account[i]; + if (sum != N_ACCOUNT * ACCOUNT_VALUE) + die ("accounts out of balance"); +} + + +static void +print_accounts (void) +{ + int i; + + for (i=0; i < N_ACCOUNT; i++) + printf ("account %d: %6d\n", i, account[i]); +} + + +#if defined(_WIN32) || defined(USE_POSIX_THREADS) +/* Get a a random integer value in the range 0 to HIGH. */ +static unsigned int +get_rand (int high) +{ + return (unsigned int)(1+(int)((double)(high+1)*rand ()/(RAND_MAX+1.0))) - 1; +} + + +/* Pick a random account. Note that this function is not + thread-safe. */ +static int +pick_account (void) +{ + return get_rand (N_ACCOUNT - 1); +} + + +/* Pick a random value for a transaction. This is not thread-safe. */ +static int +pick_value (void) +{ + return get_rand (MAX_TRANSACTION_VALUE); +} + + +/* This is the revision department. */ +static THREAD_RET_TYPE +revision_thread (void *arg) +{ + gpg_err_code_t rc; + int i = 0; + + (void)arg; + + while (!stop_revision_thread) + { + rc = gpgrt_lock_lock (&accounts_lock); + if (rc) + fail ("gpgrt_lock_lock failed at %d: %s", __LINE__, gpg_strerror (rc)); + + check_accounts (); + rc = gpgrt_lock_unlock (&accounts_lock); + if (rc) + fail ("gpgrt_lock_unlock failed at %d: %s", __LINE__,gpg_strerror (rc)); + if (!(++i%7)) + gpgrt_yield (); + } + return THREAD_RET_VALUE; +} + + +/* This is one of our accountants. */ +static THREAD_RET_TYPE +accountant_thread (void *arg) +{ + gpg_err_code_t rc; + int i; + int acc1, acc2; + int value; + + (void)arg; + +#ifdef _WIN32 + srand (time(NULL)*getpid()); /* Windows needs it per thread. */ +#endif + for (i = 0; i < N_TRANSACTIONS; i++) + { + rc = gpgrt_lock_lock (&accounts_lock); + if (rc) + fail ("gpgrt_lock_lock failed at %d: %s", __LINE__, gpg_strerror (rc)); + + acc1 = pick_account (); + acc2 = pick_account (); + value = pick_value (); + account[acc1] += value; + account[acc2] -= value; + + rc = gpgrt_lock_unlock (&accounts_lock); + if (rc) + fail ("gpgrt_lock_unlock failed at %d: %s", __LINE__,gpg_strerror (rc)); + if (i && !(i%8)) + gpgrt_yield (); + } + return THREAD_RET_VALUE; +} +#endif /*_WIN32||USE_POSIX_THREADS*/ + + +static void +run_test (void) +{ +#ifdef _WIN32 + HANDLE rthread; + HANDLE athreads[N_ACCOUNTANTS]; + int i; + int rc; + + stop_revision_thread = 0; + rthread = CreateThread (NULL, 0, revision_thread, NULL, 0, NULL); + if (!rthread) + die ("error creating revision thread: rc=%d", (int)GetLastError ()); + + for (i=0; i < N_ACCOUNTANTS; i++) + { + athreads[i] = CreateThread (NULL, 0, accountant_thread, NULL, 0, NULL); + if (!athreads[i]) + die ("error creating accountant thread %d: rc=%d", + i, (int)GetLastError ()); + } + + for (i=0; i < N_ACCOUNTANTS; i++) + { + rc = WaitForSingleObject (athreads[i], INFINITE); + if (rc == WAIT_OBJECT_0) + show ("accountant thread %d has terminated", i); + else + fail ("waiting for accountant thread %d failed: %d", + i, (int)GetLastError ()); + CloseHandle (athreads[i]); + } + stop_revision_thread = 1; + + rc = WaitForSingleObject (rthread, INFINITE); + if (rc == WAIT_OBJECT_0) + show ("revision thread has terminated"); + else + fail ("waiting for revision thread failed: %d", (int)GetLastError ()); + CloseHandle (rthread); + +#else /*!_WIN32*/ +# ifdef USE_POSIX_THREADS + pthread_t rthread; + pthread_t athreads[N_ACCOUNTANTS]; + int i; + + stop_revision_thread = 0; + pthread_create (&rthread, NULL, revision_thread, NULL); + + for (i=0; i < N_ACCOUNTANTS; i++) + pthread_create (&athreads[i], NULL, accountant_thread, NULL); + + for (i=0; i < N_ACCOUNTANTS; i++) + { + pthread_join (athreads[i], NULL); + show ("accountant thread %d has terminated", i); + } + + stop_revision_thread = 1; + pthread_join (rthread, NULL); + show ("revision thread has terminated"); +# else /*!USE_POSIX_THREADS*/ + verbose++; + show ("no thread support - skipping test\n", PGM); + verbose--; +# endif /*!USE_POSIX_THREADS*/ +#endif /*!_WIN32*/ + + gpgrt_lock_destroy (&accounts_lock); +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + int rc; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--help")) + { + puts ( +"usage: ./t-lock [options]\n" +"\n" +"Options:\n" +" --verbose Show what is going on\n" +" --debug Flyswatter\n" +); + exit (0); + } + if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + } + + srand (time(NULL)*getpid()); + + if (!gpg_error_check_version (GPG_ERROR_VERSION)) + { + die ("gpg_error_check_version returned an error"); + errorcount++; + } + + init_accounts (); + check_accounts (); + run_test (); + check_accounts (); + /* Run a second time to check deinit code. */ + run_test (); + check_accounts (); + /* And a third time to test an explicit init. */ + rc = gpgrt_lock_init (&accounts_lock); + if (rc) + fail ("gpgrt_lock_init failed at %d: %s", __LINE__, gpg_strerror (rc)); + run_test (); + check_accounts (); + if (verbose) + print_accounts (); + + return errorcount ? 1 : 0; +} diff --git a/comm/third_party/libgpg-error/tests/t-logging.c b/comm/third_party/libgpg-error/tests/t-logging.c new file mode 100644 index 0000000000..4fcb64b518 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-logging.c @@ -0,0 +1,250 @@ +/* t-logging.c - Check the logging interface + * Copyright (C) 2018 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#define PGM "t-logging" +#include "t-common.h" + +/* The memory based estream we use for logging. */ +static estream_t logmemfp; + + +static const char * +my_strusage (int level) +{ + const char *p; + + switch (level) + { + case 9: p = "LGPL-2.1-or-later"; break; + case 11: p = PGM; break; + default: p = NULL; + } + return p; +} + + +/* Read all data from the log stream into a new malloced buffer and return + * that buffer. The buffer is always 0 terminated. Either returns a + * string or dies. The stream will be truncated to zero. */ +static char * +log_to_string (void) +{ +#define NCHUNK 1024 + estream_t stream = gpgrt_log_get_stream (); + char *buffer; + size_t bufsize, buflen; + size_t nread; + + gpgrt_log_flush (); + gpgrt_rewind (stream); + + buffer = NULL; + buflen = bufsize = 0; + do + { + bufsize += NCHUNK; + buffer = realloc (buffer, bufsize+1); + if (!buffer) + die ("malloc failed at line %d\n", __LINE__); + + nread = gpgrt_fread (buffer + buflen, 1, NCHUNK, stream); + if (nread < NCHUNK && gpgrt_ferror (stream)) + die ("fread failed at line %d: %s\n", __LINE__, + gpg_strerror (gpg_err_code_from_syserror ())); + buflen += nread; + } + while (nread == NCHUNK); + buffer[nread] = 0; + + if (strlen (buffer) != buflen) + fail ("stream_to_string detected an embedded nul"); + + gpgrt_ftruncate (stream, 0); + return buffer; +#undef NCHUNK +} + + +static void +check_log_info (void) +{ + char *logbuf; + + log_info ("first log\n"); + logbuf = log_to_string (); + if (strcmp (logbuf, "t-logging: first log\n")) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + + /* The second line should not have a LF. */ + log_info ("second log line"); + log_info ("third log line"); + logbuf = log_to_string (); + if (strcmp (logbuf, ("t-logging: second log line\n" + "t-logging: third log line"))) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + + /* Now a multi line log. */ + log_info ("This is log line 1\nand 2\nand 3\n"); + logbuf = log_to_string (); + if (strcmp (logbuf, ("t-logging: This is log line 1\n" + "and 2\n" + "and 3\n"))) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + + /* With arguments. */ + log_info ("file '%s' line %d: %s\n", "/foo/bar.txt", 20, "not found"); + logbuf = log_to_string (); + if (strcmp (logbuf, "t-logging: file '/foo/bar.txt' line 20: not found\n")) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + + /* With arguments and a control char in the string arg. */ + log_info ("file '%s' line %d: %s\n", "/foo/bar.txt\b", 20, "not found"); + logbuf = log_to_string (); + if (strcmp (logbuf, + "t-logging: file '/foo/bar.txt\\b' line 20: not found\n")) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + + /* With arguments and the prefix in a string arg. */ + log_info ("file '%s': %s\n", "/foo/bar.txt\nt-logging", "not \x01 found"); + logbuf = log_to_string (); + if (strcmp (logbuf, + "t-logging: file '/foo/bar.txt\\nt-logging': not \\x01 found\n")) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + + /* With arguments and byte with bit 7 set in a string arg. */ + log_info ("file '%s': %s\n", "/foo/bar.txt\n", "not \x81 found"); + logbuf = log_to_string (); + if (strcmp (logbuf, + "t-logging: file '/foo/bar.txt\\n': not \x81 found\n")) + fail ("log_info test failed at line %d\n", __LINE__); + /* show ("===>%s<===\n", logbuf); */ + + free (logbuf); +} + + +static void +check_with_pid (void) +{ + char testbuf[100]; + char *logbuf; + + snprintf (testbuf, sizeof testbuf, "t-logging[%u]: ", + (unsigned int)getpid ()); + + log_info ("first log\n"); + logbuf = log_to_string (); + if (strncmp (logbuf, testbuf, strlen (testbuf)) + || strcmp (logbuf+strlen (testbuf), "first log\n")) + fail ("log_with_pid test failed at line %d\n", __LINE__); + free (logbuf); + + log_info ("This is log line 1\nand 2\nand 3\n"); + logbuf = log_to_string (); + if (strncmp (logbuf, testbuf, strlen (testbuf)) + || strcmp (logbuf+strlen (testbuf), ("This is log line 1\n" + "and 2\n" + "and 3\n"))) + fail ("log_with_pid test failed at line %d\n", __LINE__); + free (logbuf); +} + + +static void +check_log_error (void) +{ + char *logbuf; + + if (log_get_errorcount (0)) + fail ("log_get_errorcount() != 0 at line %d\n", __LINE__); + + log_error ("Hola, something went wrong\n"); + if (log_get_errorcount (0) != 1) + fail ("log_get_errorcount() != 1 at line %d\n", __LINE__); + logbuf = log_to_string (); + if (strcmp (logbuf, "t-logging: Hola, something went wrong\n")) + fail ("log_info test failed at line %d\n", __LINE__); + free (logbuf); + if (log_get_errorcount (0) != 1) + fail ("log_get_errorcount() != 1 at line %d\n", __LINE__); + if (log_get_errorcount (1) != 1) /* note: clear returns old value. */ + fail ("log_get_errorcount() != 1 at line %d\n", __LINE__); + if (log_get_errorcount (0)) + fail ("log_get_errorcount() != 0 after clear at line %d\n", __LINE__); +} + + +int +main (int argc, char **argv) +{ + gpgrt_opt_t opts[] = { + ARGPARSE_x ('v', "verbose", NONE, 0, "Print more diagnostics"), + ARGPARSE_s_n('d', "debug", "Flyswatter"), + ARGPARSE_end() + }; + gpgrt_argparse_t pargs = { &argc, &argv, 0 }; + + gpgrt_set_strusage (my_strusage); + gpgrt_log_set_prefix (gpgrt_strusage (11), GPGRT_LOG_WITH_PREFIX); + + while (gpgrt_argparse (NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case 'v': verbose++; break; + case 'd': debug++; break; + default : pargs.err = ARGPARSE_PRINT_ERROR; break; + } + } + gpgrt_argparse (NULL, &pargs, NULL); + + show ("testing logging using a memory log stream\n"); + logmemfp = gpgrt_fopenmem (0, "w+b"); + if (!logmemfp) + die ("fopenmem failed at line %d\n", __LINE__); + gpgrt_log_set_sink (NULL, logmemfp, -1); + + check_log_info (); + gpgrt_log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_WITH_PID); + check_with_pid (); + gpgrt_log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX); + check_log_error (); + + /* FIXME: Add more tests. */ + + show ("testing logging finished\n"); + return !!errorcount; +} diff --git a/comm/third_party/libgpg-error/tests/t-malloc.c b/comm/third_party/libgpg-error/tests/t-malloc.c new file mode 100644 index 0000000000..be2ec81d73 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-malloc.c @@ -0,0 +1,141 @@ +/* t-malloc.c - Check some malloc functions + * Copyright (C) 2020 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define PGM "t-malloc" +#include "t-common.h" + + +static const char * +my_strusage (int level) +{ + const char *p; + + switch (level) + { + case 9: p = "LGPL-2.1-or-later"; break; + case 11: p = PGM; break; + default: p = NULL; + } + return p; +} + + +static void +check_reallocarray (void) +{ + struct foo_s { const char *a; int b; } *array; + size_t n; + + array = gpgrt_calloc (10, sizeof *array); + if (!array) + die ("%s: malloc failed\n", __func__); + + for (n=0; n < 10; n++) + if (array[n].a || array[n].b) + fail ("%s: array not cleared at index %zu\n", __func__, n); + + for (n=0; n < 10; n++) + { + array[n].a = "dummy string"; + array[n].b = 100+n; + } + + array = gpgrt_reallocarray (array, 10, 20, sizeof *array); + if (!array) + die ("%s: realloc failed\n", __func__); + + for (n=0; n < 10; n++) + { + if (!array[n].a || strcmp (array[n].a, "dummy string")) + fail ("%s: string in realloced array changed at index %zu\n", + __func__, n); + + if (array[n].b != 100 + n) + fail ("%s: number in realloced array changed at index %zu\n", + __func__, n); + } + for (n=10; n < 20; n++) + if (array[n].a || array[n].b) + fail ("%s: realloced array not cleared at index %zu\n", __func__, n); + + /* We can't easily check whether the reallocated array does not + * iniitialze in the case OLDN is equal or larger to N, so we skip + * this. Let's do a simple shrink test instead. */ + + array = gpgrt_reallocarray (array, 20, 7, sizeof *array); + if (!array) + die ("%s: realloc (shrinking) failed\n", __func__); + + for (n=0; n < 7; n++) + { + if (!array[n].a || strcmp (array[n].a, "dummy string")) + fail ("%s: string in shrunk array changed at index %zu\n", + __func__, n); + + if (array[n].b != 100 + n) + fail ("%s: number in shrunk array changed at index %zu\n", + __func__, n); + } + + xfree (array); +} + + +int +main (int argc, char **argv) +{ + gpgrt_opt_t opts[] = { + ARGPARSE_x ('v', "verbose", NONE, 0, "Print more diagnostics"), + ARGPARSE_s_n('d', "debug", "Flyswatter"), + ARGPARSE_end() + }; + gpgrt_argparse_t pargs = { &argc, &argv, 0 }; + + gpgrt_set_strusage (my_strusage); + gpgrt_log_set_prefix (gpgrt_strusage (11), GPGRT_LOG_WITH_PREFIX); + + while (gpgrt_argparse (NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case 'v': verbose++; break; + case 'd': debug++; break; + default : pargs.err = ARGPARSE_PRINT_ERROR; break; + } + } + gpgrt_argparse (NULL, &pargs, NULL); + + show ("testing malloc functions\n"); + + check_reallocarray (); + + return !!errorcount; +} diff --git a/comm/third_party/libgpg-error/tests/t-poll.c b/comm/third_party/libgpg-error/tests/t-poll.c new file mode 100644 index 0000000000..ec79416b61 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-poll.c @@ -0,0 +1,440 @@ +/* t-poll.c - Check the poll function + * Copyright (C) 2015 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* FIXME: We need much better tests that this very basic one. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +# include +#else +# ifdef USE_POSIX_THREADS +# include +# endif +#endif + +#define PGM "t-poll" + +#include "t-common.h" + +#ifdef _WIN32 +# define THREAD_RET_TYPE DWORD WINAPI +# define THREAD_RET_VALUE 0 +#else +# define THREAD_RET_TYPE void * +# define THREAD_RET_VALUE NULL +#endif + + +/* Object to convey data to a thread. */ +struct thread_arg +{ + const char *name; + estream_t stream; + volatile int stop_me; +#ifdef USE_POSIX_THREADS + pthread_t thread; +#elif _WIN32 + HANDLE thread; +#endif +}; + + +static struct thread_arg peer_stdin; /* Thread to feed the stdin. */ +static struct thread_arg peer_stdout; /* Thread to feed the stdout. */ +static struct thread_arg peer_stderr; /* Thread to feed the stderr. */ + +static estream_t test_stdin; +static estream_t test_stdout; +static estream_t test_stderr; + +#if defined(_WIN32) || defined(USE_POSIX_THREADS) + +/* This thread feeds data to the given stream. */ +static THREAD_RET_TYPE +producer_thread (void *argaddr) +{ + struct thread_arg *arg = argaddr; + int i = 0; + + (void)arg; + + while (!arg->stop_me && i++ < 3) + { + show ("thread '%s' about to write\n", arg->name); + es_fprintf (arg->stream, "This is '%s' count=%d\n", arg->name, i); + es_fflush (arg->stream); + } + es_fclose (arg->stream); + return THREAD_RET_VALUE; +} + +/* This thread eats data from the given stream. */ +static THREAD_RET_TYPE +consumer_thread (void *argaddr) +{ + struct thread_arg *arg = argaddr; + char buf[15]; + + (void)arg; + + while (!arg->stop_me) + { + show ("thread '%s' ready to read\n", arg->name); + if (!es_fgets (buf, sizeof buf, arg->stream)) + { + show ("Thread '%s' received EOF or error\n", arg->name); + break; + } + show ("Thread '%s' got: '%s'\n", arg->name, buf); + } + es_fclose (arg->stream); + return THREAD_RET_VALUE; +} + +#endif /*_WIN32 || USE_POSIX_THREADS */ + + +static void +launch_thread (THREAD_RET_TYPE (*fnc)(void *), struct thread_arg *th) +{ + int fd; + + th->stop_me = 0; + fd = es_fileno (th->stream); +#ifdef _WIN32 + + th->thread = CreateThread (NULL, 0, fnc, th, 0, NULL); + if (!th->thread) + die ("creating thread '%s' failed: rc=%d", th->name, (int)GetLastError ()); + show ("thread '%s' launched (fd=%d)\n", th->name, fd); + +#elif USE_POSIX_THREADS + + if (pthread_create (&th->thread, NULL, fnc, th)) + die ("creating thread '%s' failed: %s\n", th->name, strerror (errno)); + show ("thread '%s' launched (fd=%d)\n", th->name, fd); + +# else /* no thread support */ + + verbose++; + show ("no thread support - skipping test\n", PGM); + verbose--; + +#endif /* no thread support */ +} + + +static void +join_thread (struct thread_arg *th) +{ +#ifdef _WIN32 + int rc; + + rc = WaitForSingleObject (th->thread, INFINITE); + if (rc == WAIT_OBJECT_0) + show ("thread '%s' has terminated\n", th->name); + else + fail ("waiting for thread '%s' failed: %d", th->name, (int)GetLastError ()); + CloseHandle (th->thread); + +#elif USE_POSIX_THREADS + + pthread_join (th->thread, NULL); + show ("thread '%s' has terminated\n", th->name); + +#endif +} + + +static void +create_pipe (estream_t *r_in, estream_t *r_out) +{ + gpg_error_t err; + int filedes[2]; + +#ifdef _WIN32 + if (_pipe (filedes, 512, 0) == -1) +#else + if (pipe (filedes) == -1) +#endif + { + err = gpg_error_from_syserror (); + die ("error creating a pipe: %s\n", gpg_strerror (err)); + } + + show ("created pipe [%d, %d]\n", filedes[0], filedes[1]); + + *r_in = es_fdopen (filedes[0], "r,pollable"); + if (!*r_in) + { + err = gpg_error_from_syserror (); + die ("error creating a stream for a pipe: %s\n", gpg_strerror (err)); + } + + *r_out = es_fdopen (filedes[1], "w,pollable"); + if (!*r_out) + { + err = gpg_error_from_syserror (); + die ("error creating a stream for a pipe: %s\n", gpg_strerror (err)); + } +} + + +static void +test_poll (void) +{ + int ret; + gpgrt_poll_t fds[3]; + char buffer[16]; + size_t used, nwritten; + int c; + + memset (fds, 0, sizeof fds); + fds[0].stream = test_stdin; + fds[0].want_read = 1; + fds[1].stream = test_stdout; + fds[1].want_write = 1; + /* FIXME: We don't use the next stream at all. */ + fds[2].stream = test_stderr; + fds[2].want_write = 1; + fds[2].ignore = 1; + + + used = 0; + while (used || !fds[0].ignore) + { + ret = gpgrt_poll (fds, DIM(fds), -1); + if (ret == -1) + { + fail ("gpgrt_poll failed: %s\n", strerror (errno)); + continue; + } + if (!ret) + { + fail ("gpgrt_poll unexpectedly timed out\n"); + continue; + } + + show ("gpgrt_poll detected %d events\n", ret); + if (debug) + show ("gpgrt_poll: r=%d" + " 0:%c%c%c%c%c%c%c%c%c%c%c%c" + " 1:%c%c%c%c%c%c%c%c%c%c%c%c" + " 2:%c%c%c%c%c%c%c%c%c%c%c%c" + "\n", + ret, + fds[0].want_read? 'r':'-', + fds[0].want_write? 'w':'-', + fds[0].want_oob? 'o':'-', + fds[0].want_rdhup? 'h':'-', + fds[0].ignore? '!':'=', + fds[0].got_read? 'r':'-', + fds[0].got_write? 'w':'-', + fds[0].got_oob? 'o':'-', + fds[0].got_rdhup? 'h':'-', + fds[0].got_hup? 'H':' ', + fds[0].got_err? 'e':' ', + fds[0].got_nval? 'n':' ', + + fds[1].want_read? 'r':'-', + fds[1].want_write? 'w':'-', + fds[1].want_oob? 'o':'-', + fds[1].want_rdhup? 'h':'-', + fds[1].ignore? '!':'=', + fds[1].got_read? 'r':'-', + fds[1].got_write? 'w':'-', + fds[1].got_oob? 'o':'-', + fds[1].got_rdhup? 'h':'-', + fds[1].got_hup? 'H':' ', + fds[1].got_err? 'e':' ', + fds[1].got_nval? 'n':' ', + + fds[2].want_read? 'r':'-', + fds[2].want_write? 'w':'-', + fds[2].want_oob? 'o':'-', + fds[2].want_rdhup? 'h':'-', + fds[2].ignore? '!':'=', + fds[2].got_read? 'r':'-', + fds[2].got_write? 'w':'-', + fds[2].got_oob? 'o':'-', + fds[2].got_rdhup? 'h':'-', + fds[2].got_hup? 'H':' ', + fds[2].got_err? 'e':' ', + fds[2].got_nval? 'n':' ' + ); + else + show ("gpgrt_poll detected %d events\n", ret); + + if (fds[0].got_read) + { + /* Read from the producer. */ + for (;;) + { + c = es_fgetc (fds[0].stream); + if (c == EOF) + { + if (es_feof (fds[0].stream)) + { + show ("reading '%s': EOF\n", peer_stdin.name); + fds[0].ignore = 1; /* Not anymore needed. */ + peer_stdin.stop_me = 1; /* Tell the thread to stop. */ + } + else if (es_ferror (fds[0].stream)) + { + fail ("error reading '%s': %s\n", + peer_stdin.name, strerror (errno)); + fds[0].ignore = 1; /* Disable. */ + peer_stdin.stop_me = 1; /* Tell the thread to stop. */ + } + else + show ("reading '%s': EAGAIN\n", peer_stdin.name); + break; + } + else + { + if (used <= sizeof buffer -1) + buffer[used++] = c; + if (used == sizeof buffer) + { + show ("throttling reading from '%s'\n", peer_stdin.name); + fds[0].ignore = 1; + break; + } + } + } + show ("read from '%s': %zu bytes\n", peer_stdin.name, used); + if (used) + fds[1].ignore = 0; /* Data to send. */ + } + if (fds[1].got_write) + { + if (used) + { + ret = es_write (fds[1].stream, buffer, used, &nwritten); + show ("result for writing to '%s': ret=%d, n=%zu, nwritten=%zu\n", + peer_stdout.name, ret, used, nwritten); + if (!ret) + { + assert (nwritten <= used); + /* Move the remaining data to the front of buffer. */ + memmove (buffer, buffer + nwritten, + sizeof buffer - nwritten); + used -= nwritten; + } + ret = es_fflush (fds[1].stream); + if (ret) + fail ("Flushing for '%s' failed: %s\n", + peer_stdout.name, strerror (errno)); + } + if (!used) + fds[1].ignore = 1; /* No need to send data. */ + } + + if (used < sizeof buffer / 2 && !peer_stdin.stop_me && fds[0].ignore) + { + show ("accelerate reading from '%s'\n", peer_stdin.name); + fds[0].ignore = 0; + } + } +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--help")) + { + puts ( +"usage: ./t-poll [options]\n" +"\n" +"Options:\n" +" --verbose Show what is going on\n" +" --debug Flyswatter\n" +); + exit (0); + } + if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + } + + if (!gpg_error_check_version (GPG_ERROR_VERSION)) + { + die ("gpg_error_check_version returned an error"); + errorcount++; + } + + peer_stdin.name = "stdin producer"; + create_pipe (&test_stdin, &peer_stdin.stream); + peer_stdout.name = "stdout consumer"; + create_pipe (&peer_stdout.stream, &test_stdout); + peer_stderr.name = "stderr consumer"; + create_pipe (&peer_stderr.stream, &test_stderr); + + if (es_set_nonblock (test_stdin, 1)) + fail ("error setting test_stdin to nonblock: %s\n", strerror (errno)); + if (es_set_nonblock (test_stdout, 1)) + fail ("error setting test_stdout to nonblock: %s\n", strerror (errno)); + if (es_set_nonblock (test_stderr, 1)) + fail ("error setting test_stderr to nonblock: %s\n", strerror (errno)); + + launch_thread (producer_thread, &peer_stdin ); + launch_thread (consumer_thread, &peer_stdout); + launch_thread (consumer_thread, &peer_stderr); + test_poll (); + show ("Waiting for threads to terminate...\n"); + es_fclose (test_stdin); + es_fclose (test_stdout); + es_fclose (test_stderr); + peer_stdin.stop_me = 1; + peer_stdout.stop_me = 1; + peer_stderr.stop_me = 1; + join_thread (&peer_stdin); + join_thread (&peer_stdout); + join_thread (&peer_stderr); + + return errorcount ? 1 : 0; +} diff --git a/comm/third_party/libgpg-error/tests/t-printf.c b/comm/third_party/libgpg-error/tests/t-printf.c new file mode 100644 index 0000000000..c2618389c0 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-printf.c @@ -0,0 +1,544 @@ +/* t-printf.c - Check the estream printf fucntions. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +/* Note that these tests check against glibc behaviour. On non glibc + systems expect non matching return codes in some border cases. */ + + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#define PGM "t-printf" + +#include "t-common.h" + + +static char *one_test_buf1; +static int one_test_rc1; + + + + +/* Read all data from STREAM into a new malloced buffer and return + * that buffer. The buffer is always 0 terminated. Either returns a + * string or dies. The stream will be trunctaed to zero. */ +static char * +stream_to_string (gpgrt_stream_t stream) +{ +#define NCHUNK 1024 + char *buffer; + size_t bufsize, buflen; + size_t nread; + + gpgrt_rewind (stream); + + buffer = NULL; + buflen = bufsize = 0; + do + { + bufsize += NCHUNK; + buffer = realloc (buffer, bufsize+1); + if (!buffer) + die ("malloc failed at line %d\n", __LINE__); + + nread = gpgrt_fread (buffer + buflen, 1, NCHUNK, stream); + if (nread < NCHUNK && gpgrt_ferror (stream)) + die ("fread failed at line %d: %s\n", __LINE__, strerror (errno)); + buflen += nread; + } + while (nread == NCHUNK); + buffer[nread] = 0; + + if (strlen (buffer) != buflen) + fail ("stream_to_string detected an embedded nul"); + + gpgrt_ftruncate (stream, 0); + return buffer; +#undef NCHUNK +} + + + +static void +one_test_x0 (const char *format, ...) +{ + va_list arg_ptr; + + show ("format: ->%s<-\n", format); + + errno = ENOENT; /* For the "%m" test. */ + va_start (arg_ptr, format); +#ifdef HAVE_VASPRINTF + one_test_rc1 = vasprintf (&one_test_buf1, format, arg_ptr); +#else + one_test_rc1 = -1; +#endif + va_end (arg_ptr); + if (one_test_rc1 == -1) + { + fail (" sys: errno=%d (%s)\n", errno, strerror (errno)); + one_test_buf1 = NULL; + } + else + show (" sys: ->%s<-\n", one_test_buf1); +} + +static void +one_test_x1 (const char *format, ...) +{ + int rc2; + va_list arg_ptr; + char *buf2; + + errno = ENOENT; + va_start (arg_ptr, format); + rc2 = gpgrt_vasprintf (&buf2, format, arg_ptr); + va_end (arg_ptr); + if (rc2 == -1) + { + fail (" our: errno=%d (%s)\n", errno, strerror (errno)); + } + else + show (" our: ->%s<-\n", buf2); + + if (one_test_rc1 != -1 && rc2 != -1 && strcmp (one_test_buf1, buf2)) + { + fail ("error: output does not match\n" + "format: ->%s<-\n sys: ->%s<-\n our: ->%s<-\n", + format, one_test_buf1, buf2); + } + else if ( one_test_rc1 != rc2 ) + { + fail ("error: return codes are different: sys_rc=%d our_rc=%d\n", + one_test_rc1, rc2); + } + + free (buf2); +} + +static void +one_test_x2 (const char *format, ...) +{ + va_list arg_ptr; + char *buf2; + + /* Test once more using the bsprintf variant. */ + errno = ENOENT; + va_start (arg_ptr, format); + buf2 = gpgrt_vbsprintf (format, arg_ptr); + va_end (arg_ptr); + if (!buf2) + { + fail (" our(2): errno=%d (%s)\n", errno, strerror (errno)); + } + else if (verbose) + show (" our: ->%s<-\n", buf2); + + if (one_test_rc1 != -1 && buf2 && strcmp (one_test_buf1, buf2)) + { + fail ("error: output does not match\n" + "format(2): ->%s<-\n sys: ->%s<-\n our: ->%s<-\n", + format, one_test_buf1, buf2); + } + es_free (buf2); + + free (one_test_buf1); + one_test_buf1 = NULL; +} + + +#define one_test_0(a) \ + one_test_x0 (a); \ + one_test_x1 (a); \ + one_test_x2 (a) +#define one_test_1(a, b) \ + one_test_x0 (a, b); \ + one_test_x1 (a, b); \ + one_test_x2 (a, b) +#define one_test_2(a, b, c) \ + one_test_x0 (a, b, c); \ + one_test_x1 (a, b, c); \ + one_test_x2 (a, b, c) +#define one_test_3(a, b, c, d) \ + one_test_x0 (a, b, c, d); \ + one_test_x1 (a, b, c, d); \ + one_test_x2 (a, b, c, d) + +static void +run_tests (void) +{ +#ifndef HAVE_VASPRINTF + /* We do not have a system vasprintf. */ + show ("run-tests: disabled due to missing vasprintf.\n"); +#else /*HAVE_VASPRINTF */ + + /*one_test ("%d %% %'d", 17, 19681977);*/ + + one_test_2 ("%d %% %d", 17, 768114563); + one_test_2 ("%d %% %d", 17, -768114563); + + /* Checking thousands is not easy because it depends on the locale. */ + /* one_test_1 ("%'d", 768114563); */ + + one_test_1 ("%d", 17); + one_test_1 ("%4d", 17); + one_test_1 ("%40d", 17); + one_test_1 ("%-d", 17); + one_test_1 ("%-4d", 17); + one_test_1 ("%-140d", 17); + one_test_1 ("%d", -17); + one_test_1 ("%4d", -17); + one_test_1 ("%40d", -17); + one_test_1 ("%-d", -17); + one_test_1 ("%-4d", -17); + one_test_1 ("%-40d", -17); + + one_test_1 ("%+4d", 17); + one_test_1 ("%+4d", -17); + one_test_1 ("%-+4d", 17); + one_test_1 ("%-+4d", -17); + one_test_1 ("% 4d", 17); + one_test_1 ("% 4d", -17); + one_test_1 ("%- +4d", 17); + one_test_1 ("%- +4d", -17); + + one_test_1 ("%.4d", 17); + one_test_1 ("%.0d", 17); + one_test_1 ("%.0d", 0); + one_test_1 ("%.4d", -17); + one_test_1 ("%.0d", -17); + one_test_1 ("%6.4d", 17); + one_test_1 ("%6.4d", -17); + one_test_1 ("%6.0d", 0); + one_test_1 ("%4.6d", 17); + one_test_1 ("%4.6d", -17); + + one_test_1 ("% 4.6d", 17); + one_test_1 ("% 6.0d", 0); + + one_test_1 ("%.4d", 17); + one_test_1 ("%04d", 17); + one_test_1 ("%.4d", -17); + one_test_1 ("%04d", -17); + one_test_1 ("%0.d", 0); + + one_test_2 ("%*d", 7, 42); + one_test_2 ("%*d", -7, 42); + one_test_2 ("%.*d", 7, 42); + one_test_2 ("%.*d", -7, 42); + one_test_3 ("%*.*d", 10, 7, 42); + one_test_3 ("%*.*d", 10, -7, 42); + one_test_3 ("%*.*d", -10, 7, 42); + one_test_3 ("%*.*d", -10, -7, 42); + + one_test_2 ("%*x", 7, 42); + one_test_2 ("%*x", -7, 42); + one_test_2 ("%.*x", 7, 42); + one_test_2 ("%.*x", -7, 42); + one_test_3 ("%*.*x", 10, 7, 42); + one_test_3 ("%*.*x", 10, -7, 42); + one_test_3 ("%*.*x", -10, 7, 42); + one_test_3 ("%*.*x", -10, -7, 42); + one_test_2 ("%#*x", 7, 42); + one_test_2 ("%#*x", -7, 42); + one_test_2 ("%#.*x", 7, 42); + one_test_2 ("%#.*x", -7, 42); + one_test_3 ("%#*.*x", 10, 7, 42); + one_test_3 ("%#*.*x", 10, -7, 42); + one_test_3 ("%#*.*x", -10, 7, 42); + one_test_3 ("%#*.*x", -10, -7, 42); + + one_test_2 ("%*X", 7, 42); + one_test_2 ("%*X", -7, 42); + one_test_2 ("%.*X", 7, 42); + one_test_2 ("%.*X", -7, 42); + one_test_3 ("%*.*X", 10, 7, 42); + one_test_3 ("%*.*X", 10, -7, 42); + one_test_3 ("%*.*X", -10, 7, 42); + one_test_3 ("%*.*X", -10, -7, 42); + one_test_2 ("%#*X", 7, 42); + one_test_2 ("%#*X", -7, 42); + one_test_2 ("%#.*X", 7, 42); + one_test_2 ("%#.*X", -7, 42); + one_test_3 ("%#*.*X", 10, 7, 42); + one_test_3 ("%#*.*X", 10, -7, 42); + one_test_3 ("%#*.*X", -10, 7, 42); + one_test_3 ("%#*.*X", -10, -7, 42); + + one_test_2 ("%*o", 7, 42); + one_test_2 ("%*o", -7, 42); + one_test_2 ("%.*o", 7, 42); + one_test_2 ("%.*o", -7, 42); + one_test_3 ("%*.*o", 10, 7, 42); + one_test_3 ("%*.*o", 10, -7, 42); + one_test_3 ("%*.*o", -10, 7, 42); + one_test_3 ("%*.*o", -10, -7, 42); + one_test_2 ("%#*o", 7, 42); + one_test_2 ("%#*o", -7, 42); + one_test_2 ("%#.*o", 7, 42); + one_test_2 ("%#.*o", -7, 42); + one_test_3 ("%#*.*o", 10, 7, 42); + one_test_3 ("%#*.*o", 10, -7, 42); + one_test_3 ("%#*.*o", -10, 7, 42); + one_test_3 ("%#*.*o", -10, -7, 42); + + one_test_1 ("%s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%.0s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%.10s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%.48s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%.49s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%.50s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%.51s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%48s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%49s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%50s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%51s", "the quick brown fox jumps over the lazy dogs back"); + one_test_1 ("%-51s", "the quick brown fox jumps over the lazy dogs back"); + + one_test_1 ("/%s=", "CN"); + + one_test_1 ("%f", 3.1415926535); + one_test_1 ("%f", -3.1415926535); + one_test_1 ("%.10f", 3.1415926535); + one_test_1 ("%.2f", 3.1415926535); + one_test_1 ("%.1f", 3.1415926535); + one_test_1 ("%.0f", 3.1415926535); + one_test_1 ("%.20f", 3.1415926535); + one_test_1 ("%10.10f", 3.1415926535); + one_test_1 ("%10.2f", 3.1415926535); + one_test_1 ("%10.1f", 3.1415926535); + one_test_1 ("%10.0f", 3.1415926535); + one_test_1 ("%30.20f", 3.1415926535); + one_test_1 ("%10.10f", -3.1415926535); + one_test_1 ("%10.2f", -3.1415926535); + one_test_1 ("%10.1f", -3.1415926535); + one_test_1 ("%10.0f", -3.1415926535); + one_test_1 ("%30.20f", -3.1415926535); + + one_test_1 ("%-10f", 3.1415926535); + one_test_1 ("%-10.10f", 3.1415926535); + one_test_1 ("%-10.2f", 3.1415926535); + one_test_1 ("%-10.1f", 3.1415926535); + one_test_1 ("%-10.0f", 3.1415926535); + one_test_1 ("%-30.20f", 3.1415926535); + one_test_1 ("%-10f", -3.1415926535); + one_test_1 ("%-10.10f", -3.1415926535); + one_test_1 ("%-10.2f", -3.1415926535); + one_test_1 ("%-10.1f", -3.1415926535); + one_test_1 ("%-10.0f", -3.1415926535); + one_test_1 ("%-30.20f", -3.1415926535); + + one_test_1 ("%#.0f", 3.1415926535); + one_test_1 ("%#10.0f", 3.1415926535); + one_test_1 ("%#10.0f", -3.1415926535); + one_test_1 ("%-#10.0f", 3.1415926535); + one_test_1 ("%-#10.0f", -3.1415926535); + + one_test_1 ("%e", 3.1415926535); + one_test_1 ("%g", 3.1415926535); + + one_test_1 ("%a", 1.0); + one_test_1 ("%a", -1.0); + one_test_1 ("%a", 3.1415926535); + +#ifdef HAVE_LONG_DOUBLE + one_test_1 ("%La", (long double)1.0); + one_test_1 ("%La", (long double)-1.0); + one_test_1 ("%La", (long double)3.1415926535); +#endif + +#ifdef __GLIBC__ + /* "%m" is a glibc extension so this _test_ will only work on such a + system. */ + one_test_0 ("%m"); + one_test_1 ("%d=%m", 17); + one_test_2 ("%2$d:%m:%1$d", 42, 17); +#endif /*__GLIBC__*/ + +#endif /*HAVE_VASPRINTF */ +} + +static void +check_snprintf (void) +{ + char buffer[20]; + int rc, rc2; + size_t tmplen, blen, blen2; + + rc = gpgrt_snprintf (buffer, 0, "%*s", 18, ""); + if (rc != 18) + printf ("rc=%d\n", rc ); + rc = gpgrt_snprintf (buffer, sizeof buffer, "%*s", 18, ""); + if (rc != 18) + printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer)); + rc = gpgrt_snprintf (buffer, sizeof buffer, "%*s", 19, ""); + if (rc != 19) + printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer)); + rc = gpgrt_snprintf (buffer, sizeof buffer, "%*s", 20, ""); + if (rc != 20) + printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer)); + rc = gpgrt_snprintf (buffer, sizeof buffer, "%*s", 21, ""); + if (rc != 21) + printf ("rc=%d, strlen(buffer)=%d\n", rc, (int)strlen (buffer)); + + for (tmplen = 0; tmplen <= sizeof buffer; tmplen++) + { + rc = gpgrt_snprintf (buffer, tmplen, "%04d%02d%02dT%02d%02d%02d", + 1998, 9, 7, 16, 56, 05); + blen = strlen (buffer); + rc2 = snprintf (buffer, tmplen, "%04d%02d%02dT%02d%02d%02d", + 1998, 9, 7, 16, 56, 05); + blen2 = strlen (buffer); + if (rc != rc2 || blen != blen2) + printf ("snprintf test with len %u gives %d instead of %d (%u,%u)\n", + (unsigned int)tmplen, rc, rc2, + (unsigned int)blen, (unsigned int)blen2); + } +} + + +struct sfstate_s +{ + char *last_result; +}; + +static char * +string_filter (const char *string, int no, void *opaque) +{ + struct sfstate_s *state = opaque; + + free (state->last_result); + if (no == -1) + { + state->last_result = NULL; + return NULL; + } + if (no == 3) + state->last_result = NULL; + else + state->last_result = strdup (string? string : "[==>Niente<==]"); + + return state->last_result; +} + + +static void +check_fprintf_sf (void) +{ + volatile char *nullptr = NULL; /* Avoid compiler warning. */ + struct sfstate_s sfstate = {NULL}; + gpgrt_stream_t stream; + const char *expect; + char *result; + + stream = gpgrt_fopenmem (0, "w+b"); + if (!stream) + die ("fopenmem failed at line %d\n", __LINE__); + + gpgrt_fprintf_sf (stream, string_filter, &sfstate, + "%s a=%d b=%s c=%d d=%.8s null=%s\n", + nullptr, 1, "foo\x01 bar", 2, + "a longer string", nullptr); + expect = "[==>Niente<==] a=1 b=foo\x01 bar c=2 d=a longer null=(null)\n"; + result = stream_to_string (stream); + if (strcmp (result, expect)) + { + show ("expect: '%s'\n", expect); + show ("result: '%s'\n", result); + fail ("fprintf_sf failed at %d\n", __LINE__); + } + free (result); + + gpgrt_fprintf_sf (stream, string_filter, &sfstate, + "a=%d b=%s c=%d d=%.8s e=%s\n", + 1, "foo\n bar", 2, nullptr, ""); + expect = "a=1 b=foo\n bar c=2 d=[==>Nien e=\n"; + result = stream_to_string (stream); + if (strcmp (result, expect)) + { + show ("expect: '%s'\n", expect); + show ("result: '%s'\n", result); + fail ("fprintf_sf failed at %d\n", __LINE__); + } + free (result); + + gpgrt_fclose (stream); +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--help")) + { + puts ( +"usage: ./" PGM " [options]\n" +"\n" +"Options:\n" +" --verbose Show what is going on\n" +" --debug Flyswatter\n" +); + exit (0); + } + if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + } + + setlocale (LC_NUMERIC, ""); + if (!gpg_error_check_version (GPG_ERROR_VERSION)) + { + die ("gpg_error_check_version returned an error"); + errorcount++; + } + + run_tests (); + check_snprintf (); + check_fprintf_sf (); + +#ifdef __GLIBC__ + return !!errorcount; +#else + return 0; +#endif +} diff --git a/comm/third_party/libgpg-error/tests/t-strerror.c b/comm/third_party/libgpg-error/tests/t-strerror.c new file mode 100644 index 0000000000..92890661c9 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-strerror.c @@ -0,0 +1,63 @@ +/* t-strerror.c - Regression test. + Copyright (C) 2003 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpgme-error; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#if HAVE_STDLIB_H +#include +#endif + +#include + +int +main (int argc, char *argv[]) +{ + if (argc > 1) + { + int i = 1; + while (i + 1 < argc) + { + gpg_error_t err = gpg_err_make (atoi (argv[i]), atoi (argv[i + 1])); + printf ("%s: %s\n", gpg_strsource (err), gpg_strerror (err)); + i += 2; + } + } + else + { + struct + { + gpg_err_source_t src; + gpg_err_code_t code; + } list[] = { { 0, 0 }, { 1, 201 }, { 2, 2 }, { 3, 102 }, + { 4, 100 }, { 5, 99 }, { 6, 110 }, { 7, 7 }, { 8, 888 } }; + int i = 0; + + while (i < sizeof (list) / sizeof (list[0])) + { + gpg_error_t err = gpg_err_make (list[i].src, list[i].code); + printf ("%s: %s\n", gpg_strsource (err), gpg_strerror (err)); + i++; + } + } + return 0; +} diff --git a/comm/third_party/libgpg-error/tests/t-stringutils.c b/comm/third_party/libgpg-error/tests/t-stringutils.c new file mode 100644 index 0000000000..8879e1a4d1 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-stringutils.c @@ -0,0 +1,395 @@ +/* t-stringutils.c - Check some string utilities + * Copyright (C) 2020 g10 Code GmbH + * + * This file is part of Libgpg-error. + * + * Libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see . + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_STAT +# include +#endif +#include +#ifdef HAVE_PWD_H +# include +#endif +#include +#ifdef HAVE_W32_SYSTEM +# include +#endif + +#define PGM "t-stringutils" +#include "t-common.h" + + +static const char * +my_strusage (int level) +{ + const char *p; + + switch (level) + { + case 9: p = "LGPL-2.1-or-later"; break; + case 11: p = PGM; break; + default: p = NULL; + } + return p; +} + + +const char * +mygethome (void) +{ + static char *home_buffer; + + if (!home_buffer) + { + char *home = getenv("HOME"); + + if(home) + home_buffer = xstrdup (home); +#if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H) + else + { + struct passwd *pwd; + + pwd = getpwuid (getuid()); + if (pwd) + home_buffer = xstrdup (pwd->pw_dir); + } +#endif + } + return home_buffer; +} + + +#ifdef HAVE_W32_SYSTEM +static wchar_t * +utf8_to_wchar (const char *string) +{ + int n; + wchar_t *result; + size_t nbytes; + int cbmultibyte = -1; + + n = MultiByteToWideChar (CP_UTF8, 0, string, cbmultibyte, NULL, 0); + if (n < 0 || (n+1) <= 0) + die ("utf8_to_wchar failed\n"); + nbytes = (size_t)(n+1) * sizeof(*result); + if (nbytes / sizeof(*result) != (n+1)) + die ("utf8_to_wchar failed\n"); + result = xmalloc (nbytes); + n = MultiByteToWideChar (CP_UTF8, 0, string, cbmultibyte, result, n); + if (n < 0) + die ("utf8_to_wchar failed\n"); + return result; + +} + + +static char * +wchar_to_utf8 (const wchar_t *string, size_t length) +{ + int n; + char *result; + + n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL); + if (n < 0 || (n+1) <= 0) + die ("wchar_to_utf8 failed\n"); + + result = xmalloc (n+1); + if (!result) + die ("wchar_to_utf8 failed\n"); + n = WideCharToMultiByte (CP_UTF8, 0, string, length, result, n, NULL, NULL); + if (n < 0) + die ("wchar_to_utf8 failed\n"); + result[n] = 0; + return result; +} +#endif + +static char * +mygetcwd (void) +{ +#ifdef HAVE_W32_SYSTEM + wchar_t wbuffer[MAX_PATH + sizeof(wchar_t)]; + wchar_t *wp; + DWORD wlen; + char *buf, *p; + + wlen = GetCurrentDirectoryW (MAX_PATH, wbuffer); + if (!wlen) + die ("GCDW failed - error code: %d\n", (int)GetLastError ()); + else if (wlen > MAX_PATH) + die ("GCDW failed - wlen too large\n"); + + buf = wchar_to_utf8 (wbuffer, wlen); + + /* Quick test that the reverse works. */ + wp = utf8_to_wchar (buf); + if (wcscmp (wp, wbuffer)) + die ("GCDW: reverse converting failed\n"); + xfree (wp); + + for (p=buf; *p; p++) + if (*p == '\\') + *p = '/'; + return buf; + +#else + char *buffer; + size_t size = 100; + + for (;;) + { + buffer = xmalloc (size+1); + if (getcwd (buffer, size) == buffer) + { + return buffer; + } + xfree (buffer); + if (errno != ERANGE) + die ("error getting current cwd: %s\n", strerror (errno)); + size *= 2; + } +#endif +} + + +static void +check_fnameconcat (void) +{ + char *out; + const char *home = mygethome (); + size_t homelen = home? strlen (home):0; + + out = gpgrt_fnameconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", NULL); + if (out) + fail ("fnameconcat succeeded but should not at line %d\n", __LINE__); + else if (errno != EINVAL) + fail ("fnameconcat return wrong error at line %d\n", __LINE__); + xfree (out); + + out = gpgrt_fnameconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", NULL); + if (out) + fail ("fnameconcat succeeded but should not at line %d\n", __LINE__); + else if (errno != EINVAL) + fail ("fnameconcat return wrong error at line %d\n", __LINE__); + xfree (out); + + out = gpgrt_fnameconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "1", "2", NULL); + if (!out || strcmp (out, + "1/2/3/4/5/6/7/8/9/10/" + "1/2/3/4/5/6/7/8/9/10/" + "1/2/3/4/5/6/7/8/9/10/" + "1/2")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_fnameconcat ("foo", "~/bar", "baz/cde", NULL); + if (!out || strcmp (out, "foo/~/bar/baz/cde")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_fnameconcat ("foo", "~/bar", "baz/cde/", NULL); + if (!out || strcmp (out, "foo/~/bar/baz/cde/")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_fnameconcat ("/foo", "~/bar", "baz/cde/", NULL); + if (!out || strcmp (out, "/foo/~/bar/baz/cde/")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_fnameconcat ("//foo", "~/bar", "baz/cde/", NULL); + if (!out || strcmp (out, "//foo/~/bar/baz/cde/")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_fnameconcat ("", "~/bar", "baz/cde", NULL); + if (!out || strcmp (out, "/~/bar/baz/cde")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_fnameconcat ("~/foo", "bar", NULL); + if (!out) + fail ("fnameconcat failed at line %d\n", __LINE__); + else if (home) + { + if (strlen (out) < homelen + 7) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strncmp (out, home, homelen)) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strcmp (out+homelen, "/foo/bar")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + } + else + { + if (strcmp (out, "~/foo/bar")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + } + xfree (out); + + out = gpgrt_fnameconcat ("~", "bar", NULL); + if (!out) + fail ("fnameconcat failed at line %d\n", __LINE__); + else if (home) + { + if (strlen (out) < homelen + 3) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strncmp (out, home, homelen)) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strcmp (out+homelen, "/bar")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + } + else + { + if (strcmp (out, "~/bar")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + } + xfree (out); +} + + +static void +check_absfnameconcat (void) +{ + char *out; + char *cwd = mygetcwd (); + size_t cwdlen = strlen (cwd); + + out = gpgrt_absfnameconcat ("foo", "bar", NULL); + if (!out) + fail ("fnameconcat failed at line %d\n", __LINE__); + else if (strlen (out) < cwdlen + 7) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strncmp (out, cwd, cwdlen)) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strcmp (out+cwdlen, "/foo/bar")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_absfnameconcat ("./foo", NULL); + if (!out) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strlen (out) < cwdlen + 5) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strncmp (out, cwd, cwdlen)) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strcmp (out+cwdlen, "/./foo")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + out = gpgrt_absfnameconcat (".", NULL); + if (!out) + fail ("fnameconcat failed at line %d\n", __LINE__); + else if (strlen (out) < cwdlen) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strncmp (out, cwd, cwdlen)) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + else if (strcmp (out+cwdlen, "")) + fail ("fnameconcat failed at line %d (out=%s)\n", __LINE__, out); + xfree (out); + + xfree (cwd); +} + + +static void +check_access (void) +{ + char *cwd = mygetcwd (); + + if (gpgrt_access (cwd, F_OK)) + fail ("gpgrt_access(%s) failed: %s\n", + cwd, gpg_strerror (gpg_error_from_syserror ())); + else + show ("gpgrt_access(%s) succeeded\n", cwd); + + xfree (cwd); +} + + +int +main (int argc, char **argv) +{ + gpgrt_opt_t opts[] = { + ARGPARSE_x ('v', "verbose", NONE, 0, "Print more diagnostics"), + ARGPARSE_s_n('d', "debug", "Flyswatter"), + ARGPARSE_x (501, "pwd", NONE, 0, "Print working directory"), + ARGPARSE_end() + }; + gpgrt_argparse_t pargs = { &argc, &argv, 0 }; + char *cwd; + int opt_pwd = 0; + + gpgrt_set_strusage (my_strusage); + gpgrt_log_set_prefix (gpgrt_strusage (11), GPGRT_LOG_WITH_PREFIX); + + while (gpgrt_argparse (NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case 'v': verbose++; break; + case 'd': debug++; break; + case 501: opt_pwd = 1; break; + default : pargs.err = ARGPARSE_PRINT_ERROR; break; + } + } + gpgrt_argparse (NULL, &pargs, NULL); + + cwd = gpgrt_getcwd (); + if (!cwd) + fail ("gpgrt_getcwd returned error: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + else + { + if (opt_pwd) + { + int save_verbose = verbose; + verbose = 1; + show ("getcwd -> '%s'\n", cwd); + verbose = save_verbose; + } + xfree (cwd); + } + + show ("testing string utilities\n"); + + check_fnameconcat (); + check_absfnameconcat (); + check_access (); + + show ("testing string utilities finished\n"); + return !!errorcount; +} diff --git a/comm/third_party/libgpg-error/tests/t-syserror.c b/comm/third_party/libgpg-error/tests/t-syserror.c new file mode 100644 index 0000000000..a4cb9839cd --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-syserror.c @@ -0,0 +1,87 @@ +/* t-syserror.c - System error specific regression test. + Copyright (C) 2006 g10 Code GmbH + + This file is part of libgpg-error. + + libgpg-error is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + libgpg-error is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libgpgme-error; if not, write to the Free + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + + +#if HAVE_CONFIG_H +#include +#endif + +#include +#if HAVE_STDLIB_H +#include +#endif +#include + +#include + +int +main (int argc, char *argv[]) +{ + FILE *fp; + int save_errno; + gpg_err_code_t ec; + + (void)argc; + (void)argv; + + fp = fopen ("/does-not-exist/110761/nowhere.foo", "r"); + if (fp) + { + fclose (fp); + fp = fopen (" no this file does not exists foo 4711", "r"); + } + if (fp) + { + fprintf (stderr, "unable to run test\n"); + return 1; + } + save_errno = errno; + + ec = gpg_err_code_from_syserror (); + if (ec != GPG_ERR_ENOENT) + { + fprintf (stderr, "fopen failed with bad code: %d\n", save_errno); + return 1; + } + + if (ec != gpg_err_code_from_errno (save_errno)) + { + fprintf (stderr, "oops at %d\n",__LINE__); + return 1; + } + + gpg_err_set_errno (0); + + ec = gpg_err_code_from_syserror (); + if (ec != GPG_ERR_MISSING_ERRNO) + { + fprintf (stderr, "oops at %d\n",__LINE__); + return 1; + } + + if ( gpg_err_code_from_errno (0) ) + { + fprintf (stderr, "oops at %d\n",__LINE__); + return 1; + } + + + return 0; +} diff --git a/comm/third_party/libgpg-error/tests/t-version.c b/comm/third_party/libgpg-error/tests/t-version.c new file mode 100644 index 0000000000..d71f3602b4 --- /dev/null +++ b/comm/third_party/libgpg-error/tests/t-version.c @@ -0,0 +1,178 @@ +/* t-version.c - Check the version info function + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of libgpg-error. + * + * libgpg-error is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libgpg-error is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#define PGM "t-version" +#include "t-common.h" + +static const char *logpfx = PGM; + + +static void +t_gpgrt_cmp_version (void) +{ + struct { int result; int level; const char *a; const char *b; } t[] = { + { 0, 1, "0", "0" }, + { -1, 1, "0", "1" }, + { 1, 1, "1", "0" }, + { -1, 1, "0.0", "0.1" }, + { -1, 1, "0.1", "1.2" }, + { 1, 1, "1.0", "0.9" }, + { -1, 1, "-1.0", "0.9" }, /* A is invalid */ + { 0, 1, "0rc0", "0rc0" }, + { 1, 1, "0rc1", "0rc0" }, + { -1, 1, "0rc1", "0rc2" }, + { 0, 1, "0.rc0", "0.rc0" }, + { 1, 1, "0.rc1", "0.rc0" }, + { -1, 1, "0.rc1", "0.rc2" }, + { 0, 1, "0.rc1", "0.rc1" }, + { -1, 1, "0qc1", "0rc0" }, + { -1, 1, "0.qc1", "0.rc0" }, + { 0, 2, "0.0", "0.0" }, + { -1, 2, "0.1", "0.2" }, + { -1, 2, "3.1", "3.2" }, + { -1, 2, "3.1", "4.0" }, + { 0, 2, "1.1rc0", "1.1rc0" }, + { 1, 2, "1.1rc1", "1.1rc0" }, + { -1, 2, "1.1rc0", "1.1rc1" }, + { 0, 3, "7.0.0", "7.0.0" }, + { -1, 3, "7.0.1", "7.0.2" }, + { -1, 3, "7.3.1", "7.3.2" }, + { -1, 3, "7.3.1", "7.4.0" }, + { 0, 3, "7.1.1rc0", "7.1.1rc0" }, + { 1, 3, "7.1.1rc1", "7.1.1rc0" }, + { -1, 3, "7.1.1rc0", "7.1.1rc1" }, + { 1, 3, "6.0.0", "5.0.0" }, + { 0, 3, "6.0.0", "6.0.0" }, + { 1, 3, "6.0.1", "6.0.0" }, + { 1, 3, "6.1.0", "6.0.0" }, + { 1, 3, "6.2.1", "6.2.0" }, + { -1, 3, "6.2.1", "6.2.2" }, + { -1, 3, "6.0.0", "6.0.2" }, + { -1, 3, "6.0.0", "6.1.0" }, + { -1, 3, "6.2.0", "6.2.1" }, + { 1, 3, "6.0.0-beta1", "6.0.0-beta0" }, + { 0, 3, "6.0.0-beta2", "6.0.0-beta2" }, + { 1, 3, "6.0.0-beta20", "6.0.0-beta19" }, + { -1, 3, "6.0.0-beta1", "6.0.0-beta2" }, + { 1, 3, "6.0.0-beta2", "6.0.0-beta1" }, + { -1, 3, "6.0.0-beta20", "6.0.0-beta21" }, + { 0,13, "6.0.0-beta1", "6.0.0-beta0" }, + { 0,13, "6.0.0-beta2", "6.0.0-beta2" }, + { 0,13, "6.0.0-beta20", "6.0.0-beta19" }, + { 0,13, "6.0.0-beta1", "6.0.0-beta2" }, + { 0,13, "6.0.0-beta2", "6.0.0-beta1" }, + { 0,13, "6.0.0-beta20", "6.0.0-beta21" } + }; + int i; + int result, expected; + + for (i=0; i < DIM (t); i++) + { + expected = t[i].result; + result = gpgrt_cmp_version (t[i].a, t[i].b, t[i].level); + if (result != expected) + fail ("test %d failed: cmp('%s','%s',%d) = %d expected %d", + i, t[i].a, t[i].b, t[i].level, result, expected); + } + for (i=0; i < DIM (t); i++) + { + expected = 0 - t[i].result; + result = gpgrt_cmp_version (t[i].a, t[i].b, -t[i].level); + if (result != expected) + fail ("test %d-rev failed: cmp('%s','%s',%d) = %d expected %d", + i, t[i].a, t[i].b, -t[i].level, result, expected); + } +} + + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--help")) + { + puts ( +"usage: ./version [options]\n" +"\n" +"Options:\n" +" --verbose Show what is going on\n" +); + exit (0); + } + if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + } + + t_gpgrt_cmp_version (); + + if (!gpg_error_check_version (GPG_ERROR_VERSION)) + { + fprintf (stderr, "%s: gpg_error_check_version returned an error\n", + logpfx); + errorcount++; + } + if (!gpg_error_check_version ("1.10")) + { + fprintf (stderr, "%s: gpg_error_check_version returned an " + "error for an old version\n", logpfx); + errorcount++; + } + if (gpg_error_check_version ("15.0")) + { + fprintf (stderr, "%s: gpg_error_check_version did not return an error" + " for a newer version\n", logpfx); + errorcount++; + show ("\n"); /* Reference this function to silence gcc. */ + } + if (verbose || errorcount) + { + printf ("Version from header: %s (0x%06x)\n", + GPG_ERROR_VERSION, GPG_ERROR_VERSION_NUMBER); + printf ("Version from binary: %s\n", gpg_error_check_version (NULL)); + printf ("Copyright blurb ...:%s\n", gpg_error_check_version ("\x01\x01")); + } + + return errorcount ? 1 : 0; +} diff --git a/comm/third_party/libotr/AUTHORS b/comm/third_party/libotr/AUTHORS new file mode 100644 index 0000000000..cf8140c590 --- /dev/null +++ b/comm/third_party/libotr/AUTHORS @@ -0,0 +1,9 @@ +Off-the-Record Messaging Library and Toolkit + +Authors: + + Ian Goldberg, David Goulet, Rob Smits, Chris Alexander, Willy Lew, + Lisa Du, Nikita Borisov + + +See the README file for mailing list information diff --git a/comm/third_party/libotr/COPYING b/comm/third_party/libotr/COPYING new file mode 100644 index 0000000000..73680a2db0 --- /dev/null +++ b/comm/third_party/libotr/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/comm/third_party/libotr/COPYING.LIB b/comm/third_party/libotr/COPYING.LIB new file mode 100644 index 0000000000..a2f935aa90 --- /dev/null +++ b/comm/third_party/libotr/COPYING.LIB @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/comm/third_party/libotr/ChangeLog b/comm/third_party/libotr/ChangeLog new file mode 100644 index 0000000000..35752b00bc --- /dev/null +++ b/comm/third_party/libotr/ChangeLog @@ -0,0 +1,1026 @@ +2016-03-07 + + * tests/regression/client/Makefile.am: + * tests/unit/Makefile.am: Add LIBGCRYPT_CFLAGS to the test suite + + * Makefile.am: + * configure.ac: Only build the test suite on Linux, since it + currently uses Linux-specific features such as epoll + +2016-03-06 + + * Makefile.am: Add bootstrap to the tarball + +2016-03-04 + + * README: + * configure.ac: + * src/version.h: Bump version number to 4.1.1 + +2016-03-03 + + * src/proto.c (otrl_proto_accept_data): + * src/proto.c (otrl_proto_fragment_accumulate): + * src/proto.c (otrl_proto_fragment_create): Prevent integer + overflow on 64-bit architectures when receiving 4GB messages. + In several places in proto.c, the sizes of portions of incoming + messages were stored in variables of type int or unsigned int + instead of size_t. If a message arrives with very large + sizes (for example unsigned int datalen = UINT_MAX), then + constructions like malloc(datalen+1) will turn into malloc(0), + which on some architectures returns a non-NULL pointer, but + UINT_MAX bytes will get written to that pointer. Ensure all + calls to malloc or realloc cannot integer overflow like this. + Thanks to Markus Vervier of X41 D-Sec GmbH + for the report. + + * Protocol-v3.html: Clarify that instance tags and fragment + numbers in the OTR fragment format are allowed to have leading + 0s. Also fix that how to handle v2 versus v3 messages for the + Reveal Signature and Signature messages was missing. Thanks to + Ola Bini for the report. + +2015-12-25 + + * src/instag.c (otrl_instag_read_FILEp): Fix memory leak in + otrl_instag_read_FILEp if the tag file is malformed. Thanks to + Jean-Philippe Aumasson for the + report. + +2015-08-18 + + * src/message.c (otrl_message_receiving): + * src/proto.c (otrl_proto_create_data): Set to NULL the sendsmp + pointer when handling SMP to avoid a potential free() of an + uninitialized pointer. Also ensure the message pointer is set + to NULL in otrl_proto_create_data for extra precaution and to + prevent future code paths from having the same error. Thanks to + Nicolas Guigo and Ben Hawkes + for the report. + +2015-02-08 + + * Protocol-v3.html: Typo fixes, thanks to Hannes Mehnert + and Nadim Kobeissi + for the reports. + + * src/message.c: Be stricter about parsing v3 fragments. Thanks + to Jean-Philippe Aumasson for + the report. + +2014-12-18 + + * Protocol-v3.html: Remove "sender_instance, receiver_instance," + from description of v2 fragmentation and clarify that you can't + fragment a fragment. Thanks to Hannes Mehnert + for the report. + + * Protocol-v3.html: Remove a stray "DRAFT" from the tag. + + * Protocol-v2.html: + * Protocol-v3.html: Clarify the DSA computation in the protocol + specs. Thanks to Adam Langley <agl@imperialviolet.org> and + Hannes Mehnert <hannes@mehnert.org> for the report. + +2014-11-29 + + * README: + * Makefile.am: + * configure.ac: + * tests/*: Brand new testsuite, thanks to + David Goulet <dgoulet@ev0ke.net> and + Julien Voisin <julien.voisin@dustri.org>. + "make check" to run it. + +2014-11-11 + + * b64.c (otrl_base64_otr_encode): In case some future code path + tries to call otrl_base64_otr_encode with a buffer more than + 3/4 the size of all addressable memory, return NULL rather than + causing an integer overflow and a heap overrun. Thanks to + David Remahl <david@remahl.se> for the report. + * proto.c (otrl_proto_create_data): Tiny refactor to call + otrl_base64_otr_encode instead of duplicating the code here. + +2014-10-18 + + * README: + * configure.ac: + * src/version.h: Bump version number to 4.1.0 + +2014-10-18 + + * Protocol-v3.html: Correctly count the number of actions an OTR + client must handle. Thanks to Fred Yontz <fred@ridersite.org> + for the report. + +2014-10-13 + + * src/context.h: Add API functions + otrl_context_find_recent_instance and + otrl_context_find_recent_secure_instance. + +2014-10-13 + + * src/context.c (otrl_context_forget): Correct check for + children contexts' state being OTRL_MSGSTATE_PLAINTEXT. Thanks + to k007k <k007k@wp.pl> for the report. + +2014-10-13 + + * src/message.c (otrl_message_receiving): Fix memory leak in + fragment reassembly. Thanks to Matthew D. Green + <matthewdgreen@gmail.com> for the report and David Goulet + <dgoulet@ev0ke.net> for the patch. + +2014-10-13 + + * src/message.c (otrl_message_sending): Fix possible memory + leak. + +2014-07-13 + + * src/auth.c (otrl_auth_handle_commit): Add a clarifying + comment. + +2014-06-12 + + * src/message.h: Typo fix. + +2014-06-03 + + * Makefile.am: + * configure.ac: Modernize autoconf build system. Thanks to + David Goulet <dgoulet@ev0ke.net> for the patch. + +2014-05-22 + + * README: + * src/context.c: Typo fixes. + +2014-05-04 + + * INSTALL: + * bootstrap: Add bootstrap script to set up the build system. + Thanks to David Goulet <dgoulet@ev0ke.net> for the patch. + +2014-05-04 + + * src/dh.c: + * src/sm.c: + * toolkit/sesskeys.c: Use gcrypt secure memory allocation. + Thanks to Julien Voisin <julien.voisin@dustri.org> for the + patch. + +2014-04-21 + + * src/mem.c (otrl_mem_differ): Simplify otrl_mem_differ. Thanks + to Julien Voisin <julien.voisin@dustri.org> for the patch. + +2014-02-20 + + * src/proto.c (otrl_proto_instance): Fix a memory leak when + receiving an invalid instance tag. Thanks to Julien Voisin + <julien.voisin@dustri.org> for the patch. + +2014-02-15 + + * src/proto.c: + * src/auth.c: + * src/mem.c: + * src/mem.h: Use a constant-time memory comparison for safety. + Thanks to jvoisin <julien.voisin@dustri.org> for the suggestion. + +2013-10-13 + + * src/proto.c: Return 0 instead of crashing from + otrl_proto_query_bestversion if passed an illegal input. + Thanks to Conrad Hoffmann <ch@bitfehler.net> for the report and + the patch. + +2013-08-21 + + * src/proto.c: Fix warning from clang in proto.c. Before, trying + to fragment a message into more than 65535 pieces would cause + incorrect fragments to be output. Now, it just returns an error + (as that is disallowed by the spec). Thanks to Teemu Huovila + <thuovila@cs.helsinki.fi> for reporting the issue. + +2013-08-08 + + * Protocol-v3.html: Random exponents in SMP should be 1536 bits. + The spec (but not the code) incorrectly said "128 bits" before. + +2013-07-28 + + * packaging/fedora/libotr.spec: Fedora spec file for 4.x from + Paul Wouters <paul@cypherpunks.ca> + +2013-07-17 + + * toolkit/sesskeys.c: Workaround for a crash bug in libgcrypt + affecting otr_sesskeys. Passing a private key value of 0 to + otr_sesskeys would cause libgcrypt to crash in gcry_mpi_powm. + We reported this libgcrypt bug and it was then fixed in + http://lists.gnupg.org/pipermail/gcrypt-devel/2013-July/002251.html + but the workaround is simply to use + gcry_mpi_new(DH1536_MOD_LEN_BITS) instead of gcry_mpi_new(0). + Note that this only affected the otr_sesskeys toolkit program, + and not libotr itself. + Thanks to the Mayhem Team at CMU (Alexandre Rebert, Thanassis + Avgerinos, Sang Kil Cha, David Brumley, Manuel Egele) for the + report. + +2013-01-19 + + * src/message.c: pass opdata when sending message fragment + The inject_message callback was missing the opdata when sending + message fragments. Thanks to David Goulet <dgoulet@ev0ke.net> + for the report. + +2012-12-18 + + * src/message.c: Copy lastmessage to the newly created context. + This fixes a case where the first user message gets lost when + OTRL_POLICY_REQUIRE_ENCRYPTION policy is set because after + establishing the encryption lastmessage remains with the master + context and will not be resent. Thanks to Andreas Schlick + <schlick@lavabit.com> for the report. + +2012-09-09 + + * configure.ac: Make linker hardening [DEP, ALSR] work on + Windows builds. Thanks to Daniel Atallah <datallah@pidgin.im> + for noticing that it wasn't working before. + +2012-09-04 + + * README: Release 4.0.0 + +2012-08-28 + + * UPGRADING: + * src/proto.h: + * src/proto.c: Don't have otrl_init call exit(1) if the + application's requested version number differs from libotr's. + Rather, return a non-zero error code, and have the application + clean up gracefully. The OTRL_INIT macro now checks the error + code and does an exit(1) as the default behaviour, but the + application can do what it likes. + +2012-08-27 + + * src/auth.h: + * src/auth.c: + * src/message.c: Record the time the last COMMIT was sent from a + master context. This will be used to clear the committed key + from the master context once we don't expect any more instances + of our buddy to respond with a DHKEY message. + + * UPGRADING: + * src/userstate.h: + * src/userstate.c: + * src/message.h: + * src/message.c: Add a timer_control callback to + OtrlMessageAppOps in order to actually clear out the above stale + committed keys. + +2012-08-26 + + * src/context.c: + * src/context_priv.c: + * src/context_priv.h: libotr was exporting exactly two functions + without the otrl_ prefix: context_priv_new and + context_priv_force_finished. Change the names of these + functions to start with otrl_. Thanks to David Goulet + <dgoulet@ev0ke.net> for noticing it. + + * Protocol-v3.html: Document the v3 whitespace tag, and better + document the extra symmetric key. Thanks to Kjell Braden + <kb@pentabarf.de> for noticing the omission. + +2012-08-25 + + * src/sm.c: + * src/context.c: + * src/auth.c: + * src/message.c: If OTRL_DEBUGGING is non-zero, then a message + containing a special debug string ("?OTR!") will cause debug + info to be printed to stderr. (This #define should *not* be set + in release code.) + + * src/auth.c: + * src/auth.h: + * src/message.c: Correct the logic for handling incoming COMMIT + messages when we've recently sent our own COMMIT message. + + * src/message.c: Don't update the recent_sent_child field to + point to the master context just becuase we sent a version 3 + COMMIT message (which has no destination instance). + +2012-08-24 + + * README: + * configure.ac: Prepare for release 4.0.0 + +2012-08-24 + + * src/message.c: Consider copying the master auth context to the + child, even if the child is already in ENCRYPTED, because we + might be trying to refresh a private conversation. + +2012-08-22 + + * configure.ac: Use gcc and ld hardening flags, where possible. + * configure.ac: + * src/auth.c: + * src/dh.c: + * src/mem.c: + * src/privkey.c: + * src/proto.c: + * src/sm.c: + * toolkit/sesskey.c: Build cleanly with -Wall -Wextra + -Wformat-security -Wno-unused-parameter + +2012-08-17 + + * src/message.c: Don't call memchr(foo,'\0',-1) even if it has + no ill effects. Thanks to George Kadianakis + <desnacked@riseup.net> for the report. + +2012-07-20 + + * src/message.c, src/instag.c, toolkit/parse.c, src/sm.c, + src/proto.c, src/privkey.c, src/auth.c, src/context.[ch]: + Fix some memory leaks, some NULL pointer handling, and + compilation warnings. Thanks to Paul Wouters + <pwouters@redhat.com> for the report. + + * src/message.c: Better handling of OTRv3 fragments. + +2012-07-19 + + * src/b64.[ch], src/proto.c, toolkit/parse.c: Clean up the + previous b64 patch and apply it to all places where + otrl_base64_decode() is called. + +2012-07-17 + + * src/b64.c: Use ceil instead of floor to compute the size + of the data buffer. This prevents a one-byte heap buffer + overflow. Thanks to Justin Ferguson <jnferguson@gmail.com> + for the report. + +2012-06-21 + + * src/context.c: A couple bug fixes. + * Release 4.0.0-beta2 + +2012-06-07 + + * Release 4.0.0-beta1 + +2012-05-08: + + * src/instag.c: + * src/message.c: Returning proper gcry types to avoid + compile warnings. + +2012-05-03: + + * src/instag.c: Fixed otrl_instag_new(). + +2012-04-30: + + * AUTHORS: + * README: + * toolkit/otr_parse.c: + * toolkit/otr_remac.c: + * toolkit/parse.c: + * toolkit/parse.h: + * src/auth.c: + * src/auth.h: + * src/context.c: + * src/context.h: + * src/message.c: + * src/message.h: + * src/privkey.c: + * src/privkey.h: + * src/proto.c: + * src/proto.h: + * src/serial.h: + * src/tests.c: + * src/userstate.c: + * src/userstate.h: More changes for instance tags (Rob Smits). + +2009-06-11: + + * src/auth.c: + * src/auth.h: + * src/context.c: + * src/context.h: + * src/context_priv.h: + * src/message.c: + * src/message.h: + * src/privkey.c: + * src/privkey.h: + * src/proto.c: + * src/proto.h: + * src/serial.h: + * src/tests.c: + * src/userstate.c: + * src/userstate.h: Core instance tag functionality (Lisa Du). + +2009-09-30: + + * Protocol-v2.html: Edits from Göran Weinholt + <goran@weinholt.se> + +2009-04-28: + + * src/auth.c: pubkey_type should be shifted by 8, not 16. It + doesn't matter right now, because it's always 0, but still. + (Thanks to Can Tang.) + +2008-08-15: + + * src/Makefile.am: + * src/context.c: + * src/context.h: + * src/context_priv.c: + * src/context_priv.h: + * src/message.c: + * src/message.h: + * src/proto.c: + * src/proto.h: Willy Lew's updates of the libotr API + +2008-08-06: + + * src/proto.c: gcc 4.2 with -O2 assumes that integer overflow + never occurs when optimizing away tests, including those for + integer overflow. The code was made more specific. + +2008-07-09: + + * src/privkey.h: + * src/privkey.c: Add otrl_privkey_generate_cancel to handle the + case that the background key generation thread is cancelled or + fails. + +2008-07-06: + + * configure.ac: Update libtool version to match 4.0.0. + + * src/privkey-t.h: + * src/privkey.c: + * src/privkey.h: + * src/userstate.c: + * src/userstate.h: Support for generating privkeys in a + background thread. + +2008-07-02: + + * version.h: Change version number to 4.0.0 (but still far from + release). + + * tlv.h: + * proto.h: + * proto.c: + * message.h: + * message.c: + * dh.h: + * dh.c: Support for applications requesting an extra session key + that can be used for things like file transfers. + + * message.h: + * message.c: Applications now use the handle_smp_event callback + to handle SMP events, rather than having to hardcode part of the + SMP state machine themselves. + +2008-06-15: + + * README: Release version 3.2.0. + +2008-06-13: + + * UPGRADING: Clarify what was new in 3.1.0, what was changed + in 3.2.0. + +2008-05-27: + + * UPGRADING: Update documentation. + + * README: + * toolkit/*.[ch]: + * src/*.[ch]: Update copyright dates to 2004-2008. + + * src/tlv.h: Add new OTRL_TLV_SMP1Q TLV type to indicate an + instance of the first SMP message, with an explicit question. + + * src/sm.h: + * src/sm.c: More carefully track the progress of the SMP using a + new smp_prog_state field. Also keep track of whether Bob + received an explicit question from Alice using a new + received_question field. + + * src/message.c: Handle explicit questions for the SMP. + + * src/message.c: Behave better if an SMP message fails + verification. + + * README: + * configure.ac: + * src/version.h: Update version number to 3.2.0. + +2007-07-26 + + * src/sm.c: + * src/message.c: ISO C cleanups (no mixing declarations with + code) + + * src/sm.c: Fixed a 64-bit pointer error + +2007-07-25 + + * src/message.c: Behave sanely if we receive a totally malformed + SMP message. + +2007-07-24 + + * src/proto.h: + * src/proto.c: + * src/message.c: Implemented fragmentation of large messages + + * src/message.h: New callback for fragmentation + + * src/privkey.h: + * src/privkey.c (otrl_privkey_fingerprint_raw): New function to + return a raw hash of an account's public key + + * src/proto.c: Keep track of the API version number passed to + otrl_init() + + * src/context.h: + * src/context.c: + * src/tlv.h: + * src/sm.h: + * src/sm.c: Implemented the Socialist Millionaires' Protocol for + authenticating buddies without using user-visible fingerprints + + * src/b64.h: + * src/b64.c (decode, otrl_base64_decode): Corrected char vs. + unsigned char + + * README: + * configure.ac: + * src/version.h: Change version number to 3.1.0 + + * Most files: Update copyright information + +2007-07-23 + + * src/message.h: + * src/message.c: Added account_name and account_name_free callbacks + to OtrlMessageAppOps to let the application choose how to + display the account name in OTR Error Messages. Based on a + patch from Evan Schoenberg <evan.s@dreskin.net>. + +2006-07-24 + + * src/privkey.h: + * src/privkey.c: Add routines to read and write privkey and + fingerprint data to FILE*s, instead of to filenames. + +2006-05-09 + + * Protocol-v2.html: Fix a typo, and correct the documentation + regarding when MAC keys are revealed. + +2006-04-13 + + * src/context.h: Change "struct fingerprint" to "struct + s_fingerprint" to appease some C++ compilers. + +2006-02-09 + + * src/auth.c (otrl_auth_handle_v1_key_exchange): Fix + uninitialized variable received_pub. + +2005-12-30 + + * src/message.c: Fix a typo, thanks to Anton Blanchard + <anton@samba.org>. + +2005-11-20 + + * src/proto.h: Fix typo in policy #defines. + +2005-11-02 + + * README: + * src/version.h: Release version 3.0.0 + +2005-10-30 + + * Protocol-v2.html: Clarified the uniqueness conditions for the + counter. + + * src/auth.c (otrl_auth_handle_v1_key_exchange): Clear the auth + structure when we receive an unexpected v1 Key Exchange Message. + +2005-10-27 + + * src/auth.h: + * src/auth.c: + * src/message.c: Ensure version 2 AKEs are always done with + fresh D-H parameters. + + * src/proto.h: + * src/proto.c: + * src/message.c: Add a "flags" field to the version 2 Data + Message, which can indicate that the Data Message should be + ignored if unreadable (as opposed to displaying an error). + + * toolkit/parse.h: + * toolkit/parse.c: + * toolkit/otr_parse.c: + * toolkit/otr_remac.c: Deal with the new kind of Data Message. + + * src/message.c: Use the gone_secure callback instead of the + still_secure callback if the other side changes its fingerprint. + +2005-10-19 + + * src/context.h: + * src/context.c: Added protocol_version as an explicit field in + the ConnContext. + + * src/message.h: + * src/message.c: protocol_version no longer needs to be + explicitly passed to the gone_secure() and still_secure() + callbacks. + + * packaging/fedora/libotr.spec: Patches from Paul + + * src/proto.c (rotate_dh_keys): Avoid potential double + gcry_cipher_close(). + + * src/tests.c: Regression test for double gcry_cipher_close(). + +2005-10-16 + + * Major overhaul with implementation of version 2 AKE. + +2005-08-08 + + * toolkit/otr_parse.c (parse): Ignore MACs that are too short, + rather than going into an infinite loop. + +2005-08-04 + + * Protocol: Added section describing fragments. + + * src/proto.h: + * src/proto.c (otrl_proto_fragment_accumulate): + * src/context.h: + * src/context.c (new_context, otrl_context_force_setup): Keep + track of fragments in the ConnContext structure. + + * src/message.c (otrl_message_receiving): Handle fragments in + received messages. + + * src/mem.c: Don't do arithmetic on void pointers. + +2005-07-29 + + * src/message.h: + * src/message.c: Move ops to be the first param of + new_fingerprint, as it is with all the other callbacks. + + * src/context.h: + * src/context.c (otrl_context_set_preshared_secret): + * src/dh.h: + * src/dh.c (otrl_dh_session, otrl_dh_cmpctr): + * src/message.h: + * src/message.c (otrl_message_sending, send_or_error, process_kem) + (otrl_message_receiving, otrl_message_disconnect): + * src/privkey.h: + * src/privkey.c (otrl_privkey_hash_to_human): + * src/proto.h: + * src/proto.c (otrl_proto_create_data): + * src/tlv.h: + * src/tlv.c (otrl_tlv_new, otrl_tlv_parse, otrl_tlv_seriallen) + (otrl_tlv_serialize): Add missing "const"s. (Closes #1243963) + +2005-06-24 + + * README: + * configure.ac: + * packaging/fedora/libotr.spec: + * src/version.h: Change version to 3.0.0 (but don't yet release) + + * Protocol: Clarify that, if the user requests to see the secure + session id in the middle of the conversation, the value + displayed should be the one calculated at the time the private + connection was established (the last Key Exchange Message that + caused a rekeying), _not_ the DH secure id calculated from DH + keys in more recent Data Messages. + + * libotr.m4: Have the version check require an exact match on + the major version, since, for example, source that expects + libotr 2.0.0 won't work with libotr 3.0.0. + + * libotr.m4: Add #include <stdlib.h> to the version test so that + it compiles cleanly with -Wall -Werror. + + * src/proto.c: + * src/dh.h: + * src/dh.c: + * src/context.h: + * src/context.c: Save the secure session id so that it can be + displayed to the user upon request, instead of only when the + private session is initially set up. + + * src/privkey.c: + * src/context.h: + * src/context.c: Allow the app to set a "trust level" for + fingerprints. This is an arbitrary string, intended to indicate + whether (or possibly by what means) the user has verified that + this fingerprint is accurate. + + * src/context.h: + * src/context.c: Allow the app to set an arbitrary binary + "preshared secret" for the ConnContext. This is currently + unused, but in the future it would allow for users to exchange a + secret _before_ they generate their fingerprints. [But the + protocol would have to be extended to support this.] + + * src/message.h: + * src/message.c: Remove the "confirm_fingerprint" callback + which requires the user to acknowledge the new fingerprint + before it can be used. Replace it with a "new_fingerprint" + callback which merely informs the user that a new fingerprint + has been received. + +2005-05-13 + + * libotr.m4: Fixed a bug which made configure fail to find the + libotr header files if they weren't in the standard place. + +2005-05-09 + + * src/privkey.c (otrl_privkey_read_fingerprints): Allow fields, + particularly accountnames, to contain spaces. Closes #1198379. + +2005-05-03 + + * README: + * configure.ac: + * packaging/fedora/libotr.spec: + * src/version.h: Change version to 2.0.2 + + * packaging/debian: Remove this directory, as Thibaut VARENE + <varenet@debian.org> is now responsible for the debian packages. + +2005-02-23 + + * src/privkey.c (otrl_privkey_hash_to_human): Avoid writing a + NUL one byte past the end of the buffer + +2005-02-16 + + * README: + * configure.ac: + * packaging/debian/changelog: + * packaging/fedora/libotr.spec: + * src/version.h: Change version to 2.0.1 + +2005-02-15 + + * src/message.c (otrl_message_sending, otrl_message_receiving) + (otrl_message_disconnect): + * src/proto.c (otrl_proto_accept_key_exchange) + (otrl_proto_create_data, otrl_proto_accept_data): Don't send + encrypted messages to a buddy who has disconnected his private + connection with us. + + * src/message.c (otrl_message_sending): Don't show the user the + "the last message was resent" notice if the message has never + actually been sent before. + +2005-02-09 + + * src/proto.c (otrl_proto_create_data): Copy the msg before + using since, since it may be an alias for context->lastmessage, + which we're going to gcry_free(). + +2005-02-08 + + * README: + * configure.ac: + * packaging/debian/changelog: + * packaging/fedora/libotr.spec: + * src/version.h: Change version to 2.0.0 + +2005-02-07 + + * src/context.h: + * src/context.c (new_context, otrl_context_force_setup): + * src/message.c (otrl_message_sending, otrl_message_receiving): + * src/proto.c (otrl_proto_accept_key_exchange): Keep track of + whether the last message is eligible for retransmission. + +2005-02-02 + + * README: + * configure.ac: + * packaging/debian/changelog: + * packaging/fedora/libotr.spec: + * src/version.h: Change version to 1.99.0 + + * packaging/debian/libotr1.dirs: + * packaging/debian/libotr1.install: + * packaging/debian/rules: Build and install with the correct mandir + + * packaging/debian/rules: Install a shlibs file + + * packaging/debian/control: Add Replaces: to the packages so + that dpkg -i will install them. + + * toolkit/Makefile.am: Create the mandir if it's not yet there + + * packaging/debian/libotr1-dev.dirs: + * packaging/debian/libotr1-dev.install: + * packaging/fedora/libotr.spec: Package the libotr.m4 file + + * Protocol: Added sections on policies and TLVs + +2005-02-01 + + * Makefile.am: + * src/Makefile.am: + * toolkit/Makefile.am: Use automake-1.8 + +2005-01-31 + + * tlv.h: + * tlv.c: + * src/Makefile.am: add new files tlv.c and tlv.h + + * src/message.c (otrl_message_sending): Allow you to specify a + TLV chain to attach to a message. + + * src/message.c (otrl_message_receiving): Also return any TLV + chain attached to the message, if present. + + * src/README: Document new TLV parameters to message functions. + + * src/message.c (otrl_message_receiving): No longer handle + messages starting with "?OTR:" specially; that functionality now + goes into TLVs. + + * src/message.c (otrl_message_disconnect): Send the notice of + disconnect as a OTRL_TLV_DISCONNECTED TLV. + +2005-01-30 + + * README: update documentation for 2.0.0 API + + * src/message.c (otrl_message_receiving): Only send heartbeats + in response to "real" messages. + + * src/message.c (otrl_message_receiving): If we receive a DATA + message whose *plaintext* starts with "?OTR:", display it with + display_otr_message if possible. + + * src/message.c (otrl_message_receiving): Display OTR_ERROR + messages without the leading '?' using display_otr_message. + + * src/message.h (otrl_message_disconnect): + * src/message.c (otrl_message_disconnect): new function + + * src/message.c (otrl_message_receiving): Display the "received + unencrypted" warning message if we receive an unencrypted + message with policy ALWAYS, even when not CONNECTED. + +2005-01-29 + + * src/proto.c (otrl_proto_accept_key_exchange): + * src/message.c (otrl_message_sending, process_kem): Make the + retransmission of an unencrypted message in ALWAYS work. + +2005-01-28 + + * src/message.h: New callback for checking whether a given user + is online. + + * src/message.c (otrl_message_sending): Notify the user if he + attempts to send an unencrypted message with policy ALWAYS. + + * src/message.h: New callback for fetching OTR policy + * src/message.c (otrl_message_sending): Create a ConnContext if + we don't have one already. Use it to fetch the OTR policy. + Just return if the policy is NEVER. Only append the whitespace + tag if the policy is OPPORTUNISTIC or ALWAYS. Don't send + unencrypted messages in ALWAYS, but store them for + retransmission later. + * src/message.c (otrl_message_receiving): Fetch the OTR policy. + Just return if the policy is NEVER. Only send a Key Exchange + Message in response to an unexpected Data or Error Message in + OPPORTUNISTIC and ALWAYS. Only recognize the whitespace tag in + OPPORTUNISTIC and ALWAYS. + + * src/message.h: + * src/message.c: add accountname/protocol/username parameters to + notify callback + + * src/message.h: + * src/message.c: add display_otr_message callback for displaying + OTR control messages + +2005-01-27 + + * src/privkey.h: #include <gcrypt.h> since we use things from + libgcrypt in the .h file + + * src/proto.h: + * src/proto.c: Make otrl_init take unsigned ints as arguments. + + * src/context.h: + * src/context.c: + * src/message.c: + * src/proto.c: Keep track of the last message sent, and + potentially resend it if sending it the first time triggered a + rekey (because the other side had lost its OTR state, for + example). + +2005-01-26 + + * packaging/debian/control: Changed debian package names to + libotr1 and libotr1-dev. + + * libotr.m4: Added copyright notice, more comments + + * src/userstate.c: + * src/userstate.h: New files + + * src/Makefile.am: Added -Wall to default CFLAGS + * toolkit/Makefile.am: Added -Wall to default CFLAGS + + * src/context.c (otrl_context_find, otrl_context_forget_all): + * src/context.h (otrl_context_find, otrl_context_forget_all): + * src/message.c (otrl_message_sending, process_kem) + (process_confresp, otrl_message_receiving): + * src/message.h (otrl_message_sending, otrl_message_receiving) + (OtrlMessageAppOps.confirm_fingerprint): + * src/privkey.c (otrl_privkey_fingerprint, otrl_privkey_read) + (otrl_privkey_generate, otrl_privkey_read_fingerprints) + (otrl_privkey_write_fingerprints, otrl_privkey_find) + (otrl_privkey_forget_all): + * src/privkey.h (otrl_privkey_fingerprint, otrl_privkey_read) + (otrl_privkey_generate, otrl_privkey_read_fingerprints) + (otrl_privkey_write_fingerprints, otrl_privkey_find) + (otrl_privkey_forget_all): + * src/proto.c (otrl_proto_create_key_exchange) + (otrl_proto_accept_key_exchange): + * src/proto.h (otrl_proto_create_key_exchange) + (otrl_proto_accept_key_exchange): Added OtrlUserState parameter + to many calls, eliminating global state. + + * src/privkey.c (otrl_privkey_fingerprint): the buffer is now + passed in, and not static + +2005-01-25 + + * src/version.h: bumped version number to 2.0.0 because API + changed incompatibly + * configure.ac: bumped version number to 2.0.0 because API + changed incompatibly + + * src/message.h: added accountname parameter to + confirm_fingerprint callback + * src/message.c: passed accountname to confirm_fingerprint + callback + + * libotr.m4: new file + * Makefile.am: install (and uninstall) new libotr.m4 file + + * tools/Makefile.am: clean up manpage symlinks and add an + uninstall rule + +2005-01-23 + + * src/proto.h: moved numeric version defines into version.h + * src/version.h: moved numeric version defines into version.h + + * src/message.c (otrl_message_receiving): Update the context + list if we create a new context + +2005-01-22 + + Released 1.0.4. + + Initial autoconfiscation, thanks to Greg Troxel <gdt@ir.bbn.com>. + + * src/message.c: log, but otherwise ignore, unrecognized OTR + messages diff --git a/comm/third_party/libotr/INSTALL b/comm/third_party/libotr/INSTALL new file mode 100644 index 0000000000..4226b2f44d --- /dev/null +++ b/comm/third_party/libotr/INSTALL @@ -0,0 +1,45 @@ +REQUIREMENTS + +To compile the OTR library and toolkit, you'll need at least: + - libgpg-error 1.0 [ftp://ftp.gnupg.org/gcrypt/libgpg-error/] + - libgcrypt 1.2.0 [ftp://ftp.gnupg.org/gcrypt/libgcrypt/] + +If you install these with a package manager, you'll probably need the +-dev or -devel versions of the packages. + +On Fedora, these packages are: + libgpg-error-devel libgcrypt-devel + +On Debian (testing or unstable), they are: + libgpg-error-dev libgcrypt11-dev + +COMPILING + +If you're got a CVS copy, you will need to regenerate the configure +script using: + + ./bootstrap + +Once you have the configure script (which comes with the source +deistribution), run it with the "--with-pic" option, as well as any +other options that may be necessary for your system. Some examples: + +Linux: + ./configure --with-pic --prefix=/usr --mandir=/usr/share/man + +NETBSD: + CPPFLAGS="-I/usr/pkg/include" LDFLAGS="-R/usr/pkg/lib -L/usr/pkg/lib" \ + ./configure --with-pic --prefix=/usr/pkg + +mingw cross-compiler from Debian Linux: + ./configure --with-pic --host=i586-mingw32msvc \ + --prefix=/usr/i586-mingw32msvc + +Once the configure script writes a Makefile, you should be able to just +run "make". + +INSTALLATION + +You should be able to simply do "make install". If you want to install +somewhere other than / (this is useful for package creators), use +something like "make DESTDIR=/path/to/install/to install". diff --git a/comm/third_party/libotr/Makefile.am b/comm/third_party/libotr/Makefile.am new file mode 100644 index 0000000000..0508e67052 --- /dev/null +++ b/comm/third_party/libotr/Makefile.am @@ -0,0 +1,14 @@ +ACLOCAL_AMFLAGS = -I config + +SUBDIRS = src toolkit +if BUILD_TESTS +SUBDIRS += tests +endif + +EXTRA_DIST = Protocol-v3.html UPGRADING packaging libotr.m4 libotr.pc.in bootstrap + +aclocaldir = $(datadir)/aclocal +aclocal_DATA = libotr.m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libotr.pc diff --git a/comm/third_party/libotr/Makefile.in b/comm/third_party/libotr/Makefile.in new file mode 100644 index 0000000000..6096f6a60f --- /dev/null +++ b/comm/third_party/libotr/Makefile.in @@ -0,0 +1,894 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_TESTS_TRUE@am__append_1 = tests +subdir = . +DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ + $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/configure $(am__configure_deps) \ + $(srcdir)/config.h.in $(srcdir)/libotr.pc.in COPYING \ + COPYING.LIB config/compile config.guess config/config.guess \ + config.sub config/config.sub config/depcomp install-sh \ + config/install-sh config/missing ltmain.sh config/ltmain.sh \ + $(top_srcdir)/config/compile $(top_srcdir)/config/config.guess \ + $(top_srcdir)/config/config.sub \ + $(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \ + $(top_srcdir)/config/missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = libotr.pc +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(aclocaldir)" \ + "$(DESTDIR)$(pkgconfigdir)" +DATA = $(aclocal_DATA) $(pkgconfig_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +DIST_SUBDIRS = src toolkit tests +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I config +SUBDIRS = src toolkit $(am__append_1) +EXTRA_DIST = Protocol-v3.html UPGRADING packaging libotr.m4 libotr.pc.in bootstrap +aclocaldir = $(datadir)/aclocal +aclocal_DATA = libotr.m4 +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libotr.pc +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +libotr.pc: $(top_builddir)/config.status $(srcdir)/libotr.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-aclocalDATA: $(aclocal_DATA) + @$(NORMAL_INSTALL) + @list='$(aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(aclocaldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(aclocaldir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(aclocaldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(aclocaldir)" || exit $$?; \ + done + +uninstall-aclocalDATA: + @$(NORMAL_UNINSTALL) + @list='$(aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(aclocaldir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(aclocaldir)" "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-aclocalDATA install-pkgconfigDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-aclocalDATA uninstall-pkgconfigDATA + +.MAKE: $(am__recursive_targets) all install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-aclocalDATA install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pkgconfigDATA install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-aclocalDATA uninstall-am \ + uninstall-pkgconfigDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/NEWS b/comm/third_party/libotr/NEWS new file mode 100644 index 0000000000..1be74666e3 --- /dev/null +++ b/comm/third_party/libotr/NEWS @@ -0,0 +1,273 @@ +9 Mar 2016: +- Release 4.1.1 +- Fix an integer overflow bug that can cause a heap buffer overflow (and + from there remote code execution) on 64-bit platforms +- Fix possible free() of an uninitialized pointer +- Be stricter about parsing v3 fragments +- Add a testsuite ("make check" to run it), but only on Linux for now, + since it uses Linux-specific features such as epoll +- Fix a memory leak when reading a malformed instance tag file +- Protocol documentation clarifications + +21 Oct 2014: +- Release 4.1.0 +- Modernized autoconf build system +- Use constant-time comparisons where needed +- Use gcrypt secure memory allocation +- Correctly reject attempts to fragment a message into too many pieces +- Fix a missing opdata when sending message fragments +- Don't lose the first user message when REQUIRE_ENCRYPTION is set +- Fix some memory leaks +- Correctly check for children contexts' state when forgetting a context +- API Changes: + - Added API functions otrl_context_find_recent_instance and + otrl_context_find_recent_secure_instance. + +24 Aug 2012: +- Release 4.0.0 +- Support v3 of the OTR protocol +- The main new feature: sensibly handle the case where a user is logged + in multiple times to the same IM account +- API changes: + - instance tags, to support multiple simultaneous logins + - support for asynchronous private key generation + - the ability to provide an "extra" symmetric key to applications + (with forward secrecy) + - applications can supply a formation conversion callback if they do + not natively use XHTML-style UTF8 markup + - error messages formerly provided by libotr are now handled using + callbacks to the application, for better i18n support + - otrl_message_sending now handles message fragmentation internally + +27 May 2008: +- Added support for one-way authentication using an explicit question, + based on the SOUPS 2008 user study. + +1 Aug 2007: +- Released 3.1.0 + +24 Jul 2007: +- Added fragmentation support for large messages +- Added new method for buddy authentication which does not require the + (explicit) use of fingerprints. + +02 Nov 2005: +- Released 3.0.0 + +16 Oct 2005: +- Major overhaul with implementation of version 2 of the protocol. + +24 Jun 2005: +- Remove the "confirm_fingerprint" callback which requires the user to + acknowledge the new fingerprint before it can be used. Replace it + with a "new_fingerprint" callback which merely informs the user that a + new fingerprint has been received. +- Allow the app to set a "trust level" for fingerprints. This is an + arbitrary string, intended to indicate whether (or possibly by what + means) the user has verified that this fingerprint is accurate. +- Clarify that, if the user requests to see the secure session id in + the middle of the conversation, the value displayed should be the one + calculated at the time the private connection was established (the + last Key Exchange Message that caused a rekeying), _not_ the DH secure + id calculated from DH keys in more recent Data Messages. + +03 May 2005: +- Released 2.0.2 + +16 Feb 2005: +- Released 2.0.1 +- Don't send encrypted messages to a buddy who has disconnected his + private connection with us. +- Don't show the user the "the last message was resent" notice if the + message has never actually been sent before. +- Fix a crash bug that happened when messages were retransmitted under + certain circumstances. + +08 Feb 2005: +- Released 2.0.0 +- Keep track of whether a given message is eligible for retransmission + +02 Feb 2005: +- Released 1.99.0, the first preview release of 2.0.0 + +31 Jan 2005: +- Machine-readable records can now be attached to Data Messages inside + the private channel. + +30 Jan 2005: +- New OtrlUserState datatype encapsulates private keys and known + fingerprints, instead of having a single global list. +- Added libotr.m4 for helping to autoconfiscate packages that use + libotr. +- Resend the last message if it caused a re-keying. +- New OtrlPolicy datatype allows you to specify a per-connection OTR + policy: never use OTR, OTR only if manually requested, automatically + start OTR if possible, refuse to *not* use OTR. +- New callbacks: display_otr_message, policy, is_logged_in + +22 Jan 2005: +- Released 1.0.4 +- Log, but otherwise ignore, unrecognized OTR messages. +- Initial autoconfiscation, thanks to Greg Troxel <gdt@ir.bbn.com>. + +18 Jan 2005: +- Released 1.0.3 +- Split gaim-otr and libotr into separate packages. + +13 Jan 2005: +- Generate private keys automatically, if needed. Show a Please Wait + dialog while this is happening. +- We may as well try to use the "tag" method of checking for OTR, even + when we don't already know a fingerprint for the correspondent. +- Add version checking to the otrl_init() call. + +12 Jan 2005: +- Refactored the logic parts of gaim-otr into libotr, so they can be + shared by other libotr-enabled apps. + +21 Dec 2004: +- Released 1.0.2 +- If a Man-in-the-Middle steals both Alice's and Bob's DSA private keys, + he can perform a birthday attack to try to get his session id with + each end to match. Since the session id was only 64 bits long, his + work was only 2^32, which is not enough. We now make the session id + the whole SHA-1 hash, instead of truncating it. +- Made otr_sesskeys output the calculated public key as well, for added + ease of forging messages when you don't know any plaintext. + +14 Dec 2004: +- Released 1.0.1 +- Added a more sensible error message in the event that we receive our + own OTR Key Exchange messages. +- If we're about to send a plaintext message to a correspondent for whom + we've got a fingerprint, append a special (whitespace) OTR tag + sequence. The other side (if in fact running OTR) will recognize it + and start a Key Exchange. + +12 Dec 2004: +- Released 1.0.0 + +11 Dec 2004: +- OTR button now gets sensitized and desensitized along with the other + buttons in the conversation window when you log in and out of + accounts. + +10 Dec 2004: +- Released 0.9.9rc2 +- Heartbeats now only get sent if (1) we have just received a message, + and (2) we haven't sent one to that user in over a minute. + +09 Dec 2004: +- Back out of the sending of heartbeats. They were causing too many + problems. It seems some networks don't let buddies know when you + log out, and then you get a dialog box "unable to send message" each + minute. :-( + +08 Dec 2004: +- Released 0.9.9rc1 +- Removed the 100 private connection limit, by not using a fixed amount + of secure memory. Unfortuantely, this means that *no* memory is + pinned any more, but pinning only ever happened before in the unlikely + event you ran gaim as root. +- Changed the "Private connection with (username) refreshed" dialog at + Paul's request so that it's no longer in "scary" "evil" bold, and + rephrased it so it's less likely to be misread as "refused" instead of + "refreshed". ;-) +- We now send heartbeats (OTR Data Messages with an empty message part) + once a minute, to anyone we're confident is still online. If both + sides are doing this, then keys get rotated regularly, even if one + or both sides aren't actively typing. This aids perfect forward + secrecy. + +04 Dec 2004: +- Fixed a bug wherein multi-person chat windows would get the OTR button + in their button bar if the OTR plugin was enabled when one of them was + active. + +03 Dec 2004: +- Released 0.9.1 + +02 Dec 2004: +- Clicking "OTR: Private" when you're already private will display an + info dialog letting you know the connection was refreshed (assuming it + actually is; if the other side isn't running OTR at all, the dialog + doesn't show, and if the other side had lost its private connection, a + new one will be established, with the "new private connection" dialog + displayed to each side (as before)). +- The toolip for "OTR: Private" is now "Refresh the private connection". +- "make install" now depends on "make all". +- Added man page for OTR toolkit programs +- Log a debug message when we receive and discard a heartbeat + +1 Dec 2004: +- Fixed the Makefiles so that "make clean" also removes the binaries +- Fixed the Makefiles so that they install into DESTDIR +- Added packaging/debian + +30 Nov 2004: +- Released 0.9.0 +- Included the OTR Messaging Toolkit. See the README for details. + +28 Nov 2004: +- Finished the Protocol document +- Changed the name of the plugin binary from "otr-plugin.so" to + "gaim-otr.so". *** NOTE: this means you'll have to (1) remove the + old otr-plugin.so file from your plugins directory, and (2) re-enable + the Off-the-Record Messaging plugin in the Preferences panel. +- Included MAC keys used to create messages in the revealed MAC section + of the Data message, in addition to MAC keys used to verify messages. +- Set all exported symbols to start with otrl_ (for the library) or + otrg_ (for the gaim plugin), in preparation for moving the pieces + into their own directories. +- If we receive a Data message with no actual message in it, don't + display it to the user. This may eventually be useful for doing + "heartbeat" key rotations. +- Separated libotr and gaim-otr into their own directories. + +27 Nov 2004: +- Switched from using gaim_notify_* to a slightly modified version that + doesn't grab the focus + +26 Nov 2004: +- Put all the cipher operations in secure memory. This makes each + private connection take 9472 bytes of secure memory, so we up the + available amount of secure memory to 100 times that. Eventually, + we'd like to make this dynamically grow. + +25 Nov 2004: +- Released 0.8.3 +- Don't put the DSA keys in libgcrypt secure memory, since (a) we read + them off disk anyway, and (b) we want to avoid running out of secure + memory. +- Removed the "Do you want to start a private conversation" dialogs when + one side in encrypted and the other side isn't, and instead just try + to start one if we know for sure the other side supports it. +- Sped up the DH computations by using a 320-bit exponent. + +23 Nov 2004: +- Released 0.8.2 +- There was a crash if you received an OTR Query before setting up a + private key. Fixed. +- The fingerprint in the UI is now selectable, for cut/paste. +- *** Protocol change. We're no longer backward compatible. + - The "revealed MAC keys" moved out of the MAC'd region of the data + packet. It's not wrong where it is, but it's more obviously + correct in the new place. + +22 Nov 2004: +- Released 0.8.1 +- Jabber wasn't working, for two reasons: + - it sticks <tags>...</tags> around the message + - it refers to the same user by multiple names; e.g. "user@jabber.org" + vs. "user@jabber.org/Gaim" + Both are now fixed: we look for the OTR message anywhere in the packet + now, not just at the beginning, and we normalize all usernames. +- Each account now has its own private key / fingerprint + - This is so you don't automatically leak the information that the + accounts are owned by the same person +- There's a better indicator of private / not private status in the + conversation window, which you can click to start the private + communication. + +21 Nov 2004: +- Initial 0.8.0 release diff --git a/comm/third_party/libotr/Protocol-v3.html b/comm/third_party/libotr/Protocol-v3.html new file mode 100644 index 0000000000..49b2edbabc --- /dev/null +++ b/comm/third_party/libotr/Protocol-v3.html @@ -0,0 +1,1710 @@ +<!DOCTYPE html +PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html><head> +<title>Off-the-Record Messaging Protocol version 3 + + +

Off-the-Record Messaging Protocol version 3

+

This document describes version 3 of the Off-the-Record Messaging +protocol. The main changes over version 2 include:

+
    +
  • Both fragmented and unfragmented messages contain sender and +recipient instance tags. This avoids an issue on IM networks that +always relay all messages to all sessions of a client who is logged +in multiple times. In this situation, OTR clients can attempt to +establish an OTR session indefinitely if there are interleaving +messages from each of the sessions.
  • +
  • An extra symmetric key is derived during AKE. This may be used for +secure communication over a different channel (e.g., file transfer, +voice chat).
  • +
+

Very high level overview

+

OTR assumes a network model which provides in-order delivery of +messages, but that some messages may not get delivered at all +(for example, if the user disconnects). There may be +an active attacker, who is allowed to perform a Denial of +Service attack, but not to learn the contents of messages.

+
    +
  1. Alice signals to Bob that she would like (using an OTR Query Message) +or is willing (using a whitespace-tagged plaintext message) to use OTR +to communicate. Either mechanism should convey the version(s) of OTR +that Alice is willing to use.
  2. +
  3. Bob initiates the authenticated key exchange (AKE) with Alice. +Versions 2 and 3 of OTR use a variant of the SIGMA protocol as its AKE.
  4. +
  5. Alice and Bob exchange Data Messages to send information to each +other.
  6. +
+

High level overview

+

Requesting an OTR conversation

+

There are two ways Alice can inform Bob that she is willing to use +the OTR protocol to speak with him: by sending him the OTR Query Message, +or by including a special "tag" consisting of whitespace characters in +one of her messages to him. Each method also includes a way for Alice +to communicate to Bob which versions of the OTR protocol she is willing +to speak with him.

+

The semantics of the OTR Query Message are that Alice is +requesting that Bob start an OTR conversation with her (if, of +course, he is willing and able to do so). On the other hand, the +semantics of the whitespace tag are that Alice is merely +indicating to Bob that she is willing and able to have an OTR +conversation with him. If Bob has a policy of "only use OTR when it's +explicitly requested", for example, then he would start an OTR +conversation upon receiving an OTR Query Message, but would not +upon receiving the whitespace tag.

+

Authenticated Key Exchange (AKE)

+

This section outlines the version of the SIGMA protocol used as the +AKE. All exponentiations are done modulo a particular 1536-bit prime, +and g is a generator of that group, as indicated in the detailed +description below. Alice and Bob's long-term authentication public keys +are pubA and pubB, respectively.

+

The general idea is that Alice and Bob do an unauthenticated +Diffie-Hellman (D-H) key exchange to set up an encrypted channel, and +then do mutual authentication inside that channel.

+

Bob will be initiating the AKE with Alice.

+
    +
  • Bob: +
      +
    1. Picks a random value r (128 bits)
    2. +
    3. Picks a random value x (at least 320 bits)
    4. +
    5. Sends Alice AESr(gx), HASH(gx)
    6. +
  • +
  • Alice: +
      +
    1. Picks a random value y (at least 320 bits)
    2. +
    3. Sends Bob gy
    4. +
  • +
  • Bob: +
      +
    1. Verifies that Alice's gy is a legal value (2 <= +gy <= modulus-2)
    2. +
    3. Computes s = (gy)x
    4. +
    5. Computes two AES keys c, c' and four MAC keys m1, m1', m2, m2' by +hashing s in various ways
    6. +
    7. Picks keyidB, a serial number for his D-H key +gx
    8. +
    9. Computes MB = MACm1(gx, gy, +pubB, keyidB)
    10. +
    11. Computes XB = pubB, keyidB, +sigB(MB)
    12. +
    13. Sends Alice r, AESc(XB), +MACm2(AESc(XB))
    14. +
  • +
  • Alice: +
      +
    1. Uses r to decrypt the value of gx sent earlier
    2. +
    3. Verifies that HASH(gx) matches the value sent earlier
    4. +
    5. Verifies that Bob's gx is a legal value (2 <= +gx <= modulus-2)
    6. +
    7. Computes s = (gx)y (note that this will be the +same as the value of s Bob calculated)
    8. +
    9. Computes two AES keys c, c' and four MAC keys m1, m1', m2, m2' by +hashing s in various ways (the same as Bob)
    10. +
    11. Uses m2 to verify MACm2(AESc(XB))
    12. +
    13. Uses c to decrypt AESc(XB) to obtain +XB = pubB, keyidB, +sigB(MB)
    14. +
    15. Computes MB = MACm1(gx, +gy, pubB, keyidB)
    16. +
    17. Uses pubB to verify sigB(MB)
    18. + +
    19. Picks keyidA, a serial number for her D-H key +gy
    20. +
    21. Computes MA = MACm1'(gy, gx, +pubA, keyidA)
    22. +
    23. Computes XA = pubA, keyidA, +sigA(MA)
    24. +
    25. Sends Bob AESc'(XA), +MACm2'(AESc'(XA))
    26. +
  • +
  • Bob: +
      +
    1. Uses m2' to verify MACm2'(AESc'(XA))
    2. +
    3. Uses c' to decrypt AESc'(XA) to obtain +XA = pubA, keyidA, +sigA(MA)
    4. +
    5. Computes MA = MACm1'(gy, +gx, pubA, keyidA)
    6. +
    7. Uses pubA to verify sigA(MA)
    8. +
  • +
  • If all of the verifications succeeded, Alice and Bob now know each +other's Diffie-Hellman public keys, and share the value s. Alice is +assured that s is known by someone with access to the private key +corresponding to pubB, and similarly for Bob.
  • +
+

Exchanging data

+

This section outlines the method used to protect data being exchanged +between Alice and Bob. As above, all exponentiations are done modulo +a particular 1536-bit prime, and g is a generator of +that group, as indicated in the detailed description below.

+

Suppose Alice has a message (msg) to send to Bob.

+
    +
  • Alice: +
      +
    1. Picks the most recent of her own D-H encryption keys that Bob has +acknowledged receiving (by using it in a Data Message, or failing that, +in the AKE). Let keyA be that key, and let keyidA +be its serial number.
    2. +
    3. If the above key is Alice's most recent key, she generates a new D-H key +(next_dh), to get the serial number keyidA+1.
    4. +
    5. Picks the most recent of Bob's D-H encryption keys that she has +received from him (either in a Data Message or in the AKE). Let +keyB by that key, and let keyidB be its serial +number.
    6. +
    7. Uses Diffie-Hellman to compute a shared secret from the two keys +keyA and keyB, and generates the +sending AES key, ek, and the sending MAC key, mk, as detailed +below.
    8. +
    9. Collects any old MAC keys that were used in previous messages, but +will never again be used (because their associated D-H keys are no +longer the most recent ones) into a list, oldmackeys.
    10. +
    11. Picks a value of the counter, ctr, so that the triple +(keyA, keyB, ctr) is never the same for more +than one Data Message Alice sends to Bob.
    12. +
    13. Computes TA = (keyidA, keyidB, next_dh, +ctr, AES-CTRek,ctr(msg))
    14. +
    15. Sends Bob TA, MACmk(TA), +oldmackeys
    16. +
  • +
  • Bob: +
      +
    1. Uses Diffie-Hellman to compute a shared secret from the two keys +labelled by keyidA and keyidB, and generates the +receiving AES key, ek, and the receiving MAC key, mk, as detailed +below. (These will be the same as the keys Alice generated, above.)
    2. +
    3. Uses mk to verify MACmk(TA).
    4. +
    5. Uses ek and ctr to decrypt +AES-CTRek,ctr(msg).
    6. +
    +
  • +
+

Socialist Millionaires' Protocol (SMP)

+

While data messages are being exchanged, either Alice or Bob may +run SMP to detect impersonation or man-in-the-middle attacks. +As above, all exponentiations are done modulo a particular 1536-bit +prime, and g1 is a generator of that group. All sent values +include zero-knowledge proofs that they were generated according to +this protocol, as indicated in the detailed description below.

+

Suppose Alice and Bob have secret information x and y respectively, +and they wish to know whether x = y. The Socialist Millionaires' Protocol +allows them to compare x and y without revealing any other information +than the value of (x == y). For OTR, the secrets contain +information about both parties' long-term authentication public keys, +as well as information entered by the users themselves. If x = y, +this means that Alice and Bob entered the same secret information, and +so must be the same entities who established that secret to begin with.

+

Assuming that Alice begins the exchange:

+
    +
  • Alice: +
      +
    1. Picks random exponents a2 and a3
    2. +
    3. Sends Bob g2a = g1a2 and +g3a = g1a3
    4. +
  • +
  • Bob: +
      +
    1. Picks random exponents b2 and b3
    2. +
    3. Computes g2b = g1b2 and +g3b = g1b3
    4. +
    5. Computes g2 = g2ab2 and +g3 = g3ab3
    6. +
    7. Picks random exponent r
    8. +
    9. Computes Pb = g3r and +Qb = g1r g2y
    10. +
    11. Sends Alice g2b, g3b, Pb and +Qb
    12. +
  • +
  • Alice: +
      +
    1. Computes g2 = g2ba2 and +g3 = g3ba3
    2. +
    3. Picks random exponent s
    4. +
    5. Computes Pa = g3s and +Qa = g1s g2x
    6. +
    7. Computes Ra = (Qa / Qb) +a3
    8. +
    9. Sends Bob Pa, Qa and Ra
    10. +
  • +
  • Bob: +
      +
    1. Computes Rb = (Qa / Qb) +b3
    2. +
    3. Computes Rab = Rab3
    4. +
    5. Checks whether Rab == (Pa / Pb)
    6. +
    7. Sends Alice Rb
    8. +
  • +
  • Alice: +
      +
    1. Computes Rab = Rba3
    2. +
    3. Checks whether Rab == (Pa / Pb)
    4. +
  • +
  • If everything is done correctly, then Rab should hold the +value of (Pa / Pb) times +(g2a3b3)(x - y), which means that the test at the end of +the protocol will only succeed if x == y. Further, since +g2a3b3 is a random number +not known to any party, if x is not equal to y, no other information is +revealed.
  • +
+

Details of the protocol

+

Unencoded messages

+

This section describes the messages in the OTR protocol that are not +base-64 encoded binary.

+

OTR Query Messages

+

If Alice wishes to communicate to Bob that she would like to use OTR, +she sends a message containing the string "?OTR" followed by an +indication of what versions of OTR she is willing to use with Bob. The +version string is constructed as follows:

+
    +
  • If she is willing to use OTR version 1, the version string must +start with "?".
  • +
  • If she is willing to use OTR versions other than 1, a "v" followed +by the byte identifiers for the versions in question, followed by "?". +The byte identifier for OTR version 2 is "2", and similarly for 3. The +order of the identifiers between the "v" and the "?" does not matter, +but none should be listed more than once.
  • +
+

For example:

+
+
"?OTR?"
+
Version 1 only
+
"?OTRv2?"
+
Version 2 only
+
"?OTRv23?"
+
Versions 2 and 3
+
"?OTR?v2?"
+
Versions 1 and 2
+
"?OTRv24x?"
+
Version 2, and hypothetical future versions identified by "4" and +"x"
+
"?OTR?v24x?"
+
Versions 1, 2, and hypothetical future versions identified by "4" and +"x"
+
"?OTR?v?"
+
Also version 1 only
+
"?OTRv?"
+
A bizarre claim that Alice would like to start an OTR conversation, +but is unwilling to speak any version of the protocol
+
+

These strings may be hidden from the user (for example, in +an attribute of an HTML tag), and/or may be accompanied by an +explanitory message ("Alice has requested an Off-the-Record private +conversation."). If Bob is willing to use OTR with Alice (with a +protocol version that Alice has offered), he should start the AKE.

+

Tagged plaintext messages

+

If Alice wishes to communicate to Bob that she is willing to use OTR, +she can attach a special whitespace tag to any plaintext message she +sends him. This tag may occur anywhere in the message, and may be +hidden from the user (as in the Query Messages, above).

+

The tag consists of the following 16 bytes, followed by one or more +sets of 8 bytes indicating the version of OTR Alice is willing to +use:

+
    +
  • Always send "\x20\x09\x20\x20\x09\x09\x09\x09" +"\x20\x09\x20\x09\x20\x09\x20\x20", followed by one or more of:
  • +
  • "\x20\x09\x20\x09\x20\x20\x09\x20" to indicate a willingness to use +OTR version 1 with Bob (note: this string must come before all other +whitespace version tags, if it is present, for backwards +compatibility)
  • +
  • "\x20\x20\x09\x09\x20\x20\x09\x20" to indicate a willingness to use +OTR version 2 with Bob
  • +
  • "\x20\x20\x09\x09\x20\x20\x09\x09" to indicate a willingness to use +OTR version 3 with Bob
  • +
+

If Bob is willing to use OTR with Alice (with a protocol version that +Alice has offered), he should start the AKE. On the other hand, if +Alice receives a plaintext message from Bob (rather than an initiation +of the AKE), she should stop sending him the whitespace tag.

+

OTR Error Messages

+

Any message containing the string "?OTR Error:" is an OTR Error +Message. The following part of the message should contain +human-readable details of the error.

+

Encoded messages

+

This section describes the byte-level format of the base-64 encoded +binary OTR messages. The binary form of each of the messages is +described below. To transmit one of these messages, construct the ASCII +string consisting of the five bytes "?OTR:", followed by the base-64 +encoding of the binary form of the message, followed by the byte +".".

+

For the Diffie-Hellman group computations, the group is the one +defined in RFC 3526 with 1536-bit modulus (hex, big-endian):

+
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
+
+

and a generator (g) of 2. Note that this means that whenever you see a +Diffie-Hellman exponentiation in this document, it always means that the +exponentiation is done modulo the above 1536-bit number.

+

Data types

+
+
Bytes (BYTE):
+
1 byte unsigned value
+
Shorts (SHORT):
+
2 byte unsigned value, big-endian
+
Ints (INT):
+
4 byte unsigned value, big-endian
+
Multi-precision integers (MPI):
+
4 byte unsigned len, big-endian +
len byte unsigned value, big-endian +
(MPIs must use the minimum-length encoding; i.e. no leading 0x00 + bytes. This is important when calculating public key + fingerprints.)
+
Opaque variable-length data (DATA):
+
4 byte unsigned len, big-endian +
len byte data
+
Initial CTR-mode counter value (CTR):
+
8 bytes data
+
Message Authentication Code (MAC):
+
20 bytes MAC data
+
+

Public keys, signatures, and fingerprints

+

OTR users have long-lived public keys that they use for +authentication (but not encryption). The current version of +the OTR protocol only supports DSA public keys, but there is a key type +marker for future extensibility.

+
+
OTR public authentication DSA key (PUBKEY):
+
Pubkey type (SHORT) +
  • DSA public keys have type 0x0000
+p (MPI) +
q (MPI) +
g (MPI) +
y (MPI) +
  • (p,q,g,y) are the DSA public key parameters
+
+
+

OTR public keys are used to generate signatures; different +types of keys produce signatures in different formats. The format for a +signature made by a DSA public key is as follows:

+
+
DSA signature (SIG):
+
(len is the length of the DSA public parameter q, which in +current implementations must be 20 bytes, or 160 bits) +
len byte unsigned r, big-endian +
len byte unsigned s, big-endian
+
+

OTR public keys have fingerprints, which are hex strings that +serve as identifiers for the public key. The fingerprint is calculated +by taking the SHA-1 hash of the byte-level representation of the public +key. However, there is an exception for backwards compatibility: if the +pubkey type is 0x0000, those two leading 0x00 bytes are omitted from the +data to be hashed. The encoding assures that, assuming the hash +function itself has no useful collisions, and DSA keys have length less +than 524281 bits (500 times larger than most DSA keys), no two public +keys will have the same fingerprint.

+

Instance Tags

+

Clients include instance tags in all OTR version 3 messages. Instance +tags are 32-bit values that are intended to be persistent. If the same +client is logged into the same account from multiple locations, the +intention is that the client will have different instance tags at each +location. As shown below, OTR version 3 messages (fragmented and +unfragmented) include the source and destination instance tags. If a client +receives a message that lists a destination instance tag different from its +own, the client should discard the message.

+

The smallest valid instance tag is 0x00000100. It is appropriate to set the +destination instance tag to '0' when an actual destination instance tag is +not known at the time the message is prepared. If a client receives a +message with the sender instance tag set to less than 0x00000100, it should +discard the message. Similarly, if a client receives a message with the +recipient instance tag set to greater than 0 but less than 0x00000100, it +should discard the message. +

+ +

This avoids an issue on IM networks that always relay all messages to +all sessions of a client who is logged in multiple times. In this +situation, OTR clients can attempt to establish an OTR session indefinitely +if there are interleaving messages from each of the sessions.

+

D-H Commit Message

+

This is the first message of the AKE. Bob sends it to Alice to +commit to a choice of D-H encryption key (but the key itself is not yet +revealed). This allows the secure session id to be much shorter than in +OTR version 1, while still preventing a man-in-the-middle attack on +it.

+
+
Protocol version (SHORT)
+
The version number of this protocol is 0x0003.
+
Message type (BYTE)
+
The D-H Commit Message has type 0x02.
+
Sender Instance tag (INT)
+
The instance tag of the person sending this message.
+
Receiver Instance tag (INT)
+
The instance tag of the intended recipient. +For a commit message this will often be 0, since the other party +may not have identified their instance tag yet.
+
Encrypted gx (DATA)
+
Produce this field as follows: +
    +
  • Choose a random value r (128 bits)
  • +
  • Choose a random value x (at least 320 bits)
  • +
  • Serialize gx as an MPI, gxmpi. [gxmpi will probably be +196 bytes long, starting with "\x00\x00\x00\xc0".]
  • +
  • Encrypt gxmpi using AES128-CTR, with key r and initial counter value +0. The result will be the same length as gxmpi.
  • +
  • Encode this encrypted value as the DATA field.
  • +
+
Hashed gx (DATA)
+
This is the SHA256 hash of gxmpi.
+
+

D-H Key Message

+

This is the second message of the AKE. Alice sends it to Bob, and it +simply consists of Alice's D-H encryption key.

+
+
Protocol version (SHORT)
+
The version number of this protocol is 0x0003.
+
Message type (BYTE)
+
The D-H Key Message has type 0x0a.
+
Sender Instance tag (INT)
+
The instance tag of the person sending this message.
+
Receiver Instance tag (INT)
+
The instance tag of the intended recipient.
+
gy (MPI)
+
Choose a random value y (at least 320 bits), and calculate +gy.
+
+

Reveal Signature Message

+

This is the third message of the AKE. Bob sends it to Alice, +revealing his D-H encryption key (and thus opening an encrypted +channel), and also authenticating himself (and the parameters of the +channel, preventing a man-in-the-middle attack on the channel itself) to +Alice.

+
+
Protocol version (SHORT)
+
The version number of this protocol is 0x0003.
+
Message type (BYTE)
+
The Reveal Signature Message has type 0x11.
+
Sender Instance tag (INT)
+
The instance tag of the person sending this message.
+
Receiver Instance tag (INT)
+
The instance tag of the intended recipient.
+
Revealed key (DATA)
+
This is the value r picked earlier.
+
Encrypted signature (DATA)
+
This field is calculated as follows: +
    +
  • Compute the Diffie-Hellman shared secret s.
  • +
  • Use s to compute an AES key c and two MAC keys m1 and m2, as specified below.
  • +
  • Select keyidB, a serial number for the D-H key computed +earlier. It is an INT, and must be greater than 0.
  • +
  • Compute the 32-byte value MB to be the SHA256-HMAC of the +following data, using the key m1:
    +
    gx (MPI)
    +
    gy (MPI)
    +
    pubB (PUBKEY)
    +
    keyidB (INT)
    +
  • +
  • Let XB be the following structure:
    +
    pubB (PUBKEY)
    +
    keyidB (INT)
    +
    sigB(MB) (SIG)
    +
    This is the signature, using the private part of the key +pubB, of the 32-byte MB (taken modulo q instead of +being truncated (as described in FIPS-186), and not hashed again).
    +
  • +
  • Encrypt XB using AES128-CTR with key c and initial +counter value 0.
  • +
  • Encode this encrypted value as the DATA field.
  • +
+
MAC'd signature (MAC)
+
This is the SHA256-HMAC-160 (that is, the first 160 bits of the +SHA256-HMAC) of the encrypted signature field (including the four-byte +length), using the key m2.
+
+

Signature Message

+

This is the final message of the AKE. Alice sends it to Bob, +authenticating herself and the channel parameters to him.

+
+
Protocol version (SHORT)
+
The version number of this protocol is 0x0003.
+
Message type (BYTE)
+
The Signature Message has type 0x12.
+
Sender Instance tag (INT)
+
The instance tag of the person sending this message.
+
Receiver Instance tag (INT)
+
The instance tag of the intended recipient.
+
Encrypted signature (DATA)
+
This field is calculated as follows: +
    +
  • Compute the Diffie-Hellman shared secret s.
  • +
  • Use s to compute an AES key c' and two MAC keys m1' and m2', as specified below.
  • +
  • Select keyidA, a serial number for the D-H key computed +earlier. It is an INT, and must be greater than 0.
  • +
  • Compute the 32-byte value MA to be the SHA256-HMAC of the +following data, using the key m1':
    +
    gy (MPI)
    +
    gx (MPI)
    +
    pubA (PUBKEY)
    +
    keyidA (INT)
    +
  • +
  • Let XA be the following structure:
    +
    pubA (PUBKEY)
    +
    keyidA (INT)
    +
    sigA(MA) (SIG)
    +
    This is the signature, using the private part of the key +pubA, of the 32-byte MA (which does not need to be +hashed again to produce the signature).
    +
  • +
  • Encrypt XA using AES128-CTR with key c' and initial +counter value 0.
  • +
  • Encode this encrypted value as the DATA field.
  • +
+
MAC'd signature (MAC)
+
This is the SHA256-HMAC-160 (that is, the first 160 bits of the +SHA256-HMAC) of the encrypted signature field (including the four-byte +length), using the key m2'.
+
+

Data Message

+

This message is used to transmit a private message to the +correspondent. It is also used to reveal old MAC keys.

+

The plaintext message (either before encryption, or after decryption) +consists of a human-readable message (encoded in UTF-8, optionally with +HTML markup), optionally followed by:

+
    +
  • a single NUL (a BYTE with value 0x00), and
  • +
  • zero or more TLV (type/length/value) records (with no padding +between them)
  • +
+

Each TLV record is of the form:

+
+
Type (SHORT)
+
The type of this record. Records with unrecognized types should be +ignored.
+
Length (SHORT)
+
The length of the following field
+
Value (len BYTEs) [where len is the value of the Length field]
+
Any pertinent data for the record type.
+
+

Some TLV examples:

+
+
\x00\x01\x00\x00
+
A TLV of type 1, containing no data
+
\x00\x00\x00\x05\x68\x65\x6c\x6c\x6f
+
A TLV of type 0, containing the value "hello"
+
+

The currently defined TLV record types are:

+
+
Type 0: Padding
+
The value may be an arbitrary amount of data, which should be +ignored. This type can be used to disguise the length of the plaintext +message.
+
Type 1: Disconnected
+
If the user requests to close the private connection, you may send a +message (possibly with empty human-readable part) containing a record +with this TLV type just before you discard the session keys, and +transition to MSGSTATE_PLAINTEXT (see below). If you receive a TLV +record of this type, you should transition to MSGSTATE_FINISHED (see +below), and inform the user that his correspondent has closed his end of +the private connection, and the user should do the same.
+
Type 2: SMP Message 1
+
The value represents an initiating message of the Socialist +Millionaires' Protocol, described below.
+
Type 3: SMP Message 2
+
The value represents the second message in an instance of SMP.
+
Type 4: SMP Message 3
+
The value represents the third message in an instance of SMP.
+
Type 5: SMP Message 4
+
The value represents the final message in an instance of SMP.
+
Type 6: SMP Abort Message
+
If the user cancels SMP prematurely or encounters an error in the +protocol and cannot continue, you may send a message (possibly with empty +human-readable part) with this TLV type to instruct the other party's +client to abort the protocol. The associated length should be zero and +the associated value should be empty. If you receive a TLV of this type, +you should change the SMP state to SMP_EXPECT1 (see below).
+
Type 7: SMP Message 1Q
+
Like a SMP Message 1, but whose value begins with a NUL-terminated +user-specified question.
+
Type 8: Extra symmetric key
+
If you wish to use the extra symmetric key, compute it yourself as +outlined in the section "Extra symmetric key", below. Then send this +type 8 TLV to your buddy to indicate that you'd like to use the extra +symmetric key for something. The value of the TLV begins with a 4-byte +indication of what this symmetric key will be used for (file transfer, +voice encryption, etc.). After that, the contents are use-specific +(which file, etc.). There are no currently defined uses. Note that the +value of the key itself is not placed into the TLV; your buddy +will compute it on his/her own. +
+
+

SMP Message TLVs (types 2-5) all carry data sharing the same general +format:

+
+
MPI count (INT)
+
The number of MPIs contained in the remainder of the TLV.
+
MPI 1 (MPI)
+
The first MPI of the TLV, serialized into a byte array.
+
MPI 2 (MPI)
+
The second MPI of the TLV, serialized into a byte array.
+
etc.
+
+

There should be as many MPIs as declared in the MPI count field. For +the exact MPIs passed for each SMP TLV, see the SMP state machine +below.

+

A message with an empty human-readable part (the plaintext is of zero +length, or starts with a NUL) is a "heartbeat" packet, and should not +be displayed to the user. (But it's still useful to effect key +rotations.)

+

Data Message format:

+
+
Protocol version (SHORT)
+
The version number of this protocol is 0x0003.
+
Message type (BYTE)
+
The Data Message has type 0x03.
+
Sender Instance tag (INT)
+
The instance tag of the person sending this message.
+
Receiver Instance tag (INT)
+
The instance tag of the intended recipient.
+
Flags (BYTE)
+
The bitwise-OR of the flags for this message. Usually you should +set this to 0x00. The only currently defined flag is:
+
IGNORE_UNREADABLE (0x01)
+
If you receive a Data Message with this flag set, and you are unable +to decrypt the message or verify the MAC (because, for example, you +don't have the right keys), just ignore the message instead of producing +some kind of error or notification to the user.
+
+
Sender keyid (INT)
+
Must be strictly greater than 0, and increment by 1 with each key +change
+
Recipient keyid (INT)
+
Must therefore be strictly greater than 0, as the receiver has no +key with id 0. +
The sender and recipient keyids are those used to encrypt and MAC +this message.
+
DH y (MPI)
+
The *next* [i.e. sender_keyid+1] public key for the sender
+
Top half of counter init (CTR)
+
This should monotonically increase (as a big-endian value) for + each message sent with the same (sender keyid, recipient keyid) + pair, and must not be all 0x00.
+
Encrypted message (DATA)
+
Using the appropriate encryption key (see below) derived from the + sender's and recipient's DH public keys (with the keyids given in + this message), perform AES128 counter-mode (CTR) encryption of the + message. The initial counter is a 16-byte value whose first 8 + bytes are the above "top half of counter init" value, and whose + last 8 bytes are all 0x00. Note that counter mode does not change + the length of the message, so no message padding needs to be done. + If you *want* to do message padding (to disguise the length of + your message), use the above TLV of type 0.
+
Authenticator (MAC)
+
The SHA1-HMAC, using the appropriate MAC key (see below) of everything + from the Protocol version to the end of the encrypted message
+
Old MAC keys to be revealed (DATA)
+
See "Revealing MAC Keys", below.
+
+

Socialist Millionaires' Protocol (SMP)

+

The Socialist Millionaires' Protocol allows two parties with secret +information x and y respectively to check whether (x==y) without revealing +any additional information about the secrets. The protocol used by OTR is +based on the work of Boudot, Schoenmakers and Traore (2001). A full +justification for its use in OTR is made by Alexander and Goldberg, +in a paper published in 2007. The following is a technical account +of what is transmitted during the course of the protocol.

+

Secret information

+

The secret information x and y compared during this protocol contains +not only information entered by the users, but also information unique to +the conversation in which SMP takes place. Specifically, the format is:

+
+
Version (BYTE)
+
The version of SMP used. The version described here is 1.
+
Initiator fingerprint (20 BYTEs)
+
The fingerprint that the party initiating SMP is using in +the current conversation.
+
Responder fingerprint (20 BYTEs)
+
The fingerprint that the party that did not initiate SMP is +using in the current conversation.
+
Secure Session ID
+
The ssid described below.
+
User-specified secret
+
The input string given by the user at runtime.
+
+

Then the SHA256 hash of the above is taken, and the digest becomes the +actual secret (x or y) to be used in SMP. The additional fields insure +that not only do both parties know the same secret input string, but no +man-in-the-middle is capable of reading their communication either.

+

The SMP state machine

+

Whenever the OTR message state machine has MSGSTATE_ENCRYPTED set +(see below), the SMP state machine may progress. If at any point +MSGSTATE_ENCRYPTED becomes unset, SMP must abandon its state and return +to its initial setup. The SMP state consists of one main variable, as +well as information from the partial computations at each protocol step.

+

Expected Message

+

This main state variable for SMP controls what SMP-specific TLVs will +be accepted. This variable has no effect on type 0 or type 1 TLVs, which +are always allowed. smpstate can take one of four values:

+
+
SMPSTATE_EXPECT1
+
This state indicates that only type 2 (SMP message 1) and type 7 +(SMP message 1Q) TLVs should be accepted. This is the default state when +SMP has not yet begun. This state is also reached whenever an error +occurs or SMP is aborted, and the protocol must be restarted from the +beginning.
+
SMPSTATE_EXPECT2
+
This state indicates that only type 3 TLVs (SMP message 2) should +be accepted.
+
SMPSTATE_EXPECT3
+
This state indicates that only type 4 TLVs (SMP message 3) should +be accepted.
+
SMPSTATE_EXPECT4
+
This state indicates that only type 5 TLVs (SMP message 4) should +be accepted.
+
+

State Transitions

+

There are 7 actions that an OTR client must handle:

+
    +
  • Received TLVs: +
      +
    • SMP Message 1
    • +
    • SMP Message 2
    • +
    • SMP Message 3
    • +
    • SMP Message 4
    • +
    • SMP Abort Message
    • +
  • +
  • User actions:
  • +
      +
    • User requests to begin SMP
    • +
    • User requests to abort SMP
    • +
    +
+

The following sections outline what is to be done in each case. They +all assume that MSGSTATE_ENCRYPTED is set. For simplicity, they also +assume that Alice has begun SMP, and Bob is responding to her.

+

SMP Hash function

+

In the following actions, there are many places where a SHA256 hash of +an integer followed by one or two MPIs is taken. The input to this hash +function is:

+
+
Version (BYTE)
+
This distinguishes calls to the hash function at different points in +the protocol, to prevent Alice from replaying Bob's zero knowledge proofs +or vice versa.
+
First MPI (MPI)
+
The first MPI given as input, serialized in the usual way.
+
Second MPI (MPI)
+
The second MPI given as input, if present, serialized in the usual way. +If only one MPI is given as input, this field is simply omitted.
+
+

Receiving a type 2 TLV (SMP message 1)

+

SMP message 1 is sent by Alice to begin a DH exchange to determine two +new generators, g2 and g3. It contains the +following mpi values:

+
+
g2a
+
Alice's half of the DH exchange to determine g2.
+
c2, D2
+
A zero-knowledge proof that Alice knows the exponent associated with +her transmitted value g2a.
+
g3a
+
Alice's half of the DH exchange to determine g3.
+
c3, D3
+
A zero-knowledge proof that Alice knows the exponent associated with +her transmitted value g3a.
+
+

A type 7 (SMP Message 1Q) TLV is the same as the above, but is +preceded by a user-specified question, which is associated with the +user-specified portion of the secret.

+

When Bob receives this TLV he should do:

+
+
If smpstate is not SMPSTATE_EXPECT1:
+
Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort) +to Alice.
+
If smpstate is SMPSTATE_EXPECT1:
+
Verify Alice's zero-knowledge proofs for g2a and +g3a: +
    +
  1. Check that both g2a and g3a are >= 2 and +<= modulus-2.
  2. +
  3. Check that c2 = SHA256(1, g1D2 +g2ac2).
  4. +
  5. Check that c3 = SHA256(2, g1D3 +g3ac3).
  6. +
+Create a type 3 TLV (SMP message 2) and send it to Alice: +
    +
  1. Determine Bob's secret input y, which is to be compared to Alice's +secret x.
  2. +
  3. Pick random exponents b2 and b3. +These will used during the DH exchange to pick generators.
  4. +
  5. Pick random exponents r2, r3, r4, r5 and r6. +These will be used to add a blinding factor to the final results, and +to generate zero-knowledge proofs that this message was created honestly.
  6. +
  7. Compute g2b = g1b2 and +g3b = g1b3
  8. +
  9. Generate a zero-knowledge proof that the exponent b2 is +known by setting c2 = SHA256(3, g1r2) and +D2 = r2 - b2 c2 mod q. In the zero-knowledge proofs the D values +are calculated modulo q = (p - 1) / 2, where p is the same 1536-bit prime +as elsewhere. The random exponents are 1536-bit numbers.
  10. +
  11. Generate a zero-knowledge proof that the exponent b3 is +known by setting c3 = SHA256(4, g1r3) and +D3 = r3 - b3 c3 mod q.
  12. +
  13. Compute g2 = g2ab2 and +g3 = g3ab3
  14. +
  15. Compute Pb = g3r4 and +Qb = g1r4 g2y
  16. +
  17. Generate a zero-knowledge proof that Pb and Qb +were created according to the protocol by setting +cP = SHA256(5, g3r5, g1r5 +g2r6), D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q.
  18. +
  19. Store the values of g3a, g2, g3, +b3, Pb and Qb for use later in the +protocol.
  20. +
  21. Send Alice a type 3 TLV (SMP message 2) containing g2b, +c2, D2, g3b, c3, D3, Pb, Qb, cP, D5 +and D6, in that order.
  22. +
+Set smpstate to SMPSTATE_EXPECT3.
+
+

Receiving a type 3 TLV (SMP message 2)

+

SMP message 2 is sent by Bob to complete the DH exchange to +determine the new generators, g2 and g3. +It also begins the construction of the values used in the final +comparison of the protocol. It contains the following mpi values:

+
+
g2b
+
Bob's half of the DH exchange to determine g2.
+
c2, D2
+
A zero-knowledge proof that Bob knows the exponent associated with +his transmitted value g2b.
+
g3b
+
Bob's half of the DH exchange to determine g3.
+
c3, D3
+
A zero-knowledge proof that Bob knows the exponent associated with +his transmitted value g3b.
+
Pb, Qb
+
These values are used in the final comparison to determine if Alice +and Bob share the same secret.
+
cP, D5, D6
+
A zero-knowledge proof that Pb and Qb were +created according to the protcol given above.
+
+

When Alice receives this TLV she should do:

+
+
If smpstate is not SMPSTATE_EXPECT2:
+
Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort) +to Bob.
+
If smpstate is SMPSTATE_EXPECT2:
+
Verify Bob's zero-knowledge proofs for g2b, +g3b, Pb and Qb: +
    +
  1. Check that g2b, +g3b, Pb and Qb are >= 2 and +<= modulus-2.
  2. +
  3. Check that c2 = SHA256(3, g1D2 +g2bc2).
  4. +
  5. Check that c3 = SHA256(4, g1D3 +g3bc3).
  6. +
  7. Check that cP = SHA256(5, g3D5 +PbcP, g1D5 +g2D6 QbcP).
  8. +
+Create a type 4 TLV (SMP message 3) and send it to Bob: +
    +
  1. Pick random exponents r4, r5, r6 and r7. +These will be used to add a blinding factor to the final results, and +to generate zero-knowledge proofs that this message was created honestly.
  2. +
  3. Compute g2 = g2ba2 and +g3 = g3ba3
  4. +
  5. Compute Pa = g3r4 and +Qa = g1r4 g2x
  6. +
  7. Generate a zero-knowledge proof that Pa and Qa +were created according to the protocol by setting +cP = SHA256(6, g3r5, g1r5 +g2r6), D5 = r5 - r4 cP mod q and D6 = r6 - x cP mod q.
  8. +
  9. Compute Ra = (Qa / Qb) +a3
  10. +
  11. Generate a zero-knowledge proof that Ra was created +according to the protocol by setting cR = SHA256(7, g1r7, +(Qa / Qb)r7) and +D7 = r7 - a3 cR mod q.
  12. +
  13. Store the values of g3b, (Pa / Pb), +(Qa / Qb) and a3 for use later in the +protocol.
  14. +
  15. Send Bob a type 4 TLV (SMP message 3) containing Pa, +Qa, cP, D5, D6, Ra, cR and D7 in that order.
  16. +
+Set smpstate to SMPSTATE_EXPECT4.
+
+

Receiving a type 4 TLV (SMP message 3)

+

SMP message 3 is Alice's final message in the SMP exchange. It +has the last of the information required by Bob to determine if x = y. +It contains the following mpi values:

+
+
Pa, Qa
+
These values are used in the final comparison to determine if Alice +and Bob share the same secret.
+
cP, D5, D6
+
A zero-knowledge proof that Pa and Qa were +created according to the protcol given above.
+
Ra
+
This value is used in the final comparison to determine if Alice +and Bob share the same secret.
+
cR, D7
+
A zero-knowledge proof that Ra was +created according to the protcol given above.
+
+
+

When Bob receives this TLV he should do:

+
+
If smpstate is not SMPSTATE_EXPECT3:
+
Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort) +to Bob.
+
If smpstate is SMPSTATE_EXPECT3:
+
Verify Alice's zero-knowledge proofs for Pa, Qa +and Ra: +
    +
  1. Check that Pa, Qa and Ra are >= 2 and +<= modulus-2.
  2. +
  3. Check that cP = SHA256(6, g3D5 +PacP, g1D5 g2D6 +QacP).
  4. +
  5. Check that cR = SHA256(7, g1D7 +g3acR, (Qa / Qb)D7 +RacR).
  6. +
+Create a type 5 TLV (SMP message 4) and send it to Alice: +
    +
  1. Pick a random exponent r7. +This will be used to generate Bob's final zero-knowledge proof that +this message was created honestly.
  2. +
  3. Compute Rb = (Qa / Qb) +b3
  4. +
  5. Generate a zero-knowledge proof that Rb was created +according to the protocol by setting cR = SHA256(8, g1r7, +(Qa / Qb)r7) and +D7 = r7 - b3 cR mod q.
  6. +
  7. Send Alice a type 5 TLV (SMP message 4) containing Rb, +cR and D7 in that order.
  8. +
+Check whether the protocol was successful: +
    +
  1. Compute Rab = Rab3.
  2. +
  3. Determine if x = y by checking the equivalent condition that +(Pa / Pb) = Rab.
  4. +
+Set smpstate to SMPSTATE_EXPECT1, as no more messages are expected from +Alice.
+
+

Receiving a type 5 TLV (SMP message 4)

+

SMP message 4 is Bob's final message in the SMP exchange. It +has the last of the information required by Alice to determine if x = y. +It contains the following mpi values:

+
+
Rb
+
This value is used in the final comparison to determine if Alice +and Bob share the same secret.
+
cR, D7
+
A zero-knowledge proof that Rb was +created according to the protcol given above.
+
+
+

When Alice receives this TLV she should do:

+
+
If smpstate is not SMPSTATE_EXPECT4:
+
Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort) +to Bob.
+
If smpstate is SMPSTATE_EXPECT4:
+
Verify Bob's zero-knowledge proof for Rb: +
    +
  1. Check that Rb is >= 2 and +<= modulus-2.
  2. +
  3. Check that cR = SHA256(8, g1D7 +g3bcR, (Qa / Qb)D7 +RbcR).
  4. +
+Check whether the protocol was successful: +
    +
  1. Compute Rab = Rba3.
  2. +
  3. Determine if x = y by checking the equivalent condition that +(Pa / Pb) = Rab.
  4. +
+Set smpstate to SMPSTATE_EXPECT1, as no more messages are expected from +Bob.
+
+

User requests to begin SMP

+
+
If smpstate is not set to SMPSTATE_EXPECT1:
+
SMP is already underway. If you wish to restart SMP, send a +type 6 TLV (SMP abort) to the other party and then proceed as if +smpstate was SMPSTATE_EXPECT1. Otherwise, you may simply continue the +current SMP instance.
+
If smpstate is set to SMPSTATE_EXPECT1:
+
No current exchange is underway. In this case, Alice should +create a valid type 2 TLV (SMP message 1) as follows: +
    +
  1. Determine her secret input x, which is to be compared to Bob's +secret y.
  2. +
  3. Pick random values a2 and a3 (1536 bits). +These will be Alice's exponents for the DH exchange to pick generators.
  4. +
  5. Pick random values r2 and r3 (1536 bits). +These will be used to generate zero-knowledge proofs that this message +was created according to the protocol.
  6. +
  7. Compute g2a = g1a2 and +g3a = g1a3
  8. +
  9. Generate a zero-knowledge proof that the exponent a2 is +known by setting c2 = SHA256(1, g1r2) and +D2 = r2 - a2 c2 mod q.
  10. +
  11. Generate a zero-knowledge proof that the exponent a3 is +known by setting c3 = SHA256(2, g1r3) and +D3 = r3 - a3 c3 mod q.
  12. +
  13. Store the values of x, a2 and a3 +for use later in the protocol.
  14. +
  15. Send Bob a type 2 TLV (SMP message 1) containing g2a, +c2, D2, g3a, c3 and D3 in that order.
  16. +
+Set smpstate to SMPSTATE_EXPECT2.
+
+

User requests to abort SMP

+

In all cases, send a type 6 TLV (SMP abort) to the correspondent and +set smpstate to SMPSTATE_EXPECT1.

+

Key Management

+

For each correspondent, keep track of:

+
+
Your two most recent DH public/private key pairs
+
our_dh[our_keyid] (most recent) and our_dh[our_keyid-1] (previous)
+
His two most recent DH public keys
+
their_y[their_keyid] (most recent) and their_y[their_keyid-1] +(previous)
+
+ +

When starting a private conversation with a correspondent, generate +two DH key pairs for yourself, and set our_keyid = 2. Note that all DH +key pairs should have a private part that is at least 320 bits long.

+ +
+
When you send AKE messages:
+
Send the public part of our_dh[our_keyid-1], with the keyid field, + of course, set to (our_keyid-1).
+ +
Upon completing the AKE:
+
If the specified keyid equals either their_keyid or their_keyid-1, + and the DH pubkey contained in the AKE messages matches the + one you've stored for that keyid, that's great. Otherwise, forget + all values of their_y[], and of their_keyid, and set their_keyid to + the keyid value given in the AKE messages, and + their_y[their_keyid] to the DH pubkey value given in the AKE + messages. their_y[their_keyid-1] should be set to NULL.
+ +
When you send a Data Message:
+
Set the sender keyid to (our_keyid-1), and the recipient keyid to + (their_keyid). Set the DH pubkey in the Data message to the public + part of our_dh[our_keyid]. Use our_dh[our_keyid-1] and + their_y[their_keyid] to calculate session keys, as outlined below. + Use the "sending AES key" to encrypt the message, and the "sending + MAC key" to calculate its MAC.
+ +
When you receive a Data Message:
+
Use the keyids in the message to select which of your DH key pairs + and which of his DH pubkeys to use to verify the MAC. If the keyids + do not represent either the most recent key or the previous key (for + either the sender or receiver), reject the message. Also reject the + message if the sender keyid is their_keyid-1, but + their_y[their_keyid-1] is NULL. + +

Otherwise, calculate the session keys as outlined below. Use the + "receiving MAC key" to verify the MAC on the message. If it does not + verify, reject the message.

+ +

Check that the counter in the Data message is strictly larger than the + last counter you saw using this pair of keys. If not, reject the + message.

+ +

If the MAC verifies, decrypt the message using the "receiving AES + key".

+ +

Finally, check if keys need rotation:

+
    +
  • If the "recipient keyid" in the Data message equals our_keyid, then + he's seen the public part of our most recent DH key pair, so you + must securely forget our_dh[our_keyid-1], increment our_keyid, and set + our_dh[our_keyid] to a new DH key pair which you generate.
  • +
  • If the "sender keyid" in the Data message equals their_keyid, + increment their_keyid, and set their_y[their_keyid] to the new DH + pubkey specified in the Data message.
  • +
+
+ +

Computing AES keys, MAC keys, and the secure session id

+

OTR uses Diffie-Hellman to calculate shared secrets in the usual way: +if Bob knows x, and tells Alice gx, and Alice knows y, and +tells Bob gy, then they each can calculate s = +gxy: Alice calculates (gx)y, and Bob +calculates (gy)x.

+

During the AKE, Alice and Bob each calculate s in this way, and then +they each compute seven values based on s:

+
    +
  • A 64-bit secure session id, ssid
  • +
  • Two 128-bit AES encryption keys, c and c'
  • +
  • Four 256-bit SHA256-HMAC keys, m1, m2, m1', and m2'
  • +
+

This is done in the following way:

+
    +
  • Write the value of s as a minimum-length MPI, as specified above +(4-byte big-endian len, len-byte big-endian value). Let this +(4+len)-byte value be "secbytes".
  • +
  • For a given byte b, define h2(b) to be the 256-bit output of the +SHA256 hash of the (5+len) bytes consisting of the byte b followed by +secbytes.
  • +
  • Let ssid be the first 64 bits of h2(0x00).
  • +
  • Let c be the first 128 bits of h2(0x01), and let c' be the second +128 bits of h2(0x01).
  • +
  • Let m1 be h2(0x02).
  • +
  • Let m2 be h2(0x03).
  • +
  • Let m1' be h2(0x04).
  • +
  • Let m2' be h2(0x05).
  • +
+

c, m1, and m2 are used to create and verify the Reveal Signature +Message; c', m1', and m2' are used to create and verify the Signature +message.

+

If the user requests to see the secure session id, it should be +displayed as two 32-bit bigendian unsigned values, in C "%08x" format. +If the user transmitted the Reveal Signature message during the AKE that +produced this ssid, then display the first 32 bits in bold, and the +second 32 bits in non-bold. If the user transmitted the Signature +message instead, display the first 32 bits in non-bold, and the +second 32 bits in bold. This session id can be used by the parties to +verify (say, over the telephone, assuming the parties recognize each +others' voices) that there is no man-in-the-middle by having each side +read his bold part to the other. [Note that this only needs to be done +in the event that the users do not trust that their long-term signature +keys have not been compromised.]

+

During the exchange of Data Messages, Alice and Bob use the keyids +listed in the Data Message to select Diffie-Hellman keys to use to +compute s, and the (4+len)-byte value of secbytes, as above.

+

From this, they calculate four values:

+
    +
  • Two 128-bit AES encryption keys, the "sending AES key", and the +"receiving AES key"
  • +
  • Two 160-bit SHA1-HMAC keys, the "sending MAC key", and the +"receiving MAC key"
  • +
+

These keys are calculated as follows:

+
    +
  • Alice (and similarly for Bob) determines if she is the "low" end +or the "high" end of this Data Message. If Alice's public key is +numerically greater than Bob's public key, then she +is the "high" end. Otherwise, she is the "low" end. Note that who is the +"low" end and who is the "high" end can change every time a new D-H +public key is exchanged in a Data Message.
  • +
  • She sets the values of "sendbyte" and "recvbyte" according to +whether she is the the "low" or the "high" end of the Data Message: +
      +
    • If she is the "high" end, she sets "sendbyte" to 0x01 and "recvbyte" +to 0x02.
    • +
    • If she is the "low" end, she sets "sendbyte" to 0x02 and "recvbyte" +to 0x01.
    • +
  • +
  • For a given byte b, define h1(b) to be the 160-bit output of the +SHA-1 hash of the (5+len) bytes consisting of the byte b, followed by +secbytes.
  • +
  • The "sending AES key" is the first 16 bytes of h1(sendbyte).
  • +
  • The "sending MAC key" is the 20-byte SHA-1 hash of the 16-byte +sending AES key.
  • +
  • The "receiving AES key" is the first 16 bytes of h1(recvbyte).
  • +
  • The "receiving MAC key" is the 20-byte SHA-1 hash of the 16-byte +receiving AES key.
  • +
+

Extra symmetric key

+

OTR version 3 defines an additional symmetric key that can be derived +by the communicating parties to use for application-specific purposes, +such as file transfer, voice encryption, etc. When one party wishes to +use the extra symmetric key, he or she creates a type 8 TLV attached to +a Data Message (see above). The key itself is then derived using the +same "secbytes" used to compute the encryption and MAC keys used to +protect the Data Message. +The extra symmetric key is derived by calculating +h2(0xFF) and keeping the entire 256 bits, using the same definition +of h2 as above.

+

Upon receipt of the Data Message containing the type 8 TLV, the +recipient will compute the extra symmetric key in the same way. Note +that the value of the extra symmetric key is not contained in +the TLV itself.

+

Revealing MAC keys

+

Whenever you are about to forget either one of your old D-H key pairs, or +one of your correspondent's old D-H public keys, take all of the +receiving MAC keys +that were generated by that key (note that there are up to two: the +receiving MAC keys produced by the pairings of that key with +each of two of the other side's keys; but note that you only need to +take MAC keys that were actually used to verify a MAC on a message), and +put them (as a set of +concatenated 20-byte values) into the "Old MAC keys to be revealed" +section of the next Data Message you send. This in done to allow the +forgeability of OTR transcripts: once the MAC keys are revealed, anyone +can modify an OTR message and still have it appear valid. But since we +don't reveal the MAC keys until their corresponding pubkeys are being +discarded, there is no danger of accepting a message as valid which +uses a MAC key which has already been revealed.

+

Fragmentation

+

Some networks may have a maximum message size that is too small to +contain an encoded OTR message. In that event, the sender may choose +to split the message into a number of fragments. This section +describes the format of the fragments. All OTR version 2 and 3 clients +must be able to assemble received fragments, but performing +fragmentation on outgoing messages is optional.

+ +
+
Transmitting Fragments
+
If you have information about the maximum size of message you are + able to send (the different IM networks have different limits), you + can fragment an encoded OTR message as follows: +
    +
  • Start with the OTR message as you would normally transmit it. For + example, a Data Message would start with "?OTR:AAED" and end + with ".".
  • +
  • Break it up into sufficiently small pieces. Let the number of + pieces be (n), and the pieces be + piece[1],piece[2],...,piece[n].
  • +
  • Transmit (n) OTR version 3 fragmented messages with the following + (printf-like) structure (as k runs from 1 to n inclusive): + +

    "?OTR|%x|%x,%hu,%hu,%s," , sender_instance, receiver_instance, + k , n , piece[k]

    + + OTR version 2 messages get fragmented in a similar format, but + without the instance tags fields: + +

    "?OTR,%hu,%hu,%s," , + k , n , piece[k]

  • + +
  • Note that k and n are unsigned short ints (2 bytes), and each has + a maximum value of 65535. Also, each piece[k] must be + non-empty. The instance tags (if applicable) and the k and n + values may have leading zeroes.
  • +
+

Note that fragments are not themselves messages that can be + fragmented: you can't fragment a fragment.

+ +
Receiving Fragments:
+ +
If you receive a message containing "?OTR|" (note that you'll need + to check for this _before_ checking for any of the other "?OTR:" + markers): + +
    +
  • Parse it as the printf statement above into k, n, and + piece.
  • +
  • If the recipient's own instance tag does not match the listed + receiver instance tag, and the listed receiver instance tag is not + zero, the recipient should discard the message and optionally pass + along a warning for the user.
  • +
  • Let (K,N) be your currently stored fragment number, and F be your + currently stored fragment. [If you have no currently stored + fragment, then K = N = 0 and F = "".]
  • + +
  • If k == 0 or n == 0 or k > n, discard this (illegal) + fragment.
  • + +
  • If k == 1: +
      +
    • Forget any stored fragment you may have
    • +
    • Store (piece) as F.
    • +
    • Store (k,n) as (K,N).
    • +
  • + +
  • If n == N and k == K+1: +
      +
    • Append (piece) to F.
    • +
    • Store (k,n) as (K,N).
    • +
  • + +
  • Otherwise: +
      +
    • Forget any stored fragment you may have
    • +
    • Store "" as F.
    • +
    • Store (0,0) as (K,N).
    • +
  • +
+ +

After this, if N > 0 and K == N, treat F as the received + message.

+ +

If you receive a non-OTR message, or an unfragmented message, + forget any stored fragment you may have, store "" as F and store + (0,0) as (K,N).

+ +

OTR version 2 fragmented messages follow the same behaviour as + described above, but do not list the sender and receiver instance + tags.

+
+ +

For example, here is a Data Message we would like to transmit over a +network with an unreasonably small maximum message size:

+ +
+?OTR:AAMDJ+MVmSfjFZcAAAAAAQAAAAIAAADA1g5IjD1ZGLDVQEyCgCyn9hb
+rL3KAbGDdzE2ZkMyTKl7XfkSxh8YJnudstiB74i4BzT0W2haClg6dMary/jo
+9sMudwmUdlnKpIGEKXWdvJKT+hQ26h9nzMgEditLB8vjPEWAJ6gBXvZrY6ZQ
+rx3gb4v0UaSMOMiR5sB7Eaulb2Yc6RmRnnlxgUUC2alosg4WIeFN951PLjSc
+ajVba6dqlDi+q1H5tPvI5SWMN7PCBWIJ41+WvF+5IAZzQZYgNaVLbAAAAAAA
+AAAEAAAAHwNiIi5Ms+4PsY/L2ipkTtquknfx6HodLvk3RAAAAAA==.
+
+ +

We could fragment this message into (for example) three + pieces:

+ +
+?OTR|5a73a599|27e31597,00001,00003,?OTR:AAMDJ+MVmSfjFZcAAAAA
+AQAAAAIAAADA1g5IjD1ZGLDVQEyCgCyn9hbrL3KAbGDdzE2ZkMyTKl7XfkSx
+h8YJnudstiB74i4BzT0W2haClg6dMary/jo9sMudwmUdlnKpIGEKXWdvJKT+
+hQ26h9nzMgEditLB8v,
+
+ +
+?OTR|5a73a599|27e31597,00002,00003,jPEWAJ6gBXvZrY6ZQrx3gb4v0
+UaSMOMiR5sB7Eaulb2Yc6RmRnnlxgUUC2alosg4WIeFN951PLjScajVba6dq
+lDi+q1H5tPvI5SWMN7PCBWIJ41+WvF+5IAZzQZYgNaVLbAAAAAAAAAAEAAAA
+HwNiIi5Ms+4PsY/L2i,
+
+ +
+?OTR|5a73a599|27e31597,00003,00003,pkTtquknfx6HodLvk3RAAAAAA
+==.,
+
+

The protocol state machine

+

An OTR client maintains separate state for every correspondent. For +example, Alice may have an active OTR conversation with Bob, while +having an unprotected conversation with Charlie. This state consists of +two main state variables, as well as some other information (such as +encryption keys). The two main state variables are:

+

Message state

+

The message state variable, msgstate, controls what happens to +outgoing messages typed by the user. It can take one of three +values:

+
+
MSGSTATE_PLAINTEXT
+
This state indicates that outgoing messages are sent without +encryption. This is the state that is used before an OTR conversation +is initiated. This is the initial state, and the only way to +subsequently enter this state is for the user to explicitly request to +do so via some UI operation.
+
MSGSTATE_ENCRYPTED
+
This state indicates that outgoing messages are sent encrypted. +This is the state that is used during an OTR conversation. The only way +to enter this state is for the authentication state machine (below) to +successfully complete.
+
MSGSTATE_FINISHED
+
This state indicates that outgoing messages are not delivered at +all. This state is entered only when the other party indicates he has +terminated his side of the OTR conversation. For example, if Alice and +Bob are having an OTR conversation, and Bob instructs his OTR client to +end its private session with Alice (for example, by logging out), Alice +will be notified of this, and her client will switch to +MSGSTATE_FINISHED mode. This prevents Alice from accidentally sending a +message to Bob in plaintext. (Consider what happens if Alice was in the +middle of typing a private message to Bob when he suddenly logs out, +just as Alice hits Enter.)
+
+

Authentication state

+

The authentication state variable, authstate, can take one of four +values (plus one extra for OTR version 1 compatibility):

+
+
AUTHSTATE_NONE
+
This state indicates that the authentication protocol is not +currently in progress. This is the initial state.
+
AUTHSTATE_AWAITING_DHKEY
+
After Bob initiates the authentication protocol by sending Alice +the D-H Commit Message, he enters this state to await Alice's reply.
+
AUTHSTATE_AWAITING_REVEALSIG
+
After Alice receives Bob's D-H Commit Message, and replies with her +own D-H Key Message, she enters this state to await Bob's reply.
+
AUTHSTATE_AWAITING_SIG
+
After Bob receives Alice's D-H Key Message, and replies with his own +Reveal Signature Message, he enters this state to await Alice's reply.
+
AUTHSTATE_V1_SETUP
+
For OTR version 1 compatibility, if Bob sends a version 1 Key +Exchange Message to Alice, he enters this state to await Alice's +reply.
+
+

After:

+
    +
  • Alice (in AUTHSTATE_AWAITING_REVEALSIG) receives Bob's Reveal +Signature Message (and replies with her own Signature Message), or +
  • +
  • Bob (in AUTHSTATE_AWAITING_SIG) receives Alice's Signature Message, +/li> +
+

then, +assuming the signature verifications succeed, the msgstate +variable is transitioned to MSGSTATE_ENCRYPTED. Regardless of whether +the signature verifications succeed, the authstate variable is +transitioned to AUTHSTATE_NONE.

+

Policies

+

OTR clients can set different policies for different +correspondents. For example, Alice could set up her client so that it +speaks only OTR version 3, except with Charlie, who she knows has only +an old client; so that it will opportunistically start an OTR conversation +whenever it detects the correspondent supports it; or so that it refuses +to send non-encrypted messages to Bob, ever.

+

The policies that can be set (on a global or per-correspondent basis) +are any combination of the following boolean flags:

+
+
ALLOW_V1
+
Allow version 1 of the OTR protocol to be used (in general this +document will not address OTR protocol version 1; see previous +protocol documents for these details).
+
ALLOW_V2
+
Allow version 2 of the OTR protocol to be used.
+
ALLOW_V3
+
Allow version 3 of the OTR protocol to be used.
+
REQUIRE_ENCRYPTION
+
Refuse to send unencrypted messages.
+
SEND_WHITESPACE_TAG
+
Advertise your support of OTR using the whitespace tag.
+
WHITESPACE_START_AKE
+
Start the OTR AKE when you receive a whitespace tag.
+
ERROR_START_AKE
+
Start the OTR AKE when you receive an OTR Error Message.
+
+

Note that it is possible for UIs simply to offer the old +"combinations" of options, and not ask about each one separately.

+

State transitions

+

There are twelve actions an OTR client must handle:

+
    +
  • Received messages: +
      +
    • Plaintext without the whitespace tag
    • +
    • Plaintext with the whitespace tag
    • +
    • Query Message
    • +
    • Error Message
    • +
    • D-H Commit Message
    • +
    • D-H Key Message
    • +
    • Reveal Signature Message
    • +
    • Signature Message
    • +
    • Data Message
    • +
  • +
  • User actions: +
      +
    • User requests to start an OTR conversation
    • +
    • User requests to end an OTR conversation
    • +
    • User types a message to be sent
    • +
  • +
+

The following sections will outline what actions to take in each +case. They all assume that at least one of ALLOW_V1, ALLOW_V2 or +ALLOW_V3 is set; if not, then OTR is completely disabled, and no +special handling of messages should be done at all. For version 1 +messages, please refer to previous OTR protocol documents. For version +3 messages, someone receiving a message with a recipient instance tag +specified that does not equal their own should discard the message +and optionally warn the user. The exception here is the D-H Commit +Message where the recipient instance tag may be 0, indicating that no +particular instance is specified.

+

Receiving plaintext without the whitespace tag

+
+
If msgstate is MSGSTATE_PLAINTEXT:
+
Simply display the message to the user. If REQUIRE_ENCRYPTION is +set, warn him that the message was received unencrypted.
+
If msgstate is MSGSTATE_ENCRYPTED or MSGSTATE_FINISHED:
+
Display the message to the user, but warn him that the message was +received unencrypted.
+
+

Receiving plaintext with the whitespace tag

+
+
If msgstate is MSGSTATE_PLAINTEXT:
+
Remove the whitespace tag and display the message to the user. If +REQUIRE_ENCRYPTION is set, warn him that the message was received +unencrypted.
+
If msgstate is MSGSTATE_ENCRYPTED or MSGSTATE_FINISHED:
+
Remove the whitespace tag and display the message to the user, but +warn him that the message was received unencrypted.
+
+

In any event, if WHITESPACE_START_AKE is set:

+
+
If the tag offers OTR version 3 and ALLOW_V3 is set:
+
Send a version 3 D-H Commit Message, and transition authstate to +AUTHSTATE_AWAITING_DHKEY.
+
Otherwise, if the tag offers OTR version 2 and ALLOW_V2 is set:
+
Send a version 2 D-H Commit Message, and transition authstate to +AUTHSTATE_AWAITING_DHKEY.
+
+

Receiving a Query Message

+
+
If the query message offers OTR version 3 and ALLOW_V3 is set:
+
Send a version 3 D-H Commit Message, and transition authstate to +AUTHSTATE_AWAITING_DHKEY.
+
Otherwise, if the message offers OTR version 2 and ALLOW_V2 is set:
+
Send a version 2 D-H Commit Message, and transition authstate to +AUTHSTATE_AWAITING_DHKEY.
+
+

Receiving an Error Message

+

Display the message to the user. If ERROR_START_AKE is set, reply +with a Query Message.

+

User requests to start an OTR conversation

+

Send an OTR Query Message to the correspondent.

+

Receiving a D-H Commit Message

+

If the message is version 2 and ALLOW_V2 is not set, ignore this message. +Similarly if the message is version 3 and ALLOW_V3 is not set, ignore the +message. Otherwise:

+
+
If authstate is AUTHSTATE_NONE:
+
Reply with a D-H Key Message, and transition authstate to +AUTHSTATE_AWAITING_REVEALSIG.
+
If authstate is AUTHSTATE_AWAITING_DHKEY:
+
This is the trickiest transition in the whole protocol. It +indicates that you have already sent a D-H Commit message to your +correspondent, but that he either didn't receive it, or just didn't +receive it yet, and has sent you one as well. The symmetry +will be broken by comparing the hashed gx you sent in your +D-H Commit Message with the one you received, considered as 32-byte +unsigned big-endian values. +
+
If yours is the higher hash value:
+
Ignore the incoming D-H Commit message, but resend your D-H +Commit message.
+
Otherwise:
+
Forget your old gx value that you sent (encrypted) +earlier, and pretend you're in AUTHSTATE_NONE; i.e. reply with a D-H Key +Message, and transition authstate to AUTHSTATE_AWAITING_REVEALSIG.
+
+
If authstate is AUTHSTATE_AWAITING_REVEALSIG:
+
Retransmit your D-H Key Message (the same +one as you sent when you entered AUTHSTATE_AWAITING_REVEALSIG). Forget +the old D-H Commit message, and use this new one instead. There +are a number of reasons this might happen, including: +
    +
  • Your correspondent simply started a new AKE.
  • +
  • Your correspondent resent his D-H Commit message, as specified +above.
  • +
  • On some networks, like AIM, if your correspondent is logged in +multiple times, each of his clients will send a D-H Commit Message in +response to a Query Message; resending the same D-H Key Message in +response to each of those messages will prevent compounded confusion, +since each of his clients will see each of the D-H Key Messages you +send. [And the problem gets even worse if you are each logged +in multiple times.]
  • +
+
If authstate is AUTHSTATE_AWAITING_SIG or AUTHSTATE_V1_SETUP:
+
Reply with a new D-H Key message, and transition authstate to +AUTHSTATE_AWAITING_REVEALSIG.
+
+

Receiving a D-H Key Message

+

If the message is version 2 and ALLOW_V2 is not set, ignore this +message. Similarly if the message is version 3 and ALLOW_V3 is not +set, ignore this message. Otherwise:

+
+
If authstate is AUTHSTATE_AWAITING_DHKEY:
+
Reply with a Reveal Signature Message and transition authstate to +AUTHSTATE_AWAITING_SIG.
+
If authstate is AUTHSTATE_AWAITING_SIG:
+
+
+
If this D-H Key message is the same the one you received earlier +(when you entered AUTHSTATE_AWAITING_SIG):
+
Retransmit your Reveal Signature Message.
+
Otherwise:
+
Ignore the message.
+
+
If authstate is AUTHSTATE_NONE, AUTHSTATE_AWAITING_REVEALSIG, or +AUTHSTATE_V1_SETUP:
+
Ignore the message.
+
+

Receiving a Reveal Signature Message

+

If the message is version 2 and ALLOW_V2 is not set, ignore this message. +Similarly if the message is version 3 and ALLOW_V3 is not set, ignore the +message. Otherwise:

+
+
If authstate is AUTHSTATE_AWAITING_REVEALSIG:
+
Use the received value of r to decrypt the value of gx +received in the D-H Commit Message, and verify the hash therein. +Decrypt the encrypted signature, and verify the signature and the MACs. +If everything checks out: +
    +
  • Reply with a Signature Message.
  • +
  • Transition authstate to AUTHSTATE_NONE.
  • +
  • Transition msgstate to MSGSTATE_ENCRYPTED.
  • +
  • If there is a recent stored message, encrypt it and send it as a +Data Message.
  • +
+Otherwise, ignore the message.
+
If authstate is AUTHSTATE_NONE, AUTHSTATE_AWAITING_DHKEY, +AUTHSTATE_AWAITING_SIG, or AUTHSTATE_V1_SETUP:
+
Ignore the message.
+
+

Receiving a Signature Message

+

If the message is version 2 and ALLOW_V2 is not set, ignore this message. +Similarly if the message is version 3 and ALLOW_V3 is not set, ignore the +message. Otherwise:

+
+
If authstate is AUTHSTATE_AWAITING_SIG:
+
Decrypt the encrypted signature, and verify the signature and the MACs. +If everything checks out: +
    +
  • Transition authstate to AUTHSTATE_NONE.
  • +
  • Transition msgstate to MSGSTATE_ENCRYPTED.
  • +
  • If there is a recent stored message, encrypt it and send it as a +Data Message.
  • +
+Otherwise, ignore the message.
+
If authstate is AUTHSTATE_NONE, AUTHSTATE_AWAITING_DHKEY, +or AUTHSTATE_AWAITING_REVEALSIG:
+
Ignore the message.
+
+

User types a message to be sent

+
+
If msgstate is MSGSTATE_PLAINTEXT:
+
If REQUIRE_ENCRYPTION is set:
+
Store the plaintext message for possible retransmission, and send a +Query Message.
+
Otherwise:
+
If SEND_WHITESPACE_TAG is set, and you have not received a plaintext +message from this correspondent since last entering MSGSTATE_PLAINTEXT, +attach the whitespace tag to the message. Send the (possibly modified) +message as plaintext.
+
If msgstate is MSGSTATE_ENCRYPTED:
+
Encrypt the message, and send it as a Data Message. Store the +plaintext message for possible retransmission.
+
If msgstate is MSGSTATE_FINISHED:
+
Inform the user that the message cannot be sent at this time. Store +the plaintext message for possible retransmission.
+
+

Receiving a Data Message

+
+
If msgstate is MSGSTATE_ENCRYPTED:
+
Verify the information (MAC, keyids, ctr value, etc.) in the +message. +
+
If the verification succeeds:
+
+
    +
  • Decrypt the message and display the human-readable part (if +non-empty) to the user.
  • +
  • Update the D-H encryption keys, if necessary.
  • +
  • If you have not sent a message to this correspondent in some +(configurable) time, send a "heartbeat" message, consisting of a Data +Message encoding an empty plaintext. The heartbeat message should have +the IGNORE_UNREADABLE flag set.
  • +
  • If the received message contains a TLV type 1, forget all encryption +keys for this correspondent, and transition msgstate to +MSGSTATE_FINISHED.
  • +
+
+
Otherwise, inform the user that an unreadable encrypted message was +received, and reply with an Error Message.
+
+
If msgstate is MSGSTATE_PLAINTEXT or MSGSTATE_FINISHED:
+
Inform the user that an unreadable encrypted message was received, +and reply with an Error Message.
+
+

User requests to end an OTR conversation

+
+
If msgstate is MSGSTATE_PLAINTEXT:
+
Do nothing.
+
If msgstate is MSGSTATE_ENCRYPTED:
+
Send a Data Message, encoding a message with an empty human-readable +part, and TLV type 1. Transition msgstate to MSGSTATE_PLAINTEXT.
+
If msgstate is MSGSTATE_FINISHED:
+
Transition msgstate to MSGSTATE_PLAINTEXT.
+
+ diff --git a/comm/third_party/libotr/README b/comm/third_party/libotr/README new file mode 100644 index 0000000000..aa34e08e4f --- /dev/null +++ b/comm/third_party/libotr/README @@ -0,0 +1,382 @@ + Off-the-Record Messaging Library and Toolkit + v4.1.1, 9 Mar 2016 + +This is a library and toolkit which implements Off-the-Record (OTR) Messaging. + +OTR allows you to have private conversations over IM by providing: + - Encryption + - No one else can read your instant messages. + - Authentication + - You are assured the correspondent is who you think it is. + - Deniability + - The messages you send do _not_ have digital signatures that are + checkable by a third party. Anyone can forge messages after a + conversation to make them look like they came from you. However, + _during_ a conversation, your correspondent is assured the messages + he sees are authentic and unmodified. + - Perfect forward secrecy + - If you lose control of your private keys, no previous conversation + is compromised. + +For more information on Off-the-Record Messaging, see +https://otr.cypherpunks.ca/ + +LIBRARY USAGE + +1. Initialization + +Before you call any other libotr routine, you need to initialize the +library. The easiest way to do that is to include proto.h, and use the +macro: + + OTRL_INIT; + +somewhere early in your program. This should be called only once. + +You will also need an OtrlUserState. An OtrlUserState encapsulates the +list of known fingerprints and the list of private keys, so it should be +"one per user". Many OTR-enabled programs (such as IM clients) only have a +single user, so for them, you can just create a single one, and use it +throughout. Create an OtrlUserState as follows: + + userstate = otrl_userstate_create(); + +If you need to free an OtrlUserState: + + otrl_userstate_free(userstate); + +To read stored private keys: + + otrl_privkey_read(userstate, privkeyfilename); + +To read stored instance tags: + + otrl_instag_read(userstate, instagfilename); + +To read stored fingerprints: + + otrl_privkey_read_fingerprints(userstate, fingerprintfilename, + add_app_info, add_app_info_data); + +add_app_info is a function that will be called in the event that a new +ConnContext is created. It will be passed the add_app_info_data that +you supplied, as well as a pointer to the new ConnContext. You can use +this to add application-specific information to the ConnContext using +the "context->app" field, for example. If you don't need to do this, +you can pass NULL for the last two arguments of +otrl_privkey_read_fingerprints. + +2. Setting up the UI functions + +You need to let the library know how to do any UI it might require +(error messages, confirming new fingerprints, etc.). To this end, you +need to define a number of UI functions, and collect them in a +OtrlMessageAppOps struct. + +The first parameter of every UI function is "void *opdata". This is a +pointer you pass to the library, and it will pass back (opaquely) to the +UI functions when it calls them. You can use this to keep track of +state or any other information. + +You will need to include proto.h and message.h, and you can find a list +of the UI functions in message.h. + +3. Sending messages + +When you have a message you're about to send, you'll need to know four +things: you account name, the protocol id, the name of the recipient, +their instance tag, and the message. + +OTR protocol version 3 introduces the notion of "instance tags." A +client may be logged into the same account multiple times from different +locations. An instance tag is intended to differentiate these clients. +When sending a message, you may also specify a particular instance tag, +or use meta instance tags like OTRL_INSTAG_MOST_SECURE. + +The protocol id is just a unique string that is used to distinguish +the user foo on AIM from the user foo on MSN, etc. It can be anything +you like, so long as you're consistent, but if you've got nothing better +to use, you may as well use the ids from gaim. (Programs that use the +same protocol ids can share fingerprint and private key files.) The +gaim protocol id for AIM/ICQ is "prpl-oscar". + +Note that a name does not uniquely identify a user (as shown by the +"foo" example above). Even if you know both the name and the protocol, +it may not identify the user, since there may be multiple "foo" users on +IRC, on different servers. But the *three* items (your account name, +protocol id, their name) _must_ uniquely identify a user, so your +account name needs to include any network identifier, such as a server +name. Examples would be "foo@irc.freenode.net" or "foo@jabber.org". +Protocols such as AIM that do not have separate networks can just use +"foo", of course. + +To encrypt the message (if necessary; the library keeps track of which +users you have secure connections to, so you should *always* call this +next function), simply do this: + + gcry_error_t err; + char *newmessage = NULL; + + err = otrl_message_sending(userstate, &ui_ops, opdata, accountname, + protocolid, recipient_name, instag, message, tlvs, + &newmessage, fragPolicy, contextp, add_app_info, + add_app_info_data); + +add_app_info and add_app_info_data are as above, and may be NULL. + +tlvs should usually be NULL. If it's not, then it points to a chain of +OtrlTLVs which represent machine-readable data to send along with this +message. + +If contextp is not NULL, it will be set to the context that was used +for sending the message. + +If err is non-zero, then the library tried to encrypt the message, +but for some reason failed. DO NOT send the message in the clear in +that case. + +If newmessage gets set by the call to something non-NULL, then you +should replace your message with the contents of newmessage, and +send that instead. + +Once the message is encrypted, it may still be too large to send over +the network in a single piece. To check the maximum message size and +break your message into fragments if necessary, do this: + + gcry_error_t err; + char *extrafragment = NULL; + + err = otrl_message_fragment_and_send(&ui_ops, opdata, context, + message, fragmentPolicy, extrafragment); + +fragmentPolicy determines which, if any, fragments to return instead +of sending them immediately. For example, you may wish to send all +fragments except the last one, which is handled differently. Valid +policies may be found in proto.h. + +If err returns a nonzero value from fragment_and_send, the application +tried to break your message into fragments but failed for some reason. +You may still attempt to send the original message, but it might be +rejected if it too large. + +When you're done with newmessage, you must call + + otrl_message_free(newmessage) + +4. Receiving messages + +Receiving messages is similarly straightforward. Again, you need to +know four things: your account name, the protocol id, the sender's name, +and the message. + + int ignore_message; + char *newmessage = NULL; + + ignore_message = otrl_message_receiving(userstate, &ui_ops, opdata, + accountname, protocolid, sender_name, message, &newmessage, + &tlvs, contextp, add_app_info, add_app_info_data); + +add_app_info and add_app_info_data are as above, and may be NULL. + +If contextp is not NULL, it will be set to the context that was used +for receiving the message. + +If otrl_message_receiving returns 1, then the message you received was +an internal protocol message, and no message should be delivered to the +user. + +If it returns 0, then check if newmessage was set to non-NULL. If so, +replace the received message with the contents of newmessage, and +deliver that to the user instead. You must call +otrl_message_free(newmessage) when you're done with it. + +If otrl_message_receiving returns 0 and newmessage is NULL, then this +was an ordinary, non-OTR message, which should just be delivered to the +user without modification. + +If tlvs is set to non-NULL, then there is machine-readable data that was +sent along with this message. Call otrl_tlv_free(tlvs) when you're done +dealing with it (or ignoring it). + +5. Socialist Millionaires' Protocol + +The Socialist Millionaires' Protocol (SMP) is a way to detect +eavesdropping and man-in-the-middle attacks without requiring users to +work with fingerprints. This feature was added to OTR starting in +version 3.1.0. To learn how to modify your application to use SMP, read +the UPGRADING file. + +TOOLKIT + +Along with the library, this package comes with the OTR Messaging +Toolkit. This toolkit is useful for analyzing and/or forging OTR +messages. Why do we offer this? Primarily, to make absolutely sure +that transcripts of OTR conversations are really easy to forge after the +fact. [Note that *during* an OTR conversation, messages can't be forged +without real-time access to the secret keys on the participants' +computers, and in that case, all security has already been lost.] +Easily forgeable transcripts help us provide the "Deniability" property: +if someone claims you said something over OTR, they'll have no proof, as +anyone at all can modify a transcript to make it say whatever they like, +and still have all the verification come out correctly. + +Here are the six programs in the toolkit: + + - otr_parse + - Parse OTR messages given on stdin, showing the values of all the + fields in OTR protocol messages. + + - otr_sesskeys our_privkey their_pubkey + - Shows our public key, the session id, two AES and two MAC keys + derived from the given Diffie-Hellman keys (one private, one public). + + - otr_mackey aes_enc_key + - Shows the MAC key derived from the given AES key. + + - otr_readforge aes_enc_key [newmsg] + - Decrypts an OTR Data message using the given AES key, and displays + the message, if the key was correct. + - If newmsg is given, replace the message with that one, encrypt + and MAC it properly, and output the resulting OTR Data Message. + This works even if the given key was not correct for the original + message, so as to enable complete forgeries. + + - otr_modify mackey old_text new_text offset + - Even if you can't read the data because you don't know either + the AES key or the Diffie-Hellman private key, but you can make a + good guess that the substring "old_text" appears at the given + offset in the message, replace the old_text with the new_text + (which must be of the same length), recalculate the MAC with the + given mackey, and output the resulting Data message. + - Note that, even if you don't know any text in an existing message, + you can still forge messages of your choice using the otr_readforge + command, above. + + - otr_remac mackey sender_instance receiver_instance flags keyid keyid + pubkey counter encdata revealed_mackeys + - Make a new OTR Data Message, with the given pieces (note that the + data part is already encrypted). MAC it with the given mackey. + +NOTES + +Please send your bug reports, comments, suggestions, patches, etc. to us +at the contact address below. + +In otrl_message_sending, specifying an instance tag allows you to send a +message to a particular session of a buddy who is logged in multiple times +with an otr-enabled client. The OTRL_INSTAG_RECENT_RECEIVED meta-instance +relies on the time that libotr processed the most recent message. Meta- +instance tags resolve to actual instance tags before a message is sent. An +instant messaging network may not agree on which session of the remote party is +the most recent, e.g., due to underlying network race conditions. If the +behaviour of an instant messaging network is to only deliver to the most recent, +and libotr and the network disagree on which session is the most recent, the +other party will not process the given message. That is, the instant messaging +network will deliver the message to the session whose actual instance tag does +not match the addressed instance tag. Also note that OTRL_INSTAG_BEST also +prefers more recent instance tags in the case of multiple instances with the +same "best" status (most secure). In this case, the most recent has a +resolution of one second. + +If otrl_message_sending is called with an original_msg that contains the text +"?OTR?", this is a signal to initiate or refresh an OTR session. There is +currently no way to indicate if this text was actually typed in by a user and +part of a conversation (e.g., someone communicating instructions on how to +refresh OTR). In the future, we may allow a policy to specify whether "?OTR?" +is a signal to start OTR, or just an ordinary message for encrypted and +unencrypted conversations. + +MAILING LISTS + +There are three mailing lists pertaining to Off-the-Record Messaging: + +otr-announce: + https://lists.cypherpunks.ca/mailman/listinfo/otr-announce/ + *** All users of OTR software should join this. *** It is used to + announce new versions of OTR software, and other important information. + +otr-users: + https://lists.cypherpunks.ca/mailman/listinfo/otr-users/ + Discussion of usage issues related to OTR Messaging software. + +otr-dev: + https://lists.cypherpunks.ca/mailman/listinfo/otr-dev/ + Discussion of OTR Messaging software development. + +LICENSE + +The Off-the-Record Messaging library (in the src directory) is +covered by the following (LGPL) license: + + Off-the-Record Messaging library + Copyright (C) 2004-2016 Ian Goldberg, David Goulet, Rob Smits, + Chris Alexander, Willy Lew, Lisa Du, + Nikita Borisov + + + This library is free software; you can redistribute it and/or + modify it under the terms of version 2.1 of the GNU Lesser General + Public License as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + There is a copy of the GNU Lesser General Public License in the + COPYING.LIB file packaged with this library; if you cannot find it, + write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA + +The library comes with a test suite (in the tests directory), which is +covered by the following (GPL) license: + + Copyright (C) 2014 Julien Voisin , + David Goulet + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2 only, as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +The Off-the-Record Messaging Toolkit (in the toolkit directory) is covered +by the following (GPL) license: + + Off-the-Record Messaging Toolkit + Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + Chris Alexander, Nikita Borisov + + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + There is a copy of the GNU General Public License in the COPYING file + packaged with this toolkit; if you cannot find it, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + +CONTACT + +To report problems, comments, suggestions, patches, etc., you can email +the authors: + +Ian Goldberg, David Goulet, Rob Smits, Chris Alexander, Lisa Du, +Nikita Borisov + + +For more information on Off-the-Record Messaging, visit +https://otr.cypherpunks.ca/ diff --git a/comm/third_party/libotr/UPGRADING b/comm/third_party/libotr/UPGRADING new file mode 100644 index 0000000000..f7445c3472 --- /dev/null +++ b/comm/third_party/libotr/UPGRADING @@ -0,0 +1,515 @@ +Table of Contents + +1. Introduction +2. Major Additions +2.1. Instance Tags +2.2. Asynchronous Private Key Generation +2.3. Extra Symmetric Key +2.4. Convert Operations +2.5. SMP, Error, and Message Event Callbacks +2.6. Fragmentation Changes +3. Required Changes +3.1. OtrlMessageAppOps Callbacks +3.1.1. Removed Operations +3.1.2. Added Operations +3.2. Instance Tags +3.3. Fragmentation Changes +3.4. Asynchronous Private Key Generation +3.5. Library Initialization + +1. Introduction + +This file contains information about the changes between the 3.2.0 and +the 4.0.0 APIs for libotr. Note that applications compiled against +previous versions of OTR will not work with libotr 4.0.0. + +2. Major Additions + +This section describes the new features in OTR 4.0.0 along with a short +history or motivation for each. + +2.1. Instance Tags + +Clients generate instance tags that are intended to be persistent. If +the same client is logged into the same account from multiple locations, +the intention is that he or she will have different instance tags at +each location. OTR wire messages (fragmented and unfragmented) include +the source and destination instance tags. If a client receives a message +that lists a destination instance tag different from his own, the client +will discard it (and issue a callback notifying the application of the +event). + +This avoids an issue on IM networks that always relay all messages to +all sessions of a client who is logged in multiple times. In this +situation, OTR clients can attempt to establish an OTR session +indefinitely if there are interleaving messages from each of the +sessions. + +2.2. Asynchronous Private Key Generation + +Key generation can happen in a separate thread without blocking an +application. + +2.3. Extra Symmetric Key + +An extra symmetric key is kept synchronized during a conversation with a +buddy. Either side can send a signal that they wish to use this key for +some external purpose (e.g. things like a file transfer, in some other +channel of communication). + +2.4. Convert Operations + +There is now a callback that is made immediately before a message is +encrypted and immediately after a message is decrypted. This callback +can tweak the plaintext message as needed. For example, this could allow +an application to convert formatting on a message if this would normally +be done on the plaintext by some other entity while the message is in +transit. + +2.5. SMP, Error, and Message Event Callbacks + +To avoid hard-coded English phrases in libotr, operations which used to +pass back strings are replaced by operations that pass back event codes. + +2.6. Fragmentation Changes + +In libotr version 3.2.0, you would need to call otrl_message_sending() +to create an encrypted message, and then call fragment_and_send() to get +libotr to fragment and inject that message. In libotr 4.0.0, the +functionality of fragment_and_send() has been integrated into +otrl_message_sending(). + +3. Required Changes + +3.1. OtrlMessageAppOps Callbacks + +3.1.1. Removed Operations + +/* Display a notification message for a particular accountname / + * protocol / username conversation. */ +void (*notify)(void *opdata, OtrlNotifyLevel level, + const char *accountname, const char *protocol, + const char *username, const char *title, + const char *primary, const char *secondary); + +The notify() operation was removed since it was used to pass in +hardcoded English strings. This has been replaced by error and message +event callbacks, described below, which pass event codes rather than +hardcoded strings. + + +/* Display an OTR control message for a particular accountname / + * protocol / username conversation. Return 0 if you are able to + * successfully display it. If you return non-0 (or if this + * function is NULL), the control message will be displayed inline, + * as a received message, or else by using the above notify() + * callback. */ +int (*display_otr_message)(void *opdata, const char *accountname, + const char *protocol, const char *username, const char *msg); + +The display_otr_message() operation was removed for the same reasons as +above for the notify() operation. + + +/* Return a newly allocated string containing a human-friendly name + * for the given protocol id */ +const char *(*protocol_name)(void *opdata, const char *protocol); + +/* Deallocate a string allocated by protocol_name */ +void (*protocol_name_free)(void *opdata, const char *protocol_name); + +The above operations are no longer required, as they were used when +preparing messages shown to users. + + +/* Log a message. The passed message will end in "\n". */ +void (*log_message)(void *opdata, const char *message); + +The log_message() operation was also replaced by message event +callbacks. + +3.1.2. Added Operations + +/* We received a request from the buddy to use the current "extra" + * symmetric key. The key will be passed in symkey, of length + * OTRL_EXTRAKEY_BYTES. The requested use, as well as use-specific + * data will be passed so that the applications can communicate other + * information (some id for the data transfer, for example). */ +void (*received_symkey)(void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, + size_t usedatalen, const unsigned char *symkey); + +This is called when a remote buddy has specified a use for the current +symmetric key. If your application does not use the extra symmetric key +it does not need to provide an implementation for this operation. + + +/* Return a string according to the error event. This string will then + * be concatenated to an OTR header to produce an OTR protocol error + * message. The following are the possible error events: + * - OTRL_ERRCODE_ENCRYPTION_ERROR + * occured while encrypting a message + * - OTRL_ERRCODE_MSG_NOT_IN_PRIVATE + * sent encrypted message to somebody who is not in + * a mutual OTR session + * - OTRL_ERRCODE_MSG_UNREADABLE + * sent an unreadable encrypted message + * - OTRL_ERRCODE_MSG_MALFORMED + * message sent is malformed */ +const char *(*otr_error_message)(void *opdata, ConnContext *context, + OtrlErrorCode err_code); + +/* Deallocate a string returned by otr_error_message */ +void (*otr_error_message_free)(void *opdata, const char *err_msg); + +These methods are for producing human-readable error message that will +be sent to the remote buddy when one of these error conditions occurs. +They will be appended to the string "?OTR Error: ". Implementing this +operation is not required, but depending on your application it may be a +good idea. + + +/* Return a string that will be prefixed to any resent message. If this + * function is not provided by the application then the default prefix, + * "[resent]", will be used. + * */ +const char *(*resent_msg_prefix)(void *opdata, ConnContext *context); + +/* Deallocate a string returned by resent_msg_prefix */ +void (*resent_msg_prefix_free)(void *opdata, const char *prefix); + +These operations give the option of chosing an alternative to the +English string "[resent]", when a message is resent. + + +/* Update the authentication UI with respect to SMP events + * These are the possible events: + * - OTRL_SMPEVENT_ASK_FOR_SECRET + * prompt the user to enter a shared secret. The sender application + * should call otrl_message_initiate_smp, passing NULL as the question. + * When the receiver application resumes the SM protocol by calling + * otrl_message_respond_smp with the secret answer. + * - OTRL_SMPEVENT_ASK_FOR_ANSWER + * (same as OTRL_SMPEVENT_ASK_FOR_SECRET but sender calls + * otrl_message_initiate_smp_q instead) + * - OTRL_SMPEVENT_CHEATED + * abort the current auth and update the auth progress dialog + * with progress_percent. otrl_message_abort_smp should be called to + * stop the SM protocol. + * - OTRL_SMPEVENT_INPROGRESS and + * OTRL_SMPEVENT_SUCCESS and + * OTRL_SMPEVENT_FAILURE and + * OTRL_SMPEVENT_ABORT + * update the auth progress dialog with progress_percent + * - OTRL_SMPEVENT_ERROR + * (same as OTRL_SMPEVENT_CHEATED) + * */ +void (*handle_smp_event)(void *opdata, OtrlSMPEvent smp_event, + ConnContext *context, unsigned short progress_percent, + char *question); + +These SMP events are initiated by otrl_message_receiving() when it has +received an SMP TLV from a remote buddy. If you application is +implementing support for SMP authentication it should handle these +events appropriately. + +Previously applications had to manually check, upon receiving messages, +whether the message contained any SMP TLVs that are relevant to the +current SMP state. + +/* Handle and send the appropriate message(s) to the sender/recipient + * depending on the message events. All the events only require an opdata, + * the event, and the context. The message and err will be NULL except for + * some events (see below). The possible events are: + * - OTRL_MSGEVENT_ENCRYPTION_REQUIRED + * Our policy requires encryption but we are trying to send + * an unencrypted message out. + * - OTRL_MSGEVENT_ENCRYPTION_ERROR + * An error occured while encrypting a message and the message + * was not sent. + * - OTRL_MSGEVENT_CONNECTION_ENDED + * Message has not been sent because our buddy has ended the + * private conversation. We should either close the connection, + * or refresh it. + * - OTRL_MSGEVENT_SETUP_ERROR + * A private conversation could not be set up. A gcry_error_t + * will be passed. + * - OTRL_MSGEVENT_MSG_REFLECTED + * Received our own OTR messages. + * - OTRL_MSGEVENT_MSG_RESENT + * The previous message was resent. + * - OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE + * Received an encrypted message but cannot read + * it because no private connection is established yet. + * - OTRL_MSGEVENT_RCVDMSG_UNREADABLE + * Cannot read the received message. + * - OTRL_MSGEVENT_RCVDMSG_MALFORMED + * The message received contains malformed data. + * - OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD + * Received a heartbeat. + * - OTRL_MSGEVENT_LOG_HEARTBEAT_SENT + * Sent a heartbeat. + * - OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR + * Received a general OTR error. The argument 'message' will + * also be passed and it will contain the OTR error message. + * - OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED + * Received an unencrypted message. The argument 'smessage' will + * also be passed and it will contain the plaintext message. + * - OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED + * Cannot recognize the type of OTR message received. + * - OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE + * Received and discarded a message intended for another instance. */ +void (*handle_msg_event)(void *opdata, OtrlMessageEvent msg_event, + ConnContext *context, const char *message, + gcry_error_t err); + +This operation is called when some type of exceptional event has occured +that your application may want to be aware of. Your application may want +to write an event to a log file, display a message to the user, or +ignore the event. While it is not required to implement this operation, +it is probably a good idea. + + +/* Create a instance tag for the given accountname/protocol if + * desired. */ +void (*create_instag)(void *opdata, const char *accountname, + const char *protocol); + +This is called when the library notices this account name and protocol +pair does not have an instance tag. Similar to create_privkey(), your +application may simply open a file handle and call: +gcry_error_t otrl_instag_generate_FILEp(OtrlUserState us, FILE *instf, + const char *accountname, const char *protocol) + +If you don't provide an implementation for this operation, a new +non-persistent instance tag will be randomly generated. One benefit to +having a persisted instance tag is that if your application closes and +re-opens during a private conversation, further messages you receive +from this buddy will correctly raise the +OTRL_MSGEVENT_RCVDMSG_UNREADABLE event instead of raising +OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE because destination instance +tag is now different from your own. + + +/* Called immediately before a data message is encrypted, and after a data + * message is decrypted. The OtrlConvertType parameter has the value + * OTRL_CONVERT_SENDING or OTRL_CONVERT_RECEIVING to differentiate these + * cases. */ +void (*convert_msg)(void *opdata, ConnContext *context, + OtrlConvertType convert_type, char ** dest, const char *src); + +/* Deallocate a string returned by convert_msg. */ +void (*convert_free)(void *opdata, ConnContext *context, char *dest); + +The convert_msg() operation is called immediately before a message is +encrypted and immediately after a message is decrypted. This callback +can tweak the plaintext message as needed. One use case would be for an +application to tweak formatting on the plaintext if, for example, this +is something that would normally be done on the plaintext by some other +entity while the message is in transit. + +/* When timer_control is called, turn off any existing periodic + * timer. + * + * Additionally, if interval > 0, set a new periodic timer + * to go off every interval seconds. When that timer fires, you + * must call otrl_message_poll(userstate, uiops, uiopdata); from the + * main libotr thread. + * + * The timing does not have to be exact; this timer is used to + * provide forward secrecy by cleaning up stale private state that + * may otherwise stick around in memory. Note that the + * timer_control callback may be invoked from otrl_message_poll + * itself, possibly to indicate that interval == 0 (that is, that + * there's no more periodic work to be done at this time). + * + * If you set this callback to NULL, then you must ensure that your + * application calls otrl_message_poll(userstate, uiops, uiopdata); + * from the main libotr thread every definterval seconds (where + * definterval can be obtained by calling + * definterval = otrl_message_poll_get_default_interval(userstate); + * right after creating the userstate). The advantage of + * implementing the timer_control callback is that the timer can be + * turned on by libotr only when it's needed. + * + * It is not a problem (except for a minor performance hit) to call + * otrl_message_poll more often than requested, whether + * timer_control is implemented or not. + * + * If you fail to implement the timer_control callback, and also + * fail to periodically call otrl_message_poll, then you open your + * users to a possible forward secrecy violation: an attacker that + * compromises the user's computer may be able to decrypt a handful + * of long-past messages (the first messages of an OTR + * conversation). + */ +void (*timer_control)(void *opdata, unsigned int interval); + +In order to prevent a forward secrecy violation, applications using +libotr now need to be able to call otrl_message_poll on occasion. The +simplest thing to do is just to set up a local timer that calls that +function every definterval = +otrl_message_poll_get_default_interval(userstate) seconds. To avoid +unnecessary overhead, however, the timer_control callback is available. +If you set timer_control to non-NULL, it will be called with +instructions to turn on or off the periodic timer, and to what interval. + +You must also be sure to turn off the timer before freeing your +userstate with otrl_userstate_free. + +3.2. Instance Tags + +If your application allows the same user to be logged in multiple times +from different locations, it should probably be aware of instance tags. +A user can maintain multiple concurrent OTR conversations with a buddy +who is logged in multiple times. Only one of the buddy's sessions can be +a client who is running OTR protocol version 2. When a user has a +conversation with a buddy who is running OTR protocol version 2, the +conversation is associated with a ConnContext that lists +"their_instance" as OTRL_INSTAG_MASTER (which has a value of 0). Each +version 3 conversation with the same buddy will have its own +ConnContext, which you can differentiate by the value in the +"their_instance" field. + +In the linked list of ConnContexts, the master context for a buddy is +always listed immediately before its children. Fingerprints are only +stored with the master context. Given a ConnContext associated to a +conversation with a buddy, you can easily iterate over all the contexts +for that buddy by doing the following: + +void example_something_happened(ConnContext * context) { + ConnContext * context_iter = context->m_context; + + while (context_iter && context_iter->m_context == context->m_context) { + /* Something you wish to affect all contexts of a particular buddy */ + context_iter = context_iter->next; + } + +If a user has multiple OTR sessions with the same buddy, your +application will likely want to provide some way for the user to select +which instance to send outgoing messages to. You can detect when a user +has multiple OTR sessions with the same buddy by iterating over the +ConnContexts of a buddy when a conversation has gone secure and checking +whether more than one is not in plaintext state. You specify which +instance outgoing messages are directed to in otrl_message_sending: + +gcry_error_t otrl_message_sending(OtrlUserState us, + const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *recipient, otrl_instag_t instag, const char *original_msg, + OtrlTLV *tlvs, char **messagep, OtrlFragmentPolicy fragPolicy, + ConnContext **contextp, + void (*add_appdata)(void *data, ConnContext *context), + void *data); + +Instead of an actual instance tag, you can specify a meta instance tag +(e.g., if the user has not made an explicit selection). Here are the +list of meta instance tags, as defined in instag.h: + +#define OTRL_INSTAG_BEST 1 /* Most secure, based on: conv status, + * then fingerprint status, then most recent. */ +#define OTRL_INSTAG_RECENT 2 /* Most recent of the two meta instances below */ +#define OTRL_INSTAG_RECENT_RECEIVED 3 +#define OTRL_INSTAG_RECENT_SENT 4 + +OTRL_INSTAG_BEST choses the instance that has the best conv status, then +fingerprint status (in the event of a tie), then most recent (similarly +in the event of a tie). When calculating how recent an instance has been +active, OTRL_INSTAG_BEST is limited by a one second resolution. +OTRL_INSTAG_RECENT* does not have this limitation, but due to inherent +uncertainty in some networks, libotr's notion of the most recent may not +always agree with the remote network. It is important to understand +this limitation due to the issue noted in the next paragraph. + +Note that instances do add some uncertainty when dealing with networks +that only deliver messages to the most recently active session for a +buddy who is logged in multiple times. If you have a particular instance +selected, and the IM network is simply not going to deliver to that +particular instance, there isn't too much libotr can do. In this case, +you may want your application to warn when a user has selected an +instance that is not the most recent. + +To explicitly specify the destination instance of a protocol version 2 +conversation with a particular buddy, the instag value is +OTRL_INSTAG_MASTER. + +To look up a ConnContext associated with a particular instance (or meta- +instance), specify the instance in otrl_context_find(): + +ConnContext * otrl_context_find(OtrlUserState us, const char *user, + const char *accountname, const char *protocol, + otrl_instag_t their_instance, int add_if_missing, int *addedp, + void (*add_app_data)(void *data, ConnContext *context), void *data) + +If your application persists instance tags, when it starts up, it should +call one the following functions to read the persisted instance tags: + +gcry_error_t otrl_instag_read(OtrlUserState us, const char *filename); +gcry_error_t otrl_instag_read_FILEp(OtrlUserState us, FILE *instf); + +It would make sense to do this immediately after your application has +read stored privkeys and fingerprints. + +3.3. Fragmentation Changes + +In libotr version 3.2.0, you would need to call otrl_message_sending() +to create an encrypted message, and then call fragment_and_send() to +get libotr to fragment and inject that message. In libotr 4.0.0, the +functionality of fragment_and_send() has been integrated into +otrl_message_sending(). Simply specify an OtrlFragmentPolicy to +otrl_message_sending(). The fragmentation policies are the same as +before, and an addition policy "OTRL_FRAGMENT_SEND_SKIP" has been added +for cases when fragmentation is not desired. + +3.4. Asynchronous Private Key Generation + +An application that wants to begin asynchronous key generation calls the +following method: + +/* Begin a private key generation that will potentially take place in + * a background thread. This routine must be called from the main + * thread. It will set *newkeyp, which you can pass to + * otrl_privkey_generate_calculate in a background thread. If it + * returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for + * this accountname/protocol is already in progress, and *newkeyp will + * be set to NULL. */ +gcry_error_t otrl_privkey_generate_start(OtrlUserState us, + const char *accountname, const char *protocol, void **newkeyp) + +A background thread can call the following method with the structure +that was passed into "newkeyp" above: + +/* Do the private key generation calculation. You may call this from a + * background thread. When it completes, call + * otrl_privkey_generate_finish from the _main_ thread. */ +gcry_error_t otrl_privkey_generate_calculate(void *newkey) + + +Upon completion the application would call: + +/* Call this from the main thread only. It will write the newly created + * private key into the given file and store it in the OtrlUserState. */ +gcry_error_t otrl_privkey_generate_finish(OtrlUserState us, + void *newkey, const char *filename) + +If the privkey generation was cancelled, the application should call: + +/* Call this from the main thread only, in the event that the background + * thread generating the key is cancelled. The newkey is deallocated, + * and must not be used further. */ +void otrl_privkey_generate_cancelled(OtrlUserState us, void *newkey) + + +3.5. Library Initialization + +If you currently initialize libotr with the recommended OTRL_INIT; +macro, you do not need to change anything. + +If you call otrl_init(ver_major, ver_minor, ver_sub) directly, then know +that this function no longer returns void. Previously, if the +application requested version numbers incompatible with those of the +library, the library would exit(1). Now, the otrl_init call will return +a non-zero error code. You must check the return value of otrl_init (a +gcry_error_t), and if it is non-zero, your application's expected +API/ABI does not match the installed libotr, and libotr cannot be used. + diff --git a/comm/third_party/libotr/aclocal.m4 b/comm/third_party/libotr/aclocal.m4 new file mode 100644 index 0000000000..c39029a0a1 --- /dev/null +++ b/comm/third_party/libotr/aclocal.m4 @@ -0,0 +1,1307 @@ +# generated automatically by aclocal 1.14.1 -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +dnl Autoconf macros for libgcrypt +dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc. +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This file is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS. +dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed +dnl with the API version to also check the API compatibility. Example: +dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed +dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using +dnl this features allows to prevent build against newer versions of libgcrypt +dnl with a changed API. +dnl +AC_DEFUN([AM_PATH_LIBGCRYPT], +[ AC_ARG_WITH(libgcrypt-prefix, + AC_HELP_STRING([--with-libgcrypt-prefix=PFX], + [prefix where LIBGCRYPT is installed (optional)]), + libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="") + if test x$libgcrypt_config_prefix != x ; then + if test x${LIBGCRYPT_CONFIG+set} != xset ; then + LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config + fi + fi + + AC_PATH_TOOL(LIBGCRYPT_CONFIG, libgcrypt-config, no) + tmp=ifelse([$1], ,1:1.2.0,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_libgcrypt_api=0 + min_libgcrypt_version="$tmp" + fi + + AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version) + ok=no + if test "$LIBGCRYPT_CONFIG" != "no" ; then + req_major=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` + major=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + micro=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -gt "$req_minor"; then + ok=yes + else + if test "$minor" -eq "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + AC_MSG_RESULT([yes ($libgcrypt_config_version)]) + else + AC_MSG_RESULT(no) + fi + if test $ok = yes; then + # If we have a recent libgcrypt, we should also check that the + # API is compatible + if test "$req_libgcrypt_api" -gt 0 ; then + tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + AC_MSG_CHECKING([LIBGCRYPT API version]) + if test "$req_libgcrypt_api" -eq "$tmp" ; then + AC_MSG_RESULT([okay]) + else + ok=no + AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp]) + fi + fi + fi + fi + if test $ok = yes; then + LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` + LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` + ifelse([$2], , :, [$2]) + if test x"$host" != x ; then + libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none` + if test x"$libgcrypt_config_host" != xnone ; then + if test x"$libgcrypt_config_host" != x"$host" ; then + AC_MSG_WARN([[ +*** +*** The config script $LIBGCRYPT_CONFIG was +*** built for $libgcrypt_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-libgcrypt-prefix +*** to specify a matching config script. +***]]) + fi + fi + fi + else + LIBGCRYPT_CFLAGS="" + LIBGCRYPT_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(LIBGCRYPT_CFLAGS) + AC_SUBST(LIBGCRYPT_LIBS) +]) + +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.14' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.14.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.14.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# -*- Autoconf -*- +# Obsolete and "removed" macros, that must however still report explicit +# error messages when used, to smooth transition. +# +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +AC_DEFUN([AM_CONFIG_HEADER], +[AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl +AC_CONFIG_HEADERS($@)]) + +AC_DEFUN([AM_PROG_CC_STDC], +[AC_PROG_CC +am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc +AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should simply use the 'AC][_PROG_CC' macro instead. +Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', +but upon 'ac_cv_prog_cc_stdc'.])]) + +AC_DEFUN([AM_C_PROTOTYPES], + [AC_FATAL([automatic de-ANSI-fication support has been removed])]) +AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([config/libtool.m4]) +m4_include([config/ltoptions.m4]) +m4_include([config/ltsugar.m4]) +m4_include([config/ltversion.m4]) +m4_include([config/lt~obsolete.m4]) diff --git a/comm/third_party/libotr/bootstrap b/comm/third_party/libotr/bootstrap new file mode 100755 index 0000000000..a2ed29ca5a --- /dev/null +++ b/comm/third_party/libotr/bootstrap @@ -0,0 +1,9 @@ +#!/bin/bash + +set -x + +if [ ! -e config ]; then + mkdir config +fi + +autoreconf -i diff --git a/comm/third_party/libotr/config.guess b/comm/third_party/libotr/config.guess new file mode 100755 index 0000000000..b79252d6b1 --- /dev/null +++ b/comm/third_party/libotr/config.guess @@ -0,0 +1,1558 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-06-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + or1k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/comm/third_party/libotr/config.h.in b/comm/third_party/libotr/config.h.in new file mode 100644 index 0000000000..423fcf8f0a --- /dev/null +++ b/comm/third_party/libotr/config.h.in @@ -0,0 +1,62 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION diff --git a/comm/third_party/libotr/config.sub b/comm/third_party/libotr/config.sub new file mode 100755 index 0000000000..9633db7046 --- /dev/null +++ b/comm/third_party/libotr/config.sub @@ -0,0 +1,1791 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-08-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 \ + | or1k | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or1k-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/comm/third_party/libotr/config/compile b/comm/third_party/libotr/config/compile new file mode 100755 index 0000000000..531136b068 --- /dev/null +++ b/comm/third_party/libotr/config/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libotr/config/config.guess b/comm/third_party/libotr/config/config.guess new file mode 100755 index 0000000000..d622a44e55 --- /dev/null +++ b/comm/third_party/libotr/config/config.guess @@ -0,0 +1,1530 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/comm/third_party/libotr/config/config.sub b/comm/third_party/libotr/config/config.sub new file mode 100755 index 0000000000..c894da4550 --- /dev/null +++ b/comm/third_party/libotr/config/config.sub @@ -0,0 +1,1773 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/comm/third_party/libotr/config/depcomp b/comm/third_party/libotr/config/depcomp new file mode 100755 index 0000000000..bd0ac08958 --- /dev/null +++ b/comm/third_party/libotr/config/depcomp @@ -0,0 +1,688 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2011-12-04.11; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, +# 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test "$stat" = 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/ \1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/ / + G + p +}' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libotr/config/install-sh b/comm/third_party/libotr/config/install-sh new file mode 100755 index 0000000000..6781b987bd --- /dev/null +++ b/comm/third_party/libotr/config/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libotr/config/libtool.m4 b/comm/third_party/libotr/config/libtool.m4 new file mode 100644 index 0000000000..828104cfde --- /dev/null +++ b/comm/third_party/libotr/config/libtool.m4 @@ -0,0 +1,8001 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/comm/third_party/libotr/config/ltmain.sh b/comm/third_party/libotr/config/ltmain.sh new file mode 100644 index 0000000000..c2852d8561 --- /dev/null +++ b/comm/third_party/libotr/config/ltmain.sh @@ -0,0 +1,9661 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.2 Debian-2.4.2-1ubuntu1" +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/comm/third_party/libotr/config/ltoptions.m4 b/comm/third_party/libotr/config/ltoptions.m4 new file mode 100644 index 0000000000..5d9acd8e23 --- /dev/null +++ b/comm/third_party/libotr/config/ltoptions.m4 @@ -0,0 +1,384 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/comm/third_party/libotr/config/ltsugar.m4 b/comm/third_party/libotr/config/ltsugar.m4 new file mode 100644 index 0000000000..9000a057d3 --- /dev/null +++ b/comm/third_party/libotr/config/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/comm/third_party/libotr/config/ltversion.m4 b/comm/third_party/libotr/config/ltversion.m4 new file mode 100644 index 0000000000..07a8602d48 --- /dev/null +++ b/comm/third_party/libotr/config/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/comm/third_party/libotr/config/lt~obsolete.m4 b/comm/third_party/libotr/config/lt~obsolete.m4 new file mode 100644 index 0000000000..c573da90c5 --- /dev/null +++ b/comm/third_party/libotr/config/lt~obsolete.m4 @@ -0,0 +1,98 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/comm/third_party/libotr/config/missing b/comm/third_party/libotr/config/missing new file mode 100755 index 0000000000..86a8fc31e3 --- /dev/null +++ b/comm/third_party/libotr/config/missing @@ -0,0 +1,331 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2012-01-06.13; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libotr/configure b/comm/third_party/libotr/configure new file mode 100755 index 0000000000..e5b064c4a8 --- /dev/null +++ b/comm/third_party/libotr/configure @@ -0,0 +1,17285 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for libotr 4.1.1. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and otr@cypherpunks.ca +$0: about your system, including any error possibly output +$0: before this message. Then install a modern shell, or +$0: manually run the script under such a shell if you do +$0: have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='libotr' +PACKAGE_TARNAME='libotr' +PACKAGE_VERSION='4.1.1' +PACKAGE_STRING='libotr 4.1.1' +PACKAGE_BUGREPORT='otr@cypherpunks.ca' +PACKAGE_URL='https://otr.cypherpunks.ca' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +BUILD_NT_SERVICES_FALSE +BUILD_NT_SERVICES_TRUE +BUILD_TESTS_FALSE +BUILD_TESTS_TRUE +LIBGCRYPT_LIBS +LIBGCRYPT_CFLAGS +LIBGCRYPT_CONFIG +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +LIBOTR_LIBTOOL_VERSION +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +with_sysroot +enable_libtool_lock +with_libgcrypt_prefix +enable_gcc_hardening +enable_linker_hardening +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libotr 4.1.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libotr] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libotr 4.1.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-gcc-hardening disable compiler security checks + --disable-linker-hardening + disable linker security fixups + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + --with-libgcrypt-prefix=PFX + prefix where LIBGCRYPT is installed (optional) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +libotr home page: . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +libotr configure 4.1.1 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libotr $as_me 4.1.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers config.h" + +ac_aux_dir= +for ac_dir in config "$srcdir"/config; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +am__api_version='1.14' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libotr' + VERSION='4.1.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi +LIBOTR_LIBTOOL_VERSION="6:1:1" + + +# Silent compilation so warnings can be spotted. +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.2' +macro_revision='1.3337' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + + +# Check whether --with-libgcrypt-prefix was given. +if test "${with_libgcrypt_prefix+set}" = set; then : + withval=$with_libgcrypt_prefix; libgcrypt_config_prefix="$withval" +else + libgcrypt_config_prefix="" +fi + + if test x$libgcrypt_config_prefix != x ; then + if test x${LIBGCRYPT_CONFIG+set} != xset ; then + LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config + fi + fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}libgcrypt-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}libgcrypt-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_LIBGCRYPT_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $LIBGCRYPT_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_LIBGCRYPT_CONFIG="$LIBGCRYPT_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +LIBGCRYPT_CONFIG=$ac_cv_path_LIBGCRYPT_CONFIG +if test -n "$LIBGCRYPT_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGCRYPT_CONFIG" >&5 +$as_echo "$LIBGCRYPT_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_LIBGCRYPT_CONFIG"; then + ac_pt_LIBGCRYPT_CONFIG=$LIBGCRYPT_CONFIG + # Extract the first word of "libgcrypt-config", so it can be a program name with args. +set dummy libgcrypt-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_LIBGCRYPT_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_LIBGCRYPT_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_LIBGCRYPT_CONFIG="$ac_pt_LIBGCRYPT_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_LIBGCRYPT_CONFIG=$ac_cv_path_ac_pt_LIBGCRYPT_CONFIG +if test -n "$ac_pt_LIBGCRYPT_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LIBGCRYPT_CONFIG" >&5 +$as_echo "$ac_pt_LIBGCRYPT_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_LIBGCRYPT_CONFIG" = x; then + LIBGCRYPT_CONFIG="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIBGCRYPT_CONFIG=$ac_pt_LIBGCRYPT_CONFIG + fi +else + LIBGCRYPT_CONFIG="$ac_cv_path_LIBGCRYPT_CONFIG" +fi + + tmp=1:1.2.0 + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_libgcrypt_api=0 + min_libgcrypt_version="$tmp" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGCRYPT - version >= $min_libgcrypt_version" >&5 +$as_echo_n "checking for LIBGCRYPT - version >= $min_libgcrypt_version... " >&6; } + ok=no + if test "$LIBGCRYPT_CONFIG" != "no" ; then + req_major=`echo $min_libgcrypt_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + req_minor=`echo $min_libgcrypt_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + req_micro=`echo $min_libgcrypt_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` + major=`echo $libgcrypt_config_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1/'` + minor=`echo $libgcrypt_config_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\2/'` + micro=`echo $libgcrypt_config_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\3/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -gt "$req_minor"; then + ok=yes + else + if test "$minor" -eq "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($libgcrypt_config_version)" >&5 +$as_echo "yes ($libgcrypt_config_version)" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + if test $ok = yes; then + # If we have a recent libgcrypt, we should also check that the + # API is compatible + if test "$req_libgcrypt_api" -gt 0 ; then + tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking LIBGCRYPT API version" >&5 +$as_echo_n "checking LIBGCRYPT API version... " >&6; } + if test "$req_libgcrypt_api" -eq "$tmp" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: okay" >&5 +$as_echo "okay" >&6; } + else + ok=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: does not match. want=$req_libgcrypt_api got=$tmp" >&5 +$as_echo "does not match. want=$req_libgcrypt_api got=$tmp" >&6; } + fi + fi + fi + fi + if test $ok = yes; then + LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` + LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` + : + if test x"$host" != x ; then + libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none` + if test x"$libgcrypt_config_host" != xnone ; then + if test x"$libgcrypt_config_host" != x"$host" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +*** +*** The config script $LIBGCRYPT_CONFIG was +*** built for $libgcrypt_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-libgcrypt-prefix +*** to specify a matching config script. +***" >&5 +$as_echo "$as_me: WARNING: +*** +*** The config script $LIBGCRYPT_CONFIG was +*** built for $libgcrypt_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-libgcrypt-prefix +*** to specify a matching config script. +***" >&2;} + fi + fi + fi + else + LIBGCRYPT_CFLAGS="" + LIBGCRYPT_LIBS="" + as_fn_error $? "libgcrypt 1.2.0 or newer is required." "$LINENO" 5 + fi + + + + + +# Identify which OS we are building and do specific things based on the host +case $host_os in + *linux*) + HOST_OS=linux + ;; +esac + +# Build tests for now only for Linux. + if test x$HOST_OS = xlinux; then + BUILD_TESTS_TRUE= + BUILD_TESTS_FALSE='#' +else + BUILD_TESTS_TRUE='#' + BUILD_TESTS_FALSE= +fi + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for win32" >&5 +$as_echo_n "checking for win32... " >&6; } +if test "$cross_compiling" = yes; then : + bwin32=cross; { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross" >&5 +$as_echo "cross" >&6; } + +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main(int c, char **v) { +#ifdef _WIN32 +#if _WIN32 + return 0; +#else + return 1; +#endif +#else + return 2; +#endif +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + bwin32=true; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + bwin32=false; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +if test "$bwin32" = cross; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for win32 (cross)" >&5 +$as_echo_n "checking for win32 (cross)... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef _WIN32 +int main(int c, char **v) {return 0;} +#else +#error +int main(int c, char **v) {return x(y);} +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + bwin32=true; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + bwin32=false; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + if test x$bwin32 = xtrue; then + BUILD_NT_SERVICES_TRUE= + BUILD_NT_SERVICES_FALSE='#' +else + BUILD_NT_SERVICES_TRUE='#' + BUILD_NT_SERVICES_FALSE= +fi + + +# Check whether --enable-gcc-hardening was given. +if test "${enable_gcc_hardening+set}" = set; then : + enableval=$enable_gcc_hardening; +fi + + +# Check whether --enable-linker-hardening was given. +if test "${enable_linker_hardening+set}" = set; then : + enableval=$enable_linker_hardening; +fi + + + +all_ldflags_for_check="$LDFLAGS" +all_libs_for_check="$LIBGCRYPT_LIBS" + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#if !defined(__clang__) +#error +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_clang=yes +else + have_clang=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test x$enable_gcc_hardening != xno; then + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + if test x$have_clang = xyes; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Qunused-arguments" >&5 +$as_echo_n "checking whether the compiler accepts -Qunused-arguments... " >&6; } +if ${otr_cv_cflags__Qunused_arguments+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -Qunused-arguments" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__Qunused_arguments=yes +else + otr_cv_cflags__Qunused_arguments=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__Qunused_arguments" >&5 +$as_echo "$otr_cv_cflags__Qunused_arguments" >&6; } + if test x$otr_cv_cflags__Qunused_arguments = xyes; then + CFLAGS="$CFLAGS -Qunused-arguments" + fi + + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fstack-protector-all" >&5 +$as_echo_n "checking whether the compiler accepts -fstack-protector-all... " >&6; } +if ${otr_cv_cflags__fstack_protector_all+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -fstack-protector-all" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__fstack_protector_all=yes +else + otr_cv_cflags__fstack_protector_all=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__fstack_protector_all" >&5 +$as_echo "$otr_cv_cflags__fstack_protector_all" >&6; } + if test x$otr_cv_cflags__fstack_protector_all = xyes; then + CFLAGS="$CFLAGS -fstack-protector-all" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wstack-protector" >&5 +$as_echo_n "checking whether the compiler accepts -Wstack-protector... " >&6; } +if ${otr_cv_cflags__Wstack_protector+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -Wstack-protector" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__Wstack_protector=yes +else + otr_cv_cflags__Wstack_protector=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__Wstack_protector" >&5 +$as_echo "$otr_cv_cflags__Wstack_protector" >&6; } + if test x$otr_cv_cflags__Wstack_protector = xyes; then + CFLAGS="$CFLAGS -Wstack-protector" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fwrapv" >&5 +$as_echo_n "checking whether the compiler accepts -fwrapv... " >&6; } +if ${otr_cv_cflags__fwrapv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -fwrapv" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__fwrapv=yes +else + otr_cv_cflags__fwrapv=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__fwrapv" >&5 +$as_echo "$otr_cv_cflags__fwrapv" >&6; } + if test x$otr_cv_cflags__fwrapv = xyes; then + CFLAGS="$CFLAGS -fwrapv" + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fno-strict-overflow" >&5 +$as_echo_n "checking whether the compiler accepts -fno-strict-overflow... " >&6; } +if ${otr_cv_cflags__fno_strict_overflow+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -fno-strict-overflow" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__fno_strict_overflow=yes +else + otr_cv_cflags__fno_strict_overflow=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__fno_strict_overflow" >&5 +$as_echo "$otr_cv_cflags__fno_strict_overflow" >&6; } + if test x$otr_cv_cflags__fno_strict_overflow = xyes; then + CFLAGS="$CFLAGS -fno-strict-overflow" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wall" >&5 +$as_echo_n "checking whether the compiler accepts -Wall... " >&6; } +if ${otr_cv_cflags__Wall+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -Wall" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__Wall=yes +else + otr_cv_cflags__Wall=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__Wall" >&5 +$as_echo "$otr_cv_cflags__Wall" >&6; } + if test x$otr_cv_cflags__Wall = xyes; then + CFLAGS="$CFLAGS -Wall" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wextra -Wno-unused-parameter" >&5 +$as_echo_n "checking whether the compiler accepts -Wextra -Wno-unused-parameter... " >&6; } +if ${otr_cv_cflags__Wextra__Wno_unused_parameter+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -Wextra -Wno-unused-parameter" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__Wextra__Wno_unused_parameter=yes +else + otr_cv_cflags__Wextra__Wno_unused_parameter=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__Wextra__Wno_unused_parameter" >&5 +$as_echo "$otr_cv_cflags__Wextra__Wno_unused_parameter" >&6; } + if test x$otr_cv_cflags__Wextra__Wno_unused_parameter = xyes; then + CFLAGS="$CFLAGS -Wextra -Wno-unused-parameter" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -Wformat-security" >&5 +$as_echo_n "checking whether the compiler accepts -Wformat-security... " >&6; } +if ${otr_cv_cflags__Wformat_security+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -Wformat-security" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__Wformat_security=yes +else + otr_cv_cflags__Wformat_security=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__Wformat_security" >&5 +$as_echo "$otr_cv_cflags__Wformat_security" >&6; } + if test x$otr_cv_cflags__Wformat_security = xyes; then + CFLAGS="$CFLAGS -Wformat-security" + fi + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts --param ssp-buffer-size=1" >&5 +$as_echo_n "checking whether the compiler accepts --param ssp-buffer-size=1... " >&6; } +if ${otr_cv_cflags___param_ssp_buffer_size_1+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror --param ssp-buffer-size=1" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags___param_ssp_buffer_size_1=yes +else + otr_cv_cflags___param_ssp_buffer_size_1=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags___param_ssp_buffer_size_1" >&5 +$as_echo "$otr_cv_cflags___param_ssp_buffer_size_1" >&6; } + if test x$otr_cv_cflags___param_ssp_buffer_size_1 = xyes; then + CFLAGS="$CFLAGS --param ssp-buffer-size=1" + fi + + + if test "$bwin32" = "false"; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fPIE" >&5 +$as_echo_n "checking whether the compiler accepts -fPIE... " >&6; } +if ${otr_cv_cflags__fPIE+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -fPIE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__fPIE=yes +else + otr_cv_cflags__fPIE=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__fPIE" >&5 +$as_echo "$otr_cv_cflags__fPIE" >&6; } + if test x$otr_cv_cflags__fPIE = xyes; then + CFLAGS="$CFLAGS -fPIE" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -pie" >&5 +$as_echo_n "checking whether the linker accepts -pie... " >&6; } +if ${otr_cv_ldflags__pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + otr_saved_LDFLAGS="$LDFLAGS" + otr_saved_LIBS="$LIBS" + CFLAGS="$CFLAGS -pedantic -Werror" + LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -pie" + LIBS="$LIBS "$all_libs_for_check"" + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + otr_cv_ldflags__pie=yes +else + otr_cv_ldflags__pie=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fputs("", stdout) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + otr_cv_ldflags__pie=yes +else + otr_cv_ldflags__pie=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$otr_saved_CFLAGS" + LDFLAGS="$otr_saved_LDFLAGS" + LIBS="$otr_saved_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_ldflags__pie" >&5 +$as_echo "$otr_cv_ldflags__pie" >&6; } + if test x$otr_cv_ldflags__pie = xyes; then + LDFLAGS="$LDFLAGS -pie" + fi + + + else + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler accepts -fPIE" >&5 +$as_echo_n "checking whether the compiler accepts -fPIE... " >&6; } +if ${otr_cv_cflags__fPIE+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror -fPIE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + otr_cv_cflags__fPIE=yes +else + otr_cv_cflags__fPIE=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$otr_saved_CFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_cflags__fPIE" >&5 +$as_echo "$otr_cv_cflags__fPIE" >&6; } + if test x$otr_cv_cflags__fPIE = xyes; then + CFLAGS="$CFLAGS -fPIE" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -pie" >&5 +$as_echo_n "checking whether the linker accepts -pie... " >&6; } +if ${otr_cv_ldflags__pie+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + otr_saved_LDFLAGS="$LDFLAGS" + otr_saved_LIBS="$LIBS" + CFLAGS="$CFLAGS -pedantic -Werror" + LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -pie" + LIBS="$LIBS "$all_libs_for_check"" + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + otr_cv_ldflags__pie=yes +else + otr_cv_ldflags__pie=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fputs("", stdout) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + otr_cv_ldflags__pie=yes +else + otr_cv_ldflags__pie=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$otr_saved_CFLAGS" + LDFLAGS="$otr_saved_LDFLAGS" + LIBS="$otr_saved_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_ldflags__pie" >&5 +$as_echo "$otr_cv_ldflags__pie" >&6; } + if test x$otr_cv_ldflags__pie = xyes; then + LDFLAGS="$LDFLAGS -pie" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -Wl,--dynamicbase" >&5 +$as_echo_n "checking whether the linker accepts -Wl,--dynamicbase... " >&6; } +if ${otr_cv_ldflags__Wl___dynamicbase+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + otr_saved_LDFLAGS="$LDFLAGS" + otr_saved_LIBS="$LIBS" + CFLAGS="$CFLAGS -pedantic -Werror" + LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -Wl,--dynamicbase" + LIBS="$LIBS "$all_libs_for_check"" + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + otr_cv_ldflags__Wl___dynamicbase=yes +else + otr_cv_ldflags__Wl___dynamicbase=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fputs("", stdout) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + otr_cv_ldflags__Wl___dynamicbase=yes +else + otr_cv_ldflags__Wl___dynamicbase=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$otr_saved_CFLAGS" + LDFLAGS="$otr_saved_LDFLAGS" + LIBS="$otr_saved_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_ldflags__Wl___dynamicbase" >&5 +$as_echo "$otr_cv_ldflags__Wl___dynamicbase" >&6; } + if test x$otr_cv_ldflags__Wl___dynamicbase = xyes; then + LDFLAGS="$LDFLAGS -Wl,--dynamicbase" + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -Wl,--nxcompat" >&5 +$as_echo_n "checking whether the linker accepts -Wl,--nxcompat... " >&6; } +if ${otr_cv_ldflags__Wl___nxcompat+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + otr_saved_LDFLAGS="$LDFLAGS" + otr_saved_LIBS="$LIBS" + CFLAGS="$CFLAGS -pedantic -Werror" + LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -Wl,--nxcompat" + LIBS="$LIBS "$all_libs_for_check"" + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + otr_cv_ldflags__Wl___nxcompat=yes +else + otr_cv_ldflags__Wl___nxcompat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fputs("", stdout) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + otr_cv_ldflags__Wl___nxcompat=yes +else + otr_cv_ldflags__Wl___nxcompat=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$otr_saved_CFLAGS" + LDFLAGS="$otr_saved_LDFLAGS" + LIBS="$otr_saved_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_ldflags__Wl___nxcompat" >&5 +$as_echo "$otr_cv_ldflags__Wl___nxcompat" >&6; } + if test x$otr_cv_ldflags__Wl___nxcompat = xyes; then + LDFLAGS="$LDFLAGS -Wl,--nxcompat" + fi + + + fi +fi + +if test x$enable_linker_hardening != xno; then + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -z relro -z now" >&5 +$as_echo_n "checking whether the linker accepts -z relro -z now... " >&6; } +if ${otr_cv_ldflags__z_relro__z_now+:} false; then : + $as_echo_n "(cached) " >&6 +else + + otr_saved_CFLAGS="$CFLAGS" + otr_saved_LDFLAGS="$LDFLAGS" + otr_saved_LIBS="$LIBS" + CFLAGS="$CFLAGS -pedantic -Werror" + LDFLAGS="$LDFLAGS "$all_ldflags_for_check" -z relro -z now" + LIBS="$LIBS "$all_libs_for_check"" + if test "$cross_compiling" = yes; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + otr_cv_ldflags__z_relro__z_now=yes +else + otr_cv_ldflags__z_relro__z_now=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +fputs("", stdout) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + otr_cv_ldflags__z_relro__z_now=yes +else + otr_cv_ldflags__z_relro__z_now=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$otr_saved_CFLAGS" + LDFLAGS="$otr_saved_LDFLAGS" + LIBS="$otr_saved_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $otr_cv_ldflags__z_relro__z_now" >&5 +$as_echo "$otr_cv_ldflags__z_relro__z_now" >&6; } + if test x$otr_cv_ldflags__z_relro__z_now = xyes; then + LDFLAGS="$LDFLAGS -z relro -z now" + fi + + +fi + +ac_config_files="$ac_config_files Makefile src/Makefile toolkit/Makefile tests/Makefile tests/utils/Makefile libotr.pc tests/utils/tap/Makefile tests/unit/Makefile tests/regression/Makefile tests/regression/client/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_TESTS_TRUE}" && test -z "${BUILD_TESTS_FALSE}"; then + as_fn_error $? "conditional \"BUILD_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_NT_SERVICES_TRUE}" && test -z "${BUILD_NT_SERVICES_FALSE}"; then + as_fn_error $? "conditional \"BUILD_NT_SERVICES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libotr $as_me 4.1.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to . +libotr home page: ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +libotr config.status 4.1.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "toolkit/Makefile") CONFIG_FILES="$CONFIG_FILES toolkit/Makefile" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; + "tests/utils/Makefile") CONFIG_FILES="$CONFIG_FILES tests/utils/Makefile" ;; + "libotr.pc") CONFIG_FILES="$CONFIG_FILES libotr.pc" ;; + "tests/utils/tap/Makefile") CONFIG_FILES="$CONFIG_FILES tests/utils/tap/Makefile" ;; + "tests/unit/Makefile") CONFIG_FILES="$CONFIG_FILES tests/unit/Makefile" ;; + "tests/regression/Makefile") CONFIG_FILES="$CONFIG_FILES tests/regression/Makefile" ;; + "tests/regression/client/Makefile") CONFIG_FILES="$CONFIG_FILES tests/regression/client/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_TESTS_TRUE}" && test -z "${BUILD_TESTS_FALSE}"; then + as_fn_error $? "conditional \"BUILD_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_NT_SERVICES_TRUE}" && test -z "${BUILD_NT_SERVICES_FALSE}"; then + as_fn_error $? "conditional \"BUILD_NT_SERVICES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__EXEEXT_TRUE}" && test -z "${am__EXEEXT_FALSE}"; then + as_fn_error $? "conditional \"am__EXEEXT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libotr $as_me 4.1.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to . +libotr home page: ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +libotr config.status 4.1.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + +ac_aux_dir='$ac_aux_dir' + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "toolkit/Makefile") CONFIG_FILES="$CONFIG_FILES toolkit/Makefile" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; + "tests/utils/Makefile") CONFIG_FILES="$CONFIG_FILES tests/utils/Makefile" ;; + "libotr.pc") CONFIG_FILES="$CONFIG_FILES libotr.pc" ;; + "tests/utils/tap/Makefile") CONFIG_FILES="$CONFIG_FILES tests/utils/tap/Makefile" ;; + "tests/unit/Makefile") CONFIG_FILES="$CONFIG_FILES tests/unit/Makefile" ;; + "tests/regression/Makefile") CONFIG_FILES="$CONFIG_FILES tests/regression/Makefile" ;; + "tests/regression/client/Makefile") CONFIG_FILES="$CONFIG_FILES tests/regression/client/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/comm/third_party/libotr/configure.ac b/comm/third_party/libotr/configure.ac new file mode 100644 index 0000000000..d8c857d895 --- /dev/null +++ b/comm/third_party/libotr/configure.ac @@ -0,0 +1,191 @@ +dnl Process this file with autoconf to produce configure. + +dnl Notes on version numbering: +dnl For an implementation-only change: +dnl Change the libotr package version from a.b.c to a.b.(c+1) +dnl Change the libotr libtool version from x:y:z to x:(y+1):z +dnl For a backwards-compatible API change (e.g. adding functions): +dnl Change the libotr package version from a.b.c to a.(b+1).0 +dnl Change the libotr libtool version from x:y:z to (x+1):0:(z+1) +dnl [Note that this does *not* change the major number of the .so.] +dnl For a backwards-incompatible API change (e.g. changing data structures): +dnl Change the libotr package version from a.b.c to (a+1).0.0 +dnl Change the libotr libtool version from x:y:z to (x+1):0:0 +AC_INIT([libotr],[4.1.1],[otr@cypherpunks.ca],[],[https://otr.cypherpunks.ca]) + +AM_CONFIG_HEADER(config.h) +AC_CONFIG_AUX_DIR([config]) + +AM_INIT_AUTOMAKE +LIBOTR_LIBTOOL_VERSION="6:1:1" + +AC_CONFIG_MACRO_DIR([config]) +# Silent compilation so warnings can be spotted. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_SUBST(LIBOTR_LIBTOOL_VERSION) + +AC_PROG_CC +LT_INIT + +AM_PATH_LIBGCRYPT(1:1.2.0,,AC_MSG_ERROR(libgcrypt 1.2.0 or newer is required.)) + +AC_CANONICAL_HOST +# Identify which OS we are building and do specific things based on the host +case $host_os in + *linux*) + HOST_OS=linux + ;; +esac + +# Build tests for now only for Linux. +AM_CONDITIONAL([BUILD_TESTS], [test x$HOST_OS = xlinux]) + +dnl 1:flags +dnl Taken from Tor's autoconf magic repository +AC_DEFUN([OTR_CHECK_CFLAGS], [ + AS_VAR_PUSHDEF([VAR],[otr_cv_cflags_$1]) + AC_CACHE_CHECK([whether the compiler accepts $1], VAR, [ + otr_saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -pedantic -Werror $1" + AC_TRY_COMPILE([], [return 0;], + [AS_VAR_SET(VAR,yes)], + [AS_VAR_SET(VAR,no)]) + CFLAGS="$otr_saved_CFLAGS" + ]) + if test x$VAR = xyes; then + CFLAGS="$CFLAGS $1" + fi + AS_VAR_POPDEF([VAR]) +]) + +dnl 1:flags +dnl 2:extra ldflags +dnl 3:extra libraries +AC_DEFUN([OTR_CHECK_LDFLAGS], [ + AS_VAR_PUSHDEF([VAR],[otr_cv_ldflags_$1]) + AC_CACHE_CHECK([whether the linker accepts $1], VAR, [ + otr_saved_CFLAGS="$CFLAGS" + otr_saved_LDFLAGS="$LDFLAGS" + otr_saved_LIBS="$LIBS" + CFLAGS="$CFLAGS -pedantic -Werror" + LDFLAGS="$LDFLAGS $2 $1" + LIBS="$LIBS $3" + AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [fputs("", stdout)])], + [AS_VAR_SET(VAR,yes)], + [AS_VAR_SET(VAR,no)], + [AC_TRY_LINK([], [return 0;], + [AS_VAR_SET(VAR,yes)], + [AS_VAR_SET(VAR,no)])]) + CFLAGS="$otr_saved_CFLAGS" + LDFLAGS="$otr_saved_LDFLAGS" + LIBS="$otr_saved_LIBS" + ]) + if test x$VAR = xyes; then + LDFLAGS="$LDFLAGS $1" + fi + AS_VAR_POPDEF([VAR]) +]) + + +dnl If _WIN32 is defined and non-zero, we are building for win32 +AC_MSG_CHECKING([for win32]) +AC_RUN_IFELSE([AC_LANG_SOURCE([ +int main(int c, char **v) { +#ifdef _WIN32 +#if _WIN32 + return 0; +#else + return 1; +#endif +#else + return 2; +#endif +}])], +bwin32=true; AC_MSG_RESULT([yes]), +bwin32=false; AC_MSG_RESULT([no]), +bwin32=cross; AC_MSG_RESULT([cross]) +) + +if test "$bwin32" = cross; then +AC_MSG_CHECKING([for win32 (cross)]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#ifdef _WIN32 +int main(int c, char **v) {return 0;} +#else +#error +int main(int c, char **v) {return x(y);} +#endif +])], +bwin32=true; AC_MSG_RESULT([yes]), +bwin32=false; AC_MSG_RESULT([no])) +fi + +AM_CONDITIONAL(BUILD_NT_SERVICES, test x$bwin32 = xtrue) + +dnl Adam Shostack suggests the following for Windows: +dnl -D_FORTIFY_SOURCE=2 -fstack-protector-all +dnl Others suggest '/gs /safeseh /nxcompat /dynamicbase' for non-gcc on Windows +dnl This requires that we use gcc and that we add -O2 to the CFLAGS. +AC_ARG_ENABLE(gcc-hardening, + AS_HELP_STRING(--disable-gcc-hardening, disable compiler security checks)) + +dnl Linker hardening options +dnl Currently these options are ELF specific - you can't use this with MacOSX +AC_ARG_ENABLE(linker-hardening, + AS_HELP_STRING(--disable-linker-hardening, disable linker security fixups)) + +dnl --------------------------------------------------------------------- +dnl Now that we know about our major libraries, we can check for compiler +dnl and linker hardening options. We need to do this with the libraries known, +dnl since sometimes the linker will like an option but not be willing to +dnl use it with a build of a library. + +all_ldflags_for_check="$LDFLAGS" +all_libs_for_check="$LIBGCRYPT_LIBS" + +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ +#if !defined(__clang__) +#error +#endif +])], have_clang=yes, have_clang=no) + +if test x$enable_gcc_hardening != xno; then + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + if test x$have_clang = xyes; then + OTR_CHECK_CFLAGS(-Qunused-arguments) + fi + OTR_CHECK_CFLAGS(-fstack-protector-all) + OTR_CHECK_CFLAGS(-Wstack-protector) + OTR_CHECK_CFLAGS(-fwrapv) + + dnl Ian added the next four: + OTR_CHECK_CFLAGS(-fno-strict-overflow) + OTR_CHECK_CFLAGS(-Wall) + OTR_CHECK_CFLAGS(-Wextra -Wno-unused-parameter) + OTR_CHECK_CFLAGS(-Wformat-security) + + OTR_CHECK_CFLAGS(--param ssp-buffer-size=1) + if test "$bwin32" = "false"; then + OTR_CHECK_CFLAGS(-fPIE) + OTR_CHECK_LDFLAGS(-pie, "$all_ldflags_for_check", "$all_libs_for_check") + else + OTR_CHECK_CFLAGS(-fPIE) + OTR_CHECK_LDFLAGS(-pie, "$all_ldflags_for_check", "$all_libs_for_check") + OTR_CHECK_LDFLAGS([-Wl,--dynamicbase], "$all_ldflags_for_check", "$all_libs_for_check") + OTR_CHECK_LDFLAGS([-Wl,--nxcompat], "$all_ldflags_for_check", "$all_libs_for_check") + fi +fi + +if test x$enable_linker_hardening != xno; then + OTR_CHECK_LDFLAGS(-z relro -z now, "$all_ldflags_for_check", "$all_libs_for_check") +fi + +AC_OUTPUT([Makefile src/Makefile toolkit/Makefile tests/Makefile tests/utils/Makefile libotr.pc + tests/utils/tap/Makefile + tests/unit/Makefile + tests/regression/Makefile + tests/regression/client/Makefile +]) + +AC_OUTPUT diff --git a/comm/third_party/libotr/install-sh b/comm/third_party/libotr/install-sh new file mode 100755 index 0000000000..377bb8687f --- /dev/null +++ b/comm/third_party/libotr/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-11-20.07; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/comm/third_party/libotr/libotr.m4 b/comm/third_party/libotr/libotr.m4 new file mode 100644 index 0000000000..80b25f86bc --- /dev/null +++ b/comm/third_party/libotr/libotr.m4 @@ -0,0 +1,134 @@ +dnl +dnl Off-the-Record Messaging library +dnl Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov +dnl +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of version 2.1 of the GNU Lesser General +dnl Public License as published by the Free Software Foundation. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +dnl + +dnl AM_PATH_LIBOTR([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for libotr, and define LIBOTR_CFLAGS and LIBOTR_LIBS as appropriate. +dnl enables arguments --with-libotr-prefix= +dnl --with-libotr-inc-prefix= +dnl +dnl You must already have found libgcrypt with AM_PATH_LIBGCRYPT +dnl +dnl Adapted from alsa.m4, originally by +dnl Richard Boulton +dnl Christopher Lansdown +dnl Jaroslav Kysela + +AC_DEFUN([AM_PATH_LIBOTR], +[dnl Save the original CFLAGS, LDFLAGS, and LIBS +libotr_save_CFLAGS="$CFLAGS" +libotr_save_LDFLAGS="$LDFLAGS" +libotr_save_LIBS="$LIBS" +libotr_found=yes + +dnl +dnl Get the cflags and libraries for libotr +dnl +AC_ARG_WITH(libotr-prefix, +[ --with-libotr-prefix=PFX Prefix where libotr is installed(optional)], +[libotr_prefix="$withval"], [libotr_prefix=""]) + +AC_ARG_WITH(libotr-inc-prefix, +[ --with-libotr-inc-prefix=PFX Prefix where libotr includes are (optional)], +[libotr_inc_prefix="$withval"], [libotr_inc_prefix=""]) + +dnl Add any special include directories +AC_MSG_CHECKING(for libotr CFLAGS) +if test "$libotr_inc_prefix" != "" ; then + LIBOTR_CFLAGS="$LIBOTR_CFLAGS -I$libotr_inc_prefix" + CFLAGS="$CFLAGS $LIBOTR_CFLAGS" +fi +AC_MSG_RESULT($LIBOTR_CFLAGS) + +dnl add any special lib dirs +AC_MSG_CHECKING(for libotr LIBS) +if test "$libotr_prefix" != "" ; then + LIBOTR_LIBS="$LIBOTR_LIBS -L$libotr_prefix" + LDFLAGS="$LDFLAGS $LIBOTR_LIBS" +fi + +dnl add the libotr library +LIBOTR_LIBS="$LIBOTR_LIBS -lotr" +LIBS="$LIBOTR_LIBS $LIBS" +AC_MSG_RESULT($LIBOTR_LIBS) + +dnl Check for a working version of libotr that is of the right version. +min_libotr_version=ifelse([$1], ,3.0.0,$1) +no_libotr="" + libotr_min_major_version=`echo $min_libotr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + libotr_min_minor_version=`echo $min_libotr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + libotr_min_sub_version=`echo $min_libotr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` +AC_MSG_CHECKING(for libotr headers version $libotr_min_major_version.x >= $min_libotr_version) + +AC_LANG_SAVE +AC_LANG_C +AC_TRY_COMPILE([ +#include +#include +], [ +# if(OTRL_VERSION_MAJOR != $libotr_min_major_version) +# error not present +# else + +# if(OTRL_VERSION_MINOR > $libotr_min_minor_version) + exit(0); +# else +# if(OTRL_VERSION_MINOR < $libotr_min_minor_version) +# error not present +# endif + +# if(OTRL_VERSION_SUB < $libotr_min_sub_version) +# error not present +# endif +# endif +# endif +exit(0); +], + [AC_MSG_RESULT(found.)], + [AC_MSG_RESULT(not present.) + ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libotr not found.)]) + libotr_found=no] +) +AC_LANG_RESTORE + +dnl Now that we know that we have the right version, let's see if we have the library and not just the headers. +AC_CHECK_LIB([otr], [otrl_message_receiving],, + [ifelse([$3], , [AC_MSG_ERROR(No linkable libotr was found.)]) + libotr_found=no], + $LIBGCRYPT_LIBS +) + +LDFLAGS="$libotr_save_LDFLAGS" +LIBS="$libotr_save_LIBS" + +if test "x$libotr_found" = "xyes" ; then + ifelse([$2], , :, [$2]) +else + LIBOTR_CFLAGS="" + LIBOTR_LIBS="" + ifelse([$3], , :, [$3]) +fi + +dnl That should be it. Now just export our symbols: +AC_SUBST(LIBOTR_CFLAGS) +AC_SUBST(LIBOTR_LIBS) +]) + diff --git a/comm/third_party/libotr/libotr.pc.in b/comm/third_party/libotr/libotr.pc.in new file mode 100644 index 0000000000..38f8582613 --- /dev/null +++ b/comm/third_party/libotr/libotr.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libotr +Description: Off-the-Record Messaging Library +Version: @VERSION@ +URL: https://otr.cypherpunks.ca/ +Libs: -L${libdir} -lotr +Cflags: -I${includedir} diff --git a/comm/third_party/libotr/ltmain.sh b/comm/third_party/libotr/ltmain.sh new file mode 100644 index 0000000000..a356acafa4 --- /dev/null +++ b/comm/third_party/libotr/ltmain.sh @@ -0,0 +1,9661 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.7ubuntu1 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.2 Debian-2.4.2-1.7ubuntu1" +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/comm/third_party/libotr/packaging/fedora/libotr.spec b/comm/third_party/libotr/packaging/fedora/libotr.spec new file mode 100644 index 0000000000..82dd709d27 --- /dev/null +++ b/comm/third_party/libotr/packaging/fedora/libotr.spec @@ -0,0 +1,173 @@ +%global snapshot 0 +Summary: Off-The-Record Messaging library and toolkit +Name: libotr +Version: 4.0.0 +Release: 1%{?dist} +License: GPLv2 and LGPLv2 +Group: System Environment/Libraries +Source0: https://otr.cypherpunks.ca/%{name}-%{version}.tar.gz +Url: https://otr.cypherpunks.ca/ +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Provides: libotr-toolkit = %{version} +Obsoletes: libotr-toolkit < %{version} +Requires: libgcrypt >= 1.2.0 +Requires: pkgconfig +BuildRequires: libgcrypt-devel >= 1.2.0, libgpg-error-devel +%if %{snapshot} +Buildrequires: libtool automake autoconf +%endif + +%description +Off-the-Record Messaging Library and Toolkit +This is a library and toolkit which implements Off-the-Record (OTR) Messaging. +OTR allows you to have private conversations over IM by providing Encryption, +Authentication, Deniability and Perfect forward secrecy. + +%package devel +Summary: Development library and include files for libotr +Group: Development/Libraries +Requires: %{name} = %{version}-%{release}, libgcrypt-devel >= 1.2.0 + +%description devel +The devel package contains the libotr library and include files. + +%prep +%setup -q + +%if %{snapshot} +aclocal +intltoolize --force --copy +autoreconf -s -i +%endif + +%build +%configure --with-pic --disable-rpath --disable-static +sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool +sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool +make %{?_smp_mflags} all + +%install +rm -rf $RPM_BUILD_ROOT +make \ + DESTDIR=$RPM_BUILD_ROOT \ + LIBINSTDIR=%{_libdir} \ + install +rm -rf $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%doc AUTHORS README COPYING COPYING.LIB NEWS Protocol* +%{_libdir}/libotr.so.* +%{_bindir}/* +%{_mandir}/man1/* + +%files devel +%defattr(-,root,root,-) +%doc ChangeLog +%{_libdir}/libotr.so +%{_libdir}/pkgconfig/libotr.pc +%dir %{_includedir}/libotr +%{_includedir}/libotr/* +%{_datadir}/aclocal/* + + +%changelog +* Sat Jul 27 2013 Paul Wouters - 4.0.0-1 +- Upgraded to libotr-4.0.0 +- Since this is API incompatible, there is also a libotr3 package + +* Thu Feb 14 2013 Fedora Release Engineering - 3.2.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Aug 15 2012 Paul Wouters - 3.2.1-1 +- Updated to 3.2.1, updates patch for rhbz#846377, CVE-2012-3461 + +* Wed Aug 08 2012 Paul Wouters - 3.2.0-9 +- Patch for Multiple heap-based buffer overflows in the Base64 decoder + (rhbz#846377, upstream will not release 3.2.1 for this) + +* Thu Jul 19 2012 Fedora Release Engineering - 3.2.0-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri Jan 13 2012 Fedora Release Engineering - 3.2.0-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Feb 08 2011 Fedora Release Engineering - 3.2.0-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon May 24 2010 Tom "spot" Callaway - 3.2.0-5 +- disable static libs +- disable rpath + +* Fri Jul 24 2009 Fedora Release Engineering - 3.2.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed Feb 25 2009 Fedora Release Engineering - 3.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Aug 7 2008 Tom "spot" Callaway - 3.2.0-2 +- fix license tag + +* Sun Jun 15 2008 Paul Wouters 3.2.0-1 +- Upgraded to 3.2.0 + +* Tue Feb 19 2008 Fedora Release Engineering - 3.1.0-2 +- Autorebuild for GCC 4.3 + +* Wed Aug 1 2007 Paul Wouters 3.1.0-1 +- Upgraded to current version +- Updated URLS and configure line + +* Mon Sep 11 2006 Paul Wouters 3.0.0-2 +- Rebuild requested for PT_GNU_HASH support from gcc + +* Mon Oct 17 2005 Paul Wouters 3.0.0-1 +- Minor change to allow for new documentation files. Fixed Requires: + +* Sat Jun 19 2005 Paul Wouters +- Fixed defattr, groups, description and duplicate files in devel + +* Fri Jun 17 2005 Tom "spot" Callaway +- reworked for Fedora Extras + +* Tue May 3 2005 Ian Goldberg +- Bumped version number to 2.0.2 +* Wed Feb 16 2005 Ian Goldberg +- Bumped version number to 2.0.1 +* Tue Feb 8 2005 Ian Goldberg +- Bumped version number to 2.0.0 +* Wed Feb 2 2005 Ian Goldberg +- Added libotr.m4 to the devel package +- Bumped version number to 1.99.0 +* Wed Jan 19 2005 Paul Wouters +- Updated spec file for the gaim-otr libotr split +* Tue Dec 21 2004 Ian Goldberg +- Bumped to version 1.0.2. +* Fri Dec 17 2004 Paul Wouters +- instll fix for x86_64 +* Sun Dec 12 2004 Ian Goldberg +- Bumped to version 1.0.0. +* Fri Dec 10 2004 Ian Goldberg +- Bumped to version 0.9.9rc2. +* Thu Dec 9 2004 Ian Goldberg +- Added CFLAGS to "make all", removed DESTDIR +* Wed Dec 8 2004 Ian Goldberg +- Bumped to version 0.9.9rc1. +* Fri Dec 3 2004 Ian Goldberg +- Bumped to version 0.9.1. +* Wed Dec 1 2004 Paul Wouters +- Bumped to version 0.9.0. +- Fixed install for tools and cos +- Added Obsoletes: target for otr-plugin so rpm-Uhv gaim-otr removes it. +* Mon Nov 22 2004 Ian Goldberg +- Bumped version to 0.8.1 +* Sun Nov 21 2004 Paul Wouters +- Initial version + diff --git a/comm/third_party/libotr/src/Makefile.am b/comm/third_party/libotr/src/Makefile.am new file mode 100644 index 0000000000..c2146cff8e --- /dev/null +++ b/comm/third_party/libotr/src/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = @LIBGCRYPT_CFLAGS@ + +lib_LTLIBRARIES = libotr.la + +libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \ + userstate.c tlv.c auth.c sm.c context_priv.c instag.c + +libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@ + +otrincdir = $(includedir)/libotr + +otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \ + version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h \ + context_priv.h instag.h diff --git a/comm/third_party/libotr/src/Makefile.in b/comm/third_party/libotr/src/Makefile.in new file mode 100644 index 0000000000..41789c7b66 --- /dev/null +++ b/comm/third_party/libotr/src/Makefile.in @@ -0,0 +1,680 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/config/depcomp $(otrinc_HEADERS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(otrincdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libotr_la_LIBADD = +am_libotr_la_OBJECTS = privkey.lo context.lo proto.lo b64.lo dh.lo \ + mem.lo message.lo userstate.lo tlv.lo auth.lo sm.lo \ + context_priv.lo instag.lo +libotr_la_OBJECTS = $(am_libotr_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libotr_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libotr_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libotr_la_SOURCES) +DIST_SOURCES = $(libotr_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(otrinc_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = @LIBGCRYPT_CFLAGS@ +lib_LTLIBRARIES = libotr.la +libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \ + userstate.c tlv.c auth.c sm.c context_priv.c instag.c + +libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@ +otrincdir = $(includedir)/libotr +otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \ + version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h \ + context_priv.h instag.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libotr.la: $(libotr_la_OBJECTS) $(libotr_la_DEPENDENCIES) $(EXTRA_libotr_la_DEPENDENCIES) + $(AM_V_CCLD)$(libotr_la_LINK) -rpath $(libdir) $(libotr_la_OBJECTS) $(libotr_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/b64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context_priv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instag.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privkey.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userstate.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-otrincHEADERS: $(otrinc_HEADERS) + @$(NORMAL_INSTALL) + @list='$(otrinc_HEADERS)'; test -n "$(otrincdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(otrincdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(otrincdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(otrincdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(otrincdir)" || exit $$?; \ + done + +uninstall-otrincHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(otrinc_HEADERS)'; test -n "$(otrincdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(otrincdir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(otrincdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-otrincHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES uninstall-otrincHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man \ + install-otrincHEADERS install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-libLTLIBRARIES uninstall-otrincHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/src/auth.c b/comm/third_party/libotr/src/auth.c new file mode 100644 index 0000000000..d0c55057e1 --- /dev/null +++ b/comm/third_party/libotr/src/auth.c @@ -0,0 +1,1573 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include +#include + +/* libotr headers */ +#include "b64.h" +#include "privkey.h" +#include "auth.h" +#include "serial.h" +#include "proto.h" +#include "context.h" +#include "mem.h" + +#if OTRL_DEBUGGING +#include + +/* Dump the contents of an OtrlAuthInfo to the FILE *f. */ +void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth) +{ + int i; + + fprintf(f, " Auth info %p:\n", auth); + fprintf(f, " State: %d (%s)\n", auth->authstate, + auth->authstate == OTRL_AUTHSTATE_NONE ? "NONE" : + auth->authstate == OTRL_AUTHSTATE_AWAITING_DHKEY ? "AWAITING_DHKEY" : + auth->authstate == OTRL_AUTHSTATE_AWAITING_REVEALSIG ? + "AWAITING_REVEALSIG" : + auth->authstate == OTRL_AUTHSTATE_AWAITING_SIG ? "AWAITING_SIG" : + auth->authstate == OTRL_AUTHSTATE_V1_SETUP ? "V1_SETUP" : + "INVALID"); + fprintf(f, " Context: %p\n", auth->context); + fprintf(f, " Our keyid: %u\n", auth->our_keyid); + fprintf(f, " Their keyid: %u\n", auth->their_keyid); + fprintf(f, " Their fingerprint: "); + for (i=0;i<20;++i) { + fprintf(f, "%02x", auth->their_fingerprint[i]); + } + fprintf(f, "\n Initiated = %d\n", auth->initiated); + fprintf(f, "\n Proto version = %d\n", auth->protocol_version); + fprintf(f, "\n Lastauthmsg = %s\n", + auth->lastauthmsg ? auth->lastauthmsg : "(nil)"); + fprintf(f, "\n Commit sent time = %ld\n", + (long) auth->commit_sent_time); +} + +#endif + +/* + * Initialize the fields of an OtrlAuthInfo (already allocated). + */ +void otrl_auth_new(struct context *context) +{ + OtrlAuthInfo *auth = &(context->auth); + auth->authstate = OTRL_AUTHSTATE_NONE; + otrl_dh_keypair_init(&(auth->our_dh)); + auth->our_keyid = 0; + auth->encgx = NULL; + auth->encgx_len = 0; + memset(auth->r, 0, 16); + memset(auth->hashgx, 0, 32); + auth->their_pub = NULL; + auth->their_keyid = 0; + auth->enc_c = NULL; + auth->enc_cp = NULL; + auth->mac_m1 = NULL; + auth->mac_m1p = NULL; + auth->mac_m2 = NULL; + auth->mac_m2p = NULL; + memset(auth->their_fingerprint, 0, 20); + auth->initiated = 0; + auth->protocol_version = 0; + memset(auth->secure_session_id, 0, 20); + auth->secure_session_id_len = 0; + auth->lastauthmsg = NULL; + auth->commit_sent_time = 0; + auth->context = context; +} + +/* + * Clear the fields of an OtrlAuthInfo (but leave it allocated). + */ +void otrl_auth_clear(OtrlAuthInfo *auth) +{ + auth->authstate = OTRL_AUTHSTATE_NONE; + otrl_dh_keypair_free(&(auth->our_dh)); + auth->our_keyid = 0; + free(auth->encgx); + auth->encgx = NULL; + auth->encgx_len = 0; + memset(auth->r, 0, 16); + memset(auth->hashgx, 0, 32); + gcry_mpi_release(auth->their_pub); + auth->their_pub = NULL; + auth->their_keyid = 0; + gcry_cipher_close(auth->enc_c); + gcry_cipher_close(auth->enc_cp); + gcry_md_close(auth->mac_m1); + gcry_md_close(auth->mac_m1p); + gcry_md_close(auth->mac_m2); + gcry_md_close(auth->mac_m2p); + auth->enc_c = NULL; + auth->enc_cp = NULL; + auth->mac_m1 = NULL; + auth->mac_m1p = NULL; + auth->mac_m2 = NULL; + auth->mac_m2p = NULL; + memset(auth->their_fingerprint, 0, 20); + auth->initiated = 0; + auth->protocol_version = 0; + memset(auth->secure_session_id, 0, 20); + auth->secure_session_id_len = 0; + free(auth->lastauthmsg); + auth->lastauthmsg = NULL; + auth->commit_sent_time = 0; +} + +/* + * Start a fresh AKE (version 2 or 3) using the given OtrlAuthInfo. Generate + * a fresh DH keypair to use. If no error is returned, the message to + * transmit will be contained in auth->lastauthmsg. + */ +gcry_error_t otrl_auth_start_v23(OtrlAuthInfo *auth, int version) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + const enum gcry_mpi_format format = GCRYMPI_FMT_USG; + size_t npub; + gcry_cipher_hd_t enc = NULL; + unsigned char ctr[16]; + unsigned char *buf, *bufp; + size_t buflen, lenp; + + /* Clear out this OtrlAuthInfo and start over */ + otrl_auth_clear(auth); + auth->initiated = 1; + auth->protocol_version = version; + auth->context->protocol_version = version; + + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); + auth->our_keyid = 1; + + /* Pick an encryption key */ + gcry_randomize(auth->r, 16, GCRY_STRONG_RANDOM); + + /* Allocate space for the encrypted g^x */ + gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub); + auth->encgx = malloc(4+npub); + if (auth->encgx == NULL) goto memerr; + auth->encgx_len = 4+npub; + bufp = auth->encgx; + lenp = auth->encgx_len; + write_mpi(auth->our_dh.pub, npub, "g^x"); + assert(lenp == 0); + + /* Hash g^x */ + gcry_md_hash_buffer(GCRY_MD_SHA256, auth->hashgx, auth->encgx, + auth->encgx_len); + + /* Encrypt g^x using the key r */ + err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + GCRY_CIPHER_SECURE); + if (err) goto err; + + err = gcry_cipher_setkey(enc, auth->r, 16); + if (err) goto err; + + memset(ctr, 0, 16); + err = gcry_cipher_setctr(enc, ctr, 16); + if (err) goto err; + + err = gcry_cipher_encrypt(enc, auth->encgx, auth->encgx_len, NULL, 0); + if (err) goto err; + + gcry_cipher_close(enc); + enc = NULL; + + /* Now serialize the message */ + lenp = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4 + + auth->encgx_len + 4 + 32; + bufp = malloc(lenp); + if (bufp == NULL) goto memerr; + buf = bufp; + buflen = lenp; + + /* Header */ + write_header(auth->protocol_version, '\x02'); + if (auth->protocol_version == 3) { + /* instance tags */ + write_int(auth->context->our_instance); + debug_int("Sender instag", bufp-4); + write_int(auth->context->their_instance); + debug_int("Recipient instag", bufp-4); + } + + /* Encrypted g^x */ + write_int(auth->encgx_len); + debug_int("Enc gx len", bufp-4); + memmove(bufp, auth->encgx, auth->encgx_len); + debug_data("Enc gx", bufp, auth->encgx_len); + bufp += auth->encgx_len; lenp -= auth->encgx_len; + + /* Hashed g^x */ + write_int(32); + debug_int("hashgx len", bufp-4); + memmove(bufp, auth->hashgx, 32); + debug_data("hashgx", bufp, 32); + bufp += 32; lenp -= 32; + + assert(lenp == 0); + + auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); + free(buf); + if (auth->lastauthmsg == NULL) goto memerr; + auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY; + + return err; + +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + otrl_auth_clear(auth); + gcry_cipher_close(enc); + return err; +} + +/* + * Create a D-H Key Message using the our_dh value in the given auth, + * and store it in auth->lastauthmsg. + */ +static gcry_error_t create_key_message(OtrlAuthInfo *auth) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + const enum gcry_mpi_format format = GCRYMPI_FMT_USG; + unsigned char *buf, *bufp; + size_t buflen, lenp; + size_t npub; + + gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub); + buflen = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4 + npub; + buf = malloc(buflen); + if (buf == NULL) goto memerr; + bufp = buf; + lenp = buflen; + + /* header */ + write_header(auth->protocol_version, '\x0a'); + if (auth->protocol_version == 3) { + /* instance tags */ + write_int(auth->context->our_instance); + debug_int("Sender instag", bufp-4); + write_int(auth->context->their_instance); + debug_int("Recipient instag", bufp-4); + } + + /* g^y */ + write_mpi(auth->our_dh.pub, npub, "g^y"); + + assert(lenp == 0); + + free(auth->lastauthmsg); + auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); + free(buf); + if (auth->lastauthmsg == NULL) goto memerr; + + return err; + +memerr: + err = gcry_error(GPG_ERR_ENOMEM); + return err; +} + +/* + * Handle an incoming D-H Commit Message. If no error is returned, the + * message to send will be left in auth->lastauthmsg. Generate a fresh + * keypair to use. + */ +gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth, + const char *commitmsg, int version) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp = NULL, *encbuf = NULL; + unsigned char hashbuf[32]; + size_t buflen, lenp, enclen, hashlen; + int res; + + /* Are we the auth for the master context? */ + int is_master = (auth->context->m_context == auth->context); + + res = otrl_base64_otr_decode(commitmsg, &buf, &buflen); + if (res == -1) goto memerr; + if (res == -2) goto invval; + + bufp = buf; + lenp = buflen; + + /* Header */ + auth->protocol_version = version; + auth->context->protocol_version = version; + skip_header('\x02'); + + if (version == 3) { + require_len(8); + bufp += 8; lenp -= 8; + } + + /* Encrypted g^x */ + read_int(enclen); + require_len(enclen); + encbuf = malloc(enclen); + if (encbuf == NULL && enclen > 0) goto memerr; + memmove(encbuf, bufp, enclen); + bufp += enclen; lenp -= enclen; + + /* Hashed g^x */ + read_int(hashlen); + if (hashlen != 32) goto invval; + require_len(32); + memmove(hashbuf, bufp, 32); + bufp += 32; lenp -= 32; + + if (lenp != 0) goto invval; + free(buf); + buf = NULL; + + switch(auth->authstate) { + case OTRL_AUTHSTATE_NONE: + case OTRL_AUTHSTATE_AWAITING_SIG: + case OTRL_AUTHSTATE_V1_SETUP: + /* Store the incoming information */ + otrl_auth_clear(auth); + auth->protocol_version = version; + + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); + + auth->our_keyid = 1; + auth->encgx = encbuf; + encbuf = NULL; + auth->encgx_len = enclen; + memmove(auth->hashgx, hashbuf, 32); + + /* Create a D-H Key Message */ + err = create_key_message(auth); + if (err) goto err; + auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG; + break; + + case OTRL_AUTHSTATE_AWAITING_DHKEY: + /* We sent a D-H Commit Message, and we also received one + * back. If we're the master context, then the keypair in here + * is probably stale; we just kept it around for a little + * while in case some other logged in instance of our buddy + * replied with a DHKEY message. In that case, use the + * incoming parameters. Otherwise, compare the hashgx + * values to see which one wins. + * + * This does NOT use constant time comparison because these + * are two public values thus don't need it. Also, this checks + * which pubkey is larger and not if they are the same. */ + if (!is_master && memcmp(auth->hashgx, hashbuf, 32) > 0) { + /* Ours wins. Ignore the message we received, and just + * resend the same D-H Commit message again. */ + free(encbuf); + encbuf = NULL; + } else { + /* Ours loses. Use the incoming parameters instead. */ + otrl_auth_clear(auth); + auth->protocol_version = version; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); + auth->our_keyid = 1; + auth->encgx = encbuf; + encbuf = NULL; + auth->encgx_len = enclen; + memmove(auth->hashgx, hashbuf, 32); + + /* Create a D-H Key Message */ + err = create_key_message(auth); + if (err) goto err; + auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG; + } + break; + case OTRL_AUTHSTATE_AWAITING_REVEALSIG: + /* Use the incoming parameters, but just retransmit the old + * D-H Key Message. */ + free(auth->encgx); + auth->encgx = encbuf; + encbuf = NULL; + auth->encgx_len = enclen; + memmove(auth->hashgx, hashbuf, 32); + break; + } + + return err; + +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + free(encbuf); + return err; +} + +/* + * Calculate the encrypted part of the Reveal Signature and Signature + * Messages, given a MAC key, an encryption key, two DH public keys, an + * authentication public key (contained in an OtrlPrivKey structure), + * and a keyid. If no error is returned, *authbufp will point to the + * result, and *authlenp will point to its length. + */ +static gcry_error_t calculate_pubkey_auth(unsigned char **authbufp, + size_t *authlenp, gcry_md_hd_t mackey, gcry_cipher_hd_t enckey, + gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub, + OtrlPrivKey *privkey, unsigned int keyid) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + const enum gcry_mpi_format format = GCRYMPI_FMT_USG; + size_t ourpublen, theirpublen, totallen, lenp; + unsigned char *buf = NULL, *bufp = NULL; + unsigned char macbuf[32]; + unsigned char *sigbuf = NULL; + size_t siglen; + + /* How big are the DH public keys? */ + gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub); + gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub); + + /* How big is the total structure to be MAC'd? */ + totallen = 4 + ourpublen + 4 + theirpublen + 2 + privkey->pubkey_datalen + + 4; + buf = malloc(totallen); + if (buf == NULL) goto memerr; + + bufp = buf; + lenp = totallen; + + /* Write the data to be MAC'd */ + write_mpi(our_dh_pub, ourpublen, "Our DH pubkey"); + write_mpi(their_dh_pub, theirpublen, "Their DH pubkey"); + bufp[0] = ((privkey->pubkey_type) >> 8) & 0xff; + bufp[1] = (privkey->pubkey_type) & 0xff; + bufp += 2; lenp -= 2; + memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen); + debug_data("Pubkey", bufp, privkey->pubkey_datalen); + bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen; + write_int(keyid); + debug_int("Keyid", bufp-4); + + assert(lenp == 0); + + /* Do the MAC */ + gcry_md_reset(mackey); + gcry_md_write(mackey, buf, totallen); + memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32); + + free(buf); + buf = NULL; + + /* Sign the MAC */ + err = otrl_privkey_sign(&sigbuf, &siglen, privkey, macbuf, 32); + if (err) goto err; + + /* Calculate the total size of the structure to be encrypted */ + totallen = 2 + privkey->pubkey_datalen + 4 + siglen; + buf = malloc(totallen); + if (buf == NULL) goto memerr; + bufp = buf; + lenp = totallen; + + /* Write the data to be encrypted */ + bufp[0] = ((privkey->pubkey_type) >> 8) & 0xff; + bufp[1] = (privkey->pubkey_type) & 0xff; + bufp += 2; lenp -= 2; + memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen); + debug_data("Pubkey", bufp, privkey->pubkey_datalen); + bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen; + write_int(keyid); + debug_int("Keyid", bufp-4); + memmove(bufp, sigbuf, siglen); + debug_data("Signature", bufp, siglen); + bufp += siglen; lenp -= siglen; + free(sigbuf); + sigbuf = NULL; + + assert(lenp == 0); + + /* Now do the encryption */ + err = gcry_cipher_encrypt(enckey, buf, totallen, NULL, 0); + if (err) goto err; + + *authbufp = buf; + buf = NULL; + *authlenp = totallen; + + return err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + free(sigbuf); + return err; +} + +/* + * Decrypt the authenticator in the Reveal Signature and Signature + * Messages, given a MAC key, and encryption key, and two DH public + * keys. The fingerprint of the received public key will get put into + * fingerprintbufp, and the received keyid will get put in *keyidp. + * The encrypted data pointed to by authbuf will be decrypted in place. + */ +static gcry_error_t check_pubkey_auth(unsigned char fingerprintbufp[20], + unsigned int *keyidp, unsigned char *authbuf, size_t authlen, + gcry_md_hd_t mackey, gcry_cipher_hd_t enckey, + gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + const enum gcry_mpi_format format = GCRYMPI_FMT_USG; + size_t ourpublen, theirpublen, totallen, lenp; + unsigned char *buf = NULL, *bufp = NULL; + unsigned char macbuf[32]; + unsigned short pubkey_type; + gcry_mpi_t p,q,g,y; + gcry_sexp_t pubs = NULL; + unsigned int received_keyid; + unsigned char *fingerprintstart, *fingerprintend, *sigbuf; + size_t siglen; + + /* Start by decrypting it */ + err = gcry_cipher_decrypt(enckey, authbuf, authlen, NULL, 0); + if (err) goto err; + + bufp = authbuf; + lenp = authlen; + + /* Get the public key and calculate its fingerprint */ + require_len(2); + pubkey_type = (bufp[0] << 8) + bufp[1]; + bufp += 2; lenp -= 2; + if (pubkey_type != OTRL_PUBKEY_TYPE_DSA) goto invval; + fingerprintstart = bufp; + read_mpi(p); + read_mpi(q); + read_mpi(g); + read_mpi(y); + fingerprintend = bufp; + gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbufp, + fingerprintstart, fingerprintend-fingerprintstart); + gcry_sexp_build(&pubs, NULL, + "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y); + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); + + /* Get the keyid */ + read_int(received_keyid); + if (received_keyid == 0) goto invval; + + /* Get the signature */ + sigbuf = bufp; + siglen = lenp; + + /* How big are the DH public keys? */ + gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub); + gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub); + + /* Now calculate the message to be MAC'd. */ + totallen = 4 + ourpublen + 4 + theirpublen + 2 + + (fingerprintend - fingerprintstart) + 4; + buf = malloc(totallen); + if (buf == NULL) goto memerr; + + bufp = buf; + lenp = totallen; + + write_mpi(their_dh_pub, theirpublen, "Their DH pubkey"); + write_mpi(our_dh_pub, ourpublen, "Our DH pubkey"); + bufp[0] = (pubkey_type >> 8) & 0xff; + bufp[1] = pubkey_type & 0xff; + bufp += 2; lenp -= 2; + memmove(bufp, fingerprintstart, fingerprintend - fingerprintstart); + debug_data("Pubkey", bufp, fingerprintend - fingerprintstart); + bufp += fingerprintend - fingerprintstart; + lenp -= fingerprintend - fingerprintstart; + write_int(received_keyid); + debug_int("Keyid", bufp-4); + + assert(lenp == 0); + + /* Do the MAC */ + gcry_md_reset(mackey); + gcry_md_write(mackey, buf, totallen); + memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32); + + free(buf); + buf = NULL; + + /* Verify the signature on the MAC */ + err = otrl_privkey_verify(sigbuf, siglen, pubkey_type, pubs, macbuf, 32); + if (err) goto err; + gcry_sexp_release(pubs); + pubs = NULL; + + /* Everything checked out */ + *keyidp = received_keyid; + + return err; +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + gcry_sexp_release(pubs); + return err; +} + +/* + * Create a Reveal Signature Message using the values in the given auth, + * and store it in auth->lastauthmsg. Use the given privkey to sign the + * message. + */ +static gcry_error_t create_revealsig_message(OtrlAuthInfo *auth, + OtrlPrivKey *privkey) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp, *startmac; + size_t buflen, lenp; + + unsigned char *authbuf = NULL; + size_t authlen; + + /* Get the encrypted authenticator */ + err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1, auth->enc_c, + auth->our_dh.pub, auth->their_pub, privkey, auth->our_keyid); + if (err) goto err; + + buflen = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4 + 16 + + 4 + authlen + 20; + buf = malloc(buflen); + if (buf == NULL) goto memerr; + + bufp = buf; + lenp = buflen; + + /* header */ + write_header(auth->protocol_version, '\x11'); + if (auth->protocol_version == 3) { + /* instance tags */ + write_int(auth->context->our_instance); + debug_int("Sender instag", bufp-4); + write_int(auth->context->their_instance); + debug_int("Recipient instag", bufp-4); + } + + /* r */ + write_int(16); + memmove(bufp, auth->r, 16); + debug_data("r", bufp, 16); + bufp += 16; lenp -= 16; + + /* Encrypted authenticator */ + startmac = bufp; + write_int(authlen); + memmove(bufp, authbuf, authlen); + debug_data("auth", bufp, authlen); + bufp += authlen; lenp -= authlen; + free(authbuf); + authbuf = NULL; + + /* MAC it, but only take the first 20 bytes */ + gcry_md_reset(auth->mac_m2); + gcry_md_write(auth->mac_m2, startmac, bufp - startmac); + memmove(bufp, gcry_md_read(auth->mac_m2, GCRY_MD_SHA256), 20); + debug_data("MAC", bufp, 20); + bufp += 20; lenp -= 20; + + assert(lenp == 0); + + free(auth->lastauthmsg); + auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); + if (auth->lastauthmsg == NULL) goto memerr; + free(buf); + buf = NULL; + + return err; + +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + free(authbuf); + return err; +} + +/* + * Create a Signature Message using the values in the given auth, and + * store it in auth->lastauthmsg. Use the given privkey to sign the + * message. + */ +static gcry_error_t create_signature_message(OtrlAuthInfo *auth, + OtrlPrivKey *privkey) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp, *startmac; + size_t buflen, lenp; + + unsigned char *authbuf = NULL; + size_t authlen; + + /* Get the encrypted authenticator */ + err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1p, + auth->enc_cp, auth->our_dh.pub, auth->their_pub, privkey, + auth->our_keyid); + if (err) goto err; + + buflen = OTRL_HEADER_LEN + (auth->protocol_version == 3 ? 8 : 0) + 4 + + authlen + 20; + buf = malloc(buflen); + if (buf == NULL) goto memerr; + + bufp = buf; + lenp = buflen; + + /* header */ + write_header(auth->protocol_version, '\x12'); + if (auth->protocol_version == 3) { + /* instance tags */ + write_int(auth->context->our_instance); + debug_int("Sender instag", bufp-4); + write_int(auth->context->their_instance); + debug_int("Recipient instag", bufp-4); + } + + /* Encrypted authenticator */ + startmac = bufp; + write_int(authlen); + memmove(bufp, authbuf, authlen); + debug_data("auth", bufp, authlen); + bufp += authlen; lenp -= authlen; + free(authbuf); + authbuf = NULL; + + /* MAC it, but only take the first 20 bytes */ + gcry_md_reset(auth->mac_m2p); + gcry_md_write(auth->mac_m2p, startmac, bufp - startmac); + memmove(bufp, gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256), 20); + debug_data("MAC", bufp, 20); + bufp += 20; lenp -= 20; + + assert(lenp == 0); + + free(auth->lastauthmsg); + auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); + if (auth->lastauthmsg == NULL) goto memerr; + free(buf); + buf = NULL; + + return err; + +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + free(authbuf); + return err; +} + +/* + * Handle an incoming D-H Key Message. If no error is returned, and + * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg. + * Use the given private authentication key to sign messages. + */ +gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg, + int *havemsgp, OtrlPrivKey *privkey) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp = NULL; + size_t buflen, lenp; + gcry_mpi_t incoming_pub = NULL; + int res; + unsigned int msg_version; + + *havemsgp = 0; + + msg_version = otrl_proto_message_version(keymsg); + + res = otrl_base64_otr_decode(keymsg, &buf, &buflen); + if (res == -1) goto memerr; + if (res == -2) goto invval; + + bufp = buf; + lenp = buflen; + + /* Header */ + skip_header('\x0a'); + + if (msg_version == 3) { + require_len(8); + bufp += 8; lenp -= 8; + } + + /* g^y */ + read_mpi(incoming_pub); + + if (lenp != 0) goto invval; + free(buf); + buf = NULL; + + switch(auth->authstate) { + case OTRL_AUTHSTATE_AWAITING_DHKEY: + /* The other party may also be establishing a session with + another instance running a different version. Ignore any + DHKEY messages we aren't expecting. */ + if (msg_version != auth->protocol_version) { + goto err; + } + + /* Store the incoming public key */ + gcry_mpi_release(auth->their_pub); + auth->their_pub = incoming_pub; + incoming_pub = NULL; + + /* Compute the encryption and MAC keys */ + err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh), + auth->their_pub, auth->secure_session_id, + &(auth->secure_session_id_len), + &(auth->enc_c), &(auth->enc_cp), + &(auth->mac_m1), &(auth->mac_m1p), + &(auth->mac_m2), &(auth->mac_m2p)); + if (err) goto err; + + /* Create the Reveal Signature Message */ + err = create_revealsig_message(auth, privkey); + if (err) goto err; + *havemsgp = 1; + auth->authstate = OTRL_AUTHSTATE_AWAITING_SIG; + + break; + + case OTRL_AUTHSTATE_AWAITING_SIG: + if (gcry_mpi_cmp(incoming_pub, auth->their_pub) == 0) { + /* Retransmit the Reveal Signature Message */ + *havemsgp = 1; + } else { + /* Ignore this message */ + *havemsgp = 0; + } + break; + case OTRL_AUTHSTATE_NONE: + case OTRL_AUTHSTATE_AWAITING_REVEALSIG: + case OTRL_AUTHSTATE_V1_SETUP: + /* Ignore this message */ + *havemsgp = 0; + break; + } + + gcry_mpi_release(incoming_pub); + return err; + +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + gcry_mpi_release(incoming_pub); + return err; +} + +/* + * Handle an incoming Reveal Signature Message. If no error is + * returned, and *havemsgp is 1, the message to be sent will be left in + * auth->lastauthmsg. Use the given private authentication key to sign + * messages. Call the auth_succeeded callback if authentication is + * successful. + */ +gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth, + const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey, + gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), + void *asdata) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp = NULL, *gxbuf = NULL; + unsigned char *authstart, *authend, *macstart; + size_t buflen, lenp, rlen, authlen; + gcry_cipher_hd_t enc = NULL; + gcry_mpi_t incoming_pub = NULL; + unsigned char ctr[16], hashbuf[32]; + int res; + unsigned char version; + + *havemsgp = 0; + + res = otrl_base64_otr_decode(revealmsg, &buf, &buflen); + if (res == -1) goto memerr; + if (res == -2) goto invval; + + bufp = buf; + lenp = buflen; + + require_len(3); + version = bufp[1]; + + /* Header */ + skip_header('\x11'); + + if (version == 3) { + require_len(8); + bufp += 8; lenp -= 8; + } + + /* r */ + read_int(rlen); + if (rlen != 16) goto invval; + require_len(rlen); + memmove(auth->r, bufp, rlen); + bufp += rlen; lenp -= rlen; + + /* auth */ + authstart = bufp; + read_int(authlen); + require_len(authlen); + bufp += authlen; lenp -= authlen; + authend = bufp; + + /* MAC */ + require_len(20); + macstart = bufp; + bufp += 20; lenp -= 20; + + if (lenp != 0) goto invval; + + switch(auth->authstate) { + case OTRL_AUTHSTATE_AWAITING_REVEALSIG: + gxbuf = malloc(auth->encgx_len); + if (auth->encgx_len && gxbuf == NULL) goto memerr; + + /* Use r to decrypt the value of g^x we received earlier */ + err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + GCRY_CIPHER_SECURE); + if (err) goto err; + + err = gcry_cipher_setkey(enc, auth->r, 16); + if (err) goto err; + + memset(ctr, 0, 16); + err = gcry_cipher_setctr(enc, ctr, 16); + if (err) goto err; + + err = gcry_cipher_decrypt(enc, gxbuf, auth->encgx_len, + auth->encgx, auth->encgx_len); + if (err) goto err; + + gcry_cipher_close(enc); + enc = NULL; + + /* Check the hash */ + gcry_md_hash_buffer(GCRY_MD_SHA256, hashbuf, gxbuf, + auth->encgx_len); + /* This isn't comparing secret data, but may as well use the + * constant-time version. */ + if (otrl_mem_differ(hashbuf, auth->hashgx, 32)) goto decfail; + + /* Extract g^x */ + bufp = gxbuf; + lenp = auth->encgx_len; + + read_mpi(incoming_pub); + free(gxbuf); + gxbuf = NULL; + + if (lenp != 0) goto invval; + + gcry_mpi_release(auth->their_pub); + auth->their_pub = incoming_pub; + incoming_pub = NULL; + + /* Compute the encryption and MAC keys */ + err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh), + auth->their_pub, auth->secure_session_id, + &(auth->secure_session_id_len), + &(auth->enc_c), &(auth->enc_cp), + &(auth->mac_m1), &(auth->mac_m1p), + &(auth->mac_m2), &(auth->mac_m2p)); + if (err) goto err; + + /* Check the MAC */ + gcry_md_reset(auth->mac_m2); + gcry_md_write(auth->mac_m2, authstart, authend - authstart); + + if (otrl_mem_differ(macstart, + gcry_md_read(auth->mac_m2, GCRY_MD_SHA256), + 20)) goto invval; + + /* Check the auth */ + err = check_pubkey_auth(auth->their_fingerprint, + &(auth->their_keyid), authstart + 4, + authend - authstart - 4, auth->mac_m1, auth->enc_c, + auth->our_dh.pub, auth->their_pub); + if (err) goto err; + + authstart = NULL; + authend = NULL; + macstart = NULL; + free(buf); + buf = NULL; + + /* Create the Signature Message */ + err = create_signature_message(auth, privkey); + if (err) goto err; + + /* No error? Then we've completed our end of the + * authentication. */ + auth->session_id_half = OTRL_SESSIONID_SECOND_HALF_BOLD; + if (auth_succeeded) err = auth_succeeded(auth, asdata); + *havemsgp = 1; + auth->our_keyid = 0; + auth->authstate = OTRL_AUTHSTATE_NONE; + + break; + case OTRL_AUTHSTATE_NONE: + case OTRL_AUTHSTATE_AWAITING_DHKEY: + case OTRL_AUTHSTATE_AWAITING_SIG: + case OTRL_AUTHSTATE_V1_SETUP: + /* Ignore this message */ + *havemsgp = 0; + free(buf); + buf = NULL; + break; + } + + return err; + +decfail: + err = gcry_error(GPG_ERR_NO_ERROR); + goto err; +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + free(gxbuf); + gcry_cipher_close(enc); + gcry_mpi_release(incoming_pub); + return err; +} + +/* + * Handle an incoming Signature Message. If no error is returned, and + * *havemsgp is 1, the message to be sent will be left in + * auth->lastauthmsg. Call the auth_succeeded callback if + * authentication is successful. + */ +gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth, + const char *sigmsg, int *havemsgp, + gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), + void *asdata) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp = NULL; + unsigned char *authstart, *authend, *macstart; + size_t buflen, lenp, authlen; + int res; + unsigned char version; + + *havemsgp = 0; + + res = otrl_base64_otr_decode(sigmsg, &buf, &buflen); + if (res == -1) goto memerr; + if (res == -2) goto invval; + + bufp = buf; + lenp = buflen; + + require_len(3); + version = bufp[1]; + + /* Header */ + skip_header('\x12'); + + if (version == 3) { + require_len(8); + bufp += 8; lenp -= 8; + } + + /* auth */ + authstart = bufp; + read_int(authlen); + require_len(authlen); + bufp += authlen; lenp -= authlen; + authend = bufp; + + /* MAC */ + require_len(20); + macstart = bufp; + bufp += 20; lenp -= 20; + + if (lenp != 0) goto invval; + + switch(auth->authstate) { + case OTRL_AUTHSTATE_AWAITING_SIG: + /* Check the MAC */ + gcry_md_reset(auth->mac_m2p); + gcry_md_write(auth->mac_m2p, authstart, authend - authstart); + if (otrl_mem_differ(macstart, + gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256), + 20)) goto invval; + + /* Check the auth */ + err = check_pubkey_auth(auth->their_fingerprint, + &(auth->their_keyid), authstart + 4, + authend - authstart - 4, auth->mac_m1p, auth->enc_cp, + auth->our_dh.pub, auth->their_pub); + if (err) goto err; + + authstart = NULL; + authend = NULL; + macstart = NULL; + free(buf); + buf = NULL; + + /* No error? Then we've completed our end of the + * authentication. */ + auth->session_id_half = OTRL_SESSIONID_FIRST_HALF_BOLD; + if (auth_succeeded) err = auth_succeeded(auth, asdata); + free(auth->lastauthmsg); + auth->lastauthmsg = NULL; + *havemsgp = 0; + auth->our_keyid = 0; + auth->authstate = OTRL_AUTHSTATE_NONE; + + break; + case OTRL_AUTHSTATE_NONE: + case OTRL_AUTHSTATE_AWAITING_DHKEY: + case OTRL_AUTHSTATE_AWAITING_REVEALSIG: + case OTRL_AUTHSTATE_V1_SETUP: + /* Ignore this message */ + *havemsgp = 0; + free(buf); + buf = NULL; + break; + } + + return err; + +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + return err; +} + +/* Version 1 routines, for compatibility */ + +/* + * Create a verion 1 Key Exchange Message using the values in the given + * auth, and store it in auth->lastauthmsg. Set the Reply field to the + * given value, and use the given privkey to sign the message. + */ +static gcry_error_t create_v1_key_exchange_message(OtrlAuthInfo *auth, + unsigned char reply, OtrlPrivKey *privkey) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + const enum gcry_mpi_format format = GCRYMPI_FMT_USG; + unsigned char *buf = NULL, *bufp = NULL, *sigbuf = NULL; + size_t lenp, ourpublen, totallen, siglen; + unsigned char hashbuf[20]; + + if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) { + return gpg_error(GPG_ERR_INV_VALUE); + } + + /* How big is the DH public key? */ + gcry_mpi_print(format, NULL, 0, &ourpublen, auth->our_dh.pub); + + totallen = 3 + 1 + privkey->pubkey_datalen + 4 + 4 + ourpublen + 40; + buf = malloc(totallen); + if (buf == NULL) goto memerr; + + bufp = buf; + lenp = totallen; + + memmove(bufp, "\x00\x01\x0a", 3); /* header */ + debug_data("Header", bufp, 3); + bufp += 3; lenp -= 3; + + bufp[0] = reply; + debug_data("Reply", bufp, 1); + bufp += 1; lenp -= 1; + + memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen); + debug_data("Pubkey", bufp, privkey->pubkey_datalen); + bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen; + + write_int(auth->our_keyid); + debug_int("Keyid", bufp-4); + + write_mpi(auth->our_dh.pub, ourpublen, "D-H y"); + + /* Hash all the data written so far, and sign the hash */ + gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf); + + err = otrl_privkey_sign(&sigbuf, &siglen, privkey, hashbuf, 20); + if (err) goto err; + + if (siglen != 40) goto invval; + memmove(bufp, sigbuf, 40); + debug_data("Signature", bufp, 40); + bufp += 40; lenp -= 40; + free(sigbuf); + sigbuf = NULL; + + assert(lenp == 0); + + free(auth->lastauthmsg); + auth->lastauthmsg = otrl_base64_otr_encode(buf, totallen); + if (auth->lastauthmsg == NULL) goto memerr; + free(buf); + buf = NULL; + + return err; + +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + free(sigbuf); + return err; +} + +/* + * Start a fresh AKE (version 1) using the given OtrlAuthInfo. If + * our_dh is NULL, generate a fresh DH keypair to use. Otherwise, use a + * copy of the one passed (with the given keyid). Use the given private + * key to sign the message. If no error is returned, the message to + * transmit will be contained in auth->lastauthmsg. + */ +gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh, + unsigned int our_keyid, OtrlPrivKey *privkey) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + + /* Clear out this OtrlAuthInfo and start over */ + otrl_auth_clear(auth); + auth->initiated = 1; + auth->protocol_version = 1; + + /* Import the given DH keypair, or else create a fresh one */ + if (our_dh) { + otrl_dh_keypair_copy(&(auth->our_dh), our_dh); + auth->our_keyid = our_keyid; + } else { + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); + auth->our_keyid = 1; + } + + err = create_v1_key_exchange_message(auth, 0, privkey); + if (!err) { + auth->authstate = OTRL_AUTHSTATE_V1_SETUP; + } + + return err; +} + +/* + * Handle an incoming v1 Key Exchange Message. If no error is returned, + * and *havemsgp is 1, the message to be sent will be left in + * auth->lastauthmsg. Use the given private authentication key to sign + * messages. Call the auth_secceeded callback if authentication is + * successful. If non-NULL, use a copy of the given D-H keypair, with + * the given keyid. + */ +gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth, + const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey, + DH_keypair *our_dh, unsigned int our_keyid, + gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), + void *asdata) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + unsigned char *buf = NULL, *bufp = NULL; + unsigned char *fingerprintstart, *fingerprintend; + unsigned char fingerprintbuf[20], hashbuf[20]; + gcry_mpi_t p, q, g, y, received_pub = NULL; + gcry_sexp_t pubs = NULL; + size_t buflen, lenp; + unsigned char received_reply; + unsigned int received_keyid; + int res; + + *havemsgp = 0; + + res = otrl_base64_otr_decode(keyexchmsg, &buf, &buflen); + if (res == -1) goto memerr; + if (res == -2) goto invval; + + bufp = buf; + lenp = buflen; + + /* Header */ + require_len(3); + if (memcmp(bufp, "\x00\x01\x0a", 3)) goto invval; + bufp += 3; lenp -= 3; + + /* Reply */ + require_len(1); + received_reply = bufp[0]; + bufp += 1; lenp -= 1; + + /* Public Key */ + fingerprintstart = bufp; + read_mpi(p); + read_mpi(q); + read_mpi(g); + read_mpi(y); + fingerprintend = bufp; + gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbuf, + fingerprintstart, fingerprintend-fingerprintstart); + gcry_sexp_build(&pubs, NULL, + "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y); + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); + + /* keyid */ + read_int(received_keyid); + if (received_keyid == 0) goto invval; + + /* D-H pubkey */ + read_mpi(received_pub); + + /* Verify the signature */ + if (lenp != 40) goto invval; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf); + err = otrl_privkey_verify(bufp, lenp, OTRL_PUBKEY_TYPE_DSA, + pubs, hashbuf, 20); + if (err) goto err; + gcry_sexp_release(pubs); + pubs = NULL; + free(buf); + buf = NULL; + + if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP && received_reply == 0x01) { + /* They're replying to something we never sent. We must be + * logged in more than once; ignore the message. */ + err = gpg_error(GPG_ERR_NO_ERROR); + goto err; + } + + if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP) { + /* Clear the auth and start over */ + otrl_auth_clear(auth); + } + + /* Everything checked out */ + auth->their_keyid = received_keyid; + gcry_mpi_release(auth->their_pub); + auth->their_pub = received_pub; + received_pub = NULL; + memmove(auth->their_fingerprint, fingerprintbuf, 20); + + if (received_reply == 0x01) { + /* Don't send a reply to this. */ + *havemsgp = 0; + } else { + /* Import the given DH keypair, or else create a fresh one */ + if (our_dh) { + otrl_dh_keypair_copy(&(auth->our_dh), our_dh); + auth->our_keyid = our_keyid; + } else if (auth->our_keyid == 0) { + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); + auth->our_keyid = 1; + } + + /* Reply with our own Key Exchange Message */ + err = create_v1_key_exchange_message(auth, 1, privkey); + if (err) goto err; + *havemsgp = 1; + } + + /* Compute the session id */ + err = otrl_dh_compute_v1_session_id(&(auth->our_dh), + auth->their_pub, auth->secure_session_id, + &(auth->secure_session_id_len), + &(auth->session_id_half)); + if (err) goto err; + + /* We've completed our end of the authentication */ + auth->protocol_version = 1; + if (auth_succeeded) err = auth_succeeded(auth, asdata); + auth->our_keyid = 0; + auth->authstate = OTRL_AUTHSTATE_NONE; + + return err; + +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +memerr: + err = gcry_error(GPG_ERR_ENOMEM); +err: + free(buf); + gcry_sexp_release(pubs); + gcry_mpi_release(received_pub); + return err; +} + +/* + * Copy relevant information from the master OtrlAuthInfo to an + * instance OtrlAuthInfo in response to a D-H Key with a new + * instance. The fields copied will depend on the state of the + * master auth. + */ +void otrl_auth_copy_on_key(OtrlAuthInfo *m_auth, OtrlAuthInfo *auth) +{ + switch(m_auth->authstate) { + case OTRL_AUTHSTATE_AWAITING_DHKEY: + case OTRL_AUTHSTATE_AWAITING_SIG: + /* Copy our D-H Commit information to the new instance */ + otrl_dh_keypair_free(&(auth->our_dh)); + auth->initiated = m_auth->initiated; + otrl_dh_keypair_copy(&(auth->our_dh), &(m_auth->our_dh)); + auth->our_keyid = m_auth->our_keyid; + memmove(auth->r, m_auth->r, 16); + if (auth->encgx) free(auth->encgx); + auth->encgx = malloc(m_auth->encgx_len); + memmove(auth->encgx, m_auth->encgx, m_auth->encgx_len); + memmove(auth->hashgx, m_auth->hashgx, 32); + + auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY; + break; + + default: + /* This bad state will be detected and handled later */ + break; + } +} + +#ifdef OTRL_TESTING_AUTH +#include "mem.h" +#include "privkey.h" + +#define CHECK_ERR if (err) { printf("Error: %s\n", gcry_strerror(err)); \ + return 1; } + +static gcry_error_t starting(const OtrlAuthInfo *auth, void *asdata) +{ + char *name = asdata; + + fprintf(stderr, "\nStarting ENCRYPTED mode for %s (v%d).\n", + name, auth->protocol_version); + + fprintf(stderr, "\nour_dh (%d):", auth->our_keyid); + gcry_mpi_dump(auth->our_dh.pub); + fprintf(stderr, "\ntheir_pub (%d):", auth->their_keyid); + gcry_mpi_dump(auth->their_pub); + + debug_data("\nTheir fingerprint", auth->their_fingerprint, 20); + debug_data("\nSecure session id", auth->secure_session_id, + auth->secure_session_id_len); + fprintf(stderr, "Sessionid half: %d\n\n", auth->session_id_half); + + return gpg_error(GPG_ERR_NO_ERROR); +} + +int main(int argc, char **argv) +{ + OtrlAuthInfo alice, bob; + gcry_error_t err; + int havemsg; + OtrlUserState us; + OtrlPrivKey *alicepriv, *bobpriv; + + otrl_mem_init(); + otrl_dh_init(); + otrl_auth_new(&alice); + otrl_auth_new(&bob); + + us = otrl_userstate_create(); + otrl_privkey_read(us, "/home/iang/.gaim/otr.private_key"); + alicepriv = otrl_privkey_find(us, "oneeyedian", "prpl-oscar"); + bobpriv = otrl_privkey_find(us, "otr4ian", "prpl-oscar"); + + printf("\n\n ***** V2 *****\n\n"); + + err = otrl_auth_start_v23(&bob, NULL, 0); + CHECK_ERR + printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); + err = otrl_auth_handle_commit(&alice, bob.lastauthmsg, NULL, 0); + CHECK_ERR + printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg); + err = otrl_auth_handle_key(&bob, alice.lastauthmsg, &havemsg, bobpriv); + CHECK_ERR + if (havemsg) { + printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); + } else { + printf("\nIGNORE\n\n"); + } + err = otrl_auth_handle_revealsig(&alice, bob.lastauthmsg, &havemsg, + alicepriv, starting, "Alice"); + CHECK_ERR + if (havemsg) { + printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), + alice.lastauthmsg); + } else { + printf("\nIGNORE\n\n"); + } + err = otrl_auth_handle_signature(&bob, alice.lastauthmsg, &havemsg, + starting, "Bob"); + CHECK_ERR + + printf("\n\n ***** V1 *****\n\n"); + + err = otrl_auth_start_v1(&bob, NULL, 0, bobpriv); + CHECK_ERR + printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); + err = otrl_auth_handle_v1_key_exchange(&alice, bob.lastauthmsg, + &havemsg, alicepriv, NULL, 0, starting, "Alice"); + CHECK_ERR + if (havemsg) { + printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), + alice.lastauthmsg); + } else { + printf("\nIGNORE\n\n"); + } + err = otrl_auth_handle_v1_key_exchange(&bob, alice.lastauthmsg, + &havemsg, bobpriv, NULL, 0, starting, "Bob"); + CHECK_ERR + if (havemsg) { + printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); + } else { + printf("\nIGNORE\n\n"); + } + + otrl_userstate_free(us); + otrl_auth_clear(&alice); + otrl_auth_clear(&bob); + return 0; +} +#endif diff --git a/comm/third_party/libotr/src/auth.h b/comm/third_party/libotr/src/auth.h new file mode 100644 index 0000000000..0b9db544aa --- /dev/null +++ b/comm/third_party/libotr/src/auth.h @@ -0,0 +1,177 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __AUTH_H__ +#define __AUTH_H__ + +#include +#include +#include "dh.h" + + +typedef enum { + OTRL_AUTHSTATE_NONE, + OTRL_AUTHSTATE_AWAITING_DHKEY, + OTRL_AUTHSTATE_AWAITING_REVEALSIG, + OTRL_AUTHSTATE_AWAITING_SIG, + OTRL_AUTHSTATE_V1_SETUP +} OtrlAuthState; + +typedef struct { + OtrlAuthState authstate; /* Our state */ + + struct context *context; /* The context which points to us */ + + DH_keypair our_dh; /* Our D-H key */ + unsigned int our_keyid; /* ...and its keyid */ + + unsigned char *encgx; /* The encrypted value of g^x */ + size_t encgx_len; /* ...and its length */ + unsigned char r[16]; /* The encryption key */ + + unsigned char hashgx[32]; /* SHA256(g^x) */ + + gcry_mpi_t their_pub; /* Their D-H public key */ + unsigned int their_keyid; /* ...and its keyid */ + + + gcry_cipher_hd_t enc_c, enc_cp; /* c and c' encryption keys */ + gcry_md_hd_t mac_m1, mac_m1p; /* m1 and m1' MAC keys */ + gcry_md_hd_t mac_m2, mac_m2p; /* m2 and m2' MAC keys */ + + unsigned char their_fingerprint[20]; /* The fingerprint of their + long-term signing key */ + + int initiated; /* Did we initiate this + authentication? */ + + unsigned int protocol_version; /* The protocol version number + used to authenticate. */ + + unsigned char secure_session_id[20]; /* The secure session id */ + size_t secure_session_id_len; /* And its actual length, + which may be either 20 (for + v1) or 8 (for v2) */ + OtrlSessionIdHalf session_id_half; /* Which half of the session + id gets shown in bold */ + + char *lastauthmsg; /* The last auth message + (base-64 encoded) we sent, + in case we need to + retransmit it. */ + + time_t commit_sent_time; /* The time we last sent the + lastauthmsg, if it was a + COMMIT message, and this is + a master context. 0 + otherwise. */ +} OtrlAuthInfo; + +#include "privkey-t.h" + +/* + * Initialize the fields of an OtrlAuthInfo (already allocated). + */ +void otrl_auth_new(struct context *context); + +/* + * Clear the fields of an OtrlAuthInfo (but leave it allocated). + */ +void otrl_auth_clear(OtrlAuthInfo *auth); + +/* + * Start a fresh AKE (version 2 or 3) using the given OtrlAuthInfo. Generate + * a fresh DH keypair to use. If no error is returned, the message to + * transmit will be contained in auth->lastauthmsg. + */ +gcry_error_t otrl_auth_start_v23(OtrlAuthInfo *auth, int version); + +/* + * Handle an incoming D-H Commit Message. If no error is returned, the + * message to send will be left in auth->lastauthmsg. Generate a fresh + * keypair to use. + */ +gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth, + const char *commitmsg, int version); + +/* + * Handle an incoming D-H Key Message. If no error is returned, and + * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg. + * Use the given private authentication key to sign messages. + */ +gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg, + int *havemsgp, OtrlPrivKey *privkey); + +/* + * Handle an incoming Reveal Signature Message. If no error is + * returned, and *havemsgp is 1, the message to be sent will be left in + * auth->lastauthmsg. Use the given private authentication key to sign + * messages. Call the auth_succeeded callback if authentication is + * successful. + */ +gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth, + const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey, + gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), + void *asdata); + +/* + * Handle an incoming Signature Message. If no error is returned, and + * *havemsgp is 1, the message to be sent will be left in + * auth->lastauthmsg. Call the auth_succeeded callback if + * authentication is successful. + */ +gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth, + const char *sigmsg, int *havemsgp, + gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), + void *asdata); + +/* + * Start a fresh AKE (version 1) using the given OtrlAuthInfo. If + * our_dh is NULL, generate a fresh DH keypair to use. Otherwise, use a + * copy of the one passed (with the given keyid). Use the given private + * key to sign the message. If no error is returned, the message to + * transmit will be contained in auth->lastauthmsg. + */ +gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh, + unsigned int our_keyid, OtrlPrivKey *privkey); + +/* + * Handle an incoming v1 Key Exchange Message. If no error is returned, + * and *havemsgp is 1, the message to be sent will be left in + * auth->lastauthmsg. Use the given private authentication key to sign + * messages. Call the auth_secceeded callback if authentication is + * successful. If non-NULL, use a copy of the given D-H keypair, with + * the given keyid. + */ +gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth, + const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey, + DH_keypair *our_dh, unsigned int our_keyid, + gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), + void *asdata); + +/* + * Copy relevant information from the master OtrlAuthInfo to an + * instance OtrlAuthInfo in response to a D-H Key with a new + * instance. The fields copied will depend on the state of the + * master auth. + */ +void otrl_auth_copy_on_key(OtrlAuthInfo *m_auth, OtrlAuthInfo *auth); + +#endif diff --git a/comm/third_party/libotr/src/b64.c b/comm/third_party/libotr/src/b64.c new file mode 100644 index 0000000000..a7d53aa2b1 --- /dev/null +++ b/comm/third_party/libotr/src/b64.c @@ -0,0 +1,267 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Modified from: */ + +/*********************************************************************\ + +MODULE NAME: b64.c + +AUTHOR: Bob Trower 08/04/01 + +LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall + be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +VERSION HISTORY: + Bob Trower 08/04/01 -- Create Version 0.00.00B + +\******************************************************************* */ + +/* system headers */ +#include +#include + +/* libotr headers */ +#include "b64.h" + +/* +** Translation Table as described in RFC1113 +*/ +static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* +** Translation Table to decode (created by author) +*/ +static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +/* +** encodeblock +** +** encode up to 3 8-bit binary bytes as 4 '6-bit' characters. +** len must be 1, 2, or 3. +*/ +static void encodeblock( char *out, const unsigned char *in, size_t len ) +{ + unsigned char in0, in1, in2; + in0 = in[0]; + in1 = len > 1 ? in[1] : 0; + in2 = len > 2 ? in[2] : 0; + + out[0] = cb64[ in0 >> 2 ]; + out[1] = cb64[ ((in0 & 0x03) << 4) | ((in1 & 0xf0) >> 4) ]; + out[2] = len > 1 ? cb64[ ((in1 & 0x0f) << 2) | ((in2 & 0xc0) >> 6) ] + : '='; + out[3] = len > 2 ? cb64[ in2 & 0x3f ] + : '='; +} + +/* + * base64 encode data. Insert no linebreaks or whitespace. + * + * The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of + * space. This function will return the number of bytes actually used. + */ +size_t otrl_base64_encode(char *base64data, const unsigned char *data, + size_t datalen) +{ + size_t base64len = 0; + + while(datalen > 2) { + encodeblock(base64data, data, 3); + base64data += 4; + base64len += 4; + data += 3; + datalen -= 3; + } + if (datalen > 0) { + encodeblock(base64data, data, datalen); + base64len += 4; + } + + return base64len; +} + +static size_t decode(unsigned char *out, const char *in, size_t b64len) +{ + size_t written = 0; + unsigned char c = 0; + + if (b64len > 0) { + c = in[0] << 2; + } + if (b64len > 1) { + out[0] = c | in[1] >> 4; + written = 1; + c = in[1] << 4; + } + if (b64len > 2) { + out[1] = c | in[2] >> 2; + written = 2; + c = in[2] << 6; + } + if (b64len > 3) { + out[2] = c | in[3]; + written = 3; + } + return written; +} + +/* + * base64 decode data. Skip non-base64 chars, and terminate at the + * first '=', or the end of the buffer. + * + * The buffer data must contain at least ((base64len+3) / 4) * 3 bytes + * of space. This function will return the number of bytes actually + * used. + */ +size_t otrl_base64_decode(unsigned char *data, const char *base64data, + size_t base64len) +{ + size_t datalen = 0; + char b64[4]; + size_t b64accum = 0; + + while(base64len > 0) { + char b = *base64data; + unsigned char bdecode; + ++base64data; + --base64len; + if (b < '+' || b > 'z') continue; /* Skip non-base64 chars */ + if (b == '=') { + /* Force termination */ + datalen += decode(data, b64, b64accum); + base64len = 0; + } else { + bdecode = cd64[b-'+']; + if (bdecode == '$') continue; /* Skip non-base64 chars */ + b64[b64accum++] = bdecode-'>'; + if (b64accum == 4) { + /* We have a complete block; decode it. */ + size_t written = decode(data, b64, b64accum); + data += written; + datalen += written; + b64accum = 0; + } + } + } + + /* Just discard any short block at the end. */ + + return datalen; +} + +/* + * Base64-encode a block of data, stick "?OTR:" and "." around it, and + * return the result, or NULL in the event of a memory error. The + * caller must free() the return value. + */ +char *otrl_base64_otr_encode(const unsigned char *buf, size_t buflen) +{ + char *base64buf; + size_t base64len; + const size_t HALF_MAX_SIZE_T = ((size_t)-1) >> 1; + + if (buflen > HALF_MAX_SIZE_T) { + /* You somehow have a buffer that's of size more than half of + * all addressable memory, and you now want a base64 version in + * a new buffer 33% larger? Not going to happen. Exit now, + * rather in the malloc below, to avoid integer overflowing the + * computation of base64len. */ + return NULL; + } + + /* Make the base64-encoding. */ + base64len = ((buflen + 2) / 3) * 4; + base64buf = malloc(5 + base64len + 1 + 1); + if (base64buf == NULL) { + return NULL; + } + memmove(base64buf, "?OTR:", 5); + otrl_base64_encode(base64buf+5, buf, buflen); + base64buf[5 + base64len] = '.'; + base64buf[5 + base64len + 1] = '\0'; + + return base64buf; +} + +/* + * Base64-decode the portion of the given message between "?OTR:" and + * ".". Set *bufp to the decoded data, and set *lenp to its length. + * The caller must free() the result. Return 0 on success, -1 on a + * memory error, or -2 on invalid input. + */ +int otrl_base64_otr_decode(const char *msg, unsigned char **bufp, + size_t *lenp) +{ + char *otrtag, *endtag; + size_t msglen, rawlen; + unsigned char *rawmsg; + + otrtag = strstr(msg, "?OTR:"); + if (!otrtag) { + return -2; + } + + endtag = strchr(otrtag, '.'); + if (endtag) { + msglen = endtag-otrtag; + } else { + return -2; + } + + /* Skip over the "?OTR:" */ + otrtag += 5; + msglen -= 5; + + /* Base64-decode the message */ + rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen); /* maximum possible */ + rawmsg = malloc(rawlen); + if (!rawmsg && rawlen > 0) { + return -1; + } + + rawlen = otrl_base64_decode(rawmsg, otrtag, msglen); /* actual size */ + + *bufp = rawmsg; + *lenp = rawlen; + + return 0; +} diff --git a/comm/third_party/libotr/src/b64.h b/comm/third_party/libotr/src/b64.h new file mode 100644 index 0000000000..bdd584a45e --- /dev/null +++ b/comm/third_party/libotr/src/b64.h @@ -0,0 +1,72 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __B64_H__ +#define __B64_H__ + +#include + +/* Base64 encodes blocks of this many bytes: */ +#define OTRL_B64_DECODED_LEN 3 +/* into blocks of this many bytes: */ +#define OTRL_B64_ENCODED_LEN 4 + +/* An encoded block of length encoded_len can turn into a maximum of + * this many decoded bytes: */ +#define OTRL_B64_MAX_DECODED_SIZE(encoded_len) \ + (((encoded_len + OTRL_B64_ENCODED_LEN - 1) / OTRL_B64_ENCODED_LEN) \ + * OTRL_B64_DECODED_LEN) + +/* + * base64 encode data. Insert no linebreaks or whitespace. + * + * The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of + * space. This function will return the number of bytes actually used. + */ +size_t otrl_base64_encode(char *base64data, const unsigned char *data, + size_t datalen); + +/* + * base64 decode data. Skip non-base64 chars, and terminate at the + * first '=', or the end of the buffer. + * + * The buffer data must contain at least ((base64len+3) / 4) * 3 bytes + * of space. This function will return the number of bytes actually + * used. + */ +size_t otrl_base64_decode(unsigned char *data, const char *base64data, + size_t base64len); + +/* + * Base64-encode a block of data, stick "?OTR:" and "." around it, and + * return the result, or NULL in the event of a memory error. + */ +char *otrl_base64_otr_encode(const unsigned char *buf, size_t buflen); + +/* + * Base64-decode the portion of the given message between "?OTR:" and + * ".". Set *bufp to the decoded data, and set *lenp to its length. + * The caller must free() the result. Return 0 on success, -1 on a + * memory error, or -2 on invalid input. + */ +int otrl_base64_otr_decode(const char *msg, unsigned char **bufp, + size_t *lenp); + +#endif diff --git a/comm/third_party/libotr/src/context.c b/comm/third_party/libotr/src/context.c new file mode 100644 index 0000000000..44d8b860f7 --- /dev/null +++ b/comm/third_party/libotr/src/context.c @@ -0,0 +1,547 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "context.h" +#include "instag.h" + +#if OTRL_DEBUGGING +#include + +void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth); +void otrl_sm_dump(FILE *f, const OtrlSMState *sm); + +/* Dump the contents of a context to the FILE *f. */ +void otrl_context_dump(FILE *f, const ConnContext *context) +{ + const Fingerprint *fing; + + fprintf(f, "Context %p:\n\n", context); + + fprintf(f, " Username: %s\n", context->username); + fprintf(f, " Accountname: %s\n", context->accountname); + fprintf(f, " Protocol: %s\n\n", context->protocol); + fprintf(f, " Master context: %p%s\n", context->m_context, + context->m_context == context ? " IS MASTER" : ""); + fprintf(f, " Recent recv child: %p\n", context->recent_rcvd_child); + fprintf(f, " Recent sent child: %p\n", context->recent_sent_child); + fprintf(f, " Recent child: %p\n\n", context->recent_child); + fprintf(f, " Our instance: %08x\n", context->our_instance); + fprintf(f, " Their instance: %08x\n\n", context->their_instance); + fprintf(f, " Msgstate: %d (%s)\n\n", context->msgstate, + context->msgstate == OTRL_MSGSTATE_PLAINTEXT ? "PLAINTEXT" : + context->msgstate == OTRL_MSGSTATE_ENCRYPTED ? "ENCRYPTED" : + context->msgstate == OTRL_MSGSTATE_FINISHED ? "FINISHED" : + "INVALID"); + otrl_auth_dump(f, &context->auth); + fprintf(f, "\n Fingerprints:\n"); + for (fing = context->fingerprint_root.next; fing; fing = fing->next) { + fprintf(f, " %p ", fing); + if (fing->fingerprint == NULL) { + fprintf(f, "(null)"); + } else { + int i; + for (i=0;i<20;++i) { + fprintf(f, "%02x", fing->fingerprint[i]); + } + } + fprintf(f, " %p", fing->context); + if (fing->trust && fing->trust[0]) { + fprintf(f, " %s", fing->trust); + } + fprintf(f, "\n"); + } + fprintf(f, "\n Active fingerprint: %p\n\n", context->active_fingerprint); + fprintf(f, " Protocol version: %d\n", context->protocol_version); + fprintf(f, " OTR offer: %d (%s)\n\n", context->otr_offer, + context->otr_offer == OFFER_NOT ? "NOT" : + context->otr_offer == OFFER_SENT ? "SENT" : + context->otr_offer == OFFER_REJECTED ? "REJECTED" : + context->otr_offer == OFFER_ACCEPTED ? "ACCEPTED" : + "INVALID"); + + fprintf(f, " Application data: %p\n", context->app_data); + if (context->smstate == NULL) { + fprintf(f, " SM state: NULL\n"); + } else { + otrl_sm_dump(f, context->smstate); + } + fprintf(f, "\n"); +} + +/* Dump the master context of this context, and all of its children. */ +void otrl_context_siblings_dump(FILE *f, const ConnContext *context) +{ + const ConnContext *citer; + for (citer = context->m_context; + citer && citer->m_context == context->m_context; + citer = citer->next) { + if (citer == context) { + fprintf(f, "*** "); + } + otrl_context_dump(f, citer); + } +} + +/* Dump all contexts. */ +void otrl_context_all_dump(FILE *f, OtrlUserState us) +{ + const ConnContext *citer; + unsigned int ctxnum = 1; + for (citer = us->context_root; citer; citer = citer->next, ++ctxnum) { + fprintf(f, "%u. ", ctxnum); + otrl_context_dump(f, citer); + } +} +#endif + +/* Create a new connection context. */ +static ConnContext * new_context(const char * user, const char * accountname, + const char * protocol) +{ + ConnContext * context; + OtrlSMState *smstate; + + context = malloc(sizeof(ConnContext)); + assert(context != NULL); + + context->username = strdup(user); + context->accountname = strdup(accountname); + context->protocol = strdup(protocol); + + context->msgstate = OTRL_MSGSTATE_PLAINTEXT; + otrl_auth_new(context); + + smstate = malloc(sizeof(OtrlSMState)); + assert(smstate != NULL); + otrl_sm_state_new(smstate); + context->smstate = smstate; + + context->our_instance = 0; + context->their_instance = OTRL_INSTAG_MASTER; + context->fingerprint_root.fingerprint = NULL; + context->fingerprint_root.context = context; + context->fingerprint_root.next = NULL; + context->fingerprint_root.tous = NULL; + context->active_fingerprint = NULL; + memset(context->sessionid, 0, 20); + context->sessionid_len = 0; + context->protocol_version = 0; + context->otr_offer = OFFER_NOT; + context->app_data = NULL; + context->app_data_free = NULL; + context->context_priv = otrl_context_priv_new(); + assert(context->context_priv != NULL); + context->next = NULL; + context->m_context = context; + context->recent_rcvd_child = NULL; + context->recent_sent_child = NULL; + context->recent_child = NULL; + + return context; +} + +ConnContext * otrl_context_find_recent_instance(ConnContext * context, + otrl_instag_t recent_instag) { + ConnContext * m_context; + + if (!context) return NULL; + + m_context = context->m_context; + + if (!m_context) return NULL; + + switch(recent_instag) { + case OTRL_INSTAG_RECENT: + return m_context->recent_child; + case OTRL_INSTAG_RECENT_RECEIVED: + return m_context->recent_rcvd_child; + case OTRL_INSTAG_RECENT_SENT: + return m_context->recent_sent_child; + default: + return NULL; + } +} + +/* Find the instance of this context that has the best security level, + and for which we have most recently received a message from. Note that most + recent in this case is limited to a one-second resolution. */ +ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context) +{ + ConnContext *curp; /* for iteration */ + ConnContext *m_context; /* master */ + ConnContext *cresult = context; /* best so far */ + + if (!context) { + return cresult; + } + + m_context = context->m_context; + + for (curp = m_context; curp && curp->m_context == m_context; + curp = curp->next) { + int msgstate_improved = 0; /* 0 == same, 1 == improved */ + int trust_improved = 0; /* (will immediately 'continue' if worse + * than) */ + + if (cresult->msgstate == curp->msgstate) { + msgstate_improved = 0; + } else if (curp->msgstate == OTRL_MSGSTATE_ENCRYPTED || + (cresult->msgstate == OTRL_MSGSTATE_PLAINTEXT && + curp->msgstate == OTRL_MSGSTATE_FINISHED)) { + msgstate_improved = 1; + } else { + continue; + } + + + if (otrl_context_is_fingerprint_trusted(cresult->active_fingerprint) == + otrl_context_is_fingerprint_trusted(curp->active_fingerprint)) { + + trust_improved = 0; + } else if + (otrl_context_is_fingerprint_trusted(curp->active_fingerprint)){ + + trust_improved = 1; + } else { + continue; + } + + if (msgstate_improved || trust_improved || + (!msgstate_improved && !trust_improved && + curp->context_priv->lastrecv >= + cresult->context_priv->lastrecv)) { + cresult = curp; + } + } + + return cresult; +} + +/* Look up a connection context by name/account/protocol/instag from the given + * OtrlUserState. If add_if_missing is true, allocate and return a new + * context if one does not currently exist. In that event, call + * add_app_data(data, context) so that app_data and app_data_free can be + * filled in by the application, and set *addedp to 1. + * In the 'their_instance' field note that you can also specify a 'meta- + * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAG_RECENT, + * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */ +ConnContext * otrl_context_find(OtrlUserState us, const char *user, + const char *accountname, const char *protocol, + otrl_instag_t their_instance, int add_if_missing, int *addedp, + void (*add_app_data)(void *data, ConnContext *context), void *data) +{ + ConnContext ** curp; + int usercmp = 1, acctcmp = 1, protocmp = 1; + if (addedp) *addedp = 0; + if (!user || !accountname || !protocol) return NULL; + + for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) { + if ((usercmp = strcmp((*curp)->username, user)) > 0 || + (usercmp == 0 && + (acctcmp = strcmp((*curp)->accountname, accountname)) > 0) || + (usercmp == 0 && acctcmp == 0 && + (protocmp = strcmp((*curp)->protocol, protocol)) > 0) || + (usercmp == 0 && acctcmp == 0 && protocmp == 0 + && (their_instance < OTRL_MIN_VALID_INSTAG || + ((*curp)->their_instance >= their_instance)))) + /* We're at the right place in the list. We've either found + * it, or gone too far. */ + break; + } + + if (usercmp == 0 && acctcmp == 0 && protocmp == 0 && *curp && + (their_instance < OTRL_MIN_VALID_INSTAG || + (their_instance == (*curp)->their_instance))) { + /* Found one! */ + if (their_instance >= OTRL_MIN_VALID_INSTAG || + their_instance == OTRL_INSTAG_MASTER) { + return *curp; + } + + /* We need to go back and check more values in the context */ + switch(their_instance) { + case OTRL_INSTAG_BEST: + return otrl_context_find_recent_secure_instance(*curp); + case OTRL_INSTAG_RECENT: + case OTRL_INSTAG_RECENT_RECEIVED: + case OTRL_INSTAG_RECENT_SENT: + return otrl_context_find_recent_instance(*curp, their_instance); + default: + return NULL; + } + } + + if (add_if_missing) { + ConnContext *newctx; + OtrlInsTag *our_instag = (OtrlInsTag *)otrl_instag_find(us, accountname, + protocol); + + if (addedp) *addedp = 1; + newctx = new_context(user, accountname, protocol); + newctx->next = *curp; + if (*curp) { + (*curp)->tous = &(newctx->next); + } + *curp = newctx; + newctx->tous = curp; + if (add_app_data) { + add_app_data(data, *curp); + } + + /* Initialize specified instance tags */ + if (our_instag) { + newctx->our_instance = our_instag->instag; + } + + if (their_instance >= OTRL_MIN_VALID_INSTAG || + their_instance == OTRL_INSTAG_MASTER) { + newctx->their_instance = their_instance; + } + + if (their_instance >= OTRL_MIN_VALID_INSTAG) { + newctx->m_context = otrl_context_find(us, user, accountname, + protocol, OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data); + } + + if (their_instance == OTRL_INSTAG_MASTER) { + /* if we're adding a master, there are no children, so the most + * recent context is the one we add. */ + newctx->recent_child = newctx; + newctx->recent_rcvd_child = newctx; + newctx->recent_sent_child = newctx; + } + + return *curp; + } + return NULL; +} + +/* Return true iff the given fingerprint is marked as trusted. */ +int otrl_context_is_fingerprint_trusted(Fingerprint *fprint) { + return fprint && fprint->trust && fprint->trust[0] != '\0'; +} + +/* This method gets called after sending or receiving a message, to + * update the master context's "recent context" pointers. */ +void otrl_context_update_recent_child(ConnContext *context, + unsigned int sent_msg) { + ConnContext *m_context = context->m_context; + + if (sent_msg) { + m_context->recent_sent_child = context; + } else { + m_context->recent_rcvd_child = context; + } + + m_context->recent_child = context; + +} + +/* Find a fingerprint in a given context, perhaps adding it if not + * present. */ +Fingerprint *otrl_context_find_fingerprint(ConnContext *context, + unsigned char fingerprint[20], int add_if_missing, int *addedp) +{ + Fingerprint *f; + if (addedp) *addedp = 0; + + if (!context || !context->m_context) return NULL; + + context = context->m_context; + + f = context->fingerprint_root.next; + while(f) { + if (!memcmp(f->fingerprint, fingerprint, 20)) return f; + f = f->next; + } + + /* Didn't find it. */ + if (add_if_missing) { + if (addedp) *addedp = 1; + f = malloc(sizeof(*f)); + assert(f != NULL); + f->fingerprint = malloc(20); + assert(f->fingerprint != NULL); + memmove(f->fingerprint, fingerprint, 20); + f->context = context; + f->trust = NULL; + f->next = context->fingerprint_root.next; + if (f->next) { + f->next->tous = &(f->next); + } + context->fingerprint_root.next = f; + f->tous = &(context->fingerprint_root.next); + return f; + } + return NULL; +} + +/* Set the trust level for a given fingerprint */ +void otrl_context_set_trust(Fingerprint *fprint, const char *trust) +{ + if (fprint == NULL) return; + + free(fprint->trust); + fprint->trust = trust ? strdup(trust) : NULL; +} + +/* Force a context into the OTRL_MSGSTATE_FINISHED state. */ +void otrl_context_force_finished(ConnContext *context) +{ + context->msgstate = OTRL_MSGSTATE_FINISHED; + otrl_auth_clear(&(context->auth)); + context->active_fingerprint = NULL; + memset(context->sessionid, 0, 20); + context->sessionid_len = 0; + context->protocol_version = 0; + otrl_sm_state_free(context->smstate); + otrl_context_priv_force_finished(context->context_priv); +} + +/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */ +void otrl_context_force_plaintext(ConnContext *context) +{ + /* First clean up everything we'd need to do for the FINISHED state */ + otrl_context_force_finished(context); + + /* And just set the state properly */ + context->msgstate = OTRL_MSGSTATE_PLAINTEXT; +} + +/* Forget a fingerprint (so long as it's not the active one. If it's a + * fingerprint_root, forget the whole context (as long as + * and_maybe_context is set, and it's PLAINTEXT). Also, if it's not + * the fingerprint_root, but it's the only fingerprint, and we're + * PLAINTEXT, forget the whole context if and_maybe_context is set. */ +void otrl_context_forget_fingerprint(Fingerprint *fprint, + int and_maybe_context) +{ + ConnContext *context = fprint->context; + if (fprint == &(context->fingerprint_root)) { + if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT && + and_maybe_context) { + otrl_context_forget(context); + } + } else { + if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT || + context->active_fingerprint != fprint) { + + free(fprint->fingerprint); + free(fprint->trust); + *(fprint->tous) = fprint->next; + if (fprint->next) { + fprint->next->tous = fprint->tous; + } + free(fprint); + if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT && + context->fingerprint_root.next == NULL && + and_maybe_context) { + /* We just deleted the only fingerprint. Forget the + * whole thing. */ + otrl_context_forget(context); + } + } + } +} + +/* Forget a whole context, so long as it's PLAINTEXT. If a context has child + * instances, don't remove this instance unless children are also all in + * PLAINTEXT state. In this case, the children will also be removed. + * Returns 0 on success, 1 on failure. */ +int otrl_context_forget(ConnContext *context) +{ + if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1; + + if (context->their_instance == OTRL_INSTAG_MASTER) { + ConnContext *c_iter; + + for (c_iter = context; c_iter && + c_iter->m_context == context->m_context; + c_iter = c_iter->next) { + if (c_iter->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1; + } + + c_iter = context->next; + while (c_iter && c_iter->m_context == context->m_context) { + if (!otrl_context_forget(c_iter)) { + c_iter = context->next; + } else { + return 1; + } + } + + } + + /* Just to be safe, force to plaintext. This also frees any + * extraneous data lying around. */ + otrl_context_force_plaintext(context); + + /* First free all the Fingerprints */ + while(context->fingerprint_root.next) { + otrl_context_forget_fingerprint(context->fingerprint_root.next, 0); + } + /* Now free all the dynamic info here */ + free(context->username); + free(context->accountname); + free(context->protocol); + free(context->smstate); + context->username = NULL; + context->accountname = NULL; + context->protocol = NULL; + context->smstate = NULL; + + /* Free the application data, if it exists */ + if (context->app_data && context->app_data_free) { + (context->app_data_free)(context->app_data); + context->app_data = NULL; + } + + /* Fix the list linkages */ + *(context->tous) = context->next; + if (context->next) { + context->next->tous = context->tous; + } + + free(context); + return 0; +} + +/* Forget all the contexts in a given OtrlUserState. */ +void otrl_context_forget_all(OtrlUserState us) +{ + ConnContext *c_iter; + + for (c_iter = us->context_root; c_iter; c_iter = c_iter->next) { + otrl_context_force_plaintext(c_iter); + } + + while (us->context_root) { + otrl_context_forget(us->context_root); + } +} diff --git a/comm/third_party/libotr/src/context.h b/comm/third_party/libotr/src/context.h new file mode 100644 index 0000000000..55cd082845 --- /dev/null +++ b/comm/third_party/libotr/src/context.h @@ -0,0 +1,193 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __CONTEXT_H__ +#define __CONTEXT_H__ + +#include "context_priv.h" + +#include + +#include "dh.h" +#include "auth.h" +#include "sm.h" + +typedef struct context ConnContext; /* Forward declare */ + +#include "instag.h" + +typedef enum { + OTRL_MSGSTATE_PLAINTEXT, /* Not yet started an encrypted + conversation */ + OTRL_MSGSTATE_ENCRYPTED, /* Currently in an encrypted + conversation */ + OTRL_MSGSTATE_FINISHED /* The remote side has sent us a + notification that he has ended + his end of the encrypted + conversation; prevent any + further messages from being + sent to him. */ +} OtrlMessageState; + +typedef struct s_fingerprint { + struct s_fingerprint *next; /* The next fingerprint in the list */ + struct s_fingerprint **tous; /* A pointer to the pointer to us */ + unsigned char *fingerprint; /* The fingerprint, or NULL */ + struct context *context; /* The context to which we belong */ + char *trust; /* The trust level of the fingerprint */ +} Fingerprint; + +struct context { + struct context * next; /* Linked list pointer */ + struct context ** tous; /* A pointer to the pointer to us */ + + /* Context information that is meant for internal use */ + + ConnContextPriv *context_priv; + + /* Context information that is meant for application use */ + + char * username; /* The user this context is for */ + char * accountname; /* The username is relative to + this account... */ + char * protocol; /* ... and this protocol */ + + struct context *m_context; /* If this is a child context, this + field will point to the master + context. Otherwise it will point to + itself. */ + struct context *recent_rcvd_child; /* If this is a master context, this + points to the child context that + has received a message most recently. + By default, it will point to the + master context. In child contexts + this field is NULL. */ + struct context *recent_sent_child; /* Similar to above, but it points to + the child who has sent most + recently. */ + struct context *recent_child; /* Similar to above, but will point to + the most recent of recent_rcvd_child + and recent_sent_child */ + + otrl_instag_t our_instance; /* Our instance tag for this computer*/ + otrl_instag_t their_instance; /* The user's instance tag */ + + OtrlMessageState msgstate; /* The state of message disposition + with this user */ + OtrlAuthInfo auth; /* The state of ongoing + authentication with this user */ + + Fingerprint fingerprint_root; /* The root of a linked list of + Fingerprints entries. This list will + only be populated in master contexts. + For child contexts, + fingerprint_root.next will always + point to NULL. */ + Fingerprint *active_fingerprint; /* Which fingerprint is in use now? + A pointer into the above list */ + + unsigned char sessionid[20]; /* The sessionid and bold half */ + size_t sessionid_len; /* determined when this private */ + OtrlSessionIdHalf sessionid_half; /* connection was established. */ + + unsigned int protocol_version; /* The version of OTR in use */ + + enum { + OFFER_NOT, + OFFER_SENT, + OFFER_REJECTED, + OFFER_ACCEPTED + } otr_offer; /* Has this correspondent repsponded to our + OTR offers? */ + + /* Application data to be associated with this context */ + void *app_data; + /* A function to free the above data when we forget this context */ + void (*app_data_free)(void *); + + OtrlSMState *smstate; /* The state of the current + socialist millionaires exchange */ +}; + +#include "userstate.h" + +/* Look up a connection context by name/account/protocol/instance from the + * given OtrlUserState. If add_if_missing is true, allocate and return a + * new context if one does not currently exist. In that event, call + * add_app_data(data, context) so that app_data and app_data_free can be + * filled in by the application, and set *addedp to 1. + * In the 'their_instance' field note that you can also specify a 'meta- + * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAL_RECENT, + * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */ +ConnContext * otrl_context_find(OtrlUserState us, const char *user, + const char *accountname, const char *protocol, + otrl_instag_t their_instance, int add_if_missing, int *addedp, + void (*add_app_data)(void *data, ConnContext *context), void *data); + +/* Return true iff the given fingerprint is marked as trusted. */ +int otrl_context_is_fingerprint_trusted(Fingerprint *fprint); + +/* This method gets called after sending or receiving a message, to + * update the master context's "recent context" pointers. */ +void otrl_context_update_recent_child(ConnContext *context, + unsigned int sent_msg); + +/* Find a fingerprint in a given context, perhaps adding it if not + * present. */ +Fingerprint *otrl_context_find_fingerprint(ConnContext *context, + unsigned char fingerprint[20], int add_if_missing, int *addedp); + +/* Set the trust level for a given fingerprint */ +void otrl_context_set_trust(Fingerprint *fprint, const char *trust); + +/* Force a context into the OTRL_MSGSTATE_FINISHED state. */ +void otrl_context_force_finished(ConnContext *context); + +/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */ +void otrl_context_force_plaintext(ConnContext *context); + +/* Forget a fingerprint (so long as it's not the active one. If it's a + * fingerprint_root, forget the whole context (as long as + * and_maybe_context is set, and it's PLAINTEXT). Also, if it's not + * the fingerprint_root, but it's the only fingerprint, and we're + * PLAINTEXT, forget the whole context if and_maybe_context is set. */ +void otrl_context_forget_fingerprint(Fingerprint *fprint, + int and_maybe_context); + +/* Forget a whole context, so long as it's PLAINTEXT. If a context has child + * instances, don't remove this instance unless children are also all in + * PLAINTEXT state. In this case, the children will also be removed. + * Returns 0 on success, 1 on failure. */ +int otrl_context_forget(ConnContext *context); + +/* Forget all the contexts in a given OtrlUserState. */ +void otrl_context_forget_all(OtrlUserState us); + +/* Find requested recent instance */ +ConnContext * otrl_context_find_recent_instance(ConnContext * context, + otrl_instag_t recent_instag); + +/* Find the instance of this context that has the best security level, and for + * which we have most recently received a message from. Note that most recent + * in this case is limited to a one-second resolution. */ +ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context); + +#endif diff --git a/comm/third_party/libotr/src/context_priv.c b/comm/third_party/libotr/src/context_priv.c new file mode 100644 index 0000000000..47d05b9204 --- /dev/null +++ b/comm/third_party/libotr/src/context_priv.c @@ -0,0 +1,95 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "context_priv.h" + +/* Create a new private connection context */ +ConnContextPriv *otrl_context_priv_new() +{ + ConnContextPriv *context_priv; + context_priv = malloc(sizeof(*context_priv)); + assert(context_priv != NULL); + + context_priv->fragment = NULL; + context_priv->fragment_len = 0; + context_priv->fragment_n = 0; + context_priv->fragment_k = 0; + context_priv->numsavedkeys = 0; + context_priv->saved_mac_keys = NULL; + context_priv->generation = 0; + context_priv->lastsent = 0; + context_priv->lastmessage = NULL; + context_priv->lastrecv = 0; + context_priv->may_retransmit = 0; + context_priv->their_keyid = 0; + context_priv->their_y = NULL; + context_priv->their_old_y = NULL; + context_priv->our_keyid = 0; + context_priv->our_dh_key.groupid = 0; + context_priv->our_dh_key.priv = NULL; + context_priv->our_dh_key.pub = NULL; + context_priv->our_old_dh_key.groupid = 0; + context_priv->our_old_dh_key.priv = NULL; + context_priv->our_old_dh_key.pub = NULL; + otrl_dh_session_blank(&(context_priv->sesskeys[0][0])); + otrl_dh_session_blank(&(context_priv->sesskeys[0][1])); + otrl_dh_session_blank(&(context_priv->sesskeys[1][0])); + otrl_dh_session_blank(&(context_priv->sesskeys[1][1])); + + return context_priv; +} + +/* Resets the appropriate variables when a context + * is being force finished + */ +void otrl_context_priv_force_finished(ConnContextPriv *context_priv) +{ + free(context_priv->fragment); + context_priv->fragment = NULL; + context_priv->fragment_len = 0; + context_priv->fragment_n = 0; + context_priv->fragment_k = 0; + context_priv->numsavedkeys = 0; + free(context_priv->saved_mac_keys); + context_priv->saved_mac_keys = NULL; + gcry_free(context_priv->lastmessage); + context_priv->lastmessage = NULL; + context_priv->may_retransmit = 0; + context_priv->their_keyid = 0; + gcry_mpi_release(context_priv->their_y); + context_priv->their_y = NULL; + gcry_mpi_release(context_priv->their_old_y); + context_priv->their_old_y = NULL; + context_priv->our_keyid = 0; + otrl_dh_keypair_free(&(context_priv->our_dh_key)); + otrl_dh_keypair_free(&(context_priv->our_old_dh_key)); + otrl_dh_session_free(&(context_priv->sesskeys[0][0])); + otrl_dh_session_free(&(context_priv->sesskeys[0][1])); + otrl_dh_session_free(&(context_priv->sesskeys[1][0])); + otrl_dh_session_free(&(context_priv->sesskeys[1][1])); +} diff --git a/comm/third_party/libotr/src/context_priv.h b/comm/third_party/libotr/src/context_priv.h new file mode 100644 index 0000000000..0748074e9b --- /dev/null +++ b/comm/third_party/libotr/src/context_priv.h @@ -0,0 +1,94 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __CONTEXT_PRIV_H__ +#define __CONTEXT_PRIV_H__ + +#include + +#include "dh.h" +#include "auth.h" +#include "sm.h" + +typedef struct context_priv { + /* The part of the fragmented message we've seen so far */ + char *fragment; + + /* The length of fragment */ + size_t fragment_len; + + /* The total number of fragments in this message */ + unsigned short fragment_n; + + /* The highest fragment number we've seen so far for this message */ + unsigned short fragment_k; + + /* current keyid used by other side; this is set to 0 if we get + * a OTRL_TLV_DISCONNECTED message from them. */ + unsigned int their_keyid; + + /* Y[their_keyid] (their DH pubkey) */ + gcry_mpi_t their_y; + + /* Y[their_keyid-1] (their prev DH pubkey) */ + gcry_mpi_t their_old_y; + + /* current keyid used by us */ + unsigned int our_keyid; + + /* DH key[our_keyid] */ + DH_keypair our_dh_key; + + /* DH key[our_keyid-1] */ + DH_keypair our_old_dh_key; + + /* sesskeys[i][j] are the session keys derived from DH + * key[our_keyid-i] and mpi Y[their_keyid-j] */ + DH_sesskeys sesskeys[2][2]; + + /* saved mac keys to be revealed later */ + unsigned int numsavedkeys; + unsigned char *saved_mac_keys; + + /* generation number: increment every time we go private, and never + * reset to 0 (unless we remove the context entirely) */ + unsigned int generation; + + /* The last time a Data Message was sent */ + time_t lastsent; + + /* The last time a Data Message was received */ + time_t lastrecv; + + /* The plaintext of the last Data Message sent */ + char *lastmessage; + + /* Is the last message eligible for retransmission? */ + int may_retransmit; + +} ConnContextPriv; + +/* Create a new private connection context. */ +ConnContextPriv *otrl_context_priv_new(); + +/* Frees up memory that was used in otrl_context_priv_new */ +void otrl_context_priv_force_finished(ConnContextPriv *context_priv); + +#endif diff --git a/comm/third_party/libotr/src/dh.c b/comm/third_party/libotr/src/dh.c new file mode 100644 index 0000000000..d8bc45d10d --- /dev/null +++ b/comm/third_party/libotr/src/dh.c @@ -0,0 +1,476 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "dh.h" + + +static const char* DH1536_MODULUS_S = "0x" + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; +static const char *DH1536_GENERATOR_S = "0x02"; +static const int DH1536_MOD_LEN_BITS = 1536; +static const int DH1536_MOD_LEN_BYTES = 192; + +static gcry_mpi_t DH1536_MODULUS = NULL; +static gcry_mpi_t DH1536_MODULUS_MINUS_2 = NULL; +static gcry_mpi_t DH1536_GENERATOR = NULL; + +/* + * Call this once, at plugin load time. It sets up the modulus and + * generator MPIs. + */ +void otrl_dh_init(void) +{ + gcry_mpi_scan(&DH1536_MODULUS, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_MODULUS_S, 0, NULL); + gcry_mpi_scan(&DH1536_GENERATOR, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_GENERATOR_S, 0, NULL); + DH1536_MODULUS_MINUS_2 = gcry_mpi_new(DH1536_MOD_LEN_BITS); + gcry_mpi_sub_ui(DH1536_MODULUS_MINUS_2, DH1536_MODULUS, 2); +} + +/* + * Initialize the fields of a DH keypair. + */ +void otrl_dh_keypair_init(DH_keypair *kp) +{ + kp->groupid = 0; + kp->priv = NULL; + kp->pub = NULL; +} + +/* + * Copy a DH_keypair. + */ +void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src) +{ + dst->groupid = src->groupid; + dst->priv = gcry_mpi_copy(src->priv); + dst->pub = gcry_mpi_copy(src->pub); +} + +/* + * Deallocate the contents of a DH_keypair (but not the DH_keypair + * itself) + */ +void otrl_dh_keypair_free(DH_keypair *kp) +{ + gcry_mpi_release(kp->priv); + gcry_mpi_release(kp->pub); + kp->priv = NULL; + kp->pub = NULL; +} + +/* + * Generate a DH keypair for a specified group. + */ +gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp) +{ + unsigned char *secbuf = NULL; + gcry_mpi_t privkey = NULL; + + if (groupid != DH1536_GROUP_ID) { + /* Invalid group id */ + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Generate the secret key: a random 320-bit value */ + secbuf = gcry_random_bytes_secure(40, GCRY_STRONG_RANDOM); + gcry_mpi_scan(&privkey, GCRYMPI_FMT_USG, secbuf, 40, NULL); + gcry_free(secbuf); + + kp->groupid = groupid; + kp->priv = privkey; + kp->pub = gcry_mpi_new(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(kp->pub, DH1536_GENERATOR, privkey, DH1536_MODULUS); + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* + * Construct session keys from a DH keypair and someone else's public + * key. + */ +gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp, + gcry_mpi_t y) +{ + gcry_mpi_t gab; + size_t gablen; + unsigned char *gabdata; + unsigned char *hashdata; + unsigned char sendbyte, rcvbyte; + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + + otrl_dh_session_blank(sess); + + if (kp->groupid != DH1536_GROUP_ID) { + /* Invalid group id */ + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Calculate the shared secret MPI */ + gab = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(gab, y, kp->priv, DH1536_MODULUS); + + /* Output it in the right format */ + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &gablen, gab); + gabdata = gcry_malloc_secure(gablen + 5); + if (!gabdata) { + gcry_mpi_release(gab); + return gcry_error(GPG_ERR_ENOMEM); + } + gabdata[1] = (gablen >> 24) & 0xff; + gabdata[2] = (gablen >> 16) & 0xff; + gabdata[3] = (gablen >> 8) & 0xff; + gabdata[4] = gablen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, gabdata+5, gablen, NULL, gab); + gcry_mpi_release(gab); + + hashdata = gcry_malloc_secure(20); + if (!hashdata) { + gcry_free(gabdata); + return gcry_error(GPG_ERR_ENOMEM); + } + + /* Are we the "high" or "low" end of the connection? */ + if ( gcry_mpi_cmp(kp->pub, y) > 0 ) { + sendbyte = 0x01; + rcvbyte = 0x02; + } else { + sendbyte = 0x02; + rcvbyte = 0x01; + } + + /* Calculate the sending encryption key */ + gabdata[0] = sendbyte; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5); + err = gcry_cipher_open(&(sess->sendenc), GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + if (err) goto err; + err = gcry_cipher_setkey(sess->sendenc, hashdata, 16); + if (err) goto err; + + /* Calculate the sending MAC key */ + gcry_md_hash_buffer(GCRY_MD_SHA1, sess->sendmackey, hashdata, 16); + err = gcry_md_open(&(sess->sendmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + if (err) goto err; + err = gcry_md_setkey(sess->sendmac, sess->sendmackey, 20); + if (err) goto err; + + /* Calculate the receiving encryption key */ + gabdata[0] = rcvbyte; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5); + err = gcry_cipher_open(&(sess->rcvenc), GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + if (err) goto err; + err = gcry_cipher_setkey(sess->rcvenc, hashdata, 16); + if (err) goto err; + + /* Calculate the receiving MAC key (and save it in the DH_sesskeys + * struct, so we can reveal it later) */ + gcry_md_hash_buffer(GCRY_MD_SHA1, sess->rcvmackey, hashdata, 16); + err = gcry_md_open(&(sess->rcvmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + if (err) goto err; + err = gcry_md_setkey(sess->rcvmac, sess->rcvmackey, 20); + if (err) goto err; + + /* Calculate the extra key (used if applications wish to extract a + * symmetric key for transferring files, or something like that) */ + gabdata[0] = 0xff; + gcry_md_hash_buffer(GCRY_MD_SHA256, sess->extrakey, gabdata, gablen+5); + + gcry_free(gabdata); + gcry_free(hashdata); + return gcry_error(GPG_ERR_NO_ERROR); +err: + otrl_dh_session_free(sess); + gcry_free(gabdata); + gcry_free(hashdata); + return err; +} + +/* + * Compute the secure session id, two encryption keys, and four MAC keys + * given our DH key and their DH public key. + */ +gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh, + gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, + gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp, + gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p, + gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p) +{ + gcry_mpi_t s; + size_t slen; + unsigned char *sdata; + unsigned char *hashdata; + unsigned char ctr[16]; + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + + *enc_c = NULL; + *enc_cp = NULL; + *mac_m1 = NULL; + *mac_m1p = NULL; + *mac_m2 = NULL; + *mac_m2p = NULL; + memset(ctr, 0, 16); + + if (our_dh->groupid != DH1536_GROUP_ID) { + /* Invalid group id */ + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Check that their_pub is in range */ + if (gcry_mpi_cmp_ui(their_pub, 2) < 0 || + gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) { + /* Invalid pubkey */ + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Calculate the shared secret MPI */ + s = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS); + + /* Output it in the right format */ + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s); + sdata = gcry_malloc_secure(slen + 5); + if (!sdata) { + gcry_mpi_release(s); + return gcry_error(GPG_ERR_ENOMEM); + } + sdata[1] = (slen >> 24) & 0xff; + sdata[2] = (slen >> 16) & 0xff; + sdata[3] = (slen >> 8) & 0xff; + sdata[4] = slen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s); + gcry_mpi_release(s); + + /* Calculate the session id */ + hashdata = gcry_malloc_secure(32); + if (!hashdata) { + gcry_free(sdata); + return gcry_error(GPG_ERR_ENOMEM); + } + sdata[0] = 0x00; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + memmove(sessionid, hashdata, 8); + *sessionidlenp = 8; + + /* Calculate the encryption keys */ + sdata[0] = 0x01; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + + err = gcry_cipher_open(enc_c, GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + if (err) goto err; + err = gcry_cipher_setkey(*enc_c, hashdata, 16); + if (err) goto err; + err = gcry_cipher_setctr(*enc_c, ctr, 16); + if (err) goto err; + + err = gcry_cipher_open(enc_cp, GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + if (err) goto err; + err = gcry_cipher_setkey(*enc_cp, hashdata+16, 16); + if (err) goto err; + err = gcry_cipher_setctr(*enc_cp, ctr, 16); + if (err) goto err; + + /* Calculate the MAC keys */ + sdata[0] = 0x02; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + err = gcry_md_open(mac_m1, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if (err) goto err; + err = gcry_md_setkey(*mac_m1, hashdata, 32); + if (err) goto err; + + sdata[0] = 0x03; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + err = gcry_md_open(mac_m2, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if (err) goto err; + err = gcry_md_setkey(*mac_m2, hashdata, 32); + if (err) goto err; + + sdata[0] = 0x04; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + err = gcry_md_open(mac_m1p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if (err) goto err; + err = gcry_md_setkey(*mac_m1p, hashdata, 32); + if (err) goto err; + + sdata[0] = 0x05; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + err = gcry_md_open(mac_m2p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if (err) goto err; + err = gcry_md_setkey(*mac_m2p, hashdata, 32); + if (err) goto err; + + gcry_free(sdata); + gcry_free(hashdata); + return gcry_error(GPG_ERR_NO_ERROR); + +err: + gcry_cipher_close(*enc_c); + gcry_cipher_close(*enc_cp); + gcry_md_close(*mac_m1); + gcry_md_close(*mac_m1p); + gcry_md_close(*mac_m2); + gcry_md_close(*mac_m2p); + *enc_c = NULL; + *enc_cp = NULL; + *mac_m1 = NULL; + *mac_m1p = NULL; + *mac_m2 = NULL; + *mac_m2p = NULL; + gcry_free(sdata); + gcry_free(hashdata); + return err; +} + +/* + * Compute the secure session id, given our DH key and their DH public + * key. + */ +gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh, + gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, + OtrlSessionIdHalf *halfp) +{ + gcry_mpi_t s; + size_t slen; + unsigned char *sdata; + unsigned char *hashdata; + + if (our_dh->groupid != DH1536_GROUP_ID) { + /* Invalid group id */ + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Check that their_pub is in range */ + if (gcry_mpi_cmp_ui(their_pub, 2) < 0 || + gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) { + /* Invalid pubkey */ + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Calculate the shared secret MPI */ + s = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS); + + /* Output it in the right format */ + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s); + sdata = gcry_malloc_secure(slen + 5); + if (!sdata) { + gcry_mpi_release(s); + return gcry_error(GPG_ERR_ENOMEM); + } + sdata[1] = (slen >> 24) & 0xff; + sdata[2] = (slen >> 16) & 0xff; + sdata[3] = (slen >> 8) & 0xff; + sdata[4] = slen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s); + gcry_mpi_release(s); + + /* Calculate the session id */ + hashdata = gcry_malloc_secure(20); + if (!hashdata) { + gcry_free(sdata); + return gcry_error(GPG_ERR_ENOMEM); + } + sdata[0] = 0x00; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, sdata, slen+5); + memmove(sessionid, hashdata, 20); + *sessionidlenp = 20; + + /* Which half should be bold? */ + if (gcry_mpi_cmp(our_dh->pub, their_pub) > 0) { + *halfp = OTRL_SESSIONID_SECOND_HALF_BOLD; + } else { + *halfp = OTRL_SESSIONID_FIRST_HALF_BOLD; + } + + gcry_free(hashdata); + gcry_free(sdata); + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* + * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys + * itself) + */ +void otrl_dh_session_free(DH_sesskeys *sess) +{ + gcry_cipher_close(sess->sendenc); + gcry_cipher_close(sess->rcvenc); + gcry_md_close(sess->sendmac); + gcry_md_close(sess->rcvmac); + + otrl_dh_session_blank(sess); +} + +/* + * Blank out the contents of a DH_sesskeys (without releasing it) + */ +void otrl_dh_session_blank(DH_sesskeys *sess) +{ + sess->sendenc = NULL; + sess->sendmac = NULL; + sess->rcvenc = NULL; + sess->rcvmac = NULL; + memset(sess->sendctr, 0, 16); + memset(sess->rcvctr, 0, 16); + memset(sess->sendmackey, 0, 20); + memset(sess->rcvmackey, 0, 20); + sess->sendmacused = 0; + sess->rcvmacused = 0; + memset(sess->extrakey, 0, OTRL_EXTRAKEY_BYTES); +} + +/* Increment the top half of a counter block */ +void otrl_dh_incctr(unsigned char *ctr) +{ + int i; + for (i=8;i;--i) { + if (++ctr[i-1]) break; + } +} + +/* Compare two counter values (8 bytes each). Return 0 if ctr1 == ctr2, + * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */ +int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2) +{ + int i; + for (i=0;i<8;++i) { + int c = ctr1[i] - ctr2[i]; + if (c) return c; + } + return 0; +} diff --git a/comm/third_party/libotr/src/dh.h b/comm/third_party/libotr/src/dh.h new file mode 100644 index 0000000000..742c408042 --- /dev/null +++ b/comm/third_party/libotr/src/dh.h @@ -0,0 +1,123 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __DH_H__ +#define __DH_H__ + +#define DH1536_GROUP_ID 5 + +typedef struct { + unsigned int groupid; + gcry_mpi_t priv, pub; +} DH_keypair; + +/* Which half of the secure session id should be shown in bold? */ +typedef enum { + OTRL_SESSIONID_FIRST_HALF_BOLD, + OTRL_SESSIONID_SECOND_HALF_BOLD +} OtrlSessionIdHalf; + +#define OTRL_EXTRAKEY_BYTES 32 + +typedef struct { + unsigned char sendctr[16]; + unsigned char rcvctr[16]; + gcry_cipher_hd_t sendenc; + gcry_cipher_hd_t rcvenc; + gcry_md_hd_t sendmac; + unsigned char sendmackey[20]; + int sendmacused; + gcry_md_hd_t rcvmac; + unsigned char rcvmackey[20]; + int rcvmacused; + unsigned char extrakey[OTRL_EXTRAKEY_BYTES]; +} DH_sesskeys; + +/* + * Call this once, at plugin load time. It sets up the modulus and + * generator MPIs. + */ +void otrl_dh_init(void); + +/* + * Initialize the fields of a DH keypair. + */ +void otrl_dh_keypair_init(DH_keypair *kp); + +/* + * Copy a DH_keypair. + */ +void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src); + +/* + * Deallocate the contents of a DH_keypair (but not the DH_keypair + * itself) + */ +void otrl_dh_keypair_free(DH_keypair *kp); + +/* + * Generate a DH keypair for a specified group. + */ +gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp); + +/* + * Construct session keys from a DH keypair and someone else's public + * key. + */ +gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp, + gcry_mpi_t y); + +/* + * Compute the secure session id, two encryption keys, and four MAC keys + * given our DH key and their DH public key. + */ +gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh, + gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, + gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp, + gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p, + gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p); + +/* + * Compute the secure session id, given our DH key and their DH public + * key. + */ +gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh, + gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, + OtrlSessionIdHalf *halfp); + +/* + * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys + * itself) + */ +void otrl_dh_session_free(DH_sesskeys *sess); + +/* + * Blank out the contents of a DH_sesskeys (without releasing it) + */ +void otrl_dh_session_blank(DH_sesskeys *sess); + +/* Increment the top half of a counter block */ +void otrl_dh_incctr(unsigned char *ctr); + +/* Compare two counter values (8 bytes each). Return 0 if ctr1 == ctr2, + * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */ +int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2); + +#endif diff --git a/comm/third_party/libotr/src/instag.c b/comm/third_party/libotr/src/instag.c new file mode 100644 index 0000000000..cccd94fb6c --- /dev/null +++ b/comm/third_party/libotr/src/instag.c @@ -0,0 +1,277 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2015 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "instag.h" +#include "userstate.h" + +/* Forget the given instag. */ +void otrl_instag_forget(OtrlInsTag* instag) { + if (!instag) return; + + if (instag->accountname) free(instag->accountname); + if (instag->protocol) free(instag->protocol); + + /* Re-link the list */ + *(instag->tous) = instag->next; + if (instag->next) { + instag->next->tous = instag->tous; + } + + free(instag); +} + +/* Forget all instags in a given OtrlUserState. */ +void otrl_instag_forget_all(OtrlUserState us) { + while(us->instag_root) { + otrl_instag_forget(us->instag_root); + } +} + +/* Fetch the instance tag from the given OtrlUserState associated with + * the given account */ +OtrlInsTag * otrl_instag_find(OtrlUserState us, const char *accountname, + const char *protocol) +{ + OtrlInsTag *p; + + for(p=us->instag_root; p; p=p->next) { + if (!strcmp(p->accountname, accountname) && + !strcmp(p->protocol, protocol)) { + return p; + } + } + return NULL; +} + +/* Read our instance tag from a file on disk into the given + * OtrlUserState. */ +gcry_error_t otrl_instag_read(OtrlUserState us, const char *filename) +{ + gcry_error_t err; + FILE *instf; + + /* Open the instance tag file. */ + instf = fopen(filename, "rb"); + if (!instf) { + return gcry_error_from_errno(errno); + } + + err = otrl_instag_read_FILEp(us, instf); + fclose(instf); + return err; +} + +/* Read our instance tag from a file on disk into the given + * OtrlUserState. The FILE* must be open for reading. */ +gcry_error_t otrl_instag_read_FILEp(OtrlUserState us, FILE *instf) +{ + if (!instf) return gcry_error(GPG_ERR_NO_ERROR); + + OtrlInsTag *p; + char storeline[1000]; + size_t maxsize = sizeof(storeline); + + while(fgets(storeline, maxsize, instf)) { + char *prevpos; + char *pos; + unsigned int instag = 0; + + p = malloc(sizeof(*p)); + if (!p) { + return gcry_error(GPG_ERR_ENOMEM); + } + + /* Parse the line, which should be of the form: + * accountname\tprotocol\t40_hex_nybbles\n */ + prevpos = storeline; + pos = strchr(prevpos, '\t'); + if (!pos) { + free(p); + continue; + } + *pos = '\0'; + pos++; + p->accountname = malloc(pos - prevpos); + if (!(p->accountname)) { + free(p); + return gcry_error(GPG_ERR_ENOMEM); + } + memmove(p->accountname, prevpos, pos - prevpos); + + prevpos = pos; + pos = strchr(prevpos, '\t'); + if (!pos) { + free(p->accountname); + free(p); + continue; + } + *pos = '\0'; + pos++; + p->protocol = malloc(pos - prevpos); + if (!(p->protocol)) { + free(p->accountname); + free(p); + return gcry_error(GPG_ERR_ENOMEM); + } + memmove(p->protocol, prevpos, pos - prevpos); + + prevpos = pos; + pos = strchr(prevpos, '\r'); + if (!pos) pos = strchr(prevpos, '\n'); + if (!pos) { + free(p->accountname); + free(p->protocol); + free(p); + continue; + } + *pos = '\0'; + pos++; + /* hex str of length 8 */ + if (strlen(prevpos) != 8) { + free(p->accountname); + free(p->protocol); + free(p); + continue; + } + + sscanf(prevpos, "%08x", &instag); + + if (instag < OTRL_MIN_VALID_INSTAG) { + free(p->accountname); + free(p->protocol); + free(p); + continue; + } + p->instag = instag; + + /* Link it up */ + p->next = us->instag_root; + if (p->next) { + p->next->tous = &(p->next); + } + p->tous = &(us->instag_root); + us->instag_root = p; + } + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Generate a new instance tag for the given account and write to file */ +gcry_error_t otrl_instag_generate(OtrlUserState us, const char *filename, + const char *accountname, const char *protocol) +{ + gcry_error_t err; + FILE *instf; + + /* Open the instance tag file. */ + instf = fopen(filename, "wb"); + if (!instf) { + return gcry_error_from_errno(errno); + } + + err = otrl_instag_generate_FILEp(us, instf, accountname, protocol); + fclose(instf); + return err; +} + +/* Return a new valid instance tag */ +otrl_instag_t otrl_instag_get_new() +{ + otrl_instag_t result = 0; + + while(result < OTRL_MIN_VALID_INSTAG) { + otrl_instag_t * instag = (otrl_instag_t *)gcry_random_bytes( + sizeof(otrl_instag_t), GCRY_STRONG_RANDOM); + result = *instag; + gcry_free(instag); + } + + return result; +} + +/* Generate a new instance tag for the given account and write to file + * The FILE* must be open for writing. */ +gcry_error_t otrl_instag_generate_FILEp(OtrlUserState us, FILE *instf, + const char *accountname, const char *protocol) +{ + OtrlInsTag *p; + if (!accountname || !protocol) return gcry_error(GPG_ERR_NO_ERROR); + + p = (OtrlInsTag *)malloc(sizeof(OtrlInsTag)); + p->accountname = strdup(accountname); + p->protocol = strdup(protocol); + + p->instag = otrl_instag_get_new(); + + /* Add to our list in OtrlUserState */ + p->next = us->instag_root; + if (p->next) { + p->next->tous = &(p->next); + } + p->tous = &(us->instag_root); + us->instag_root = p; + + otrl_instag_write_FILEp(us, instf); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Write our instance tags to a file on disk. */ +gcry_error_t otrl_instag_write(OtrlUserState us, const char *filename) +{ + gcry_error_t err; + FILE *instf; + + /* Open the instance tag file. */ + instf = fopen(filename, "wb"); + if (!instf) { + return gcry_error_from_errno(errno); + } + + err = otrl_instag_write_FILEp(us, instf); + fclose(instf); + return err; +} + +/* Write our instance tags to a file on disk. + * The FILE* must be open for writing. */ +gcry_error_t otrl_instag_write_FILEp(OtrlUserState us, FILE *instf) +{ + OtrlInsTag *p; + /* This line should be ignored when read back in, since there are no + tabs. */ + fprintf(instf, "# WARNING! You shouldn't copy this file to another" + " computer. It is unnecessary and can cause problems.\n"); + for(p=us->instag_root; p; p=p->next) { + fprintf(instf, "%s\t%s\t%08x\n", p->accountname, p->protocol, + p->instag); + } + + return gcry_error(GPG_ERR_NO_ERROR); +} + diff --git a/comm/third_party/libotr/src/instag.h b/comm/third_party/libotr/src/instag.h new file mode 100644 index 0000000000..c8aabb324f --- /dev/null +++ b/comm/third_party/libotr/src/instag.h @@ -0,0 +1,89 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __INSTAG_H__ +#define __INSTAG_H__ + +#include +#include + +#define OTRL_INSTAG_MASTER 0 +#define OTRL_INSTAG_BEST 1 /* Most secure, based on: conv status, + * then fingerprint status, then most recent. */ +#define OTRL_INSTAG_RECENT 2 +#define OTRL_INSTAG_RECENT_RECEIVED 3 +#define OTRL_INSTAG_RECENT_SENT 4 + +#define OTRL_MIN_VALID_INSTAG 0x100 /* Instag values below this are reserved + * for meta instags, defined above, */ + +typedef unsigned int otrl_instag_t; + +/* The list of instance tags used for our accounts */ +typedef struct s_OtrlInsTag { + struct s_OtrlInsTag *next; + struct s_OtrlInsTag **tous; + + char *accountname; + char *protocol; + otrl_instag_t instag; +} OtrlInsTag; + +#include "userstate.h" + +/* Forget the given instag. */ +void otrl_instag_forget(OtrlInsTag* instag); + +/* Forget all instags in a given OtrlUserState. */ +void otrl_instag_forget_all(OtrlUserState us); + +/* Fetch the instance tag from the given OtrlUserState associated with + * the given account */ +OtrlInsTag * otrl_instag_find(OtrlUserState us, const char *accountname, + const char *protocol); + +/* Read our instance tag from a file on disk into the given + * OtrlUserState. */ +gcry_error_t otrl_instag_read(OtrlUserState us, const char *filename); + +/* Read our instance tag from a file on disk into the given + * OtrlUserState. The FILE* must be open for reading. */ +gcry_error_t otrl_instag_read_FILEp(OtrlUserState us, FILE *instf); + +/* Return a new valid instance tag */ +otrl_instag_t otrl_instag_get_new(); + +/* Get a new instance tag for the given account and write to file*/ +gcry_error_t otrl_instag_generate(OtrlUserState us, const char *filename, + const char *accountname, const char *protocol); + +/* Get a new instance tag for the given account and write to file + * The FILE* must be open for writing. */ +gcry_error_t otrl_instag_generate_FILEp(OtrlUserState us, FILE *instf, + const char *accountname, const char *protocol); + +/* Write our instance tags to a file on disk. */ +gcry_error_t otrl_instag_write(OtrlUserState us, const char *filename); + +/* Write our instance tags to a file on disk. + * The FILE* must be open for writing. */ +gcry_error_t otrl_instag_write_FILEp(OtrlUserState us, FILE *instf); + +#endif diff --git a/comm/third_party/libotr/src/mem.c b/comm/third_party/libotr/src/mem.c new file mode 100644 index 0000000000..29330ae757 --- /dev/null +++ b/comm/third_party/libotr/src/mem.c @@ -0,0 +1,180 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Memory allocation routines for libgcrypt. All of the session key + * information gets allocated through here, so we can wipe it out when + * it's free()d. We don't use the built-in secmem functions of + * libgcrypt because you need to declare a fixed amount of it when you + * start up. + * + * Because "secure" and "insecure" allocations from libgcrypt will get + * handled the same way (since we're not going to be running as root, + * and so won't actually have pinned memory), pretend all allocated + * memory (but just from libgcrypt) is requested secure, and wipe it on + * free(). */ + +/* Uncomment the following to add a check that our free() and realloc() only + * get called on things returned from our malloc(). */ +/* #define OTRL_MEM_MAGIC 0x31415926 */ + +/* system headers */ +#ifdef OTRL_MEM_MAGIC +#include +#endif +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "mem.h" + +static size_t header_size; + +static void *otrl_mem_malloc(size_t n) +{ + void *p; + size_t new_n = n; + new_n += header_size; + + /* Check for overflow attack */ + if (new_n < n) return NULL; + p = malloc(new_n); + if (p == NULL) return NULL; + + ((size_t *)p)[0] = new_n; /* Includes header size */ +#ifdef OTRL_MEM_MAGIC + ((size_t *)p)[1] = OTRL_MEM_MAGIC; +#endif + + return (void *)((char *)p + header_size); +} + +static int otrl_mem_is_secure(const void *p) +{ + return 1; +} + +static void otrl_mem_free(void *p) +{ + void *real_p = (void *)((char *)p - header_size); + size_t n = ((size_t *)real_p)[0]; +#ifdef OTRL_MEM_MAGIC + if (((size_t *)real_p)[1] != OTRL_MEM_MAGIC) { + fprintf(stderr, "Illegal free!\n"); + return; + } +#endif + + /* Wipe the memory (in the same way the built-in deallocator in + * libgcrypt would) */ + memset(real_p, 0xff, n); + memset(real_p, 0xaa, n); + memset(real_p, 0x55, n); + memset(real_p, 0x00, n); + + free(real_p); +} + +static void *otrl_mem_realloc(void *p, size_t n) +{ + if (p == NULL) { + return otrl_mem_malloc(n); + } else if (n == 0) { + otrl_mem_free(p); + return NULL; + } else { + void *real_p = (void *)((char *)p - header_size); + void *new_p; + size_t old_n = ((size_t *)real_p)[0]; +#ifdef OTRL_MEM_MAGIC + size_t magic = ((size_t *)real_p)[1]; +#endif + size_t new_n = n; + new_n += header_size; + + /* Check for overflow attack */ + if (new_n < n) return NULL; + +#ifdef OTRL_MEM_MAGIC + if (magic != OTRL_MEM_MAGIC) { + fprintf(stderr, "Illegal realloc!\n"); + return NULL; + } +#endif + + if (new_n < old_n) { + /* Overwrite the space we're about to stop using */ + void *p = (void *)((char *)real_p + new_n); + size_t excess = old_n - new_n; + memset(p, 0xff, excess); + memset(p, 0xaa, excess); + memset(p, 0x55, excess); + memset(p, 0x00, excess); + + /* We don't actually need to realloc() */ + new_p = real_p; + } else { + new_p = realloc(real_p, new_n); + if (new_p == NULL) return NULL; + } + + ((size_t *)new_p)[0] = new_n; /* Includes header size */ + return (void *)((char *)new_p + header_size); + } +} + +void otrl_mem_init(void) +{ + header_size = 8; +#ifdef OTRL_MEM_MAGIC + if (header_size < 2*sizeof(size_t)) { + header_size = 2*sizeof(size_t); + } +#else + if (header_size < sizeof(size_t)) { + header_size = sizeof(size_t); + } +#endif + + gcry_set_allocation_handler( + otrl_mem_malloc, + otrl_mem_malloc, + otrl_mem_is_secure, + otrl_mem_realloc, + otrl_mem_free + ); +} + +/* Compare two memory blocks in time dependent on the length of the + * blocks, but not their contents. Returns 1 if they differ, 0 if they + * are the same. */ +int otrl_mem_differ(const unsigned char *buf1, const unsigned char *buf2, + size_t len) +{ + volatile unsigned char diff = 0; + size_t i; + + for (i = 0; i < len; ++i) { + diff |= (buf1[i] ^ buf2[i]); + } + return (diff != 0); +} diff --git a/comm/third_party/libotr/src/mem.h b/comm/third_party/libotr/src/mem.h new file mode 100644 index 0000000000..2baf8f2e9a --- /dev/null +++ b/comm/third_party/libotr/src/mem.h @@ -0,0 +1,35 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __MEM_H__ +#define __MEM_H__ + +#include + +void otrl_mem_init(void); + +/* Compare two memory blocks in time dependent on the length of the + * blocks, but not their contents. Returns 1 if they differ, 0 if they + * are the same. */ +int otrl_mem_differ(const unsigned char *buf1, const unsigned char *buf2, + size_t len); + +#endif diff --git a/comm/third_party/libotr/src/message.c b/comm/third_party/libotr/src/message.c new file mode 100644 index 0000000000..c44ce7b8fc --- /dev/null +++ b/comm/third_party/libotr/src/message.c @@ -0,0 +1,2058 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2015 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "privkey.h" +#include "userstate.h" +#include "proto.h" +#include "auth.h" +#include "message.h" +#include "sm.h" +#include "instag.h" + +#if OTRL_DEBUGGING +#include + +/* If OTRL_DEBUGGING is on, and the user types this string, the current + * context and its siblings will be dumped to stderr. */ +const char *OTRL_DEBUGGING_DEBUGSTR = "?OTR!"; + +void otrl_context_all_dump(FILE *f, OtrlUserState us); +void otrl_context_siblings_dump(FILE *f, const ConnContext *context); +#endif + +/* The API version */ +extern unsigned int otrl_api_version; + +/* How long after sending a packet should we wait to send a heartbeat? */ +#define HEARTBEAT_INTERVAL 60 + +/* How old are messages allowed to be in order to be candidates for + * resending in response to a rekey? */ +#define RESEND_INTERVAL 60 + +/* How long should we wait for the last of the logged-in instances of + * our buddy to respond before marking our private key as a candidate + * for wiping (in seconds)? */ +#define MAX_AKE_WAIT_TIME 60 + +/* How frequently should we check our ConnContexts for wipeable private + * keys (and wipe them) (in seconds)? */ +#define POLL_DEFAULT_INTERVAL 70 + +/* Send a message to the network, fragmenting first if necessary. + * All messages to be sent to the network should go through this + * method immediately before they are sent, ie after encryption. */ +static gcry_error_t fragment_and_send(const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context, const char *message, + OtrlFragmentPolicy fragPolicy, char **returnFragment) +{ + int mms = 0; + + if (message && ops->inject_message) { + int msglen; + + if (ops->max_message_size) { + mms = ops->max_message_size(opdata, context); + } + msglen = strlen(message); + + /* Don't incur overhead of fragmentation unless necessary */ + if(mms != 0 && msglen > mms) { + char **fragments; + gcry_error_t err; + int i; + int headerlen = context->protocol_version == 3 ? 37 : 19; + /* Like ceil(msglen/(mms - headerlen)) */ + int fragment_count = ((msglen - 1) / (mms - headerlen)) + 1; + + err = otrl_proto_fragment_create(mms, fragment_count, &fragments, + context, message); + if (err) { + return err; + } + + /* Determine which fragments to send and which to return + * based on given Fragment Policy. If the first fragment + * should be returned instead of sent, store it. */ + if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_FIRST) { + *returnFragment = strdup(fragments[0]); + } else { + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, fragments[0]); + } + for (i=1; iinject_message(opdata, context->accountname, + context->protocol, context->username, fragments[i]); + } + /* If the last fragment should be stored instead of sent, + * store it */ + if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_LAST) { + *returnFragment = strdup(fragments[fragment_count-1]); + } else { + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, + fragments[fragment_count-1]); + } + /* Now free all fragment memory */ + otrl_proto_fragment_free(&fragments, fragment_count); + + } else { + /* No fragmentation necessary */ + if (fragPolicy == OTRL_FRAGMENT_SEND_ALL) { + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, message); + } else { + /* Copy and return the entire given message. */ + *returnFragment = strdup(message); + } + } + } + + return gcry_error(GPG_ERR_NO_ERROR); +} + +static void populate_context_instag(OtrlUserState us, const OtrlMessageAppOps + *ops, void *opdata, const char *accountname, const char *protocol, + ConnContext *context) { + OtrlInsTag *p_instag; + + p_instag = otrl_instag_find(us, accountname, protocol); + if ((!p_instag) && ops->create_instag) { + ops->create_instag(opdata, accountname, protocol); + p_instag = otrl_instag_find(us, accountname, protocol); + } + + if (p_instag && p_instag->instag >= OTRL_MIN_VALID_INSTAG) { + context->our_instance = p_instag->instag; + } else { + context->our_instance = otrl_instag_get_new(); + } +} + +/* Deallocate a message allocated by other otrl_message_* routines. */ +void otrl_message_free(char *message) +{ + free(message); +} + +/* Handle a message about to be sent to the network. It is safe to pass + * all messages about to be sent to this routine. add_appdata is a + * function that will be called in the event that a new ConnContext is + * created. It will be passed the data that you supplied, as well as a + * pointer to the new ConnContext. You can use this to add + * application-specific information to the ConnContext using the + * "context->app" field, for example. If you don't need to do this, you + * can pass NULL for the last two arguments of otrl_message_sending. + * + * tlvs is a chain of OtrlTLVs to append to the private message. It is + * usually correct to just pass NULL here. + * + * If non-NULL, ops->convert_msg will be called just before encrypting a + * message. + * + * "instag" specifies the instance tag of the buddy (protocol version 3 only). + * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE). + * If "contextp" is not NULL, it will be set to the ConnContext used for + * sending the message. + * + * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP + * as the OtrlFragmentPolicy. In this case, this function will assign *messagep + * with the encrypted msg. If the routine returns non-zero, then the library + * tried to encrypt the message, but for some reason failed. DO NOT send the + * message in the clear in that case. If *messagep gets set by the call to + * something non-NULL, then you should replace your message with the contents + * of *messagep, and send that instead. + * + * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL, + * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In + * these cases, the appropriate fragments will be automatically sent. For the + * last two policies, the remaining fragment will be passed in *original_msg. + * + * Call otrl_message_free(*messagep) if you don't need *messagep or when you're + * done with it. */ +gcry_error_t otrl_message_sending(OtrlUserState us, + const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *recipient, otrl_instag_t their_instag, + const char *original_msg, OtrlTLV *tlvs, char **messagep, + OtrlFragmentPolicy fragPolicy, ConnContext **contextp, + void (*add_appdata)(void *data, ConnContext *context), + void *data) +{ + ConnContext * context = NULL; + char * msgtosend; + const char * err_msg; + gcry_error_t err_code, err; + OtrlPolicy policy = OTRL_POLICY_DEFAULT; + int context_added = 0; + int convert_called = 0; + char *converted_msg = NULL; + + if (messagep) { + *messagep = NULL; + } + + err = gcry_error(GPG_ERR_NO_ERROR); /* Default to no error */ + + if (contextp) { + *contextp = NULL; + } + + if (!accountname || !protocol || !recipient || + !original_msg || !messagep) { + err = gcry_error(GPG_ERR_INV_VALUE); + goto fragment; + } + + /* See if we have a fingerprint for this user */ + context = otrl_context_find(us, recipient, accountname, protocol, + their_instag, 1, &context_added, add_appdata, data); + + /* Update the context list if we added one */ + if (context_added && ops->update_context_list) { + ops->update_context_list(opdata); + } + + /* Find or generate the instance tag if needed */ + if (!context->our_instance) { + populate_context_instag(us, ops, opdata, accountname, protocol, + context); + } + + if (contextp) { + *contextp = context; + } + + /* Check the policy */ + if (ops->policy) { + policy = ops->policy(opdata, context); + } + + /* Should we go on at all? */ + if ((policy & OTRL_POLICY_VERSION_MASK) == 0) { + err = gcry_error(GPG_ERR_NO_ERROR); + goto fragment; + } + +#if OTRL_DEBUGGING + /* If the user typed the magic debug string, dump this context and + * its siblings. */ + { + const char *debugtag = strstr(original_msg, OTRL_DEBUGGING_DEBUGSTR); + + if (debugtag) { + const char *debugargs = + debugtag + strlen(OTRL_DEBUGGING_DEBUGSTR); + if (debugargs[0] == '!') { /* typed ?OTR!! */ + otrl_context_all_dump(stderr, us); + } else { /* typed ?OTR! without extra command chars */ + otrl_context_siblings_dump(stderr, context); + } + + /* Don't actually send the message */ + *messagep = strdup(""); + if (!(*messagep)) { + err = gcry_error(GPG_ERR_ENOMEM); + } + goto fragment; + } + } +#endif + + /* If this is an OTR Query message, don't encrypt it. */ + if (otrl_proto_message_type(original_msg) == OTRL_MSGTYPE_QUERY) { + /* Replace the "?OTR?" with a custom message */ + char *bettermsg = otrl_proto_default_query_msg(accountname, policy); + if (bettermsg) { + *messagep = bettermsg; + } + context->otr_offer = OFFER_SENT; + err = gcry_error(GPG_ERR_NO_ERROR); + goto fragment; + } + + /* What is the current message disposition? */ + switch(context->msgstate) { + + case OTRL_MSGSTATE_PLAINTEXT: + if ((policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) { + /* We're trying to send an unencrypted message with a policy + * that disallows that. Don't do that, but try to start + * up OTR instead. */ + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_ENCRYPTION_REQUIRED, + context, NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + + context->context_priv->lastmessage = + gcry_malloc_secure(strlen(original_msg) + 1); + if (context->context_priv->lastmessage) { + char *bettermsg = otrl_proto_default_query_msg(accountname, + policy); + strcpy(context->context_priv->lastmessage, original_msg); + context->context_priv->lastsent = time(NULL); + otrl_context_update_recent_child(context, 1); + context->context_priv->may_retransmit = 2; + if (bettermsg) { + *messagep = bettermsg; + context->otr_offer = OFFER_SENT; + } else { + err = gcry_error(GPG_ERR_ENOMEM); + goto fragment; + } + } + } else { + if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG) && + context->otr_offer != OFFER_REJECTED) { + /* See if this user can speak OTR. Append the + * OTR_MESSAGE_TAG to the plaintext message, and see + * if he responds. */ + size_t msglen = strlen(original_msg); + size_t basetaglen = strlen(OTRL_MESSAGE_TAG_BASE); + size_t v1taglen = (policy & OTRL_POLICY_ALLOW_V1) ? + strlen(OTRL_MESSAGE_TAG_V1) : 0; + size_t v2taglen = (policy & OTRL_POLICY_ALLOW_V2) ? + strlen(OTRL_MESSAGE_TAG_V2) : 0; + size_t v3taglen = (policy & OTRL_POLICY_ALLOW_V3) ? + strlen(OTRL_MESSAGE_TAG_V3) : 0; + char *taggedmsg = malloc(msglen + basetaglen + v1taglen + + v2taglen + v3taglen + 1); + if (taggedmsg) { + strcpy(taggedmsg, original_msg); + strcpy(taggedmsg + msglen, OTRL_MESSAGE_TAG_BASE); + if (v1taglen) { + strcpy(taggedmsg + msglen + basetaglen, + OTRL_MESSAGE_TAG_V1); + } + if (v2taglen) { + strcpy(taggedmsg + msglen + basetaglen + v1taglen, + OTRL_MESSAGE_TAG_V2); + } + if (v3taglen) { + strcpy(taggedmsg + msglen + basetaglen + v1taglen + + v2taglen, OTRL_MESSAGE_TAG_V3); + } + *messagep = taggedmsg; + context->otr_offer = OFFER_SENT; + } + } + } + break; + case OTRL_MSGSTATE_ENCRYPTED: + /* convert the original message if necessary */ + if (ops->convert_msg) { + ops->convert_msg(opdata, context, OTRL_CONVERT_SENDING, + &converted_msg, original_msg); + + if (converted_msg) { + convert_called = 1; + } + } + + /* Create the new, encrypted message */ + if (convert_called) { + err_code = otrl_proto_create_data(&msgtosend, context, + converted_msg, tlvs, 0, NULL); + + if (ops->convert_free) { + ops->convert_free(opdata, context, converted_msg); + converted_msg = NULL; + } + } else { + err_code = otrl_proto_create_data(&msgtosend, context, + original_msg, tlvs, 0, NULL); + } + if (!err_code) { + context->context_priv->lastsent = time(NULL); + otrl_context_update_recent_child(context, 1); + *messagep = msgtosend; + } else { + /* Uh, oh. Whatever we do, *don't* send the message in the + * clear. */ + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_ENCRYPTION_ERROR, + context, NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + if (ops->otr_error_message) { + err_msg = ops->otr_error_message(opdata, context, + OTRL_ERRCODE_ENCRYPTION_ERROR); + *messagep = malloc(strlen(OTR_ERROR_PREFIX) + + strlen(err_msg) + 1); + if (*messagep) { + strcpy(*messagep, OTR_ERROR_PREFIX); + strcat(*messagep, err_msg); + } + if (ops->otr_error_message_free) { + ops->otr_error_message_free(opdata, err_msg); + } + if (!(*messagep)) { + err = gcry_error(GPG_ERR_ENOMEM); + goto fragment; + } + } + } + break; + case OTRL_MSGSTATE_FINISHED: + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, OTRL_MSGEVENT_CONNECTION_ENDED, + context, NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + *messagep = strdup(""); + if (!(*messagep)) { + err = gcry_error(GPG_ERR_ENOMEM); + goto fragment; + } + break; + } + +fragment: + if (fragPolicy == OTRL_FRAGMENT_SEND_SKIP ) { + /* Do not fragment/inject. Default behaviour of libotr3.2.0 */ + return err; + } else { + /* Fragment and send according to policy */ + if (!err && messagep && *messagep) { + if (context) { + char *rmessagep = NULL; + err = fragment_and_send(ops, opdata, context, *messagep, + fragPolicy, &rmessagep); + if (rmessagep) { + /* Free the current message pointer and return back the + * returned fragmented one. */ + free(*messagep); + *messagep = rmessagep; + } + } + } + return err; + } +} + +/* If err == 0, send the last auth message for the given context to the + * appropriate user. Otherwise, display an appripriate error dialog. + * Return the value of err that was passed. */ +static gcry_error_t send_or_error_auth(const OtrlMessageAppOps *ops, + void *opdata, gcry_error_t err, ConnContext *context, + OtrlUserState us) +{ + if (!err) { + const char *msg = context->auth.lastauthmsg; + if (msg && *msg) { + fragment_and_send(ops, opdata, context, msg, + OTRL_FRAGMENT_SEND_ALL, NULL); + time_t now = time(NULL); + /* Update the "last sent" fields, unless this is a version 3 + * message typing to update the master context (as happens + * when sending a v3 COMMIT message, for example). */ + if (context != context->m_context || + context->auth.protocol_version != 3) { + context->context_priv->lastsent = now; + otrl_context_update_recent_child(context, 1); + } + + /* If this is a master context, and we're sending a v3 COMMIT + * message, update the commit_sent_time timestamp, so we can + * expire it. */ + if (context == context->m_context && + context->auth.authstate == OTRL_AUTHSTATE_AWAITING_DHKEY && + context->auth.protocol_version == 3) { + context->auth.commit_sent_time = now; + /* If there's not already a timer running to clean up + * this private key, try to start one. */ + if (us->timer_running == 0 && ops && ops->timer_control) { + ops->timer_control(opdata, POLL_DEFAULT_INTERVAL); + us->timer_running = 1; + } + } + } + } else { + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, OTRL_MSGEVENT_SETUP_ERROR, + context, NULL, err); + } + } + return err; +} + +typedef struct { + int gone_encrypted; + OtrlUserState us; + const OtrlMessageAppOps *ops; + void *opdata; + ConnContext *context; + int ignore_message; + char **messagep; +} EncrData; + +static gcry_error_t go_encrypted(const OtrlAuthInfo *auth, void *asdata) +{ + EncrData *edata = asdata; + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + Fingerprint *found_print = NULL; + int fprint_added = 0; + OtrlMessageState oldstate = edata->context->msgstate; + Fingerprint *oldprint = edata->context->active_fingerprint; + + /* See if we're talking to ourselves */ + if (!gcry_mpi_cmp(auth->their_pub, auth->our_dh.pub)) { + /* Yes, we are. */ + if (edata->ops->handle_msg_event) { + edata->ops->handle_msg_event(edata->opdata, + OTRL_MSGEVENT_MSG_REFLECTED, edata->context, + NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + edata->ignore_message = 1; + return gcry_error(GPG_ERR_NO_ERROR); + } + + found_print = otrl_context_find_fingerprint(edata->context, + edata->context->auth.their_fingerprint, 1, &fprint_added); + + if (fprint_added) { + /* Inform the user of the new fingerprint */ + if (edata->ops->new_fingerprint) { + edata->ops->new_fingerprint(edata->opdata, edata->us, + edata->context->accountname, edata->context->protocol, + edata->context->username, + edata->context->auth.their_fingerprint); + } + /* Arrange that the new fingerprint be written to disk */ + if (edata->ops->write_fingerprints) { + edata->ops->write_fingerprints(edata->opdata); + } + } + + /* Is this a new session or just a refresh of an existing one? */ + if (edata->context->msgstate == OTRL_MSGSTATE_ENCRYPTED && + oldprint == found_print && + edata->context->context_priv->our_keyid - 1 == + edata->context->auth.our_keyid && + !gcry_mpi_cmp(edata->context->context_priv->our_old_dh_key.pub, + edata->context->auth.our_dh.pub) && + ((edata->context->context_priv->their_keyid > 0 && + edata->context->context_priv->their_keyid == + edata->context->auth.their_keyid && + !gcry_mpi_cmp(edata->context->context_priv->their_y, + edata->context->auth.their_pub)) || + (edata->context->context_priv->their_keyid > 1 && + edata->context->context_priv->their_keyid - 1 == + edata->context->auth.their_keyid && + edata->context->context_priv->their_old_y != NULL && + !gcry_mpi_cmp(edata->context->context_priv->their_old_y, + edata->context->auth.their_pub)))) { + /* This is just a refresh of the existing session. */ + if (edata->ops->still_secure) { + edata->ops->still_secure(edata->opdata, edata->context, + edata->context->auth.initiated); + } + edata->ignore_message = 1; + return gcry_error(GPG_ERR_NO_ERROR); + } + + /* Copy the information from the auth into the context */ + memmove(edata->context->sessionid, + edata->context->auth.secure_session_id, 20); + edata->context->sessionid_len = + edata->context->auth.secure_session_id_len; + edata->context->sessionid_half = + edata->context->auth.session_id_half; + edata->context->protocol_version = + edata->context->auth.protocol_version; + + edata->context->context_priv->their_keyid = + edata->context->auth.their_keyid; + gcry_mpi_release(edata->context->context_priv->their_y); + gcry_mpi_release(edata->context->context_priv->their_old_y); + edata->context->context_priv->their_y = + gcry_mpi_copy(edata->context->auth.their_pub); + edata->context->context_priv->their_old_y = NULL; + + if (edata->context->context_priv->our_keyid - 1 != + edata->context->auth.our_keyid || + gcry_mpi_cmp(edata->context->context_priv->our_old_dh_key.pub, + edata->context->auth.our_dh.pub)) { + otrl_dh_keypair_free(&(edata->context->context_priv->our_dh_key)); + otrl_dh_keypair_free(&(edata->context->context_priv->our_old_dh_key)); + otrl_dh_keypair_copy(&(edata->context->context_priv->our_old_dh_key), + &(edata->context->auth.our_dh)); + otrl_dh_gen_keypair( + edata->context->context_priv->our_old_dh_key.groupid, + &(edata->context->context_priv->our_dh_key)); + edata->context->context_priv->our_keyid = edata->context->auth.our_keyid + + 1; + } + + /* Create the session keys from the DH keys */ + otrl_dh_session_free(&(edata->context->context_priv->sesskeys[0][0])); + err = otrl_dh_session(&(edata->context->context_priv->sesskeys[0][0]), + &(edata->context->context_priv->our_dh_key), + edata->context->context_priv->their_y); + if (err) return err; + otrl_dh_session_free(&(edata->context->context_priv->sesskeys[1][0])); + err = otrl_dh_session(&(edata->context->context_priv->sesskeys[1][0]), + &(edata->context->context_priv->our_old_dh_key), + edata->context->context_priv->their_y); + if (err) return err; + + edata->context->context_priv->generation++; + edata->context->active_fingerprint = found_print; + edata->context->msgstate = OTRL_MSGSTATE_ENCRYPTED; + + if (edata->ops->update_context_list) { + edata->ops->update_context_list(edata->opdata); + } + if (oldstate == OTRL_MSGSTATE_ENCRYPTED && oldprint == found_print) { + if (edata->ops->still_secure) { + edata->ops->still_secure(edata->opdata, edata->context, + edata->context->auth.initiated); + } + } else { + if (edata->ops->gone_secure) { + edata->ops->gone_secure(edata->opdata, edata->context); + } + } + + edata->gone_encrypted = 1; + + return gpg_error(GPG_ERR_NO_ERROR); +} + +static void maybe_resend(EncrData *edata) +{ + gcry_error_t err; + time_t now; + + if (!edata->gone_encrypted) return; + + /* See if there's a message we sent recently that should be resent. */ + now = time(NULL); + if (edata->context->context_priv->lastmessage != NULL && + edata->context->context_priv->may_retransmit && + edata->context->context_priv->lastsent >= (now - RESEND_INTERVAL)) { + char *resendmsg; + char *msg_to_send; + int resending = (edata->context->context_priv->may_retransmit == 1); + + /* Initialize msg_to_send */ + if (resending) { + const char *resent_prefix; + int used_ops_resentmp = 1; + resent_prefix = edata->ops->resent_msg_prefix ? + edata->ops->resent_msg_prefix(edata->opdata, + edata->context) : NULL; + if (!resent_prefix) { + resent_prefix = "[resent]"; /* Assign default prefix */ + used_ops_resentmp = 0; + } + msg_to_send = malloc( + strlen(edata->context->context_priv->lastmessage) + + strlen(resent_prefix) + 2); + if (msg_to_send) { + strcpy(msg_to_send, resent_prefix); + strcat(msg_to_send, " "); + strcat(msg_to_send, edata->context->context_priv->lastmessage); + } else { + return; /* Out of memory; don't try to resend */ + } + if (used_ops_resentmp) { + edata->ops->resent_msg_prefix_free(edata->opdata, + resent_prefix); + } + } else { + msg_to_send = edata->context->context_priv->lastmessage; + } + + /* Re-encrypt the message with the new keys */ + err = otrl_proto_create_data(&resendmsg, + edata->context, msg_to_send, NULL, 0, NULL); + if (resending) { + free(msg_to_send); + } + if (!err) { + /* Resend the message */ + fragment_and_send(edata->ops, edata->opdata, edata->context, + resendmsg, OTRL_FRAGMENT_SEND_ALL, NULL); + free(resendmsg); + edata->context->context_priv->lastsent = now; + otrl_context_update_recent_child(edata->context, 1); + if (resending) { + /* We're not sending it for the first time; let the user + * know we resent it */ + if (edata->ops->handle_msg_event) { + edata->ops->handle_msg_event(edata->opdata, + OTRL_MSGEVENT_MSG_RESENT, edata->context, + NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + } + edata->ignore_message = 1; + } + } +} + +/* Set the trust level based on the result of the SMP */ +static void set_smp_trust(const OtrlMessageAppOps *ops, void *opdata, + ConnContext *context, int trusted) +{ + otrl_context_set_trust(context->active_fingerprint, trusted ? "smp" : ""); + + /* Write the new info to disk, redraw the ui, and redraw the + * OTR buttons. */ + if (ops->write_fingerprints) { + ops->write_fingerprints(opdata); + } +} + +static void init_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context, const char *question, + const unsigned char *secret, size_t secretlen, int initiating) +{ + unsigned char *smpmsg = NULL; + int smpmsglen; + unsigned char combined_secret[SM_DIGEST_SIZE]; + gcry_error_t err; + unsigned char our_fp[20]; + unsigned char *combined_buf; + size_t combined_buf_len; + OtrlTLV *sendtlv; + char *sendsmp = NULL; + + if (!context || context->msgstate != OTRL_MSGSTATE_ENCRYPTED) return; + + /* + * Construct the combined secret as a SHA256 hash of: + * Version byte (0x01), Initiator fingerprint (20 bytes), + * responder fingerprint (20 bytes), secure session id, input secret + */ + otrl_privkey_fingerprint_raw(us, our_fp, context->accountname, + context->protocol); + + combined_buf_len = 41 + context->sessionid_len + secretlen; + combined_buf = malloc(combined_buf_len); + combined_buf[0] = 0x01; + if (initiating) { + memmove(combined_buf + 1, our_fp, 20); + memmove(combined_buf + 21, + context->active_fingerprint->fingerprint, 20); + } else { + memmove(combined_buf + 1, + context->active_fingerprint->fingerprint, 20); + memmove(combined_buf + 21, our_fp, 20); + } + memmove(combined_buf + 41, context->sessionid, + context->sessionid_len); + memmove(combined_buf + 41 + context->sessionid_len, + secret, secretlen); + gcry_md_hash_buffer(SM_HASH_ALGORITHM, combined_secret, combined_buf, + combined_buf_len); + free(combined_buf); + + if (initiating) { + otrl_sm_step1(context->smstate, combined_secret, SM_DIGEST_SIZE, + &smpmsg, &smpmsglen); + } else { + otrl_sm_step2b(context->smstate, combined_secret, SM_DIGEST_SIZE, + &smpmsg, &smpmsglen); + } + + /* If we've got a question, attach it to the smpmsg */ + if (question != NULL) { + size_t qlen = strlen(question); + unsigned char *qsmpmsg = malloc(qlen + 1 + smpmsglen); + if (!qsmpmsg) { + free(smpmsg); + return; + } + strcpy((char *)qsmpmsg, question); + memmove(qsmpmsg + qlen + 1, smpmsg, smpmsglen); + free(smpmsg); + smpmsg = qsmpmsg; + smpmsglen += qlen + 1; + } + + /* Send msg with next smp msg content */ + sendtlv = otrl_tlv_new(initiating ? + (question != NULL ? OTRL_TLV_SMP1Q : OTRL_TLV_SMP1) + : OTRL_TLV_SMP2, + smpmsglen, smpmsg); + err = otrl_proto_create_data(&sendsmp, context, "", sendtlv, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL); + if (!err) { + /* Send it, and set the next expected message to the + * logical response */ + err = fragment_and_send(ops, opdata, context, + sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL); + context->smstate->nextExpected = + initiating ? OTRL_SMP_EXPECT2 : OTRL_SMP_EXPECT3; + } + free(sendsmp); + otrl_tlv_free(sendtlv); + free(smpmsg); +} + +/* Initiate the Socialist Millionaires' Protocol */ +void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context, const unsigned char *secret, + size_t secretlen) +{ + init_respond_smp(us, ops, opdata, context, NULL, secret, secretlen, 1); +} + +/* Initiate the Socialist Millionaires' Protocol and send a prompt + * question to the buddy */ +void otrl_message_initiate_smp_q(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, + const char *question, const unsigned char *secret, size_t secretlen) +{ + init_respond_smp(us, ops, opdata, context, question, secret, secretlen, 1); +} + +/* Respond to a buddy initiating the Socialist Millionaires' Protocol */ +void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context, const unsigned char *secret, + size_t secretlen) +{ + init_respond_smp(us, ops, opdata, context, NULL, secret, secretlen, 0); +} + +/* Abort the SMP. Called when an unexpected SMP message breaks the + * normal flow. */ +void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context) +{ + OtrlTLV *sendtlv = otrl_tlv_new(OTRL_TLV_SMP_ABORT, 0, + (const unsigned char *)""); + char *sendsmp = NULL; + gcry_error_t err; + + context->smstate->nextExpected = OTRL_SMP_EXPECT1; + + err = otrl_proto_create_data(&sendsmp, + context, "", sendtlv, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL); + if (!err) { + /* Send the abort signal so our buddy knows we've stopped */ + err = fragment_and_send(ops, opdata, context, + sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL); + } + free(sendsmp); + otrl_tlv_free(sendtlv); +} + +static void message_malformed(const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context) { + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, OTRL_MSGEVENT_RCVDMSG_MALFORMED, context, + NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + + if (ops->inject_message && ops->otr_error_message) { + const char *err_msg = ops->otr_error_message(opdata, context, + OTRL_ERRCODE_MSG_MALFORMED); + + if (err_msg) { + char *buf = malloc(strlen(OTR_ERROR_PREFIX) + strlen(err_msg) + 1); + + if (buf) { + strcpy(buf, OTR_ERROR_PREFIX); + strcat(buf, err_msg); + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, buf); + free(buf); + } + + if (ops->otr_error_message_free) { + ops->otr_error_message_free(opdata, err_msg); + } + } + } +} + + +/* Handle a message just received from the network. It is safe to pass + * all received messages to this routine. add_appdata is a function + * that will be called in the event that a new ConnContext is created. + * It will be passed the data that you supplied, as well as + * a pointer to the new ConnContext. You can use this to add + * application-specific information to the ConnContext using the + * "context->app" field, for example. If you don't need to do this, you + * can pass NULL for the last two arguments of otrl_message_receiving. + * + * If non-NULL, ops->convert_msg will be called after a data message is + * decrypted. + * + * If "contextp" is not NULL, it will be set to the ConnContext used for + * receiving the message. + * + * If otrl_message_receiving returns 1, then the message you received + * was an internal protocol message, and no message should be delivered + * to the user. + * + * If it returns 0, then check if *messagep was set to non-NULL. If + * so, replace the received message with the contents of *messagep, and + * deliver that to the user instead. You must call + * otrl_message_free(*messagep) when you're done with it. If tlvsp is + * non-NULL, *tlvsp will be set to a chain of any TLVs that were + * transmitted along with this message. You must call + * otrl_tlv_free(*tlvsp) when you're done with those. + * + * If otrl_message_receiving returns 0 and *messagep is NULL, then this + * was an ordinary, non-OTR message, which should just be delivered to + * the user without modification. */ +int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *sender, const char *message, char **newmessagep, + OtrlTLV **tlvsp, ConnContext **contextp, + void (*add_appdata)(void *data, ConnContext *context), + void *data) +{ + ConnContext *context, *m_context, *best_context; + OtrlMessageType msgtype; + int context_added = 0; + OtrlPolicy policy = OTRL_POLICY_DEFAULT; + char *unfragmessage = NULL, *otrtag = NULL; + EncrData edata; + otrl_instag_t our_instance = 0, their_instance = 0; + int version; + gcry_error_t err; + + if (!accountname || !protocol || !sender || !message || !newmessagep) + return 0; + + *newmessagep = NULL; + if (tlvsp) *tlvsp = NULL; + + if (contextp) { + *contextp = NULL; + } + + /* Find the master context and state with this correspondent */ + m_context = otrl_context_find(us, sender, accountname, + protocol, OTRL_INSTAG_MASTER, 1, &context_added, add_appdata, data); + context = m_context; + + /* Update the context list if we added one */ + if (context_added && ops->update_context_list) { + ops->update_context_list(opdata); + } + + best_context = otrl_context_find(us, sender, accountname, + protocol, OTRL_INSTAG_BEST, 0, NULL, add_appdata, data); + + /* Find or generate the instance tag if needed */ + if (!context->our_instance) { + populate_context_instag(us, ops, opdata, accountname, protocol, + context); + } + + + /* Check the policy */ + if (ops->policy) { + policy = ops->policy(opdata, context); + } + + /* Should we go on at all? */ + if ((policy & OTRL_POLICY_VERSION_MASK) == 0) { + return 0; + } + + otrtag = strstr(message, "?OTR"); + if (otrtag) { + /* See if we have a V3 fragment. The '4' in the next line is + * strlen("?OTR"). otrtag[4] is the character immediately after + * the "?OTR", and is guaranteed to exist, because in the worst + * case, it is the NUL terminating 'message'. */ + if (otrtag[4] == '|') { + /* Get the instance tag from fragment header*/ + sscanf(otrtag, "?OTR|%x|%x,", &their_instance, &our_instance); + /* Ignore message if it is intended for a different instance */ + if (our_instance && context->our_instance != our_instance) { + + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE, + m_context, NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + return 1; + } + /* Get the context for this instance */ + if (their_instance >= OTRL_MIN_VALID_INSTAG) { + context = otrl_context_find(us, sender, accountname, + protocol, their_instance, 1, &context_added, + add_appdata, data); + } else { + message_malformed(ops, opdata, context); + return 1; + } + } + switch(otrl_proto_fragment_accumulate(&unfragmessage, + context, message)) { + case OTRL_FRAGMENT_UNFRAGMENTED: + /* Do nothing */ + break; + case OTRL_FRAGMENT_INCOMPLETE: + /* We've accumulated this fragment, but we don't have a + * complete message yet */ + return 1; + case OTRL_FRAGMENT_COMPLETE: + /* We've got a new complete message, in unfragmessage. */ + message = unfragmessage; + otrtag = strstr(message, "?OTR"); + break; + } + } + + /* What type of message is it? Note that this just checks the + * header; it's not necessarily a _valid_ message of this type. */ + msgtype = otrl_proto_message_type(message); + version = otrl_proto_message_version(message); + + /* See if they responded to our OTR offer */ + if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG)) { + if (msgtype != OTRL_MSGTYPE_NOTOTR) { + context->otr_offer = OFFER_ACCEPTED; + } else if (context->otr_offer == OFFER_SENT) { + context->otr_offer = OFFER_REJECTED; + } + } + + /* Check that this version is allowed by the policy */ + if (((version == 3) && !(policy & OTRL_POLICY_ALLOW_V3)) + || ((version == 2) && !(policy & OTRL_POLICY_ALLOW_V2)) + || ((version == 1) && !(policy & OTRL_POLICY_ALLOW_V1))) { + edata.ignore_message = 1; + goto end; + } + /* Check the to and from instance tags */ + if (version == 3) { + err = gcry_error(GPG_ERR_INV_VALUE); + if (otrtag) { + err = otrl_proto_instance(otrtag, &their_instance, &our_instance); + } + if (!err) { + if ((msgtype == OTRL_MSGTYPE_DH_COMMIT && our_instance && + context->our_instance != our_instance) || + (msgtype != OTRL_MSGTYPE_DH_COMMIT && + context->our_instance != our_instance)) { + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE, + m_context, NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + /* ignore message intended for a different instance */ + edata.ignore_message = 1; + goto end; + } + + if (their_instance >= OTRL_MIN_VALID_INSTAG) { + context = otrl_context_find(us, sender, accountname, + protocol, their_instance, 1, &context_added, + add_appdata, data); + } + } + + if (err || their_instance < OTRL_MIN_VALID_INSTAG) { + message_malformed(ops, opdata, context); + edata.ignore_message = 1; + goto end; + } + + if (context_added) { + /* Context added because of new instance (either here or when + * accumulating fragments */ + /* Copy information from m_context to the new instance context */ + context->auth.protocol_version = 3; + context->protocol_version = 3; + context->msgstate = m_context->msgstate; + + if (m_context->context_priv->may_retransmit) { + gcry_free(context->context_priv->lastmessage); + context->context_priv->lastmessage = m_context->context_priv->lastmessage; + m_context->context_priv->lastmessage = NULL; + context->context_priv->may_retransmit = m_context->context_priv->may_retransmit; + m_context->context_priv->may_retransmit = 0; + } + + if (msgtype == OTRL_MSGTYPE_DH_KEY) { + otrl_auth_copy_on_key(&(m_context->auth), &(context->auth)); + } else if (msgtype != OTRL_MSGTYPE_DH_COMMIT) { + edata.ignore_message = 1; + goto end; + } + + /* Update the context list */ + if (ops->update_context_list) { + ops->update_context_list(opdata); + } + } else if (m_context != context) { + /* Switching from m_context to existing instance context */ + if (msgtype == OTRL_MSGTYPE_DH_KEY && m_context->auth.authstate + == OTRL_AUTHSTATE_AWAITING_DHKEY && + !(context->auth.authstate == + OTRL_AUTHSTATE_AWAITING_DHKEY)) { + context->msgstate = m_context->msgstate; + context->auth.protocol_version = 3; + context->protocol_version = 3; + otrl_auth_copy_on_key(&(m_context->auth), &(context->auth)); + } + } + } + + if (contextp) { + *contextp = context; + } + + /* update time of last received message */ + context->context_priv->lastrecv = time(NULL); + otrl_context_update_recent_child(context, 0); + + edata.gone_encrypted = 0; + edata.us = us; + edata.context = context; + edata.ops = ops; + edata.opdata = opdata; + edata.ignore_message = -1; + edata.messagep = newmessagep; + + switch(msgtype) { + unsigned int bestversion; + const char *startwhite, *endwhite; + DH_keypair *our_dh; + unsigned int our_keyid; + OtrlPrivKey *privkey; + int haveauthmsg; + + case OTRL_MSGTYPE_QUERY: + /* See if we should use an existing DH keypair, or generate + * a fresh one. */ + if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { + our_dh = &(context->context_priv->our_old_dh_key); + our_keyid = context->context_priv->our_keyid - 1; + } else { + our_dh = NULL; + our_keyid = 0; + } + + /* Find the best version of OTR that we both speak */ + switch(otrl_proto_query_bestversion(message, policy)) { + case 3: + err = otrl_auth_start_v23(&(context->auth), 3); + send_or_error_auth(ops, opdata, err, context, us); + break; + case 2: + err = otrl_auth_start_v23(&(context->auth), 2); + send_or_error_auth(ops, opdata, err, context, us); + break; + case 1: + /* Get our private key */ + privkey = otrl_privkey_find(us, context->accountname, + context->protocol); + if (privkey == NULL) { + /* We've got no private key! */ + if (ops->create_privkey) { + ops->create_privkey(opdata, context->accountname, + context->protocol); + privkey = otrl_privkey_find(us, + context->accountname, context->protocol); + } + } + if (privkey) { + err = otrl_auth_start_v1(&(context->auth), our_dh, + our_keyid, privkey); + send_or_error_auth(ops, opdata, err, context, us); + } + break; + default: + /* Just ignore this message */ + break; + } + /* Don't display the Query message to the user. */ + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + + case OTRL_MSGTYPE_DH_COMMIT: + err = otrl_auth_handle_commit(&(context->auth), otrtag, version); + send_or_error_auth(ops, opdata, err, context, us); + + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + + case OTRL_MSGTYPE_DH_KEY: + /* Get our private key */ + privkey = otrl_privkey_find(us, context->accountname, + context->protocol); + if (privkey == NULL) { + /* We've got no private key! */ + if (ops->create_privkey) { + ops->create_privkey(opdata, context->accountname, + context->protocol); + privkey = otrl_privkey_find(us, + context->accountname, context->protocol); + } + } + if (privkey) { + err = otrl_auth_handle_key(&(context->auth), otrtag, + &haveauthmsg, privkey); + if (err || haveauthmsg) { + send_or_error_auth(ops, opdata, err, context, us); + } + } + + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + + case OTRL_MSGTYPE_REVEALSIG: + /* Get our private key */ + privkey = otrl_privkey_find(us, context->accountname, + context->protocol); + if (privkey == NULL) { + /* We've got no private key! */ + if (ops->create_privkey) { + ops->create_privkey(opdata, context->accountname, + context->protocol); + privkey = otrl_privkey_find(us, + context->accountname, context->protocol); + } + } + if (privkey) { + err = otrl_auth_handle_revealsig(&(context->auth), + otrtag, &haveauthmsg, privkey, go_encrypted, + &edata); + if (err || haveauthmsg) { + send_or_error_auth(ops, opdata, err, context, us); + maybe_resend(&edata); + } + } + + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + + case OTRL_MSGTYPE_SIGNATURE: + err = otrl_auth_handle_signature(&(context->auth), + otrtag, &haveauthmsg, go_encrypted, &edata); + if (err || haveauthmsg) { + send_or_error_auth(ops, opdata, err, context, us); + maybe_resend(&edata); + } + + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + + case OTRL_MSGTYPE_V1_KEYEXCH: + /* See if we should use an existing DH keypair, or generate + * a fresh one. */ + if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { + our_dh = &(context->context_priv->our_old_dh_key); + our_keyid = context->context_priv->our_keyid - 1; + } else { + our_dh = NULL; + our_keyid = 0; + } + + /* Get our private key */ + privkey = otrl_privkey_find(us, context->accountname, + context->protocol); + if (privkey == NULL) { + /* We've got no private key! */ + if (ops->create_privkey) { + ops->create_privkey(opdata, context->accountname, + context->protocol); + privkey = otrl_privkey_find(us, context->accountname, + context->protocol); + } + } + if (privkey) { + err = otrl_auth_handle_v1_key_exchange(&(context->auth), + message, &haveauthmsg, privkey, our_dh, our_keyid, + go_encrypted, &edata); + if (err || haveauthmsg) { + send_or_error_auth(ops, opdata, err, context, us); + maybe_resend(&edata); + } + } + + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + + case OTRL_MSGTYPE_DATA: + switch(context->msgstate) { + gcry_error_t err; + OtrlTLV *tlvs, *tlv; + char *plaintext; + char *buf; + const char *err_msg; + unsigned char *extrakey; + unsigned char flags; + NextExpectedSMP nextMsg; + + case OTRL_MSGSTATE_PLAINTEXT: + case OTRL_MSGSTATE_FINISHED: + /* See if we're supposed to ignore this message in + * the event it's unreadable. */ + err = otrl_proto_data_read_flags(message, &flags); + if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) { + edata.ignore_message = 1; + break; + } + + if(best_context && best_context != context && + best_context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { + + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE, + m_context, NULL, + gcry_error(GPG_ERR_NO_ERROR)); + } + } else if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE, + context, NULL, + gcry_error(GPG_ERR_NO_ERROR)); + } + edata.ignore_message = 1; + + /* We don't actually want to send anything in this case, + since this could just be a message intended for another + v2 instance. We still notify the local user though */ + break; + + case OTRL_MSGSTATE_ENCRYPTED: + extrakey = gcry_malloc_secure(OTRL_EXTRAKEY_BYTES); + err = otrl_proto_accept_data(&plaintext, &tlvs, context, + message, &flags, extrakey); + if (err) { + int is_conflict = + (gpg_err_code(err) == GPG_ERR_CONFLICT); + if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) { + edata.ignore_message = 1; + break; + } + if (is_conflict) { + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_UNREADABLE, + context, NULL, + gcry_error(GPG_ERR_NO_ERROR)); + } + } else { + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_MALFORMED, + context, NULL, + gcry_error(GPG_ERR_NO_ERROR)); + } + } + if (ops->inject_message && ops->otr_error_message) { + err_msg = ops->otr_error_message(opdata, + context, + is_conflict ? + OTRL_ERRCODE_MSG_UNREADABLE : + OTRL_ERRCODE_MSG_MALFORMED); + if (err_msg) { + buf = malloc(strlen(OTR_ERROR_PREFIX) + + strlen(err_msg) + 1); + if (buf) { + strcpy(buf, OTR_ERROR_PREFIX); + strcat(buf, err_msg); + ops->inject_message(opdata, + accountname, protocol, + sender, buf); + free(buf); + } + } + if (ops->otr_error_message_free) { + ops->otr_error_message_free(opdata, + err_msg); + } + } + edata.ignore_message = 1; + break; + } + + /* If the other side told us he's disconnected his + * private connection, make a note of that so we + * don't try sending anything else to him. */ + if (otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED)) { + otrl_context_force_finished(context); + } + + /* If the other side told us to use the current + * extra symmetric key, let the application know. */ + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SYMKEY); + if (tlv && otrl_api_version >= 0x040000) { + if (ops->received_symkey && tlv->len >= 4) { + unsigned char *bufp = tlv->data; + unsigned int use = + (bufp[0] << 24) | (bufp[1] << 16) | + (bufp[2] << 8) | bufp[3]; + ops->received_symkey(opdata, context, use, + bufp+4, tlv->len - 4, extrakey); + } + } + gcry_free(extrakey); + extrakey = NULL; + + /* If TLVs contain SMP data, process it */ + nextMsg = context->smstate->nextExpected; + + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q); + if (tlv) { + if (nextMsg == OTRL_SMP_EXPECT1 && tlv->len > 0) { + /* We can only do the verification half now. + * We must wait for the secret to be entered + * to continue. */ + char *question = (char *)tlv->data; + char *qend = memchr(question, '\0', tlv->len - 1); + size_t qlen = qend ? (qend - question + 1) : + tlv->len; + otrl_sm_step2a(context->smstate, tlv->data + qlen, + tlv->len - qlen, 1); + + if (context->smstate->sm_prog_state != + OTRL_SMP_PROG_CHEATED) { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ASK_FOR_ANSWER, + context, 25, question); + } + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_CHEATED, context, + 0, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + context->smstate->sm_prog_state = + OTRL_SMP_PROG_OK; + } + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ERROR, context, + 0, NULL); + } + } + } + + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); + if (tlv) { + if (nextMsg == OTRL_SMP_EXPECT1) { + /* We can only do the verification half now. + * We must wait for the secret to be entered + * to continue. */ + otrl_sm_step2a(context->smstate, tlv->data, + tlv->len, 0); + if (context->smstate->sm_prog_state != + OTRL_SMP_PROG_CHEATED) { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ASK_FOR_SECRET, + context, 25, NULL); + } + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_CHEATED, + context, 0, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + context->smstate->sm_prog_state = + OTRL_SMP_PROG_OK; + } + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ERROR, context, + 0, NULL); + } + } + } + + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); + if (tlv) { + if (nextMsg == OTRL_SMP_EXPECT2) { + unsigned char* nextmsg; + int nextmsglen; + OtrlTLV *sendtlv; + char *sendsmp = NULL; + otrl_sm_step3(context->smstate, tlv->data, + tlv->len, &nextmsg, &nextmsglen); + + if (context->smstate->sm_prog_state != + OTRL_SMP_PROG_CHEATED) { + /* Send msg with next smp msg content */ + sendtlv = otrl_tlv_new(OTRL_TLV_SMP3, + nextmsglen, nextmsg); + err = otrl_proto_create_data(&sendsmp, + context, "", sendtlv, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, + NULL); + if (!err) { + err = fragment_and_send(ops, + opdata, context, sendsmp, + OTRL_FRAGMENT_SEND_ALL, NULL); + } + free(sendsmp); + otrl_tlv_free(sendtlv); + + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_IN_PROGRESS, + context, 60, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT4; + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_CHEATED, + context, 0, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + context->smstate->sm_prog_state = + OTRL_SMP_PROG_OK; + } + free(nextmsg); + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ERROR, context, + 0, NULL); + } + } + } + + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); + if (tlv) { + if (nextMsg == OTRL_SMP_EXPECT3) { + unsigned char* nextmsg; + int nextmsglen; + OtrlTLV *sendtlv; + char *sendsmp = NULL; + err = otrl_sm_step4(context->smstate, tlv->data, + tlv->len, &nextmsg, &nextmsglen); + /* Set trust level based on result */ + if (context->smstate->received_question == 0) { + set_smp_trust(ops, opdata, context, + (err == gcry_error(GPG_ERR_NO_ERROR))); + } + + if (context->smstate->sm_prog_state != + OTRL_SMP_PROG_CHEATED) { + /* Send msg with next smp msg content */ + sendtlv = otrl_tlv_new(OTRL_TLV_SMP4, + nextmsglen, nextmsg); + err = otrl_proto_create_data(&sendsmp, + context, "", sendtlv, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, + NULL); + if (!err) { + err = fragment_and_send(ops, + opdata, context, sendsmp, + OTRL_FRAGMENT_SEND_ALL, NULL); + } + free(sendsmp); + otrl_tlv_free(sendtlv); + + if (ops->handle_smp_event) { + OtrlSMPEvent succorfail = + context->smstate->sm_prog_state == + OTRL_SMP_PROG_SUCCEEDED ? + OTRL_SMPEVENT_SUCCESS : + OTRL_SMPEVENT_FAILURE; + ops->handle_smp_event(opdata, succorfail, + context, 100, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_CHEATED, + context, 0, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + context->smstate->sm_prog_state = + OTRL_SMP_PROG_OK; + } + free(nextmsg); + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ERROR, context, + 0, NULL); + } + } + } + + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); + if (tlv) { + if (nextMsg == OTRL_SMP_EXPECT4) { + err = otrl_sm_step5(context->smstate, tlv->data, + tlv->len); + /* Set trust level based on result */ + set_smp_trust(ops, opdata, context, + (err == gcry_error(GPG_ERR_NO_ERROR))); + + if (context->smstate->sm_prog_state != + OTRL_SMP_PROG_CHEATED) { + if (ops->handle_smp_event) { + OtrlSMPEvent succorfail = + context->smstate->sm_prog_state == + OTRL_SMP_PROG_SUCCEEDED ? + OTRL_SMPEVENT_SUCCESS : + OTRL_SMPEVENT_FAILURE; + ops->handle_smp_event(opdata, succorfail, + context, 100, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_CHEATED, + context, 0, NULL); + } + context->smstate->nextExpected = + OTRL_SMP_EXPECT1; + context->smstate->sm_prog_state = + OTRL_SMP_PROG_OK; + } + } else { + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, + OTRL_SMPEVENT_ERROR, context, + 0, NULL); + } + } + } + + tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); + if (tlv) { + context->smstate->nextExpected = OTRL_SMP_EXPECT1; + if (ops->handle_smp_event) { + ops->handle_smp_event(opdata, OTRL_SMPEVENT_ABORT, + context, 0, NULL); + } + } + + if (plaintext[0] == '\0') { + /* If it's a heartbeat (an empty message), don't + * display it to the user, but signal an event. */ + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD, + context, NULL, + gcry_error(GPG_ERR_NO_ERROR)); + } + edata.ignore_message = 1; + } else if (edata.ignore_message != 1 && + context->context_priv->their_keyid > 0) { + /* If it's *not* a heartbeat, and we haven't + * sent anything in a while, also send a + * heartbeat. */ + time_t now = time(NULL); + if (context->context_priv->lastsent < + (now - HEARTBEAT_INTERVAL)) { + char *heartbeat; + + /* Create the heartbeat message */ + err = otrl_proto_create_data(&heartbeat, + context, "", NULL, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, + NULL); + if (!err) { + /* Send it, and inject a debug message */ + if (ops->inject_message) { + ops->inject_message(opdata, accountname, + protocol, sender, heartbeat); + } + free(heartbeat); + + context->context_priv->lastsent = now; + otrl_context_update_recent_child(context, 1); + + /* Signal an event for the heartbeat message */ + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_LOG_HEARTBEAT_SENT, + context, NULL, + gcry_error(GPG_ERR_NO_ERROR)); + } + } + } + } + + /* Return the TLVs even if ignore_message == 1 so + * that we can attach TLVs to heartbeats. */ + if (tlvsp) { + *tlvsp = tlvs; + } else { + otrl_tlv_free(tlvs); + } + + if (edata.ignore_message != 1) { + char *converted_msg = NULL; + + *newmessagep = plaintext; + edata.ignore_message = 0; + + /* convert the plaintext message if necessary */ + if (ops->convert_msg) { + ops->convert_msg(opdata, context, + OTRL_CONVERT_RECEIVING, &converted_msg, + plaintext); + + if (converted_msg) { + free(plaintext); + plaintext = NULL; + *newmessagep = strdup(converted_msg); + + if (ops->convert_free) { + ops->convert_free(opdata, context, + converted_msg); + } + } + } + } else { + free(plaintext); + } + break; + } + break; + + case OTRL_MSGTYPE_ERROR: + if ((policy & OTRL_POLICY_ERROR_START_AKE)) { + char *msgtosend = otrl_proto_default_query_msg( + context->accountname, policy); + if (msgtosend && ops->inject_message) { + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, + msgtosend); + } + free(msgtosend); + } + + if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { + /* Mark the last message we sent as eligible for + * retransmission */ + context->context_priv->may_retransmit = 1; + } + + /* In any event, display the error message, with the + * display_otr_message callback, if possible */ + if (ops->handle_msg_event) { + /* Remove the OTR error prefix and pass the msg */ + const char *just_err_msg = strstr(message, OTR_ERROR_PREFIX); + if (!just_err_msg) { + just_err_msg = message; + } else { + just_err_msg += (strlen(OTR_ERROR_PREFIX)); + if (*just_err_msg == ' ') { + /* Advance pointer to skip the space character */ + just_err_msg++; + } + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR, + context, just_err_msg, + gcry_error(GPG_ERR_NO_ERROR)); + edata.ignore_message = 1; + } + } + break; + + case OTRL_MSGTYPE_TAGGEDPLAINTEXT: + /* Strip the tag from the message */ + bestversion = otrl_proto_whitespace_bestversion(message, + &startwhite, &endwhite, policy); + if (startwhite && endwhite) { + size_t restlen = strlen(endwhite); + char *strippedmsg = strdup(message); + + if (strippedmsg) { + memmove(strippedmsg + (startwhite - message), + strippedmsg + (endwhite - message), restlen+1); + *newmessagep = strippedmsg; + edata.ignore_message = 0; + } + } + if (bestversion && context->msgstate != OTRL_MSGSTATE_ENCRYPTED + && (policy & OTRL_POLICY_WHITESPACE_START_AKE)) { + switch(bestversion) { + case 3: + err = otrl_auth_start_v23(&(context->auth), 3); + send_or_error_auth(ops, opdata, err, context, us); + break; + case 2: + err = otrl_auth_start_v23(&(context->auth), 2); + send_or_error_auth(ops, opdata, err, context, us); + break; + case 1: + /* Get our private key */ + privkey = otrl_privkey_find(us, context->accountname, + context->protocol); + if (privkey == NULL) { + /* We've got no private key! */ + if (ops->create_privkey) { + ops->create_privkey(opdata, + context->accountname, + context->protocol); + privkey = otrl_privkey_find(us, + context->accountname, + context->protocol); + } + } + if (privkey) { + err = otrl_auth_start_v1(&(context->auth), NULL, 0, + privkey); + send_or_error_auth(ops, opdata, err, context, us); + } + break; + default: + /* Don't start the AKE */ + break; + } + } + + /* FALLTHROUGH */ + case OTRL_MSGTYPE_NOTOTR: + if (best_context->msgstate != OTRL_MSGSTATE_PLAINTEXT || + (policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) { + /* Not fine. Let the user know. */ + const char *plainmsg = (*newmessagep) ? *newmessagep : message; + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED, + context, plainmsg, gcry_error(GPG_ERR_NO_ERROR)); + free(*newmessagep); + *newmessagep = NULL; + edata.ignore_message = 1; + } + } + break; + + case OTRL_MSGTYPE_UNKNOWN: + /* We received an OTR message we didn't recognize. Ignore + * it, and signal an event. */ + if (ops->handle_msg_event) { + ops->handle_msg_event(opdata, + OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED, + context, NULL, gcry_error(GPG_ERR_NO_ERROR)); + } + if (edata.ignore_message == -1) edata.ignore_message = 1; + break; + } + +end: + /* If we reassembled a fragmented message, we need to free the + * allocated memory now. */ + free(unfragmessage); + + if (edata.ignore_message == -1) edata.ignore_message = 0; + return edata.ignore_message; +} + +/* Put a connection into the PLAINTEXT state, first sending the + * other side a notice that we're doing so if we're currently ENCRYPTED, + * and we think he's logged in. Affects only the specified context. */ +static void disconnect_context(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context) +{ + if (!context) return; + + if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED && + context->context_priv->their_keyid > 0 && + ops->is_logged_in && + ops->is_logged_in(opdata, context->accountname, context->protocol, + context->username) == 1) { + if (ops->inject_message) { + char *encmsg = NULL; + gcry_error_t err; + OtrlTLV *tlv = otrl_tlv_new(OTRL_TLV_DISCONNECTED, 0, NULL); + + err = otrl_proto_create_data(&encmsg, context, "", tlv, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, NULL); + if (!err) { + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, encmsg); + } + free(encmsg); + otrl_tlv_free(tlv); + } + } + + otrl_context_force_plaintext(context); + if (ops->update_context_list) { + ops->update_context_list(opdata); + } +} + + +/* Put a connection into the PLAINTEXT state, first sending the + * other side a notice that we're doing so if we're currently ENCRYPTED, + * and we think he's logged in. Affects only the specified instance. */ +void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *username, otrl_instag_t instance) +{ + ConnContext *context = otrl_context_find(us, username, accountname, + protocol, instance, 0, NULL, NULL, NULL); + + if (!context) return; + + disconnect_context(us, ops, opdata, context); +} + +/* Put a connection into the PLAINTEXT state, first sending the + * other side a notice that we're doing so if we're currently ENCRYPTED, + * and we think he's logged in. Affects all matching instances. */ +void otrl_message_disconnect_all_instances(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, const char *accountname, + const char *protocol, const char *username) +{ + ConnContext * c_iter; + ConnContext *context; + + if (!username || !accountname || !protocol) return; + + context = otrl_context_find(us, username, accountname, + protocol, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); + + if (!context) return; + + for (c_iter = context; c_iter && c_iter->m_context == context->m_context; + c_iter = c_iter->next) { + disconnect_context(us, ops, opdata, c_iter); + } +} + +/* Get the current extra symmetric key (of size OTRL_EXTRAKEY_BYTES + * bytes) and let the other side know what we're going to use it for. + * The key is stored in symkey, which must already be allocated + * and OTRL_EXTRAKEY_BYTES bytes long. */ +gcry_error_t otrl_message_symkey(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, size_t usedatalen, + unsigned char *symkey) +{ + if (!context || (usedatalen > 0 && !usedata)) { + return gcry_error(GPG_ERR_INV_VALUE); + } + + if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED && + context->context_priv->their_keyid > 0) { + unsigned char *tlvdata = malloc(usedatalen+4); + char *encmsg = NULL; + gcry_error_t err; + OtrlTLV *tlv; + + tlvdata[0] = (use >> 24) & 0xff; + tlvdata[1] = (use >> 16) & 0xff; + tlvdata[2] = (use >> 8) & 0xff; + tlvdata[3] = (use) & 0xff; + if (usedatalen > 0) { + memmove(tlvdata+4, usedata, usedatalen); + } + + tlv = otrl_tlv_new(OTRL_TLV_SYMKEY, usedatalen+4, tlvdata); + free(tlvdata); + + err = otrl_proto_create_data(&encmsg, context, "", tlv, + OTRL_MSGFLAGS_IGNORE_UNREADABLE, symkey); + if (!err && ops->inject_message) { + ops->inject_message(opdata, context->accountname, + context->protocol, context->username, encmsg); + } + free(encmsg); + otrl_tlv_free(tlv); + + return err; + } + + /* We weren't in an encrypted session. */ + return gcry_error(GPG_ERR_INV_VALUE); +} + +/* If you do _not_ define a timer_control callback function, set a timer + * to go off every definterval = + * otrl_message_poll_get_default_interval(userstate) seconds, and call + * otrl_message_poll every time the timer goes off. */ +unsigned int otrl_message_poll_get_default_interval(OtrlUserState us) +{ + return POLL_DEFAULT_INTERVAL; +} + +/* Call this function every so often, either as directed by the + * timer_control callback, or every definterval = + * otrl_message_poll_get_default_interval(userstate) seconds if you have + * no timer_control callback. This function must be called from the + * main libotr thread.*/ +void otrl_message_poll(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata) +{ + /* Wipe private keys last sent before this time */ + time_t expire_before = time(NULL) - MAX_AKE_WAIT_TIME; + + ConnContext *contextp; + + /* Is there a context still waiting for a DHKEY message, even after + * we wipe the stale ones? */ + int still_waiting = 0; + + if (us == NULL) return; + + for (contextp = us->context_root; contextp; contextp = contextp->next) { + /* If this is a master context, and it's still waiting for a + * v3 DHKEY message, see if it's waited long enough. */ + if (contextp->m_context == contextp && + contextp->auth.authstate == OTRL_AUTHSTATE_AWAITING_DHKEY && + contextp->auth.protocol_version == 3 && + contextp->auth.commit_sent_time > 0) { + if (contextp->auth.commit_sent_time < expire_before) { + otrl_auth_clear(&contextp->auth); + } else { + /* Not yet expired */ + still_waiting = 1; + } + } + } + + /* If there's nothing more to wait for, stop the timer, if possible. */ + if (still_waiting == 0 && ops && ops->timer_control) { + ops->timer_control(opdata, 0); + us->timer_running = 0; + } +} diff --git a/comm/third_party/libotr/src/message.h b/comm/third_party/libotr/src/message.h new file mode 100644 index 0000000000..bb82ffc7e6 --- /dev/null +++ b/comm/third_party/libotr/src/message.h @@ -0,0 +1,440 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __MESSAGE_H__ +#define __MESSAGE_H__ + +#define OTR_ERROR_PREFIX "?OTR Error: " + +typedef enum { + OTRL_ERRCODE_NONE, + OTRL_ERRCODE_ENCRYPTION_ERROR, + OTRL_ERRCODE_MSG_NOT_IN_PRIVATE, + OTRL_ERRCODE_MSG_UNREADABLE, + OTRL_ERRCODE_MSG_MALFORMED, +} OtrlErrorCode; + +/* These define the events used to indicate status of SMP to the UI */ +typedef enum { + OTRL_SMPEVENT_NONE, + OTRL_SMPEVENT_ERROR, + OTRL_SMPEVENT_ABORT, + OTRL_SMPEVENT_CHEATED, + OTRL_SMPEVENT_ASK_FOR_ANSWER, + OTRL_SMPEVENT_ASK_FOR_SECRET, + OTRL_SMPEVENT_IN_PROGRESS, + OTRL_SMPEVENT_SUCCESS, + OTRL_SMPEVENT_FAILURE +} OtrlSMPEvent; + +/* These define the events used to indicate the messages that need + * to be sent */ +typedef enum { + OTRL_MSGEVENT_NONE, + OTRL_MSGEVENT_ENCRYPTION_REQUIRED, + OTRL_MSGEVENT_ENCRYPTION_ERROR, + OTRL_MSGEVENT_CONNECTION_ENDED, + OTRL_MSGEVENT_SETUP_ERROR, + OTRL_MSGEVENT_MSG_REFLECTED, + OTRL_MSGEVENT_MSG_RESENT, + OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE, + OTRL_MSGEVENT_RCVDMSG_UNREADABLE, + OTRL_MSGEVENT_RCVDMSG_MALFORMED, + OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD, + OTRL_MSGEVENT_LOG_HEARTBEAT_SENT, + OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR, + OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED, + OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED, + OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE +} OtrlMessageEvent; + +typedef enum { + OTRL_NOTIFY_ERROR, + OTRL_NOTIFY_WARNING, + OTRL_NOTIFY_INFO +} OtrlNotifyLevel; + +typedef enum { + OTRL_CONVERT_SENDING, + OTRL_CONVERT_RECEIVING +} OtrlConvertType; + +typedef struct s_OtrlMessageAppOps { + /* Return the OTR policy for the given context. */ + OtrlPolicy (*policy)(void *opdata, ConnContext *context); + + /* Create a private key for the given accountname/protocol if + * desired. */ + void (*create_privkey)(void *opdata, const char *accountname, + const char *protocol); + + /* Report whether you think the given user is online. Return 1 if + * you think he is, 0 if you think he isn't, -1 if you're not sure. + * + * If you return 1, messages such as heartbeats or other + * notifications may be sent to the user, which could result in "not + * logged in" errors if you're wrong. */ + int (*is_logged_in)(void *opdata, const char *accountname, + const char *protocol, const char *recipient); + + /* Send the given IM to the given recipient from the given + * accountname/protocol. */ + void (*inject_message)(void *opdata, const char *accountname, + const char *protocol, const char *recipient, const char *message); + + /* When the list of ConnContexts changes (including a change in + * state), this is called so the UI can be updated. */ + void (*update_context_list)(void *opdata); + + /* A new fingerprint for the given user has been received. */ + void (*new_fingerprint)(void *opdata, OtrlUserState us, + const char *accountname, const char *protocol, + const char *username, unsigned char fingerprint[20]); + + /* The list of known fingerprints has changed. Write them to disk. */ + void (*write_fingerprints)(void *opdata); + + /* A ConnContext has entered a secure state. */ + void (*gone_secure)(void *opdata, ConnContext *context); + + /* A ConnContext has left a secure state. */ + void (*gone_insecure)(void *opdata, ConnContext *context); + + /* We have completed an authentication, using the D-H keys we + * already knew. is_reply indicates whether we initiated the AKE. */ + void (*still_secure)(void *opdata, ConnContext *context, int is_reply); + + /* Find the maximum message size supported by this protocol. */ + int (*max_message_size)(void *opdata, ConnContext *context); + + /* Return a newly allocated string containing a human-friendly + * representation for the given account */ + const char *(*account_name)(void *opdata, const char *account, + const char *protocol); + + /* Deallocate a string returned by account_name */ + void (*account_name_free)(void *opdata, const char *account_name); + + /* We received a request from the buddy to use the current "extra" + * symmetric key. The key will be passed in symkey, of length + * OTRL_EXTRAKEY_BYTES. The requested use, as well as use-specific + * data will be passed so that the applications can communicate other + * information (some id for the data transfer, for example). */ + void (*received_symkey)(void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, + size_t usedatalen, const unsigned char *symkey); + + /* Return a string according to the error event. This string will then + * be concatenated to an OTR header to produce an OTR protocol error + * message. The following are the possible error events: + * - OTRL_ERRCODE_ENCRYPTION_ERROR + * occured while encrypting a message + * - OTRL_ERRCODE_MSG_NOT_IN_PRIVATE + * sent encrypted message to somebody who is not in + * a mutual OTR session + * - OTRL_ERRCODE_MSG_UNREADABLE + * sent an unreadable encrypted message + * - OTRL_ERRCODE_MSG_MALFORMED + * message sent is malformed */ + const char *(*otr_error_message)(void *opdata, ConnContext *context, + OtrlErrorCode err_code); + + /* Deallocate a string returned by otr_error_message */ + void (*otr_error_message_free)(void *opdata, const char *err_msg); + + /* Return a string that will be prefixed to any resent message. If this + * function is not provided by the application then the default prefix, + * "[resent]", will be used. + * */ + const char *(*resent_msg_prefix)(void *opdata, ConnContext *context); + + /* Deallocate a string returned by resent_msg_prefix */ + void (*resent_msg_prefix_free)(void *opdata, const char *prefix); + + /* Update the authentication UI with respect to SMP events + * These are the possible events: + * - OTRL_SMPEVENT_ASK_FOR_SECRET + * prompt the user to enter a shared secret. The sender application + * should call otrl_message_initiate_smp, passing NULL as the question. + * When the receiver application resumes the SM protocol by calling + * otrl_message_respond_smp with the secret answer. + * - OTRL_SMPEVENT_ASK_FOR_ANSWER + * (same as OTRL_SMPEVENT_ASK_FOR_SECRET but sender calls + * otrl_message_initiate_smp_q instead) + * - OTRL_SMPEVENT_CHEATED + * abort the current auth and update the auth progress dialog + * with progress_percent. otrl_message_abort_smp should be called to + * stop the SM protocol. + * - OTRL_SMPEVENT_INPROGRESS and + * OTRL_SMPEVENT_SUCCESS and + * OTRL_SMPEVENT_FAILURE and + * OTRL_SMPEVENT_ABORT + * update the auth progress dialog with progress_percent + * - OTRL_SMPEVENT_ERROR + * (same as OTRL_SMPEVENT_CHEATED) + * */ + void (*handle_smp_event)(void *opdata, OtrlSMPEvent smp_event, + ConnContext *context, unsigned short progress_percent, + char *question); + + /* Handle and send the appropriate message(s) to the sender/recipient + * depending on the message events. All the events only require an opdata, + * the event, and the context. The message and err will be NULL except for + * some events (see below). The possible events are: + * - OTRL_MSGEVENT_ENCRYPTION_REQUIRED + * Our policy requires encryption but we are trying to send + * an unencrypted message out. + * - OTRL_MSGEVENT_ENCRYPTION_ERROR + * An error occured while encrypting a message and the message + * was not sent. + * - OTRL_MSGEVENT_CONNECTION_ENDED + * Message has not been sent because our buddy has ended the + * private conversation. We should either close the connection, + * or refresh it. + * - OTRL_MSGEVENT_SETUP_ERROR + * A private conversation could not be set up. A gcry_error_t + * will be passed. + * - OTRL_MSGEVENT_MSG_REFLECTED + * Received our own OTR messages. + * - OTRL_MSGEVENT_MSG_RESENT + * The previous message was resent. + * - OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE + * Received an encrypted message but cannot read + * it because no private connection is established yet. + * - OTRL_MSGEVENT_RCVDMSG_UNREADABLE + * Cannot read the received message. + * - OTRL_MSGEVENT_RCVDMSG_MALFORMED + * The message received contains malformed data. + * - OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD + * Received a heartbeat. + * - OTRL_MSGEVENT_LOG_HEARTBEAT_SENT + * Sent a heartbeat. + * - OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR + * Received a general OTR error. The argument 'message' will + * also be passed and it will contain the OTR error message. + * - OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED + * Received an unencrypted message. The argument 'message' will + * also be passed and it will contain the plaintext message. + * - OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED + * Cannot recognize the type of OTR message received. + * - OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE + * Received and discarded a message intended for another instance. */ + void (*handle_msg_event)(void *opdata, OtrlMessageEvent msg_event, + ConnContext *context, const char *message, + gcry_error_t err); + + /* Create a instance tag for the given accountname/protocol if + * desired. */ + void (*create_instag)(void *opdata, const char *accountname, + const char *protocol); + + /* Called immediately before a data message is encrypted, and after a data + * message is decrypted. The OtrlConvertType parameter has the value + * OTRL_CONVERT_SENDING or OTRL_CONVERT_RECEIVING to differentiate these + * cases. */ + void (*convert_msg)(void *opdata, ConnContext *context, + OtrlConvertType convert_type, char ** dest, const char *src); + + /* Deallocate a string returned by convert_msg. */ + void (*convert_free)(void *opdata, ConnContext *context, char *dest); + + /* When timer_control is called, turn off any existing periodic + * timer. + * + * Additionally, if interval > 0, set a new periodic timer + * to go off every interval seconds. When that timer fires, you + * must call otrl_message_poll(userstate, uiops, uiopdata); from the + * main libotr thread. + * + * The timing does not have to be exact; this timer is used to + * provide forward secrecy by cleaning up stale private state that + * may otherwise stick around in memory. Note that the + * timer_control callback may be invoked from otrl_message_poll + * itself, possibly to indicate that interval == 0 (that is, that + * there's no more periodic work to be done at this time). + * + * If you set this callback to NULL, then you must ensure that your + * application calls otrl_message_poll(userstate, uiops, uiopdata); + * from the main libotr thread every definterval seconds (where + * definterval can be obtained by calling + * definterval = otrl_message_poll_get_default_interval(userstate); + * right after creating the userstate). The advantage of + * implementing the timer_control callback is that the timer can be + * turned on by libotr only when it's needed. + * + * It is not a problem (except for a minor performance hit) to call + * otrl_message_poll more often than requested, whether + * timer_control is implemented or not. + * + * If you fail to implement the timer_control callback, and also + * fail to periodically call otrl_message_poll, then you open your + * users to a possible forward secrecy violation: an attacker that + * compromises the user's computer may be able to decrypt a handful + * of long-past messages (the first messages of an OTR + * conversation). + */ + void (*timer_control)(void *opdata, unsigned int interval); + +} OtrlMessageAppOps; + +/* Deallocate a message allocated by other otrl_message_* routines. */ +void otrl_message_free(char *message); + +/* Handle a message about to be sent to the network. It is safe to pass + * all messages about to be sent to this routine. add_appdata is a + * function that will be called in the event that a new ConnContext is + * created. It will be passed the data that you supplied, as well as a + * pointer to the new ConnContext. You can use this to add + * application-specific information to the ConnContext using the + * "context->app" field, for example. If you don't need to do this, you + * can pass NULL for the last two arguments of otrl_message_sending. + * + * tlvs is a chain of OtrlTLVs to append to the private message. It is + * usually correct to just pass NULL here. + * + * If non-NULL, ops->convert_msg will be called just before encrypting a + * message. + * + * "instag" specifies the instance tag of the buddy (protocol version 3 only). + * Meta-instances may also be specified (e.g., OTRL_INSTAG_MOST_SECURE). + * If "contextp" is not NULL, it will be set to the ConnContext used for + * sending the message. + * + * If no fragmentation or msg injection is wanted, use OTRL_FRAGMENT_SEND_SKIP + * as the OtrlFragmentPolicy. In this case, this function will assign *messagep + * with the encrypted msg. If the routine returns non-zero, then the library + * tried to encrypt the message, but for some reason failed. DO NOT send the + * message in the clear in that case. If *messagep gets set by the call to + * something non-NULL, then you should replace your message with the contents + * of *messagep, and send that instead. + * + * Other fragmentation policies are OTRL_FRAGMENT_SEND_ALL, + * OTRL_FRAGMENT_SEND_ALL_BUT_LAST, or OTRL_FRAGMENT_SEND_ALL_BUT_FIRST. In + * these cases, the appropriate fragments will be automatically sent. For the + * last two policies, the remaining fragment will be passed in *original_msg. + * + * Call otrl_message_free(*messagep) if you don't need *messagep or when you're + * done with it. */ +gcry_error_t otrl_message_sending(OtrlUserState us, + const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *recipient, otrl_instag_t instag, const char *original_msg, + OtrlTLV *tlvs, char **messagep, OtrlFragmentPolicy fragPolicy, + ConnContext **contextp, + void (*add_appdata)(void *data, ConnContext *context), + void *data); + +/* Handle a message just received from the network. It is safe to pass + * all received messages to this routine. add_appdata is a function + * that will be called in the event that a new ConnContext is created. + * It will be passed the data that you supplied, as well as + * a pointer to the new ConnContext. You can use this to add + * application-specific information to the ConnContext using the + * "context->app" field, for example. If you don't need to do this, you + * can pass NULL for the last two arguments of otrl_message_receiving. + * + * If non-NULL, ops->convert_msg will be called after a data message is + * decrypted. + * + * If "contextp" is not NULL, it will be set to the ConnContext used for + * receiving the message. + * + * If otrl_message_receiving returns 1, then the message you received + * was an internal protocol message, and no message should be delivered + * to the user. + * + * If it returns 0, then check if *messagep was set to non-NULL. If + * so, replace the received message with the contents of *messagep, and + * deliver that to the user instead. You must call + * otrl_message_free(*messagep) when you're done with it. If tlvsp is + * non-NULL, *tlvsp will be set to a chain of any TLVs that were + * transmitted along with this message. You must call + * otrl_tlv_free(*tlvsp) when you're done with those. + * + * If otrl_message_receiving returns 0 and *messagep is NULL, then this + * was an ordinary, non-OTR message, which should just be delivered to + * the user without modification. */ +int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *sender, const char *message, char **newmessagep, + OtrlTLV **tlvsp, ConnContext **contextp, + void (*add_appdata)(void *data, ConnContext *context), + void *data); + +/* Put a connection into the PLAINTEXT state, first sending the + * other side a notice that we're doing so if we're currently ENCRYPTED, + * and we think he's logged in. Affects only the specified instance. */ +void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, const char *accountname, const char *protocol, + const char *username, otrl_instag_t instance); + +/* Put a connection into the PLAINTEXT state, first sending the + * other side a notice that we're doing so if we're currently ENCRYPTED, + * and we think he's logged in. Affects all matching instances. */ +void otrl_message_disconnect_all_instances(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, const char *accountname, + const char *protocol, const char *username); + +/* Initiate the Socialist Millionaires' Protocol */ +void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context, const unsigned char *secret, + size_t secretlen); + +/* Initiate the Socialist Millionaires' Protocol and send a prompt + * question to the buddy */ +void otrl_message_initiate_smp_q(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, + const char *question, const unsigned char *secret, size_t secretlen); + +/* Respond to a buddy initiating the Socialist Millionaires' Protocol */ +void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context, const unsigned char *secret, + size_t secretlen); + +/* Abort the SMP. Called when an unexpected SMP message breaks the + * normal flow. */ +void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata, ConnContext *context); + +/* Get the current extra symmetric key (of size OTRL_EXTRAKEY_BYTES + * bytes) and let the other side know what we're going to use it for. + * The key is stored in symkey, which must already be allocated + * and OTRL_EXTRAKEY_BYTES bytes long. */ +gcry_error_t otrl_message_symkey(OtrlUserState us, + const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, size_t usedatalen, + unsigned char *symkey); + +/* If you do _not_ define a timer_control callback function, set a timer + * to go off every definterval = + * otrl_message_poll_get_default_interval(userstate) seconds, and call + * otrl_message_poll every time the timer goes off. */ +unsigned int otrl_message_poll_get_default_interval(OtrlUserState us); + +/* Call this function every so often, either as directed by the + * timer_control callback, or every definterval = + * otrl_message_poll_get_default_interval(userstate) seconds if you have + * no timer_control callback. This function must be called from the + * main libotr thread.*/ +void otrl_message_poll(OtrlUserState us, const OtrlMessageAppOps *ops, + void *opdata); + +#endif diff --git a/comm/third_party/libotr/src/privkey-t.h b/comm/third_party/libotr/src/privkey-t.h new file mode 100644 index 0000000000..7dd120e789 --- /dev/null +++ b/comm/third_party/libotr/src/privkey-t.h @@ -0,0 +1,50 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2009 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __PRIVKEY_T_H__ +#define __PRIVKEY_T_H__ + +#include + +typedef struct s_OtrlPrivKey { + struct s_OtrlPrivKey *next; + struct s_OtrlPrivKey **tous; + + char *accountname; + char *protocol; + unsigned short pubkey_type; + gcry_sexp_t privkey; + unsigned char *pubkey_data; + size_t pubkey_datalen; +} OtrlPrivKey; + +#define OTRL_PUBKEY_TYPE_DSA 0x0000 + +/* The list of privkeys currently being constructed, possibly in a + * background thread */ +typedef struct s_OtrlPendingPrivKey { + struct s_OtrlPendingPrivKey *next; + struct s_OtrlPendingPrivKey **tous; + + char *accountname; + char *protocol; +} OtrlPendingPrivKey; + +#endif diff --git a/comm/third_party/libotr/src/privkey.c b/comm/third_party/libotr/src/privkey.c new file mode 100644 index 0000000000..6e4bbe40fc --- /dev/null +++ b/comm/third_party/libotr/src/privkey.c @@ -0,0 +1,938 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "privkey.h" +#include "serial.h" + +/* Convert a 20-byte hash value to a 45-byte human-readable value */ +void otrl_privkey_hash_to_human( + char human[OTRL_PRIVKEY_FPRINT_HUMAN_LEN], + const unsigned char hash[20]) +{ + int word, byte; + char *p = human; + + for(word=0; word<5; ++word) { + for(byte=0; byte<4; ++byte) { + sprintf(p, "%02X", hash[word*4+byte]); + p += 2; + } + *(p++) = ' '; + } + /* Change that last ' ' to a '\0' */ + --p; + *p = '\0'; +} + +/* Calculate a human-readable hash of our DSA public key. Return it in + * the passed fingerprint buffer. Return NULL on error, or a pointer to + * the given buffer on success. */ +char *otrl_privkey_fingerprint(OtrlUserState us, + char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN], + const char *accountname, const char *protocol) +{ + unsigned char hash[20]; + OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol); + + if (p) { + /* Calculate the hash */ + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data, + p->pubkey_datalen); + + /* Now convert it to a human-readable format */ + otrl_privkey_hash_to_human(fingerprint, hash); + } else { + return NULL; + } + + return fingerprint; +} + +/* Calculate a raw hash of our DSA public key. Return it in the passed + * fingerprint buffer. Return NULL on error, or a pointer to the given + * buffer on success. */ +unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us, + unsigned char hash[20], const char *accountname, const char *protocol) +{ + OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol); + + if (p) { + /* Calculate the hash */ + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data, + p->pubkey_datalen); + } else { + return NULL; + } + + return hash; +} + +/* Create a public key block from a private key */ +static gcry_error_t make_pubkey(unsigned char **pubbufp, size_t *publenp, + gcry_sexp_t privkey) +{ + gcry_mpi_t p,q,g,y; + gcry_sexp_t dsas,ps,qs,gs,ys; + size_t np,nq,ng,ny; + enum gcry_mpi_format format = GCRYMPI_FMT_USG; + unsigned char *bufp; + size_t lenp; + + *pubbufp = NULL; + *publenp = 0; + + /* Extract the public parameters */ + dsas = gcry_sexp_find_token(privkey, "dsa", 0); + if (dsas == NULL) { + return gcry_error(GPG_ERR_UNUSABLE_SECKEY); + } + ps = gcry_sexp_find_token(dsas, "p", 0); + qs = gcry_sexp_find_token(dsas, "q", 0); + gs = gcry_sexp_find_token(dsas, "g", 0); + ys = gcry_sexp_find_token(dsas, "y", 0); + gcry_sexp_release(dsas); + if (!ps || !qs || !gs || !ys) { + gcry_sexp_release(ps); + gcry_sexp_release(qs); + gcry_sexp_release(gs); + gcry_sexp_release(ys); + return gcry_error(GPG_ERR_UNUSABLE_SECKEY); + } + p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(ps); + q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(qs); + g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(gs); + y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(ys); + if (!p || !q || !g || !y) { + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); + return gcry_error(GPG_ERR_UNUSABLE_SECKEY); + } + + *publenp = 0; + gcry_mpi_print(format, NULL, 0, &np, p); + *publenp += np + 4; + gcry_mpi_print(format, NULL, 0, &nq, q); + *publenp += nq + 4; + gcry_mpi_print(format, NULL, 0, &ng, g); + *publenp += ng + 4; + gcry_mpi_print(format, NULL, 0, &ny, y); + *publenp += ny + 4; + + *pubbufp = malloc(*publenp); + if (*pubbufp == NULL) { + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); + return gcry_error(GPG_ERR_ENOMEM); + } + bufp = *pubbufp; + lenp = *publenp; + + write_mpi(p,np,"P"); + write_mpi(q,nq,"Q"); + write_mpi(g,ng,"G"); + write_mpi(y,ny,"Y"); + + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Read a sets of private DSA keys from a file on disk into the given + * OtrlUserState. */ +gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename) +{ + FILE *privf; + gcry_error_t err; + + /* Open the privkey file. We use rb mode so that on WIN32, fread() + * reads the same number of bytes that fstat() indicates are in the + * file. */ + privf = fopen(filename, "rb"); + if (!privf) { + err = gcry_error_from_errno(errno); + return err; + } + + err = otrl_privkey_read_FILEp(us, privf); + + fclose(privf); + return err; +} + +/* Read a sets of private DSA keys from a FILE* into the given + * OtrlUserState. The FILE* must be open for reading. */ +gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf) +{ + int privfd; + struct stat st; + char *buf; + const char *token; + size_t tokenlen; + gcry_error_t err; + gcry_sexp_t allkeys; + int i; + + if (!privf) return gcry_error(GPG_ERR_NO_ERROR); + + /* Release any old ideas we had about our keys */ + otrl_privkey_forget_all(us); + + /* Load the data into a buffer */ + privfd = fileno(privf); + if (fstat(privfd, &st)) { + err = gcry_error_from_errno(errno); + return err; + } + buf = malloc(st.st_size); + if (!buf && st.st_size > 0) { + return gcry_error(GPG_ERR_ENOMEM); + } + if (fread(buf, st.st_size, 1, privf) != 1) { + err = gcry_error_from_errno(errno); + free(buf); + return err; + } + + err = gcry_sexp_new(&allkeys, buf, st.st_size, 0); + free(buf); + if (err) { + return err; + } + + token = gcry_sexp_nth_data(allkeys, 0, &tokenlen); + if (tokenlen != 8 || strncmp(token, "privkeys", 8)) { + gcry_sexp_release(allkeys); + return gcry_error(GPG_ERR_UNUSABLE_SECKEY); + } + + /* Get each account */ + for(i=1; iaccountname = name; + p->protocol = proto; + p->pubkey_type = OTRL_PUBKEY_TYPE_DSA; + p->privkey = privs; + p->next = us->privkey_root; + if (p->next) { + p->next->tous = &(p->next); + } + p->tous = &(us->privkey_root); + us->privkey_root = p; + err = make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey); + if (err) { + gcry_sexp_release(allkeys); + otrl_privkey_forget(p); + return gcry_error(GPG_ERR_UNUSABLE_SECKEY); + } + } + gcry_sexp_release(allkeys); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +static OtrlPendingPrivKey *pending_find(OtrlUserState us, + const char *accountname, const char *protocol) +{ + OtrlPendingPrivKey *search = us->pending_root; + + while (search) { + if (!strcmp(search->accountname, accountname) && + !strcmp(search->protocol, protocol)) { + /* Found it */ + return search; + } + search = search->next; + } + return NULL; +} + +/* Insert an account/protocol pair into the pending privkey list of the + * given OtrlUserState and return a pointer to the new + * OtrlPendingPrivKey, or return NULL if it's already there. */ +static OtrlPendingPrivKey *pending_insert(OtrlUserState us, + const char *accountname, const char *protocol) +{ + /* See if it's already there */ + OtrlPendingPrivKey *search = pending_find(us, accountname, protocol); + + if (search) { + /* It is */ + return NULL; + } + + /* We'll insert it at the beginning of the list */ + search = malloc(sizeof(*search)); + if (!search) return NULL; + + search->accountname = strdup(accountname); + search->protocol = strdup(protocol); + + search->next = us->pending_root; + us->pending_root = search; + if (search->next) { + search->next->tous = &(search->next); + } + search->tous = &(us->pending_root); + return search; +} + +static void pending_forget(OtrlPendingPrivKey *ppk) +{ + if (ppk) { + free(ppk->accountname); + free(ppk->protocol); + + /* Re-link the list */ + *(ppk->tous) = ppk->next; + if (ppk->next) { + ppk->next->tous = ppk->tous; + } + + free(ppk); + } +} + +/* Free the memory associated with the pending privkey list */ +void otrl_privkey_pending_forget_all(OtrlUserState us) +{ + while(us->pending_root) { + pending_forget(us->pending_root); + } +} + +static gcry_error_t sexp_write(FILE *privf, gcry_sexp_t sexp) +{ + size_t buflen; + char *buf; + + buflen = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); + buf = malloc(buflen); + if (buf == NULL && buflen > 0) { + return gcry_error(GPG_ERR_ENOMEM); + } + gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, buflen); + + fprintf(privf, "%s", buf); + free(buf); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +static gcry_error_t account_write(FILE *privf, const char *accountname, + const char *protocol, gcry_sexp_t privkey) +{ + gcry_error_t err; + gcry_sexp_t names, protos; + + fprintf(privf, " (account\n"); + + err = gcry_sexp_build(&names, NULL, "(name %s)", accountname); + if (!err) { + err = sexp_write(privf, names); + gcry_sexp_release(names); + } + if (!err) err = gcry_sexp_build(&protos, NULL, "(protocol %s)", protocol); + if (!err) { + err = sexp_write(privf, protos); + gcry_sexp_release(protos); + } + if (!err) err = sexp_write(privf, privkey); + + fprintf(privf, " )\n"); + + return err; +} + +struct s_pending_privkey_calc { + char *accountname; + char *protocol; + gcry_sexp_t privkey; +}; + +/* Begin a private key generation that will potentially take place in + * a background thread. This routine must be called from the main + * thread. It will set *newkeyp, which you can pass to + * otrl_privkey_generate_calculate in a background thread. If it + * returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for + * this accountname/protocol is already in progress, and *newkeyp will + * be set to NULL. */ +gcry_error_t otrl_privkey_generate_start(OtrlUserState us, + const char *accountname, const char *protocol, void **newkeyp) +{ + OtrlPendingPrivKey *found = pending_find(us, accountname, protocol); + struct s_pending_privkey_calc *ppc; + + if (found) { + if (newkeyp) *newkeyp = NULL; + return gcry_error(GPG_ERR_EEXIST); + } + + /* We're not already creating this key. Mark it as in progress. */ + pending_insert(us, accountname, protocol); + + /* Allocate the working structure */ + ppc = malloc(sizeof(*ppc)); + ppc->accountname = strdup(accountname); + ppc->protocol = strdup(protocol); + ppc->privkey = NULL; + + *newkeyp = ppc; + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Do the private key generation calculation. You may call this from a + * background thread. When it completes, call + * otrl_privkey_generate_finish from the _main_ thread. */ +gcry_error_t otrl_privkey_generate_calculate(void *newkey) +{ + struct s_pending_privkey_calc *ppc = + (struct s_pending_privkey_calc *)newkey; + gcry_error_t err; + gcry_sexp_t key, parms; + static const char *parmstr = "(genkey (dsa (nbits 4:1024)))"; + + /* Create a DSA key */ + err = gcry_sexp_new(&parms, parmstr, strlen(parmstr), 0); + if (err) { + return err; + } + err = gcry_pk_genkey(&key, parms); + gcry_sexp_release(parms); + if (err) { + return err; + } + + /* Extract the privkey */ + ppc->privkey = gcry_sexp_find_token(key, "private-key", 0); + gcry_sexp_release(key); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +static FILE* privkey_fopen(const char *filename, gcry_error_t *errp) +{ + FILE *privf; +#ifndef WIN32 + mode_t oldmask; +#endif + +#ifndef WIN32 + oldmask = umask(077); +#endif + privf = fopen(filename, "w+b"); + if (!privf && errp) { + *errp = gcry_error_from_errno(errno); + } +#ifndef WIN32 + umask(oldmask); +#endif + return privf; +} + +/* Call this from the main thread only, in the event that the background + * thread generating the key is cancelled. The newkey is deallocated, + * and must not be used further. */ +void otrl_privkey_generate_cancelled(OtrlUserState us, void *newkey) +{ + struct s_pending_privkey_calc *ppc = + (struct s_pending_privkey_calc *)newkey; + + if (us) { + pending_forget(pending_find(us, ppc->accountname, ppc->protocol)); + } + + /* Deallocate ppc */ + free(ppc->accountname); + free(ppc->protocol); + gcry_sexp_release(ppc->privkey); + free(ppc); +} + +/* Call this from the main thread only. It will write the newly created + * private key into the given file and store it in the OtrlUserState. */ +gcry_error_t otrl_privkey_generate_finish(OtrlUserState us, + void *newkey, const char *filename) +{ + gcry_error_t err; + FILE *privf = privkey_fopen(filename, &err); + if (!privf) { + return err; + } + + err = otrl_privkey_generate_finish_FILEp(us, newkey, privf); + + fclose(privf); + return err; +} + +/* Call this from the main thread only. It will write the newly created + * private key into the given FILE* (which must be open for reading and + * writing) and store it in the OtrlUserState. */ +gcry_error_t otrl_privkey_generate_finish_FILEp(OtrlUserState us, + void *newkey, FILE *privf) +{ + struct s_pending_privkey_calc *ppc = + (struct s_pending_privkey_calc *)newkey; + gcry_error_t ret = gcry_error(GPG_ERR_INV_VALUE); + + if (ppc && us && privf) { + OtrlPrivKey *p; + + /* Output the other keys we know */ + fprintf(privf, "(privkeys\n"); + + for (p=us->privkey_root; p; p=p->next) { + /* Skip this one if our new key replaces it */ + if (!strcmp(p->accountname, ppc->accountname) && + !strcmp(p->protocol, ppc->protocol)) { + continue; + } + + account_write(privf, p->accountname, p->protocol, p->privkey); + } + account_write(privf, ppc->accountname, ppc->protocol, ppc->privkey); + fprintf(privf, ")\n"); + + fseek(privf, 0, SEEK_SET); + + ret = otrl_privkey_read_FILEp(us, privf); + } + + otrl_privkey_generate_cancelled(us, newkey); + + return ret; +} + +/* Generate a private DSA key for a given account, storing it into a + * file on disk, and loading it into the given OtrlUserState. Overwrite any + * previously generated keys for that account in that OtrlUserState. */ +gcry_error_t otrl_privkey_generate(OtrlUserState us, const char *filename, + const char *accountname, const char *protocol) +{ + gcry_error_t err; + FILE *privf = privkey_fopen(filename, &err); + if (!privf) { + return err; + } + + err = otrl_privkey_generate_FILEp(us, privf, accountname, protocol); + + fclose(privf); + return err; +} + +/* Generate a private DSA key for a given account, storing it into a + * FILE*, and loading it into the given OtrlUserState. Overwrite any + * previously generated keys for that account in that OtrlUserState. + * The FILE* must be open for reading and writing. */ +gcry_error_t otrl_privkey_generate_FILEp(OtrlUserState us, FILE *privf, + const char *accountname, const char *protocol) +{ + void *newkey = NULL; + gcry_error_t err; + + err = otrl_privkey_generate_start(us, accountname, protocol, &newkey); + if (newkey) { + otrl_privkey_generate_calculate(newkey); + err = otrl_privkey_generate_finish_FILEp(us, newkey, privf); + } + + return err; +} + +/* Convert a hex character to a value */ +static unsigned int ctoh(char c) +{ + if (c >= '0' && c <= '9') return c-'0'; + if (c >= 'a' && c <= 'f') return c-'a'+10; + if (c >= 'A' && c <= 'F') return c-'A'+10; + return 0; /* Unknown hex char */ +} + +/* Read the fingerprint store from a file on disk into the given + * OtrlUserState. Use add_app_data to add application data to each + * ConnContext so created. */ +gcry_error_t otrl_privkey_read_fingerprints(OtrlUserState us, + const char *filename, + void (*add_app_data)(void *data, ConnContext *context), + void *data) +{ + gcry_error_t err; + FILE *storef; + + storef = fopen(filename, "rb"); + if (!storef) { + err = gcry_error_from_errno(errno); + return err; + } + + err = otrl_privkey_read_fingerprints_FILEp(us, storef, add_app_data, data); + + fclose(storef); + return err; +} + +/* Read the fingerprint store from a FILE* into the given + * OtrlUserState. Use add_app_data to add application data to each + * ConnContext so created. The FILE* must be open for reading. */ +gcry_error_t otrl_privkey_read_fingerprints_FILEp(OtrlUserState us, + FILE *storef, + void (*add_app_data)(void *data, ConnContext *context), + void *data) +{ + ConnContext *context; + char storeline[1000]; + unsigned char fingerprint[20]; + size_t maxsize = sizeof(storeline); + + if (!storef) return gcry_error(GPG_ERR_NO_ERROR); + + while(fgets(storeline, maxsize, storef)) { + char *username; + char *accountname; + char *protocol; + char *hex; + char *trust; + char *tab; + char *eol; + Fingerprint *fng; + int i, j; + /* Parse the line, which should be of the form: + * username\taccountname\tprotocol\t40_hex_nybbles\n */ + username = storeline; + tab = strchr(username, '\t'); + if (!tab) continue; + *tab = '\0'; + + accountname = tab + 1; + tab = strchr(accountname, '\t'); + if (!tab) continue; + *tab = '\0'; + + protocol = tab + 1; + tab = strchr(protocol, '\t'); + if (!tab) continue; + *tab = '\0'; + + hex = tab + 1; + tab = strchr(hex, '\t'); + if (!tab) { + eol = strchr(hex, '\r'); + if (!eol) eol = strchr(hex, '\n'); + if (!eol) continue; + *eol = '\0'; + trust = NULL; + } else { + *tab = '\0'; + trust = tab + 1; + eol = strchr(trust, '\r'); + if (!eol) eol = strchr(trust, '\n'); + if (!eol) continue; + *eol = '\0'; + } + + if (strlen(hex) != 40) continue; + for(j=0, i=0; i<40; i+=2) { + fingerprint[j++] = (ctoh(hex[i]) << 4) + (ctoh(hex[i+1])); + } + /* Get the context for this user, adding if not yet present */ + context = otrl_context_find(us, username, accountname, protocol, + OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data); + /* Add the fingerprint if not already there */ + fng = otrl_context_find_fingerprint(context, fingerprint, 1, NULL); + otrl_context_set_trust(fng, trust); + } + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Write the fingerprint store from a given OtrlUserState to a file on disk. */ +gcry_error_t otrl_privkey_write_fingerprints(OtrlUserState us, + const char *filename) +{ + gcry_error_t err; + FILE *storef; + + storef = fopen(filename, "wb"); + if (!storef) { + err = gcry_error_from_errno(errno); + return err; + } + + err = otrl_privkey_write_fingerprints_FILEp(us, storef); + + fclose(storef); + return err; +} + +/* Write the fingerprint store from a given OtrlUserState to a FILE*. + * The FILE* must be open for writing. */ +gcry_error_t otrl_privkey_write_fingerprints_FILEp(OtrlUserState us, + FILE *storef) +{ + ConnContext *context; + Fingerprint *fprint; + + if (!storef) return gcry_error(GPG_ERR_NO_ERROR); + + for(context = us->context_root; context; context = context->next) { + /* Fingerprints are only stored in the master contexts */ + if (context->their_instance != OTRL_INSTAG_MASTER) continue; + + /* Don't bother with the first (fingerprintless) entry. */ + for (fprint = context->fingerprint_root.next; fprint; + fprint = fprint->next) { + int i; + fprintf(storef, "%s\t%s\t%s\t", context->username, + context->accountname, context->protocol); + for(i=0;i<20;++i) { + fprintf(storef, "%02x", fprint->fingerprint[i]); + } + fprintf(storef, "\t%s\n", fprint->trust ? fprint->trust : ""); + } + } + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Fetch the private key from the given OtrlUserState associated with + * the given account */ +OtrlPrivKey *otrl_privkey_find(OtrlUserState us, const char *accountname, + const char *protocol) +{ + OtrlPrivKey *p; + if (!accountname || !protocol) return NULL; + + for(p=us->privkey_root; p; p=p->next) { + if (!strcmp(p->accountname, accountname) && + !strcmp(p->protocol, protocol)) { + return p; + } + } + return NULL; +} + +/* Forget a private key */ +void otrl_privkey_forget(OtrlPrivKey *privkey) +{ + free(privkey->accountname); + free(privkey->protocol); + gcry_sexp_release(privkey->privkey); + free(privkey->pubkey_data); + + /* Re-link the list */ + *(privkey->tous) = privkey->next; + if (privkey->next) { + privkey->next->tous = privkey->tous; + } + + /* Free the privkey struct */ + free(privkey); +} + +/* Forget all private keys in a given OtrlUserState. */ +void otrl_privkey_forget_all(OtrlUserState us) +{ + while (us->privkey_root) { + otrl_privkey_forget(us->privkey_root); + } +} + +/* Sign data using a private key. The data must be small enough to be + * signed (i.e. already hashed, if necessary). The signature will be + * returned in *sigp, which the caller must free(). Its length will be + * returned in *siglenp. */ +gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp, + OtrlPrivKey *privkey, const unsigned char *data, size_t len) +{ + gcry_mpi_t r,s, datampi; + gcry_sexp_t dsas, rs, ss, sigs, datas; + size_t nr, ns; + const enum gcry_mpi_format format = GCRYMPI_FMT_USG; + + if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) + return gcry_error(GPG_ERR_INV_VALUE); + + *sigp = malloc(40); + if (*sigp == NULL) return gcry_error(GPG_ERR_ENOMEM); + *siglenp = 40; + + if (len) { + gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL); + } else { + datampi = gcry_mpi_set_ui(NULL, 0); + } + gcry_sexp_build(&datas, NULL, "(%m)", datampi); + gcry_mpi_release(datampi); + gcry_pk_sign(&sigs, datas, privkey->privkey); + gcry_sexp_release(datas); + dsas = gcry_sexp_find_token(sigs, "dsa", 0); + gcry_sexp_release(sigs); + rs = gcry_sexp_find_token(dsas, "r", 0); + ss = gcry_sexp_find_token(dsas, "s", 0); + gcry_sexp_release(dsas); + r = gcry_sexp_nth_mpi(rs, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(rs); + s = gcry_sexp_nth_mpi(ss, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(ss); + gcry_mpi_print(format, NULL, 0, &nr, r); + gcry_mpi_print(format, NULL, 0, &ns, s); + memset(*sigp, 0, 40); + gcry_mpi_print(format, (*sigp)+(20-nr), nr, NULL, r); + gcry_mpi_print(format, (*sigp)+20+(20-ns), ns, NULL, s); + gcry_mpi_release(r); + gcry_mpi_release(s); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Verify a signature on data using a public key. The data must be + * small enough to be signed (i.e. already hashed, if necessary). */ +gcry_error_t otrl_privkey_verify(const unsigned char *sigbuf, size_t siglen, + unsigned short pubkey_type, gcry_sexp_t pubs, + const unsigned char *data, size_t len) +{ + gcry_error_t err; + gcry_mpi_t datampi,r,s; + gcry_sexp_t datas, sigs; + + if (pubkey_type != OTRL_PUBKEY_TYPE_DSA || siglen != 40) + return gcry_error(GPG_ERR_INV_VALUE); + + if (len) { + gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL); + } else { + datampi = gcry_mpi_set_ui(NULL, 0); + } + gcry_sexp_build(&datas, NULL, "(%m)", datampi); + gcry_mpi_release(datampi); + gcry_mpi_scan(&r, GCRYMPI_FMT_USG, sigbuf, 20, NULL); + gcry_mpi_scan(&s, GCRYMPI_FMT_USG, sigbuf+20, 20, NULL); + gcry_sexp_build(&sigs, NULL, "(sig-val (dsa (r %m)(s %m)))", r, s); + gcry_mpi_release(r); + gcry_mpi_release(s); + + err = gcry_pk_verify(sigs, datas, pubs); + gcry_sexp_release(datas); + gcry_sexp_release(sigs); + + return err; +} + diff --git a/comm/third_party/libotr/src/privkey.h b/comm/third_party/libotr/src/privkey.h new file mode 100644 index 0000000000..3b2c1735e3 --- /dev/null +++ b/comm/third_party/libotr/src/privkey.h @@ -0,0 +1,154 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __PRIVKEY_H__ +#define __PRIVKEY_H__ + +#include +#include "privkey-t.h" +#include "userstate.h" + +/* The length of a string representing a human-readable version of a + * fingerprint (including the trailing NUL) */ +#define OTRL_PRIVKEY_FPRINT_HUMAN_LEN 45 + +/* Convert a 20-byte hash value to a 45-byte human-readable value */ +void otrl_privkey_hash_to_human( + char human[OTRL_PRIVKEY_FPRINT_HUMAN_LEN], + const unsigned char hash[20]); + +/* Calculate a human-readable hash of our DSA public key. Return it in + * the passed fingerprint buffer. Return NULL on error, or a pointer to + * the given buffer on success. */ +char *otrl_privkey_fingerprint(OtrlUserState us, + char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN], + const char *accountname, const char *protocol); + +/* Calculate a raw hash of our DSA public key. Return it in the passed + * fingerprint buffer. Return NULL on error, or a pointer to the given + * buffer on success. */ +unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us, + unsigned char hash[20], const char *accountname, const char *protocol); + +/* Read a sets of private DSA keys from a file on disk into the given + * OtrlUserState. */ +gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename); + +/* Read a sets of private DSA keys from a FILE* into the given + * OtrlUserState. The FILE* must be open for reading. */ +gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf); + +/* Free the memory associated with the pending privkey list */ +void otrl_privkey_pending_forget_all(OtrlUserState us); + +/* Begin a private key generation that will potentially take place in + * a background thread. This routine must be called from the main + * thread. It will set *newkeyp, which you can pass to + * otrl_privkey_generate_calculate in a background thread. If it + * returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for + * this accountname/protocol is already in progress, and *newkeyp will + * be set to NULL. */ +gcry_error_t otrl_privkey_generate_start(OtrlUserState us, + const char *accountname, const char *protocol, void **newkeyp); + +/* Do the private key generation calculation. You may call this from a + * background thread. When it completes, call + * otrl_privkey_generate_finish from the _main_ thread. */ +gcry_error_t otrl_privkey_generate_calculate(void *newkey); + +/* Call this from the main thread only. It will write the newly created + * private key into the given file and store it in the OtrlUserState. */ +gcry_error_t otrl_privkey_generate_finish(OtrlUserState us, + void *newkey, const char *filename); + +/* Call this from the main thread only. It will write the newly created + * private key into the given FILE* (which must be open for reading and + * writing) and store it in the OtrlUserState. */ +gcry_error_t otrl_privkey_generate_finish_FILEp(OtrlUserState us, + void *newkey, FILE *privf); + +/* Call this from the main thread only, in the event that the background + * thread generating the key is cancelled. The newkey is deallocated, + * and must not be used further. */ +void otrl_privkey_generate_cancelled(OtrlUserState us, void *newkey); + +/* Generate a private DSA key for a given account, storing it into a + * file on disk, and loading it into the given OtrlUserState. Overwrite any + * previously generated keys for that account in that OtrlUserState. */ +gcry_error_t otrl_privkey_generate(OtrlUserState us, const char *filename, + const char *accountname, const char *protocol); + +/* Generate a private DSA key for a given account, storing it into a + * FILE*, and loading it into the given OtrlUserState. Overwrite any + * previously generated keys for that account in that OtrlUserState. + * The FILE* must be open for reading and writing. */ +gcry_error_t otrl_privkey_generate_FILEp(OtrlUserState us, FILE *privf, + const char *accountname, const char *protocol); + +/* Read the fingerprint store from a file on disk into the given + * OtrlUserState. Use add_app_data to add application data to each + * ConnContext so created. */ +gcry_error_t otrl_privkey_read_fingerprints(OtrlUserState us, + const char *filename, + void (*add_app_data)(void *data, ConnContext *context), + void *data); + +/* Read the fingerprint store from a FILE* into the given + * OtrlUserState. Use add_app_data to add application data to each + * ConnContext so created. The FILE* must be open for reading. */ +gcry_error_t otrl_privkey_read_fingerprints_FILEp(OtrlUserState us, + FILE *storef, + void (*add_app_data)(void *data, ConnContext *context), + void *data); + +/* Write the fingerprint store from a given OtrlUserState to a file on disk. */ +gcry_error_t otrl_privkey_write_fingerprints(OtrlUserState us, + const char *filename); + +/* Write the fingerprint store from a given OtrlUserState to a FILE*. + * The FILE* must be open for writing. */ +gcry_error_t otrl_privkey_write_fingerprints_FILEp(OtrlUserState us, + FILE *storef); + +/* Fetch the private key from the given OtrlUserState associated with + * the given account */ +OtrlPrivKey *otrl_privkey_find(OtrlUserState us, const char *accountname, + const char *protocol); + +/* Forget a private key */ +void otrl_privkey_forget(OtrlPrivKey *privkey); + +/* Forget all private keys in a given OtrlUserState. */ +void otrl_privkey_forget_all(OtrlUserState us); + +/* Sign data using a private key. The data must be small enough to be + * signed (i.e. already hashed, if necessary). The signature will be + * returned in *sigp, which the caller must free(). Its length will be + * returned in *siglenp. */ +gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp, + OtrlPrivKey *privkey, const unsigned char *data, size_t len); + +/* Verify a signature on data using a public key. The data must be + * small enough to be signed (i.e. already hashed, if necessary). */ +gcry_error_t otrl_privkey_verify(const unsigned char *sigbuf, size_t siglen, + unsigned short pubkey_type, gcry_sexp_t pubs, + const unsigned char *data, size_t len); + +#endif diff --git a/comm/third_party/libotr/src/proto.c b/comm/third_party/libotr/src/proto.c new file mode 100644 index 0000000000..8d82dc126e --- /dev/null +++ b/comm/third_party/libotr/src/proto.c @@ -0,0 +1,1081 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2016 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* OTR Protocol implementation. This file should be independent of + * gaim, so that it can be used to make other clients. */ + +/* system headers */ +#include +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "b64.h" +#include "privkey.h" +#include "proto.h" +#include "mem.h" +#include "version.h" +#include "tlv.h" +#include "serial.h" + +#if OTRL_DEBUGGING +extern const char *OTRL_DEBUGGING_DEBUGSTR; +#endif + +/* For now, we need to know the API version the client is using so that + * we don't use any UI callbacks it hasn't set. */ +unsigned int otrl_api_version = 0; + +/* Initialize the OTR library. Pass the version of the API you are + * using. */ +gcry_error_t otrl_init(unsigned int ver_major, unsigned int ver_minor, + unsigned int ver_sub) +{ + unsigned int api_version; + + /* The major versions have to match, and you can't be using a newer + * minor version than we expect. */ + if (ver_major != OTRL_VERSION_MAJOR || ver_minor > OTRL_VERSION_MINOR) { + fprintf(stderr, "Expected libotr API version %u.%u.%u incompatible " + "with actual version %u.%u.%u. Aborting.\n", + ver_major, ver_minor, ver_sub, + OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Set the API version. If we get called multiple times for some + * reason, take the smallest value. */ + api_version = (ver_major << 16) | (ver_minor << 8) | (ver_sub); + if (otrl_api_version == 0 || otrl_api_version > api_version) { + otrl_api_version = api_version; + } + + /* Initialize the memory module */ + otrl_mem_init(); + + /* Initialize the DH module */ + otrl_dh_init(); + + /* Initialize the SM module */ + otrl_sm_init(); + +#if OTRL_DEBUGGING + /* Inform the user that debugging is available */ + fprintf(stderr, "\nlibotr debugging is available. Type %s in a message\n" + " to see debug info.\n\n", OTRL_DEBUGGING_DEBUGSTR); +#endif + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Return a pointer to a static string containing the version number of + * the OTR library. */ +const char *otrl_version(void) +{ + return OTRL_VERSION; +} + +/* Store some MAC keys to be revealed later */ +static gcry_error_t reveal_macs(ConnContext *context, + DH_sesskeys *sess1, DH_sesskeys *sess2) +{ + unsigned int numnew = sess1->rcvmacused + sess1->sendmacused + + sess2->rcvmacused + sess2->sendmacused; + unsigned int newnumsaved; + unsigned char *newmacs; + + /* Is there anything to do? */ + if (numnew == 0) return gcry_error(GPG_ERR_NO_ERROR); + + newnumsaved = context->context_priv->numsavedkeys + numnew; + newmacs = realloc(context->context_priv->saved_mac_keys, + newnumsaved * 20); + if (!newmacs) { + return gcry_error(GPG_ERR_ENOMEM); + } + if (sess1->rcvmacused) { + memmove(newmacs + context->context_priv->numsavedkeys * 20, + sess1->rcvmackey, 20); + context->context_priv->numsavedkeys++; + } + if (sess1->sendmacused) { + memmove(newmacs + context->context_priv->numsavedkeys * 20, + sess1->sendmackey, 20); + context->context_priv->numsavedkeys++; + } + if (sess2->rcvmacused) { + memmove(newmacs + context->context_priv->numsavedkeys * 20, + sess2->rcvmackey, 20); + context->context_priv->numsavedkeys++; + } + if (sess2->sendmacused) { + memmove(newmacs + context->context_priv->numsavedkeys * 20, + sess2->sendmackey, 20); + context->context_priv->numsavedkeys++; + } + context->context_priv->saved_mac_keys = newmacs; + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Make a new DH key for us, and rotate old old ones. Be sure to keep + * the sesskeys array in sync. */ +static gcry_error_t rotate_dh_keys(ConnContext *context) +{ + gcry_error_t err; + + /* Rotate the keypair */ + otrl_dh_keypair_free(&(context->context_priv->our_old_dh_key)); + memmove(&(context->context_priv->our_old_dh_key), + &(context->context_priv->our_dh_key), + sizeof(DH_keypair)); + + /* Rotate the session keys */ + err = reveal_macs(context, &(context->context_priv->sesskeys[1][0]), + &(context->context_priv->sesskeys[1][1])); + if (err) return err; + otrl_dh_session_free(&(context->context_priv->sesskeys[1][0])); + otrl_dh_session_free(&(context->context_priv->sesskeys[1][1])); + memmove(&(context->context_priv->sesskeys[1][0]), + &(context->context_priv->sesskeys[0][0]), + sizeof(DH_sesskeys)); + memmove(&(context->context_priv->sesskeys[1][1]), + &(context->context_priv->sesskeys[0][1]), + sizeof(DH_sesskeys)); + + /* Create a new DH key */ + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(context->context_priv->our_dh_key)); + context->context_priv->our_keyid++; + + /* Make the session keys */ + if (context->context_priv->their_y) { + err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]), + &(context->context_priv->our_dh_key), + context->context_priv->their_y); + if (err) return err; + } else { + otrl_dh_session_blank(&(context->context_priv->sesskeys[0][0])); + } + if (context->context_priv->their_old_y) { + err = otrl_dh_session(&(context->context_priv->sesskeys[0][1]), + &(context->context_priv->our_dh_key), + context->context_priv->their_old_y); + if (err) return err; + } else { + otrl_dh_session_blank(&(context->context_priv->sesskeys[0][1])); + } + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Rotate in a new DH public key for our correspondent. Be sure to keep + * the sesskeys array in sync. */ +static gcry_error_t rotate_y_keys(ConnContext *context, gcry_mpi_t new_y) +{ + gcry_error_t err; + + /* Rotate the public key */ + gcry_mpi_release(context->context_priv->their_old_y); + context->context_priv->their_old_y = context->context_priv->their_y; + + /* Rotate the session keys */ + err = reveal_macs(context, &(context->context_priv->sesskeys[0][1]), + &(context->context_priv->sesskeys[1][1])); + if (err) return err; + otrl_dh_session_free(&(context->context_priv->sesskeys[0][1])); + otrl_dh_session_free(&(context->context_priv->sesskeys[1][1])); + memmove(&(context->context_priv->sesskeys[0][1]), + &(context->context_priv->sesskeys[0][0]), + sizeof(DH_sesskeys)); + memmove(&(context->context_priv->sesskeys[1][1]), + &(context->context_priv->sesskeys[1][0]), + sizeof(DH_sesskeys)); + + /* Copy in the new public key */ + context->context_priv->their_y = gcry_mpi_copy(new_y); + context->context_priv->their_keyid++; + + /* Make the session keys */ + err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]), + &(context->context_priv->our_dh_key), + context->context_priv->their_y); + if (err) return err; + err = otrl_dh_session(&(context->context_priv->sesskeys[1][0]), + &(context->context_priv->our_old_dh_key), + context->context_priv->their_y); + if (err) return err; + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Return a pointer to a newly-allocated OTR query message, customized + * with our name. The caller should free() the result when he's done + * with it. */ +char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy) +{ + char *msg; + int v1_supported, v2_supported, v3_supported; + char *version_tag; + char *bufp; + /* Don't use g_strdup_printf here, because someone (not us) is going + * to free() the *message pointer, not g_free() it. We can't + * require that they g_free() it, because this pointer will probably + * get passed to the main IM application for processing (and + * free()ing). */ + const char *format = "?OTR%s\n%s has requested an " + "
Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + /* Figure out the version tag */ + v1_supported = (policy & OTRL_POLICY_ALLOW_V1); + v2_supported = (policy & OTRL_POLICY_ALLOW_V2); + v3_supported = (policy & OTRL_POLICY_ALLOW_V3); + version_tag = malloc(8); + bufp = version_tag; + if (v1_supported) { + *bufp = '?'; + bufp++; + } + if (v2_supported || v3_supported) { + *bufp = 'v'; + bufp++; + if (v2_supported) { + *bufp = '2'; + bufp++; + } + if (v3_supported) { + *bufp = '3'; + bufp++; + } + *bufp = '?'; + bufp++; + } + *bufp = '\0'; + + /* Remove two "%s", add '\0' */ + msg = malloc(strlen(format) + strlen(version_tag) + strlen(ourname) - 3); + if (!msg) { + free(version_tag); + return NULL; + } + sprintf(msg, format, version_tag, ourname); + free(version_tag); + return msg; +} + +/* Return the best version of OTR support by both sides, given an OTR + * Query Message and the local policy. */ +unsigned int otrl_proto_query_bestversion(const char *otrquerymsg, + OtrlPolicy policy) +{ + char *otrtag; + unsigned int query_versions = 0; + + + otrtag = strstr(otrquerymsg, "?OTR"); + if (!otrtag) { + return 0; + } + otrtag += 4; + + if (*otrtag == '?') { + query_versions = (1<<0); + ++otrtag; + } + if (*otrtag == 'v') { + for(++otrtag; *otrtag && *otrtag != '?'; ++otrtag) { + switch(*otrtag) { + case '2': + query_versions |= (1<<1); + break; + case '3': + query_versions |= (1<<2); + break; + } + } + } + + if ((policy & OTRL_POLICY_ALLOW_V3) && (query_versions & (1<<2))) { + return 3; + } + if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) { + return 2; + } + if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) { + return 1; + } + return 0; +} + +/* Locate any whitespace tag in this message, and return the best + * version of OTR support on both sides. Set *starttagp and *endtagp to + * the start and end of the located tag, so that it can be snipped out. */ +unsigned int otrl_proto_whitespace_bestversion(const char *msg, + const char **starttagp, const char **endtagp, OtrlPolicy policy) +{ + const char *starttag, *endtag; + unsigned int query_versions = 0; + + *starttagp = NULL; + *endtagp = NULL; + + starttag = strstr(msg, OTRL_MESSAGE_TAG_BASE); + if (!starttag) return 0; + + endtag = starttag + strlen(OTRL_MESSAGE_TAG_BASE); + + /* Look for groups of 8 spaces and/or tabs */ + while(1) { + int i; + int allwhite = 1; + for(i=0;i<8;++i) { + if (endtag[i] != ' ' && endtag[i] != '\t') { + allwhite = 0; + break; + } + } + if (allwhite) { + if (!strncmp(endtag, OTRL_MESSAGE_TAG_V1, 8)) { + query_versions |= (1<<0); + } + if (!strncmp(endtag, OTRL_MESSAGE_TAG_V2, 8)) { + query_versions |= (1<<1); + } + if (!strncmp(endtag, OTRL_MESSAGE_TAG_V3, 8)) { + query_versions |= (1<<2); + } + endtag += 8; + } else { + break; + } + } + + *starttagp = starttag; + *endtagp = endtag; + + if ((policy & OTRL_POLICY_ALLOW_V3) && (query_versions & (1<<2))) { + return 3; + } + if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) { + return 2; + } + if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) { + return 1; + } + return 0; +} + +/* Find the message type. */ +OtrlMessageType otrl_proto_message_type(const char *message) +{ + char *otrtag; + + otrtag = strstr(message, "?OTR"); + + if (!otrtag) { + if (strstr(message, OTRL_MESSAGE_TAG_BASE)) { + return OTRL_MSGTYPE_TAGGEDPLAINTEXT; + } else { + return OTRL_MSGTYPE_NOTOTR; + } + } + + if (!strncmp(otrtag, "?OTR:AAM", 8) || !strncmp(otrtag, "?OTR:AAI", 8)) { + switch(*(otrtag + 8)) { + case 'C': return OTRL_MSGTYPE_DH_COMMIT; + case 'K': return OTRL_MSGTYPE_DH_KEY; + case 'R': return OTRL_MSGTYPE_REVEALSIG; + case 'S': return OTRL_MSGTYPE_SIGNATURE; + case 'D': return OTRL_MSGTYPE_DATA; + } + } else { + if (!strncmp(otrtag, "?OTR?", 5)) return OTRL_MSGTYPE_QUERY; + if (!strncmp(otrtag, "?OTRv", 5)) return OTRL_MSGTYPE_QUERY; + if (!strncmp(otrtag, "?OTR:AAEK", 9)) return OTRL_MSGTYPE_V1_KEYEXCH; + if (!strncmp(otrtag, "?OTR:AAED", 9)) return OTRL_MSGTYPE_DATA; + if (!strncmp(otrtag, "?OTR Error:", 11)) return OTRL_MSGTYPE_ERROR; + } + return OTRL_MSGTYPE_UNKNOWN; +} + +/* Find the message version. */ +int otrl_proto_message_version(const char *message) +{ + char *otrtag; + + otrtag = strstr(message, "?OTR"); + + if (!otrtag) { + return 0; + } + + if (!strncmp(otrtag, "?OTR:AAM", 8)) + return 3; + if (!strncmp(otrtag, "?OTR:AAI", 8)) + return 2; + if (!strncmp(otrtag, "?OTR:AAE", 8)) + return 1; + + return 0; +} + +/* Find the instance tags in this message */ +gcry_error_t otrl_proto_instance(const char *otrmsg, + unsigned int *instance_from, unsigned int *instance_to) +{ + gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); + + const char *otrtag = otrmsg; + unsigned char *bufp = NULL; + unsigned char *bufp_head = NULL; + size_t lenp; + + if (!otrtag || strncmp(otrtag, "?OTR:AAM", 8)) { + goto invval; + } + + if (strlen(otrtag) < 21 ) goto invval; + + /* Decode and extract instance tag */ + bufp = malloc(OTRL_B64_MAX_DECODED_SIZE(12)); + bufp_head = bufp; + lenp = otrl_base64_decode(bufp, otrtag+9, 12); + read_int(*instance_from); + read_int(*instance_to); + free(bufp_head); + return gcry_error(GPG_ERR_NO_ERROR); +invval: + free(bufp_head); + err = gcry_error(GPG_ERR_INV_VALUE); + return err; +} + +/* Create an OTR Data message. Pass the plaintext as msg, and an + * optional chain of TLVs. A newly-allocated string will be returned in + * *encmessagep. Put the current extra symmetric key into extrakey + * (if non-NULL). */ +gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context, + const char *msg, const OtrlTLV *tlvs, unsigned char flags, + unsigned char *extrakey) +{ + size_t justmsglen = strlen(msg); + size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs); + size_t buflen; + size_t pubkeylen; + unsigned char *buf = NULL; + unsigned char *bufp; + size_t lenp; + DH_sesskeys *sess = &(context->context_priv->sesskeys[1][0]); + gcry_error_t err; + size_t reveallen = 20 * context->context_priv->numsavedkeys; + char *base64buf = NULL; + unsigned char *msgbuf = NULL; + enum gcry_mpi_format format = GCRYMPI_FMT_USG; + char *msgdup; + int version = context->protocol_version; + + *encmessagep = NULL; + + /* Make sure we're actually supposed to be able to encrypt */ + if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED || + context->context_priv->their_keyid == 0) { + return gcry_error(GPG_ERR_CONFLICT); + } + + /* We need to copy the incoming msg, since it might be an alias for + * context->lastmessage, which we'll be freeing soon. */ + msgdup = gcry_malloc_secure(justmsglen + 1); + if (msgdup == NULL) { + return gcry_error(GPG_ERR_ENOMEM); + } + strcpy(msgdup, msg); + + /* Header, msg flags, send keyid, recv keyid, counter, msg len, msg + * len of revealed mac keys, revealed mac keys, MAC */ + buflen = OTRL_HEADER_LEN + (version == 3 ? 8 : 0) + + (version == 2 || version == 3 ? 1 : 0) + 4 + 4 + + 8 + 4 + msglen + 4 + reveallen + 20; + gcry_mpi_print(format, NULL, 0, &pubkeylen, + context->context_priv->our_dh_key.pub); + buflen += pubkeylen + 4; + buf = malloc(buflen); + msgbuf = gcry_malloc_secure(msglen); + if (buf == NULL || msgbuf == NULL) { + free(buf); + gcry_free(msgbuf); + gcry_free(msgdup); + return gcry_error(GPG_ERR_ENOMEM); + } + memmove(msgbuf, msgdup, justmsglen); + msgbuf[justmsglen] = '\0'; + otrl_tlv_serialize(msgbuf + justmsglen + 1, tlvs); + bufp = buf; + lenp = buflen; + if (version == 1) { + memmove(bufp, "\x00\x01\x03", 3); /* header */ + } else if (version == 2) { + memmove(bufp, "\x00\x02\x03", 3); /* header */ + } else { + memmove(bufp, "\x00\x03\x03", 3); /* header */ + } + + debug_data("Header", bufp, 3); + bufp += 3; lenp -= 3; + + if (version == 3) { + /* v3 instance tags */ + write_int(context->our_instance); + debug_int("Sender instag", bufp-4); + write_int(context->their_instance); + debug_int("Recipient instag", bufp-4); + } + + if (version == 2 || version == 3) { + bufp[0] = flags; + bufp += 1; lenp -= 1; + } + + write_int(context->context_priv->our_keyid-1); /* sender keyid */ + debug_int("Sender keyid", bufp-4); + write_int(context->context_priv->their_keyid); /* recipient keyid */ + debug_int("Recipient keyid", bufp-4); + + write_mpi(context->context_priv->our_dh_key.pub, pubkeylen, "Y"); /* Y */ + + otrl_dh_incctr(sess->sendctr); + memmove(bufp, sess->sendctr, 8); /* Counter (top 8 bytes only) */ + debug_data("Counter", bufp, 8); + bufp += 8; lenp -= 8; + + write_int(msglen); /* length of encrypted data */ + debug_int("Msg len", bufp-4); + + err = gcry_cipher_reset(sess->sendenc); + if (err) goto err; + err = gcry_cipher_setctr(sess->sendenc, sess->sendctr, 16); + if (err) goto err; + err = gcry_cipher_encrypt(sess->sendenc, bufp, msglen, msgbuf, msglen); + if (err) goto err; /* encrypted data */ + debug_data("Enc data", bufp, msglen); + bufp += msglen; + lenp -= msglen; + + gcry_md_reset(sess->sendmac); + gcry_md_write(sess->sendmac, buf, bufp-buf); + memmove(bufp, gcry_md_read(sess->sendmac, GCRY_MD_SHA1), 20); + debug_data("MAC", bufp, 20); + bufp += 20; /* MAC */ + lenp -= 20; + + write_int(reveallen); /* length of revealed MAC keys */ + debug_int("Revealed MAC length", bufp-4); + + if (reveallen > 0) { + memmove(bufp, context->context_priv->saved_mac_keys, reveallen); + debug_data("Revealed MAC data", bufp, reveallen); + bufp += reveallen; lenp -= reveallen; + free(context->context_priv->saved_mac_keys); + context->context_priv->saved_mac_keys = NULL; + context->context_priv->numsavedkeys = 0; + } + + assert(lenp == 0); + + /* Make the base64-encoding. */ + base64buf = otrl_base64_otr_encode(buf, buflen); + if (base64buf == NULL) { + err = gcry_error(GPG_ERR_ENOMEM); + goto err; + } + + free(buf); + gcry_free(msgbuf); + *encmessagep = base64buf; + gcry_free(context->context_priv->lastmessage); + context->context_priv->lastmessage = NULL; + context->context_priv->may_retransmit = 0; + if (msglen > 0) { + context->context_priv->lastmessage = gcry_malloc_secure(justmsglen + 1); + if (context->context_priv->lastmessage) { + strcpy(context->context_priv->lastmessage, msgdup); + } + } + gcry_free(msgdup); + + /* Save a copy of the current extra key */ + if (extrakey) { + memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES); + } + + return gcry_error(GPG_ERR_NO_ERROR); +err: + free(buf); + gcry_free(msgbuf); + gcry_free(msgdup); + *encmessagep = NULL; + return err; +} + +/* Extract the flags from an otherwise unreadable Data Message. */ +gcry_error_t otrl_proto_data_read_flags(const char *datamsg, + unsigned char *flagsp) +{ + char *otrtag, *endtag; + unsigned char *rawmsg = NULL; + unsigned char *bufp; + size_t msglen, rawlen, lenp; + unsigned char version; + + if (flagsp) *flagsp = 0; + otrtag = strstr(datamsg, "?OTR:"); + if (!otrtag) { + goto invval; + } + endtag = strchr(otrtag, '.'); + if (endtag) { + msglen = endtag-otrtag; + } else { + msglen = strlen(otrtag); + } + + /* Skip over the "?OTR:" */ + otrtag += 5; + msglen -= 5; + + /* Base64-decode the message */ + rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen); /* maximum possible */ + rawmsg = malloc(rawlen); + if (!rawmsg && rawlen > 0) { + return gcry_error(GPG_ERR_ENOMEM); + } + rawlen = otrl_base64_decode(rawmsg, otrtag, msglen); /* actual size */ + + bufp = rawmsg; + lenp = rawlen; + + require_len(3); + version = bufp[1]; + skip_header('\x03'); + + if (version == 3) { + require_len(8); + bufp += 8; lenp -= 8; + } + + if (version == 2 || version == 3) { + require_len(1); + if (flagsp) *flagsp = bufp[0]; + bufp += 1; lenp -= 1; + } + + free(rawmsg); + return gcry_error(GPG_ERR_NO_ERROR); + +invval: + free(rawmsg); + return gcry_error(GPG_ERR_INV_VALUE); +} + +/* Accept an OTR Data Message in datamsg. Decrypt it and put the + * plaintext into *plaintextp, and any TLVs into tlvsp. Put any + * received flags into *flagsp (if non-NULL). Put the current extra + * symmetric key into extrakey (if non-NULL). */ +gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp, + ConnContext *context, const char *datamsg, unsigned char *flagsp, + unsigned char *extrakey) +{ + char *otrtag, *endtag; + gcry_error_t err; + unsigned char *rawmsg = NULL; + size_t msglen, rawlen, lenp; + unsigned char *macstart, *macend; + unsigned char *bufp; + unsigned int sender_keyid, recipient_keyid; + gcry_mpi_t sender_next_y = NULL; + unsigned char ctr[8]; + size_t datalen, reveallen; + unsigned char *data = NULL; + unsigned char *nul = NULL; + unsigned char givenmac[20]; + DH_sesskeys *sess; + unsigned char version; + + *plaintextp = NULL; + *tlvsp = NULL; + if (flagsp) *flagsp = 0; + otrtag = strstr(datamsg, "?OTR:"); + if (!otrtag) { + goto invval; + } + endtag = strchr(otrtag, '.'); + if (endtag) { + msglen = endtag-otrtag; + } else { + msglen = strlen(otrtag); + } + + /* Skip over the "?OTR:" */ + otrtag += 5; + msglen -= 5; + + /* Base64-decode the message */ + rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen); /* maximum possible */ + rawmsg = malloc(rawlen); + if (!rawmsg && rawlen > 0) { + err = gcry_error(GPG_ERR_ENOMEM); + goto err; + } + rawlen = otrl_base64_decode(rawmsg, otrtag, msglen); /* actual size */ + + bufp = rawmsg; + lenp = rawlen; + + macstart = bufp; + require_len(3); + version = bufp[1]; + + skip_header('\x03'); + + if (version == 3) { + require_len(8); + bufp += 8; lenp -= 8; + } + + if (version == 2 || version == 3) { + require_len(1); + if (flagsp) *flagsp = bufp[0]; + bufp += 1; lenp -= 1; + } + + read_int(sender_keyid); + read_int(recipient_keyid); + read_mpi(sender_next_y); + require_len(8); + memmove(ctr, bufp, 8); + bufp += 8; lenp -= 8; + read_int(datalen); + require_len(datalen); + data = malloc(datalen+1); + if (!data) { + err = gcry_error(GPG_ERR_ENOMEM); + goto err; + } + memmove(data, bufp, datalen); + data[datalen] = '\0'; + bufp += datalen; lenp -= datalen; + macend = bufp; + require_len(20); + memmove(givenmac, bufp, 20); + bufp += 20; lenp -= 20; + read_int(reveallen); + require_len(reveallen); + /* Just skip over the revealed MAC keys, which we don't need. They + * were published for deniability of transcripts. */ + bufp += reveallen; lenp -= reveallen; + + /* That should be everything */ + if (lenp != 0) goto invval; + + /* We don't take any action on this message (especially rotating + * keys) until we've verified the MAC on this message. To that end, + * we need to know which keys this message is claiming to use. */ + if (context->context_priv->their_keyid == 0 || + (sender_keyid != context->context_priv->their_keyid && + sender_keyid != context->context_priv->their_keyid - 1) || + (recipient_keyid != context->context_priv->our_keyid && + recipient_keyid != context->context_priv->our_keyid - 1) || + sender_keyid == 0 || recipient_keyid == 0) { + goto conflict; + } + + if (sender_keyid == context->context_priv->their_keyid - 1 && + context->context_priv->their_old_y == NULL) { + goto conflict; + } + + /* These are the session keys this message is claiming to use. */ + sess = &(context->context_priv->sesskeys + [context->context_priv->our_keyid - recipient_keyid] + [context->context_priv->their_keyid - sender_keyid]); + + gcry_md_reset(sess->rcvmac); + gcry_md_write(sess->rcvmac, macstart, macend-macstart); + if (otrl_mem_differ(givenmac, gcry_md_read(sess->rcvmac, GCRY_MD_SHA1), + 20)) { + /* The MACs didn't match! */ + goto conflict; + } + sess->rcvmacused = 1; + + /* Check to see that the counter is increasing; i.e. that this isn't + * a replay. */ + if (otrl_dh_cmpctr(ctr, sess->rcvctr) <= 0) { + goto conflict; + } + + /* Decrypt the message */ + memmove(sess->rcvctr, ctr, 8); + err = gcry_cipher_reset(sess->rcvenc); + if (err) goto err; + err = gcry_cipher_setctr(sess->rcvenc, sess->rcvctr, 16); + if (err) goto err; + err = gcry_cipher_decrypt(sess->rcvenc, data, datalen, NULL, 0); + if (err) goto err; + + /* Save a copy of the current extra key */ + if (extrakey) { + memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES); + } + + /* See if either set of keys needs rotating */ + + if (recipient_keyid == context->context_priv->our_keyid) { + /* They're using our most recent key, so generate a new one */ + err = rotate_dh_keys(context); + if (err) goto err; + } + + if (sender_keyid == context->context_priv->their_keyid) { + /* They've sent us a new public key */ + err = rotate_y_keys(context, sender_next_y); + if (err) goto err; + } + + gcry_mpi_release(sender_next_y); + *plaintextp = (char *)data; + + /* See if there are TLVs */ + nul = data; + while (nul < data+datalen && *nul) ++nul; + /* If we stopped before the end, skip the NUL we stopped at */ + if (nul < data+datalen) ++nul; + *tlvsp = otrl_tlv_parse(nul, (data+datalen)-nul); + + free(rawmsg); + return gcry_error(GPG_ERR_NO_ERROR); + +invval: + err = gcry_error(GPG_ERR_INV_VALUE); + goto err; +conflict: + err = gcry_error(GPG_ERR_CONFLICT); + goto err; +err: + gcry_mpi_release(sender_next_y); + free(data); + free(rawmsg); + return err; +} + +/* Accumulate a potential fragment into the current context. */ +OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep, + ConnContext *context, const char *msg) +{ + OtrlFragmentResult res = OTRL_FRAGMENT_INCOMPLETE; + const char *tag; + unsigned short n = 0, k = 0; + int start = 0, end = 0; + + tag = strstr(msg, "?OTR|"); + if (tag) { + sscanf(tag, "?OTR|%*x|%*x,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end); + } else if ((tag = strstr(msg, "?OTR,")) != NULL) { + sscanf(tag, "?OTR,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end); + } else { + /* Unfragmented message, so discard any fragment we may have */ + free(context->context_priv->fragment); + context->context_priv->fragment = NULL; + context->context_priv->fragment_len = 0; + context->context_priv->fragment_n = 0; + context->context_priv->fragment_k = 0; + res = OTRL_FRAGMENT_UNFRAGMENTED; + return res; + } + + if (k > 0 && n > 0 && k <= n && start > 0 && end > 0 && start < end) { + if (k == 1) { + size_t fraglen = end - start - 1; + size_t newsize = fraglen + 1; + free(context->context_priv->fragment); + context->context_priv->fragment = NULL; + if (newsize >= 1) { /* Check for overflow */ + context->context_priv->fragment = malloc(newsize); + } + if (context->context_priv->fragment) { + memmove(context->context_priv->fragment, tag + start, fraglen); + context->context_priv->fragment_len = fraglen; + context->context_priv->fragment[ + context->context_priv->fragment_len] = '\0'; + context->context_priv->fragment_n = n; + context->context_priv->fragment_k = k; + } else { + context->context_priv->fragment_len = 0; + context->context_priv->fragment_n = 0; + context->context_priv->fragment_k = 0; + } + } else if (n == context->context_priv->fragment_n && + k == context->context_priv->fragment_k + 1) { + size_t fraglen = end - start - 1; + char *newfrag = NULL; + size_t newsize = context->context_priv->fragment_len + fraglen + 1; + /* Check for overflow */ + if (newsize > context->context_priv->fragment_len) { + newfrag = realloc(context->context_priv->fragment, newsize); + } + if (newfrag) { + context->context_priv->fragment = newfrag; + memmove(context->context_priv->fragment + + context->context_priv->fragment_len, + tag + start, fraglen); + context->context_priv->fragment_len += fraglen; + context->context_priv->fragment[ + context->context_priv->fragment_len] = '\0'; + context->context_priv->fragment_k = k; + } else { + free(context->context_priv->fragment); + context->context_priv->fragment = NULL; + context->context_priv->fragment_len = 0; + context->context_priv->fragment_n = 0; + context->context_priv->fragment_k = 0; + } + } else { + free(context->context_priv->fragment); + context->context_priv->fragment = NULL; + context->context_priv->fragment_len = 0; + context->context_priv->fragment_n = 0; + context->context_priv->fragment_k = 0; + } + } + + if (context->context_priv->fragment_n > 0 && + context->context_priv->fragment_n == + context->context_priv->fragment_k) { + /* We've got a complete message */ + *unfragmessagep = context->context_priv->fragment; + context->context_priv->fragment = NULL; + context->context_priv->fragment_len = 0; + context->context_priv->fragment_n = 0; + context->context_priv->fragment_k = 0; + res = OTRL_FRAGMENT_COMPLETE; + } + + return res; +} + +/* Create a fragmented message. */ +gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count, + char ***fragments, ConnContext *context, const char *message) +{ + char *fragdata; + size_t fragdatalen = 0; + int curfrag = 0; + size_t index = 0; + size_t msglen = strlen(message); + /* Should vary by number of msgs */ + int headerlen = context->protocol_version == 3 ? 37 : 19; + + char **fragmentarray; + + if (fragment_count < 1 || fragment_count > 65535) { + return gcry_error(GPG_ERR_INV_VALUE); + } + + fragmentarray = malloc(fragment_count * sizeof(char*)); + if(!fragmentarray) return gcry_error(GPG_ERR_ENOMEM); + + /* + * Find the next message fragment and store it in the array. + */ + for(curfrag = 1; curfrag <= fragment_count; curfrag++) { + int i; + char *fragmentmsg; + + if (msglen - index < (size_t)(mms - headerlen)) { + fragdatalen = msglen - index; + } else { + fragdatalen = mms - headerlen; + } + + fragdata = malloc(fragdatalen + 1); + if(!fragdata) { + for (i=0; iauth.protocol_version != 3) { + snprintf(fragmentmsg, fragdatalen + headerlen, + "?OTR,%05hu,%05hu,%s,", (unsigned short)curfrag, + (unsigned short)fragment_count, fragdata); + } else { + /* V3 messages require instance tags in the header */ + snprintf(fragmentmsg, fragdatalen + headerlen, + "?OTR|%08x|%08x,%05hu,%05hu,%s,", + context->our_instance, context->their_instance, + (unsigned short)curfrag, (unsigned short)fragment_count, + fragdata); + } + fragmentmsg[fragdatalen + headerlen] = 0; + + fragmentarray[curfrag-1] = fragmentmsg; + + free(fragdata); + index += fragdatalen; + message += fragdatalen; + } + + *fragments = fragmentarray; + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Free a string array containing fragment messages. */ +void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen) +{ + int i; + char **fragmentarray = *fragments; + if(fragmentarray) { + for(i = 0; i < arraylen; i++) + { + if(fragmentarray[i]) { + free(fragmentarray[i]); + } + } + free(fragmentarray); + } +} + diff --git a/comm/third_party/libotr/src/proto.h b/comm/third_party/libotr/src/proto.h new file mode 100644 index 0000000000..28be83f439 --- /dev/null +++ b/comm/third_party/libotr/src/proto.h @@ -0,0 +1,174 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __PROTO_H__ +#define __PROTO_H__ + +#include "context.h" +#include "version.h" +#include "tlv.h" + +/* If we ever see this sequence in a plaintext message, we'll assume the + * other side speaks OTR, and try to establish a connection. */ +#define OTRL_MESSAGE_TAG_BASE " \t \t\t\t\t \t \t \t " +/* The following must each be of length 8 */ +#define OTRL_MESSAGE_TAG_V1 " \t \t \t " +#define OTRL_MESSAGE_TAG_V2 " \t\t \t " +#define OTRL_MESSAGE_TAG_V3 " \t\t \t\t" + +/* The possible flags contained in a Data Message */ +#define OTRL_MSGFLAGS_IGNORE_UNREADABLE 0x01 + +typedef unsigned int OtrlPolicy; + +#define OTRL_POLICY_ALLOW_V1 0x01 +#define OTRL_POLICY_ALLOW_V2 0x02 +#define OTRL_POLICY_ALLOW_V3 0x04 +#define OTRL_POLICY_REQUIRE_ENCRYPTION 0x08 +#define OTRL_POLICY_SEND_WHITESPACE_TAG 0x10 +#define OTRL_POLICY_WHITESPACE_START_AKE 0x20 +#define OTRL_POLICY_ERROR_START_AKE 0x40 + +#define OTRL_POLICY_VERSION_MASK (OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2 |\ + OTRL_POLICY_ALLOW_V3) + +/* Length of OTR message headers */ +#define OTRL_HEADER_LEN 3 +#define OTRL_B64_HEADER_LEN 4 + +/* Analogous to v1 policies */ +#define OTRL_POLICY_NEVER 0x00 +#define OTRL_POLICY_OPPORTUNISTIC \ + ( OTRL_POLICY_ALLOW_V2 | \ + OTRL_POLICY_ALLOW_V3 | \ + OTRL_POLICY_SEND_WHITESPACE_TAG | \ + OTRL_POLICY_WHITESPACE_START_AKE | \ + OTRL_POLICY_ERROR_START_AKE ) +#define OTRL_POLICY_MANUAL \ + ( OTRL_POLICY_ALLOW_V2 | \ + OTRL_POLICY_ALLOW_V3) +#define OTRL_POLICY_ALWAYS \ + ( OTRL_POLICY_ALLOW_V2 | \ + OTRL_POLICY_ALLOW_V3 | \ + OTRL_POLICY_REQUIRE_ENCRYPTION | \ + OTRL_POLICY_WHITESPACE_START_AKE | \ + OTRL_POLICY_ERROR_START_AKE ) +#define OTRL_POLICY_DEFAULT OTRL_POLICY_OPPORTUNISTIC + +typedef enum { + OTRL_MSGTYPE_NOTOTR, + OTRL_MSGTYPE_TAGGEDPLAINTEXT, + OTRL_MSGTYPE_QUERY, + OTRL_MSGTYPE_DH_COMMIT, + OTRL_MSGTYPE_DH_KEY, + OTRL_MSGTYPE_REVEALSIG, + OTRL_MSGTYPE_SIGNATURE, + OTRL_MSGTYPE_V1_KEYEXCH, + OTRL_MSGTYPE_DATA, + OTRL_MSGTYPE_ERROR, + OTRL_MSGTYPE_UNKNOWN +} OtrlMessageType; + +typedef enum { + OTRL_FRAGMENT_UNFRAGMENTED, + OTRL_FRAGMENT_INCOMPLETE, + OTRL_FRAGMENT_COMPLETE +} OtrlFragmentResult; + +typedef enum { + OTRL_FRAGMENT_SEND_SKIP, /* Return new message back to caller, + * but don't inject. */ + OTRL_FRAGMENT_SEND_ALL, + OTRL_FRAGMENT_SEND_ALL_BUT_FIRST, + OTRL_FRAGMENT_SEND_ALL_BUT_LAST +} OtrlFragmentPolicy; + +/* Initialize the OTR library. Pass the version of the API you are + * using. */ +gcry_error_t otrl_init(unsigned int ver_major, unsigned int ver_minor, + unsigned int ver_sub); + +/* Shortcut */ +#define OTRL_INIT do { \ + if (otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, \ + OTRL_VERSION_SUB)) { \ + exit(1); \ + } \ + } while(0) + +/* Return a pointer to a static string containing the version number of + * the OTR library. */ +const char *otrl_version(void); + +/* Return a pointer to a newly-allocated OTR query message, customized + * with our name. The caller should free() the result when he's done + * with it. */ +char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy); + +/* Return the best version of OTR support by both sides, given an OTR + * Query Message and the local policy. */ +unsigned int otrl_proto_query_bestversion(const char *querymsg, + OtrlPolicy policy); + +/* Locate any whitespace tag in this message, and return the best + * version of OTR support on both sides. Set *starttagp and *endtagp to + * the start and end of the located tag, so that it can be snipped out. */ +unsigned int otrl_proto_whitespace_bestversion(const char *msg, + const char **starttagp, const char **endtagp, OtrlPolicy policy); + +/* Find the message type. */ +OtrlMessageType otrl_proto_message_type(const char *message); + +/* Find the message version. */ +int otrl_proto_message_version(const char *message); + +/* Find the instance tags in this message. */ +gcry_error_t otrl_proto_instance(const char *otrmsg, + unsigned int *instance_from, unsigned int *instance_to); + +/* Create an OTR Data message. Pass the plaintext as msg, and an + * optional chain of TLVs. A newly-allocated string will be returned in + * *encmessagep. Put the current extra symmetric key into extrakey + * (if non-NULL). */ +gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context, + const char *msg, const OtrlTLV *tlvs, unsigned char flags, + unsigned char *extrakey); + +/* Extract the flags from an otherwise unreadable Data Message. */ +gcry_error_t otrl_proto_data_read_flags(const char *datamsg, + unsigned char *flagsp); + +/* Accept an OTR Data Message in datamsg. Decrypt it and put the + * plaintext into *plaintextp, and any TLVs into tlvsp. Put any + * received flags into *flagsp (if non-NULL). Put the current extra + * symmetric key into extrakey (if non-NULL). */ +gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp, + ConnContext *context, const char *datamsg, unsigned char *flagsp, + unsigned char *extrakey); + +/* Accumulate a potential fragment into the current context. */ +OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep, + ConnContext *context, const char *msg); + +gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count, + char ***fragments, ConnContext *context, const char *message); + +void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen); +#endif diff --git a/comm/third_party/libotr/src/serial.h b/comm/third_party/libotr/src/serial.h new file mode 100644 index 0000000000..cd2442b332 --- /dev/null +++ b/comm/third_party/libotr/src/serial.h @@ -0,0 +1,107 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#undef DEBUG + +#ifdef DEBUG + +#include + +#define debug_data(t,b,l) do { const unsigned char *data = (b); size_t i; \ + fprintf(stderr, "%s: ", (t)); \ + for(i=0;i<(l);++i) { \ + fprintf(stderr, "%02x", data[i]); \ + } \ + fprintf(stderr, "\n"); \ + } while(0) + +#define debug_int(t,b) do { const unsigned char *data = (b); \ + unsigned int v = \ + (((unsigned int)data[0]) << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \ + fprintf(stderr, "%s: %u (0x%x)\n", (t), v, v); \ + } while(0) + +#else +#define debug_data(t,b,l) +#define debug_int(t,b) +#endif + +#define write_int(x) do { \ + bufp[0] = ((x) >> 24) & 0xff; \ + bufp[1] = ((x) >> 16) & 0xff; \ + bufp[2] = ((x) >> 8) & 0xff; \ + bufp[3] = (x) & 0xff; \ + bufp += 4; lenp -= 4; \ + } while(0) + +#define write_mpi(x,nx,dx) do { \ + write_int(nx); \ + gcry_mpi_print(format, bufp, lenp, NULL, (x)); \ + debug_data((dx), bufp, (nx)); \ + bufp += (nx); lenp -= (nx); \ + } while(0) + +#define require_len(l) do { \ + if (lenp < (l)) goto invval; \ + } while(0) + +#define read_int(x) do { \ + require_len(4); \ + (x) = (((unsigned int)bufp[0]) << 24) | (bufp[1] << 16) | (bufp[2] << 8) | bufp[3]; \ + bufp += 4; lenp -= 4; \ + } while(0) + +#define read_mpi(x) do { \ + size_t mpilen; \ + read_int(mpilen); \ + if (mpilen) { \ + require_len(mpilen); \ + gcry_mpi_scan(&(x), GCRYMPI_FMT_USG, bufp, mpilen, NULL); \ + } else { \ + (x) = gcry_mpi_set_ui(NULL, 0); \ + } \ + bufp += mpilen; lenp -= mpilen; \ + } while(0) + +/* Write version and msg type into bufp*/ +#define write_header(version, msgtype) do { \ + bufp[0] = 0x00; \ + bufp[1] = version & 0xff; \ + bufp[2] = msgtype; \ + debug_data("Header", bufp, 3); \ + bufp += 3; lenp -= 3; \ + } while(0) + +/* Verify msg header is v1, v2 or v3 and has type x, +* increment bufp past msg header */ +#define skip_header(x) do { \ + require_len(3); \ + if ((bufp[0] != 0x00) || (bufp[2] != x)) \ + goto invval; \ + if ((bufp[1] == 0x01) || (bufp[1] == 0x02) || \ + (bufp[1] == 0x03)) { \ + bufp += 3; lenp -= 3; \ + } else goto invval; \ + } while(0) + +#endif diff --git a/comm/third_party/libotr/src/sm.c b/comm/third_party/libotr/src/sm.c new file mode 100644 index 0000000000..4fb679ea81 --- /dev/null +++ b/comm/third_party/libotr/src/sm.c @@ -0,0 +1,998 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include +#include + +/* libgcrypt headers */ +#include + +/* libotr headers */ +#include "sm.h" +#include "serial.h" + +#if OTRL_DEBUGGING + +/* Dump the contents of an SMState to the FILE *f. */ +void otrl_sm_dump(FILE *f, const OtrlSMState *sm) +{ + fprintf(f, " SM state:\n"); + fprintf(f, " Next expected: %d (%s)\n", sm->nextExpected, + sm->nextExpected == OTRL_SMP_EXPECT1 ? "EXPECT1" : + sm->nextExpected == OTRL_SMP_EXPECT2 ? "EXPECT2" : + sm->nextExpected == OTRL_SMP_EXPECT3 ? "EXPECT3" : + sm->nextExpected == OTRL_SMP_EXPECT4 ? "EXPECT4" : + sm->nextExpected == OTRL_SMP_EXPECT5 ? "EXPECT5" : + "INVALID"); + fprintf(f, " Received_Q: %d\n", sm->received_question); + fprintf(f, " Progress state: %d (%s)\n", sm->sm_prog_state, + sm->sm_prog_state == OTRL_SMP_PROG_OK ? "OK" : + sm->sm_prog_state == OTRL_SMP_PROG_CHEATED ? "CHEATED" : + sm->sm_prog_state == OTRL_SMP_PROG_FAILED ? "FAILED" : + sm->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED ? "SUCCEEDED" : + "INVALID"); +} + +#endif + +static const int SM_MSG1_LEN = 6; +static const int SM_MSG2_LEN = 11; +static const int SM_MSG3_LEN = 8; +static const int SM_MSG4_LEN = 3; + +/* The modulus p */ +static const char* SM_MODULUS_S = "0x" + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; +/* The order of the group q = (p-1)/2 */ +static const char* SM_ORDER_S = "0x" + "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" + "948127044533E63A0105DF531D89CD9128A5043CC71A026E" + "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" + "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" + "F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9E" + "E1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AF" + "C1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36" + "B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF"; +static const char *SM_GENERATOR_S = "0x02"; +static const int SM_MOD_LEN_BITS = 1536; +static const int SM_MOD_LEN_BYTES = 192; + +static gcry_mpi_t SM_MODULUS = NULL; +static gcry_mpi_t SM_GENERATOR = NULL; +static gcry_mpi_t SM_ORDER = NULL; +static gcry_mpi_t SM_MODULUS_MINUS_2 = NULL; + +/* + * Call this once, at plugin load time. It sets up the modulus and + * generator MPIs. + */ +void otrl_sm_init(void) +{ + gcry_check_version(NULL); + gcry_mpi_scan(&SM_MODULUS, GCRYMPI_FMT_HEX, + (const unsigned char *)SM_MODULUS_S, 0, NULL); + gcry_mpi_scan(&SM_ORDER, GCRYMPI_FMT_HEX, + (const unsigned char *)SM_ORDER_S, 0, NULL); + gcry_mpi_scan(&SM_GENERATOR, GCRYMPI_FMT_HEX, + (const unsigned char *)SM_GENERATOR_S, 0, NULL); + SM_MODULUS_MINUS_2 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_sub_ui(SM_MODULUS_MINUS_2, SM_MODULUS, 2); +} + +/* + * Initialize the fields of a SM state. + */ +void otrl_sm_state_new(OtrlSMState *smst) +{ + smst->secret = NULL; + smst->x2 = NULL; + smst->x3 = NULL; + smst->g1 = NULL; + smst->g2 = NULL; + smst->g3 = NULL; + smst->g3o = NULL; + smst->p = NULL; + smst->q = NULL; + smst->pab = NULL; + smst->qab = NULL; + smst->nextExpected = OTRL_SMP_EXPECT1; + smst->received_question = 0; + smst->sm_prog_state = OTRL_SMP_PROG_OK; +} + +/* + * Initialize the fields of a SM state. Called the first time that + * a user begins an SMP session. + */ +void otrl_sm_state_init(OtrlSMState *smst) +{ + otrl_sm_state_free(smst); + smst->secret = gcry_mpi_snew(SM_MOD_LEN_BITS); + smst->x2 = NULL; + smst->x3 = NULL; + smst->g1 = gcry_mpi_copy(SM_GENERATOR); + smst->g2 = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->g3 = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->g3o = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->p = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->q = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->pab = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->qab = gcry_mpi_new(SM_MOD_LEN_BITS); + smst->received_question = 0; + smst->sm_prog_state = OTRL_SMP_PROG_OK; +} + +/* + * Initialize the fields of a SM message1. + * [0] = g2a, [1] = c2, [2] = d2, [3] = g3a, [4] = c3, [5] = d3 + */ +void otrl_sm_msg1_init(gcry_mpi_t **msg1) +{ + gcry_mpi_t *msg = malloc(SM_MSG1_LEN * sizeof(gcry_mpi_t)); + msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[1] = NULL; + msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[4] = NULL; + msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS); + + *msg1 = msg; +} + +/* + * Initialize the fields of a SM message2. + * [0] = g2b, [1] = c2, [2] = d2, [3] = g3b, [4] = c3, [5] = d3 + * [6] = pb, [7] = qb, [8] = cp, [9] = d5, [10] = d6 + */ +void otrl_sm_msg2_init(gcry_mpi_t **msg2) +{ + gcry_mpi_t *msg = malloc(SM_MSG2_LEN * sizeof(gcry_mpi_t)); + msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[1] = NULL; + msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[4] = NULL; + msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[6] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[8] = NULL; + msg[9] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[10] = gcry_mpi_new(SM_MOD_LEN_BITS); + + *msg2 = msg; +} + +/* + * Initialize the fields of a SM message3. + * [0] = pa, [1] = qa, [2] = cp, [3] = d5, [4] = d6, [5] = ra, + * [6] = cr, [7] = d7 + */ +void otrl_sm_msg3_init(gcry_mpi_t **msg3) +{ + gcry_mpi_t *msg = malloc(SM_MSG3_LEN * sizeof(gcry_mpi_t)); + msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[1] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[2] = NULL; + msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[4] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[6] = NULL; + msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS); + + *msg3 = msg; +} + +/* + * Initialize the fields of a SM message4. + * [0] = rb, [1] = cr, [2] = d7 + */ +void otrl_sm_msg4_init(gcry_mpi_t **msg4) +{ + gcry_mpi_t *msg = malloc(SM_MSG4_LEN * sizeof(gcry_mpi_t)); + msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); + msg[1] = NULL; + msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS); + + *msg4 = msg; +} + +/* + * Deallocate the contents of a OtrlSMState (but not the OtrlSMState + * itself) + */ +void otrl_sm_state_free(OtrlSMState *smst) +{ + gcry_mpi_release(smst->secret); + gcry_mpi_release(smst->x2); + gcry_mpi_release(smst->x3); + gcry_mpi_release(smst->g1); + gcry_mpi_release(smst->g2); + gcry_mpi_release(smst->g3); + gcry_mpi_release(smst->g3o); + gcry_mpi_release(smst->p); + gcry_mpi_release(smst->q); + gcry_mpi_release(smst->pab); + gcry_mpi_release(smst->qab); + otrl_sm_state_new(smst); +} + +/* + * Deallocate the contents of a message + */ +void otrl_sm_msg_free(gcry_mpi_t **message, int msglen) +{ + gcry_mpi_t *msg = *message; + int i; + for (i=0; i> 24) & 0xFF); + input[2] = (unsigned char)((sizea >> 16) & 0xFF); + input[3] = (unsigned char)((sizea >> 8) & 0xFF); + input[4] = (unsigned char)(sizea & 0xFF); + memmove(input + 5, dataa, sizea); + if (b) { + input[5 + sizea] = (unsigned char)((sizeb >> 24) & 0xFF); + input[6 + sizea] = (unsigned char)((sizeb >> 16) & 0xFF); + input[7 + sizea] = (unsigned char)((sizeb >> 8) & 0xFF); + input[8 + sizea] = (unsigned char)(sizeb & 0xFF); + memmove(input + 9 + sizea, datab, sizeb); + } + + gcry_md_hash_buffer(SM_HASH_ALGORITHM, output, input, totalsize); + gcry_mpi_scan(hash, GCRYMPI_FMT_USG, output, SM_DIGEST_SIZE, NULL); + free(input); + input = NULL; + + /* free memory */ + gcry_free(dataa); + if (b) gcry_free(datab); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* This method should be passed a pointer to an uninitialized buffer, + * and a list of mpis with a list length. When returns, the buffer will + * point to newly-allocated memory (using malloc) containing a + * reversible serialization. */ +static gcry_error_t serialize_mpi_array(unsigned char **buffer, int *buflen, + unsigned int count, gcry_mpi_t *mpis) +{ + size_t totalsize = 0, lenp, nextsize; + unsigned int i, j; + size_t *list_sizes = malloc(count * sizeof(size_t)); + unsigned char **tempbuffer = malloc(count * sizeof(unsigned char *)); + unsigned char *bufp; + + for (i=0; i 0) { + return 1; + } + return 0; +} + +/* Check that an MPI is in the right range to be a (non-zero) exponent */ +static int check_expon(gcry_mpi_t x) +{ + if (gcry_mpi_cmp_ui(x, 1) < 0 || + gcry_mpi_cmp(x, SM_ORDER) >= 0) { + return 1; + } + return 0; +} + +/* + * Proof of knowledge of a discrete logarithm + */ +static gcry_error_t otrl_sm_proof_know_log(gcry_mpi_t *c, gcry_mpi_t *d, + const gcry_mpi_t g, const gcry_mpi_t x, int version) +{ + gcry_mpi_t r = randomExponent(); + gcry_mpi_t temp = gcry_mpi_snew(SM_MOD_LEN_BITS); + gcry_mpi_powm(temp, g, r, SM_MODULUS); + otrl_sm_hash(c, version, temp, NULL); + gcry_mpi_mulm(temp, x, *c, SM_ORDER); + gcry_mpi_subm(*d, r, temp, SM_ORDER); + gcry_mpi_release(temp); + gcry_mpi_release(r); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* + * Verify a proof of knowledge of a discrete logarithm. + * Checks that c = h(g^d x^c) + */ +static int otrl_sm_check_know_log(const gcry_mpi_t c, const gcry_mpi_t d, + const gcry_mpi_t g, const gcry_mpi_t x, int version) +{ + int comp; + + gcry_mpi_t gd = gcry_mpi_new(SM_MOD_LEN_BITS); /* g^d */ + gcry_mpi_t xc = gcry_mpi_new(SM_MOD_LEN_BITS); /* x^c */ + gcry_mpi_t gdxc = gcry_mpi_new(SM_MOD_LEN_BITS); /* (g^d x^c) */ + gcry_mpi_t hgdxc = NULL; /* h(g^d x^c) */ + + gcry_mpi_powm(gd, g, d, SM_MODULUS); + gcry_mpi_powm(xc, x, c, SM_MODULUS); + gcry_mpi_mulm(gdxc, gd, xc, SM_MODULUS); + otrl_sm_hash(&hgdxc, version, gdxc, NULL); + + comp = gcry_mpi_cmp(hgdxc, c); + gcry_mpi_release(gd); + gcry_mpi_release(xc); + gcry_mpi_release(gdxc); + gcry_mpi_release(hgdxc); + + return comp; +} + +/* + * Proof of knowledge of coordinates with first components being equal + */ +static gcry_error_t otrl_sm_proof_equal_coords(gcry_mpi_t *c, gcry_mpi_t *d1, + gcry_mpi_t *d2, const OtrlSMState *state, const gcry_mpi_t r, + int version) +{ + gcry_mpi_t r1 = randomExponent(); + gcry_mpi_t r2 = randomExponent(); + gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); + + /* Compute the value of c, as c = h(g3^r1, g1^r1 g2^r2) */ + gcry_mpi_powm(temp1, state->g1, r1, SM_MODULUS); + gcry_mpi_powm(temp2, state->g2, r2, SM_MODULUS); + gcry_mpi_mulm(temp2, temp1, temp2, SM_MODULUS); + gcry_mpi_powm(temp1, state->g3, r1, SM_MODULUS); + otrl_sm_hash(c, version, temp1, temp2); + + /* Compute the d values, as d1 = r1 - r c, d2 = r2 - secret c */ + gcry_mpi_mulm(temp1, r, *c, SM_ORDER); + gcry_mpi_subm(*d1, r1, temp1, SM_ORDER); + + gcry_mpi_mulm(temp1, state->secret, *c, SM_ORDER); + gcry_mpi_subm(*d2, r2, temp1, SM_ORDER); + + /* All clear */ + gcry_mpi_release(r1); + gcry_mpi_release(r2); + gcry_mpi_release(temp1); + gcry_mpi_release(temp2); + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* + * Verify a proof of knowledge of coordinates with first components being equal + */ +static gcry_error_t otrl_sm_check_equal_coords(const gcry_mpi_t c, + const gcry_mpi_t d1, const gcry_mpi_t d2, const gcry_mpi_t p, + const gcry_mpi_t q, const OtrlSMState *state, int version) +{ + int comp; + + gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t cprime = NULL; + + /* To verify, we test that hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) = c + * If indeed c = hash(g3^r1, g1^r1 g2^r2), d1 = r1 - r*c, + * d2 = r2 - secret*c. And if indeed p = g3^r, q = g1^r * g2^secret + * Then we should have that: + * hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) + * = hash(g3^(r1 - r*c + r*c), g1^(r1 - r*c + q*c) * + * g2^(r2 - secret*c + secret*c)) + * = hash(g3^r1, g1^r1 g2^r2) + * = c + */ + gcry_mpi_powm(temp2, state->g3, d1, SM_MODULUS); + gcry_mpi_powm(temp3, p, c, SM_MODULUS); + gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS); + + gcry_mpi_powm(temp2, state->g1, d1, SM_MODULUS); + gcry_mpi_powm(temp3, state->g2, d2, SM_MODULUS); + gcry_mpi_mulm(temp2, temp2, temp3, SM_MODULUS); + gcry_mpi_powm(temp3, q, c, SM_MODULUS); + gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS); + + otrl_sm_hash(&cprime, version, temp1, temp2); + + comp = gcry_mpi_cmp(c, cprime); + gcry_mpi_release(temp1); + gcry_mpi_release(temp2); + gcry_mpi_release(temp3); + gcry_mpi_release(cprime); + + return comp; +} + +/* + * Proof of knowledge of logs with exponents being equal + */ +static gcry_error_t otrl_sm_proof_equal_logs(gcry_mpi_t *c, gcry_mpi_t *d, + OtrlSMState *state, int version) +{ + gcry_mpi_t r = randomExponent(); + gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); + + /* Compute the value of c, as c = h(g1^r, (Qa/Qb)^r) */ + gcry_mpi_powm(temp1, state->g1, r, SM_MODULUS); + gcry_mpi_powm(temp2, state->qab, r, SM_MODULUS); + otrl_sm_hash(c, version, temp1, temp2); + + /* Compute the d values, as d = r - x3 c */ + gcry_mpi_mulm(temp1, state->x3, *c, SM_ORDER); + gcry_mpi_subm(*d, r, temp1, SM_ORDER); + + /* All clear */ + gcry_mpi_release(r); + gcry_mpi_release(temp1); + gcry_mpi_release(temp2); + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* + * Verify a proof of knowledge of logs with exponents being equal + */ +static gcry_error_t otrl_sm_check_equal_logs(const gcry_mpi_t c, + const gcry_mpi_t d, const gcry_mpi_t r, const OtrlSMState *state, + int version) +{ + int comp; + + gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_t cprime = NULL; + + /* Here, we recall the exponents used to create g3. + * If we have previously seen g3o = g1^x where x is unknown + * during the DH exchange to produce g3, then we may proceed with: + * + * To verify, we test that hash(g1^d * g3o^c, qab^d * r^c) = c + * If indeed c = hash(g1^r1, qab^r1), d = r1- x * c + * And if indeed r = qab^x + * Then we should have that: + * hash(g1^d * g3o^c, qab^d r^c) + * = hash(g1^(r1 - x*c + x*c), qab^(r1 - x*c + x*c)) + * = hash(g1^r1, qab^r1) + * = c + */ + gcry_mpi_powm(temp2, state->g1, d, SM_MODULUS); + gcry_mpi_powm(temp3, state->g3o, c, SM_MODULUS); + gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS); + + gcry_mpi_powm(temp3, state->qab, d, SM_MODULUS); + gcry_mpi_powm(temp2, r, c, SM_MODULUS); + gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS); + + otrl_sm_hash(&cprime, version, temp1, temp2); + + comp = gcry_mpi_cmp(c, cprime); + gcry_mpi_release(temp1); + gcry_mpi_release(temp2); + gcry_mpi_release(temp3); + gcry_mpi_release(cprime); + + return comp; +} + +/* Create first message in SMP exchange. Input is Alice's secret value + * which this protocol aims to compare to Bob's. Output is a serialized + * mpi array whose elements correspond to the following: + * [0] = g2a, Alice's half of DH exchange to determine g2 + * [1] = c2, [2] = d2, Alice's ZK proof of knowledge of g2a exponent + * [3] = g3a, Alice's half of DH exchange to determine g3 + * [4] = c3, [5] = d3, Alice's ZK proof of knowledge of g3a exponent */ +gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate, + const unsigned char* secret, int secretlen, + unsigned char** output, int* outputlen) +{ + /* Initialize the sm state or update the secret */ + gcry_mpi_t secret_mpi = NULL; + gcry_mpi_t *msg1; + + *output = NULL; + *outputlen = 0; + + gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL); + + if (! astate->g1) { + otrl_sm_state_init(astate); + } + gcry_mpi_set(astate->secret, secret_mpi); + gcry_mpi_release(secret_mpi); + astate->received_question = 0; + + otrl_sm_msg1_init(&msg1); + + astate->x2 = randomExponent(); + astate->x3 = randomExponent(); + + gcry_mpi_powm(msg1[0], astate->g1, astate->x2, SM_MODULUS); + otrl_sm_proof_know_log(&(msg1[1]), &(msg1[2]), astate->g1, astate->x2, 1); + + gcry_mpi_powm(msg1[3], astate->g1, astate->x3, SM_MODULUS); + otrl_sm_proof_know_log(&(msg1[4]), &(msg1[5]), astate->g1, astate->x3, 2); + + serialize_mpi_array(output, outputlen, SM_MSG1_LEN, msg1); + otrl_sm_msg_free(&msg1, SM_MSG1_LEN); + astate->sm_prog_state = OTRL_SMP_PROG_OK; + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Receive the first message in SMP exchange, which was generated by + * otrl_sm_step1. Input is saved until the user inputs their secret + * information. No output. */ +gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, + const int inputlen, int received_question) +{ + gcry_mpi_t *msg1; + gcry_error_t err; + + /* Initialize the sm state if needed */ + if (! bstate->g1) { + otrl_sm_state_init(bstate); + } + bstate->received_question = received_question; + bstate->sm_prog_state = OTRL_SMP_PROG_CHEATED; + + /* Read from input to find the mpis */ + err = unserialize_mpi_array(&msg1, SM_MSG1_LEN, input, inputlen); + + if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; + + if (check_group_elem(msg1[0]) || check_expon(msg1[2]) || + check_group_elem(msg1[3]) || check_expon(msg1[5])) { + otrl_sm_msg_free(&msg1, SM_MSG1_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Store Alice's g3a value for later in the protocol */ + gcry_mpi_set(bstate->g3o, msg1[3]); + + /* Verify Alice's proofs */ + if (otrl_sm_check_know_log(msg1[1], msg1[2], bstate->g1, msg1[0], 1) || + otrl_sm_check_know_log(msg1[4], msg1[5], bstate->g1, msg1[3], 2)) { + otrl_sm_msg_free(&msg1, SM_MSG1_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Create Bob's half of the generators g2 and g3 */ + bstate->x2 = randomExponent(); + bstate->x3 = randomExponent(); + + /* Combine the two halves from Bob and Alice and determine g2 and g3 */ + gcry_mpi_powm(bstate->g2, msg1[0], bstate->x2, SM_MODULUS); + gcry_mpi_powm(bstate->g3, msg1[3], bstate->x3, SM_MODULUS); + + bstate->sm_prog_state = OTRL_SMP_PROG_OK; + + otrl_sm_msg_free(&msg1, SM_MSG1_LEN); + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Create second message in SMP exchange. Input is Bob's secret value. + * Information from earlier steps in the exchange is taken from Bob's + * state. Output is a serialized mpi array whose elements correspond + * to the following: + * [0] = g2b, Bob's half of DH exchange to determine g2 + * [1] = c2, [2] = d2, Bob's ZK proof of knowledge of g2b exponent + * [3] = g3b, Bob's half of DH exchange to determine g3 + * [4] = c3, [5] = d3, Bob's ZK proof of knowledge of g3b exponent + * [6] = pb, [7] = qb, Bob's halves of the (Pa/Pb) and (Qa/Qb) values + * [8] = cp, [9] = d5, [10] = d6, Bob's ZK proof that pb, qb formed correctly */ +gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, + int secretlen, unsigned char **output, int* outputlen) +{ + /* Convert the given secret to the proper form and store it */ + gcry_mpi_t r, qb1, qb2; + gcry_mpi_t *msg2; + gcry_mpi_t secret_mpi = NULL; + + *output = NULL; + *outputlen = 0; + + gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL); + gcry_mpi_set(bstate->secret, secret_mpi); + gcry_mpi_release(secret_mpi); + + otrl_sm_msg2_init(&msg2); + + gcry_mpi_powm(msg2[0], bstate->g1, bstate->x2, SM_MODULUS); + otrl_sm_proof_know_log(&(msg2[1]), &(msg2[2]), bstate->g1, bstate->x2, 3); + + gcry_mpi_powm(msg2[3], bstate->g1, bstate->x3, SM_MODULUS); + otrl_sm_proof_know_log(&(msg2[4]), &(msg2[5]), bstate->g1, bstate->x3, 4); + + /* Calculate P and Q values for Bob */ + r = randomExponent(); + qb1 = gcry_mpi_new(SM_MOD_LEN_BITS); + qb2 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_powm(bstate->p, bstate->g3, r, SM_MODULUS); + gcry_mpi_set(msg2[6], bstate->p); + gcry_mpi_powm(qb1, bstate->g1, r, SM_MODULUS); + gcry_mpi_powm(qb2, bstate->g2, bstate->secret, SM_MODULUS); + gcry_mpi_mulm(bstate->q, qb1, qb2, SM_MODULUS); + gcry_mpi_set(msg2[7], bstate->q); + + otrl_sm_proof_equal_coords(&(msg2[8]), &(msg2[9]), + &(msg2[10]), bstate, r, 5); + + /* Convert to serialized form */ + serialize_mpi_array(output, outputlen, SM_MSG2_LEN, msg2); + + /* Free up memory for unserialized and intermediate values */ + gcry_mpi_release(r); + gcry_mpi_release(qb1); + gcry_mpi_release(qb2); + otrl_sm_msg_free(&msg2, SM_MSG2_LEN); + + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Create third message in SMP exchange. Input is a message generated + * by otrl_sm_step2b. Output is a serialized mpi array whose elements + * correspond to the following: + * [0] = pa, [1] = qa, Alice's halves of the (Pa/Pb) and (Qa/Qb) values + * [2] = cp, [3] = d5, [4] = d6, Alice's ZK proof that pa, qa formed correctly + * [5] = ra, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3a + * [6] = cr, [7] = d7, Alice's ZK proof that ra is formed correctly */ +gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, + const int inputlen, unsigned char **output, int* outputlen) +{ + /* Read from input to find the mpis */ + gcry_mpi_t r, qa1, qa2, inv; + gcry_mpi_t *msg2; + gcry_mpi_t *msg3; + gcry_error_t err; + + *output = NULL; + *outputlen = 0; + astate->sm_prog_state = OTRL_SMP_PROG_CHEATED; + + err = unserialize_mpi_array(&msg2, SM_MSG2_LEN, input, inputlen); + if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; + + if (check_group_elem(msg2[0]) || check_group_elem(msg2[3]) || + check_group_elem(msg2[6]) || check_group_elem(msg2[7]) || + check_expon(msg2[2]) || check_expon(msg2[5]) || + check_expon(msg2[9]) || check_expon(msg2[10])) { + otrl_sm_msg_free(&msg2, SM_MSG2_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + otrl_sm_msg3_init(&msg3); + + /* Store Bob's g3a value for later in the protocol */ + gcry_mpi_set(astate->g3o, msg2[3]); + + /* Verify Bob's knowledge of discrete log proofs */ + if (otrl_sm_check_know_log(msg2[1], msg2[2], astate->g1, msg2[0], 3) || + otrl_sm_check_know_log(msg2[4], msg2[5], astate->g1, msg2[3], 4)) { + otrl_sm_msg_free(&msg2, SM_MSG2_LEN); + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Combine the two halves from Bob and Alice and determine g2 and g3 */ + gcry_mpi_powm(astate->g2, msg2[0], astate->x2, SM_MODULUS); + gcry_mpi_powm(astate->g3, msg2[3], astate->x3, SM_MODULUS); + + /* Verify Bob's coordinate equality proof */ + if (otrl_sm_check_equal_coords(msg2[8], msg2[9], msg2[10], msg2[6], msg2[7], + astate, 5)) { + otrl_sm_msg_free(&msg2, SM_MSG2_LEN); + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Calculate P and Q values for Alice */ + r = randomExponent(); + qa1 = gcry_mpi_new(SM_MOD_LEN_BITS); + qa2 = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_powm(astate->p, astate->g3, r, SM_MODULUS); + gcry_mpi_set(msg3[0], astate->p); + gcry_mpi_powm(qa1, astate->g1, r, SM_MODULUS); + gcry_mpi_powm(qa2, astate->g2, astate->secret, SM_MODULUS); + gcry_mpi_mulm(astate->q, qa1, qa2, SM_MODULUS); + gcry_mpi_set(msg3[1], astate->q); + + otrl_sm_proof_equal_coords(&(msg3[2]), &(msg3[3]), &(msg3[4]), astate, + r, 6); + + /* Calculate Ra and proof */ + inv = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_invm(inv, msg2[6], SM_MODULUS); + gcry_mpi_mulm(astate->pab, astate->p, inv, SM_MODULUS); + gcry_mpi_invm(inv, msg2[7], SM_MODULUS); + gcry_mpi_mulm(astate->qab, astate->q, inv, SM_MODULUS); + gcry_mpi_powm(msg3[5], astate->qab, astate->x3, SM_MODULUS); + otrl_sm_proof_equal_logs(&(msg3[6]), &(msg3[7]), astate, 7); + + serialize_mpi_array(output, outputlen, SM_MSG3_LEN, msg3); + otrl_sm_msg_free(&msg2, SM_MSG2_LEN); + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + + gcry_mpi_release(r); + gcry_mpi_release(qa1); + gcry_mpi_release(qa2); + gcry_mpi_release(inv); + + astate->sm_prog_state = OTRL_SMP_PROG_OK; + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Create final message in SMP exchange. Input is a message generated + * by otrl_sm_step3. Output is a serialized mpi array whose elements + * correspond to the following: + * [0] = rb, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3b + * [1] = cr, [2] = d7, Bob's ZK proof that rb is formed correctly + * This method also checks if Alice and Bob's secrets were the same. If + * so, it returns NO_ERROR. If the secrets differ, an INV_VALUE error is + * returned instead. */ +gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, + const int inputlen, unsigned char **output, int* outputlen) +{ + /* Read from input to find the mpis */ + int comp; + gcry_mpi_t inv, rab; + gcry_mpi_t *msg3; + gcry_mpi_t *msg4; + gcry_error_t err; + err = unserialize_mpi_array(&msg3, SM_MSG3_LEN, input, inputlen); + + *output = NULL; + *outputlen = 0; + bstate->sm_prog_state = OTRL_SMP_PROG_CHEATED; + + if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; + + otrl_sm_msg4_init(&msg4); + + if (check_group_elem(msg3[0]) || check_group_elem(msg3[1]) || + check_group_elem(msg3[5]) || check_expon(msg3[3]) || + check_expon(msg3[4]) || check_expon(msg3[7])) { + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Verify Alice's coordinate equality proof */ + if (otrl_sm_check_equal_coords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1], + bstate, 6)) { + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Find Pa/Pb and Qa/Qb */ + inv = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_invm(inv, bstate->p, SM_MODULUS); + gcry_mpi_mulm(bstate->pab, msg3[0], inv, SM_MODULUS); + gcry_mpi_invm(inv, bstate->q, SM_MODULUS); + gcry_mpi_mulm(bstate->qab, msg3[1], inv, SM_MODULUS); + + /* Verify Alice's log equality proof */ + if (otrl_sm_check_equal_logs(msg3[6], msg3[7], msg3[5], bstate, 7)) { + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + gcry_mpi_release(inv); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Calculate Rb and proof */ + gcry_mpi_powm(msg4[0], bstate->qab, bstate->x3, SM_MODULUS); + otrl_sm_proof_equal_logs(&(msg4[1]), &(msg4[2]), bstate, 8); + + serialize_mpi_array(output, outputlen, SM_MSG4_LEN, msg4); + + /* Calculate Rab and verify that secrets match */ + rab = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_powm(rab, msg3[5], bstate->x3, SM_MODULUS); + comp = gcry_mpi_cmp(rab, bstate->pab); + + /* Clean up everything allocated in this step */ + otrl_sm_msg_free(&msg3, SM_MSG3_LEN); + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + gcry_mpi_release(rab); + gcry_mpi_release(inv); + + bstate->sm_prog_state = comp ? OTRL_SMP_PROG_FAILED : + OTRL_SMP_PROG_SUCCEEDED; + + if (comp) + return gcry_error(GPG_ERR_INV_VALUE); + else + return gcry_error(GPG_ERR_NO_ERROR); +} + +/* Receives the final SMP message, which was generated in otrl_sm_step. + * This method checks if Alice and Bob's secrets were the same. If + * so, it returns NO_ERROR. If the secrets differ, an INV_VALUE error is + * returned instead. */ +gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, + const int inputlen) +{ + /* Read from input to find the mpis */ + int comp; + gcry_mpi_t rab; + gcry_mpi_t *msg4; + gcry_error_t err; + err = unserialize_mpi_array(&msg4, SM_MSG4_LEN, input, inputlen); + astate->sm_prog_state = OTRL_SMP_PROG_CHEATED; + + if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; + + if (check_group_elem(msg4[0]) || check_expon(msg4[2])) { + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Verify Bob's log equality proof */ + if (otrl_sm_check_equal_logs(msg4[1], msg4[2], msg4[0], astate, 8)) { + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + return gcry_error(GPG_ERR_INV_VALUE); + } + + /* Calculate Rab and verify that secrets match */ + rab = gcry_mpi_new(SM_MOD_LEN_BITS); + gcry_mpi_powm(rab, msg4[0], astate->x3, SM_MODULUS); + + comp = gcry_mpi_cmp(rab, astate->pab); + gcry_mpi_release(rab); + otrl_sm_msg_free(&msg4, SM_MSG4_LEN); + + astate->sm_prog_state = comp ? OTRL_SMP_PROG_FAILED : + OTRL_SMP_PROG_SUCCEEDED; + + if (comp) + return gcry_error(GPG_ERR_INV_VALUE); + else + return gcry_error(GPG_ERR_NO_ERROR); +} diff --git a/comm/third_party/libotr/src/sm.h b/comm/third_party/libotr/src/sm.h new file mode 100644 index 0000000000..53703ff301 --- /dev/null +++ b/comm/third_party/libotr/src/sm.h @@ -0,0 +1,84 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SM_H__ +#define __SM_H__ + +#include + +#define SM_HASH_ALGORITHM GCRY_MD_SHA256 +#define SM_DIGEST_SIZE 32 + +typedef enum { + OTRL_SMP_EXPECT1, + OTRL_SMP_EXPECT2, + OTRL_SMP_EXPECT3, + OTRL_SMP_EXPECT4, + OTRL_SMP_EXPECT5 +} NextExpectedSMP; + +typedef enum { + OTRL_SMP_PROG_OK = 0, /* All is going fine so far */ + OTRL_SMP_PROG_CHEATED = -2, /* Some verification failed */ + OTRL_SMP_PROG_FAILED = -1, /* The secrets didn't match */ + OTRL_SMP_PROG_SUCCEEDED = 1 /* The SMP completed successfully */ +} OtrlSMProgState; + +typedef struct { + gcry_mpi_t secret, x2, x3, g1, g2, g3, g3o, p, q, pab, qab; + NextExpectedSMP nextExpected; + int received_question; /* 1 if we received a question in an SMP1Q TLV */ + OtrlSMProgState sm_prog_state; +} OtrlSMState; + +typedef OtrlSMState OtrlSMAliceState; +typedef OtrlSMState OtrlSMBobState; + +/* + * Call this once, at plugin load time. It sets up the modulus and + * generator MPIs. + */ +void otrl_sm_init(void); + +/* + * Initialize the fields of a SM state. + */ +void otrl_sm_state_new(OtrlSMState *smst); + +/* + * Initialize the fields of a SM state. Called the first time that + * a user begins an SMP session. + */ +void otrl_sm_state_init(OtrlSMState *smst); + +/* + * Deallocate the contents of a OtrlSMState (but not the OtrlSMState + * itself) + */ +void otrl_sm_state_free(OtrlSMState *smst); + +gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate, const unsigned char* secret, int secretlen, unsigned char** output, int* outputlen); +gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, int received_question); +gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, int secretlen, unsigned char **output, int* outputlen); +gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen); +gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen); +gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen); + +#endif diff --git a/comm/third_party/libotr/src/tlv.c b/comm/third_party/libotr/src/tlv.c new file mode 100644 index 0000000000..fa76c3d76c --- /dev/null +++ b/comm/third_party/libotr/src/tlv.c @@ -0,0 +1,109 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "tlv.h" + +/* Make a single TLV, copying the supplied data */ +OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len, + const unsigned char *data) +{ + OtrlTLV *tlv = malloc(sizeof(OtrlTLV)); + assert(tlv != NULL); + tlv->type = type; + tlv->len = len; + tlv->data = malloc(len + 1); + assert(tlv->data != NULL); + memmove(tlv->data, data, len); + tlv->data[tlv->len] = '\0'; + tlv->next = NULL; + return tlv; +} + +/* Construct a chain of TLVs from the given data */ +OtrlTLV *otrl_tlv_parse(const unsigned char *serialized, size_t seriallen) +{ + OtrlTLV *tlv = NULL; + OtrlTLV **tlvp = &tlv; + while (seriallen >= 4) { + unsigned short type = (serialized[0] << 8) + serialized[1]; + unsigned short len = (serialized[2] << 8) + serialized[3]; + serialized += 4; seriallen -=4; + if (seriallen < len) break; + *tlvp = otrl_tlv_new(type, len, serialized); + serialized += len; + seriallen -= len; + tlvp = &((*tlvp)->next); + } + return tlv; +} + +/* Deallocate a chain of TLVs */ +void otrl_tlv_free(OtrlTLV *tlv) +{ + while (tlv) { + OtrlTLV *next = tlv->next; + free(tlv->data); + free(tlv); + tlv = next; + } +} + +/* Find the serialized length of a chain of TLVs */ +size_t otrl_tlv_seriallen(const OtrlTLV *tlv) +{ + size_t totlen = 0; + while (tlv) { + totlen += tlv->len + 4; + tlv = tlv->next; + } + return totlen; +} + +/* Serialize a chain of TLVs. The supplied buffer must already be large + * enough. */ +void otrl_tlv_serialize(unsigned char *buf, const OtrlTLV *tlv) +{ + while (tlv) { + buf[0] = (tlv->type >> 8) & 0xff; + buf[1] = tlv->type & 0xff; + buf[2] = (tlv->len >> 8) & 0xff; + buf[3] = tlv->len & 0xff; + buf += 4; + memmove(buf, tlv->data, tlv->len); + buf += tlv->len; + tlv = tlv->next; + } +} + +/* Return the first TLV with the given type in the chain, or NULL if one + * isn't found. (The tlvs argument isn't const because the return type + * needs to be non-const.) */ +OtrlTLV *otrl_tlv_find(OtrlTLV *tlvs, unsigned short type) +{ + while (tlvs) { + if (tlvs->type == type) return tlvs; + tlvs = tlvs->next; + } + return NULL; +} diff --git a/comm/third_party/libotr/src/tlv.h b/comm/third_party/libotr/src/tlv.h new file mode 100644 index 0000000000..0bfeeb27fd --- /dev/null +++ b/comm/third_party/libotr/src/tlv.h @@ -0,0 +1,78 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Willy Lew, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TLV_H__ +#define __TLV_H__ + +typedef struct s_OtrlTLV { + unsigned short type; + unsigned short len; + unsigned char *data; + struct s_OtrlTLV *next; +} OtrlTLV; + +/* TLV types */ + +/* This is just padding for the encrypted message, and should be ignored. */ +#define OTRL_TLV_PADDING 0x0000 + +/* The sender has thrown away his OTR session keys with you */ +#define OTRL_TLV_DISCONNECTED 0x0001 + +/* The message contains a step in the Socialist Millionaires' Protocol. */ +#define OTRL_TLV_SMP1 0x0002 +#define OTRL_TLV_SMP2 0x0003 +#define OTRL_TLV_SMP3 0x0004 +#define OTRL_TLV_SMP4 0x0005 +#define OTRL_TLV_SMP_ABORT 0x0006 +/* Like OTRL_TLV_SMP1, but there's a question for the buddy at the + * beginning */ +#define OTRL_TLV_SMP1Q 0x0007 +/* Tell the application the current "extra" symmetric key */ +/* XXX: Document this in the protocol spec: + * The body of the TLV will begin with a 4-byte indication of what this + * symmetric key will be used for (file transfer, voice encryption, + * etc.). After that, the contents are use-specific (which file, etc.). + * There are no currently defined uses. */ +#define OTRL_TLV_SYMKEY 0x0008 + +/* Make a single TLV, copying the supplied data */ +OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len, + const unsigned char *data); + +/* Construct a chain of TLVs from the given data */ +OtrlTLV *otrl_tlv_parse(const unsigned char *serialized, size_t seriallen); + +/* Deallocate a chain of TLVs */ +void otrl_tlv_free(OtrlTLV *tlv); + +/* Find the serialized length of a chain of TLVs */ +size_t otrl_tlv_seriallen(const OtrlTLV *tlv); + +/* Serialize a chain of TLVs. The supplied buffer must already be large + * enough. */ +void otrl_tlv_serialize(unsigned char *buf, const OtrlTLV *tlv); + +/* Return the first TLV with the given type in the chain, or NULL if one + * isn't found. (The tlvs argument isn't const because the return type + * needs to be non-const.) */ +OtrlTLV *otrl_tlv_find(OtrlTLV *tlvs, unsigned short type); + +#endif diff --git a/comm/third_party/libotr/src/userstate.c b/comm/third_party/libotr/src/userstate.c new file mode 100644 index 0000000000..58f5a05578 --- /dev/null +++ b/comm/third_party/libotr/src/userstate.c @@ -0,0 +1,57 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include + +/* libotr headers */ +#include "context.h" +#include "privkey.h" +#include "userstate.h" + +/* Create a new OtrlUserState. Most clients will only need one of + * these. A OtrlUserState encapsulates the list of known fingerprints + * and the list of private keys; if you have separate files for these + * things for (say) different users, use different OtrlUserStates. If + * you've got only one user, with multiple accounts all stored together + * in the same fingerprint store and privkey store files, use just one + * OtrlUserState. */ +OtrlUserState otrl_userstate_create(void) +{ + OtrlUserState us = malloc(sizeof(struct s_OtrlUserState)); + if (!us) return NULL; + us->context_root = NULL; + us->privkey_root = NULL; + us->instag_root = NULL; + us->pending_root = NULL; + us->timer_running = 0; + return us; +} + +/* Free a OtrlUserState. If you have a timer running for this userstate, +stop it before freeing the userstate. */ +void otrl_userstate_free(OtrlUserState us) +{ + otrl_context_forget_all(us); + otrl_privkey_forget_all(us); + otrl_privkey_pending_forget_all(us); + otrl_instag_forget_all(us); + free(us); +} diff --git a/comm/third_party/libotr/src/userstate.h b/comm/third_party/libotr/src/userstate.h new file mode 100644 index 0000000000..3f1e3b89cf --- /dev/null +++ b/comm/third_party/libotr/src/userstate.h @@ -0,0 +1,51 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Willy Lew, Lisa Du, Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __USERSTATE_H__ +#define __USERSTATE_H__ + +typedef struct s_OtrlUserState* OtrlUserState; + +#include "instag.h" +#include "context.h" +#include "privkey-t.h" + +struct s_OtrlUserState { + ConnContext *context_root; + OtrlPrivKey *privkey_root; + OtrlInsTag *instag_root; + OtrlPendingPrivKey *pending_root; + int timer_running; +}; + +/* Create a new OtrlUserState. Most clients will only need one of + * these. A OtrlUserState encapsulates the list of known fingerprints + * and the list of private keys; if you have separate files for these + * things for (say) different users, use different OtrlUserStates. If + * you've got only one user, with multiple accounts all stored together + * in the same fingerprint store and privkey store files, use just one + * OtrlUserState. */ +OtrlUserState otrl_userstate_create(void); + +/* Free a OtrlUserState. If you have a timer running for this userstate, +stop it before freeing the userstate. */ +void otrl_userstate_free(OtrlUserState us); + +#endif diff --git a/comm/third_party/libotr/src/version.h b/comm/third_party/libotr/src/version.h new file mode 100644 index 0000000000..c7f990fb50 --- /dev/null +++ b/comm/third_party/libotr/src/version.h @@ -0,0 +1,31 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2016 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __VERSION_H__ +#define __VERSION_H__ + +#define OTRL_VERSION "4.1.1" + +#define OTRL_VERSION_MAJOR 4 +#define OTRL_VERSION_MINOR 1 +#define OTRL_VERSION_SUB 1 + +#endif diff --git a/comm/third_party/libotr/tests/Makefile.am b/comm/third_party/libotr/tests/Makefile.am new file mode 100644 index 0000000000..b5949db630 --- /dev/null +++ b/comm/third_party/libotr/tests/Makefile.am @@ -0,0 +1,11 @@ +SUBDIRS = utils unit regression + +AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_srcdir)/tests/utils/ -I$(srcdir) + +LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la + +check-am: + ./run.sh test_list + +dist_noinst_SCRIPTS = test_list run.sh +EXTRA_DIST = run.sh test_list diff --git a/comm/third_party/libotr/tests/Makefile.in b/comm/third_party/libotr/tests/Makefile.in new file mode 100644 index 0000000000..65c85adb8c --- /dev/null +++ b/comm/third_party/libotr/tests/Makefile.in @@ -0,0 +1,617 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tests +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(dist_noinst_SCRIPTS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SCRIPTS = $(dist_noinst_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = utils unit regression +AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_srcdir)/tests/utils/ -I$(srcdir) +LIBTAP = $(top_builddir)/tests/utils/tap/libtap.la +dist_noinst_SCRIPTS = test_list run.sh +EXTRA_DIST = run.sh test_list +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(SCRIPTS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + + +check-am: + ./run.sh test_list + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/tests/regression/Makefile.am b/comm/third_party/libotr/tests/regression/Makefile.am new file mode 100644 index 0000000000..c4d20f4009 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = client + +EXTRA_DIST = random-msg.sh random-msg-disconnect.sh random-msg-disconnect-auth.sh \ + random-msg-disconnect-frag-auth.sh random-msg-fast.sh random-msg-auth.sh \ + random-msg-disconnect-frag.sh random-msg-frag.sh diff --git a/comm/third_party/libotr/tests/regression/Makefile.in b/comm/third_party/libotr/tests/regression/Makefile.in new file mode 100644 index 0000000000..d85033e665 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/Makefile.in @@ -0,0 +1,611 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tests/regression +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = client +EXTRA_DIST = random-msg.sh random-msg-disconnect.sh random-msg-disconnect-auth.sh \ + random-msg-disconnect-frag-auth.sh random-msg-fast.sh random-msg-auth.sh \ + random-msg-disconnect-frag.sh random-msg-frag.sh + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/regression/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/regression/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/tests/regression/client/Makefile.am b/comm/third_party/libotr/tests/regression/client/Makefile.am new file mode 100644 index 0000000000..d2b11be132 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/client/Makefile.am @@ -0,0 +1,16 @@ +AM_CFLAGS = -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/tests/utils/ \ + -I$(srcdir) \ + @LIBGCRYPT_CFLAGS@ + +LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la + +LIBOTR=$(top_builddir)/src/libotr.la + +noinst_PROGRAMS = client + +client_SOURCES = client.c +client_LDADD = $(LIBTAP) $(LIBOTR) -lpthread @LIBGCRYPT_LIBS@ + +EXTRA_DIST = otr.key diff --git a/comm/third_party/libotr/tests/regression/client/Makefile.in b/comm/third_party/libotr/tests/regression/client/Makefile.in new file mode 100644 index 0000000000..de3aa908ee --- /dev/null +++ b/comm/third_party/libotr/tests/regression/client/Makefile.in @@ -0,0 +1,584 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = client$(EXEEXT) +subdir = tests/regression/client +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/config/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_client_OBJECTS = client.$(OBJEXT) +client_OBJECTS = $(am_client_OBJECTS) +client_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(client_SOURCES) +DIST_SOURCES = $(client_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/tests/utils/ \ + -I$(srcdir) \ + @LIBGCRYPT_CFLAGS@ + +LIBTAP = $(top_builddir)/tests/utils/tap/libtap.la +LIBOTR = $(top_builddir)/src/libotr.la +client_SOURCES = client.c +client_LDADD = $(LIBTAP) $(LIBOTR) -lpthread @LIBGCRYPT_LIBS@ +EXTRA_DIST = otr.key +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/regression/client/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/regression/client/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +client$(EXEEXT): $(client_OBJECTS) $(client_DEPENDENCIES) $(EXTRA_client_DEPENDENCIES) + @rm -f client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(client_OBJECTS) $(client_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/tests/regression/client/client.c b/comm/third_party/libotr/tests/regression/client/client.c new file mode 100644 index 0000000000..e72b6613e9 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/client/client.c @@ -0,0 +1,1158 @@ +/* + * Copyright (C) 2014 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define zmalloc(x) calloc(1, x) + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +/* Global OTR user state. */ +static OtrlUserState user_state; + +/* Getopt options. */ +static struct option long_opts[] = { + { "load-instag", 1, NULL, 'i' }, + { "load-key", 1, NULL, 'k' }, + { "load-fp", 1, NULL, 'f' }, + { "timeout", 1, NULL, 't' }, + { "max-msg", 1, NULL, 'm' }, + { "disconnect", 0, NULL, 'd' }, + { "auth", 0, NULL, 'a' }, + { "fragment", 0, NULL, 'F' }, + + /* Closure. */ + { NULL, 0, NULL, 0 } +}; + +static char *opt_instag_path; +static char *opt_key_path; +static char *opt_key_fp_path; +static unsigned int opt_max_num_msg; +static int opt_disconnect; +static int opt_auth; +static int opt_fragment; + +/* Currently, the message size sent is between 1 and 600 len so 100 is a good + * middle ground. */ +static const int fragment_size = 100; +/* By default, don't send frag. */ +static OtrlFragmentPolicy fragPolicy = OTRL_FRAGMENT_SEND_SKIP; + +static const char *protocol = "otr-test"; +static const char *alice_name = "alice"; +static const char *bob_name = "bob"; + +static const char *unix_sock_bob_path = "/tmp/otr-test-bob.sock"; +static const char *unix_sock_alice_path = "/tmp/otr-test-alice.sock"; + +static const char *auth_question = "What is NSA?"; +static const char *auth_secret = "No Sugar Added"; + +/* Alice and Bob thread's socket. */ +static int alice_sock; +static int bob_sock; +/* Declare it global because we use it multiple times. */ +static struct sockaddr_un alice_sun; +static struct sockaddr_un bob_sun; + +static int timeout_max = 1000; +static unsigned int num_recv_msg; +static unsigned int session_disconnected; + +static int quit_pipe[2] = { -1, -1 }; + +/* + * For now not really do much more but if we want to use the OK condition at + * some point to do something else, that will ease our life :). + */ +#define OK(cond, fmt, args...) \ + do { \ + ok(cond, fmt, ## args); \ + } while (0) + +/* + * Used to pass OTR message between threads. This contains the cipher and + * plaintext so we are able to validate what's expected in both threads. + */ +struct otr_msg { + size_t plaintext_len; + size_t ciphertext_len; + char *plaintext; + char *ciphertext; +}; + +struct otr_info { + const char *user; + int sock; + unsigned int gone_secure; + unsigned int auth_done; +}; + +/* Stub */ +static int send_otr_msg(int sock, const char *to, const char *from, + struct otr_info *oinfo, const char *message); + +static OtrlPolicy ops_policy(void *opdata, ConnContext *context) +{ + return OTRL_POLICY_DEFAULT; +} + +static void ops_inject_msg(void *opdata, const char *accountname, + const char *protocol, const char *recipient, const char *message) +{ + ssize_t ret; + struct otr_info *oinfo = opdata; + struct otr_msg *msg; + + msg = zmalloc(sizeof(*msg)); + if (!msg) { + perror("zmalloc inject"); + return; + } + + msg->ciphertext = strdup(message); + msg->ciphertext_len = strlen(message); + + ret = send(oinfo->sock, &msg, sizeof(msg), 0); + if (ret < 0) { + perror("send msg"); + } +} + +static void ops_gone_secure(void *opdata, ConnContext *context) +{ + struct otr_info *oinfo = opdata; + + session_disconnected = 0; + oinfo->gone_secure = 1; + /* XXX: gone_insecure is never called ref bug #40 so this will always be + * true. */ + OK(oinfo->gone_secure, "Gone secure for %s", + oinfo->user); +} + +static void ops_gone_insecure(void *opdata, ConnContext *context) +{ + struct otr_info *oinfo = opdata; + + OK(oinfo->gone_secure, "Gone insecure for %s", + oinfo->user); + oinfo->gone_secure = 0; +} + +static int ops_max_message_size(void *opdata, ConnContext *context) +{ + if (opt_fragment) { + return fragment_size; + } + return 0; +} + +static const char *ops_otr_error_message(void *opdata, ConnContext *context, + OtrlErrorCode code) +{ + char *msg = NULL; + + switch (code) { + case OTRL_ERRCODE_NONE: + break; + case OTRL_ERRCODE_ENCRYPTION_ERROR: + msg = strdup("OTRL_ERRCODE_ENCRYPTION_ERROR"); + break; + case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE: + msg = strdup("OTRL_ERRCODE_MSG_NOT_IN_PRIVATE"); + break; + case OTRL_ERRCODE_MSG_UNREADABLE: + msg = strdup("OTRL_ERRCODE_MSG_UNREADABLE"); + break; + case OTRL_ERRCODE_MSG_MALFORMED: + msg = strdup("OTRL_ERRCODE_MSG_MALFORMED"); + break; + } + + return msg; +} + +static void ops_otr_error_message_free(void *opdata, const char *err_msg) +{ + free((char *) err_msg); +} + +static void ops_handle_msg_event(void *opdata, OtrlMessageEvent msg_event, + ConnContext *context, const char *message, gcry_error_t err) +{ + //char* msg = ""; + struct otr_info *oinfo = opdata; + + switch(msg_event) { + case OTRL_MSGEVENT_NONE: + //msg = "OTRL_MSGEVENT_NONE"; + break; + case OTRL_MSGEVENT_ENCRYPTION_REQUIRED: + //msg = "OTRL_MSGEVENT_ENCRYPTION_REQUIRED"; + break; + case OTRL_MSGEVENT_ENCRYPTION_ERROR: + //msg = "OTRL_MSGEVENT_ENCRYPTION_ERROR"; + break; + case OTRL_MSGEVENT_CONNECTION_ENDED: + //msg = "OTRL_MSGEVENT_CONNECTION_ENDED"; + oinfo->gone_secure = 0; + break; + case OTRL_MSGEVENT_SETUP_ERROR: + //msg = "OTRL_MSGEVENT_SETUP_ERROR"; + break; + case OTRL_MSGEVENT_MSG_REFLECTED: + //msg = "OTRL_MSGEVENT_MSG_REFLECTED"; + break; + case OTRL_MSGEVENT_MSG_RESENT: + //msg = "OTRL_MSGEVENT_MSG_RESENT"; + break; + case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE: + //msg = "OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE"; + break; + case OTRL_MSGEVENT_RCVDMSG_UNREADABLE: + //msg = "OTRL_MSGEVENT_RCVDMSG_UNREADABLE"; + break; + case OTRL_MSGEVENT_RCVDMSG_MALFORMED: + //msg = "OTRL_MSGEVENT_RCVDMSG_MALFORMED"; + break; + case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD: + //msg = "OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD"; + break; + case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT: + //msg = "OTRL_MSGEVENT_LOG_HEARTBEAT_SENT"; + break; + case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR: + //msg = "OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR"; + break; + case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED: + //msg = "OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED"; + break; + case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED: + //msg = "OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED"; + break; + case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE: + //msg = "OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE"; + break; + default: + //msg = "Unknown OTRL message event"; + break; + } +} + +static void ops_create_instag(void *opdata, const char *accountname, + const char *protocol) +{ + otrl_instag_generate(user_state, "/dev/null", accountname, + protocol); +} + +static int ops_is_logged_in(void *opdata, const char *accountname, + const char *protocol, const char *recipient) +{ + /* Always logged in or else we don't receive a disconnected TLV. */ + return 1; +} + +static void ops_create_privkey(void *opdata, const char *accountname, + const char *protocol) +{ + /* XXX: We should gen. our own key each time at some point? */ + return; +} + +static void ops_update_context_list(void *opdata) +{ + return; +} + +static void ops_new_fingerprint(void *opdata, OtrlUserState us, + const char *accountname, const char *protocol, + const char *username, unsigned char fingerprint[20]) +{ + return; +} + +static void ops_write_fingerprints(void *opdata) +{ + return; +} + +static void ops_still_secure(void *opdata, ConnContext *context, int is_reply) +{ + struct otr_info *oinfo = opdata; + + OK(oinfo->gone_secure, "OP still secure"); +} + +static void ops_received_symkey(void *opdata, ConnContext *context, + unsigned int use, const unsigned char *usedata, + size_t usedatalen, const unsigned char *symkey) +{ + return; +} + +static const char *ops_resent_msg_prefix(void *opdata, ConnContext *context) +{ + /* Just so we can test resent_msg_prefix_free */ + char *prefix = zmalloc(32); + strncpy(prefix, "[such resent]", 32); + + return prefix; +} + +static void ops_resent_msg_prefix_free(void *opdata, const char *prefix) +{ + free((char *) prefix); +} + +static void ops_convert_msg(void *opdata, ConnContext *context, + OtrlConvertType convert_type, char ** dest, const char *src) +{ + switch (convert_type) { + case OTRL_CONVERT_SENDING: + case OTRL_CONVERT_RECEIVING: + break; + default: + OK(0, "OP convert_msg, got a unknown type %d", convert_type); + break; + } + + *dest = NULL; +} + +static void ops_convert_free(void *opdata, ConnContext *context, char *dest) +{ + return; +} + +/* Stub */ +static void ops_handle_smp_event(void *opdata, OtrlSMPEvent smp_event, + ConnContext *context, unsigned short progress_percent, char *question); +static void ops_timer_control(void *opdata, unsigned int interval); + +/* OTR message operations. */ +static OtrlMessageAppOps ops = { + ops_policy, + ops_create_privkey, + ops_is_logged_in, + ops_inject_msg, + ops_update_context_list, + ops_new_fingerprint, + ops_write_fingerprints, + ops_gone_secure, + ops_gone_insecure, + ops_still_secure, + ops_max_message_size, + NULL, /* account_name - NOT USED */ + NULL, /* account_name_free - NOT USED */ + ops_received_symkey, + ops_otr_error_message, + ops_otr_error_message_free, + ops_resent_msg_prefix, + ops_resent_msg_prefix_free, + ops_handle_smp_event, + ops_handle_msg_event, + ops_create_instag, + ops_convert_msg, + ops_convert_free, + ops_timer_control, +}; + + +static void ops_timer_control(void *opdata, unsigned int interval) +{ + otrl_message_poll(user_state, &ops, NULL); +} + +static void ops_handle_smp_event(void *opdata, OtrlSMPEvent smp_event, + ConnContext *context, unsigned short progress_percent, char *question) +{ + struct otr_info *oinfo = opdata; + + switch (smp_event) { + case OTRL_SMPEVENT_ASK_FOR_SECRET: + OK(!oinfo->auth_done && + !strncmp(oinfo->user, alice_name, strlen(alice_name)), + "SMP Event, %s asking for secret", alice_name); + break; + case OTRL_SMPEVENT_ASK_FOR_ANSWER: + OK(!oinfo->auth_done && + !strncmp(oinfo->user, bob_name, strlen(bob_name)) && + !strncmp(auth_question, question, strlen(auth_question)), + "SMP Event, %s asking for answer", bob_name); + /* + * Directly respond to the SMP auth here. Much more easy instead of in + * bob's thread. + */ + otrl_message_respond_smp(user_state, &ops, opdata, context, + (unsigned char *) auth_secret, strlen(auth_secret)); + break; + case OTRL_SMPEVENT_IN_PROGRESS: + OK(!oinfo->auth_done && + !strncmp(oinfo->user, alice_name, strlen(alice_name)), + "SMP Event, %s asking for secret", alice_name); + break; + case OTRL_SMPEVENT_SUCCESS: + oinfo->auth_done = 1; + OK(oinfo->auth_done, "SMP authentication success for %s", oinfo->user); + break; + case OTRL_SMPEVENT_ABORT: + case OTRL_SMPEVENT_FAILURE: + case OTRL_SMPEVENT_CHEATED: + case OTRL_SMPEVENT_ERROR: + default: + OK(0, "SMP auth failed with event %d", smp_event); + break; + } +} + +static void cleanup(void) +{ + ssize_t ret; + + /* Wake up threads. */ + ret = write(quit_pipe[1], "42", 2); + if (ret < 0) { + perror("write quit pipe"); + } + + /* Cleanup residual Unix socket path. */ + unlink(alice_sun.sun_path); + unlink(bob_sun.sun_path); +} + +static void update_msg_counter(void) +{ + num_recv_msg++; + if (num_recv_msg == opt_max_num_msg) { + cleanup(); + } +} + +/* + * Generate random string and stores it in out of size len. + */ +static void gen_random_string(char *out, size_t len) +{ + size_t i; + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + for (i = 0; i < len; i++) { + out[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + } + out[len - 1] = '\0'; +} + +static int send_otr_msg(int sock, const char *to, const char *from, + struct otr_info *oinfo, const char *message) +{ + char *new_msg = NULL; + ssize_t ret; + gcry_error_t err; + struct otr_msg *omsg; + + omsg = zmalloc(sizeof(*omsg)); + if (!omsg) { + perror("zmalloc send otr msg"); + goto error; + } + + if (!message) { + size_t len = rand() % 600; + char *msg = zmalloc(len); + if (!msg) { + perror("random msg"); + goto error; + } + gen_random_string(msg, len); + omsg->plaintext = msg; + omsg->plaintext_len = strlen(msg); + } else { + omsg->plaintext = strdup(message); + omsg->plaintext_len = strlen(message); + } + + err = otrl_message_sending(user_state, &ops, oinfo, from, protocol, to, + OTRL_INSTAG_BEST, omsg->plaintext, NULL, &new_msg, + fragPolicy, NULL, NULL, NULL); + if (err) { + goto error; + } + if (new_msg) { + free(omsg->ciphertext); + omsg->ciphertext = strdup(new_msg); + omsg->ciphertext_len = strlen(omsg->ciphertext); + otrl_message_free(new_msg); + } + + ret = send(sock, &omsg, sizeof(omsg), 0); + if (ret < 0) { + perror("send OTR msg"); + goto error; + } + + return 0; + +error: + if(omsg){ + free(omsg->plaintext); + free(omsg->ciphertext); + free(omsg); + } + return -1; +} + +static int recv_otr_msg(int sock, const char *to, const char *from, + struct otr_info *oinfo) +{ + int err; + ssize_t ret; + char *new_msg = NULL; + struct otr_msg *omsg; + OtrlTLV *tlvs = NULL; + + ret = recv(sock, &omsg, sizeof(omsg), 0); + if (ret < 0) { + goto error; + } + + err = otrl_message_receiving(user_state, &ops, oinfo, to, protocol, from, + omsg->ciphertext, &new_msg, &tlvs, NULL, NULL, NULL); + if (!err) { + if (new_msg) { + OK(strncmp(omsg->plaintext, new_msg, omsg->plaintext_len) == 0, + "Message exchanged is valid"); + update_msg_counter(); + } + } else { + OK(err == 1, "Internal OTR message valid"); + } + + free(omsg->plaintext); + free(omsg->ciphertext); + free(omsg); + + OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED); + /* + * XXX: Somehow you can end up with a disconnected TLV in a gone secure + * session (see #54). This is probably a bug but since the gone_insecure is + * never called (see bug #48) we have no reliable way of knowing the state + * of the session at this point. + */ + if (tlv && !oinfo->gone_secure) { + OK(session_disconnected, "Disconnected TLV confirmed"); + } + + otrl_tlv_free(tlvs); + + return 0; + +error: + return -1; +} + +static int add_sock_to_pollset(int epfd, int sock, uint32_t req_ev) +{ + int ret; + struct epoll_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.events = req_ev; + ev.data.fd = sock; + + ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev); + if (ret < 0) { + perror("epoll_ctl add"); + } + return ret; +} + +static void *alice_thread(void *data) +{ + int sock_to_bob, sock_from_bob = 0, epfd, ret; + unsigned int auth_started = 0; + struct otr_info oinfo; + + memset(&oinfo, 0, sizeof(oinfo)); + + /* Poll size is ignored since 2.6.8 */ + epfd = epoll_create(42); + if (epfd < 0) { + perror("epoll_create Bob"); + goto error; + } + + sock_to_bob = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock_to_bob < 0) { + perror("Bob socket to Alice"); + goto sock_error; + } + oinfo.sock = sock_to_bob; + oinfo.user = alice_name; + if (!opt_auth) { + /* We are not going to SMP auth for this session so indicate it's + * completed so we can go forward with random disconnect. + */ + oinfo.auth_done = 1; + } + + ret = connect(sock_to_bob, (struct sockaddr *) &bob_sun, + sizeof(bob_sun)); + if (ret < 0) { + perror("connect to Alice"); + goto end; + } + + /* Add quit pipe to pollset trigger by a cleanup. */ + ret = add_sock_to_pollset(epfd, quit_pipe[0], EPOLLIN); + if (ret < 0) { + goto end; + } + + /* Add our socket to epoll set. */ + ret = add_sock_to_pollset(epfd, alice_sock, + EPOLLIN | EPOLLRDHUP); + if (ret < 0) { + goto end; + } + + while (1) { + int i, nb_fd, timeout; + struct epoll_event ev[3]; + memset(ev, 0, sizeof(ev)); + + /* + * Set random timeout and when we do timeout, use that to send message + * to Alice. + */ + timeout = (rand() % (timeout_max - 1)); + + ret = epoll_wait(epfd, ev, sizeof(ev), timeout); + if (ret < 0) { + perror("epoll_wait Alice"); + goto end; + } + nb_fd = ret; + + /* Each timeout to 10 finishes the OTR session. */ + if (!(timeout % 3) && opt_disconnect && oinfo.auth_done) { + session_disconnected = 1; + oinfo.gone_secure = 0; + otrl_message_disconnect(user_state, &ops, &oinfo, + alice_name, protocol, bob_name, OTRL_INSTAG_BEST); + OK(!oinfo.gone_secure, "OTR message disconnect"); + } + + /* Start authentication with Bob. */ + if (opt_auth && !auth_started && oinfo.gone_secure) { + ConnContext *ctx; + + /* We have to find our context before auth. */ + ctx = otrl_context_find(user_state, bob_name, alice_name, + protocol, OTRL_INSTAG_BEST, 0, NULL, NULL, &oinfo); + OK(ctx, "Alice context found for SMP auth"); + + otrl_message_initiate_smp_q(user_state, &ops, &oinfo, ctx, + auth_question, (unsigned char *) auth_secret, + strlen(auth_secret)); + auth_started = 1; + } + + /* No event thus timeout, send message to Alice. */ + if (nb_fd == 0) { + (void) send_otr_msg(sock_to_bob, bob_name, alice_name, &oinfo, + NULL); + continue; + } + + for (i = 0; i < nb_fd; i++) { + int fd; + uint32_t event; + + fd = ev[i].data.fd; + event = ev[i].events; + + if (fd == quit_pipe[0]) { + /* Time to leave. */ + goto end; + } else if (fd == alice_sock) { + if (event & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) { + goto end; + } else if (event & EPOLLIN) { + socklen_t len; + struct sockaddr_un sun; + + /* Connection from Bob, accept it so we can handle it. */ + sock_from_bob = accept(fd, (struct sockaddr *) &sun, + &len); + ret = add_sock_to_pollset(epfd, sock_from_bob, + EPOLLIN | EPOLLERR | EPOLLHUP); + if (ret < 0) { + goto end; + } + } + continue; + } else if (fd == sock_from_bob) { + if (event & (EPOLLERR | EPOLLHUP)) { + /* Stop since Bob's thread just shut us down. */ + goto end; + } else if (event & EPOLLIN) { + (void) recv_otr_msg(sock_from_bob, alice_name, bob_name, + &oinfo); + } + continue; + } else { + goto end; + } + } + } + +end: + if (sock_from_bob) { + (void) close(sock_from_bob); + } + (void) close(sock_to_bob); +sock_error: + (void) close(epfd); +error: + (void) close(alice_sock); + + return NULL; +} + +static void *bob_thread(void *data) +{ + int sock_to_alice, sock_from_alice = 0, epfd, ret; + struct otr_info oinfo; + + memset(&oinfo, 0, sizeof(oinfo)); + + /* Poll size is ignored since 2.6.8 */ + epfd = epoll_create(42); + if (epfd < 0) { + perror("epoll_create Bob"); + goto error; + } + + sock_to_alice = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock_to_alice < 0) { + perror("Bob socket to Alice"); + goto sock_error; + } + oinfo.sock = sock_to_alice; + oinfo.user = bob_name; + + ret = connect(sock_to_alice, (struct sockaddr *) &alice_sun, + sizeof(alice_sun)); + if (ret < 0) { + perror("connect to Alice"); + goto end; + } + + /* Add quit pipe to pollset trigger by a cleanup. */ + ret = add_sock_to_pollset(epfd, quit_pipe[0], EPOLLIN); + if (ret < 0) { + goto end; + } + + /* Add our socket to epoll set. */ + ret = add_sock_to_pollset(epfd, bob_sock, + EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLRDHUP); + if (ret < 0) { + goto end; + } + + while (1) { + int i, timeout = 500, nb_fd; + struct epoll_event ev[3]; + memset(ev, 0, sizeof(ev)); + + /* + * Set random timeout and when we do timeout, use that to send message + * to Alice. + */ + timeout = (rand() % (timeout_max - 1)); + + ret = epoll_wait(epfd, ev, sizeof(ev), timeout); + if (ret < 0) { + perror("epoll_wait Bob"); + goto end; + } + nb_fd = ret; + + /* No event thus timeout, send message to Alice. */ + if (nb_fd == 0) { + (void) send_otr_msg(sock_to_alice, alice_name, bob_name, &oinfo, + NULL); + continue; + } + + for (i = 0; i < nb_fd; i++) { + int fd; + uint32_t event; + + fd = ev[i].data.fd; + event = ev[i].events; + + if (fd == quit_pipe[0]) { + /* Time to leave. */ + goto end; + } else if (fd == bob_sock) { + if (event & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) { + goto end; + } else if (event & (EPOLLIN | EPOLLHUP)) { + socklen_t len; + struct sockaddr_un sun; + + /* Connection from Alice, accept it so we can handle it. */ + sock_from_alice = accept(fd, (struct sockaddr *) &sun, + &len); + ret = add_sock_to_pollset(epfd, sock_from_alice, + EPOLLIN | EPOLLERR | EPOLLHUP); + if (ret < 0) { + goto end; + } + } + continue; + } else if (fd == sock_from_alice) { + if (event & (EPOLLERR | EPOLLHUP)) { + goto end; + } else if (event & EPOLLIN) { + (void) recv_otr_msg(sock_from_alice, bob_name, + alice_name, &oinfo); + } + continue; + } else { + goto end; + } + } + } + +end: + if (sock_from_alice) { + (void) close(sock_from_alice); + } + (void) close(sock_to_alice); +sock_error: + (void) close(epfd); +error: + (void) close(bob_sock); + return NULL; +} + +static void run(void) +{ + int ret; + void *status; + pthread_t alice_th, bob_th; + + /* Init quit pipe. */ + ret = pipe(quit_pipe); + if (ret < 0) { + perror("pipe quit pipe"); + goto end; + } + + ret = pthread_create(&alice_th, NULL, alice_thread, NULL); + if (ret) { + fail("pthread_create sender thread failed (errno: %d)", errno); + goto end; + } + + ret = pthread_create(&bob_th, NULL, bob_thread, NULL); + if (ret) { + fail("pthread_create receiver thread failed (errno: %d)", errno); + goto exit_receiver; + } + + (void) pthread_join(bob_th, &status); + +exit_receiver: + (void) pthread_join(alice_th, &status); +end: + /* Get rid of the quit pipe. */ + close(quit_pipe[0]); + close(quit_pipe[1]); + return; +} + +/* + * Load OTR instag using the given opt argument. + */ +static void load_instag(void) +{ + int ret; + gcry_error_t err; + + ret = access(opt_instag_path, R_OK); + if (ret < 0) { + fail("Instag file %s is not readable", opt_instag_path); + return; + } + + err = otrl_instag_read(user_state, opt_instag_path); + OK(err == GPG_ERR_NO_ERROR, "Loading instag from given file"); +} + +/* + * Load private key file using the given opt argument. + */ +static void load_key(void) +{ + int ret; + gcry_error_t err; + + ret = access(opt_key_path, R_OK); + if (ret < 0) { + fail("Key file %s is not readable", opt_key_path); + return; + } + + err = otrl_privkey_read(user_state, opt_key_path); + OK(err == GPG_ERR_NO_ERROR, "Loading key from given file"); +} + +/* + * Load private key fingerprint file using the given opt argument. + */ +static void load_key_fp(void) +{ + int ret; + gcry_error_t err; + + ret = access(opt_key_fp_path, R_OK); + if (ret < 0) { + fail("Key fingerprints file %s is not readable", opt_key_fp_path); + return; + } + + err = otrl_privkey_read_fingerprints(user_state, opt_key_fp_path, NULL, + NULL); + OK(err == GPG_ERR_NO_ERROR, "Loading key fingerprints from given file"); +} + +static int create_unix_socket(const char *pathname, + struct sockaddr_un *sun) +{ + int sock, ret; + + /* Create both Unix socket. */ + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + ret = -errno; + perror("Unix socket"); + goto error; + } + + memset(sun, 0, sizeof(struct sockaddr_un)); + sun->sun_family = AF_UNIX; + strncpy(sun->sun_path, pathname, sizeof(sun->sun_path)); + sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; + + ret = bind(sock, (struct sockaddr *) sun, sizeof(struct sockaddr_un)); + if (ret < 0) { + perror("bind unix sock"); + goto error; + } + + ret = listen(sock, 10); + if (ret < 0) { + perror("listen unix sock"); + goto error; + } + + return sock; +error: + return ret; +} + +/* + * Bootstrap client by initializing the OTR library and creating an OTR user + * state. + * + * Return 0 on success else a negative value on error. + */ +static int init_client(void) +{ + int ret; + + /* Init libgcrypt threading system. */ + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + + /* Init OTR library. */ + OTRL_INIT; + OK(1, "OTR library initialization done."); + + user_state = otrl_userstate_create(); + OK(user_state, "OTR userstate creation done."); + if (!user_state) { + fail("Out of memory on userstate create"); + ret = -ENOMEM; + goto error; + } + + /* Seed the prng. */ + srand(time(NULL)); + + /* Cleanup Unix socket file before creating them. */ + unlink(unix_sock_alice_path); + unlink(unix_sock_bob_path); + + alice_sock = create_unix_socket(unix_sock_alice_path, &alice_sun); + bob_sock = create_unix_socket(unix_sock_bob_path, &bob_sun); + if (alice_sock < 0 || bob_sock < 0) { + ret = -EINVAL; + goto error; + } + + if (opt_fragment) { + fragPolicy = OTRL_FRAGMENT_SEND_ALL; + } + + return 0; + +error: + return ret; +} + +static void sighandler(int sig) +{ + switch (sig) { + case SIGPIPE: + case SIGINT: + case SIGTERM: + cleanup(); + break; + default: + break; + } +} + +/* + * main entry point. + */ +int main(int argc, char **argv) +{ + int ret, opt; + struct sigaction sa; + sigset_t sigset; + + plan_no_plan(); + + if ((ret = sigemptyset(&sigset)) < 0) { + perror("sigemptyset"); + goto error; + } + + sa.sa_handler = sighandler; + sa.sa_mask = sigset; + sa.sa_flags = 0; + + if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { + perror("sigaction"); + goto error; + } + if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) { + perror("sigaction"); + goto error; + } + if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { + perror("sigaction"); + goto error; + } + + while ((opt = getopt_long(argc, argv, "+i:k:f:t:m:daF", long_opts, NULL)) != -1) { + switch (opt) { + case 'i': + opt_instag_path = strdup(optarg); + break; + case 'k': + opt_key_path = strdup(optarg); + break; + case 'f': + opt_key_fp_path = strdup(optarg); + break; + case 't': + timeout_max = atoi(optarg); + break; + case 'm': + opt_max_num_msg = atoi(optarg); + break; + case 'd': + opt_disconnect = 1; + break; + case 'a': + opt_auth = 1; + break; + case 'F': + opt_fragment = 1; + break; + default: + goto error; + } + } + + if (!opt_key_path) { + fail("No key file, failing"); + goto error; + } + + /* Running OTR tests. */ + ret = init_client(); + if (ret < 0) { + goto error; + } + + if (opt_instag_path) { + load_instag(); + } + if (opt_key_fp_path) { + load_key_fp(); + } + load_key(); + + run(); + + return exit_status(); + +error: + return -1; +} diff --git a/comm/third_party/libotr/tests/regression/client/otr.key b/comm/third_party/libotr/tests/regression/client/otr.key new file mode 100644 index 0000000000..ee8767db22 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/client/otr.key @@ -0,0 +1,41 @@ +(privkeys + (account +(name alice) +(protocol otr-test) +(private-key + (dsa + (p #00E4240AE9740D5FB1DF076A3270143BBD5B66DEB9BFD601CF3C3DC3E8D76BF1EA0D1A66E209516600E915B79552887EE9810D613C63EA6D2B6E69321C3C81F71F533F02430D20AF65C05C15BA46EF10C78EFF3BE687C33A4F6EA90877AB30E6423070AAFD3F22B5939D0DC8FBE5145A68F38EBA98ADCA7E06EFBC5E345E9AEDEF#) + (q "\x00§Õ»Ç*ÂÝi#ûb§U~õ{U©öq") + (g #00D3A15721AEF3A49DF26E875EC8C5FF4096B0B1717AF89485A015245176FD4AE3065D9F7B2D185B1E02CEAFB53E6984B1D341E62EBB4A5C189EB40959CFED0C48DAE73F3391C5E1482372E9DE539CD6911C54583DC0A3179547A38E19549F81A6DBFA8036C471C2A358D4B3AB86C7424556DFD61C35CC1EC08304B0102A0EEE08#) + (y #6E3996E07B6CB54DC443BD83033293956E5B7CCC511D19DCAC8735496B061D6EB6DF3D5540548D3C97201393E669EF9066BCA6A72E3AC68710188BEDF06FDF22548D8709BD4E9E1AD02DB0E193399BEB39DE5218D70C999D9856D3205DB79BA8DFC188726E646A1BE1722843F5E56A51C499C5BE5F63FACE7802ECD565E99F39#) + (x #2C5887BA7EC5F426B6BE4438E2FAE4589DBF2CB6#) + ) + ) + ) + (account +(name bob) +(protocol otr-test) +(private-key + (dsa + (p #00BD114F05B275A8A94954047983C5CD96ED95C782D2ED65A18E78C98E8EAFBAF58BBD046BE9895AD55FD0FF95907E7EBD6ACA2688D24779BDE9F0AAB13924CE65F597F9C9B9953DDBACF51DA7113FBAB9BE1DF6C6EA836DEB48983CCDCFC4125B5013D0CE52F890D0C391A035D30BCD5169A3451FD7023685274576DCB5F8FA47#) + (q #00D1DA3915346A704EB2D2F2A48CD48F3DCC4CF25D#) + (g #501BCFB989AD2C346BBD7782CA0230551F976B1A07EE3AEE27E4B63B7B00B1ACA712AD85784986411278163156D4DBA9DF75C8560F9C2E02C02AEC830EC403A56B6F64432869D6CA9314A648076511343507629BF4FC96F8FDBB9797258DDF11F437B1450BA23F1AA7E885EC6A33D37B7D7EC384A004420DB238E140B94AAAFE#) + (y #7C9CB7732164787DD1931BB58257665EB60D6AA72B8D64D634530A61BE93D5AF01427962646542F18401B73032B12B9CBCAE8E3CF080DAD55C6612A97D6D8776CF2CBDD3AAC75D302B60E6956E5B3C60B39E171A2D5F150A924C6E22981EFDF052D5C6507B2DEC15E96CB6CAF7B260D5386BBDD7D7F69B4BF14451D64D847AEB#) + (x #00AB1E941176D94505911118AC799A504ADCCE88F8#) + ) + ) + ) + (account +(name otrtest3) +(protocol otr-test) +(private-key + (dsa + (p #00BB4C57669E50E4C35F8E4CA84855CF2C83EE75C4F44B4BB4A7E88590D394D7A738E82EE97892E5051CE45E200741E18D423137AA8E6679B1CFAB4FF11D45D8C9CBDE388D30FC800B4879713E3C57BA48A92FE135BB9AF265F770B706FB9A04802244D12CBFFD97ACE5C73FCE88C2B716B4B22B994CD6429A7E16D9B6D1874137#) + (q #00C40DA63B679A80FC31BF49A68503BB39754D0A45#) + (g #6C0A48BEA859587D6677306D1777A2A0635470F149A86EB64EA62EAAA4C21ECE4375ACD016B776E3AD3411C18BB3FF37F963FCEBB8820FF8838AFA6FCD1B39558DAB78450AE2ED9457DEDBDCE13DF5A6B20A738D2973D375D360C044AF7F0204CCC372098F0B6460963274B1EA0B5FEC93571A15F5C03DCDF54EE83BB198F363#) + (y #00AB2C8A82F020DB99EF5B7A8330EC43E0D5EBD623FEB67D1B046D88FACA01D8E31E4D7865DC62D4DA58CF8BC7FF4B57C203A9F7F5C85DAB1B63D63299EF13AD89AAA7E6638C9DBC42D096408936C9F0382224CFB5C1528DCC8C7F2554CB4CA2FF3C3239BC921F1C690295DD9AE69C8EF5BBD8E58A8FAA8BB9D5F88463CAECEE7B#) + (x #7824B713A4E5FA6D6C69172196648CD4657A1ED1#) + ) + ) + ) +) diff --git a/comm/third_party/libotr/tests/regression/random-msg-auth.sh b/comm/third_party/libotr/tests/regression/random-msg-auth.sh new file mode 100755 index 0000000000..bb9938f811 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-auth.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=50 +MAX_INTERVAL=500 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL and authentication" +$CLIENT --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG --auth diff --git a/comm/third_party/libotr/tests/regression/random-msg-disconnect-auth.sh b/comm/third_party/libotr/tests/regression/random-msg-disconnect-auth.sh new file mode 100755 index 0000000000..875c49ffa5 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-disconnect-auth.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=50 +MAX_INTERVAL=100 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL with disconnect and authentication" +$CLIENT --disconnect --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG --auth diff --git a/comm/third_party/libotr/tests/regression/random-msg-disconnect-frag-auth.sh b/comm/third_party/libotr/tests/regression/random-msg-disconnect-frag-auth.sh new file mode 100755 index 0000000000..f9c1b9be16 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-disconnect-frag-auth.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=20 +MAX_INTERVAL=500 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL with disconnect, framgents and authentication" +$CLIENT --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG --fragment --disconnect --auth diff --git a/comm/third_party/libotr/tests/regression/random-msg-disconnect-frag.sh b/comm/third_party/libotr/tests/regression/random-msg-disconnect-frag.sh new file mode 100755 index 0000000000..f58c315376 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-disconnect-frag.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=20 +MAX_INTERVAL=500 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL, disconnect and fragmentation" +$CLIENT --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG --fragment --disconnect diff --git a/comm/third_party/libotr/tests/regression/random-msg-disconnect.sh b/comm/third_party/libotr/tests/regression/random-msg-disconnect.sh new file mode 100755 index 0000000000..bae0703366 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-disconnect.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=50 +MAX_INTERVAL=500 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL with disconnect" +$CLIENT --disconnect --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG diff --git a/comm/third_party/libotr/tests/regression/random-msg-fast.sh b/comm/third_party/libotr/tests/regression/random-msg-fast.sh new file mode 100755 index 0000000000..dc400fe02b --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-fast.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=250 +MAX_INTERVAL=10 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL and number of message to $MAX_MSG" +$CLIENT --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG diff --git a/comm/third_party/libotr/tests/regression/random-msg-frag.sh b/comm/third_party/libotr/tests/regression/random-msg-frag.sh new file mode 100755 index 0000000000..0a4c6b04b8 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg-frag.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=20 +MAX_INTERVAL=500 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL and fragmentation" +$CLIENT --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG --fragment diff --git a/comm/third_party/libotr/tests/regression/random-msg.sh b/comm/third_party/libotr/tests/regression/random-msg.sh new file mode 100755 index 0000000000..d7679b2c97 --- /dev/null +++ b/comm/third_party/libotr/tests/regression/random-msg.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +CURDIR=$(dirname $0)/ +TESTDIR=$CURDIR/.. +CLIENT=$CURDIR/client/client +KEYFILE=$CURDIR/client/otr.key + +MAX_MSG=50 +MAX_INTERVAL=500 # msec + +source $TESTDIR/utils/tap/tap.sh + +diag "Messaging with random interval of max $MAX_INTERVAL" +$CLIENT --load-key $KEYFILE --timeout $MAX_INTERVAL --max-msg $MAX_MSG diff --git a/comm/third_party/libotr/tests/run.sh b/comm/third_party/libotr/tests/run.sh new file mode 100755 index 0000000000..33d850e7f0 --- /dev/null +++ b/comm/third_party/libotr/tests/run.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# Copyright (C) 2013 - Christian Babeux +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +[ -z "$1" ] && echo "Error: No testlist. Please specify a testlist to run." && exit 1 + +prove $2 --merge --exec '' - < $1 diff --git a/comm/third_party/libotr/tests/test_list b/comm/third_party/libotr/tests/test_list new file mode 100644 index 0000000000..aab15e1792 --- /dev/null +++ b/comm/third_party/libotr/tests/test_list @@ -0,0 +1,19 @@ +unit/test_auth +unit/test_proto +unit/test_dh +unit/test_b64 +unit/test_context +unit/test_userstate +unit/test_tlv +unit/test_mem +unit/test_sm +unit/test_instag +unit/test_privkey +regression/random-msg.sh +regression/random-msg-auth.sh +regression/random-msg-fast.sh +regression/random-msg-frag.sh +regression/random-msg-disconnect.sh +regression/random-msg-disconnect-frag.sh +regression/random-msg-disconnect-auth.sh +regression/random-msg-disconnect-frag-auth.sh diff --git a/comm/third_party/libotr/tests/unit/Makefile.am b/comm/third_party/libotr/tests/unit/Makefile.am new file mode 100644 index 0000000000..d48a6c7e4f --- /dev/null +++ b/comm/third_party/libotr/tests/unit/Makefile.am @@ -0,0 +1,50 @@ +AM_CFLAGS = -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/tests/utils/ \ + -I$(srcdir) \ + @LIBGCRYPT_CFLAGS@ + +LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la + +LIBOTR=$(top_builddir)/src/libotr.la + +noinst_PROGRAMS = test_auth test_proto test_dh \ + test_b64 test_context \ + test_userstate test_tlv \ + test_mem test_sm test_instag \ + test_privkey + +test_auth_SOURCES = test_auth.c +test_auth_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_proto_SOURCES = test_proto.c +test_proto_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_dh_SOURCES = test_dh.c +test_dh_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_b64_SOURCES = test_b64.c +test_b64_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_context_SOURCES = test_context.c +test_context_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_userstate_SOURCES = test_userstate.c +test_userstate_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_tlv_SOURCES = test_tlv.c +test_tlv_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_mem_SOURCES = test_mem.c +test_mem_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_sm_SOURCES = test_sm.c +test_sm_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_instag_SOURCES = test_instag.c +test_instag_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +test_privkey_SOURCES = test_privkey.c +test_privkey_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ + +EXTRA_DIST = instag.txt diff --git a/comm/third_party/libotr/tests/unit/Makefile.in b/comm/third_party/libotr/tests/unit/Makefile.in new file mode 100644 index 0000000000..33f11b540e --- /dev/null +++ b/comm/third_party/libotr/tests/unit/Makefile.in @@ -0,0 +1,697 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = test_auth$(EXEEXT) test_proto$(EXEEXT) \ + test_dh$(EXEEXT) test_b64$(EXEEXT) test_context$(EXEEXT) \ + test_userstate$(EXEEXT) test_tlv$(EXEEXT) test_mem$(EXEEXT) \ + test_sm$(EXEEXT) test_instag$(EXEEXT) test_privkey$(EXEEXT) +subdir = tests/unit +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/config/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_test_auth_OBJECTS = test_auth.$(OBJEXT) +test_auth_OBJECTS = $(am_test_auth_OBJECTS) +test_auth_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_test_b64_OBJECTS = test_b64.$(OBJEXT) +test_b64_OBJECTS = $(am_test_b64_OBJECTS) +test_b64_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_context_OBJECTS = test_context.$(OBJEXT) +test_context_OBJECTS = $(am_test_context_OBJECTS) +test_context_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_dh_OBJECTS = test_dh.$(OBJEXT) +test_dh_OBJECTS = $(am_test_dh_OBJECTS) +test_dh_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_instag_OBJECTS = test_instag.$(OBJEXT) +test_instag_OBJECTS = $(am_test_instag_OBJECTS) +test_instag_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_mem_OBJECTS = test_mem.$(OBJEXT) +test_mem_OBJECTS = $(am_test_mem_OBJECTS) +test_mem_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_privkey_OBJECTS = test_privkey.$(OBJEXT) +test_privkey_OBJECTS = $(am_test_privkey_OBJECTS) +test_privkey_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_proto_OBJECTS = test_proto.$(OBJEXT) +test_proto_OBJECTS = $(am_test_proto_OBJECTS) +test_proto_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_sm_OBJECTS = test_sm.$(OBJEXT) +test_sm_OBJECTS = $(am_test_sm_OBJECTS) +test_sm_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_tlv_OBJECTS = test_tlv.$(OBJEXT) +test_tlv_OBJECTS = $(am_test_tlv_OBJECTS) +test_tlv_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +am_test_userstate_OBJECTS = test_userstate.$(OBJEXT) +test_userstate_OBJECTS = $(am_test_userstate_OBJECTS) +test_userstate_DEPENDENCIES = $(LIBTAP) $(LIBOTR) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(test_auth_SOURCES) $(test_b64_SOURCES) \ + $(test_context_SOURCES) $(test_dh_SOURCES) \ + $(test_instag_SOURCES) $(test_mem_SOURCES) \ + $(test_privkey_SOURCES) $(test_proto_SOURCES) \ + $(test_sm_SOURCES) $(test_tlv_SOURCES) \ + $(test_userstate_SOURCES) +DIST_SOURCES = $(test_auth_SOURCES) $(test_b64_SOURCES) \ + $(test_context_SOURCES) $(test_dh_SOURCES) \ + $(test_instag_SOURCES) $(test_mem_SOURCES) \ + $(test_privkey_SOURCES) $(test_proto_SOURCES) \ + $(test_sm_SOURCES) $(test_tlv_SOURCES) \ + $(test_userstate_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/tests/utils/ \ + -I$(srcdir) \ + @LIBGCRYPT_CFLAGS@ + +LIBTAP = $(top_builddir)/tests/utils/tap/libtap.la +LIBOTR = $(top_builddir)/src/libotr.la +test_auth_SOURCES = test_auth.c +test_auth_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_proto_SOURCES = test_proto.c +test_proto_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_dh_SOURCES = test_dh.c +test_dh_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_b64_SOURCES = test_b64.c +test_b64_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_context_SOURCES = test_context.c +test_context_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_userstate_SOURCES = test_userstate.c +test_userstate_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_tlv_SOURCES = test_tlv.c +test_tlv_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_mem_SOURCES = test_mem.c +test_mem_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_sm_SOURCES = test_sm.c +test_sm_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_instag_SOURCES = test_instag.c +test_instag_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +test_privkey_SOURCES = test_privkey.c +test_privkey_LDADD = $(LIBTAP) $(LIBOTR) @LIBGCRYPT_LIBS@ +EXTRA_DIST = instag.txt +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/unit/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/unit/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +test_auth$(EXEEXT): $(test_auth_OBJECTS) $(test_auth_DEPENDENCIES) $(EXTRA_test_auth_DEPENDENCIES) + @rm -f test_auth$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_auth_OBJECTS) $(test_auth_LDADD) $(LIBS) + +test_b64$(EXEEXT): $(test_b64_OBJECTS) $(test_b64_DEPENDENCIES) $(EXTRA_test_b64_DEPENDENCIES) + @rm -f test_b64$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_b64_OBJECTS) $(test_b64_LDADD) $(LIBS) + +test_context$(EXEEXT): $(test_context_OBJECTS) $(test_context_DEPENDENCIES) $(EXTRA_test_context_DEPENDENCIES) + @rm -f test_context$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_context_OBJECTS) $(test_context_LDADD) $(LIBS) + +test_dh$(EXEEXT): $(test_dh_OBJECTS) $(test_dh_DEPENDENCIES) $(EXTRA_test_dh_DEPENDENCIES) + @rm -f test_dh$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_dh_OBJECTS) $(test_dh_LDADD) $(LIBS) + +test_instag$(EXEEXT): $(test_instag_OBJECTS) $(test_instag_DEPENDENCIES) $(EXTRA_test_instag_DEPENDENCIES) + @rm -f test_instag$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_instag_OBJECTS) $(test_instag_LDADD) $(LIBS) + +test_mem$(EXEEXT): $(test_mem_OBJECTS) $(test_mem_DEPENDENCIES) $(EXTRA_test_mem_DEPENDENCIES) + @rm -f test_mem$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_mem_OBJECTS) $(test_mem_LDADD) $(LIBS) + +test_privkey$(EXEEXT): $(test_privkey_OBJECTS) $(test_privkey_DEPENDENCIES) $(EXTRA_test_privkey_DEPENDENCIES) + @rm -f test_privkey$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_privkey_OBJECTS) $(test_privkey_LDADD) $(LIBS) + +test_proto$(EXEEXT): $(test_proto_OBJECTS) $(test_proto_DEPENDENCIES) $(EXTRA_test_proto_DEPENDENCIES) + @rm -f test_proto$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_proto_OBJECTS) $(test_proto_LDADD) $(LIBS) + +test_sm$(EXEEXT): $(test_sm_OBJECTS) $(test_sm_DEPENDENCIES) $(EXTRA_test_sm_DEPENDENCIES) + @rm -f test_sm$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_sm_OBJECTS) $(test_sm_LDADD) $(LIBS) + +test_tlv$(EXEEXT): $(test_tlv_OBJECTS) $(test_tlv_DEPENDENCIES) $(EXTRA_test_tlv_DEPENDENCIES) + @rm -f test_tlv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_tlv_OBJECTS) $(test_tlv_LDADD) $(LIBS) + +test_userstate$(EXEEXT): $(test_userstate_OBJECTS) $(test_userstate_DEPENDENCIES) $(EXTRA_test_userstate_DEPENDENCIES) + @rm -f test_userstate$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_userstate_OBJECTS) $(test_userstate_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_auth.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_b64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_context.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dh.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_instag.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mem.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_privkey.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_proto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_sm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tlv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_userstate.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/tests/unit/instag.txt b/comm/third_party/libotr/tests/unit/instag.txt new file mode 100644 index 0000000000..3cf4c31164 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/instag.txt @@ -0,0 +1,4 @@ +alice_xmpp XMPP 01234567 +alice_irc IRC 9abcdef0 +alice_inv IRC WRONG +alice_icq ICQ 98765432 diff --git a/comm/third_party/libotr/tests/unit/test_auth.c b/comm/third_party/libotr/tests/unit/test_auth.c new file mode 100644 index 0000000000..06b5908246 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_auth.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2014 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include +#include +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 5 + +static void test_auth_new(void) +{ + struct context ctx; + OtrlAuthInfo *auth = &ctx.auth; + + /* API call. */ + otrl_auth_new(&ctx); + + ok(auth->authstate == OTRL_AUTHSTATE_NONE && + auth->our_keyid == 0 && + auth->encgx == NULL && + auth->encgx_len == 0 && + utils_is_zeroed(auth->r, 16) && + utils_is_zeroed(auth->hashgx, 32) && + auth->their_pub == NULL && + auth->their_keyid == 0 && + auth->enc_c == NULL && + auth->enc_cp == NULL && + auth->mac_m1 == NULL && + auth->mac_m1p == NULL && + auth->mac_m2 == NULL && + auth->mac_m2p == NULL && + utils_is_zeroed(auth->their_fingerprint, 20) && + auth->initiated == 0 && + auth->protocol_version == 0 && + utils_is_zeroed(auth->secure_session_id, 20) && + auth->secure_session_id_len == 0 && + auth->lastauthmsg == NULL && + auth->commit_sent_time == 0 && + auth->context == &ctx, + "OTR auth info init is valid"); +} + +static void test_auth_clear(void) +{ + struct context ctx; + OtrlAuthInfo *auth = &ctx.auth; + + /* API call. */ + otrl_auth_clear(auth); + + ok(auth->authstate == OTRL_AUTHSTATE_NONE && + auth->our_keyid == 0 && + auth->encgx == NULL && + auth->encgx_len == 0 && + utils_is_zeroed(auth->r, 16) && + utils_is_zeroed(auth->hashgx, 32) && + auth->their_pub == NULL && + auth->their_keyid == 0 && + auth->enc_c == NULL && + auth->enc_cp == NULL && + auth->mac_m1 == NULL && + auth->mac_m1p == NULL && + auth->mac_m2 == NULL && + auth->mac_m2p == NULL && + utils_is_zeroed(auth->their_fingerprint, 20) && + auth->initiated == 0 && + auth->protocol_version == 0 && + utils_is_zeroed(auth->secure_session_id, 20) && + auth->secure_session_id_len == 0 && + auth->lastauthmsg == NULL && + auth->commit_sent_time == 0 && + auth->context == &ctx, + "OTR auth info clear is valid"); +} + +static void test_auth_start_v23(void) +{ + unsigned int version = 3; + gcry_error_t err; + struct context ctx; + OtrlAuthInfo *auth = &ctx.auth; + + /* API call. */ + otrl_auth_new(&ctx); + err = otrl_auth_start_v23(auth, version); + + ok(err == gcry_error(GPG_ERR_NO_ERROR) && + auth->initiated == 1 && + auth->protocol_version == version && + auth->context->protocol_version == version && + auth->our_keyid == 1 && + !utils_is_zeroed(auth->r, sizeof(auth->r)) && + auth->encgx != NULL && + auth->encgx_len > 0 && + !utils_is_zeroed(auth->hashgx, sizeof(auth->hashgx)) && + auth->lastauthmsg != NULL && + auth->authstate == OTRL_AUTHSTATE_AWAITING_DHKEY, + "OTR auth start v23 is valid"); +} + +static void test_otrl_auth_copy_on_key() +{ + struct context m_ctx, ctx; + OtrlAuthInfo *auth = &ctx.auth; + OtrlAuthInfo *m_auth = &m_ctx.auth; + + otrl_auth_new(&ctx); + otrl_auth_new(&m_ctx); + + otrl_auth_start_v23(auth, 3); + otrl_auth_start_v23(m_auth, 3); + + m_auth->authstate = OTRL_AUTHSTATE_NONE; + auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG, + otrl_auth_copy_on_key(m_auth, auth); + + ok(gcry_mpi_cmp((m_auth->our_dh.priv), (auth->our_dh.priv)) != 0 && + gcry_mpi_cmp((m_auth->our_dh.pub), (auth->our_dh.pub)) != 0 && + m_auth->our_keyid == auth->our_keyid && + memcmp(m_auth->r, auth->r, 16) != 0 && + memcmp(m_auth->encgx, auth->encgx, 16) != 0 && + memcmp(m_auth->hashgx, auth->hashgx, 16) != 0 && + auth->authstate == OTRL_AUTHSTATE_AWAITING_REVEALSIG, + "Copy not done"); + + auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY; + m_auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY; + otrl_auth_copy_on_key(m_auth, auth); + + ok(m_auth->initiated == auth->initiated && + m_auth->our_keyid == auth->our_keyid && + m_auth->our_dh.groupid == auth->our_dh.groupid && + gcry_mpi_cmp((m_auth->our_dh.priv), (auth->our_dh.priv)) == 0 && + gcry_mpi_cmp((m_auth->our_dh.pub), (auth->our_dh.pub)) == 0 && + m_auth->our_keyid == auth->our_keyid && + memcmp(m_auth->r, auth->r, 16) == 0 && + memcmp(m_auth->encgx, auth->encgx, 16) == 0 && + memcmp(m_auth->hashgx, auth->hashgx, 16) == 0 && + auth->authstate == OTRL_AUTHSTATE_AWAITING_DHKEY, + "Copy OK"); +} + +int main(int argc, char **argv) +{ + /* Libtap call for the number of tests planned. */ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + /* Initialize libotr. */ + otrl_dh_init(); + + test_auth_new(); + test_auth_clear(); + test_auth_start_v23(); + test_otrl_auth_copy_on_key(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_b64.c b/comm/third_party/libotr/tests/unit/test_b64.c new file mode 100644 index 0000000000..6d5599288e --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_b64.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include +#include +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 10 + +const char *alphanum_encoded = + "?OTR:" "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwCg==" "."; +const char *alphanum_decoded = + "abcdefghijklmnopqrstuvwxyz1234567890\n"; + +static void test_otrl_base64_otr_decode(void) +{ + int ret; + unsigned char *bufp = NULL; + size_t len = 0; + + /* + * Invalid decoding. + */ + + ok(otrl_base64_otr_decode("hello", NULL, NULL) == -2, + "Call with no prefix returned an error"); + ok(otrl_base64_otr_decode("?OTR:" "MTIzNAo=", NULL, NULL) == -2, + "Call with no suffix returned an error"); + /* Message of size 0. */ + ret = otrl_base64_otr_decode("", &bufp, &len); + ok(ret == -2 && bufp == NULL && len == 0, + "Decode b64 with message of len 0"); + /* + * Valid decoding. + */ + + /* Invalid chars are ignored */ + ok(otrl_base64_otr_decode("?OTR:invalid_base64_thing.", &bufp, &len) == 0 + && len == 12, "Invalid b64 data"); + free(bufp); + bufp = NULL; + len = 0; + + ok(otrl_base64_otr_decode(alphanum_encoded, &bufp, &len) == 0, + "Call with valid data successfull"); + ok(strcmp((const char*)bufp, alphanum_decoded) == 0 + && len == 37, "Decoded valid b64 test vector with success"); + free(bufp); + bufp = NULL; + len = 0; + + /* Invalid base64 char. */ + ret = otrl_base64_otr_decode("?OTR:_*&?!!*\"().", &bufp, &len); + ok(ret == 0 && bufp != NULL && len == 0, + "Decode b64 with invalid b64 characters"); + free(bufp); + bufp = NULL; + len = 0; + +} + +static void test_otrl_base64_otr_encode(void) +{ + unsigned char *bufp = NULL; + size_t len = 0; + char *encoded; + + encoded = otrl_base64_otr_encode((const unsigned char *) alphanum_decoded, + strlen(alphanum_decoded)); + + ok(strcmp(encoded, alphanum_encoded) == 0, + "Encoded b64 test vector with success"); + ok(otrl_base64_otr_decode(encoded, &bufp, &len) == 0, + "Decoded previously encoded test vector"); + ok(memcmp(bufp, alphanum_decoded, len) == 0 + && len == strlen(alphanum_decoded), + "Decoded value is exact"); + free(bufp); + free(encoded); +} + +int main(int argc, char** argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + test_otrl_base64_otr_decode(); + test_otrl_base64_otr_encode(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_context.c b/comm/third_party/libotr/tests/unit/test_context.c new file mode 100644 index 0000000000..6e173cd252 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_context.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include + +#include + +#define NUM_TESTS 22 + +static void test_otrl_context_find_fingerprint(void) +{ + unsigned char fingerprint[20] = {0}; + int add_if_missing = 0, addedp = 0; + + ok(otrl_context_find_fingerprint(NULL, fingerprint, + add_if_missing, &addedp) == NULL, "NULL context detected"); +} + +static ConnContext *new_context(const char *user, const char *account, + const char *protocol) +{ + ConnContext *context; + context = calloc(1, sizeof(ConnContext)); + context->username = strdup(user); + context->accountname = strdup(account); + context->protocol = strdup(protocol); + context->m_context = context; + context->active_fingerprint = calloc(1, sizeof(Fingerprint)); + context->context_priv = calloc(1, sizeof(ConnContextPriv)); + + return context; +} + +static void free_context(ConnContext *context) +{ + free(context->username); + free(context->accountname); + free(context->protocol); + free(context); +} + +static void test_otrl_context_find_recent_instance() +{ + ConnContext *context = new_context("main", "main", "main"); + ConnContext *context_child = new_context("child", "child", "child"); + ConnContext *context_rcvd = new_context("rcvd", "rcvd", "rcvd"); + ConnContext *context_sent = new_context("sent", "sent", "sent"); + ConnContext *tmp; + + context->recent_child = context_child; + context->recent_rcvd_child = context_rcvd; + context->recent_sent_child = context_sent; + + ok(otrl_context_find_recent_instance(NULL, OTRL_INSTAG_RECENT) == NULL, + "NULL context detected"); + + tmp = otrl_context_find_recent_instance(context, OTRL_INSTAG_RECENT); + ok(strcmp(tmp->username, "child") == 0, "OTRL_INSTAG_RECENT ok"); + + tmp = otrl_context_find_recent_instance(context, + OTRL_INSTAG_RECENT_RECEIVED); + ok(strcmp(tmp->username, "rcvd") == 0, "OTRL_INSTAG_RECENT_RECEIVED ok"); + + tmp = otrl_context_find_recent_instance(context, OTRL_INSTAG_RECENT_SENT); + ok(strcmp(tmp->username, "sent") == 0, "OTRL_INSTAG_RECENT_SENT ok"); + + tmp = otrl_context_find_recent_instance(context, INT_MAX); + ok(!tmp, "Invalid instag detected"); + + free_context(context); + free_context(context_child); + free_context(context_rcvd); + free_context(context_sent); +} + +static void test_otrl_context_find_recent_secure_instance(void) +{ + ConnContext *context1 = new_context("1", "1", "1"); + ConnContext *context2 = new_context("2", "2", "2"); + ConnContext *tmp; + + ok(otrl_context_find_recent_secure_instance(NULL) == NULL, + "NULL detected"); + + context1->next = context2; + context2->next = NULL; + context2->m_context = context1; + + context1->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->msgstate = OTRL_MSGSTATE_PLAINTEXT; + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context2, "Same msgstate"); + + context1->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->msgstate = OTRL_MSGSTATE_FINISHED; + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context2, "plaintext then finished"); + + context1->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->msgstate = OTRL_MSGSTATE_ENCRYPTED; + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context2, "Most secure context found"); + + context1->msgstate = OTRL_MSGSTATE_ENCRYPTED; + context2->msgstate = OTRL_MSGSTATE_ENCRYPTED; + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context2, "Most secure context found"); + + context1->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->active_fingerprint->trust = strdup("hello"); + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context2, "Most secure context found"); + free(context2->active_fingerprint); + context2->active_fingerprint = NULL; + + context1->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context2->context_priv->lastrecv = 1; + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context2, "Most secure context found"); + + context1->msgstate = OTRL_MSGSTATE_PLAINTEXT; + context1->context_priv->lastrecv = 2; + context2->msgstate = OTRL_MSGSTATE_PLAINTEXT; + tmp = otrl_context_find_recent_secure_instance(context1); + ok(tmp == context1, "Most secure context found"); + + free_context(context1); + free_context(context2); +} + +static void test_otrl_context_is_fingerprint_trusted() +{ + Fingerprint fprint; + fprint.trust = NULL; + + ok(otrl_context_is_fingerprint_trusted(NULL) == 0, + "NULL fingerprint detected"); + ok(otrl_context_is_fingerprint_trusted(&fprint) == 0, + "NULL trust detected"); + fprint.trust = "1234"; + ok(otrl_context_is_fingerprint_trusted(&fprint) != 0, + "Trusted fingerprint detected"); +} + +static void test_otrl_context_update_recent_child() +{ + ConnContext context1, context2; + context1.m_context = &context1; + context2.m_context = &context1; + + otrl_context_update_recent_child(&context1, 0); + ok(context1.recent_rcvd_child == &context1 && + context1.recent_child == &context1, + "Recent self rcvd set"); + + otrl_context_update_recent_child(&context1, 1); + ok(context1.recent_sent_child == &context1 && + context1.recent_child == &context1, + "Recent self sent set"); + + otrl_context_update_recent_child(&context2, 0); + ok(context1.recent_rcvd_child == &context2 && + context1.recent_child == &context2, + "Recent rcvd set"); + + otrl_context_update_recent_child(&context2, 1); + ok(context1.recent_sent_child == &context2 && + context1.recent_child == &context2, + "Recent sent set"); +} + +static void test_otrl_context_set_trust(void) +{ + Fingerprint fprint; + const char *trust = "I don't trust anyone."; + + fprint.trust = NULL; + + otrl_context_set_trust(&fprint, trust); + ok(strcmp(fprint.trust, trust) == 0, "Fingerprint set with success"); +} + +int main(int argc, char **argv) +{ + plan_tests(NUM_TESTS); + + test_otrl_context_set_trust(); + test_otrl_context_find_recent_instance(); + test_otrl_context_find_fingerprint(); + test_otrl_context_find_recent_secure_instance(); + test_otrl_context_is_fingerprint_trusted(); + test_otrl_context_update_recent_child(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_dh.c b/comm/third_party/libotr/tests/unit/test_dh.c new file mode 100644 index 0000000000..c27c09b886 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_dh.c @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 38 + +/* + * The re-implementation/inclusion of crypto stuff is necessary because libotr + * doesn't expose them. + */ + +static const char* DH1536_MODULUS_S = "0x" + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; +static const char *DH1536_GENERATOR_S = "0x02"; +static const int DH1536_MOD_LEN_BITS = 1536; + +static gcry_mpi_t DH1536_MODULUS = NULL; +static gcry_mpi_t DH1536_MODULUS_MINUS_2 = NULL; +static gcry_mpi_t DH1536_GENERATOR = NULL; + +static void test_otrl_dh_keypair_init(void) +{ + DH_keypair kp; + + otrl_dh_keypair_init(&kp); + + ok(kp.groupid == 0 && + kp.priv == NULL && + kp.pub == NULL, + "Keypair initialized"); +} + +static void test_otrl_dh_keypair_copy(void) +{ + DH_keypair k1, k2; + unsigned char *buf; + + k1.groupid = rand(); + + buf = gcry_random_bytes(32, GCRY_WEAK_RANDOM); + gcry_mpi_scan(&(k1.priv), GCRYMPI_FMT_USG, buf, 32, NULL); + gcry_free(buf); + + buf = gcry_random_bytes(32, GCRY_WEAK_RANDOM); + gcry_mpi_scan(&(k1.pub), GCRYMPI_FMT_USG, buf, 32, NULL); + gcry_free(buf); + + otrl_dh_keypair_copy(&k2, &k1); + + ok(k1.groupid == k2.groupid && + gcry_mpi_cmp(k1.priv, k2.priv) == 0 && + gcry_mpi_cmp(k1.pub, k2.pub) == 0, + "Keypair copied"); + + gcry_mpi_release(k1.priv); + gcry_mpi_release(k1.pub); + gcry_mpi_release(k2.priv); + gcry_mpi_release(k2.pub); +} + +static void test_otrl_dh_session_free() +{ + DH_sesskeys sess; + DH_keypair kp1, kp2; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp1)); + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp2)); + otrl_dh_session(&sess, &kp1, kp2.pub); + + otrl_dh_session_free(&sess); + + ok(sess.sendenc == NULL && + sess.sendmac == NULL && + sess.rcvenc == NULL && + sess.rcvmac == NULL && + utils_is_zeroed(sess.sendctr, 16) && + utils_is_zeroed(sess.rcvctr, 16) && + utils_is_zeroed(sess.sendmackey, 16) && + utils_is_zeroed(sess.rcvmackey, 16) && + sess.sendmacused == 0 && + sess.rcvmacused == 0 && + utils_is_zeroed(sess.extrakey, OTRL_EXTRAKEY_BYTES), + "Session freed"); +} + + +static void test_otrl_dh_session_blank() +{ + DH_sesskeys sess; + DH_keypair kp1, kp2; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp1)); + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp2)); + otrl_dh_session(&sess, &kp1, kp2.pub); + + otrl_dh_session_blank(&sess); + + ok(sess.sendenc == NULL && + sess.sendmac == NULL && + sess.rcvenc == NULL && + sess.rcvmac == NULL && + utils_is_zeroed(sess.sendctr, 16) && + utils_is_zeroed(sess.rcvctr, 16) && + utils_is_zeroed(sess.sendmackey, 16) && + utils_is_zeroed(sess.rcvmackey, 16) && + sess.sendmacused == 0 && + sess.rcvmacused == 0 && + utils_is_zeroed(sess.extrakey, OTRL_EXTRAKEY_BYTES), + "Session blanked"); +} + +static void test_otrl_dh_gen_keypair(void) +{ + DH_keypair kp; + gcry_mpi_t pubkey = NULL; + + otrl_dh_keypair_init(&kp); + + ok(otrl_dh_gen_keypair(DH1536_GROUP_ID+1, &kp) == + gcry_error(GPG_ERR_INV_VALUE), + "Invalid group detected"); + + ok(otrl_dh_gen_keypair(DH1536_GROUP_ID, &kp) == + gcry_error(GPG_ERR_NO_ERROR), + "Valid group set"); + ok(kp.groupid == DH1536_GROUP_ID, "Group set"); + + pubkey = gcry_mpi_new(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(pubkey, DH1536_GENERATOR, kp.priv, DH1536_MODULUS); + ok(gcry_mpi_cmp(pubkey, kp.pub) == 0, "Matching pubkey"); + otrl_dh_keypair_free(&kp); +} + +static void test_otrl_dh_keypair_free(void) +{ + DH_keypair kp; + otrl_dh_gen_keypair(DH1536_GROUP_ID, &kp); + otrl_dh_keypair_free(&kp); + ok(kp.pub == NULL && kp.priv == NULL && kp.groupid == DH1536_GROUP_ID, + "DH_keypair free'd with success"); + +} + +static void invert_DH_keypair(DH_keypair* kp1, DH_keypair* kp2) +{ + DH_keypair tmp; + otrl_dh_keypair_copy(&tmp, kp1); + otrl_dh_keypair_copy(kp1, kp2); + otrl_dh_keypair_copy(kp2, &tmp); + otrl_dh_keypair_free(&tmp); +} + +/* + * This is an helper function. See the next one. + */ +static void _test_ortl_dh_session(const DH_keypair *kp, gcry_mpi_t y) +{ + unsigned char *gabdata; + unsigned char *hashdata; + unsigned char encrypt[32] = {0}; + unsigned char expected_encrypt[32] = {0}; + unsigned char sendbyte, rcvbyte; + const char test_vector[] = "This is a test vector"; + DH_sesskeys sess; + DH_sesskeys sess_expected; + gcry_mpi_t gab; + size_t gablen; + otrl_dh_session_blank(&sess); + otrl_dh_session(&sess, kp, y); + + gab = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(gab, y, kp->priv, DH1536_MODULUS); + + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &gablen, gab); + gabdata = gcry_malloc_secure(gablen + 5); + gabdata[1] = (gablen >> 24) & 0xff; + gabdata[2] = (gablen >> 16) & 0xff; + gabdata[3] = (gablen >> 8) & 0xff; + gabdata[4] = gablen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, gabdata + 5, gablen, NULL, gab); + gcry_mpi_release(gab); + + hashdata = gcry_malloc_secure(20); + + if (gcry_mpi_cmp(kp->pub, y) > 0 ) { + sendbyte = 0x01; + rcvbyte = 0x02; + } else { + sendbyte = 0x02; + rcvbyte = 0x01; + } + + gabdata[0] = sendbyte; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen + 5); + + gcry_cipher_open(&(sess_expected.sendenc), GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + gcry_cipher_setkey(sess_expected.sendenc, hashdata, 16); + gcry_cipher_encrypt(sess_expected.sendenc, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(sess.sendenc, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "sendenc ok"); + + gcry_md_hash_buffer(GCRY_MD_SHA1, sess_expected.sendmackey, hashdata, 16); + gcry_md_open(&(sess_expected.sendmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(sess_expected.sendmac, sess_expected.sendmackey, 20); + gcry_md_write(sess_expected.sendmac, test_vector, sizeof(test_vector)); + gcry_md_write(sess.sendmac, test_vector, sizeof(test_vector)); + + ok(memcmp(gcry_md_read(sess_expected.sendmac, 0), + gcry_md_read(sess.sendmac, 0), 32) == 0, + "Sendmac ok"); + + gabdata[0] = rcvbyte; + gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen + 5); + gcry_cipher_open(&(sess_expected.rcvenc), GCRY_CIPHER_AES, + GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); + gcry_cipher_setkey(sess_expected.rcvenc, hashdata, 16); + gcry_cipher_encrypt(sess_expected.rcvenc, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(sess.rcvenc, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "Sendenc ok"); + + gcry_md_hash_buffer(GCRY_MD_SHA1, sess_expected.rcvmackey, hashdata, 16); + gcry_md_open(&(sess_expected.rcvmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(sess_expected.rcvmac, sess_expected.rcvmackey, 20); + gcry_md_write(sess_expected.rcvmac, test_vector, sizeof(test_vector)); + gcry_md_write(sess.rcvmac, test_vector, sizeof(test_vector)); + ok(memcmp(gcry_md_read(sess_expected.sendmac, 0), + gcry_md_read(sess.sendmac, 0), 32) == 0, + "rcvmac ok"); + + gabdata[0] = 0xff; + + gcry_md_hash_buffer(GCRY_MD_SHA256, sess_expected.extrakey, gabdata, + gablen + 5); + ok(memcmp(sess_expected.extrakey, sess.extrakey, 32) == 0, "extrakey set"); + + gcry_free(gabdata); + gcry_free(hashdata); +} + +/* + * This function is a little bit tricky, since it uses an array of 3 + * DH_keypair. The first one has a smaller pubkey than the second, which has a + * smaller pubkey than the third one. + * + * The second key is used as "main" key. The two other ones are used to test + * the otrl_dh_session, with a biggest and a smallest key than the "main" one. + */ +static void test_otrl_dh_session(void) +{ + int i; + DH_keypair kp[3]; /* kp[0] < kp[1] < kp[2] */ + DH_sesskeys sess; + + for (i = 0; i < 3; i++) { + otrl_dh_gen_keypair(DH1536_GROUP_ID, &(kp[i])); + } + + /* Sort the array. */ + for (i = 0; i < 2; i++) { + if (gcry_mpi_cmp(kp[i].pub, kp[i + 1].pub) > 0) { + invert_DH_keypair(kp + i, kp + i + 1); + } + } + + if (gcry_mpi_cmp(kp[0].pub, kp[1].pub) > 0) { + invert_DH_keypair(kp, kp + 1); + } + + kp[1].groupid++; + + ok(otrl_dh_session(&sess, &(kp[1]), kp[0].pub) == + gcry_error(GPG_ERR_INV_VALUE), + "Invalid group detected"); + kp[1].groupid--; + + _test_ortl_dh_session(&(kp[1]), kp[0].pub); + _test_ortl_dh_session(&(kp[1]), kp[2].pub); +} + +static void test_otrl_dh_compute_v2_auth_keys(void) +{ + const char test_vector[] = "This is a test vector"; + size_t slen = 0; + size_t sessionidlenp = 0; + unsigned char *sdata = NULL; + unsigned char *hashdata = NULL; + gcry_mpi_t s = NULL; + unsigned char ctr[16] = {0}; + + DH_keypair our_dh, their_dh; + gcry_mpi_t public_key = NULL; + + unsigned char sessionid[8]; + gcry_md_hd_t mac_m1 = NULL, mac_m1p = NULL, mac_m2 = NULL, mac_m2p = NULL; + gcry_cipher_hd_t enc_c = NULL, enc_cp = NULL; + unsigned char encrypt[32] = {0}; + + unsigned char sessionid_expected[8]; + + gcry_md_hd_t mac_m1_expected = NULL, mac_m1p_expected = NULL; + gcry_md_hd_t mac_m2_expected = NULL, mac_m2p_expected = NULL; + gcry_cipher_hd_t enc_c_expected = NULL, enc_cp_expected = NULL; + unsigned char expected_encrypt[32] = {0}; + + otrl_dh_gen_keypair(DH1536_GROUP_ID, &our_dh); + otrl_dh_gen_keypair(DH1536_GROUP_ID, &their_dh); + + our_dh.groupid++; + ok(otrl_dh_compute_v2_auth_keys(&our_dh, their_dh.pub, + sessionid, &sessionidlenp, &enc_c, &enc_cp, + &mac_m1, &mac_m1p, &mac_m2, &mac_m2p) + == gcry_error(GPG_ERR_INV_VALUE), + "Invalid group detected"); + our_dh.groupid--; + + gcry_mpi_scan(&public_key, GCRYMPI_FMT_USG, "1", 0, NULL); + + ok(otrl_dh_compute_v2_auth_keys(&our_dh, public_key, + sessionid, &sessionidlenp, &enc_c, &enc_cp, + &mac_m1, &mac_m1p, &mac_m2, &mac_m2p) + == gcry_error(GPG_ERR_INV_VALUE), + "Public key too small"); + + gcry_mpi_scan(&public_key, GCRYMPI_FMT_HEX, + (const unsigned char *) DH1536_MODULUS_S, 0, NULL); + gcry_mpi_add_ui(public_key, DH1536_MODULUS, 1); + + ok(otrl_dh_compute_v2_auth_keys(&our_dh, DH1536_MODULUS, + sessionid, &sessionidlenp, &enc_c, &enc_cp, + &mac_m1, &mac_m1p, &mac_m2, &mac_m2p) + == gcry_error(GPG_ERR_INV_VALUE), + "Public key too big"); + + ok(otrl_dh_compute_v2_auth_keys(&our_dh, their_dh.pub, sessionid, + &sessionidlenp, &enc_c, &enc_cp, &mac_m1, &mac_m1p, &mac_m2, + &mac_m2p) == gcry_error(GPG_ERR_NO_ERROR), + "Auth keys generated"); + + ok(sessionidlenp == 8, "Session id len p set to correct value"); + + s = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(s, their_dh.pub, our_dh.priv, DH1536_MODULUS); + + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s); + sdata = gcry_malloc_secure(slen + 5); + sdata[1] = (slen >> 24) & 0xff; + sdata[2] = (slen >> 16) & 0xff; + sdata[3] = (slen >> 8) & 0xff; + sdata[4] = slen & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s); + gcry_mpi_release(s); + + hashdata = gcry_malloc_secure(32); + sdata[0] = 0x00; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + memmove(sessionid_expected, hashdata, 8); + ok(memcmp(sessionid_expected, sessionid, 8) == 0, "Session id is correct"); + + sdata[0] = 0x01; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + + gcry_cipher_open(&enc_c_expected, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + GCRY_CIPHER_SECURE); + gcry_cipher_setkey(enc_c_expected, hashdata, 16); + gcry_cipher_setctr(enc_c_expected, ctr, 16); + + gcry_cipher_encrypt(enc_c_expected, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(enc_c, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "Enc ok"); + + gcry_cipher_open(&(enc_cp_expected), GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + GCRY_CIPHER_SECURE); + gcry_cipher_setkey(enc_cp_expected, hashdata+16, 16); + gcry_cipher_setctr(enc_cp_expected, ctr, 16); + gcry_cipher_encrypt(enc_cp_expected, expected_encrypt, + sizeof(expected_encrypt), test_vector, strlen(test_vector)); + gcry_cipher_encrypt(enc_cp, encrypt, sizeof(encrypt), test_vector, + strlen(test_vector)); + ok(memcmp(encrypt, expected_encrypt, sizeof(encrypt)) == 0, "Encp ok"); + + sdata[0] = 0x02; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m1_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m1_expected, hashdata, 32); + gcry_md_write(mac_m1_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m1, test_vector, sizeof(test_vector)); + ok(memcmp(gcry_md_read(mac_m1_expected, 0), + gcry_md_read(mac_m1, 0), 32) == 0, + "mac_m1 set"); + + sdata[0] = 0x03; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m2_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m2_expected, hashdata, 32); + gcry_md_write(mac_m2_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m2, test_vector, sizeof(test_vector)); + ok(memcmp(gcry_md_read(mac_m2_expected, 0), + gcry_md_read(mac_m2, 0), 32) == 0, + "mac_m2 set"); + + sdata[0] = 0x04; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m1p_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m1p_expected, hashdata, 32); + gcry_md_write(mac_m1p_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m1p, test_vector, sizeof(test_vector)); + + ok(memcmp(gcry_md_read(mac_m1p_expected, 0), + gcry_md_read(mac_m1p, 0), 32) == 0, + "mac_m1p set"); + + sdata[0] = 0x05; + gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); + gcry_md_open(&mac_m2p_expected, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + gcry_md_setkey(mac_m2p_expected, hashdata, 32); + gcry_md_write(mac_m2p_expected, test_vector, sizeof(test_vector)); + gcry_md_write(mac_m2p, test_vector, sizeof(test_vector)); + + ok(memcmp(gcry_md_read(mac_m2p_expected, 0), + gcry_md_read(mac_m2p, 0), 32) == 0, + "mac_m2p set"); + + gcry_free(sdata); + gcry_free(hashdata); +} + +static void test_otrl_dh_incctr() +{ + unsigned char ctr[8] = {0}; + otrl_dh_incctr(ctr); + ok(ctr[7] == 1 && utils_is_zeroed(ctr, 7), "Counter set"); + ctr[7] = 255; + otrl_dh_incctr(ctr); + ok(ctr[7] == 0 && ctr[6] == 1 && utils_is_zeroed(ctr, 5), + "Counter set"); + memset(ctr, 255, sizeof(ctr)); + otrl_dh_incctr(ctr); + ok(utils_is_zeroed(ctr, sizeof(ctr)), "Counter set"); +} + +static void test_otrl_dh_cmpctr() +{ + unsigned char ctr1[8] = {0}, ctr2[8] = {0}; + ok(otrl_dh_cmpctr(ctr1, ctr2) == 0, "Null counters are equals"); + ctr1[1]++; + ok(otrl_dh_cmpctr(ctr1, ctr2) > 0, "Ctr1 is bigger than ctr2"); + ctr2[0]++; + ok(otrl_dh_cmpctr(ctr1, ctr2) < 0, "Ctr2 is bigger than ctr1"); +} + +int main(int argc, char **argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + otrl_dh_init(); + + gcry_mpi_scan(&DH1536_MODULUS, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_MODULUS_S, 0, NULL); + gcry_mpi_scan(&DH1536_GENERATOR, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_GENERATOR_S, 0, NULL); + DH1536_MODULUS_MINUS_2 = gcry_mpi_new(DH1536_MOD_LEN_BITS); + gcry_mpi_sub_ui(DH1536_MODULUS_MINUS_2, DH1536_MODULUS, 2); + + test_otrl_dh_gen_keypair(); + test_otrl_dh_keypair_free(); + test_otrl_dh_keypair_init(); + test_otrl_dh_compute_v2_auth_keys(); + test_otrl_dh_session(); + test_otrl_dh_keypair_copy(); + test_otrl_dh_session_blank(); + test_otrl_dh_session_free(); + test_otrl_dh_incctr(); + test_otrl_dh_cmpctr(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_instag.c b/comm/third_party/libotr/tests/unit/test_instag.c new file mode 100644 index 0000000000..3758ae2f2b --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_instag.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 13 + +/* Current directory of this executable. */ +static char curdir[PATH_MAX]; +static char instag_filepath[PATH_MAX]; + +static void test_otrl_instag_forget(void) +{ + OtrlInsTag *instag1 = calloc(1, sizeof(OtrlInsTag)); + OtrlInsTag *instag2 = calloc(1, sizeof(OtrlInsTag)); + + instag1->tous = &instag1; + instag1->accountname = strdup("name one"); + instag1->protocol = strdup("protocol one"); + instag1->next = instag2; + instag1->next->tous = &(instag1->next); + instag2->accountname = strdup("name two"); + instag2->protocol = strdup("protocol two"); + + otrl_instag_forget(NULL); + ok(1, "Forget on NULL didn't segfault"); + + otrl_instag_forget(instag2); + ok(instag1->next == NULL, "Instag forgotten without segfault"); +} + +static void test_otrl_instag_forget_all(void) +{ + OtrlUserState us = otrl_userstate_create(); + OtrlInsTag *p = malloc(sizeof(OtrlInsTag)); + p->accountname = strdup("account name"); + p->protocol = strdup("protocol name"); + p->instag = otrl_instag_get_new(); + + otrl_instag_forget_all(us); + ok(1, "Forget all on empty user state"); + + p->next = us->instag_root; + p->tous = &(us->instag_root); + us->instag_root = p; + + otrl_instag_forget_all(us); + ok(1, "Forget all on a non-empty user state"); +} + +static void test_otrl_instag_find(void) +{ + OtrlUserState us = otrl_userstate_create(); + OtrlInsTag *p1 = malloc(sizeof(OtrlInsTag)); + OtrlInsTag *p2 = malloc(sizeof(OtrlInsTag)); + + p1->accountname = strdup("account one"); + p1->protocol = strdup("protocol one"); + p1->instag = otrl_instag_get_new(); + p1->next = us->instag_root; + p1->tous = &(us->instag_root); + us->instag_root = p1; + + p2->accountname = strdup("account two"); + p2->protocol = strdup("protocol two"); + p2->instag = otrl_instag_get_new(); + p2->next = us->instag_root; + p2->next->tous = &(p2->next); + p2->tous = &(us->instag_root); + us->instag_root = p2; + + ok(otrl_instag_find(us, "account two", "protocol two") == p2, + "Found instag"); + ok(otrl_instag_find(us, "account one", "protocol two") == NULL, + "Instag not found"); + ok(otrl_instag_find(us, "account three", "protocol three") == NULL, + "Instag not found"); +} + +static void test_otrl_instag_read(void) +{ + OtrlUserState us = otrl_userstate_create(); + OtrlInsTag *one, *two, *three, *four; + char sone[9] = {0}, stwo[9] = {0}, sfour[9] = {0}; + one = two = three = four = NULL; + ok(otrl_instag_read(us, "/non_existent_file") == + gcry_error_from_errno(ENOENT), + "Non-existent file detected"); + + ok(otrl_instag_read(us, instag_filepath) == GPG_ERR_NO_ERROR, + "Instag called with success"); + + one = otrl_instag_find(us, "alice_xmpp", "XMPP"); + snprintf(sone, sizeof(sone), "%08x", one->instag); + + two = otrl_instag_find(us, "alice_irc", "IRC"); + snprintf(stwo, sizeof(stwo), "%08x", two->instag); + + three = otrl_instag_find(us, "alice_inv", "IRC"); + + four = otrl_instag_find(us, "alice_icq", "ICQ"); + snprintf(sfour, sizeof(sfour), "%08x", four->instag); + + ok(one && two && !three && four && + strcmp(sone, "01234567") == 0 && + strcmp(stwo, "9abcdef0") == 0 && + strcmp(sfour, "98765432") == 0, + "Instag succesfully read"); +} + +static void test_otrl_instag_read_FILEp(void) +{ + FILE* instf = fopen(instag_filepath, "rb"); + OtrlUserState us = otrl_userstate_create(); + OtrlInsTag* one, *two, *three, *four; + char sone[9] = {0}, stwo[9] = {0}, sfour[9] = {0}; + one = two = three = four = NULL; + + ok(otrl_instag_read_FILEp(us, instf) == gcry_error(GPG_ERR_NO_ERROR), + "Instead read from FILEp"); + fclose(instf); + + one = otrl_instag_find(us, "alice_xmpp", "XMPP"); + snprintf(sone, sizeof(sone), "%08x", one->instag); + + two = otrl_instag_find(us, "alice_irc", "IRC"); + snprintf(stwo, sizeof(stwo), "%08x", two->instag); + + three = otrl_instag_find(us, "alice_inv", "IRC"); + + four = otrl_instag_find(us, "alice_icq", "ICQ"); + snprintf(sfour, sizeof(sfour), "%08x", four->instag); + + ok(one && two && !three && four && + strcmp(sone, "01234567") == 0 && + strcmp(stwo, "9abcdef0") == 0 && + strcmp(sfour, "98765432") == 0, + "Instag succesfully read"); +} + +static void test_otrl_instag_get_new(void) +{ + ok(otrl_instag_get_new() != 0, "New instag generated"); +} + +static ssize_t get_exe_path(char *buf, size_t len) +{ + char *path_end; + + if (readlink("/proc/self/exe", buf, len) < 0) { + return -ENOMEM; + } + + /* + * Workaround to handle libtool path of the binary that is actually in the + * $(buildir)/.libs. This is to make sure unit test works outside of tree. + */ + path_end = strstr(buf, ".libs/"); + if (!path_end) { + path_end = strrchr(buf, '/'); + if (!path_end) { + return -errno; + } + *(++path_end) = '\0'; + } else { + *path_end = '\0'; + } + + return path_end - buf; +} + +int main(int argc, char **argv) +{ + /* Libtap call for the number of tests planned. */ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + if (get_exe_path(curdir, sizeof(curdir)) < 0) { + return -ENOMEM; + } + + /* Build the full path of the instag.txt file. */ + (void) snprintf(instag_filepath, sizeof(instag_filepath), "%s%s", curdir, + "instag.txt"); + + test_otrl_instag_forget(); + test_otrl_instag_forget_all(); + test_otrl_instag_find(); + test_otrl_instag_read(); + test_otrl_instag_read_FILEp(); + test_otrl_instag_get_new(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_mem.c b/comm/third_party/libotr/tests/unit/test_mem.c new file mode 100644 index 0000000000..24eae20151 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_mem.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 5 + +static void test_otrl_mem_differ(void) +{ + const unsigned char buf1[] = "\x00" "12" "\x00" "34"; + const unsigned char buf2[] = "\x00" "13" "\x00" "34"; + const unsigned char buf3[] = "\x00" "13" "\x00" "345"; + + ok(otrl_mem_differ(buf1, buf1, sizeof(buf1)) == 0, + "Identical buf are identical"); + ok(otrl_mem_differ(buf1, buf2, sizeof(buf1)) == 1, + "buf1 and buf2 are not identical"); + ok(otrl_mem_differ(buf2, buf3, sizeof(buf1)) == 1, + "buf1 and buf2 are not identical"); + ok(otrl_mem_differ(buf1, NULL, 0) == 0, + "buf1 and NULL are identical"); + ok(otrl_mem_differ(NULL, NULL, 0) == 0, + "NULL and NULL are identical"); +} + +int main(int argc, char **argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + test_otrl_mem_differ(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_privkey.c b/comm/third_party/libotr/tests/unit/test_privkey.c new file mode 100644 index 0000000000..9e2db46189 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_privkey.c @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include +#include + +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 13 + +static OtrlUserState us = NULL; +static char filename[] = "/tmp/libotr-testing-XXXXXX"; +static FILE* f = NULL; + +/* + * Create a public key block from a private key + */ +static void make_pubkey(unsigned char **pubbufp, size_t *publenp, + gcry_sexp_t privkey) +{ + gcry_mpi_t p,q,g,y; + gcry_sexp_t dsas,ps,qs,gs,ys; + size_t np,nq,ng,ny; + enum gcry_mpi_format format = GCRYMPI_FMT_USG; + + *pubbufp = NULL; + *publenp = 0; + + /* Extract the public parameters */ + dsas = gcry_sexp_find_token(privkey, "dsa", 0); + ps = gcry_sexp_find_token(dsas, "p", 0); + qs = gcry_sexp_find_token(dsas, "q", 0); + gs = gcry_sexp_find_token(dsas, "g", 0); + ys = gcry_sexp_find_token(dsas, "y", 0); + gcry_sexp_release(dsas); + + p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(ps); + q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(qs); + g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(gs); + y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(ys); + + *publenp = 0; + gcry_mpi_print(format, NULL, 0, &np, p); + *publenp += np + 4; + gcry_mpi_print(format, NULL, 0, &nq, q); + *publenp += nq + 4; + gcry_mpi_print(format, NULL, 0, &ng, g); + *publenp += ng + 4; + gcry_mpi_print(format, NULL, 0, &ny, y); + *publenp += ny + 4; + + *pubbufp = malloc(*publenp); + + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); +} + +static void test_otrl_privkey_generate_FILEp(void) +{ + int fd = mkstemp(filename); + f = fdopen(fd, "w+b"); + + unlink(filename); // The file will be removed on close + us = otrl_userstate_create(); + ok(otrl_privkey_generate_FILEp(us, f, "alice", "irc") + == gcry_error(GPG_ERR_NO_ERROR) && + us->privkey_root != NULL, + "key generated"); +} + +static void test_otrl_privkey_hash_to_human(void) +{ + int i; + char human[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; + unsigned char hash[20]; + + for(i = 0; i < 20; i++) { + hash[i] = 'A' + i; + } + + otrl_privkey_hash_to_human(human, hash); + ok(strcmp("41424344 45464748 494A4B4C 4D4E4F50 51525354", human) == 0, + "Hash to human ok"); +} + +static void test_otrl_privkey_fingerprint(void) +{ + char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN] = {0}; + char expected_fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN] = {0}; + unsigned char hash[20] = {0}; + char *fp = otrl_privkey_fingerprint(us, fingerprint, "alice", "irc"); + const OtrlPrivKey *p = otrl_privkey_find(us, "alice", "irc"); + + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data, p->pubkey_datalen); + otrl_privkey_hash_to_human(expected_fingerprint, hash); + + ok(fp == fingerprint && + memcmp(fingerprint, expected_fingerprint, + OTRL_PRIVKEY_FPRINT_HUMAN_LEN) == 0, + "Privkey fingerprint ok"); +} + +static void test_otrl_privkey_fingerprint_raw(void) +{ + unsigned char hash[20] = {0}; + unsigned char expected_hash[20] = {0}; + unsigned char *h = otrl_privkey_fingerprint_raw(us, hash, "alice", "irc"); + + const OtrlPrivKey *p = otrl_privkey_find(us, "alice", "irc"); + gcry_md_hash_buffer(GCRY_MD_SHA1, expected_hash, p->pubkey_data, + p->pubkey_datalen); + + ok(h == hash && memcmp(hash, expected_hash, 20) == 0, + "Raw privkey fingerprint ok"); +} + +static void test_otrl_privkey_find(void) +{ + OtrlPrivKey *p = NULL; + + ok(otrl_privkey_find(us, "bob", "xmpp") == NULL, + "Privkey not found"); + + ok(otrl_privkey_find(us, "alice", "xmpp") == NULL, + "Privkey not found because of wrong protocol"); + + ok(otrl_privkey_find(us, "bob", "irc") == NULL, + "Privkey not found because of wrong name"); + + p = otrl_privkey_find(us, "alice", "irc"); + ok(p != NULL && strcmp(p->accountname, "alice") == 0 && + strcmp(p->protocol, "irc") == 0, + "Privkey found"); +} + +static void test_otrl_privkey_sign(void) +{ + unsigned char *sig = NULL; + size_t siglen; + const char *data = "Some data to sign."; + size_t len = strlen(data); + OtrlPrivKey *p = otrl_privkey_find(us, "alice", "irc"); + + p->pubkey_type = OTRL_PUBKEY_TYPE_DSA + 1; + + ok(otrl_privkey_sign(&sig, &siglen, p, + (unsigned char *) data, len) == gcry_error(GPG_ERR_INV_VALUE), + "Wrong pubkey type detected"); + free(sig); + + p->pubkey_type = OTRL_PUBKEY_TYPE_DSA; + + ok(otrl_privkey_sign(&sig, &siglen, p, + (unsigned char *) data, len) == gcry_error(GPG_ERR_NO_ERROR), + "data signed"); + free(sig); + + ok(otrl_privkey_sign(&sig, &siglen, p, (unsigned char*)data, 0) == + gcry_error(GPG_ERR_NO_ERROR), "data with len 0 signed"); + free(sig); +} + +static void test_otrl_privkey_verify(void) +{ + unsigned char *sigbuf = NULL; + size_t siglen; + const char *data = "Some data to sign."; + OtrlPrivKey *privkey = otrl_privkey_find(us, "alice", "irc"); + gcry_mpi_t p,q,g,y; + gcry_sexp_t dsas, ps, qs, gs, ys; + gcry_sexp_t pubs = NULL; + gcry_error_t ret; + + /* Extract pubkey */ + dsas = gcry_sexp_find_token(privkey->privkey, "dsa", 0); + ps = gcry_sexp_find_token(dsas, "p", 0); + qs = gcry_sexp_find_token(dsas, "q", 0); + gs = gcry_sexp_find_token(dsas, "g", 0); + ys = gcry_sexp_find_token(dsas, "y", 0); + gcry_sexp_release(dsas); + p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG); + q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG); + g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG); + y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(ps); + gcry_sexp_release(qs); + gcry_sexp_release(gs); + gcry_sexp_release(ys); + + gcry_sexp_build(&pubs, NULL, "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", + p, q, g, y); + + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(g); + gcry_mpi_release(y); + + otrl_privkey_sign(&sigbuf, &siglen, privkey, (unsigned char*)data, + strlen(data)); + + ok(otrl_privkey_verify(sigbuf, siglen, OTRL_PUBKEY_TYPE_DSA, pubs, + (unsigned char *) data, strlen(data)) == 0, "Signature ok"); + + ret = otrl_privkey_verify(sigbuf, siglen, OTRL_PUBKEY_TYPE_DSA, pubs, + (unsigned char *) data + 1, strlen(data) - 1); + ok(gcry_error(ret) == gcry_error(GPG_ERR_BAD_SIGNATURE), + "Wrong signature"); + + free(sigbuf); +} + +int main(int argc, char **argv) +{ + OtrlPrivKey *p; + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + /* Set to quick random so we don't wait on /dev/random. */ + gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); + + test_otrl_privkey_generate_FILEp(); //This must be the first one + p = otrl_privkey_find(us, "alice", "irc"); + make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey); + + test_otrl_privkey_hash_to_human(); + test_otrl_privkey_fingerprint(); + test_otrl_privkey_fingerprint_raw(); + test_otrl_privkey_sign(); + test_otrl_privkey_verify(); + test_otrl_privkey_find(); + + fclose(f); + otrl_userstate_free(us); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_proto.c b/comm/third_party/libotr/tests/unit/test_proto.c new file mode 100644 index 0000000000..5b522efc0b --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_proto.c @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include + +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 48 + +static ConnContext *new_context(const char *user, const char *accountname, + const char *protocol) +{ + ConnContext *context; + OtrlSMState *smstate; + + context = malloc(sizeof(ConnContext)); + + context->username = strdup(user); + context->accountname = strdup(accountname); + context->protocol = strdup(protocol); + + context->msgstate = OTRL_MSGSTATE_PLAINTEXT; + otrl_auth_new(context); + + smstate = malloc(sizeof(OtrlSMState)); + otrl_sm_state_new(smstate); + context->smstate = smstate; + + context->our_instance = 0; + context->their_instance = OTRL_INSTAG_MASTER; + context->fingerprint_root.fingerprint = NULL; + context->fingerprint_root.context = context; + context->fingerprint_root.next = NULL; + context->fingerprint_root.tous = NULL; + context->active_fingerprint = NULL; + memset(context->sessionid, 0, 20); + context->sessionid_len = 0; + context->protocol_version = 0; + context->otr_offer = OFFER_NOT; + context->app_data = NULL; + context->app_data_free = NULL; + context->context_priv = otrl_context_priv_new(); + context->next = NULL; + context->m_context = context; + context->recent_rcvd_child = NULL; + context->recent_sent_child = NULL; + context->recent_child = NULL; + + return context; +} + +static void test_otrl_proto_whitespace_bestversion(void) +{ + unsigned int ret; + const char *start, *end; + const char *test1 = OTRL_MESSAGE_TAG_BASE OTRL_MESSAGE_TAG_V2; + const char *test2 = OTRL_MESSAGE_TAG_BASE OTRL_MESSAGE_TAG_V3; + const char *test3 = OTRL_MESSAGE_TAG_BASE "foobar"; + + ret = otrl_proto_whitespace_bestversion(test1, &start, &end, + OTRL_POLICY_ALLOW_V2); + ok(ret == 2, "Best version whitespace v2"); + + ret = otrl_proto_whitespace_bestversion(test1, &start, &end, + OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3); + ok(ret == 2, "Best version whitespace v2 dual policy"); + + ret = otrl_proto_whitespace_bestversion(test2, &start, &end, + OTRL_POLICY_ALLOW_V3); + ok(ret == 3, "Best version whitespace v3"); + + ret = otrl_proto_whitespace_bestversion(test2, &start, &end, + OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3); + ok(ret == 3, "Best version whitespace v3 dual policy"); + + ret = otrl_proto_whitespace_bestversion(test3, &start, &end, + OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3); + ok(ret == 0, "Best version whitespace invalid"); +} + +static void test_otrl_proto_query_bestversion(void) +{ + const char *query2 = "?OTRv2?\nalice has requested an " + "Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + const char *query23 = "?OTRv23?\nalice has requested an " + "Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + const char *query3 = "?OTRv3?\nalice has requested an " + "Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + ok(otrl_proto_query_bestversion(query2, OTRL_POLICY_ALLOW_V2) == 2, + "The best from query2 is 2"); + ok(otrl_proto_query_bestversion(query3, OTRL_POLICY_ALLOW_V3) == 3, + "The best from query3 is 3"); + ok(otrl_proto_query_bestversion(query23, OTRL_POLICY_ALLOW_V2) == 2, + "The best from query23 is 2"); + ok(otrl_proto_query_bestversion(query23, OTRL_POLICY_ALLOW_V3) == 3, + "The best from query23 is 3"); +} + +static void test_otrl_proto_default_query_msg(void) +{ + const char *expected2 = "?OTRv2?\nalice has requested an " + "Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + const char *expected23 = "?OTRv23?\nalice has requested an " + "Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + const char *expected3 = "?OTRv3?\nalice has requested an " + "Off-the-Record " + "private conversation. However, you do not have a plugin " + "to support that.\nSee " + "https://otr.cypherpunks.ca/ for more information."; + + const char *msg2 = otrl_proto_default_query_msg("alice", + OTRL_POLICY_ALLOW_V2); + const char *msg23 = otrl_proto_default_query_msg("alice", + OTRL_POLICY_ALLOW_V2 | OTRL_POLICY_ALLOW_V3); + const char *msg3 = otrl_proto_default_query_msg("alice", + OTRL_POLICY_ALLOW_V3); + ok(strcmp(expected2, msg2) == 0, "OTRv2 default query message is valid"); + ok(strcmp(expected23, msg23) == 0, + "OTRv23 default query message is valid"); + ok(strcmp(expected3, msg3) == 0, "OTRv3 default query message is valid"); +} + +void test_otrl_init(void) +{ + extern unsigned int otrl_api_version; + + const unsigned int expected = rand(); + otrl_api_version = expected; + ok(otrl_init(OTRL_VERSION_MAJOR+1, 0, 0) == gcry_error(GPG_ERR_INV_VALUE), + "Too recent major version"); + ok(otrl_api_version == expected, "Api number unchanged"); + + ok(otrl_init(OTRL_VERSION_MAJOR-1, 0, 0) == gcry_error(GPG_ERR_INV_VALUE), + "Too old major version"); + ok(otrl_api_version == expected, "Api number unchanged"); + + ok(otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR+1, 0) + == gcry_error(GPG_ERR_INV_VALUE), + "Too recent minor version"); + ok(otrl_api_version = expected, "Api number unchanged"); + + ok(otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR?OTRL_VERSION_MINOR-1:0, + OTRL_VERSION_SUB) == gcry_error(GPG_ERR_NO_ERROR), + "Inferior minor version"); + ok(otrl_api_version = expected, "Api number unchanged"); + + otrl_api_version = 0; + + ok(otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB) + == gcry_error(GPG_ERR_NO_ERROR), "Exact version"); + ok(otrl_api_version == ( + (OTRL_VERSION_MAJOR << 16) | + (OTRL_VERSION_MINOR << 8) | + (OTRL_VERSION_SUB) + ), "Api version set for exact version"); +} + +static void test_otrl_proto_message_type(void) +{ + OtrlMessageType ret; + + const char *test1 = "This is plaintext"; + ret = otrl_proto_message_type(test1); + ok(ret == OTRL_MSGTYPE_NOTOTR, "Proto message type is not OTR"); + + const char *test2 = OTRL_MESSAGE_TAG_BASE "This is plaintext"; + ret = otrl_proto_message_type(test2); + ok(ret == OTRL_MSGTYPE_TAGGEDPLAINTEXT, + "Proto message type is tagged plaintext"); + + const char *test3 = "?OTR:AAIC"; + ret = otrl_proto_message_type(test3); + ok(ret == OTRL_MSGTYPE_DH_COMMIT, "Proto message type v2 is dh commit"); + + const char *test4 = "?OTR:AAMC"; + ret = otrl_proto_message_type(test4); + ok(ret == OTRL_MSGTYPE_DH_COMMIT, "Proto message type v3 is dh commit"); + + const char *test5 = "?OTR:AAIK"; + ret = otrl_proto_message_type(test5); + ok(ret == OTRL_MSGTYPE_DH_KEY, "Proto message type v2 is DH key"); + + const char *test6 = "?OTR:AAMK"; + ret = otrl_proto_message_type(test6); + ok(ret == OTRL_MSGTYPE_DH_KEY, "Proto message type v3 is DH key"); + + const char *test7 = "?OTR:AAIR"; + ret = otrl_proto_message_type(test7); + ok(ret == OTRL_MSGTYPE_REVEALSIG, "Proto message type v2 is revealsig"); + + const char *test8 = "?OTR:AAMR"; + ret = otrl_proto_message_type(test8); + ok(ret == OTRL_MSGTYPE_REVEALSIG, "Proto message type v3 is revealsig"); + + const char *test9 = "?OTR:AAIS"; + ret = otrl_proto_message_type(test9); + ok(ret == OTRL_MSGTYPE_SIGNATURE, "Proto message type v2 is a signature"); + + const char *test10 = "?OTR:AAMS"; + ret = otrl_proto_message_type(test10); + ok(ret == OTRL_MSGTYPE_SIGNATURE, "Proto message type v3 is a signature"); + + const char *test11 = "?OTR:AAID"; + ret = otrl_proto_message_type(test11); + ok(ret == OTRL_MSGTYPE_DATA, "Proto message type v2 is a data msg"); + + const char *test12 = "?OTR:AAMD"; + ret = otrl_proto_message_type(test12); + ok(ret == OTRL_MSGTYPE_DATA, "Proto message type v3 is a data msg"); + + const char *test13 = "?OTR?"; + ret = otrl_proto_message_type(test13); + ok(ret == OTRL_MSGTYPE_QUERY, "Proto message type is a query"); + + const char *test14 = "?OTR?v"; + ret = otrl_proto_message_type(test14); + ok(ret == OTRL_MSGTYPE_QUERY, "Proto message type is a query"); + + const char *test15 = "?OTR Error:"; + ret = otrl_proto_message_type(test15); + ok(ret == OTRL_MSGTYPE_ERROR, "Proto message type is an error"); + + const char *test16 = "?OTR: Please verify me"; + ret = otrl_proto_message_type(test16); + ok(ret == OTRL_MSGTYPE_UNKNOWN, "Proto message type is unknown"); + + const char *test17 = "?OTR:AAMA"; + ret = otrl_proto_message_type(test17); + ok(ret == OTRL_MSGTYPE_UNKNOWN, "Proto message type is unknown"); +} + +static void test_otrl_proto_message_version(void) +{ + int ret; + + const char *test1 = "?OTR:AAI"; + ret = otrl_proto_message_version(test1); + ok(ret == 2, "Protocol message version is 2"); + + const char *test2 = "?OTR:AAM"; + ret = otrl_proto_message_version(test2); + ok(ret == 3, "Protocol message version is 3"); + + const char *test3 = "?OTR:BLAH"; + ret = otrl_proto_message_version(test3); + ok(ret == 0, "Protocol message version is unknown"); +} + +static void test_otrl_proto_instance(void) +{ + /* Canary that shouldn't get modified on error. */ + unsigned int inst_from = 42, inst_to = 42; + gcry_error_t ret; + + /* + * Instance tags only supported in protocol v3 (AAM in b64). The msg type + * here is "A" which does not represent a valid one but we don't care + * followed by the Sender Instance set to 1 and Receiver Instance set to 2. + */ + const char *test1 = "?OTR:AAMAAAAAAQAAAAI=="; + ret = otrl_proto_instance(test1, &inst_from, &inst_to); + ok(ret == gcry_error(GPG_ERR_NO_ERROR) + && inst_from == 1 + && inst_to == 2, + "Proto instance find for v3"); + + /* Reset canary. */ + inst_from = inst_to = 42; + + /* Len is not enough here. */ + const char *test2 = "?OTR:AAMAAA="; + ret = otrl_proto_instance(test2, &inst_from, &inst_to); + ok(ret == gcry_error(GPG_ERR_INV_VALUE) + && inst_from == 42 + && inst_to == 42, "Proto instance failed for v3"); + + /* Reset canary. */ + inst_from = inst_to = 42; + + /* Message from protocol v2. */ + const char *test3 = "?OTR:AAIAAAAAAQAAAAI=="; + ret = otrl_proto_instance(test3, &inst_from, &inst_to); + ok(ret == gcry_error(GPG_ERR_INV_VALUE) + && inst_from == 42 + && inst_to == 42, "Proto instance failed for v2"); +} + +static void test_otrl_version(void) +{ + ok(strcmp(otrl_version(), OTRL_VERSION) == 0, "Otrl version OK"); +} + +static void test_otrl_proto_create_data(void) +{ + char *encmessagep = NULL, *msg = "HELO"; + unsigned char flags = 12; + unsigned char *extrakey = NULL; + OtrlTLV *tlvs = NULL; + ConnContext *context = + new_context("Alice", "Alice's account", "Secret protocol"); + + context->msgstate = OTRL_MSGSTATE_PLAINTEXT; + ok(otrl_proto_create_data(&encmessagep, context, msg, tlvs, flags, + extrakey) == gcry_error(GPG_ERR_CONFLICT), + "Conflict detected for msgstate plaintext"); + + context->msgstate = OTRL_MSGSTATE_ENCRYPTED; + context->context_priv->their_keyid = 0; + ok(otrl_proto_create_data(&encmessagep, context, msg, tlvs, flags, + extrakey) == gcry_error(GPG_ERR_CONFLICT), + "Conflict detected for msgstate encrypted"); +} + +int main(int argc, char **argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + test_otrl_proto_default_query_msg(); + test_otrl_proto_query_bestversion(); + test_otrl_init(); + test_otrl_proto_whitespace_bestversion(); + test_otrl_proto_message_type(); + test_otrl_proto_message_version(); + test_otrl_proto_instance(); + test_otrl_version(); + test_otrl_proto_create_data(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_sm.c b/comm/third_party/libotr/tests/unit/test_sm.c new file mode 100644 index 0000000000..8f4162ab1a --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_sm.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2014 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 23 + +/* Copied from sm.c */ +static const int SM_MOD_LEN_BITS = 1536; +static const char *SM_GENERATOR_S = "0x02"; +static gcry_mpi_t SM_GENERATOR = NULL; + +static const int SM_MSG1_LEN = 6; +static const int SM_MSG2_LEN = 11; +static const int SM_MSG3_LEN = 8; +static const int SM_MSG4_LEN = 3; + +/* Alice and Bob SM state for the SMP tests. */ +static OtrlSMState *astate; +static OtrlSMState *bstate; +static const char *secret = "truie"; +static unsigned char *alice_output; +static int alice_output_len; +static unsigned char *bob_output; +static int bob_output_len; + +/* Stub. */ +void otrl_sm_msg1_init(gcry_mpi_t **msg1); +void otrl_sm_msg2_init(gcry_mpi_t **msg2); +void otrl_sm_msg3_init(gcry_mpi_t **msg3); +void otrl_sm_msg4_init(gcry_mpi_t **msg4); +void otrl_sm_msg_free(gcry_mpi_t **message, int msglen); + +static OtrlSMState *alloc_sm_state(void) +{ + OtrlSMState *smst = malloc(sizeof(*smst)); + ok(smst, "SM State allocated"); + + return smst; +} + +static void test_sm_state_new(void) +{ + OtrlSMState *smst; + + smst = alloc_sm_state(); + + otrl_sm_state_new(smst); + ok(!smst->secret && + !smst->x2 && + !smst->x3 && + !smst->g1 && + !smst->g2 && + !smst->g3 && + !smst->g3o && + !smst->p && + !smst->q && + !smst->pab && + !smst->qab && + smst->nextExpected == OTRL_SMP_EXPECT1 && + smst->received_question == 0 && + smst->sm_prog_state == OTRL_SMP_PROG_OK, + "SM state new"); + + otrl_sm_state_free(smst); + free(smst); +} + +static void test_sm_state_init(void) +{ + OtrlSMState *smst; + + smst = alloc_sm_state(); + + otrl_sm_state_new(smst); + otrl_sm_state_init(smst); + ok(!gcry_mpi_cmp(smst->secret, gcry_mpi_snew(SM_MOD_LEN_BITS)) && + !smst->x2 && + !smst->x3 && + !gcry_mpi_cmp(smst->g1, gcry_mpi_copy(SM_GENERATOR)) && + !gcry_mpi_cmp(smst->g2, gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(smst->g3, gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(smst->g3o, gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(smst->p, gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(smst->q, gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(smst->pab, gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(smst->qab, gcry_mpi_new(SM_MOD_LEN_BITS)) && + smst->nextExpected == OTRL_SMP_EXPECT1 && + smst->received_question == 0 && + smst->sm_prog_state == OTRL_SMP_PROG_OK, + "SM state init"); + + otrl_sm_state_free(smst); + free(smst); +} + +static void test_sm_msg1_init(void) +{ + gcry_mpi_t *msg; + + otrl_sm_msg1_init(&msg); + ok(msg && + !gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[1] && + !gcry_mpi_cmp(msg[2], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[3], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[4] && + !gcry_mpi_cmp(msg[5], gcry_mpi_new(SM_MOD_LEN_BITS)), + "SM msg1 initialized"); + otrl_sm_msg_free(&msg, SM_MSG1_LEN); + /* Test once here. */ + ok(!msg, "SM msg1 freed"); +} + +static void test_sm_msg2_init(void) +{ + gcry_mpi_t *msg; + + otrl_sm_msg2_init(&msg); + ok(msg && + !gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[1] && + !gcry_mpi_cmp(msg[2], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[3], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[4] && + !gcry_mpi_cmp(msg[5], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[6], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[7], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[8] && + !gcry_mpi_cmp(msg[9], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[10], gcry_mpi_new(SM_MOD_LEN_BITS)), + "SM msg2 initialized"); + otrl_sm_msg_free(&msg, SM_MSG2_LEN); +} + +static void test_sm_msg3_init(void) +{ + gcry_mpi_t *msg; + + otrl_sm_msg3_init(&msg); + ok(msg && + !gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[1], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[2] && + !gcry_mpi_cmp(msg[3], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[4], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !gcry_mpi_cmp(msg[5], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[6] && + !gcry_mpi_cmp(msg[7], gcry_mpi_new(SM_MOD_LEN_BITS)), + "SM msg3 initialized"); + otrl_sm_msg_free(&msg, SM_MSG3_LEN); +} + +static void test_sm_msg4_init(void) +{ + gcry_mpi_t *msg; + + otrl_sm_msg4_init(&msg); + ok(msg && + !gcry_mpi_cmp(msg[0], gcry_mpi_new(SM_MOD_LEN_BITS)) && + !msg[1] && + !gcry_mpi_cmp(msg[2], gcry_mpi_new(SM_MOD_LEN_BITS)), + "SM msg4 initialized"); + otrl_sm_msg_free(&msg, SM_MSG4_LEN); +} + +static void test_sm_step1(void) +{ + gcry_error_t err; + unsigned char hash_secret[SM_DIGEST_SIZE]; + + astate = alloc_sm_state(); + otrl_sm_state_new(astate); + otrl_sm_state_init(astate); + + gcry_md_hash_buffer(SM_HASH_ALGORITHM, hash_secret, secret, + strlen(secret)); + + err = otrl_sm_step1(astate, hash_secret, sizeof(hash_secret), + &alice_output, &alice_output_len); + ok(err == GPG_ERR_NO_ERROR, "SMP step1 success"); + + gcry_mpi_t secret_mpi; + gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, hash_secret, + sizeof(hash_secret), NULL); + ok(!gcry_mpi_cmp(astate->secret, secret_mpi) && + astate->received_question == 0 && + astate->x2 && + astate->x3 && + astate->sm_prog_state == OTRL_SMP_PROG_OK && + alice_output && alice_output_len > 0, + "SMP step 1 validated"); + gcry_mpi_release(secret_mpi); +} + +static void test_sm_step2a(void) +{ + gcry_error_t err; + + bstate = alloc_sm_state(); + otrl_sm_state_new(bstate); + otrl_sm_state_init(bstate); + + err = otrl_sm_step2a(bstate, alice_output, alice_output_len, 1); + ok(err == GPG_ERR_NO_ERROR, "SMP step2a success"); + + ok(bstate->received_question == 1 && + bstate->sm_prog_state == OTRL_SMP_PROG_OK && + bstate->g3o && + bstate->x2 && + bstate->x3, + "SMP step2a validate"); +} + +static void test_sm_step2b(void) +{ + gcry_error_t err; + unsigned char hash_secret[SM_DIGEST_SIZE]; + + gcry_md_hash_buffer(SM_HASH_ALGORITHM, hash_secret, secret, + strlen(secret)); + + err = otrl_sm_step2b(bstate, hash_secret, sizeof(hash_secret), &bob_output, + &bob_output_len); + ok(err == GPG_ERR_NO_ERROR, "SMP step2b success"); + + /* Generate expected data. */ + gcry_mpi_t secret_mpi; + gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, hash_secret, + sizeof(hash_secret), NULL); + ok(bob_output && bob_output_len > 0 && + !gcry_mpi_cmp(bstate->secret, secret_mpi) && + bstate->p && + bstate->q, + "SMP step2b validate"); + gcry_mpi_release(secret_mpi); +} + +static void test_sm_step3(void) +{ + gcry_error_t err; + + free(alice_output); + + err = otrl_sm_step3(astate, bob_output, bob_output_len, &alice_output, + &alice_output_len); + ok(err == GPG_ERR_NO_ERROR, "SMP step3 success"); + + ok(alice_output && alice_output_len > 0 && + astate->sm_prog_state == OTRL_SMP_PROG_OK && + astate->g3o && + astate->g2 && + astate->g3 && + astate->p && + astate->q && + astate->qab && + astate->pab, + "SMP step3 validate"); +} + +static void test_sm_step4(void) +{ + gcry_error_t err; + + free(bob_output); + + err = otrl_sm_step4(bstate, alice_output, alice_output_len, &bob_output, + &bob_output_len); + ok(err == gcry_error(GPG_ERR_NO_ERROR), "SMP step4 success"); + + ok(bob_output && bob_output_len > 0 && + bstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED && + bstate->pab && + bstate->qab, + "SMP step4 validate"); +} + +static void test_sm_step5(void) +{ + gcry_error_t err; + + err = otrl_sm_step5(astate, bob_output, bob_output_len); + ok(err == gcry_error(GPG_ERR_NO_ERROR), "SMP step5 success"); + + ok(astate && astate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED, + "SMP step5 validate"); +} + +int main(int argc, char **argv) +{ + /* Libtap call for the number of tests planned. */ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + /* Initialize sm subsystem. We can't really unit test that because every + * value that is being initialized is static to sm.c. */ + otrl_sm_init(); + + /* Init variables we need for testing. */ + gcry_mpi_scan(&SM_GENERATOR, GCRYMPI_FMT_HEX, + (const unsigned char *)SM_GENERATOR_S, 0, NULL); + + test_sm_state_new(); + test_sm_state_init(); + test_sm_msg1_init(); + test_sm_msg2_init(); + test_sm_msg3_init(); + test_sm_msg4_init(); + + test_sm_step1(); + test_sm_step2a(); + test_sm_step2b(); + test_sm_step3(); + test_sm_step4(); + test_sm_step5(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_tlv.c b/comm/third_party/libotr/tests/unit/test_tlv.c new file mode 100644 index 0000000000..d05f9b8323 --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_tlv.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 11 + +static void test_otrl_tlv_new() +{ + const unsigned short type = OTRL_TLV_SMP1Q; + const char *data = "This is some test data"; + const unsigned short len = strlen(data); + + OtrlTLV* tlv = otrl_tlv_new(type, len, (unsigned char*)data); + ok(tlv->type == type && + tlv->len == len && + memcmp(tlv->data, data, len) == 0 && + tlv->data[len] == '\0' && + tlv->next == NULL, + "TLV created with success"); + otrl_tlv_free(tlv); +} + +static void test_otrl_tlv_parse() +{ + const unsigned char serialized1[] = + {'\x01', '\x02', '\x00', '\x03', '1', '2', '3'}; + const unsigned char serialized2[] = {'\x02', '\x04', '\x00', '\x00'}; + const unsigned char serialized3[] = + {'\x04', '\x02', '\x00', '\x03', '1', '2', '3', + '\x02', '\x02', '\xff', '\xff', '1', '3', '3', '7'}; + const unsigned char serialized4[] = + {'\x04', '\x02', '\x00', '\x03', '1', '2', '3', + '\x02', '\x02', '\x00', '\x04', '1', '3', '3', '7'}; + + OtrlTLV *tlv1 = otrl_tlv_parse(serialized1, sizeof(serialized1)); + OtrlTLV *tlv2 = otrl_tlv_parse(serialized2, sizeof(serialized2)); + OtrlTLV *tlv3 = otrl_tlv_parse(serialized3, sizeof(serialized3)); + OtrlTLV *tlv4 = otrl_tlv_parse(serialized4, sizeof(serialized4)); + + ok(tlv1->type == 258 && + tlv1->len == 3 && + tlv1->next == NULL && + memcmp(tlv1->data, "123", tlv1->len) == 0 && + tlv1->data[tlv1->len] == 0, + "Single-TLV chain constructed with success"); + otrl_tlv_free(tlv1); + + ok(tlv2->type == 516 && + tlv2->len == 0 && + tlv2->next == NULL, + "tlv2 chain with no data constructed with success"); + otrl_tlv_free(tlv2); + + ok(tlv3->type == 1026 && + tlv3->len == 3 && + memcmp(tlv3->data, "123", tlv3->len) == 0 && + tlv3->data[tlv3->len] == 0 && + tlv3->next == NULL, + "tlv3 chain with overflow constructed with success"); + otrl_tlv_free(tlv3); + + ok(tlv4->type == 1026 && + tlv4->len == 3 && + memcmp(tlv4->data, "123", tlv4->len) == 0 && + tlv4->data[tlv4->len] == 0 && + tlv4->next != NULL, + "First part of the 2-part tlv chain build"); + + ok(tlv4->next != NULL && + tlv4->next->type == 514 && + tlv4->next->len == 4 && + memcmp(tlv4->next->data, "1337", tlv4->next->len) == 0 && + tlv4->next->data[tlv4->next->len] == 0 && + tlv4->next->next == NULL, + "Second part of the 2-part tlv chain build"); + otrl_tlv_free(tlv4); +} + +static void test_otrl_tlv_seriallen() +{ + const unsigned char serialized[] = + {'\x04', '\x02', '\x00', '\x03', '1', '2', '3', + '\x02', '\x02', '\x00', '\x04', '1', '3', '3', '7'}; + OtrlTLV* tlv = otrl_tlv_parse(serialized, sizeof(serialized)); + ok(otrl_tlv_seriallen(tlv) == 4 + 3 + 4 + 4, + "Size correctly guessed"); + otrl_tlv_free(tlv); +} + +static void test_otrl_tlv_serialize() +{ + const unsigned char serialized[] = + {'\x04', '\x02', '\x00', '\x03', '1', '2', '3', + '\x02', '\x02', '\x00', '\x04', '1', '3', '3', '7'}; + OtrlTLV *tlv = otrl_tlv_parse(serialized, sizeof(serialized)); + unsigned char *buf = malloc(otrl_tlv_seriallen(tlv)); + otrl_tlv_serialize(buf, tlv); + ok(memcmp(serialized, buf, sizeof(serialized)) == 0, + "tlv correctly serialized"); + free(tlv); + + tlv = otrl_tlv_parse(buf, sizeof(serialized)); + otrl_tlv_serialize(buf, tlv); + ok(memcmp(serialized, buf, sizeof(serialized)) == 0, + "tlv correctly unserialized and serialized again"); + otrl_tlv_free(tlv); +} + +static void test_otrl_tlv_find() +{ + const unsigned char serialized[] = + {'\x04', '\x02', '\x00', '\x03', '1', '2', '3', + '\x02', '\x02', '\x00', '\x04', '1', '3', '3', '7', + '\x01', '\x03', '\x0', '\x01', 'A', + '\x01', '\x02', '\x0', '\x01', 'B'}; + OtrlTLV *tlv = otrl_tlv_parse(serialized, sizeof(serialized)); + OtrlTLV *result = otrl_tlv_find(tlv, (1<<8) + 3); + ok(result == tlv->next->next, "TLV found"); + + result = otrl_tlv_find(tlv, 7); + ok(result == NULL, "Unexistent TLV not found"); + + otrl_tlv_free(tlv); +} + +int main(int argc, char **argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + test_otrl_tlv_new(); + test_otrl_tlv_parse(); + test_otrl_tlv_seriallen(); + test_otrl_tlv_serialize(); + test_otrl_tlv_find(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/unit/test_userstate.c b/comm/third_party/libotr/tests/unit/test_userstate.c new file mode 100644 index 0000000000..62e996e68c --- /dev/null +++ b/comm/third_party/libotr/tests/unit/test_userstate.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 - Julien Voisin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include + +#include + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define NUM_TESTS 1 + +static void test_otrl_userstate_create() +{ + OtrlUserState us = otrl_userstate_create(); + ok(us->context_root == NULL && + us->privkey_root == NULL && + us->instag_root == NULL && + us->pending_root == NULL && + us->timer_running == 0, + "OtrlUserState ok"); + otrl_userstate_free(us); +} + +int main(int argc, char** argv) +{ + plan_tests(NUM_TESTS); + + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + OTRL_INIT; + + test_otrl_userstate_create(); + + return 0; +} diff --git a/comm/third_party/libotr/tests/utils/Makefile.am b/comm/third_party/libotr/tests/utils/Makefile.am new file mode 100644 index 0000000000..7e4ab05463 --- /dev/null +++ b/comm/third_party/libotr/tests/utils/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = tap + +EXTRA_DIST = utils.c utils.h diff --git a/comm/third_party/libotr/tests/utils/Makefile.in b/comm/third_party/libotr/tests/utils/Makefile.in new file mode 100644 index 0000000000..81a726ab0a --- /dev/null +++ b/comm/third_party/libotr/tests/utils/Makefile.in @@ -0,0 +1,608 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tests/utils +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = tap +EXTRA_DIST = utils.c utils.h +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/utils/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/utils/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/tests/utils/tap/Makefile.am b/comm/third_party/libotr/tests/utils/tap/Makefile.am new file mode 100644 index 0000000000..3650e8874c --- /dev/null +++ b/comm/third_party/libotr/tests/utils/tap/Makefile.am @@ -0,0 +1,7 @@ +AM_CFLAGS = -DHAVE_LIBPTHREAD + +noinst_LTLIBRARIES = libtap.la +libtap_la_SOURCES = tap.c tap.h +libtap_la_LIBADD = -lpthread +dist_noinst_SCRIPTS = tap.sh +EXTRA_DIST = tap.sh diff --git a/comm/third_party/libotr/tests/utils/tap/Makefile.in b/comm/third_party/libotr/tests/utils/tap/Makefile.in new file mode 100644 index 0000000000..c11385726e --- /dev/null +++ b/comm/third_party/libotr/tests/utils/tap/Makefile.in @@ -0,0 +1,581 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = tests/utils/tap +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(dist_noinst_SCRIPTS) $(top_srcdir)/config/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libtap_la_DEPENDENCIES = +am_libtap_la_OBJECTS = tap.lo +libtap_la_OBJECTS = $(am_libtap_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +SCRIPTS = $(dist_noinst_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libtap_la_SOURCES) +DIST_SOURCES = $(libtap_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = -DHAVE_LIBPTHREAD +noinst_LTLIBRARIES = libtap.la +libtap_la_SOURCES = tap.c tap.h +libtap_la_LIBADD = -lpthread +dist_noinst_SCRIPTS = tap.sh +EXTRA_DIST = tap.sh +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/utils/tap/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/utils/tap/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libtap.la: $(libtap_la_OBJECTS) $(libtap_la_DEPENDENCIES) $(EXTRA_libtap_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libtap_la_OBJECTS) $(libtap_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tap.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/tests/utils/tap/tap.c b/comm/third_party/libotr/tests/utils/tap/tap.c new file mode 100644 index 0000000000..d52cb03f16 --- /dev/null +++ b/comm/third_party/libotr/tests/utils/tap/tap.c @@ -0,0 +1,433 @@ +/*- + * Copyright (c) 2004 Nik Clayton + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "tap.h" + +static int no_plan = 0; +static int skip_all = 0; +static int have_plan = 0; +static unsigned int test_count = 0; /* Number of tests that have been run */ +static unsigned int e_tests = 0; /* Expected number of tests to run */ +static unsigned int failures = 0; /* Number of tests that failed */ +static char *todo_msg = NULL; +static char *todo_msg_fixed = "libtap malloc issue"; +static int todo = 0; +static int test_died = 0; + +/* Encapsulate the pthread code in a conditional. In the absence of + libpthread the code does nothing */ +#ifdef HAVE_LIBPTHREAD +#include +static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER; +# define LOCK pthread_mutex_lock(&M); +# define UNLOCK pthread_mutex_unlock(&M); +#else +# define LOCK +# define UNLOCK +#endif + +static void _expected_tests(unsigned int); +static void _tap_init(void); +static void _cleanup(void); + +/* + * Generate a test result. + * + * ok -- boolean, indicates whether or not the test passed. + * test_name -- the name of the test, may be NULL + * test_comment -- a comment to print afterwards, may be NULL + */ +unsigned int +_gen_result(int ok, const char *func, char *file, unsigned int line, + char *test_name, ...) +{ + va_list ap; + char *local_test_name = NULL; + char *c; + int name_is_digits; + + LOCK; + + test_count++; + + /* Start by taking the test name and performing any printf() + expansions on it */ + if(test_name != NULL) { + va_start(ap, test_name); + if (vasprintf(&local_test_name, test_name, ap) == -1) { + local_test_name = NULL; + } + va_end(ap); + + /* Make sure the test name contains more than digits + and spaces. Emit an error message and exit if it + does */ + if(local_test_name) { + name_is_digits = 1; + for(c = local_test_name; *c != '\0'; c++) { + if(!isdigit((unsigned char)*c) && !isspace((unsigned char)*c)) { + name_is_digits = 0; + break; + } + } + + if(name_is_digits) { + diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); + diag(" Very confusing."); + } + } + } + + if(!ok) { + printf("not "); + failures++; + } + + printf("ok %d", test_count); + + if(test_name != NULL) { + printf(" - "); + + /* Print the test name, escaping any '#' characters it + might contain */ + if(local_test_name != NULL) { + flockfile(stdout); + for(c = local_test_name; *c != '\0'; c++) { + if(*c == '#') + fputc('\\', stdout); + fputc((int)*c, stdout); + } + funlockfile(stdout); + } else { /* vasprintf() failed, use a fixed message */ + printf("%s", todo_msg_fixed); + } + } + + /* If we're in a todo_start() block then flag the test as being + TODO. todo_msg should contain the message to print at this + point. If it's NULL then asprintf() failed, and we should + use the fixed message. + + This is not counted as a failure, so decrement the counter if + the test failed. */ + if(todo) { + printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); + if(!ok) + failures--; + } + + printf("\n"); + + if(!ok) { + if(getenv("HARNESS_ACTIVE") != NULL) + fputs("\n", stderr); + + diag(" Failed %stest (%s:%s() at line %d)", + todo ? "(TODO) " : "", file, func, line); + } + free(local_test_name); + + UNLOCK; + + /* We only care (when testing) that ok is positive, but here we + specifically only want to return 1 or 0 */ + return ok ? 1 : 0; +} + +/* + * Initialise the TAP library. Will only do so once, however many times it's + * called. + */ +void +_tap_init(void) +{ + static int run_once = 0; + + if(!run_once) { + atexit(_cleanup); + + /* stdout needs to be unbuffered so that the output appears + in the same place relative to stderr output as it does + with Test::Harness */ + setbuf(stdout, 0); + run_once = 1; + } +} + +/* + * Note that there's no plan. + */ +int +plan_no_plan(void) +{ + + LOCK; + + _tap_init(); + + if(have_plan != 0) { + fprintf(stderr, "You tried to plan twice!\n"); + test_died = 1; + UNLOCK; + exit(255); + } + + have_plan = 1; + no_plan = 1; + + UNLOCK; + + return 1; +} + +/* + * Note that the plan is to skip all tests + */ +int +plan_skip_all(char *reason) +{ + + LOCK; + + _tap_init(); + + skip_all = 1; + + printf("1..0"); + + if(reason != NULL) + printf(" # Skip %s", reason); + + printf("\n"); + + UNLOCK; + + exit(0); +} + +/* + * Note the number of tests that will be run. + */ +int +plan_tests(unsigned int tests) +{ + + LOCK; + + _tap_init(); + + if(have_plan != 0) { + fprintf(stderr, "You tried to plan twice!\n"); + test_died = 1; + UNLOCK; + exit(255); + } + + if(tests == 0) { + fprintf(stderr, "You said to run 0 tests! You've got to run something.\n"); + test_died = 1; + UNLOCK; + exit(255); + } + + have_plan = 1; + + _expected_tests(tests); + + UNLOCK; + + return e_tests; +} + +unsigned int +diag(char *fmt, ...) +{ + va_list ap; + + fputs("# ", stderr); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputs("\n", stderr); + + return 0; +} + +void +_expected_tests(unsigned int tests) +{ + + printf("1..%d\n", tests); + e_tests = tests; +} + +int +skip(unsigned int n, char *fmt, ...) +{ + va_list ap; + char *skip_msg = NULL; + + LOCK; + + va_start(ap, fmt); + if (asprintf(&skip_msg, fmt, ap) == -1) { + skip_msg = NULL; + } + va_end(ap); + + while(n-- > 0) { + test_count++; + printf("ok %d # skip %s\n", test_count, + skip_msg != NULL ? + skip_msg : "libtap():malloc() failed"); + } + + free(skip_msg); + + UNLOCK; + + return 1; +} + +void +todo_start(char *fmt, ...) +{ + va_list ap; + + LOCK; + + va_start(ap, fmt); + if (vasprintf(&todo_msg, fmt, ap) == -1) { + todo_msg = NULL; + } + va_end(ap); + + todo = 1; + + UNLOCK; +} + +void +todo_end(void) +{ + + LOCK; + + todo = 0; + free(todo_msg); + + UNLOCK; +} + +int +exit_status(void) +{ + int r; + + LOCK; + + /* If there's no plan, just return the number of failures */ + if(no_plan || !have_plan) { + UNLOCK; + return failures; + } + + /* Ran too many tests? Return the number of tests that were run + that shouldn't have been */ + if(e_tests < test_count) { + r = test_count - e_tests; + UNLOCK; + return r; + } + + /* Return the number of tests that failed + the number of tests + that weren't run */ + r = failures + e_tests - test_count; + UNLOCK; + + return r; +} + +/* + * Cleanup at the end of the run, produce any final output that might be + * required. + */ +void +_cleanup(void) +{ + + LOCK; + + /* If plan_no_plan() wasn't called, and we don't have a plan, + and we're not skipping everything, then something happened + before we could produce any output */ + if(!no_plan && !have_plan && !skip_all) { + diag("Looks like your test died before it could output anything."); + UNLOCK; + return; + } + + if(test_died) { + diag("Looks like your test died just after %d.", test_count); + UNLOCK; + return; + } + + + /* No plan provided, but now we know how many tests were run, and can + print the header at the end */ + if(!skip_all && (no_plan || !have_plan)) { + printf("1..%d\n", test_count); + } + + if((have_plan && !no_plan) && e_tests < test_count) { + diag("Looks like you planned %d %s but ran %d extra.", + e_tests, e_tests == 1 ? "test" : "tests", test_count - e_tests); + UNLOCK; + return; + } + + if((have_plan || !no_plan) && e_tests > test_count) { + diag("Looks like you planned %d %s but only ran %d.", + e_tests, e_tests == 1 ? "test" : "tests", test_count); + UNLOCK; + return; + } + + if(failures) + diag("Looks like you failed %d %s of %d.", + failures, failures == 1 ? "test" : "tests", test_count); + + UNLOCK; +} diff --git a/comm/third_party/libotr/tests/utils/tap/tap.h b/comm/third_party/libotr/tests/utils/tap/tap.h new file mode 100644 index 0000000000..0f0594308e --- /dev/null +++ b/comm/third_party/libotr/tests/utils/tap/tap.h @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2004 Nik Clayton + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* '## __VA_ARGS__' is a gcc'ism. C99 doesn't allow the token pasting + and requires the caller to add the final comma if they've ommitted + the optional arguments */ +#ifdef __GNUC__ +# define ok(e, test, ...) ((e) ? \ + _gen_result(1, __func__, __FILE__, __LINE__, \ + test, ## __VA_ARGS__) : \ + _gen_result(0, __func__, __FILE__, __LINE__, \ + test, ## __VA_ARGS__)) + +# define ok1(e) ((e) ? \ + _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ + _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) + +# define pass(test, ...) ok(1, test, ## __VA_ARGS__); +# define fail(test, ...) ok(0, test, ## __VA_ARGS__); + +# define skip_start(test, n, fmt, ...) \ + do { \ + if((test)) { \ + skip(n, fmt, ## __VA_ARGS__); \ + continue; \ + } +#elif __STDC_VERSION__ >= 199901L /* __GNUC__ */ +# define ok(e, ...) ((e) ? \ + _gen_result(1, __func__, __FILE__, __LINE__, \ + __VA_ARGS__) : \ + _gen_result(0, __func__, __FILE__, __LINE__, \ + __VA_ARGS__)) + +# define ok1(e) ((e) ? \ + _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ + _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) + +# define pass(...) ok(1, __VA_ARGS__); +# define fail(...) ok(0, __VA_ARGS__); + +# define skip_start(test, n, ...) \ + do { \ + if((test)) { \ + skip(n, __VA_ARGS__); \ + continue; \ + } +#else /* __STDC_VERSION__ */ +# error "Needs gcc or C99 compiler for variadic macros." +#endif /* __STDC_VERSION__ */ + +#define skip_end() } while(0); + +unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...); + +int plan_no_plan(void); +int plan_skip_all(char *); +int plan_tests(unsigned int); + +unsigned int diag(char *, ...); + +int skip(unsigned int, char *, ...); + +void todo_start(char *, ...); +void todo_end(void); + +int exit_status(void); diff --git a/comm/third_party/libotr/tests/utils/tap/tap.sh b/comm/third_party/libotr/tests/utils/tap/tap.sh new file mode 100755 index 0000000000..24ac1aa250 --- /dev/null +++ b/comm/third_party/libotr/tests/utils/tap/tap.sh @@ -0,0 +1,456 @@ +#!/bin/bash +# +# Copyright 2010 Patrick LeBoutillier +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +_version='1.01' + +_plan_set=0 +_no_plan=0 +_skip_all=0 +_test_died=0 +_expected_tests=0 +_executed_tests=0 +_failed_tests=0 +TODO= + + +usage(){ + cat <<'USAGE' +tap-functions: A TAP-producing BASH library + +PLAN: + plan_no_plan + plan_skip_all [REASON] + plan_tests NB_TESTS + +TEST: + ok RESULT [NAME] + okx COMMAND + is RESULT EXPECTED [NAME] + isnt RESULT EXPECTED [NAME] + like RESULT PATTERN [NAME] + unlike RESULT PATTERN [NAME] + pass [NAME] + fail [NAME] + +SKIP: + skip [CONDITION] [REASON] [NB_TESTS=1] + + skip $feature_not_present "feature not present" 2 || { + is $a "a" + is $b "b" + } + +TODO: + Specify TODO mode by setting $TODO: + TODO="not implemented yet" + ok $result "some not implemented test" + unset TODO + +OTHER: + diag MSG + +EXAMPLE: + #!/bin/bash + + . tap-functions + + plan_tests 7 + + me=$USER + is $USER $me "I am myself" + like $HOME $me "My home is mine" + like "`id`" $me "My id matches myself" + + /bin/ls $HOME 1>&2 + ok $? "/bin/ls $HOME" + # Same thing using okx shortcut + okx /bin/ls $HOME + + [[ "`id -u`" != "0" ]] + i_am_not_root=$? + skip $i_am_not_root "Must be root" || { + okx ls /root + } + + TODO="figure out how to become root..." + okx [ "$HOME" == "/root" ] + unset TODO +USAGE + exit +} + +opt= +set_u= +while getopts ":sx" opt ; do + case $_opt in + u) set_u=1 ;; + *) usage ;; + esac +done +shift $(( OPTIND - 1 )) +# Don't allow uninitialized variables if requested +[[ -n "$set_u" ]] && set -u +unset opt set_u + +# Used to call _cleanup on shell exit +trap _exit EXIT + + +plan_no_plan(){ + (( _plan_set != 0 )) && "You tried to plan twice!" + + _plan_set=1 + _no_plan=1 + + return 0 +} + + +plan_skip_all(){ + local reason=${1:-''} + + (( _plan_set != 0 )) && _die "You tried to plan twice!" + + _print_plan 0 "Skip $reason" + + _skip_all=1 + _plan_set=1 + _exit 0 + + return 0 +} + +plan_tests(){ + local tests=${1:?} + + (( _plan_set != 0 )) && _die "You tried to plan twice!" + (( tests == 0 )) && _die "You said to run 0 tests! You've got to run something." + + _print_plan $tests + _expected_tests=$tests + _plan_set=1 + + return $tests +} + + +_print_plan(){ + local tests=${1:?} + local directive=${2:-''} + + echo -n "1..$tests" + [[ -n "$directive" ]] && echo -n " # $directive" + echo +} + + +pass(){ + local name=$1 + ok 0 "$name" +} + + +fail(){ + local name=$1 + ok 1 "$name" +} + +# This is the workhorse method that actually +# prints the tests result. +ok(){ + local result=${1:?} + local name=${2:-''} + + (( _plan_set == 0 )) && _die "You tried to run a test without a plan! Gotta have a plan." + + _executed_tests=$(( $_executed_tests + 1 )) + + if [[ -n "$name" ]] ; then + if _matches "$name" "^[0-9]+$" ; then + diag " You named your test '$name'. You shouldn't use numbers for your test names." + diag " Very confusing." + fi + fi + + if (( result != 0 )) ; then + echo -n "not " + _failed_tests=$(( _failed_tests + 1 )) + fi + echo -n "ok $_executed_tests" + + if [[ -n "$name" ]] ; then + local ename=${name//\#/\\#} + echo -n " - $ename" + fi + + if [[ -n "$TODO" ]] ; then + echo -n " # TODO $TODO" ; + if (( result != 0 )) ; then + _failed_tests=$(( _failed_tests - 1 )) + fi + fi + + echo + if (( result != 0 )) ; then + local file='tap-functions' + local func= + local line= + + local i=0 + local bt=$(caller $i) + while _matches "$bt" "tap-functions$" ; do + i=$(( $i + 1 )) + bt=$(caller $i) + done + local backtrace= + eval $(caller $i | (read line func file ; echo "backtrace=\"$file:$func() at line $line.\"")) + + local t= + [[ -n "$TODO" ]] && t="(TODO) " + + if [[ -n "$name" ]] ; then + diag " Failed ${t}test '$name'" + diag " in $backtrace" + else + diag " Failed ${t}test in $backtrace" + fi + fi + + return $result +} + + +okx(){ + local command="$@" + + local line= + diag "Output of '$command':" + "$@" | while read line ; do + diag "$line" + done + ok ${PIPESTATUS[0]} "$command" +} + + +_equals(){ + local result=${1:?} + local expected=${2:?} + + if [[ "$result" == "$expected" ]] ; then + return 0 + else + return 1 + fi +} + + +# Thanks to Aaron Kangas for the patch to allow regexp matching +# under bash < 3. + _bash_major_version=${BASH_VERSION%%.*} +_matches(){ + local result=${1:?} + local pattern=${2:?} + + if [[ -z "$result" || -z "$pattern" ]] ; then + return 1 + else + if (( _bash_major_version >= 3 )) ; then + [[ "$result" =~ "$pattern" ]] + else + echo "$result" | egrep -q "$pattern" + fi + fi +} + + +_is_diag(){ + local result=${1:?} + local expected=${2:?} + + diag " got: '$result'" + diag " expected: '$expected'" +} + + +is(){ + local result=${1:?} + local expected=${2:?} + local name=${3:-''} + + _equals "$result" "$expected" + (( $? == 0 )) + ok $? "$name" + local r=$? + (( r != 0 )) && _is_diag "$result" "$expected" + return $r +} + + +isnt(){ + local result=${1:?} + local expected=${2:?} + local name=${3:-''} + + _equals "$result" "$expected" + (( $? != 0 )) + ok $? "$name" + local r=$? + (( r != 0 )) && _is_diag "$result" "$expected" + return $r +} + + +like(){ + local result=${1:?} + local pattern=${2:?} + local name=${3:-''} + + _matches "$result" "$pattern" + (( $? == 0 )) + ok $? "$name" + local r=$? + (( r != 0 )) && diag " '$result' doesn't match '$pattern'" + return $r +} + + +unlike(){ + local result=${1:?} + local pattern=${2:?} + local name=${3:-''} + + _matches "$result" "$pattern" + (( $? != 0 )) + ok $? "$name" + local r=$? + (( r != 0 )) && diag " '$result' matches '$pattern'" + return $r +} + + +skip(){ + local condition=${1:?} + local reason=${2:-''} + local n=${3:-1} + + if (( condition == 0 )) ; then + local i= + for (( i=0 ; i<$n ; i++ )) ; do + _executed_tests=$(( _executed_tests + 1 )) + echo "ok $_executed_tests # skip: $reason" + done + return 0 + else + return + fi +} + + +diag(){ + local msg=${1:?} + + if [[ -n "$msg" ]] ; then + echo "# $msg" + fi + + return 1 +} + + +_die(){ + local reason=${1:-''} + + echo "$reason" >&2 + _test_died=1 + _exit 255 +} + + +BAIL_OUT(){ + local reason=${1:-''} + + echo "Bail out! $reason" >&2 + _exit 255 +} + + +_cleanup(){ + local rc=0 + + if (( _plan_set == 0 )) ; then + diag "Looks like your test died before it could output anything." + return $rc + fi + + if (( _test_died != 0 )) ; then + diag "Looks like your test died just after $_executed_tests." + return $rc + fi + + if (( _skip_all == 0 && _no_plan != 0 )) ; then + _print_plan $_executed_tests + fi + + local s= + if (( _no_plan == 0 && _expected_tests < _executed_tests )) ; then + s= ; (( _expected_tests > 1 )) && s=s + local extra=$(( _executed_tests - _expected_tests )) + diag "Looks like you planned $_expected_tests test$s but ran $extra extra." + rc=1 ; + fi + + if (( _no_plan == 0 && _expected_tests > _executed_tests )) ; then + s= ; (( _expected_tests > 1 )) && s=s + diag "Looks like you planned $_expected_tests test$s but only ran $_executed_tests." + fi + + if (( _failed_tests > 0 )) ; then + s= ; (( _failed_tests > 1 )) && s=s + diag "Looks like you failed $_failed_tests test$s of $_executed_tests." + fi + + return $rc +} + + +_exit_status(){ + if (( _no_plan != 0 || _plan_set == 0 )) ; then + return $_failed_tests + fi + + if (( _expected_tests < _executed_tests )) ; then + return $(( _executed_tests - _expected_tests )) + fi + + return $(( _failed_tests + ( _expected_tests - _executed_tests ))) +} + + +_exit(){ + local rc=${1:-''} + if [[ -z "$rc" ]] ; then + _exit_status + rc=$? + fi + + _cleanup + local alt_rc=$? + (( alt_rc != 0 )) && rc=$alt_rc + trap - EXIT + exit $rc +} diff --git a/comm/third_party/libotr/tests/utils/utils.c b/comm/third_party/libotr/tests/utils/utils.c new file mode 100644 index 0000000000..acc8427cfb --- /dev/null +++ b/comm/third_party/libotr/tests/utils/utils.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2014 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "utils.h" diff --git a/comm/third_party/libotr/tests/utils/utils.h b/comm/third_party/libotr/tests/utils/utils.h new file mode 100644 index 0000000000..951ce43179 --- /dev/null +++ b/comm/third_party/libotr/tests/utils/utils.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TESTS_UTILS_H +#define TESTS_UTILS_H + +/* + * Return 1 if the given buffer is zeroed or 0 if not. + */ +static inline int utils_is_zeroed(const unsigned char *buf, size_t size) +{ + return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1); +} + +#endif /* TESTS_UTILS_H */ diff --git a/comm/third_party/libotr/toolkit/Makefile.am b/comm/third_party/libotr/toolkit/Makefile.am new file mode 100644 index 0000000000..4c069fb5ce --- /dev/null +++ b/comm/third_party/libotr/toolkit/Makefile.am @@ -0,0 +1,44 @@ +AM_CPPFLAGS = -I$(includedir) -I../src @LIBGCRYPT_CFLAGS@ + +noinst_HEADERS = aes.h ctrmode.h parse.h sesskeys.h readotr.h sha1hmac.h + +bin_PROGRAMS = otr_parse otr_sesskeys otr_mackey otr_readforge \ + otr_modify otr_remac + +COMMON_S = parse.c sha1hmac.c +COMMON_LD = ../src/libotr.la @LIBS@ @LIBGCRYPT_LIBS@ + +otr_parse_SOURCES = otr_parse.c readotr.c $(COMMON_S) +otr_parse_LDADD = $(COMMON_LD) + +otr_sesskeys_SOURCES = otr_sesskeys.c sesskeys.c $(COMMON_S) +otr_sesskeys_LDADD = $(COMMON_LD) + +otr_mackey_SOURCES = otr_mackey.c sesskeys.c $(COMMON_S) +otr_mackey_LDADD = $(COMMON_LD) + +otr_readforge_SOURCES = otr_readforge.c readotr.c sesskeys.c \ + aes.c ctrmode.c $(COMMON_S) +otr_readforge_LDADD = $(COMMON_LD) + +otr_modify_SOURCES = otr_modify.c readotr.c $(COMMON_S) +otr_modify_LDADD = $(COMMON_LD) + +otr_remac_SOURCES = otr_remac.c $(COMMON_S) +otr_remac_LDADD = $(COMMON_LD) + + +man_MANS = otr_toolkit.1 +EXTRA_DIST = otr_toolkit.1 + +MANLINKS = otr_parse.1 otr_sesskeys.1 otr_mackey.1 otr_readforge.1 \ + otr_modify.1 otr_remac.1 + +install-data-local: + -mkdir -p $(DESTDIR)$(man1dir) + (cd $(DESTDIR)$(man1dir) && \ + for f in $(MANLINKS); do ln -sf otr_toolkit.1 $$f; done) + +uninstall-local: + (cd $(DESTDIR)$(man1dir) && \ + for f in $(MANLINKS); do rm -f $$f; done) diff --git a/comm/third_party/libotr/toolkit/Makefile.in b/comm/third_party/libotr/toolkit/Makefile.in new file mode 100644 index 0000000000..deca5003c1 --- /dev/null +++ b/comm/third_party/libotr/toolkit/Makefile.in @@ -0,0 +1,787 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = otr_parse$(EXEEXT) otr_sesskeys$(EXEEXT) \ + otr_mackey$(EXEEXT) otr_readforge$(EXEEXT) otr_modify$(EXEEXT) \ + otr_remac$(EXEEXT) +subdir = toolkit +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/config/depcomp $(noinst_HEADERS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \ + $(top_srcdir)/config/ltoptions.m4 \ + $(top_srcdir)/config/ltsugar.m4 \ + $(top_srcdir)/config/ltversion.m4 \ + $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +PROGRAMS = $(bin_PROGRAMS) +am__objects_1 = parse.$(OBJEXT) sha1hmac.$(OBJEXT) +am_otr_mackey_OBJECTS = otr_mackey.$(OBJEXT) sesskeys.$(OBJEXT) \ + $(am__objects_1) +otr_mackey_OBJECTS = $(am_otr_mackey_OBJECTS) +am__DEPENDENCIES_1 = ../src/libotr.la +otr_mackey_DEPENDENCIES = $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_otr_modify_OBJECTS = otr_modify.$(OBJEXT) readotr.$(OBJEXT) \ + $(am__objects_1) +otr_modify_OBJECTS = $(am_otr_modify_OBJECTS) +otr_modify_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_otr_parse_OBJECTS = otr_parse.$(OBJEXT) readotr.$(OBJEXT) \ + $(am__objects_1) +otr_parse_OBJECTS = $(am_otr_parse_OBJECTS) +otr_parse_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_otr_readforge_OBJECTS = otr_readforge.$(OBJEXT) readotr.$(OBJEXT) \ + sesskeys.$(OBJEXT) aes.$(OBJEXT) ctrmode.$(OBJEXT) \ + $(am__objects_1) +otr_readforge_OBJECTS = $(am_otr_readforge_OBJECTS) +otr_readforge_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_otr_remac_OBJECTS = otr_remac.$(OBJEXT) $(am__objects_1) +otr_remac_OBJECTS = $(am_otr_remac_OBJECTS) +otr_remac_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_otr_sesskeys_OBJECTS = otr_sesskeys.$(OBJEXT) sesskeys.$(OBJEXT) \ + $(am__objects_1) +otr_sesskeys_OBJECTS = $(am_otr_sesskeys_OBJECTS) +otr_sesskeys_DEPENDENCIES = $(am__DEPENDENCIES_1) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(otr_mackey_SOURCES) $(otr_modify_SOURCES) \ + $(otr_parse_SOURCES) $(otr_readforge_SOURCES) \ + $(otr_remac_SOURCES) $(otr_sesskeys_SOURCES) +DIST_SOURCES = $(otr_mackey_SOURCES) $(otr_modify_SOURCES) \ + $(otr_parse_SOURCES) $(otr_readforge_SOURCES) \ + $(otr_remac_SOURCES) $(otr_sesskeys_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(man_MANS) +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = -I$(includedir) -I../src @LIBGCRYPT_CFLAGS@ +noinst_HEADERS = aes.h ctrmode.h parse.h sesskeys.h readotr.h sha1hmac.h +COMMON_S = parse.c sha1hmac.c +COMMON_LD = ../src/libotr.la @LIBS@ @LIBGCRYPT_LIBS@ +otr_parse_SOURCES = otr_parse.c readotr.c $(COMMON_S) +otr_parse_LDADD = $(COMMON_LD) +otr_sesskeys_SOURCES = otr_sesskeys.c sesskeys.c $(COMMON_S) +otr_sesskeys_LDADD = $(COMMON_LD) +otr_mackey_SOURCES = otr_mackey.c sesskeys.c $(COMMON_S) +otr_mackey_LDADD = $(COMMON_LD) +otr_readforge_SOURCES = otr_readforge.c readotr.c sesskeys.c \ + aes.c ctrmode.c $(COMMON_S) + +otr_readforge_LDADD = $(COMMON_LD) +otr_modify_SOURCES = otr_modify.c readotr.c $(COMMON_S) +otr_modify_LDADD = $(COMMON_LD) +otr_remac_SOURCES = otr_remac.c $(COMMON_S) +otr_remac_LDADD = $(COMMON_LD) +man_MANS = otr_toolkit.1 +EXTRA_DIST = otr_toolkit.1 +MANLINKS = otr_parse.1 otr_sesskeys.1 otr_mackey.1 otr_readforge.1 \ + otr_modify.1 otr_remac.1 + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu toolkit/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu toolkit/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +otr_mackey$(EXEEXT): $(otr_mackey_OBJECTS) $(otr_mackey_DEPENDENCIES) $(EXTRA_otr_mackey_DEPENDENCIES) + @rm -f otr_mackey$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(otr_mackey_OBJECTS) $(otr_mackey_LDADD) $(LIBS) + +otr_modify$(EXEEXT): $(otr_modify_OBJECTS) $(otr_modify_DEPENDENCIES) $(EXTRA_otr_modify_DEPENDENCIES) + @rm -f otr_modify$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(otr_modify_OBJECTS) $(otr_modify_LDADD) $(LIBS) + +otr_parse$(EXEEXT): $(otr_parse_OBJECTS) $(otr_parse_DEPENDENCIES) $(EXTRA_otr_parse_DEPENDENCIES) + @rm -f otr_parse$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(otr_parse_OBJECTS) $(otr_parse_LDADD) $(LIBS) + +otr_readforge$(EXEEXT): $(otr_readforge_OBJECTS) $(otr_readforge_DEPENDENCIES) $(EXTRA_otr_readforge_DEPENDENCIES) + @rm -f otr_readforge$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(otr_readforge_OBJECTS) $(otr_readforge_LDADD) $(LIBS) + +otr_remac$(EXEEXT): $(otr_remac_OBJECTS) $(otr_remac_DEPENDENCIES) $(EXTRA_otr_remac_DEPENDENCIES) + @rm -f otr_remac$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(otr_remac_OBJECTS) $(otr_remac_LDADD) $(LIBS) + +otr_sesskeys$(EXEEXT): $(otr_sesskeys_OBJECTS) $(otr_sesskeys_DEPENDENCIES) $(EXTRA_otr_sesskeys_DEPENDENCIES) + @rm -f otr_sesskeys$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(otr_sesskeys_OBJECTS) $(otr_sesskeys_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctrmode.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otr_mackey.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otr_modify.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otr_parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otr_readforge.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otr_remac.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otr_sesskeys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readotr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sesskeys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1hmac.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-local uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ + ctags ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-data-local install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-man1 install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-local \ + uninstall-man uninstall-man1 + + +install-data-local: + -mkdir -p $(DESTDIR)$(man1dir) + (cd $(DESTDIR)$(man1dir) && \ + for f in $(MANLINKS); do ln -sf otr_toolkit.1 $$f; done) + +uninstall-local: + (cd $(DESTDIR)$(man1dir) && \ + for f in $(MANLINKS); do rm -f $$f; done) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libotr/toolkit/aes.c b/comm/third_party/libotr/toolkit/aes.c new file mode 100644 index 0000000000..1dff0ef89c --- /dev/null +++ b/comm/third_party/libotr/toolkit/aes.c @@ -0,0 +1,866 @@ +/* Retrieved from http://www.cr0.net:8040/code/crypto/aes/aes.c */ + +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2001-2004 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "aes.h" + +/* uncomment the following line to run the test suite */ + +/* #define TEST */ + +/* uncomment the following line to use pre-computed tables */ +/* otherwise the tables will be generated at the first run */ + +/* #define FIXED_TABLES */ + +#ifndef FIXED_TABLES + +/* forward S-box & tables */ + +uint32 FSb[256]; +uint32 FT0[256]; +uint32 FT1[256]; +uint32 FT2[256]; +uint32 FT3[256]; + +/* reverse S-box & tables */ + +uint32 RSb[256]; +uint32 RT0[256]; +uint32 RT1[256]; +uint32 RT2[256]; +uint32 RT3[256]; + +/* round constants */ + +uint32 RCON[10]; + +/* tables generation flag */ + +int do_init = 1; + +/* tables generation routine */ + +#define ROTR8(x) ( ( ( x << 24 ) & 0xFFFFFFFF ) | \ + ( ( x & 0xFFFFFFFF ) >> 8 ) ) + +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x] + log[y]) % 255] : 0 ) + +void aes_gen_tables( void ) +{ + int i; + uint8 x, y; + uint8 pow[256]; + uint8 log[256]; + + /* compute pow and log tables over GF(2^8) */ + + for( i = 0, x = 1; i < 256; i++, x ^= XTIME( x ) ) + { + pow[i] = x; + log[x] = i; + } + + /* calculate the round constants */ + + for( i = 0, x = 1; i < 10; i++, x = XTIME( x ) ) + { + RCON[i] = (uint32) x << 24; + } + + /* generate the forward and reverse S-boxes */ + + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( y << 1 ) | ( y >> 7 ); + x ^= y; y = ( y << 1 ) | ( y >> 7 ); + x ^= y; y = ( y << 1 ) | ( y >> 7 ); + x ^= y; y = ( y << 1 ) | ( y >> 7 ); + x ^= y ^ 0x63; + + FSb[i] = x; + RSb[x] = i; + } + + /* generate the forward and reverse tables */ + + for( i = 0; i < 256; i++ ) + { + x = (unsigned char) FSb[i]; y = XTIME( x ); + + FT0[i] = (uint32) ( x ^ y ) ^ + ( (uint32) x << 8 ) ^ + ( (uint32) x << 16 ) ^ + ( (uint32) y << 24 ); + + FT0[i] &= 0xFFFFFFFF; + + FT1[i] = ROTR8( FT0[i] ); + FT2[i] = ROTR8( FT1[i] ); + FT3[i] = ROTR8( FT2[i] ); + + y = (unsigned char) RSb[i]; + + RT0[i] = ( (uint32) MUL( 0x0B, y ) ) ^ + ( (uint32) MUL( 0x0D, y ) << 8 ) ^ + ( (uint32) MUL( 0x09, y ) << 16 ) ^ + ( (uint32) MUL( 0x0E, y ) << 24 ); + + RT0[i] &= 0xFFFFFFFF; + + RT1[i] = ROTR8( RT0[i] ); + RT2[i] = ROTR8( RT1[i] ); + RT3[i] = ROTR8( RT2[i] ); + } +} + +#else + +/* forward S-box */ + +static const uint32 FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* forward tables */ + +#define FT \ +\ + V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ + V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ + V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ + V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ + V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ + V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ + V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ + V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ + V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ + V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ + V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ + V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ + V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ + V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ + V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ + V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ + V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ + V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ + V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ + V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ + V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ + V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ + V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ + V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ + V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ + V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ + V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ + V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ + V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ + V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ + V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ + V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ + V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ + V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ + V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ + V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ + V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ + V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ + V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ + V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ + V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ + V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ + V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ + V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ + V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ + V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ + V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ + V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ + V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ + V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ + V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ + V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ + V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ + V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ + V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ + V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ + V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ + V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ + V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ + V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ + V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ + V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ + V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ + V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32 FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32 FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32 FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32 FT3[256] = { FT }; +#undef V + +#undef FT + +/* reverse S-box */ + +static const uint32 RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* reverse tables */ + +#define RT \ +\ + V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ + V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ + V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ + V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ + V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ + V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ + V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ + V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ + V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ + V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ + V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ + V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ + V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ + V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ + V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ + V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ + V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ + V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ + V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ + V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ + V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ + V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ + V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ + V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ + V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ + V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ + V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ + V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ + V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ + V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ + V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ + V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ + V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ + V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ + V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ + V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ + V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ + V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ + V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ + V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ + V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ + V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ + V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ + V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ + V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ + V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ + V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ + V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ + V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ + V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ + V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ + V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ + V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ + V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ + V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ + V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ + V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ + V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ + V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ + V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ + V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ + V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ + V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ + V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32 RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32 RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32 RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32 RT3[256] = { RT }; +#undef V + +#undef RT + +/* round constants */ + +static const uint32 RCON[10] = +{ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000 +}; + +int do_init = 0; + +void aes_gen_tables( void ) +{ +} + +#endif + +/* platform-independant 32-bit integer manipulation macros */ + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32) (b)[(i) ] << 24 ) \ + | ( (uint32) (b)[(i) + 1] << 16 ) \ + | ( (uint32) (b)[(i) + 2] << 8 ) \ + | ( (uint32) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8) ( (n) >> 24 ); \ + (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ + (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ + (b)[(i) + 3] = (uint8) ( (n) ); \ +} + +/* decryption key schedule tables */ + +int KT_init = 1; + +uint32 KT0[256]; +uint32 KT1[256]; +uint32 KT2[256]; +uint32 KT3[256]; + +/* AES key scheduling routine */ + +int aes_set_key( aes_context *ctx, uint8 *key, int nbits ) +{ + int i; + uint32 *RK, *SK; + + if( do_init ) + { + aes_gen_tables(); + + do_init = 0; + } + + switch( nbits ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( 1 ); + } + + RK = ctx->erk; + + for( i = 0; i < (nbits >> 5); i++ ) + { + GET_UINT32( RK[i], key, i * 4 ); + } + + /* setup encryption round keys */ + + switch( nbits ) + { + case 128: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 192: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 256: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( RK[11] ) ] ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + /* setup decryption round keys */ + + if( KT_init ) + { + for( i = 0; i < 256; i++ ) + { + KT0[i] = RT0[ FSb[i] ]; + KT1[i] = RT1[ FSb[i] ]; + KT2[i] = RT2[ FSb[i] ]; + KT3[i] = RT3[ FSb[i] ]; + } + + KT_init = 0; + } + + SK = ctx->drk; + + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + + for( i = 1; i < ctx->nr; i++ ) + { + RK -= 8; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + + *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ + KT1[ (uint8) ( *RK >> 16 ) ] ^ + KT2[ (uint8) ( *RK >> 8 ) ] ^ + KT3[ (uint8) ( *RK ) ]; RK++; + } + + RK -= 8; + + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + + return( 0 ); +} + +/* AES 128-bit block encryption routine */ + +void aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->erk; + + GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; + GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; + GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; + GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + RK += 4; \ + \ + X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y3 ) ]; \ + \ + X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y0 ) ]; \ + \ + X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y1 ) ]; \ + \ + X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y2 ) ]; \ +} + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ + + if( ctx->nr > 10 ) + { + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ + } + + if( ctx->nr > 12 ) + { + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y3 ) ] ); + + X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y0 ) ] ); + + X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y1 ) ] ); + + X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ + ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ + ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ + ( FSb[ (uint8) ( Y2 ) ] ); + + PUT_UINT32( X0, output, 0 ); + PUT_UINT32( X1, output, 4 ); + PUT_UINT32( X2, output, 8 ); + PUT_UINT32( X3, output, 12 ); +} + +/* AES 128-bit block decryption routine */ + +void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->drk; + + GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; + GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; + GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; + GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + RK += 4; \ + \ + X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y1 ) ]; \ + \ + X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y2 ) ]; \ + \ + X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y3 ) ]; \ + \ + X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y0 ) ]; \ +} + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ + + if( ctx->nr > 10 ) + { + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ + } + + if( ctx->nr > 12 ) + { + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y1 ) ] ); + + X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y2 ) ] ); + + X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y3 ) ] ); + + X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ + ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ + ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ + ( RSb[ (uint8) ( Y0 ) ] ); + + PUT_UINT32( X0, output, 0 ); + PUT_UINT32( X1, output, 4 ); + PUT_UINT32( X2, output, 8 ); + PUT_UINT32( X3, output, 12 ); +} + +#ifdef TEST + +#include +#include + +/* + * Rijndael Monte Carlo Test: ECB mode + * source: NIST - rijndael-vals.zip + */ + +static unsigned char AES_enc_test[3][16] = +{ + { 0xA0, 0x43, 0x77, 0xAB, 0xE2, 0x59, 0xB0, 0xD0, + 0xB5, 0xBA, 0x2D, 0x40, 0xA5, 0x01, 0x97, 0x1B }, + { 0x4E, 0x46, 0xF8, 0xC5, 0x09, 0x2B, 0x29, 0xE2, + 0x9A, 0x97, 0x1A, 0x0C, 0xD1, 0xF6, 0x10, 0xFB }, + { 0x1F, 0x67, 0x63, 0xDF, 0x80, 0x7A, 0x7E, 0x70, + 0x96, 0x0D, 0x4C, 0xD3, 0x11, 0x8E, 0x60, 0x1A } +}; + +static unsigned char AES_dec_test[3][16] = +{ + { 0xF5, 0xBF, 0x8B, 0x37, 0x13, 0x6F, 0x2E, 0x1F, + 0x6B, 0xEC, 0x6F, 0x57, 0x20, 0x21, 0xE3, 0xBA }, + { 0xF1, 0xA8, 0x1B, 0x68, 0xF6, 0xE5, 0xA6, 0x27, + 0x1A, 0x8C, 0xB2, 0x4E, 0x7D, 0x94, 0x91, 0xEF }, + { 0x4D, 0xE0, 0xC6, 0xDF, 0x7C, 0xB1, 0x69, 0x72, + 0x84, 0x60, 0x4D, 0x60, 0x27, 0x1B, 0xC5, 0x9A } +}; + +int main( void ) +{ + int m, n, i, j; + aes_context ctx; + unsigned char buf[16]; + unsigned char key[32]; + + for( m = 0; m < 2; m++ ) + { + printf( "\n Rijndael Monte Carlo Test (ECB mode) - " ); + + if( m == 0 ) printf( "encryption\n\n" ); + if( m == 1 ) printf( "decryption\n\n" ); + + for( n = 0; n < 3; n++ ) + { + printf( " Test %d, key size = %3d bits: ", + n + 1, 128 + n * 64 ); + + fflush( stdout ); + + memset( buf, 0, 16 ); + memset( key, 0, 16 + n * 8 ); + + for( i = 0; i < 400; i++ ) + { + aes_set_key( &ctx, key, 128 + n * 64 ); + + for( j = 0; j < 9999; j++ ) + { + if( m == 0 ) aes_encrypt( &ctx, buf, buf ); + if( m == 1 ) aes_decrypt( &ctx, buf, buf ); + } + + if( n > 0 ) + { + for( j = 0; j < (n << 3); j++ ) + { + key[j] ^= buf[j + 16 - (n << 3)]; + } + } + + if( m == 0 ) aes_encrypt( &ctx, buf, buf ); + if( m == 1 ) aes_decrypt( &ctx, buf, buf ); + + for( j = 0; j < 16; j++ ) + { + key[j + (n << 3)] ^= buf[j]; + } + } + + if( ( m == 0 && memcmp( buf, AES_enc_test[n], 16 ) != 0 ) || + ( m == 1 && memcmp( buf, AES_dec_test[n], 16 ) != 0 ) ) + { + printf( "failed!\n" ); + return( 1 ); + } + + printf( "passed.\n" ); + } + } + + printf( "\n" ); + + return( 0 ); +} + +#endif + diff --git a/comm/third_party/libotr/toolkit/aes.h b/comm/third_party/libotr/toolkit/aes.h new file mode 100644 index 0000000000..67bd4237a2 --- /dev/null +++ b/comm/third_party/libotr/toolkit/aes.h @@ -0,0 +1,26 @@ +/* Retrieved from http://www.cr0.net:8040/code/crypto/aes/aes.h */ + +#ifndef _AES_H +#define _AES_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +typedef struct +{ + uint32 erk[64]; /* encryption round keys */ + uint32 drk[64]; /* decryption round keys */ + int nr; /* number of rounds */ +} +aes_context; + +int aes_set_key( aes_context *ctx, uint8 *key, int nbits ); +void aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); +void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); + +#endif /* aes.h */ diff --git a/comm/third_party/libotr/toolkit/ctrmode.c b/comm/third_party/libotr/toolkit/ctrmode.c new file mode 100644 index 0000000000..987f29c20f --- /dev/null +++ b/comm/third_party/libotr/toolkit/ctrmode.c @@ -0,0 +1,60 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* toolkit headers */ +#include "aes.h" + +/* Encrypt or decrypt data in AES-CTR mode. (The operations are the + * same.) We roll our own here just to double-check that the calls + * libotr makes to libgcrypt are doing the right thing. */ +void aes_ctr_crypt(unsigned char *out, const unsigned char *in, size_t len, + unsigned char key[16], unsigned char ctrtop[8]) +{ + unsigned char ctr[16], encctr[16]; + aes_context aesc; + + aes_set_key(&aesc, key, 128); + + memmove(ctr, ctrtop, 8); + memset(ctr+8, 0, 8); + + while(len > 0) { + /* How much to do at a time? */ + size_t i; + size_t amt = len; + if (amt > 16) amt = 16; + aes_encrypt(&aesc, ctr, encctr); + for(i=0;i0;--i) { + if (++ctr[i-1] != 0) break; + } + + out += amt; + in += amt; + len -= amt; + } +} diff --git a/comm/third_party/libotr/toolkit/ctrmode.h b/comm/third_party/libotr/toolkit/ctrmode.h new file mode 100644 index 0000000000..6ef648fd5a --- /dev/null +++ b/comm/third_party/libotr/toolkit/ctrmode.h @@ -0,0 +1,29 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __CTRMODE_H__ +#define __CTRMODE_H__ + +/* Encrypt or decrypt data in AES-CTR mode. (The operations are the + * same.) We roll our own here just to double-check that the calls + * libotr makes to libgcrypt are doing the right thing. */ +void aes_ctr_crypt(unsigned char *out, const unsigned char *in, size_t len, + unsigned char key[16], unsigned char ctrtop[8]); + +#endif diff --git a/comm/third_party/libotr/toolkit/otr_mackey.c b/comm/third_party/libotr/toolkit/otr_mackey.c new file mode 100644 index 0000000000..cf2b4eb6e1 --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_mackey.c @@ -0,0 +1,65 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* toolkit headers */ +#include "parse.h" +#include "sesskeys.h" + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s aeskey\n" +"Calculate and display the MAC key derived from a given AES key.\n", + progname); + exit(1); +} + +int main(int argc, char **argv) +{ + unsigned char *argbuf; + size_t argbuflen; + unsigned char mackey[20]; + + if (argc != 2) { + usage(argv[0]); + } + + argv_to_buf(&argbuf, &argbuflen, argv[1]); + /* AES keys are 128 bits long, so check for that */ + if (!argbuf) { + usage(argv[0]); + } + + if (argbuflen != 16) { + fprintf(stderr, "The AES key must be 32 hex chars long.\n"); + usage(argv[0]); + } + + sesskeys_make_mac(mackey, argbuf); + + dump_data(stdout, "AES key", argbuf, 16); + dump_data(stdout, "MAC key", mackey, 20); + + free(argbuf); + fflush(stdout); + return 0; +} diff --git a/comm/third_party/libotr/toolkit/otr_modify.c b/comm/third_party/libotr/toolkit/otr_modify.c new file mode 100644 index 0000000000..8257b511e1 --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_modify.c @@ -0,0 +1,126 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libotr headers */ +#include "proto.h" + +/* toolkit headers */ +#include "readotr.h" +#include "parse.h" +#include "sha1hmac.h" + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s mackey old_text new_text offset\n" +"Read an OTR Data Message from stdin. Even if we can't read the\n" +"data because we don't know either the AES key or the DH privkey,\n" +"but we can make a good guess that the substring \"old_text\"\n" +"appears at the given offset in the message, replace the old_text\n" +"with the new_text (which must be of the same length), recalculate\n" +"the MAC with the given mackey, and output the resulting Data message.\n", + progname); + exit(1); +} + +int main(int argc, char **argv) +{ + unsigned char *mackey; + size_t mackeylen; + unsigned char macval[20]; + char *otrmsg = NULL; + DataMsg datamsg; + size_t textlen; + unsigned int offset; + const unsigned char *old_text, *new_text; + char *newdatamsg; + size_t i; + + if (argc != 5) { + usage(argv[0]); + } + + argv_to_buf(&mackey, &mackeylen, argv[1]); + if (!mackey) { + usage(argv[0]); + } + + if (mackeylen != 20) { + fprintf(stderr, "The MAC key must be 40 hex chars long.\n"); + usage(argv[0]); + } + + textlen = strlen(argv[2]); + if (textlen != strlen(argv[3])) { + fprintf(stderr, "The old_text and new_text must be of the same " + "length.\n"); + usage(argv[0]); + } + old_text = (const unsigned char *)argv[2]; + new_text = (const unsigned char *)argv[3]; + + if (sscanf(argv[4], "%u", &offset) != 1) { + fprintf(stderr, "Unparseable offset given.\n"); + usage(argv[0]); + } + + otrmsg = readotr(stdin); + if (otrmsg == NULL) { + fprintf(stderr, "No OTR Data Message found on stdin.\n"); + exit(1); + } + + if (otrl_proto_message_type(otrmsg) != OTRL_MSGTYPE_DATA) { + fprintf(stderr, "OTR Non-Data Message found on stdin.\n"); + exit(1); + } + + datamsg = parse_datamsg(otrmsg); + free(otrmsg); + if (datamsg == NULL) { + fprintf(stderr, "Invalid OTR Data Message found on stdin.\n"); + exit(1); + } + + /* Check the MAC */ + sha1hmac(macval, mackey, datamsg->macstart, + datamsg->macend - datamsg->macstart); + if (memcmp(macval, datamsg->mac, 20)) { + fprintf(stderr, "MAC does not verify: wrong MAC key?\n"); + exit(1); + } + + /* Modify the ciphertext */ + for(i=0; iencmsglen; ++i) { + datamsg->encmsg[offset+i] ^= (old_text[i] ^ new_text[i]); + } + + /* Recalculate the MAC */ + newdatamsg = remac_datamsg(datamsg, mackey); + printf("%s\n", newdatamsg); + free(newdatamsg); + + free_datamsg(datamsg); + free(mackey); + fflush(stdout); + return 0; +} diff --git a/comm/third_party/libotr/toolkit/otr_parse.c b/comm/third_party/libotr/toolkit/otr_parse.c new file mode 100644 index 0000000000..e791835413 --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_parse.c @@ -0,0 +1,224 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libotr headers */ +#include "proto.h" + +/* toolkit headers */ +#include "readotr.h" +#include "parse.h" + +static void parse(const char *msg) +{ + OtrlMessageType mtype = otrl_proto_message_type(msg); + CommitMsg cmsg; + KeyMsg kmsg; + RevealSigMsg rmsg; + SignatureMsg smsg; + KeyExchMsg keyexch; + DataMsg datamsg; + + switch(mtype) { + case OTRL_MSGTYPE_QUERY: + printf("OTR Query:\n\t%s\n\n", msg); + break; + case OTRL_MSGTYPE_DH_COMMIT: + cmsg = parse_commit(msg); + if (!cmsg) { + printf("Invalid D-H Commit Message\n\n"); + break; + } + + printf("D-H Commit Message:\n"); + + dump_data(stdout, "\tVersion", &(cmsg->version), 1); + if (cmsg->version == 3) { + dump_int(stdout, "\tSender instance", cmsg->sender_instance); + dump_int(stdout, "\tReceiver instance", + cmsg->receiver_instance); + } + dump_data(stdout, "\tEncrypted Key", cmsg->enckey, + cmsg->enckeylen); + dump_data(stdout, "\tHashed Key", cmsg->hashkey, + cmsg->hashkeylen); + printf("\n"); + free_commit(cmsg); + break; + case OTRL_MSGTYPE_DH_KEY: + kmsg = parse_key(msg); + if (!kmsg) { + printf("Invalid D-H Key Message\n\n"); + break; + } + printf("D-H Key Message:\n"); + dump_data(stdout, "\tVersion", &(kmsg->version), 1); + if (kmsg->version == 3) { + dump_int(stdout, "\tSender instance", kmsg->sender_instance); + dump_int(stdout, "\tReceiver instance", + kmsg->receiver_instance); + } + dump_mpi(stdout, "\tD-H Key", kmsg->y); + printf("\n"); + free_key(kmsg); + break; + case OTRL_MSGTYPE_REVEALSIG: + rmsg = parse_revealsig(msg); + if (!rmsg) { + printf("Invalid Reveal Signature Message\n\n"); + break; + } + printf("Reveal Signature Message:\n"); + dump_data(stdout, "\tVersion", &(rmsg->version), 1); + if (rmsg->version == 3) { + dump_int(stdout, "\tSender instance", rmsg->sender_instance); + dump_int(stdout, "\tReceiver instance", + rmsg->receiver_instance); + } + dump_data(stdout, "\tKey", rmsg->key, rmsg->keylen); + dump_data(stdout, "\tEncrypted Signature", + rmsg->encsig, rmsg->encsiglen); + dump_data(stdout, "\tMAC", rmsg->mac, 20); + printf("\n"); + free_revealsig(rmsg); + break; + case OTRL_MSGTYPE_SIGNATURE: + smsg = parse_signature(msg); + if (!smsg) { + printf("Invalid Signature Message\n\n"); + break; + } + printf("Signature Message:\n"); + dump_data(stdout, "\tVersion", &(smsg->version), 1); + if (smsg->version == 3) { + dump_int(stdout, "\tSender instance", smsg->sender_instance); + dump_int(stdout, "\tReceiver instance", + smsg->receiver_instance); + } + dump_data(stdout, "\tEncrypted Signature", + smsg->encsig, smsg->encsiglen); + dump_data(stdout, "\tMAC", smsg->mac, 20); + printf("\n"); + free_signature(smsg); + break; + case OTRL_MSGTYPE_V1_KEYEXCH: + keyexch = parse_keyexch(msg); + if (!keyexch) { + printf("Invalid Key Exchange Message\n\n"); + break; + } + printf("Key Exchange Message:\n"); + dump_int(stdout, "\tReply", keyexch->reply); + dump_mpi(stdout, "\tDSA p", keyexch->p); + dump_mpi(stdout, "\tDSA q", keyexch->q); + dump_mpi(stdout, "\tDSA g", keyexch->g); + dump_mpi(stdout, "\tDSA e", keyexch->e); + dump_int(stdout, "\tKeyID", keyexch->keyid); + dump_mpi(stdout, "\tDH y", keyexch->y); + dump_mpi(stdout, "\tSIG r", keyexch->r); + dump_mpi(stdout, "\tSIG s", keyexch->s); + printf("\n"); + free_keyexch(keyexch); + break; + case OTRL_MSGTYPE_DATA: + datamsg = parse_datamsg(msg); + if (!datamsg) { + printf("Invalid Data Message\n\n"); + break; + } + printf("Data Message:\n"); + + dump_data(stdout, "\tVersion", &(datamsg->version), 1); + if (datamsg->flags >= 0) { + dump_int(stdout, "\tFlags", datamsg->flags); + } + + if (datamsg->version == 3) { + dump_int(stdout, "\tSender instance", datamsg->sender_instance); + dump_int(stdout, "\tReceiver instance", + datamsg->receiver_instance); + } + + dump_int(stdout, "\tSender keyid", datamsg->sender_keyid); + dump_int(stdout, "\tRcpt keyid", datamsg->rcpt_keyid); + dump_mpi(stdout, "\tDH y", datamsg->y); + dump_data(stdout, "\tCounter", datamsg->ctr, 8); + dump_data(stdout, "\tEncrypted message", datamsg->encmsg, + datamsg->encmsglen); + dump_data(stdout, "\tMAC", datamsg->mac, 20); + if (datamsg->mackeyslen > 0) { + size_t len = datamsg->mackeyslen; + unsigned char *mks = datamsg->mackeys; + unsigned int i = 0; + printf("\tRevealed MAC keys:\n"); + + while(len > 19) { + char title[20]; + sprintf(title, "\t\tKey %u", ++i); + dump_data(stdout, title, mks, 20); + mks += 20; len -= 20; + } + } + + printf("\n"); + free_datamsg(datamsg); + break; + case OTRL_MSGTYPE_ERROR: + printf("OTR Error:\n\t%s\n\n", msg); + break; + case OTRL_MSGTYPE_TAGGEDPLAINTEXT: + printf("Tagged plaintext message:\n\t%s\n\n", msg); + break; + case OTRL_MSGTYPE_NOTOTR: + printf("Not an OTR message:\n\t%s\n\n", msg); + break; + case OTRL_MSGTYPE_UNKNOWN: + printf("Unrecognized OTR message:\n\t%s\n\n", msg); + break; + } + fflush(stdout); +} + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s\n" +"Read Off-the-Record (OTR) Key Exchange and/or Data messages from stdin\n" +"and display their contents in a more readable format.\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + char *otrmsg = NULL; + + if (argc != 1) { + usage(argv[0]); + } + + while ((otrmsg = readotr(stdin)) != NULL) { + parse(otrmsg); + free(otrmsg); + } + + return 0; +} diff --git a/comm/third_party/libotr/toolkit/otr_readforge.c b/comm/third_party/libotr/toolkit/otr_readforge.c new file mode 100644 index 0000000000..733f2212fb --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_readforge.c @@ -0,0 +1,133 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libotr headers */ +#include "proto.h" + +/* toolkit headers */ +#include "readotr.h" +#include "parse.h" +#include "sesskeys.h" +#include "sha1hmac.h" +#include "ctrmode.h" + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s aeskey [new_message]\n" +"Read an OTR Data Message from stdin. Use the given AES key to\n" +"verify its MAC and decrypt the message to stdout. If new_message\n" +"is given, output a new OTR Data Message with the same fields as the\n" +"original, but with the message replaced by new_message\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + unsigned char *aeskey; + unsigned char mackey[20]; + unsigned char macval[20]; + size_t aeskeylen; + unsigned char *plaintext, *ciphertext; + char *otrmsg = NULL; + DataMsg datamsg; + + if (argc != 2 && argc != 3) { + usage(argv[0]); + } + + argv_to_buf(&aeskey, &aeskeylen, argv[1]); + if (!aeskey) { + usage(argv[0]); + } + + if (aeskeylen != 16) { + fprintf(stderr, "The AES key must be 32 hex chars long.\n"); + usage(argv[0]); + } + + otrmsg = readotr(stdin); + if (otrmsg == NULL) { + fprintf(stderr, "No OTR Data Message found on stdin.\n"); + exit(1); + } + + if (otrl_proto_message_type(otrmsg) != OTRL_MSGTYPE_DATA) { + fprintf(stderr, "OTR Non-Data Message found on stdin.\n"); + exit(1); + } + + datamsg = parse_datamsg(otrmsg); + free(otrmsg); + if (datamsg == NULL) { + fprintf(stderr, "Invalid OTR Data Message found on stdin.\n"); + exit(1); + } + + /* Create the MAC key */ + sesskeys_make_mac(mackey, aeskey); + + /* Check the MAC */ + sha1hmac(macval, mackey, datamsg->macstart, + datamsg->macend - datamsg->macstart); + if (memcmp(macval, datamsg->mac, 20)) { + fprintf(stderr, "MAC does not verify: wrong AES key?\n"); + } else { + /* Decrypt the message */ + plaintext = malloc(datamsg->encmsglen+1); + if (!plaintext) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + aes_ctr_crypt(plaintext, datamsg->encmsg, datamsg->encmsglen, + aeskey, datamsg->ctr); + plaintext[datamsg->encmsglen] = '\0'; + printf("Plaintext: ``%s''\n", plaintext); + free(plaintext); + } + + /* Do we want to forge a message? */ + if (argv[2] != NULL) { + char *newdatamsg; + size_t newlen = strlen(argv[2]); + ciphertext = malloc(newlen); + if (!ciphertext && newlen > 0) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + aes_ctr_crypt(ciphertext, (const unsigned char *)argv[2], newlen, + aeskey, datamsg->ctr); + free(datamsg->encmsg); + datamsg->encmsg = ciphertext; + datamsg->encmsglen = newlen; + + newdatamsg = remac_datamsg(datamsg, mackey); + + printf("%s\n", newdatamsg); + free(newdatamsg); + } + + free_datamsg(datamsg); + free(aeskey); + fflush(stdout); + return 0; +} diff --git a/comm/third_party/libotr/toolkit/otr_remac.c b/comm/third_party/libotr/toolkit/otr_remac.c new file mode 100644 index 0000000000..1567eeb929 --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_remac.c @@ -0,0 +1,143 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libgcrypt headers */ +#include + +/* toolkit headers */ +#include "parse.h" +#include "sha1hmac.h" + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s mackey sender_instance receiver_instance " + "flags snd_keyid rcp_keyid pubkey counter encdata revealed_mackeys\n" +"Make a new Data message, with the given pieces (note that the\n" +"data part is already encrypted). MAC it with the given mackey.\n" +"mackey, pubkey, counter, encdata, and revealed_mackeys are given\n" +"as strings of hex chars. snd_keyid and rcp_keyid are decimal integers.\n", + progname); + exit(1); +} + +int main(int argc, char **argv) +{ + unsigned char *mackey; + size_t mackeylen; + unsigned int snd_keyid, rcp_keyid; + int flags; + unsigned char version = 3; + unsigned int sender_instance; + unsigned int receiver_instance; + unsigned char *pubkey; + size_t pubkeylen; + gcry_mpi_t pubv; + unsigned char *ctr; + size_t ctrlen; + unsigned char *encdata; + size_t encdatalen; + unsigned char *mackeys; + size_t mackeyslen; + char *newdatamsg; + + if (argc != 11) { + usage(argv[0]); + } + + argv_to_buf(&mackey, &mackeylen, argv[1]); + if (!mackey) { + usage(argv[0]); + } + + if (mackeylen != 20) { + fprintf(stderr, "The MAC key must be 40 hex chars long.\n"); + usage(argv[0]); + } + + if (sscanf(argv[2], "%u", &sender_instance) != 1) { + fprintf(stderr, "Unparseable sender_instance given.\n"); + usage(argv[0]); + } + + if (sscanf(argv[3], "%u", &receiver_instance) != 1) { + fprintf(stderr, "Unparseable receiver_instance given.\n"); + usage(argv[0]); + } + + if (sscanf(argv[4], "%d", &flags) != 1) { + fprintf(stderr, "Unparseable flags given.\n"); + usage(argv[0]); + } + + if (sscanf(argv[5], "%u", &snd_keyid) != 1) { + fprintf(stderr, "Unparseable snd_keyid given.\n"); + usage(argv[0]); + } + + if (sscanf(argv[6], "%u", &rcp_keyid) != 1) { + fprintf(stderr, "Unparseable rcp_keyid given.\n"); + usage(argv[0]); + } + + argv_to_buf(&pubkey, &pubkeylen, argv[7]); + if (!pubkey) { + usage(argv[0]); + } + gcry_mpi_scan(&pubv, GCRYMPI_FMT_USG, pubkey, pubkeylen, NULL); + free(pubkey); + + argv_to_buf(&ctr, &ctrlen, argv[8]); + if (!ctr) { + usage(argv[0]); + } + + if (ctrlen != 8) { + fprintf(stderr, "The counter must be 16 hex chars long.\n"); + usage(argv[0]); + } + + argv_to_buf(&encdata, &encdatalen, argv[9]); + if (!encdata) { + usage(argv[0]); + } + + argv_to_buf(&mackeys, &mackeyslen, argv[10]); + if (!mackeys) { + usage(argv[0]); + } + + newdatamsg = assemble_datamsg(mackey, version, sender_instance, + receiver_instance, flags, snd_keyid, rcp_keyid, pubv, ctr, encdata, + encdatalen, mackeys, mackeyslen); + printf("%s\n", newdatamsg); + free(newdatamsg); + + free(mackey); + gcry_mpi_release(pubv); + free(ctr); + free(encdata); + free(mackeys); + fflush(stdout); + return 0; +} diff --git a/comm/third_party/libotr/toolkit/otr_sesskeys.c b/comm/third_party/libotr/toolkit/otr_sesskeys.c new file mode 100644 index 0000000000..227d18ffee --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_sesskeys.c @@ -0,0 +1,92 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* toolkit headers */ +#include "parse.h" +#include "sesskeys.h" + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s our_privkey their_pubkey\n" +"Calculate and display our public key, the session id, two AES keys,\n" +"and two MAC keys generated by the given DH private key and public key.\n", + progname); + exit(1); +} + +int main(int argc, char **argv) +{ + unsigned char *argbuf; + size_t argbuflen; + gcry_mpi_t our_x, our_y, their_y; + unsigned char *pubbuf; + size_t publen; + unsigned char sessionid[20], sendenc[16], rcvenc[16]; + unsigned char sendmac[20], rcvmac[20]; + int is_high; + + if (argc != 3) { + usage(argv[0]); + } + + argv_to_buf(&argbuf, &argbuflen, argv[1]); + /* Private keys are only 320 bits long, so check for that to make + * sure they didn't get the args the wrong way around */ + if (!argbuf || argbuflen > 40) usage(argv[0]); + gcry_mpi_scan(&our_x, GCRYMPI_FMT_USG, argbuf, argbuflen, NULL); + free(argbuf); + argv_to_buf(&argbuf, &argbuflen, argv[2]); + if (!argbuf) usage(argv[0]); + gcry_mpi_scan(&their_y, GCRYMPI_FMT_USG, argbuf, argbuflen, NULL); + free(argbuf); + + sesskeys_gen(sessionid, sendenc, rcvenc, &is_high, &our_y, our_x, their_y); + sesskeys_make_mac(sendmac, sendenc); + sesskeys_make_mac(rcvmac, rcvenc); + + /* Print our public key into a buffer */ + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &publen, our_y); + pubbuf = malloc(publen); + if (!pubbuf) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + gcry_mpi_print(GCRYMPI_FMT_USG, pubbuf, publen, NULL, our_y); + + puts(""); + printf("We are the %s end of this key exchange.\n", + is_high ? "high" : "low"); + puts(""); + dump_data(stdout, "Our public key", pubbuf, publen); + puts(""); + dump_data(stdout, "Session id", sessionid, 20); + puts(""); + dump_data(stdout, "Sending AES key", sendenc, 16); + dump_data(stdout, "Sending MAC key", sendmac, 20); + dump_data(stdout, "Receiving AES key", rcvenc, 16); + dump_data(stdout, "Receiving MAC key", rcvmac, 20); + puts(""); + fflush(stdout); + + return 0; +} diff --git a/comm/third_party/libotr/toolkit/otr_toolkit.1 b/comm/third_party/libotr/toolkit/otr_toolkit.1 new file mode 100644 index 0000000000..9ded38f61e --- /dev/null +++ b/comm/third_party/libotr/toolkit/otr_toolkit.1 @@ -0,0 +1,110 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH OTR_PARSE 1 "March 14, 2012" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +otr_parse, otr_sesskeys, otr_mackey, otr_readforge, otr_modify, otr_remac \- Process Off-the-Record Messaging transcripts +.SH SYNOPSIS +.B otr_parse +.br +.B otr_sesskeys +.I our_privkey their_pubkey +.br +.B otr_mackey +.I aes_enc_key +.br +.B otr_readforge +.I aes_enc_key [newmsg] +.br +.B otr_modify +.I mackey old_text new_text offset +.br +.B otr_remac +.I mackey sender_instance receiver_instance flags snd_keyid rcv_keyid pubkey counter encdata revealed_mackeys +.SH DESCRIPTION +Off-the-Record (OTR) Messaging allows you to have private conversations +over IM by providing: + - Encryption + - No one else can read your instant messages. + - Authentication + - You are assured the correspondent is who you think it is. + - Deniability + - The messages you send do \fInot\fP have digital signatures that are + checkable by a third party. Anyone can forge messages after a + conversation to make them look like they came from you. However, + \fIduring\fP a conversation, your correspondent is assured the messages + he sees are authentic and unmodified. + - Perfect forward secrecy + - If you lose control of your private keys, no previous conversation + is compromised. +.PP +The OTR Toolkit is useful for analyzing and/or +forging OTR messages. Why do we offer this? Primarily, to make +absolutely sure that transcripts of OTR conversations are really easy +to forge after the fact. [Note that \fIduring\fP an OTR conversation, +messages can't be forged without real-time access to the secret keys on +the participants' computers, and in that case, all security has already +been lost.] Easily-forgeable transcripts help us provide the +"Deniability" property: if someone claims you said something over OTR, +they'll have no proof, as anyone at all can modify a transcript to make +it say whatever they like, and still have all the verification come out +correctly. + +Here are the six programs in the toolkit: + + - otr_parse + - Parse OTR messages given on stdin, showing the values of all the + fields in OTR protocol messages. + + - otr_sesskeys our_privkey their_pubkey + - Shows our public key, the session id, two AES and two MAC keys + derived from the given Diffie-Hellman keys (one private, one public). + + - otr_mackey aes_enc_key + - Shows the MAC key derived from the given AES key. + + - otr_readforge aes_enc_key [newmsg] + - Decrypts an OTR Data message using the given AES key, and displays + the message. + - If newmsg is given, replace the message with that one, encrypt + and MAC it properly, and output the resulting OTR Data Message. + This works even if the given key was not correct for the original + message, so as to enable complete forgeries. + + - otr_modify mackey old_text new_text offset + - Even if you can't read the data because you don't know either + the AES key or the Diffie-Hellman private key, but you can make a + good guess that the substring "old_text" appears at the given + offset in the message, replace the old_text with the new_text + (which must be of the same length), recalculate the MAC with the + given mackey, and output the resulting Data message. + - Note that, even if you don't know any text in an existing message, + you can still forge messages of your choice using the + otr_readforge command, above. + + - otr_remac mackey sender_instance receiver_instance flags snd_keyid rcv_keyid pubkey counter encdata revealed_mackeys + - Make a new OTR protocol version 3 Data Message, with the given + pieces (note that the data part is already encrypted). MAC it + with the given mackey. + +.SH SEE ALSO +.BR "Off-the-Record Messaging" , +at +.UR https://www.cypherpunks.ca/otr/ +https://www.cypherpunks.ca/otr/ +.UE +.SH AUTHOR +otr_toolkit was written by the OTR Dev Team . diff --git a/comm/third_party/libotr/toolkit/parse.c b/comm/third_party/libotr/toolkit/parse.c new file mode 100644 index 0000000000..aaa0ad59c9 --- /dev/null +++ b/comm/third_party/libotr/toolkit/parse.c @@ -0,0 +1,654 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits, Chris Alexander, + * Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libotr headers */ +#include "b64.h" + +/* toolkit headers */ +#include "sha1hmac.h" +#include "parse.h" + +/* Dump an unsigned int to a FILE * */ +void dump_int(FILE *stream, const char *title, unsigned int val) +{ + fprintf(stream, "%s: %u\n", title, val); +} + +/* Dump an mpi to a FILE * */ +void dump_mpi(FILE *stream, const char *title, gcry_mpi_t val) +{ + size_t plen; + unsigned char *d; + + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &plen, val); + d = malloc(plen); + gcry_mpi_print(GCRYMPI_FMT_USG, d, plen, NULL, val); + dump_data(stream, title, d, plen); + free(d); +} + +/* Dump data to a FILE * */ +void dump_data(FILE *stream, const char *title, const unsigned char *data, + size_t datalen) +{ + size_t i; + fprintf(stream, "%s: ", title); + for(i=0;i 0) return NULL; + *lenp = otrl_base64_decode(raw, header, footer-header); + + return raw; +} + +#define require_len(l) do { if (lenp < (l)) goto inv; } while(0) +#define read_int(x) do { \ + require_len(4); \ + (x) = (((unsigned int)bufp[0]) << 24) | (bufp[1] << 16) | (bufp[2] << 8 ) | bufp[3]; \ + bufp += 4; lenp -= 4; \ + } while(0) +#define read_mpi(x) do { \ + size_t mpilen; \ + read_int(mpilen); \ + require_len(mpilen); \ + gcry_mpi_scan(&(x), GCRYMPI_FMT_USG, bufp, mpilen, NULL); \ + bufp += mpilen; lenp -= mpilen; \ + } while(0) +#define read_raw(b, l) do { \ + if (l) { \ + require_len(l); \ + memmove((b), bufp, (l)); \ + bufp += (l); lenp -= (l); \ + } \ + } while(0) +#define write_int(x) do { \ + bufp[0] = ((x) >> 24) & 0xff; \ + bufp[1] = ((x) >> 16) & 0xff; \ + bufp[2] = ((x) >> 8) & 0xff; \ + bufp[3] = (x) & 0xff; \ + bufp += 4; lenp -= 4; \ + } while(0) +#define write_mpi(x,l) do { \ + write_int(l); \ + gcry_mpi_print(GCRYMPI_FMT_USG, bufp, lenp, NULL, (x)); \ + bufp += (l); lenp -= (l); \ + } while(0) +#define write_raw(x,l) do { \ + memmove(bufp, (x), (l)); \ + bufp += (l); lenp -= (l); \ + } while(0) + +/* Parse a Key Exchange Message into a newly-allocated KeyExchMsg structure */ +KeyExchMsg parse_keyexch(const char *msg) +{ + KeyExchMsg kem = NULL; + size_t lenp; + unsigned char *raw = decode(msg, &lenp); + unsigned char *bufp = raw; + if (!raw) goto inv; + + kem = calloc(1, sizeof(struct s_KeyExchMsg)); + if (!kem) { + free(raw); + goto inv; + } + + kem->raw = raw; + kem->sigstart = bufp; + + require_len(3); + if (memcmp(bufp, "\x00\x01\x0a", 3)) goto inv; + bufp += 3; lenp -= 3; + + require_len(1); + kem->reply = *bufp; + bufp += 1; lenp -= 1; + + read_mpi(kem->p); + read_mpi(kem->q); + read_mpi(kem->g); + read_mpi(kem->e); + + read_int(kem->keyid); + + read_mpi(kem->y); + + kem->sigend = bufp; + + require_len(40); + gcry_mpi_scan(&kem->r, GCRYMPI_FMT_USG, bufp, 20, NULL); + gcry_mpi_scan(&kem->s, GCRYMPI_FMT_USG, bufp+20, 20, NULL); + bufp += 40; lenp -= 40; + + if (lenp != 0) goto inv; + + return kem; +inv: + free_keyexch(kem); + return NULL; +} + +/* Deallocate a KeyExchMsg and all of the data it points to */ +void free_keyexch(KeyExchMsg keyexch) +{ + if (!keyexch) return; + free(keyexch->raw); + gcry_mpi_release(keyexch->p); + gcry_mpi_release(keyexch->q); + gcry_mpi_release(keyexch->g); + gcry_mpi_release(keyexch->e); + gcry_mpi_release(keyexch->y); + gcry_mpi_release(keyexch->r); + gcry_mpi_release(keyexch->s); + free(keyexch); +} + +/* Parse a D-H Commit Message into a newly-allocated CommitMsg structure */ +CommitMsg parse_commit(const char *msg) +{ + CommitMsg cmsg = NULL; + size_t lenp; + unsigned char *raw = decode(msg, &lenp); + unsigned char *bufp = raw; + if (!raw) goto inv; + + cmsg = calloc(1, sizeof(struct s_CommitMsg)); + if (!cmsg) { + free(raw); + goto inv; + } + + cmsg->raw = raw; + + require_len(3); + + cmsg->version = bufp[1]; + + if (!memcmp(bufp, "\x00\x03\x02", 3)) { + bufp += 3; lenp -= 3; + read_int(cmsg->sender_instance); + read_int(cmsg->receiver_instance); + } else if (!memcmp(bufp, "\x00\x02\x02", 3)) { + bufp += 3; lenp -= 3; + cmsg->sender_instance = 0; + cmsg->receiver_instance = 0; + } else goto inv; + + read_int(cmsg->enckeylen); + cmsg->enckey = malloc(cmsg->enckeylen); + if (!cmsg->enckey && cmsg->enckeylen > 0) goto inv; + read_raw(cmsg->enckey, cmsg->enckeylen); + + read_int(cmsg->hashkeylen); + cmsg->hashkey = malloc(cmsg->hashkeylen); + if (!cmsg->hashkey && cmsg->hashkeylen > 0) goto inv; + read_raw(cmsg->hashkey, cmsg->hashkeylen); + + if (lenp != 0) goto inv; + + return cmsg; +inv: + free_commit(cmsg); + return NULL; +} + +/* Deallocate a CommitMsg and all of the data it points to */ +void free_commit(CommitMsg cmsg) +{ + if (!cmsg) return; + free(cmsg->raw); + free(cmsg->enckey); + free(cmsg->hashkey); + free(cmsg); +} + +/* Parse a D-H Key Message into a newly-allocated KeyMsg structure */ +KeyMsg parse_key(const char *msg) +{ + KeyMsg kmsg = NULL; + size_t lenp; + unsigned char *raw = decode(msg, &lenp); + unsigned char *bufp = raw; + if (!raw) goto inv; + + kmsg = calloc(1, sizeof(struct s_KeyMsg)); + if (!kmsg) { + free(raw); + goto inv; + } + + kmsg->raw = raw; + + require_len(3); + + kmsg->version = bufp[1]; + + if (!memcmp(bufp, "\x00\x03\x0a", 3)) { + bufp += 3; lenp -= 3; + read_int(kmsg->sender_instance); + read_int(kmsg->receiver_instance); + } else if (!memcmp(bufp, "\x00\x02\x0a", 3)) { + bufp += 3; lenp -= 3; + kmsg->sender_instance = 0; + kmsg->receiver_instance = 0; + } else goto inv; + + read_mpi(kmsg->y); + + if (lenp != 0) goto inv; + + return kmsg; +inv: + free_key(kmsg); + return NULL; +} + +/* Deallocate a KeyMsg and all of the data it points to */ +void free_key(KeyMsg kmsg) +{ + if (!kmsg) return; + free(kmsg->raw); + gcry_mpi_release(kmsg->y); + free(kmsg); +} + +/* Parse a Reveal Signature Message into a newly-allocated RevealSigMsg + * structure */ +RevealSigMsg parse_revealsig(const char *msg) +{ + RevealSigMsg rmsg = NULL; + size_t lenp; + unsigned char *raw = decode(msg, &lenp); + unsigned char *bufp = raw; + if (!raw) goto inv; + + rmsg = calloc(1, sizeof(struct s_RevealSigMsg)); + if (!rmsg) { + free(raw); + goto inv; + } + + rmsg->raw = raw; + + require_len(3); + + rmsg->version = bufp[1]; + + if (!memcmp(bufp, "\x00\x03\x11", 3)) { + bufp += 3; lenp -= 3; + read_int(rmsg->sender_instance); + read_int(rmsg->receiver_instance); + } else if (!memcmp(bufp, "\x00\x02\x11", 3)) { + bufp += 3; lenp -= 3; + rmsg->sender_instance = 0; + rmsg->receiver_instance = 0; + } else goto inv; + + read_int(rmsg->keylen); + rmsg->key = malloc(rmsg->keylen); + if (!rmsg->key && rmsg->keylen > 0) goto inv; + read_raw(rmsg->key, rmsg->keylen); + + read_int(rmsg->encsiglen); + rmsg->encsig = malloc(rmsg->encsiglen); + if (!rmsg->encsig && rmsg->encsiglen > 0) goto inv; + read_raw(rmsg->encsig, rmsg->encsiglen); + + read_raw(rmsg->mac, 20); + + if (lenp != 0) goto inv; + + return rmsg; +inv: + free_revealsig(rmsg); + return NULL; +} + +/* Deallocate a RevealSigMsg and all of the data it points to */ +void free_revealsig(RevealSigMsg rmsg) +{ + if (!rmsg) return; + free(rmsg->raw); + free(rmsg->key); + free(rmsg->encsig); + free(rmsg); +} + +/* Parse a Signature Message into a newly-allocated SignatureMsg structure */ +SignatureMsg parse_signature(const char *msg) +{ + SignatureMsg smsg = NULL; + size_t lenp; + unsigned char *raw = decode(msg, &lenp); + unsigned char *bufp = raw; + if (!raw) goto inv; + + smsg = calloc(1, sizeof(struct s_SignatureMsg)); + if (!smsg) { + free(raw); + goto inv; + } + + smsg->raw = raw; + + require_len(3); + + smsg->version = bufp[1]; + + if (!memcmp(bufp, "\x00\x03\x12", 3)) { + bufp += 3; lenp -= 3; + read_int(smsg->sender_instance); + read_int(smsg->receiver_instance); + } else if (!memcmp(bufp, "\x00\x02\x12", 3)) { + bufp += 3; lenp -= 3; + smsg->sender_instance = 0; + smsg->receiver_instance = 0; + } else goto inv; + + read_int(smsg->encsiglen); + smsg->encsig = malloc(smsg->encsiglen); + if (!smsg->encsig && smsg->encsiglen > 0) goto inv; + read_raw(smsg->encsig, smsg->encsiglen); + + read_raw(smsg->mac, 20); + + if (lenp != 0) goto inv; + + return smsg; +inv: + free_signature(smsg); + return NULL; +} + +/* Deallocate a SignatureMsg and all of the data it points to */ +void free_signature(SignatureMsg smsg) +{ + if (!smsg) return; + free(smsg->raw); + free(smsg->encsig); + free(smsg); +} + +/* Parse a Data Message into a newly-allocated DataMsg structure */ +DataMsg parse_datamsg(const char *msg) +{ + DataMsg datam = NULL; + size_t lenp; + unsigned char *raw = decode(msg, &lenp); + unsigned char *bufp = raw; + unsigned char version; + if (!raw) goto inv; + + datam = calloc(1, sizeof(struct s_DataMsg)); + if (!datam) { + free(raw); + goto inv; + } + + datam->raw = raw; + datam->rawlen = lenp; + datam->macstart = bufp; + + require_len(3); + if (memcmp(bufp, "\x00\x01\x03", 3) && memcmp(bufp, "\x00\x03\x03", 3) && + memcmp(bufp, "\x00\x02\x03", 3)) goto inv; + + version = bufp[1]; + + datam->sender_instance = 0; + datam->receiver_instance = 0; + datam->version = version; + datam->flags = -1; + bufp += 3; lenp -= 3; + + if (version == 3) { + read_int(datam->sender_instance); + read_int(datam->receiver_instance); + } + + if (version == 2 || version == 3) { + require_len(1); + datam->flags = bufp[0]; + bufp += 1; lenp -= 1; + } + + read_int(datam->sender_keyid); + read_int(datam->rcpt_keyid); + read_mpi(datam->y); + read_raw(datam->ctr, 8); + read_int(datam->encmsglen); + datam->encmsg = malloc(datam->encmsglen); + if (!datam->encmsg && datam->encmsglen > 0) goto inv; + read_raw(datam->encmsg, datam->encmsglen); + datam->macend = bufp; + read_raw(datam->mac, 20); + read_int(datam->mackeyslen); + datam->mackeys = malloc(datam->mackeyslen); + + if (!datam->mackeys && datam->mackeyslen > 0) goto inv; + + read_raw(datam->mackeys, datam->mackeyslen); + if (lenp != 0) goto inv; + + return datam; +inv: + free_datamsg(datam); + return NULL; +} + +/* Recalculate the MAC on the message, base64-encode the resulting MAC'd + * message, and put on the appropriate header and footer. Return a + * newly-allocated pointer to the result, which the caller will have to + * free(). */ +char *remac_datamsg(DataMsg datamsg, unsigned char mackey[20]) +{ + size_t rawlen, lenp; + size_t ylen; + size_t base64len; + char *outmsg; + unsigned char *raw, *bufp; + unsigned char version = datamsg->version; + + /* Calculate the size of the message that will result */ + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &ylen, datamsg->y); + rawlen = 3 + (version == 3 ? 8 : 0) + (version == 2 || + version == 3 ? 1 : 0) + 4 + 4 + 4 + ylen + 8 + 4 + + datamsg->encmsglen + 20 + 4 + datamsg->mackeyslen; + + /* Construct the new raw message (note that some of the pieces may + * have been altered, so we construct it from scratch). */ + raw = malloc(rawlen); + if (!raw) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + bufp = raw; + lenp = rawlen; + datamsg->macstart = raw; + datamsg->macend = NULL; + free(datamsg->raw); + datamsg->raw = raw; + datamsg->rawlen = rawlen; + + + memmove(bufp, "\x00", 1); + memmove(bufp+1, &version, 1); + memmove(bufp+2, "\x03", 1); + bufp += 3; lenp -= 3; + + if (version == 3) { + write_int(datamsg->sender_instance); + write_int(datamsg->receiver_instance); + } + + if (version == 2 || version == 3) { + bufp[0] = datamsg->flags; + bufp += 1; lenp -= 1; + } + + write_int(datamsg->sender_keyid); + write_int(datamsg->rcpt_keyid); + write_mpi(datamsg->y, ylen); + write_raw(datamsg->ctr, 8); + write_int(datamsg->encmsglen); + write_raw(datamsg->encmsg, datamsg->encmsglen); + datamsg->macend = bufp; + + /* Recalculate the MAC */ + sha1hmac(datamsg->mac, mackey, datamsg->macstart, + datamsg->macend - datamsg->macstart); + + write_raw(datamsg->mac, 20); + write_int(datamsg->mackeyslen); + write_raw(datamsg->mackeys, datamsg->mackeyslen); + + if (lenp != 0) { + fprintf(stderr, "Error creating OTR Data Message.\n"); + exit(1); + } + + base64len = 5 + ((datamsg->rawlen + 2) / 3) * 4 + 1 + 1; + outmsg = malloc(base64len); + if (!outmsg) return NULL; + + memmove(outmsg, "?OTR:", 5); + otrl_base64_encode(outmsg + 5, datamsg->raw, datamsg->rawlen); + strcpy(outmsg + base64len - 2, "."); + return outmsg; +} + +/* Assemble a new Data Message from its pieces. Return a + * newly-allocated string containing the base64 representation. */ +char *assemble_datamsg(unsigned char mackey[20], + unsigned char version, unsigned int sender_instance, + unsigned int receiver_instance, int flags, unsigned int sender_keyid, + unsigned int rcpt_keyid, gcry_mpi_t y, + unsigned char ctr[8], unsigned char *encmsg, size_t encmsglen, + unsigned char *mackeys, size_t mackeyslen) +{ + DataMsg datam = calloc(1, sizeof(struct s_DataMsg)); + char *newmsg = NULL; + if (!datam) goto inv; + datam->version = version; + datam->flags = flags; + datam->sender_instance = sender_instance; + datam->receiver_instance = receiver_instance; + datam->sender_keyid = sender_keyid; + datam->rcpt_keyid = rcpt_keyid; + datam->y = gcry_mpi_copy(y); + memmove(datam->ctr, ctr, 8); + datam->encmsg = malloc(encmsglen); + if (!datam->encmsg && encmsglen > 0) goto inv; + memmove(datam->encmsg, encmsg, encmsglen); + datam->encmsglen = encmsglen; + datam->mackeys = malloc(mackeyslen); + if (!datam->mackeys && mackeyslen > 0) goto inv; + memmove(datam->mackeys, mackeys, mackeyslen); + datam->mackeyslen = mackeyslen; + + /* Recalculate the MAC and base64-encode the result */ + newmsg = remac_datamsg(datam, mackey); + free_datamsg(datam); + return newmsg; +inv: + free_datamsg(datam); + return NULL; +} + +/* Deallocate a DataMsg and all of the data it points to */ +void free_datamsg(DataMsg datamsg) +{ + if (!datamsg) return; + free(datamsg->raw); + gcry_mpi_release(datamsg->y); + free(datamsg->encmsg); + free(datamsg->mackeys); + free(datamsg); +} + +static int ctoh(char c) +{ + if (c >= '0' && c <= '9') return (c-'0'); + if (c >= 'a' && c <= 'f') return (c-'a'+10); + if (c >= 'A' && c <= 'F') return (c-'A'+10); + return -1; +} + +/* Convert a string of hex chars to a buffer of unsigned chars. */ +void argv_to_buf(unsigned char **bufp, size_t *lenp, char *arg) +{ + unsigned char *buf; + size_t len, i; + + *bufp = NULL; + *lenp = 0; + + len = strlen(arg); + if (len % 2) { + fprintf(stderr, "Argument ``%s'' must have even length.\n", arg); + return; + } + buf = malloc(len/2); + if (buf == NULL && len > 0) { + fprintf(stderr, "Out of memory!\n"); + return; + } + + for(i=0;i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __PARSE_H__ +#define __PARSE_H__ + +#include + +typedef struct s_KeyExchMsg { + unsigned char *raw; /* The base64-decoded data; must be free()d */ + unsigned char reply; + gcry_mpi_t p, q, g, e; + unsigned int keyid; + gcry_mpi_t y; + gcry_mpi_t r, s; + unsigned char *sigstart; /* Pointers into the "raw" array. Don't */ + unsigned char *sigend; /* free() these. */ +} * KeyExchMsg; + +typedef struct s_DataMsg { + unsigned char *raw; /* The base64-decoded data; must be free()d */ + size_t rawlen; + int flags; + unsigned char version; + unsigned int sender_instance; + unsigned int receiver_instance; + unsigned int sender_keyid; + unsigned int rcpt_keyid; + gcry_mpi_t y; + unsigned char ctr[8]; + unsigned char *encmsg; /* A copy; must be free()d */ + size_t encmsglen; + unsigned char mac[20]; + unsigned char *mackeys; /* A copy; must be free()d */ + size_t mackeyslen; + unsigned char *macstart; /* Pointers into the "raw" array. Don't */ + unsigned char *macend; /* free() these. */ +} * DataMsg; + +typedef struct s_CommitMsg { + unsigned char *raw; /* The base64-decoded data; must be free()d */ + unsigned char version; + unsigned int sender_instance; + unsigned int receiver_instance; + unsigned char *enckey; + size_t enckeylen; + unsigned char *hashkey; + size_t hashkeylen; +} * CommitMsg; + +typedef struct s_KeyMsg { + unsigned char *raw; /* The base64-decoded data; must be free()d */ + unsigned char version; + unsigned int sender_instance; + unsigned int receiver_instance; + gcry_mpi_t y; +} * KeyMsg; + +typedef struct s_RevealSigMsg { + unsigned char *raw; /* The base64-decoded data; must be free()d */ + unsigned char version; + unsigned int sender_instance; + unsigned int receiver_instance; + unsigned char *key; + size_t keylen; + unsigned char *encsig; + size_t encsiglen; + unsigned char mac[20]; +} * RevealSigMsg; + +typedef struct s_SignatureMsg { + unsigned char *raw; /* The base64-decoded data; must be free()d */ + unsigned char version; + unsigned int sender_instance; + unsigned int receiver_instance; + unsigned char *encsig; + size_t encsiglen; + unsigned char mac[20]; +} * SignatureMsg; + +/* Dump an unsigned int to a FILE * */ +void dump_int(FILE *stream, const char *title, unsigned int val); + +/* Dump an mpi to a FILE * */ +void dump_mpi(FILE *stream, const char *title, gcry_mpi_t val); + +/* Dump data to a FILE * */ +void dump_data(FILE *stream, const char *title, const unsigned char *data, + size_t datalen); + +/* Parse a Key Exchange Message into a newly-allocated KeyExchMsg structure */ +KeyExchMsg parse_keyexch(const char *msg); + +/* Deallocate a KeyExchMsg and all of the data it points to */ +void free_keyexch(KeyExchMsg keyexch); + +/* Parse a D-H Commit Message into a newly-allocated CommitMsg structure */ +CommitMsg parse_commit(const char *msg); + +/* Parse a Data Message into a newly-allocated DataMsg structure */ +DataMsg parse_datamsg(const char *msg); + +/* Deallocate a CommitMsg and all of the data it points to */ +void free_commit(CommitMsg cmsg); + +/* Parse a Reveal Signature Message into a newly-allocated RevealSigMsg + * structure */ +RevealSigMsg parse_revealsig(const char *msg); + +/* Deallocate a RevealSigMsg and all of the data it points to */ +void free_revealsig(RevealSigMsg rmsg); + +/* Parse a Signature Message into a newly-allocated SignatureMsg structure */ +SignatureMsg parse_signature(const char *msg); + +/* Deallocate a SignatureMsg and all of the data it points to */ +void free_signature(SignatureMsg smsg); + +/* Parse a D-H Key Message into a newly-allocated KeyMsg structure */ +KeyMsg parse_key(const char *msg); + +/* Deallocate a KeyMsg and all of the data it points to */ +void free_key(KeyMsg cmsg); + +/* Recalculate the MAC on the message, base64-encode the resulting MAC'd + * message, and put on the appropriate header and footer. Return a + * newly-allocated pointer to the result, which the caller will have to + * free(). */ +char *remac_datamsg(DataMsg datamsg, unsigned char mackey[20]); + +/* Assemble a new Data Message from its pieces. Return a + * newly-allocated string containing the base64 representation. */ +char *assemble_datamsg(unsigned char mackey[20], + unsigned char version, unsigned int sender_instance, + unsigned int receiver_instance, int flags, unsigned int sender_keyid, + unsigned int rcpt_keyid, gcry_mpi_t y, + unsigned char ctr[8], unsigned char *encmsg, size_t encmsglen, + unsigned char *mackeys, size_t mackeyslen); + +/* Deallocate a DataMsg and all of the data it points to */ +void free_datamsg(DataMsg datamsg); + +/* Convert a string of hex chars to a buffer of unsigned chars. */ +void argv_to_buf(unsigned char **bufp, size_t *lenp, char *arg); + +#endif diff --git a/comm/third_party/libotr/toolkit/readotr.c b/comm/third_party/libotr/toolkit/readotr.c new file mode 100644 index 0000000000..77ffcbb6a6 --- /dev/null +++ b/comm/third_party/libotr/toolkit/readotr.c @@ -0,0 +1,91 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include +#include + +typedef struct { + char *data; + size_t len; + size_t alloclen; +} Buffer; + +static void buf_new(Buffer *bufp) +{ + bufp->data = NULL; + bufp->len = 0; + bufp->alloclen = 0; +} + +static void buf_put(Buffer *bufp, const char *str, size_t len) +{ + while (bufp->len + len + 1 > bufp->alloclen) { + char *newdata = realloc(bufp->data, bufp->alloclen + 1024); + if (!newdata) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + bufp->data = newdata; + bufp->alloclen += 1024; + } + memmove(bufp->data + bufp->len, str, len); + bufp->len += len; + bufp->data[bufp->len] = '\0'; +} + +static void buf_putc(Buffer *bufp, char c) +{ + buf_put(bufp, &c, 1); +} + +/* Read from the given stream until we see a complete OTR Key Exchange + * or OTR Data message. Return a newly-allocated pointer to a copy of + * this message, which the caller should free(). Returns NULL if no + * such message could be found. */ +char *readotr(FILE *stream) +{ + int seen = 0; + const char header[] = "?OTR:"; /* There are no '?' chars other than + the leading one */ + int headerlen = strlen(header); + Buffer buf; + + while(seen < headerlen) { + int c = fgetc(stream); + if (c == EOF) return NULL; + else if (c == header[seen]) seen++; + else if (c == header[0]) seen = 1; + else seen = 0; + } + + buf_new(&buf); + buf_put(&buf, header, headerlen); + + /* Look for the trailing '.' */ + while(1) { + int c = fgetc(stream); + if (c == EOF) break; + buf_putc(&buf, c); + if (c == '.') break; + } + + return buf.data; +} diff --git a/comm/third_party/libotr/toolkit/readotr.h b/comm/third_party/libotr/toolkit/readotr.h new file mode 100644 index 0000000000..a1b78f9130 --- /dev/null +++ b/comm/third_party/libotr/toolkit/readotr.h @@ -0,0 +1,29 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __READOTR_H__ +#define __READOTR_H__ + +/* Read from the given stream until we see a complete OTR Key Exchange + * or OTR Data message. Return a newly-allocated pointer to a copy of + * this message, which the caller should free(). Returns NULL if no + * such message could be found. */ +char *readotr(FILE *stream); + +#endif diff --git a/comm/third_party/libotr/toolkit/sesskeys.c b/comm/third_party/libotr/toolkit/sesskeys.c new file mode 100644 index 0000000000..08649e60f2 --- /dev/null +++ b/comm/third_party/libotr/toolkit/sesskeys.c @@ -0,0 +1,98 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Chris Alexander, + * Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include + +/* libgcrypt headers */ +#include + +static const char* DH1536_MODULUS_S = "0x" + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; +static const int DH1536_MOD_LEN_BITS = 1536; +static const char *DH1536_GENERATOR_S = "0x02"; + +/* Generate the session id and the two encryption keys from our private + * DH key and their public DH key. Also indicate in *high_endp if we + * are the "high" end of the key exchange (set to 1) or the "low" end + * (set to 0) */ +void sesskeys_gen(unsigned char sessionid[20], unsigned char sendenc[16], + unsigned char rcvenc[16], int *high_endp, gcry_mpi_t *our_yp, + gcry_mpi_t our_x, gcry_mpi_t their_y) +{ + gcry_mpi_t modulus, generator, secretv; + unsigned char *secret; + size_t secretlen; + unsigned char hash[20]; + int is_high; + + gcry_mpi_scan(&modulus, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_MODULUS_S, 0, NULL); + gcry_mpi_scan(&generator, GCRYMPI_FMT_HEX, + (const unsigned char *)DH1536_GENERATOR_S, 0, NULL); + *our_yp = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(*our_yp, generator, our_x, modulus); + secretv = gcry_mpi_snew(DH1536_MOD_LEN_BITS); + gcry_mpi_powm(secretv, their_y, our_x, modulus); + gcry_mpi_release(generator); + gcry_mpi_release(modulus); + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &secretlen, secretv); + secret = malloc(secretlen + 5); + + secret[1] = (secretlen >> 24) & 0xff; + secret[2] = (secretlen >> 16) & 0xff; + secret[3] = (secretlen >> 8) & 0xff; + secret[4] = (secretlen) & 0xff; + gcry_mpi_print(GCRYMPI_FMT_USG, secret+5, secretlen, NULL, secretv); + gcry_mpi_release(secretv); + + is_high = (gcry_mpi_cmp(*our_yp, their_y) > 0); + + /* Calculate the session id */ + secret[0] = 0x00; + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, secret, secretlen+5); + memmove(sessionid, hash, 20); + + /* Calculate the sending enc key */ + secret[0] = is_high ? 0x01 : 0x02; + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, secret, secretlen+5); + memmove(sendenc, hash, 16); + + /* Calculate the receiving enc key */ + secret[0] = is_high ? 0x02 : 0x01; + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, secret, secretlen+5); + memmove(rcvenc, hash, 16); + + *high_endp = is_high; + free(secret); +} + +/* Generate a MAC key from the corresponding encryption key */ +void sesskeys_make_mac(unsigned char mackey[20], unsigned char enckey[16]) +{ + gcry_md_hash_buffer(GCRY_MD_SHA1, mackey, enckey, 16); +} diff --git a/comm/third_party/libotr/toolkit/sesskeys.h b/comm/third_party/libotr/toolkit/sesskeys.h new file mode 100644 index 0000000000..677d2054c7 --- /dev/null +++ b/comm/third_party/libotr/toolkit/sesskeys.h @@ -0,0 +1,34 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SESSKEYS_H__ +#define __SESSKEYS_H__ + +/* Generate the session id and the two encryption keys from our private + * DH key and their public DH key. Also indicate in *high_endp if we + * are the "high" end of the key exchange (set to 1) or the "low" end + * (set to 0) */ +void sesskeys_gen(unsigned char sessionid[20], unsigned char sendenc[16], + unsigned char rcvenc[16], int *high_endp, gcry_mpi_t *our_yp, + gcry_mpi_t our_x, gcry_mpi_t their_y); + +/* Generate a MAC key from the corresponding encryption key */ +void sesskeys_make_mac(unsigned char mackey[20], unsigned char enckey[16]); + +#endif diff --git a/comm/third_party/libotr/toolkit/sha1hmac.c b/comm/third_party/libotr/toolkit/sha1hmac.c new file mode 100644 index 0000000000..7cf82d6a10 --- /dev/null +++ b/comm/third_party/libotr/toolkit/sha1hmac.c @@ -0,0 +1,61 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* system headers */ +#include +#include + +/* libgcrypt headers */ +#include + +/* Implementation of SHA1-HMAC. We're rolling our own just to + * double-check that the calls libotr makes to libgcrypt are in fact + * doing the right thing. */ +void sha1hmac(unsigned char digest[20], unsigned char key[20], + unsigned char *data, size_t datalen) +{ + unsigned char ipad[64], opad[64]; + size_t i; + gcry_md_hd_t sha1; + gcry_error_t err; + unsigned char hash[20]; + + memset(ipad, 0, 64); + memset(opad, 0, 64); + memmove(ipad, key, 20); + memmove(opad, key, 20); + for(i=0;i<64;++i) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + err = gcry_md_open(&sha1, GCRY_MD_SHA1, 0); + if (err) { + fprintf(stderr, "Error: %s\n", gcry_strerror(err)); + exit(1); + } + gcry_md_write(sha1, ipad, 64); + gcry_md_write(sha1, data, datalen); + memmove(hash, gcry_md_read(sha1, 0), 20); + gcry_md_reset(sha1); + gcry_md_write(sha1, opad, 64); + gcry_md_write(sha1, hash, 20); + memmove(digest, gcry_md_read(sha1, 0), 20); + gcry_md_close(sha1); +} diff --git a/comm/third_party/libotr/toolkit/sha1hmac.h b/comm/third_party/libotr/toolkit/sha1hmac.h new file mode 100644 index 0000000000..1f76ddc41b --- /dev/null +++ b/comm/third_party/libotr/toolkit/sha1hmac.h @@ -0,0 +1,29 @@ +/* + * Off-the-Record Messaging Toolkit + * Copyright (C) 2004-2012 Ian Goldberg, Chris Alexander, Nikita Borisov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SHA1HMAC_H__ +#define __SHA1HMAC_H__ + +/* Implementation of SHA1-HMAC. We're rolling our own just to + * double-check that the calls libotr makes to libgcrypt are in fact + * doing the right thing. */ +void sha1hmac(unsigned char digest[20], unsigned char key[20], + unsigned char *data, size_t datalen); + +#endif diff --git a/comm/third_party/moz.build b/comm/third_party/moz.build new file mode 100644 index 0000000000..a81f2cd3a8 --- /dev/null +++ b/comm/third_party/moz.build @@ -0,0 +1,24 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += [ + "asn1js", +] + +if CONFIG["TB_LIBOTR_PREBUILT"]: + DEFINES["TB_LIBOTR_PREBUILT"] = CONFIG["TB_LIBOTR_PREBUILT"] + + if CONFIG["HAVE_64BIT_BUILD"]: + DEFINES["HAVE_64BIT_BUILD"] = True + +if CONFIG["MZLA_LIBRNP"]: + DIRS += [ + "bzip2", + "json-c", + "rnp", + "zlib", + ] + if CONFIG["MZLA_LIBRNP_BACKEND"] == "botan": + DIRS += ["botan"] diff --git a/comm/third_party/niwcompat/dirent.h b/comm/third_party/niwcompat/dirent.h new file mode 100644 index 0000000000..1b14e16122 --- /dev/null +++ b/comm/third_party/niwcompat/dirent.h @@ -0,0 +1,1166 @@ +/* + * Dirent interface for Microsoft Visual Studio + * + * Copyright (C) 1998-2019 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* Hide warnings about unreferenced local functions */ +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunused-function" +#elif defined(_MSC_VER) +# pragma warning(disable:4505) +#elif defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/* + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. + */ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat(), general mask */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT +#endif + +/* Directory bit */ +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR +#endif + +/* Character device bit */ +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR +#endif + +/* Pipe bit */ +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO +#endif + +/* Regular file bit */ +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG +#endif + +/* Read permission */ +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD +#endif + +/* Write permission */ +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE +#endif + +/* Execute permission */ +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC +#endif + +/* Pipe */ +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + +/* Block device */ +#if !defined(S_IFBLK) +# define S_IFBLK 0 +#endif + +/* Link */ +#if !defined(S_IFLNK) +# define S_IFLNK 0 +#endif + +/* Socket */ +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +# define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +# define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +# define S_IXUSR 0 +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +# define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +# define S_IWGRP 0 +#endif + +/* Execute group permission */ +#if !defined(S_IXGRP) +# define S_IXGRP 0 +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +# define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +# define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +# define S_IXOTH 0 +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#if !defined(S_ISFIFO) +# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISDIR) +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISLNK) +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) +# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISCHR) +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISBLK) +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#endif + +/* Return the exact length of the file name without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX+1]; +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; +}; +typedef struct _WDIR _WDIR; + +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX+1]; +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + + +/* Dirent functions */ +static DIR *opendir (const char *dirname); +static _WDIR *_wopendir (const wchar_t *dirname); + +static struct dirent *readdir (DIR *dirp); +static struct _wdirent *_wreaddir (_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + +static int closedir (DIR *dirp); +static int _wclosedir (_WDIR *dirp); + +static void rewinddir (DIR* dirp); +static void _wrewinddir (_WDIR* dirp); + +static int scandir (const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort (const struct dirent **a, const struct dirent **b); + +static int versionsort (const struct dirent **a, const struct dirent **b); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); + +static int dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count); + +static int dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count); + +static void dirent_set_errno (int error); + + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR* +_wopendir( + const wchar_t *dirname) +{ + _WDIR *dirp; +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + DWORD n; +#else + /* WinRT */ + size_t n; +#endif + wchar_t *p; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); + if (!dirp) { + return NULL; + } + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* + * Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + n = GetFullPathNameW (dirname, 0, NULL, NULL); +#else + /* WinRT */ + n = wcslen (dirname); +#endif + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt == NULL) { + goto exit_closedir; + } + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); + if (n <= 0) { + goto exit_closedir; + } +#else + /* WinRT */ + wcsncpy_s (dirp->patt, n+1, dirname, n); +#endif + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (!dirent_first (dirp)) { + goto exit_closedir; + } + + /* Success */ + return dirp; + + /* Failure */ +exit_closedir: + _wclosedir (dirp); + return NULL; +} + +/* + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). + */ +static struct _wdirent* +_wreaddir( + _WDIR *dirp) +{ + struct _wdirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) _wreaddir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, + struct _wdirent *entry, + struct _wdirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next (dirp); + if (datap) { + size_t n; + DWORD attr; + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n < PATH_MAX && datap->cFileName[n] != 0) { + entry->d_name[n] = datap->cFileName[n]; + n++; + } + entry->d_name[n] = 0; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n; + + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct _wdirent); + + /* Set result address */ + *result = entry; + + } else { + + /* Return NULL to indicate end of directory */ + *result = NULL; + + } + + return /*OK*/0; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir( + _WDIR *dirp) +{ + int ok; + if (dirp) { + + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Release search pattern */ + free (dirp->patt); + + /* Release directory structure */ + free (dirp); + ok = /*success*/0; + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void +_wrewinddir( + _WDIR* dirp) +{ + if (dirp) { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Open new search handle */ + dirent_first (dirp); + } +} + +/* Get first directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_first( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + DWORD error; + + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); + if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + + } else { + + /* Failed to open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + + /* Set error code */ + error = GetLastError (); + switch (error) { + case ERROR_ACCESS_DENIED: + /* No read access to directory */ + dirent_set_errno (EACCES); + break; + + case ERROR_DIRECTORY: + /* Directory name is invalid */ + dirent_set_errno (ENOTDIR); + break; + + case ERROR_PATH_NOT_FOUND: + default: + /* Cannot find the file */ + dirent_set_errno (ENOENT); + } + + } + return datap; +} + +/* + * Get next directory entry (internal). + * + * Returns + */ +static WIN32_FIND_DATAW* +dirent_next( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *p; + + /* Get next directory entry */ + if (dirp->cached != 0) { + + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + + } else if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* Get the next directory entry from stream */ + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { + /* Got a file */ + p = &dirp->data; + } else { + /* The very last entry has been processed or an error occurred */ + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + + } else { + + /* End of directory stream reached */ + p = NULL; + + } + + return p; +} + +/* + * Open directory stream using plain old C-string. + */ +static DIR* +opendir( + const char *dirname) +{ + struct DIR *dirp; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (!dirp) { + return NULL; + } + { + int error; + wchar_t wname[PATH_MAX + 1]; + size_t n; + + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s( + &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (error) { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + goto exit_free; + } + + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (!dirp->wdirp) { + goto exit_free; + } + + } + + /* Success */ + return dirp; + + /* Failure */ +exit_free: + free (dirp); + return NULL; +} + +/* + * Read next directory entry. + */ +static struct dirent* +readdir( + DIR *dirp) +{ + struct dirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) readdir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, + struct dirent *entry, + struct dirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next (dirp->wdirp); + if (datap) { + size_t n; + int error; + + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); + + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = dirent_wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); + } + + if (!error) { + DWORD attr; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n - 1; + + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct dirent); + + } else { + + /* + * Cannot convert file name to multi-byte string so construct + * an erroneous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + + } + + /* Return pointer to directory entry */ + *result = entry; + + } else { + + /* No more directory entries */ + *result = NULL; + + } + + return /*OK*/0; +} + +/* + * Close directory stream. + */ +static int +closedir( + DIR *dirp) +{ + int ok; + if (dirp) { + + /* Close wide-character directory stream */ + ok = _wclosedir (dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free (dirp); + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream to beginning. + */ +static void +rewinddir( + DIR* dirp) +{ + /* Rewind wide-character string directory stream */ + _wrewinddir (dirp->wdirp); +} + +/* + * Scan directory for entries. + */ +static int +scandir( + const char *dirname, + struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + const size_t init_size = 1; + DIR *dir = NULL; + struct dirent *entry; + struct dirent *tmp = NULL; + size_t i; + int result = 0; + + /* Open directory stream */ + dir = opendir (dirname); + if (dir) { + + /* Read directory entries to memory */ + while (1) { + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + void *p; + size_t num_entries; + + /* Compute number of entries in the enlarged pointer table */ + if (size < init_size) { + /* Allocate initial pointer table */ + num_entries = init_size; + } else { + /* Double the size */ + num_entries = size * 2; + } + + /* Allocate first pointer table or enlarge existing table */ + p = realloc (files, sizeof (void*) * num_entries); + if (p != NULL) { + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } else { + /* Out of memory */ + result = -1; + break; + } + + } + + /* Allocate room for temporary directory entry */ + if (tmp == NULL) { + tmp = (struct dirent*) malloc (sizeof (struct dirent)); + if (tmp == NULL) { + /* Cannot allocate temporary directory entry */ + result = -1; + break; + } + } + + /* Read directory entry to temporary area */ + if (readdir_r (dir, tmp, &entry) == /*OK*/0) { + + /* Did we get an entry? */ + if (entry != NULL) { + int pass; + + /* Determine whether to include the entry in result */ + if (filter) { + /* Let the filter function decide */ + pass = filter (tmp); + } else { + /* No filter function, include everything */ + pass = 1; + } + + if (pass) { + /* Store the temporary entry to pointer table */ + files[size++] = tmp; + tmp = NULL; + + /* Keep up with the number of files */ + result++; + } + + } else { + + /* + * End of directory stream reached => sort entries and + * exit. + */ + qsort (files, size, sizeof (void*), + (int (*) (const void*, const void*)) compare); + break; + + } + + } else { + /* Error reading directory entry */ + result = /*Error*/ -1; + break; + } + + } + + } else { + /* Cannot open directory */ + result = /*Error*/ -1; + } + + /* Release temporary directory entry */ + free (tmp); + + /* Release allocated memory on error */ + if (result < 0) { + for (i = 0; i < size; i++) { + free (files[i]); + } + free (files); + files = NULL; + } + + /* Close directory stream */ + if (dir) { + closedir (dir); + } + + /* Pass pointer table to caller */ + if (namelist) { + *namelist = files; + } + return result; +} + +/* Alphabetical sorting */ +static int +alphasort( + const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort( + const struct dirent **a, const struct dirent **b) +{ + /* FIXME: implement strverscmp and use that */ + return alphasort (a, b); +} + +/* Convert multi-byte string to wide character string */ +static int +dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to wide-character string (or count characters) */ + n = mbstowcs (wcstr, mbstr, sizeInWords); + if (!wcstr || n < count) { + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) { + n = sizeInWords - 1; + } + wcstr[n] = 0; + } + + /* Length of resulting multi-byte string WITH zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Could not convert string */ + error = 1; + + } + +#endif + return error; +} + +/* Convert wide-character string to multi-byte string */ +static int +dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, /* max size of mbstr */ + const wchar_t *wcstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to multi-byte string (or count the number of bytes needed) */ + n = wcstombs (mbstr, wcstr, sizeInBytes); + if (!mbstr || n < count) { + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Length of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Cannot convert string */ + error = 1; + + } + +#endif + return error; +} + +/* Set errno variable */ +static void +dirent_set_errno( + int error) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 and later */ + _set_errno (error); + +#else + + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; + +#endif +} + + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ diff --git a/comm/third_party/niwcompat/extra_include.h b/comm/third_party/niwcompat/extra_include.h new file mode 100644 index 0000000000..34ed66bdfa --- /dev/null +++ b/comm/third_party/niwcompat/extra_include.h @@ -0,0 +1 @@ +#include diff --git a/comm/third_party/niwcompat/getopt.c b/comm/third_party/niwcompat/getopt.c new file mode 100644 index 0000000000..f7e0b37bc9 --- /dev/null +++ b/comm/third_party/niwcompat/getopt.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 1987, 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "getopt.h" + +int opterr; /* if error message should be printed */ +int optind; /* index into parent argv vector */ +int optopt; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define __P(x) x +#define _DIAGASSERT(x) assert(x) + +static char * __progname __P((char *)); +int getopt_internal __P((int, char * const *, const char *)); + +static char * +__progname(nargv0) + char * nargv0; +{ + char * tmp; + + _DIAGASSERT(nargv0 != NULL); + + tmp = strrchr(nargv0, '/'); + if (tmp) + tmp++; + else + tmp = nargv0; + return(tmp); +} + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt_internal(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(ostr != NULL); + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + /* ++optind; */ + place = EMSG; + return (-2); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname(nargv[0]), optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if ((opterr) && (*ostr != ':')) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname(nargv[0]), optopt); + return (BADARG); + } else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + int retval; + + if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) { + retval = -1; + ++optind; + } + return(retval); +} + + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(nargc, nargv, options, long_options, index) + int nargc; + char ** nargv; + const char * options; + const struct option * long_options; + int * index; +{ + int retval; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + _DIAGASSERT(long_options != NULL); + /* index may be NULL */ + + if ((retval = getopt_internal(nargc, nargv, options)) == -2) { + char *current_argv = nargv[optind++] + 2, *has_equal; + int i, current_argv_len, match = -1; + + if (*current_argv == '\0') { + return(-1); + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + if (strncmp(current_argv, long_options[i].name, current_argv_len)) + continue; + + if (strlen(long_options[i].name) == (unsigned)current_argv_len) { + match = i; + break; + } + if (match == -1) + match = i; + } + if (match != -1) { + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else + optarg = nargv[optind++]; + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument, leading : + * indicates no error should be generated + */ + if ((opterr) && (*options != ':')) + (void)fprintf(stderr, + "%s: option requires an argument -- %s\n", + __progname(nargv[0]), current_argv); + return (BADARG); + } + } else { /* No matching argument */ + if ((opterr) && (*options != ':')) + (void)fprintf(stderr, + "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv); + return (BADCH); + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (index) + *index = match; + } + return(retval); +} diff --git a/comm/third_party/niwcompat/getopt.h b/comm/third_party/niwcompat/getopt.h new file mode 100644 index 0000000000..bbb56c6cae --- /dev/null +++ b/comm/third_party/niwcompat/getopt.h @@ -0,0 +1,33 @@ +#ifndef __GETOPT_H__ +#define __GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +int getopt(int, char * const*, const char*); +int getopt_long(int, char**, const char*, const struct option*, int*); + +#ifdef __cplusplus +} +#endif + +#endif /* __GETOPT_H__ */ diff --git a/comm/third_party/openpgp.configure b/comm/third_party/openpgp.configure new file mode 100644 index 0000000000..03f760ed57 --- /dev/null +++ b/comm/third_party/openpgp.configure @@ -0,0 +1,374 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +@template +def noset_check_header( + header, language="C++", flags=None, includes=None, when=None, onerror=lambda: None +): + if when is None: + when = always + + if includes: + includes = includes[:] + else: + includes = [] + includes.append(header) + + return try_compile( + includes=includes, + language=language, + flags=flags, + check_msg="for %s" % header, + when=when, + onerror=onerror, + ) + + +@template +def check_symbol_exists( + symbol, + header, + language="C", + flags=None, + includes=None, + when=None, + onerror=lambda: None, +): + if when is None: + when = always + + if includes: + includes = includes[:] + else: + includes = [] + includes.append("stdio.h") + + if isinstance(header, str): + header = [header] + includes.extend(header) + + body = """#ifndef %s +(void) %s; +#endif +""" % ( + symbol, + symbol, + ) + + return try_compile( + includes, + body, + language=language, + flags=flags, + check_msg="for %s" % symbol, + when=when, + onerror=onerror, + ) + + +with only_when("--enable-compile-environment"): + option( + "--with-system-librnp", + help="Use system RNP (librnp) for OpenPGP support.", + ) + + @depends("--with-system-librnp") + def in_tree_librnp(system_librnp): + if system_librnp: + log.info("System librnp will be used at runtime.") + return False + return True + + set_config("MZLA_LIBRNP", depends_if(in_tree_librnp)(lambda _: True)) + set_define("MZLA_LIBRNP", depends_if(in_tree_librnp)(lambda _: True)) + + +with only_when(in_tree_librnp): + # JSON-C --with-system-json + system_lib_option( + "--with-system-jsonc", + help="Use system JSON-C for librnp (located with pkgconfig)", + ) + + jsonc_pkg = pkg_check_modules("MZLA_JSONC", "json-c >= 0.11", when="--with-system-jsonc") + set_config("MZLA_SYSTEM_JSONC", depends_if(jsonc_pkg)(lambda _: True)) + + @depends("--with-system-jsonc") + def in_tree_jsonc(system_jsonc): + if not system_jsonc: + return True + + # Bzip2 --with-system-bz2 + system_lib_option( + "--with-system-bz2", + nargs="?", + help="Use system Bzip2 for librnp (pkgconfig/given prefix)", + ) + set_config("MZLA_SYSTEM_BZIP2", True, when="--with-system-bz2") + + # Bzip2 does not include a pkgconfig file, but some Linux distributions add one + bzip2_pkg = pkg_check_modules( + "MZLA_BZIP2", + "bzip2 >= 1.0.6", + when="--with-system-bz2", + allow_missing=True, + config=False, + ) + + @depends_if("--with-system-bz2", bzip2_pkg) + def bzip2_flags(value, bzip2_pkg): + if len(value): + # A path (eg. /usr/local was given) + return namespace( + cflags=("-I%s/include" % value[0],), + ldflags=("-L%s/lib" % value[0], "-lbz2"), + ) + if bzip2_pkg: + cflags = list(bzip2_pkg.cflags) + libs = bzip2_pkg.libs + return namespace( + cflags=cflags, + ldflags=libs, + ) + # Fallback + return namespace( + ldflags=["-lbz2"], + ) + + with only_when("--with-system-bz2"): + check_symbol( + "BZ2_bzread", + flags=bzip2_flags.ldflags, + onerror=lambda: die("--with-system-bz2 requested but symbol " "BZ2_bzread not found."), + ) + c_compiler.try_compile( + includes=[ + "stdio.h", + "sys/types.h", + "bzlib.h", + ], + body=""" + #ifndef _BZLIB_H + #error _BZLIB_H bzlib.h not found + #endif + """, + flags=bzip2_flags.cflags, + check_msg="for bzlib.h", + onerror=lambda: die("bzlib.h header not found"), + ) + set_config("MZLA_BZIP2_CFLAGS", bzip2_flags.cflags) + set_config("MZLA_BZIP2_LIBS", bzip2_flags.ldflags) + + # librnp crypto backend selection + @depends(target_has_linux_kernel) + def librnp_backend_choices(is_linux): + if is_linux: + return ("botan", "openssl") + else: + return ("botan",) + + option( + "--with-librnp-backend", + help="Build librnp with the selected backend", + choices=librnp_backend_choices, + nargs=1, + default="botan", + ) + + @depends("--with-librnp-backend") + def librnp_backend(backend): + if backend: + return backend[0] + + set_config("MZLA_LIBRNP_BACKEND", librnp_backend) + + @depends(librnp_backend) + def rnp_botan(backend): + return backend == "botan" + + @depends(librnp_backend) + def rnp_openssl(backend): + return backend == "openssl" + + # Botan backend (--with-system-botan) + with only_when(rnp_botan): + system_lib_option( + "--with-system-botan", + help="Use system Botan for librnp (located with pkgconfig)", + ) + + botan_pkg = pkg_check_modules("MZLA_BOTAN", "botan-2 >= 2.8.0", when="--with-system-botan") + set_config("MZLA_SYSTEM_BOTAN", depends_if(botan_pkg)(lambda _: True)) + + # OpenSSL backend + with only_when(rnp_openssl): + option( + "--with-openssl", + nargs=1, + help="OpenSSL library prefix (when not found by pkgconfig)", + ) + openssl_pkg = pkg_check_modules( + "MZLA_LIBRNP_OPENSSL", "openssl >= 1.1.1e", allow_missing=True, config=False + ) + + @depends_if("--with-openssl", openssl_pkg) + @imports(_from="os.path", _import="isdir") + @imports(_from="os.path", _import="join") + def openssl_flags(openssl_prefix, openssl_pkg): + if openssl_prefix: + openssl_prefix = openssl_prefix[0] + include = join(openssl_prefix, "include") + lib = join(openssl_prefix, "lib") + if not isdir(lib): + lib = join(openssl_prefix, "lib64") + if isdir(include) and isdir(lib): + log.info(f"Using OpenSSL at {openssl_prefix}.") + return namespace( + cflags=(f"-I{include}",), + ldflags=(f"-L{lib}", "-lssl", "-lcrypto"), + ) + if openssl_pkg: + return namespace( + cflags=openssl_pkg.cflags, + ldflags=openssl_pkg.libs, + ) + + set_config("MZLA_LIBRNP_OPENSSL_CFLAGS", openssl_flags.cflags) + set_config("MZLA_LIBRNP_OPENSSL_LIBS", openssl_flags.ldflags) + + @depends(configure_cache, c_compiler, openssl_flags) + @imports(_from="textwrap", _import="dedent") + @imports(_from="__builtin__", _import="chr") + def openssl_version(configure_cache, compiler, openssl_flags): + log.info("Checking for OpenSSL >= 1.1.1e") + if openssl_flags is None: + die("OpenSSL not found. Must be locatable with pkg-config or use --with-openssl.") + + def ossl_hexver(hex_str): + # See opensshlv.h for description of OPENSSL_VERSION_NUMBER + MIN_OSSL_VER = 0x1010105F # Version 1.1.1e + ver_as_int = int(hex_str[:-1], 16) + ossl_major = (ver_as_int & 0xF0000000) >> 28 + ossl_minor = (ver_as_int & 0x0FF00000) >> 20 + ossl_fix = (ver_as_int & 0x000FF000) >> 12 + # as a letter a-z + ossl_patch = chr(96 + ((ver_as_int & 0x00000FF0) >> 4)) + ver_as_str = f"{ossl_major}.{ossl_minor}.{ossl_fix}{ossl_patch}" + if ver_as_int < MIN_OSSL_VER: + die(f"OpenSSL version {ver_as_str} is too old.") + return ver_as_str + + check = dedent( + """\ + #include + #ifdef OPENSSL_VERSION_STR + OPENSSL_VERSION_STR + #elif defined(OPENSSL_VERSION_NUMBER) + OPENSSL_VERSION_NUMBER + #else + #error Unable to determine OpenSSL version. + #endif + """ + ) + result = try_preprocess( + configure_cache, + compiler.wrapper + + [compiler.compiler] + + compiler.flags + + list(openssl_flags.cflags), + "C", + check, + ) + if result: + openssl_ver = result.splitlines()[-1] + if openssl_ver.startswith("0x"): + # OpenSSL 1.x.x - like 0x1010107fL + openssl_ver = ossl_hexver(openssl_ver) + else: + # OpenSSL 3.x.x - quoted version like "3.0.7" + openssl_ver = openssl_ver.replace('"', "") + major_version = openssl_ver.split(".")[0] + if major_version != "3": + die( + "Unrecognized OpenSSL version {openssl_version} found. Require >= 1.1.1e or 3.x.x" + ) + + log.info(f"Found OpenSSL {openssl_ver}.") + return openssl_ver + + set_config("MZLA_LIBRNP_OPENSSL_VERSION", openssl_version) + + # Checks for building librnp itself + # ================================= + have_fcntl_h = check_header("fcntl.h") + have_string_h = check_header("string.h") + check_headers( + "limits.h", + "sys/auxv.h", + "sys/cdefs.h", + "sys/resource.h", + "sys/param.h", + "sys/stat.h", + "sys/wait.h", + ) + + set_define("HAVE_MKDTEMP", check_symbol_exists("mkdtemp", ["stdlib.h", "unistd.h"])) + set_define("HAVE_MKSTEMP", check_symbol_exists("mkstemp", ["stdlib.h", "unistd.h"])) + set_define("HAVE_REALPATH", check_symbol_exists("realpath", "stdlib.h")) + set_define("HAVE_O_BINARY", check_symbol_exists("O_BINARY", "fcntl.h")) + set_define("HAVE__O_BINARY", check_symbol_exists("_O_BINARY", "fcntl.h")) + + # Checks when building JSON-C from tree sources + # ============================================= + with only_when(in_tree_jsonc): + have_stdlib_h = check_header("stdlib.h") + have_locale_h = check_header("locale.h") + have_strings_h = check_header("strings.h") + + check_headers("stdarg.h", "dlfcn.h", "endian.h", "memory.h", "xlocale.h") + + set_define("JSON_C_HAVE_INTTYPES_H", noset_check_header("inttypes.h")) + + set_define("HAVE_DECL__ISNAN", check_symbol_exists("_isnan", "float.h")) + + set_define("HAVE_DECL__FINITE", check_symbol_exists("_finite", "float.h")) + set_define("HAVE_DECL_INFINITY", check_symbol_exists("INFINITY", "math.h")) + set_define("HAVE_DECL_ISINF", check_symbol_exists("isinf", "math.h")) + set_define("HAVE_DECL_ISNAN", check_symbol_exists("isnan", "math.h")) + set_define("HAVE_DECL_NAN", check_symbol_exists("nan", "math.h")) + + set_define("HAVE_DOPRNT", check_symbol_exists("_doprnt", "stdio.h")) + set_define("HAVE_SNPRINTF", check_symbol_exists("snprintf", "stdio.h")) + set_define( + "HAVE_VASPRINTF", + check_symbol_exists("vasprintf", "stdio.h", flags=["-D_GNU_SOURCE"]), + ) + set_define("HAVE_VSNPRINTF", check_symbol_exists("vsnprintf", "stdio.h")) + set_define("HAVE_VPRINTF", check_symbol_exists("vprintf", "stdio.h")) + + set_define("HAVE_OPEN", check_symbol_exists("open", "fcntl.h", when=have_fcntl_h)) + set_define( + "HAVE_REALLOC", + check_symbol_exists("realloc", "stdlib.h", when=have_stdlib_h), + ) + set_define( + "HAVE_SETLOCALE", + check_symbol_exists("setlocale", "locale.h", when=have_locale_h), + ) + set_define( + "HAVE_USELOCALE", + check_symbol_exists("uselocale", "locale.h", when=have_locale_h), + ) + set_define( + "HAVE_STRCASECMP", + check_symbol_exists("strcasecmp", "strings.h", when=have_strings_h), + ) + set_define( + "HAVE_STRNCASECMP", + check_symbol_exists("strncasecmp", "strings.h", when=have_strings_h), + ) + set_define("HAVE_STRDUP", check_symbol_exists("strdup", "string.h", when=have_string_h)) diff --git a/comm/third_party/patches/rnp/bug1843535_gcc13_missing_header.patch b/comm/third_party/patches/rnp/bug1843535_gcc13_missing_header.patch new file mode 100644 index 0000000000..b2245fef6b --- /dev/null +++ b/comm/third_party/patches/rnp/bug1843535_gcc13_missing_header.patch @@ -0,0 +1,27 @@ +diff --git a/src/libsexp/include/sexp/sexp-error.h b/src/libsexp/include/sexp/sexp-error.h +--- a/src/libsexp/include/sexp/sexp-error.h ++++ b/src/libsexp/include/sexp/sexp-error.h +@@ -24,16 +24,17 @@ + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + #pragma once + ++#include + #include + #include + #include + + namespace sexp { + + class sexp_exception_t : public std::exception { + public: +diff --git a/version.txt b/version.txt +--- a/version.txt ++++ b/version.txt +@@ -1,1 +1,1 @@ +-0.17.0 ++0.17.0+PR2073 diff --git a/comm/third_party/python/fluent.migratetb/LICENSE b/comm/third_party/python/fluent.migratetb/LICENSE new file mode 100644 index 0000000000..f6a01a51d0 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/LICENSE @@ -0,0 +1,13 @@ +Copyright 2016 Mozilla Foundation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/comm/third_party/python/fluent.migratetb/PKG-INFO b/comm/third_party/python/fluent.migratetb/PKG-INFO new file mode 100644 index 0000000000..a717c518eb --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/PKG-INFO @@ -0,0 +1,61 @@ +Metadata-Version: 2.1 +Name: fluent.migratetb +Version: 0.11.2 +Summary: Toolchain to migrate legacy translation to Fluent. (Thunderbird fork) +Home-page: https://github.com/jfx2006/tb-fluent-migrate/ +Author: Mozilla +Author-email: l10n-drivers@mozilla.org +License: APL 2 +Keywords: fluent,localization,l10n +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Python :: 3.7 +Description-Content-Type: text/markdown +Provides-Extra: hg +License-File: LICENSE + +# Fluent Migration Tools - Thunderbird Fork + +Programmatically create Fluent files from existing content in both legacy +and Fluent formats. Use recipes written in Python to migrate content for each +of your localizations. + +This is a fork for performing Thunderbird string migrations. Usage is slightly +different than upsteam due to the use of a monorepo. + +`migrate-l10n` is a CLI script which uses the `fluent.migrate` module under +the hood to run migrations on existing translations. + +`validate-l10n-recipe` is a CLI script to test a migration recipe for common +errors, without trying to apply it. + +Installation +------------ + +- Clone this repo somewhere + +- pip install "/tb-fluent-migrate[hg]" + +Alternatively, install right from the repo: + +- pip install "fluent.migrate[hg] @ git+https://github.com/jfx2006/tb-fluent-migrate" + + +Usage +----- + +Migrations consist of _recipes_, which are applied to a _localization repository_, based on _template files_. +You can find recipes for Thunderbird in `comm-central/python/l10n/tb_fluent_migrations/`, +the reference repository is [comm-strings-quarantine](https://hg.mozilla.org/projects/comm-strings-quarantine/) or _quarantine_. +You apply those migrations to l10n repositories in [comm-l10n](https://hg.mozilla.org/projects/comm-l10n/). + +The migrations are run as python modules, so you need to have their file location in `PYTHONPATH`. + +An example would look like + + $ migrate-l10n --locale it --reference-dir comm-strings-quarantine --localization-dir comm-l10n bug_1802387_langpack_defines + +Upstream +-------- +https://hg.mozilla.org/l10n/fluent-migration/ diff --git a/comm/third_party/python/fluent.migratetb/README.md b/comm/third_party/python/fluent.migratetb/README.md new file mode 100644 index 0000000000..f8ca21f808 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/README.md @@ -0,0 +1,44 @@ +# Fluent Migration Tools - Thunderbird Fork + +Programmatically create Fluent files from existing content in both legacy +and Fluent formats. Use recipes written in Python to migrate content for each +of your localizations. + +This is a fork for performing Thunderbird string migrations. Usage is slightly +different than upsteam due to the use of a monorepo. + +`migrate-l10n` is a CLI script which uses the `fluent.migrate` module under +the hood to run migrations on existing translations. + +`validate-l10n-recipe` is a CLI script to test a migration recipe for common +errors, without trying to apply it. + +Installation +------------ + +- Clone this repo somewhere + +- pip install "/tb-fluent-migrate[hg]" + +Alternatively, install right from the repo: + +- pip install "fluent.migrate[hg] @ git+https://github.com/jfx2006/tb-fluent-migrate" + + +Usage +----- + +Migrations consist of _recipes_, which are applied to a _localization repository_, based on _template files_. +You can find recipes for Thunderbird in `comm-central/python/l10n/tb_fluent_migrations/`, +the reference repository is [comm-strings-quarantine](https://hg.mozilla.org/projects/comm-strings-quarantine/) or _quarantine_. +You apply those migrations to l10n repositories in [comm-l10n](https://hg.mozilla.org/projects/comm-l10n/). + +The migrations are run as python modules, so you need to have their file location in `PYTHONPATH`. + +An example would look like + + $ migrate-l10n --locale it --reference-dir comm-strings-quarantine --localization-dir comm-l10n bug_1802387_langpack_defines + +Upstream +-------- +https://hg.mozilla.org/l10n/fluent-migration/ diff --git a/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/PKG-INFO b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/PKG-INFO new file mode 100644 index 0000000000..a717c518eb --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/PKG-INFO @@ -0,0 +1,61 @@ +Metadata-Version: 2.1 +Name: fluent.migratetb +Version: 0.11.2 +Summary: Toolchain to migrate legacy translation to Fluent. (Thunderbird fork) +Home-page: https://github.com/jfx2006/tb-fluent-migrate/ +Author: Mozilla +Author-email: l10n-drivers@mozilla.org +License: APL 2 +Keywords: fluent,localization,l10n +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Python :: 3.7 +Description-Content-Type: text/markdown +Provides-Extra: hg +License-File: LICENSE + +# Fluent Migration Tools - Thunderbird Fork + +Programmatically create Fluent files from existing content in both legacy +and Fluent formats. Use recipes written in Python to migrate content for each +of your localizations. + +This is a fork for performing Thunderbird string migrations. Usage is slightly +different than upsteam due to the use of a monorepo. + +`migrate-l10n` is a CLI script which uses the `fluent.migrate` module under +the hood to run migrations on existing translations. + +`validate-l10n-recipe` is a CLI script to test a migration recipe for common +errors, without trying to apply it. + +Installation +------------ + +- Clone this repo somewhere + +- pip install "/tb-fluent-migrate[hg]" + +Alternatively, install right from the repo: + +- pip install "fluent.migrate[hg] @ git+https://github.com/jfx2006/tb-fluent-migrate" + + +Usage +----- + +Migrations consist of _recipes_, which are applied to a _localization repository_, based on _template files_. +You can find recipes for Thunderbird in `comm-central/python/l10n/tb_fluent_migrations/`, +the reference repository is [comm-strings-quarantine](https://hg.mozilla.org/projects/comm-strings-quarantine/) or _quarantine_. +You apply those migrations to l10n repositories in [comm-l10n](https://hg.mozilla.org/projects/comm-l10n/). + +The migrations are run as python modules, so you need to have their file location in `PYTHONPATH`. + +An example would look like + + $ migrate-l10n --locale it --reference-dir comm-strings-quarantine --localization-dir comm-l10n bug_1802387_langpack_defines + +Upstream +-------- +https://hg.mozilla.org/l10n/fluent-migration/ diff --git a/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/SOURCES.txt b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/SOURCES.txt new file mode 100644 index 0000000000..075b179bd3 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/SOURCES.txt @@ -0,0 +1,24 @@ +LICENSE +README.md +setup.cfg +setup.py +fluent/__init__.py +fluent.migratetb.egg-info/PKG-INFO +fluent.migratetb.egg-info/SOURCES.txt +fluent.migratetb.egg-info/dependency_links.txt +fluent.migratetb.egg-info/entry_points.txt +fluent.migratetb.egg-info/requires.txt +fluent.migratetb.egg-info/top_level.txt +fluent/migratetb/__init__.py +fluent/migratetb/_context.py +fluent/migratetb/blame.py +fluent/migratetb/changesets.py +fluent/migratetb/context.py +fluent/migratetb/errors.py +fluent/migratetb/evaluator.py +fluent/migratetb/helpers.py +fluent/migratetb/merge.py +fluent/migratetb/tool.py +fluent/migratetb/transforms.py +fluent/migratetb/util.py +fluent/migratetb/validator.py \ No newline at end of file diff --git a/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/dependency_links.txt b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/dependency_links.txt new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/entry_points.txt b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/entry_points.txt new file mode 100644 index 0000000000..ad6c985e8f --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +migrate-l10n-tb = fluent.migratetb.tool:cli +validate-l10n-tb-recipe = fluent.migratetb.validator:cli diff --git a/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/requires.txt b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/requires.txt new file mode 100644 index 0000000000..84a38c8fe2 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/requires.txt @@ -0,0 +1,6 @@ +compare-locales<9.0,>=8.1 +fluent.syntax<0.19,>=0.18.0 +six + +[hg] +python-hglib diff --git a/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/top_level.txt b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/top_level.txt new file mode 100644 index 0000000000..a3582d405a --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent.migratetb.egg-info/top_level.txt @@ -0,0 +1 @@ +fluent diff --git a/comm/third_party/python/fluent.migratetb/fluent/__init__.py b/comm/third_party/python/fluent.migratetb/fluent/__init__.py new file mode 100644 index 0000000000..69e3be50da --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/__init__.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/__init__.py new file mode 100644 index 0000000000..fead341500 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/__init__.py @@ -0,0 +1,5 @@ +# coding=utf8 + +from .transforms import ( # noqa: F401 + CONCAT, COPY, COPY_PATTERN, PLURALS, REPLACE, REPLACE_IN_TEXT +) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/_context.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/_context.py new file mode 100644 index 0000000000..53a771d58a --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/_context.py @@ -0,0 +1,333 @@ +# coding=utf8 +from __future__ import unicode_literals +from __future__ import absolute_import + +import os +import codecs +from functools import partial +import logging +from six.moves import zip_longest + +import fluent.syntax.ast as FTL +from fluent.syntax.parser import FluentParser +from fluent.syntax.serializer import FluentSerializer +from compare_locales.parser import getParser +from compare_locales.plurals import get_plural + +from .evaluator import Evaluator +from .merge import merge_resource +from .errors import ( + UnreadableReferenceError, +) + + +class InternalContext(object): + """Internal context for merging translation resources. + + For the public interface, see `context.MigrationContext`. + """ + + def __init__( + self, lang, reference_dir, localization_dir, enforce_translated=False + ): + self.fluent_parser = FluentParser(with_spans=False) + self.fluent_serializer = FluentSerializer() + + # An iterable of plural category names relevant to the context's + # language. E.g. ('one', 'other') for English. + self.plural_categories = get_plural(lang) + if self.plural_categories is None: + logger = logging.getLogger('migrate') + logger.warning( + 'Plural rule for "{}" is not defined in ' + 'compare-locales'.format(lang)) + self.plural_categories = ('one', 'other') + + self.enforce_translated = enforce_translated + # Parsed input resources stored by resource path. + self.reference_resources = {} + self.localization_resources = {} + self.target_resources = {} + + # An iterable of `FTL.Message` objects some of whose nodes can be the + # transform operations. + self.transforms = {} + + # The evaluator instance is an AST transformer capable of walking an + # AST hierarchy and evaluating nodes which are migration Transforms. + self.evaluator = Evaluator(self) + + def read_ftl_resource(self, path): + """Read an FTL resource and parse it into an AST.""" + f = codecs.open(path, 'r', 'utf8') + try: + contents = f.read() + except UnicodeDecodeError as err: + logger = logging.getLogger('migrate') + logger.warning('Unable to read file {}: {}'.format(path, err)) + raise err + finally: + f.close() + + ast = self.fluent_parser.parse(contents) + + annots = [ + annot + for entry in ast.body + if isinstance(entry, FTL.Junk) + for annot in entry.annotations + ] + + if len(annots): + logger = logging.getLogger('migrate') + for annot in annots: + msg = annot.message + logger.warning('Syntax error in {}: {}'.format(path, msg)) + + return ast + + def read_legacy_resource(self, path): + """Read a legacy resource and parse it into a dict.""" + parser = getParser(path) + parser.readFile(path) + # Transform the parsed result which is an iterator into a dict. + return { + entity.key: entity.val for entity in parser + if entity.localized or self.enforce_translated + } + + def read_reference_ftl(self, path): + """Read and parse a reference FTL file. + + A missing resource file is a fatal error and will raise an + UnreadableReferenceError. + """ + fullpath = os.path.join(self.reference_dir, path) + try: + return self.read_ftl_resource(fullpath) + except IOError: + error_message = 'Missing reference file: {}'.format(fullpath) + logging.getLogger('migrate').error(error_message) + raise UnreadableReferenceError(error_message) + except UnicodeDecodeError as err: + error_message = 'Error reading file {}: {}'.format(fullpath, err) + logging.getLogger('migrate').error(error_message) + raise UnreadableReferenceError(error_message) + + def read_localization_ftl(self, path): + """Read and parse an existing localization FTL file. + + Create a new FTL.Resource if the file doesn't exist or can't be + decoded. + """ + fullpath = os.path.join(self.localization_dir, path) + try: + return self.read_ftl_resource(fullpath) + except IOError: + logger = logging.getLogger('migrate') + logger.info( + 'Localization file {} does not exist and ' + 'it will be created'.format(path)) + return FTL.Resource() + except UnicodeDecodeError: + logger = logging.getLogger('migrate') + logger.warning( + 'Localization file {} has broken encoding. ' + 'It will be re-created and some translations ' + 'may be lost'.format(path)) + return FTL.Resource() + + def maybe_add_localization(self, path): + """Add a localization resource to migrate translations from. + + Uses a compare-locales parser to create a dict of (key, string value) + tuples. + For Fluent sources, we store the AST. + """ + try: + fullpath = os.path.join(self.localization_dir, path) + if not fullpath.endswith('.ftl'): + collection = self.read_legacy_resource(fullpath) + else: + collection = self.read_ftl_resource(fullpath) + except IOError: + logger = logging.getLogger('migrate') + logger.warning('Missing localization file: {}'.format(path)) + else: + self.localization_resources[path] = collection + + def get_legacy_source(self, path, key): + """Get an entity value from a localized legacy source. + + Used by the `Source` transform. + """ + resource = self.localization_resources[path] + return resource.get(key, None) + + def get_fluent_source_pattern(self, path, key): + """Get a pattern from a localized Fluent source. + + If the key contains a `.`, does an attribute lookup. + Used by the `COPY_PATTERN` transform. + """ + resource = self.localization_resources[path] + msg_key, _, attr_key = key.partition('.') + found = None + for entry in resource.body: + if isinstance(entry, (FTL.Message, FTL.Term)): + if entry.id.name == msg_key: + found = entry + break + if found is None: + return None + if not attr_key: + return found.value + for attribute in found.attributes: + if attribute.id.name == attr_key: + return attribute.value + return None + + def messages_equal(self, res1, res2): + """Compare messages and terms of two FTL resources. + + Uses FTL.BaseNode.equals to compare all messages/terms + in two FTL resources. + If the order or number of messages differ, the result is also False. + """ + def message_id(message): + "Return the message's identifer name for sorting purposes." + return message.id.name + + messages1 = sorted( + (entry for entry in res1.body + if isinstance(entry, FTL.Message) + or isinstance(entry, FTL.Term)), + key=message_id) + messages2 = sorted( + (entry for entry in res2.body + if isinstance(entry, FTL.Message) + or isinstance(entry, FTL.Term)), + key=message_id) + for msg1, msg2 in zip_longest(messages1, messages2): + if msg1 is None or msg2 is None: + return False + if not msg1.equals(msg2): + return False + return True + + def merge_changeset(self, changeset=None, known_translations=None): + """Return a generator of FTL ASTs for the changeset. + + The input data must be configured earlier using the `add_*` methods. + if given, `changeset` must be a set of (path, key) tuples describing + which legacy translations are to be merged. If `changeset` is None, + all legacy translations will be allowed to be migrated in a single + changeset. + + We use the `in_changeset` method to determine if a message should be + migrated for the given changeset. + + Given `changeset`, return a dict whose keys are resource paths and + values are `FTL.Resource` instances. The values will also be used to + update this context's existing localization resources. + """ + + if changeset is None: + # Merge all known legacy translations. Used in tests. + changeset = { + (path, key) + for path, strings in self.localization_resources.items() + if not path.endswith('.ftl') + for key in strings.keys() + } + + if known_translations is None: + known_translations = changeset + + for path, reference in self.reference_resources.items(): + current = self.target_resources[path] + transforms = self.transforms.get(path, []) + in_changeset = partial( + self.in_changeset, changeset, known_translations, path) + + # Merge legacy translations with the existing ones using the + # reference as a template. + snapshot = merge_resource( + self, reference, current, transforms, in_changeset + ) + + # Skip this path if the messages in the merged snapshot are + # identical to those in the current state of the localization file. + # This may happen when: + # + # - none of the transforms is in the changset, or + # - all messages which would be migrated by the context's + # transforms already exist in the current state. + if self.messages_equal(current, snapshot): + continue + + # Store the merged snapshot on the context so that the next merge + # already takes it into account as the existing localization. + self.target_resources[path] = snapshot + + # The result for this path is a complete `FTL.Resource`. + yield path, snapshot + + def in_changeset(self, changeset, known_translations, path, ident): + """Check if a message should be migrated in this changeset. + + The message is identified by path and ident. + + + A message will be migrated only if all of its dependencies + are present in the currently processed changeset. + + If a transform defined for this message points to a missing + legacy translation, this message will not be merged. The + missing legacy dependency won't be present in the changeset. + + This also means that partially translated messages (e.g. + constructed from two legacy strings out of which only one is + avaiable) will never be migrated. + """ + message_deps = self.dependencies.get((path, ident), None) + + # Don't merge if we don't have a transform for this message. + if message_deps is None: + return False + + # As a special case, if a transform exists but has no + # dependecies, it's a hardcoded `FTL.Node` which doesn't + # migrate any existing translation but rather creates a new + # one. Merge it. + if len(message_deps) == 0: + return True + + # Make sure all the dependencies are present in the current + # changeset. Partial migrations are not currently supported. + # See https://bugzilla.mozilla.org/show_bug.cgi?id=1321271 + # We only return True if our current changeset touches + # the transform, and we have all of the dependencies. + active_deps = message_deps & changeset + available_deps = message_deps & known_translations + return active_deps and message_deps == available_deps + + def serialize_changeset(self, changeset, known_translations=None): + """Return a dict of serialized FTLs for the changeset. + + Given `changeset`, return a dict whose keys are resource paths and + values are serialized FTL snapshots. + """ + + return { + path: self.fluent_serializer.serialize(snapshot) + for path, snapshot in self.merge_changeset( + changeset, known_translations + ) + } + + def evaluate(self, node): + return self.evaluator.visit(node) + + +logging.basicConfig() diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/blame.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/blame.py new file mode 100644 index 0000000000..9aa24e0c67 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/blame.py @@ -0,0 +1,102 @@ +# coding=utf8 +from __future__ import unicode_literals +from __future__ import absolute_import + +import argparse +import json +import os + +from compare_locales.parser import getParser, Junk +from compare_locales.parser.fluent import FluentEntity +from compare_locales import mozpath +import hglib +from hglib.util import b, cmdbuilder + + +class Blame(object): + def __init__(self, client, cwd=None): + self.client = client + self._cwd = cwd + self.users = [] + self.blame = {} + + @property + def cwd(self): + if self._cwd is None: + return self.client.root() + else: + return mozpath.join(self.client.root(), self._cwd.encode("utf-8")) + + def file_path_relative(self, file_path): + if self._cwd is None: + return file_path + check_val = f"{self._cwd}" + if file_path.startswith(check_val): + return file_path[len(check_val)+1:] + return file_path + + def attribution(self, file_paths): + + args = cmdbuilder( + b('annotate'), *[b(p) for p in file_paths], template='json', + date=True, user=True, cwd=self.cwd) + blame_json = self.client.rawcommand(args) + file_blames = json.loads(blame_json) + + for file_blame in file_blames: + self.handleFile(file_blame) + + return {'authors': self.users, + 'blame': self.blame} + + def handleFile(self, file_blame): + path = mozpath.normsep(self.file_path_relative(file_blame['path'])) + + + try: + parser = getParser(path) + except UserWarning: + return + + self.blame[path] = {} + + self.readFile(parser, path) + entities = parser.parse() + for e in entities: + if isinstance(e, Junk): + continue + if e.val_span: + key_vals = [(e.key, e.val_span)] + else: + key_vals = [] + if isinstance(e, FluentEntity): + key_vals += [ + ('{}.{}'.format(e.key, attr.key), attr.val_span) + for attr in e.attributes + ] + for key, (val_start, val_end) in key_vals: + entity_lines = file_blame['lines'][ + (e.ctx.linecol(val_start)[0] - 1):e.ctx.linecol(val_end)[0] + ] + # ignore timezone + entity_lines.sort(key=lambda blame: -blame['date'][0]) + line_blame = entity_lines[0] + user = line_blame['user'] + timestamp = line_blame['date'][0] # ignore timezone + if user not in self.users: + self.users.append(user) + userid = self.users.index(user) + self.blame[path][key] = [userid, timestamp] + + def readFile(self, parser, path): + parser.readFile(os.path.join(self.cwd.decode('utf-8'), path)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('repo_path') + parser.add_argument('file_path', nargs='+') + args = parser.parse_args() + blame = Blame(hglib.open(args.repo_path)) + attrib = blame.attribution(args.file_path) + print(json.dumps(attrib, indent=4, separators=(',', ': '))) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/changesets.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/changesets.py new file mode 100644 index 0000000000..e4ad95f2d1 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/changesets.py @@ -0,0 +1,59 @@ +# coding=utf8 +from __future__ import absolute_import + +import time + + +def by_first_commit(item): + """Order two changesets by their first commit date.""" + return item['first_commit'] + + +def convert_blame_to_changesets(blame_json): + """Convert a blame dict into a list of changesets. + + The blame information in `blame_json` should be a dict of the following + structure: + + { + 'authors': [ + 'A.N. Author ', + ], + 'blame': { + 'path/one': { + 'key1': [0, 1346095921.0], + }, + } + } + + It will be transformed into a list of changesets which can be fed into + `InternalContext.serialize_changeset`: + + [ + { + 'author': 'A.N. Author ', + 'first_commit': 1346095921.0, + 'changes': { + ('path/one', 'key1'), + } + }, + ] + + """ + now = time.time() + changesets = [ + { + 'author': author, + 'first_commit': now, + 'changes': set() + } for author in blame_json['authors'] + ] + + for path, keys_info in blame_json['blame'].items(): + for key, (author_index, timestamp) in keys_info.items(): + changeset = changesets[author_index] + changeset['changes'].add((path, key)) + if timestamp < changeset['first_commit']: + changeset['first_commit'] = timestamp + + return sorted(changesets, key=by_first_commit) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/context.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/context.py new file mode 100644 index 0000000000..de54b52fe1 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/context.py @@ -0,0 +1,152 @@ +# coding=utf8 +from __future__ import unicode_literals +from __future__ import absolute_import + +import logging + +import fluent.syntax.ast as FTL +from fluent.migratetb.util import fold + +from .transforms import Source +from .util import get_message, skeleton +from .errors import ( + EmptyLocalizationError, + UnreadableReferenceError, +) +from ._context import InternalContext + + +__all__ = [ + 'EmptyLocalizationError', + 'UnreadableReferenceError', + 'MigrationContext', +] + + +class MigrationContext(InternalContext): + """Stateful context for merging translation resources. + + `MigrationContext` must be configured with the target locale and the + directory locations of the input data. + + The transformation takes four types of input data: + + - The en-US FTL reference files which will be used as templates for + message order, comments and sections. If the reference_dir is None, + the migration will create Messages and Terms in the order given by + the transforms. + + - The current FTL files for the given locale. + + - A list of `FTL.Message` or `FTL.Term` objects some of whose nodes + are special helper or transform nodes: + + helpers: VARIABLE_REFERENCE, MESSAGE_REFERENCE, TERM_REFERENCE + transforms: COPY, REPLACE_IN_TEXT, REPLACE, PLURALS, CONCAT + fluent value helper: COPY_PATTERN + + The legacy (DTD, properties) translation files are deduced by the + dependencies in the transforms. The translations from these files will be + read from the localization_dir and transformed into FTL and merged + into the existing FTL files for the given language. + """ + + def __init__( + self, locale, reference_dir, localization_dir, enforce_translated=False + ): + super(MigrationContext, self).__init__( + locale, reference_dir, localization_dir, + enforce_translated=enforce_translated + ) + self.locale = locale + # Paths to directories with input data, relative to CWD. + self.reference_dir = reference_dir + self.localization_dir = localization_dir + + # A dict whose keys are `(path, key)` tuples corresponding to target + # FTL translations, and values are sets of `(path, key)` tuples + # corresponding to localized entities which will be migrated. + self.dependencies = {} + + def add_transforms(self, target, reference, transforms): + """Define transforms for target using reference as template. + + `target` is a path of the destination FTL file relative to the + localization directory. `reference` is a path to the template FTL + file relative to the reference directory. + + Each transform is an extended FTL node with `Transform` nodes as some + values. Transforms are stored in their lazy AST form until + `merge_changeset` is called, at which point they are evaluated to real + FTL nodes with migrated translations. + + Each transform is scanned for `Source` nodes which will be used to + build the list of dependencies for the transformed message. + + For transforms that merely copy legacy messages or Fluent patterns, + using `fluent.migratetb.helpers.transforms_from` is recommended. + """ + def get_sources(acc, cur): + if isinstance(cur, Source): + acc.add((cur.path, cur.key)) + return acc + + if self.reference_dir is None: + # Add skeletons to resource body for each transform + # if there's no reference. + reference_ast = self.reference_resources.get(target) + if reference_ast is None: + reference_ast = FTL.Resource() + reference_ast.body.extend( + skeleton(transform) for transform in transforms + ) + else: + reference_ast = self.read_reference_ftl(reference) + self.reference_resources[target] = reference_ast + + for node in transforms: + ident = node.id.name + # Scan `node` for `Source` nodes and collect the information they + # store into a set of dependencies. + dependencies = fold(get_sources, node, set()) + # Set these sources as dependencies for the current transform. + self.dependencies[(target, ident)] = dependencies + + # The target Fluent message should exist in the reference file. If + # it doesn't, it's probably a typo. + # Of course, only if we're having a reference. + if self.reference_dir is None: + continue + if get_message(reference_ast.body, ident) is None: + logger = logging.getLogger('migrate') + logger.warning( + '{} "{}" was not found in {}'.format( + type(node).__name__, ident, reference)) + + # Keep track of localization resource paths which were defined as + # sources in the transforms. + expected_paths = set() + + # Read all legacy translation files defined in Source transforms. This + # may fail but a single missing legacy resource doesn't mean that the + # migration can't succeed. + for dependencies in self.dependencies.values(): + for path in set(path for path, _ in dependencies): + expected_paths.add(path) + self.maybe_add_localization(path) + + # However, if all legacy resources are missing, bail out early. There + # are no translations to migrate. We'd also get errors in hg annotate. + if len(expected_paths) > 0 and len(self.localization_resources) == 0: + error_message = 'No localization files were found' + logging.getLogger('migrate').error(error_message) + raise EmptyLocalizationError(error_message) + + # Add the current transforms to any other transforms added earlier for + # this path. + path_transforms = self.transforms.setdefault(target, []) + path_transforms += transforms + + if target not in self.target_resources: + target_ast = self.read_localization_ftl(target) + self.target_resources[target] = target_ast diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/errors.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/errors.py new file mode 100644 index 0000000000..dcc3025377 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/errors.py @@ -0,0 +1,22 @@ +class SkipTransform(RuntimeError): + pass + + +class MigrationError(ValueError): + pass + + +class EmptyLocalizationError(MigrationError): + pass + + +class NotSupportedError(MigrationError): + pass + + +class UnreadableReferenceError(MigrationError): + pass + + +class InvalidTransformError(MigrationError): + pass diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/evaluator.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/evaluator.py new file mode 100644 index 0000000000..90c626f933 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/evaluator.py @@ -0,0 +1,28 @@ +from fluent.syntax import ast as FTL +from fluent.syntax.visitor import Transformer + +from .transforms import Transform + + +class Evaluator(Transformer): + """An AST transformer for evaluating migration Transforms. + + An AST transformer (i.e. a visitor capable of modifying the AST) which + walks an AST hierarchy and evaluates nodes which are migration Transforms. + """ + + def __init__(self, ctx): + self.ctx = ctx + + def visit(self, node): + if not isinstance(node, FTL.BaseNode): + return node + + if isinstance(node, Transform): + # Some transforms don't expect other transforms as children. + # Evaluate the children first. + transform = self.generic_visit(node) + # Then, evaluate this transform. + return transform(self.ctx) + + return self.generic_visit(node) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/helpers.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/helpers.py new file mode 100644 index 0000000000..848c541da4 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/helpers.py @@ -0,0 +1,176 @@ +# coding=utf8 +"""Fluent AST helpers. + +The functions defined in this module offer a shorthand for defining common AST +nodes. + +They take a string argument and immediately return a corresponding AST node. +(As opposed to Transforms which are AST nodes on their own and only return the +migrated AST nodes when they are evaluated by a MigrationContext.) """ + +from __future__ import unicode_literals +from __future__ import absolute_import + +from fluent.syntax import FluentParser, ast as FTL +from fluent.syntax.visitor import Transformer +from .transforms import Transform, CONCAT, COPY, COPY_PATTERN, REPLACE +from .errors import NotSupportedError, InvalidTransformError + + +def VARIABLE_REFERENCE(name): + """Create an ExternalArgument expression.""" + + return FTL.VariableReference( + id=FTL.Identifier(name) + ) + + +def MESSAGE_REFERENCE(name): + """Create a MessageReference expression. + + If the passed name contains a `.`, we're generating + a message reference with an attribute. + """ + if '.' in name: + name, attribute = name.split('.') + attribute = FTL.Identifier(attribute) + else: + attribute = None + + return FTL.MessageReference( + id=FTL.Identifier(name), + attribute=attribute, + ) + + +def TERM_REFERENCE(name): + """Create a TermReference expression.""" + + return FTL.TermReference( + id=FTL.Identifier(name) + ) + + +class IntoTranforms(Transformer): + IMPLICIT_TRANSFORMS = ("CONCAT",) + FORBIDDEN_TRANSFORMS = ("PLURALS",) + + def __init__(self, substitutions): + self.substitutions = substitutions + + def visit_Junk(self, node): + anno = node.annotations[0] + raise InvalidTransformError( + "Transform contains parse error: {}, at {}".format( + anno.message, anno.span.start)) + + def visit_FunctionReference(self, node): + name = node.id.name + if name in self.IMPLICIT_TRANSFORMS: + raise NotSupportedError( + "{} may not be used with transforms_from(). It runs " + "implicitly on all Patterns anyways.".format(name)) + if name in self.FORBIDDEN_TRANSFORMS: + raise NotSupportedError( + "{} may not be used with transforms_from(). It requires " + "additional logic in Python code.".format(name)) + if name in ('COPY', 'COPY_PATTERN', 'REPLACE'): + args = ( + self.into_argument(arg) for arg in node.arguments.positional + ) + kwargs = { + arg.name.name: self.into_argument(arg.value) + for arg in node.arguments.named} + if name == 'COPY': + return COPY(*args, **kwargs) + elif name == 'REPLACE': + return REPLACE(*args, **kwargs) + return COPY_PATTERN(*args, **kwargs) + return self.generic_visit(node) + + def visit_Placeable(self, node): + """If the expression is a Transform, replace this Placeable + with the Transform it's holding. + Transforms evaluate to Patterns, which are flattened as + elements of Patterns in Transform.pattern_of, but only + one level deep. + """ + node = self.generic_visit(node) + if isinstance(node.expression, Transform): + return node.expression + return node + + def visit_Pattern(self, node): + """Replace the Pattern with CONCAT which is more accepting of its + elements. CONCAT takes PatternElements, Expressions and other + Patterns (e.g. returned from evaluating transforms). + """ + node = self.generic_visit(node) + return CONCAT(*node.elements) + + def into_argument(self, node): + """Convert AST node into an argument to migration transforms.""" + if isinstance(node, FTL.StringLiteral): + # Special cases for booleans which don't exist in Fluent. + if node.value == "True": + return True + if node.value == "False": + return False + return node.value + if isinstance(node, FTL.MessageReference): + try: + return self.substitutions[node.id.name] + except KeyError: + raise InvalidTransformError( + "Unknown substitution in COPY: {}".format( + node.id.name)) + else: + raise InvalidTransformError( + "Invalid argument passed to COPY: {}".format( + type(node).__name__)) + + +def transforms_from(ftl, **substitutions): + """Parse FTL code into a list of Message nodes with Transforms. + + The FTL may use a fabricated COPY function inside of placeables which + will be converted into actual COPY migration transform. + + new-key = Hardcoded text { COPY("filepath.dtd", "string.key") } + + For convenience, COPY may also refer to transforms_from's keyword + arguments via the MessageReference syntax: + + transforms_from(\""" + new-key = Hardcoded text { COPY(file_dtd, "string.key") } + \""", file_dtd="very/long/path/to/a/file.dtd") + + REPLACE may also be used. The only tested use case is to do brand string + replacements from DTD strings. + + + + First define a dictionary with the replacements outside of the migrate + function like (must be wrapped in a dict() function call): + + about_replacements = dict({ + "&brandShortName;": TERM_REFERENCE("brand-short-name"), + }) + + Note: In the TERM_REFERENCE replacement, omit the initial "-". It winds up + in the final result somehow. + + Then, use transforms_from: + + transforms_from(\""" + update-no-updates-found = { REPLACE(source, "update.noUpdatesFound", about_replacements) } + \""", source=source, about_replacements=about_replacements) + + If doing multiple string migrations in a single transforms_from template, + your replacements dictionary can have multiple key, value pairs and be used + for all REPLACE transforms. + """ + + parser = FluentParser(with_spans=False) + resource = parser.parse(ftl) + return IntoTranforms(substitutions).visit(resource).body diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/merge.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/merge.py new file mode 100644 index 0000000000..b4575f0ca7 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/merge.py @@ -0,0 +1,59 @@ +# coding=utf8 +from __future__ import unicode_literals +from __future__ import absolute_import + +import fluent.syntax.ast as FTL + +from .errors import SkipTransform +from .util import get_message, get_transform + + +def merge_resource(ctx, reference, current, transforms, in_changeset): + """Transform legacy translations into FTL. + + Use the `reference` FTL AST as a template. For each en-US string in the + reference, first check for an existing translation in the current FTL + `localization` and use it if it's present; then if the string has + a transform defined in the migration specification and if it's in the + currently processed changeset, evaluate the transform. + """ + + def merge_body(body): + return [ + entry + for entry in map(merge_entry, body) + if entry is not None + ] + + def merge_entry(entry): + # All standalone comments will be merged. + if isinstance(entry, FTL.BaseComment): + return entry + + # Ignore Junk + if isinstance(entry, FTL.Junk): + return None + + ident = entry.id.name + + # If the message is present in the existing localization, we add it to + # the resulting resource. This ensures consecutive merges don't remove + # translations but rather create supersets of them. + existing = get_message(current.body, ident) + if existing is not None: + return existing + + transform = get_transform(transforms, ident) + + # Make sure this message is supposed to be migrated as part of the + # current changeset. + if transform is not None and in_changeset(ident): + if transform.comment is None: + transform.comment = entry.comment + try: + return ctx.evaluate(transform) + except SkipTransform: + return None + + body = merge_body(reference.body) + return FTL.Resource(body) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/tool.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/tool.py new file mode 100644 index 0000000000..62ffdfdad6 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/tool.py @@ -0,0 +1,185 @@ +# coding=utf8 + +import os +import logging +import argparse +from contextlib import contextmanager +import importlib +import sys + +import hglib +import six + +from fluent.migratetb.context import MigrationContext +from fluent.migratetb.errors import MigrationError +from fluent.migratetb.changesets import convert_blame_to_changesets +from fluent.migratetb.blame import Blame + + +@contextmanager +def dont_write_bytecode(): + _dont_write_bytecode = sys.dont_write_bytecode + sys.dont_write_bytecode = True + yield + sys.dont_write_bytecode = _dont_write_bytecode + + +class Migrator(object): + def __init__(self, locale, reference_dir, localization_dir, dry_run): + self.locale = locale + self.reference_dir = reference_dir + self.localization_repo = localization_dir + self.localization_dir = os.path.join(localization_dir, locale) + self.dry_run = dry_run + self._client = None + + @property + def client(self): + if self._client is None: + self._client = hglib.open(self.localization_repo, 'utf-8') + return self._client + + def close(self): + # close hglib.client, if we cached one. + if self._client is not None: + self._client.close() + + def run(self, migration): + print('\nRunning migration {} for {}'.format( + migration.__name__, self.locale)) + + # For each migration create a new context. + ctx = MigrationContext( + self.locale, self.reference_dir, self.localization_dir + ) + + try: + # Add the migration spec. + migration.migrate(ctx) + except MigrationError as e: + print(' Skipping migration {} for {}:\n {}'.format( + migration.__name__, self.locale, e)) + return + + # Keep track of how many changesets we're committing. + index = 0 + description_template = migration.migrate.__doc__ + + # Annotate localization files used as sources by this migration + # to preserve attribution of translations. + files = ctx.localization_resources.keys() + blame = Blame(self.client, self.locale).attribution(files) + changesets = convert_blame_to_changesets(blame) + known_legacy_translations = set() + + for changeset in changesets: + snapshot = self.snapshot( + ctx, changeset['changes'], known_legacy_translations + ) + if not snapshot: + continue + self.serialize_changeset(snapshot) + index += 1 + self.commit_changeset( + description_template, changeset['author'], index + ) + + def snapshot(self, ctx, changes_in_changeset, known_legacy_translations): + '''Run the migration for the changeset, with the set of + this and all prior legacy translations. + ''' + known_legacy_translations.update(changes_in_changeset) + return ctx.serialize_changeset( + changes_in_changeset, + known_legacy_translations + ) + + def serialize_changeset(self, snapshot): + '''Write serialized FTL files to disk.''' + for path, content in six.iteritems(snapshot): + fullpath = os.path.join(self.localization_dir, path) + print(' Writing to {}'.format(fullpath)) + if not self.dry_run: + fulldir = os.path.dirname(fullpath) + if not os.path.isdir(fulldir): + os.makedirs(fulldir) + with open(fullpath, 'wb') as f: + f.write(content.encode('utf8')) + f.close() + + def commit_changeset( + self, description_template, author, index + ): + message = description_template.format( + index=index, + author=author + ) + + print(' Committing changeset: {}'.format(message)) + if self.dry_run: + return + try: + self.client.commit( + message, user=author.encode('utf-8'), addremove=True + ) + except hglib.error.CommandError as err: + print(' WARNING: hg commit failed ({})'.format(err)) + + +def main(locale, reference_dir, localization_dir, migrations, dry_run): + """Run migrations and commit files with the result.""" + migrator = Migrator(locale, reference_dir, localization_dir, dry_run) + + for migration in migrations: + migrator.run(migration) + + migrator.close() + + +def cli(): + parser = argparse.ArgumentParser( + description='Migrate translations to FTL.' + ) + parser.add_argument( + 'migrations', metavar='MIGRATION', type=str, nargs='+', + help='migrations to run (Python modules)' + ) + parser.add_argument( + '--locale', '--lang', type=str, + help='target locale code (--lang is deprecated)' + ) + parser.add_argument( + '--reference-dir', type=str, + help='directory with reference FTL files' + ) + parser.add_argument( + '--localization-dir', type=str, + help='directory for localization files' + ) + parser.add_argument( + '--dry-run', action='store_true', + help='do not write to disk nor commit any changes' + ) + parser.set_defaults(dry_run=False) + + logger = logging.getLogger('migrate') + logger.setLevel(logging.INFO) + + args = parser.parse_args() + + # Don't byte-compile migrations. + # They're not our code, and infrequently run + with dont_write_bytecode(): + migrations = map(importlib.import_module, args.migrations) + + main( + locale=args.locale, + reference_dir=args.reference_dir, + localization_dir=args.localization_dir, + migrations=migrations, + dry_run=args.dry_run + ) + + +if __name__ == '__main__': + cli() diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/transforms.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/transforms.py new file mode 100644 index 0000000000..1d9cddb387 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/transforms.py @@ -0,0 +1,580 @@ +# coding=utf8 +"""Migration Transforms. + +Transforms are AST nodes which describe how legacy translations should be +migrated. They are created inert and only return the migrated AST nodes when +they are evaluated by a MigrationContext. + +All Transforms evaluate to Fluent Patterns. This makes them suitable for +defining migrations of values of message, attributes and variants. The special +CONCAT Transform is capable of joining multiple Patterns returned by evaluating +other Transforms into a single Pattern. It can also concatenate Pattern +elements: TextElements and Placeables. + +The COPY, REPLACE and PLURALS Transforms inherit from Source which is a special +AST Node defining the location (the file path and the id) of the legacy +translation. During the migration, the current MigrationContext scans the +migration spec for Source nodes and extracts the information about all legacy +translations being migrated. For instance, + + COPY('file.dtd', 'hello') + +is equivalent to: + + FTL.Pattern([ + Source('file.dtd', 'hello') + ]) + +Sometimes it's useful to work with text rather than (path, key) source +definitions. This is the case when the migrated translation requires some +hardcoded text, e.g. and when multiple translations become a single +one with a DOM overlay. In such cases it's best to use FTL.TextElements: + + FTL.Message( + id=FTL.Identifier('update-failed'), + value=CONCAT( + COPY('aboutDialog.dtd', 'update.failed.start'), + FTL.TextElement(''), + COPY('aboutDialog.dtd', 'update.failed.linkText'), + FTL.TextElement(''), + COPY('aboutDialog.dtd', 'update.failed.end'), + ) + ) + +The REPLACE_IN_TEXT Transform also takes TextElements as input, making it +possible to pass it as the foreach function of the PLURALS Transform. In the +example below, each slice of the plural string is converted into a +TextElement by PLURALS and then run through the REPLACE_IN_TEXT transform. + + FTL.Message( + FTL.Identifier('delete-all'), + value=PLURALS( + 'aboutDownloads.dtd', + 'deleteAll', + VARIABLE_REFERENCE('num'), + lambda text: REPLACE_IN_TEXT( + text, + { + '#1': VARIABLE_REFERENCE('num') + } + ) + ) + ) +""" + +from __future__ import unicode_literals +from __future__ import absolute_import +import re + +from fluent.syntax import ast as FTL +from fluent.syntax.visitor import Transformer +from .errors import NotSupportedError + + +def chain_elements(elements): + '''Flatten a list of FTL nodes into an iterator over PatternElements.''' + for element in elements: + if isinstance(element, FTL.Pattern): + # PY3 yield from element.elements + for child in element.elements: + yield child + elif isinstance(element, FTL.PatternElement): + yield element + elif isinstance(element, FTL.Expression): + yield FTL.Placeable(element) + else: + raise RuntimeError( + 'Expected Pattern, PatternElement or Expression') + + +re_leading_ws = re.compile( + r'\A(?:(?P +)(?P.*?)|(?P\n.*?))\Z', + re.S, +) +re_trailing_ws = re.compile( + r'\A(?:(?P.*?)(?P +)|(?P.*\n))\Z', + re.S +) + + +def extract_whitespace(regex, element): + '''Extract leading or trailing whitespace from a TextElement. + + Return a tuple of (Placeable, TextElement) in which the Placeable + encodes the extracted whitespace as a StringLiteral and the + TextElement has the same amount of whitespace removed. The + Placeable with the extracted whitespace is always returned first. + If the element starts or ends with a newline, add an empty + StringLiteral. + ''' + match = re.search(regex, element.value) + if match: + # If white-space is None, we're a newline. Add an + # empty { "" } + whitespace = match.group('whitespace') or '' + placeable = FTL.Placeable(FTL.StringLiteral(whitespace)) + if whitespace == element.value: + return placeable, None + else: + # Either text or block_text matched the rest. + text = match.group('text') or match.group('block_text') + return placeable, FTL.TextElement(text) + else: + return None, element + + +class Transform(FTL.BaseNode): + def __call__(self, ctx): + raise NotImplementedError + + @staticmethod + def pattern_of(*elements): + normalized = [] + + # Normalize text content: convert text content to TextElements, join + # adjacent text and prune empty. Text content is either existing + # TextElements or whitespace-only StringLiterals. This may result in + # leading and trailing whitespace being put back into TextElements if + # the new Pattern is built from existing Patterns (CONCAT(COPY...)). + # The leading and trailing whitespace of the new Pattern will be + # extracted later into new StringLiterals. + for element in chain_elements(elements): + if isinstance(element, FTL.TextElement): + text_content = element.value + elif isinstance(element, FTL.Placeable) \ + and isinstance(element.expression, FTL.StringLiteral) \ + and re.match(r'^ *$', element.expression.value): + text_content = element.expression.value + else: + # The element does not contain text content which should be + # normalized. It may be a number, a reference, or + # a StringLiteral which should be preserved in the Pattern. + normalized.append(element) + continue + + previous = normalized[-1] if len(normalized) else None + if isinstance(previous, FTL.TextElement): + # Join adjacent TextElements. + previous.value += text_content + elif len(text_content) > 0: + # Normalize non-empty text to a TextElement. + normalized.append(FTL.TextElement(text_content)) + else: + # Prune empty text. + pass + + # Store empty values explicitly as {""}. + if len(normalized) == 0: + empty = FTL.Placeable(FTL.StringLiteral('')) + return FTL.Pattern([empty]) + + # Extract explicit leading whitespace into a StringLiteral. + if isinstance(normalized[0], FTL.TextElement): + ws, text = extract_whitespace(re_leading_ws, normalized[0]) + normalized[:1] = [ws, text] + + # Extract explicit trailing whitespace into a StringLiteral. + if isinstance(normalized[-1], FTL.TextElement): + ws, text = extract_whitespace(re_trailing_ws, normalized[-1]) + normalized[-1:] = [text, ws] + + return FTL.Pattern([ + element + for element in normalized + if element is not None + ]) + + +class Source(Transform): + """Base class for Transforms that get translations from source files. + + The contract is that the first argument is the source path, and the + second is a key representing legacy string IDs, or Fluent id.attr. + """ + def __init__(self, path, key): + self.path = path + self.key = key + + +class FluentSource(Source): + """Declare a Fluent source translation to be copied over. + + When evaluated, it clones the Pattern of the parsed source. + """ + def __init__(self, path, key): + if not path.endswith('.ftl'): + raise NotSupportedError( + 'Please use COPY to migrate from legacy files ' + '({})'.format(path) + ) + if key[0] == '-' and '.' in key: + raise NotSupportedError( + 'Cannot migrate from Term Attributes, as they are' + 'locale-dependent ({})'.format(path) + ) + super(FluentSource, self).__init__(path, key) + + def __call__(self, ctx): + pattern = ctx.get_fluent_source_pattern(self.path, self.key) + return pattern.clone() + + +class COPY_PATTERN(FluentSource): + """Create a Pattern with the translation value from the given source. + + The given key can be a Message ID, Message ID.attribute_name, or + Term ID. Accessing Term attributes is not supported, as they're internal + to the localization. + """ + pass + + +class TransformPattern(FluentSource, Transformer): + """Base class for modifying a Fluent pattern as part of a migration. + + Implement visit_* methods of the Transformer pattern to do the + actual modifications. + """ + def __call__(self, ctx): + pattern = super(TransformPattern, self).__call__(ctx) + return self.visit(pattern) + + def visit_Pattern(self, node): + # Make sure we're creating valid Patterns after restructuring + # transforms. + node = self.generic_visit(node) + pattern = Transform.pattern_of(*node.elements) + return pattern + + def visit_Placeable(self, node): + # Ensure we have a Placeable with an expression still. + # Transforms could have replaced the expression with + # a Pattern or PatternElement, in which case we + # just pass that through. + # Patterns then get flattened by visit_Pattern. + node = self.generic_visit(node) + if isinstance(node.expression, (FTL.Pattern, FTL.PatternElement)): + return node.expression + return node + + +class LegacySource(Source): + """Declare the source translation to be migrated with other transforms. + + When evaluated, `Source` returns a TextElement with the content from the + source translation. Escaped characters are unescaped by the + compare-locales parser according to the file format: + + - in properties files: \\uXXXX, + - in DTD files: known named, decimal, and hexadecimal HTML entities. + + Consult the following files for the list of known named HTML entities: + + https://github.com/python/cpython/blob/2.7/Lib/htmlentitydefs.py + https://github.com/python/cpython/blob/3.6/Lib/html/entities.py + + By default, leading and trailing whitespace on each line as well as + leading and trailing empty lines will be stripped from the source + translation's content. Set `trim=False` to disable this behavior. + """ + + def __init__(self, path, key, trim=None): + if path.endswith('.ftl'): + raise NotSupportedError( + 'Please use COPY_PATTERN to migrate from Fluent files ' + '({})'.format(path)) + + super(LegacySource, self).__init__(path, key) + self.trim = trim + + def get_text(self, ctx): + return ctx.get_legacy_source(self.path, self.key) + + @staticmethod + def trim_text(text): + # strip leading white-space from each line + text = re.sub('^[ \t]+', '', text, flags=re.M) + # strip trailing white-space from each line + text = re.sub('[ \t]+$', '', text, flags=re.M) + # strip leading and trailing empty lines + text = text.strip('\r\n') + return text + + def __call__(self, ctx): + text = self.get_text(ctx) + if self.trim is not False: + text = self.trim_text(text) + return FTL.TextElement(text) + + +class COPY(LegacySource): + """Create a Pattern with the translation value from the given source.""" + + def __call__(self, ctx): + element = super(COPY, self).__call__(ctx) + return Transform.pattern_of(element) + + +PRINTF = re.compile( + r'%(?P%|' + r'(?:(?P[1-9][0-9]*)\$)?' + r'(?P\*|[0-9]+)?' + r'(?P\.(?:\*|[0-9]+)?)?' + r'(?P[duxXosScpfg]))' +) + + +def number(): + i = 1 + while True: + yield i + i += 1 + + +def normalize_printf(text): + """Normalize printf arguments so that they're all numbered. + Gecko forbids mixing unnumbered and numbered ones, so + we just need to convert unnumbered to numbered ones. + Also remove ones that have zero width, as they're intended + to be removed from the output by the localizer. + """ + next_number = number() + + def normalized(match): + if match.group('good') == '%': + return '%' + hidden = match.group('width') == '0' + if match.group('number'): + return '' if hidden else match.group() + num = next(next_number) + return '' if hidden else '%{}${}'.format(num, match.group('spec')) + + return PRINTF.sub(normalized, text) + + +class REPLACE_IN_TEXT(Transform): + """Create a Pattern from a TextElement and replace legacy placeables. + + The original placeables are defined as keys on the `replacements` dict. + For each key the value must be defined as a FTL Pattern, Placeable, + TextElement or Expression to be interpolated. + """ + + def __init__(self, element, replacements, normalize_printf=False): + self.element = element + self.replacements = replacements + self.normalize_printf = normalize_printf + + def __call__(self, ctx): + # For each specified replacement, find all indices of the original + # placeable in the source translation. If missing, the list of indices + # will be empty. + value = self.element.value + if self.normalize_printf: + value = normalize_printf(value) + key_indices = { + key: [m.start() for m in re.finditer(re.escape(key), value)] + for key in self.replacements.keys() + } + + # Build a dict of indices to replacement keys. + keys_indexed = {} + for key, indices in key_indices.items(): + for index in indices: + keys_indexed[index] = key + + # Order the replacements by the position of the original placeable in + # the translation. + replacements = ( + (key, ctx.evaluate(self.replacements[key])) + for index, key + in sorted(keys_indexed.items(), key=lambda x: x[0]) + ) + + # A list of PatternElements built from the legacy translation and the + # FTL replacements. It may contain empty or adjacent TextElements. + elements = [] + tail = value + + # Convert original placeables and text into FTL Nodes. For each + # original placeable the translation will be partitioned around it and + # the text before it will be converted into an `FTL.TextElement` and + # the placeable will be replaced with its replacement. + for key, node in replacements: + before, key, tail = tail.partition(key) + elements.append(FTL.TextElement(before)) + elements.append(node) + + # Don't forget about the tail after the loop ends. + elements.append(FTL.TextElement(tail)) + return Transform.pattern_of(*elements) + + +class REPLACE(LegacySource): + """Create a Pattern with interpolations from given source. + + Interpolations in the translation value from the given source will be + replaced with FTL placeables using the `REPLACE_IN_TEXT` transform. + """ + + def __init__( + self, path, key, replacements, **kwargs + ): + # We default normalize_printf to False except for .properties files. + # We still allow the caller to override the default value. + normalize_printf = False + if 'normalize_printf' in kwargs: + normalize_printf = kwargs['normalize_printf'] + del kwargs['normalize_printf'] + elif path.endswith('.properties'): + normalize_printf = True + + super(REPLACE, self).__init__(path, key, **kwargs) + self.replacements = replacements + self.normalize_printf = normalize_printf + + def __call__(self, ctx): + element = super(REPLACE, self).__call__(ctx) + return REPLACE_IN_TEXT( + element, self.replacements, + normalize_printf=self.normalize_printf + )(ctx) + + +class PLURALS(LegacySource): + """Create a Pattern with plurals from given source. + + Build an `FTL.SelectExpression` with the supplied `selector` and variants + extracted from the source. The original translation should be a + semicolon-separated list of plural forms. Each form will be converted + into a TextElement and run through the `foreach` function, which should + return an `FTL.Node` or a `Transform`. By default, the `foreach` function + creates a valid Pattern from the TextElement passed into it. + """ + DEFAULT_ORDER = ('zero', 'one', 'two', 'few', 'many', 'other') + + def __init__(self, path, key, selector, foreach=Transform.pattern_of, + **kwargs): + super(PLURALS, self).__init__(path, key, **kwargs) + self.selector = selector + self.foreach = foreach + + def __call__(self, ctx): + element = super(PLURALS, self).__call__(ctx) + selector = ctx.evaluate(self.selector) + keys = ctx.plural_categories + forms = [ + FTL.TextElement(part.strip()) + for part in element.value.split(';') + ] + + # The default CLDR form should be the last we have in DEFAULT_ORDER, + # usually `other`, but in some cases `many`. If we don't have a variant + # for that, we'll append one, using the, in CLDR order, last existing + # variant in the legacy translation. That may or may not be the last + # variant. + default_key = [ + key for key in reversed(self.DEFAULT_ORDER) if key in keys + ][0] + + # Match keys to legacy forms in the order they are defined in Gecko's + # PluralForm.jsm. Filter out empty forms. + pairs = [ + (key, var) + for key, var in zip(keys, forms) + if var.value + ] + + # A special case for legacy translations which don't define any + # plural forms. + if len(pairs) == 0: + return Transform.pattern_of() + + # A special case for languages with one plural category or one legacy + # variant. We don't need to insert a SelectExpression for them. + if len(pairs) == 1: + _, only_form = pairs[0] + only_variant = ctx.evaluate(self.foreach(only_form)) + return Transform.pattern_of(only_variant) + + # Make sure the default key is defined. If it's missing, use the last + # form (in CLDR order) found in the legacy translation. + pairs.sort(key=lambda pair: self.DEFAULT_ORDER.index(pair[0])) + last_key, last_form = pairs[-1] + if last_key != default_key: + pairs.append((default_key, last_form)) + + def createVariant(key, form): + # Run the legacy plural form through `foreach` which returns an + # `FTL.Node` describing the transformation required for each + # variant. Then evaluate it to a migrated FTL node. + value = ctx.evaluate(self.foreach(form)) + return FTL.Variant( + key=FTL.Identifier(key), + value=value, + default=key == default_key + ) + + select = FTL.SelectExpression( + selector=selector, + variants=[ + createVariant(key, form) + for key, form in pairs + ] + ) + + return Transform.pattern_of(select) + + +class CONCAT(Transform): + """Create a new Pattern from Patterns, PatternElements and Expressions. + + When called with at least two elements, `CONCAT` disables the trimming + behavior of the elements which are subclasses of `LegacySource` by + setting `trim=False`, unless `trim` has already been set explicitly. The + following two `CONCAT` calls are equivalent: + + CONCAT( + FTL.TextElement("Hello"), + COPY("file.properties", "hello") + ) + + CONCAT( + FTL.TextElement("Hello"), + COPY("file.properties", "hello", trim=False) + ) + + Set `trim=True` explicitly to force trimming: + + CONCAT( + FTL.TextElement("Hello "), + COPY("file.properties", "hello", trim=True) + ) + + When called with a single element and when the element is a subclass of + `LegacySource`, the trimming behavior is not changed. The following two + transforms are equivalent: + + CONCAT(COPY("file.properties", "hello")) + + COPY("file.properties", "hello") + """ + + def __init__(self, *elements, **kwargs): + # We want to support both passing elements as *elements in the + # migration specs and as elements=[]. The latter is used by + # FTL.BaseNode.traverse when it recreates the traversed node using its + # attributes as kwargs. + self.elements = list(kwargs.get('elements', elements)) + + # We want to make CONCAT(COPY()) equivalent to COPY() so that it's + # always safe (no-op) to wrap transforms in a CONCAT. This is used by + # the implementation of transforms_from. + if len(self.elements) > 1: + for elem in self.elements: + # Only change trim if it hasn't been set explicitly. + if isinstance(elem, LegacySource) and elem.trim is None: + elem.trim = False + + def __call__(self, ctx): + return Transform.pattern_of(*self.elements) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/util.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/util.py new file mode 100644 index 0000000000..7fcd1c1b5c --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/util.py @@ -0,0 +1,114 @@ +# coding=utf8 +from __future__ import unicode_literals +from __future__ import absolute_import + +import textwrap + +import fluent.syntax.ast as FTL +from fluent.syntax.parser import FluentParser, FluentParserStream + + +fluent_parser = FluentParser(with_spans=False) + + +def parse(Parser, string): + if Parser is FluentParser: + return fluent_parser.parse(string) + + # Parsing a legacy resource. + + # Parse the string into the internal Context. + parser = Parser() + # compare-locales expects ASCII strings. + parser.readContents(string.encode('utf8')) + # Transform the parsed result which is an iterator into a dict. + return {ent.key: ent for ent in parser} + + +def ftl_resource_to_ast(code): + return fluent_parser.parse(ftl(code)) + + +def ftl_resource_to_json(code): + return fluent_parser.parse(ftl(code)).to_json() + + +def ftl_pattern_to_json(code): + ps = FluentParserStream(ftl(code)) + return fluent_parser.maybe_get_pattern(ps).to_json() + + +def to_json(merged_iter): + return { + path: resource.to_json() + for path, resource in merged_iter + } + + +LOCALIZABLE_ENTRIES = (FTL.Message, FTL.Term) + + +def get_message(body, ident): + """Get message called `ident` from the `body` iterable.""" + for entity in body: + if isinstance(entity, LOCALIZABLE_ENTRIES) and entity.id.name == ident: + return entity + + +def get_transform(body, ident): + """Get entity called `ident` from the `body` iterable.""" + for transform in body: + if transform.id.name == ident: + return transform + + +def skeleton(node): + """Create a skeleton copy of the given node. + + For localizable entries, the value is None and the attributes are {}. + That's not a valid Fluent entry, so it requires further manipulation to + set values and/or attributes. + """ + if isinstance(node, LOCALIZABLE_ENTRIES): + return type(node)(id=node.id.clone(), value=None) + return node.clone() + + +def ftl(code): + """Nicer indentation for FTL code. + + The code returned by this function is meant to be compared against the + output of the FTL Serializer. The input code will end with a newline to + match the output of the serializer. + """ + + # The code might be triple-quoted. + code = code.lstrip('\n') + + return textwrap.dedent(code) + + +def fold(fun, node, init): + """Reduce `node` to a single value using `fun`. + + Apply `fun` against an accumulator and each subnode of `node` (in postorder + traversal) to reduce it to a single value. + """ + + def fold_(vals, acc): + if not vals: + return acc + + head = list(vals)[0] + tail = list(vals)[1:] + + if isinstance(head, FTL.BaseNode): + acc = fold(fun, head, acc) + if isinstance(head, list): + acc = fold_(head, acc) + if isinstance(head, dict): + acc = fold_(head.values(), acc) + + return fold_(tail, fun(acc, head)) + + return fold_(vars(node).values(), init) diff --git a/comm/third_party/python/fluent.migratetb/fluent/migratetb/validator.py b/comm/third_party/python/fluent.migratetb/fluent/migratetb/validator.py new file mode 100644 index 0000000000..11b2f85a27 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/fluent/migratetb/validator.py @@ -0,0 +1,339 @@ +# coding=utf8 +from __future__ import absolute_import + +import argparse +import ast +import six +from six.moves import zip_longest + +from fluent.migratetb import transforms +from fluent.migratetb.errors import MigrationError +from fluent.migratetb.helpers import transforms_from +from fluent.syntax import ast as FTL +from fluent.syntax.visitor import Visitor +from compare_locales import mozpath + + +class MigrateNotFoundException(Exception): + pass + + +class BadContextAPIException(Exception): + pass + + +def process_assign(node, context): + if isinstance(node.value, ast.Str): + val = node.value.s + elif isinstance(node.value, ast.Name): + val = context.get(node.value.id) + elif isinstance(node.value, ast.Call): + val = node.value + if val is None: + return + for target in node.targets: + if isinstance(target, ast.Name): + context[target.id] = val + + +class Validator(object): + """Validate a migration recipe + + Extract information from the migration recipe about which files to + migrate from, and which files to migrate to. + Also check for errors in the recipe, or bad API usage. + """ + + @classmethod + def validate(cls, path, code=None): + if code is None: + with open(path) as fh: + code = fh.read() + validator = cls(code, path) + return validator.inspect() + + def __init__(self, code, path): + self.ast = ast.parse(code, path) + + def inspect(self): + migrate_func = None + global_assigns = {} + for top_level in ast.iter_child_nodes(self.ast): + if ( + isinstance(top_level, ast.FunctionDef) + and top_level.name == 'migrate' + ): + if migrate_func: + raise MigrateNotFoundException( + 'Duplicate definition of migrate' + ) + migrate_func = top_level + details = self.inspect_migrate(migrate_func, global_assigns) + if isinstance(top_level, ast.Assign): + process_assign(top_level, global_assigns) + if isinstance(top_level, (ast.Import, ast.ImportFrom)): + if 'module' in top_level._fields: + module = top_level.module + else: + module = None + for alias in top_level.names: + asname = alias.asname or alias.name + dotted = alias.name + if module: + dotted = '{}.{}'.format(module, dotted) + global_assigns[asname] = dotted + if not migrate_func: + raise MigrateNotFoundException( + 'migrate function not found' + ) + return details + + def inspect_migrate(self, migrate_func, global_assigns): + if ( + len(migrate_func.args.args) != 1 or + any( + getattr(migrate_func.args, arg_field) + for arg_field in migrate_func.args._fields + if arg_field != 'args' + ) + ): + raise MigrateNotFoundException( + 'migrate takes only one positional argument' + ) + arg = migrate_func.args.args[0] + if isinstance(arg, ast.Name): + ctx_var = arg.id # python 2 + else: + ctx_var = arg.arg # python 3 + visitor = MigrateAnalyzer(ctx_var, global_assigns) + visitor.visit(migrate_func) + return { + 'references': visitor.references, + 'issues': visitor.issues, + } + + +def full_name(node, global_assigns): + leafs = [] + while isinstance(node, ast.Attribute): + leafs.append(node.attr) + node = node.value + if isinstance(node, ast.Name): + leafs.append(global_assigns.get(node.id, node.id)) + return '.'.join(reversed(leafs)) + + +PATH_TYPES = six.string_types + (ast.Call,) + + +class MigrateAnalyzer(ast.NodeVisitor): + def __init__(self, ctx_var, global_assigns): + super(MigrateAnalyzer, self).__init__() + self.ctx_var = ctx_var + self.global_assigns = global_assigns + self.depth = 0 + self.issues = [] + self.references = set() + + def generic_visit(self, node): + self.depth += 1 + super(MigrateAnalyzer, self).generic_visit(node) + self.depth -= 1 + + def visit_Assign(self, node): + if self.depth == 1: + process_assign(node, self.global_assigns) + self.generic_visit(node) + + def visit_Attribute(self, node): + if isinstance(node.value, ast.Name) and node.value.id == self.ctx_var: + if node.attr not in ( + 'add_transforms', + 'locale', + ): + raise BadContextAPIException( + 'Unexpected attribute access on {}.{}'.format( + self.ctx_var, node.attr + ) + ) + self.generic_visit(node) + + def visit_Call(self, node): + if ( + isinstance(node.func, ast.Attribute) and + isinstance(node.func.value, ast.Name) and + node.func.value.id == self.ctx_var + ): + return self.call_ctx(node) + dotted = full_name(node.func, self.global_assigns) + if dotted == 'fluent.migratetb.helpers.transforms_from': + return self.call_helpers_transforms_from(node) + if dotted.startswith('fluent.migratetb.'): + return self.call_transform(node, dotted) + self.generic_visit(node) + + def call_ctx(self, node): + if node.func.attr == 'add_transforms': + return self.call_add_transforms(node) + raise BadContextAPIException( + 'Unexpected call on {}.{}'.format( + self.ctx_var, node.func.attr + ) + ) + + def call_add_transforms(self, node): + args_msg = ( + 'Expected arguments to {}.add_transforms: ' + 'target_ftl_path, reference_ftl_path, list_of_transforms' + ).format(self.ctx_var) + ref_msg = ( + 'Expected second argument to {}.add_transforms: ' + 'reference should be string or variable with string value' + ).format(self.ctx_var) + # Just check call signature here, check actual types below + if not self.check_arguments(node, (ast.AST, ast.AST, ast.AST)): + self.issues.append({ + 'msg': args_msg, + 'line': node.lineno, + }) + return + in_reference = node.args[1] + if isinstance(in_reference, ast.Name): + in_reference = self.global_assigns.get(in_reference.id) + if isinstance(in_reference, ast.Str): + in_reference = in_reference.s + if not isinstance(in_reference, six.string_types): + self.issues.append({ + 'msg': ref_msg, + 'line': node.args[1].lineno, + }) + return + self.references.add(in_reference) + # Checked node.args[1]. + # There's not a lot we can say about our target path, + # ignoring that. + # For our transforms, we want more checks. + self.generic_visit(node.args[2]) + + def call_transform(self, node, dotted): + module, called = dotted.rsplit('.', 1) + if module not in ('fluent.migratetb', 'fluent.migratetb.transforms'): + return + transform = getattr(transforms, called) + if not issubclass(transform, transforms.Source): + return + bad_args = '{} takes path and key as first two params'.format(called) + if not self.check_arguments( + node, ((ast.Str, ast.Name), (ast.Str, ast.Name),), + allow_more=True, check_kwargs=False + ): + self.issues.append({ + 'msg': bad_args, + 'line': node.lineno + }) + return + path = node.args[0] + if isinstance(path, ast.Str): + path = path.s + if isinstance(path, ast.Name): + path = self.global_assigns.get(path.id) + if not isinstance(path, PATH_TYPES): + self.issues.append({ + 'msg': bad_args, + 'line': node.lineno + }) + + def call_helpers_transforms_from(self, node): + args_msg = ( + 'Expected arguments to transforms_from: ' + 'str, **substitions' + ) + if not self.check_arguments( + node, (ast.Str,), check_kwargs=False + ): + self.issues.append({ + 'msg': args_msg, + 'line': node.lineno, + }) + return + kwargs = {} + found_bad_keywords = False + for keyword in node.keywords: + v = keyword.value + if isinstance(v, ast.Str): + v = v.s + if isinstance(v, ast.Name): + v = self.global_assigns.get(v.id) + if isinstance(v, ast.Call): + v = 'determined at runtime' + if not isinstance(v, PATH_TYPES): + msg = 'Bad keyword arg {} to transforms_from'.format( + keyword.arg + ) + self.issues.append({ + 'msg': msg, + 'line': node.lineno, + }) + found_bad_keywords = True + else: + kwargs[keyword.arg] = v + if found_bad_keywords: + return + try: + transforms = transforms_from(node.args[0].s, **kwargs) + except MigrationError as e: + self.issues.append({ + 'msg': str(e), + 'line': node.lineno, + }) + return + ti = TransformsInspector() + ti.visit(transforms) + self.issues.extend({ + 'msg': issue, + 'line': node.lineno, + } for issue in set(ti.issues)) + + def check_arguments( + self, node, argspec, check_kwargs=True, allow_more=False + ): + if check_kwargs and ( + node.keywords or + (hasattr(node, 'kwargs') and node.kwargs) + ): + return False + if hasattr(node, 'starargs') and node.starargs: + return False + for arg, NODE_TYPE in zip_longest(node.args, argspec): + if NODE_TYPE is None: + return True if allow_more else False + if not (isinstance(arg, NODE_TYPE)): + return False + return True + + +class TransformsInspector(Visitor): + def __init__(self): + super(TransformsInspector, self).__init__() + self.issues = [] + + def generic_visit(self, node): + if isinstance(node, transforms.Source): + src = node.path + # Source needs paths to be normalized + # https://bugzilla.mozilla.org/show_bug.cgi?id=1568199 + if src != mozpath.normpath(src): + self.issues.append( + 'Source "{}" needs to be a normalized path'.format(src) + ) + super(TransformsInspector, self).generic_visit(node) + + +def cli(): + parser = argparse.ArgumentParser() + parser.add_argument('migration') + args = parser.parse_args() + issues = Validator.validate(args.migration)['issues'] + for issue in issues: + print(issue['msg'], 'at line', issue['line']) + return 1 if issues else 0 diff --git a/comm/third_party/python/fluent.migratetb/setup.cfg b/comm/third_party/python/fluent.migratetb/setup.cfg new file mode 100644 index 0000000000..4ad9421229 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/setup.cfg @@ -0,0 +1,16 @@ +[options.entry_points] +console_scripts = + migrate-l10n-tb=fluent.migratetb.tool:cli + validate-l10n-tb-recipe=fluent.migratetb.validator:cli + +[metadata] +long_description = file: README.md +long_description_content_type = text/markdown + +[bdist_wheel] +universal = 1 + +[egg_info] +tag_build = +tag_date = 0 + diff --git a/comm/third_party/python/fluent.migratetb/setup.py b/comm/third_party/python/fluent.migratetb/setup.py new file mode 100644 index 0000000000..9a40a580c1 --- /dev/null +++ b/comm/third_party/python/fluent.migratetb/setup.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +from setuptools import setup + +setup( + name='fluent.migratetb', + version='0.11.2', + description='Toolchain to migrate legacy translation to Fluent. (Thunderbird fork)', + author='Mozilla', + author_email='l10n-drivers@mozilla.org', + license='APL 2', + url='https://github.com/jfx2006/tb-fluent-migrate/', + keywords=['fluent', 'localization', 'l10n'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python :: 3.7', + ], + packages=['fluent', 'fluent.migratetb'], + install_requires=[ + 'compare-locales >=8.1, <9.0', + 'fluent.syntax >=0.18.0, <0.19', + 'six', + ], + extras_require={ + 'hg': ['python-hglib',], + }, + tests_require=[ + 'mock', + ], + test_suite='tests.migratetb' +) diff --git a/comm/third_party/rnp/CHANGELOG.md b/comm/third_party/rnp/CHANGELOG.md new file mode 100644 index 0000000000..611e46122b --- /dev/null +++ b/comm/third_party/rnp/CHANGELOG.md @@ -0,0 +1,436 @@ +## Changelog + +### 0.17.0 [2023-05-01] + +#### General + +* Added support for hidden recipient during decryption. +* Added support for AEAD-OCB for OpenSSL backend. +* Improve support for offline secret keys during default key selection. +* Support for GnuPG 2.3+ secret key store format. +* SExp parsing code is moved to separate library, https://github.com/rnpgp/sexp. +* Mark subkeys as expired instead of invalid if primary key is expired. +* AEAD: use OCB by default instead of EAX. +* Do not attempt to validate signatures of unexpected types. +* Use thread-safe time and date handling functions. +* Added ENABLE_BLOWFISH, ENABLE_CAST5 and ENABLE_RIPEMD160 build time options. +* Do not use `EVP_PKEY_CTX_set_dsa_paramgen_q_bits()` if OpenSSL backend version is < 1.1.1e. +* Corrected usage of CEK/KEK algorithms if those differs. + +#### FFI + +* Added function `rnp_signature_export()`. +* Added flag `RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT` to `rnp_op_verify_set_flags()`. + +#### CLI + +* Added default armor message type for `--enarmor` command. +* Added command `--set-filename` to specify which file name should be stored in message. +* Added `--add-subkey` subcommand to the `--edit-key`. +* Added `set-expire` subcommand to the `--edit-key`. +* Added `--s2k-iterations` and `--s2k-msec` options to the `rnp`. +* Added `--allow-weak-hash` command to allow usage of weak hash algorithms. +* Report number of new/updated keys during the key import. + +### 0.16.3 [2023-04-11] + +#### Security + +* Fixed issue with possible hang on malformed inputs (CVE-2023-29479). +* Fixed issue where in some cases, secret keys remain unlocked after use (CVE-2023-29480). + +### 0.16.2 [2022-09-20] + +#### General + +* Fixed CMake issues with ENABLE_IDEA and ENABLE_BRAINPOOL. + +### 0.16.1 [2022-09-06] + +#### General + +* Ensure support for RHEL9/CentOS Stream 9/Fedora 36, updating OpenSSL backend support for v3.0. +* Optional import and export of base64-encoded keys. +* Optional raw encryption of the data. +* Optional overriding of the current timestamp. +* Do not fail completely on unknown signature versions. +* Do not fail completely on unknown PKESK/SKESK packet versions. +* Support armored messages without empty line after the headers. +* Added automatic feature detection based on backend. + +#### Security + +* Separate security rules for the data and key signatures, extending SHA1 key signature support till the Jan, 19 2024. +* Set default key expiration time to 2 years. +* Limit maximum AEAD chunk bits to 16. + +#### FFI + +* Changed behaviour of `rnp_op_verify_execute()`: now it requires single valid signature to succeed. +* Added function `rnp_op_verify_set_flags()` to override default behaviour of verification. +* Added function `rnp_key_is_expired()`. +* Added function `rnp_op_encrypt_set_flags()` and flag `RNP_ENCRYPT_NOWRAP` to allow raw encryption. +* Added flag `RNP_LOAD_SAVE_BASE64` to the function `rnp_import_keys()`. +* Added flag `RNP_KEY_EXPORT_BASE64` to the function `rnp_key_export_autocrypt()`. +* Added function `rnp_set_timestamp()` to allow to override current time. +* Update security rules functions with flags `RNP_SECURITY_VERIFY_KEY` and `RNP_SECURITY_VERIFY_DATA`. + +#### CLI + +* Make password request more verbose. +* Print `RSA` instead of `RSA (Encrypt and Sign)` in the key listing to avoid confusion. +* Added option `--source` to specify detached signature's source file. +* Added option `--no-wrap` to allow raw data encryption. +* Added option `--current-time` to allow to override current timestamp. +* Strip known extensions (like `.pgp`, `.asc`, etc.) when decrypting or verifying data. +* Display key and signature validity status in the key listing. +* Do not attempt to use GnuPG's config to set default key. + +### 0.16.0 [2022-01-20] + +#### General + +* Added support for OpenSSL cryptography backend so RNP may be built and used on systems without the Botan installed. +* Added compile-time switches to disable certain features (AEAD, Brainpool curves, SM2/SM3/SM4 algorithms, Twofish) +* Fixed possible incompatibility with GnuPG on x25519 secret key export from RNP to GnuPG. +* Fixed building if Git is not available. +* Fixed export of non-FFI symbols from the rnp.so/rnp.dylib. +* Fixed support for Gnu/Hurd (absence of PATH_MAX). +* Added support for `None` compression algorithm. +* Added support for the dumping of notation data signature subpackets. +* Fixed key expiration time calculation in the case with newer non-primary self-certification. +* Improved performance of key import (no key material checks) + +#### Security + +* Added initial support for customizable security profiles. +* Mark SHA1 signatures produced later than 2019-01-19, as invalid. +* Mark MD5 signatures produced later than 2012-01-01, as invalid. +* Remove SHA1 and 3DES from the default key preferences. +* Use SHA1 collision detection code when using SHA1. +* Mark signatures with unknown critical notation as invalid. +* Do not prematurely mark secret keys as valid. +* Validate secret key material before the first operation. +* Limit the number of possible message recipients/signatures to a reasonable value (16k). +* Limit the number of signature subpackets during parsing. + +#### FFI + +* Added functions `rnp_backend_string()` and `rnp_backend_version()`. +* Added functions `rnp_key_25519_bits_tweaked()` and `rnp_key_25519_bits_tweak()` to check and fix x25519 secret key bits. +* Added security profile manipulation functions: `rnp_add_security_rule()`, `rnp_get_security_rule()`, `rnp_remove_security_rule()`. +* Added function `rnp_signature_get_expiration()`. +* Deprecate functions `rnp_enable_debug()`/`rnp_disable_debug()`. + +#### CLI + +* Write new detailed help messages for `rnp` and `rnpkeys`. +* Added `-` (stdin) and `env:VAR_NAME` input specifiers, as well as `-` (stdout) output specifier. +* Do not fail with empty keyrings if those are not needed for the operation. +* Added algorithm aliases for better usability (i.e. `SHA-256`, `SHA256`, etc.). +* Added option `--notty` to print everything to stdout instead of TTY. +* Added command `--edit-key` with subcommands `--check-cv25519-bits` and `--fix-cv25519-bits`. +* Remove support for `-o someoption=somevalue`, which is unused. +* Remove no longer used support for additional debug dumping via `--debug source.c`. + +### 0.15.2 [2021-07-20] + +#### General + +* Be less strict in userid validation: allow to use userids with self-signature, which has key expiration in the past. +* Do not mark signature as invalid if key which produced it is expired now, but was valid during signing. +* Fix incorrect key expiration calculation in some cases. +* Fix incorrect version number in the `version.txt`. + +#### FFI + +* Add function `rnp_key_get_default_key()` to pick the default key/subkey for the specific operation. +* Allow to pass NULL hash parameter to `rnp_key_add_uid()` to pick the default one. +* Use the same approach as in `rnp_op_encrypt_add_recipient()` for encryption subkey selection in `rnp_key_export_autocrypt()`. + +#### CLI + +* `rnp`: Show error message if encryption failed. +* `rnpkeys` : Add `--expiration` option to specify expiration time during key generation. + +### 0.15.1 [2021-05-28] + +#### General + +* Make man pages building optional. +* Fixed updating of expiration time for a key with multiple user ids. +* Fixed key expiry check for keys valid after the year 2038. +* Pick up key expiration time from direct-key signature or primary userid certification if available. + +#### FFI + +* Added function `rnp_key_valid_till64()` to correctly handle keys which expire after the year 2038. +* Added `RNP_FEATURE_*` defines to be used instead of raw strings. + +#### Security + +* Fixed issue with cleartext key data after the `rnp_key_unprotect()`/`rnp_key_protect()` calls (CVE-2021-33589). + +### 0.15.0 [2021-04-04] + +#### General + +* Added CMake options to allow offline builds, i.e. without Googletest/ruby-rnp downloads. +* Removed major library version from the library name (librnp-0.so/dll -> librnp.so/dll). +* Improved handling of cleartext signatures, when empty line between headers and contents contains some whitespace characters. +* Relaxed requirements for the armored messages CRC (allow absence of the CRC, and issue warning instead of complete failure). +* Updated build instructions for MSVC. +* Improved support of 32-bit platforms (year 2038 problem). + +#### CLI + +* Added up-to-date manual pages for `rnp` and `rnpkeys`. +* rnpkeys: added `--remove-key` command. + +#### FFI + +* Added up-to-date manual page for `librnp`. +* Added function `rnp_signature_remove` +* Added function `rnp_uid_remove` +* Added function `rnp_key_remove_signatures` for batch signature removal and filtering. + +### 0.14.0 [2021-01-15] + +#### General + +* Improved key validation: require to have at least one valid, non-expiring self signature. +* Added support for 'stripped' keys without userids and certifications but with valid subkey binding signature. +* Added support for Windows via MinGW/MSYS2. +* Added support for Windows via MSVC. +* Fixed secret key locking when it is updated with new signatures/subkeys. +* Fixed key expiry/flags calculation (take in account only the latest valid self-signature/subkey binding). +* Fixed MDC reading if it appears on 8k boundary. +* Disabled logging by default in release builds and added support for environment variable `RNP_LOG_CONSOLE` to enable it back. +* Fixed leading zeroes for secp521r1 b & n field constants. +* Allowed keys and signatures with invalid MPI bit count. +* Added support for private/experimental signature subpackets, used by GnuPG and other implementations. +* Added support for reserved/placeholder signatures. +* Added support for zero-size userid/attr packet. +* Relaxed packet dumping, ignoring invalid packets and allowing to find wrong packet easier. +* Improved logging of errored keys/subkeys information for easier debugging. +* Fixed support for old RSA sign-only/encrypt-only and ElGamal encrypt-and-sign keys. +* Fixed support for ElGamal keys larger then 3072 bits. +* Fixed symbol visibility so only FFI functions are exposed outside of the library. +* Added support for unwrapping of raw literal packets. +* Fixed crash with non-detached signature input, fed into the `rnp_op_verify_detached_create()`. +* Significantly reduced memory usage for the keys large number of signatures. +* Fixed long armor header lines processing. +* Added basic support for GnuPG's offline primary keys (`gnupg --export-secret-subkeys`) and secret keys, stored on card. +* Fixed primary key binding signature validation when hash algorithm differs from the one used in the subkey binding signature. +* Fixed multiple memory leaks related to invalid algorithms/versions/etc. +* Fixed possible crashes during processing of malformed armored input. +* Limited allowed nesting levels for OpenPGP packets. +* Fixed support for text-mode signatures. +* Replaced strcpy calls with std::string and memcpy where applicable. +* Removed usage of mktemp, replacing it with mkstemp. +* Replaced usage of deprecated `botan_pbkdf()` with `botan_pwdhash()`. +* Added support for the marker packet, issued by some implementations. +* Added support for unknown experimental s2ks. +* Fixed armored message contents detection (so armored revocation signature is not more reported as the public key). +* Changed behaviour to use latest encryption subkey by default. +* Fixed support for widechar parameters/file names on Windows. +* Implemented userid validity checks so only certified/non-expired/non-revoked userid may be searched. +* Fixed GnuPG compatibility issues with CR (`\r`) characters in text-mode and cleartext-signed documents. +* Improved performance of the key/uid signatures access. +* Migrated tests to the Python 3. +* Migrated most of the internal code to C++. + +#### CLI + +* Do not load keyring when it is not required, avoiding extra `keyring not found` output. +* Input/output data via the tty, if available, instead of stdin/stdout. +* Fixed possible crash when HOME variable is not set. +* rnpkeys: Added `--import-sigs` and changed behavior of `--import` to check whether input is key or signature. +* rnpkeys: Added `--export-rev` command to export key's revocation, parameters `--rev-type`, `--rev-reason`. +* rnpkeys: Added `--revoke-key` command. +* rnpkeys: Added `--permissive` parameter to `--import-keys` command. +* rnpkeys: Added `--password` options, allowing to specify password and/or generate unprotected key. + +#### FFI + +* Added keystore type constants `RNP_KEYSTORE_*`. +* Added `rnp_import_signatures`. +* Added `rnp_key_export_revocation`. +* Added `rnp_key_revoke`. +* Added `rnp_request_password`. +* Added `rnp_key_set_expiration` to update key's/subkey's expiration time. +* Added flag `RNP_LOAD_SAVE_PERMISSIVE` to `rnp_import_keys`, allowing to skip erroneous packets. +* Added flag `RNP_LOAD_SAVE_SINGLE`, allowing to import keys one-by-one. +* Added `rnp_op_verify_get_protection_info` to check mode and cipher used to encrypt message. +* Added functions to retrieve recipients information (`rnp_op_verify_get_recipient_count`, `rnp_op_verify_get_symenc_count`, etc.). +* Added flag `RNP_KEY_REMOVE_SUBKEYS` to `rnp_key_remove` function. +* Added function `rnp_output_pipe` allowing to write data from input to the output. +* Added function `rnp_output_armor_set_line_length` allowing to change base64 encoding line length. +* Added function `rnp_key_export_autocrypt` to export public key in autocrypt-compatible format. +* Added functions to retrieve information about the secret key's protection (`rnp_key_get_protection_type`, etc.). +* Added functions `rnp_uid_get_type`, `rnp_uid_get_data`, `rnp_uid_is_primary`. +* Added function `rnp_uid_is_valid`. +* Added functions `rnp_key_get_revocation_signature` and `rnp_uid_get_revocation_signature`. +* Added function `rnp_signature_get_type`. +* Added function `rnp_signature_is_valid`. +* Added functions `rnp_key_is_valid` and `rnp_key_valid_till`. +* Added exception guard to FFI boundary. +* Fixed documentation for the `rnp_unload_keys` function. + +#### Security + +* Removed version header from armored messages (see https://mailarchive.ietf.org/arch/msg/openpgp/KikdJaxvdulxIRX_yxU2_i3lQ7A/ ). +* Enabled fuzzing via oss-fuzz and fixed reported issues. +* Fixed a bunch of issues reported by static analyzer. +* Require at least Botan 2.14.0. + +### 0.13.1 [2020-01-15] +#### Security + +* rnpkeys: Fix issue #1030 where rnpkeys would generate unprotected secret keys. + +### 0.13.0 [2019-12-31] +#### General + +* Fixed a double-free on invalid armor headers. +* Fixed broken versioning when used as a git submodule. +* Fixed an infinite loop on parsing truncated armored keys. +* Fixed armored stream parsing to be more flexible and allow blank lines before trailer. +* Fixed the armor header for detached signatures (previously MESSAGE, now SIGNATURE). +* Improved setting of default qbits for DSA. +* Fixed a crash when retrieving signature revocation reason. +* Stop using expensive tests for key material validation. + +#### CLI + +* rnpkeys: Removed a few redundant commands (--get-key, --print-sigs, --trusted-keys, ...). +* rnpkeys: Added --secret option. +* rnpkeys: Display 'ssb' for secret subkeys. +* rnp: Added `--list-packets` parameters (`--json`, etc.). +* rnp: Removed `--show-keys`. + +#### FFI + +* Added `rnp_version_commit_timestamp` to retrieve the commit timestamp + (for non-release builds). +* Added a new (non-JSON) key generation API (`rnp_op_generate_create` etc.). +* Added `rnp_unload_keys` function to unload all keys. +* Added `rnp_key_remove` to unload a single key. +* Expanded bit length support for JSON key generation. +* Added `rnp_key_get_subkey_count`/`rnp_key_get_subkey_at`. +* Added various key property accessors (`rnp_key_get_bits`, `rnp_key_get_curve`). +* Added `rnp_op_generate_set_protection_password`. +* Added `rnp_key_packets_to_json`/`rnp_dump_packets_to_json`. +* Added `rnp_key_get_creation`, `rnp_key_get_expiration`. +* Added `rnp_key_get_uid_handle_at`, `rnp_uid_is_revoked`, etc. +* Added `rnp_key_is_revoked` and related functions to check for revocation. +* Added `rnp_output_to_path` and `rnp_output_finish`. +* Added `rnp_import_keys`. +* Added `rnp_calculate_iterations`. +* Added `rnp_supports_feature`/`rnp_supported_features`. +* Added `rnp_enable_debug`/`rnp_disable_debug`. +* Added `rnp_key_get_primary_grip`. +* Added `rnp_output_to_armor`. +* Added `rnp_op_generate_set_request_password`. +* Added `rnp_dump_packets_to_output`. +* Added `rnp_output_write`. +* Added `rnp_guess_contents`. +* Implemented `rnp_op_set_file_name`/`rnp_op_set_file_mtime`. +* Added `rnp_op_encrypt_set_aead_bits`. +* Added `rnp_op_verify_signature_get_handle`. +* Added `rnp_signature_packet_to_json`. + +#### Packaging + +* RPM: Split packages into librnp0, librnp0-devel, and rnp0. + +### 0.12.0 [2019-01-13] +#### General + +* We now require Botan 2.8+. +* Fixed key grip calculations for various key types. +* Fixed SM2 signatures hashing the hash of the message. See comment in issue #436. +* Added support for G10 ECC keys. +* Fixed dumping of partial-length packets. +* Added support for extra ECC curves: + * Brainpool p256, p384, p512 ECDSA/ECDH + * secp256k1 ECDSA/ECDH + * x25519 +* Fixed AEAD with newer versions of Botan. +* Removed a lot of legacy code. + +#### CLI + +* rnp: Added -f/--keyfile option to load keys directly from a file. +* rnp: Fixed issue with selecting G10 secret keys via userid. +* rnpkeys: Added support for SM2 with arbitrary hashes. +* redumper: Added -g option to dump fingerprints and grips. +* redumper: Display key id/fingerprint/grip in packet listings. + +#### FFI + +* Added FFI examples. +* Fixed a regression with loading subkeys directly. +* Implemented support for per-signature hash and creation/expiration time. +* Added AEAD support. + +### 0.11.0 [2018-09-16] +#### General + +* Remove some old SSH key support. +* Add support for dynamically calculating the S2K iterations. +* Add support for extracting the public key from the secret key. +* Add support for merging information between keys. + +#### CLI + +* Add options for custom S2K iterations/times (dynamic by default). + +### 0.10.0 [2018-08-20] +#### General + +* Fixed some compiler warnings. +* Switched armoring to use PRIVATE KEY instead of SECRET KEY. + +#### ECDSA + +* Use the matching hash to be used for the deterministic nonce generation. +* Check that the input is of the expected length. +* Removed the code to truncate the ECDSA input since this is now handled by Botan. + +#### FFI + +* Added enarmor and dearmor support. +* Added library version retrieval. +* Removed rnp_export_public_key, added rnp_key_export. + + +### 0.9.2 [2018-08-13] +#### General + +* Support for generation and verification of embedded signature subpacket for signing subkeys +* Verification of public key signatures and key material +* Improved performance of asymmetric operations (key material is now validated on load) + +#### FFI + +* Fixed `rnp_op_add_signature` for G10 keys + + +### 0.9.1 [2018-07-12] +#### General + +* Added issuer fingerprint to certifications and subkey bindings. + +#### CLI + +* Added support for keyid/fpr usage with (some) spaces and 0x prefix in + operations (`--sign`, etc). + +#### FFI + +* Fixed key search by fingerprint. + + +### 0.9.0 [2018-06-27] +* First official release. diff --git a/comm/third_party/rnp/LICENSE-OCB.md b/comm/third_party/rnp/LICENSE-OCB.md new file mode 100644 index 0000000000..6293e3330b --- /dev/null +++ b/comm/third_party/rnp/LICENSE-OCB.md @@ -0,0 +1,93 @@ +License for OCB Usage +===================== + +Last updated: November 1, 2022 + +This license has been graciously granted by Professor Phillip Rogaway to allow +users of [`rnp`](https://github.com/rnpgp/rnp) to utilize the patented +[OCB](http://web.cs.ucdavis.edu/~rogaway/ocb/) blockcipher mode of operation, +which simultaneously provides privacy and authenticity. + +While the license is irrevocable and does not expire, it is no longer necessary, +since Professor Phillip Rogaway confirmed that the OCB patents are now in the +public domain and officially abandoned, announced at the link below: + +* https://mailarchive.ietf.org/arch/msg/cfrg/qLTveWOdTJcLn4HP3ev-vrj05Vg/ + +This license text remains in RNP as an acknowledgement of kindness given by +Professor Phillip Rogaway to make OCB available for RNP users. + +The license text is presented below in plain text form purely for referential +purposes. The original signed license is available on request from Ribose Inc., +reachable at open.source@ribose.com. + +This file adheres to the formatting guidelines of +[readable-licenses](https://github.com/nevir/readable-licenses). + + +OCB Patent License for Ribose Inc. +---------------------------------- + +1. Definitions + +1.1 "Licensor" means Phillip Rogaway, of 1212 Purdue Dr., Davis, California, USA. + +1.2 "Licensed Patents" means any patent that claims priority to United States +Patent Application No. 09/918,615 entitled "Method and Apparatus for +Facilitating Efficient Authenticated Encryption," and any utility, divisional, +provisional, continuation, continuations in part, reexamination, reissue, or +foreign counterpart patents that may issue with respect to the aforesaid patent +application. This includes, but is not limited to, United States Patent No. +7,046,802; United States Patent No. 7,200,227; United States Patent No. +7,949,129; United States Patent No. 8,321,675; and any patent that issues out +or United States Patent Application No. 13/669,114. + +1.3 "Licensee" means Ribose Inc., at Suite 1, 8/F, 10 Ice House Street, +Central, Hong Kong, its affiliates, assignees, or successors in interest, or +anyone using, making, copying, modifying, distributing, having made, importing, +or having imported any program, software, or computer system including or based +upon Open Source Software published by Ribose Inc., or their customers, +suppliers, importers, manufacturers, distributors, or insurers. + +1.4 "Use in Licensee Products" means using, making, copying, modifying, +distributing, having made, importing or having imported any program, software, +or computer system published by Licensee, which contains or is based upon Open +Source Software which may include any implementation of the Licensed Patents. + +1.5 "Open Source Software" means software whose source code is published and +made available for inspection and use by anyone because either (a) the source +code is subject to a license that permits recipients to copy, modify, and +distribute the source code without payment of fees or royalties, or (b) the +source code is in the public domain, including code released for public use +through a CC0 waiver. All licenses certified by the Open Source Initiative at +opensource.org as of January 1, 2017 and all Creative Commons licenses +identified on the creativecommons.org website as of January 1, 2017, including +the Public License Fallback of the CC0 waiver, satisfy these requirements for +the purposes of this license. + +2. Grant of License + +2.1 Licensor hereby grants to Licensee a perpetual, worldwide, non-exclusive, +nontransferable, non-sublicenseable, no-charge, royalty-free, irrevocable +license to Use in Licensee Products any invention claimed in the Licensed +Patents in any Open Source Software Implementation and in hardware as long as +the Open Source Software incorporated in such hardware is freely licensed for +hardware embodiment. + +3. Disclaimer + +3.1 LICENSEE'S USE OF THE LICENSED PATENTS IS AT LICENSEE'S OWN RISK AND UNLESS +REQUIRED BY APPLICABLE LAW, LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES OF +ANY KIND CONCERNING THE LICENSED PATENTS OR ANY PRODUCT EMBODYING ANY LICENSED +PATENT, EXPRESS OR IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT +LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR +PURPOSE, OR NONINFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING +FROM OR RELATED TO ANY USE OF THE LICENSED PATENTS, INCLUDING, WITHOUT +LIMITATION, DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR SPECIAL +DAMAGES, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES +PRIOR TO SUCH AN OCCURRENCE. + +[SIGNATURE by Phillip Rogaway] + +Date: August 28, 2017 diff --git a/comm/third_party/rnp/LICENSE.md b/comm/third_party/rnp/LICENSE.md new file mode 100644 index 0000000000..d9f32dc441 --- /dev/null +++ b/comm/third_party/rnp/LICENSE.md @@ -0,0 +1,178 @@ +Licenses & Copyright +==================== + +This license file adheres to the formatting guidelines of +[readable-licenses](https://github.com/nevir/readable-licenses). + + +Ribose's BSD 2-Clause License +----------------------------- + +Copyright (c) 2017-2021, [Ribose Inc](https://www.ribose.com). +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +NetBSD's BSD 2-Clause License +----------------------------- + +This software contains source code originating from NetPGP, which +carries the following copyright notice and license. + +Copyright (c) 2009-2016, [The NetBSD Foundation, Inc](https://www.netbsd.org). +All rights reserved. + +This code is derived from software contributed to The NetBSD Foundation +by [Alistair Crooks](mailto:agc@NetBSD.org) + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Nominet UK's Apache 2.0 Licence +------------------------------- + +This software contains source code originating from NetPGP, which +carries the following copyright notice and license. + +Copyright (c) 2005-2008 [Nominet UK](www.nic.uk) +All rights reserved. + +Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted +their moral rights under the UK Copyright Design and Patents Act 1988 to +be recorded as the authors of this copyright work. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. + + +Nominet UK's BSD 3-Clause License +------------------------------- + +This software contains source code originating from NetPGP, which +carries the following copyright notice and license. + +Copyright (c) 2005 [Nominet UK](www.nic.uk) +All rights reserved. + +Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted +their moral rights under the UK Copyright Design and Patents Act 1988 to +be recorded as the authors of this copyright work. + +This is a BSD-style Open Source licence. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. The name of Nominet UK or the contributors may not be used to + endorse or promote products derived from this software without specific + prior written permission; + +and provided that the user accepts the terms of the following disclaimer: + +THIS SOFTWARE IS PROVIDED BY NOMINET UK AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL NOMINET UK OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + +MIT License for SHA-1 collision detection code +---------------------------------------------- + +These files are derived from +[sha1collisiondetection-tools](https://github.com/cr-marcstevens/sha1collisiondetection-tools), +which is distributed with this [license](https://github.com/git/sha1collisiondetection/blob/master/LICENSE.txt) +reproduced below. + +* `src/lib/crypto/sha1cd/sha1.{c,h}` +* `src/lib/crypto/sha1cd/ubc_check.{c,h}` + +Copyright (c) 2017: + + Marc Stevens + Cryptology Group + Centrum Wiskunde & Informatica + P.O. Box 94079, 1090 GB Amsterdam, Netherlands + marc@marc-stevens.nl + + Dan Shumow + Microsoft Research + danshu@microsoft.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/comm/third_party/rnp/README.adoc b/comm/third_party/rnp/README.adoc new file mode 100644 index 0000000000..a0162faa63 --- /dev/null +++ b/comm/third_party/rnp/README.adoc @@ -0,0 +1,69 @@ += RNP + +image:https://github.com/rnpgp/rnp/workflows/macos/badge.svg["macOS Build Status", link="https://github.com/rnpgp/rnp/actions?workflow=macos"] +image:https://github.com/rnpgp/rnp/workflows/ubuntu/badge.svg["Ubuntu Build Status", link="https://github.com/rnpgp/rnp/actions?workflow=ubuntu"] +image:https://github.com/rnpgp/rnp/workflows/centos7/badge.svg["CentOS 7 Build Status", link="https://github.com/rnpgp/rnp/actions?workflow=centos7"] +image:https://github.com/rnpgp/rnp/workflows/windows-native/badge.svg["Windows Native Build Status", link="https://github.com/rnpgp/rnp/actions?workflow=windows-native"] +image:https://github.com/rnpgp/rnp/workflows/windows-msys2/badge.svg["Windows MSys2 Build Status", link="https://github.com/rnpgp/rnp/actions?workflow=windows-msys2"] +image:https://github.com/rnpgp/rnp/workflows/nix/badge.svg["Nix Build Status", link="https://github.com/rnpgp/rnp/actions?workflow=nix"] +image:https://img.shields.io/cirrus/github/rnpgp/rnp?label=freebsd&logo=cirrus%20ci["FreeBSD Build Status", link="https://cirrus-ci.com/github/rnpgp/rnp"] + +image:https://img.shields.io/coverity/scan/12616.svg["Coverity Scan Build Status", link="https://scan.coverity.com/projects/rnpgp-rnp"] +image:https://codecov.io/gh/rnpgp/rnp/branch/main/graph/badge.svg["Code coverage", link="https://codecov.io/gh/rnpgp/rnp"] + +== Introduction + +RNP is a set of OpenPGP (RFC4880) tools that works on Linux, macOS, Windows and +*BSD built with C++. + +`librnp` is the library used by RNP for all OpenPGP functions, useful +for developers to build against, different from GPGME. + + +== Supported Platforms + +Currently supported platforms: + +* Fedora +* RHEL/CentOS +* Ubuntu +* NixOS / Nix +* FreeBSD +* MacOS +* Windows +* Debian + +Upcoming supported platforms: + +* OpenSUSE Leap +* SLES + +== link:docs/installation.adoc[Installation] + +== link:docs/cli-usage.adoc[Using CLI tool] + +== link:docs/c-usage.adoc[Using the RNP C API in your projects] + +== link:docs/signing-keys.adoc[PGP keys used for signing source code] + +== Versioning + +RNP follows the http://semver.org/[semantic versioning] syntax. + +=== Checking versions + +The output of `rnp --version` contains the `git` hash of +the version the binary was built from, which value is generated when +`cmake` runs. Consequently, a release tarball generated with `make +dist` will contain this hash version. + +=== Historic information + +The first version of rnp started at `0.8.0` to indicate its development +completeness (or lack thereof). + +RNP originated as an attempt to modernize the NetPGP codebase originally +created by Alistair Crooks of NetBSD in 2016. RNP has been heavily rewritten, +and carries minimal if any code from the original codebase. + +== link:docs/code-of-conduct.adoc[Code of Conduct] diff --git a/comm/third_party/rnp/doc/tests/README.md b/comm/third_party/rnp/doc/tests/README.md new file mode 100644 index 0000000000..a116569f54 --- /dev/null +++ b/comm/third_party/rnp/doc/tests/README.md @@ -0,0 +1,72 @@ +# Test Case Guidelines for `rnp` + +The document aims to describe and capture various use cases for `rnp` in +the form of the test cases. These can be used as acceptance tests for +the maintenance of the project. + + +## Naming conventions + +The test case name is composed of the three parts. + +* First being the module under test, +* Second being the feature and third details the motivation of the test. + +Naming structure looks like: `__`. + +For example, when testing the `generatekey` feature of `rnpkeys`, the +test case name would be `rnpkeys.generatekey.`. + + +## Test Case Specification Template + +The following template **SHOULD** be used for describing a test case. + + +~~~~~~ md +# + +Component +: + +Feature +: + +## Objective + +% Objective of test case + +## Description + +% Describe test case briefly + +## Preconditions + +% List of conditions prior to testing + +* condition 1 +* condition 2 +* condition 3 + +## Test steps and expected behavior + +1. Test step 1 + +1. Test step 2 + +Expectation: expectation here + +## Verification steps and logic + +1. Verification step 1 + * Rationale: verification logic + +1. Verification step 2 + * Rationale: verification logic + +## Comments + +% if any + +~~~~~~ + diff --git a/comm/third_party/rnp/doc/tests/rnpkeys-generate-key.md b/comm/third_party/rnp/doc/tests/rnpkeys-generate-key.md new file mode 100644 index 0000000000..113a9e697f --- /dev/null +++ b/comm/third_party/rnp/doc/tests/rnpkeys-generate-key.md @@ -0,0 +1,192 @@ +# rnpkeys_generatekey_verifySupportedHashAlg + +Component +: rnpkeys + +Feature +: Generate-key + +## Objective + +Verify SupportedHashAlg. + +## Description + +The test aims to test key generation with all possible hash algorithm. +Following hash algorithm are tested for the key generation: + +* `MD5` +* `SHA-1` +* `RIPEMD160` +* `SHA256` +* `SHA384` +* `SHA512` +* `SHA224` + +## Preconditions + +* Initialize RNP +* Set the default value for `res`, `format`, `hash` via `rnp_setvar()`. + +## Test steps and expected behavior + +1. Set the hash algorithm via `rnp_setvar` + +1. Call the API to generate key (`rnp_generate_key`) + +Expectation: key is generated using options set via `rnp_setvar` + +## Verification steps and logic + +1. Load the newly generated RNP keys + * Rationale: Ensures keys are loaded in the `rnp` control structure + for verification. + +1. Find existence of key via `userId`. + + * **Note**: If `userid` variable is not set, default is `always`. + * Rationale: Ensures the key exists by finding it. + +## Comments + +It is required to delete the old keys if the test case iterates over the +hashing algorithm. + + +# rnpkeys_generatekey_VerifyUserIdOption + +Component +: rnpkeys + +Feature +: Generate-key + +## Objective + +Verify `UserIdOption` + +## Description + +The test aims to test key generation with command line option `UserId`. + +Following different `userid`s are tested: + +* `rnpkeys_Generatekey_VerifyUserIdOption_MD5` +* `rnpkeys_Generatekey_VerifyUserIdOption_SHA-1` +* `rnpkeys_Generatekey_VerifyUserIdOption_RIPEMD160` +* `rnpkeys_Generatekey_VerifyUserIdOption_SHA256` +* `rnpkeys_Generatekey_VerifyUserIdOption_SHA384` +* `rnpkeys_Generatekey_VerifyUserIdOption_SHA512` +* `rnpkeys_Generatekey_VerifyUserIdOption_SHA224` + + +## Preconditions + +* Initialize RNP +* Set the default value for res, format, hash via `rnp_setvar`. + +## Test steps and expected behavior + +1. Set the userId via `rnp_setvar` + +1. Call the API to generate key (`rnp_generate_key`) + +Expectation: key is generated using options set via `rnp_setvar` + +## Verification steps and logic + +1. Load the newly generated RNP keys + * Rationale: Ensures keys are loaded in the rnp control structure for + verification. + +1. Find the existence of the key via finding the key with the userId. + + +# rnpkeys_generatekey_verifykeyRingOptions + +Component +: rnpkeys + +Feature +: Generate-key + +## Objective + +Verify keyRingOptions. + +## Description + +The test aims to test key generation with the user specified keyring. + +## Preconditions + +* Initialize RNP +* Set the default value for `res`, `format`, `hash` via `rnp_setvar()`. + +## Test steps and expected behavior + +1. Set the keyring via `rnp_setvar` + +1. Call the API to generate key (`rnp_generate_key`) + +Expectation: key is generated using options set via `rnp_setvar` + +## Verification steps and logic + +1. Delete the default keyring i.e. `pubring.gpg` and `secring.gpg` found + in the homedir + + * Rationale: To ensure that default keyring is **NOT** available. + +1. Load the newly generated RNP keys + + * Rationale: Ensures keys are loaded in the `rnp` control structure + for verification. + +1. Find existence of key via `userId`. + + * **Note**: If `userid` variable is not set, default is `always`. + * Rationale: Ensures the key exists by finding it. + + +# rnpkeys_generatekey_verifykeyHomeDirOption + +Component +: rnpkeys + +Feature +: Generate-key + +## Objective + +Verify keyHomeDirOption. + +## Description + +The test aims to test key generation with the user specified keyring. + +## Preconditions + +* Create new home dir with read/write permissions. +* Delete the keys (if any) in the previous default directory. +* Initialize RNP +* Set the default value for `res`, `format`, `hash` via `rnp_setvar()`. + +## Test steps and expected behavior + +1. Call the API to generate key (`rnp_generate_key`) + +Expectation: key is generated using options set via `rnp_setvar` + +## Verification steps and logic + +1. Load the newly generated RNP keys + + * Rationale: Ensures keys are loaded in the rnp control structure for + verification. + +1. Find existence of key via `userId`. + + * **Note**: If `userid` variable is not set, default is `always`. + * Rationale: Ensures the key exists by finding it. + diff --git a/comm/third_party/rnp/docs/c-usage.adoc b/comm/third_party/rnp/docs/c-usage.adoc new file mode 100644 index 0000000000..b45f9b91bb --- /dev/null +++ b/comm/third_party/rnp/docs/c-usage.adoc @@ -0,0 +1,129 @@ += Using the RNP C API + +This document is for developers who wish to use RNP as a library in C. + +Examples are given below to demonstrate such usage. + +== Examples + +[TIP] +.Location of examples +==== +The source code of these examples can be found under +`https://github.com/rnpgp/rnp/blob/main/src/examples/[src/examples]`. + +If you are planning to build from source, these examples are built +together with the RNP library and will be available under `src/examples` +within your build folder. +==== + +[TIP] +==== +All samples below use APIs exposed via the header file +`https://github.com/rnpgp/rnp/blob/main/include/rnp/rnp.h[include/rnp/rnp.h]`. +For further details please refer to the file directly. +==== + +The following example applications are available: + +`generate`:: Demonstrates generating keys, save/load of keyrings, exporting keys. + +`encrypt`:: Demonstrates how to encrypt a file using a password and/or key. + +`decrypt`:: Demonstrates how to decrypt OpenPGP data using a key and/or password. + +`sign`:: Demonstrates how to sign messages, using one or more keys from a loaded keyring. + +`verify`:: Demonstrates how to verify signed messages using dynamic keys fetching + (using a sample key provider implementation). + +`dump`:: Demonstrates how to dump OpenPGP packet information. + + +=== generate.c + +Location: https://github.com/rnpgp/rnp/blob/main/src/examples/generate.c + +This example is composed from 2 functions: + +* `ffi_generate_keys()`: Demonstrates how to generate and save different key types + (RSA and EDDSA/Curve25519) using JSON key description. + Also demonstrates usage of the password provider. ++ +Keyrings will be saved to files `pubring.pgp` and `secring.pgp` in the current directory. +You can use `rnp --list-packets pubring.pgp` to check the properties of the generated key(s). + +* `ffi_output_keys()`: Demonstrates how to load keyrings, + search for keys (in helper functions `ffi_print_key()`/`ffi_export_key()`), + and how to export them to memory or file in armored format. + +=== encrypt.c + +Location: https://github.com/rnpgp/rnp/blob/main/src/examples/encrypt.c + +This code example does the following: + +* first loads a public keyring (`pubring.pgp`) (created by the `generate.c` example) +* then creates an encryption operation structure and +* configures it with various options (including the setup of password encryption and public-key encryption). + +The result is the encrypted and armored (for easier reading) message +`RNP encryption sample message`. + +This message is saved to the file `encrypted.asc` in current directory. + +What you can do after: + +* Inspect the message with `rnp --list-packets encrypted.asc`. +* Decrypt the saved file via `rnp --keyfile secring.pgp -d encrypted.asc`. + +=== decrypt.c + +Location: https://github.com/rnpgp/rnp/blob/main/src/examples/decrypt.c + +This example uses keyrings generated from the `generate.c` example +to decrypt messages encrypted by the `encrypt.c` example. + +This example demonstrates how to decrypt message with a password or with a key, +and implements a custom password provider for decryption via key or key password. + +The decrypted message is saved to memory and then printed to the `stdout`. + +=== sign.c + +Location: https://github.com/rnpgp/rnp/blob/main/src/examples/sign.c + +This example uses keyrings generated in the preceding `generate.c` example. + +It demonstrates configuration of a signing context, signing of the message, +and the saving of the detached signature to the `signed.asc` file. + +Then the attached signature is used: i.e. the data is encapsulated into +the resulting message. + +What you can do after: + +* Inspect the signed message with `rnp --list-packets signed.asc`. +* Verify the message with `rnp --keyfile pubring.pgp -v signed.asc`. + +=== verify.c + +Location: https://github.com/rnpgp/rnp/blob/main/src/examples/verify.c + +This example uses keyrings generated in the `generate.c` example. + +However, instead of loading the whole keyring, it implements dynamic key fetching +via custom key provider (see function `example_key_provider`). + +After verification, it outputs the verified embedded message +and all signatures to `stdout` (with signing key IDs and statuses). + +=== dump.c + +Location: https://github.com/rnpgp/rnp/blob/main/src/examples/dump.c + +This example dumps OpenPGP packet information from the input stream +(via `stdin` or filename), tuned with flags passed via the +command-line interface. + +The resulting human-readable text or JSON is printed to `stdout`. diff --git a/comm/third_party/rnp/docs/cli-usage.adoc b/comm/third_party/rnp/docs/cli-usage.adoc new file mode 100644 index 0000000000..7039381f77 --- /dev/null +++ b/comm/third_party/rnp/docs/cli-usage.adoc @@ -0,0 +1,174 @@ += Using the RNP command-line interface + +== Generating an RSA private key + +By default, `rnpkeys --generate-key` generates a 2048-bit RSA key. + +[source,console] +---- +export keydir=/tmp +rnpkeys --generate-key --homedir=${keydir} +---- + +=> + +[source,console] +---- +rnpkeys: generated keys in directory ${keydir}/6ed2d908150b82e7 +---- + +NOTE: Here `6ed2d...` is the key fingerprint. + +In order to use fully-featured key-pair generation, the `--expert` flag +should be used. + +With this flag added to `rnpkeys --generate-key`, the user will be +able to generate a key-pair for any supported algorithm and/or key size. + +Example: + +[source,console] +---- +> export keydir=/tmp +> rnpkeys --generate-key --expert --homedir=${keydir} + +Please select what kind of key you want: + (1) RSA (Encrypt or Sign) + (19) ECDSA + (22) EDDSA +> 19 + +Please select which elliptic curve you want: + (1) NIST P-256 + (2) NIST P-384 + (3) NIST P-521 +> 2 + +Generating a new key... +signature 384/ECDSA d45592277b75ada1 2017-06-21 +Key fingerprint: 4244 2969 07ca 42f7 b6d8 1636 d455 9227 7b75 ada1 +uid ECDSA 384-bit key +rnp: generated keys in directory /tmp/.rnp +Enter password for d45592277b75ada1: +Repeat password for d45592277b75ada1: +> +---- + + +== Listing keys + +[source,console] +---- +export keyringdir=${keydir}/MYFINGERPRINT +rnpkeys --list-keys --homedir=${keyringdir} + +---- + +=> + +[source,console] +---- +1 key found +... +---- + + +== Signing a file + + +=== Signing in binary format + +[source,console] +---- +rnp --sign --homedir=${keyringdir} ${filename} +---- + +=> + +Creates `${filename}.gpg` which is an OpenPGP message that includes the +message together with the signature as a 'signed message'. + +This type of file can be verified with: + +* `rnp --verify --homedir=${keyringdir} ${filename}.gpg` + + +=== Signing in binary detached format + +[source,console] +---- +rnp --sign --detach --homedir=${keyringdir} ${filename} +---- + +=> + +Creates `${filename}.sig` which is an OpenPGP message in binary +format, that only contains the signature. + +This type of file can be verified with: + +* `rnp --verify --homedir=${keyringdir} ${filename}.sig` + + +=== Signing in armored ("`ASCII-armored`") format + +[source,console] +---- +rnp --sign --armor --homedir=${keyringdir} ${filename} +---- + +=> + +Creates `${filename}.asc` which is an OpenPGP message in ASCII-armored +format, including the message together with the signature as a +"`signed message`". + +This type of file can be verified with: + +* `rnp --verify --homedir=${keyringdir} ${filename}.asc` + + +=== Other options + +`--clearsign`:: +appends a separate OpenPGP signature to the end of the newly +signed message. + +`--detach`:: +saves the OpenPGP signature in a separate file from the newly +signed message. + + +== Encrypt + + +[source,console] +---- +rnp --encrypt --homedir=${keyringdir} ${filename} +---- + +=> + +Creates `${filename}.gpg`, which is an encrypted OpenPGP message. + + +== Decrypt + +[source,console] +---- +rnp --decrypt --homedir=${keyringdir} ${filename}.gpg +---- + +=> + +Creates `${filename}`, the decrypted form of the `${filename}.gpg` +encrypted OpenPGP message. + + +== Check version + +The output of `rnp --version` contains the `git` hash of the version +the binary was built from, of which value is generated when `cmake` runs. + +Consequently, a release tarball generated with `make dist` will +contain this hash version. diff --git a/comm/third_party/rnp/docs/code-of-conduct.adoc b/comm/third_party/rnp/docs/code-of-conduct.adoc new file mode 100644 index 0000000000..14f5e0365e --- /dev/null +++ b/comm/third_party/rnp/docs/code-of-conduct.adoc @@ -0,0 +1,128 @@ + += Contributor Covenant Code of Conduct + +== Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +== Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +== Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +== Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +== Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +open.source@ribose.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +== Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +=== 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +=== 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +=== 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +=== 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +== Attribution + +This Code of Conduct is adapted from the +https://www.contributor-covenant.org[Contributor Covenant], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by +https://github.com/mozilla/diversity[Mozilla's code of conduct enforcement ladder]. + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/comm/third_party/rnp/docs/develop.adoc b/comm/third_party/rnp/docs/develop.adoc new file mode 100644 index 0000000000..e0c0e4116e --- /dev/null +++ b/comm/third_party/rnp/docs/develop.adoc @@ -0,0 +1,435 @@ += RNP development guide + +The following are a set of conventions and items that are relevant to +contributors. + +== Contributing + +=== Pull Requests + +See also: https://github.com/thoughtbot/guides/tree/master/code-review[Thoughtbot’s Code Review guide] + +Pull Requests should be used for any non-trivial changes. This presents +an opportunity for feedback and allows the CI tests to complete prior to +merging. + +The `master` branch should generally always be in a buildable and +functional state. + +Pull Requests should be: + +* Focused. Do not include changes that are unrelated to the main purpose + of the PR. +* As small as possible. Sometimes large pull requests may be necessary + for adding complex features, but generally they should be kept as small + as possible to ensure a quick and thorough review process. +* Related to a GH issue to which you are assigned. If there is none, + file one (but search first!). This ensures there is no duplication of + effort and allows for a discussion prior to beginning work. + (This may not be necessary for PRs that are purely documentation updates) +* Approved by **2** reviewers before merging. + (Updates related to policies, like this section, should be approved by + the project owner) +* Merged by a reviewer via the most appropriate method + (see https://github.com/rnpgp/guides/tree/master/protocol/git[here]). + +=== Branches + +See also: https://github.com/rnpgp/guides/tree/master/protocol/git[Guides - Protocol / Git] + +Git branches should be used generously. Most branches should be topic branches, +created for adding a specific feature or fixing a specific bug. + +Keep branches short-lived (treat them as disposable/transient) and try to +avoid long-running branches. + +A good example of using a branch would be: + +* User `@joe` notices a bug where a NULL pointer is dereferenced during + key export. He creates GH issue `#500`. +* He creates a new branch to fix this bug named + `joe-500-fix-null-deref-in-pgp_export_key`. +* Joe commits a fix for the issue to this new branch. +* Joe creates a Pull Request to merge this branch in to main. +* Once merged, Joe deletes the branch since it is no longer useful. + +Branch names may vary but should be somewhat descriptive, with words +separated by hyphens. It is also helpful to start the branch name with +your GitHub username, to make it clear who created the branch and +prevent naming conflicts. + +Remember that branch names may be preserved permanently in the commit +history of `main`, depending on how they are merged. + +=== Commits + +* Try to keep commits as small as possible. This may be difficult or + impractical at times, so use your best judgement. +* Each commit should be buildable and should pass all tests. This helps + to ensure that git bisect remains a useful method of pinpointing issues. +* Commit messages should follow 50/72 rule. +* When integrating pull requests, merge function should be preferred over + squashing. From the other hand, developers should squash commits and + create meaningful commit stack before PR is merged into mainstream branch. + Merging commits like "Fix build" or "Implement comments from code review" + should be avoided. + +== Continuous Integration (Github Actions) + +Github actions are used for continuously testing new commits and pull requests. +Those include testing for different operating systems, linting via clang-format and shellcheck, +and code coverage and quality checks via `Codecov` and `LGTM.io`. + +For Github workflows sources see `.github/workflows/` folder and scripts from the `ci/` folder. +Also there is a Cirrus CI runner, configuration for which is stored in `.cirrus.yml`. + +=== Reproducing Locally + +If tests fail in CI, you may attempt to reproduce those locally via `ctest` command: + +[source,console] +-- +ctest -j4 -V -R rnp_tests +-- + +Or, more specific: + +[source,console] +-- +ctest -V -R cli_tests-Misc +-- + +If test fails under the specific OS, you should construct corresponding Docker container and run tests inside, taking Github workflows as a guide. + +== Code Coverage + +CodeCov is used for assessing our test coverage. +The current coverage can always be viewed here: https://codecov.io/github/rnpgp/rnp/ + +== Security / Bug Hunting + +=== Static Analysis + +==== Coverity Scan + +Coverity Scan is used for static analysis of the code base. +It is run daily on the main branch via the Github actions. +See `.github/workflows/coverity.yml` for the details. + +The results can be accessed on https://scan.coverity.com/projects/rnpgp-rnp. +You will need to create an account and request access to the rnpgp/rnp project. + +Since the scan results are not updated live, line numbers may no longer +be accurate against the `main` branch, issues may already be resolved, +etc. + +==== Clang Static Analyzer + +Clang includes a useful static analyzer that can also be used to locate +potential bugs. + +Note: It is normal for the build time to increase significantly when using this static analyzer. + +[source,console] +-- +# it's important to start fresh for this! +rm -rf build && mkdir build && cd build +scan-build cmake .. && scan-build make -j8 +[...] +scan-build: 61 bugs found. +scan-build: Run 'scan-view /tmp/scan-build-2018-09-17-085354-22998-1' to examine bug reports. +-- + +Then use `scan-view`, as indicated above, to start a web server and use +your web browser to view the results. + +=== Dynamic Analysis + +==== Fuzzing + +It is often useful to utilize a fuzzer like +http://lcamtuf.coredump.cx/afl/["american fuzzy lop" ("AFL")] or +https://llvm.org/docs/LibFuzzer.html["libfuzzer"] to find +ways to improve the robustness of the code base. + +Presently, rnp builds in +https://github.com/google/oss-fuzz/tree/master/projects/rnp["OSS-Fuzz"] +and certain fuzzers are enabled there. + +In the `src/fuzzing` directory, we have the fuzzers that run in OSS-Fuzz. +Setting `-DENABLE_SANITIZERS=1 -DENABLE_FUZZERS=1` will build these fuzzers +with the libfuzzer engine; and running the resulting executables will perform +the fuzzing. + +To build and run fuzzers locally, or reproduce an issue, see https://google.github.io/oss-fuzz/advanced-topics/reproducing/ + +===== Further Reading + +* AFL's `README`, `parallel_fuzzing.txt`, and other bundled documentation. +* See https://fuzzing-project.org/tutorial3.html[Tutorial: Instrumented fuzzing with american fuzzy lop] + +==== Clang Sanitizer + +Clang and GCC both support a number of sanitizers that can help locate +issues in the code base during runtime. + +To use them, you should rebuild with the sanitizers enabled, and then +run the tests (or any executable): + +[source,console] +-- +env CXX=clang++ CXXFLAGS="-fsanitize=address,undefined" LDFLAGS="-fsanitize=address,undefined" ./configure +make -j4 +src/tests/rnp_tests +-- + +Here we are using the +https://clang.llvm.org/docs/AddressSanitizer.html[AddressSanitizer] +and +https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html[UndefinedBehaviorSanitizer]. + +This will produce output showing any memory leaks, heap overflows, or +other issues. + +== Code Conventions + +C is a very flexible and powerful language. Because of this, it is +important to establish a set of conventions to avoid common problems and +to maintain a consistent code base. + +=== Code Formatting + +`clang-format` (v9.0.0) can be used to format the code base, utilizing +the `.clang-format` file included in the repository. + +==== clang-format git hook + +A git pre-commit hook exists to perform this task automatically, and can +be enabled like so: + +[source,console] +-- +cd rnp +git-hooks/enable.sh +-- + +If you do not have clang-format v9.0.0 available, you can use a docker +container for this purpose by setting `USE_DOCKER="yes"` in +`git-hooks/pre-commit.sh`. + +This should generally work if you commit from the command line. + +Note that if you have unstaged changes on some of the files you are +attempting to commit, which have formatting issues detected, you will +have to resolve this yourself (the script will inform you of this). + +If your commit does not touch any `.c`/`.h` files, you can skip the +pre-commit hook with git's `--no-verify`/`-n` option. + +==== clang-format (manually) + +If you are not able to use the git hook, you can run `clang-format` +manually in a docker container. + +Create a suitable container image with: + +[source,console] +-- +docker run --name=clang-format alpine:latest apk --no-cache add clang +docker commit clang-format clang-format +docker rm clang-format +-- + +You can then reformat a file (say, `src/lib/crypto/bn.cpp`) like so: + +[source,console] +-- +cd rnp +docker run --rm -v $PWD:/rnp -w /rnp clang-format clang-format -style=file -i src/lib/crypto/bn.cpp +-- + +Also you may wish to reformat all modified uncommitted files: + +[source,console] +-- +docker run --rm -v $PWD:/rnp -w /rnp clang-format clang-format -style=file -i `git ls-files -m |grep "\.\(c\|h\|cpp\)\$"` +-- + +...or files, modified since referenced commit, say `54c5476`: + +[source,console] +-- +docker run --rm -v $PWD:/rnp -w /rnp clang-format clang-format -style=file -i `git diff --name-only 54c5476..HEAD |grep "\.\(c\|h\|cpp\)\$"` +-- + +=== Style Guide + +In order to keep the code base consistent, we should define and adhere +to a single style. + +When in doubt, consult the existing code base. + +==== Naming + +The following are samples that demonstrate the style for naming +different things. + +* Functions: `some_function` +* Variables: `some_variable` +* Filenames: `packet-parse.c` `packet-parse.h` +* Struct: `pgp_key_t` +* Typedefed Enums: `pgp_pubkey_alg_t` +* Enum Values: `PGP_PKA_RSA = 1` +* Constants (macro): `RNP_BUFSIZ` + +==== General Guidelines + +Do: + +* Do use header guards (`#ifndef SOME_HEADER_H [...]`) in headers. +* Do use `sizeof(variable)`, rather than `sizeof(type)`. Or + `sizeof(*variable)` as appropriate. +* Do use commit messages that close GitHub issues automatically, when + applicable. `Fix XYZ. Closes #78.` See + https://help.github.com/articles/closing-issues-via-commit-messages/[here]. +* Do declare functions `static` when they do not need to be referenced + outside the current source file. +* Do always use braces for conditionals, even if the block only contains a + single statement. ++ +[source,c] +-- +if (something) { + return val; +} +-- + +* Do use a default failure (not success) value for `ret` variables. Example: ++ +[source,c] +-- +rnp_result_t ret = RNP_ERROR_GENERIC; +// ... + +return ret; +-- + +Do not: + +* Do not use the static storage class for local variables, *unless* they + are constant. ++ +**Not OK** ++ +[source,c] +-- +int somefunc() { + static char buffer[256]; + //... +} +-- ++ +**OK** ++ +[source,c] +-- +int somefunc() { + static const uint16_t some_data[] = { + 0x00, 0x01, 0x02, //... + }; +} +-- + +* Do not use `pragma`, and try to avoid `__attribute__` as well. + +* Do not use uninitialized memory. Try to ensure your code will not cause any errors in valgrind and other memory checkers. + +==== Documentation + +Documentation is done in Doxygen comments format, which must be put in header files. + +Exception are static or having only definition functions - it is not required to document them, +however if they are documented then this should be done in the source file and using the @private tag. + +Comments should use doxygen markdown style, like the following example: + +[source,c] +-- +/** Some comments regarding the file purpose, like 'PGP packet parsing utilities' + * @file + */ + +/** brief description of the sample function which does something, keyword 'brief' is omitted + * Which may be continued here + * + * After an empty line you may add detailed description in case it is needed. You may put + * details about the memory allocation, what happens if function fails and so on. + * + * @param param1 first parameter, null-terminated string which should not be NULL + * @param param2 integer, some number representing something + * @param size number of bytes available to store in buffer + * @param buffer buffer to store results, may be NULL. In this case size can be used to + * obtain the required buffer length + * @return 0 if operation succeeds, or error code otherwise. If operation succeeds then buffer + * is populated with the resulting data, and size contains the length of this data. + * if error code is E_BUF_TOOSMALL then size will contain the required size to store + * the result + **/ +rnp_result_t +rnp_do_operation(const char *param1, const int param2, int *size, char *buffer); +-- + +== OpenPGP protocol specification + +During development you'll need to reference OpenPGP protocol and related documents. +Here is the list of RFCs and Internet Drafts available at the moment: + +* https://www.ietf.org/rfc/rfc1991.txt[RFC 1991]: PGP Message Exchange Formats. Now obsolete, but may have some historical interest. +* https://www.ietf.org/rfc/rfc2440.txt[RFC 2440]: OpenPGP Message Format. Superseded by RFC 4880. +* https://www.ietf.org/rfc/rfc4880.txt[RFC 4880]: OpenPGP Message Format. Latest RFC available at the moment, however has a lot of suggested changes via RFC 4880bis +* https://tools.ietf.org/rfc/rfc5581.txt[RFC 5581]: The Camellia cipher in OpenPGP. +* https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.txt[RFC 4880bis-09]: OpenPGP Message Format. Latest suggested update to the RFC 4880. + +More information sources: + +* https://mailarchive.ietf.org/arch/browse/openpgp/[OpenPGP Working Group mailing list]. Here you can pick up all the latest discussions and suggestions regarding the update of RFC 4880 +* https://gitlab.com/openpgp-wg/rfc4880bis[OpenPGP Working Group gitlab]. Latest work on RFC update is available here. + +== Reviewers and Responsibility areas + +The individuals are responsible for the following areas of `rnp`. +When submitting a Pull Request please seek reviews by whoever is +responsible according to this list. + +General: + +* Code style: @dewyatt +* Algorithms: @randombit, @dewyatt, @flowher, @catap, @ni4 +* Performance: @catap, @ni4 +* CLI: @ni4 +* GnuPG compatibility: @MohitKumarAgniotri, @frank-trampe, @ni4 +* Security Testing/Analysis: @MohitKumarAgniotri, @flowher +* Autotools: @randombit, @zgyarmati, @catap + +Data formats: + +* OpenPGP Packet: @randombit, @catap, @ni4 +* Keystore: @catap +* JSON: @zgyarmati +* SSH: @ni4 + +Bindings: + +* FFI: @dewyatt +* Ruby: @dewyatt +* Java/JNI: @catap +* Obj-C/Swift: @ni4 +* Python: @dewyatt, @ni4 + +Platforms: + +* RHEL/CentOS: @dewyatt +* BSD: +* Windows: @rrrooommmaaa +* macOS / iOS / Homebrew: @ni4 +* Debian: @zgyarmati diff --git a/comm/third_party/rnp/docs/develop/cpp-usage.adoc b/comm/third_party/rnp/docs/develop/cpp-usage.adoc new file mode 100644 index 0000000000..e0c18427bf --- /dev/null +++ b/comm/third_party/rnp/docs/develop/cpp-usage.adoc @@ -0,0 +1,49 @@ += Usage of {cpp} within RNP + +This is a provisional document reflecting the recent conversion from C +to {cpp}. It should be revisited as experience with using {cpp} within RNP +codebase increases. + +== Encouraged Features + +These are features which seem broadly useful, their downsides are minimal +and well understood. + + - STL types std::vector, std::string, std::unique_ptr, std::map + + - RAII techniques (destructors, smart pointers) to minimize use of + goto to handle cleanup. + + - Value types, that is to say types which simply encapsulate some + data. + + - std::function or virtual functions to replace function pointers. + + - Prefer virtual functions only on "interface" classes (with no data), + and derive only one level of classes from this interface class. + + - Anonymous namespaces are an alternative to `static` functions. + +== Questionable Features + +These are features that may be useful in certain situations, but should +be used carefully. + + - Exceptions. While convenient, they do have a non-zero cost in runtime + and binary size. + +== Forbidden Features + +These are {cpp} features that simply should be avoided, at least until a +very clear use case for them has been identified and no other approach +suffices. + + - RTTI. This has a significant runtime cost and usually there are + better alternatives. + + - Multiple inheritance. This leads to many confusing and problematic + scenarios. + + - Template metaprogramming. If you have a problem, and you think + template metaprogramming will solve it, now you have two problems, + and one of them is incomprehensible. diff --git a/comm/third_party/rnp/docs/develop/packaging.adoc b/comm/third_party/rnp/docs/develop/packaging.adoc new file mode 100644 index 0000000000..917c9aa71c --- /dev/null +++ b/comm/third_party/rnp/docs/develop/packaging.adoc @@ -0,0 +1,78 @@ += Packaging + +== CentOS 7 + +=== 1. Retrieve the source + +==== Tarball + +[source,console] +-- +curl -LO https://github.com/rnpgp/rnp/archive/v0.9.0.tar.gz +tar xzf v0.9.0.tar.gz +cd rnp-0.9.0 +-- + +==== Git + +[source,console] +-- +git clone https://github.com/rnpgp/rnp +cd rnp +git checkout v0.9.0 +-- + +=== 2. Launch a container + +[source,console] +-- +docker run -ti --rm -v $PWD:/usr/local/rnp centos:7 bash +-- + +From this point, all commands are executed in the container. + +==== 3. Install pre-requisites + +[source,console] +-- +# for newer cmake and other things +yum -y install epel-release + +# rnp +yum -y install git cmake3 make gcc-c++ +yum -y install bzip2-devel zlib-devel json-c12-devel + +# botan +rpm --import https://github.com/riboseinc/yum/raw/master/ribose-packages.pub +rpm --import https://github.com/riboseinc/yum/raw/master/ribose-packages-next.pub +curl -L https://github.com/riboseinc/yum/raw/master/ribose.repo > /etc/yum.repos.d/ribose.repo +yum -y install botan2-devel +-- + +=== 4. Build the RPM + +[source,console] +-- +yum -y install rpm-build +mkdir ~/build +cd ~/build +cmake3 -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=off -DCPACK_GENERATOR=RPM /usr/local/rnp +make package +-- + +=== 5. Check and Install the RPM + +It may be helpful to run `rpmlint` on the RPM and note new warnings or errors. + +[source,console] +-- +yum -y install rpmlint +rpmlint rnp-0.9.0-1.el7.centos.x86_64.rpm +-- + +At this point, you can test that the RPM installs successfully: + +[source,console] +-- +yum localinstall rnp-0.9.0-1.el7.centos.x86_64.rpm +-- diff --git a/comm/third_party/rnp/docs/develop/release-workflow.adoc b/comm/third_party/rnp/docs/develop/release-workflow.adoc new file mode 100644 index 0000000000..40f4203bd0 --- /dev/null +++ b/comm/third_party/rnp/docs/develop/release-workflow.adoc @@ -0,0 +1,122 @@ += Releases + +== General notes + +* Avoid tagging commits in the `main` branch. +* Release branches should have annotated tags and a CHANGELOG.md. +* The steps below detail creation of a brand new 1.0.0 release. + Some steps would be omitted for minor releases. + +== Creating an initial release + +=== Update documentation + +Update references to version numbers in relevant documentation to the new +version you intend to release. + +[source,console] +---- +git checkout main +vim docs/installation.adoc +git add docs/installation.adoc +git commit +git push +---- + +=== Create branch + +Release branches have names of the form `release/N.x`, where N is the major +version (and `x` is a literal -- not a placeholder). + +[source,console] +---- +git checkout -b release/1.x main +---- + +[[update-changelog-and-version]] +=== Update CHANGELOG and version + +[source,console] +---- +vim CHANGELOG.md +# Add/update CHANGELOG entry for the new version +git add CHANGELOG.md + +echo 1.0.0 > version.txt +git add -f version.txt + +git commit +---- + +=== Create tag + +An initial release would be tagged as follows: + +[source,console] +---- +git tag -a v1.0.0 -m '' +---- + +=== Push branch and tag + +[source,console] +---- +# push the branch +git push origin release/1.x + +# push the tag +git push origin v1.0.0 +---- + +=== Edit tagged release description on GitHub + +. Navigate to the link:#https://github.com/rnpgp/rnp/releases[Releases] page; + +. Edit the tag that was just pushed; + +. Fill the tag's description with data from the corresponding `CHANGELOG` + entries of the same tag version; + +. Publish the release. + + +== Creating a new release + +Maintaining a release branch involves cherry-picking hotfixes and +similar commits from the `main` branch, while following the rules for +Semantic Versioning. + +The steps below will show the release of version 1.0.1. + +=== Add desired changes + +Cherry-pick the appropriate commits into the appropriate `release/N.x` branch. + +To see what commits are in `main` that are not in the release branch, you +can observe the lines starting with `+` in: + +[source,console] +---- +git cherry -v release/1.x main +---- + +It is often useful to pick a range of commits. For example: + +[source,console] +---- +git checkout release/0.x +git cherry-pick a57b36f^..e23352c +---- + +If there are merge commits in this range, this will not work. +Instead, try: + +[source,console] +---- +git checkout release/0.x +git cherry release/0.x main | grep '^+ ' | cut -c 3-9 | \ + while read commit; do git cherry-pick $commit; done +---- + +From here, you can follow the steps for an initial release, +starting with <>. diff --git a/comm/third_party/rnp/docs/installation.adoc b/comm/third_party/rnp/docs/installation.adoc new file mode 100644 index 0000000000..991fa85291 --- /dev/null +++ b/comm/third_party/rnp/docs/installation.adoc @@ -0,0 +1,262 @@ += Installing RNP + +Binaries that will be installed: + +* `rnp` +* `rnpkeys` + + +== On NixOS or Nix package manager + +We provide a Nix package for easy installation on NixOS and any OS with Nix +installed (including Linux and macOS, even NixOS on WSL). + +[source,console] +---- +nix-env -iA nixpkgs.rnp +---- + +== With Nix Flakes + +We provide a Nix flake. + +[source,console] +---- +nix profile install github:rnpgp/rnp +---- + +== On macOS using Homebrew + +We provide a Homebrew tap for easy installation of RNP on macOS. + +[source,console] +---- +brew tap rnpgp/rnp +brew install rnp +---- + +== On RHEL and CentOS via YUM + +We provide pre-built packages for RHEL and CentOS at our YUM repository hosted +at GitHub. + +[source,console] +---- +rpm --import https://github.com/riboseinc/yum/raw/master/ribose-packages.pub +rpm --import https://github.com/riboseinc/yum/raw/master/ribose-packages-next.pub +curl -L https://github.com/riboseinc/yum/raw/master/ribose.repo > /etc/yum.repos.d/ribose.repo +yum install -y rnp +---- + +== On Ubuntu + +Prerequisites: please ensure `git` is installed on the system +[source,console] +---- +# Clone the repository by version tag (or omit it to get the latest sources) +git clone https://github.com/rnpgp/rnp.git -b v0.17.0 + +Please ensure that you clone with submodules if you use a version higher then 0.16.2 +git clone https://github.com/rnpgp/rnp.git --recurse-submodules --shallow-submodules + +# Install required packages +sudo apt install g++-8 cmake libbz2-dev zlib1g-dev libjson-c-dev build-essential python-minimal + +# Download, build and install Botan2 +wget -qO- https://botan.randombit.net/releases/Botan-2.18.2.tar.xz | tar xvJ +cd Botan-2.18.2 +./configure.py --prefix=/usr +make +sudo make install +cd .. + +# CMake encourages building outside of the source directory. +mkdir rnp-build +cd rnp-build + +# Run CMake +cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=off ../rnp/ + +# Compile +make + +# Install +sudo make install +---- + +== On Debian + +Prerequisite: please ensure `git` is installed on the system. + +[source,console] +---- +# Clone the repository by version tag (or omit it to get the latest sources) +git clone https://github.com/rnpgp/rnp.git -b v0.17.0 + +Please ensure that you clone with submodules if you use a version higher then 0.16.2 +git clone https://github.com/rnpgp/rnp.git --recurse-submodules --shallow-submodules + +# Enable access to `testing` packages by editing /etc/apt/sources.list +# deb http://deb.debian.org/debian testing main + +# Install required packages +sudo apt install g++-8 cmake libbz2-dev zlib1g-dev libjson-c-dev \ + libbotan-2-dev build-essential + +# Cmake recommend out-of-source builds +mkdir rnp-build +cd rnp-build + +# Cmake it +cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=off ../rnp/ + +# Compile and install +sudo make install +---- + +== On Gentoo Linux + +RNP ebuilds are available from an overlay repository named `rnp`. + +=== Using eselect-repository (the current way) + +Prerequisite: ensure `eselect-repository` is installed on your system. + +[source,console] +---- +eselect repository enable rnp +emaint sync -r rnp +emerge -av app-crypt/rnp +---- + +=== Using layman (the old way) + +Prerequisite: ensure `layman` is installed on your system. + +[source,console] +---- +layman -a rnp +layman -s rnp +emerge -av app-crypt/rnp +---- + +== Compile from source + +Clone this repo, or download a release and expand it. + +Enter the source folder and run the following commands: + +[source,console] +---- +cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_SHARED_LIBS=on -DBUILD_TESTING=off . + +make install +---- + +== On Windows + +=== Using MSYS/MinGW + +From a clean MSYS2 install, please first update `pacman` and install required +packages via the `msys` console. + +[source,console] +---- +pacman -Syu --noconfirm --needed + +# Most likely you'll need to close msys console and run it again: +pacman -Syu --noconfirm --needed + +# Install packages +pacman --noconfirm -S --needed tar zlib-devel libbz2-devel git automake autoconf libtool automake-wrapper make pkg-config mingw64/mingw-w64-x86_64-cmake mingw64/mingw-w64-x86_64-gcc mingw64/mingw-w64-x86_64-json-c mingw64/mingw-w64-x86_64-libbotan mingw64/mingw-w64-x86_64-python3 +---- + +Then clone the RNP repository and build it. + +Please ensure that you clone with submodules if you use a version higher then 0.16.2 +git clone https://github.com/rnpgp/rnp.git --recurse-submodules --shallow-submodules + +[source,console] +---- +# CMake encourages building outside of the source directory. +mkdir rnp-build +cd rnp-build + +# Add paths to PATH so dependency dll/lib files can be found +export PATH="/c/msys64/mingw64/lib:/c/msys64/mingw64/bin:$PWD/bin:$PATH" + +# Run CMake +cmake -DBUILD_SHARED_LIBS=yes -G "MSYS Makefiles" -DBUILD_TESTING=off ../rnp + +# Compile and install +make && make install +---- + +=== Using Microsoft Visual Studio 2019 and vcpkg + +Install `vcpkg` according to +https://docs.microsoft.com/en-us/cpp/build/install-vcpkg?view=msvc-160&tabs=windows[these instructions]: + +Set the `VCPKG_ROOT` environment variable to the `vcpkg` root folder. + +For botan backend: +[source,console] +---- +vcpkg install --triplet x64-windows bzip2 zlib botan json-c getopt dirent python3[core,enable-shared] +---- + +For openssl backend: +[source,console] +---- +vcpkg install --triplet x64-windows bzip2 zlib botan json-c getopt dirent python3[core,enable-shared] +---- + +If you need to target 32-bit platform you'll need to to replace `x64-windows` with `x86-windows`. + +* The following steps will perform a console build for CMake using Visual Studio 2019 CMake generator: + ++ +-- +[source,console] +---- +cmake -B build -G "Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake \ + -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=off -DCRYPTO_BACKEND="botan" . +cmake --build . --config Release +cmake --install . +---- +-- +Replace CRYPTO_BACKEND parameter to "openssl" if you target this backend. + +Ensure that the following dependencies are available on path: + +* `librnp.dll` +* `botan.dll` or `libcrypto.dll` depending on target backend and architecture +* `bz2.dll` +* `getopt.dll` +* `json-c.dll` +* `zlib1.dll` + +=== Using Microsoft Visual Studio 2019 and pre-installed libraries + +Install dependencies and make them available either on PATH or using CMAKE_TARGET_PREFIX parameter: + +* Botan(2.14+) or Crypto (OpenSSL 1.1.1+) depending on target backend +* BZip2 +* GetOpt +* JSON-C (0.12.1+) +* ZLIB + +If openssl backend is used note that your environment may have another ("default") openssl installation. +In such case use OPENSSL_ROOT_DIR. + +* The following steps will perform a console build for CMake using Visual Studio 2019 CMake generator: + ++ +-- +[source,console] +---- +cmake -B build -G "Visual Studio 16 2019" -A x64 -DOPENSSL_ROOT_DIR= -DCMAKE_TARGET_PREFIX= \ + -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=off -DCRYPTO_BACKEND="botan" . +cmake --build . --config Release +cmake --install . +---- +-- +Replace CRYPTO_BACKEND parameter to "openssl" if you target this backend, use OPENSSL_ROOT_DIR and CMAKE_TARGET_PREFIX optionally as explained above diff --git a/comm/third_party/rnp/docs/navigation.adoc b/comm/third_party/rnp/docs/navigation.adoc new file mode 100644 index 0000000000..385992cb8f --- /dev/null +++ b/comm/third_party/rnp/docs/navigation.adoc @@ -0,0 +1,18 @@ +--- +items: +- { title: Installation, path: installation/ } +- { title: Command-line usage, path: cli-usage/ } +- { title: C API usage, path: c-usage/ } +- title: Developing RNP + path: develop/ + items: + - { title: "C++ usage", path: develop/cpp-usage/ } + - { title: "Packaging", path: develop/packaging/ } + - { title: "Release workflow", path: develop/release-workflow/ } + # - title: "Acceptance tests" + # path: develop/acceptance-tests/ + # items: + # - { title: "rnpkeys-generate-key", path: develop/acceptance-tests/rnpkeys-generate-key } +--- + += Navigation diff --git a/comm/third_party/rnp/docs/signing-keys.adoc b/comm/third_party/rnp/docs/signing-keys.adoc new file mode 100644 index 0000000000..0ebf7ffe52 --- /dev/null +++ b/comm/third_party/rnp/docs/signing-keys.adoc @@ -0,0 +1,5 @@ + += PGP keys used for signing source code + +The current OpenPGP key used for signing source code for RNP is hosted at +https://www.rnpgp.org/openpgp_keys/[rnpgp.org^]. diff --git a/comm/third_party/rnp/include/rekey/rnp_key_store.h b/comm/third_party/rnp/include/rekey/rnp_key_store.h new file mode 100644 index 0000000000..04faabf75f --- /dev/null +++ b/comm/third_party/rnp/include/rekey/rnp_key_store.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef KEY_STORE_H_ +#define KEY_STORE_H_ + +#include +#include +#include "rnp.h" +#include "librepgp/stream-common.h" +#include "pgp-key.h" +#include +#include +#include +#include +#include +#include "librekey/kbx_blob.hpp" +#include "sec_profile.hpp" + +/* Key import status. Order of elements is important. */ +typedef enum pgp_key_import_status_t { + PGP_KEY_IMPORT_STATUS_UNKNOWN = 0, + PGP_KEY_IMPORT_STATUS_UNCHANGED, + PGP_KEY_IMPORT_STATUS_UPDATED, + PGP_KEY_IMPORT_STATUS_NEW, +} pgp_key_import_status_t; + +typedef enum pgp_sig_import_status_t { + PGP_SIG_IMPORT_STATUS_UNKNOWN = 0, + PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY, + PGP_SIG_IMPORT_STATUS_UNCHANGED, + PGP_SIG_IMPORT_STATUS_NEW +} pgp_sig_import_status_t; + +typedef std::unordered_map::iterator> pgp_key_fp_map_t; + +typedef struct rnp_key_store_t { + std::string path; + pgp_key_store_format_t format; + rnp::SecurityContext & secctx; + bool disable_validation = + false; /* do not automatically validate keys, added to this key store */ + + std::list keys; + pgp_key_fp_map_t keybyfp; + std::vector> blobs; + + ~rnp_key_store_t(); + rnp_key_store_t(rnp::SecurityContext &ctx) + : path(""), format(PGP_KEY_STORE_UNKNOWN), secctx(ctx){}; + rnp_key_store_t(pgp_key_store_format_t format, + const std::string & path, + rnp::SecurityContext & ctx); + /* make sure we use only empty constructor */ + rnp_key_store_t(rnp_key_store_t &&src) = delete; + rnp_key_store_t &operator=(rnp_key_store_t &&) = delete; + rnp_key_store_t(const rnp_key_store_t &src) = delete; + rnp_key_store_t &operator=(const rnp_key_store_t &) = delete; +} rnp_key_store_t; + +bool rnp_key_store_load_from_path(rnp_key_store_t *, const pgp_key_provider_t *key_provider); +bool rnp_key_store_load_from_src(rnp_key_store_t *, + pgp_source_t *, + const pgp_key_provider_t *key_provider); + +bool rnp_key_store_write_to_path(rnp_key_store_t *); +bool rnp_key_store_write_to_dst(rnp_key_store_t *, pgp_dest_t *); + +void rnp_key_store_clear(rnp_key_store_t *); + +size_t rnp_key_store_get_key_count(const rnp_key_store_t *); + +/** + * @brief Add key to the keystore, copying it. + * + * @param keyring allocated keyring, cannot be NULL. + * @param key key to be added, cannot be NULL. + * @return pointer to the added key or NULL if failed. + */ +pgp_key_t *rnp_key_store_add_key(rnp_key_store_t *keyring, pgp_key_t *key); + +pgp_key_t *rnp_key_store_import_key(rnp_key_store_t *, + pgp_key_t *, + bool, + pgp_key_import_status_t *); + +/** + * @brief Get signer's key from key store. + * + * @param store populated key store, cannot be NULL. + * @param sig signature, cannot be NULL. + * @return pointer to pgp_key_t structure if key was found or NULL otherwise. + */ +pgp_key_t *rnp_key_store_get_signer_key(rnp_key_store_t *store, const pgp_signature_t *sig); + +pgp_sig_import_status_t rnp_key_store_import_key_signature(rnp_key_store_t * keyring, + pgp_key_t * key, + const pgp_signature_t *sig); + +/** + * @brief Import revocation or direct-key signature to the keyring. + * + * @param keyring populated keyring, cannot be NULL. + * @param sig signature to import. + * @param status signature import status will be put here, if not NULL. + * @return pointer to the key to which this signature belongs (or NULL if key was not found) + */ +pgp_key_t *rnp_key_store_import_signature(rnp_key_store_t * keyring, + const pgp_signature_t * sig, + pgp_sig_import_status_t *status); + +bool rnp_key_store_remove_key(rnp_key_store_t *, const pgp_key_t *, bool); + +bool rnp_key_store_get_key_grip(const pgp_key_material_t *, pgp_key_grip_t &grip); + +const pgp_key_t *rnp_key_store_get_key_by_fpr(const rnp_key_store_t *, + const pgp_fingerprint_t &fpr); +pgp_key_t * rnp_key_store_get_key_by_fpr(rnp_key_store_t *, const pgp_fingerprint_t &fpr); +pgp_key_t * rnp_key_store_get_primary_key(rnp_key_store_t *, const pgp_key_t *); +pgp_key_t *rnp_key_store_search(rnp_key_store_t *, const pgp_key_search_t *, pgp_key_t *); + +#endif /* KEY_STORE_H_ */ diff --git a/comm/third_party/rnp/include/repgp/repgp_def.h b/comm/third_party/rnp/include/repgp/repgp_def.h new file mode 100644 index 0000000000..218736c377 --- /dev/null +++ b/comm/third_party/rnp/include/repgp/repgp_def.h @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2017-2020, 2023 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef REPGP_DEF_H_ +#define REPGP_DEF_H_ + +#include + +/************************************/ +/* Packet Tags - RFC4880, 4.2 */ +/************************************/ + +/** Packet Tag - Bit 7 Mask (this bit is always set). + * The first byte of a packet is the "Packet Tag". It always + * has bit 7 set. This is the mask for it. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_ALWAYS_SET 0x80 + +/** Packet Tag - New Format Flag. + * Bit 6 of the Packet Tag is the packet format indicator. + * If it is set, the new format is used, if cleared the + * old format is used. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_NEW_FORMAT 0x40 + +/** Old Packet Format: Mask for content tag. + * In the old packet format bits 5 to 2 (including) + * are the content tag. This is the mask to apply + * to the packet tag. Note that you need to + * shift by #PGP_PTAG_OF_CONTENT_TAG_SHIFT bits. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_OF_CONTENT_TAG_MASK 0x3c +/** Old Packet Format: Offset for the content tag. + * As described at #PGP_PTAG_OF_CONTENT_TAG_MASK the + * content tag needs to be shifted after being masked + * out from the Packet Tag. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_OF_CONTENT_TAG_SHIFT 2 +/** Old Packet Format: Mask for length type. + * Bits 1 and 0 of the packet tag are the length type + * in the old packet format. + * + * See #pgp_ptag_of_lt_t for the meaning of the values. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_OF_LENGTH_TYPE_MASK 0x03 + +/* Maximum block size for symmetric crypto */ +#define PGP_MAX_BLOCK_SIZE 16 + +/* Maximum key size for symmetric crypto */ +#define PGP_MAX_KEY_SIZE 32 + +/* Salt size for hashing */ +#define PGP_SALT_SIZE 8 + +/* Size of the keyid */ +#define PGP_KEY_ID_SIZE 8 + +/* Size of the fingerprint */ +#define PGP_FINGERPRINT_SIZE 20 +#define PGP_FINGERPRINT_HEX_SIZE (PGP_FINGERPRINT_SIZE * 2) + 1 + +/* Size of the key grip */ +#define PGP_KEY_GRIP_SIZE 20 + +/* PGP marker packet contents */ +#define PGP_MARKER_CONTENTS "PGP" +#define PGP_MARKER_LEN 3 + +/** Old Packet Format Lengths. + * Defines the meanings of the 2 bits for length type in the + * old packet format. + * + * \see RFC4880 4.2.1 + */ +typedef enum { + PGP_PTAG_OLD_LEN_1 = 0x00, /* Packet has a 1 byte length - + * header is 2 bytes long. */ + PGP_PTAG_OLD_LEN_2 = 0x01, /* Packet has a 2 byte length - + * header is 3 bytes long. */ + PGP_PTAG_OLD_LEN_4 = 0x02, /* Packet has a 4 byte + * length - header is 5 bytes + * long. */ + PGP_PTAG_OLD_LEN_INDETERMINATE = 0x03 /* Packet has a + * indeterminate length. */ +} pgp_ptag_of_lt_t; + +/** New Packet Format: Mask for content tag. + * In the new packet format the 6 rightmost bits + * are the content tag. This is the mask to apply + * to the packet tag. Note that you need to + * shift by #PGP_PTAG_NF_CONTENT_TAG_SHIFT bits. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_NF_CONTENT_TAG_MASK 0x3f +/** New Packet Format: Offset for the content tag. + * As described at #PGP_PTAG_NF_CONTENT_TAG_MASK the + * content tag needs to be shifted after being masked + * out from the Packet Tag. + * + * \see RFC4880 4.2 + */ +#define PGP_PTAG_NF_CONTENT_TAG_SHIFT 0 + +#define MDC_PKT_TAG 0xd3 +#define MDC_V1_SIZE 22 + +typedef enum : uint8_t { + PGP_REVOCATION_NO_REASON = 0, + PGP_REVOCATION_SUPERSEDED = 1, + PGP_REVOCATION_COMPROMISED = 2, + PGP_REVOCATION_RETIRED = 3, + PGP_REVOCATION_NO_LONGER_VALID = 0x20 +} pgp_revocation_type_t; + +/** + * @brief OpenPGP packet tags. See section 4.3 of RFC4880 for the detailed description. + * + */ +typedef enum : uint8_t { + PGP_PKT_RESERVED = 0, /* Reserved - a packet tag must not have this value */ + PGP_PKT_PK_SESSION_KEY = 1, /* Public-Key Encrypted Session Key Packet */ + PGP_PKT_SIGNATURE = 2, /* Signature Packet */ + PGP_PKT_SK_SESSION_KEY = 3, /* Symmetric-Key Encrypted Session Key Packet */ + PGP_PKT_ONE_PASS_SIG = 4, /* One-Pass Signature Packet */ + PGP_PKT_SECRET_KEY = 5, /* Secret Key Packet */ + PGP_PKT_PUBLIC_KEY = 6, /* Public Key Packet */ + PGP_PKT_SECRET_SUBKEY = 7, /* Secret Subkey Packet */ + PGP_PKT_COMPRESSED = 8, /* Compressed Data Packet */ + PGP_PKT_SE_DATA = 9, /* Symmetrically Encrypted Data Packet */ + PGP_PKT_MARKER = 10, /* Marker Packet */ + PGP_PKT_LITDATA = 11, /* Literal Data Packet */ + PGP_PKT_TRUST = 12, /* Trust Packet */ + PGP_PKT_USER_ID = 13, /* User ID Packet */ + PGP_PKT_PUBLIC_SUBKEY = 14, /* Public Subkey Packet */ + PGP_PKT_RESERVED2 = 15, /* Reserved */ + PGP_PKT_RESERVED3 = 16, /* Reserved */ + PGP_PKT_USER_ATTR = 17, /* User Attribute Packet */ + PGP_PKT_SE_IP_DATA = 18, /* Sym. Encrypted and Integrity Protected Data Packet */ + PGP_PKT_MDC = 19, /* Modification Detection Code Packet */ + PGP_PKT_AEAD_ENCRYPTED = 20 /* AEAD Encrypted Data Packet, RFC 4880bis */ +} pgp_pkt_type_t; + +/** Public Key Algorithm Numbers. + * OpenPGP assigns a unique Algorithm Number to each algorithm that is part of OpenPGP. + * + * This lists algorithm numbers for public key algorithms. + * + * \see RFC4880 9.1 + */ +typedef enum : uint8_t { + PGP_PKA_NOTHING = 0, /* No PKA */ + PGP_PKA_RSA = 1, /* RSA (Encrypt or Sign) */ + PGP_PKA_RSA_ENCRYPT_ONLY = 2, /* RSA Encrypt-Only (deprecated - + * \see RFC4880 13.5) */ + PGP_PKA_RSA_SIGN_ONLY = 3, /* RSA Sign-Only (deprecated - + * \see RFC4880 13.5) */ + PGP_PKA_ELGAMAL = 16, /* Elgamal (Encrypt-Only) */ + PGP_PKA_DSA = 17, /* DSA (Digital Signature Algorithm) */ + PGP_PKA_ECDH = 18, /* ECDH public key algorithm */ + PGP_PKA_ECDSA = 19, /* ECDSA public key algorithm [FIPS186-3] */ + PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN = 20, /* Elgamal Encrypt or Sign. Implementation MUST not + generate such keys and elgamal signatures. */ + PGP_PKA_RESERVED_DH = 21, /* Reserved for Diffie-Hellman + * (X9.42, as defined for + * IETF-S/MIME) */ + PGP_PKA_EDDSA = 22, /* EdDSA from draft-ietf-openpgp-rfc4880bis */ + PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ + + PGP_PKA_PRIVATE00 = 100, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE01 = 101, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE02 = 102, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE03 = 103, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE04 = 104, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE05 = 105, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE06 = 106, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE07 = 107, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE08 = 108, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE09 = 109, /* Private/Experimental Algorithm */ + PGP_PKA_PRIVATE10 = 110 /* Private/Experimental Algorithm */ +} pgp_pubkey_alg_t; + +/** + * Enumeration of elliptic curves used by PGP. + * + * \see RFC4880-bis01 9.2. ECC Curve OID + * + * Values in this enum correspond to order in ec_curve array (in ec.c) + */ +typedef enum { + PGP_CURVE_UNKNOWN = 0, + PGP_CURVE_NIST_P_256, + PGP_CURVE_NIST_P_384, + PGP_CURVE_NIST_P_521, + PGP_CURVE_ED25519, + PGP_CURVE_25519, + PGP_CURVE_BP256, + PGP_CURVE_BP384, + PGP_CURVE_BP512, + PGP_CURVE_P256K1, + + PGP_CURVE_SM2_P_256, + + // Keep always last one + PGP_CURVE_MAX +} pgp_curve_t; + +/** Symmetric Key Algorithm Numbers. + * OpenPGP assigns a unique Algorithm Number to each algorithm that is + * part of OpenPGP. + * + * This lists algorithm numbers for symmetric key algorithms. + * + * \see RFC4880 9.2 + */ +typedef enum { + PGP_SA_PLAINTEXT = 0, /* Plaintext or unencrypted data */ + PGP_SA_IDEA = 1, /* IDEA */ + PGP_SA_TRIPLEDES = 2, /* TripleDES */ + PGP_SA_CAST5 = 3, /* CAST5 */ + PGP_SA_BLOWFISH = 4, /* Blowfish */ + PGP_SA_AES_128 = 7, /* AES with 128-bit key (AES) */ + PGP_SA_AES_192 = 8, /* AES with 192-bit key */ + PGP_SA_AES_256 = 9, /* AES with 256-bit key */ + PGP_SA_TWOFISH = 10, /* Twofish with 256-bit key (TWOFISH) */ + PGP_SA_CAMELLIA_128 = 11, /* Camellia with 128-bit key (CAMELLIA) */ + PGP_SA_CAMELLIA_192 = 12, /* Camellia with 192-bit key */ + PGP_SA_CAMELLIA_256 = 13, /* Camellia with 256-bit key */ + + PGP_SA_SM4 = 105, /* RNP extension - SM4 */ + PGP_SA_UNKNOWN = 255 +} pgp_symm_alg_t; + +typedef enum { + PGP_CIPHER_MODE_NONE = 0, + PGP_CIPHER_MODE_CFB = 1, + PGP_CIPHER_MODE_CBC = 2, + PGP_CIPHER_MODE_OCB = 3, +} pgp_cipher_mode_t; + +typedef enum { + PGP_AEAD_NONE = 0, + PGP_AEAD_EAX = 1, + PGP_AEAD_OCB = 2, + PGP_AEAD_UNKNOWN = 255 +} pgp_aead_alg_t; + +/** s2k_usage_t + */ +typedef enum { + PGP_S2KU_NONE = 0, + PGP_S2KU_ENCRYPTED_AND_HASHED = 254, + PGP_S2KU_ENCRYPTED = 255 +} pgp_s2k_usage_t; + +/** s2k_specifier_t + */ +typedef enum : uint8_t { + PGP_S2KS_SIMPLE = 0, + PGP_S2KS_SALTED = 1, + PGP_S2KS_ITERATED_AND_SALTED = 3, + PGP_S2KS_EXPERIMENTAL = 101 +} pgp_s2k_specifier_t; + +typedef enum { + PGP_S2K_GPG_NONE = 0, + PGP_S2K_GPG_NO_SECRET = 1, + PGP_S2K_GPG_SMARTCARD = 2 +} pgp_s2k_gpg_extension_t; + +/** Signature Type. + * OpenPGP defines different signature types that allow giving + * different meanings to signatures. Signature types include 0x10 for + * generitc User ID certifications (used when Ben signs Weasel's key), + * Subkey binding signatures, document signatures, key revocations, + * etc. + * + * Different types are used in different places, and most make only + * sense in their intended location (for instance a subkey binding has + * no place on a UserID). + * + * \see RFC4880 5.2.1 + */ +typedef enum : uint8_t { + PGP_SIG_BINARY = 0x00, /* Signature of a binary document */ + PGP_SIG_TEXT = 0x01, /* Signature of a canonical text document */ + PGP_SIG_STANDALONE = 0x02, /* Standalone signature */ + + PGP_CERT_GENERIC = 0x10, /* Generic certification of a User ID and + * Public Key packet */ + PGP_CERT_PERSONA = 0x11, /* Persona certification of a User ID and + * Public Key packet */ + PGP_CERT_CASUAL = 0x12, /* Casual certification of a User ID and + * Public Key packet */ + PGP_CERT_POSITIVE = 0x13, /* Positive certification of a + * User ID and Public Key packet */ + + PGP_SIG_SUBKEY = 0x18, /* Subkey Binding Signature */ + PGP_SIG_PRIMARY = 0x19, /* Primary Key Binding Signature */ + PGP_SIG_DIRECT = 0x1f, /* Signature directly on a key */ + + PGP_SIG_REV_KEY = 0x20, /* Key revocation signature */ + PGP_SIG_REV_SUBKEY = 0x28, /* Subkey revocation signature */ + PGP_SIG_REV_CERT = 0x30, /* Certification revocation signature */ + + PGP_SIG_TIMESTAMP = 0x40, /* Timestamp signature */ + + PGP_SIG_3RD_PARTY = 0x50 /* Third-Party Confirmation signature */ +} pgp_sig_type_t; + +/** Signature Subpacket Type + * Signature subpackets contains additional information about the signature + * + * \see RFC4880 5.2.3.1-5.2.3.26 + */ + +typedef enum { + PGP_SIG_SUBPKT_UNKNOWN = 0, + PGP_SIG_SUBPKT_RESERVED_1 = 1, + PGP_SIG_SUBPKT_CREATION_TIME = 2, /* signature creation time */ + PGP_SIG_SUBPKT_EXPIRATION_TIME = 3, /* signature expiration time */ + PGP_SIG_SUBPKT_EXPORT_CERT = 4, /* exportable certification */ + PGP_SIG_SUBPKT_TRUST = 5, /* trust signature */ + PGP_SIG_SUBPKT_REGEXP = 6, /* regular expression */ + PGP_SIG_SUBPKT_REVOCABLE = 7, /* revocable */ + PGP_SIG_SUBPKT_RESERVED_8 = 8, + PGP_SIG_SUBPKT_KEY_EXPIRY = 9, /* key expiration time */ + PGP_SIG_SUBPKT_PLACEHOLDER = 10, /* placeholder for backward compatibility */ + PGP_SIG_SUBPKT_PREFERRED_SKA = 11, /* preferred symmetric algs */ + PGP_SIG_SUBPKT_REVOCATION_KEY = 12, /* revocation key */ + PGP_SIG_SUBPKT_RESERVED_13 = 13, + PGP_SIG_SUBPKT_RESERVED_14 = 14, + PGP_SIG_SUBPKT_RESERVED_15 = 15, + PGP_SIG_SUBPKT_ISSUER_KEY_ID = 16, /* issuer key ID */ + PGP_SIG_SUBPKT_RESERVED_17 = 17, + PGP_SIG_SUBPKT_RESERVED_18 = 18, + PGP_SIG_SUBPKT_RESERVED_19 = 19, + PGP_SIG_SUBPKT_NOTATION_DATA = 20, /* notation data */ + PGP_SIG_SUBPKT_PREFERRED_HASH = 21, /* preferred hash algs */ + PGP_SIG_SUBPKT_PREF_COMPRESS = 22, /* preferred compression algorithms */ + PGP_SIG_SUBPKT_KEYSERV_PREFS = 23, /* key server preferences */ + PGP_SIG_SUBPKT_PREF_KEYSERV = 24, /* preferred key Server */ + PGP_SIG_SUBPKT_PRIMARY_USER_ID = 25, /* primary user ID */ + PGP_SIG_SUBPKT_POLICY_URI = 26, /* policy URI */ + PGP_SIG_SUBPKT_KEY_FLAGS = 27, /* key flags */ + PGP_SIG_SUBPKT_SIGNERS_USER_ID = 28, /* signer's user ID */ + PGP_SIG_SUBPKT_REVOCATION_REASON = 29, /* reason for revocation */ + PGP_SIG_SUBPKT_FEATURES = 30, /* features */ + PGP_SIG_SUBPKT_SIGNATURE_TARGET = 31, /* signature target */ + PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE = 32, /* embedded signature */ + PGP_SIG_SUBPKT_ISSUER_FPR = 33, /* issuer fingerprint */ + PGP_SIG_SUBPKT_PREFERRED_AEAD = 34, /* preferred AEAD algorithms */ + PGP_SIG_SUBPKT_PRIVATE_100 = 100, /* private/experimental subpackets */ + PGP_SIG_SUBPKT_PRIVATE_101 = 101, + PGP_SIG_SUBPKT_PRIVATE_102 = 102, + PGP_SIG_SUBPKT_PRIVATE_103 = 103, + PGP_SIG_SUBPKT_PRIVATE_104 = 104, + PGP_SIG_SUBPKT_PRIVATE_105 = 105, + PGP_SIG_SUBPKT_PRIVATE_106 = 106, + PGP_SIG_SUBPKT_PRIVATE_107 = 107, + PGP_SIG_SUBPKT_PRIVATE_108 = 108, + PGP_SIG_SUBPKT_PRIVATE_109 = 109, + PGP_SIG_SUBPKT_PRIVATE_110 = 110 +} pgp_sig_subpacket_type_t; + +/** Key Flags + * + * \see RFC4880 5.2.3.21 + */ +typedef enum { + PGP_KF_CERTIFY = 0x01, /* This key may be used to certify other keys. */ + PGP_KF_SIGN = 0x02, /* This key may be used to sign data. */ + PGP_KF_ENCRYPT_COMMS = 0x04, /* This key may be used to encrypt communications. */ + PGP_KF_ENCRYPT_STORAGE = 0x08, /* This key may be used to encrypt storage. */ + PGP_KF_SPLIT = 0x10, /* The private component of this key may have been split + by a secret-sharing mechanism. */ + PGP_KF_AUTH = 0x20, /* This key may be used for authentication. */ + PGP_KF_SHARED = 0x80, /* The private component of this key may be in the + possession of more than one person. */ + /* pseudo flags */ + PGP_KF_NONE = 0x00, + PGP_KF_ENCRYPT = PGP_KF_ENCRYPT_COMMS | PGP_KF_ENCRYPT_STORAGE, +} pgp_key_flags_t; + +typedef enum { + PGP_KEY_FEATURE_MDC = 0x01, + PGP_KEY_FEATURE_AEAD = 0x02, + PGP_KEY_FEATURE_V5 = 0x04 +} pgp_key_feature_t; + +/** Types of Compression */ +typedef enum { + PGP_C_NONE = 0, + PGP_C_ZIP = 1, + PGP_C_ZLIB = 2, + PGP_C_BZIP2 = 3, + PGP_C_UNKNOWN = 255 +} pgp_compression_type_t; + +enum { PGP_SE_IP_DATA_VERSION = 1, PGP_PKSK_V3 = 3, PGP_SKSK_V4 = 4, PGP_SKSK_V5 = 5 }; + +/** Version. + * OpenPGP has two different protocol versions: version 3 and version 4. + * + * \see RFC4880 5.2 + */ +typedef enum { + PGP_VUNKNOWN = 0, + PGP_V2 = 2, /* Version 2 (essentially the same as v3) */ + PGP_V3 = 3, /* Version 3 */ + PGP_V4 = 4 /* Version 4 */ +} pgp_version_t; + +typedef enum pgp_op_t { + PGP_OP_UNKNOWN = 0, + PGP_OP_ADD_SUBKEY = 1, /* adding a subkey, primary key password required */ + PGP_OP_SIGN = 2, /* signing file or data */ + PGP_OP_DECRYPT = 3, /* decrypting file or data */ + PGP_OP_UNLOCK = 4, /* unlocking a key with key->unlock() */ + PGP_OP_PROTECT = 5, /* adding protection to a key */ + PGP_OP_UNPROTECT = 6, /* removing protection from a (locked) key */ + PGP_OP_DECRYPT_SYM = 7, /* symmetric decryption */ + PGP_OP_ENCRYPT_SYM = 8, /* symmetric encryption */ + PGP_OP_VERIFY = 9, /* signature verification */ + PGP_OP_ADD_USERID = 10, /* adding a userid */ + PGP_OP_MERGE_INFO = 11, /* merging information from one key to another */ + PGP_OP_ENCRYPT = 12, /* public-key encryption */ + PGP_OP_CERTIFY = 13 /* key certification */ +} pgp_op_t; + +/** Hashing Algorithm Numbers. + * OpenPGP assigns a unique Algorithm Number to each algorithm that is + * part of OpenPGP. + * + * This lists algorithm numbers for hash algorithms. + * + * \see RFC4880 9.4 + */ +typedef enum : uint8_t { + PGP_HASH_UNKNOWN = 0, /* used to indicate errors */ + PGP_HASH_MD5 = 1, + PGP_HASH_SHA1 = 2, + PGP_HASH_RIPEMD = 3, + + PGP_HASH_SHA256 = 8, + PGP_HASH_SHA384 = 9, + PGP_HASH_SHA512 = 10, + PGP_HASH_SHA224 = 11, + PGP_HASH_SHA3_256 = 12, + PGP_HASH_SHA3_512 = 14, + + /* Private range */ + PGP_HASH_SM3 = 105, +} pgp_hash_alg_t; + +typedef enum pgp_key_store_format_t { + PGP_KEY_STORE_UNKNOWN = 0, + PGP_KEY_STORE_GPG, + PGP_KEY_STORE_KBX, + PGP_KEY_STORE_G10, +} pgp_key_store_format_t; + +namespace rnp { +enum class AuthType { None, MDC, AEADv1 }; +} + +#endif diff --git a/comm/third_party/rnp/include/rnp.h b/comm/third_party/rnp/include/rnp.h new file mode 100644 index 0000000000..0d666db7eb --- /dev/null +++ b/comm/third_party/rnp/include/rnp.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_RNP_H +#define RNP_RNP_H + +#include "types.h" +#include "pass-provider.h" +#include "key-provider.h" +#include "crypto/rng.h" +#include +#include "utils.h" + +#endif // RNP_RNP_H diff --git a/comm/third_party/rnp/include/rnp/rnp.h b/comm/third_party/rnp/include/rnp/rnp.h new file mode 100644 index 0000000000..66671698a2 --- /dev/null +++ b/comm/third_party/rnp/include/rnp/rnp.h @@ -0,0 +1,3150 @@ +/*- + * Copyright (c) 2017-2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Function return type. 0 == SUCCESS, all other values indicate an error. + */ +typedef uint32_t rnp_result_t; + +#define RNP_KEY_EXPORT_ARMORED (1U << 0) +#define RNP_KEY_EXPORT_PUBLIC (1U << 1) +#define RNP_KEY_EXPORT_SECRET (1U << 2) +#define RNP_KEY_EXPORT_SUBKEYS (1U << 3) + +/* Export base64-encoded autocrypt key instead of binary */ +#define RNP_KEY_EXPORT_BASE64 (1U << 9) + +#define RNP_KEY_REMOVE_PUBLIC (1U << 0) +#define RNP_KEY_REMOVE_SECRET (1U << 1) +#define RNP_KEY_REMOVE_SUBKEYS (1U << 2) + +#define RNP_KEY_UNLOAD_PUBLIC (1U << 0) +#define RNP_KEY_UNLOAD_SECRET (1U << 1) + +/** + * Flags for optional details to include in JSON. + */ +#define RNP_JSON_PUBLIC_MPIS (1U << 0) +#define RNP_JSON_SECRET_MPIS (1U << 1) +#define RNP_JSON_SIGNATURES (1U << 2) +#define RNP_JSON_SIGNATURE_MPIS (1U << 3) + +/** + * Flags to include additional data in packet dumping + */ +#define RNP_JSON_DUMP_MPI (1U << 0) +#define RNP_JSON_DUMP_RAW (1U << 1) +#define RNP_JSON_DUMP_GRIP (1U << 2) + +#define RNP_DUMP_MPI (1U << 0) +#define RNP_DUMP_RAW (1U << 1) +#define RNP_DUMP_GRIP (1U << 2) + +/** + * Flags for the key loading/saving functions. + */ +#define RNP_LOAD_SAVE_PUBLIC_KEYS (1U << 0) +#define RNP_LOAD_SAVE_SECRET_KEYS (1U << 1) +#define RNP_LOAD_SAVE_PERMISSIVE (1U << 8) +#define RNP_LOAD_SAVE_SINGLE (1U << 9) +#define RNP_LOAD_SAVE_BASE64 (1U << 10) + +/** + * Flags for the rnp_key_remove_signatures + */ + +#define RNP_KEY_SIGNATURE_INVALID (1U << 0) +#define RNP_KEY_SIGNATURE_UNKNOWN_KEY (1U << 1) +#define RNP_KEY_SIGNATURE_NON_SELF_SIG (1U << 2) + +#define RNP_KEY_SIGNATURE_KEEP (0U) +#define RNP_KEY_SIGNATURE_REMOVE (1U) + +/** + * Flags for output structure creation. + */ +#define RNP_OUTPUT_FILE_OVERWRITE (1U << 0) +#define RNP_OUTPUT_FILE_RANDOM (1U << 1) + +/** + * Flags for default key selection. + */ +#define RNP_KEY_SUBKEYS_ONLY (1U << 0) + +/** + * User id type + */ +#define RNP_USER_ID (1U) +#define RNP_USER_ATTR (2U) + +/** + * Predefined feature security levels + */ +#define RNP_SECURITY_PROHIBITED (0U) +#define RNP_SECURITY_INSECURE (1U) +#define RNP_SECURITY_DEFAULT (2U) + +/** + * Flags for feature security rules. + */ +#define RNP_SECURITY_OVERRIDE (1U << 0) +#define RNP_SECURITY_VERIFY_KEY (1U << 1) +#define RNP_SECURITY_VERIFY_DATA (1U << 2) +#define RNP_SECURITY_REMOVE_ALL (1U << 16) + +/** + * Encryption flags + */ +#define RNP_ENCRYPT_NOWRAP (1U << 0) + +/** + * Decryption/verification flags + */ +#define RNP_VERIFY_IGNORE_SIGS_ON_DECRYPT (1U << 0) +#define RNP_VERIFY_REQUIRE_ALL_SIGS (1U << 1) +#define RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT (1U << 2) + +/** + * Return a constant string describing the result code + */ +RNP_API const char *rnp_result_to_string(rnp_result_t result); + +RNP_API const char *rnp_version_string(); +RNP_API const char *rnp_version_string_full(); + +/** return a value representing the version of librnp + * + * This function is only useful for releases. For non-releases, + * it will return 0. + * + * The value returned can be used in comparisons by utilizing + * rnp_version_for. + * + * @return a value representing the librnp version + **/ +RNP_API uint32_t rnp_version(); + +/** return a value representing a specific version of librnp + * + * This value can be used in comparisons. + * + * @return a value representing a librnp version + **/ +RNP_API uint32_t rnp_version_for(uint32_t major, uint32_t minor, uint32_t patch); + +/** return the librnp major version + * + * @return + **/ +RNP_API uint32_t rnp_version_major(uint32_t version); + +/** return the librnp minor version + * + * @return + **/ +RNP_API uint32_t rnp_version_minor(uint32_t version); + +/** return the librnp patch version + * + * @return + **/ +RNP_API uint32_t rnp_version_patch(uint32_t version); + +/** return a unix timestamp of the last commit, if available + * + * This function is only useful for non-releases. For releases, + * it will return 0. + * + * The intended usage is to provide a form of versioning for the main + * branch. + * + * @return the unix timestamp of the last commit, or 0 if unavailable + **/ +RNP_API uint64_t rnp_version_commit_timestamp(); + +#ifndef RNP_NO_DEPRECATED +/** @brief This function is deprecated and should not be used anymore. It would just silently + * return RNP_SUCCESS. + * + * @param file name of the sourcer file. Use 'all' to enable debug for all code. + * + */ +RNP_API RNP_DEPRECATED rnp_result_t rnp_enable_debug(const char *file); + +/** + * @brief This function is deprecated and should not be used anymore. It would just silently + * return RNP_SUCCESS. + * + */ +RNP_API RNP_DEPRECATED rnp_result_t rnp_disable_debug(); +#endif + +/* + * Opaque structures + */ +typedef struct rnp_ffi_st * rnp_ffi_t; +typedef struct rnp_key_handle_st * rnp_key_handle_t; +typedef struct rnp_input_st * rnp_input_t; +typedef struct rnp_output_st * rnp_output_t; +typedef struct rnp_op_generate_st * rnp_op_generate_t; +typedef struct rnp_op_sign_st * rnp_op_sign_t; +typedef struct rnp_op_sign_signature_st * rnp_op_sign_signature_t; +typedef struct rnp_op_verify_st * rnp_op_verify_t; +typedef struct rnp_op_verify_signature_st *rnp_op_verify_signature_t; +typedef struct rnp_op_encrypt_st * rnp_op_encrypt_t; +typedef struct rnp_identifier_iterator_st *rnp_identifier_iterator_t; +typedef struct rnp_uid_handle_st * rnp_uid_handle_t; +typedef struct rnp_signature_handle_st * rnp_signature_handle_t; +typedef struct rnp_recipient_handle_st * rnp_recipient_handle_t; +typedef struct rnp_symenc_handle_st * rnp_symenc_handle_t; + +/* Callbacks */ +/** + * @brief Callback, used to read data from the source. + * + * @param app_ctx custom parameter, passed back to the function. + * @param buf on successful call data should be put here. Cannot be NULL, + * and must be capable to store at least len bytes. + * @param len number of bytes to read. + * @param read on successful call number of read bytes must be put here. + * @return true on success (including EOF condition), or false on read error. + * EOF case is indicated by zero bytes read on non-zero read call. + */ +typedef bool rnp_input_reader_t(void *app_ctx, void *buf, size_t len, size_t *read); +/** + * @brief Callback, used to close input stream. + * + * @param app_ctx custom parameter, passed back to the function. + * @return void + */ +typedef void rnp_input_closer_t(void *app_ctx); +/** + * @brief Callback, used to write data to the output stream. + * + * @param app_ctx custom parameter, passed back to the function. + * @param buf buffer with data, cannot be NULL. + * @param len number of bytes to write. + * @return true if call was successful and all data is written, or false otherwise. + */ +typedef bool rnp_output_writer_t(void *app_ctx, const void *buf, size_t len); + +/** + * @brief Callback, used to close output stream. + * + * @param app_ctx custom parameter, passed back to the function. + * @param discard true if the already written data should be deleted. + * @return void + */ +typedef void rnp_output_closer_t(void *app_ctx, bool discard); + +/** + * Callback used for getting a password. + * + * @param ffi + * @param app_ctx provided by application + * @param key the key, if any, for which the password is being requested. + * Note: this key handle should not be held by the application, + * it is destroyed after the callback. It should only be used to + * retrieve information like the userids, grip, etc. + * @param pgp_context a descriptive string on why the password is being + * requested, may have one of the following values: + * - "add subkey": add subkey to the encrypted secret key + * - "add userid": add userid to the encrypted secret key + * - "sign": sign data + * - "decrypt": decrypt data using the encrypted secret key + * - "unlock": temporary unlock secret key (decrypting its fields), so it may be used + * later without need to decrypt + * - "protect": encrypt secret key fields + * - "unprotect": decrypt secret key fields, leaving those in a raw format + * - "decrypt (symmetric)": decrypt data, using the password + * - "encrypt (symmetric)": encrypt data, using the password + * @param buf to which the callback should write the returned password, NULL terminated. + * @param buf_len the size of buf + * @return true if a password was provided, false otherwise + */ +typedef bool (*rnp_password_cb)(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len); + +/** callback used to signal the application that a key is needed + * + * The application should use the appropriate functions (rnp_load_public_keys, etc) + * to load the requested key. + * + * This may be called multiple times for the same key. For example, if attempting + * to verify a signature, the signer's keyid may be used first to request the key. + * If that is not successful, the signer's fingerprint (if available) may be used. + * + * Please note that there is a special case with 'hidden' recipient, with all-zero keyid. In + * this case implementation should load all available secret keys for the decryption attempt + * (or do nothing, in this case decryption to the hidden recipient would fail). + * + * Situations in which this callback would be used include: + * - When decrypting data that includes a public-key encrypted session key, + * and the key is not found in the keyrings. + * - When attempting to verify a signature, when the signer's key is not found in + * the keyrings. + * + * @param ffi + * @param app_ctx provided by application in rnp_keyring_open + * @param identifier_type the type of identifier ("userid", "keyid", "grip") + * @param identifier the identifier for locating the key + * @param secret true if a secret key is being requested + */ +typedef void (*rnp_get_key_cb)(rnp_ffi_t ffi, + void * app_ctx, + const char *identifier_type, + const char *identifier, + bool secret); + +/** + * @brief callback used to report back signatures from the function + * rnp_key_remove_signatures(). This may be used to implement custom signature filtering + * code or record information about the signatures which are removed. + * @param ffi + * @param app_ctx custom context, provided by application. + * @param sig signature handle to retrieve information about the signature. Callback must not + * call rnp_signature_handle_destroy() on it. + * @param action action which will be performed on the signature. Currently defined are + * RNP_KEY_SIGNATURE_KEEP an RNP_KEY_SIGNATURE_REMOVE. + * Callback may overwrite this value. + * + */ +typedef void (*rnp_key_signatures_cb)(rnp_ffi_t ffi, + void * app_ctx, + rnp_signature_handle_t sig, + uint32_t * action); + +/** create the top-level object used for interacting with the library + * + * @param ffi pointer that will be set to the created ffi object + * @param pub_format the format of the public keyring, RNP_KEYSTORE_GPG or other + * RNP_KEYSTORE_* constant + * @param sec_format the format of the secret keyring, RNP_KEYSTORE_GPG or other + * RNP_KEYSTORE_* constant + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_ffi_create(rnp_ffi_t * ffi, + const char *pub_format, + const char *sec_format); + +/** destroy the top-level object used for interacting with the library + * + * Note that this invalidates key handles, keyrings, and any other + * objects associated with this particular object. + * + * @param ffi the ffi object + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_ffi_destroy(rnp_ffi_t ffi); + +RNP_API rnp_result_t rnp_ffi_set_log_fd(rnp_ffi_t ffi, int fd); + +/** + * @brief Set key provider callback. This callback would be called in case when required public + * or secret key is not loaded to the keyrings. + * + * @param ffi initialized ffi object, cannot be NULL. + * @param getkeycb callback function. See rnp_get_key_cb documentation for details. + * @param getkeycb_ctx implementation-specific context, which would be passed to the getkeycb + * on invocation. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_ffi_set_key_provider(rnp_ffi_t ffi, + rnp_get_key_cb getkeycb, + void * getkeycb_ctx); +RNP_API rnp_result_t rnp_ffi_set_pass_provider(rnp_ffi_t ffi, + rnp_password_cb getpasscb, + void * getpasscb_ctx); + +/* Operations on key rings */ + +/** retrieve the default homedir (example: /home/user/.rnp) + * + * @param homedir pointer that will be set to the homedir path. + * The caller should free this with rnp_buffer_destroy. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_get_default_homedir(char **homedir); + +/** Try to detect the formats and paths of the homedir keyrings. + * @param homedir the path to the home directory (example: /home/user/.rnp) + * @param pub_format pointer that will be set to the format of the public keyring. + * The caller should free this with rnp_buffer_destroy. + * Note: this and below may be set to NULL in case of no known format is found. + * @param pub_path pointer that will be set to the path to the public keyring. + * The caller should free this with rnp_buffer_destroy. + * @param sec_format pointer that will be set to the format of the secret keyring. + * The caller should free this with rnp_buffer_destroy. + * @param sec_path pointer that will be set to the path to the secret keyring. + * The caller should free this with rnp_buffer_destroy. + * @return RNP_SUCCESS on success (even if no known format was found), or any other value on + * error. + */ +RNP_API rnp_result_t rnp_detect_homedir_info( + const char *homedir, char **pub_format, char **pub_path, char **sec_format, char **sec_path); + +/** try to detect the key format of the provided data + * + * @param buf the key data, must not be NULL + * @param buf_len the size of the buffer, must be > 0 + * @param format pointer that will be set to the format of the keyring. + * Must not be NULL. The caller should free this with rnp_buffer_destroy. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_detect_key_format(const uint8_t buf[], size_t buf_len, char **format); + +/** Get the number of s2k hash iterations, based on calculation time requested. + * Number of iterations is used to derive encryption key from password. + * + * @param hash hash algorithm to try + * @param msec number of milliseconds which will be needed to derive key from the password. + * Since it depends on CPU speed the calculated value will make sense only for the + * system it was calculated for. + * @param iterations approximate number of iterations to satisfy time complexity. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_calculate_iterations(const char *hash, + size_t msec, + size_t * iterations); + +/** Check whether rnp supports specific feature (algorithm, elliptic curve, whatever else). + * + * @param type string with the feature type. See RNP_FEATURE_* defines for the supported + * values. + * @param name value of the feature to check whether it is supported. + * @param supported will contain true or false depending whether feature is supported or not. + * @return RNP_SUCCESS on success or any other value on error. + */ +RNP_API rnp_result_t rnp_supports_feature(const char *type, const char *name, bool *supported); + +/** Get the JSON with array of supported rnp feature values (algorithms, curves, etc) by type. + * + * @param type type of the feature. See RNP_FEATURE_* defines for the supported values. + * @param result after successful execution will contain the JSON with supported feature + * values. You must destroy it using the rnp_buffer_destroy() function. + * @return RNP_SUCCESS on success or any other value on error. + */ +RNP_API rnp_result_t rnp_supported_features(const char *type, char **result); + +/** + * @brief Add new security rule to the FFI. Security rules allows to override default algorithm + * security settings by disabling them or marking as insecure. After creation of FFI + * object default rules are added, however caller may add more strict rules or + * completely overwrite rule table by calling rnp_remove_security_rule(). + * Note: key signature validation status is cached, so rules should be changed before + * keyrings are loaded or keyring should be reloaded after updating rules. + * + * @param ffi initialized FFI object. + * @param type type of the feature, cannot be NULL. Currently only RNP_FEATURE_HASH_ALG is + * supported. + * @param name name of the feature, i.e. SHA1, MD5. The same values are used in + * rnp_supports_feature()/rnp_supported_features(). + * @param flags additional flags. Following ones currently supported: + * - RNP_SECURITY_OVERRIDE : override all other rules for the specified feature. + * May be used to temporarily enable or disable some feature value (e.g., to + * enable verification of SHA1 or MD5 signature), and then revert changes via + * rnp_remove_security_rule(). + * - RNP_SECURITY_VERIFY_KEY : limit rule only to the key signature verification. + * - RNP_SECURITY_VERIFY_DATA : limit rule only to the data signature + * verification. + * Note: by default rule applies to all possible usages. + * + * @param from timestamp, from when the rule is active. Objects that have creation time (like + * signatures) are matched with the closest rules from the past, unless there is + * a rule with an override flag. For instance, given a single rule with algorithm + * 'MD5', level 'insecure' and timestamp '2012-01-01', all signatures made before + * 2012-01-01 using the MD5 hash algorithm are considered to be at the default + * security level (i.e., valid), whereas all signatures made after 2021-01-01 will + * be marked as 'insecure' (i.e., invalid). + * @param level security level of the rule. Currently the following ones are defined: + * - RNP_SECURITY_PROHIBITED : feature (for instance, MD5 algorithm) is completely + * disabled, so no processing can be done. In terms of signature check, that + * would mean the check will fail right after the hashing begins. + * Note: Currently it works in the same way as RNP_SECURITY_INSECURE. + * - RNP_SECURITY_INSECURE : feature (for instance, SHA1 algorithm) is marked as + * insecure. So even valid signatures, produced later than `from`, will be + * marked as invalid. + * - RNP_SECURITY_DEFAULT : feature is secure enough. Default value when there are + * no other rules for feature. + * + * @return RNP_SUCCESS or any other value on error. + */ +RNP_API rnp_result_t rnp_add_security_rule(rnp_ffi_t ffi, + const char *type, + const char *name, + uint32_t flags, + uint64_t from, + uint32_t level); + +/** + * @brief Get security rule applicable for the corresponding feature value and timestamp. + * Note: if there is no matching rule, it will fall back to the default security level + * with empty flags and `from`. + * + * @param ffi initialized FFI object. + * @param type feature type to search for. Only RNP_FEATURE_HASH_ALG is supported right now. + * @param name feature name, i.e. SHA1 or so on. + * @param time timestamp for which feature should be checked. + * @param flags if non-NULL then rule's flags will be put here. In this case *flags must be + * initialized to the desired usage limitation: + * - 0 to look up for any usage (this is also assumed if flags parameter is + * NULL). + * - RNP_SECURITY_VERIFY_KEY, RNP_SECURITY_VERIFY_DATA and so on to look up for + * the specific usage. Please note that constants cannot be ORed here, only + * single one must be present. + * @param from if non-NULL then rule's from time will be put here. + * @param level cannot be NULL. Security level will be stored here. + * @return RNP_SUCCESS or any other value on error. + */ +RNP_API rnp_result_t rnp_get_security_rule(rnp_ffi_t ffi, + const char *type, + const char *name, + uint64_t time, + uint32_t * flags, + uint64_t * from, + uint32_t * level); + +/** + * @brief Remove security rule(s), matching the parameters. + * Note: use this with caution, as this may also clear default security rules, so + * all affected features would be considered of the default security level. + * + * @param ffi populated FFI structure, cannot be NULL. + * @param type type of the feature. If NULL, then all of the rules will be cleared. + * @param name name of the feature. If NULL, then all rules of the type will be cleared. + * @param level security level of the rule. + * @param flags additional flags, following are defined at the moment: + * - RNP_SECURITY_OVERRIDE : rule should match this flag + * - RNP_SECURITY_VERIFY_KEY, RNP_SECURITY_VERIFY_DATA : rule should match these flags + * (can be ORed together) + * - RNP_SECURITY_REMOVE_ALL : remove all rules for type and name. + * @param from timestamp, for when the rule should be removed. Ignored if + * RNP_SECURITY_REMOVE_ALL_FROM is specified. + * @param removed if non-NULL then number of removed rules will be stored here. + * @return RNP_SUCCESS on success or any other value on error. Please note that if no rules are + * matched, execution will be marked as successful. Use the `removed` parameter to + * check for this case. + */ +RNP_API rnp_result_t rnp_remove_security_rule(rnp_ffi_t ffi, + const char *type, + const char *name, + uint32_t level, + uint32_t flags, + uint64_t from, + size_t * removed); + +/** + * @brief Request password via configured FFI's callback + * + * @param ffi initialized FFI structure + * @param key key handle for which password is requested. May be NULL. + * @param context string describing the purpose of password request. See description of + * rnp_password_cb for the list of possible values. Also you may use any + * custom one as far as your password callback handles it. + * @param password password will be put here on success. Must be destroyed via + * rnp_buffer_destroy(), also it is good idea to securely clear it via + * rnp_buffer_clear(). + * @return RNP_SUCCESS or other value on error. + */ +RNP_API rnp_result_t rnp_request_password(rnp_ffi_t ffi, + rnp_key_handle_t key, + const char * context, + char ** password); + +/** + * @brief Set timestamp, used in all operations instead of system's time. These operations + * include key/signature generation (this timestamp will be used as signature/key + * creation date), verification of the keys and signatures (this timestamp will be used + * as 'current' time). + * Please note, that exactly this timestamp will be used during the whole ffi lifetime. + * + * @param ffi initialized FFI structure + * @param time non-zero timestamp to be used. Zero value restores original behaviour and uses + * system's time. + * @return RNP_SUCCESS or other value on error. + */ +RNP_API rnp_result_t rnp_set_timestamp(rnp_ffi_t ffi, uint64_t time); + +/** load keys + * + * Note that for G10, the input must be a directory (which must already exist). + * + * @param ffi + * @param format the key format of the data (GPG, KBX, G10). Must not be NULL. + * @param input source to read from. + * @param flags the flags. See RNP_LOAD_SAVE_*. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_load_keys(rnp_ffi_t ffi, + const char *format, + rnp_input_t input, + uint32_t flags); + +/** unload public and/or secret keys + * Note: After unloading all key handles will become invalid and must be destroyed. + * @param ffi + * @param flags choose which keys should be unloaded (pubic, secret or both). + * See RNP_KEY_UNLOAD_PUBLIC/RNP_KEY_UNLOAD_SECRET. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_unload_keys(rnp_ffi_t ffi, uint32_t flags); + +/** import keys to the keyring and receive JSON list of the new/updated keys. + * Note: this will work only with keys in OpenPGP format, use rnp_load_keys for other formats. + * @param ffi + * @param input source to read from. Cannot be NULL. + * @param flags see RNP_LOAD_SAVE_* constants. If RNP_LOAD_SAVE_PERMISSIVE is specified + * then import process will skip unrecognized or bad keys/signatures instead of + * failing the whole operation. + * If flag RNP_LOAD_SAVE_SINGLE is set, then only first key will be loaded (subkey + * or primary key with its subkeys). In case RNP_LOAD_SAVE_PERMISSIVE and + * erroneous first key on the stream RNP_SUCCESS will be returned, but results + * will include an empty array. Also RNP_ERROR_EOF will be returned if the last + * key was read. + * RNP_LOAD_SAVE_BASE64 should set to allow import of base64-encoded keys (i.e. + * autocrypt ones). By default only binary and OpenPGP-armored keys are allowed. + * @param results if not NULL then after the successful execution will contain JSON with + * information about new and updated keys. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS on success + * RNP_ERROR_EOF if last key was read (if RNP_LOAD_SAVE_SINGLE was used) + * any other value on error. + */ +RNP_API rnp_result_t rnp_import_keys(rnp_ffi_t ffi, + rnp_input_t input, + uint32_t flags, + char ** results); + +/** import standalone signatures to the keyring and receive JSON list of the updated keys. + * + * @param ffi + * @param input source to read from. Cannot be NULL. + * @param flags additional import flags, currently must be 0. + * @param results if not NULL then after the successful execution will contain JSON with + * information about the updated keys. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_import_signatures(rnp_ffi_t ffi, + rnp_input_t input, + uint32_t flags, + char ** results); + +/** save keys + * + * Note that for G10, the output must be a directory (which must already exist). + * + * @param ffi + * @param format the key format of the data (GPG, KBX, G10). Must not be NULL. + * @param output the output destination to write to. + * @param flags the flags. See RNP_LOAD_SAVE_*. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_save_keys(rnp_ffi_t ffi, + const char * format, + rnp_output_t output, + uint32_t flags); + +RNP_API rnp_result_t rnp_get_public_key_count(rnp_ffi_t ffi, size_t *count); +RNP_API rnp_result_t rnp_get_secret_key_count(rnp_ffi_t ffi, size_t *count); + +/** Search for the key + * Note: only valid userids are checked while searching by userid. + * + * @param ffi + * @param identifier_type string with type of the identifier: userid, keyid, fingerprint, grip + * @param identifier for userid is the userid string, for other search types - hex string + * representation of the value + * @param key if key was found then the resulting key handle will be stored here, otherwise it + * will contain NULL value. You must free handle after use with rnp_key_handle_destroy. + * @return RNP_SUCCESS on success (including case where key is not found), or any other value + * on error + */ +RNP_API rnp_result_t rnp_locate_key(rnp_ffi_t ffi, + const char * identifier_type, + const char * identifier, + rnp_key_handle_t *key); + +RNP_API rnp_result_t rnp_key_handle_destroy(rnp_key_handle_t key); + +/** generate a key or pair of keys using a JSON description + * + * Notes: + * - When generating a subkey, the pass provider may be required. + * + * @param ffi + * @param json the json data that describes the key generation. + * Must not be NULL. + * @param results pointer that will be set to the JSON results. + * Must not be NULL. The caller should free this with rnp_buffer_destroy. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_generate_key_json(rnp_ffi_t ffi, const char *json, char **results); + +/* Key operations */ + +/** Shortcut function for rsa key-subkey pair generation. See rnp_generate_key_ex() for the + * detailed parameters description. + */ +RNP_API rnp_result_t rnp_generate_key_rsa(rnp_ffi_t ffi, + uint32_t bits, + uint32_t subbits, + const char * userid, + const char * password, + rnp_key_handle_t *key); + +/** Shortcut function for DSA/ElGamal key-subkey pair generation. See rnp_generate_key_ex() for + * the detailed parameters description. + */ +RNP_API rnp_result_t rnp_generate_key_dsa_eg(rnp_ffi_t ffi, + uint32_t bits, + uint32_t subbits, + const char * userid, + const char * password, + rnp_key_handle_t *key); + +/** Shortcut function for ECDSA/ECDH key-subkey pair generation. See rnp_generate_key_ex() for + * the detailed parameters description. + */ +RNP_API rnp_result_t rnp_generate_key_ec(rnp_ffi_t ffi, + const char * curve, + const char * userid, + const char * password, + rnp_key_handle_t *key); + +/** Shortcut function for EdDSA/x25519 key-subkey pair generation. See rnp_generate_key_ex() + * for the detailed parameters description. + */ +RNP_API rnp_result_t rnp_generate_key_25519(rnp_ffi_t ffi, + const char * userid, + const char * password, + rnp_key_handle_t *key); + +/** Shortcut function for SM2/SM2 key-subkey pair generation. See rnp_generate_key_ex() for + * for the detailed parameters description. + */ +RNP_API rnp_result_t rnp_generate_key_sm2(rnp_ffi_t ffi, + const char * userid, + const char * password, + rnp_key_handle_t *key); + +/** + * @brief Shortcut for quick key generation. It is used in other shortcut functions for + * key generation (rnp_generate_key_*). + * + * @param ffi + * @param key_alg string with primary key algorithm. Cannot be NULL. + * @param sub_alg string with subkey algorithm. If NULL then subkey will not be generated. + * @param key_bits size of key in bits. If zero then default value will be used. + * Must be zero for EC-based primary key algorithm (use curve instead). + * @param sub_bits size of subkey in bits. If zero then default value will be used. + * Must be zero for EC-based subkey algorithm (use scurve instead). + * @param key_curve Curve name. Must be non-NULL only with EC-based primary key algorithm, + * otherwise error will be returned. + * @param sub_curve Subkey curve name. Must be non-NULL only with EC-based subkey algorithm, + * otherwise error will be returned. + * @param userid String with userid. Cannot be NULL. + * @param password String with password which would be used to protect the key and subkey. + * If NULL then key will be stored in cleartext (unencrypted). + * @param key if non-NULL, then handle of the primary key will be stored here on success. + * Caller must destroy it with rnp_key_handle_destroy() call. + * @return RNP_SUCCESS or error code instead. + */ +RNP_API rnp_result_t rnp_generate_key_ex(rnp_ffi_t ffi, + const char * key_alg, + const char * sub_alg, + uint32_t key_bits, + uint32_t sub_bits, + const char * key_curve, + const char * sub_curve, + const char * userid, + const char * password, + rnp_key_handle_t *key); + +/** Create key generation context for the primary key. + * To generate a subkey use function rnp_op_generate_subkey_create() instead. + * Note: pass provider is required if generated key needs protection. + * + * @param op pointer to opaque key generation context. + * @param ffi + * @param alg key algorithm as string. Must be able to sign. Currently the following algorithms + * are supported (case-insensetive) : 'rsa', 'dsa', 'ecdsa', 'eddsa', 'sm2'. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_create(rnp_op_generate_t *op, + rnp_ffi_t ffi, + const char * alg); + +/** Create key generation context for the subkey. + * Note: you need to have primary key before calling this function. It can be loaded from + * keyring or generated via the function rnp_op_generate_create(). Also pass provider is needed + * if primary key is encrypted (protected and locked). + * + * @param op pointer to opaque key generation context. + * @param ffi + * @param primary primary key handle, must have secret part. + * @param alg key algorithm as string. Currently the following algorithms are supported + * (case-insensetive) : 'rsa', 'dsa', 'elgamal', 'ecdsa', 'eddsa', 'ecdh', 'sm2'. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_subkey_create(rnp_op_generate_t *op, + rnp_ffi_t ffi, + rnp_key_handle_t primary, + const char * alg); + +/** Set bits of the generated key or subkey. + * Note: this is applicable only to rsa, dsa and el-gamal keys. + * + * @param op pointer to opaque key generation context. + * @param bits number of bits + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_bits(rnp_op_generate_t op, uint32_t bits); + +/** Set hash algorithm used in self signature or subkey binding signature. + * + * @param op pointer to opaque key generation context. + * @param hash string with hash algorithm name. Following hash algorithms are supported: + * "MD5", "SHA1", "RIPEMD160", "SHA256", "SHA384", "SHA512", "SHA224", "SM3" + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_hash(rnp_op_generate_t op, const char *hash); + +/** Set size of q parameter for DSA key. + * Note: appropriate default value will be set, depending on key bits. However you may + * override it if needed. + * @param op pointer to opaque key generation context. + * @param qbits number of bits + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_dsa_qbits(rnp_op_generate_t op, uint32_t qbits); + +/** Set the curve used for ECC key + * Note: this is only applicable for ECDSA, ECDH and SM2 keys. + * @param op pointer to opaque key generation context. + * @param curve string with curve name. Following curve names may be used: + * "NIST P-256", "NIST P-384", "NIST P-521", "Curve25519" (ECDH only), + * "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1", "secp256k1", + * "SM2 P-256" (SM2 only) + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_curve(rnp_op_generate_t op, const char *curve); + +/** Set password, used to encrypt secret key data. If this method is not called then + * key will be generated without protection (unencrypted). + * + * @param op pointer to opaque key generation context. + * @param password string with password, could not be NULL. Will be copied internally so may + * be safely freed after the call. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_protection_password(rnp_op_generate_t op, + const char * password); + +/** + * @brief Enable or disable password requesting via ffi's password provider. This password + * then will be used for key encryption. + * Note: this will be ignored if password was set via + * rnp_op_generate_set_protection_password(). + * + * @param op pointer to opaque key generation context. + * @param request true to enable password requesting or false otherwise. Default value is false + * (i.e. key will be generated unencrypted). + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_request_password(rnp_op_generate_t op, bool request); + +/** Set cipher used to encrypt secret key data. If not called then default one will be used. + * + * @param op pointer to opaque key generation context. + * @param cipher string with cipher name. Following ciphers are supported: + * "Idea", "Tripledes", "Cast5", "Blowfish", "AES128", "AES192", "AES256", + * "Twofish", "Camellia128", "Camellia192", "Camellia256", "SM4". + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_protection_cipher(rnp_op_generate_t op, + const char * cipher); + +/** Set hash algorithm, used to derive key from password for secret key data encryption. + * If not called then default one will be used. + * + * @param op pointer to opaque key generation context. + * @param hash string with hash algorithm, see rnp_op_generate_set_hash() for the whole list. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_protection_hash(rnp_op_generate_t op, + const char * hash); + +/** Set encryption mode, used for secret key data encryption. + * Note: currently this makes sense only for G10 key format + * + * @param op pointer to opaque key generation context. + * @param mode string with mode name: "CFB", "CBC", "OCB" + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_protection_mode(rnp_op_generate_t op, + const char * mode); + +/** Set number of iterations used to derive key from password for secret key encryption. + * If not called then default one will be used. + * + * @param op pointer to opaque key generation context. + * @param iterations number of iterations + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_protection_iterations(rnp_op_generate_t op, + uint32_t iterations); + +/** Add key usage flag to the key or subkey. + * Note: use it only if you need to override defaults, which depend on primary key or subkey, + * and public key algorithm. + * + * @param op pointer to opaque key generation context. + * @param usage string, representing key usage. Following values are supported: "sign", + * "certify", "encrypt", "authenticate". + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_add_usage(rnp_op_generate_t op, const char *usage); + +/** Reset key usage flags, so default ones will be used during key/subkey generation + * + * @param op pointer to opaque key generation context. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_clear_usage(rnp_op_generate_t op); + +/** Set the userid which will represent the generate key. + * Note: Makes sense only for primary key generation. + * + * @param op pointer to opaque key generation context. + * @param userid NULL-terminated string with userid. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_userid(rnp_op_generate_t op, const char *userid); + +/** Set the key or subkey expiration time. + * + * @param op pointer to opaque key generation context. + * @param expiration expiration time in seconds. 0 value means that key doesn't expire. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_expiration(rnp_op_generate_t op, uint32_t expiration); + +/** Add preferred hash to user preferences. + * Note: the first added hash algorithm has the highest priority, then the second and so on. + * Applicable only for the primary key generation. + * + * @param op pointer to opaque key generation context. + * @param hash string, representing the hash algorithm. See the rnp_op_generate_set_hash() + * function description for the list of possible values. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_add_pref_hash(rnp_op_generate_t op, const char *hash); + +/** Clear the preferred hash algorithms list, so default ones will be used. + * + * @param op pointer to opaque key generation context. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_clear_pref_hashes(rnp_op_generate_t op); + +/** Add preferred compression algorithm to user preferences. + * Note: the first added algorithm has the highest priority, then the second and so on. + * Applicable only for the primary key generation. + * + * @param op pointer to opaque key generation context. + * @param compression string, representing the compression algorithm. Possible values are: + * "zip", "zlib", "bzip2" + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_add_pref_compression(rnp_op_generate_t op, + const char * compression); + +/** Clear the preferred compression algorithms list, so default ones will be used. + * + * @param op pointer to opaque key generation context. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_clear_pref_compression(rnp_op_generate_t op); + +/** Add preferred encryption algorithm to user preferences. + * Note: the first added algorithm has the highest priority, then the second and so on. + * Applicable only for the primary key generation. + * + * @param op pointer to opaque key generation context. + * @param cipher string, representing the encryption algorithm. + * See the rnp_op_generate_set_protection_cipher() function description for + * the list of possible values. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_add_pref_cipher(rnp_op_generate_t op, const char *cipher); + +/** Clear the preferred encryption algorithms list, so default ones will be used. + * + * @param op pointer to opaque key generation context. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op); + +/** Set the preferred key server. Applicable only for the primary key. + * + * @param op pointer to opaque key generation context. + * @param keyserver NULL-terminated string with key server's URL, or NULL to delete it from + * user preferences. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, + const char * keyserver); + +/** Execute the prepared key or subkey generation operation. + * Note: if you set protection algorithm, then you need to specify ffi password provider to + * be able to request password for key encryption. + * + * @param op pointer to opaque key generation context. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_execute(rnp_op_generate_t op); + +/** Get the generated key's handle. Should be called only after successful execution of + * rnp_op_generate_execute(). + * + * @param op pointer to opaque key generation context. + * @param handle pointer to key handle will be stored here. + * You must free handle after use with rnp_key_handle_destroy. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_get_key(rnp_op_generate_t op, rnp_key_handle_t *handle); + +/** Free resources associated with key generation operation. + * + * @param op opaque key generation context. Must be successfully initialized with one of the + * rnp_op_generate_*_create functions. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_destroy(rnp_op_generate_t op); + +/** export a key + * + * @param key the key to export + * @param output the stream to write to + * @param flags see RNP_KEY_EXPORT_*. + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_export(rnp_key_handle_t key, rnp_output_t output, uint32_t flags); + +/** + * @brief Export minimal key for autocrypt feature (just 5 packets: key, uid, signature, + * encryption subkey, signature) + * + * @param key primary key handle, cannot be NULL. + * @param subkey subkey to export. May be NULL to pick the first suitable. + * @param uid userid to export. May be NULL if key has only one uid. + * @param output the stream to write to + * @param flags additional flags. Currently only RNP_KEY_EXPORT_BASE64 is supported. Enabling + * it would export key base64-encoded instead of binary. + * @return RNP_SUCCESS on success, or any other value if failed. + */ +RNP_API rnp_result_t rnp_key_export_autocrypt(rnp_key_handle_t key, + rnp_key_handle_t subkey, + const char * uid, + rnp_output_t output, + uint32_t flags); + +/** + * @brief Generate and export primary key revocation signature. + * Note: to revoke a key you'll need to import this signature into the keystore or use + * rnp_key_revoke() function. + * @param key primary key to be revoked. Must have secret key, otherwise keyrings will be + * searched for the authorized to issue revocation signature secret key. If secret + * key is locked then password will be asked via password provider. + * @param output signature contents will be saved here. + * @param flags must be RNP_KEY_EXPORT_ARMORED or 0. + * @param hash hash algorithm used to calculate signature. Pass NULL for default algorithm + * selection. + * @param code reason for revocation code. Possible values: 'no', 'superseded', 'compromised', + * 'retired'. May be NULL - then 'no' value will be used. + * @param reason textual representation of the reason for revocation. May be NULL or empty + * string. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_key_export_revocation(rnp_key_handle_t key, + rnp_output_t output, + uint32_t flags, + const char * hash, + const char * code, + const char * reason); + +/** + * @brief revoke a key or subkey by generating and adding revocation signature. + * @param key key or subkey to be revoked. For primary key must have secret key, otherwise + * keyrings will be searched for the authorized to issue revocation signatures + * secret key. For subkey keyrings must have primary secret key. + * If secret key is locked then password will be asked via password provider. + * @param flags currently must be 0. + * @param hash hash algorithm used to calculate signature. Pass NULL for default algorithm + * selection. + * @param code reason for revocation code. Possible values: 'no', 'superseded', 'compromised', + * 'retired'. May be NULL - then 'no' value will be used. + * @param reason textual representation of the reason for revocation. May be NULL or empty + * string. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_key_revoke(rnp_key_handle_t key, + uint32_t flags, + const char * hash, + const char * code, + const char * reason); + +/** + * @brief Check whether Curve25519 secret key's bits are correctly set, i.e. 3 least + * significant bits are zero and key is exactly 255 bits in size. See RFC 7748, section + * 5 for the details. RNP interpreted RFC requirements in the way that Curve25519 secret + * key is random 32-byte string, which bits are correctly tweaked afterwards within + * secret key operation. However, for compatibility reasons, it would be more correct to + * store/transfer secret key with bits already tweaked. + * + * Note: this operation requires unlocked secret key, so make sure to call + * rnp_key_lock() afterwards. + * + * @param key key handle, cannot be NULL. Must be ECDH Curve25519 unlocked secret key. + * @param result true will be stored here if secret key's low/high bits are not correctly set. + * In this case you may need to call `rnp_key_25519_bits_tweak()` on it to set + * bits to correct values so exported secret key will be compatible with + * implementations which do not tweak these bits automatically. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_25519_bits_tweaked(rnp_key_handle_t key, bool *result); + +/** + * @brief Make sure Curve25519 secret key's least significant and most significant bits are + * correctly set, see rnp_key_25519_bits_tweaked() documentation for the details. + * Note: this operation requires unprotected secret key since it would modify secret + * key's data, so make sure to call rnp_key_protect() afterwards. + * + * @param key key handle, cannot be NULL. Must be ECDH Curve25519 unprotected secret key. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_25519_bits_tweak(rnp_key_handle_t key); + +/** remove a key from keyring(s) + * Note: you need to call rnp_save_keys() to write updated keyring(s) out. + * Other handles of the same key should not be used after this call. + * @param key pointer to the key handle. + * @param flags see RNP_KEY_REMOVE_* constants. Flag RNP_KEY_REMOVE_SUBKEYS will work only for + * primary key, and remove all of its subkeys as well. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_remove(rnp_key_handle_t key, uint32_t flags); + +/** + * @brief Remove unneeded signatures from the key, it's userids and subkeys if any. + * May be called on subkey handle as well. + * Note: you'll need to call rnp_save_keys() to write updated keyring(s) out. + * Any signature handles related to this key, it's uids or subkeys should not be used + * after this call. + * + * @param key key handle, cannot be NULL. + * @param flags flags, controlling which signatures to remove. Signature will be removed if it + * matches at least one of these flags. + * Currently following signature matching flags are defined: + * - RNP_KEY_SIGNATURE_INVALID : signature is invalid and was never valid. Note, + * that this will not remove invalid signature if there is no signer's public + * key in the keyring. + * - RNP_KEY_SIGNATURE_UNKNOWN_KEY : signature is made by the key which is not + * known/available. + * - RNP_KEY_SIGNATURE_NON_SELF_SIG : signature is not a self-signature (i.e. made + * by the key itself or corresponding primary key). + * + * Note: if RNP_KEY_SIGNATURE_NON_SELF_SIG is not specified then function will + * attempt to validate all the signatures, and look up for the signer's public key + * via keyring/key provider. + * + * @param sigcb callback, used to record information about the removed signatures, or further + * filter out the signatures. May be NULL. + * @param app_ctx context information, passed to sigcb. May be NULL. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_remove_signatures(rnp_key_handle_t key, + uint32_t flags, + rnp_key_signatures_cb sigcb, + void * app_ctx); + +/** + * @brief Guess contents of the OpenPGP data stream. + * Note: This call just peeks data from the stream, so stream is still usable for + * the further processing. + * @param input stream with data. Must be opened and cannot be NULL. + * @param contents string with guessed data format will be stored here. + * Possible values: 'message', 'public key', 'secret key', 'signature', + * 'unknown'. May be used as type in rnp_enarmor() function. Must be + * deallocated with rnp_buffer_destroy() call. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_guess_contents(rnp_input_t input, char **contents); + +/** Add ASCII Armor + * + * @param input stream to read data from + * @param output stream to write armored data to + * @param type the type of armor to add ("message", "public key", + * "secret key", "signature", "cleartext"). Use NULL to try + * to guess the type. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_enarmor(rnp_input_t input, rnp_output_t output, const char *type); + +/** Remove ASCII Armor + * + * @param input stream to read armored data from + * @param output stream to write dearmored data to + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_dearmor(rnp_input_t input, rnp_output_t output); + +/** Get key's primary user id. + * Note: userid considered as primary if it has marked as primary in self-certification, and + * is valid (i.e. both certification and key are valid, not expired and not revoked). If + * there is no userid marked as primary then the first valid userid handle will be + * returned. + * @param key key handle. + * @param uid pointer to the string with primary user id will be stored here. + * You must free it using the rnp_buffer_destroy(). + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_primary_uid(rnp_key_handle_t key, char **uid); + +/** Get number of the key's user ids. + * + * @param key key handle. + * @param count number of user ids will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_uid_count(rnp_key_handle_t key, size_t *count); + +/** Get key's user id by its index. + * + * @param key key handle. + * @param idx zero-based index of the userid. + * @param uid pointer to the string with user id will be stored here. + * You must free it using the rnp_buffer_destroy(). + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_uid_at(rnp_key_handle_t key, size_t idx, char **uid); + +/** Get key's user id handle by its index. + * Note: user id handle may become invalid once corresponding user id or key is removed. + * + * @param key key handle + * @param idx zero-based index of the userid. + * @param uid user id handle will be stored here on success. You must destroy it + * using the rnp_uid_handle_destroy(). + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_uid_handle_at(rnp_key_handle_t key, + size_t idx, + rnp_uid_handle_t *uid); + +/** Get userid's type. Currently two possible values are defined: + * - RNP_USER_ID - string representation of user's name and email. + * - RNP_USER_ATTR - binary photo of the user + + * @param uid uid handle, cannot be NULL. + * @param type on success userid type will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_get_type(rnp_uid_handle_t uid, uint32_t *type); + +/** Get userid's data. Representation of data depends on userid type (see rnp_uid_get_type() + * function) + * + * @param uid uid handle, cannot be NULL. + * @param data cannot be NULL. On success pointer to the allocated buffer with data will be + * stored here. Must be deallocated by caller via rnp_buffer_destroy(). + * @param size cannot be NULL. On success size of the data will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_get_data(rnp_uid_handle_t uid, void **data, size_t *size); + +/** Check whether uid is marked as primary. + * + * @param uid uid handle, cannot be NULL + * @param primary cannot be NULL. On success true or false will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_is_primary(rnp_uid_handle_t uid, bool *primary); + +/** Get userid validity status. Userid is considered as valid if key itself is valid, and + * userid has at least one valid, non-expired self-certification. + * Note: - userid still may be valid even if a primary key is invalid - expired, revoked, etc. + * - up to the RNP version 0.15.1 uid was not considered as valid if it's latest + * self-signature has key expiration in the past. + * + * @param uid user id handle. + * @param valid validity status will be stored here on success. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_is_valid(rnp_uid_handle_t uid, bool *valid); + +/** Get number of key's signatures. + * Note: this will not count user id certifications and subkey(s) signatures if any. + * I.e. it will return only number of direct-key and key revocation signatures for the + * primary key, and number of subkey bindings/revocation signatures for the subkey. + * Use rnp_uid_get_signature_count() or call this function on subkey's handle. + * + * @param key key handle + * @param count number of key's signatures will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_signature_count(rnp_key_handle_t key, size_t *count); + +/** Get key's signature, based on its index. + * Note: see the rnp_key_get_signature_count() description for the details. + * + * @param key key handle + * @param idx zero-based signature index. + * @param sig signature handle will be stored here on success. You must free it after use with + * the rnp_signature_handle_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_signature_at(rnp_key_handle_t key, + size_t idx, + rnp_signature_handle_t *sig); + +/** + * @brief Get key's revocation signature handle, if any. + * + * @param key key handle + * @param sig signature handle or NULL will be stored here on success. NULL will be stored in + * case when there is no valid revocation signature. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_revocation_signature(rnp_key_handle_t key, + rnp_signature_handle_t *sig); + +/** Get the number of user id's signatures. + * + * @param uid user id handle. + * @param count number of uid's signatures will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_get_signature_count(rnp_uid_handle_t uid, size_t *count); + +/** Get user id's signature, based on its index. + * + * @param uid uid handle. + * @param idx zero-based signature index. + * @param sig signature handle will be stored here on success. You must free it after use with + * the rnp_signature_handle_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_get_signature_at(rnp_uid_handle_t uid, + size_t idx, + rnp_signature_handle_t *sig); + +/** + * @brief Get signature's type. + * + * @param sig signature handle. + * @param type on success string with signature type will be saved here. Cannot be NULL. + * You must free it using the rnp_buffer_destroy(). + * Currently defined values are: + * - 'binary' : signature of a binary document + * - 'text' : signature of a canonical text document + * - 'standalone' : standalone signature + * - 'certification (generic)` : generic certification of a user id + * - 'certification (persona)' : persona certification of a user id + * - 'certification (casual)' : casual certification of a user id + * - 'certification (positive)' : positive certification of a user id + * - 'subkey binding' : subkey binding signature + * - 'primary key binding' : primary key binding signature + * - 'direct' : direct-key signature + * - 'key revocation' : primary key revocation signature + * - 'subkey revocation' : subkey revocation signature + * - 'certification revocation' : certification revocation signature + * - 'timestamp' : timestamp signature + * - 'third-party' : third party confirmation signature + * - 'uknown: 0..255' : unknown signature with its type specified as number + * + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_type(rnp_signature_handle_t sig, char **type); + +/** Get signature's algorithm. + * + * @param sig signature handle. + * @param alg on success string with algorithm name will be saved here. Cannot be NULL. +* You must free it using the rnp_buffer_destroy(). + + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_alg(rnp_signature_handle_t sig, char **alg); + +/** Get signature's hash algorithm. + * + * @param sig signature handle. + * @param alg on success string with algorithm name will be saved here. Cannot be NULL. + * You must free it using the rnp_buffer_destroy(). + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_hash_alg(rnp_signature_handle_t sig, char **alg); + +/** Get the signature creation time as number of seconds since Jan, 1 1970 UTC + * + * @param sig signature handle. + * @param create on success result will be stored here. Cannot be NULL. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_creation(rnp_signature_handle_t sig, uint32_t *create); + +/** Get the signature expiration time as number of seconds after creation time + * + * @param sig signature handle. + * @param expires on success result will be stored here. Cannot be NULL. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_expiration(rnp_signature_handle_t sig, + uint32_t * expires); + +/** Get signer's key id from the signature. + * Note: if key id is not available from the signature then NULL value will + * be stored to result. + * @param sig signature handle + * @param result hex-encoded key id will be stored here. Cannot be NULL. You must free it + * later on using the rnp_buffer_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_keyid(rnp_signature_handle_t sig, char **result); + +/** Get signer's key fingerprint from the signature. + * Note: if key fingerprint is not available from the signature then NULL value will + * be stored to result. + * @param sig signature handle + * @param result hex-encoded key fp will be stored here. Cannot be NULL. You must free it + * later on using the rnp_buffer_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_key_fprint(rnp_signature_handle_t sig, char **result); + +/** Get signing key handle, if available. + * Note: if signing key is not available then NULL will be stored in key. + * @param sig signature handle + * @param key on success and key availability will contain signing key's handle. You must + * destroy it using the rnp_key_handle_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_get_signer(rnp_signature_handle_t sig, + rnp_key_handle_t * key); + +/** + * @brief Get signature validity, revalidating it if didn't before. + * + * @param sig key/userid signature handle + * @param flags validation flags, currently must be zero. + * @return Following error codes represents the validation status: + * RNP_SUCCESS : operation succeeds and signature is valid + * RNP_ERROR_KEY_NOT_FOUND : signer's key not found + * RNP_ERROR_VERIFICATION_FAILED: verification failed, so validity cannot be checked + * RNP_ERROR_SIGNATURE_EXPIRED: signature is valid but expired + * RNP_ERROR_SIGNATURE_INVALID: signature is invalid (corrupted, malformed, was issued + * by invalid key, whatever else.) + * + * Please also note that other error codes may be returned because of wrong + * function call (included, but not limited to): + * RNP_ERROR_NULL_POINTER: sig as well as some of its fields are NULL + * RNP_ERROR_BAD_PARAMETERS: invalid parameter value (unsupported flag, etc). + */ +RNP_API rnp_result_t rnp_signature_is_valid(rnp_signature_handle_t sig, uint32_t flags); + +/** Dump signature packet to JSON, obtaining the whole information about it. + * + * @param sig sigmature handle, cannot be NULL + * @param flags include additional fields in JSON (see RNP_JSON_DUMP_MPI and other + * RNP_JSON_DUMP_* flags) + * @param result resulting JSON string will be stored here. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_signature_packet_to_json(rnp_signature_handle_t sig, + uint32_t flags, + char ** json); + +/** + * @brief Remove a signature. + * + * @param key key handle, cannot be NULL. + * @param sig signature handle, cannot be NULL. Must be obtained via the key handle or one of + * its userids. You still need to call rnp_signature_handle_destroy afterwards to + * destroy handle itself. All other handles of the same signature, if any, should + * not be used after the call is made. + * @return RNP_SUCCESS if signature was successfully deleted, or any other value on error. + */ +RNP_API rnp_result_t rnp_signature_remove(rnp_key_handle_t key, rnp_signature_handle_t sig); + +/** + * @brief Export a signature. + * + * @param sig signature handle, cannot be NULL. + * @param output destination of the data stream. + * @param flags must be RNP_KEY_EXPORT_ARMORED or 0. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_export(rnp_signature_handle_t sig, + rnp_output_t output, + uint32_t flags); + +/** Free signature handle. + * + * @param sig signature handle. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_signature_handle_destroy(rnp_signature_handle_t sig); + +/** Check whether user id is revoked. + * + * @param uid user id handle, should not be NULL. + * @param result boolean result will be stored here on success. Cannot be NULL. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_is_revoked(rnp_uid_handle_t uid, bool *result); + +/** Retrieve uid revocation signature, if any. + * + * @param uid user id handle, should not be NULL. + * @param sig on success signature handle or NULL will be stored here. NULL will be stored in + * case when uid is not revoked. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_get_revocation_signature(rnp_uid_handle_t uid, + rnp_signature_handle_t *sig); + +/** + * @brief Remove userid with all of its signatures from the key + * + * @param key key handle, cannot be NULL and must own the uid. + * @param uid uid handle, cannot be NULL. Still must be destroyed afterwards via the + * rnp_uid_handle_destroy(). All other handles pointing to the same uid will + * become invalid and should not be used. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_uid_remove(rnp_key_handle_t key, rnp_uid_handle_t uid); + +/** Destroy previously allocated user id handle. + * + * @param uid user id handle. + * @return RNP_SUCCESS or error code + */ +RNP_API rnp_result_t rnp_uid_handle_destroy(rnp_uid_handle_t uid); + +/** Get number of the key's subkeys. + * + * @param key key handle. + * @param count number of subkeys will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_subkey_count(rnp_key_handle_t key, size_t *count); + +/** Get the handle of one of the key's subkeys, using its index in the list. + * + * @param key handle of the primary key. + * @param idx zero-based index of the subkey. + * @param subkey on success handle for the subkey will be stored here. You must free it + * using the rnp_key_handle_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_subkey_at(rnp_key_handle_t key, + size_t idx, + rnp_key_handle_t *subkey); + +/** Get default key for specified usage. Accepts primary key + * and returns one of its subkeys suitable for desired usage. + * May return the same primary key if it is suitable for requested + * usage and flag RNP_KEY_SUBKEYS_ONLY is not set. + * + * @param primary_key handle of the primary key. + * @param usage desired key usage i.e. "sign", "certify", etc, + * see rnp_op_generate_add_usage() function description for all possible values. + * @param flags possible values: RNP_KEY_SUBKEYS_ONLY - select only subkeys, + * otherwise if flags is 0, primary key can be returned if + * it is suitable for specified usage. + * @param default_key on success resulting key handle will be stored here, otherwise it + * will contain NULL value. You must free this handle after use with + * rnp_key_handle_destroy(). + * @return RNP_SUCCESS on success, RNP_ERROR_KEY_NOT_FOUND if no key with desired usage + * was found or any other error code. + */ +RNP_API rnp_result_t rnp_key_get_default_key(rnp_key_handle_t primary_key, + const char * usage, + uint32_t flags, + rnp_key_handle_t *default_key); + +/** Get the key's algorithm. + * + * @param key key handle + * @param alg string with algorithm name will be stored here. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_alg(rnp_key_handle_t key, char **alg); + +/** Get number of bits in the key. For EC-based keys it will return size of the curve. + * + * @param key key handle + * @param bits number of bits will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_bits(rnp_key_handle_t key, uint32_t *bits); + +/** Get the number of bits in q parameter of the DSA key. Makes sense only for DSA keys. + * + * @param key key handle + * @param qbits number of bits will be stored here. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_dsa_qbits(rnp_key_handle_t key, uint32_t *qbits); + +/** Get the curve of EC-based key. + * + * @param key key handle + * @param curve string with name of the curve will be stored here. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_get_curve(rnp_key_handle_t key, char **curve); + +/** Add a new user identifier to a key + * + * @param ffi + * @param key the key to add - must be a secret key + * @param uid the UID to add + * @param hash name of the hash function to use for the uid binding + * signature (eg "SHA256"). If NULL, default hash algorithm + * will be used. + * @param expiration time when this user id expires + * @param key_flags usage flags, see section 5.2.3.21 of RFC 4880 + * or just provide zero to indicate no special handling. + * @param primary indicates if this is the primary UID + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_add_uid(rnp_key_handle_t key, + const char * uid, + const char * hash, + uint32_t expiration, + uint8_t key_flags, + bool primary); + +/* The following output hex encoded strings */ + +/** + * @brief Get key's fingerprint as hex-encoded string. + * + * @param key key handle, should not be NULL + * @param fprint pointer to the NULL-terminated string with hex-encoded fingerprint will be + * stored here. You must free it later using rnp_buffer_destroy function. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_fprint(rnp_key_handle_t key, char **fprint); + +/** + * @brief Get key's id as hex-encoded string + * + * @param key key handle, should not be NULL + * @param keyid pointer to the NULL-terminated string with hex-encoded key id will be + * stored here. You must free it later using rnp_buffer_destroy function. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_keyid(rnp_key_handle_t key, char **keyid); + +/** + * @brief Get key's grip as hex-encoded string + * + * @param key key handle, should not be NULL + * @param grip pointer to the NULL-terminated string with hex-encoded key grip will be + * stored here. You must free it later using rnp_buffer_destroy function. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_grip(rnp_key_handle_t key, char **grip); + +/** + * @brief Get primary's key grip for the subkey, if available. + * + * @param key key handle, should not be NULL + * @param grip pointer to the NULL-terminated string with hex-encoded key grip or NULL will be + * stored here, depending whether primary key is available or not. + * You must free it later using rnp_buffer_destroy function. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_primary_grip(rnp_key_handle_t key, char **grip); + +/** + * @brief Get primary's key fingerprint for the subkey, if available. + * + * @param key subkey handle, should not be NULL + * @param grip pointer to the NULL-terminated string with hex-encoded key fingerprint or NULL + * will be stored here, depending whether primary key is available or not. You must + * free it later using rnp_buffer_destroy function. + * @return RNP_SUCCESS on success, RNP_BAD_PARAMETERS if not a subkey, or other error code + * on failure. + */ +RNP_API rnp_result_t rnp_key_get_primary_fprint(rnp_key_handle_t key, char **fprint); + +/** + * @brief Check whether certain usage type is allowed for the key. + * + * @param key key handle, should not be NULL + * @param usage string describing the key usage. For the list of allowed values see the + * rnp_op_generate_add_usage() function description. + * @param result function result will be stored here. Could not be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_allows_usage(rnp_key_handle_t key, + const char * usage, + bool * result); + +/** + * @brief Get the key's creation time. + * + * @param key key handle, should not be NULL. + * @param result creation time will be stored here. Cannot be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_creation(rnp_key_handle_t key, uint32_t *result); + +/** + * @brief Get the key's expiration time in seconds. + * Note: 0 means that the key doesn't expire. + * + * @param key key handle, should not be NULL + * @param result expiration time will be stored here. Could not be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_expiration(rnp_key_handle_t key, uint32_t *result); + +/** + * @brief Set the key's expiration time in seconds. + * Note: this will require re-signing, which requires availability of the secret key (or + * secret primary key for the subkey). If the secret key is locked then may ask for + * key's password via FFI callback. + * + * @param key key's handle. + * @param expiry expiration time in seconds (or 0 if key doesn't expire). Please note that it + * is calculated from the key creation time, not from the current time. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_set_expiration(rnp_key_handle_t key, uint32_t expiry); + +/** + * @brief Check whether public key is valid. This includes checks of the self-signatures, + * expiration times, revocations and so on. + * Note: it doesn't take in account secret key, if it is available. + * + * @param key key's handle. + * @param result on success true or false will be stored here. Cannot be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_is_valid(rnp_key_handle_t key, bool *result); + +/** + * @brief Get the timestamp till which key can be considered as valid. + * Note: this will take into account not only key's expiration, but revocations as well. + * For the subkey primary key's validity time will be also checked. + * While in OpenPGP key creation and expiration times are 32-bit, their sum may overflow + * 32 bits, so rnp_key_valid_till64 function should be used. + * In case of 32 bit overflow result will be set to the UINT32_MAX - 1. + * @param key key's handle. + * @param result on success timestamp will be stored here. If key doesn't expire then maximum + * value (UINT32_MAX or UINT64_MAX) will be stored here. If key was never valid + * then zero value will be stored here. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_valid_till(rnp_key_handle_t key, uint32_t *result); +RNP_API rnp_result_t rnp_key_valid_till64(rnp_key_handle_t key, uint64_t *result); + +/** + * @brief Check whether key is revoked. + * + * @param key key handle, should not be NULL + * @param result on success result will be stored here. Could not be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_is_revoked(rnp_key_handle_t key, bool *result); + +/** + * @brief Get textual description of the key's revocation reason (if any) + * + * @param key key handle, should not be NULL + * @param result on success pointer to the NULL-terminated string will be stored here. + * You must free it later using rnp_buffer_destroy() function. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_revocation_reason(rnp_key_handle_t key, char **result); + +/** + * @brief Check whether revoked key was superseded by other key. + * + * @param key key handle, should not be NULL + * @param result on success result will be stored here. Could not be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_is_superseded(rnp_key_handle_t key, bool *result); + +/** + * @brief Check whether revoked key's material was compromised. + * + * @param key key handle, should not be NULL + * @param result on success result will be stored here. Could not be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_is_compromised(rnp_key_handle_t key, bool *result); + +/** + * @brief Check whether revoked key was retired. + * + * @param key key handle, should not be NULL + * @param result on success result will be stored here. Could not be NULL. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_is_retired(rnp_key_handle_t key, bool *result); + +/** + * @brief Check whether key is expired. + * Note: while expired key cannot be used to generate new signatures or encrypt to, it + * still could be used to check older signatures/decrypt previously encrypted data. + * + * @param key key handle, should not be NULL. + * @param result on success result will be stored here. True means that key is expired and is + * not usable and false otherwise. + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_is_expired(rnp_key_handle_t key, bool *result); + +/** check if a key is currently locked + * + * @param key + * @param result pointer to hold the result. This will be set to true if + * the key is currently locked, or false otherwise. Must not be NULL. + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_is_locked(rnp_key_handle_t key, bool *result); + +/** + * @brief Get type of protection, used for secret key data. + * + * @param key key handle, cannot be NULL and should have secret part (see function + * rnp_key_have_secret()). + * @param type on success protection type will be stored here. Cannot be NULL. + * Must be freed by caller via rnp_buffer_destroy() call. + * Currently defined values are: + * - "None" : secret key data is stored in plaintext. + * - "Encrypted" : secret key data is encrypted, using just CRC as integrity + * protection. + * - "Encrypted-Hashed" : secret key data is encrypted, using the SHA1 hash as + * an integrity protection. + * - "GPG-None" : secret key data is not available at all (this would happen if + * secret key is exported from GnuPG via --export-secret-subkeys) + * - "GPG-Smartcard" : secret key data is stored on smartcard by GnuPG, so is not + * available + * - "Unknown" : key protection type is unknown, so secret key data is not + * available + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_key_get_protection_type(rnp_key_handle_t key, char **type); + +/** + * @brief Get mode in which secret key data is encrypted. + * + * @param key key handle, cannot be NULL and should have secret part (see function + * rnp_key_have_secret()). + * @param mode on success secret key protection mode name will be stored here. Cannot be NULL. + * Must be freed by caller via rnp_buffer_destroy() call. + * Currently defined values are: + * - "None" : secret key data is not encrypted at all + * - "Unknown" : it is not known how secret key data is encrypted, so there is no + * way to unlock/unprotect the key. + * - "CFB" : secret key data is encrypted in CFB mode, using the password + * - "CBC" : secret key data is encrypted in CBC mode, using the password + * (only for G10 keys) + * - "OCB" : secert key data is encrypted in OCB mode, using the password + * (only for G10 keys) + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_get_protection_mode(rnp_key_handle_t key, char **mode); + +/** + * @brief Get cipher, used to encrypt secret key data. + * Note: this call will return an error if secret key data is not available or secret + * key is not encrypted. + * + * @param key key handle, cannot be NULL and should have secret part. + * @param cipher on success cipher name will be stored here. See + * rnp_op_generate_set_protection_cipher for possible values. Cannot be NULL. + * Must be freed by caller via rnp_buffer_destroy() call. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_get_protection_cipher(rnp_key_handle_t key, char **cipher); + +/** + * @brief Get hash, used to derive secret key data encrypting key from the password. + * Note: this call will return an error if secret key data is not available or secret + * key is not encrypted. + * @param key key handle, cannot be NULL and should have secret part. + * @param hash on success hash name will be stored here. See rnp_op_generate_set_hash() for the + * whole list of possible values. Cannot be NULL. + * Must be freed by caller via rnp_buffer_destroy() call. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_get_protection_hash(rnp_key_handle_t key, char **hash); + +/** + * @brief Get number of iterations used to derive encrypting key from password, using the hash + * function. + * Note: this call will return an error if secret key data is not available or secret + * key is not encrypted. + * + * @param key key handle, cannot be NULL and should have secret part. + * @param iterations on success number of iterations will be stored here. Cannot be NULL. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_get_protection_iterations(rnp_key_handle_t key, + size_t * iterations); + +/** lock the key + * + * A locked key does not have the secret key material immediately + * available for use. A locked and protected (aka encrypted) key + * is safely encrypted in memory and requires a password for + * performing any operations involving the secret key material. + * + * Generally lock/unlock are not useful for unencrypted (not protected) keys. + * + * @param key + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_lock(rnp_key_handle_t key); + +/** unlock the key + * + * An unlocked key has unencrypted secret key material available for use + * without a password. + * + * Generally lock/unlock are not useful for unencrypted (not protected) keys. + * + * @param key + * @param password the password to unlock the key. If NULL, the password + * provider will be used. + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_unlock(rnp_key_handle_t key, const char *password); + +/** check if a key is currently protected + * + * A protected key is one that is encrypted and can be safely held in memory + * and locked/unlocked as needed. + * + * @param key + * @param result pointer to hold the result. This will be set to true if + * the key is currently protected, or false otherwise. Must not be NULL. + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_is_protected(rnp_key_handle_t key, bool *result); + +/** protect the key + * + * This can be used to set a new password on a key or to protect an unprotected + * key. + * + * Note that the only required parameter is "password". + * + * @param key + * @param password the new password to encrypt/re-encrypt the key with. + * Must not be NULL. + * @param cipher the cipher (AES256, etc) used to encrypt the key. May be NULL, + * in which case a default will be used. + * @param cipher_mode the cipher mode (CFB, CBC, OCB). This parameter is not + * well supported currently and is mostly relevant for G10. + * May be NULL. + * @param hash the hash algorithm (SHA512, etc) used for the String-to-Key key + * derivation. May be NULL, in which case a default will be used. + * @param iterations the number of iterations used for the String-to-Key key + * derivation. Use 0 to select a reasonable default. + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_protect(rnp_key_handle_t handle, + const char * password, + const char * cipher, + const char * cipher_mode, + const char * hash, + size_t iterations); + +/** unprotect the key + * + * This removes the encryption from the key. + * + * @param key + * @param password the password to unlock the key. If NULL, the password + * provider will be used. + * @return RNP_SUCCESS on success, or any other value on error + **/ +RNP_API rnp_result_t rnp_key_unprotect(rnp_key_handle_t key, const char *password); + +/** + * @brief Check whether key is primary key. + * + * @param key key handle, cannot be NULL. + * @param result true or false will be stored here on success. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_is_primary(rnp_key_handle_t key, bool *result); + +/** + * @brief Check whether key is subkey. + * + * @param key key handle, cannot be NULL. + * @param result true or false will be stored here on success. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_is_sub(rnp_key_handle_t key, bool *result); + +/** + * @brief Check whether key has secret part. + * + * @param key key handle, cannot be NULL. + * @param result true will be stored here on success, or false otherwise. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_have_secret(rnp_key_handle_t key, bool *result); + +/** + * @brief Check whether key has public part. Generally all keys would have public part. + * + * @param key key handle, cannot be NULL. + * @param result true will be stored here on success, or false otherwise. + * @return RNP_SUCCESS on success, or any other value on error. + */ +RNP_API rnp_result_t rnp_key_have_public(rnp_key_handle_t key, bool *result); + +/** Get the information about key packets in JSON string. + * Note: this will not work for G10 keys. + * + * @param key key's handle, cannot be NULL + * @param secret dump secret key instead of public + * @param flags include additional fields in JSON (see RNP_JSON_DUMP_MPI and other + * RNP_JSON_DUMP_* flags) + * @param result resulting JSON string will be stored here. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_key_packets_to_json(rnp_key_handle_t key, + bool secret, + uint32_t flags, + char ** result); + +/** Dump OpenPGP packets stream information to the JSON string. + * @param input source with OpenPGP data + * @param flags include additional fields in JSON (see RNP_JSON_DUMP_MPI and other + * RNP_JSON_DUMP_* flags) + * @result resulting JSON string will be stored here. You must free it using the + * rnp_buffer_destroy() function. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_dump_packets_to_json(rnp_input_t input, + uint32_t flags, + char ** result); + +/** Dump OpenPGP packets stream information to output in humand-readable format. + * @param input source with OpenPGP data + * @param output text, describing packet sequence, will be written here + * @param flags see RNP_DUMP_MPI and other RNP_DUMP_* constants. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_dump_packets_to_output(rnp_input_t input, + rnp_output_t output, + uint32_t flags); + +/* Signing operations */ + +/** @brief Create signing operation context. This method should be used for embedded + * signatures of binary data. For detached and cleartext signing corresponding + * function should be used. + * @param op pointer to opaque signing context + * @param ffi + * @param input stream with data to be signed. Could not be NULL. + * @param output stream to write results to. Could not be NULL. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_create(rnp_op_sign_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output); + +/** @brief Create cleartext signing operation context. Input should be text data. Output will + * contain source data with additional headers and armored signature. + * @param op pointer to opaque signing context + * @param ffi + * @param input stream with data to be signed. Could not be NULL. + * @param output stream to write results to. Could not be NULL. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_cleartext_create(rnp_op_sign_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output); + +/** @brief Create detached signing operation context. Output will contain only signature of the + * source data. + * @param op pointer to opaque signing context + * @param ffi + * @param input stream with data to be signed. Could not be NULL. + * @param signature stream to write results to. Could not be NULL. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_detached_create(rnp_op_sign_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t signature); + +/** @brief Add information about the signature so it could be calculated later in execute + * function call. Multiple signatures could be added. + * @param op opaque signing context. Must be successfully initialized with one of the + * rnp_op_sign_*_create functions. + * @param key handle of the private key. Private key should be capable for signing. + * @param sig pointer to opaque structure holding the signature information. May be NULL. + * You should not free it as it will be destroyed together with signing context. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_add_signature(rnp_op_sign_t op, + rnp_key_handle_t key, + rnp_op_sign_signature_t *sig); + +/** @brief Set hash algorithm used during signature calculation instead of default one, or one + * set by rnp_op_encrypt_set_hash/rnp_op_sign_set_hash + * @param sig opaque signature context, returned via rnp_op_sign_add_signature + * @param hash hash algorithm to be used + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_signature_set_hash(rnp_op_sign_signature_t sig, + const char * hash); + +/** @brief Set signature creation time. By default current time is used or value set by + * rnp_op_encrypt_set_creation_time/rnp_op_sign_set_creation_time + * @param sig opaque signature context, returned via rnp_op_sign_add_signature + * @param create creation time in seconds since Jan, 1 1970 UTC + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_signature_set_creation_time(rnp_op_sign_signature_t sig, + uint32_t create); + +/** @brief Set signature expiration time. By default is set to never expire or to value set by + * rnp_op_encrypt_set_expiration_time/rnp_op_sign_set_expiration_time + * @param sig opaque signature context, returned via rnp_op_sign_add_signature + * @param expire expiration time in seconds since the creation time. 0 value is used to mark + * signature as non-expiring (default value) + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_signature_set_expiration_time(rnp_op_sign_signature_t sig, + uint32_t expires); + +/** @brief Set data compression parameters. Makes sense only for embedded signatures. + * @param op opaque signing context. Must be initialized with rnp_op_sign_create function + * @param compression compression algorithm (zlib, zip, bzip2) + * @param level compression level, 0-9. 0 disables compression. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_compression(rnp_op_sign_t op, + const char * compression, + int level); + +/** @brief Enabled or disable armored (textual) output. Doesn't make sense for cleartext sign. + * @param op opaque signing context. Must be initialized with rnp_op_sign_create or + * rnp_op_sign_detached_create function. + * @param armored true if armoring should be used (it is disabled by default) + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_armor(rnp_op_sign_t op, bool armored); + +/** @brief Set hash algorithm used during signature calculation. This will set hash function + * for all signature. To change it for a single signature use + * rnp_op_sign_signature_set_hash function. + * @param op opaque signing context. Must be successfully initialized with one of the + * rnp_op_sign_*_create functions. + * @param hash hash algorithm to be used + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_hash(rnp_op_sign_t op, const char *hash); + +/** @brief Set signature creation time. By default current time is used. + * @param op opaque signing context. Must be successfully initialized with one of the + * rnp_op_sign_*_create functions. + * @param create creation time in seconds since Jan, 1 1970 UTC. 32 bit unsigned integer + * datatype is used here instead of 64 bit (like modern timestamps do) because + * in OpenPGP messages times are stored as 32-bit unsigned integers. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_creation_time(rnp_op_sign_t op, uint32_t create); + +/** @brief Set signature expiration time. + * @param op opaque signing context. Must be successfully initialized with one of the + * rnp_op_sign_*_create functions. + * @param expire expiration time in seconds since the creation time. 0 value is used to mark + * signature as non-expiring (default value) + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_expiration_time(rnp_op_sign_t op, uint32_t expire); + +/** @brief Set input's file name. Makes sense only for embedded signature. + * @param op opaque signing context. Must be initialized with rnp_op_sign_create function + * @param filename source data file name. Special value _CONSOLE may be used to mark message + * as 'for your eyes only', i.e. it should not be stored anywhere but only displayed + * to the receiver. Default is the empty string. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_file_name(rnp_op_sign_t op, const char *filename); + +/** @brief Set input's file modification date. Makes sense only for embedded signature. + * @param op opaque signing context. Must be initialized with rnp_op_sign_create function + * @param mtime modification time in seconds since Jan, 1 1970 UTC. 32 bit unsigned integer + * datatype is used here instead of 64 bit (like modern timestamps do) because + * in OpenPGP messages times are stored as 32-bit unsigned integers. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_sign_set_file_mtime(rnp_op_sign_t op, uint32_t mtime); + +/** @brief Execute previously initialized signing operation. + * @param op opaque signing context. Must be successfully initialized with one of the + * rnp_op_sign_*_create functions. At least one signing key should be added. + * @return RNP_SUCCESS or error code if failed. On success output stream, passed in the create + * function call, will be populated with signed data + */ +RNP_API rnp_result_t rnp_op_sign_execute(rnp_op_sign_t op); + +/** @brief Free resources associated with signing operation. + * @param op opaque signing context. Must be successfully initialized with one of the + * rnp_op_sign_*_create functions. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_sign_destroy(rnp_op_sign_t op); + +/* Verification */ + +/** @brief Create verification operation context. This method should be used for embedded + * signatures, cleartext signed data and encrypted (and possibly signed) data. + * For the detached signature verification the function rnp_op_verify_detached_create() + * should be used. + * @param op pointer to opaque verification context + * @param ffi + * @param input stream with signed data. Could not be NULL. + * @param output stream to write results to. Could not be NULL, but may be null output stream + * if verified data should be discarded. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_verify_create(rnp_op_verify_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output); + +/** @brief Create verification operation context for detached signature. + * @param op pointer to opaque verification context + * @param ffi + * @param input stream with raw data. Could not be NULL. + * @param signature stream with detached signature data + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_verify_detached_create(rnp_op_verify_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_input_t signature); + +/** + * @brief Set additional flags which control data verification/decryption process. + * + * @param op pointer to opaque verification context. + * @param flags verification flags. OR-ed combination of RNP_VERIFY_* values. + * Following flags are supported: + * RNP_VERIFY_IGNORE_SIGS_ON_DECRYPT - ignore invalid signatures for the encrypted + * and signed data. If this flag is set then rnp_op_verify_execute() call will + * succeed and output data even if all signatures are invalid or issued by the + * unknown key(s). + * RNP_VERIFY_REQUIRE_ALL_SIGS - require that all signatures (if any) must be + * valid for successful run of rnp_op_verify_execute(). + * RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT - allow hidden recipient during the + * decryption. + * + * Note: all flags are set at once, if some flag is not present in the subsequent + * call then it will be unset. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_verify_set_flags(rnp_op_verify_t op, uint32_t flags); + +/** @brief Execute previously initialized verification operation. + * @param op opaque verification context. Must be successfully initialized. + * @return RNP_SUCCESS if data was processed successfully and output may be used. By default + * this means at least one valid signature for the signed data, or successfully + * decrypted data if no signatures are present. + * This behaviour may be overriden via rnp_op_verify_set_flags() call. + * + * To check number of signatures and their verification status use functions + * rnp_op_verify_get_signature_count() and rnp_op_verify_get_signature_at(). + * To check data encryption status use function rnp_op_verify_get_protection_info(). + */ +RNP_API rnp_result_t rnp_op_verify_execute(rnp_op_verify_t op); + +/** @brief Get number of the signatures for verified data. + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param count result will be stored here on success. + * @return RNP_SUCCESS if call succeeded. + */ +RNP_API rnp_result_t rnp_op_verify_get_signature_count(rnp_op_verify_t op, size_t *count); + +/** @brief Get single signature information based on its index. + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param sig opaque signature context data will be stored here on success. + * @return RNP_SUCCESS if call succeeded. + */ +RNP_API rnp_result_t rnp_op_verify_get_signature_at(rnp_op_verify_t op, + size_t idx, + rnp_op_verify_signature_t *sig); + +/** @brief Get embedded in OpenPGP data file name and modification time. Makes sense only for + * embedded signature verification. + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param filename pointer to the filename. On success caller is responsible for freeing it + * via the rnp_buffer_destroy function call. May be NULL if this information + * is not needed. + * @param mtime file modification time will be stored here on success. May be NULL. + * @return RNP_SUCCESS if call succeeded. + */ +RNP_API rnp_result_t rnp_op_verify_get_file_info(rnp_op_verify_t op, + char ** filename, + uint32_t * mtime); + +/** + * @brief Get data protection (encryption) mode, used in processed message. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param mode on success string with mode will be stored here. Caller is responsible for + * freeing it using the rnp_buffer_destroy() call. May be NULL if information is + * not needed. Currently defined values are as following: + * - none : message was not protected/encrypted + * - cfb : message was encrypted in CFB mode without the MDC + * - cfb-mdc : message was encrypted in CFB mode and protected with MDC + * - aead-ocb : message was encrypted in AEAD-OCB mode + * - aead-eax : message was encrypted in AEAD-EAX mode + * @param cipher symmetric cipher, used for data encryption. May be NULL if information is not + * needed. Must be freed by rnp_buffer_destroy() call. + * @param valid true if message integrity protection was used (i.e. MDC or AEAD), and it was + * validated successfully. Otherwise (even for raw cfb mode) will be false. May be + * NULL if information is not needed. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_protection_info(rnp_op_verify_t op, + char ** mode, + char ** cipher, + bool * valid); + +/** + * @brief Get number of public keys (recipients) to whom message was encrypted to. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param count on success number of keys will be stored here. Cannot be NULL. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_recipient_count(rnp_op_verify_t op, size_t *count); + +/** + * @brief Get the recipient's handle, used to decrypt message. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param recipient pointer to the opaque handle context. Cannot be NULL. If recipient's key + * was used to decrypt a message then handle will be stored here, otherwise + * it will be set to NULL. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_used_recipient(rnp_op_verify_t op, + rnp_recipient_handle_t *recipient); + +/** + * @brief Get the recipient's handle by index. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param idx zero-based index in array. + * @param recipient pointer to the opaque handle context. Cannot be NULL. On success handle + * will be stored here. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_recipient_at(rnp_op_verify_t op, + size_t idx, + rnp_recipient_handle_t *recipient); + +/** + * @brief Get recipient's keyid. + * + * @param recipient recipient's handle, obtained via rnp_op_verify_get_used_recipient() or + * rnp_op_verify_get_recipient_at() function call. Cannot be NULL. + * @param keyid on success pointer to NULL-terminated string with hex-encoded keyid will be + * stored here. Cannot be NULL. Must be freed using the rnp_buffer_destroy(). + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_recipient_get_keyid(rnp_recipient_handle_t recipient, char **keyid); + +/** + * @brief Get recipient's key algorithm. + * + * @param recipient recipient's handle, obtained via rnp_op_verify_get_used_recipient() or + * rnp_op_verify_get_recipient_at() function call. Cannot be NULL. + * @param alg on success pointer to NULL-terminated string with algorithm will be stored here. + * Cannot be NULL. Must be freed using the rnp_buffer_destroy(). + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_recipient_get_alg(rnp_recipient_handle_t recipient, char **alg); + +/** + * @brief Get number of symenc entries (i.e. passwords), to which message was encrypted. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param count on success number of keys will be stored here. Cannot be NULL. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_symenc_count(rnp_op_verify_t op, size_t *count); + +/** + * @brief Get the symenc handle, used to decrypt a message. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param symenc pointer to the opaque symenc context. Cannot be NULL. If password was used to + * decrypt a message then handle will be stored here, otherwise it will be set to + * NULL. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_used_symenc(rnp_op_verify_t op, + rnp_symenc_handle_t *symenc); + +/** + * @brief Get the symenc handle by index. + * + * @param op opaque verification context. Must be initialized and have execute() called on it. + * @param idx zero-based index in array. + * @param symenc pointer to the opaque handle context. Cannot be NULL. On success handle + * will be stored here. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_verify_get_symenc_at(rnp_op_verify_t op, + size_t idx, + rnp_symenc_handle_t *symenc); + +/** + * @brief Get the symmetric cipher, used to encrypt data encryption key. + * Note: if message is encrypted with only one passphrase and without public keys, then + * key, derived from password, may be used to encrypt the whole message. + * @param symenc opaque handle, cannot be NULL. + * @param cipher NULL-terminated string with cipher's name will be stored here. Cannot be NULL. + * Must be freed using the rnp_buffer_destroy(). + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_symenc_get_cipher(rnp_symenc_handle_t symenc, char **cipher); + +/** + * @brief Get AEAD algorithm if it was used to encrypt data encryption key. + * + * @param symenc opaque handle, cannot be NULL. + * @param alg NULL-terminated string with AEAD algorithm name will be stored here. If AEAD was + * not used then it will contain string 'None'. Must be freed using the + * rnp_buffer_destroy(). + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_symenc_get_aead_alg(rnp_symenc_handle_t symenc, char **alg); + +/** + * @brief Get hash algorithm, used to derive key from the passphrase. + * + * @param symenc opaque handle, cannot be NULL. + * @param alg NULL-terminated string with hash algorithm name will be stored here. Cannot be + * NULL. Must be freed using the rnp_buffer_destroy(). + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_symenc_get_hash_alg(rnp_symenc_handle_t symenc, char **alg); + +/** + * @brief Get string-to-key type, used to derive password. + * + * @param symenc opaque handle, cannot be NULL. + * @param type NULL-terminated string with s2k type will be stored here. Currently following + * types are available: 'Simple', 'Salted', 'Iterated and salted'. Please note that + * first two are considered weak and should not be used. Must be freed using the + * rnp_buffer_destroy(). + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_symenc_get_s2k_type(rnp_symenc_handle_t symenc, char **type); + +/** + * @brief Get number of iterations in iterated-and-salted S2K, if it was used. + * + * @param symenc opaque handle, cannot be NULL. + * @param iterations on success number of iterations will be stored here. Cannot be NULL. + * If non-iterated s2k was used then will be set to 0. + * @return RNP_SUCCESS if call succeeded, or error code otherwise. + */ +RNP_API rnp_result_t rnp_symenc_get_s2k_iterations(rnp_symenc_handle_t symenc, + uint32_t * iterations); + +/** @brief Free resources allocated in verification context. + * @param op opaque verification context. Must be initialized. + * @return RNP_SUCCESS if call succeeded. + */ +RNP_API rnp_result_t rnp_op_verify_destroy(rnp_op_verify_t op); + +/** @brief Get signature verification status. + * @param sig opaque signature context obtained via rnp_op_verify_get_signature_at call. + * @return signature verification status: + * RNP_SUCCESS : signature is valid + * RNP_ERROR_SIGNATURE_EXPIRED : signature is valid but expired + * RNP_ERROR_KEY_NOT_FOUND : public key to verify signature was not available + * RNP_ERROR_SIGNATURE_INVALID : data or signature was modified + * RNP_ERROR_SIGNATURE_UNKNOWN : signature has unknown format + */ +RNP_API rnp_result_t rnp_op_verify_signature_get_status(rnp_op_verify_signature_t sig); + +/** Get the signature handle from the verified signature. This would allow to query extended + * information on the signature. + * + * @param sig verified signature context, cannot be NULL. + * @param handle signature handle will be stored here on success. You must free it after use + * with the rnp_signature_handle_destroy() function. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_verify_signature_get_handle(rnp_op_verify_signature_t sig, + rnp_signature_handle_t * handle); + +/** @brief Get hash function used to calculate signature + * @param sig opaque signature context obtained via rnp_op_verify_get_signature_at call. + * @param hash pointer to string with hash algorithm name will be put here on success. + * Caller is responsible for freeing it with rnp_buffer_destroy + * @return RNP_SUCCESS or error code otherwise + */ +RNP_API rnp_result_t rnp_op_verify_signature_get_hash(rnp_op_verify_signature_t sig, + char ** hash); + +/** @brief Get key used for signing + * @param sig opaque signature context obtained via rnp_op_verify_get_signature_at call. + * @param key pointer to opaque key handle structure. + * @return RNP_SUCCESS or error code otherwise + */ +RNP_API rnp_result_t rnp_op_verify_signature_get_key(rnp_op_verify_signature_t sig, + rnp_key_handle_t * key); + +/** @brief Get signature creation and expiration times + * @param sig opaque signature context obtained via rnp_op_verify_get_signature_at call. + * @param create signature creation time will be put here. It is number of seconds since + * Jan, 1 1970 UTC. May be NULL if called doesn't need this data. + * @param expires signature expiration time will be stored here. It is number of seconds since + * the creation time or 0 if signature never expires. May be NULL. + * @return RNP_SUCCESS or error code otherwise + */ +RNP_API rnp_result_t rnp_op_verify_signature_get_times(rnp_op_verify_signature_t sig, + uint32_t * create, + uint32_t * expires); + +/** + * @brief Free buffer allocated by a function in this header. + * + * @param ptr previously allocated buffer. May be NULL, then nothing is done. + */ +RNP_API void rnp_buffer_destroy(void *ptr); + +/** + * @brief Securely clear buffer contents. + * + * @param ptr pointer to the buffer contents, may be NULL. + * @param size number of bytes in buffer. + */ +RNP_API void rnp_buffer_clear(void *ptr, size_t size); + +/** + * @brief Initialize input struct to read from a path + * + * @param input pointer to the input opaque structure + * @param path path of the file to read from + * @return RNP_SUCCESS if operation succeeded and input struct is ready to read, or error code + * otherwise + */ +RNP_API rnp_result_t rnp_input_from_path(rnp_input_t *input, const char *path); + +/** + * @brief Initialize input struct to read from the stdin + * + * @param input pointer to the input opaque structure + * @return RNP_SUCCESS if operation succeeded and input struct is ready to read, or error code + * otherwise + */ +RNP_API rnp_result_t rnp_input_from_stdin(rnp_input_t *input); + +/** + * @brief Initialize input struct to read from memory + * + * @param input pointer to the input opaque structure + * @param buf memory buffer. Could not be NULL. + * @param buf_len number of bytes available to read from buf + * @param do_copy if true then the buffer will be copied internally. If + * false then the application should ensure that the buffer + * is valid and not modified during the lifetime of this object. + * @return RNP_SUCCESS if operation succeeded or error code otherwise + */ +RNP_API rnp_result_t rnp_input_from_memory(rnp_input_t * input, + const uint8_t buf[], + size_t buf_len, + bool do_copy); + +/** + * @brief Initialize input struct to read via callbacks + * + * @param input pointer to the input opaque structure + * @param reader callback used for reading + * @param closer callback used to close the stream + * @param app_ctx context to pass as parameter to reader and closer + * @return RNP_SUCCESS if operation succeeded or error code otherwise + */ +RNP_API rnp_result_t rnp_input_from_callback(rnp_input_t * input, + rnp_input_reader_t *reader, + rnp_input_closer_t *closer, + void * app_ctx); + +/** + * @brief Close previously opened input and free all corresponding resources + * + * @param input previously opened input structure + * @return RNP_SUCCESS if operation succeeded or error code otherwise + */ +RNP_API rnp_result_t rnp_input_destroy(rnp_input_t input); + +/** + * @brief Initialize output structure to write to a path. If path is a file + * that already exists then it will be overwritten. + * + * @param output pointer to the opaque output structure. + * @param path path to the file. + * @return RNP_SUCCESS if file was opened successfully and ready for writing or error code + * otherwise. + */ +RNP_API rnp_result_t rnp_output_to_path(rnp_output_t *output, const char *path); + +/** + * @brief Initialize structure to write to a file. + * Note: it doesn't allow output to directory like rnp_output_to_path does, but + * allows additional options to be specified. + * When RNP_OUTPUT_FILE_RANDOM flag is included then you may want to call + * rnp_output_finish() to make sure that final rename succeeded. + * @param output pointer to the opaque output structure. After use you must free it using the + * rnp_output_destroy() function. + * @param path path to the file. + * @param flags additional flags, see RNP_OUTPUT_* flags. + * @return RNP_SUCCESS if file was opened successfully and ready for writing or error code + * otherwise. + */ +RNP_API rnp_result_t rnp_output_to_file(rnp_output_t *output, + const char * path, + uint32_t flags); + +/** + * @brief Initialize structure to write to the stdout. + * + * @param output pointer to the opaque output structure. After use you must free it using the + * rnp_output_destroy() function. + * @return RNP_SUCCESS if output was initialized successfully or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_to_stdout(rnp_output_t *output); + +/** + * @brief Initialize output structure to write to the memory. + * + * @param output pointer to the opaque output structure. + * @param max_alloc maximum amount of memory to allocate. 0 value means unlimited. + * @return RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_to_memory(rnp_output_t *output, size_t max_alloc); + +/** + * @brief Output data to armored stream (and then output to other destination), allowing + * streamed output. + * + * @param base initialized output structure, where armored data will be written to. + * @param output pointer to the opaque output structure. You must free it later using the + * rnp_output_destroy() function. + * @param type type of the armored stream. See rnp_enarmor() for possible values. + * @return RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_to_armor(rnp_output_t base, + rnp_output_t *output, + const char * type); + +/** + * @brief Get the pointer to the buffer of output, initialized by rnp_output_to_memory + * + * @param output output structure, initialized by rnp_output_to_memory and populated with data + * @param buf pointer to the buffer will be stored here, could not be NULL + * @param len number of bytes in buffer will be stored here, could not be NULL + * @param do_copy if true then a newly-allocated buffer will be returned and the application + * will be responsible for freeing it with rnp_buffer_destroy. If false + * then the internal buffer is returned and the application must not modify the + * buffer or access it after this object is destroyed. + * @return RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_memory_get_buf(rnp_output_t output, + uint8_t ** buf, + size_t * len, + bool do_copy); + +/** + * @brief Initialize output structure to write to callbacks. + * + * @param output pointer to the opaque output structure. + * @param writer write callback. + * @param closer close callback. + * @param app_ctx context parameter which will be passed to writer and closer. + * @return RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_to_callback(rnp_output_t * output, + rnp_output_writer_t *writer, + rnp_output_closer_t *closer, + void * app_ctx); + +/** + * @brief Initialize output structure which will discard all data + * + * @param output pointer to the opaque output structure. + * @return RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_to_null(rnp_output_t *output); + +/** + * @brief write some data to the output structure. + * + * @param output pointer to the initialized opaque output structure. + * @param data pointer to data which should be written. + * @param size number of bytes to write. + * @param written on success will contain the number of bytes written. May be NULL. + * @return rnp_result_t RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_write(rnp_output_t output, + const void * data, + size_t size, + size_t * written); + +/** + * @brief Finish writing to the output. + * Note: on most output types you'll need just to call rnp_output_destroy(). + * However, for file output with RNP_OUTPUT_FILE_RANDOM flag, you need to call this + * to make sure that rename from random to required name succeeded. + * + * @param output pointer to the opaque output structure. + * @return RNP_SUCCESS if operation succeeded or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_finish(rnp_output_t output); + +/** + * @brief Close previously opened output and free all associated data. + * + * @param output previously opened output structure. + * @return RNP_SUCCESS if operation succeeds or error code otherwise. + */ +RNP_API rnp_result_t rnp_output_destroy(rnp_output_t output); + +/* encrypt */ +RNP_API rnp_result_t rnp_op_encrypt_create(rnp_op_encrypt_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output); + +/** + * @brief Add recipient's public key to encrypting context. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param key public key, used for encryption. Key is not checked for + * validity or expiration. + * @return RNP_SUCCESS if operation succeeds or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_handle_t key); + +/** + * @brief Add signature to encrypting context, so data will be encrypted and signed. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param key private key, used for signing. + * @param sig pointer to the newly added signature will be stored here. May be NULL. + * @return RNP_SUCCESS if signature was added or error code otherwise. + */ +RNP_API rnp_result_t rnp_op_encrypt_add_signature(rnp_op_encrypt_t op, + rnp_key_handle_t key, + rnp_op_sign_signature_t *sig); + +/** + * @brief Set hash function used for signature calculation. Makes sense if encrypt-and-sign is + * used. To set hash function for each signature separately use rnp_op_sign_signature_set_hash. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param hash hash algorithm to be used as NULL-terminated string. Following values are + * supported: "MD5", "SHA1", "RIPEMD160", "SHA256", "SHA384", "SHA512", "SHA224", "SM3". + * However, some signature types may require specific hash function or hash function + * output length. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_hash(rnp_op_encrypt_t op, const char *hash); + +/** + * @brief Set signature creation time. By default current time is used. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param create creation time in seconds since Jan, 1 1970 UTC + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_creation_time(rnp_op_encrypt_t op, uint32_t create); + +/** + * @brief Set signature expiration time. By default signatures do not expire. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param expire expiration time in seconds since the creation time. 0 value is used to mark + * signature as non-expiring + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_expiration_time(rnp_op_encrypt_t op, uint32_t expire); + +/** + * @brief Add password which is used to encrypt data. Multiple passwords can be added. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param password NULL-terminated password string, or NULL if password should be requested + * via password provider. + * @param s2k_hash hash algorithm, used in key-from-password derivation. Pass NULL for default + * value. See rnp_op_encrypt_set_hash for possible values. + * @param iterations number of iterations, used in key derivation function. + * According to RFC 4880, chapter 3.7.1.3, only 256 distinct values within the range + * [1024..0x3e00000] can be encoded. Thus, the number will be increased to the closest + * encodable value. In case it exceeds the maximum encodable value, it will be decreased + * to the maximum encodable value. + * If 0 is passed, an optimal number (greater or equal to 1024) will be calculated based + * on performance measurement. + * @param s2k_cipher symmetric cipher, used for key encryption. Pass NULL for default value. + * See rnp_op_encrypt_set_cipher for possible values. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_add_password(rnp_op_encrypt_t op, + const char * password, + const char * s2k_hash, + size_t iterations, + const char * s2k_cipher); + +/** + * @brief Set whether output should be ASCII-armored, or binary. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param armored true for armored, false for binary + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_armor(rnp_op_encrypt_t op, bool armored); + +/** + * @brief set the encryption algorithm + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param cipher NULL-terminated string with cipher's name. One of the "IDEA", "TRIPLEDES", + * "CAST5", "BLOWFISH", "AES128", "AES192", "AES256", "TWOFISH", "CAMELLIA128", + * "CAMELLIA192", "CAMELLIA256", "SM4". + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_cipher(rnp_op_encrypt_t op, const char *cipher); + +/** + * @brief set AEAD mode algorithm or disable AEAD usage. By default it is disabled. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param alg NULL-terminated AEAD algorithm name. Use "None" to disable AEAD, or "EAX", "OCB" + * to use the corresponding algorithm. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_aead(rnp_op_encrypt_t op, const char *alg); + +/** + * @brief set chunk length for AEAD mode via number of chunk size bits (refer to the OpenPGP + * specification for the details). + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param bits number of bits, currently it must be from 0 to 16. + * @return RNP_SUCCESS or error code if failed + */ +RNP_API rnp_result_t rnp_op_encrypt_set_aead_bits(rnp_op_encrypt_t op, int bits); + +/** + * @brief set the compression algorithm and level for the inner raw data + * + * @param op opaque encrypted context. Must be allocated and initialized + * @param compression compression algorithm name. Can be one of the "Uncompressed", "ZIP", + * "ZLIB", "BZip2". Please note that ZIP is not PkWare's ZIP file format but just a + * DEFLATE compressed data (RFC 1951). + * @param level 0 - 9, where 0 is no compression and 9 is maximum compression level. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_op_encrypt_set_compression(rnp_op_encrypt_t op, + const char * compression, + int level); + +/** + * @brief Set additional encryption flags. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @param flags encryption flags. ORed combination of RNP_ENCRYPT_* values. + * Following flags are supported: + * RNP_ENCRYPT_NOWRAP - do not wrap the data in a literal data packet. This + * would allow to encrypt already signed data. + * + * @return RNP_SUCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_encrypt_set_flags(rnp_op_encrypt_t op, uint32_t flags); + +/** + * @brief set the internally stored file name for the data being encrypted + * + * @param op opaque encrypted context. Must be allocated and initialized + * @param filename file name as NULL-terminated string. May be empty string. Value "_CONSOLE" + * may have specific processing (see RFC 4880 for the details), depending on implementation. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_op_encrypt_set_file_name(rnp_op_encrypt_t op, const char *filename); + +/** + * @brief set the internally stored file modification date for the data being encrypted + * + * @param op opaque encrypted context. Must be allocated and initialized + * @param mtime time in seconds since Jan, 1 1970. 32 bit unsigned integer datatype is used + * here instead of 64 bit (like modern timestamps do) because in OpenPGP messages + * times are stored as 32-bit unsigned integers. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_op_encrypt_set_file_mtime(rnp_op_encrypt_t op, uint32_t mtime); + +RNP_API rnp_result_t rnp_op_encrypt_execute(rnp_op_encrypt_t op); +RNP_API rnp_result_t rnp_op_encrypt_destroy(rnp_op_encrypt_t op); + +/** + * @brief Decrypt encrypted data in input and write it to the output on success. + * If data is additionally signed then signatures are ignored. + * For more control over the decryption process see functions rnp_op_verify_create() and + * rnp_op_verify_execute(), which allows to verify signatures as well as decrypt data + * and retrieve encryption-related information. + * + * @param ffi initialized FFI object. Cannot be NULL. + * @param input source with encrypted data. Cannot be NULL. + * @param output on success decrypted data will be written here. Cannot be NULL. + * @return RNP_SUCCESS if data was successfully decrypted and written to the output, or any + * other value on error. + */ +RNP_API rnp_result_t rnp_decrypt(rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output); + +/** retrieve the raw data for a public key + * + * This will always be PGP packets and will never include ASCII armor. + * + * @param handle the key handle + * @param buf + * @param buf_len + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_get_public_key_data(rnp_key_handle_t handle, + uint8_t ** buf, + size_t * buf_len); + +/** retrieve the raw data for a secret key + * + * If this is a G10 key, this will be the s-expr data. Otherwise, it will + * be PGP packets. + * + * Note that this result will never include ASCII armor. + * + * @param handle the key handle + * @param buf + * @param buf_len + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_get_secret_key_data(rnp_key_handle_t handle, + uint8_t ** buf, + size_t * buf_len); + +/** output key information to JSON structure and serialize it to the string + * + * @param handle the key handle, could not be NULL + * @param flags controls which key data is printed, see RNP_JSON_* constants. + * @param result pointer to the resulting string will be stored here on success. You must + * release it afterwards via rnp_buffer_destroy() function call. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_to_json(rnp_key_handle_t handle, uint32_t flags, char **result); + +/** create an identifier iterator + * + * @param ffi + * @param it pointer that will be set to the created iterator + * @param identifier_type the type of identifier ("userid", "keyid", "grip", "fingerprint") + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_identifier_iterator_create(rnp_ffi_t ffi, + rnp_identifier_iterator_t *it, + const char *identifier_type); + +/** retrieve the next item from an iterator + * + * @param it the iterator + * @param identifier pointer that will be set to the identifier value. + * Must not be NULL. This buffer should not be freed by the application. + * It will be modified by subsequent calls to this function, and its + * life is tied to the iterator. + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_identifier_iterator_next(rnp_identifier_iterator_t it, + const char ** identifier); + +/** destroy an identifier iterator + * + * @param it the iterator object + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_identifier_iterator_destroy(rnp_identifier_iterator_t it); + +/** Read from input and write to output + * + * @param input stream to read data from + * @param output stream to write data to + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_output_pipe(rnp_input_t input, rnp_output_t output); + +/** Set line length for armored output + * + * @param output stream to configure + * @param llen line length in characters [16..76] + * @return RNP_SUCCESS on success, or any other value on error + */ +RNP_API rnp_result_t rnp_output_armor_set_line_length(rnp_output_t output, size_t llen); + +/** + * @brief Return cryptographic backend library name. + * + * @return Backend name string. Currently supported + * backends are "Botan" and "OpenSSL". + */ +RNP_API const char *rnp_backend_string(); + +/** + * @brief Return cryptographic backend library version. + * + * @return Version string. + */ +RNP_API const char *rnp_backend_version(); + +#if defined(__cplusplus) +} + +#endif + +/** + * Feature strings. + */ +#ifndef RNP_FEATURE_SYMM_ALG + +#define RNP_FEATURE_SYMM_ALG "symmetric algorithm" +#define RNP_FEATURE_AEAD_ALG "aead algorithm" +#define RNP_FEATURE_PROT_MODE "protection mode" +#define RNP_FEATURE_PK_ALG "public key algorithm" +#define RNP_FEATURE_HASH_ALG "hash algorithm" +#define RNP_FEATURE_COMP_ALG "compression algorithm" +#define RNP_FEATURE_CURVE "elliptic curve" + +#endif + +/** Algorithm Strings + */ +#ifndef RNP_ALGNAME_PLAINTEXT + +#define RNP_ALGNAME_PLAINTEXT "PLAINTEXT" +#define RNP_ALGNAME_RSA "RSA" +#define RNP_ALGNAME_ELGAMAL "ELGAMAL" +#define RNP_ALGNAME_DSA "DSA" +#define RNP_ALGNAME_ECDH "ECDH" +#define RNP_ALGNAME_ECDSA "ECDSA" +#define RNP_ALGNAME_EDDSA "EDDSA" +#define RNP_ALGNAME_IDEA "IDEA" +#define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" +#define RNP_ALGNAME_CAST5 "CAST5" +#define RNP_ALGNAME_BLOWFISH "BLOWFISH" +#define RNP_ALGNAME_TWOFISH "TWOFISH" +#define RNP_ALGNAME_AES_128 "AES128" +#define RNP_ALGNAME_AES_192 "AES192" +#define RNP_ALGNAME_AES_256 "AES256" +#define RNP_ALGNAME_CAMELLIA_128 "CAMELLIA128" +#define RNP_ALGNAME_CAMELLIA_192 "CAMELLIA192" +#define RNP_ALGNAME_CAMELLIA_256 "CAMELLIA256" +#define RNP_ALGNAME_SM2 "SM2" +#define RNP_ALGNAME_SM3 "SM3" +#define RNP_ALGNAME_SM4 "SM4" +#define RNP_ALGNAME_MD5 "MD5" +#define RNP_ALGNAME_SHA1 "SHA1" +#define RNP_ALGNAME_SHA256 "SHA256" +#define RNP_ALGNAME_SHA384 "SHA384" +#define RNP_ALGNAME_SHA512 "SHA512" +#define RNP_ALGNAME_SHA224 "SHA224" +#define RNP_ALGNAME_SHA3_256 "SHA3-256" +#define RNP_ALGNAME_SHA3_512 "SHA3-512" +#define RNP_ALGNAME_RIPEMD160 "RIPEMD160" +#define RNP_ALGNAME_CRC24 "CRC24" + +/* SHA1 is not considered secured anymore and SHOULD NOT be used to create messages (as per + * Appendix C of RFC 4880-bis-02). SHA2 MUST be implemented. + * Let's preempt this by specifying SHA256 - gpg interoperates just fine with SHA256 - agc, + * 20090522 + */ +#define DEFAULT_HASH_ALG RNP_ALGNAME_SHA256 + +/* Default symmetric algorithm */ +#define DEFAULT_SYMM_ALG RNP_ALGNAME_AES_256 + +/* Keystore format: GPG, KBX (pub), G10 (sec), GPG21 ( KBX for pub, G10 for sec) */ +#define RNP_KEYSTORE_GPG ("GPG") +#define RNP_KEYSTORE_KBX ("KBX") +#define RNP_KEYSTORE_G10 ("G10") +#define RNP_KEYSTORE_GPG21 ("GPG21") + +#endif diff --git a/comm/third_party/rnp/include/rnp/rnp_def.h b/comm/third_party/rnp/include/rnp/rnp_def.h new file mode 100644 index 0000000000..5b099d98dd --- /dev/null +++ b/comm/third_party/rnp/include/rnp/rnp_def.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_DEF_H_ +#define RNP_DEF_H_ + +#include +#include "rnp_err.h" + +/* rnp_result_t is the type used for return codes from the APIs. */ +typedef uint32_t rnp_result_t; + +#endif diff --git a/comm/third_party/rnp/include/rnp/rnp_err.h b/comm/third_party/rnp/include/rnp/rnp_err.h new file mode 100644 index 0000000000..f4ff179e5f --- /dev/null +++ b/comm/third_party/rnp/include/rnp/rnp_err.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017-2019, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_ERR_H_ +#define RNP_ERR_H_ + +/* + * Error code definitions + */ +enum { + + RNP_SUCCESS = 0x00000000, + + /* Common error codes */ + RNP_ERROR_GENERIC = 0x10000000, + RNP_ERROR_BAD_FORMAT, + RNP_ERROR_BAD_PARAMETERS, + RNP_ERROR_NOT_IMPLEMENTED, + RNP_ERROR_NOT_SUPPORTED, + RNP_ERROR_OUT_OF_MEMORY, + RNP_ERROR_SHORT_BUFFER, + RNP_ERROR_NULL_POINTER, + + /* Storage */ + RNP_ERROR_ACCESS = 0x11000000, + RNP_ERROR_READ, + RNP_ERROR_WRITE, + + /* Crypto */ + RNP_ERROR_BAD_STATE = 0x12000000, + RNP_ERROR_MAC_INVALID, + RNP_ERROR_SIGNATURE_INVALID, + RNP_ERROR_KEY_GENERATION, + RNP_ERROR_BAD_PASSWORD, + RNP_ERROR_KEY_NOT_FOUND, + RNP_ERROR_NO_SUITABLE_KEY, + RNP_ERROR_DECRYPT_FAILED, + RNP_ERROR_RNG, + RNP_ERROR_SIGNING_FAILED, + RNP_ERROR_NO_SIGNATURES_FOUND, + + RNP_ERROR_SIGNATURE_EXPIRED, + RNP_ERROR_VERIFICATION_FAILED, + RNP_ERROR_SIGNATURE_UNKNOWN, + + /* Parsing */ + RNP_ERROR_NOT_ENOUGH_DATA = 0x13000000, + RNP_ERROR_UNKNOWN_TAG, + RNP_ERROR_PACKET_NOT_CONSUMED, + RNP_ERROR_NO_USERID, + RNP_ERROR_EOF + +}; + +#endif diff --git a/comm/third_party/rnp/module.ver b/comm/third_party/rnp/module.ver new file mode 100644 index 0000000000..b78ab6b351 --- /dev/null +++ b/comm/third_party/rnp/module.ver @@ -0,0 +1,8 @@ +WIN32_MODULE_DESCRIPTION=@MOZ_APP_DISPLAYNAME@ +WIN32_MODULE_PRODUCTNAME=@MOZ_APP_DISPLAYNAME@ +WIN32_MODULE_NAME=@MOZ_APP_DISPLAYNAME@ @MOZ_APP_VERSION@ rnp +WIN32_MODULE_PRODUCTVERSION=@MOZ_APP_WINVERSION@ +WIN32_MODULE_PRODUCTVERSION_STRING=@MOZ_APP_VERSION@ +WIN32_MODULE_COPYRIGHT=Thunderbird and Mozilla Developers, according to the MPL 1.1/GPL 2.0/LGPL 2.1 licenses, as applicable. +WIN32_MODULE_COMPANYNAME=MZLA Technologies +WIN32_MODULE_COMMENT=OpenPGP support library. Includes RNP, Botan, Json-C. See license and README files. diff --git a/comm/third_party/rnp/moz.build b/comm/third_party/rnp/moz.build new file mode 100644 index 0000000000..3ab156a4b2 --- /dev/null +++ b/comm/third_party/rnp/moz.build @@ -0,0 +1,227 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SharedLibrary("rnp") + +include("../rnpdefs.mozbuild") + + +@template +def IQuote(*paths): + """Add a set of paths to the include path via -iquote""" + if CONFIG["CC_TYPE"] == "clang-cl": + flags = ["-Xclang", "-iquote", "-Xclang"] + else: + flags = ["-iquote"] + for p in paths: + CXXFLAGS += flags + [p] + + +def get_defines(defines): + """For DEFINES that are False, do not include them in the preprocesser + commandline. Such preprocessor macros will be #undef'd in the output file while + allowing the build code to be explicit (and hopefully more readable).""" + + for define, value in defines.items(): + if value is True: + yield ("-D%s" % define) + elif value is not False: + yield ("-D%s=%s" % (define, value)) + + +COMPILE_FLAGS["WARNINGS_CFLAGS"] += [ + "-Wall", + "-Wextra", + "-Wunreachable-code", + "-Wpointer-arith", + "-Wmissing-declarations", + "-Wno-pedantic", + "-Wno-ignored-qualifiers", + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", +] + +if CONFIG["CC_TYPE"] == "clang-cl": + CXXFLAGS += [ + "/EHs", + ] + +LOCAL_INCLUDES = [ + "include", + "src", + "src/common", + "src/lib", + "src/libsexp/include" +] + +IQuote( + "{}/src/lib".format(OBJDIR), +) + +# Set up defines for src/lib/config.h +rnp_defines = { + "HAVE_BZLIB_H": True, + "HAVE_ZLIB_H": True, + "ENABLE_SM2": False, + "ENABLE_IDEA": True, + "ENABLE_AEAD": True, + "ENABLE_BLOWFISH": True, + "ENABLE_CAST5": True, + "ENABLE_RIPEMD160": True, + "PACKAGE_BUGREPORT": '"https://bugzilla.mozilla.org/enter_bug.cgi?product=Thunderbird"', +} +if CONFIG["MZLA_LIBRNP_BACKEND"] == "botan": + LOCAL_INCLUDES += ["!../botan/build/include"] + if CONFIG["MZLA_SYSTEM_BOTAN"]: + CXXFLAGS += CONFIG["MZLA_BOTAN_CFLAGS"] + + rnp_defines.update({ + "CRYPTO_BACKEND_BOTAN": True, + "ENABLE_TWOFISH": True, + "ENABLE_BRAINPOOL": True, + }) +elif CONFIG["MZLA_LIBRNP_BACKEND"] == "openssl": + CXXFLAGS += CONFIG["MZLA_LIBRNP_OPENSSL_CFLAGS"] + OS_LIBS += CONFIG["MZLA_LIBRNP_OPENSSL_LIBS"] + + rnp_defines.update({ + "CRYPTO_BACKEND_OPENSSL": True, + # Not supported by OpenSSL https://github.com/openssl/openssl/issues/2046 + "ENABLE_TWOFISH": False, + # Supported, but not with RHEL's OpenSSL, disabled for now; + "ENABLE_BRAINPOOL": False, + }) + rnp_defines["PACKAGE_STRING"] = rnp_defines["PACKAGE_STRING"][:-1] + '-openssl"' + if CONFIG["MZLA_LIBRNP_OPENSSL_VERSION"][0] == "3": + rnp_defines["CRYPTO_BACKEND_OPENSSL3"] = True + + +gen_files_flags = [d for d in get_defines(rnp_defines)] + +GeneratedFile( + "src/lib/version.h", "src/lib/config.h", + script="/comm/python/thirdroc/rnp_generated.py", + inputs=["src/lib/version.h.in", "src/lib/config.h.in"], + flags=["-V", f"{SRCDIR}/version.txt", + "-m", CONFIG["MOZ_APP_VERSION_DISPLAY"]] + gen_files_flags +) + +if CONFIG["MOZ_SYSTEM_ZLIB"]: + CXXFLAGS += CONFIG["MOZ_ZLIB_CFLAGS"] +else: + LOCAL_INCLUDES += ["../zlib"] + +if CONFIG["MZLA_SYSTEM_JSONC"]: + CXXFLAGS += CONFIG["MZLA_JSONC_CFLAGS"] +else: + IQuote("{}/../json-c".format(OBJDIR)) + LOCAL_INCLUDES += ["!../json-c", "../json-c"] + +if CONFIG["MZLA_SYSTEM_BZIP2"]: + CXXFLAGS += CONFIG["MZLA_BZIP2_CFLAGS"] +else: + LOCAL_INCLUDES += ["../bzip2"] + +if CONFIG["CC_TYPE"] == "clang-cl": + LOCAL_INCLUDES += [ + "../niwcompat", + ] + + if CONFIG["CPU_ARCH"] == "x86": + LDFLAGS += ["clang_rt.builtins-i386.lib"] + elif CONFIG["CPU_ARCH"] == "x86_64": + LDFLAGS += ["clang_rt.builtins-x86_64.lib"] + +SYMBOLS_FILE = "rnp.symbols" + + +SOURCES += [ + "src/common/file-utils.cpp", + "src/common/str-utils.cpp", + "src/common/time-utils.cpp", + "src/lib/crypto.cpp", + "src/lib/crypto/backend_version.cpp", + "src/lib/crypto/cipher.cpp", + "src/lib/crypto/ec_curves.cpp", + "src/lib/crypto/ecdh_utils.cpp", + "src/lib/crypto/hash_common.cpp", + "src/lib/crypto/hash_sha1cd.cpp", + "src/lib/crypto/mpi.cpp", + "src/lib/crypto/s2k.cpp", + "src/lib/crypto/sha1cd/sha1.c", + "src/lib/crypto/sha1cd/ubc_check.c", + "src/lib/crypto/signatures.cpp", + "src/lib/fingerprint.cpp", + "src/lib/generate-key.cpp", + "src/lib/json-utils.cpp", + "src/lib/key-provider.cpp", + "src/lib/logging.cpp", + "src/lib/pass-provider.cpp", + "src/lib/pgp-key.cpp", + "src/lib/rnp.cpp", + "src/lib/sec_profile.cpp", + "src/lib/utils.cpp", + # librekey + "src/librekey/key_store_g10.cpp", + "src/librekey/key_store_kbx.cpp", + "src/librekey/key_store_pgp.cpp", + "src/librekey/rnp_key_store.cpp", + # librepgp + "src/librepgp/stream-armor.cpp", + "src/librepgp/stream-common.cpp", + "src/librepgp/stream-ctx.cpp", + "src/librepgp/stream-dump.cpp", + "src/librepgp/stream-key.cpp", + "src/librepgp/stream-packet.cpp", + "src/librepgp/stream-parse.cpp", + "src/librepgp/stream-sig.cpp", + "src/librepgp/stream-write.cpp", + # libsexp + "src/libsexp/src/ext-key-format.cpp", + "src/libsexp/src/sexp-char-defs.cpp", + "src/libsexp/src/sexp-error.cpp", + "src/libsexp/src/sexp-input.cpp", + "src/libsexp/src/sexp-object.cpp", + "src/libsexp/src/sexp-output.cpp", + "src/libsexp/src/sexp-simple-string.cpp", +] + +if CONFIG["MZLA_LIBRNP_BACKEND"] == "botan": + SOURCES += [ + "src/lib/crypto/bn.cpp", + "src/lib/crypto/cipher_botan.cpp", + "src/lib/crypto/dsa.cpp", + "src/lib/crypto/ec.cpp", + "src/lib/crypto/ecdh.cpp", + "src/lib/crypto/ecdsa.cpp", + "src/lib/crypto/eddsa.cpp", + "src/lib/crypto/elgamal.cpp", + "src/lib/crypto/hash.cpp", + "src/lib/crypto/mem.cpp", + "src/lib/crypto/rng.cpp", + "src/lib/crypto/rsa.cpp", + "src/lib/crypto/symmetric.cpp", + ] +if CONFIG["MZLA_LIBRNP_BACKEND"] == "openssl": + SOURCES += [ + "src/lib/crypto/bn_ossl.cpp", + "src/lib/crypto/cipher_ossl.cpp", + "src/lib/crypto/dl_ossl.cpp", + "src/lib/crypto/dsa_ossl.cpp", + "src/lib/crypto/ec_ossl.cpp", + "src/lib/crypto/ecdh_ossl.cpp", + "src/lib/crypto/ecdsa_ossl.cpp", + "src/lib/crypto/eddsa_ossl.cpp", + "src/lib/crypto/elgamal_ossl.cpp", + "src/lib/crypto/hash_crc24.cpp", + "src/lib/crypto/hash_ossl.cpp", + "src/lib/crypto/mem_ossl.cpp", + "src/lib/crypto/rng_ossl.cpp", + "src/lib/crypto/rsa_ossl.cpp", + "src/lib/crypto/s2k_ossl.cpp", + "src/lib/crypto/symmetric_ossl.cpp", + ] + +DIRS += ["src/rnp", "src/rnpkeys"] diff --git a/comm/third_party/rnp/moz.yaml b/comm/third_party/rnp/moz.yaml new file mode 100644 index 0000000000..e2249767fc --- /dev/null +++ b/comm/third_party/rnp/moz.yaml @@ -0,0 +1,76 @@ +--- +schema: 1 + +bugzilla: + product: "Thunderbird" + component: "Build Config" + +origin: + name: "rnp" + description: "High performance C++ OpenPGP library" + + url: "https://www.rnpgp.org/" + license: BSD-2-Clause + + release: v0.17.0 (2023-05-02T08:01:48Z). + + revision: v0.17.0 + + license-file: LICENSE.md + +vendoring: + url: https://github.com/rnpgp/rnp + source-hosting: github + tracking: tag + release-artifact: "rnp-{tag}.tar.gz" + + skip-vendoring-steps: + - hg-add + - spurious-check + - update-moz-build + + keep: + - module.ver + - rnp.symbols + - src/lib/rnp/rnp_export.h + + exclude: + - "**" + - ".*" + - ".*/**" + - "src/libsexp/**" + - "src/libsexp/.**" + - "src/libsexp/.github/**" + + include: + - doc/ + - docs/ + - include/ + - src/common/ + - src/examples/ + - src/fuzzing/ + - src/lib/ + - src/librekey/ + - src/librepgp/ + - src/libsexp/include/ + - src/libsexp/src/ + - src/libsexp/LICENSE.md + - src/libsexp/README.adoc + - src/libsexp/version.txt + - src/rnp/ + - src/rnpkeys/ + - src/tests/ + - CHANGELOG.md + - LICENSE-OCB.md + - LICENSE.md + - README.adoc + - version.txt + + patches: + - ../patches/rnp/bug1843535_gcc13_missing_header.patch + + update-actions: + - action: replace-in-file-regex + file: '{yaml_dir}/../README.rnp' + pattern: '\[(tag v[0-9\.]+|commit [0-9a-f]+)\]' + with: '[tag {revision}]' diff --git a/comm/third_party/rnp/rnp.symbols b/comm/third_party/rnp/rnp.symbols new file mode 100644 index 0000000000..3c682425ac --- /dev/null +++ b/comm/third_party/rnp/rnp.symbols @@ -0,0 +1,240 @@ +rnp_add_security_rule +rnp_backend_string +rnp_backend_version +rnp_buffer_clear +rnp_buffer_destroy +rnp_calculate_iterations +rnp_dearmor +rnp_decrypt +rnp_detect_homedir_info +rnp_detect_key_format +rnp_dump_packets_to_json +rnp_dump_packets_to_output +rnp_enarmor +rnp_ffi_create +rnp_ffi_destroy +rnp_ffi_set_key_provider +rnp_ffi_set_log_fd +rnp_ffi_set_pass_provider +rnp_generate_key_25519 +rnp_generate_key_dsa_eg +rnp_generate_key_ec +rnp_generate_key_ex +rnp_generate_key_json +rnp_generate_key_rsa +rnp_generate_key_sm2 +rnp_get_default_homedir +rnp_get_public_key_count +rnp_get_public_key_data +rnp_get_secret_key_count +rnp_get_secret_key_data +rnp_get_security_rule +rnp_guess_contents +rnp_identifier_iterator_create +rnp_identifier_iterator_destroy +rnp_identifier_iterator_next +rnp_import_keys +rnp_import_signatures +rnp_input_destroy +rnp_input_from_callback +rnp_input_from_memory +rnp_input_from_path +rnp_input_from_stdin +rnp_key_25519_bits_tweak +rnp_key_25519_bits_tweaked +rnp_key_add_uid +rnp_key_allows_usage +rnp_key_export +rnp_key_export_autocrypt +rnp_key_export_revocation +rnp_key_get_alg +rnp_key_get_bits +rnp_key_get_creation +rnp_key_get_curve +rnp_key_get_default_key +rnp_key_get_dsa_qbits +rnp_key_get_expiration +rnp_key_get_fprint +rnp_key_get_grip +rnp_key_get_keyid +rnp_key_get_primary_fprint +rnp_key_get_primary_grip +rnp_key_get_primary_uid +rnp_key_get_protection_cipher +rnp_key_get_protection_hash +rnp_key_get_protection_iterations +rnp_key_get_protection_mode +rnp_key_get_protection_type +rnp_key_get_revocation_reason +rnp_key_get_revocation_signature +rnp_key_get_signature_at +rnp_key_get_signature_count +rnp_key_get_subkey_at +rnp_key_get_subkey_count +rnp_key_get_uid_at +rnp_key_get_uid_count +rnp_key_get_uid_handle_at +rnp_key_handle_destroy +rnp_key_have_public +rnp_key_have_secret +rnp_key_is_compromised +rnp_key_is_expired +rnp_key_is_locked +rnp_key_is_primary +rnp_key_is_protected +rnp_key_is_retired +rnp_key_is_revoked +rnp_key_is_sub +rnp_key_is_superseded +rnp_key_is_valid +rnp_key_lock +rnp_key_packets_to_json +rnp_key_protect +rnp_key_remove +rnp_key_remove_signatures +rnp_key_revoke +rnp_key_set_expiration +rnp_key_to_json +rnp_key_unlock +rnp_key_unprotect +rnp_key_valid_till +rnp_key_valid_till64 +rnp_load_keys +rnp_locate_key +rnp_op_encrypt_add_password +rnp_op_encrypt_add_recipient +rnp_op_encrypt_add_signature +rnp_op_encrypt_create +rnp_op_encrypt_destroy +rnp_op_encrypt_execute +rnp_op_encrypt_set_aead +rnp_op_encrypt_set_aead_bits +rnp_op_encrypt_set_armor +rnp_op_encrypt_set_cipher +rnp_op_encrypt_set_compression +rnp_op_encrypt_set_creation_time +rnp_op_encrypt_set_expiration_time +rnp_op_encrypt_set_file_mtime +rnp_op_encrypt_set_file_name +rnp_op_encrypt_set_flags +rnp_op_encrypt_set_hash +rnp_op_generate_add_pref_cipher +rnp_op_generate_add_pref_compression +rnp_op_generate_add_pref_hash +rnp_op_generate_add_usage +rnp_op_generate_clear_pref_ciphers +rnp_op_generate_clear_pref_compression +rnp_op_generate_clear_pref_hashes +rnp_op_generate_clear_usage +rnp_op_generate_create +rnp_op_generate_destroy +rnp_op_generate_execute +rnp_op_generate_get_key +rnp_op_generate_set_bits +rnp_op_generate_set_curve +rnp_op_generate_set_dsa_qbits +rnp_op_generate_set_expiration +rnp_op_generate_set_hash +rnp_op_generate_set_pref_keyserver +rnp_op_generate_set_protection_cipher +rnp_op_generate_set_protection_hash +rnp_op_generate_set_protection_iterations +rnp_op_generate_set_protection_mode +rnp_op_generate_set_protection_password +rnp_op_generate_set_request_password +rnp_op_generate_set_userid +rnp_op_generate_subkey_create +rnp_op_sign_add_signature +rnp_op_sign_cleartext_create +rnp_op_sign_create +rnp_op_sign_destroy +rnp_op_sign_detached_create +rnp_op_sign_execute +rnp_op_sign_set_armor +rnp_op_sign_set_compression +rnp_op_sign_set_creation_time +rnp_op_sign_set_expiration_time +rnp_op_sign_set_file_mtime +rnp_op_sign_set_file_name +rnp_op_sign_set_hash +rnp_op_sign_signature_set_creation_time +rnp_op_sign_signature_set_expiration_time +rnp_op_sign_signature_set_hash +rnp_op_verify_create +rnp_op_verify_destroy +rnp_op_verify_detached_create +rnp_op_verify_execute +rnp_op_verify_get_file_info +rnp_op_verify_get_protection_info +rnp_op_verify_get_recipient_at +rnp_op_verify_get_recipient_count +rnp_op_verify_get_signature_at +rnp_op_verify_get_signature_count +rnp_op_verify_get_symenc_at +rnp_op_verify_get_symenc_count +rnp_op_verify_get_used_recipient +rnp_op_verify_get_used_symenc +rnp_op_verify_set_flags +rnp_op_verify_signature_get_handle +rnp_op_verify_signature_get_hash +rnp_op_verify_signature_get_key +rnp_op_verify_signature_get_status +rnp_op_verify_signature_get_times +rnp_output_armor_set_line_length +rnp_output_destroy +rnp_output_finish +rnp_output_memory_get_buf +rnp_output_pipe +rnp_output_to_armor +rnp_output_to_callback +rnp_output_to_file +rnp_output_to_memory +rnp_output_to_null +rnp_output_to_path +rnp_output_to_stdout +rnp_output_write +rnp_recipient_get_alg +rnp_recipient_get_keyid +rnp_remove_security_rule +rnp_request_password +rnp_result_to_string +rnp_save_keys +rnp_set_timestamp +rnp_signature_get_alg +rnp_signature_get_creation +rnp_signature_get_expiration +rnp_signature_get_hash_alg +rnp_signature_get_key_fprint +rnp_signature_get_keyid +rnp_signature_get_signer +rnp_signature_get_type +rnp_signature_handle_destroy +rnp_signature_is_valid +rnp_signature_packet_to_json +rnp_signature_remove +rnp_supported_features +rnp_supports_feature +rnp_symenc_get_aead_alg +rnp_symenc_get_cipher +rnp_symenc_get_hash_alg +rnp_symenc_get_s2k_iterations +rnp_symenc_get_s2k_type +rnp_uid_get_data +rnp_uid_get_revocation_signature +rnp_uid_get_signature_at +rnp_uid_get_signature_count +rnp_uid_get_type +rnp_uid_handle_destroy +rnp_uid_is_primary +rnp_uid_is_revoked +rnp_uid_is_valid +rnp_uid_remove +rnp_unload_keys +rnp_version +rnp_version_commit_timestamp +rnp_version_for +rnp_version_major +rnp_version_minor +rnp_version_patch +rnp_version_string +rnp_version_string_full diff --git a/comm/third_party/rnp/src/common/CMakeLists.txt b/comm/third_party/rnp/src/common/CMakeLists.txt new file mode 100644 index 0000000000..1ea344592a --- /dev/null +++ b/comm/third_party/rnp/src/common/CMakeLists.txt @@ -0,0 +1,64 @@ +# Copyright (c) 2020 Ribose Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +add_library(rnp-common OBJECT + str-utils.cpp + file-utils.cpp + time-utils.cpp +) + +if(MSVC) + find_path(GETOPT_INCLUDE_DIR + NAMES getopt.h + ) + find_library(GETOPT_LIBRARY + NAMES getopt + ) + find_path(DIRENT_INCLUDE_DIR + NAMES dirent.h + ) +endif() + +target_include_directories(rnp-common + PUBLIC + "$" + "$" + "$" + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}" + "${PROJECT_SOURCE_DIR}/src" +) +if(MSVC) + target_include_directories(rnp-common + PRIVATE + "${GETOPT_INCLUDE_DIR}" + "${DIRENT_INCLUDE_DIR}" + ) +endif() + +set_target_properties(rnp-common PROPERTIES + POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET hidden +) + diff --git a/comm/third_party/rnp/src/common/file-utils.cpp b/comm/third_party/rnp/src/common/file-utils.cpp new file mode 100644 index 0000000000..d9cdb402dc --- /dev/null +++ b/comm/third_party/rnp/src/common/file-utils.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** File utilities + * @file + */ + +#include "file-utils.h" +#include "config.h" +#ifdef _MSC_VER +#include +#include +#include "uniwin.h" +#include +#else +#include +#include +#include +#endif // !_MSC_VER +#include "str-utils.h" +#include +#ifdef _WIN32 +#include // for rnp_mkstemp +#define CATCH_AND_RETURN(v) \ + catch (...) \ + { \ + errno = ENOMEM; \ + return v; \ + } +#else +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#include + +int +rnp_unlink(const char *filename) +{ +#ifdef _WIN32 + try { + return _wunlink(wstr_from_utf8(filename).c_str()); + } + CATCH_AND_RETURN(-1) +#else + return unlink(filename); +#endif +} + +bool +rnp_file_exists(const char *path) +{ + struct stat st; + return rnp_stat(path, &st) == 0 && S_ISREG(st.st_mode); +} + +bool +rnp_dir_exists(const char *path) +{ + struct stat st; + return rnp_stat(path, &st) == 0 && S_ISDIR(st.st_mode); +} + +int +rnp_open(const char *filename, int oflag, int pmode) +{ +#ifdef _WIN32 + try { + return _wopen(wstr_from_utf8(filename).c_str(), oflag, pmode); + } + CATCH_AND_RETURN(-1) +#else + return open(filename, oflag, pmode); +#endif +} + +FILE * +rnp_fopen(const char *filename, const char *mode) +{ +#ifdef _WIN32 + try { + return _wfopen(wstr_from_utf8(filename).c_str(), wstr_from_utf8(mode).c_str()); + } + CATCH_AND_RETURN(NULL) +#else + return fopen(filename, mode); +#endif +} + +FILE * +rnp_fdopen(int fildes, const char *mode) +{ +#ifdef _WIN32 + return _fdopen(fildes, mode); +#else + return fdopen(fildes, mode); +#endif +} + +int +rnp_access(const char *path, int mode) +{ +#ifdef _WIN32 + try { + return _waccess(wstr_from_utf8(path).c_str(), mode); + } + CATCH_AND_RETURN(-1) +#else + return access(path, mode); +#endif +} + +int +rnp_stat(const char *filename, struct stat *statbuf) +{ +#ifdef _WIN32 + static_assert(sizeof(struct stat) == sizeof(struct _stat64i32), + "stat is expected to match _stat64i32"); + try { + return _wstat64i32(wstr_from_utf8(filename).c_str(), (struct _stat64i32 *) statbuf); + } + CATCH_AND_RETURN(-1) +#else + return stat(filename, statbuf); +#endif +} + +#ifdef _WIN32 +int +rnp_mkdir(const char *path) +{ + try { + return _wmkdir(wstr_from_utf8(path).c_str()); + } + CATCH_AND_RETURN(-1) +} +#endif + +int +rnp_rename(const char *oldpath, const char *newpath) +{ +#ifdef _WIN32 + try { + return _wrename(wstr_from_utf8(oldpath).c_str(), wstr_from_utf8(newpath).c_str()); + } + CATCH_AND_RETURN(-1) +#else + return rename(oldpath, newpath); +#endif +} + +#ifdef _WIN32 +_WDIR * +#else +DIR * +#endif +rnp_opendir(const char *path) +{ +#ifdef _WIN32 + try { + return _wopendir(wstr_from_utf8(path).c_str()); + } + CATCH_AND_RETURN(NULL) +#else + return opendir(path); +#endif +} + +std::string +#ifdef _WIN32 +rnp_readdir_name(_WDIR *dir) +{ + _wdirent *ent; + for (;;) { + if ((ent = _wreaddir(dir)) == NULL) { + return std::string(); + } + if (wcscmp(ent->d_name, L".") && wcscmp(ent->d_name, L"..")) { + break; + } + } + try { + return wstr_to_utf8(ent->d_name); + } + CATCH_AND_RETURN(std::string()) +#else +rnp_readdir_name(DIR *dir) +{ + dirent *ent; + for (;;) { + if ((ent = readdir(dir)) == NULL) { + return std::string(); + } + if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) { + break; + } + } + return std::string(ent->d_name); +#endif +} + +/* return the file modification time */ +int64_t +rnp_filemtime(const char *path) +{ + struct stat st; + + if (rnp_stat(path, &st) != 0) { + return 0; + } else { + return st.st_mtime; + } +} + +#ifdef _WIN32 +static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/** @private + * generate a temporary file name based on TMPL. + * + * @param tmpl filename template in UTF-8 ending in XXXXXX + * @return file descriptor of newly created and opened file, or -1 on error + **/ +int +rnp_mkstemp(char *tmpl) +{ + try { + int save_errno = errno; + const int mask_length = 6; + int len = strlen(tmpl); + if (len < mask_length || strcmp(&tmpl[len - mask_length], "XXXXXX")) { + errno = EINVAL; + return -1; + } + std::wstring tmpl_w = wstr_from_utf8(tmpl, tmpl + len - mask_length); + + /* This is where the Xs start. */ + char *XXXXXX = &tmpl[len - mask_length]; + + std::random_device rd; + std::mt19937_64 rng(rd()); + + for (unsigned int countdown = TMP_MAX; --countdown;) { + unsigned long long v = rng(); + + XXXXXX[0] = letters[v % 36]; + v /= 36; + XXXXXX[1] = letters[v % 36]; + v /= 36; + XXXXXX[2] = letters[v % 36]; + v /= 36; + XXXXXX[3] = letters[v % 36]; + v /= 36; + XXXXXX[4] = letters[v % 36]; + v /= 36; + XXXXXX[5] = letters[v % 36]; + + int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY; + int fd = + _wopen((tmpl_w + wstr_from_utf8(XXXXXX)).c_str(), flags, _S_IREAD | _S_IWRITE); + if (fd != -1) { + errno = save_errno; + return fd; + } else if (errno != EEXIST) + return -1; + } + + // We got out of the loop because we ran out of combinations to try. + errno = EEXIST; + return -1; + } + CATCH_AND_RETURN(-1) +} +#endif // _WIN32 + +namespace rnp { +namespace path { +inline char +separator() +{ +#ifdef _WIN32 + return '\\'; +#else + return '/'; +#endif +} + +bool +exists(const std::string &path, bool is_dir) +{ + return is_dir ? rnp_dir_exists(path.c_str()) : rnp_file_exists(path.c_str()); +} + +bool +empty(const std::string &path) +{ + auto dir = rnp_opendir(path.c_str()); + if (!dir) { + return true; + } + bool empty = rnp_readdir_name(dir).empty(); + rnp_closedir(dir); + return empty; +} + +std::string +HOME(const std::string &sdir) +{ + const char *home = getenv("HOME"); + if (!home) { + return ""; + } + return sdir.empty() ? home : append(home, sdir); +} + +static bool +has_forward_slash(const std::string &path) +{ + return std::find(path.begin(), path.end(), '/') != path.end(); +} + +std::string +append(const std::string &path, const std::string &name) +{ + bool no_sep = path.empty() || name.empty() || (rnp::is_slash(path.back())) || + (rnp::is_slash(name.front())); + if (no_sep) { + return path + name; + } + /* Use forward slash if there is at least one in the path/name. */ + char sep = has_forward_slash(path) || has_forward_slash(name) ? '/' : separator(); + return path + sep + name; +} + +} // namespace path +} // namespace rnp diff --git a/comm/third_party/rnp/src/common/file-utils.h b/comm/third_party/rnp/src/common/file-utils.h new file mode 100644 index 0000000000..1993d173f7 --- /dev/null +++ b/comm/third_party/rnp/src/common/file-utils.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_FILE_UTILS_H_ +#define RNP_FILE_UTILS_H_ + +#include +#include +#include +#include + +bool rnp_file_exists(const char *path); +bool rnp_dir_exists(const char *path); +int64_t rnp_filemtime(const char *path); +int rnp_open(const char *filename, int oflag, int pmode); +FILE * rnp_fopen(const char *filename, const char *mode); +FILE * rnp_fdopen(int fildes, const char *mode); +int rnp_access(const char *path, int mode); +int rnp_stat(const char *filename, struct stat *statbuf); +int rnp_rename(const char *oldpath, const char *newpath); +int rnp_unlink(const char *path); + +#ifdef _WIN32 +#define rnp_closedir _wclosedir +int rnp_mkdir(const char *path); +_WDIR * rnp_opendir(const char *path); +std::string rnp_readdir_name(_WDIR *dir); +#else +#define rnp_closedir closedir +DIR * rnp_opendir(const char *path); +std::string rnp_readdir_name(DIR *dir); +#endif +#ifdef _WIN32 +#define RNP_MKDIR(pathname, mode) rnp_mkdir(pathname) +#else +#define RNP_MKDIR(pathname, mode) mkdir(pathname, mode) +#endif + +#ifdef _MSC_VER +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +#define F_OK 0 /* Test for existence. */ +#endif + +/** @private + * generate a temporary file name based on TMPL. TMPL must match the + * rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed + * does not exist at the time of the call to mkstemp. TMPL is + * overwritten with the result.get the list item at specified index + * + * @param tmpl filename template + * @return file descriptor of newly created and opened file, or -1 on error + **/ +int rnp_mkstemp(char *tmpl); + +namespace rnp { +namespace path { +inline char separator(); +bool exists(const std::string &path, bool is_dir = false); +bool empty(const std::string &path); +std::string HOME(const std::string &sdir = ""); +std::string append(const std::string &path, const std::string &name); +} // namespace path +} // namespace rnp + +#endif diff --git a/comm/third_party/rnp/src/common/getoptwin.h b/comm/third_party/rnp/src/common/getoptwin.h new file mode 100644 index 0000000000..84a9583a5d --- /dev/null +++ b/comm/third_party/rnp/src/common/getoptwin.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _GETOPTWIN_H +#define _GETOPTWIN_H 1 + +#include + +#define _BEGIN_EXTERN_C extern "C" { +#define _END_EXTERN_C } + +#endif /* getoptwin.h */ \ No newline at end of file diff --git a/comm/third_party/rnp/src/common/str-utils.cpp b/comm/third_party/rnp/src/common/str-utils.cpp new file mode 100644 index 0000000000..245e31e1f3 --- /dev/null +++ b/comm/third_party/rnp/src/common/str-utils.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2017 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** String utilities + * @file + */ + +#include +#include +#include +#include +#include "str-utils.h" +#ifdef _WIN32 +#include +#include +#endif + +using std::size_t; +using std::strlen; + +namespace rnp { +char * +strip_eol(char *s) +{ + size_t len = strlen(s); + + while ((len > 0) && ((s[len - 1] == '\n') || (s[len - 1] == '\r'))) { + s[--len] = '\0'; + } + + return s; +} + +bool +strip_eol(std::string &s) +{ + size_t len = s.size(); + while (len && ((s[len - 1] == '\n') || (s[len - 1] == '\r'))) { + len--; + } + if (len == s.size()) { + return false; + } + s.resize(len); + return true; +} + +bool +is_blank_line(const char *line, size_t len) +{ + for (size_t i = 0; i < len && line[i]; i++) { + if (line[i] != ' ' && line[i] != '\t' && line[i] != '\r') { + return false; + } + } + return true; +} + +bool +str_case_eq(const char *s1, const char *s2) +{ + while (*s1 && *s2) { + if (std::tolower(*s1) != std::tolower(*s2)) { + return false; + } + s1++; + s2++; + } + return !*s1 && !*s2; +} + +bool +str_case_eq(const std::string &s1, const std::string &s2) +{ + if (s1.size() != s2.size()) { + return false; + } + return str_case_eq(s1.c_str(), s2.c_str()); +} + +static size_t +hex_prefix_len(const std::string &str) +{ + if ((str.length() >= 2) && (str[0] == '0') && ((str[1] == 'x') || (str[1] == 'X'))) { + return 2; + } + return 0; +} + +bool +is_hex(const std::string &s) +{ + for (size_t i = hex_prefix_len(s); i < s.length(); i++) { + auto &ch = s[i]; + if ((ch >= '0') && (ch <= '9')) { + continue; + } + if ((ch >= 'a') && (ch <= 'f')) { + continue; + } + if ((ch >= 'A') && (ch <= 'F')) { + continue; + } + if ((ch == ' ') || (ch == '\t')) { + continue; + } + return false; + } + return true; +} + +std::string +strip_hex(const std::string &s) +{ + std::string res = ""; + for (size_t idx = hex_prefix_len(s); idx < s.length(); idx++) { + auto ch = s[idx]; + if ((ch == ' ') || (ch == '\t')) { + continue; + } + res.push_back(ch); + } + return res; +} + +char * +lowercase(char *s) +{ + if (!s) { + return s; + } + for (char *ptr = s; *ptr; ++ptr) { + *ptr = tolower(*ptr); + } + return s; +} + +bool +str_to_int(const std::string &s, int &val) +{ + for (const char &ch : s) { + if ((ch < '0') || (ch > '9')) { + return false; + } + } + try { + val = std::stoi(s); + } catch (std::out_of_range const &ex) { + return false; + } + return true; +} + +bool +is_slash(char c) +{ + return (c == '/') || (c == '\\'); +} + +} // namespace rnp + +#ifdef _WIN32 +std::wstring +wstr_from_utf8(const char *s) +{ + std::wstring_convert> utf8conv; + return utf8conv.from_bytes(s); +} + +std::wstring +wstr_from_utf8(const char *first, const char *last) +{ + std::wstring_convert> utf8conv; + return utf8conv.from_bytes(first, last); +} + +std::wstring +wstr_from_utf8(const std::string &s) +{ + return wstr_from_utf8(s.c_str()); +} + +std::string +wstr_to_utf8(const wchar_t *ws) +{ + std::wstring_convert> utf8conv; + return utf8conv.to_bytes(ws); +} + +std::string +wstr_to_utf8(const std::wstring &ws) +{ + return wstr_to_utf8(ws.c_str()); +} +#endif diff --git a/comm/third_party/rnp/src/common/str-utils.h b/comm/third_party/rnp/src/common/str-utils.h new file mode 100644 index 0000000000..9a4eb734a2 --- /dev/null +++ b/comm/third_party/rnp/src/common/str-utils.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019-2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_STR_UTILS_H_ +#define RNP_STR_UTILS_H_ + +#include + +namespace rnp { +char *strip_eol(char *s); +/** + * @brief Strip EOL characters from the string's end. + * + * @param s string to check + * @return true if EOL was found and stripped, or false otherwise. + */ +bool strip_eol(std::string &s); +bool is_blank_line(const char *line, size_t len); +bool str_case_eq(const char *s1, const char *s2); +bool str_case_eq(const std::string &s1, const std::string &s2); + +bool is_hex(const std::string &s); +std::string strip_hex(const std::string &s); + +/** + * @brief Convert string to lowercase and return it. + */ +char *lowercase(char *s); +bool str_to_int(const std::string &s, int &val); +bool is_slash(char c); +} // namespace rnp +#ifdef _WIN32 +#include +std::wstring wstr_from_utf8(const char *s); +std::wstring wstr_from_utf8(const char *first, const char *last); +std::wstring wstr_from_utf8(const std::string &s); +std::string wstr_to_utf8(const wchar_t *ws); +std::string wstr_to_utf8(const std::wstring &ws); +#endif // _WIN32 +#endif diff --git a/comm/third_party/rnp/src/common/time-utils.cpp b/comm/third_party/rnp/src/common/time-utils.cpp new file mode 100644 index 0000000000..83d934aff1 --- /dev/null +++ b/comm/third_party/rnp/src/common/time-utils.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** Time utilities + * @file + */ + +#include +#include "time-utils.h" + +static inline time_t +adjust_time32(time_t t) +{ + return (sizeof(t) == 4 && t < 0) ? INT32_MAX : t; +} + +bool +rnp_y2k38_warning(time_t t) +{ + return (sizeof(t) == 4 && (t < 0 || t == INT32_MAX)); +} + +time_t +rnp_mktime(struct tm *tm) +{ + return adjust_time32(mktime(tm)); +} + +void +rnp_gmtime(time_t t, struct tm &tm) +{ + time_t adjusted = adjust_time32(t); +#ifndef _WIN32 + gmtime_r(&adjusted, &tm); +#else + (void) gmtime_s(&tm, &adjusted); +#endif +} + +void +rnp_localtime(time_t t, struct tm &tm) +{ + time_t adjusted = adjust_time32(t); +#ifndef _WIN32 + localtime_r(&adjusted, &tm); +#else + (void) localtime_s(&tm, &adjusted); +#endif +} + +std::string +rnp_ctime(time_t t) +{ + char time_buf[26]; + time_t adjusted = adjust_time32(t); +#ifndef _WIN32 + (void) ctime_r(&adjusted, time_buf); +#else + (void) ctime_s(time_buf, sizeof(time_buf), &adjusted); +#endif + return std::string(time_buf); +} + +time_t +rnp_timeadd(time_t t1, time_t t2) +{ + if (sizeof(time_t) == 4) { + if (t1 < 0 || t2 < 0) { + return INT32_MAX; + } + return adjust_time32(t1 + t2); + } + return t1 + t2; +} diff --git a/comm/third_party/rnp/src/common/time-utils.h b/comm/third_party/rnp/src/common/time-utils.h new file mode 100644 index 0000000000..525309e740 --- /dev/null +++ b/comm/third_party/rnp/src/common/time-utils.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_TIME_UTILS_H_ +#define RNP_TIME_UTILS_H_ + +#include +#include +time_t rnp_mktime(struct tm *tm); +void rnp_gmtime(time_t t, struct tm &tm); +void rnp_localtime(time_t t, struct tm &tm); +bool rnp_y2k38_warning(time_t t); +std::string rnp_ctime(time_t t); +time_t rnp_timeadd(time_t t1, time_t t2); +#endif diff --git a/comm/third_party/rnp/src/common/uniwin.h b/comm/third_party/rnp/src/common/uniwin.h new file mode 100644 index 0000000000..095c325bcb --- /dev/null +++ b/comm/third_party/rnp/src/common/uniwin.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#if !defined(_UNISTD_H) && defined(_MSC_VER) +#define _UNISTD_H 1 + +/* Taken partially from + * https://stackoverflow.com/a/826027/1202830 + */ + +#include +#include "getoptwin.h" +#include /* for _getcwd() and _chdir() */ + +#ifdef _WIN64 +#define ssize_t __int64 +#else +#define ssize_t long +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define NOMINMAX 1 /* to retain std::min and std::max */ +#include +#include /* for S_ISREG and S_ISDIR */ + +#define strncasecmp strnicmp +#define strcasecmp stricmp + +#ifndef MAXPATHLEN +#define MAXPATHLEN _MAX_PATH +#endif + +typedef unsigned short mode_t; + +#endif \ No newline at end of file diff --git a/comm/third_party/rnp/src/examples/CMakeLists.txt b/comm/third_party/rnp/src/examples/CMakeLists.txt new file mode 100644 index 0000000000..8cf1e72b25 --- /dev/null +++ b/comm/third_party/rnp/src/examples/CMakeLists.txt @@ -0,0 +1,140 @@ +# Copyright (c) 2018-2020 Ribose Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +if(MSVC) + # remove extra ${Configuration} subfolder + set(ArchiveOutputDir ${CMAKE_BINARY_DIR}\\src\\examples) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${ArchiveOutputDir}) + + set(RuntimeOutputDir ${CMAKE_BINARY_DIR}\\src\\examples) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${RuntimeOutputDir}) + + find_path(GETOPT_INCLUDE_DIR + NAMES getopt.h + ) + find_library(GETOPT_LIBRARY + NAMES getopt + ) +endif() + +add_executable(generate generate.c) + +target_include_directories(generate + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(generate + PRIVATE + librnp +) + +add_executable(encrypt encrypt.c) + +target_include_directories(encrypt + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(encrypt + PRIVATE + librnp +) + +add_executable(decrypt decrypt.c) + +target_include_directories(decrypt + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(decrypt + PRIVATE + librnp +) + +add_executable(sign sign.c) + +target_include_directories(sign + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(sign + PRIVATE + librnp +) + +add_executable(verify verify.c) + +target_include_directories(verify + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(verify + PRIVATE + librnp +) + +add_executable(dump dump.c) + +target_include_directories(dump + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(dump + PRIVATE + librnp +) + +if(MSVC) + target_include_directories(dump + PRIVATE + "${GETOPT_INCLUDE_DIR}" + ) + target_link_libraries(dump + PRIVATE + "${GETOPT_LIBRARY}" + ) +endif() + +if (ENABLE_SANITIZERS) + foreach(tgt generate encrypt decrypt sign verify dump) + set_target_properties(${tgt} PROPERTIES LINKER_LANGUAGE CXX) + endforeach() +endif() diff --git a/comm/third_party/rnp/src/examples/README.md b/comm/third_party/rnp/src/examples/README.md new file mode 100644 index 0000000000..84bdc2ec7b --- /dev/null +++ b/comm/third_party/rnp/src/examples/README.md @@ -0,0 +1,5 @@ +# RNP C API usage samples + +This folder includes examples of RNP library usage for developers. + +See [Using the RNP C API](/docs/c-usage.adoc) for more details. diff --git a/comm/third_party/rnp/src/examples/decrypt.c b/comm/third_party/rnp/src/examples/decrypt.c new file mode 100644 index 0000000000..5454a4b728 --- /dev/null +++ b/comm/third_party/rnp/src/examples/decrypt.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#define RNP_SUCCESS 0 + +/* sample pass provider implementation, which always return 'password' for key decryption and + * 'encpassword' when password is needed for file decryption. You may ask for password via + * stdin, or choose password based on key properties, whatever else */ +static bool +example_pass_provider(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + if (!strcmp(pgp_context, "decrypt (symmetric)")) { + strncpy(buf, "encpassword", buf_len); + return true; + } + if (!strcmp(pgp_context, "decrypt")) { + strncpy(buf, "password", buf_len); + return true; + } + + return false; +} + +static int +ffi_decrypt(bool usekeys) +{ + rnp_ffi_t ffi = NULL; + rnp_input_t keyfile = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + uint8_t * buf = NULL; + size_t buf_len = 0; + int result = 1; + + /* initialize FFI object */ + if (rnp_ffi_create(&ffi, "GPG", "GPG") != RNP_SUCCESS) { + return result; + } + + /* check whether we want to use key or password for decryption */ + if (usekeys) { + /* load secret keyring, as it is required for public-key decryption. However, you may + * need to load public keyring as well to validate key's signatures. */ + if (rnp_input_from_path(&keyfile, "secring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to open secring.pgp. Did you run ./generate sample?\n"); + goto finish; + } + + /* we may use RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_PUBLIC_KEYS as well*/ + if (rnp_load_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_SECRET_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to read secring.pgp\n"); + goto finish; + } + rnp_input_destroy(keyfile); + keyfile = NULL; + } + + /* set the password provider */ + rnp_ffi_set_pass_provider(ffi, example_pass_provider, NULL); + + /* create file input and memory output objects for the encrypted message and decrypted + * message */ + if (rnp_input_from_path(&input, "encrypted.asc") != RNP_SUCCESS) { + fprintf(stdout, "failed to create input object\n"); + goto finish; + } + + if (rnp_output_to_memory(&output, 0) != RNP_SUCCESS) { + fprintf(stdout, "failed to create output object\n"); + goto finish; + } + + if (rnp_decrypt(ffi, input, output) != RNP_SUCCESS) { + fprintf(stdout, "public-key decryption failed\n"); + goto finish; + } + + /* get the decrypted message from the output structure */ + if (rnp_output_memory_get_buf(output, &buf, &buf_len, false) != RNP_SUCCESS) { + goto finish; + } + fprintf(stdout, + "Decrypted message (%s):\n%.*s\n", + usekeys ? "with key" : "with password", + (int) buf_len, + buf); + + result = 0; +finish: + rnp_input_destroy(keyfile); + rnp_input_destroy(input); + rnp_output_destroy(output); + rnp_ffi_destroy(ffi); + return result; +} + +int +main(int argc, char **argv) +{ + int res; + res = ffi_decrypt(true); + if (res) { + return res; + } + res = ffi_decrypt(false); + return res; +} \ No newline at end of file diff --git a/comm/third_party/rnp/src/examples/dump.c b/comm/third_party/rnp/src/examples/dump.c new file mode 100644 index 0000000000..dc24644774 --- /dev/null +++ b/comm/third_party/rnp/src/examples/dump.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifdef _MSC_VER +#include "uniwin.h" +#else +#include /* getopt() */ +#include /* basename() */ +#endif +#include + +#define PFX "dump: " + +static void +print_usage(char *program_name) +{ + const char *program_basename; +#ifdef _MSC_VER + char fname[_MAX_FNAME]; + program_basename = fname; + _splitpath_s(program_name, NULL, 0, NULL, 0, fname, _MAX_FNAME, NULL, 0); +#else + program_basename = basename(program_name); +#endif + + fprintf(stderr, + "dump: " PFX "Program dumps PGP packets. \n\nUsage:\n" + "\t%s [-d|-h] [input.pgp]\n" + "\t -d : indicates whether to print packet content. Data is represented as hex\n" + "\t -m : dump mpi values\n" + "\t -g : dump key fingerprints and grips\n" + "\t -j : JSON output\n" + "\t -h : prints help and exists\n", + program_basename); +} + +static bool +stdin_reader(void *app_ctx, void *buf, size_t len, size_t *readres) +{ + ssize_t res = read(STDIN_FILENO, buf, len); + if (res < 0) { + return false; + } + *readres = res; + return true; +} + +static bool +stdout_writer(void *app_ctx, const void *buf, size_t len) +{ + ssize_t wlen = write(STDOUT_FILENO, buf, len); + return (wlen >= 0) && (size_t) wlen == len; +} + +int +main(int argc, char *const argv[]) +{ + char * input_file = NULL; + uint32_t flags = 0; + uint32_t jflags = 0; + bool json = false; + + /* Parse command line options: + -i input_file [mandatory]: specifies name of the file with PGP packets + -d : indicates whether to dump whole packet content + -m : dump mpi contents + -g : dump key grips and fingerprints + -j : JSON output + -h : prints help and exists + */ + int opt = 0; + while ((opt = getopt(argc, argv, "dmgjh")) != -1) { + switch (opt) { + case 'd': + flags |= RNP_DUMP_RAW; + jflags |= RNP_JSON_DUMP_RAW; + break; + case 'm': + flags |= RNP_DUMP_MPI; + jflags |= RNP_JSON_DUMP_MPI; + break; + case 'g': + flags |= RNP_DUMP_GRIP; + jflags |= RNP_JSON_DUMP_GRIP; + break; + case 'j': + json = true; + break; + default: + print_usage(argv[0]); + return 1; + } + } + + /* Check whether we have input file */ + if (optind < argc) { + input_file = argv[optind]; + } + + rnp_input_t input = NULL; + rnp_result_t ret = 0; + if (input_file) { + ret = rnp_input_from_path(&input, input_file); + } else { + ret = rnp_input_from_callback(&input, stdin_reader, NULL, NULL); + } + if (ret) { + fprintf(stderr, "failed to open source: error 0x%x\n", (int) ret); + return 1; + } + + if (!json) { + rnp_output_t output = NULL; + ret = rnp_output_to_callback(&output, stdout_writer, NULL, NULL); + if (ret) { + fprintf(stderr, "failed to open stdout: error 0x%x\n", (int) ret); + rnp_input_destroy(input); + return 1; + } + ret = rnp_dump_packets_to_output(input, output, flags); + rnp_output_destroy(output); + } else { + char *json = NULL; + ret = rnp_dump_packets_to_json(input, jflags, &json); + if (!ret) { + fprintf(stdout, "%s\n", json); + } + rnp_buffer_destroy(json); + } + rnp_input_destroy(input); + + /* Inform in case of error occurred during parsing */ + if (ret) { + fprintf(stderr, "Operation failed [error code: 0x%X]\n", (int) ret); + return 1; + } + + return 0; +} diff --git a/comm/third_party/rnp/src/examples/encrypt.c b/comm/third_party/rnp/src/examples/encrypt.c new file mode 100644 index 0000000000..0b07fd40fc --- /dev/null +++ b/comm/third_party/rnp/src/examples/encrypt.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#define RNP_SUCCESS 0 + +static int +ffi_encrypt() +{ + rnp_ffi_t ffi = NULL; + rnp_op_encrypt_t encrypt = NULL; + rnp_key_handle_t key = NULL; + rnp_input_t keyfile = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + const char * message = "RNP encryption sample message"; + int result = 1; + + /* initialize FFI object */ + if (rnp_ffi_create(&ffi, "GPG", "GPG") != RNP_SUCCESS) { + return result; + } + + /* load public keyring - we do not need secret for encryption */ + if (rnp_input_from_path(&keyfile, "pubring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to open pubring.pgp. Did you run ./generate sample?\n"); + goto finish; + } + + /* we may use RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_PUBLIC_KEYS as well */ + if (rnp_load_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_PUBLIC_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to read pubring.pgp\n"); + goto finish; + } + rnp_input_destroy(keyfile); + keyfile = NULL; + + /* create memory input and file output objects for the message and encrypted message */ + if (rnp_input_from_memory(&input, (uint8_t *) message, strlen(message), false) != + RNP_SUCCESS) { + fprintf(stdout, "failed to create input object\n"); + goto finish; + } + + if (rnp_output_to_path(&output, "encrypted.asc") != RNP_SUCCESS) { + fprintf(stdout, "failed to create output object\n"); + goto finish; + } + + /* create encryption operation */ + if (rnp_op_encrypt_create(&encrypt, ffi, input, output) != RNP_SUCCESS) { + fprintf(stdout, "failed to create encrypt operation\n"); + goto finish; + } + + /* setup encryption parameters */ + rnp_op_encrypt_set_armor(encrypt, true); + rnp_op_encrypt_set_file_name(encrypt, "message.txt"); + rnp_op_encrypt_set_file_mtime(encrypt, (uint32_t) time(NULL)); + rnp_op_encrypt_set_compression(encrypt, "ZIP", 6); + rnp_op_encrypt_set_cipher(encrypt, RNP_ALGNAME_AES_256); + rnp_op_encrypt_set_aead(encrypt, "None"); + + /* locate recipient's key and add it to the operation context. While we search by userid + * (which is easier), you can search by keyid, fingerprint or grip. */ + if (rnp_locate_key(ffi, "userid", "rsa@key", &key) != RNP_SUCCESS) { + fprintf(stdout, "failed to locate recipient key rsa@key.\n"); + goto finish; + } + + if (rnp_op_encrypt_add_recipient(encrypt, key) != RNP_SUCCESS) { + fprintf(stdout, "failed to add recipient\n"); + goto finish; + } + rnp_key_handle_destroy(key); + key = NULL; + + /* add encryption password as well */ + if (rnp_op_encrypt_add_password( + encrypt, "encpassword", RNP_ALGNAME_SHA256, 0, RNP_ALGNAME_AES_256) != RNP_SUCCESS) { + fprintf(stdout, "failed to add encryption password\n"); + goto finish; + } + + /* execute encryption operation */ + if (rnp_op_encrypt_execute(encrypt) != RNP_SUCCESS) { + fprintf(stdout, "encryption failed\n"); + goto finish; + } + + fprintf(stdout, "Encryption succeeded. Encrypted message written to file encrypted.asc\n"); + result = 0; +finish: + rnp_op_encrypt_destroy(encrypt); + rnp_input_destroy(keyfile); + rnp_input_destroy(input); + rnp_output_destroy(output); + rnp_key_handle_destroy(key); + rnp_ffi_destroy(ffi); + return result; +} + +int +main(int argc, char **argv) +{ + return ffi_encrypt(); +} diff --git a/comm/third_party/rnp/src/examples/generate.c b/comm/third_party/rnp/src/examples/generate.c new file mode 100644 index 0000000000..979e63e878 --- /dev/null +++ b/comm/third_party/rnp/src/examples/generate.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#define RNP_SUCCESS 0 + +/* RSA key JSON description. 31536000 = 1 year expiration, 15768000 = half year */ +const char *RSA_KEY_DESC = "{\ + 'primary': {\ + 'type': 'RSA',\ + 'length': 2048,\ + 'userid': 'rsa@key',\ + 'expiration': 31536000,\ + 'usage': ['sign'],\ + 'protection': {\ + 'cipher': 'AES256',\ + 'hash': 'SHA256'\ + }\ + },\ + 'sub': {\ + 'type': 'RSA',\ + 'length': 2048,\ + 'expiration': 15768000,\ + 'usage': ['encrypt'],\ + 'protection': {\ + 'cipher': 'AES256',\ + 'hash': 'SHA256'\ + }\ + }\ +}"; + +const char *CURVE_25519_KEY_DESC = "{\ + 'primary': {\ + 'type': 'EDDSA',\ + 'userid': '25519@key',\ + 'expiration': 0,\ + 'usage': ['sign'],\ + 'protection': {\ + 'cipher': 'AES256',\ + 'hash': 'SHA256'\ + }\ + },\ + 'sub': {\ + 'type': 'ECDH',\ + 'curve': 'Curve25519',\ + 'expiration': 15768000,\ + 'usage': ['encrypt'],\ + 'protection': {\ + 'cipher': 'AES256',\ + 'hash': 'SHA256'\ + }\ + }\ +}"; + +/* basic pass provider implementation, which always return 'password' for key protection. +You may ask for password via stdin, or choose password based on key properties, whatever else +*/ +static bool +example_pass_provider(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + if (strcmp(pgp_context, "protect")) { + return false; + } + + strncpy(buf, "password", buf_len); + return true; +} + +/* this simple helper function just prints armored key, searched by userid, to stdout */ +static bool +ffi_print_key(rnp_ffi_t ffi, const char *uid, bool secret) +{ + rnp_output_t keydata = NULL; + rnp_key_handle_t key = NULL; + uint32_t flags = RNP_KEY_EXPORT_ARMORED | RNP_KEY_EXPORT_SUBKEYS; + uint8_t * buf = NULL; + size_t buf_len = 0; + bool result = false; + + /* you may search for the key via userid, keyid, fingerprint, grip */ + if (rnp_locate_key(ffi, "userid", uid, &key) != RNP_SUCCESS) { + return false; + } + + if (!key) { + return false; + } + + /* create in-memory output structure to later use buffer */ + if (rnp_output_to_memory(&keydata, 0) != RNP_SUCCESS) { + goto finish; + } + + flags = flags | (secret ? RNP_KEY_EXPORT_SECRET : RNP_KEY_EXPORT_PUBLIC); + if (rnp_key_export(key, keydata, flags) != RNP_SUCCESS) { + goto finish; + } + + /* get key's contents from the output structure */ + if (rnp_output_memory_get_buf(keydata, &buf, &buf_len, false) != RNP_SUCCESS) { + goto finish; + } + fprintf(stdout, "%.*s", (int) buf_len, buf); + + result = true; +finish: + rnp_key_handle_destroy(key); + rnp_output_destroy(keydata); + return result; +} + +static bool +ffi_export_key(rnp_ffi_t ffi, const char *uid, bool secret) +{ + rnp_output_t keyfile = NULL; + rnp_key_handle_t key = NULL; + uint32_t flags = RNP_KEY_EXPORT_ARMORED | RNP_KEY_EXPORT_SUBKEYS; + char filename[32] = {0}; + char * keyid = NULL; + bool result = false; + + /* you may search for the key via userid, keyid, fingerprint, grip */ + if (rnp_locate_key(ffi, "userid", uid, &key) != RNP_SUCCESS) { + return false; + } + + if (!key) { + return false; + } + + /* get key's id and build filename */ + if (rnp_key_get_keyid(key, &keyid) != RNP_SUCCESS) { + goto finish; + } + snprintf(filename, sizeof(filename), "key-%s-%s.asc", keyid, secret ? "sec" : "pub"); + rnp_buffer_destroy(keyid); + + /* create file output structure */ + if (rnp_output_to_path(&keyfile, filename) != RNP_SUCCESS) { + goto finish; + } + + flags = flags | (secret ? RNP_KEY_EXPORT_SECRET : RNP_KEY_EXPORT_PUBLIC); + if (rnp_key_export(key, keyfile, flags) != RNP_SUCCESS) { + goto finish; + } + + result = true; +finish: + rnp_key_handle_destroy(key); + rnp_output_destroy(keyfile); + return result; +} + +/* this example function generates RSA/RSA and Eddsa/X25519 keypairs */ +static int +ffi_generate_keys() +{ + rnp_ffi_t ffi = NULL; + rnp_output_t keyfile = NULL; + char * key_grips = NULL; + int result = 1; + + /* initialize FFI object */ + if (rnp_ffi_create(&ffi, "GPG", "GPG") != RNP_SUCCESS) { + return result; + } + + /* set password provider */ + if (rnp_ffi_set_pass_provider(ffi, example_pass_provider, NULL)) { + goto finish; + } + + /* generate EDDSA/X25519 keypair */ + if (rnp_generate_key_json(ffi, CURVE_25519_KEY_DESC, &key_grips) != RNP_SUCCESS) { + fprintf(stdout, "failed to generate eddsa key\n"); + goto finish; + } + + fprintf(stdout, "Generated 25519 key/subkey:\n%s\n", key_grips); + /* destroying key_grips buffer is our obligation */ + rnp_buffer_destroy(key_grips); + key_grips = NULL; + + /* generate RSA keypair */ + if (rnp_generate_key_json(ffi, RSA_KEY_DESC, &key_grips) != RNP_SUCCESS) { + fprintf(stdout, "failed to generate rsa key\n"); + goto finish; + } + + fprintf(stdout, "Generated RSA key/subkey:\n%s\n", key_grips); + rnp_buffer_destroy(key_grips); + key_grips = NULL; + + /* create file output object and save public keyring with generated keys, overwriting + * previous file if any. You may use rnp_output_to_memory() here as well. */ + if (rnp_output_to_path(&keyfile, "pubring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to initialize pubring.pgp writing\n"); + goto finish; + } + + if (rnp_save_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_PUBLIC_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to save pubring\n"); + goto finish; + } + + rnp_output_destroy(keyfile); + keyfile = NULL; + + /* create file output object and save secret keyring with generated keys */ + if (rnp_output_to_path(&keyfile, "secring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to initialize secring.pgp writing\n"); + goto finish; + } + + if (rnp_save_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_SECRET_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to save secring\n"); + goto finish; + } + + rnp_output_destroy(keyfile); + keyfile = NULL; + + result = 0; +finish: + rnp_buffer_destroy(key_grips); + rnp_output_destroy(keyfile); + rnp_ffi_destroy(ffi); + return result; +} + +static int +ffi_output_keys() +{ + rnp_ffi_t ffi = NULL; + rnp_input_t keyfile = NULL; + int result = 2; + + /* initialize FFI object */ + if (rnp_ffi_create(&ffi, "GPG", "GPG") != RNP_SUCCESS) { + return result; + } + + /* load keyrings */ + if (rnp_input_from_path(&keyfile, "pubring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to open pubring.pgp\n"); + goto finish; + } + + /* actually, we may use 0 instead of RNP_LOAD_SAVE_PUBLIC_KEYS, to not check key types */ + if (rnp_load_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_PUBLIC_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to read pubring.pgp\n"); + goto finish; + } + rnp_input_destroy(keyfile); + keyfile = NULL; + + if (rnp_input_from_path(&keyfile, "secring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to open secring.pgp\n"); + goto finish; + } + + if (rnp_load_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_SECRET_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to read secring.pgp\n"); + goto finish; + } + rnp_input_destroy(keyfile); + keyfile = NULL; + + /* print armored keys to the stdout */ + if (!ffi_print_key(ffi, "rsa@key", false) || !ffi_print_key(ffi, "rsa@key", true) || + !ffi_print_key(ffi, "25519@key", false) || !ffi_print_key(ffi, "25519@key", true)) { + fprintf(stdout, "failed to print armored key(s)\n"); + goto finish; + } + + /* write armored keys to the files, named key--pub.asc/named key--sec.asc */ + if (!ffi_export_key(ffi, "rsa@key", false) || !ffi_export_key(ffi, "rsa@key", true) || + !ffi_export_key(ffi, "25519@key", false) || !ffi_export_key(ffi, "25519@key", true)) { + fprintf(stdout, "failed to write armored key(s) to file\n"); + goto finish; + } + + result = 0; +finish: + rnp_input_destroy(keyfile); + rnp_ffi_destroy(ffi); + return result; +} + +int +main(int argc, char **argv) +{ + int res = ffi_generate_keys(); + if (res) { + return res; + } + res = ffi_output_keys(); + return res; +} diff --git a/comm/third_party/rnp/src/examples/sign.c b/comm/third_party/rnp/src/examples/sign.c new file mode 100644 index 0000000000..678dd910e0 --- /dev/null +++ b/comm/third_party/rnp/src/examples/sign.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#define RNP_SUCCESS 0 + +/* sample pass provider implementation, which always return 'password' */ +static bool +example_pass_provider(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + strncpy(buf, "password", buf_len); + return true; +} + +static int +ffi_sign() +{ + rnp_ffi_t ffi = NULL; + rnp_input_t keyfile = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + rnp_op_sign_t sign = NULL; + rnp_key_handle_t key = NULL; + const char * message = "RNP signing sample message"; + int result = 1; + + /* initialize FFI object */ + if (rnp_ffi_create(&ffi, "GPG", "GPG") != RNP_SUCCESS) { + return result; + } + + /* load secret keyring, as it is required for signing. However, you may need to load public + * keyring as well to validate key's signatures. */ + if (rnp_input_from_path(&keyfile, "secring.pgp") != RNP_SUCCESS) { + fprintf(stdout, "failed to open secring.pgp. Did you run ./generate sample?\n"); + goto finish; + } + + /* we may use RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_PUBLIC_KEYS as well */ + if (rnp_load_keys(ffi, "GPG", keyfile, RNP_LOAD_SAVE_SECRET_KEYS) != RNP_SUCCESS) { + fprintf(stdout, "failed to read secring.pgp\n"); + goto finish; + } + rnp_input_destroy(keyfile); + keyfile = NULL; + + /* set the password provider - we'll need password to unlock secret keys */ + rnp_ffi_set_pass_provider(ffi, example_pass_provider, NULL); + + /* create file input and memory output objects for the encrypted message and decrypted + * message */ + if (rnp_input_from_memory(&input, (uint8_t *) message, strlen(message), false) != + RNP_SUCCESS) { + fprintf(stdout, "failed to create input object\n"); + goto finish; + } + + if (rnp_output_to_path(&output, "signed.asc") != RNP_SUCCESS) { + fprintf(stdout, "failed to create output object\n"); + goto finish; + } + + /* initialize and configure sign operation, use + * rnp_op_sign_create_cleartext/rnp_op_sign_create_detached for cleartext or detached + * signature. */ + if (rnp_op_sign_create(&sign, ffi, input, output) != RNP_SUCCESS) { + fprintf(stdout, "failed to create sign operation\n"); + goto finish; + } + + /* armor, file name, compression */ + rnp_op_sign_set_armor(sign, true); + rnp_op_sign_set_file_name(sign, "message.txt"); + rnp_op_sign_set_file_mtime(sign, (uint32_t) time(NULL)); + rnp_op_sign_set_compression(sign, "ZIP", 6); + /* signatures creation time - by default will be set to the current time as well */ + rnp_op_sign_set_creation_time(sign, (uint32_t) time(NULL)); + /* signatures expiration time - by default will be 0, i.e. never expire */ + rnp_op_sign_set_expiration_time(sign, 365 * 24 * 60 * 60); + /* set hash algorithm - should be compatible for all signatures */ + rnp_op_sign_set_hash(sign, RNP_ALGNAME_SHA256); + + /* now add signatures. First locate the signing key, then add and setup signature */ + /* RSA signature */ + if (rnp_locate_key(ffi, "userid", "rsa@key", &key) != RNP_SUCCESS) { + fprintf(stdout, "failed to locate signing key rsa@key.\n"); + goto finish; + } + + /* we do not need pointer to the signature so passing NULL as the last parameter */ + if (rnp_op_sign_add_signature(sign, key, NULL) != RNP_SUCCESS) { + fprintf(stdout, "failed to add signature for key rsa@key.\n"); + goto finish; + } + + /* do not forget to destroy key handle */ + rnp_key_handle_destroy(key); + key = NULL; + + /* EdDSA signature */ + if (rnp_locate_key(ffi, "userid", "25519@key", &key) != RNP_SUCCESS) { + fprintf(stdout, "failed to locate signing key 25519@key.\n"); + goto finish; + } + + if (rnp_op_sign_add_signature(sign, key, NULL) != RNP_SUCCESS) { + fprintf(stdout, "failed to add signature for key 25519@key.\n"); + goto finish; + } + + rnp_key_handle_destroy(key); + key = NULL; + + /* finally do signing */ + if (rnp_op_sign_execute(sign) != RNP_SUCCESS) { + fprintf(stdout, "failed to sign\n"); + goto finish; + } + + fprintf(stdout, "Signing succeeded. See file signed.asc.\n"); + + result = 0; +finish: + rnp_input_destroy(keyfile); + rnp_key_handle_destroy(key); + rnp_op_sign_destroy(sign); + rnp_input_destroy(input); + rnp_output_destroy(output); + rnp_ffi_destroy(ffi); + return result; +} + +int +main(int argc, char **argv) +{ + return ffi_sign(); +} diff --git a/comm/third_party/rnp/src/examples/verify.c b/comm/third_party/rnp/src/examples/verify.c new file mode 100644 index 0000000000..17f42a82c7 --- /dev/null +++ b/comm/third_party/rnp/src/examples/verify.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#define RNP_SUCCESS 0 + +/* example key provider which loads key from file based on its keyid */ +static void +example_key_provider(rnp_ffi_t ffi, + void * app_ctx, + const char *identifier_type, + const char *identifier, + bool secret) +{ + rnp_input_t input = NULL; + char filename[32] = {0}; + if (strcmp(identifier_type, "keyid")) { + if (strcmp(identifier_type, "fingerprint")) { + fprintf(stdout, "Unsupported key search: %s = %s\n", identifier_type, identifier); + return; + } + /* if we search by fp then keyid is last 16 chars */ + if (strlen(identifier) < 40) { + fprintf(stdout, "Invalid fingerprint: %s\n", identifier); + return; + } + identifier += 24; + } + + snprintf(filename, sizeof(filename), "key-%s-%s.asc", identifier, secret ? "sec" : "pub"); + + if (rnp_input_from_path(&input, filename) != RNP_SUCCESS) { + fprintf(stdout, "failed to open key file %s\n", filename); + return; + } + + if (rnp_load_keys( + ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_PUBLIC_KEYS) != + RNP_SUCCESS) { + fprintf(stdout, "failed to load key from file %s\n", filename); + } + rnp_input_destroy(input); +} + +static int +ffi_verify() +{ + rnp_ffi_t ffi = NULL; + rnp_op_verify_t verify = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + uint8_t * buf = NULL; + size_t buf_len = 0; + size_t sigcount = 0; + int result = 1; + + /* initialize FFI object */ + if (rnp_ffi_create(&ffi, "GPG", "GPG") != RNP_SUCCESS) { + return result; + } + + /* we do not load any keys here since we'll use key provider */ + rnp_ffi_set_key_provider(ffi, example_key_provider, NULL); + + /* create file input and memory output objects for the signed message and verified + * message */ + if (rnp_input_from_path(&input, "signed.asc") != RNP_SUCCESS) { + fprintf(stdout, "failed to open file 'signed.asc'. Did you run the sign example?\n"); + goto finish; + } + + if (rnp_output_to_memory(&output, 0) != RNP_SUCCESS) { + fprintf(stdout, "failed to create output object\n"); + goto finish; + } + + if (rnp_op_verify_create(&verify, ffi, input, output) != RNP_SUCCESS) { + fprintf(stdout, "failed to create verification context\n"); + goto finish; + } + + if (rnp_op_verify_execute(verify) != RNP_SUCCESS) { + fprintf(stdout, "failed to execute verification operation\n"); + goto finish; + } + + /* now check signatures and get some info about them */ + if (rnp_op_verify_get_signature_count(verify, &sigcount) != RNP_SUCCESS) { + fprintf(stdout, "failed to get signature count\n"); + goto finish; + } + + for (size_t i = 0; i < sigcount; i++) { + rnp_op_verify_signature_t sig = NULL; + rnp_result_t sigstatus = RNP_SUCCESS; + rnp_key_handle_t key = NULL; + char * keyid = NULL; + + if (rnp_op_verify_get_signature_at(verify, i, &sig) != RNP_SUCCESS) { + fprintf(stdout, "failed to get signature %d\n", (int) i); + goto finish; + } + + if (rnp_op_verify_signature_get_key(sig, &key) != RNP_SUCCESS) { + fprintf(stdout, "failed to get signature's %d key\n", (int) i); + goto finish; + } + + if (rnp_key_get_keyid(key, &keyid) != RNP_SUCCESS) { + fprintf(stdout, "failed to get key id %d\n", (int) i); + rnp_key_handle_destroy(key); + goto finish; + } + + sigstatus = rnp_op_verify_signature_get_status(sig); + fprintf(stdout, "Status for signature from key %s : %d\n", keyid, (int) sigstatus); + rnp_buffer_destroy(keyid); + rnp_key_handle_destroy(key); + } + + /* get the verified message from the output structure */ + if (rnp_output_memory_get_buf(output, &buf, &buf_len, false) != RNP_SUCCESS) { + goto finish; + } + fprintf(stdout, "Verified message:\n%.*s\n", (int) buf_len, buf); + + result = 0; +finish: + rnp_op_verify_destroy(verify); + rnp_input_destroy(input); + rnp_output_destroy(output); + rnp_ffi_destroy(ffi); + return result; +} + +int +main(int argc, char **argv) +{ + return ffi_verify(); +} diff --git a/comm/third_party/rnp/src/fuzzing/CMakeLists.txt b/comm/third_party/rnp/src/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..c177035e1d --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/CMakeLists.txt @@ -0,0 +1,145 @@ +# Copyright (c) 2020 Ribose Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +if(NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + add_compile_options(-fsanitize=fuzzer-no-link) + add_link_options(-fsanitize=fuzzer) +else() + # This section is used by OSS-Fuzz + add_link_options($ENV{LIB_FUZZING_ENGINE}) + if($ENV{FUZZING_ENGINE} STREQUAL "afl") + link_libraries(-stdlib=libc++) + endif() +endif() + +add_executable(fuzz_dump dump.c) + +target_include_directories(fuzz_dump + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_dump + PRIVATE + librnp +) + +add_executable(fuzz_keyring keyring.c) + +target_include_directories(fuzz_keyring + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_keyring + PRIVATE + librnp +) + +add_executable(fuzz_keyimport keyimport.c) + +target_include_directories(fuzz_keyimport + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_keyimport + PRIVATE + librnp +) + +add_executable(fuzz_sigimport sigimport.c) + +target_include_directories(fuzz_sigimport + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_sigimport + PRIVATE + librnp +) + +add_executable(fuzz_verify verify.c) + +target_include_directories(fuzz_verify + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_verify + PRIVATE + librnp +) + +add_executable(fuzz_verify_detached verify_detached.c) + +target_include_directories(fuzz_verify_detached + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_verify_detached + PRIVATE + librnp +) + +add_executable(fuzz_keyring_kbx keyring_kbx.c) + +target_include_directories(fuzz_keyring_kbx + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_keyring_kbx + PRIVATE + librnp +) + +add_executable(fuzz_keyring_g10 keyring_g10.cpp) + +target_include_directories(fuzz_keyring_g10 + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" +) + +target_link_libraries(fuzz_keyring_g10 + PRIVATE + librnp-static +) + +if (ENABLE_SANITIZERS) + foreach(tgt fuzz_dump fuzz_keyring fuzz_keyimport fuzz_sigimport fuzz_verify fuzz_verify_detached fuzz_keyring_kbx fuzz_keyring_g10) + set_target_properties(${tgt} PROPERTIES LINKER_LANGUAGE CXX) + endforeach() +endif() diff --git a/comm/third_party/rnp/src/fuzzing/dump.c b/comm/third_party/rnp/src/fuzzing/dump.c new file mode 100644 index 0000000000..026bfc2503 --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/dump.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef RNP_RUN_TESTS +int dump_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +dump_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_input_t input = NULL; + (void) rnp_input_from_memory(&input, data, size, false); + rnp_output_t output = NULL; + (void) rnp_output_to_null(&output); + + (void) rnp_dump_packets_to_output(input, output, RNP_DUMP_RAW); + rnp_output_destroy(output); + rnp_input_destroy(input); + + (void) rnp_input_from_memory(&input, data, size, false); + char *json = NULL; + (void) rnp_dump_packets_to_json(input, RNP_DUMP_RAW, &json); + rnp_buffer_destroy(json); + rnp_input_destroy(input); + + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/keyimport.c b/comm/third_party/rnp/src/fuzzing/keyimport.c new file mode 100644 index 0000000000..16e1272f8c --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/keyimport.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#ifdef RNP_RUN_TESTS +int keyimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +keyimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_input_t input = NULL; + rnp_result_t ret = 0; + rnp_ffi_t ffi = NULL; + + /* try non-permissive import */ + ret = rnp_input_from_memory(&input, data, size, false); + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + char *results = NULL; + ret = rnp_import_keys( + ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, &results); + rnp_buffer_destroy(results); + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + + /* try permissive import */ + ret = rnp_input_from_memory(&input, data, size, false); + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + results = NULL; + ret = rnp_import_keys(ffi, + input, + RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS | + RNP_LOAD_SAVE_PERMISSIVE, + &results); + rnp_buffer_destroy(results); + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + + /* try non-permissive iterative import */ + ret = rnp_input_from_memory(&input, data, size, false); + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + do { + results = NULL; + ret = rnp_import_keys(ffi, + input, + RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS | + RNP_LOAD_SAVE_SINGLE, + &results); + rnp_buffer_destroy(results); + } while (!ret); + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + + /* try permissive iterative import */ + ret = rnp_input_from_memory(&input, data, size, false); + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + do { + results = NULL; + ret = rnp_import_keys(ffi, + input, + RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS | + RNP_LOAD_SAVE_PERMISSIVE | RNP_LOAD_SAVE_SINGLE, + &results); + rnp_buffer_destroy(results); + } while (!ret); + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/keyring.c b/comm/third_party/rnp/src/fuzzing/keyring.c new file mode 100644 index 0000000000..bac4e1325a --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/keyring.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef RNP_RUN_TESTS +int keyring_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +keyring_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_input_t input = NULL; + rnp_result_t ret = 0; + rnp_ffi_t ffi = NULL; + + ret = rnp_input_from_memory(&input, data, size, false); + + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + ret = + rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS); + + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/keyring_g10.cpp b/comm/third_party/rnp/src/fuzzing/keyring_g10.cpp new file mode 100644 index 0000000000..f2495a591d --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/keyring_g10.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "../lib/pgp-key.h" +#include "../librekey/key_store_g10.h" +#include "../librepgp/stream-common.h" +#include "../lib/sec_profile.hpp" + +#ifdef RNP_RUN_TESTS +int keyring_g10_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +keyring_g10_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +extern "C" RNP_API int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp::SecurityContext ctx; + rnp_key_store_t ks(ctx); + pgp_source_t memsrc = {}; + + init_mem_src(&memsrc, data, size, false); + rnp_key_store_g10_from_src(&ks, &memsrc, NULL); + src_close(&memsrc); + + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/keyring_kbx.c b/comm/third_party/rnp/src/fuzzing/keyring_kbx.c new file mode 100644 index 0000000000..768e66911b --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/keyring_kbx.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef RNP_RUN_TESTS +int keyring_kbx_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +keyring_kbx_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_input_t input = NULL; + rnp_result_t ret = 0; + rnp_ffi_t ffi = NULL; + + ret = rnp_input_from_memory(&input, data, size, false); + + ret = rnp_ffi_create(&ffi, "KBX", "G10"); + ret = rnp_load_keys(ffi, "KBX", input, RNP_LOAD_SAVE_PUBLIC_KEYS); + + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/sigimport.c b/comm/third_party/rnp/src/fuzzing/sigimport.c new file mode 100644 index 0000000000..35adeb7343 --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/sigimport.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef RNP_RUN_TESTS +int sigimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +sigimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_input_t input = NULL; + rnp_result_t ret = 0; + rnp_ffi_t ffi = NULL; + + ret = rnp_input_from_memory(&input, data, size, false); + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + char *results = NULL; + ret = rnp_import_signatures(ffi, input, 0, &results); + rnp_buffer_destroy(results); + rnp_input_destroy(input); + rnp_ffi_destroy(ffi); + + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/verify.c b/comm/third_party/rnp/src/fuzzing/verify.c new file mode 100644 index 0000000000..cd6c849f63 --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/verify.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "stdio.h" + +#ifdef RNP_RUN_TESTS +int verify_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +verify_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + rnp_result_t ret; + + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + ret = rnp_input_from_memory(&input, data, size, false); + ret = rnp_output_to_null(&output); + + rnp_op_verify_t op = NULL; + ret = rnp_op_verify_create(&op, ffi, input, output); + ret = rnp_op_verify_execute(op); + ret = rnp_op_verify_destroy(op); + + rnp_input_destroy(input); + rnp_output_destroy(output); + rnp_ffi_destroy(ffi); + + return 0; +} diff --git a/comm/third_party/rnp/src/fuzzing/verify_detached.c b/comm/third_party/rnp/src/fuzzing/verify_detached.c new file mode 100644 index 0000000000..2afb59ab44 --- /dev/null +++ b/comm/third_party/rnp/src/fuzzing/verify_detached.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "string.h" + +#ifdef RNP_RUN_TESTS +int verify_detached_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int +verify_detached_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#else +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +#endif +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + rnp_input_t msg_input = NULL; + rnp_result_t ret; + + ret = rnp_ffi_create(&ffi, "GPG", "GPG"); + ret = rnp_input_from_memory(&input, data, size, false); + const char *msg = "message"; + ret = rnp_input_from_memory(&msg_input, (const uint8_t *) msg, strlen(msg), true); + + rnp_op_verify_t verify = NULL; + ret = rnp_op_verify_detached_create(&verify, ffi, msg_input, input); + ret = rnp_op_verify_execute(verify); + ret = rnp_op_verify_destroy(verify); + + rnp_input_destroy(input); + rnp_input_destroy(msg_input); + rnp_ffi_destroy(ffi); + + return 0; +} diff --git a/comm/third_party/rnp/src/lib/CMakeLists.txt b/comm/third_party/rnp/src/lib/CMakeLists.txt new file mode 100755 index 0000000000..086ac57d8e --- /dev/null +++ b/comm/third_party/rnp/src/lib/CMakeLists.txt @@ -0,0 +1,594 @@ +# Copyright (c) 2018-2020 Ribose Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +include(GNUInstallDirs) +include(GenerateExportHeader) + +# these could probably be optional but are currently not +find_package(BZip2 REQUIRED) +find_package(ZLIB REQUIRED) + +# required packages +find_package(JSON-C 0.11 REQUIRED) +if (CRYPTO_BACKEND_BOTAN) + find_package(Botan2 2.14.0 REQUIRED) +endif() +if (CRYPTO_BACKEND_OPENSSL) + include(FindOpenSSL) + find_package(OpenSSL 1.1.1 REQUIRED) + include(FindOpenSSLFeatures) + if("${OPENSSL_VERSION}" VERSION_GREATER_EQUAL "3.0.0") + set(CRYPTO_BACKEND_OPENSSL3 1) + endif() +endif() + +# generate a config.h +include(CheckIncludeFileCXX) +include(CheckCXXSymbolExists) +check_include_file_cxx(fcntl.h HAVE_FCNTL_H) +check_include_file_cxx(inttypes.h HAVE_INTTYPES_H) +check_include_file_cxx(limits.h HAVE_LIMITS_H) +check_include_file_cxx(stdint.h HAVE_STDINT_H) +check_include_file_cxx(string.h HAVE_STRING_H) +check_include_file_cxx(sys/cdefs.h HAVE_SYS_CDEFS_H) +check_include_file_cxx(sys/cdefs.h HAVE_SYS_MMAN_H) +check_include_file_cxx(sys/resource.h HAVE_SYS_RESOURCE_H) +check_include_file_cxx(sys/stat.h HAVE_SYS_STAT_H) +check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H) +check_include_file_cxx(sys/param.h HAVE_SYS_PARAM_H) +check_include_file_cxx(unistd.h HAVE_UNISTD_H) +check_include_file_cxx(sys/wait.h HAVE_SYS_WAIT_H) +check_cxx_symbol_exists(mkdtemp "stdlib.h;unistd.h" HAVE_MKDTEMP) +check_cxx_symbol_exists(mkstemp "stdlib.h;unistd.h" HAVE_MKSTEMP) +check_cxx_symbol_exists(realpath stdlib.h HAVE_REALPATH) +check_cxx_symbol_exists(O_BINARY fcntl.h HAVE_O_BINARY) +check_cxx_symbol_exists(_O_BINARY fcntl.h HAVE__O_BINARY) +check_cxx_symbol_exists(_tempnam stdio.h HAVE__TEMPNAM) +set(HAVE_ZLIB_H "${ZLIB_FOUND}") +set(HAVE_BZLIB_H "${BZIP2_FOUND}") +# generate a version.h +configure_file(version.h.in version.h) + +# Checks feature in CRYPTO_BACKEND and puts the result into variable whose name is stored in RESULT_VARNAME variable. +function(backend_has_feature FEATURE RESULT_VARNAME) + if (CRYPTO_BACKEND_LOWERCASE STREQUAL "botan") + check_cxx_symbol_exists("BOTAN_HAS_${FEATURE}" botan/build.h ${RESULT_VARNAME}) + else() + message(STATUS "Looking for OpenSSL feature ${FEATURE}") + OpenSSLHasFeature(${FEATURE} ${RESULT_VARNAME}) + if (${RESULT_VARNAME}) + message(STATUS "Looking for OpenSSL feature ${FEATURE} - found") + endif() + set(${RESULT_VARNAME} "${${RESULT_VARNAME}}" PARENT_SCOPE) + endif() +endfunction() + +function(resolve_feature_state RNP_FEATURE BACKEND_FEATURES) + if (NOT ${RNP_FEATURE}) # User has explicitly disabled this feature + return() + endif() + + string(TOLOWER "${${RNP_FEATURE}}" ${RNP_FEATURE}) + if (${RNP_FEATURE} STREQUAL "auto") + set(MESSAGE_TYPE "NOTICE") + set(OUTCOME "Disabling") + else() # User has explicitly enabled this feature + set(MESSAGE_TYPE "FATAL_ERROR") + set(OUTCOME "Aborting") + endif() + + foreach(feature ${BACKEND_FEATURES}) + backend_has_feature("${feature}" _has_${feature}) + if (NOT ${_has_${feature}}) + set(${RNP_FEATURE} Off CACHE STRING "Autodetected" FORCE) + message(${MESSAGE_TYPE} "${RNP_FEATURE} requires ${CRYPTO_BACKEND} feature which is missing: ${feature}. ${OUTCOME}.") + return() + endif() + endforeach() + set(${RNP_FEATURE} On CACHE STRING "Autodetected" FORCE) +endfunction() + +function(openssl_nope RNP_FEATURE REASON) + if (NOT ${RNP_FEATURE}) # User has explicitly disabled this feature + return() + endif() + + string(TOLOWER "${${RNP_FEATURE}}" ${RNP_FEATURE}) + if (${RNP_FEATURE} STREQUAL "auto") + set(MESSAGE_TYPE "NOTICE") + set(OUTCOME "Disabling") + else() # User has explicitly enabled this feature + set(MESSAGE_TYPE "FATAL_ERROR") + set(OUTCOME "Aborting") + endif() + + set(${RNP_FEATURE} Off CACHE STRING "Auto -> Off as no support" FORCE) + message(${MESSAGE_TYPE} "${RNP_FEATURE} doesn't work with OpenSSL backend (${REASON}). ${OUTCOME}.") +endfunction() + +if(CRYPTO_BACKEND_BOTAN) + # check botan's enabled features + set(CMAKE_REQUIRED_INCLUDES "${BOTAN2_INCLUDE_DIRS}") + set(_botan_required_features + # base + BIGINT FFI HEX_CODEC PGP_S2K + # symmetric ciphers + BLOCK_CIPHER AES CAMELLIA DES + # cipher modes + MODE_CBC MODE_CFB + # RNG + AUTO_RNG AUTO_SEEDING_RNG HMAC HMAC_DRBG + # hash + CRC24 HASH MD5 SHA1 SHA2_32 SHA2_64 SHA3 + # public-key core + DL_GROUP DL_PUBLIC_KEY_FAMILY ECC_GROUP ECC_PUBLIC_KEY_CRYPTO PUBLIC_KEY_CRYPTO + # public-key algs + CURVE_25519 DSA ECDH ECDSA ED25519 ELGAMAL RSA + # public-key operations etc + EME_PKCS1v15 EMSA_PKCS1 EMSA_RAW KDF_BASE RFC3394_KEYWRAP SP800_56A + ) + foreach(feature ${_botan_required_features}) + check_cxx_symbol_exists("BOTAN_HAS_${feature}" botan/build.h _botan_has_${feature}) + if (NOT _botan_has_${feature}) + message(FATAL_ERROR "A required botan feature is missing: ${feature}") + endif() + endforeach() + + resolve_feature_state(ENABLE_SM2 "SM2;SM3;SM4") + resolve_feature_state(ENABLE_AEAD "AEAD_EAX;AEAD_OCB") + resolve_feature_state(ENABLE_TWOFISH "TWOFISH") + resolve_feature_state(ENABLE_IDEA "IDEA") + # Botan supports Brainpool curves together with SECP via the ECC_GROUP define + resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH") + resolve_feature_state(ENABLE_CAST5 "CAST_128") + resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160") + set(CMAKE_REQUIRED_INCLUDES) +endif() +if(CRYPTO_BACKEND_OPENSSL) + # check OpenSSL features + set(_openssl_required_features + # symmetric ciphers + AES-128-ECB AES-192-ECB AES-256-ECB AES-128-CBC AES-192-CBC AES-256-CBC + AES-128-OCB AES-192-OCB AES-256-OCB + CAMELLIA-128-ECB CAMELLIA-192-ECB CAMELLIA-256-ECB + DES-EDE3 + # hashes + MD5 SHA1 SHA224 SHA256 SHA384 SHA512 SHA3-256 SHA3-512 + # curves + PRIME256V1 SECP384R1 SECP521R1 SECP256K1 + # public key + RSAENCRYPTION DSAENCRYPTION DHKEYAGREEMENT ID-ECPUBLICKEY X25519 ED25519 + ) + foreach(feature ${_openssl_required_features}) + message(STATUS "Looking for OpenSSL feature ${feature}") + OpenSSLHasFeature("${feature}" _openssl_has_${feature}) + if (NOT _openssl_has_${feature}) + message(FATAL_ERROR "A required OpenSSL feature is missing: ${feature}") + endif() + message(STATUS "Looking for OpenSSL feature ${feature} - found") + endforeach() + + resolve_feature_state(ENABLE_BRAINPOOL "BRAINPOOLP256R1;BRAINPOOLP384R1;BRAINPOOLP512R1") + resolve_feature_state(ENABLE_IDEA "IDEA-ECB;IDEA-CBC") + resolve_feature_state(ENABLE_BLOWFISH "BF-ECB") + resolve_feature_state(ENABLE_CAST5 "CAST5-ECB") + resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD160") + resolve_feature_state(ENABLE_AEAD "AES-128-OCB;AES-192-OCB;AES-256-OCB") + openssl_nope(ENABLE_SM2 "it's on our roadmap, see https://github.com/rnpgp/rnp/issues/1877") + #resolve_feature_state(ENABLE_SM2 "SM2;SM3;SM4-ECB") + openssl_nope(ENABLE_TWOFISH "Twofish isn't and won't be supported by OpenSSL, see https://github.com/openssl/openssl/issues/2046") +endif() + +configure_file(config.h.in config.h) + +if(CRYPTO_BACKEND_OPENSSL) + set(CRYPTO_SOURCES + crypto/bn_ossl.cpp + crypto/dsa_ossl.cpp + crypto/ec_curves.cpp + crypto/ec_ossl.cpp + crypto/ecdh_utils.cpp + crypto/ecdh_ossl.cpp + crypto/ecdsa_ossl.cpp + crypto/eddsa_ossl.cpp + crypto/dl_ossl.cpp + crypto/elgamal_ossl.cpp + crypto/hash_common.cpp + crypto/hash_ossl.cpp + crypto/hash_crc24.cpp + crypto/mpi.cpp + crypto/rng_ossl.cpp + crypto/rsa_ossl.cpp + crypto/s2k.cpp + crypto/s2k_ossl.cpp + crypto/symmetric_ossl.cpp + crypto/signatures.cpp + crypto/mem_ossl.cpp + crypto/cipher.cpp + crypto/cipher_ossl.cpp + ) + if(ENABLE_SM2) + list(APPEND CRYPTO_SOURCES crypto/sm2_ossl.cpp) + endif() +elseif(CRYPTO_BACKEND_BOTAN) + set(CRYPTO_SOURCES + crypto/bn.cpp + crypto/dsa.cpp + crypto/ec_curves.cpp + crypto/ec.cpp + crypto/ecdh_utils.cpp + crypto/ecdh.cpp + crypto/ecdsa.cpp + crypto/eddsa.cpp + crypto/elgamal.cpp + crypto/hash_common.cpp + crypto/hash.cpp + crypto/mpi.cpp + crypto/rng.cpp + crypto/rsa.cpp + crypto/s2k.cpp + crypto/symmetric.cpp + crypto/signatures.cpp + crypto/mem.cpp + crypto/cipher.cpp + crypto/cipher_botan.cpp + ) + if(ENABLE_SM2) + list(APPEND CRYPTO_SOURCES crypto/sm2.cpp) + endif() +else() + message(FATAL_ERROR "Unknown crypto backend: ${CRYPTO_BACKEND}.") +endif() +list(APPEND CRYPTO_SOURCES crypto/backend_version.cpp) + +# sha11collisiondetection sources +list(APPEND CRYPTO_SOURCES crypto/hash_sha1cd.cpp crypto/sha1cd/sha1.c crypto/sha1cd/ubc_check.c) + +add_library(librnp-obj OBJECT + # librepgp + ../librepgp/stream-armor.cpp + ../librepgp/stream-common.cpp + ../librepgp/stream-ctx.cpp + ../librepgp/stream-dump.cpp + ../librepgp/stream-key.cpp + ../librepgp/stream-packet.cpp + ../librepgp/stream-parse.cpp + ../librepgp/stream-sig.cpp + ../librepgp/stream-write.cpp + + # librekey + ../librekey/key_store_g10.cpp + ../librekey/key_store_kbx.cpp + ../librekey/key_store_pgp.cpp + ../librekey/rnp_key_store.cpp + + # cryptography + ${CRYPTO_SOURCES} + + # other sources + sec_profile.cpp + crypto.cpp + fingerprint.cpp + generate-key.cpp + key-provider.cpp + logging.cpp + json-utils.cpp + utils.cpp + pass-provider.cpp + pgp-key.cpp + rnp.cpp +) + +get_target_property(_comp_options librnp-obj COMPILE_OPTIONS) +string(REGEX MATCH "\\-fsanitize=[a-z,]*undefined" _comp_sanitizers "${_comp_options}" "${CMAKE_C_FLAGS}") +if (ENABLE_SANITIZERS OR _comp_sanitizers) + # sha1cd attempts to use unaligned access for optimisations on intel CPUs + # CFLAGS is checked as sanitizers may be enabled without CMake var + set_source_files_properties(crypto/sha1cd/sha1.c + PROPERTIES COMPILE_DEFINITIONS "SHA1DC_FORCE_ALIGNED_ACCESS" + ) +endif() + +set_target_properties(librnp-obj PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_include_directories(librnp-obj + PUBLIC + "$" + "$" + "$" + "$" + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}" + "${PROJECT_SOURCE_DIR}/src" +) +target_link_libraries(librnp-obj PRIVATE JSON-C::JSON-C) +if (CRYPTO_BACKEND_BOTAN) + target_link_libraries(librnp-obj PRIVATE Botan2::Botan2) +elseif (CRYPTO_BACKEND_OPENSSL) + target_link_libraries(librnp-obj PRIVATE OpenSSL::Crypto) +endif() + +target_link_libraries(librnp-obj PRIVATE sexp) + +set_target_properties(librnp-obj PROPERTIES CXX_VISIBILITY_PRESET hidden) +if (TARGET BZip2::BZip2) + target_link_libraries(librnp-obj PRIVATE BZip2::BZip2) +endif() +if (TARGET ZLIB::ZLIB) + target_link_libraries(librnp-obj PRIVATE ZLIB::ZLIB) +endif() +if (BUILD_SHARED_LIBS) + target_compile_definitions(librnp-obj PRIVATE librnp_EXPORTS) +else() + target_compile_definitions(librnp-obj PRIVATE RNP_STATIC) +endif() + +add_library(librnp $ $) +if (OpenSSL::applink) + target_link_libraries(librnp PRIVATE OpenSSL::applink) +endif(OpenSSL::applink) + +set_target_properties(librnp + PROPERTIES + VERSION "${RNP_VERSION}" + SOVERSION "${RNP_VERSION_MAJOR}" + OUTPUT_NAME "rnp" +) + +if (BUILD_SHARED_LIBS) + add_library(librnp-static STATIC $ $) + if (OpenSSL::applink) + target_link_libraries(librnp-static PRIVATE OpenSSL::applink) + endif(OpenSSL::applink) + if (WIN32) + set_target_properties(librnp-static PROPERTIES OUTPUT_NAME "rnp-static") + else (WIN32) +# On Unix like systems we will build/install/pack shared and static libraries librnp.so and librnp.a +# On Windows we will build/install/pack dynamic, import and static libraries rnp.dll, rnp.lib and rnp-static.lib + set_target_properties(librnp-static PROPERTIES OUTPUT_NAME "rnp") + endif (WIN32) + # Limit symbols export only to rnp_* functions. + if (APPLE) + # use -export_symbols_list on Apple OSs + target_link_options(librnp PRIVATE -Wl,-exported_symbols_list "${CMAKE_CURRENT_SOURCE_DIR}/librnp.symbols") + set_target_properties(librnp PROPERTIES LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/librnp.symbols") + elseif(NOT WIN32) + target_link_options(librnp PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/librnp.vsc") + set_target_properties(librnp PROPERTIES LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/librnp.vsc") + endif() +else() + add_library(librnp-static ALIAS librnp) +endif() + +foreach (prop LINK_LIBRARIES INTERFACE_LINK_LIBRARIES INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(val librnp-obj ${prop}) + if (BUILD_SHARED_LIBS) + set_property(TARGET librnp-static PROPERTY ${prop} ${val}) + list(REMOVE_ITEM val "$") + set_property(TARGET librnp PROPERTY ${prop} ${val}) + else() + set_property(TARGET librnp PROPERTY ${prop} ${val}) + endif() + +endforeach() + +generate_export_header(librnp + BASE_NAME rnp + EXPORT_MACRO_NAME RNP_API + EXPORT_FILE_NAME rnp/rnp_export.h + STATIC_DEFINE RNP_STATIC + INCLUDE_GUARD_NAME RNP_EXPORT +) + +# This has precedence and can cause some confusion when the binary +# dir one isn't actually being used. To be improved. +if (NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/config.h") + file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/version.h") +endif() + +if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + set(namelink_component NAMELINK_COMPONENT development) +else() + set(namelink_component) +endif() + +# add these to the rnp-targets export +# On Unix like systems we will build/install/pack shared and static libraries librnp.so and librnp.a +# On Windows we will build/install/pack dynamic, import and static libraries rnp.dll, rnp.lib and rnp-static.lib + +# If a client application uses shared rnp library, sexp is statically linked to librnp.so +# If a client application uses static rnp library, it still needs libsexp.a + +if (BUILD_SHARED_LIBS) +# both static and shared libraries +install(TARGETS librnp + EXPORT rnp-targets + LIBRARY + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT runtime + ${namelink_component} + ARCHIVE + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT development + ) + + install(TARGETS librnp-static sexp + EXPORT rnp-targets + ARCHIVE + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT development + ) +else(BUILD_SHARED_LIBS) +# static libraries only +install(TARGETS librnp sexp + EXPORT rnp-targets + ARCHIVE + DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT development +) +endif(BUILD_SHARED_LIBS) + +# install dll only for windows +if (WIN32) + install(TARGETS librnp + RUNTIME + DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT runtime + ) +endif(WIN32) + +# install headers +install( + FILES + "${PROJECT_SOURCE_DIR}/include/rnp/rnp.h" + COMPONENT + development + DESTINATION + "${CMAKE_INSTALL_INCLUDEDIR}/rnp" + RENAME + rnp.h +) +install( + FILES + "${PROJECT_SOURCE_DIR}/include/rnp/rnp_err.h" + COMPONENT + development + DESTINATION + "${CMAKE_INSTALL_INCLUDEDIR}/rnp" + RENAME + rnp_err.h +) +install( + FILES + "${PROJECT_BINARY_DIR}/src/lib/rnp/rnp_export.h" + COMPONENT + development + DESTINATION + "${CMAKE_INSTALL_INCLUDEDIR}/rnp" + RENAME + rnp_export.h +) + +# .cmake installs +set(INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/rnp") + +install(EXPORT rnp-targets + FILE rnp-targets.cmake + NAMESPACE rnp:: + DESTINATION "${INSTALL_CMAKEDIR}" + COMPONENT development +) + +include(CMakePackageConfigHelpers) +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/rnp-config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/rnp-config.cmake" + INSTALL_DESTINATION "${INSTALL_CMAKEDIR}" +) +write_basic_package_version_file(rnp-config-version.cmake + VERSION "${PROJECT_VERSION}" + COMPATIBILITY SameMajorVersion +) +install ( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/rnp-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/rnp-config-version.cmake" + DESTINATION "${INSTALL_CMAKEDIR}" + COMPONENT development +) + +function(get_linked_libs libsvar dirsvar tgt) + get_target_property(imported ${tgt} IMPORTED) + list(APPEND visited_targets ${tgt}) + if (imported) + get_target_property(linkedlibs ${tgt} INTERFACE_LINK_LIBRARIES) + endif() + set(libs) + foreach (lib ${linkedlibs}) + if (TARGET ${lib}) + list(FIND visited_targets ${lib} visited) + if ((${visited} EQUAL -1) AND (${CMAKE_SHARED_LIBRARY_PREFIX})) + # library + get_target_property(liblocation ${lib} LOCATION) + get_filename_component(linkedlib ${liblocation} NAME_WE) + string(REGEX REPLACE "^${CMAKE_SHARED_LIBRARY_PREFIX}" "" linkedlib ${linkedlib}) + get_linked_libs(linkedlibs libdirs ${lib}) + list(APPEND libs ${linkedlib} ${linkedlibs}) + # directory + get_filename_component(libdir ${liblocation} DIRECTORY) + list(FIND ${dirsvar} ${libdir} seendir) + if (${seendir} EQUAL -1) + list(APPEND ${dirsvar} ${libdir} ${libdirs}) + endif() + endif() + endif() + endforeach() + set(visited_targets ${visited_targets} PARENT_SCOPE) + set(${libsvar} ${libs} PARENT_SCOPE) + set(${dirsvar} ${${dirsvar}} PARENT_SCOPE) +endfunction() + +get_linked_libs(libs dirs librnp) +set(linkercmd) +foreach (dir ${dirs}) + string(APPEND linkercmd "-L${dir} ") +endforeach() +foreach (lib ${libs}) + string(APPEND linkercmd "-l${lib} ") +endforeach() +string(STRIP "${linkercmd}" linkercmd) +set(LIBRNP_PRIVATE_LIBS ${linkercmd}) + +# create a pkgconfig .pc too +find_package(PkgConfig) +if (PKG_CONFIG_FOUND) + get_target_property(LIBRNP_OUTPUT_NAME librnp OUTPUT_NAME) + + if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + set(PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}") + else() + set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}") + endif() + if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") + else() + set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") + endif() + + configure_file( + "${PROJECT_SOURCE_DIR}/cmake/librnp.pc.in" + "${PROJECT_BINARY_DIR}/librnp.pc" + @ONLY + ) + install( + FILES "${PROJECT_BINARY_DIR}/librnp.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" + COMPONENT development + ) +endif() + +# Build and install man page +if (ENABLE_DOC) + add_adoc_man("${CMAKE_CURRENT_SOURCE_DIR}/librnp.3.adoc" ${RNP_VERSION}) +endif() diff --git a/comm/third_party/rnp/src/lib/config.h.in b/comm/third_party/rnp/src/lib/config.h.in new file mode 100644 index 0000000000..f8880d55d7 --- /dev/null +++ b/comm/third_party/rnp/src/lib/config.h.in @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2018-2020 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define PACKAGE_STRING "rnp @RNP_VERSION_FULL@" +#define PACKAGE_BUGREPORT "@BUGREPORT_EMAIL@" + +#cmakedefine HAVE_BZLIB_H +#cmakedefine HAVE_ZLIB_H + +#cmakedefine HAVE_FCNTL_H +#cmakedefine HAVE_INTTYPES_H +#cmakedefine HAVE_LIMITS_H +#cmakedefine HAVE_STDINT_H +#cmakedefine HAVE_STRING_H +#cmakedefine HAVE_SYS_CDEFS_H +#cmakedefine HAVE_SYS_MMAN_H +#cmakedefine HAVE_SYS_RESOURCE_H +#cmakedefine HAVE_SYS_STAT_H +#cmakedefine HAVE_SYS_TYPES_H +#cmakedefine HAVE_UNISTD_H +#cmakedefine HAVE_SYS_WAIT_H +#cmakedefine HAVE_SYS_PARAM_H +#cmakedefine HAVE_MKDTEMP +#cmakedefine HAVE_MKSTEMP +#cmakedefine HAVE_REALPATH +#cmakedefine HAVE_O_BINARY +#cmakedefine HAVE__O_BINARY +#cmakedefine HAVE__TEMPNAM + +#cmakedefine CRYPTO_BACKEND_BOTAN +#cmakedefine CRYPTO_BACKEND_OPENSSL +#cmakedefine CRYPTO_BACKEND_OPENSSL3 + +#cmakedefine ENABLE_SM2 +#cmakedefine ENABLE_AEAD +#cmakedefine ENABLE_TWOFISH +#cmakedefine ENABLE_BRAINPOOL +#cmakedefine ENABLE_IDEA +#cmakedefine ENABLE_BLOWFISH +#cmakedefine ENABLE_CAST5 +#cmakedefine ENABLE_RIPEMD160 + +/* Macro _GLIBCXX_USE_CXX11_ABI was first introduced with GCC 5.0, which + * we assume to be bundled with a sane implementation of std::regex. */ +#if !defined(__GNUC__) || defined(_GLIBCXX_USE_CXX11_ABI) || \ + (defined(WIN32) && !defined(MSYS)) || \ + ((defined(__clang__) && (__clang_major__ >= 4)) ) +#define RNP_USE_STD_REGEX 1 +#endif diff --git a/comm/third_party/rnp/src/lib/crypto.cpp b/comm/third_party/rnp/src/lib/crypto.cpp new file mode 100644 index 0000000000..26346049e8 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" + +#ifdef HAVE_SYS_CDEFS_H +#include +#endif + +#if defined(__NetBSD__) +__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); +__RCSID("$NetBSD: crypto.c,v 1.36 2014/02/17 07:39:19 agc Exp $"); +#endif + +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "types.h" +#include "crypto/common.h" +#include "crypto.h" +#include "fingerprint.h" +#include "pgp-key.h" +#include "utils.h" + +bool +pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, + pgp_key_pkt_t & seckey, + bool primary) +{ + /* populate pgp key structure */ + seckey = {}; + seckey.version = PGP_V4; + seckey.creation_time = crypto.ctx->time(); + seckey.alg = crypto.key_alg; + seckey.material.alg = crypto.key_alg; + seckey.tag = primary ? PGP_PKT_SECRET_KEY : PGP_PKT_SECRET_SUBKEY; + + switch (seckey.alg) { + case PGP_PKA_RSA: + if (rsa_generate(&crypto.ctx->rng, &seckey.material.rsa, crypto.rsa.modulus_bit_len)) { + RNP_LOG("failed to generate RSA key"); + return false; + } + break; + case PGP_PKA_DSA: + if (dsa_generate(&crypto.ctx->rng, + &seckey.material.dsa, + crypto.dsa.p_bitlen, + crypto.dsa.q_bitlen)) { + RNP_LOG("failed to generate DSA key"); + return false; + } + break; + case PGP_PKA_EDDSA: + if (eddsa_generate(&crypto.ctx->rng, &seckey.material.ec)) { + RNP_LOG("failed to generate EDDSA key"); + return false; + } + break; + case PGP_PKA_ECDH: + if (!ecdh_set_params(&seckey.material.ec, crypto.ecc.curve)) { + RNP_LOG("Unsupported curve [ID=%d]", crypto.ecc.curve); + return false; + } + if (crypto.ecc.curve == PGP_CURVE_25519) { + if (x25519_generate(&crypto.ctx->rng, &seckey.material.ec)) { + RNP_LOG("failed to generate x25519 key"); + return false; + } + seckey.material.ec.curve = crypto.ecc.curve; + break; + } + [[fallthrough]]; + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + if (!curve_supported(crypto.ecc.curve)) { + RNP_LOG("EC generate: curve %d is not supported.", (int) crypto.ecc.curve); + return false; + } + if (ec_generate(&crypto.ctx->rng, &seckey.material.ec, seckey.alg, crypto.ecc.curve)) { + RNP_LOG("failed to generate EC key"); + return false; + } + seckey.material.ec.curve = crypto.ecc.curve; + break; + case PGP_PKA_ELGAMAL: + if (elgamal_generate( + &crypto.ctx->rng, &seckey.material.eg, crypto.elgamal.key_bitlen)) { + RNP_LOG("failed to generate ElGamal key"); + return false; + } + break; + default: + RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); + return false; + } + seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; + seckey.material.secret = true; + seckey.material.validity.mark_valid(); + /* fill the sec_data/sec_len */ + if (encrypt_secret_key(&seckey, NULL, crypto.ctx->rng)) { + RNP_LOG("failed to fill sec_data"); + return false; + } + return true; +} + +bool +key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2) +{ + if (key1->alg != key2->alg) { + return false; + } + + switch (key1->alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return mpi_equal(&key1->rsa.n, &key2->rsa.n) && mpi_equal(&key1->rsa.e, &key2->rsa.e); + case PGP_PKA_DSA: + return mpi_equal(&key1->dsa.p, &key2->dsa.p) && + mpi_equal(&key1->dsa.q, &key2->dsa.q) && + mpi_equal(&key1->dsa.g, &key2->dsa.g) && mpi_equal(&key1->dsa.y, &key2->dsa.y); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return mpi_equal(&key1->eg.p, &key2->eg.p) && mpi_equal(&key1->eg.g, &key2->eg.g) && + mpi_equal(&key1->eg.y, &key2->eg.y); + case PGP_PKA_EDDSA: + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + return (key1->ec.curve == key2->ec.curve) && mpi_equal(&key1->ec.p, &key2->ec.p); + default: + RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); + return false; + } +} + +rnp_result_t +validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) +{ +#ifdef FUZZERS_ENABLED + /* do not timeout on large keys during fuzzing */ + return RNP_SUCCESS; +#else + switch (material->alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return rsa_validate_key(rng, &material->rsa, material->secret); + case PGP_PKA_DSA: + return dsa_validate_key(rng, &material->dsa, material->secret); + case PGP_PKA_EDDSA: + return eddsa_validate_key(rng, &material->ec, material->secret); + case PGP_PKA_ECDH: + if (!curve_supported(material->ec.curve)) { + /* allow to import key if curve is not supported */ + RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve); + return RNP_SUCCESS; + } + return ecdh_validate_key(rng, &material->ec, material->secret); + case PGP_PKA_ECDSA: + if (!curve_supported(material->ec.curve)) { + /* allow to import key if curve is not supported */ + RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve); + return RNP_SUCCESS; + } + return ecdsa_validate_key(rng, &material->ec, material->secret); + case PGP_PKA_SM2: +#if defined(ENABLE_SM2) + return sm2_validate_key(rng, &material->ec, material->secret); +#else + RNP_LOG("SM2 key validation is not available."); + return RNP_ERROR_NOT_IMPLEMENTED; +#endif + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return elgamal_validate_key(&material->eg, material->secret) ? RNP_SUCCESS : + RNP_ERROR_GENERIC; + default: + RNP_LOG("unknown public key algorithm: %d", (int) material->alg); + } + + return RNP_ERROR_BAD_PARAMETERS; +#endif +} diff --git a/comm/third_party/rnp/src/lib/crypto.h b/comm/third_party/rnp/src/lib/crypto.h new file mode 100644 index 0000000000..320daf8d4f --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + */ + +#ifndef CRYPTO_H_ +#define CRYPTO_H_ + +#include +#include "crypto/common.h" +#include + +/* raw key generation */ +bool pgp_generate_seckey(const rnp_keygen_crypto_params_t ¶ms, + pgp_key_pkt_t & seckey, + bool primary); + +/** generate a new primary key + * + * @param desc keygen description + * @param merge_defaults true if you want defaults to be set for unset + * keygen description parameters. + * @param primary_sec pointer to store the generated secret key, must not be NULL + * @param primary_pub pointer to store the generated public key, must not be NULL + * @return true if successful, false otherwise. + **/ +bool pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, + bool merge_defaults, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_store_format_t secformat); + +/** generate a new subkey + * + * @param desc keygen description + * @param merge_defaults true if you want defaults to be set for unset + * keygen description parameters. + * @param primary_sec pointer to the primary secret key that will own this + * subkey, must not be NULL + * @param primary_pub pointer to the primary public key that will own this + * subkey, must not be NULL + * @param subkey_sec pointer to store the generated secret key, must not be NULL + * @param subkey_pub pointer to store the generated public key, must not be NULL + * @param password_provider the password provider that will be used to + * decrypt the primary key, may be NULL if primary key is unlocked + * @return true if successful, false otherwise. + **/ +bool pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, + bool merge_defaults, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_t & subkey_sec, + pgp_key_t & subkey_pub, + const pgp_password_provider_t &password_provider, + pgp_key_store_format_t secformat); + +/** + * @brief Check two key material for equality. Only public part is checked, so this can be + * called on public/secret key material + * + * @param key1 first key material + * @param key2 second key material + * @return true if both key materials are equal or false otherwise + */ +bool key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2); + +rnp_result_t validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng); + +#endif /* CRYPTO_H_ */ diff --git a/comm/third_party/rnp/src/lib/crypto/backend_version.cpp b/comm/third_party/rnp/src/lib/crypto/backend_version.cpp new file mode 100644 index 0000000000..859b048c36 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/backend_version.cpp @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "backend_version.h" +#include "logging.h" +#if defined(CRYPTO_BACKEND_BOTAN) +#include +#elif defined(CRYPTO_BACKEND_OPENSSL) +#include +#include +#include "ossl_common.h" +#if defined(CRYPTO_BACKEND_OPENSSL3) +#include +#endif +#include +#include "config.h" +#ifndef RNP_USE_STD_REGEX +#include +#else +#include +#endif +#endif +#include + +namespace rnp { + +const char * +backend_string() +{ +#if defined(CRYPTO_BACKEND_BOTAN) + return "Botan"; +#elif defined(CRYPTO_BACKEND_OPENSSL) + return "OpenSSL"; +#else +#error "Unknown backend" +#endif +} + +const char * +backend_version() +{ +#if defined(CRYPTO_BACKEND_BOTAN) + return Botan::short_version_cstr(); +#elif defined(CRYPTO_BACKEND_OPENSSL) + /* Use regexp to retrieve version (second word) from version string + * like "OpenSSL 1.1.1l 24 Aug 2021" + * */ + static char version[32] = {}; + if (version[0]) { + return version; + } + const char *reg = "OpenSSL (([0-9]\\.[0-9]\\.[0-9])[a-z]*(-beta[0-9])*(-dev)*) "; +#ifndef RNP_USE_STD_REGEX + static regex_t r; + regmatch_t matches[5]; + const char * ver = OpenSSL_version(OPENSSL_VERSION); + + if (!strlen(version)) { + if (regcomp(&r, reg, REG_EXTENDED) != 0) { + RNP_LOG("failed to compile regexp"); + return "unknown"; + } + } + if (regexec(&r, ver, 5, matches, 0) != 0) { + return "unknown"; + } + assert(sizeof(version) > matches[1].rm_eo - matches[1].rm_so); + memcpy(version, ver + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so); + version[matches[1].rm_eo - matches[1].rm_so] = '\0'; +#else + static std::regex re(reg, std::regex_constants::extended); + std::smatch result; + std::string ver = OpenSSL_version(OPENSSL_VERSION); + if (!std::regex_search(ver, result, re)) { + return "unknown"; + } + assert(sizeof(version) > result[1].str().size()); + strncpy(version, result[1].str().c_str(), sizeof(version) - 1); +#endif + return version; +#else +#error "Unknown backend" +#endif +} + +#if defined(CRYPTO_BACKEND_OPENSSL3) + +#if defined(ENABLE_IDEA) || defined(ENABLE_CAST5) || defined(ENABLE_BLOWFISH) || \ + defined(ENABLE_RIPEMD160) +#define OPENSSL_LOAD_LEGACY +#endif + +typedef struct openssl3_state { +#if defined(OPENSSL_LOAD_LEGACY) + OSSL_PROVIDER *legacy; +#endif + OSSL_PROVIDER *def; +} openssl3_state; + +bool +backend_init(void **param) +{ + if (!param) { + return false; + } + + *param = NULL; + openssl3_state *state = (openssl3_state *) calloc(1, sizeof(openssl3_state)); + if (!state) { + RNP_LOG("Allocation failure."); + return false; + } + /* Load default crypto provider */ + state->def = OSSL_PROVIDER_load(NULL, "default"); + if (!state->def) { + RNP_LOG("Failed to load default crypto provider: %s", ossl_latest_err()); + free(state); + return false; + } + /* Load legacy crypto provider if needed */ +#if defined(OPENSSL_LOAD_LEGACY) + state->legacy = OSSL_PROVIDER_load(NULL, "legacy"); + if (!state->legacy) { + RNP_LOG("Failed to load legacy crypto provider: %s", ossl_latest_err()); + OSSL_PROVIDER_unload(state->def); + free(state); + return false; + } +#endif + *param = state; + return true; +} + +void +backend_finish(void *param) +{ + if (!param) { + return; + } + openssl3_state *state = (openssl3_state *) param; + OSSL_PROVIDER_unload(state->def); +#if defined(OPENSSL_LOAD_LEGACY) + OSSL_PROVIDER_unload(state->legacy); +#endif + free(state); +} +#else +bool +backend_init(void **param) +{ + return true; +} + +void +backend_finish(void *param) +{ + // Do nothing +} +#endif + +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/backend_version.h b/comm/third_party/rnp/src/lib/crypto/backend_version.h new file mode 100644 index 0000000000..13c52692e6 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/backend_version.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_BACKEND_VERSION_H_ +#define CRYPTO_BACKEND_VERSION_H_ + +#include "config.h" + +namespace rnp { + +const char *backend_string(); + +const char *backend_version(); + +bool backend_init(void **param); + +void backend_finish(void *param); + +} // namespace rnp + +#endif // CRYPTO_BACKEND_VERSION_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/bn.cpp b/comm/third_party/rnp/src/lib/crypto/bn.cpp new file mode 100644 index 0000000000..d5ae6b4a94 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/bn.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017-2021 Ribose Inc. + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bn.h" +#include +#include +#include +#include "utils.h" + +/* essentiually, these are just wrappers around the botan functions */ +/* usually the order of args changes */ +/* the bignum_t API tends to have more const poisoning */ +/* these wrappers also check the arguments passed for sanity */ + +/* store in unsigned [big endian] format */ +int +bn_bn2bin(const bignum_t *a, unsigned char *b) +{ + if (!a || !b) { + return -1; + } + return botan_mp_to_bin(a->mp, b); +} + +bignum_t * +mpi2bn(const pgp_mpi_t *val) +{ + assert(val); + if (!val) { + RNP_LOG("NULL val."); + return NULL; + } + bignum_t *res = bn_new(); + if (!res) { + return NULL; + } + if (botan_mp_from_bin(res->mp, val->mpi, val->len)) { + bn_free(res); + res = NULL; + } + return res; +} + +bool +bn2mpi(const bignum_t *bn, pgp_mpi_t *val) +{ + val->len = bn_num_bytes(*bn); + if (val->len > PGP_MPINT_SIZE) { + RNP_LOG("Too large MPI."); + val->len = 0; + return false; + } + return bn_bn2bin(bn, val->mpi) == 0; +} + +bignum_t * +bn_new(void) +{ + bignum_t *a = (bignum_t *) calloc(1, sizeof(*a)); + if (!a) { + return NULL; + } + botan_mp_init(&a->mp); + return a; +} + +void +bn_free(bignum_t *a) +{ + if (a) { + botan_mp_destroy(a->mp); + free(a); + } +} + +size_t +bn_num_bytes(const bignum_t &a) +{ + size_t bytes = 0; + if (botan_mp_num_bits(a.mp, &bytes)) { + RNP_LOG("botan_mp_num_bits failed."); + } + return BITS_TO_BYTES(bytes); +} diff --git a/comm/third_party/rnp/src/lib/crypto/bn.h b/comm/third_party/rnp/src/lib/crypto/bn.h new file mode 100644 index 0000000000..26cc547690 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/bn.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2017-2021 Ribose Inc. + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_BN_H_ +#define RNP_BN_H_ + +#include +#include +#include "config.h" +#include "mpi.h" + +#if defined(CRYPTO_BACKEND_OPENSSL) +#include + +#define bignum_t BIGNUM +#elif defined(CRYPTO_BACKEND_BOTAN) +typedef struct botan_mp_struct *botan_mp_t; +typedef struct bignum_t_st { + botan_mp_t mp; +} bignum_t; + +#define BN_HANDLE(x) ((x).mp) +#define BN_HANDLE_PTR(x) ((x)->mp) +#else +#error "Unknown crypto backend." +#endif + +/*********************************/ + +bignum_t *bn_new(void); +void bn_free(bignum_t * /*a*/); + +int bn_bn2bin(const bignum_t * /*a*/, unsigned char * /*b*/); + +bignum_t *mpi2bn(const pgp_mpi_t *val); + +bool bn2mpi(const bignum_t *bn, pgp_mpi_t *val); + +size_t bn_num_bytes(const bignum_t &a); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/bn_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/bn_ossl.cpp new file mode 100644 index 0000000000..34e1a3e205 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/bn_ossl.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "bn.h" +#include "logging.h" + +/* store in unsigned [big endian] format */ +int +bn_bn2bin(const bignum_t *a, unsigned char *b) +{ + if (!a || !b) { + return -1; + } + return BN_bn2bin(a, b) >= 0 ? 0 : -1; +} + +bignum_t * +mpi2bn(const pgp_mpi_t *val) +{ + assert(val); + if (!val) { + RNP_LOG("NULL val."); + return NULL; + } + bignum_t *res = bn_new(); + if (!res) { + return NULL; + } + if (!BN_bin2bn(val->mpi, val->len, res)) { + bn_free(res); + res = NULL; + } + return res; +} + +bool +bn2mpi(const bignum_t *bn, pgp_mpi_t *val) +{ + val->len = bn_num_bytes(*bn); + return bn_bn2bin(bn, val->mpi) == 0; +} + +bignum_t * +bn_new(void) +{ + return BN_new(); +} + +void +bn_free(bignum_t *a) +{ + BN_clear_free(a); +} + +size_t +bn_num_bytes(const bignum_t &a) +{ + return (BN_num_bits(&a) + 7) / 8; +} diff --git a/comm/third_party/rnp/src/lib/crypto/cipher.cpp b/comm/third_party/rnp/src/lib/crypto/cipher.cpp new file mode 100644 index 0000000000..a6c6fcee43 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/cipher.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" +#include "symmetric.h" +#include "cipher.hpp" + +#if defined(CRYPTO_BACKEND_OPENSSL) +#include "cipher_ossl.hpp" +#elif defined(CRYPTO_BACKEND_BOTAN) +#include "cipher_botan.hpp" +#endif + +std::unique_ptr +Cipher::encryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding) +{ +#if defined(CRYPTO_BACKEND_OPENSSL) + return Cipher_OpenSSL::encryption(cipher, mode, tag_size, disable_padding); +#elif defined(CRYPTO_BACKEND_BOTAN) + return Cipher_Botan::encryption(cipher, mode, tag_size, disable_padding); +#else +#error "Crypto backend not specified" +#endif +} + +std::unique_ptr +Cipher::decryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding) +{ +#if defined(CRYPTO_BACKEND_OPENSSL) + return Cipher_OpenSSL::decryption(cipher, mode, tag_size, disable_padding); +#elif defined(CRYPTO_BACKEND_BOTAN) + return Cipher_Botan::decryption(cipher, mode, tag_size, disable_padding); +#else +#error "Crypto backend not specified" +#endif +} + +Cipher::Cipher(pgp_symm_alg_t alg) : m_alg(alg) +{ +} + +Cipher::~Cipher() +{ +} + +size_t +Cipher::block_size() const +{ + return pgp_block_size(m_alg); +} diff --git a/comm/third_party/rnp/src/lib/crypto/cipher.hpp b/comm/third_party/rnp/src/lib/crypto/cipher.hpp new file mode 100644 index 0000000000..c9edf15789 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/cipher.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_CIPHER_HPP +#define RNP_CIPHER_HPP + +#include +#include +#include + +// Note: for AEAD modes we append the authentication tag to the ciphertext as in RFC 5116 +class Cipher { + public: + // the tag size should be 0 for non-AEAD and must be non-zero for AEAD modes (no default) + static std::unique_ptr encryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size = 0, + bool disable_padding = false); + static std::unique_ptr decryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size = 0, + bool disable_padding = false); + + virtual bool set_key(const uint8_t *key, size_t key_length) = 0; + virtual bool set_iv(const uint8_t *iv, size_t iv_length) = 0; + // only valid for AEAD modes + virtual bool set_ad(const uint8_t *ad, size_t ad_length) = 0; + + virtual size_t block_size() const; + virtual size_t update_granularity() const = 0; + + // input_length must be a multiple of update_granularity + virtual bool update(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) = 0; + // process final block and perform any padding + virtual bool finish(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) = 0; + + virtual ~Cipher(); + + protected: + Cipher(pgp_symm_alg_t alg); + + pgp_symm_alg_t m_alg; +}; + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/cipher_botan.cpp b/comm/third_party/rnp/src/lib/crypto/cipher_botan.cpp new file mode 100644 index 0000000000..c2c4ab3939 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/cipher_botan.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include "cipher_botan.hpp" +#include "utils.h" +#include "types.h" + +static const id_str_pair cipher_mode_map[] = { + {PGP_CIPHER_MODE_CBC, "CBC"}, + {PGP_CIPHER_MODE_OCB, "OCB"}, + {0, NULL}, +}; + +static const id_str_pair cipher_map[] = { + {PGP_SA_AES_128, "AES-128"}, + {PGP_SA_AES_256, "AES-256"}, + {PGP_SA_IDEA, "IDEA"}, + {0, NULL}, +}; + +Cipher_Botan * +Cipher_Botan::create(pgp_symm_alg_t alg, const std::string &name, bool encrypt) +{ +#if !defined(ENABLE_IDEA) + if (alg == PGP_SA_IDEA) { + RNP_LOG("IDEA support has been disabled"); + return nullptr; + } +#endif +#if !defined(ENABLE_BLOWFISH) + if (alg == PGP_SA_BLOWFISH) { + RNP_LOG("Blowfish support has been disabled"); + return nullptr; + } +#endif +#if !defined(ENABLE_CAST5) + if (alg == PGP_SA_CAST5) { + RNP_LOG("CAST5 support has been disabled"); + return nullptr; + } +#endif + auto cipher = Botan::Cipher_Mode::create( + name, encrypt ? Botan::Cipher_Dir::ENCRYPTION : Botan::Cipher_Dir::DECRYPTION); + if (!cipher) { + RNP_LOG("Failed to create cipher '%s'", name.c_str()); + return nullptr; + } + return new (std::nothrow) Cipher_Botan(alg, std::move(cipher)); +} + +static std::string +make_name(pgp_symm_alg_t cipher, pgp_cipher_mode_t mode, size_t tag_size, bool disable_padding) +{ + const char *cipher_string = id_str_pair::lookup(cipher_map, cipher, NULL); + const char *mode_string = id_str_pair::lookup(cipher_mode_map, mode, NULL); + if (!cipher_string || !mode_string) { + return ""; + } + try { + std::stringstream ss; + ss << cipher_string << "/" << mode_string; + if (tag_size) { + ss << "(" << tag_size << ")"; + } + if (mode == PGP_CIPHER_MODE_CBC && disable_padding) { + ss << "/NoPadding"; + } + return ss.str(); + } catch (const std::exception &e) { + return ""; + } +} + +std::unique_ptr +Cipher_Botan::encryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding) +{ + return std::unique_ptr( + create(cipher, make_name(cipher, mode, tag_size, disable_padding), true)); +} + +std::unique_ptr +Cipher_Botan::decryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding) +{ + return std::unique_ptr( + create(cipher, make_name(cipher, mode, tag_size, disable_padding), false)); +} + +size_t +Cipher_Botan::update_granularity() const +{ + return m_cipher->update_granularity(); +} + +bool +Cipher_Botan::set_key(const uint8_t *key, size_t key_length) +{ + try { + m_cipher->set_key(key, key_length); + } catch (const std::exception &e) { + RNP_LOG("Failed to set key: %s", e.what()); + return false; + } + return true; +} + +bool +Cipher_Botan::set_iv(const uint8_t *iv, size_t iv_length) +{ + try { + m_cipher->start(iv, iv_length); + m_buf.reserve(this->update_granularity()); + } catch (const std::exception &e) { + RNP_LOG("Failed to set IV: %s", e.what()); + return false; + } + return true; +} + +bool +Cipher_Botan::set_ad(const uint8_t *ad, size_t ad_length) +{ + assert(m_cipher->authenticated()); + try { + dynamic_cast(*m_cipher).set_associated_data(ad, ad_length); + } catch (const std::exception &e) { + RNP_LOG("Failed to set AAD: %s", e.what()); + return false; + } + return true; +} + +bool +Cipher_Botan::update(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) +{ + try { + size_t ud = this->update_granularity(); + m_buf.resize(ud); + + *input_consumed = 0; + *output_written = 0; + while (input_length >= ud && output_length >= ud) { + m_buf.assign(input, input + ud); + size_t written = m_cipher->process(m_buf.data(), ud); + std::copy(m_buf.data(), m_buf.data() + written, output); + input += ud; + output += written; + input_length -= ud; + output_length -= written; + + *output_written += written; + *input_consumed += ud; + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + return true; +} + +bool +Cipher_Botan::finish(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) +{ + try { + *input_consumed = 0; + *output_written = 0; + size_t ud = this->update_granularity(); + if (input_length > ud) { + if (!update(output, + output_length, + output_written, + input, + input_length - ud, + input_consumed)) { + return false; + } + input += *input_consumed; + input_length = input_length - *input_consumed; + output += *output_written; + output_length -= *output_written; + } + Botan::secure_vector final_block(input, input + input_length); + m_cipher->finish(final_block); + if (final_block.size() > output_length) { + RNP_LOG("Insufficient buffer"); + return false; + } + std::copy(final_block.begin(), final_block.end(), output); + *output_written += final_block.size(); + *input_consumed += input_length; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + return true; +} + +Cipher_Botan::Cipher_Botan(pgp_symm_alg_t alg, std::unique_ptr cipher) + : Cipher(alg), m_cipher(std::move(cipher)) +{ +} + +Cipher_Botan::~Cipher_Botan() +{ +} diff --git a/comm/third_party/rnp/src/lib/crypto/cipher_botan.hpp b/comm/third_party/rnp/src/lib/crypto/cipher_botan.hpp new file mode 100644 index 0000000000..517d38b6af --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/cipher_botan.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_CIPHER_BOTAN_HPP +#define RNP_CIPHER_BOTAN_HPP + +#include "cipher.hpp" +#include +#include + +class Cipher_Botan : public Cipher { + public: + static std::unique_ptr encryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding); + static std::unique_ptr decryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding); + + bool set_key(const uint8_t *key, size_t key_length) override; + bool set_iv(const uint8_t *iv, size_t iv_length) override; + bool set_ad(const uint8_t *ad, size_t ad_length) override; + + size_t update_granularity() const override; + + bool update(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) override; + bool finish(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) override; + virtual ~Cipher_Botan(); + + private: + Cipher_Botan(pgp_symm_alg_t alg, std::unique_ptr cipher); + + std::unique_ptr m_cipher; + std::vector m_buf; + + static Cipher_Botan *create(pgp_symm_alg_t alg, const std::string &name, bool encrypt); +}; + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/cipher_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/cipher_ossl.cpp new file mode 100644 index 0000000000..bb81d488a1 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/cipher_ossl.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#include "cipher_ossl.hpp" +#include "utils.h" +#include "types.h" +#include + +static const id_str_pair cipher_mode_map[] = { + {PGP_CIPHER_MODE_CBC, "CBC"}, + {PGP_CIPHER_MODE_OCB, "OCB"}, + {0, NULL}, +}; + +static const id_str_pair cipher_map[] = { + {PGP_SA_AES_128, "AES-128"}, + {PGP_SA_AES_256, "AES-256"}, + {PGP_SA_IDEA, "IDEA"}, + {0, NULL}, +}; + +EVP_CIPHER_CTX * +Cipher_OpenSSL::create(pgp_symm_alg_t alg, + const std::string &name, + bool encrypt, + size_t tag_size, + bool disable_padding) +{ +#if !defined(ENABLE_IDEA) + if (alg == PGP_SA_IDEA) { + RNP_LOG("IDEA support has been disabled"); + return nullptr; + } +#endif +#if !defined(ENABLE_BLOWFISH) + if (alg == PGP_SA_BLOWFISH) { + RNP_LOG("Blowfish support has been disabled"); + return nullptr; + } +#endif +#if !defined(ENABLE_CAST5) + if (alg == PGP_SA_CAST5) { + RNP_LOG("CAST5 support has been disabled"); + return nullptr; + } +#endif + const EVP_CIPHER *cipher = EVP_get_cipherbyname(name.c_str()); + if (!cipher) { + RNP_LOG("Unsupported cipher: %s", name.c_str()); + return nullptr; + } + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + RNP_LOG("Failed to create cipher context: %lu", ERR_peek_last_error()); + return nullptr; + } + if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encrypt ? 1 : 0) != 1) { + RNP_LOG("Failed to initialize cipher: %lu", ERR_peek_last_error()); + EVP_CIPHER_CTX_free(ctx); + return nullptr; + } + // set tag size + if (encrypt && tag_size) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_size, NULL) != 1) { + RNP_LOG("Failed to set AEAD tag length: %lu", ERR_peek_last_error()); + EVP_CIPHER_CTX_free(ctx); + return nullptr; + } + } + if (disable_padding) { + EVP_CIPHER_CTX_set_padding(ctx, 0); + } + return ctx; +} + +static std::string +make_name(pgp_symm_alg_t cipher, pgp_cipher_mode_t mode) +{ + const char *cipher_string = id_str_pair::lookup(cipher_map, cipher, NULL); + const char *mode_string = id_str_pair::lookup(cipher_mode_map, mode, NULL); + if (!cipher_string || !mode_string) { + return ""; + } + return std::string(cipher_string) + "-" + mode_string; +} + +std::unique_ptr +Cipher_OpenSSL::encryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding) +{ + EVP_CIPHER_CTX *ossl_ctx = + create(cipher, make_name(cipher, mode), true, tag_size, disable_padding); + if (!ossl_ctx) { + return NULL; + } + return std::unique_ptr(new (std::nothrow) + Cipher_OpenSSL(cipher, ossl_ctx, tag_size, true)); +} + +std::unique_ptr +Cipher_OpenSSL::decryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding) +{ + EVP_CIPHER_CTX *ossl_ctx = + create(cipher, make_name(cipher, mode), false, tag_size, disable_padding); + if (!ossl_ctx) { + return NULL; + } + return std::unique_ptr( + new (std::nothrow) Cipher_OpenSSL(cipher, ossl_ctx, tag_size, false)); +} + +bool +Cipher_OpenSSL::set_key(const uint8_t *key, size_t key_length) +{ + assert(key_length <= INT_MAX); + return EVP_CIPHER_CTX_set_key_length(m_ctx, (int) key_length) == 1 && + EVP_CipherInit_ex(m_ctx, NULL, NULL, key, NULL, -1) == 1; +} + +bool +Cipher_OpenSSL::set_iv(const uint8_t *iv, size_t iv_length) +{ + assert(iv_length <= INT_MAX); + // set IV len for AEAD modes + if (m_tag_size && + EVP_CIPHER_CTX_ctrl(m_ctx, EVP_CTRL_AEAD_SET_IVLEN, (int) iv_length, NULL) != 1) { + RNP_LOG("Failed to set AEAD IV length: %lu", ERR_peek_last_error()); + return false; + } + if (EVP_CIPHER_CTX_iv_length(m_ctx) != (int) iv_length) { + RNP_LOG("IV length mismatch"); + return false; + } + if (EVP_CipherInit_ex(m_ctx, NULL, NULL, NULL, iv, -1) != 1) { + RNP_LOG("Failed to set IV: %lu", ERR_peek_last_error()); + } + return true; +} + +bool +Cipher_OpenSSL::set_ad(const uint8_t *ad, size_t ad_length) +{ + assert(m_tag_size); + int outlen = 0; + if (EVP_CipherUpdate(m_ctx, NULL, &outlen, ad, ad_length) != 1) { + RNP_LOG("Failed to set AD: %lu", ERR_peek_last_error()); + return false; + } + return true; +} + +size_t +Cipher_OpenSSL::update_granularity() const +{ + return (size_t) EVP_CIPHER_CTX_block_size(m_ctx); +} + +bool +Cipher_OpenSSL::update(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) +{ + if (input_length > INT_MAX) { + return false; + } + *input_consumed = 0; + *output_written = 0; + if (input_length == 0) { + return true; + } + int outl = 0; + if (EVP_CipherUpdate(m_ctx, output, &outl, input, (int) input_length) != 1) { + RNP_LOG("EVP_CipherUpdate failed: %lu", ERR_peek_last_error()); + return false; + } + assert((size_t) outl < output_length); + *input_consumed = input_length; + *output_written = (size_t) outl; + return true; +} + +bool +Cipher_OpenSSL::finish(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) +{ + if (input_length > INT_MAX) { + return false; + } + if (!m_encrypt && input_length < m_tag_size) { + RNP_LOG("Insufficient input for final block (missing tag)"); + return false; + } + *input_consumed = 0; + *output_written = 0; + if (!m_encrypt && m_tag_size) { + // set the tag from the end of the ciphertext + if (EVP_CIPHER_CTX_ctrl(m_ctx, + EVP_CTRL_AEAD_SET_TAG, + m_tag_size, + const_cast(input) + input_length - m_tag_size) != + 1) { + RNP_LOG("Failed to set expected AEAD tag: %lu", ERR_peek_last_error()); + return false; + } + size_t ats = std::min(m_tag_size, input_length); + input_length -= ats; // m_tag_size; + *input_consumed += ats; // m_tag_size; + } + int outl = 0; + if (EVP_CipherUpdate(m_ctx, output, &outl, input, (int) input_length) != 1) { + RNP_LOG("EVP_CipherUpdate failed: %lu", ERR_peek_last_error()); + return false; + } + input += input_length; + *input_consumed += input_length; + output += outl; + *output_written += (size_t) outl; + if (EVP_CipherFinal_ex(m_ctx, output, &outl) != 1) { + RNP_LOG("EVP_CipherFinal_ex failed: %lu", ERR_peek_last_error()); + return false; + } + *output_written += (size_t) outl; + output += (size_t) outl; + if (m_encrypt && m_tag_size) { + // append the tag + if (EVP_CIPHER_CTX_ctrl(m_ctx, EVP_CTRL_AEAD_GET_TAG, m_tag_size, output) != 1) { + RNP_LOG("Failed to append AEAD tag: %lu", ERR_peek_last_error()); + return false; + } + *output_written += m_tag_size; + } + return true; +} + +Cipher_OpenSSL::Cipher_OpenSSL(pgp_symm_alg_t alg, + EVP_CIPHER_CTX *ctx, + size_t tag_size, + bool encrypt) + : Cipher(alg), m_ctx(ctx), m_tag_size(tag_size), m_encrypt(encrypt) +{ + m_block_size = EVP_CIPHER_CTX_block_size(m_ctx); +} + +Cipher_OpenSSL::~Cipher_OpenSSL() +{ + EVP_CIPHER_CTX_free(m_ctx); +} diff --git a/comm/third_party/rnp/src/lib/crypto/cipher_ossl.hpp b/comm/third_party/rnp/src/lib/crypto/cipher_ossl.hpp new file mode 100644 index 0000000000..da2bb4efe9 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/cipher_ossl.hpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_CIPHER_OSSL_HPP +#define RNP_CIPHER_OSSL_HPP + +#include "cipher.hpp" +#include +#include + +class Cipher_OpenSSL : public Cipher { + public: + static std::unique_ptr encryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding); + static std::unique_ptr decryption(pgp_symm_alg_t cipher, + pgp_cipher_mode_t mode, + size_t tag_size, + bool disable_padding); + + bool set_key(const uint8_t *key, size_t key_length) override; + bool set_iv(const uint8_t *iv, size_t iv_length) override; + bool set_ad(const uint8_t *ad, size_t ad_length) override; + + size_t update_granularity() const override; + + // input_length should not exceed INT_MAX + bool update(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) override; + bool finish(uint8_t * output, + size_t output_length, + size_t * output_written, + const uint8_t *input, + size_t input_length, + size_t * input_consumed) override; + virtual ~Cipher_OpenSSL(); + + private: + Cipher_OpenSSL(pgp_symm_alg_t alg, EVP_CIPHER_CTX *ctx, size_t tag_size, bool encrypt); + + EVP_CIPHER_CTX *m_ctx; + size_t m_block_size; + size_t m_tag_size; + bool m_encrypt; + + static EVP_CIPHER_CTX *create(pgp_symm_alg_t alg, + const std::string &name, + bool encrypt, + size_t tag_size, + bool disable_padding); +}; + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/common.h b/comm/third_party/rnp/src/lib/crypto/common.h new file mode 100644 index 0000000000..3d9b8378e7 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/common.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2018 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_CRYPTO_COMMON_H_ +#define RNP_CRYPTO_COMMON_H_ + +/* base */ +#include "mpi.h" +#include "rng.h" +/* asymmetric crypto */ +#include "rsa.h" +#include "dsa.h" +#include "elgamal.h" +#include "ec.h" +#include "ecdh.h" +#include "ecdsa.h" +#include "sm2.h" +#include "eddsa.h" +/* symmetric crypto */ +#include "symmetric.h" +/* hash */ +#include "hash.hpp" +/* s2k */ +#include "s2k.h" +/* backend name and version */ +#include "backend_version.h" + +#endif // RNP_CRYPTO_COMMON_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/dl_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/dl_ossl.cpp new file mode 100644 index 0000000000..1e96218af9 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/dl_ossl.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "bn.h" +#include "dl_ossl.h" +#include "utils.h" +#include +#include +#include + +EVP_PKEY * +dl_load_key(const pgp_mpi_t &mp, + const pgp_mpi_t *mq, + const pgp_mpi_t &mg, + const pgp_mpi_t &my, + const pgp_mpi_t *mx) +{ + DH * dh = NULL; + EVP_PKEY *evpkey = NULL; + bignum_t *p = mpi2bn(&mp); + bignum_t *q = mq ? mpi2bn(mq) : NULL; + bignum_t *g = mpi2bn(&mg); + bignum_t *y = mpi2bn(&my); + bignum_t *x = mx ? mpi2bn(mx) : NULL; + + if (!p || (mq && !q) || !g || !y || (mx && !x)) { + RNP_LOG("out of memory"); + goto done; + } + + dh = DH_new(); + if (!dh) { + RNP_LOG("out of memory"); + goto done; + } + int res; + /* line below must not fail */ + res = DH_set0_pqg(dh, p, q, g); + assert(res == 1); + if (res < 1) { + goto done; + } + p = NULL; + q = NULL; + g = NULL; + /* line below must not fail */ + res = DH_set0_key(dh, y, x); + assert(res == 1); + if (res < 1) { + goto done; + } + y = NULL; + x = NULL; + + evpkey = EVP_PKEY_new(); + if (!evpkey) { + RNP_LOG("allocation failed"); + goto done; + } + if (EVP_PKEY_set1_DH(evpkey, dh) <= 0) { + RNP_LOG("Failed to set key: %lu", ERR_peek_last_error()); + EVP_PKEY_free(evpkey); + evpkey = NULL; + } +done: + DH_free(dh); + bn_free(p); + bn_free(q); + bn_free(g); + bn_free(y); + bn_free(x); + return evpkey; +} + +static rnp_result_t +dl_validate_secret_key(EVP_PKEY *dlkey, const pgp_mpi_t &mx) +{ + const DH *dh = EVP_PKEY_get0_DH(dlkey); + assert(dh); + const bignum_t *p = DH_get0_p(dh); + const bignum_t *q = DH_get0_q(dh); + const bignum_t *g = DH_get0_g(dh); + const bignum_t *y = DH_get0_pub_key(dh); + assert(p && g && y); + bignum_t *p1 = NULL; + + rnp_result_t ret = RNP_ERROR_GENERIC; + + BN_CTX * ctx = BN_CTX_new(); + bignum_t *x = mpi2bn(&mx); + bignum_t *cy = bn_new(); + + if (!x || !cy || !ctx) { + RNP_LOG("Allocation failed"); + goto done; + } + if (!q) { + /* if q is NULL then group order is (p - 1) / 2 */ + p1 = BN_dup(p); + if (!p1) { + RNP_LOG("Allocation failed"); + goto done; + } + int res; + res = BN_rshift(p1, p1, 1); + assert(res == 1); + if (res < 1) { + RNP_LOG("BN_rshift failed."); + goto done; + } + q = p1; + } + if (BN_cmp(x, q) != -1) { + RNP_LOG("x is too large."); + goto done; + } + if (BN_mod_exp_mont_consttime(cy, g, x, p, ctx, NULL) < 1) { + RNP_LOG("Exponentiation failed"); + goto done; + } + if (BN_cmp(cy, y) == 0) { + ret = RNP_SUCCESS; + } +done: + BN_CTX_free(ctx); + bn_free(x); + bn_free(cy); + bn_free(p1); + return ret; +} + +rnp_result_t +dl_validate_key(EVP_PKEY *pkey, const pgp_mpi_t *x) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + int res; + res = EVP_PKEY_param_check(ctx); + if (res < 0) { + RNP_LOG("Param validation error: %lu (%s)", + ERR_peek_last_error(), + ERR_reason_error_string(ERR_peek_last_error())); + } + if (res < 1) { + /* ElGamal specification doesn't seem to restrict P to the safe prime */ + auto err = ERR_peek_last_error(); + DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_SAFE_PRIME); + if ((ERR_GET_REASON(err) == DH_R_CHECK_P_NOT_SAFE_PRIME)) { + RNP_LOG("Warning! P is not a safe prime."); + } else { + goto done; + } + } + res = EVP_PKEY_public_check(ctx); + if (res < 0) { + RNP_LOG("Key validation error: %lu", ERR_peek_last_error()); + } + if (res < 1) { + goto done; + } + /* There is no private key check in OpenSSL yet, so need to check x vs y manually */ + if (!x) { + ret = RNP_SUCCESS; + goto done; + } + ret = dl_validate_secret_key(pkey, *x); +done: + EVP_PKEY_CTX_free(ctx); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/dl_ossl.h b/comm/third_party/rnp/src/lib/crypto/dl_ossl.h new file mode 100644 index 0000000000..fcafc0ac9a --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/dl_ossl.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DL_OSSL_H_ +#define DL_OSSL_H_ + +#include "types.h" +#include "config.h" +#include +#include "mpi.h" +#include + +EVP_PKEY *dl_load_key(const pgp_mpi_t &mp, + const pgp_mpi_t *mq, + const pgp_mpi_t &mg, + const pgp_mpi_t &my, + const pgp_mpi_t *mx); + +rnp_result_t dl_validate_key(EVP_PKEY *pkey, const pgp_mpi_t *mx); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/dsa.cpp b/comm/third_party/rnp/src/lib/crypto/dsa.cpp new file mode 100644 index 0000000000..8763f00400 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/dsa.cpp @@ -0,0 +1,382 @@ +/*- + * Copyright (c) 2017-2018 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Alistair Crooks (agc@NetBSD.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + */ +#include +#include +#include +#include +#include "dsa.h" +#include "bn.h" +#include "utils.h" + +#define DSA_MAX_Q_BITLEN 256 + +rnp_result_t +dsa_validate_key(rnp::RNG *rng, const pgp_dsa_key_t *key, bool secret) +{ + bignum_t * p = NULL; + bignum_t * q = NULL; + bignum_t * g = NULL; + bignum_t * y = NULL; + bignum_t * x = NULL; + botan_pubkey_t bpkey = NULL; + botan_privkey_t bskey = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + + /* load and check public key part */ + p = mpi2bn(&key->p); + q = mpi2bn(&key->q); + g = mpi2bn(&key->g); + y = mpi2bn(&key->y); + + if (!p || !q || !g || !y) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + if (botan_pubkey_load_dsa( + &bpkey, BN_HANDLE_PTR(p), BN_HANDLE_PTR(q), BN_HANDLE_PTR(g), BN_HANDLE_PTR(y))) { + goto done; + } + + if (botan_pubkey_check_key(bpkey, rng->handle(), 0)) { + goto done; + } + + if (!secret) { + ret = RNP_SUCCESS; + goto done; + } + + /* load and check secret key part */ + if (!(x = mpi2bn(&key->x))) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + if (botan_privkey_load_dsa( + &bskey, BN_HANDLE_PTR(p), BN_HANDLE_PTR(q), BN_HANDLE_PTR(g), BN_HANDLE_PTR(x))) { + goto done; + } + + if (botan_privkey_check_key(bskey, rng->handle(), 0)) { + goto done; + } + + ret = RNP_SUCCESS; +done: + bn_free(p); + bn_free(q); + bn_free(g); + bn_free(y); + bn_free(x); + botan_privkey_destroy(bskey); + botan_pubkey_destroy(bpkey); + return ret; +} + +rnp_result_t +dsa_sign(rnp::RNG * rng, + pgp_dsa_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_dsa_key_t *key) +{ + botan_privkey_t dsa_key = NULL; + botan_pk_op_sign_t sign_op = NULL; + size_t q_order = 0; + uint8_t sign_buf[2 * BITS_TO_BYTES(DSA_MAX_Q_BITLEN)] = {0}; + bignum_t * p = NULL, *q = NULL, *g = NULL, *x = NULL; + rnp_result_t ret = RNP_ERROR_SIGNING_FAILED; + size_t sigbuf_size = sizeof(sign_buf); + + size_t z_len = 0; + + memset(sig, 0, sizeof(*sig)); + q_order = mpi_bytes(&key->q); + if ((2 * q_order) > sizeof(sign_buf)) { + RNP_LOG("wrong q order"); + return RNP_ERROR_BAD_PARAMETERS; + } + + // As 'Raw' is used we need to reduce hash size (as per FIPS-186-4, 4.6) + z_len = hash_len < q_order ? hash_len : q_order; + + p = mpi2bn(&key->p); + q = mpi2bn(&key->q); + g = mpi2bn(&key->g); + x = mpi2bn(&key->x); + + if (!p || !q || !g || !x) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto end; + } + + if (botan_privkey_load_dsa( + &dsa_key, BN_HANDLE_PTR(p), BN_HANDLE_PTR(q), BN_HANDLE_PTR(g), BN_HANDLE_PTR(x))) { + RNP_LOG("Can't load key"); + goto end; + } + + if (botan_pk_op_sign_create(&sign_op, dsa_key, "Raw", 0)) { + goto end; + } + + if (botan_pk_op_sign_update(sign_op, hash, z_len)) { + goto end; + } + + if (botan_pk_op_sign_finish(sign_op, rng->handle(), sign_buf, &sigbuf_size)) { + RNP_LOG("Signing has failed"); + goto end; + } + + // Now load the DSA (r,s) values from the signature. + if (!mem2mpi(&sig->r, sign_buf, q_order) || + !mem2mpi(&sig->s, sign_buf + q_order, q_order)) { + goto end; + } + ret = RNP_SUCCESS; + +end: + bn_free(p); + bn_free(q); + bn_free(g); + bn_free(x); + botan_pk_op_sign_destroy(sign_op); + botan_privkey_destroy(dsa_key); + return ret; +} + +rnp_result_t +dsa_verify(const pgp_dsa_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_dsa_key_t * key) +{ + botan_pubkey_t dsa_key = NULL; + botan_pk_op_verify_t verify_op = NULL; + uint8_t sign_buf[2 * BITS_TO_BYTES(DSA_MAX_Q_BITLEN)] = {0}; + size_t q_order = 0; + size_t r_blen, s_blen; + bignum_t * p = NULL, *q = NULL, *g = NULL, *y = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + size_t z_len = 0; + + q_order = mpi_bytes(&key->q); + if ((2 * q_order) > sizeof(sign_buf)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + z_len = hash_len < q_order ? hash_len : q_order; + + r_blen = mpi_bytes(&sig->r); + s_blen = mpi_bytes(&sig->s); + if ((r_blen > q_order) || (s_blen > q_order)) { + RNP_LOG("Wrong signature"); + return RNP_ERROR_BAD_PARAMETERS; + } + + p = mpi2bn(&key->p); + q = mpi2bn(&key->q); + g = mpi2bn(&key->g); + y = mpi2bn(&key->y); + + if (!p || !q || !g || !y) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto end; + } + + if (botan_pubkey_load_dsa( + &dsa_key, BN_HANDLE_PTR(p), BN_HANDLE_PTR(q), BN_HANDLE_PTR(g), BN_HANDLE_PTR(y))) { + RNP_LOG("Wrong key"); + goto end; + } + + mpi2mem(&sig->r, sign_buf + q_order - r_blen); + mpi2mem(&sig->s, sign_buf + 2 * q_order - s_blen); + + if (botan_pk_op_verify_create(&verify_op, dsa_key, "Raw", 0)) { + RNP_LOG("Can't create verifier"); + goto end; + } + + if (botan_pk_op_verify_update(verify_op, hash, z_len)) { + goto end; + } + + ret = (botan_pk_op_verify_finish(verify_op, sign_buf, 2 * q_order) == BOTAN_FFI_SUCCESS) ? + RNP_SUCCESS : + RNP_ERROR_SIGNATURE_INVALID; + +end: + bn_free(p); + bn_free(q); + bn_free(g); + bn_free(y); + botan_pk_op_verify_destroy(verify_op); + botan_pubkey_destroy(dsa_key); + return ret; +} + +rnp_result_t +dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits) +{ + if ((keylen < 1024) || (keylen > 3072) || (qbits < 160) || (qbits > 256)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + botan_privkey_t key_priv = NULL; + botan_pubkey_t key_pub = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + bignum_t * p = bn_new(); + bignum_t * q = bn_new(); + bignum_t * g = bn_new(); + bignum_t * y = bn_new(); + bignum_t * x = bn_new(); + + if (!p || !q || !g || !y || !x) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto end; + } + + if (botan_privkey_create_dsa(&key_priv, rng->handle(), keylen, qbits) || + botan_privkey_check_key(key_priv, rng->handle(), 1) || + botan_privkey_export_pubkey(&key_pub, key_priv)) { + RNP_LOG("Wrong parameters"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto end; + } + + if (botan_pubkey_get_field(BN_HANDLE_PTR(p), key_pub, "p") || + botan_pubkey_get_field(BN_HANDLE_PTR(q), key_pub, "q") || + botan_pubkey_get_field(BN_HANDLE_PTR(g), key_pub, "g") || + botan_pubkey_get_field(BN_HANDLE_PTR(y), key_pub, "y") || + botan_privkey_get_field(BN_HANDLE_PTR(x), key_priv, "x")) { + RNP_LOG("Botan FFI call failed"); + ret = RNP_ERROR_GENERIC; + goto end; + } + + if (!bn2mpi(p, &key->p) || !bn2mpi(q, &key->q) || !bn2mpi(g, &key->g) || + !bn2mpi(y, &key->y) || !bn2mpi(x, &key->x)) { + RNP_LOG("failed to copy mpi"); + goto end; + } + ret = RNP_SUCCESS; +end: + bn_free(p); + bn_free(q); + bn_free(g); + bn_free(y); + bn_free(x); + botan_privkey_destroy(key_priv); + botan_pubkey_destroy(key_pub); + return ret; +} + +pgp_hash_alg_t +dsa_get_min_hash(size_t qsize) +{ + /* + * I'm using _broken_ SHA1 here only because + * some old implementations may not understand keys created + * with other hashes. If you're sure we don't have to support + * such implementations, please be my guest and remove it. + */ + return (qsize < 160) ? PGP_HASH_UNKNOWN : + (qsize == 160) ? PGP_HASH_SHA1 : + (qsize <= 224) ? PGP_HASH_SHA224 : + (qsize <= 256) ? PGP_HASH_SHA256 : + (qsize <= 384) ? PGP_HASH_SHA384 : + (qsize <= 512) ? PGP_HASH_SHA512 + /*(qsize>512)*/ : + PGP_HASH_UNKNOWN; +} + +size_t +dsa_choose_qsize_by_psize(size_t psize) +{ + return (psize == 1024) ? 160 : + (psize <= 2047) ? 224 : + (psize <= 3072) ? DSA_MAX_Q_BITLEN : + 0; +} diff --git a/comm/third_party/rnp/src/lib/crypto/dsa.h b/comm/third_party/rnp/src/lib/crypto/dsa.h new file mode 100644 index 0000000000..52a186ac2b --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/dsa.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017-2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_DSA_H_ +#define RNP_DSA_H_ + +#include +#include +#include "crypto/rng.h" +#include "crypto/mpi.h" + +typedef struct pgp_dsa_key_t { + pgp_mpi_t p; + pgp_mpi_t q; + pgp_mpi_t g; + pgp_mpi_t y; + /* secret mpi */ + pgp_mpi_t x; +} pgp_dsa_key_t; + +typedef struct pgp_dsa_signature_t { + pgp_mpi_t r; + pgp_mpi_t s; +} pgp_dsa_signature_t; + +/** + * @brief Checks DSA key fields for validity + * + * @param rng initialized PRNG + * @param key initialized DSA key structure + * @param secret flag which tells whether key has populated secret fields + * + * @return RNP_SUCCESS if key is valid or error code otherwise + */ +rnp_result_t dsa_validate_key(rnp::RNG *rng, const pgp_dsa_key_t *key, bool secret); + +/* + * @brief Performs DSA signing + * + * @param rng initialized PRNG + * @param sig[out] created signature + * @param hash hash to sign + * @param hash_len length of `hash` + * @param key DSA key (must include secret mpi) + * + * @returns RNP_SUCCESS + * RNP_ERROR_BAD_PARAMETERS wrong input provided + * RNP_ERROR_SIGNING_FAILED internal error + */ +rnp_result_t dsa_sign(rnp::RNG * rng, + pgp_dsa_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_dsa_key_t *key); + +/* + * @brief Performs DSA verification + * + * @param hash hash to verify + * @param hash_len length of `hash` + * @param sig signature to be verified + * @param key DSA key (secret mpi is not needed) + * + * @returns RNP_SUCCESS + * RNP_ERROR_BAD_PARAMETERS wrong input provided + * RNP_ERROR_GENERIC internal error + * RNP_ERROR_SIGNATURE_INVALID signature is invalid + */ +rnp_result_t dsa_verify(const pgp_dsa_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_dsa_key_t * key); + +/* + * @brief Performs DSA key generation + * + * @param rng initialized PRNG + * @param key[out] generated key data will be stored here + * @param keylen length of the key, in bits + * @param qbits subgroup size in bits + * + * @returns RNP_SUCCESS + * RNP_ERROR_BAD_PARAMETERS wrong input provided + * RNP_ERROR_OUT_OF_MEMORY memory allocation failed + * RNP_ERROR_GENERIC internal error + * RNP_ERROR_SIGNATURE_INVALID signature is invalid + */ +rnp_result_t dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits); + +/* + * @brief Returns minimally sized hash which will work + * with the DSA subgroup. + * + * @param qsize subgroup order + * + * @returns Either ID of the hash algorithm, or PGP_HASH_UNKNOWN + * if not found + */ +pgp_hash_alg_t dsa_get_min_hash(size_t qsize); + +/* + * @brief Helps to determine subgroup size by size of p + * In order not to confuse users, we use less complicated + * approach than suggested by FIPS-186, which is: + * p=1024 => q=160 + * p<2048 => q=224 + * p<=3072 => q=256 + * So we don't generate (2048, 224) pair + * + * @return Size of `q' or 0 in case `psize' is not in <1024,3072> range + */ +size_t dsa_choose_qsize_by_psize(size_t psize); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/dsa_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/dsa_ossl.cpp new file mode 100644 index 0000000000..1fb75b5fce --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/dsa_ossl.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "bn.h" +#include "dsa.h" +#include "dl_ossl.h" +#include "utils.h" +#include +#include +#include +#include + +#define DSA_MAX_Q_BITLEN 256 + +static bool +dsa_decode_sig(const uint8_t *data, size_t len, pgp_dsa_signature_t &sig) +{ + DSA_SIG *dsig = d2i_DSA_SIG(NULL, &data, len); + if (!dsig) { + RNP_LOG("Failed to parse DSA sig: %lu", ERR_peek_last_error()); + return false; + } + const BIGNUM *r, *s; + DSA_SIG_get0(dsig, &r, &s); + bn2mpi(r, &sig.r); + bn2mpi(s, &sig.s); + DSA_SIG_free(dsig); + return true; +} + +static bool +dsa_encode_sig(uint8_t *data, size_t *len, const pgp_dsa_signature_t &sig) +{ + bool res = false; + DSA_SIG *dsig = DSA_SIG_new(); + BIGNUM * r = mpi2bn(&sig.r); + BIGNUM * s = mpi2bn(&sig.s); + if (!dsig || !r || !s) { + RNP_LOG("Allocation failed."); + goto done; + } + DSA_SIG_set0(dsig, r, s); + r = NULL; + s = NULL; + int outlen; + outlen = i2d_DSA_SIG(dsig, &data); + if (outlen < 0) { + RNP_LOG("Failed to encode signature."); + goto done; + } + *len = outlen; + res = true; +done: + DSA_SIG_free(dsig); + BN_free(r); + BN_free(s); + return res; +} + +static EVP_PKEY * +dsa_load_key(const pgp_dsa_key_t *key, bool secret = false) +{ + DSA * dsa = NULL; + EVP_PKEY *evpkey = NULL; + bignum_t *p = mpi2bn(&key->p); + bignum_t *q = mpi2bn(&key->q); + bignum_t *g = mpi2bn(&key->g); + bignum_t *y = mpi2bn(&key->y); + bignum_t *x = secret ? mpi2bn(&key->x) : NULL; + + if (!p || !q || !g || !y || (secret && !x)) { + RNP_LOG("out of memory"); + goto done; + } + + dsa = DSA_new(); + if (!dsa) { + RNP_LOG("Out of memory"); + goto done; + } + if (DSA_set0_pqg(dsa, p, q, g) != 1) { + RNP_LOG("Failed to set pqg. Error: %lu", ERR_peek_last_error()); + goto done; + } + p = NULL; + q = NULL; + g = NULL; + if (DSA_set0_key(dsa, y, x) != 1) { + RNP_LOG("Secret key load error: %lu", ERR_peek_last_error()); + goto done; + } + y = NULL; + x = NULL; + + evpkey = EVP_PKEY_new(); + if (!evpkey) { + RNP_LOG("allocation failed"); + goto done; + } + if (EVP_PKEY_set1_DSA(evpkey, dsa) <= 0) { + RNP_LOG("Failed to set key: %lu", ERR_peek_last_error()); + EVP_PKEY_free(evpkey); + evpkey = NULL; + } +done: + DSA_free(dsa); + bn_free(p); + bn_free(q); + bn_free(g); + bn_free(y); + bn_free(x); + return evpkey; +} + +rnp_result_t +dsa_validate_key(rnp::RNG *rng, const pgp_dsa_key_t *key, bool secret) +{ + /* OpenSSL doesn't implement key checks for the DSA, however we may use DL via DH */ + EVP_PKEY *pkey = dl_load_key(key->p, &key->q, key->g, key->y, NULL); + if (!pkey) { + RNP_LOG("Failed to load key"); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_result_t ret = dl_validate_key(pkey, secret ? &key->x : NULL); + EVP_PKEY_free(pkey); + return ret; +} + +rnp_result_t +dsa_sign(rnp::RNG * rng, + pgp_dsa_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_dsa_key_t *key) +{ + if (mpi_bytes(&key->x) == 0) { + RNP_LOG("private key not set"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* Load secret key to DSA structure*/ + EVP_PKEY *evpkey = dsa_load_key(key, true); + if (!evpkey) { + RNP_LOG("Failed to load key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + /* init context and sign */ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_sign_init(ctx) <= 0) { + RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error()); + goto done; + } + sig->s.len = PGP_MPINT_SIZE; + if (EVP_PKEY_sign(ctx, sig->s.mpi, &sig->s.len, hash, hash_len) <= 0) { + RNP_LOG("Signing failed: %lu", ERR_peek_last_error()); + sig->s.len = 0; + goto done; + } + if (!dsa_decode_sig(&sig->s.mpi[0], sig->s.len, *sig)) { + RNP_LOG("Failed to parse DSA sig: %lu", ERR_peek_last_error()); + goto done; + } + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(evpkey); + return ret; +} + +rnp_result_t +dsa_verify(const pgp_dsa_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_dsa_key_t * key) +{ + /* Load secret key to DSA structure*/ + EVP_PKEY *evpkey = dsa_load_key(key, false); + if (!evpkey) { + RNP_LOG("Failed to load key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + /* init context and sign */ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_verify_init(ctx) <= 0) { + RNP_LOG("Failed to initialize verify: %lu", ERR_peek_last_error()); + goto done; + } + pgp_mpi_t sigbuf; + if (!dsa_encode_sig(sigbuf.mpi, &sigbuf.len, *sig)) { + goto done; + } + if (EVP_PKEY_verify(ctx, sigbuf.mpi, sigbuf.len, hash, hash_len) <= 0) { + ret = RNP_ERROR_SIGNATURE_INVALID; + } else { + ret = RNP_SUCCESS; + } +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(evpkey); + return ret; +} + +rnp_result_t +dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits) +{ + if ((keylen < 1024) || (keylen > 3072) || (qbits < 160) || (qbits > 256)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + const DSA * dsa = NULL; + EVP_PKEY * pkey = NULL; + EVP_PKEY * parmkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + + /* Generate DSA params */ + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + if (!ctx) { + RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); + return ret; + } + if (EVP_PKEY_paramgen_init(ctx) <= 0) { + RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, keylen) <= 0) { + RNP_LOG("Failed to set key bits: %lu", ERR_peek_last_error()); + goto done; + } +#if OPENSSL_VERSION_NUMBER < 0x1010105fL + EVP_PKEY_CTX_ctrl( + ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL); +#else + if (EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, qbits) <= 0) { + RNP_LOG("Failed to set key qbits: %lu", ERR_peek_last_error()); + goto done; + } +#endif + if (EVP_PKEY_paramgen(ctx, &parmkey) <= 0) { + RNP_LOG("Failed to generate parameters: %lu", ERR_peek_last_error()); + goto done; + } + EVP_PKEY_CTX_free(ctx); + /* Generate DSA key */ + ctx = EVP_PKEY_CTX_new(parmkey, NULL); + if (!ctx) { + RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_keygen_init(ctx) <= 0) { + RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + RNP_LOG("DSA keygen failed: %lu", ERR_peek_last_error()); + goto done; + } + dsa = EVP_PKEY_get0_DSA(pkey); + if (!dsa) { + RNP_LOG("Failed to retrieve DSA key: %lu", ERR_peek_last_error()); + goto done; + } + + const bignum_t *p; + const bignum_t *q; + const bignum_t *g; + const bignum_t *y; + const bignum_t *x; + p = DSA_get0_p(dsa); + q = DSA_get0_q(dsa); + g = DSA_get0_g(dsa); + y = DSA_get0_pub_key(dsa); + x = DSA_get0_priv_key(dsa); + if (!p || !q || !g || !y || !x) { + ret = RNP_ERROR_BAD_STATE; + goto done; + } + bn2mpi(p, &key->p); + bn2mpi(q, &key->q); + bn2mpi(g, &key->g); + bn2mpi(y, &key->y); + bn2mpi(x, &key->x); + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(parmkey); + EVP_PKEY_free(pkey); + return ret; +} + +pgp_hash_alg_t +dsa_get_min_hash(size_t qsize) +{ + /* + * I'm using _broken_ SHA1 here only because + * some old implementations may not understand keys created + * with other hashes. If you're sure we don't have to support + * such implementations, please be my guest and remove it. + */ + return (qsize < 160) ? PGP_HASH_UNKNOWN : + (qsize == 160) ? PGP_HASH_SHA1 : + (qsize <= 224) ? PGP_HASH_SHA224 : + (qsize <= 256) ? PGP_HASH_SHA256 : + (qsize <= 384) ? PGP_HASH_SHA384 : + (qsize <= 512) ? PGP_HASH_SHA512 + /*(qsize>512)*/ : + PGP_HASH_UNKNOWN; +} + +size_t +dsa_choose_qsize_by_psize(size_t psize) +{ + return (psize == 1024) ? 160 : + (psize <= 2047) ? 224 : + (psize <= 3072) ? DSA_MAX_Q_BITLEN : + 0; +} diff --git a/comm/third_party/rnp/src/lib/crypto/ec.cpp b/comm/third_party/rnp/src/lib/crypto/ec.cpp new file mode 100644 index 0000000000..144c362ea5 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ec.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "ec.h" +#include "types.h" +#include "utils.h" +#include "mem.h" +#include "bn.h" + +static id_str_pair ec_algo_to_botan[] = { + {PGP_PKA_ECDH, "ECDH"}, + {PGP_PKA_ECDSA, "ECDSA"}, + {PGP_PKA_SM2, "SM2_Sig"}, + {0, NULL}, +}; + +rnp_result_t +x25519_generate(rnp::RNG *rng, pgp_ec_key_t *key) +{ + botan_privkey_t pr_key = NULL; + botan_pubkey_t pu_key = NULL; + rnp_result_t ret = RNP_ERROR_KEY_GENERATION; + + rnp::secure_array keyle; + + if (botan_privkey_create(&pr_key, "Curve25519", "", rng->handle())) { + goto end; + } + + if (botan_privkey_export_pubkey(&pu_key, pr_key)) { + goto end; + } + + /* botan returns key in little-endian, while mpi is big-endian */ + if (botan_privkey_x25519_get_privkey(pr_key, keyle.data())) { + goto end; + } + for (int i = 0; i < 32; i++) { + key->x.mpi[31 - i] = keyle[i]; + } + key->x.len = 32; + /* botan doesn't tweak secret key bits, so we should do that here */ + if (!x25519_tweak_bits(*key)) { + goto end; + } + + if (botan_pubkey_x25519_get_pubkey(pu_key, &key->p.mpi[1])) { + goto end; + } + key->p.len = 33; + key->p.mpi[0] = 0x40; + + ret = RNP_SUCCESS; +end: + botan_privkey_destroy(pr_key); + botan_pubkey_destroy(pu_key); + return ret; +} + +rnp_result_t +ec_generate(rnp::RNG * rng, + pgp_ec_key_t * key, + const pgp_pubkey_alg_t alg_id, + const pgp_curve_t curve) +{ + /** + * Keeps "0x04 || x || y" + * \see 13.2. ECDSA, ECDH, SM2 Conversion Primitives + * + * P-521 is biggest supported curve + */ + botan_privkey_t pr_key = NULL; + botan_pubkey_t pu_key = NULL; + bignum_t * px = NULL; + bignum_t * py = NULL; + bignum_t * x = NULL; + rnp_result_t ret = RNP_ERROR_KEY_GENERATION; + size_t filed_byte_size = 0; + + if (!alg_allows_curve(alg_id, curve)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + const char *ec_algo = id_str_pair::lookup(ec_algo_to_botan, alg_id, NULL); + assert(ec_algo); + const ec_curve_desc_t *ec_desc = get_curve_desc(curve); + if (!ec_desc) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto end; + } + filed_byte_size = BITS_TO_BYTES(ec_desc->bitlen); + + // at this point it must succeed + if (botan_privkey_create(&pr_key, ec_algo, ec_desc->botan_name, rng->handle())) { + goto end; + } + + if (botan_privkey_export_pubkey(&pu_key, pr_key)) { + goto end; + } + + // Crash if seckey is null. It's clean and easy to debug design + px = bn_new(); + py = bn_new(); + x = bn_new(); + + if (!px || !py || !x) { + RNP_LOG("Allocation failed"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto end; + } + + if (botan_pubkey_get_field(BN_HANDLE_PTR(px), pu_key, "public_x")) { + goto end; + } + + if (botan_pubkey_get_field(BN_HANDLE_PTR(py), pu_key, "public_y")) { + goto end; + } + + if (botan_privkey_get_field(BN_HANDLE_PTR(x), pr_key, "x")) { + goto end; + } + + size_t x_bytes; + size_t y_bytes; + x_bytes = bn_num_bytes(*px); + y_bytes = bn_num_bytes(*py); + + // Safety check + if ((x_bytes > filed_byte_size) || (y_bytes > filed_byte_size)) { + RNP_LOG("Key generation failed"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto end; + } + + /* + * Convert coordinates to MPI stored as + * "0x04 || x || y" + * + * \see 13.2. ECDSA and ECDH Conversion Primitives + * + * Note: Generated pk/sk may not always have exact number of bytes + * which is important when converting to octet-string + */ + memset(key->p.mpi, 0, sizeof(key->p.mpi)); + key->p.mpi[0] = 0x04; + bn_bn2bin(px, &key->p.mpi[1 + filed_byte_size - x_bytes]); + bn_bn2bin(py, &key->p.mpi[1 + filed_byte_size + (filed_byte_size - y_bytes)]); + key->p.len = 2 * filed_byte_size + 1; + /* secret key value */ + bn2mpi(x, &key->x); + ret = RNP_SUCCESS; +end: + botan_privkey_destroy(pr_key); + botan_pubkey_destroy(pu_key); + bn_free(px); + bn_free(py); + bn_free(x); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/ec.h b/comm/third_party/rnp/src/lib/crypto/ec.h new file mode 100644 index 0000000000..07cb8e8101 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ec.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EC_H_ +#define EC_H_ + +#include "config.h" +#include +#include +#include "crypto/rng.h" +#include "crypto/mpi.h" + +#define MAX_CURVE_BIT_SIZE 521 // secp521r1 +/* Maximal byte size of elliptic curve order (NIST P-521) */ +#define MAX_CURVE_BYTELEN ((MAX_CURVE_BIT_SIZE + 7) / 8) + +/** + * Maximal length of the OID in hex representation. + * + * \see RFC4880 bis01 - 9.2 ECC Curve OID + */ +#define MAX_CURVE_OID_HEX_LEN 10U + +/** + * Structure holds description of elliptic curve + */ +typedef struct ec_curve_desc_t { + const pgp_curve_t rnp_curve_id; + const size_t bitlen; + const uint8_t OIDhex[MAX_CURVE_OID_HEX_LEN]; + const size_t OIDhex_len; +#if defined(CRYPTO_BACKEND_BOTAN) + const char *botan_name; +#endif +#if defined(CRYPTO_BACKEND_OPENSSL) + const char *openssl_name; +#endif + const char *pgp_name; + /* Curve is supported for keygen/sign/encrypt operations */ + bool supported; + /* Curve parameters below. Needed for grip calculation */ + const char *p; + const char *a; + const char *b; + const char *n; + const char *gx; + const char *gy; + const char *h; +} ec_curve_desc_t; + +typedef struct pgp_ec_key_t { + pgp_curve_t curve; + pgp_mpi_t p; + /* secret mpi */ + pgp_mpi_t x; + /* ecdh params */ + pgp_hash_alg_t kdf_hash_alg; /* Hash used by kdf */ + pgp_symm_alg_t key_wrap_alg; /* Symmetric algorithm used to wrap KEK*/ +} pgp_ec_key_t; + +typedef struct pgp_ec_signature_t { + pgp_mpi_t r; + pgp_mpi_t s; +} pgp_ec_signature_t; + +/* + * @brief Finds curve ID by hex representation of OID + * + * @param oid buffer with OID in hex + * @param oid_len length of oid buffer + * + * @returns success curve ID + * failure PGP_CURVE_MAX is returned + * + * @remarks see RFC 4880 bis 01 - 9.2 ECC Curve OID + */ +pgp_curve_t find_curve_by_OID(const uint8_t *oid, size_t oid_len); + +pgp_curve_t find_curve_by_name(const char *name); + +/* + * @brief Returns pointer to the curve descriptor + * + * @param Valid curve ID + * + * @returns NULL if wrong ID provided, otherwise descriptor + * + */ +const ec_curve_desc_t *get_curve_desc(const pgp_curve_t curve_id); + +bool alg_allows_curve(pgp_pubkey_alg_t alg, pgp_curve_t curve); + +/** + * @brief Check whether curve is supported for operations. + * All available curves are supported for reading/parsing key data, however some of them + * may be disabled for use, i.e. for key generation/signing/encryption. + */ +bool curve_supported(pgp_curve_t curve); + +/* + * @brief Generates EC key in uncompressed format + * + * @param rng initialized rnp::RNG context* + * @param key key data to be generated + * @param alg_id ID of EC algorithm + * @param curve underlying ECC curve ID + * + * @pre alg_id MUST be supported algorithm + * + * @returns RNP_ERROR_BAD_PARAMETERS unknown curve_id + * @returns RNP_ERROR_OUT_OF_MEMORY memory allocation failed + * @returns RNP_ERROR_KEY_GENERATION implementation error + */ +rnp_result_t ec_generate(rnp::RNG * rng, + pgp_ec_key_t * key, + const pgp_pubkey_alg_t alg_id, + const pgp_curve_t curve); + +/* + * @brief Generates x25519 ECDH key in x25519-specific format + * + * @param rng initialized rnp::RNG context* + * @param key key data to be generated + * + * @returns RNP_ERROR_KEY_GENERATION implementation error + */ +rnp_result_t x25519_generate(rnp::RNG *rng, pgp_ec_key_t *key); + +/** + * @brief Set least significant/most significant bits of the 25519 secret key as per + * specification. + * + * @param key secret key. + * @return true on success or false otherwise. + */ +bool x25519_tweak_bits(pgp_ec_key_t &key); + +/** + * @brief Check whether least significant/most significant bits of 25519 secret key are + * correctly tweaked. + * + * @param key secret key. + * @return true if bits are set correctly, and false otherwise. + */ +bool x25519_bits_tweaked(const pgp_ec_key_t &key); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/ec_curves.cpp b/comm/third_party/rnp/src/lib/crypto/ec_curves.cpp new file mode 100644 index 0000000000..db5cf090fe --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ec_curves.cpp @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "ec.h" +#include "types.h" +#include "utils.h" +#include "str-utils.h" + +/** + * EC Curves definition used by implementation + * + * \see RFC4880 bis01 - 9.2. ECC Curve OID + * + * Order of the elements in this array corresponds to + * values in pgp_curve_t enum. + */ +static const ec_curve_desc_t ec_curves[] = { + {PGP_CURVE_UNKNOWN, 0, {0}, 0, NULL, NULL}, + + {PGP_CURVE_NIST_P_256, + 256, + {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}, + 8, +#if defined(CRYPTO_BACKEND_BOTAN) + "secp256r1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "prime256v1", +#endif + "NIST P-256", + true, + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + "0x01"}, + {PGP_CURVE_NIST_P_384, + 384, + {0x2B, 0x81, 0x04, 0x00, 0x22}, + 5, +#if defined(CRYPTO_BACKEND_BOTAN) + "secp384r1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "secp384r1", +#endif + "NIST P-384", + true, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000" + "ffffffff", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000" + "fffffffc", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8ed" + "d3ec2aef", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196a" + "ccc52973", + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e38" + "72760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c" + "90ea0e5f", + "0x01"}, + {PGP_CURVE_NIST_P_521, + 521, + {0x2B, 0x81, 0x04, 0x00, 0x23}, + 5, +#if defined(CRYPTO_BACKEND_BOTAN) + "secp521r1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "secp521r1", +#endif + "NIST P-521", + true, + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffffff", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffc", + "0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652" + "c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc" + "0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1d" + "c127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550" + "b9013fad0761353c7086a272c24088be94769fd16650", + "0x01"}, + {PGP_CURVE_ED25519, + 255, + {0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01}, + 9, +#if defined(CRYPTO_BACKEND_BOTAN) + "Ed25519", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "ED25519", +#endif + "Ed25519", + true, + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", + /* two below are actually negative */ + "0x01", + "0x2dfc9311d490018c7338bf8688861767ff8ff5b2bebe27548a14b235eca6874a", + "0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", + "0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a", + "0x6666666666666666666666666666666666666666666666666666666666666658", + "0x08"}, + {PGP_CURVE_25519, + 255, + {0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}, + 10, +#if defined(CRYPTO_BACKEND_BOTAN) + "curve25519", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "X25519", +#endif + "Curve25519", + true, + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", + "0x01db41", + "0x01", + "0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", + "0x0000000000000000000000000000000000000000000000000000000000000009", + "0x20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9", + "0x08"}, + {PGP_CURVE_BP256, + 256, + {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}, + 9, +#if defined(CRYPTO_BACKEND_BOTAN) + "brainpool256r1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "brainpoolP256r1", +#endif + "brainpoolP256r1", +#if defined(ENABLE_BRAINPOOL) + true, +#else + false, +#endif + "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377", + "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9", + "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6", + "0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7", + "0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262", + "0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997", + "0x01"}, + {PGP_CURVE_BP384, + 384, + {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}, + 9, +#if defined(CRYPTO_BACKEND_BOTAN) + "brainpool384r1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "brainpoolP384r1", +#endif + "brainpoolP384r1", +#if defined(ENABLE_BRAINPOOL) + true, +#else + false, +#endif + "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a7187470013" + "3107ec53", + "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd" + "22ce2826", + "0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696" + "fa504c11", + "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202" + "e9046565", + "0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e2" + "47d4af1e", + "0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341" + "263c5315", + "0x01"}, + {PGP_CURVE_BP512, + 512, + {0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}, + 9, +#if defined(CRYPTO_BACKEND_BOTAN) + "brainpool512r1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "brainpoolP512r1", +#endif + "brainpoolP512r1", +#if defined(ENABLE_BRAINPOOL) + true, +#else + false, +#endif + "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca703308717d4d9b009bc66842aecda12a" + "e6a380e62881ff2f2d82c68528aa6056583a48f3", + "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c9" + "8b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca", + "0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca" + "dc083e67984050b75ebae5dd2809bd638016f723", + "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca9261941866119" + "7fac10471db1d381085ddaddb58796829ca90069", + "0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098eff3b1f78e2d0d48d50d1687b" + "93b97d5f7c6d5047406a5e688b352209bcb9f822", + "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111b2dcde494a5f485e5bca4bd8" + "8a2763aed1ca2b2fa8f0540678cd1e0f3ad80892", + "0x01"}, + {PGP_CURVE_P256K1, + 256, + {0x2B, 0x81, 0x04, 0x00, 0x0A}, + 5, +#if defined(CRYPTO_BACKEND_BOTAN) + "secp256k1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "secp256k1", +#endif + "secp256k1", + true, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", + "0x01"}, + { + PGP_CURVE_SM2_P_256, + 256, + {0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x82, 0x2D}, + 8, +#if defined(CRYPTO_BACKEND_BOTAN) + "sm2p256v1", +#elif defined(CRYPTO_BACKEND_OPENSSL) + "sm2", +#endif + "SM2 P-256", +#if defined(ENABLE_SM2) + true, +#else + false, +#endif + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", + "0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", + "0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", + "0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", + }, +}; + +pgp_curve_t +find_curve_by_OID(const uint8_t *oid, size_t oid_len) +{ + for (size_t i = 0; i < PGP_CURVE_MAX; i++) { + if ((oid_len == ec_curves[i].OIDhex_len) && + (!memcmp(oid, ec_curves[i].OIDhex, oid_len))) { + return static_cast(i); + } + } + + return PGP_CURVE_MAX; +} + +pgp_curve_t +find_curve_by_name(const char *name) +{ + for (size_t i = 1; i < PGP_CURVE_MAX; i++) { + if (rnp::str_case_eq(ec_curves[i].pgp_name, name)) { + return ec_curves[i].rnp_curve_id; + } + } + + return PGP_CURVE_MAX; +} + +const ec_curve_desc_t * +get_curve_desc(const pgp_curve_t curve_id) +{ + return (curve_id < PGP_CURVE_MAX && curve_id > 0) ? &ec_curves[curve_id] : NULL; +} + +bool +alg_allows_curve(pgp_pubkey_alg_t alg, pgp_curve_t curve) +{ + /* SM2 curve is only for SM2 algo */ + if ((alg == PGP_PKA_SM2) || (curve == PGP_CURVE_SM2_P_256)) { + return (alg == PGP_PKA_SM2) && (curve == PGP_CURVE_SM2_P_256); + } + /* EDDSA and PGP_CURVE_ED25519 */ + if ((alg == PGP_PKA_EDDSA) || (curve == PGP_CURVE_ED25519)) { + return (alg == PGP_PKA_EDDSA) && (curve == PGP_CURVE_ED25519); + } + /* Curve x25519 is only for ECDH */ + if (curve == PGP_CURVE_25519) { + return alg == PGP_PKA_ECDH; + } + /* Other curves are good for both ECDH and ECDSA */ + return true; +} + +bool +curve_supported(pgp_curve_t curve) +{ + const ec_curve_desc_t *info = get_curve_desc(curve); + return info && info->supported; +} diff --git a/comm/third_party/rnp/src/lib/crypto/ec_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/ec_ossl.cpp new file mode 100644 index 0000000000..6974b4c210 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ec_ossl.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "ec.h" +#include "ec_ossl.h" +#include "bn.h" +#include "types.h" +#include "mem.h" +#include "utils.h" +#include +#include +#include +#include + +static bool +ec_is_raw_key(const pgp_curve_t curve) +{ + return (curve == PGP_CURVE_ED25519) || (curve == PGP_CURVE_25519); +} + +rnp_result_t +x25519_generate(rnp::RNG *rng, pgp_ec_key_t *key) +{ + return ec_generate(rng, key, PGP_PKA_ECDH, PGP_CURVE_25519); +} + +EVP_PKEY * +ec_generate_pkey(const pgp_pubkey_alg_t alg_id, const pgp_curve_t curve) +{ + if (!alg_allows_curve(alg_id, curve)) { + return NULL; + } + const ec_curve_desc_t *ec_desc = get_curve_desc(curve); + if (!ec_desc) { + return NULL; + } + int nid = OBJ_sn2nid(ec_desc->openssl_name); + if (nid == NID_undef) { + RNP_LOG("Unknown SN: %s", ec_desc->openssl_name); + return NULL; + } + bool raw = ec_is_raw_key(curve); + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(raw ? nid : EVP_PKEY_EC, NULL); + if (!ctx) { + RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); + return NULL; + } + EVP_PKEY *pkey = NULL; + if (EVP_PKEY_keygen_init(ctx) <= 0) { + RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); + goto done; + } + if (!raw && (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) <= 0)) { + RNP_LOG("Failed to set curve nid: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + RNP_LOG("EC keygen failed: %lu", ERR_peek_last_error()); + } +done: + EVP_PKEY_CTX_free(ctx); + return pkey; +} + +static bool +ec_write_raw_seckey(EVP_PKEY *pkey, pgp_ec_key_t *key) +{ + /* EdDSA and X25519 keys are saved in a different way */ + static_assert(sizeof(key->x.mpi) > 32, "mpi is too small."); + key->x.len = sizeof(key->x.mpi); + if (EVP_PKEY_get_raw_private_key(pkey, key->x.mpi, &key->x.len) <= 0) { + RNP_LOG("Failed get raw private key: %lu", ERR_peek_last_error()); + return false; + } + assert(key->x.len == 32); + if (EVP_PKEY_id(pkey) == EVP_PKEY_X25519) { + /* in OpenSSL private key is exported as little-endian, while MPI is big-endian */ + for (size_t i = 0; i < 16; i++) { + std::swap(key->x.mpi[i], key->x.mpi[31 - i]); + } + } + return true; +} + +rnp_result_t +ec_generate(rnp::RNG * rng, + pgp_ec_key_t * key, + const pgp_pubkey_alg_t alg_id, + const pgp_curve_t curve) +{ + EVP_PKEY *pkey = ec_generate_pkey(alg_id, curve); + if (!pkey) { + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_result_t ret = RNP_ERROR_GENERIC; + if (ec_is_raw_key(curve)) { + if (ec_write_pubkey(pkey, key->p, curve) && ec_write_raw_seckey(pkey, key)) { + ret = RNP_SUCCESS; + } + EVP_PKEY_free(pkey); + return ret; + } + const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + if (!ec) { + RNP_LOG("Failed to retrieve EC key: %lu", ERR_peek_last_error()); + goto done; + } + if (!ec_write_pubkey(pkey, key->p, curve)) { + RNP_LOG("Failed to write pubkey."); + goto done; + } + const bignum_t *x; + x = EC_KEY_get0_private_key(ec); + if (!x) { + ret = RNP_ERROR_BAD_STATE; + goto done; + } + if (bn2mpi(x, &key->x)) { + ret = RNP_SUCCESS; + } +done: + EVP_PKEY_free(pkey); + return ret; +} + +static EVP_PKEY * +ec_load_raw_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, int nid) +{ + if (!keyx) { + /* as per RFC, EdDSA & 25519 keys must use 0x40 byte for encoding */ + if ((mpi_bytes(&keyp) != 33) || (keyp.mpi[0] != 0x40)) { + RNP_LOG("Invalid 25519 public key."); + return NULL; + } + + EVP_PKEY *evpkey = + EVP_PKEY_new_raw_public_key(nid, NULL, &keyp.mpi[1], mpi_bytes(&keyp) - 1); + if (!evpkey) { + RNP_LOG("Failed to load public key: %lu", ERR_peek_last_error()); + } + return evpkey; + } + + EVP_PKEY *evpkey = NULL; + if (nid == EVP_PKEY_X25519) { + if (keyx->len != 32) { + RNP_LOG("Invalid 25519 secret key"); + return NULL; + } + /* need to reverse byte order since in mpi we have big-endian */ + rnp::secure_array prkey; + for (int i = 0; i < 32; i++) { + prkey[i] = keyx->mpi[31 - i]; + } + evpkey = EVP_PKEY_new_raw_private_key(nid, NULL, prkey.data(), keyx->len); + } else { + if (keyx->len > 32) { + RNP_LOG("Invalid Ed25519 secret key"); + return NULL; + } + /* keyx->len may be smaller then 32 as high byte is random and could become 0 */ + rnp::secure_array prkey{}; + memcpy(prkey.data() + 32 - keyx->len, keyx->mpi, keyx->len); + evpkey = EVP_PKEY_new_raw_private_key(nid, NULL, prkey.data(), 32); + } + if (!evpkey) { + RNP_LOG("Failed to load private key: %lu", ERR_peek_last_error()); + } + return evpkey; +} + +EVP_PKEY * +ec_load_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, pgp_curve_t curve) +{ + const ec_curve_desc_t *curv_desc = get_curve_desc(curve); + if (!curv_desc) { + RNP_LOG("unknown curve"); + return NULL; + } + if (!curve_supported(curve)) { + RNP_LOG("Curve %s is not supported.", curv_desc->pgp_name); + return NULL; + } + int nid = OBJ_sn2nid(curv_desc->openssl_name); + if (nid == NID_undef) { + RNP_LOG("Unknown SN: %s", curv_desc->openssl_name); + return NULL; + } + /* EdDSA and X25519 keys are loaded in a different way */ + if (ec_is_raw_key(curve)) { + return ec_load_raw_key(keyp, keyx, nid); + } + EC_KEY *ec = EC_KEY_new_by_curve_name(nid); + if (!ec) { + RNP_LOG("Failed to create EC key with group %d (%s): %s", + nid, + curv_desc->openssl_name, + ERR_reason_error_string(ERR_peek_last_error())); + return NULL; + } + + bool res = false; + bignum_t *x = NULL; + EVP_PKEY *pkey = NULL; + EC_POINT *p = EC_POINT_new(EC_KEY_get0_group(ec)); + if (!p) { + RNP_LOG("Failed to allocate point: %lu", ERR_peek_last_error()); + goto done; + } + if (EC_POINT_oct2point(EC_KEY_get0_group(ec), p, keyp.mpi, keyp.len, NULL) <= 0) { + RNP_LOG("Failed to decode point: %lu", ERR_peek_last_error()); + goto done; + } + if (EC_KEY_set_public_key(ec, p) <= 0) { + RNP_LOG("Failed to set public key: %lu", ERR_peek_last_error()); + goto done; + } + + pkey = EVP_PKEY_new(); + if (!pkey) { + RNP_LOG("EVP_PKEY allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + if (!keyx) { + res = true; + goto done; + } + + x = mpi2bn(keyx); + if (!x) { + RNP_LOG("allocation failed"); + goto done; + } + if (EC_KEY_set_private_key(ec, x) <= 0) { + RNP_LOG("Failed to set secret key: %lu", ERR_peek_last_error()); + goto done; + } + res = true; +done: + if (res) { + res = EVP_PKEY_set1_EC_KEY(pkey, ec) > 0; + } + EC_POINT_free(p); + BN_free(x); + EC_KEY_free(ec); + if (!res) { + EVP_PKEY_free(pkey); + pkey = NULL; + } + return pkey; +} + +rnp_result_t +ec_validate_key(const pgp_ec_key_t &key, bool secret) +{ + if (key.curve == PGP_CURVE_25519) { + /* No key check implementation for x25519 in the OpenSSL yet, so just basic size checks + */ + if ((mpi_bytes(&key.p) != 33) || (key.p.mpi[0] != 0x40)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (secret && mpi_bytes(&key.x) != 32) { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; + } + EVP_PKEY *evpkey = ec_load_key(key.p, secret ? &key.x : NULL, key.curve); + if (!evpkey) { + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_result_t ret = RNP_ERROR_GENERIC; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + int res; + res = secret ? EVP_PKEY_check(ctx) : EVP_PKEY_public_check(ctx); + if (res < 0) { + auto err = ERR_peek_last_error(); + RNP_LOG("EC key check failed: %lu (%s)", err, ERR_reason_error_string(err)); + } + if (res > 0) { + ret = RNP_SUCCESS; + } +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(evpkey); + return ret; +} + +bool +ec_write_pubkey(EVP_PKEY *pkey, pgp_mpi_t &mpi, pgp_curve_t curve) +{ + if (ec_is_raw_key(curve)) { + /* EdDSA and X25519 keys are saved in a different way */ + mpi.len = sizeof(mpi.mpi) - 1; + if (EVP_PKEY_get_raw_public_key(pkey, &mpi.mpi[1], &mpi.len) <= 0) { + RNP_LOG("Failed get raw public key: %lu", ERR_peek_last_error()); + return false; + } + assert(mpi.len == 32); + mpi.mpi[0] = 0x40; + mpi.len++; + return true; + } + const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + if (!ec) { + RNP_LOG("Failed to retrieve EC key: %lu", ERR_peek_last_error()); + return false; + } + const EC_POINT *p = EC_KEY_get0_public_key(ec); + if (!p) { + RNP_LOG("Null point: %lu", ERR_peek_last_error()); + return false; + } + /* call below adds leading zeroes if needed */ + mpi.len = EC_POINT_point2oct( + EC_KEY_get0_group(ec), p, POINT_CONVERSION_UNCOMPRESSED, mpi.mpi, sizeof(mpi.mpi), NULL); + if (!mpi.len) { + RNP_LOG("Failed to encode public key: %lu", ERR_peek_last_error()); + } + return mpi.len; +} diff --git a/comm/third_party/rnp/src/lib/crypto/ec_ossl.h b/comm/third_party/rnp/src/lib/crypto/ec_ossl.h new file mode 100644 index 0000000000..f16afe8bd5 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ec_ossl.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EC_OSSL_H_ +#define EC_OSSL_H_ + +#include "types.h" +#include "ec.h" +#include + +EVP_PKEY *ec_load_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, pgp_curve_t curve); + +rnp_result_t ec_validate_key(const pgp_ec_key_t &key, bool secret); + +EVP_PKEY *ec_generate_pkey(const pgp_pubkey_alg_t alg_id, const pgp_curve_t curve); + +bool ec_write_pubkey(EVP_PKEY *key, pgp_mpi_t &mpi, pgp_curve_t curve); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/ecdh.cpp b/comm/third_party/rnp/src/lib/crypto/ecdh.cpp new file mode 100644 index 0000000000..d4411c39f0 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdh.cpp @@ -0,0 +1,377 @@ +/*- + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "hash_botan.hpp" +#include "ecdh.h" +#include "ecdh_utils.h" +#include "symmetric.h" +#include "types.h" +#include "utils.h" +#include "mem.h" +#include "bn.h" + +// Produces kek of size kek_len which corresponds to length of wrapping key +static bool +compute_kek(uint8_t * kek, + size_t kek_len, + const uint8_t * other_info, + size_t other_info_size, + const ec_curve_desc_t *curve_desc, + const pgp_mpi_t * ec_pubkey, + const botan_privkey_t ec_prvkey, + const pgp_hash_alg_t hash_alg) +{ + const uint8_t *p = ec_pubkey->mpi; + uint8_t p_len = ec_pubkey->len; + + if (curve_desc->rnp_curve_id == PGP_CURVE_25519) { + if ((p_len != 33) || (p[0] != 0x40)) { + return false; + } + p++; + p_len--; + } + + rnp::secure_array s; + + botan_pk_op_ka_t op_key_agreement = NULL; + bool ret = false; + char kdf_name[32] = {0}; + size_t s_len = s.size(); + + if (botan_pk_op_key_agreement_create(&op_key_agreement, ec_prvkey, "Raw", 0) || + botan_pk_op_key_agreement(op_key_agreement, s.data(), &s_len, p, p_len, NULL, 0)) { + goto end; + } + + snprintf( + kdf_name, sizeof(kdf_name), "SP800-56A(%s)", rnp::Hash_Botan::name_backend(hash_alg)); + ret = !botan_kdf( + kdf_name, kek, kek_len, s.data(), s_len, NULL, 0, other_info, other_info_size); +end: + return ret && !botan_pk_op_key_agreement_destroy(op_key_agreement); +} + +static bool +ecdh_load_public_key(botan_pubkey_t *pubkey, const pgp_ec_key_t *key) +{ + bool res = false; + + const ec_curve_desc_t *curve = get_curve_desc(key->curve); + if (!curve) { + RNP_LOG("unknown curve"); + return false; + } + + if (curve->rnp_curve_id == PGP_CURVE_25519) { + if ((key->p.len != 33) || (key->p.mpi[0] != 0x40)) { + return false; + } + rnp::secure_array pkey; + memcpy(pkey.data(), key->p.mpi + 1, 32); + return !botan_pubkey_load_x25519(pubkey, pkey.data()); + } + + if (!mpi_bytes(&key->p) || (key->p.mpi[0] != 0x04)) { + RNP_LOG("Failed to load public key"); + return false; + } + + botan_mp_t px = NULL; + botan_mp_t py = NULL; + const size_t curve_order = BITS_TO_BYTES(curve->bitlen); + + if (botan_mp_init(&px) || botan_mp_init(&py) || + botan_mp_from_bin(px, &key->p.mpi[1], curve_order) || + botan_mp_from_bin(py, &key->p.mpi[1 + curve_order], curve_order)) { + goto end; + } + + if (!(res = !botan_pubkey_load_ecdh(pubkey, px, py, curve->botan_name))) { + RNP_LOG("failed to load ecdh public key"); + } +end: + botan_mp_destroy(px); + botan_mp_destroy(py); + return res; +} + +static bool +ecdh_load_secret_key(botan_privkey_t *seckey, const pgp_ec_key_t *key) +{ + const ec_curve_desc_t *curve = get_curve_desc(key->curve); + + if (!curve) { + return false; + } + + if (curve->rnp_curve_id == PGP_CURVE_25519) { + if (key->x.len != 32) { + RNP_LOG("wrong x25519 key"); + return false; + } + /* need to reverse byte order since in mpi we have big-endian */ + rnp::secure_array prkey; + for (int i = 0; i < 32; i++) { + prkey[i] = key->x.mpi[31 - i]; + } + return !botan_privkey_load_x25519(seckey, prkey.data()); + } + + bignum_t *x = NULL; + if (!(x = mpi2bn(&key->x))) { + return false; + } + bool res = !botan_privkey_load_ecdh(seckey, BN_HANDLE_PTR(x), curve->botan_name); + bn_free(x); + return res; +} + +rnp_result_t +ecdh_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + botan_pubkey_t bpkey = NULL; + botan_privkey_t bskey = NULL; + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + + const ec_curve_desc_t *curve_desc = get_curve_desc(key->curve); + if (!curve_desc) { + return RNP_ERROR_NOT_SUPPORTED; + } + + if (!ecdh_load_public_key(&bpkey, key) || + botan_pubkey_check_key(bpkey, rng->handle(), 0)) { + goto done; + } + if (!secret) { + ret = RNP_SUCCESS; + goto done; + } + + if (!ecdh_load_secret_key(&bskey, key) || + botan_privkey_check_key(bskey, rng->handle(), 0)) { + goto done; + } + ret = RNP_SUCCESS; +done: + botan_privkey_destroy(bskey); + botan_pubkey_destroy(bpkey); + return ret; +} + +rnp_result_t +ecdh_encrypt_pkcs5(rnp::RNG * rng, + pgp_ecdh_encrypted_t * out, + const uint8_t *const in, + size_t in_len, + const pgp_ec_key_t * key, + const pgp_fingerprint_t &fingerprint) +{ + botan_privkey_t eph_prv_key = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + uint8_t other_info[MAX_SP800_56A_OTHER_INFO]; + uint8_t kek[32] = {0}; // Size of SHA-256 or smaller + // 'm' is padded to the 8-byte granularity + uint8_t m[MAX_SESSION_KEY_SIZE]; + const size_t m_padded_len = ((in_len / 8) + 1) * 8; + + if (!key || !out || !in || (in_len > sizeof(m))) { + return RNP_ERROR_BAD_PARAMETERS; + } +#if !defined(ENABLE_SM2) + if (key->curve == PGP_CURVE_SM2_P_256) { + RNP_LOG("SM2 curve support is disabled."); + return RNP_ERROR_NOT_IMPLEMENTED; + } +#endif + const ec_curve_desc_t *curve_desc = get_curve_desc(key->curve); + if (!curve_desc) { + RNP_LOG("unsupported curve"); + return RNP_ERROR_NOT_SUPPORTED; + } + + // +8 because of AES-wrap adds 8 bytes + if (ECDH_WRAPPED_KEY_SIZE < (m_padded_len + 8)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + // See 13.5 of RFC 4880 for definition of other_info_size + const size_t other_info_size = curve_desc->OIDhex_len + 46; + const size_t kek_len = pgp_key_size(key->key_wrap_alg); + size_t tmp_len = kdf_other_info_serialize( + other_info, curve_desc, fingerprint, key->kdf_hash_alg, key->key_wrap_alg); + + if (tmp_len != other_info_size) { + RNP_LOG("Serialization of other info failed"); + return RNP_ERROR_GENERIC; + } + + if (!strcmp(curve_desc->botan_name, "curve25519")) { + if (botan_privkey_create(&eph_prv_key, "Curve25519", "", rng->handle())) { + goto end; + } + } else { + if (botan_privkey_create( + &eph_prv_key, "ECDH", curve_desc->botan_name, rng->handle())) { + goto end; + } + } + + if (!compute_kek(kek, + kek_len, + other_info, + other_info_size, + curve_desc, + &key->p, + eph_prv_key, + key->kdf_hash_alg)) { + RNP_LOG("KEK computation failed"); + goto end; + } + + memcpy(m, in, in_len); + if (!pad_pkcs7(m, m_padded_len, in_len)) { + // Should never happen + goto end; + } + + out->mlen = sizeof(out->m); + if (botan_key_wrap3394(m, m_padded_len, kek, kek_len, out->m, &out->mlen)) { + goto end; + } + + /* we need to prepend 0x40 for the x25519 */ + if (key->curve == PGP_CURVE_25519) { + out->p.len = sizeof(out->p.mpi) - 1; + if (botan_pk_op_key_agreement_export_public( + eph_prv_key, out->p.mpi + 1, &out->p.len)) { + goto end; + } + out->p.mpi[0] = 0x40; + out->p.len++; + } else { + out->p.len = sizeof(out->p.mpi); + if (botan_pk_op_key_agreement_export_public(eph_prv_key, out->p.mpi, &out->p.len)) { + goto end; + } + } + + // All OK + ret = RNP_SUCCESS; +end: + botan_privkey_destroy(eph_prv_key); + return ret; +} + +rnp_result_t +ecdh_decrypt_pkcs5(uint8_t * out, + size_t * out_len, + const pgp_ecdh_encrypted_t *in, + const pgp_ec_key_t * key, + const pgp_fingerprint_t & fingerprint) +{ + if (!out_len || !in || !key || !mpi_bytes(&key->x)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + const ec_curve_desc_t *curve_desc = get_curve_desc(key->curve); + if (!curve_desc) { + RNP_LOG("unknown curve"); + return RNP_ERROR_NOT_SUPPORTED; + } + + const pgp_symm_alg_t wrap_alg = key->key_wrap_alg; + const pgp_hash_alg_t kdf_hash = key->kdf_hash_alg; + /* Ensure that AES is used for wrapping */ + if ((wrap_alg != PGP_SA_AES_128) && (wrap_alg != PGP_SA_AES_192) && + (wrap_alg != PGP_SA_AES_256)) { + RNP_LOG("non-aes wrap algorithm"); + return RNP_ERROR_NOT_SUPPORTED; + } + + // See 13.5 of RFC 4880 for definition of other_info_size + uint8_t other_info[MAX_SP800_56A_OTHER_INFO]; + const size_t other_info_size = curve_desc->OIDhex_len + 46; + const size_t tmp_len = + kdf_other_info_serialize(other_info, curve_desc, fingerprint, kdf_hash, wrap_alg); + + if (other_info_size != tmp_len) { + RNP_LOG("Serialization of other info failed"); + return RNP_ERROR_GENERIC; + } + + botan_privkey_t prv_key = NULL; + if (!ecdh_load_secret_key(&prv_key, key)) { + RNP_LOG("failed to load ecdh secret key"); + return RNP_ERROR_GENERIC; + } + + // Size of SHA-256 or smaller + rnp::secure_array kek; + rnp::secure_array deckey; + + size_t deckey_len = deckey.size(); + size_t offset = 0; + rnp_result_t ret = RNP_ERROR_GENERIC; + + /* Security: Always return same error code in case compute_kek, + * botan_key_unwrap3394 or unpad_pkcs7 fails + */ + size_t kek_len = pgp_key_size(wrap_alg); + if (!compute_kek(kek.data(), + kek_len, + other_info, + other_info_size, + curve_desc, + &in->p, + prv_key, + kdf_hash)) { + goto end; + } + + if (botan_key_unwrap3394( + in->m, in->mlen, kek.data(), kek_len, deckey.data(), &deckey_len)) { + goto end; + } + + if (!unpad_pkcs7(deckey.data(), deckey_len, &offset)) { + goto end; + } + + if (*out_len < offset) { + ret = RNP_ERROR_SHORT_BUFFER; + goto end; + } + + *out_len = offset; + memcpy(out, deckey.data(), *out_len); + ret = RNP_SUCCESS; +end: + botan_privkey_destroy(prv_key); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/ecdh.h b/comm/third_party/rnp/src/lib/crypto/ecdh.h new file mode 100644 index 0000000000..017e1e69e5 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdh.h @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2017 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECDH_H_ +#define ECDH_H_ + +#include "crypto/ec.h" + +/* Max size of wrapped and obfuscated key size + * + * RNP pads a key with PKCS-5 always to 8 byte granularity, + * then 8 bytes is added by AES-wrap (RFC3394). + */ +#define ECDH_WRAPPED_KEY_SIZE 48 + +/* Forward declarations */ +typedef struct pgp_fingerprint_t pgp_fingerprint_t; + +typedef struct pgp_ecdh_encrypted_t { + pgp_mpi_t p; + uint8_t m[ECDH_WRAPPED_KEY_SIZE]; + size_t mlen; +} pgp_ecdh_encrypted_t; + +rnp_result_t ecdh_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret); + +/* + * @brief Sets hash algorithm and key wrapping algo + * based on curve_id + * + * @param key ec key to set parameters for + * @param curve underlying ECC curve ID + * + * @returns false if curve is not supported, otherwise true + */ +bool ecdh_set_params(pgp_ec_key_t *key, pgp_curve_t curve_id); + +/* + * Encrypts session key with a KEK agreed during ECDH as specified in + * RFC 4880 bis 01, 13.5 + * + * @param rng initialized rnp::RNG object + * @param session_key key to be encrypted + * @param session_key_len length of the key buffer + * @param wrapped_key [out] resulting key wrapped in by some AES + * as specified in RFC 3394 + * @param wrapped_key_len [out] length of the `wrapped_key' buffer + * Current implementation always produces 48 bytes as key + * is padded with PKCS-5/7 + * @param ephemeral_key [out] public ephemeral ECDH key used for key + * agreement (private part). Must be initialized + * @param pubkey public key to be used for encryption + * @param fingerprint fingerprint of the pubkey + * + * @return RNP_SUCCESS on success and output parameters are populated + * @return RNP_ERROR_NOT_SUPPORTED unknown curve + * @return RNP_ERROR_BAD_PARAMETERS unexpected input provided + * @return RNP_ERROR_SHORT_BUFFER `wrapped_key_len' to small to store result + * @return RNP_ERROR_GENERIC implementation error + */ +rnp_result_t ecdh_encrypt_pkcs5(rnp::RNG * rng, + pgp_ecdh_encrypted_t * out, + const uint8_t *const in, + size_t in_len, + const pgp_ec_key_t * key, + const pgp_fingerprint_t &fingerprint); + +/* + * Decrypts session key with a KEK agreed during ECDH as specified in + * RFC 4880 bis 01, 13.5 + * + * @param session_key [out] resulting session key + * @param session_key_len [out] length of the resulting session key + * @param wrapped_key session key wrapped with some AES as specified + * in RFC 3394 + * @param wrapped_key_len length of the `wrapped_key' buffer + * @param ephemeral_key public ephemeral ECDH key coming from + * encrypted packet. + * @param seckey secret key to be used for decryption + * @param fingerprint fingerprint of the key + * + * @return RNP_SUCCESS on success and output parameters are populated + * @return RNP_ERROR_NOT_SUPPORTED unknown curve + * @return RNP_ERROR_BAD_PARAMETERS unexpected input provided + * @return RNP_ERROR_SHORT_BUFFER `session_key_len' to small to store result + * @return RNP_ERROR_GENERIC decryption failed or implementation error + */ +rnp_result_t ecdh_decrypt_pkcs5(uint8_t * out, + size_t * out_len, + const pgp_ecdh_encrypted_t *in, + const pgp_ec_key_t * key, + const pgp_fingerprint_t & fingerprint); + +#endif // ECDH_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/ecdh_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/ecdh_ossl.cpp new file mode 100644 index 0000000000..60b7260456 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdh_ossl.cpp @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2021-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "ecdh.h" +#include "ecdh_utils.h" +#include "ec_ossl.h" +#include "hash.hpp" +#include "symmetric.h" +#include "types.h" +#include "utils.h" +#include "logging.h" +#include "mem.h" +#include +#include + +static const struct ecdh_wrap_alg_map_t { + pgp_symm_alg_t alg; + const char * name; +} ecdh_wrap_alg_map[] = {{PGP_SA_AES_128, "aes128-wrap"}, + {PGP_SA_AES_192, "aes192-wrap"}, + {PGP_SA_AES_256, "aes256-wrap"}}; + +rnp_result_t +ecdh_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + return ec_validate_key(*key, secret); +} + +static rnp_result_t +ecdh_derive_kek(uint8_t * x, + size_t xlen, + const pgp_ec_key_t & key, + const pgp_fingerprint_t &fingerprint, + uint8_t * kek, + const size_t kek_len) +{ + const ec_curve_desc_t *curve_desc = get_curve_desc(key.curve); + if (!curve_desc) { + RNP_LOG("unsupported curve"); + return RNP_ERROR_NOT_SUPPORTED; + } + + // Serialize other info, see 13.5 of RFC 4880 bis + uint8_t other_info[MAX_SP800_56A_OTHER_INFO]; + const size_t hash_len = rnp::Hash::size(key.kdf_hash_alg); + if (!hash_len) { + // must not assert here as kdf/hash algs are not checked during key parsing + RNP_LOG("Unsupported key wrap hash algorithm."); + return RNP_ERROR_NOT_SUPPORTED; + } + size_t other_len = kdf_other_info_serialize( + other_info, curve_desc, fingerprint, key.kdf_hash_alg, key.key_wrap_alg); + // Self-check + assert(other_len == curve_desc->OIDhex_len + 46); + // Derive KEK, using the KDF from SP800-56A + rnp::secure_array dgst; + assert(hash_len <= PGP_MAX_HASH_SIZE); + size_t reps = (kek_len + hash_len - 1) / hash_len; + // As we use AES & SHA2 we should not get more then 2 iterations + if (reps > 2) { + RNP_LOG("Invalid key wrap/hash alg combination."); + return RNP_ERROR_NOT_SUPPORTED; + } + size_t have = 0; + try { + for (size_t i = 1; i <= reps; i++) { + auto hash = rnp::Hash::create(key.kdf_hash_alg); + hash->add(i); + hash->add(x, xlen); + hash->add(other_info, other_len); + hash->finish(dgst.data()); + size_t bytes = std::min(hash_len, kek_len - have); + memcpy(kek + have, dgst.data(), bytes); + have += bytes; + } + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("Failed to derive kek: %s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +static rnp_result_t +ecdh_rfc3394_wrap_ctx(EVP_CIPHER_CTX **ctx, + pgp_symm_alg_t wrap_alg, + const uint8_t * key, + bool decrypt) +{ + /* get OpenSSL EVP cipher for key wrap */ + const char *cipher_name = NULL; + ARRAY_LOOKUP_BY_ID(ecdh_wrap_alg_map, alg, name, wrap_alg, cipher_name); + if (!cipher_name) { + RNP_LOG("Unsupported key wrap algorithm: %d", (int) wrap_alg); + return RNP_ERROR_NOT_SUPPORTED; + } + const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipher_name); + if (!cipher) { + RNP_LOG("Cipher %s is not supported by OpenSSL.", cipher_name); + return RNP_ERROR_NOT_SUPPORTED; + } + *ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + RNP_LOG("Context allocation failed : %lu", ERR_peek_last_error()); + return RNP_ERROR_OUT_OF_MEMORY; + } + EVP_CIPHER_CTX_set_flags(*ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + int res = decrypt ? EVP_DecryptInit_ex(*ctx, cipher, NULL, key, NULL) : + EVP_EncryptInit_ex(*ctx, cipher, NULL, key, NULL); + if (res <= 0) { + RNP_LOG("Failed to initialize cipher : %lu", ERR_peek_last_error()); + EVP_CIPHER_CTX_free(*ctx); + *ctx = NULL; + return RNP_ERROR_GENERIC; + } + return RNP_SUCCESS; +} + +static rnp_result_t +ecdh_rfc3394_wrap(uint8_t * out, + size_t * out_len, + const uint8_t *const in, + size_t in_len, + const uint8_t * key, + pgp_symm_alg_t wrap_alg) +{ + EVP_CIPHER_CTX *ctx = NULL; + rnp_result_t ret = ecdh_rfc3394_wrap_ctx(&ctx, wrap_alg, key, false); + if (ret) { + RNP_LOG("Wrap context initialization failed."); + return ret; + } + int intlen = *out_len; + /* encrypts in one pass, no final is needed */ + int res = EVP_EncryptUpdate(ctx, out, &intlen, in, in_len); + if (res <= 0) { + RNP_LOG("Failed to encrypt data : %lu", ERR_peek_last_error()); + } else { + *out_len = intlen; + } + EVP_CIPHER_CTX_free(ctx); + return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC; +} + +static rnp_result_t +ecdh_rfc3394_unwrap(uint8_t * out, + size_t * out_len, + const uint8_t *const in, + size_t in_len, + const uint8_t * key, + pgp_symm_alg_t wrap_alg) +{ + if ((in_len < 16) || (in_len % 8)) { + RNP_LOG("Invalid wrapped key size."); + return RNP_ERROR_GENERIC; + } + EVP_CIPHER_CTX *ctx = NULL; + rnp_result_t ret = ecdh_rfc3394_wrap_ctx(&ctx, wrap_alg, key, true); + if (ret) { + RNP_LOG("Unwrap context initialization failed."); + return ret; + } + int intlen = *out_len; + /* decrypts in one pass, no final is needed */ + int res = EVP_DecryptUpdate(ctx, out, &intlen, in, in_len); + if (res <= 0) { + RNP_LOG("Failed to decrypt data : %lu", ERR_peek_last_error()); + } else { + *out_len = intlen; + } + EVP_CIPHER_CTX_free(ctx); + return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC; +} + +static bool +ecdh_derive_secret(EVP_PKEY *sec, EVP_PKEY *peer, uint8_t *x, size_t *xlen) +{ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(sec, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + return false; + } + bool res = false; + if (EVP_PKEY_derive_init(ctx) <= 0) { + RNP_LOG("Key derivation init failed: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_derive_set_peer(ctx, peer) <= 0) { + RNP_LOG("Peer setting failed: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_derive(ctx, x, xlen) <= 0) { + RNP_LOG("Failed to obtain shared secret size: %lu", ERR_peek_last_error()); + goto done; + } + res = true; +done: + EVP_PKEY_CTX_free(ctx); + return res; +} + +static size_t +ecdh_kek_len(pgp_symm_alg_t wrap_alg) +{ + switch (wrap_alg) { + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + return pgp_key_size(wrap_alg); + default: + return 0; + } +} + +rnp_result_t +ecdh_encrypt_pkcs5(rnp::RNG * rng, + pgp_ecdh_encrypted_t * out, + const uint8_t *const in, + size_t in_len, + const pgp_ec_key_t * key, + const pgp_fingerprint_t &fingerprint) +{ + if (!key || !out || !in || (in_len > MAX_SESSION_KEY_SIZE)) { + return RNP_ERROR_BAD_PARAMETERS; + } +#if !defined(ENABLE_SM2) + if (key->curve == PGP_CURVE_SM2_P_256) { + RNP_LOG("SM2 curve support is disabled."); + return RNP_ERROR_NOT_IMPLEMENTED; + } +#endif + /* check whether we have valid wrap_alg before doing heavy operations */ + size_t keklen = ecdh_kek_len(key->key_wrap_alg); + if (!keklen) { + RNP_LOG("Unsupported key wrap algorithm: %d", (int) key->key_wrap_alg); + return RNP_ERROR_NOT_SUPPORTED; + } + /* load our public key */ + EVP_PKEY *pkey = ec_load_key(key->p, NULL, key->curve); + if (!pkey) { + RNP_LOG("Failed to load public key."); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp::secure_array sec; + rnp::secure_array kek; + rnp::secure_array mpad; + + size_t seclen = sec.size(); + rnp_result_t ret = RNP_ERROR_GENERIC; + /* generate ephemeral key */ + EVP_PKEY *ephkey = ec_generate_pkey(PGP_PKA_ECDH, key->curve); + if (!ephkey) { + RNP_LOG("Failed to generate ephemeral key."); + ret = RNP_ERROR_KEY_GENERATION; + goto done; + } + /* do ECDH derivation */ + if (!ecdh_derive_secret(ephkey, pkey, sec.data(), &seclen)) { + RNP_LOG("ECDH derivation failed."); + goto done; + } + /* here we got x value in sec, deriving kek */ + ret = ecdh_derive_kek(sec.data(), seclen, *key, fingerprint, kek.data(), keklen); + if (ret) { + RNP_LOG("Failed to derive KEK."); + goto done; + } + /* add PKCS#7 padding */ + size_t m_padded_len; + m_padded_len = ((in_len / 8) + 1) * 8; + memcpy(mpad.data(), in, in_len); + if (!pad_pkcs7(mpad.data(), m_padded_len, in_len)) { + RNP_LOG("Failed to add PKCS #7 padding."); + goto done; + } + /* do RFC 3394 AES key wrap */ + static_assert(sizeof(out->m) == ECDH_WRAPPED_KEY_SIZE, "Wrong ECDH wrapped key size."); + out->mlen = ECDH_WRAPPED_KEY_SIZE; + ret = ecdh_rfc3394_wrap( + out->m, &out->mlen, mpad.data(), m_padded_len, kek.data(), key->key_wrap_alg); + if (ret) { + RNP_LOG("Failed to wrap key."); + goto done; + } + /* write ephemeral public key */ + if (!ec_write_pubkey(ephkey, out->p, key->curve)) { + RNP_LOG("Failed to write ec key."); + goto done; + } + ret = RNP_SUCCESS; +done: + EVP_PKEY_free(ephkey); + EVP_PKEY_free(pkey); + return ret; +} + +rnp_result_t +ecdh_decrypt_pkcs5(uint8_t * out, + size_t * out_len, + const pgp_ecdh_encrypted_t *in, + const pgp_ec_key_t * key, + const pgp_fingerprint_t & fingerprint) +{ + if (!out || !out_len || !in || !key || !mpi_bytes(&key->x)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* check whether we have valid wrap_alg before doing heavy operations */ + size_t keklen = ecdh_kek_len(key->key_wrap_alg); + if (!keklen) { + RNP_LOG("Unsupported key wrap algorithm: %d", (int) key->key_wrap_alg); + return RNP_ERROR_NOT_SUPPORTED; + } + /* load ephemeral public key */ + EVP_PKEY *ephkey = ec_load_key(in->p, NULL, key->curve); + if (!ephkey) { + RNP_LOG("Failed to load ephemeral public key."); + return RNP_ERROR_BAD_PARAMETERS; + } + /* load our secret key */ + rnp::secure_array sec; + rnp::secure_array kek; + rnp::secure_array mpad; + + size_t seclen = sec.size(); + size_t mpadlen = mpad.size(); + rnp_result_t ret = RNP_ERROR_GENERIC; + EVP_PKEY * pkey = ec_load_key(key->p, &key->x, key->curve); + if (!pkey) { + RNP_LOG("Failed to load secret key."); + ret = RNP_ERROR_BAD_PARAMETERS; + goto done; + } + /* do ECDH derivation */ + if (!ecdh_derive_secret(pkey, ephkey, sec.data(), &seclen)) { + RNP_LOG("ECDH derivation failed."); + goto done; + } + /* here we got x value in sec, deriving kek */ + ret = ecdh_derive_kek(sec.data(), seclen, *key, fingerprint, kek.data(), keklen); + if (ret) { + RNP_LOG("Failed to derive KEK."); + goto done; + } + /* do RFC 3394 AES key unwrap */ + ret = ecdh_rfc3394_unwrap( + mpad.data(), &mpadlen, in->m, in->mlen, kek.data(), key->key_wrap_alg); + if (ret) { + RNP_LOG("Failed to unwrap key."); + goto done; + } + /* remove PKCS#7 padding */ + if (!unpad_pkcs7(mpad.data(), mpadlen, &mpadlen)) { + RNP_LOG("Failed to unpad key."); + goto done; + } + assert(mpadlen <= *out_len); + *out_len = mpadlen; + memcpy(out, mpad.data(), mpadlen); + ret = RNP_SUCCESS; +done: + EVP_PKEY_free(ephkey); + EVP_PKEY_free(pkey); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/ecdh_utils.cpp b/comm/third_party/rnp/src/lib/crypto/ecdh_utils.cpp new file mode 100644 index 0000000000..3ceb153f2e --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdh_utils.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ecdh_utils.h" +#include "types.h" +#include "utils.h" +#include + +/* Used by ECDH keys. Specifies which hash and wrapping algorithm + * to be used (see point 15. of RFC 4880). + * + * Note: sync with ec_curves. + */ +static const struct ecdh_params_t { + pgp_curve_t curve; /* Curve ID */ + pgp_hash_alg_t hash; /* Hash used by kdf */ + pgp_symm_alg_t wrap_alg; /* Symmetric algorithm used to wrap KEK*/ +} ecdh_params[] = { + {PGP_CURVE_NIST_P_256, PGP_HASH_SHA256, PGP_SA_AES_128}, + {PGP_CURVE_NIST_P_384, PGP_HASH_SHA384, PGP_SA_AES_192}, + {PGP_CURVE_NIST_P_521, PGP_HASH_SHA512, PGP_SA_AES_256}, + {PGP_CURVE_BP256, PGP_HASH_SHA256, PGP_SA_AES_128}, + {PGP_CURVE_BP384, PGP_HASH_SHA384, PGP_SA_AES_192}, + {PGP_CURVE_BP512, PGP_HASH_SHA512, PGP_SA_AES_256}, + {PGP_CURVE_25519, PGP_HASH_SHA256, PGP_SA_AES_128}, + {PGP_CURVE_P256K1, PGP_HASH_SHA256, PGP_SA_AES_128}, +}; + +// "Anonymous Sender " in hex +static const unsigned char ANONYMOUS_SENDER[] = {0x41, 0x6E, 0x6F, 0x6E, 0x79, 0x6D, 0x6F, + 0x75, 0x73, 0x20, 0x53, 0x65, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x20, 0x20, 0x20}; + +// returns size of data written to other_info +size_t +kdf_other_info_serialize(uint8_t other_info[MAX_SP800_56A_OTHER_INFO], + const ec_curve_desc_t * ec_curve, + const pgp_fingerprint_t &fingerprint, + const pgp_hash_alg_t kdf_hash, + const pgp_symm_alg_t wrap_alg) +{ + assert(fingerprint.length >= 20); + uint8_t *buf_ptr = &other_info[0]; + + /* KDF-OtherInfo: AlgorithmID + * Current implementation will always use SHA-512 and AES-256 for KEK wrapping + */ + *(buf_ptr++) = ec_curve->OIDhex_len; + memcpy(buf_ptr, ec_curve->OIDhex, ec_curve->OIDhex_len); + buf_ptr += ec_curve->OIDhex_len; + *(buf_ptr++) = PGP_PKA_ECDH; + // size of following 3 params (each 1 byte) + *(buf_ptr++) = 0x03; + // Value reserved for future use + *(buf_ptr++) = 0x01; + // Hash used with KDF + *(buf_ptr++) = kdf_hash; + // Algorithm ID used for key wrapping + *(buf_ptr++) = wrap_alg; + + /* KDF-OtherInfo: PartyUInfo + * 20 bytes representing "Anonymous Sender " + */ + memcpy(buf_ptr, ANONYMOUS_SENDER, sizeof(ANONYMOUS_SENDER)); + buf_ptr += sizeof(ANONYMOUS_SENDER); + + // keep 20, as per spec + memcpy(buf_ptr, fingerprint.fingerprint, 20); + return (buf_ptr - other_info) + 20 /*anonymous_sender*/; +} + +bool +pad_pkcs7(uint8_t *buf, size_t buf_len, size_t offset) +{ + if (buf_len <= offset) { + // Must have at least 1 byte of padding + return false; + } + + const uint8_t pad_byte = buf_len - offset; + memset(buf + offset, pad_byte, pad_byte); + return true; +} + +bool +unpad_pkcs7(uint8_t *buf, size_t buf_len, size_t *offset) +{ + if (!buf || !offset || !buf_len) { + return false; + } + + uint8_t err = 0; + const uint8_t pad_byte = buf[buf_len - 1]; + const uint32_t pad_begin = buf_len - pad_byte; + + // TODO: Still >, <, and <=,== are not constant time (maybe?) + err |= (pad_byte > buf_len); + err |= (pad_byte == 0); + + /* Check if padding is OK */ + for (size_t c = 0; c < buf_len; c++) { + err |= (buf[c] ^ pad_byte) * (pad_begin <= c); + } + + *offset = pad_begin; + return (err == 0); +} + +bool +ecdh_set_params(pgp_ec_key_t *key, pgp_curve_t curve_id) +{ + for (size_t i = 0; i < ARRAY_SIZE(ecdh_params); i++) { + if (ecdh_params[i].curve == curve_id) { + key->kdf_hash_alg = ecdh_params[i].hash; + key->key_wrap_alg = ecdh_params[i].wrap_alg; + return true; + } + } + + return false; +} + +bool +x25519_tweak_bits(pgp_ec_key_t &key) +{ + if (key.x.len != 32) { + return false; + } + /* MPI is big-endian, while raw x25519 key is little-endian */ + key.x.mpi[31] &= 248; // zero 3 low bits + key.x.mpi[0] &= 127; // zero high bit + key.x.mpi[0] |= 64; // set high - 1 bit + return true; +} + +bool +x25519_bits_tweaked(const pgp_ec_key_t &key) +{ + if (key.x.len != 32) { + return false; + } + return !(key.x.mpi[31] & 7) && (key.x.mpi[0] < 128) && (key.x.mpi[0] >= 64); +} diff --git a/comm/third_party/rnp/src/lib/crypto/ecdh_utils.h b/comm/third_party/rnp/src/lib/crypto/ecdh_utils.h new file mode 100644 index 0000000000..2d37a713b7 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdh_utils.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECDH_UTILS_H_ +#define ECDH_UTILS_H_ + +#include "ecdh.h" + +#define MAX_SP800_56A_OTHER_INFO 56 +// Keys up to 312 bits (+1 bytes of PKCS5 padding) +#define MAX_SESSION_KEY_SIZE 40 +#define MAX_AES_KEY_SIZE 32 + +size_t kdf_other_info_serialize(uint8_t other_info[MAX_SP800_56A_OTHER_INFO], + const ec_curve_desc_t * ec_curve, + const pgp_fingerprint_t &fingerprint, + const pgp_hash_alg_t kdf_hash, + const pgp_symm_alg_t wrap_alg); + +bool pad_pkcs7(uint8_t *buf, size_t buf_len, size_t offset); + +bool unpad_pkcs7(uint8_t *buf, size_t buf_len, size_t *offset); + +#endif // ECDH_UTILS_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/ecdsa.cpp b/comm/third_party/rnp/src/lib/crypto/ecdsa.cpp new file mode 100644 index 0000000000..cffce12ba7 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdsa.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ecdsa.h" +#include "utils.h" +#include +#include +#include "bn.h" + +static bool +ecdsa_load_public_key(botan_pubkey_t *pubkey, const pgp_ec_key_t *keydata) +{ + botan_mp_t px = NULL; + botan_mp_t py = NULL; + bool res = false; + + const ec_curve_desc_t *curve = get_curve_desc(keydata->curve); + if (!curve) { + RNP_LOG("unknown curve"); + return false; + } + const size_t curve_order = BITS_TO_BYTES(curve->bitlen); + + if (!mpi_bytes(&keydata->p) || (keydata->p.mpi[0] != 0x04)) { + RNP_LOG( + "Failed to load public key: %zu, %02x", mpi_bytes(&keydata->p), keydata->p.mpi[0]); + return false; + } + + if (botan_mp_init(&px) || botan_mp_init(&py) || + botan_mp_from_bin(px, &keydata->p.mpi[1], curve_order) || + botan_mp_from_bin(py, &keydata->p.mpi[1 + curve_order], curve_order)) { + goto end; + } + + if (!(res = !botan_pubkey_load_ecdsa(pubkey, px, py, curve->botan_name))) { + RNP_LOG("failed to load ecdsa public key"); + } +end: + botan_mp_destroy(px); + botan_mp_destroy(py); + return res; +} + +static bool +ecdsa_load_secret_key(botan_privkey_t *seckey, const pgp_ec_key_t *keydata) +{ + const ec_curve_desc_t *curve; + bignum_t * x = NULL; + bool res = false; + + if (!(curve = get_curve_desc(keydata->curve))) { + return false; + } + if (!(x = mpi2bn(&keydata->x))) { + return false; + } + if (!(res = !botan_privkey_load_ecdsa(seckey, BN_HANDLE_PTR(x), curve->botan_name))) { + RNP_LOG("Can't load private key"); + } + bn_free(x); + return res; +} + +rnp_result_t +ecdsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + botan_pubkey_t bpkey = NULL; + botan_privkey_t bskey = NULL; + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + + if (!ecdsa_load_public_key(&bpkey, key) || + botan_pubkey_check_key(bpkey, rng->handle(), 0)) { + goto done; + } + if (!secret) { + ret = RNP_SUCCESS; + goto done; + } + + if (!ecdsa_load_secret_key(&bskey, key) || + botan_privkey_check_key(bskey, rng->handle(), 0)) { + goto done; + } + ret = RNP_SUCCESS; +done: + botan_privkey_destroy(bskey); + botan_pubkey_destroy(bpkey); + return ret; +} + +static const char * +ecdsa_padding_str_for(pgp_hash_alg_t hash_alg) +{ + switch (hash_alg) { + case PGP_HASH_MD5: + return "Raw(MD5)"; + case PGP_HASH_SHA1: + return "Raw(SHA-1)"; + case PGP_HASH_RIPEMD: + return "Raw(RIPEMD-160)"; + + case PGP_HASH_SHA256: + return "Raw(SHA-256)"; + case PGP_HASH_SHA384: + return "Raw(SHA-384)"; + case PGP_HASH_SHA512: + return "Raw(SHA-512)"; + case PGP_HASH_SHA224: + return "Raw(SHA-224)"; + case PGP_HASH_SHA3_256: + return "Raw(SHA3(256))"; + case PGP_HASH_SHA3_512: + return "Raw(SHA3(512))"; + + case PGP_HASH_SM3: + return "Raw(SM3)"; + default: + return "Raw"; + } +} + +rnp_result_t +ecdsa_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key) +{ + botan_pk_op_sign_t signer = NULL; + botan_privkey_t b_key = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + uint8_t out_buf[2 * MAX_CURVE_BYTELEN] = {0}; + const ec_curve_desc_t *curve = get_curve_desc(key->curve); + const char * padding_str = ecdsa_padding_str_for(hash_alg); + + if (!curve) { + return RNP_ERROR_BAD_PARAMETERS; + } + const size_t curve_order = BITS_TO_BYTES(curve->bitlen); + size_t sig_len = 2 * curve_order; + + if (!ecdsa_load_secret_key(&b_key, key)) { + RNP_LOG("Can't load private key"); + goto end; + } + + if (botan_pk_op_sign_create(&signer, b_key, padding_str, 0)) { + goto end; + } + + if (botan_pk_op_sign_update(signer, hash, hash_len)) { + goto end; + } + + if (botan_pk_op_sign_finish(signer, rng->handle(), out_buf, &sig_len)) { + RNP_LOG("Signing failed"); + goto end; + } + + // Allocate memory and copy results + if (mem2mpi(&sig->r, out_buf, curve_order) && + mem2mpi(&sig->s, out_buf + curve_order, curve_order)) { + ret = RNP_SUCCESS; + } +end: + botan_privkey_destroy(b_key); + botan_pk_op_sign_destroy(signer); + return ret; +} + +rnp_result_t +ecdsa_verify(const pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key) +{ + botan_pubkey_t pub = NULL; + botan_pk_op_verify_t verifier = NULL; + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + uint8_t sign_buf[2 * MAX_CURVE_BYTELEN] = {0}; + size_t r_blen, s_blen; + const char * padding_str = ecdsa_padding_str_for(hash_alg); + + const ec_curve_desc_t *curve = get_curve_desc(key->curve); + if (!curve) { + RNP_LOG("unknown curve"); + return RNP_ERROR_BAD_PARAMETERS; + } + const size_t curve_order = BITS_TO_BYTES(curve->bitlen); + + if (!ecdsa_load_public_key(&pub, key)) { + goto end; + } + + if (botan_pk_op_verify_create(&verifier, pub, padding_str, 0)) { + goto end; + } + + if (botan_pk_op_verify_update(verifier, hash, hash_len)) { + goto end; + } + + r_blen = mpi_bytes(&sig->r); + s_blen = mpi_bytes(&sig->s); + if ((r_blen > curve_order) || (s_blen > curve_order) || + (curve_order > MAX_CURVE_BYTELEN)) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto end; + } + + // Both can't fail + mpi2mem(&sig->r, &sign_buf[curve_order - r_blen]); + mpi2mem(&sig->s, &sign_buf[curve_order + curve_order - s_blen]); + + if (!botan_pk_op_verify_finish(verifier, sign_buf, curve_order * 2)) { + ret = RNP_SUCCESS; + } +end: + botan_pubkey_destroy(pub); + botan_pk_op_verify_destroy(verifier); + return ret; +} + +pgp_hash_alg_t +ecdsa_get_min_hash(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_NIST_P_256: + case PGP_CURVE_BP256: + case PGP_CURVE_P256K1: + return PGP_HASH_SHA256; + case PGP_CURVE_NIST_P_384: + case PGP_CURVE_BP384: + return PGP_HASH_SHA384; + case PGP_CURVE_NIST_P_521: + case PGP_CURVE_BP512: + return PGP_HASH_SHA512; + default: + return PGP_HASH_UNKNOWN; + } +} diff --git a/comm/third_party/rnp/src/lib/crypto/ecdsa.h b/comm/third_party/rnp/src/lib/crypto/ecdsa.h new file mode 100644 index 0000000000..aebfe6a68f --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdsa.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2017 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECDSA_H_ +#define ECDSA_H_ + +#include "crypto/ec.h" + +rnp_result_t ecdsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret); + +rnp_result_t ecdsa_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key); + +rnp_result_t ecdsa_verify(const pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key); + +/* + * @brief Returns hash which should be used with the curve + * + * @param curve Curve ID + * + * @returns Either ID of the hash algorithm, or PGP_HASH_UNKNOWN + * if not found + */ +pgp_hash_alg_t ecdsa_get_min_hash(pgp_curve_t curve); + +#endif // ECDSA_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/ecdsa_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/ecdsa_ossl.cpp new file mode 100644 index 0000000000..534811ad32 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ecdsa_ossl.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ecdsa.h" +#include "utils.h" +#include +#include "bn.h" +#include "ec_ossl.h" +#include +#include +#include + +static bool +ecdsa_decode_sig(const uint8_t *data, size_t len, pgp_ec_signature_t &sig) +{ + ECDSA_SIG *esig = d2i_ECDSA_SIG(NULL, &data, len); + if (!esig) { + RNP_LOG("Failed to parse ECDSA sig: %lu", ERR_peek_last_error()); + return false; + } + const BIGNUM *r, *s; + ECDSA_SIG_get0(esig, &r, &s); + bn2mpi(r, &sig.r); + bn2mpi(s, &sig.s); + ECDSA_SIG_free(esig); + return true; +} + +static bool +ecdsa_encode_sig(uint8_t *data, size_t *len, const pgp_ec_signature_t &sig) +{ + bool res = false; + ECDSA_SIG *dsig = ECDSA_SIG_new(); + BIGNUM * r = mpi2bn(&sig.r); + BIGNUM * s = mpi2bn(&sig.s); + if (!dsig || !r || !s) { + RNP_LOG("Allocation failed."); + goto done; + } + ECDSA_SIG_set0(dsig, r, s); + r = NULL; + s = NULL; + int outlen; + outlen = i2d_ECDSA_SIG(dsig, &data); + if (outlen < 0) { + RNP_LOG("Failed to encode signature."); + goto done; + } + *len = outlen; + res = true; +done: + ECDSA_SIG_free(dsig); + BN_free(r); + BN_free(s); + return res; +} + +rnp_result_t +ecdsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + return ec_validate_key(*key, secret); +} + +rnp_result_t +ecdsa_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key) +{ + if (mpi_bytes(&key->x) == 0) { + RNP_LOG("private key not set"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* Load secret key to DSA structure*/ + EVP_PKEY *evpkey = ec_load_key(key->p, &key->x, key->curve); + if (!evpkey) { + RNP_LOG("Failed to load key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + /* init context and sign */ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_sign_init(ctx) <= 0) { + RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error()); + goto done; + } + sig->s.len = PGP_MPINT_SIZE; + if (EVP_PKEY_sign(ctx, sig->s.mpi, &sig->s.len, hash, hash_len) <= 0) { + RNP_LOG("Signing failed: %lu", ERR_peek_last_error()); + sig->s.len = 0; + goto done; + } + if (!ecdsa_decode_sig(&sig->s.mpi[0], sig->s.len, *sig)) { + RNP_LOG("Failed to parse ECDSA sig: %lu", ERR_peek_last_error()); + goto done; + } + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(evpkey); + return ret; +} + +rnp_result_t +ecdsa_verify(const pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key) +{ + /* Load secret key to DSA structure*/ + EVP_PKEY *evpkey = ec_load_key(key->p, NULL, key->curve); + if (!evpkey) { + RNP_LOG("Failed to load key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + /* init context and sign */ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_verify_init(ctx) <= 0) { + RNP_LOG("Failed to initialize verify: %lu", ERR_peek_last_error()); + goto done; + } + pgp_mpi_t sigbuf; + if (!ecdsa_encode_sig(sigbuf.mpi, &sigbuf.len, *sig)) { + goto done; + } + if (EVP_PKEY_verify(ctx, sigbuf.mpi, sigbuf.len, hash, hash_len) > 0) { + ret = RNP_SUCCESS; + } +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(evpkey); + return ret; +} + +pgp_hash_alg_t +ecdsa_get_min_hash(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_NIST_P_256: + case PGP_CURVE_BP256: + case PGP_CURVE_P256K1: + return PGP_HASH_SHA256; + case PGP_CURVE_NIST_P_384: + case PGP_CURVE_BP384: + return PGP_HASH_SHA384; + case PGP_CURVE_NIST_P_521: + case PGP_CURVE_BP512: + return PGP_HASH_SHA512; + default: + return PGP_HASH_UNKNOWN; + } +} diff --git a/comm/third_party/rnp/src/lib/crypto/eddsa.cpp b/comm/third_party/rnp/src/lib/crypto/eddsa.cpp new file mode 100644 index 0000000000..8669180861 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/eddsa.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "eddsa.h" +#include "utils.h" + +static bool +eddsa_load_public_key(botan_pubkey_t *pubkey, const pgp_ec_key_t *keydata) +{ + if (keydata->curve != PGP_CURVE_ED25519) { + return false; + } + /* + * See draft-ietf-openpgp-rfc4880bis-01 section 13.3 + */ + if ((mpi_bytes(&keydata->p) != 33) || (keydata->p.mpi[0] != 0x40)) { + return false; + } + if (botan_pubkey_load_ed25519(pubkey, keydata->p.mpi + 1)) { + return false; + } + + return true; +} + +static bool +eddsa_load_secret_key(botan_privkey_t *seckey, const pgp_ec_key_t *keydata) +{ + uint8_t keybuf[32] = {0}; + size_t sz; + + if (keydata->curve != PGP_CURVE_ED25519) { + return false; + } + sz = mpi_bytes(&keydata->x); + if (!sz || (sz > 32)) { + return false; + } + mpi2mem(&keydata->x, keybuf + 32 - sz); + if (botan_privkey_load_ed25519(seckey, keybuf)) { + return false; + } + + return true; +} + +rnp_result_t +eddsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + botan_pubkey_t bpkey = NULL; + botan_privkey_t bskey = NULL; + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + + if (!eddsa_load_public_key(&bpkey, key) || + botan_pubkey_check_key(bpkey, rng->handle(), 0)) { + goto done; + } + + if (!secret) { + ret = RNP_SUCCESS; + goto done; + } + + if (!eddsa_load_secret_key(&bskey, key) || + botan_privkey_check_key(bskey, rng->handle(), 0)) { + goto done; + } + ret = RNP_SUCCESS; +done: + botan_privkey_destroy(bskey); + botan_pubkey_destroy(bpkey); + return ret; +} + +rnp_result_t +eddsa_generate(rnp::RNG *rng, pgp_ec_key_t *key) +{ + botan_privkey_t eddsa = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + uint8_t key_bits[64]; + + if (botan_privkey_create(&eddsa, "Ed25519", NULL, rng->handle()) != 0) { + goto end; + } + + if (botan_privkey_ed25519_get_privkey(eddsa, key_bits)) { + goto end; + } + + // First 32 bytes of key_bits are the EdDSA seed (private key) + // Second 32 bytes are the EdDSA public key + + mem2mpi(&key->x, key_bits, 32); + // insert the required 0x40 prefix on the public key + key_bits[31] = 0x40; + mem2mpi(&key->p, key_bits + 31, 33); + key->curve = PGP_CURVE_ED25519; + + ret = RNP_SUCCESS; +end: + botan_privkey_destroy(eddsa); + return ret; +} + +rnp_result_t +eddsa_verify(const pgp_ec_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key) +{ + botan_pubkey_t eddsa = NULL; + botan_pk_op_verify_t verify_op = NULL; + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + uint8_t bn_buf[64] = {0}; + + if (!eddsa_load_public_key(&eddsa, key)) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto done; + } + + if (botan_pk_op_verify_create(&verify_op, eddsa, "Pure", 0) != 0) { + goto done; + } + + if (botan_pk_op_verify_update(verify_op, hash, hash_len) != 0) { + goto done; + } + + // Unexpected size for Ed25519 signature + if ((mpi_bytes(&sig->r) > 32) || (mpi_bytes(&sig->s) > 32)) { + goto done; + } + mpi2mem(&sig->r, &bn_buf[32 - mpi_bytes(&sig->r)]); + mpi2mem(&sig->s, &bn_buf[64 - mpi_bytes(&sig->s)]); + + if (botan_pk_op_verify_finish(verify_op, bn_buf, 64) == 0) { + ret = RNP_SUCCESS; + } +done: + botan_pk_op_verify_destroy(verify_op); + botan_pubkey_destroy(eddsa); + return ret; +} + +rnp_result_t +eddsa_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key) +{ + botan_privkey_t eddsa = NULL; + botan_pk_op_sign_t sign_op = NULL; + rnp_result_t ret = RNP_ERROR_SIGNING_FAILED; + uint8_t bn_buf[64] = {0}; + size_t sig_size = sizeof(bn_buf); + + if (!eddsa_load_secret_key(&eddsa, key)) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto done; + } + + if (botan_pk_op_sign_create(&sign_op, eddsa, "Pure", 0) != 0) { + goto done; + } + + if (botan_pk_op_sign_update(sign_op, hash, hash_len) != 0) { + goto done; + } + + if (botan_pk_op_sign_finish(sign_op, rng->handle(), bn_buf, &sig_size) != 0) { + goto done; + } + + // Unexpected size... + if (sig_size != 64) { + goto done; + } + + mem2mpi(&sig->r, bn_buf, 32); + mem2mpi(&sig->s, bn_buf + 32, 32); + ret = RNP_SUCCESS; +done: + botan_pk_op_sign_destroy(sign_op); + botan_privkey_destroy(eddsa); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/eddsa.h b/comm/third_party/rnp/src/lib/crypto/eddsa.h new file mode 100644 index 0000000000..7410a2806d --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/eddsa.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_ED25519_H_ +#define RNP_ED25519_H_ + +#include "ec.h" + +rnp_result_t eddsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret); +/* + * curve_len must be 255 currently (for Ed25519) + * If Ed448 was supported in the future curve_len=448 would also be allowed. + */ +rnp_result_t eddsa_generate(rnp::RNG *rng, pgp_ec_key_t *key); + +rnp_result_t eddsa_verify(const pgp_ec_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key); + +rnp_result_t eddsa_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/eddsa_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/eddsa_ossl.cpp new file mode 100644 index 0000000000..16d8fad704 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/eddsa_ossl.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "eddsa.h" +#include "ec.h" +#include "ec_ossl.h" +#include "utils.h" +#include "bn.h" +#include +#include +#include +#include + +rnp_result_t +eddsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + /* Not implemented in the OpenSSL, so just do basic size checks. */ + if ((mpi_bytes(&key->p) != 33) || (key->p.mpi[0] != 0x40)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (secret && mpi_bytes(&key->x) > 32) { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} + +rnp_result_t +eddsa_generate(rnp::RNG *rng, pgp_ec_key_t *key) +{ + rnp_result_t ret = ec_generate(rng, key, PGP_PKA_EDDSA, PGP_CURVE_ED25519); + if (!ret) { + key->curve = PGP_CURVE_ED25519; + } + return ret; +} + +rnp_result_t +eddsa_verify(const pgp_ec_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key) +{ + if ((mpi_bytes(&sig->r) > 32) || (mpi_bytes(&sig->s) > 32)) { + RNP_LOG("Invalid EdDSA signature."); + return RNP_ERROR_BAD_PARAMETERS; + } + if ((mpi_bytes(&key->p) != 33) || (key->p.mpi[0] != 0x40)) { + RNP_LOG("Invalid EdDSA public key."); + return RNP_ERROR_BAD_PARAMETERS; + } + + EVP_PKEY *evpkey = ec_load_key(key->p, NULL, PGP_CURVE_ED25519); + if (!evpkey) { + RNP_LOG("Failed to load key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + uint8_t sigbuf[64] = {0}; + /* init context and sign */ + EVP_PKEY_CTX *ctx = NULL; + EVP_MD_CTX * md = EVP_MD_CTX_new(); + if (!md) { + RNP_LOG("Failed to allocate MD ctx: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_DigestVerifyInit(md, &ctx, NULL, NULL, evpkey) <= 0) { + RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error()); + goto done; + } + mpi2mem(&sig->r, &sigbuf[32 - mpi_bytes(&sig->r)]); + mpi2mem(&sig->s, &sigbuf[64 - mpi_bytes(&sig->s)]); + + if (EVP_DigestVerify(md, sigbuf, 64, hash, hash_len) > 0) { + ret = RNP_SUCCESS; + } +done: + /* line below will also free ctx */ + EVP_MD_CTX_free(md); + EVP_PKEY_free(evpkey); + return ret; +} + +rnp_result_t +eddsa_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key) +{ + if (!mpi_bytes(&key->x)) { + RNP_LOG("private key not set"); + return RNP_ERROR_BAD_PARAMETERS; + } + EVP_PKEY *evpkey = ec_load_key(key->p, &key->x, PGP_CURVE_ED25519); + if (!evpkey) { + RNP_LOG("Failed to load private key: %lu", ERR_peek_last_error()); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + /* init context and sign */ + EVP_PKEY_CTX *ctx = NULL; + EVP_MD_CTX * md = EVP_MD_CTX_new(); + if (!md) { + RNP_LOG("Failed to allocate MD ctx: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_DigestSignInit(md, &ctx, NULL, NULL, evpkey) <= 0) { + RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error()); + goto done; + } + static_assert((sizeof(sig->r.mpi) == PGP_MPINT_SIZE) && (PGP_MPINT_SIZE >= 64), + "invalid mpi type/size"); + sig->r.len = PGP_MPINT_SIZE; + if (EVP_DigestSign(md, sig->r.mpi, &sig->r.len, hash, hash_len) <= 0) { + RNP_LOG("Signing failed: %lu", ERR_peek_last_error()); + sig->r.len = 0; + goto done; + } + assert(sig->r.len == 64); + sig->r.len = 32; + sig->s.len = 32; + memcpy(sig->s.mpi, &sig->r.mpi[32], 32); + ret = RNP_SUCCESS; +done: + /* line below will also free ctx */ + EVP_MD_CTX_free(md); + EVP_PKEY_free(evpkey); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/elgamal.cpp b/comm/third_party/rnp/src/lib/crypto/elgamal.cpp new file mode 100644 index 0000000000..acebf4d684 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/elgamal.cpp @@ -0,0 +1,302 @@ +/*- + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "elgamal.h" +#include "utils.h" +#include "bn.h" + +// Max supported key byte size +#define ELGAMAL_MAX_P_BYTELEN BITS_TO_BYTES(PGP_MPINT_BITS) + +static bool +elgamal_load_public_key(botan_pubkey_t *pubkey, const pgp_eg_key_t *keydata) +{ + bignum_t *p = NULL; + bignum_t *g = NULL; + bignum_t *y = NULL; + bool res = false; + + // Check if provided public key byte size is not greater than ELGAMAL_MAX_P_BYTELEN. + if (mpi_bytes(&keydata->p) > ELGAMAL_MAX_P_BYTELEN) { + goto done; + } + + if (!(p = mpi2bn(&keydata->p)) || !(g = mpi2bn(&keydata->g)) || + !(y = mpi2bn(&keydata->y))) { + goto done; + } + + res = + !botan_pubkey_load_elgamal(pubkey, BN_HANDLE_PTR(p), BN_HANDLE_PTR(g), BN_HANDLE_PTR(y)); +done: + bn_free(p); + bn_free(g); + bn_free(y); + return res; +} + +static bool +elgamal_load_secret_key(botan_privkey_t *seckey, const pgp_eg_key_t *keydata) +{ + bignum_t *p = NULL; + bignum_t *g = NULL; + bignum_t *x = NULL; + bool res = false; + + // Check if provided secret key byte size is not greater than ELGAMAL_MAX_P_BYTELEN. + if (mpi_bytes(&keydata->p) > ELGAMAL_MAX_P_BYTELEN) { + goto done; + } + + if (!(p = mpi2bn(&keydata->p)) || !(g = mpi2bn(&keydata->g)) || + !(x = mpi2bn(&keydata->x))) { + goto done; + } + + res = !botan_privkey_load_elgamal( + seckey, BN_HANDLE_PTR(p), BN_HANDLE_PTR(g), BN_HANDLE_PTR(x)); +done: + bn_free(p); + bn_free(g); + bn_free(x); + return res; +} + +bool +elgamal_validate_key(const pgp_eg_key_t *key, bool secret) +{ + // Check if provided public key byte size is not greater than ELGAMAL_MAX_P_BYTELEN. + if (mpi_bytes(&key->p) > ELGAMAL_MAX_P_BYTELEN) { + return false; + } + + /* Use custom validation since we added some custom validation, and Botan has slow test for + * prime for p */ + try { + Botan::BigInt p(key->p.mpi, key->p.len); + Botan::BigInt g(key->g.mpi, key->g.len); + + /* 1 < g < p */ + if ((g.cmp_word(1) != 1) || (g.cmp(p) != -1)) { + return false; + } + /* g ^ (p - 1) = 1 mod p */ + if (Botan::power_mod(g, p - 1, p).cmp_word(1)) { + return false; + } + /* check for small order subgroups */ + Botan::Modular_Reducer reducer(p); + Botan::BigInt v = g; + for (size_t i = 2; i < (1 << 17); i++) { + v = reducer.multiply(v, g); + if (!v.cmp_word(1)) { + RNP_LOG("Small subgroup detected. Order %zu", i); + return false; + } + } + if (!secret) { + return true; + } + /* check that g ^ x = y (mod p) */ + Botan::BigInt y(key->y.mpi, key->y.len); + Botan::BigInt x(key->x.mpi, key->x.len); + return Botan::power_mod(g, x, p) == y; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +rnp_result_t +elgamal_encrypt_pkcs1(rnp::RNG * rng, + pgp_eg_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const pgp_eg_key_t *key) +{ + botan_pubkey_t b_key = NULL; + botan_pk_op_encrypt_t op_ctx = NULL; + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + /* Max size of an output len is twice an order of underlying group (p length) */ + uint8_t enc_buf[ELGAMAL_MAX_P_BYTELEN * 2] = {0}; + size_t p_len; + + if (!elgamal_load_public_key(&b_key, key)) { + RNP_LOG("Failed to load public key"); + goto end; + } + + /* Size of output buffer must be equal to twice the size of key byte len. + * as ElGamal encryption outputs concatenation of two components, both + * of size equal to size of public key byte len. + * Successful call to botan's ElGamal encryption will return output that's + * always 2*pubkey size. + */ + p_len = mpi_bytes(&key->p) * 2; + + if (botan_pk_op_encrypt_create(&op_ctx, b_key, "PKCS1v15", 0) || + botan_pk_op_encrypt(op_ctx, rng->handle(), enc_buf, &p_len, in, in_len)) { + RNP_LOG("Failed to create operation context"); + goto end; + } + + /* + * Botan's ElGamal formats the g^k and msg*(y^k) together into a single byte string. + * We have to parse out the two values after encryption, as rnp stores those values + * separatelly. + * + * We don't trim zeros from octet string as it is done before final marshalling + * (add_packet_body_mpi) + * + * We must assume that botan copies even number of bytes to output buffer (to avoid + * memory corruption) + */ + p_len /= 2; + if (mem2mpi(&out->g, enc_buf, p_len) && mem2mpi(&out->m, enc_buf + p_len, p_len)) { + ret = RNP_SUCCESS; + } +end: + botan_pk_op_encrypt_destroy(op_ctx); + botan_pubkey_destroy(b_key); + return ret; +} + +rnp_result_t +elgamal_decrypt_pkcs1(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_eg_encrypted_t *in, + const pgp_eg_key_t * key) +{ + botan_privkey_t b_key = NULL; + botan_pk_op_decrypt_t op_ctx = NULL; + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + uint8_t enc_buf[ELGAMAL_MAX_P_BYTELEN * 2] = {0}; + size_t p_len; + size_t g_len; + size_t m_len; + + if (!mpi_bytes(&key->x)) { + RNP_LOG("empty secret key"); + goto end; + } + + // Check if provided public key byte size is not greater than ELGAMAL_MAX_P_BYTELEN. + p_len = mpi_bytes(&key->p); + g_len = mpi_bytes(&in->g); + m_len = mpi_bytes(&in->m); + + if ((2 * p_len > sizeof(enc_buf)) || (g_len > p_len) || (m_len > p_len)) { + RNP_LOG("Unsupported/wrong public key or encrypted data"); + goto end; + } + + if (!elgamal_load_secret_key(&b_key, key)) { + RNP_LOG("Failed to load private key"); + goto end; + } + + /* Botan expects ciphertext to be concatenated (g^k | encrypted m). Size must + * be equal to twice the byte size of public key, potentially prepended with zeros. + */ + memcpy(&enc_buf[p_len - g_len], in->g.mpi, g_len); + memcpy(&enc_buf[2 * p_len - m_len], in->m.mpi, m_len); + + *out_len = p_len; + if (botan_pk_op_decrypt_create(&op_ctx, b_key, "PKCS1v15", 0) || + botan_pk_op_decrypt(op_ctx, out, out_len, enc_buf, 2 * p_len)) { + RNP_LOG("Decryption failed"); + goto end; + } + ret = RNP_SUCCESS; +end: + botan_pk_op_decrypt_destroy(op_ctx); + botan_privkey_destroy(b_key); + return ret; +} + +rnp_result_t +elgamal_generate(rnp::RNG *rng, pgp_eg_key_t *key, size_t keybits) +{ + if ((keybits < 1024) || (keybits > PGP_MPINT_BITS)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + botan_privkey_t key_priv = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + bignum_t * p = bn_new(); + bignum_t * g = bn_new(); + bignum_t * y = bn_new(); + bignum_t * x = bn_new(); + + if (!p || !g || !y || !x) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto end; + } + +start: + if (botan_privkey_create_elgamal(&key_priv, rng->handle(), keybits, keybits - 1)) { + RNP_LOG("Wrong parameters"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto end; + } + + if (botan_privkey_get_field(BN_HANDLE_PTR(y), key_priv, "y")) { + RNP_LOG("Failed to obtain public key"); + goto end; + } + if (bn_num_bytes(*y) < BITS_TO_BYTES(keybits)) { + botan_privkey_destroy(key_priv); + goto start; + } + + if (botan_privkey_get_field(BN_HANDLE_PTR(p), key_priv, "p") || + botan_privkey_get_field(BN_HANDLE_PTR(g), key_priv, "g") || + botan_privkey_get_field(BN_HANDLE_PTR(y), key_priv, "y") || + botan_privkey_get_field(BN_HANDLE_PTR(x), key_priv, "x")) { + RNP_LOG("Botan FFI call failed"); + ret = RNP_ERROR_GENERIC; + goto end; + } + + if (bn2mpi(p, &key->p) && bn2mpi(g, &key->g) && bn2mpi(y, &key->y) && bn2mpi(x, &key->x)) { + ret = RNP_SUCCESS; + } +end: + bn_free(p); + bn_free(g); + bn_free(y); + bn_free(x); + botan_privkey_destroy(key_priv); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/elgamal.h b/comm/third_party/rnp/src/lib/crypto/elgamal.h new file mode 100644 index 0000000000..42d05550fb --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/elgamal.h @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_ELG_H_ +#define RNP_ELG_H_ + +#include +#include "crypto/rng.h" +#include "crypto/mpi.h" + +typedef struct pgp_eg_key_t { + pgp_mpi_t p; + pgp_mpi_t g; + pgp_mpi_t y; + /* secret mpi */ + pgp_mpi_t x; +} pgp_eg_key_t; + +typedef struct pgp_eg_signature_t { + /* This is kept only for packet reading. Implementation MUST + * not create elgamal signatures */ + pgp_mpi_t r; + pgp_mpi_t s; +} pgp_eg_signature_t; + +typedef struct pgp_eg_encrypted_t { + pgp_mpi_t g; + pgp_mpi_t m; +} pgp_eg_encrypted_t; + +bool elgamal_validate_key(const pgp_eg_key_t *key, bool secret); + +/* + * Performs ElGamal encryption + * Result of an encryption is composed of two parts - g2k and encm + * + * @param rng initialized rnp::RNG + * @param out encryption result + * @param in plaintext to be encrypted + * @param in_len length of the plaintext + * @param key public key to be used for encryption + * + * @pre out: must be valid pointer to corresponding structure + * @pre in_len: can't be bigger than byte size of `p' + * + * @return RNP_SUCCESS + * RNP_ERROR_OUT_OF_MEMORY allocation failure + * RNP_ERROR_BAD_PARAMETERS wrong input provided + */ +rnp_result_t elgamal_encrypt_pkcs1(rnp::RNG * rng, + pgp_eg_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const pgp_eg_key_t *key); + +/* + * Performs ElGamal decryption + * + * @param rng initialized rnp::RNG + * @param out decrypted plaintext. Must be capable of storing at least as much bytes as p size + * @param out_len number of plaintext bytes written will be put here + * @param in encrypted data + * @param key private key + * + * @pre out, in: must be valid pointers + * @pre out: length must be long enough to store decrypted data. Max size of + * decrypted data is equal to bytes size of `p' + * + * @return RNP_SUCCESS + * RNP_ERROR_OUT_OF_MEMORY allocation failure + * RNP_ERROR_BAD_PARAMETERS wrong input provided + */ +rnp_result_t elgamal_decrypt_pkcs1(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_eg_encrypted_t *in, + const pgp_eg_key_t * key); + +/* + * Generates ElGamal key + * + * @param rng pointer to PRNG + * @param key generated key + * @param keybits key bitlen + * + * @pre `keybits' > 1024 + * + * @returns RNP_ERROR_BAD_PARAMETERS wrong parameters provided + * RNP_ERROR_GENERIC internal error + * RNP_SUCCESS key generated and copied to `seckey' + */ +rnp_result_t elgamal_generate(rnp::RNG *rng, pgp_eg_key_t *key, size_t keybits); +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/elgamal_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/elgamal_ossl.cpp new file mode 100644 index 0000000000..f3fa381fd8 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/elgamal_ossl.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "elgamal.h" +#include "dl_ossl.h" +#include "utils.h" +#include "bn.h" +#include "mem.h" +#include +#include +#include +#include +#include + +// Max supported key byte size +#define ELGAMAL_MAX_P_BYTELEN BITS_TO_BYTES(PGP_MPINT_BITS) + +bool +elgamal_validate_key(const pgp_eg_key_t *key, bool secret) +{ + BN_CTX *ctx = BN_CTX_new(); + if (!ctx) { + RNP_LOG("Allocation failed."); + return false; + } + BN_CTX_start(ctx); + bool res = false; + bignum_t * p = mpi2bn(&key->p); + bignum_t * g = mpi2bn(&key->g); + bignum_t * p1 = BN_CTX_get(ctx); + bignum_t * r = BN_CTX_get(ctx); + bignum_t * y = NULL; + bignum_t * x = NULL; + BN_RECP_CTX *rctx = NULL; + + if (!p || !g || !p1 || !r) { + goto done; + } + + /* 1 < g < p */ + if ((BN_cmp(g, BN_value_one()) != 1) || (BN_cmp(g, p) != -1)) { + RNP_LOG("Invalid g value."); + goto done; + } + /* g ^ (p - 1) = 1 mod p */ + if (!BN_copy(p1, p) || !BN_sub_word(p1, 1) || !BN_mod_exp(r, g, p1, p, ctx)) { + RNP_LOG("g exp failed."); + goto done; + } + if (BN_cmp(r, BN_value_one()) != 0) { + RNP_LOG("Wrong g exp value."); + goto done; + } + /* check for small order subgroups */ + rctx = BN_RECP_CTX_new(); + if (!rctx || !BN_RECP_CTX_set(rctx, p, ctx) || !BN_copy(r, g)) { + RNP_LOG("Failed to init RECP context."); + goto done; + } + for (size_t i = 2; i < (1 << 17); i++) { + if (!BN_mod_mul_reciprocal(r, r, g, rctx, ctx)) { + RNP_LOG("Multiplication failed."); + goto done; + } + if (BN_cmp(r, BN_value_one()) == 0) { + RNP_LOG("Small subgroup detected. Order %zu", i); + goto done; + } + } + if (!secret) { + res = true; + goto done; + } + /* check that g ^ x = y (mod p) */ + x = mpi2bn(&key->x); + y = mpi2bn(&key->y); + if (!x || !y) { + goto done; + } + res = BN_mod_exp(r, g, x, p, ctx) && !BN_cmp(r, y); +done: + BN_CTX_free(ctx); + BN_RECP_CTX_free(rctx); + bn_free(p); + bn_free(g); + bn_free(y); + bn_free(x); + return res; +} + +static bool +pkcs1v15_pad(uint8_t *out, size_t out_len, const uint8_t *in, size_t in_len) +{ + assert(out && in); + if (out_len < in_len + 11) { + return false; + } + out[0] = 0x00; + out[1] = 0x02; + size_t rnd = out_len - in_len - 3; + out[2 + rnd] = 0x00; + if (RAND_bytes(&out[2], rnd) != 1) { + return false; + } + for (size_t i = 2; i < 2 + rnd; i++) { + /* we need non-zero bytes */ + size_t cntr = 16; + while (!out[i] && (cntr--) && (RAND_bytes(&out[i], 1) == 1)) { + } + if (!out[i]) { + RNP_LOG("Something is wrong with RNG."); + return false; + } + } + memcpy(out + rnd + 3, in, in_len); + return true; +} + +static bool +pkcs1v15_unpad(size_t *padlen, const uint8_t *in, size_t in_len, bool skip0) +{ + if (in_len <= (size_t)(11 - skip0)) { + return false; + } + if (!skip0 && in[0]) { + return false; + } + if (in[1 - skip0] != 0x02) { + return false; + } + size_t pad = 2 - skip0; + while ((pad < in_len) && in[pad]) { + pad++; + } + if (pad >= in_len) { + return false; + } + *padlen = pad + 1; + return true; +} + +rnp_result_t +elgamal_encrypt_pkcs1(rnp::RNG * rng, + pgp_eg_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const pgp_eg_key_t *key) +{ + pgp_mpi_t mm = {}; + mm.len = key->p.len; + if (!pkcs1v15_pad(mm.mpi, mm.len, in, in_len)) { + RNP_LOG("Failed to add PKCS1 v1.5 padding."); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_result_t ret = RNP_ERROR_GENERIC; + BN_CTX * ctx = BN_CTX_new(); + if (!ctx) { + RNP_LOG("Allocation failed."); + return RNP_ERROR_OUT_OF_MEMORY; + } + BN_CTX_start(ctx); + BN_MONT_CTX *mctx = BN_MONT_CTX_new(); + bignum_t * m = mpi2bn(&mm); + bignum_t * p = mpi2bn(&key->p); + bignum_t * g = mpi2bn(&key->g); + bignum_t * y = mpi2bn(&key->y); + bignum_t * c1 = BN_CTX_get(ctx); + bignum_t * c2 = BN_CTX_get(ctx); + bignum_t * k = BN_secure_new(); + if (!mctx || !m || !p || !g || !y || !c1 || !c2 || !k) { + RNP_LOG("Allocation failed."); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + /* initialize Montgomery context */ + if (BN_MONT_CTX_set(mctx, p, ctx) < 1) { + RNP_LOG("Failed to setup Montgomery context."); + goto done; + } + int res; + /* must not fail */ + res = BN_rshift1(c1, p); + assert(res == 1); + if (res < 1) { + RNP_LOG("BN_rshift1 failed."); + goto done; + } + /* generate k */ + if (BN_rand_range(k, c1) < 1) { + RNP_LOG("Failed to generate k."); + goto done; + } + /* calculate c1 = g ^ k (mod p) */ + if (BN_mod_exp_mont_consttime(c1, g, k, p, ctx, mctx) < 1) { + RNP_LOG("Exponentiation 1 failed"); + goto done; + } + /* calculate c2 = m * y ^ k (mod p)*/ + if (BN_mod_exp_mont_consttime(c2, y, k, p, ctx, mctx) < 1) { + RNP_LOG("Exponentiation 2 failed"); + goto done; + } + if (BN_mod_mul(c2, c2, m, p, ctx) < 1) { + RNP_LOG("Multiplication failed"); + goto done; + } + res = bn2mpi(c1, &out->g) && bn2mpi(c2, &out->m); + assert(res == 1); + ret = RNP_SUCCESS; +done: + BN_MONT_CTX_free(mctx); + BN_CTX_free(ctx); + bn_free(m); + bn_free(p); + bn_free(g); + bn_free(y); + bn_free(k); + return ret; +} + +rnp_result_t +elgamal_decrypt_pkcs1(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_eg_encrypted_t *in, + const pgp_eg_key_t * key) +{ + if (!mpi_bytes(&key->x)) { + RNP_LOG("Secret key not set."); + return RNP_ERROR_BAD_PARAMETERS; + } + BN_CTX *ctx = BN_CTX_new(); + if (!ctx) { + RNP_LOG("Allocation failed."); + return RNP_ERROR_OUT_OF_MEMORY; + } + pgp_mpi_t mm = {}; + size_t padlen = 0; + rnp_result_t ret = RNP_ERROR_GENERIC; + BN_CTX_start(ctx); + BN_MONT_CTX *mctx = BN_MONT_CTX_new(); + bignum_t * p = mpi2bn(&key->p); + bignum_t * g = mpi2bn(&key->g); + bignum_t * x = mpi2bn(&key->x); + bignum_t * c1 = mpi2bn(&in->g); + bignum_t * c2 = mpi2bn(&in->m); + bignum_t * s = BN_CTX_get(ctx); + bignum_t * m = BN_secure_new(); + if (!mctx || !p || !g || !x || !c1 || !c2 || !m) { + RNP_LOG("Allocation failed."); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + /* initialize Montgomery context */ + if (BN_MONT_CTX_set(mctx, p, ctx) < 1) { + RNP_LOG("Failed to setup Montgomery context."); + goto done; + } + /* calculate s = c1 ^ x (mod p) */ + if (BN_mod_exp_mont_consttime(s, c1, x, p, ctx, mctx) < 1) { + RNP_LOG("Exponentiation 1 failed"); + goto done; + } + /* calculate s^-1 (mod p) */ + BN_set_flags(s, BN_FLG_CONSTTIME); + if (!BN_mod_inverse(s, s, p, ctx)) { + RNP_LOG("Failed to calculate inverse."); + goto done; + } + /* calculate m = c2 * s ^ -1 (mod p)*/ + if (BN_mod_mul(m, c2, s, p, ctx) < 1) { + RNP_LOG("Multiplication failed"); + goto done; + } + bool res; + res = bn2mpi(m, &mm); + assert(res); + if (!res) { + RNP_LOG("bn2mpi failed."); + goto done; + } + /* unpad, handling skipped leftmost 0 case */ + if (!pkcs1v15_unpad(&padlen, mm.mpi, mm.len, mm.len == key->p.len - 1)) { + RNP_LOG("Unpad failed."); + goto done; + } + *out_len = mm.len - padlen; + memcpy(out, &mm.mpi[padlen], *out_len); + ret = RNP_SUCCESS; +done: + secure_clear(mm.mpi, PGP_MPINT_SIZE); + BN_MONT_CTX_free(mctx); + BN_CTX_free(ctx); + bn_free(p); + bn_free(g); + bn_free(x); + bn_free(c1); + bn_free(c2); + bn_free(m); + return ret; +} + +rnp_result_t +elgamal_generate(rnp::RNG *rng, pgp_eg_key_t *key, size_t keybits) +{ + if ((keybits < 1024) || (keybits > PGP_MPINT_BITS)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + const DH * dh = NULL; + EVP_PKEY * pkey = NULL; + EVP_PKEY * parmkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + + /* Generate DH params, which usable for ElGamal as well */ + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); + if (!ctx) { + RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); + return ret; + } + if (EVP_PKEY_paramgen_init(ctx) <= 0) { + RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, keybits) <= 0) { + RNP_LOG("Failed to set key bits: %lu", ERR_peek_last_error()); + goto done; + } + /* OpenSSL correctly handles case with g = 5, making sure that g is primitive root of + * q-group */ + if (EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, DH_GENERATOR_5) <= 0) { + RNP_LOG("Failed to set key generator: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_paramgen(ctx, &parmkey) <= 0) { + RNP_LOG("Failed to generate parameters: %lu", ERR_peek_last_error()); + goto done; + } + EVP_PKEY_CTX_free(ctx); + /* Generate DH (ElGamal) key */ +start: + ctx = EVP_PKEY_CTX_new(parmkey, NULL); + if (!ctx) { + RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_keygen_init(ctx) <= 0) { + RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + RNP_LOG("ElGamal keygen failed: %lu", ERR_peek_last_error()); + goto done; + } + dh = EVP_PKEY_get0_DH(pkey); + if (!dh) { + RNP_LOG("Failed to retrieve DH key: %lu", ERR_peek_last_error()); + goto done; + } + if (BITS_TO_BYTES(BN_num_bits(DH_get0_pub_key(dh))) != BITS_TO_BYTES(keybits)) { + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + goto start; + } + + const bignum_t *p; + const bignum_t *g; + const bignum_t *y; + const bignum_t *x; + p = DH_get0_p(dh); + g = DH_get0_g(dh); + y = DH_get0_pub_key(dh); + x = DH_get0_priv_key(dh); + if (!p || !g || !y || !x) { + ret = RNP_ERROR_BAD_STATE; + goto done; + } + bn2mpi(p, &key->p); + bn2mpi(g, &key->g); + bn2mpi(y, &key->y); + bn2mpi(x, &key->x); + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(parmkey); + EVP_PKEY_free(pkey); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/hash.cpp b/comm/third_party/rnp/src/lib/crypto/hash.cpp new file mode 100644 index 0000000000..250deec8c2 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hash_botan.hpp" +#include "logging.h" +#include + +static const id_str_pair botan_alg_map[] = { + {PGP_HASH_MD5, "MD5"}, + {PGP_HASH_SHA1, "SHA-1"}, + {PGP_HASH_RIPEMD, "RIPEMD-160"}, + {PGP_HASH_SHA256, "SHA-256"}, + {PGP_HASH_SHA384, "SHA-384"}, + {PGP_HASH_SHA512, "SHA-512"}, + {PGP_HASH_SHA224, "SHA-224"}, +#if defined(ENABLE_SM2) + {PGP_HASH_SM3, "SM3"}, +#endif + {PGP_HASH_SHA3_256, "SHA-3(256)"}, + {PGP_HASH_SHA3_512, "SHA-3(512)"}, + {0, NULL}, +}; + +namespace rnp { + +Hash_Botan::Hash_Botan(pgp_hash_alg_t alg) : Hash(alg) +{ + auto name = Hash_Botan::name_backend(alg); + if (!name) { + throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + fn_ = Botan::HashFunction::create(name); + if (!fn_) { + RNP_LOG("Error creating hash object for '%s'", name); + throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + assert(size_ == fn_->output_length()); +} + +Hash_Botan::Hash_Botan(const Hash_Botan &src) : Hash(src.alg_) +{ + if (!src.fn_) { + throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + fn_ = src.fn_->copy_state(); +} + +Hash_Botan::~Hash_Botan() +{ +} + +std::unique_ptr +Hash_Botan::create(pgp_hash_alg_t alg) +{ + return std::unique_ptr(new Hash_Botan(alg)); +} + +std::unique_ptr +Hash_Botan::clone() const +{ + return std::unique_ptr(new Hash_Botan(*this)); +} + +void +Hash_Botan::add(const void *buf, size_t len) +{ + if (!fn_) { + throw rnp_exception(RNP_ERROR_NULL_POINTER); + } + fn_->update(static_cast(buf), len); +} + +size_t +Hash_Botan::finish(uint8_t *digest) +{ + if (!fn_) { + return 0; + } + size_t outlen = size_; + if (digest) { + fn_->final(digest); + } + fn_ = nullptr; + size_ = 0; + return outlen; +} + +const char * +Hash_Botan::name_backend(pgp_hash_alg_t alg) +{ + return id_str_pair::lookup(botan_alg_map, alg); +} + +CRC24_Botan::CRC24_Botan() +{ + fn_ = Botan::HashFunction::create("CRC24"); + if (!fn_) { + RNP_LOG("Error creating CRC24 object"); + throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + assert(3 == fn_->output_length()); +} + +CRC24_Botan::~CRC24_Botan() +{ +} + +std::unique_ptr +CRC24_Botan::create() +{ + return std::unique_ptr(new CRC24_Botan()); +} + +void +CRC24_Botan::add(const void *buf, size_t len) +{ + if (!fn_) { + throw rnp_exception(RNP_ERROR_NULL_POINTER); + } + fn_->update(static_cast(buf), len); +} + +std::array +CRC24_Botan::finish() +{ + if (!fn_) { + throw rnp_exception(RNP_ERROR_NULL_POINTER); + } + std::array crc{}; + fn_->final(crc.data()); + fn_ = nullptr; + return crc; +} + +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/hash.hpp b/comm/third_party/rnp/src/lib/crypto/hash.hpp new file mode 100644 index 0000000000..7fcb817700 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash.hpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_HASH_H_ +#define CRYPTO_HASH_H_ + +#include +#include "types.h" +#include "config.h" +#include +#include +#include + +/** + * Output size (in bytes) of biggest supported hash algo + */ +#define PGP_MAX_HASH_SIZE (64) + +namespace rnp { +class Hash { + protected: + pgp_hash_alg_t alg_; + size_t size_; + Hash(pgp_hash_alg_t alg) : alg_(alg) + { + size_ = Hash::size(alg); + }; + + public: + pgp_hash_alg_t alg() const; + size_t size() const; + + static std::unique_ptr create(pgp_hash_alg_t alg); + virtual std::unique_ptr clone() const = 0; + + virtual void add(const void *buf, size_t len) = 0; + virtual void add(uint32_t val); + virtual void add(const pgp_mpi_t &mpi); + virtual size_t finish(uint8_t *digest = NULL) = 0; + + virtual ~Hash(); + + /* Hash algorithm by string representation from cleartext-signed text */ + static pgp_hash_alg_t alg(const char *name); + /* Hash algorithm representation for cleartext-signed text */ + static const char *name(pgp_hash_alg_t alg); + /* Size of the hash algorithm output or 0 if algorithm is unknown */ + static size_t size(pgp_hash_alg_t alg); +}; + +class CRC24 { + protected: + CRC24(){}; + + public: + static std::unique_ptr create(); + + virtual void add(const void *buf, size_t len) = 0; + virtual std::array finish() = 0; + + virtual ~CRC24(){}; +}; + +class HashList { + public: + std::vector> hashes; + + void add_alg(pgp_hash_alg_t alg); + const Hash *get(pgp_hash_alg_t alg) const; + void add(const void *buf, size_t len); +}; + +} // namespace rnp + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/hash_botan.hpp b/comm/third_party/rnp/src/lib/crypto/hash_botan.hpp new file mode 100644 index 0000000000..942e3a8051 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_botan.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_HASH_BOTAN_HPP_ +#define CRYPTO_HASH_BOTAN_HPP_ + +#include "hash.hpp" +#include + +namespace rnp { +class Hash_Botan : public Hash { + private: + std::unique_ptr fn_; + + Hash_Botan(pgp_hash_alg_t alg); + Hash_Botan(const Hash_Botan &src); + + public: + virtual ~Hash_Botan(); + + static std::unique_ptr create(pgp_hash_alg_t alg); + std::unique_ptr clone() const override; + + void add(const void *buf, size_t len) override; + size_t finish(uint8_t *digest = NULL) override; + + static const char *name_backend(pgp_hash_alg_t alg); +}; + +class CRC24_Botan : public CRC24 { + std::unique_ptr fn_; + CRC24_Botan(); + + public: + virtual ~CRC24_Botan(); + + static std::unique_ptr create(); + + void add(const void *buf, size_t len) override; + std::array finish() override; +}; + +} // namespace rnp + +#endif \ No newline at end of file diff --git a/comm/third_party/rnp/src/lib/crypto/hash_common.cpp b/comm/third_party/rnp/src/lib/crypto/hash_common.cpp new file mode 100644 index 0000000000..69b400b0e9 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_common.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "hash.hpp" +#include "types.h" +#include "utils.h" +#include "str-utils.h" +#include "hash_sha1cd.hpp" +#if defined(CRYPTO_BACKEND_BOTAN) +#include "hash_botan.hpp" +#endif +#if defined(CRYPTO_BACKEND_OPENSSL) +#include "hash_ossl.hpp" +#include "hash_crc24.hpp" +#endif + +static const struct hash_alg_map_t { + pgp_hash_alg_t type; + const char * name; + size_t len; +} hash_alg_map[] = {{PGP_HASH_MD5, "MD5", 16}, + {PGP_HASH_SHA1, "SHA1", 20}, + {PGP_HASH_RIPEMD, "RIPEMD160", 20}, + {PGP_HASH_SHA256, "SHA256", 32}, + {PGP_HASH_SHA384, "SHA384", 48}, + {PGP_HASH_SHA512, "SHA512", 64}, + {PGP_HASH_SHA224, "SHA224", 28}, + {PGP_HASH_SM3, "SM3", 32}, + {PGP_HASH_SHA3_256, "SHA3-256", 32}, + {PGP_HASH_SHA3_512, "SHA3-512", 64}}; + +namespace rnp { + +pgp_hash_alg_t +Hash::alg() const +{ + return alg_; +} + +size_t +Hash::size() const +{ + return Hash::size(alg_); +} + +std::unique_ptr +Hash::create(pgp_hash_alg_t alg) +{ + if (alg == PGP_HASH_SHA1) { + return Hash_SHA1CD::create(); + } +#if !defined(ENABLE_SM2) + if (alg == PGP_HASH_SM3) { + RNP_LOG("SM3 hash is not available."); + throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +#endif +#if defined(CRYPTO_BACKEND_OPENSSL) + return Hash_OpenSSL::create(alg); +#elif defined(CRYPTO_BACKEND_BOTAN) + return Hash_Botan::create(alg); +#else +#error "Crypto backend not specified" +#endif +} + +std::unique_ptr +CRC24::create() +{ +#if defined(CRYPTO_BACKEND_OPENSSL) + return CRC24_RNP::create(); +#elif defined(CRYPTO_BACKEND_BOTAN) + return CRC24_Botan::create(); +#else +#error "Crypto backend not specified" +#endif +} + +void +Hash::add(uint32_t val) +{ + uint8_t ibuf[4]; + STORE32BE(ibuf, val); + add(ibuf, sizeof(ibuf)); +} + +void +Hash::add(const pgp_mpi_t &val) +{ + size_t len = mpi_bytes(&val); + size_t idx = 0; + while ((idx < len) && (!val.mpi[idx])) { + idx++; + } + + if (idx >= len) { + add(0); + return; + } + + add(len - idx); + if (val.mpi[idx] & 0x80) { + uint8_t padbyte = 0; + add(&padbyte, 1); + } + add(val.mpi + idx, len - idx); +} + +Hash::~Hash() +{ +} + +pgp_hash_alg_t +Hash::alg(const char *name) +{ + if (!name) { + return PGP_HASH_UNKNOWN; + } + for (size_t i = 0; i < ARRAY_SIZE(hash_alg_map); i++) { + if (rnp::str_case_eq(name, hash_alg_map[i].name)) { + return hash_alg_map[i].type; + } + } + return PGP_HASH_UNKNOWN; +} + +const char * +Hash::name(pgp_hash_alg_t alg) +{ + const char *ret = NULL; + ARRAY_LOOKUP_BY_ID(hash_alg_map, type, name, alg, ret); + return ret; +} + +size_t +Hash::size(pgp_hash_alg_t alg) +{ + size_t val = 0; + ARRAY_LOOKUP_BY_ID(hash_alg_map, type, len, alg, val); + return val; +} + +void +HashList::add_alg(pgp_hash_alg_t alg) +{ + if (!get(alg)) { + hashes.emplace_back(rnp::Hash::create(alg)); + } +} + +const Hash * +HashList::get(pgp_hash_alg_t alg) const +{ + for (auto &hash : hashes) { + if (hash->alg() == alg) { + return hash.get(); + } + } + return NULL; +} + +void +HashList::add(const void *buf, size_t len) +{ + for (auto &hash : hashes) { + hash->add(buf, len); + } +} + +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/hash_crc24.cpp b/comm/third_party/rnp/src/lib/crypto/hash_crc24.cpp new file mode 100644 index 0000000000..54f4d96ba5 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_crc24.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2017-2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "utils.h" +#include "hash_crc24.hpp" + +static const uint32_t T0[256] = { + 0x00000000, 0x00FB4C86, 0x000DD58A, 0x00F6990C, 0x00E1E693, 0x001AAA15, 0x00EC3319, + 0x00177F9F, 0x003981A1, 0x00C2CD27, 0x0034542B, 0x00CF18AD, 0x00D86732, 0x00232BB4, + 0x00D5B2B8, 0x002EFE3E, 0x00894EC5, 0x00720243, 0x00849B4F, 0x007FD7C9, 0x0068A856, + 0x0093E4D0, 0x00657DDC, 0x009E315A, 0x00B0CF64, 0x004B83E2, 0x00BD1AEE, 0x00465668, + 0x005129F7, 0x00AA6571, 0x005CFC7D, 0x00A7B0FB, 0x00E9D10C, 0x00129D8A, 0x00E40486, + 0x001F4800, 0x0008379F, 0x00F37B19, 0x0005E215, 0x00FEAE93, 0x00D050AD, 0x002B1C2B, + 0x00DD8527, 0x0026C9A1, 0x0031B63E, 0x00CAFAB8, 0x003C63B4, 0x00C72F32, 0x00609FC9, + 0x009BD34F, 0x006D4A43, 0x009606C5, 0x0081795A, 0x007A35DC, 0x008CACD0, 0x0077E056, + 0x00591E68, 0x00A252EE, 0x0054CBE2, 0x00AF8764, 0x00B8F8FB, 0x0043B47D, 0x00B52D71, + 0x004E61F7, 0x00D2A319, 0x0029EF9F, 0x00DF7693, 0x00243A15, 0x0033458A, 0x00C8090C, + 0x003E9000, 0x00C5DC86, 0x00EB22B8, 0x00106E3E, 0x00E6F732, 0x001DBBB4, 0x000AC42B, + 0x00F188AD, 0x000711A1, 0x00FC5D27, 0x005BEDDC, 0x00A0A15A, 0x00563856, 0x00AD74D0, + 0x00BA0B4F, 0x004147C9, 0x00B7DEC5, 0x004C9243, 0x00626C7D, 0x009920FB, 0x006FB9F7, + 0x0094F571, 0x00838AEE, 0x0078C668, 0x008E5F64, 0x007513E2, 0x003B7215, 0x00C03E93, + 0x0036A79F, 0x00CDEB19, 0x00DA9486, 0x0021D800, 0x00D7410C, 0x002C0D8A, 0x0002F3B4, + 0x00F9BF32, 0x000F263E, 0x00F46AB8, 0x00E31527, 0x001859A1, 0x00EEC0AD, 0x00158C2B, + 0x00B23CD0, 0x00497056, 0x00BFE95A, 0x0044A5DC, 0x0053DA43, 0x00A896C5, 0x005E0FC9, + 0x00A5434F, 0x008BBD71, 0x0070F1F7, 0x008668FB, 0x007D247D, 0x006A5BE2, 0x00911764, + 0x00678E68, 0x009CC2EE, 0x00A44733, 0x005F0BB5, 0x00A992B9, 0x0052DE3F, 0x0045A1A0, + 0x00BEED26, 0x0048742A, 0x00B338AC, 0x009DC692, 0x00668A14, 0x00901318, 0x006B5F9E, + 0x007C2001, 0x00876C87, 0x0071F58B, 0x008AB90D, 0x002D09F6, 0x00D64570, 0x0020DC7C, + 0x00DB90FA, 0x00CCEF65, 0x0037A3E3, 0x00C13AEF, 0x003A7669, 0x00148857, 0x00EFC4D1, + 0x00195DDD, 0x00E2115B, 0x00F56EC4, 0x000E2242, 0x00F8BB4E, 0x0003F7C8, 0x004D963F, + 0x00B6DAB9, 0x004043B5, 0x00BB0F33, 0x00AC70AC, 0x00573C2A, 0x00A1A526, 0x005AE9A0, + 0x0074179E, 0x008F5B18, 0x0079C214, 0x00828E92, 0x0095F10D, 0x006EBD8B, 0x00982487, + 0x00636801, 0x00C4D8FA, 0x003F947C, 0x00C90D70, 0x003241F6, 0x00253E69, 0x00DE72EF, + 0x0028EBE3, 0x00D3A765, 0x00FD595B, 0x000615DD, 0x00F08CD1, 0x000BC057, 0x001CBFC8, + 0x00E7F34E, 0x00116A42, 0x00EA26C4, 0x0076E42A, 0x008DA8AC, 0x007B31A0, 0x00807D26, + 0x009702B9, 0x006C4E3F, 0x009AD733, 0x00619BB5, 0x004F658B, 0x00B4290D, 0x0042B001, + 0x00B9FC87, 0x00AE8318, 0x0055CF9E, 0x00A35692, 0x00581A14, 0x00FFAAEF, 0x0004E669, + 0x00F27F65, 0x000933E3, 0x001E4C7C, 0x00E500FA, 0x001399F6, 0x00E8D570, 0x00C62B4E, + 0x003D67C8, 0x00CBFEC4, 0x0030B242, 0x0027CDDD, 0x00DC815B, 0x002A1857, 0x00D154D1, + 0x009F3526, 0x006479A0, 0x0092E0AC, 0x0069AC2A, 0x007ED3B5, 0x00859F33, 0x0073063F, + 0x00884AB9, 0x00A6B487, 0x005DF801, 0x00AB610D, 0x00502D8B, 0x00475214, 0x00BC1E92, + 0x004A879E, 0x00B1CB18, 0x00167BE3, 0x00ED3765, 0x001BAE69, 0x00E0E2EF, 0x00F79D70, + 0x000CD1F6, 0x00FA48FA, 0x0001047C, 0x002FFA42, 0x00D4B6C4, 0x00222FC8, 0x00D9634E, + 0x00CE1CD1, 0x00355057, 0x00C3C95B, 0x003885DD, +}; + +static const uint32_t T1[256] = { + 0x00000000, 0x00488F66, 0x00901ECD, 0x00D891AB, 0x00DB711C, 0x0093FE7A, 0x004B6FD1, + 0x0003E0B7, 0x00B6E338, 0x00FE6C5E, 0x0026FDF5, 0x006E7293, 0x006D9224, 0x00251D42, + 0x00FD8CE9, 0x00B5038F, 0x006CC771, 0x00244817, 0x00FCD9BC, 0x00B456DA, 0x00B7B66D, + 0x00FF390B, 0x0027A8A0, 0x006F27C6, 0x00DA2449, 0x0092AB2F, 0x004A3A84, 0x0002B5E2, + 0x00015555, 0x0049DA33, 0x00914B98, 0x00D9C4FE, 0x00D88EE3, 0x00900185, 0x0048902E, + 0x00001F48, 0x0003FFFF, 0x004B7099, 0x0093E132, 0x00DB6E54, 0x006E6DDB, 0x0026E2BD, + 0x00FE7316, 0x00B6FC70, 0x00B51CC7, 0x00FD93A1, 0x0025020A, 0x006D8D6C, 0x00B44992, + 0x00FCC6F4, 0x0024575F, 0x006CD839, 0x006F388E, 0x0027B7E8, 0x00FF2643, 0x00B7A925, + 0x0002AAAA, 0x004A25CC, 0x0092B467, 0x00DA3B01, 0x00D9DBB6, 0x009154D0, 0x0049C57B, + 0x00014A1D, 0x004B5141, 0x0003DE27, 0x00DB4F8C, 0x0093C0EA, 0x0090205D, 0x00D8AF3B, + 0x00003E90, 0x0048B1F6, 0x00FDB279, 0x00B53D1F, 0x006DACB4, 0x002523D2, 0x0026C365, + 0x006E4C03, 0x00B6DDA8, 0x00FE52CE, 0x00279630, 0x006F1956, 0x00B788FD, 0x00FF079B, + 0x00FCE72C, 0x00B4684A, 0x006CF9E1, 0x00247687, 0x00917508, 0x00D9FA6E, 0x00016BC5, + 0x0049E4A3, 0x004A0414, 0x00028B72, 0x00DA1AD9, 0x009295BF, 0x0093DFA2, 0x00DB50C4, + 0x0003C16F, 0x004B4E09, 0x0048AEBE, 0x000021D8, 0x00D8B073, 0x00903F15, 0x00253C9A, + 0x006DB3FC, 0x00B52257, 0x00FDAD31, 0x00FE4D86, 0x00B6C2E0, 0x006E534B, 0x0026DC2D, + 0x00FF18D3, 0x00B797B5, 0x006F061E, 0x00278978, 0x002469CF, 0x006CE6A9, 0x00B47702, + 0x00FCF864, 0x0049FBEB, 0x0001748D, 0x00D9E526, 0x00916A40, 0x00928AF7, 0x00DA0591, + 0x0002943A, 0x004A1B5C, 0x0096A282, 0x00DE2DE4, 0x0006BC4F, 0x004E3329, 0x004DD39E, + 0x00055CF8, 0x00DDCD53, 0x00954235, 0x002041BA, 0x0068CEDC, 0x00B05F77, 0x00F8D011, + 0x00FB30A6, 0x00B3BFC0, 0x006B2E6B, 0x0023A10D, 0x00FA65F3, 0x00B2EA95, 0x006A7B3E, + 0x0022F458, 0x002114EF, 0x00699B89, 0x00B10A22, 0x00F98544, 0x004C86CB, 0x000409AD, + 0x00DC9806, 0x00941760, 0x0097F7D7, 0x00DF78B1, 0x0007E91A, 0x004F667C, 0x004E2C61, + 0x0006A307, 0x00DE32AC, 0x0096BDCA, 0x00955D7D, 0x00DDD21B, 0x000543B0, 0x004DCCD6, + 0x00F8CF59, 0x00B0403F, 0x0068D194, 0x00205EF2, 0x0023BE45, 0x006B3123, 0x00B3A088, + 0x00FB2FEE, 0x0022EB10, 0x006A6476, 0x00B2F5DD, 0x00FA7ABB, 0x00F99A0C, 0x00B1156A, + 0x006984C1, 0x00210BA7, 0x00940828, 0x00DC874E, 0x000416E5, 0x004C9983, 0x004F7934, + 0x0007F652, 0x00DF67F9, 0x0097E89F, 0x00DDF3C3, 0x00957CA5, 0x004DED0E, 0x00056268, + 0x000682DF, 0x004E0DB9, 0x00969C12, 0x00DE1374, 0x006B10FB, 0x00239F9D, 0x00FB0E36, + 0x00B38150, 0x00B061E7, 0x00F8EE81, 0x00207F2A, 0x0068F04C, 0x00B134B2, 0x00F9BBD4, + 0x00212A7F, 0x0069A519, 0x006A45AE, 0x0022CAC8, 0x00FA5B63, 0x00B2D405, 0x0007D78A, + 0x004F58EC, 0x0097C947, 0x00DF4621, 0x00DCA696, 0x009429F0, 0x004CB85B, 0x0004373D, + 0x00057D20, 0x004DF246, 0x009563ED, 0x00DDEC8B, 0x00DE0C3C, 0x0096835A, 0x004E12F1, + 0x00069D97, 0x00B39E18, 0x00FB117E, 0x002380D5, 0x006B0FB3, 0x0068EF04, 0x00206062, + 0x00F8F1C9, 0x00B07EAF, 0x0069BA51, 0x00213537, 0x00F9A49C, 0x00B12BFA, 0x00B2CB4D, + 0x00FA442B, 0x0022D580, 0x006A5AE6, 0x00DF5969, 0x0097D60F, 0x004F47A4, 0x0007C8C2, + 0x00042875, 0x004CA713, 0x009436B8, 0x00DCB9DE, +}; + +static const uint32_t T2[256] = { + 0x00000000, 0x00D70983, 0x00555F80, 0x00825603, 0x0051F286, 0x0086FB05, 0x0004AD06, + 0x00D3A485, 0x0059A88B, 0x008EA108, 0x000CF70B, 0x00DBFE88, 0x00085A0D, 0x00DF538E, + 0x005D058D, 0x008A0C0E, 0x00491C91, 0x009E1512, 0x001C4311, 0x00CB4A92, 0x0018EE17, + 0x00CFE794, 0x004DB197, 0x009AB814, 0x0010B41A, 0x00C7BD99, 0x0045EB9A, 0x0092E219, + 0x0041469C, 0x00964F1F, 0x0014191C, 0x00C3109F, 0x006974A4, 0x00BE7D27, 0x003C2B24, + 0x00EB22A7, 0x00388622, 0x00EF8FA1, 0x006DD9A2, 0x00BAD021, 0x0030DC2F, 0x00E7D5AC, + 0x006583AF, 0x00B28A2C, 0x00612EA9, 0x00B6272A, 0x00347129, 0x00E378AA, 0x00206835, + 0x00F761B6, 0x007537B5, 0x00A23E36, 0x00719AB3, 0x00A69330, 0x0024C533, 0x00F3CCB0, + 0x0079C0BE, 0x00AEC93D, 0x002C9F3E, 0x00FB96BD, 0x00283238, 0x00FF3BBB, 0x007D6DB8, + 0x00AA643B, 0x0029A4CE, 0x00FEAD4D, 0x007CFB4E, 0x00ABF2CD, 0x00785648, 0x00AF5FCB, + 0x002D09C8, 0x00FA004B, 0x00700C45, 0x00A705C6, 0x002553C5, 0x00F25A46, 0x0021FEC3, + 0x00F6F740, 0x0074A143, 0x00A3A8C0, 0x0060B85F, 0x00B7B1DC, 0x0035E7DF, 0x00E2EE5C, + 0x00314AD9, 0x00E6435A, 0x00641559, 0x00B31CDA, 0x003910D4, 0x00EE1957, 0x006C4F54, + 0x00BB46D7, 0x0068E252, 0x00BFEBD1, 0x003DBDD2, 0x00EAB451, 0x0040D06A, 0x0097D9E9, + 0x00158FEA, 0x00C28669, 0x001122EC, 0x00C62B6F, 0x00447D6C, 0x009374EF, 0x001978E1, + 0x00CE7162, 0x004C2761, 0x009B2EE2, 0x00488A67, 0x009F83E4, 0x001DD5E7, 0x00CADC64, + 0x0009CCFB, 0x00DEC578, 0x005C937B, 0x008B9AF8, 0x00583E7D, 0x008F37FE, 0x000D61FD, + 0x00DA687E, 0x00506470, 0x00876DF3, 0x00053BF0, 0x00D23273, 0x000196F6, 0x00D69F75, + 0x0054C976, 0x0083C0F5, 0x00A9041B, 0x007E0D98, 0x00FC5B9B, 0x002B5218, 0x00F8F69D, + 0x002FFF1E, 0x00ADA91D, 0x007AA09E, 0x00F0AC90, 0x0027A513, 0x00A5F310, 0x0072FA93, + 0x00A15E16, 0x00765795, 0x00F40196, 0x00230815, 0x00E0188A, 0x00371109, 0x00B5470A, + 0x00624E89, 0x00B1EA0C, 0x0066E38F, 0x00E4B58C, 0x0033BC0F, 0x00B9B001, 0x006EB982, + 0x00ECEF81, 0x003BE602, 0x00E84287, 0x003F4B04, 0x00BD1D07, 0x006A1484, 0x00C070BF, + 0x0017793C, 0x00952F3F, 0x004226BC, 0x00918239, 0x00468BBA, 0x00C4DDB9, 0x0013D43A, + 0x0099D834, 0x004ED1B7, 0x00CC87B4, 0x001B8E37, 0x00C82AB2, 0x001F2331, 0x009D7532, + 0x004A7CB1, 0x00896C2E, 0x005E65AD, 0x00DC33AE, 0x000B3A2D, 0x00D89EA8, 0x000F972B, + 0x008DC128, 0x005AC8AB, 0x00D0C4A5, 0x0007CD26, 0x00859B25, 0x005292A6, 0x00813623, + 0x00563FA0, 0x00D469A3, 0x00036020, 0x0080A0D5, 0x0057A956, 0x00D5FF55, 0x0002F6D6, + 0x00D15253, 0x00065BD0, 0x00840DD3, 0x00530450, 0x00D9085E, 0x000E01DD, 0x008C57DE, + 0x005B5E5D, 0x0088FAD8, 0x005FF35B, 0x00DDA558, 0x000AACDB, 0x00C9BC44, 0x001EB5C7, + 0x009CE3C4, 0x004BEA47, 0x00984EC2, 0x004F4741, 0x00CD1142, 0x001A18C1, 0x009014CF, + 0x00471D4C, 0x00C54B4F, 0x001242CC, 0x00C1E649, 0x0016EFCA, 0x0094B9C9, 0x0043B04A, + 0x00E9D471, 0x003EDDF2, 0x00BC8BF1, 0x006B8272, 0x00B826F7, 0x006F2F74, 0x00ED7977, + 0x003A70F4, 0x00B07CFA, 0x00677579, 0x00E5237A, 0x00322AF9, 0x00E18E7C, 0x003687FF, + 0x00B4D1FC, 0x0063D87F, 0x00A0C8E0, 0x0077C163, 0x00F59760, 0x00229EE3, 0x00F13A66, + 0x002633E5, 0x00A465E6, 0x00736C65, 0x00F9606B, 0x002E69E8, 0x00AC3FEB, 0x007B3668, + 0x00A892ED, 0x007F9B6E, 0x00FDCD6D, 0x002AC4EE, +}; + +static const uint32_t T3[256] = { + 0x00000000, 0x00520936, 0x00A4126C, 0x00F61B5A, 0x004825D8, 0x001A2CEE, 0x00EC37B4, + 0x00BE3E82, 0x006B0636, 0x00390F00, 0x00CF145A, 0x009D1D6C, 0x002323EE, 0x00712AD8, + 0x00873182, 0x00D538B4, 0x00D60C6C, 0x0084055A, 0x00721E00, 0x00201736, 0x009E29B4, + 0x00CC2082, 0x003A3BD8, 0x006832EE, 0x00BD0A5A, 0x00EF036C, 0x00191836, 0x004B1100, + 0x00F52F82, 0x00A726B4, 0x00513DEE, 0x000334D8, 0x00AC19D8, 0x00FE10EE, 0x00080BB4, + 0x005A0282, 0x00E43C00, 0x00B63536, 0x00402E6C, 0x0012275A, 0x00C71FEE, 0x009516D8, + 0x00630D82, 0x003104B4, 0x008F3A36, 0x00DD3300, 0x002B285A, 0x0079216C, 0x007A15B4, + 0x00281C82, 0x00DE07D8, 0x008C0EEE, 0x0032306C, 0x0060395A, 0x00962200, 0x00C42B36, + 0x00111382, 0x00431AB4, 0x00B501EE, 0x00E708D8, 0x0059365A, 0x000B3F6C, 0x00FD2436, + 0x00AF2D00, 0x00A37F36, 0x00F17600, 0x00076D5A, 0x0055646C, 0x00EB5AEE, 0x00B953D8, + 0x004F4882, 0x001D41B4, 0x00C87900, 0x009A7036, 0x006C6B6C, 0x003E625A, 0x00805CD8, + 0x00D255EE, 0x00244EB4, 0x00764782, 0x0075735A, 0x00277A6C, 0x00D16136, 0x00836800, + 0x003D5682, 0x006F5FB4, 0x009944EE, 0x00CB4DD8, 0x001E756C, 0x004C7C5A, 0x00BA6700, + 0x00E86E36, 0x005650B4, 0x00045982, 0x00F242D8, 0x00A04BEE, 0x000F66EE, 0x005D6FD8, + 0x00AB7482, 0x00F97DB4, 0x00474336, 0x00154A00, 0x00E3515A, 0x00B1586C, 0x006460D8, + 0x003669EE, 0x00C072B4, 0x00927B82, 0x002C4500, 0x007E4C36, 0x0088576C, 0x00DA5E5A, + 0x00D96A82, 0x008B63B4, 0x007D78EE, 0x002F71D8, 0x00914F5A, 0x00C3466C, 0x00355D36, + 0x00675400, 0x00B26CB4, 0x00E06582, 0x00167ED8, 0x004477EE, 0x00FA496C, 0x00A8405A, + 0x005E5B00, 0x000C5236, 0x0046FF6C, 0x0014F65A, 0x00E2ED00, 0x00B0E436, 0x000EDAB4, + 0x005CD382, 0x00AAC8D8, 0x00F8C1EE, 0x002DF95A, 0x007FF06C, 0x0089EB36, 0x00DBE200, + 0x0065DC82, 0x0037D5B4, 0x00C1CEEE, 0x0093C7D8, 0x0090F300, 0x00C2FA36, 0x0034E16C, + 0x0066E85A, 0x00D8D6D8, 0x008ADFEE, 0x007CC4B4, 0x002ECD82, 0x00FBF536, 0x00A9FC00, + 0x005FE75A, 0x000DEE6C, 0x00B3D0EE, 0x00E1D9D8, 0x0017C282, 0x0045CBB4, 0x00EAE6B4, + 0x00B8EF82, 0x004EF4D8, 0x001CFDEE, 0x00A2C36C, 0x00F0CA5A, 0x0006D100, 0x0054D836, + 0x0081E082, 0x00D3E9B4, 0x0025F2EE, 0x0077FBD8, 0x00C9C55A, 0x009BCC6C, 0x006DD736, + 0x003FDE00, 0x003CEAD8, 0x006EE3EE, 0x0098F8B4, 0x00CAF182, 0x0074CF00, 0x0026C636, + 0x00D0DD6C, 0x0082D45A, 0x0057ECEE, 0x0005E5D8, 0x00F3FE82, 0x00A1F7B4, 0x001FC936, + 0x004DC000, 0x00BBDB5A, 0x00E9D26C, 0x00E5805A, 0x00B7896C, 0x00419236, 0x00139B00, + 0x00ADA582, 0x00FFACB4, 0x0009B7EE, 0x005BBED8, 0x008E866C, 0x00DC8F5A, 0x002A9400, + 0x00789D36, 0x00C6A3B4, 0x0094AA82, 0x0062B1D8, 0x0030B8EE, 0x00338C36, 0x00618500, + 0x00979E5A, 0x00C5976C, 0x007BA9EE, 0x0029A0D8, 0x00DFBB82, 0x008DB2B4, 0x00588A00, + 0x000A8336, 0x00FC986C, 0x00AE915A, 0x0010AFD8, 0x0042A6EE, 0x00B4BDB4, 0x00E6B482, + 0x00499982, 0x001B90B4, 0x00ED8BEE, 0x00BF82D8, 0x0001BC5A, 0x0053B56C, 0x00A5AE36, + 0x00F7A700, 0x00229FB4, 0x00709682, 0x00868DD8, 0x00D484EE, 0x006ABA6C, 0x0038B35A, + 0x00CEA800, 0x009CA136, 0x009F95EE, 0x00CD9CD8, 0x003B8782, 0x00698EB4, 0x00D7B036, + 0x0085B900, 0x0073A25A, 0x0021AB6C, 0x00F493D8, 0x00A69AEE, 0x005081B4, 0x00028882, + 0x00BCB600, 0x00EEBF36, 0x0018A46C, 0x004AAD5A}; + +#define CRC24_FAST_INIT 0xce04b7L + +static inline uint32_t +process8(uint32_t crc, uint8_t data) +{ + return (crc >> 8) ^ T0[(crc & 0xff) ^ data]; +} + +/* + * Process 4 bytes in one go + */ +static inline uint32_t +process32(uint32_t crc, uint32_t word) +{ + crc ^= word; + crc = T3[crc & 0xff] ^ T2[((crc >> 8) & 0xff)] ^ T1[((crc >> 16) & 0xff)] ^ + T0[(crc >> 24) & 0xff]; + return crc; +} + +static uint32_t +crc24_update(uint32_t crc, const uint8_t *in, size_t length) +{ + uint32_t d0, d1, d2, d3; + + while (length >= 16) { + LOAD32LE(d0, &in[0]); + LOAD32LE(d1, &in[4]); + LOAD32LE(d2, &in[8]); + LOAD32LE(d3, &in[12]); + + crc = process32(crc, d0); + crc = process32(crc, d1); + crc = process32(crc, d2); + crc = process32(crc, d3); + + in += 16; + length -= 16; + } + + while (length--) { + crc = process8(crc, *in++); + } + + return crc & 0xffffff; +} + +/* Swap endianness of 32-bit value */ +#if defined(__GNUC__) || defined(__clang__) +#define BSWAP32(x) __builtin_bswap32(x) +#else +#define BSWAP32(x) \ + ((x & 0x000000FF) << 24 | (x & 0x0000FF00) << 8 | (x & 0x00FF0000) >> 8 | \ + (x & 0xFF000000) >> 24) +#endif + +static uint32_t +crc24_final(uint32_t crc) +{ + return (BSWAP32(crc) >> 8); +} + +namespace rnp { + +CRC24_RNP::CRC24_RNP() +{ + state_ = CRC24_FAST_INIT; +} + +CRC24_RNP::~CRC24_RNP() +{ +} + +std::unique_ptr +CRC24_RNP::create() +{ + return std::unique_ptr(new CRC24_RNP()); +} + +void +CRC24_RNP::add(const void *buf, size_t len) +{ + state_ = crc24_update(state_, static_cast(buf), len); +} + +std::array +CRC24_RNP::finish() +{ + uint32_t crc_fin = crc24_final(state_); + state_ = 0; + std::array res; + res[0] = (crc_fin >> 16) & 0xff; + res[1] = (crc_fin >> 8) & 0xff; + res[2] = crc_fin & 0xff; + return res; +} + +}; // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/hash_crc24.hpp b/comm/third_party/rnp/src/lib/crypto/hash_crc24.hpp new file mode 100644 index 0000000000..a73a46682e --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_crc24.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_HASH_CRC24_HPP_ +#define CRYPTO_HASH_CRC24_HPP_ + +#include "hash.hpp" + +namespace rnp { +class CRC24_RNP : public CRC24 { + uint32_t state_; + CRC24_RNP(); + + public: + virtual ~CRC24_RNP(); + + static std::unique_ptr create(); + + void add(const void *buf, size_t len) override; + std::array finish() override; +}; +} // namespace rnp + +#endif \ No newline at end of file diff --git a/comm/third_party/rnp/src/lib/crypto/hash_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/hash_ossl.cpp new file mode 100644 index 0000000000..37b75464d4 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_ossl.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hash_ossl.hpp" +#include +#include +#include +#include +#include "config.h" +#include "types.h" +#include "utils.h" +#include "str-utils.h" +#include "defaults.h" + +static const id_str_pair openssl_alg_map[] = { + {PGP_HASH_MD5, "md5"}, + {PGP_HASH_SHA1, "sha1"}, + {PGP_HASH_RIPEMD, "ripemd160"}, + {PGP_HASH_SHA256, "sha256"}, + {PGP_HASH_SHA384, "sha384"}, + {PGP_HASH_SHA512, "sha512"}, + {PGP_HASH_SHA224, "sha224"}, + {PGP_HASH_SM3, "sm3"}, + {PGP_HASH_SHA3_256, "sha3-256"}, + {PGP_HASH_SHA3_512, "sha3-512"}, + {0, NULL}, +}; + +namespace rnp { +Hash_OpenSSL::Hash_OpenSSL(pgp_hash_alg_t alg) : Hash(alg) +{ + const char * hash_name = Hash_OpenSSL::name_backend(alg); + const EVP_MD *hash_tp = EVP_get_digestbyname(hash_name); + if (!hash_tp) { + RNP_LOG("Error creating hash object for '%s'", hash_name); + throw rnp_exception(RNP_ERROR_BAD_STATE); + } + fn_ = EVP_MD_CTX_new(); + if (!fn_) { + RNP_LOG("Allocation failure"); + throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY); + } + int res = EVP_DigestInit_ex(fn_, hash_tp, NULL); + if (res != 1) { + RNP_LOG("Digest initializataion error %d : %lu", res, ERR_peek_last_error()); + EVP_MD_CTX_free(fn_); + throw rnp_exception(RNP_ERROR_BAD_STATE); + } + assert(size_ == (size_t) EVP_MD_size(hash_tp)); +} + +Hash_OpenSSL::Hash_OpenSSL(const Hash_OpenSSL &src) : Hash(src.alg_) +{ + if (!src.fn_) { + throw rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + fn_ = EVP_MD_CTX_new(); + if (!fn_) { + RNP_LOG("Allocation failure"); + throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY); + } + + int res = EVP_MD_CTX_copy(fn_, src.fn_); + if (res != 1) { + RNP_LOG("Digest copying error %d: %lu", res, ERR_peek_last_error()); + EVP_MD_CTX_free(fn_); + throw rnp_exception(RNP_ERROR_BAD_STATE); + } +} + +std::unique_ptr +Hash_OpenSSL::create(pgp_hash_alg_t alg) +{ + return std::unique_ptr(new Hash_OpenSSL(alg)); +} + +std::unique_ptr +Hash_OpenSSL::clone() const +{ + return std::unique_ptr(new Hash_OpenSSL(*this)); +} + +void +Hash_OpenSSL::add(const void *buf, size_t len) +{ + if (!fn_) { + throw rnp_exception(RNP_ERROR_NULL_POINTER); + } + int res = EVP_DigestUpdate(fn_, buf, len); + if (res != 1) { + RNP_LOG("Digest updating error %d: %lu", res, ERR_peek_last_error()); + throw rnp_exception(RNP_ERROR_GENERIC); + } +} + +size_t +Hash_OpenSSL::finish(uint8_t *digest) +{ + if (!fn_) { + return 0; + } + int res = digest ? EVP_DigestFinal_ex(fn_, digest, NULL) : 1; + EVP_MD_CTX_free(fn_); + fn_ = NULL; + if (res != 1) { + RNP_LOG("Digest finalization error %d: %lu", res, ERR_peek_last_error()); + return 0; + } + + size_t outsz = size_; + size_ = 0; + return outsz; +} + +Hash_OpenSSL::~Hash_OpenSSL() +{ + if (!fn_) { + return; + } + EVP_MD_CTX_free(fn_); +} + +const char * +Hash_OpenSSL::name_backend(pgp_hash_alg_t alg) +{ + return id_str_pair::lookup(openssl_alg_map, alg); +} +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/hash_ossl.hpp b/comm/third_party/rnp/src/lib/crypto/hash_ossl.hpp new file mode 100644 index 0000000000..95b365b92b --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_ossl.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_HASH_OSSL_HPP_ +#define CRYPTO_HASH_OSSL_HPP_ + +#include "hash.hpp" +#include + +namespace rnp { +class Hash_OpenSSL : public Hash { + private: + EVP_MD_CTX *fn_; + + Hash_OpenSSL(pgp_hash_alg_t alg); + Hash_OpenSSL(const Hash_OpenSSL &src); + + public: + virtual ~Hash_OpenSSL(); + + static std::unique_ptr create(pgp_hash_alg_t alg); + std::unique_ptr clone() const override; + + void add(const void *buf, size_t len) override; + size_t finish(uint8_t *digest = NULL) override; + + static const char *name_backend(pgp_hash_alg_t alg); +}; + +} // namespace rnp + +#endif \ No newline at end of file diff --git a/comm/third_party/rnp/src/lib/crypto/hash_sha1cd.cpp b/comm/third_party/rnp/src/lib/crypto/hash_sha1cd.cpp new file mode 100644 index 0000000000..863591e762 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_sha1cd.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2021-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "logging.h" +#include "hash_sha1cd.hpp" + +namespace rnp { +Hash_SHA1CD::Hash_SHA1CD() : Hash(PGP_HASH_SHA1) +{ + assert(size_ == 20); + SHA1DCInit(&ctx_); +} + +Hash_SHA1CD::Hash_SHA1CD(const Hash_SHA1CD &src) : Hash(PGP_HASH_SHA1) +{ + ctx_ = src.ctx_; +} + +Hash_SHA1CD::~Hash_SHA1CD() +{ +} + +std::unique_ptr +Hash_SHA1CD::create() +{ + return std::unique_ptr(new Hash_SHA1CD()); +} + +std::unique_ptr +Hash_SHA1CD::clone() const +{ + return std::unique_ptr(new Hash_SHA1CD(*this)); +} + +/* This produces runtime error: load of misaligned address 0x60d0000030a9 for type 'const + * uint32_t' (aka 'const unsigned int'), which requires 4 byte alignment */ +#if defined(__clang__) +__attribute__((no_sanitize("undefined"))) +#endif +void +Hash_SHA1CD::add(const void *buf, size_t len) +{ + SHA1DCUpdate(&ctx_, (const char *) buf, len); +} + +#if defined(__clang__) +__attribute__((no_sanitize("undefined"))) +#endif +size_t +Hash_SHA1CD::finish(uint8_t *digest) +{ + unsigned char fixed_digest[20]; + int res = SHA1DCFinal(fixed_digest, &ctx_); + if (res && digest) { + /* Show warning only if digest is non-null */ + RNP_LOG("Warning! SHA1 collision detected and mitigated."); + } + if (res) { + throw rnp_exception(RNP_ERROR_BAD_STATE); + } + if (digest) { + memcpy(digest, fixed_digest, 20); + } + return 20; +} + +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/hash_sha1cd.hpp b/comm/third_party/rnp/src/lib/crypto/hash_sha1cd.hpp new file mode 100644 index 0000000000..523bbe0e9c --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/hash_sha1cd.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_HASH_SHA1CD_HPP_ +#define CRYPTO_HASH_SHA1CD_HPP_ + +#include "hash.hpp" +#include "sha1cd/sha1.h" + +namespace rnp { +class Hash_SHA1CD : public Hash { + private: + SHA1_CTX ctx_; + + Hash_SHA1CD(); + Hash_SHA1CD(const Hash_SHA1CD &src); + + public: + virtual ~Hash_SHA1CD(); + + static std::unique_ptr create(); + std::unique_ptr clone() const override; + + void add(const void *buf, size_t len) override; + size_t finish(uint8_t *digest = NULL) override; +}; + +} // namespace rnp +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/mem.cpp b/comm/third_party/rnp/src/lib/crypto/mem.cpp new file mode 100644 index 0000000000..bf54aa6b81 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/mem.cpp @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "mem.h" +#include "logging.h" +#include + +void +secure_clear(void *vp, size_t size) +{ + botan_scrub_mem(vp, size); +} + +namespace rnp { + +bool +hex_encode(const uint8_t *buf, size_t buf_len, char *hex, size_t hex_len, hex_format_t format) +{ + uint32_t flags = format == HEX_LOWERCASE ? BOTAN_FFI_HEX_LOWER_CASE : 0; + + if (hex_len < (buf_len * 2 + 1)) { + return false; + } + hex[buf_len * 2] = '\0'; + return botan_hex_encode(buf, buf_len, hex, flags) == 0; +} + +size_t +hex_decode(const char *hex, uint8_t *buf, size_t buf_len) +{ + size_t hexlen = strlen(hex); + + /* check for 0x prefix */ + if ((hexlen >= 2) && (hex[0] == '0') && ((hex[1] == 'x') || (hex[1] == 'X'))) { + hex += 2; + hexlen -= 2; + } + if (botan_hex_decode(hex, hexlen, buf, &buf_len) != 0) { + RNP_LOG("Hex decode failed on string: %s", hex); + return 0; + } + return buf_len; +} +} // namespace rnp \ No newline at end of file diff --git a/comm/third_party/rnp/src/lib/crypto/mem.h b/comm/third_party/rnp/src/lib/crypto/mem.h new file mode 100644 index 0000000000..fe574da978 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/mem.h @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CRYPTO_MEM_H_ +#define CRYPTO_MEM_H_ + +#include "config.h" +#include +#include +#if defined(CRYPTO_BACKEND_BOTAN) +#include +#include +#elif defined(CRYPTO_BACKEND_OPENSSL) +#include +#endif + +namespace rnp { + +#if defined(CRYPTO_BACKEND_BOTAN) +template using secure_vector = Botan::secure_vector; +#elif defined(CRYPTO_BACKEND_OPENSSL) +template class ossl_allocator { + public: + static_assert(std::is_integral::value, "T must be integral type"); + + typedef T value_type; + typedef std::size_t size_type; + + ossl_allocator() noexcept = default; + ossl_allocator(const ossl_allocator &) noexcept = default; + ossl_allocator &operator=(const ossl_allocator &) noexcept = default; + ~ossl_allocator() noexcept = default; + + template ossl_allocator(const ossl_allocator &) noexcept + { + } + + T * + allocate(std::size_t n) + { + if (!n) { + return nullptr; + } + + /* attempt to use OpenSSL secure alloc */ + T *ptr = static_cast(OPENSSL_secure_zalloc(n * sizeof(T))); + if (ptr) { + return ptr; + } + /* fallback to std::alloc if failed */ + ptr = static_cast(std::calloc(n, sizeof(T))); + if (!ptr) + throw std::bad_alloc(); + return ptr; + } + + void + deallocate(T *p, std::size_t n) + { + if (!p) { + return; + } + if (CRYPTO_secure_allocated(p)) { + OPENSSL_secure_clear_free(p, n * sizeof(T)); + return; + } + OPENSSL_cleanse(p, n * sizeof(T)); + std::free(p); + } +}; + +template using secure_vector = std::vector >; +#else +#error Unsupported backend. +#endif + +template struct secure_array { + private: + static_assert(std::is_integral::value, "T must be integer type"); + std::array data_; + + public: + secure_array() : data_({0}) + { + } + + T * + data() + { + return &data_[0]; + } + + std::size_t + size() const + { + return data_.size(); + } + + T + operator[](size_t idx) const + { + return data_[idx]; + } + + T & + operator[](size_t idx) + { + return data_[idx]; + } + + ~secure_array() + { +#if defined(CRYPTO_BACKEND_BOTAN) + botan_scrub_mem(&data_[0], sizeof(data_)); +#elif defined(CRYPTO_BACKEND_OPENSSL) + OPENSSL_cleanse(&data_[0], sizeof(data_)); +#else +#error "Unsupported crypto backend." +#endif + } +}; + +typedef enum { HEX_LOWERCASE, HEX_UPPERCASE } hex_format_t; + +bool hex_encode(const uint8_t *buf, + size_t buf_len, + char * hex, + size_t hex_len, + hex_format_t format = HEX_UPPERCASE); +size_t hex_decode(const char *hex, uint8_t *buf, size_t buf_len); +} // namespace rnp + +void secure_clear(void *vp, size_t size); + +#endif // CRYPTO_MEM_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/mem_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/mem_ossl.cpp new file mode 100644 index 0000000000..e9d6a9373f --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/mem_ossl.cpp @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "mem.h" +#include "logging.h" +#include + +void +secure_clear(void *vp, size_t size) +{ + OPENSSL_cleanse(vp, size); +} + +namespace rnp { + +bool +hex_encode(const uint8_t *buf, size_t buf_len, char *hex, size_t hex_len, hex_format_t format) +{ + if (hex_len < (buf_len * 2 + 1)) { + return false; + } + static const char *hex_low = "0123456789abcdef"; + static const char *hex_up = "0123456789ABCDEF"; + const char * hex_ch = (format == HEX_LOWERCASE) ? hex_low : hex_up; + hex[buf_len * 2] = '\0'; + for (size_t i = 0; i < buf_len; i++) { + hex[i << 1] = hex_ch[buf[i] >> 4]; + hex[(i << 1) + 1] = hex_ch[buf[i] & 0xF]; + } + return true; +} + +static bool +hex_char_decode(const char hex, uint8_t &res) +{ + if ((hex >= '0') && (hex <= '9')) { + res = hex - '0'; + return true; + } + if (hex >= 'a' && hex <= 'f') { + res = hex + 10 - 'a'; + return true; + } + if (hex >= 'A' && hex <= 'F') { + res = hex + 10 - 'A'; + return true; + } + return false; +} + +size_t +hex_decode(const char *hex, uint8_t *buf, size_t buf_len) +{ + size_t hexlen = strlen(hex); + + /* check for 0x prefix */ + if ((hexlen >= 2) && (hex[0] == '0') && ((hex[1] == 'x') || (hex[1] == 'X'))) { + hex += 2; + hexlen -= 2; + } + const char *end = hex + hexlen; + uint8_t * buf_st = buf; + uint8_t * buf_en = buf + buf_len; + while (hex < end) { + /* skip whitespaces */ + if ((*hex < '0') && + ((*hex == ' ') || (*hex == '\t') || (*hex == '\r') || (*hex == '\n'))) { + hex++; + continue; + } + if (hexlen < 2) { + RNP_LOG("Invalid hex string length."); + return 0; + } + uint8_t lo, hi; + if (!hex_char_decode(*hex++, hi) || !hex_char_decode(*hex++, lo)) { + RNP_LOG("Hex decode failed on string: %s", hex); + return 0; + } + if (buf == buf_en) { + return 0; + } + *buf++ = (hi << 4) | lo; + } + return buf - buf_st; +} + +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/mpi.cpp b/comm/third_party/rnp/src/lib/crypto/mpi.cpp new file mode 100644 index 0000000000..4df7eea528 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/mpi.cpp @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2018 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "mpi.h" +#include "mem.h" +#include "utils.h" + +size_t +mpi_bits(const pgp_mpi_t *val) +{ + size_t bits = 0; + size_t idx = 0; + uint8_t bt; + + for (idx = 0; (idx < val->len) && !val->mpi[idx]; idx++) + ; + + if (idx < val->len) { + for (bits = (val->len - idx - 1) << 3, bt = val->mpi[idx]; bt; bits++, bt = bt >> 1) + ; + } + + return bits; +} + +size_t +mpi_bytes(const pgp_mpi_t *val) +{ + return val->len; +} + +bool +mem2mpi(pgp_mpi_t *val, const void *mem, size_t len) +{ + if (len > sizeof(val->mpi)) { + return false; + } + + memcpy(val->mpi, mem, len); + val->len = len; + return true; +} + +void +mpi2mem(const pgp_mpi_t *val, void *mem) +{ + memcpy(mem, val->mpi, val->len); +} + +char * +mpi2hex(const pgp_mpi_t *val) +{ + static const char *hexes = "0123456789abcdef"; + char * out; + size_t len; + size_t idx = 0; + + len = mpi_bytes(val); + out = (char *) malloc(len * 2 + 1); + + if (!out) { + return out; + } + + for (size_t i = 0; i < len; i++) { + out[idx++] = hexes[val->mpi[i] >> 4]; + out[idx++] = hexes[val->mpi[i] & 0xf]; + } + out[idx] = '\0'; + return out; +} + +bool +mpi_equal(const pgp_mpi_t *val1, const pgp_mpi_t *val2) +{ + size_t idx1 = 0; + size_t idx2 = 0; + + for (idx1 = 0; (idx1 < val1->len) && !val1->mpi[idx1]; idx1++) + ; + + for (idx2 = 0; (idx2 < val2->len) && !val2->mpi[idx2]; idx2++) + ; + + return ((val1->len - idx1) == (val2->len - idx2) && + !memcmp(val1->mpi + idx1, val2->mpi + idx2, val1->len - idx1)); +} + +void +mpi_forget(pgp_mpi_t *val) +{ + secure_clear(val, sizeof(*val)); + val->len = 0; +} diff --git a/comm/third_party/rnp/src/lib/crypto/mpi.h b/comm/third_party/rnp/src/lib/crypto/mpi.h new file mode 100644 index 0000000000..f95aeea15f --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/mpi.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2018 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_MPI_H_ +#define RNP_MPI_H_ + +#include +#include +#include + +/* 16384 bits should be pretty enough for now */ +#define PGP_MPINT_BITS (16384) +#define PGP_MPINT_SIZE (PGP_MPINT_BITS >> 3) + +/** multi-precision integer, used in signatures and public/secret keys */ +typedef struct pgp_mpi_t { + uint8_t mpi[PGP_MPINT_SIZE]; + size_t len; +} pgp_mpi_t; + +bool mem2mpi(pgp_mpi_t *val, const void *mem, size_t len); + +void mpi2mem(const pgp_mpi_t *val, void *mem); + +char *mpi2hex(const pgp_mpi_t *val); + +size_t mpi_bits(const pgp_mpi_t *val); + +size_t mpi_bytes(const pgp_mpi_t *val); + +bool mpi_equal(const pgp_mpi_t *val1, const pgp_mpi_t *val2); + +void mpi_forget(pgp_mpi_t *val); + +#endif // MPI_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/ossl_common.h b/comm/third_party/rnp/src/lib/crypto/ossl_common.h new file mode 100644 index 0000000000..b6b7067ce4 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/ossl_common.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_OSSL_COMMON_H_ +#define RNP_OSSL_COMMON_H_ + +#include +#include "config.h" +#include + +inline const char * +ossl_latest_err() +{ + return ERR_error_string(ERR_peek_last_error(), NULL); +} + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/rng.cpp b/comm/third_party/rnp/src/lib/crypto/rng.cpp new file mode 100644 index 0000000000..bf5bfadc8a --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/rng.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017-2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "rng.h" +#include "types.h" + +namespace rnp { +RNG::RNG(Type type) +{ + if (botan_rng_init(&botan_rng, type == Type::DRBG ? "user" : NULL)) { + throw rnp::rnp_exception(RNP_ERROR_RNG); + } +} + +RNG::~RNG() +{ + (void) botan_rng_destroy(botan_rng); +} + +void +RNG::get(uint8_t *data, size_t len) +{ + if (botan_rng_get(botan_rng, data, len)) { + // This should never happen + throw rnp::rnp_exception(RNP_ERROR_RNG); + } +} + +struct botan_rng_struct * +RNG::handle() +{ + return botan_rng; +} +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/rng.h b/comm/third_party/rnp/src/lib/crypto/rng.h new file mode 100644 index 0000000000..f452bd9edf --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/rng.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017-2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_RNG_H_ +#define RNP_RNG_H_ + +#include +#include +#include +#include "config.h" + +#ifdef CRYPTO_BACKEND_BOTAN +typedef struct botan_rng_struct *botan_rng_t; +#endif + +namespace rnp { +class RNG { + private: +#ifdef CRYPTO_BACKEND_BOTAN + struct botan_rng_struct *botan_rng; +#endif + public: + enum Type { DRBG, System }; + /** + * @brief Construct a new RNG object. + * Note: OpenSSL uses own global RNG, so this class is not needed there and left + * only for code-level compatibility. + * + * @param type indicates which random generator to initialize. + * Possible values for Botan backend: + * - DRBG will initialize HMAC_DRBG, this generator is initialized on-demand + * (when used for the first time) + * - SYSTEM will initialize /dev/(u)random + */ + RNG(Type type = Type::DRBG); + ~RNG(); + /** + * @brief Get randoom bytes. + * + * @param data buffer where data should be stored. Cannot be NULL. + * @param len number of bytes required. + */ + void get(uint8_t *data, size_t len); +#ifdef CRYPTO_BACKEND_BOTAN + /** + * @brief Returns internal handle to botan rng. Returned + * handle is always initialized. In case of + * internal error NULL is returned + */ + struct botan_rng_struct *handle(); +#endif +}; +} // namespace rnp + +#endif // RNP_RNG_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/rng_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/rng_ossl.cpp new file mode 100644 index 0000000000..4ebcc95dca --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/rng_ossl.cpp @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "rng.h" +#include "types.h" + +namespace rnp { +RNG::RNG(Type type) +{ +} + +RNG::~RNG() +{ +} + +void +RNG::get(uint8_t *data, size_t len) +{ + if (RAND_bytes(data, len) != 1) { + throw rnp::rnp_exception(RNP_ERROR_RNG); + } +} +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/crypto/rsa.cpp b/comm/third_party/rnp/src/lib/crypto/rsa.cpp new file mode 100644 index 0000000000..f7ddefe318 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/rsa.cpp @@ -0,0 +1,419 @@ +/*- + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Alistair Crooks (agc@NetBSD.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + */ +#include +#include +#include +#include "hash_botan.hpp" +#include "crypto/rsa.h" +#include "config.h" +#include "utils.h" +#include "bn.h" + +rnp_result_t +rsa_validate_key(rnp::RNG *rng, const pgp_rsa_key_t *key, bool secret) +{ + bignum_t * n = NULL; + bignum_t * e = NULL; + bignum_t * p = NULL; + bignum_t * q = NULL; + botan_pubkey_t bpkey = NULL; + botan_privkey_t bskey = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + + /* load and check public key part */ + if (!(n = mpi2bn(&key->n)) || !(e = mpi2bn(&key->e))) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + if (botan_pubkey_load_rsa(&bpkey, BN_HANDLE_PTR(n), BN_HANDLE_PTR(e)) != 0) { + goto done; + } + + if (botan_pubkey_check_key(bpkey, rng->handle(), 0)) { + goto done; + } + + if (!secret) { + ret = RNP_SUCCESS; + goto done; + } + + /* load and check secret key part */ + if (!(p = mpi2bn(&key->p)) || !(q = mpi2bn(&key->q))) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + /* p and q are reversed from normal usage in PGP */ + if (botan_privkey_load_rsa(&bskey, BN_HANDLE_PTR(q), BN_HANDLE_PTR(p), BN_HANDLE_PTR(e))) { + goto done; + } + + if (botan_privkey_check_key(bskey, rng->handle(), 0)) { + goto done; + } + ret = RNP_SUCCESS; +done: + botan_pubkey_destroy(bpkey); + botan_privkey_destroy(bskey); + bn_free(n); + bn_free(e); + bn_free(p); + bn_free(q); + return ret; +} + +static bool +rsa_load_public_key(botan_pubkey_t *bkey, const pgp_rsa_key_t *key) +{ + bignum_t *n = NULL; + bignum_t *e = NULL; + bool res = false; + + *bkey = NULL; + n = mpi2bn(&key->n); + e = mpi2bn(&key->e); + + if (!n || !e) { + RNP_LOG("out of memory"); + goto done; + } + + res = !botan_pubkey_load_rsa(bkey, BN_HANDLE_PTR(n), BN_HANDLE_PTR(e)); +done: + bn_free(n); + bn_free(e); + return res; +} + +static bool +rsa_load_secret_key(botan_privkey_t *bkey, const pgp_rsa_key_t *key) +{ + bignum_t *p = NULL; + bignum_t *q = NULL; + bignum_t *e = NULL; + bool res = false; + + *bkey = NULL; + p = mpi2bn(&key->p); + q = mpi2bn(&key->q); + e = mpi2bn(&key->e); + + if (!p || !q || !e) { + RNP_LOG("out of memory"); + goto done; + } + + /* p and q are reversed from normal usage in PGP */ + res = !botan_privkey_load_rsa(bkey, BN_HANDLE_PTR(q), BN_HANDLE_PTR(p), BN_HANDLE_PTR(e)); +done: + bn_free(p); + bn_free(q); + bn_free(e); + return res; +} + +rnp_result_t +rsa_encrypt_pkcs1(rnp::RNG * rng, + pgp_rsa_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const pgp_rsa_key_t *key) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + botan_pubkey_t rsa_key = NULL; + botan_pk_op_encrypt_t enc_op = NULL; + + if (!rsa_load_public_key(&rsa_key, key)) { + RNP_LOG("failed to load key"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (botan_pk_op_encrypt_create(&enc_op, rsa_key, "PKCS1v15", 0) != 0) { + goto done; + } + + out->m.len = sizeof(out->m.mpi); + if (botan_pk_op_encrypt(enc_op, rng->handle(), out->m.mpi, &out->m.len, in, in_len)) { + out->m.len = 0; + goto done; + } + ret = RNP_SUCCESS; +done: + botan_pk_op_encrypt_destroy(enc_op); + botan_pubkey_destroy(rsa_key); + return ret; +} + +rnp_result_t +rsa_verify_pkcs1(const pgp_rsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_rsa_key_t * key) +{ + char padding_name[64] = {0}; + botan_pubkey_t rsa_key = NULL; + botan_pk_op_verify_t verify_op = NULL; + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + + if (!rsa_load_public_key(&rsa_key, key)) { + RNP_LOG("failed to load key"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + snprintf(padding_name, + sizeof(padding_name), + "EMSA-PKCS1-v1_5(Raw,%s)", + rnp::Hash_Botan::name_backend(hash_alg)); + + if (botan_pk_op_verify_create(&verify_op, rsa_key, padding_name, 0) != 0) { + goto done; + } + + if (botan_pk_op_verify_update(verify_op, hash, hash_len) != 0) { + goto done; + } + + if (botan_pk_op_verify_finish(verify_op, sig->s.mpi, sig->s.len) != 0) { + goto done; + } + + ret = RNP_SUCCESS; +done: + botan_pk_op_verify_destroy(verify_op); + botan_pubkey_destroy(rsa_key); + return ret; +} + +rnp_result_t +rsa_sign_pkcs1(rnp::RNG * rng, + pgp_rsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_rsa_key_t *key) +{ + char padding_name[64] = {0}; + botan_privkey_t rsa_key; + botan_pk_op_sign_t sign_op; + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (mpi_bytes(&key->q) == 0) { + RNP_LOG("private key not set"); + return ret; + } + + if (!rsa_load_secret_key(&rsa_key, key)) { + RNP_LOG("failed to load key"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + snprintf(padding_name, + sizeof(padding_name), + "EMSA-PKCS1-v1_5(Raw,%s)", + rnp::Hash_Botan::name_backend(hash_alg)); + + if (botan_pk_op_sign_create(&sign_op, rsa_key, padding_name, 0) != 0) { + goto done; + } + + if (botan_pk_op_sign_update(sign_op, hash, hash_len)) { + goto done; + } + + sig->s.len = sizeof(sig->s.mpi); + if (botan_pk_op_sign_finish(sign_op, rng->handle(), sig->s.mpi, &sig->s.len)) { + goto done; + } + + ret = RNP_SUCCESS; +done: + botan_pk_op_sign_destroy(sign_op); + botan_privkey_destroy(rsa_key); + return ret; +} + +rnp_result_t +rsa_decrypt_pkcs1(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_rsa_encrypted_t *in, + const pgp_rsa_key_t * key) +{ + botan_privkey_t rsa_key = NULL; + botan_pk_op_decrypt_t decrypt_op = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (mpi_bytes(&key->q) == 0) { + RNP_LOG("private key not set"); + return ret; + } + + if (!rsa_load_secret_key(&rsa_key, key)) { + RNP_LOG("failed to load key"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (botan_pk_op_decrypt_create(&decrypt_op, rsa_key, "PKCS1v15", 0)) { + goto done; + } + + *out_len = PGP_MPINT_SIZE; + if (botan_pk_op_decrypt(decrypt_op, out, out_len, in->m.mpi, in->m.len)) { + goto done; + } + ret = RNP_SUCCESS; +done: + botan_privkey_destroy(rsa_key); + botan_pk_op_decrypt_destroy(decrypt_op); + return ret; +} + +rnp_result_t +rsa_generate(rnp::RNG *rng, pgp_rsa_key_t *key, size_t numbits) +{ + if ((numbits < 1024) || (numbits > PGP_MPINT_BITS)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + botan_privkey_t rsa_key = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + int cmp; + bignum_t * n = bn_new(); + bignum_t * e = bn_new(); + bignum_t * p = bn_new(); + bignum_t * q = bn_new(); + bignum_t * d = bn_new(); + bignum_t * u = bn_new(); + + if (!n || !e || !p || !q || !d || !u) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto end; + } + + if (botan_privkey_create( + &rsa_key, "RSA", std::to_string(numbits).c_str(), rng->handle())) { + goto end; + } + + if (botan_privkey_check_key(rsa_key, rng->handle(), 1) != 0) { + goto end; + } + + if (botan_privkey_get_field(BN_HANDLE_PTR(n), rsa_key, "n") || + botan_privkey_get_field(BN_HANDLE_PTR(e), rsa_key, "e") || + botan_privkey_get_field(BN_HANDLE_PTR(d), rsa_key, "d") || + botan_privkey_get_field(BN_HANDLE_PTR(p), rsa_key, "p") || + botan_privkey_get_field(BN_HANDLE_PTR(q), rsa_key, "q")) { + goto end; + } + + /* RFC 4880, 5.5.3 tells that p < q. GnuPG relies on this. */ + (void) botan_mp_cmp(&cmp, BN_HANDLE_PTR(p), BN_HANDLE_PTR(q)); + if (cmp > 0) { + (void) botan_mp_swap(BN_HANDLE_PTR(p), BN_HANDLE_PTR(q)); + } + + if (botan_mp_mod_inverse(BN_HANDLE_PTR(u), BN_HANDLE_PTR(p), BN_HANDLE_PTR(q)) != 0) { + RNP_LOG("Error computing RSA u param"); + ret = RNP_ERROR_BAD_STATE; + goto end; + } + + bn2mpi(n, &key->n); + bn2mpi(e, &key->e); + bn2mpi(p, &key->p); + bn2mpi(q, &key->q); + bn2mpi(d, &key->d); + bn2mpi(u, &key->u); + + ret = RNP_SUCCESS; +end: + botan_privkey_destroy(rsa_key); + bn_free(n); + bn_free(e); + bn_free(p); + bn_free(q); + bn_free(d); + bn_free(u); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/rsa.h b/comm/third_party/rnp/src/lib/crypto/rsa.h new file mode 100644 index 0000000000..6b1b615374 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/rsa.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_RSA_H_ +#define RNP_RSA_H_ + +#include +#include +#include "crypto/rng.h" +#include "crypto/mpi.h" + +typedef struct pgp_rsa_key_t { + pgp_mpi_t n; + pgp_mpi_t e; + /* secret mpis */ + pgp_mpi_t d; + pgp_mpi_t p; + pgp_mpi_t q; + pgp_mpi_t u; +} pgp_rsa_key_t; + +typedef struct pgp_rsa_signature_t { + pgp_mpi_t s; +} pgp_rsa_signature_t; + +typedef struct pgp_rsa_encrypted_t { + pgp_mpi_t m; +} pgp_rsa_encrypted_t; + +/* + * RSA encrypt/decrypt + */ + +rnp_result_t rsa_validate_key(rnp::RNG *rng, const pgp_rsa_key_t *key, bool secret); + +rnp_result_t rsa_generate(rnp::RNG *rng, pgp_rsa_key_t *key, size_t numbits); + +rnp_result_t rsa_encrypt_pkcs1(rnp::RNG * rng, + pgp_rsa_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const pgp_rsa_key_t *key); + +rnp_result_t rsa_decrypt_pkcs1(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_rsa_encrypted_t *in, + const pgp_rsa_key_t * key); + +rnp_result_t rsa_verify_pkcs1(const pgp_rsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_rsa_key_t * key); + +rnp_result_t rsa_sign_pkcs1(rnp::RNG * rng, + pgp_rsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_rsa_key_t *key); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/rsa_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/rsa_ossl.cpp new file mode 100644 index 0000000000..24cff296d9 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/rsa_ossl.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2021-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "crypto/rsa.h" +#include "config.h" +#include "utils.h" +#include "bn.h" +#include "ossl_common.h" +#include +#include +#include +#ifdef CRYPTO_BACKEND_OPENSSL3 +#include +#include +#endif +#include "hash_ossl.hpp" + +#ifndef CRYPTO_BACKEND_OPENSSL3 +static RSA * +rsa_load_public_key(const pgp_rsa_key_t *key) +{ + RSA * rsa = NULL; + bignum_t *n = mpi2bn(&key->n); + bignum_t *e = mpi2bn(&key->e); + + if (!n || !e) { + RNP_LOG("out of memory"); + goto done; + } + rsa = RSA_new(); + if (!rsa) { + RNP_LOG("Out of memory"); + goto done; + } + if (RSA_set0_key(rsa, n, e, NULL) != 1) { + RNP_LOG("Public key load error: %lu", ERR_peek_last_error()); + RSA_free(rsa); + rsa = NULL; + goto done; + } +done: + /* OpenSSL set0 function transfers ownership of bignums */ + if (!rsa) { + bn_free(n); + bn_free(e); + } + return rsa; +} + +static RSA * +rsa_load_secret_key(const pgp_rsa_key_t *key) +{ + RSA * rsa = NULL; + bignum_t *n = mpi2bn(&key->n); + bignum_t *e = mpi2bn(&key->e); + bignum_t *p = mpi2bn(&key->p); + bignum_t *q = mpi2bn(&key->q); + bignum_t *d = mpi2bn(&key->d); + + if (!n || !p || !q || !e || !d) { + RNP_LOG("out of memory"); + goto done; + } + + rsa = RSA_new(); + if (!rsa) { + RNP_LOG("Out of memory"); + goto done; + } + if (RSA_set0_key(rsa, n, e, d) != 1) { + RNP_LOG("Secret key load error: %lu", ERR_peek_last_error()); + RSA_free(rsa); + rsa = NULL; + goto done; + } + /* OpenSSL has p < q, as we do */ + if (RSA_set0_factors(rsa, p, q) != 1) { + RNP_LOG("Factors load error: %lu", ERR_peek_last_error()); + RSA_free(rsa); + rsa = NULL; + goto done; + } +done: + /* OpenSSL set0 function transfers ownership of bignums */ + if (!rsa) { + bn_free(n); + bn_free(p); + bn_free(q); + bn_free(e); + bn_free(d); + } + return rsa; +} + +static EVP_PKEY_CTX * +rsa_init_context(const pgp_rsa_key_t *key, bool secret) +{ + EVP_PKEY *evpkey = EVP_PKEY_new(); + if (!evpkey) { + RNP_LOG("allocation failed"); + return NULL; + } + EVP_PKEY_CTX *ctx = NULL; + RSA * rsakey = secret ? rsa_load_secret_key(key) : rsa_load_public_key(key); + if (!rsakey) { + goto done; + } + if (EVP_PKEY_set1_RSA(evpkey, rsakey) <= 0) { + RNP_LOG("Failed to set key: %lu", ERR_peek_last_error()); + goto done; + } + ctx = EVP_PKEY_CTX_new(evpkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); + } +done: + RSA_free(rsakey); + EVP_PKEY_free(evpkey); + return ctx; +} +#else +static OSSL_PARAM * +rsa_bld_params(const pgp_rsa_key_t *key, bool secret) +{ + OSSL_PARAM * params = NULL; + OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); + bignum_t * n = mpi2bn(&key->n); + bignum_t * e = mpi2bn(&key->e); + bignum_t * d = NULL; + bignum_t * p = NULL; + bignum_t * q = NULL; + bignum_t * u = NULL; + BN_CTX * bnctx = NULL; + + if (!n || !e || !bld) { + RNP_LOG("Out of memory"); + goto done; + } + + if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e)) { + RNP_LOG("Failed to push RSA params."); + goto done; + } + if (secret) { + d = mpi2bn(&key->d); + /* As we have u = p^-1 mod q, and qInv = q^-1 mod p, we need to replace one with + * another */ + p = mpi2bn(&key->q); + q = mpi2bn(&key->p); + u = mpi2bn(&key->u); + if (!d || !p || !q || !u) { + goto done; + } + /* We need to calculate exponents manually */ + bnctx = BN_CTX_new(); + if (!bnctx) { + RNP_LOG("Failed to allocate BN_CTX."); + goto done; + } + bignum_t *p1 = BN_CTX_get(bnctx); + bignum_t *q1 = BN_CTX_get(bnctx); + bignum_t *dp = BN_CTX_get(bnctx); + bignum_t *dq = BN_CTX_get(bnctx); + if (!BN_copy(p1, p) || !BN_sub_word(p1, 1) || !BN_copy(q1, q) || !BN_sub_word(q1, 1) || + !BN_mod(dp, d, p1, bnctx) || !BN_mod(dq, d, q1, bnctx)) { + RNP_LOG("Failed to calculate dP or dQ."); + } + /* Push params */ + if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, p) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, q) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, dp) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, dq) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u)) { + RNP_LOG("Failed to push RSA secret params."); + goto done; + } + } + params = OSSL_PARAM_BLD_to_param(bld); + if (!params) { + RNP_LOG("Failed to build RSA params: %s.", ossl_latest_err()); + } +done: + bn_free(n); + bn_free(e); + bn_free(d); + bn_free(p); + bn_free(q); + bn_free(u); + BN_CTX_free(bnctx); + OSSL_PARAM_BLD_free(bld); + return params; +} + +static EVP_PKEY * +rsa_load_key(const pgp_rsa_key_t *key, bool secret) +{ + /* Build params */ + OSSL_PARAM *params = rsa_bld_params(key, secret); + if (!params) { + return NULL; + } + /* Create context for key creation */ + EVP_PKEY * res = NULL; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %s", ossl_latest_err()); + goto done; + } + /* Create key */ + if (EVP_PKEY_fromdata_init(ctx) <= 0) { + RNP_LOG("Failed to initialize key creation: %s", ossl_latest_err()); + goto done; + } + if (EVP_PKEY_fromdata( + ctx, &res, secret ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) <= 0) { + RNP_LOG("Failed to create RSA key: %s", ossl_latest_err()); + } +done: + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + return res; +} + +static EVP_PKEY_CTX * +rsa_init_context(const pgp_rsa_key_t *key, bool secret) +{ + EVP_PKEY *pkey = rsa_load_key(key, secret); + if (!pkey) { + return NULL; + } + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!ctx) { + RNP_LOG("Context allocation failed: %s", ossl_latest_err()); + } + EVP_PKEY_free(pkey); + return ctx; +} +#endif + +rnp_result_t +rsa_validate_key(rnp::RNG *rng, const pgp_rsa_key_t *key, bool secret) +{ +#ifdef CRYPTO_BACKEND_OPENSSL3 + EVP_PKEY_CTX *ctx = rsa_init_context(key, secret); + if (!ctx) { + RNP_LOG("Failed to init context: %s", ossl_latest_err()); + return RNP_ERROR_GENERIC; + } + int res = secret ? EVP_PKEY_pairwise_check(ctx) : EVP_PKEY_public_check(ctx); + if (res <= 0) { + RNP_LOG("Key validation error: %s", ossl_latest_err()); + } + EVP_PKEY_CTX_free(ctx); + return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC; +#else + if (secret) { + EVP_PKEY_CTX *ctx = rsa_init_context(key, secret); + if (!ctx) { + RNP_LOG("Failed to init context: %s", ossl_latest_err()); + return RNP_ERROR_GENERIC; + } + int res = EVP_PKEY_check(ctx); + if (res <= 0) { + RNP_LOG("Key validation error: %s", ossl_latest_err()); + } + EVP_PKEY_CTX_free(ctx); + return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC; + } + + /* OpenSSL 1.1.1 doesn't have RSA public key check function, so let's do some checks */ + rnp_result_t ret = RNP_ERROR_GENERIC; + bignum_t * n = mpi2bn(&key->n); + bignum_t * e = mpi2bn(&key->e); + if (!n || !e) { + RNP_LOG("out of memory"); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + if ((BN_num_bits(n) < 512) || !BN_is_odd(n) || (BN_num_bits(e) < 2) || !BN_is_odd(e)) { + goto done; + } + ret = RNP_SUCCESS; +done: + bn_free(n); + bn_free(e); + return ret; +#endif +} + +static bool +rsa_setup_context(EVP_PKEY_CTX *ctx) +{ + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + RNP_LOG("Failed to set padding: %lu", ERR_peek_last_error()); + return false; + } + return true; +} + +static const uint8_t PKCS1_SHA1_ENCODING[15] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}; + +static bool +rsa_setup_signature_hash(EVP_PKEY_CTX * ctx, + pgp_hash_alg_t hash_alg, + const uint8_t *&enc, + size_t & enc_size) +{ + const char *hash_name = rnp::Hash_OpenSSL::name(hash_alg); + if (!hash_name) { + RNP_LOG("Unknown hash: %d", (int) hash_alg); + return false; + } + const EVP_MD *hash_tp = EVP_get_digestbyname(hash_name); + if (!hash_tp) { + RNP_LOG("Error creating hash object for '%s'", hash_name); + return false; + } + if (EVP_PKEY_CTX_set_signature_md(ctx, hash_tp) <= 0) { + if ((hash_alg != PGP_HASH_SHA1)) { + RNP_LOG("Failed to set digest %s: %s", hash_name, ossl_latest_err()); + return false; + } + enc = &PKCS1_SHA1_ENCODING[0]; + enc_size = sizeof(PKCS1_SHA1_ENCODING); + } else { + enc = NULL; + enc_size = 0; + } + return true; +} + +rnp_result_t +rsa_encrypt_pkcs1(rnp::RNG * rng, + pgp_rsa_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const pgp_rsa_key_t *key) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + EVP_PKEY_CTX *ctx = rsa_init_context(key, false); + if (!ctx) { + return ret; + } + if (EVP_PKEY_encrypt_init(ctx) <= 0) { + RNP_LOG("Failed to initialize encryption: %lu", ERR_peek_last_error()); + goto done; + } + if (!rsa_setup_context(ctx)) { + goto done; + } + out->m.len = sizeof(out->m.mpi); + if (EVP_PKEY_encrypt(ctx, out->m.mpi, &out->m.len, in, in_len) <= 0) { + RNP_LOG("Encryption failed: %lu", ERR_peek_last_error()); + out->m.len = 0; + goto done; + } + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + return ret; +} + +rnp_result_t +rsa_verify_pkcs1(const pgp_rsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_rsa_key_t * key) +{ + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + EVP_PKEY_CTX *ctx = rsa_init_context(key, false); + if (!ctx) { + return ret; + } + const uint8_t *hash_enc = NULL; + size_t hash_enc_size = 0; + uint8_t hash_enc_buf[PGP_MAX_HASH_SIZE + 32] = {0}; + assert(hash_len + hash_enc_size <= sizeof(hash_enc_buf)); + + if (EVP_PKEY_verify_init(ctx) <= 0) { + RNP_LOG("Failed to initialize verification: %lu", ERR_peek_last_error()); + goto done; + } + if (!rsa_setup_context(ctx) || + !rsa_setup_signature_hash(ctx, hash_alg, hash_enc, hash_enc_size)) { + goto done; + } + /* Check whether we need to workaround on unsupported SHA1 for RSA signature verification + */ + if (hash_enc_size) { + memcpy(hash_enc_buf, hash_enc, hash_enc_size); + memcpy(&hash_enc_buf[hash_enc_size], hash, hash_len); + hash = hash_enc_buf; + hash_len += hash_enc_size; + } + int res; + if (sig->s.len < key->n.len) { + /* OpenSSL doesn't like signatures smaller then N */ + pgp_mpi_t sn; + sn.len = key->n.len; + size_t diff = key->n.len - sig->s.len; + memset(sn.mpi, 0, diff); + memcpy(&sn.mpi[diff], sig->s.mpi, sig->s.len); + res = EVP_PKEY_verify(ctx, sn.mpi, sn.len, hash, hash_len); + } else { + res = EVP_PKEY_verify(ctx, sig->s.mpi, sig->s.len, hash, hash_len); + } + if (res > 0) { + ret = RNP_SUCCESS; + } else { + RNP_LOG("RSA verification failure: %s", ossl_latest_err()); + } +done: + EVP_PKEY_CTX_free(ctx); + return ret; +} + +rnp_result_t +rsa_sign_pkcs1(rnp::RNG * rng, + pgp_rsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_rsa_key_t *key) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + if (mpi_bytes(&key->q) == 0) { + RNP_LOG("private key not set"); + return ret; + } + EVP_PKEY_CTX *ctx = rsa_init_context(key, true); + if (!ctx) { + return ret; + } + const uint8_t *hash_enc = NULL; + size_t hash_enc_size = 0; + uint8_t hash_enc_buf[PGP_MAX_HASH_SIZE + 32] = {0}; + assert(hash_len + hash_enc_size <= sizeof(hash_enc_buf)); + if (EVP_PKEY_sign_init(ctx) <= 0) { + RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error()); + goto done; + } + if (!rsa_setup_context(ctx) || + !rsa_setup_signature_hash(ctx, hash_alg, hash_enc, hash_enc_size)) { + goto done; + } + /* Check whether we need to workaround on unsupported SHA1 for RSA signature verification + */ + if (hash_enc_size) { + memcpy(hash_enc_buf, hash_enc, hash_enc_size); + memcpy(&hash_enc_buf[hash_enc_size], hash, hash_len); + hash = hash_enc_buf; + hash_len += hash_enc_size; + } + sig->s.len = PGP_MPINT_SIZE; + if (EVP_PKEY_sign(ctx, sig->s.mpi, &sig->s.len, hash, hash_len) <= 0) { + RNP_LOG("Encryption failed: %lu", ERR_peek_last_error()); + sig->s.len = 0; + goto done; + } + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + return ret; +} + +rnp_result_t +rsa_decrypt_pkcs1(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_rsa_encrypted_t *in, + const pgp_rsa_key_t * key) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + if (mpi_bytes(&key->q) == 0) { + RNP_LOG("private key not set"); + return ret; + } + EVP_PKEY_CTX *ctx = rsa_init_context(key, true); + if (!ctx) { + return ret; + } + if (EVP_PKEY_decrypt_init(ctx) <= 0) { + RNP_LOG("Failed to initialize encryption: %lu", ERR_peek_last_error()); + goto done; + } + if (!rsa_setup_context(ctx)) { + goto done; + } + *out_len = PGP_MPINT_SIZE; + if (EVP_PKEY_decrypt(ctx, out, out_len, in->m.mpi, in->m.len) <= 0) { + RNP_LOG("Encryption failed: %lu", ERR_peek_last_error()); + *out_len = 0; + goto done; + } + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + return ret; +} + +rnp_result_t +rsa_generate(rnp::RNG *rng, pgp_rsa_key_t *key, size_t numbits) +{ + if ((numbits < 1024) || (numbits > PGP_MPINT_BITS)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + const RSA * rsa = NULL; + EVP_PKEY * pkey = NULL; + EVP_PKEY_CTX * ctx = NULL; + const bignum_t *u = NULL; + BN_CTX * bnctx = NULL; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (!ctx) { + RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error()); + return ret; + } + if (EVP_PKEY_keygen_init(ctx) <= 0) { + RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, numbits) <= 0) { + RNP_LOG("Failed to set rsa bits: %lu", ERR_peek_last_error()); + goto done; + } + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + RNP_LOG("RSA keygen failed: %lu", ERR_peek_last_error()); + goto done; + } + rsa = EVP_PKEY_get0_RSA(pkey); + if (!rsa) { + RNP_LOG("Failed to retrieve RSA key: %lu", ERR_peek_last_error()); + goto done; + } + if (RSA_check_key(rsa) != 1) { + RNP_LOG("Key validation error: %lu", ERR_peek_last_error()); + goto done; + } + + const bignum_t *n; + const bignum_t *e; + const bignum_t *p; + const bignum_t *q; + const bignum_t *d; + n = RSA_get0_n(rsa); + e = RSA_get0_e(rsa); + d = RSA_get0_d(rsa); + p = RSA_get0_p(rsa); + q = RSA_get0_q(rsa); + if (!n || !e || !d || !p || !q) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + /* OpenSSL doesn't care whether p < q */ + if (BN_cmp(p, q) > 0) { + /* In this case we have u, as iqmp is inverse of q mod p, and we exchange them */ + const bignum_t *tmp = p; + p = q; + q = tmp; + u = RSA_get0_iqmp(rsa); + } else { + /* we need to calculate u, since we need inverse of p mod q, while OpenSSL has inverse + * of q mod p, and doesn't care of p < q */ + bnctx = BN_CTX_new(); + if (!bnctx) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + BN_CTX_start(bnctx); + bignum_t *nu = BN_CTX_get(bnctx); + bignum_t *nq = BN_CTX_get(bnctx); + if (!nu || !nq) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + BN_with_flags(nq, q, BN_FLG_CONSTTIME); + /* calculate inverse of p mod q */ + if (!BN_mod_inverse(nu, p, nq, bnctx)) { + RNP_LOG("Failed to calculate u"); + ret = RNP_ERROR_BAD_STATE; + goto done; + } + u = nu; + } + bn2mpi(n, &key->n); + bn2mpi(e, &key->e); + bn2mpi(p, &key->p); + bn2mpi(q, &key->q); + bn2mpi(d, &key->d); + bn2mpi(u, &key->u); + ret = RNP_SUCCESS; +done: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + BN_CTX_free(bnctx); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/s2k.cpp b/comm/third_party/rnp/src/lib/crypto/s2k.cpp new file mode 100644 index 0000000000..ede7965dda --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/s2k.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017-2022 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "config.h" +#ifndef _MSC_VER +#include +#else +#include "uniwin.h" +#endif + +#include "crypto/s2k.h" +#include "defaults.h" +#include "rnp.h" +#include "types.h" +#include "utils.h" +#ifdef CRYPTO_BACKEND_BOTAN +#include +#include "hash_botan.hpp" +#endif + +bool +pgp_s2k_derive_key(pgp_s2k_t *s2k, const char *password, uint8_t *key, int keysize) +{ + uint8_t *saltptr = NULL; + unsigned iterations = 1; + + switch (s2k->specifier) { + case PGP_S2KS_SIMPLE: + break; + case PGP_S2KS_SALTED: + saltptr = s2k->salt; + break; + case PGP_S2KS_ITERATED_AND_SALTED: + saltptr = s2k->salt; + if (s2k->iterations < 256) { + iterations = pgp_s2k_decode_iterations(s2k->iterations); + } else { + iterations = s2k->iterations; + } + break; + default: + return false; + } + + if (pgp_s2k_iterated(s2k->hash_alg, key, keysize, password, saltptr, iterations)) { + RNP_LOG("s2k failed"); + return false; + } + + return true; +} + +#ifdef CRYPTO_BACKEND_BOTAN +int +pgp_s2k_iterated(pgp_hash_alg_t alg, + uint8_t * out, + size_t output_len, + const char * password, + const uint8_t *salt, + size_t iterations) +{ + char s2k_algo_str[128]; + snprintf(s2k_algo_str, + sizeof(s2k_algo_str), + "OpenPGP-S2K(%s)", + rnp::Hash_Botan::name_backend(alg)); + + return botan_pwdhash(s2k_algo_str, + iterations, + 0, + 0, + out, + output_len, + password, + 0, + salt, + salt ? PGP_SALT_SIZE : 0); +} +#endif + +size_t +pgp_s2k_decode_iterations(uint8_t c) +{ + // See RFC 4880 section 3.7.1.3 + return (16 + (c & 0x0F)) << ((c >> 4) + 6); +} + +size_t +pgp_s2k_round_iterations(size_t iterations) +{ + return pgp_s2k_decode_iterations(pgp_s2k_encode_iterations(iterations)); +} + +uint8_t +pgp_s2k_encode_iterations(size_t iterations) +{ + /* For compatibility, when an S2K specifier is used, the special value + * 254 or 255 is stored in the position where the hash algorithm octet + * would have been in the old data structure. This is then followed + * immediately by a one-octet algorithm identifier, and then by the S2K + * specifier as encoded above. + * 0: secret data is unencrypted (no password) + * 255 or 254: followed by algorithm octet and S2K specifier + * Cipher alg: use Simple S2K algorithm using MD5 hash + * For more info refer to rfc 4880 section 3.7.2.1. + */ + for (uint16_t c = 0; c < 256; ++c) { + // This could be a binary search + if (pgp_s2k_decode_iterations(c) >= iterations) { + return c; + } + } + return 255; +} + +/// Should this function be elsewhere? +static uint64_t +get_timestamp_usec() +{ +#ifndef _MSC_VER + // TODO: Consider clock_gettime + struct timeval tv; + ::gettimeofday(&tv, NULL); + return (static_cast(tv.tv_sec) * 1000000) + static_cast(tv.tv_usec); +#else + return GetTickCount64() * 1000; +#endif +} + +size_t +pgp_s2k_compute_iters(pgp_hash_alg_t alg, size_t desired_msec, size_t trial_msec) +{ + if (desired_msec == 0) { + desired_msec = DEFAULT_S2K_MSEC; + } + if (trial_msec == 0) { + trial_msec = DEFAULT_S2K_TUNE_MSEC; + } + + // number of iterations to estimate the number of iterations + // (sorry, cannot tell it better) + const uint8_t NUM_ITERATIONS = 16; + uint64_t duration = 0; + size_t bytes = 0; + try { + for (uint8_t i = 0; i < NUM_ITERATIONS; i++) { + uint64_t start = get_timestamp_usec(); + uint64_t end = start; + auto hash = rnp::Hash::create(alg); + uint8_t buf[8192] = {0}; + while (end - start < trial_msec * 1000ull) { + hash->add(buf, sizeof(buf)); + bytes += sizeof(buf); + end = get_timestamp_usec(); + } + hash->finish(buf); + duration += (end - start); + } + } catch (const std::exception &e) { + RNP_LOG("Failed to hash data: %s", e.what()); + return 0; + } + + const uint8_t MIN_ITERS = 96; + if (duration == 0) { + return pgp_s2k_decode_iterations(MIN_ITERS); + } + + const double bytes_per_usec = static_cast(bytes) / duration; + const double desired_usec = desired_msec * 1000.0; + const double bytes_for_target = bytes_per_usec * desired_usec; + const uint8_t iters = pgp_s2k_encode_iterations(bytes_for_target); + + return pgp_s2k_decode_iterations((iters > MIN_ITERS) ? iters : MIN_ITERS); +} diff --git a/comm/third_party/rnp/src/lib/crypto/s2k.h b/comm/third_party/rnp/src/lib/crypto/s2k.h new file mode 100644 index 0000000000..c67a77321c --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/s2k.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_S2K_H_ +#define RNP_S2K_H_ + +#include +#include "repgp/repgp_def.h" + +typedef struct pgp_s2k_t pgp_s2k_t; + +int pgp_s2k_iterated(pgp_hash_alg_t alg, + uint8_t * out, + size_t output_len, + const char * password, + const uint8_t *salt, + size_t iterations); + +size_t pgp_s2k_decode_iterations(uint8_t encoded_iter); + +uint8_t pgp_s2k_encode_iterations(size_t iterations); + +// Round iterations to nearest representable value +size_t pgp_s2k_round_iterations(size_t iterations); + +size_t pgp_s2k_compute_iters(pgp_hash_alg_t alg, size_t desired_msec, size_t trial_msec); + +/** @brief Derive key from password using the information stored in s2k structure + * @param s2k pointer to s2k structure, filled according to RFC 4880. + * Iterations field may contain encoded ( < 256) or decoded ( > 256) value. + * @param password NULL-terminated password + * @param key buffer to store the derived key, must have at least keysize bytes + * @param keysize number of bytes in the key. + * @return true on success or false otherwise + */ +bool pgp_s2k_derive_key(pgp_s2k_t *s2k, const char *password, uint8_t *key, int keysize); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/s2k_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/s2k_ossl.cpp new file mode 100644 index 0000000000..acf1ca9d8c --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/s2k_ossl.cpp @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "hash.hpp" +#include "s2k.h" +#include "mem.h" +#include "logging.h" + +int +pgp_s2k_iterated(pgp_hash_alg_t alg, + uint8_t * out, + size_t output_len, + const char * password, + const uint8_t *salt, + size_t iterations) +{ + if ((iterations > 1) && !salt) { + RNP_LOG("Iterated S2K mus be salted as well."); + return 1; + } + size_t hash_len = rnp::Hash::size(alg); + if (!hash_len) { + RNP_LOG("Unknown digest: %d", (int) alg); + return 1; + } + try { + size_t pswd_len = strlen(password); + size_t salt_len = salt ? PGP_SALT_SIZE : 0; + + rnp::secure_vector data(salt_len + pswd_len); + if (salt_len) { + memcpy(data.data(), salt, PGP_SALT_SIZE); + } + memcpy(data.data() + salt_len, password, pswd_len); + size_t zeroes = 0; + + while (output_len) { + /* create hash context */ + auto hash = rnp::Hash::create(alg); + /* add leading zeroes */ + for (size_t z = 0; z < zeroes; z++) { + uint8_t zero = 0; + hash->add(&zero, 1); + } + if (!data.empty()) { + /* if iteration is 1 then still hash the whole data chunk */ + size_t left = std::max(data.size(), iterations); + while (left) { + size_t to_hash = std::min(left, data.size()); + hash->add(data.data(), to_hash); + left -= to_hash; + } + } + rnp::secure_vector dgst(hash_len); + size_t out_cpy = std::min(dgst.size(), output_len); + if (hash->finish(dgst.data()) != dgst.size()) { + RNP_LOG("Unexpected digest size."); + return 1; + } + memcpy(out, dgst.data(), out_cpy); + output_len -= out_cpy; + out += out_cpy; + zeroes++; + } + return 0; + } catch (const std::exception &e) { + RNP_LOG("s2k failed: %s", e.what()); + return 1; + } +} diff --git a/comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.c b/comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.c new file mode 100644 index 0000000000..d90bc418f8 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.c @@ -0,0 +1,2162 @@ +/*** + * Copyright 2017 Marc Stevens , Dan Shumow (danshu@microsoft.com) + * Distributed under the MIT Software License. + * See accompanying file LICENSE.txt or copy at + * https://opensource.org/licenses/MIT + ***/ + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#include +#include +#include +#ifdef __unix__ +#include /* make sure macros like _BIG_ENDIAN visible */ +#endif +#endif + +#ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C +#include SHA1DC_CUSTOM_INCLUDE_SHA1_C +#endif + +#ifndef SHA1DC_INIT_SAFE_HASH_DEFAULT +#define SHA1DC_INIT_SAFE_HASH_DEFAULT 1 +#endif + +#include "sha1.h" +#include "ubc_check.h" + +#if (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \ + defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || \ + defined(__386) || defined(_M_X64) || defined(_M_AMD64)) +#define SHA1DC_ON_INTEL_LIKE_PROCESSOR +#endif + +/* + Because Little-Endian architectures are most common, + we only set SHA1DC_BIGENDIAN if one of these conditions is met. + Note that all MSFT platforms are little endian, + so none of these will be defined under the MSC compiler. + If you are compiling on a big endian platform and your compiler does not define one of + these, you will have to add whatever macros your tool chain defines to indicate + Big-Endianness. + */ + +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) +/* + * Should detect Big Endian under GCC since at least 4.6.0 (gcc svn + * rev #165881). See + * https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + * + * This also works under clang since 3.2, it copied the GCC-ism. See + * clang.git's 3b198a97d2 ("Preprocessor: add __BYTE_ORDER__ + * predefined macro", 2012-07-27) + */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define SHA1DC_BIGENDIAN +#endif + +/* Not under GCC-alike */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) +/* + * Should detect Big Endian under glibc.git since 14245eb70e ("entered + * into RCS", 1992-11-25). Defined in which will have been + * brought in by standard headers. See glibc.git and + * https://sourceforge.net/p/predef/wiki/Endianness/ + */ +#if __BYTE_ORDER == __BIG_ENDIAN +#define SHA1DC_BIGENDIAN +#endif + +/* Not under GCC-alike or glibc */ +#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) +/* + * *BSD and newlib (embedded linux, cygwin, etc). + * the defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) part prevents + * this condition from matching with Solaris/sparc. + * (Solaris defines only one endian macro) + */ +#if _BYTE_ORDER == _BIG_ENDIAN +#define SHA1DC_BIGENDIAN +#endif + +/* Not under GCC-alike or glibc or *BSD or newlib */ +#elif (defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ + defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(__sparc)) +/* + * Should define Big Endian for a whitelist of known processors. See + * https://sourceforge.net/p/predef/wiki/Endianness/ and + * http://www.oracle.com/technetwork/server-storage/solaris/portingtosolaris-138514.html + */ +#define SHA1DC_BIGENDIAN + +/* Not under GCC-alike or glibc or *BSD or newlib or */ +#elif (defined(_AIX) || defined(__hpux)) + +/* + * Defines Big Endian on a whitelist of OSs that are known to be Big + * Endian-only. See + * https://public-inbox.org/git/93056823-2740-d072-1ebd-46b440b33d7e@felt.demon.nl/ + */ +#define SHA1DC_BIGENDIAN + +/* Not under GCC-alike or glibc or *BSD or newlib or or */ +#elif defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR) +/* + * As a last resort before we do anything else we're not 100% sure + * about below, we blacklist specific processors here. We could add + * more, see e.g. https://wiki.debian.org/ArchitectureSpecificsMemo + */ +#else /* Not under GCC-alike or glibc or *BSD or newlib or or or */ + +/* We do nothing more here for now */ +/*#error "Uncomment this to see if you fall through all the detection"*/ + +#endif /* Big Endian detection */ + +#if (defined(SHA1DC_FORCE_LITTLEENDIAN) && defined(SHA1DC_BIGENDIAN)) +#undef SHA1DC_BIGENDIAN +#endif +#if (defined(SHA1DC_FORCE_BIGENDIAN) && !defined(SHA1DC_BIGENDIAN)) +#define SHA1DC_BIGENDIAN +#endif +/*ENDIANNESS SELECTION*/ + +#ifndef SHA1DC_FORCE_ALIGNED_ACCESS +#if defined(SHA1DC_FORCE_UNALIGNED_ACCESS) || defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR) +#define SHA1DC_ALLOW_UNALIGNED_ACCESS +#endif /*UNALIGNED ACCESS DETECTION*/ +#endif /*FORCE ALIGNED ACCESS*/ + +#define rotate_right(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define rotate_left(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define sha1_bswap32(x) \ + { \ + x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF); \ + x = (x << 16) | (x >> 16); \ + } + +#define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1)) + +#ifdef SHA1DC_BIGENDIAN +#define sha1_load(m, t, temp) \ + { \ + temp = m[t]; \ + } +#else +#define sha1_load(m, t, temp) \ + { \ + temp = m[t]; \ + sha1_bswap32(temp); \ + } +#endif + +#define sha1_store(W, t, x) *(volatile uint32_t *) &W[t] = x + +#define sha1_f1(b, c, d) ((d) ^ ((b) & ((c) ^ (d)))) +#define sha1_f2(b, c, d) ((b) ^ (c) ^ (d)) +#define sha1_f3(b, c, d) (((b) & (c)) + ((d) & ((b) ^ (c)))) +#define sha1_f4(b, c, d) ((b) ^ (c) ^ (d)) + +#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, m, t) \ + { \ + e += rotate_left(a, 5) + sha1_f1(b, c, d) + 0x5A827999 + m[t]; \ + b = rotate_left(b, 30); \ + } +#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, m, t) \ + { \ + e += rotate_left(a, 5) + sha1_f2(b, c, d) + 0x6ED9EBA1 + m[t]; \ + b = rotate_left(b, 30); \ + } +#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, m, t) \ + { \ + e += rotate_left(a, 5) + sha1_f3(b, c, d) + 0x8F1BBCDC + m[t]; \ + b = rotate_left(b, 30); \ + } +#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, m, t) \ + { \ + e += rotate_left(a, 5) + sha1_f4(b, c, d) + 0xCA62C1D6 + m[t]; \ + b = rotate_left(b, 30); \ + } + +#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, m, t) \ + { \ + b = rotate_right(b, 30); \ + e -= rotate_left(a, 5) + sha1_f1(b, c, d) + 0x5A827999 + m[t]; \ + } +#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, m, t) \ + { \ + b = rotate_right(b, 30); \ + e -= rotate_left(a, 5) + sha1_f2(b, c, d) + 0x6ED9EBA1 + m[t]; \ + } +#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, m, t) \ + { \ + b = rotate_right(b, 30); \ + e -= rotate_left(a, 5) + sha1_f3(b, c, d) + 0x8F1BBCDC + m[t]; \ + } +#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, m, t) \ + { \ + b = rotate_right(b, 30); \ + e -= rotate_left(a, 5) + sha1_f4(b, c, d) + 0xCA62C1D6 + m[t]; \ + } + +#define SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, t, temp) \ + { \ + sha1_load(m, t, temp); \ + sha1_store(W, t, temp); \ + e += temp + rotate_left(a, 5) + sha1_f1(b, c, d) + 0x5A827999; \ + b = rotate_left(b, 30); \ + } + +#define SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(a, b, c, d, e, W, t, temp) \ + { \ + temp = sha1_mix(W, t); \ + sha1_store(W, t, temp); \ + e += temp + rotate_left(a, 5) + sha1_f1(b, c, d) + 0x5A827999; \ + b = rotate_left(b, 30); \ + } + +#define SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, t, temp) \ + { \ + temp = sha1_mix(W, t); \ + sha1_store(W, t, temp); \ + e += temp + rotate_left(a, 5) + sha1_f2(b, c, d) + 0x6ED9EBA1; \ + b = rotate_left(b, 30); \ + } + +#define SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, t, temp) \ + { \ + temp = sha1_mix(W, t); \ + sha1_store(W, t, temp); \ + e += temp + rotate_left(a, 5) + sha1_f3(b, c, d) + 0x8F1BBCDC; \ + b = rotate_left(b, 30); \ + } + +#define SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, t, temp) \ + { \ + temp = sha1_mix(W, t); \ + sha1_store(W, t, temp); \ + e += temp + rotate_left(a, 5) + sha1_f4(b, c, d) + 0xCA62C1D6; \ + b = rotate_left(b, 30); \ + } + +#define SHA1_STORE_STATE(i) \ + states[i][0] = a; \ + states[i][1] = b; \ + states[i][2] = c; \ + states[i][3] = d; \ + states[i][4] = e; + +#ifdef BUILDNOCOLLDETECTSHA1COMPRESSION +void +sha1_compression(uint32_t ihv[5], const uint32_t m[16]) +{ + uint32_t W[80]; + uint32_t a, b, c, d, e; + unsigned i; + + memcpy(W, m, 16 * 4); + for (i = 16; i < 80; ++i) + W[i] = sha1_mix(W, i); + + a = ihv[0]; + b = ihv[1]; + c = ihv[2]; + d = ihv[3]; + e = ihv[4]; + + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); + + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + + ihv[0] += a; + ihv[1] += b; + ihv[2] += c; + ihv[3] += d; + ihv[4] += e; +} +#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/ + +static void +sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]) +{ + uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); + + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + + ihv[0] += a; + ihv[1] += b; + ihv[2] += c; + ihv[3] += d; + ihv[4] += e; +} + +void +sha1_compression_states(uint32_t ihv[5], + const uint32_t m[16], + uint32_t W[80], + uint32_t states[80][5]) +{ + uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + uint32_t temp; + +#ifdef DOSTORESTATE00 + SHA1_STORE_STATE(0) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp); + +#ifdef DOSTORESTATE01 + SHA1_STORE_STATE(1) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp); + +#ifdef DOSTORESTATE02 + SHA1_STORE_STATE(2) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp); + +#ifdef DOSTORESTATE03 + SHA1_STORE_STATE(3) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp); + +#ifdef DOSTORESTATE04 + SHA1_STORE_STATE(4) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp); + +#ifdef DOSTORESTATE05 + SHA1_STORE_STATE(5) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp); + +#ifdef DOSTORESTATE06 + SHA1_STORE_STATE(6) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp); + +#ifdef DOSTORESTATE07 + SHA1_STORE_STATE(7) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp); + +#ifdef DOSTORESTATE08 + SHA1_STORE_STATE(8) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp); + +#ifdef DOSTORESTATE09 + SHA1_STORE_STATE(9) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp); + +#ifdef DOSTORESTATE10 + SHA1_STORE_STATE(10) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp); + +#ifdef DOSTORESTATE11 + SHA1_STORE_STATE(11) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp); + +#ifdef DOSTORESTATE12 + SHA1_STORE_STATE(12) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp); + +#ifdef DOSTORESTATE13 + SHA1_STORE_STATE(13) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp); + +#ifdef DOSTORESTATE14 + SHA1_STORE_STATE(14) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp); + +#ifdef DOSTORESTATE15 + SHA1_STORE_STATE(15) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp); + +#ifdef DOSTORESTATE16 + SHA1_STORE_STATE(16) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp); + +#ifdef DOSTORESTATE17 + SHA1_STORE_STATE(17) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp); + +#ifdef DOSTORESTATE18 + SHA1_STORE_STATE(18) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp); + +#ifdef DOSTORESTATE19 + SHA1_STORE_STATE(19) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp); + +#ifdef DOSTORESTATE20 + SHA1_STORE_STATE(20) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp); + +#ifdef DOSTORESTATE21 + SHA1_STORE_STATE(21) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp); + +#ifdef DOSTORESTATE22 + SHA1_STORE_STATE(22) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp); + +#ifdef DOSTORESTATE23 + SHA1_STORE_STATE(23) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp); + +#ifdef DOSTORESTATE24 + SHA1_STORE_STATE(24) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp); + +#ifdef DOSTORESTATE25 + SHA1_STORE_STATE(25) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp); + +#ifdef DOSTORESTATE26 + SHA1_STORE_STATE(26) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp); + +#ifdef DOSTORESTATE27 + SHA1_STORE_STATE(27) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp); + +#ifdef DOSTORESTATE28 + SHA1_STORE_STATE(28) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp); + +#ifdef DOSTORESTATE29 + SHA1_STORE_STATE(29) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp); + +#ifdef DOSTORESTATE30 + SHA1_STORE_STATE(30) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp); + +#ifdef DOSTORESTATE31 + SHA1_STORE_STATE(31) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp); + +#ifdef DOSTORESTATE32 + SHA1_STORE_STATE(32) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp); + +#ifdef DOSTORESTATE33 + SHA1_STORE_STATE(33) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp); + +#ifdef DOSTORESTATE34 + SHA1_STORE_STATE(34) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp); + +#ifdef DOSTORESTATE35 + SHA1_STORE_STATE(35) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp); + +#ifdef DOSTORESTATE36 + SHA1_STORE_STATE(36) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp); + +#ifdef DOSTORESTATE37 + SHA1_STORE_STATE(37) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp); + +#ifdef DOSTORESTATE38 + SHA1_STORE_STATE(38) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp); + +#ifdef DOSTORESTATE39 + SHA1_STORE_STATE(39) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp); + +#ifdef DOSTORESTATE40 + SHA1_STORE_STATE(40) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp); + +#ifdef DOSTORESTATE41 + SHA1_STORE_STATE(41) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp); + +#ifdef DOSTORESTATE42 + SHA1_STORE_STATE(42) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp); + +#ifdef DOSTORESTATE43 + SHA1_STORE_STATE(43) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp); + +#ifdef DOSTORESTATE44 + SHA1_STORE_STATE(44) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp); + +#ifdef DOSTORESTATE45 + SHA1_STORE_STATE(45) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp); + +#ifdef DOSTORESTATE46 + SHA1_STORE_STATE(46) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp); + +#ifdef DOSTORESTATE47 + SHA1_STORE_STATE(47) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp); + +#ifdef DOSTORESTATE48 + SHA1_STORE_STATE(48) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp); + +#ifdef DOSTORESTATE49 + SHA1_STORE_STATE(49) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp); + +#ifdef DOSTORESTATE50 + SHA1_STORE_STATE(50) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp); + +#ifdef DOSTORESTATE51 + SHA1_STORE_STATE(51) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp); + +#ifdef DOSTORESTATE52 + SHA1_STORE_STATE(52) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp); + +#ifdef DOSTORESTATE53 + SHA1_STORE_STATE(53) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp); + +#ifdef DOSTORESTATE54 + SHA1_STORE_STATE(54) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp); + +#ifdef DOSTORESTATE55 + SHA1_STORE_STATE(55) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp); + +#ifdef DOSTORESTATE56 + SHA1_STORE_STATE(56) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp); + +#ifdef DOSTORESTATE57 + SHA1_STORE_STATE(57) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp); + +#ifdef DOSTORESTATE58 + SHA1_STORE_STATE(58) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp); + +#ifdef DOSTORESTATE59 + SHA1_STORE_STATE(59) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp); + +#ifdef DOSTORESTATE60 + SHA1_STORE_STATE(60) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp); + +#ifdef DOSTORESTATE61 + SHA1_STORE_STATE(61) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp); + +#ifdef DOSTORESTATE62 + SHA1_STORE_STATE(62) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp); + +#ifdef DOSTORESTATE63 + SHA1_STORE_STATE(63) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp); + +#ifdef DOSTORESTATE64 + SHA1_STORE_STATE(64) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp); + +#ifdef DOSTORESTATE65 + SHA1_STORE_STATE(65) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp); + +#ifdef DOSTORESTATE66 + SHA1_STORE_STATE(66) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp); + +#ifdef DOSTORESTATE67 + SHA1_STORE_STATE(67) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp); + +#ifdef DOSTORESTATE68 + SHA1_STORE_STATE(68) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp); + +#ifdef DOSTORESTATE69 + SHA1_STORE_STATE(69) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp); + +#ifdef DOSTORESTATE70 + SHA1_STORE_STATE(70) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp); + +#ifdef DOSTORESTATE71 + SHA1_STORE_STATE(71) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp); + +#ifdef DOSTORESTATE72 + SHA1_STORE_STATE(72) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp); + +#ifdef DOSTORESTATE73 + SHA1_STORE_STATE(73) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp); + +#ifdef DOSTORESTATE74 + SHA1_STORE_STATE(74) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp); + +#ifdef DOSTORESTATE75 + SHA1_STORE_STATE(75) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp); + +#ifdef DOSTORESTATE76 + SHA1_STORE_STATE(76) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp); + +#ifdef DOSTORESTATE77 + SHA1_STORE_STATE(77) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp); + +#ifdef DOSTORESTATE78 + SHA1_STORE_STATE(78) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp); + +#ifdef DOSTORESTATE79 + SHA1_STORE_STATE(79) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp); + + ihv[0] += a; + ihv[1] += b; + ihv[2] += c; + ihv[3] += d; + ihv[4] += e; +} + +#define SHA1_RECOMPRESS(t) \ + static void sha1recompress_fast_##t( \ + uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \ + { \ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; \ + if (t > 79) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 79); \ + if (t > 78) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 78); \ + if (t > 77) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 77); \ + if (t > 76) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 76); \ + if (t > 75) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 75); \ + if (t > 74) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 74); \ + if (t > 73) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 73); \ + if (t > 72) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 72); \ + if (t > 71) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 71); \ + if (t > 70) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 70); \ + if (t > 69) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 69); \ + if (t > 68) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 68); \ + if (t > 67) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 67); \ + if (t > 66) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 66); \ + if (t > 65) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 65); \ + if (t > 64) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 64); \ + if (t > 63) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 63); \ + if (t > 62) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 62); \ + if (t > 61) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 61); \ + if (t > 60) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 60); \ + if (t > 59) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 59); \ + if (t > 58) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 58); \ + if (t > 57) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 57); \ + if (t > 56) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 56); \ + if (t > 55) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 55); \ + if (t > 54) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 54); \ + if (t > 53) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 53); \ + if (t > 52) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 52); \ + if (t > 51) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 51); \ + if (t > 50) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 50); \ + if (t > 49) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 49); \ + if (t > 48) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 48); \ + if (t > 47) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 47); \ + if (t > 46) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 46); \ + if (t > 45) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 45); \ + if (t > 44) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 44); \ + if (t > 43) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 43); \ + if (t > 42) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 42); \ + if (t > 41) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 41); \ + if (t > 40) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 40); \ + if (t > 39) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 39); \ + if (t > 38) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 38); \ + if (t > 37) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 37); \ + if (t > 36) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 36); \ + if (t > 35) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 35); \ + if (t > 34) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 34); \ + if (t > 33) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 33); \ + if (t > 32) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 32); \ + if (t > 31) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 31); \ + if (t > 30) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 30); \ + if (t > 29) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 29); \ + if (t > 28) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 28); \ + if (t > 27) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 27); \ + if (t > 26) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 26); \ + if (t > 25) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 25); \ + if (t > 24) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 24); \ + if (t > 23) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 23); \ + if (t > 22) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 22); \ + if (t > 21) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 21); \ + if (t > 20) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 20); \ + if (t > 19) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 19); \ + if (t > 18) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 18); \ + if (t > 17) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 17); \ + if (t > 16) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 16); \ + if (t > 15) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 15); \ + if (t > 14) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 14); \ + if (t > 13) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 13); \ + if (t > 12) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 12); \ + if (t > 11) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 11); \ + if (t > 10) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 10); \ + if (t > 9) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 9); \ + if (t > 8) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 8); \ + if (t > 7) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 7); \ + if (t > 6) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 6); \ + if (t > 5) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 5); \ + if (t > 4) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 4); \ + if (t > 3) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 3); \ + if (t > 2) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 2); \ + if (t > 1) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 1); \ + if (t > 0) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 0); \ + ihvin[0] = a; \ + ihvin[1] = b; \ + ihvin[2] = c; \ + ihvin[3] = d; \ + ihvin[4] = e; \ + a = state[0]; \ + b = state[1]; \ + c = state[2]; \ + d = state[3]; \ + e = state[4]; \ + if (t <= 0) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 0); \ + if (t <= 1) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 1); \ + if (t <= 2) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 2); \ + if (t <= 3) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 3); \ + if (t <= 4) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 4); \ + if (t <= 5) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 5); \ + if (t <= 6) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 6); \ + if (t <= 7) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 7); \ + if (t <= 8) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 8); \ + if (t <= 9) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 9); \ + if (t <= 10) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 10); \ + if (t <= 11) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 11); \ + if (t <= 12) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 12); \ + if (t <= 13) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 13); \ + if (t <= 14) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 14); \ + if (t <= 15) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 15); \ + if (t <= 16) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 16); \ + if (t <= 17) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 17); \ + if (t <= 18) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 18); \ + if (t <= 19) \ + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 19); \ + if (t <= 20) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 20); \ + if (t <= 21) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 21); \ + if (t <= 22) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 22); \ + if (t <= 23) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 23); \ + if (t <= 24) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 24); \ + if (t <= 25) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 25); \ + if (t <= 26) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 26); \ + if (t <= 27) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 27); \ + if (t <= 28) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 28); \ + if (t <= 29) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 29); \ + if (t <= 30) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 30); \ + if (t <= 31) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 31); \ + if (t <= 32) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 32); \ + if (t <= 33) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 33); \ + if (t <= 34) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 34); \ + if (t <= 35) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 35); \ + if (t <= 36) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 36); \ + if (t <= 37) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 37); \ + if (t <= 38) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 38); \ + if (t <= 39) \ + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 39); \ + if (t <= 40) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 40); \ + if (t <= 41) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 41); \ + if (t <= 42) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 42); \ + if (t <= 43) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 43); \ + if (t <= 44) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 44); \ + if (t <= 45) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 45); \ + if (t <= 46) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 46); \ + if (t <= 47) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 47); \ + if (t <= 48) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 48); \ + if (t <= 49) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 49); \ + if (t <= 50) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 50); \ + if (t <= 51) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 51); \ + if (t <= 52) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 52); \ + if (t <= 53) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 53); \ + if (t <= 54) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 54); \ + if (t <= 55) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 55); \ + if (t <= 56) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 56); \ + if (t <= 57) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 57); \ + if (t <= 58) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 58); \ + if (t <= 59) \ + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 59); \ + if (t <= 60) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 60); \ + if (t <= 61) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 61); \ + if (t <= 62) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 62); \ + if (t <= 63) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 63); \ + if (t <= 64) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 64); \ + if (t <= 65) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 65); \ + if (t <= 66) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 66); \ + if (t <= 67) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 67); \ + if (t <= 68) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 68); \ + if (t <= 69) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 69); \ + if (t <= 70) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 70); \ + if (t <= 71) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 71); \ + if (t <= 72) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 72); \ + if (t <= 73) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 73); \ + if (t <= 74) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 74); \ + if (t <= 75) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 75); \ + if (t <= 76) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 76); \ + if (t <= 77) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 77); \ + if (t <= 78) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 78); \ + if (t <= 79) \ + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 79); \ + ihvout[0] = ihvin[0] + a; \ + ihvout[1] = ihvin[1] + b; \ + ihvout[2] = ihvin[2] + c; \ + ihvout[3] = ihvin[3] + d; \ + ihvout[4] = ihvin[4] + e; \ + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127) /* Compiler complains about the checks in the above macro \ + being constant. */ +#endif + +#ifdef DOSTORESTATE0 +SHA1_RECOMPRESS(0) +#endif + +#ifdef DOSTORESTATE1 +SHA1_RECOMPRESS(1) +#endif + +#ifdef DOSTORESTATE2 +SHA1_RECOMPRESS(2) +#endif + +#ifdef DOSTORESTATE3 +SHA1_RECOMPRESS(3) +#endif + +#ifdef DOSTORESTATE4 +SHA1_RECOMPRESS(4) +#endif + +#ifdef DOSTORESTATE5 +SHA1_RECOMPRESS(5) +#endif + +#ifdef DOSTORESTATE6 +SHA1_RECOMPRESS(6) +#endif + +#ifdef DOSTORESTATE7 +SHA1_RECOMPRESS(7) +#endif + +#ifdef DOSTORESTATE8 +SHA1_RECOMPRESS(8) +#endif + +#ifdef DOSTORESTATE9 +SHA1_RECOMPRESS(9) +#endif + +#ifdef DOSTORESTATE10 +SHA1_RECOMPRESS(10) +#endif + +#ifdef DOSTORESTATE11 +SHA1_RECOMPRESS(11) +#endif + +#ifdef DOSTORESTATE12 +SHA1_RECOMPRESS(12) +#endif + +#ifdef DOSTORESTATE13 +SHA1_RECOMPRESS(13) +#endif + +#ifdef DOSTORESTATE14 +SHA1_RECOMPRESS(14) +#endif + +#ifdef DOSTORESTATE15 +SHA1_RECOMPRESS(15) +#endif + +#ifdef DOSTORESTATE16 +SHA1_RECOMPRESS(16) +#endif + +#ifdef DOSTORESTATE17 +SHA1_RECOMPRESS(17) +#endif + +#ifdef DOSTORESTATE18 +SHA1_RECOMPRESS(18) +#endif + +#ifdef DOSTORESTATE19 +SHA1_RECOMPRESS(19) +#endif + +#ifdef DOSTORESTATE20 +SHA1_RECOMPRESS(20) +#endif + +#ifdef DOSTORESTATE21 +SHA1_RECOMPRESS(21) +#endif + +#ifdef DOSTORESTATE22 +SHA1_RECOMPRESS(22) +#endif + +#ifdef DOSTORESTATE23 +SHA1_RECOMPRESS(23) +#endif + +#ifdef DOSTORESTATE24 +SHA1_RECOMPRESS(24) +#endif + +#ifdef DOSTORESTATE25 +SHA1_RECOMPRESS(25) +#endif + +#ifdef DOSTORESTATE26 +SHA1_RECOMPRESS(26) +#endif + +#ifdef DOSTORESTATE27 +SHA1_RECOMPRESS(27) +#endif + +#ifdef DOSTORESTATE28 +SHA1_RECOMPRESS(28) +#endif + +#ifdef DOSTORESTATE29 +SHA1_RECOMPRESS(29) +#endif + +#ifdef DOSTORESTATE30 +SHA1_RECOMPRESS(30) +#endif + +#ifdef DOSTORESTATE31 +SHA1_RECOMPRESS(31) +#endif + +#ifdef DOSTORESTATE32 +SHA1_RECOMPRESS(32) +#endif + +#ifdef DOSTORESTATE33 +SHA1_RECOMPRESS(33) +#endif + +#ifdef DOSTORESTATE34 +SHA1_RECOMPRESS(34) +#endif + +#ifdef DOSTORESTATE35 +SHA1_RECOMPRESS(35) +#endif + +#ifdef DOSTORESTATE36 +SHA1_RECOMPRESS(36) +#endif + +#ifdef DOSTORESTATE37 +SHA1_RECOMPRESS(37) +#endif + +#ifdef DOSTORESTATE38 +SHA1_RECOMPRESS(38) +#endif + +#ifdef DOSTORESTATE39 +SHA1_RECOMPRESS(39) +#endif + +#ifdef DOSTORESTATE40 +SHA1_RECOMPRESS(40) +#endif + +#ifdef DOSTORESTATE41 +SHA1_RECOMPRESS(41) +#endif + +#ifdef DOSTORESTATE42 +SHA1_RECOMPRESS(42) +#endif + +#ifdef DOSTORESTATE43 +SHA1_RECOMPRESS(43) +#endif + +#ifdef DOSTORESTATE44 +SHA1_RECOMPRESS(44) +#endif + +#ifdef DOSTORESTATE45 +SHA1_RECOMPRESS(45) +#endif + +#ifdef DOSTORESTATE46 +SHA1_RECOMPRESS(46) +#endif + +#ifdef DOSTORESTATE47 +SHA1_RECOMPRESS(47) +#endif + +#ifdef DOSTORESTATE48 +SHA1_RECOMPRESS(48) +#endif + +#ifdef DOSTORESTATE49 +SHA1_RECOMPRESS(49) +#endif + +#ifdef DOSTORESTATE50 +SHA1_RECOMPRESS(50) +#endif + +#ifdef DOSTORESTATE51 +SHA1_RECOMPRESS(51) +#endif + +#ifdef DOSTORESTATE52 +SHA1_RECOMPRESS(52) +#endif + +#ifdef DOSTORESTATE53 +SHA1_RECOMPRESS(53) +#endif + +#ifdef DOSTORESTATE54 +SHA1_RECOMPRESS(54) +#endif + +#ifdef DOSTORESTATE55 +SHA1_RECOMPRESS(55) +#endif + +#ifdef DOSTORESTATE56 +SHA1_RECOMPRESS(56) +#endif + +#ifdef DOSTORESTATE57 +SHA1_RECOMPRESS(57) +#endif + +#ifdef DOSTORESTATE58 +SHA1_RECOMPRESS(58) +#endif + +#ifdef DOSTORESTATE59 +SHA1_RECOMPRESS(59) +#endif + +#ifdef DOSTORESTATE60 +SHA1_RECOMPRESS(60) +#endif + +#ifdef DOSTORESTATE61 +SHA1_RECOMPRESS(61) +#endif + +#ifdef DOSTORESTATE62 +SHA1_RECOMPRESS(62) +#endif + +#ifdef DOSTORESTATE63 +SHA1_RECOMPRESS(63) +#endif + +#ifdef DOSTORESTATE64 +SHA1_RECOMPRESS(64) +#endif + +#ifdef DOSTORESTATE65 +SHA1_RECOMPRESS(65) +#endif + +#ifdef DOSTORESTATE66 +SHA1_RECOMPRESS(66) +#endif + +#ifdef DOSTORESTATE67 +SHA1_RECOMPRESS(67) +#endif + +#ifdef DOSTORESTATE68 +SHA1_RECOMPRESS(68) +#endif + +#ifdef DOSTORESTATE69 +SHA1_RECOMPRESS(69) +#endif + +#ifdef DOSTORESTATE70 +SHA1_RECOMPRESS(70) +#endif + +#ifdef DOSTORESTATE71 +SHA1_RECOMPRESS(71) +#endif + +#ifdef DOSTORESTATE72 +SHA1_RECOMPRESS(72) +#endif + +#ifdef DOSTORESTATE73 +SHA1_RECOMPRESS(73) +#endif + +#ifdef DOSTORESTATE74 +SHA1_RECOMPRESS(74) +#endif + +#ifdef DOSTORESTATE75 +SHA1_RECOMPRESS(75) +#endif + +#ifdef DOSTORESTATE76 +SHA1_RECOMPRESS(76) +#endif + +#ifdef DOSTORESTATE77 +SHA1_RECOMPRESS(77) +#endif + +#ifdef DOSTORESTATE78 +SHA1_RECOMPRESS(78) +#endif + +#ifdef DOSTORESTATE79 +SHA1_RECOMPRESS(79) +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static void +sha1_recompression_step(uint32_t step, + uint32_t ihvin[5], + uint32_t ihvout[5], + const uint32_t me2[80], + const uint32_t state[5]) +{ + switch (step) { +#ifdef DOSTORESTATE0 + case 0: + sha1recompress_fast_0(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE1 + case 1: + sha1recompress_fast_1(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE2 + case 2: + sha1recompress_fast_2(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE3 + case 3: + sha1recompress_fast_3(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE4 + case 4: + sha1recompress_fast_4(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE5 + case 5: + sha1recompress_fast_5(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE6 + case 6: + sha1recompress_fast_6(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE7 + case 7: + sha1recompress_fast_7(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE8 + case 8: + sha1recompress_fast_8(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE9 + case 9: + sha1recompress_fast_9(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE10 + case 10: + sha1recompress_fast_10(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE11 + case 11: + sha1recompress_fast_11(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE12 + case 12: + sha1recompress_fast_12(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE13 + case 13: + sha1recompress_fast_13(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE14 + case 14: + sha1recompress_fast_14(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE15 + case 15: + sha1recompress_fast_15(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE16 + case 16: + sha1recompress_fast_16(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE17 + case 17: + sha1recompress_fast_17(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE18 + case 18: + sha1recompress_fast_18(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE19 + case 19: + sha1recompress_fast_19(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE20 + case 20: + sha1recompress_fast_20(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE21 + case 21: + sha1recompress_fast_21(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE22 + case 22: + sha1recompress_fast_22(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE23 + case 23: + sha1recompress_fast_23(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE24 + case 24: + sha1recompress_fast_24(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE25 + case 25: + sha1recompress_fast_25(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE26 + case 26: + sha1recompress_fast_26(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE27 + case 27: + sha1recompress_fast_27(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE28 + case 28: + sha1recompress_fast_28(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE29 + case 29: + sha1recompress_fast_29(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE30 + case 30: + sha1recompress_fast_30(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE31 + case 31: + sha1recompress_fast_31(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE32 + case 32: + sha1recompress_fast_32(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE33 + case 33: + sha1recompress_fast_33(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE34 + case 34: + sha1recompress_fast_34(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE35 + case 35: + sha1recompress_fast_35(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE36 + case 36: + sha1recompress_fast_36(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE37 + case 37: + sha1recompress_fast_37(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE38 + case 38: + sha1recompress_fast_38(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE39 + case 39: + sha1recompress_fast_39(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE40 + case 40: + sha1recompress_fast_40(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE41 + case 41: + sha1recompress_fast_41(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE42 + case 42: + sha1recompress_fast_42(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE43 + case 43: + sha1recompress_fast_43(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE44 + case 44: + sha1recompress_fast_44(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE45 + case 45: + sha1recompress_fast_45(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE46 + case 46: + sha1recompress_fast_46(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE47 + case 47: + sha1recompress_fast_47(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE48 + case 48: + sha1recompress_fast_48(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE49 + case 49: + sha1recompress_fast_49(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE50 + case 50: + sha1recompress_fast_50(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE51 + case 51: + sha1recompress_fast_51(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE52 + case 52: + sha1recompress_fast_52(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE53 + case 53: + sha1recompress_fast_53(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE54 + case 54: + sha1recompress_fast_54(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE55 + case 55: + sha1recompress_fast_55(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE56 + case 56: + sha1recompress_fast_56(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE57 + case 57: + sha1recompress_fast_57(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE58 + case 58: + sha1recompress_fast_58(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE59 + case 59: + sha1recompress_fast_59(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE60 + case 60: + sha1recompress_fast_60(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE61 + case 61: + sha1recompress_fast_61(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE62 + case 62: + sha1recompress_fast_62(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE63 + case 63: + sha1recompress_fast_63(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE64 + case 64: + sha1recompress_fast_64(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE65 + case 65: + sha1recompress_fast_65(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE66 + case 66: + sha1recompress_fast_66(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE67 + case 67: + sha1recompress_fast_67(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE68 + case 68: + sha1recompress_fast_68(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE69 + case 69: + sha1recompress_fast_69(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE70 + case 70: + sha1recompress_fast_70(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE71 + case 71: + sha1recompress_fast_71(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE72 + case 72: + sha1recompress_fast_72(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE73 + case 73: + sha1recompress_fast_73(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE74 + case 74: + sha1recompress_fast_74(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE75 + case 75: + sha1recompress_fast_75(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE76 + case 76: + sha1recompress_fast_76(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE77 + case 77: + sha1recompress_fast_77(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE78 + case 78: + sha1recompress_fast_78(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE79 + case 79: + sha1recompress_fast_79(ihvin, ihvout, me2, state); + break; +#endif + default: + abort(); + } +} + +static void +sha1_process(SHA1_CTX *ctx, const uint32_t block[16]) +{ + unsigned i, j; + uint32_t ubc_dv_mask[DVMASKSIZE] = {0xFFFFFFFF}; + uint32_t ihvtmp[5]; + + ctx->ihv1[0] = ctx->ihv[0]; + ctx->ihv1[1] = ctx->ihv[1]; + ctx->ihv1[2] = ctx->ihv[2]; + ctx->ihv1[3] = ctx->ihv[3]; + ctx->ihv1[4] = ctx->ihv[4]; + + sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states); + + if (ctx->detect_coll) { + if (ctx->ubc_check) { + ubc_check(ctx->m1, ubc_dv_mask); + } + + if (ubc_dv_mask[0] != 0) { + for (i = 0; sha1_dvs[i].dvType != 0; ++i) { + if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb)) { + for (j = 0; j < 80; ++j) + ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j]; + + sha1_recompression_step(sha1_dvs[i].testt, + ctx->ihv2, + ihvtmp, + ctx->m2, + ctx->states[sha1_dvs[i].testt]); + + /* to verify SHA-1 collision detection code with collisions for + * reduced-step SHA-1 */ + if ((0 == ((ihvtmp[0] ^ ctx->ihv[0]) | (ihvtmp[1] ^ ctx->ihv[1]) | + (ihvtmp[2] ^ ctx->ihv[2]) | (ihvtmp[3] ^ ctx->ihv[3]) | + (ihvtmp[4] ^ ctx->ihv[4]))) || + (ctx->reduced_round_coll && + 0 == ((ctx->ihv1[0] ^ ctx->ihv2[0]) | (ctx->ihv1[1] ^ ctx->ihv2[1]) | + (ctx->ihv1[2] ^ ctx->ihv2[2]) | (ctx->ihv1[3] ^ ctx->ihv2[3]) | + (ctx->ihv1[4] ^ ctx->ihv2[4])))) { + ctx->found_collision = 1; + + if (ctx->safe_hash) { + sha1_compression_W(ctx->ihv, ctx->m1); + sha1_compression_W(ctx->ihv, ctx->m1); + } + + break; + } + } + } + } + } +} + +void +SHA1DCInit(SHA1_CTX *ctx) +{ + ctx->total = 0; + ctx->ihv[0] = 0x67452301; + ctx->ihv[1] = 0xEFCDAB89; + ctx->ihv[2] = 0x98BADCFE; + ctx->ihv[3] = 0x10325476; + ctx->ihv[4] = 0xC3D2E1F0; + ctx->found_collision = 0; + ctx->safe_hash = SHA1DC_INIT_SAFE_HASH_DEFAULT; + ctx->ubc_check = 1; + ctx->detect_coll = 1; + ctx->reduced_round_coll = 0; + ctx->callback = NULL; +} + +void +SHA1DCSetSafeHash(SHA1_CTX *ctx, int safehash) +{ + if (safehash) + ctx->safe_hash = 1; + else + ctx->safe_hash = 0; +} + +void +SHA1DCSetUseUBC(SHA1_CTX *ctx, int ubc_check) +{ + if (ubc_check) + ctx->ubc_check = 1; + else + ctx->ubc_check = 0; +} + +void +SHA1DCSetUseDetectColl(SHA1_CTX *ctx, int detect_coll) +{ + if (detect_coll) + ctx->detect_coll = 1; + else + ctx->detect_coll = 0; +} + +void +SHA1DCSetDetectReducedRoundCollision(SHA1_CTX *ctx, int reduced_round_coll) +{ + if (reduced_round_coll) + ctx->reduced_round_coll = 1; + else + ctx->reduced_round_coll = 0; +} + +void +SHA1DCSetCallback(SHA1_CTX *ctx, collision_block_callback callback) +{ + ctx->callback = callback; +} + +void +SHA1DCUpdate(SHA1_CTX *ctx, const char *buf, size_t len) +{ + unsigned left, fill; + + if (len == 0) + return; + + left = ctx->total & 63; + fill = 64 - left; + + if (left && len >= fill) { + ctx->total += fill; + memcpy(ctx->buffer + left, buf, fill); + sha1_process(ctx, (uint32_t *) (ctx->buffer)); + buf += fill; + len -= fill; + left = 0; + } + while (len >= 64) { + ctx->total += 64; + +#if defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) + sha1_process(ctx, (uint32_t *) (buf)); +#else + memcpy(ctx->buffer, buf, 64); + sha1_process(ctx, (uint32_t *) (ctx->buffer)); +#endif /* defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) */ + buf += 64; + len -= 64; + } + if (len > 0) { + ctx->total += len; + memcpy(ctx->buffer + left, buf, len); + } +} + +static const unsigned char sha1_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int +SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx) +{ + uint32_t last = ctx->total & 63; + uint32_t padn = (last < 56) ? (56 - last) : (120 - last); + uint64_t total; + SHA1DCUpdate(ctx, (const char *) (sha1_padding), padn); + + total = ctx->total - padn; + total <<= 3; + ctx->buffer[56] = (unsigned char) (total >> 56); + ctx->buffer[57] = (unsigned char) (total >> 48); + ctx->buffer[58] = (unsigned char) (total >> 40); + ctx->buffer[59] = (unsigned char) (total >> 32); + ctx->buffer[60] = (unsigned char) (total >> 24); + ctx->buffer[61] = (unsigned char) (total >> 16); + ctx->buffer[62] = (unsigned char) (total >> 8); + ctx->buffer[63] = (unsigned char) (total); + sha1_process(ctx, (uint32_t *) (ctx->buffer)); + output[0] = (unsigned char) (ctx->ihv[0] >> 24); + output[1] = (unsigned char) (ctx->ihv[0] >> 16); + output[2] = (unsigned char) (ctx->ihv[0] >> 8); + output[3] = (unsigned char) (ctx->ihv[0]); + output[4] = (unsigned char) (ctx->ihv[1] >> 24); + output[5] = (unsigned char) (ctx->ihv[1] >> 16); + output[6] = (unsigned char) (ctx->ihv[1] >> 8); + output[7] = (unsigned char) (ctx->ihv[1]); + output[8] = (unsigned char) (ctx->ihv[2] >> 24); + output[9] = (unsigned char) (ctx->ihv[2] >> 16); + output[10] = (unsigned char) (ctx->ihv[2] >> 8); + output[11] = (unsigned char) (ctx->ihv[2]); + output[12] = (unsigned char) (ctx->ihv[3] >> 24); + output[13] = (unsigned char) (ctx->ihv[3] >> 16); + output[14] = (unsigned char) (ctx->ihv[3] >> 8); + output[15] = (unsigned char) (ctx->ihv[3]); + output[16] = (unsigned char) (ctx->ihv[4] >> 24); + output[17] = (unsigned char) (ctx->ihv[4] >> 16); + output[18] = (unsigned char) (ctx->ihv[4] >> 8); + output[19] = (unsigned char) (ctx->ihv[4]); + return ctx->found_collision; +} + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.h b/comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.h new file mode 100644 index 0000000000..5bc0925798 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sha1cd/sha1.h @@ -0,0 +1,122 @@ +/*** + * Copyright 2017 Marc Stevens , Dan Shumow + * Distributed under the MIT Software License. + * See accompanying file LICENSE.txt or copy at + * https://opensource.org/licenses/MIT + ***/ + +#ifndef SHA1DC_SHA1_H +#define SHA1DC_SHA1_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#endif + +/* sha-1 compression function that takes an already expanded message, and additionally store + * intermediate states */ +/* only stores states ii (the state between step ii-1 and step ii) when DOSTORESTATEii is + * defined in ubc_check.h */ +void sha1_compression_states(uint32_t[5], const uint32_t[16], uint32_t[80], uint32_t[80][5]); + +/* +// Function type for sha1_recompression_step_T (uint32_t ihvin[5], uint32_t ihvout[5], const +uint32_t me2[80], const uint32_t state[5]). +// Where 0 <= T < 80 +// me2 is an expanded message (the expansion of an original message block XOR'ed with a +disturbance vector's message block difference.) +// state is the internal state (a,b,c,d,e) before step T of the SHA-1 compression +function while processing the original message block. +// The function will return: +// ihvin: The reconstructed input chaining value. +// ihvout: The reconstructed output chaining value. +*/ +typedef void (*sha1_recompression_type)(uint32_t *, + uint32_t *, + const uint32_t *, + const uint32_t *); + +/* A callback function type that can be set to be called when a collision block has been found: + */ +/* void collision_block_callback(uint64_t byteoffset, const uint32_t ihvin1[5], const uint32_t + * ihvin2[5], const uint32_t m1[80], const uint32_t m2[80]) */ +typedef void (*collision_block_callback)( + uint64_t, const uint32_t *, const uint32_t *, const uint32_t *, const uint32_t *); + +/* The SHA-1 context. */ +typedef struct { + uint64_t total; + uint32_t ihv[5]; + unsigned char buffer[64]; + int found_collision; + int safe_hash; + int detect_coll; + int ubc_check; + int reduced_round_coll; + collision_block_callback callback; + + uint32_t ihv1[5]; + uint32_t ihv2[5]; + uint32_t m1[80]; + uint32_t m2[80]; + uint32_t states[80][5]; +} SHA1_CTX; + +/* Initialize SHA-1 context. */ +void SHA1DCInit(SHA1_CTX *); + +/* + Function to enable safe SHA-1 hashing: + Collision attacks are thwarted by hashing a detected near-collision block 3 times. + Think of it as extending SHA-1 from 80-steps to 240-steps for such blocks: + The best collision attacks against SHA-1 have complexity about 2^60, + thus for 240-steps an immediate lower-bound for the best cryptanalytic attacks would be + 2^180. An attacker would be better off using a generic birthday search of complexity 2^80. + + Enabling safe SHA-1 hashing will result in the correct SHA-1 hash for messages where no + collision attack was detected, but it will result in a different SHA-1 hash for messages + where a collision attack was detected. This will automatically invalidate SHA-1 based + digital signature forgeries. Enabled by default. +*/ +void SHA1DCSetSafeHash(SHA1_CTX *, int); + +/* + Function to disable or enable the use of Unavoidable Bitconditions (provides a significant + speed up). Enabled by default + */ +void SHA1DCSetUseUBC(SHA1_CTX *, int); + +/* + Function to disable or enable the use of Collision Detection. + Enabled by default. + */ +void SHA1DCSetUseDetectColl(SHA1_CTX *, int); + +/* function to disable or enable the detection of reduced-round SHA-1 collisions */ +/* disabled by default */ +void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX *, int); + +/* function to set a callback function, pass NULL to disable */ +/* by default no callback set */ +void SHA1DCSetCallback(SHA1_CTX *, collision_block_callback); + +/* update SHA-1 context with buffer contents */ +void SHA1DCUpdate(SHA1_CTX *, const char *, size_t); + +/* obtain SHA-1 hash from SHA-1 context */ +/* returns: 0 = no collision detected, otherwise = collision found => warn user for active + * attack */ +int SHA1DCFinal(unsigned char[20], SHA1_CTX *); + +#if defined(__cplusplus) +} +#endif + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H +#endif + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.c b/comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.c new file mode 100644 index 0000000000..c44c53d9d0 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.c @@ -0,0 +1,908 @@ +/*** + * Copyright 2017 Marc Stevens , Dan Shumow + * Distributed under the MIT Software License. + * See accompanying file LICENSE.txt or copy at + * https://opensource.org/licenses/MIT + ***/ + +/* +// this file was generated by the 'parse_bitrel' program in the tools section +// using the data files from directory 'tools/data/3565' +// +// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check +// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper) +// dm[80] is the expanded message block XOR-difference defined by the DV +// testt is the step to do the recompression from for collision detection +// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check +// +// ubc_check takes as input an expanded message block and verifies the unavoidable +bitconditions for all listed DVs +// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions +for that DV have been met +// thus one needs to do the recompression check for each DV that has its bit set +// +// ubc_check is programmatically generated and the unavoidable bitconditions have been +hardcoded +// a directly verifiable version named ubc_check_verify can be found in ubc_check_verify.c +// ubc_check has been verified against ubc_check_verify using the 'ubc_check_test' program in +the tools section +*/ + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#endif +#ifdef SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C +#include SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C +#endif +#include "ubc_check.h" + +static const uint32_t DV_I_43_0_bit = (uint32_t)(1) << 0; +static const uint32_t DV_I_44_0_bit = (uint32_t)(1) << 1; +static const uint32_t DV_I_45_0_bit = (uint32_t)(1) << 2; +static const uint32_t DV_I_46_0_bit = (uint32_t)(1) << 3; +static const uint32_t DV_I_46_2_bit = (uint32_t)(1) << 4; +static const uint32_t DV_I_47_0_bit = (uint32_t)(1) << 5; +static const uint32_t DV_I_47_2_bit = (uint32_t)(1) << 6; +static const uint32_t DV_I_48_0_bit = (uint32_t)(1) << 7; +static const uint32_t DV_I_48_2_bit = (uint32_t)(1) << 8; +static const uint32_t DV_I_49_0_bit = (uint32_t)(1) << 9; +static const uint32_t DV_I_49_2_bit = (uint32_t)(1) << 10; +static const uint32_t DV_I_50_0_bit = (uint32_t)(1) << 11; +static const uint32_t DV_I_50_2_bit = (uint32_t)(1) << 12; +static const uint32_t DV_I_51_0_bit = (uint32_t)(1) << 13; +static const uint32_t DV_I_51_2_bit = (uint32_t)(1) << 14; +static const uint32_t DV_I_52_0_bit = (uint32_t)(1) << 15; +static const uint32_t DV_II_45_0_bit = (uint32_t)(1) << 16; +static const uint32_t DV_II_46_0_bit = (uint32_t)(1) << 17; +static const uint32_t DV_II_46_2_bit = (uint32_t)(1) << 18; +static const uint32_t DV_II_47_0_bit = (uint32_t)(1) << 19; +static const uint32_t DV_II_48_0_bit = (uint32_t)(1) << 20; +static const uint32_t DV_II_49_0_bit = (uint32_t)(1) << 21; +static const uint32_t DV_II_49_2_bit = (uint32_t)(1) << 22; +static const uint32_t DV_II_50_0_bit = (uint32_t)(1) << 23; +static const uint32_t DV_II_50_2_bit = (uint32_t)(1) << 24; +static const uint32_t DV_II_51_0_bit = (uint32_t)(1) << 25; +static const uint32_t DV_II_51_2_bit = (uint32_t)(1) << 26; +static const uint32_t DV_II_52_0_bit = (uint32_t)(1) << 27; +static const uint32_t DV_II_53_0_bit = (uint32_t)(1) << 28; +static const uint32_t DV_II_54_0_bit = (uint32_t)(1) << 29; +static const uint32_t DV_II_55_0_bit = (uint32_t)(1) << 30; +static const uint32_t DV_II_56_0_bit = (uint32_t)(1) << 31; + +dv_info_t sha1_dvs[] = { + {1, 43, 0, 58, 0, 0, {0x08000000, 0x9800000c, 0xd8000010, 0x08000010, 0xb8000010, 0x98000000, + 0x60000000, 0x00000008, 0xc0000000, 0x90000014, 0x10000010, 0xb8000014, + 0x28000000, 0x20000010, 0x48000000, 0x08000018, 0x60000000, 0x90000010, + 0xf0000010, 0x90000008, 0xc0000000, 0x90000010, 0xf0000010, 0xb0000008, + 0x40000000, 0x90000000, 0xf0000010, 0x90000018, 0x60000000, 0x90000010, + 0x90000010, 0x90000000, 0x80000000, 0x00000010, 0xa0000000, 0x20000000, + 0xa0000000, 0x20000010, 0x00000000, 0x20000010, 0x20000000, 0x00000010, + 0x20000000, 0x00000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000020, + 0x00000001, 0x40000002, 0x40000040, 0x40000002, 0x80000004, 0x80000080, + 0x80000006, 0x00000049, 0x00000103, 0x80000009, 0x80000012, 0x80000202, + 0x00000018, 0x00000164, 0x00000408, 0x800000e6, 0x8000004c, 0x00000803, + 0x80000161, 0x80000599}}, + {1, 44, 0, 58, 0, 1, {0xb4000008, 0x08000000, 0x9800000c, 0xd8000010, 0x08000010, 0xb8000010, + 0x98000000, 0x60000000, 0x00000008, 0xc0000000, 0x90000014, 0x10000010, + 0xb8000014, 0x28000000, 0x20000010, 0x48000000, 0x08000018, 0x60000000, + 0x90000010, 0xf0000010, 0x90000008, 0xc0000000, 0x90000010, 0xf0000010, + 0xb0000008, 0x40000000, 0x90000000, 0xf0000010, 0x90000018, 0x60000000, + 0x90000010, 0x90000010, 0x90000000, 0x80000000, 0x00000010, 0xa0000000, + 0x20000000, 0xa0000000, 0x20000010, 0x00000000, 0x20000010, 0x20000000, + 0x00000010, 0x20000000, 0x00000010, 0xa0000000, 0x00000000, 0x20000000, + 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000020, 0x00000001, 0x40000002, 0x40000040, 0x40000002, 0x80000004, + 0x80000080, 0x80000006, 0x00000049, 0x00000103, 0x80000009, 0x80000012, + 0x80000202, 0x00000018, 0x00000164, 0x00000408, 0x800000e6, 0x8000004c, + 0x00000803, 0x80000161}}, + {1, 45, 0, 58, 0, 2, {0xf4000014, 0xb4000008, 0x08000000, 0x9800000c, 0xd8000010, 0x08000010, + 0xb8000010, 0x98000000, 0x60000000, 0x00000008, 0xc0000000, 0x90000014, + 0x10000010, 0xb8000014, 0x28000000, 0x20000010, 0x48000000, 0x08000018, + 0x60000000, 0x90000010, 0xf0000010, 0x90000008, 0xc0000000, 0x90000010, + 0xf0000010, 0xb0000008, 0x40000000, 0x90000000, 0xf0000010, 0x90000018, + 0x60000000, 0x90000010, 0x90000010, 0x90000000, 0x80000000, 0x00000010, + 0xa0000000, 0x20000000, 0xa0000000, 0x20000010, 0x00000000, 0x20000010, + 0x20000000, 0x00000010, 0x20000000, 0x00000010, 0xa0000000, 0x00000000, + 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000020, 0x00000001, 0x40000002, 0x40000040, 0x40000002, + 0x80000004, 0x80000080, 0x80000006, 0x00000049, 0x00000103, 0x80000009, + 0x80000012, 0x80000202, 0x00000018, 0x00000164, 0x00000408, 0x800000e6, + 0x8000004c, 0x00000803}}, + {1, 46, 0, 58, 0, 3, {0x2c000010, 0xf4000014, 0xb4000008, 0x08000000, 0x9800000c, 0xd8000010, + 0x08000010, 0xb8000010, 0x98000000, 0x60000000, 0x00000008, 0xc0000000, + 0x90000014, 0x10000010, 0xb8000014, 0x28000000, 0x20000010, 0x48000000, + 0x08000018, 0x60000000, 0x90000010, 0xf0000010, 0x90000008, 0xc0000000, + 0x90000010, 0xf0000010, 0xb0000008, 0x40000000, 0x90000000, 0xf0000010, + 0x90000018, 0x60000000, 0x90000010, 0x90000010, 0x90000000, 0x80000000, + 0x00000010, 0xa0000000, 0x20000000, 0xa0000000, 0x20000010, 0x00000000, + 0x20000010, 0x20000000, 0x00000010, 0x20000000, 0x00000010, 0xa0000000, + 0x00000000, 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000020, 0x00000001, 0x40000002, 0x40000040, + 0x40000002, 0x80000004, 0x80000080, 0x80000006, 0x00000049, 0x00000103, + 0x80000009, 0x80000012, 0x80000202, 0x00000018, 0x00000164, 0x00000408, + 0x800000e6, 0x8000004c}}, + {1, 46, 2, 58, 0, 4, {0xb0000040, 0xd0000053, 0xd0000022, 0x20000000, 0x60000032, 0x60000043, + 0x20000040, 0xe0000042, 0x60000002, 0x80000001, 0x00000020, 0x00000003, + 0x40000052, 0x40000040, 0xe0000052, 0xa0000000, 0x80000040, 0x20000001, + 0x20000060, 0x80000001, 0x40000042, 0xc0000043, 0x40000022, 0x00000003, + 0x40000042, 0xc0000043, 0xc0000022, 0x00000001, 0x40000002, 0xc0000043, + 0x40000062, 0x80000001, 0x40000042, 0x40000042, 0x40000002, 0x00000002, + 0x00000040, 0x80000002, 0x80000000, 0x80000002, 0x80000040, 0x00000000, + 0x80000040, 0x80000000, 0x00000040, 0x80000000, 0x00000040, 0x80000002, + 0x00000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000080, 0x00000004, 0x00000009, 0x00000101, + 0x00000009, 0x00000012, 0x00000202, 0x0000001a, 0x00000124, 0x0000040c, + 0x00000026, 0x0000004a, 0x0000080a, 0x00000060, 0x00000590, 0x00001020, + 0x0000039a, 0x00000132}}, + {1, 47, 0, 58, 0, 5, {0xc8000010, 0x2c000010, 0xf4000014, 0xb4000008, 0x08000000, 0x9800000c, + 0xd8000010, 0x08000010, 0xb8000010, 0x98000000, 0x60000000, 0x00000008, + 0xc0000000, 0x90000014, 0x10000010, 0xb8000014, 0x28000000, 0x20000010, + 0x48000000, 0x08000018, 0x60000000, 0x90000010, 0xf0000010, 0x90000008, + 0xc0000000, 0x90000010, 0xf0000010, 0xb0000008, 0x40000000, 0x90000000, + 0xf0000010, 0x90000018, 0x60000000, 0x90000010, 0x90000010, 0x90000000, + 0x80000000, 0x00000010, 0xa0000000, 0x20000000, 0xa0000000, 0x20000010, + 0x00000000, 0x20000010, 0x20000000, 0x00000010, 0x20000000, 0x00000010, + 0xa0000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000020, 0x00000001, 0x40000002, + 0x40000040, 0x40000002, 0x80000004, 0x80000080, 0x80000006, 0x00000049, + 0x00000103, 0x80000009, 0x80000012, 0x80000202, 0x00000018, 0x00000164, + 0x00000408, 0x800000e6}}, + {1, 47, 2, 58, 0, 6, {0x20000043, 0xb0000040, 0xd0000053, 0xd0000022, 0x20000000, 0x60000032, + 0x60000043, 0x20000040, 0xe0000042, 0x60000002, 0x80000001, 0x00000020, + 0x00000003, 0x40000052, 0x40000040, 0xe0000052, 0xa0000000, 0x80000040, + 0x20000001, 0x20000060, 0x80000001, 0x40000042, 0xc0000043, 0x40000022, + 0x00000003, 0x40000042, 0xc0000043, 0xc0000022, 0x00000001, 0x40000002, + 0xc0000043, 0x40000062, 0x80000001, 0x40000042, 0x40000042, 0x40000002, + 0x00000002, 0x00000040, 0x80000002, 0x80000000, 0x80000002, 0x80000040, + 0x00000000, 0x80000040, 0x80000000, 0x00000040, 0x80000000, 0x00000040, + 0x80000002, 0x00000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000004, 0x00000080, 0x00000004, 0x00000009, + 0x00000101, 0x00000009, 0x00000012, 0x00000202, 0x0000001a, 0x00000124, + 0x0000040c, 0x00000026, 0x0000004a, 0x0000080a, 0x00000060, 0x00000590, + 0x00001020, 0x0000039a}}, + {1, 48, 0, 58, 0, 7, {0xb800000a, 0xc8000010, 0x2c000010, 0xf4000014, 0xb4000008, 0x08000000, + 0x9800000c, 0xd8000010, 0x08000010, 0xb8000010, 0x98000000, 0x60000000, + 0x00000008, 0xc0000000, 0x90000014, 0x10000010, 0xb8000014, 0x28000000, + 0x20000010, 0x48000000, 0x08000018, 0x60000000, 0x90000010, 0xf0000010, + 0x90000008, 0xc0000000, 0x90000010, 0xf0000010, 0xb0000008, 0x40000000, + 0x90000000, 0xf0000010, 0x90000018, 0x60000000, 0x90000010, 0x90000010, + 0x90000000, 0x80000000, 0x00000010, 0xa0000000, 0x20000000, 0xa0000000, + 0x20000010, 0x00000000, 0x20000010, 0x20000000, 0x00000010, 0x20000000, + 0x00000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000020, 0x00000001, + 0x40000002, 0x40000040, 0x40000002, 0x80000004, 0x80000080, 0x80000006, + 0x00000049, 0x00000103, 0x80000009, 0x80000012, 0x80000202, 0x00000018, + 0x00000164, 0x00000408}}, + {1, 48, 2, 58, 0, 8, {0xe000002a, 0x20000043, 0xb0000040, 0xd0000053, 0xd0000022, 0x20000000, + 0x60000032, 0x60000043, 0x20000040, 0xe0000042, 0x60000002, 0x80000001, + 0x00000020, 0x00000003, 0x40000052, 0x40000040, 0xe0000052, 0xa0000000, + 0x80000040, 0x20000001, 0x20000060, 0x80000001, 0x40000042, 0xc0000043, + 0x40000022, 0x00000003, 0x40000042, 0xc0000043, 0xc0000022, 0x00000001, + 0x40000002, 0xc0000043, 0x40000062, 0x80000001, 0x40000042, 0x40000042, + 0x40000002, 0x00000002, 0x00000040, 0x80000002, 0x80000000, 0x80000002, + 0x80000040, 0x00000000, 0x80000040, 0x80000000, 0x00000040, 0x80000000, + 0x00000040, 0x80000002, 0x00000000, 0x80000000, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000080, 0x00000004, + 0x00000009, 0x00000101, 0x00000009, 0x00000012, 0x00000202, 0x0000001a, + 0x00000124, 0x0000040c, 0x00000026, 0x0000004a, 0x0000080a, 0x00000060, + 0x00000590, 0x00001020}}, + {1, 49, 0, 58, 0, 9, {0x18000000, 0xb800000a, 0xc8000010, 0x2c000010, 0xf4000014, 0xb4000008, + 0x08000000, 0x9800000c, 0xd8000010, 0x08000010, 0xb8000010, 0x98000000, + 0x60000000, 0x00000008, 0xc0000000, 0x90000014, 0x10000010, 0xb8000014, + 0x28000000, 0x20000010, 0x48000000, 0x08000018, 0x60000000, 0x90000010, + 0xf0000010, 0x90000008, 0xc0000000, 0x90000010, 0xf0000010, 0xb0000008, + 0x40000000, 0x90000000, 0xf0000010, 0x90000018, 0x60000000, 0x90000010, + 0x90000010, 0x90000000, 0x80000000, 0x00000010, 0xa0000000, 0x20000000, + 0xa0000000, 0x20000010, 0x00000000, 0x20000010, 0x20000000, 0x00000010, + 0x20000000, 0x00000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000020, + 0x00000001, 0x40000002, 0x40000040, 0x40000002, 0x80000004, 0x80000080, + 0x80000006, 0x00000049, 0x00000103, 0x80000009, 0x80000012, 0x80000202, + 0x00000018, 0x00000164}}, + {1, 49, 2, 58, 0, 10, {0x60000000, 0xe000002a, 0x20000043, 0xb0000040, 0xd0000053, + 0xd0000022, 0x20000000, 0x60000032, 0x60000043, 0x20000040, + 0xe0000042, 0x60000002, 0x80000001, 0x00000020, 0x00000003, + 0x40000052, 0x40000040, 0xe0000052, 0xa0000000, 0x80000040, + 0x20000001, 0x20000060, 0x80000001, 0x40000042, 0xc0000043, + 0x40000022, 0x00000003, 0x40000042, 0xc0000043, 0xc0000022, + 0x00000001, 0x40000002, 0xc0000043, 0x40000062, 0x80000001, + 0x40000042, 0x40000042, 0x40000002, 0x00000002, 0x00000040, + 0x80000002, 0x80000000, 0x80000002, 0x80000040, 0x00000000, + 0x80000040, 0x80000000, 0x00000040, 0x80000000, 0x00000040, + 0x80000002, 0x00000000, 0x80000000, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000004, + 0x00000080, 0x00000004, 0x00000009, 0x00000101, 0x00000009, + 0x00000012, 0x00000202, 0x0000001a, 0x00000124, 0x0000040c, + 0x00000026, 0x0000004a, 0x0000080a, 0x00000060, 0x00000590}}, + {1, 50, 0, 65, 0, 11, {0x0800000c, 0x18000000, 0xb800000a, 0xc8000010, 0x2c000010, + 0xf4000014, 0xb4000008, 0x08000000, 0x9800000c, 0xd8000010, + 0x08000010, 0xb8000010, 0x98000000, 0x60000000, 0x00000008, + 0xc0000000, 0x90000014, 0x10000010, 0xb8000014, 0x28000000, + 0x20000010, 0x48000000, 0x08000018, 0x60000000, 0x90000010, + 0xf0000010, 0x90000008, 0xc0000000, 0x90000010, 0xf0000010, + 0xb0000008, 0x40000000, 0x90000000, 0xf0000010, 0x90000018, + 0x60000000, 0x90000010, 0x90000010, 0x90000000, 0x80000000, + 0x00000010, 0xa0000000, 0x20000000, 0xa0000000, 0x20000010, + 0x00000000, 0x20000010, 0x20000000, 0x00000010, 0x20000000, + 0x00000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000020, 0x00000001, 0x40000002, 0x40000040, + 0x40000002, 0x80000004, 0x80000080, 0x80000006, 0x00000049, + 0x00000103, 0x80000009, 0x80000012, 0x80000202, 0x00000018}}, + {1, 50, 2, 65, 0, 12, {0x20000030, 0x60000000, 0xe000002a, 0x20000043, 0xb0000040, + 0xd0000053, 0xd0000022, 0x20000000, 0x60000032, 0x60000043, + 0x20000040, 0xe0000042, 0x60000002, 0x80000001, 0x00000020, + 0x00000003, 0x40000052, 0x40000040, 0xe0000052, 0xa0000000, + 0x80000040, 0x20000001, 0x20000060, 0x80000001, 0x40000042, + 0xc0000043, 0x40000022, 0x00000003, 0x40000042, 0xc0000043, + 0xc0000022, 0x00000001, 0x40000002, 0xc0000043, 0x40000062, + 0x80000001, 0x40000042, 0x40000042, 0x40000002, 0x00000002, + 0x00000040, 0x80000002, 0x80000000, 0x80000002, 0x80000040, + 0x00000000, 0x80000040, 0x80000000, 0x00000040, 0x80000000, + 0x00000040, 0x80000002, 0x00000000, 0x80000000, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000004, 0x00000080, 0x00000004, 0x00000009, 0x00000101, + 0x00000009, 0x00000012, 0x00000202, 0x0000001a, 0x00000124, + 0x0000040c, 0x00000026, 0x0000004a, 0x0000080a, 0x00000060}}, + {1, 51, 0, 65, 0, 13, {0xe8000000, 0x0800000c, 0x18000000, 0xb800000a, 0xc8000010, + 0x2c000010, 0xf4000014, 0xb4000008, 0x08000000, 0x9800000c, + 0xd8000010, 0x08000010, 0xb8000010, 0x98000000, 0x60000000, + 0x00000008, 0xc0000000, 0x90000014, 0x10000010, 0xb8000014, + 0x28000000, 0x20000010, 0x48000000, 0x08000018, 0x60000000, + 0x90000010, 0xf0000010, 0x90000008, 0xc0000000, 0x90000010, + 0xf0000010, 0xb0000008, 0x40000000, 0x90000000, 0xf0000010, + 0x90000018, 0x60000000, 0x90000010, 0x90000010, 0x90000000, + 0x80000000, 0x00000010, 0xa0000000, 0x20000000, 0xa0000000, + 0x20000010, 0x00000000, 0x20000010, 0x20000000, 0x00000010, + 0x20000000, 0x00000010, 0xa0000000, 0x00000000, 0x20000000, + 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000020, 0x00000001, 0x40000002, + 0x40000040, 0x40000002, 0x80000004, 0x80000080, 0x80000006, + 0x00000049, 0x00000103, 0x80000009, 0x80000012, 0x80000202}}, + {1, 51, 2, 65, 0, 14, {0xa0000003, 0x20000030, 0x60000000, 0xe000002a, 0x20000043, + 0xb0000040, 0xd0000053, 0xd0000022, 0x20000000, 0x60000032, + 0x60000043, 0x20000040, 0xe0000042, 0x60000002, 0x80000001, + 0x00000020, 0x00000003, 0x40000052, 0x40000040, 0xe0000052, + 0xa0000000, 0x80000040, 0x20000001, 0x20000060, 0x80000001, + 0x40000042, 0xc0000043, 0x40000022, 0x00000003, 0x40000042, + 0xc0000043, 0xc0000022, 0x00000001, 0x40000002, 0xc0000043, + 0x40000062, 0x80000001, 0x40000042, 0x40000042, 0x40000002, + 0x00000002, 0x00000040, 0x80000002, 0x80000000, 0x80000002, + 0x80000040, 0x00000000, 0x80000040, 0x80000000, 0x00000040, + 0x80000000, 0x00000040, 0x80000002, 0x00000000, 0x80000000, + 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000080, 0x00000004, 0x00000009, + 0x00000101, 0x00000009, 0x00000012, 0x00000202, 0x0000001a, + 0x00000124, 0x0000040c, 0x00000026, 0x0000004a, 0x0000080a}}, + {1, 52, 0, 65, 0, 15, {0x04000010, 0xe8000000, 0x0800000c, 0x18000000, 0xb800000a, + 0xc8000010, 0x2c000010, 0xf4000014, 0xb4000008, 0x08000000, + 0x9800000c, 0xd8000010, 0x08000010, 0xb8000010, 0x98000000, + 0x60000000, 0x00000008, 0xc0000000, 0x90000014, 0x10000010, + 0xb8000014, 0x28000000, 0x20000010, 0x48000000, 0x08000018, + 0x60000000, 0x90000010, 0xf0000010, 0x90000008, 0xc0000000, + 0x90000010, 0xf0000010, 0xb0000008, 0x40000000, 0x90000000, + 0xf0000010, 0x90000018, 0x60000000, 0x90000010, 0x90000010, + 0x90000000, 0x80000000, 0x00000010, 0xa0000000, 0x20000000, + 0xa0000000, 0x20000010, 0x00000000, 0x20000010, 0x20000000, + 0x00000010, 0x20000000, 0x00000010, 0xa0000000, 0x00000000, + 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000020, 0x00000001, + 0x40000002, 0x40000040, 0x40000002, 0x80000004, 0x80000080, + 0x80000006, 0x00000049, 0x00000103, 0x80000009, 0x80000012}}, + {2, 45, 0, 58, 0, 16, {0xec000014, 0x0c000002, 0xc0000010, 0xb400001c, 0x2c000004, + 0xbc000018, 0xb0000010, 0x0000000c, 0xb8000010, 0x08000018, + 0x78000010, 0x08000014, 0x70000010, 0xb800001c, 0xe8000000, + 0xb0000004, 0x58000010, 0xb000000c, 0x48000000, 0xb0000000, + 0xb8000010, 0x98000010, 0xa0000000, 0x00000000, 0x00000000, + 0x20000000, 0x80000000, 0x00000010, 0x00000000, 0x20000010, + 0x20000000, 0x00000010, 0x60000000, 0x00000018, 0xe0000000, + 0x90000000, 0x30000010, 0xb0000000, 0x20000000, 0x20000000, + 0xa0000000, 0x00000010, 0x80000000, 0x20000000, 0x20000000, + 0x20000000, 0x80000000, 0x00000010, 0x00000000, 0x20000010, + 0xa0000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000020, 0x00000001, 0x40000002, 0x40000041, + 0x40000022, 0x80000005, 0xc0000082, 0xc0000046, 0x4000004b, + 0x80000107, 0x00000089, 0x00000014, 0x8000024b, 0x0000011b, + 0x8000016d, 0x8000041a, 0x000002e4, 0x80000054, 0x00000967}}, + {2, 46, 0, 58, 0, 17, {0x2400001c, 0xec000014, 0x0c000002, 0xc0000010, 0xb400001c, + 0x2c000004, 0xbc000018, 0xb0000010, 0x0000000c, 0xb8000010, + 0x08000018, 0x78000010, 0x08000014, 0x70000010, 0xb800001c, + 0xe8000000, 0xb0000004, 0x58000010, 0xb000000c, 0x48000000, + 0xb0000000, 0xb8000010, 0x98000010, 0xa0000000, 0x00000000, + 0x00000000, 0x20000000, 0x80000000, 0x00000010, 0x00000000, + 0x20000010, 0x20000000, 0x00000010, 0x60000000, 0x00000018, + 0xe0000000, 0x90000000, 0x30000010, 0xb0000000, 0x20000000, + 0x20000000, 0xa0000000, 0x00000010, 0x80000000, 0x20000000, + 0x20000000, 0x20000000, 0x80000000, 0x00000010, 0x00000000, + 0x20000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000020, 0x00000001, 0x40000002, + 0x40000041, 0x40000022, 0x80000005, 0xc0000082, 0xc0000046, + 0x4000004b, 0x80000107, 0x00000089, 0x00000014, 0x8000024b, + 0x0000011b, 0x8000016d, 0x8000041a, 0x000002e4, 0x80000054}}, + {2, 46, 2, 58, 0, 18, {0x90000070, 0xb0000053, 0x30000008, 0x00000043, 0xd0000072, + 0xb0000010, 0xf0000062, 0xc0000042, 0x00000030, 0xe0000042, + 0x20000060, 0xe0000041, 0x20000050, 0xc0000041, 0xe0000072, + 0xa0000003, 0xc0000012, 0x60000041, 0xc0000032, 0x20000001, + 0xc0000002, 0xe0000042, 0x60000042, 0x80000002, 0x00000000, + 0x00000000, 0x80000000, 0x00000002, 0x00000040, 0x00000000, + 0x80000040, 0x80000000, 0x00000040, 0x80000001, 0x00000060, + 0x80000003, 0x40000002, 0xc0000040, 0xc0000002, 0x80000000, + 0x80000000, 0x80000002, 0x00000040, 0x00000002, 0x80000000, + 0x80000000, 0x80000000, 0x00000002, 0x00000040, 0x00000000, + 0x80000040, 0x80000002, 0x00000000, 0x80000000, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000080, 0x00000004, 0x00000009, + 0x00000105, 0x00000089, 0x00000016, 0x0000020b, 0x0000011b, + 0x0000012d, 0x0000041e, 0x00000224, 0x00000050, 0x0000092e, + 0x0000046c, 0x000005b6, 0x0000106a, 0x00000b90, 0x00000152}}, + {2, 47, 0, 58, 0, 19, {0x20000010, 0x2400001c, 0xec000014, 0x0c000002, 0xc0000010, + 0xb400001c, 0x2c000004, 0xbc000018, 0xb0000010, 0x0000000c, + 0xb8000010, 0x08000018, 0x78000010, 0x08000014, 0x70000010, + 0xb800001c, 0xe8000000, 0xb0000004, 0x58000010, 0xb000000c, + 0x48000000, 0xb0000000, 0xb8000010, 0x98000010, 0xa0000000, + 0x00000000, 0x00000000, 0x20000000, 0x80000000, 0x00000010, + 0x00000000, 0x20000010, 0x20000000, 0x00000010, 0x60000000, + 0x00000018, 0xe0000000, 0x90000000, 0x30000010, 0xb0000000, + 0x20000000, 0x20000000, 0xa0000000, 0x00000010, 0x80000000, + 0x20000000, 0x20000000, 0x20000000, 0x80000000, 0x00000010, + 0x00000000, 0x20000010, 0xa0000000, 0x00000000, 0x20000000, + 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000020, 0x00000001, + 0x40000002, 0x40000041, 0x40000022, 0x80000005, 0xc0000082, + 0xc0000046, 0x4000004b, 0x80000107, 0x00000089, 0x00000014, + 0x8000024b, 0x0000011b, 0x8000016d, 0x8000041a, 0x000002e4}}, + {2, 48, 0, 58, 0, 20, {0xbc00001a, 0x20000010, 0x2400001c, 0xec000014, 0x0c000002, + 0xc0000010, 0xb400001c, 0x2c000004, 0xbc000018, 0xb0000010, + 0x0000000c, 0xb8000010, 0x08000018, 0x78000010, 0x08000014, + 0x70000010, 0xb800001c, 0xe8000000, 0xb0000004, 0x58000010, + 0xb000000c, 0x48000000, 0xb0000000, 0xb8000010, 0x98000010, + 0xa0000000, 0x00000000, 0x00000000, 0x20000000, 0x80000000, + 0x00000010, 0x00000000, 0x20000010, 0x20000000, 0x00000010, + 0x60000000, 0x00000018, 0xe0000000, 0x90000000, 0x30000010, + 0xb0000000, 0x20000000, 0x20000000, 0xa0000000, 0x00000010, + 0x80000000, 0x20000000, 0x20000000, 0x20000000, 0x80000000, + 0x00000010, 0x00000000, 0x20000010, 0xa0000000, 0x00000000, + 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000020, + 0x00000001, 0x40000002, 0x40000041, 0x40000022, 0x80000005, + 0xc0000082, 0xc0000046, 0x4000004b, 0x80000107, 0x00000089, + 0x00000014, 0x8000024b, 0x0000011b, 0x8000016d, 0x8000041a}}, + {2, 49, 0, 58, 0, 21, {0x3c000004, 0xbc00001a, 0x20000010, 0x2400001c, 0xec000014, + 0x0c000002, 0xc0000010, 0xb400001c, 0x2c000004, 0xbc000018, + 0xb0000010, 0x0000000c, 0xb8000010, 0x08000018, 0x78000010, + 0x08000014, 0x70000010, 0xb800001c, 0xe8000000, 0xb0000004, + 0x58000010, 0xb000000c, 0x48000000, 0xb0000000, 0xb8000010, + 0x98000010, 0xa0000000, 0x00000000, 0x00000000, 0x20000000, + 0x80000000, 0x00000010, 0x00000000, 0x20000010, 0x20000000, + 0x00000010, 0x60000000, 0x00000018, 0xe0000000, 0x90000000, + 0x30000010, 0xb0000000, 0x20000000, 0x20000000, 0xa0000000, + 0x00000010, 0x80000000, 0x20000000, 0x20000000, 0x20000000, + 0x80000000, 0x00000010, 0x00000000, 0x20000010, 0xa0000000, + 0x00000000, 0x20000000, 0x20000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000020, 0x00000001, 0x40000002, 0x40000041, 0x40000022, + 0x80000005, 0xc0000082, 0xc0000046, 0x4000004b, 0x80000107, + 0x00000089, 0x00000014, 0x8000024b, 0x0000011b, 0x8000016d}}, + {2, 49, 2, 58, 0, 22, {0xf0000010, 0xf000006a, 0x80000040, 0x90000070, 0xb0000053, + 0x30000008, 0x00000043, 0xd0000072, 0xb0000010, 0xf0000062, + 0xc0000042, 0x00000030, 0xe0000042, 0x20000060, 0xe0000041, + 0x20000050, 0xc0000041, 0xe0000072, 0xa0000003, 0xc0000012, + 0x60000041, 0xc0000032, 0x20000001, 0xc0000002, 0xe0000042, + 0x60000042, 0x80000002, 0x00000000, 0x00000000, 0x80000000, + 0x00000002, 0x00000040, 0x00000000, 0x80000040, 0x80000000, + 0x00000040, 0x80000001, 0x00000060, 0x80000003, 0x40000002, + 0xc0000040, 0xc0000002, 0x80000000, 0x80000000, 0x80000002, + 0x00000040, 0x00000002, 0x80000000, 0x80000000, 0x80000000, + 0x00000002, 0x00000040, 0x00000000, 0x80000040, 0x80000002, + 0x00000000, 0x80000000, 0x80000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000004, + 0x00000080, 0x00000004, 0x00000009, 0x00000105, 0x00000089, + 0x00000016, 0x0000020b, 0x0000011b, 0x0000012d, 0x0000041e, + 0x00000224, 0x00000050, 0x0000092e, 0x0000046c, 0x000005b6}}, + {2, 50, 0, 65, 0, 23, {0xb400001c, 0x3c000004, 0xbc00001a, 0x20000010, 0x2400001c, + 0xec000014, 0x0c000002, 0xc0000010, 0xb400001c, 0x2c000004, + 0xbc000018, 0xb0000010, 0x0000000c, 0xb8000010, 0x08000018, + 0x78000010, 0x08000014, 0x70000010, 0xb800001c, 0xe8000000, + 0xb0000004, 0x58000010, 0xb000000c, 0x48000000, 0xb0000000, + 0xb8000010, 0x98000010, 0xa0000000, 0x00000000, 0x00000000, + 0x20000000, 0x80000000, 0x00000010, 0x00000000, 0x20000010, + 0x20000000, 0x00000010, 0x60000000, 0x00000018, 0xe0000000, + 0x90000000, 0x30000010, 0xb0000000, 0x20000000, 0x20000000, + 0xa0000000, 0x00000010, 0x80000000, 0x20000000, 0x20000000, + 0x20000000, 0x80000000, 0x00000010, 0x00000000, 0x20000010, + 0xa0000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000020, 0x00000001, 0x40000002, 0x40000041, + 0x40000022, 0x80000005, 0xc0000082, 0xc0000046, 0x4000004b, + 0x80000107, 0x00000089, 0x00000014, 0x8000024b, 0x0000011b}}, + {2, 50, 2, 65, 0, 24, {0xd0000072, 0xf0000010, 0xf000006a, 0x80000040, 0x90000070, + 0xb0000053, 0x30000008, 0x00000043, 0xd0000072, 0xb0000010, + 0xf0000062, 0xc0000042, 0x00000030, 0xe0000042, 0x20000060, + 0xe0000041, 0x20000050, 0xc0000041, 0xe0000072, 0xa0000003, + 0xc0000012, 0x60000041, 0xc0000032, 0x20000001, 0xc0000002, + 0xe0000042, 0x60000042, 0x80000002, 0x00000000, 0x00000000, + 0x80000000, 0x00000002, 0x00000040, 0x00000000, 0x80000040, + 0x80000000, 0x00000040, 0x80000001, 0x00000060, 0x80000003, + 0x40000002, 0xc0000040, 0xc0000002, 0x80000000, 0x80000000, + 0x80000002, 0x00000040, 0x00000002, 0x80000000, 0x80000000, + 0x80000000, 0x00000002, 0x00000040, 0x00000000, 0x80000040, + 0x80000002, 0x00000000, 0x80000000, 0x80000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000004, 0x00000080, 0x00000004, 0x00000009, 0x00000105, + 0x00000089, 0x00000016, 0x0000020b, 0x0000011b, 0x0000012d, + 0x0000041e, 0x00000224, 0x00000050, 0x0000092e, 0x0000046c}}, + {2, 51, 0, 65, 0, 25, {0xc0000010, 0xb400001c, 0x3c000004, 0xbc00001a, 0x20000010, + 0x2400001c, 0xec000014, 0x0c000002, 0xc0000010, 0xb400001c, + 0x2c000004, 0xbc000018, 0xb0000010, 0x0000000c, 0xb8000010, + 0x08000018, 0x78000010, 0x08000014, 0x70000010, 0xb800001c, + 0xe8000000, 0xb0000004, 0x58000010, 0xb000000c, 0x48000000, + 0xb0000000, 0xb8000010, 0x98000010, 0xa0000000, 0x00000000, + 0x00000000, 0x20000000, 0x80000000, 0x00000010, 0x00000000, + 0x20000010, 0x20000000, 0x00000010, 0x60000000, 0x00000018, + 0xe0000000, 0x90000000, 0x30000010, 0xb0000000, 0x20000000, + 0x20000000, 0xa0000000, 0x00000010, 0x80000000, 0x20000000, + 0x20000000, 0x20000000, 0x80000000, 0x00000010, 0x00000000, + 0x20000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000020, 0x00000001, 0x40000002, + 0x40000041, 0x40000022, 0x80000005, 0xc0000082, 0xc0000046, + 0x4000004b, 0x80000107, 0x00000089, 0x00000014, 0x8000024b}}, + {2, 51, 2, 65, 0, 26, {0x00000043, 0xd0000072, 0xf0000010, 0xf000006a, 0x80000040, + 0x90000070, 0xb0000053, 0x30000008, 0x00000043, 0xd0000072, + 0xb0000010, 0xf0000062, 0xc0000042, 0x00000030, 0xe0000042, + 0x20000060, 0xe0000041, 0x20000050, 0xc0000041, 0xe0000072, + 0xa0000003, 0xc0000012, 0x60000041, 0xc0000032, 0x20000001, + 0xc0000002, 0xe0000042, 0x60000042, 0x80000002, 0x00000000, + 0x00000000, 0x80000000, 0x00000002, 0x00000040, 0x00000000, + 0x80000040, 0x80000000, 0x00000040, 0x80000001, 0x00000060, + 0x80000003, 0x40000002, 0xc0000040, 0xc0000002, 0x80000000, + 0x80000000, 0x80000002, 0x00000040, 0x00000002, 0x80000000, + 0x80000000, 0x80000000, 0x00000002, 0x00000040, 0x00000000, + 0x80000040, 0x80000002, 0x00000000, 0x80000000, 0x80000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000080, 0x00000004, 0x00000009, + 0x00000105, 0x00000089, 0x00000016, 0x0000020b, 0x0000011b, + 0x0000012d, 0x0000041e, 0x00000224, 0x00000050, 0x0000092e}}, + {2, 52, 0, 65, 0, 27, {0x0c000002, 0xc0000010, 0xb400001c, 0x3c000004, 0xbc00001a, + 0x20000010, 0x2400001c, 0xec000014, 0x0c000002, 0xc0000010, + 0xb400001c, 0x2c000004, 0xbc000018, 0xb0000010, 0x0000000c, + 0xb8000010, 0x08000018, 0x78000010, 0x08000014, 0x70000010, + 0xb800001c, 0xe8000000, 0xb0000004, 0x58000010, 0xb000000c, + 0x48000000, 0xb0000000, 0xb8000010, 0x98000010, 0xa0000000, + 0x00000000, 0x00000000, 0x20000000, 0x80000000, 0x00000010, + 0x00000000, 0x20000010, 0x20000000, 0x00000010, 0x60000000, + 0x00000018, 0xe0000000, 0x90000000, 0x30000010, 0xb0000000, + 0x20000000, 0x20000000, 0xa0000000, 0x00000010, 0x80000000, + 0x20000000, 0x20000000, 0x20000000, 0x80000000, 0x00000010, + 0x00000000, 0x20000010, 0xa0000000, 0x00000000, 0x20000000, + 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000020, 0x00000001, + 0x40000002, 0x40000041, 0x40000022, 0x80000005, 0xc0000082, + 0xc0000046, 0x4000004b, 0x80000107, 0x00000089, 0x00000014}}, + {2, 53, 0, 65, 0, 28, {0xcc000014, 0x0c000002, 0xc0000010, 0xb400001c, 0x3c000004, + 0xbc00001a, 0x20000010, 0x2400001c, 0xec000014, 0x0c000002, + 0xc0000010, 0xb400001c, 0x2c000004, 0xbc000018, 0xb0000010, + 0x0000000c, 0xb8000010, 0x08000018, 0x78000010, 0x08000014, + 0x70000010, 0xb800001c, 0xe8000000, 0xb0000004, 0x58000010, + 0xb000000c, 0x48000000, 0xb0000000, 0xb8000010, 0x98000010, + 0xa0000000, 0x00000000, 0x00000000, 0x20000000, 0x80000000, + 0x00000010, 0x00000000, 0x20000010, 0x20000000, 0x00000010, + 0x60000000, 0x00000018, 0xe0000000, 0x90000000, 0x30000010, + 0xb0000000, 0x20000000, 0x20000000, 0xa0000000, 0x00000010, + 0x80000000, 0x20000000, 0x20000000, 0x20000000, 0x80000000, + 0x00000010, 0x00000000, 0x20000010, 0xa0000000, 0x00000000, + 0x20000000, 0x20000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000020, + 0x00000001, 0x40000002, 0x40000041, 0x40000022, 0x80000005, + 0xc0000082, 0xc0000046, 0x4000004b, 0x80000107, 0x00000089}}, + {2, 54, 0, 65, 0, 29, {0x0400001c, 0xcc000014, 0x0c000002, 0xc0000010, 0xb400001c, + 0x3c000004, 0xbc00001a, 0x20000010, 0x2400001c, 0xec000014, + 0x0c000002, 0xc0000010, 0xb400001c, 0x2c000004, 0xbc000018, + 0xb0000010, 0x0000000c, 0xb8000010, 0x08000018, 0x78000010, + 0x08000014, 0x70000010, 0xb800001c, 0xe8000000, 0xb0000004, + 0x58000010, 0xb000000c, 0x48000000, 0xb0000000, 0xb8000010, + 0x98000010, 0xa0000000, 0x00000000, 0x00000000, 0x20000000, + 0x80000000, 0x00000010, 0x00000000, 0x20000010, 0x20000000, + 0x00000010, 0x60000000, 0x00000018, 0xe0000000, 0x90000000, + 0x30000010, 0xb0000000, 0x20000000, 0x20000000, 0xa0000000, + 0x00000010, 0x80000000, 0x20000000, 0x20000000, 0x20000000, + 0x80000000, 0x00000010, 0x00000000, 0x20000010, 0xa0000000, + 0x00000000, 0x20000000, 0x20000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000020, 0x00000001, 0x40000002, 0x40000041, 0x40000022, + 0x80000005, 0xc0000082, 0xc0000046, 0x4000004b, 0x80000107}}, + {2, 55, 0, 65, 0, 30, {0x00000010, 0x0400001c, 0xcc000014, 0x0c000002, 0xc0000010, + 0xb400001c, 0x3c000004, 0xbc00001a, 0x20000010, 0x2400001c, + 0xec000014, 0x0c000002, 0xc0000010, 0xb400001c, 0x2c000004, + 0xbc000018, 0xb0000010, 0x0000000c, 0xb8000010, 0x08000018, + 0x78000010, 0x08000014, 0x70000010, 0xb800001c, 0xe8000000, + 0xb0000004, 0x58000010, 0xb000000c, 0x48000000, 0xb0000000, + 0xb8000010, 0x98000010, 0xa0000000, 0x00000000, 0x00000000, + 0x20000000, 0x80000000, 0x00000010, 0x00000000, 0x20000010, + 0x20000000, 0x00000010, 0x60000000, 0x00000018, 0xe0000000, + 0x90000000, 0x30000010, 0xb0000000, 0x20000000, 0x20000000, + 0xa0000000, 0x00000010, 0x80000000, 0x20000000, 0x20000000, + 0x20000000, 0x80000000, 0x00000010, 0x00000000, 0x20000010, + 0xa0000000, 0x00000000, 0x20000000, 0x20000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000020, 0x00000001, 0x40000002, 0x40000041, + 0x40000022, 0x80000005, 0xc0000082, 0xc0000046, 0x4000004b}}, + {2, 56, 0, 65, 0, 31, {0x2600001a, 0x00000010, 0x0400001c, 0xcc000014, 0x0c000002, + 0xc0000010, 0xb400001c, 0x3c000004, 0xbc00001a, 0x20000010, + 0x2400001c, 0xec000014, 0x0c000002, 0xc0000010, 0xb400001c, + 0x2c000004, 0xbc000018, 0xb0000010, 0x0000000c, 0xb8000010, + 0x08000018, 0x78000010, 0x08000014, 0x70000010, 0xb800001c, + 0xe8000000, 0xb0000004, 0x58000010, 0xb000000c, 0x48000000, + 0xb0000000, 0xb8000010, 0x98000010, 0xa0000000, 0x00000000, + 0x00000000, 0x20000000, 0x80000000, 0x00000010, 0x00000000, + 0x20000010, 0x20000000, 0x00000010, 0x60000000, 0x00000018, + 0xe0000000, 0x90000000, 0x30000010, 0xb0000000, 0x20000000, + 0x20000000, 0xa0000000, 0x00000010, 0x80000000, 0x20000000, + 0x20000000, 0x20000000, 0x80000000, 0x00000010, 0x00000000, + 0x20000010, 0xa0000000, 0x00000000, 0x20000000, 0x20000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000020, 0x00000001, 0x40000002, + 0x40000041, 0x40000022, 0x80000005, 0xc0000082, 0xc0000046}}, + {0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}; +void +ubc_check(const uint32_t W[80], uint32_t dvmask[1]) +{ + uint32_t mask = ~((uint32_t)(0)); + mask &= (((((W[44] ^ W[45]) >> 29) & 1) - 1) | + ~(DV_I_48_0_bit | DV_I_51_0_bit | DV_I_52_0_bit | DV_II_45_0_bit | + DV_II_46_0_bit | DV_II_50_0_bit | DV_II_51_0_bit)); + mask &= (((((W[49] ^ W[50]) >> 29) & 1) - 1) | + ~(DV_I_46_0_bit | DV_II_45_0_bit | DV_II_50_0_bit | DV_II_51_0_bit | + DV_II_55_0_bit | DV_II_56_0_bit)); + mask &= (((((W[48] ^ W[49]) >> 29) & 1) - 1) | + ~(DV_I_45_0_bit | DV_I_52_0_bit | DV_II_49_0_bit | DV_II_50_0_bit | + DV_II_54_0_bit | DV_II_55_0_bit)); + mask &= ((((W[47] ^ (W[50] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_47_0_bit | DV_I_49_0_bit | DV_I_51_0_bit | DV_II_45_0_bit | + DV_II_51_0_bit | DV_II_56_0_bit)); + mask &= (((((W[47] ^ W[48]) >> 29) & 1) - 1) | + ~(DV_I_44_0_bit | DV_I_51_0_bit | DV_II_48_0_bit | DV_II_49_0_bit | + DV_II_53_0_bit | DV_II_54_0_bit)); + mask &= (((((W[46] >> 4) ^ (W[49] >> 29)) & 1) - 1) | + ~(DV_I_46_0_bit | DV_I_48_0_bit | DV_I_50_0_bit | DV_I_52_0_bit | DV_II_50_0_bit | + DV_II_55_0_bit)); + mask &= (((((W[46] ^ W[47]) >> 29) & 1) - 1) | + ~(DV_I_43_0_bit | DV_I_50_0_bit | DV_II_47_0_bit | DV_II_48_0_bit | + DV_II_52_0_bit | DV_II_53_0_bit)); + mask &= (((((W[45] >> 4) ^ (W[48] >> 29)) & 1) - 1) | + ~(DV_I_45_0_bit | DV_I_47_0_bit | DV_I_49_0_bit | DV_I_51_0_bit | DV_II_49_0_bit | + DV_II_54_0_bit)); + mask &= (((((W[45] ^ W[46]) >> 29) & 1) - 1) | + ~(DV_I_49_0_bit | DV_I_52_0_bit | DV_II_46_0_bit | DV_II_47_0_bit | + DV_II_51_0_bit | DV_II_52_0_bit)); + mask &= (((((W[44] >> 4) ^ (W[47] >> 29)) & 1) - 1) | + ~(DV_I_44_0_bit | DV_I_46_0_bit | DV_I_48_0_bit | DV_I_50_0_bit | DV_II_48_0_bit | + DV_II_53_0_bit)); + mask &= (((((W[43] >> 4) ^ (W[46] >> 29)) & 1) - 1) | + ~(DV_I_43_0_bit | DV_I_45_0_bit | DV_I_47_0_bit | DV_I_49_0_bit | DV_II_47_0_bit | + DV_II_52_0_bit)); + mask &= (((((W[43] ^ W[44]) >> 29) & 1) - 1) | + ~(DV_I_47_0_bit | DV_I_50_0_bit | DV_I_51_0_bit | DV_II_45_0_bit | + DV_II_49_0_bit | DV_II_50_0_bit)); + mask &= (((((W[42] >> 4) ^ (W[45] >> 29)) & 1) - 1) | + ~(DV_I_44_0_bit | DV_I_46_0_bit | DV_I_48_0_bit | DV_I_52_0_bit | DV_II_46_0_bit | + DV_II_51_0_bit)); + mask &= (((((W[41] >> 4) ^ (W[44] >> 29)) & 1) - 1) | + ~(DV_I_43_0_bit | DV_I_45_0_bit | DV_I_47_0_bit | DV_I_51_0_bit | DV_II_45_0_bit | + DV_II_50_0_bit)); + mask &= (((((W[40] ^ W[41]) >> 29) & 1) - 1) | + ~(DV_I_44_0_bit | DV_I_47_0_bit | DV_I_48_0_bit | DV_II_46_0_bit | + DV_II_47_0_bit | DV_II_56_0_bit)); + mask &= + (((((W[54] ^ W[55]) >> 29) & 1) - 1) | + ~(DV_I_51_0_bit | DV_II_47_0_bit | DV_II_50_0_bit | DV_II_55_0_bit | DV_II_56_0_bit)); + mask &= + (((((W[53] ^ W[54]) >> 29) & 1) - 1) | + ~(DV_I_50_0_bit | DV_II_46_0_bit | DV_II_49_0_bit | DV_II_54_0_bit | DV_II_55_0_bit)); + mask &= + (((((W[52] ^ W[53]) >> 29) & 1) - 1) | + ~(DV_I_49_0_bit | DV_II_45_0_bit | DV_II_48_0_bit | DV_II_53_0_bit | DV_II_54_0_bit)); + mask &= + ((((W[50] ^ (W[53] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_50_0_bit | DV_I_52_0_bit | DV_II_46_0_bit | DV_II_48_0_bit | DV_II_54_0_bit)); + mask &= + (((((W[50] ^ W[51]) >> 29) & 1) - 1) | + ~(DV_I_47_0_bit | DV_II_46_0_bit | DV_II_51_0_bit | DV_II_52_0_bit | DV_II_56_0_bit)); + mask &= + ((((W[49] ^ (W[52] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_49_0_bit | DV_I_51_0_bit | DV_II_45_0_bit | DV_II_47_0_bit | DV_II_53_0_bit)); + mask &= + ((((W[48] ^ (W[51] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_48_0_bit | DV_I_50_0_bit | DV_I_52_0_bit | DV_II_46_0_bit | DV_II_52_0_bit)); + mask &= + (((((W[42] ^ W[43]) >> 29) & 1) - 1) | + ~(DV_I_46_0_bit | DV_I_49_0_bit | DV_I_50_0_bit | DV_II_48_0_bit | DV_II_49_0_bit)); + mask &= + (((((W[41] ^ W[42]) >> 29) & 1) - 1) | + ~(DV_I_45_0_bit | DV_I_48_0_bit | DV_I_49_0_bit | DV_II_47_0_bit | DV_II_48_0_bit)); + mask &= + (((((W[40] >> 4) ^ (W[43] >> 29)) & 1) - 1) | + ~(DV_I_44_0_bit | DV_I_46_0_bit | DV_I_50_0_bit | DV_II_49_0_bit | DV_II_56_0_bit)); + mask &= + (((((W[39] >> 4) ^ (W[42] >> 29)) & 1) - 1) | + ~(DV_I_43_0_bit | DV_I_45_0_bit | DV_I_49_0_bit | DV_II_48_0_bit | DV_II_55_0_bit)); + if (mask & + (DV_I_44_0_bit | DV_I_48_0_bit | DV_II_47_0_bit | DV_II_54_0_bit | DV_II_56_0_bit)) + mask &= (((((W[38] >> 4) ^ (W[41] >> 29)) & 1) - 1) | + ~(DV_I_44_0_bit | DV_I_48_0_bit | DV_II_47_0_bit | DV_II_54_0_bit | + DV_II_56_0_bit)); + mask &= + (((((W[37] >> 4) ^ (W[40] >> 29)) & 1) - 1) | + ~(DV_I_43_0_bit | DV_I_47_0_bit | DV_II_46_0_bit | DV_II_53_0_bit | DV_II_55_0_bit)); + if (mask & (DV_I_52_0_bit | DV_II_48_0_bit | DV_II_51_0_bit | DV_II_56_0_bit)) + mask &= (((((W[55] ^ W[56]) >> 29) & 1) - 1) | + ~(DV_I_52_0_bit | DV_II_48_0_bit | DV_II_51_0_bit | DV_II_56_0_bit)); + if (mask & (DV_I_52_0_bit | DV_II_48_0_bit | DV_II_50_0_bit | DV_II_56_0_bit)) + mask &= ((((W[52] ^ (W[55] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_52_0_bit | DV_II_48_0_bit | DV_II_50_0_bit | DV_II_56_0_bit)); + if (mask & (DV_I_51_0_bit | DV_II_47_0_bit | DV_II_49_0_bit | DV_II_55_0_bit)) + mask &= ((((W[51] ^ (W[54] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_51_0_bit | DV_II_47_0_bit | DV_II_49_0_bit | DV_II_55_0_bit)); + if (mask & (DV_I_48_0_bit | DV_II_47_0_bit | DV_II_52_0_bit | DV_II_53_0_bit)) + mask &= (((((W[51] ^ W[52]) >> 29) & 1) - 1) | + ~(DV_I_48_0_bit | DV_II_47_0_bit | DV_II_52_0_bit | DV_II_53_0_bit)); + if (mask & (DV_I_46_0_bit | DV_I_49_0_bit | DV_II_45_0_bit | DV_II_48_0_bit)) + mask &= (((((W[36] >> 4) ^ (W[40] >> 29)) & 1) - 1) | + ~(DV_I_46_0_bit | DV_I_49_0_bit | DV_II_45_0_bit | DV_II_48_0_bit)); + if (mask & (DV_I_52_0_bit | DV_II_48_0_bit | DV_II_49_0_bit)) + mask &= ((0 - (((W[53] ^ W[56]) >> 29) & 1)) | + ~(DV_I_52_0_bit | DV_II_48_0_bit | DV_II_49_0_bit)); + if (mask & (DV_I_50_0_bit | DV_II_46_0_bit | DV_II_47_0_bit)) + mask &= ((0 - (((W[51] ^ W[54]) >> 29) & 1)) | + ~(DV_I_50_0_bit | DV_II_46_0_bit | DV_II_47_0_bit)); + if (mask & (DV_I_49_0_bit | DV_I_51_0_bit | DV_II_45_0_bit)) + mask &= ((0 - (((W[50] ^ W[52]) >> 29) & 1)) | + ~(DV_I_49_0_bit | DV_I_51_0_bit | DV_II_45_0_bit)); + if (mask & (DV_I_48_0_bit | DV_I_50_0_bit | DV_I_52_0_bit)) + mask &= ((0 - (((W[49] ^ W[51]) >> 29) & 1)) | + ~(DV_I_48_0_bit | DV_I_50_0_bit | DV_I_52_0_bit)); + if (mask & (DV_I_47_0_bit | DV_I_49_0_bit | DV_I_51_0_bit)) + mask &= ((0 - (((W[48] ^ W[50]) >> 29) & 1)) | + ~(DV_I_47_0_bit | DV_I_49_0_bit | DV_I_51_0_bit)); + if (mask & (DV_I_46_0_bit | DV_I_48_0_bit | DV_I_50_0_bit)) + mask &= ((0 - (((W[47] ^ W[49]) >> 29) & 1)) | + ~(DV_I_46_0_bit | DV_I_48_0_bit | DV_I_50_0_bit)); + if (mask & (DV_I_45_0_bit | DV_I_47_0_bit | DV_I_49_0_bit)) + mask &= ((0 - (((W[46] ^ W[48]) >> 29) & 1)) | + ~(DV_I_45_0_bit | DV_I_47_0_bit | DV_I_49_0_bit)); + mask &= ((((W[45] ^ W[47]) & (1 << 6)) - (1 << 6)) | + ~(DV_I_47_2_bit | DV_I_49_2_bit | DV_I_51_2_bit)); + if (mask & (DV_I_44_0_bit | DV_I_46_0_bit | DV_I_48_0_bit)) + mask &= ((0 - (((W[45] ^ W[47]) >> 29) & 1)) | + ~(DV_I_44_0_bit | DV_I_46_0_bit | DV_I_48_0_bit)); + mask &= + (((((W[44] ^ W[46]) >> 6) & 1) - 1) | ~(DV_I_46_2_bit | DV_I_48_2_bit | DV_I_50_2_bit)); + if (mask & (DV_I_43_0_bit | DV_I_45_0_bit | DV_I_47_0_bit)) + mask &= ((0 - (((W[44] ^ W[46]) >> 29) & 1)) | + ~(DV_I_43_0_bit | DV_I_45_0_bit | DV_I_47_0_bit)); + mask &= ((0 - ((W[41] ^ (W[42] >> 5)) & (1 << 1))) | + ~(DV_I_48_2_bit | DV_II_46_2_bit | DV_II_51_2_bit)); + mask &= ((0 - ((W[40] ^ (W[41] >> 5)) & (1 << 1))) | + ~(DV_I_47_2_bit | DV_I_51_2_bit | DV_II_50_2_bit)); + if (mask & (DV_I_44_0_bit | DV_I_46_0_bit | DV_II_56_0_bit)) + mask &= ((0 - (((W[40] ^ W[42]) >> 4) & 1)) | + ~(DV_I_44_0_bit | DV_I_46_0_bit | DV_II_56_0_bit)); + mask &= ((0 - ((W[39] ^ (W[40] >> 5)) & (1 << 1))) | + ~(DV_I_46_2_bit | DV_I_50_2_bit | DV_II_49_2_bit)); + if (mask & (DV_I_43_0_bit | DV_I_45_0_bit | DV_II_55_0_bit)) + mask &= ((0 - (((W[39] ^ W[41]) >> 4) & 1)) | + ~(DV_I_43_0_bit | DV_I_45_0_bit | DV_II_55_0_bit)); + if (mask & (DV_I_44_0_bit | DV_II_54_0_bit | DV_II_56_0_bit)) + mask &= ((0 - (((W[38] ^ W[40]) >> 4) & 1)) | + ~(DV_I_44_0_bit | DV_II_54_0_bit | DV_II_56_0_bit)); + if (mask & (DV_I_43_0_bit | DV_II_53_0_bit | DV_II_55_0_bit)) + mask &= ((0 - (((W[37] ^ W[39]) >> 4) & 1)) | + ~(DV_I_43_0_bit | DV_II_53_0_bit | DV_II_55_0_bit)); + mask &= ((0 - ((W[36] ^ (W[37] >> 5)) & (1 << 1))) | + ~(DV_I_47_2_bit | DV_I_50_2_bit | DV_II_46_2_bit)); + if (mask & (DV_I_45_0_bit | DV_I_48_0_bit | DV_II_47_0_bit)) + mask &= (((((W[35] >> 4) ^ (W[39] >> 29)) & 1) - 1) | + ~(DV_I_45_0_bit | DV_I_48_0_bit | DV_II_47_0_bit)); + if (mask & (DV_I_48_0_bit | DV_II_48_0_bit)) + mask &= + ((0 - ((W[63] ^ (W[64] >> 5)) & (1 << 0))) | ~(DV_I_48_0_bit | DV_II_48_0_bit)); + if (mask & (DV_I_45_0_bit | DV_II_45_0_bit)) + mask &= + ((0 - ((W[63] ^ (W[64] >> 5)) & (1 << 1))) | ~(DV_I_45_0_bit | DV_II_45_0_bit)); + if (mask & (DV_I_47_0_bit | DV_II_47_0_bit)) + mask &= + ((0 - ((W[62] ^ (W[63] >> 5)) & (1 << 0))) | ~(DV_I_47_0_bit | DV_II_47_0_bit)); + if (mask & (DV_I_46_0_bit | DV_II_46_0_bit)) + mask &= + ((0 - ((W[61] ^ (W[62] >> 5)) & (1 << 0))) | ~(DV_I_46_0_bit | DV_II_46_0_bit)); + mask &= ((0 - ((W[61] ^ (W[62] >> 5)) & (1 << 2))) | ~(DV_I_46_2_bit | DV_II_46_2_bit)); + if (mask & (DV_I_45_0_bit | DV_II_45_0_bit)) + mask &= + ((0 - ((W[60] ^ (W[61] >> 5)) & (1 << 0))) | ~(DV_I_45_0_bit | DV_II_45_0_bit)); + if (mask & (DV_II_51_0_bit | DV_II_54_0_bit)) + mask &= (((((W[58] ^ W[59]) >> 29) & 1) - 1) | ~(DV_II_51_0_bit | DV_II_54_0_bit)); + if (mask & (DV_II_50_0_bit | DV_II_53_0_bit)) + mask &= (((((W[57] ^ W[58]) >> 29) & 1) - 1) | ~(DV_II_50_0_bit | DV_II_53_0_bit)); + if (mask & (DV_II_52_0_bit | DV_II_54_0_bit)) + mask &= ((((W[56] ^ (W[59] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_II_52_0_bit | DV_II_54_0_bit)); + if (mask & (DV_II_51_0_bit | DV_II_52_0_bit)) + mask &= ((0 - (((W[56] ^ W[59]) >> 29) & 1)) | ~(DV_II_51_0_bit | DV_II_52_0_bit)); + if (mask & (DV_II_49_0_bit | DV_II_52_0_bit)) + mask &= (((((W[56] ^ W[57]) >> 29) & 1) - 1) | ~(DV_II_49_0_bit | DV_II_52_0_bit)); + if (mask & (DV_II_51_0_bit | DV_II_53_0_bit)) + mask &= ((((W[55] ^ (W[58] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_II_51_0_bit | DV_II_53_0_bit)); + if (mask & (DV_II_50_0_bit | DV_II_52_0_bit)) + mask &= ((((W[54] ^ (W[57] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_II_50_0_bit | DV_II_52_0_bit)); + if (mask & (DV_II_49_0_bit | DV_II_51_0_bit)) + mask &= ((((W[53] ^ (W[56] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_II_49_0_bit | DV_II_51_0_bit)); + mask &= + ((((W[51] ^ (W[50] >> 5)) & (1 << 1)) - (1 << 1)) | ~(DV_I_50_2_bit | DV_II_46_2_bit)); + mask &= ((((W[48] ^ W[50]) & (1 << 6)) - (1 << 6)) | ~(DV_I_50_2_bit | DV_II_46_2_bit)); + if (mask & (DV_I_51_0_bit | DV_I_52_0_bit)) + mask &= ((0 - (((W[48] ^ W[55]) >> 29) & 1)) | ~(DV_I_51_0_bit | DV_I_52_0_bit)); + mask &= ((((W[47] ^ W[49]) & (1 << 6)) - (1 << 6)) | ~(DV_I_49_2_bit | DV_I_51_2_bit)); + mask &= + ((((W[48] ^ (W[47] >> 5)) & (1 << 1)) - (1 << 1)) | ~(DV_I_47_2_bit | DV_II_51_2_bit)); + mask &= ((((W[46] ^ W[48]) & (1 << 6)) - (1 << 6)) | ~(DV_I_48_2_bit | DV_I_50_2_bit)); + mask &= + ((((W[47] ^ (W[46] >> 5)) & (1 << 1)) - (1 << 1)) | ~(DV_I_46_2_bit | DV_II_50_2_bit)); + mask &= ((0 - ((W[44] ^ (W[45] >> 5)) & (1 << 1))) | ~(DV_I_51_2_bit | DV_II_49_2_bit)); + mask &= ((((W[43] ^ W[45]) & (1 << 6)) - (1 << 6)) | ~(DV_I_47_2_bit | DV_I_49_2_bit)); + mask &= (((((W[42] ^ W[44]) >> 6) & 1) - 1) | ~(DV_I_46_2_bit | DV_I_48_2_bit)); + mask &= + ((((W[43] ^ (W[42] >> 5)) & (1 << 1)) - (1 << 1)) | ~(DV_II_46_2_bit | DV_II_51_2_bit)); + mask &= + ((((W[42] ^ (W[41] >> 5)) & (1 << 1)) - (1 << 1)) | ~(DV_I_51_2_bit | DV_II_50_2_bit)); + mask &= + ((((W[41] ^ (W[40] >> 5)) & (1 << 1)) - (1 << 1)) | ~(DV_I_50_2_bit | DV_II_49_2_bit)); + if (mask & (DV_I_52_0_bit | DV_II_51_0_bit)) + mask &= ((((W[39] ^ (W[43] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_52_0_bit | DV_II_51_0_bit)); + if (mask & (DV_I_51_0_bit | DV_II_50_0_bit)) + mask &= ((((W[38] ^ (W[42] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_51_0_bit | DV_II_50_0_bit)); + if (mask & (DV_I_48_2_bit | DV_I_51_2_bit)) + mask &= ((0 - ((W[37] ^ (W[38] >> 5)) & (1 << 1))) | ~(DV_I_48_2_bit | DV_I_51_2_bit)); + if (mask & (DV_I_50_0_bit | DV_II_49_0_bit)) + mask &= ((((W[37] ^ (W[41] >> 25)) & (1 << 4)) - (1 << 4)) | + ~(DV_I_50_0_bit | DV_II_49_0_bit)); + if (mask & (DV_II_52_0_bit | DV_II_54_0_bit)) + mask &= ((0 - ((W[36] ^ W[38]) & (1 << 4))) | ~(DV_II_52_0_bit | DV_II_54_0_bit)); + mask &= ((0 - ((W[35] ^ (W[36] >> 5)) & (1 << 1))) | ~(DV_I_46_2_bit | DV_I_49_2_bit)); + if (mask & (DV_I_51_0_bit | DV_II_47_0_bit)) + mask &= ((((W[35] ^ (W[39] >> 25)) & (1 << 3)) - (1 << 3)) | + ~(DV_I_51_0_bit | DV_II_47_0_bit)); + if (mask) { + if (mask & DV_I_43_0_bit) + if (!((W[61] ^ (W[62] >> 5)) & (1 << 1)) || + !(!((W[59] ^ (W[63] >> 25)) & (1 << 5))) || + !((W[58] ^ (W[63] >> 30)) & (1 << 0))) + mask &= ~DV_I_43_0_bit; + if (mask & DV_I_44_0_bit) + if (!((W[62] ^ (W[63] >> 5)) & (1 << 1)) || + !(!((W[60] ^ (W[64] >> 25)) & (1 << 5))) || + !((W[59] ^ (W[64] >> 30)) & (1 << 0))) + mask &= ~DV_I_44_0_bit; + if (mask & DV_I_46_2_bit) + mask &= ((~((W[40] ^ W[42]) >> 2)) | ~DV_I_46_2_bit); + if (mask & DV_I_47_2_bit) + if (!((W[62] ^ (W[63] >> 5)) & (1 << 2)) || !(!((W[41] ^ W[43]) & (1 << 6)))) + mask &= ~DV_I_47_2_bit; + if (mask & DV_I_48_2_bit) + if (!((W[63] ^ (W[64] >> 5)) & (1 << 2)) || + !(!((W[48] ^ (W[49] << 5)) & (1 << 6)))) + mask &= ~DV_I_48_2_bit; + if (mask & DV_I_49_2_bit) + if (!(!((W[49] ^ (W[50] << 5)) & (1 << 6))) || !((W[42] ^ W[50]) & (1 << 1)) || + !(!((W[39] ^ (W[40] << 5)) & (1 << 6))) || !((W[38] ^ W[40]) & (1 << 1))) + mask &= ~DV_I_49_2_bit; + if (mask & DV_I_50_0_bit) + mask &= ((((W[36] ^ W[37]) << 7)) | ~DV_I_50_0_bit); + if (mask & DV_I_50_2_bit) + mask &= ((((W[43] ^ W[51]) << 11)) | ~DV_I_50_2_bit); + if (mask & DV_I_51_0_bit) + mask &= ((((W[37] ^ W[38]) << 9)) | ~DV_I_51_0_bit); + if (mask & DV_I_51_2_bit) + if (!(!((W[51] ^ (W[52] << 5)) & (1 << 6))) || !(!((W[49] ^ W[51]) & (1 << 6))) || + !(!((W[37] ^ (W[37] >> 5)) & (1 << 1))) || + !(!((W[35] ^ (W[39] >> 25)) & (1 << 5)))) + mask &= ~DV_I_51_2_bit; + if (mask & DV_I_52_0_bit) + mask &= ((((W[38] ^ W[39]) << 11)) | ~DV_I_52_0_bit); + if (mask & DV_II_46_2_bit) + mask &= ((((W[47] ^ W[51]) << 17)) | ~DV_II_46_2_bit); + if (mask & DV_II_48_0_bit) + if (!(!((W[36] ^ (W[40] >> 25)) & (1 << 3))) || + !((W[35] ^ (W[40] << 2)) & (1 << 30))) + mask &= ~DV_II_48_0_bit; + if (mask & DV_II_49_0_bit) + if (!(!((W[37] ^ (W[41] >> 25)) & (1 << 3))) || + !((W[36] ^ (W[41] << 2)) & (1 << 30))) + mask &= ~DV_II_49_0_bit; + if (mask & DV_II_49_2_bit) + if (!(!((W[53] ^ (W[54] << 5)) & (1 << 6))) || !(!((W[51] ^ W[53]) & (1 << 6))) || + !((W[50] ^ W[54]) & (1 << 1)) || !(!((W[45] ^ (W[46] << 5)) & (1 << 6))) || + !(!((W[37] ^ (W[41] >> 25)) & (1 << 5))) || + !((W[36] ^ (W[41] >> 30)) & (1 << 0))) + mask &= ~DV_II_49_2_bit; + if (mask & DV_II_50_0_bit) + if (!((W[55] ^ W[58]) & (1 << 29)) || !(!((W[38] ^ (W[42] >> 25)) & (1 << 3))) || + !((W[37] ^ (W[42] << 2)) & (1 << 30))) + mask &= ~DV_II_50_0_bit; + if (mask & DV_II_50_2_bit) + if (!(!((W[54] ^ (W[55] << 5)) & (1 << 6))) || !(!((W[52] ^ W[54]) & (1 << 6))) || + !((W[51] ^ W[55]) & (1 << 1)) || !((W[45] ^ W[47]) & (1 << 1)) || + !(!((W[38] ^ (W[42] >> 25)) & (1 << 5))) || + !((W[37] ^ (W[42] >> 30)) & (1 << 0))) + mask &= ~DV_II_50_2_bit; + if (mask & DV_II_51_0_bit) + if (!(!((W[39] ^ (W[43] >> 25)) & (1 << 3))) || + !((W[38] ^ (W[43] << 2)) & (1 << 30))) + mask &= ~DV_II_51_0_bit; + if (mask & DV_II_51_2_bit) + if (!(!((W[55] ^ (W[56] << 5)) & (1 << 6))) || !(!((W[53] ^ W[55]) & (1 << 6))) || + !((W[52] ^ W[56]) & (1 << 1)) || !((W[46] ^ W[48]) & (1 << 1)) || + !(!((W[39] ^ (W[43] >> 25)) & (1 << 5))) || + !((W[38] ^ (W[43] >> 30)) & (1 << 0))) + mask &= ~DV_II_51_2_bit; + if (mask & DV_II_52_0_bit) + if (!(!((W[59] ^ W[60]) & (1 << 29))) || + !(!((W[40] ^ (W[44] >> 25)) & (1 << 3))) || + !(!((W[40] ^ (W[44] >> 25)) & (1 << 4))) || + !((W[39] ^ (W[44] << 2)) & (1 << 30))) + mask &= ~DV_II_52_0_bit; + if (mask & DV_II_53_0_bit) + if (!((W[58] ^ W[61]) & (1 << 29)) || !(!((W[57] ^ (W[61] >> 25)) & (1 << 4))) || + !(!((W[41] ^ (W[45] >> 25)) & (1 << 3))) || + !(!((W[41] ^ (W[45] >> 25)) & (1 << 4)))) + mask &= ~DV_II_53_0_bit; + if (mask & DV_II_54_0_bit) + if (!(!((W[58] ^ (W[62] >> 25)) & (1 << 4))) || + !(!((W[42] ^ (W[46] >> 25)) & (1 << 3))) || + !(!((W[42] ^ (W[46] >> 25)) & (1 << 4)))) + mask &= ~DV_II_54_0_bit; + if (mask & DV_II_55_0_bit) + if (!(!((W[59] ^ (W[63] >> 25)) & (1 << 4))) || + !(!((W[57] ^ (W[59] >> 25)) & (1 << 4))) || + !(!((W[43] ^ (W[47] >> 25)) & (1 << 3))) || + !(!((W[43] ^ (W[47] >> 25)) & (1 << 4)))) + mask &= ~DV_II_55_0_bit; + if (mask & DV_II_56_0_bit) + if (!(!((W[60] ^ (W[64] >> 25)) & (1 << 4))) || + !(!((W[44] ^ (W[48] >> 25)) & (1 << 3))) || + !(!((W[44] ^ (W[48] >> 25)) & (1 << 4)))) + mask &= ~DV_II_56_0_bit; + } + + dvmask[0] = mask; +} + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.h b/comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.h new file mode 100644 index 0000000000..a43c7b685a --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sha1cd/ubc_check.h @@ -0,0 +1,62 @@ +/*** + * Copyright 2017 Marc Stevens , Dan Shumow + * Distributed under the MIT Software License. + * See accompanying file LICENSE.txt or copy at + * https://opensource.org/licenses/MIT + ***/ + +/* +// this file was generated by the 'parse_bitrel' program in the tools section +// using the data files from directory 'tools/data/3565' +// +// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check +// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper) +// dm[80] is the expanded message block XOR-difference defined by the DV +// testt is the step to do the recompression from for collision detection +// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check +// +// ubc_check takes as input an expanded message block and verifies the unavoidable +bitconditions for all listed DVs +// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions +for that DV have been met +// thus one needs to do the recompression check for each DV that has its bit set +*/ + +#ifndef SHA1DC_UBC_CHECK_H +#define SHA1DC_UBC_CHECK_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef SHA1DC_NO_STANDARD_INCLUDES +#include +#endif + +#define DVMASKSIZE 1 +typedef struct { + int dvType; + int dvK; + int dvB; + int testt; + int maski; + int maskb; + uint32_t dm[80]; +} dv_info_t; +extern dv_info_t sha1_dvs[]; +void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]); + +#define DOSTORESTATE58 +#define DOSTORESTATE65 + +#define CHECK_DVMASK(_DVMASK) (0 != _DVMASK[0]) + +#if defined(__cplusplus) +} +#endif + +#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H +#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H +#endif + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/signatures.cpp b/comm/third_party/rnp/src/lib/crypto/signatures.cpp new file mode 100644 index 0000000000..ea39935d7a --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/signatures.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2018-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "crypto/signatures.h" +#include "librepgp/stream-packet.h" +#include "librepgp/stream-sig.h" +#include "utils.h" +#include "sec_profile.hpp" + +/** + * @brief Add signature fields to the hash context and finish it. + * @param hash initialized hash context fed with signed data (document, key, etc). + * It is finalized in this function. + * @param sig populated or loaded signature + * @param hbuf buffer to store the resulting hash. Must be large enough for hash output. + * @param hlen on success will be filled with the hash size, otherwise zeroed + * @return RNP_SUCCESS on success or some error otherwise + */ +static void +signature_hash_finish(const pgp_signature_t &sig, rnp::Hash &hash, uint8_t *hbuf, size_t &hlen) +{ + hash.add(sig.hashed_data, sig.hashed_len); + if (sig.version > PGP_V3) { + uint8_t trailer[6] = {0x04, 0xff, 0x00, 0x00, 0x00, 0x00}; + STORE32BE(&trailer[2], sig.hashed_len); + hash.add(trailer, 6); + } + hlen = hash.finish(hbuf); +} + +std::unique_ptr +signature_init(const pgp_key_material_t &key, pgp_hash_alg_t hash_alg) +{ + auto hash = rnp::Hash::create(hash_alg); + if (key.alg == PGP_PKA_SM2) { +#if defined(ENABLE_SM2) + rnp_result_t r = sm2_compute_za(key.ec, *hash); + if (r != RNP_SUCCESS) { + RNP_LOG("failed to compute SM2 ZA field"); + throw rnp::rnp_exception(r); + } +#else + RNP_LOG("SM2 ZA computation not available"); + throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED); +#endif + } + return hash; +} + +void +signature_calculate(pgp_signature_t & sig, + pgp_key_material_t & seckey, + rnp::Hash & hash, + rnp::SecurityContext &ctx) +{ + uint8_t hval[PGP_MAX_HASH_SIZE]; + size_t hlen = 0; + rnp_result_t ret = RNP_ERROR_GENERIC; + const pgp_hash_alg_t hash_alg = hash.alg(); + + /* Finalize hash first, since function is required to do this */ + try { + signature_hash_finish(sig, hash, hval, hlen); + } catch (const std::exception &e) { + RNP_LOG("Failed to finalize hash: %s", e.what()); + throw; + } + + if (!seckey.secret) { + RNP_LOG("Secret key is required."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + if (sig.palg != seckey.alg) { + RNP_LOG("Signature and secret key do not agree on algorithm type."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + /* Validate key material if didn't before */ + seckey.validate(ctx, false); + if (!seckey.valid()) { + RNP_LOG("Attempt to sign with invalid key material."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + /* copy left 16 bits to signature */ + memcpy(sig.lbits, hval, 2); + + /* sign */ + pgp_signature_material_t material = {}; + switch (sig.palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + ret = rsa_sign_pkcs1(&ctx.rng, &material.rsa, sig.halg, hval, hlen, &seckey.rsa); + if (ret) { + RNP_LOG("rsa signing failed"); + } + break; + case PGP_PKA_EDDSA: + ret = eddsa_sign(&ctx.rng, &material.ecc, hval, hlen, &seckey.ec); + if (ret) { + RNP_LOG("eddsa signing failed"); + } + break; + case PGP_PKA_DSA: + ret = dsa_sign(&ctx.rng, &material.dsa, hval, hlen, &seckey.dsa); + if (ret != RNP_SUCCESS) { + RNP_LOG("DSA signing failed"); + } + break; + /* + * ECDH is signed with ECDSA. This must be changed when ECDH will support + * X25519, but I need to check how it should be done exactly. + */ + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: { + const ec_curve_desc_t *curve = get_curve_desc(seckey.ec.curve); + if (!curve) { + RNP_LOG("Unknown curve"); + ret = RNP_ERROR_BAD_PARAMETERS; + break; + } + if (!curve_supported(seckey.ec.curve)) { + RNP_LOG("EC sign: curve %s is not supported.", curve->pgp_name); + ret = RNP_ERROR_NOT_SUPPORTED; + break; + } + /* "-2" because ECDSA on P-521 must work with SHA-512 digest */ + if (BITS_TO_BYTES(curve->bitlen) - 2 > hlen) { + RNP_LOG("Message hash too small"); + ret = RNP_ERROR_BAD_PARAMETERS; + break; + } + + if (sig.palg == PGP_PKA_SM2) { +#if defined(ENABLE_SM2) + ret = sm2_sign(&ctx.rng, &material.ecc, hash_alg, hval, hlen, &seckey.ec); + if (ret) { + RNP_LOG("SM2 signing failed"); + } +#else + RNP_LOG("SM2 signing is not available."); + ret = RNP_ERROR_NOT_IMPLEMENTED; +#endif + break; + } + + ret = ecdsa_sign(&ctx.rng, &material.ecc, hash_alg, hval, hlen, &seckey.ec); + if (ret) { + RNP_LOG("ECDSA signing failed"); + } + break; + } + default: + RNP_LOG("Unsupported algorithm %d", sig.palg); + break; + } + if (ret) { + throw rnp::rnp_exception(ret); + } + try { + sig.write_material(material); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + throw; + } +} + +rnp_result_t +signature_validate(const pgp_signature_t & sig, + const pgp_key_material_t & key, + rnp::Hash & hash, + const rnp::SecurityContext &ctx) +{ + if (sig.palg != key.alg) { + RNP_LOG("Signature and key do not agree on algorithm type: %d vs %d", + (int) sig.palg, + (int) key.alg); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* Check signature security */ + auto action = + sig.is_document() ? rnp::SecurityAction::VerifyData : rnp::SecurityAction::VerifyKey; + if (ctx.profile.hash_level(sig.halg, sig.creation(), action) < + rnp::SecurityLevel::Default) { + RNP_LOG("Insecure hash algorithm %d, marking signature as invalid.", sig.halg); + return RNP_ERROR_SIGNATURE_INVALID; + } + + /* Finalize hash */ + uint8_t hval[PGP_MAX_HASH_SIZE]; + size_t hlen = 0; + try { + signature_hash_finish(sig, hash, hval, hlen); + } catch (const std::exception &e) { + RNP_LOG("Failed to finalize signature hash."); + return RNP_ERROR_GENERIC; + } + + /* compare lbits */ + if (memcmp(hval, sig.lbits, 2)) { + RNP_LOG("wrong lbits"); + return RNP_ERROR_SIGNATURE_INVALID; + } + + /* validate signature */ + pgp_signature_material_t material = {}; + try { + sig.parse_material(material); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t ret = RNP_ERROR_GENERIC; + switch (sig.palg) { + case PGP_PKA_DSA: + ret = dsa_verify(&material.dsa, hval, hlen, &key.dsa); + break; + case PGP_PKA_EDDSA: + ret = eddsa_verify(&material.ecc, hval, hlen, &key.ec); + break; + case PGP_PKA_SM2: +#if defined(ENABLE_SM2) + ret = sm2_verify(&material.ecc, hash.alg(), hval, hlen, &key.ec); +#else + RNP_LOG("SM2 verification is not available."); + ret = RNP_ERROR_NOT_IMPLEMENTED; +#endif + break; + case PGP_PKA_RSA: + case PGP_PKA_RSA_SIGN_ONLY: + ret = rsa_verify_pkcs1(&material.rsa, sig.halg, hval, hlen, &key.rsa); + break; + case PGP_PKA_RSA_ENCRYPT_ONLY: + RNP_LOG("RSA encrypt-only signature considered as invalid."); + ret = RNP_ERROR_SIGNATURE_INVALID; + break; + case PGP_PKA_ECDSA: + if (!curve_supported(key.ec.curve)) { + RNP_LOG("ECDSA verify: curve %d is not supported.", (int) key.ec.curve); + ret = RNP_ERROR_NOT_SUPPORTED; + break; + } + ret = ecdsa_verify(&material.ecc, hash.alg(), hval, hlen, &key.ec); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + RNP_LOG("ElGamal are considered as invalid."); + ret = RNP_ERROR_SIGNATURE_INVALID; + break; + default: + RNP_LOG("Unknown algorithm"); + ret = RNP_ERROR_BAD_PARAMETERS; + } + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/signatures.h b/comm/third_party/rnp/src/lib/crypto/signatures.h new file mode 100644 index 0000000000..6ba64ce1f6 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/signatures.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_SIGNATURES_H_ +#define RNP_SIGNATURES_H_ + +#include "crypto/hash.hpp" + +/** + * @brief Initialize a signature computation. + * @param key the key that will be used to sign or verify + * @param hash_alg the digest algo to be used + * @param hash digest object that will be initialized + */ +std::unique_ptr signature_init(const pgp_key_material_t &key, + pgp_hash_alg_t hash_alg); + +/** + * @brief Calculate signature with pre-populated hash + * @param sig signature to calculate + * @param seckey signing secret key material + * @param hash pre-populated with signed data hash context. It is finalized and destroyed + * during the execution. Signature fields and trailer are hashed in this function. + * @param rng random number generator + */ +void signature_calculate(pgp_signature_t & sig, + pgp_key_material_t & seckey, + rnp::Hash & hash, + rnp::SecurityContext &ctx); + +/** + * @brief Validate a signature with pre-populated hash. This method just checks correspondence + * between the hash and signature material. Expiration time and other fields are not + * checked for validity. + * @param sig signature to validate + * @param key public key material of the verifying key + * @param hash pre-populated with signed data hash context. It is finalized + * during the execution. Signature fields and trailer are hashed in this function. + * @return RNP_SUCCESS if signature was successfully validated or error code otherwise. + */ +rnp_result_t signature_validate(const pgp_signature_t & sig, + const pgp_key_material_t & key, + rnp::Hash & hash, + const rnp::SecurityContext &ctx); + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/sm2.cpp b/comm/third_party/rnp/src/lib/crypto/sm2.cpp new file mode 100644 index 0000000000..2af537d5f2 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sm2.cpp @@ -0,0 +1,383 @@ +/*- + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "hash_botan.hpp" +#include "sm2.h" +#include "utils.h" +#include "bn.h" + +static bool +sm2_load_public_key(botan_pubkey_t *pubkey, const pgp_ec_key_t *keydata) +{ + const ec_curve_desc_t *curve = NULL; + botan_mp_t px = NULL; + botan_mp_t py = NULL; + size_t sz; + bool res = false; + + if (!(curve = get_curve_desc(keydata->curve))) { + return false; + } + + const size_t sign_half_len = BITS_TO_BYTES(curve->bitlen); + sz = mpi_bytes(&keydata->p); + if (!sz || (sz != (2 * sign_half_len + 1)) || (keydata->p.mpi[0] != 0x04)) { + goto end; + } + + if (botan_mp_init(&px) || botan_mp_init(&py) || + botan_mp_from_bin(px, &keydata->p.mpi[1], sign_half_len) || + botan_mp_from_bin(py, &keydata->p.mpi[1 + sign_half_len], sign_half_len)) { + goto end; + } + res = !botan_pubkey_load_sm2(pubkey, px, py, curve->botan_name); +end: + botan_mp_destroy(px); + botan_mp_destroy(py); + return res; +} + +static bool +sm2_load_secret_key(botan_privkey_t *seckey, const pgp_ec_key_t *keydata) +{ + const ec_curve_desc_t *curve = NULL; + bignum_t * x = NULL; + bool res = false; + + if (!(curve = get_curve_desc(keydata->curve))) { + return false; + } + if (!(x = mpi2bn(&keydata->x))) { + return false; + } + res = !botan_privkey_load_sm2(seckey, BN_HANDLE_PTR(x), curve->botan_name); + bn_free(x); + return res; +} + +rnp_result_t +sm2_compute_za(const pgp_ec_key_t &key, rnp::Hash &hash, const char *ident_field) +{ + rnp_result_t result = RNP_ERROR_GENERIC; + botan_pubkey_t sm2_key = NULL; + int rc; + + const char *hash_algo = rnp::Hash_Botan::name_backend(hash.alg()); + size_t digest_len = hash.size(); + + uint8_t *digest_buf = (uint8_t *) malloc(digest_len); + if (!digest_buf) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (!sm2_load_public_key(&sm2_key, &key)) { + RNP_LOG("Failed to load SM2 key"); + goto done; + } + + if (ident_field == NULL) + ident_field = "1234567812345678"; + + rc = botan_pubkey_sm2_compute_za(digest_buf, &digest_len, ident_field, hash_algo, sm2_key); + + if (rc != 0) { + RNP_LOG("compute_za failed %d", rc); + goto done; + } + + try { + hash.add(digest_buf, digest_len); + } catch (const std::exception &e) { + RNP_LOG("Failed to update hash: %s", e.what()); + goto done; + } + + result = RNP_SUCCESS; +done: + free(digest_buf); + botan_pubkey_destroy(sm2_key); + return result; +} + +rnp_result_t +sm2_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + botan_pubkey_t bpkey = NULL; + botan_privkey_t bskey = NULL; + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + + if (!sm2_load_public_key(&bpkey, key) || botan_pubkey_check_key(bpkey, rng->handle(), 0)) { + goto done; + } + + if (!secret) { + ret = RNP_SUCCESS; + goto done; + } + + if (!sm2_load_secret_key(&bskey, key) || + botan_privkey_check_key(bskey, rng->handle(), 0)) { + goto done; + } + ret = RNP_SUCCESS; +done: + botan_privkey_destroy(bskey); + botan_pubkey_destroy(bpkey); + return ret; +} + +rnp_result_t +sm2_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key) +{ + const ec_curve_desc_t *curve = NULL; + botan_pk_op_sign_t signer = NULL; + botan_privkey_t b_key = NULL; + uint8_t out_buf[2 * MAX_CURVE_BYTELEN] = {0}; + size_t sign_half_len = 0; + size_t sig_len = 0; + rnp_result_t ret = RNP_ERROR_SIGNING_FAILED; + + if (botan_ffi_supports_api(20180713) != 0) { + RNP_LOG("SM2 signatures requires Botan 2.8 or higher"); + return RNP_ERROR_NOT_SUPPORTED; + } + + if (hash_len != rnp::Hash::size(hash_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!(curve = get_curve_desc(key->curve))) { + return RNP_ERROR_BAD_PARAMETERS; + } + sign_half_len = BITS_TO_BYTES(curve->bitlen); + sig_len = 2 * sign_half_len; + + if (!sm2_load_secret_key(&b_key, key)) { + RNP_LOG("Can't load private key"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto end; + } + + if (botan_pk_op_sign_create(&signer, b_key, ",Raw", 0)) { + goto end; + } + + if (botan_pk_op_sign_update(signer, hash, hash_len)) { + goto end; + } + + if (botan_pk_op_sign_finish(signer, rng->handle(), out_buf, &sig_len)) { + RNP_LOG("Signing failed"); + goto end; + } + + // Allocate memory and copy results + if (mem2mpi(&sig->r, out_buf, sign_half_len) && + mem2mpi(&sig->s, out_buf + sign_half_len, sign_half_len)) { + // All good now + ret = RNP_SUCCESS; + } +end: + botan_privkey_destroy(b_key); + botan_pk_op_sign_destroy(signer); + return ret; +} + +rnp_result_t +sm2_verify(const pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key) +{ + const ec_curve_desc_t *curve = NULL; + botan_pubkey_t pub = NULL; + botan_pk_op_verify_t verifier = NULL; + rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID; + uint8_t sign_buf[2 * MAX_CURVE_BYTELEN] = {0}; + size_t r_blen, s_blen, sign_half_len; + + if (botan_ffi_supports_api(20180713) != 0) { + RNP_LOG("SM2 signatures requires Botan 2.8 or higher"); + return RNP_ERROR_NOT_SUPPORTED; + } + + if (hash_len != rnp::Hash::size(hash_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + curve = get_curve_desc(key->curve); + if (curve == NULL) { + return RNP_ERROR_BAD_PARAMETERS; + } + sign_half_len = BITS_TO_BYTES(curve->bitlen); + + if (!sm2_load_public_key(&pub, key)) { + RNP_LOG("Failed to load public key"); + goto end; + } + + if (botan_pk_op_verify_create(&verifier, pub, ",Raw", 0)) { + goto end; + } + + if (botan_pk_op_verify_update(verifier, hash, hash_len)) { + goto end; + } + + r_blen = sig->r.len; + s_blen = sig->s.len; + if (!r_blen || (r_blen > sign_half_len) || !s_blen || (s_blen > sign_half_len) || + (sign_half_len > MAX_CURVE_BYTELEN)) { + goto end; + } + + mpi2mem(&sig->r, sign_buf + sign_half_len - r_blen); + mpi2mem(&sig->s, sign_buf + 2 * sign_half_len - s_blen); + + if (!botan_pk_op_verify_finish(verifier, sign_buf, sign_half_len * 2)) { + ret = RNP_SUCCESS; + } +end: + botan_pubkey_destroy(pub); + botan_pk_op_verify_destroy(verifier); + return ret; +} + +rnp_result_t +sm2_encrypt(rnp::RNG * rng, + pgp_sm2_encrypted_t *out, + const uint8_t * in, + size_t in_len, + pgp_hash_alg_t hash_algo, + const pgp_ec_key_t * key) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + const ec_curve_desc_t *curve = NULL; + botan_pubkey_t sm2_key = NULL; + botan_pk_op_encrypt_t enc_op = NULL; + size_t point_len; + size_t hash_alg_len; + size_t ctext_len; + + curve = get_curve_desc(key->curve); + if (curve == NULL) { + return RNP_ERROR_GENERIC; + } + point_len = BITS_TO_BYTES(curve->bitlen); + hash_alg_len = rnp::Hash::size(hash_algo); + if (!hash_alg_len) { + RNP_LOG("Unknown hash algorithm for SM2 encryption"); + goto done; + } + + /* + * Format of SM2 ciphertext is a point (2*point_len+1) plus + * the masked ciphertext (out_len) plus a hash. + */ + ctext_len = (2 * point_len + 1) + in_len + hash_alg_len; + if (ctext_len > PGP_MPINT_SIZE) { + RNP_LOG("too large output for SM2 encryption"); + goto done; + } + + if (!sm2_load_public_key(&sm2_key, key)) { + RNP_LOG("Failed to load public key"); + goto done; + } + + /* + SM2 encryption doesn't have any kind of format specifier because + it's an all in one scheme, only the hash (used for the integrity + check) is specified. + */ + if (botan_pk_op_encrypt_create( + &enc_op, sm2_key, rnp::Hash_Botan::name_backend(hash_algo), 0)) { + goto done; + } + + out->m.len = sizeof(out->m.mpi); + if (botan_pk_op_encrypt(enc_op, rng->handle(), out->m.mpi, &out->m.len, in, in_len) == 0) { + out->m.mpi[out->m.len++] = hash_algo; + ret = RNP_SUCCESS; + } +done: + botan_pk_op_encrypt_destroy(enc_op); + botan_pubkey_destroy(sm2_key); + return ret; +} + +rnp_result_t +sm2_decrypt(uint8_t * out, + size_t * out_len, + const pgp_sm2_encrypted_t *in, + const pgp_ec_key_t * key) +{ + const ec_curve_desc_t *curve; + botan_pk_op_decrypt_t decrypt_op = NULL; + botan_privkey_t b_key = NULL; + size_t in_len; + rnp_result_t ret = RNP_ERROR_GENERIC; + uint8_t hash_id; + const char * hash_name = NULL; + + curve = get_curve_desc(key->curve); + in_len = mpi_bytes(&in->m); + if (curve == NULL || in_len < 64) { + goto done; + } + + if (!sm2_load_secret_key(&b_key, key)) { + RNP_LOG("Can't load private key"); + goto done; + } + + hash_id = in->m.mpi[in_len - 1]; + hash_name = rnp::Hash_Botan::name_backend((pgp_hash_alg_t) hash_id); + if (!hash_name) { + RNP_LOG("Unknown hash used in SM2 ciphertext"); + goto done; + } + + if (botan_pk_op_decrypt_create(&decrypt_op, b_key, hash_name, 0) != 0) { + goto done; + } + + if (botan_pk_op_decrypt(decrypt_op, out, out_len, in->m.mpi, in_len - 1) == 0) { + ret = RNP_SUCCESS; + } +done: + botan_privkey_destroy(b_key); + botan_pk_op_decrypt_destroy(decrypt_op); + return ret; +} diff --git a/comm/third_party/rnp/src/lib/crypto/sm2.h b/comm/third_party/rnp/src/lib/crypto/sm2.h new file mode 100644 index 0000000000..a16f7fad83 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sm2.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2017-2022 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_SM2_H_ +#define RNP_SM2_H_ + +#include "config.h" +#include "ec.h" + +typedef struct pgp_sm2_encrypted_t { + pgp_mpi_t m; +} pgp_sm2_encrypted_t; + +namespace rnp { +class Hash; +} // namespace rnp + +#if defined(ENABLE_SM2) +rnp_result_t sm2_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret); + +/** + * Compute the SM2 "ZA" field, and add it to the hash object + * + * If ident_field is null, uses the default value + */ +rnp_result_t sm2_compute_za(const pgp_ec_key_t &key, + rnp::Hash & hash, + const char * ident_field = NULL); + +rnp_result_t sm2_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key); + +rnp_result_t sm2_verify(const pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key); + +rnp_result_t sm2_encrypt(rnp::RNG * rng, + pgp_sm2_encrypted_t *out, + const uint8_t * in, + size_t in_len, + pgp_hash_alg_t hash_algo, + const pgp_ec_key_t * key); + +rnp_result_t sm2_decrypt(uint8_t * out, + size_t * out_len, + const pgp_sm2_encrypted_t *in, + const pgp_ec_key_t * key); +#endif // defined(ENABLE_SM2) + +#endif // SM2_H_ diff --git a/comm/third_party/rnp/src/lib/crypto/sm2_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/sm2_ossl.cpp new file mode 100644 index 0000000000..4c1eaf17a8 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/sm2_ossl.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "sm2.h" +#include "utils.h" + +rnp_result_t +sm2_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) +{ + return RNP_ERROR_NOT_IMPLEMENTED; +} + +rnp_result_t +sm2_sign(rnp::RNG * rng, + pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t *key) +{ + return RNP_ERROR_NOT_IMPLEMENTED; +} + +rnp_result_t +sm2_verify(const pgp_ec_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len, + const pgp_ec_key_t * key) +{ + return RNP_ERROR_NOT_IMPLEMENTED; +} + +rnp_result_t +sm2_encrypt(rnp::RNG * rng, + pgp_sm2_encrypted_t *out, + const uint8_t * in, + size_t in_len, + pgp_hash_alg_t hash_algo, + const pgp_ec_key_t * key) +{ + return RNP_ERROR_NOT_IMPLEMENTED; +} + +rnp_result_t +sm2_decrypt(uint8_t * out, + size_t * out_len, + const pgp_sm2_encrypted_t *in, + const pgp_ec_key_t * key) +{ + return RNP_ERROR_NOT_IMPLEMENTED; +} diff --git a/comm/third_party/rnp/src/lib/crypto/symmetric.cpp b/comm/third_party/rnp/src/lib/crypto/symmetric.cpp new file mode 100644 index 0000000000..aeed78432d --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/symmetric.cpp @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "crypto.h" +#include "config.h" +#include "defaults.h" + +#include +#include +#include +#include +#include "utils.h" + +static const char * +pgp_sa_to_botan_string(int alg, bool silent = false) +{ + switch (alg) { +#if defined(BOTAN_HAS_IDEA) && defined(ENABLE_IDEA) + case PGP_SA_IDEA: + return "IDEA"; +#endif + +#if defined(BOTAN_HAS_DES) + case PGP_SA_TRIPLEDES: + return "TripleDES"; +#endif + +#if defined(BOTAN_HAS_CAST) && defined(ENABLE_CAST5) + case PGP_SA_CAST5: + return "CAST-128"; +#endif + +#if defined(BOTAN_HAS_BLOWFISH) && defined(ENABLE_BLOWFISH) + case PGP_SA_BLOWFISH: + return "Blowfish"; +#endif + +#if defined(BOTAN_HAS_AES) + case PGP_SA_AES_128: + return "AES-128"; + case PGP_SA_AES_192: + return "AES-192"; + case PGP_SA_AES_256: + return "AES-256"; +#endif + +#if defined(BOTAN_HAS_SM4) && defined(ENABLE_SM2) + case PGP_SA_SM4: + return "SM4"; +#endif + +#if defined(BOTAN_HAS_TWOFISH) && defined(ENABLE_TWOFISH) + case PGP_SA_TWOFISH: + return "Twofish"; +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + case PGP_SA_CAMELLIA_128: + return "Camellia-128"; + case PGP_SA_CAMELLIA_192: + return "Camellia-192"; + case PGP_SA_CAMELLIA_256: + return "Camellia-256"; +#endif + + default: + if (!silent) { + RNP_LOG("Unsupported symmetric algorithm %d", alg); + } + return NULL; + } +} + +#if defined(ENABLE_AEAD) +static bool +pgp_aead_to_botan_string(pgp_symm_alg_t ealg, pgp_aead_alg_t aalg, char *buf, size_t len) +{ + const char *ealg_name = pgp_sa_to_botan_string(ealg); + size_t ealg_len; + + if (!ealg_name) { + return false; + } + + ealg_len = strlen(ealg_name); + + if (len < ealg_len + 5) { + RNP_LOG("buffer too small"); + return false; + } + + switch (aalg) { + case PGP_AEAD_EAX: + memcpy(buf, ealg_name, ealg_len); + strncpy(buf + ealg_len, "/EAX", len - ealg_len); + break; + case PGP_AEAD_OCB: + memcpy(buf, ealg_name, ealg_len); + strncpy(buf + ealg_len, "/OCB", len - ealg_len); + break; + default: + RNP_LOG("unsupported AEAD alg %d", (int) aalg); + return false; + } + + return true; +} +#endif + +bool +pgp_cipher_cfb_start(pgp_crypt_t * crypt, + pgp_symm_alg_t alg, + const uint8_t *key, + const uint8_t *iv) +{ + memset(crypt, 0x0, sizeof(*crypt)); + + const char *cipher_name = pgp_sa_to_botan_string(alg); + if (!cipher_name) { + return false; + } + + crypt->alg = alg; + crypt->blocksize = pgp_block_size(alg); + + // This shouldn't happen if pgp_sa_to_botan_string returned a ptr + if (botan_block_cipher_init(&(crypt->cfb.obj), cipher_name) != 0) { + RNP_LOG("Block cipher '%s' not available", cipher_name); + return false; + } + + const size_t keysize = pgp_key_size(alg); + + if (botan_block_cipher_set_key(crypt->cfb.obj, key, keysize) != 0) { + RNP_LOG("Failure setting key on block cipher object"); + return false; + } + + if (iv != NULL) { + // Otherwise left as all zeros via memset at start of function + memcpy(crypt->cfb.iv, iv, crypt->blocksize); + } + + crypt->cfb.remaining = 0; + + return true; +} + +void +pgp_cipher_cfb_resync(pgp_crypt_t *crypt, const uint8_t *buf) +{ + /* iv will be encrypted in the upcoming call to encrypt/decrypt */ + memcpy(crypt->cfb.iv, buf, crypt->blocksize); + crypt->cfb.remaining = 0; +} + +int +pgp_cipher_cfb_finish(pgp_crypt_t *crypt) +{ + if (!crypt) { + return 0; + } + if (crypt->cfb.obj) { + botan_block_cipher_destroy(crypt->cfb.obj); + crypt->cfb.obj = NULL; + } + botan_scrub_mem((uint8_t *) crypt, sizeof(*crypt)); + return 0; +} + +/* we rely on fact that in and out could be the same */ +int +pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t bytes) +{ + uint64_t *in64; + uint64_t buf64[512]; // 4KB - page size + uint64_t iv64[2]; + size_t blocks, blockb; + unsigned blsize = crypt->blocksize; + + /* encrypting till the block boundary */ + while (bytes && crypt->cfb.remaining) { + *out = *in++ ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = *out++; + crypt->cfb.remaining--; + bytes--; + } + + if (!bytes) { + return 0; + } + + /* encrypting full blocks */ + if (bytes > blsize) { + memcpy(iv64, crypt->cfb.iv, blsize); + while ((blocks = bytes & ~(blsize - 1)) > 0) { + if (blocks > sizeof(buf64)) { + blocks = sizeof(buf64); + } + bytes -= blocks; + blockb = blocks; + memcpy(buf64, in, blockb); + in64 = buf64; + + if (blsize == 16) { + blocks >>= 4; + while (blocks--) { + botan_block_cipher_encrypt_blocks( + crypt->cfb.obj, (uint8_t *) iv64, (uint8_t *) iv64, 1); + *in64 ^= iv64[0]; + iv64[0] = *in64++; + *in64 ^= iv64[1]; + iv64[1] = *in64++; + } + } else { + blocks >>= 3; + while (blocks--) { + botan_block_cipher_encrypt_blocks( + crypt->cfb.obj, (uint8_t *) iv64, (uint8_t *) iv64, 1); + *in64 ^= iv64[0]; + iv64[0] = *in64++; + } + } + + memcpy(out, buf64, blockb); + out += blockb; + in += blockb; + } + + memcpy(crypt->cfb.iv, iv64, blsize); + } + + if (!bytes) { + return 0; + } + + botan_block_cipher_encrypt_blocks(crypt->cfb.obj, crypt->cfb.iv, crypt->cfb.iv, 1); + crypt->cfb.remaining = blsize; + + /* encrypting tail */ + while (bytes) { + *out = *in++ ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = *out++; + crypt->cfb.remaining--; + bytes--; + } + + return 0; +} + +/* we rely on fact that in and out could be the same */ +int +pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t bytes) +{ + /* for better code readability */ + uint64_t *out64, *in64; + uint64_t inbuf64[512]; // 4KB - page size + uint64_t outbuf64[512]; + uint64_t iv64[2]; + size_t blocks, blockb; + unsigned blsize = crypt->blocksize; + + /* decrypting till the block boundary */ + while (bytes && crypt->cfb.remaining) { + uint8_t c = *in++; + *out++ = c ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = c; + crypt->cfb.remaining--; + bytes--; + } + + if (!bytes) { + return 0; + } + + /* decrypting full blocks */ + if (bytes > blsize) { + memcpy(iv64, crypt->cfb.iv, blsize); + + while ((blocks = bytes & ~(blsize - 1)) > 0) { + if (blocks > sizeof(inbuf64)) { + blocks = sizeof(inbuf64); + } + bytes -= blocks; + blockb = blocks; + memcpy(inbuf64, in, blockb); + out64 = outbuf64; + in64 = inbuf64; + + if (blsize == 16) { + blocks >>= 4; + while (blocks--) { + botan_block_cipher_encrypt_blocks( + crypt->cfb.obj, (uint8_t *) iv64, (uint8_t *) iv64, 1); + *out64++ = *in64 ^ iv64[0]; + iv64[0] = *in64++; + *out64++ = *in64 ^ iv64[1]; + iv64[1] = *in64++; + } + } else { + blocks >>= 3; + while (blocks--) { + botan_block_cipher_encrypt_blocks( + crypt->cfb.obj, (uint8_t *) iv64, (uint8_t *) iv64, 1); + *out64++ = *in64 ^ iv64[0]; + iv64[0] = *in64++; + } + } + + memcpy(out, outbuf64, blockb); + out += blockb; + in += blockb; + } + + memcpy(crypt->cfb.iv, iv64, blsize); + } + + if (!bytes) { + return 0; + } + + botan_block_cipher_encrypt_blocks(crypt->cfb.obj, crypt->cfb.iv, crypt->cfb.iv, 1); + crypt->cfb.remaining = blsize; + + /* decrypting tail */ + while (bytes) { + uint8_t c = *in++; + *out++ = c ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = c; + crypt->cfb.remaining--; + bytes--; + } + + return 0; +} + +size_t +pgp_cipher_block_size(pgp_crypt_t *crypt) +{ + return crypt->blocksize; +} + +unsigned +pgp_block_size(pgp_symm_alg_t alg) +{ + switch (alg) { + case PGP_SA_IDEA: + case PGP_SA_TRIPLEDES: + case PGP_SA_CAST5: + case PGP_SA_BLOWFISH: + return 8; + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + case PGP_SA_TWOFISH: + case PGP_SA_CAMELLIA_128: + case PGP_SA_CAMELLIA_192: + case PGP_SA_CAMELLIA_256: + case PGP_SA_SM4: + return 16; + default: + return 0; + } +} + +unsigned +pgp_key_size(pgp_symm_alg_t alg) +{ + /* Update MAX_SYMM_KEY_SIZE after adding algorithm + * with bigger key size. + */ + static_assert(32 == MAX_SYMM_KEY_SIZE, "MAX_SYMM_KEY_SIZE must be updated"); + + switch (alg) { + case PGP_SA_IDEA: + case PGP_SA_CAST5: + case PGP_SA_BLOWFISH: + case PGP_SA_AES_128: + case PGP_SA_CAMELLIA_128: + case PGP_SA_SM4: + return 16; + + case PGP_SA_TRIPLEDES: + case PGP_SA_AES_192: + case PGP_SA_CAMELLIA_192: + return 24; + + case PGP_SA_TWOFISH: + case PGP_SA_AES_256: + case PGP_SA_CAMELLIA_256: + return 32; + + default: + return 0; + } +} + +bool +pgp_is_sa_supported(int alg, bool silent) +{ + return pgp_sa_to_botan_string(alg, silent); +} + +#if defined(ENABLE_AEAD) +bool +pgp_cipher_aead_init(pgp_crypt_t * crypt, + pgp_symm_alg_t ealg, + pgp_aead_alg_t aalg, + const uint8_t *key, + bool decrypt) +{ + char cipher_name[32]; + uint32_t flags; + + memset(crypt, 0x0, sizeof(*crypt)); + + if (!pgp_aead_to_botan_string(ealg, aalg, cipher_name, sizeof(cipher_name))) { + return false; + } + + crypt->alg = ealg; + crypt->blocksize = pgp_block_size(ealg); + crypt->aead.alg = aalg; + crypt->aead.decrypt = decrypt; + crypt->aead.taglen = PGP_AEAD_EAX_OCB_TAG_LEN; /* it's the same for EAX and OCB */ + + flags = decrypt ? BOTAN_CIPHER_INIT_FLAG_DECRYPT : BOTAN_CIPHER_INIT_FLAG_ENCRYPT; + + if (botan_cipher_init(&(crypt->aead.obj), cipher_name, flags)) { + RNP_LOG("cipher %s is not available", cipher_name); + return false; + } + + if (botan_cipher_set_key(crypt->aead.obj, key, (size_t) pgp_key_size(ealg))) { + RNP_LOG("failed to set key"); + return false; + } + + if (botan_cipher_get_update_granularity(crypt->aead.obj, &crypt->aead.granularity)) { + RNP_LOG("failed to get update granularity"); + return false; + } + + return true; +} + +size_t +pgp_cipher_aead_granularity(pgp_crypt_t *crypt) +{ + return crypt->aead.granularity; +} +#endif + +size_t +pgp_cipher_aead_nonce_len(pgp_aead_alg_t aalg) +{ + switch (aalg) { + case PGP_AEAD_EAX: + return PGP_AEAD_EAX_NONCE_LEN; + case PGP_AEAD_OCB: + return PGP_AEAD_OCB_NONCE_LEN; + default: + return 0; + } +} + +size_t +pgp_cipher_aead_tag_len(pgp_aead_alg_t aalg) +{ + switch (aalg) { + case PGP_AEAD_EAX: + case PGP_AEAD_OCB: + return PGP_AEAD_EAX_OCB_TAG_LEN; + default: + return 0; + } +} + +#if defined(ENABLE_AEAD) +bool +pgp_cipher_aead_set_ad(pgp_crypt_t *crypt, const uint8_t *ad, size_t len) +{ + return botan_cipher_set_associated_data(crypt->aead.obj, ad, len) == 0; +} + +bool +pgp_cipher_aead_start(pgp_crypt_t *crypt, const uint8_t *nonce, size_t len) +{ + return botan_cipher_start(crypt->aead.obj, nonce, len) == 0; +} + +bool +pgp_cipher_aead_update(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len) +{ + size_t outwr = 0; + size_t inread = 0; + + if (len % crypt->aead.granularity) { + RNP_LOG("aead wrong update len"); + return false; + } + + if (botan_cipher_update(crypt->aead.obj, 0, out, len, &outwr, in, len, &inread) != 0) { + RNP_LOG("aead update failed"); + return false; + } + + if ((outwr != len) || (inread != len)) { + RNP_LOG("wrong aead usage"); + return false; + } + + return true; +} + +void +pgp_cipher_aead_reset(pgp_crypt_t *crypt) +{ + botan_cipher_reset(crypt->aead.obj); +} + +bool +pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len) +{ + uint32_t flags = BOTAN_CIPHER_UPDATE_FLAG_FINAL; + size_t inread = 0; + size_t outwr = 0; + int res; + + if (crypt->aead.decrypt) { + size_t datalen = len - crypt->aead.taglen; + /* for decryption we should have tag for the final update call */ + res = + botan_cipher_update(crypt->aead.obj, flags, out, datalen, &outwr, in, len, &inread); + if (res != 0) { + if (res != BOTAN_FFI_ERROR_BAD_MAC) { + RNP_LOG("aead finish failed: %d", res); + } + return false; + } + + if ((outwr != datalen) || (inread != len)) { + RNP_LOG("wrong decrypt aead finish usage"); + return false; + } + } else { + /* for encryption tag will be generated */ + size_t outlen = len + crypt->aead.taglen; + if (botan_cipher_update( + crypt->aead.obj, flags, out, outlen, &outwr, in, len, &inread) != 0) { + RNP_LOG("aead finish failed"); + return false; + } + + if ((outwr != outlen) || (inread != len)) { + RNP_LOG("wrong encrypt aead finish usage"); + return false; + } + } + + pgp_cipher_aead_reset(crypt); + return true; +} + +void +pgp_cipher_aead_destroy(pgp_crypt_t *crypt) +{ + botan_cipher_destroy(crypt->aead.obj); +} + +size_t +pgp_cipher_aead_nonce(pgp_aead_alg_t aalg, const uint8_t *iv, uint8_t *nonce, size_t index) +{ + switch (aalg) { + case PGP_AEAD_EAX: + /* The nonce for EAX mode is computed by treating the starting + initialization vector as a 16-octet, big-endian value and + exclusive-oring the low eight octets of it with the chunk index. + */ + memcpy(nonce, iv, PGP_AEAD_EAX_NONCE_LEN); + for (int i = 15; (i > 7) && index; i--) { + nonce[i] ^= index & 0xff; + index = index >> 8; + } + return PGP_AEAD_EAX_NONCE_LEN; + case PGP_AEAD_OCB: + /* The nonce for a chunk of chunk index "i" in OCB processing is defined as: + OCB-Nonce_{i} = IV[1..120] xor i + */ + memcpy(nonce, iv, PGP_AEAD_OCB_NONCE_LEN); + for (int i = 14; (i >= 0) && index; i--) { + nonce[i] ^= index & 0xff; + index = index >> 8; + } + return PGP_AEAD_OCB_NONCE_LEN; + default: + return 0; + } +} +#endif // ENABLE_AEAD diff --git a/comm/third_party/rnp/src/lib/crypto/symmetric.h b/comm/third_party/rnp/src/lib/crypto/symmetric.h new file mode 100644 index 0000000000..a50fe9a184 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/symmetric.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2017, 2021 [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYMMETRIC_CRYPTO_H_ +#define SYMMETRIC_CRYPTO_H_ + +#include +#include "crypto/rng.h" +#include "config.h" +#ifdef CRYPTO_BACKEND_OPENSSL +#include +#include "mem.h" +#endif + +/* Nonce len for AEAD/EAX */ +#define PGP_AEAD_EAX_NONCE_LEN 16 + +/* Nonce len for AEAD/OCB */ +#define PGP_AEAD_OCB_NONCE_LEN 15 + +/* Maximum AEAD nonce length */ +#define PGP_AEAD_MAX_NONCE_LEN 16 + +/* Authentication tag len for AEAD/EAX and AEAD/OCB */ +#define PGP_AEAD_EAX_OCB_TAG_LEN 16 + +/* Maximal size of symmetric key */ +#define MAX_SYMM_KEY_SIZE 32 + +/* Maximum AEAD tag length */ +#define PGP_AEAD_MAX_TAG_LEN 16 + +/* Maximum authenticated data length for AEAD */ +#define PGP_AEAD_MAX_AD_LEN 32 + +struct pgp_crypt_cfb_param_t { +#ifdef CRYPTO_BACKEND_BOTAN + struct botan_block_cipher_struct *obj; +#endif +#ifdef CRYPTO_BACKEND_OPENSSL + EVP_CIPHER_CTX *obj; +#endif + size_t remaining; + uint8_t iv[PGP_MAX_BLOCK_SIZE]; +}; + +struct pgp_crypt_aead_param_t { +#ifdef CRYPTO_BACKEND_BOTAN + struct botan_cipher_struct *obj; +#endif +#ifdef CRYPTO_BACKEND_OPENSSL + EVP_CIPHER_CTX * obj; + const EVP_CIPHER * cipher; + rnp::secure_vector *key; + uint8_t ad[PGP_AEAD_MAX_AD_LEN]; + size_t ad_len; + size_t n_len; +#endif + pgp_aead_alg_t alg; + bool decrypt; + size_t granularity; + size_t taglen; +}; + +/** pgp_crypt_t */ +typedef struct pgp_crypt_t { + union { + struct pgp_crypt_cfb_param_t cfb; +#if defined(ENABLE_AEAD) + struct pgp_crypt_aead_param_t aead; +#endif + }; + + pgp_symm_alg_t alg; + size_t blocksize; + rnp::RNG * rng; +} pgp_crypt_t; + +unsigned pgp_block_size(pgp_symm_alg_t); +unsigned pgp_key_size(pgp_symm_alg_t); +bool pgp_is_sa_supported(int alg, bool silent = false); +size_t pgp_cipher_block_size(pgp_crypt_t *crypt); + +/** + * Initialize a cipher object. + * @param iv if null an all-zero IV is assumed + */ +bool pgp_cipher_cfb_start(pgp_crypt_t * crypt, + pgp_symm_alg_t alg, + const uint8_t *key, + const uint8_t *iv); + +// Deallocate all storage +int pgp_cipher_cfb_finish(pgp_crypt_t *crypt); +// CFB encryption/decryption +int pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len); +int pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len); + +void pgp_cipher_cfb_resync(pgp_crypt_t *crypt, const uint8_t *buf); + +#if defined(ENABLE_AEAD) +/** @brief Initialize AEAD cipher instance + * @param crypt pgp crypto object + * @param ealg symmetric encryption algorithm to use together with AEAD cipher mode + * @param aalg AEAD cipher mode. Only EAX is supported now + * @param key key buffer. Number of key bytes is determined by ealg. + * @param decrypt true for decryption, or false for encryption + * @return true on success or false otherwise. + */ +bool pgp_cipher_aead_init(pgp_crypt_t * crypt, + pgp_symm_alg_t ealg, + pgp_aead_alg_t aalg, + const uint8_t *key, + bool decrypt); + +/** @brief Return the AEAD cipher update granularity. Botan FFI will consume chunks which are + * multiple of this value. See the description of pgp_cipher_aead_update() + * @param crypt initialized AEAD crypto + * @return Update granularity value in bytes + */ +size_t pgp_cipher_aead_granularity(pgp_crypt_t *crypt); +#endif + +/** @brief Return the AEAD cipher tag length + * @param aalg OpenPGP AEAD algorithm + * @return length of authentication tag in bytes, or 0 for unknown algorithm + */ +size_t pgp_cipher_aead_tag_len(pgp_aead_alg_t aalg); + +/** @brief Return the AEAD cipher nonce and IV length + * @param aalg OpenPGP AEAD algorithm + * @return length of nonce in bytes, or 0 for unknown algorithm + */ +size_t pgp_cipher_aead_nonce_len(pgp_aead_alg_t aalg); + +#if defined(ENABLE_AEAD) +/** @brief Set associated data + * @param crypt initialized AEAD crypto + * @param ad buffer with data. Cannot be NULL. + * @param len number of bytes in ad + * @return true on success or false otherwise. + */ +bool pgp_cipher_aead_set_ad(pgp_crypt_t *crypt, const uint8_t *ad, size_t len); + +/** @brief Start the cipher operation, using the given nonce + * @param crypt initialized AEAD crypto + * @param nonce buffer with nonce, cannot be NULL. + * @param len number of bytes in nonce. Must conform to the cipher properties. + * @return true on success or false otherwise. + */ +bool pgp_cipher_aead_start(pgp_crypt_t *crypt, const uint8_t *nonce, size_t len); + +/** @brief Update the cipher. This should be called for non-final data, respecting the + * update granularity of underlying botan cipher. Now it is 256 bytes. + * @param crypt initialized AEAD crypto + * @param out buffer to put processed data. Cannot be NULL, and should be large enough to put + * len bytes + * @param in buffer with input, cannot be NULL + * @param len number of bytes to process. Should be multiple of update granularity. + * @return true on success or false otherwise. On success exactly len processed bytes will be + * stored in out buffer + */ +bool pgp_cipher_aead_update(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len); + +/** @brief Do final update on the cipher. For decryption final chunk should contain at least + * authentication tag, for encryption input could be zero-size. + * @param crypt initialized AEAD crypto + * @param out buffer to put processed data. For decryption it should be large enough to put + * len bytes minus authentication tag, for encryption it should be large enough to + * put len byts plus a tag. + * @param in buffer with input, if any. May be NULL for encryption, then len should be zero. + * For decryption it should contain at least authentication tag. + * @param len number of input bytes bytes + * @return true on success or false otherwise. On success for decryption len minus tag size + * bytes will be stored in out, for encryption out will contain len bytes plus + * tag size. + */ +bool pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len); + +/** @brief Reset the AEAD cipher's state, calling the finish() and ignoring the result + * @param crypt initialized AEAD crypto + */ +void pgp_cipher_aead_reset(pgp_crypt_t *crypt); + +/** @brief Destroy the cipher object, deallocating all the memory. + * @param crypt initialized AEAD crypto + */ +void pgp_cipher_aead_destroy(pgp_crypt_t *crypt); + +/** @brief Helper function to set AEAD nonce for the chunk by its index. + * iv and nonce should be large enough to hold max nonce bytes + * @param aalg AEAD algorithm used + * @param iv Initial vector for the message, must have 16 bytes of data + * @param nonce Nonce to fill up, should have space for 16 bytes of data + * @param index Chunk's index + * @return Length of the nonce, or 0 if algorithm is unknown + */ +size_t pgp_cipher_aead_nonce(pgp_aead_alg_t aalg, + const uint8_t *iv, + uint8_t * nonce, + size_t index); +#endif // ENABLE_AEAD + +#endif diff --git a/comm/third_party/rnp/src/lib/crypto/symmetric_ossl.cpp b/comm/third_party/rnp/src/lib/crypto/symmetric_ossl.cpp new file mode 100644 index 0000000000..98e90eded3 --- /dev/null +++ b/comm/third_party/rnp/src/lib/crypto/symmetric_ossl.cpp @@ -0,0 +1,644 @@ +/*- + * Copyright (c) 2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "crypto.h" +#include "config.h" +#include "defaults.h" + +#include +#include +#include +#include +#include +#include "mem.h" +#include "utils.h" + +static const char * +pgp_sa_to_openssl_string(int alg, bool silent = false) +{ + switch (alg) { +#if defined(ENABLE_IDEA) + case PGP_SA_IDEA: + return "idea-ecb"; +#endif + case PGP_SA_TRIPLEDES: + return "des-ede3"; +#if defined(ENABLE_CAST5) + case PGP_SA_CAST5: + return "cast5-ecb"; +#endif +#if defined(ENABLE_BLOWFISH) + case PGP_SA_BLOWFISH: + return "bf-ecb"; +#endif + case PGP_SA_AES_128: + return "aes-128-ecb"; + case PGP_SA_AES_192: + return "aes-192-ecb"; + case PGP_SA_AES_256: + return "aes-256-ecb"; +#if defined(ENABLE_SM2) + case PGP_SA_SM4: + return "sm4-ecb"; +#endif + case PGP_SA_CAMELLIA_128: + return "camellia-128-ecb"; + case PGP_SA_CAMELLIA_192: + return "camellia-192-ecb"; + case PGP_SA_CAMELLIA_256: + return "camellia-256-ecb"; + default: + if (!silent) { + RNP_LOG("Unsupported symmetric algorithm %d", alg); + } + return NULL; + } +} + +bool +pgp_cipher_cfb_start(pgp_crypt_t * crypt, + pgp_symm_alg_t alg, + const uint8_t *key, + const uint8_t *iv) +{ + memset(crypt, 0x0, sizeof(*crypt)); + + const char *cipher_name = pgp_sa_to_openssl_string(alg); + if (!cipher_name) { + RNP_LOG("Unsupported algorithm: %d", alg); + return false; + } + + const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipher_name); + if (!cipher) { + RNP_LOG("Cipher %s is not supported by OpenSSL.", cipher_name); + return false; + } + + crypt->alg = alg; + crypt->blocksize = pgp_block_size(alg); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int res = EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv); + if (res != 1) { + RNP_LOG("Failed to initialize cipher."); + EVP_CIPHER_CTX_free(ctx); + return false; + } + crypt->cfb.obj = ctx; + + if (iv) { + // Otherwise left as all zeros via memset at start of function + memcpy(crypt->cfb.iv, iv, crypt->blocksize); + } + + crypt->cfb.remaining = 0; + return true; +} + +void +pgp_cipher_cfb_resync(pgp_crypt_t *crypt, const uint8_t *buf) +{ + /* iv will be encrypted in the upcoming call to encrypt/decrypt */ + memcpy(crypt->cfb.iv, buf, crypt->blocksize); + crypt->cfb.remaining = 0; +} + +int +pgp_cipher_cfb_finish(pgp_crypt_t *crypt) +{ + if (!crypt) { + return 0; + } + if (crypt->cfb.obj) { + EVP_CIPHER_CTX_free(crypt->cfb.obj); + crypt->cfb.obj = NULL; + } + OPENSSL_cleanse((uint8_t *) crypt, sizeof(*crypt)); + return 0; +} + +/* we rely on fact that in and out could be the same */ +int +pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t bytes) +{ + uint64_t *in64; + uint64_t buf64[512]; // 4KB - page size + uint64_t iv64[2]; + size_t blocks, blockb; + unsigned blsize = crypt->blocksize; + + /* encrypting till the block boundary */ + while (bytes && crypt->cfb.remaining) { + *out = *in++ ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = *out++; + crypt->cfb.remaining--; + bytes--; + } + + if (!bytes) { + return 0; + } + + /* encrypting full blocks */ + if (bytes > blsize) { + memcpy(iv64, crypt->cfb.iv, blsize); + while ((blocks = bytes & ~(blsize - 1)) > 0) { + if (blocks > sizeof(buf64)) { + blocks = sizeof(buf64); + } + bytes -= blocks; + blockb = blocks; + memcpy(buf64, in, blockb); + in64 = buf64; + + if (blsize == 16) { + blocks >>= 4; + while (blocks--) { + int outlen = 16; + EVP_EncryptUpdate( + crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 16); + if (outlen != 16) { + RNP_LOG("Bad outlen: must be 16"); + } + *in64 ^= iv64[0]; + iv64[0] = *in64++; + *in64 ^= iv64[1]; + iv64[1] = *in64++; + } + } else { + blocks >>= 3; + while (blocks--) { + int outlen = 8; + EVP_EncryptUpdate( + crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 8); + if (outlen != 8) { + RNP_LOG("Bad outlen: must be 8"); + } + *in64 ^= iv64[0]; + iv64[0] = *in64++; + } + } + + memcpy(out, buf64, blockb); + out += blockb; + in += blockb; + } + + memcpy(crypt->cfb.iv, iv64, blsize); + } + + if (!bytes) { + return 0; + } + + int outlen = blsize; + EVP_EncryptUpdate(crypt->cfb.obj, crypt->cfb.iv, &outlen, crypt->cfb.iv, (int) blsize); + if (outlen != (int) blsize) { + RNP_LOG("Bad outlen: must be %u", blsize); + } + crypt->cfb.remaining = blsize; + + /* encrypting tail */ + while (bytes) { + *out = *in++ ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = *out++; + crypt->cfb.remaining--; + bytes--; + } + + return 0; +} + +/* we rely on fact that in and out could be the same */ +int +pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t bytes) +{ + /* for better code readability */ + uint64_t *out64, *in64; + uint64_t inbuf64[512]; // 4KB - page size + uint64_t outbuf64[512]; + uint64_t iv64[2]; + size_t blocks, blockb; + unsigned blsize = crypt->blocksize; + + /* decrypting till the block boundary */ + while (bytes && crypt->cfb.remaining) { + uint8_t c = *in++; + *out++ = c ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = c; + crypt->cfb.remaining--; + bytes--; + } + + if (!bytes) { + return 0; + } + + /* decrypting full blocks */ + if (bytes > blsize) { + memcpy(iv64, crypt->cfb.iv, blsize); + + while ((blocks = bytes & ~(blsize - 1)) > 0) { + if (blocks > sizeof(inbuf64)) { + blocks = sizeof(inbuf64); + } + bytes -= blocks; + blockb = blocks; + memcpy(inbuf64, in, blockb); + out64 = outbuf64; + in64 = inbuf64; + + if (blsize == 16) { + blocks >>= 4; + while (blocks--) { + int outlen = 16; + EVP_EncryptUpdate( + crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 16); + if (outlen != 16) { + RNP_LOG("Bad outlen: must be 16"); + } + *out64++ = *in64 ^ iv64[0]; + iv64[0] = *in64++; + *out64++ = *in64 ^ iv64[1]; + iv64[1] = *in64++; + } + } else { + blocks >>= 3; + while (blocks--) { + int outlen = 8; + EVP_EncryptUpdate( + crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 8); + if (outlen != 8) { + RNP_LOG("Bad outlen: must be 8"); + } + *out64++ = *in64 ^ iv64[0]; + iv64[0] = *in64++; + } + } + + memcpy(out, outbuf64, blockb); + out += blockb; + in += blockb; + } + + memcpy(crypt->cfb.iv, iv64, blsize); + } + + if (!bytes) { + return 0; + } + + int outlen = blsize; + EVP_EncryptUpdate(crypt->cfb.obj, crypt->cfb.iv, &outlen, crypt->cfb.iv, (int) blsize); + if (outlen != (int) blsize) { + RNP_LOG("Bad outlen: must be %u", blsize); + } + crypt->cfb.remaining = blsize; + + /* decrypting tail */ + while (bytes) { + uint8_t c = *in++; + *out++ = c ^ crypt->cfb.iv[blsize - crypt->cfb.remaining]; + crypt->cfb.iv[blsize - crypt->cfb.remaining] = c; + crypt->cfb.remaining--; + bytes--; + } + + return 0; +} + +size_t +pgp_cipher_block_size(pgp_crypt_t *crypt) +{ + return crypt->blocksize; +} + +unsigned +pgp_block_size(pgp_symm_alg_t alg) +{ + switch (alg) { + case PGP_SA_IDEA: + case PGP_SA_TRIPLEDES: + case PGP_SA_CAST5: + case PGP_SA_BLOWFISH: + return 8; + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + case PGP_SA_TWOFISH: + case PGP_SA_CAMELLIA_128: + case PGP_SA_CAMELLIA_192: + case PGP_SA_CAMELLIA_256: + case PGP_SA_SM4: + return 16; + default: + return 0; + } +} + +unsigned +pgp_key_size(pgp_symm_alg_t alg) +{ + /* Update MAX_SYMM_KEY_SIZE after adding algorithm + * with bigger key size. + */ + static_assert(32 == MAX_SYMM_KEY_SIZE, "MAX_SYMM_KEY_SIZE must be updated"); + + switch (alg) { + case PGP_SA_IDEA: + case PGP_SA_CAST5: + case PGP_SA_BLOWFISH: + case PGP_SA_AES_128: + case PGP_SA_CAMELLIA_128: + case PGP_SA_SM4: + return 16; + case PGP_SA_TRIPLEDES: + case PGP_SA_AES_192: + case PGP_SA_CAMELLIA_192: + return 24; + case PGP_SA_TWOFISH: + case PGP_SA_AES_256: + case PGP_SA_CAMELLIA_256: + return 32; + default: + return 0; + } +} + +bool +pgp_is_sa_supported(int alg, bool silent) +{ + return pgp_sa_to_openssl_string(alg, silent); +} + +#if defined(ENABLE_AEAD) + +static const char * +openssl_aead_name(pgp_symm_alg_t ealg, pgp_aead_alg_t aalg) +{ + switch (aalg) { + case PGP_AEAD_OCB: + break; + default: + RNP_LOG("Only OCB mode is supported by the OpenSSL backend."); + return NULL; + } + switch (ealg) { + case PGP_SA_AES_128: + return "AES-128-OCB"; + case PGP_SA_AES_192: + return "AES-192-OCB"; + case PGP_SA_AES_256: + return "AES-256-OCB"; + default: + RNP_LOG("Only AES-OCB is supported by the OpenSSL backend."); + return NULL; + } +} + +bool +pgp_cipher_aead_init(pgp_crypt_t * crypt, + pgp_symm_alg_t ealg, + pgp_aead_alg_t aalg, + const uint8_t *key, + bool decrypt) +{ + memset(crypt, 0x0, sizeof(*crypt)); + /* OpenSSL backend currently supports only AES-OCB */ + const char *algname = openssl_aead_name(ealg, aalg); + if (!algname) { + return false; + } + auto cipher = EVP_get_cipherbyname(algname); + if (!cipher) { + RNP_LOG("Cipher %s is not supported.", algname); + return false; + } + /* Create and setup context */ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + RNP_LOG("Failed to create cipher context: %lu", ERR_peek_last_error()); + return false; + } + + crypt->aead.key = new rnp::secure_vector(key, key + pgp_key_size(ealg)); + crypt->alg = ealg; + crypt->blocksize = pgp_block_size(ealg); + crypt->aead.cipher = cipher; + crypt->aead.obj = ctx; + crypt->aead.alg = aalg; + crypt->aead.decrypt = decrypt; + crypt->aead.granularity = crypt->blocksize; + crypt->aead.taglen = PGP_AEAD_EAX_OCB_TAG_LEN; + crypt->aead.ad_len = 0; + crypt->aead.n_len = pgp_cipher_aead_nonce_len(aalg); + return true; +} + +size_t +pgp_cipher_aead_granularity(pgp_crypt_t *crypt) +{ + return crypt->aead.granularity; +} +#endif + +size_t +pgp_cipher_aead_nonce_len(pgp_aead_alg_t aalg) +{ + switch (aalg) { + case PGP_AEAD_EAX: + return PGP_AEAD_EAX_NONCE_LEN; + case PGP_AEAD_OCB: + return PGP_AEAD_OCB_NONCE_LEN; + default: + return 0; + } +} + +size_t +pgp_cipher_aead_tag_len(pgp_aead_alg_t aalg) +{ + switch (aalg) { + case PGP_AEAD_EAX: + case PGP_AEAD_OCB: + return PGP_AEAD_EAX_OCB_TAG_LEN; + default: + return 0; + } +} + +#if defined(ENABLE_AEAD) +bool +pgp_cipher_aead_set_ad(pgp_crypt_t *crypt, const uint8_t *ad, size_t len) +{ + assert(len <= sizeof(crypt->aead.ad)); + memcpy(crypt->aead.ad, ad, len); + crypt->aead.ad_len = len; + return true; +} + +bool +pgp_cipher_aead_start(pgp_crypt_t *crypt, const uint8_t *nonce, size_t len) +{ + auto &aead = crypt->aead; + auto ctx = aead.obj; + int enc = aead.decrypt ? 0 : 1; + assert(len == aead.n_len); + EVP_CIPHER_CTX_reset(ctx); + if (EVP_CipherInit_ex(ctx, aead.cipher, NULL, NULL, NULL, enc) != 1) { + RNP_LOG("Failed to initialize cipher: %lu", ERR_peek_last_error()); + return false; + } + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, aead.n_len, NULL) != 1) { + RNP_LOG("Failed to set nonce length: %lu", ERR_peek_last_error()); + return false; + } + if (EVP_CipherInit_ex(ctx, NULL, NULL, aead.key->data(), nonce, enc) != 1) { + RNP_LOG("Failed to start cipher: %lu", ERR_peek_last_error()); + return false; + } + int adlen = 0; + if (EVP_CipherUpdate(ctx, NULL, &adlen, aead.ad, aead.ad_len) != 1) { + RNP_LOG("Failed to set AD: %lu", ERR_peek_last_error()); + return false; + } + return true; +} + +bool +pgp_cipher_aead_update(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len) +{ + if (!len) { + return true; + } + int out_len = 0; + bool res = EVP_CipherUpdate(crypt->aead.obj, out, &out_len, in, len) == 1; + if (!res) { + RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error()); + } + assert(out_len == (int) len); + return res; +} + +void +pgp_cipher_aead_reset(pgp_crypt_t *crypt) +{ + /* Do nothing as subsequent pgp_cipher_aead_start() call will reset context */ +} + +bool +pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len) +{ + auto &aead = crypt->aead; + auto ctx = aead.obj; + if (aead.decrypt) { + assert(len >= aead.taglen); + if (len < aead.taglen) { + RNP_LOG("Invalid state: too few input bytes."); + return false; + } + size_t data_len = len - aead.taglen; + int out_len = 0; + if (EVP_CipherUpdate(ctx, out, &out_len, in, data_len) != 1) { + RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error()); + return false; + } + uint8_t tag[PGP_AEAD_MAX_TAG_LEN] = {0}; + memcpy(tag, in + data_len, aead.taglen); + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead.taglen, tag) != 1) { + RNP_LOG("Failed to set tag: %lu", ERR_peek_last_error()); + return false; + } + int out_len2 = 0; + if (EVP_CipherFinal_ex(ctx, out + out_len, &out_len2) != 1) { + /* Zero value if auth tag is incorrect */ + if (ERR_peek_last_error()) { + RNP_LOG("Failed to finish AEAD decryption: %lu", ERR_peek_last_error()); + } + return false; + } + assert(out_len + out_len2 == (int) (len - aead.taglen)); + } else { + int out_len = 0; + if (EVP_CipherUpdate(ctx, out, &out_len, in, len) != 1) { + RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error()); + return false; + } + int out_len2 = 0; + if (EVP_CipherFinal_ex(ctx, out + out_len, &out_len2) != 1) { + RNP_LOG("Failed to finish AEAD encryption: %lu", ERR_peek_last_error()); + return false; + } + assert(out_len + out_len2 == (int) len); + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, aead.taglen, out + len) != 1) { + RNP_LOG("Failed to get tag: %lu", ERR_peek_last_error()); + return false; + } + } + return true; +} + +void +pgp_cipher_aead_destroy(pgp_crypt_t *crypt) +{ + if (crypt->aead.obj) { + EVP_CIPHER_CTX_free(crypt->aead.obj); + } + delete crypt->aead.key; + memset(crypt, 0x0, sizeof(*crypt)); +} + +size_t +pgp_cipher_aead_nonce(pgp_aead_alg_t aalg, const uint8_t *iv, uint8_t *nonce, size_t index) +{ + switch (aalg) { + case PGP_AEAD_EAX: + /* The nonce for EAX mode is computed by treating the starting + initialization vector as a 16-octet, big-endian value and + exclusive-oring the low eight octets of it with the chunk index. + */ + memcpy(nonce, iv, PGP_AEAD_EAX_NONCE_LEN); + for (int i = 15; (i > 7) && index; i--) { + nonce[i] ^= index & 0xff; + index = index >> 8; + } + return PGP_AEAD_EAX_NONCE_LEN; + case PGP_AEAD_OCB: + /* The nonce for a chunk of chunk index "i" in OCB processing is defined as: + OCB-Nonce_{i} = IV[1..120] xor i + */ + memcpy(nonce, iv, PGP_AEAD_OCB_NONCE_LEN); + for (int i = 14; (i >= 0) && index; i--) { + nonce[i] ^= index & 0xff; + index = index >> 8; + } + return PGP_AEAD_OCB_NONCE_LEN; + default: + return 0; + } +} +#endif diff --git a/comm/third_party/rnp/src/lib/defaults.h b/comm/third_party/rnp/src/lib/defaults.h new file mode 100644 index 0000000000..22a3c46377 --- /dev/null +++ b/comm/third_party/rnp/src/lib/defaults.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018-2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DEFAULTS_H_ +#define DEFAULTS_H_ + +/* Default hash algorithm as PGP constant */ +#define DEFAULT_PGP_HASH_ALG PGP_HASH_SHA256 + +/* Default symmetric algorithm as PGP constant */ +#define DEFAULT_PGP_SYMM_ALG PGP_SA_AES_256 + +/* Default number of msec to run S2K derivation */ +#define DEFAULT_S2K_MSEC 150 + +/* Default number of msec to run S2K tuning */ +#define DEFAULT_S2K_TUNE_MSEC 10 + +/* Default compression algorithm and level */ +#define DEFAULT_Z_ALG "ZIP" +#define DEFAULT_Z_LEVEL 6 + +/* Default AEAD algorithm */ +#define DEFAULT_AEAD_ALG PGP_AEAD_OCB + +/* Default AEAD chunk bits, equals to 256K chunks */ +#define DEFAULT_AEAD_CHUNK_BITS 12 + +/* Default cipher mode for secret key encryption */ +#define DEFAULT_CIPHER_MODE "CFB" + +/* Default cipher mode for secret key encryption */ +#define DEFAULT_PGP_CIPHER_MODE PGP_CIPHER_MODE_CFB + +/* Default public key algorithm for new key generation */ +#define DEFAULT_PK_ALG PGP_PKA_RSA + +/* Default RSA key length */ +#define DEFAULT_RSA_NUMBITS 2048 + +/* Default ElGamal key length */ +#define DEFAULT_ELGAMAL_NUMBITS 2048 +#define ELGAMAL_MIN_P_BITLEN 1024 +#define ELGAMAL_MAX_P_BITLEN 4096 + +/* Default, min and max DSA key length */ +#define DSA_MIN_P_BITLEN 1024 +#define DSA_MAX_P_BITLEN 3072 +#define DSA_DEFAULT_P_BITLEN 2048 + +/* Default EC curve */ +#define DEFAULT_CURVE "NIST P-256" + +/* Default maximum password request attempts */ +#define MAX_PASSWORD_ATTEMPTS 3 + +/* Infinite password request attempts */ +#define INFINITE_ATTEMPTS -1 + +/* Default key expiration in seconds, 2 years */ +#define DEFAULT_KEY_EXPIRATION (2 * 365 * 24 * 60 * 60) + +#endif diff --git a/comm/third_party/rnp/src/lib/ffi-priv-types.h b/comm/third_party/rnp/src/lib/ffi-priv-types.h new file mode 100644 index 0000000000..beb624c9ba --- /dev/null +++ b/comm/third_party/rnp/src/lib/ffi-priv-types.h @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 2019 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "utils.h" +#include +#include +#include "sec_profile.hpp" + +struct rnp_key_handle_st { + rnp_ffi_t ffi; + pgp_key_search_t locator; + pgp_key_t * pub; + pgp_key_t * sec; +}; + +struct rnp_uid_handle_st { + rnp_ffi_t ffi; + pgp_key_t *key; + size_t idx; +}; + +struct rnp_signature_handle_st { + rnp_ffi_t ffi; + const pgp_key_t *key; + pgp_subsig_t * sig; + bool own_sig; +}; + +struct rnp_recipient_handle_st { + rnp_ffi_t ffi; + uint8_t keyid[PGP_KEY_ID_SIZE]; + pgp_pubkey_alg_t palg; +}; + +struct rnp_symenc_handle_st { + rnp_ffi_t ffi; + pgp_symm_alg_t alg; + pgp_hash_alg_t halg; + pgp_s2k_specifier_t s2k_type; + uint32_t iterations; + pgp_aead_alg_t aalg; +}; + +struct rnp_ffi_st { + FILE * errs; + rnp_key_store_t * pubring; + rnp_key_store_t * secring; + rnp_get_key_cb getkeycb; + void * getkeycb_ctx; + rnp_password_cb getpasscb; + void * getpasscb_ctx; + pgp_key_provider_t key_provider; + pgp_password_provider_t pass_provider; + rnp::SecurityContext context; + + rnp_ffi_st(pgp_key_store_format_t pub_fmt, pgp_key_store_format_t sec_fmt); + ~rnp_ffi_st(); + + rnp::RNG & rng() noexcept; + rnp::SecurityProfile &profile() noexcept; +}; + +struct rnp_input_st { + /* either src or src_directory are valid, not both */ + pgp_source_t src; + std::string src_directory; + rnp_input_reader_t *reader; + rnp_input_closer_t *closer; + void * app_ctx; + + rnp_input_st(); + rnp_input_st(const rnp_input_st &) = delete; + rnp_input_st(rnp_input_st &&) = delete; + ~rnp_input_st(); + + rnp_input_st &operator=(const rnp_input_st &) = delete; + rnp_input_st &operator=(rnp_input_st &&src); +}; + +struct rnp_output_st { + /* either dst or dst_directory are valid, not both */ + pgp_dest_t dst; + char * dst_directory; + rnp_output_writer_t *writer; + rnp_output_closer_t *closer; + void * app_ctx; + bool keep; +}; + +struct rnp_op_generate_st { + rnp_ffi_t ffi{}; + bool primary{}; + pgp_key_t *primary_sec{}; + pgp_key_t *primary_pub{}; + pgp_key_t *gen_sec{}; + pgp_key_t *gen_pub{}; + /* password used to encrypt the key, if specified */ + rnp::secure_vector password; + /* request password for key encryption via ffi's password provider */ + bool request_password{}; + /* we don't use top-level keygen action here for easier fields access */ + rnp_keygen_crypto_params_t crypto{}; + rnp_key_protection_params_t protection{}; + rnp_selfsig_cert_info_t cert{}; + rnp_selfsig_binding_info_t binding{}; +}; + +struct rnp_op_sign_signature_st { + rnp_ffi_t ffi{}; + rnp_signer_info_t signer{}; + bool expiry_set : 1; + bool create_set : 1; + bool hash_set : 1; +}; + +typedef std::list rnp_op_sign_signatures_t; + +struct rnp_op_sign_st { + rnp_ffi_t ffi{}; + rnp_input_t input{}; + rnp_output_t output{}; + rnp_ctx_t rnpctx{}; + rnp_op_sign_signatures_t signatures{}; +}; + +struct rnp_op_verify_signature_st { + rnp_ffi_t ffi; + rnp_result_t verify_status; + pgp_signature_t sig_pkt; +}; + +struct rnp_op_verify_st { + rnp_ffi_t ffi{}; + rnp_input_t input{}; + rnp_input_t detached_input{}; /* for detached signature will be source file/data */ + rnp_output_t output{}; + rnp_ctx_t rnpctx{}; + /* these fields are filled after operation execution */ + rnp_op_verify_signature_t signatures{}; + size_t signature_count{}; + char * filename{}; + uint32_t file_mtime{}; + /* encryption information */ + bool encrypted{}; + bool mdc{}; + bool validated{}; + pgp_aead_alg_t aead{}; + pgp_symm_alg_t salg{}; + bool ignore_sigs{}; + bool require_all_sigs{}; + bool allow_hidden{}; + /* recipient/symenc information */ + rnp_recipient_handle_t recipients{}; + size_t recipient_count{}; + rnp_recipient_handle_t used_recipient{}; + rnp_symenc_handle_t symencs{}; + size_t symenc_count{}; + rnp_symenc_handle_t used_symenc{}; + size_t encrypted_layers{}; + + ~rnp_op_verify_st(); +}; + +struct rnp_op_encrypt_st { + rnp_ffi_t ffi{}; + rnp_input_t input{}; + rnp_output_t output{}; + rnp_ctx_t rnpctx{}; + rnp_op_sign_signatures_t signatures{}; +}; + +#define RNP_LOCATOR_MAX_SIZE (MAX_ID_LENGTH + 1) +static_assert(RNP_LOCATOR_MAX_SIZE > PGP_FINGERPRINT_SIZE * 2, "Locator size mismatch."); +static_assert(RNP_LOCATOR_MAX_SIZE > PGP_KEY_ID_SIZE * 2, "Locator size mismatch."); +static_assert(RNP_LOCATOR_MAX_SIZE > PGP_KEY_GRIP_SIZE * 2, "Locator size mismatch."); +static_assert(RNP_LOCATOR_MAX_SIZE > MAX_ID_LENGTH, "Locator size mismatch."); + +struct rnp_identifier_iterator_st { + rnp_ffi_t ffi; + pgp_key_search_type_t type; + rnp_key_store_t * store; + std::list::iterator *keyp; + unsigned uididx; + json_object * tbl; + char buf[RNP_LOCATOR_MAX_SIZE]; +}; + +struct rnp_decryption_kp_param_t { + rnp_op_verify_t op; + bool has_hidden; /* key provider had hidden keyid request */ + pgp_key_t * last; /* last key, returned in hidden keyid request */ + + rnp_decryption_kp_param_t(rnp_op_verify_t opobj) + : op(opobj), has_hidden(false), last(NULL){}; +}; + +/* This is just for readability at the call site and will hopefully reduce mistakes. + * + * Instead of: + * void do_something(rnp_ffi_t ffi, bool with_secret_keys); + * do_something(ffi, true); + * do_something(ffi, false); + * + * You can have something a bit clearer: + * void do_something(rnp_ffi_t ffi, key_type_t key_type); + * do_something(ffi, KEY_TYPE_PUBLIC); + * do_something(ffi, KEY_TYPE_SECRET); + */ +typedef enum key_type_t { + KEY_TYPE_NONE, + KEY_TYPE_PUBLIC, + KEY_TYPE_SECRET, + KEY_TYPE_ANY +} key_type_t; diff --git a/comm/third_party/rnp/src/lib/fingerprint.cpp b/comm/third_party/rnp/src/lib/fingerprint.cpp new file mode 100644 index 0000000000..c937c74915 --- /dev/null +++ b/comm/third_party/rnp/src/lib/fingerprint.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017-2022, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "fingerprint.h" +#include "crypto/hash.hpp" +#include +#include +#include +#include "utils.h" + +rnp_result_t +pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key) +{ + if ((key.version == PGP_V2) || (key.version == PGP_V3)) { + if (!is_rsa_key_alg(key.alg)) { + RNP_LOG("bad algorithm"); + return RNP_ERROR_NOT_SUPPORTED; + } + try { + auto hash = rnp::Hash::create(PGP_HASH_MD5); + hash->add(key.material.rsa.n); + hash->add(key.material.rsa.e); + fp.length = hash->finish(fp.fingerprint); + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("Failed to calculate v3 fingerprint: %s", e.what()); + return RNP_ERROR_BAD_STATE; + } + } + + if (key.version != PGP_V4) { + RNP_LOG("unsupported key version"); + return RNP_ERROR_NOT_SUPPORTED; + } + + try { + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + signature_hash_key(key, *hash); + fp.length = hash->finish(fp.fingerprint); + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("Failed to calculate v4 fingerprint: %s", e.what()); + return RNP_ERROR_BAD_STATE; + } +} + +/** + * \ingroup Core_Keys + * \brief Calculate the Key ID from the public key. + * \param keyid Space for the calculated ID to be stored + * \param key The key for which the ID is calculated + */ + +rnp_result_t +pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key) +{ + pgp_fingerprint_t fp; + rnp_result_t ret; + size_t n; + + if ((key.version == PGP_V2) || (key.version == PGP_V3)) { + if (!is_rsa_key_alg(key.alg)) { + RNP_LOG("bad algorithm"); + return RNP_ERROR_NOT_SUPPORTED; + } + n = mpi_bytes(&key.material.rsa.n); + (void) memcpy(keyid.data(), key.material.rsa.n.mpi + n - keyid.size(), keyid.size()); + return RNP_SUCCESS; + } + + if ((ret = pgp_fingerprint(fp, key))) { + return ret; + } + (void) memcpy(keyid.data(), fp.fingerprint + fp.length - keyid.size(), keyid.size()); + return RNP_SUCCESS; +} + +bool +pgp_fingerprint_t::operator==(const pgp_fingerprint_t &src) const +{ + return (length == src.length) && !memcmp(fingerprint, src.fingerprint, length); +} + +bool +pgp_fingerprint_t::operator!=(const pgp_fingerprint_t &src) const +{ + return !(*this == src); +} diff --git a/comm/third_party/rnp/src/lib/fingerprint.h b/comm/third_party/rnp/src/lib/fingerprint.h new file mode 100644 index 0000000000..e8d47138fd --- /dev/null +++ b/comm/third_party/rnp/src/lib/fingerprint.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2017 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_FINGERPRINT_H_ +#define RNP_FINGERPRINT_H_ + +#include +#include +#include +#include "types.h" + +rnp_result_t pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key); + +rnp_result_t pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key); + +#endif diff --git a/comm/third_party/rnp/src/lib/generate-key.cpp b/comm/third_party/rnp/src/lib/generate-key.cpp new file mode 100644 index 0000000000..dfd5556dd6 --- /dev/null +++ b/comm/third_party/rnp/src/lib/generate-key.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include "crypto.h" +#include "pgp-key.h" +#include "defaults.h" +#include "utils.h" + +static const uint8_t DEFAULT_SYMMETRIC_ALGS[] = { + PGP_SA_AES_256, PGP_SA_AES_192, PGP_SA_AES_128}; +static const uint8_t DEFAULT_HASH_ALGS[] = { + PGP_HASH_SHA256, PGP_HASH_SHA384, PGP_HASH_SHA512, PGP_HASH_SHA224}; +static const uint8_t DEFAULT_COMPRESS_ALGS[] = { + PGP_C_ZLIB, PGP_C_BZIP2, PGP_C_ZIP, PGP_C_NONE}; + +static const id_str_pair pubkey_alg_map[] = { + {PGP_PKA_RSA, "RSA (Encrypt or Sign)"}, + {PGP_PKA_RSA_ENCRYPT_ONLY, "RSA Encrypt-Only"}, + {PGP_PKA_RSA_SIGN_ONLY, "RSA Sign-Only"}, + {PGP_PKA_ELGAMAL, "Elgamal (Encrypt-Only)"}, + {PGP_PKA_DSA, "DSA"}, + {PGP_PKA_ECDH, "ECDH"}, + {PGP_PKA_ECDSA, "ECDSA"}, + {PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN, "Reserved (formerly Elgamal Encrypt or Sign"}, + {PGP_PKA_RESERVED_DH, "Reserved for Diffie-Hellman (X9.42)"}, + {PGP_PKA_EDDSA, "EdDSA"}, + {PGP_PKA_SM2, "SM2"}, + {PGP_PKA_PRIVATE00, "Private/Experimental"}, + {PGP_PKA_PRIVATE01, "Private/Experimental"}, + {PGP_PKA_PRIVATE02, "Private/Experimental"}, + {PGP_PKA_PRIVATE03, "Private/Experimental"}, + {PGP_PKA_PRIVATE04, "Private/Experimental"}, + {PGP_PKA_PRIVATE05, "Private/Experimental"}, + {PGP_PKA_PRIVATE06, "Private/Experimental"}, + {PGP_PKA_PRIVATE07, "Private/Experimental"}, + {PGP_PKA_PRIVATE08, "Private/Experimental"}, + {PGP_PKA_PRIVATE09, "Private/Experimental"}, + {PGP_PKA_PRIVATE10, "Private/Experimental"}, + {0, NULL}}; + +static bool +load_generated_g10_key(pgp_key_t * dst, + pgp_key_pkt_t * newkey, + pgp_key_t * primary_key, + pgp_key_t * pubkey, + rnp::SecurityContext &ctx) +{ + // this should generally be zeroed + assert(dst->type() == 0); + // if a primary is provided, make sure it's actually a primary key + assert(!primary_key || primary_key->is_primary()); + // if a pubkey is provided, make sure it's actually a public key + assert(!pubkey || pubkey->is_public()); + // G10 always needs pubkey here + assert(pubkey); + + // this would be better on the stack but the key store does not allow it + std::unique_ptr key_store(new (std::nothrow) rnp_key_store_t(ctx)); + if (!key_store) { + return false; + } + /* Write g10 seckey */ + rnp::MemoryDest memdst(NULL, 0); + if (!g10_write_seckey(&memdst.dst(), newkey, NULL, ctx)) { + RNP_LOG("failed to write generated seckey"); + return false; + } + + std::vector key_ptrs; /* holds primary and pubkey, when used */ + // if this is a subkey, add the primary in first + if (primary_key) { + key_ptrs.push_back(primary_key); + } + // G10 needs the pubkey for copying some attributes (key version, creation time, etc) + key_ptrs.push_back(pubkey); + + rnp::MemorySource memsrc(memdst.memory(), memdst.writeb(), false); + pgp_key_provider_t prov(rnp_key_provider_key_ptr_list, &key_ptrs); + if (!rnp_key_store_g10_from_src(key_store.get(), &memsrc.src(), &prov)) { + return false; + } + if (rnp_key_store_get_key_count(key_store.get()) != 1) { + return false; + } + // if a primary key is provided, it should match the sub with regards to type + assert(!primary_key || (primary_key->is_secret() == key_store->keys.front().is_secret())); + *dst = pgp_key_t(key_store->keys.front()); + return true; +} + +static uint8_t +pk_alg_default_flags(pgp_pubkey_alg_t alg) +{ + // just use the full capabilities as the ultimate fallback + return pgp_pk_alg_capabilities(alg); +} + +// TODO: Similar as pgp_pick_hash_alg but different enough to +// keep another version. This will be changed when refactoring crypto +static void +adjust_hash_alg(rnp_keygen_crypto_params_t &crypto) +{ + if (!crypto.hash_alg) { + crypto.hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0]; + } + + if ((crypto.key_alg != PGP_PKA_DSA) && (crypto.key_alg != PGP_PKA_ECDSA)) { + return; + } + + pgp_hash_alg_t min_hash = (crypto.key_alg == PGP_PKA_ECDSA) ? + ecdsa_get_min_hash(crypto.ecc.curve) : + dsa_get_min_hash(crypto.dsa.q_bitlen); + + if (rnp::Hash::size(crypto.hash_alg) < rnp::Hash::size(min_hash)) { + crypto.hash_alg = min_hash; + } +} + +static void +keygen_merge_crypto_defaults(rnp_keygen_crypto_params_t &crypto) +{ + // default to RSA + if (!crypto.key_alg) { + crypto.key_alg = PGP_PKA_RSA; + } + + switch (crypto.key_alg) { + case PGP_PKA_RSA: + if (!crypto.rsa.modulus_bit_len) { + crypto.rsa.modulus_bit_len = DEFAULT_RSA_NUMBITS; + } + break; + + case PGP_PKA_SM2: + if (!crypto.hash_alg) { + crypto.hash_alg = PGP_HASH_SM3; + } + if (!crypto.ecc.curve) { + crypto.ecc.curve = PGP_CURVE_SM2_P_256; + } + break; + + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: { + if (!crypto.hash_alg) { + crypto.hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0]; + } + break; + } + + case PGP_PKA_EDDSA: + if (!crypto.ecc.curve) { + crypto.ecc.curve = PGP_CURVE_ED25519; + } + break; + + case PGP_PKA_DSA: { + if (!crypto.dsa.p_bitlen) { + crypto.dsa.p_bitlen = DSA_DEFAULT_P_BITLEN; + } + if (!crypto.dsa.q_bitlen) { + crypto.dsa.q_bitlen = dsa_choose_qsize_by_psize(crypto.dsa.p_bitlen); + } + break; + } + default: + break; + } + + adjust_hash_alg(crypto); +} + +static bool +validate_keygen_primary(const rnp_keygen_primary_desc_t &desc) +{ + /* Confirm that the specified pk alg can certify. + * gpg requires this, though the RFC only says that a V4 primary + * key SHOULD be a key capable of certification. + */ + if (!(pgp_pk_alg_capabilities(desc.crypto.key_alg) & PGP_KF_CERTIFY)) { + RNP_LOG("primary key alg (%d) must be able to sign", desc.crypto.key_alg); + return false; + } + + // check key flags + if (!desc.cert.key_flags) { + // these are probably not *technically* required + RNP_LOG("key flags are required"); + return false; + } else if (desc.cert.key_flags & ~pgp_pk_alg_capabilities(desc.crypto.key_alg)) { + // check the flags against the alg capabilities + RNP_LOG("usage not permitted for pk algorithm"); + return false; + } + // require a userid + if (!desc.cert.userid[0]) { + RNP_LOG("userid is required for primary key"); + return false; + } + return true; +} + +static uint32_t +get_numbits(const rnp_keygen_crypto_params_t *crypto) +{ + switch (crypto->key_alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return crypto->rsa.modulus_bit_len; + case PGP_PKA_ECDSA: + case PGP_PKA_ECDH: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: { + if (const ec_curve_desc_t *curve = get_curve_desc(crypto->ecc.curve)) { + return curve->bitlen; + } else { + return 0; + } + } + case PGP_PKA_DSA: + return crypto->dsa.p_bitlen; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return crypto->elgamal.key_bitlen; + default: + return 0; + } +} + +static void +set_default_user_prefs(pgp_user_prefs_t &prefs) +{ + if (prefs.symm_algs.empty()) { + prefs.set_symm_algs( + std::vector(DEFAULT_SYMMETRIC_ALGS, + DEFAULT_SYMMETRIC_ALGS + ARRAY_SIZE(DEFAULT_SYMMETRIC_ALGS))); + } + if (prefs.hash_algs.empty()) { + prefs.set_hash_algs(std::vector( + DEFAULT_HASH_ALGS, DEFAULT_HASH_ALGS + ARRAY_SIZE(DEFAULT_HASH_ALGS))); + } + if (prefs.z_algs.empty()) { + prefs.set_z_algs(std::vector( + DEFAULT_COMPRESS_ALGS, DEFAULT_COMPRESS_ALGS + ARRAY_SIZE(DEFAULT_COMPRESS_ALGS))); + } +} + +static void +keygen_primary_merge_defaults(rnp_keygen_primary_desc_t &desc) +{ + keygen_merge_crypto_defaults(desc.crypto); + set_default_user_prefs(desc.cert.prefs); + + if (!desc.cert.key_flags) { + // set some default key flags if none are provided + desc.cert.key_flags = pk_alg_default_flags(desc.crypto.key_alg); + } + if (desc.cert.userid.empty()) { + char uid[MAX_ID_LENGTH] = {0}; + snprintf(uid, + sizeof(uid), + "%s %d-bit key <%s@localhost>", + id_str_pair::lookup(pubkey_alg_map, desc.crypto.key_alg), + get_numbits(&desc.crypto), + getenv_logname()); + desc.cert.userid = uid; + } +} + +bool +pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, + bool merge_defaults, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_store_format_t secformat) +{ + // validate args + if (primary_sec.type() || primary_pub.type()) { + RNP_LOG("invalid parameters (should be zeroed)"); + return false; + } + + try { + // merge some defaults in, if requested + if (merge_defaults) { + keygen_primary_merge_defaults(desc); + } + // now validate the keygen fields + if (!validate_keygen_primary(desc)) { + return false; + } + + // generate the raw key and fill tag/secret fields + pgp_key_pkt_t secpkt; + if (!pgp_generate_seckey(desc.crypto, secpkt, true)) { + return false; + } + + pgp_key_t sec(secpkt); + pgp_key_t pub(secpkt, true); + sec.add_uid_cert(desc.cert, desc.crypto.hash_alg, *desc.crypto.ctx, &pub); + + switch (secformat) { + case PGP_KEY_STORE_GPG: + case PGP_KEY_STORE_KBX: + primary_sec = std::move(sec); + primary_pub = std::move(pub); + break; + case PGP_KEY_STORE_G10: + primary_pub = std::move(pub); + if (!load_generated_g10_key( + &primary_sec, &secpkt, NULL, &primary_pub, *desc.crypto.ctx)) { + RNP_LOG("failed to load generated key"); + return false; + } + break; + default: + RNP_LOG("invalid format"); + return false; + } + } catch (const std::exception &e) { + RNP_LOG("Failure: %s", e.what()); + return false; + } + + /* mark it as valid */ + primary_pub.mark_valid(); + primary_sec.mark_valid(); + /* refresh key's data */ + return primary_pub.refresh_data(*desc.crypto.ctx) && + primary_sec.refresh_data(*desc.crypto.ctx); +} + +static bool +validate_keygen_subkey(rnp_keygen_subkey_desc_t &desc) +{ + if (!desc.binding.key_flags) { + RNP_LOG("key flags are required"); + return false; + } else if (desc.binding.key_flags & ~pgp_pk_alg_capabilities(desc.crypto.key_alg)) { + // check the flags against the alg capabilities + RNP_LOG("usage not permitted for pk algorithm"); + return false; + } + return true; +} + +static void +keygen_subkey_merge_defaults(rnp_keygen_subkey_desc_t &desc) +{ + keygen_merge_crypto_defaults(desc.crypto); + if (!desc.binding.key_flags) { + // set some default key flags if none are provided + desc.binding.key_flags = pk_alg_default_flags(desc.crypto.key_alg); + } +} + +bool +pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, + bool merge_defaults, + pgp_key_t & primary_sec, + pgp_key_t & primary_pub, + pgp_key_t & subkey_sec, + pgp_key_t & subkey_pub, + const pgp_password_provider_t &password_provider, + pgp_key_store_format_t secformat) +{ + // validate args + if (!primary_sec.is_primary() || !primary_pub.is_primary() || !primary_sec.is_secret() || + !primary_pub.is_public()) { + RNP_LOG("invalid parameters"); + return false; + } + if (subkey_sec.type() || subkey_pub.type()) { + RNP_LOG("invalid parameters (should be zeroed)"); + return false; + } + + // merge some defaults in, if requested + if (merge_defaults) { + keygen_subkey_merge_defaults(desc); + } + + // now validate the keygen fields + if (!validate_keygen_subkey(desc)) { + return false; + } + + try { + /* decrypt the primary seckey if needed (for signatures) */ + rnp::KeyLocker primlock(primary_sec); + if (primary_sec.encrypted() && + !primary_sec.unlock(password_provider, PGP_OP_ADD_SUBKEY)) { + RNP_LOG("Failed to unlock primary key."); + return false; + } + /* generate the raw subkey */ + pgp_key_pkt_t secpkt; + if (!pgp_generate_seckey(desc.crypto, secpkt, false)) { + return false; + } + pgp_key_pkt_t pubpkt = pgp_key_pkt_t(secpkt, true); + pgp_key_t sec(secpkt, primary_sec); + pgp_key_t pub(pubpkt, primary_pub); + /* add binding */ + primary_sec.add_sub_binding( + sec, pub, desc.binding, desc.crypto.hash_alg, *desc.crypto.ctx); + /* copy to the result */ + subkey_pub = std::move(pub); + switch (secformat) { + case PGP_KEY_STORE_GPG: + case PGP_KEY_STORE_KBX: + subkey_sec = std::move(sec); + break; + case PGP_KEY_STORE_G10: + if (!load_generated_g10_key( + &subkey_sec, &secpkt, &primary_sec, &subkey_pub, *desc.crypto.ctx)) { + RNP_LOG("failed to load generated key"); + return false; + } + break; + default: + RNP_LOG("invalid format"); + return false; + } + + subkey_pub.mark_valid(); + subkey_sec.mark_valid(); + return subkey_pub.refresh_data(&primary_pub, *desc.crypto.ctx) && + subkey_sec.refresh_data(&primary_sec, *desc.crypto.ctx); + } catch (const std::exception &e) { + RNP_LOG("Subkey generation failed: %s", e.what()); + return false; + } +} diff --git a/comm/third_party/rnp/src/lib/json-utils.cpp b/comm/third_party/rnp/src/lib/json-utils.cpp new file mode 100644 index 0000000000..742fbc1eeb --- /dev/null +++ b/comm/third_party/rnp/src/lib/json-utils.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "json-utils.h" +#include "logging.h" +#include "crypto/mem.h" + +/* Shortcut function to add field checking it for null to avoid allocation failure. + Please note that it deallocates val on failure. */ +bool +obj_add_field_json(json_object *obj, const char *name, json_object *val) +{ + if (!val) { + return false; + } + // TODO: in JSON-C 0.13 json_object_object_add returns bool instead of void + json_object_object_add(obj, name, val); + if (!json_object_object_get_ex(obj, name, NULL)) { + json_object_put(val); + return false; + } + + return true; +} + +bool +json_add(json_object *obj, const char *name, const char *value) +{ + return obj_add_field_json(obj, name, json_object_new_string(value)); +} + +bool +json_add(json_object *obj, const char *name, bool value) +{ + return obj_add_field_json(obj, name, json_object_new_boolean(value)); +} + +bool +json_add(json_object *obj, const char *name, const char *value, size_t len) +{ + return obj_add_field_json(obj, name, json_object_new_string_len(value, len)); +} + +bool +obj_add_hex_json(json_object *obj, const char *name, const uint8_t *val, size_t val_len) +{ + if (val_len > 1024 * 1024) { + RNP_LOG("too large json hex field: %zu", val_len); + val_len = 1024 * 1024; + } + + char smallbuf[64] = {0}; + size_t hexlen = val_len * 2 + 1; + + char *hexbuf = hexlen < sizeof(smallbuf) ? smallbuf : (char *) malloc(hexlen); + if (!hexbuf) { + return false; + } + + bool res = rnp::hex_encode(val, val_len, hexbuf, hexlen, rnp::HEX_LOWERCASE) && + obj_add_field_json(obj, name, json_object_new_string(hexbuf)); + + if (hexbuf != smallbuf) { + free(hexbuf); + } + return res; +} + +bool +array_add_element_json(json_object *obj, json_object *val) +{ + if (!val) { + return false; + } + if (json_object_array_add(obj, val)) { + json_object_put(val); + return false; + } + return true; +} diff --git a/comm/third_party/rnp/src/lib/json-utils.h b/comm/third_party/rnp/src/lib/json-utils.h new file mode 100644 index 0000000000..c60615b147 --- /dev/null +++ b/comm/third_party/rnp/src/lib/json-utils.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_JSON_UTILS_H_ +#define RNP_JSON_UTILS_H_ + +#include +#include "types.h" +#include +#include "json_object.h" +#include "json.h" + +/** + * @brief Add field to the json object. + * Note: this function is for convenience, it will check val for NULL and destroy val + * on failure. + * @param obj allocated json_object of object type. + * @param name name of the field + * @param val json object of any type. Will be checked for NULL. + * @return true if val is not NULL and field was added successfully, false otherwise. + */ +bool obj_add_field_json(json_object *obj, const char *name, json_object *val); + +/** + * @brief Shortcut to add string via obj_add_field_json(). + */ +bool json_add(json_object *obj, const char *name, const char *value); + +/** + * @brief Shortcut to add string with length via obj_add_field_json(). + */ +bool json_add(json_object *obj, const char *name, const char *value, size_t len); + +/** + * @brief Shortcut to add bool via obj_add_field_json(). + */ +bool json_add(json_object *obj, const char *name, bool value); + +/** + * @brief Add hex representation of binary data as string field to JSON object. + * Note: this function follows conventions of obj_add_field_json(). + */ +bool obj_add_hex_json(json_object *obj, const char *name, const uint8_t *val, size_t val_len); + +/** + * @brief Add element to JSON array. + * Note: this function follows convention of the obj_add_field_json. + */ +bool array_add_element_json(json_object *obj, json_object *val); + +namespace rnp { +class JSONObject { + json_object *obj_; + + public: + JSONObject(json_object *obj) : obj_(obj) + { + } + + ~JSONObject() + { + if (obj_) { + json_object_put(obj_); + } + } +}; +} // namespace rnp + +#endif diff --git a/comm/third_party/rnp/src/lib/key-provider.cpp b/comm/third_party/rnp/src/lib/key-provider.cpp new file mode 100644 index 0000000000..2a64b63329 --- /dev/null +++ b/comm/third_party/rnp/src/lib/key-provider.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "key-provider.h" +#include "pgp-key.h" +#include "fingerprint.h" +#include "types.h" +#include "utils.h" +#include + +bool +rnp_key_matches_search(const pgp_key_t *key, const pgp_key_search_t *search) +{ + if (!key) { + return false; + } + switch (search->type) { + case PGP_KEY_SEARCH_KEYID: + return (key->keyid() == search->by.keyid) || (search->by.keyid == pgp_key_id_t({})); + case PGP_KEY_SEARCH_FINGERPRINT: + return key->fp() == search->by.fingerprint; + case PGP_KEY_SEARCH_GRIP: + return key->grip() == search->by.grip; + case PGP_KEY_SEARCH_USERID: + if (key->has_uid(search->by.userid)) { + return true; + } + break; + default: + assert(false); + break; + } + return false; +} + +pgp_key_t * +pgp_request_key(const pgp_key_provider_t *provider, const pgp_key_request_ctx_t *ctx) +{ + pgp_key_t *key = NULL; + if (!provider || !provider->callback || !ctx) { + return NULL; + } + if (!(key = provider->callback(ctx, provider->userdata))) { + return NULL; + } + // confirm that the key actually matches the search criteria + if (!rnp_key_matches_search(key, &ctx->search) && key->is_secret() == ctx->secret) { + return NULL; + } + return key; +} + +pgp_key_t * +rnp_key_provider_key_ptr_list(const pgp_key_request_ctx_t *ctx, void *userdata) +{ + std::vector *key_list = (std::vector *) userdata; + for (auto key : *key_list) { + if (rnp_key_matches_search(key, &ctx->search) && (key->is_secret() == ctx->secret)) { + return key; + } + } + return NULL; +} + +pgp_key_t * +rnp_key_provider_chained(const pgp_key_request_ctx_t *ctx, void *userdata) +{ + for (pgp_key_provider_t **pprovider = (pgp_key_provider_t **) userdata; + pprovider && *pprovider; + pprovider++) { + pgp_key_provider_t *provider = *pprovider; + pgp_key_t * key = NULL; + if ((key = provider->callback(ctx, provider->userdata))) { + return key; + } + } + return NULL; +} + +pgp_key_t * +rnp_key_provider_store(const pgp_key_request_ctx_t *ctx, void *userdata) +{ + rnp_key_store_t *ks = (rnp_key_store_t *) userdata; + + for (pgp_key_t *key = rnp_key_store_search(ks, &ctx->search, NULL); key; + key = rnp_key_store_search(ks, &ctx->search, key)) { + if (key->is_secret() == ctx->secret) { + return key; + } + } + return NULL; +} diff --git a/comm/third_party/rnp/src/lib/key-provider.h b/comm/third_party/rnp/src/lib/key-provider.h new file mode 100644 index 0000000000..4d09e2f825 --- /dev/null +++ b/comm/third_party/rnp/src/lib/key-provider.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_KEY_PROVIDER_H +#define RNP_KEY_PROVIDER_H + +#include "types.h" +#include "fingerprint.h" + +typedef struct pgp_key_t pgp_key_t; + +typedef enum { + PGP_KEY_SEARCH_UNKNOWN, + PGP_KEY_SEARCH_KEYID, + PGP_KEY_SEARCH_FINGERPRINT, + PGP_KEY_SEARCH_GRIP, + PGP_KEY_SEARCH_USERID +} pgp_key_search_type_t; + +typedef struct pgp_key_search_t { + pgp_key_search_type_t type; + union { + pgp_key_id_t keyid; + pgp_key_grip_t grip; + pgp_fingerprint_t fingerprint; + char userid[MAX_ID_LENGTH + 1]; + } by; + + pgp_key_search_t(pgp_key_search_type_t atype = PGP_KEY_SEARCH_UNKNOWN) : type(atype){}; +} pgp_key_search_t; + +typedef struct pgp_key_request_ctx_t { + pgp_op_t op; + bool secret; + pgp_key_search_t search; + + pgp_key_request_ctx_t(pgp_op_t anop = PGP_OP_UNKNOWN, + bool sec = false, + pgp_key_search_type_t tp = PGP_KEY_SEARCH_UNKNOWN) + : op(anop), secret(sec) + { + search.type = tp; + } +} pgp_key_request_ctx_t; + +typedef pgp_key_t *pgp_key_callback_t(const pgp_key_request_ctx_t *ctx, void *userdata); + +typedef struct pgp_key_provider_t { + pgp_key_callback_t *callback; + void * userdata; + + pgp_key_provider_t(pgp_key_callback_t *cb = NULL, void *ud = NULL) + : callback(cb), userdata(ud){}; +} pgp_key_provider_t; + +/** checks if a key matches search criteria + * + * Note that this does not do any check on the type of key (public/secret), + * that is left up to the caller. + * + * @param key the key to check + * @param search the search criteria to check against + * @return true if the key satisfies the search criteria, false otherwise + **/ +bool rnp_key_matches_search(const pgp_key_t *key, const pgp_key_search_t *search); + +/** @brief request public or secret pgp key, according to information stored in ctx + * @param ctx information about the request - which operation requested the key, which search + * criteria should be used and whether secret or public key is needed + * @param key pointer to the key structure will be stored here on success + * @return a key pointer on success, or NULL if key was not found otherwise + **/ +pgp_key_t *pgp_request_key(const pgp_key_provider_t * provider, + const pgp_key_request_ctx_t *ctx); + +/** key provider callback that searches a list of pgp_key_t pointers + * + * @param ctx + * @param userdata must be a list of key pgp_key_t** + */ +pgp_key_t *rnp_key_provider_key_ptr_list(const pgp_key_request_ctx_t *ctx, void *userdata); + +/** key provider callback that searches a given store + * + * @param ctx + * @param userdata must be a pointer to rnp_key_store_t + */ +pgp_key_t *rnp_key_provider_store(const pgp_key_request_ctx_t *ctx, void *userdata); + +/** key provider that calls other key providers + * + * @param ctx + * @param userdata must be an array pgp_key_provider_t pointers, + * ending with a NULL. + */ +pgp_key_t *rnp_key_provider_chained(const pgp_key_request_ctx_t *ctx, void *userdata); + +#endif diff --git a/comm/third_party/rnp/src/lib/librnp.3.adoc b/comm/third_party/rnp/src/lib/librnp.3.adoc new file mode 100644 index 0000000000..9af84ab9f9 --- /dev/null +++ b/comm/third_party/rnp/src/lib/librnp.3.adoc @@ -0,0 +1,89 @@ += librnp(3) +RNP +:doctype: manpage +:release-version: {component-version} +:man manual: RNP Manual +:man source: RNP {release-version} + +== NAME + +librnp - OpenPGP implementation, available via FFI interface. + +== SYNOPSIS + +*#include * + +*#include * + + +== DESCRIPTION + +*librnp* is part of the *RNP* suite and forms the basis for the _rnp(1)_ and _rnpkeys(1)_ command-line utilities. + +It provides an FFI interface to functions required for operations needed by the OpenPGP protocol. + +Interface to the library is exposed via __ and __ headers. +You will also need to link to _librnp_. + +Please see its headers for the full function list and detailed documentation. + +== EXAMPLES + +A number of examples are provided in *src/examples* folder of the *RNP* suite source tree. + +*generate.c*:: +Demonstrates generation of an OpenPGP keypair using the JSON key description mechanism. +May be used to generate any custom key types that are supported by the *RNP* suite. + +*encrypt.c*:: +Demonstrates how to build OpenPGP-encrypted messages. +A message is encrypted with keys, generated via *./generate*, with a hardcoded password. + +*decrypt.c*:: +Demonstrates how to decrypt OpenPGP messages. +Running this example requires the *./encrypt* example to be first run +in order to produce the sample encrypted message for decryption. + +*sign.c*:: +Demonstrates how to sign OpenPGP messages. +Running this example requires the *./generate* example to be first run +in order to generate and write out secret keys. + +*verify.c*:: +Demonstrates verify OpenPGP signed messages. +Again, running this example requires the *./sign* example to be first run +in order to generate a signed OpenPGP message. + +== BUGS + +Please report _issues_ via the RNP public issue tracker at: +https://github.com/rnpgp/rnp/issues. + +_Security reports_ or _security-sensitive feedback_ should be reported +according to the instructions at: +https://www.rnpgp.org/feedback. + + +== AUTHORS + +*RNP* is an open source project led by Ribose and has +received contributions from numerous individuals and +organizations. + + +== RESOURCES + +*Web site*: https://www.rnpgp.org + +*Source repository*: https://github.com/rnpgp/rnp + + +== COPYING + +Copyright \(C) 2017-2021 Ribose. +The RNP software suite is _freely licensed_: +please refer to the *LICENSE* file for details. + + +== SEE ALSO + +*rnp(1)*, *rnpkeys(1)* diff --git a/comm/third_party/rnp/src/lib/librnp.symbols b/comm/third_party/rnp/src/lib/librnp.symbols new file mode 100644 index 0000000000..d8667cea57 --- /dev/null +++ b/comm/third_party/rnp/src/lib/librnp.symbols @@ -0,0 +1 @@ +_rnp_* diff --git a/comm/third_party/rnp/src/lib/librnp.vsc b/comm/third_party/rnp/src/lib/librnp.vsc new file mode 100644 index 0000000000..460db98583 --- /dev/null +++ b/comm/third_party/rnp/src/lib/librnp.vsc @@ -0,0 +1,4 @@ +{ + global: rnp_*; + local: *; +}; diff --git a/comm/third_party/rnp/src/lib/logging.cpp b/comm/third_party/rnp/src/lib/logging.cpp new file mode 100644 index 0000000000..74c67e3a41 --- /dev/null +++ b/comm/third_party/rnp/src/lib/logging.cpp @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2017-2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "string.h" +#include "logging.h" + +/* -1 -- not initialized + 0 -- logging is off + 1 -- logging is on +*/ +static int8_t _rnp_log_switch = +#ifdef NDEBUG + -1 // lazy-initialize later +#else + 1 // always on in debug build +#endif + ; + +/* Temporary disable logging */ +static size_t _rnp_log_disable = 0; + +void +set_rnp_log_switch(int8_t value) +{ + _rnp_log_switch = value; +} + +bool +rnp_log_switch() +{ + if (_rnp_log_switch < 0) { + const char *var = getenv(RNP_LOG_CONSOLE); + _rnp_log_switch = (var && strcmp(var, "0")) ? 1 : 0; + } + return !_rnp_log_disable && !!_rnp_log_switch; +} + +void +rnp_log_stop() +{ + if (_rnp_log_disable < SIZE_MAX) { + _rnp_log_disable++; + } +} + +void +rnp_log_continue() +{ + if (_rnp_log_disable) { + _rnp_log_disable--; + } +} diff --git a/comm/third_party/rnp/src/lib/logging.h b/comm/third_party/rnp/src/lib/logging.h new file mode 100644 index 0000000000..7335e57483 --- /dev/null +++ b/comm/third_party/rnp/src/lib/logging.h @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2017-2021 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_LOGGING_H_ +#define RNP_LOGGING_H_ + +#include +#include + +/* environment variable name */ +static const char RNP_LOG_CONSOLE[] = "RNP_LOG_CONSOLE"; + +bool rnp_log_switch(); +void set_rnp_log_switch(int8_t); +void rnp_log_stop(); +void rnp_log_continue(); + +namespace rnp { +class LogStop { + bool stop_; + + public: + LogStop(bool stop = true) : stop_(stop) + { + if (stop_) { + rnp_log_stop(); + } + } + ~LogStop() + { + if (stop_) { + rnp_log_continue(); + } + } +}; +} // namespace rnp + +#define RNP_LOG_FD(fd, ...) \ + do { \ + if (!rnp_log_switch()) \ + break; \ + (void) fprintf((fd), "[%s() %s:%d] ", __func__, __FILE__, __LINE__); \ + (void) fprintf((fd), __VA_ARGS__); \ + (void) fprintf((fd), "\n"); \ + } while (0) + +#define RNP_LOG(...) RNP_LOG_FD(stderr, __VA_ARGS__) + +#define RNP_LOG_KEY(msg, key) \ + do { \ + if (!(key)) { \ + RNP_LOG(msg, "(null)"); \ + break; \ + } \ + char keyid[PGP_KEY_ID_SIZE * 2 + 1] = {0}; \ + const pgp_key_id_t &id = key->keyid(); \ + rnp::hex_encode(id.data(), id.size(), keyid, sizeof(keyid), rnp::HEX_LOWERCASE); \ + RNP_LOG(msg, keyid); \ + } while (0) + +#define RNP_LOG_KEY_PKT(msg, key) \ + do { \ + pgp_key_id_t keyid = {}; \ + if (pgp_keyid(keyid, (key))) { \ + RNP_LOG(msg, "unknown"); \ + break; \ + }; \ + char keyidhex[PGP_KEY_ID_SIZE * 2 + 1] = {0}; \ + rnp::hex_encode( \ + keyid.data(), keyid.size(), keyidhex, sizeof(keyidhex), rnp::HEX_LOWERCASE); \ + RNP_LOG(msg, keyidhex); \ + } while (0) + +#endif \ No newline at end of file diff --git a/comm/third_party/rnp/src/lib/pass-provider.cpp b/comm/third_party/rnp/src/lib/pass-provider.cpp new file mode 100644 index 0000000000..788fc23eac --- /dev/null +++ b/comm/third_party/rnp/src/lib/pass-provider.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 - 2019, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "pass-provider.h" +#include +#include + +bool +rnp_password_provider_string(const pgp_password_ctx_t *ctx, + char * password, + size_t password_size, + void * userdata) +{ + char *passc = (char *) userdata; + + if (!passc || strlen(passc) >= (password_size - 1)) { + return false; + } + + strncpy(password, passc, password_size - 1); + return true; +} + +bool +pgp_request_password(const pgp_password_provider_t *provider, + const pgp_password_ctx_t * ctx, + char * password, + size_t password_size) +{ + if (!provider || !provider->callback || !ctx || !password || !password_size) { + return false; + } + return provider->callback(ctx, password, password_size, provider->userdata); +} diff --git a/comm/third_party/rnp/src/lib/pass-provider.h b/comm/third_party/rnp/src/lib/pass-provider.h new file mode 100644 index 0000000000..fd79fc5719 --- /dev/null +++ b/comm/third_party/rnp/src/lib/pass-provider.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017 - 2019, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_PASS_PROVIDER_H +#define RNP_PASS_PROVIDER_H + +#include +#include + +typedef struct pgp_key_t pgp_key_t; + +typedef struct pgp_password_ctx_t { + uint8_t op; + const pgp_key_t *key; + + pgp_password_ctx_t(uint8_t anop, const pgp_key_t *akey = NULL) : op(anop), key(akey){}; +} pgp_password_ctx_t; + +typedef bool pgp_password_callback_t(const pgp_password_ctx_t *ctx, + char * password, + size_t password_size, + void * userdata); + +typedef struct pgp_password_provider_t { + pgp_password_callback_t *callback; + void * userdata; + pgp_password_provider_t(pgp_password_callback_t *cb = NULL, void *ud = NULL) + : callback(cb), userdata(ud){}; +} pgp_password_provider_t; + +bool pgp_request_password(const pgp_password_provider_t *provider, + const pgp_password_ctx_t * ctx, + char * password, + size_t password_size); +bool rnp_password_provider_string(const pgp_password_ctx_t *ctx, + char * password, + size_t password_size, + void * userdata); +#endif diff --git a/comm/third_party/rnp/src/lib/pgp-key.cpp b/comm/third_party/rnp/src/lib/pgp-key.cpp new file mode 100644 index 0000000000..430033158b --- /dev/null +++ b/comm/third_party/rnp/src/lib/pgp-key.cpp @@ -0,0 +1,2776 @@ +/* + * Copyright (c) 2017-2022 [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pgp-key.h" +#include "utils.h" +#include +#include +#include "crypto.h" +#include "crypto/s2k.h" +#include "crypto/mem.h" +#include "crypto/signatures.h" +#include "fingerprint.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "defaults.h" + +pgp_key_pkt_t * +pgp_decrypt_seckey_pgp(const pgp_rawpacket_t &raw, + const pgp_key_pkt_t & pubkey, + const char * password) +{ + try { + rnp::MemorySource src(raw.raw.data(), raw.raw.size(), false); + auto res = std::unique_ptr(new pgp_key_pkt_t()); + if (res->parse(src.src()) || decrypt_secret_key(res.get(), password)) { + return NULL; + } + return res.release(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return NULL; + } +} + +/* Note that this function essentially serves two purposes. + * - In the case of a protected key, it requests a password and + * uses it to decrypt the key and fill in key->key.seckey. + * - In the case of an unprotected key, it simply re-loads + * key->key.seckey by parsing the key data in packets[0]. + */ +pgp_key_pkt_t * +pgp_decrypt_seckey(const pgp_key_t & key, + const pgp_password_provider_t &provider, + const pgp_password_ctx_t & ctx) +{ + // sanity checks + if (!key.is_secret()) { + RNP_LOG("invalid args"); + return NULL; + } + // ask the provider for a password + rnp::secure_array password; + if (key.is_protected() && + !pgp_request_password(&provider, &ctx, password.data(), password.size())) { + return NULL; + } + // attempt to decrypt with the provided password + switch (key.format) { + case PGP_KEY_STORE_GPG: + case PGP_KEY_STORE_KBX: + return pgp_decrypt_seckey_pgp(key.rawpkt(), key.pkt(), password.data()); + case PGP_KEY_STORE_G10: + return g10_decrypt_seckey(key.rawpkt(), key.pkt(), password.data()); + default: + RNP_LOG("unexpected format: %d", key.format); + return NULL; + } +} + +pgp_key_t * +pgp_sig_get_signer(const pgp_subsig_t &sig, rnp_key_store_t *keyring, pgp_key_provider_t *prov) +{ + pgp_key_request_ctx_t ctx(PGP_OP_VERIFY, false, PGP_KEY_SEARCH_UNKNOWN); + /* if we have fingerprint let's check it */ + if (sig.sig.has_keyfp()) { + ctx.search.by.fingerprint = sig.sig.keyfp(); + ctx.search.type = PGP_KEY_SEARCH_FINGERPRINT; + } else if (sig.sig.has_keyid()) { + ctx.search.by.keyid = sig.sig.keyid(); + ctx.search.type = PGP_KEY_SEARCH_KEYID; + } else { + RNP_LOG("No way to search for the signer."); + return NULL; + } + + pgp_key_t *key = rnp_key_store_search(keyring, &ctx.search, NULL); + if (key || !prov) { + return key; + } + return pgp_request_key(prov, &ctx); +} + +static const id_str_pair ss_rr_code_map[] = { + {PGP_REVOCATION_NO_REASON, "No reason specified"}, + {PGP_REVOCATION_SUPERSEDED, "Key is superseded"}, + {PGP_REVOCATION_COMPROMISED, "Key material has been compromised"}, + {PGP_REVOCATION_RETIRED, "Key is retired and no longer used"}, + {PGP_REVOCATION_NO_LONGER_VALID, "User ID information is no longer valid"}, + {0x00, NULL}, +}; + +pgp_key_t * +pgp_key_get_subkey(const pgp_key_t *key, rnp_key_store_t *store, size_t idx) +{ + try { + return rnp_key_store_get_key_by_fpr(store, key->get_subkey_fp(idx)); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return NULL; + } +} + +pgp_key_flags_t +pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_RSA: + return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH | PGP_KF_ENCRYPT); + + case PGP_PKA_RSA_SIGN_ONLY: + // deprecated, but still usable + return PGP_KF_SIGN; + + case PGP_PKA_RSA_ENCRYPT_ONLY: + // deprecated, but still usable + return PGP_KF_ENCRYPT; + + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: /* deprecated */ + // These are no longer permitted per the RFC + return PGP_KF_NONE; + + case PGP_PKA_DSA: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); + + case PGP_PKA_SM2: + return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH | PGP_KF_ENCRYPT); + + case PGP_PKA_ECDH: + case PGP_PKA_ELGAMAL: + return PGP_KF_ENCRYPT; + + default: + RNP_LOG("unknown pk alg: %d\n", alg); + return PGP_KF_NONE; + } +} + +bool +pgp_key_t::write_sec_pgp(pgp_dest_t & dst, + pgp_key_pkt_t & seckey, + const std::string &password, + rnp::RNG & rng) +{ + bool res = false; + pgp_pkt_type_t oldtag = seckey.tag; + + seckey.tag = type(); + if (encrypt_secret_key(&seckey, password.c_str(), rng)) { + goto done; + } + try { + seckey.write(dst); + res = !dst.werr; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } +done: + seckey.tag = oldtag; + return res; +} + +bool +pgp_key_t::write_sec_rawpkt(pgp_key_pkt_t & seckey, + const std::string & password, + rnp::SecurityContext &ctx) +{ + // encrypt+write the key in the appropriate format + try { + rnp::MemoryDest memdst; + switch (format) { + case PGP_KEY_STORE_GPG: + case PGP_KEY_STORE_KBX: + if (!write_sec_pgp(memdst.dst(), seckey, password, ctx.rng)) { + RNP_LOG("failed to write secret key"); + return false; + } + break; + case PGP_KEY_STORE_G10: + if (!g10_write_seckey(&memdst.dst(), &seckey, password.c_str(), ctx)) { + RNP_LOG("failed to write g10 secret key"); + return false; + } + break; + default: + RNP_LOG("invalid format"); + return false; + } + + rawpkt_ = pgp_rawpacket_t((uint8_t *) memdst.memory(), memdst.writeb(), type()); + return true; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +static bool +update_sig_expiration(pgp_signature_t * dst, + const pgp_signature_t *src, + uint64_t create, + uint32_t expiry) +{ + try { + *dst = *src; + if (!expiry) { + dst->remove_subpkt(dst->get_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)); + } else { + dst->set_key_expiration(expiry); + } + dst->set_creation(create); + return true; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +bool +pgp_key_set_expiration(pgp_key_t * key, + pgp_key_t * seckey, + uint32_t expiry, + const pgp_password_provider_t &prov, + rnp::SecurityContext & ctx) +{ + if (!key->is_primary()) { + RNP_LOG("Not a primary key"); + return false; + } + + std::vector sigs; + /* update expiration for the latest direct-key signature and self-signature for each userid + */ + pgp_subsig_t *sig = key->latest_selfsig(PGP_UID_NONE); + if (sig) { + sigs.push_back(sig->sigid); + } + for (size_t uid = 0; uid < key->uid_count(); uid++) { + sig = key->latest_selfsig(uid); + if (sig) { + sigs.push_back(sig->sigid); + } + } + if (sigs.empty()) { + RNP_LOG("No valid self-signature(s)"); + return false; + } + + rnp::KeyLocker seclock(*seckey); + for (const auto &sigid : sigs) { + pgp_subsig_t &sig = key->get_sig(sigid); + /* update signature and re-sign it */ + if (!expiry && !sig.sig.has_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)) { + continue; + } + + /* unlock secret key if needed */ + if (seckey->is_locked() && !seckey->unlock(prov)) { + RNP_LOG("Failed to unlock secret key"); + return false; + } + + pgp_signature_t newsig; + pgp_sig_id_t oldsigid = sigid; + if (!update_sig_expiration(&newsig, &sig.sig, ctx.time(), expiry)) { + return false; + } + try { + if (sig.is_cert()) { + if (sig.uid >= key->uid_count()) { + RNP_LOG("uid not found"); + return false; + } + seckey->sign_cert(key->pkt(), key->get_uid(sig.uid).pkt, newsig, ctx); + } else { + /* direct-key signature case */ + seckey->sign_direct(key->pkt(), newsig, ctx); + } + /* replace signature, first for secret key since it may be replaced in public */ + if (seckey->has_sig(oldsigid)) { + seckey->replace_sig(oldsigid, newsig); + } + if (key != seckey) { + key->replace_sig(oldsigid, newsig); + } + } catch (const std::exception &e) { + RNP_LOG("failed to calculate or add signature: %s", e.what()); + return false; + } + } + + if (!seckey->refresh_data(ctx)) { + RNP_LOG("Failed to refresh seckey data."); + return false; + } + if ((key != seckey) && !key->refresh_data(ctx)) { + RNP_LOG("Failed to refresh key data."); + return false; + } + return true; +} + +bool +pgp_subkey_set_expiration(pgp_key_t * sub, + pgp_key_t * primsec, + pgp_key_t * secsub, + uint32_t expiry, + const pgp_password_provider_t &prov, + rnp::SecurityContext & ctx) +{ + if (!sub->is_subkey()) { + RNP_LOG("Not a subkey"); + return false; + } + + /* find the latest valid subkey binding */ + pgp_subsig_t *subsig = sub->latest_binding(); + if (!subsig) { + RNP_LOG("No valid subkey binding"); + return false; + } + if (!expiry && !subsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)) { + return true; + } + + rnp::KeyLocker primlock(*primsec); + if (primsec->is_locked() && !primsec->unlock(prov)) { + RNP_LOG("Failed to unlock primary key"); + return false; + } + bool subsign = secsub->can_sign(); + rnp::KeyLocker sublock(*secsub); + if (subsign && secsub->is_locked() && !secsub->unlock(prov)) { + RNP_LOG("Failed to unlock subkey"); + return false; + } + + try { + /* update signature and re-sign */ + pgp_signature_t newsig; + pgp_sig_id_t oldsigid = subsig->sigid; + if (!update_sig_expiration(&newsig, &subsig->sig, ctx.time(), expiry)) { + return false; + } + primsec->sign_subkey_binding(*secsub, newsig, ctx); + /* replace signature, first for the secret key since it may be replaced in public */ + if (secsub->has_sig(oldsigid)) { + secsub->replace_sig(oldsigid, newsig); + if (!secsub->refresh_data(primsec, ctx)) { + return false; + } + } + if (sub == secsub) { + return true; + } + sub->replace_sig(oldsigid, newsig); + return sub->refresh_data(primsec, ctx); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +pgp_key_t * +find_suitable_key(pgp_op_t op, + pgp_key_t * key, + pgp_key_provider_t *key_provider, + bool no_primary) +{ + if (!key) { + return NULL; + } + bool secret = false; + switch (op) { + case PGP_OP_ENCRYPT: + break; + case PGP_OP_SIGN: + case PGP_OP_CERTIFY: + secret = true; + break; + default: + RNP_LOG("Unsupported operation: %d", (int) op); + return NULL; + } + /* Return if specified primary key fits our needs */ + if (!no_primary && key->usable_for(op)) { + return key; + } + /* Check for the case when we need to look up for a secret key */ + pgp_key_request_ctx_t ctx(op, secret, PGP_KEY_SEARCH_FINGERPRINT); + if (!no_primary && secret && key->is_public() && key->usable_for(op, true)) { + ctx.search.by.fingerprint = key->fp(); + pgp_key_t *sec = pgp_request_key(key_provider, &ctx); + if (sec && sec->usable_for(op)) { + return sec; + } + } + /* Now look up for subkeys */ + pgp_key_t *subkey = NULL; + for (auto &fp : key->subkey_fps()) { + ctx.search.by.fingerprint = fp; + pgp_key_t *cur = pgp_request_key(key_provider, &ctx); + if (!cur || !cur->usable_for(op)) { + continue; + } + if (!subkey || (cur->creation() > subkey->creation())) { + subkey = cur; + } + } + return subkey; +} + +pgp_hash_alg_t +pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey) +{ + if ((pubkey->alg != PGP_PKA_DSA) && (pubkey->alg != PGP_PKA_ECDSA)) { + return hash; + } + + pgp_hash_alg_t hash_min; + if (pubkey->alg == PGP_PKA_ECDSA) { + hash_min = ecdsa_get_min_hash(pubkey->material.ec.curve); + } else { + hash_min = dsa_get_min_hash(mpi_bits(&pubkey->material.dsa.q)); + } + + if (rnp::Hash::size(hash) < rnp::Hash::size(hash_min)) { + return hash_min; + } + return hash; +} + +static void +bytevec_append_uniq(std::vector &vec, uint8_t val) +{ + if (std::find(vec.begin(), vec.end(), val) == vec.end()) { + vec.push_back(val); + } +} + +void +pgp_user_prefs_t::set_symm_algs(const std::vector &algs) +{ + symm_algs = algs; +} + +void +pgp_user_prefs_t::add_symm_alg(pgp_symm_alg_t alg) +{ + bytevec_append_uniq(symm_algs, alg); +} + +void +pgp_user_prefs_t::set_hash_algs(const std::vector &algs) +{ + hash_algs = algs; +} + +void +pgp_user_prefs_t::add_hash_alg(pgp_hash_alg_t alg) +{ + bytevec_append_uniq(hash_algs, alg); +} + +void +pgp_user_prefs_t::set_z_algs(const std::vector &algs) +{ + z_algs = algs; +} + +void +pgp_user_prefs_t::add_z_alg(pgp_compression_type_t alg) +{ + bytevec_append_uniq(z_algs, alg); +} + +void +pgp_user_prefs_t::set_ks_prefs(const std::vector &prefs) +{ + ks_prefs = prefs; +} + +void +pgp_user_prefs_t::add_ks_pref(pgp_key_server_prefs_t pref) +{ + bytevec_append_uniq(ks_prefs, pref); +} + +pgp_rawpacket_t::pgp_rawpacket_t(const pgp_signature_t &sig) +{ + rnp::MemoryDest dst; + sig.write(dst.dst()); + raw = dst.to_vector(); + tag = PGP_PKT_SIGNATURE; +} + +pgp_rawpacket_t::pgp_rawpacket_t(pgp_key_pkt_t &key) +{ + rnp::MemoryDest dst; + key.write(dst.dst()); + raw = dst.to_vector(); + tag = key.tag; +} + +pgp_rawpacket_t::pgp_rawpacket_t(const pgp_userid_pkt_t &uid) +{ + rnp::MemoryDest dst; + uid.write(dst.dst()); + raw = dst.to_vector(); + tag = uid.tag; +} + +void +pgp_rawpacket_t::write(pgp_dest_t &dst) const +{ + dst_write(&dst, raw.data(), raw.size()); +} + +void +pgp_validity_t::mark_valid() +{ + validated = true; + valid = true; + expired = false; +} + +void +pgp_validity_t::reset() +{ + validated = false; + valid = false; + expired = false; +} + +pgp_subsig_t::pgp_subsig_t(const pgp_signature_t &pkt) +{ + sig = pkt; + sigid = sig.get_id(); + if (sig.has_subpkt(PGP_SIG_SUBPKT_TRUST)) { + trustlevel = sig.trust_level(); + trustamount = sig.trust_amount(); + } + prefs.set_symm_algs(sig.preferred_symm_algs()); + prefs.set_hash_algs(sig.preferred_hash_algs()); + prefs.set_z_algs(sig.preferred_z_algs()); + + if (sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { + key_flags = sig.key_flags(); + } + if (sig.has_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS)) { + prefs.set_ks_prefs({sig.key_server_prefs()}); + } + if (sig.has_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV)) { + prefs.key_server = sig.key_server(); + } + /* add signature rawpacket */ + rawpkt = pgp_rawpacket_t(sig); +} + +bool +pgp_subsig_t::valid() const +{ + return validity.validated && validity.valid && !validity.expired; +} + +bool +pgp_subsig_t::validated() const +{ + return validity.validated; +} + +bool +pgp_subsig_t::is_cert() const +{ + pgp_sig_type_t type = sig.type(); + return (type == PGP_CERT_CASUAL) || (type == PGP_CERT_GENERIC) || + (type == PGP_CERT_PERSONA) || (type == PGP_CERT_POSITIVE); +} + +bool +pgp_subsig_t::expired(uint64_t at) const +{ + /* sig expiration: absence of subpkt or 0 means it never expires */ + uint64_t expiration = sig.expiration(); + if (!expiration) { + return false; + } + return expiration + sig.creation() < at; +} + +pgp_userid_t::pgp_userid_t(const pgp_userid_pkt_t &uidpkt) +{ + /* copy packet data */ + pkt = uidpkt; + rawpkt = pgp_rawpacket_t(uidpkt); + /* populate uid string */ + if (uidpkt.tag == PGP_PKT_USER_ID) { + str = std::string(uidpkt.uid, uidpkt.uid + uidpkt.uid_len); + } else { + str = "(photo)"; + } +} + +size_t +pgp_userid_t::sig_count() const +{ + return sigs_.size(); +} + +const pgp_sig_id_t & +pgp_userid_t::get_sig(size_t idx) const +{ + if (idx >= sigs_.size()) { + throw std::out_of_range("idx"); + } + return sigs_[idx]; +} + +bool +pgp_userid_t::has_sig(const pgp_sig_id_t &id) const +{ + return std::find(sigs_.begin(), sigs_.end(), id) != sigs_.end(); +} + +void +pgp_userid_t::add_sig(const pgp_sig_id_t &sig) +{ + sigs_.push_back(sig); +} + +void +pgp_userid_t::replace_sig(const pgp_sig_id_t &id, const pgp_sig_id_t &newsig) +{ + auto it = std::find(sigs_.begin(), sigs_.end(), id); + if (it == sigs_.end()) { + throw std::invalid_argument("id"); + } + *it = newsig; +} + +bool +pgp_userid_t::del_sig(const pgp_sig_id_t &id) +{ + auto it = std::find(sigs_.begin(), sigs_.end(), id); + if (it == sigs_.end()) { + return false; + } + sigs_.erase(it); + return true; +} + +void +pgp_userid_t::clear_sigs() +{ + sigs_.clear(); +} + +pgp_revoke_t::pgp_revoke_t(pgp_subsig_t &sig) +{ + uid = sig.uid; + sigid = sig.sigid; + if (!sig.sig.has_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON)) { + RNP_LOG("Warning: no revocation reason in the revocation"); + code = PGP_REVOCATION_NO_REASON; + } else { + code = sig.sig.revocation_code(); + reason = sig.sig.revocation_reason(); + } + if (reason.empty()) { + reason = id_str_pair::lookup(ss_rr_code_map, code); + } +} + +pgp_key_t::pgp_key_t(const pgp_key_pkt_t &keypkt) : pkt_(keypkt) +{ + if (!is_key_pkt(pkt_.tag) || !pkt_.material.alg) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + if (pgp_keyid(keyid_, pkt_) || pgp_fingerprint(fingerprint_, pkt_) || + !rnp_key_store_get_key_grip(&pkt_.material, grip_)) { + throw rnp::rnp_exception(RNP_ERROR_GENERIC); + } + + /* parse secret key if not encrypted */ + if (is_secret_key_pkt(pkt_.tag)) { + bool cleartext = pkt_.sec_protection.s2k.usage == PGP_S2KU_NONE; + if (cleartext && decrypt_secret_key(&pkt_, NULL)) { + RNP_LOG("failed to setup key fields"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + /* decryption resets validity */ + pkt_.material.validity = keypkt.material.validity; + } + /* add rawpacket */ + rawpkt_ = pgp_rawpacket_t(pkt_); + format = PGP_KEY_STORE_GPG; +} + +pgp_key_t::pgp_key_t(const pgp_key_pkt_t &pkt, pgp_key_t &primary) : pgp_key_t(pkt) +{ + primary.link_subkey_fp(*this); +} + +pgp_key_t::pgp_key_t(const pgp_key_t &src, bool pubonly) +{ + /* Do some checks for g10 keys */ + if (src.format == PGP_KEY_STORE_G10) { + if (pubonly) { + RNP_LOG("attempt to copy public part from g10 key"); + throw std::invalid_argument("pubonly"); + } + } + + if (pubonly) { + pkt_ = pgp_key_pkt_t(src.pkt_, true); + rawpkt_ = pgp_rawpacket_t(pkt_); + } else { + pkt_ = src.pkt_; + rawpkt_ = src.rawpkt_; + } + + uids_ = src.uids_; + sigs_ = src.sigs_; + sigs_map_ = src.sigs_map_; + keysigs_ = src.keysigs_; + subkey_fps_ = src.subkey_fps_; + primary_fp_set_ = src.primary_fp_set_; + primary_fp_ = src.primary_fp_; + expiration_ = src.expiration_; + flags_ = src.flags_; + keyid_ = src.keyid_; + fingerprint_ = src.fingerprint_; + grip_ = src.grip_; + uid0_ = src.uid0_; + uid0_set_ = src.uid0_set_; + revoked_ = src.revoked_; + revocation_ = src.revocation_; + format = src.format; + validity_ = src.validity_; + valid_till_ = src.valid_till_; +} + +pgp_key_t::pgp_key_t(const pgp_transferable_key_t &src) : pgp_key_t(src.key) +{ + /* add direct-key signatures */ + for (auto &sig : src.signatures) { + add_sig(sig); + } + + /* add userids and their signatures */ + for (auto &uid : src.userids) { + add_uid(uid); + } +} + +pgp_key_t::pgp_key_t(const pgp_transferable_subkey_t &src, pgp_key_t *primary) + : pgp_key_t(src.subkey) +{ + /* add subkey binding signatures */ + for (auto &sig : src.signatures) { + add_sig(sig); + } + + /* setup key grips if primary is available */ + if (primary) { + primary->link_subkey_fp(*this); + } +} + +size_t +pgp_key_t::sig_count() const +{ + return sigs_.size(); +} + +pgp_subsig_t & +pgp_key_t::get_sig(size_t idx) +{ + if (idx >= sigs_.size()) { + throw std::out_of_range("idx"); + } + return get_sig(sigs_[idx]); +} + +const pgp_subsig_t & +pgp_key_t::get_sig(size_t idx) const +{ + if (idx >= sigs_.size()) { + throw std::out_of_range("idx"); + } + return get_sig(sigs_[idx]); +} + +bool +pgp_key_t::has_sig(const pgp_sig_id_t &id) const +{ + return sigs_map_.count(id); +} + +pgp_subsig_t & +pgp_key_t::get_sig(const pgp_sig_id_t &id) +{ + if (!has_sig(id)) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return sigs_map_.at(id); +} + +const pgp_subsig_t & +pgp_key_t::get_sig(const pgp_sig_id_t &id) const +{ + if (!has_sig(id)) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return sigs_map_.at(id); +} + +pgp_subsig_t & +pgp_key_t::replace_sig(const pgp_sig_id_t &id, const pgp_signature_t &newsig) +{ + /* save oldsig's uid */ + size_t uid = get_sig(id).uid; + /* delete first old sig since we may have theoretically the same sigid */ + pgp_sig_id_t oldid = id; + sigs_map_.erase(oldid); + auto &res = sigs_map_.emplace(std::make_pair(newsig.get_id(), newsig)).first->second; + res.uid = uid; + auto it = std::find(sigs_.begin(), sigs_.end(), oldid); + if (it == sigs_.end()) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + *it = res.sigid; + if (uid == PGP_UID_NONE) { + auto it = std::find(keysigs_.begin(), keysigs_.end(), oldid); + if (it == keysigs_.end()) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + *it = res.sigid; + } else { + uids_[uid].replace_sig(oldid, res.sigid); + } + return res; +} + +pgp_subsig_t & +pgp_key_t::add_sig(const pgp_signature_t &sig, size_t uid) +{ + const pgp_sig_id_t sigid = sig.get_id(); + sigs_map_.erase(sigid); + pgp_subsig_t &res = sigs_map_.emplace(std::make_pair(sigid, sig)).first->second; + res.uid = uid; + sigs_.push_back(sigid); + if (uid == PGP_UID_NONE) { + keysigs_.push_back(sigid); + } else { + uids_[uid].add_sig(sigid); + } + return res; +} + +bool +pgp_key_t::del_sig(const pgp_sig_id_t &sigid) +{ + if (!has_sig(sigid)) { + return false; + } + uint32_t uid = get_sig(sigid).uid; + if (uid == PGP_UID_NONE) { + /* signature over the key itself */ + auto it = std::find(keysigs_.begin(), keysigs_.end(), sigid); + if (it != keysigs_.end()) { + keysigs_.erase(it); + } + } else if (uid < uids_.size()) { + /* userid-related signature */ + uids_[uid].del_sig(sigid); + } + auto it = std::find(sigs_.begin(), sigs_.end(), sigid); + if (it != sigs_.end()) { + sigs_.erase(it); + } + return sigs_map_.erase(sigid); +} + +size_t +pgp_key_t::del_sigs(const std::vector &sigs) +{ + /* delete actual signatures */ + size_t res = 0; + for (auto &sig : sigs) { + res += sigs_map_.erase(sig); + } + /* rebuild vectors with signatures order */ + keysigs_.clear(); + for (auto &uid : uids_) { + uid.clear_sigs(); + } + std::vector newsigs; + newsigs.reserve(sigs_map_.size()); + for (auto &sigid : sigs_) { + if (!sigs_map_.count(sigid)) { + continue; + } + newsigs.push_back(sigid); + uint32_t uid = get_sig(sigid).uid; + if (uid == PGP_UID_NONE) { + keysigs_.push_back(sigid); + } else { + uids_[uid].add_sig(sigid); + } + } + sigs_ = std::move(newsigs); + return res; +} + +size_t +pgp_key_t::keysig_count() const +{ + return keysigs_.size(); +} + +pgp_subsig_t & +pgp_key_t::get_keysig(size_t idx) +{ + if (idx >= keysigs_.size()) { + throw std::out_of_range("idx"); + } + return get_sig(keysigs_[idx]); +} + +size_t +pgp_key_t::uid_count() const +{ + return uids_.size(); +} + +pgp_userid_t & +pgp_key_t::get_uid(size_t idx) +{ + if (idx >= uids_.size()) { + throw std::out_of_range("idx"); + } + return uids_[idx]; +} + +const pgp_userid_t & +pgp_key_t::get_uid(size_t idx) const +{ + if (idx >= uids_.size()) { + throw std::out_of_range("idx"); + } + return uids_[idx]; +} + +bool +pgp_key_t::has_uid(const std::string &uidstr) const +{ + for (auto &userid : uids_) { + if (!userid.valid) { + continue; + } + if (userid.str == uidstr) { + return true; + } + } + return false; +} + +void +pgp_key_t::del_uid(size_t idx) +{ + if (idx >= uids_.size()) { + throw std::out_of_range("idx"); + } + + std::vector newsigs; + /* copy sigs which do not belong to uid */ + newsigs.reserve(sigs_.size()); + for (auto &id : sigs_) { + if (get_sig(id).uid == idx) { + sigs_map_.erase(id); + continue; + } + newsigs.push_back(id); + } + sigs_ = newsigs; + uids_.erase(uids_.begin() + idx); + /* update uids */ + if (idx == uids_.size()) { + return; + } + for (auto &sig : sigs_map_) { + if ((sig.second.uid == PGP_UID_NONE) || (sig.second.uid <= idx)) { + continue; + } + sig.second.uid--; + } +} + +bool +pgp_key_t::has_primary_uid() const +{ + return uid0_set_; +} + +uint32_t +pgp_key_t::get_primary_uid() const +{ + if (!uid0_set_) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return uid0_; +} + +pgp_userid_t & +pgp_key_t::add_uid(const pgp_transferable_userid_t &uid) +{ + /* construct userid */ + uids_.emplace_back(uid.uid); + /* add certifications */ + for (auto &sig : uid.signatures) { + add_sig(sig, uid_count() - 1); + } + return uids_.back(); +} + +bool +pgp_key_t::revoked() const +{ + return revoked_; +} + +const pgp_revoke_t & +pgp_key_t::revocation() const +{ + if (!revoked_) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return revocation_; +} + +void +pgp_key_t::clear_revokes() +{ + revoked_ = false; + revocation_ = {}; + for (auto &uid : uids_) { + uid.revoked = false; + uid.revocation = {}; + } +} + +const pgp_key_pkt_t & +pgp_key_t::pkt() const +{ + return pkt_; +} + +pgp_key_pkt_t & +pgp_key_t::pkt() +{ + return pkt_; +} + +void +pgp_key_t::set_pkt(const pgp_key_pkt_t &pkt) +{ + pkt_ = pkt; +} + +pgp_key_material_t & +pgp_key_t::material() +{ + return pkt_.material; +} + +pgp_pubkey_alg_t +pgp_key_t::alg() const +{ + return pkt_.alg; +} + +pgp_curve_t +pgp_key_t::curve() const +{ + switch (alg()) { + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + return pkt_.material.ec.curve; + default: + return PGP_CURVE_UNKNOWN; + } +} + +pgp_version_t +pgp_key_t::version() const +{ + return pkt().version; +} + +pgp_pkt_type_t +pgp_key_t::type() const +{ + return pkt().tag; +} + +bool +pgp_key_t::encrypted() const +{ + return is_secret() && !pkt().material.secret; +} + +uint8_t +pgp_key_t::flags() const +{ + return flags_; +} + +bool +pgp_key_t::can_sign() const +{ + return flags_ & PGP_KF_SIGN; +} + +bool +pgp_key_t::can_certify() const +{ + return flags_ & PGP_KF_CERTIFY; +} + +bool +pgp_key_t::can_encrypt() const +{ + return flags_ & PGP_KF_ENCRYPT; +} + +bool +pgp_key_t::has_secret() const +{ + if (!is_secret()) { + return false; + } + if ((format == PGP_KEY_STORE_GPG) && !pkt_.sec_len) { + return false; + } + if (pkt_.sec_protection.s2k.usage == PGP_S2KU_NONE) { + return true; + } + switch (pkt_.sec_protection.s2k.specifier) { + case PGP_S2KS_SIMPLE: + case PGP_S2KS_SALTED: + case PGP_S2KS_ITERATED_AND_SALTED: + return true; + default: + return false; + } +} + +bool +pgp_key_t::usable_for(pgp_op_t op, bool if_secret) const +{ + switch (op) { + case PGP_OP_ADD_SUBKEY: + return is_primary() && can_sign() && (if_secret || has_secret()); + case PGP_OP_SIGN: + return can_sign() && valid() && (if_secret || has_secret()); + case PGP_OP_CERTIFY: + return can_certify() && valid() && (if_secret || has_secret()); + case PGP_OP_DECRYPT: + return can_encrypt() && valid() && (if_secret || has_secret()); + case PGP_OP_UNLOCK: + case PGP_OP_PROTECT: + case PGP_OP_UNPROTECT: + return has_secret(); + case PGP_OP_VERIFY: + return can_sign() && valid(); + case PGP_OP_ADD_USERID: + return is_primary() && can_sign() && (if_secret || has_secret()); + case PGP_OP_ENCRYPT: + return can_encrypt() && valid(); + default: + return false; + } +} + +uint32_t +pgp_key_t::expiration() const +{ + if (pkt_.version >= 4) { + return expiration_; + } + /* too large value for pkt.v3_days may overflow uint32_t */ + if (pkt_.v3_days > (0xffffffffu / 86400)) { + return 0xffffffffu; + } + return (uint32_t) pkt_.v3_days * 86400; +} + +bool +pgp_key_t::expired() const +{ + return validity_.expired; +} + +uint32_t +pgp_key_t::creation() const +{ + return pkt_.creation_time; +} + +bool +pgp_key_t::is_public() const +{ + return is_public_key_pkt(pkt_.tag); +} + +bool +pgp_key_t::is_secret() const +{ + return is_secret_key_pkt(pkt_.tag); +} + +bool +pgp_key_t::is_primary() const +{ + return is_primary_key_pkt(pkt_.tag); +} + +bool +pgp_key_t::is_subkey() const +{ + return is_subkey_pkt(pkt_.tag); +} + +bool +pgp_key_t::is_locked() const +{ + if (!is_secret()) { + RNP_LOG("key is not a secret key"); + return false; + } + return encrypted(); +} + +bool +pgp_key_t::is_protected() const +{ + // sanity check + if (!is_secret()) { + RNP_LOG("Warning: this is not a secret key"); + } + return pkt_.sec_protection.s2k.usage != PGP_S2KU_NONE; +} + +bool +pgp_key_t::valid() const +{ + return validity_.validated && validity_.valid && !validity_.expired; +} + +bool +pgp_key_t::validated() const +{ + return validity_.validated; +} + +uint64_t +pgp_key_t::valid_till_common(bool expiry) const +{ + if (!validated()) { + return 0; + } + uint64_t till = expiration() ? (uint64_t) creation() + expiration() : UINT64_MAX; + if (valid()) { + return till; + } + if (revoked()) { + /* we should not believe to the compromised key at all */ + if (revocation_.code == PGP_REVOCATION_COMPROMISED) { + return 0; + } + const pgp_subsig_t &revsig = get_sig(revocation_.sigid); + if (revsig.sig.creation() > creation()) { + /* pick less time from revocation time and expiration time */ + return std::min((uint64_t) revsig.sig.creation(), till); + } + return 0; + } + /* if key is not marked as expired then it wasn't valid at all */ + return expiry ? till : 0; +} + +uint64_t +pgp_key_t::valid_till() const +{ + return valid_till_; +} + +bool +pgp_key_t::valid_at(uint64_t timestamp) const +{ + /* TODO: consider implementing more sophisticated checks, as key validity time could + * possibly be non-continuous */ + return (timestamp >= creation()) && timestamp && (timestamp <= valid_till()); +} + +const pgp_key_id_t & +pgp_key_t::keyid() const +{ + return keyid_; +} + +const pgp_fingerprint_t & +pgp_key_t::fp() const +{ + return fingerprint_; +} + +const pgp_key_grip_t & +pgp_key_t::grip() const +{ + return grip_; +} + +const pgp_fingerprint_t & +pgp_key_t::primary_fp() const +{ + if (!primary_fp_set_) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return primary_fp_; +} + +bool +pgp_key_t::has_primary_fp() const +{ + return primary_fp_set_; +} + +void +pgp_key_t::unset_primary_fp() +{ + primary_fp_set_ = false; + primary_fp_ = {}; +} + +void +pgp_key_t::link_subkey_fp(pgp_key_t &subkey) +{ + if (!is_primary() || !subkey.is_subkey()) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + subkey.primary_fp_ = fp(); + subkey.primary_fp_set_ = true; + add_subkey_fp(subkey.fp()); +} + +void +pgp_key_t::add_subkey_fp(const pgp_fingerprint_t &fp) +{ + if (std::find(subkey_fps_.begin(), subkey_fps_.end(), fp) == subkey_fps_.end()) { + subkey_fps_.push_back(fp); + } +} + +size_t +pgp_key_t::subkey_count() const +{ + return subkey_fps_.size(); +} + +void +pgp_key_t::remove_subkey_fp(const pgp_fingerprint_t &fp) +{ + auto it = std::find(subkey_fps_.begin(), subkey_fps_.end(), fp); + if (it != subkey_fps_.end()) { + subkey_fps_.erase(it); + } +} + +const pgp_fingerprint_t & +pgp_key_t::get_subkey_fp(size_t idx) const +{ + return subkey_fps_[idx]; +} + +const std::vector & +pgp_key_t::subkey_fps() const +{ + return subkey_fps_; +} + +size_t +pgp_key_t::rawpkt_count() const +{ + if (format == PGP_KEY_STORE_G10) { + return 1; + } + return 1 + uid_count() + sig_count(); +} + +pgp_rawpacket_t & +pgp_key_t::rawpkt() +{ + return rawpkt_; +} + +const pgp_rawpacket_t & +pgp_key_t::rawpkt() const +{ + return rawpkt_; +} + +void +pgp_key_t::set_rawpkt(const pgp_rawpacket_t &src) +{ + rawpkt_ = src; +} + +bool +pgp_key_t::unlock(const pgp_password_provider_t &provider, pgp_op_t op) +{ + // sanity checks + if (!usable_for(PGP_OP_UNLOCK)) { + return false; + } + // see if it's already unlocked + if (!is_locked()) { + return true; + } + + pgp_password_ctx_t ctx(op, this); + pgp_key_pkt_t * decrypted_seckey = pgp_decrypt_seckey(*this, provider, ctx); + if (!decrypted_seckey) { + return false; + } + + // this shouldn't really be necessary, but just in case + forget_secret_key_fields(&pkt_.material); + // copy the decrypted mpis into the pgp_key_t + pkt_.material = decrypted_seckey->material; + pkt_.material.secret = true; + delete decrypted_seckey; + return true; +} + +bool +pgp_key_t::lock() +{ + // sanity checks + if (!is_secret()) { + RNP_LOG("invalid args"); + return false; + } + + // see if it's already locked + if (is_locked()) { + return true; + } + + forget_secret_key_fields(&pkt_.material); + return true; +} + +bool +pgp_key_t::protect(const rnp_key_protection_params_t &protection, + const pgp_password_provider_t & password_provider, + rnp::SecurityContext & sctx) +{ + pgp_password_ctx_t ctx(PGP_OP_PROTECT, this); + + // ask the provider for a password + rnp::secure_array password; + if (!pgp_request_password(&password_provider, &ctx, password.data(), password.size())) { + return false; + } + return protect(pkt_, protection, password.data(), sctx); +} + +bool +pgp_key_t::protect(pgp_key_pkt_t & decrypted, + const rnp_key_protection_params_t &protection, + const std::string & new_password, + rnp::SecurityContext & ctx) +{ + if (!is_secret()) { + RNP_LOG("Warning: this is not a secret key"); + return false; + } + bool ownpkt = &decrypted == &pkt_; + if (!decrypted.material.secret) { + RNP_LOG("Decrypted secret key must be provided"); + return false; + } + + /* force encrypted-and-hashed and iterated-and-salted as it's the only method we support*/ + pkt_.sec_protection.s2k.usage = PGP_S2KU_ENCRYPTED_AND_HASHED; + pkt_.sec_protection.s2k.specifier = PGP_S2KS_ITERATED_AND_SALTED; + /* use default values where needed */ + pkt_.sec_protection.symm_alg = + protection.symm_alg ? protection.symm_alg : DEFAULT_PGP_SYMM_ALG; + pkt_.sec_protection.cipher_mode = + protection.cipher_mode ? protection.cipher_mode : DEFAULT_PGP_CIPHER_MODE; + pkt_.sec_protection.s2k.hash_alg = + protection.hash_alg ? protection.hash_alg : DEFAULT_PGP_HASH_ALG; + auto iter = protection.iterations; + if (!iter) { + iter = ctx.s2k_iterations(pkt_.sec_protection.s2k.hash_alg); + } + pkt_.sec_protection.s2k.iterations = pgp_s2k_round_iterations(iter); + if (!ownpkt) { + /* decrypted is assumed to be temporary variable so we may modify it */ + decrypted.sec_protection = pkt_.sec_protection; + } + + /* write the protected key to raw packet */ + return write_sec_rawpkt(decrypted, new_password, ctx); +} + +bool +pgp_key_t::unprotect(const pgp_password_provider_t &password_provider, + rnp::SecurityContext & secctx) +{ + /* sanity check */ + if (!is_secret()) { + RNP_LOG("Warning: this is not a secret key"); + return false; + } + /* already unprotected */ + if (!is_protected()) { + return true; + } + /* simple case */ + if (!encrypted()) { + pkt_.sec_protection.s2k.usage = PGP_S2KU_NONE; + return write_sec_rawpkt(pkt_, "", secctx); + } + + pgp_password_ctx_t ctx(PGP_OP_UNPROTECT, this); + + pgp_key_pkt_t *decrypted_seckey = pgp_decrypt_seckey(*this, password_provider, ctx); + if (!decrypted_seckey) { + return false; + } + decrypted_seckey->sec_protection.s2k.usage = PGP_S2KU_NONE; + if (!write_sec_rawpkt(*decrypted_seckey, "", secctx)) { + delete decrypted_seckey; + return false; + } + pkt_ = std::move(*decrypted_seckey); + /* current logic is that unprotected key should be additionally unlocked */ + forget_secret_key_fields(&pkt_.material); + delete decrypted_seckey; + return true; +} + +void +pgp_key_t::write(pgp_dest_t &dst) const +{ + /* write key rawpacket */ + rawpkt_.write(dst); + + if (format == PGP_KEY_STORE_G10) { + return; + } + + /* write signatures on key */ + for (auto &sigid : keysigs_) { + get_sig(sigid).rawpkt.write(dst); + } + + /* write uids and their signatures */ + for (const auto &uid : uids_) { + uid.rawpkt.write(dst); + for (size_t idx = 0; idx < uid.sig_count(); idx++) { + get_sig(uid.get_sig(idx)).rawpkt.write(dst); + } + } +} + +void +pgp_key_t::write_xfer(pgp_dest_t &dst, const rnp_key_store_t *keyring) const +{ + write(dst); + if (dst.werr) { + RNP_LOG("Failed to export primary key"); + return; + } + + if (!keyring) { + return; + } + + // Export subkeys + for (auto &fp : subkey_fps_) { + const pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(keyring, fp); + if (!subkey) { + char fphex[PGP_FINGERPRINT_SIZE * 2 + 1] = {0}; + rnp::hex_encode( + fp.fingerprint, fp.length, fphex, sizeof(fphex), rnp::HEX_LOWERCASE); + RNP_LOG("Warning! Subkey %s not found.", fphex); + continue; + } + subkey->write(dst); + if (dst.werr) { + RNP_LOG("Error occurred when exporting a subkey"); + return; + } + } +} + +bool +pgp_key_t::write_autocrypt(pgp_dest_t &dst, pgp_key_t &sub, uint32_t uid) +{ + pgp_subsig_t *cert = latest_uid_selfcert(uid); + if (!cert) { + RNP_LOG("No valid uid certification"); + return false; + } + pgp_subsig_t *binding = sub.latest_binding(); + if (!binding) { + RNP_LOG("No valid binding for subkey"); + return false; + } + if (is_secret() || sub.is_secret()) { + RNP_LOG("Public key required"); + return false; + } + + try { + /* write all or nothing */ + rnp::MemoryDest memdst; + pkt().write(memdst.dst()); + get_uid(uid).pkt.write(memdst.dst()); + cert->sig.write(memdst.dst()); + sub.pkt().write(memdst.dst()); + binding->sig.write(memdst.dst()); + dst_write(&dst, memdst.memory(), memdst.writeb()); + return !dst.werr; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +/* look only for primary userids */ +#define PGP_UID_PRIMARY ((uint32_t) -2) +/* look for any uid, except PGP_UID_NONE) */ +#define PGP_UID_ANY ((uint32_t) -3) + +pgp_subsig_t * +pgp_key_t::latest_selfsig(uint32_t uid) +{ + uint32_t latest = 0; + pgp_subsig_t *res = nullptr; + + for (auto &sigid : sigs_) { + auto &sig = get_sig(sigid); + if (!sig.valid()) { + continue; + } + bool skip = false; + switch (uid) { + case PGP_UID_NONE: + skip = (sig.uid != PGP_UID_NONE) || !is_direct_self(sig); + break; + case PGP_UID_PRIMARY: { + pgp_sig_subpkt_t *subpkt = sig.sig.get_subpkt(PGP_SIG_SUBPKT_PRIMARY_USER_ID); + skip = !is_self_cert(sig) || !subpkt || !subpkt->fields.primary_uid || + (sig.uid == PGP_UID_NONE); + break; + } + case PGP_UID_ANY: + skip = !is_self_cert(sig) || (sig.uid == PGP_UID_NONE); + break; + default: + skip = (sig.uid != uid) || !is_self_cert(sig); + break; + } + if (skip) { + continue; + } + + uint32_t creation = sig.sig.creation(); + if (creation >= latest) { + latest = creation; + res = &sig; + } + } + + /* if there is later self-sig for the same uid without primary flag, then drop res */ + if ((uid == PGP_UID_PRIMARY) && res) { + pgp_subsig_t *overres = latest_selfsig(res->uid); + if (overres && (overres->sig.creation() > res->sig.creation())) { + res = nullptr; + } + } + return res; +} + +pgp_subsig_t * +pgp_key_t::latest_binding(bool validated) +{ + uint32_t latest = 0; + pgp_subsig_t *res = NULL; + + for (auto &sigid : sigs_) { + auto &sig = get_sig(sigid); + if (validated && !sig.valid()) { + continue; + } + if (!is_binding(sig)) { + continue; + } + + uint32_t creation = sig.sig.creation(); + if (creation >= latest) { + latest = creation; + res = &sig; + } + } + return res; +} + +pgp_subsig_t * +pgp_key_t::latest_uid_selfcert(uint32_t uid) +{ + uint32_t latest = 0; + pgp_subsig_t *res = NULL; + + if (uid >= uids_.size()) { + return NULL; + } + + for (size_t idx = 0; idx < uids_[uid].sig_count(); idx++) { + auto &sig = get_sig(uids_[uid].get_sig(idx)); + if (!sig.valid() || (sig.uid != uid)) { + continue; + } + if (!is_self_cert(sig)) { + continue; + } + + uint32_t creation = sig.sig.creation(); + if (creation >= latest) { + latest = creation; + res = &sig; + } + } + return res; +} + +bool +pgp_key_t::is_signer(const pgp_subsig_t &sig) const +{ + /* if we have fingerprint let's check it */ + if (sig.sig.has_keyfp()) { + return sig.sig.keyfp() == fp(); + } + if (!sig.sig.has_keyid()) { + return false; + } + return keyid() == sig.sig.keyid(); +} + +bool +pgp_key_t::expired_with(const pgp_subsig_t &sig, uint64_t at) const +{ + /* key expiration: absence of subpkt or 0 means it never expires */ + uint64_t expiration = sig.sig.key_expiration(); + if (!expiration) { + return false; + } + return expiration + creation() < at; +} + +bool +pgp_key_t::is_self_cert(const pgp_subsig_t &sig) const +{ + return is_primary() && sig.is_cert() && is_signer(sig); +} + +bool +pgp_key_t::is_direct_self(const pgp_subsig_t &sig) const +{ + return is_primary() && (sig.sig.type() == PGP_SIG_DIRECT) && is_signer(sig); +} + +bool +pgp_key_t::is_revocation(const pgp_subsig_t &sig) const +{ + return is_primary() ? (sig.sig.type() == PGP_SIG_REV_KEY) : + (sig.sig.type() == PGP_SIG_REV_SUBKEY); +} + +bool +pgp_key_t::is_uid_revocation(const pgp_subsig_t &sig) const +{ + return is_primary() && (sig.sig.type() == PGP_SIG_REV_CERT); +} + +bool +pgp_key_t::is_binding(const pgp_subsig_t &sig) const +{ + return is_subkey() && (sig.sig.type() == PGP_SIG_SUBKEY); +} + +void +pgp_key_t::validate_sig(const pgp_key_t & key, + pgp_subsig_t & sig, + const rnp::SecurityContext &ctx) const noexcept +{ + sig.validity.reset(); + + pgp_signature_info_t sinfo = {}; + sinfo.sig = &sig.sig; + sinfo.signer_valid = true; + if (key.is_self_cert(sig) || key.is_binding(sig)) { + sinfo.ignore_expiry = true; + } + + pgp_sig_type_t stype = sig.sig.type(); + try { + switch (stype) { + case PGP_SIG_BINARY: + case PGP_SIG_TEXT: + case PGP_SIG_STANDALONE: + case PGP_SIG_PRIMARY: + RNP_LOG("Invalid key signature type: %d", (int) stype); + return; + case PGP_CERT_GENERIC: + case PGP_CERT_PERSONA: + case PGP_CERT_CASUAL: + case PGP_CERT_POSITIVE: + case PGP_SIG_REV_CERT: { + if (sig.uid >= key.uid_count()) { + RNP_LOG("Userid not found"); + return; + } + validate_cert(sinfo, key.pkt(), key.get_uid(sig.uid).pkt, ctx); + break; + } + case PGP_SIG_SUBKEY: + if (!is_signer(sig)) { + RNP_LOG("Invalid subkey binding's signer."); + return; + } + validate_binding(sinfo, key, ctx); + break; + case PGP_SIG_DIRECT: + case PGP_SIG_REV_KEY: + validate_direct(sinfo, ctx); + break; + case PGP_SIG_REV_SUBKEY: + if (!is_signer(sig)) { + RNP_LOG("Invalid subkey revocation's signer."); + return; + } + validate_sub_rev(sinfo, key.pkt(), ctx); + break; + default: + RNP_LOG("Unsupported key signature type: %d", (int) stype); + return; + } + } catch (const std::exception &e) { + RNP_LOG("Key signature validation failed: %s", e.what()); + } + + sig.validity.validated = true; + sig.validity.valid = sinfo.valid; + /* revocation signature cannot expire */ + if ((stype != PGP_SIG_REV_KEY) && (stype != PGP_SIG_REV_SUBKEY) && + (stype != PGP_SIG_REV_CERT)) { + sig.validity.expired = sinfo.expired; + } +} + +void +pgp_key_t::validate_sig(pgp_signature_info_t & sinfo, + rnp::Hash & hash, + const rnp::SecurityContext &ctx) const noexcept +{ + sinfo.no_signer = false; + sinfo.valid = false; + sinfo.expired = false; + + /* Validate signature itself */ + if (sinfo.signer_valid || valid_at(sinfo.sig->creation())) { + sinfo.valid = !signature_validate(*sinfo.sig, pkt_.material, hash, ctx); + } else { + sinfo.valid = false; + RNP_LOG("invalid or untrusted key"); + } + + /* Check signature's expiration time */ + uint32_t now = ctx.time(); + uint32_t create = sinfo.sig->creation(); + uint32_t expiry = sinfo.sig->expiration(); + if (create > now) { + /* signature created later then now */ + RNP_LOG("signature created %d seconds in future", (int) (create - now)); + sinfo.expired = true; + } + if (create && expiry && (create + expiry < now)) { + /* signature expired */ + RNP_LOG("signature expired"); + sinfo.expired = true; + } + + /* check key creation time vs signature creation */ + if (creation() > create) { + RNP_LOG("key is newer than signature"); + sinfo.valid = false; + } + + /* check whether key was not expired when sig created */ + if (!sinfo.ignore_expiry && expiration() && (creation() + expiration() < create)) { + RNP_LOG("signature made after key expiration"); + sinfo.valid = false; + } + + /* Check signer's fingerprint */ + if (sinfo.sig->has_keyfp() && (sinfo.sig->keyfp() != fp())) { + RNP_LOG("issuer fingerprint doesn't match signer's one"); + sinfo.valid = false; + } + + /* Check for unknown critical notations */ + for (auto &subpkt : sinfo.sig->subpkts) { + if (!subpkt.critical || (subpkt.type != PGP_SIG_SUBPKT_NOTATION_DATA)) { + continue; + } + std::string name(subpkt.fields.notation.name, + subpkt.fields.notation.name + subpkt.fields.notation.nlen); + RNP_LOG("unknown critical notation: %s", name.c_str()); + sinfo.valid = false; + } +} + +void +pgp_key_t::validate_cert(pgp_signature_info_t & sinfo, + const pgp_key_pkt_t & key, + const pgp_userid_pkt_t & uid, + const rnp::SecurityContext &ctx) const +{ + auto hash = signature_hash_certification(*sinfo.sig, key, uid); + validate_sig(sinfo, *hash, ctx); +} + +void +pgp_key_t::validate_binding(pgp_signature_info_t & sinfo, + const pgp_key_t & subkey, + const rnp::SecurityContext &ctx) const +{ + if (!is_primary() || !subkey.is_subkey()) { + RNP_LOG("Invalid binding signature key type(s)"); + sinfo.valid = false; + return; + } + auto hash = signature_hash_binding(*sinfo.sig, pkt(), subkey.pkt()); + validate_sig(sinfo, *hash, ctx); + if (!sinfo.valid || !(sinfo.sig->key_flags() & PGP_KF_SIGN)) { + return; + } + + /* check primary key binding signature if any */ + sinfo.valid = false; + pgp_sig_subpkt_t *subpkt = sinfo.sig->get_subpkt(PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE, false); + if (!subpkt) { + RNP_LOG("error! no primary key binding signature"); + return; + } + if (!subpkt->parsed) { + RNP_LOG("invalid embedded signature subpacket"); + return; + } + if (subpkt->fields.sig->type() != PGP_SIG_PRIMARY) { + RNP_LOG("invalid primary key binding signature"); + return; + } + if (subpkt->fields.sig->version < PGP_V4) { + RNP_LOG("invalid primary key binding signature version"); + return; + } + + hash = signature_hash_binding(*subpkt->fields.sig, pkt(), subkey.pkt()); + pgp_signature_info_t bindinfo = {}; + bindinfo.sig = subpkt->fields.sig; + bindinfo.signer_valid = true; + bindinfo.ignore_expiry = true; + subkey.validate_sig(bindinfo, *hash, ctx); + sinfo.valid = bindinfo.valid && !bindinfo.expired; +} + +void +pgp_key_t::validate_sub_rev(pgp_signature_info_t & sinfo, + const pgp_key_pkt_t & subkey, + const rnp::SecurityContext &ctx) const +{ + auto hash = signature_hash_binding(*sinfo.sig, pkt(), subkey); + validate_sig(sinfo, *hash, ctx); +} + +void +pgp_key_t::validate_direct(pgp_signature_info_t &sinfo, const rnp::SecurityContext &ctx) const +{ + auto hash = signature_hash_direct(*sinfo.sig, pkt()); + validate_sig(sinfo, *hash, ctx); +} + +void +pgp_key_t::validate_self_signatures(const rnp::SecurityContext &ctx) +{ + for (auto &sigid : sigs_) { + pgp_subsig_t &sig = get_sig(sigid); + if (sig.validity.validated) { + continue; + } + + if (is_direct_self(sig) || is_self_cert(sig) || is_uid_revocation(sig) || + is_revocation(sig)) { + validate_sig(*this, sig, ctx); + } + } +} + +void +pgp_key_t::validate_self_signatures(pgp_key_t &primary, const rnp::SecurityContext &ctx) +{ + for (auto &sigid : sigs_) { + pgp_subsig_t &sig = get_sig(sigid); + if (sig.validity.validated) { + continue; + } + + if (is_binding(sig) || is_revocation(sig)) { + primary.validate_sig(*this, sig, ctx); + } + } +} + +void +pgp_key_t::validate_primary(rnp_key_store_t &keyring) +{ + /* validate signatures if needed */ + validate_self_signatures(keyring.secctx); + + /* consider public key as valid on this level if it is not expired and has at least one + * valid self-signature, and is not revoked */ + validity_.reset(); + validity_.validated = true; + bool has_cert = false; + bool has_expired = false; + /* check whether key is revoked */ + for (auto &sigid : sigs_) { + pgp_subsig_t &sig = get_sig(sigid); + if (!sig.valid()) { + continue; + } + if (is_revocation(sig)) { + return; + } + } + /* if we have direct-key signature, then it has higher priority for expiration check */ + uint64_t now = keyring.secctx.time(); + pgp_subsig_t *dirsig = latest_selfsig(PGP_UID_NONE); + if (dirsig) { + has_expired = expired_with(*dirsig, now); + has_cert = !has_expired; + } + /* if we have primary uid and it is more restrictive, then use it as well */ + pgp_subsig_t *prisig = NULL; + if (!has_expired && (prisig = latest_selfsig(PGP_UID_PRIMARY))) { + has_expired = expired_with(*prisig, now); + has_cert = !has_expired; + } + /* if we don't have direct-key sig and primary uid, use the latest self-cert */ + pgp_subsig_t *latest = NULL; + if (!dirsig && !prisig && (latest = latest_selfsig(PGP_UID_ANY))) { + has_expired = expired_with(*latest, now); + has_cert = !has_expired; + } + + /* we have at least one non-expiring key self-signature */ + if (has_cert) { + validity_.valid = true; + return; + } + /* we have valid self-signature which expires key */ + if (has_expired) { + validity_.expired = true; + return; + } + + /* let's check whether key has at least one valid subkey binding */ + for (size_t i = 0; i < subkey_count(); i++) { + pgp_key_t *sub = pgp_key_get_subkey(this, &keyring, i); + if (!sub) { + continue; + } + sub->validate_self_signatures(*this, keyring.secctx); + pgp_subsig_t *sig = sub->latest_binding(); + if (!sig) { + continue; + } + /* check whether subkey is expired - then do not mark key as valid */ + if (sub->expired_with(*sig, now)) { + continue; + } + validity_.valid = true; + return; + } +} + +void +pgp_key_t::validate_subkey(pgp_key_t *primary, const rnp::SecurityContext &ctx) +{ + /* consider subkey as valid on this level if it has valid primary key, has at least one + * non-expired binding signature, and is not revoked. */ + validity_.reset(); + validity_.validated = true; + if (!primary || (!primary->valid() && !primary->expired())) { + return; + } + /* validate signatures if needed */ + validate_self_signatures(*primary, ctx); + + bool has_binding = false; + bool has_expired = false; + for (auto &sigid : sigs_) { + pgp_subsig_t &sig = get_sig(sigid); + if (!sig.valid()) { + continue; + } + + if (is_binding(sig) && !has_binding) { + /* check whether subkey is expired */ + if (expired_with(sig, ctx.time())) { + has_expired = true; + continue; + } + has_binding = true; + } else if (is_revocation(sig)) { + return; + } + } + validity_.valid = has_binding && primary->valid(); + if (!validity_.valid) { + validity_.expired = has_expired; + } +} + +void +pgp_key_t::validate(rnp_key_store_t &keyring) +{ + validity_.reset(); + if (!is_subkey()) { + validate_primary(keyring); + } else { + pgp_key_t *primary = NULL; + if (has_primary_fp()) { + primary = rnp_key_store_get_key_by_fpr(&keyring, primary_fp()); + } + validate_subkey(primary, keyring.secctx); + } +} + +void +pgp_key_t::revalidate(rnp_key_store_t &keyring) +{ + if (is_subkey()) { + pgp_key_t *primary = rnp_key_store_get_primary_key(&keyring, this); + if (primary) { + primary->revalidate(keyring); + } else { + validate_subkey(NULL, keyring.secctx); + } + return; + } + + validate(keyring); + if (!refresh_data(keyring.secctx)) { + RNP_LOG("Failed to refresh key data"); + } + /* validate/re-validate all subkeys as well */ + for (auto &fp : subkey_fps_) { + pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(&keyring, fp); + if (subkey) { + subkey->validate_subkey(this, keyring.secctx); + if (!subkey->refresh_data(this, keyring.secctx)) { + RNP_LOG("Failed to refresh subkey data"); + } + } + } +} + +void +pgp_key_t::mark_valid() +{ + validity_.mark_valid(); + for (size_t i = 0; i < sig_count(); i++) { + get_sig(i).validity.mark_valid(); + } +} + +void +pgp_key_t::sign_init(pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation) const +{ + sig.version = PGP_V4; + sig.halg = pgp_hash_adjust_alg_to_key(hash, &pkt_); + sig.palg = alg(); + sig.set_keyfp(fp()); + sig.set_creation(creation); + sig.set_keyid(keyid()); +} + +void +pgp_key_t::sign_cert(const pgp_key_pkt_t & key, + const pgp_userid_pkt_t &uid, + pgp_signature_t & sig, + rnp::SecurityContext & ctx) +{ + sig.fill_hashed_data(); + auto hash = signature_hash_certification(sig, key, uid); + signature_calculate(sig, pkt_.material, *hash, ctx); +} + +void +pgp_key_t::sign_direct(const pgp_key_pkt_t & key, + pgp_signature_t & sig, + rnp::SecurityContext &ctx) +{ + sig.fill_hashed_data(); + auto hash = signature_hash_direct(sig, key); + signature_calculate(sig, pkt_.material, *hash, ctx); +} + +void +pgp_key_t::sign_binding(const pgp_key_pkt_t & key, + pgp_signature_t & sig, + rnp::SecurityContext &ctx) +{ + sig.fill_hashed_data(); + auto hash = is_primary() ? signature_hash_binding(sig, pkt(), key) : + signature_hash_binding(sig, key, pkt()); + signature_calculate(sig, pkt_.material, *hash, ctx); +} + +void +pgp_key_t::gen_revocation(const pgp_revoke_t & revoke, + pgp_hash_alg_t hash, + const pgp_key_pkt_t & key, + pgp_signature_t & sig, + rnp::SecurityContext &ctx) +{ + sign_init(sig, hash, ctx.time()); + sig.set_type(is_primary_key_pkt(key.tag) ? PGP_SIG_REV_KEY : PGP_SIG_REV_SUBKEY); + sig.set_revocation_reason(revoke.code, revoke.reason); + + if (is_primary_key_pkt(key.tag)) { + sign_direct(key, sig, ctx); + } else { + sign_binding(key, sig, ctx); + } +} + +void +pgp_key_t::sign_subkey_binding(pgp_key_t & sub, + pgp_signature_t & sig, + rnp::SecurityContext &ctx, + bool subsign) +{ + if (!is_primary()) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + sign_binding(sub.pkt(), sig, ctx); + /* add primary key binding subpacket if requested */ + if (subsign) { + pgp_signature_t embsig; + sub.sign_init(embsig, sig.halg, ctx.time()); + embsig.set_type(PGP_SIG_PRIMARY); + sub.sign_binding(pkt(), embsig, ctx); + sig.set_embedded_sig(embsig); + } +} + +void +pgp_key_t::add_uid_cert(rnp_selfsig_cert_info_t &cert, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx, + pgp_key_t * pubkey) +{ + if (cert.userid.empty()) { + /* todo: why not to allow empty uid? */ + RNP_LOG("wrong parameters"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + // userids are only valid for primary keys, not subkeys + if (!is_primary()) { + RNP_LOG("cannot add a userid to a subkey"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + // see if the key already has this userid + if (has_uid(cert.userid)) { + RNP_LOG("key already has this userid"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + // this isn't really valid for this format + if (format == PGP_KEY_STORE_G10) { + RNP_LOG("Unsupported key store type"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + // We only support modifying v4 and newer keys + if (pkt().version < PGP_V4) { + RNP_LOG("adding a userid to V2/V3 key is not supported"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + /* TODO: if key has at least one uid then has_primary_uid() will be always true! */ + if (has_primary_uid() && cert.primary) { + RNP_LOG("changing the primary userid is not supported"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + /* Fill the transferable userid */ + pgp_userid_pkt_t uid; + pgp_signature_t sig; + sign_init(sig, hash, ctx.time()); + cert.populate(uid, sig); + try { + sign_cert(pkt_, uid, sig, ctx); + } catch (const std::exception &e) { + RNP_LOG("Failed to certify: %s", e.what()); + throw; + } + /* add uid and signature to the key and pubkey, if non-NULL */ + uids_.emplace_back(uid); + add_sig(sig, uid_count() - 1); + refresh_data(ctx); + if (!pubkey) { + return; + } + pubkey->uids_.emplace_back(uid); + pubkey->add_sig(sig, pubkey->uid_count() - 1); + pubkey->refresh_data(ctx); +} + +void +pgp_key_t::add_sub_binding(pgp_key_t & subsec, + pgp_key_t & subpub, + const rnp_selfsig_binding_info_t &binding, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx) +{ + if (!is_primary()) { + RNP_LOG("must be called on primary key"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + /* populate signature */ + pgp_signature_t sig; + sign_init(sig, hash, ctx.time()); + sig.set_type(PGP_SIG_SUBKEY); + if (binding.key_expiration) { + sig.set_key_expiration(binding.key_expiration); + } + if (binding.key_flags) { + sig.set_key_flags(binding.key_flags); + } + /* calculate binding */ + pgp_key_flags_t realkf = (pgp_key_flags_t) binding.key_flags; + if (!realkf) { + realkf = pgp_pk_alg_capabilities(subsec.alg()); + } + sign_subkey_binding(subsec, sig, ctx, realkf & PGP_KF_SIGN); + /* add to the secret and public key */ + subsec.add_sig(sig); + subpub.add_sig(sig); +} + +bool +pgp_key_t::refresh_data(const rnp::SecurityContext &ctx) +{ + if (!is_primary()) { + RNP_LOG("key must be primary"); + return false; + } + /* validate self-signatures if not done yet */ + validate_self_signatures(ctx); + /* key expiration */ + expiration_ = 0; + /* if we have direct-key signature, then it has higher priority */ + pgp_subsig_t *dirsig = latest_selfsig(PGP_UID_NONE); + if (dirsig) { + expiration_ = dirsig->sig.key_expiration(); + } + /* if we have primary uid and it is more restrictive, then use it as well */ + pgp_subsig_t *prisig = latest_selfsig(PGP_UID_PRIMARY); + if (prisig && prisig->sig.key_expiration() && + (!expiration_ || (prisig->sig.key_expiration() < expiration_))) { + expiration_ = prisig->sig.key_expiration(); + } + /* if we don't have direct-key sig and primary uid, use the latest self-cert */ + pgp_subsig_t *latest = latest_selfsig(PGP_UID_ANY); + if (!dirsig && !prisig && latest) { + expiration_ = latest->sig.key_expiration(); + } + /* key flags: check in direct-key sig first, then primary uid, and then latest */ + if (dirsig && dirsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { + flags_ = dirsig->key_flags; + } else if (prisig && prisig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { + flags_ = prisig->key_flags; + } else if (latest && latest->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { + flags_ = latest->key_flags; + } else { + flags_ = pgp_pk_alg_capabilities(alg()); + } + /* revocation(s) */ + clear_revokes(); + for (size_t i = 0; i < sig_count(); i++) { + pgp_subsig_t &sig = get_sig(i); + if (!sig.valid()) { + continue; + } + try { + if (is_revocation(sig)) { + if (revoked_) { + continue; + } + revoked_ = true; + revocation_ = pgp_revoke_t(sig); + } else if (is_uid_revocation(sig)) { + if (sig.uid >= uid_count()) { + RNP_LOG("Invalid uid index"); + continue; + } + pgp_userid_t &uid = get_uid(sig.uid); + if (uid.revoked) { + continue; + } + uid.revoked = true; + uid.revocation = pgp_revoke_t(sig); + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + } + /* valid till */ + valid_till_ = valid_till_common(expired()); + /* userid validities */ + for (size_t i = 0; i < uid_count(); i++) { + get_uid(i).valid = false; + } + for (size_t i = 0; i < sig_count(); i++) { + pgp_subsig_t &sig = get_sig(i); + /* consider userid as valid if it has at least one non-expired self-sig */ + if (!sig.valid() || !sig.is_cert() || !is_signer(sig) || sig.expired(ctx.time())) { + continue; + } + if (sig.uid >= uid_count()) { + continue; + } + get_uid(sig.uid).valid = true; + } + /* check whether uid is revoked */ + for (size_t i = 0; i < uid_count(); i++) { + pgp_userid_t &uid = get_uid(i); + if (uid.revoked) { + uid.valid = false; + } + } + /* primary userid: use latest one which is not overridden by later non-primary selfsig */ + uid0_set_ = false; + if (prisig && get_uid(prisig->uid).valid) { + uid0_ = prisig->uid; + uid0_set_ = true; + } + return true; +} + +bool +pgp_key_t::refresh_data(pgp_key_t *primary, const rnp::SecurityContext &ctx) +{ + /* validate self-signatures if not done yet */ + if (primary) { + validate_self_signatures(*primary, ctx); + } + pgp_subsig_t *sig = latest_binding(primary); + /* subkey expiration */ + expiration_ = sig ? sig->sig.key_expiration() : 0; + /* subkey flags */ + if (sig && sig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) { + flags_ = sig->key_flags; + } else { + flags_ = pgp_pk_alg_capabilities(alg()); + } + /* revocation */ + clear_revokes(); + for (size_t i = 0; i < sig_count(); i++) { + pgp_subsig_t &sig = get_sig(i); + if (!sig.valid() || !is_revocation(sig)) { + continue; + } + revoked_ = true; + try { + revocation_ = pgp_revoke_t(sig); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + break; + } + /* valid till */ + if (primary) { + valid_till_ = + std::min(primary->valid_till(), valid_till_common(expired() || primary->expired())); + } else { + valid_till_ = valid_till_common(expired()); + } + return true; +} + +void +pgp_key_t::merge_validity(const pgp_validity_t &src) +{ + validity_.valid = validity_.valid && src.valid; + /* We may safely leave validated status only if both merged keys are valid && validated. + * Otherwise we'll need to revalidate. For instance, one validated but invalid key may add + * revocation signature, or valid key may add certification to the invalid one. */ + validity_.validated = validity_.valid && validity_.validated && src.validated; + /* if expired is true at least in one case then valid and validated are false */ + validity_.expired = false; +} + +bool +pgp_key_t::merge(const pgp_key_t &src) +{ + if (is_subkey() || src.is_subkey()) { + RNP_LOG("wrong key merge call"); + return false; + } + + pgp_transferable_key_t dstkey; + if (transferable_key_from_key(dstkey, *this)) { + RNP_LOG("failed to get transferable key from dstkey"); + return false; + } + + pgp_transferable_key_t srckey; + if (transferable_key_from_key(srckey, src)) { + RNP_LOG("failed to get transferable key from srckey"); + return false; + } + + /* if src is secret key then merged key will become secret as well. */ + if (is_secret_key_pkt(srckey.key.tag) && !is_secret_key_pkt(dstkey.key.tag)) { + pgp_key_pkt_t tmp = dstkey.key; + dstkey.key = srckey.key; + srckey.key = tmp; + /* no subkey processing here - they are separated from the main key */ + } + + if (transferable_key_merge(dstkey, srckey)) { + RNP_LOG("failed to merge transferable keys"); + return false; + } + + pgp_key_t tmpkey; + try { + tmpkey = std::move(dstkey); + for (auto &fp : subkey_fps()) { + tmpkey.add_subkey_fp(fp); + } + for (auto &fp : src.subkey_fps()) { + tmpkey.add_subkey_fp(fp); + } + } catch (const std::exception &e) { + RNP_LOG("failed to process key/add subkey fps: %s", e.what()); + return false; + } + /* check whether key was unlocked and assign secret key data */ + if (is_secret() && !is_locked()) { + /* we may do thing below only because key material is opaque structure without + * pointers! */ + tmpkey.pkt().material = pkt().material; + } else if (src.is_secret() && !src.is_locked()) { + tmpkey.pkt().material = src.pkt().material; + } + /* copy validity status */ + tmpkey.validity_ = validity_; + tmpkey.merge_validity(src.validity_); + + *this = std::move(tmpkey); + return true; +} + +bool +pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) +{ + if (!is_subkey() || !src.is_subkey()) { + RNP_LOG("wrong subkey merge call"); + return false; + } + + pgp_transferable_subkey_t dstkey; + if (transferable_subkey_from_key(dstkey, *this)) { + RNP_LOG("failed to get transferable key from dstkey"); + return false; + } + + pgp_transferable_subkey_t srckey; + if (transferable_subkey_from_key(srckey, src)) { + RNP_LOG("failed to get transferable key from srckey"); + return false; + } + + /* if src is secret key then merged key will become secret as well. */ + if (is_secret_key_pkt(srckey.subkey.tag) && !is_secret_key_pkt(dstkey.subkey.tag)) { + pgp_key_pkt_t tmp = dstkey.subkey; + dstkey.subkey = srckey.subkey; + srckey.subkey = tmp; + } + + if (transferable_subkey_merge(dstkey, srckey)) { + RNP_LOG("failed to merge transferable subkeys"); + return false; + } + + pgp_key_t tmpkey; + try { + tmpkey = pgp_key_t(dstkey, primary); + } catch (const std::exception &e) { + RNP_LOG("failed to process subkey: %s", e.what()); + return false; + } + + /* check whether key was unlocked and assign secret key data */ + if (is_secret() && !is_locked()) { + /* we may do thing below only because key material is opaque structure without + * pointers! */ + tmpkey.pkt().material = pkt().material; + } else if (src.is_secret() && !src.is_locked()) { + tmpkey.pkt().material = src.pkt().material; + } + /* copy validity status */ + tmpkey.validity_ = validity_; + tmpkey.merge_validity(src.validity_); + + *this = std::move(tmpkey); + return true; +} + +size_t +pgp_key_material_t::bits() const +{ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return 8 * mpi_bytes(&rsa.n); + case PGP_PKA_DSA: + return 8 * mpi_bytes(&dsa.p); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return 8 * mpi_bytes(&eg.y); + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: { + // bn_num_bytes returns value <= curve order + const ec_curve_desc_t *curve = get_curve_desc(ec.curve); + return curve ? curve->bitlen : 0; + } + default: + RNP_LOG("Unknown public key alg: %d", (int) alg); + return 0; + } +} + +size_t +pgp_key_material_t::qbits() const +{ + if (alg != PGP_PKA_DSA) { + return 0; + } + return 8 * mpi_bytes(&dsa.q); +} + +void +pgp_key_material_t::validate(rnp::SecurityContext &ctx, bool reset) +{ + if (!reset && validity.validated) { + return; + } + validity.reset(); + validity.valid = !validate_pgp_key_material(this, &ctx.rng); + validity.validated = true; +} + +bool +pgp_key_material_t::valid() const +{ + return validity.validated && validity.valid; +} diff --git a/comm/third_party/rnp/src/lib/pgp-key.h b/comm/third_party/rnp/src/lib/pgp-key.h new file mode 100644 index 0000000000..aa088bb47b --- /dev/null +++ b/comm/third_party/rnp/src/lib/pgp-key.h @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2017-2021 [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RNP_PACKET_KEY_H +#define RNP_PACKET_KEY_H + +#include +#include +#include +#include +#include "pass-provider.h" +#include "../librepgp/stream-key.h" +#include +#include "../librepgp/stream-packet.h" +#include "crypto/symmetric.h" +#include "types.h" +#include "sec_profile.hpp" + +/** pgp_rawpacket_t */ +typedef struct pgp_rawpacket_t { + pgp_pkt_type_t tag; + std::vector raw; + + pgp_rawpacket_t() = default; + pgp_rawpacket_t(const uint8_t *data, size_t len, pgp_pkt_type_t tag) + : tag(tag), + raw(data ? std::vector(data, data + len) : std::vector()){}; + pgp_rawpacket_t(const pgp_signature_t &sig); + pgp_rawpacket_t(pgp_key_pkt_t &key); + pgp_rawpacket_t(const pgp_userid_pkt_t &uid); + + void write(pgp_dest_t &dst) const; +} pgp_rawpacket_t; + +/** information about the signature */ +typedef struct pgp_subsig_t { + uint32_t uid{}; /* index in userid array in key for certification sig */ + pgp_signature_t sig{}; /* signature packet */ + pgp_sig_id_t sigid{}; /* signature identifier */ + pgp_rawpacket_t rawpkt{}; /* signature's rawpacket */ + uint8_t trustlevel{}; /* level of trust */ + uint8_t trustamount{}; /* amount of trust */ + uint8_t key_flags{}; /* key flags for certification/direct key sig */ + pgp_user_prefs_t prefs{}; /* user preferences for certification sig */ + pgp_validity_t validity{}; /* signature validity information */ + + pgp_subsig_t() = delete; + pgp_subsig_t(const pgp_signature_t &sig); + + bool validated() const; + bool valid() const; + /** @brief Returns true if signature is certification */ + bool is_cert() const; + /** @brief Returns true if signature is expired */ + bool expired(uint64_t at) const; +} pgp_subsig_t; + +typedef std::unordered_map pgp_sig_map_t; + +/* userid, built on top of userid packet structure */ +typedef struct pgp_userid_t { + private: + std::vector sigs_{}; /* all signatures related to this userid */ + public: + pgp_userid_pkt_t pkt{}; /* User ID or User Attribute packet as it was loaded */ + pgp_rawpacket_t rawpkt{}; /* Raw packet contents */ + std::string str{}; /* Human-readable representation of the userid */ + bool valid{}; /* User ID is valid, i.e. has valid, non-expired self-signature */ + bool revoked{}; + pgp_revoke_t revocation{}; + + pgp_userid_t(const pgp_userid_pkt_t &pkt); + + size_t sig_count() const; + const pgp_sig_id_t &get_sig(size_t idx) const; + bool has_sig(const pgp_sig_id_t &id) const; + void add_sig(const pgp_sig_id_t &sig); + void replace_sig(const pgp_sig_id_t &id, const pgp_sig_id_t &newsig); + bool del_sig(const pgp_sig_id_t &id); + void clear_sigs(); +} pgp_userid_t; + +#define PGP_UID_NONE ((uint32_t) -1) + +typedef struct rnp_key_store_t rnp_key_store_t; + +/* describes a user's key */ +struct pgp_key_t { + private: + pgp_sig_map_t sigs_map_{}; /* map with subsigs stored by their id */ + std::vector sigs_{}; /* subsig ids to lookup actual sig in map */ + std::vector keysigs_{}; /* direct-key signature ids in the original order */ + std::vector uids_{}; /* array of user ids */ + pgp_key_pkt_t pkt_{}; /* pubkey/seckey data packet */ + uint8_t flags_{}; /* key flags */ + uint32_t expiration_{}; /* key expiration time, if available */ + pgp_key_id_t keyid_{}; + pgp_fingerprint_t fingerprint_{}; + pgp_key_grip_t grip_{}; + pgp_fingerprint_t primary_fp_{}; /* fingerprint of the primary key (for subkeys) */ + bool primary_fp_set_{}; + std::vector + subkey_fps_{}; /* array of subkey fingerprints (for primary keys) */ + pgp_rawpacket_t rawpkt_{}; /* key raw packet */ + uint32_t uid0_{}; /* primary uid index in uids array */ + bool uid0_set_{}; /* flag for the above */ + bool revoked_{}; /* key has been revoked */ + pgp_revoke_t revocation_{}; /* revocation reason */ + pgp_validity_t validity_{}; /* key's validity */ + uint64_t valid_till_{}; /* date till which key is/was valid */ + + pgp_subsig_t *latest_uid_selfcert(uint32_t uid); + void validate_primary(rnp_key_store_t &keyring); + void merge_validity(const pgp_validity_t &src); + uint64_t valid_till_common(bool expiry) const; + bool write_sec_pgp(pgp_dest_t & dst, + pgp_key_pkt_t & seckey, + const std::string &password, + rnp::RNG & rng); + + public: + pgp_key_store_format_t format{}; /* the format of the key in packets[0] */ + + pgp_key_t() = default; + pgp_key_t(const pgp_key_pkt_t &pkt); + pgp_key_t(const pgp_key_pkt_t &pkt, pgp_key_t &primary); + pgp_key_t(const pgp_key_t &src, bool pubonly = false); + pgp_key_t(const pgp_transferable_key_t &src); + pgp_key_t(const pgp_transferable_subkey_t &src, pgp_key_t *primary); + pgp_key_t &operator=(const pgp_key_t &) = default; + pgp_key_t &operator=(pgp_key_t &&) = default; + + size_t sig_count() const; + pgp_subsig_t & get_sig(size_t idx); + const pgp_subsig_t &get_sig(size_t idx) const; + bool has_sig(const pgp_sig_id_t &id) const; + pgp_subsig_t & replace_sig(const pgp_sig_id_t &id, const pgp_signature_t &newsig); + pgp_subsig_t & get_sig(const pgp_sig_id_t &id); + const pgp_subsig_t &get_sig(const pgp_sig_id_t &id) const; + pgp_subsig_t & add_sig(const pgp_signature_t &sig, size_t uid = PGP_UID_NONE); + bool del_sig(const pgp_sig_id_t &sigid); + size_t del_sigs(const std::vector &sigs); + size_t keysig_count() const; + pgp_subsig_t & get_keysig(size_t idx); + size_t uid_count() const; + pgp_userid_t & get_uid(size_t idx); + const pgp_userid_t &get_uid(size_t idx) const; + pgp_userid_t & add_uid(const pgp_transferable_userid_t &uid); + bool has_uid(const std::string &uid) const; + void del_uid(size_t idx); + bool has_primary_uid() const; + uint32_t get_primary_uid() const; + bool revoked() const; + const pgp_revoke_t &revocation() const; + void clear_revokes(); + + const pgp_key_pkt_t &pkt() const; + pgp_key_pkt_t & pkt(); + void set_pkt(const pgp_key_pkt_t &pkt); + + pgp_key_material_t &material(); + + pgp_pubkey_alg_t alg() const; + pgp_curve_t curve() const; + pgp_version_t version() const; + pgp_pkt_type_t type() const; + bool encrypted() const; + uint8_t flags() const; + bool can_sign() const; + bool can_certify() const; + bool can_encrypt() const; + bool has_secret() const; + /** + * @brief Check whether key is usable for the specified operation. + * + * @param op operation to check. + * @param if_secret check whether secret part of this key could be usable for op. + * @return true if key (or corresponding secret key) is usable or false otherwise. + */ + bool usable_for(pgp_op_t op, bool if_secret = false) const; + /** @brief Get key's expiration time in seconds. If 0 then it doesn't expire. */ + uint32_t expiration() const; + /** @brief Check whether key is expired. Must be validated before that. */ + bool expired() const; + /** @brief Get key's creation time in seconds since Jan, 1 1970. */ + uint32_t creation() const; + bool is_public() const; + bool is_secret() const; + bool is_primary() const; + bool is_subkey() const; + /** @brief check if a key is currently locked, i.e. secret fields are not decrypted. + * Note: Key locking does not apply to unprotected keys. + */ + bool is_locked() const; + /** @brief check if a key is currently protected, i.e. its secret data is encrypted */ + bool is_protected() const; + + bool valid() const; + bool validated() const; + /** @brief return time till which key is considered to be valid */ + uint64_t valid_till() const; + /** @brief check whether key was/will be valid at the specified time */ + bool valid_at(uint64_t timestamp) const; + + /** @brief Get key's id */ + const pgp_key_id_t &keyid() const; + /** @brief Get key's fingerprint */ + const pgp_fingerprint_t &fp() const; + /** @brief Get key's grip */ + const pgp_key_grip_t &grip() const; + /** @brief Get primary key's fingerprint for the subkey, if it is available. + * Note: will throw if it is not available, use has_primary_fp() to check. + */ + const pgp_fingerprint_t &primary_fp() const; + /** @brief Check whether key has primary key's fingerprint */ + bool has_primary_fp() const; + /** @brief Clean primary_fp */ + void unset_primary_fp(); + /** @brief Link key with subkey via primary_fp and subkey_fps list */ + void link_subkey_fp(pgp_key_t &subkey); + /** + * @brief Add subkey fp to key's list. + * Note: this function will check for duplicates. + */ + void add_subkey_fp(const pgp_fingerprint_t &fp); + /** @brief Get the number of pgp key's subkeys. */ + size_t subkey_count() const; + /** @brief Remove subkey fingerprint from key's list. */ + void remove_subkey_fp(const pgp_fingerprint_t &fp); + /** + * @brief Get the pgp key's subkey fingerprint + * @return fingerprint or throws std::out_of_range exception + */ + const pgp_fingerprint_t & get_subkey_fp(size_t idx) const; + const std::vector &subkey_fps() const; + + size_t rawpkt_count() const; + pgp_rawpacket_t & rawpkt(); + const pgp_rawpacket_t &rawpkt() const; + void set_rawpkt(const pgp_rawpacket_t &src); + /** @brief write secret key data to the rawpkt, optionally encrypting with password */ + bool write_sec_rawpkt(pgp_key_pkt_t & seckey, + const std::string & password, + rnp::SecurityContext &ctx); + + /** @brief Unlock a key, i.e. decrypt its secret data so it can be used for + * signing/decryption. + * Note: Key locking does not apply to unprotected keys. + * + * @param pass_provider the password provider that may be used to unlock the key + * @param op operation for which secret key should be unloacked + * @return true if the key was unlocked, false otherwise + **/ + bool unlock(const pgp_password_provider_t &provider, pgp_op_t op = PGP_OP_UNLOCK); + /** @brief Lock a key, i.e. cleanup decrypted secret data. + * Note: Key locking does not apply to unprotected keys. + * + * @param key the key + * @return true if the key was locked, false otherwise + **/ + bool lock(); + /** @brief Add protection to an unlocked key, i.e. encrypt its secret data with specified + * parameters. */ + bool protect(const rnp_key_protection_params_t &protection, + const pgp_password_provider_t & password_provider, + rnp::SecurityContext & ctx); + /** @brief Add/change protection of a key */ + bool protect(pgp_key_pkt_t & decrypted, + const rnp_key_protection_params_t &protection, + const std::string & new_password, + rnp::SecurityContext & ctx); + /** @brief Remove protection from a key, i.e. leave secret fields unencrypted */ + bool unprotect(const pgp_password_provider_t &password_provider, + rnp::SecurityContext & ctx); + + /** @brief Write key's packets to the output. */ + void write(pgp_dest_t &dst) const; + /** + * @brief Write OpenPGP key packets (including subkeys) to the specified stream + * + * @param dst stream to write packets + * @param keyring keyring, which will be searched for subkeys. Pass NULL to skip subkeys. + * @return void, but error may be checked via dst.werr + */ + void write_xfer(pgp_dest_t &dst, const rnp_key_store_t *keyring = NULL) const; + /** + * @brief Export key with subkey as it is required by Autocrypt (5-packet sequence: key, + * uid, sig, subkey, sig). + * + * @param dst stream to write packets + * @param sub subkey + * @param uid index of uid to export + * @return true on success or false otherwise + */ + bool write_autocrypt(pgp_dest_t &dst, pgp_key_t &sub, uint32_t uid); + + /** + * @brief Get the latest valid self-signature with information about the primary key for + * the specified uid (including the special cases). It could be userid certification + * or direct-key signature. + * + * @param uid uid for which latest self-signature should be returned, + * PGP_UID_NONE for direct-key signature, + * PGP_UID_PRIMARY for any primary key, + * PGP_UID_ANY for any uid. + * @return pointer to signature object or NULL if failed/not found. + */ + pgp_subsig_t *latest_selfsig(uint32_t uid); + + /** + * @brief Get the latest valid subkey binding. Should be called on subkey. + * + * @param validated set to true whether binding signature must be validated + * @return pointer to signature object or NULL if failed/not found. + */ + pgp_subsig_t *latest_binding(bool validated = true); + + /** @brief Returns true if signature is produced by the key itself. */ + bool is_signer(const pgp_subsig_t &sig) const; + + /** @brief Returns true if key is expired according to sig. */ + bool expired_with(const pgp_subsig_t &sig, uint64_t at) const; + + /** @brief Check whether signature is key's self certification. */ + bool is_self_cert(const pgp_subsig_t &sig) const; + + /** @brief Check whether signature is key's direct-key self-signature */ + bool is_direct_self(const pgp_subsig_t &sig) const; + + /** @brief Check whether signature is key's/subkey's revocation */ + bool is_revocation(const pgp_subsig_t &sig) const; + + /** @brief Check whether signature is userid revocation */ + bool is_uid_revocation(const pgp_subsig_t &sig) const; + + /** @brief Check whether signature is subkey binding */ + bool is_binding(const pgp_subsig_t &sig) const; + + /** + * @brief Validate key's signature, assuming that 'this' is a signing key. + * + * @param key key or subkey to which signature belongs. + * @param sig signature to validate. + * @param ctx Populated security context. + */ + void validate_sig(const pgp_key_t & key, + pgp_subsig_t & sig, + const rnp::SecurityContext &ctx) const noexcept; + + /** + * @brief Validate signature, assuming that 'this' is a signing key. + * + * @param sinfo populated signature info. Validation results will be stored here. + * @param hash hash, feed with all signed data except signature trailer. + * @param ctx Populated security context. + */ + void validate_sig(pgp_signature_info_t & sinfo, + rnp::Hash & hash, + const rnp::SecurityContext &ctx) const noexcept; + + /** + * @brief Validate certification. + * + * @param sinfo populated signature info. Validation results will be stored here. + * @param key key packet to which certification belongs. + * @param uid userid which is bound by certification to the key packet. + */ + void validate_cert(pgp_signature_info_t & sinfo, + const pgp_key_pkt_t & key, + const pgp_userid_pkt_t & uid, + const rnp::SecurityContext &ctx) const; + + /** + * @brief Validate subkey binding. + * + * @param sinfo populated signature info. Validation results will be stored here. + * @param subkey subkey packet. + */ + void validate_binding(pgp_signature_info_t & sinfo, + const pgp_key_t & subkey, + const rnp::SecurityContext &ctx) const; + + /** + * @brief Validate subkey revocation. + * + * @param sinfo populated signature info. Validation results will be stored here. + * @param subkey subkey packet. + */ + void validate_sub_rev(pgp_signature_info_t & sinfo, + const pgp_key_pkt_t & subkey, + const rnp::SecurityContext &ctx) const; + + /** + * @brief Validate direct-key signature. + * + * @param sinfo populated signature info. Validation results will be stored here. + */ + void validate_direct(pgp_signature_info_t &sinfo, const rnp::SecurityContext &ctx) const; + + void validate_self_signatures(const rnp::SecurityContext &ctx); + void validate_self_signatures(pgp_key_t &primary, const rnp::SecurityContext &ctx); + void validate(rnp_key_store_t &keyring); + void validate_subkey(pgp_key_t *primary, const rnp::SecurityContext &ctx); + void revalidate(rnp_key_store_t &keyring); + void mark_valid(); + /** + * @brief Fill common signature parameters, assuming that current key is a signing one. + * @param sig signature to init. + * @param hash hash algorithm to use (may be changed if it is not suitable for public key + * algorithm). + * @param creation signature's creation time. + */ + void sign_init(pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation) const; + /** + * @brief Calculate a certification and fill signature material. + * Note: secret key must be unlocked before calling this function. + * + * @param key key packet to sign. May be both public and secret. Could be signing key's + * packet for self-signature, or any other one for cross-key certification. + * @param uid uid to certify. + * @param sig signature, pre-populated with all of the required data, except the + * signature material. + */ + void sign_cert(const pgp_key_pkt_t & key, + const pgp_userid_pkt_t &uid, + pgp_signature_t & sig, + rnp::SecurityContext & ctx); + + /** + * @brief Calculate direct-key signature. + * Note: secret key must be unlocked before calling this function. + * + * @param key key packet to sign. May be both public and secret. + * @param sig signature, pre-populated with all of the required data, except the + * signature material. + */ + void sign_direct(const pgp_key_pkt_t & key, + pgp_signature_t & sig, + rnp::SecurityContext &ctx); + + /** + * @brief Calculate subkey or primary key binding. + * Note: this will not embed primary key binding for the signing subkey, it should + * be added by the caller. + * + * @param key subkey or primary key packet, may be both public or secret. + * @param sig signature, pre-populated with all of the required data, except the + * signature material. + */ + void sign_binding(const pgp_key_pkt_t & key, + pgp_signature_t & sig, + rnp::SecurityContext &ctx); + + /** + * @brief Calculate subkey binding. + * Note: secret key must be unlocked before calling this function. If subsign is + * true then subkey must be secret and unlocked as well so function can calculate + * primary key binding. + * + * @param sub subkey to bind to the primary key. If subsign is true then must be unlocked + * secret key. + * @param sig signature, pre-populated with all of the required data, except the + * signature material. + */ + void sign_subkey_binding(pgp_key_t & sub, + pgp_signature_t & sig, + rnp::SecurityContext &ctx, + bool subsign = false); + + /** + * @brief Generate key or subkey revocation signature. + * + * @param revoke revocation information. + * @param key key or subkey packet to revoke. + * @param sig object to store revocation signature. Will be populated in method call. + */ + void gen_revocation(const pgp_revoke_t & revoke, + pgp_hash_alg_t hash, + const pgp_key_pkt_t & key, + pgp_signature_t & sig, + rnp::SecurityContext &ctx); + + /** + * @brief Add and certify userid. + * Note: secret key must be unlocked before calling this function. + * + * @param cert certification and userid parameters. + * @param hash hash algorithm to use during signing. See sign_init() for more details. + * @param ctx security context. + * @param pubkey if non-NULL then userid and certification will be added to this key as + * well. + */ + void add_uid_cert(rnp_selfsig_cert_info_t &cert, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx, + pgp_key_t * pubkey = nullptr); + + /** + * @brief Calculate and add subkey binding signature. + * Note: must be called on the unlocked secret primary key. Calculated signature is + * added to the subkey. + * + * @param subsec secret subkey. + * @param subpub subkey's public part (so signature is added to both). + * @param binding information about subkey to put to the signature. + * @param hash hash algorithm to use (may be adjusted according to key and subkey + * algorithms) + */ + void add_sub_binding(pgp_key_t & subsec, + pgp_key_t & subpub, + const rnp_selfsig_binding_info_t &binding, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx); + + /** @brief Refresh internal fields after primary key is updated */ + bool refresh_data(const rnp::SecurityContext &ctx); + /** @brief Refresh internal fields after subkey is updated */ + bool refresh_data(pgp_key_t *primary, const rnp::SecurityContext &ctx); + /** @brief Merge primary key with the src, i.e. add all new userids/signatures/subkeys */ + bool merge(const pgp_key_t &src); + /** @brief Merge subkey with the source, i.e. add all new signatures */ + bool merge(const pgp_key_t &src, pgp_key_t *primary); +}; + +namespace rnp { +class KeyLocker { + bool lock_; + pgp_key_t &key_; + + public: + KeyLocker(pgp_key_t &key) : lock_(key.is_locked()), key_(key) + { + } + + ~KeyLocker() + { + if (lock_ && !key_.is_locked()) { + key_.lock(); + } + } +}; +}; // namespace rnp + +pgp_key_pkt_t *pgp_decrypt_seckey_pgp(const pgp_rawpacket_t &raw, + const pgp_key_pkt_t & key, + const char * password); + +pgp_key_pkt_t *pgp_decrypt_seckey(const pgp_key_t &, + const pgp_password_provider_t &, + const pgp_password_ctx_t &); + +/** + * @brief Get the signer's key for signature + * + * @param sig signature + * @param keyring keyring to search for the key. May be NULL. + * @param prov key provider to request needed key, may be NULL. + * @return pointer to the key or NULL if key is not found. + */ +pgp_key_t *pgp_sig_get_signer(const pgp_subsig_t &sig, + rnp_key_store_t * keyring, + pgp_key_provider_t *prov); + +/** + * @brief Get the key's subkey by its index + * + * @param key primary key + * @param store key store which will be searched for subkeys + * @param idx index of the subkey + * @return pointer to the subkey or NULL if subkey not found + */ +pgp_key_t *pgp_key_get_subkey(const pgp_key_t *key, rnp_key_store_t *store, size_t idx); + +pgp_key_flags_t pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg); + +bool pgp_key_set_expiration(pgp_key_t * key, + pgp_key_t * signer, + uint32_t expiry, + const pgp_password_provider_t &prov, + rnp::SecurityContext & ctx); + +bool pgp_subkey_set_expiration(pgp_key_t * sub, + pgp_key_t * primsec, + pgp_key_t * secsub, + uint32_t expiry, + const pgp_password_provider_t &prov, + rnp::SecurityContext & ctx); + +/** Find a key or it's subkey, suitable for a particular operation + * + * If the key passed is suitable, it will be returned. + * Otherwise, its subkeys (if it is a primary w/subs) + * will be checked. NULL will be returned if no suitable + * key is found. + * + * @param op the operation for which the key should be suitable + * @param key the key + * @param key_provider the key provider. This will be used + * if/when subkeys are checked. + * @param no_primary set true if only subkeys must be returned + * + * @returns key or last created subkey with desired usage flag + * set or NULL if not found + */ +pgp_key_t *find_suitable_key(pgp_op_t op, + pgp_key_t * key, + pgp_key_provider_t *key_provider, + bool no_primary = false); + +/* + * Picks up hash algorithm according to domain parameters set + * in `pubkey' and user provided hash. That's mostly because DSA + * and ECDSA needs special treatment. + * + * @param hash set by the caller + * @param pubkey initialized public key + * + * @returns hash algorithm that must be use for operation (mostly + signing with secure key which corresponds to 'pubkey') + */ +pgp_hash_alg_t pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey); + +#endif // RNP_PACKET_KEY_H diff --git a/comm/third_party/rnp/src/lib/rnp.cpp b/comm/third_party/rnp/src/lib/rnp.cpp new file mode 100644 index 0000000000..24c46f986d --- /dev/null +++ b/comm/third_party/rnp/src/lib/rnp.cpp @@ -0,0 +1,8403 @@ +/*- + * Copyright (c) 2017-2021, Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "crypto.h" +#include "crypto/common.h" +#include "pgp-key.h" +#include "defaults.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include "uniwin.h" +#include +#else +#include +#endif +#include +#include +#include +#include "utils.h" +#include "str-utils.h" +#include "json-utils.h" +#include "version.h" +#include "ffi-priv-types.h" +#include "file-utils.h" + +#define FFI_LOG(ffi, ...) \ + do { \ + FILE *fp = stderr; \ + if (ffi && ffi->errs) { \ + fp = ffi->errs; \ + } \ + RNP_LOG_FD(fp, __VA_ARGS__); \ + } while (0) + +static pgp_key_t *get_key_require_public(rnp_key_handle_t handle); +static pgp_key_t *get_key_prefer_public(rnp_key_handle_t handle); +static pgp_key_t *get_key_require_secret(rnp_key_handle_t handle); + +static bool locator_to_str(const pgp_key_search_t &locator, + const char ** identifier_type, + char * identifier, + size_t identifier_size); + +static bool rnp_password_cb_bounce(const pgp_password_ctx_t *ctx, + char * password, + size_t password_size, + void * userdata_void); + +static rnp_result_t rnp_dump_src_to_json(pgp_source_t *src, uint32_t flags, char **result); + +static bool +call_key_callback(rnp_ffi_t ffi, const pgp_key_search_t &search, bool secret) +{ + if (!ffi->getkeycb) { + return false; + } + char identifier[RNP_LOCATOR_MAX_SIZE]; + const char *identifier_type = NULL; + if (!locator_to_str(search, &identifier_type, identifier, sizeof(identifier))) { + return false; + } + + ffi->getkeycb(ffi, ffi->getkeycb_ctx, identifier_type, identifier, secret); + return true; +} + +static pgp_key_t * +find_key(rnp_ffi_t ffi, + const pgp_key_search_t &search, + bool secret, + bool try_key_provider, + pgp_key_t * after = NULL) +{ + pgp_key_t *key = + rnp_key_store_search(secret ? ffi->secring : ffi->pubring, &search, after); + if (!key && try_key_provider && call_key_callback(ffi, search, secret)) { + // recurse and try the store search above once more + return find_key(ffi, search, secret, false, after); + } + return key; +} + +static pgp_key_t * +ffi_key_provider(const pgp_key_request_ctx_t *ctx, void *userdata) +{ + rnp_ffi_t ffi = (rnp_ffi_t) userdata; + return find_key(ffi, ctx->search, ctx->secret, true); +} + +static void +rnp_ctx_init_ffi(rnp_ctx_t &ctx, rnp_ffi_t ffi) +{ + ctx.ctx = &ffi->context; + ctx.ealg = DEFAULT_PGP_SYMM_ALG; + ctx.aalg = PGP_AEAD_NONE; + ctx.abits = DEFAULT_AEAD_CHUNK_BITS; +} + +static const id_str_pair sig_type_map[] = {{PGP_SIG_BINARY, "binary"}, + {PGP_SIG_TEXT, "text"}, + {PGP_SIG_STANDALONE, "standalone"}, + {PGP_CERT_GENERIC, "certification (generic)"}, + {PGP_CERT_PERSONA, "certification (persona)"}, + {PGP_CERT_CASUAL, "certification (casual)"}, + {PGP_CERT_POSITIVE, "certification (positive)"}, + {PGP_SIG_SUBKEY, "subkey binding"}, + {PGP_SIG_PRIMARY, "primary key binding"}, + {PGP_SIG_DIRECT, "direct"}, + {PGP_SIG_REV_KEY, "key revocation"}, + {PGP_SIG_REV_SUBKEY, "subkey revocation"}, + {PGP_SIG_REV_CERT, "certification revocation"}, + {PGP_SIG_TIMESTAMP, "timestamp"}, + {PGP_SIG_3RD_PARTY, "third-party"}, + {0, NULL}}; + +static const id_str_pair pubkey_alg_map[] = { + {PGP_PKA_RSA, RNP_ALGNAME_RSA}, + {PGP_PKA_RSA_ENCRYPT_ONLY, RNP_ALGNAME_RSA}, + {PGP_PKA_RSA_SIGN_ONLY, RNP_ALGNAME_RSA}, + {PGP_PKA_ELGAMAL, RNP_ALGNAME_ELGAMAL}, + {PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN, RNP_ALGNAME_ELGAMAL}, + {PGP_PKA_DSA, RNP_ALGNAME_DSA}, + {PGP_PKA_ECDH, RNP_ALGNAME_ECDH}, + {PGP_PKA_ECDSA, RNP_ALGNAME_ECDSA}, + {PGP_PKA_EDDSA, RNP_ALGNAME_EDDSA}, + {PGP_PKA_SM2, RNP_ALGNAME_SM2}, + {0, NULL}}; + +static const id_str_pair symm_alg_map[] = {{PGP_SA_IDEA, RNP_ALGNAME_IDEA}, + {PGP_SA_TRIPLEDES, RNP_ALGNAME_TRIPLEDES}, + {PGP_SA_CAST5, RNP_ALGNAME_CAST5}, + {PGP_SA_BLOWFISH, RNP_ALGNAME_BLOWFISH}, + {PGP_SA_AES_128, RNP_ALGNAME_AES_128}, + {PGP_SA_AES_192, RNP_ALGNAME_AES_192}, + {PGP_SA_AES_256, RNP_ALGNAME_AES_256}, + {PGP_SA_TWOFISH, RNP_ALGNAME_TWOFISH}, + {PGP_SA_CAMELLIA_128, RNP_ALGNAME_CAMELLIA_128}, + {PGP_SA_CAMELLIA_192, RNP_ALGNAME_CAMELLIA_192}, + {PGP_SA_CAMELLIA_256, RNP_ALGNAME_CAMELLIA_256}, + {PGP_SA_SM4, RNP_ALGNAME_SM4}, + {0, NULL}}; + +static const id_str_pair aead_alg_map[] = { + {PGP_AEAD_NONE, "None"}, {PGP_AEAD_EAX, "EAX"}, {PGP_AEAD_OCB, "OCB"}, {0, NULL}}; + +static const id_str_pair cipher_mode_map[] = {{PGP_CIPHER_MODE_CFB, "CFB"}, + {PGP_CIPHER_MODE_CBC, "CBC"}, + {PGP_CIPHER_MODE_OCB, "OCB"}, + {0, NULL}}; + +static const id_str_pair compress_alg_map[] = {{PGP_C_NONE, "Uncompressed"}, + {PGP_C_ZIP, "ZIP"}, + {PGP_C_ZLIB, "ZLIB"}, + {PGP_C_BZIP2, "BZip2"}, + {0, NULL}}; + +static const id_str_pair hash_alg_map[] = {{PGP_HASH_MD5, RNP_ALGNAME_MD5}, + {PGP_HASH_SHA1, RNP_ALGNAME_SHA1}, + {PGP_HASH_RIPEMD, RNP_ALGNAME_RIPEMD160}, + {PGP_HASH_SHA256, RNP_ALGNAME_SHA256}, + {PGP_HASH_SHA384, RNP_ALGNAME_SHA384}, + {PGP_HASH_SHA512, RNP_ALGNAME_SHA512}, + {PGP_HASH_SHA224, RNP_ALGNAME_SHA224}, + {PGP_HASH_SHA3_256, RNP_ALGNAME_SHA3_256}, + {PGP_HASH_SHA3_512, RNP_ALGNAME_SHA3_512}, + {PGP_HASH_SM3, RNP_ALGNAME_SM3}, + {0, NULL}}; + +static const id_str_pair s2k_type_map[] = { + {PGP_S2KS_SIMPLE, "Simple"}, + {PGP_S2KS_SALTED, "Salted"}, + {PGP_S2KS_ITERATED_AND_SALTED, "Iterated and salted"}, + {0, NULL}}; + +static const id_str_pair key_usage_map[] = { + {PGP_KF_SIGN, "sign"}, + {PGP_KF_CERTIFY, "certify"}, + {PGP_KF_ENCRYPT, "encrypt"}, + {PGP_KF_AUTH, "authenticate"}, + {0, NULL}, +}; + +static const id_str_pair key_flags_map[] = { + {PGP_KF_SPLIT, "split"}, + {PGP_KF_SHARED, "shared"}, + {0, NULL}, +}; + +static const id_str_pair identifier_type_map[] = {{PGP_KEY_SEARCH_USERID, "userid"}, + {PGP_KEY_SEARCH_KEYID, "keyid"}, + {PGP_KEY_SEARCH_FINGERPRINT, "fingerprint"}, + {PGP_KEY_SEARCH_GRIP, "grip"}, + {0, NULL}}; + +static const id_str_pair key_server_prefs_map[] = {{PGP_KEY_SERVER_NO_MODIFY, "no-modify"}, + {0, NULL}}; + +static const id_str_pair armor_type_map[] = {{PGP_ARMORED_MESSAGE, "message"}, + {PGP_ARMORED_PUBLIC_KEY, "public key"}, + {PGP_ARMORED_SECRET_KEY, "secret key"}, + {PGP_ARMORED_SIGNATURE, "signature"}, + {PGP_ARMORED_CLEARTEXT, "cleartext"}, + {0, NULL}}; + +static const id_str_pair key_import_status_map[] = { + {PGP_KEY_IMPORT_STATUS_UNKNOWN, "unknown"}, + {PGP_KEY_IMPORT_STATUS_UNCHANGED, "unchanged"}, + {PGP_KEY_IMPORT_STATUS_UPDATED, "updated"}, + {PGP_KEY_IMPORT_STATUS_NEW, "new"}, + {0, NULL}}; + +static const id_str_pair sig_import_status_map[] = { + {PGP_SIG_IMPORT_STATUS_UNKNOWN, "unknown"}, + {PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY, "unknown key"}, + {PGP_SIG_IMPORT_STATUS_UNCHANGED, "unchanged"}, + {PGP_SIG_IMPORT_STATUS_NEW, "new"}, + {0, NULL}}; + +static const id_str_pair revocation_code_map[] = { + {PGP_REVOCATION_NO_REASON, "no"}, + {PGP_REVOCATION_SUPERSEDED, "superseded"}, + {PGP_REVOCATION_COMPROMISED, "compromised"}, + {PGP_REVOCATION_RETIRED, "retired"}, + {PGP_REVOCATION_NO_LONGER_VALID, "no longer valid"}, + {0, NULL}}; + +static bool +symm_alg_supported(int alg) +{ + return pgp_is_sa_supported(alg, true); +} + +static bool +hash_alg_supported(int alg) +{ + switch (alg) { + case PGP_HASH_MD5: + case PGP_HASH_SHA1: +#if defined(ENABLE_RIPEMD160) + case PGP_HASH_RIPEMD: +#endif + case PGP_HASH_SHA256: + case PGP_HASH_SHA384: + case PGP_HASH_SHA512: + case PGP_HASH_SHA224: + case PGP_HASH_SHA3_256: + case PGP_HASH_SHA3_512: +#if defined(ENABLE_SM2) + case PGP_HASH_SM3: +#endif + return true; + default: + return false; + } +} + +static bool +aead_alg_supported(int alg) +{ + switch (alg) { + case PGP_AEAD_NONE: +#if defined(ENABLE_AEAD) +#if !defined(CRYPTO_BACKEND_OPENSSL) + case PGP_AEAD_EAX: +#endif + case PGP_AEAD_OCB: +#endif + return true; + default: + return false; + } +} + +static bool +pub_alg_supported(int alg) +{ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_ELGAMAL: + case PGP_PKA_DSA: + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: +#if defined(ENABLE_SM2) + case PGP_PKA_SM2: +#endif + return true; + default: + return false; + } +} + +static bool +z_alg_supported(int alg) +{ + switch (alg) { + case PGP_C_NONE: + case PGP_C_ZIP: + case PGP_C_ZLIB: + case PGP_C_BZIP2: + return true; + default: + return false; + } +} + +static bool +curve_str_to_type(const char *str, pgp_curve_t *value) +{ + *value = find_curve_by_name(str); + return curve_supported(*value); +} + +static bool +curve_type_to_str(pgp_curve_t type, const char **str) +{ + const ec_curve_desc_t *desc = get_curve_desc(type); + if (!desc) { + return false; + } + *str = desc->pgp_name; + return true; +} + +static bool +str_to_cipher(const char *str, pgp_symm_alg_t *cipher) +{ + auto alg = id_str_pair::lookup(symm_alg_map, str, PGP_SA_UNKNOWN); + if (!symm_alg_supported(alg)) { + return false; + } + *cipher = static_cast(alg); + return true; +} + +static bool +str_to_hash_alg(const char *str, pgp_hash_alg_t *hash_alg) +{ + auto alg = id_str_pair::lookup(hash_alg_map, str, PGP_HASH_UNKNOWN); + if (!hash_alg_supported(alg)) { + return false; + } + *hash_alg = static_cast(alg); + return true; +} + +static bool +str_to_aead_alg(const char *str, pgp_aead_alg_t *aead_alg) +{ + auto alg = id_str_pair::lookup(aead_alg_map, str, PGP_AEAD_UNKNOWN); + if (!aead_alg_supported(alg)) { + return false; + } + *aead_alg = static_cast(alg); + return true; +} + +static bool +str_to_compression_alg(const char *str, pgp_compression_type_t *zalg) +{ + auto alg = id_str_pair::lookup(compress_alg_map, str, PGP_C_UNKNOWN); + if (!z_alg_supported(alg)) { + return false; + } + *zalg = static_cast(alg); + return true; +} + +static bool +str_to_revocation_type(const char *str, pgp_revocation_type_t *code) +{ + pgp_revocation_type_t rev = static_cast( + id_str_pair::lookup(revocation_code_map, str, PGP_REVOCATION_NO_REASON)); + if ((rev == PGP_REVOCATION_NO_REASON) && !rnp::str_case_eq(str, "no")) { + return false; + } + *code = rev; + return true; +} + +static bool +str_to_cipher_mode(const char *str, pgp_cipher_mode_t *mode) +{ + pgp_cipher_mode_t c_mode = static_cast( + id_str_pair::lookup(cipher_mode_map, str, PGP_CIPHER_MODE_NONE)); + if (c_mode == PGP_CIPHER_MODE_NONE) { + return false; + } + + *mode = c_mode; + return true; +} + +static bool +str_to_pubkey_alg(const char *str, pgp_pubkey_alg_t *pub_alg) +{ + auto alg = id_str_pair::lookup(pubkey_alg_map, str, PGP_PKA_NOTHING); + if (!pub_alg_supported(alg)) { + return false; + } + *pub_alg = static_cast(alg); + return true; +} + +static bool +str_to_key_flag(const char *str, uint8_t *flag) +{ + uint8_t _flag = id_str_pair::lookup(key_usage_map, str); + if (!_flag) { + return false; + } + *flag = _flag; + return true; +} + +static bool +parse_ks_format(pgp_key_store_format_t *key_store_format, const char *format) +{ + if (!strcmp(format, RNP_KEYSTORE_GPG)) { + *key_store_format = PGP_KEY_STORE_GPG; + } else if (!strcmp(format, RNP_KEYSTORE_KBX)) { + *key_store_format = PGP_KEY_STORE_KBX; + } else if (!strcmp(format, RNP_KEYSTORE_G10)) { + *key_store_format = PGP_KEY_STORE_G10; + } else { + return false; + } + return true; +} + +static rnp_result_t +hex_encode_value(const uint8_t * value, + size_t len, + char ** res, + rnp::hex_format_t format = rnp::HEX_UPPERCASE) +{ + size_t hex_len = len * 2 + 1; + *res = (char *) malloc(hex_len); + if (!*res) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!rnp::hex_encode(value, len, *res, hex_len, format)) { + free(*res); + *res = NULL; + return RNP_ERROR_GENERIC; + } + return RNP_SUCCESS; +} + +static rnp_result_t +get_map_value(const id_str_pair *map, int val, char **res) +{ + const char *str = id_str_pair::lookup(map, val, NULL); + if (!str) { + return RNP_ERROR_BAD_PARAMETERS; + } + char *strcp = strdup(str); + if (!strcp) { + return RNP_ERROR_OUT_OF_MEMORY; + } + *res = strcp; + return RNP_SUCCESS; +} + +static rnp_result_t +ret_str_value(const char *str, char **res) +{ + if (!str) { + return RNP_ERROR_BAD_PARAMETERS; + } + char *strcp = strdup(str); + if (!strcp) { + return RNP_ERROR_OUT_OF_MEMORY; + } + *res = strcp; + return RNP_SUCCESS; +} + +static uint32_t +ffi_exception(FILE *fp, const char *func, const char *msg, uint32_t ret = RNP_ERROR_GENERIC) +{ + if (rnp_log_switch()) { + fprintf( + fp, "[%s()] Error 0x%08X (%s): %s\n", func, ret, rnp_result_to_string(ret), msg); + } + return ret; +} + +#define FFI_GUARD_FP(fp) \ + catch (rnp::rnp_exception & e) \ + { \ + return ffi_exception((fp), __func__, e.what(), e.code()); \ + } \ + catch (std::bad_alloc &) \ + { \ + return ffi_exception((fp), __func__, "bad_alloc", RNP_ERROR_OUT_OF_MEMORY); \ + } \ + catch (std::exception & e) \ + { \ + return ffi_exception((fp), __func__, e.what()); \ + } \ + catch (...) \ + { \ + return ffi_exception((fp), __func__, "unknown exception"); \ + } + +#define FFI_GUARD FFI_GUARD_FP((stderr)) + +rnp_ffi_st::rnp_ffi_st(pgp_key_store_format_t pub_fmt, pgp_key_store_format_t sec_fmt) +{ + errs = stderr; + pubring = new rnp_key_store_t(pub_fmt, "", context); + secring = new rnp_key_store_t(sec_fmt, "", context); + getkeycb = NULL; + getkeycb_ctx = NULL; + getpasscb = NULL; + getpasscb_ctx = NULL; + key_provider.callback = ffi_key_provider; + key_provider.userdata = this; + pass_provider.callback = rnp_password_cb_bounce; + pass_provider.userdata = this; +} + +rnp::RNG & +rnp_ffi_st::rng() noexcept +{ + return context.rng; +} + +rnp::SecurityProfile & +rnp_ffi_st::profile() noexcept +{ + return context.profile; +} + +rnp_result_t +rnp_ffi_create(rnp_ffi_t *ffi, const char *pub_format, const char *sec_format) +try { + // checks + if (!ffi || !pub_format || !sec_format) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_store_format_t pub_ks_format = PGP_KEY_STORE_UNKNOWN; + pgp_key_store_format_t sec_ks_format = PGP_KEY_STORE_UNKNOWN; + if (!parse_ks_format(&pub_ks_format, pub_format) || + !parse_ks_format(&sec_ks_format, sec_format)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + struct rnp_ffi_st *ob = new rnp_ffi_st(pub_ks_format, sec_ks_format); + *ffi = ob; + return RNP_SUCCESS; +} +FFI_GUARD + +static bool +is_std_file(FILE *fp) +{ + return fp == stdout || fp == stderr; +} + +static void +close_io_file(FILE **fp) +{ + if (*fp && !is_std_file(*fp)) { + fclose(*fp); + } + *fp = NULL; +} + +rnp_ffi_st::~rnp_ffi_st() +{ + close_io_file(&errs); + delete pubring; + delete secring; +} + +rnp_result_t +rnp_ffi_destroy(rnp_ffi_t ffi) +try { + if (ffi) { + delete ffi; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_ffi_set_log_fd(rnp_ffi_t ffi, int fd) +try { + // checks + if (!ffi) { + return RNP_ERROR_NULL_POINTER; + } + + // open + FILE *errs = rnp_fdopen(fd, "a"); + if (!errs) { + return RNP_ERROR_ACCESS; + } + // close previous streams and replace them + close_io_file(&ffi->errs); + ffi->errs = errs; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_ffi_set_key_provider(rnp_ffi_t ffi, rnp_get_key_cb getkeycb, void *getkeycb_ctx) +try { + if (!ffi) { + return RNP_ERROR_NULL_POINTER; + } + ffi->getkeycb = getkeycb; + ffi->getkeycb_ctx = getkeycb_ctx; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_ffi_set_pass_provider(rnp_ffi_t ffi, rnp_password_cb getpasscb, void *getpasscb_ctx) +try { + if (!ffi) { + return RNP_ERROR_NULL_POINTER; + } + ffi->getpasscb = getpasscb; + ffi->getpasscb_ctx = getpasscb_ctx; + return RNP_SUCCESS; +} +FFI_GUARD + +static const char * +operation_description(uint8_t op) +{ + switch (op) { + case PGP_OP_ADD_SUBKEY: + return "add subkey"; + case PGP_OP_ADD_USERID: + return "add userid"; + case PGP_OP_SIGN: + return "sign"; + case PGP_OP_DECRYPT: + return "decrypt"; + case PGP_OP_UNLOCK: + return "unlock"; + case PGP_OP_PROTECT: + return "protect"; + case PGP_OP_UNPROTECT: + return "unprotect"; + case PGP_OP_DECRYPT_SYM: + return "decrypt (symmetric)"; + case PGP_OP_ENCRYPT_SYM: + return "encrypt (symmetric)"; + default: + return "unknown"; + } +} + +static bool +rnp_password_cb_bounce(const pgp_password_ctx_t *ctx, + char * password, + size_t password_size, + void * userdata_void) +{ + rnp_ffi_t ffi = (rnp_ffi_t) userdata_void; + + if (!ffi || !ffi->getpasscb) { + return false; + } + + struct rnp_key_handle_st key = {}; + key.ffi = ffi; + key.sec = (pgp_key_t *) ctx->key; + return ffi->getpasscb(ffi, + ffi->getpasscb_ctx, + ctx->key ? &key : NULL, + operation_description(ctx->op), + password, + password_size); +} + +const char * +rnp_result_to_string(rnp_result_t result) +{ + switch (result) { + case RNP_SUCCESS: + return "Success"; + + case RNP_ERROR_GENERIC: + return "Unknown error"; + case RNP_ERROR_BAD_FORMAT: + return "Bad format"; + case RNP_ERROR_BAD_PARAMETERS: + return "Bad parameters"; + case RNP_ERROR_NOT_IMPLEMENTED: + return "Not implemented"; + case RNP_ERROR_NOT_SUPPORTED: + return "Not supported"; + case RNP_ERROR_OUT_OF_MEMORY: + return "Out of memory"; + case RNP_ERROR_SHORT_BUFFER: + return "Buffer too short"; + case RNP_ERROR_NULL_POINTER: + return "Null pointer"; + + case RNP_ERROR_ACCESS: + return "Error accessing file"; + case RNP_ERROR_READ: + return "Error reading file"; + case RNP_ERROR_WRITE: + return "Error writing file"; + + case RNP_ERROR_BAD_STATE: + return "Bad state"; + case RNP_ERROR_MAC_INVALID: + return "Invalid MAC"; + case RNP_ERROR_SIGNATURE_INVALID: + return "Invalid signature"; + case RNP_ERROR_KEY_GENERATION: + return "Error during key generation"; + case RNP_ERROR_BAD_PASSWORD: + return "Bad password"; + case RNP_ERROR_KEY_NOT_FOUND: + return "Key not found"; + case RNP_ERROR_NO_SUITABLE_KEY: + return "No suitable key"; + case RNP_ERROR_DECRYPT_FAILED: + return "Decryption failed"; + case RNP_ERROR_RNG: + return "Failure of random number generator"; + case RNP_ERROR_SIGNING_FAILED: + return "Signing failed"; + case RNP_ERROR_NO_SIGNATURES_FOUND: + return "No signatures found cannot verify"; + + case RNP_ERROR_SIGNATURE_EXPIRED: + return "Expired signature"; + case RNP_ERROR_VERIFICATION_FAILED: + return "Signature verification failed cannot verify"; + case RNP_ERROR_SIGNATURE_UNKNOWN: + return "Unknown signature"; + + case RNP_ERROR_NOT_ENOUGH_DATA: + return "Not enough data"; + case RNP_ERROR_UNKNOWN_TAG: + return "Unknown tag"; + case RNP_ERROR_PACKET_NOT_CONSUMED: + return "Packet not consumed"; + case RNP_ERROR_NO_USERID: + return "No userid"; + case RNP_ERROR_EOF: + return "EOF detected"; + } + + return "Unsupported error code"; +} + +const char * +rnp_version_string() +{ + return RNP_VERSION_STRING; +} + +const char * +rnp_version_string_full() +{ + return RNP_VERSION_STRING_FULL; +} + +uint32_t +rnp_version() +{ + return RNP_VERSION_CODE; +} + +uint32_t +rnp_version_for(uint32_t major, uint32_t minor, uint32_t patch) +{ + if (major > RNP_VERSION_COMPONENT_MASK || minor > RNP_VERSION_COMPONENT_MASK || + patch > RNP_VERSION_COMPONENT_MASK) { + RNP_LOG("invalid version, out of range: %d.%d.%d", major, minor, patch); + return 0; + } + return RNP_VERSION_CODE_FOR(major, minor, patch); +} + +uint32_t +rnp_version_major(uint32_t version) +{ + return (version >> RNP_VERSION_MAJOR_SHIFT) & RNP_VERSION_COMPONENT_MASK; +} + +uint32_t +rnp_version_minor(uint32_t version) +{ + return (version >> RNP_VERSION_MINOR_SHIFT) & RNP_VERSION_COMPONENT_MASK; +} + +uint32_t +rnp_version_patch(uint32_t version) +{ + return (version >> RNP_VERSION_PATCH_SHIFT) & RNP_VERSION_COMPONENT_MASK; +} + +uint64_t +rnp_version_commit_timestamp() +{ + return RNP_VERSION_COMMIT_TIMESTAMP; +} + +#ifndef RNP_NO_DEPRECATED +rnp_result_t +rnp_enable_debug(const char *file) +try { + return RNP_SUCCESS; +} +FFI_GUARD +#endif + +#ifndef RNP_NO_DEPRECATED +rnp_result_t +rnp_disable_debug() +try { + return RNP_SUCCESS; +} +FFI_GUARD +#endif + +rnp_result_t +rnp_get_default_homedir(char **homedir) +try { + // checks + if (!homedir) { + return RNP_ERROR_NULL_POINTER; + } + + // get the users home dir + auto home = rnp::path::HOME(".rnp"); + if (home.empty()) { + return RNP_ERROR_NOT_SUPPORTED; + } + *homedir = strdup(home.c_str()); + if (!*homedir) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_detect_homedir_info( + const char *homedir, char **pub_format, char **pub_path, char **sec_format, char **sec_path) +try { + // checks + if (!homedir || !pub_format || !pub_path || !sec_format || !sec_path) { + return RNP_ERROR_NULL_POINTER; + } + + // we only support the common cases of GPG+GPG or GPG+G10, we don't + // support unused combinations like KBX+KBX + + *pub_format = NULL; + *pub_path = NULL; + *sec_format = NULL; + *sec_path = NULL; + + // check for pubring.kbx file and for private-keys-v1.d dir + std::string pub = rnp::path::append(homedir, "pubring.kbx"); + std::string sec = rnp::path::append(homedir, "private-keys-v1.d"); + if (rnp::path::exists(pub) && rnp::path::exists(sec, true)) { + *pub_format = strdup("KBX"); + *sec_format = strdup("G10"); + } else { + // check for pubring.gpg and secring.gpg + pub = rnp::path::append(homedir, "pubring.gpg"); + sec = rnp::path::append(homedir, "secring.gpg"); + if (rnp::path::exists(pub) && rnp::path::exists(sec)) { + *pub_format = strdup("GPG"); + *sec_format = strdup("GPG"); + } else { + // we leave the *formats as NULL if we were not able to determine the format + // (but no error occurred) + return RNP_SUCCESS; + } + } + + // set pathes + *pub_path = strdup(pub.c_str()); + *sec_path = strdup(sec.c_str()); + + // check for allocation failures + if (*pub_format && *pub_path && *sec_format && *sec_path) { + return RNP_SUCCESS; + } + + free(*pub_format); + *pub_format = NULL; + free(*pub_path); + *pub_path = NULL; + free(*sec_format); + *sec_format = NULL; + free(*sec_path); + *sec_path = NULL; + return RNP_ERROR_OUT_OF_MEMORY; +} +FFI_GUARD + +rnp_result_t +rnp_detect_key_format(const uint8_t buf[], size_t buf_len, char **format) +try { + rnp_result_t ret = RNP_ERROR_GENERIC; + + // checks + if (!buf || !format) { + return RNP_ERROR_NULL_POINTER; + } + if (!buf_len) { + return RNP_ERROR_SHORT_BUFFER; + } + + *format = NULL; + // ordered from most reliable detection to least + const char *guess = NULL; + if (buf_len >= 12 && memcmp(buf + 8, "KBXf", 4) == 0) { + // KBX has a magic KBXf marker + guess = "KBX"; + } else if (buf_len >= 5 && memcmp(buf, "-----", 5) == 0) { + // likely armored GPG + guess = "GPG"; + } else if (buf[0] == '(') { + // G10 is s-exprs and should start end end with parentheses + guess = "G10"; + } else if (buf[0] & PGP_PTAG_ALWAYS_SET) { + // this is harder to reliably determine, but could likely be improved + guess = "GPG"; + } + if (guess) { + *format = strdup(guess); + if (!*format) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + } + + // success + ret = RNP_SUCCESS; +done: + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_calculate_iterations(const char *hash, size_t msec, size_t *iterations) +try { + if (!hash || !iterations) { + return RNP_ERROR_NULL_POINTER; + } + pgp_hash_alg_t halg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(hash, &halg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *iterations = pgp_s2k_compute_iters(halg, msec, 0); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_supports_feature(const char *type, const char *name, bool *supported) +try { + if (!type || !name || !supported) { + return RNP_ERROR_NULL_POINTER; + } + if (rnp::str_case_eq(type, RNP_FEATURE_SYMM_ALG)) { + pgp_symm_alg_t alg = PGP_SA_UNKNOWN; + *supported = str_to_cipher(name, &alg); + } else if (rnp::str_case_eq(type, RNP_FEATURE_AEAD_ALG)) { + pgp_aead_alg_t alg = PGP_AEAD_UNKNOWN; + *supported = str_to_aead_alg(name, &alg); + } else if (rnp::str_case_eq(type, RNP_FEATURE_PROT_MODE)) { + // for now we support only CFB for key encryption + *supported = rnp::str_case_eq(name, "CFB"); + } else if (rnp::str_case_eq(type, RNP_FEATURE_PK_ALG)) { + pgp_pubkey_alg_t alg = PGP_PKA_NOTHING; + *supported = str_to_pubkey_alg(name, &alg); + } else if (rnp::str_case_eq(type, RNP_FEATURE_HASH_ALG)) { + pgp_hash_alg_t alg = PGP_HASH_UNKNOWN; + *supported = str_to_hash_alg(name, &alg); + } else if (rnp::str_case_eq(type, RNP_FEATURE_COMP_ALG)) { + pgp_compression_type_t alg = PGP_C_UNKNOWN; + *supported = str_to_compression_alg(name, &alg); + } else if (rnp::str_case_eq(type, RNP_FEATURE_CURVE)) { + pgp_curve_t curve = PGP_CURVE_UNKNOWN; + *supported = curve_str_to_type(name, &curve); + } else { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +json_array_add_id_str(json_object *arr, const id_str_pair *map, bool (*check)(int)) +{ + while (map->str) { + if (check(map->id) && !array_add_element_json(arr, json_object_new_string(map->str))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + map++; + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_supported_features(const char *type, char **result) +try { + if (!type || !result) { + return RNP_ERROR_NULL_POINTER; + } + + json_object *features = json_object_new_array(); + if (!features) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + rnp_result_t ret = RNP_ERROR_BAD_PARAMETERS; + + if (rnp::str_case_eq(type, RNP_FEATURE_SYMM_ALG)) { + ret = json_array_add_id_str(features, symm_alg_map, symm_alg_supported); + } else if (rnp::str_case_eq(type, RNP_FEATURE_AEAD_ALG)) { + ret = json_array_add_id_str(features, aead_alg_map, aead_alg_supported); + } else if (rnp::str_case_eq(type, RNP_FEATURE_PROT_MODE)) { + ret = json_array_add_id_str( + features, cipher_mode_map, [](int alg) { return alg == PGP_CIPHER_MODE_CFB; }); + } else if (rnp::str_case_eq(type, RNP_FEATURE_PK_ALG)) { + ret = json_array_add_id_str(features, pubkey_alg_map, pub_alg_supported); + } else if (rnp::str_case_eq(type, RNP_FEATURE_HASH_ALG)) { + ret = json_array_add_id_str(features, hash_alg_map, hash_alg_supported); + } else if (rnp::str_case_eq(type, RNP_FEATURE_COMP_ALG)) { + ret = json_array_add_id_str(features, compress_alg_map, z_alg_supported); + } else if (rnp::str_case_eq(type, RNP_FEATURE_CURVE)) { + for (pgp_curve_t curve = PGP_CURVE_NIST_P_256; curve < PGP_CURVE_MAX; + curve = (pgp_curve_t)(curve + 1)) { + const ec_curve_desc_t *desc = get_curve_desc(curve); + if (!desc) { + ret = RNP_ERROR_BAD_STATE; + goto done; + } + if (!desc->supported) { + continue; + } + if (!array_add_element_json(features, json_object_new_string(desc->pgp_name))) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + } + ret = RNP_SUCCESS; + } + + if (ret) { + goto done; + } + + *result = (char *) json_object_to_json_string_ext(features, JSON_C_TO_STRING_PRETTY); + if (!*result) { + ret = RNP_ERROR_BAD_STATE; + goto done; + } + *result = strdup(*result); + if (!*result) { + ret = RNP_ERROR_OUT_OF_MEMORY; + } +done: + json_object_put(features); + return ret; +} +FFI_GUARD + +static bool +get_feature_sec_value( + rnp_ffi_t ffi, const char *stype, const char *sname, rnp::FeatureType &type, int &value) +{ + /* check type */ + if (!rnp::str_case_eq(stype, RNP_FEATURE_HASH_ALG)) { + FFI_LOG(ffi, "Unsupported feature type: %s", stype); + return false; + } + type = rnp::FeatureType::Hash; + /* check feature name */ + pgp_hash_alg_t alg = PGP_HASH_UNKNOWN; + if (sname && !str_to_hash_alg(sname, &alg)) { + FFI_LOG(ffi, "Unknown hash algorithm: %s", sname); + return false; + } + value = alg; + return true; +} + +static bool +get_feature_sec_level(rnp_ffi_t ffi, uint32_t flevel, rnp::SecurityLevel &level) +{ + switch (flevel) { + case RNP_SECURITY_PROHIBITED: + level = rnp::SecurityLevel::Disabled; + break; + case RNP_SECURITY_INSECURE: + level = rnp::SecurityLevel::Insecure; + break; + case RNP_SECURITY_DEFAULT: + level = rnp::SecurityLevel::Default; + break; + default: + FFI_LOG(ffi, "Invalid security level : %" PRIu32, flevel); + return false; + } + return true; +} + +static bool +extract_flag(uint32_t &flags, uint32_t flag) +{ + bool res = flags & flag; + flags &= ~flag; + return res; +} + +rnp_result_t +rnp_add_security_rule(rnp_ffi_t ffi, + const char *type, + const char *name, + uint32_t flags, + uint64_t from, + uint32_t level) +try { + if (!ffi || !type || !name) { + return RNP_ERROR_NULL_POINTER; + } + /* convert values */ + rnp::FeatureType ftype; + int fvalue; + rnp::SecurityLevel sec_level; + if (!get_feature_sec_value(ffi, type, name, ftype, fvalue) || + !get_feature_sec_level(ffi, level, sec_level)) { + return RNP_ERROR_BAD_PARAMETERS; + } + /* check flags */ + bool rule_override = extract_flag(flags, RNP_SECURITY_OVERRIDE); + bool verify_key = extract_flag(flags, RNP_SECURITY_VERIFY_KEY); + bool verify_data = extract_flag(flags, RNP_SECURITY_VERIFY_DATA); + if (flags) { + FFI_LOG(ffi, "Unknown flags: %" PRIu32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + /* add rule */ + rnp::SecurityRule newrule(ftype, fvalue, sec_level, from); + newrule.override = rule_override; + /* Add rule for any action */ + if (!verify_key && !verify_data) { + ffi->profile().add_rule(newrule); + return RNP_SUCCESS; + } + /* Add rule for each specified key usage */ + if (verify_key) { + newrule.action = rnp::SecurityAction::VerifyKey; + ffi->profile().add_rule(newrule); + } + if (verify_data) { + newrule.action = rnp::SecurityAction::VerifyData; + ffi->profile().add_rule(newrule); + } + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp::SecurityAction +get_security_action(uint32_t flags) +{ + if (flags & RNP_SECURITY_VERIFY_KEY) { + return rnp::SecurityAction::VerifyKey; + } + if (flags & RNP_SECURITY_VERIFY_DATA) { + return rnp::SecurityAction::VerifyData; + } + return rnp::SecurityAction::Any; +} + +rnp_result_t +rnp_get_security_rule(rnp_ffi_t ffi, + const char *type, + const char *name, + uint64_t time, + uint32_t * flags, + uint64_t * from, + uint32_t * level) +try { + if (!ffi || !type || !name || !level) { + return RNP_ERROR_NULL_POINTER; + } + /* convert values */ + rnp::FeatureType ftype; + int fvalue; + if (!get_feature_sec_value(ffi, type, name, ftype, fvalue)) { + return RNP_ERROR_BAD_PARAMETERS; + } + /* init default rule */ + rnp::SecurityRule rule(ftype, fvalue, ffi->profile().def_level()); + /* Check whether limited usage is requested */ + auto action = get_security_action(flags ? *flags : 0); + /* check whether rule exists */ + if (ffi->profile().has_rule(ftype, fvalue, time, action)) { + rule = ffi->profile().get_rule(ftype, fvalue, time, action); + } + /* fill the results */ + if (flags) { + *flags = rule.override ? RNP_SECURITY_OVERRIDE : 0; + switch (rule.action) { + case rnp::SecurityAction::VerifyKey: + *flags |= RNP_SECURITY_VERIFY_KEY; + break; + case rnp::SecurityAction::VerifyData: + *flags |= RNP_SECURITY_VERIFY_DATA; + break; + default: + break; + } + } + if (from) { + *from = rule.from; + } + switch (rule.level) { + case rnp::SecurityLevel::Disabled: + *level = RNP_SECURITY_PROHIBITED; + break; + case rnp::SecurityLevel::Insecure: + *level = RNP_SECURITY_INSECURE; + break; + case rnp::SecurityLevel::Default: + *level = RNP_SECURITY_DEFAULT; + break; + default: + FFI_LOG(ffi, "Invalid security level."); + return RNP_ERROR_BAD_STATE; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_remove_security_rule(rnp_ffi_t ffi, + const char *type, + const char *name, + uint32_t level, + uint32_t flags, + uint64_t from, + size_t * removed) +try { + if (!ffi) { + return RNP_ERROR_NULL_POINTER; + } + /* check flags */ + bool remove_all = extract_flag(flags, RNP_SECURITY_REMOVE_ALL); + bool rule_override = extract_flag(flags, RNP_SECURITY_OVERRIDE); + rnp::SecurityAction action = get_security_action(flags); + extract_flag(flags, RNP_SECURITY_VERIFY_DATA | RNP_SECURITY_VERIFY_KEY); + if (flags) { + FFI_LOG(ffi, "Unknown flags: %" PRIu32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + /* remove all rules */ + size_t rules = ffi->profile().size(); + if (!type) { + ffi->profile().clear_rules(); + goto success; + } + rnp::FeatureType ftype; + int fvalue; + rnp::SecurityLevel flevel; + if (!get_feature_sec_value(ffi, type, name, ftype, fvalue) || + !get_feature_sec_level(ffi, level, flevel)) { + return RNP_ERROR_BAD_PARAMETERS; + } + /* remove all rules for the specified type */ + if (!name) { + ffi->profile().clear_rules(ftype); + goto success; + } + if (remove_all) { + /* remove all rules for the specified type and name */ + ffi->profile().clear_rules(ftype, fvalue); + } else { + /* remove specific rule */ + rnp::SecurityRule rule(ftype, fvalue, flevel, from, action); + rule.override = rule_override; + ffi->profile().del_rule(rule); + } +success: + if (removed) { + *removed = rules - ffi->profile().size(); + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_request_password(rnp_ffi_t ffi, rnp_key_handle_t key, const char *context, char **password) +try { + if (!ffi || !password || !ffi->getpasscb) { + return RNP_ERROR_NULL_POINTER; + } + + rnp::secure_vector pass(MAX_PASSWORD_LENGTH, '\0'); + bool req_res = + ffi->getpasscb(ffi, ffi->getpasscb_ctx, key, context, pass.data(), pass.size()); + if (!req_res) { + return RNP_ERROR_GENERIC; + } + size_t pass_len = strlen(pass.data()) + 1; + *password = (char *) malloc(pass_len); + if (!*password) { + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(*password, pass.data(), pass_len); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_set_timestamp(rnp_ffi_t ffi, uint64_t time) +try { + if (!ffi) { + return RNP_ERROR_NULL_POINTER; + } + ffi->context.set_time(time); + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +load_keys_from_input(rnp_ffi_t ffi, rnp_input_t input, rnp_key_store_t *store) +{ + pgp_key_provider_t chained(rnp_key_provider_store, store); + const pgp_key_provider_t *key_providers[] = {&chained, &ffi->key_provider, NULL}; + const pgp_key_provider_t key_provider(rnp_key_provider_chained, key_providers); + + if (!input->src_directory.empty()) { + // load the keys + store->path = input->src_directory; + if (!rnp_key_store_load_from_path(store, &key_provider)) { + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; + } + + // load the keys + if (!rnp_key_store_load_from_src(store, &input->src, &key_provider)) { + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; +} + +static bool +key_needs_conversion(const pgp_key_t *key, const rnp_key_store_t *store) +{ + pgp_key_store_format_t key_format = key->format; + pgp_key_store_format_t store_format = store->format; + /* pgp_key_t->format is only ever GPG or G10. + * + * The key store, however, could have a format of KBX, GPG, or G10. + * A KBX (and GPG) key store can only handle a pgp_key_t with a format of GPG. + * A G10 key store can only handle a pgp_key_t with a format of G10. + */ + // should never be the case + assert(key_format != PGP_KEY_STORE_KBX); + // normalize the store format + if (store_format == PGP_KEY_STORE_KBX) { + store_format = PGP_KEY_STORE_GPG; + } + // from here, both the key and store formats can only be GPG or G10 + return key_format != store_format; +} + +static rnp_result_t +do_load_keys(rnp_ffi_t ffi, + rnp_input_t input, + pgp_key_store_format_t format, + key_type_t key_type) +{ + // create a temporary key store to hold the keys + std::unique_ptr tmp_store; + try { + tmp_store = + std::unique_ptr(new rnp_key_store_t(format, "", ffi->context)); + } catch (const std::invalid_argument &e) { + FFI_LOG(ffi, "Failed to create key store of format: %d", (int) format); + return RNP_ERROR_BAD_PARAMETERS; + } + + // load keys into our temporary store + rnp_result_t tmpret = load_keys_from_input(ffi, input, tmp_store.get()); + if (tmpret) { + return tmpret; + } + // go through all the loaded keys + for (auto &key : tmp_store->keys) { + // check that the key is the correct type and has not already been loaded + // add secret key part if it is and we need it + if (key.is_secret() && ((key_type == KEY_TYPE_SECRET) || (key_type == KEY_TYPE_ANY))) { + if (key_needs_conversion(&key, ffi->secring)) { + FFI_LOG(ffi, "This key format conversion is not yet supported"); + return RNP_ERROR_NOT_IMPLEMENTED; + } + + if (!rnp_key_store_add_key(ffi->secring, &key)) { + FFI_LOG(ffi, "Failed to add secret key"); + return RNP_ERROR_GENERIC; + } + } + + // add public key part if needed + if ((key.format == PGP_KEY_STORE_G10) || + ((key_type != KEY_TYPE_ANY) && (key_type != KEY_TYPE_PUBLIC))) { + continue; + } + + pgp_key_t keycp; + try { + keycp = pgp_key_t(key, true); + } catch (const std::exception &e) { + RNP_LOG("Failed to copy public key part: %s", e.what()); + return RNP_ERROR_GENERIC; + } + + /* TODO: We could do this a few different ways. There isn't an obvious reason + * to restrict what formats we load, so we don't necessarily need to require a + * conversion just to load and use a G10 key when using GPG keyrings, for + * example. We could just convert when saving. + */ + + if (key_needs_conversion(&key, ffi->pubring)) { + FFI_LOG(ffi, "This key format conversion is not yet supported"); + return RNP_ERROR_NOT_IMPLEMENTED; + } + + if (!rnp_key_store_add_key(ffi->pubring, &keycp)) { + FFI_LOG(ffi, "Failed to add public key"); + return RNP_ERROR_GENERIC; + } + } + // success, even if we didn't actually load any + return RNP_SUCCESS; +} + +static key_type_t +flags_to_key_type(uint32_t *flags) +{ + key_type_t type = KEY_TYPE_NONE; + // figure out what type of keys to operate on, based on flags + if ((*flags & RNP_LOAD_SAVE_PUBLIC_KEYS) && (*flags & RNP_LOAD_SAVE_SECRET_KEYS)) { + type = KEY_TYPE_ANY; + extract_flag(*flags, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS); + } else if (*flags & RNP_LOAD_SAVE_PUBLIC_KEYS) { + type = KEY_TYPE_PUBLIC; + extract_flag(*flags, RNP_LOAD_SAVE_PUBLIC_KEYS); + } else if (*flags & RNP_LOAD_SAVE_SECRET_KEYS) { + type = KEY_TYPE_SECRET; + extract_flag(*flags, RNP_LOAD_SAVE_SECRET_KEYS); + } + return type; +} + +rnp_result_t +rnp_load_keys(rnp_ffi_t ffi, const char *format, rnp_input_t input, uint32_t flags) +try { + // checks + if (!ffi || !format || !input) { + return RNP_ERROR_NULL_POINTER; + } + key_type_t type = flags_to_key_type(&flags); + if (!type) { + FFI_LOG(ffi, "invalid flags - must have public and/or secret keys"); + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_store_format_t ks_format = PGP_KEY_STORE_UNKNOWN; + if (!parse_ks_format(&ks_format, format)) { + FFI_LOG(ffi, "invalid key store format: %s", format); + return RNP_ERROR_BAD_PARAMETERS; + } + + // check for any unrecognized flags (not forward-compat, but maybe still a good idea) + if (flags) { + FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + return do_load_keys(ffi, input, ks_format, type); +} +FFI_GUARD + +rnp_result_t +rnp_unload_keys(rnp_ffi_t ffi, uint32_t flags) +try { + if (!ffi) { + return RNP_ERROR_NULL_POINTER; + } + + if (flags & ~(RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (flags & RNP_KEY_UNLOAD_PUBLIC) { + rnp_key_store_clear(ffi->pubring); + } + if (flags & RNP_KEY_UNLOAD_SECRET) { + rnp_key_store_clear(ffi->secring); + } + + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +rnp_input_dearmor_if_needed(rnp_input_t input, bool noheaders = false) +{ + if (!input) { + return RNP_ERROR_NULL_POINTER; + } + if (!input->src_directory.empty()) { + return RNP_ERROR_BAD_PARAMETERS; + } + bool require_armor = false; + /* check whether we already have armored stream */ + if (input->src.type == PGP_STREAM_ARMORED) { + if (!src_eof(&input->src)) { + /* be ready for the case of damaged armoring */ + return src_error(&input->src) ? RNP_ERROR_READ : RNP_SUCCESS; + } + /* eof - probably next we have another armored message */ + src_close(&input->src); + rnp_input_st *base = (rnp_input_st *) input->app_ctx; + *input = std::move(*base); + delete base; + /* we should not mix armored data with binary */ + require_armor = true; + } + if (src_eof(&input->src)) { + return RNP_ERROR_EOF; + } + /* check whether input is armored only if base64 is not forced */ + if (!noheaders && !is_armored_source(&input->src)) { + return require_armor ? RNP_ERROR_BAD_FORMAT : RNP_SUCCESS; + } + + /* Store original input in app_ctx and replace src/app_ctx with armored data */ + rnp_input_t app_ctx = new rnp_input_st(); + *app_ctx = std::move(*input); + + rnp_result_t ret = init_armored_src(&input->src, &app_ctx->src, noheaders); + if (ret) { + /* original src may be changed during init_armored_src call, so copy it back */ + *input = std::move(*app_ctx); + delete app_ctx; + return ret; + } + input->app_ctx = app_ctx; + return RNP_SUCCESS; +} + +static const char * +key_status_to_str(pgp_key_import_status_t status) +{ + if (status == PGP_KEY_IMPORT_STATUS_UNKNOWN) { + return "none"; + } + return id_str_pair::lookup(key_import_status_map, status, "none"); +} + +static rnp_result_t +add_key_status(json_object * keys, + const pgp_key_t * key, + pgp_key_import_status_t pub, + pgp_key_import_status_t sec) +{ + json_object *jsokey = json_object_new_object(); + if (!jsokey) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (!obj_add_field_json( + jsokey, "public", json_object_new_string(key_status_to_str(pub))) || + !obj_add_field_json( + jsokey, "secret", json_object_new_string(key_status_to_str(sec))) || + !obj_add_hex_json(jsokey, "fingerprint", key->fp().fingerprint, key->fp().length) || + !array_add_element_json(keys, jsokey)) { + json_object_put(jsokey); + return RNP_ERROR_OUT_OF_MEMORY; + } + + return RNP_SUCCESS; +} + +rnp_result_t +rnp_import_keys(rnp_ffi_t ffi, rnp_input_t input, uint32_t flags, char **results) +try { + if (!ffi || !input) { + return RNP_ERROR_NULL_POINTER; + } + bool sec = extract_flag(flags, RNP_LOAD_SAVE_SECRET_KEYS); + bool pub = extract_flag(flags, RNP_LOAD_SAVE_PUBLIC_KEYS); + if (!pub && !sec) { + FFI_LOG(ffi, "bad flags: need to specify public and/or secret keys"); + return RNP_ERROR_BAD_PARAMETERS; + } + bool skipbad = extract_flag(flags, RNP_LOAD_SAVE_PERMISSIVE); + bool single = extract_flag(flags, RNP_LOAD_SAVE_SINGLE); + bool base64 = extract_flag(flags, RNP_LOAD_SAVE_BASE64); + if (flags) { + FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + rnp_key_store_t tmp_store(PGP_KEY_STORE_GPG, "", ffi->context); + + /* check whether input is base64 */ + if (base64 && is_base64_source(input->src)) { + ret = rnp_input_dearmor_if_needed(input, true); + if (ret) { + return ret; + } + } + + // load keys to temporary keystore. + if (single) { + /* we need to init and handle dearmor on this layer since it may be used for the next + * keys import */ + ret = rnp_input_dearmor_if_needed(input); + if (ret == RNP_ERROR_EOF) { + return ret; + } + if (ret) { + FFI_LOG(ffi, "Failed to init/check dearmor."); + return ret; + } + ret = rnp_key_store_pgp_read_key_from_src(tmp_store, input->src, skipbad); + if (ret) { + return ret; + } + } else { + ret = rnp_key_store_pgp_read_from_src(&tmp_store, &input->src, skipbad); + if (ret) { + return ret; + } + } + + json_object *jsores = json_object_new_object(); + if (!jsores) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp::JSONObject jsowrap(jsores); + json_object * jsokeys = json_object_new_array(); + if (!obj_add_field_json(jsores, "keys", jsokeys)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + // import keys to the main keystore. + for (auto &key : tmp_store.keys) { + pgp_key_import_status_t pub_status = PGP_KEY_IMPORT_STATUS_UNKNOWN; + pgp_key_import_status_t sec_status = PGP_KEY_IMPORT_STATUS_UNKNOWN; + if (!pub && key.is_public()) { + continue; + } + // if we got here then we add public key itself or public part of the secret key + if (!rnp_key_store_import_key(ffi->pubring, &key, true, &pub_status)) { + return RNP_ERROR_BAD_PARAMETERS; + } + // import secret key part if available and requested + if (sec && key.is_secret()) { + if (!rnp_key_store_import_key(ffi->secring, &key, false, &sec_status)) { + return RNP_ERROR_BAD_PARAMETERS; + } + // add uids, certifications and other stuff from the public key if any + pgp_key_t *expub = rnp_key_store_get_key_by_fpr(ffi->pubring, key.fp()); + if (expub && !rnp_key_store_import_key(ffi->secring, expub, true, NULL)) { + return RNP_ERROR_BAD_PARAMETERS; + } + } + // now add key fingerprint to json based on statuses + rnp_result_t tmpret = add_key_status(jsokeys, &key, pub_status, sec_status); + if (tmpret) { + return tmpret; + } + } + + if (results) { + *results = (char *) json_object_to_json_string_ext(jsores, JSON_C_TO_STRING_PRETTY); + if (!*results) { + return RNP_ERROR_GENERIC; + } + *results = strdup(*results); + if (!*results) { + return RNP_ERROR_OUT_OF_MEMORY; + } + } + return RNP_SUCCESS; +} +FFI_GUARD + +static const char * +sig_status_to_str(pgp_sig_import_status_t status) +{ + if (status == PGP_SIG_IMPORT_STATUS_UNKNOWN) { + return "none"; + } + return id_str_pair::lookup(sig_import_status_map, status, "none"); +} + +static rnp_result_t +add_sig_status(json_object * sigs, + const pgp_key_t * signer, + pgp_sig_import_status_t pub, + pgp_sig_import_status_t sec) +{ + json_object *jsosig = json_object_new_object(); + if (!jsosig) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (!obj_add_field_json( + jsosig, "public", json_object_new_string(sig_status_to_str(pub))) || + !obj_add_field_json( + jsosig, "secret", json_object_new_string(sig_status_to_str(sec)))) { + json_object_put(jsosig); + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (signer) { + const pgp_fingerprint_t &fp = signer->fp(); + if (!obj_add_hex_json(jsosig, "signer fingerprint", fp.fingerprint, fp.length)) { + json_object_put(jsosig); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + + if (!array_add_element_json(sigs, jsosig)) { + json_object_put(jsosig); + return RNP_ERROR_OUT_OF_MEMORY; + } + + return RNP_SUCCESS; +} + +rnp_result_t +rnp_import_signatures(rnp_ffi_t ffi, rnp_input_t input, uint32_t flags, char **results) +try { + if (!ffi || !input) { + return RNP_ERROR_NULL_POINTER; + } + if (flags) { + FFI_LOG(ffi, "wrong flags: %d", (int) flags); + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_signature_list_t sigs; + rnp_result_t sigret = process_pgp_signatures(input->src, sigs); + if (sigret) { + FFI_LOG(ffi, "failed to parse signature(s)"); + return sigret; + } + + json_object *jsores = json_object_new_object(); + if (!jsores) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp::JSONObject jsowrap(jsores); + json_object * jsosigs = json_object_new_array(); + if (!obj_add_field_json(jsores, "sigs", jsosigs)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + for (auto &sig : sigs) { + pgp_sig_import_status_t pub_status = PGP_SIG_IMPORT_STATUS_UNKNOWN; + pgp_sig_import_status_t sec_status = PGP_SIG_IMPORT_STATUS_UNKNOWN; + pgp_key_t *pkey = rnp_key_store_import_signature(ffi->pubring, &sig, &pub_status); + pgp_key_t *skey = rnp_key_store_import_signature(ffi->secring, &sig, &sec_status); + sigret = add_sig_status(jsosigs, pkey ? pkey : skey, pub_status, sec_status); + if (sigret) { + return sigret; + } + } + + if (results) { + *results = (char *) json_object_to_json_string_ext(jsores, JSON_C_TO_STRING_PRETTY); + if (!*results) { + return RNP_ERROR_OUT_OF_MEMORY; + } + *results = strdup(*results); + if (!*results) { + return RNP_ERROR_OUT_OF_MEMORY; + } + } + return RNP_SUCCESS; +} +FFI_GUARD + +static bool +copy_store_keys(rnp_ffi_t ffi, rnp_key_store_t *dest, rnp_key_store_t *src) +{ + for (auto &key : src->keys) { + if (!rnp_key_store_add_key(dest, &key)) { + FFI_LOG(ffi, "failed to add key to the store"); + return false; + } + } + return true; +} + +static rnp_result_t +do_save_keys(rnp_ffi_t ffi, + rnp_output_t output, + pgp_key_store_format_t format, + key_type_t key_type) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + + // create a temporary key store to hold the keys + rnp_key_store_t *tmp_store = NULL; + try { + tmp_store = new rnp_key_store_t(format, "", ffi->context); + } catch (const std::invalid_argument &e) { + FFI_LOG(ffi, "Failed to create key store of format: %d", (int) format); + return RNP_ERROR_BAD_PARAMETERS; + } catch (const std::exception &e) { + FFI_LOG(ffi, "%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + // include the public keys, if desired + if (key_type == KEY_TYPE_PUBLIC || key_type == KEY_TYPE_ANY) { + if (!copy_store_keys(ffi, tmp_store, ffi->pubring)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + } + // include the secret keys, if desired + if (key_type == KEY_TYPE_SECRET || key_type == KEY_TYPE_ANY) { + if (!copy_store_keys(ffi, tmp_store, ffi->secring)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + } + // preliminary check on the format + for (auto &key : tmp_store->keys) { + if (key_needs_conversion(&key, tmp_store)) { + FFI_LOG(ffi, "This key format conversion is not yet supported"); + ret = RNP_ERROR_NOT_IMPLEMENTED; + goto done; + } + } + // write + if (output->dst_directory) { + try { + tmp_store->path = output->dst_directory; + } catch (const std::exception &e) { + FFI_LOG(ffi, "%s", e.what()); + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + if (!rnp_key_store_write_to_path(tmp_store)) { + ret = RNP_ERROR_WRITE; + goto done; + } + ret = RNP_SUCCESS; + } else { + if (!rnp_key_store_write_to_dst(tmp_store, &output->dst)) { + ret = RNP_ERROR_WRITE; + goto done; + } + dst_flush(&output->dst); + output->keep = (output->dst.werr == RNP_SUCCESS); + ret = output->dst.werr; + } + +done: + delete tmp_store; + return ret; +} + +rnp_result_t +rnp_save_keys(rnp_ffi_t ffi, const char *format, rnp_output_t output, uint32_t flags) +try { + // checks + if (!ffi || !format || !output) { + return RNP_ERROR_NULL_POINTER; + } + key_type_t type = flags_to_key_type(&flags); + if (!type) { + FFI_LOG(ffi, "invalid flags - must have public and/or secret keys"); + return RNP_ERROR_BAD_PARAMETERS; + } + // check for any unrecognized flags (not forward-compat, but maybe still a good idea) + if (flags) { + FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_store_format_t ks_format = PGP_KEY_STORE_UNKNOWN; + if (!parse_ks_format(&ks_format, format)) { + FFI_LOG(ffi, "unknown key store format: %s", format); + return RNP_ERROR_BAD_PARAMETERS; + } + return do_save_keys(ffi, output, ks_format, type); +} +FFI_GUARD + +rnp_result_t +rnp_get_public_key_count(rnp_ffi_t ffi, size_t *count) +try { + if (!ffi || !count) { + return RNP_ERROR_NULL_POINTER; + } + *count = rnp_key_store_get_key_count(ffi->pubring); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_get_secret_key_count(rnp_ffi_t ffi, size_t *count) +try { + if (!ffi || !count) { + return RNP_ERROR_NULL_POINTER; + } + *count = rnp_key_store_get_key_count(ffi->secring); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_input_st::rnp_input_st() : reader(NULL), closer(NULL), app_ctx(NULL) +{ + memset(&src, 0, sizeof(src)); +} + +rnp_input_st & +rnp_input_st::operator=(rnp_input_st &&input) +{ + src_close(&src); + src = std::move(input.src); + memset(&input.src, 0, sizeof(input.src)); + reader = input.reader; + input.reader = NULL; + closer = input.closer; + input.closer = NULL; + app_ctx = input.app_ctx; + input.app_ctx = NULL; + src_directory = std::move(input.src_directory); + return *this; +} + +rnp_input_st::~rnp_input_st() +{ + bool armored = src.type == PGP_STREAM_ARMORED; + src_close(&src); + if (armored) { + rnp_input_t armored = (rnp_input_t) app_ctx; + delete armored; + app_ctx = NULL; + } +} + +rnp_result_t +rnp_input_from_path(rnp_input_t *input, const char *path) +try { + if (!input || !path) { + return RNP_ERROR_NULL_POINTER; + } + rnp_input_st *ob = new rnp_input_st(); + struct stat st = {0}; + if (rnp_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { + // a bit hacky, just save the directory path + ob->src_directory = path; + // return error on attempt to read from this source + (void) init_null_src(&ob->src); + } else { + // simple input from a file + rnp_result_t ret = init_file_src(&ob->src, path); + if (ret) { + delete ob; + return ret; + } + } + *input = ob; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_input_from_stdin(rnp_input_t *input) +try { + if (!input) { + return RNP_ERROR_NULL_POINTER; + } + *input = new rnp_input_st(); + rnp_result_t ret = init_stdin_src(&(*input)->src); + if (ret) { + delete *input; + *input = NULL; + return ret; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_input_from_memory(rnp_input_t *input, const uint8_t buf[], size_t buf_len, bool do_copy) +try { + if (!input || !buf) { + return RNP_ERROR_NULL_POINTER; + } + if (!buf_len) { + return RNP_ERROR_SHORT_BUFFER; + } + *input = new rnp_input_st(); + uint8_t *data = (uint8_t *) buf; + if (do_copy) { + data = (uint8_t *) malloc(buf_len); + if (!data) { + delete *input; + *input = NULL; + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(data, buf, buf_len); + } + rnp_result_t ret = init_mem_src(&(*input)->src, data, buf_len, do_copy); + if (ret) { + if (do_copy) { + free(data); + } + delete *input; + *input = NULL; + return ret; + } + return RNP_SUCCESS; +} +FFI_GUARD + +static bool +input_reader_bounce(pgp_source_t *src, void *buf, size_t len, size_t *read) +{ + rnp_input_t input = (rnp_input_t) src->param; + if (!input->reader) { + return false; + } + return input->reader(input->app_ctx, buf, len, read); +} + +static void +input_closer_bounce(pgp_source_t *src) +{ + rnp_input_t input = (rnp_input_t) src->param; + if (input->closer) { + input->closer(input->app_ctx); + } +} + +rnp_result_t +rnp_input_from_callback(rnp_input_t * input, + rnp_input_reader_t *reader, + rnp_input_closer_t *closer, + void * app_ctx) +try { + // checks + if (!input || !reader) { + return RNP_ERROR_NULL_POINTER; + } + rnp_input_st *obj = new rnp_input_st(); + pgp_source_t *src = &obj->src; + obj->reader = reader; + obj->closer = closer; + obj->app_ctx = app_ctx; + if (!init_src_common(src, 0)) { + delete obj; + return RNP_ERROR_OUT_OF_MEMORY; + } + src->param = obj; + src->read = input_reader_bounce; + src->close = input_closer_bounce; + src->type = PGP_STREAM_MEMORY; + *input = obj; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_input_destroy(rnp_input_t input) +try { + delete input; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_to_path(rnp_output_t *output, const char *path) +try { + struct rnp_output_st *ob = NULL; + struct stat st = {0}; + + if (!output || !path) { + return RNP_ERROR_NULL_POINTER; + } + ob = (rnp_output_st *) calloc(1, sizeof(*ob)); + if (!ob) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (rnp_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { + // a bit hacky, just save the directory path + ob->dst_directory = strdup(path); + if (!ob->dst_directory) { + free(ob); + return RNP_ERROR_OUT_OF_MEMORY; + } + } else { + // simple output to a file + rnp_result_t ret = init_file_dest(&ob->dst, path, true); + if (ret) { + free(ob); + return ret; + } + } + *output = ob; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_to_file(rnp_output_t *output, const char *path, uint32_t flags) +try { + if (!output || !path) { + return RNP_ERROR_NULL_POINTER; + } + bool overwrite = extract_flag(flags, RNP_OUTPUT_FILE_OVERWRITE); + bool random = extract_flag(flags, RNP_OUTPUT_FILE_RANDOM); + if (flags) { + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_output_t res = (rnp_output_t) calloc(1, sizeof(*res)); + if (!res) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t ret = RNP_ERROR_GENERIC; + if (random) { + ret = init_tmpfile_dest(&res->dst, path, overwrite); + } else { + ret = init_file_dest(&res->dst, path, overwrite); + } + if (ret) { + free(res); + return ret; + } + *output = res; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_to_stdout(rnp_output_t *output) +try { + if (!output) { + return RNP_ERROR_NULL_POINTER; + } + rnp_output_t res = (rnp_output_t) calloc(1, sizeof(*res)); + if (!res) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t ret = init_stdout_dest(&res->dst); + if (ret) { + free(res); + return ret; + } + *output = res; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_to_memory(rnp_output_t *output, size_t max_alloc) +try { + // checks + if (!output) { + return RNP_ERROR_NULL_POINTER; + } + + *output = (rnp_output_t) calloc(1, sizeof(**output)); + if (!*output) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t ret = init_mem_dest(&(*output)->dst, NULL, max_alloc); + if (ret) { + free(*output); + *output = NULL; + return ret; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_to_armor(rnp_output_t base, rnp_output_t *output, const char *type) +try { + if (!base || !output) { + return RNP_ERROR_NULL_POINTER; + } + pgp_armored_msg_t msgtype = PGP_ARMORED_MESSAGE; + if (type) { + msgtype = static_cast( + id_str_pair::lookup(armor_type_map, type, PGP_ARMORED_UNKNOWN)); + if (msgtype == PGP_ARMORED_UNKNOWN) { + RNP_LOG("Unsupported armor type: %s", type); + return RNP_ERROR_BAD_PARAMETERS; + } + } + *output = (rnp_output_t) calloc(1, sizeof(**output)); + if (!*output) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t ret = init_armored_dst(&(*output)->dst, &base->dst, msgtype); + if (ret) { + free(*output); + *output = NULL; + return ret; + } + (*output)->app_ctx = base; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_memory_get_buf(rnp_output_t output, uint8_t **buf, size_t *len, bool do_copy) +try { + if (!output || !buf || !len) { + return RNP_ERROR_NULL_POINTER; + } + + *len = output->dst.writeb; + *buf = (uint8_t *) mem_dest_get_memory(&output->dst); + if (!*buf) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (do_copy) { + uint8_t *tmp_buf = *buf; + *buf = (uint8_t *) malloc(*len); + if (!*buf) { + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(*buf, tmp_buf, *len); + } + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +output_writer_bounce(pgp_dest_t *dst, const void *buf, size_t len) +{ + rnp_output_t output = (rnp_output_t) dst->param; + if (!output->writer) { + return RNP_ERROR_NULL_POINTER; + } + if (!output->writer(output->app_ctx, buf, len)) { + return RNP_ERROR_WRITE; + } + return RNP_SUCCESS; +} + +static void +output_closer_bounce(pgp_dest_t *dst, bool discard) +{ + rnp_output_t output = (rnp_output_t) dst->param; + if (output->closer) { + output->closer(output->app_ctx, discard); + } +} + +rnp_result_t +rnp_output_to_null(rnp_output_t *output) +try { + // checks + if (!output) { + return RNP_ERROR_NULL_POINTER; + } + + *output = (rnp_output_t) calloc(1, sizeof(**output)); + if (!*output) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t ret = init_null_dest(&(*output)->dst); + if (ret) { + free(*output); + *output = NULL; + return ret; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_write(rnp_output_t output, const void *data, size_t size, size_t *written) +try { + if (!output || (!data && size)) { + return RNP_ERROR_NULL_POINTER; + } + if (!data && !size) { + if (written) { + *written = 0; + } + return RNP_SUCCESS; + } + size_t old = output->dst.writeb + output->dst.clen; + dst_write(&output->dst, data, size); + if (!output->dst.werr && written) { + *written = output->dst.writeb + output->dst.clen - old; + } + output->keep = !output->dst.werr; + return output->dst.werr; +} +FFI_GUARD + +rnp_result_t +rnp_output_to_callback(rnp_output_t * output, + rnp_output_writer_t *writer, + rnp_output_closer_t *closer, + void * app_ctx) +try { + // checks + if (!output || !writer) { + return RNP_ERROR_NULL_POINTER; + } + + *output = (rnp_output_t) calloc(1, sizeof(**output)); + if (!*output) { + return RNP_ERROR_OUT_OF_MEMORY; + } + (*output)->writer = writer; + (*output)->closer = closer; + (*output)->app_ctx = app_ctx; + + pgp_dest_t *dst = &(*output)->dst; + dst->write = output_writer_bounce; + dst->close = output_closer_bounce; + dst->param = *output; + dst->type = PGP_STREAM_MEMORY; + dst->writeb = 0; + dst->werr = RNP_SUCCESS; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_output_finish(rnp_output_t output) +try { + if (!output) { + return RNP_ERROR_NULL_POINTER; + } + return dst_finish(&output->dst); +} +FFI_GUARD + +rnp_result_t +rnp_output_destroy(rnp_output_t output) +try { + if (output) { + if (output->dst.type == PGP_STREAM_ARMORED) { + ((rnp_output_t) output->app_ctx)->keep = output->keep; + } + dst_close(&output->dst, !output->keep); + free(output->dst_directory); + free(output); + } + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +rnp_op_add_signature(rnp_ffi_t ffi, + rnp_op_sign_signatures_t &signatures, + rnp_key_handle_t key, + rnp_ctx_t & ctx, + rnp_op_sign_signature_t * sig) +{ + if (!key) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *signkey = + find_suitable_key(PGP_OP_SIGN, get_key_require_secret(key), &key->ffi->key_provider); + if (!signkey) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + + try { + signatures.emplace_back(); + } catch (const std::exception &e) { + FFI_LOG(ffi, "%s", e.what()); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_op_sign_signature_t newsig = &signatures.back(); + newsig->signer.key = signkey; + /* set default create/expire times */ + newsig->signer.sigcreate = ctx.sigcreate; + newsig->signer.sigexpire = ctx.sigexpire; + newsig->ffi = ffi; + + if (sig) { + *sig = newsig; + } + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_armor(rnp_ctx_t &ctx, bool armored) +{ + ctx.armor = armored; + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_compression(rnp_ffi_t ffi, rnp_ctx_t &ctx, const char *compression, int level) +{ + if (!compression) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_compression_type_t zalg = PGP_C_UNKNOWN; + if (!str_to_compression_alg(compression, &zalg)) { + FFI_LOG(ffi, "Invalid compression: %s", compression); + return RNP_ERROR_BAD_PARAMETERS; + } + ctx.zalg = (int) zalg; + ctx.zlevel = level; + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_hash(rnp_ffi_t ffi, rnp_ctx_t &ctx, const char *hash) +{ + if (!hash) { + return RNP_ERROR_NULL_POINTER; + } + + if (!str_to_hash_alg(hash, &ctx.halg)) { + FFI_LOG(ffi, "Invalid hash: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_creation_time(rnp_ctx_t &ctx, uint32_t create) +{ + ctx.sigcreate = create; + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_expiration_time(rnp_ctx_t &ctx, uint32_t expire) +{ + ctx.sigexpire = expire; + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_flags(rnp_ffi_t ffi, rnp_ctx_t &ctx, uint32_t flags) +{ + ctx.no_wrap = extract_flag(flags, RNP_ENCRYPT_NOWRAP); + if (flags) { + FFI_LOG(ffi, "Unknown operation flags: %x", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_file_name(rnp_ctx_t &ctx, const char *filename) +{ + ctx.filename = filename ? filename : ""; + return RNP_SUCCESS; +} + +static rnp_result_t +rnp_op_set_file_mtime(rnp_ctx_t &ctx, uint32_t mtime) +{ + ctx.filemtime = mtime; + return RNP_SUCCESS; +} + +rnp_result_t +rnp_op_encrypt_create(rnp_op_encrypt_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output) +try { + // checks + if (!op || !ffi || !input || !output) { + return RNP_ERROR_NULL_POINTER; + } + + *op = new rnp_op_encrypt_st(); + rnp_ctx_init_ffi((*op)->rnpctx, ffi); + (*op)->ffi = ffi; + (*op)->input = input; + (*op)->output = output; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_handle_t handle) +try { + // checks + if (!op || !handle) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = find_suitable_key( + PGP_OP_ENCRYPT, get_key_prefer_public(handle), &handle->ffi->key_provider); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + op->rnpctx.recipients.push_back(key); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_add_signature(rnp_op_encrypt_t op, + rnp_key_handle_t key, + rnp_op_sign_signature_t *sig) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_add_signature(op->ffi, op->signatures, key, op->rnpctx, sig); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_hash(rnp_op_encrypt_t op, const char *hash) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_hash(op->ffi, op->rnpctx, hash); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_creation_time(rnp_op_encrypt_t op, uint32_t create) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_creation_time(op->rnpctx, create); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_expiration_time(rnp_op_encrypt_t op, uint32_t expire) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_expiration_time(op->rnpctx, expire); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_add_password(rnp_op_encrypt_t op, + const char * password, + const char * s2k_hash, + size_t iterations, + const char * s2k_cipher) +try { + // checks + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (password && !*password) { + // no blank passwords + FFI_LOG(op->ffi, "Blank password"); + return RNP_ERROR_BAD_PARAMETERS; + } + + // set some defaults + if (!s2k_hash) { + s2k_hash = DEFAULT_HASH_ALG; + } + if (!s2k_cipher) { + s2k_cipher = DEFAULT_SYMM_ALG; + } + // parse + pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(s2k_hash, &hash_alg)) { + FFI_LOG(op->ffi, "Invalid hash: %s", s2k_hash); + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN; + if (!str_to_cipher(s2k_cipher, &symm_alg)) { + FFI_LOG(op->ffi, "Invalid cipher: %s", s2k_cipher); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp::secure_vector ask_pass(MAX_PASSWORD_LENGTH, '\0'); + if (!password) { + pgp_password_ctx_t pswdctx(PGP_OP_ENCRYPT_SYM); + if (!pgp_request_password( + &op->ffi->pass_provider, &pswdctx, ask_pass.data(), ask_pass.size())) { + return RNP_ERROR_BAD_PASSWORD; + } + password = ask_pass.data(); + } + return op->rnpctx.add_encryption_password(password, hash_alg, symm_alg, iterations); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_armor(rnp_op_encrypt_t op, bool armored) +try { + // checks + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_armor(op->rnpctx, armored); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_cipher(rnp_op_encrypt_t op, const char *cipher) +try { + // checks + if (!op || !cipher) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_cipher(cipher, &op->rnpctx.ealg)) { + FFI_LOG(op->ffi, "Invalid cipher: %s", cipher); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_aead(rnp_op_encrypt_t op, const char *alg) +try { + // checks + if (!op || !alg) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_aead_alg(alg, &op->rnpctx.aalg)) { + FFI_LOG(op->ffi, "Invalid AEAD algorithm: %s", alg); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_aead_bits(rnp_op_encrypt_t op, int bits) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if ((bits < 0) || (bits > 16)) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->rnpctx.abits = bits; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_compression(rnp_op_encrypt_t op, const char *compression, int level) +try { + // checks + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_compression(op->ffi, op->rnpctx, compression, level); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_flags(rnp_op_encrypt_t op, uint32_t flags) +try { + // checks + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_flags(op->ffi, op->rnpctx, flags); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_file_name(rnp_op_encrypt_t op, const char *filename) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_file_name(op->rnpctx, filename); +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_set_file_mtime(rnp_op_encrypt_t op, uint32_t mtime) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_file_mtime(op->rnpctx, mtime); +} +FFI_GUARD + +static pgp_write_handler_t +pgp_write_handler(pgp_password_provider_t *pass_provider, + rnp_ctx_t * rnpctx, + void * param, + pgp_key_provider_t * key_provider) +{ + pgp_write_handler_t handler; + memset(&handler, 0, sizeof(handler)); + handler.password_provider = pass_provider; + handler.ctx = rnpctx; + handler.param = param; + handler.key_provider = key_provider; + return handler; +} + +static rnp_result_t +rnp_op_add_signatures(rnp_op_sign_signatures_t &opsigs, rnp_ctx_t &ctx) +{ + for (auto &sig : opsigs) { + if (!sig.signer.key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + + rnp_signer_info_t sinfo = sig.signer; + if (!sig.hash_set) { + sinfo.halg = ctx.halg; + } + if (!sig.expiry_set) { + sinfo.sigexpire = ctx.sigexpire; + } + if (!sig.create_set) { + sinfo.sigcreate = ctx.sigcreate; + } + ctx.signers.push_back(sinfo); + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_op_encrypt_execute(rnp_op_encrypt_t op) +try { + // checks + if (!op || !op->input || !op->output) { + return RNP_ERROR_NULL_POINTER; + } + + // set the default hash alg if none was specified + if (!op->rnpctx.halg) { + op->rnpctx.halg = DEFAULT_PGP_HASH_ALG; + } + pgp_write_handler_t handler = + pgp_write_handler(&op->ffi->pass_provider, &op->rnpctx, NULL, &op->ffi->key_provider); + + rnp_result_t ret; + if (!op->signatures.empty() && (ret = rnp_op_add_signatures(op->signatures, op->rnpctx))) { + return ret; + } + ret = rnp_encrypt_sign_src(&handler, &op->input->src, &op->output->dst); + + dst_flush(&op->output->dst); + op->output->keep = ret == RNP_SUCCESS; + op->input = NULL; + op->output = NULL; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_op_encrypt_destroy(rnp_op_encrypt_t op) +try { + delete op; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_create(rnp_op_sign_t *op, rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output) +try { + // checks + if (!op || !ffi || !input || !output) { + return RNP_ERROR_NULL_POINTER; + } + + *op = new rnp_op_sign_st(); + rnp_ctx_init_ffi((*op)->rnpctx, ffi); + (*op)->ffi = ffi; + (*op)->input = input; + (*op)->output = output; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_cleartext_create(rnp_op_sign_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output) +try { + rnp_result_t res = rnp_op_sign_create(op, ffi, input, output); + if (!res) { + (*op)->rnpctx.clearsign = true; + } + return res; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_detached_create(rnp_op_sign_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t signature) +try { + rnp_result_t res = rnp_op_sign_create(op, ffi, input, signature); + if (!res) { + (*op)->rnpctx.detached = true; + } + return res; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_add_signature(rnp_op_sign_t op, rnp_key_handle_t key, rnp_op_sign_signature_t *sig) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_add_signature(op->ffi, op->signatures, key, op->rnpctx, sig); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_signature_set_hash(rnp_op_sign_signature_t sig, const char *hash) +try { + if (!sig || !hash) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_hash_alg(hash, &sig->signer.halg)) { + FFI_LOG(sig->ffi, "Invalid hash: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + sig->hash_set = true; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_signature_set_creation_time(rnp_op_sign_signature_t sig, uint32_t create) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + sig->signer.sigcreate = create; + sig->create_set = true; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_signature_set_expiration_time(rnp_op_sign_signature_t sig, uint32_t expires) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + sig->signer.sigexpire = expires; + sig->expiry_set = true; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_armor(rnp_op_sign_t op, bool armored) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_armor(op->rnpctx, armored); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_compression(rnp_op_sign_t op, const char *compression, int level) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_compression(op->ffi, op->rnpctx, compression, level); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_hash(rnp_op_sign_t op, const char *hash) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_hash(op->ffi, op->rnpctx, hash); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_creation_time(rnp_op_sign_t op, uint32_t create) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_creation_time(op->rnpctx, create); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_expiration_time(rnp_op_sign_t op, uint32_t expire) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_expiration_time(op->rnpctx, expire); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_file_name(rnp_op_sign_t op, const char *filename) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_file_name(op->rnpctx, filename); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_set_file_mtime(rnp_op_sign_t op, uint32_t mtime) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + return rnp_op_set_file_mtime(op->rnpctx, mtime); +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_execute(rnp_op_sign_t op) +try { + // checks + if (!op || !op->input || !op->output) { + return RNP_ERROR_NULL_POINTER; + } + + // set the default hash alg if none was specified + if (!op->rnpctx.halg) { + op->rnpctx.halg = DEFAULT_PGP_HASH_ALG; + } + pgp_write_handler_t handler = + pgp_write_handler(&op->ffi->pass_provider, &op->rnpctx, NULL, &op->ffi->key_provider); + + rnp_result_t ret; + if ((ret = rnp_op_add_signatures(op->signatures, op->rnpctx))) { + return ret; + } + ret = rnp_sign_src(&handler, &op->input->src, &op->output->dst); + + dst_flush(&op->output->dst); + op->output->keep = ret == RNP_SUCCESS; + op->input = NULL; + op->output = NULL; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_op_sign_destroy(rnp_op_sign_t op) +try { + delete op; + return RNP_SUCCESS; +} +FFI_GUARD + +static void +rnp_op_verify_on_signatures(const std::vector &sigs, void *param) +{ + rnp_op_verify_t op = (rnp_op_verify_t) param; + + try { + /* in case we have multiple signed layers */ + delete[] op->signatures; + op->signatures = new rnp_op_verify_signature_st[sigs.size()]; + } catch (const std::exception &e) { + FFI_LOG(op->ffi, "%s", e.what()); + return; + } + op->signature_count = sigs.size(); + + size_t i = 0; + for (const auto &sinfo : sigs) { + rnp_op_verify_signature_t res = &op->signatures[i++]; + /* sinfo.sig may be NULL */ + if (sinfo.sig) { + try { + res->sig_pkt = *sinfo.sig; + } catch (const std::exception &e) { + FFI_LOG(op->ffi, "%s", e.what()); + } + } + + if (sinfo.unknown) { + res->verify_status = RNP_ERROR_SIGNATURE_UNKNOWN; + } else if (sinfo.valid) { + res->verify_status = sinfo.expired ? RNP_ERROR_SIGNATURE_EXPIRED : RNP_SUCCESS; + } else { + res->verify_status = + sinfo.no_signer ? RNP_ERROR_KEY_NOT_FOUND : RNP_ERROR_SIGNATURE_INVALID; + } + res->ffi = op->ffi; + } +} + +static bool +rnp_verify_src_provider(pgp_parse_handler_t *handler, pgp_source_t *src) +{ + /* this one is called only when input for detached signature is needed */ + rnp_op_verify_t op = (rnp_op_verify_t) handler->param; + if (!op->detached_input) { + return false; + } + *src = op->detached_input->src; + /* we should give ownership on src to caller */ + memset(&op->detached_input->src, 0, sizeof(op->detached_input->src)); + return true; +}; + +static bool +rnp_verify_dest_provider(pgp_parse_handler_t *handler, + pgp_dest_t ** dst, + bool * closedst, + const char * filename, + uint32_t mtime) +{ + rnp_op_verify_t op = (rnp_op_verify_t) handler->param; + if (!op->output) { + return false; + } + *dst = &(op->output->dst); + *closedst = false; + op->filename = filename ? strdup(filename) : NULL; + op->file_mtime = mtime; + return true; +} + +static void +recipient_handle_from_pk_sesskey(rnp_recipient_handle_t handle, + const pgp_pk_sesskey_t &sesskey) +{ + static_assert(sizeof(handle->keyid) == PGP_KEY_ID_SIZE, "Keyid size mismatch"); + memcpy(handle->keyid, sesskey.key_id.data(), PGP_KEY_ID_SIZE); + handle->palg = sesskey.alg; +} + +static void +symenc_handle_from_sk_sesskey(rnp_symenc_handle_t handle, const pgp_sk_sesskey_t &sesskey) +{ + handle->alg = sesskey.alg; + handle->halg = sesskey.s2k.hash_alg; + handle->s2k_type = sesskey.s2k.specifier; + if (sesskey.s2k.specifier == PGP_S2KS_ITERATED_AND_SALTED) { + handle->iterations = pgp_s2k_decode_iterations(sesskey.s2k.iterations); + } else { + handle->iterations = 1; + } + handle->aalg = sesskey.aalg; +} + +static void +rnp_verify_on_recipients(const std::vector &recipients, + const std::vector &passwords, + void * param) +{ + rnp_op_verify_t op = (rnp_op_verify_t) param; + /* store only top-level encrypted stream recipients info for now */ + if (op->encrypted_layers++) { + return; + } + if (!recipients.empty()) { + op->recipients = + (rnp_recipient_handle_t) calloc(recipients.size(), sizeof(*op->recipients)); + if (!op->recipients) { + FFI_LOG(op->ffi, "allocation failed"); + return; + } + for (size_t i = 0; i < recipients.size(); i++) { + recipient_handle_from_pk_sesskey(&op->recipients[i], recipients[i]); + } + } + op->recipient_count = recipients.size(); + if (!passwords.empty()) { + op->symencs = (rnp_symenc_handle_t) calloc(passwords.size(), sizeof(*op->symencs)); + if (!op->symencs) { + FFI_LOG(op->ffi, "allocation failed"); + return; + } + for (size_t i = 0; i < passwords.size(); i++) { + symenc_handle_from_sk_sesskey(&op->symencs[i], passwords[i]); + } + } + op->symenc_count = passwords.size(); +} + +static void +rnp_verify_on_decryption_start(pgp_pk_sesskey_t *pubenc, pgp_sk_sesskey_t *symenc, void *param) +{ + rnp_op_verify_t op = (rnp_op_verify_t) param; + /* store only top-level encrypted stream info */ + if (op->encrypted_layers > 1) { + return; + } + if (pubenc) { + op->used_recipient = (rnp_recipient_handle_t) calloc(1, sizeof(*op->used_recipient)); + if (!op->used_recipient) { + FFI_LOG(op->ffi, "allocation failed"); + return; + } + recipient_handle_from_pk_sesskey(op->used_recipient, *pubenc); + return; + } + if (symenc) { + op->used_symenc = (rnp_symenc_handle_t) calloc(1, sizeof(*op->used_symenc)); + if (!op->used_symenc) { + FFI_LOG(op->ffi, "allocation failed"); + return; + } + symenc_handle_from_sk_sesskey(op->used_symenc, *symenc); + return; + } + FFI_LOG(op->ffi, "Warning! Both pubenc and symenc are NULL."); +} + +static void +rnp_verify_on_decryption_info(bool mdc, pgp_aead_alg_t aead, pgp_symm_alg_t salg, void *param) +{ + rnp_op_verify_t op = (rnp_op_verify_t) param; + /* store only top-level encrypted stream info for now */ + if (op->encrypted_layers > 1) { + return; + } + op->mdc = mdc; + op->aead = aead; + op->salg = salg; + op->encrypted = true; +} + +static void +rnp_verify_on_decryption_done(bool validated, void *param) +{ + rnp_op_verify_t op = (rnp_op_verify_t) param; + if (op->encrypted_layers > 1) { + return; + } + op->validated = validated; +} + +rnp_result_t +rnp_op_verify_create(rnp_op_verify_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_output_t output) +try { + if (!op || !ffi || !input || !output) { + return RNP_ERROR_NULL_POINTER; + } + + *op = new rnp_op_verify_st(); + rnp_ctx_init_ffi((*op)->rnpctx, ffi); + (*op)->ffi = ffi; + (*op)->input = input; + (*op)->output = output; + + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_detached_create(rnp_op_verify_t *op, + rnp_ffi_t ffi, + rnp_input_t input, + rnp_input_t signature) +try { + if (!op || !ffi || !input || !signature) { + return RNP_ERROR_NULL_POINTER; + } + + *op = new rnp_op_verify_st(); + rnp_ctx_init_ffi((*op)->rnpctx, ffi); + (*op)->rnpctx.detached = true; + (*op)->ffi = ffi; + (*op)->input = signature; + (*op)->detached_input = input; + + return RNP_SUCCESS; +} +FFI_GUARD + +static pgp_key_t * +ffi_decrypt_key_provider(const pgp_key_request_ctx_t *ctx, void *userdata) +{ + rnp_decryption_kp_param_t *kparam = (rnp_decryption_kp_param_t *) userdata; + + auto ffi = kparam->op->ffi; + bool hidden = ctx->secret && (ctx->search.type == PGP_KEY_SEARCH_KEYID) && + (ctx->search.by.keyid == pgp_key_id_t({})); + /* default to the FFI key provider if not hidden keyid request */ + if (!hidden) { + return ffi->key_provider.callback(ctx, ffi->key_provider.userdata); + } + /* if we had hidden request and last key is NULL then key search was exhausted */ + if (!kparam->op->allow_hidden || (kparam->has_hidden && !kparam->last)) { + return NULL; + } + /* inform user about the hidden recipient before searching through the loaded keys */ + if (!kparam->has_hidden) { + call_key_callback(ffi, ctx->search, ctx->secret); + } + kparam->has_hidden = true; + kparam->last = find_key(ffi, ctx->search, true, true, kparam->last); + return kparam->last; +} + +rnp_result_t +rnp_op_verify_set_flags(rnp_op_verify_t op, uint32_t flags) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + /* Allow to decrypt without valid signatures */ + op->ignore_sigs = extract_flag(flags, RNP_VERIFY_IGNORE_SIGS_ON_DECRYPT); + /* Strict mode: require all signatures to be valid */ + op->require_all_sigs = extract_flag(flags, RNP_VERIFY_REQUIRE_ALL_SIGS); + /* Allow hidden recipients if any */ + op->allow_hidden = extract_flag(flags, RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT); + + if (flags) { + FFI_LOG(op->ffi, "Unknown operation flags: %x", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_execute(rnp_op_verify_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_parse_handler_t handler; + + handler.password_provider = &op->ffi->pass_provider; + + rnp_decryption_kp_param_t kparam(op); + pgp_key_provider_t kprov = {ffi_decrypt_key_provider, &kparam}; + + handler.key_provider = &kprov; + handler.on_signatures = rnp_op_verify_on_signatures; + handler.src_provider = rnp_verify_src_provider; + handler.dest_provider = rnp_verify_dest_provider; + handler.on_recipients = rnp_verify_on_recipients; + handler.on_decryption_start = rnp_verify_on_decryption_start; + handler.on_decryption_info = rnp_verify_on_decryption_info; + handler.on_decryption_done = rnp_verify_on_decryption_done; + handler.param = op; + handler.ctx = &op->rnpctx; + + rnp_result_t ret = process_pgp_source(&handler, op->input->src); + /* Allow to decrypt data ignoring the signatures check if requested */ + if (op->ignore_sigs && op->validated && (ret == RNP_ERROR_SIGNATURE_INVALID)) { + ret = RNP_SUCCESS; + } + /* Allow to require all signatures be valid */ + if (op->require_all_sigs && !ret) { + for (size_t i = 0; i < op->signature_count; i++) { + if (op->signatures[i].verify_status) { + ret = RNP_ERROR_SIGNATURE_INVALID; + break; + } + } + } + if (op->output) { + dst_flush(&op->output->dst); + op->output->keep = ret == RNP_SUCCESS; + } + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_signature_count(rnp_op_verify_t op, size_t *count) +try { + if (!op || !count) { + return RNP_ERROR_NULL_POINTER; + } + + *count = op->signature_count; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_signature_at(rnp_op_verify_t op, size_t idx, rnp_op_verify_signature_t *sig) +try { + if (!op || !sig) { + return RNP_ERROR_NULL_POINTER; + } + if (idx >= op->signature_count) { + FFI_LOG(op->ffi, "Invalid signature index: %zu", idx); + return RNP_ERROR_BAD_PARAMETERS; + } + *sig = &op->signatures[idx]; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_file_info(rnp_op_verify_t op, char **filename, uint32_t *mtime) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (mtime) { + *mtime = op->file_mtime; + } + if (filename) { + if (op->filename) { + *filename = strdup(op->filename); + } else { + *filename = NULL; + } + } + return RNP_SUCCESS; +} +FFI_GUARD + +static const char * +get_protection_mode(rnp_op_verify_t op) +{ + if (!op->encrypted) { + return "none"; + } + if (op->mdc) { + return "cfb-mdc"; + } + if (op->aead == PGP_AEAD_NONE) { + return "cfb"; + } + switch (op->aead) { + case PGP_AEAD_EAX: + return "aead-eax"; + case PGP_AEAD_OCB: + return "aead-ocb"; + default: + return "aead-unknown"; + } +} + +static const char * +get_protection_cipher(rnp_op_verify_t op) +{ + if (!op->encrypted) { + return "none"; + } + return id_str_pair::lookup(symm_alg_map, op->salg); +} + +rnp_result_t +rnp_op_verify_get_protection_info(rnp_op_verify_t op, char **mode, char **cipher, bool *valid) +try { + if (!op || (!mode && !cipher && !valid)) { + return RNP_ERROR_NULL_POINTER; + } + + if (mode) { + *mode = strdup(get_protection_mode(op)); + if (!*mode) { + return RNP_ERROR_OUT_OF_MEMORY; + } + } + if (cipher) { + *cipher = strdup(get_protection_cipher(op)); + if (!*cipher) { + return RNP_ERROR_OUT_OF_MEMORY; + } + } + if (valid) { + *valid = op->validated; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_recipient_count(rnp_op_verify_t op, size_t *count) +try { + if (!op || !count) { + return RNP_ERROR_NULL_POINTER; + } + *count = op->recipient_count; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_used_recipient(rnp_op_verify_t op, rnp_recipient_handle_t *recipient) +try { + if (!op || !recipient) { + return RNP_ERROR_NULL_POINTER; + } + *recipient = op->used_recipient; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_recipient_at(rnp_op_verify_t op, + size_t idx, + rnp_recipient_handle_t *recipient) +try { + if (!op || !recipient) { + return RNP_ERROR_NULL_POINTER; + } + if (idx >= op->recipient_count) { + return RNP_ERROR_BAD_PARAMETERS; + } + *recipient = &op->recipients[idx]; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_recipient_get_keyid(rnp_recipient_handle_t recipient, char **keyid) +try { + if (!recipient || !keyid) { + return RNP_ERROR_NULL_POINTER; + } + static_assert(sizeof(recipient->keyid) == PGP_KEY_ID_SIZE, + "rnp_recipient_handle_t.keyid size mismatch"); + return hex_encode_value(recipient->keyid, PGP_KEY_ID_SIZE, keyid); +} +FFI_GUARD + +rnp_result_t +rnp_recipient_get_alg(rnp_recipient_handle_t recipient, char **alg) +try { + if (!recipient || !alg) { + return RNP_ERROR_NULL_POINTER; + } + return get_map_value(pubkey_alg_map, recipient->palg, alg); +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_symenc_count(rnp_op_verify_t op, size_t *count) +try { + if (!op || !count) { + return RNP_ERROR_NULL_POINTER; + } + *count = op->symenc_count; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_used_symenc(rnp_op_verify_t op, rnp_symenc_handle_t *symenc) +try { + if (!op || !symenc) { + return RNP_ERROR_NULL_POINTER; + } + *symenc = op->used_symenc; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_get_symenc_at(rnp_op_verify_t op, size_t idx, rnp_symenc_handle_t *symenc) +try { + if (!op || !symenc) { + return RNP_ERROR_NULL_POINTER; + } + if (idx >= op->symenc_count) { + return RNP_ERROR_BAD_PARAMETERS; + } + *symenc = &op->symencs[idx]; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_symenc_get_cipher(rnp_symenc_handle_t symenc, char **cipher) +try { + if (!symenc || !cipher) { + return RNP_ERROR_NULL_POINTER; + } + return get_map_value(symm_alg_map, symenc->alg, cipher); +} +FFI_GUARD + +rnp_result_t +rnp_symenc_get_aead_alg(rnp_symenc_handle_t symenc, char **alg) +try { + if (!symenc || !alg) { + return RNP_ERROR_NULL_POINTER; + } + return get_map_value(aead_alg_map, symenc->aalg, alg); +} +FFI_GUARD + +rnp_result_t +rnp_symenc_get_hash_alg(rnp_symenc_handle_t symenc, char **alg) +try { + if (!symenc || !alg) { + return RNP_ERROR_NULL_POINTER; + } + return get_map_value(hash_alg_map, symenc->halg, alg); +} +FFI_GUARD + +rnp_result_t +rnp_symenc_get_s2k_type(rnp_symenc_handle_t symenc, char **type) +try { + if (!symenc || !type) { + return RNP_ERROR_NULL_POINTER; + } + return get_map_value(s2k_type_map, symenc->s2k_type, type); +} +FFI_GUARD + +rnp_result_t +rnp_symenc_get_s2k_iterations(rnp_symenc_handle_t symenc, uint32_t *iterations) +try { + if (!symenc || !iterations) { + return RNP_ERROR_NULL_POINTER; + } + *iterations = symenc->iterations; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_destroy(rnp_op_verify_t op) +try { + delete op; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_op_verify_st::~rnp_op_verify_st() +{ + delete[] signatures; + free(filename); + free(recipients); + free(used_recipient); + free(symencs); + free(used_symenc); +} + +rnp_result_t +rnp_op_verify_signature_get_status(rnp_op_verify_signature_t sig) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + return sig->verify_status; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_signature_get_handle(rnp_op_verify_signature_t sig, + rnp_signature_handle_t * handle) +try { + if (!sig || !handle) { + return RNP_ERROR_NULL_POINTER; + } + + *handle = (rnp_signature_handle_t) calloc(1, sizeof(**handle)); + if (!*handle) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + try { + (*handle)->sig = new pgp_subsig_t(sig->sig_pkt); + } catch (const std::exception &e) { + FFI_LOG(sig->ffi, "%s", e.what()); + free(*handle); + return RNP_ERROR_OUT_OF_MEMORY; + } + (*handle)->ffi = sig->ffi; + (*handle)->key = NULL; + (*handle)->own_sig = true; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_signature_get_hash(rnp_op_verify_signature_t sig, char **hash) +try { + if (!sig || !hash) { + return RNP_ERROR_NULL_POINTER; + } + return get_map_value(hash_alg_map, sig->sig_pkt.halg, hash); +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_signature_get_key(rnp_op_verify_signature_t sig, rnp_key_handle_t *key) +try { + if (!sig->sig_pkt.has_keyid()) { + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_ffi_t ffi = sig->ffi; + // create a search (since we'll use this later anyways) + pgp_key_search_t search(PGP_KEY_SEARCH_KEYID); + search.by.keyid = sig->sig_pkt.keyid(); + + // search the stores + pgp_key_t *pub = rnp_key_store_search(ffi->pubring, &search, NULL); + pgp_key_t *sec = rnp_key_store_search(ffi->secring, &search, NULL); + if (!pub && !sec) { + return RNP_ERROR_KEY_NOT_FOUND; + } + + struct rnp_key_handle_st *handle = (rnp_key_handle_st *) calloc(1, sizeof(*handle)); + if (!handle) { + return RNP_ERROR_OUT_OF_MEMORY; + } + handle->ffi = ffi; + handle->pub = pub; + handle->sec = sec; + handle->locator = search; + *key = handle; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_verify_signature_get_times(rnp_op_verify_signature_t sig, + uint32_t * create, + uint32_t * expires) +try { + if (create) { + *create = sig->sig_pkt.creation(); + } + if (expires) { + *expires = sig->sig_pkt.expiration(); + } + + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_decrypt(rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output) +try { + // checks + if (!ffi || !input || !output) { + return RNP_ERROR_NULL_POINTER; + } + + rnp_op_verify_t op = NULL; + rnp_result_t ret = rnp_op_verify_create(&op, ffi, input, output); + if (ret) { + return ret; + } + ret = rnp_op_verify_set_flags(op, RNP_VERIFY_IGNORE_SIGS_ON_DECRYPT); + if (!ret) { + ret = rnp_op_verify_execute(op); + } + rnp_op_verify_destroy(op); + return ret; +} +FFI_GUARD + +static rnp_result_t +str_to_locator(rnp_ffi_t ffi, + pgp_key_search_t *locator, + const char * identifier_type, + const char * identifier) +{ + // parse the identifier type + locator->type = static_cast( + id_str_pair::lookup(identifier_type_map, identifier_type, PGP_KEY_SEARCH_UNKNOWN)); + if (locator->type == PGP_KEY_SEARCH_UNKNOWN) { + FFI_LOG(ffi, "Invalid identifier type: %s", identifier_type); + return RNP_ERROR_BAD_PARAMETERS; + } + // see what type we have + switch (locator->type) { + case PGP_KEY_SEARCH_USERID: + if (snprintf(locator->by.userid, sizeof(locator->by.userid), "%s", identifier) >= + (int) sizeof(locator->by.userid)) { + FFI_LOG(ffi, "UserID too long"); + return RNP_ERROR_BAD_PARAMETERS; + } + break; + case PGP_KEY_SEARCH_KEYID: { + if (strlen(identifier) != (PGP_KEY_ID_SIZE * 2) || + !rnp::hex_decode(identifier, locator->by.keyid.data(), locator->by.keyid.size())) { + FFI_LOG(ffi, "Invalid keyid: %s", identifier); + return RNP_ERROR_BAD_PARAMETERS; + } + } break; + case PGP_KEY_SEARCH_FINGERPRINT: { + // TODO: support v5 fingerprints + // Note: v2/v3 fingerprint are 16 bytes (32 chars) long. + if ((strlen(identifier) != (PGP_FINGERPRINT_SIZE * 2)) && (strlen(identifier) != 32)) { + FFI_LOG(ffi, "Invalid fingerprint: %s", identifier); + return RNP_ERROR_BAD_PARAMETERS; + } + locator->by.fingerprint.length = rnp::hex_decode( + identifier, locator->by.fingerprint.fingerprint, PGP_FINGERPRINT_SIZE); + if (!locator->by.fingerprint.length) { + FFI_LOG(ffi, "Invalid fingerprint: %s", identifier); + return RNP_ERROR_BAD_PARAMETERS; + } + } break; + case PGP_KEY_SEARCH_GRIP: { + if (strlen(identifier) != (PGP_KEY_GRIP_SIZE * 2) || + !rnp::hex_decode(identifier, locator->by.grip.data(), locator->by.grip.size())) { + FFI_LOG(ffi, "Invalid grip: %s", identifier); + return RNP_ERROR_BAD_PARAMETERS; + } + } break; + default: + // should never happen + assert(false); + return RNP_ERROR_BAD_STATE; + } + return RNP_SUCCESS; +} + +static bool +locator_to_str(const pgp_key_search_t &locator, + const char ** identifier_type, + char * identifier, + size_t identifier_size) +{ + // find the identifier type string with the map + *identifier_type = id_str_pair::lookup(identifier_type_map, locator.type, NULL); + if (!*identifier_type) { + return false; + } + // fill in the actual identifier + switch (locator.type) { + case PGP_KEY_SEARCH_USERID: + if (snprintf(identifier, identifier_size, "%s", locator.by.userid) >= + (int) identifier_size) { + return false; + } + break; + case PGP_KEY_SEARCH_KEYID: + if (!rnp::hex_encode( + locator.by.keyid.data(), locator.by.keyid.size(), identifier, identifier_size)) { + return false; + } + break; + case PGP_KEY_SEARCH_FINGERPRINT: + if (!rnp::hex_encode(locator.by.fingerprint.fingerprint, + locator.by.fingerprint.length, + identifier, + identifier_size)) { + return false; + } + break; + case PGP_KEY_SEARCH_GRIP: + if (!rnp::hex_encode( + locator.by.grip.data(), locator.by.grip.size(), identifier, identifier_size)) { + return false; + } + break; + default: + assert(false); + return false; + } + return true; +} + +static rnp_result_t +rnp_locate_key_int(rnp_ffi_t ffi, + const pgp_key_search_t &locator, + rnp_key_handle_t * handle, + bool require_secret = false) +{ + // search pubring + pgp_key_t *pub = rnp_key_store_search(ffi->pubring, &locator, NULL); + // search secring + pgp_key_t *sec = rnp_key_store_search(ffi->secring, &locator, NULL); + + if (require_secret && !sec) { + *handle = NULL; + return RNP_SUCCESS; + } + + if (pub || sec) { + *handle = (rnp_key_handle_t) malloc(sizeof(**handle)); + if (!*handle) { + return RNP_ERROR_OUT_OF_MEMORY; + } + (*handle)->ffi = ffi; + (*handle)->pub = pub; + (*handle)->sec = sec; + (*handle)->locator = locator; + } else { + *handle = NULL; + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_locate_key(rnp_ffi_t ffi, + const char * identifier_type, + const char * identifier, + rnp_key_handle_t *handle) +try { + // checks + if (!ffi || !identifier_type || !identifier || !handle) { + return RNP_ERROR_NULL_POINTER; + } + + // figure out the identifier type + pgp_key_search_t locator; + rnp_result_t ret = str_to_locator(ffi, &locator, identifier_type, identifier); + if (ret) { + return ret; + } + + return rnp_locate_key_int(ffi, locator, handle); +} +FFI_GUARD + +rnp_result_t +rnp_key_export(rnp_key_handle_t handle, rnp_output_t output, uint32_t flags) +try { + pgp_dest_t *dst = NULL; + pgp_dest_t armordst = {}; + + // checks + if (!handle || !output) { + return RNP_ERROR_NULL_POINTER; + } + dst = &output->dst; + if ((flags & RNP_KEY_EXPORT_PUBLIC) && (flags & RNP_KEY_EXPORT_SECRET)) { + FFI_LOG(handle->ffi, "Invalid export flags, select only public or secret, not both."); + return RNP_ERROR_BAD_PARAMETERS; + } + + // handle flags + bool armored = extract_flag(flags, RNP_KEY_EXPORT_ARMORED); + pgp_key_t * key = NULL; + rnp_key_store_t *store = NULL; + if (flags & RNP_KEY_EXPORT_PUBLIC) { + extract_flag(flags, RNP_KEY_EXPORT_PUBLIC); + key = get_key_require_public(handle); + store = handle->ffi->pubring; + } else if (flags & RNP_KEY_EXPORT_SECRET) { + extract_flag(flags, RNP_KEY_EXPORT_SECRET); + key = get_key_require_secret(handle); + store = handle->ffi->secring; + } else { + FFI_LOG(handle->ffi, "must specify public or secret key for export"); + return RNP_ERROR_BAD_PARAMETERS; + } + bool export_subs = extract_flag(flags, RNP_KEY_EXPORT_SUBKEYS); + // check for any unrecognized flags + if (flags) { + FFI_LOG(handle->ffi, "unrecognized flags remaining: 0x%X", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + // make sure we found our key + if (!key) { + FFI_LOG(handle->ffi, "no suitable key found"); + return RNP_ERROR_NO_SUITABLE_KEY; + } + // only PGP packets supported for now + if (key->format != PGP_KEY_STORE_GPG && key->format != PGP_KEY_STORE_KBX) { + return RNP_ERROR_NOT_IMPLEMENTED; + } + if (armored) { + auto msgtype = key->is_secret() ? PGP_ARMORED_SECRET_KEY : PGP_ARMORED_PUBLIC_KEY; + rnp_result_t res = init_armored_dst(&armordst, &output->dst, msgtype); + if (res) { + return res; + } + dst = &armordst; + } + // write + if (key->is_primary()) { + // primary key, write just the primary or primary and all subkeys + key->write_xfer(*dst, export_subs ? store : NULL); + if (dst->werr) { + return RNP_ERROR_WRITE; + } + } else { + // subkeys flag is only valid for primary + if (export_subs) { + FFI_LOG(handle->ffi, "export with subkeys requested but key is not primary"); + return RNP_ERROR_BAD_PARAMETERS; + } + // subkey, write the primary + this subkey only + pgp_key_t *primary = rnp_key_store_get_primary_key(store, key); + if (!primary) { + // shouldn't happen + return RNP_ERROR_GENERIC; + } + primary->write_xfer(*dst); + if (dst->werr) { + return RNP_ERROR_WRITE; + } + key->write_xfer(*dst); + if (dst->werr) { + return RNP_ERROR_WRITE; + } + } + if (armored) { + dst_finish(&armordst); + dst_close(&armordst, false); + } + output->keep = true; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_export_autocrypt(rnp_key_handle_t key, + rnp_key_handle_t subkey, + const char * uid, + rnp_output_t output, + uint32_t flags) +try { + if (!key || !output) { + return RNP_ERROR_NULL_POINTER; + } + bool base64 = extract_flag(flags, RNP_KEY_EXPORT_BASE64); + if (flags) { + FFI_LOG(key->ffi, "Unknown flags remaining: 0x%X", flags); + return RNP_ERROR_BAD_PARAMETERS; + } + /* Get the primary key */ + pgp_key_t *primary = get_key_prefer_public(key); + if (!primary || !primary->is_primary() || !primary->usable_for(PGP_OP_VERIFY)) { + FFI_LOG(key->ffi, "No valid signing primary key"); + return RNP_ERROR_BAD_PARAMETERS; + } + /* Get encrypting subkey */ + pgp_key_t *sub = + subkey ? get_key_prefer_public(subkey) : + find_suitable_key(PGP_OP_ENCRYPT, primary, &key->ffi->key_provider, true); + if (!sub || sub->is_primary() || !sub->usable_for(PGP_OP_ENCRYPT)) { + FFI_LOG(key->ffi, "No encrypting subkey"); + return RNP_ERROR_KEY_NOT_FOUND; + } + /* Get userid */ + size_t uididx = primary->uid_count(); + if (uid) { + for (size_t idx = 0; idx < primary->uid_count(); idx++) { + if (primary->get_uid(idx).str == uid) { + uididx = idx; + break; + } + } + } else { + if (primary->uid_count() > 1) { + FFI_LOG(key->ffi, "Ambiguous userid"); + return RNP_ERROR_BAD_PARAMETERS; + } + uididx = 0; + } + if (uididx >= primary->uid_count()) { + FFI_LOG(key->ffi, "Userid not found"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* Check whether base64 is requested */ + bool res = false; + if (base64) { + rnp::ArmoredDest armor(output->dst, PGP_ARMORED_BASE64); + res = primary->write_autocrypt(armor.dst(), *sub, uididx); + } else { + res = primary->write_autocrypt(output->dst, *sub, uididx); + } + return res ? RNP_SUCCESS : RNP_ERROR_BAD_PARAMETERS; +} +FFI_GUARD + +static pgp_key_t * +rnp_key_get_revoker(rnp_key_handle_t key) +{ + pgp_key_t *exkey = get_key_prefer_public(key); + if (!exkey) { + return NULL; + } + if (exkey->is_subkey()) { + return rnp_key_store_get_primary_key(key->ffi->secring, exkey); + } + // TODO: search through revocation key subpackets as well + return get_key_require_secret(key); +} + +static rnp_result_t +rnp_key_get_revocation(rnp_ffi_t ffi, + pgp_key_t * key, + pgp_key_t * revoker, + const char * hash, + const char * code, + const char * reason, + pgp_signature_t &sig) +{ + if (!hash) { + hash = DEFAULT_HASH_ALG; + } + pgp_hash_alg_t halg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(hash, &halg)) { + FFI_LOG(ffi, "Unknown hash algorithm: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_revoke_t revinfo = {}; + if (code && !str_to_revocation_type(code, &revinfo.code)) { + FFI_LOG(ffi, "Wrong revocation code: %s", code); + return RNP_ERROR_BAD_PARAMETERS; + } + if (revinfo.code > PGP_REVOCATION_RETIRED) { + FFI_LOG(ffi, "Wrong key revocation code: %d", (int) revinfo.code); + return RNP_ERROR_BAD_PARAMETERS; + } + if (reason) { + try { + revinfo.reason = reason; + } catch (const std::exception &e) { + FFI_LOG(ffi, "%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + /* unlock the secret key if needed */ + rnp::KeyLocker revlock(*revoker); + if (revoker->is_locked() && !revoker->unlock(ffi->pass_provider)) { + FFI_LOG(ffi, "Failed to unlock secret key"); + return RNP_ERROR_BAD_PASSWORD; + } + try { + revoker->gen_revocation(revinfo, halg, key->pkt(), sig, ffi->context); + } catch (const std::exception &e) { + FFI_LOG(ffi, "Failed to generate revocation signature: %s", e.what()); + return RNP_ERROR_BAD_STATE; + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_key_export_revocation(rnp_key_handle_t key, + rnp_output_t output, + uint32_t flags, + const char * hash, + const char * code, + const char * reason) +try { + if (!key || !key->ffi || !output) { + return RNP_ERROR_NULL_POINTER; + } + bool need_armor = extract_flag(flags, RNP_KEY_EXPORT_ARMORED); + if (flags) { + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_key_t *exkey = get_key_prefer_public(key); + if (!exkey || !exkey->is_primary()) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *revoker = rnp_key_get_revoker(key); + if (!revoker) { + FFI_LOG(key->ffi, "Revoker secret key not found"); + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_signature_t sig; + rnp_result_t ret = + rnp_key_get_revocation(key->ffi, exkey, revoker, hash, code, reason, sig); + if (ret) { + return ret; + } + + if (need_armor) { + rnp::ArmoredDest armor(output->dst, PGP_ARMORED_PUBLIC_KEY); + sig.write(armor.dst()); + ret = armor.werr(); + dst_flush(&armor.dst()); + } else { + sig.write(output->dst); + ret = output->dst.werr; + dst_flush(&output->dst); + } + output->keep = !ret; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_key_revoke( + rnp_key_handle_t key, uint32_t flags, const char *hash, const char *code, const char *reason) +try { + if (!key || !key->ffi) { + return RNP_ERROR_NULL_POINTER; + } + if (flags) { + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_key_t *exkey = get_key_prefer_public(key); + if (!exkey) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *revoker = rnp_key_get_revoker(key); + if (!revoker) { + FFI_LOG(key->ffi, "Revoker secret key not found"); + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_signature_t sig; + rnp_result_t ret = + rnp_key_get_revocation(key->ffi, exkey, revoker, hash, code, reason, sig); + if (ret) { + return ret; + } + pgp_sig_import_status_t pub_status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY; + pgp_sig_import_status_t sec_status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY; + if (key->pub) { + pub_status = rnp_key_store_import_key_signature(key->ffi->pubring, key->pub, &sig); + } + if (key->sec) { + sec_status = rnp_key_store_import_key_signature(key->ffi->secring, key->sec, &sig); + } + + if ((pub_status == PGP_SIG_IMPORT_STATUS_UNKNOWN) || + (sec_status == PGP_SIG_IMPORT_STATUS_UNKNOWN)) { + return RNP_ERROR_GENERIC; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_25519_bits_tweaked(rnp_key_handle_t key, bool *result) +try { + if (!key || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *seckey = get_key_require_secret(key); + if (!seckey || seckey->is_locked() || (seckey->alg() != PGP_PKA_ECDH) || + (seckey->curve() != PGP_CURVE_25519)) { + return RNP_ERROR_BAD_PARAMETERS; + } + *result = x25519_bits_tweaked(seckey->material().ec); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_25519_bits_tweak(rnp_key_handle_t key) +try { + if (!key) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *seckey = get_key_require_secret(key); + if (!seckey || seckey->is_protected() || (seckey->alg() != PGP_PKA_ECDH) || + (seckey->curve() != PGP_CURVE_25519)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!x25519_tweak_bits(seckey->pkt().material.ec)) { + FFI_LOG(key->ffi, "Failed to tweak 25519 key bits."); + return RNP_ERROR_BAD_STATE; + } + if (!seckey->write_sec_rawpkt(seckey->pkt(), "", key->ffi->context)) { + FFI_LOG(key->ffi, "Failed to update rawpkt."); + return RNP_ERROR_BAD_STATE; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_remove(rnp_key_handle_t key, uint32_t flags) +try { + if (!key || !key->ffi) { + return RNP_ERROR_NULL_POINTER; + } + bool pub = extract_flag(flags, RNP_KEY_REMOVE_PUBLIC); + bool sec = extract_flag(flags, RNP_KEY_REMOVE_SECRET); + bool sub = extract_flag(flags, RNP_KEY_REMOVE_SUBKEYS); + if (flags) { + FFI_LOG(key->ffi, "Unknown flags: %" PRIu32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + if (!pub && !sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (sub && get_key_prefer_public(key)->is_subkey()) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (pub) { + if (!key->ffi->pubring || !key->pub) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!rnp_key_store_remove_key(key->ffi->pubring, key->pub, sub)) { + return RNP_ERROR_KEY_NOT_FOUND; + } + key->pub = NULL; + } + if (sec) { + if (!key->ffi->secring || !key->sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!rnp_key_store_remove_key(key->ffi->secring, key->sec, sub)) { + return RNP_ERROR_KEY_NOT_FOUND; + } + key->sec = NULL; + } + return RNP_SUCCESS; +} +FFI_GUARD + +static void +report_signature_removal(rnp_ffi_t ffi, + const pgp_key_t & key, + rnp_key_signatures_cb sigcb, + void * app_ctx, + pgp_subsig_t & keysig, + bool & remove) +{ + if (!sigcb) { + return; + } + rnp_signature_handle_t sig = (rnp_signature_handle_t) calloc(1, sizeof(*sig)); + if (!sig) { + FFI_LOG(ffi, "Signature handle allocation failed."); + return; + } + sig->ffi = ffi; + sig->key = &key; + sig->sig = &keysig; + sig->own_sig = false; + uint32_t action = remove ? RNP_KEY_SIGNATURE_REMOVE : RNP_KEY_SIGNATURE_KEEP; + sigcb(ffi, app_ctx, sig, &action); + switch (action) { + case RNP_KEY_SIGNATURE_REMOVE: + remove = true; + break; + case RNP_KEY_SIGNATURE_KEEP: + remove = false; + break; + default: + FFI_LOG(ffi, "Invalid signature removal action: %" PRIu32, action); + break; + } + rnp_signature_handle_destroy(sig); +} + +static bool +signature_needs_removal(rnp_ffi_t ffi, const pgp_key_t &key, pgp_subsig_t &sig, uint32_t flags) +{ + /* quick check for non-self signatures */ + bool nonself = flags & RNP_KEY_SIGNATURE_NON_SELF_SIG; + if (nonself && key.is_primary() && !key.is_signer(sig)) { + return true; + } + if (nonself && key.is_subkey()) { + pgp_key_t *primary = rnp_key_store_get_primary_key(ffi->pubring, &key); + if (primary && !primary->is_signer(sig)) { + return true; + } + } + /* unknown signer */ + pgp_key_t *signer = pgp_sig_get_signer(sig, ffi->pubring, &ffi->key_provider); + if (!signer && (flags & RNP_KEY_SIGNATURE_UNKNOWN_KEY)) { + return true; + } + /* validate signature if didn't */ + if (signer && !sig.validated()) { + signer->validate_sig(key, sig, ffi->context); + } + /* we cannot check for invalid/expired if sig was not validated */ + if (!sig.validated()) { + return false; + } + if ((flags & RNP_KEY_SIGNATURE_INVALID) && !sig.validity.valid) { + return true; + } + return false; +} + +static void +remove_key_signatures(rnp_ffi_t ffi, + pgp_key_t & pub, + pgp_key_t * sec, + uint32_t flags, + rnp_key_signatures_cb sigcb, + void * app_ctx) +{ + std::vector sigs; + + for (size_t idx = 0; idx < pub.sig_count(); idx++) { + pgp_subsig_t &sig = pub.get_sig(idx); + bool remove = signature_needs_removal(ffi, pub, sig, flags); + report_signature_removal(ffi, pub, sigcb, app_ctx, sig, remove); + if (remove) { + sigs.push_back(sig.sigid); + } + } + size_t deleted = pub.del_sigs(sigs); + if (deleted != sigs.size()) { + FFI_LOG(ffi, "Invalid deleted sigs count: %zu instead of %zu.", deleted, sigs.size()); + } + /* delete from the secret key if any */ + if (sec && (sec != &pub)) { + sec->del_sigs(sigs); + } +} + +rnp_result_t +rnp_key_remove_signatures(rnp_key_handle_t handle, + uint32_t flags, + rnp_key_signatures_cb sigcb, + void * app_ctx) +try { + if (!handle) { + return RNP_ERROR_NULL_POINTER; + } + if (!flags && !sigcb) { + return RNP_ERROR_BAD_PARAMETERS; + } + uint32_t origflags = flags; + extract_flag(flags, + RNP_KEY_SIGNATURE_INVALID | RNP_KEY_SIGNATURE_NON_SELF_SIG | + RNP_KEY_SIGNATURE_UNKNOWN_KEY); + if (flags) { + FFI_LOG(handle->ffi, "Invalid flags: %" PRIu32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + flags = origflags; + + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* process key itself */ + pgp_key_t *sec = get_key_require_secret(handle); + remove_key_signatures(handle->ffi, *key, sec, flags, sigcb, app_ctx); + + /* process subkeys */ + for (size_t idx = 0; key->is_primary() && (idx < key->subkey_count()); idx++) { + pgp_key_t *sub = pgp_key_get_subkey(key, handle->ffi->pubring, idx); + if (!sub) { + FFI_LOG(handle->ffi, "Failed to get subkey at idx %zu.", idx); + continue; + } + pgp_key_t *subsec = rnp_key_store_get_key_by_fpr(handle->ffi->secring, sub->fp()); + remove_key_signatures(handle->ffi, *sub, subsec, flags, sigcb, app_ctx); + } + /* revalidate key/subkey */ + key->revalidate(*handle->ffi->pubring); + if (sec) { + sec->revalidate(*handle->ffi->secring); + } + return RNP_SUCCESS; +} +FFI_GUARD + +static bool +pk_alg_allows_custom_curve(pgp_pubkey_alg_t pkalg) +{ + switch (pkalg) { + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + return true; + default: + return false; + } +} + +static bool +parse_preferences(json_object *jso, pgp_user_prefs_t &prefs) +{ + static const struct { + const char * key; + enum json_type type; + } properties[] = {{"hashes", json_type_array}, + {"ciphers", json_type_array}, + {"compression", json_type_array}, + {"key server", json_type_string}}; + + for (size_t iprop = 0; iprop < ARRAY_SIZE(properties); iprop++) { + json_object *value = NULL; + const char * key = properties[iprop].key; + + if (!json_object_object_get_ex(jso, key, &value)) { + continue; + } + + if (!json_object_is_type(value, properties[iprop].type)) { + return false; + } + try { + if (rnp::str_case_eq(key, "hashes")) { + int length = json_object_array_length(value); + for (int i = 0; i < length; i++) { + json_object *item = json_object_array_get_idx(value, i); + if (!json_object_is_type(item, json_type_string)) { + return false; + } + pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(json_object_get_string(item), &hash_alg)) { + return false; + } + prefs.add_hash_alg(hash_alg); + } + } else if (rnp::str_case_eq(key, "ciphers")) { + int length = json_object_array_length(value); + for (int i = 0; i < length; i++) { + json_object *item = json_object_array_get_idx(value, i); + if (!json_object_is_type(item, json_type_string)) { + return false; + } + pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN; + if (!str_to_cipher(json_object_get_string(item), &symm_alg)) { + return false; + } + prefs.add_symm_alg(symm_alg); + } + } else if (rnp::str_case_eq(key, "compression")) { + int length = json_object_array_length(value); + for (int i = 0; i < length; i++) { + json_object *item = json_object_array_get_idx(value, i); + if (!json_object_is_type(item, json_type_string)) { + return false; + } + pgp_compression_type_t z_alg = PGP_C_UNKNOWN; + if (!str_to_compression_alg(json_object_get_string(item), &z_alg)) { + return false; + } + prefs.add_z_alg(z_alg); + } + } else if (rnp::str_case_eq(key, "key server")) { + prefs.key_server = json_object_get_string(value); + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + // delete this field since it has been handled + json_object_object_del(jso, key); + } + return true; +} + +static bool +parse_keygen_crypto(json_object *jso, rnp_keygen_crypto_params_t &crypto) +{ + static const struct { + const char * key; + enum json_type type; + } properties[] = {{"type", json_type_string}, + {"curve", json_type_string}, + {"length", json_type_int}, + {"hash", json_type_string}}; + + for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { + json_object *value = NULL; + const char * key = properties[i].key; + + if (!json_object_object_get_ex(jso, key, &value)) { + continue; + } + + if (!json_object_is_type(value, properties[i].type)) { + return false; + } + // TODO: make sure there are no duplicate keys in the JSON + if (rnp::str_case_eq(key, "type")) { + if (!str_to_pubkey_alg(json_object_get_string(value), &crypto.key_alg)) { + return false; + } + } else if (rnp::str_case_eq(key, "length")) { + int length = json_object_get_int(value); + switch (crypto.key_alg) { + case PGP_PKA_RSA: + crypto.rsa.modulus_bit_len = length; + break; + case PGP_PKA_DSA: + crypto.dsa.p_bitlen = length; + break; + case PGP_PKA_ELGAMAL: + crypto.elgamal.key_bitlen = length; + break; + default: + return false; + } + } else if (rnp::str_case_eq(key, "curve")) { + if (!pk_alg_allows_custom_curve(crypto.key_alg)) { + return false; + } + if (!curve_str_to_type(json_object_get_string(value), &crypto.ecc.curve)) { + return false; + } + } else if (rnp::str_case_eq(key, "hash")) { + if (!str_to_hash_alg(json_object_get_string(value), &crypto.hash_alg)) { + return false; + } + } else { + // shouldn't happen + return false; + } + // delete this field since it has been handled + json_object_object_del(jso, key); + } + return true; +} + +static bool +parse_protection(json_object *jso, rnp_key_protection_params_t &protection) +{ + static const struct { + const char * key; + enum json_type type; + } properties[] = {{"cipher", json_type_string}, + {"mode", json_type_string}, + {"iterations", json_type_int}, + {"hash", json_type_string}}; + + for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { + json_object *value = NULL; + const char * key = properties[i].key; + + if (!json_object_object_get_ex(jso, key, &value)) { + continue; + } + + if (!json_object_is_type(value, properties[i].type)) { + return false; + } + // TODO: make sure there are no duplicate keys in the JSON + if (rnp::str_case_eq(key, "cipher")) { + if (!str_to_cipher(json_object_get_string(value), &protection.symm_alg)) { + return false; + } + } else if (rnp::str_case_eq(key, "mode")) { + if (!str_to_cipher_mode(json_object_get_string(value), &protection.cipher_mode)) { + return false; + } + } else if (rnp::str_case_eq(key, "iterations")) { + protection.iterations = json_object_get_int(value); + } else if (rnp::str_case_eq(key, "hash")) { + if (!str_to_hash_alg(json_object_get_string(value), &protection.hash_alg)) { + return false; + } + } else { + // shouldn't happen + return false; + } + // delete this field since it has been handled + json_object_object_del(jso, key); + } + return true; +} + +static bool +parse_keygen_primary(json_object * jso, + rnp_keygen_primary_desc_t & desc, + rnp_key_protection_params_t &prot) +{ + static const char *properties[] = { + "userid", "usage", "expiration", "preferences", "protection"}; + auto &cert = desc.cert; + + if (!parse_keygen_crypto(jso, desc.crypto)) { + return false; + } + for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { + json_object *value = NULL; + const char * key = properties[i]; + + if (!json_object_object_get_ex(jso, key, &value)) { + continue; + } + if (rnp::str_case_eq(key, "userid")) { + if (!json_object_is_type(value, json_type_string)) { + return false; + } + auto uid = json_object_get_string(value); + if (strlen(uid) > MAX_ID_LENGTH) { + return false; + } + cert.userid = json_object_get_string(value); + } else if (rnp::str_case_eq(key, "usage")) { + switch (json_object_get_type(value)) { + case json_type_array: { + int length = json_object_array_length(value); + for (int j = 0; j < length; j++) { + json_object *item = json_object_array_get_idx(value, j); + if (!json_object_is_type(item, json_type_string)) { + return false; + } + uint8_t flag = 0; + if (!str_to_key_flag(json_object_get_string(item), &flag)) { + return false; + } + // check for duplicate + if (cert.key_flags & flag) { + return false; + } + cert.key_flags |= flag; + } + } break; + case json_type_string: { + if (!str_to_key_flag(json_object_get_string(value), &cert.key_flags)) { + return false; + } + } break; + default: + return false; + } + } else if (rnp::str_case_eq(key, "expiration")) { + if (!json_object_is_type(value, json_type_int)) { + return false; + } + cert.key_expiration = json_object_get_int(value); + } else if (rnp::str_case_eq(key, "preferences")) { + if (!json_object_is_type(value, json_type_object)) { + return false; + } + if (!parse_preferences(value, cert.prefs)) { + return false; + } + if (json_object_object_length(value)) { + return false; + } + } else if (rnp::str_case_eq(key, "protection")) { + if (!json_object_is_type(value, json_type_object)) { + return false; + } + if (!parse_protection(value, prot)) { + return false; + } + if (json_object_object_length(value)) { + return false; + } + } + // delete this field since it has been handled + json_object_object_del(jso, key); + } + return !json_object_object_length(jso); +} + +static bool +parse_keygen_sub(json_object * jso, + rnp_keygen_subkey_desc_t & desc, + rnp_key_protection_params_t &prot) +{ + static const char *properties[] = {"usage", "expiration", "protection"}; + auto & binding = desc.binding; + + if (!parse_keygen_crypto(jso, desc.crypto)) { + return false; + } + for (size_t i = 0; i < ARRAY_SIZE(properties); i++) { + json_object *value = NULL; + const char * key = properties[i]; + + if (!json_object_object_get_ex(jso, key, &value)) { + continue; + } + if (rnp::str_case_eq(key, "usage")) { + switch (json_object_get_type(value)) { + case json_type_array: { + int length = json_object_array_length(value); + for (int j = 0; j < length; j++) { + json_object *item = json_object_array_get_idx(value, j); + if (!json_object_is_type(item, json_type_string)) { + return false; + } + uint8_t flag = 0; + if (!str_to_key_flag(json_object_get_string(item), &flag)) { + return false; + } + if (binding.key_flags & flag) { + return false; + } + binding.key_flags |= flag; + } + } break; + case json_type_string: { + if (!str_to_key_flag(json_object_get_string(value), &binding.key_flags)) { + return false; + } + } break; + default: + return false; + } + } else if (rnp::str_case_eq(key, "expiration")) { + if (!json_object_is_type(value, json_type_int)) { + return false; + } + binding.key_expiration = json_object_get_int(value); + } else if (rnp::str_case_eq(key, "protection")) { + if (!json_object_is_type(value, json_type_object)) { + return false; + } + if (!parse_protection(value, prot)) { + return false; + } + if (json_object_object_length(value)) { + return false; + } + } + // delete this field since it has been handled + json_object_object_del(jso, key); + } + return !json_object_object_length(jso); +} + +static bool +gen_json_grips(char **result, const pgp_key_t *primary, const pgp_key_t *sub) +{ + if (!result) { + return true; + } + + json_object *jso = json_object_new_object(); + if (!jso) { + return false; + } + rnp::JSONObject jsowrap(jso); + + char grip[PGP_KEY_GRIP_SIZE * 2 + 1]; + if (primary) { + json_object *jsoprimary = json_object_new_object(); + if (!jsoprimary) { + return false; + } + json_object_object_add(jso, "primary", jsoprimary); + if (!rnp::hex_encode( + primary->grip().data(), primary->grip().size(), grip, sizeof(grip))) { + return false; + } + json_object *jsogrip = json_object_new_string(grip); + if (!jsogrip) { + return false; + } + json_object_object_add(jsoprimary, "grip", jsogrip); + } + if (sub) { + json_object *jsosub = json_object_new_object(); + if (!jsosub) { + return false; + } + json_object_object_add(jso, "sub", jsosub); + if (!rnp::hex_encode(sub->grip().data(), sub->grip().size(), grip, sizeof(grip))) { + return false; + } + json_object *jsogrip = json_object_new_string(grip); + if (!jsogrip) { + return false; + } + json_object_object_add(jsosub, "grip", jsogrip); + } + *result = strdup(json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY)); + return *result; +} + +static rnp_result_t +gen_json_primary_key(rnp_ffi_t ffi, + json_object * jsoparams, + rnp_key_protection_params_t &prot, + pgp_fingerprint_t & fp, + bool protect) +{ + rnp_keygen_primary_desc_t desc = {}; + // desc.crypto is a union + // so at least Clang 12 on Windows zero-initializes the first union member only + // keeping the "larger" member partially unintialized + desc.crypto.dsa.q_bitlen = 0; + + desc.cert.key_expiration = DEFAULT_KEY_EXPIRATION; + if (!parse_keygen_primary(jsoparams, desc, prot)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_key_t pub; + pgp_key_t sec; + desc.crypto.ctx = &ffi->context; + if (!pgp_generate_primary_key(desc, true, sec, pub, ffi->secring->format)) { + return RNP_ERROR_GENERIC; + } + if (!rnp_key_store_add_key(ffi->pubring, &pub)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + /* encrypt secret key if specified */ + if (protect && prot.symm_alg && !sec.protect(prot, ffi->pass_provider, ffi->context)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!rnp_key_store_add_key(ffi->secring, &sec)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + fp = pub.fp(); + return RNP_SUCCESS; +} + +static rnp_result_t +gen_json_subkey(rnp_ffi_t ffi, + json_object * jsoparams, + pgp_key_t & prim_pub, + pgp_key_t & prim_sec, + pgp_fingerprint_t &fp) +{ + rnp_keygen_subkey_desc_t desc = {}; + rnp_key_protection_params_t prot = {}; + + desc.binding.key_expiration = DEFAULT_KEY_EXPIRATION; + if (!parse_keygen_sub(jsoparams, desc, prot)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!desc.binding.key_flags) { + /* Generate encrypt-only subkeys by default */ + desc.binding.key_flags = PGP_KF_ENCRYPT; + } + pgp_key_t pub; + pgp_key_t sec; + desc.crypto.ctx = &ffi->context; + if (!pgp_generate_subkey(desc, + true, + prim_sec, + prim_pub, + sec, + pub, + ffi->pass_provider, + ffi->secring->format)) { + return RNP_ERROR_GENERIC; + } + if (!rnp_key_store_add_key(ffi->pubring, &pub)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + /* encrypt subkey if specified */ + if (prot.symm_alg && !sec.protect(prot, ffi->pass_provider, ffi->context)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!rnp_key_store_add_key(ffi->secring, &sec)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + fp = pub.fp(); + return RNP_SUCCESS; +} + +rnp_result_t +rnp_generate_key_json(rnp_ffi_t ffi, const char *json, char **results) +try { + // checks + if (!ffi || !ffi->secring || !json) { + return RNP_ERROR_NULL_POINTER; + } + + // parse the JSON + json_tokener_error error; + json_object * jso = json_tokener_parse_verbose(json, &error); + if (!jso) { + // syntax error or some other issue + FFI_LOG(ffi, "Invalid JSON: %s", json_tokener_error_desc(error)); + return RNP_ERROR_BAD_FORMAT; + } + rnp::JSONObject jsowrap(jso); + + // locate the appropriate sections + rnp_result_t ret = RNP_ERROR_GENERIC; + json_object *jsoprimary = NULL; + json_object *jsosub = NULL; + { + json_object_object_foreach(jso, key, value) + { + json_object **dest = NULL; + + if (rnp::str_case_eq(key, "primary")) { + dest = &jsoprimary; + } else if (rnp::str_case_eq(key, "sub")) { + dest = &jsosub; + } else { + // unrecognized key in the object + FFI_LOG(ffi, "Unexpected key in JSON: %s", key); + return RNP_ERROR_BAD_PARAMETERS; + } + + // duplicate "primary"/"sub" + if (*dest) { + return RNP_ERROR_BAD_PARAMETERS; + } + *dest = value; + } + } + + if (!jsoprimary && !jsosub) { + return RNP_ERROR_BAD_PARAMETERS; + } + + // generate primary key + pgp_key_t * prim_pub = NULL; + pgp_key_t * prim_sec = NULL; + rnp_key_protection_params_t prim_prot = {}; + pgp_fingerprint_t fp; + if (jsoprimary) { + ret = gen_json_primary_key(ffi, jsoprimary, prim_prot, fp, !jsosub); + if (ret) { + return ret; + } + prim_pub = rnp_key_store_get_key_by_fpr(ffi->pubring, fp); + if (!jsosub) { + if (!gen_json_grips(results, prim_pub, NULL)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; + } + prim_sec = rnp_key_store_get_key_by_fpr(ffi->secring, fp); + } else { + /* generate subkey only - find primary key via JSON params */ + json_object *jsoparent = NULL; + if (!json_object_object_get_ex(jsosub, "primary", &jsoparent) || + json_object_object_length(jsoparent) != 1) { + return RNP_ERROR_BAD_PARAMETERS; + } + const char *identifier_type = NULL; + const char *identifier = NULL; + json_object_object_foreach(jsoparent, key, value) + { + if (!json_object_is_type(value, json_type_string)) { + return RNP_ERROR_BAD_PARAMETERS; + } + identifier_type = key; + identifier = json_object_get_string(value); + } + if (!identifier_type || !identifier) { + return RNP_ERROR_BAD_STATE; + } + + pgp_key_search_t locator; + rnp_result_t tmpret = str_to_locator(ffi, &locator, identifier_type, identifier); + if (tmpret) { + return tmpret; + } + + prim_pub = rnp_key_store_search(ffi->pubring, &locator, NULL); + prim_sec = rnp_key_store_search(ffi->secring, &locator, NULL); + if (!prim_sec || !prim_pub) { + return RNP_ERROR_KEY_NOT_FOUND; + } + json_object_object_del(jsosub, "primary"); + } + + /* Generate subkey */ + ret = gen_json_subkey(ffi, jsosub, *prim_pub, *prim_sec, fp); + if (ret) { + if (jsoprimary) { + /* do not leave generated primary key in keyring */ + rnp_key_store_remove_key(ffi->pubring, prim_pub, false); + rnp_key_store_remove_key(ffi->secring, prim_sec, false); + } + return ret; + } + /* Protect the primary key now */ + if (prim_prot.symm_alg && + !prim_sec->protect(prim_prot, ffi->pass_provider, ffi->context)) { + rnp_key_store_remove_key(ffi->pubring, prim_pub, true); + rnp_key_store_remove_key(ffi->secring, prim_sec, true); + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_key_t *sub_pub = rnp_key_store_get_key_by_fpr(ffi->pubring, fp); + bool res = gen_json_grips(results, jsoprimary ? prim_pub : NULL, sub_pub); + return res ? RNP_SUCCESS : RNP_ERROR_OUT_OF_MEMORY; +} +FFI_GUARD + +rnp_result_t +rnp_generate_key_ex(rnp_ffi_t ffi, + const char * key_alg, + const char * sub_alg, + uint32_t key_bits, + uint32_t sub_bits, + const char * key_curve, + const char * sub_curve, + const char * userid, + const char * password, + rnp_key_handle_t *key) +try { + rnp_op_generate_t op = NULL; + rnp_op_generate_t subop = NULL; + rnp_key_handle_t primary = NULL; + rnp_key_handle_t subkey = NULL; + rnp_result_t ret = RNP_ERROR_KEY_GENERATION; + + /* generate primary key */ + if ((ret = rnp_op_generate_create(&op, ffi, key_alg))) { + return ret; + } + if (key_bits && (ret = rnp_op_generate_set_bits(op, key_bits))) { + goto done; + } + if (key_curve && (ret = rnp_op_generate_set_curve(op, key_curve))) { + goto done; + } + if ((ret = rnp_op_generate_set_userid(op, userid))) { + goto done; + } + if ((ret = rnp_op_generate_add_usage(op, "sign"))) { + goto done; + } + if ((ret = rnp_op_generate_add_usage(op, "certify"))) { + goto done; + } + if ((ret = rnp_op_generate_execute(op))) { + goto done; + } + if ((ret = rnp_op_generate_get_key(op, &primary))) { + goto done; + } + /* generate subkey if requested */ + if (!sub_alg) { + goto done; + } + if ((ret = rnp_op_generate_subkey_create(&subop, ffi, primary, sub_alg))) { + goto done; + } + if (sub_bits && (ret = rnp_op_generate_set_bits(subop, sub_bits))) { + goto done; + } + if (sub_curve && (ret = rnp_op_generate_set_curve(subop, sub_curve))) { + goto done; + } + if (password && (ret = rnp_op_generate_set_protection_password(subop, password))) { + goto done; + } + if ((ret = rnp_op_generate_add_usage(subop, "encrypt"))) { + goto done; + } + if ((ret = rnp_op_generate_execute(subop))) { + goto done; + } + if ((ret = rnp_op_generate_get_key(subop, &subkey))) { + goto done; + } +done: + /* only now will protect the primary key - to not spend time on unlocking to sign + * subkey */ + if (!ret && password) { + ret = rnp_key_protect(primary, password, NULL, NULL, NULL, 0); + } + if (ret && primary) { + rnp_key_remove(primary, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SECRET); + } + if (ret && subkey) { + rnp_key_remove(subkey, RNP_KEY_REMOVE_PUBLIC | RNP_KEY_REMOVE_SECRET); + } + if (!ret && key) { + *key = primary; + } else { + rnp_key_handle_destroy(primary); + } + rnp_key_handle_destroy(subkey); + rnp_op_generate_destroy(op); + rnp_op_generate_destroy(subop); + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_generate_key_rsa(rnp_ffi_t ffi, + uint32_t bits, + uint32_t subbits, + const char * userid, + const char * password, + rnp_key_handle_t *key) +try { + return rnp_generate_key_ex(ffi, + RNP_ALGNAME_RSA, + subbits ? RNP_ALGNAME_RSA : NULL, + bits, + subbits, + NULL, + NULL, + userid, + password, + key); +} +FFI_GUARD + +rnp_result_t +rnp_generate_key_dsa_eg(rnp_ffi_t ffi, + uint32_t bits, + uint32_t subbits, + const char * userid, + const char * password, + rnp_key_handle_t *key) +try { + return rnp_generate_key_ex(ffi, + RNP_ALGNAME_DSA, + subbits ? RNP_ALGNAME_ELGAMAL : NULL, + bits, + subbits, + NULL, + NULL, + userid, + password, + key); +} +FFI_GUARD + +rnp_result_t +rnp_generate_key_ec(rnp_ffi_t ffi, + const char * curve, + const char * userid, + const char * password, + rnp_key_handle_t *key) +try { + return rnp_generate_key_ex( + ffi, RNP_ALGNAME_ECDSA, RNP_ALGNAME_ECDH, 0, 0, curve, curve, userid, password, key); +} +FFI_GUARD + +rnp_result_t +rnp_generate_key_25519(rnp_ffi_t ffi, + const char * userid, + const char * password, + rnp_key_handle_t *key) +try { + return rnp_generate_key_ex(ffi, + RNP_ALGNAME_EDDSA, + RNP_ALGNAME_ECDH, + 0, + 0, + NULL, + "Curve25519", + userid, + password, + key); +} +FFI_GUARD + +rnp_result_t +rnp_generate_key_sm2(rnp_ffi_t ffi, + const char * userid, + const char * password, + rnp_key_handle_t *key) +try { + return rnp_generate_key_ex( + ffi, RNP_ALGNAME_SM2, RNP_ALGNAME_SM2, 0, 0, NULL, NULL, userid, password, key); +} +FFI_GUARD + +static pgp_key_flags_t +default_key_flags(pgp_pubkey_alg_t alg, bool subkey) +{ + switch (alg) { + case PGP_PKA_RSA: + return subkey ? PGP_KF_ENCRYPT : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); + case PGP_PKA_DSA: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); + case PGP_PKA_SM2: + return subkey ? PGP_KF_ENCRYPT : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); + case PGP_PKA_ECDH: + case PGP_PKA_ELGAMAL: + return PGP_KF_ENCRYPT; + default: + return PGP_KF_NONE; + } +} + +rnp_result_t +rnp_op_generate_create(rnp_op_generate_t *op, rnp_ffi_t ffi, const char *alg) +try { + pgp_pubkey_alg_t key_alg = PGP_PKA_NOTHING; + + if (!op || !ffi || !alg) { + return RNP_ERROR_NULL_POINTER; + } + + if (!ffi->pubring || !ffi->secring) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!str_to_pubkey_alg(alg, &key_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!(pgp_pk_alg_capabilities(key_alg) & PGP_KF_SIGN)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *op = new rnp_op_generate_st(); + (*op)->ffi = ffi; + (*op)->primary = true; + (*op)->crypto.key_alg = key_alg; + (*op)->crypto.ctx = &ffi->context; + (*op)->cert.key_flags = default_key_flags(key_alg, false); + (*op)->cert.key_expiration = DEFAULT_KEY_EXPIRATION; + + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_subkey_create(rnp_op_generate_t *op, + rnp_ffi_t ffi, + rnp_key_handle_t primary, + const char * alg) +try { + if (!op || !ffi || !alg || !primary) { + return RNP_ERROR_NULL_POINTER; + } + + if (!ffi->pubring || !ffi->secring) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* TODO: should we do these checks here or may leave it up till generate call? */ + if (!primary->sec || !primary->sec->usable_for(PGP_OP_ADD_SUBKEY)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_pubkey_alg_t key_alg = PGP_PKA_NOTHING; + if (!str_to_pubkey_alg(alg, &key_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *op = new rnp_op_generate_st(); + (*op)->ffi = ffi; + (*op)->primary = false; + (*op)->crypto.key_alg = key_alg; + (*op)->crypto.ctx = &ffi->context; + (*op)->binding.key_flags = default_key_flags(key_alg, true); + (*op)->binding.key_expiration = DEFAULT_KEY_EXPIRATION; + (*op)->primary_sec = primary->sec; + (*op)->primary_pub = primary->pub; + + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_bits(rnp_op_generate_t op, uint32_t bits) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + + switch (op->crypto.key_alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + op->crypto.rsa.modulus_bit_len = bits; + break; + case PGP_PKA_ELGAMAL: + op->crypto.elgamal.key_bitlen = bits; + break; + case PGP_PKA_DSA: + op->crypto.dsa.p_bitlen = bits; + break; + default: + return RNP_ERROR_BAD_PARAMETERS; + } + + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_hash(rnp_op_generate_t op, const char *hash) +try { + if (!op || !hash) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_hash_alg(hash, &op->crypto.hash_alg)) { + FFI_LOG(op->ffi, "Invalid hash: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_dsa_qbits(rnp_op_generate_t op, uint32_t qbits) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (op->crypto.key_alg != PGP_PKA_DSA) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->crypto.dsa.q_bitlen = qbits; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_curve(rnp_op_generate_t op, const char *curve) +try { + if (!op || !curve) { + return RNP_ERROR_NULL_POINTER; + } + if (!pk_alg_allows_custom_curve(op->crypto.key_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!curve_str_to_type(curve, &op->crypto.ecc.curve)) { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_protection_password(rnp_op_generate_t op, const char *password) +try { + if (!op || !password) { + return RNP_ERROR_NULL_POINTER; + } + op->password.assign(password, password + strlen(password) + 1); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_request_password(rnp_op_generate_t op, bool request) +try { + if (!op || !request) { + return RNP_ERROR_NULL_POINTER; + } + op->request_password = request; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_protection_cipher(rnp_op_generate_t op, const char *cipher) +try { + if (!op || !cipher) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_cipher(cipher, &op->protection.symm_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_protection_hash(rnp_op_generate_t op, const char *hash) +try { + if (!op || !hash) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_hash_alg(hash, &op->protection.hash_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_protection_mode(rnp_op_generate_t op, const char *mode) +try { + if (!op || !mode) { + return RNP_ERROR_NULL_POINTER; + } + if (!str_to_cipher_mode(mode, &op->protection.cipher_mode)) { + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_protection_iterations(rnp_op_generate_t op, uint32_t iterations) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + op->protection.iterations = iterations; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_add_usage(rnp_op_generate_t op, const char *usage) +try { + if (!op || !usage) { + return RNP_ERROR_NULL_POINTER; + } + uint8_t flag = 0; + if (!str_to_key_flag(usage, &flag)) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!(pgp_pk_alg_capabilities(op->crypto.key_alg) & flag)) { + return RNP_ERROR_NOT_SUPPORTED; + } + if (op->primary) { + op->cert.key_flags |= flag; + } else { + op->binding.key_flags |= flag; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_clear_usage(rnp_op_generate_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (op->primary) { + op->cert.key_flags = 0; + } else { + op->binding.key_flags = 0; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_userid(rnp_op_generate_t op, const char *userid) +try { + if (!op || !userid) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (strlen(userid) > MAX_ID_LENGTH) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.userid = userid; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_expiration(rnp_op_generate_t op, uint32_t expiration) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (op->primary) { + op->cert.key_expiration = expiration; + } else { + op->binding.key_expiration = expiration; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_clear_pref_hashes(rnp_op_generate_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.set_hash_algs({}); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_add_pref_hash(rnp_op_generate_t op, const char *hash) +try { + if (!op || !hash) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(hash, &hash_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.add_hash_alg(hash_alg); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_clear_pref_compression(rnp_op_generate_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.set_z_algs({}); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_add_pref_compression(rnp_op_generate_t op, const char *compression) +try { + if (!op || !compression) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_compression_type_t z_alg = PGP_C_UNKNOWN; + if (!str_to_compression_alg(compression, &z_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.add_z_alg(z_alg); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.set_symm_algs({}); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_add_pref_cipher(rnp_op_generate_t op, const char *cipher) +try { + if (!op || !cipher) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN; + if (!str_to_cipher(cipher, &symm_alg)) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.add_symm_alg(symm_alg); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, const char *keyserver) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->primary) { + return RNP_ERROR_BAD_PARAMETERS; + } + op->cert.prefs.key_server = keyserver ? keyserver : ""; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_execute(rnp_op_generate_t op) +try { + if (!op || !op->ffi) { + return RNP_ERROR_NULL_POINTER; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + pgp_key_t pub; + pgp_key_t sec; + pgp_password_provider_t prov; + + if (op->primary) { + rnp_keygen_primary_desc_t keygen = {}; + keygen.crypto = op->crypto; + keygen.cert = op->cert; + op->cert.prefs = {}; /* generate call will free prefs */ + + if (!pgp_generate_primary_key(keygen, true, sec, pub, op->ffi->secring->format)) { + return RNP_ERROR_KEY_GENERATION; + } + } else { + /* subkey generation */ + rnp_keygen_subkey_desc_t keygen = {}; + keygen.crypto = op->crypto; + keygen.binding = op->binding; + if (!pgp_generate_subkey(keygen, + true, + *op->primary_sec, + *op->primary_pub, + sec, + pub, + op->ffi->pass_provider, + op->ffi->secring->format)) { + return RNP_ERROR_KEY_GENERATION; + } + } + + /* add public key part to the keyring */ + if (!(op->gen_pub = rnp_key_store_add_key(op->ffi->pubring, &pub))) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + /* encrypt secret key if requested */ + if (!op->password.empty()) { + prov = {rnp_password_provider_string, (void *) op->password.data()}; + } else if (op->request_password) { + prov = {rnp_password_cb_bounce, op->ffi}; + } + if (prov.callback && !sec.protect(op->protection, prov, op->ffi->context)) { + FFI_LOG(op->ffi, "failed to encrypt the key"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto done; + } + + /* add secret key to the keyring */ + if (!(op->gen_sec = rnp_key_store_add_key(op->ffi->secring, &sec))) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + ret = RNP_SUCCESS; +done: + op->password.clear(); + if (ret && op->gen_pub) { + rnp_key_store_remove_key(op->ffi->pubring, op->gen_pub, false); + op->gen_pub = NULL; + } + if (ret && op->gen_sec) { + rnp_key_store_remove_key(op->ffi->secring, op->gen_sec, false); + op->gen_sec = NULL; + } + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_get_key(rnp_op_generate_t op, rnp_key_handle_t *handle) +try { + if (!op || !handle) { + return RNP_ERROR_NULL_POINTER; + } + if (!op->gen_sec || !op->gen_pub) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *handle = (rnp_key_handle_t) malloc(sizeof(**handle)); + if (!*handle) { + return RNP_ERROR_OUT_OF_MEMORY; + } + (*handle)->ffi = op->ffi; + (*handle)->pub = op->gen_pub; + (*handle)->sec = op->gen_sec; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_op_generate_destroy(rnp_op_generate_t op) +try { + delete op; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_handle_destroy(rnp_key_handle_t key) +try { + // This does not free key->key which is owned by the keyring + free(key); + return RNP_SUCCESS; +} +FFI_GUARD + +void +rnp_buffer_destroy(void *ptr) +{ + free(ptr); +} + +void +rnp_buffer_clear(void *ptr, size_t size) +{ + if (ptr) { + secure_clear(ptr, size); + } +} + +static pgp_key_t * +get_key_require_public(rnp_key_handle_t handle) +{ + if (!handle->pub && handle->sec) { + pgp_key_request_ctx_t request; + request.secret = false; + + // try fingerprint + request.search.type = PGP_KEY_SEARCH_FINGERPRINT; + request.search.by.fingerprint = handle->sec->fp(); + handle->pub = pgp_request_key(&handle->ffi->key_provider, &request); + if (handle->pub) { + return handle->pub; + } + + // try keyid + request.search.type = PGP_KEY_SEARCH_KEYID; + request.search.by.keyid = handle->sec->keyid(); + handle->pub = pgp_request_key(&handle->ffi->key_provider, &request); + } + return handle->pub; +} + +static pgp_key_t * +get_key_prefer_public(rnp_key_handle_t handle) +{ + pgp_key_t *pub = get_key_require_public(handle); + return pub ? pub : get_key_require_secret(handle); +} + +static pgp_key_t * +get_key_require_secret(rnp_key_handle_t handle) +{ + if (!handle->sec && handle->pub) { + pgp_key_request_ctx_t request; + request.secret = true; + + // try fingerprint + request.search.type = PGP_KEY_SEARCH_FINGERPRINT; + request.search.by.fingerprint = handle->pub->fp(); + handle->sec = pgp_request_key(&handle->ffi->key_provider, &request); + if (handle->sec) { + return handle->sec; + } + + // try keyid + request.search.type = PGP_KEY_SEARCH_KEYID; + request.search.by.keyid = handle->pub->keyid(); + handle->sec = pgp_request_key(&handle->ffi->key_provider, &request); + } + return handle->sec; +} + +static rnp_result_t +key_get_uid_at(pgp_key_t *key, size_t idx, char **uid) +{ + if (!key || !uid) { + return RNP_ERROR_NULL_POINTER; + } + if (idx >= key->uid_count()) { + return RNP_ERROR_BAD_PARAMETERS; + } + *uid = strdup(key->get_uid(idx).str.c_str()); + if (!*uid) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_key_add_uid(rnp_key_handle_t handle, + const char * uid, + const char * hash, + uint32_t expiration, + uint8_t key_flags, + bool primary) +try { + if (!handle || !uid) { + return RNP_ERROR_NULL_POINTER; + } + /* setup parameters */ + if (!hash) { + hash = DEFAULT_HASH_ALG; + } + pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN; + if (!str_to_hash_alg(hash, &hash_alg)) { + FFI_LOG(handle->ffi, "Invalid hash: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (strlen(uid) > MAX_ID_LENGTH) { + FFI_LOG(handle->ffi, "UserID too long"); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_selfsig_cert_info_t info; + info.userid = uid; + info.key_flags = key_flags; + info.key_expiration = expiration; + info.primary = primary; + + /* obtain and unlok secret key */ + pgp_key_t *secret_key = get_key_require_secret(handle); + if (!secret_key || !secret_key->usable_for(PGP_OP_ADD_USERID)) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + pgp_key_t *public_key = get_key_prefer_public(handle); + if (!public_key && secret_key->format == PGP_KEY_STORE_G10) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + rnp::KeyLocker seclock(*secret_key); + if (secret_key->is_locked() && + !secret_key->unlock(handle->ffi->pass_provider, PGP_OP_ADD_USERID)) { + return RNP_ERROR_BAD_PASSWORD; + } + /* add and certify userid */ + secret_key->add_uid_cert(info, hash_alg, handle->ffi->context, public_key); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_primary_uid(rnp_key_handle_t handle, char **uid) +try { + if (!handle || !uid) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = get_key_prefer_public(handle); + if (key->has_primary_uid()) { + return key_get_uid_at(key, key->get_primary_uid(), uid); + } + for (size_t i = 0; i < key->uid_count(); i++) { + if (!key->get_uid(i).valid) { + continue; + } + return key_get_uid_at(key, i, uid); + } + return RNP_ERROR_BAD_PARAMETERS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_uid_count(rnp_key_handle_t handle, size_t *count) +try { + if (!handle || !count) { + return RNP_ERROR_NULL_POINTER; + } + + *count = get_key_prefer_public(handle)->uid_count(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_uid_at(rnp_key_handle_t handle, size_t idx, char **uid) +try { + if (handle == NULL || uid == NULL) + return RNP_ERROR_NULL_POINTER; + + pgp_key_t *key = get_key_prefer_public(handle); + return key_get_uid_at(key, idx, uid); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_uid_handle_at(rnp_key_handle_t key, size_t idx, rnp_uid_handle_t *uid) +try { + if (!key || !uid) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *akey = get_key_prefer_public(key); + if (!akey) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (idx >= akey->uid_count()) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *uid = (rnp_uid_handle_t) malloc(sizeof(**uid)); + if (!*uid) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + (*uid)->ffi = key->ffi; + (*uid)->key = akey; + (*uid)->idx = idx; + return RNP_SUCCESS; +} +FFI_GUARD + +static pgp_userid_t * +rnp_uid_handle_get_uid(rnp_uid_handle_t uid) +{ + if (!uid || !uid->key) { + return NULL; + } + return &uid->key->get_uid(uid->idx); +} + +rnp_result_t +rnp_uid_get_type(rnp_uid_handle_t uid, uint32_t *type) +try { + if (!type) { + return RNP_ERROR_NULL_POINTER; + } + pgp_userid_t *id = rnp_uid_handle_get_uid(uid); + if (!id) { + return RNP_ERROR_NULL_POINTER; + } + switch (id->pkt.tag) { + case PGP_PKT_USER_ID: + *type = RNP_USER_ID; + return RNP_SUCCESS; + case PGP_PKT_USER_ATTR: + *type = RNP_USER_ATTR; + return RNP_SUCCESS; + default: + return RNP_ERROR_BAD_STATE; + } +} +FFI_GUARD + +rnp_result_t +rnp_uid_get_data(rnp_uid_handle_t uid, void **data, size_t *size) +try { + if (!data || !size) { + return RNP_ERROR_NULL_POINTER; + } + pgp_userid_t *id = rnp_uid_handle_get_uid(uid); + if (!id) { + return RNP_ERROR_NULL_POINTER; + } + *data = malloc(id->pkt.uid_len); + if (id->pkt.uid_len && !*data) { + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(*data, id->pkt.uid, id->pkt.uid_len); + *size = id->pkt.uid_len; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_uid_is_primary(rnp_uid_handle_t uid, bool *primary) +try { + if (!primary) { + return RNP_ERROR_NULL_POINTER; + } + pgp_userid_t *id = rnp_uid_handle_get_uid(uid); + if (!id) { + return RNP_ERROR_NULL_POINTER; + } + *primary = uid->key->has_primary_uid() && (uid->key->get_primary_uid() == uid->idx); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_uid_is_valid(rnp_uid_handle_t uid, bool *valid) +try { + if (!valid) { + return RNP_ERROR_NULL_POINTER; + } + pgp_userid_t *id = rnp_uid_handle_get_uid(uid); + if (!id) { + return RNP_ERROR_NULL_POINTER; + } + *valid = id->valid; + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +rnp_key_return_signature(rnp_ffi_t ffi, + pgp_key_t * key, + pgp_subsig_t * subsig, + rnp_signature_handle_t *sig) +{ + *sig = (rnp_signature_handle_t) calloc(1, sizeof(**sig)); + if (!*sig) { + return RNP_ERROR_OUT_OF_MEMORY; + } + (*sig)->ffi = ffi; + (*sig)->key = key; + (*sig)->sig = subsig; + return RNP_SUCCESS; +} + +rnp_result_t +rnp_key_get_signature_count(rnp_key_handle_t handle, size_t *count) +try { + if (!handle || !count) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *count = key->keysig_count(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_signature_at(rnp_key_handle_t handle, size_t idx, rnp_signature_handle_t *sig) +try { + if (!handle || !sig) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = get_key_prefer_public(handle); + if (!key || (idx >= key->keysig_count())) { + return RNP_ERROR_BAD_PARAMETERS; + } + return rnp_key_return_signature(handle->ffi, key, &key->get_keysig(idx), sig); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_revocation_signature(rnp_key_handle_t handle, rnp_signature_handle_t *sig) +try { + if (!handle || !sig) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!key->revoked()) { + *sig = NULL; + return RNP_SUCCESS; + } + if (!key->has_sig(key->revocation().sigid)) { + return RNP_ERROR_BAD_STATE; + } + return rnp_key_return_signature( + handle->ffi, key, &key->get_sig(key->revocation().sigid), sig); +} +FFI_GUARD + +rnp_result_t +rnp_uid_get_signature_count(rnp_uid_handle_t handle, size_t *count) +try { + if (!handle || !count) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *count = handle->key->get_uid(handle->idx).sig_count(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_uid_get_signature_at(rnp_uid_handle_t handle, size_t idx, rnp_signature_handle_t *sig) +try { + if (!handle || !sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->key) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_userid_t &uid = handle->key->get_uid(handle->idx); + if (idx >= uid.sig_count()) { + return RNP_ERROR_BAD_PARAMETERS; + } + const pgp_sig_id_t &sigid = uid.get_sig(idx); + if (!handle->key->has_sig(sigid)) { + return RNP_ERROR_BAD_STATE; + } + return rnp_key_return_signature( + handle->ffi, handle->key, &handle->key->get_sig(sigid), sig); +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_type(rnp_signature_handle_t handle, char **type) +try { + if (!handle || !type) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + auto sigtype = id_str_pair::lookup(sig_type_map, handle->sig->sig.type()); + return ret_str_value(sigtype, type); +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_alg(rnp_signature_handle_t handle, char **alg) +try { + if (!handle || !alg) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + return get_map_value(pubkey_alg_map, handle->sig->sig.palg, alg); +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_hash_alg(rnp_signature_handle_t handle, char **alg) +try { + if (!handle || !alg) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + return get_map_value(hash_alg_map, handle->sig->sig.halg, alg); +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_creation(rnp_signature_handle_t handle, uint32_t *create) +try { + if (!handle || !create) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + *create = handle->sig->sig.creation(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_expiration(rnp_signature_handle_t handle, uint32_t *expires) +try { + if (!handle || !expires) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + *expires = handle->sig->sig.expiration(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_keyid(rnp_signature_handle_t handle, char **result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!handle->sig->sig.has_keyid()) { + *result = NULL; + return RNP_SUCCESS; + } + pgp_key_id_t keyid = handle->sig->sig.keyid(); + return hex_encode_value(keyid.data(), keyid.size(), result); +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_key_fprint(rnp_signature_handle_t handle, char **result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + if (!handle->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!handle->sig->sig.has_keyfp()) { + *result = NULL; + return RNP_SUCCESS; + } + pgp_fingerprint_t keyfp = handle->sig->sig.keyfp(); + return hex_encode_value(keyfp.fingerprint, keyfp.length, result); +} +FFI_GUARD + +rnp_result_t +rnp_signature_get_signer(rnp_signature_handle_t sig, rnp_key_handle_t *key) +try { + if (!sig || !sig->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!sig->sig->sig.has_keyid()) { + *key = NULL; + return RNP_SUCCESS; + } + pgp_key_search_t locator(PGP_KEY_SEARCH_KEYID); + locator.by.keyid = sig->sig->sig.keyid(); + return rnp_locate_key_int(sig->ffi, locator, key); +} +FFI_GUARD + +rnp_result_t +rnp_signature_is_valid(rnp_signature_handle_t sig, uint32_t flags) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->sig || sig->own_sig || flags) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!sig->sig->validity.validated) { + pgp_key_t *signer = + pgp_sig_get_signer(*sig->sig, sig->ffi->pubring, &sig->ffi->key_provider); + if (!signer) { + return RNP_ERROR_KEY_NOT_FOUND; + } + signer->validate_sig(*sig->key, *sig->sig, sig->ffi->context); + } + + if (!sig->sig->validity.validated) { + return RNP_ERROR_VERIFICATION_FAILED; + } + if (sig->sig->validity.expired) { + return RNP_ERROR_SIGNATURE_EXPIRED; + } + return sig->sig->valid() ? RNP_SUCCESS : RNP_ERROR_SIGNATURE_INVALID; +} +FFI_GUARD + +rnp_result_t +rnp_signature_packet_to_json(rnp_signature_handle_t sig, uint32_t flags, char **json) +try { + if (!sig || !json) { + return RNP_ERROR_NULL_POINTER; + } + + rnp::MemoryDest memdst; + sig->sig->sig.write(memdst.dst()); + auto vec = memdst.to_vector(); + rnp::MemorySource memsrc(vec); + return rnp_dump_src_to_json(&memsrc.src(), flags, json); +} +FFI_GUARD + +rnp_result_t +rnp_signature_remove(rnp_key_handle_t key, rnp_signature_handle_t sig) +try { + if (!key || !sig) { + return RNP_ERROR_NULL_POINTER; + } + if (sig->own_sig || !sig->sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *pkey = get_key_require_public(key); + pgp_key_t *skey = get_key_require_secret(key); + if (!pkey && !skey) { + return RNP_ERROR_BAD_PARAMETERS; + } + const pgp_sig_id_t sigid = sig->sig->sigid; + bool ok = false; + if (pkey) { + ok = pkey->del_sig(sigid); + pkey->revalidate(*key->ffi->pubring); + } + if (skey) { + /* secret key may not have signature, but we still need to delete it at least once to + * succeed */ + ok = skey->del_sig(sigid) || ok; + skey->revalidate(*key->ffi->secring); + } + return ok ? RNP_SUCCESS : RNP_ERROR_NO_SIGNATURES_FOUND; +} +FFI_GUARD + +static rnp_result_t +write_signature(rnp_signature_handle_t sig, pgp_dest_t &dst) +{ + sig->sig->rawpkt.write(dst); + dst_flush(&dst); + return dst.werr; +} + +rnp_result_t +rnp_signature_export(rnp_signature_handle_t sig, rnp_output_t output, uint32_t flags) +try { + if (!sig || !sig->sig || !output) { + return RNP_ERROR_NULL_POINTER; + } + bool need_armor = extract_flag(flags, RNP_KEY_EXPORT_ARMORED); + if (flags) { + FFI_LOG(sig->ffi, "Invalid flags: %" PRIu32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + rnp_result_t ret; + if (need_armor) { + rnp::ArmoredDest armor(output->dst, PGP_ARMORED_PUBLIC_KEY); + ret = write_signature(sig, armor.dst()); + } else { + ret = write_signature(sig, output->dst); + } + output->keep = !ret; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_signature_handle_destroy(rnp_signature_handle_t sig) +try { + if (sig && sig->own_sig) { + delete sig->sig; + } + free(sig); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_uid_is_revoked(rnp_uid_handle_t uid, bool *result) +try { + if (!uid || !result) { + return RNP_ERROR_NULL_POINTER; + } + + if (!uid->key) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *result = uid->key->get_uid(uid->idx).revoked; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_uid_get_revocation_signature(rnp_uid_handle_t uid, rnp_signature_handle_t *sig) +try { + if (!uid || !sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!uid->key) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (uid->idx >= uid->key->uid_count()) { + return RNP_ERROR_BAD_STATE; + } + const pgp_userid_t &userid = uid->key->get_uid(uid->idx); + if (!userid.revoked) { + *sig = NULL; + return RNP_SUCCESS; + } + if (!uid->key->has_sig(userid.revocation.sigid)) { + return RNP_ERROR_BAD_STATE; + } + return rnp_key_return_signature( + uid->ffi, uid->key, &uid->key->get_sig(userid.revocation.sigid), sig); +} +FFI_GUARD + +rnp_result_t +rnp_uid_remove(rnp_key_handle_t key, rnp_uid_handle_t uid) +try { + if (!key || !uid) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *pkey = get_key_require_public(key); + pgp_key_t *skey = get_key_require_secret(key); + if (!pkey && !skey) { + return RNP_ERROR_BAD_PARAMETERS; + } + if ((uid->key != pkey) && (uid->key != skey)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + bool ok = false; + if (pkey && (pkey->uid_count() > uid->idx)) { + pkey->del_uid(uid->idx); + pkey->revalidate(*key->ffi->pubring); + ok = true; + } + if (skey && (skey->uid_count() > uid->idx)) { + skey->del_uid(uid->idx); + skey->revalidate(*key->ffi->secring); + ok = true; + } + return ok ? RNP_SUCCESS : RNP_ERROR_BAD_PARAMETERS; +} +FFI_GUARD + +rnp_result_t +rnp_uid_handle_destroy(rnp_uid_handle_t uid) +try { + free(uid); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_subkey_count(rnp_key_handle_t handle, size_t *count) +try { + if (!handle || !count) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + *count = key->subkey_count(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_subkey_at(rnp_key_handle_t handle, size_t idx, rnp_key_handle_t *subkey) +try { + if (!handle || !subkey) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (idx >= key->subkey_count()) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_search_t locator(PGP_KEY_SEARCH_FINGERPRINT); + locator.by.fingerprint = key->get_subkey_fp(idx); + return rnp_locate_key_int(handle->ffi, locator, subkey); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_default_key(rnp_key_handle_t primary_key, + const char * usage, + uint32_t flags, + rnp_key_handle_t *default_key) +try { + if (!primary_key || !usage || !default_key) { + return RNP_ERROR_NULL_POINTER; + } + uint8_t keyflag = 0; + if (!str_to_key_flag(usage, &keyflag)) { + return RNP_ERROR_BAD_PARAMETERS; + } + bool no_primary = extract_flag(flags, RNP_KEY_SUBKEYS_ONLY); + if (flags) { + FFI_LOG(primary_key->ffi, "Invalid flags: %" PRIu32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_op_t op = PGP_OP_UNKNOWN; + bool secret = false; + switch (keyflag) { + case PGP_KF_SIGN: + op = PGP_OP_SIGN; + secret = true; + break; + case PGP_KF_CERTIFY: + op = PGP_OP_CERTIFY; + secret = true; + break; + case PGP_KF_ENCRYPT: + op = PGP_OP_ENCRYPT; + break; + default: + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *key = get_key_prefer_public(primary_key); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *defkey = + find_suitable_key(op, key, &primary_key->ffi->key_provider, no_primary); + if (!defkey) { + *default_key = NULL; + return RNP_ERROR_NO_SUITABLE_KEY; + } + + pgp_key_search_t search(PGP_KEY_SEARCH_FINGERPRINT); + search.by.fingerprint = defkey->fp(); + + rnp_result_t ret = rnp_locate_key_int(primary_key->ffi, search, default_key, secret); + + if (!*default_key && !ret) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_alg(rnp_key_handle_t handle, char **alg) +try { + if (!handle || !alg) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + return get_map_value(pubkey_alg_map, key->alg(), alg); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_bits(rnp_key_handle_t handle, uint32_t *bits) +try { + if (!handle || !bits) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + size_t _bits = key->material().bits(); + if (!_bits) { + return RNP_ERROR_BAD_PARAMETERS; + } + *bits = _bits; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_dsa_qbits(rnp_key_handle_t handle, uint32_t *qbits) +try { + if (!handle || !qbits) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + size_t _qbits = key->material().qbits(); + if (!_qbits) { + return RNP_ERROR_BAD_PARAMETERS; + } + *qbits = _qbits; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_curve(rnp_key_handle_t handle, char **curve) +try { + if (!handle || !curve) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t * key = get_key_prefer_public(handle); + pgp_curve_t _curve = key->curve(); + if (_curve == PGP_CURVE_UNKNOWN) { + return RNP_ERROR_BAD_PARAMETERS; + } + const char *curvename = NULL; + if (!curve_type_to_str(_curve, &curvename)) { + return RNP_ERROR_BAD_PARAMETERS; + } + char *curvenamecp = strdup(curvename); + if (!curvenamecp) { + return RNP_ERROR_OUT_OF_MEMORY; + } + *curve = curvenamecp; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_fprint(rnp_key_handle_t handle, char **fprint) +try { + if (!handle || !fprint) { + return RNP_ERROR_NULL_POINTER; + } + + const pgp_fingerprint_t &fp = get_key_prefer_public(handle)->fp(); + return hex_encode_value(fp.fingerprint, fp.length, fprint); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_keyid(rnp_key_handle_t handle, char **keyid) +try { + if (!handle || !keyid) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = get_key_prefer_public(handle); + return hex_encode_value(key->keyid().data(), key->keyid().size(), keyid); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_grip(rnp_key_handle_t handle, char **grip) +try { + if (!handle || !grip) { + return RNP_ERROR_NULL_POINTER; + } + + const pgp_key_grip_t &kgrip = get_key_prefer_public(handle)->grip(); + return hex_encode_value(kgrip.data(), kgrip.size(), grip); +} +FFI_GUARD + +static const pgp_key_grip_t * +rnp_get_grip_by_fp(rnp_ffi_t ffi, const pgp_fingerprint_t &fp) +{ + pgp_key_t *key = NULL; + if (ffi->pubring) { + key = rnp_key_store_get_key_by_fpr(ffi->pubring, fp); + } + if (!key && ffi->secring) { + key = rnp_key_store_get_key_by_fpr(ffi->secring, fp); + } + return key ? &key->grip() : NULL; +} + +rnp_result_t +rnp_key_get_primary_grip(rnp_key_handle_t handle, char **grip) +try { + if (!handle || !grip) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = get_key_prefer_public(handle); + if (!key->is_subkey()) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!key->has_primary_fp()) { + *grip = NULL; + return RNP_SUCCESS; + } + const pgp_key_grip_t *pgrip = rnp_get_grip_by_fp(handle->ffi, key->primary_fp()); + if (!pgrip) { + *grip = NULL; + return RNP_SUCCESS; + } + return hex_encode_value(pgrip->data(), pgrip->size(), grip); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_primary_fprint(rnp_key_handle_t handle, char **fprint) +try { + if (!handle || !fprint) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = get_key_prefer_public(handle); + if (!key->is_subkey()) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!key->has_primary_fp()) { + *fprint = NULL; + return RNP_SUCCESS; + } + const pgp_fingerprint_t &fp = key->primary_fp(); + return hex_encode_value(fp.fingerprint, fp.length, fprint); +} +FFI_GUARD + +rnp_result_t +rnp_key_allows_usage(rnp_key_handle_t handle, const char *usage, bool *result) +try { + if (!handle || !usage || !result) { + return RNP_ERROR_NULL_POINTER; + } + uint8_t flag = 0; + if (!str_to_key_flag(usage, &flag)) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *result = key->flags() & flag; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_creation(rnp_key_handle_t handle, uint32_t *result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *result = key->creation(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_is_revoked(rnp_key_handle_t handle, bool *result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *result = key->revoked(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_is_valid(rnp_key_handle_t handle, bool *result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_require_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!key->validated()) { + key->validate(*handle->ffi->pubring); + } + if (!key->validated()) { + return RNP_ERROR_VERIFICATION_FAILED; + } + *result = key->valid(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_valid_till(rnp_key_handle_t handle, uint32_t *result) +try { + if (!result) { + return RNP_ERROR_NULL_POINTER; + } + uint64_t res = 0; + rnp_result_t ret = rnp_key_valid_till64(handle, &res); + if (ret) { + return ret; + } + if (res == UINT64_MAX) { + *result = UINT32_MAX; + } else if (res >= UINT32_MAX) { + *result = UINT32_MAX - 1; + } else { + *result = (uint32_t) res; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_valid_till64(rnp_key_handle_t handle, uint64_t *result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_require_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!key->validated()) { + key->validate(*handle->ffi->pubring); + } + if (!key->validated()) { + return RNP_ERROR_VERIFICATION_FAILED; + } + + if (key->is_subkey()) { + /* check validity time of the primary key as well */ + pgp_key_t *primary = rnp_key_store_get_primary_key(handle->ffi->pubring, key); + if (!primary) { + /* no primary key - subkey considered as never valid */ + *result = 0; + return RNP_SUCCESS; + } + if (!primary->validated()) { + primary->validate(*handle->ffi->pubring); + } + if (!primary->validated()) { + return RNP_ERROR_VERIFICATION_FAILED; + } + *result = key->valid_till(); + } else { + *result = key->valid_till(); + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_expiration(rnp_key_handle_t handle, uint32_t *result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *result = key->expiration(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_set_expiration(rnp_key_handle_t key, uint32_t expiry) +try { + if (!key) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *pkey = get_key_prefer_public(key); + if (!pkey) { + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_key_t *skey = get_key_require_secret(key); + if (!skey) { + FFI_LOG(key->ffi, "Secret key required."); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (pkey->is_primary()) { + if (!pgp_key_set_expiration( + pkey, skey, expiry, key->ffi->pass_provider, key->ffi->context)) { + return RNP_ERROR_GENERIC; + } + pkey->revalidate(*key->ffi->pubring); + if (pkey != skey) { + skey->revalidate(*key->ffi->secring); + } + return RNP_SUCCESS; + } + + /* for subkey we need primary key */ + if (!pkey->has_primary_fp()) { + FFI_LOG(key->ffi, "Primary key fp not available."); + return RNP_ERROR_BAD_PARAMETERS; + } + + pgp_key_search_t search(PGP_KEY_SEARCH_FINGERPRINT); + search.by.fingerprint = pkey->primary_fp(); + pgp_key_t *prim_sec = find_key(key->ffi, search, true, true); + if (!prim_sec) { + FFI_LOG(key->ffi, "Primary secret key not found."); + return RNP_ERROR_KEY_NOT_FOUND; + } + if (!pgp_subkey_set_expiration( + pkey, prim_sec, skey, expiry, key->ffi->pass_provider, key->ffi->context)) { + return RNP_ERROR_GENERIC; + } + prim_sec->revalidate(*key->ffi->secring); + pgp_key_t *prim_pub = find_key(key->ffi, search, false, true); + if (prim_pub) { + prim_pub->revalidate(*key->ffi->pubring); + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_revocation_reason(rnp_key_handle_t handle, char **result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key || !key->revoked()) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *result = strdup(key->revocation().reason.c_str()); + if (!*result) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +rnp_key_is_revoked_with_code(rnp_key_handle_t handle, bool *result, int code) +{ + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key || !key->revoked()) { + return RNP_ERROR_BAD_PARAMETERS; + } + + *result = key->revocation().code == code; + return RNP_SUCCESS; +} + +rnp_result_t +rnp_key_is_superseded(rnp_key_handle_t handle, bool *result) +try { + return rnp_key_is_revoked_with_code(handle, result, PGP_REVOCATION_SUPERSEDED); +} +FFI_GUARD + +rnp_result_t +rnp_key_is_compromised(rnp_key_handle_t handle, bool *result) +try { + return rnp_key_is_revoked_with_code(handle, result, PGP_REVOCATION_COMPROMISED); +} +FFI_GUARD + +rnp_result_t +rnp_key_is_retired(rnp_key_handle_t handle, bool *result) +try { + return rnp_key_is_revoked_with_code(handle, result, PGP_REVOCATION_RETIRED); +} +FFI_GUARD + +rnp_result_t +rnp_key_is_expired(rnp_key_handle_t handle, bool *result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_prefer_public(handle); + if (!key) { + return RNP_ERROR_BAD_PARAMETERS; + } + *result = key->expired(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_get_protection_type(rnp_key_handle_t key, char **type) +try { + if (!key || !type) { + return RNP_ERROR_NULL_POINTER; + } + if (!key->sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + + const pgp_s2k_t &s2k = key->sec->pkt().sec_protection.s2k; + const char * res = "Unknown"; + if (s2k.usage == PGP_S2KU_NONE) { + res = "None"; + } + if ((s2k.usage == PGP_S2KU_ENCRYPTED) && (s2k.specifier != PGP_S2KS_EXPERIMENTAL)) { + res = "Encrypted"; + } + if ((s2k.usage == PGP_S2KU_ENCRYPTED_AND_HASHED) && + (s2k.specifier != PGP_S2KS_EXPERIMENTAL)) { + res = "Encrypted-Hashed"; + } + if ((s2k.specifier == PGP_S2KS_EXPERIMENTAL) && + (s2k.gpg_ext_num == PGP_S2K_GPG_NO_SECRET)) { + res = "GPG-None"; + } + if ((s2k.specifier == PGP_S2KS_EXPERIMENTAL) && + (s2k.gpg_ext_num == PGP_S2K_GPG_SMARTCARD)) { + res = "GPG-Smartcard"; + } + + return ret_str_value(res, type); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_protection_mode(rnp_key_handle_t key, char **mode) +try { + if (!key || !mode) { + return RNP_ERROR_NULL_POINTER; + } + if (!key->sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (key->sec->pkt().sec_protection.s2k.usage == PGP_S2KU_NONE) { + return ret_str_value("None", mode); + } + if (key->sec->pkt().sec_protection.s2k.specifier == PGP_S2KS_EXPERIMENTAL) { + return ret_str_value("Unknown", mode); + } + + return get_map_value(cipher_mode_map, key->sec->pkt().sec_protection.cipher_mode, mode); +} +FFI_GUARD + +static bool +pgp_key_has_encryption_info(const pgp_key_t *key) +{ + return (key->pkt().sec_protection.s2k.usage != PGP_S2KU_NONE) && + (key->pkt().sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL); +} + +rnp_result_t +rnp_key_get_protection_cipher(rnp_key_handle_t key, char **cipher) +try { + if (!key || !cipher) { + return RNP_ERROR_NULL_POINTER; + } + if (!key->sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!pgp_key_has_encryption_info(key->sec)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + return get_map_value(symm_alg_map, key->sec->pkt().sec_protection.symm_alg, cipher); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_protection_hash(rnp_key_handle_t key, char **hash) +try { + if (!key || !hash) { + return RNP_ERROR_NULL_POINTER; + } + if (!key->sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!pgp_key_has_encryption_info(key->sec)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + return get_map_value(hash_alg_map, key->sec->pkt().sec_protection.s2k.hash_alg, hash); +} +FFI_GUARD + +rnp_result_t +rnp_key_get_protection_iterations(rnp_key_handle_t key, size_t *iterations) +try { + if (!key || !iterations) { + return RNP_ERROR_NULL_POINTER; + } + if (!key->sec) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!pgp_key_has_encryption_info(key->sec)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if (key->sec->pkt().sec_protection.s2k.specifier == PGP_S2KS_ITERATED_AND_SALTED) { + *iterations = pgp_s2k_decode_iterations(key->sec->pkt().sec_protection.s2k.iterations); + } else { + *iterations = 1; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_is_locked(rnp_key_handle_t handle, bool *result) +try { + if (handle == NULL || result == NULL) + return RNP_ERROR_NULL_POINTER; + + pgp_key_t *key = get_key_require_secret(handle); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + *result = key->is_locked(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_lock(rnp_key_handle_t handle) +try { + if (handle == NULL) + return RNP_ERROR_NULL_POINTER; + + pgp_key_t *key = get_key_require_secret(handle); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + if (!key->lock()) { + return RNP_ERROR_GENERIC; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_unlock(rnp_key_handle_t handle, const char *password) +try { + if (!handle) { + return RNP_ERROR_NULL_POINTER; + } + pgp_key_t *key = get_key_require_secret(handle); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + bool ok = false; + if (password) { + pgp_password_provider_t prov(rnp_password_provider_string, + reinterpret_cast(const_cast(password))); + ok = key->unlock(prov); + } else { + ok = key->unlock(handle->ffi->pass_provider); + } + if (!ok) { + // likely a bad password + return RNP_ERROR_BAD_PASSWORD; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_is_protected(rnp_key_handle_t handle, bool *result) +try { + if (handle == NULL || result == NULL) + return RNP_ERROR_NULL_POINTER; + + pgp_key_t *key = get_key_require_secret(handle); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + *result = key->is_protected(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_protect(rnp_key_handle_t handle, + const char * password, + const char * cipher, + const char * cipher_mode, + const char * hash, + size_t iterations) +try { + rnp_key_protection_params_t protection = {}; + + // checks + if (!handle || !password) { + return RNP_ERROR_NULL_POINTER; + } + + if (cipher && !str_to_cipher(cipher, &protection.symm_alg)) { + FFI_LOG(handle->ffi, "Invalid cipher: %s", cipher); + return RNP_ERROR_BAD_PARAMETERS; + } + if (cipher_mode && !str_to_cipher_mode(cipher_mode, &protection.cipher_mode)) { + FFI_LOG(handle->ffi, "Invalid cipher mode: %s", cipher_mode); + return RNP_ERROR_BAD_PARAMETERS; + } + if (hash && !str_to_hash_alg(hash, &protection.hash_alg)) { + FFI_LOG(handle->ffi, "Invalid hash: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + protection.iterations = iterations; + + // get the key + pgp_key_t *key = get_key_require_secret(handle); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + pgp_key_pkt_t * decrypted_key = NULL; + const std::string pass = password; + if (key->encrypted()) { + pgp_password_ctx_t ctx(PGP_OP_PROTECT, key); + decrypted_key = pgp_decrypt_seckey(*key, handle->ffi->pass_provider, ctx); + if (!decrypted_key) { + return RNP_ERROR_GENERIC; + } + } + bool res = key->protect( + decrypted_key ? *decrypted_key : key->pkt(), protection, pass, handle->ffi->context); + delete decrypted_key; + return res ? RNP_SUCCESS : RNP_ERROR_GENERIC; +} +FFI_GUARD + +rnp_result_t +rnp_key_unprotect(rnp_key_handle_t handle, const char *password) +try { + // checks + if (!handle) { + return RNP_ERROR_NULL_POINTER; + } + + // get the key + pgp_key_t *key = get_key_require_secret(handle); + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + bool ok = false; + if (password) { + pgp_password_provider_t prov(rnp_password_provider_string, + reinterpret_cast(const_cast(password))); + ok = key->unprotect(prov, handle->ffi->context); + } else { + ok = key->unprotect(handle->ffi->pass_provider, handle->ffi->context); + } + if (!ok) { + // likely a bad password + return RNP_ERROR_BAD_PASSWORD; + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_is_primary(rnp_key_handle_t handle, bool *result) +try { + if (handle == NULL || result == NULL) + return RNP_ERROR_NULL_POINTER; + + pgp_key_t *key = get_key_prefer_public(handle); + if (key->format == PGP_KEY_STORE_G10) { + // we can't currently determine this for a G10 secret key + return RNP_ERROR_NO_SUITABLE_KEY; + } + *result = key->is_primary(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_is_sub(rnp_key_handle_t handle, bool *result) +try { + if (handle == NULL || result == NULL) + return RNP_ERROR_NULL_POINTER; + + pgp_key_t *key = get_key_prefer_public(handle); + if (key->format == PGP_KEY_STORE_G10) { + // we can't currently determine this for a G10 secret key + return RNP_ERROR_NO_SUITABLE_KEY; + } + *result = key->is_subkey(); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_have_secret(rnp_key_handle_t handle, bool *result) +try { + if (handle == NULL || result == NULL) + return RNP_ERROR_NULL_POINTER; + + *result = handle->sec != NULL; + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_have_public(rnp_key_handle_t handle, bool *result) +try { + if (handle == NULL || result == NULL) + return RNP_ERROR_NULL_POINTER; + *result = handle->pub != NULL; + return RNP_SUCCESS; +} +FFI_GUARD + +static rnp_result_t +key_to_bytes(pgp_key_t *key, uint8_t **buf, size_t *buf_len) +{ + auto vec = rnp_key_to_vec(*key); + *buf = (uint8_t *) calloc(1, vec.size()); + if (!*buf) { + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(*buf, vec.data(), vec.size()); + *buf_len = vec.size(); + return RNP_SUCCESS; +} + +rnp_result_t +rnp_get_public_key_data(rnp_key_handle_t handle, uint8_t **buf, size_t *buf_len) +try { + // checks + if (!handle || !buf || !buf_len) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = handle->pub; + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + return key_to_bytes(key, buf, buf_len); +} +FFI_GUARD + +rnp_result_t +rnp_get_secret_key_data(rnp_key_handle_t handle, uint8_t **buf, size_t *buf_len) +try { + // checks + if (!handle || !buf || !buf_len) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = handle->sec; + if (!key) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + return key_to_bytes(key, buf, buf_len); +} +FFI_GUARD + +static bool +add_json_string_field(json_object *jso, const char *key, const char *value) +{ + json_object *jsostr = json_object_new_string(value); + if (!jsostr) { + return false; + } + json_object_object_add(jso, key, jsostr); + return true; +} + +static bool +add_json_int_field(json_object *jso, const char *key, int32_t value) +{ + json_object *jsoval = json_object_new_int(value); + if (!jsoval) { + return false; + } + json_object_object_add(jso, key, jsoval); + return true; +} + +static bool +add_json_key_usage(json_object *jso, uint8_t key_flags) +{ + json_object *jsoarr = json_object_new_array(); + if (!jsoarr) { + return false; + } + for (size_t i = 0; i < ARRAY_SIZE(key_usage_map); i++) { + if (key_usage_map[i].id & key_flags) { + json_object *jsostr = json_object_new_string(key_usage_map[i].str); + if (!jsostr || json_object_array_add(jsoarr, jsostr)) { + json_object_put(jsoarr); + return false; + } + } + } + if (json_object_array_length(jsoarr)) { + json_object_object_add(jso, "usage", jsoarr); + } else { + json_object_put(jsoarr); + } + return true; +} + +static bool +add_json_key_flags(json_object *jso, uint8_t key_flags) +{ + json_object *jsoarr = json_object_new_array(); + if (!jsoarr) { + return false; + } + for (size_t i = 0; i < ARRAY_SIZE(key_flags_map); i++) { + if (key_flags_map[i].id & key_flags) { + json_object *jsostr = json_object_new_string(key_flags_map[i].str); + if (!jsostr || json_object_array_add(jsoarr, jsostr)) { + json_object_put(jsoarr); + return false; + } + } + } + if (json_object_array_length(jsoarr)) { + json_object_object_add(jso, "flags", jsoarr); + } else { + json_object_put(jsoarr); + } + return true; +} + +static rnp_result_t +add_json_mpis(json_object *jso, ...) +{ + va_list ap; + const char * name; + rnp_result_t ret = RNP_ERROR_GENERIC; + + va_start(ap, jso); + while ((name = va_arg(ap, const char *))) { + pgp_mpi_t *val = va_arg(ap, pgp_mpi_t *); + if (!val) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto done; + } + char *hex = mpi2hex(val); + if (!hex) { + // this could probably be other things + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + json_object *jsostr = json_object_new_string(hex); + free(hex); + if (!jsostr) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + json_object_object_add(jso, name, jsostr); + } + ret = RNP_SUCCESS; + +done: + va_end(ap); + return ret; +} + +static rnp_result_t +add_json_public_mpis(json_object *jso, pgp_key_t *key) +{ + const pgp_key_material_t &km = key->material(); + switch (km.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return add_json_mpis(jso, "n", &km.rsa.n, "e", &km.rsa.e, NULL); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return add_json_mpis(jso, "p", &km.eg.p, "g", &km.eg.g, "y", &km.eg.y, NULL); + case PGP_PKA_DSA: + return add_json_mpis( + jso, "p", &km.dsa.p, "q", &km.dsa.q, "g", &km.dsa.g, "y", &km.dsa.y, NULL); + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + return add_json_mpis(jso, "point", &km.ec.p, NULL); + default: + return RNP_ERROR_NOT_SUPPORTED; + } + return RNP_SUCCESS; +} + +static rnp_result_t +add_json_secret_mpis(json_object *jso, pgp_key_t *key) +{ + const pgp_key_material_t &km = key->material(); + switch (key->alg()) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return add_json_mpis( + jso, "d", &km.rsa.d, "p", &km.rsa.p, "q", &km.rsa.q, "u", &km.rsa.u, NULL); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return add_json_mpis(jso, "x", &km.eg.x, NULL); + case PGP_PKA_DSA: + return add_json_mpis(jso, "x", &km.dsa.x, NULL); + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + return add_json_mpis(jso, "x", &km.ec.x, NULL); + default: + return RNP_ERROR_NOT_SUPPORTED; + } + return RNP_SUCCESS; +} + +static rnp_result_t +add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) +{ + pgp_signature_material_t material = {}; + try { + if (!sig->parse_material(material)) { + return RNP_ERROR_BAD_PARAMETERS; + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + switch (sig->palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return add_json_mpis(jso, "sig", &material.rsa.s, NULL); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return add_json_mpis(jso, "r", &material.eg.r, "s", &material.eg.s, NULL); + case PGP_PKA_DSA: + return add_json_mpis(jso, "r", &material.dsa.r, "s", &material.dsa.s, NULL); + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + return add_json_mpis(jso, "r", &material.ecc.r, "s", &material.ecc.s, NULL); + default: + // TODO: we could use info->unknown and add a hex string of raw data here + return RNP_ERROR_NOT_SUPPORTED; + } + return RNP_SUCCESS; +} + +static bool +add_json_user_prefs(json_object *jso, const pgp_user_prefs_t &prefs) +{ + // TODO: instead of using a string "Unknown" as a fallback for these, + // we could add a string of hex/dec (or even an int) + if (!prefs.symm_algs.empty()) { + json_object *jsoarr = json_object_new_array(); + if (!jsoarr) { + return false; + } + json_object_object_add(jso, "ciphers", jsoarr); + for (auto alg : prefs.symm_algs) { + const char * name = id_str_pair::lookup(symm_alg_map, alg, "Unknown"); + json_object *jsoname = json_object_new_string(name); + if (!jsoname || json_object_array_add(jsoarr, jsoname)) { + return false; + } + } + } + if (!prefs.hash_algs.empty()) { + json_object *jsoarr = json_object_new_array(); + if (!jsoarr) { + return false; + } + json_object_object_add(jso, "hashes", jsoarr); + for (auto alg : prefs.hash_algs) { + const char * name = id_str_pair::lookup(hash_alg_map, alg, "Unknown"); + json_object *jsoname = json_object_new_string(name); + if (!jsoname || json_object_array_add(jsoarr, jsoname)) { + return false; + } + } + } + if (!prefs.z_algs.empty()) { + json_object *jsoarr = json_object_new_array(); + if (!jsoarr) { + return false; + } + json_object_object_add(jso, "compression", jsoarr); + for (auto alg : prefs.z_algs) { + const char * name = id_str_pair::lookup(compress_alg_map, alg, "Unknown"); + json_object *jsoname = json_object_new_string(name); + if (!jsoname || json_object_array_add(jsoarr, jsoname)) { + return false; + } + } + } + if (!prefs.ks_prefs.empty()) { + json_object *jsoarr = json_object_new_array(); + if (!jsoarr) { + return false; + } + json_object_object_add(jso, "key server preferences", jsoarr); + for (auto flag : prefs.ks_prefs) { + const char * name = id_str_pair::lookup(key_server_prefs_map, flag, "Unknown"); + json_object *jsoname = json_object_new_string(name); + if (!jsoname || json_object_array_add(jsoarr, jsoname)) { + return false; + } + } + } + if (!prefs.key_server.empty()) { + if (!add_json_string_field(jso, "key server", prefs.key_server.c_str())) { + return false; + } + } + return true; +} + +static rnp_result_t +add_json_subsig(json_object *jso, bool is_sub, uint32_t flags, const pgp_subsig_t *subsig) +{ + // userid (if applicable) + if (!is_sub) { + json_object *jsouid = json_object_new_int(subsig->uid); + if (!jsouid) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "userid", jsouid); + } + // trust + json_object *jsotrust = json_object_new_object(); + if (!jsotrust) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "trust", jsotrust); + // trust (level) + json_object *jsotrust_level = json_object_new_int(subsig->trustlevel); + if (!jsotrust_level) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jsotrust, "level", jsotrust_level); + // trust (amount) + json_object *jsotrust_amount = json_object_new_int(subsig->trustamount); + if (!jsotrust_amount) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jsotrust, "amount", jsotrust_amount); + // key flags (usage) + if (!add_json_key_usage(jso, subsig->key_flags)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // key flags (other) + if (!add_json_key_flags(jso, subsig->key_flags)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // preferences + const pgp_user_prefs_t &prefs = subsig->prefs; + if (!prefs.symm_algs.empty() || !prefs.hash_algs.empty() || !prefs.z_algs.empty() || + !prefs.ks_prefs.empty() || !prefs.key_server.empty()) { + json_object *jsoprefs = json_object_new_object(); + if (!jsoprefs) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "preferences", jsoprefs); + if (!add_json_user_prefs(jsoprefs, prefs)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + } + const pgp_signature_t *sig = &subsig->sig; + // version + json_object *jsoversion = json_object_new_int(sig->version); + if (!jsoversion) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "version", jsoversion); + // signature type + auto type = id_str_pair::lookup(sig_type_map, sig->type()); + if (!add_json_string_field(jso, "type", type)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // signer key type + const char *key_type = id_str_pair::lookup(pubkey_alg_map, sig->palg); + if (!add_json_string_field(jso, "key type", key_type)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // hash + const char *hash = id_str_pair::lookup(hash_alg_map, sig->halg); + if (!add_json_string_field(jso, "hash", hash)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // creation time + json_object *jsocreation_time = json_object_new_int64(sig->creation()); + if (!jsocreation_time) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "creation time", jsocreation_time); + // expiration (seconds) + json_object *jsoexpiration = json_object_new_int64(sig->expiration()); + if (!jsoexpiration) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "expiration", jsoexpiration); + // signer + json_object *jsosigner = NULL; + // TODO: add signer fingerprint as well (no support internally yet) + if (sig->has_keyid()) { + jsosigner = json_object_new_object(); + if (!jsosigner) { + return RNP_ERROR_OUT_OF_MEMORY; + } + char keyid[PGP_KEY_ID_SIZE * 2 + 1]; + pgp_key_id_t signer = sig->keyid(); + if (!rnp::hex_encode(signer.data(), signer.size(), keyid, sizeof(keyid))) { + return RNP_ERROR_GENERIC; + } + if (!add_json_string_field(jsosigner, "keyid", keyid)) { + json_object_put(jsosigner); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + json_object_object_add(jso, "signer", jsosigner); + // mpis + json_object *jsompis = NULL; + if (flags & RNP_JSON_SIGNATURE_MPIS) { + jsompis = json_object_new_object(); + if (!jsompis) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t tmpret; + if ((tmpret = add_json_sig_mpis(jsompis, sig))) { + json_object_put(jsompis); + return tmpret; + } + } + json_object_object_add(jso, "mpis", jsompis); + return RNP_SUCCESS; +} + +static rnp_result_t +key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) +{ + pgp_key_t *key = get_key_prefer_public(handle); + + // type + const char *str = id_str_pair::lookup(pubkey_alg_map, key->alg(), NULL); + if (!str) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!add_json_string_field(jso, "type", str)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // length + if (!add_json_int_field(jso, "length", key->material().bits())) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // curve / alg-specific items + switch (key->alg()) { + case PGP_PKA_ECDH: { + const char *hash_name = + id_str_pair::lookup(hash_alg_map, key->material().ec.kdf_hash_alg, NULL); + if (!hash_name) { + return RNP_ERROR_BAD_PARAMETERS; + } + const char *cipher_name = + id_str_pair::lookup(symm_alg_map, key->material().ec.key_wrap_alg, NULL); + if (!cipher_name) { + return RNP_ERROR_BAD_PARAMETERS; + } + json_object *jsohash = json_object_new_string(hash_name); + if (!jsohash) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "kdf hash", jsohash); + json_object *jsocipher = json_object_new_string(cipher_name); + if (!jsocipher) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "key wrap cipher", jsocipher); + } + [[fallthrough]]; + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: { + const char *curve_name = NULL; + if (!curve_type_to_str(key->material().ec.curve, &curve_name)) { + return RNP_ERROR_BAD_PARAMETERS; + } + json_object *jsocurve = json_object_new_string(curve_name); + if (!jsocurve) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "curve", jsocurve); + } break; + default: + break; + } + + // keyid + char keyid[PGP_KEY_ID_SIZE * 2 + 1]; + if (!rnp::hex_encode(key->keyid().data(), key->keyid().size(), keyid, sizeof(keyid))) { + return RNP_ERROR_GENERIC; + } + if (!add_json_string_field(jso, "keyid", keyid)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // fingerprint + char fpr[PGP_FINGERPRINT_SIZE * 2 + 1]; + if (!rnp::hex_encode(key->fp().fingerprint, key->fp().length, fpr, sizeof(fpr))) { + return RNP_ERROR_GENERIC; + } + if (!add_json_string_field(jso, "fingerprint", fpr)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // grip + char grip[PGP_KEY_GRIP_SIZE * 2 + 1]; + if (!rnp::hex_encode(key->grip().data(), key->grip().size(), grip, sizeof(grip))) { + return RNP_ERROR_GENERIC; + } + if (!add_json_string_field(jso, "grip", grip)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // revoked + json_object *jsorevoked = json_object_new_boolean(key->revoked() ? true : false); + if (!jsorevoked) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "revoked", jsorevoked); + // creation time + json_object *jsocreation_time = json_object_new_int64(key->creation()); + if (!jsocreation_time) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "creation time", jsocreation_time); + // expiration + json_object *jsoexpiration = json_object_new_int64(key->expiration()); + if (!jsoexpiration) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "expiration", jsoexpiration); + // key flags (usage) + if (!add_json_key_usage(jso, key->flags())) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // key flags (other) + if (!add_json_key_flags(jso, key->flags())) { + return RNP_ERROR_OUT_OF_MEMORY; + } + // parent / subkeys + if (key->is_primary()) { + json_object *jsosubkeys_arr = json_object_new_array(); + if (!jsosubkeys_arr) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "subkey grips", jsosubkeys_arr); + for (auto &subfp : key->subkey_fps()) { + const pgp_key_grip_t *subgrip = rnp_get_grip_by_fp(handle->ffi, subfp); + if (!subgrip) { + continue; + } + if (!rnp::hex_encode(subgrip->data(), subgrip->size(), grip, sizeof(grip))) { + return RNP_ERROR_GENERIC; + } + json_object *jsostr = json_object_new_string(grip); + if (!jsostr || json_object_array_add(jsosubkeys_arr, jsostr)) { + json_object_put(jsostr); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + } else if (key->has_primary_fp()) { + auto pgrip = rnp_get_grip_by_fp(handle->ffi, key->primary_fp()); + if (pgrip) { + if (!rnp::hex_encode(pgrip->data(), pgrip->size(), grip, sizeof(grip))) { + return RNP_ERROR_GENERIC; + } + if (!add_json_string_field(jso, "primary key grip", grip)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + } + } + // public + json_object *jsopublic = json_object_new_object(); + if (!jsopublic) { + return RNP_ERROR_OUT_OF_MEMORY; + } + bool have_sec = handle->sec != NULL; + bool have_pub = handle->pub != NULL; + json_object_object_add(jso, "public key", jsopublic); + json_object_object_add( + jsopublic, "present", json_object_new_boolean(have_pub ? true : false)); + if (flags & RNP_JSON_PUBLIC_MPIS) { + json_object *jsompis = json_object_new_object(); + if (!jsompis) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jsopublic, "mpis", jsompis); + rnp_result_t tmpret; + if ((tmpret = add_json_public_mpis(jsompis, key))) { + return tmpret; + } + } + // secret + json_object *jsosecret = json_object_new_object(); + if (!jsosecret) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "secret key", jsosecret); + json_object_object_add( + jsosecret, "present", json_object_new_boolean(have_sec ? true : false)); + if (have_sec) { + bool locked = handle->sec->is_locked(); + if (flags & RNP_JSON_SECRET_MPIS) { + if (locked) { + json_object_object_add(jsosecret, "mpis", NULL); + } else { + json_object *jsompis = json_object_new_object(); + if (!jsompis) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jsosecret, "mpis", jsompis); + rnp_result_t tmpret; + if ((tmpret = add_json_secret_mpis(jsompis, handle->sec))) { + return tmpret; + } + } + } + json_object *jsolocked = json_object_new_boolean(locked ? true : false); + if (!jsolocked) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jsosecret, "locked", jsolocked); + json_object *jsoprotected = + json_object_new_boolean(handle->sec->is_protected() ? true : false); + if (!jsoprotected) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jsosecret, "protected", jsoprotected); + } + // userids + if (key->is_primary()) { + json_object *jsouids_arr = json_object_new_array(); + if (!jsouids_arr) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "userids", jsouids_arr); + for (size_t i = 0; i < key->uid_count(); i++) { + json_object *jsouid = json_object_new_string(key->get_uid(i).str.c_str()); + if (!jsouid || json_object_array_add(jsouids_arr, jsouid)) { + json_object_put(jsouid); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + } + // signatures + if (flags & RNP_JSON_SIGNATURES) { + json_object *jsosigs_arr = json_object_new_array(); + if (!jsosigs_arr) { + return RNP_ERROR_OUT_OF_MEMORY; + } + json_object_object_add(jso, "signatures", jsosigs_arr); + for (size_t i = 0; i < key->sig_count(); i++) { + json_object *jsosig = json_object_new_object(); + if (!jsosig || json_object_array_add(jsosigs_arr, jsosig)) { + json_object_put(jsosig); + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t tmpret; + if ((tmpret = + add_json_subsig(jsosig, key->is_subkey(), flags, &key->get_sig(i)))) { + return tmpret; + } + } + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_key_to_json(rnp_key_handle_t handle, uint32_t flags, char **result) +try { + rnp_result_t ret = RNP_ERROR_GENERIC; + json_object *jso = NULL; + + // checks + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + jso = json_object_new_object(); + if (!jso) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + if ((ret = key_to_json(jso, handle, flags))) { + goto done; + } + *result = (char *) json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY); + if (!*result) { + goto done; + } + *result = strdup(*result); + if (!*result) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + ret = RNP_SUCCESS; +done: + json_object_put(jso); + return ret; +} +FFI_GUARD + +static rnp_result_t +rnp_dump_src_to_json(pgp_source_t *src, uint32_t flags, char **result) +{ + rnp_dump_ctx_t dumpctx = {}; + + dumpctx.dump_mpi = extract_flag(flags, RNP_JSON_DUMP_MPI); + dumpctx.dump_packets = extract_flag(flags, RNP_JSON_DUMP_RAW); + dumpctx.dump_grips = extract_flag(flags, RNP_JSON_DUMP_GRIP); + if (flags) { + return RNP_ERROR_BAD_PARAMETERS; + } + + json_object *jso = NULL; + rnp_result_t ret = stream_dump_packets_json(&dumpctx, src, &jso); + if (ret) { + goto done; + } + + *result = (char *) json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY); + if (!*result) { + goto done; + } + *result = strdup(*result); + if (!*result) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + ret = RNP_SUCCESS; +done: + json_object_put(jso); + return ret; +} + +rnp_result_t +rnp_key_packets_to_json(rnp_key_handle_t handle, bool secret, uint32_t flags, char **result) +try { + if (!handle || !result) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_key_t *key = secret ? handle->sec : handle->pub; + if (!key || (key->format == PGP_KEY_STORE_G10)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + auto vec = rnp_key_to_vec(*key); + rnp::MemorySource mem(vec); + return rnp_dump_src_to_json(&mem.src(), flags, result); +} +FFI_GUARD + +rnp_result_t +rnp_dump_packets_to_json(rnp_input_t input, uint32_t flags, char **result) +try { + if (!input || !result) { + return RNP_ERROR_NULL_POINTER; + } + + return rnp_dump_src_to_json(&input->src, flags, result); +} +FFI_GUARD + +rnp_result_t +rnp_dump_packets_to_output(rnp_input_t input, rnp_output_t output, uint32_t flags) +try { + if (!input || !output) { + return RNP_ERROR_NULL_POINTER; + } + + rnp_dump_ctx_t dumpctx = {}; + dumpctx.dump_mpi = extract_flag(flags, RNP_DUMP_MPI); + dumpctx.dump_packets = extract_flag(flags, RNP_DUMP_RAW); + dumpctx.dump_grips = extract_flag(flags, RNP_DUMP_GRIP); + if (flags) { + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp_result_t ret = stream_dump_packets(&dumpctx, &input->src, &output->dst); + output->keep = true; + return ret; +} +FFI_GUARD + +// move to next key +static bool +key_iter_next_key(rnp_identifier_iterator_t it) +{ + // check if we not reached the end of the ring + *it->keyp = std::next(*it->keyp); + if (*it->keyp != it->store->keys.end()) { + it->uididx = 0; + return true; + } + // if we are currently on pubring, switch to secring (if not empty) + if (it->store == it->ffi->pubring && !it->ffi->secring->keys.empty()) { + it->store = it->ffi->secring; + *it->keyp = it->store->keys.begin(); + it->uididx = 0; + return true; + } + // we've gone through both rings + it->store = NULL; + return false; +} + +// move to next item (key or userid) +static bool +key_iter_next_item(rnp_identifier_iterator_t it) +{ + switch (it->type) { + case PGP_KEY_SEARCH_KEYID: + case PGP_KEY_SEARCH_FINGERPRINT: + case PGP_KEY_SEARCH_GRIP: + return key_iter_next_key(it); + case PGP_KEY_SEARCH_USERID: + it->uididx++; + while (it->uididx >= (*it->keyp)->uid_count()) { + if (!key_iter_next_key(it)) { + return false; + } + it->uididx = 0; + } + break; + default: + assert(false); + break; + } + return true; +} + +static bool +key_iter_first_key(rnp_identifier_iterator_t it) +{ + if (rnp_key_store_get_key_count(it->ffi->pubring)) { + it->store = it->ffi->pubring; + } else if (rnp_key_store_get_key_count(it->ffi->secring)) { + it->store = it->ffi->secring; + } else { + it->store = NULL; + return false; + } + *it->keyp = it->store->keys.begin(); + it->uididx = 0; + return true; +} + +static bool +key_iter_first_item(rnp_identifier_iterator_t it) +{ + switch (it->type) { + case PGP_KEY_SEARCH_KEYID: + case PGP_KEY_SEARCH_FINGERPRINT: + case PGP_KEY_SEARCH_GRIP: + return key_iter_first_key(it); + case PGP_KEY_SEARCH_USERID: + if (!key_iter_first_key(it)) { + return false; + } + it->uididx = 0; + while (it->uididx >= (*it->keyp)->uid_count()) { + if (!key_iter_next_key(it)) { + return false; + } + } + break; + default: + assert(false); + break; + } + return true; +} + +static bool +key_iter_get_item(const rnp_identifier_iterator_t it, char *buf, size_t buf_len) +{ + const pgp_key_t *key = &**it->keyp; + switch (it->type) { + case PGP_KEY_SEARCH_KEYID: { + if (!rnp::hex_encode(key->keyid().data(), key->keyid().size(), buf, buf_len)) { + return false; + } + break; + } + case PGP_KEY_SEARCH_FINGERPRINT: + if (!rnp::hex_encode(key->fp().fingerprint, key->fp().length, buf, buf_len)) { + return false; + } + break; + case PGP_KEY_SEARCH_GRIP: + if (!rnp::hex_encode(key->grip().data(), key->grip().size(), buf, buf_len)) { + return false; + } + break; + case PGP_KEY_SEARCH_USERID: { + if (it->uididx >= key->uid_count()) { + return false; + } + const pgp_userid_t &uid = key->get_uid(it->uididx); + if (uid.str.size() >= buf_len) { + return false; + } + memcpy(buf, uid.str.c_str(), uid.str.size() + 1); + } break; + default: + assert(false); + break; + } + return true; +} + +rnp_result_t +rnp_identifier_iterator_create(rnp_ffi_t ffi, + rnp_identifier_iterator_t *it, + const char * identifier_type) +try { + rnp_result_t ret = RNP_ERROR_GENERIC; + struct rnp_identifier_iterator_st *obj = NULL; + + // checks + if (!ffi || !it || !identifier_type) { + return RNP_ERROR_NULL_POINTER; + } + // create iterator + obj = (struct rnp_identifier_iterator_st *) calloc(1, sizeof(*obj)); + if (!obj) { + return RNP_ERROR_OUT_OF_MEMORY; + } + obj->ffi = ffi; + obj->keyp = new std::list::iterator(); + obj->uididx = 0; + // parse identifier type + obj->type = static_cast( + id_str_pair::lookup(identifier_type_map, identifier_type, PGP_KEY_SEARCH_UNKNOWN)); + if (obj->type == PGP_KEY_SEARCH_UNKNOWN) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto done; + } + obj->tbl = json_object_new_object(); + if (!obj->tbl) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + // move to first item (if any) + key_iter_first_item(obj); + *it = obj; + + ret = RNP_SUCCESS; +done: + if (ret) { + rnp_identifier_iterator_destroy(obj); + } + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_identifier_iterator_next(rnp_identifier_iterator_t it, const char **identifier) +try { + rnp_result_t ret = RNP_ERROR_GENERIC; + + // checks + if (!it || !identifier) { + return RNP_ERROR_NULL_POINTER; + } + // initialize the result to NULL + *identifier = NULL; + // this means we reached the end of the rings + if (!it->store) { + return RNP_SUCCESS; + } + // get the item + if (!key_iter_get_item(it, it->buf, sizeof(it->buf))) { + return RNP_ERROR_GENERIC; + } + bool exists; + bool iterator_valid = true; + while ((exists = json_object_object_get_ex(it->tbl, it->buf, NULL))) { + if (!((iterator_valid = key_iter_next_item(it)))) { + break; + } + if (!key_iter_get_item(it, it->buf, sizeof(it->buf))) { + return RNP_ERROR_GENERIC; + } + } + // see if we actually found a new entry + if (!exists) { + // TODO: Newer json-c has a useful return value for json_object_object_add, + // which doesn't require the json_object_object_get_ex check below. + json_object_object_add(it->tbl, it->buf, NULL); + if (!json_object_object_get_ex(it->tbl, it->buf, NULL)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + *identifier = it->buf; + } + // prepare for the next one + if (iterator_valid) { + key_iter_next_item(it); + } + ret = RNP_SUCCESS; + +done: + if (ret) { + *identifier = NULL; + } + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_identifier_iterator_destroy(rnp_identifier_iterator_t it) +try { + if (it) { + json_object_put(it->tbl); + if (it->keyp) { + delete it->keyp; + } + free(it); + } + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_guess_contents(rnp_input_t input, char **contents) +try { + if (!input || !contents) { + return RNP_ERROR_NULL_POINTER; + } + + pgp_armored_msg_t msgtype = PGP_ARMORED_UNKNOWN; + if (is_armored_source(&input->src)) { + msgtype = rnp_armored_get_type(&input->src); + } else { + msgtype = rnp_armor_guess_type(&input->src); + } + const char *msg = id_str_pair::lookup(armor_type_map, msgtype); + size_t len = strlen(msg); + *contents = (char *) calloc(1, len + 1); + if (!*contents) { + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(*contents, msg, len); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_enarmor(rnp_input_t input, rnp_output_t output, const char *type) +try { + pgp_armored_msg_t msgtype = PGP_ARMORED_UNKNOWN; + if (!input || !output) { + return RNP_ERROR_NULL_POINTER; + } + if (type) { + msgtype = static_cast( + id_str_pair::lookup(armor_type_map, type, PGP_ARMORED_UNKNOWN)); + if (msgtype == PGP_ARMORED_UNKNOWN) { + RNP_LOG("Unsupported armor type: %s", type); + return RNP_ERROR_BAD_PARAMETERS; + } + } else { + msgtype = rnp_armor_guess_type(&input->src); + if (!msgtype) { + RNP_LOG("Unrecognized data to armor (try specifying a type)"); + return RNP_ERROR_BAD_PARAMETERS; + } + } + rnp_result_t ret = rnp_armor_source(&input->src, &output->dst, msgtype); + output->keep = !ret; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_dearmor(rnp_input_t input, rnp_output_t output) +try { + if (!input || !output) { + return RNP_ERROR_NULL_POINTER; + } + rnp_result_t ret = rnp_dearmor_source(&input->src, &output->dst); + output->keep = !ret; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_output_pipe(rnp_input_t input, rnp_output_t output) +try { + if (!input || !output) { + return RNP_ERROR_NULL_POINTER; + } + rnp_result_t ret = dst_write_src(&input->src, &output->dst); + output->keep = !ret; + return ret; +} +FFI_GUARD + +rnp_result_t +rnp_output_armor_set_line_length(rnp_output_t output, size_t llen) +try { + if (!output || !llen) { + return RNP_ERROR_BAD_PARAMETERS; + } + return armored_dst_set_line_length(&output->dst, llen); +} +FFI_GUARD + +const char * +rnp_backend_string() +{ + return rnp::backend_string(); +} + +const char * +rnp_backend_version() +{ + return rnp::backend_version(); +} diff --git a/comm/third_party/rnp/src/lib/rnp/rnp_export.h b/comm/third_party/rnp/src/lib/rnp/rnp_export.h new file mode 100644 index 0000000000..3fdce5edcf --- /dev/null +++ b/comm/third_party/rnp/src/lib/rnp/rnp_export.h @@ -0,0 +1,42 @@ + +#ifndef RNP_EXPORT +#define RNP_EXPORT + +#ifdef RNP_STATIC +# define RNP_API +# define RNP_NO_EXPORT +#else +# ifndef RNP_API +# ifdef librnp_EXPORTS + /* We are building this library */ +# define RNP_API +# else + /* We are using this library */ +# define RNP_API +# endif +# endif + +# ifndef RNP_NO_EXPORT +# define RNP_NO_EXPORT +# endif +#endif + +#ifndef RNP_DEPRECATED +# define RNP_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef RNP_DEPRECATED_EXPORT +# define RNP_DEPRECATED_EXPORT RNP_API RNP_DEPRECATED +#endif + +#ifndef RNP_DEPRECATED_NO_EXPORT +# define RNP_DEPRECATED_NO_EXPORT RNP_NO_EXPORT RNP_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef RNP_NO_DEPRECATED +# define RNP_NO_DEPRECATED +# endif +#endif + +#endif /* RNP_EXPORT */ diff --git a/comm/third_party/rnp/src/lib/sec_profile.cpp b/comm/third_party/rnp/src/lib/sec_profile.cpp new file mode 100644 index 0000000000..f9d0de8362 --- /dev/null +++ b/comm/third_party/rnp/src/lib/sec_profile.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2021 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sec_profile.hpp" +#include "types.h" +#include "defaults.h" +#include +#include + +namespace rnp { +bool +SecurityRule::operator==(const SecurityRule &src) const +{ + return (type == src.type) && (feature == src.feature) && (from == src.from) && + (level == src.level) && (override == src.override) && (action == src.action); +} + +bool +SecurityRule::operator!=(const SecurityRule &src) const +{ + return !(*this == src); +} + +bool +SecurityRule::matches(FeatureType ftype, + int fval, + uint64_t ftime, + SecurityAction faction) const noexcept +{ + if ((type != ftype) || (feature != fval) || (from > ftime)) { + return false; + } + return (action == SecurityAction::Any) || (faction == SecurityAction::Any) || + (action == faction); +} + +size_t +SecurityProfile::size() const noexcept +{ + return rules_.size(); +} + +SecurityRule & +SecurityProfile::add_rule(const SecurityRule &rule) +{ + rules_.push_back(rule); + return rules_.back(); +} + +SecurityRule & +SecurityProfile::add_rule(SecurityRule &&rule) +{ + rules_.emplace_back(rule); + return rules_.back(); +} + +bool +SecurityProfile::del_rule(const SecurityRule &rule) +{ + size_t old_size = rules_.size(); + rules_.erase(std::remove_if(rules_.begin(), + rules_.end(), + [rule](const SecurityRule &item) { return item == rule; }), + rules_.end()); + return old_size != rules_.size(); +} + +void +SecurityProfile::clear_rules(FeatureType type, int feature) +{ + rules_.erase(std::remove_if(rules_.begin(), + rules_.end(), + [type, feature](const SecurityRule &item) { + return (item.type == type) && (item.feature == feature); + }), + rules_.end()); +} + +void +SecurityProfile::clear_rules(FeatureType type) +{ + rules_.erase( + std::remove_if(rules_.begin(), + rules_.end(), + [type](const SecurityRule &item) { return item.type == type; }), + rules_.end()); +} + +void +SecurityProfile::clear_rules() +{ + rules_.clear(); +} + +bool +SecurityProfile::has_rule(FeatureType type, + int value, + uint64_t time, + SecurityAction action) const noexcept +{ + for (auto &rule : rules_) { + if (rule.matches(type, value, time, action)) { + return true; + } + } + return false; +} + +const SecurityRule & +SecurityProfile::get_rule(FeatureType type, + int value, + uint64_t time, + SecurityAction action) const +{ + const SecurityRule *res = nullptr; + for (auto &rule : rules_) { + if (!rule.matches(type, value, time, action)) { + continue; + } + if (rule.override) { + return rule; + } + if (!res || (res->from < rule.from)) { + res = &rule; + } + } + if (!res) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + return *res; +} + +SecurityLevel +SecurityProfile::hash_level(pgp_hash_alg_t hash, + uint64_t time, + SecurityAction action) const noexcept +{ + if (!has_rule(FeatureType::Hash, hash, time, action)) { + return def_level(); + } + + try { + return get_rule(FeatureType::Hash, hash, time, action).level; + } catch (const std::exception &e) { + /* this should never happen however we need to satisfy noexcept specifier */ + return def_level(); + } +} + +SecurityLevel +SecurityProfile::def_level() const +{ + return SecurityLevel::Default; +}; + +SecurityContext::SecurityContext() : time_(0), prov_state_(NULL), rng(RNG::Type::DRBG) +{ + /* Initialize crypto provider if needed (currently only for OpenSSL 3.0) */ + if (!rnp::backend_init(&prov_state_)) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + /* Mark SHA-1 data signature insecure since 2019-01-19, as GnuPG does */ + profile.add_rule({FeatureType::Hash, + PGP_HASH_SHA1, + SecurityLevel::Insecure, + 1547856000, + SecurityAction::VerifyData}); + /* Mark SHA-1 key signature insecure since 2024-01-19 by default */ + profile.add_rule({FeatureType::Hash, + PGP_HASH_SHA1, + SecurityLevel::Insecure, + 1705629600, + SecurityAction::VerifyKey}); + /* Mark MD5 insecure since 2012-01-01 */ + profile.add_rule({FeatureType::Hash, PGP_HASH_MD5, SecurityLevel::Insecure, 1325376000}); +} + +SecurityContext::~SecurityContext() +{ + rnp::backend_finish(prov_state_); +} + +size_t +SecurityContext::s2k_iterations(pgp_hash_alg_t halg) +{ + if (!s2k_iterations_.count(halg)) { + s2k_iterations_[halg] = + pgp_s2k_compute_iters(halg, DEFAULT_S2K_MSEC, DEFAULT_S2K_TUNE_MSEC); + } + return s2k_iterations_[halg]; +} + +void +SecurityContext::set_time(uint64_t time) noexcept +{ + time_ = time; +} + +uint64_t +SecurityContext::time() const noexcept +{ + return time_ ? time_ : ::time(NULL); +} + +} // namespace rnp diff --git a/comm/third_party/rnp/src/lib/sec_profile.hpp b/comm/third_party/rnp/src/lib/sec_profile.hpp new file mode 100644 index 0000000000..a4d84563fc --- /dev/null +++ b/comm/third_party/rnp/src/lib/sec_profile.hpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_SEC_PROFILE_H_ +#define RNP_SEC_PROFILE_H_ + +#include +#include +#include +#include "repgp/repgp_def.h" +#include "crypto/rng.h" + +namespace rnp { + +enum class FeatureType { Hash, Cipher, PublicKey }; +enum class SecurityLevel { Disabled, Insecure, Default }; +enum class SecurityAction { Any, VerifyKey, VerifyData }; + +struct SecurityRule { + FeatureType type; + int feature; + SecurityLevel level; + uint64_t from; + bool override; + SecurityAction action; + + SecurityRule(FeatureType ftype, + int fval, + SecurityLevel flevel, + uint64_t ffrom = 0, + SecurityAction faction = SecurityAction::Any) + : type(ftype), feature(fval), level(flevel), from(ffrom), override(false), + action(faction){}; + + bool operator==(const SecurityRule &src) const; + bool operator!=(const SecurityRule &src) const; + + bool matches(FeatureType ftype, + int fval, + uint64_t ftime, + SecurityAction faction) const noexcept; +}; + +class SecurityProfile { + private: + std::vector rules_; + + public: + size_t size() const noexcept; + SecurityRule &add_rule(const SecurityRule &rule); + SecurityRule &add_rule(SecurityRule &&rule); + bool del_rule(const SecurityRule &rule); + void clear_rules(FeatureType type, int feature); + void clear_rules(FeatureType type); + void clear_rules(); + + bool has_rule(FeatureType type, + int value, + uint64_t time, + SecurityAction action = SecurityAction::Any) const noexcept; + const SecurityRule &get_rule(FeatureType type, + int value, + uint64_t time, + SecurityAction action = SecurityAction::Any) const; + SecurityLevel hash_level(pgp_hash_alg_t hash, + uint64_t time, + SecurityAction action = SecurityAction::Any) const noexcept; + SecurityLevel def_level() const; +}; + +class SecurityContext { + std::unordered_map s2k_iterations_; + uint64_t time_; + void * prov_state_; + + public: + SecurityProfile profile; + RNG rng; + + SecurityContext(); + ~SecurityContext(); + + size_t s2k_iterations(pgp_hash_alg_t halg); + + void set_time(uint64_t time) noexcept; + uint64_t time() const noexcept; +}; +} // namespace rnp + +#endif diff --git a/comm/third_party/rnp/src/lib/types.h b/comm/third_party/rnp/src/lib/types.h new file mode 100644 index 0000000000..5a67d4225c --- /dev/null +++ b/comm/third_party/rnp/src/lib/types.h @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2017-2021, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TYPES_H_ +#define TYPES_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include "crypto/common.h" +#include "sec_profile.hpp" + +/* SHA1 Hash Size */ +#define PGP_SHA1_HASH_SIZE 20 + +/* Maximum length of the packet header */ +#define PGP_MAX_HEADER_SIZE 6 + +/* Maximum supported userid length */ +#define MAX_ID_LENGTH 128 + +/* Maximum supported password length */ +#define MAX_PASSWORD_LENGTH 256 + +class id_str_pair { + public: + int id; + const char *str; + + /** + * @brief Lookup constant pair array for the specified id or string value. + * Note: array must be finished with NULL string to stop the lookup. + * + * @param pair pointer to the const array with pairs. + * @param id identifier to search for + * @param notfound value to return if identifier is not found. + * @return string, representing the identifier. + */ + static const char *lookup(const id_str_pair pair[], + int id, + const char * notfound = "unknown"); + static int lookup(const id_str_pair pair[], const char *str, int notfound = 0); + static int lookup(const id_str_pair pair[], + const std::vector &bytes, + int notfound = 0); + static int lookup(const id_str_pair pair[], + const std::basic_string &bytes, + int notfound = 0); +}; + +/** pgp_fingerprint_t */ +typedef struct pgp_fingerprint_t { + uint8_t fingerprint[PGP_FINGERPRINT_SIZE]; + unsigned length; + bool operator==(const pgp_fingerprint_t &src) const; + bool operator!=(const pgp_fingerprint_t &src) const; +} pgp_fingerprint_t; + +typedef std::array pgp_sig_id_t; + +namespace std { +template <> struct hash { + std::size_t + operator()(pgp_fingerprint_t const &fp) const noexcept + { + /* since fingerprint value is hash itself, we may use its low bytes */ + size_t res = 0; + static_assert(sizeof(fp.fingerprint) == PGP_FINGERPRINT_SIZE, + "pgp_fingerprint_t size mismatch"); + static_assert(PGP_FINGERPRINT_SIZE >= sizeof(res), "pgp_fingerprint_t size mismatch"); + std::memcpy(&res, fp.fingerprint, sizeof(res)); + return res; + } +}; + +template <> struct hash { + std::size_t + operator()(pgp_sig_id_t const &sigid) const noexcept + { + /* since signature id value is hash itself, we may use its low bytes */ + size_t res = 0; + static_assert(std::tuple_size::value >= sizeof(res), + "pgp_sig_id_t size mismatch"); + std::memcpy(&res, sigid.data(), sizeof(res)); + return res; + } +}; +}; // namespace std + +typedef std::array pgp_key_grip_t; + +typedef std::array pgp_key_id_t; + +namespace rnp { +class rnp_exception : public std::exception { + rnp_result_t code_; + + public: + rnp_exception(rnp_result_t code = RNP_ERROR_GENERIC) : code_(code){}; + virtual const char * + what() const throw() + { + return "rnp_exception"; + }; + rnp_result_t + code() const + { + return code_; + }; +}; +} // namespace rnp + +/* validity information for the signature/key/userid */ +typedef struct pgp_validity_t { + bool validated{}; /* item was validated */ + bool valid{}; /* item is valid by signature/key checks and calculations. + Still may be revoked or expired. */ + bool expired{}; /* item is expired */ + + void mark_valid(); + void reset(); +} pgp_validity_t; + +/** + * Type to keep public/secret key mpis without any openpgp-dependent data. + */ +typedef struct pgp_key_material_t { + pgp_pubkey_alg_t alg; /* algorithm of the key */ + bool secret; /* secret part of the key material is populated */ + pgp_validity_t validity; /* key material validation status */ + + union { + pgp_rsa_key_t rsa; + pgp_dsa_key_t dsa; + pgp_eg_key_t eg; + pgp_ec_key_t ec; + }; + + size_t bits() const; + size_t qbits() const; + void validate(rnp::SecurityContext &ctx, bool reset = true); + bool valid() const; +} pgp_key_material_t; + +/** + * Type to keep signature without any openpgp-dependent data. + */ +typedef struct pgp_signature_material_t { + union { + pgp_rsa_signature_t rsa; + pgp_dsa_signature_t dsa; + pgp_ec_signature_t ecc; + pgp_eg_signature_t eg; + }; +} pgp_signature_material_t; + +/** + * Type to keep pk-encrypted data without any openpgp-dependent data. + */ +typedef struct pgp_encrypted_material_t { + union { + pgp_rsa_encrypted_t rsa; + pgp_eg_encrypted_t eg; + pgp_sm2_encrypted_t sm2; + pgp_ecdh_encrypted_t ecdh; + }; +} pgp_encrypted_material_t; + +typedef struct pgp_s2k_t { + pgp_s2k_usage_t usage{}; + + /* below fields may not all be valid, depending on the usage field above */ + pgp_s2k_specifier_t specifier{}; + pgp_hash_alg_t hash_alg{}; + uint8_t salt[PGP_SALT_SIZE]; + unsigned iterations{}; + /* GnuPG custom s2k data */ + pgp_s2k_gpg_extension_t gpg_ext_num{}; + uint8_t gpg_serial_len{}; + uint8_t gpg_serial[16]; + /* Experimental s2k data */ + std::vector experimental{}; +} pgp_s2k_t; + +typedef struct pgp_key_protection_t { + pgp_s2k_t s2k{}; /* string-to-key kdf params */ + pgp_symm_alg_t symm_alg{}; /* symmetric alg */ + pgp_cipher_mode_t cipher_mode{}; /* block cipher mode */ + uint8_t iv[PGP_MAX_BLOCK_SIZE]; +} pgp_key_protection_t; + +typedef struct pgp_key_pkt_t pgp_key_pkt_t; +typedef struct pgp_userid_pkt_t pgp_userid_pkt_t; +typedef struct pgp_signature_t pgp_signature_t; + +/* Signature subpacket, see 5.2.3.1 in RFC 4880 and RFC 4880 bis 02 */ +typedef struct pgp_sig_subpkt_t { + pgp_sig_subpacket_type_t type; /* type of the subpacket */ + size_t len; /* length of the data */ + uint8_t * data; /* raw subpacket data, excluding the header */ + bool critical : 1; /* critical flag */ + bool hashed : 1; /* whether subpacket is hashed or not */ + bool parsed : 1; /* whether subpacket was successfully parsed */ + union { + uint32_t create; /* 5.2.3.4. Signature Creation Time */ + uint32_t expiry; /* 5.2.3.6. Key Expiration Time */ + /* 5.2.3.10. Signature Expiration Time */ + bool exportable; /* 5.2.3.11. Exportable Certification */ + struct { + uint8_t level; + uint8_t amount; + } trust; /* 5.2.3.13. Trust Signature */ + struct { + const char *str; + unsigned len; + } regexp; /* 5.2.3.14. Regular Expression */ + bool revocable; /* 5.2.3.12. Revocable */ + struct { + uint8_t *arr; + unsigned len; + } preferred; /* 5.2.3.7. Preferred Symmetric Algorithms */ + /* 5.2.3.8. Preferred Hash Algorithms */ + /* 5.2.3.9. Preferred Compression Algorithms */ + struct { + uint8_t klass; + pgp_pubkey_alg_t pkalg; + uint8_t * fp; + } revocation_key; /* 5.2.3.15. Revocation Key */ + uint8_t *issuer; /* 5.2.3.5. Issuer */ + struct { + uint8_t flags[4]; + unsigned nlen; + unsigned vlen; + bool human; + const uint8_t *name; + const uint8_t *value; + } notation; /* 5.2.3.16. Notation Data */ + struct { + bool no_modify; + } ks_prefs; /* 5.2.3.17. Key Server Preferences */ + struct { + const char *uri; + unsigned len; + } preferred_ks; /* 5.2.3.18. Preferred Key Server */ + bool primary_uid; /* 5.2.3.19. Primary User ID */ + struct { + const char *uri; + unsigned len; + } policy; /* 5.2.3.20. Policy URI */ + uint8_t key_flags; /* 5.2.3.21. Key Flags */ + struct { + const char *uid; + unsigned len; + } signer; /* 5.2.3.22. Signer's User ID */ + struct { + pgp_revocation_type_t code; + const char * str; + unsigned len; + } revocation_reason; /* 5.2.3.23. Reason for Revocation */ + uint8_t features; /* 5.2.3.24. Features */ + struct { + pgp_pubkey_alg_t pkalg; + pgp_hash_alg_t halg; + uint8_t * hash; + unsigned hlen; + } sig_target; /* 5.2.3.25. Signature Target */ + pgp_signature_t *sig; /* 5.2.3.27. Embedded Signature */ + struct { + uint8_t version; + uint8_t *fp; + unsigned len; + } issuer_fp; /* 5.2.3.28. Issuer Fingerprint, RFC 4880 bis 04 */ + } fields; /* parsed contents of the subpacket */ + + pgp_sig_subpkt_t() + : type(PGP_SIG_SUBPKT_UNKNOWN), len(0), data(NULL), critical(false), hashed(false), + parsed(false), fields({}){}; + pgp_sig_subpkt_t(const pgp_sig_subpkt_t &src); + pgp_sig_subpkt_t(pgp_sig_subpkt_t &&src); + pgp_sig_subpkt_t &operator=(pgp_sig_subpkt_t &&src); + pgp_sig_subpkt_t &operator=(const pgp_sig_subpkt_t &src); + ~pgp_sig_subpkt_t(); + bool parse(); +} pgp_sig_subpkt_t; + +typedef struct pgp_one_pass_sig_t pgp_one_pass_sig_t; + +typedef enum { + /* first octet */ + PGP_KEY_SERVER_NO_MODIFY = 0x80 +} pgp_key_server_prefs_t; + +typedef struct pgp_literal_hdr_t { + uint8_t format; + char fname[256]; + uint8_t fname_len; + uint32_t timestamp; +} pgp_literal_hdr_t; + +typedef struct pgp_aead_hdr_t { + int version{}; /* version of the AEAD packet */ + pgp_symm_alg_t ealg; /* underlying symmetric algorithm */ + pgp_aead_alg_t aalg; /* AEAD algorithm, i.e. EAX, OCB, etc */ + int csize{}; /* chunk size bits */ + uint8_t iv[PGP_AEAD_MAX_NONCE_LEN]; /* initial vector for the message */ + size_t ivlen{}; /* iv length */ + + pgp_aead_hdr_t() : ealg(PGP_SA_UNKNOWN), aalg(PGP_AEAD_NONE) + { + } +} pgp_aead_hdr_t; + +/** litdata_type_t */ +typedef enum { + PGP_LDT_BINARY = 'b', + PGP_LDT_TEXT = 't', + PGP_LDT_UTF8 = 'u', + PGP_LDT_LOCAL = 'l', + PGP_LDT_LOCAL2 = '1' +} pgp_litdata_enum; + +/* user revocation info */ +typedef struct pgp_subsig_t pgp_subsig_t; + +typedef struct pgp_revoke_t { + uint32_t uid{}; /* index in uid array */ + pgp_revocation_type_t code{}; /* revocation code */ + std::string reason; /* revocation reason */ + pgp_sig_id_t sigid{}; /* id of the corresponding subsig */ + + pgp_revoke_t() = default; + pgp_revoke_t(pgp_subsig_t &sig); +} pgp_revoke_t; + +typedef struct pgp_user_prefs_t { + // preferred symmetric algs (pgp_symm_alg_t) + std::vector symm_algs{}; + // preferred hash algs (pgp_hash_alg_t) + std::vector hash_algs{}; + // preferred compression algs (pgp_compression_type_t) + std::vector z_algs{}; + // key server preferences (pgp_key_server_prefs_t) + std::vector ks_prefs{}; + // preferred key server + std::string key_server{}; + + void set_symm_algs(const std::vector &algs); + void add_symm_alg(pgp_symm_alg_t alg); + void set_hash_algs(const std::vector &algs); + void add_hash_alg(pgp_hash_alg_t alg); + void set_z_algs(const std::vector &algs); + void add_z_alg(pgp_compression_type_t alg); + void set_ks_prefs(const std::vector &prefs); + void add_ks_pref(pgp_key_server_prefs_t pref); +} pgp_user_prefs_t; + +struct rnp_keygen_ecc_params_t { + pgp_curve_t curve; +}; + +struct rnp_keygen_rsa_params_t { + uint32_t modulus_bit_len; +}; + +struct rnp_keygen_dsa_params_t { + size_t p_bitlen; + size_t q_bitlen; +}; + +struct rnp_keygen_elgamal_params_t { + size_t key_bitlen; +}; + +/* structure used to hold context of key generation */ +namespace rnp { +class SecurityContext; +} + +typedef struct rnp_keygen_crypto_params_t { + // Asymmteric algorithm that user requesed key for + pgp_pubkey_alg_t key_alg; + // Hash to be used for key signature + pgp_hash_alg_t hash_alg; + // Pointer to security context + rnp::SecurityContext *ctx; + union { + struct rnp_keygen_ecc_params_t ecc; + struct rnp_keygen_rsa_params_t rsa; + struct rnp_keygen_dsa_params_t dsa; + struct rnp_keygen_elgamal_params_t elgamal; + }; +} rnp_keygen_crypto_params_t; + +typedef struct rnp_selfsig_cert_info_t { + std::string userid; /* userid, required */ + uint8_t key_flags{}; /* key flags */ + uint32_t key_expiration{}; /* key expiration time (sec), 0 = no expiration */ + pgp_user_prefs_t prefs{}; /* user preferences, optional */ + bool primary; /* mark this as the primary user id */ + + /** + * @brief Populate uid and sig packet with data stored in this struct. + * At some point we should get rid of it. + */ + void populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig); +} rnp_selfsig_cert_info_t; + +typedef struct rnp_selfsig_binding_info_t { + uint8_t key_flags; + uint32_t key_expiration; +} rnp_selfsig_binding_info_t; + +typedef struct rnp_keygen_primary_desc_t { + rnp_keygen_crypto_params_t crypto{}; + rnp_selfsig_cert_info_t cert{}; +} rnp_keygen_primary_desc_t; + +typedef struct rnp_keygen_subkey_desc_t { + rnp_keygen_crypto_params_t crypto; + rnp_selfsig_binding_info_t binding; +} rnp_keygen_subkey_desc_t; + +typedef struct rnp_key_protection_params_t { + pgp_symm_alg_t symm_alg; + pgp_cipher_mode_t cipher_mode; + unsigned iterations; + pgp_hash_alg_t hash_alg; +} rnp_key_protection_params_t; + +#endif /* TYPES_H_ */ diff --git a/comm/third_party/rnp/src/lib/utils.cpp b/comm/third_party/rnp/src/lib/utils.cpp new file mode 100644 index 0000000000..3c6216c604 --- /dev/null +++ b/comm/third_party/rnp/src/lib/utils.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "types.h" +#include "str-utils.h" + +const char * +id_str_pair::lookup(const id_str_pair pair[], int id, const char *notfound) +{ + while (pair && pair->str) { + if (pair->id == id) { + return pair->str; + } + pair++; + } + return notfound; +} + +int +id_str_pair::lookup(const id_str_pair pair[], const char *str, int notfound) +{ + while (pair && pair->str) { + if (rnp::str_case_eq(str, pair->str)) { + return pair->id; + } + pair++; + } + return notfound; +} + +int +id_str_pair::lookup(const id_str_pair pair[], const std::vector &bytes, int notfound) +{ + while (pair && pair->str) { + if ((strlen(pair->str) == bytes.size()) && + !memcmp(pair->str, bytes.data(), bytes.size())) { + return pair->id; + } + pair++; + } + return notfound; +} + +int +id_str_pair::lookup(const id_str_pair pair[], + const std::basic_string &bytes, + int notfound) +{ + while (pair && pair->str) { + if ((strlen(pair->str) == bytes.size()) && + !memcmp(pair->str, bytes.data(), bytes.size())) { + return pair->id; + } + pair++; + } + return notfound; +} diff --git a/comm/third_party/rnp/src/lib/utils.h b/comm/third_party/rnp/src/lib/utils.h new file mode 100644 index 0000000000..3035ee5105 --- /dev/null +++ b/comm/third_party/rnp/src/lib/utils.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017-2021 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_UTILS_H_ +#define RNP_UTILS_H_ + +#include +#include +#include "logging.h" + +/* number of elements in an array */ +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + +/* + * @params + * array: array of the structures to lookup + * id_field name of the field to compare against + * ret_field filed to return + * lookup_value lookup value + * ret return value + */ +#define ARRAY_LOOKUP_BY_ID(array, id_field, ret_field, lookup_value, ret) \ + do { \ + for (size_t i__ = 0; i__ < ARRAY_SIZE(array); i__++) { \ + if ((array)[i__].id_field == (lookup_value)) { \ + (ret) = (array)[i__].ret_field; \ + break; \ + } \ + } \ + } while (0) + +/* Portable way to convert bits to bytes */ + +#define BITS_TO_BYTES(b) (((b) + (CHAR_BIT - 1)) / CHAR_BIT) + +/* Load little-endian 32-bit from y to x in portable fashion */ + +inline void +LOAD32LE(uint32_t &x, const uint8_t y[4]) +{ + x = (static_cast(y[3]) << 24) | (static_cast(y[2]) << 16) | + (static_cast(y[1]) << 8) | (static_cast(y[0]) << 0); +} + +/* Store big-endian 32-bit value x in y */ +inline void +STORE32BE(uint8_t x[4], uint32_t y) +{ + x[0] = (uint8_t)(y >> 24) & 0xff; + x[1] = (uint8_t)(y >> 16) & 0xff; + x[2] = (uint8_t)(y >> 8) & 0xff; + x[3] = (uint8_t)(y >> 0) & 0xff; +} + +/* Store big-endian 64-bit value x in y */ +inline void +STORE64BE(uint8_t x[8], uint64_t y) +{ + x[0] = (uint8_t)(y >> 56) & 0xff; + x[1] = (uint8_t)(y >> 48) & 0xff; + x[2] = (uint8_t)(y >> 40) & 0xff; + x[3] = (uint8_t)(y >> 32) & 0xff; + x[4] = (uint8_t)(y >> 24) & 0xff; + x[5] = (uint8_t)(y >> 16) & 0xff; + x[6] = (uint8_t)(y >> 8) & 0xff; + x[7] = (uint8_t)(y >> 0) & 0xff; +} + +inline char * +getenv_logname(void) +{ + char *name = getenv("LOGNAME"); + if (!name) { + name = getenv("USER"); + } + return name; +} + +#endif diff --git a/comm/third_party/rnp/src/lib/version.h.in b/comm/third_party/rnp/src/lib/version.h.in new file mode 100644 index 0000000000..2382cfd95d --- /dev/null +++ b/comm/third_party/rnp/src/lib/version.h.in @@ -0,0 +1,52 @@ +/* Copyright (c) 2018 Ribose Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define RNP_VERSION_MAJOR @RNP_VERSION_MAJOR@ +#define RNP_VERSION_MINOR @RNP_VERSION_MINOR@ +#define RNP_VERSION_PATCH @RNP_VERSION_PATCH@ + +#define RNP_VERSION_STRING "@RNP_VERSION@" +#define RNP_VERSION_STRING_FULL "@RNP_VERSION_FULL@" + +#define RNP_VERSION_COMMIT_TIMESTAMP @RNP_VERSION_COMMIT_TIMESTAMP@ + +// using a 32-bit version with 10 bits per component +#define RNP_VERSION_COMPONENT_MASK 0x3ff +#define RNP_VERSION_MAJOR_SHIFT 20 +#define RNP_VERSION_MINOR_SHIFT 10 +#define RNP_VERSION_PATCH_SHIFT 0 +#define RNP_VERSION_CODE_FOR(major, minor, patch) \ + (((major & RNP_VERSION_COMPONENT_MASK) << RNP_VERSION_MAJOR_SHIFT) | \ + ((minor & RNP_VERSION_COMPONENT_MASK) << RNP_VERSION_MINOR_SHIFT) | \ + ((patch & RNP_VERSION_COMPONENT_MASK) << RNP_VERSION_PATCH_SHIFT)) + +#define RNP_VERSION_CODE \ + RNP_VERSION_CODE_FOR(RNP_VERSION_MAJOR, RNP_VERSION_MINOR, RNP_VERSION_PATCH) + +static_assert(RNP_VERSION_MAJOR <= RNP_VERSION_COMPONENT_MASK && + RNP_VERSION_MINOR <= RNP_VERSION_COMPONENT_MASK && + RNP_VERSION_PATCH <= RNP_VERSION_COMPONENT_MASK, + "version components must be within range"); + diff --git a/comm/third_party/rnp/src/librekey/g23_sexp.hpp b/comm/third_party/rnp/src/librekey/g23_sexp.hpp new file mode 100644 index 0000000000..b888680f50 --- /dev/null +++ b/comm/third_party/rnp/src/librekey/g23_sexp.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE RIBOSE, INC. AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_G23_SEXP_HPP +#define RNP_G23_SEXP_HPP + +#include "sexp/sexp.h" +#include "sexp/ext-key-format.h" + +#define SXP_MAX_DEPTH 30 + +class gnupg_sexp_t; +typedef std::shared_ptr p_gnupg_sexp; + +class gnupg_sexp_t : public sexp::sexp_list_t { + /* write gnupg_sexp_t contents, adding padding, for the further encryption */ + rnp::secure_vector write_padded(size_t padblock) const; + + public: + void + add(const std::string &str) + { + push_back(std::shared_ptr(new sexp::sexp_string_t(str))); + }; + void + add(const uint8_t *data, size_t size) + { + push_back(std::shared_ptr(new sexp::sexp_string_t(data, size))); + }; + void add(unsigned u); + p_gnupg_sexp add_sub(); + void add_mpi(const std::string &name, const pgp_mpi_t &val); + void add_curve(const std::string &name, const pgp_ec_key_t &key); + void add_pubkey(const pgp_key_pkt_t &key); + void add_seckey(const pgp_key_pkt_t &key); + void add_protected_seckey(pgp_key_pkt_t & seckey, + const std::string & password, + rnp::SecurityContext &ctx); + bool parse(const char *r_bytes, size_t r_length, size_t depth = 1); + bool write(pgp_dest_t &dst) const noexcept; +}; + +class gnupg_extended_private_key_t : public ext_key_format::extended_private_key_t { + public: + bool parse(const char *r_bytes, size_t r_length, size_t depth = 1); +}; + +#endif diff --git a/comm/third_party/rnp/src/librekey/kbx_blob.hpp b/comm/third_party/rnp/src/librekey/kbx_blob.hpp new file mode 100644 index 0000000000..274413c6e9 --- /dev/null +++ b/comm/third_party/rnp/src/librekey/kbx_blob.hpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE RIBOSE, INC. AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_KBX_BLOB_HPP +#define RNP_KBX_BLOB_HPP + +typedef enum : uint8_t { + KBX_EMPTY_BLOB = 0, + KBX_HEADER_BLOB = 1, + KBX_PGP_BLOB = 2, + KBX_X509_BLOB = 3 +} kbx_blob_type_t; + +class kbx_blob_t { + protected: + kbx_blob_type_t type_; + std::vector image_; + + uint8_t ru8(size_t idx); + uint16_t ru16(size_t idx); + uint32_t ru32(size_t idx); + + public: + virtual ~kbx_blob_t() = default; + kbx_blob_t(std::vector &data); + virtual bool + parse() + { + return true; + }; + + kbx_blob_type_t + type() + { + return type_; + } + + std::vector & + image() + { + return image_; + } + + uint32_t + length() const noexcept + { + return image_.size(); + } +}; + +class kbx_header_blob_t : public kbx_blob_t { + protected: + uint8_t version_{}; + uint16_t flags_{}; + uint32_t file_created_at_{}; + uint32_t last_maintenance_run_{}; + + public: + kbx_header_blob_t(std::vector &data) : kbx_blob_t(data){}; + bool parse(); + + uint32_t + file_created_at() + { + return file_created_at_; + } +}; + +typedef struct { + uint8_t fp[PGP_FINGERPRINT_SIZE]; + uint32_t keyid_offset; + uint16_t flags; +} kbx_pgp_key_t; + +typedef struct { + uint32_t offset; + uint32_t length; + uint16_t flags; + uint8_t validity; +} kbx_pgp_uid_t; + +typedef struct { + uint32_t expired; +} kbx_pgp_sig_t; + +class kbx_pgp_blob_t : public kbx_blob_t { + protected: + uint8_t version_{}; + uint16_t flags_{}; + uint32_t keyblock_offset_{}; + uint32_t keyblock_length_{}; + + std::vector sn_{}; + std::vector keys_{}; + std::vector uids_{}; + std::vector sigs_{}; + + uint8_t ownertrust_{}; + uint8_t all_validity_{}; + + uint32_t recheck_after_{}; + uint32_t latest_timestamp_{}; + uint32_t blob_created_at_{}; + + public: + kbx_pgp_blob_t(std::vector &data) : kbx_blob_t(data){}; + + uint32_t + keyblock_offset() + { + return keyblock_offset_; + } + + uint32_t + keyblock_length() + { + return keyblock_length_; + } + + size_t + nkeys() + { + return keys_.size(); + } + size_t + nuids() + { + return uids_.size(); + } + size_t + nsigs() + { + return sigs_.size(); + } + + bool parse(); +}; + +#endif diff --git a/comm/third_party/rnp/src/librekey/key_store_g10.cpp b/comm/third_party/rnp/src/librekey/key_store_g10.cpp new file mode 100644 index 0000000000..dcf3fe112a --- /dev/null +++ b/comm/third_party/rnp/src/librekey/key_store_g10.cpp @@ -0,0 +1,1243 @@ +/* + * Copyright (c) 2017-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "config.h" + +#include +#include "key_store_pgp.h" +#include "key_store_g10.h" + +#include "crypto/common.h" +#include "crypto/mem.h" +#include "crypto/cipher.hpp" +#include "pgp-key.h" +#include "time-utils.h" + +#include "g23_sexp.hpp" +using namespace ext_key_format; +using namespace sexp; + +#define G10_CBC_IV_SIZE 16 + +#define G10_OCB_NONCE_SIZE 12 + +#define G10_SHA1_HASH_SIZE 20 + +#define G10_PROTECTED_AT_SIZE 15 + +typedef struct format_info { + pgp_symm_alg_t cipher; + pgp_cipher_mode_t cipher_mode; + pgp_hash_alg_t hash_alg; + size_t cipher_block_size; + const char * g10_type; + size_t iv_size; + size_t tag_length; + bool with_associated_data; + bool disable_padding; +} format_info; + +static bool g10_calculated_hash(const pgp_key_pkt_t &key, + const char * protected_at, + uint8_t * checksum); + +static const format_info formats[] = {{PGP_SA_AES_128, + PGP_CIPHER_MODE_CBC, + PGP_HASH_SHA1, + 16, + "openpgp-s2k3-sha1-aes-cbc", + G10_CBC_IV_SIZE, + 0, + false, + true}, + {PGP_SA_AES_256, + PGP_CIPHER_MODE_CBC, + PGP_HASH_SHA1, + 16, + "openpgp-s2k3-sha1-aes256-cbc", + G10_CBC_IV_SIZE, + 0, + false, + true}, + {PGP_SA_AES_128, + PGP_CIPHER_MODE_OCB, + PGP_HASH_SHA1, + 16, + "openpgp-s2k3-ocb-aes", + G10_OCB_NONCE_SIZE, + 16, + true, + true}}; + +static const id_str_pair g10_alg_aliases[] = { + {PGP_PKA_RSA, "rsa"}, + {PGP_PKA_RSA, "openpgp-rsa"}, + {PGP_PKA_RSA, "oid.1.2.840.113549.1.1.1"}, + {PGP_PKA_RSA, "oid.1.2.840.113549.1.1.1"}, + {PGP_PKA_ELGAMAL, "elg"}, + {PGP_PKA_ELGAMAL, "elgamal"}, + {PGP_PKA_ELGAMAL, "openpgp-elg"}, + {PGP_PKA_ELGAMAL, "openpgp-elg-sig"}, + {PGP_PKA_DSA, "dsa"}, + {PGP_PKA_DSA, "openpgp-dsa"}, + {PGP_PKA_ECDSA, "ecc"}, + {PGP_PKA_ECDSA, "ecdsa"}, + {PGP_PKA_ECDH, "ecdh"}, + {PGP_PKA_EDDSA, "eddsa"}, + {0, NULL}, +}; + +static const id_str_pair g10_curve_aliases[] = { + {PGP_CURVE_NIST_P_256, "NIST P-256"}, + {PGP_CURVE_NIST_P_256, "1.2.840.10045.3.1.7"}, + {PGP_CURVE_NIST_P_256, "prime256v1"}, + {PGP_CURVE_NIST_P_256, "secp256r1"}, + {PGP_CURVE_NIST_P_256, "nistp256"}, + {PGP_CURVE_NIST_P_384, "NIST P-384"}, + {PGP_CURVE_NIST_P_384, "secp384r1"}, + {PGP_CURVE_NIST_P_384, "1.3.132.0.34"}, + {PGP_CURVE_NIST_P_384, "nistp384"}, + {PGP_CURVE_NIST_P_521, "NIST P-521"}, + {PGP_CURVE_NIST_P_521, "secp521r1"}, + {PGP_CURVE_NIST_P_521, "1.3.132.0.35"}, + {PGP_CURVE_NIST_P_521, "nistp521"}, + {PGP_CURVE_25519, "Curve25519"}, + {PGP_CURVE_25519, "1.3.6.1.4.1.3029.1.5.1"}, + {PGP_CURVE_ED25519, "Ed25519"}, + {PGP_CURVE_ED25519, "1.3.6.1.4.1.11591.15.1"}, + {PGP_CURVE_BP256, "brainpoolP256r1"}, + {PGP_CURVE_BP256, "1.3.36.3.3.2.8.1.1.7"}, + {PGP_CURVE_BP384, "brainpoolP384r1"}, + {PGP_CURVE_BP384, "1.3.36.3.3.2.8.1.1.11"}, + {PGP_CURVE_BP512, "brainpoolP512r1"}, + {PGP_CURVE_BP512, "1.3.36.3.3.2.8.1.1.13"}, + {PGP_CURVE_P256K1, "secp256k1"}, + {PGP_CURVE_P256K1, "1.3.132.0.10"}, + {0, NULL}, +}; + +static const id_str_pair g10_curve_names[] = { + {PGP_CURVE_NIST_P_256, "NIST P-256"}, + {PGP_CURVE_NIST_P_384, "NIST P-384"}, + {PGP_CURVE_NIST_P_521, "NIST P-521"}, + {PGP_CURVE_ED25519, "Ed25519"}, + {PGP_CURVE_25519, "Curve25519"}, + {PGP_CURVE_BP256, "brainpoolP256r1"}, + {PGP_CURVE_BP384, "brainpoolP384r1"}, + {PGP_CURVE_BP512, "brainpoolP512r1"}, + {PGP_CURVE_P256K1, "secp256k1"}, + {0, NULL}, +}; + +static const format_info * +find_format(pgp_symm_alg_t cipher, pgp_cipher_mode_t mode, pgp_hash_alg_t hash_alg) +{ + for (size_t i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].cipher == cipher && formats[i].cipher_mode == mode && + formats[i].hash_alg == hash_alg) { + return &formats[i]; + } + } + return NULL; +} + +static const format_info * +parse_format(const char *format, size_t format_len) +{ + for (size_t i = 0; i < ARRAY_SIZE(formats); i++) { + if (strlen(formats[i].g10_type) == format_len && + !strncmp(formats[i].g10_type, format, format_len)) { + return &formats[i]; + } + } + return NULL; +} + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +void +gnupg_sexp_t::add(unsigned u) +{ + char s[sizeof(STR(UINT_MAX)) + 1]; + snprintf(s, sizeof(s), "%u", u); + push_back(std::make_shared(s)); +} + +std::shared_ptr +gnupg_sexp_t::add_sub() +{ + auto res = std::make_shared(); + push_back(res); + return res; +} + +/* + * Parse S-expression + * https://people.csail.mit.edu/rivest/Sexp.txt + * sexp library supports canonical and advanced transport formats + * as well as base64 encoding of canonical + */ + +bool +gnupg_sexp_t::parse(const char *r_bytes, size_t r_length, size_t depth) +{ + bool res = false; + std::istringstream iss(std::string(r_bytes, r_length)); + try { + sexp_input_stream_t sis(&iss, depth); + sexp_list_t::parse(sis.set_byte_size(8)->get_char()); + res = true; + } catch (sexp_exception_t &e) { + RNP_LOG("%s", e.what()); + } + return res; +} + +/* + * Parse gnupg extended private key file ("G23") + * https://github.com/gpg/gnupg/blob/main/agent/keyformat.txt + */ + +bool +gnupg_extended_private_key_t::parse(const char *r_bytes, size_t r_length, size_t depth) +{ + bool res = false; + std::istringstream iss(std::string(r_bytes, r_length)); + try { + ext_key_input_stream_t g23_is(&iss, depth); + g23_is.scan(*this); + res = true; + } catch (sexp_exception_t &e) { + RNP_LOG("%s", e.what()); + } + return res; +} + +static const sexp_list_t * +lookup_var(const sexp_list_t *list, const std::string &name) noexcept +{ + const sexp_list_t *res = nullptr; + // We are looking for a list element (condition 1) + // that: + // -- has at least two SEXP elements (condition 2) + // -- has a SEXP string at 0 postion (condition 3) + // matching given name (condition 4) + auto match = [name](const std::shared_ptr &ptr) { + bool r = false; + auto r1 = ptr->sexp_list_view(); + if (r1 && r1->size() >= 2) { // conditions (1) and (2) + auto r2 = r1->sexp_string_at(0); + if (r2 && r2 == name) // conditions (3) and (4) + r = true; + } + return r; + }; + auto r3 = std::find_if(list->begin(), list->end(), match); + if (r3 == list->end()) + RNP_LOG("Haven't got variable '%s'", name.c_str()); + else + res = (*r3)->sexp_list_view(); + return res; +} + +static const sexp_string_t * +lookup_var_data(const sexp_list_t *list, const std::string &name) noexcept +{ + const sexp_list_t *var = lookup_var(list, name); + if (!var) { + return NULL; + } + + if (!var->at(1)->is_sexp_string()) { + RNP_LOG("Expected block value"); + return NULL; + } + + return var->sexp_string_at(1); +} + +static bool +read_mpi(const sexp_list_t *list, const std::string &name, pgp_mpi_t &val) noexcept +{ + const sexp_string_t *data = lookup_var_data(list, name); + if (!data) { + return false; + } + + /* strip leading zero */ + const auto &bytes = data->get_string(); + if ((bytes.size() > 1) && !bytes[0] && (bytes[1] & 0x80)) { + return mem2mpi(&val, bytes.data() + 1, bytes.size() - 1); + } + return mem2mpi(&val, bytes.data(), bytes.size()); +} + +static bool +read_curve(const sexp_list_t *list, const std::string &name, pgp_ec_key_t &key) noexcept +{ + const sexp_string_t *data = lookup_var_data(list, name); + if (!data) { + return false; + } + + const auto &bytes = data->get_string(); + pgp_curve_t curve = static_cast( + id_str_pair::lookup(g10_curve_aliases, data->get_string(), PGP_CURVE_UNKNOWN)); + if (curve != PGP_CURVE_UNKNOWN) { + key.curve = curve; + return true; + } + RNP_LOG("Unknown curve: %.*s", (int) bytes.size(), (char *) bytes.data()); + return false; +} + +void +gnupg_sexp_t::add_mpi(const std::string &name, const pgp_mpi_t &mpi) +{ + auto sub_s_exp = add_sub(); + sub_s_exp->push_back(std::make_shared(name)); + auto value_block = std::make_shared(); + sub_s_exp->push_back(value_block); + + sexp_simple_string_t data; + size_t len = mpi_bytes(&mpi); + size_t idx; + + for (idx = 0; (idx < len) && !mpi.mpi[idx]; idx++) + ; + + if (idx < len) { + if (mpi.mpi[idx] & 0x80) { + data.append(0); + data.std::basic_string::append(mpi.mpi + idx, len - idx); + } else { + data.assign(mpi.mpi + idx, mpi.mpi + len); + } + value_block->set_string(data); + } +} + +void +gnupg_sexp_t::add_curve(const std::string &name, const pgp_ec_key_t &key) +{ + const char *curve = id_str_pair::lookup(g10_curve_names, key.curve, NULL); + if (!curve) { + RNP_LOG("unknown curve"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + auto psub_s_exp = add_sub(); + psub_s_exp->add(name); + psub_s_exp->add(curve); + + if ((key.curve != PGP_CURVE_ED25519) && (key.curve != PGP_CURVE_25519)) { + return; + } + + psub_s_exp = add_sub(); + psub_s_exp->add("flags"); + psub_s_exp->add((key.curve == PGP_CURVE_ED25519) ? "eddsa" : "djb-tweak"); +} + +static bool +parse_pubkey(pgp_key_pkt_t &pubkey, const sexp_list_t *s_exp, pgp_pubkey_alg_t alg) +{ + pubkey.version = PGP_V4; + pubkey.alg = alg; + pubkey.material.alg = alg; + switch (alg) { + case PGP_PKA_DSA: + if (!read_mpi(s_exp, "p", pubkey.material.dsa.p) || + !read_mpi(s_exp, "q", pubkey.material.dsa.q) || + !read_mpi(s_exp, "g", pubkey.material.dsa.g) || + !read_mpi(s_exp, "y", pubkey.material.dsa.y)) { + return false; + } + break; + + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!read_mpi(s_exp, "n", pubkey.material.rsa.n) || + !read_mpi(s_exp, "e", pubkey.material.rsa.e)) { + return false; + } + break; + + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!read_mpi(s_exp, "p", pubkey.material.eg.p) || + !read_mpi(s_exp, "g", pubkey.material.eg.g) || + !read_mpi(s_exp, "y", pubkey.material.eg.y)) { + return false; + } + break; + case PGP_PKA_ECDSA: + case PGP_PKA_ECDH: + case PGP_PKA_EDDSA: + if (!read_curve(s_exp, "curve", pubkey.material.ec) || + !read_mpi(s_exp, "q", pubkey.material.ec.p)) { + return false; + } + if (pubkey.material.ec.curve == PGP_CURVE_ED25519) { + /* need to adjust it here since 'ecc' key type defaults to ECDSA */ + pubkey.alg = PGP_PKA_EDDSA; + pubkey.material.alg = PGP_PKA_EDDSA; + } + break; + default: + RNP_LOG("Unsupported public key algorithm: %d", (int) alg); + return false; + } + + return true; +} + +static bool +parse_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *s_exp, pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_DSA: + if (!read_mpi(s_exp, "x", seckey.material.dsa.x)) { + return false; + } + break; + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!read_mpi(s_exp, "d", seckey.material.rsa.d) || + !read_mpi(s_exp, "p", seckey.material.rsa.p) || + !read_mpi(s_exp, "q", seckey.material.rsa.q) || + !read_mpi(s_exp, "u", seckey.material.rsa.u)) { + return false; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!read_mpi(s_exp, "x", seckey.material.eg.x)) { + return false; + } + break; + case PGP_PKA_ECDSA: + case PGP_PKA_ECDH: + case PGP_PKA_EDDSA: + if (!read_mpi(s_exp, "d", seckey.material.ec.x)) { + return false; + } + break; + default: + RNP_LOG("Unsupported public key algorithm: %d", (int) alg); + return false; + } + + seckey.material.secret = true; + return true; +} + +static bool +decrypt_protected_section(const sexp_simple_string_t &encrypted_data, + const pgp_key_pkt_t & seckey, + const std::string & password, + gnupg_sexp_t & r_s_exp, + uint8_t * associated_data, + size_t associated_data_len) +{ + const format_info * info = NULL; + unsigned keysize = 0; + uint8_t derived_key[PGP_MAX_KEY_SIZE]; + uint8_t * decrypted_data = NULL; + size_t decrypted_data_len = 0; + size_t output_written = 0; + size_t input_consumed = 0; + std::unique_ptr dec; + bool ret = false; + + const char *decrypted_bytes; + size_t s_exp_len; + + // sanity checks + const pgp_key_protection_t &prot = seckey.sec_protection; + keysize = pgp_key_size(prot.symm_alg); + if (!keysize) { + RNP_LOG("parse_seckey: unknown symmetric algo"); + goto done; + } + // find the protection format in our table + info = find_format(prot.symm_alg, prot.cipher_mode, prot.s2k.hash_alg); + if (!info) { + RNP_LOG("Unsupported format, alg: %d, chiper_mode: %d, hash: %d", + prot.symm_alg, + prot.cipher_mode, + prot.s2k.hash_alg); + goto done; + } + + // derive the key + if (pgp_s2k_iterated(prot.s2k.hash_alg, + derived_key, + keysize, + password.c_str(), + prot.s2k.salt, + prot.s2k.iterations)) { + RNP_LOG("pgp_s2k_iterated failed"); + goto done; + } + + // decrypt + decrypted_data = (uint8_t *) malloc(encrypted_data.size()); + if (decrypted_data == NULL) { + RNP_LOG("can't allocate memory"); + goto done; + } + dec = Cipher::decryption( + info->cipher, info->cipher_mode, info->tag_length, info->disable_padding); + if (!dec || !dec->set_key(derived_key, keysize)) { + goto done; + } + if (associated_data != nullptr && associated_data_len != 0) { + if (!dec->set_ad(associated_data, associated_data_len)) { + goto done; + } + } + // Nonce shall be the last chunk of associated data + if (!dec->set_iv(prot.iv, info->iv_size)) { + goto done; + } + if (!dec->finish(decrypted_data, + encrypted_data.size(), + &output_written, + encrypted_data.data(), + encrypted_data.size(), + &input_consumed)) { + goto done; + } + decrypted_data_len = output_written; + s_exp_len = decrypted_data_len; + decrypted_bytes = (const char *) decrypted_data; + + // parse and validate the decrypted s-exp + + if (!r_s_exp.parse(decrypted_bytes, s_exp_len, SXP_MAX_DEPTH)) { + goto done; + } + if (!r_s_exp.size() || r_s_exp.at(0)->is_sexp_string()) { + RNP_LOG("Hasn't got sub s-exp with key data."); + goto done; + } + ret = true; +done: + if (!ret) { + r_s_exp.clear(); + } + secure_clear(decrypted_data, decrypted_data_len); + free(decrypted_data); + return ret; +} + +static bool +parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const char *password) +{ + // find and validate the protected section + const sexp_list_t *protected_key = lookup_var(list, "protected"); + if (!protected_key) { + RNP_LOG("missing protected section"); + return false; + } + if (protected_key->size() != 4 || !protected_key->at(1)->is_sexp_string() || + protected_key->at(2)->is_sexp_string() || !protected_key->at(3)->is_sexp_string()) { + RNP_LOG("Wrong protected format, expected: (protected mode (params) " + "encrypted_octet_string)\n"); + return false; + } + + // lookup the protection format + auto & fmt_bt = protected_key->sexp_string_at(1)->get_string(); + const format_info *format = parse_format((const char *) fmt_bt.data(), fmt_bt.size()); + if (!format) { + RNP_LOG("Unsupported protected mode: '%.*s'\n", + (int) fmt_bt.size(), + (const char *) fmt_bt.data()); + return false; + } + + // fill in some fields based on the lookup above + pgp_key_protection_t &prot = seckey.sec_protection; + prot.symm_alg = format->cipher; + prot.cipher_mode = format->cipher_mode; + prot.s2k.hash_alg = format->hash_alg; + + // locate and validate the protection parameters + auto params = protected_key->sexp_list_at(2); + if (params->size() != 2 || params->at(0)->is_sexp_string() || + !params->at(1)->is_sexp_string()) { + RNP_LOG("Wrong params format, expected: ((hash salt no_of_iterations) iv)\n"); + return false; + } + + // locate and validate the (hash salt no_of_iterations) exp + auto alg = params->sexp_list_at(0); + if (alg->size() != 3 || !alg->at(0)->is_sexp_string() || !alg->at(1)->is_sexp_string() || + !alg->at(2)->is_sexp_string()) { + RNP_LOG("Wrong params sub-level format, expected: (hash salt no_of_iterations)\n"); + return false; + } + auto &hash_bt = alg->sexp_string_at(0)->get_string(); + if (hash_bt != "sha1") { + RNP_LOG("Wrong hashing algorithm, should be sha1 but %.*s\n", + (int) hash_bt.size(), + (const char *) hash_bt.data()); + return false; + } + + // fill in some constant values + prot.s2k.hash_alg = PGP_HASH_SHA1; + prot.s2k.usage = PGP_S2KU_ENCRYPTED_AND_HASHED; + prot.s2k.specifier = PGP_S2KS_ITERATED_AND_SALTED; + + // check salt size + auto &salt_bt = alg->sexp_string_at(1)->get_string(); + if (salt_bt.size() != PGP_SALT_SIZE) { + RNP_LOG("Wrong salt size, should be %d but %d\n", PGP_SALT_SIZE, (int) salt_bt.size()); + return false; + } + + // salt + memcpy(prot.s2k.salt, salt_bt.data(), salt_bt.size()); + // s2k iterations + auto iter = alg->sexp_string_at(2); + prot.s2k.iterations = iter->as_unsigned(); + if (prot.s2k.iterations == UINT_MAX) { + RNP_LOG("Wrong numbers of iteration, %.*s\n", + (int) iter->get_string().size(), + (const char *) iter->get_string().data()); + return false; + } + + // iv + auto &iv_bt = params->sexp_string_at(1)->get_string(); + if (iv_bt.size() != format->iv_size) { + RNP_LOG("Wrong nonce size, should be %zu but %zu\n", format->iv_size, iv_bt.size()); + return false; + } + memcpy(prot.iv, iv_bt.data(), iv_bt.size()); + + // we're all done if no password was provided (decryption not requested) + if (!password) { + seckey.material.secret = false; + return true; + } + + // password was provided, so decrypt + auto & enc_bt = protected_key->sexp_string_at(3)->get_string(); + gnupg_sexp_t decrypted_s_exp; + + // Build associated data (AD) that is not included in the ciphertext but that should be + // authenticated. gnupg builds AD as follows (file 'protect.c' do_encryption/do_decryption + // functions) + // -- "protected-private-key" section content + // -- less "protected" subsection + // -- serialized in canonical format + std::string associated_data; + if (format->with_associated_data) { + std::ostringstream oss(std::ios_base::binary); + sexp_output_stream_t os(&oss); + os.var_put_char('('); + for_each(list->begin(), list->end(), [&](const std::shared_ptr &obj) { + if (obj->sexp_list_view() != protected_key) + obj->print_canonical(&os); + }); + os.var_put_char(')'); + associated_data = oss.str(); + } + + if (!decrypt_protected_section( + enc_bt, + seckey, + password, + decrypted_s_exp, + format->with_associated_data ? (uint8_t *) associated_data.data() : nullptr, + format->with_associated_data ? associated_data.length() : 0)) { + return false; + } + // see if we have a protected-at section + char protected_at[G10_PROTECTED_AT_SIZE] = {0}; + auto protected_at_data = lookup_var_data(list, "protected-at"); + if (protected_at_data) { + if (protected_at_data->get_string().size() != G10_PROTECTED_AT_SIZE) { + RNP_LOG("protected-at has wrong length: %zu, expected, %d\n", + protected_at_data->get_string().size(), + G10_PROTECTED_AT_SIZE); + return false; + } + memcpy(protected_at, + protected_at_data->get_string().data(), + protected_at_data->get_string().size()); + } + // parse MPIs + if (!parse_seckey(seckey, decrypted_s_exp.sexp_list_at(0), seckey.alg)) { + RNP_LOG("failed to parse seckey"); + return false; + } + // check hash, if present + if (decrypted_s_exp.size() > 1) { + if (decrypted_s_exp.at(1)->is_sexp_string()) { + RNP_LOG("Wrong hash block type."); + return false; + } + auto sub_el = decrypted_s_exp.sexp_list_at(1); + if (sub_el->size() < 3 || !sub_el->at(0)->is_sexp_string() || + !sub_el->at(1)->is_sexp_string() || !sub_el->at(2)->is_sexp_string()) { + RNP_LOG("Wrong hash block structure."); + return false; + } + + auto &hkey = sub_el->sexp_string_at(0)->get_string(); + if (hkey != "hash") { + RNP_LOG("Has got wrong hash block at encrypted key data."); + return false; + } + auto &halg = sub_el->sexp_string_at(1)->get_string(); + if (halg != "sha1") { + RNP_LOG("Supported only sha1 hash at encrypted private key."); + return false; + } + uint8_t checkhash[G10_SHA1_HASH_SIZE]; + if (!g10_calculated_hash(seckey, protected_at, checkhash)) { + RNP_LOG("failed to calculate hash"); + return false; + } + auto &hval = sub_el->sexp_string_at(2)->get_string(); + if (hval.size() != G10_SHA1_HASH_SIZE || + memcmp(checkhash, hval.data(), G10_SHA1_HASH_SIZE)) { + RNP_LOG("Incorrect hash at encrypted private key."); + return false; + } + } + seckey.material.secret = true; + return true; +} + +static bool +g23_parse_seckey(pgp_key_pkt_t &seckey, + const uint8_t *data, + size_t data_len, + const char * password) +{ + gnupg_extended_private_key_t g23_extended_key; + + const char *bytes = (const char *) data; + if (!g23_extended_key.parse(bytes, data_len, SXP_MAX_DEPTH)) { + RNP_LOG("Failed to parse s-exp."); + return false; + } + // Although the library parses full g23 extended key + // we extract and use g10 part only + const sexp_list_t &g10_key = g23_extended_key.key; + + /* expected format: + * ( + * ( + * (x ) + * (y ) + * ) + * ) + */ + + if (g10_key.size() != 2 || !g10_key.at(0)->is_sexp_string() || + !g10_key.at(1)->is_sexp_list()) { + RNP_LOG("Wrong format, expected: ( (...))"); + return false; + } + + bool is_protected = false; + + auto &name = g10_key.sexp_string_at(0)->get_string(); + if (name == "private-key") { + is_protected = false; + } else if (name == "protected-private-key") { + is_protected = true; + } else { + RNP_LOG("Unsupported top-level block: '%.*s'", + (int) name.size(), + (const char *) name.data()); + return false; + } + + auto alg_s_exp = g10_key.sexp_list_at(1); + if (alg_s_exp->size() < 2) { + RNP_LOG("Wrong count of algorithm-level elements: %zu", alg_s_exp->size()); + return false; + } + + if (!alg_s_exp->at(0)->is_sexp_string()) { + RNP_LOG("Expected block with algorithm name, but has s-exp"); + return false; + } + + auto & alg_bt = alg_s_exp->sexp_string_at(0)->get_string(); + pgp_pubkey_alg_t alg = static_cast( + id_str_pair::lookup(g10_alg_aliases, alg_bt.c_str(), PGP_PKA_NOTHING)); + if (alg == PGP_PKA_NOTHING) { + RNP_LOG( + "Unsupported algorithm: '%.*s'", (int) alg_bt.size(), (const char *) alg_bt.data()); + return false; + } + + bool ret = false; + if (!parse_pubkey(seckey, alg_s_exp, alg)) { + RNP_LOG("failed to parse pubkey"); + goto done; + } + + if (is_protected) { + if (!parse_protected_seckey(seckey, alg_s_exp, password)) { + goto done; + } + } else { + seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; + seckey.sec_protection.symm_alg = PGP_SA_PLAINTEXT; + seckey.sec_protection.s2k.hash_alg = PGP_HASH_UNKNOWN; + if (!parse_seckey(seckey, alg_s_exp, alg)) { + RNP_LOG("failed to parse seckey"); + goto done; + } + } + ret = true; +done: + if (!ret) { + seckey = pgp_key_pkt_t(); + } + return ret; +} + +pgp_key_pkt_t * +g10_decrypt_seckey(const pgp_rawpacket_t &raw, + const pgp_key_pkt_t & pubkey, + const char * password) +{ + if (!password) { + return NULL; + } + auto seckey = std::unique_ptr(new pgp_key_pkt_t(pubkey, false)); + if (!g23_parse_seckey(*seckey, raw.raw.data(), raw.raw.size(), password)) { + return NULL; + } + /* g10 has the same 'ecc' algo for ECDSA/ECDH/EDDSA. Probably should be better place to fix + * this. */ + seckey->alg = pubkey.alg; + seckey->material.alg = pubkey.material.alg; + return seckey.release(); +} + +static bool +copy_secret_fields(pgp_key_pkt_t &dst, const pgp_key_pkt_t &src) +{ + switch (src.alg) { + case PGP_PKA_DSA: + dst.material.dsa.x = src.material.dsa.x; + break; + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + dst.material.rsa.d = src.material.rsa.d; + dst.material.rsa.p = src.material.rsa.p; + dst.material.rsa.q = src.material.rsa.q; + dst.material.rsa.u = src.material.rsa.u; + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + dst.material.eg.x = src.material.eg.x; + break; + case PGP_PKA_ECDSA: + case PGP_PKA_ECDH: + case PGP_PKA_EDDSA: + dst.material.ec.x = src.material.ec.x; + break; + default: + RNP_LOG("Unsupported public key algorithm: %d", (int) src.alg); + return false; + } + + dst.material.secret = src.material.secret; + dst.sec_protection = src.sec_protection; + dst.tag = is_subkey_pkt(dst.tag) ? PGP_PKT_SECRET_SUBKEY : PGP_PKT_SECRET_KEY; + return true; +} + +bool +rnp_key_store_g10_from_src(rnp_key_store_t * key_store, + pgp_source_t * src, + const pgp_key_provider_t *key_provider) +{ + try { + /* read src to the memory */ + rnp::MemorySource memsrc(*src); + /* parse secret key: fills material and sec_protection only */ + pgp_key_pkt_t seckey; + if (!g23_parse_seckey(seckey, (uint8_t *) memsrc.memory(), memsrc.size(), NULL)) { + return false; + } + /* copy public key fields if any */ + pgp_key_t key; + if (key_provider) { + pgp_key_request_ctx_t req_ctx(PGP_OP_MERGE_INFO, false, PGP_KEY_SEARCH_GRIP); + if (!rnp_key_store_get_key_grip(&seckey.material, req_ctx.search.by.grip)) { + return false; + } + + const pgp_key_t *pubkey = pgp_request_key(key_provider, &req_ctx); + if (!pubkey) { + return false; + } + + /* public key packet has some more info then the secret part */ + key = pgp_key_t(*pubkey, true); + if (!copy_secret_fields(key.pkt(), seckey)) { + return false; + } + } else { + key.set_pkt(std::move(seckey)); + } + /* set rawpkt */ + key.set_rawpkt( + pgp_rawpacket_t((uint8_t *) memsrc.memory(), memsrc.size(), PGP_PKT_RESERVED)); + key.format = PGP_KEY_STORE_G10; + if (!rnp_key_store_add_key(key_store, &key)) { + return false; + } + return true; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +/* + * Write G10 S-exp to buffer + * + * Supported format: (1:a2:ab(3:asd1:a)) + */ +bool +gnupg_sexp_t::write(pgp_dest_t &dst) const noexcept +{ + bool res = false; + try { + std::ostringstream oss(std::ios_base::binary); + sexp_output_stream_t os(&oss); + print_canonical(&os); + const std::string &s = oss.str(); + const char * ss = s.c_str(); + dst_write(&dst, ss, s.size()); + res = (dst.werr == RNP_SUCCESS); + + } catch (...) { + } + + return res; +} + +void +gnupg_sexp_t::add_pubkey(const pgp_key_pkt_t &key) +{ + switch (key.alg) { + case PGP_PKA_DSA: + add("dsa"); + add_mpi("p", key.material.dsa.p); + add_mpi("q", key.material.dsa.q); + add_mpi("g", key.material.dsa.g); + add_mpi("y", key.material.dsa.y); + break; + case PGP_PKA_RSA_SIGN_ONLY: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA: + add("rsa"); + add_mpi("n", key.material.rsa.n); + add_mpi("e", key.material.rsa.e); + break; + case PGP_PKA_ELGAMAL: + add("elg"); + add_mpi("p", key.material.eg.p); + add_mpi("g", key.material.eg.g); + add_mpi("y", key.material.eg.y); + break; + case PGP_PKA_ECDSA: + case PGP_PKA_ECDH: + case PGP_PKA_EDDSA: + add("ecc"); + add_curve("curve", key.material.ec); + add_mpi("q", key.material.ec.p); + break; + default: + RNP_LOG("Unsupported public key algorithm: %d", (int) key.alg); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +void +gnupg_sexp_t::add_seckey(const pgp_key_pkt_t &key) +{ + switch (key.alg) { + case PGP_PKA_DSA: + add_mpi("x", key.material.dsa.x); + break; + case PGP_PKA_RSA_SIGN_ONLY: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA: + add_mpi("d", key.material.rsa.d); + add_mpi("p", key.material.rsa.p); + add_mpi("q", key.material.rsa.q); + add_mpi("u", key.material.rsa.u); + break; + case PGP_PKA_ELGAMAL: + add_mpi("x", key.material.eg.x); + break; + case PGP_PKA_ECDSA: + case PGP_PKA_ECDH: + case PGP_PKA_EDDSA: { + add_mpi("d", key.material.ec.x); + break; + } + default: + RNP_LOG("Unsupported public key algorithm: %d", (int) key.alg); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +rnp::secure_vector +gnupg_sexp_t::write_padded(size_t padblock) const +{ + rnp::MemoryDest raw; + raw.set_secure(true); + + if (!write(raw.dst())) { + RNP_LOG("failed to serialize s_exp"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + // add padding! + size_t padding = padblock - raw.writeb() % padblock; + for (size_t i = 0; i < padding; i++) { + raw.write("X", 1); + } + if (raw.werr()) { + RNP_LOG("failed to write padding"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + const uint8_t *mem = (uint8_t *) raw.memory(); + return rnp::secure_vector(mem, mem + raw.writeb()); +} + +void +gnupg_sexp_t::add_protected_seckey(pgp_key_pkt_t & seckey, + const std::string & password, + rnp::SecurityContext &ctx) +{ + pgp_key_protection_t &prot = seckey.sec_protection; + if (prot.s2k.specifier != PGP_S2KS_ITERATED_AND_SALTED) { + RNP_LOG("Bad s2k specifier: %d", (int) prot.s2k.specifier); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + const format_info *format = + find_format(prot.symm_alg, prot.cipher_mode, prot.s2k.hash_alg); + if (!format) { + RNP_LOG("Unknown protection format."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + // randomize IV and salt + ctx.rng.get(prot.iv, sizeof(prot.iv)); + ctx.rng.get(prot.s2k.salt, sizeof(prot.s2k.salt)); + + // write seckey + gnupg_sexp_t raw_s_exp; + auto psub_s_exp = raw_s_exp.add_sub(); + psub_s_exp->add_seckey(seckey); + + // calculate hash + char protected_at[G10_PROTECTED_AT_SIZE + 1]; + uint8_t checksum[G10_SHA1_HASH_SIZE]; + // TODO: how critical is it if we have a skewed timestamp here due to y2k38 problem? + struct tm tm = {}; + rnp_gmtime(ctx.time(), tm); + strftime(protected_at, sizeof(protected_at), "%Y%m%dT%H%M%S", &tm); + if (!g10_calculated_hash(seckey, protected_at, checksum)) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + psub_s_exp = raw_s_exp.add_sub(); + psub_s_exp->add("hash"); + psub_s_exp->add("sha1"); + psub_s_exp->add(checksum, sizeof(checksum)); + + /* write raw secret key to the memory */ + rnp::secure_vector rawkey = raw_s_exp.write_padded(format->cipher_block_size); + + /* derive encrypting key */ + unsigned keysize = pgp_key_size(prot.symm_alg); + if (!keysize) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + rnp::secure_array derived_key; + if (pgp_s2k_iterated(format->hash_alg, + derived_key.data(), + keysize, + password.c_str(), + prot.s2k.salt, + prot.s2k.iterations)) { + RNP_LOG("s2k key derivation failed"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + /* encrypt raw key */ + std::unique_ptr enc( + Cipher::encryption(format->cipher, format->cipher_mode, 0, true)); + if (!enc || !enc->set_key(derived_key.data(), keysize) || + !enc->set_iv(prot.iv, format->iv_size)) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + size_t output_written, input_consumed; + std::vector enckey(rawkey.size()); + + if (!enc->finish(enckey.data(), + enckey.size(), + &output_written, + rawkey.data(), + rawkey.size(), + &input_consumed)) { + RNP_LOG("Encryption failed"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + /* build s_exp with encrypted key */ + psub_s_exp = add_sub(); + psub_s_exp->add("protected"); + psub_s_exp->add(format->g10_type); + /* protection params: s2k, iv */ + auto psub_sub_s_exp = psub_s_exp->add_sub(); + /* s2k params: hash, salt, iterations */ + auto psub_sub_sub_s_exp = psub_sub_s_exp->add_sub(); + psub_sub_sub_s_exp->add("sha1"); + psub_sub_sub_s_exp->add(prot.s2k.salt, PGP_SALT_SIZE); + psub_sub_sub_s_exp->add(prot.s2k.iterations); + psub_sub_s_exp->add(prot.iv, format->iv_size); + /* encrypted key data itself */ + psub_s_exp->add(enckey.data(), enckey.size()); + /* protected-at */ + psub_s_exp = add_sub(); + psub_s_exp->add("protected-at"); + psub_s_exp->add((uint8_t *) protected_at, G10_PROTECTED_AT_SIZE); +} + +bool +g10_write_seckey(pgp_dest_t * dst, + pgp_key_pkt_t * seckey, + const char * password, + rnp::SecurityContext &ctx) +{ + bool is_protected = true; + + switch (seckey->sec_protection.s2k.usage) { + case PGP_S2KU_NONE: + is_protected = false; + break; + case PGP_S2KU_ENCRYPTED_AND_HASHED: + is_protected = true; + // TODO: these are forced for now, until openpgp-native is implemented + seckey->sec_protection.symm_alg = PGP_SA_AES_128; + seckey->sec_protection.cipher_mode = PGP_CIPHER_MODE_CBC; + seckey->sec_protection.s2k.hash_alg = PGP_HASH_SHA1; + break; + default: + RNP_LOG("unsupported s2k usage"); + return false; + } + + try { + gnupg_sexp_t s_exp; + s_exp.add(is_protected ? "protected-private-key" : "private-key"); + auto pkey = s_exp.add_sub(); + pkey->add_pubkey(*seckey); + + if (is_protected) { + pkey->add_protected_seckey(*seckey, password, ctx); + } else { + pkey->add_seckey(*seckey); + } + return s_exp.write(*dst) && !dst->werr; + } catch (const std::exception &e) { + RNP_LOG("Failed to write g10 key: %s", e.what()); + return false; + } +} + +static bool +g10_calculated_hash(const pgp_key_pkt_t &key, const char *protected_at, uint8_t *checksum) +{ + try { + /* populate s_exp */ + gnupg_sexp_t s_exp; + s_exp.add_pubkey(key); + s_exp.add_seckey(key); + auto s_sub_exp = s_exp.add_sub(); + s_sub_exp->add("protected-at"); + s_sub_exp->add((uint8_t *) protected_at, G10_PROTECTED_AT_SIZE); + /* write it to memdst */ + rnp::MemoryDest memdst; + memdst.set_secure(true); + if (!s_exp.write(memdst.dst())) { + RNP_LOG("Failed to write s_exp"); + return false; + } + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + hash->add(memdst.memory(), memdst.writeb()); + hash->finish(checksum); + return true; + } catch (const std::exception &e) { + RNP_LOG("Failed to build s_exp: %s", e.what()); + return false; + } +} + +bool +rnp_key_store_gnupg_sexp_to_dst(pgp_key_t *key, pgp_dest_t *dest) +{ + if (key->format != PGP_KEY_STORE_G10) { + RNP_LOG("incorrect format: %d", key->format); + return false; + } + pgp_rawpacket_t &packet = key->rawpkt(); + dst_write(dest, packet.raw.data(), packet.raw.size()); + return dest->werr == RNP_SUCCESS; +} diff --git a/comm/third_party/rnp/src/librekey/key_store_g10.h b/comm/third_party/rnp/src/librekey/key_store_g10.h new file mode 100644 index 0000000000..f770628c7c --- /dev/null +++ b/comm/third_party/rnp/src/librekey/key_store_g10.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE RIBOSE, INC. AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_KEY_STORE_G10_H +#define RNP_KEY_STORE_G10_H + +#include + +bool rnp_key_store_g10_from_src(rnp_key_store_t *, pgp_source_t *, const pgp_key_provider_t *); +bool rnp_key_store_gnupg_sexp_to_dst(pgp_key_t *, pgp_dest_t *); +bool g10_write_seckey(pgp_dest_t * dst, + pgp_key_pkt_t * seckey, + const char * password, + rnp::SecurityContext &ctx); +pgp_key_pkt_t *g10_decrypt_seckey(const pgp_rawpacket_t &raw, + const pgp_key_pkt_t & pubkey, + const char * password); + +#endif // RNP_KEY_STORE_G10_H diff --git a/comm/third_party/rnp/src/librekey/key_store_kbx.cpp b/comm/third_party/rnp/src/librekey/key_store_kbx.cpp new file mode 100644 index 0000000000..bc504f6612 --- /dev/null +++ b/comm/third_party/rnp/src/librekey/key_store_kbx.cpp @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2017-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifdef HAVE_SYS_PARAM_H +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include +#include +#include + +#include "key_store_pgp.h" +#include "key_store_kbx.h" +#include "pgp-key.h" +#include + +/* same limit with GnuPG 2.1 */ +#define BLOB_SIZE_LIMIT (5 * 1024 * 1024) +/* limit the number of keys/sigs/uids in the blob */ +#define BLOB_OBJ_LIMIT 0x8000 + +#define BLOB_HEADER_SIZE 0x5 +#define BLOB_FIRST_SIZE 0x20 +#define BLOB_KEY_SIZE 0x1C +#define BLOB_UID_SIZE 0x0C +#define BLOB_SIG_SIZE 0x04 +#define BLOB_VALIDITY_SIZE 0x10 + +uint8_t +kbx_blob_t::ru8(size_t idx) +{ + return image_[idx]; +} + +uint16_t +kbx_blob_t::ru16(size_t idx) +{ + return read_uint16(image_.data() + idx); +} + +uint32_t +kbx_blob_t::ru32(size_t idx) +{ + return read_uint32(image_.data() + idx); +} + +kbx_blob_t::kbx_blob_t(std::vector &data) +{ + if (data.size() < BLOB_HEADER_SIZE) { + RNP_LOG("Too small KBX blob."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + uint32_t len = read_uint32(data.data()); + if (len > BLOB_SIZE_LIMIT) { + RNP_LOG("Too large KBX blob."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + if (len != data.size()) { + RNP_LOG("KBX blob size mismatch."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + image_ = data; + type_ = (kbx_blob_type_t) ru8(4); +} + +bool +kbx_header_blob_t::parse() +{ + if (length() != BLOB_FIRST_SIZE) { + RNP_LOG("The first blob has wrong length: %" PRIu32 " but expected %d", + length(), + (int) BLOB_FIRST_SIZE); + return false; + } + + size_t idx = BLOB_HEADER_SIZE; + version_ = ru8(idx++); + if (version_ != 1) { + RNP_LOG("Wrong version, expect 1 but has %" PRIu8, version_); + return false; + } + + flags_ = ru16(idx); + idx += 2; + + // blob should contains a magic KBXf + if (memcmp(image_.data() + idx, "KBXf", 4)) { + RNP_LOG("The first blob hasn't got a KBXf magic string"); + return false; + } + idx += 4; + // RFU + idx += 4; + // File creation time + file_created_at_ = ru32(idx); + idx += 4; + // Duplicated? + file_created_at_ = ru32(idx); + // RFU +4 bytes + // RFU +4 bytes + return true; +} + +bool +kbx_pgp_blob_t::parse() +{ + if (image_.size() < 15 + BLOB_HEADER_SIZE) { + RNP_LOG("Too few data in the blob."); + return false; + } + + size_t idx = BLOB_HEADER_SIZE; + /* version */ + version_ = ru8(idx++); + if (version_ != 1) { + RNP_LOG("Wrong version: %" PRIu8, version_); + return false; + } + /* flags */ + flags_ = ru16(idx); + idx += 2; + /* keyblock offset */ + keyblock_offset_ = ru32(idx); + idx += 4; + /* keyblock length */ + keyblock_length_ = ru32(idx); + idx += 4; + + if ((keyblock_offset_ > image_.size()) || + (keyblock_offset_ > (UINT32_MAX - keyblock_length_)) || + (image_.size() < (keyblock_offset_ + keyblock_length_))) { + RNP_LOG("Wrong keyblock offset/length, blob size: %zu" + ", keyblock offset: %" PRIu32 ", length: %" PRIu32, + image_.size(), + keyblock_offset_, + keyblock_length_); + return false; + } + /* number of key blocks */ + size_t nkeys = ru16(idx); + idx += 2; + if (nkeys < 1) { + RNP_LOG("PGP blob should contains at least 1 key"); + return false; + } + if (nkeys > BLOB_OBJ_LIMIT) { + RNP_LOG("Too many keys in the PGP blob"); + return false; + } + + /* Size of the single key record */ + size_t keys_len = ru16(idx); + idx += 2; + if (keys_len < BLOB_KEY_SIZE) { + RNP_LOG( + "PGP blob needs %d bytes, but contains: %zu bytes", (int) BLOB_KEY_SIZE, keys_len); + return false; + } + + for (size_t i = 0; i < nkeys; i++) { + if (image_.size() - idx < keys_len) { + RNP_LOG("Too few bytes left for key blob"); + return false; + } + + kbx_pgp_key_t nkey = {}; + /* copy fingerprint */ + memcpy(nkey.fp, &image_[idx], 20); + idx += 20; + /* keyid offset */ + nkey.keyid_offset = ru32(idx); + idx += 4; + /* flags */ + nkey.flags = ru16(idx); + idx += 2; + /* RFU */ + idx += 2; + /* skip padding bytes if it existed */ + idx += keys_len - BLOB_KEY_SIZE; + keys_.push_back(std::move(nkey)); + } + + if (image_.size() - idx < 2) { + RNP_LOG("No data for sn_size"); + return false; + } + size_t sn_size = ru16(idx); + idx += 2; + + if (image_.size() - idx < sn_size) { + RNP_LOG("SN is %zu, while bytes left are %zu", sn_size, image_.size() - idx); + return false; + } + + if (sn_size) { + sn_ = {image_.begin() + idx, image_.begin() + idx + sn_size}; + idx += sn_size; + } + + if (image_.size() - idx < 4) { + RNP_LOG("Too few data for uids"); + return false; + } + size_t nuids = ru16(idx); + if (nuids > BLOB_OBJ_LIMIT) { + RNP_LOG("Too many uids in the PGP blob"); + return false; + } + + size_t uids_len = ru16(idx + 2); + idx += 4; + + if (uids_len < BLOB_UID_SIZE) { + RNP_LOG("Too few bytes for uid struct: %zu", uids_len); + return false; + } + + for (size_t i = 0; i < nuids; i++) { + if (image_.size() - idx < uids_len) { + RNP_LOG("Too few bytes to read uid struct."); + return false; + } + kbx_pgp_uid_t nuid = {}; + /* offset */ + nuid.offset = ru32(idx); + idx += 4; + /* length */ + nuid.length = ru32(idx); + idx += 4; + /* flags */ + nuid.flags = ru16(idx); + idx += 2; + /* validity */ + nuid.validity = ru8(idx); + idx++; + /* RFU */ + idx++; + // skip padding bytes if it existed + idx += uids_len - BLOB_UID_SIZE; + + uids_.push_back(std::move(nuid)); + } + + if (image_.size() - idx < 4) { + RNP_LOG("No data left for sigs"); + return false; + } + + size_t nsigs = ru16(idx); + if (nsigs > BLOB_OBJ_LIMIT) { + RNP_LOG("Too many sigs in the PGP blob"); + return false; + } + + size_t sigs_len = ru16(idx + 2); + idx += 4; + + if (sigs_len < BLOB_SIG_SIZE) { + RNP_LOG("Too small SIGN structure: %zu", uids_len); + return false; + } + + for (size_t i = 0; i < nsigs; i++) { + if (image_.size() - idx < sigs_len) { + RNP_LOG("Too few data for sig"); + return false; + } + + kbx_pgp_sig_t nsig = {}; + nsig.expired = ru32(idx); + idx += 4; + + // skip padding bytes if it existed + idx += (sigs_len - BLOB_SIG_SIZE); + + sigs_.push_back(nsig); + } + + if (image_.size() - idx < BLOB_VALIDITY_SIZE) { + RNP_LOG("Too few data for trust/validities"); + return false; + } + + ownertrust_ = ru8(idx); + idx++; + all_validity_ = ru8(idx); + idx++; + // RFU + idx += 2; + recheck_after_ = ru32(idx); + idx += 4; + latest_timestamp_ = ru32(idx); + idx += 4; + blob_created_at_ = ru32(idx); + // do not forget to idx += 4 on further expansion + + // here starts keyblock, UID and reserved space for future usage + + // Maybe we should add checksum verify but GnuPG never checked it + // Checksum is last 20 bytes of blob and it is SHA-1, if it invalid MD5 and starts from 4 + // zero it is MD5. + + return true; +} + +static std::unique_ptr +rnp_key_store_kbx_parse_blob(const uint8_t *image, size_t image_len) +{ + std::unique_ptr blob; + // a blob shouldn't be less of length + type + if (image_len < BLOB_HEADER_SIZE) { + RNP_LOG("Blob size is %zu but it shouldn't be less of header", image_len); + return blob; + } + + try { + std::vector data(image, image + image_len); + kbx_blob_type_t type = (kbx_blob_type_t) image[4]; + + switch (type) { + case KBX_EMPTY_BLOB: + blob = std::unique_ptr(new kbx_blob_t(data)); + break; + case KBX_HEADER_BLOB: + blob = std::unique_ptr(new kbx_header_blob_t(data)); + break; + case KBX_PGP_BLOB: + blob = std::unique_ptr(new kbx_pgp_blob_t(data)); + break; + case KBX_X509_BLOB: + // current we doesn't parse X509 blob, so, keep it as is + blob = std::unique_ptr(new kbx_blob_t(data)); + break; + // unsupported blob type + default: + RNP_LOG("Unsupported blob type: %d", (int) type); + return blob; + } + + if (!blob->parse()) { + return NULL; + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return NULL; + } + return blob; +} + +bool +rnp_key_store_kbx_from_src(rnp_key_store_t * key_store, + pgp_source_t * src, + const pgp_key_provider_t *key_provider) +{ + try { + rnp::MemorySource mem(*src); + size_t has_bytes = mem.size(); + uint8_t * buf = (uint8_t *) mem.memory(); + + while (has_bytes > 4) { + size_t blob_length = read_uint32(buf); + if (blob_length > BLOB_SIZE_LIMIT) { + RNP_LOG("Blob size is %zu bytes but limit is %d bytes", + blob_length, + (int) BLOB_SIZE_LIMIT); + return false; + } + if (blob_length < BLOB_HEADER_SIZE) { + RNP_LOG("Too small blob header size"); + return false; + } + if (has_bytes < blob_length) { + RNP_LOG("Blob have size %zu bytes but file contains only %zu bytes", + blob_length, + has_bytes); + return false; + } + auto blob = rnp_key_store_kbx_parse_blob(buf, blob_length); + if (!blob.get()) { + RNP_LOG("Failed to parse blob"); + return false; + } + kbx_blob_t *pblob = blob.get(); + key_store->blobs.push_back(std::move(blob)); + + if (pblob->type() == KBX_PGP_BLOB) { + // parse keyblock if it existed + kbx_pgp_blob_t &pgp_blob = dynamic_cast(*pblob); + if (!pgp_blob.keyblock_length()) { + RNP_LOG("PGP blob have zero size"); + return false; + } + + rnp::MemorySource blsrc(pgp_blob.image().data() + pgp_blob.keyblock_offset(), + pgp_blob.keyblock_length(), + false); + if (rnp_key_store_pgp_read_from_src(key_store, &blsrc.src())) { + return false; + } + } + + has_bytes -= blob_length; + buf += blob_length; + } + return true; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +static bool +pbuf(pgp_dest_t *dst, const void *buf, size_t len) +{ + dst_write(dst, buf, len); + return dst->werr == RNP_SUCCESS; +} + +static bool +pu8(pgp_dest_t *dst, uint8_t p) +{ + return pbuf(dst, &p, 1); +} + +static bool +pu16(pgp_dest_t *dst, uint16_t f) +{ + uint8_t p[2]; + p[0] = (uint8_t)(f >> 8); + p[1] = (uint8_t) f; + return pbuf(dst, p, 2); +} + +static bool +pu32(pgp_dest_t *dst, uint32_t f) +{ + uint8_t p[4]; + STORE32BE(p, f); + return pbuf(dst, p, 4); +} + +static bool +rnp_key_store_kbx_write_header(rnp_key_store_t *key_store, pgp_dest_t *dst) +{ + uint16_t flags = 0; + uint32_t file_created_at = key_store->secctx.time(); + + if (!key_store->blobs.empty() && (key_store->blobs[0]->type() == KBX_HEADER_BLOB)) { + kbx_header_blob_t &blob = dynamic_cast(*key_store->blobs[0]); + file_created_at = blob.file_created_at(); + } + + return !(!pu32(dst, BLOB_FIRST_SIZE) || !pu8(dst, KBX_HEADER_BLOB) || + !pu8(dst, 1) // version + || !pu16(dst, flags) || !pbuf(dst, "KBXf", 4) || !pu32(dst, 0) // RFU + || !pu32(dst, 0) // RFU + || !pu32(dst, file_created_at) || !pu32(dst, key_store->secctx.time()) || + !pu32(dst, 0)); // RFU +} + +static bool +rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest_t *dst) +{ + rnp::MemoryDest mem(NULL, BLOB_SIZE_LIMIT); + + if (!pu32(&mem.dst(), 0)) { // length, we don't know length of blob yet, so it's 0 + return false; + } + + if (!pu8(&mem.dst(), KBX_PGP_BLOB) || !pu8(&mem.dst(), 1)) { // type, version + return false; + } + + if (!pu16(&mem.dst(), 0)) { // flags, not used by GnuPG + return false; + } + + if (!pu32(&mem.dst(), 0) || + !pu32(&mem.dst(), 0)) { // offset and length of keyblock, update later + return false; + } + + if (!pu16(&mem.dst(), 1 + key->subkey_count())) { // number of keys in keyblock + return false; + } + if (!pu16(&mem.dst(), 28)) { // size of key info structure) + return false; + } + + if (!pbuf(&mem.dst(), key->fp().fingerprint, PGP_FINGERPRINT_SIZE) || + !pu32(&mem.dst(), mem.writeb() - 8) || // offset to keyid (part of fpr for V4) + !pu16(&mem.dst(), 0) || // flags, not used by GnuPG + !pu16(&mem.dst(), 0)) { // RFU + return false; + } + + // same as above, for each subkey + std::vector subkey_sig_expirations; + for (auto &sfp : key->subkey_fps()) { + pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp); + if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, PGP_FINGERPRINT_SIZE) || + !pu32(&mem.dst(), mem.writeb() - 8) || // offset to keyid (part of fpr for V4) + !pu16(&mem.dst(), 0) || // flags, not used by GnuPG + !pu16(&mem.dst(), 0)) { // RFU + return false; + } + // load signature expirations while we're at it + for (size_t i = 0; i < subkey->sig_count(); i++) { + uint32_t expiration = subkey->get_sig(i).sig.key_expiration(); + subkey_sig_expirations.push_back(expiration); + } + } + + if (!pu16(&mem.dst(), 0)) { // Zero size of serial number + return false; + } + + // skip serial number + if (!pu16(&mem.dst(), key->uid_count()) || !pu16(&mem.dst(), 12)) { + return false; + } + + size_t uid_start = mem.writeb(); + for (size_t i = 0; i < key->uid_count(); i++) { + if (!pu32(&mem.dst(), 0) || + !pu32(&mem.dst(), 0)) { // UID offset and length, update when blob has done + return false; + } + + if (!pu16(&mem.dst(), 0)) { // flags, (not yet used) + return false; + } + + if (!pu8(&mem.dst(), 0) || !pu8(&mem.dst(), 0)) { // Validity & RFU + return false; + } + } + + if (!pu16(&mem.dst(), key->sig_count() + subkey_sig_expirations.size()) || + !pu16(&mem.dst(), 4)) { + return false; + } + + for (size_t i = 0; i < key->sig_count(); i++) { + if (!pu32(&mem.dst(), key->get_sig(i).sig.key_expiration())) { + return false; + } + } + for (auto &expiration : subkey_sig_expirations) { + if (!pu32(&mem.dst(), expiration)) { + return false; + } + } + + if (!pu8(&mem.dst(), 0) || + !pu8(&mem.dst(), 0)) { // Assigned ownertrust & All_Validity (not yet used) + return false; + } + + if (!pu16(&mem.dst(), 0) || !pu32(&mem.dst(), 0)) { // RFU & Recheck_after + return false; + } + + if (!pu32(&mem.dst(), key_store->secctx.time()) || + !pu32(&mem.dst(), key_store->secctx.time())) { // Latest timestamp && created + return false; + } + + if (!pu32(&mem.dst(), 0)) { // Size of reserved space + return false; + } + + // wrtite UID, we might redesign PGP write and use this information from keyblob + for (size_t i = 0; i < key->uid_count(); i++) { + const pgp_userid_t &uid = key->get_uid(i); + uint8_t * p = (uint8_t *) mem.memory() + uid_start + (12 * i); + /* store absolute uid offset in the output stream */ + uint32_t pt = mem.writeb() + dst->writeb; + STORE32BE(p, pt); + /* and uid length */ + pt = uid.str.size(); + STORE32BE(p + 4, pt); + /* uid data itself */ + if (!pbuf(&mem.dst(), uid.str.c_str(), pt)) { + return false; + } + } + + /* write keyblock and fix the offset/length */ + size_t key_start = mem.writeb(); + uint32_t pt = key_start; + uint8_t *p = (uint8_t *) mem.memory() + 8; + STORE32BE(p, pt); + + key->write(mem.dst()); + if (mem.werr()) { + return false; + } + + for (auto &sfp : key->subkey_fps()) { + const pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp); + if (!subkey) { + return false; + } + subkey->write(mem.dst()); + if (mem.werr()) { + return false; + } + } + + /* key blob length */ + pt = mem.writeb() - key_start; + p = (uint8_t *) mem.memory() + 12; + STORE32BE(p, pt); + + // fix the length of blob + pt = mem.writeb() + 20; + p = (uint8_t *) mem.memory(); + STORE32BE(p, pt); + + // checksum + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + hash->add(mem.memory(), mem.writeb()); + uint8_t checksum[PGP_SHA1_HASH_SIZE]; + assert(hash->size() == sizeof(checksum)); + hash->finish(checksum); + + if (!(pbuf(&mem.dst(), checksum, PGP_SHA1_HASH_SIZE))) { + return false; + } + + /* finally write to the output */ + dst_write(dst, mem.memory(), mem.writeb()); + return !dst->werr; +} + +static bool +rnp_key_store_kbx_write_x509(rnp_key_store_t *key_store, pgp_dest_t *dst) +{ + for (auto &blob : key_store->blobs) { + if (blob->type() != KBX_X509_BLOB) { + continue; + } + if (!pbuf(dst, blob->image().data(), blob->length())) { + return false; + } + } + return true; +} + +bool +rnp_key_store_kbx_to_dst(rnp_key_store_t *key_store, pgp_dest_t *dst) +{ + try { + if (!rnp_key_store_kbx_write_header(key_store, dst)) { + RNP_LOG("Can't write KBX header"); + return false; + } + + for (auto &key : key_store->keys) { + if (!key.is_primary()) { + continue; + } + if (!rnp_key_store_kbx_write_pgp(key_store, &key, dst)) { + RNP_LOG("Can't write PGP blobs for key %p", &key); + return false; + } + } + + if (!rnp_key_store_kbx_write_x509(key_store, dst)) { + RNP_LOG("Can't write X509 blobs"); + return false; + } + return true; + } catch (const std::exception &e) { + RNP_LOG("Failed to write KBX store: %s", e.what()); + return false; + } +} diff --git a/comm/third_party/rnp/src/librekey/key_store_kbx.h b/comm/third_party/rnp/src/librekey/key_store_kbx.h new file mode 100644 index 0000000000..68d725d4cf --- /dev/null +++ b/comm/third_party/rnp/src/librekey/key_store_kbx.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_KEY_STORE_KBX_H +#define RNP_KEY_STORE_KBX_H + +#include +#include "sec_profile.hpp" + +bool rnp_key_store_kbx_from_src(rnp_key_store_t *, pgp_source_t *, const pgp_key_provider_t *); +bool rnp_key_store_kbx_to_dst(rnp_key_store_t *, pgp_dest_t *); + +#endif // RNP_KEY_STORE_KBX_H diff --git a/comm/third_party/rnp/src/librekey/key_store_pgp.cpp b/comm/third_party/rnp/src/librekey/key_store_pgp.cpp new file mode 100644 index 0000000000..6edc099b2e --- /dev/null +++ b/comm/third_party/rnp/src/librekey/key_store_pgp.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(__NetBSD__) +__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); +__RCSID("$NetBSD: keyring.c,v 1.50 2011/06/25 00:37:44 agc Exp $"); +#endif + +#include +#include + +#include +#include +#include +#include +#include "crypto/mem.h" + +#include "types.h" +#include "key_store_pgp.h" +#include "pgp-key.h" + +bool +rnp_key_store_add_transferable_subkey(rnp_key_store_t * keyring, + pgp_transferable_subkey_t *tskey, + pgp_key_t * pkey) +{ + try { + /* create subkey */ + pgp_key_t skey(*tskey, pkey); + /* add it to the storage */ + return rnp_key_store_add_key(keyring, &skey); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + RNP_LOG_KEY_PKT("failed to create subkey %s", tskey->subkey); + RNP_LOG_KEY("primary key is %s", pkey); + return false; + } +} + +bool +rnp_key_store_add_transferable_key(rnp_key_store_t *keyring, pgp_transferable_key_t *tkey) +{ + pgp_key_t *addkey = NULL; + + /* create key from transferable key */ + try { + pgp_key_t key(*tkey); + /* temporary disable key validation */ + keyring->disable_validation = true; + /* add key to the storage before subkeys */ + addkey = rnp_key_store_add_key(keyring, &key); + } catch (const std::exception &e) { + keyring->disable_validation = false; + RNP_LOG_KEY_PKT("failed to add key %s", tkey->key); + return false; + } + + if (!addkey) { + keyring->disable_validation = false; + RNP_LOG("Failed to add key to key store."); + return false; + } + + /* add subkeys */ + for (auto &subkey : tkey->subkeys) { + if (!rnp_key_store_add_transferable_subkey(keyring, &subkey, addkey)) { + RNP_LOG("Failed to add subkey to key store."); + keyring->disable_validation = false; + goto error; + } + } + + /* now validate/refresh the whole key with subkeys */ + keyring->disable_validation = false; + addkey->revalidate(*keyring); + return true; +error: + /* during key addition all fields are copied so will be cleaned below */ + rnp_key_store_remove_key(keyring, addkey, false); + return false; +} + +rnp_result_t +rnp_key_store_pgp_read_key_from_src(rnp_key_store_t &keyring, + pgp_source_t & src, + bool skiperrors) +{ + pgp_transferable_key_t key; + rnp_result_t ret = process_pgp_key_auto(src, key, true, skiperrors); + + if (ret && (!skiperrors || (ret != RNP_ERROR_BAD_FORMAT))) { + return ret; + } + + /* check whether we have primary key */ + if (key.key.tag != PGP_PKT_RESERVED) { + return rnp_key_store_add_transferable_key(&keyring, &key) ? RNP_SUCCESS : + RNP_ERROR_BAD_STATE; + } + + /* we just skipped some unexpected packets and read nothing */ + if (key.subkeys.empty()) { + return RNP_SUCCESS; + } + + return rnp_key_store_add_transferable_subkey(&keyring, &key.subkeys.front(), NULL) ? + RNP_SUCCESS : + RNP_ERROR_BAD_STATE; +} + +rnp_result_t +rnp_key_store_pgp_read_from_src(rnp_key_store_t *keyring, pgp_source_t *src, bool skiperrors) +{ + /* check whether we have transferable subkey in source */ + if (is_subkey_pkt(stream_pkt_type(*src))) { + pgp_transferable_subkey_t tskey; + rnp_result_t ret = process_pgp_subkey(*src, tskey, skiperrors); + if (ret) { + return ret; + } + return rnp_key_store_add_transferable_subkey(keyring, &tskey, NULL) ? + RNP_SUCCESS : + RNP_ERROR_BAD_STATE; + } + + /* process armored or raw transferable key packets sequence(s) */ + try { + pgp_key_sequence_t keys; + rnp_result_t ret = process_pgp_keys(*src, keys, skiperrors); + if (ret) { + return ret; + } + for (auto &key : keys.keys) { + if (!rnp_key_store_add_transferable_key(keyring, &key)) { + return RNP_ERROR_BAD_STATE; + } + } + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_PARAMETERS; + } +} + +std::vector +rnp_key_to_vec(const pgp_key_t &key) +{ + rnp::MemoryDest dst; + key.write(dst.dst()); + return dst.to_vector(); +} + +static bool +do_write(rnp_key_store_t *key_store, pgp_dest_t *dst, bool secret) +{ + for (auto &key : key_store->keys) { + if (key.is_secret() != secret) { + continue; + } + // skip subkeys, they are written below (orphans are ignored) + if (!key.is_primary()) { + continue; + } + + if (key.format != PGP_KEY_STORE_GPG) { + RNP_LOG("incorrect format (conversions not supported): %d", key.format); + return false; + } + key.write(*dst); + if (dst->werr) { + return false; + } + for (auto &sfp : key.subkey_fps()) { + pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp); + if (!subkey) { + RNP_LOG("Missing subkey"); + continue; + } + subkey->write(*dst); + if (dst->werr) { + return false; + } + } + } + return true; +} + +bool +rnp_key_store_pgp_write_to_dst(rnp_key_store_t *key_store, pgp_dest_t *dst) +{ + // two separate passes (public keys, then secret keys) + return do_write(key_store, dst, false) && do_write(key_store, dst, true); +} diff --git a/comm/third_party/rnp/src/librekey/key_store_pgp.h b/comm/third_party/rnp/src/librekey/key_store_pgp.h new file mode 100644 index 0000000000..d3dcd06250 --- /dev/null +++ b/comm/third_party/rnp/src/librekey/key_store_pgp.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + */ + +#ifndef KEY_STORE_PGP_H_ +#define KEY_STORE_PGP_H_ + +#include +#include +#include + +/* Read the whole keyring from the src, processing all available keys or subkeys */ +rnp_result_t rnp_key_store_pgp_read_from_src(rnp_key_store_t *keyring, + pgp_source_t * src, + bool skiperrors = false); + +/* Read the first key or subkey from the src */ +rnp_result_t rnp_key_store_pgp_read_key_from_src(rnp_key_store_t &keyring, + pgp_source_t & src, + bool skiperrors = false); + +bool rnp_key_store_pgp_write_to_dst(rnp_key_store_t *key_store, pgp_dest_t *dst); + +bool rnp_key_store_add_transferable_subkey(rnp_key_store_t * keyring, + pgp_transferable_subkey_t *tskey, + pgp_key_t * pkey); + +bool rnp_key_store_add_transferable_key(rnp_key_store_t * keyring, + pgp_transferable_key_t *tkey); + +std::vector rnp_key_to_vec(const pgp_key_t &key); + +#endif /* KEY_STORE_PGP_H_ */ diff --git a/comm/third_party/rnp/src/librekey/rnp_key_store.cpp b/comm/third_party/rnp/src/librekey/rnp_key_store.cpp new file mode 100644 index 0000000000..002a51e7cc --- /dev/null +++ b/comm/third_party/rnp/src/librekey/rnp_key_store.cpp @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2017-2022 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#ifdef HAVE_SYS_PARAM_H +#include +#else +#include "uniwin.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "key_store_pgp.h" +#include "key_store_kbx.h" +#include "key_store_g10.h" +#include "kbx_blob.hpp" + +#include "pgp-key.h" +#include "fingerprint.h" +#include "crypto/hash.hpp" +#include "crypto/mem.h" +#include "file-utils.h" +#ifdef _WIN32 +#include "str-utils.h" +#endif + +bool +rnp_key_store_load_from_path(rnp_key_store_t * key_store, + const pgp_key_provider_t *key_provider) +{ + pgp_source_t src = {}; + + if (key_store->format == PGP_KEY_STORE_G10) { + auto dir = rnp_opendir(key_store->path.c_str()); + if (!dir) { + RNP_LOG( + "Can't open G10 directory %s: %s", key_store->path.c_str(), strerror(errno)); + return false; + } + + std::string dirname; + while (!((dirname = rnp_readdir_name(dir)).empty())) { + std::string path = rnp::path::append(key_store->path, dirname); + + if (init_file_src(&src, path.c_str())) { + RNP_LOG("failed to read file %s", path.c_str()); + continue; + } + // G10 may fail to read one file, so ignore it! + if (!rnp_key_store_g10_from_src(key_store, &src, key_provider)) { + RNP_LOG("Can't parse file: %s", path.c_str()); // TODO: %S ? + } + src_close(&src); + } + rnp_closedir(dir); + return true; + } + + /* init file source and load from it */ + if (init_file_src(&src, key_store->path.c_str())) { + RNP_LOG("failed to read file %s", key_store->path.c_str()); + return false; + } + + bool rc = rnp_key_store_load_from_src(key_store, &src, key_provider); + src_close(&src); + return rc; +} + +bool +rnp_key_store_load_from_src(rnp_key_store_t * key_store, + pgp_source_t * src, + const pgp_key_provider_t *key_provider) +{ + switch (key_store->format) { + case PGP_KEY_STORE_GPG: + return rnp_key_store_pgp_read_from_src(key_store, src) == RNP_SUCCESS; + case PGP_KEY_STORE_KBX: + return rnp_key_store_kbx_from_src(key_store, src, key_provider); + case PGP_KEY_STORE_G10: + return rnp_key_store_g10_from_src(key_store, src, key_provider); + default: + RNP_LOG("Unsupported load from memory for key-store format: %d", key_store->format); + } + + return false; +} + +bool +rnp_key_store_write_to_path(rnp_key_store_t *key_store) +{ + bool rc; + pgp_dest_t keydst = {}; + + /* write g10 key store to the directory */ + if (key_store->format == PGP_KEY_STORE_G10) { + char path[MAXPATHLEN]; + + struct stat path_stat; + if (rnp_stat(key_store->path.c_str(), &path_stat) != -1) { + if (!S_ISDIR(path_stat.st_mode)) { + RNP_LOG("G10 keystore should be a directory: %s", key_store->path.c_str()); + return false; + } + } else { + if (errno != ENOENT) { + RNP_LOG("stat(%s): %s", key_store->path.c_str(), strerror(errno)); + return false; + } + if (RNP_MKDIR(key_store->path.c_str(), S_IRWXU) != 0) { + RNP_LOG("mkdir(%s, S_IRWXU): %s", key_store->path.c_str(), strerror(errno)); + return false; + } + } + + for (auto &key : key_store->keys) { + char grip[PGP_FINGERPRINT_HEX_SIZE] = {0}; + rnp::hex_encode(key.grip().data(), key.grip().size(), grip, sizeof(grip)); + snprintf(path, sizeof(path), "%s/%s.key", key_store->path.c_str(), grip); + + if (init_tmpfile_dest(&keydst, path, true)) { + RNP_LOG("failed to create file"); + return false; + } + + if (!rnp_key_store_gnupg_sexp_to_dst(&key, &keydst)) { + RNP_LOG("failed to write key to file"); + dst_close(&keydst, true); + return false; + } + + rc = dst_finish(&keydst) == RNP_SUCCESS; + dst_close(&keydst, !rc); + + if (!rc) { + return false; + } + } + + return true; + } + + /* write kbx/gpg store to the single file */ + if (init_tmpfile_dest(&keydst, key_store->path.c_str(), true)) { + RNP_LOG("failed to create keystore file"); + return false; + } + + if (!rnp_key_store_write_to_dst(key_store, &keydst)) { + RNP_LOG("failed to write keys to file"); + dst_close(&keydst, true); + return false; + } + + rc = dst_finish(&keydst) == RNP_SUCCESS; + dst_close(&keydst, !rc); + return rc; +} + +bool +rnp_key_store_write_to_dst(rnp_key_store_t *key_store, pgp_dest_t *dst) +{ + switch (key_store->format) { + case PGP_KEY_STORE_GPG: + return rnp_key_store_pgp_write_to_dst(key_store, dst); + case PGP_KEY_STORE_KBX: + return rnp_key_store_kbx_to_dst(key_store, dst); + default: + RNP_LOG("Unsupported write to memory for key-store format: %d", key_store->format); + } + + return false; +} + +void +rnp_key_store_clear(rnp_key_store_t *keyring) +{ + keyring->keybyfp.clear(); + keyring->keys.clear(); + keyring->blobs.clear(); +} + +size_t +rnp_key_store_get_key_count(const rnp_key_store_t *keyring) +{ + return keyring->keys.size(); +} + +static bool +rnp_key_store_refresh_subkey_grips(rnp_key_store_t *keyring, pgp_key_t *key) +{ + if (key->is_subkey()) { + RNP_LOG("wrong argument"); + return false; + } + + for (auto &skey : keyring->keys) { + bool found = false; + + /* if we have primary_grip then we also added to subkey_grips */ + if (!skey.is_subkey() || skey.has_primary_fp()) { + continue; + } + + for (size_t i = 0; i < skey.sig_count(); i++) { + const pgp_subsig_t &subsig = skey.get_sig(i); + + if (subsig.sig.type() != PGP_SIG_SUBKEY) { + continue; + } + if (subsig.sig.has_keyfp() && (key->fp() == subsig.sig.keyfp())) { + found = true; + break; + } + if (subsig.sig.has_keyid() && (key->keyid() == subsig.sig.keyid())) { + found = true; + break; + } + } + + if (found) { + try { + key->link_subkey_fp(skey); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + } + } + + return true; +} + +static pgp_key_t * +rnp_key_store_add_subkey(rnp_key_store_t *keyring, pgp_key_t *srckey, pgp_key_t *oldkey) +{ + pgp_key_t *primary = NULL; + if (oldkey) { + primary = rnp_key_store_get_primary_key(keyring, oldkey); + } + if (!primary) { + primary = rnp_key_store_get_primary_key(keyring, srckey); + } + + if (oldkey) { + /* check for the weird case when same subkey has different primary keys */ + if (srckey->has_primary_fp() && oldkey->has_primary_fp() && + (srckey->primary_fp() != oldkey->primary_fp())) { + RNP_LOG_KEY("Warning: different primary keys for subkey %s", srckey); + pgp_key_t *srcprim = rnp_key_store_get_key_by_fpr(keyring, srckey->primary_fp()); + if (srcprim && (srcprim != primary)) { + srcprim->remove_subkey_fp(srckey->fp()); + } + } + /* in case we already have key let's merge it in */ + if (!oldkey->merge(*srckey, primary)) { + RNP_LOG_KEY("failed to merge subkey %s", srckey); + RNP_LOG_KEY("primary key is %s", primary); + return NULL; + } + } else { + try { + keyring->keys.emplace_back(); + oldkey = &keyring->keys.back(); + keyring->keybyfp[srckey->fp()] = std::prev(keyring->keys.end()); + *oldkey = pgp_key_t(*srckey); + if (primary) { + primary->link_subkey_fp(*oldkey); + } + } catch (const std::exception &e) { + RNP_LOG_KEY("key %s copying failed", srckey); + RNP_LOG_KEY("primary key is %s", primary); + RNP_LOG("%s", e.what()); + if (oldkey) { + keyring->keys.pop_back(); + keyring->keybyfp.erase(srckey->fp()); + } + return NULL; + } + } + + /* validate all added keys if not disabled */ + if (!keyring->disable_validation && !oldkey->validated()) { + oldkey->validate_subkey(primary, keyring->secctx); + } + if (!oldkey->refresh_data(primary, keyring->secctx)) { + RNP_LOG_KEY("Failed to refresh subkey %s data", srckey); + RNP_LOG_KEY("primary key is %s", primary); + } + return oldkey; +} + +/* add a key to keyring */ +pgp_key_t * +rnp_key_store_add_key(rnp_key_store_t *keyring, pgp_key_t *srckey) +{ + assert(srckey->type() && srckey->version()); + pgp_key_t *added_key = rnp_key_store_get_key_by_fpr(keyring, srckey->fp()); + /* we cannot merge G10 keys - so just return it */ + if (added_key && (srckey->format == PGP_KEY_STORE_G10)) { + return added_key; + } + /* different processing for subkeys */ + if (srckey->is_subkey()) { + return rnp_key_store_add_subkey(keyring, srckey, added_key); + } + + if (added_key) { + if (!added_key->merge(*srckey)) { + RNP_LOG_KEY("failed to merge key %s", srckey); + return NULL; + } + } else { + try { + keyring->keys.emplace_back(); + added_key = &keyring->keys.back(); + keyring->keybyfp[srckey->fp()] = std::prev(keyring->keys.end()); + *added_key = pgp_key_t(*srckey); + /* primary key may be added after subkeys, so let's handle this case correctly */ + if (!rnp_key_store_refresh_subkey_grips(keyring, added_key)) { + RNP_LOG_KEY("failed to refresh subkey grips for %s", added_key); + } + } catch (const std::exception &e) { + RNP_LOG_KEY("key %s copying failed", srckey); + RNP_LOG("%s", e.what()); + if (added_key) { + keyring->keys.pop_back(); + keyring->keybyfp.erase(srckey->fp()); + } + return NULL; + } + } + + /* validate all added keys if not disabled or already validated */ + if (!keyring->disable_validation && !added_key->validated()) { + added_key->revalidate(*keyring); + } else if (!added_key->refresh_data(keyring->secctx)) { + RNP_LOG_KEY("Failed to refresh key %s data", srckey); + } + return added_key; +} + +pgp_key_t * +rnp_key_store_import_key(rnp_key_store_t * keyring, + pgp_key_t * srckey, + bool pubkey, + pgp_key_import_status_t *status) +{ + /* add public key */ + pgp_key_t *exkey = rnp_key_store_get_key_by_fpr(keyring, srckey->fp()); + size_t expackets = exkey ? exkey->rawpkt_count() : 0; + try { + pgp_key_t keycp(*srckey, pubkey); + keyring->disable_validation = true; + exkey = rnp_key_store_add_key(keyring, &keycp); + keyring->disable_validation = false; + if (!exkey) { + RNP_LOG("failed to add key to the keyring"); + return NULL; + } + bool changed = exkey->rawpkt_count() > expackets; + if (changed || !exkey->validated()) { + /* this will revalidated primary key with all subkeys */ + exkey->revalidate(*keyring); + } + if (status) { + *status = changed ? (expackets ? PGP_KEY_IMPORT_STATUS_UPDATED : + PGP_KEY_IMPORT_STATUS_NEW) : + PGP_KEY_IMPORT_STATUS_UNCHANGED; + } + return exkey; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + keyring->disable_validation = false; + return NULL; + } +} + +pgp_key_t * +rnp_key_store_get_signer_key(rnp_key_store_t *store, const pgp_signature_t *sig) +{ + pgp_key_search_t search; + // prefer using the issuer fingerprint when available + if (sig->has_keyfp()) { + search.by.fingerprint = sig->keyfp(); + search.type = PGP_KEY_SEARCH_FINGERPRINT; + return rnp_key_store_search(store, &search, NULL); + } + // fall back to key id search + if (sig->has_keyid()) { + search.by.keyid = sig->keyid(); + search.type = PGP_KEY_SEARCH_KEYID; + return rnp_key_store_search(store, &search, NULL); + } + return NULL; +} + +static pgp_sig_import_status_t +rnp_key_store_import_subkey_signature(rnp_key_store_t * keyring, + pgp_key_t * key, + const pgp_signature_t *sig) +{ + if ((sig->type() != PGP_SIG_SUBKEY) && (sig->type() != PGP_SIG_REV_SUBKEY)) { + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + pgp_key_t *primary = rnp_key_store_get_signer_key(keyring, sig); + if (!primary || !key->has_primary_fp()) { + RNP_LOG("No primary grip or primary key"); + return PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY; + } + if (primary->fp() != key->primary_fp()) { + RNP_LOG("Wrong subkey signature's signer."); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + + try { + pgp_key_t tmpkey(key->pkt()); + tmpkey.add_sig(*sig); + if (!tmpkey.refresh_data(primary, keyring->secctx)) { + RNP_LOG("Failed to add signature to the key."); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + + size_t expackets = key->rawpkt_count(); + key = rnp_key_store_add_key(keyring, &tmpkey); + if (!key) { + RNP_LOG("Failed to add key with imported sig to the keyring"); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + return (key->rawpkt_count() > expackets) ? PGP_SIG_IMPORT_STATUS_NEW : + PGP_SIG_IMPORT_STATUS_UNCHANGED; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } +} + +pgp_sig_import_status_t +rnp_key_store_import_key_signature(rnp_key_store_t * keyring, + pgp_key_t * key, + const pgp_signature_t *sig) +{ + if (key->is_subkey()) { + return rnp_key_store_import_subkey_signature(keyring, key, sig); + } + if ((sig->type() != PGP_SIG_DIRECT) && (sig->type() != PGP_SIG_REV_KEY)) { + RNP_LOG("Wrong signature type: %d", (int) sig->type()); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + + try { + pgp_key_t tmpkey(key->pkt()); + tmpkey.add_sig(*sig); + if (!tmpkey.refresh_data(keyring->secctx)) { + RNP_LOG("Failed to add signature to the key."); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + + size_t expackets = key->rawpkt_count(); + key = rnp_key_store_add_key(keyring, &tmpkey); + if (!key) { + RNP_LOG("Failed to add key with imported sig to the keyring"); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } + return (key->rawpkt_count() > expackets) ? PGP_SIG_IMPORT_STATUS_NEW : + PGP_SIG_IMPORT_STATUS_UNCHANGED; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return PGP_SIG_IMPORT_STATUS_UNKNOWN; + } +} + +pgp_key_t * +rnp_key_store_import_signature(rnp_key_store_t * keyring, + const pgp_signature_t * sig, + pgp_sig_import_status_t *status) +{ + pgp_sig_import_status_t tmp_status = PGP_SIG_IMPORT_STATUS_UNKNOWN; + if (!status) { + status = &tmp_status; + } + *status = PGP_SIG_IMPORT_STATUS_UNKNOWN; + + /* we support only direct-key and key revocation signatures here */ + if ((sig->type() != PGP_SIG_DIRECT) && (sig->type() != PGP_SIG_REV_KEY)) { + return NULL; + } + + pgp_key_t *res_key = rnp_key_store_get_signer_key(keyring, sig); + if (!res_key || !res_key->is_primary()) { + *status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY; + return NULL; + } + *status = rnp_key_store_import_key_signature(keyring, res_key, sig); + return res_key; +} + +bool +rnp_key_store_remove_key(rnp_key_store_t *keyring, const pgp_key_t *key, bool subkeys) +{ + auto it = keyring->keybyfp.find(key->fp()); + if (it == keyring->keybyfp.end()) { + return false; + } + + /* cleanup primary_grip (or subkey)/subkey_grips */ + if (key->is_primary() && key->subkey_count()) { + for (size_t i = 0; i < key->subkey_count(); i++) { + auto it = keyring->keybyfp.find(key->get_subkey_fp(i)); + if (it == keyring->keybyfp.end()) { + continue; + } + /* if subkeys are deleted then no need to update grips */ + if (subkeys) { + keyring->keys.erase(it->second); + keyring->keybyfp.erase(it); + continue; + } + it->second->unset_primary_fp(); + } + } + if (key->is_subkey() && key->has_primary_fp()) { + pgp_key_t *primary = rnp_key_store_get_primary_key(keyring, key); + if (primary) { + primary->remove_subkey_fp(key->fp()); + } + } + + keyring->keys.erase(it->second); + keyring->keybyfp.erase(it); + return true; +} + +const pgp_key_t * +rnp_key_store_get_key_by_fpr(const rnp_key_store_t *keyring, const pgp_fingerprint_t &fpr) +{ + auto it = keyring->keybyfp.find(fpr); + if (it == keyring->keybyfp.end()) { + return NULL; + } + return &*it->second; +} + +pgp_key_t * +rnp_key_store_get_key_by_fpr(rnp_key_store_t *keyring, const pgp_fingerprint_t &fpr) +{ + auto it = keyring->keybyfp.find(fpr); + if (it == keyring->keybyfp.end()) { + return NULL; + } + return &*it->second; +} + +pgp_key_t * +rnp_key_store_get_primary_key(rnp_key_store_t *keyring, const pgp_key_t *subkey) +{ + if (!subkey->is_subkey()) { + return NULL; + } + + if (subkey->has_primary_fp()) { + pgp_key_t *primary = rnp_key_store_get_key_by_fpr(keyring, subkey->primary_fp()); + return primary && primary->is_primary() ? primary : NULL; + } + + for (size_t i = 0; i < subkey->sig_count(); i++) { + const pgp_subsig_t &subsig = subkey->get_sig(i); + if (subsig.sig.type() != PGP_SIG_SUBKEY) { + continue; + } + + pgp_key_t *primary = rnp_key_store_get_signer_key(keyring, &subsig.sig); + if (primary && primary->is_primary()) { + return primary; + } + } + return NULL; +} + +static void +grip_hash_mpi(rnp::Hash &hash, const pgp_mpi_t &val, const char name, bool lzero = true) +{ + size_t len = mpi_bytes(&val); + size_t idx = 0; + for (idx = 0; (idx < len) && !val.mpi[idx]; idx++) + ; + + if (name) { + size_t hlen = idx >= len ? 0 : len - idx; + if ((len > idx) && lzero && (val.mpi[idx] & 0x80)) { + hlen++; + } + + char buf[20] = {0}; + snprintf(buf, sizeof(buf), "(1:%c%zu:", name, hlen); + hash.add(buf, strlen(buf)); + } + + if (idx < len) { + /* gcrypt prepends mpis with zero if higher bit is set */ + if (lzero && (val.mpi[idx] & 0x80)) { + uint8_t zero = 0; + hash.add(&zero, 1); + } + hash.add(val.mpi + idx, len - idx); + } + if (name) { + hash.add(")", 1); + } +} + +static void +grip_hash_ecc_hex(rnp::Hash &hash, const char *hex, char name) +{ + pgp_mpi_t mpi = {}; + mpi.len = rnp::hex_decode(hex, mpi.mpi, sizeof(mpi.mpi)); + if (!mpi.len) { + RNP_LOG("wrong hex mpi"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + /* libgcrypt doesn't add leading zero when hashes ecc mpis */ + return grip_hash_mpi(hash, mpi, name, false); +} + +static void +grip_hash_ec(rnp::Hash &hash, const pgp_ec_key_t &key) +{ + const ec_curve_desc_t *desc = get_curve_desc(key.curve); + if (!desc) { + RNP_LOG("unknown curve %d", (int) key.curve); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + /* build uncompressed point from gx and gy */ + pgp_mpi_t g = {}; + g.mpi[0] = 0x04; + g.len = 1; + size_t len = rnp::hex_decode(desc->gx, g.mpi + g.len, sizeof(g.mpi) - g.len); + if (!len) { + RNP_LOG("wrong x mpi"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + g.len += len; + len = rnp::hex_decode(desc->gy, g.mpi + g.len, sizeof(g.mpi) - g.len); + if (!len) { + RNP_LOG("wrong y mpi"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + g.len += len; + + /* p, a, b, g, n, q */ + grip_hash_ecc_hex(hash, desc->p, 'p'); + grip_hash_ecc_hex(hash, desc->a, 'a'); + grip_hash_ecc_hex(hash, desc->b, 'b'); + grip_hash_mpi(hash, g, 'g', false); + grip_hash_ecc_hex(hash, desc->n, 'n'); + + if ((key.curve == PGP_CURVE_ED25519) || (key.curve == PGP_CURVE_25519)) { + if (g.len < 1) { + RNP_LOG("wrong 25519 p"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + g.len = key.p.len - 1; + memcpy(g.mpi, key.p.mpi + 1, g.len); + grip_hash_mpi(hash, g, 'q', false); + } else { + grip_hash_mpi(hash, key.p, 'q', false); + } +} + +/* keygrip is subjectKeyHash from pkcs#15 for RSA. */ +bool +rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) +{ + try { + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + switch (key->alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_SIGN_ONLY: + case PGP_PKA_RSA_ENCRYPT_ONLY: + grip_hash_mpi(*hash, key->rsa.n, '\0'); + break; + case PGP_PKA_DSA: + grip_hash_mpi(*hash, key->dsa.p, 'p'); + grip_hash_mpi(*hash, key->dsa.q, 'q'); + grip_hash_mpi(*hash, key->dsa.g, 'g'); + grip_hash_mpi(*hash, key->dsa.y, 'y'); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + grip_hash_mpi(*hash, key->eg.p, 'p'); + grip_hash_mpi(*hash, key->eg.g, 'g'); + grip_hash_mpi(*hash, key->eg.y, 'y'); + break; + case PGP_PKA_ECDH: + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + grip_hash_ec(*hash, key->ec); + break; + default: + RNP_LOG("unsupported public-key algorithm %d", (int) key->alg); + return false; + } + return hash->finish(grip.data()) == grip.size(); + } catch (const std::exception &e) { + RNP_LOG("Grip calculation failed: %s", e.what()); + return false; + } +} + +pgp_key_t * +rnp_key_store_search(rnp_key_store_t * keyring, + const pgp_key_search_t *search, + pgp_key_t * after) +{ + // since keys are distinguished by fingerprint then just do map lookup + if (search->type == PGP_KEY_SEARCH_FINGERPRINT) { + pgp_key_t *key = rnp_key_store_get_key_by_fpr(keyring, search->by.fingerprint); + if (after && (after != key)) { + RNP_LOG("searching with invalid after param"); + return NULL; + } + // return NULL if after is specified + return after ? NULL : key; + } + + // if after is provided, make sure it is a member of the appropriate list + auto it = + std::find_if(keyring->keys.begin(), keyring->keys.end(), [after](const pgp_key_t &key) { + return !after || (after == &key); + }); + if (after && (it == keyring->keys.end())) { + RNP_LOG("searching with non-keyrings after param"); + return NULL; + } + if (after) { + it = std::next(it); + } + it = std::find_if(it, keyring->keys.end(), [search](const pgp_key_t &key) { + return rnp_key_matches_search(&key, search); + }); + return (it == keyring->keys.end()) ? NULL : &(*it); +} + +rnp_key_store_t::rnp_key_store_t(pgp_key_store_format_t _format, + const std::string & _path, + rnp::SecurityContext & ctx) + : secctx(ctx) +{ + if (_format == PGP_KEY_STORE_UNKNOWN) { + RNP_LOG("Invalid key store format"); + throw std::invalid_argument("format"); + } + format = _format; + path = _path; +} + +rnp_key_store_t::~rnp_key_store_t() +{ + rnp_key_store_clear(this); +} diff --git a/comm/third_party/rnp/src/librepgp/stream-armor.cpp b/comm/third_party/rnp/src/librepgp/stream-armor.cpp new file mode 100644 index 0000000000..669c3057c3 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-armor.cpp @@ -0,0 +1,1287 @@ +/* + * Copyright (c) 2017-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#ifdef HAVE_UNISTD_H +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include "stream-def.h" +#include "stream-armor.h" +#include "stream-packet.h" +#include "str-utils.h" +#include "crypto/hash.hpp" +#include "utils.h" + +#define ARMORED_BLOCK_SIZE (4096) +#define ARMORED_PEEK_BUF_SIZE 1024 +#define ARMORED_MIN_LINE_LENGTH (16) +#define ARMORED_MAX_LINE_LENGTH (76) + +typedef struct pgp_source_armored_param_t { + pgp_source_t * readsrc; /* source to read from */ + pgp_armored_msg_t type; /* type of the message */ + char * armorhdr; /* armor header */ + char * version; /* Version: header if any */ + char * comment; /* Comment: header if any */ + char * hash; /* Hash: header if any */ + char * charset; /* Charset: header if any */ + uint8_t rest[ARMORED_BLOCK_SIZE]; /* unread decoded bytes, makes implementation easier */ + unsigned restlen; /* number of bytes in rest */ + unsigned restpos; /* index of first unread byte in rest, restpos <= restlen */ + uint8_t brest[3]; /* decoded 6-bit tail bytes */ + unsigned brestlen; /* number of bytes in brest */ + bool eofb64; /* end of base64 stream reached */ + uint8_t readcrc[3]; /* crc-24 from the armored data */ + bool has_crc; /* message contains CRC line */ + std::unique_ptr crc_ctx; /* CTX used to calculate CRC */ + bool noheaders; /* only base64 data, no headers */ +} pgp_source_armored_param_t; + +typedef struct pgp_dest_armored_param_t { + pgp_dest_t * writedst; + pgp_armored_msg_t type; /* type of the message */ + char eol[2]; /* end of line, all non-zeroes are written */ + unsigned lout; /* chars written in current line */ + unsigned llen; /* length of the base64 line, defaults to 76 as per RFC */ + uint8_t tail[2]; /* bytes which didn't fit into 3-byte boundary */ + unsigned tailc; /* number of bytes in tail */ + std::unique_ptr crc_ctx; /* CTX used to calculate CRC */ +} pgp_dest_armored_param_t; + +/* + Table for base64 lookups: + 0xff - wrong character, + 0xfe - '=' + 0xfd - eol/whitespace, + 0..0x3f - represented 6-bit number +*/ +static const uint8_t B64DEC[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xff, 0xff, 0xfd, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, + 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, + 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff}; + +static bool +armor_read_padding(pgp_source_armored_param_t *param, size_t *read) +{ + char st[64]; + size_t stlen = 0; + + if (!src_peek_line(param->readsrc, st, 64, &stlen)) { + return false; + } + + if ((stlen == 1) || (stlen == 2)) { + if ((st[0] != CH_EQ) || ((stlen == 2) && (st[1] != CH_EQ))) { + return false; + } + + *read = stlen; + src_skip(param->readsrc, stlen); + return src_skip_eol(param->readsrc); + } else if (stlen == 5) { + *read = 0; + return true; + } else if ((stlen > 5) && !memcmp(st, ST_DASHES, 5)) { + /* case with absent crc and 3-byte last chunk */ + *read = 0; + return true; + } + return false; +} + +static bool +base64_read_padding(pgp_source_armored_param_t *param, size_t *read) +{ + char pad[16]; + size_t padlen = sizeof(pad); + + /* we would allow arbitrary number of whitespaces/eols after the padding */ + if (!src_read(param->readsrc, pad, padlen, &padlen)) { + return false; + } + /* strip trailing whitespaces */ + while (padlen && (B64DEC[(int) pad[padlen - 1]] == 0xfd)) { + padlen--; + } + /* check for '=' */ + for (size_t i = 0; i < padlen; i++) { + if (pad[i] != CH_EQ) { + RNP_LOG("wrong base64 padding: %.*s", (int) padlen, pad); + return false; + } + } + if (padlen > 2) { + RNP_LOG("wrong base64 padding length %zu.", padlen); + return false; + } + if (!src_eof(param->readsrc)) { + RNP_LOG("warning: extra data after the base64 stream."); + } + *read = padlen; + return true; +} + +static bool +armor_read_crc(pgp_source_t *src) +{ + uint8_t dec[4] = {0}; + char crc[8] = {0}; + size_t clen = 0; + pgp_source_armored_param_t *param = (pgp_source_armored_param_t *) src->param; + + if (!src_peek_line(param->readsrc, crc, sizeof(crc), &clen)) { + return false; + } + + if ((clen != 5) || (crc[0] != CH_EQ)) { + return false; + } + + for (int i = 0; i < 4; i++) { + if ((dec[i] = B64DEC[(uint8_t) crc[i + 1]]) >= 64) { + return false; + } + } + + param->readcrc[0] = (dec[0] << 2) | ((dec[1] >> 4) & 0x0F); + param->readcrc[1] = (dec[1] << 4) | ((dec[2] >> 2) & 0x0F); + param->readcrc[2] = (dec[2] << 6) | dec[3]; + + param->has_crc = true; + + src_skip(param->readsrc, 5); + return src_skip_eol(param->readsrc); +} + +static bool +armor_skip_chars(pgp_source_t *src, const char *chars) +{ + uint8_t ch; + size_t read; + + do { + bool found = false; + if (!src_peek(src, &ch, 1, &read)) { + return false; + } + if (!read) { + /* return true only if there is no underlying read error */ + return true; + } + for (const char *chptr = chars; *chptr; chptr++) { + if (ch == *chptr) { + src_skip(src, 1); + found = true; + break; + } + } + if (!found) { + break; + } + } while (1); + + return true; +} + +static bool +armor_read_trailer(pgp_source_t *src) +{ + char st[64]; + char str[64]; + size_t stlen; + pgp_source_armored_param_t *param = (pgp_source_armored_param_t *) src->param; + + if (!armor_skip_chars(param->readsrc, "\r\n")) { + return false; + } + + stlen = strlen(param->armorhdr); + if ((stlen > 5) && (stlen + 8 + 1 <= sizeof(st))) { + memcpy(st, ST_ARMOR_END, 8); /* 8 here is mandatory */ + memcpy(st + 8, param->armorhdr + 5, stlen - 5); + memcpy(st + stlen + 3, ST_DASHES, 5); + stlen += 8; + } else { + RNP_LOG("Internal error"); + return false; + } + if (!src_peek_eq(param->readsrc, str, stlen) || strncmp(str, st, stlen)) { + return false; + } + src_skip(param->readsrc, stlen); + (void) armor_skip_chars(param->readsrc, "\t "); + (void) src_skip_eol(param->readsrc); + return true; +} + +static bool +armored_update_crc(pgp_source_armored_param_t *param, + const void * buf, + size_t len, + bool finish = false) +{ + if (param->noheaders) { + return true; + } + try { + param->crc_ctx->add(buf, len); + if (!finish) { + return true; + } + auto crc = param->crc_ctx->finish(); + if (param->has_crc && memcmp(param->readcrc, crc.data(), 3)) { + RNP_LOG("Warning: CRC mismatch"); + } + return true; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } +} + +static bool +armored_src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + pgp_source_armored_param_t *param = (pgp_source_armored_param_t *) src->param; + uint8_t b64buf[ARMORED_BLOCK_SIZE]; /* input base64 data with spaces and so on */ + uint8_t decbuf[ARMORED_BLOCK_SIZE + 4]; /* decoded 6-bit values */ + uint8_t *bufptr = (uint8_t *) buf; /* for better readability below */ + uint8_t *bptr, *bend; /* pointer to input data in b64buf */ + uint8_t *dptr, *dend, *pend; /* pointers to decoded data in decbuf: working pointer, last + available byte, last byte to process */ + uint8_t bval; + uint32_t b24; + size_t read = 0; + size_t left = len; + size_t eqcount = 0; /* number of '=' at the end of base64 stream */ + + if (!param) { + return false; + } + + /* checking whether there are some decoded bytes */ + if (param->restpos < param->restlen) { + if (param->restlen - param->restpos >= len) { + memcpy(bufptr, ¶m->rest[param->restpos], len); + param->restpos += len; + try { + param->crc_ctx->add(bufptr, len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + *readres = len; + return true; + } else { + left = len - (param->restlen - param->restpos); + memcpy(bufptr, ¶m->rest[param->restpos], len - left); + param->restpos = param->restlen = 0; + bufptr += len - left; + } + } + + if (param->eofb64) { + *readres = len - left; + return true; + } + + memcpy(decbuf, param->brest, param->brestlen); + dend = decbuf + param->brestlen; + + do { + if (!src_peek(param->readsrc, b64buf, sizeof(b64buf), &read)) { + return false; + } + if (!read) { + RNP_LOG("premature end of armored input"); + return false; + } + + dptr = dend; + bptr = b64buf; + bend = b64buf + read; + /* checking input data, stripping away whitespaces, checking for end of the b64 data */ + while (bptr < bend) { + if ((bval = B64DEC[*(bptr++)]) < 64) { + *(dptr++) = bval; + } else if (bval == 0xfe) { + /* '=' means the base64 padding or the beginning of checksum */ + param->eofb64 = true; + break; + } else if (bval == 0xff) { + auto ch = *(bptr - 1); + /* OpenPGP message headers without the crc and without trailing = */ + if ((ch == CH_DASH) && !param->noheaders) { + param->eofb64 = true; + break; + } + RNP_LOG("wrong base64 character 0x%02hhX", ch); + return false; + } + } + + dend = dptr; + dptr = decbuf; + /* Processing full 4s which will go directly to the buf. + After this left < 3 or decbuf has < 4 bytes */ + if ((size_t)(dend - dptr) / 4 * 3 < left) { + pend = decbuf + (dend - dptr) / 4 * 4; + left -= (dend - dptr) / 4 * 3; + } else { + pend = decbuf + (left / 3) * 4; + left -= left / 3 * 3; + } + + /* this one would the most performance-consuming part for large chunks */ + while (dptr < pend) { + b24 = *dptr++ << 18; + b24 |= *dptr++ << 12; + b24 |= *dptr++ << 6; + b24 |= *dptr++; + *bufptr++ = b24 >> 16; + *bufptr++ = b24 >> 8; + *bufptr++ = b24 & 0xff; + } + + /* moving rest to the beginning of decbuf */ + memmove(decbuf, dptr, dend - dptr); + dend = decbuf + (dend - dptr); + + /* skip already processed data */ + if (!param->eofb64) { + /* all input is base64 data or eol/spaces, so skipping it */ + src_skip(param->readsrc, read); + /* check for eof for base64-encoded data without headers */ + if (param->noheaders && src_eof(param->readsrc)) { + src_skip(param->readsrc, read); + param->eofb64 = true; + } else { + continue; + } + } else { + /* '=' reached, bptr points on it */ + src_skip(param->readsrc, bptr - b64buf - 1); + } + + /* end of base64 data */ + if (param->noheaders) { + if (!base64_read_padding(param, &eqcount)) { + return false; + } + break; + } + /* reading b64 padding if any */ + if (!armor_read_padding(param, &eqcount)) { + RNP_LOG("wrong padding"); + return false; + } + /* reading crc */ + if (!armor_read_crc(src)) { + RNP_LOG("Warning: missing or malformed CRC line"); + } + /* reading armor trailing line */ + if (!armor_read_trailer(src)) { + RNP_LOG("wrong armor trailer"); + return false; + } + break; + } while (left >= 3); + + /* process bytes left in decbuf */ + + dptr = decbuf; + pend = decbuf + (dend - decbuf) / 4 * 4; + bptr = param->rest; + while (dptr < pend) { + b24 = *dptr++ << 18; + b24 |= *dptr++ << 12; + b24 |= *dptr++ << 6; + b24 |= *dptr++; + *bptr++ = b24 >> 16; + *bptr++ = b24 >> 8; + *bptr++ = b24 & 0xff; + } + + if (!armored_update_crc(param, buf, bufptr - (uint8_t *) buf)) { + return false; + } + + if (param->eofb64) { + if ((dend - dptr + eqcount) % 4 != 0) { + RNP_LOG("wrong b64 padding"); + return false; + } + + if (eqcount == 1) { + b24 = (*dptr << 10) | (*(dptr + 1) << 4) | (*(dptr + 2) >> 2); + *bptr++ = b24 >> 8; + *bptr++ = b24 & 0xff; + } else if (eqcount == 2) { + *bptr++ = (*dptr << 2) | (*(dptr + 1) >> 4); + } + + /* Calculate CRC after reading whole input stream */ + if (!armored_update_crc(param, param->rest, bptr - param->rest, true)) { + return false; + } + } else { + /* few bytes which do not fit to 4 boundary */ + for (int i = 0; i < dend - dptr; i++) { + param->brest[i] = *(dptr + i); + } + param->brestlen = dend - dptr; + } + + param->restlen = bptr - param->rest; + + /* check whether we have some bytes to add */ + if ((left > 0) && (param->restlen > 0)) { + read = left > param->restlen ? param->restlen : left; + memcpy(bufptr, param->rest, read); + if (!param->eofb64 && !armored_update_crc(param, bufptr, read)) { + return false; + } + left -= read; + param->restpos += read; + } + + *readres = len - left; + return true; +} + +static void +armored_src_close(pgp_source_t *src) +{ + pgp_source_armored_param_t *param = (pgp_source_armored_param_t *) src->param; + + if (param) { + free(param->armorhdr); + free(param->version); + free(param->comment); + free(param->hash); + free(param->charset); + delete param; + src->param = NULL; + } +} + +/** @brief finds armor header position in the buffer, returning beginning of header or NULL. + * hdrlen will contain the length of the header + **/ +static const char * +find_armor_header(const char *buf, size_t len, size_t *hdrlen) +{ + int st = -1; + + for (unsigned i = 0; i < len - 10; i++) { + if ((buf[i] == CH_DASH) && !strncmp(&buf[i + 1], ST_DASHES, 4)) { + st = i; + break; + } + } + + if (st < 0) { + return NULL; + } + + for (unsigned i = st + 5; i <= len - 5; i++) { + if ((buf[i] == CH_DASH) && !strncmp(&buf[i + 1], ST_DASHES, 4)) { + *hdrlen = i + 5 - st; + return &buf[st]; + } + } + + return NULL; +} + +static bool +str_equals(const char *str, size_t len, const char *another) +{ + size_t alen = strlen(another); + return (len == alen) && !memcmp(str, another, alen); +} + +static pgp_armored_msg_t +armor_str_to_data_type(const char *str, size_t len) +{ + if (!str) { + return PGP_ARMORED_UNKNOWN; + } + if (str_equals(str, len, "BEGIN PGP MESSAGE")) { + return PGP_ARMORED_MESSAGE; + } + if (str_equals(str, len, "BEGIN PGP PUBLIC KEY BLOCK") || + str_equals(str, len, "BEGIN PGP PUBLIC KEY")) { + return PGP_ARMORED_PUBLIC_KEY; + } + if (str_equals(str, len, "BEGIN PGP SECRET KEY BLOCK") || + str_equals(str, len, "BEGIN PGP SECRET KEY") || + str_equals(str, len, "BEGIN PGP PRIVATE KEY BLOCK") || + str_equals(str, len, "BEGIN PGP PRIVATE KEY")) { + return PGP_ARMORED_SECRET_KEY; + } + if (str_equals(str, len, "BEGIN PGP SIGNATURE")) { + return PGP_ARMORED_SIGNATURE; + } + if (str_equals(str, len, "BEGIN PGP SIGNED MESSAGE")) { + return PGP_ARMORED_CLEARTEXT; + } + return PGP_ARMORED_UNKNOWN; +} + +pgp_armored_msg_t +rnp_armor_guess_type(pgp_source_t *src) +{ + uint8_t ptag; + + if (!src_peek_eq(src, &ptag, 1)) { + return PGP_ARMORED_UNKNOWN; + } + + switch (get_packet_type(ptag)) { + case PGP_PKT_PK_SESSION_KEY: + case PGP_PKT_SK_SESSION_KEY: + case PGP_PKT_ONE_PASS_SIG: + case PGP_PKT_SE_DATA: + case PGP_PKT_SE_IP_DATA: + case PGP_PKT_COMPRESSED: + case PGP_PKT_LITDATA: + case PGP_PKT_MARKER: + return PGP_ARMORED_MESSAGE; + case PGP_PKT_PUBLIC_KEY: + case PGP_PKT_PUBLIC_SUBKEY: + return PGP_ARMORED_PUBLIC_KEY; + case PGP_PKT_SECRET_KEY: + case PGP_PKT_SECRET_SUBKEY: + return PGP_ARMORED_SECRET_KEY; + case PGP_PKT_SIGNATURE: + return PGP_ARMORED_SIGNATURE; + default: + return PGP_ARMORED_UNKNOWN; + } +} + +static pgp_armored_msg_t +rnp_armored_guess_type_by_readahead(pgp_source_t *src) +{ + if (!src->cache) { + return PGP_ARMORED_UNKNOWN; + } + + pgp_source_t armorsrc = {0}; + pgp_source_t memsrc = {0}; + size_t read; + // peek as much as the cache can take + bool cache_res = src_peek(src, NULL, sizeof(src->cache->buf), &read); + if (!cache_res || !read || + init_mem_src(&memsrc, + src->cache->buf + src->cache->pos, + src->cache->len - src->cache->pos, + false)) { + return PGP_ARMORED_UNKNOWN; + } + rnp_result_t res = init_armored_src(&armorsrc, &memsrc); + if (res) { + src_close(&memsrc); + RNP_LOG("failed to parse armored data"); + return PGP_ARMORED_UNKNOWN; + } + pgp_armored_msg_t guessed = rnp_armor_guess_type(&armorsrc); + src_close(&armorsrc); + src_close(&memsrc); + return guessed; +} + +pgp_armored_msg_t +rnp_armored_get_type(pgp_source_t *src) +{ + pgp_armored_msg_t guessed = rnp_armored_guess_type_by_readahead(src); + if (guessed != PGP_ARMORED_UNKNOWN) { + return guessed; + } + + char hdr[ARMORED_PEEK_BUF_SIZE]; + const char *armhdr; + size_t armhdrlen; + size_t read; + + if (!src_peek(src, hdr, sizeof(hdr), &read) || (read < 20)) { + return PGP_ARMORED_UNKNOWN; + } + if (!(armhdr = find_armor_header(hdr, read, &armhdrlen))) { + return PGP_ARMORED_UNKNOWN; + } + + return armor_str_to_data_type(armhdr + 5, armhdrlen - 10); +} + +static bool +armor_parse_header(pgp_source_t *src) +{ + char hdr[ARMORED_PEEK_BUF_SIZE]; + const char * armhdr; + size_t armhdrlen; + size_t read; + pgp_source_armored_param_t *param = (pgp_source_armored_param_t *) src->param; + + if (!src_peek(param->readsrc, hdr, sizeof(hdr), &read) || (read < 20)) { + return false; + } + + if (!(armhdr = find_armor_header(hdr, read, &armhdrlen))) { + RNP_LOG("no armor header"); + return false; + } + + /* if there are non-whitespaces before the armor header then issue warning */ + for (char *ch = hdr; ch < armhdr; ch++) { + if (B64DEC[(uint8_t) *ch] != 0xfd) { + RNP_LOG("extra data before the header line"); + break; + } + } + + param->type = armor_str_to_data_type(armhdr + 5, armhdrlen - 10); + if (param->type == PGP_ARMORED_UNKNOWN) { + RNP_LOG("unknown armor header"); + return false; + } + + if ((param->armorhdr = (char *) malloc(armhdrlen - 9)) == NULL) { + RNP_LOG("allocation failed"); + return false; + } + + memcpy(param->armorhdr, armhdr + 5, armhdrlen - 10); + param->armorhdr[armhdrlen - 10] = '\0'; + src_skip(param->readsrc, armhdr - hdr + armhdrlen); + armor_skip_chars(param->readsrc, "\t "); + return true; +} + +static bool +armor_skip_line(pgp_source_t *src) +{ + char header[ARMORED_PEEK_BUF_SIZE] = {0}; + do { + size_t hdrlen = 0; + bool res = src_peek_line(src, header, sizeof(header), &hdrlen); + if (hdrlen) { + src_skip(src, hdrlen); + } + if (res || (hdrlen < sizeof(header) - 1)) { + return res; + } + } while (1); +} + +static bool +is_base64_line(const char *line, size_t len) +{ + for (size_t i = 0; i < len && line[i]; i++) { + if (B64DEC[(uint8_t) line[i]] == 0xff) + return false; + } + return true; +} + +static bool +armor_parse_headers(pgp_source_t *src) +{ + pgp_source_armored_param_t *param = (pgp_source_armored_param_t *) src->param; + char header[ARMORED_PEEK_BUF_SIZE] = {0}; + + do { + size_t hdrlen = 0; + if (!src_peek_line(param->readsrc, header, sizeof(header), &hdrlen)) { + /* if line is too long let's cut it to the reasonable size */ + src_skip(param->readsrc, hdrlen); + if ((hdrlen != sizeof(header) - 1) || !armor_skip_line(param->readsrc)) { + RNP_LOG("failed to peek line: unexpected end of data"); + return false; + } + RNP_LOG("Too long armor header - truncated."); + header[hdrlen] = '\0'; + } else if (hdrlen) { + if (is_base64_line(header, hdrlen)) { + RNP_LOG("Warning: no empty line after the base64 headers"); + return true; + } + src_skip(param->readsrc, hdrlen); + if (rnp::is_blank_line(header, hdrlen)) { + return src_skip_eol(param->readsrc); + } + } else { + /* empty line - end of the headers */ + return src_skip_eol(param->readsrc); + } + + char *hdrval = (char *) malloc(hdrlen + 1); + if (!hdrval) { + RNP_LOG("malloc failed"); + return false; + } + + if ((hdrlen >= 9) && !strncmp(header, ST_HEADER_VERSION, 9)) { + memcpy(hdrval, header + 9, hdrlen - 8); + free(param->version); + param->version = hdrval; + } else if ((hdrlen >= 9) && !strncmp(header, ST_HEADER_COMMENT, 9)) { + memcpy(hdrval, header + 9, hdrlen - 8); + free(param->comment); + param->comment = hdrval; + } else if ((hdrlen >= 5) && !strncmp(header, ST_HEADER_HASH, 6)) { + memcpy(hdrval, header + 6, hdrlen - 5); + free(param->hash); + param->hash = hdrval; + } else if ((hdrlen >= 9) && !strncmp(header, ST_HEADER_CHARSET, 9)) { + memcpy(hdrval, header + 9, hdrlen - 8); + free(param->charset); + param->charset = hdrval; + } else { + RNP_LOG("unknown header '%s'", header); + free(hdrval); + } + + if (!src_skip_eol(param->readsrc)) { + return false; + } + } while (1); +} + +rnp_result_t +init_armored_src(pgp_source_t *src, pgp_source_t *readsrc, bool noheaders) +{ + if (!init_src_common(src, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + pgp_source_armored_param_t *param = new (std::nothrow) pgp_source_armored_param_t(); + if (!param) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + param->readsrc = readsrc; + param->noheaders = noheaders; + src->param = param; + src->read = armored_src_read; + src->close = armored_src_close; + src->type = PGP_STREAM_ARMORED; + + /* base64 data only */ + if (noheaders) { + return RNP_SUCCESS; + } + + /* initialize crc context */ + param->crc_ctx = rnp::CRC24::create(); + /* parsing armored header */ + rnp_result_t errcode = RNP_ERROR_GENERIC; + if (!armor_parse_header(src)) { + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + /* eol */ + if (!src_skip_eol(param->readsrc)) { + RNP_LOG("no eol after the armor header"); + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + /* parsing headers */ + if (!armor_parse_headers(src)) { + RNP_LOG("failed to parse headers"); + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + + /* now we are good to go with base64-encoded data */ + errcode = RNP_SUCCESS; +finish: + if (errcode) { + src_close(src); + } + return errcode; +} + +/** @brief Write message header to the dst. */ +static bool +armor_write_message_header(pgp_dest_armored_param_t *param, bool finish) +{ + const char *str = finish ? ST_ARMOR_END : ST_ARMOR_BEGIN; + dst_write(param->writedst, str, strlen(str)); + switch (param->type) { + case PGP_ARMORED_MESSAGE: + str = "MESSAGE"; + break; + case PGP_ARMORED_PUBLIC_KEY: + str = "PUBLIC KEY BLOCK"; + break; + case PGP_ARMORED_SECRET_KEY: + str = "PRIVATE KEY BLOCK"; + break; + case PGP_ARMORED_SIGNATURE: + str = "SIGNATURE"; + break; + case PGP_ARMORED_CLEARTEXT: + str = "SIGNED MESSAGE"; + break; + default: + return false; + } + dst_write(param->writedst, str, strlen(str)); + dst_write(param->writedst, ST_DASHES, strlen(ST_DASHES)); + return true; +} + +static void +armor_write_eol(pgp_dest_armored_param_t *param) +{ + if (param->eol[0]) { + dst_write(param->writedst, ¶m->eol[0], 1); + } + if (param->eol[1]) { + dst_write(param->writedst, ¶m->eol[1], 1); + } +} + +static void +armor_append_eol(pgp_dest_armored_param_t *param, uint8_t *&ptr) +{ + if (param->eol[0]) { + *ptr++ = param->eol[0]; + } + if (param->eol[1]) { + *ptr++ = param->eol[1]; + } +} + +/* Base 64 encoded table, quadruplicated to save cycles on use & 0x3f operation */ +static const uint8_t B64ENC[256] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/'}; + +static void +armored_encode3(uint8_t *out, uint8_t *in) +{ + out[0] = B64ENC[in[0] >> 2]; + out[1] = B64ENC[((in[0] << 4) | (in[1] >> 4)) & 0xff]; + out[2] = B64ENC[((in[1] << 2) | (in[2] >> 6)) & 0xff]; + out[3] = B64ENC[in[2] & 0xff]; +} + +static rnp_result_t +armored_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_armored_param_t *param = (pgp_dest_armored_param_t *) dst->param; + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* update crc */ + bool base64 = param->type == PGP_ARMORED_BASE64; + if (!base64) { + try { + param->crc_ctx->add(buf, len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_STATE; + } + } + + uint8_t encbuf[PGP_INPUT_CACHE_SIZE / 2]; + uint8_t *bufptr = (uint8_t *) buf; + uint8_t *bufend = bufptr + len; + uint8_t *encptr = encbuf; + /* processing tail if any */ + if (len + param->tailc < 3) { + memcpy(¶m->tail[param->tailc], buf, len); + param->tailc += len; + return RNP_SUCCESS; + } else if (param->tailc > 0) { + uint8_t dec3[3] = {0}; + memcpy(dec3, param->tail, param->tailc); + memcpy(&dec3[param->tailc], bufptr, 3 - param->tailc); + bufptr += 3 - param->tailc; + param->tailc = 0; + armored_encode3(encptr, dec3); + encptr += 4; + param->lout += 4; + if (param->lout == param->llen) { + armor_append_eol(param, encptr); + param->lout = 0; + } + } + + /* this version prints whole chunks, so rounding down to the closest 4 */ + auto adjusted_llen = param->llen & ~3; + /* number of input bytes to form a whole line of output, param->llen / 4 * 3 */ + auto inllen = (adjusted_llen >> 2) + (adjusted_llen >> 1); + /* pointer to the last full line space in encbuf */ + auto enclast = encbuf + sizeof(encbuf) - adjusted_llen - 2; + + /* processing line chunks, this is the main performance-hitting cycle */ + while (bufptr + 3 <= bufend) { + /* checking whether we have enough space in encbuf */ + if (encptr > enclast) { + dst_write(param->writedst, encbuf, encptr - encbuf); + encptr = encbuf; + } + /* setup length of the input to process in this iteration */ + uint8_t *inlend = + !param->lout ? bufptr + inllen : bufptr + ((adjusted_llen - param->lout) >> 2) * 3; + if (inlend > bufend) { + /* no enough input for the full line */ + inlend = bufptr + (bufend - bufptr) / 3 * 3; + param->lout += (inlend - bufptr) / 3 * 4; + } else { + /* we have full line of input */ + param->lout = 0; + } + + /* processing one line */ + while (bufptr < inlend) { + uint32_t t = (bufptr[0] << 16) | (bufptr[1] << 8) | (bufptr[2]); + bufptr += 3; + *encptr++ = B64ENC[(t >> 18) & 0xff]; + *encptr++ = B64ENC[(t >> 12) & 0xff]; + *encptr++ = B64ENC[(t >> 6) & 0xff]; + *encptr++ = B64ENC[t & 0xff]; + } + + /* adding line ending */ + if (!param->lout) { + armor_append_eol(param, encptr); + } + } + + dst_write(param->writedst, encbuf, encptr - encbuf); + + /* saving tail */ + param->tailc = bufend - bufptr; + memcpy(param->tail, bufptr, param->tailc); + + return RNP_SUCCESS; +} + +static rnp_result_t +armored_dst_finish(pgp_dest_t *dst) +{ + pgp_dest_armored_param_t *param = (pgp_dest_armored_param_t *) dst->param; + + /* writing tail */ + uint8_t buf[5]; + if (param->tailc == 1) { + buf[0] = B64ENC[param->tail[0] >> 2]; + buf[1] = B64ENC[(param->tail[0] << 4) & 0xff]; + buf[2] = CH_EQ; + buf[3] = CH_EQ; + dst_write(param->writedst, buf, 4); + } else if (param->tailc == 2) { + buf[0] = B64ENC[(param->tail[0] >> 2)]; + buf[1] = B64ENC[((param->tail[0] << 4) | (param->tail[1] >> 4)) & 0xff]; + buf[2] = B64ENC[(param->tail[1] << 2) & 0xff]; + buf[3] = CH_EQ; + dst_write(param->writedst, buf, 4); + } + /* Check for base64 */ + if (param->type == PGP_ARMORED_BASE64) { + return param->writedst->werr; + } + + /* writing EOL if needed */ + if ((param->tailc > 0) || (param->lout > 0)) { + armor_write_eol(param); + } + + /* writing CRC and EOL */ + // At this point crc_ctx is initialized, so call can't fail + buf[0] = CH_EQ; + try { + auto crc = param->crc_ctx->finish(); + armored_encode3(&buf[1], crc.data()); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } + dst_write(param->writedst, buf, 5); + armor_write_eol(param); + + /* writing armor header */ + if (!armor_write_message_header(param, true)) { + return RNP_ERROR_BAD_PARAMETERS; + } + armor_write_eol(param); + return param->writedst->werr; +} + +static void +armored_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_armored_param_t *param = (pgp_dest_armored_param_t *) dst->param; + + if (!param) { + return; + } + /* dst_close may be called without dst_finish on error */ + delete param; + dst->param = NULL; +} + +rnp_result_t +init_armored_dst(pgp_dest_t *dst, pgp_dest_t *writedst, pgp_armored_msg_t msgtype) +{ + if (!init_dst_common(dst, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + pgp_dest_armored_param_t *param = new (std::nothrow) pgp_dest_armored_param_t(); + if (!param) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + dst->param = param; + dst->write = armored_dst_write; + dst->finish = armored_dst_finish; + dst->close = armored_dst_close; + dst->type = PGP_STREAM_ARMORED; + dst->writeb = 0; + dst->clen = 0; + + param->writedst = writedst; + param->type = msgtype; + /* Base64 message */ + if (msgtype == PGP_ARMORED_BASE64) { + /* Base64 encoding will not output EOLs but we need this to not duplicate code for a + * separate base64_dst_write function */ + param->eol[0] = 0; + param->eol[1] = 0; + param->llen = 256; + return RNP_SUCCESS; + } + /* create crc context */ + param->crc_ctx = rnp::CRC24::create(); + param->eol[0] = CH_CR; + param->eol[1] = CH_LF; + param->llen = 76; /* must be multiple of 4 */ + /* armor header */ + if (!armor_write_message_header(param, false)) { + RNP_LOG("unknown data type"); + armored_dst_close(dst, true); + return RNP_ERROR_BAD_PARAMETERS; + } + armor_write_eol(param); + /* empty line */ + armor_write_eol(param); + return RNP_SUCCESS; +} + +bool +is_armored_dest(pgp_dest_t *dst) +{ + return dst->type == PGP_STREAM_ARMORED; +} + +rnp_result_t +armored_dst_set_line_length(pgp_dest_t *dst, size_t llen) +{ + if (!dst || (llen < ARMORED_MIN_LINE_LENGTH) || (llen > ARMORED_MAX_LINE_LENGTH) || + !dst->param || !is_armored_dest(dst)) { + return RNP_ERROR_BAD_PARAMETERS; + } + auto param = (pgp_dest_armored_param_t *) dst->param; + param->llen = llen; + return RNP_SUCCESS; +} + +bool +is_armored_source(pgp_source_t *src) +{ + uint8_t buf[ARMORED_PEEK_BUF_SIZE]; + size_t read = 0; + + if (!src_peek(src, buf, sizeof(buf), &read) || (read < strlen(ST_ARMOR_BEGIN) + 1)) { + return false; + } + buf[read - 1] = 0; + return !!strstr((char *) buf, ST_ARMOR_BEGIN); +} + +bool +is_cleartext_source(pgp_source_t *src) +{ + uint8_t buf[ARMORED_PEEK_BUF_SIZE]; + size_t read = 0; + + if (!src_peek(src, buf, sizeof(buf), &read) || (read < strlen(ST_CLEAR_BEGIN))) { + return false; + } + buf[read - 1] = 0; + return !!strstr((char *) buf, ST_CLEAR_BEGIN); +} + +bool +is_base64_source(pgp_source_t &src) +{ + char buf[128]; + size_t read = 0; + + if (!src_peek(&src, buf, sizeof(buf), &read) || (read < 4)) { + return false; + } + return is_base64_line(buf, read); +} + +rnp_result_t +rnp_dearmor_source(pgp_source_t *src, pgp_dest_t *dst) +{ + rnp_result_t res = RNP_ERROR_BAD_FORMAT; + pgp_source_t armorsrc = {0}; + + /* initializing armored message */ + res = init_armored_src(&armorsrc, src); + if (res) { + return res; + } + /* Reading data from armored source and writing it to the output */ + res = dst_write_src(&armorsrc, dst); + if (res) { + RNP_LOG("dearmoring failed"); + } + + src_close(&armorsrc); + return res; +} + +rnp_result_t +rnp_armor_source(pgp_source_t *src, pgp_dest_t *dst, pgp_armored_msg_t msgtype) +{ + pgp_dest_t armordst = {0}; + rnp_result_t res = init_armored_dst(&armordst, dst, msgtype); + if (res) { + return res; + } + + res = dst_write_src(src, &armordst); + if (res) { + RNP_LOG("armoring failed"); + } + + dst_close(&armordst, res != RNP_SUCCESS); + return res; +} + +namespace rnp { + +const uint32_t ArmoredSource::AllowBinary = 0x01; +const uint32_t ArmoredSource::AllowBase64 = 0x02; +const uint32_t ArmoredSource::AllowMultiple = 0x04; + +ArmoredSource::ArmoredSource(pgp_source_t &readsrc, uint32_t flags) + : Source(), readsrc_(readsrc), multiple_(false) +{ + /* Do not dearmor already armored stream */ + bool already = readsrc_.type == PGP_STREAM_ARMORED; + /* Check for base64 source: no multiple streams allowed */ + if (!already && (flags & AllowBase64) && (is_base64_source(readsrc))) { + auto res = init_armored_src(&src_, &readsrc_, true); + if (res) { + RNP_LOG("Failed to parse base64 data."); + throw rnp::rnp_exception(res); + } + armored_ = true; + return; + } + /* Check for armored source */ + if (!already && is_armored_source(&readsrc)) { + auto res = init_armored_src(&src_, &readsrc_); + if (res) { + RNP_LOG("Failed to parse armored data."); + throw rnp::rnp_exception(res); + } + armored_ = true; + multiple_ = flags & AllowMultiple; + return; + } + /* Use binary source if allowed */ + if (!(flags & AllowBinary)) { + RNP_LOG("Non-armored data is not allowed here."); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + armored_ = false; +} + +void +ArmoredSource::restart() +{ + if (!armored_ || src_eof(&readsrc_) || src_error(&readsrc_)) { + return; + } + src_close(&src_); + auto res = init_armored_src(&src_, &readsrc_); + if (res) { + throw rnp::rnp_exception(res); + } +} + +pgp_source_t & +ArmoredSource::src() +{ + return armored_ ? src_ : readsrc_; +} +} // namespace rnp diff --git a/comm/third_party/rnp/src/librepgp/stream-armor.h b/comm/third_party/rnp/src/librepgp/stream-armor.h new file mode 100644 index 0000000000..4c91fd20a5 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-armor.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_ARMOUR_H_ +#define STREAM_ARMOUR_H_ + +#include "stream-common.h" + +typedef enum { + PGP_ARMORED_UNKNOWN, + PGP_ARMORED_MESSAGE, + PGP_ARMORED_PUBLIC_KEY, + PGP_ARMORED_SECRET_KEY, + PGP_ARMORED_SIGNATURE, + PGP_ARMORED_CLEARTEXT, + PGP_ARMORED_BASE64 +} pgp_armored_msg_t; + +/* @brief Init dearmoring stream + * @param src allocated pgp_source_t structure + * @param readsrc source to read data from + * @return RNP_SUCCESS on success or error code otherwise + **/ +rnp_result_t init_armored_src(pgp_source_t *src, + pgp_source_t *readsrc, + bool noheaders = false); + +/* @brief Init armoring stream + * @param dst allocated pgp_dest_t structure + * @param writedst destination to write armored data to + * @param msgtype type of the message (see pgp_armored_msg_t) + * @return RNP_SUCCESS on success or error code otherwise + **/ +rnp_result_t init_armored_dst(pgp_dest_t * dst, + pgp_dest_t * writedst, + pgp_armored_msg_t msgtype); + +/* @brief Dearmor the source, outputting binary data + * @param src initialized source with armored data + * @param dst initialized dest to write binary data to + * @return RNP_SUCCESS on success or error code otherwise + **/ +rnp_result_t rnp_dearmor_source(pgp_source_t *src, pgp_dest_t *dst); + +/* @brief Armor the source, outputting base64-encoded data with headers + * @param src initialized source with binary data + * @param dst destination to write armored data + * @msgtype type of the message, to write correct armor headers + * @return RNP_SUCCESS on success or error code otherwise + **/ +rnp_result_t rnp_armor_source(pgp_source_t *src, pgp_dest_t *dst, pgp_armored_msg_t msgtype); + +/* @brief Guess the corresponding armored message type by first byte(s) of PGP message + * @param src initialized source with binary PGP message data + * @return corresponding enum element or PGP_ARMORED_UNKNOWN + **/ +pgp_armored_msg_t rnp_armor_guess_type(pgp_source_t *src); + +/* @brief Get type of the armored message by peeking header. + * @param src initialized source with armored message data. + * @return corresponding enum element or PGP_ARMORED_UNKNOWN + **/ +pgp_armored_msg_t rnp_armored_get_type(pgp_source_t *src); + +/* @brief Check whether source could be an armored source + * @param src initialized source with some data + * @return true if source could be an armored data or false otherwise + **/ +bool is_armored_source(pgp_source_t *src); + +/* @brief Check whether destination is armored + * @param dest initialized destination + * @return true if destination is armored or false otherwise + **/ +bool is_armored_dest(pgp_dest_t *dst); + +/* @brief Check whether source is cleartext signed + * @param src initialized source with some data + * @return true if source could be a cleartext signed data or false otherwise + **/ +bool is_cleartext_source(pgp_source_t *src); + +/** @brief Check whether source is base64-encoded + * @param src initialized source with some data + * @return true if source could be a base64-encoded data or false otherwise + **/ +bool is_base64_source(pgp_source_t &src); + +/** Set line length for armoring + * + * @param dst initialized dest to write armored data to + * @param llen line length in characters + * @return RNP_SUCCESS on success, or any other value on error + */ +rnp_result_t armored_dst_set_line_length(pgp_dest_t *dst, size_t llen); + +namespace rnp { + +class ArmoredSource : public Source { + pgp_source_t &readsrc_; + bool armored_; + bool multiple_; + + public: + static const uint32_t AllowBinary; + static const uint32_t AllowBase64; + static const uint32_t AllowMultiple; + + ArmoredSource(const ArmoredSource &) = delete; + ArmoredSource(ArmoredSource &&) = delete; + + ArmoredSource(pgp_source_t &readsrc, uint32_t flags = 0); + + pgp_source_t &src(); + + bool + multiple() + { + return multiple_; + } + + /* Restart dearmoring in case of multiple armored messages in a single stream */ + void restart(); +}; + +class ArmoredDest : public Dest { + pgp_dest_t &writedst_; + + public: + ArmoredDest(const ArmoredDest &) = delete; + ArmoredDest(ArmoredDest &&) = delete; + + ArmoredDest(pgp_dest_t &writedst, pgp_armored_msg_t msgtype) : Dest(), writedst_(writedst) + { + auto ret = init_armored_dst(&dst_, &writedst_, msgtype); + if (ret) { + throw rnp::rnp_exception(ret); + } + }; + + ~ArmoredDest() + { + if (!discard_) { + dst_finish(&dst_); + } + } +}; + +} // namespace rnp + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-common.cpp b/comm/third_party/rnp/src/librepgp/stream-common.cpp new file mode 100644 index 0000000000..334f93b527 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-common.cpp @@ -0,0 +1,1212 @@ +/* + * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#ifdef HAVE_UNISTD_H +#include +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include "rnp.h" +#include "stream-common.h" +#include "types.h" +#include "file-utils.h" +#include "crypto/mem.h" +#include +#include + +bool +src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + size_t left = len; + size_t read; + pgp_source_cache_t *cache = src->cache; + bool readahead = cache ? cache->readahead : false; + + if (src->error) { + return false; + } + + if (src->eof || (len == 0)) { + *readres = 0; + return true; + } + + // Do not read more then available if source size is known + if (src->knownsize && (src->readb + len > src->size)) { + len = src->size - src->readb; + left = len; + readahead = false; + } + + // Check whether we have cache and there is data inside + if (cache && (cache->len > cache->pos)) { + read = cache->len - cache->pos; + if (read >= len) { + memcpy(buf, &cache->buf[cache->pos], len); + cache->pos += len; + goto finish; + } else { + memcpy(buf, &cache->buf[cache->pos], read); + cache->pos += read; + buf = (uint8_t *) buf + read; + left = len - read; + } + } + + // If we got here then we have empty cache or no cache at all + while (left > 0) { + if (left > sizeof(cache->buf) || !readahead || !cache) { + // If there is no cache or chunk is larger then read directly + if (!src->read(src, buf, left, &read)) { + src->error = 1; + return false; + } + if (!read) { + src->eof = 1; + len = len - left; + goto finish; + } + left -= read; + buf = (uint8_t *) buf + read; + } else { + // Try to fill the cache to avoid small reads + if (!src->read(src, &cache->buf[0], sizeof(cache->buf), &read)) { + src->error = 1; + return false; + } + if (!read) { + src->eof = 1; + len = len - left; + goto finish; + } else if (read < left) { + memcpy(buf, &cache->buf[0], read); + left -= read; + buf = (uint8_t *) buf + read; + } else { + memcpy(buf, &cache->buf[0], left); + cache->pos = left; + cache->len = read; + goto finish; + } + } + } + +finish: + src->readb += len; + if (src->knownsize && (src->readb == src->size)) { + src->eof = 1; + } + *readres = len; + return true; +} + +bool +src_read_eq(pgp_source_t *src, void *buf, size_t len) +{ + size_t res = 0; + return src_read(src, buf, len, &res) && (res == len); +} + +bool +src_peek(pgp_source_t *src, void *buf, size_t len, size_t *peeked) +{ + pgp_source_cache_t *cache = src->cache; + if (src->error) { + return false; + } + if (!cache || (len > sizeof(cache->buf))) { + return false; + } + if (src->eof) { + *peeked = 0; + return true; + } + + size_t read = 0; + bool readahead = cache->readahead; + // Do not read more then available if source size is known + if (src->knownsize && (src->readb + len > src->size)) { + len = src->size - src->readb; + readahead = false; + } + + if (cache->len - cache->pos >= len) { + if (buf) { + memcpy(buf, &cache->buf[cache->pos], len); + } + *peeked = len; + return true; + } + + if (cache->pos > 0) { + memmove(&cache->buf[0], &cache->buf[cache->pos], cache->len - cache->pos); + cache->len -= cache->pos; + cache->pos = 0; + } + + while (cache->len < len) { + read = readahead ? sizeof(cache->buf) - cache->len : len - cache->len; + if (src->knownsize && (src->readb + read > src->size)) { + read = src->size - src->readb; + } + if (!src->read(src, &cache->buf[cache->len], read, &read)) { + src->error = 1; + return false; + } + if (!read) { + if (buf) { + memcpy(buf, &cache->buf[0], cache->len); + } + *peeked = cache->len; + return true; + } + cache->len += read; + if (cache->len >= len) { + if (buf) { + memcpy(buf, cache->buf, len); + } + *peeked = len; + return true; + } + } + return false; +} + +bool +src_peek_eq(pgp_source_t *src, void *buf, size_t len) +{ + size_t res = 0; + return src_peek(src, buf, len, &res) && (res == len); +} + +void +src_skip(pgp_source_t *src, size_t len) +{ + if (src->cache && (src->cache->len - src->cache->pos >= len)) { + src->readb += len; + src->cache->pos += len; + return; + } + + size_t res = 0; + uint8_t sbuf[16]; + if (len < sizeof(sbuf)) { + (void) src_read(src, sbuf, len, &res); + return; + } + if (src_eof(src)) { + return; + } + + void *buf = calloc(1, std::min((size_t) PGP_INPUT_CACHE_SIZE, len)); + if (!buf) { + src->error = 1; + return; + } + + while (len && !src_eof(src)) { + if (!src_read(src, buf, std::min((size_t) PGP_INPUT_CACHE_SIZE, len), &res)) { + break; + } + len -= res; + } + free(buf); +} + +rnp_result_t +src_finish(pgp_source_t *src) +{ + rnp_result_t res = RNP_SUCCESS; + if (src->finish) { + res = src->finish(src); + } + + return res; +} + +bool +src_error(const pgp_source_t *src) +{ + return src->error; +} + +bool +src_eof(pgp_source_t *src) +{ + if (src->eof) { + return true; + } + /* Error on stream read is NOT considered as eof. See src_error(). */ + uint8_t check; + size_t read = 0; + return src_peek(src, &check, 1, &read) && (read == 0); +} + +void +src_close(pgp_source_t *src) +{ + if (src->close) { + src->close(src); + } + + if (src->cache) { + free(src->cache); + src->cache = NULL; + } +} + +bool +src_skip_eol(pgp_source_t *src) +{ + uint8_t eol[2]; + size_t read; + + if (!src_peek(src, eol, 2, &read) || !read) { + return false; + } + if (eol[0] == '\n') { + src_skip(src, 1); + return true; + } + if ((read == 2) && (eol[0] == '\r') && (eol[1] == '\n')) { + src_skip(src, 2); + return true; + } + return false; +} + +bool +src_peek_line(pgp_source_t *src, char *buf, size_t len, size_t *readres) +{ + size_t scan_pos = 0; + size_t inc = 64; + len = len - 1; + + do { + size_t to_peek = scan_pos + inc; + to_peek = to_peek > len ? len : to_peek; + inc = inc * 2; + + /* inefficient, each time we again read from the beginning */ + if (!src_peek(src, buf, to_peek, readres)) { + return false; + } + + /* we continue scanning where we stopped previously */ + for (; scan_pos < *readres; scan_pos++) { + if (buf[scan_pos] == '\n') { + if ((scan_pos > 0) && (buf[scan_pos - 1] == '\r')) { + scan_pos--; + } + buf[scan_pos] = '\0'; + *readres = scan_pos; + return true; + } + } + if (*readres < to_peek) { + return false; + } + } while (scan_pos < len); + return false; +} + +bool +init_src_common(pgp_source_t *src, size_t paramsize) +{ + memset(src, 0, sizeof(*src)); + src->cache = (pgp_source_cache_t *) calloc(1, sizeof(*src->cache)); + if (!src->cache) { + RNP_LOG("cache allocation failed"); + return false; + } + src->cache->readahead = true; + if (!paramsize) { + return true; + } + src->param = calloc(1, paramsize); + if (!src->param) { + RNP_LOG("param allocation failed"); + free(src->cache); + src->cache = NULL; + return false; + } + return true; +} + +typedef struct pgp_source_file_param_t { + int fd; +} pgp_source_file_param_t; + +static bool +file_src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + pgp_source_file_param_t *param = (pgp_source_file_param_t *) src->param; + if (!param) { + return false; + } + + int64_t rres = read(param->fd, buf, len); + if (rres < 0) { + return false; + } + *readres = rres; + return true; +} + +static void +file_src_close(pgp_source_t *src) +{ + pgp_source_file_param_t *param = (pgp_source_file_param_t *) src->param; + if (param) { + if (src->type == PGP_STREAM_FILE) { + close(param->fd); + } + free(src->param); + src->param = NULL; + } +} + +static rnp_result_t +init_fd_src(pgp_source_t *src, int fd, uint64_t *size) +{ + if (!init_src_common(src, sizeof(pgp_source_file_param_t))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + pgp_source_file_param_t *param = (pgp_source_file_param_t *) src->param; + param->fd = fd; + src->read = file_src_read; + src->close = file_src_close; + src->type = PGP_STREAM_FILE; + src->size = size ? *size : 0; + src->knownsize = !!size; + + return RNP_SUCCESS; +} + +rnp_result_t +init_file_src(pgp_source_t *src, const char *path) +{ + int fd; + struct stat st; + + if (rnp_stat(path, &st) != 0) { + RNP_LOG("can't stat '%s'", path); + return RNP_ERROR_READ; + } + + /* read call may succeed on directory depending on OS type */ + if (S_ISDIR(st.st_mode)) { + RNP_LOG("source is directory"); + return RNP_ERROR_BAD_PARAMETERS; + } + + int flags = O_RDONLY; +#ifdef HAVE_O_BINARY + flags |= O_BINARY; +#else +#ifdef HAVE__O_BINARY + flags |= _O_BINARY; +#endif +#endif + fd = rnp_open(path, flags, 0); + + if (fd < 0) { + RNP_LOG("can't open '%s'", path); + return RNP_ERROR_READ; + } + uint64_t size = st.st_size; + rnp_result_t ret = init_fd_src(src, fd, &size); + if (ret) { + close(fd); + } + return ret; +} + +rnp_result_t +init_stdin_src(pgp_source_t *src) +{ + pgp_source_file_param_t *param; + + if (!init_src_common(src, sizeof(pgp_source_file_param_t))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_source_file_param_t *) src->param; + param->fd = 0; + src->read = file_src_read; + src->close = file_src_close; + src->type = PGP_STREAM_STDIN; + + return RNP_SUCCESS; +} + +typedef struct pgp_source_mem_param_t { + const void *memory; + bool free; + size_t len; + size_t pos; +} pgp_source_mem_param_t; + +typedef struct pgp_dest_mem_param_t { + unsigned maxalloc; + unsigned allocated; + void * memory; + bool free; + bool discard_overflow; + bool secure; +} pgp_dest_mem_param_t; + +static bool +mem_src_read(pgp_source_t *src, void *buf, size_t len, size_t *read) +{ + pgp_source_mem_param_t *param = (pgp_source_mem_param_t *) src->param; + if (!param) { + return false; + } + + if (len > param->len - param->pos) { + len = param->len - param->pos; + } + memcpy(buf, (uint8_t *) param->memory + param->pos, len); + param->pos += len; + *read = len; + return true; +} + +static void +mem_src_close(pgp_source_t *src) +{ + pgp_source_mem_param_t *param = (pgp_source_mem_param_t *) src->param; + if (param) { + if (param->free) { + free((void *) param->memory); + } + free(src->param); + src->param = NULL; + } +} + +rnp_result_t +init_mem_src(pgp_source_t *src, const void *mem, size_t len, bool free) +{ + if (!mem && len) { + return RNP_ERROR_NULL_POINTER; + } + /* this is actually double buffering, but then src_peek will fail */ + if (!init_src_common(src, sizeof(pgp_source_mem_param_t))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + pgp_source_mem_param_t *param = (pgp_source_mem_param_t *) src->param; + param->memory = mem; + param->len = len; + param->pos = 0; + param->free = free; + src->read = mem_src_read; + src->close = mem_src_close; + src->finish = NULL; + src->size = len; + src->knownsize = 1; + src->type = PGP_STREAM_MEMORY; + + return RNP_SUCCESS; +} + +static bool +null_src_read(pgp_source_t *src, void *buf, size_t len, size_t *read) +{ + return false; +} + +rnp_result_t +init_null_src(pgp_source_t *src) +{ + memset(src, 0, sizeof(*src)); + src->read = null_src_read; + src->type = PGP_STREAM_NULL; + src->error = true; + return RNP_SUCCESS; +} + +rnp_result_t +read_mem_src(pgp_source_t *src, pgp_source_t *readsrc) +{ + pgp_dest_t dst; + rnp_result_t ret; + + if ((ret = init_mem_dest(&dst, NULL, 0))) { + return ret; + } + + if ((ret = dst_write_src(readsrc, &dst))) { + goto done; + } + + if ((ret = init_mem_src(src, mem_dest_own_memory(&dst), dst.writeb, true))) { + goto done; + } + + ret = RNP_SUCCESS; +done: + dst_close(&dst, true); + return ret; +} + +rnp_result_t +file_to_mem_src(pgp_source_t *src, const char *filename) +{ + pgp_source_t fsrc = {}; + rnp_result_t res = RNP_ERROR_GENERIC; + + if ((res = init_file_src(&fsrc, filename))) { + return res; + } + + res = read_mem_src(src, &fsrc); + src_close(&fsrc); + + return res; +} + +const void * +mem_src_get_memory(pgp_source_t *src, bool own) +{ + if (src->type != PGP_STREAM_MEMORY) { + RNP_LOG("wrong function call"); + return NULL; + } + + if (!src->param) { + return NULL; + } + + pgp_source_mem_param_t *param = (pgp_source_mem_param_t *) src->param; + if (own) { + param->free = false; + } + return param->memory; +} + +bool +init_dst_common(pgp_dest_t *dst, size_t paramsize) +{ + memset(dst, 0, sizeof(*dst)); + dst->werr = RNP_SUCCESS; + if (!paramsize) { + return true; + } + /* allocate param */ + dst->param = calloc(1, paramsize); + if (!dst->param) { + RNP_LOG("allocation failed"); + } + return dst->param; +} + +void +dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + /* we call write function only if all previous calls succeeded */ + if ((len > 0) && (dst->write) && (dst->werr == RNP_SUCCESS)) { + /* if cache non-empty and len will overflow it then fill it and write out */ + if ((dst->clen > 0) && (dst->clen + len > sizeof(dst->cache))) { + memcpy(dst->cache + dst->clen, buf, sizeof(dst->cache) - dst->clen); + buf = (uint8_t *) buf + sizeof(dst->cache) - dst->clen; + len -= sizeof(dst->cache) - dst->clen; + dst->werr = dst->write(dst, dst->cache, sizeof(dst->cache)); + dst->writeb += sizeof(dst->cache); + dst->clen = 0; + if (dst->werr != RNP_SUCCESS) { + return; + } + } + + /* here everything will fit into the cache or cache is empty */ + if (dst->no_cache || (len > sizeof(dst->cache))) { + dst->werr = dst->write(dst, buf, len); + if (!dst->werr) { + dst->writeb += len; + } + } else { + memcpy(dst->cache + dst->clen, buf, len); + dst->clen += len; + } + } +} + +void +dst_printf(pgp_dest_t *dst, const char *format, ...) +{ + char buf[2048]; + size_t len; + va_list ap; + + va_start(ap, format); + len = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + if (len >= sizeof(buf)) { + RNP_LOG("too long dst_printf"); + len = sizeof(buf) - 1; + } + dst_write(dst, buf, len); +} + +void +dst_flush(pgp_dest_t *dst) +{ + if ((dst->clen > 0) && (dst->write) && (dst->werr == RNP_SUCCESS)) { + dst->werr = dst->write(dst, dst->cache, dst->clen); + dst->writeb += dst->clen; + dst->clen = 0; + } +} + +rnp_result_t +dst_finish(pgp_dest_t *dst) +{ + rnp_result_t res = RNP_SUCCESS; + + if (!dst->finished) { + /* flush write cache in the dst */ + dst_flush(dst); + if (dst->finish) { + res = dst->finish(dst); + } + dst->finished = true; + } + + return res; +} + +void +dst_close(pgp_dest_t *dst, bool discard) +{ + if (!discard && !dst->finished) { + dst_finish(dst); + } + + if (dst->close) { + dst->close(dst, discard); + } +} + +typedef struct pgp_dest_file_param_t { + int fd; + int errcode; + bool overwrite; + std::string path; +} pgp_dest_file_param_t; + +static rnp_result_t +file_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_file_param_t *param = (pgp_dest_file_param_t *) dst->param; + + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* we assyme that blocking I/O is used so everything is written or error received */ + ssize_t ret = write(param->fd, buf, len); + if (ret < 0) { + param->errcode = errno; + RNP_LOG("write failed, error %d", param->errcode); + return RNP_ERROR_WRITE; + } else { + param->errcode = 0; + return RNP_SUCCESS; + } +} + +static void +file_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_file_param_t *param = (pgp_dest_file_param_t *) dst->param; + if (!param) { + return; + } + + if (dst->type == PGP_STREAM_FILE) { + close(param->fd); + if (discard) { + rnp_unlink(param->path.c_str()); + } + } + + delete param; + dst->param = NULL; +} + +static rnp_result_t +init_fd_dest(pgp_dest_t *dst, int fd, const char *path) +{ + if (!init_dst_common(dst, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + try { + std::unique_ptr param(new pgp_dest_file_param_t()); + param->path = path; + param->fd = fd; + dst->param = param.release(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + + dst->write = file_dst_write; + dst->close = file_dst_close; + dst->type = PGP_STREAM_FILE; + return RNP_SUCCESS; +} + +rnp_result_t +init_file_dest(pgp_dest_t *dst, const char *path, bool overwrite) +{ + /* check whether file/dir already exists */ + struct stat st; + if (!rnp_stat(path, &st)) { + if (!overwrite) { + RNP_LOG("file already exists: '%s'", path); + return RNP_ERROR_WRITE; + } + + /* if we are overwriting empty directory then should first remove it */ + if (S_ISDIR(st.st_mode)) { + if (rmdir(path) == -1) { + RNP_LOG("failed to remove directory: error %d", errno); + return RNP_ERROR_BAD_PARAMETERS; + } + } + } + + int flags = O_WRONLY | O_CREAT; + flags |= overwrite ? O_TRUNC : O_EXCL; +#ifdef HAVE_O_BINARY + flags |= O_BINARY; +#else +#ifdef HAVE__O_BINARY + flags |= _O_BINARY; +#endif +#endif + int fd = rnp_open(path, flags, S_IRUSR | S_IWUSR); + if (fd < 0) { + RNP_LOG("failed to create file '%s'. Error %d.", path, errno); + return RNP_ERROR_WRITE; + } + + rnp_result_t res = init_fd_dest(dst, fd, path); + if (res) { + close(fd); + } + return res; +} + +#define TMPDST_SUFFIX ".rnp-tmp.XXXXXX" + +static rnp_result_t +file_tmpdst_finish(pgp_dest_t *dst) +{ + pgp_dest_file_param_t *param = (pgp_dest_file_param_t *) dst->param; + if (!param) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* close the file */ + close(param->fd); + param->fd = -1; + + /* rename the temporary file */ + if (param->path.size() < strlen(TMPDST_SUFFIX)) { + return RNP_ERROR_BAD_PARAMETERS; + } + try { + /* remove suffix so we have required path */ + std::string origpath(param->path.begin(), param->path.end() - strlen(TMPDST_SUFFIX)); + /* check if file already exists */ + struct stat st; + if (!rnp_stat(origpath.c_str(), &st)) { + if (!param->overwrite) { + RNP_LOG("target path already exists"); + return RNP_ERROR_BAD_STATE; + } +#ifdef _WIN32 + /* rename() call on Windows fails if destination exists */ + else { + rnp_unlink(origpath.c_str()); + } +#endif + + /* we should remove dir if overwriting, file will be unlinked in rename call */ + if (S_ISDIR(st.st_mode) && rmdir(origpath.c_str())) { + RNP_LOG("failed to remove directory"); + return RNP_ERROR_BAD_STATE; + } + } + + if (rnp_rename(param->path.c_str(), origpath.c_str())) { + RNP_LOG("failed to rename temporary path to target file: %s", strerror(errno)); + return RNP_ERROR_BAD_STATE; + } + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_STATE; + } +} + +static void +file_tmpdst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_file_param_t *param = (pgp_dest_file_param_t *) dst->param; + if (!param) { + return; + } + + /* we close file in finish function, except the case when some error occurred */ + if (!dst->finished && (dst->type == PGP_STREAM_FILE)) { + close(param->fd); + if (discard) { + rnp_unlink(param->path.c_str()); + } + } + + delete param; + dst->param = NULL; +} + +rnp_result_t +init_tmpfile_dest(pgp_dest_t *dst, const char *path, bool overwrite) +{ + try { + std::string tmp = std::string(path) + std::string(TMPDST_SUFFIX); + /* make sure tmp.data() is zero-terminated */ + tmp.push_back('\0'); +#if defined(HAVE_MKSTEMP) && !defined(_WIN32) + int fd = mkstemp(&tmp[0]); +#else + int fd = rnp_mkstemp(&tmp[0]); +#endif + if (fd < 0) { + RNP_LOG("failed to create temporary file with template '%s'. Error %d.", + tmp.c_str(), + errno); + return RNP_ERROR_WRITE; + } + rnp_result_t res = init_fd_dest(dst, fd, tmp.c_str()); + if (res) { + close(fd); + return res; + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_STATE; + } + + /* now let's change some parameters to handle temporary file correctly */ + pgp_dest_file_param_t *param = (pgp_dest_file_param_t *) dst->param; + param->overwrite = overwrite; + dst->finish = file_tmpdst_finish; + dst->close = file_tmpdst_close; + return RNP_SUCCESS; +} + +rnp_result_t +init_stdout_dest(pgp_dest_t *dst) +{ + rnp_result_t res = init_fd_dest(dst, STDOUT_FILENO, ""); + if (res) { + return res; + } + dst->type = PGP_STREAM_STDOUT; + return RNP_SUCCESS; +} + +static rnp_result_t +mem_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_mem_param_t *param = (pgp_dest_mem_param_t *) dst->param; + if (!param) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* checking whether we need to realloc or discard extra bytes */ + if (param->discard_overflow && (dst->writeb >= param->allocated)) { + return RNP_SUCCESS; + } + if (param->discard_overflow && (dst->writeb + len > param->allocated)) { + len = param->allocated - dst->writeb; + } + + if (dst->writeb + len > param->allocated) { + if ((param->maxalloc > 0) && (dst->writeb + len > param->maxalloc)) { + RNP_LOG("attempt to alloc more then allowed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + /* round up to the page boundary and do it exponentially */ + size_t alloc = ((dst->writeb + len) * 2 + 4095) / 4096 * 4096; + if ((param->maxalloc > 0) && (alloc > param->maxalloc)) { + alloc = param->maxalloc; + } + + void *newalloc = param->secure ? calloc(1, alloc) : realloc(param->memory, alloc); + if (!newalloc) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (param->secure && param->memory) { + memcpy(newalloc, param->memory, dst->writeb); + secure_clear(param->memory, dst->writeb); + free(param->memory); + } + param->memory = newalloc; + param->allocated = alloc; + } + + memcpy((uint8_t *) param->memory + dst->writeb, buf, len); + return RNP_SUCCESS; +} + +static void +mem_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_mem_param_t *param = (pgp_dest_mem_param_t *) dst->param; + if (!param) { + return; + } + + if (param->free) { + if (param->secure) { + secure_clear(param->memory, param->allocated); + } + free(param->memory); + } + free(param); + dst->param = NULL; +} + +rnp_result_t +init_mem_dest(pgp_dest_t *dst, void *mem, unsigned len) +{ + pgp_dest_mem_param_t *param; + + if (!init_dst_common(dst, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_dest_mem_param_t *) dst->param; + + param->maxalloc = len; + param->allocated = mem ? len : 0; + param->memory = mem; + param->free = !mem; + param->secure = false; + + dst->write = mem_dst_write; + dst->close = mem_dst_close; + dst->type = PGP_STREAM_MEMORY; + dst->werr = RNP_SUCCESS; + dst->no_cache = true; + + return RNP_SUCCESS; +} + +void +mem_dest_discard_overflow(pgp_dest_t *dst, bool discard) +{ + if (dst->type != PGP_STREAM_MEMORY) { + RNP_LOG("wrong function call"); + return; + } + + pgp_dest_mem_param_t *param = (pgp_dest_mem_param_t *) dst->param; + if (param) { + param->discard_overflow = discard; + } +} + +void * +mem_dest_get_memory(pgp_dest_t *dst) +{ + if (dst->type != PGP_STREAM_MEMORY) { + RNP_LOG("wrong function call"); + return NULL; + } + + pgp_dest_mem_param_t *param = (pgp_dest_mem_param_t *) dst->param; + + if (param) { + return param->memory; + } + + return NULL; +} + +void * +mem_dest_own_memory(pgp_dest_t *dst) +{ + if (dst->type != PGP_STREAM_MEMORY) { + RNP_LOG("wrong function call"); + return NULL; + } + + pgp_dest_mem_param_t *param = (pgp_dest_mem_param_t *) dst->param; + + if (!param) { + RNP_LOG("null param"); + return NULL; + } + + dst_finish(dst); + + if (param->free) { + if (!dst->writeb) { + free(param->memory); + param->memory = NULL; + return param->memory; + } + /* it may be larger then required - let's truncate */ + void *newalloc = realloc(param->memory, dst->writeb); + if (!newalloc) { + return NULL; + } + param->memory = newalloc; + param->allocated = dst->writeb; + param->free = false; + return param->memory; + } + + /* in this case we should copy the memory */ + void *res = malloc(dst->writeb); + if (res) { + memcpy(res, param->memory, dst->writeb); + } + return res; +} + +void +mem_dest_secure_memory(pgp_dest_t *dst, bool secure) +{ + if (!dst || (dst->type != PGP_STREAM_MEMORY)) { + RNP_LOG("wrong function call"); + return; + } + pgp_dest_mem_param_t *param = (pgp_dest_mem_param_t *) dst->param; + if (param) { + param->secure = secure; + } +} + +static rnp_result_t +null_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + return RNP_SUCCESS; +} + +static void +null_dst_close(pgp_dest_t *dst, bool discard) +{ + ; +} + +rnp_result_t +init_null_dest(pgp_dest_t *dst) +{ + dst->param = NULL; + dst->write = null_dst_write; + dst->close = null_dst_close; + dst->type = PGP_STREAM_NULL; + dst->writeb = 0; + dst->clen = 0; + dst->werr = RNP_SUCCESS; + dst->no_cache = true; + + return RNP_SUCCESS; +} + +rnp_result_t +dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit) +{ + const size_t bufsize = PGP_INPUT_CACHE_SIZE; + uint8_t * readbuf = (uint8_t *) malloc(bufsize); + if (!readbuf) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t res = RNP_SUCCESS; + try { + size_t read; + uint64_t totalread = 0; + + while (!src->eof) { + if (!src_read(src, readbuf, bufsize, &read)) { + res = RNP_ERROR_GENERIC; + break; + } + if (!read) { + continue; + } + totalread += read; + if (limit && totalread > limit) { + res = RNP_ERROR_GENERIC; + break; + } + if (dst) { + dst_write(dst, readbuf, read); + if (dst->werr) { + RNP_LOG("failed to output data"); + res = RNP_ERROR_WRITE; + break; + } + } + } + } catch (...) { + free(readbuf); + throw; + } + free(readbuf); + if (res || !dst) { + return res; + } + dst_flush(dst); + return dst->werr; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-common.h b/comm/third_party/rnp/src/librepgp/stream-common.h new file mode 100644 index 0000000000..02279d3bae --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-common.h @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_COMMON_H_ +#define STREAM_COMMON_H_ + +#include +#include +#include +#include "types.h" + +#define PGP_INPUT_CACHE_SIZE 32768 +#define PGP_OUTPUT_CACHE_SIZE 32768 + +#define PGP_PARTIAL_PKT_FIRST_PART_MIN_SIZE 512 + +typedef enum { + PGP_STREAM_NULL, + PGP_STREAM_FILE, + PGP_STREAM_MEMORY, + PGP_STREAM_STDIN, + PGP_STREAM_STDOUT, + PGP_STREAM_PACKET, + PGP_STREAM_PARLEN_PACKET, + PGP_STREAM_LITERAL, + PGP_STREAM_COMPRESSED, + PGP_STREAM_ENCRYPTED, + PGP_STREAM_SIGNED, + PGP_STREAM_ARMORED, + PGP_STREAM_CLEARTEXT +} pgp_stream_type_t; + +typedef struct pgp_source_t pgp_source_t; +typedef struct pgp_dest_t pgp_dest_t; + +typedef bool pgp_source_read_func_t(pgp_source_t *src, void *buf, size_t len, size_t *read); +typedef rnp_result_t pgp_source_finish_func_t(pgp_source_t *src); +typedef void pgp_source_close_func_t(pgp_source_t *src); + +typedef rnp_result_t pgp_dest_write_func_t(pgp_dest_t *dst, const void *buf, size_t len); +typedef rnp_result_t pgp_dest_finish_func_t(pgp_dest_t *src); +typedef void pgp_dest_close_func_t(pgp_dest_t *dst, bool discard); + +/* statically preallocated cache for sources */ +typedef struct pgp_source_cache_t { + uint8_t buf[PGP_INPUT_CACHE_SIZE]; + unsigned pos; /* current position in cache */ + unsigned len; /* number of bytes available in cache */ + bool readahead; /* whether read-ahead with larger chunks allowed */ +} pgp_source_cache_t; + +typedef struct pgp_source_t { + pgp_source_read_func_t * read; + pgp_source_finish_func_t *finish; + pgp_source_close_func_t * close; + pgp_stream_type_t type; + + uint64_t size; /* size of the data if available, see knownsize */ + uint64_t readb; /* number of bytes read from the stream via src_read. Do not confuse with + number of bytes as returned via the read since data may be cached */ + pgp_source_cache_t *cache; /* cache if used */ + void * param; /* source-specific additional data */ + + unsigned eof : 1; /* end of data as reported by read and empty cache */ + unsigned knownsize : 1; /* whether size of the data is known */ + unsigned error : 1; /* there were reading error */ +} pgp_source_t; + +/** @brief helper function to allocate memory for source's cache and param + * Also fills src and param with zeroes + * @param src pointer to the source structure + * @param paramsize number of bytes required for src->param + * @return true on success or false if memory allocation failed. + **/ +bool init_src_common(pgp_source_t *src, size_t paramsize); + +/** @brief read up to len bytes from the source + * While this function tries to read as much bytes as possible however it may return + * less then len bytes. Then src->eof can be checked if it's end of data. + * + * @param src source structure + * @param buf preallocated buffer which can store up to len bytes + * @param len number of bytes to read + * @param read number of read bytes will be stored here. Cannot be NULL. + * @return true on success or false otherwise + **/ +bool src_read(pgp_source_t *src, void *buf, size_t len, size_t *read); + +/** @brief shortcut to read exactly len bytes from source. See src_read for parameters. + * @return true if len bytes were read or false otherwise (i.e. less then len were read or + * read error occurred) */ +bool src_read_eq(pgp_source_t *src, void *buf, size_t len); + +/** @brief read up to len bytes and keep them in the cache/do not process + * Works only for streams with cache + * @param src source structure + * @param buf preallocated buffer which can store up to len bytes, or NULL if data should be + * discarded, just making sure that needed input is available in source + * @param len number of bytes to read. Must be less then PGP_INPUT_CACHE_SIZE. + * @param read number of bytes read will be stored here. Cannot be NULL. + * @return true on success or false otherwise + **/ +bool src_peek(pgp_source_t *src, void *buf, size_t len, size_t *read); + +/** @brief shortcut to read exactly len bytes and keep them in the cache/do not process + * Works only for streams with cache + * @return true if len bytes were read or false otherwise (i.e. less then len were read or + * read error occurred) */ +bool src_peek_eq(pgp_source_t *src, void *buf, size_t len); + +/** @brief skip up to len bytes. + * Note: use src_read() if you want to check error condition/get number of bytes + *skipped. + * @param src source structure + * @param len number of bytes to skip + **/ +void src_skip(pgp_source_t *src, size_t len); + +/** @brief notify source that all reading is done, so final data processing may be started, + * i.e. signature reading and verification and so on. Do not misuse with src_close. + * @param src allocated and initialized source structure + * @return RNP_SUCCESS or error code. If source doesn't have finish handler then also + * RNP_SUCCESS is returned + */ +rnp_result_t src_finish(pgp_source_t *src); + +/** @brief check whether there were reading error on source + * @param allocated and initialized source structure + * @return true if there were reading error or false otherwise + */ +bool src_error(const pgp_source_t *src); + +/** @brief check whether there is no more input on source + * @param src allocated and initialized source structure + * @return true if there is no more input or false otherwise. + * On read error false will be returned. + */ +bool src_eof(pgp_source_t *src); + +/** @brief close the source and deallocate all internal resources if any + */ +void src_close(pgp_source_t *src); + +/** @brief skip end of line on the source (\r\n or \n, depending on input) + * @param src allocated and initialized source + * @return true if eol was found and skipped or false otherwise + */ +bool src_skip_eol(pgp_source_t *src); + +/** @brief peek the line on the source + * @param src allocated and initialized source with data + * @param buf preallocated buffer to store the result. Result include NULL character and + * doesn't include the end of line sequence. + * @param len maximum length of data to store in buf, including terminating NULL + * @param read on success here will be stored number of bytes in the string, without the NULL + * character. + * @return true on success + * false is returned if there were eof, read error or eol was not found within the + * len. Supported eol sequences are \r\n and \n + */ +bool src_peek_line(pgp_source_t *src, char *buf, size_t len, size_t *read); + +/** @brief init file source + * @param src pre-allocated source structure + * @param path path to the file + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_file_src(pgp_source_t *src, const char *path); + +/** @brief init stdin source + * @param src pre-allocated source structure + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_stdin_src(pgp_source_t *src); + +/** @brief init memory source + * @param src pre-allocated source structure + * @param mem memory to read from + * @param len number of bytes in input + * @param free free the memory pointer on stream close or not + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_mem_src(pgp_source_t *src, const void *mem, size_t len, bool free); + +/** @brief init NULL source, which doesn't allow to read anything and always returns an error. + * @param src pre-allocated source structure + * @return always RNP_SUCCESS + **/ +rnp_result_t init_null_src(pgp_source_t *src); + +/** @brief init memory source with contents of other source + * @param src pre-allocated source structure + * @param readsrc opened source with data + * @return RNP_SUCCESS or error code + **/ +rnp_result_t read_mem_src(pgp_source_t *src, pgp_source_t *readsrc); + +/** @brief init memory source with contents of the specified file + * @param src pre-allocated source structure + * @param filename name of the file + * @return RNP_SUCCESS or error code + **/ +rnp_result_t file_to_mem_src(pgp_source_t *src, const char *filename); + +/** @brief get memory from the memory source + * @param src initialized memory source + * @param own transfer ownership of the memory + * @return pointer to the memory or NULL if it is not a memory source + **/ +const void *mem_src_get_memory(pgp_source_t *src, bool own = false); + +typedef struct pgp_dest_t { + pgp_dest_write_func_t * write; + pgp_dest_finish_func_t *finish; + pgp_dest_close_func_t * close; + pgp_stream_type_t type; + rnp_result_t werr; /* write function may set this to some error code */ + + size_t writeb; /* number of bytes written */ + void * param; /* source-specific additional data */ + bool no_cache; /* disable write caching */ + uint8_t cache[PGP_OUTPUT_CACHE_SIZE]; + unsigned clen; /* number of bytes in cache */ + bool finished; /* whether dst_finish was called on dest or not */ +} pgp_dest_t; + +/** @brief helper function to allocate memory for dest's param. + * Initializes dst and param with zeroes as well. + * @param dst dest structure + * @param paramsize number of bytes required for dst->param + * @return true on success, or false if memory allocation failed + **/ +bool init_dst_common(pgp_dest_t *dst, size_t paramsize); + +/** @brief write buffer to the destination + * + * @param dst destination structure + * @param buf buffer with data + * @param len number of bytes to write + * @return true on success or false otherwise + **/ +void dst_write(pgp_dest_t *dst, const void *buf, size_t len); + +/** @brief printf formatted string to the destination + * + * @param dst destination structure + * @param format format string, which is the same as printf() uses + * @param ... additional arguments + */ +void dst_printf(pgp_dest_t *dst, const char *format, ...); + +/** @brief do all finalization tasks after all writing is done, i.e. calculate and write + * mdc, signatures and so on. Do not misuse with dst_close. If was not called then will be + * called from the dst_close + * + * @param dst destination structure + * @return RNP_SUCCESS or error code if something went wrong + **/ +rnp_result_t dst_finish(pgp_dest_t *dst); + +/** @brief close the destination + * + * @param dst destination structure to be closed + * @param discard if this is true then all produced output should be discarded + * @return void + **/ +void dst_close(pgp_dest_t *dst, bool discard); + +/** @brief flush cached data if any. dst_write caches small writes, so data does not + * immediately go to stream write function. + * + * @param dst destination structure + * @return void + **/ +void dst_flush(pgp_dest_t *dst); + +/** @brief init file destination + * @param dst pre-allocated dest structure + * @param path path to the file + * @param overwrite overwrite existing file + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_file_dest(pgp_dest_t *dst, const char *path, bool overwrite); + +/** @brief init file destination, using the temporary file name, based on path. + * Once writing is over, dst_finish() will attempt to rename to the desired name. + * @param dst pre-allocated dest structure + * @param path path to the file + * @param overwrite overwrite existing file on rename + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_tmpfile_dest(pgp_dest_t *dst, const char *path, bool overwrite); + +/** @brief init stdout destination + * @param dst pre-allocated dest structure + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_stdout_dest(pgp_dest_t *dst); + +/** @brief init memory destination + * @param dst pre-allocated dest structure + * @param mem pointer to the pre-allocated memory buffer, or NULL if it should be allocated + * @param len number of bytes which mem can keep, or maximum amount of memory to allocate if + * mem is NULL. If len is zero in later case then allocation is not limited. + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_mem_dest(pgp_dest_t *dst, void *mem, unsigned len); + +/** @brief set whether to silently discard bytes which overflow memory of the dst. + * @param dst pre-allocated and initialized memory dest + * @param discard true to discard or false to return an error on overflow. + **/ +void mem_dest_discard_overflow(pgp_dest_t *dst, bool discard); + +/** @brief get the pointer to the memory where data is written. + * Do not retain the result, it may change between calls due to realloc + * @param dst pre-allocated and initialized memory dest + * @return pointer to the memory area or NULL if memory was not allocated + **/ +void *mem_dest_get_memory(pgp_dest_t *dst); + +/** @brief get ownership on the memory dest's contents. This must be called only before + * closing the dest + * @param dst pre-allocated and initialized memory dest + * @return pointer to the memory area or NULL if memory was not allocated (i.e. nothing was + * written to the destination). Also NULL will be returned on possible (re-)allocation + * failure, this case can be identified by non-zero dst->writeb. + **/ +void *mem_dest_own_memory(pgp_dest_t *dst); + +/** @brief mark memory dest as secure, so it will be deallocated securely + * @param dst pre-allocated and initialized memory dest + * @param secure whether memory should be considered as secure or not + * @return void + **/ +void mem_dest_secure_memory(pgp_dest_t *dst, bool secure); + +/** @brief init null destination which silently discards all the output + * @param dst pre-allocated dest structure + * @return RNP_SUCCESS or error code + **/ +rnp_result_t init_null_dest(pgp_dest_t *dst); + +/** @brief reads from source and writes to destination + * @param src initialized source + * @param dst initialized destination + * @param limit sets the maximum amount of bytes to be read, + * returning an error if the source hasn't come to eof after that amount + * if 0, no limit is imposed + * @return RNP_SUCCESS or error code + **/ +rnp_result_t dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit = 0); + +namespace rnp { +/* Temporary wrapper to destruct stack-based pgp_source_t */ +class Source { + protected: + pgp_source_t src_; + + public: + Source(const Source &) = delete; + Source(Source &&) = delete; + + Source() : src_({}) + { + } + + virtual ~Source() + { + src_close(&src_); + } + + virtual pgp_source_t & + src() + { + return src_; + } + + size_t + size() + { + return src().size; + } + + size_t + readb() + { + return src().readb; + } + + bool + eof() + { + return src_eof(&src()); + } + + bool + error() + { + return src_error(&src()); + } +}; + +class MemorySource : public Source { + public: + MemorySource(const MemorySource &) = delete; + MemorySource(MemorySource &&) = delete; + + /** + * @brief Construct memory source object. + * + * @param mem source memory. Must be valid for the whole lifetime of the object. + * @param len size of the memory. + * @param free free memory once processing is finished. + */ + MemorySource(const void *mem, size_t len, bool free) : Source() + { + auto res = init_mem_src(&src_, mem, len, free); + if (res) { + throw std::bad_alloc(); + } + } + + /** + * @brief Construct memory source object + * + * @param vec vector with data. Must be valid for the whole lifetime of the object. + */ + MemorySource(const std::vector &vec) : MemorySource(vec.data(), vec.size(), false) + { + } + + MemorySource(pgp_source_t &src) : Source() + { + auto res = read_mem_src(&src_, &src); + if (res) { + throw rnp::rnp_exception(res); + } + } + + const void * + memory(bool own = false) + { + return mem_src_get_memory(&src_, own); + } +}; + +/* Temporary wrapper to destruct stack-based pgp_dest_t */ +class Dest { + protected: + pgp_dest_t dst_; + bool discard_; + + public: + Dest(const Dest &) = delete; + Dest(Dest &&) = delete; + + Dest() : dst_({}), discard_(false) + { + } + + virtual ~Dest() + { + dst_close(&dst_, discard_); + } + + void + write(const void *buf, size_t len) + { + dst_write(&dst_, buf, len); + } + + void + set_discard(bool discard) + { + discard_ = discard; + } + + pgp_dest_t & + dst() + { + return dst_; + } + + size_t + writeb() + { + return dst_.writeb; + } + + rnp_result_t + werr() + { + return dst_.werr; + } +}; + +class MemoryDest : public Dest { + public: + MemoryDest(const MemoryDest &) = delete; + MemoryDest(MemoryDest &&) = delete; + + MemoryDest(void *mem = NULL, size_t len = 0) : Dest() + { + auto res = init_mem_dest(&dst_, mem, len); + if (res) { + throw std::bad_alloc(); + } + discard_ = true; + } + + void * + memory() + { + return mem_dest_get_memory(&dst_); + } + + void + set_secure(bool secure) + { + mem_dest_secure_memory(&dst_, secure); + } + + std::vector + to_vector() + { + uint8_t *mem = (uint8_t *) memory(); + return std::vector(mem, mem + writeb()); + } +}; +} // namespace rnp + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-ctx.cpp b/comm/third_party/rnp/src/librepgp/stream-ctx.cpp new file mode 100644 index 0000000000..28b5444f45 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-ctx.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "defaults.h" +#include "utils.h" +#include "stream-ctx.h" + +rnp_result_t +rnp_ctx_t::add_encryption_password(const std::string &password, + pgp_hash_alg_t halg, + pgp_symm_alg_t ealg, + size_t iterations) +{ + rnp_symmetric_pass_info_t info = {}; + + info.s2k.usage = PGP_S2KU_ENCRYPTED_AND_HASHED; + info.s2k.specifier = PGP_S2KS_ITERATED_AND_SALTED; + info.s2k.hash_alg = halg; + ctx->rng.get(info.s2k.salt, sizeof(info.s2k.salt)); + if (!iterations) { + iterations = ctx->s2k_iterations(halg); + } + if (!iterations) { + return RNP_ERROR_BAD_PARAMETERS; + } + info.s2k.iterations = pgp_s2k_encode_iterations(iterations); + info.s2k_cipher = ealg; + /* Note: we're relying on the fact that a longer-than-needed key length + * here does not change the entire derived key (it just generates unused + * extra bytes at the end). We derive a key of our maximum supported length, + * which is a bit wasteful. + * + * This is done because we do not yet know what cipher this key will actually + * end up being used with until later. + * + * An alternative would be to keep a list of actual passwords and s2k params, + * and save the key derivation for later. + */ + if (!pgp_s2k_derive_key(&info.s2k, password.c_str(), info.key.data(), info.key.size())) { + return RNP_ERROR_GENERIC; + } + passwords.push_back(info); + return RNP_SUCCESS; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-ctx.h b/comm/third_party/rnp/src/librepgp/stream-ctx.h new file mode 100644 index 0000000000..b9e0c105ec --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-ctx.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2019-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_CTX_H_ +#define STREAM_CTX_H_ + +#include +#include +#include +#include "types.h" +#include +#include +#include "pgp-key.h" +#include "crypto/mem.h" +#include "sec_profile.hpp" + +/* signature info structure */ +typedef struct rnp_signer_info_t { + pgp_key_t * key{}; + pgp_hash_alg_t halg{}; + int64_t sigcreate{}; + uint64_t sigexpire{}; +} rnp_signer_info_t; + +typedef struct rnp_symmetric_pass_info_t { + pgp_s2k_t s2k{}; + pgp_symm_alg_t s2k_cipher{}; + + rnp::secure_array key; +} rnp_symmetric_pass_info_t; + +/** rnp operation context : contains configuration data about the currently ongoing operation. + * + * Common fields which make sense for every operation: + * - overwrite : silently overwrite output file if exists + * - armor : except cleartext signing, which outputs text in clear and always armor signature, + * this controls whether output is armored (base64-encoded). For armor/dearmor operation it + * controls the direction of the conversion (true means enarmor, false - dearmor), + * - rng : random number generator + * - operation : current operation type + * + * For operations with OpenPGP embedded data (i.e. encrypted data and attached signatures): + * - filename, filemtime : to specify information about the contents of literal data packet + * - zalg, zlevel : compression algorithm and level, zlevel = 0 to disable compression + * + * For encryption operation (including encrypt-and-sign): + * - halg : hash algorithm used during key derivation for password-based encryption + * - ealg, aalg, abits : symmetric encryption algorithm and AEAD parameters if used + * - recipients : list of key ids used to encrypt data to + * - passwords : list of passwords used for password-based encryption + * - filename, filemtime, zalg, zlevel : see previous + * + * For signing of any kind (attached, detached, cleartext): + * - clearsign, detached : controls kind of the signed data. Both are mutually-exclusive. + * If both are false then attached signing is used. + * - halg : hash algorithm used to calculate signature(s) + * - signers : list of rnp_signer_info_t structures describing signing key and parameters + * - sigcreate, sigexpire : default signature(s) creation and expiration times + * - filename, filemtime, zalg, zlevel : only for attached signatures, see previous + * + * For data decryption and/or verification there is not much of fields: + * - discard: discard the output data (i.e. just decrypt and/or verify signatures) + * + */ + +typedef struct rnp_ctx_t { + std::string filename{}; /* name of the input file to store in literal data packet */ + int64_t filemtime{}; /* file modification time to store in literal data packet */ + int64_t sigcreate{}; /* signature creation time */ + uint64_t sigexpire{}; /* signature expiration time */ + bool clearsign{}; /* cleartext signature */ + bool detached{}; /* detached signature */ + pgp_hash_alg_t halg{}; /* hash algorithm */ + pgp_symm_alg_t ealg{}; /* encryption algorithm */ + int zalg{}; /* compression algorithm used */ + int zlevel{}; /* compression level */ + pgp_aead_alg_t aalg{}; /* non-zero to use AEAD */ + int abits{}; /* AEAD chunk bits */ + bool overwrite{}; /* allow to overwrite output file if exists */ + bool armor{}; /* whether to use ASCII armor on output */ + bool no_wrap{}; /* do not wrap source in literal data packet */ + std::list recipients{}; /* recipients of the encrypted message */ + std::list passwords{}; /* passwords to encrypt message */ + std::list signers{}; /* keys to which sign message */ + rnp::SecurityContext * ctx{}; /* pointer to rnp::RNG */ + + rnp_ctx_t() = default; + rnp_ctx_t(const rnp_ctx_t &) = delete; + rnp_ctx_t(rnp_ctx_t &&) = delete; + + rnp_ctx_t &operator=(const rnp_ctx_t &) = delete; + rnp_ctx_t &operator=(rnp_ctx_t &&) = delete; + + rnp_result_t add_encryption_password(const std::string &password, + pgp_hash_alg_t halg, + pgp_symm_alg_t ealg, + size_t iterations = 0); +} rnp_ctx_t; + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-def.h b/comm/third_party/rnp/src/librepgp/stream-def.h new file mode 100644 index 0000000000..7a1108f827 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-def.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_DEF_H_ +#define STREAM_DEF_H_ + +#define CT_BUF_LEN 4096 +#define CH_CR ('\r') +#define CH_LF ('\n') +#define CH_EQ ('=') +#define CH_DASH ('-') +#define CH_SPACE (' ') +#define CH_TAB ('\t') +#define CH_COMMA (',') +#define ST_CR ("\r") +#define ST_LF ("\n") +#define ST_CRLF ("\r\n") +#define ST_CRLFCRLF ("\r\n\r\n") +#define ST_DASHSP ("- ") +#define ST_COMMA (",") + +#define ST_DASHES ("-----") +#define ST_ARMOR_BEGIN ("-----BEGIN PGP ") +#define ST_ARMOR_END ("-----END PGP ") +#define ST_CLEAR_BEGIN ("-----BEGIN PGP SIGNED MESSAGE-----") +#define ST_SIG_BEGIN ("\n-----BEGIN PGP SIGNATURE-----") +#define ST_HEADER_VERSION ("Version: ") +#define ST_HEADER_COMMENT ("Comment: ") +#define ST_HEADER_HASH ("Hash: ") +#define ST_HEADER_CHARSET ("Charset: ") +#define ST_FROM ("From") + +/* Preallocated cache length for AEAD encryption/decryption */ +#define PGP_AEAD_CACHE_LEN (PGP_INPUT_CACHE_SIZE + PGP_AEAD_MAX_TAG_LEN) + +/* Maximum OpenPGP packet nesting level */ +#define MAXIMUM_NESTING_LEVEL 32 +#define MAXIMUM_STREAM_PKTS 16 +#define MAXIMUM_ERROR_PKTS 64 + +/* Maximum text line length supported by GnuPG */ +#define MAXIMUM_GNUPG_LINELEN 19995 + +#endif /* !STREAM_DEF_H_ */ diff --git a/comm/third_party/rnp/src/librepgp/stream-dump.cpp b/comm/third_party/rnp/src/librepgp/stream-dump.cpp new file mode 100644 index 0000000000..416f9ae581 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-dump.cpp @@ -0,0 +1,2533 @@ +/* + * Copyright (c) 2018-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#else +#include "uniwin.h" +#endif +#include +#include "time-utils.h" +#include "stream-def.h" +#include "stream-dump.h" +#include "stream-armor.h" +#include "stream-packet.h" +#include "stream-parse.h" +#include "types.h" +#include "ctype.h" +#include "crypto/symmetric.h" +#include "crypto/s2k.h" +#include "fingerprint.h" +#include "pgp-key.h" +#include "crypto.h" +#include "json-utils.h" +#include + +static const id_str_pair packet_tag_map[] = { + {PGP_PKT_RESERVED, "Reserved"}, + {PGP_PKT_PK_SESSION_KEY, "Public-Key Encrypted Session Key"}, + {PGP_PKT_SIGNATURE, "Signature"}, + {PGP_PKT_SK_SESSION_KEY, "Symmetric-Key Encrypted Session Key"}, + {PGP_PKT_ONE_PASS_SIG, "One-Pass Signature"}, + {PGP_PKT_SECRET_KEY, "Secret Key"}, + {PGP_PKT_PUBLIC_KEY, "Public Key"}, + {PGP_PKT_SECRET_SUBKEY, "Secret Subkey"}, + {PGP_PKT_COMPRESSED, "Compressed Data"}, + {PGP_PKT_SE_DATA, "Symmetrically Encrypted Data"}, + {PGP_PKT_MARKER, "Marker"}, + {PGP_PKT_LITDATA, "Literal Data"}, + {PGP_PKT_TRUST, "Trust"}, + {PGP_PKT_USER_ID, "User ID"}, + {PGP_PKT_PUBLIC_SUBKEY, "Public Subkey"}, + {PGP_PKT_RESERVED2, "reserved2"}, + {PGP_PKT_RESERVED3, "reserved3"}, + {PGP_PKT_USER_ATTR, "User Attribute"}, + {PGP_PKT_SE_IP_DATA, "Symmetric Encrypted and Integrity Protected Data"}, + {PGP_PKT_MDC, "Modification Detection Code"}, + {PGP_PKT_AEAD_ENCRYPTED, "AEAD Encrypted Data Packet"}, + {0x00, NULL}, +}; + +static const id_str_pair sig_type_map[] = { + {PGP_SIG_BINARY, "Signature of a binary document"}, + {PGP_SIG_TEXT, "Signature of a canonical text document"}, + {PGP_SIG_STANDALONE, "Standalone signature"}, + {PGP_CERT_GENERIC, "Generic User ID certification"}, + {PGP_CERT_PERSONA, "Personal User ID certification"}, + {PGP_CERT_CASUAL, "Casual User ID certification"}, + {PGP_CERT_POSITIVE, "Positive User ID certification"}, + {PGP_SIG_SUBKEY, "Subkey Binding Signature"}, + {PGP_SIG_PRIMARY, "Primary Key Binding Signature"}, + {PGP_SIG_DIRECT, "Direct-key signature"}, + {PGP_SIG_REV_KEY, "Key revocation signature"}, + {PGP_SIG_REV_SUBKEY, "Subkey revocation signature"}, + {PGP_SIG_REV_CERT, "Certification revocation signature"}, + {PGP_SIG_TIMESTAMP, "Timestamp signature"}, + {PGP_SIG_3RD_PARTY, "Third-Party Confirmation signature"}, + {0x00, NULL}, +}; + +static const id_str_pair sig_subpkt_type_map[] = { + {PGP_SIG_SUBPKT_CREATION_TIME, "signature creation time"}, + {PGP_SIG_SUBPKT_EXPIRATION_TIME, "signature expiration time"}, + {PGP_SIG_SUBPKT_EXPORT_CERT, "exportable certification"}, + {PGP_SIG_SUBPKT_TRUST, "trust signature"}, + {PGP_SIG_SUBPKT_REGEXP, "regular expression"}, + {PGP_SIG_SUBPKT_REVOCABLE, "revocable"}, + {PGP_SIG_SUBPKT_KEY_EXPIRY, "key expiration time"}, + {PGP_SIG_SUBPKT_PREFERRED_SKA, "preferred symmetric algorithms"}, + {PGP_SIG_SUBPKT_REVOCATION_KEY, "revocation key"}, + {PGP_SIG_SUBPKT_ISSUER_KEY_ID, "issuer key ID"}, + {PGP_SIG_SUBPKT_NOTATION_DATA, "notation data"}, + {PGP_SIG_SUBPKT_PREFERRED_HASH, "preferred hash algorithms"}, + {PGP_SIG_SUBPKT_PREF_COMPRESS, "preferred compression algorithms"}, + {PGP_SIG_SUBPKT_KEYSERV_PREFS, "key server preferences"}, + {PGP_SIG_SUBPKT_PREF_KEYSERV, "preferred key server"}, + {PGP_SIG_SUBPKT_PRIMARY_USER_ID, "primary user ID"}, + {PGP_SIG_SUBPKT_POLICY_URI, "policy URI"}, + {PGP_SIG_SUBPKT_KEY_FLAGS, "key flags"}, + {PGP_SIG_SUBPKT_SIGNERS_USER_ID, "signer's user ID"}, + {PGP_SIG_SUBPKT_REVOCATION_REASON, "reason for revocation"}, + {PGP_SIG_SUBPKT_FEATURES, "features"}, + {PGP_SIG_SUBPKT_SIGNATURE_TARGET, "signature target"}, + {PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE, "embedded signature"}, + {PGP_SIG_SUBPKT_ISSUER_FPR, "issuer fingerprint"}, + {PGP_SIG_SUBPKT_PREFERRED_AEAD, "preferred AEAD algorithms"}, + {0x00, NULL}, +}; + +static const id_str_pair key_type_map[] = { + {PGP_PKT_SECRET_KEY, "Secret key"}, + {PGP_PKT_PUBLIC_KEY, "Public key"}, + {PGP_PKT_SECRET_SUBKEY, "Secret subkey"}, + {PGP_PKT_PUBLIC_SUBKEY, "Public subkey"}, + {0x00, NULL}, +}; + +static const id_str_pair pubkey_alg_map[] = { + {PGP_PKA_RSA, "RSA (Encrypt or Sign)"}, + {PGP_PKA_RSA_ENCRYPT_ONLY, "RSA (Encrypt-Only)"}, + {PGP_PKA_RSA_SIGN_ONLY, "RSA (Sign-Only)"}, + {PGP_PKA_ELGAMAL, "Elgamal (Encrypt-Only)"}, + {PGP_PKA_DSA, "DSA"}, + {PGP_PKA_ECDH, "ECDH"}, + {PGP_PKA_ECDSA, "ECDSA"}, + {PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN, "Elgamal"}, + {PGP_PKA_RESERVED_DH, "Reserved for DH (X9.42)"}, + {PGP_PKA_EDDSA, "EdDSA"}, + {PGP_PKA_SM2, "SM2"}, + {0x00, NULL}, +}; + +static const id_str_pair symm_alg_map[] = { + {PGP_SA_PLAINTEXT, "Plaintext"}, + {PGP_SA_IDEA, "IDEA"}, + {PGP_SA_TRIPLEDES, "TripleDES"}, + {PGP_SA_CAST5, "CAST5"}, + {PGP_SA_BLOWFISH, "Blowfish"}, + {PGP_SA_AES_128, "AES-128"}, + {PGP_SA_AES_192, "AES-192"}, + {PGP_SA_AES_256, "AES-256"}, + {PGP_SA_TWOFISH, "Twofish"}, + {PGP_SA_CAMELLIA_128, "Camellia-128"}, + {PGP_SA_CAMELLIA_192, "Camellia-192"}, + {PGP_SA_CAMELLIA_256, "Camellia-256"}, + {PGP_SA_SM4, "SM4"}, + {0x00, NULL}, +}; + +static const id_str_pair hash_alg_map[] = { + {PGP_HASH_MD5, "MD5"}, + {PGP_HASH_SHA1, "SHA1"}, + {PGP_HASH_RIPEMD, "RIPEMD160"}, + {PGP_HASH_SHA256, "SHA256"}, + {PGP_HASH_SHA384, "SHA384"}, + {PGP_HASH_SHA512, "SHA512"}, + {PGP_HASH_SHA224, "SHA224"}, + {PGP_HASH_SM3, "SM3"}, + {PGP_HASH_SHA3_256, "SHA3-256"}, + {PGP_HASH_SHA3_512, "SHA3-512"}, + {0x00, NULL}, +}; + +static const id_str_pair z_alg_map[] = { + {PGP_C_NONE, "Uncompressed"}, + {PGP_C_ZIP, "ZIP"}, + {PGP_C_ZLIB, "ZLib"}, + {PGP_C_BZIP2, "BZip2"}, + {0x00, NULL}, +}; + +static const id_str_pair aead_alg_map[] = { + {PGP_AEAD_NONE, "None"}, + {PGP_AEAD_EAX, "EAX"}, + {PGP_AEAD_OCB, "OCB"}, + {0x00, NULL}, +}; + +static const id_str_pair revoc_reason_map[] = { + {PGP_REVOCATION_NO_REASON, "No reason"}, + {PGP_REVOCATION_SUPERSEDED, "Superseded"}, + {PGP_REVOCATION_COMPROMISED, "Compromised"}, + {PGP_REVOCATION_RETIRED, "Retired"}, + {PGP_REVOCATION_NO_LONGER_VALID, "No longer valid"}, + {0x00, NULL}, +}; + +typedef struct pgp_dest_indent_param_t { + int level; + bool lstart; + pgp_dest_t *writedst; +} pgp_dest_indent_param_t; + +static rnp_result_t +indent_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_indent_param_t *param = (pgp_dest_indent_param_t *) dst->param; + const char * line = (const char *) buf; + char indent[4] = {' ', ' ', ' ', ' '}; + + if (!len) { + return RNP_SUCCESS; + } + + do { + if (param->lstart) { + for (int i = 0; i < param->level; i++) { + dst_write(param->writedst, indent, sizeof(indent)); + } + param->lstart = false; + } + + for (size_t i = 0; i < len; i++) { + if ((line[i] == '\n') || (i == len - 1)) { + dst_write(param->writedst, line, i + 1); + param->lstart = line[i] == '\n'; + line += i + 1; + len -= i + 1; + break; + } + } + } while (len > 0); + + return RNP_SUCCESS; +} + +static void +indent_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_indent_param_t *param = (pgp_dest_indent_param_t *) dst->param; + if (!param) { + return; + } + + free(param); +} + +static rnp_result_t +init_indent_dest(pgp_dest_t *dst, pgp_dest_t *origdst) +{ + pgp_dest_indent_param_t *param; + + if (!init_dst_common(dst, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + dst->write = indent_dst_write; + dst->close = indent_dst_close; + dst->finish = NULL; + dst->no_cache = true; + param = (pgp_dest_indent_param_t *) dst->param; + param->writedst = origdst; + param->lstart = true; + + return RNP_SUCCESS; +} + +static void +indent_dest_increase(pgp_dest_t *dst) +{ + pgp_dest_indent_param_t *param = (pgp_dest_indent_param_t *) dst->param; + param->level++; +} + +static void +indent_dest_decrease(pgp_dest_t *dst) +{ + pgp_dest_indent_param_t *param = (pgp_dest_indent_param_t *) dst->param; + if (param->level > 0) { + param->level--; + } +} + +static void +indent_dest_set(pgp_dest_t *dst, int level) +{ + pgp_dest_indent_param_t *param = (pgp_dest_indent_param_t *) dst->param; + param->level = level; +} + +static size_t +vsnprinthex(char *str, size_t slen, const uint8_t *buf, size_t buflen) +{ + static const char *hexes = "0123456789abcdef"; + size_t idx = 0; + + for (size_t i = 0; (i < buflen) && (i < (slen - 1) / 2); i++) { + str[idx++] = hexes[buf[i] >> 4]; + str[idx++] = hexes[buf[i] & 0xf]; + } + str[idx] = '\0'; + return buflen * 2; +} + +static void +dst_print_mpi(pgp_dest_t *dst, const char *name, pgp_mpi_t *mpi, bool dumpbin) +{ + char hex[5000]; + if (!dumpbin) { + dst_printf(dst, "%s: %d bits\n", name, (int) mpi_bits(mpi)); + } else { + vsnprinthex(hex, sizeof(hex), mpi->mpi, mpi->len); + dst_printf(dst, "%s: %d bits, %s\n", name, (int) mpi_bits(mpi), hex); + } +} + +static void +dst_print_palg(pgp_dest_t *dst, const char *name, pgp_pubkey_alg_t palg) +{ + const char *palg_name = id_str_pair::lookup(pubkey_alg_map, palg, "Unknown"); + if (!name) { + name = "public key algorithm"; + } + + dst_printf(dst, "%s: %d (%s)\n", name, (int) palg, palg_name); +} + +static void +dst_print_halg(pgp_dest_t *dst, const char *name, pgp_hash_alg_t halg) +{ + const char *halg_name = id_str_pair::lookup(hash_alg_map, halg, "Unknown"); + if (!name) { + name = "hash algorithm"; + } + + dst_printf(dst, "%s: %d (%s)\n", name, (int) halg, halg_name); +} + +static void +dst_print_salg(pgp_dest_t *dst, const char *name, pgp_symm_alg_t salg) +{ + const char *salg_name = id_str_pair::lookup(symm_alg_map, salg, "Unknown"); + if (!name) { + name = "symmetric algorithm"; + } + + dst_printf(dst, "%s: %d (%s)\n", name, (int) salg, salg_name); +} + +static void +dst_print_aalg(pgp_dest_t *dst, const char *name, pgp_aead_alg_t aalg) +{ + const char *aalg_name = id_str_pair::lookup(aead_alg_map, aalg, "Unknown"); + if (!name) { + name = "aead algorithm"; + } + + dst_printf(dst, "%s: %d (%s)\n", name, (int) aalg, aalg_name); +} + +static void +dst_print_zalg(pgp_dest_t *dst, const char *name, pgp_compression_type_t zalg) +{ + const char *zalg_name = id_str_pair::lookup(z_alg_map, zalg, "Unknown"); + if (!name) { + name = "compression algorithm"; + } + + dst_printf(dst, "%s: %d (%s)\n", name, (int) zalg, zalg_name); +} + +static void +dst_print_raw(pgp_dest_t *dst, const char *name, const void *data, size_t len) +{ + dst_printf(dst, "%s: ", name); + dst_write(dst, data, len); + dst_printf(dst, "\n"); +} + +static void +dst_print_algs( + pgp_dest_t *dst, const char *name, uint8_t *algs, size_t algc, const id_str_pair map[]) +{ + if (!name) { + name = "algorithms"; + } + + dst_printf(dst, "%s: ", name); + for (size_t i = 0; i < algc; i++) { + dst_printf( + dst, "%s%s", id_str_pair::lookup(map, algs[i], "Unknown"), i + 1 < algc ? ", " : ""); + } + dst_printf(dst, " ("); + for (size_t i = 0; i < algc; i++) { + dst_printf(dst, "%d%s", (int) algs[i], i + 1 < algc ? ", " : ""); + } + dst_printf(dst, ")\n"); +} + +static void +dst_print_sig_type(pgp_dest_t *dst, const char *name, pgp_sig_type_t sigtype) +{ + const char *sig_name = id_str_pair::lookup(sig_type_map, sigtype, "Unknown"); + if (!name) { + name = "signature type"; + } + dst_printf(dst, "%s: %d (%s)\n", name, (int) sigtype, sig_name); +} + +static void +dst_print_hex(pgp_dest_t *dst, const char *name, const uint8_t *data, size_t len, bool bytes) +{ + char hex[512]; + vsnprinthex(hex, sizeof(hex), data, len); + if (bytes) { + dst_printf(dst, "%s: 0x%s (%d bytes)\n", name, hex, (int) len); + } else { + dst_printf(dst, "%s: 0x%s\n", name, hex); + } +} + +static void +dst_print_keyid(pgp_dest_t *dst, const char *name, const pgp_key_id_t &keyid) +{ + if (!name) { + name = "key id"; + } + dst_print_hex(dst, name, keyid.data(), keyid.size(), false); +} + +static void +dst_print_s2k(pgp_dest_t *dst, pgp_s2k_t *s2k) +{ + dst_printf(dst, "s2k specifier: %d\n", (int) s2k->specifier); + if ((s2k->specifier == PGP_S2KS_EXPERIMENTAL) && s2k->gpg_ext_num) { + dst_printf(dst, "GPG extension num: %d\n", (int) s2k->gpg_ext_num); + if (s2k->gpg_ext_num == PGP_S2K_GPG_SMARTCARD) { + static_assert(sizeof(s2k->gpg_serial) == 16, "invalid s2k->gpg_serial size"); + size_t slen = s2k->gpg_serial_len > 16 ? 16 : s2k->gpg_serial_len; + dst_print_hex(dst, "card serial number", s2k->gpg_serial, slen, true); + } + return; + } + if (s2k->specifier == PGP_S2KS_EXPERIMENTAL) { + dst_print_hex(dst, + "Unknown experimental s2k", + s2k->experimental.data(), + s2k->experimental.size(), + true); + return; + } + dst_print_halg(dst, "s2k hash algorithm", s2k->hash_alg); + if ((s2k->specifier == PGP_S2KS_SALTED) || + (s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED)) { + dst_print_hex(dst, "s2k salt", s2k->salt, PGP_SALT_SIZE, false); + } + if (s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED) { + size_t real_iter = pgp_s2k_decode_iterations(s2k->iterations); + dst_printf(dst, "s2k iterations: %zu (encoded as %u)\n", real_iter, s2k->iterations); + } +} + +static void +dst_print_time(pgp_dest_t *dst, const char *name, uint32_t time) +{ + if (!name) { + name = "time"; + } + auto str = rnp_ctime(time).substr(0, 24); + dst_printf(dst, + "%s: %zu (%s%s)\n", + name, + (size_t) time, + rnp_y2k38_warning(time) ? ">=" : "", + str.c_str()); +} + +static void +dst_print_expiration(pgp_dest_t *dst, const char *name, uint32_t seconds) +{ + if (!name) { + name = "expiration"; + } + if (seconds) { + int days = seconds / (24 * 60 * 60); + dst_printf(dst, "%s: %zu seconds (%d days)\n", name, (size_t) seconds, days); + } else { + dst_printf(dst, "%s: 0 (never)\n", name); + } +} + +#define LINELEN 16 + +static void +dst_hexdump(pgp_dest_t *dst, const uint8_t *src, size_t length) +{ + size_t i; + char line[LINELEN + 1]; + + for (i = 0; i < length; i++) { + if (i % LINELEN == 0) { + dst_printf(dst, "%.5zu | ", i); + } + dst_printf(dst, "%.02x ", (uint8_t) src[i]); + line[i % LINELEN] = (isprint(src[i])) ? src[i] : '.'; + if (i % LINELEN == LINELEN - 1) { + line[LINELEN] = 0x0; + dst_printf(dst, " | %s\n", line); + } + } + if (i % LINELEN != 0) { + for (; i % LINELEN != 0; i++) { + dst_printf(dst, " "); + line[i % LINELEN] = ' '; + } + line[LINELEN] = 0x0; + dst_printf(dst, " | %s\n", line); + } +} + +static rnp_result_t stream_dump_packets_raw(rnp_dump_ctx_t *ctx, + pgp_source_t * src, + pgp_dest_t * dst); +static void stream_dump_signature_pkt(rnp_dump_ctx_t * ctx, + pgp_signature_t *sig, + pgp_dest_t * dst); + +static void +signature_dump_subpacket(rnp_dump_ctx_t *ctx, pgp_dest_t *dst, const pgp_sig_subpkt_t &subpkt) +{ + const char *sname = id_str_pair::lookup(sig_subpkt_type_map, subpkt.type, "Unknown"); + + switch (subpkt.type) { + case PGP_SIG_SUBPKT_CREATION_TIME: + dst_print_time(dst, sname, subpkt.fields.create); + break; + case PGP_SIG_SUBPKT_EXPIRATION_TIME: + dst_print_expiration(dst, sname, subpkt.fields.expiry); + break; + case PGP_SIG_SUBPKT_EXPORT_CERT: + dst_printf(dst, "%s: %d\n", sname, (int) subpkt.fields.exportable); + break; + case PGP_SIG_SUBPKT_TRUST: + dst_printf(dst, + "%s: amount %d, level %d\n", + sname, + (int) subpkt.fields.trust.amount, + (int) subpkt.fields.trust.level); + break; + case PGP_SIG_SUBPKT_REGEXP: + dst_print_raw(dst, sname, subpkt.fields.regexp.str, subpkt.fields.regexp.len); + break; + case PGP_SIG_SUBPKT_REVOCABLE: + dst_printf(dst, "%s: %d\n", sname, (int) subpkt.fields.revocable); + break; + case PGP_SIG_SUBPKT_KEY_EXPIRY: + dst_print_expiration(dst, sname, subpkt.fields.expiry); + break; + case PGP_SIG_SUBPKT_PREFERRED_SKA: + dst_print_algs(dst, + "preferred symmetric algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + symm_alg_map); + break; + case PGP_SIG_SUBPKT_REVOCATION_KEY: + dst_printf(dst, "%s\n", sname); + dst_printf(dst, "class: %d\n", (int) subpkt.fields.revocation_key.klass); + dst_print_palg(dst, NULL, subpkt.fields.revocation_key.pkalg); + dst_print_hex( + dst, "fingerprint", subpkt.fields.revocation_key.fp, PGP_FINGERPRINT_SIZE, true); + break; + case PGP_SIG_SUBPKT_ISSUER_KEY_ID: + dst_print_hex(dst, sname, subpkt.fields.issuer, PGP_KEY_ID_SIZE, false); + break; + case PGP_SIG_SUBPKT_NOTATION_DATA: { + std::string name(subpkt.fields.notation.name, + subpkt.fields.notation.name + subpkt.fields.notation.nlen); + std::vector value(subpkt.fields.notation.value, + subpkt.fields.notation.value + subpkt.fields.notation.vlen); + if (subpkt.fields.notation.human) { + dst_printf(dst, "%s: %s = ", sname, name.c_str()); + dst_printf(dst, "%.*s\n", (int) value.size(), (char *) value.data()); + } else { + char hex[64]; + vsnprinthex(hex, sizeof(hex), value.data(), value.size()); + dst_printf(dst, "%s: %s = ", sname, name.c_str()); + dst_printf(dst, "0x%s (%zu bytes)\n", hex, value.size()); + } + break; + } + case PGP_SIG_SUBPKT_PREFERRED_HASH: + dst_print_algs(dst, + "preferred hash algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + hash_alg_map); + break; + case PGP_SIG_SUBPKT_PREF_COMPRESS: + dst_print_algs(dst, + "preferred compression algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + z_alg_map); + break; + case PGP_SIG_SUBPKT_KEYSERV_PREFS: + dst_printf(dst, "%s\n", sname); + dst_printf(dst, "no-modify: %d\n", (int) subpkt.fields.ks_prefs.no_modify); + break; + case PGP_SIG_SUBPKT_PREF_KEYSERV: + dst_print_raw( + dst, sname, subpkt.fields.preferred_ks.uri, subpkt.fields.preferred_ks.len); + break; + case PGP_SIG_SUBPKT_PRIMARY_USER_ID: + dst_printf(dst, "%s: %d\n", sname, (int) subpkt.fields.primary_uid); + break; + case PGP_SIG_SUBPKT_POLICY_URI: + dst_print_raw(dst, sname, subpkt.fields.policy.uri, subpkt.fields.policy.len); + break; + case PGP_SIG_SUBPKT_KEY_FLAGS: { + uint8_t flg = subpkt.fields.key_flags; + dst_printf(dst, "%s: 0x%02x ( ", sname, flg); + dst_printf(dst, "%s", flg ? "" : "none"); + dst_printf(dst, "%s", flg & PGP_KF_CERTIFY ? "certify " : ""); + dst_printf(dst, "%s", flg & PGP_KF_SIGN ? "sign " : ""); + dst_printf(dst, "%s", flg & PGP_KF_ENCRYPT_COMMS ? "encrypt_comm " : ""); + dst_printf(dst, "%s", flg & PGP_KF_ENCRYPT_STORAGE ? "encrypt_storage " : ""); + dst_printf(dst, "%s", flg & PGP_KF_SPLIT ? "split " : ""); + dst_printf(dst, "%s", flg & PGP_KF_AUTH ? "auth " : ""); + dst_printf(dst, "%s", flg & PGP_KF_SHARED ? "shared " : ""); + dst_printf(dst, ")\n"); + break; + } + case PGP_SIG_SUBPKT_SIGNERS_USER_ID: + dst_print_raw(dst, sname, subpkt.fields.signer.uid, subpkt.fields.signer.len); + break; + case PGP_SIG_SUBPKT_REVOCATION_REASON: { + int code = subpkt.fields.revocation_reason.code; + const char *reason = id_str_pair::lookup(revoc_reason_map, code, "Unknown"); + dst_printf(dst, "%s: %d (%s)\n", sname, code, reason); + dst_print_raw(dst, + "message", + subpkt.fields.revocation_reason.str, + subpkt.fields.revocation_reason.len); + break; + } + case PGP_SIG_SUBPKT_FEATURES: + dst_printf(dst, "%s: 0x%02x ( ", sname, subpkt.data[0]); + dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_MDC ? "mdc " : ""); + dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_AEAD ? "aead " : ""); + dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_V5 ? "v5 keys " : ""); + dst_printf(dst, ")\n"); + break; + case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE: + dst_printf(dst, "%s:\n", sname); + stream_dump_signature_pkt(ctx, subpkt.fields.sig, dst); + break; + case PGP_SIG_SUBPKT_ISSUER_FPR: + dst_print_hex( + dst, sname, subpkt.fields.issuer_fp.fp, subpkt.fields.issuer_fp.len, true); + break; + case PGP_SIG_SUBPKT_PREFERRED_AEAD: + dst_print_algs(dst, + "preferred aead algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + aead_alg_map); + break; + default: + if (!ctx->dump_packets) { + indent_dest_increase(dst); + dst_hexdump(dst, subpkt.data, subpkt.len); + indent_dest_decrease(dst); + } + } +} + +static void +signature_dump_subpackets(rnp_dump_ctx_t * ctx, + pgp_dest_t * dst, + pgp_signature_t *sig, + bool hashed) +{ + bool empty = true; + + for (auto &subpkt : sig->subpkts) { + if (subpkt.hashed != hashed) { + continue; + } + empty = false; + dst_printf(dst, ":type %d, len %d", (int) subpkt.type, (int) subpkt.len); + dst_printf(dst, "%s\n", subpkt.critical ? ", critical" : ""); + if (ctx->dump_packets) { + dst_printf(dst, ":subpacket contents:\n"); + indent_dest_increase(dst); + dst_hexdump(dst, subpkt.data, subpkt.len); + indent_dest_decrease(dst); + } + signature_dump_subpacket(ctx, dst, subpkt); + } + + if (empty) { + dst_printf(dst, "none\n"); + } +} + +static void +stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t *dst) +{ + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) sig->version); + dst_print_sig_type(dst, "type", sig->type()); + if (sig->version < PGP_V4) { + dst_print_time(dst, "creation time", sig->creation_time); + dst_print_keyid(dst, "signing key id", sig->signer); + } + dst_print_palg(dst, NULL, sig->palg); + dst_print_halg(dst, NULL, sig->halg); + + if (sig->version >= PGP_V4) { + dst_printf(dst, "hashed subpackets:\n"); + indent_dest_increase(dst); + signature_dump_subpackets(ctx, dst, sig, true); + indent_dest_decrease(dst); + + dst_printf(dst, "unhashed subpackets:\n"); + indent_dest_increase(dst); + signature_dump_subpackets(ctx, dst, sig, false); + indent_dest_decrease(dst); + } + + dst_print_hex(dst, "lbits", sig->lbits, sizeof(sig->lbits), false); + dst_printf(dst, "signature material:\n"); + indent_dest_increase(dst); + + pgp_signature_material_t material = {}; + try { + sig->parse_material(material); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return; + } + switch (sig->palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + dst_print_mpi(dst, "rsa s", &material.rsa.s, ctx->dump_mpi); + break; + case PGP_PKA_DSA: + dst_print_mpi(dst, "dsa r", &material.dsa.r, ctx->dump_mpi); + dst_print_mpi(dst, "dsa s", &material.dsa.s, ctx->dump_mpi); + break; + case PGP_PKA_EDDSA: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + dst_print_mpi(dst, "ecc r", &material.ecc.r, ctx->dump_mpi); + dst_print_mpi(dst, "ecc s", &material.ecc.s, ctx->dump_mpi); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + dst_print_mpi(dst, "eg r", &material.eg.r, ctx->dump_mpi); + dst_print_mpi(dst, "eg s", &material.eg.s, ctx->dump_mpi); + break; + default: + dst_printf(dst, "unknown algorithm\n"); + } + indent_dest_decrease(dst); + indent_dest_decrease(dst); +} + +static rnp_result_t +stream_dump_signature(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_signature_t sig; + rnp_result_t ret; + + dst_printf(dst, "Signature packet\n"); + try { + ret = sig.parse(*src); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + } + if (ret) { + indent_dest_increase(dst); + dst_printf(dst, "failed to parse\n"); + indent_dest_decrease(dst); + return ret; + } + stream_dump_signature_pkt(ctx, &sig, dst); + return ret; +} + +static rnp_result_t +stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_key_pkt_t key; + rnp_result_t ret; + pgp_fingerprint_t keyfp = {}; + + try { + ret = key.parse(*src); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + dst_printf(dst, "%s packet\n", id_str_pair::lookup(key_type_map, key.tag, "Unknown")); + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) key.version); + dst_print_time(dst, "creation time", key.creation_time); + if (key.version < PGP_V4) { + dst_printf(dst, "v3 validity days: %d\n", (int) key.v3_days); + } + dst_print_palg(dst, NULL, key.alg); + dst_printf(dst, "public key material:\n"); + indent_dest_increase(dst); + + switch (key.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + dst_print_mpi(dst, "rsa n", &key.material.rsa.n, ctx->dump_mpi); + dst_print_mpi(dst, "rsa e", &key.material.rsa.e, ctx->dump_mpi); + break; + case PGP_PKA_DSA: + dst_print_mpi(dst, "dsa p", &key.material.dsa.p, ctx->dump_mpi); + dst_print_mpi(dst, "dsa q", &key.material.dsa.q, ctx->dump_mpi); + dst_print_mpi(dst, "dsa g", &key.material.dsa.g, ctx->dump_mpi); + dst_print_mpi(dst, "dsa y", &key.material.dsa.y, ctx->dump_mpi); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + dst_print_mpi(dst, "eg p", &key.material.eg.p, ctx->dump_mpi); + dst_print_mpi(dst, "eg g", &key.material.eg.g, ctx->dump_mpi); + dst_print_mpi(dst, "eg y", &key.material.eg.y, ctx->dump_mpi); + break; + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: { + const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); + dst_print_mpi(dst, "ecc p", &key.material.ec.p, ctx->dump_mpi); + dst_printf(dst, "ecc curve: %s\n", cdesc ? cdesc->pgp_name : "unknown"); + break; + } + case PGP_PKA_ECDH: { + const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); + dst_print_mpi(dst, "ecdh p", &key.material.ec.p, ctx->dump_mpi); + dst_printf(dst, "ecdh curve: %s\n", cdesc ? cdesc->pgp_name : "unknown"); + dst_print_halg(dst, "ecdh hash algorithm", key.material.ec.kdf_hash_alg); + dst_printf(dst, "ecdh key wrap algorithm: %d\n", (int) key.material.ec.key_wrap_alg); + break; + } + default: + dst_printf(dst, "unknown public key algorithm\n"); + } + indent_dest_decrease(dst); + + if (is_secret_key_pkt(key.tag)) { + dst_printf(dst, "secret key material:\n"); + indent_dest_increase(dst); + + dst_printf(dst, "s2k usage: %d\n", (int) key.sec_protection.s2k.usage); + if ((key.sec_protection.s2k.usage == PGP_S2KU_ENCRYPTED) || + (key.sec_protection.s2k.usage == PGP_S2KU_ENCRYPTED_AND_HASHED)) { + dst_print_salg(dst, NULL, key.sec_protection.symm_alg); + dst_print_s2k(dst, &key.sec_protection.s2k); + if (key.sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL) { + size_t bl_size = pgp_block_size(key.sec_protection.symm_alg); + if (bl_size) { + dst_print_hex(dst, "cipher iv", key.sec_protection.iv, bl_size, true); + } else { + dst_printf(dst, "cipher iv: unknown algorithm\n"); + } + } + dst_printf(dst, "encrypted secret key data: %d bytes\n", (int) key.sec_len); + } + + if (!key.sec_protection.s2k.usage) { + dst_printf(dst, "cleartext secret key data: %d bytes\n", (int) key.sec_len); + } + indent_dest_decrease(dst); + } + + pgp_key_id_t keyid = {}; + if (!pgp_keyid(keyid, key)) { + dst_print_hex(dst, "keyid", keyid.data(), keyid.size(), false); + } else { + dst_printf(dst, "keyid: failed to calculate"); + } + + if ((key.version > PGP_V3) && (ctx->dump_grips)) { + if (!pgp_fingerprint(keyfp, key)) { + dst_print_hex(dst, "fingerprint", keyfp.fingerprint, keyfp.length, false); + } else { + dst_printf(dst, "fingerprint: failed to calculate"); + } + } + + if (ctx->dump_grips) { + pgp_key_grip_t grip; + if (rnp_key_store_get_key_grip(&key.material, grip)) { + dst_print_hex(dst, "grip", grip.data(), grip.size(), false); + } else { + dst_printf(dst, "grip: failed to calculate"); + } + } + + indent_dest_decrease(dst); + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_userid(pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_userid_pkt_t uid; + rnp_result_t ret; + const char * utype; + + try { + ret = uid.parse(*src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + switch (uid.tag) { + case PGP_PKT_USER_ID: + utype = "UserID"; + break; + case PGP_PKT_USER_ATTR: + utype = "UserAttr"; + break; + default: + utype = "Unknown user id"; + } + + dst_printf(dst, "%s packet\n", utype); + indent_dest_increase(dst); + + switch (uid.tag) { + case PGP_PKT_USER_ID: + dst_printf(dst, "id: "); + dst_write(dst, uid.uid, uid.uid_len); + dst_printf(dst, "\n"); + break; + case PGP_PKT_USER_ATTR: + dst_printf(dst, "id: (%d bytes of data)\n", (int) uid.uid_len); + break; + default:; + } + + indent_dest_decrease(dst); + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_pk_sesskey_t pkey; + pgp_encrypted_material_t material; + rnp_result_t ret; + + try { + ret = pkey.parse(*src); + if (!pkey.parse_material(material)) { + ret = RNP_ERROR_BAD_FORMAT; + } + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + dst_printf(dst, "Public-key encrypted session key packet\n"); + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) pkey.version); + dst_print_keyid(dst, NULL, pkey.key_id); + dst_print_palg(dst, NULL, pkey.alg); + dst_printf(dst, "encrypted material:\n"); + indent_dest_increase(dst); + + switch (pkey.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + dst_print_mpi(dst, "rsa m", &material.rsa.m, ctx->dump_mpi); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + dst_print_mpi(dst, "eg g", &material.eg.g, ctx->dump_mpi); + dst_print_mpi(dst, "eg m", &material.eg.m, ctx->dump_mpi); + break; + case PGP_PKA_SM2: + dst_print_mpi(dst, "sm2 m", &material.sm2.m, ctx->dump_mpi); + break; + case PGP_PKA_ECDH: + dst_print_mpi(dst, "ecdh p", &material.ecdh.p, ctx->dump_mpi); + if (ctx->dump_mpi) { + dst_print_hex(dst, "ecdh m", material.ecdh.m, material.ecdh.mlen, true); + } else { + dst_printf(dst, "ecdh m: %d bytes\n", (int) material.ecdh.mlen); + } + break; + default: + dst_printf(dst, "unknown public key algorithm\n"); + } + + indent_dest_decrease(dst); + indent_dest_decrease(dst); + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_sk_session_key(pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_sk_sesskey_t skey; + rnp_result_t ret; + + try { + ret = skey.parse(*src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + dst_printf(dst, "Symmetric-key encrypted session key packet\n"); + indent_dest_increase(dst); + dst_printf(dst, "version: %d\n", (int) skey.version); + dst_print_salg(dst, NULL, skey.alg); + if (skey.version == PGP_SKSK_V5) { + dst_print_aalg(dst, NULL, skey.aalg); + } + dst_print_s2k(dst, &skey.s2k); + if (skey.version == PGP_SKSK_V5) { + dst_print_hex(dst, "aead iv", skey.iv, skey.ivlen, true); + } + dst_print_hex(dst, "encrypted key", skey.enckey, skey.enckeylen, true); + indent_dest_decrease(dst); + + return RNP_SUCCESS; +} + +static bool +stream_dump_get_aead_hdr(pgp_source_t *src, pgp_aead_hdr_t *hdr) +{ + pgp_dest_t encdst = {}; + uint8_t encpkt[64] = {}; + + if (init_mem_dest(&encdst, &encpkt, sizeof(encpkt))) { + return false; + } + mem_dest_discard_overflow(&encdst, true); + + if (stream_read_packet(src, &encdst)) { + dst_close(&encdst, false); + return false; + } + size_t len = std::min(encdst.writeb, sizeof(encpkt)); + dst_close(&encdst, false); + + pgp_source_t memsrc = {}; + if (init_mem_src(&memsrc, encpkt, len, false)) { + return false; + } + bool res = get_aead_src_hdr(&memsrc, hdr); + src_close(&memsrc); + return res; +} + +static rnp_result_t +stream_dump_aead_encrypted(pgp_source_t *src, pgp_dest_t *dst) +{ + dst_printf(dst, "AEAD-encrypted data packet\n"); + + pgp_aead_hdr_t aead = {}; + if (!stream_dump_get_aead_hdr(src, &aead)) { + dst_printf(dst, "ERROR: failed to read AEAD header\n"); + return RNP_ERROR_READ; + } + + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) aead.version); + dst_print_salg(dst, NULL, aead.ealg); + dst_print_aalg(dst, NULL, aead.aalg); + dst_printf(dst, "chunk size: %d\n", (int) aead.csize); + dst_print_hex(dst, "initialization vector", aead.iv, aead.ivlen, true); + + indent_dest_decrease(dst); + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_encrypted(pgp_source_t *src, pgp_dest_t *dst, int tag) +{ + switch (tag) { + case PGP_PKT_SE_DATA: + dst_printf(dst, "Symmetrically-encrypted data packet\n\n"); + break; + case PGP_PKT_SE_IP_DATA: + dst_printf(dst, "Symmetrically-encrypted integrity protected data packet\n\n"); + break; + case PGP_PKT_AEAD_ENCRYPTED: + return stream_dump_aead_encrypted(src, dst); + default: + dst_printf(dst, "Unknown encrypted data packet\n\n"); + break; + } + + return stream_skip_packet(src); +} + +static rnp_result_t +stream_dump_one_pass(pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_one_pass_sig_t onepass; + rnp_result_t ret; + + try { + ret = onepass.parse(*src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + dst_printf(dst, "One-pass signature packet\n"); + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) onepass.version); + dst_print_sig_type(dst, NULL, onepass.type); + dst_print_halg(dst, NULL, onepass.halg); + dst_print_palg(dst, NULL, onepass.palg); + dst_print_keyid(dst, "signing key id", onepass.keyid); + dst_printf(dst, "nested: %d\n", (int) onepass.nested); + + indent_dest_decrease(dst); + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_compressed(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_source_t zsrc = {0}; + uint8_t zalg; + rnp_result_t ret; + + if ((ret = init_compressed_src(&zsrc, src))) { + return ret; + } + + dst_printf(dst, "Compressed data packet\n"); + indent_dest_increase(dst); + + get_compressed_src_alg(&zsrc, &zalg); + dst_print_zalg(dst, NULL, (pgp_compression_type_t) zalg); + dst_printf(dst, "Decompressed contents:\n"); + ret = stream_dump_packets_raw(ctx, &zsrc, dst); + + src_close(&zsrc); + indent_dest_decrease(dst); + return ret; +} + +static rnp_result_t +stream_dump_literal(pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_source_t lsrc = {0}; + pgp_literal_hdr_t lhdr = {0}; + rnp_result_t ret; + uint8_t readbuf[16384]; + + if ((ret = init_literal_src(&lsrc, src))) { + return ret; + } + + dst_printf(dst, "Literal data packet\n"); + indent_dest_increase(dst); + + get_literal_src_hdr(&lsrc, &lhdr); + dst_printf(dst, "data format: '%c'\n", lhdr.format); + dst_printf(dst, "filename: %s (len %d)\n", lhdr.fname, (int) lhdr.fname_len); + dst_print_time(dst, "timestamp", lhdr.timestamp); + + ret = RNP_SUCCESS; + while (!src_eof(&lsrc)) { + size_t read = 0; + if (!src_read(&lsrc, readbuf, sizeof(readbuf), &read)) { + ret = RNP_ERROR_READ; + break; + } + } + + dst_printf(dst, "data bytes: %lu\n", (unsigned long) lsrc.readb); + src_close(&lsrc); + indent_dest_decrease(dst); + return ret; +} + +static rnp_result_t +stream_dump_marker(pgp_source_t &src, pgp_dest_t &dst) +{ + dst_printf(&dst, "Marker packet\n"); + indent_dest_increase(&dst); + rnp_result_t ret = stream_parse_marker(src); + dst_printf(&dst, "contents: %s\n", ret ? "invalid" : PGP_MARKER_CONTENTS); + indent_dest_decrease(&dst); + return ret; +} + +static rnp_result_t +stream_dump_packets_raw(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + char msg[1024 + PGP_MAX_HEADER_SIZE] = {0}; + char smsg[128] = {0}; + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (src_eof(src)) { + return RNP_SUCCESS; + } + + /* do not allow endless recursion */ + if (++ctx->layers > MAXIMUM_NESTING_LEVEL) { + RNP_LOG("Too many OpenPGP nested layers during the dump."); + dst_printf(dst, ":too many OpenPGP packet layers, stopping.\n"); + ret = RNP_SUCCESS; + goto finish; + } + + while (!src_eof(src)) { + pgp_packet_hdr_t hdr = {}; + size_t off = src->readb; + rnp_result_t hdrret = stream_peek_packet_hdr(src, &hdr); + if (hdrret) { + ret = hdrret; + goto finish; + } + + if (hdr.partial) { + snprintf(msg, sizeof(msg), "partial len"); + } else if (hdr.indeterminate) { + snprintf(msg, sizeof(msg), "indeterminate len"); + } else { + snprintf(msg, sizeof(msg), "len %zu", hdr.pkt_len); + } + vsnprinthex(smsg, sizeof(smsg), hdr.hdr, hdr.hdr_len); + dst_printf( + dst, ":off %zu: packet header 0x%s (tag %d, %s)\n", off, smsg, hdr.tag, msg); + + if (ctx->dump_packets) { + size_t rlen = hdr.pkt_len + hdr.hdr_len; + bool part = false; + + if (!hdr.pkt_len || (rlen > 1024 + hdr.hdr_len)) { + rlen = 1024 + hdr.hdr_len; + part = true; + } + + dst_printf(dst, ":off %zu: packet contents ", off + hdr.hdr_len); + if (!src_peek(src, msg, rlen, &rlen)) { + dst_printf(dst, "- failed to read\n"); + } else { + rlen -= hdr.hdr_len; + if (part || (rlen < hdr.pkt_len)) { + dst_printf(dst, "(first %d bytes)\n", (int) rlen); + } else { + dst_printf(dst, "(%d bytes)\n", (int) rlen); + } + indent_dest_increase(dst); + dst_hexdump(dst, (uint8_t *) msg + hdr.hdr_len, rlen); + indent_dest_decrease(dst); + } + dst_printf(dst, "\n"); + } + + switch (hdr.tag) { + case PGP_PKT_SIGNATURE: + ret = stream_dump_signature(ctx, src, dst); + break; + case PGP_PKT_SECRET_KEY: + case PGP_PKT_PUBLIC_KEY: + case PGP_PKT_SECRET_SUBKEY: + case PGP_PKT_PUBLIC_SUBKEY: + ret = stream_dump_key(ctx, src, dst); + break; + case PGP_PKT_USER_ID: + case PGP_PKT_USER_ATTR: + ret = stream_dump_userid(src, dst); + break; + case PGP_PKT_PK_SESSION_KEY: + ret = stream_dump_pk_session_key(ctx, src, dst); + break; + case PGP_PKT_SK_SESSION_KEY: + ret = stream_dump_sk_session_key(src, dst); + break; + case PGP_PKT_SE_DATA: + case PGP_PKT_SE_IP_DATA: + case PGP_PKT_AEAD_ENCRYPTED: + ctx->stream_pkts++; + ret = stream_dump_encrypted(src, dst, hdr.tag); + break; + case PGP_PKT_ONE_PASS_SIG: + ret = stream_dump_one_pass(src, dst); + break; + case PGP_PKT_COMPRESSED: + ctx->stream_pkts++; + ret = stream_dump_compressed(ctx, src, dst); + break; + case PGP_PKT_LITDATA: + ctx->stream_pkts++; + ret = stream_dump_literal(src, dst); + break; + case PGP_PKT_MARKER: + ret = stream_dump_marker(*src, *dst); + break; + case PGP_PKT_TRUST: + case PGP_PKT_MDC: + dst_printf(dst, "Skipping unhandled pkt: %d\n\n", (int) hdr.tag); + ret = stream_skip_packet(src); + break; + default: + dst_printf(dst, "Skipping Unknown pkt: %d\n\n", (int) hdr.tag); + ret = stream_skip_packet(src); + if (ret) { + goto finish; + } + } + + if (ret) { + RNP_LOG("failed to process packet"); + if (++ctx->failures > MAXIMUM_ERROR_PKTS) { + RNP_LOG("too many packet dump errors."); + goto finish; + } + } + + if (ctx->stream_pkts > MAXIMUM_STREAM_PKTS) { + RNP_LOG("Too many OpenPGP stream packets during the dump."); + dst_printf(dst, ":too many OpenPGP stream packets, stopping.\n"); + ret = RNP_SUCCESS; + goto finish; + } + } + + ret = RNP_SUCCESS; +finish: + return ret; +} + +static bool +stream_skip_cleartext(pgp_source_t *src) +{ + char buf[4096]; + size_t read = 0; + size_t siglen = strlen(ST_SIG_BEGIN); + char * hdrpos; + + while (!src_eof(src)) { + if (!src_peek(src, buf, sizeof(buf) - 1, &read) || (read <= siglen)) { + return false; + } + buf[read] = '\0'; + + if ((hdrpos = strstr(buf, ST_SIG_BEGIN))) { + /* +1 here is to skip \n on the beginning of ST_SIG_BEGIN */ + src_skip(src, hdrpos - buf + 1); + return true; + } + src_skip(src, read - siglen + 1); + } + return false; +} + +rnp_result_t +stream_dump_packets(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_source_t armorsrc = {0}; + pgp_dest_t wrdst = {0}; + bool armored = false; + bool indent = false; + rnp_result_t ret = RNP_ERROR_GENERIC; + + ctx->layers = 0; + ctx->stream_pkts = 0; + ctx->failures = 0; + /* check whether source is cleartext - then skip till the signature */ + if (is_cleartext_source(src)) { + dst_printf(dst, ":cleartext signed data\n"); + if (!stream_skip_cleartext(src)) { + RNP_LOG("malformed cleartext signed data"); + ret = RNP_ERROR_BAD_FORMAT; + goto finish; + } + } + /* check whether source is armored */ + if (is_armored_source(src)) { + if ((ret = init_armored_src(&armorsrc, src))) { + RNP_LOG("failed to parse armored data"); + goto finish; + } + armored = true; + src = &armorsrc; + dst_printf(dst, ":armored input\n"); + } + + if (src_eof(src)) { + dst_printf(dst, ":empty input\n"); + ret = RNP_SUCCESS; + goto finish; + } + + if ((ret = init_indent_dest(&wrdst, dst))) { + RNP_LOG("failed to init indent dest"); + goto finish; + } + indent = true; + indent_dest_set(&wrdst, 0); + + ret = stream_dump_packets_raw(ctx, src, &wrdst); +finish: + if (armored) { + src_close(&armorsrc); + } + if (indent) { + dst_close(&wrdst, false); + } + return ret; +} + +static bool +obj_add_intstr_json(json_object *obj, const char *name, int val, const id_str_pair map[]) +{ + if (!obj_add_field_json(obj, name, json_object_new_int(val))) { + return false; + } + if (!map) { + return true; + } + char namestr[64] = {0}; + const char *str = id_str_pair::lookup(map, val, "Unknown"); + snprintf(namestr, sizeof(namestr), "%s.str", name); + return obj_add_field_json(obj, namestr, json_object_new_string(str)); +} + +static bool +obj_add_mpi_json(json_object *obj, const char *name, const pgp_mpi_t *mpi, bool contents) +{ + char strname[64] = {0}; + snprintf(strname, sizeof(strname), "%s.bits", name); + if (!obj_add_field_json(obj, strname, json_object_new_int(mpi_bits(mpi)))) { + return false; + } + if (!contents) { + return true; + } + snprintf(strname, sizeof(strname), "%s.raw", name); + return obj_add_hex_json(obj, strname, mpi->mpi, mpi->len); +} + +static bool +subpacket_obj_add_algs( + json_object *obj, const char *name, uint8_t *algs, size_t len, const id_str_pair map[]) +{ + json_object *jso_algs = json_object_new_array(); + if (!jso_algs || !obj_add_field_json(obj, name, jso_algs)) { + return false; + } + for (size_t i = 0; i < len; i++) { + if (!array_add_element_json(jso_algs, json_object_new_int(algs[i]))) { + return false; + } + } + if (!map) { + return true; + } + + char strname[64] = {0}; + snprintf(strname, sizeof(strname), "%s.str", name); + + jso_algs = json_object_new_array(); + if (!jso_algs || !obj_add_field_json(obj, strname, jso_algs)) { + return false; + } + for (size_t i = 0; i < len; i++) { + if (!array_add_element_json( + jso_algs, + json_object_new_string(id_str_pair::lookup(map, algs[i], "Unknown")))) { + return false; + } + } + return true; +} + +static bool +obj_add_s2k_json(json_object *obj, pgp_s2k_t *s2k) +{ + json_object *s2k_obj = json_object_new_object(); + if (!obj_add_field_json(obj, "s2k", s2k_obj)) { + return false; + } + if (!obj_add_field_json(s2k_obj, "specifier", json_object_new_int(s2k->specifier))) { + return false; + } + if ((s2k->specifier == PGP_S2KS_EXPERIMENTAL) && s2k->gpg_ext_num) { + if (!obj_add_field_json( + s2k_obj, "gpg extension", json_object_new_int(s2k->gpg_ext_num))) { + return false; + } + if (s2k->gpg_ext_num == PGP_S2K_GPG_SMARTCARD) { + size_t slen = s2k->gpg_serial_len > 16 ? 16 : s2k->gpg_serial_len; + if (!obj_add_hex_json(s2k_obj, "card serial number", s2k->gpg_serial, slen)) { + return false; + } + } + } + if (s2k->specifier == PGP_S2KS_EXPERIMENTAL) { + return obj_add_hex_json( + s2k_obj, "unknown experimental", s2k->experimental.data(), s2k->experimental.size()); + } + if (!obj_add_intstr_json(s2k_obj, "hash algorithm", s2k->hash_alg, hash_alg_map)) { + return false; + } + if (((s2k->specifier == PGP_S2KS_SALTED) || + (s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED)) && + !obj_add_hex_json(s2k_obj, "salt", s2k->salt, PGP_SALT_SIZE)) { + return false; + } + if (s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED) { + size_t real_iter = pgp_s2k_decode_iterations(s2k->iterations); + if (!obj_add_field_json(s2k_obj, "iterations", json_object_new_int(real_iter))) { + return false; + } + } + return true; +} + +static rnp_result_t stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, + const pgp_signature_t *sig, + json_object * pkt); + +static bool +signature_dump_subpacket_json(rnp_dump_ctx_t * ctx, + const pgp_sig_subpkt_t &subpkt, + json_object * obj) +{ + switch (subpkt.type) { + case PGP_SIG_SUBPKT_CREATION_TIME: + return obj_add_field_json( + obj, "creation time", json_object_new_int64(subpkt.fields.create)); + case PGP_SIG_SUBPKT_EXPIRATION_TIME: + return obj_add_field_json( + obj, "expiration time", json_object_new_int64(subpkt.fields.expiry)); + case PGP_SIG_SUBPKT_EXPORT_CERT: + return obj_add_field_json( + obj, "exportable", json_object_new_boolean(subpkt.fields.exportable)); + case PGP_SIG_SUBPKT_TRUST: + return obj_add_field_json( + obj, "amount", json_object_new_int(subpkt.fields.trust.amount)) && + obj_add_field_json( + obj, "level", json_object_new_int(subpkt.fields.trust.level)); + case PGP_SIG_SUBPKT_REGEXP: + return obj_add_field_json( + obj, + "regexp", + json_object_new_string_len(subpkt.fields.regexp.str, subpkt.fields.regexp.len)); + case PGP_SIG_SUBPKT_REVOCABLE: + return obj_add_field_json( + obj, "revocable", json_object_new_boolean(subpkt.fields.revocable)); + case PGP_SIG_SUBPKT_KEY_EXPIRY: + return obj_add_field_json( + obj, "key expiration", json_object_new_int64(subpkt.fields.expiry)); + case PGP_SIG_SUBPKT_PREFERRED_SKA: + return subpacket_obj_add_algs(obj, + "algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + symm_alg_map); + case PGP_SIG_SUBPKT_PREFERRED_HASH: + return subpacket_obj_add_algs(obj, + "algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + hash_alg_map); + case PGP_SIG_SUBPKT_PREF_COMPRESS: + return subpacket_obj_add_algs(obj, + "algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + z_alg_map); + case PGP_SIG_SUBPKT_PREFERRED_AEAD: + return subpacket_obj_add_algs(obj, + "algorithms", + subpkt.fields.preferred.arr, + subpkt.fields.preferred.len, + aead_alg_map); + case PGP_SIG_SUBPKT_REVOCATION_KEY: + return obj_add_field_json( + obj, "class", json_object_new_int(subpkt.fields.revocation_key.klass)) && + obj_add_field_json( + obj, "algorithm", json_object_new_int(subpkt.fields.revocation_key.pkalg)) && + obj_add_hex_json( + obj, "fingerprint", subpkt.fields.revocation_key.fp, PGP_FINGERPRINT_SIZE); + case PGP_SIG_SUBPKT_ISSUER_KEY_ID: + return obj_add_hex_json(obj, "issuer keyid", subpkt.fields.issuer, PGP_KEY_ID_SIZE); + case PGP_SIG_SUBPKT_KEYSERV_PREFS: + return obj_add_field_json( + obj, "no-modify", json_object_new_boolean(subpkt.fields.ks_prefs.no_modify)); + case PGP_SIG_SUBPKT_PREF_KEYSERV: + return obj_add_field_json(obj, + "uri", + json_object_new_string_len(subpkt.fields.preferred_ks.uri, + subpkt.fields.preferred_ks.len)); + case PGP_SIG_SUBPKT_PRIMARY_USER_ID: + return obj_add_field_json( + obj, "primary", json_object_new_boolean(subpkt.fields.primary_uid)); + case PGP_SIG_SUBPKT_POLICY_URI: + return obj_add_field_json( + obj, + "uri", + json_object_new_string_len(subpkt.fields.policy.uri, subpkt.fields.policy.len)); + case PGP_SIG_SUBPKT_KEY_FLAGS: { + uint8_t flg = subpkt.fields.key_flags; + if (!obj_add_field_json(obj, "flags", json_object_new_int(flg))) { + return false; + } + json_object *jso_flg = json_object_new_array(); + if (!jso_flg || !obj_add_field_json(obj, "flags.str", jso_flg)) { + return false; + } + if ((flg & PGP_KF_CERTIFY) && + !array_add_element_json(jso_flg, json_object_new_string("certify"))) { + return false; + } + if ((flg & PGP_KF_SIGN) && + !array_add_element_json(jso_flg, json_object_new_string("sign"))) { + return false; + } + if ((flg & PGP_KF_ENCRYPT_COMMS) && + !array_add_element_json(jso_flg, json_object_new_string("encrypt_comm"))) { + return false; + } + if ((flg & PGP_KF_ENCRYPT_STORAGE) && + !array_add_element_json(jso_flg, json_object_new_string("encrypt_storage"))) { + return false; + } + if ((flg & PGP_KF_SPLIT) && + !array_add_element_json(jso_flg, json_object_new_string("split"))) { + return false; + } + if ((flg & PGP_KF_AUTH) && + !array_add_element_json(jso_flg, json_object_new_string("auth"))) { + return false; + } + if ((flg & PGP_KF_SHARED) && + !array_add_element_json(jso_flg, json_object_new_string("shared"))) { + return false; + } + return true; + } + case PGP_SIG_SUBPKT_SIGNERS_USER_ID: + return obj_add_field_json( + obj, + "uid", + json_object_new_string_len(subpkt.fields.signer.uid, subpkt.fields.signer.len)); + case PGP_SIG_SUBPKT_REVOCATION_REASON: { + if (!obj_add_intstr_json( + obj, "code", subpkt.fields.revocation_reason.code, revoc_reason_map)) { + return false; + } + return obj_add_field_json( + obj, + "message", + json_object_new_string_len(subpkt.fields.revocation_reason.str, + subpkt.fields.revocation_reason.len)); + } + case PGP_SIG_SUBPKT_FEATURES: + return obj_add_field_json( + obj, + "mdc", + json_object_new_boolean(subpkt.fields.features & PGP_KEY_FEATURE_MDC)) && + obj_add_field_json( + obj, + "aead", + json_object_new_boolean(subpkt.fields.features & PGP_KEY_FEATURE_AEAD)) && + obj_add_field_json( + obj, + "v5 keys", + json_object_new_boolean(subpkt.fields.features & PGP_KEY_FEATURE_V5)); + case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE: { + json_object *sig = json_object_new_object(); + if (!sig || !obj_add_field_json(obj, "signature", sig)) { + return false; + } + return !stream_dump_signature_pkt_json(ctx, subpkt.fields.sig, sig); + } + case PGP_SIG_SUBPKT_ISSUER_FPR: + return obj_add_hex_json( + obj, "fingerprint", subpkt.fields.issuer_fp.fp, subpkt.fields.issuer_fp.len); + case PGP_SIG_SUBPKT_NOTATION_DATA: { + bool human = subpkt.fields.notation.human; + if (!json_add(obj, "human", human) || !json_add(obj, + "name", + (char *) subpkt.fields.notation.name, + subpkt.fields.notation.nlen)) { + return false; + } + if (human) { + return json_add(obj, + "value", + (char *) subpkt.fields.notation.value, + subpkt.fields.notation.vlen); + } + return obj_add_hex_json( + obj, "value", subpkt.fields.notation.value, subpkt.fields.notation.vlen); + } + default: + if (!ctx->dump_packets) { + return obj_add_hex_json(obj, "raw", subpkt.data, subpkt.len); + } + return true; + } + return true; +} + +static json_object * +signature_dump_subpackets_json(rnp_dump_ctx_t *ctx, const pgp_signature_t *sig) +{ + json_object *res = json_object_new_array(); + + for (auto &subpkt : sig->subpkts) { + json_object *jso_subpkt = json_object_new_object(); + if (json_object_array_add(res, jso_subpkt)) { + json_object_put(jso_subpkt); + goto error; + } + + if (!obj_add_intstr_json(jso_subpkt, "type", subpkt.type, sig_subpkt_type_map)) { + goto error; + } + if (!obj_add_field_json(jso_subpkt, "length", json_object_new_int(subpkt.len))) { + goto error; + } + if (!obj_add_field_json( + jso_subpkt, "hashed", json_object_new_boolean(subpkt.hashed))) { + goto error; + } + if (!obj_add_field_json( + jso_subpkt, "critical", json_object_new_boolean(subpkt.critical))) { + goto error; + } + + if (ctx->dump_packets && + !obj_add_hex_json(jso_subpkt, "raw", subpkt.data, subpkt.len)) { + goto error; + } + + if (!signature_dump_subpacket_json(ctx, subpkt, jso_subpkt)) { + goto error; + } + } + + return res; +error: + json_object_put(res); + return NULL; +} + +static rnp_result_t +stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, + const pgp_signature_t *sig, + json_object * pkt) +{ + json_object * material = NULL; + pgp_signature_material_t sigmaterial = {}; + rnp_result_t ret = RNP_ERROR_OUT_OF_MEMORY; + + if (!obj_add_field_json(pkt, "version", json_object_new_int(sig->version))) { + goto done; + } + if (!obj_add_intstr_json(pkt, "type", sig->type(), sig_type_map)) { + goto done; + } + + if (sig->version < PGP_V4) { + if (!obj_add_field_json( + pkt, "creation time", json_object_new_int(sig->creation_time))) { + goto done; + } + if (!obj_add_hex_json(pkt, "signer", sig->signer.data(), sig->signer.size())) { + goto done; + } + } + if (!obj_add_intstr_json(pkt, "algorithm", sig->palg, pubkey_alg_map)) { + goto done; + } + if (!obj_add_intstr_json(pkt, "hash algorithm", sig->halg, hash_alg_map)) { + goto done; + } + + if (sig->version >= PGP_V4) { + json_object *subpkts = signature_dump_subpackets_json(ctx, sig); + if (!subpkts) { + goto done; + } + if (!obj_add_field_json(pkt, "subpackets", subpkts)) { + goto done; + } + } + + if (!obj_add_hex_json(pkt, "lbits", sig->lbits, sizeof(sig->lbits))) { + goto done; + } + + material = json_object_new_object(); + if (!material || !obj_add_field_json(pkt, "material", material)) { + goto done; + } + + try { + sig->parse_material(sigmaterial); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + switch (sig->palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!obj_add_mpi_json(material, "s", &sigmaterial.rsa.s, ctx->dump_mpi)) { + goto done; + } + break; + case PGP_PKA_DSA: + if (!obj_add_mpi_json(material, "r", &sigmaterial.dsa.r, ctx->dump_mpi) || + !obj_add_mpi_json(material, "s", &sigmaterial.dsa.s, ctx->dump_mpi)) { + goto done; + } + break; + case PGP_PKA_EDDSA: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + if (!obj_add_mpi_json(material, "r", &sigmaterial.ecc.r, ctx->dump_mpi) || + !obj_add_mpi_json(material, "s", &sigmaterial.ecc.s, ctx->dump_mpi)) { + goto done; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!obj_add_mpi_json(material, "r", &sigmaterial.eg.r, ctx->dump_mpi) || + !obj_add_mpi_json(material, "s", &sigmaterial.eg.s, ctx->dump_mpi)) { + goto done; + } + break; + default: + break; + } + ret = RNP_SUCCESS; +done: + return ret; +} + +static rnp_result_t +stream_dump_signature_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +{ + pgp_signature_t sig; + rnp_result_t ret; + try { + ret = sig.parse(*src); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + return stream_dump_signature_pkt_json(ctx, &sig, pkt); +} + +static rnp_result_t +stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +{ + pgp_key_pkt_t key; + rnp_result_t ret; + pgp_key_id_t keyid = {}; + pgp_fingerprint_t keyfp = {}; + json_object * material = NULL; + + try { + ret = key.parse(*src); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + ret = RNP_ERROR_OUT_OF_MEMORY; + + if (!obj_add_field_json(pkt, "version", json_object_new_int(key.version))) { + goto done; + } + if (!obj_add_field_json(pkt, "creation time", json_object_new_int64(key.creation_time))) { + goto done; + } + if ((key.version < PGP_V4) && + !obj_add_field_json(pkt, "v3 days", json_object_new_int(key.v3_days))) { + goto done; + } + if (!obj_add_intstr_json(pkt, "algorithm", key.alg, pubkey_alg_map)) { + goto done; + } + + material = json_object_new_object(); + if (!material || !obj_add_field_json(pkt, "material", material)) { + goto done; + } + + switch (key.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!obj_add_mpi_json(material, "n", &key.material.rsa.n, ctx->dump_mpi) || + !obj_add_mpi_json(material, "e", &key.material.rsa.e, ctx->dump_mpi)) { + goto done; + } + break; + case PGP_PKA_DSA: + if (!obj_add_mpi_json(material, "p", &key.material.dsa.p, ctx->dump_mpi) || + !obj_add_mpi_json(material, "q", &key.material.dsa.q, ctx->dump_mpi) || + !obj_add_mpi_json(material, "g", &key.material.dsa.g, ctx->dump_mpi) || + !obj_add_mpi_json(material, "y", &key.material.dsa.y, ctx->dump_mpi)) { + goto done; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!obj_add_mpi_json(material, "p", &key.material.eg.p, ctx->dump_mpi) || + !obj_add_mpi_json(material, "g", &key.material.eg.g, ctx->dump_mpi) || + !obj_add_mpi_json(material, "y", &key.material.eg.y, ctx->dump_mpi)) { + goto done; + } + break; + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: { + const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); + if (!obj_add_mpi_json(material, "p", &key.material.ec.p, ctx->dump_mpi)) { + goto done; + } + if (!obj_add_field_json(material, + "curve", + json_object_new_string(cdesc ? cdesc->pgp_name : "unknown"))) { + goto done; + } + break; + } + case PGP_PKA_ECDH: { + const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); + if (!obj_add_mpi_json(material, "p", &key.material.ec.p, ctx->dump_mpi)) { + goto done; + } + if (!obj_add_field_json(material, + "curve", + json_object_new_string(cdesc ? cdesc->pgp_name : "unknown"))) { + goto done; + } + if (!obj_add_intstr_json( + material, "hash algorithm", key.material.ec.kdf_hash_alg, hash_alg_map)) { + goto done; + } + if (!obj_add_intstr_json( + material, "key wrap algorithm", key.material.ec.key_wrap_alg, symm_alg_map)) { + goto done; + } + break; + } + default: + break; + } + + if (is_secret_key_pkt(key.tag)) { + if (!obj_add_field_json( + material, "s2k usage", json_object_new_int(key.sec_protection.s2k.usage))) { + goto done; + } + if (!obj_add_s2k_json(material, &key.sec_protection.s2k)) { + goto done; + } + if (key.sec_protection.s2k.usage && + !obj_add_intstr_json( + material, "symmetric algorithm", key.sec_protection.symm_alg, symm_alg_map)) { + goto done; + } + } + + if (pgp_keyid(keyid, key) || !obj_add_hex_json(pkt, "keyid", keyid.data(), keyid.size())) { + goto done; + } + + if (ctx->dump_grips) { + if (pgp_fingerprint(keyfp, key) || + !obj_add_hex_json(pkt, "fingerprint", keyfp.fingerprint, keyfp.length)) { + goto done; + } + + pgp_key_grip_t grip; + if (!rnp_key_store_get_key_grip(&key.material, grip) || + !obj_add_hex_json(pkt, "grip", grip.data(), grip.size())) { + goto done; + } + } + ret = RNP_SUCCESS; +done: + return ret; +} + +static rnp_result_t +stream_dump_userid_json(pgp_source_t *src, json_object *pkt) +{ + pgp_userid_pkt_t uid; + rnp_result_t ret; + + try { + ret = uid.parse(*src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + switch (uid.tag) { + case PGP_PKT_USER_ID: + if (!obj_add_field_json( + pkt, "userid", json_object_new_string_len((char *) uid.uid, uid.uid_len))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + break; + case PGP_PKT_USER_ATTR: + if (!obj_add_hex_json(pkt, "userattr", uid.uid, uid.uid_len)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + break; + default:; + } + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +{ + pgp_pk_sesskey_t pkey; + pgp_encrypted_material_t pkmaterial; + rnp_result_t ret; + + try { + ret = pkey.parse(*src); + if (!pkey.parse_material(pkmaterial)) { + ret = RNP_ERROR_BAD_FORMAT; + } + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + if (!obj_add_field_json(pkt, "version", json_object_new_int(pkey.version)) || + !obj_add_hex_json(pkt, "keyid", pkey.key_id.data(), pkey.key_id.size()) || + !obj_add_intstr_json(pkt, "algorithm", pkey.alg, pubkey_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + json_object *material = json_object_new_object(); + if (!obj_add_field_json(pkt, "material", material)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + switch (pkey.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!obj_add_mpi_json(material, "m", &pkmaterial.rsa.m, ctx->dump_mpi)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!obj_add_mpi_json(material, "g", &pkmaterial.eg.g, ctx->dump_mpi) || + !obj_add_mpi_json(material, "m", &pkmaterial.eg.m, ctx->dump_mpi)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + break; + case PGP_PKA_SM2: + if (!obj_add_mpi_json(material, "m", &pkmaterial.sm2.m, ctx->dump_mpi)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + break; + case PGP_PKA_ECDH: + if (!obj_add_mpi_json(material, "p", &pkmaterial.ecdh.p, ctx->dump_mpi) || + !obj_add_field_json( + material, "m.bytes", json_object_new_int(pkmaterial.ecdh.mlen))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (ctx->dump_mpi && + !obj_add_hex_json(material, "m", pkmaterial.ecdh.m, pkmaterial.ecdh.mlen)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + break; + default:; + } + + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_sk_session_key_json(pgp_source_t *src, json_object *pkt) +{ + pgp_sk_sesskey_t skey; + rnp_result_t ret; + + try { + ret = skey.parse(*src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + if (!obj_add_field_json(pkt, "version", json_object_new_int(skey.version)) || + !obj_add_intstr_json(pkt, "algorithm", skey.alg, symm_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if ((skey.version == PGP_SKSK_V5) && + !obj_add_intstr_json(pkt, "aead algorithm", skey.aalg, aead_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_s2k_json(pkt, &skey.s2k)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if ((skey.version == PGP_SKSK_V5) && + !obj_add_hex_json(pkt, "aead iv", skey.iv, skey.ivlen)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_hex_json(pkt, "encrypted key", skey.enckey, skey.enckeylen)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_encrypted_json(pgp_source_t *src, json_object *pkt, pgp_pkt_type_t tag) +{ + if (tag != PGP_PKT_AEAD_ENCRYPTED) { + /* packet header with tag is already in pkt */ + return stream_skip_packet(src); + } + + /* dumping AEAD data */ + pgp_aead_hdr_t aead = {}; + if (!stream_dump_get_aead_hdr(src, &aead)) { + return RNP_ERROR_READ; + } + + if (!obj_add_field_json(pkt, "version", json_object_new_int(aead.version)) || + !obj_add_intstr_json(pkt, "algorithm", aead.ealg, symm_alg_map) || + !obj_add_intstr_json(pkt, "aead algorithm", aead.aalg, aead_alg_map) || + !obj_add_field_json(pkt, "chunk size", json_object_new_int(aead.csize)) || + !obj_add_hex_json(pkt, "aead iv", aead.iv, aead.ivlen)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_one_pass_json(pgp_source_t *src, json_object *pkt) +{ + pgp_one_pass_sig_t onepass; + rnp_result_t ret; + + try { + ret = onepass.parse(*src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + return ret; + } + + if (!obj_add_field_json(pkt, "version", json_object_new_int(onepass.version))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_intstr_json(pkt, "type", onepass.type, sig_type_map)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_intstr_json(pkt, "hash algorithm", onepass.halg, hash_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_intstr_json(pkt, "public key algorithm", onepass.palg, pubkey_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_hex_json(pkt, "signer", onepass.keyid.data(), onepass.keyid.size())) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!obj_add_field_json(pkt, "nested", json_object_new_boolean(onepass.nested))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; +} + +static rnp_result_t +stream_dump_marker_json(pgp_source_t &src, json_object *pkt) +{ + rnp_result_t ret = stream_parse_marker(src); + + if (!obj_add_field_json( + pkt, "contents", json_object_new_string(ret ? "invalid" : PGP_MARKER_CONTENTS))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + return ret; +} + +static rnp_result_t stream_dump_raw_packets_json(rnp_dump_ctx_t *ctx, + pgp_source_t * src, + json_object ** jso); + +static rnp_result_t +stream_dump_compressed_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +{ + pgp_source_t zsrc = {0}; + uint8_t zalg; + rnp_result_t ret; + json_object *contents = NULL; + + if ((ret = init_compressed_src(&zsrc, src))) { + return ret; + } + + get_compressed_src_alg(&zsrc, &zalg); + if (!obj_add_intstr_json(pkt, "algorithm", zalg, z_alg_map)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + ret = stream_dump_raw_packets_json(ctx, &zsrc, &contents); + if (!ret && !obj_add_field_json(pkt, "contents", contents)) { + json_object_put(contents); + ret = RNP_ERROR_OUT_OF_MEMORY; + } +done: + src_close(&zsrc); + return ret; +} + +static rnp_result_t +stream_dump_literal_json(pgp_source_t *src, json_object *pkt) +{ + pgp_source_t lsrc = {0}; + pgp_literal_hdr_t lhdr = {0}; + rnp_result_t ret; + uint8_t readbuf[16384]; + + if ((ret = init_literal_src(&lsrc, src))) { + return ret; + } + ret = RNP_ERROR_OUT_OF_MEMORY; + get_literal_src_hdr(&lsrc, &lhdr); + if (!obj_add_field_json( + pkt, "format", json_object_new_string_len((char *) &lhdr.format, 1))) { + goto done; + } + if (!obj_add_field_json( + pkt, "filename", json_object_new_string_len(lhdr.fname, lhdr.fname_len))) { + goto done; + } + if (!obj_add_field_json(pkt, "timestamp", json_object_new_int64(lhdr.timestamp))) { + goto done; + } + + while (!src_eof(&lsrc)) { + size_t read = 0; + if (!src_read(&lsrc, readbuf, sizeof(readbuf), &read)) { + ret = RNP_ERROR_READ; + goto done; + } + } + + if (!obj_add_field_json(pkt, "datalen", json_object_new_int64(lsrc.readb))) { + goto done; + } + ret = RNP_SUCCESS; +done: + src_close(&lsrc); + return ret; +} + +static bool +stream_dump_hdr_json(pgp_source_t *src, pgp_packet_hdr_t *hdr, json_object *pkt) +{ + rnp_result_t hdrret = stream_peek_packet_hdr(src, hdr); + if (hdrret) { + return false; + } + + json_object *jso_hdr = json_object_new_object(); + if (!jso_hdr) { + return false; + } + + if (!obj_add_field_json(jso_hdr, "offset", json_object_new_int64(src->readb))) { + goto error; + } + if (!obj_add_intstr_json(jso_hdr, "tag", hdr->tag, packet_tag_map)) { + goto error; + } + if (!obj_add_hex_json(jso_hdr, "raw", hdr->hdr, hdr->hdr_len)) { + goto error; + } + if (!hdr->partial && !hdr->indeterminate && + !obj_add_field_json(jso_hdr, "length", json_object_new_int64(hdr->pkt_len))) { + goto error; + } + if (!obj_add_field_json(jso_hdr, "partial", json_object_new_boolean(hdr->partial))) { + goto error; + } + if (!obj_add_field_json( + jso_hdr, "indeterminate", json_object_new_boolean(hdr->indeterminate))) { + goto error; + } + return obj_add_field_json(pkt, "header", jso_hdr); +error: + json_object_put(jso_hdr); + return false; +} + +static rnp_result_t +stream_dump_raw_packets_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object **jso) +{ + json_object *pkts = NULL; + json_object *pkt = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + + pkts = json_object_new_array(); + if (!pkts) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (src_eof(src)) { + ret = RNP_SUCCESS; + goto done; + } + + /* do not allow endless recursion */ + if (++ctx->layers > MAXIMUM_NESTING_LEVEL) { + RNP_LOG("Too many OpenPGP nested layers during the dump."); + ret = RNP_SUCCESS; + goto done; + } + + while (!src_eof(src)) { + pgp_packet_hdr_t hdr = {}; + + pkt = json_object_new_object(); + if (!pkt) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + if (!stream_dump_hdr_json(src, &hdr, pkt)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + + if (ctx->dump_packets) { + size_t rlen = hdr.pkt_len + hdr.hdr_len; + uint8_t buf[2048 + sizeof(hdr.hdr)] = {0}; + + if (!hdr.pkt_len || (rlen > 2048 + hdr.hdr_len)) { + rlen = 2048 + hdr.hdr_len; + } + if (!src_peek(src, buf, rlen, &rlen) || (rlen < hdr.hdr_len)) { + ret = RNP_ERROR_READ; + goto done; + } + if (!obj_add_hex_json(pkt, "raw", buf + hdr.hdr_len, rlen - hdr.hdr_len)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + } + + switch (hdr.tag) { + case PGP_PKT_SIGNATURE: + ret = stream_dump_signature_json(ctx, src, pkt); + break; + case PGP_PKT_SECRET_KEY: + case PGP_PKT_PUBLIC_KEY: + case PGP_PKT_SECRET_SUBKEY: + case PGP_PKT_PUBLIC_SUBKEY: + ret = stream_dump_key_json(ctx, src, pkt); + break; + case PGP_PKT_USER_ID: + case PGP_PKT_USER_ATTR: + ret = stream_dump_userid_json(src, pkt); + break; + case PGP_PKT_PK_SESSION_KEY: + ret = stream_dump_pk_session_key_json(ctx, src, pkt); + break; + case PGP_PKT_SK_SESSION_KEY: + ret = stream_dump_sk_session_key_json(src, pkt); + break; + case PGP_PKT_SE_DATA: + case PGP_PKT_SE_IP_DATA: + case PGP_PKT_AEAD_ENCRYPTED: + ctx->stream_pkts++; + ret = stream_dump_encrypted_json(src, pkt, hdr.tag); + break; + case PGP_PKT_ONE_PASS_SIG: + ret = stream_dump_one_pass_json(src, pkt); + break; + case PGP_PKT_COMPRESSED: + ctx->stream_pkts++; + ret = stream_dump_compressed_json(ctx, src, pkt); + break; + case PGP_PKT_LITDATA: + ctx->stream_pkts++; + ret = stream_dump_literal_json(src, pkt); + break; + case PGP_PKT_MARKER: + ret = stream_dump_marker_json(*src, pkt); + break; + case PGP_PKT_TRUST: + case PGP_PKT_MDC: + ret = stream_skip_packet(src); + break; + default: + ret = stream_skip_packet(src); + } + + if (ret) { + RNP_LOG("failed to process packet"); + if (++ctx->failures > MAXIMUM_ERROR_PKTS) { + RNP_LOG("too many packet dump errors."); + goto done; + } + ret = RNP_SUCCESS; + } + + if (json_object_array_add(pkts, pkt)) { + ret = RNP_ERROR_OUT_OF_MEMORY; + goto done; + } + if (ctx->stream_pkts > MAXIMUM_STREAM_PKTS) { + RNP_LOG("Too many OpenPGP stream packets during the dump."); + ret = RNP_SUCCESS; + goto done; + } + + pkt = NULL; + } +done: + if (ret) { + json_object_put(pkts); + json_object_put(pkt); + pkts = NULL; + } + *jso = pkts; + return ret; +} + +rnp_result_t +stream_dump_packets_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object **jso) +{ + pgp_source_t armorsrc = {0}; + bool armored = false; + rnp_result_t ret = RNP_ERROR_GENERIC; + + ctx->layers = 0; + ctx->stream_pkts = 0; + ctx->failures = 0; + /* check whether source is cleartext - then skip till the signature */ + if (is_cleartext_source(src)) { + if (!stream_skip_cleartext(src)) { + RNP_LOG("malformed cleartext signed data"); + ret = RNP_ERROR_BAD_FORMAT; + goto finish; + } + } + /* check whether source is armored */ + if (is_armored_source(src)) { + if ((ret = init_armored_src(&armorsrc, src))) { + RNP_LOG("failed to parse armored data"); + goto finish; + } + armored = true; + src = &armorsrc; + } + + if (src_eof(src)) { + ret = RNP_ERROR_NOT_ENOUGH_DATA; + goto finish; + } + + ret = stream_dump_raw_packets_json(ctx, src, jso); +finish: + if (armored) { + src_close(&armorsrc); + } + return ret; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-dump.h b/comm/third_party/rnp/src/librepgp/stream-dump.h new file mode 100644 index 0000000000..6c2fcf1d4f --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-dump.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_DUMP_H_ +#define STREAM_DUMP_H_ + +#include +#include +#include +#include "json_object.h" +#include "json.h" +#include "rnp.h" +#include "stream-common.h" + +typedef struct rnp_dump_ctx_t { + bool dump_mpi; + bool dump_packets; + bool dump_grips; + size_t layers; + size_t stream_pkts; + size_t failures; +} rnp_dump_ctx_t; + +rnp_result_t stream_dump_packets(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst); + +rnp_result_t stream_dump_packets_json(rnp_dump_ctx_t *ctx, + pgp_source_t * src, + json_object ** jso); + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-key.cpp b/comm/third_party/rnp/src/librepgp/stream-key.cpp new file mode 100644 index 0000000000..8090ff7d59 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-key.cpp @@ -0,0 +1,1469 @@ +/* + * Copyright (c) 2018-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include +#include "stream-def.h" +#include "stream-key.h" +#include "stream-armor.h" +#include "stream-packet.h" +#include "stream-sig.h" +#include "types.h" +#include "fingerprint.h" +#include "pgp-key.h" +#include "crypto.h" +#include "crypto/signatures.h" +#include "crypto/mem.h" +#include "../librekey/key_store_pgp.h" +#include +#include +#include + +/** + * @brief Add signatures from src to dst, skipping the duplicates. + * + * @param dst Vector which will contain all distinct signatures from src and dst + * @param src Vector to merge signatures from + * @return true on success or false otherwise. On failure dst may have some sigs appended. + */ +static rnp_result_t +merge_signatures(pgp_signature_list_t &dst, const pgp_signature_list_t &src) +{ + for (auto &sig : src) { + try { + if (std::find(dst.begin(), dst.end(), sig) != dst.end()) { + continue; + } + dst.emplace_back(sig); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + return RNP_SUCCESS; +} + +static rnp_result_t +transferable_userid_merge(pgp_transferable_userid_t &dst, const pgp_transferable_userid_t &src) +{ + if (dst.uid != src.uid) { + RNP_LOG("wrong userid merge attempt"); + return RNP_ERROR_BAD_PARAMETERS; + } + return merge_signatures(dst.signatures, src.signatures); +} + +rnp_result_t +transferable_subkey_from_key(pgp_transferable_subkey_t &dst, const pgp_key_t &key) +{ + try { + auto vec = rnp_key_to_vec(key); + rnp::MemorySource mem(vec); + return process_pgp_subkey(mem.src(), dst, false); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +rnp_result_t +transferable_subkey_merge(pgp_transferable_subkey_t &dst, const pgp_transferable_subkey_t &src) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (!dst.subkey.equals(src.subkey, true)) { + RNP_LOG("wrong subkey merge call"); + return RNP_ERROR_BAD_PARAMETERS; + } + if ((ret = merge_signatures(dst.signatures, src.signatures))) { + RNP_LOG("failed to merge signatures"); + } + return ret; +} + +rnp_result_t +transferable_key_from_key(pgp_transferable_key_t &dst, const pgp_key_t &key) +{ + try { + auto vec = rnp_key_to_vec(key); + rnp::MemorySource mem(vec); + return process_pgp_key(mem.src(), dst, false); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +static pgp_transferable_userid_t * +transferable_key_has_userid(pgp_transferable_key_t &src, const pgp_userid_pkt_t &userid) +{ + for (auto &uid : src.userids) { + if (uid.uid == userid) { + return &uid; + } + } + return NULL; +} + +static pgp_transferable_subkey_t * +transferable_key_has_subkey(pgp_transferable_key_t &src, const pgp_key_pkt_t &subkey) +{ + for (auto &srcsub : src.subkeys) { + if (srcsub.subkey.equals(subkey, true)) { + return &srcsub; + } + } + return NULL; +} + +rnp_result_t +transferable_key_merge(pgp_transferable_key_t &dst, const pgp_transferable_key_t &src) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (!dst.key.equals(src.key, true)) { + RNP_LOG("wrong key merge call"); + return RNP_ERROR_BAD_PARAMETERS; + } + /* direct-key signatures */ + if ((ret = merge_signatures(dst.signatures, src.signatures))) { + RNP_LOG("failed to merge signatures"); + return ret; + } + /* userids */ + for (auto &srcuid : src.userids) { + pgp_transferable_userid_t *dstuid = transferable_key_has_userid(dst, srcuid.uid); + if (dstuid) { + if ((ret = transferable_userid_merge(*dstuid, srcuid))) { + RNP_LOG("failed to merge userid"); + return ret; + } + continue; + } + /* add userid */ + try { + dst.userids.emplace_back(srcuid); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + + /* subkeys */ + for (auto &srcsub : src.subkeys) { + pgp_transferable_subkey_t *dstsub = transferable_key_has_subkey(dst, srcsub.subkey); + if (dstsub) { + if ((ret = transferable_subkey_merge(*dstsub, srcsub))) { + RNP_LOG("failed to merge subkey"); + return ret; + } + continue; + } + /* add subkey */ + if (is_public_key_pkt(dst.key.tag) != is_public_key_pkt(srcsub.subkey.tag)) { + RNP_LOG("warning: adding public/secret subkey to secret/public key"); + } + try { + dst.subkeys.emplace_back(srcsub); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + return RNP_SUCCESS; +} + +static bool +skip_pgp_packets(pgp_source_t &src, const std::set &pkts) +{ + do { + int pkt = stream_pkt_type(src); + if (!pkt) { + break; + } + if (pkt < 0) { + return false; + } + if (pkts.find((pgp_pkt_type_t) pkt) == pkts.end()) { + return true; + } + uint64_t ppos = src.readb; + if (stream_skip_packet(&src)) { + RNP_LOG("failed to skip packet at %" PRIu64, ppos); + return false; + } + } while (1); + + return true; +} + +static rnp_result_t +process_pgp_key_signatures(pgp_source_t &src, pgp_signature_list_t &sigs, bool skiperrors) +{ + int ptag; + while ((ptag = stream_pkt_type(src)) == PGP_PKT_SIGNATURE) { + uint64_t sigpos = src.readb; + try { + pgp_signature_t sig; + rnp_result_t ret = sig.parse(src); + if (ret) { + RNP_LOG("failed to parse signature at %" PRIu64, sigpos); + if (!skiperrors) { + return ret; + } + } else { + sigs.emplace_back(std::move(sig)); + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!skip_pgp_packets(src, {PGP_PKT_TRUST})) { + return RNP_ERROR_READ; + } + } + return ptag < 0 ? RNP_ERROR_BAD_FORMAT : RNP_SUCCESS; +} + +static rnp_result_t +process_pgp_userid(pgp_source_t &src, pgp_transferable_userid_t &uid, bool skiperrors) +{ + rnp_result_t ret; + uint64_t uidpos = src.readb; + try { + ret = uid.uid.parse(src); + } catch (const std::exception &e) { + ret = RNP_ERROR_GENERIC; + } + if (ret) { + RNP_LOG("failed to parse userid at %" PRIu64, uidpos); + return ret; + } + if (!skip_pgp_packets(src, {PGP_PKT_TRUST})) { + return RNP_ERROR_READ; + } + return process_pgp_key_signatures(src, uid.signatures, skiperrors); +} + +rnp_result_t +process_pgp_subkey(pgp_source_t &src, pgp_transferable_subkey_t &subkey, bool skiperrors) +{ + int ptag; + subkey = pgp_transferable_subkey_t(); + uint64_t keypos = src.readb; + if (!is_subkey_pkt(ptag = stream_pkt_type(src))) { + RNP_LOG("wrong subkey ptag: %d at %" PRIu64, ptag, keypos); + return RNP_ERROR_BAD_FORMAT; + } + + rnp_result_t ret = RNP_ERROR_BAD_FORMAT; + try { + ret = subkey.subkey.parse(src); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + } + if (ret) { + RNP_LOG("failed to parse subkey at %" PRIu64, keypos); + subkey.subkey = {}; + return ret; + } + + if (!skip_pgp_packets(src, {PGP_PKT_TRUST})) { + return RNP_ERROR_READ; + } + + return process_pgp_key_signatures(src, subkey.signatures, skiperrors); +} + +rnp_result_t +process_pgp_key_auto(pgp_source_t & src, + pgp_transferable_key_t &key, + bool allowsub, + bool skiperrors) +{ + key = {}; + uint64_t srcpos = src.readb; + int ptag = stream_pkt_type(src); + if (is_subkey_pkt(ptag) && allowsub) { + pgp_transferable_subkey_t subkey; + rnp_result_t ret = process_pgp_subkey(src, subkey, skiperrors); + if (subkey.subkey.tag != PGP_PKT_RESERVED) { + try { + key.subkeys.push_back(std::move(subkey)); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_OUT_OF_MEMORY; + } + } + /* change error code if we didn't process anything at all */ + if (srcpos == src.readb) { + ret = RNP_ERROR_BAD_STATE; + } + return ret; + } + + rnp_result_t ret = RNP_ERROR_BAD_FORMAT; + if (!is_primary_key_pkt(ptag)) { + RNP_LOG("wrong key tag: %d at pos %" PRIu64, ptag, src.readb); + } else { + try { + ret = process_pgp_key(src, key, skiperrors); + } catch (const rnp::rnp_exception &e) { + RNP_LOG("%s", e.what()); + ret = e.code(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + } + } + if (skiperrors && (ret == RNP_ERROR_BAD_FORMAT) && + !skip_pgp_packets(src, + {PGP_PKT_TRUST, + PGP_PKT_SIGNATURE, + PGP_PKT_USER_ID, + PGP_PKT_USER_ATTR, + PGP_PKT_PUBLIC_SUBKEY, + PGP_PKT_SECRET_SUBKEY})) { + ret = RNP_ERROR_READ; + } + /* change error code if we didn't process anything at all */ + if (srcpos == src.readb) { + ret = RNP_ERROR_BAD_STATE; + } + return ret; +} + +rnp_result_t +process_pgp_keys(pgp_source_t &src, pgp_key_sequence_t &keys, bool skiperrors) +{ + bool has_secret = false; + bool has_public = false; + + keys.keys.clear(); + /* create maybe-armored stream */ + rnp::ArmoredSource armor( + src, rnp::ArmoredSource::AllowBinary | rnp::ArmoredSource::AllowMultiple); + + /* read sequence of transferable OpenPGP keys as described in RFC 4880, 11.1 - 11.2 */ + while (!armor.error()) { + /* Allow multiple armored messages in a single stream */ + if (armor.eof() && armor.multiple()) { + armor.restart(); + } + if (armor.eof()) { + break; + } + /* Attempt to read the next key */ + pgp_transferable_key_t curkey; + rnp_result_t ret = process_pgp_key_auto(armor.src(), curkey, false, skiperrors); + if (ret && (!skiperrors || (ret != RNP_ERROR_BAD_FORMAT))) { + keys.keys.clear(); + return ret; + } + /* check whether we actually read any key or just skipped erroneous packets */ + if (curkey.key.tag == PGP_PKT_RESERVED) { + continue; + } + has_secret |= (curkey.key.tag == PGP_PKT_SECRET_KEY); + has_public |= (curkey.key.tag == PGP_PKT_PUBLIC_KEY); + + keys.keys.emplace_back(std::move(curkey)); + } + + if (has_secret && has_public) { + RNP_LOG("warning! public keys are mixed together with secret ones!"); + } + + if (armor.error()) { + keys.keys.clear(); + return RNP_ERROR_READ; + } + return RNP_SUCCESS; +} + +rnp_result_t +process_pgp_key(pgp_source_t &src, pgp_transferable_key_t &key, bool skiperrors) +{ + key = pgp_transferable_key_t(); + /* create maybe-armored stream */ + rnp::ArmoredSource armor( + src, rnp::ArmoredSource::AllowBinary | rnp::ArmoredSource::AllowMultiple); + + /* main key packet */ + uint64_t keypos = armor.readb(); + int ptag = stream_pkt_type(armor.src()); + if ((ptag <= 0) || !is_primary_key_pkt(ptag)) { + RNP_LOG("wrong key packet tag: %d at %" PRIu64, ptag, keypos); + return RNP_ERROR_BAD_FORMAT; + } + + rnp_result_t ret = key.key.parse(armor.src()); + if (ret) { + RNP_LOG("failed to parse key pkt at %" PRIu64, keypos); + key.key = {}; + return ret; + } + + if (!skip_pgp_packets(armor.src(), {PGP_PKT_TRUST})) { + return RNP_ERROR_READ; + } + + /* direct-key signatures */ + if ((ret = process_pgp_key_signatures(armor.src(), key.signatures, skiperrors))) { + return ret; + } + + /* user ids/attrs with signatures */ + while ((ptag = stream_pkt_type(armor.src())) > 0) { + if ((ptag != PGP_PKT_USER_ID) && (ptag != PGP_PKT_USER_ATTR)) { + break; + } + + pgp_transferable_userid_t uid; + ret = process_pgp_userid(armor.src(), uid, skiperrors); + if ((ret == RNP_ERROR_BAD_FORMAT) && skiperrors && + skip_pgp_packets(armor.src(), {PGP_PKT_TRUST, PGP_PKT_SIGNATURE})) { + /* skip malformed uid */ + continue; + } + if (ret) { + return ret; + } + key.userids.push_back(std::move(uid)); + } + + /* subkeys with signatures */ + while ((ptag = stream_pkt_type(armor.src())) > 0) { + if (!is_subkey_pkt(ptag)) { + break; + } + + pgp_transferable_subkey_t subkey; + ret = process_pgp_subkey(armor.src(), subkey, skiperrors); + if ((ret == RNP_ERROR_BAD_FORMAT) && skiperrors && + skip_pgp_packets(armor.src(), {PGP_PKT_TRUST, PGP_PKT_SIGNATURE})) { + /* skip malformed subkey */ + continue; + } + if (ret) { + return ret; + } + key.subkeys.emplace_back(std::move(subkey)); + } + return ptag >= 0 ? RNP_SUCCESS : RNP_ERROR_BAD_FORMAT; +} + +static rnp_result_t +decrypt_secret_key_v3(pgp_crypt_t *crypt, uint8_t *dec, const uint8_t *enc, size_t len) +{ + size_t idx; + size_t pos = 0; + size_t mpilen; + size_t blsize; + + if (!(blsize = pgp_cipher_block_size(crypt))) { + RNP_LOG("wrong crypto"); + return RNP_ERROR_BAD_STATE; + } + + /* 4 RSA secret mpis with cleartext header */ + for (idx = 0; idx < 4; idx++) { + if (pos + 2 > len) { + RNP_LOG("bad v3 secret key data"); + return RNP_ERROR_BAD_FORMAT; + } + mpilen = (read_uint16(enc + pos) + 7) >> 3; + memcpy(dec + pos, enc + pos, 2); + pos += 2; + if (pos + mpilen > len) { + RNP_LOG("bad v3 secret key data"); + return RNP_ERROR_BAD_FORMAT; + } + pgp_cipher_cfb_decrypt(crypt, dec + pos, enc + pos, mpilen); + pos += mpilen; + if (mpilen < blsize) { + RNP_LOG("bad rsa v3 mpi len"); + return RNP_ERROR_BAD_FORMAT; + } + pgp_cipher_cfb_resync(crypt, enc + pos - blsize); + } + + /* sum16 */ + if (pos + 2 != len) { + return RNP_ERROR_BAD_FORMAT; + } + memcpy(dec + pos, enc + pos, 2); + return RNP_SUCCESS; +} + +static rnp_result_t +parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) +{ + if (!mpis) { + return RNP_ERROR_NULL_POINTER; + } + + /* check the cleartext data */ + switch (key.sec_protection.s2k.usage) { + case PGP_S2KU_NONE: + case PGP_S2KU_ENCRYPTED: { + /* calculate and check sum16 of the cleartext */ + if (len < 2) { + RNP_LOG("No space for checksum."); + return RNP_ERROR_BAD_FORMAT; + } + uint16_t sum = 0; + len -= 2; + for (size_t idx = 0; idx < len; idx++) { + sum += mpis[idx]; + } + uint16_t expsum = read_uint16(mpis + len); + if (sum != expsum) { + RNP_LOG("Wrong key checksum, got 0x%X instead of 0x%X.", (int) sum, (int) expsum); + return RNP_ERROR_DECRYPT_FAILED; + } + break; + } + case PGP_S2KU_ENCRYPTED_AND_HASHED: { + if (len < PGP_SHA1_HASH_SIZE) { + RNP_LOG("No space for hash"); + return RNP_ERROR_BAD_FORMAT; + } + /* calculate and check sha1 hash of the cleartext */ + uint8_t hval[PGP_SHA1_HASH_SIZE]; + try { + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + assert(hash->size() == sizeof(hval)); + len -= PGP_SHA1_HASH_SIZE; + hash->add(mpis, len); + if (hash->finish(hval) != PGP_SHA1_HASH_SIZE) { + return RNP_ERROR_BAD_STATE; + } + } catch (const std::exception &e) { + RNP_LOG("hash calculation failed: %s", e.what()); + return RNP_ERROR_BAD_STATE; + } + if (memcmp(hval, mpis + len, PGP_SHA1_HASH_SIZE)) { + return RNP_ERROR_DECRYPT_FAILED; + } + break; + } + default: + RNP_LOG("unknown s2k usage: %d", (int) key.sec_protection.s2k.usage); + return RNP_ERROR_BAD_PARAMETERS; + } + + try { + /* parse mpis depending on algorithm */ + pgp_packet_body_t body(mpis, len); + + switch (key.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!body.get(key.material.rsa.d) || !body.get(key.material.rsa.p) || + !body.get(key.material.rsa.q) || !body.get(key.material.rsa.u)) { + RNP_LOG("failed to parse rsa secret key data"); + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_DSA: + if (!body.get(key.material.dsa.x)) { + RNP_LOG("failed to parse dsa secret key data"); + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_EDDSA: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + if (!body.get(key.material.ec.x)) { + RNP_LOG("failed to parse ecc secret key data"); + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!body.get(key.material.eg.x)) { + RNP_LOG("failed to parse eg secret key data"); + return RNP_ERROR_BAD_FORMAT; + } + break; + default: + RNP_LOG("unknown pk alg : %d", (int) key.alg); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (body.left()) { + RNP_LOG("extra data in sec key"); + return RNP_ERROR_BAD_FORMAT; + } + key.material.secret = true; + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +rnp_result_t +decrypt_secret_key(pgp_key_pkt_t *key, const char *password) +{ + if (!key) { + return RNP_ERROR_NULL_POINTER; + } + if (!is_secret_key_pkt(key->tag)) { + return RNP_ERROR_BAD_PARAMETERS; + } + /* mark material as not validated as it may be valid for public part */ + key->material.validity.reset(); + + /* check whether data is not encrypted */ + if (!key->sec_protection.s2k.usage) { + return parse_secret_key_mpis(*key, key->sec_data, key->sec_len); + } + + /* check whether secret key data present */ + if (!key->sec_len) { + RNP_LOG("No secret key data"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* data is encrypted */ + if (!password) { + return RNP_ERROR_NULL_POINTER; + } + + if (key->sec_protection.cipher_mode != PGP_CIPHER_MODE_CFB) { + RNP_LOG("unsupported secret key encryption mode"); + return RNP_ERROR_BAD_PARAMETERS; + } + + rnp::secure_array keybuf; + size_t keysize = pgp_key_size(key->sec_protection.symm_alg); + if (!keysize || + !pgp_s2k_derive_key(&key->sec_protection.s2k, password, keybuf.data(), keysize)) { + RNP_LOG("failed to derive key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + try { + rnp::secure_vector decdata(key->sec_len); + pgp_crypt_t crypt; + if (!pgp_cipher_cfb_start( + &crypt, key->sec_protection.symm_alg, keybuf.data(), key->sec_protection.iv)) { + RNP_LOG("failed to start cfb decryption"); + return RNP_ERROR_DECRYPT_FAILED; + } + + rnp_result_t ret = RNP_ERROR_GENERIC; + switch (key->version) { + case PGP_V3: + if (!is_rsa_key_alg(key->alg)) { + RNP_LOG("non-RSA v3 key"); + ret = RNP_ERROR_BAD_PARAMETERS; + break; + } + ret = decrypt_secret_key_v3(&crypt, decdata.data(), key->sec_data, key->sec_len); + break; + case PGP_V4: + pgp_cipher_cfb_decrypt(&crypt, decdata.data(), key->sec_data, key->sec_len); + ret = RNP_SUCCESS; + break; + default: + ret = RNP_ERROR_BAD_PARAMETERS; + } + + pgp_cipher_cfb_finish(&crypt); + if (ret) { + return ret; + } + + return parse_secret_key_mpis(*key, decdata.data(), key->sec_len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +static void +write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) +{ + /* add mpis */ + switch (key.alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + body.add(key.material.rsa.d); + body.add(key.material.rsa.p); + body.add(key.material.rsa.q); + body.add(key.material.rsa.u); + break; + case PGP_PKA_DSA: + body.add(key.material.dsa.x); + break; + case PGP_PKA_EDDSA: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + body.add(key.material.ec.x); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + body.add(key.material.eg.x); + break; + default: + RNP_LOG("unknown pk alg : %d", (int) key.alg); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + /* add sum16 if sha1 is not used */ + if (key.sec_protection.s2k.usage != PGP_S2KU_ENCRYPTED_AND_HASHED) { + uint16_t sum = 0; + for (size_t i = 0; i < body.size(); i++) { + sum += body.data()[i]; + } + body.add_uint16(sum); + return; + } + + /* add sha1 hash */ + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + hash->add(body.data(), body.size()); + uint8_t hval[PGP_SHA1_HASH_SIZE]; + assert(sizeof(hval) == hash->size()); + if (hash->finish(hval) != PGP_SHA1_HASH_SIZE) { + RNP_LOG("failed to finish hash"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + body.add(hval, PGP_SHA1_HASH_SIZE); +} + +rnp_result_t +encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) +{ + if (!is_secret_key_pkt(key->tag) || !key->material.secret) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (key->sec_protection.s2k.usage && + (key->sec_protection.cipher_mode != PGP_CIPHER_MODE_CFB)) { + RNP_LOG("unsupported secret key encryption mode"); + return RNP_ERROR_BAD_PARAMETERS; + } + + try { + /* build secret key data */ + pgp_packet_body_t body(PGP_PKT_RESERVED); + body.mark_secure(); + write_secret_key_mpis(body, *key); + + /* check whether data is not encrypted */ + if (key->sec_protection.s2k.usage == PGP_S2KU_NONE) { + secure_clear(key->sec_data, key->sec_len); + free(key->sec_data); + key->sec_data = (uint8_t *) malloc(body.size()); + if (!key->sec_data) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(key->sec_data, body.data(), body.size()); + key->sec_len = body.size(); + return RNP_SUCCESS; + } + if (key->version < PGP_V4) { + RNP_LOG("encryption of v3 keys is not supported"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* data is encrypted */ + size_t keysize = pgp_key_size(key->sec_protection.symm_alg); + size_t blsize = pgp_block_size(key->sec_protection.symm_alg); + if (!keysize || !blsize) { + RNP_LOG("wrong symm alg"); + return RNP_ERROR_BAD_PARAMETERS; + } + /* generate iv and s2k salt */ + rng.get(key->sec_protection.iv, blsize); + if ((key->sec_protection.s2k.specifier != PGP_S2KS_SIMPLE)) { + rng.get(key->sec_protection.s2k.salt, PGP_SALT_SIZE); + } + /* derive key */ + rnp::secure_array keybuf; + if (!pgp_s2k_derive_key(&key->sec_protection.s2k, password, keybuf.data(), keysize)) { + RNP_LOG("failed to derive key"); + return RNP_ERROR_BAD_PARAMETERS; + } + /* encrypt sec data */ + pgp_crypt_t crypt; + if (!pgp_cipher_cfb_start( + &crypt, key->sec_protection.symm_alg, keybuf.data(), key->sec_protection.iv)) { + RNP_LOG("failed to start cfb encryption"); + return RNP_ERROR_DECRYPT_FAILED; + } + pgp_cipher_cfb_encrypt(&crypt, body.data(), body.data(), body.size()); + pgp_cipher_cfb_finish(&crypt); + secure_clear(key->sec_data, key->sec_len); + free(key->sec_data); + key->sec_data = (uint8_t *) malloc(body.size()); + if (!key->sec_data) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(key->sec_data, body.data(), body.size()); + key->sec_len = body.size(); + /* cleanup cleartext fields */ + forget_secret_key_fields(&key->material); + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +void +forget_secret_key_fields(pgp_key_material_t *key) +{ + if (!key || !key->secret) { + return; + } + + switch (key->alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + mpi_forget(&key->rsa.d); + mpi_forget(&key->rsa.p); + mpi_forget(&key->rsa.q); + mpi_forget(&key->rsa.u); + break; + case PGP_PKA_DSA: + mpi_forget(&key->dsa.x); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + mpi_forget(&key->eg.x); + break; + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + mpi_forget(&key->ec.x); + break; + default: + RNP_LOG("unknown key algorithm: %d", (int) key->alg); + } + + key->secret = false; +} + +pgp_userid_pkt_t::pgp_userid_pkt_t(const pgp_userid_pkt_t &src) +{ + tag = src.tag; + uid_len = src.uid_len; + uid = NULL; + if (src.uid) { + uid = (uint8_t *) malloc(uid_len); + if (!uid) { + throw std::bad_alloc(); + } + memcpy(uid, src.uid, uid_len); + } +} + +pgp_userid_pkt_t::pgp_userid_pkt_t(pgp_userid_pkt_t &&src) +{ + tag = src.tag; + uid_len = src.uid_len; + uid = src.uid; + src.uid = NULL; +} + +pgp_userid_pkt_t & +pgp_userid_pkt_t::operator=(pgp_userid_pkt_t &&src) +{ + if (this == &src) { + return *this; + } + tag = src.tag; + uid_len = src.uid_len; + free(uid); + uid = src.uid; + src.uid = NULL; + return *this; +} + +pgp_userid_pkt_t & +pgp_userid_pkt_t::operator=(const pgp_userid_pkt_t &src) +{ + if (this == &src) { + return *this; + } + tag = src.tag; + uid_len = src.uid_len; + free(uid); + uid = NULL; + if (src.uid) { + uid = (uint8_t *) malloc(uid_len); + if (!uid) { + throw std::bad_alloc(); + } + memcpy(uid, src.uid, uid_len); + } + return *this; +} + +bool +pgp_userid_pkt_t::operator==(const pgp_userid_pkt_t &src) const +{ + return (tag == src.tag) && (uid_len == src.uid_len) && !memcmp(uid, src.uid, uid_len); +} + +bool +pgp_userid_pkt_t::operator!=(const pgp_userid_pkt_t &src) const +{ + return !(*this == src); +} + +pgp_userid_pkt_t::~pgp_userid_pkt_t() +{ + free(uid); +} + +void +pgp_userid_pkt_t::write(pgp_dest_t &dst) const +{ + if ((tag != PGP_PKT_USER_ID) && (tag != PGP_PKT_USER_ATTR)) { + RNP_LOG("wrong userid tag"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + if (uid_len && !uid) { + RNP_LOG("null but non-empty userid"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + pgp_packet_body_t pktbody(tag); + if (uid) { + pktbody.add(uid, uid_len); + } + pktbody.write(dst); +} + +rnp_result_t +pgp_userid_pkt_t::parse(pgp_source_t &src) +{ + /* check the tag */ + int stag = stream_pkt_type(src); + if ((stag != PGP_PKT_USER_ID) && (stag != PGP_PKT_USER_ATTR)) { + RNP_LOG("wrong userid tag: %d", stag); + return RNP_ERROR_BAD_FORMAT; + } + + pgp_packet_body_t pkt(PGP_PKT_RESERVED); + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + + /* userid type, i.e. tag */ + tag = (pgp_pkt_type_t) stag; + free(uid); + uid = (uint8_t *) malloc(pkt.size()); + if (!uid) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(uid, pkt.data(), pkt.size()); + uid_len = pkt.size(); + return RNP_SUCCESS; +} + +pgp_key_pkt_t::pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly) +{ + if (pubonly && is_secret_key_pkt(src.tag)) { + tag = (src.tag == PGP_PKT_SECRET_KEY) ? PGP_PKT_PUBLIC_KEY : PGP_PKT_PUBLIC_SUBKEY; + } else { + tag = src.tag; + } + version = src.version; + creation_time = src.creation_time; + alg = src.alg; + v3_days = src.v3_days; + hashed_len = src.hashed_len; + hashed_data = NULL; + if (src.hashed_data) { + hashed_data = (uint8_t *) malloc(hashed_len); + if (!hashed_data) { + throw std::bad_alloc(); + } + memcpy(hashed_data, src.hashed_data, hashed_len); + } + material = src.material; + if (pubonly) { + forget_secret_key_fields(&material); + sec_len = 0; + sec_data = NULL; + sec_protection = {}; + return; + } + sec_len = src.sec_len; + sec_data = NULL; + if (src.sec_data) { + sec_data = (uint8_t *) malloc(sec_len); + if (!sec_data) { + free(hashed_data); + hashed_data = NULL; + throw std::bad_alloc(); + } + memcpy(sec_data, src.sec_data, sec_len); + } + sec_protection = src.sec_protection; +} + +pgp_key_pkt_t::pgp_key_pkt_t(pgp_key_pkt_t &&src) +{ + tag = src.tag; + version = src.version; + creation_time = src.creation_time; + alg = src.alg; + v3_days = src.v3_days; + hashed_len = src.hashed_len; + hashed_data = src.hashed_data; + src.hashed_data = NULL; + material = src.material; + forget_secret_key_fields(&src.material); + sec_len = src.sec_len; + sec_data = src.sec_data; + src.sec_data = NULL; + sec_protection = src.sec_protection; +} + +pgp_key_pkt_t & +pgp_key_pkt_t::operator=(pgp_key_pkt_t &&src) +{ + if (this == &src) { + return *this; + } + tag = src.tag; + version = src.version; + creation_time = src.creation_time; + alg = src.alg; + v3_days = src.v3_days; + hashed_len = src.hashed_len; + free(hashed_data); + hashed_data = src.hashed_data; + src.hashed_data = NULL; + material = src.material; + forget_secret_key_fields(&src.material); + secure_clear(sec_data, sec_len); + free(sec_data); + sec_len = src.sec_len; + sec_data = src.sec_data; + src.sec_data = NULL; + src.sec_len = 0; + sec_protection = src.sec_protection; + return *this; +} + +pgp_key_pkt_t & +pgp_key_pkt_t::operator=(const pgp_key_pkt_t &src) +{ + if (this == &src) { + return *this; + } + tag = src.tag; + version = src.version; + creation_time = src.creation_time; + alg = src.alg; + v3_days = src.v3_days; + hashed_len = src.hashed_len; + free(hashed_data); + hashed_data = NULL; + if (src.hashed_data) { + hashed_data = (uint8_t *) malloc(hashed_len); + if (!hashed_data) { + throw std::bad_alloc(); + } + memcpy(hashed_data, src.hashed_data, hashed_len); + } + material = src.material; + secure_clear(sec_data, sec_len); + free(sec_data); + sec_data = NULL; + sec_len = src.sec_len; + if (src.sec_data) { + sec_data = (uint8_t *) malloc(sec_len); + if (!sec_data) { + free(hashed_data); + hashed_data = NULL; + throw std::bad_alloc(); + } + memcpy(sec_data, src.sec_data, sec_len); + } + sec_protection = src.sec_protection; + return *this; +} + +pgp_key_pkt_t::~pgp_key_pkt_t() +{ + forget_secret_key_fields(&material); + free(hashed_data); + secure_clear(sec_data, sec_len); + free(sec_data); +} + +void +pgp_key_pkt_t::write(pgp_dest_t &dst) +{ + if (!is_key_pkt(tag)) { + RNP_LOG("wrong key tag"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + if (!hashed_data) { + fill_hashed_data(); + } + + pgp_packet_body_t pktbody(tag); + /* all public key data is written in hashed_data */ + pktbody.add(hashed_data, hashed_len); + /* if we have public key then we do not need further processing */ + if (!is_secret_key_pkt(tag)) { + pktbody.write(dst); + return; + } + + /* secret key fields should be pre-populated in sec_data field */ + if ((sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL) && (!sec_data || !sec_len)) { + RNP_LOG("secret key data is not populated"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + pktbody.add_byte(sec_protection.s2k.usage); + + switch (sec_protection.s2k.usage) { + case PGP_S2KU_NONE: + break; + case PGP_S2KU_ENCRYPTED_AND_HASHED: + case PGP_S2KU_ENCRYPTED: { + pktbody.add_byte(sec_protection.symm_alg); + pktbody.add(sec_protection.s2k); + if (sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL) { + size_t blsize = pgp_block_size(sec_protection.symm_alg); + if (!blsize) { + RNP_LOG("wrong block size"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + pktbody.add(sec_protection.iv, blsize); + } + break; + } + default: + RNP_LOG("wrong s2k usage"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + if (sec_len) { + /* if key is stored on card, or exported via gpg --export-secret-subkeys, then + * sec_data is empty */ + pktbody.add(sec_data, sec_len); + } + pktbody.write(dst); +} + +rnp_result_t +pgp_key_pkt_t::parse(pgp_source_t &src) +{ + /* check the key tag */ + int atag = stream_pkt_type(src); + if (!is_key_pkt(atag)) { + RNP_LOG("wrong key packet tag: %d", atag); + return RNP_ERROR_BAD_FORMAT; + } + + pgp_packet_body_t pkt((pgp_pkt_type_t) atag); + /* Read the packet into memory */ + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + /* key type, i.e. tag */ + tag = (pgp_pkt_type_t) atag; + /* version */ + uint8_t ver = 0; + if (!pkt.get(ver) || (ver < PGP_V2) || (ver > PGP_V4)) { + RNP_LOG("wrong key packet version"); + return RNP_ERROR_BAD_FORMAT; + } + version = (pgp_version_t) ver; + /* creation time */ + if (!pkt.get(creation_time)) { + return RNP_ERROR_BAD_FORMAT; + } + /* v3: validity days */ + if ((version < PGP_V4) && !pkt.get(v3_days)) { + return RNP_ERROR_BAD_FORMAT; + } + /* key algorithm */ + uint8_t analg = 0; + if (!pkt.get(analg)) { + return RNP_ERROR_BAD_FORMAT; + } + alg = (pgp_pubkey_alg_t) analg; + material.alg = (pgp_pubkey_alg_t) analg; + /* v3 keys must be RSA-only */ + if ((version < PGP_V4) && !is_rsa_key_alg(alg)) { + RNP_LOG("wrong v3 pk algorithm"); + return RNP_ERROR_BAD_FORMAT; + } + /* algorithm specific fields */ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + if (!pkt.get(material.rsa.n) || !pkt.get(material.rsa.e)) { + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_DSA: + if (!pkt.get(material.dsa.p) || !pkt.get(material.dsa.q) || !pkt.get(material.dsa.g) || + !pkt.get(material.dsa.y)) { + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!pkt.get(material.eg.p) || !pkt.get(material.eg.g) || !pkt.get(material.eg.y)) { + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + if (!pkt.get(material.ec.curve) || !pkt.get(material.ec.p)) { + return RNP_ERROR_BAD_FORMAT; + } + break; + case PGP_PKA_ECDH: { + if (!pkt.get(material.ec.curve) || !pkt.get(material.ec.p)) { + return RNP_ERROR_BAD_FORMAT; + } + /* read KDF parameters. At the moment should be 0x03 0x01 halg ealg */ + uint8_t len = 0, halg = 0, walg = 0; + if (!pkt.get(len) || (len != 3)) { + return RNP_ERROR_BAD_FORMAT; + } + if (!pkt.get(len) || (len != 1)) { + return RNP_ERROR_BAD_FORMAT; + } + if (!pkt.get(halg) || !pkt.get(walg)) { + return RNP_ERROR_BAD_FORMAT; + } + material.ec.kdf_hash_alg = (pgp_hash_alg_t) halg; + material.ec.key_wrap_alg = (pgp_symm_alg_t) walg; + break; + } + default: + RNP_LOG("unknown key algorithm: %d", (int) alg); + return RNP_ERROR_BAD_FORMAT; + } + /* fill hashed data used for signatures */ + if (!(hashed_data = (uint8_t *) malloc(pkt.size() - pkt.left()))) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(hashed_data, pkt.data(), pkt.size() - pkt.left()); + hashed_len = pkt.size() - pkt.left(); + + /* secret key fields if any */ + if (is_secret_key_pkt(tag)) { + uint8_t usage = 0; + if (!pkt.get(usage)) { + RNP_LOG("failed to read key protection"); + return RNP_ERROR_BAD_FORMAT; + } + sec_protection.s2k.usage = (pgp_s2k_usage_t) usage; + sec_protection.cipher_mode = PGP_CIPHER_MODE_CFB; + + switch (sec_protection.s2k.usage) { + case PGP_S2KU_NONE: + break; + case PGP_S2KU_ENCRYPTED: + case PGP_S2KU_ENCRYPTED_AND_HASHED: { + /* we have s2k */ + uint8_t salg = 0; + if (!pkt.get(salg) || !pkt.get(sec_protection.s2k)) { + RNP_LOG("failed to read key protection"); + return RNP_ERROR_BAD_FORMAT; + } + sec_protection.symm_alg = (pgp_symm_alg_t) salg; + break; + } + default: + /* old-style: usage is symmetric algorithm identifier */ + sec_protection.symm_alg = (pgp_symm_alg_t) usage; + sec_protection.s2k.usage = PGP_S2KU_ENCRYPTED; + sec_protection.s2k.specifier = PGP_S2KS_SIMPLE; + sec_protection.s2k.hash_alg = PGP_HASH_MD5; + break; + } + + /* iv */ + if (sec_protection.s2k.usage && + (sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL)) { + size_t bl_size = pgp_block_size(sec_protection.symm_alg); + if (!bl_size || !pkt.get(sec_protection.iv, bl_size)) { + RNP_LOG("failed to read iv"); + return RNP_ERROR_BAD_FORMAT; + } + } + + /* encrypted/cleartext secret MPIs are left */ + size_t asec_len = pkt.left(); + if (!asec_len) { + sec_data = NULL; + } else { + if (!(sec_data = (uint8_t *) calloc(1, asec_len))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + if (!pkt.get(sec_data, asec_len)) { + return RNP_ERROR_BAD_STATE; + } + } + sec_len = asec_len; + } + + if (pkt.left()) { + RNP_LOG("extra %d bytes in key packet", (int) pkt.left()); + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; +} + +void +pgp_key_pkt_t::fill_hashed_data() +{ + /* we don't have a need to write v2-v3 signatures */ + if (version != PGP_V4) { + RNP_LOG("unknown key version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + pgp_packet_body_t hbody(PGP_PKT_RESERVED); + hbody.add_byte(version); + hbody.add_uint32(creation_time); + hbody.add_byte(alg); + /* Algorithm specific fields */ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + hbody.add(material.rsa.n); + hbody.add(material.rsa.e); + break; + case PGP_PKA_DSA: + hbody.add(material.dsa.p); + hbody.add(material.dsa.q); + hbody.add(material.dsa.g); + hbody.add(material.dsa.y); + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + hbody.add(material.eg.p); + hbody.add(material.eg.g); + hbody.add(material.eg.y); + break; + case PGP_PKA_ECDSA: + case PGP_PKA_EDDSA: + case PGP_PKA_SM2: + hbody.add(material.ec.curve); + hbody.add(material.ec.p); + break; + case PGP_PKA_ECDH: + hbody.add(material.ec.curve); + hbody.add(material.ec.p); + hbody.add_byte(3); + hbody.add_byte(1); + hbody.add_byte(material.ec.kdf_hash_alg); + hbody.add_byte(material.ec.key_wrap_alg); + break; + default: + RNP_LOG("unknown key algorithm: %d", (int) alg); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + hashed_data = (uint8_t *) malloc(hbody.size()); + if (!hashed_data) { + RNP_LOG("allocation failed"); + throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY); + } + memcpy(hashed_data, hbody.data(), hbody.size()); + hashed_len = hbody.size(); +} + +bool +pgp_key_pkt_t::equals(const pgp_key_pkt_t &key, bool pubonly) const noexcept +{ + /* check tag. We allow public/secret key comparison here */ + if (pubonly) { + if (is_subkey_pkt(tag) && !is_subkey_pkt(key.tag)) { + return false; + } + if (is_key_pkt(tag) && !is_key_pkt(key.tag)) { + return false; + } + } else if (tag != key.tag) { + return false; + } + /* check basic fields */ + if ((version != key.version) || (alg != key.alg) || (creation_time != key.creation_time)) { + return false; + } + /* check key material */ + return key_material_equal(&material, &key.material); +} + +pgp_transferable_subkey_t::pgp_transferable_subkey_t(const pgp_transferable_subkey_t &src, + bool pubonly) +{ + subkey = pgp_key_pkt_t(src.subkey, pubonly); + signatures = src.signatures; +} + +pgp_transferable_key_t::pgp_transferable_key_t(const pgp_transferable_key_t &src, bool pubonly) +{ + key = pgp_key_pkt_t(src.key, pubonly); + userids = src.userids; + subkeys = src.subkeys; + signatures = src.signatures; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-key.h b/comm/third_party/rnp/src/librepgp/stream-key.h new file mode 100644 index 0000000000..a19a986455 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-key.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_KEY_H_ +#define STREAM_KEY_H_ + +#include +#include +#include +#include "rnp.h" +#include "stream-common.h" +#include "stream-sig.h" +#include "stream-packet.h" + +/** Struct to hold a key packet. May contain public or private key/subkey */ +typedef struct pgp_key_pkt_t { + pgp_pkt_type_t tag; /* packet tag: public key/subkey or private key/subkey */ + pgp_version_t version; /* Key packet version */ + uint32_t creation_time; /* Key creation time */ + pgp_pubkey_alg_t alg; + uint16_t v3_days; /* v2/v3 validity time */ + + uint8_t *hashed_data; /* key's hashed data used for signature calculation */ + size_t hashed_len; + + pgp_key_material_t material; + + /* secret key data, if available. sec_len == 0, sec_data == NULL for public key/subkey */ + pgp_key_protection_t sec_protection; + uint8_t * sec_data; + size_t sec_len; + + pgp_key_pkt_t() + : tag(PGP_PKT_RESERVED), version(PGP_VUNKNOWN), creation_time(0), alg(PGP_PKA_NOTHING), + v3_days(0), hashed_data(NULL), hashed_len(0), material({}), sec_protection({}), + sec_data(NULL), sec_len(0){}; + pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly = false); + pgp_key_pkt_t(pgp_key_pkt_t &&src); + pgp_key_pkt_t &operator=(pgp_key_pkt_t &&src); + pgp_key_pkt_t &operator=(const pgp_key_pkt_t &src); + ~pgp_key_pkt_t(); + + void write(pgp_dest_t &dst); + rnp_result_t parse(pgp_source_t &src); + /** @brief Fills the hashed (signed) data part of the key packet. Must be called before + * pgp_key_pkt_t::write() on the newly generated key */ + void fill_hashed_data(); + bool equals(const pgp_key_pkt_t &key, bool pubonly = false) const noexcept; +} pgp_key_pkt_t; + +/* userid/userattr with all the corresponding signatures */ +typedef struct pgp_transferable_userid_t { + pgp_userid_pkt_t uid; + pgp_signature_list_t signatures; +} pgp_transferable_userid_t; + +/* subkey with all corresponding signatures */ +typedef struct pgp_transferable_subkey_t { + pgp_key_pkt_t subkey; + pgp_signature_list_t signatures; + + pgp_transferable_subkey_t() = default; + pgp_transferable_subkey_t(const pgp_transferable_subkey_t &src, bool pubonly = false); + pgp_transferable_subkey_t &operator=(const pgp_transferable_subkey_t &) = default; +} pgp_transferable_subkey_t; + +/* transferable key with userids, subkeys and revocation signatures */ +typedef struct pgp_transferable_key_t { + pgp_key_pkt_t key; /* main key packet */ + std::vector userids; + std::vector subkeys; + pgp_signature_list_t signatures; + + pgp_transferable_key_t() = default; + pgp_transferable_key_t(const pgp_transferable_key_t &src, bool pubonly = false); + pgp_transferable_key_t &operator=(const pgp_transferable_key_t &) = default; +} pgp_transferable_key_t; + +/* sequence of OpenPGP transferable keys */ +typedef struct pgp_key_sequence_t { + std::vector keys; +} pgp_key_sequence_t; + +rnp_result_t transferable_key_from_key(pgp_transferable_key_t &dst, const pgp_key_t &key); + +rnp_result_t transferable_key_merge(pgp_transferable_key_t & dst, + const pgp_transferable_key_t &src); + +rnp_result_t transferable_subkey_from_key(pgp_transferable_subkey_t &dst, + const pgp_key_t & key); + +rnp_result_t transferable_subkey_merge(pgp_transferable_subkey_t & dst, + const pgp_transferable_subkey_t &src); + +/* Process single primary key or subkey, skipping all key-related packets on error. + If key.key.tag is zero, then (on success) result is subkey and it is stored in + key.subkeys[0]. + If returns RNP_ERROR_BAD_FORMAT then some packets failed parsing, but still key may contain + successfully read key or subkey. +*/ +rnp_result_t process_pgp_key_auto(pgp_source_t & src, + pgp_transferable_key_t &key, + bool allowsub, + bool skiperrors); + +rnp_result_t process_pgp_keys(pgp_source_t &src, pgp_key_sequence_t &keys, bool skiperrors); + +rnp_result_t process_pgp_key(pgp_source_t &src, pgp_transferable_key_t &key, bool skiperrors); + +rnp_result_t process_pgp_subkey(pgp_source_t & src, + pgp_transferable_subkey_t &subkey, + bool skiperrors); + +rnp_result_t decrypt_secret_key(pgp_key_pkt_t *key, const char *password); + +rnp_result_t encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng); + +void forget_secret_key_fields(pgp_key_material_t *key); + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-packet.cpp b/comm/third_party/rnp/src/librepgp/stream-packet.cpp new file mode 100644 index 0000000000..49dd63d09c --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-packet.cpp @@ -0,0 +1,1228 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include +#include "types.h" +#include "crypto.h" +#include "crypto/mem.h" +#include "stream-packet.h" +#include "stream-key.h" +#include + +uint32_t +read_uint32(const uint8_t *buf) +{ + return ((uint32_t) buf[0] << 24) | ((uint32_t) buf[1] << 16) | ((uint32_t) buf[2] << 8) | + (uint32_t) buf[3]; +} + +uint16_t +read_uint16(const uint8_t *buf) +{ + return ((uint16_t) buf[0] << 8) | buf[1]; +} + +void +write_uint16(uint8_t *buf, uint16_t val) +{ + buf[0] = val >> 8; + buf[1] = val & 0xff; +} + +size_t +write_packet_len(uint8_t *buf, size_t len) +{ + if (len < 192) { + buf[0] = len; + return 1; + } else if (len < 8192 + 192) { + buf[0] = ((len - 192) >> 8) + 192; + buf[1] = (len - 192) & 0xff; + return 2; + } else { + buf[0] = 0xff; + STORE32BE(&buf[1], len); + return 5; + } +} + +int +get_packet_type(uint8_t ptag) +{ + if (!(ptag & PGP_PTAG_ALWAYS_SET)) { + return -1; + } + + if (ptag & PGP_PTAG_NEW_FORMAT) { + return (int) (ptag & PGP_PTAG_NF_CONTENT_TAG_MASK); + } else { + return (int) ((ptag & PGP_PTAG_OF_CONTENT_TAG_MASK) >> PGP_PTAG_OF_CONTENT_TAG_SHIFT); + } +} + +int +stream_pkt_type(pgp_source_t &src) +{ + if (src_eof(&src)) { + return 0; + } + size_t hdrneed = 0; + if (!stream_pkt_hdr_len(src, hdrneed)) { + return -1; + } + uint8_t hdr[PGP_MAX_HEADER_SIZE]; + if (!src_peek_eq(&src, hdr, hdrneed)) { + return -1; + } + return get_packet_type(hdr[0]); +} + +bool +stream_pkt_hdr_len(pgp_source_t &src, size_t &hdrlen) +{ + uint8_t buf[2]; + + if (!src_peek_eq(&src, buf, 2) || !(buf[0] & PGP_PTAG_ALWAYS_SET)) { + return false; + } + + if (buf[0] & PGP_PTAG_NEW_FORMAT) { + if (buf[1] < 192) { + hdrlen = 2; + } else if (buf[1] < 224) { + hdrlen = 3; + } else if (buf[1] < 255) { + hdrlen = 2; + } else { + hdrlen = 6; + } + return true; + } + + switch (buf[0] & PGP_PTAG_OF_LENGTH_TYPE_MASK) { + case PGP_PTAG_OLD_LEN_1: + hdrlen = 2; + return true; + case PGP_PTAG_OLD_LEN_2: + hdrlen = 3; + return true; + case PGP_PTAG_OLD_LEN_4: + hdrlen = 5; + return true; + case PGP_PTAG_OLD_LEN_INDETERMINATE: + hdrlen = 1; + return true; + default: + return false; + } +} + +static bool +get_pkt_len(uint8_t *hdr, size_t *pktlen) +{ + if (hdr[0] & PGP_PTAG_NEW_FORMAT) { + // 1-byte length + if (hdr[1] < 192) { + *pktlen = hdr[1]; + return true; + } + // 2-byte length + if (hdr[1] < 224) { + *pktlen = ((size_t)(hdr[1] - 192) << 8) + (size_t) hdr[2] + 192; + return true; + } + // partial length - we do not allow it here + if (hdr[1] < 255) { + return false; + } + // 4-byte length + *pktlen = read_uint32(&hdr[2]); + return true; + } + + switch (hdr[0] & PGP_PTAG_OF_LENGTH_TYPE_MASK) { + case PGP_PTAG_OLD_LEN_1: + *pktlen = hdr[1]; + return true; + case PGP_PTAG_OLD_LEN_2: + *pktlen = read_uint16(&hdr[1]); + return true; + case PGP_PTAG_OLD_LEN_4: + *pktlen = read_uint32(&hdr[1]); + return true; + default: + return false; + } +} + +bool +stream_read_pkt_len(pgp_source_t *src, size_t *pktlen) +{ + uint8_t buf[6] = {}; + size_t read = 0; + + if (!stream_pkt_hdr_len(*src, read)) { + return false; + } + + if (!src_read_eq(src, buf, read)) { + return false; + } + + return get_pkt_len(buf, pktlen); +} + +bool +stream_read_partial_chunk_len(pgp_source_t *src, size_t *clen, bool *last) +{ + uint8_t hdr[5] = {}; + size_t read = 0; + + if (!src_read(src, hdr, 1, &read)) { + RNP_LOG("failed to read header"); + return false; + } + if (read < 1) { + RNP_LOG("wrong eof"); + return false; + } + + *last = true; + // partial length + if ((hdr[0] >= 224) && (hdr[0] < 255)) { + *last = false; + *clen = get_partial_pkt_len(hdr[0]); + return true; + } + // 1-byte length + if (hdr[0] < 192) { + *clen = hdr[0]; + return true; + } + // 2-byte length + if (hdr[0] < 224) { + if (!src_read_eq(src, &hdr[1], 1)) { + RNP_LOG("wrong 2-byte length"); + return false; + } + *clen = ((size_t)(hdr[0] - 192) << 8) + (size_t) hdr[1] + 192; + return true; + } + // 4-byte length + if (!src_read_eq(src, &hdr[1], 4)) { + RNP_LOG("wrong 4-byte length"); + return false; + } + *clen = ((size_t) hdr[1] << 24) | ((size_t) hdr[2] << 16) | ((size_t) hdr[3] << 8) | + (size_t) hdr[4]; + return true; +} + +bool +stream_old_indeterminate_pkt_len(pgp_source_t *src) +{ + uint8_t ptag = 0; + if (!src_peek_eq(src, &ptag, 1)) { + return false; + } + return !(ptag & PGP_PTAG_NEW_FORMAT) && + ((ptag & PGP_PTAG_OF_LENGTH_TYPE_MASK) == PGP_PTAG_OLD_LEN_INDETERMINATE); +} + +bool +stream_partial_pkt_len(pgp_source_t *src) +{ + uint8_t hdr[2] = {}; + if (!src_peek_eq(src, hdr, 2)) { + return false; + } + return (hdr[0] & PGP_PTAG_NEW_FORMAT) && (hdr[1] >= 224) && (hdr[1] < 255); +} + +size_t +get_partial_pkt_len(uint8_t blen) +{ + return 1 << (blen & 0x1f); +} + +rnp_result_t +stream_peek_packet_hdr(pgp_source_t *src, pgp_packet_hdr_t *hdr) +{ + size_t hlen = 0; + memset(hdr, 0, sizeof(*hdr)); + if (!stream_pkt_hdr_len(*src, hlen)) { + uint8_t hdr2[2] = {0}; + if (!src_peek_eq(src, hdr2, 2)) { + RNP_LOG("pkt header read failed"); + return RNP_ERROR_READ; + } + + RNP_LOG("bad packet header: 0x%02x%02x", hdr2[0], hdr2[1]); + return RNP_ERROR_BAD_FORMAT; + } + + if (!src_peek_eq(src, hdr->hdr, hlen)) { + RNP_LOG("failed to read pkt header"); + return RNP_ERROR_READ; + } + + hdr->hdr_len = hlen; + hdr->tag = (pgp_pkt_type_t) get_packet_type(hdr->hdr[0]); + + if (stream_partial_pkt_len(src)) { + hdr->partial = true; + } else if (stream_old_indeterminate_pkt_len(src)) { + hdr->indeterminate = true; + } else { + (void) get_pkt_len(hdr->hdr, &hdr->pkt_len); + } + + return RNP_SUCCESS; +} + +static rnp_result_t +stream_read_packet_partial(pgp_source_t *src, pgp_dest_t *dst) +{ + uint8_t hdr = 0; + if (!src_read_eq(src, &hdr, 1)) { + return RNP_ERROR_READ; + } + + bool last = false; + size_t partlen = 0; + if (!stream_read_partial_chunk_len(src, &partlen, &last)) { + return RNP_ERROR_BAD_FORMAT; + } + + uint8_t *buf = (uint8_t *) malloc(PGP_INPUT_CACHE_SIZE); + if (!buf) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + while (partlen > 0) { + size_t read = std::min(partlen, (size_t) PGP_INPUT_CACHE_SIZE); + if (!src_read_eq(src, buf, read)) { + free(buf); + return RNP_ERROR_READ; + } + if (dst) { + dst_write(dst, buf, read); + } + partlen -= read; + if (partlen > 0) { + continue; + } + if (last) { + break; + } + if (!stream_read_partial_chunk_len(src, &partlen, &last)) { + free(buf); + return RNP_ERROR_BAD_FORMAT; + } + } + free(buf); + return RNP_SUCCESS; +} + +rnp_result_t +stream_read_packet(pgp_source_t *src, pgp_dest_t *dst) +{ + if (stream_old_indeterminate_pkt_len(src)) { + return dst_write_src(src, dst, PGP_MAX_OLD_LEN_INDETERMINATE_PKT_SIZE); + } + + if (stream_partial_pkt_len(src)) { + return stream_read_packet_partial(src, dst); + } + + try { + pgp_packet_body_t body(PGP_PKT_RESERVED); + rnp_result_t ret = body.read(*src); + if (dst) { + body.write(*dst, false); + } + return ret; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } +} + +rnp_result_t +stream_skip_packet(pgp_source_t *src) +{ + return stream_read_packet(src, NULL); +} + +rnp_result_t +stream_parse_marker(pgp_source_t &src) +{ + try { + pgp_packet_body_t pkt(PGP_PKT_MARKER); + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + if ((pkt.size() != PGP_MARKER_LEN) || + memcmp(pkt.data(), PGP_MARKER_CONTENTS, PGP_MARKER_LEN)) { + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } +} + +bool +is_key_pkt(int tag) +{ + switch (tag) { + case PGP_PKT_PUBLIC_KEY: + case PGP_PKT_PUBLIC_SUBKEY: + case PGP_PKT_SECRET_KEY: + case PGP_PKT_SECRET_SUBKEY: + return true; + default: + return false; + } +} + +bool +is_subkey_pkt(int tag) +{ + return (tag == PGP_PKT_PUBLIC_SUBKEY) || (tag == PGP_PKT_SECRET_SUBKEY); +} + +bool +is_primary_key_pkt(int tag) +{ + return (tag == PGP_PKT_PUBLIC_KEY) || (tag == PGP_PKT_SECRET_KEY); +} + +bool +is_public_key_pkt(int tag) +{ + switch (tag) { + case PGP_PKT_PUBLIC_KEY: + case PGP_PKT_PUBLIC_SUBKEY: + return true; + default: + return false; + } +} + +bool +is_secret_key_pkt(int tag) +{ + switch (tag) { + case PGP_PKT_SECRET_KEY: + case PGP_PKT_SECRET_SUBKEY: + return true; + default: + return false; + } +} + +bool +is_rsa_key_alg(pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return true; + default: + return false; + } +} + +pgp_packet_body_t::pgp_packet_body_t(pgp_pkt_type_t tag) +{ + data_.reserve(16); + tag_ = tag; + secure_ = is_secret_key_pkt(tag); +} + +pgp_packet_body_t::pgp_packet_body_t(const uint8_t *data, size_t len) +{ + data_.assign(data, data + len); + tag_ = PGP_PKT_RESERVED; + secure_ = false; +} + +pgp_packet_body_t::~pgp_packet_body_t() +{ + if (secure_) { + secure_clear(data_.data(), data_.size()); + } +} + +uint8_t * +pgp_packet_body_t::data() noexcept +{ + return data_.data(); +} + +size_t +pgp_packet_body_t::size() const noexcept +{ + return data_.size(); +} + +size_t +pgp_packet_body_t::left() const noexcept +{ + return data_.size() - pos_; +} + +bool +pgp_packet_body_t::get(uint8_t &val) noexcept +{ + if (pos_ >= data_.size()) { + return false; + } + val = data_[pos_++]; + return true; +} + +bool +pgp_packet_body_t::get(uint16_t &val) noexcept +{ + if (pos_ + 2 > data_.size()) { + return false; + } + val = read_uint16(data_.data() + pos_); + pos_ += 2; + return true; +} + +bool +pgp_packet_body_t::get(uint32_t &val) noexcept +{ + if (pos_ + 4 > data_.size()) { + return false; + } + val = read_uint32(data_.data() + pos_); + pos_ += 4; + return true; +} + +bool +pgp_packet_body_t::get(uint8_t *val, size_t len) noexcept +{ + if (pos_ + len > data_.size()) { + return false; + } + memcpy(val, data_.data() + pos_, len); + pos_ += len; + return true; +} + +bool +pgp_packet_body_t::get(pgp_key_id_t &val) noexcept +{ + static_assert(std::tuple_size::value == PGP_KEY_ID_SIZE, + "pgp_key_id_t size mismatch"); + return get(val.data(), val.size()); +} + +bool +pgp_packet_body_t::get(pgp_mpi_t &val) noexcept +{ + uint16_t bits = 0; + if (!get(bits)) { + return false; + } + size_t len = (bits + 7) >> 3; + if (len > PGP_MPINT_SIZE) { + RNP_LOG("too large mpi"); + return false; + } + if (!len) { + RNP_LOG("0 mpi"); + return false; + } + if (!get(val.mpi, len)) { + RNP_LOG("failed to read mpi body"); + return false; + } + /* check the mpi bit count */ + val.len = len; + size_t mbits = mpi_bits(&val); + if (mbits != bits) { + RNP_LOG( + "Warning! Wrong mpi bit count: got %" PRIu16 ", but actual is %zu", bits, mbits); + } + return true; +} + +bool +pgp_packet_body_t::get(pgp_curve_t &val) noexcept +{ + uint8_t oidlen = 0; + if (!get(oidlen)) { + return false; + } + uint8_t oid[MAX_CURVE_OID_HEX_LEN] = {0}; + if (!oidlen || (oidlen == 0xff) || (oidlen > sizeof(oid))) { + RNP_LOG("unsupported curve oid len: %" PRIu8, oidlen); + return false; + } + if (!get(oid, oidlen)) { + return false; + } + pgp_curve_t res = find_curve_by_OID(oid, oidlen); + if (res == PGP_CURVE_MAX) { + RNP_LOG("unsupported curve"); + return false; + } + val = res; + return true; +} + +bool +pgp_packet_body_t::get(pgp_s2k_t &s2k) noexcept +{ + uint8_t spec = 0, halg = 0; + if (!get(spec) || !get(halg)) { + return false; + } + s2k.specifier = (pgp_s2k_specifier_t) spec; + s2k.hash_alg = (pgp_hash_alg_t) halg; + + switch (s2k.specifier) { + case PGP_S2KS_SIMPLE: + return true; + case PGP_S2KS_SALTED: + return get(s2k.salt, PGP_SALT_SIZE); + case PGP_S2KS_ITERATED_AND_SALTED: { + uint8_t iter = 0; + if (!get(s2k.salt, PGP_SALT_SIZE) || !get(iter)) { + return false; + } + s2k.iterations = iter; + return true; + } + case PGP_S2KS_EXPERIMENTAL: { + try { + s2k.experimental = {data_.begin() + pos_, data_.end()}; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + uint8_t gnu[3] = {0}; + if (!get(gnu, 3) || memcmp(gnu, "GNU", 3)) { + RNP_LOG("Unknown experimental s2k. Skipping."); + pos_ = data_.size(); + s2k.gpg_ext_num = PGP_S2K_GPG_NONE; + return true; + } + uint8_t ext_num = 0; + if (!get(ext_num)) { + return false; + } + if ((ext_num != PGP_S2K_GPG_NO_SECRET) && (ext_num != PGP_S2K_GPG_SMARTCARD)) { + RNP_LOG("Unsupported gpg extension num: %" PRIu8 ", skipping", ext_num); + pos_ = data_.size(); + s2k.gpg_ext_num = PGP_S2K_GPG_NONE; + return true; + } + s2k.gpg_ext_num = (pgp_s2k_gpg_extension_t) ext_num; + if (s2k.gpg_ext_num == PGP_S2K_GPG_NO_SECRET) { + return true; + } + if (!get(s2k.gpg_serial_len)) { + RNP_LOG("Failed to get GPG serial len"); + return false; + } + size_t len = s2k.gpg_serial_len; + if (s2k.gpg_serial_len > 16) { + RNP_LOG("Warning: gpg_serial_len is %d", (int) len); + len = 16; + } + if (!get(s2k.gpg_serial, len)) { + RNP_LOG("Failed to get GPG serial"); + return false; + } + return true; + } + default: + RNP_LOG("unknown s2k specifier: %d", (int) s2k.specifier); + return false; + } +} + +void +pgp_packet_body_t::add(const void *data, size_t len) +{ + data_.insert(data_.end(), (uint8_t *) data, (uint8_t *) data + len); +} + +void +pgp_packet_body_t::add_byte(uint8_t bt) +{ + data_.push_back(bt); +} + +void +pgp_packet_body_t::add_uint16(uint16_t val) +{ + uint8_t bytes[2]; + write_uint16(bytes, val); + add(bytes, 2); +} + +void +pgp_packet_body_t::add_uint32(uint32_t val) +{ + uint8_t bytes[4]; + STORE32BE(bytes, val); + add(bytes, 4); +} + +void +pgp_packet_body_t::add(const pgp_key_id_t &val) +{ + add(val.data(), val.size()); +} + +void +pgp_packet_body_t::add(const pgp_mpi_t &val) +{ + if (!val.len) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + unsigned idx = 0; + while ((idx < val.len - 1) && (!val.mpi[idx])) { + idx++; + } + + unsigned bits = (val.len - idx - 1) << 3; + unsigned hibyte = val.mpi[idx]; + while (hibyte) { + bits++; + hibyte = hibyte >> 1; + } + + uint8_t hdr[2] = {(uint8_t)(bits >> 8), (uint8_t)(bits & 0xff)}; + add(hdr, 2); + add(val.mpi + idx, val.len - idx); +} + +void +pgp_packet_body_t::add_subpackets(const pgp_signature_t &sig, bool hashed) +{ + pgp_packet_body_t spbody(PGP_PKT_RESERVED); + + for (auto &subpkt : sig.subpkts) { + if (subpkt.hashed != hashed) { + continue; + } + + uint8_t splen[6]; + size_t lenlen = write_packet_len(splen, subpkt.len + 1); + spbody.add(splen, lenlen); + spbody.add_byte(subpkt.type | (subpkt.critical << 7)); + spbody.add(subpkt.data, subpkt.len); + } + + if (spbody.data_.size() > 0xffff) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + add_uint16(spbody.data_.size()); + add(spbody.data_.data(), spbody.data_.size()); +} + +void +pgp_packet_body_t::add(const pgp_curve_t curve) +{ + const ec_curve_desc_t *desc = get_curve_desc(curve); + if (!desc) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + add_byte((uint8_t) desc->OIDhex_len); + add(desc->OIDhex, (uint8_t) desc->OIDhex_len); +} + +void +pgp_packet_body_t::add(const pgp_s2k_t &s2k) +{ + add_byte(s2k.specifier); + add_byte(s2k.hash_alg); + + switch (s2k.specifier) { + case PGP_S2KS_SIMPLE: + return; + case PGP_S2KS_SALTED: + add(s2k.salt, PGP_SALT_SIZE); + return; + case PGP_S2KS_ITERATED_AND_SALTED: { + unsigned iter = s2k.iterations; + if (iter > 255) { + iter = pgp_s2k_encode_iterations(iter); + } + add(s2k.salt, PGP_SALT_SIZE); + add_byte(iter); + return; + } + case PGP_S2KS_EXPERIMENTAL: { + if ((s2k.gpg_ext_num != PGP_S2K_GPG_NO_SECRET) && + (s2k.gpg_ext_num != PGP_S2K_GPG_SMARTCARD)) { + RNP_LOG("Unknown experimental s2k."); + add(s2k.experimental.data(), s2k.experimental.size()); + return; + } + add("GNU", 3); + add_byte(s2k.gpg_ext_num); + if (s2k.gpg_ext_num == PGP_S2K_GPG_SMARTCARD) { + static_assert(sizeof(s2k.gpg_serial) == 16, "invalid gpg serial length"); + size_t slen = s2k.gpg_serial_len > 16 ? 16 : s2k.gpg_serial_len; + add_byte(s2k.gpg_serial_len); + add(s2k.gpg_serial, slen); + } + return; + } + default: + RNP_LOG("unknown s2k specifier"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +rnp_result_t +pgp_packet_body_t::read(pgp_source_t &src) noexcept +{ + /* Make sure we have enough data for packet header */ + if (!src_peek_eq(&src, hdr_, 2)) { + return RNP_ERROR_READ; + } + + /* Read the packet header and length */ + size_t len = 0; + if (!stream_pkt_hdr_len(src, len)) { + return RNP_ERROR_BAD_FORMAT; + } + if (!src_peek_eq(&src, hdr_, len)) { + return RNP_ERROR_READ; + } + hdr_len_ = len; + + int ptag = get_packet_type(hdr_[0]); + if ((ptag < 0) || ((tag_ != PGP_PKT_RESERVED) && (tag_ != ptag))) { + RNP_LOG("tag mismatch: %d vs %d", (int) tag_, ptag); + return RNP_ERROR_BAD_FORMAT; + } + tag_ = (pgp_pkt_type_t) ptag; + + if (!stream_read_pkt_len(&src, &len)) { + return RNP_ERROR_READ; + } + + /* early exit for the empty packet */ + if (!len) { + return RNP_SUCCESS; + } + + if (len > PGP_MAX_PKT_SIZE) { + RNP_LOG("too large packet"); + return RNP_ERROR_BAD_FORMAT; + } + + /* Read the packet contents */ + try { + data_.resize(len); + } catch (const std::exception &e) { + RNP_LOG("malloc of %d bytes failed, %s", (int) len, e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + + size_t read = 0; + if (!src_read(&src, data_.data(), len, &read) || (read != len)) { + RNP_LOG("read %d instead of %d", (int) read, (int) len); + return RNP_ERROR_READ; + } + pos_ = 0; + return RNP_SUCCESS; +} + +void +pgp_packet_body_t::write(pgp_dest_t &dst, bool hdr) noexcept +{ + if (hdr) { + uint8_t hdrbt[6] = { + (uint8_t)(tag_ | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT), 0, 0, 0, 0, 0}; + size_t hlen = 1 + write_packet_len(&hdrbt[1], data_.size()); + dst_write(&dst, hdrbt, hlen); + } + dst_write(&dst, data_.data(), data_.size()); +} + +void +pgp_packet_body_t::mark_secure(bool secure) noexcept +{ + secure_ = secure; +} + +void +pgp_sk_sesskey_t::write(pgp_dest_t &dst) const +{ + pgp_packet_body_t pktbody(PGP_PKT_SK_SESSION_KEY); + /* version and algorithm fields */ + pktbody.add_byte(version); + pktbody.add_byte(alg); + if (version == PGP_SKSK_V5) { + pktbody.add_byte(aalg); + } + /* S2K specifier */ + pktbody.add_byte(s2k.specifier); + pktbody.add_byte(s2k.hash_alg); + + switch (s2k.specifier) { + case PGP_S2KS_SIMPLE: + break; + case PGP_S2KS_SALTED: + pktbody.add(s2k.salt, sizeof(s2k.salt)); + break; + case PGP_S2KS_ITERATED_AND_SALTED: + pktbody.add(s2k.salt, sizeof(s2k.salt)); + pktbody.add_byte(s2k.iterations); + break; + default: + RNP_LOG("Unexpected s2k specifier: %d", (int) s2k.specifier); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + /* v5 : iv */ + if (version == PGP_SKSK_V5) { + pktbody.add(iv, ivlen); + } + /* encrypted key and auth tag for v5 */ + if (enckeylen) { + pktbody.add(enckey, enckeylen); + } + /* write packet */ + pktbody.write(dst); +} + +rnp_result_t +pgp_sk_sesskey_t::parse(pgp_source_t &src) +{ + pgp_packet_body_t pkt(PGP_PKT_SK_SESSION_KEY); + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + + /* version */ + uint8_t bt; + if (!pkt.get(bt) || ((bt != PGP_SKSK_V4) && (bt != PGP_SKSK_V5))) { + RNP_LOG("wrong packet version"); + return RNP_ERROR_BAD_FORMAT; + } + version = bt; + /* symmetric algorithm */ + if (!pkt.get(bt)) { + RNP_LOG("failed to get symm alg"); + return RNP_ERROR_BAD_FORMAT; + } + alg = (pgp_symm_alg_t) bt; + + if (version == PGP_SKSK_V5) { + /* aead algorithm */ + if (!pkt.get(bt)) { + RNP_LOG("failed to get aead alg"); + return RNP_ERROR_BAD_FORMAT; + } + aalg = (pgp_aead_alg_t) bt; + if ((aalg != PGP_AEAD_EAX) && (aalg != PGP_AEAD_OCB)) { + RNP_LOG("unsupported AEAD algorithm : %d", (int) aalg); + return RNP_ERROR_BAD_PARAMETERS; + } + } + + /* s2k */ + if (!pkt.get(s2k)) { + RNP_LOG("failed to parse s2k"); + return RNP_ERROR_BAD_FORMAT; + } + + /* v4 key */ + if (version == PGP_SKSK_V4) { + /* encrypted session key if present */ + size_t keylen = pkt.left(); + if (keylen) { + if (keylen > PGP_MAX_KEY_SIZE + 1) { + RNP_LOG("too long esk"); + return RNP_ERROR_BAD_FORMAT; + } + if (!pkt.get(enckey, keylen)) { + RNP_LOG("failed to get key"); + return RNP_ERROR_BAD_FORMAT; + } + } + enckeylen = keylen; + return RNP_SUCCESS; + } + + /* v5: iv + esk + tag. For both EAX and OCB ivlen and taglen are 16 octets */ + size_t noncelen = pgp_cipher_aead_nonce_len(aalg); + size_t taglen = pgp_cipher_aead_tag_len(aalg); + size_t keylen = 0; + + if (pkt.left() > noncelen + taglen + PGP_MAX_KEY_SIZE) { + RNP_LOG("too long esk"); + return RNP_ERROR_BAD_FORMAT; + } + if (pkt.left() < noncelen + taglen + 8) { + RNP_LOG("too short esk"); + return RNP_ERROR_BAD_FORMAT; + } + /* iv */ + if (!pkt.get(iv, noncelen)) { + RNP_LOG("failed to get iv"); + return RNP_ERROR_BAD_FORMAT; + } + ivlen = noncelen; + + /* key */ + keylen = pkt.left(); + if (!pkt.get(enckey, keylen)) { + RNP_LOG("failed to get key"); + return RNP_ERROR_BAD_FORMAT; + } + enckeylen = keylen; + return RNP_SUCCESS; +} + +void +pgp_pk_sesskey_t::write(pgp_dest_t &dst) const +{ + pgp_packet_body_t pktbody(PGP_PKT_PK_SESSION_KEY); + pktbody.add_byte(version); + pktbody.add(key_id); + pktbody.add_byte(alg); + pktbody.add(material_buf.data(), material_buf.size()); + pktbody.write(dst); +} + +rnp_result_t +pgp_pk_sesskey_t::parse(pgp_source_t &src) +{ + pgp_packet_body_t pkt(PGP_PKT_PK_SESSION_KEY); + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + /* version */ + uint8_t bt = 0; + if (!pkt.get(bt) || (bt != PGP_PKSK_V3)) { + RNP_LOG("wrong packet version"); + return RNP_ERROR_BAD_FORMAT; + } + version = bt; + /* key id */ + if (!pkt.get(key_id)) { + RNP_LOG("failed to get key id"); + return RNP_ERROR_BAD_FORMAT; + } + /* public key algorithm */ + if (!pkt.get(bt)) { + RNP_LOG("failed to get palg"); + return RNP_ERROR_BAD_FORMAT; + } + alg = (pgp_pubkey_alg_t) bt; + + /* raw signature material */ + if (!pkt.left()) { + RNP_LOG("No encrypted material"); + return RNP_ERROR_BAD_FORMAT; + } + try { + material_buf.resize(pkt.left()); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + /* we cannot fail here */ + pkt.get(material_buf.data(), material_buf.size()); + /* check whether it can be parsed */ + pgp_encrypted_material_t material = {}; + if (!parse_material(material)) { + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; +} + +bool +pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const +{ + pgp_packet_body_t pkt(material_buf.data(), material_buf.size()); + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + /* RSA m */ + if (!pkt.get(material.rsa.m)) { + RNP_LOG("failed to get rsa m"); + return false; + } + break; + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + /* ElGamal g, m */ + if (!pkt.get(material.eg.g) || !pkt.get(material.eg.m)) { + RNP_LOG("failed to get elgamal mpis"); + return false; + } + break; + case PGP_PKA_SM2: + /* SM2 m */ + if (!pkt.get(material.sm2.m)) { + RNP_LOG("failed to get sm2 m"); + return false; + } + break; + case PGP_PKA_ECDH: { + /* ECDH ephemeral point */ + if (!pkt.get(material.ecdh.p)) { + RNP_LOG("failed to get ecdh p"); + return false; + } + /* ECDH m */ + uint8_t bt = 0; + if (!pkt.get(bt)) { + RNP_LOG("failed to get ecdh m len"); + return false; + } + if (bt > ECDH_WRAPPED_KEY_SIZE) { + RNP_LOG("wrong ecdh m len"); + return false; + } + material.ecdh.mlen = bt; + if (!pkt.get(material.ecdh.m, bt)) { + RNP_LOG("failed to get ecdh m len"); + return false; + } + break; + } + default: + RNP_LOG("unknown pk alg %d", (int) alg); + return false; + } + + if (pkt.left()) { + RNP_LOG("extra %d bytes in pk packet", (int) pkt.left()); + return false; + } + return true; +} + +void +pgp_pk_sesskey_t::write_material(const pgp_encrypted_material_t &material) +{ + pgp_packet_body_t pktbody(PGP_PKT_PK_SESSION_KEY); + + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + pktbody.add(material.rsa.m); + break; + case PGP_PKA_SM2: + pktbody.add(material.sm2.m); + break; + case PGP_PKA_ECDH: + pktbody.add(material.ecdh.p); + pktbody.add_byte(material.ecdh.mlen); + pktbody.add(material.ecdh.m, material.ecdh.mlen); + break; + case PGP_PKA_ELGAMAL: + pktbody.add(material.eg.g); + pktbody.add(material.eg.m); + break; + default: + RNP_LOG("Unknown pk alg: %d", (int) alg); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + material_buf = {pktbody.data(), pktbody.data() + pktbody.size()}; +} + +void +pgp_one_pass_sig_t::write(pgp_dest_t &dst) const +{ + pgp_packet_body_t pktbody(PGP_PKT_ONE_PASS_SIG); + pktbody.add_byte(version); + pktbody.add_byte(type); + pktbody.add_byte(halg); + pktbody.add_byte(palg); + pktbody.add(keyid); + pktbody.add_byte(nested); + pktbody.write(dst); +} + +rnp_result_t +pgp_one_pass_sig_t::parse(pgp_source_t &src) +{ + pgp_packet_body_t pkt(PGP_PKT_ONE_PASS_SIG); + /* Read the packet into memory */ + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + + uint8_t buf[13] = {0}; + if ((pkt.size() != 13) || !pkt.get(buf, 13)) { + return RNP_ERROR_BAD_FORMAT; + } + /* version */ + if (buf[0] != 3) { + RNP_LOG("wrong packet version"); + return RNP_ERROR_BAD_FORMAT; + } + version = buf[0]; + /* signature type */ + type = (pgp_sig_type_t) buf[1]; + /* hash algorithm */ + halg = (pgp_hash_alg_t) buf[2]; + /* pk algorithm */ + palg = (pgp_pubkey_alg_t) buf[3]; + /* key id */ + static_assert(std::tuple_size::value == PGP_KEY_ID_SIZE, + "pgp_one_pass_sig_t.keyid size mismatch"); + memcpy(keyid.data(), &buf[4], PGP_KEY_ID_SIZE); + /* nested flag */ + nested = buf[12]; + return RNP_SUCCESS; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-packet.h b/comm/third_party/rnp/src/librepgp/stream-packet.h new file mode 100644 index 0000000000..f88c96f22d --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-packet.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_PACKET_H_ +#define STREAM_PACKET_H_ + +#include +#include +#include +#include "types.h" +#include "stream-common.h" + +/* maximum size of the 'small' packet */ +#define PGP_MAX_PKT_SIZE 0x100000 + +/* maximum size of indeterminate-size packet allowed with old length format */ +#define PGP_MAX_OLD_LEN_INDETERMINATE_PKT_SIZE 0x40000000 + +typedef struct pgp_packet_hdr_t { + pgp_pkt_type_t tag; /* packet tag */ + uint8_t hdr[PGP_MAX_HEADER_SIZE]; /* PGP packet header, needed for AEAD */ + size_t hdr_len; /* length of the header */ + size_t pkt_len; /* packet body length if non-partial and non-indeterminate */ + bool partial; /* partial length packet */ + bool indeterminate; /* indeterminate length packet */ +} pgp_packet_hdr_t; + +/* structure for convenient writing or parsing of non-stream packets */ +typedef struct pgp_packet_body_t { + private: + pgp_pkt_type_t tag_; /* packet tag */ + std::vector data_; /* packet bytes */ + /* fields below are filled only for parsed packet */ + uint8_t hdr_[PGP_MAX_HEADER_SIZE]{}; /* packet header bytes */ + size_t hdr_len_{}; /* number of bytes in hdr */ + size_t pos_{}; /* current read position in packet data */ + bool secure_{}; /* contents of the packet are secure so must be wiped in the destructor */ + public: + /** @brief initialize writing of packet body + * @param tag tag of the packet + **/ + pgp_packet_body_t(pgp_pkt_type_t tag); + /** @brief init packet body (without headers) with memory. Used for easier data parsing. + * @param data buffer with packet body part + * @param len number of available bytes in mem + */ + pgp_packet_body_t(const uint8_t *data, size_t len); + + pgp_packet_body_t(const pgp_packet_body_t &src) = delete; + pgp_packet_body_t(pgp_packet_body_t &&src) = delete; + pgp_packet_body_t &operator=(const pgp_packet_body_t &) = delete; + pgp_packet_body_t &operator=(pgp_packet_body_t &&) = delete; + ~pgp_packet_body_t(); + + /** @brief pointer to the data, kept in the packet */ + uint8_t *data() noexcept; + /** @brief number of bytes, kept in the packet (without the header) */ + size_t size() const noexcept; + /** @brief number of bytes left to read */ + size_t left() const noexcept; + /** @brief get next byte from the packet body, populated with read() call. + * @param val result will be stored here on success + * @return true on success or false otherwise (if end of the packet is reached) + **/ + bool get(uint8_t &val) noexcept; + /** @brief get next big-endian uint16 from the packet body, populated with read() call. + * @param val result will be stored here on success + * @return true on success or false otherwise (if end of the packet is reached) + **/ + bool get(uint16_t &val) noexcept; + /** @brief get next big-endian uint32 from the packet body, populated with read() call. + * @param val result will be stored here on success + * @return true on success or false otherwise (if end of the packet is reached) + **/ + bool get(uint32_t &val) noexcept; + /** @brief get some bytes from the packet body, populated with read() call. + * @param val packet body bytes will be stored here. Must be capable of storing len bytes. + * @param len number of bytes to read + * @return true on success or false otherwise (if end of the packet is reached) + **/ + bool get(uint8_t *val, size_t len) noexcept; + /** @brief get next keyid from the packet body, populated with read() call. + * @param val result will be stored here on success + * @return true on success or false otherwise (if end of the packet is reached) + **/ + bool get(pgp_key_id_t &val) noexcept; + /** @brief get next mpi from the packet body, populated with read() call. + * @param val result will be stored here on success + * @return true on success or false otherwise (if end of the packet is reached + * or mpi is ill-formed) + **/ + bool get(pgp_mpi_t &val) noexcept; + /** @brief Read ECC key curve and convert it to pgp_curve_t */ + bool get(pgp_curve_t &val) noexcept; + /** @brief read s2k from the packet */ + bool get(pgp_s2k_t &s2k) noexcept; + /** @brief append some bytes to the packet body */ + void add(const void *data, size_t len); + /** @brief append single byte to the packet body */ + void add_byte(uint8_t bt); + /** @brief append big endian 16-bit value to the packet body */ + void add_uint16(uint16_t val); + /** @brief append big endian 32-bit value to the packet body */ + void add_uint32(uint32_t val); + /** @brief append keyid to the packet body */ + void add(const pgp_key_id_t &val); + /** @brief add pgp mpi (including header) to the packet body */ + void add(const pgp_mpi_t &val); + /** + * @brief add pgp signature subpackets (including their length) to the packet body + * @param sig signature, containing subpackets + * @param hashed whether write hashed or not hashed subpackets + */ + void add_subpackets(const pgp_signature_t &sig, bool hashed); + /** @brief add ec curve description to the packet body */ + void add(const pgp_curve_t curve); + /** @brief add s2k description to the packet body */ + void add(const pgp_s2k_t &s2k); + /** @brief read 'short-length' packet body (including tag and length bytes) from the source + * @param src source to read from + * @return RNP_SUCCESS or error code if operation failed + **/ + rnp_result_t read(pgp_source_t &src) noexcept; + /** @brief write packet header, length and body to the dst + * @param dst destination to write to. + * @param hdr write packet's header or not + **/ + void write(pgp_dest_t &dst, bool hdr = true) noexcept; + /** @brief mark contents as secure, so secure_clear() must be called in the destructor */ + void mark_secure(bool secure = true) noexcept; +} pgp_packet_body_t; + +/** public-key encrypted session key packet */ +typedef struct pgp_pk_sesskey_t { + unsigned version{}; + pgp_key_id_t key_id{}; + pgp_pubkey_alg_t alg{}; + std::vector material_buf{}; + + void write(pgp_dest_t &dst) const; + rnp_result_t parse(pgp_source_t &src); + /** + * @brief Parse encrypted material which is stored in packet in raw. + * @param material on success parsed material will be stored here. + * @return true on success or false otherwise. May also throw an exception. + */ + bool parse_material(pgp_encrypted_material_t &material) const; + /** + * @brief Write encrypted material to the material_buf. + * @param material populated encrypted material. + */ + void write_material(const pgp_encrypted_material_t &material); +} pgp_pk_sesskey_t; + +/** pkp_sk_sesskey_t */ +typedef struct pgp_sk_sesskey_t { + unsigned version{}; + pgp_symm_alg_t alg{}; + pgp_s2k_t s2k{}; + uint8_t enckey[PGP_MAX_KEY_SIZE + PGP_AEAD_MAX_TAG_LEN + 1]{}; + unsigned enckeylen{}; + /* v5 specific fields */ + pgp_aead_alg_t aalg{}; + uint8_t iv[PGP_MAX_BLOCK_SIZE]{}; + unsigned ivlen{}; + + void write(pgp_dest_t &dst) const; + rnp_result_t parse(pgp_source_t &src); +} pgp_sk_sesskey_t; + +/** pgp_one_pass_sig_t */ +typedef struct pgp_one_pass_sig_t { + uint8_t version{}; + pgp_sig_type_t type{}; + pgp_hash_alg_t halg{}; + pgp_pubkey_alg_t palg{}; + pgp_key_id_t keyid{}; + unsigned nested{}; + + void write(pgp_dest_t &dst) const; + rnp_result_t parse(pgp_source_t &src); +} pgp_one_pass_sig_t; + +/** Struct to hold userid or userattr packet. We don't parse userattr now, just storing the + * binary blob as it is. It may be distinguished by tag field. + */ +typedef struct pgp_userid_pkt_t { + pgp_pkt_type_t tag; + uint8_t * uid; + size_t uid_len; + + pgp_userid_pkt_t() : tag(PGP_PKT_RESERVED), uid(NULL), uid_len(0){}; + pgp_userid_pkt_t(const pgp_userid_pkt_t &src); + pgp_userid_pkt_t(pgp_userid_pkt_t &&src); + pgp_userid_pkt_t &operator=(pgp_userid_pkt_t &&src); + pgp_userid_pkt_t &operator=(const pgp_userid_pkt_t &src); + bool operator==(const pgp_userid_pkt_t &src) const; + bool operator!=(const pgp_userid_pkt_t &src) const; + ~pgp_userid_pkt_t(); + + void write(pgp_dest_t &dst) const; + rnp_result_t parse(pgp_source_t &src); +} pgp_userid_pkt_t; + +uint16_t read_uint16(const uint8_t *buf); + +uint32_t read_uint32(const uint8_t *buf); + +void write_uint16(uint8_t *buf, uint16_t val); + +/** @brief write new packet length + * @param buf pre-allocated buffer, must have 5 bytes + * @param len packet length + * @return number of bytes, saved in buf + **/ +size_t write_packet_len(uint8_t *buf, size_t len); + +/** @brief get packet type from the packet header byte + * @param ptag first byte of the packet header + * @return packet type or -1 if ptag is wrong + **/ +int get_packet_type(uint8_t ptag); + +/** @brief peek the packet type from the stream + * @param src source to peek from + * @return packet tag or -1 if read failed or packet header is malformed + */ +int stream_pkt_type(pgp_source_t &src); + +/** @brief Peek length of the packet header. Returns false on error. + * @param src source to read length from + * @param hdrlen header length will be put here on success. Cannot be NULL. + * @return true on success or false if there is a read error or packet length + * is ill-formed + **/ +bool stream_pkt_hdr_len(pgp_source_t &src, size_t &hdrlen); + +bool stream_old_indeterminate_pkt_len(pgp_source_t *src); + +bool stream_partial_pkt_len(pgp_source_t *src); + +size_t get_partial_pkt_len(uint8_t blen); + +/** @brief Read packet length for fixed-size (say, small) packet. Returns false on error. + * Will also read packet tag byte. We do not allow partial length here as well as large + * packets (so ignoring possible size_t overflow) + * + * @param src source to read length from + * @param pktlen packet length will be stored here on success. Cannot be NULL. + * @return true on success or false if there is read error or packet length is ill-formed + **/ +bool stream_read_pkt_len(pgp_source_t *src, size_t *pktlen); + +/** @brief Read partial packet chunk length. + * + * @param src source to read length from + * @param clen chunk length will be stored here on success. Cannot be NULL. + * @param last will be set to true if chunk is last (i.e. has non-partial length) + * @return true on success or false if there is read error or packet length is ill-formed + **/ +bool stream_read_partial_chunk_len(pgp_source_t *src, size_t *clen, bool *last); + +/** @brief get and parse OpenPGP packet header to the structure. + * Note: this will not read but just peek required bytes. + * + * @param src source to read from + * @param hdr header structure + * @return RNP_SUCCESS or error code if operation failed + **/ +rnp_result_t stream_peek_packet_hdr(pgp_source_t *src, pgp_packet_hdr_t *hdr); + +/* Packet handling functions */ + +/** @brief read OpenPGP packet from the stream, and write its contents to another stream. + * @param src source with packet data + * @param dst destination to write packet contents. All write failures on dst + * will be ignored. Can be NULL if you need just to skip packet. + * @return RNP_SUCCESS or error code if operation failed. + */ +rnp_result_t stream_read_packet(pgp_source_t *src, pgp_dest_t *dst); + +rnp_result_t stream_skip_packet(pgp_source_t *src); + +rnp_result_t stream_parse_marker(pgp_source_t &src); + +/* Public/Private key or Subkey */ + +bool is_key_pkt(int tag); + +bool is_subkey_pkt(int tag); + +bool is_primary_key_pkt(int tag); + +bool is_public_key_pkt(int tag); + +bool is_secret_key_pkt(int tag); + +bool is_rsa_key_alg(pgp_pubkey_alg_t alg); + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-parse.cpp b/comm/third_party/rnp/src/librepgp/stream-parse.cpp new file mode 100644 index 0000000000..5ec4d64be9 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-parse.cpp @@ -0,0 +1,2636 @@ +/* + * Copyright (c) 2017-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stream-ctx.h" +#include "stream-def.h" +#include "stream-parse.h" +#include "stream-armor.h" +#include "stream-packet.h" +#include "stream-sig.h" +#include "str-utils.h" +#include "types.h" +#include "crypto/s2k.h" +#include "crypto.h" +#include "crypto/signatures.h" +#include "fingerprint.h" +#include "pgp-key.h" + +#ifdef HAVE_ZLIB_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif + +typedef enum pgp_message_t { + PGP_MESSAGE_UNKNOWN = 0, + PGP_MESSAGE_NORMAL, + PGP_MESSAGE_DETACHED, + PGP_MESSAGE_CLEARTEXT +} pgp_message_t; + +typedef struct pgp_processing_ctx_t { + pgp_parse_handler_t handler; + pgp_source_t * signed_src; + pgp_source_t * literal_src; + pgp_message_t msg_type; + pgp_dest_t output; + std::list sources; + + ~pgp_processing_ctx_t(); +} pgp_processing_ctx_t; + +/* common fields for encrypted, compressed and literal data */ +typedef struct pgp_source_packet_param_t { + pgp_source_t * readsrc; /* source to read from, could be partial*/ + pgp_source_t * origsrc; /* original source passed to init_*_src */ + pgp_packet_hdr_t hdr; /* packet header info */ +} pgp_source_packet_param_t; + +typedef struct pgp_source_encrypted_param_t { + pgp_source_packet_param_t pkt{}; /* underlying packet-related params */ + std::vector symencs; /* array of sym-encrypted session keys */ + std::vector pubencs; /* array of pk-encrypted session keys */ + rnp::AuthType auth_type; /* Authentication type */ + bool auth_validated{}; /* Auth tag (MDC or AEAD) was already validated */ + pgp_crypt_t decrypt{}; /* decrypting crypto */ + std::unique_ptr mdc; /* mdc SHA1 hash */ + size_t chunklen{}; /* size of AEAD chunk in bytes */ + size_t chunkin{}; /* number of bytes read from the current chunk */ + size_t chunkidx{}; /* index of the current chunk */ + uint8_t cache[PGP_AEAD_CACHE_LEN]; /* read cache */ + size_t cachelen{}; /* number of bytes in the cache */ + size_t cachepos{}; /* index of first unread byte in the cache */ + pgp_aead_hdr_t aead_hdr; /* AEAD encryption parameters */ + uint8_t aead_ad[PGP_AEAD_MAX_AD_LEN]; /* additional data */ + size_t aead_adlen{}; /* length of the additional data */ + pgp_symm_alg_t salg; /* data encryption algorithm */ + pgp_parse_handler_t * handler{}; /* parsing handler with callbacks */ + + pgp_source_encrypted_param_t() : auth_type(rnp::AuthType::None), salg(PGP_SA_UNKNOWN) + { + } + + bool + use_cfb() + { + return auth_type != rnp::AuthType::AEADv1; + } +} pgp_source_encrypted_param_t; + +typedef struct pgp_source_signed_param_t { + pgp_parse_handler_t *handler; /* parsing handler with callbacks */ + pgp_source_t * readsrc; /* source to read from */ + bool detached; /* detached signature */ + bool cleartext; /* source is cleartext signed */ + bool clr_eod; /* cleartext data is over */ + bool clr_fline; /* first line of the cleartext */ + bool clr_mline; /* in the middle of the very long line */ + uint8_t out[CT_BUF_LEN]; /* cleartext output cache for easier parsing */ + size_t outlen; /* total bytes in out */ + size_t outpos; /* offset of first available byte in out */ + bool max_line_warn; /* warning about too long line is already issued */ + size_t text_line_len; /* length of a current line in a text document */ + long stripped_crs; /* number of trailing CR characters stripped from the end of the last + processed chunk */ + + std::vector onepasses; /* list of one-pass singatures */ + std::list sigs; /* list of signatures */ + std::vector siginfos; /* signature validation info */ + rnp::HashList hashes; /* hash contexts */ + rnp::HashList txt_hashes; /* hash contexts for text-mode sigs */ + + pgp_source_signed_param_t() = default; + ~pgp_source_signed_param_t() = default; +} pgp_source_signed_param_t; + +typedef struct pgp_source_compressed_param_t { + pgp_source_packet_param_t pkt; /* underlying packet-related params */ + pgp_compression_type_t alg; + union { + z_stream z; + bz_stream bz; + }; + uint8_t in[PGP_INPUT_CACHE_SIZE / 2]; + size_t inpos; + size_t inlen; + bool zend; +} pgp_source_compressed_param_t; + +typedef struct pgp_source_literal_param_t { + pgp_source_packet_param_t pkt; /* underlying packet-related params */ + pgp_literal_hdr_t hdr; /* literal packet fields */ +} pgp_source_literal_param_t; + +typedef struct pgp_source_partial_param_t { + pgp_source_t *readsrc; /* source to read from */ + int type; /* type of the packet */ + size_t psize; /* size of the current part */ + size_t pleft; /* bytes left to read from the current part */ + bool last; /* current part is last */ +} pgp_source_partial_param_t; + +static bool +is_pgp_source(pgp_source_t &src) +{ + uint8_t buf; + if (!src_peek_eq(&src, &buf, 1)) { + return false; + } + + switch (get_packet_type(buf)) { + case PGP_PKT_PK_SESSION_KEY: + case PGP_PKT_SK_SESSION_KEY: + case PGP_PKT_ONE_PASS_SIG: + case PGP_PKT_SIGNATURE: + case PGP_PKT_SE_DATA: + case PGP_PKT_SE_IP_DATA: + case PGP_PKT_COMPRESSED: + case PGP_PKT_LITDATA: + case PGP_PKT_MARKER: + return true; + default: + return false; + } +} + +static bool +partial_pkt_src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + if (src->eof) { + *readres = 0; + return true; + } + + pgp_source_partial_param_t *param = (pgp_source_partial_param_t *) src->param; + if (!param) { + return false; + } + + size_t read; + size_t write = 0; + while (len > 0) { + if (!param->pleft && param->last) { + // we have the last chunk + *readres = write; + return true; + } + if (!param->pleft) { + // reading next chunk + if (!stream_read_partial_chunk_len(param->readsrc, &read, ¶m->last)) { + return false; + } + param->psize = read; + param->pleft = read; + } + + if (!param->pleft) { + *readres = write; + return true; + } + + read = param->pleft > len ? len : param->pleft; + if (!src_read(param->readsrc, buf, read, &read)) { + RNP_LOG("failed to read data chunk"); + return false; + } + if (!read) { + RNP_LOG("unexpected eof"); + *readres = write; + return true; + } + write += read; + len -= read; + buf = (uint8_t *) buf + read; + param->pleft -= read; + } + + *readres = write; + return true; +} + +static void +partial_pkt_src_close(pgp_source_t *src) +{ + pgp_source_partial_param_t *param = (pgp_source_partial_param_t *) src->param; + if (param) { + free(src->param); + src->param = NULL; + } +} + +static rnp_result_t +init_partial_pkt_src(pgp_source_t *src, pgp_source_t *readsrc, pgp_packet_hdr_t &hdr) +{ + pgp_source_partial_param_t *param; + if (!init_src_common(src, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + assert(hdr.partial); + /* we are sure that header is indeterminate */ + param = (pgp_source_partial_param_t *) src->param; + param->type = hdr.tag; + param->psize = get_partial_pkt_len(hdr.hdr[1]); + param->pleft = param->psize; + param->last = false; + param->readsrc = readsrc; + + src->read = partial_pkt_src_read; + src->close = partial_pkt_src_close; + src->type = PGP_STREAM_PARLEN_PACKET; + + if (param->psize < PGP_PARTIAL_PKT_FIRST_PART_MIN_SIZE) { + RNP_LOG("first part of partial length packet sequence has size %d and that's less " + "than allowed by the protocol", + (int) param->psize); + } + + return RNP_SUCCESS; +} + +static bool +literal_src_read(pgp_source_t *src, void *buf, size_t len, size_t *read) +{ + pgp_source_literal_param_t *param = (pgp_source_literal_param_t *) src->param; + if (!param) { + return false; + } + return src_read(param->pkt.readsrc, buf, len, read); +} + +static void +literal_src_close(pgp_source_t *src) +{ + pgp_source_literal_param_t *param = (pgp_source_literal_param_t *) src->param; + if (param) { + if (param->pkt.hdr.partial) { + src_close(param->pkt.readsrc); + free(param->pkt.readsrc); + param->pkt.readsrc = NULL; + } + + free(src->param); + src->param = NULL; + } +} + +static bool +compressed_src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + pgp_source_compressed_param_t *param = (pgp_source_compressed_param_t *) src->param; + if (!param) { + return false; + } + + if (src->eof || param->zend) { + *readres = 0; + return true; + } + + if (param->alg == PGP_C_NONE) { + if (!src_read(param->pkt.readsrc, buf, len, readres)) { + RNP_LOG("failed to read uncompressed data"); + return false; + } + return true; + } + if ((param->alg == PGP_C_ZIP) || (param->alg == PGP_C_ZLIB)) { + param->z.next_out = (Bytef *) buf; + param->z.avail_out = len; + param->z.next_in = param->in + param->inpos; + param->z.avail_in = param->inlen - param->inpos; + + while ((param->z.avail_out > 0) && (!param->zend)) { + if (param->z.avail_in == 0) { + size_t read = 0; + if (!src_read(param->pkt.readsrc, param->in, sizeof(param->in), &read)) { + RNP_LOG("failed to read data"); + return false; + } + param->z.next_in = param->in; + param->z.avail_in = read; + param->inlen = read; + param->inpos = 0; + } + int ret = inflate(¶m->z, Z_SYNC_FLUSH); + if (ret == Z_STREAM_END) { + param->zend = true; + if (param->z.avail_in > 0) { + RNP_LOG("data beyond the end of z stream"); + } + break; + } + if (ret != Z_OK) { + RNP_LOG("inflate error %d", ret); + return false; + } + if (!param->z.avail_in && src_eof(param->pkt.readsrc)) { + RNP_LOG("unexpected end of zlib stream"); + return false; + } + } + param->inpos = param->z.next_in - param->in; + *readres = len - param->z.avail_out; + return true; + } +#ifdef HAVE_BZLIB_H + if (param->alg == PGP_C_BZIP2) { + param->bz.next_out = (char *) buf; + param->bz.avail_out = len; + param->bz.next_in = (char *) (param->in + param->inpos); + param->bz.avail_in = param->inlen - param->inpos; + + while ((param->bz.avail_out > 0) && (!param->zend)) { + if (param->bz.avail_in == 0) { + size_t read = 0; + if (!src_read(param->pkt.readsrc, param->in, sizeof(param->in), &read)) { + RNP_LOG("failed to read data"); + return false; + } + param->bz.next_in = (char *) param->in; + param->bz.avail_in = read; + param->inlen = read; + param->inpos = 0; + } + int ret = BZ2_bzDecompress(¶m->bz); + if (ret == BZ_STREAM_END) { + param->zend = true; + if (param->bz.avail_in > 0) { + RNP_LOG("data beyond the end of z stream"); + } + break; + } + if (ret != BZ_OK) { + RNP_LOG("bzdecompress error %d", ret); + return false; + } + if (!param->bz.avail_in && src_eof(param->pkt.readsrc)) { + RNP_LOG("unexpected end of bzip stream"); + return false; + } + } + + param->inpos = (uint8_t *) param->bz.next_in - param->in; + *readres = len - param->bz.avail_out; + return true; + } +#endif + return false; +} + +static void +compressed_src_close(pgp_source_t *src) +{ + pgp_source_compressed_param_t *param = (pgp_source_compressed_param_t *) src->param; + if (!param) { + return; + } + + if (param->pkt.hdr.partial) { + src_close(param->pkt.readsrc); + free(param->pkt.readsrc); + param->pkt.readsrc = NULL; + } + +#ifdef HAVE_BZLIB_H + if (param->alg == PGP_C_BZIP2) { + BZ2_bzDecompressEnd(¶m->bz); + } +#endif + if ((param->alg == PGP_C_ZIP) || (param->alg == PGP_C_ZLIB)) { + inflateEnd(¶m->z); + } + + free(src->param); + src->param = NULL; +} + +#if defined(ENABLE_AEAD) +static bool +encrypted_start_aead_chunk(pgp_source_encrypted_param_t *param, size_t idx, bool last) +{ + uint8_t nonce[PGP_AEAD_MAX_NONCE_LEN]; + size_t nlen; + + /* set chunk index for additional data */ + STORE64BE(param->aead_ad + param->aead_adlen - 8, idx); + + if (last) { + uint64_t total = idx * param->chunklen; + if (idx && param->chunkin) { + total -= param->chunklen - param->chunkin; + } + + if (!param->chunkin) { + /* reset the crypto in case we had empty chunk before the last one */ + pgp_cipher_aead_reset(¶m->decrypt); + } + STORE64BE(param->aead_ad + param->aead_adlen, total); + param->aead_adlen += 8; + } + + if (!pgp_cipher_aead_set_ad(¶m->decrypt, param->aead_ad, param->aead_adlen)) { + RNP_LOG("failed to set ad"); + return false; + } + + /* setup chunk */ + param->chunkidx = idx; + param->chunkin = 0; + + /* set chunk index for nonce */ + nlen = pgp_cipher_aead_nonce(param->aead_hdr.aalg, param->aead_hdr.iv, nonce, idx); + + /* start cipher */ + return pgp_cipher_aead_start(¶m->decrypt, nonce, nlen); +} + +/* read and decrypt bytes to the cache. Should be called only on empty cache. */ +static bool +encrypted_src_read_aead_part(pgp_source_encrypted_param_t *param) +{ + bool lastchunk = false; + bool chunkend = false; + bool res = false; + size_t read; + size_t tagread; + size_t taglen; + + param->cachepos = 0; + param->cachelen = 0; + + if (param->auth_validated) { + return true; + } + + /* it is always 16 for defined EAX and OCB, however this may change in future */ + taglen = pgp_cipher_aead_tag_len(param->aead_hdr.aalg); + read = sizeof(param->cache) - 2 * PGP_AEAD_MAX_TAG_LEN; + + if (read >= param->chunklen - param->chunkin) { + read = param->chunklen - param->chunkin; + chunkend = true; + } else { + read = read - read % pgp_cipher_aead_granularity(¶m->decrypt); + } + + if (!src_read(param->pkt.readsrc, param->cache, read, &read)) { + return false; + } + + /* checking whether we have enough input for the final tags */ + if (!src_peek(param->pkt.readsrc, param->cache + read, taglen * 2, &tagread)) { + return false; + } + + if (tagread < taglen * 2) { + /* this would mean the end of the stream */ + if ((param->chunkin == 0) && (read + tagread == taglen)) { + /* we have empty chunk and final tag */ + chunkend = false; + lastchunk = true; + } else if (read + tagread >= 2 * taglen) { + /* we have end of chunk and final tag */ + chunkend = true; + lastchunk = true; + } else { + RNP_LOG("unexpected end of data"); + return false; + } + } + + if (!chunkend && !lastchunk) { + param->chunkin += read; + res = pgp_cipher_aead_update(¶m->decrypt, param->cache, param->cache, read); + if (res) { + param->cachelen = read; + } + return res; + } + + if (chunkend) { + if (tagread > taglen) { + src_skip(param->pkt.readsrc, tagread - taglen); + } + + res = pgp_cipher_aead_finish( + ¶m->decrypt, param->cache, param->cache, read + tagread - taglen); + if (!res) { + RNP_LOG("failed to finalize aead chunk"); + return res; + } + param->cachelen = read + tagread - 2 * taglen; + param->chunkin += param->cachelen; + } + + size_t chunkidx = param->chunkidx; + if (chunkend && param->chunkin) { + chunkidx++; + } + + if (!(res = encrypted_start_aead_chunk(param, chunkidx, lastchunk))) { + RNP_LOG("failed to start aead chunk"); + return res; + } + + if (lastchunk) { + if (tagread > 0) { + src_skip(param->pkt.readsrc, tagread); + } + + size_t off = read + tagread - taglen; + res = pgp_cipher_aead_finish( + ¶m->decrypt, param->cache + off, param->cache + off, taglen); + if (!res) { + RNP_LOG("wrong last chunk"); + return res; + } + param->auth_validated = true; + } + + return res; +} +#endif + +static bool +encrypted_src_read_aead(pgp_source_t *src, void *buf, size_t len, size_t *read) +{ +#if !defined(ENABLE_AEAD) + return false; +#else + pgp_source_encrypted_param_t *param = (pgp_source_encrypted_param_t *) src->param; + size_t cbytes; + size_t left = len; + + do { + /* check whether we have something in the cache */ + cbytes = param->cachelen - param->cachepos; + if (cbytes > 0) { + if (cbytes >= left) { + memcpy(buf, param->cache + param->cachepos, left); + param->cachepos += left; + if (param->cachepos == param->cachelen) { + param->cachepos = param->cachelen = 0; + } + *read = len; + return true; + } + memcpy(buf, param->cache + param->cachepos, cbytes); + buf = (uint8_t *) buf + cbytes; + left -= cbytes; + param->cachepos = param->cachelen = 0; + } + + /* read something into cache */ + if (!encrypted_src_read_aead_part(param)) { + return false; + } + } while ((left > 0) && (param->cachelen > 0)); + + *read = len - left; + return true; +#endif +} + +static bool +encrypted_src_read_cfb(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + pgp_source_encrypted_param_t *param = (pgp_source_encrypted_param_t *) src->param; + if (param == NULL) { + return false; + } + + if (src->eof) { + *readres = 0; + return true; + } + + size_t read; + if (!src_read(param->pkt.readsrc, buf, len, &read)) { + return false; + } + if (!read) { + *readres = 0; + return true; + } + + bool parsemdc = false; + uint8_t mdcbuf[MDC_V1_SIZE]; + if (param->auth_type == rnp::AuthType::MDC) { + size_t mdcread = 0; + /* make sure there are always 22 bytes left on input */ + if (!src_peek(param->pkt.readsrc, mdcbuf, MDC_V1_SIZE, &mdcread) || + (mdcread + read < MDC_V1_SIZE)) { + RNP_LOG("wrong mdc read state"); + return false; + } + if (mdcread < MDC_V1_SIZE) { + src_skip(param->pkt.readsrc, mdcread); + size_t mdcsub = MDC_V1_SIZE - mdcread; + memmove(&mdcbuf[mdcsub], mdcbuf, mdcread); + memcpy(mdcbuf, (uint8_t *) buf + read - mdcsub, mdcsub); + read -= mdcsub; + parsemdc = true; + } + } + + pgp_cipher_cfb_decrypt(¶m->decrypt, (uint8_t *) buf, (uint8_t *) buf, read); + + if (param->auth_type == rnp::AuthType::MDC) { + try { + param->mdc->add(buf, read); + + if (parsemdc) { + pgp_cipher_cfb_decrypt(¶m->decrypt, mdcbuf, mdcbuf, MDC_V1_SIZE); + pgp_cipher_cfb_finish(¶m->decrypt); + param->mdc->add(mdcbuf, 2); + uint8_t hash[PGP_SHA1_HASH_SIZE] = {0}; + param->mdc->finish(hash); + param->mdc = nullptr; + + if ((mdcbuf[0] != MDC_PKT_TAG) || (mdcbuf[1] != MDC_V1_SIZE - 2)) { + RNP_LOG("mdc header check failed"); + return false; + } + + if (memcmp(&mdcbuf[2], hash, PGP_SHA1_HASH_SIZE) != 0) { + RNP_LOG("mdc hash check failed"); + return false; + } + param->auth_validated = true; + } + } catch (const std::exception &e) { + RNP_LOG("mdc update failed: %s", e.what()); + return false; + } + } + *readres = read; + return true; +} + +static rnp_result_t +encrypted_src_finish(pgp_source_t *src) +{ + pgp_source_encrypted_param_t *param = (pgp_source_encrypted_param_t *) src->param; + + /* report to the handler that decryption is finished */ + if (param->handler->on_decryption_done) { + bool validated = (param->auth_type != rnp::AuthType::None) && param->auth_validated; + param->handler->on_decryption_done(validated, param->handler->param); + } + + if ((param->auth_type == rnp::AuthType::None) || param->auth_validated) { + return RNP_SUCCESS; + } + switch (param->auth_type) { + case rnp::AuthType::MDC: + RNP_LOG("mdc was not validated"); + break; + case rnp::AuthType::AEADv1: + RNP_LOG("aead last chunk was not validated"); + break; + default: + RNP_LOG("auth was not validated"); + break; + } + return RNP_ERROR_BAD_STATE; +} + +static void +encrypted_src_close(pgp_source_t *src) +{ + pgp_source_encrypted_param_t *param = (pgp_source_encrypted_param_t *) src->param; + if (!param) { + return; + } + if (param->pkt.hdr.partial) { + src_close(param->pkt.readsrc); + free(param->pkt.readsrc); + param->pkt.readsrc = NULL; + } + + if (!param->use_cfb()) { +#if defined(ENABLE_AEAD) + pgp_cipher_aead_destroy(¶m->decrypt); +#endif + } else { + pgp_cipher_cfb_finish(¶m->decrypt); + } + + delete param; + src->param = NULL; +} + +static void +add_hash_for_sig(pgp_source_signed_param_t *param, pgp_sig_type_t stype, pgp_hash_alg_t halg) +{ + /* Cleartext always uses param->hashes instead of param->txt_hashes */ + if (!param->cleartext && (stype == PGP_SIG_TEXT)) { + param->txt_hashes.add_alg(halg); + } + param->hashes.add_alg(halg); +} + +static const rnp::Hash * +get_hash_for_sig(pgp_source_signed_param_t ¶m, pgp_signature_info_t &sinfo) +{ + /* Cleartext always uses param->hashes instead of param->txt_hashes */ + if (!param.cleartext && (sinfo.sig->type() == PGP_SIG_TEXT)) { + return param.txt_hashes.get(sinfo.sig->halg); + } + return param.hashes.get(sinfo.sig->halg); +} + +static void +signed_validate_signature(pgp_source_signed_param_t ¶m, pgp_signature_info_t &sinfo) +{ + /* Check signature type */ + if (!sinfo.sig->is_document()) { + RNP_LOG("Invalid document signature type: %d", (int) sinfo.sig->type()); + sinfo.valid = false; + return; + } + /* Find signing key */ + pgp_key_request_ctx_t keyctx(PGP_OP_VERIFY, false, PGP_KEY_SEARCH_FINGERPRINT); + + /* Get signer's fp or keyid */ + if (sinfo.sig->has_keyfp()) { + keyctx.search.by.fingerprint = sinfo.sig->keyfp(); + } else if (sinfo.sig->has_keyid()) { + keyctx.search.type = PGP_KEY_SEARCH_KEYID; + keyctx.search.by.keyid = sinfo.sig->keyid(); + } else { + RNP_LOG("cannot get signer's key fp or id from signature."); + sinfo.unknown = true; + return; + } + /* Get the public key */ + pgp_key_t *key = pgp_request_key(param.handler->key_provider, &keyctx); + if (!key) { + /* fallback to secret key */ + keyctx.secret = true; + if (!(key = pgp_request_key(param.handler->key_provider, &keyctx))) { + RNP_LOG("signer's key not found"); + sinfo.no_signer = true; + return; + } + } + try { + /* Get the hash context and clone it. */ + auto hash = get_hash_for_sig(param, sinfo); + if (!hash) { + RNP_LOG("failed to get hash context."); + return; + } + auto shash = hash->clone(); + key->validate_sig(sinfo, *shash, *param.handler->ctx->ctx); + } catch (const std::exception &e) { + RNP_LOG("Signature validation failed: %s", e.what()); + sinfo.valid = false; + } +} + +static long +stripped_line_len(uint8_t *begin, uint8_t *end) +{ + uint8_t *stripped_end = end; + + while (stripped_end >= begin && (*stripped_end == CH_CR || *stripped_end == CH_LF)) { + stripped_end--; + } + + return stripped_end - begin + 1; +} + +static void +signed_src_update(pgp_source_t *src, const void *buf, size_t len) +{ + if (!len) { + return; + } + /* check for extremely unlikely pointer overflow/wrap case */ + if (((uint8_t *) buf + len) < ((uint8_t *) buf + len - 1)) { + signed_src_update(src, buf, len - 1); + uint8_t last = *((uint8_t *) buf + len - 1); + signed_src_update(src, &last, 1); + } + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + try { + param->hashes.add(buf, len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } + /* update text-mode sig hashes */ + if (param->txt_hashes.hashes.empty()) { + return; + } + + uint8_t *ch = (uint8_t *) buf; + uint8_t *linebeg = ch; + uint8_t *end = (uint8_t *) buf + len; + /* we support LF and CRLF line endings */ + while (ch < end) { + /* continue if not reached LF */ + if (*ch != CH_LF) { + if (*ch != CH_CR && param->stripped_crs > 0) { + while (param->stripped_crs--) { + try { + param->txt_hashes.add(ST_CR, 1); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } + } + param->stripped_crs = 0; + } + + if (!param->max_line_warn && param->text_line_len >= MAXIMUM_GNUPG_LINELEN) { + RNP_LOG("Canonical text document signature: line is too long, may cause " + "incompatibility with other implementations. Consider using binary " + "signature instead."); + param->max_line_warn = true; + } + + ch++; + param->text_line_len++; + continue; + } + /* reached eol: dump line contents */ + param->stripped_crs = 0; + param->text_line_len = 0; + if (ch > linebeg) { + long stripped_len = stripped_line_len(linebeg, ch); + if (stripped_len > 0) { + try { + param->txt_hashes.add(linebeg, stripped_len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } + } + } + /* dump EOL */ + try { + param->txt_hashes.add(ST_CRLF, 2); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } + ch++; + linebeg = ch; + } + /* check if we have undumped line contents */ + if (linebeg < end) { + long stripped_len = stripped_line_len(linebeg, end - 1); + if (stripped_len < end - linebeg) { + param->stripped_crs = end - linebeg - stripped_len; + } + if (stripped_len > 0) { + try { + param->txt_hashes.add(linebeg, stripped_len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + } + } + } +} + +static bool +signed_src_read(pgp_source_t *src, void *buf, size_t len, size_t *read) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + if (!param) { + return false; + } + return src_read(param->readsrc, buf, len, read); +} + +static void +signed_src_close(pgp_source_t *src) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + if (!param) { + return; + } + delete param; + src->param = NULL; +} + +#define MAX_SIGNATURES 16384 + +static rnp_result_t +signed_read_single_signature(pgp_source_signed_param_t *param, + pgp_source_t * readsrc, + pgp_signature_t ** sig) +{ + uint8_t ptag; + if (!src_peek_eq(readsrc, &ptag, 1)) { + RNP_LOG("failed to read signature packet header"); + return RNP_ERROR_READ; + } + + int ptype = get_packet_type(ptag); + if (ptype != PGP_PKT_SIGNATURE) { + RNP_LOG("unexpected packet %d", ptype); + return RNP_ERROR_BAD_FORMAT; + } + + if (param->siginfos.size() >= MAX_SIGNATURES) { + RNP_LOG("Too many signatures in the stream."); + return RNP_ERROR_BAD_FORMAT; + } + + try { + param->siginfos.emplace_back(); + pgp_signature_info_t &siginfo = param->siginfos.back(); + pgp_signature_t readsig; + if (readsig.parse(*readsrc)) { + RNP_LOG("failed to parse signature"); + siginfo.unknown = true; + if (sig) { + *sig = NULL; + } + return RNP_SUCCESS; + } + param->sigs.push_back(std::move(readsig)); + siginfo.sig = ¶m->sigs.back(); + if (sig) { + *sig = siginfo.sig; + } + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } +} + +static rnp_result_t +signed_read_cleartext_signatures(pgp_source_t &src, pgp_source_signed_param_t *param) +{ + try { + rnp::ArmoredSource armor(*param->readsrc); + while (!armor.eof()) { + auto ret = signed_read_single_signature(param, &armor.src(), NULL); + if (ret) { + return ret; + } + } + return RNP_SUCCESS; + } catch (const rnp::rnp_exception &e) { + RNP_LOG("%s", e.what()); + return e.code(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_FORMAT; + } +} + +static rnp_result_t +signed_read_signatures(pgp_source_t *src) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + + /* reading signatures */ + for (auto op = param->onepasses.rbegin(); op != param->onepasses.rend(); op++) { + pgp_signature_t *sig = NULL; + rnp_result_t ret = signed_read_single_signature(param, src, &sig); + /* we have more onepasses then signatures */ + if (ret == RNP_ERROR_READ) { + RNP_LOG("Warning: premature end of signatures"); + return param->siginfos.size() ? RNP_SUCCESS : ret; + } + if (ret) { + return ret; + } + if (sig && !sig->matches_onepass(*op)) { + RNP_LOG("Warning: signature doesn't match one-pass"); + } + } + return RNP_SUCCESS; +} + +static rnp_result_t +signed_src_finish(pgp_source_t *src) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (param->cleartext) { + ret = signed_read_cleartext_signatures(*src, param); + } else { + ret = signed_read_signatures(src); + } + + if (ret) { + return ret; + } + + if (!src_eof(src)) { + RNP_LOG("warning: unexpected data on the stream end"); + } + + /* validating signatures */ + for (auto &sinfo : param->siginfos) { + if (!sinfo.sig) { + continue; + } + signed_validate_signature(*param, sinfo); + } + + /* checking the validation results */ + ret = RNP_ERROR_SIGNATURE_INVALID; + for (auto &sinfo : param->siginfos) { + if (sinfo.valid) { + /* If we have at least one valid signature then data is safe to process */ + ret = RNP_SUCCESS; + break; + } + } + + /* call the callback with signature infos */ + if (param->handler->on_signatures) { + param->handler->on_signatures(param->siginfos, param->handler->param); + } + return ret; +} + +/* + * str is a string to tokenize. + * delims is a string containing a list of delimiter characters. + * result is a container that supports push_back. + */ +template +static void +tokenize(const typename T::value_type &str, const typename T::value_type &delims, T &result) +{ + typedef typename T::value_type::size_type string_size_t; + const string_size_t npos = T::value_type::npos; + + result.clear(); + string_size_t current; + string_size_t next = 0; + do { + next = str.find_first_not_of(delims, next); + if (next == npos) { + break; + } + current = next; + next = str.find_first_of(delims, current); + string_size_t count = (next == npos) ? npos : (next - current); + result.push_back(str.substr(current, count)); + } while (next != npos); +} + +static bool +cleartext_parse_headers(pgp_source_t *src) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + char hdr[1024] = {0}; + char * hval; + pgp_hash_alg_t halg; + size_t hdrlen; + + do { + if (!src_peek_line(param->readsrc, hdr, sizeof(hdr), &hdrlen)) { + RNP_LOG("failed to peek line"); + return false; + } + + if (!hdrlen) { + break; + } + + if (rnp::is_blank_line(hdr, hdrlen)) { + src_skip(param->readsrc, hdrlen); + break; + } + + try { + if ((hdrlen >= 6) && !strncmp(hdr, ST_HEADER_HASH, 6)) { + hval = hdr + 6; + + std::string remainder = hval; + + const std::string delimiters = ", \t"; + std::vector tokens; + + tokenize(remainder, delimiters, tokens); + + for (const auto &token : tokens) { + if ((halg = rnp::Hash::alg(token.c_str())) == PGP_HASH_UNKNOWN) { + RNP_LOG("unknown halg: %s", token.c_str()); + continue; + } + add_hash_for_sig(param, PGP_SIG_TEXT, halg); + } + } else { + RNP_LOG("unknown header '%s'", hdr); + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + + src_skip(param->readsrc, hdrlen); + + if (!src_skip_eol(param->readsrc)) { + return false; + } + } while (1); + + /* we have exactly one empty line after the headers */ + return src_skip_eol(param->readsrc); +} + +static void +cleartext_process_line(pgp_source_t *src, const uint8_t *buf, size_t len, bool eol) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + uint8_t * bufen = (uint8_t *) buf + len - 1; + + /* check for dashes only if we are not in the middle */ + if (!param->clr_mline && (len > 0) && (buf[0] == CH_DASH)) { + if ((len > 1) && (buf[1] == CH_SPACE)) { + buf += 2; + len -= 2; + } else if ((len > 5) && !memcmp(buf, ST_DASHES, 5)) { + param->clr_eod = true; + return; + } else { + RNP_LOG("dash at the line begin"); + } + } + + /* hash eol if it is not the first line and we are not in the middle */ + if (!param->clr_fline && !param->clr_mline) { + /* we hash \r\n after the previous line to not hash the last eol before the sig */ + signed_src_update(src, ST_CRLF, 2); + } + + if (!len) { + return; + } + + if (len + param->outlen > sizeof(param->out)) { + RNP_LOG("wrong state"); + return; + } + + /* if we have eol after this line then strip trailing spaces and tabs */ + if (eol) { + for (; (bufen >= buf) && + ((*bufen == CH_SPACE) || (*bufen == CH_TAB) || (*bufen == CH_CR)); + bufen--) + ; + } + + if ((len = bufen + 1 - buf)) { + memcpy(param->out + param->outlen, buf, len); + param->outlen += len; + signed_src_update(src, buf, len); + } +} + +static bool +cleartext_src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres) +{ + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + if (!param) { + return false; + } + + uint8_t srcb[CT_BUF_LEN]; + uint8_t *cur, *en, *bg; + size_t read = 0; + size_t origlen = len; + + read = param->outlen - param->outpos; + if (read >= len) { + memcpy(buf, param->out + param->outpos, len); + param->outpos += len; + if (param->outpos == param->outlen) { + param->outpos = param->outlen = 0; + } + *readres = len; + return true; + } else if (read > 0) { + memcpy(buf, param->out + param->outpos, read); + len -= read; + buf = (uint8_t *) buf + read; + param->outpos = param->outlen = 0; + } + + if (param->clr_eod) { + *readres = origlen - len; + return true; + } + + do { + if (!src_peek(param->readsrc, srcb, sizeof(srcb), &read)) { + return false; + } else if (!read) { + break; + } + + /* processing data line by line, eol could be \n or \r\n */ + for (cur = srcb, bg = srcb, en = cur + read; cur < en; cur++) { + if ((*cur == CH_LF) || + ((*cur == CH_CR) && (cur + 1 < en) && (*(cur + 1) == CH_LF))) { + cleartext_process_line(src, bg, cur - bg, true); + /* processing eol */ + if (param->clr_eod) { + break; + } + + /* processing eol */ + param->clr_fline = false; + param->clr_mline = false; + if (*cur == CH_CR) { + param->out[param->outlen++] = *cur++; + } + param->out[param->outlen++] = *cur; + bg = cur + 1; + } + } + + /* if line is larger then 4k then just dump it out */ + if ((bg == srcb) && !param->clr_eod) { + /* if last char is \r, and it's not the end of stream, then do not dump it */ + if ((en > bg) && (*(en - 1) == CH_CR) && (read > 1)) { + en--; + } + cleartext_process_line(src, bg, en - bg, false); + param->clr_mline = true; + bg = en; + } + src_skip(param->readsrc, bg - srcb); + + /* put data from the param->out to buf */ + read = param->outlen > len ? len : param->outlen; + memcpy(buf, param->out, read); + buf = (uint8_t *) buf + read; + len -= read; + + if (read == param->outlen) { + param->outlen = 0; + } else { + param->outpos = read; + } + + /* we got to the signature marker */ + if (param->clr_eod || !len) { + break; + } + } while (1); + + *readres = origlen - len; + return true; +} + +static bool +encrypted_decrypt_cfb_header(pgp_source_encrypted_param_t *param, + pgp_symm_alg_t alg, + uint8_t * key) +{ + pgp_crypt_t crypt; + uint8_t enchdr[PGP_MAX_BLOCK_SIZE + 2]; + uint8_t dechdr[PGP_MAX_BLOCK_SIZE + 2]; + unsigned blsize; + + if (!(blsize = pgp_block_size(alg))) { + return false; + } + + /* reading encrypted header to check the password validity */ + if (!src_peek_eq(param->pkt.readsrc, enchdr, blsize + 2)) { + RNP_LOG("failed to read encrypted header"); + return false; + } + + /* having symmetric key in keybuf let's decrypt blocksize + 2 bytes and check them */ + if (!pgp_cipher_cfb_start(&crypt, alg, key, NULL)) { + RNP_LOG("failed to start cipher"); + return false; + } + + pgp_cipher_cfb_decrypt(&crypt, dechdr, enchdr, blsize + 2); + + if ((dechdr[blsize] != dechdr[blsize - 2]) || (dechdr[blsize + 1] != dechdr[blsize - 1])) { + RNP_LOG("checksum check failed"); + goto error; + } + + src_skip(param->pkt.readsrc, blsize + 2); + param->decrypt = crypt; + + /* init mdc if it is here */ + /* RFC 4880, 5.13: Unlike the Symmetrically Encrypted Data Packet, no special CFB + * resynchronization is done after encrypting this prefix data. */ + if (param->auth_type == rnp::AuthType::None) { + pgp_cipher_cfb_resync(¶m->decrypt, enchdr + 2); + return true; + } + + try { + param->mdc = rnp::Hash::create(PGP_HASH_SHA1); + param->mdc->add(dechdr, blsize + 2); + } catch (const std::exception &e) { + RNP_LOG("cannot create sha1 hash: %s", e.what()); + goto error; + } + return true; +error: + pgp_cipher_cfb_finish(&crypt); + return false; +} + +static bool +encrypted_start_aead(pgp_source_encrypted_param_t *param, pgp_symm_alg_t alg, uint8_t *key) +{ +#if !defined(ENABLE_AEAD) + RNP_LOG("AEAD is not enabled."); + return false; +#else + size_t gran; + + if (alg != param->aead_hdr.ealg) { + return false; + } + + /* initialize cipher with key */ + if (!pgp_cipher_aead_init( + ¶m->decrypt, param->aead_hdr.ealg, param->aead_hdr.aalg, key, true)) { + return false; + } + + gran = pgp_cipher_aead_granularity(¶m->decrypt); + if (gran > sizeof(param->cache)) { + RNP_LOG("wrong granularity"); + return false; + } + + return encrypted_start_aead_chunk(param, 0, false); +#endif +} + +static bool +encrypted_try_key(pgp_source_encrypted_param_t *param, + pgp_pk_sesskey_t * sesskey, + pgp_key_pkt_t * seckey, + rnp::SecurityContext & ctx) +{ + pgp_encrypted_material_t encmaterial; + try { + if (!sesskey->parse_material(encmaterial)) { + return false; + } + seckey->material.validate(ctx, false); + if (!seckey->material.valid()) { + RNP_LOG("Attempt to decrypt using the key with invalid material."); + return false; + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + + rnp::secure_array decbuf; + /* Decrypting session key value */ + rnp_result_t err; + bool res = false; + pgp_key_material_t *keymaterial = &seckey->material; + size_t declen = 0; + switch (sesskey->alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + err = rsa_decrypt_pkcs1( + &ctx.rng, decbuf.data(), &declen, &encmaterial.rsa, &keymaterial->rsa); + if (err) { + RNP_LOG("RSA decryption failure"); + return false; + } + break; + case PGP_PKA_SM2: +#if defined(ENABLE_SM2) + declen = decbuf.size(); + err = sm2_decrypt(decbuf.data(), &declen, &encmaterial.sm2, &keymaterial->ec); + if (err != RNP_SUCCESS) { + RNP_LOG("SM2 decryption failure, error %x", (int) err); + return false; + } + break; +#else + RNP_LOG("SM2 decryption is not available."); + return false; +#endif + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + const rnp_result_t ret = elgamal_decrypt_pkcs1( + &ctx.rng, decbuf.data(), &declen, &encmaterial.eg, &keymaterial->eg); + if (ret) { + RNP_LOG("ElGamal decryption failure [%X]", ret); + return false; + } + break; + } + case PGP_PKA_ECDH: { + if (!curve_supported(keymaterial->ec.curve)) { + RNP_LOG("ECDH decrypt: curve %d is not supported.", (int) keymaterial->ec.curve); + return false; + } + pgp_fingerprint_t fingerprint; + if (pgp_fingerprint(fingerprint, *seckey)) { + RNP_LOG("ECDH fingerprint calculation failed"); + return false; + } + if ((keymaterial->ec.curve == PGP_CURVE_25519) && + !x25519_bits_tweaked(keymaterial->ec)) { + RNP_LOG("Warning: bits of 25519 secret key are not tweaked."); + } + declen = decbuf.size(); + err = ecdh_decrypt_pkcs5( + decbuf.data(), &declen, &encmaterial.ecdh, &keymaterial->ec, fingerprint); + if (err != RNP_SUCCESS) { + RNP_LOG("ECDH decryption error %u", err); + return false; + } + break; + } + default: + RNP_LOG("unsupported public key algorithm %d\n", seckey->alg); + return false; + } + + /* Check algorithm and key length */ + if (!pgp_is_sa_supported(decbuf[0])) { + RNP_LOG("Unsupported symmetric algorithm %" PRIu8, decbuf[0]); + return false; + } + + pgp_symm_alg_t salg = static_cast(decbuf[0]); + size_t keylen = pgp_key_size(salg); + if (declen != keylen + 3) { + RNP_LOG("invalid symmetric key length"); + return false; + } + + /* Validate checksum */ + rnp::secure_array checksum; + for (unsigned i = 1; i <= keylen; i++) { + checksum[0] += decbuf[i]; + } + + if ((checksum[0] & 0xffff) != + (decbuf[keylen + 2] | ((unsigned) decbuf[keylen + 1] << 8))) { + RNP_LOG("wrong checksum\n"); + return false; + } + + if (param->use_cfb()) { + /* Decrypt header */ + res = encrypted_decrypt_cfb_header(param, salg, &decbuf[1]); + } else { + /* Start AEAD decrypting, assuming we have correct key */ + res = encrypted_start_aead(param, salg, &decbuf[1]); + } + if (res) { + param->salg = salg; + } + return res; +} + +#if defined(ENABLE_AEAD) +static bool +encrypted_sesk_set_ad(pgp_crypt_t *crypt, pgp_sk_sesskey_t *skey) +{ + /* TODO: this method is exact duplicate as in stream-write.c. Not sure where to put it */ + uint8_t ad_data[4]; + + ad_data[0] = PGP_PKT_SK_SESSION_KEY | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; + ad_data[1] = skey->version; + ad_data[2] = skey->alg; + ad_data[3] = skey->aalg; + + return pgp_cipher_aead_set_ad(crypt, ad_data, 4); +} +#endif + +static int +encrypted_try_password(pgp_source_encrypted_param_t *param, const char *password) +{ + bool keyavail = false; /* tried password at least once */ + + for (auto &skey : param->symencs) { + rnp::secure_array keybuf; + /* deriving symmetric key from password */ + size_t keysize = pgp_key_size(skey.alg); + if (!keysize || !pgp_s2k_derive_key(&skey.s2k, password, keybuf.data(), keysize)) { + continue; + } + pgp_crypt_t crypt; + pgp_symm_alg_t alg; + + if (skey.version == PGP_SKSK_V4) { + /* v4 symmetrically-encrypted session key */ + if (skey.enckeylen > 0) { + /* decrypting session key */ + if (!pgp_cipher_cfb_start(&crypt, skey.alg, keybuf.data(), NULL)) { + continue; + } + + pgp_cipher_cfb_decrypt(&crypt, keybuf.data(), skey.enckey, skey.enckeylen); + pgp_cipher_cfb_finish(&crypt); + + alg = (pgp_symm_alg_t) keybuf[0]; + keysize = pgp_key_size(alg); + if (!keysize || (keysize + 1 != skey.enckeylen)) { + continue; + } + memmove(keybuf.data(), keybuf.data() + 1, keysize); + } else { + alg = (pgp_symm_alg_t) skey.alg; + } + + if (!pgp_block_size(alg)) { + continue; + } + keyavail = true; + } else if (skey.version == PGP_SKSK_V5) { +#if !defined(ENABLE_AEAD) + continue; +#else + /* v5 AEAD-encrypted session key */ + size_t taglen = pgp_cipher_aead_tag_len(skey.aalg); + size_t ceklen = pgp_key_size(param->aead_hdr.ealg); + if (!taglen || !ceklen || (ceklen + taglen != skey.enckeylen)) { + RNP_LOG("CEK len/alg mismatch"); + continue; + } + alg = skey.alg; + + /* initialize cipher */ + if (!pgp_cipher_aead_init(&crypt, skey.alg, skey.aalg, keybuf.data(), true)) { + continue; + } + + /* set additional data */ + if (!encrypted_sesk_set_ad(&crypt, &skey)) { + RNP_LOG("failed to set ad"); + continue; + } + + /* calculate nonce */ + uint8_t nonce[PGP_AEAD_MAX_NONCE_LEN]; + size_t noncelen = pgp_cipher_aead_nonce(skey.aalg, skey.iv, nonce, 0); + + /* start cipher, decrypt key and verify tag */ + keyavail = + pgp_cipher_aead_start(&crypt, nonce, noncelen) && + pgp_cipher_aead_finish(&crypt, keybuf.data(), skey.enckey, skey.enckeylen); + pgp_cipher_aead_destroy(&crypt); + + /* we have decrypted key so let's start decryption */ + if (!keyavail) { + continue; + } +#endif + } else { + continue; + } + + /* Decrypt header for CFB */ + if (param->use_cfb() && !encrypted_decrypt_cfb_header(param, alg, keybuf.data())) { + continue; + } + if (!param->use_cfb() && + !encrypted_start_aead(param, param->aead_hdr.ealg, keybuf.data())) { + continue; + } + + param->salg = param->use_cfb() ? alg : param->aead_hdr.ealg; + /* inform handler that we used this symenc */ + if (param->handler->on_decryption_start) { + param->handler->on_decryption_start(NULL, &skey, param->handler->param); + } + return 1; + } + + if (!param->use_cfb() && pgp_block_size(param->aead_hdr.ealg)) { + /* we know aead symm alg even if we wasn't able to start decryption */ + param->salg = param->aead_hdr.ealg; + } + + if (!keyavail) { + RNP_LOG("no supported sk available"); + return -1; + } + return 0; +} + +/** @brief Initialize common to stream packets params, including partial data source */ +static rnp_result_t +init_packet_params(pgp_source_packet_param_t ¶m) +{ + param.origsrc = NULL; + + /* save packet header */ + rnp_result_t ret = stream_peek_packet_hdr(param.readsrc, ¶m.hdr); + if (ret) { + return ret; + } + src_skip(param.readsrc, param.hdr.hdr_len); + if (!param.hdr.partial) { + return RNP_SUCCESS; + } + + /* initialize partial reader if needed */ + pgp_source_t *partsrc = (pgp_source_t *) calloc(1, sizeof(*partsrc)); + if (!partsrc) { + return RNP_ERROR_OUT_OF_MEMORY; + } + rnp_result_t errcode = init_partial_pkt_src(partsrc, param.readsrc, param.hdr); + if (errcode) { + free(partsrc); + return errcode; + } + param.origsrc = param.readsrc; + param.readsrc = partsrc; + return RNP_SUCCESS; +} + +rnp_result_t +init_literal_src(pgp_source_t *src, pgp_source_t *readsrc) +{ + rnp_result_t ret = RNP_ERROR_GENERIC; + pgp_source_literal_param_t *param; + uint8_t format = 0; + uint8_t nlen = 0; + uint8_t timestamp[4]; + + if (!init_src_common(src, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_source_literal_param_t *) src->param; + param->pkt.readsrc = readsrc; + src->read = literal_src_read; + src->close = literal_src_close; + src->type = PGP_STREAM_LITERAL; + + /* Reading packet length/checking whether it is partial */ + if ((ret = init_packet_params(param->pkt))) { + goto finish; + } + + /* data format */ + if (!src_read_eq(param->pkt.readsrc, &format, 1)) { + RNP_LOG("failed to read data format"); + ret = RNP_ERROR_READ; + goto finish; + } + + switch (format) { + case 'b': + case 't': + case 'u': + case 'l': + case '1': + break; + default: + RNP_LOG("unknown data format %" PRIu8, format); + ret = RNP_ERROR_BAD_FORMAT; + goto finish; + } + param->hdr.format = format; + /* file name */ + if (!src_read_eq(param->pkt.readsrc, &nlen, 1)) { + RNP_LOG("failed to read file name length"); + ret = RNP_ERROR_READ; + goto finish; + } + if (nlen && !src_read_eq(param->pkt.readsrc, param->hdr.fname, nlen)) { + RNP_LOG("failed to read file name"); + ret = RNP_ERROR_READ; + goto finish; + } + param->hdr.fname[nlen] = 0; + param->hdr.fname_len = nlen; + /* timestamp */ + if (!src_read_eq(param->pkt.readsrc, timestamp, 4)) { + RNP_LOG("failed to read file timestamp"); + ret = RNP_ERROR_READ; + goto finish; + } + param->hdr.timestamp = read_uint32(timestamp); + + if (!param->pkt.hdr.indeterminate && !param->pkt.hdr.partial) { + /* format filename-length filename timestamp */ + const uint16_t nbytes = 1 + 1 + nlen + 4; + if (param->pkt.hdr.pkt_len < nbytes) { + ret = RNP_ERROR_BAD_FORMAT; + goto finish; + } + src->size = param->pkt.hdr.pkt_len - nbytes; + src->knownsize = 1; + } + ret = RNP_SUCCESS; +finish: + if (ret != RNP_SUCCESS) { + src_close(src); + } + return ret; +} + +bool +get_literal_src_hdr(pgp_source_t *src, pgp_literal_hdr_t *hdr) +{ + pgp_source_literal_param_t *param; + + if (src->type != PGP_STREAM_LITERAL) { + RNP_LOG("wrong stream"); + return false; + } + + param = (pgp_source_literal_param_t *) src->param; + *hdr = param->hdr; + return true; +} + +rnp_result_t +init_compressed_src(pgp_source_t *src, pgp_source_t *readsrc) +{ + rnp_result_t errcode = RNP_ERROR_GENERIC; + pgp_source_compressed_param_t *param; + uint8_t alg; + int zret; + + if (!init_src_common(src, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_source_compressed_param_t *) src->param; + param->pkt.readsrc = readsrc; + src->read = compressed_src_read; + src->close = compressed_src_close; + src->type = PGP_STREAM_COMPRESSED; + + /* Reading packet length/checking whether it is partial */ + errcode = init_packet_params(param->pkt); + if (errcode != RNP_SUCCESS) { + goto finish; + } + + /* Reading compression algorithm */ + if (!src_read_eq(param->pkt.readsrc, &alg, 1)) { + RNP_LOG("failed to read compression algorithm"); + errcode = RNP_ERROR_READ; + goto finish; + } + + /* Initializing decompression */ + switch (alg) { + case PGP_C_NONE: + break; + case PGP_C_ZIP: + case PGP_C_ZLIB: + (void) memset(¶m->z, 0x0, sizeof(param->z)); + zret = + alg == PGP_C_ZIP ? (int) inflateInit2(¶m->z, -15) : (int) inflateInit(¶m->z); + if (zret != Z_OK) { + RNP_LOG("failed to init zlib, error %d", zret); + errcode = RNP_ERROR_READ; + goto finish; + } + break; +#ifdef HAVE_BZLIB_H + case PGP_C_BZIP2: + (void) memset(¶m->bz, 0x0, sizeof(param->bz)); + zret = BZ2_bzDecompressInit(¶m->bz, 0, 0); + if (zret != BZ_OK) { + RNP_LOG("failed to init bz, error %d", zret); + errcode = RNP_ERROR_READ; + goto finish; + } + break; +#endif + default: + RNP_LOG("unknown compression algorithm: %d", (int) alg); + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + param->alg = (pgp_compression_type_t) alg; + param->inlen = 0; + param->inpos = 0; + + errcode = RNP_SUCCESS; +finish: + if (errcode != RNP_SUCCESS) { + src_close(src); + } + return errcode; +} + +bool +get_compressed_src_alg(pgp_source_t *src, uint8_t *alg) +{ + pgp_source_compressed_param_t *param; + + if (src->type != PGP_STREAM_COMPRESSED) { + RNP_LOG("wrong stream"); + return false; + } + + param = (pgp_source_compressed_param_t *) src->param; + *alg = param->alg; + return true; +} + +bool +get_aead_src_hdr(pgp_source_t *src, pgp_aead_hdr_t *hdr) +{ + uint8_t hdrbt[4] = {0}; + + if (!src_read_eq(src, hdrbt, 4)) { + return false; + } + + hdr->version = hdrbt[0]; + hdr->ealg = (pgp_symm_alg_t) hdrbt[1]; + hdr->aalg = (pgp_aead_alg_t) hdrbt[2]; + hdr->csize = hdrbt[3]; + + if (!(hdr->ivlen = pgp_cipher_aead_nonce_len(hdr->aalg))) { + RNP_LOG("wrong aead nonce length: alg %d", (int) hdr->aalg); + return false; + } + + return src_read_eq(src, hdr->iv, hdr->ivlen); +} + +#define MAX_RECIPIENTS 16384 + +static rnp_result_t +encrypted_read_packet_data(pgp_source_encrypted_param_t *param) +{ + int ptype; + /* Reading pk/sk encrypted session key(s) */ + try { + size_t errors = 0; + bool stop = false; + while (!stop) { + if (param->pubencs.size() + param->symencs.size() + errors > MAX_RECIPIENTS) { + RNP_LOG("Too many recipients of the encrypted message. Aborting."); + return RNP_ERROR_BAD_STATE; + } + uint8_t ptag; + if (!src_peek_eq(param->pkt.readsrc, &ptag, 1)) { + RNP_LOG("failed to read packet header"); + return RNP_ERROR_READ; + } + ptype = get_packet_type(ptag); + switch (ptype) { + case PGP_PKT_SK_SESSION_KEY: { + pgp_sk_sesskey_t skey; + rnp_result_t ret = skey.parse(*param->pkt.readsrc); + if (ret == RNP_ERROR_READ) { + RNP_LOG("SKESK: Premature end of data."); + return ret; + } + if (ret) { + RNP_LOG("Failed to parse SKESK, skipping."); + errors++; + continue; + } + param->symencs.push_back(skey); + break; + } + case PGP_PKT_PK_SESSION_KEY: { + pgp_pk_sesskey_t pkey; + rnp_result_t ret = pkey.parse(*param->pkt.readsrc); + if (ret == RNP_ERROR_READ) { + RNP_LOG("PKESK: Premature end of data."); + return ret; + } + if (ret) { + RNP_LOG("Failed to parse PKESK, skipping."); + errors++; + continue; + } + param->pubencs.push_back(pkey); + break; + } + case PGP_PKT_SE_DATA: + case PGP_PKT_SE_IP_DATA: + case PGP_PKT_AEAD_ENCRYPTED: + stop = true; + break; + default: + RNP_LOG("unknown packet type: %d", ptype); + return RNP_ERROR_BAD_FORMAT; + } + } + } catch (const rnp::rnp_exception &e) { + RNP_LOG("%s: %d", e.what(), e.code()); + return e.code(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_GENERIC; + } + + /* Reading packet length/checking whether it is partial */ + rnp_result_t errcode = init_packet_params(param->pkt); + if (errcode) { + return errcode; + } + + /* Reading header of encrypted packet */ + if (ptype == PGP_PKT_AEAD_ENCRYPTED) { + param->auth_type = rnp::AuthType::AEADv1; + uint8_t hdr[4]; + if (!src_peek_eq(param->pkt.readsrc, hdr, 4)) { + return RNP_ERROR_READ; + } + + if (!get_aead_src_hdr(param->pkt.readsrc, ¶m->aead_hdr)) { + RNP_LOG("failed to read AEAD header"); + return RNP_ERROR_READ; + } + + /* check AEAD encrypted data packet header */ + if (param->aead_hdr.version != 1) { + RNP_LOG("unknown aead ver: %d", param->aead_hdr.version); + return RNP_ERROR_BAD_FORMAT; + } + if ((param->aead_hdr.aalg != PGP_AEAD_EAX) && (param->aead_hdr.aalg != PGP_AEAD_OCB)) { + RNP_LOG("unknown aead alg: %d", (int) param->aead_hdr.aalg); + return RNP_ERROR_BAD_FORMAT; + } + if (param->aead_hdr.csize > 56) { + RNP_LOG("too large chunk size: %d", param->aead_hdr.csize); + return RNP_ERROR_BAD_FORMAT; + } + if (param->aead_hdr.csize > 16) { + RNP_LOG("Warning: AEAD chunk bits > 16."); + } + param->chunklen = 1L << (param->aead_hdr.csize + 6); + + /* build additional data */ + param->aead_adlen = 13; + param->aead_ad[0] = param->pkt.hdr.hdr[0]; + memcpy(param->aead_ad + 1, hdr, 4); + memset(param->aead_ad + 5, 0, 8); + } else if (ptype == PGP_PKT_SE_IP_DATA) { + uint8_t mdcver; + if (!src_read_eq(param->pkt.readsrc, &mdcver, 1)) { + return RNP_ERROR_READ; + } + + if (mdcver != 1) { + RNP_LOG("unknown mdc ver: %d", (int) mdcver); + return RNP_ERROR_BAD_FORMAT; + } + param->auth_type = rnp::AuthType::MDC; + } + param->auth_validated = false; + + return RNP_SUCCESS; +} + +#define MAX_HIDDEN_TRIES 64 + +static rnp_result_t +init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *readsrc) +{ + if (!init_src_common(src, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + pgp_source_encrypted_param_t *param = new (std::nothrow) pgp_source_encrypted_param_t(); + if (!param) { + return RNP_ERROR_OUT_OF_MEMORY; + } + src->param = param; + param->pkt.readsrc = readsrc; + param->handler = handler; + + src->close = encrypted_src_close; + src->finish = encrypted_src_finish; + src->type = PGP_STREAM_ENCRYPTED; + + /* Read the packet-related information */ + rnp_result_t errcode = encrypted_read_packet_data(param); + if (errcode) { + goto finish; + } + + src->read = !param->use_cfb() ? encrypted_src_read_aead : encrypted_src_read_cfb; + + /* Obtaining the symmetric key */ + if (!handler->password_provider) { + RNP_LOG("no password provider"); + errcode = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + /* informing handler about the available pubencs/symencs */ + if (handler->on_recipients) { + handler->on_recipients(param->pubencs, param->symencs, handler->param); + } + + bool have_key; + have_key = false; + /* Trying public-key decryption */ + if (!param->pubencs.empty()) { + if (!handler->key_provider) { + RNP_LOG("no key provider"); + errcode = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + pgp_key_request_ctx_t keyctx(PGP_OP_DECRYPT, true, PGP_KEY_SEARCH_KEYID); + + size_t pubidx = 0; + size_t hidden_tries = 0; + errcode = RNP_ERROR_NO_SUITABLE_KEY; + while (pubidx < param->pubencs.size()) { + auto &pubenc = param->pubencs[pubidx]; + keyctx.search.by.keyid = pubenc.key_id; + /* Get the key if any */ + pgp_key_t *seckey = pgp_request_key(handler->key_provider, &keyctx); + if (!seckey) { + pubidx++; + continue; + } + /* Check whether key fits our needs */ + bool hidden = pubenc.key_id == pgp_key_id_t({}); + if (!hidden || (++hidden_tries >= MAX_HIDDEN_TRIES)) { + pubidx++; + } + if (!seckey->has_secret() || !seckey->can_encrypt()) { + continue; + } + /* Check whether key is of required algorithm for hidden keyid */ + if (hidden && seckey->alg() != pubenc.alg) { + continue; + } + /* Decrypt key */ + rnp::KeyLocker seclock(*seckey); + if (!seckey->unlock(*handler->password_provider, PGP_OP_DECRYPT)) { + errcode = RNP_ERROR_BAD_PASSWORD; + continue; + } + + /* Try to initialize the decryption */ + rnp::LogStop logstop(hidden); + if (encrypted_try_key(param, &pubenc, &seckey->pkt(), *handler->ctx->ctx)) { + have_key = true; + /* inform handler that we used this pubenc */ + if (handler->on_decryption_start) { + handler->on_decryption_start(&pubenc, NULL, handler->param); + } + break; + } + } + } + + /* Trying password-based decryption */ + if (!have_key && !param->symencs.empty()) { + rnp::secure_array password; + pgp_password_ctx_t pass_ctx(PGP_OP_DECRYPT_SYM); + if (!pgp_request_password( + handler->password_provider, &pass_ctx, password.data(), password.size())) { + errcode = RNP_ERROR_BAD_PASSWORD; + goto finish; + } + + int intres = encrypted_try_password(param, password.data()); + if (intres > 0) { + have_key = true; + } else if (intres < 0) { + errcode = RNP_ERROR_NOT_SUPPORTED; + } else { + errcode = RNP_ERROR_BAD_PASSWORD; + } + } + + /* report decryption start to the handler */ + if (handler->on_decryption_info) { + handler->on_decryption_info(param->auth_type == rnp::AuthType::MDC, + param->aead_hdr.aalg, + param->salg, + handler->param); + } + + if (!have_key) { + RNP_LOG("failed to obtain decrypting key or password"); + if (!errcode) { + errcode = RNP_ERROR_NO_SUITABLE_KEY; + } + goto finish; + } + errcode = RNP_SUCCESS; +finish: + if (errcode != RNP_SUCCESS) { + src_close(src); + } + return errcode; +} + +static rnp_result_t +init_cleartext_signed_src(pgp_source_t *src) +{ + char buf[64]; + size_t hdrlen = strlen(ST_CLEAR_BEGIN); + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param; + + /* checking header line */ + if (!src_read_eq(param->readsrc, buf, hdrlen)) { + RNP_LOG("failed to read header"); + return RNP_ERROR_READ; + } + + if (memcmp(ST_CLEAR_BEGIN, buf, hdrlen)) { + RNP_LOG("wrong header"); + return RNP_ERROR_BAD_FORMAT; + } + + /* eol */ + if (!src_skip_eol(param->readsrc)) { + RNP_LOG("no eol after the cleartext header"); + return RNP_ERROR_BAD_FORMAT; + } + + /* parsing Hash headers */ + if (!cleartext_parse_headers(src)) { + return RNP_ERROR_BAD_FORMAT; + } + + /* now we are good to go */ + param->clr_fline = true; + return RNP_SUCCESS; +} + +#define MAX_SIG_ERRORS 65536 + +static rnp_result_t +init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *readsrc) +{ + rnp_result_t errcode = RNP_ERROR_GENERIC; + pgp_source_signed_param_t *param; + uint8_t ptag; + int ptype; + pgp_signature_t * sig = NULL; + bool cleartext; + size_t sigerrors = 0; + + if (!init_src_common(src, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + try { + param = new pgp_source_signed_param_t(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + src->param = param; + + cleartext = is_cleartext_source(readsrc); + param->readsrc = readsrc; + param->handler = handler; + param->cleartext = cleartext; + param->stripped_crs = 0; + src->read = cleartext ? cleartext_src_read : signed_src_read; + src->close = signed_src_close; + src->finish = signed_src_finish; + src->type = cleartext ? PGP_STREAM_CLEARTEXT : PGP_STREAM_SIGNED; + + /* we need key provider to validate signatures */ + if (!handler->key_provider) { + RNP_LOG("no key provider"); + errcode = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + if (cleartext) { + errcode = init_cleartext_signed_src(src); + goto finish; + } + + /* Reading one-pass and signature packets */ + while (true) { + /* stop early if we are in zip-bomb with erroneous packets */ + if (sigerrors >= MAX_SIG_ERRORS) { + RNP_LOG("Too many one-pass/signature errors. Stopping."); + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + + size_t readb = readsrc->readb; + if (!src_peek_eq(readsrc, &ptag, 1)) { + RNP_LOG("failed to read packet header"); + errcode = RNP_ERROR_READ; + goto finish; + } + + ptype = get_packet_type(ptag); + + if (ptype == PGP_PKT_ONE_PASS_SIG) { + if (param->onepasses.size() >= MAX_SIGNATURES) { + RNP_LOG("Too many one-pass signatures."); + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + pgp_one_pass_sig_t onepass; + try { + errcode = onepass.parse(*readsrc); + } catch (const std::exception &e) { + errcode = RNP_ERROR_GENERIC; + } + if (errcode) { + if (errcode == RNP_ERROR_READ) { + goto finish; + } + if (readb == readsrc->readb) { + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + sigerrors++; + continue; + } + + try { + param->onepasses.push_back(onepass); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + errcode = RNP_ERROR_OUT_OF_MEMORY; + goto finish; + } + + /* adding hash context */ + try { + add_hash_for_sig(param, onepass.type, onepass.halg); + } catch (const std::exception &e) { + RNP_LOG("Failed to create hash %d for onepass %d : %s.", + (int) onepass.halg, + (int) onepass.type, + e.what()); + errcode = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + if (onepass.nested) { + /* despite the name non-zero value means that it is the last one-pass */ + break; + } + } else if (ptype == PGP_PKT_SIGNATURE) { + /* no need to check the error here - we already know tag */ + if (signed_read_single_signature(param, readsrc, &sig)) { + sigerrors++; + } + /* adding hash context */ + if (sig) { + try { + add_hash_for_sig(param, sig->type(), sig->halg); + } catch (const std::exception &e) { + RNP_LOG("Failed to create hash %d for sig %d : %s.", + (int) sig->halg, + (int) sig->type(), + e.what()); + errcode = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + } + } else { + break; + } + + /* check if we are not it endless loop */ + if (readb == readsrc->readb) { + errcode = RNP_ERROR_BAD_FORMAT; + goto finish; + } + /* for detached signature we'll get eof */ + if (src_eof(readsrc)) { + param->detached = true; + break; + } + } + + /* checking what we have now */ + if (param->onepasses.empty() && param->sigs.empty()) { + RNP_LOG("no signatures"); + errcode = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + if (!param->onepasses.empty() && !param->sigs.empty()) { + RNP_LOG("warning: one-passes are mixed with signatures"); + } + + errcode = RNP_SUCCESS; +finish: + if (errcode != RNP_SUCCESS) { + src_close(src); + } + + return errcode; +} + +pgp_processing_ctx_t::~pgp_processing_ctx_t() +{ + for (auto &src : sources) { + src_close(&src); + } +} + +/** @brief build PGP source sequence down to the literal data packet + * + **/ +static rnp_result_t +init_packet_sequence(pgp_processing_ctx_t &ctx, pgp_source_t &src) +{ + pgp_source_t *lsrc = &src; + size_t srcnum = ctx.sources.size(); + + while (1) { + uint8_t ptag = 0; + if (!src_peek_eq(lsrc, &ptag, 1)) { + RNP_LOG("cannot read packet tag"); + return RNP_ERROR_READ; + } + + int type = get_packet_type(ptag); + if (type < 0) { + RNP_LOG("wrong pkt tag %d", (int) ptag); + return RNP_ERROR_BAD_FORMAT; + } + + if (ctx.sources.size() - srcnum == MAXIMUM_NESTING_LEVEL) { + RNP_LOG("Too many nested OpenPGP packets"); + return RNP_ERROR_BAD_FORMAT; + } + + pgp_source_t psrc = {}; + rnp_result_t ret = RNP_ERROR_BAD_FORMAT; + switch (type) { + case PGP_PKT_PK_SESSION_KEY: + case PGP_PKT_SK_SESSION_KEY: + ret = init_encrypted_src(&ctx.handler, &psrc, lsrc); + break; + case PGP_PKT_ONE_PASS_SIG: + case PGP_PKT_SIGNATURE: + ret = init_signed_src(&ctx.handler, &psrc, lsrc); + break; + case PGP_PKT_COMPRESSED: + ret = init_compressed_src(&psrc, lsrc); + break; + case PGP_PKT_LITDATA: + if ((lsrc != &src) && (lsrc->type != PGP_STREAM_ENCRYPTED) && + (lsrc->type != PGP_STREAM_SIGNED) && (lsrc->type != PGP_STREAM_COMPRESSED)) { + RNP_LOG("unexpected literal pkt"); + ret = RNP_ERROR_BAD_FORMAT; + break; + } + ret = init_literal_src(&psrc, lsrc); + break; + case PGP_PKT_MARKER: + if (ctx.sources.size() != srcnum) { + RNP_LOG("Warning: marker packet wrapped in pgp stream."); + } + ret = stream_parse_marker(*lsrc); + if (ret) { + RNP_LOG("Invalid marker packet"); + return ret; + } + continue; + default: + RNP_LOG("unexpected pkt %d", type); + ret = RNP_ERROR_BAD_FORMAT; + } + + if (ret) { + return ret; + } + + try { + ctx.sources.push_back(psrc); + lsrc = &ctx.sources.back(); + } catch (const std::exception &e) { + src_close(&psrc); + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + + if (lsrc->type == PGP_STREAM_LITERAL) { + ctx.literal_src = lsrc; + ctx.msg_type = PGP_MESSAGE_NORMAL; + return RNP_SUCCESS; + } + if (lsrc->type == PGP_STREAM_SIGNED) { + ctx.signed_src = lsrc; + pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) lsrc->param; + if (param->detached) { + ctx.msg_type = PGP_MESSAGE_DETACHED; + return RNP_SUCCESS; + } + } + } +} + +static rnp_result_t +init_cleartext_sequence(pgp_processing_ctx_t &ctx, pgp_source_t &src) +{ + pgp_source_t clrsrc = {}; + rnp_result_t res; + + if ((res = init_signed_src(&ctx.handler, &clrsrc, &src))) { + return res; + } + try { + ctx.sources.push_back(clrsrc); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + src_close(&clrsrc); + return RNP_ERROR_OUT_OF_MEMORY; + } + return RNP_SUCCESS; +} + +static rnp_result_t +init_armored_sequence(pgp_processing_ctx_t &ctx, pgp_source_t &src) +{ + pgp_source_t armorsrc = {}; + rnp_result_t res; + + if ((res = init_armored_src(&armorsrc, &src))) { + return res; + } + + try { + ctx.sources.push_back(armorsrc); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + src_close(&armorsrc); + return RNP_ERROR_OUT_OF_MEMORY; + } + return init_packet_sequence(ctx, ctx.sources.back()); +} + +rnp_result_t +process_pgp_source(pgp_parse_handler_t *handler, pgp_source_t &src) +{ + rnp_result_t res = RNP_ERROR_BAD_FORMAT; + rnp_result_t fres; + pgp_processing_ctx_t ctx = {}; + pgp_source_t * decsrc = NULL; + pgp_source_t datasrc = {0}; + pgp_dest_t * outdest = NULL; + bool closeout = true; + uint8_t * readbuf = NULL; + + ctx.handler = *handler; + /* Building readers sequence. Checking whether it is binary data */ + if (is_pgp_source(src)) { + res = init_packet_sequence(ctx, src); + } else { + /* Trying armored or cleartext data */ + if (is_cleartext_source(&src)) { + /* Initializing cleartext message */ + res = init_cleartext_sequence(ctx, src); + } else if (is_armored_source(&src)) { + /* Initializing armored message */ + res = init_armored_sequence(ctx, src); + } else { + RNP_LOG("not an OpenPGP data provided"); + res = RNP_ERROR_BAD_FORMAT; + goto finish; + } + } + + if (res != RNP_SUCCESS) { + goto finish; + } + + if ((readbuf = (uint8_t *) calloc(1, PGP_INPUT_CACHE_SIZE)) == NULL) { + RNP_LOG("allocation failure"); + res = RNP_ERROR_OUT_OF_MEMORY; + goto finish; + } + + if (ctx.msg_type == PGP_MESSAGE_DETACHED) { + /* detached signature case */ + if (!handler->ctx->detached) { + RNP_LOG("Unexpected detached signature input."); + res = RNP_ERROR_BAD_STATE; + goto finish; + } + if (!handler->src_provider || !handler->src_provider(handler, &datasrc)) { + RNP_LOG("no data source for detached signature verification"); + res = RNP_ERROR_READ; + goto finish; + } + + while (!datasrc.eof) { + size_t read = 0; + if (!src_read(&datasrc, readbuf, PGP_INPUT_CACHE_SIZE, &read)) { + res = RNP_ERROR_GENERIC; + break; + } + if (read > 0) { + signed_src_update(ctx.signed_src, readbuf, read); + } + } + src_close(&datasrc); + } else { + if (handler->ctx->detached) { + RNP_LOG("Detached signature expected."); + res = RNP_ERROR_BAD_STATE; + goto finish; + } + /* file processing case */ + decsrc = &ctx.sources.back(); + char * filename = NULL; + uint32_t mtime = 0; + + if (ctx.literal_src) { + auto *param = static_cast(ctx.literal_src->param); + filename = param->hdr.fname; + mtime = param->hdr.timestamp; + } + + if (!handler->dest_provider || + !handler->dest_provider(handler, &outdest, &closeout, filename, mtime)) { + res = RNP_ERROR_WRITE; + goto finish; + } + + /* reading the input */ + while (!decsrc->eof) { + size_t read = 0; + if (!src_read(decsrc, readbuf, PGP_INPUT_CACHE_SIZE, &read)) { + res = RNP_ERROR_GENERIC; + break; + } + if (!read) { + continue; + } + if (ctx.signed_src) { + signed_src_update(ctx.signed_src, readbuf, read); + } + dst_write(outdest, readbuf, read); + if (outdest->werr != RNP_SUCCESS) { + RNP_LOG("failed to output data"); + res = RNP_ERROR_WRITE; + break; + } + } + } + + /* finalizing the input. Signatures are checked on this step */ + if (res == RNP_SUCCESS) { + for (auto &ctxsrc : ctx.sources) { + fres = src_finish(&ctxsrc); + if (fres) { + res = fres; + } + } + } + + if (closeout && (ctx.msg_type != PGP_MESSAGE_DETACHED)) { + dst_close(outdest, res != RNP_SUCCESS); + } + +finish: + free(readbuf); + return res; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-parse.h b/comm/third_party/rnp/src/librepgp/stream-parse.h new file mode 100644 index 0000000000..4f22b9a6ca --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-parse.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_PARSE_H_ +#define STREAM_PARSE_H_ + +#include +#include +#include +#include "rnp.h" +#include "stream-common.h" +#include "stream-ctx.h" +#include "stream-packet.h" + +typedef struct pgp_parse_handler_t pgp_parse_handler_t; +typedef struct pgp_signature_info_t pgp_signature_info_t; +typedef bool pgp_destination_func_t(pgp_parse_handler_t *handler, + pgp_dest_t ** dst, + bool * closedst, + const char * filename, + uint32_t mtime); +typedef bool pgp_source_func_t(pgp_parse_handler_t *handler, pgp_source_t *src); +typedef void pgp_signatures_func_t(const std::vector &sigs, void *param); + +typedef void pgp_on_recipients_func_t(const std::vector &recipients, + const std::vector &passwords, + void * param); +typedef void pgp_decryption_start_func_t(pgp_pk_sesskey_t *pubenc, + pgp_sk_sesskey_t *symenc, + void * param); +typedef void pgp_decryption_info_func_t(bool mdc, + pgp_aead_alg_t aead, + pgp_symm_alg_t salg, + void * param); +typedef void pgp_decryption_done_func_t(bool validated, void *param); + +/* handler used to return needed information during pgp source processing */ +typedef struct pgp_parse_handler_t { + pgp_password_provider_t *password_provider; /* if NULL then default will be used */ + pgp_key_provider_t * key_provider; /* must be set when key is required, i.e. during + signing/verification/public key encryption and + deryption */ + pgp_destination_func_t *dest_provider; /* called when destination stream is required */ + pgp_source_func_t * src_provider; /* required to provider source during the detached + signature verification */ + pgp_on_recipients_func_t * on_recipients; /* called before decryption start */ + pgp_decryption_start_func_t *on_decryption_start; /* called when decryption key obtained */ + pgp_decryption_info_func_t * on_decryption_info; /* called when decryption is started */ + pgp_decryption_done_func_t * on_decryption_done; /* called when decryption is finished */ + pgp_signatures_func_t * on_signatures; /* for signature verification results */ + + rnp_ctx_t *ctx; /* operation context */ + void * param; /* additional parameters */ +} pgp_parse_handler_t; + +/* @brief Process the OpenPGP source: file, memory, stdin + * Function will parse input data, provided by any source conforming to pgp_source_t, + * autodetecting whether it is armored, cleartext or binary. + * @param handler handler to respond on stream reader callbacks + * @param src initialized source with cache + * @return RNP_SUCCESS on success or error code otherwise + **/ +rnp_result_t process_pgp_source(pgp_parse_handler_t *handler, pgp_source_t &src); + +/* @brief Init source with OpenPGP compressed data packet + * @param src allocated pgp_source_t structure + * @param readsrc source to read compressed data from + * @return RNP_SUCCESS on success or error code otherwise + */ +rnp_result_t init_compressed_src(pgp_source_t *src, pgp_source_t *readsrc); + +/* @brief Get compression algorithm used in compressed source + * @param src compressed source, initialized with init_compressed_src + * @param alg algorithm will be written here. Cannot be NULL. + * @return true if operation succeeded and alg is populate or false otherwise + */ +bool get_compressed_src_alg(pgp_source_t *src, uint8_t *alg); + +/* @brief Init source with OpenPGP literal data packet + * @param src allocated pgp_source_t structure + * @param readsrc source to read literal data from + * @return RNP_SUCCESS on success or error code otherwise + */ +rnp_result_t init_literal_src(pgp_source_t *src, pgp_source_t *readsrc); + +/* @brief Get the literal data packet information fields (not the OpenPGP packet header) + * @param src literal data source, initialized with init_literal_src + * @param hdr pointer to header structure, where result will be stored + * @return true on success or false otherwise + */ +bool get_literal_src_hdr(pgp_source_t *src, pgp_literal_hdr_t *hdr); + +/* @brief Get the AEAD-encrypted packet information fields (not the OpenPGP packet header) + * @param src AEAD-encrypted data source (starting from packet data itself, not the header) + * @param hdr pointer to header structure, where result will be stored + * @return true on success or false otherwise + */ +bool get_aead_src_hdr(pgp_source_t *src, pgp_aead_hdr_t *hdr); + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-sig.cpp b/comm/third_party/rnp/src/librepgp/stream-sig.cpp new file mode 100644 index 0000000000..6f3bc81fe1 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-sig.cpp @@ -0,0 +1,1557 @@ +/* + * Copyright (c) 2018-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#ifdef HAVE_UNISTD_H +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include +#include +#include "types.h" +#include "stream-sig.h" +#include "stream-packet.h" +#include "stream-armor.h" +#include "pgp-key.h" +#include "crypto/signatures.h" + +#include + +void +signature_hash_key(const pgp_key_pkt_t &key, rnp::Hash &hash) +{ + uint8_t hdr[3] = {0x99, 0x00, 0x00}; + if (key.hashed_data) { + write_uint16(hdr + 1, key.hashed_len); + hash.add(hdr, 3); + hash.add(key.hashed_data, key.hashed_len); + return; + } + + /* call self recursively if hashed data is not filled, to overcome const restriction */ + pgp_key_pkt_t keycp(key, true); + keycp.fill_hashed_data(); + signature_hash_key(keycp, hash); +} + +void +signature_hash_userid(const pgp_userid_pkt_t &uid, rnp::Hash &hash, pgp_version_t sigver) +{ + if (sigver < PGP_V4) { + hash.add(uid.uid, uid.uid_len); + return; + } + + uint8_t hdr[5] = {0}; + switch (uid.tag) { + case PGP_PKT_USER_ID: + hdr[0] = 0xB4; + break; + case PGP_PKT_USER_ATTR: + hdr[0] = 0xD1; + break; + default: + RNP_LOG("wrong uid"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + STORE32BE(hdr + 1, uid.uid_len); + hash.add(hdr, 5); + hash.add(uid.uid, uid.uid_len); +} + +std::unique_ptr +signature_hash_certification(const pgp_signature_t & sig, + const pgp_key_pkt_t & key, + const pgp_userid_pkt_t &userid) +{ + auto hash = signature_init(key.material, sig.halg); + signature_hash_key(key, *hash); + signature_hash_userid(userid, *hash, sig.version); + return hash; +} + +std::unique_ptr +signature_hash_binding(const pgp_signature_t &sig, + const pgp_key_pkt_t & key, + const pgp_key_pkt_t & subkey) +{ + auto hash = signature_init(key.material, sig.halg); + signature_hash_key(key, *hash); + signature_hash_key(subkey, *hash); + return hash; +} + +std::unique_ptr +signature_hash_direct(const pgp_signature_t &sig, const pgp_key_pkt_t &key) +{ + auto hash = signature_init(key.material, sig.halg); + signature_hash_key(key, *hash); + return hash; +} + +rnp_result_t +process_pgp_signatures(pgp_source_t &src, pgp_signature_list_t &sigs) +{ + sigs.clear(); + /* Allow binary or armored input, including multiple armored messages */ + rnp::ArmoredSource armor( + src, rnp::ArmoredSource::AllowBinary | rnp::ArmoredSource::AllowMultiple); + /* read sequence of OpenPGP signatures */ + while (!armor.error()) { + if (armor.eof() && armor.multiple()) { + armor.restart(); + } + if (armor.eof()) { + break; + } + int ptag = stream_pkt_type(armor.src()); + if (ptag != PGP_PKT_SIGNATURE) { + RNP_LOG("wrong signature tag: %d", ptag); + sigs.clear(); + return RNP_ERROR_BAD_FORMAT; + } + + sigs.emplace_back(); + rnp_result_t ret = sigs.back().parse(armor.src()); + if (ret) { + sigs.clear(); + return ret; + } + } + if (armor.error()) { + sigs.clear(); + return RNP_ERROR_READ; + } + return RNP_SUCCESS; +} + +pgp_sig_subpkt_t::pgp_sig_subpkt_t(const pgp_sig_subpkt_t &src) +{ + type = src.type; + len = src.len; + data = (uint8_t *) malloc(len); + if (!data) { + throw std::bad_alloc(); + } + memcpy(data, src.data, len); + critical = src.critical; + hashed = src.hashed; + parsed = false; + parse(); +} + +pgp_sig_subpkt_t::pgp_sig_subpkt_t(pgp_sig_subpkt_t &&src) +{ + type = src.type; + len = src.len; + data = src.data; + src.data = NULL; + critical = src.critical; + hashed = src.hashed; + parsed = src.parsed; + memcpy(&fields, &src.fields, sizeof(fields)); + src.fields = {}; +} + +pgp_sig_subpkt_t & +pgp_sig_subpkt_t::operator=(pgp_sig_subpkt_t &&src) +{ + if (&src == this) { + return *this; + } + + if (parsed && (type == PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE)) { + delete fields.sig; + } + type = src.type; + len = src.len; + free(data); + data = src.data; + src.data = NULL; + critical = src.critical; + hashed = src.hashed; + parsed = src.parsed; + fields = src.fields; + src.fields = {}; + return *this; +} + +pgp_sig_subpkt_t & +pgp_sig_subpkt_t::operator=(const pgp_sig_subpkt_t &src) +{ + if (&src == this) { + return *this; + } + + if (parsed && (type == PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE)) { + delete fields.sig; + } + type = src.type; + len = src.len; + free(data); + data = (uint8_t *) malloc(len); + if (!data) { + throw std::bad_alloc(); + } + memcpy(data, src.data, len); + critical = src.critical; + hashed = src.hashed; + parsed = false; + fields = {}; + parse(); + return *this; +} + +bool +pgp_sig_subpkt_t::parse() +{ + bool oklen = true; + bool checked = true; + + switch (type) { + case PGP_SIG_SUBPKT_CREATION_TIME: + if (!hashed) { + RNP_LOG("creation time subpacket must be hashed"); + checked = false; + } + if ((oklen = len == 4)) { + fields.create = read_uint32(data); + } + break; + case PGP_SIG_SUBPKT_EXPIRATION_TIME: + case PGP_SIG_SUBPKT_KEY_EXPIRY: + if ((oklen = len == 4)) { + fields.expiry = read_uint32(data); + } + break; + case PGP_SIG_SUBPKT_EXPORT_CERT: + if ((oklen = len == 1)) { + fields.exportable = data[0] != 0; + } + break; + case PGP_SIG_SUBPKT_TRUST: + if ((oklen = len == 2)) { + fields.trust.level = data[0]; + fields.trust.amount = data[1]; + } + break; + case PGP_SIG_SUBPKT_REGEXP: + fields.regexp.str = (const char *) data; + fields.regexp.len = len; + break; + case PGP_SIG_SUBPKT_REVOCABLE: + if ((oklen = len == 1)) { + fields.revocable = data[0] != 0; + } + break; + case PGP_SIG_SUBPKT_PREFERRED_SKA: + case PGP_SIG_SUBPKT_PREFERRED_HASH: + case PGP_SIG_SUBPKT_PREF_COMPRESS: + case PGP_SIG_SUBPKT_PREFERRED_AEAD: + fields.preferred.arr = data; + fields.preferred.len = len; + break; + case PGP_SIG_SUBPKT_REVOCATION_KEY: + if ((oklen = len == 22)) { + fields.revocation_key.klass = data[0]; + fields.revocation_key.pkalg = (pgp_pubkey_alg_t) data[1]; + fields.revocation_key.fp = &data[2]; + } + break; + case PGP_SIG_SUBPKT_ISSUER_KEY_ID: + if ((oklen = len == 8)) { + fields.issuer = data; + } + break; + case PGP_SIG_SUBPKT_NOTATION_DATA: + if ((oklen = len >= 8)) { + memcpy(fields.notation.flags, data, 4); + fields.notation.human = fields.notation.flags[0] & 0x80; + fields.notation.nlen = read_uint16(&data[4]); + fields.notation.vlen = read_uint16(&data[6]); + if (len != 8 + fields.notation.nlen + fields.notation.vlen) { + oklen = false; + } else { + fields.notation.name = data + 8; + fields.notation.value = fields.notation.name + fields.notation.nlen; + } + } + break; + case PGP_SIG_SUBPKT_KEYSERV_PREFS: + if ((oklen = len >= 1)) { + fields.ks_prefs.no_modify = (data[0] & 0x80) != 0; + } + break; + case PGP_SIG_SUBPKT_PREF_KEYSERV: + fields.preferred_ks.uri = (const char *) data; + fields.preferred_ks.len = len; + break; + case PGP_SIG_SUBPKT_PRIMARY_USER_ID: + if ((oklen = len == 1)) { + fields.primary_uid = data[0] != 0; + } + break; + case PGP_SIG_SUBPKT_POLICY_URI: + fields.policy.uri = (const char *) data; + fields.policy.len = len; + break; + case PGP_SIG_SUBPKT_KEY_FLAGS: + if ((oklen = len >= 1)) { + fields.key_flags = data[0]; + } + break; + case PGP_SIG_SUBPKT_SIGNERS_USER_ID: + fields.signer.uid = (const char *) data; + fields.signer.len = len; + break; + case PGP_SIG_SUBPKT_REVOCATION_REASON: + if ((oklen = len >= 1)) { + fields.revocation_reason.code = (pgp_revocation_type_t) data[0]; + fields.revocation_reason.str = (const char *) &data[1]; + fields.revocation_reason.len = len - 1; + } + break; + case PGP_SIG_SUBPKT_FEATURES: + if ((oklen = len >= 1)) { + fields.features = data[0]; + } + break; + case PGP_SIG_SUBPKT_SIGNATURE_TARGET: + if ((oklen = len >= 18)) { + fields.sig_target.pkalg = (pgp_pubkey_alg_t) data[0]; + fields.sig_target.halg = (pgp_hash_alg_t) data[1]; + fields.sig_target.hash = &data[2]; + fields.sig_target.hlen = len - 2; + } + break; + case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE: + try { + /* parse signature */ + pgp_packet_body_t pkt(data, len); + pgp_signature_t sig; + oklen = checked = !sig.parse(pkt); + if (checked) { + fields.sig = new pgp_signature_t(std::move(sig)); + } + break; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return false; + } + case PGP_SIG_SUBPKT_ISSUER_FPR: + if ((oklen = len >= 21)) { + fields.issuer_fp.version = data[0]; + fields.issuer_fp.fp = &data[1]; + fields.issuer_fp.len = len - 1; + } + break; + case PGP_SIG_SUBPKT_PRIVATE_100: + case PGP_SIG_SUBPKT_PRIVATE_101: + case PGP_SIG_SUBPKT_PRIVATE_102: + case PGP_SIG_SUBPKT_PRIVATE_103: + case PGP_SIG_SUBPKT_PRIVATE_104: + case PGP_SIG_SUBPKT_PRIVATE_105: + case PGP_SIG_SUBPKT_PRIVATE_106: + case PGP_SIG_SUBPKT_PRIVATE_107: + case PGP_SIG_SUBPKT_PRIVATE_108: + case PGP_SIG_SUBPKT_PRIVATE_109: + case PGP_SIG_SUBPKT_PRIVATE_110: + oklen = true; + checked = !critical; + if (!checked) { + RNP_LOG("unknown critical private subpacket %d", (int) type); + } + break; + case PGP_SIG_SUBPKT_RESERVED_1: + case PGP_SIG_SUBPKT_RESERVED_8: + case PGP_SIG_SUBPKT_PLACEHOLDER: + case PGP_SIG_SUBPKT_RESERVED_13: + case PGP_SIG_SUBPKT_RESERVED_14: + case PGP_SIG_SUBPKT_RESERVED_15: + case PGP_SIG_SUBPKT_RESERVED_17: + case PGP_SIG_SUBPKT_RESERVED_18: + case PGP_SIG_SUBPKT_RESERVED_19: + /* do not report reserved/placeholder subpacket */ + return !critical; + default: + RNP_LOG("unknown subpacket : %d", (int) type); + return !critical; + } + + if (!oklen) { + RNP_LOG("wrong len %d of subpacket type %d", (int) len, (int) type); + } else { + parsed = 1; + } + return oklen && checked; +} + +pgp_sig_subpkt_t::~pgp_sig_subpkt_t() +{ + if (parsed && (type == PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE)) { + delete fields.sig; + } + free(data); +} + +pgp_signature_t::pgp_signature_t(const pgp_signature_t &src) +{ + version = src.version; + type_ = src.type_; + palg = src.palg; + halg = src.halg; + memcpy(lbits, src.lbits, sizeof(src.lbits)); + creation_time = src.creation_time; + signer = src.signer; + + hashed_len = src.hashed_len; + hashed_data = NULL; + if (src.hashed_data) { + if (!(hashed_data = (uint8_t *) malloc(hashed_len))) { + throw std::bad_alloc(); + } + memcpy(hashed_data, src.hashed_data, hashed_len); + } + material_len = src.material_len; + material_buf = NULL; + if (src.material_buf) { + if (!(material_buf = (uint8_t *) malloc(material_len))) { + throw std::bad_alloc(); + } + memcpy(material_buf, src.material_buf, material_len); + } + subpkts = src.subpkts; +} + +pgp_signature_t::pgp_signature_t(pgp_signature_t &&src) +{ + version = src.version; + type_ = src.type_; + palg = src.palg; + halg = src.halg; + memcpy(lbits, src.lbits, sizeof(src.lbits)); + creation_time = src.creation_time; + signer = src.signer; + hashed_len = src.hashed_len; + hashed_data = src.hashed_data; + src.hashed_data = NULL; + material_len = src.material_len; + material_buf = src.material_buf; + src.material_buf = NULL; + subpkts = std::move(src.subpkts); +} + +pgp_signature_t & +pgp_signature_t::operator=(pgp_signature_t &&src) +{ + if (this == &src) { + return *this; + } + + version = src.version; + type_ = src.type_; + palg = src.palg; + halg = src.halg; + memcpy(lbits, src.lbits, sizeof(src.lbits)); + creation_time = src.creation_time; + signer = src.signer; + hashed_len = src.hashed_len; + free(hashed_data); + hashed_data = src.hashed_data; + src.hashed_data = NULL; + material_len = src.material_len; + free(material_buf); + material_buf = src.material_buf; + src.material_buf = NULL; + subpkts = std::move(src.subpkts); + + return *this; +} + +pgp_signature_t & +pgp_signature_t::operator=(const pgp_signature_t &src) +{ + if (this == &src) { + return *this; + } + + version = src.version; + type_ = src.type_; + palg = src.palg; + halg = src.halg; + memcpy(lbits, src.lbits, sizeof(src.lbits)); + creation_time = src.creation_time; + signer = src.signer; + + hashed_len = src.hashed_len; + free(hashed_data); + hashed_data = NULL; + if (src.hashed_data) { + if (!(hashed_data = (uint8_t *) malloc(hashed_len))) { + throw std::bad_alloc(); + } + memcpy(hashed_data, src.hashed_data, hashed_len); + } + material_len = src.material_len; + free(material_buf); + material_buf = NULL; + if (src.material_buf) { + if (!(material_buf = (uint8_t *) malloc(material_len))) { + throw std::bad_alloc(); + } + memcpy(material_buf, src.material_buf, material_len); + } + subpkts = src.subpkts; + + return *this; +} + +bool +pgp_signature_t::operator==(const pgp_signature_t &src) const +{ + if ((lbits[0] != src.lbits[0]) || (lbits[1] != src.lbits[1])) { + return false; + } + if ((hashed_len != src.hashed_len) || memcmp(hashed_data, src.hashed_data, hashed_len)) { + return false; + } + return (material_len == src.material_len) && + !memcmp(material_buf, src.material_buf, material_len); +} + +bool +pgp_signature_t::operator!=(const pgp_signature_t &src) const +{ + return !(*this == src); +} + +pgp_signature_t::~pgp_signature_t() +{ + free(hashed_data); + free(material_buf); +} + +pgp_sig_id_t +pgp_signature_t::get_id() const +{ + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + hash->add(hashed_data, hashed_len); + hash->add(material_buf, material_len); + pgp_sig_id_t res = {0}; + static_assert(std::tuple_size::value == PGP_SHA1_HASH_SIZE, + "pgp_sig_id_t size mismatch"); + hash->finish(res.data()); + return res; +} + +pgp_sig_subpkt_t * +pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) +{ + if (version < PGP_V4) { + return NULL; + } + for (auto &subpkt : subpkts) { + /* if hashed is false then accept any hashed/not hashed subpacket */ + if ((subpkt.type == stype) && (!hashed || subpkt.hashed)) { + return &subpkt; + } + } + return NULL; +} + +const pgp_sig_subpkt_t * +pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) const +{ + if (version < PGP_V4) { + return NULL; + } + for (auto &subpkt : subpkts) { + /* if hashed is false then accept any hashed/not hashed subpacket */ + if ((subpkt.type == stype) && (!hashed || subpkt.hashed)) { + return &subpkt; + } + } + return NULL; +} + +bool +pgp_signature_t::has_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) const +{ + if (version < PGP_V4) { + return false; + } + for (auto &subpkt : subpkts) { + /* if hashed is false then accept any hashed/not hashed subpacket */ + if ((subpkt.type == stype) && (!hashed || subpkt.hashed)) { + return true; + } + } + return false; +} + +bool +pgp_signature_t::has_keyid() const +{ + return (version < PGP_V4) || has_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false) || + has_keyfp(); +} + +pgp_key_id_t +pgp_signature_t::keyid() const noexcept +{ + /* version 3 uses signature field */ + if (version < PGP_V4) { + return signer; + } + + /* version 4 and up use subpackets */ + pgp_key_id_t res{}; + static_assert(std::tuple_size::value == PGP_KEY_ID_SIZE, + "pgp_key_id_t size mismatch"); + + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false); + if (subpkt) { + memcpy(res.data(), subpkt->fields.issuer, PGP_KEY_ID_SIZE); + return res; + } + if ((subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR))) { + memcpy(res.data(), + subpkt->fields.issuer_fp.fp + subpkt->fields.issuer_fp.len - PGP_KEY_ID_SIZE, + PGP_KEY_ID_SIZE); + return res; + } + return res; +} + +void +pgp_signature_t::set_keyid(const pgp_key_id_t &id) +{ + if (version < PGP_V4) { + signer = id; + return; + } + + static_assert(std::tuple_size::type>::value == + PGP_KEY_ID_SIZE, + "pgp_key_id_t size mismatch"); + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, PGP_KEY_ID_SIZE, true); + subpkt.parsed = true; + subpkt.hashed = false; + memcpy(subpkt.data, id.data(), PGP_KEY_ID_SIZE); + subpkt.fields.issuer = subpkt.data; +} + +bool +pgp_signature_t::has_keyfp() const +{ + if (version < PGP_V4) { + return false; + } + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR); + return subpkt && (subpkt->fields.issuer_fp.len <= PGP_FINGERPRINT_SIZE); +} + +pgp_fingerprint_t +pgp_signature_t::keyfp() const noexcept +{ + pgp_fingerprint_t res{}; + if (version < PGP_V4) { + return res; + } + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR); + if (!subpkt || (subpkt->fields.issuer_fp.len > sizeof(res.fingerprint))) { + return res; + } + res.length = subpkt->fields.issuer_fp.len; + memcpy(res.fingerprint, subpkt->fields.issuer_fp.fp, subpkt->fields.issuer_fp.len); + return res; +} + +void +pgp_signature_t::set_keyfp(const pgp_fingerprint_t &fp) +{ + if (version < PGP_V4) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, 1 + fp.length, true); + subpkt.parsed = true; + subpkt.hashed = true; + subpkt.data[0] = 4; + memcpy(subpkt.data + 1, fp.fingerprint, fp.length); + subpkt.fields.issuer_fp.len = fp.length; + subpkt.fields.issuer_fp.version = subpkt.data[0]; + subpkt.fields.issuer_fp.fp = subpkt.data + 1; +} + +uint32_t +pgp_signature_t::creation() const +{ + if (version < PGP_V4) { + return creation_time; + } + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_CREATION_TIME); + return subpkt ? subpkt->fields.create : 0; +} + +void +pgp_signature_t::set_creation(uint32_t ctime) +{ + if (version < PGP_V4) { + creation_time = ctime; + return; + } + + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_CREATION_TIME, 4, true); + subpkt.parsed = true; + subpkt.hashed = true; + STORE32BE(subpkt.data, ctime); + subpkt.fields.create = ctime; +} + +uint32_t +pgp_signature_t::expiration() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_EXPIRATION_TIME); + return subpkt ? subpkt->fields.expiry : 0; +} + +void +pgp_signature_t::set_expiration(uint32_t etime) +{ + if (version < PGP_V4) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_EXPIRATION_TIME, 4, true); + subpkt.parsed = true; + subpkt.hashed = true; + STORE32BE(subpkt.data, etime); + subpkt.fields.expiry = etime; +} + +uint32_t +pgp_signature_t::key_expiration() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY); + return subpkt ? subpkt->fields.expiry : 0; +} + +void +pgp_signature_t::set_key_expiration(uint32_t etime) +{ + if (version < PGP_V4) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY, 4, true); + subpkt.parsed = true; + subpkt.hashed = true; + STORE32BE(subpkt.data, etime); + subpkt.fields.expiry = etime; +} + +uint8_t +pgp_signature_t::key_flags() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS); + return subpkt ? subpkt->fields.key_flags : 0; +} + +void +pgp_signature_t::set_key_flags(uint8_t flags) +{ + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS, 1, true); + subpkt.parsed = true; + subpkt.hashed = true; + subpkt.data[0] = flags; + subpkt.fields.key_flags = flags; +} + +bool +pgp_signature_t::primary_uid() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_PRIMARY_USER_ID); + return subpkt ? subpkt->fields.primary_uid : false; +} + +void +pgp_signature_t::set_primary_uid(bool primary) +{ + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_PRIMARY_USER_ID, 1, true); + subpkt.parsed = true; + subpkt.hashed = true; + subpkt.data[0] = primary; + subpkt.fields.primary_uid = primary; +} + +std::vector +pgp_signature_t::preferred(pgp_sig_subpacket_type_t type) const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(type); + return subpkt ? std::vector(subpkt->fields.preferred.arr, + subpkt->fields.preferred.arr + + subpkt->fields.preferred.len) : + std::vector(); +} + +void +pgp_signature_t::set_preferred(const std::vector &data, pgp_sig_subpacket_type_t type) +{ + if (version < PGP_V4) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + if (data.empty()) { + pgp_sig_subpkt_t *subpkt = get_subpkt(type); + if (subpkt) { + remove_subpkt(subpkt); + } + return; + } + + pgp_sig_subpkt_t &subpkt = add_subpkt(type, data.size(), true); + subpkt.parsed = true; + subpkt.hashed = true; + memcpy(subpkt.data, data.data(), data.size()); + subpkt.fields.preferred.arr = subpkt.data; + subpkt.fields.preferred.len = data.size(); +} + +std::vector +pgp_signature_t::preferred_symm_algs() const +{ + return preferred(PGP_SIG_SUBPKT_PREFERRED_SKA); +} + +void +pgp_signature_t::set_preferred_symm_algs(const std::vector &algs) +{ + set_preferred(algs, PGP_SIG_SUBPKT_PREFERRED_SKA); +} + +std::vector +pgp_signature_t::preferred_hash_algs() const +{ + return preferred(PGP_SIG_SUBPKT_PREFERRED_HASH); +} + +void +pgp_signature_t::set_preferred_hash_algs(const std::vector &algs) +{ + set_preferred(algs, PGP_SIG_SUBPKT_PREFERRED_HASH); +} + +std::vector +pgp_signature_t::preferred_z_algs() const +{ + return preferred(PGP_SIG_SUBPKT_PREF_COMPRESS); +} + +void +pgp_signature_t::set_preferred_z_algs(const std::vector &algs) +{ + set_preferred(algs, PGP_SIG_SUBPKT_PREF_COMPRESS); +} + +uint8_t +pgp_signature_t::key_server_prefs() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS); + return subpkt ? subpkt->data[0] : 0; +} + +void +pgp_signature_t::set_key_server_prefs(uint8_t prefs) +{ + if (version < PGP_V4) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS, 1, true); + subpkt.parsed = true; + subpkt.hashed = true; + subpkt.data[0] = prefs; + subpkt.fields.ks_prefs.no_modify = prefs & 0x80; +} + +std::string +pgp_signature_t::key_server() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV); + return subpkt ? std::string((char *) subpkt->data, subpkt->len) : ""; +} + +void +pgp_signature_t::set_key_server(const std::string &uri) +{ + if (version < PGP_V4) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + if (uri.empty()) { + pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV); + if (subpkt) { + remove_subpkt(subpkt); + } + return; + } + + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV, uri.size(), true); + subpkt.parsed = true; + subpkt.hashed = true; + memcpy(subpkt.data, uri.data(), uri.size()); + subpkt.fields.preferred_ks.uri = (char *) subpkt.data; + subpkt.fields.preferred_ks.len = uri.size(); +} + +uint8_t +pgp_signature_t::trust_level() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_TRUST); + return subpkt ? subpkt->fields.trust.level : 0; +} + +uint8_t +pgp_signature_t::trust_amount() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_TRUST); + return subpkt ? subpkt->fields.trust.amount : 0; +} + +void +pgp_signature_t::set_trust(uint8_t level, uint8_t amount) +{ + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_TRUST, 2, true); + subpkt.parsed = true; + subpkt.hashed = true; + subpkt.data[0] = level; + subpkt.data[1] = amount; + subpkt.fields.trust.level = level; + subpkt.fields.trust.amount = amount; +} + +bool +pgp_signature_t::revocable() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_REVOCABLE); + return subpkt ? subpkt->fields.revocable : true; +} + +void +pgp_signature_t::set_revocable(bool status) +{ + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_REVOCABLE, 1, true); + subpkt.parsed = true; + subpkt.hashed = true; + subpkt.data[0] = status; + subpkt.fields.revocable = status; +} + +std::string +pgp_signature_t::revocation_reason() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON); + return subpkt ? std::string(subpkt->fields.revocation_reason.str, + subpkt->fields.revocation_reason.len) : + ""; +} + +pgp_revocation_type_t +pgp_signature_t::revocation_code() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON); + return subpkt ? subpkt->fields.revocation_reason.code : PGP_REVOCATION_NO_REASON; +} + +void +pgp_signature_t::set_revocation_reason(pgp_revocation_type_t code, const std::string &reason) +{ + size_t datalen = 1 + reason.size(); + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON, datalen, true); + subpkt.hashed = true; + subpkt.data[0] = code; + memcpy(subpkt.data + 1, reason.data(), reason.size()); + + if (!subpkt.parse()) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } +} + +bool +pgp_signature_t::key_has_features(pgp_key_feature_t flags) const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_FEATURES); + return subpkt ? subpkt->data[0] & flags : false; +} + +void +pgp_signature_t::set_key_features(pgp_key_feature_t flags) +{ + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_FEATURES, 1, true); + subpkt.hashed = true; + subpkt.data[0] = flags; + subpkt.fields.features = flags; + subpkt.parsed = true; +} + +std::string +pgp_signature_t::signer_uid() const +{ + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_SIGNERS_USER_ID); + return subpkt ? std::string(subpkt->fields.signer.uid, subpkt->fields.signer.len) : ""; +} + +void +pgp_signature_t::set_signer_uid(const std::string &uid) +{ + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_SIGNERS_USER_ID, uid.size(), true); + subpkt.hashed = true; + memcpy(subpkt.data, uid.data(), uid.size()); + subpkt.fields.signer.uid = (const char *) subpkt.data; + subpkt.fields.signer.len = subpkt.len; + subpkt.parsed = true; +} + +void +pgp_signature_t::add_notation(const std::string & name, + const std::vector &value, + bool human, + bool critical) +{ + auto nlen = name.size(); + auto vlen = value.size(); + if ((nlen > 0xffff) || (vlen > 0xffff)) { + RNP_LOG("wrong length"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + auto &subpkt = add_subpkt(PGP_SIG_SUBPKT_NOTATION_DATA, 8 + nlen + vlen, false); + subpkt.hashed = true; + subpkt.critical = critical; + if (human) { + subpkt.data[0] = 0x80; + } + write_uint16(subpkt.data + 4, nlen); + write_uint16(subpkt.data + 6, vlen); + memcpy(subpkt.data + 8, name.data(), nlen); + memcpy(subpkt.data + 8 + nlen, value.data(), vlen); + if (!subpkt.parse()) { + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } +} + +void +pgp_signature_t::add_notation(const std::string &name, const std::string &value, bool critical) +{ + add_notation(name, std::vector(value.begin(), value.end()), true, critical); +} + +void +pgp_signature_t::set_embedded_sig(const pgp_signature_t &esig) +{ + pgp_rawpacket_t esigpkt(esig); + rnp::MemorySource mem(esigpkt.raw); + size_t len = 0; + stream_read_pkt_len(&mem.src(), &len); + if (!len || (len > 0xffff) || (len >= esigpkt.raw.size())) { + RNP_LOG("wrong pkt len"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE, len, true); + subpkt.hashed = false; + size_t skip = esigpkt.raw.size() - len; + memcpy(subpkt.data, esigpkt.raw.data() + skip, len); + subpkt.fields.sig = new pgp_signature_t(esig); + subpkt.parsed = true; +} + +pgp_sig_subpkt_t & +pgp_signature_t::add_subpkt(pgp_sig_subpacket_type_t type, size_t datalen, bool reuse) +{ + if (version < PGP_V4) { + RNP_LOG("wrong signature version"); + throw std::invalid_argument("version"); + } + + uint8_t *newdata = (uint8_t *) calloc(1, datalen); + if (!newdata) { + RNP_LOG("Allocation failed"); + throw std::bad_alloc(); + } + + pgp_sig_subpkt_t *subpkt = NULL; + if (reuse && (subpkt = get_subpkt(type))) { + *subpkt = {}; + } else { + subpkts.push_back({}); + subpkt = &subpkts.back(); + } + + subpkt->data = newdata; + subpkt->type = type; + subpkt->len = datalen; + return *subpkt; +} + +void +pgp_signature_t::remove_subpkt(pgp_sig_subpkt_t *subpkt) +{ + for (auto it = subpkts.begin(); it < subpkts.end(); it++) { + if (&*it == subpkt) { + subpkts.erase(it); + return; + } + } +} + +bool +pgp_signature_t::matches_onepass(const pgp_one_pass_sig_t &onepass) const +{ + if (!has_keyid()) { + return false; + } + return (halg == onepass.halg) && (palg == onepass.palg) && (type_ == onepass.type) && + (onepass.keyid == keyid()); +} + +rnp_result_t +pgp_signature_t::parse_v3(pgp_packet_body_t &pkt) +{ + /* parse v3-specific fields, not the whole signature */ + uint8_t buf[16] = {}; + if (!pkt.get(buf, 16)) { + RNP_LOG("cannot get enough bytes"); + return RNP_ERROR_BAD_FORMAT; + } + /* length of hashed data, 5 */ + if (buf[0] != 5) { + RNP_LOG("wrong length of hashed data"); + return RNP_ERROR_BAD_FORMAT; + } + /* hashed data */ + free(hashed_data); + if (!(hashed_data = (uint8_t *) malloc(5))) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + memcpy(hashed_data, &buf[1], 5); + hashed_len = 5; + /* signature type */ + type_ = (pgp_sig_type_t) buf[1]; + /* creation time */ + creation_time = read_uint32(&buf[2]); + /* signer's key id */ + static_assert(std::tuple_size::value == PGP_KEY_ID_SIZE, + "v3 signer field size mismatch"); + memcpy(signer.data(), &buf[6], PGP_KEY_ID_SIZE); + /* public key algorithm */ + palg = (pgp_pubkey_alg_t) buf[14]; + /* hash algorithm */ + halg = (pgp_hash_alg_t) buf[15]; + return RNP_SUCCESS; +} + +#define MAX_SUBPACKETS 64 + +bool +pgp_signature_t::parse_subpackets(uint8_t *buf, size_t len, bool hashed) +{ + bool res = true; + + while (len > 0) { + if (subpkts.size() >= MAX_SUBPACKETS) { + RNP_LOG("too many signature subpackets"); + return false; + } + if (len < 2) { + RNP_LOG("got single byte %d", (int) *buf); + return false; + } + + /* subpacket length */ + size_t splen; + if (*buf < 192) { + splen = *buf; + buf++; + len--; + } else if (*buf < 255) { + splen = ((buf[0] - 192) << 8) + buf[1] + 192; + buf += 2; + len -= 2; + } else { + if (len < 5) { + RNP_LOG("got 4-byte len but only %d bytes in buffer", (int) len); + return false; + } + splen = read_uint32(&buf[1]); + buf += 5; + len -= 5; + } + + if (splen < 1) { + RNP_LOG("got subpacket with 0 length"); + return false; + } + + /* subpacket data */ + if (len < splen) { + RNP_LOG("got subpacket len %d, while only %d bytes left", (int) splen, (int) len); + return false; + } + + pgp_sig_subpkt_t subpkt; + if (!(subpkt.data = (uint8_t *) malloc(splen - 1))) { + RNP_LOG("subpacket data allocation failed"); + return false; + } + + subpkt.type = (pgp_sig_subpacket_type_t)(*buf & 0x7f); + subpkt.critical = !!(*buf & 0x80); + subpkt.hashed = hashed; + subpkt.parsed = 0; + memcpy(subpkt.data, buf + 1, splen - 1); + subpkt.len = splen - 1; + + res = res && subpkt.parse(); + subpkts.push_back(std::move(subpkt)); + len -= splen; + buf += splen; + } + return res; +} + +rnp_result_t +pgp_signature_t::parse_v4(pgp_packet_body_t &pkt) +{ + /* parse v4-specific fields, not the whole signature */ + uint8_t buf[5]; + if (!pkt.get(buf, 5)) { + RNP_LOG("cannot get first 5 bytes"); + return RNP_ERROR_BAD_FORMAT; + } + + /* signature type */ + type_ = (pgp_sig_type_t) buf[0]; + /* public key algorithm */ + palg = (pgp_pubkey_alg_t) buf[1]; + /* hash algorithm */ + halg = (pgp_hash_alg_t) buf[2]; + /* hashed subpackets length */ + uint16_t splen = read_uint16(&buf[3]); + /* hashed subpackets length + 2 bytes of length of unhashed subpackets */ + if (pkt.left() < (size_t)(splen + 2)) { + RNP_LOG("wrong packet or hashed subpackets length"); + return RNP_ERROR_BAD_FORMAT; + } + /* building hashed data */ + free(hashed_data); + if (!(hashed_data = (uint8_t *) malloc(splen + 6))) { + RNP_LOG("allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + hashed_data[0] = version; + memcpy(hashed_data + 1, buf, 5); + + if (!pkt.get(hashed_data + 6, splen)) { + RNP_LOG("cannot get hashed subpackets data"); + return RNP_ERROR_BAD_FORMAT; + } + hashed_len = splen + 6; + /* parsing hashed subpackets */ + if (!parse_subpackets(hashed_data + 6, splen, true)) { + RNP_LOG("failed to parse hashed subpackets"); + return RNP_ERROR_BAD_FORMAT; + } + /* reading unhashed subpackets */ + if (!pkt.get(splen)) { + RNP_LOG("cannot get unhashed len"); + return RNP_ERROR_BAD_FORMAT; + } + if (pkt.left() < splen) { + RNP_LOG("not enough data for unhashed subpackets"); + return RNP_ERROR_BAD_FORMAT; + } + std::vector spbuf(splen); + if (!pkt.get(spbuf.data(), splen)) { + RNP_LOG("read of unhashed subpackets failed"); + return RNP_ERROR_READ; + } + if (!parse_subpackets(spbuf.data(), splen, false)) { + RNP_LOG("failed to parse unhashed subpackets"); + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; +} + +rnp_result_t +pgp_signature_t::parse(pgp_packet_body_t &pkt) +{ + uint8_t ver = 0; + if (!pkt.get(ver)) { + return RNP_ERROR_BAD_FORMAT; + } + version = (pgp_version_t) ver; + + /* v3 or v4 signature body */ + rnp_result_t res; + if ((ver == PGP_V2) || (ver == PGP_V3)) { + res = parse_v3(pkt); + } else if (ver == PGP_V4) { + res = parse_v4(pkt); + } else { + RNP_LOG("unknown signature version: %d", (int) ver); + res = RNP_ERROR_BAD_FORMAT; + } + + if (res) { + return res; + } + + /* left 16 bits of the hash */ + if (!pkt.get(lbits, 2)) { + RNP_LOG("not enough data for hash left bits"); + return RNP_ERROR_BAD_FORMAT; + } + /* raw signature material */ + material_len = pkt.left(); + if (!material_len) { + RNP_LOG("No signature material"); + return RNP_ERROR_BAD_FORMAT; + } + material_buf = (uint8_t *) malloc(material_len); + if (!material_buf) { + RNP_LOG("Allocation failed"); + return RNP_ERROR_OUT_OF_MEMORY; + } + /* we cannot fail here */ + pkt.get(material_buf, material_len); + /* check whether it can be parsed */ + pgp_signature_material_t material = {}; + if (!parse_material(material)) { + return RNP_ERROR_BAD_FORMAT; + } + return RNP_SUCCESS; +} + +rnp_result_t +pgp_signature_t::parse(pgp_source_t &src) +{ + pgp_packet_body_t pkt(PGP_PKT_SIGNATURE); + rnp_result_t res = pkt.read(src); + if (res) { + return res; + } + return parse(pkt); +} + +bool +pgp_signature_t::parse_material(pgp_signature_material_t &material) const +{ + pgp_packet_body_t pkt(material_buf, material_len); + + switch (palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_SIGN_ONLY: + if (!pkt.get(material.rsa.s)) { + return false; + } + break; + case PGP_PKA_DSA: + if (!pkt.get(material.dsa.r) || !pkt.get(material.dsa.s)) { + return false; + } + break; + case PGP_PKA_EDDSA: + if (version < PGP_V4) { + RNP_LOG("Warning! v3 EdDSA signature."); + } + [[fallthrough]]; + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + if (!pkt.get(material.ecc.r) || !pkt.get(material.ecc.s)) { + return false; + } + break; + case PGP_PKA_ELGAMAL: /* we support reading it but will not validate */ + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + if (!pkt.get(material.eg.r) || !pkt.get(material.eg.s)) { + return false; + } + break; + default: + RNP_LOG("Unknown pk algorithm : %d", (int) palg); + return false; + } + + if (pkt.left()) { + RNP_LOG("extra %d bytes in signature packet", (int) pkt.left()); + return false; + } + return true; +} + +void +pgp_signature_t::write(pgp_dest_t &dst) const +{ + if ((version < PGP_V2) || (version > PGP_V4)) { + RNP_LOG("don't know version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + pgp_packet_body_t pktbody(PGP_PKT_SIGNATURE); + + if (version < PGP_V4) { + /* for v3 signatures hashed data includes only type + creation_time */ + pktbody.add_byte(version); + pktbody.add_byte(hashed_len); + pktbody.add(hashed_data, hashed_len); + pktbody.add(signer); + pktbody.add_byte(palg); + pktbody.add_byte(halg); + } else { + /* for v4 sig->hashed_data must contain most of signature fields */ + pktbody.add(hashed_data, hashed_len); + pktbody.add_subpackets(*this, false); + } + pktbody.add(lbits, 2); + /* write mpis */ + pktbody.add(material_buf, material_len); + pktbody.write(dst); +} + +void +pgp_signature_t::write_material(const pgp_signature_material_t &material) +{ + pgp_packet_body_t pktbody(PGP_PKT_SIGNATURE); + switch (palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_SIGN_ONLY: + pktbody.add(material.rsa.s); + break; + case PGP_PKA_DSA: + pktbody.add(material.dsa.r); + pktbody.add(material.dsa.s); + break; + case PGP_PKA_EDDSA: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + pktbody.add(material.ecc.r); + pktbody.add(material.ecc.s); + break; + case PGP_PKA_ELGAMAL: /* we support writing it but will not generate */ + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + pktbody.add(material.eg.r); + pktbody.add(material.eg.s); + break; + default: + RNP_LOG("Unknown pk algorithm : %d", (int) palg); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + free(material_buf); + material_buf = (uint8_t *) malloc(pktbody.size()); + if (!material_buf) { + RNP_LOG("allocation failed"); + throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY); + } + memcpy(material_buf, pktbody.data(), pktbody.size()); + material_len = pktbody.size(); +} + +void +pgp_signature_t::fill_hashed_data() +{ + /* we don't have a need to write v2-v3 signatures */ + if ((version < PGP_V2) || (version > PGP_V4)) { + RNP_LOG("don't know version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + pgp_packet_body_t hbody(PGP_PKT_RESERVED); + if (version < PGP_V4) { + hbody.add_byte(type()); + hbody.add_uint32(creation_time); + } else { + hbody.add_byte(version); + hbody.add_byte(type()); + hbody.add_byte(palg); + hbody.add_byte(halg); + hbody.add_subpackets(*this, true); + } + + free(hashed_data); + hashed_data = (uint8_t *) malloc(hbody.size()); + if (!hashed_data) { + RNP_LOG("allocation failed"); + throw std::bad_alloc(); + } + memcpy(hashed_data, hbody.data(), hbody.size()); + hashed_len = hbody.size(); +} + +void +rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) +{ + /* populate signature */ + sig.set_type(PGP_CERT_POSITIVE); + if (key_expiration) { + sig.set_key_expiration(key_expiration); + } + if (key_flags) { + sig.set_key_flags(key_flags); + } + if (primary) { + sig.set_primary_uid(true); + } + if (!prefs.symm_algs.empty()) { + sig.set_preferred_symm_algs(prefs.symm_algs); + } + if (!prefs.hash_algs.empty()) { + sig.set_preferred_hash_algs(prefs.hash_algs); + } + if (!prefs.z_algs.empty()) { + sig.set_preferred_z_algs(prefs.z_algs); + } + if (!prefs.ks_prefs.empty()) { + sig.set_key_server_prefs(prefs.ks_prefs[0]); + } + if (!prefs.key_server.empty()) { + sig.set_key_server(prefs.key_server); + } + /* populate uid */ + uid.tag = PGP_PKT_USER_ID; + uid.uid_len = userid.size(); + if (!(uid.uid = (uint8_t *) malloc(uid.uid_len))) { + RNP_LOG("alloc failed"); + throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY); + } + memcpy(uid.uid, userid.data(), uid.uid_len); +} diff --git a/comm/third_party/rnp/src/librepgp/stream-sig.h b/comm/third_party/rnp/src/librepgp/stream-sig.h new file mode 100644 index 0000000000..4f36c381f1 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-sig.h @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2018-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_SIG_H_ +#define STREAM_SIG_H_ + +#include +#include +#include +#include "rnp.h" +#include "stream-common.h" +#include "stream-packet.h" + +typedef struct pgp_signature_t { + private: + pgp_sig_type_t type_; + std::vector preferred(pgp_sig_subpacket_type_t type) const; + void set_preferred(const std::vector &data, pgp_sig_subpacket_type_t type); + rnp_result_t parse_v3(pgp_packet_body_t &pkt); + rnp_result_t parse_v4(pgp_packet_body_t &pkt); + bool parse_subpackets(uint8_t *buf, size_t len, bool hashed); + + public: + pgp_version_t version; + /* common v3 and v4 fields */ + pgp_pubkey_alg_t palg; + pgp_hash_alg_t halg; + uint8_t lbits[2]; + uint8_t * hashed_data; + size_t hashed_len; + uint8_t * material_buf; /* raw signature material */ + size_t material_len; /* raw signature material length */ + + /* v3 - only fields */ + uint32_t creation_time; + pgp_key_id_t signer; + + /* v4 - only fields */ + std::vector subpkts; + + pgp_signature_t() + : type_(PGP_SIG_BINARY), version(PGP_VUNKNOWN), palg(PGP_PKA_NOTHING), + halg(PGP_HASH_UNKNOWN), hashed_data(NULL), hashed_len(0), material_buf(NULL), + material_len(0), creation_time(0){}; + pgp_signature_t(const pgp_signature_t &src); + pgp_signature_t(pgp_signature_t &&src); + pgp_signature_t &operator=(pgp_signature_t &&src); + pgp_signature_t &operator=(const pgp_signature_t &src); + bool operator==(const pgp_signature_t &src) const; + bool operator!=(const pgp_signature_t &src) const; + ~pgp_signature_t(); + + /* @brief Get signature's type */ + pgp_sig_type_t + type() const + { + return type_; + }; + void + set_type(pgp_sig_type_t atype) + { + type_ = atype; + }; + + bool + is_document() const + { + return (type_ == PGP_SIG_BINARY) || (type_ == PGP_SIG_TEXT); + }; + + /** @brief Calculate the unique signature identifier by hashing signature's fields. */ + pgp_sig_id_t get_id() const; + + /** + * @brief Get v4 signature's subpacket of the specified type and hashedness. + * @param stype subpacket type. + * @param hashed If true (default), then will search for subpacket only in hashed (i.e. + * covered by signature) area, otherwise will search in both hashed and non-hashed areas. + * @return pointer to the subpacket, or NULL if subpacket was not found. + */ + pgp_sig_subpkt_t * get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed = true); + const pgp_sig_subpkt_t *get_subpkt(pgp_sig_subpacket_type_t stype, + bool hashed = true) const; + /* @brief Check whether v4 signature has subpacket of the specified type/hashedness */ + bool has_subpkt(pgp_sig_subpacket_type_t stype, bool hashed = true) const; + /* @brief Check whether signature has signing key id (via v3 field, or v4 key id/key fp + * subpacket) */ + bool has_keyid() const; + /** + * @brief Get signer's key id if available. Availability may be checked via has_keyid(). + * @return signer's key id if available, or empty (zero-filled) keyid otherwise. + */ + pgp_key_id_t keyid() const noexcept; + /** @brief Set the signer's key id for the signature being populated. Version should be set + * prior of setting key id. */ + void set_keyid(const pgp_key_id_t &id); + /** + * @brief Check whether signature has valid issuer fingerprint subpacket. + * @return true if there is one, and it can be safely returned via keyfp() method or false + * otherwise. + */ + bool has_keyfp() const; + /** + * @brief Get signing key's fingerprint if it is available. Availability may be checked via + * has_keyfp() method. + * @return fingerprint (or empty zero-size fp in case it is unavailable) + */ + pgp_fingerprint_t keyfp() const noexcept; + + /** @brief Set signing key's fingerprint. Works only for signatures with version 4 and up, + * so version should be set prior to fingerprint. */ + void set_keyfp(const pgp_fingerprint_t &fp); + + /** + * @brief Get signature's creation time + * @return time in seconds since the Jan 1, 1970 UTC. 0 is the default value and returned + * even if creation time is not available + */ + uint32_t creation() const; + + /** + * @brief Set signature's creation time + * @param ctime creation time in seconds since the Jan 1, 1970 UTC. + */ + void set_creation(uint32_t ctime); + + /** + * @brief Get the signature's expiration time + * @return expiration time in seconds since the creation time. 0 if signature never + * expires. + */ + uint32_t expiration() const; + + /** + * @brief Set the signature's expiration time + * @param etime expiration time + */ + void set_expiration(uint32_t etime); + + /** + * @brief Get the key expiration time + * @return expiration time in seconds since the creation time. 0 if key never expires. + */ + uint32_t key_expiration() const; + + /** + * @brief Set the key expiration time + * @param etime expiration time + */ + void set_key_expiration(uint32_t etime); + + /** + * @brief Get the key flags + * @return byte of key flags. If there is no corresponding subpackets then 0 is returned. + */ + uint8_t key_flags() const; + + /** + * @brief Set the key flags + * @param flags byte of key flags + */ + void set_key_flags(uint8_t flags); + + /** + * @brief Get the primary user id flag + * @return true if user id is marked as primary or false otherwise + */ + bool primary_uid() const; + + /** + * @brief Set the primary user id flag + * @param primary true if user id should be marked as primary + */ + void set_primary_uid(bool primary); + + /** @brief Get preferred symmetric algorithms if any. If there are no ones then empty + * vector is returned. */ + std::vector preferred_symm_algs() const; + + /** @brief Set the preferred symmetric algorithms. If empty vector is passed then + * corresponding subpacket is deleted. */ + void set_preferred_symm_algs(const std::vector &algs); + + /** @brief Get preferred hash algorithms if any. If there are no ones then empty vector is + * returned.*/ + std::vector preferred_hash_algs() const; + + /** @brief Set the preferred hash algorithms. If empty vector is passed then corresponding + * subpacket is deleted. */ + void set_preferred_hash_algs(const std::vector &algs); + + /** @brief Get preferred compression algorithms if any. If there are no ones then empty + * vector is returned.*/ + std::vector preferred_z_algs() const; + + /** @brief Set the preferred compression algorithms. If empty vector is passed then + * corresponding subpacket is deleted. */ + void set_preferred_z_algs(const std::vector &algs); + + /** @brief Get key server preferences flags. If subpacket is not available then 0 is + * returned. */ + uint8_t key_server_prefs() const; + + /** @brief Set key server preferences flags. */ + void set_key_server_prefs(uint8_t prefs); + + /** @brief Get preferred key server URI, if available. Otherwise empty string is returned. + */ + std::string key_server() const; + + /** @brief Set preferred key server URI. If it is empty string then subpacket is deleted if + * it is available. */ + void set_key_server(const std::string &uri); + + /** @brief Get trust level, if available. Otherwise will return 0. See RFC 4880, 5.2.3.14. + * for the detailed information on trust level and amount. + */ + uint8_t trust_level() const; + + /** @brief Get trust amount, if available. Otherwise will return 0. See RFC 4880, 5.2.3.14. + * for the detailed information on trust level and amount. + */ + uint8_t trust_amount() const; + + /** @brief Set the trust level and amount. See RFC 4880, 5.2.3.14. + * for the detailed information on trust level and amount. + */ + void set_trust(uint8_t level, uint8_t amount); + + /** @brief check whether signature is revocable. True by default. + */ + bool revocable() const; + + /** @brief Set the signature's revocability status. + */ + void set_revocable(bool status); + + /** @brief Get the key/subkey revocation reason in humand-readable form. If there is no + * revocation reason subpacket, then empty string will be returned. + */ + std::string revocation_reason() const; + + /** @brief Get the key/subkey revocation code. If there is no revocation reason subpacket, + * then PGP_REVOCATION_NO_REASON will be rerturned. See the RFC 4880, 5.2.3.24 for + * the detailed explanation. + */ + pgp_revocation_type_t revocation_code() const; + + /** @brief Set the revocation reason and code for key/subkey revocation signature. See the + * RFC 4880, 5.2.3.24 for the detailed explanation. + */ + void set_revocation_reason(pgp_revocation_type_t code, const std::string &reason); + + /** + * @brief Check whether signer's key supports certain feature(s). Makes sense only for + * self-signature, for more details see the RFC 4880bis, 5.2.3.25. If there is + * no corresponding subpacket then false will be returned. + * @param flags one or more flags, combined via bitwise OR operation. + * @return true if key is claimed to support all of the features listed in flags, or false + * otherwise + */ + bool key_has_features(pgp_key_feature_t flags) const; + + /** + * @brief Set the features supported by the signer's key, makes sense only for + * self-signature. For more details see the RFC 4880bis, 5.2.3.25. + * @param flags one or more flags, combined via bitwise OR operation. + */ + void set_key_features(pgp_key_feature_t flags); + + /** @brief Get signer's user id, if available. Otherwise empty string is returned. See the + * RFC 4880bis, 5.2.3.23 for details. + */ + std::string signer_uid() const; + + /** + * @brief Set the signer's uid, responcible for the signature creation. See the RFC + * 4880bis, 5.2.3.23 for details. + */ + void set_signer_uid(const std::string &uid); + + /** + * @brief Add notation. + */ + void add_notation(const std::string & name, + const std::vector &value, + bool human = true, + bool critical = false); + + /** + * @brief Add human-readable notation. + */ + void add_notation(const std::string &name, + const std::string &value, + bool critical = false); + + /** + * @brief Set the embedded signature. + * @param esig populated and calculated embedded signature. + */ + void set_embedded_sig(const pgp_signature_t &esig); + + /** + * @brief Add subpacket of the specified type to v4 signature + * @param type type of the subpacket + * @param datalen length of the subpacket body + * @param reuse replace already existing subpacket of the specified type if any + * @return reference to the subpacket structure or throws an exception + */ + pgp_sig_subpkt_t &add_subpkt(pgp_sig_subpacket_type_t type, size_t datalen, bool reuse); + + /** + * @brief Remove signature's subpacket + * @param subpkt subpacket to remove. If not in the subpackets list then no action is + * taken. + */ + void remove_subpkt(pgp_sig_subpkt_t *subpkt); + + /** + * @brief Check whether signature packet matches one-pass signature packet. + * @param onepass reference to the read one-pass signature packet + * @return true if sig corresponds to onepass or false otherwise + */ + bool matches_onepass(const pgp_one_pass_sig_t &onepass) const; + + /** + * @brief Parse signature body (i.e. without checking the packet header). + * + * @param pkt packet body with data. + * @return RNP_SUCCESS or error code if failed. May also throw an exception. + */ + rnp_result_t parse(pgp_packet_body_t &pkt); + + /** + * @brief Parse signature packet from source. + * + * @param src source with data. + * @return RNP_SUCCESS or error code if failed. May also throw an exception. + */ + rnp_result_t parse(pgp_source_t &src); + + /** + * @brief Parse signature material, stored in the signature in raw. + * + * @param material on success parsed material will be stored here. + * @return true on success or false otherwise. May also throw an exception. + */ + bool parse_material(pgp_signature_material_t &material) const; + + /** + * @brief Write signature to the destination. May throw an exception. + */ + void write(pgp_dest_t &dst) const; + + /** + * @brief Write the signature material's raw representation. May throw an exception. + * + * @param material populated signature material. + */ + void write_material(const pgp_signature_material_t &material); + + /** + * @brief Fill signature's hashed data. This includes all the fields from signature which + * are hashed after the previous document or key fields. + */ + void fill_hashed_data(); +} pgp_signature_t; + +typedef std::vector pgp_signature_list_t; + +/* information about the validated signature */ +typedef struct pgp_signature_info_t { + pgp_signature_t *sig{}; /* signature, or NULL if there were parsing error */ + bool valid{}; /* signature is cryptographically valid (but may be expired) */ + bool unknown{}; /* signature is unknown - parsing error, wrong version, etc */ + bool no_signer{}; /* no signer's public key available */ + bool expired{}; /* signature is expired */ + bool signer_valid{}; /* assume that signing key is valid */ + bool ignore_expiry{}; /* ignore signer's key expiration time */ +} pgp_signature_info_t; + +/** + * @brief Hash key packet. Used in signatures and v4 fingerprint calculation. + * Throws exception on error. + * @param key key packet, must be populated + * @param hash initialized hash context + */ +void signature_hash_key(const pgp_key_pkt_t &key, rnp::Hash &hash); + +void signature_hash_userid(const pgp_userid_pkt_t &uid, rnp::Hash &hash, pgp_version_t sigver); + +std::unique_ptr signature_hash_certification(const pgp_signature_t & sig, + const pgp_key_pkt_t & key, + const pgp_userid_pkt_t &userid); + +std::unique_ptr signature_hash_binding(const pgp_signature_t &sig, + const pgp_key_pkt_t & key, + const pgp_key_pkt_t & subkey); + +std::unique_ptr signature_hash_direct(const pgp_signature_t &sig, + const pgp_key_pkt_t & key); + +/** + * @brief Parse stream with signatures to the signatures list. + * Can handle binary or armored stream with signatures, including stream with multiple + * armored signatures. + * + * @param src signatures stream, cannot be NULL. + * @param sigs on success parsed signature structures will be put here. + * @return RNP_SUCCESS or error code otherwise. + */ +rnp_result_t process_pgp_signatures(pgp_source_t &src, pgp_signature_list_t &sigs); + +#endif diff --git a/comm/third_party/rnp/src/librepgp/stream-write.cpp b/comm/third_party/rnp/src/librepgp/stream-write.cpp new file mode 100644 index 0000000000..60d867ae8d --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-write.cpp @@ -0,0 +1,1973 @@ +/* + * Copyright (c) 2017-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#include +#else +#include "uniwin.h" +#endif +#include +#ifdef HAVE_ZLIB_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif +#include +#include "stream-def.h" +#include "stream-ctx.h" +#include "stream-write.h" +#include "stream-packet.h" +#include "stream-armor.h" +#include "stream-sig.h" +#include "pgp-key.h" +#include "fingerprint.h" +#include "types.h" +#include "crypto/signatures.h" +#include "defaults.h" +#include +#include + +/* 8192 bytes, as GnuPG */ +#define PGP_PARTIAL_PKT_SIZE_BITS (13) +#define PGP_PARTIAL_PKT_BLOCK_SIZE (1 << PGP_PARTIAL_PKT_SIZE_BITS) + +/* common fields for encrypted, compressed and literal data */ +typedef struct pgp_dest_packet_param_t { + pgp_dest_t *writedst; /* destination to write to, could be partial */ + pgp_dest_t *origdst; /* original dest passed to init_*_dst */ + bool partial; /* partial length packet */ + bool indeterminate; /* indeterminate length packet */ + int tag; /* packet tag */ + uint8_t hdr[PGP_MAX_HEADER_SIZE]; /* header, including length, as it was written */ + size_t hdrlen; /* number of bytes in hdr */ +} pgp_dest_packet_param_t; + +typedef struct pgp_dest_compressed_param_t { + pgp_dest_packet_param_t pkt; + pgp_compression_type_t alg; + union { + z_stream z; + bz_stream bz; + }; + bool zstarted; /* whether we initialize zlib/bzip2 */ + uint8_t cache[PGP_INPUT_CACHE_SIZE / 2]; /* pre-allocated cache for compression */ + size_t len; /* number of bytes cached */ +} pgp_dest_compressed_param_t; + +typedef struct pgp_dest_encrypted_param_t { + pgp_dest_packet_param_t pkt; /* underlying packet-related params */ + rnp_ctx_t * ctx; /* rnp operation context with additional parameters */ + rnp::AuthType auth_type; /* Authentication type: MDC, AEAD or none */ + pgp_crypt_t encrypt; /* encrypting crypto */ + std::unique_ptr mdc; /* mdc SHA1 hash */ + pgp_aead_alg_t aalg; /* AEAD algorithm used */ + uint8_t iv[PGP_AEAD_MAX_NONCE_LEN]; /* iv for AEAD mode */ + uint8_t ad[PGP_AEAD_MAX_AD_LEN]; /* additional data for AEAD mode */ + size_t adlen; /* length of additional data, including chunk idx */ + size_t chunklen; /* length of the AEAD chunk in bytes */ + size_t chunkout; /* how many bytes from the chunk were written out */ + size_t chunkidx; /* index of the current AEAD chunk */ + size_t cachelen; /* how many bytes are in cache, for AEAD */ + uint8_t cache[PGP_AEAD_CACHE_LEN]; /* pre-allocated cache for encryption */ +} pgp_dest_encrypted_param_t; + +typedef struct pgp_dest_signer_info_t { + pgp_one_pass_sig_t onepass; + pgp_key_t * key; + pgp_hash_alg_t halg; + int64_t sigcreate; + uint64_t sigexpire; +} pgp_dest_signer_info_t; + +typedef struct pgp_dest_signed_param_t { + pgp_dest_t * writedst; /* destination to write to */ + rnp_ctx_t * ctx; /* rnp operation context with additional parameters */ + pgp_password_provider_t *password_provider; /* password provider from write handler */ + std::vector siginfos; /* list of pgp_dest_signer_info_t */ + rnp::HashList hashes; /* hashes to pass raw data through and then sign */ + bool clr_start; /* we are on the start of the line */ + uint8_t clr_buf[CT_BUF_LEN]; /* buffer to hold partial line data */ + size_t clr_buflen; /* number of bytes in buffer */ + + pgp_dest_signed_param_t() = default; + ~pgp_dest_signed_param_t() = default; +} pgp_dest_signed_param_t; + +typedef struct pgp_dest_partial_param_t { + pgp_dest_t *writedst; + uint8_t part[PGP_PARTIAL_PKT_BLOCK_SIZE]; + uint8_t parthdr; /* header byte for the current part */ + size_t partlen; /* length of the current part, up to PARTIAL_PKT_BLOCK_SIZE */ + size_t len; /* bytes cached in part */ +} pgp_dest_partial_param_t; + +static rnp_result_t +partial_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_partial_param_t *param = (pgp_dest_partial_param_t *) dst->param; + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (len > param->partlen - param->len) { + /* we have full part - in block and in buf */ + size_t wrlen = param->partlen - param->len; + dst_write(param->writedst, ¶m->parthdr, 1); + dst_write(param->writedst, param->part, param->len); + dst_write(param->writedst, buf, wrlen); + + buf = (uint8_t *) buf + wrlen; + len -= wrlen; + param->len = 0; + + /* writing all full parts directly from buf */ + while (len >= param->partlen) { + dst_write(param->writedst, ¶m->parthdr, 1); + dst_write(param->writedst, buf, param->partlen); + buf = (uint8_t *) buf + param->partlen; + len -= param->partlen; + } + } + + /* caching rest of the buf */ + if (len > 0) { + memcpy(¶m->part[param->len], buf, len); + param->len += len; + } + + return RNP_SUCCESS; +} + +static rnp_result_t +partial_dst_finish(pgp_dest_t *dst) +{ + pgp_dest_partial_param_t *param = (pgp_dest_partial_param_t *) dst->param; + uint8_t hdr[5]; + int lenlen; + + lenlen = write_packet_len(hdr, param->len); + dst_write(param->writedst, hdr, lenlen); + dst_write(param->writedst, param->part, param->len); + + return param->writedst->werr; +} + +static void +partial_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_partial_param_t *param = (pgp_dest_partial_param_t *) dst->param; + + if (!param) { + return; + } + + free(param); + dst->param = NULL; +} + +static rnp_result_t +init_partial_pkt_dst(pgp_dest_t *dst, pgp_dest_t *writedst) +{ + pgp_dest_partial_param_t *param; + + if (!init_dst_common(dst, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_dest_partial_param_t *) dst->param; + param->writedst = writedst; + param->partlen = PGP_PARTIAL_PKT_BLOCK_SIZE; + param->parthdr = 0xE0 | PGP_PARTIAL_PKT_SIZE_BITS; + dst->param = param; + dst->write = partial_dst_write; + dst->finish = partial_dst_finish; + dst->close = partial_dst_close; + dst->type = PGP_STREAM_PARLEN_PACKET; + + return RNP_SUCCESS; +} + +/** @brief helper function for streamed packets (literal, encrypted and compressed). + * Allocates part len destination if needed and writes header + **/ +static bool +init_streamed_packet(pgp_dest_packet_param_t *param, pgp_dest_t *dst) +{ + rnp_result_t ret; + + if (param->partial) { + param->hdr[0] = param->tag | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; + dst_write(dst, ¶m->hdr, 1); + + if ((param->writedst = (pgp_dest_t *) calloc(1, sizeof(*param->writedst))) == NULL) { + RNP_LOG("part len dest allocation failed"); + return false; + } + ret = init_partial_pkt_dst(param->writedst, dst); + if (ret != RNP_SUCCESS) { + free(param->writedst); + param->writedst = NULL; + return false; + } + param->origdst = dst; + + param->hdr[1] = ((pgp_dest_partial_param_t *) param->writedst->param)->parthdr; + param->hdrlen = 2; + return true; + } + + if (param->indeterminate) { + if (param->tag > 0xf) { + RNP_LOG("indeterminate tag > 0xf"); + } + + param->hdr[0] = ((param->tag & 0xf) << PGP_PTAG_OF_CONTENT_TAG_SHIFT) | + PGP_PTAG_OLD_LEN_INDETERMINATE; + param->hdrlen = 1; + dst_write(dst, ¶m->hdr, 1); + + param->writedst = dst; + param->origdst = dst; + return true; + } + + RNP_LOG("wrong call"); + return false; +} + +static rnp_result_t +finish_streamed_packet(pgp_dest_packet_param_t *param) +{ + if (param->partial) { + return dst_finish(param->writedst); + } + return RNP_SUCCESS; +} + +static void +close_streamed_packet(pgp_dest_packet_param_t *param, bool discard) +{ + if (param->partial) { + dst_close(param->writedst, discard); + free(param->writedst); + param->writedst = NULL; + } +} + +static rnp_result_t +encrypted_dst_write_cfb(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; + size_t sz; + + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (param->auth_type == rnp::AuthType::MDC) { + try { + param->mdc->add(buf, len); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_STATE; + } + } + + while (len > 0) { + sz = len > sizeof(param->cache) ? sizeof(param->cache) : len; + pgp_cipher_cfb_encrypt(¶m->encrypt, param->cache, (const uint8_t *) buf, sz); + dst_write(param->pkt.writedst, param->cache, sz); + len -= sz; + buf = (uint8_t *) buf + sz; + } + + return RNP_SUCCESS; +} + +#if defined(ENABLE_AEAD) +static rnp_result_t +encrypted_start_aead_chunk(pgp_dest_encrypted_param_t *param, size_t idx, bool last) +{ + uint8_t nonce[PGP_AEAD_MAX_NONCE_LEN]; + size_t nlen; + size_t taglen; + bool res; + uint64_t total; + + taglen = pgp_cipher_aead_tag_len(param->aalg); + + /* finish the previous chunk if needed*/ + if ((idx > 0) && (param->chunkout + param->cachelen > 0)) { + if (param->cachelen + taglen > sizeof(param->cache)) { + RNP_LOG("wrong state in aead"); + return RNP_ERROR_BAD_STATE; + } + + if (!pgp_cipher_aead_finish( + ¶m->encrypt, param->cache, param->cache, param->cachelen)) { + return RNP_ERROR_BAD_STATE; + } + + dst_write(param->pkt.writedst, param->cache, param->cachelen + taglen); + } + + /* set chunk index for additional data */ + STORE64BE(param->ad + param->adlen - 8, idx); + + if (last) { + if (!(param->chunkout + param->cachelen)) { + /* we need to clearly reset it since cipher was initialized but not finished */ + pgp_cipher_aead_reset(¶m->encrypt); + } + + total = idx * param->chunklen; + if (param->cachelen + param->chunkout) { + if (param->chunklen < (param->cachelen + param->chunkout)) { + RNP_LOG("wrong last chunk state in aead"); + return RNP_ERROR_BAD_STATE; + } + total -= param->chunklen - param->cachelen - param->chunkout; + } + + STORE64BE(param->ad + param->adlen, total); + param->adlen += 8; + } + if (!pgp_cipher_aead_set_ad(¶m->encrypt, param->ad, param->adlen)) { + RNP_LOG("failed to set ad"); + return RNP_ERROR_BAD_STATE; + } + + /* set chunk index for nonce */ + nlen = pgp_cipher_aead_nonce(param->aalg, param->iv, nonce, idx); + + /* start cipher */ + res = pgp_cipher_aead_start(¶m->encrypt, nonce, nlen); + + /* write final authentication tag */ + if (last) { + res = res && pgp_cipher_aead_finish(¶m->encrypt, param->cache, param->cache, 0); + if (res) { + dst_write(param->pkt.writedst, param->cache, taglen); + } + } + + param->chunkidx = idx; + param->chunkout = 0; + + return res ? RNP_SUCCESS : RNP_ERROR_BAD_PARAMETERS; +} +#endif + +static rnp_result_t +encrypted_dst_write_aead(pgp_dest_t *dst, const void *buf, size_t len) +{ +#if !defined(ENABLE_AEAD) + RNP_LOG("AEAD is not enabled."); + return RNP_ERROR_WRITE; +#else + pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; + + size_t sz; + size_t gran; + rnp_result_t res; + + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!len) { + return RNP_SUCCESS; + } + + /* because of botan's FFI granularity we need to make things a bit complicated */ + gran = pgp_cipher_aead_granularity(¶m->encrypt); + + if (param->cachelen > param->chunklen - param->chunkout) { + RNP_LOG("wrong AEAD cache state"); + return RNP_ERROR_BAD_STATE; + } + + while (len > 0) { + sz = std::min(sizeof(param->cache) - PGP_AEAD_MAX_TAG_LEN - param->cachelen, len); + sz = std::min(sz, param->chunklen - param->chunkout - param->cachelen); + memcpy(param->cache + param->cachelen, buf, sz); + param->cachelen += sz; + + if (param->cachelen == param->chunklen - param->chunkout) { + /* we have the tail of the chunk in cache */ + if ((res = encrypted_start_aead_chunk(param, param->chunkidx + 1, false))) { + return res; + } + param->cachelen = 0; + } else if (param->cachelen >= gran) { + /* we have part of the chunk - so need to adjust it to the granularity */ + size_t gransz = param->cachelen - param->cachelen % gran; + if (!pgp_cipher_aead_update(¶m->encrypt, param->cache, param->cache, gransz)) { + return RNP_ERROR_BAD_STATE; + } + dst_write(param->pkt.writedst, param->cache, gransz); + memmove(param->cache, param->cache + gransz, param->cachelen - gransz); + param->cachelen -= gransz; + param->chunkout += gransz; + } + + len -= sz; + buf = (uint8_t *) buf + sz; + } + + return RNP_SUCCESS; +#endif +} + +static rnp_result_t +encrypted_dst_finish(pgp_dest_t *dst) +{ + pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; + + if (param->auth_type == rnp::AuthType::AEADv1) { +#if !defined(ENABLE_AEAD) + RNP_LOG("AEAD is not enabled."); + rnp_result_t res = RNP_ERROR_NOT_IMPLEMENTED; +#else + size_t chunks = param->chunkidx; + /* if we didn't write anything in current chunk then discard it and restart */ + if (param->chunkout || param->cachelen) { + chunks++; + } + + rnp_result_t res = encrypted_start_aead_chunk(param, chunks, true); + pgp_cipher_aead_destroy(¶m->encrypt); +#endif + if (res) { + finish_streamed_packet(¶m->pkt); + return res; + } + } else if (param->auth_type == rnp::AuthType::MDC) { + uint8_t mdcbuf[MDC_V1_SIZE]; + mdcbuf[0] = MDC_PKT_TAG; + mdcbuf[1] = MDC_V1_SIZE - 2; + try { + param->mdc->add(mdcbuf, 2); + param->mdc->finish(&mdcbuf[2]); + param->mdc = nullptr; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_STATE; + } + pgp_cipher_cfb_encrypt(¶m->encrypt, mdcbuf, mdcbuf, MDC_V1_SIZE); + dst_write(param->pkt.writedst, mdcbuf, MDC_V1_SIZE); + } + + return finish_streamed_packet(¶m->pkt); +} + +static void +encrypted_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; + + if (!param) { + return; + } + + if (param->auth_type == rnp::AuthType::AEADv1) { +#if defined(ENABLE_AEAD) + pgp_cipher_aead_destroy(¶m->encrypt); +#endif + } else { + pgp_cipher_cfb_finish(¶m->encrypt); + } + close_streamed_packet(¶m->pkt, discard); + delete param; + dst->param = NULL; +} + +static rnp_result_t +encrypted_add_recipient(pgp_write_handler_t *handler, + pgp_dest_t * dst, + pgp_key_t * userkey, + const uint8_t * key, + const unsigned keylen) +{ + pgp_pk_sesskey_t pkey; + pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; + rnp_result_t ret = RNP_ERROR_GENERIC; + + /* Use primary key if good for encryption, otherwise look in subkey list */ + userkey = find_suitable_key(PGP_OP_ENCRYPT, userkey, handler->key_provider); + if (!userkey) { + return RNP_ERROR_NO_SUITABLE_KEY; + } + + /* Fill pkey */ + pkey.version = PGP_PKSK_V3; + pkey.alg = userkey->alg(); + pkey.key_id = userkey->keyid(); + + /* Encrypt the session key */ + rnp::secure_array enckey; + enckey[0] = param->ctx->ealg; + memcpy(&enckey[1], key, keylen); + + /* Calculate checksum */ + rnp::secure_array checksum; + + for (unsigned i = 1; i <= keylen; i++) { + checksum[0] += enckey[i]; + } + enckey[keylen + 1] = (checksum[0] >> 8) & 0xff; + enckey[keylen + 2] = checksum[0] & 0xff; + + pgp_encrypted_material_t material; + + switch (userkey->alg()) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: { + ret = rsa_encrypt_pkcs1(&handler->ctx->ctx->rng, + &material.rsa, + enckey.data(), + keylen + 3, + &userkey->material().rsa); + if (ret) { + RNP_LOG("rsa_encrypt_pkcs1 failed"); + return ret; + } + break; + } + case PGP_PKA_SM2: { +#if defined(ENABLE_SM2) + ret = sm2_encrypt(&handler->ctx->ctx->rng, + &material.sm2, + enckey.data(), + keylen + 3, + PGP_HASH_SM3, + &userkey->material().ec); + if (ret) { + RNP_LOG("sm2_encrypt failed"); + return ret; + } + break; +#else + RNP_LOG("sm2_encrypt is not available"); + return RNP_ERROR_NOT_IMPLEMENTED; +#endif + } + case PGP_PKA_ECDH: { + if (!curve_supported(userkey->material().ec.curve)) { + RNP_LOG("ECDH encrypt: curve %d is not supported.", + (int) userkey->material().ec.curve); + return RNP_ERROR_NOT_SUPPORTED; + } + ret = ecdh_encrypt_pkcs5(&handler->ctx->ctx->rng, + &material.ecdh, + enckey.data(), + keylen + 3, + &userkey->material().ec, + userkey->fp()); + if (ret) { + RNP_LOG("ECDH encryption failed %d", ret); + return ret; + } + break; + } + case PGP_PKA_ELGAMAL: { + ret = elgamal_encrypt_pkcs1(&handler->ctx->ctx->rng, + &material.eg, + enckey.data(), + keylen + 3, + &userkey->material().eg); + if (ret) { + RNP_LOG("pgp_elgamal_public_encrypt failed"); + return ret; + } + break; + } + default: + RNP_LOG("unsupported alg: %d", (int) userkey->alg()); + return ret; + } + + /* Writing symmetric key encrypted session key packet */ + try { + pkey.write_material(material); + pkey.write(*param->pkt.origdst); + return param->pkt.origdst->werr; + } catch (const std::exception &e) { + return RNP_ERROR_WRITE; + } +} + +#if defined(ENABLE_AEAD) +static bool +encrypted_sesk_set_ad(pgp_crypt_t *crypt, pgp_sk_sesskey_t *skey) +{ + uint8_t ad_data[4]; + + ad_data[0] = PGP_PKT_SK_SESSION_KEY | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; + ad_data[1] = skey->version; + ad_data[2] = skey->alg; + ad_data[3] = skey->aalg; + + return pgp_cipher_aead_set_ad(crypt, ad_data, 4); +} +#endif + +static rnp_result_t +encrypted_add_password(rnp_symmetric_pass_info_t * pass, + pgp_dest_encrypted_param_t *param, + uint8_t * key, + const unsigned keylen, + bool singlepass) +{ + pgp_sk_sesskey_t skey = {}; + pgp_crypt_t kcrypt; + + skey.s2k = pass->s2k; + + if (param->auth_type != rnp::AuthType::AEADv1) { + skey.version = PGP_SKSK_V4; + if (singlepass) { + /* if there are no public keys then we do not encrypt session key in the packet */ + skey.alg = param->ctx->ealg; + skey.enckeylen = 0; + memcpy(key, pass->key.data(), keylen); + } else { + /* We may use different algo for CEK and KEK */ + skey.enckeylen = keylen + 1; + skey.enckey[0] = param->ctx->ealg; + memcpy(&skey.enckey[1], key, keylen); + skey.alg = pass->s2k_cipher; + if (!pgp_cipher_cfb_start(&kcrypt, skey.alg, pass->key.data(), NULL)) { + RNP_LOG("key encryption failed"); + return RNP_ERROR_BAD_PARAMETERS; + } + pgp_cipher_cfb_encrypt(&kcrypt, skey.enckey, skey.enckey, skey.enckeylen); + pgp_cipher_cfb_finish(&kcrypt); + } + } else { +#if !defined(ENABLE_AEAD) + RNP_LOG("AEAD support is not enabled."); + return RNP_ERROR_NOT_IMPLEMENTED; +#else + /* AEAD-encrypted v5 packet */ + if ((param->ctx->aalg != PGP_AEAD_EAX) && (param->ctx->aalg != PGP_AEAD_OCB)) { + RNP_LOG("unsupported AEAD algorithm"); + return RNP_ERROR_BAD_PARAMETERS; + } + + skey.version = PGP_SKSK_V5; + skey.alg = pass->s2k_cipher; + skey.aalg = param->ctx->aalg; + skey.ivlen = pgp_cipher_aead_nonce_len(skey.aalg); + skey.enckeylen = keylen + pgp_cipher_aead_tag_len(skey.aalg); + + try { + param->ctx->ctx->rng.get(skey.iv, skey.ivlen); + } catch (const std::exception &e) { + return RNP_ERROR_RNG; + } + + /* initialize cipher */ + if (!pgp_cipher_aead_init(&kcrypt, skey.alg, skey.aalg, pass->key.data(), false)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* set additional data */ + if (!encrypted_sesk_set_ad(&kcrypt, &skey)) { + return RNP_ERROR_BAD_STATE; + } + + /* calculate nonce */ + uint8_t nonce[PGP_AEAD_MAX_NONCE_LEN]; + size_t nlen = pgp_cipher_aead_nonce(skey.aalg, skey.iv, nonce, 0); + + /* start cipher, encrypt key and get tag */ + bool res = pgp_cipher_aead_start(&kcrypt, nonce, nlen) && + pgp_cipher_aead_finish(&kcrypt, skey.enckey, key, keylen); + + pgp_cipher_aead_destroy(&kcrypt); + + if (!res) { + return RNP_ERROR_BAD_STATE; + } +#endif + } + + /* Writing symmetric key encrypted session key packet */ + try { + skey.write(*param->pkt.origdst); + } catch (const std::exception &e) { + return RNP_ERROR_WRITE; + } + return param->pkt.origdst->werr; +} + +static rnp_result_t +encrypted_start_cfb(pgp_dest_encrypted_param_t *param, uint8_t *enckey) +{ + uint8_t mdcver = 1; + uint8_t enchdr[PGP_MAX_BLOCK_SIZE + 2]; /* encrypted header */ + unsigned blsize; + + if (param->auth_type == rnp::AuthType::MDC) { + /* initializing the mdc */ + dst_write(param->pkt.writedst, &mdcver, 1); + + try { + param->mdc = rnp::Hash::create(PGP_HASH_SHA1); + } catch (const std::exception &e) { + RNP_LOG("cannot create sha1 hash: %s", e.what()); + return RNP_ERROR_GENERIC; + } + } + + /* initializing the crypto */ + if (!pgp_cipher_cfb_start(¶m->encrypt, param->ctx->ealg, enckey, NULL)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* generating and writing iv/password check bytes */ + blsize = pgp_block_size(param->ctx->ealg); + try { + param->ctx->ctx->rng.get(enchdr, blsize); + enchdr[blsize] = enchdr[blsize - 2]; + enchdr[blsize + 1] = enchdr[blsize - 1]; + + if (param->auth_type == rnp::AuthType::MDC) { + param->mdc->add(enchdr, blsize + 2); + } + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_STATE; + } + + pgp_cipher_cfb_encrypt(¶m->encrypt, enchdr, enchdr, blsize + 2); + + /* RFC 4880, 5.13: Unlike the Symmetrically Encrypted Data Packet, no special CFB + * resynchronization is done after encrypting this prefix data. */ + if (param->auth_type == rnp::AuthType::None) { + pgp_cipher_cfb_resync(¶m->encrypt, enchdr + 2); + } + + dst_write(param->pkt.writedst, enchdr, blsize + 2); + + return RNP_SUCCESS; +} + +static rnp_result_t +encrypted_start_aead(pgp_dest_encrypted_param_t *param, uint8_t *enckey) +{ +#if !defined(ENABLE_AEAD) + RNP_LOG("AEAD support is not enabled."); + return RNP_ERROR_NOT_IMPLEMENTED; +#else + uint8_t hdr[4 + PGP_AEAD_MAX_NONCE_LEN]; + size_t nlen; + + if (pgp_block_size(param->ctx->ealg) != 16) { + return RNP_ERROR_BAD_PARAMETERS; + } + + /* fill header */ + hdr[0] = 1; + hdr[1] = param->ctx->ealg; + hdr[2] = param->ctx->aalg; + hdr[3] = param->ctx->abits; + + /* generate iv */ + nlen = pgp_cipher_aead_nonce_len(param->ctx->aalg); + try { + param->ctx->ctx->rng.get(param->iv, nlen); + } catch (const std::exception &e) { + return RNP_ERROR_RNG; + } + memcpy(hdr + 4, param->iv, nlen); + + /* output header */ + dst_write(param->pkt.writedst, hdr, 4 + nlen); + + /* initialize encryption */ + param->chunklen = 1L << (hdr[3] + 6); + param->chunkout = 0; + + /* fill additional/authenticated data */ + param->ad[0] = PGP_PKT_AEAD_ENCRYPTED | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; + memcpy(param->ad + 1, hdr, 4); + memset(param->ad + 5, 0, 8); + param->adlen = 13; + + /* initialize cipher */ + if (!pgp_cipher_aead_init( + ¶m->encrypt, param->ctx->ealg, param->ctx->aalg, enckey, false)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + return encrypted_start_aead_chunk(param, 0, false); +#endif +} + +static rnp_result_t +init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *writedst) +{ + pgp_dest_encrypted_param_t *param; + bool singlepass = true; + unsigned pkeycount = 0; + unsigned skeycount = 0; + unsigned keylen; + rnp_result_t ret = RNP_ERROR_GENERIC; + + keylen = pgp_key_size(handler->ctx->ealg); + if (!keylen) { + RNP_LOG("unknown symmetric algorithm"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (handler->ctx->aalg) { + if ((handler->ctx->aalg != PGP_AEAD_EAX) && (handler->ctx->aalg != PGP_AEAD_OCB)) { + RNP_LOG("unknown AEAD algorithm: %d", (int) handler->ctx->aalg); + return RNP_ERROR_BAD_PARAMETERS; + } + + if ((pgp_block_size(handler->ctx->ealg) != 16)) { + RNP_LOG("wrong AEAD symmetric algorithm"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if ((handler->ctx->abits < 0) || (handler->ctx->abits > 16)) { + RNP_LOG("wrong AEAD chunk bits: %d", handler->ctx->abits); + return RNP_ERROR_BAD_PARAMETERS; + } + } + + if (!init_dst_common(dst, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + try { + param = new pgp_dest_encrypted_param_t(); + dst->param = param; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + param->auth_type = + handler->ctx->aalg == PGP_AEAD_NONE ? rnp::AuthType::MDC : rnp::AuthType::AEADv1; + param->aalg = handler->ctx->aalg; + param->ctx = handler->ctx; + param->pkt.origdst = writedst; + dst->write = param->auth_type == rnp::AuthType::AEADv1 ? encrypted_dst_write_aead : + encrypted_dst_write_cfb; + dst->finish = encrypted_dst_finish; + dst->close = encrypted_dst_close; + dst->type = PGP_STREAM_ENCRYPTED; + + pkeycount = handler->ctx->recipients.size(); + skeycount = handler->ctx->passwords.size(); + + rnp::secure_array enckey; /* content encryption key */ + if (!pkeycount && !skeycount) { + RNP_LOG("no recipients"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + if ((pkeycount > 0) || (skeycount > 1) || (param->auth_type == rnp::AuthType::AEADv1)) { + try { + handler->ctx->ctx->rng.get(enckey.data(), keylen); + } catch (const std::exception &e) { + ret = RNP_ERROR_RNG; + goto finish; + } + singlepass = false; + } + + /* Configuring and writing pk-encrypted session keys */ + for (auto recipient : handler->ctx->recipients) { + ret = encrypted_add_recipient(handler, dst, recipient, enckey.data(), keylen); + if (ret) { + goto finish; + } + } + + /* Configuring and writing sk-encrypted session key(s) */ + for (auto &passinfo : handler->ctx->passwords) { + ret = encrypted_add_password(&passinfo, param, enckey.data(), keylen, singlepass); + if (ret != RNP_SUCCESS) { + goto finish; + } + } + + /* Initializing partial packet writer */ + param->pkt.partial = true; + param->pkt.indeterminate = false; + if (param->auth_type == rnp::AuthType::AEADv1) { + param->pkt.tag = PGP_PKT_AEAD_ENCRYPTED; + } else { + /* We do not generate PGP_PKT_SE_DATA, leaving this just in case */ + param->pkt.tag = + param->auth_type == rnp::AuthType::MDC ? PGP_PKT_SE_IP_DATA : PGP_PKT_SE_DATA; + } + + /* initializing partial data length writer */ + /* we may use intederminate len packet here as well, for compatibility or so on */ + if (!init_streamed_packet(¶m->pkt, writedst)) { + RNP_LOG("failed to init streamed packet"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + if (param->auth_type == rnp::AuthType::AEADv1) { + /* initialize AEAD encryption */ + ret = encrypted_start_aead(param, enckey.data()); + } else { + /* initialize old CFB or CFB with MDC */ + ret = encrypted_start_cfb(param, enckey.data()); + } +finish: + handler->ctx->passwords.clear(); + if (ret) { + encrypted_dst_close(dst, true); + } + return ret; +} + +static rnp_result_t +signed_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + dst_write(param->writedst, buf, len); + return RNP_SUCCESS; +} + +static void +cleartext_dst_writeline(pgp_dest_signed_param_t *param, + const uint8_t * buf, + size_t len, + bool eol) +{ + const uint8_t *ptr; + + /* dash-escaping line if needed */ + if (param->clr_start && len && + ((buf[0] == CH_DASH) || ((len >= 4) && !strncmp((const char *) buf, ST_FROM, 4)))) { + dst_write(param->writedst, ST_DASHSP, 2); + } + + /* output data */ + dst_write(param->writedst, buf, len); + + try { + if (eol) { + bool hashcrlf = false; + ptr = buf + len - 1; + + /* skipping trailing characters - space, tab, carriage return, line feed */ + while ((ptr >= buf) && ((*ptr == CH_SPACE) || (*ptr == CH_TAB) || + (*ptr == CH_CR) || (*ptr == CH_LF))) { + if (*ptr == CH_LF) { + hashcrlf = true; + } + ptr--; + } + + /* hashing line body and \r\n */ + param->hashes.add(buf, ptr + 1 - buf); + if (hashcrlf) { + param->hashes.add(ST_CRLF, 2); + } + param->clr_start = hashcrlf; + } else if (len > 0) { + /* hashing just line's data */ + param->hashes.add(buf, len); + param->clr_start = false; + } + } catch (const std::exception &e) { + RNP_LOG("failed to hash data: %s", e.what()); + } +} + +static size_t +cleartext_dst_scanline(const uint8_t *buf, size_t len, bool *eol) +{ + for (const uint8_t *ptr = buf, *end = buf + len; ptr < end; ptr++) { + if (*ptr == CH_LF) { + if (eol) { + *eol = true; + } + return ptr - buf + 1; + } + } + + if (eol) { + *eol = false; + } + return len; +} + +static rnp_result_t +cleartext_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + const uint8_t * linebg = (const uint8_t *) buf; + size_t linelen; + size_t cplen; + bool eol; + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + + if (param->clr_buflen > 0) { + /* number of edge cases may happen here */ + linelen = cleartext_dst_scanline(linebg, len, &eol); + + if (param->clr_buflen + linelen < sizeof(param->clr_buf)) { + /* fits into buffer */ + memcpy(param->clr_buf + param->clr_buflen, linebg, linelen); + param->clr_buflen += linelen; + if (!eol) { + /* do not write the line if we don't have whole */ + return RNP_SUCCESS; + } + + cleartext_dst_writeline(param, param->clr_buf, param->clr_buflen, true); + param->clr_buflen = 0; + } else { + /* we have line longer than 4k */ + cplen = sizeof(param->clr_buf) - param->clr_buflen; + memcpy(param->clr_buf + param->clr_buflen, linebg, cplen); + cleartext_dst_writeline(param, param->clr_buf, sizeof(param->clr_buf), false); + + if (eol || (linelen >= sizeof(param->clr_buf))) { + cleartext_dst_writeline(param, linebg + cplen, linelen - cplen, eol); + param->clr_buflen = 0; + } else { + param->clr_buflen = linelen - cplen; + memcpy(param->clr_buf, linebg + cplen, param->clr_buflen); + return RNP_SUCCESS; + } + } + + linebg += linelen; + len -= linelen; + } + + /* if we get here then we don't have data in param->clr_buf */ + while (len > 0) { + linelen = cleartext_dst_scanline(linebg, len, &eol); + + if (!eol && (linelen < sizeof(param->clr_buf))) { + memcpy(param->clr_buf, linebg, linelen); + param->clr_buflen = linelen; + return RNP_SUCCESS; + } + + cleartext_dst_writeline(param, linebg, linelen, eol); + linebg += linelen; + len -= linelen; + } + + return RNP_SUCCESS; +} + +static void +signed_fill_signature(pgp_dest_signed_param_t ¶m, + pgp_signature_t & sig, + pgp_dest_signer_info_t & signer) +{ + /* fill signature fields, assuming sign_init was called on it */ + if (signer.sigcreate) { + sig.set_creation(signer.sigcreate); + } + sig.set_expiration(signer.sigexpire); + sig.fill_hashed_data(); + + auto listh = param.hashes.get(sig.halg); + if (!listh) { + RNP_LOG("failed to obtain hash"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + /* decrypt the secret key if needed */ + rnp::KeyLocker keylock(*signer.key); + if (signer.key->encrypted() && + !signer.key->unlock(*param.password_provider, PGP_OP_SIGN)) { + RNP_LOG("wrong secret key password"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PASSWORD); + } + /* calculate the signature */ + signature_calculate(sig, signer.key->material(), *listh->clone(), *param.ctx->ctx); +} + +static rnp_result_t +signed_write_signature(pgp_dest_signed_param_t *param, + pgp_dest_signer_info_t * signer, + pgp_dest_t * writedst) +{ + try { + pgp_signature_t sig; + if (signer->onepass.version) { + signer->key->sign_init(sig, signer->onepass.halg, param->ctx->ctx->time()); + sig.palg = signer->onepass.palg; + sig.set_type(signer->onepass.type); + } else { + signer->key->sign_init(sig, signer->halg, param->ctx->ctx->time()); + /* line below should be checked */ + sig.set_type(param->ctx->detached ? PGP_SIG_BINARY : PGP_SIG_TEXT); + } + signed_fill_signature(*param, sig, *signer); + sig.write(*writedst); + return writedst->werr; + } catch (const rnp::rnp_exception &e) { + return e.code(); + } catch (const std::exception &e) { + RNP_LOG("Failed to write signature: %s", e.what()); + return RNP_ERROR_WRITE; + } +} + +static rnp_result_t +signed_dst_finish(pgp_dest_t *dst) +{ + rnp_result_t ret; + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + + /* attached signature, we keep onepasses in order of signatures */ + for (auto &sinfo : param->siginfos) { + if ((ret = signed_write_signature(param, &sinfo, param->writedst))) { + RNP_LOG("failed to calculate signature"); + return ret; + } + } + + return RNP_SUCCESS; +} + +static rnp_result_t +signed_detached_dst_finish(pgp_dest_t *dst) +{ + rnp_result_t ret; + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + + /* just calculating and writing signatures to the output */ + for (auto &sinfo : param->siginfos) { + if ((ret = signed_write_signature(param, &sinfo, param->writedst))) { + RNP_LOG("failed to calculate detached signature"); + return ret; + } + } + + return RNP_SUCCESS; +} + +static rnp_result_t +cleartext_dst_finish(pgp_dest_t *dst) +{ + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + + /* writing cached line if any */ + if (param->clr_buflen > 0) { + cleartext_dst_writeline(param, param->clr_buf, param->clr_buflen, true); + } + /* trailing \r\n which is not hashed */ + dst_write(param->writedst, ST_CRLF, 2); + + /* writing signatures to the armored stream, which outputs to param->writedst */ + try { + rnp::ArmoredDest armor(*param->writedst, PGP_ARMORED_SIGNATURE); + armor.set_discard(true); + for (auto &sinfo : param->siginfos) { + auto ret = signed_write_signature(param, &sinfo, &armor.dst()); + if (ret) { + return ret; + } + } + armor.set_discard(false); + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("Failed to write armored signature: %s", e.what()); + return RNP_ERROR_WRITE; + } +} + +static void +signed_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + if (!param) { + return; + } + delete param; + dst->param = NULL; +} + +static void +signed_dst_update(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param; + param->hashes.add(buf, len); +} + +static rnp_result_t +signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, bool last) +{ + pgp_dest_signer_info_t sinfo = {}; + + if (!signer->key->is_secret()) { + RNP_LOG("secret key required for signing"); + return RNP_ERROR_BAD_PARAMETERS; + } + /* validate signing key material if didn't before */ + signer->key->pkt().material.validate(*param->ctx->ctx, false); + if (!signer->key->pkt().material.valid()) { + RNP_LOG("attempt to sign to the key with invalid material"); + return RNP_ERROR_NO_SUITABLE_KEY; + } + + /* copy fields */ + sinfo.key = signer->key; + sinfo.sigcreate = signer->sigcreate; + sinfo.sigexpire = signer->sigexpire; + + /* Add hash to the list */ + sinfo.halg = pgp_hash_adjust_alg_to_key(signer->halg, &signer->key->pkt()); + try { + param->hashes.add_alg(sinfo.halg); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_BAD_PARAMETERS; + } + + // Do not add onepass for detached/clearsign + if (param->ctx->detached || param->ctx->clearsign) { + sinfo.onepass.version = 0; + try { + param->siginfos.push_back(sinfo); + return RNP_SUCCESS; + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + } + + // Setup and add onepass + sinfo.onepass.version = 3; + sinfo.onepass.type = PGP_SIG_BINARY; + sinfo.onepass.halg = sinfo.halg; + sinfo.onepass.palg = sinfo.key->alg(); + sinfo.onepass.keyid = sinfo.key->keyid(); + sinfo.onepass.nested = false; + try { + param->siginfos.push_back(sinfo); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + + // write onepasses in reverse order so signature order will match signers list + if (!last) { + return RNP_SUCCESS; + } + try { + for (auto it = param->siginfos.rbegin(); it != param->siginfos.rend(); it++) { + pgp_dest_signer_info_t &sinfo = *it; + sinfo.onepass.nested = &sinfo == ¶m->siginfos.front(); + sinfo.onepass.write(*param->writedst); + } + return param->writedst->werr; + } catch (const std::exception &e) { + return RNP_ERROR_WRITE; + } +} + +static rnp_result_t +init_signed_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *writedst) +{ + pgp_dest_signed_param_t *param; + rnp_result_t ret = RNP_ERROR_GENERIC; + + if (!handler->key_provider) { + RNP_LOG("no key provider"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if (!init_dst_common(dst, 0)) { + return RNP_ERROR_OUT_OF_MEMORY; + } + try { + param = new pgp_dest_signed_param_t(); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_OUT_OF_MEMORY; + } + + dst->param = param; + param->writedst = writedst; + param->ctx = handler->ctx; + param->password_provider = handler->password_provider; + if (param->ctx->clearsign) { + dst->type = PGP_STREAM_CLEARTEXT; + dst->write = cleartext_dst_write; + dst->finish = cleartext_dst_finish; + param->clr_start = true; + } else { + dst->type = PGP_STREAM_SIGNED; + dst->write = signed_dst_write; + dst->finish = param->ctx->detached ? signed_detached_dst_finish : signed_dst_finish; + } + dst->close = signed_dst_close; + + /* Getting signer's infos, writing one-pass signatures if needed */ + for (auto &sg : handler->ctx->signers) { + ret = signed_add_signer(param, &sg, &sg == &handler->ctx->signers.back()); + if (ret) { + RNP_LOG("failed to add one-pass signature for signer"); + goto finish; + } + } + + /* Do we have any signatures? */ + if (param->hashes.hashes.empty()) { + ret = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + /* Writing headers for cleartext signed document */ + if (param->ctx->clearsign) { + dst_write(param->writedst, ST_CLEAR_BEGIN, strlen(ST_CLEAR_BEGIN)); + dst_write(param->writedst, ST_CRLF, strlen(ST_CRLF)); + dst_write(param->writedst, ST_HEADER_HASH, strlen(ST_HEADER_HASH)); + + for (const auto &hash : param->hashes.hashes) { + auto hname = rnp::Hash::name(hash->alg()); + dst_write(param->writedst, hname, strlen(hname)); + if (&hash != ¶m->hashes.hashes.back()) { + dst_write(param->writedst, ST_COMMA, 1); + } + } + + dst_write(param->writedst, ST_CRLFCRLF, strlen(ST_CRLFCRLF)); + } + + ret = RNP_SUCCESS; +finish: + if (ret != RNP_SUCCESS) { + signed_dst_close(dst, true); + } + + return ret; +} + +static rnp_result_t +compressed_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_compressed_param_t *param = (pgp_dest_compressed_param_t *) dst->param; + int zret; + + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + if ((param->alg == PGP_C_ZIP) || (param->alg == PGP_C_ZLIB)) { + param->z.next_in = (unsigned char *) buf; + param->z.avail_in = len; + param->z.next_out = param->cache + param->len; + param->z.avail_out = sizeof(param->cache) - param->len; + + while (param->z.avail_in > 0) { + zret = deflate(¶m->z, Z_NO_FLUSH); + /* Z_OK, Z_BUF_ERROR are ok for us, Z_STREAM_END will not happen here */ + if (zret == Z_STREAM_ERROR) { + RNP_LOG("wrong deflate state"); + return RNP_ERROR_BAD_STATE; + } + + /* writing only full blocks, the rest will be written in close */ + if (param->z.avail_out == 0) { + dst_write(param->pkt.writedst, param->cache, sizeof(param->cache)); + param->len = 0; + param->z.next_out = param->cache; + param->z.avail_out = sizeof(param->cache); + } + } + + param->len = sizeof(param->cache) - param->z.avail_out; + return RNP_SUCCESS; + } else if (param->alg == PGP_C_BZIP2) { +#ifdef HAVE_BZLIB_H + param->bz.next_in = (char *) buf; + param->bz.avail_in = len; + param->bz.next_out = (char *) (param->cache + param->len); + param->bz.avail_out = sizeof(param->cache) - param->len; + + while (param->bz.avail_in > 0) { + zret = BZ2_bzCompress(¶m->bz, BZ_RUN); + if (zret < 0) { + RNP_LOG("error %d", zret); + return RNP_ERROR_BAD_STATE; + } + + /* writing only full blocks, the rest will be written in close */ + if (param->bz.avail_out == 0) { + dst_write(param->pkt.writedst, param->cache, sizeof(param->cache)); + param->len = 0; + param->bz.next_out = (char *) param->cache; + param->bz.avail_out = sizeof(param->cache); + } + } + + param->len = sizeof(param->cache) - param->bz.avail_out; + return RNP_SUCCESS; +#else + return RNP_ERROR_NOT_IMPLEMENTED; +#endif + } else { + RNP_LOG("unknown algorithm"); + return RNP_ERROR_BAD_PARAMETERS; + } +} + +static rnp_result_t +compressed_dst_finish(pgp_dest_t *dst) +{ + int zret; + pgp_dest_compressed_param_t *param = (pgp_dest_compressed_param_t *) dst->param; + + if ((param->alg == PGP_C_ZIP) || (param->alg == PGP_C_ZLIB)) { + param->z.next_in = Z_NULL; + param->z.avail_in = 0; + param->z.next_out = param->cache + param->len; + param->z.avail_out = sizeof(param->cache) - param->len; + do { + zret = deflate(¶m->z, Z_FINISH); + + if (zret == Z_STREAM_ERROR) { + RNP_LOG("wrong deflate state"); + return RNP_ERROR_BAD_STATE; + } + + if (param->z.avail_out == 0) { + dst_write(param->pkt.writedst, param->cache, sizeof(param->cache)); + param->len = 0; + param->z.next_out = param->cache; + param->z.avail_out = sizeof(param->cache); + } + } while (zret != Z_STREAM_END); + + param->len = sizeof(param->cache) - param->z.avail_out; + dst_write(param->pkt.writedst, param->cache, param->len); + } +#ifdef HAVE_BZLIB_H + if (param->alg == PGP_C_BZIP2) { + param->bz.next_in = NULL; + param->bz.avail_in = 0; + param->bz.next_out = (char *) (param->cache + param->len); + param->bz.avail_out = sizeof(param->cache) - param->len; + + do { + zret = BZ2_bzCompress(¶m->bz, BZ_FINISH); + if (zret < 0) { + RNP_LOG("wrong bzip2 state %d", zret); + return RNP_ERROR_BAD_STATE; + } + + /* writing only full blocks, the rest will be written in close */ + if (param->bz.avail_out == 0) { + dst_write(param->pkt.writedst, param->cache, sizeof(param->cache)); + param->len = 0; + param->bz.next_out = (char *) param->cache; + param->bz.avail_out = sizeof(param->cache); + } + } while (zret != BZ_STREAM_END); + + param->len = sizeof(param->cache) - param->bz.avail_out; + dst_write(param->pkt.writedst, param->cache, param->len); + } +#endif + + if (param->pkt.writedst->werr) { + return param->pkt.writedst->werr; + } + + return finish_streamed_packet(¶m->pkt); +} + +static void +compressed_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_compressed_param_t *param = (pgp_dest_compressed_param_t *) dst->param; + + if (!param) { + return; + } + + if (param->zstarted) { + if ((param->alg == PGP_C_ZIP) || (param->alg == PGP_C_ZLIB)) { + deflateEnd(¶m->z); + } +#ifdef HAVE_BZLIB_H + if (param->alg == PGP_C_BZIP2) { + BZ2_bzCompressEnd(¶m->bz); + } +#endif + } + + close_streamed_packet(¶m->pkt, discard); + free(param); + dst->param = NULL; +} + +static rnp_result_t +init_compressed_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *writedst) +{ + pgp_dest_compressed_param_t *param; + rnp_result_t ret = RNP_ERROR_GENERIC; + uint8_t buf; + int zret; + + if (!init_dst_common(dst, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_dest_compressed_param_t *) dst->param; + dst->write = compressed_dst_write; + dst->finish = compressed_dst_finish; + dst->close = compressed_dst_close; + dst->type = PGP_STREAM_COMPRESSED; + param->alg = (pgp_compression_type_t) handler->ctx->zalg; + param->pkt.partial = true; + param->pkt.indeterminate = false; + param->pkt.tag = PGP_PKT_COMPRESSED; + + /* initializing partial length or indeterminate packet, writing header */ + if (!init_streamed_packet(¶m->pkt, writedst)) { + RNP_LOG("failed to init streamed packet"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + + /* compression algorithm */ + buf = param->alg; + dst_write(param->pkt.writedst, &buf, 1); + + /* initializing compression */ + switch (param->alg) { + case PGP_C_ZIP: + case PGP_C_ZLIB: + (void) memset(¶m->z, 0x0, sizeof(param->z)); + if (param->alg == PGP_C_ZIP) { + zret = deflateInit2( + ¶m->z, handler->ctx->zlevel, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + } else { + zret = deflateInit(¶m->z, handler->ctx->zlevel); + } + + if (zret != Z_OK) { + RNP_LOG("failed to init zlib, error %d", zret); + ret = RNP_ERROR_NOT_SUPPORTED; + goto finish; + } + break; +#ifdef HAVE_BZLIB_H + case PGP_C_BZIP2: + (void) memset(¶m->bz, 0x0, sizeof(param->bz)); + zret = BZ2_bzCompressInit(¶m->bz, handler->ctx->zlevel, 0, 0); + if (zret != BZ_OK) { + RNP_LOG("failed to init bz, error %d", zret); + ret = RNP_ERROR_NOT_SUPPORTED; + goto finish; + } + break; +#endif + default: + RNP_LOG("unknown compression algorithm"); + ret = RNP_ERROR_NOT_SUPPORTED; + goto finish; + } + param->zstarted = true; + ret = RNP_SUCCESS; +finish: + if (ret != RNP_SUCCESS) { + compressed_dst_close(dst, true); + } + + return ret; +} + +static rnp_result_t +literal_dst_write(pgp_dest_t *dst, const void *buf, size_t len) +{ + pgp_dest_packet_param_t *param = (pgp_dest_packet_param_t *) dst->param; + + if (!param) { + RNP_LOG("wrong param"); + return RNP_ERROR_BAD_PARAMETERS; + } + + dst_write(param->writedst, buf, len); + return RNP_SUCCESS; +} + +static rnp_result_t +literal_dst_finish(pgp_dest_t *dst) +{ + return finish_streamed_packet((pgp_dest_packet_param_t *) dst->param); +} + +static void +literal_dst_close(pgp_dest_t *dst, bool discard) +{ + pgp_dest_packet_param_t *param = (pgp_dest_packet_param_t *) dst->param; + + if (!param) { + return; + } + + close_streamed_packet(param, discard); + free(param); + dst->param = NULL; +} + +static rnp_result_t +init_literal_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *writedst) +{ + pgp_dest_packet_param_t *param; + rnp_result_t ret = RNP_ERROR_GENERIC; + size_t flen = 0; + uint8_t buf[4]; + + if (!init_dst_common(dst, sizeof(*param))) { + return RNP_ERROR_OUT_OF_MEMORY; + } + + param = (pgp_dest_packet_param_t *) dst->param; + dst->write = literal_dst_write; + dst->finish = literal_dst_finish; + dst->close = literal_dst_close; + dst->type = PGP_STREAM_LITERAL; + param->partial = true; + param->indeterminate = false; + param->tag = PGP_PKT_LITDATA; + + /* initializing partial length or indeterminate packet, writing header */ + if (!init_streamed_packet(param, writedst)) { + RNP_LOG("failed to init streamed packet"); + ret = RNP_ERROR_BAD_PARAMETERS; + goto finish; + } + /* content type - forcing binary now */ + buf[0] = (uint8_t) 'b'; + /* filename */ + flen = handler->ctx->filename.size(); + if (flen > 255) { + RNP_LOG("filename too long, truncating"); + flen = 255; + } + buf[1] = (uint8_t) flen; + dst_write(param->writedst, buf, 2); + if (flen) { + dst_write(param->writedst, handler->ctx->filename.c_str(), flen); + } + /* timestamp */ + STORE32BE(buf, handler->ctx->filemtime); + dst_write(param->writedst, buf, 4); + ret = RNP_SUCCESS; +finish: + if (ret != RNP_SUCCESS) { + literal_dst_close(dst, true); + } + + return ret; +} + +static rnp_result_t +process_stream_sequence(pgp_source_t *src, + pgp_dest_t * streams, + unsigned count, + pgp_dest_t * sstream, + pgp_dest_t * wstream) +{ + std::unique_ptr readbuf(new (std::nothrow) uint8_t[PGP_INPUT_CACHE_SIZE]); + if (!readbuf) { + RNP_LOG("allocation failure"); + return RNP_ERROR_OUT_OF_MEMORY; + } + + /* processing source stream */ + while (!src->eof) { + size_t read = 0; + if (!src_read(src, readbuf.get(), PGP_INPUT_CACHE_SIZE, &read)) { + RNP_LOG("failed to read from source"); + return RNP_ERROR_READ; + } else if (!read) { + continue; + } + + if (sstream) { + signed_dst_update(sstream, readbuf.get(), read); + } + + if (wstream) { + dst_write(wstream, readbuf.get(), read); + + for (int i = count - 1; i >= 0; i--) { + if (streams[i].werr) { + RNP_LOG("failed to process data"); + return RNP_ERROR_WRITE; + } + } + } + } + + /* finalizing destinations */ + for (int i = count - 1; i >= 0; i--) { + rnp_result_t ret = dst_finish(&streams[i]); + if (ret) { + RNP_LOG("failed to finish stream"); + return ret; + } + } + return RNP_SUCCESS; +} + +rnp_result_t +rnp_sign_src(pgp_write_handler_t *handler, pgp_source_t *src, pgp_dest_t *dst) +{ + /* stack of the streams would be as following: + [armoring stream] - if armoring is enabled + [compressing stream, partial writing stream] - compression is enabled, and not detached + signing stream + literal data stream, partial writing stream - if not detached or cleartext signature + */ + pgp_dest_t dests[4]; + unsigned destc = 0; + rnp_result_t ret = RNP_ERROR_GENERIC; + rnp_ctx_t & ctx = *handler->ctx; + pgp_dest_t * wstream = NULL; + pgp_dest_t * sstream = NULL; + + /* pushing armoring stream, which will write to the output */ + if (ctx.armor && !ctx.clearsign) { + pgp_armored_msg_t msgt = ctx.detached ? PGP_ARMORED_SIGNATURE : PGP_ARMORED_MESSAGE; + ret = init_armored_dst(&dests[destc], dst, msgt); + if (ret) { + goto finish; + } + destc++; + } + + /* if compression is enabled then pushing compressing stream */ + if (!ctx.detached && !ctx.clearsign && (ctx.zlevel > 0)) { + if ((ret = + init_compressed_dst(handler, &dests[destc], destc ? &dests[destc - 1] : dst))) { + goto finish; + } + destc++; + } + + /* pushing signing stream, which will use handler->ctx to distinguish between + * attached/detached/cleartext signature */ + if ((ret = init_signed_dst(handler, &dests[destc], destc ? &dests[destc - 1] : dst))) { + goto finish; + } + if (!ctx.clearsign) { + sstream = &dests[destc]; + } + if (!ctx.detached) { + wstream = &dests[destc]; + } + destc++; + + /* pushing literal data stream, if not detached/cleartext signature */ + if (!ctx.no_wrap && !ctx.detached && !ctx.clearsign) { + if ((ret = init_literal_dst(handler, &dests[destc], &dests[destc - 1]))) { + goto finish; + } + wstream = &dests[destc]; + destc++; + } + + /* process source with streams stack */ + ret = process_stream_sequence(src, dests, destc, sstream, wstream); +finish: + for (int i = destc - 1; i >= 0; i--) { + dst_close(&dests[i], ret); + } + return ret; +} + +rnp_result_t +rnp_encrypt_sign_src(pgp_write_handler_t *handler, pgp_source_t *src, pgp_dest_t *dst) +{ + /* stack of the streams would be as following: + [armoring stream] - if armoring is enabled + [encrypting stream, partial writing stream] + [compressing stream, partial writing stream] - compression is enabled + signing stream + literal data stream, partial writing stream + */ + pgp_dest_t dests[5]; + size_t destc = 0; + rnp_result_t ret = RNP_SUCCESS; + rnp_ctx_t & ctx = *handler->ctx; + pgp_dest_t * sstream = NULL; + + /* we may use only attached signatures here */ + if (ctx.clearsign || ctx.detached) { + RNP_LOG("cannot clearsign or sign detached together with encryption"); + return RNP_ERROR_BAD_PARAMETERS; + } + + /* pushing armoring stream, which will write to the output */ + if (ctx.armor) { + if ((ret = init_armored_dst(&dests[destc], dst, PGP_ARMORED_MESSAGE))) { + goto finish; + } + destc++; + } + + /* pushing encrypting stream, which will write to the output or armoring stream */ + if ((ret = init_encrypted_dst(handler, &dests[destc], destc ? &dests[destc - 1] : dst))) { + goto finish; + } + destc++; + + /* if compression is enabled then pushing compressing stream */ + if (ctx.zlevel > 0) { + if ((ret = init_compressed_dst(handler, &dests[destc], &dests[destc - 1]))) { + goto finish; + } + destc++; + } + + /* pushing signing stream if we have signers */ + if (!ctx.signers.empty()) { + if ((ret = init_signed_dst(handler, &dests[destc], &dests[destc - 1]))) { + goto finish; + } + sstream = &dests[destc]; + destc++; + } + + /* pushing literal data stream */ + if (!ctx.no_wrap) { + if ((ret = init_literal_dst(handler, &dests[destc], &dests[destc - 1]))) { + goto finish; + } + destc++; + } + + /* process source with streams stack */ + ret = process_stream_sequence(src, dests, destc, sstream, &dests[destc - 1]); +finish: + for (size_t i = destc; i > 0; i--) { + dst_close(&dests[i - 1], ret); + } + return ret; +} + +rnp_result_t +rnp_compress_src(pgp_source_t &src, pgp_dest_t &dst, pgp_compression_type_t zalg, int zlevel) +{ + pgp_write_handler_t handler = {}; + rnp_ctx_t ctx; + ctx.zalg = zalg; + ctx.zlevel = zlevel; + handler.ctx = &ctx; + + pgp_dest_t compressed = {}; + rnp_result_t ret = init_compressed_dst(&handler, &compressed, &dst); + if (ret) { + goto done; + } + ret = dst_write_src(&src, &compressed); +done: + dst_close(&compressed, ret); + return ret; +} + +rnp_result_t +rnp_wrap_src(pgp_source_t &src, pgp_dest_t &dst, const std::string &filename, uint32_t modtime) +{ + pgp_write_handler_t handler = {}; + rnp_ctx_t ctx; + ctx.filename = filename; + ctx.filemtime = modtime; + handler.ctx = &ctx; + + pgp_dest_t literal = {}; + rnp_result_t ret = init_literal_dst(&handler, &literal, &dst); + if (ret) { + goto done; + } + + ret = dst_write_src(&src, &literal); +done: + dst_close(&literal, ret); + return ret; +} + +rnp_result_t +rnp_raw_encrypt_src(pgp_source_t & src, + pgp_dest_t & dst, + const std::string & password, + rnp::SecurityContext &secctx) +{ + pgp_write_handler_t handler = {}; + rnp_ctx_t ctx; + + ctx.ctx = &secctx; + ctx.ealg = DEFAULT_PGP_SYMM_ALG; + handler.ctx = &ctx; + pgp_dest_t encrypted = {}; + + rnp_result_t ret = RNP_ERROR_GENERIC; + try { + ret = + ctx.add_encryption_password(password, DEFAULT_PGP_HASH_ALG, DEFAULT_PGP_SYMM_ALG); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + goto done; + } + if (ret) { + goto done; + } + + ret = init_encrypted_dst(&handler, &encrypted, &dst); + if (ret) { + goto done; + } + + ret = dst_write_src(&src, &encrypted); +done: + dst_close(&encrypted, ret); + return ret; +} diff --git a/comm/third_party/rnp/src/librepgp/stream-write.h b/comm/third_party/rnp/src/librepgp/stream-write.h new file mode 100644 index 0000000000..49431f9152 --- /dev/null +++ b/comm/third_party/rnp/src/librepgp/stream-write.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_WRITE_H_ +#define STREAM_WRITE_H_ + +#include +#include +#include +#include "rnp.h" +#include "stream-common.h" +#include "stream-ctx.h" + +typedef struct pgp_write_handler_t { + pgp_password_provider_t *password_provider; + pgp_key_provider_t * key_provider; + rnp_ctx_t * ctx; + + void *param; +} pgp_write_handler_t; + +/** @brief sign the input data, producing attached, detached or cleartext signature. + * Type of the signature is controlled by clearsign and detached fields of the + * rnp_ctx_t structure + * @param handler handler to respond on stream processor callbacks, and additional processing + * parameters, including rnp_ctx_t + * @param src input source: file, stdin, memory, whatever else conforming to pgp_source_t + * @param dst output destination: file, stdout, memory, whatever else conforming to pgp_dest_t + **/ +rnp_result_t rnp_sign_src(pgp_write_handler_t *handler, pgp_source_t *src, pgp_dest_t *dst); + +/** @brief encrypt and sign the input data. Signatures will be enrypted together with data. + * @param handler handler handler to respond on stream processor callbacks, and additional + * processing parameters, including rnp_ctx_t + * @param src input source: file, stdin, memory, whatever else conforming to pgp_source_t + * @param dst output destination: file, stdout, memory, whatever else conforming to pgp_dest_t + **/ +rnp_result_t rnp_encrypt_sign_src(pgp_write_handler_t *handler, + pgp_source_t * src, + pgp_dest_t * dst); + +/* Following functions are used only in tests currently. Later could be used in CLI for debug + * commands like --wrap-literal, --encrypt-raw, --compress-raw, etc. */ + +rnp_result_t rnp_compress_src(pgp_source_t & src, + pgp_dest_t & dst, + pgp_compression_type_t zalg, + int zlevel); + +rnp_result_t rnp_wrap_src(pgp_source_t & src, + pgp_dest_t & dst, + const std::string &filename, + uint32_t modtime); + +rnp_result_t rnp_raw_encrypt_src(pgp_source_t & src, + pgp_dest_t & dst, + const std::string & password, + rnp::SecurityContext &secctx); + +#endif diff --git a/comm/third_party/rnp/src/libsexp/LICENSE.md b/comm/third_party/rnp/src/libsexp/LICENSE.md new file mode 100644 index 0000000000..2e579d2074 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/LICENSE.md @@ -0,0 +1,34 @@ +Original MIT License +==================== + +Copyright 1997 Ronald L. Rivest, Butler Lampson +Copyright 1997 MIT Laboratory for Computer Science + +The code is available under the "MIT License" (open source). + +License text available at: +https://opensource.org/licenses/MIT + + +Ribose MIT License +==================== + +Copyright 2021-2022 Ribose Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/comm/third_party/rnp/src/libsexp/README.adoc b/comm/third_party/rnp/src/libsexp/README.adoc new file mode 100644 index 0000000000..69317257d4 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/README.adoc @@ -0,0 +1,195 @@ += S-expressions parser and generator library in C\++ (SEXP in C++) + +image:https://github.com/rnpgp/sexp/workflows/build-and-test/badge.svg["Build status Ubuntu/macOS/Windows", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test"] +image:https://github.com/rnpgp/sexp/workflows/build-and-test-rh/badge.svg["Build status CentOS/Fedora", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test-rh"] +image:https://github.com/rnpgp/sexp/workflows/build-and-test-deb/badge.svg["Build status Debian", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test-deb"] +image:https://github.com/rnpgp/sexp/workflows/build-and-test-msys/badge.svg["Build status MSys", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test-msys"] + + +image:https://codecov.io/gh/rnpgp/sexp/branch/feat/g23/graph/badge.svg["Code coverage", link="https://codecov.io/gh/rnpgp/sexp"] +image:https://github.com/rnpgp/sexp/workflows/CodeQL/badge.svg["CodeQL analysis", link="https://github.com/rnpgp/sexp/actions?workflow=CodeQL"] +image:https://scan.coverity.com/projects/27150/badge.svg["Coverity Scan Build Status", link="https://scan.coverity.com/projects/rnpgp-sexp"] + + +== Purpose + +This is a C++ library for working with S-expressions. This implementation +is derived from the reference SEXP C library developed by Professors Ronald Rivest +and Butler Lampson of MIT LCS (now CSAIL). + +This library differs from the original C implementation in the following ways: + +* It aims to be reuseable in C++ implementations and is importable via CMake. +* It includes a test suite for correctness testing and tests against malformed + S-expressions. +* It supports, and is tested against, all major platforms, including: +** Ubuntu, Debian, Fedora, CentOS +** macOS +** Windows +** msys +* It implements additional interface to work with S-expressions wrapped by GnuPG 2.3+ extended format as defined at https://github.com/gpg/gnupg/blob/master/agent/keyformat.txt + +The original C library is available at: + +* http://people.csail.mit.edu/rivest/sexp.html + + +== Background + +S-expressions are a data structure for representing complex data as a variation +on https://en.wikipedia.org/wiki/Lisp_(programming_language)[LISP] S-expressions. + +S-expressions were originally adopted for use in +http://theory.lcs.mit.edu/~cis/sdsi.html[SDSI] and +http://world.std.com/~cme/html/spki.html[SPKI]. + +SDSI has been developed by Professors +https://people.csail.mit.edu/rivest/index.html[Ronald L. Rivest] and Butler +Lampson of http://www.lcs.mit.edu/[MIT's Laboratory for Computer Science], +members of +http://theory.lcs.mit.edu/~cis[LCS's Cryptography and Information Security] +research group. + +NOTE: SDSI research has been supported by DARPA contract DABT63-96-C-0018, +"Security for Distributed Computer Systems". + +NOTE: SPKI has been developed by +http://www.clark.net/pub/cme/home.html[Carl Ellison] and others in the IETF SPKI +working group. + + +== Usage guide for S-expressions + +* https://people.csail.mit.edu/rivest/Sexp.txt[SEXP 1.0 guide] + + +== Code + +The library is a deep rework to C++ of the original +https://people.csail.mit.edu/rivest/sexp.html[SEXP library] that maintains full +support of original specification. + +While most applications will not need anything but the simple canonical and +transport formats; however, the code here is considerably more complex because +it also supports the advanced format, both for input and for output. + + +== Building and installation + +[source,sh] +---- +mkdir build +cd build +cmake .. +cmake --build . +ctest +cmake --install . +---- + + +== CMake script options + +`WITH_SEXP_TESTS:BOOL`:: +build tests (default: `ON`) + +`DOWNLOAD_GTEST`:: +if tests are build download googletest from github (default: `ON`) +when this option is set to `OFF` googletest binary package is a prerequisite for SEXP tests + +`WITH_SEXP_CLI:BOOL`:: +build the `sexp` client application (default: `ON`) + +`WITH_SANITIZERS:BOOL`:: +build with address and other sanitizers (default: `OFF`) +(requires clang compiler) + + + +== SEXP command-line utility + +The `sexp` command-line utility is reference parser and generator of S-expressions. +It can read, parse and print out SEXP in all defined formats. + +=== sexp switches: +[options="header"] +|======================================================================================================= +| Switch | Description | Default +3+| Input +| -i | input file name | read input from console (stdin) +| -p | prompt input if reading from console | disabled +| -s | treat input as a single SEXP string | disabled, input is treated as S-expression +3+| Output +| -o | output file name: | write output to console (stdout) +| -a | generate advanced transport format | enabled if no format is specified +| -b | generate base-64 transport format | disabled +| -c | generate canonical format | disabled +| -l | suppress linefeeds after output | disabled +| -w | set output line width (0 implies no constraint)| 75 +3+| Miscellaneous +| -x | execute repeatedly until EOF | process single S-expression then exit +| -h | print help message and exit | +|======================================================================================================= + +Running without switches implies: -p -a -b -c -x + +=== Usage examples: +Prompt for S-expressions input from console, parse and output it to `certificate.dat` in base64 transport format +[source] +---- +sexp -o certificate.dat -p -b + +> Input: +> (aa bb (cc dd)) +> +> Writing base64 (of canonical) output to 'certificate.dat' +---- + +Parse all S-expressions from `certificate.dat`, output them to console in advanced transport format with no prompts +[source] +---- +sexp -i certificate.dat -x + +> (2:aa2:bb(2:cc2:dd)) +---- + +Parse S-expressions from `certificate.dat`, output it to console in canonical, base64 and advanced format with prompts and no width limitation +[source] +---- +sexp -i certificate.dat -a -b -c -p -w 0 + +> Reading input from certificate.dat +> +> Canonical output: +> (2:aa2:bb(2:cc2:dd)) +> Base64 (of canonical) output: +> {KDI6YWEyOmJiKDI6Y2MyOmRkKSk=} +> Advanced transport output: +> (aa bb (cc dd)) +---- + +Repeatedly prompt for S-expressions input from console, parse and output it console in advanced, base64 and canonical formats +[source] +---- +sexp -p -a -b -c -x +---- +or just +---- +sexp + +> Input: +> (abc def (ghi jkl)) +> +> Canonical output: +> (3:abc3:def(3:ghi3:jkl)) +> Base64 (of canonical) output: +> {KDM6YWJjMzpkZWYoMzpnaGkzOmprbCkp} +> Advanced transport output: +> (abc def (ghi jkl)) +> +> Input: +> ^C +---- + +== License + +The code is made available as open-source software under the MIT License. diff --git a/comm/third_party/rnp/src/libsexp/include/sexp/ext-key-format.h b/comm/third_party/rnp/src/libsexp/include/sexp/ext-key-format.h new file mode 100644 index 0000000000..fc031a3473 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/include/sexp/ext-key-format.h @@ -0,0 +1,99 @@ +/** + * + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once + +#include +#include "sexp.h" + +namespace ext_key_format { + +void ext_key_error( + sexp::sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos); + +class ext_key_input_stream_t; + +class extended_private_key_t { + public: + // Comparison of names is done case insensitively !!! + struct ci_less { + // case-independent (ci) compare_less binary function + bool operator()(const std::string &s1, const std::string &s2) const + { + return std::lexicographical_compare( + s1.begin(), s1.end(), s2.begin(), s2.end(), [](char a, char b) { + return std::tolower(a) < std::tolower(b); + }); + } + }; + + // C++ 11 compatible version (no std::equals) + static bool iequals(const std::string &a, const std::string &b) + { + size_t sz = a.size(); + if (b.size() != sz) + return false; + for (size_t i = 0; i < sz; ++i) + if (tolower(a[i]) != tolower(b[i])) + return false; + return true; + } + + typedef std::multimap fields_map_t; + + sexp::sexp_list_t key; + fields_map_t fields; + + void parse(ext_key_input_stream_t &is); +}; + +class ext_key_input_stream_t : public sexp::sexp_input_stream_t { + private: + static const bool namechar[256]; /* true if allowed in the name field */ + + static bool is_newline_char(int c) { return c == '\r' || c == '\n'; }; + static bool is_namechar(int c) { return ((c >= 0 && c <= 255) && namechar[c]); } + + bool is_scanning_value; + bool has_key; + + int skip_line(void); + virtual int read_char(void); + std::string scan_name(int c); + std::string scan_value(void); + + public: + ext_key_input_stream_t(std::istream *i, size_t md = 0) + : sexp_input_stream_t(i, md), is_scanning_value(false), has_key(false) + { + } + virtual ~ext_key_input_stream_t() = default; + void scan(extended_private_key_t &extended_key); +}; +} // namespace ext_key_format diff --git a/comm/third_party/rnp/src/libsexp/include/sexp/sexp-error.h b/comm/third_party/rnp/src/libsexp/include/sexp/sexp-error.h new file mode 100644 index 0000000000..332a63bcad --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/include/sexp/sexp-error.h @@ -0,0 +1,77 @@ +/** + * + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace sexp { + +class sexp_exception_t : public std::exception { + public: + enum severity { error = 0, warning = 1 }; + + protected: + static severity verbosity; + static bool interactive; + + int position; // May be EOF aka -1 + severity level; + std::string message; + + public: + sexp_exception_t(std::string error_message, + severity error_level, + int error_position, + const char *prefix = "SEXP") + : position{error_position}, level{error_level}, + message{format(prefix, error_message, error_level, error_position)} {}; + + static std::string format(std::string prf, + std::string message, + severity level, + int position); + + static bool shall_throw(severity level) { return level == error || verbosity != error; }; + virtual const char *what(void) const throw() { return message.c_str(); }; + severity get_level(void) const { return level; }; + uint32_t get_position(void) const { return position; }; + static severity get_verbosity(void) { return verbosity; }; + static bool is_interactive(void) { return interactive; }; + static void set_verbosity(severity new_verbosity) { verbosity = new_verbosity; }; + static void set_interactive(bool new_interactive) { interactive = new_interactive; }; +}; + +void sexp_error( + sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos); + +} // namespace sexp diff --git a/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h b/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h new file mode 100644 index 0000000000..52cad55751 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h @@ -0,0 +1,435 @@ +/** + * + * Copyright (c) 2022-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP standard header file: sexp.h + * Ronald L. Rivest + * 6/29/1997 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sexp-error.h" + +namespace sexp { +/* + * SEXP octet_t definitions + * We maintain some presumable redundancy with ctype + * However, we do enforce 'C' locale this way + */ + +class sexp_char_defs_t { + protected: + static const bool base64digit[256]; /* true if c is base64 digit */ + static const bool tokenchar[256]; /* true if c can be in a token */ + static const unsigned char values[256][3]; /* values of c as { dec. hex, base64 } digit */ + static std::locale c_locale; + + static bool is_white_space(int c) + { + return c >= 0 && c <= 255 && std::isspace((char) c, c_locale); + }; + static bool is_dec_digit(int c) + { + return c >= 0 && c <= 255 && std::isdigit((char) c, c_locale); + }; + static bool is_hex_digit(int c) + { + return c >= 0 && c <= 255 && std::isxdigit((char) c, c_locale); + }; + static bool is_base64_digit(int c) { return c >= 0 && c <= 255 && base64digit[c]; }; + static bool is_token_char(int c) { return c >= 0 && c <= 255 && tokenchar[c]; }; + static bool is_alpha(int c) + { + return c >= 0 && c <= 255 && std::isalpha((char) c, c_locale); + }; + + /* decvalue(c) is value of c as dec digit */ + static unsigned char decvalue(int c) { return (c >= 0 && c <= 255) ? values[c][0] : 0; }; + /* hexvalue(c) is value of c as a hex digit */ + static unsigned char hexvalue(int c) { return (c >= 0 && c <= 255) ? values[c][1] : 0; }; + /* base64value(c) is value of c as base64 digit */ + static unsigned char base64value(int c) + { + return (c >= 0 && c <= 255) ? values[c][2] : 0; + }; +}; + +class sexp_string_t; +class sexp_list_t; + +class sexp_output_stream_t; +class sexp_input_stream_t; + +/* + * SEXP simple string + */ + +typedef uint8_t octet_t; + +class sexp_simple_string_t : public std::basic_string, private sexp_char_defs_t { + public: + sexp_simple_string_t(void) = default; + sexp_simple_string_t(const octet_t *dt) : std::basic_string{dt} {} + sexp_simple_string_t(const octet_t *bt, size_t ln) : std::basic_string{bt, ln} {} + sexp_simple_string_t &append(int c) + { + (*this) += (octet_t)(c & 0xFF); + return *this; + } + // Returns length for printing simple string as a token + size_t advanced_length_token(void) const { return length(); } + // Returns length for printing simple string as a base64 string + size_t advanced_length_base64(void) const { return (2 + 4 * ((length() + 2) / 3)); } + // Returns length for printing simple string ss in quoted-string mode + size_t advanced_length_quoted(void) const { return (1 + length() + 1); } + // Returns length for printing simple string ss in hexadecimal mode + size_t advanced_length_hexadecimal(void) const { return (1 + 2 * length() + 1); } + size_t advanced_length(sexp_output_stream_t *os) const; + + sexp_output_stream_t *print_canonical_verbatim(sexp_output_stream_t *os) const; + sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; + sexp_output_stream_t *print_token(sexp_output_stream_t *os) const; + sexp_output_stream_t *print_quoted(sexp_output_stream_t *os) const; + sexp_output_stream_t *print_hexadecimal(sexp_output_stream_t *os) const; + sexp_output_stream_t *print_base64(sexp_output_stream_t *os) const; + + bool can_print_as_quoted_string(void) const; + bool can_print_as_token(const sexp_output_stream_t *os) const; + + bool operator==(const char *right) const noexcept + { + return length() == std::strlen(right) && std::memcmp(data(), right, length()) == 0; + } + + bool operator!=(const char *right) const noexcept + { + return length() != std::strlen(right) || std::memcmp(data(), right, length()) != 0; + } + + unsigned as_unsigned() const noexcept + { + return empty() ? std::numeric_limits::max() : + (unsigned) atoi(reinterpret_cast(c_str())); + } +}; + +inline bool operator==(const sexp_simple_string_t *left, const std::string &right) noexcept +{ + return *left == right.c_str(); +} + +inline bool operator!=(const sexp_simple_string_t *left, const std::string &right) noexcept +{ + return *left != right.c_str(); +} + +/* + * SEXP object + */ + +class sexp_object_t { + public: + virtual ~sexp_object_t(){}; + + virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const = 0; + virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; + virtual size_t advanced_length(sexp_output_stream_t *os) const = 0; + + virtual sexp_list_t * sexp_list_view(void) noexcept { return nullptr; } + virtual sexp_string_t *sexp_string_view(void) noexcept { return nullptr; } + virtual bool is_sexp_list(void) const noexcept { return false; } + virtual bool is_sexp_string(void) const noexcept { return false; } + + virtual const sexp_list_t *sexp_list_at( + std::vector>::size_type pos) const noexcept + { + return nullptr; + } + virtual const sexp_string_t *sexp_string_at( + std::vector>::size_type pos) const noexcept + { + return nullptr; + } + virtual const sexp_simple_string_t *sexp_simple_string_at( + std::vector>::size_type pos) const noexcept + { + return nullptr; + } + virtual bool operator==(const char *right) const noexcept { return false; } + virtual bool operator!=(const char *right) const noexcept { return true; } + virtual unsigned as_unsigned() const noexcept + { + return std::numeric_limits::max(); + } +}; + +/* + * SEXP string + */ + +class sexp_string_t : public sexp_object_t { + protected: + bool with_presentation_hint; + sexp_simple_string_t presentation_hint; + sexp_simple_string_t data_string; + + public: + sexp_string_t(const octet_t *dt) : with_presentation_hint(false), data_string(dt) {} + sexp_string_t(const octet_t *bt, size_t ln) + : with_presentation_hint(false), data_string(bt, ln) + { + } + sexp_string_t(const std::string &str) + : with_presentation_hint(false), + data_string(reinterpret_cast(str.data())) + { + } + sexp_string_t(void) : with_presentation_hint(false) {} + sexp_string_t(sexp_input_stream_t *sis) { parse(sis); }; + + const bool has_presentation_hint(void) const noexcept { return with_presentation_hint; } + const sexp_simple_string_t &get_string(void) const noexcept { return data_string; } + const sexp_simple_string_t &set_string(const sexp_simple_string_t &ss) + { + return data_string = ss; + } + const sexp_simple_string_t &get_presentation_hint(void) const noexcept + { + return presentation_hint; + } + const sexp_simple_string_t &set_presentation_hint(const sexp_simple_string_t &ph) + { + with_presentation_hint = true; + return presentation_hint = ph; + } + + virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const; + virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; + virtual size_t advanced_length(sexp_output_stream_t *os) const; + + virtual sexp_string_t *sexp_string_view(void) noexcept { return this; } + virtual bool is_sexp_string(void) const noexcept { return true; } + + virtual bool operator==(const char *right) const noexcept { return data_string == right; } + virtual bool operator!=(const char *right) const noexcept { return data_string != right; } + + void parse(sexp_input_stream_t *sis); + virtual unsigned as_unsigned() const noexcept { return data_string.as_unsigned(); } +}; + +inline bool operator==(const sexp_string_t *left, const std::string &right) noexcept +{ + return *left == right.c_str(); +} + +inline bool operator!=(const sexp_string_t *left, const std::string &right) noexcept +{ + return *left != right.c_str(); +} + +/* + * SEXP list + */ + +class sexp_list_t : public sexp_object_t, public std::vector> { + public: + virtual ~sexp_list_t() {} + + virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const; + virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; + virtual size_t advanced_length(sexp_output_stream_t *os) const; + + virtual sexp_list_t *sexp_list_view(void) noexcept { return this; } + virtual bool is_sexp_list(void) const noexcept { return true; } + + virtual const sexp_list_t *sexp_list_at(size_type pos) const noexcept + { + return pos < size() ? (*at(pos)).sexp_list_view() : nullptr; + } + virtual const sexp_string_t *sexp_string_at(size_type pos) const noexcept + { + return pos < size() ? (*at(pos)).sexp_string_view() : nullptr; + } + const sexp_simple_string_t *sexp_simple_string_at(size_type pos) const noexcept + { + auto s = sexp_string_at(pos); + return s != nullptr ? &s->get_string() : nullptr; + } + + void parse(sexp_input_stream_t *sis); +}; + +/* + * SEXP input stream + */ + +class sexp_input_stream_t : public sexp_char_defs_t { + protected: + std::istream *input_file; + uint32_t byte_size; /* 4 or 6 or 8 == currently scanning mode */ + int next_char; /* character currently being scanned */ + uint32_t bits; /* Bits waiting to be used */ + uint32_t n_bits; /* number of such bits waiting to be used */ + int count; /* number of 8-bit characters output by get_char */ + size_t depth; /* current depth of nested SEXP lists */ + size_t max_depth; /* maximum allowed depth of nested SEXP lists, 0 if no limit */ + + virtual int read_char(void); + + public: + sexp_input_stream_t(std::istream *i, size_t max_depth = 0); + virtual ~sexp_input_stream_t() = default; + sexp_input_stream_t *set_input(std::istream *i, size_t max_depth = 0); + sexp_input_stream_t *set_byte_size(uint32_t new_byte_size); + uint32_t get_byte_size(void) { return byte_size; } + sexp_input_stream_t *get_char(void); + sexp_input_stream_t *skip_white_space(void); + sexp_input_stream_t *skip_char(int c); + sexp_input_stream_t *increase_depth(void) + { + if (max_depth != 0 && ++depth > max_depth) + sexp_error(sexp_exception_t::error, + "Maximum allowed SEXP list depth (%u) is exceeded", + max_depth, + 0, + count); + return this; + } + sexp_input_stream_t *decrease_depth(void) + { + depth--; + return this; + } + + std::shared_ptr scan_to_eof(); + std::shared_ptr scan_object(void); + std::shared_ptr scan_string(void); + std::shared_ptr scan_list(void); + sexp_simple_string_t scan_simple_string(void); + void scan_token(sexp_simple_string_t &ss); + void scan_verbatim_string(sexp_simple_string_t &ss, uint32_t length); + void scan_quoted_string(sexp_simple_string_t &ss, uint32_t length); + void scan_hexadecimal_string(sexp_simple_string_t &ss, uint32_t length); + void scan_base64_string(sexp_simple_string_t &ss, uint32_t length); + uint32_t scan_decimal_string(void); + + int get_next_char(void) const { return next_char; } + int set_next_char(int c) { return next_char = c; } +}; + +/* + * SEXP output stream + */ + +class sexp_output_stream_t { + public: + const uint32_t default_line_length = 75; + enum sexp_print_mode { /* PRINTING MODES */ + canonical = 1, /* standard for hashing and tranmission */ + base64 = 2, /* base64 version of canonical */ + advanced = 3 /* pretty-printed */ + }; + + protected: + std::ostream * output_file; + uint32_t base64_count; /* number of hex or base64 chars printed this region */ + uint32_t byte_size; /* 4 or 6 or 8 depending on output mode */ + uint32_t bits; /* bits waiting to go out */ + uint32_t n_bits; /* number of bits waiting to go out */ + sexp_print_mode mode; /* base64, advanced, or canonical */ + uint32_t column; /* column where next character will go */ + uint32_t max_column; /* max usable column, or 0 if no maximum */ + uint32_t indent; /* current indentation level (starts at 0) */ + public: + sexp_output_stream_t(std::ostream *o); + sexp_output_stream_t *set_output(std::ostream *o); + sexp_output_stream_t *put_char(int c); /* output a character */ + sexp_output_stream_t *new_line(sexp_print_mode mode); /* go to next line (and indent) */ + sexp_output_stream_t *var_put_char(int c); + sexp_output_stream_t *flush(void); + sexp_output_stream_t *print_decimal(uint64_t n); + + sexp_output_stream_t *change_output_byte_size(int newByteSize, sexp_print_mode mode); + + sexp_output_stream_t *print_canonical(const std::shared_ptr &obj) + { + return obj->print_canonical(this); + } + sexp_output_stream_t *print_advanced(const std::shared_ptr &obj) + { + return obj->print_advanced(this); + }; + sexp_output_stream_t *print_base64(const std::shared_ptr &obj); + sexp_output_stream_t *print_canonical(const sexp_simple_string_t *ss) + { + return ss->print_canonical_verbatim(this); + } + sexp_output_stream_t *print_advanced(const sexp_simple_string_t *ss) + { + return ss->print_advanced(this); + }; + + uint32_t get_byte_size(void) const { return byte_size; } + uint32_t get_column(void) const { return column; } + sexp_output_stream_t *reset_column(void) + { + column = 0; + return this; + } + uint32_t get_max_column(void) const { return max_column; } + sexp_output_stream_t *set_max_column(uint32_t mc) + { + max_column = mc; + return this; + } + sexp_output_stream_t *inc_indent(void) + { + ++indent; + return this; + } + sexp_output_stream_t *dec_indent(void) + { + --indent; + return this; + } +}; + +} // namespace sexp diff --git a/comm/third_party/rnp/src/libsexp/src/ext-key-format.cpp b/comm/third_party/rnp/src/libsexp/src/ext-key-format.cpp new file mode 100644 index 0000000000..a0c0d04b73 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/ext-key-format.cpp @@ -0,0 +1,314 @@ +/** + * + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +using namespace sexp; + +namespace ext_key_format { + +void ext_key_error( + sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos) +{ + char tmp[256]; + sexp_exception_t::severity l = (sexp_exception_t::severity) level; + snprintf(tmp, sizeof(tmp) / sizeof(tmp[0]), msg, c1, c2); + if (sexp_exception_t::shall_throw(l)) + throw sexp_exception_t(tmp, l, pos, "EXTENDED KEY FORMAT"); + if (sexp_exception_t::is_interactive()) { + std::cout.flush() << std::endl + << "*** " + << sexp_exception_t::format("EXTENDED KEY FORMAT", tmp, l, pos) + << " ***" << std::endl; + } +} + +// Valid characters are all ASCII letters, numbers and the hyphen. +// true if allowed in the name field +const bool ext_key_input_stream_t::namechar[256] = { + /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, + /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, + /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, + /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, + /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, + /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, + /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, + /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, + /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, + /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, + /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, + /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, + /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, + /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, + /* 0x2a * */ false, /* 0x2b + */ false, /* 0x2c , */ false, + /* 0x2d - */ true, /* 0x2e . */ false, /* 0x2f / */ false, + /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, + /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, + /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, + /* 0x39 9 */ true, /* 0x3a : */ false, /* 0x3b ; */ false, + /* 0x3c < */ false, /* 0x3d = */ false, /* 0x3e > */ false, + /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, + /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, + /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, + /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, + /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, + /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, + /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, + /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, + /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, + /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, + /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ false, + /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, + /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, + /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, + /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, + /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, + /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, + /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, + /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, + /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, + /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, + /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, + /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, + /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, + /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, + /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, + /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, + /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, + /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, + /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, + /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, + /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, + /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, + /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, + /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, + /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, + /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, + /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, + /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, + /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, + /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, + /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, + /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, + /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, + /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, + /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, + /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, + /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, + /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, + /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, + /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, + /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, + /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, + /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, + /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, + /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, + /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, + /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, + /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, + /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, + /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, + /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, + /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, + /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; + +/* + * ext_key_input_stream_t::skip_line + */ +int ext_key_input_stream_t::skip_line(void) +{ + int c; + do { + c = input_file->get(); + } while (!is_newline_char(c) && c != EOF); + return c; +} + +/* + * ext_key_input_stream_t::read_char + */ +int ext_key_input_stream_t::read_char(void) +{ + int lookahead_1 = input_file->get(); + count++; + if (is_scanning_value && is_newline_char(lookahead_1)) { + while (true) { + int lookahead_2 = input_file->peek(); + if (lookahead_1 == '\r' && lookahead_2 == '\n') { + lookahead_1 = input_file->get(); + count++; + lookahead_2 = input_file->peek(); + } + if (lookahead_2 == ' ') { + input_file->get(); + count++; + lookahead_2 = input_file->peek(); + if (lookahead_2 == '#') { + lookahead_1 = skip_line(); + continue; + } + if (is_newline_char(lookahead_2)) { + lookahead_1 = lookahead_2; + continue; + } + lookahead_1 = input_file->get(); + count++; + } + return lookahead_1; + } + } + return lookahead_1; +} + +/* + * ext_key_input_stream_t::scan_name + * A name must start with a letter and end with a colon. Valid characters are all ASCII + * letters, numbers and the hyphen. Comparison of names is done case insensitively. Names may + * be used several times to represent an array of values. Note that the name “Key†is special + * in that it is madandory must occur only once. + */ + +std::string ext_key_input_stream_t::scan_name(int c) +{ + std::string name; + if (!is_alpha(c)) { + ext_key_error(sexp_exception_t::error, + isprint(next_char) ? + "unexpected character '%c' (0x%x) found starting a name field" : + "unexpected character '0x%x' found starting a name field", + c, + c, + count); + } else { + name += (char) c; + c = read_char(); + while (c != ':') { + if (c == EOF) { + ext_key_error(sexp_exception_t::error, "unexpected end of file", 0, 0, count); + } + if (is_newline_char(c)) { + ext_key_error(sexp_exception_t::error, "unexpected end of line", 0, 0, count); + } + if (!is_namechar(c)) { + ext_key_error(sexp_exception_t::error, + isprint(next_char) ? + "unexpected character '%c' (0x%x) found in a name field" : + "unexpected character '0x%x' found in a name field", + c, + c, + count); + } + name += (int) c; + c = read_char(); + } + } + return name; +} + +/* + * ext_key_input_stream_t::scan_value + * Values are UTF-8 encoded strings. Values can be wrapped at any point, and continued in + * the next line indicated by leading whitespace. A continuation line with one leading space + * does not introduce a blank so that the lines can be effectively concatenated. A blank + * line as part of a continuation line encodes a newline. + */ +std::string ext_key_input_stream_t::scan_value(void) +{ + std::string value; + int c; + do { + c = read_char(); + } while (is_white_space(c)); + while (c != EOF && !is_newline_char(c)) { + value += c; + c = read_char(); + } + return value; +} + +/* + * ext_key_input_stream_t::scan + * GnuPG 2.3+ uses a new format to store private keys that is both more flexible and easier to + * read and edit by human beings. The new format stores name, value-pairs using the common mail + * and http header convention. + */ +void ext_key_input_stream_t::scan(extended_private_key_t &res) +{ + set_byte_size(8); + int c = read_char(); + if (c == '(') { + set_next_char(c); + res.key.parse(this); + has_key = true; + } else { + while (c != EOF) { + // Comparison of names is done case insensitively + std::string name = scan_name(c); + // The name “Key†is special in that it is mandatory and must occur only once. + // The associated value holds the actual S-expression with the cryptographic key. + // The S-expression is formatted using the ‘Advanced Format’ + // (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters so that the file + // can be easily inspected and edited. + is_scanning_value = true; + if (extended_private_key_t::iequals(name, "key")) { + if (has_key) { + ext_key_error(sexp_exception_t::error, + "'key' field must occur only once", + 0, + 0, + count); + } + do { + c = read_char(); + } while (is_white_space(c)); + set_next_char(c); + res.key.parse(this); + has_key = true; + } else { + std::string value = scan_value(); + res.fields.insert(std::pair{name, value}); + } + c = read_char(); + is_scanning_value = false; + } + } + if (!has_key) { + ext_key_error(sexp_exception_t::error, "missing mandatory 'key' field", 0, 0, count); + } +} + +/* + * extended_private_key_t::parse + */ +void extended_private_key_t::parse(ext_key_input_stream_t &is) +{ + is.scan(*this); +} + +} // namespace ext_key_format \ No newline at end of file diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-char-defs.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-char-defs.cpp new file mode 100644 index 0000000000..8a727d5737 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-char-defs.cpp @@ -0,0 +1,351 @@ +/** + * + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP implementation code sexp-input.c + * Ron Rivest + * 7/21/1997 + */ + +#include + +namespace sexp { + +/**************************************/ +/* CHARACTER ROUTINES AND DEFINITIONS */ +/**************************************/ +std::locale sexp_char_defs_t::c_locale{"C"}; + +const unsigned char sexp_char_defs_t::values[256][3] = + {/* values of c as { dec. hex, base64 } digit */ + {/* 0x00 */ 0x00, 0x00, 0x00}, {/* 0x01 */ 0x00, 0x00, 0x00}, + {/* 0x02 */ 0x00, 0x00, 0x00}, {/* 0x03 */ 0x00, 0x00, 0x00}, + {/* 0x04 */ 0x00, 0x00, 0x00}, {/* 0x05 */ 0x00, 0x00, 0x00}, + {/* 0x06 */ 0x00, 0x00, 0x00}, {/* 0x07 */ 0x00, 0x00, 0x00}, + {/* 0x08 */ 0x00, 0x00, 0x00}, {/* 0x09 */ 0x00, 0x00, 0x00}, + {/* 0x0a */ 0x00, 0x00, 0x00}, {/* 0x0b */ 0x00, 0x00, 0x00}, + {/* 0x0c */ 0x00, 0x00, 0x00}, {/* 0x0d */ 0x00, 0x00, 0x00}, + {/* 0x0e */ 0x00, 0x00, 0x00}, {/* 0x0f */ 0x00, 0x00, 0x00}, + {/* 0x10 */ 0x00, 0x00, 0x00}, {/* 0x11 */ 0x00, 0x00, 0x00}, + {/* 0x12 */ 0x00, 0x00, 0x00}, {/* 0x13 */ 0x00, 0x00, 0x00}, + {/* 0x14 */ 0x00, 0x00, 0x00}, {/* 0x15 */ 0x00, 0x00, 0x00}, + {/* 0x16 */ 0x00, 0x00, 0x00}, {/* 0x17 */ 0x00, 0x00, 0x00}, + {/* 0x18 */ 0x00, 0x00, 0x00}, {/* 0x19 */ 0x00, 0x00, 0x00}, + {/* 0x1a */ 0x00, 0x00, 0x00}, {/* 0x1b */ 0x00, 0x00, 0x00}, + {/* 0x1c */ 0x00, 0x00, 0x00}, {/* 0x1d */ 0x00, 0x00, 0x00}, + {/* 0x1e */ 0x00, 0x00, 0x00}, {/* 0x1f */ 0x00, 0x00, 0x00}, + {/* 0x20 */ 0x00, 0x00, 0x00}, {/* 0x21 ! */ 0x00, 0x00, 0x00}, + {/* 0x22 " */ 0x00, 0x00, 0x00}, {/* 0x23 # */ 0x00, 0x00, 0x00}, + {/* 0x24 $ */ 0x00, 0x00, 0x00}, {/* 0x25 % */ 0x00, 0x00, 0x00}, + {/* 0x26 & */ 0x00, 0x00, 0x00}, {/* 0x27 ' */ 0x00, 0x00, 0x00}, + {/* 0x28 ( */ 0x00, 0x00, 0x00}, {/* 0x29 ) */ 0x00, 0x00, 0x00}, + {/* 0x2a * */ 0x00, 0x00, 0x00}, {/* 0x2b + */ 0x00, 0x00, 0x3e}, + {/* 0x2c , */ 0x00, 0x00, 0x00}, {/* 0x2d - */ 0x00, 0x00, 0x00}, + {/* 0x2e . */ 0x00, 0x00, 0x00}, {/* 0x2f / */ 0x00, 0x00, 0x3f}, + {/* 0x30 0 */ 0x00, 0x00, 0x34}, {/* 0x31 1 */ 0x01, 0x01, 0x35}, + {/* 0x32 2 */ 0x02, 0x02, 0x36}, {/* 0x33 3 */ 0x03, 0x03, 0x37}, + {/* 0x34 4 */ 0x04, 0x04, 0x38}, {/* 0x35 5 */ 0x05, 0x05, 0x39}, + {/* 0x36 6 */ 0x06, 0x06, 0x3a}, {/* 0x37 7 */ 0x07, 0x07, 0x3b}, + {/* 0x38 8 */ 0x08, 0x08, 0x3c}, {/* 0x39 9 */ 0x09, 0x09, 0x3d}, + {/* 0x3a : */ 0x00, 0x00, 0x00}, {/* 0x3b ; */ 0x00, 0x00, 0x00}, + {/* 0x3c < */ 0x00, 0x00, 0x00}, {/* 0x3d = */ 0x00, 0x00, 0x00}, + {/* 0x3e > */ 0x00, 0x00, 0x00}, {/* 0x3f ? */ 0x00, 0x00, 0x00}, + {/* 0x40 @ */ 0x00, 0x00, 0x00}, {/* 0x41 A */ 0x00, 0x0a, 0x00}, + {/* 0x42 B */ 0x00, 0x0b, 0x01}, {/* 0x43 C */ 0x00, 0x0c, 0x02}, + {/* 0x44 D */ 0x00, 0x0d, 0x03}, {/* 0x45 E */ 0x00, 0x0e, 0x04}, + {/* 0x46 F */ 0x00, 0x0f, 0x05}, {/* 0x47 G */ 0x00, 0x00, 0x06}, + {/* 0x48 H */ 0x00, 0x00, 0x07}, {/* 0x49 I */ 0x00, 0x00, 0x08}, + {/* 0x4a J */ 0x00, 0x00, 0x09}, {/* 0x4b K */ 0x00, 0x00, 0x0a}, + {/* 0x4c L */ 0x00, 0x00, 0x0b}, {/* 0x4d M */ 0x00, 0x00, 0x0c}, + {/* 0x4e N */ 0x00, 0x00, 0x0d}, {/* 0x4f O */ 0x00, 0x00, 0x0e}, + {/* 0x50 P */ 0x00, 0x00, 0x0f}, {/* 0x51 Q */ 0x00, 0x00, 0x10}, + {/* 0x52 R */ 0x00, 0x00, 0x11}, {/* 0x53 S */ 0x00, 0x00, 0x12}, + {/* 0x54 T */ 0x00, 0x00, 0x13}, {/* 0x55 U */ 0x00, 0x00, 0x14}, + {/* 0x56 V */ 0x00, 0x00, 0x15}, {/* 0x57 W */ 0x00, 0x00, 0x16}, + {/* 0x58 X */ 0x00, 0x00, 0x17}, {/* 0x59 Y */ 0x00, 0x00, 0x18}, + {/* 0x5a Z */ 0x00, 0x00, 0x19}, {/* 0x5b [ */ 0x00, 0x00, 0x00}, + {/* 0x5c \ */ 0x00, 0x00, 0x00}, {/* 0x5d ] */ 0x00, 0x00, 0x00}, + {/* 0x5e ^ */ 0x00, 0x00, 0x00}, {/* 0x5f _ */ 0x00, 0x00, 0x00}, + {/* 0x60 ` */ 0x00, 0x00, 0x00}, {/* 0x61 a */ 0x00, 0x0a, 0x1a}, + {/* 0x62 b */ 0x00, 0x0b, 0x1b}, {/* 0x63 c */ 0x00, 0x0c, 0x1c}, + {/* 0x64 d */ 0x00, 0x0d, 0x1d}, {/* 0x65 e */ 0x00, 0x0e, 0x1e}, + {/* 0x66 f */ 0x00, 0x0f, 0x1f}, {/* 0x67 g */ 0x00, 0x00, 0x20}, + {/* 0x68 h */ 0x00, 0x00, 0x21}, {/* 0x69 i */ 0x00, 0x00, 0x22}, + {/* 0x6a j */ 0x00, 0x00, 0x23}, {/* 0x6b k */ 0x00, 0x00, 0x24}, + {/* 0x6c l */ 0x00, 0x00, 0x25}, {/* 0x6d m */ 0x00, 0x00, 0x26}, + {/* 0x6e n */ 0x00, 0x00, 0x27}, {/* 0x6f o */ 0x00, 0x00, 0x28}, + {/* 0x70 p */ 0x00, 0x00, 0x29}, {/* 0x71 q */ 0x00, 0x00, 0x2a}, + {/* 0x72 r */ 0x00, 0x00, 0x2b}, {/* 0x73 s */ 0x00, 0x00, 0x2c}, + {/* 0x74 t */ 0x00, 0x00, 0x2d}, {/* 0x75 u */ 0x00, 0x00, 0x2e}, + {/* 0x76 v */ 0x00, 0x00, 0x2f}, {/* 0x77 w */ 0x00, 0x00, 0x30}, + {/* 0x78 x */ 0x00, 0x00, 0x31}, {/* 0x79 y */ 0x00, 0x00, 0x32}, + {/* 0x7a z */ 0x00, 0x00, 0x33}, {/* 0x7b { */ 0x00, 0x00, 0x00}, + {/* 0x7c | */ 0x00, 0x00, 0x00}, {/* 0x7d } */ 0x00, 0x00, 0x00}, + {/* 0x7e ~ */ 0x00, 0x00, 0x00}, {/* 0x7f */ 0x00, 0x00, 0x00}, + {/* 0x80 */ 0x00, 0x00, 0x00}, {/* 0x81 */ 0x00, 0x00, 0x00}, + {/* 0x82 */ 0x00, 0x00, 0x00}, {/* 0x83 */ 0x00, 0x00, 0x00}, + {/* 0x84 */ 0x00, 0x00, 0x00}, {/* 0x85 */ 0x00, 0x00, 0x00}, + {/* 0x86 */ 0x00, 0x00, 0x00}, {/* 0x87 */ 0x00, 0x00, 0x00}, + {/* 0x88 */ 0x00, 0x00, 0x00}, {/* 0x89 */ 0x00, 0x00, 0x00}, + {/* 0x8a */ 0x00, 0x00, 0x00}, {/* 0x8b */ 0x00, 0x00, 0x00}, + {/* 0x8c */ 0x00, 0x00, 0x00}, {/* 0x8d */ 0x00, 0x00, 0x00}, + {/* 0x8e */ 0x00, 0x00, 0x00}, {/* 0x8f */ 0x00, 0x00, 0x00}, + {/* 0x90 */ 0x00, 0x00, 0x00}, {/* 0x91 */ 0x00, 0x00, 0x00}, + {/* 0x92 */ 0x00, 0x00, 0x00}, {/* 0x93 */ 0x00, 0x00, 0x00}, + {/* 0x94 */ 0x00, 0x00, 0x00}, {/* 0x95 */ 0x00, 0x00, 0x00}, + {/* 0x96 */ 0x00, 0x00, 0x00}, {/* 0x97 */ 0x00, 0x00, 0x00}, + {/* 0x98 */ 0x00, 0x00, 0x00}, {/* 0x99 */ 0x00, 0x00, 0x00}, + {/* 0x9a */ 0x00, 0x00, 0x00}, {/* 0x9b */ 0x00, 0x00, 0x00}, + {/* 0x9c */ 0x00, 0x00, 0x00}, {/* 0x9d */ 0x00, 0x00, 0x00}, + {/* 0x9e */ 0x00, 0x00, 0x00}, {/* 0x9f */ 0x00, 0x00, 0x00}, + {/* 0xa0 */ 0x00, 0x00, 0x00}, {/* 0xa1 */ 0x00, 0x00, 0x00}, + {/* 0xa2 */ 0x00, 0x00, 0x00}, {/* 0xa3 */ 0x00, 0x00, 0x00}, + {/* 0xa4 */ 0x00, 0x00, 0x00}, {/* 0xa5 */ 0x00, 0x00, 0x00}, + {/* 0xa6 */ 0x00, 0x00, 0x00}, {/* 0xa7 */ 0x00, 0x00, 0x00}, + {/* 0xa8 */ 0x00, 0x00, 0x00}, {/* 0xa9 */ 0x00, 0x00, 0x00}, + {/* 0xaa */ 0x00, 0x00, 0x00}, {/* 0xab */ 0x00, 0x00, 0x00}, + {/* 0xac */ 0x00, 0x00, 0x00}, {/* 0xad */ 0x00, 0x00, 0x00}, + {/* 0xae */ 0x00, 0x00, 0x00}, {/* 0xaf */ 0x00, 0x00, 0x00}, + {/* 0xb0 */ 0x00, 0x00, 0x00}, {/* 0xb1 */ 0x00, 0x00, 0x00}, + {/* 0xb2 */ 0x00, 0x00, 0x00}, {/* 0xb3 */ 0x00, 0x00, 0x00}, + {/* 0xb4 */ 0x00, 0x00, 0x00}, {/* 0xb5 */ 0x00, 0x00, 0x00}, + {/* 0xb6 */ 0x00, 0x00, 0x00}, {/* 0xb7 */ 0x00, 0x00, 0x00}, + {/* 0xb8 */ 0x00, 0x00, 0x00}, {/* 0xb9 */ 0x00, 0x00, 0x00}, + {/* 0xba */ 0x00, 0x00, 0x00}, {/* 0xbb */ 0x00, 0x00, 0x00}, + {/* 0xbc */ 0x00, 0x00, 0x00}, {/* 0xbd */ 0x00, 0x00, 0x00}, + {/* 0xbe */ 0x00, 0x00, 0x00}, {/* 0xbf */ 0x00, 0x00, 0x00}, + {/* 0xc0 */ 0x00, 0x00, 0x00}, {/* 0xc1 */ 0x00, 0x00, 0x00}, + {/* 0xc2 */ 0x00, 0x00, 0x00}, {/* 0xc3 */ 0x00, 0x00, 0x00}, + {/* 0xc4 */ 0x00, 0x00, 0x00}, {/* 0xc5 */ 0x00, 0x00, 0x00}, + {/* 0xc6 */ 0x00, 0x00, 0x00}, {/* 0xc7 */ 0x00, 0x00, 0x00}, + {/* 0xc8 */ 0x00, 0x00, 0x00}, {/* 0xc9 */ 0x00, 0x00, 0x00}, + {/* 0xca */ 0x00, 0x00, 0x00}, {/* 0xcb */ 0x00, 0x00, 0x00}, + {/* 0xcc */ 0x00, 0x00, 0x00}, {/* 0xcd */ 0x00, 0x00, 0x00}, + {/* 0xce */ 0x00, 0x00, 0x00}, {/* 0xcf */ 0x00, 0x00, 0x00}, + {/* 0xd0 */ 0x00, 0x00, 0x00}, {/* 0xd1 */ 0x00, 0x00, 0x00}, + {/* 0xd2 */ 0x00, 0x00, 0x00}, {/* 0xd3 */ 0x00, 0x00, 0x00}, + {/* 0xd4 */ 0x00, 0x00, 0x00}, {/* 0xd5 */ 0x00, 0x00, 0x00}, + {/* 0xd6 */ 0x00, 0x00, 0x00}, {/* 0xd7 */ 0x00, 0x00, 0x00}, + {/* 0xd8 */ 0x00, 0x00, 0x00}, {/* 0xd9 */ 0x00, 0x00, 0x00}, + {/* 0xda */ 0x00, 0x00, 0x00}, {/* 0xdb */ 0x00, 0x00, 0x00}, + {/* 0xdc */ 0x00, 0x00, 0x00}, {/* 0xdd */ 0x00, 0x00, 0x00}, + {/* 0xde */ 0x00, 0x00, 0x00}, {/* 0xdf */ 0x00, 0x00, 0x00}, + {/* 0xe0 */ 0x00, 0x00, 0x00}, {/* 0xe1 */ 0x00, 0x00, 0x00}, + {/* 0xe2 */ 0x00, 0x00, 0x00}, {/* 0xe3 */ 0x00, 0x00, 0x00}, + {/* 0xe4 */ 0x00, 0x00, 0x00}, {/* 0xe5 */ 0x00, 0x00, 0x00}, + {/* 0xe6 */ 0x00, 0x00, 0x00}, {/* 0xe7 */ 0x00, 0x00, 0x00}, + {/* 0xe8 */ 0x00, 0x00, 0x00}, {/* 0xe9 */ 0x00, 0x00, 0x00}, + {/* 0xea */ 0x00, 0x00, 0x00}, {/* 0xeb */ 0x00, 0x00, 0x00}, + {/* 0xec */ 0x00, 0x00, 0x00}, {/* 0xed */ 0x00, 0x00, 0x00}, + {/* 0xee */ 0x00, 0x00, 0x00}, {/* 0xef */ 0x00, 0x00, 0x00}, + {/* 0xf0 */ 0x00, 0x00, 0x00}, {/* 0xf1 */ 0x00, 0x00, 0x00}, + {/* 0xf2 */ 0x00, 0x00, 0x00}, {/* 0xf3 */ 0x00, 0x00, 0x00}, + {/* 0xf4 */ 0x00, 0x00, 0x00}, {/* 0xf5 */ 0x00, 0x00, 0x00}, + {/* 0xf6 */ 0x00, 0x00, 0x00}, {/* 0xf7 */ 0x00, 0x00, 0x00}, + {/* 0xf8 */ 0x00, 0x00, 0x00}, {/* 0xf9 */ 0x00, 0x00, 0x00}, + {/* 0xfa */ 0x00, 0x00, 0x00}, {/* 0xfb */ 0x00, 0x00, 0x00}, + {/* 0xfc */ 0x00, 0x00, 0x00}, {/* 0xfd */ 0x00, 0x00, 0x00}, + {/* 0xfe */ 0x00, 0x00, 0x00}, {/* 0xff */ 0x00, 0x00, 0x00}}; + +const bool sexp_char_defs_t::base64digit[256] = + {/* c is base64 digit */ + /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, + /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, + /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, + /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, + /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, + /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, + /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, + /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, + /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, + /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, + /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, + /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, + /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, + /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, + /* 0x2a * */ false, /* 0x2b + */ true, /* 0x2c , */ false, + /* 0x2d - */ false, /* 0x2e . */ false, /* 0x2f / */ true, + /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, + /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, + /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, + /* 0x39 9 */ true, /* 0x3a : */ false, /* 0x3b ; */ false, + /* 0x3c < */ false, /* 0x3d = */ false, /* 0x3e > */ false, + /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, + /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, + /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, + /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, + /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, + /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, + /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, + /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, + /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, + /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, + /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ false, + /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, + /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, + /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, + /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, + /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, + /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, + /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, + /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, + /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, + /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, + /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, + /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, + /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, + /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, + /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, + /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, + /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, + /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, + /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, + /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, + /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, + /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, + /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, + /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, + /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, + /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, + /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, + /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, + /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, + /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, + /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, + /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, + /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, + /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, + /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, + /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, + /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, + /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, + /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, + /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, + /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, + /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, + /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, + /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, + /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, + /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, + /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, + /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, + /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, + /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, + /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, + /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, + /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; + +const bool sexp_char_defs_t::tokenchar[256] = + {/* c can be in a token */ + /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, + /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, + /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, + /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, + /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, + /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, + /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, + /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, + /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, + /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, + /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, + /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, + /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, + /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, + /* 0x2a * */ true, /* 0x2b + */ true, /* 0x2c , */ false, + /* 0x2d - */ true, /* 0x2e . */ true, /* 0x2f / */ true, + /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, + /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, + /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, + /* 0x39 9 */ true, /* 0x3a : */ true, /* 0x3b ; */ false, + /* 0x3c < */ false, /* 0x3d = */ true, /* 0x3e > */ false, + /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, + /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, + /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, + /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, + /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, + /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, + /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, + /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, + /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, + /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, + /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ true, + /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, + /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, + /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, + /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, + /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, + /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, + /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, + /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, + /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, + /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, + /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, + /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, + /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, + /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, + /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, + /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, + /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, + /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, + /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, + /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, + /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, + /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, + /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, + /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, + /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, + /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, + /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, + /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, + /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, + /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, + /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, + /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, + /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, + /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, + /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, + /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, + /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, + /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, + /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, + /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, + /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, + /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, + /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, + /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, + /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, + /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, + /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, + /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, + /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, + /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, + /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, + /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, + /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; + +} // namespace sexp diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-error.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-error.cpp new file mode 100644 index 0000000000..992b680405 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-error.cpp @@ -0,0 +1,62 @@ +/** + * + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +namespace sexp { + +sexp_exception_t::severity sexp_exception_t::verbosity = sexp_exception_t::error; +bool sexp_exception_t::interactive = false; + +std::string sexp_exception_t::format(std::string prf, + std::string message, + severity level, + int position) +{ + std::string r = prf + (level == error ? " ERROR: " : " WARNING: ") + message; + if (position >= 0) + r += " at position " + std::to_string(position); + return r; +}; + +void sexp_error( + sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos) +{ + char tmp[256]; + sexp_exception_t::severity l = (sexp_exception_t::severity) level; + snprintf(tmp, sizeof(tmp) / sizeof(tmp[0]), msg, c1, c2); + if (sexp_exception_t::shall_throw(l)) + throw sexp_exception_t(tmp, l, pos); + if (sexp_exception_t::is_interactive()) { + std::cout.flush() << std::endl + << "*** " << sexp_exception_t::format("SEXP", tmp, l, pos) << " ***" + << std::endl; + } +} +} // namespace sexp \ No newline at end of file diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-input.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-input.cpp new file mode 100644 index 0000000000..daa8984551 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-input.cpp @@ -0,0 +1,507 @@ +/** + * + * Copyright (c) 2022-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP implementation code sexp-input.c + * Ron Rivest + * 7/21/1997 + */ + +#include + +namespace sexp { + +/* + * newSexpInputStream() + * Creates and initializes a new sexp_input_stream_t object. + * (Prefixes stream with one blank, and initializes stream + * so that it reads from standard input.) + */ +std::istream *input_file; +uint32_t byte_size; /* 4 or 6 or 8 == currently scanning mode */ +int next_char; /* character currently being scanned */ +uint32_t bits; /* Bits waiting to be used */ +uint32_t n_bits; /* number of such bits waiting to be used */ +int count; /* number of 8-bit characters output by get_char */ + +sexp_input_stream_t::sexp_input_stream_t(std::istream *i, size_t m_depth) +{ + set_input(i, m_depth); +} + +/* + * sexp_input_stream_t::set_input(std::istream *i) + */ + +sexp_input_stream_t *sexp_input_stream_t::set_input(std::istream *i, size_t m_depth) +{ + input_file = i; + byte_size = 8; + next_char = ' '; + bits = 0; + n_bits = 0; + count = -1; + depth = 0; + max_depth = m_depth; + return this; +} + +/* + * sexp_input_stream_t::set_byte_size(newByteSize) + */ +sexp_input_stream_t *sexp_input_stream_t::set_byte_size(uint32_t newByteSize) +{ + byte_size = newByteSize; + n_bits = 0; + bits = 0; + return this; +} + +int sexp_input_stream_t::read_char(void) +{ + count++; + return input_file->get(); +} + +/* + * sexp_input_stream_t::get_char() + * This is one possible character input routine for an input stream. + * (This version uses the standard input stream.) + * get_char places next 8-bit character into is->next_char. + * It also updates the count of number of 8-bit characters read. + * The value EOF is obtained when no more input is available. + * This code handles 4-bit/6-bit/8-bit channels. + */ +sexp_input_stream_t *sexp_input_stream_t::get_char(void) +{ + int c; + if (next_char == EOF) { + byte_size = 8; + return this; + } + + while (true) { + c = next_char = read_char(); + if (c == EOF) + return this; + if ((byte_size == 6 && (c == '|' || c == '}')) || (byte_size == 4 && (c == '#'))) { + // end of region reached; return terminating character, after checking for + // unused bits + if (n_bits > 0 && (((1 << n_bits) - 1) & bits) != 0) { + sexp_error(sexp_exception_t::warning, + "%d-bit region ended with %d unused bits left-over", + byte_size, + n_bits, + count); + } + return set_byte_size(8); + } else if (byte_size != 8 && is_white_space(c)) + ; /* ignore white space in hex and base64 regions */ + else if (byte_size == 6 && c == '=') + ; /* ignore equals signs in base64 regions */ + else if (byte_size == 8) { + return this; + } else if (byte_size < 8) { + bits = bits << byte_size; + n_bits += byte_size; + if (byte_size == 6 && is_base64_digit(c)) + bits = bits | base64value(c); + else if (byte_size == 4 && is_hex_digit(c)) + bits = bits | hexvalue(c); + else { + sexp_error(sexp_exception_t::error, + "character '%c' found in %u-bit coding region", + next_char, + byte_size, + count); + } + if (n_bits >= 8) { + next_char = (bits >> (n_bits - 8)) & 0xFF; + n_bits -= 8; + return this; + } + } + } +} + +/* + * sexp_input_stream_t::skip_white_space + * Skip over any white space on the given sexp_input_stream_t. + */ +sexp_input_stream_t *sexp_input_stream_t::skip_white_space(void) +{ + while (is_white_space(next_char)) + get_char(); + return this; +} + +/* + * sexp_input_stream_t::skip_char(c) + * Skip the following input character on input stream is, if it is + * equal to the character c. If it is not equal, then an error occurs. + */ +sexp_input_stream_t *sexp_input_stream_t::skip_char(int c) +{ + if (next_char != c) + sexp_error(sexp_exception_t::error, + "character '%c' found where '%c' was expected", + next_char, + c, + count); + return get_char(); +} + +/* + * sexp_input_stream_t::scan_token(ss) + * scan one or more characters into simple string ss as a token. + */ +void sexp_input_stream_t::scan_token(sexp_simple_string_t &ss) +{ + skip_white_space(); + while (is_token_char(next_char)) { + ss.append(next_char); + get_char(); + } +} + +/* + * sexp_input_stream_t::scan_to_eof(void) + * scan one or more characters (until EOF reached) + * return an object that is just that string + */ +std::shared_ptr sexp_input_stream_t::scan_to_eof(void) +{ + sexp_simple_string_t ss; + std::shared_ptr s(new sexp_string_t()); + skip_white_space(); + while (next_char != EOF) { + ss.append(next_char); + get_char(); + } + s->set_string(ss); + return s; +} + +/* + * scan_decimal_string(is) + * returns long integer that is value of decimal number + */ +uint32_t sexp_input_stream_t::scan_decimal_string(void) +{ + uint32_t value = 0; + uint32_t i = 0; + while (is_dec_digit(next_char)) { + value = value * 10 + decvalue(next_char); + get_char(); + if (i++ > 8) + sexp_error(sexp_exception_t::error, "Decimal number is too long", 0, 0, count); + } + return value; +} + +/* + * sexp_input_stream_t::scan_verbatim_string(is,ss,length) + * Reads verbatim string of given length into simple string ss. + */ +void sexp_input_stream_t::scan_verbatim_string(sexp_simple_string_t &ss, uint32_t length) +{ + skip_white_space()->skip_char(':'); + + // Some length is specified always, this is ensured by the caller's logic + assert(length != std::numeric_limits::max()); + for (uint32_t i = 0; i < length; i++) { + ss.append(next_char); + get_char(); + } +} + +/* + * sexp_input_stream_t::scan_quoted_string(ss,length) + * Reads quoted string of given length into simple string ss. + * Handles ordinary C escapes. + * If of indefinite length, length is std::numeric_limits::max(). + */ +void sexp_input_stream_t::scan_quoted_string(sexp_simple_string_t &ss, uint32_t length) +{ + skip_char('"'); + while (ss.length() <= length) { + if (next_char == '\"') { + if (length == std::numeric_limits::max() || (ss.length() == length)) { + skip_char('\"'); + return; + } else + sexp_error(sexp_exception_t::error, + "Declared length was %d, but quoted string ended too early", + (int) length, + 0, + count); + } else if (next_char == '\\') /* handle escape sequence */ + { + get_char(); + switch (next_char) { + case 'b': + ss.append('\b'); + break; + case 't': + ss.append('\t'); + break; + case 'v': + ss.append('\v'); + break; + case 'n': + ss.append('\n'); + break; + case 'f': + ss.append('\f'); + break; + case 'r': + ss.append('\r'); + break; + case '\"': + ss.append('\"'); + break; + case '\'': + ss.append('\''); + break; + case '\\': + ss.append('\\'); + break; + case 'x': /* hexadecimal number */ + { + int j, val; + val = 0; + get_char(); + for (j = 0; j < 2; j++) { + if (is_hex_digit(next_char)) { + val = ((val << 4) | hexvalue(next_char)); + if (j < 1) { + get_char(); + } + } else + sexp_error(sexp_exception_t::error, + "Hex character \x5cx%x... too short", + val, + 0, + count); + } + ss.append(val); + } break; + case '\n': /* ignore backslash line feed */ + get_char(); /* also ignore following carriage-return if present */ + if (next_char != '\r') + continue; + break; + case '\r': /* ignore backslash carriage-return */ + get_char(); /* also ignore following linefeed if present */ + if (next_char != '\n') + continue; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { /* octal number */ + int j, val; + val = 0; + for (j = 0; j < 3; j++) { + if (next_char >= '0' && next_char <= '7') { + val = ((val << 3) | (next_char - '0')); + if (j < 2) + get_char(); + } else + sexp_error(sexp_exception_t::error, + "Octal character \\%o... too short", + val, + 0, + count); + } + if (val > 255) + sexp_error(sexp_exception_t::error, + "Octal character \\%o... too big", + val, + 0, + count); + ss.append(val); + } break; + default: + sexp_error(sexp_exception_t::error, + "Unknown escape sequence \\%c", + next_char, + 0, + count); + } + } /* end of handling escape sequence */ + else if (next_char == EOF) { + sexp_error(sexp_exception_t::error, "unexpected end of file", 0, 0, count); + } else { + ss.append(next_char); + } + get_char(); + } /* end of main while loop */ +} + +/* + * scan_hexadecimal_string(ss,length) + * Reads hexadecimal string into simple string ss. + * String is of given length result, or length = std::numeric_limits::max() + * if indefinite length. + */ +void sexp_input_stream_t::scan_hexadecimal_string(sexp_simple_string_t &ss, uint32_t length) +{ + set_byte_size(4)->skip_char('#'); + while (next_char != EOF && (next_char != '#' || get_byte_size() == 4)) { + ss.append(next_char); + get_char(); + } + skip_char('#'); + if (ss.length() != length && length != std::numeric_limits::max()) + sexp_error(sexp_exception_t::warning, + "Hex string has length %d different than declared length %d", + ss.length(), + length, + count); +} + +/* + * sexp_input_stream_t::scan_base64_string(ss,length) + * Reads base64 string into simple string ss. + * String is of given length result, or length = std::numeric_limits::max() + * if indefinite length. + */ +void sexp_input_stream_t::scan_base64_string(sexp_simple_string_t &ss, uint32_t length) +{ + set_byte_size(6)->skip_char('|'); + while (next_char != EOF && (next_char != '|' || get_byte_size() == 6)) { + ss.append(next_char); + get_char(); + } + skip_char('|'); + if (ss.length() != length && length != std::numeric_limits::max()) + sexp_error(sexp_exception_t::warning, + "Base64 string has length %d different than declared length %d", + ss.length(), + length, + count); +} + +/* + * sexp_input_stream_t::scan_simple_string(void) + * Reads and returns a simple string from the input stream. + * Determines type of simple string from the initial character, and + * dispatches to appropriate routine based on that. + */ +sexp_simple_string_t sexp_input_stream_t::scan_simple_string(void) +{ + int length; + sexp_simple_string_t ss; + skip_white_space(); + /* Note that it is important in the following code to test for token-ness + * before checking the other cases, so that a token may begin with ":", + * which would otherwise be treated as a verbatim string missing a length. + */ + if (is_token_char(next_char) && !is_dec_digit(next_char)) { + scan_token(ss); + } else { + length = is_dec_digit(next_char) ? scan_decimal_string() : + std::numeric_limits::max(); + + switch (next_char) { + case '\"': + scan_quoted_string(ss, length); + break; + case '#': + scan_hexadecimal_string(ss, length); + break; + case '|': + scan_base64_string(ss, length); + break; + case ':': + // ':' is 'tokenchar', so some length shall be defined + scan_verbatim_string(ss, length); + break; + default: { + const char *const msg = (next_char == EOF) ? "unexpected end of file" : + isprint(next_char) ? "illegal character '%c' (0x%x)" : + "illegal character 0x%x"; + sexp_error(sexp_exception_t::error, msg, next_char, next_char, count); + } + } + } + + if (ss.length() == 0) + sexp_error(sexp_exception_t::warning, "Simple string has zero length", 0, 0, count); + return ss; +} + +/* + * sexp_input_stream_t::scan_string(void) + * Reads and returns a string [presentationhint]string from input stream. + */ +std::shared_ptr sexp_input_stream_t::scan_string(void) +{ + std::shared_ptr s(new sexp_string_t()); + s->parse(this); + return s; +} + +/* + * sexp_input_stream_t::scan_list(void) + * Read and return a sexp_list_t from the input stream. + */ +std::shared_ptr sexp_input_stream_t::scan_list(void) +{ + std::shared_ptr list(new sexp_list_t()); + list->parse(this); + return list; +} + +/* + * sexp_input_stream_t::scan_object(void) + * Reads and returns a sexp_object_t from the given input stream. + */ +std::shared_ptr sexp_input_stream_t::scan_object(void) +{ + std::shared_ptr object; + skip_white_space(); + if (next_char == '{' && byte_size != 6) { + set_byte_size(6)->skip_char('{'); + object = scan_object(); + skip_char('}'); + } else { + if (next_char == '(') + object = scan_list(); + else + object = scan_string(); + } + return object; +} + +} // namespace sexp diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-main.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-main.cpp new file mode 100644 index 0000000000..7406bdfd5e --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-main.cpp @@ -0,0 +1,237 @@ +/** + * + * Copyright (c) 2022-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + *CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + *EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + *PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + *IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP implementation code sexp-main.c + * Ron Rivest + * 6/29/1997 + **/ + +#include + +#include + +using namespace sexp; + +const char *help = "The program 'sexp' reads, parses, and prints out S-expressions.\n" + " INPUT:\n" + " Input is normally taken from stdin, but this can be changed:\n" + " -i filename -- takes input from file instead.\n" + " -p -- prompts user for console input\n" + " Input is normally parsed, but this can be changed:\n" + " -s -- treat input up to EOF as a single string\n" + " CONTROL LOOP:\n" + " The main routine typically reads one S-expression, prints it out " + "again, \n" + " and stops. This may be modified:\n" + " -x -- execute main loop repeatedly until EOF\n" + " OUTPUT:\n" + " Output is normally written to stdout, but this can be changed:\n" + " -o filename -- write output to file instead\n" + " The output format is normally canonical, but this can be changed:\n" + " -a -- write output in advanced transport format\n" + " -b -- write output in base-64 output format\n" + " -c -- write output in canonical format\n" + " -l -- suppress linefeeds after output\n" + " More than one output format can be requested at once.\n" + " There is normally a line-width of 75 on output, but:\n" + " -w width -- changes line width to specified width.\n" + " (0 implies no line-width constraint)\n" + " Running without switches implies: -p -a -b -c -x\n" + " Typical usage: cat certificate-file | sexp -a -x \n"; + +/*************************************************************************/ +/* main(argc,argv) + */ +int main(int argc, char **argv) +{ + char *c; + bool swa = true, swb = true, swc = true, swp = true, sws = false, swx = true, swl = false; + int i; + int ret = -1; + sexp_exception_t::set_interactive(true); + std::ifstream * ifs = nullptr; + sexp_input_stream_t * is = nullptr; + std::ofstream * ofs = nullptr; + sexp_output_stream_t *os = nullptr; + std::string ofname; + std::string ifname; + try { + std::shared_ptr object; + + is = new sexp_input_stream_t(&std::cin); + os = new sexp_output_stream_t(&std::cout); + + if (argc > 1) + swa = swb = swc = swp = sws = swx = swl = false; + for (i = 1; i < argc; i++) { + c = argv[i]; + if (*c != '-') + throw sexp_exception_t( + std::string("Unrecognized switch ") + c, sexp_exception_t::error, EOF); + c++; + if (*c == 'a') + swa = true; /* advanced output */ + else if (*c == 'b') + swb = true; /* base-64 output */ + else if (*c == 'c') + swc = true; /* canonical output */ + else if (*c == 'h') { /* help */ + std::cout << help; + exit(0); + } else if (*c == 'i') { /* input file */ + if (i + 1 < argc) + i++; + ifs = new std::ifstream(argv[i], std::ifstream::binary); + if (ifs->fail()) + sexp_error(sexp_exception_t::error, "Can't open input file.", 0, 0, EOF); + is->set_input(ifs); + ifname = argv[i]; + } else if (*c == 'l') + swl = true; /* suppress linefeeds after output */ + else if (*c == 'o') { /* output file */ + if (i + 1 < argc) + i++; + ofs = new std::ofstream(argv[i], std::ifstream::binary); + if (ofs->fail()) + sexp_error(sexp_exception_t::error, "Can't open output file.", 0, 0, EOF); + os->set_output(ofs); + ofname = argv[i]; + } else if (*c == 'p') + swp = true; /* prompt for input */ + else if (*c == 's') + sws = true; /* treat input as one big string */ + else if (*c == 'w') { /* set output width */ + if (i + 1 < argc) + i++; + os->set_max_column(atoi(argv[i])); + } else if (*c == 'x') + swx = true; /* execute repeatedly */ + else + throw sexp_exception_t( + std::string("Unrecognized switch ") + argv[i], sexp_exception_t::error, EOF); + } + + if (swa == false && swb == false && swc == false) + swc = true; /* must have some output format! */ + + /* main loop */ + if (swp == 0) + is->get_char(); + else + is->set_next_char(-2); /* this is not EOF */ + while (is->get_next_char() != EOF) { + if (swp) { + if (ifname.empty()) + std::cout << "Input:"; + else + std::cout << "Reading input from " << ifname; + std::cout << std::endl; + std::cout.flush(); + } + + is->set_byte_size(8); + if (is->get_next_char() == -2) + is->get_char(); + + is->skip_white_space(); + if (is->get_next_char() == EOF) + break; + + object = sws ? is->scan_to_eof() : is->scan_object(); + + if (swp) + std::cout << std::endl; + + if (swc) { + if (swp) { + if (ofname.empty()) + std::cout << "Canonical output:" << std::endl; + else + std::cout << "Writing canonical output to '" << ofname << "'"; + } + object->print_canonical(os); + if (!swl) { + std::cout << std::endl; + } + } + + if (swb) { + if (swp) { + if (ofname.empty()) + std::cout << "Base64 (of canonical) output:" << std::endl; + else + std::cout << "Writing base64 (of canonical) output to '" << ofname + << "'"; + } + os->set_output(ofs ? ofs : &std::cout)->print_base64(object); + if (!swl) { + std::cout << std::endl; + std::cout.flush(); + } + } + + if (swa) { + if (swp) { + if (ofname.empty()) + std::cout << "Advanced transport output:" << std::endl; + else + std::cout << "Writing advanced transport output to '" << ofname << "'"; + } + os->set_output(ofs ? ofs : &std::cout)->print_advanced(object); + if (!swl) { + std::cout << std::endl; + std::cout.flush(); + } + } + + if (!swx) + break; + if (!swp) + is->skip_white_space(); + else if (!swl) { + std::cout << std::endl; + std::cout.flush(); + } + } + ret = 0; + } catch (sexp_exception_t &e) { + std::cout << e.what() << std::endl; + } catch (...) { + std::cout << "UNEXPECTED ERROR" << std::endl; + } + if (is) + delete is; + if (ifs) + delete ifs; + if (os) + delete os; + if (ofs) + delete ofs; + return ret; +} \ No newline at end of file diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-object.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-object.cpp new file mode 100644 index 0000000000..4669cb4006 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-object.cpp @@ -0,0 +1,194 @@ +/** + * + * Copyright (c) 2022-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP implementation code sexp-output.c + * Ron Rivest + * 5/5/1997 + */ + +#include + +namespace sexp { + +/* + * sexp_string_t::parse(sis) + * Parses the strin from input stream + */ + +void sexp_string_t::parse(sexp_input_stream_t *sis) +{ + if (sis->get_next_char() == '[') { /* scan presentation hint */ + sis->skip_char('['); + set_presentation_hint(sis->scan_simple_string()); + sis->skip_white_space()->skip_char(']')->skip_white_space(); + } + set_string(sis->scan_simple_string()); +} + +/* + * sexp_string_t::print_canonical(os) + * Prints out sexp string onto output stream os + */ +sexp_output_stream_t *sexp_string_t::print_canonical(sexp_output_stream_t *os) const +{ + if (with_presentation_hint) { + os->var_put_char('['); + presentation_hint.print_canonical_verbatim(os); + os->var_put_char(']'); + } + data_string.print_canonical_verbatim(os); + return os; +} + +/* + * sexp_string_t::print_advanced(os) + * Prints out sexp string onto output stream os + */ +sexp_output_stream_t *sexp_string_t::print_advanced(sexp_output_stream_t *os) const +{ + sexp_object_t::print_advanced(os); + if (with_presentation_hint) { + os->put_char('['); + presentation_hint.print_advanced(os); + os->put_char(']'); + } + data_string.print_advanced(os); + return os; +} + +/* + * sexp_string_t::advanced_length(os) + * Returns length of printed image of string + */ +size_t sexp_string_t::advanced_length(sexp_output_stream_t *os) const +{ + size_t len = 0; + if (with_presentation_hint) + len += 2 + presentation_hint.advanced_length(os); + len += data_string.advanced_length(os); + return len; +} + +/* + * sexp_list_t::parse(sis) + * Parses the list from input stream + */ + +void sexp_list_t::parse(sexp_input_stream_t *sis) +{ + sis->skip_char('(')->increase_depth()->skip_white_space(); + if (sis->get_next_char() == ')') { + ; + } else { + push_back(sis->scan_object()); + } + + while (true) { + sis->skip_white_space(); + if (sis->get_next_char() == ')') { /* we just grabbed last element of list */ + sis->skip_char(')')->decrease_depth(); + return; + + } else { + push_back(sis->scan_object()); + } + } +} + +/* + * sexp_list_t::print_canonical(os) + * Prints out the list "list" onto output stream os + */ +sexp_output_stream_t *sexp_list_t::print_canonical(sexp_output_stream_t *os) const +{ + os->var_put_char('('); + std::for_each(begin(), end(), [os](const std::shared_ptr &obj) { + obj->print_canonical(os); + }); + os->var_put_char(')'); + return os; +} + +/* + * sexp_list_t::print_advanced(os) + * Prints out the list onto output stream os. + * Uses print-length to determine length of the image. If it all fits + * on the current line, then it is printed that way. Otherwise, it is + * written out in "vertical" mode, with items of the list starting in + * the same column on successive lines. + */ +sexp_output_stream_t *sexp_list_t::print_advanced(sexp_output_stream_t *os) const +{ + sexp_object_t::print_advanced(os); + int vertical = false; + int firstelement = true; + os->put_char('(')->inc_indent(); + vertical = (advanced_length(os) > os->get_max_column() - os->get_column()); + + std::for_each(begin(), end(), [&](const std::shared_ptr &obj) { + if (!firstelement) { + if (vertical) + os->new_line(sexp_output_stream_t::advanced); + else + os->put_char(' '); + } + obj->print_advanced(os); + firstelement = false; + }); + + if (os->get_max_column() > 0 && os->get_column() > os->get_max_column() - 2) + os->new_line(sexp_output_stream_t::advanced); + return os->dec_indent()->put_char(')'); +} + +/* + * sexp_list_t::advanced_length(os) + * Returns length of printed image of list given as iterator + */ +size_t sexp_list_t::advanced_length(sexp_output_stream_t *os) const +{ + size_t len = 1; /* for left paren */ + std::for_each(begin(), end(), [&](const std::shared_ptr &obj) { + len += obj->advanced_length(os); + }); + return (len + 1); /* for final paren */ +} + +/* + * sexp_object_t::print_advanced(os) + * Prints out object on output stream os + */ +sexp_output_stream_t *sexp_object_t::print_advanced(sexp_output_stream_t *os) const +{ + if (os->get_max_column() > 0 && os->get_column() > os->get_max_column() - 4) + os->new_line(sexp_output_stream_t::advanced); + return os; +} + +} // namespace sexp \ No newline at end of file diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-output.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-output.cpp new file mode 100644 index 0000000000..33e42fbba5 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-output.cpp @@ -0,0 +1,208 @@ +/** + * + * Copyright (c) 2022-2023, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP implementation code sexp-output.c + * Ron Rivest + * 5/5/1997 + */ + +#include + +namespace sexp { + +static const char *hexDigits = "0123456789ABCDEF"; +static const char *base64Digits = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* + * sexp_output_stream_t::sexp_output_stream_t + * Creates and initializes new sexp_output_stream_t object. + */ +sexp_output_stream_t::sexp_output_stream_t(std::ostream *o) +{ + set_output(o); +} + +/* + * sexp_output_stream_t::set_output + * Re-initializes new sexp_output_stream_t object. + */ +sexp_output_stream_t *sexp_output_stream_t::set_output(std::ostream *o) +{ + output_file = o; + byte_size = 8; + bits = 0; + n_bits = 0; + mode = canonical; + column = 0; + max_column = default_line_length; + indent = 0; + base64_count = 0; + return this; +} + +/* + * sexp_output_stream_t::put_char(c) + * Puts the character c out on the output stream os. + * Keeps track of the "column" the next output char will go to. + */ +sexp_output_stream_t *sexp_output_stream_t::put_char(int c) +{ + output_file->put(c); + column++; + return this; +} + +/* + * sexp_output_stream_t::var_put_char(c) + * put_char with variable sized output bytes considered. + * int c; -- this is always an eight-bit byte being output + */ +sexp_output_stream_t *sexp_output_stream_t::var_put_char(int c) +{ + c &= 0xFF; + bits = (bits << 8) | c; + n_bits += 8; + while (n_bits >= byte_size) { + if ((byte_size == 6 || byte_size == 4 || c == '}' || c == '{' || c == '#' || + c == '|') && + max_column > 0 && column >= max_column) + new_line(mode); + if (byte_size == 4) + put_char(hexDigits[(bits >> (n_bits - 4)) & 0x0F]); + else if (byte_size == 6) + put_char(base64Digits[(bits >> (n_bits - 6)) & 0x3F]); + else if (byte_size == 8) + put_char(bits & 0xFF); + n_bits -= byte_size; + base64_count++; + } + return this; +} + +/* + * sexp_output_stream_t::change_output_byte_size(newByteSize,newMode) + * Change os->byte_size to newByteSize + * record mode in output stream for automatic line breaks + */ +sexp_output_stream_t *sexp_output_stream_t::change_output_byte_size(int newByteSize, + sexp_print_mode newMode) +{ + if (newByteSize != 4 && newByteSize != 6 && newByteSize != 8) + sexp_error(sexp_exception_t::error, "Illegal output base %d", newByteSize, 0, EOF); + if (newByteSize != 8 && byte_size != 8) + sexp_error(sexp_exception_t::error, + "Illegal change of output byte size from %d to %d", + byte_size, + newByteSize, + EOF); + byte_size = newByteSize; + n_bits = 0; + bits = 0; + base64_count = 0; + mode = newMode; + return this; +} + +/* + * sexp_output_stream_t::flush() + * flush out any remaining bits + */ +sexp_output_stream_t *sexp_output_stream_t::flush(void) +{ + if (n_bits > 0) { + assert(byte_size == 6); + put_char(base64Digits[(bits << (6 - n_bits)) & 0x3F]); + n_bits = 0; + base64_count++; + } + if (byte_size == 6) { /* and add switch here */ + while ((base64_count & 3) != 0) { + if (max_column > 0 && column >= max_column) + new_line(mode); + put_char('='); + base64_count++; + } + } + return this; +} + +/* + * sexp_output_stream_t::new_line(mode) + * Outputs a newline symbol to the output stream os. + * For advanced mode, also outputs indentation as one blank per + * indentation level (but never indents more than half of max_column). + * Resets column for next output character. + */ +sexp_output_stream_t *sexp_output_stream_t::new_line(sexp_print_mode mode) +{ + if (mode == advanced || mode == base64) { + put_char('\n'); + column = 0; + } + if (mode == advanced) { + for (uint32_t i = 0; i < indent && (4 * i) < max_column; i++) + put_char(' '); + } + return this; +} + +/* + * sexp_output_stream_t::print_decimal(n) + * print out n in decimal to output stream os + */ +sexp_output_stream_t *sexp_output_stream_t::print_decimal(uint64_t n) +{ + char buffer[20]; // 64*ln(2)/ln(10) + snprintf(buffer, + sizeof(buffer) / sizeof(buffer[0]), +#ifdef _WIN32 + "%llu", +#else + "%lu", +#endif + n); // since itoa is not a part of any standard + for (uint32_t i = 0; buffer[i] != 0; i++) + var_put_char(buffer[i]); + return this; +} + +/* + * base64 MODE + * Same as canonical, except all characters get put out as base 64 ones + */ + +sexp_output_stream_t *sexp_output_stream_t::print_base64( + const std::shared_ptr &object) +{ + change_output_byte_size(8, base64)->var_put_char('{')->change_output_byte_size(6, base64); + print_canonical(object); + return flush()->change_output_byte_size(8, base64)->var_put_char('}'); +} +} // namespace sexp diff --git a/comm/third_party/rnp/src/libsexp/src/sexp-simple-string.cpp b/comm/third_party/rnp/src/libsexp/src/sexp-simple-string.cpp new file mode 100644 index 0000000000..612ef22705 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/src/sexp-simple-string.cpp @@ -0,0 +1,197 @@ +/** + * + * Copyright (c) 2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * This file is a part of RNP sexp library + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original copyright + * + * SEXP implementation code sexp-output.c + * Ron Rivest + * 5/5/1997 + */ + +#include + +namespace sexp { +/* + * sexp_simple_string_t::print_canonical_verbatim(os) + * Print out simple string on output stream os as verbatim string. + */ +sexp_output_stream_t *sexp_simple_string_t::print_canonical_verbatim( + sexp_output_stream_t *os) const +{ + const octet_t *c = c_str(); + /* print out len: */ + os->print_decimal(length())->var_put_char(':'); + /* print characters in fragment */ + for (uint32_t i = 0; i < length(); i++) + os->var_put_char((int) *c++); + return os; +} + +/* + * sexp_simple_string_t::advanced_length(os) + * Returns length of printed image of s + */ +size_t sexp_simple_string_t::advanced_length(sexp_output_stream_t *os) const +{ + if (can_print_as_token(os)) + return advanced_length_token(); + else if (can_print_as_quoted_string()) + return advanced_length_quoted(); + else if (length() <= 4 && os->get_byte_size() == 8) + return advanced_length_hexadecimal(); + else if (os->get_byte_size() == 8) + return advanced_length_base64(); + else + return 0; /* an error condition */ +} + +/* + * sexp_simple_string_t::print_token(os) + * Prints out simple string ss as a token (assumes that this is OK). + * May run over max-column, but there is no fragmentation allowed... + */ +sexp_output_stream_t *sexp_simple_string_t::print_token(sexp_output_stream_t *os) const +{ + const octet_t *c = c_str(); + if (os->get_max_column() > 0 && os->get_column() > (os->get_max_column() - length())) + os->new_line(sexp_output_stream_t::advanced); + for (uint32_t i = 0; i < length(); i++) + os->put_char((int) (*c++)); + return os; +} + +/* + * sexp_simple_string_t::print_base64(os) + * Prints out simple string ss as a base64 value. + */ +sexp_output_stream_t *sexp_simple_string_t::print_base64(sexp_output_stream_t *os) const +{ + const octet_t *c = c_str(); + os->var_put_char('|')->change_output_byte_size(6, sexp_output_stream_t::advanced); + for (uint32_t i = 0; i < length(); i++) + os->var_put_char((int) (*c++)); + return os->flush() + ->change_output_byte_size(8, sexp_output_stream_t::advanced) + ->var_put_char('|'); +} + +/* + * sexp_simple_string_t::print_hexadecimal(os) + * Prints out simple string as a hexadecimal value. + */ +sexp_output_stream_t *sexp_simple_string_t::print_hexadecimal(sexp_output_stream_t *os) const +{ + const octet_t *c = c_str(); + os->put_char('#')->change_output_byte_size(4, sexp_output_stream_t::advanced); + for (uint32_t i = 0; i < length(); i++) + os->var_put_char((int) (*c++)); + return os->flush() + ->change_output_byte_size(8, sexp_output_stream_t::advanced) + ->put_char('#'); +} + +/* + * sexp_simple_string_t::print_quoted(os) + * Prints out simple string ss as a quoted string + * This code assumes that all characters are tokenchars and blanks, + * so no escape sequences need to be generated. + * May run over max-column, but there is no fragmentation allowed... + */ +sexp_output_stream_t *sexp_simple_string_t::print_quoted(sexp_output_stream_t *os) const +{ + const octet_t *c = c_str(); + os->put_char('\"'); + for (uint32_t i = 0; i < length(); i++) { + if (os->get_max_column() > 0 && os->get_column() >= os->get_max_column() - 2) { + os->put_char('\\')->put_char('\n'); + os->reset_column(); + } + os->put_char(*c++); + } + return os->put_char('\"'); +} + +/* + * sexp_simple_string_t::print_advanced(os) + * Prints out simple string onto output stream ss + */ +sexp_output_stream_t *sexp_simple_string_t::print_advanced(sexp_output_stream_t *os) const +{ + if (can_print_as_token(os)) + print_token(os); + else if (can_print_as_quoted_string()) + print_quoted(os); + else if (length() <= 4 && os->get_byte_size() == 8) + print_hexadecimal(os); + else if (os->get_byte_size() == 8) + print_base64(os); + else + sexp_error(sexp_exception_t::error, + "Can't print in advanced mode with restricted output character set", + 0, + 0, + EOF); + return os; +} + +/* + * sexp_simple_string_t::can_print_as_quoted_string(void) + * Returns true if simple string can be printed as a quoted string. + * Must have only tokenchars and blanks. + */ +bool sexp_simple_string_t::can_print_as_quoted_string(void) const +{ + const octet_t *c = c_str(); + for (uint32_t i = 0; i < length(); i++, c++) { + if (!is_token_char((int) (*c)) && *c != ' ') + return false; + } + return true; +} + +/* + * sexp_simple_string_t::can_print_as_token(os) + * Returns true if simple string can be printed as a token. + * Doesn't begin with a digit, and all characters are tokenchars. + */ +bool sexp_simple_string_t::can_print_as_token(const sexp_output_stream_t *os) const +{ + const octet_t *c = c_str(); + if (length() <= 0) + return false; + if (is_dec_digit((int) *c)) + return false; + if (os->get_max_column() > 0 && os->get_column() + length() >= os->get_max_column()) + return false; + for (uint32_t i = 0; i < length(); i++) { + if (!is_token_char((int) (*c++))) + return false; + } + return true; +} + +} // namespace sexp diff --git a/comm/third_party/rnp/src/libsexp/version.txt b/comm/third_party/rnp/src/libsexp/version.txt new file mode 100644 index 0000000000..100435be13 --- /dev/null +++ b/comm/third_party/rnp/src/libsexp/version.txt @@ -0,0 +1 @@ +0.8.2 diff --git a/comm/third_party/rnp/src/rnp/CMakeLists.txt b/comm/third_party/rnp/src/rnp/CMakeLists.txt new file mode 100644 index 0000000000..d3199e7e1f --- /dev/null +++ b/comm/third_party/rnp/src/rnp/CMakeLists.txt @@ -0,0 +1,100 @@ +# Copyright (c) 2018-2020 Ribose Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +if(MSVC) + # remove extra ${Configuration} subfolder + set(ArchiveOutputDir ${CMAKE_BINARY_DIR}\\src\\rnp) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${ArchiveOutputDir}) + + set(RuntimeOutputDir ${CMAKE_BINARY_DIR}\\src\\rnp) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${RuntimeOutputDir}) + + find_path(GETOPT_INCLUDE_DIR + NAMES getopt.h + ) + find_library(GETOPT_LIBRARY + NAMES getopt + ) + find_path(DIRENT_INCLUDE_DIR + NAMES dirent.h + ) +endif() + +# for the headers +find_package(JSON-C 0.11 REQUIRED) + +add_executable(rnp + rnp.cpp + fficli.cpp + rnpcfg.cpp + ../rnpkeys/tui.cpp +) + +if(BUILD_SHARED_LIBS) + target_sources(rnp PRIVATE ../lib/logging.cpp $) +endif(BUILD_SHARED_LIBS) + +target_include_directories(rnp + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" + "${JSON-C_INCLUDE_DIRS}" +) +if(MSVC) + target_include_directories(rnp + PRIVATE + "${GETOPT_INCLUDE_DIR}" + "${DIRENT_INCLUDE_DIR}" + ) +endif() + +target_link_libraries(rnp + PRIVATE + librnp + JSON-C::JSON-C +) +if(MSVC) + target_link_libraries(rnp + PRIVATE + "${GETOPT_LIBRARY}" + ) +endif(MSVC) + +include(GNUInstallDirs) +install(TARGETS rnp + RUNTIME + DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT cli +) + +# Build and install man page +if (ENABLE_DOC) + add_adoc_man("${CMAKE_CURRENT_SOURCE_DIR}/rnp.1.adoc" ${RNP_VERSION}) +endif() diff --git a/comm/third_party/rnp/src/rnp/fficli.cpp b/comm/third_party/rnp/src/rnp/fficli.cpp new file mode 100644 index 0000000000..fa118eea23 --- /dev/null +++ b/comm/third_party/rnp/src/rnp/fficli.cpp @@ -0,0 +1,3229 @@ +/* + * Copyright (c) 2019-2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include "uniwin.h" +#else +#include +#include +#endif + +#ifndef _WIN32 +#include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#endif + +#ifdef _WIN32 +#include +#endif + +#include "fficli.h" +#include "str-utils.h" +#include "file-utils.h" +#include "time-utils.h" +#include "defaults.h" + +#ifndef RNP_USE_STD_REGEX +#include +#else +#include +#endif + +#ifdef HAVE_SYS_RESOURCE_H +/* When system resource consumption limit controls are available this + * can be used to attempt to disable core dumps which may leak + * sensitive data. + * + * Returns false if disabling core dumps failed, returns true if disabling + * core dumps succeeded. errno will be set to the result from setrlimit in + * the event of failure. + */ +static bool +disable_core_dumps(void) +{ + struct rlimit limit; + int error; + + errno = 0; + memset(&limit, 0, sizeof(limit)); + error = setrlimit(RLIMIT_CORE, &limit); + + if (error == 0) { + error = getrlimit(RLIMIT_CORE, &limit); + if (error) { + ERR_MSG("Warning - cannot turn off core dumps"); + return false; + } else if (limit.rlim_cur == 0) { + return true; // disabling core dumps ok + } else { + return false; // failed for some reason? + } + } + return false; +} +#endif + +#ifdef _WIN32 +#include +#include + +static std::vector +get_utf8_args() +{ + int arg_nb; + wchar_t **arg_w; + + arg_w = CommandLineToArgvW(GetCommandLineW(), &arg_nb); + if (!arg_w) { + throw std::runtime_error("CommandLineToArgvW failed"); + } + + try { + std::vector result; + result.reserve(arg_nb); + for (int i = 0; i < arg_nb; i++) { + auto utf8 = wstr_to_utf8(arg_w[i]); + result.push_back(utf8); + } + LocalFree(arg_w); + return result; + } catch (...) { + LocalFree(arg_w); + throw; + } +} + +void +rnp_win_clear_args(int argc, char **argv) +{ + for (int i = 0; i < argc; i++) { + if (argv[i]) { + free(argv[i]); + } + } + delete argv; +} + +bool +rnp_win_substitute_cmdline_args(int *argc, char ***argv) +{ + int argc_utf8 = 0; + char **argv_utf8_cstrs = NULL; + try { + auto argv_utf8_strings = get_utf8_args(); + argc_utf8 = argv_utf8_strings.size(); + *argc = argc_utf8; + argv_utf8_cstrs = new (std::nothrow) char *[argc_utf8 + 1](); + if (!argv_utf8_cstrs) { + throw std::bad_alloc(); + } + for (int i = 0; i < argc_utf8; i++) { + auto arg_utf8 = strdup(argv_utf8_strings[i].c_str()); + if (!arg_utf8) { + throw std::bad_alloc(); + } + argv_utf8_cstrs[i] = arg_utf8; + } + /* argv must be terminated with NULL string */ + argv_utf8_cstrs[argc_utf8] = NULL; + } catch (...) { + if (argv_utf8_cstrs) { + rnp_win_clear_args(argc_utf8, argv_utf8_cstrs); + } + throw; + } + *argc = argc_utf8; + *argv = argv_utf8_cstrs; + return true; +} +#endif + +static bool +set_pass_fd(FILE **file, int passfd) +{ + if (!file) { + return false; + } + *file = rnp_fdopen(passfd, "r"); + if (!*file) { + ERR_MSG("Cannot open fd %d for reading", passfd); + return false; + } + return true; +} + +static char * +ptimestr(char *dest, size_t size, time_t t) +{ + struct tm tm = {}; + rnp_gmtime(t, tm); + (void) snprintf(dest, + size, + "%s%04d-%02d-%02d", + rnp_y2k38_warning(t) ? ">=" : "", + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday); + return dest; +} + +static bool +cli_rnp_get_confirmation(const cli_rnp_t *rnp, const char *msg, ...) +{ + char reply[10]; + va_list ap; + + while (true) { + va_start(ap, msg); + vfprintf(rnp->userio_out, msg, ap); + va_end(ap); + fprintf(rnp->userio_out, " (y/N) "); + fflush(rnp->userio_out); + + if (fgets(reply, sizeof(reply), rnp->userio_in) == NULL) { + return false; + } + + rnp::strip_eol(reply); + + if (strlen(reply) > 0) { + if (toupper(reply[0]) == 'Y') { + return true; + } else if (toupper(reply[0]) == 'N') { + return false; + } + + fprintf(rnp->userio_out, "Sorry, response '%s' not understood.\n", reply); + } else { + return false; + } + } + + return false; +} + +static bool +rnp_ask_filename(const std::string &msg, std::string &res, cli_rnp_t &rnp) +{ + fprintf(rnp.userio_out, "%s", msg.c_str()); + fflush(rnp.userio_out); + char fname[128] = {0}; + std::string path; + do { + if (!fgets(fname, sizeof(fname), rnp.userio_in)) { + return false; + } + path = path + std::string(fname); + if (rnp::strip_eol(path)) { + res = path; + return true; + } + if (path.size() >= 2048) { + fprintf(rnp.userio_out, "%s", "Too long filename, aborting."); + fflush(rnp.userio_out); + return false; + } + } while (1); +} + +/** @brief checks whether file exists already and asks user for the new filename + * @param path output file name with path. May be an empty string, then user is asked for it. + * @param res resulting output path will be stored here. + * @param rnp initialized cli_rnp_t structure with additional data + * @return true on success, or false otherwise (user cancels the operation) + **/ + +static bool +rnp_get_output_filename(const std::string &path, std::string &res, cli_rnp_t &rnp) +{ + std::string newpath = path; + if (newpath.empty() && + !rnp_ask_filename("Please enter the output filename: ", newpath, rnp)) { + return false; + } + + while (true) { + if (!rnp_file_exists(newpath.c_str())) { + res = newpath; + return true; + } + if (rnp.cfg().get_bool(CFG_OVERWRITE) || + cli_rnp_get_confirmation( + &rnp, + "File '%s' already exists. Would you like to overwrite it?", + newpath.c_str())) { + rnp_unlink(newpath.c_str()); + res = newpath; + return true; + } + + if (!rnp_ask_filename("Please enter the new filename: ", newpath, rnp)) { + return false; + } + if (newpath.empty()) { + return false; + } + } +} + +static bool +stdin_getpass(const char *prompt, char *buffer, size_t size, cli_rnp_t &rnp) +{ +#ifndef _WIN32 + struct termios saved_flags, noecho_flags; + bool restore_ttyflags = false; +#endif + bool ok = false; + FILE *in = NULL; + FILE *out = NULL; + FILE *userio_in = rnp.userio_in ? rnp.userio_in : stdin; + + // validate args + if (!buffer) { + goto end; + } + // doesn't hurt + *buffer = '\0'; + + if (!rnp.cfg().get_bool(CFG_NOTTY)) { +#ifndef _WIN32 + in = fopen("/dev/tty", "w+ce"); +#endif + out = in; + } + + if (!in) { + in = userio_in; + out = rnp.userio_out ? rnp.userio_out : stdout; + } + + // TODO: Implement alternative for hiding password entry on Windows + // TODO: avoid duplicate termios code with pass-provider.cpp +#ifndef _WIN32 + // save the original termios + if (tcgetattr(fileno(in), &saved_flags) == 0) { + noecho_flags = saved_flags; + // disable echo in the local modes + noecho_flags.c_lflag = (noecho_flags.c_lflag & ~ECHO) | ECHONL | ISIG; + restore_ttyflags = (tcsetattr(fileno(in), TCSANOW, &noecho_flags) == 0); + } +#endif + if (prompt) { + fputs(prompt, out); + } + if (fgets(buffer, size, in) == NULL) { + goto end; + } + + rnp::strip_eol(buffer); + ok = true; +end: +#ifndef _WIN32 + if (restore_ttyflags) { + tcsetattr(fileno(in), TCSAFLUSH, &saved_flags); + } +#endif + if (in && (in != userio_in)) { + fclose(in); + } + return ok; +} + +static bool +ffi_pass_callback_stdin(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + char * keyid = NULL; + char target[64] = {0}; + char prompt[128] = {0}; + char * buffer = NULL; + bool ok = false; + bool protect = false; + bool add_subkey = false; + bool decrypt_symmetric = false; + bool encrypt_symmetric = false; + bool is_primary = false; + cli_rnp_t *rnp = static_cast(app_ctx); + + if (!ffi || !pgp_context) { + goto done; + } + + if (!strcmp(pgp_context, "protect")) { + protect = true; + } else if (!strcmp(pgp_context, "add subkey")) { + add_subkey = true; + } else if (!strcmp(pgp_context, "decrypt (symmetric)")) { + decrypt_symmetric = true; + } else if (!strcmp(pgp_context, "encrypt (symmetric)")) { + encrypt_symmetric = true; + } + + if (!decrypt_symmetric && !encrypt_symmetric) { + rnp_key_get_keyid(key, &keyid); + snprintf(target, sizeof(target), "key 0x%s", keyid); + rnp_buffer_destroy(keyid); + (void) rnp_key_is_primary(key, &is_primary); + } + + if ((protect || add_subkey) && rnp->reuse_password_for_subkey && !is_primary) { + char *primary_fprint = NULL; + if (rnp_key_get_primary_fprint(key, &primary_fprint) == RNP_SUCCESS && + !rnp->reuse_primary_fprint.empty() && + rnp->reuse_primary_fprint == primary_fprint) { + strncpy(buf, rnp->reused_password, buf_len); + ok = true; + } + + rnp_buffer_clear(rnp->reused_password, strnlen(rnp->reused_password, buf_len)); + free(rnp->reused_password); + rnp->reused_password = NULL; + rnp->reuse_password_for_subkey = false; + rnp_buffer_destroy(primary_fprint); + if (ok) + return true; + } + + buffer = (char *) calloc(1, buf_len); + if (!buffer) { + return false; + } +start: + if (decrypt_symmetric) { + snprintf(prompt, sizeof(prompt), "Enter password to decrypt data: "); + } else if (encrypt_symmetric) { + snprintf(prompt, sizeof(prompt), "Enter password to encrypt data: "); + } else { + snprintf(prompt, sizeof(prompt), "Enter password for %s to %s: ", target, pgp_context); + } + + if (!stdin_getpass(prompt, buf, buf_len, *rnp)) { + goto done; + } + if (protect || encrypt_symmetric) { + if (protect) { + snprintf(prompt, sizeof(prompt), "Repeat password for %s: ", target); + } else { + snprintf(prompt, sizeof(prompt), "Repeat password: "); + } + + if (!stdin_getpass(prompt, buffer, buf_len, *rnp)) { + goto done; + } + if (strcmp(buf, buffer) != 0) { + fputs("\nPasswords do not match!", rnp->userio_out); + // currently will loop forever + goto start; + } + if (strnlen(buf, buf_len) == 0 && !rnp->cfg().get_bool(CFG_FORCE)) { + if (!cli_rnp_get_confirmation( + rnp, "Password is empty. The key will be left unprotected. Are you sure?")) { + goto start; + } + } + } + if ((protect || add_subkey) && is_primary) { + if (cli_rnp_get_confirmation( + rnp, "Would you like to use the same password to protect subkey(s)?")) { + char *primary_fprint = NULL; + rnp->reuse_password_for_subkey = true; + rnp_key_get_fprint(key, &primary_fprint); + rnp->reuse_primary_fprint = primary_fprint; + rnp->reused_password = strdup(buf); + rnp_buffer_destroy(primary_fprint); + } + } + ok = true; +done: + fputs("", rnp->userio_out); + rnp_buffer_clear(buffer, buf_len); + free(buffer); + return ok; +} + +static bool +ffi_pass_callback_file(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + if (!app_ctx || !buf || !buf_len) { + return false; + } + + FILE *fp = (FILE *) app_ctx; + if (!fgets(buf, buf_len, fp)) { + return false; + } + rnp::strip_eol(buf); + return true; +} + +static bool +ffi_pass_callback_string(rnp_ffi_t ffi, + void * app_ctx, + rnp_key_handle_t key, + const char * pgp_context, + char buf[], + size_t buf_len) +{ + if (!app_ctx || !buf || !buf_len) { + return false; + } + + const char *pswd = (const char *) app_ctx; + if (strlen(pswd) >= buf_len) { + return false; + } + + strncpy(buf, pswd, buf_len); + return true; +} + +static void +ffi_key_callback(rnp_ffi_t ffi, + void * app_ctx, + const char *identifier_type, + const char *identifier, + bool secret) +{ + cli_rnp_t *rnp = static_cast(app_ctx); + + if (rnp::str_case_eq(identifier_type, "keyid") && + rnp::str_case_eq(identifier, "0000000000000000")) { + if (rnp->hidden_msg) { + return; + } + ERR_MSG("This message has hidden recipient. Will attempt to use all secret keys for " + "decryption."); + rnp->hidden_msg = true; + } +} + +#ifdef _WIN32 +void +rnpffiInvalidParameterHandler(const wchar_t *expression, + const wchar_t *function, + const wchar_t *file, + unsigned int line, + uintptr_t pReserved) +{ + // do nothing as within release CRT all params are NULL +} +#endif + +cli_rnp_t::~cli_rnp_t() +{ + end(); +#ifdef _WIN32 + if (subst_argv) { + rnp_win_clear_args(subst_argc, subst_argv); + } +#endif +} + +int +cli_rnp_t::ret_code(bool success) +{ + return success ? EXIT_SUCCESS : EXIT_FAILURE; +} + +#ifdef _WIN32 +void +cli_rnp_t::substitute_args(int *argc, char ***argv) +{ + rnp_win_substitute_cmdline_args(argc, argv); + subst_argc = *argc; + subst_argv = *argv; +} +#endif + +bool +cli_rnp_t::init(const rnp_cfg &cfg) +{ + cfg_.copy(cfg); + + /* Configure user's io streams. */ + if (!cfg_.get_bool(CFG_NOTTY)) { + userio_in = (isatty(fileno(stdin)) ? stdin : fopen("/dev/tty", "r")); + userio_in = (userio_in ? userio_in : stdin); + userio_out = (isatty(fileno(stdout)) ? stdout : fopen("/dev/tty", "a+")); + userio_out = (userio_out ? userio_out : stdout); + } else { + userio_in = stdin; + userio_out = stdout; + } + +#ifndef _WIN32 + /* If system resource constraints are in effect then attempt to + * disable core dumps. + */ + bool coredumps = true; + if (!cfg_.get_bool(CFG_COREDUMPS)) { +#ifdef HAVE_SYS_RESOURCE_H + coredumps = !disable_core_dumps(); +#endif + } + + if (coredumps) { + ERR_MSG("warning: core dumps may be enabled, sensitive data may be leaked to disk"); + } +#endif + +#ifdef _WIN32 + /* Setup invalid parameter handler for Windows */ + _invalid_parameter_handler handler = rnpffiInvalidParameterHandler; + _set_invalid_parameter_handler(handler); + _CrtSetReportMode(_CRT_ASSERT, 0); +#endif + + /* Configure the results stream. */ + // TODO: UTF8? + const std::string &ress = cfg_.get_str(CFG_IO_RESS); + if (ress.empty() || (ress == "")) { + resfp = stderr; + } else if (ress == "") { + resfp = stdout; + } else if (!(resfp = rnp_fopen(ress.c_str(), "w"))) { + ERR_MSG("Cannot open results %s for writing", ress.c_str()); + return false; + } + + bool res = false; + const std::string pformat = pubformat(); + const std::string sformat = secformat(); + if (pformat.empty() || sformat.empty()) { + ERR_MSG("Unknown public or secret keyring format"); + return false; + } + if (rnp_ffi_create(&ffi, pformat.c_str(), sformat.c_str())) { + ERR_MSG("Failed to initialize FFI"); + return false; + } + + // by default use stdin password provider + if (rnp_ffi_set_pass_provider(ffi, ffi_pass_callback_stdin, this)) { + goto done; + } + + // set key provider, currently for informational purposes only + if (rnp_ffi_set_key_provider(ffi, ffi_key_callback, this)) { + goto done; + } + + // setup file/pipe password input if requested + if (cfg_.get_int(CFG_PASSFD, -1) >= 0) { + if (!set_pass_fd(&passfp, cfg_.get_int(CFG_PASSFD))) { + goto done; + } + if (rnp_ffi_set_pass_provider(ffi, ffi_pass_callback_file, passfp)) { + goto done; + } + } + // setup current time if requested + if (cfg_.has(CFG_CURTIME)) { + rnp_set_timestamp(ffi, cfg_.time()); + } + pswdtries = MAX_PASSWORD_ATTEMPTS; + res = true; +done: + if (!res) { + rnp_ffi_destroy(ffi); + ffi = NULL; + } + return res; +} + +void +cli_rnp_t::end() +{ + if (passfp) { + fclose(passfp); + passfp = NULL; + } + if (resfp && (resfp != stderr) && (resfp != stdout)) { + fclose(resfp); + resfp = NULL; + } + if (userio_in && userio_in != stdin) { + fclose(userio_in); + } + userio_in = NULL; + if (userio_out && userio_out != stdout) { + fclose(userio_out); + } + userio_out = NULL; + rnp_ffi_destroy(ffi); + ffi = NULL; + cfg_.clear(); + reuse_primary_fprint.clear(); + if (reused_password) { + rnp_buffer_clear(reused_password, strlen(reused_password)); + free(reused_password); + reused_password = NULL; + } + reuse_password_for_subkey = false; +} + +bool +cli_rnp_t::load_keyring(bool secret) +{ + const std::string &path = secret ? secpath() : pubpath(); + bool dir = secret && (secformat() == RNP_KEYSTORE_G10); + if (!rnp::path::exists(path, dir)) { + return true; + } + + rnp_input_t keyin = NULL; + if (rnp_input_from_path(&keyin, path.c_str())) { + ERR_MSG("Warning: failed to open keyring at path '%s' for reading.", path.c_str()); + return true; + } + + const char * format = secret ? secformat().c_str() : pubformat().c_str(); + uint32_t flags = secret ? RNP_LOAD_SAVE_SECRET_KEYS : RNP_LOAD_SAVE_PUBLIC_KEYS; + rnp_result_t ret = rnp_load_keys(ffi, format, keyin, flags); + if (ret) { + ERR_MSG("Error: failed to load keyring from '%s'", path.c_str()); + } + rnp_input_destroy(keyin); + + if (ret) { + return false; + } + + size_t keycount = 0; + if (secret) { + (void) rnp_get_secret_key_count(ffi, &keycount); + } else { + (void) rnp_get_public_key_count(ffi, &keycount); + } + if (!keycount) { + ERR_MSG("Warning: no keys were loaded from the keyring '%s'.", path.c_str()); + } + return true; +} + +bool +cli_rnp_t::load_keyrings(bool loadsecret) +{ + /* Read public keys */ + if (rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC)) { + ERR_MSG("failed to clear public keyring"); + return false; + } + + if (!load_keyring(false)) { + return false; + } + + /* Only read secret keys if we need to */ + if (loadsecret) { + if (rnp_unload_keys(ffi, RNP_KEY_UNLOAD_SECRET)) { + ERR_MSG("failed to clear secret keyring"); + return false; + } + + if (!load_keyring(true)) { + return false; + } + } + if (defkey().empty()) { + set_defkey(); + } + return true; +} + +void +cli_rnp_t::set_defkey() +{ + rnp_identifier_iterator_t it = NULL; + rnp_key_handle_t handle = NULL; + const char * grip = NULL; + + cfg_.unset(CFG_KR_DEF_KEY); + if (rnp_identifier_iterator_create(ffi, &it, "grip")) { + ERR_MSG("failed to create key iterator"); + return; + } + + while (!rnp_identifier_iterator_next(it, &grip)) { + bool is_subkey = false; + bool is_secret = false; + + if (!grip) { + break; + } + if (rnp_locate_key(ffi, "grip", grip, &handle)) { + ERR_MSG("failed to locate key"); + continue; + } + if (rnp_key_is_sub(handle, &is_subkey) || is_subkey) { + goto next; + } + if (rnp_key_have_secret(handle, &is_secret)) { + goto next; + } + if (!cfg_.has(CFG_KR_DEF_KEY) || is_secret) { + cfg_.set_str(CFG_KR_DEF_KEY, grip); + /* if we have secret primary key then use it as default */ + if (is_secret) { + break; + } + } + next: + rnp_key_handle_destroy(handle); + handle = NULL; + } + rnp_key_handle_destroy(handle); + rnp_identifier_iterator_destroy(it); +} + +bool +cli_rnp_t::is_cv25519_subkey(rnp_key_handle_t handle) +{ + bool primary = false; + if (rnp_key_is_primary(handle, &primary)) { + ERR_MSG("Error: failed to check for subkey."); + return false; + } + if (primary) { + return false; + } + char *alg = NULL; + if (rnp_key_get_alg(handle, &alg)) { + ERR_MSG("Error: failed to check key's alg."); + return false; + } + bool ecdh = !strcmp(alg, RNP_ALGNAME_ECDH); + rnp_buffer_destroy(alg); + if (!ecdh) { + return false; + } + char *curve = NULL; + if (rnp_key_get_curve(handle, &curve)) { + ERR_MSG("Error: failed to check key's curve."); + return false; + } + bool cv25519 = !strcmp(curve, "Curve25519"); + rnp_buffer_destroy(curve); + return cv25519; +} + +bool +cli_rnp_t::get_protection(rnp_key_handle_t handle, + std::string & hash, + std::string & cipher, + size_t & iterations) +{ + bool prot = false; + if (rnp_key_is_protected(handle, &prot)) { + ERR_MSG("Error: failed to check key's protection."); + return false; + } + if (!prot) { + hash = ""; + cipher = ""; + iterations = 0; + return true; + } + + char *val = NULL; + try { + if (rnp_key_get_protection_hash(handle, &val)) { + ERR_MSG("Error: failed to retrieve key's protection hash."); + return false; + } + hash = val; + rnp_buffer_destroy(val); + if (rnp_key_get_protection_cipher(handle, &val)) { + ERR_MSG("Error: failed to retrieve key's protection cipher."); + return false; + } + cipher = val; + rnp_buffer_destroy(val); + if (rnp_key_get_protection_iterations(handle, &iterations)) { + ERR_MSG("Error: failed to retrieve key's protection iterations."); + return false; + } + return true; + } catch (const std::exception &e) { + ERR_MSG("Error: failed to retrieve key's properties: %s", e.what()); + rnp_buffer_destroy(val); + return false; + } +} + +bool +cli_rnp_t::check_cv25519_bits(rnp_key_handle_t key, char *prot_password, bool &tweaked) +{ + /* unlock key first to check whether bits are tweaked */ + if (prot_password && rnp_key_unlock(key, prot_password)) { + ERR_MSG("Error: failed to unlock key. Did you specify valid password?"); + return false; + } + rnp_result_t ret = rnp_key_25519_bits_tweaked(key, &tweaked); + if (ret) { + ERR_MSG("Error: failed to check whether key's bits are tweaked."); + } + if (prot_password) { + rnp_key_lock(key); + } + return !ret; +} + +bool +cli_rnp_t::fix_cv25519_subkey(const std::string &key, bool checkonly) +{ + std::vector keys; + if (!cli_rnp_keys_matching_string( + this, keys, key, CLI_SEARCH_SECRET | CLI_SEARCH_SUBKEYS)) { + ERR_MSG("Secret keys matching '%s' not found.", key.c_str()); + return false; + } + bool res = false; + std::string prot_hash; + std::string prot_cipher; + size_t prot_iterations; + char * prot_password = NULL; + bool tweaked = false; + + if (keys.size() > 1) { + ERR_MSG( + "Ambiguous input: too many keys found for '%s'. Did you use keyid or fingerprint?", + key.c_str()); + goto done; + } + cli_rnp_print_key_info(userio_out, ffi, keys[0], true, false); + if (!is_cv25519_subkey(keys[0])) { + ERR_MSG("Error: specified key is not Curve25519 ECDH subkey."); + goto done; + } + + if (!get_protection(keys[0], prot_hash, prot_cipher, prot_iterations)) { + goto done; + } + + if (!prot_hash.empty() && + (rnp_request_password(ffi, keys[0], "unprotect", &prot_password) || !prot_password)) { + ERR_MSG("Error: failed to obtain protection password."); + goto done; + } + + if (!check_cv25519_bits(keys[0], prot_password, tweaked)) { + goto done; + } + + if (checkonly) { + fprintf(userio_out, + tweaked ? "Cv25519 key bits are set correctly and do not require fixing.\n" : + "Warning: Cv25519 key bits need fixing.\n"); + res = tweaked; + goto done; + } + + if (tweaked) { + ERR_MSG("Warning: key's bits are fixed already, no action is required."); + res = true; + goto done; + } + + /* now unprotect so we can tweak bits */ + if (!prot_hash.empty()) { + if (rnp_key_unprotect(keys[0], prot_password)) { + ERR_MSG("Error: failed to unprotect key. Did you specify valid password?"); + goto done; + } + if (rnp_key_unlock(keys[0], NULL)) { + ERR_MSG("Error: failed to unlock key."); + goto done; + } + } + + /* tweak key bits and protect back */ + if (rnp_key_25519_bits_tweak(keys[0])) { + ERR_MSG("Error: failed to tweak key's bits."); + goto done; + } + + if (!prot_hash.empty() && rnp_key_protect(keys[0], + prot_password, + prot_cipher.c_str(), + NULL, + prot_hash.c_str(), + prot_iterations)) { + ERR_MSG("Error: failed to protect key back."); + goto done; + } + + res = cli_rnp_save_keyrings(this); +done: + clear_key_handles(keys); + if (prot_password) { + rnp_buffer_clear(prot_password, strlen(prot_password) + 1); + rnp_buffer_destroy(prot_password); + } + return res; +} + +bool +cli_rnp_t::set_key_expire(const std::string &key) +{ + std::vector keys; + if (!cli_rnp_keys_matching_string( + this, keys, key, CLI_SEARCH_SECRET | CLI_SEARCH_SUBKEYS)) { + ERR_MSG("Secret keys matching '%s' not found.", key.c_str()); + return false; + } + bool res = false; + uint32_t expiration = 0; + if (keys.size() > 1) { + ERR_MSG("Ambiguous input: too many keys found for '%s'.", key.c_str()); + goto done; + } + if (!cfg().get_expiration(CFG_SET_KEY_EXPIRE, expiration) || + rnp_key_set_expiration(keys[0], expiration)) { + ERR_MSG("Failed to set key expiration."); + goto done; + } + res = cli_rnp_save_keyrings(this); +done: + if (res) { + cli_rnp_print_key_info(stdout, ffi, keys[0], true, false); + } + clear_key_handles(keys); + return res; +} + +bool +cli_rnp_t::add_new_subkey(const std::string &key) +{ + rnp_cfg &lcfg = cfg(); + if (!cli_rnp_set_generate_params(lcfg, true)) { + ERR_MSG("Subkey generation setup failed."); + return false; + } + std::vector keys; + if (!cli_rnp_keys_matching_string(this, keys, key, CLI_SEARCH_SECRET)) { + ERR_MSG("Secret keys matching '%s' not found.", key.c_str()); + return false; + } + bool res = false; + rnp_op_generate_t genkey = NULL; + rnp_key_handle_t subkey = NULL; + char * password = NULL; + + if (keys.size() > 1) { + ERR_MSG("Ambiguous input: too many keys found for '%s'.", key.c_str()); + goto done; + } + if (rnp_op_generate_subkey_create( + &genkey, ffi, keys[0], cfg().get_cstr(CFG_KG_SUBKEY_ALG))) { + ERR_MSG("Failed to initialize subkey generation."); + goto done; + } + if (cfg().has(CFG_KG_SUBKEY_BITS) && + rnp_op_generate_set_bits(genkey, cfg().get_int(CFG_KG_SUBKEY_BITS))) { + ERR_MSG("Failed to set subkey bits."); + goto done; + } + if (cfg().has(CFG_KG_SUBKEY_CURVE) && + rnp_op_generate_set_curve(genkey, cfg().get_cstr(CFG_KG_SUBKEY_CURVE))) { + ERR_MSG("Failed to set subkey curve."); + goto done; + } + if (cfg().has(CFG_KG_SUBKEY_EXPIRATION)) { + uint32_t expiration = 0; + if (!cfg().get_expiration(CFG_KG_SUBKEY_EXPIRATION, expiration) || + rnp_op_generate_set_expiration(genkey, expiration)) { + ERR_MSG("Failed to set subkey expiration."); + goto done; + } + } + // TODO : set DSA qbits + if (rnp_op_generate_set_hash(genkey, cfg().get_cstr(CFG_KG_HASH))) { + ERR_MSG("Failed to set hash algorithm."); + goto done; + } + if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &subkey)) { + ERR_MSG("Subkey generation failed."); + goto done; + } + if (rnp_request_password(ffi, subkey, "protect", &password)) { + ERR_MSG("Failed to obtain protection password."); + goto done; + } + if (*password) { + rnp_result_t ret = rnp_key_protect(subkey, + password, + cfg().get_cstr(CFG_KG_PROT_ALG), + NULL, + cfg().get_cstr(CFG_KG_PROT_HASH), + cfg().get_int(CFG_KG_PROT_ITERATIONS)); + rnp_buffer_clear(password, strlen(password) + 1); + rnp_buffer_destroy(password); + if (ret) { + ERR_MSG("Failed to protect key."); + goto done; + } + } else { + rnp_buffer_destroy(password); + } + res = cli_rnp_save_keyrings(this); +done: + if (res) { + cli_rnp_print_key_info(stdout, ffi, keys[0], true, false); + if (subkey) { + cli_rnp_print_key_info(stdout, ffi, subkey, true, false); + } + } + clear_key_handles(keys); + rnp_op_generate_destroy(genkey); + rnp_key_handle_destroy(subkey); + return res; +} + +bool +cli_rnp_t::edit_key(const std::string &key) +{ + int edit_options = 0; + + if (cfg().get_bool(CFG_CHK_25519_BITS)) { + edit_options++; + } + if (cfg().get_bool(CFG_FIX_25519_BITS)) { + edit_options++; + } + if (cfg().get_bool(CFG_ADD_SUBKEY)) { + edit_options++; + } + if (cfg().has(CFG_SET_KEY_EXPIRE)) { + edit_options++; + } + + if (!edit_options) { + ERR_MSG("You should specify one of the editing options for --edit-key."); + return false; + } + if (edit_options > 1) { + ERR_MSG("Only one key edit option can be executed at a time."); + return false; + } + + if (cfg().get_bool(CFG_CHK_25519_BITS)) { + return fix_cv25519_subkey(key, true); + } + if (cfg().get_bool(CFG_FIX_25519_BITS)) { + return fix_cv25519_subkey(key, false); + } + + if (cfg().get_bool(CFG_ADD_SUBKEY)) { + return add_new_subkey(key); + } + + if (cfg().has(CFG_SET_KEY_EXPIRE)) { + return set_key_expire(key); + } + + return false; +} + +const char * +json_obj_get_str(json_object *obj, const char *key) +{ + json_object *fld = NULL; + if (!json_object_object_get_ex(obj, key, &fld)) { + return NULL; + } + return json_object_get_string(fld); +} + +static char * +cli_key_usage_str(rnp_key_handle_t key, char *buf) +{ + char *orig = buf; + bool allow = false; + + if (!rnp_key_allows_usage(key, "encrypt", &allow) && allow) { + *buf++ = 'E'; + } + allow = false; + if (!rnp_key_allows_usage(key, "sign", &allow) && allow) { + *buf++ = 'S'; + } + allow = false; + if (!rnp_key_allows_usage(key, "certify", &allow) && allow) { + *buf++ = 'C'; + } + allow = false; + if (!rnp_key_allows_usage(key, "authenticate", &allow) && allow) { + *buf++ = 'A'; + } + *buf = '\0'; + return orig; +} + +std::string +cli_rnp_escape_string(const std::string &src) +{ + static const int SPECIAL_CHARS_COUNT = 0x20; + static const char *escape_map[SPECIAL_CHARS_COUNT + 1] = { + "\\x00", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\x07", + "\\b", "\\x09", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", + "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", + "\\x18", "\\x19", "\\x1a", "\\x1b", "\\x1c", "\\x1d", "\\x1e", "\\x1f", + "\\x20" // space should not be auto-replaced + }; + std::string result; + // we want to replace leading and trailing spaces with escape codes to make them visible + auto original_len = src.length(); + std::string rtrimmed = src; + bool leading_space = true; + rtrimmed.erase(rtrimmed.find_last_not_of(0x20) + 1); + result.reserve(original_len); + for (char const &c : rtrimmed) { + leading_space &= c == 0x20; + if (leading_space || (c >= 0 && c < SPECIAL_CHARS_COUNT)) { + result.append(escape_map[(int) c]); + } else { + result.push_back(c); + } + } + // printing trailing spaces + for (auto pos = rtrimmed.length(); pos < original_len; pos++) { + result.append(escape_map[0x20]); + } + return result; +} + +static const std::string alg_aliases[] = { + "3DES", "TRIPLEDES", "3-DES", "TRIPLEDES", "CAST-5", "CAST5", + "AES", "AES128", "AES-128", "AES128", "AES-192", "AES192", + "AES-256", "AES256", "CAMELLIA-128", "CAMELLIA128", "CAMELLIA-192", "CAMELLIA192", + "CAMELLIA-256", "CAMELLIA256", "SHA", "SHA1", "SHA-1", "SHA1", + "SHA-224", "SHA224", "SHA-256", "SHA256", "SHA-384", "SHA384", + "SHA-512", "SHA512", "RIPEMD-160", "RIPEMD160"}; + +const std::string +cli_rnp_alg_to_ffi(const std::string alg) +{ + size_t count = sizeof(alg_aliases) / sizeof(alg_aliases[0]); + assert((count % 2) == 0); + for (size_t idx = 0; idx < count; idx += 2) { + if (rnp::str_case_eq(alg, alg_aliases[idx])) { + return alg_aliases[idx + 1]; + } + } + return alg; +} + +bool +cli_rnp_set_hash(rnp_cfg &cfg, const std::string &hash) +{ + bool supported = false; + auto &alg = cli_rnp_alg_to_ffi(hash); + if (rnp_supports_feature(RNP_FEATURE_HASH_ALG, alg.c_str(), &supported) || !supported) { + ERR_MSG("Unsupported hash algorithm: %s", hash.c_str()); + return false; + } + cfg.set_str(CFG_HASH, alg); + return true; +} + +bool +cli_rnp_set_cipher(rnp_cfg &cfg, const std::string &cipher) +{ + bool supported = false; + auto &alg = cli_rnp_alg_to_ffi(cipher); + if (rnp_supports_feature(RNP_FEATURE_SYMM_ALG, alg.c_str(), &supported) || !supported) { + ERR_MSG("Unsupported encryption algorithm: %s", cipher.c_str()); + return false; + } + cfg.set_str(CFG_CIPHER, alg); + return true; +} + +#ifndef RNP_USE_STD_REGEX +static std::string +cli_rnp_unescape_for_regcomp(const std::string &src) +{ + std::string result; + result.reserve(src.length()); + regex_t r = {}; + regmatch_t matches[1]; + if (regcomp(&r, "\\\\x[0-9a-f]([0-9a-f])?", REG_EXTENDED | REG_ICASE) != 0) + return src; + + int offset = 0; + while (regexec(&r, src.c_str() + offset, 1, matches, 0) == 0) { + result.append(src, offset, matches[0].rm_so); + int hexoff = matches[0].rm_so + 2; + std::string hex; + hex.push_back(src[offset + hexoff]); + if (hexoff + 1 < matches[0].rm_eo) { + hex.push_back(src[offset + hexoff + 1]); + } + char decoded = stoi(hex, 0, 16); + if ((decoded >= 0x7B && decoded <= 0x7D) || (decoded >= 0x24 && decoded <= 0x2E) || + decoded == 0x5C || decoded == 0x5E) { + result.push_back('\\'); + result.push_back(decoded); + } else if ((decoded == '[' || decoded == ']') && + /* not enclosed in [] */ (result.empty() || result.back() != '[')) { + result.push_back('['); + result.push_back(decoded); + result.push_back(']'); + } else { + result.push_back(decoded); + } + offset += matches[0].rm_eo; + } + + result.append(src.begin() + offset, src.end()); + + return result; +} +#endif + +/* Convert key algorithm constant to one displayed to the user */ +static const char * +cli_rnp_normalize_key_alg(const char *alg) +{ + if (!strcmp(alg, RNP_ALGNAME_EDDSA)) { + return "EdDSA"; + } + if (!strcmp(alg, RNP_ALGNAME_ELGAMAL)) { + return "ElGamal"; + } + return alg; +} + +static void +cli_rnp_print_sig_info(FILE *fp, rnp_ffi_t ffi, rnp_signature_handle_t sig) +{ + uint32_t creation = 0; + (void) rnp_signature_get_creation(sig, &creation); + + char *keyfp = NULL; + char *keyid = NULL; + (void) rnp_signature_get_key_fprint(sig, &keyfp); + (void) rnp_signature_get_keyid(sig, &keyid); + + char * signer_uid = NULL; + rnp_key_handle_t signer = NULL; + if (keyfp) { + /* Fingerprint lookup is faster */ + (void) rnp_locate_key(ffi, "fingerprint", keyfp, &signer); + } else if (keyid) { + (void) rnp_locate_key(ffi, "keyid", keyid, &signer); + } + if (signer) { + /* signer primary uid */ + (void) rnp_key_get_primary_uid(signer, &signer_uid); + } + + /* signer key id */ + fprintf(fp, "sig %s ", keyid ? rnp::lowercase(keyid) : "[no key id]"); + /* signature creation time */ + char buf[64] = {0}; + fprintf(fp, "%s", ptimestr(buf, sizeof(buf), creation)); + /* signer's userid */ + fprintf(fp, " %s", signer_uid ? signer_uid : "[unknown]"); + /* signature validity */ + const char * valmsg = NULL; + rnp_result_t validity = rnp_signature_is_valid(sig, 0); + switch (validity) { + case RNP_SUCCESS: + valmsg = ""; + break; + case RNP_ERROR_SIGNATURE_EXPIRED: + valmsg = " [expired]"; + break; + case RNP_ERROR_SIGNATURE_INVALID: + valmsg = " [invalid]"; + break; + default: + valmsg = " [unverified]"; + } + fprintf(fp, "%s\n", valmsg); + + (void) rnp_key_handle_destroy(signer); + rnp_buffer_destroy(keyid); + rnp_buffer_destroy(keyfp); + rnp_buffer_destroy(signer_uid); +} + +void +cli_rnp_print_key_info(FILE *fp, rnp_ffi_t ffi, rnp_key_handle_t key, bool psecret, bool psigs) +{ + char buf[64] = {0}; + const char *header = NULL; + bool secret = false; + bool primary = false; + + /* header */ + if (rnp_key_have_secret(key, &secret) || rnp_key_is_primary(key, &primary)) { + fprintf(fp, "Key error.\n"); + return; + } + + if (psecret && secret) { + header = primary ? "sec" : "ssb"; + } else { + header = primary ? "pub" : "sub"; + } + if (primary) { + fprintf(fp, "\n"); + } + fprintf(fp, "%s ", header); + + /* key bits */ + uint32_t bits = 0; + rnp_key_get_bits(key, &bits); + fprintf(fp, "%d/", (int) bits); + /* key algorithm */ + char *alg = NULL; + (void) rnp_key_get_alg(key, &alg); + fprintf(fp, "%s ", cli_rnp_normalize_key_alg(alg)); + /* key id */ + char *keyid = NULL; + (void) rnp_key_get_keyid(key, &keyid); + fprintf(fp, "%s", rnp::lowercase(keyid)); + /* key creation time */ + uint32_t create = 0; + (void) rnp_key_get_creation(key, &create); + fprintf(fp, " %s", ptimestr(buf, sizeof(buf), create)); + /* key usage */ + bool valid = false; + bool expired = false; + bool revoked = false; + (void) rnp_key_is_valid(key, &valid); + (void) rnp_key_is_expired(key, &expired); + (void) rnp_key_is_revoked(key, &revoked); + if (valid || expired || revoked) { + fprintf(fp, " [%s]", cli_key_usage_str(key, buf)); + } else { + fprintf(fp, " [INVALID]"); + } + /* key expiration */ + uint32_t expiry = 0; + (void) rnp_key_get_expiration(key, &expiry); + if (expiry) { + ptimestr(buf, sizeof(buf), create + expiry); + fprintf(fp, " [%s %s]", expired ? "EXPIRED" : "EXPIRES", buf); + } + /* key is revoked */ + if (revoked) { + fprintf(fp, " [REVOKED]"); + } + /* fingerprint */ + char *keyfp = NULL; + (void) rnp_key_get_fprint(key, &keyfp); + fprintf(fp, "\n %s\n", rnp::lowercase(keyfp)); + /* direct-key or binding signatures */ + if (psigs) { + size_t sigs = 0; + (void) rnp_key_get_signature_count(key, &sigs); + for (size_t i = 0; i < sigs; i++) { + rnp_signature_handle_t sig = NULL; + (void) rnp_key_get_signature_at(key, i, &sig); + if (!sig) { + continue; + } + cli_rnp_print_sig_info(fp, ffi, sig); + rnp_signature_handle_destroy(sig); + } + } + /* user ids */ + size_t uids = 0; + (void) rnp_key_get_uid_count(key, &uids); + for (size_t i = 0; i < uids; i++) { + rnp_uid_handle_t uid = NULL; + + if (rnp_key_get_uid_handle_at(key, i, &uid)) { + continue; + } + bool revoked = false; + bool valid = false; + char *uid_str = NULL; + (void) rnp_uid_is_revoked(uid, &revoked); + (void) rnp_uid_is_valid(uid, &valid); + (void) rnp_key_get_uid_at(key, i, &uid_str); + + /* userid itself with revocation status */ + fprintf(fp, "uid %s", cli_rnp_escape_string(uid_str).c_str()); + fprintf(fp, "%s\n", revoked ? " [REVOKED]" : valid ? "" : " [INVALID]"); + rnp_buffer_destroy(uid_str); + + /* print signatures only if requested */ + if (!psigs) { + (void) rnp_uid_handle_destroy(uid); + continue; + } + + size_t sigs = 0; + (void) rnp_uid_get_signature_count(uid, &sigs); + for (size_t j = 0; j < sigs; j++) { + rnp_signature_handle_t sig = NULL; + (void) rnp_uid_get_signature_at(uid, j, &sig); + if (!sig) { + continue; + } + cli_rnp_print_sig_info(fp, ffi, sig); + rnp_signature_handle_destroy(sig); + } + (void) rnp_uid_handle_destroy(uid); + } + + rnp_buffer_destroy(alg); + rnp_buffer_destroy(keyid); + rnp_buffer_destroy(keyfp); +} + +bool +cli_rnp_save_keyrings(cli_rnp_t *rnp) +{ + rnp_output_t output = NULL; + rnp_result_t pub_ret = 0; + rnp_result_t sec_ret = 0; + const std::string &ppath = rnp->pubpath(); + const std::string &spath = rnp->secpath(); + + // check whether we have G10 secret keyring - then need to create directory + if (rnp->secformat() == "G10") { + struct stat path_stat; + if (rnp_stat(spath.c_str(), &path_stat) != -1) { + if (!S_ISDIR(path_stat.st_mode)) { + ERR_MSG("G10 keystore should be a directory: %s", spath.c_str()); + return false; + } + } else { + if (errno != ENOENT) { + ERR_MSG("stat(%s): %s", spath.c_str(), strerror(errno)); + return false; + } + if (RNP_MKDIR(spath.c_str(), S_IRWXU) != 0) { + ERR_MSG("mkdir(%s, S_IRWXU): %s", spath.c_str(), strerror(errno)); + return false; + } + } + } + + // public keyring + if (!(pub_ret = rnp_output_to_path(&output, ppath.c_str()))) { + pub_ret = + rnp_save_keys(rnp->ffi, rnp->pubformat().c_str(), output, RNP_LOAD_SAVE_PUBLIC_KEYS); + rnp_output_destroy(output); + } + if (pub_ret) { + ERR_MSG("failed to write pubring to path '%s'", ppath.c_str()); + } + + // secret keyring + if (!(sec_ret = rnp_output_to_path(&output, spath.c_str()))) { + sec_ret = + rnp_save_keys(rnp->ffi, rnp->secformat().c_str(), output, RNP_LOAD_SAVE_SECRET_KEYS); + rnp_output_destroy(output); + } + if (sec_ret) { + ERR_MSG("failed to write secring to path '%s'", spath.c_str()); + } + + return !pub_ret && !sec_ret; +} + +bool +cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) +{ + /* set key generation parameters to rnp_cfg_t */ + rnp_cfg &cfg = rnp->cfg(); + if (!cli_rnp_set_generate_params(cfg)) { + ERR_MSG("Key generation setup failed."); + return false; + } + /* generate the primary key */ + rnp_op_generate_t genkey = NULL; + rnp_key_handle_t primary = NULL; + rnp_key_handle_t subkey = NULL; + bool res = false; + + if (rnp_op_generate_create(&genkey, rnp->ffi, cfg.get_cstr(CFG_KG_PRIMARY_ALG))) { + ERR_MSG("Failed to initialize key generation."); + return false; + } + if (username && rnp_op_generate_set_userid(genkey, username)) { + ERR_MSG("Failed to set userid."); + goto done; + } + if (cfg.has(CFG_KG_PRIMARY_BITS) && + rnp_op_generate_set_bits(genkey, cfg.get_int(CFG_KG_PRIMARY_BITS))) { + ERR_MSG("Failed to set key bits."); + goto done; + } + if (cfg.has(CFG_KG_PRIMARY_CURVE) && + rnp_op_generate_set_curve(genkey, cfg.get_cstr(CFG_KG_PRIMARY_CURVE))) { + ERR_MSG("Failed to set key curve."); + goto done; + } + if (cfg.has(CFG_KG_PRIMARY_EXPIRATION)) { + uint32_t expiration = 0; + if (!cfg.get_expiration(CFG_KG_PRIMARY_EXPIRATION, expiration) || + rnp_op_generate_set_expiration(genkey, expiration)) { + ERR_MSG("Failed to set primary key expiration."); + goto done; + } + } + // TODO : set DSA qbits + if (rnp_op_generate_set_hash(genkey, cfg.get_cstr(CFG_KG_HASH))) { + ERR_MSG("Failed to set hash algorithm."); + goto done; + } + + fprintf(rnp->userio_out, "Generating a new key...\n"); + if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &primary)) { + ERR_MSG("Primary key generation failed."); + goto done; + } + + if (!cfg.has(CFG_KG_SUBKEY_ALG)) { + res = true; + goto done; + } + + rnp_op_generate_destroy(genkey); + genkey = NULL; + if (rnp_op_generate_subkey_create( + &genkey, rnp->ffi, primary, cfg.get_cstr(CFG_KG_SUBKEY_ALG))) { + ERR_MSG("Failed to initialize subkey generation."); + goto done; + } + if (cfg.has(CFG_KG_SUBKEY_BITS) && + rnp_op_generate_set_bits(genkey, cfg.get_int(CFG_KG_SUBKEY_BITS))) { + ERR_MSG("Failed to set subkey bits."); + goto done; + } + if (cfg.has(CFG_KG_SUBKEY_CURVE) && + rnp_op_generate_set_curve(genkey, cfg.get_cstr(CFG_KG_SUBKEY_CURVE))) { + ERR_MSG("Failed to set subkey curve."); + goto done; + } + if (cfg.has(CFG_KG_SUBKEY_EXPIRATION)) { + uint32_t expiration = 0; + if (!cfg.get_expiration(CFG_KG_SUBKEY_EXPIRATION, expiration) || + rnp_op_generate_set_expiration(genkey, expiration)) { + ERR_MSG("Failed to set subkey expiration."); + goto done; + } + } + // TODO : set DSA qbits + if (rnp_op_generate_set_hash(genkey, cfg.get_cstr(CFG_KG_HASH))) { + ERR_MSG("Failed to set hash algorithm."); + goto done; + } + if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &subkey)) { + ERR_MSG("Subkey generation failed."); + goto done; + } + + // protect + for (auto key : {primary, subkey}) { + char *password = NULL; + if (rnp_request_password(rnp->ffi, key, "protect", &password)) { + ERR_MSG("Failed to obtain protection password."); + goto done; + } + if (*password) { + rnp_result_t ret = rnp_key_protect(key, + password, + cfg.get_cstr(CFG_KG_PROT_ALG), + NULL, + cfg.get_cstr(CFG_KG_PROT_HASH), + cfg.get_int(CFG_KG_PROT_ITERATIONS)); + rnp_buffer_clear(password, strlen(password) + 1); + rnp_buffer_destroy(password); + if (ret) { + ERR_MSG("Failed to protect key."); + goto done; + } + } else { + rnp_buffer_destroy(password); + } + } + res = cli_rnp_save_keyrings(rnp); +done: + if (res) { + cli_rnp_print_key_info(stdout, rnp->ffi, primary, true, false); + if (subkey) { + cli_rnp_print_key_info(stdout, rnp->ffi, subkey, true, false); + } + } + rnp_op_generate_destroy(genkey); + rnp_key_handle_destroy(primary); + rnp_key_handle_destroy(subkey); + return res; +} + +static bool +key_matches_string(rnp_key_handle_t handle, const std::string &str) +{ + bool matches = false; + char * id = NULL; + size_t idlen = 0; +#ifndef RNP_USE_STD_REGEX + regex_t r = {}; +#else + std::regex re; +#endif + size_t uid_count = 0; + bool boolres = false; + + if (str.empty()) { + matches = true; + goto done; + } + if (rnp::is_hex(str) && (str.length() >= RNP_KEYID_SIZE)) { + std::string hexstr = rnp::strip_hex(str); + size_t len = hexstr.length(); + + /* check whether it's key id */ + if ((len == RNP_KEYID_SIZE * 2) || (len == RNP_KEYID_SIZE)) { + if (rnp_key_get_keyid(handle, &id)) { + goto done; + } + if ((idlen = strlen(id)) < len) { + goto done; + } + if (strncasecmp(hexstr.c_str(), id + idlen - len, len) == 0) { + matches = true; + goto done; + } + rnp_buffer_destroy(id); + id = NULL; + } + + /* check fingerprint */ + if (len == RNP_FP_SIZE * 2) { + if (rnp_key_get_fprint(handle, &id)) { + goto done; + } + if (strlen(id) != len) { + goto done; + } + if (strncasecmp(hexstr.c_str(), id, len) == 0) { + matches = true; + goto done; + } + rnp_buffer_destroy(id); + id = NULL; + } + + /* check grip */ + if (len == RNP_GRIP_SIZE * 2) { + if (rnp_key_get_grip(handle, &id)) { + goto done; + } + if (strlen(id) != len) { + goto done; + } + if (strncasecmp(hexstr.c_str(), id, len) == 0) { + matches = true; + goto done; + } + rnp_buffer_destroy(id); + id = NULL; + } + /* let then search for hex userid */ + } + + /* no need to check for userid over the subkey */ + if (rnp_key_is_sub(handle, &boolres) || boolres) { + goto done; + } + if (rnp_key_get_uid_count(handle, &uid_count) || (uid_count == 0)) { + goto done; + } + +#ifndef RNP_USE_STD_REGEX + /* match on full name or email address as a NOSUB, ICASE regexp */ + if (regcomp(&r, cli_rnp_unescape_for_regcomp(str).c_str(), REG_EXTENDED | REG_ICASE) != + 0) { + goto done; + } +#else + try { + re.assign(str, std::regex_constants::ECMAScript | std::regex_constants::icase); + } catch (const std::exception &e) { + ERR_MSG("Invalid regular expression : %s, error %s.", str.c_str(), e.what()); + goto done; + } +#endif + + for (size_t idx = 0; idx < uid_count; idx++) { + if (rnp_key_get_uid_at(handle, idx, &id)) { + goto regdone; + } +#ifndef RNP_USE_STD_REGEX + if (regexec(&r, id, 0, NULL, 0) == 0) { + matches = true; + goto regdone; + } +#else + if (std::regex_search(id, re)) { + matches = true; + goto regdone; + } +#endif + rnp_buffer_destroy(id); + id = NULL; + } + +regdone: +#ifndef RNP_USE_STD_REGEX + regfree(&r); +#endif +done: + rnp_buffer_destroy(id); + return matches; +} + +static bool +key_matches_flags(rnp_key_handle_t key, int flags) +{ + /* check whether secret key search is requested */ + bool secret = false; + if (rnp_key_have_secret(key, &secret)) { + return false; + } + if ((flags & CLI_SEARCH_SECRET) && !secret) { + return false; + } + /* check whether no subkeys allowed */ + bool subkey = false; + if (rnp_key_is_sub(key, &subkey)) { + return false; + } + if (!subkey) { + return true; + } + if (!(flags & CLI_SEARCH_SUBKEYS)) { + return false; + } + /* check whether subkeys should be put after primary (if it is available) */ + if ((flags & CLI_SEARCH_SUBKEYS_AFTER) != CLI_SEARCH_SUBKEYS_AFTER) { + return true; + } + + char *grip = NULL; + if (rnp_key_get_primary_grip(key, &grip)) { + return false; + } + if (!grip) { + return true; + } + rnp_buffer_destroy(grip); + return false; +} + +void +clear_key_handles(std::vector &keys) +{ + for (auto handle : keys) { + rnp_key_handle_destroy(handle); + } + keys.clear(); +} + +static bool +add_key_to_array(rnp_ffi_t ffi, + std::vector &keys, + rnp_key_handle_t key, + int flags) +{ + bool subkey = false; + bool subkeys = (flags & CLI_SEARCH_SUBKEYS_AFTER) == CLI_SEARCH_SUBKEYS_AFTER; + if (rnp_key_is_sub(key, &subkey)) { + return false; + } + + try { + keys.push_back(key); + } catch (const std::exception &e) { + ERR_MSG("%s", e.what()); + return false; + } + if (!subkeys || subkey) { + return true; + } + + std::vector subs; + size_t sub_count = 0; + if (rnp_key_get_subkey_count(key, &sub_count)) { + goto error; + } + + try { + for (size_t i = 0; i < sub_count; i++) { + rnp_key_handle_t sub_handle = NULL; + if (rnp_key_get_subkey_at(key, i, &sub_handle)) { + goto error; + } + subs.push_back(sub_handle); + } + std::move(subs.begin(), subs.end(), std::back_inserter(keys)); + } catch (const std::exception &e) { + ERR_MSG("%s", e.what()); + goto error; + } + return true; +error: + keys.pop_back(); + clear_key_handles(subs); + return false; +} + +bool +cli_rnp_keys_matching_string(cli_rnp_t * rnp, + std::vector &keys, + const std::string & str, + int flags) +{ + bool res = false; + rnp_identifier_iterator_t it = NULL; + rnp_key_handle_t handle = NULL; + const char * fp = NULL; + + /* iterate through the keys */ + if (rnp_identifier_iterator_create(rnp->ffi, &it, "fingerprint")) { + return false; + } + + while (!rnp_identifier_iterator_next(it, &fp)) { + if (!fp) { + break; + } + if (rnp_locate_key(rnp->ffi, "fingerprint", fp, &handle) || !handle) { + goto done; + } + if (!key_matches_flags(handle, flags) || !key_matches_string(handle, str.c_str())) { + rnp_key_handle_destroy(handle); + continue; + } + if (!add_key_to_array(rnp->ffi, keys, handle, flags)) { + rnp_key_handle_destroy(handle); + goto done; + } + if (flags & CLI_SEARCH_FIRST_ONLY) { + res = true; + goto done; + } + } + res = !keys.empty(); +done: + rnp_identifier_iterator_destroy(it); + return res; +} + +bool +cli_rnp_keys_matching_strings(cli_rnp_t * rnp, + std::vector & keys, + const std::vector &strs, + int flags) +{ + bool res = false; + clear_key_handles(keys); + + for (const std::string &str : strs) { + if (!cli_rnp_keys_matching_string(rnp, keys, str, flags & ~CLI_SEARCH_DEFAULT)) { + ERR_MSG("Cannot find key matching \"%s\"", str.c_str()); + goto done; + } + } + + /* search for default key */ + if (keys.empty() && (flags & CLI_SEARCH_DEFAULT)) { + if (rnp->defkey().empty()) { + ERR_MSG("No userid or default key for operation"); + goto done; + } + cli_rnp_keys_matching_string(rnp, keys, rnp->defkey(), flags & ~CLI_SEARCH_DEFAULT); + if (keys.empty()) { + ERR_MSG("Default key not found"); + } + } + res = !keys.empty(); +done: + if (!res) { + clear_key_handles(keys); + } + return res; +} + +static bool +rnp_cfg_set_ks_info(rnp_cfg &cfg) +{ + if (cfg.get_bool(CFG_KEYSTORE_DISABLED)) { + cfg.set_str(CFG_KR_PUB_PATH, ""); + cfg.set_str(CFG_KR_SEC_PATH, ""); + cfg.set_str(CFG_KR_PUB_FORMAT, RNP_KEYSTORE_GPG); + cfg.set_str(CFG_KR_SEC_FORMAT, RNP_KEYSTORE_GPG); + return true; + } + + /* getting path to keyrings. If it is specified by user in 'homedir' param then it is + * considered as the final path */ + bool defhomedir = false; + std::string homedir = cfg.get_str(CFG_HOMEDIR); + if (homedir.empty()) { + homedir = rnp::path::HOME(); + defhomedir = true; + } + + /* Check whether $HOME or homedir exists */ + struct stat st; + if (rnp_stat(homedir.c_str(), &st) || rnp_access(homedir.c_str(), R_OK | W_OK)) { + ERR_MSG("Home directory '%s' does not exist or is not writable!", homedir.c_str()); + return false; + } + + /* creating home dir if needed */ + if (defhomedir) { + char *rnphome = NULL; + if (rnp_get_default_homedir(&rnphome)) { + ERR_MSG("Failed to obtain default home directory."); + return false; + } + homedir = rnphome; + rnp_buffer_destroy(rnphome); + if (!rnp::path::exists(homedir, true) && RNP_MKDIR(homedir.c_str(), 0700) == -1 && + errno != EEXIST) { + ERR_MSG("Cannot mkdir '%s' errno = %d", homedir.c_str(), errno); + return false; + } + } + + /* detecting key storage format */ + std::string ks_format = cfg.get_str(CFG_KEYSTOREFMT); + if (ks_format.empty()) { + char *pub_format = NULL; + char *sec_format = NULL; + char *pubpath = NULL; + char *secpath = NULL; + rnp_detect_homedir_info(homedir.c_str(), &pub_format, &pubpath, &sec_format, &secpath); + bool detected = pub_format && sec_format && pubpath && secpath; + if (detected) { + cfg.set_str(CFG_KR_PUB_FORMAT, pub_format); + cfg.set_str(CFG_KR_SEC_FORMAT, sec_format); + cfg.set_str(CFG_KR_PUB_PATH, pubpath); + cfg.set_str(CFG_KR_SEC_PATH, secpath); + } else { + /* default to GPG */ + ks_format = RNP_KEYSTORE_GPG; + } + rnp_buffer_destroy(pub_format); + rnp_buffer_destroy(sec_format); + rnp_buffer_destroy(pubpath); + rnp_buffer_destroy(secpath); + if (detected) { + return true; + } + } + + std::string pub_format = RNP_KEYSTORE_GPG; + std::string sec_format = RNP_KEYSTORE_GPG; + std::string pubpath; + std::string secpath; + + if (ks_format == RNP_KEYSTORE_GPG) { + pubpath = rnp::path::append(homedir, PUBRING_GPG); + secpath = rnp::path::append(homedir, SECRING_GPG); + } else if (ks_format == RNP_KEYSTORE_GPG21) { + pubpath = rnp::path::append(homedir, PUBRING_KBX); + secpath = rnp::path::append(homedir, SECRING_G10); + pub_format = RNP_KEYSTORE_KBX; + sec_format = RNP_KEYSTORE_G10; + } else if (ks_format == RNP_KEYSTORE_KBX) { + pubpath = rnp::path::append(homedir, PUBRING_KBX); + secpath = rnp::path::append(homedir, SECRING_KBX); + pub_format = RNP_KEYSTORE_KBX; + sec_format = RNP_KEYSTORE_KBX; + } else if (ks_format == RNP_KEYSTORE_G10) { + pubpath = rnp::path::append(homedir, PUBRING_G10); + secpath = rnp::path::append(homedir, SECRING_G10); + pub_format = RNP_KEYSTORE_G10; + sec_format = RNP_KEYSTORE_G10; + } else { + ERR_MSG("Unsupported keystore format: \"%s\"", ks_format.c_str()); + return false; + } + + /* Check whether homedir is empty */ + if (rnp::path::empty(homedir)) { + ERR_MSG("Keyring directory '%s' is empty.\nUse \"rnpkeys\" command to generate a new " + "key or import existing keys from the file or GnuPG keyrings.", + homedir.c_str()); + } + + cfg.set_str(CFG_KR_PUB_PATH, pubpath); + cfg.set_str(CFG_KR_SEC_PATH, secpath); + cfg.set_str(CFG_KR_PUB_FORMAT, pub_format); + cfg.set_str(CFG_KR_SEC_FORMAT, sec_format); + return true; +} + +static void +rnp_cfg_set_defkey(rnp_cfg &cfg) +{ + /* If a userid has been given, we'll use it. */ + std::string userid = cfg.get_count(CFG_USERID) ? cfg.get_str(CFG_USERID, 0) : ""; + if (!userid.empty()) { + cfg.set_str(CFG_KR_DEF_KEY, userid); + } +} + +bool +cli_cfg_set_keystore_info(rnp_cfg &cfg) +{ + /* detecting keystore paths and format */ + if (!rnp_cfg_set_ks_info(cfg)) { + return false; + } + + /* default key/userid */ + rnp_cfg_set_defkey(cfg); + return true; +} + +static bool +is_stdinout_spec(const std::string &spec) +{ + return spec.empty() || (spec == "-"); +} + +rnp_input_t +cli_rnp_input_from_specifier(cli_rnp_t &rnp, const std::string &spec, bool *is_path) +{ + rnp_input_t input = NULL; + rnp_result_t res = RNP_ERROR_GENERIC; + bool path = false; + if (is_stdinout_spec(spec)) { + /* input from stdin */ + res = rnp_input_from_stdin(&input); + } else if ((spec.size() > 4) && (spec.compare(0, 4, "env:") == 0)) { + /* input from an environment variable */ + const char *envval = getenv(spec.c_str() + 4); + if (!envval) { + ERR_MSG("Failed to get value of the environment variable '%s'.", spec.c_str() + 4); + return NULL; + } + res = rnp_input_from_memory(&input, (const uint8_t *) envval, strlen(envval), true); + } else { + /* input from path */ + res = rnp_input_from_path(&input, spec.c_str()); + path = true; + } + + if (res) { + return NULL; + } + if (is_path) { + *is_path = path; + } + return input; +} + +rnp_output_t +cli_rnp_output_to_specifier(cli_rnp_t &rnp, const std::string &spec, bool discard) +{ + rnp_output_t output = NULL; + rnp_result_t res = RNP_ERROR_GENERIC; + std::string path = spec; + if (discard) { + res = rnp_output_to_null(&output); + } else if (is_stdinout_spec(spec)) { + res = rnp_output_to_stdout(&output); + } else if (!rnp_get_output_filename(spec, path, rnp)) { + if (spec.empty()) { + ERR_MSG("Operation failed: no output filename specified"); + } else { + ERR_MSG("Operation failed: file '%s' already exists.", spec.c_str()); + } + res = RNP_ERROR_BAD_PARAMETERS; + } else { + res = rnp_output_to_file(&output, path.c_str(), RNP_OUTPUT_FILE_OVERWRITE); + } + return res ? NULL : output; +} + +bool +cli_rnp_export_keys(cli_rnp_t *rnp, const char *filter) +{ + bool secret = rnp->cfg().get_bool(CFG_SECRET); + int flags = secret ? CLI_SEARCH_SECRET : 0; + std::vector keys; + + if (!cli_rnp_keys_matching_string(rnp, keys, filter, flags)) { + ERR_MSG("Key(s) matching '%s' not found.", filter); + return false; + } + + rnp_output_t output = NULL; + rnp_output_t armor = NULL; + uint32_t base_flags = secret ? RNP_KEY_EXPORT_SECRET : RNP_KEY_EXPORT_PUBLIC; + bool result = false; + + output = cli_rnp_output_to_specifier(*rnp, rnp->cfg().get_str(CFG_OUTFILE)); + if (!output) { + goto done; + } + + /* We need single armored stream for all of the keys */ + if (rnp_output_to_armor(output, &armor, secret ? "secret key" : "public key")) { + goto done; + } + + for (auto key : keys) { + uint32_t flags = base_flags; + bool primary = false; + + if (rnp_key_is_primary(key, &primary)) { + goto done; + } + if (primary) { + flags = flags | RNP_KEY_EXPORT_SUBKEYS; + } + + if (rnp_key_export(key, armor, flags)) { + goto done; + } + } + result = !rnp_output_finish(armor); +done: + rnp_output_destroy(armor); + rnp_output_destroy(output); + clear_key_handles(keys); + return result; +} + +bool +cli_rnp_export_revocation(cli_rnp_t *rnp, const char *key) +{ + std::vector keys; + if (!cli_rnp_keys_matching_string(rnp, keys, key, 0)) { + ERR_MSG("Key matching '%s' not found.", key); + return false; + } + if (keys.size() > 1) { + ERR_MSG("Ambiguous input: too many keys found for '%s'.", key); + clear_key_handles(keys); + return false; + } + rnp_output_t output = NULL; + bool result = false; + + output = cli_rnp_output_to_specifier(*rnp, rnp->cfg().get_str(CFG_OUTFILE)); + if (!output) { + goto done; + } + + result = !rnp_key_export_revocation(keys[0], + output, + RNP_KEY_EXPORT_ARMORED, + rnp->cfg().get_cstr(CFG_HASH), + rnp->cfg().get_cstr(CFG_REV_TYPE), + rnp->cfg().get_cstr(CFG_REV_REASON)); +done: + rnp_output_destroy(output); + clear_key_handles(keys); + return result; +} + +bool +cli_rnp_revoke_key(cli_rnp_t *rnp, const char *key) +{ + std::vector keys; + if (!cli_rnp_keys_matching_string(rnp, keys, key, CLI_SEARCH_SUBKEYS)) { + ERR_MSG("Key matching '%s' not found.", key); + return false; + } + bool res = false; + bool revoked = false; + rnp_result_t ret = 0; + + if (keys.size() > 1) { + ERR_MSG("Ambiguous input: too many keys found for '%s'.", key); + goto done; + } + if (rnp_key_is_revoked(keys[0], &revoked)) { + ERR_MSG("Error getting key revocation status."); + goto done; + } + if (revoked && !rnp->cfg().get_bool(CFG_FORCE)) { + ERR_MSG("Error: key '%s' is revoked already. Use --force to generate another " + "revocation signature.", + key); + goto done; + } + + ret = rnp_key_revoke(keys[0], + 0, + rnp->cfg().get_cstr(CFG_HASH), + rnp->cfg().get_cstr(CFG_REV_TYPE), + rnp->cfg().get_cstr(CFG_REV_REASON)); + if (ret) { + ERR_MSG("Failed to revoke a key: error %d", (int) ret); + goto done; + } + res = cli_rnp_save_keyrings(rnp); + /* print info about the revoked key */ + if (res) { + bool subkey = false; + char *grip = NULL; + if (rnp_key_is_sub(keys[0], &subkey)) { + ERR_MSG("Failed to get key info"); + goto done; + } + ret = + subkey ? rnp_key_get_primary_grip(keys[0], &grip) : rnp_key_get_grip(keys[0], &grip); + if (ret || !grip) { + ERR_MSG("Failed to get primary key grip."); + goto done; + } + clear_key_handles(keys); + if (!cli_rnp_keys_matching_string(rnp, keys, grip, CLI_SEARCH_SUBKEYS_AFTER)) { + ERR_MSG("Failed to search for revoked key."); + rnp_buffer_destroy(grip); + goto done; + } + rnp_buffer_destroy(grip); + for (auto handle : keys) { + cli_rnp_print_key_info(rnp->userio_out, rnp->ffi, handle, false, false); + } + } +done: + clear_key_handles(keys); + return res; +} + +bool +cli_rnp_remove_key(cli_rnp_t *rnp, const char *key) +{ + std::vector keys; + if (!cli_rnp_keys_matching_string(rnp, keys, key, CLI_SEARCH_SUBKEYS)) { + ERR_MSG("Key matching '%s' not found.", key); + return false; + } + bool res = false; + bool secret = false; + bool primary = false; + uint32_t flags = RNP_KEY_REMOVE_PUBLIC; + rnp_result_t ret = 0; + + if (keys.size() > 1) { + ERR_MSG("Ambiguous input: too many keys found for '%s'.", key); + goto done; + } + if (rnp_key_have_secret(keys[0], &secret)) { + ERR_MSG("Error getting secret key presence."); + goto done; + } + if (rnp_key_is_primary(keys[0], &primary)) { + ERR_MSG("Key error."); + goto done; + } + + if (secret) { + flags |= RNP_KEY_REMOVE_SECRET; + } + if (primary) { + flags |= RNP_KEY_REMOVE_SUBKEYS; + } + + if (secret && !rnp->cfg().get_bool(CFG_FORCE)) { + if (!cli_rnp_get_confirmation( + rnp, + "Key '%s' has corresponding secret key. Do you really want to delete it?", + key)) { + goto done; + } + } + + ret = rnp_key_remove(keys[0], flags); + + if (ret) { + ERR_MSG("Failed to remove the key: error %d", (int) ret); + goto done; + } + res = cli_rnp_save_keyrings(rnp); +done: + clear_key_handles(keys); + return res; +} + +bool +cli_rnp_add_key(cli_rnp_t *rnp) +{ + const std::string &path = rnp->cfg().get_str(CFG_KEYFILE); + if (path.empty()) { + return false; + } + + rnp_input_t input = cli_rnp_input_from_specifier(*rnp, path, NULL); + if (!input) { + ERR_MSG("failed to open key from %s", path.c_str()); + return false; + } + + bool res = !rnp_import_keys( + rnp->ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, NULL); + rnp_input_destroy(input); + + // set default key if we didn't have one + if (res && rnp->defkey().empty()) { + rnp->set_defkey(); + } + return res; +} + +static bool +strip_extension(std::string &src) +{ + size_t dpos = src.find_last_of('.'); + if (dpos == std::string::npos) { + return false; + } + src.resize(dpos); + return true; +} + +static bool +has_extension(const std::string &path, const std::string &ext) +{ + if (path.length() < ext.length()) { + return false; + } + return path.compare(path.length() - ext.length(), ext.length(), ext) == 0; +} + +static std::string +output_extension(const rnp_cfg &cfg, Operation op) +{ + switch (op) { + case Operation::EncryptOrSign: { + bool armor = cfg.get_bool(CFG_ARMOR); + if (cfg.get_bool(CFG_DETACHED)) { + return armor ? EXT_ASC : EXT_SIG; + } + if (cfg.get_bool(CFG_CLEARTEXT)) { + return EXT_ASC; + } + return armor ? EXT_ASC : EXT_PGP; + } + case Operation::Enarmor: + return EXT_ASC; + default: + return ""; + } +} + +static bool +has_pgp_extension(const std::string &path) +{ + return has_extension(path, EXT_PGP) || has_extension(path, EXT_ASC) || + has_extension(path, EXT_GPG); +} + +static std::string +output_strip_extension(Operation op, const std::string &in) +{ + std::string out = in; + if ((op == Operation::Verify) && (has_pgp_extension(out))) { + strip_extension(out); + return out; + } + if ((op == Operation::Dearmor) && (has_extension(out, EXT_ASC))) { + strip_extension(out); + return out; + } + return ""; +} + +static std::string +extract_filename(const std::string path) +{ + size_t lpos = path.find_last_of("/\\"); + if (lpos == std::string::npos) { + return path; + } + return path.substr(lpos + 1); +} + +bool +cli_rnp_t::init_io(Operation op, rnp_input_t *input, rnp_output_t *output) +{ + const std::string &in = cfg().get_str(CFG_INFILE); + bool is_pathin = true; + if (input) { + *input = cli_rnp_input_from_specifier(*this, in, &is_pathin); + if (!*input) { + return false; + } + } + /* Update CFG_SETFNAME to insert into literal packet */ + if (!cfg().has(CFG_SETFNAME) && !is_pathin) { + cfg().set_str(CFG_SETFNAME, ""); + } + + if (!output) { + return true; + } + std::string out = cfg().get_str(CFG_OUTFILE); + bool discard = (op == Operation::Verify) && out.empty() && cfg().get_bool(CFG_NO_OUTPUT); + + if (out.empty() && is_pathin && !discard) { + /* Attempt to guess whether to add or strip extension for known cases */ + std::string ext = output_extension(cfg(), op); + if (!ext.empty()) { + out = in + ext; + } else { + out = output_strip_extension(op, in); + } + } + + *output = cli_rnp_output_to_specifier(*this, out, discard); + if (!*output && input) { + rnp_input_destroy(*input); + *input = NULL; + } + return *output; +} + +bool +cli_rnp_dump_file(cli_rnp_t *rnp) +{ + rnp_input_t input = NULL; + rnp_output_t output = NULL; + uint32_t flags = 0; + uint32_t jflags = 0; + + if (rnp->cfg().get_bool(CFG_GRIPS)) { + flags |= RNP_DUMP_GRIP; + jflags |= RNP_JSON_DUMP_GRIP; + } + if (rnp->cfg().get_bool(CFG_MPIS)) { + flags |= RNP_DUMP_MPI; + jflags |= RNP_JSON_DUMP_MPI; + } + if (rnp->cfg().get_bool(CFG_RAW)) { + flags |= RNP_DUMP_RAW; + jflags |= RNP_JSON_DUMP_RAW; + } + + rnp_result_t ret = 0; + if (!rnp->init_io(Operation::Dump, &input, &output)) { + ERR_MSG("failed to open source or create output"); + ret = 1; + goto done; + } + + if (rnp->cfg().get_bool(CFG_JSON)) { + char *json = NULL; + ret = rnp_dump_packets_to_json(input, jflags, &json); + if (!ret) { + size_t len = strlen(json); + size_t written = 0; + ret = rnp_output_write(output, json, len, &written); + if (written < len) { + ret = RNP_ERROR_WRITE; + } + // add trailing empty line + if (!ret) { + ret = rnp_output_write(output, "\n", 1, &written); + } + if (written < 1) { + ret = RNP_ERROR_WRITE; + } + rnp_buffer_destroy(json); + } + } else { + ret = rnp_dump_packets_to_output(input, output, flags); + } + rnp_input_destroy(input); + rnp_output_destroy(output); +done: + return !ret; +} + +bool +cli_rnp_armor_file(cli_rnp_t *rnp) +{ + rnp_input_t input = NULL; + rnp_output_t output = NULL; + + if (!rnp->init_io(Operation::Enarmor, &input, &output)) { + ERR_MSG("failed to open source or create output"); + return false; + } + rnp_result_t ret = rnp_enarmor(input, output, rnp->cfg().get_cstr(CFG_ARMOR_DATA_TYPE)); + rnp_input_destroy(input); + rnp_output_destroy(output); + return !ret; +} + +bool +cli_rnp_dearmor_file(cli_rnp_t *rnp) +{ + rnp_input_t input = NULL; + rnp_output_t output = NULL; + + if (!rnp->init_io(Operation::Dearmor, &input, &output)) { + ERR_MSG("failed to open source or create output"); + return false; + } + + rnp_result_t ret = rnp_dearmor(input, output); + rnp_input_destroy(input); + rnp_output_destroy(output); + return !ret; +} + +static bool +cli_rnp_sign(const rnp_cfg &cfg, cli_rnp_t *rnp, rnp_input_t input, rnp_output_t output) +{ + rnp_op_sign_t op = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + bool cleartext = cfg.get_bool(CFG_CLEARTEXT); + bool detached = cfg.get_bool(CFG_DETACHED); + + if (cleartext) { + ret = rnp_op_sign_cleartext_create(&op, rnp->ffi, input, output); + } else if (detached) { + ret = rnp_op_sign_detached_create(&op, rnp->ffi, input, output); + } else { + ret = rnp_op_sign_create(&op, rnp->ffi, input, output); + } + + if (ret) { + ERR_MSG("failed to initialize signing"); + return false; + } + + /* setup sign operation via cfg */ + bool res = false; + std::vector signers; + std::vector signkeys; + + if (!cleartext) { + rnp_op_sign_set_armor(op, cfg.get_bool(CFG_ARMOR)); + } + + if (!cleartext && !detached) { + if (cfg.has(CFG_SETFNAME)) { + if (rnp_op_sign_set_file_name(op, cfg.get_str(CFG_SETFNAME).c_str())) { + goto done; + } + } else if (cfg.has(CFG_INFILE)) { + const std::string &fname = cfg.get_str(CFG_INFILE); + if (rnp_op_sign_set_file_name(op, extract_filename(fname).c_str())) { + goto done; + } + rnp_op_sign_set_file_mtime(op, rnp_filemtime(fname.c_str())); + } + if (rnp_op_sign_set_compression(op, cfg.get_cstr(CFG_ZALG), cfg.get_int(CFG_ZLEVEL))) { + goto done; + } + } + + if (rnp_op_sign_set_hash(op, cfg.get_hashalg().c_str())) { + goto done; + } + rnp_op_sign_set_creation_time(op, cfg.get_sig_creation()); + { + uint32_t expiration = 0; + if (cfg.get_expiration(CFG_EXPIRATION, expiration)) { + rnp_op_sign_set_expiration_time(op, expiration); + } + } + + /* signing keys */ + signers = cfg.get_list(CFG_SIGNERS); + if (!cli_rnp_keys_matching_strings(rnp, + signkeys, + signers, + CLI_SEARCH_SECRET | CLI_SEARCH_DEFAULT | + CLI_SEARCH_SUBKEYS | CLI_SEARCH_FIRST_ONLY)) { + ERR_MSG("Failed to build signing keys list"); + goto done; + } + for (rnp_key_handle_t key : signkeys) { + if (rnp_op_sign_add_signature(op, key, NULL)) { + ERR_MSG("Failed to add signature"); + goto done; + } + } + + /* execute sign operation */ + res = !rnp_op_sign_execute(op); +done: + clear_key_handles(signkeys); + rnp_op_sign_destroy(op); + return res; +} + +static bool +cli_rnp_encrypt_and_sign(const rnp_cfg &cfg, + cli_rnp_t * rnp, + rnp_input_t input, + rnp_output_t output) +{ + rnp_op_encrypt_t op = NULL; + + if (rnp_op_encrypt_create(&op, rnp->ffi, input, output)) { + ERR_MSG("failed to initialize encryption"); + return false; + } + + std::string fname; + std::string aalg; + std::vector enckeys; + std::vector signkeys; + bool res = false; + rnp_result_t ret; + + rnp_op_encrypt_set_armor(op, cfg.get_bool(CFG_ARMOR)); + + if (cfg.has(CFG_SETFNAME)) { + if (rnp_op_encrypt_set_file_name(op, cfg.get_str(CFG_SETFNAME).c_str())) { + goto done; + } + } else if (cfg.has(CFG_INFILE)) { + const std::string &fname = cfg.get_str(CFG_INFILE); + if (rnp_op_encrypt_set_file_name(op, extract_filename(fname).c_str())) { + goto done; + } + rnp_op_encrypt_set_file_mtime(op, rnp_filemtime(fname.c_str())); + } + + if (rnp_op_encrypt_set_compression(op, cfg.get_cstr(CFG_ZALG), cfg.get_int(CFG_ZLEVEL))) { + goto done; + } + if (rnp_op_encrypt_set_cipher(op, cfg.get_cstr(CFG_CIPHER))) { + goto done; + } + if (rnp_op_encrypt_set_hash(op, cfg.get_hashalg().c_str())) { + goto done; + } + aalg = cfg.has(CFG_AEAD) ? cfg.get_str(CFG_AEAD) : "None"; + if (rnp_op_encrypt_set_aead(op, aalg.c_str())) { + goto done; + } + if (cfg.has(CFG_AEAD_CHUNK) && + rnp_op_encrypt_set_aead_bits(op, cfg.get_int(CFG_AEAD_CHUNK))) { + goto done; + } + if (cfg.has(CFG_NOWRAP) && rnp_op_encrypt_set_flags(op, RNP_ENCRYPT_NOWRAP)) { + goto done; + } + + /* adding passwords if password-based encryption is used */ + if (cfg.get_bool(CFG_ENCRYPT_SK)) { + std::string halg = cfg.get_hashalg(); + std::string ealg = cfg.get_str(CFG_CIPHER); + size_t iterations = cfg.get_int(CFG_S2K_ITER); + size_t msec = cfg.get_int(CFG_S2K_MSEC); + + if (msec != DEFAULT_S2K_MSEC) { + if (rnp_calculate_iterations(halg.c_str(), msec, &iterations)) { + ERR_MSG("Failed to calculate S2K iterations"); + goto done; + } + } + + for (int i = 0; i < cfg.get_int(CFG_PASSWORDC, 1); i++) { + if (rnp_op_encrypt_add_password( + op, NULL, halg.c_str(), iterations, ealg.c_str())) { + ERR_MSG("Failed to add encrypting password"); + goto done; + } + } + } + + /* adding encrypting keys if pk-encryption is used */ + if (cfg.get_bool(CFG_ENCRYPT_PK)) { + std::vector keynames = cfg.get_list(CFG_RECIPIENTS); + if (!cli_rnp_keys_matching_strings(rnp, + enckeys, + keynames, + CLI_SEARCH_DEFAULT | CLI_SEARCH_SUBKEYS | + CLI_SEARCH_FIRST_ONLY)) { + ERR_MSG("Failed to build recipients key list"); + goto done; + } + for (rnp_key_handle_t key : enckeys) { + if (rnp_op_encrypt_add_recipient(op, key)) { + ERR_MSG("Failed to add recipient"); + goto done; + } + } + } + + /* adding signatures if encrypt-and-sign is used */ + if (cfg.get_bool(CFG_SIGN_NEEDED)) { + rnp_op_encrypt_set_creation_time(op, cfg.get_sig_creation()); + uint32_t expiration; + if (cfg.get_expiration(CFG_EXPIRATION, expiration)) { + rnp_op_encrypt_set_expiration_time(op, expiration); + } + + /* signing keys */ + std::vector keynames = cfg.get_list(CFG_SIGNERS); + if (!cli_rnp_keys_matching_strings(rnp, + signkeys, + keynames, + CLI_SEARCH_SECRET | CLI_SEARCH_DEFAULT | + CLI_SEARCH_SUBKEYS | CLI_SEARCH_FIRST_ONLY)) { + ERR_MSG("Failed to build signing keys list"); + goto done; + } + for (rnp_key_handle_t key : signkeys) { + if (rnp_op_encrypt_add_signature(op, key, NULL)) { + ERR_MSG("Failed to add signature"); + goto done; + } + } + } + + /* execute encrypt or encrypt-and-sign operation */ + ret = rnp_op_encrypt_execute(op); + res = (ret == RNP_SUCCESS); + if (ret != RNP_SUCCESS) { + ERR_MSG("Operation failed: %s", rnp_result_to_string(ret)); + } +done: + clear_key_handles(signkeys); + clear_key_handles(enckeys); + rnp_op_encrypt_destroy(op); + return res; +} + +bool +cli_rnp_setup(cli_rnp_t *rnp) +{ + /* unset CFG_PASSWD and empty CFG_PASSWD are different cases */ + if (rnp->cfg().has(CFG_PASSWD)) { + const std::string &passwd = rnp->cfg().get_str(CFG_PASSWD); + if (rnp_ffi_set_pass_provider( + rnp->ffi, ffi_pass_callback_string, (void *) passwd.c_str())) { + return false; + } + } + rnp->pswdtries = rnp->cfg().get_pswdtries(); + return true; +} + +bool +cli_rnp_check_weak_hash(cli_rnp_t *rnp) +{ + if (rnp->cfg().has(CFG_WEAK_HASH)) { + return true; + } + + uint32_t security_level = 0; + + if (rnp_get_security_rule(rnp->ffi, + RNP_FEATURE_HASH_ALG, + rnp->cfg().get_hashalg().c_str(), + rnp->cfg().time(), + NULL, + NULL, + &security_level)) { + ERR_MSG("Failed to get security rules for hash algorithm \'%s\'!", + rnp->cfg().get_hashalg().c_str()); + return false; + } + + if (security_level < RNP_SECURITY_DEFAULT) { + ERR_MSG("Hash algorithm \'%s\' is cryptographically weak!", + rnp->cfg().get_hashalg().c_str()); + return false; + } + /* TODO: check other weak algorithms and key sizes */ + return true; +} + +bool +cli_rnp_protect_file(cli_rnp_t *rnp) +{ + rnp_input_t input = NULL; + rnp_output_t output = NULL; + + if (!rnp->init_io(Operation::EncryptOrSign, &input, &output)) { + ERR_MSG("failed to open source or create output"); + return false; + } + + bool res = false; + bool sign = rnp->cfg().get_bool(CFG_SIGN_NEEDED); + bool encrypt = rnp->cfg().get_bool(CFG_ENCRYPT_PK) || rnp->cfg().get_bool(CFG_ENCRYPT_SK); + if (sign && !encrypt) { + res = cli_rnp_sign(rnp->cfg(), rnp, input, output); + } else if (encrypt) { + res = cli_rnp_encrypt_and_sign(rnp->cfg(), rnp, input, output); + } else { + ERR_MSG("No operation specified"); + } + + rnp_input_destroy(input); + rnp_output_destroy(output); + return res; +} + +/* helper function which prints something like 'using RSA (Sign-Only) key 0x0102030405060708 */ +static void +cli_rnp_print_sig_key_info(FILE *resfp, rnp_signature_handle_t sig) +{ + char *keyid = NULL; + char *alg = NULL; + + (void) rnp_signature_get_keyid(sig, &keyid); + rnp::lowercase(keyid); + (void) rnp_signature_get_alg(sig, &alg); + + fprintf(resfp, + "using %s key %s\n", + cli_rnp_normalize_key_alg(alg), + keyid ? keyid : "0000000000000000"); + rnp_buffer_destroy(keyid); + rnp_buffer_destroy(alg); +} + +static void +cli_rnp_print_signatures(cli_rnp_t *rnp, const std::vector &sigs) +{ + unsigned invalidc = 0; + unsigned unknownc = 0; + unsigned validc = 0; + std::string title = "UNKNOWN signature"; + FILE * resfp = rnp->resfp; + + for (auto sig : sigs) { + rnp_result_t status = rnp_op_verify_signature_get_status(sig); + switch (status) { + case RNP_SUCCESS: + title = "Good signature"; + validc++; + break; + case RNP_ERROR_SIGNATURE_EXPIRED: + title = "EXPIRED signature"; + invalidc++; + break; + case RNP_ERROR_SIGNATURE_INVALID: + title = "BAD signature"; + invalidc++; + break; + case RNP_ERROR_KEY_NOT_FOUND: + title = "NO PUBLIC KEY for signature"; + unknownc++; + break; + case RNP_ERROR_SIGNATURE_UNKNOWN: + title = "UNKNOWN signature"; + unknownc++; + break; + default: + title = "UNKNOWN signature status"; + break; + } + + if (status == RNP_ERROR_SIGNATURE_UNKNOWN) { + fprintf(resfp, "%s\n", title.c_str()); + continue; + } + + uint32_t create = 0; + uint32_t expiry = 0; + rnp_op_verify_signature_get_times(sig, &create, &expiry); + + time_t crtime = create; + auto str = rnp_ctime(crtime); + fprintf(resfp, + "%s made %s%s", + title.c_str(), + rnp_y2k38_warning(crtime) ? ">=" : "", + str.c_str()); + if (expiry) { + crtime = rnp_timeadd(crtime, expiry); + str = rnp_ctime(crtime); + fprintf( + resfp, "Valid until %s%s\n", rnp_y2k38_warning(crtime) ? ">=" : "", str.c_str()); + } + + rnp_signature_handle_t handle = NULL; + if (rnp_op_verify_signature_get_handle(sig, &handle)) { + ERR_MSG("Failed to obtain signature handle."); + continue; + } + + cli_rnp_print_sig_key_info(resfp, handle); + rnp_key_handle_t key = NULL; + + if ((status != RNP_ERROR_KEY_NOT_FOUND) && !rnp_signature_get_signer(handle, &key)) { + cli_rnp_print_key_info(resfp, rnp->ffi, key, false, false); + rnp_key_handle_destroy(key); + } + rnp_signature_handle_destroy(handle); + } + + if (!sigs.size()) { + ERR_MSG("No signature(s) found - is this a signed file?"); + return; + } + if (!invalidc && !unknownc) { + ERR_MSG("Signature(s) verified successfully"); + return; + } + /* Show a proper error message if there are invalid/unknown signatures */ + auto si = invalidc > 1 ? "s" : ""; + auto su = unknownc > 1 ? "s" : ""; + auto fail = "Signature verification failure: "; + if (invalidc && !unknownc) { + ERR_MSG("%s%u invalid signature%s", fail, invalidc, si); + } else if (!invalidc && unknownc) { + ERR_MSG("%s%u unknown signature%s", fail, unknownc, su); + } else { + ERR_MSG("%s%u invalid signature%s, %u unknown signature%s", + fail, + invalidc, + si, + unknownc, + su); + } +} + +static void +cli_rnp_inform_of_hidden_recipient(rnp_op_verify_t op) +{ + size_t recipients = 0; + rnp_op_verify_get_recipient_count(op, &recipients); + if (!recipients) { + return; + } + for (size_t idx = 0; idx < recipients; idx++) { + rnp_recipient_handle_t recipient = NULL; + rnp_op_verify_get_recipient_at(op, idx, &recipient); + char *keyid = NULL; + rnp_recipient_get_keyid(recipient, &keyid); + bool hidden = keyid && !strcmp(keyid, "0000000000000000"); + rnp_buffer_destroy(keyid); + if (hidden) { + ERR_MSG("Warning: message has hidden recipient, but it was ignored. Use " + "--allow-hidden to override this."); + break; + } + } +} + +bool +cli_rnp_process_file(cli_rnp_t *rnp) +{ + rnp_input_t input = NULL; + if (!rnp->init_io(Operation::Verify, &input, NULL)) { + ERR_MSG("failed to open source"); + return false; + } + + char *contents = NULL; + if (rnp_guess_contents(input, &contents)) { + ERR_MSG("failed to check source contents"); + rnp_input_destroy(input); + return false; + } + + /* source data for detached signature verification */ + rnp_input_t source = NULL; + rnp_output_t output = NULL; + rnp_op_verify_t verify = NULL; + rnp_result_t ret = RNP_ERROR_GENERIC; + bool res = false; + std::vector sigs; + size_t scount = 0; + + if (rnp::str_case_eq(contents, "signature")) { + /* detached signature */ + std::string in = rnp->cfg().get_str(CFG_INFILE); + std::string src = rnp->cfg().get_str(CFG_SOURCE); + if (is_stdinout_spec(in) && is_stdinout_spec(src)) { + ERR_MSG("Detached signature and signed source cannot be both stdin."); + goto done; + } + if (src.empty() && !has_extension(in, EXT_SIG) && !has_extension(in, EXT_ASC)) { + ERR_MSG("Unsupported detached signature extension. Use --source to override."); + goto done; + } + if (src.empty()) { + src = in; + /* cannot fail as we checked for extension previously */ + strip_extension(src); + } + source = cli_rnp_input_from_specifier(*rnp, src, NULL); + if (!source) { + ERR_MSG("Failed to open source for detached signature verification."); + goto done; + } + + ret = rnp_op_verify_detached_create(&verify, rnp->ffi, source, input); + if (!ret) { + /* Currently CLI requires all signatures to be valid for success */ + ret = rnp_op_verify_set_flags(verify, RNP_VERIFY_REQUIRE_ALL_SIGS); + } + } else { + if (!rnp->init_io(Operation::Verify, NULL, &output)) { + ERR_MSG("Failed to create output stream."); + goto done; + } + ret = rnp_op_verify_create(&verify, rnp->ffi, input, output); + if (!ret) { + uint32_t flags = 0; + if (!rnp->cfg().get_bool(CFG_NO_OUTPUT)) { + /* This would happen if user requested decryption instead of verification */ + flags = flags | RNP_VERIFY_IGNORE_SIGS_ON_DECRYPT; + } else { + /* Currently CLI requires all signatures to be valid for success */ + flags = flags | RNP_VERIFY_REQUIRE_ALL_SIGS; + } + if (rnp->cfg().get_bool(CFG_ALLOW_HIDDEN)) { + /* Allow hidden recipient */ + flags = flags | RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT; + } + ret = rnp_op_verify_set_flags(verify, flags); + } + } + if (ret) { + ERR_MSG("Failed to initialize verification/decryption operation."); + goto done; + } + + res = !rnp_op_verify_execute(verify); + + /* Check whether we had hidden recipient on verification/decryption failure */ + if (!res && !rnp->cfg().get_bool(CFG_ALLOW_HIDDEN)) { + cli_rnp_inform_of_hidden_recipient(verify); + } + + rnp_op_verify_get_signature_count(verify, &scount); + if (!scount) { + goto done; + } + + for (size_t i = 0; i < scount; i++) { + rnp_op_verify_signature_t sig = NULL; + if (rnp_op_verify_get_signature_at(verify, i, &sig)) { + ERR_MSG("Failed to obtain signature info."); + res = false; + goto done; + } + try { + sigs.push_back(sig); + } catch (const std::exception &e) { + ERR_MSG("%s", e.what()); + res = false; + goto done; + } + } + cli_rnp_print_signatures(rnp, sigs); +done: + rnp_buffer_destroy(contents); + rnp_input_destroy(input); + rnp_input_destroy(source); + rnp_output_destroy(output); + rnp_op_verify_destroy(verify); + return res; +} + +void +cli_rnp_print_praise(void) +{ + printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT); + printf("Backend: %s\n", rnp_backend_string()); + printf("Backend version: %s\n", rnp_backend_version()); + printf("Supported algorithms:\n"); + cli_rnp_print_feature(stdout, RNP_FEATURE_PK_ALG, "Public key"); + cli_rnp_print_feature(stdout, RNP_FEATURE_SYMM_ALG, "Encryption"); + cli_rnp_print_feature(stdout, RNP_FEATURE_AEAD_ALG, "AEAD"); + cli_rnp_print_feature(stdout, RNP_FEATURE_PROT_MODE, "Key protection"); + cli_rnp_print_feature(stdout, RNP_FEATURE_HASH_ALG, "Hash"); + cli_rnp_print_feature(stdout, RNP_FEATURE_COMP_ALG, "Compression"); + cli_rnp_print_feature(stdout, RNP_FEATURE_CURVE, "Curves"); + printf("Please report security issues at (https://www.rnpgp.org/feedback) and\n" + "general bugs at https://github.com/rnpgp/rnp/issues.\n"); +} + +void +cli_rnp_print_feature(FILE *fp, const char *type, const char *printed_type) +{ + char * result = NULL; + size_t count; + if (rnp_supported_features(type, &result) != RNP_SUCCESS) { + ERR_MSG("Failed to list supported features: %s", type); + return; + } + json_object *jso = json_tokener_parse(result); + if (!jso) { + ERR_MSG("Failed to parse JSON with features: %s", type); + goto done; + } + fprintf(fp, "%s: ", printed_type); + count = json_object_array_length(jso); + for (size_t idx = 0; idx < count; idx++) { + json_object *val = json_object_array_get_idx(jso, idx); + fprintf(fp, " %s%s", json_object_get_string(val), idx < count - 1 ? "," : ""); + } + fputs("\n", fp); + fflush(fp); + json_object_put(jso); +done: + rnp_buffer_destroy(result); +} diff --git a/comm/third_party/rnp/src/rnp/fficli.h b/comm/third_party/rnp/src/rnp/fficli.h new file mode 100644 index 0000000000..7db29dc1af --- /dev/null +++ b/comm/third_party/rnp/src/rnp/fficli.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2019-2021, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FFICLI_H_ +#define FFICLI_H_ + +#include +#include +#include +#include "rnp/rnp.h" +#include "rnp/rnp_err.h" +#include "config.h" +#include "rnpcfg.h" +#include "json.h" + +enum class Operation { EncryptOrSign, Verify, Enarmor, Dearmor, Dump }; + +class cli_rnp_t { + private: + rnp_cfg cfg_{}; +#ifdef _WIN32 + int subst_argc{}; + char **subst_argv{}; +#endif + bool load_keyring(bool secret); + bool is_cv25519_subkey(rnp_key_handle_t handle); + bool get_protection(rnp_key_handle_t handle, + std::string & hash, + std::string & cipher, + size_t & iterations); + bool check_cv25519_bits(rnp_key_handle_t key, char *prot_password, bool &tweaked); + + public: + rnp_ffi_t ffi{}; + FILE * resfp{}; /* where to put result messages, defaults to stdout */ + FILE * passfp{}; /* file pointer for password input */ + FILE * userio_in{}; /* file pointer for user's inputs */ + FILE * userio_out{}; /* file pointer for user's outputs */ + int pswdtries{}; /* number of password tries, -1 for unlimited */ + bool reuse_password_for_subkey{}; + std::string reuse_primary_fprint; + char * reused_password{}; + bool hidden_msg{}; /* true if hidden recipient message was displayed */ + + static int ret_code(bool success); + + ~cli_rnp_t(); +#ifdef _WIN32 + void substitute_args(int *argc, char ***argv); +#endif + bool init(const rnp_cfg &cfg); + void end(); + + bool init_io(Operation op, rnp_input_t *input, rnp_output_t *output); + + bool load_keyrings(bool loadsecret = false); + + const std::string & + defkey() + { + return cfg_.get_str(CFG_KR_DEF_KEY); + } + + void set_defkey(); + + const std::string & + pubpath() + { + return cfg_.get_str(CFG_KR_PUB_PATH); + } + + const std::string & + secpath() + { + return cfg_.get_str(CFG_KR_SEC_PATH); + } + + const std::string & + pubformat() + { + return cfg_.get_str(CFG_KR_PUB_FORMAT); + } + + const std::string & + secformat() + { + return cfg_.get_str(CFG_KR_SEC_FORMAT); + } + + rnp_cfg & + cfg() + { + return cfg_; + } + + bool fix_cv25519_subkey(const std::string &key, bool checkonly = false); + + bool add_new_subkey(const std::string &key); + + bool set_key_expire(const std::string &key); + + bool edit_key(const std::string &key); +}; + +typedef enum cli_search_flags_t { + CLI_SEARCH_SECRET = 1 << 0, /* search secret keys only */ + CLI_SEARCH_SUBKEYS = 1 << 1, /* add subkeys as well */ + CLI_SEARCH_FIRST_ONLY = 1 << 2, /* return only first key matching */ + CLI_SEARCH_SUBKEYS_AFTER = + (1 << 3) | CLI_SEARCH_SUBKEYS, /* put subkeys after the primary key */ + CLI_SEARCH_DEFAULT = 1 << 4 /* add default key if nothing found */ +} cli_search_flags_t; + +/** + * @brief Set keystore parameters to the rnp_cfg_t. This includes keyring paths, types and + * default key. + * + * @param cfg pointer to the allocated rnp_cfg_t structure + * @return true on success or false otherwise. + * @return false + */ +bool cli_cfg_set_keystore_info(rnp_cfg &cfg); + +/** + * @brief Create input object from the specifier, which may represent: + * - path + * - stdin (if `-` or empty string is passed) + * - environment variable contents, if path looks like `env:VARIABLE_NAME` + * @param rnp initialized CLI rnp object + * @param spec specifier + * @param is_path optional parameter. If specifier is path (not stdin, env variable), then true + * will be stored here, false otherwise. May be NULL if this information is not + * needed. + * @return rnp_input_t object or NULL if operation failed. + */ +rnp_input_t cli_rnp_input_from_specifier(cli_rnp_t & rnp, + const std::string &spec, + bool * is_path); + +/** + * @brief Create output object from the specifier, which may represent: + * - path + * - stdout (if `-` or empty string is passed) + * + * @param rnp initialized CLI rnp object + * @param spec specifier + * @param discard just discard output + * @return rnp_output_t or NULL if operation failed. + */ +rnp_output_t cli_rnp_output_to_specifier(cli_rnp_t & rnp, + const std::string &spec, + bool discard = false); + +bool cli_rnp_save_keyrings(cli_rnp_t *rnp); +void cli_rnp_print_key_info( + FILE *fp, rnp_ffi_t ffi, rnp_key_handle_t key, bool psecret, bool psigs); +bool cli_rnp_set_generate_params(rnp_cfg &cfg, bool subkey = false); +bool cli_rnp_generate_key(cli_rnp_t *rnp, const char *username); +/** + * @brief Find key(s) matching set of flags and search string. + * + * @param rnp initialized cli_rnp_t object. + * @param keys search results will be added here, leaving already existing items. + * @param str search string: may be part of the userid, keyid, fingerprint or grip. + * @param flags combination of the following flags: + * CLI_SEARCH_SECRET : require key to be secret, + * CLI_SEARCH_SUBKEYS : include subkeys to the results (see + * CLI_SEARCH_SUBKEYS_AFTER description). + * CLI_SEARCH_FIRST_ONLY : include only first key found + * CLI_SEARCH_SUBKEYS_AFTER : for each primary key add its subkeys after the main + * key. This changes behaviour of subkey search, since those will be added only + * if subkey is orphaned or primary key matches search. + * @return true if operation succeeds and at least one key is found, or false otherwise. + */ +bool cli_rnp_keys_matching_string(cli_rnp_t * rnp, + std::vector &keys, + const std::string & str, + int flags); +/** + * @brief Find key(s) matching set of flags and search string(s). + * + * @param rnp initialized cli_rnp_t object. + * @param keys search results will be put here, overwriting vector's contents. + * @param strs set of search strings, may be empty. + * @param flags the same flags as for cli_rnp_keys_matching_string(), except additional one: + * CLI_SEARCH_DEFAULT : if no key is found then default key from cli_rnp_t will be + * searched. + * @return true if operation succeeds and at least one key is found for each search string, or + * false otherwise. + */ +bool cli_rnp_keys_matching_strings(cli_rnp_t * rnp, + std::vector & keys, + const std::vector &strs, + int flags); +bool cli_rnp_export_keys(cli_rnp_t *rnp, const char *filter); +bool cli_rnp_export_revocation(cli_rnp_t *rnp, const char *key); +bool cli_rnp_revoke_key(cli_rnp_t *rnp, const char *key); +bool cli_rnp_remove_key(cli_rnp_t *rnp, const char *key); +bool cli_rnp_add_key(cli_rnp_t *rnp); +bool cli_rnp_dump_file(cli_rnp_t *rnp); +bool cli_rnp_armor_file(cli_rnp_t *rnp); +bool cli_rnp_dearmor_file(cli_rnp_t *rnp); +bool cli_rnp_check_weak_hash(cli_rnp_t *rnp); +bool cli_rnp_setup(cli_rnp_t *rnp); +bool cli_rnp_protect_file(cli_rnp_t *rnp); +bool cli_rnp_process_file(cli_rnp_t *rnp); +std::string cli_rnp_escape_string(const std::string &src); +void cli_rnp_print_praise(void); +void cli_rnp_print_feature(FILE *fp, const char *type, const char *printed_type); +/** + * @brief Convert algorithm name representation to one used by FFI. + * I.e. aes-128 to AES128, 3DES to TRIPLEDES, SHA-1 to SHA1 and so on. + * + * @param alg algorithm string + * @return string with FFI algorithm's name. In case alias is not found the source string will + * be returned. + */ +const std::string cli_rnp_alg_to_ffi(const std::string alg); + +/** + * @brief Attempt to set hash algorithm using the value provided. + * + * @param cfg config + * @param hash algorithm name. + * @return true if algorithm is supported and set correctly, or false otherwise. + */ +bool cli_rnp_set_hash(rnp_cfg &cfg, const std::string &hash); + +/** + * @brief Attempt to set symmetric cipher algorithm using the value provided. + * + * @param cfg config + * @param cipher algorithm name. + * @return true if algorithm is supported and set correctly, or false otherwise. + */ +bool cli_rnp_set_cipher(rnp_cfg &cfg, const std::string &cipher); + +void clear_key_handles(std::vector &keys); + +const char *json_obj_get_str(json_object *obj, const char *key); + +#ifdef _WIN32 +bool rnp_win_substitute_cmdline_args(int *argc, char ***argv); +void rnp_win_clear_args(int argc, char **argv); +#endif + +/* TODO: we should decide what to do with functions/constants/defines below */ +#define RNP_KEYID_SIZE 8 +#define RNP_FP_SIZE 20 +#define RNP_GRIP_SIZE 20 + +#define ERR_MSG(...) \ + do { \ + (void) fprintf((stderr), __VA_ARGS__); \ + (void) fprintf((stderr), "\n"); \ + } while (0) + +#define EXT_ASC (".asc") +#define EXT_SIG (".sig") +#define EXT_PGP (".pgp") +#define EXT_GPG (".gpg") + +#define SUBDIRECTORY_GNUPG ".gnupg" +#define SUBDIRECTORY_RNP ".rnp" +#define PUBRING_KBX "pubring.kbx" +#define SECRING_KBX "secring.kbx" +#define PUBRING_GPG "pubring.gpg" +#define SECRING_GPG "secring.gpg" +#define PUBRING_G10 "public-keys-v1.d" +#define SECRING_G10 "private-keys-v1.d" + +#endif diff --git a/comm/third_party/rnp/src/rnp/moz.build b/comm/third_party/rnp/src/rnp/moz.build new file mode 100644 index 0000000000..d9ef04d51b --- /dev/null +++ b/comm/third_party/rnp/src/rnp/moz.build @@ -0,0 +1,64 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Program("rnp-cli") + +include("../../../rnpdefs.mozbuild") + +USE_LIBS += ["rnp"] + +LOCAL_INCLUDES = [ + "!../lib", + "..", + "../../include", + "../common", + "../lib", +] + +if CONFIG["MZLA_SYSTEM_JSONC"]: + CXXFLAGS += CONFIG["MZLA_JSONC_CFLAGS"] + LDFLAGS += CONFIG["MZLA_JSONC_LIBS"] + ["-Wl,-rpath,$ORIGIN"] + +else: + USE_LIBS += ["json-c"] + LOCAL_INCLUDES += ["!/comm/third_party/json-c", "/comm/third_party/json-c"] + LDFLAGS += ["-Wl,-rpath,$ORIGIN"] + +SOURCES += [ + "../common/file-utils.cpp", + "../common/str-utils.cpp", + "../common/time-utils.cpp", + "../lib/logging.cpp", + "../rnpkeys/tui.cpp", + "fficli.cpp", + "rnp.cpp", + "rnpcfg.cpp", +] + +if CONFIG["CC_TYPE"] == "clang-cl": + CXXFLAGS += [ + "/EHs", + "-Wno-deprecated-declarations", + ] + LOCAL_INCLUDES += [ + "/comm/third_party/niwcompat", + ] + + OS_LIBS += ["shell32"] + + if CONFIG["CPU_ARCH"] == "x86": + LDFLAGS += ["clang_rt.builtins-i386.lib"] + elif CONFIG["CPU_ARCH"] == "x86_64": + LDFLAGS += ["clang_rt.builtins-x86_64.lib"] + + SOURCES += [ + "/comm/third_party/niwcompat/getopt.c", + ] + SOURCES["rnpcfg.cpp"].flags += [ + "-FI", + "%s/comm/third_party/niwcompat/extra_include.h" % TOPSRCDIR, + ] + DEFINES["MOZILLA_CONFIG_H"] = True + DEFINES["_CRT_SECURE_NO_WARNINGS"] = True diff --git a/comm/third_party/rnp/src/rnp/rnp.1.adoc b/comm/third_party/rnp/src/rnp/rnp.1.adoc new file mode 100644 index 0000000000..ce1173e49a --- /dev/null +++ b/comm/third_party/rnp/src/rnp/rnp.1.adoc @@ -0,0 +1,431 @@ += rnp(1) +RNP +:doctype: manpage +:release-version: {component-version} +:man manual: RNP Manual +:man source: RNP {release-version} + +== NAME + +RNP - OpenPGP-compatible signatures and encryption. + +== SYNOPSIS + +*rnp* [_--homedir_ _dir_] [_OPTIONS_] _COMMAND_ [_INPUT_FILE_, ...] ... + + +== DESCRIPTION + +The _rnp_ command-line utility is part of the _RNP_ suite and +provides OpenPGP signing and encryption functionality +compliant with IETF RFC 4880. + +_rnp_ does not allow manipulation of keys or keyrings -- +please use _rnpkeys(1)_ for that purpose. + +=== BASICS + +By default, *rnp* will apply a _COMMAND_, additionally configured with _OPTIONS_, +to all _INPUT_FILE_(s) or _stdin_ if no _INPUT_FILE_ is given. +There are some special cases for _INPUT_FILE_ : + +* _-_ (dash) substitutes to _stdin_ +* env:VARIABLE_NAME substitutes to the contents of environment variable VARIABLE_NAME + +Depending on the input, output may be written: + +* if *--output* option is given output is written to the path specified (or to the *stdout* if *-* is used) +* to the _INPUT_FILE_ with a removed or added file extension (_.pgp_, _.gpg_, _.asc_, _.sig_), depending on operation. +* to the _stdout_ if input was read from the _stdin_. + +If output file already exists, it will *not* be overwritten, unless *--overwrite* option is given. + +Without the *--armor* option, output will be in binary. + +If _COMMAND_ requires public or private keys, *rnp* will look for the keyrings in *~/.rnp*. The options *--homedir* and *--keyfile* override this (see below). + +If _COMMAND_ needs a password, *rnp* will ask for it via *stdin* or *tty*, +unless the *--password* or *--pass-fd* option was specified. + + +== COMMANDS + +=== INFORMATIONAL + +*-h*, *--help*:: +Displays a short help message. No options are expected. + +*-V*, *--version*:: +Displays version information. No options are expected. + + +=== ENCRYPTION AND SIGNING + +*-e*, *--encrypt*:: +Encrypt data with public key(s), and optionally sign, if the *--sign* command is added. + ++ +You would likely want to specify one or more *--recipient*(s) or pick a *--cipher* (instead of the default). ++ +Additional options: + +*--recipient*::: +Specify one or more recipients. + +*--cipher*::: +Select a specific cipher. + +*-z 0..9*, *--zlib*, *--zip*, *--bzip*::: +Select a compression algorithm and level. + +*--armor*::: +Output ASCII data instead of binary via the *--armor* option. If the input file is _file.ext_, and *--output* is not specified, then the data will be written (depending on *--armor* option) to _file.ext.pgp_ or _file.ext.asc_. + + +*--no-wrap*::: +Do not wrap the output in literal data packet. This could be used to encrypt a file which is already signed or encrypted. +By default this would also disable compression, use option *-z* to override. + +*--overwrite*::: +If the destination file already exists, and the *--overwrite* option is not given, the caller will be asked for the permission to overwrite or to provide a new file name. Please see the *OPTIONS* section for more information. + +*-c*, *--symmetric*:: +Encrypt data with password(s). + ++ +Can be combined with the commands *--encrypt* and *--sign*. ++ +Options that apply to the *--encrypt* command also apply here. ++ +Additional options: + +*--passwords*::: +Encryption to multiple passwords is possible with *--passwords* option. Each password would be asked via stdin/tty unless *--password* or *--pass-fd* is specified. + + +*-s*, *--sign*:: +Digitally sign data, using one or more secret keys you own. + ++ +Public-key or password-based encryption may be added via the *--encrypt* and *--symmetric* commands. + ++ +Additional options: + +*-u*, *--userid*::: +By default, the first secret key you own will be selected for signing. Apply this option to select a different key or to use multiple keys. + +*--detach*::: +By default, the signature is stored together with signed data. This option detaches the data signature to a separate file (_file.ext.sig_). + +*--hash*::: +You may want to use *--hash* option to override default hash algorithm settings. As with encryption, output may be converted to ascii via the *--armor* option. + ++ +Compression options also apply here. Since the secret key is usually stored encrypted, you will be asked for the password to decrypt it via _stdin_/_tty_ unless *--password* or *--pass-fd* is specified. + +*--clearsign*:: +Digitally sign text data, producing human-readable output with the signature attached. + ++ +In this mode, data cannot be additionally encrypted or compressed. ++ +Other signing options, *--hash*, *-u*, *--password*, can still be used here. + +=== DECRYPTION AND VERIFICATION + +*-d*, *--decrypt*:: +Decrypt and verify data from the _INPUT_FILE_ or stdin. + ++ +If the data is signed, signature verification information will be printed to _stdout_/_tty_. ++ +Additional options: + +*--output*::: +Override the default output selection with a file name or stdout specifier (*_-_*). For the default output path selection see the *BASICS* section. + +*--password*, *--pass-fd*::: +Depending on encryption options, you may be asked for the password of one of your secret keys, or for the encryption password. These options override that behavior such that you can input the password through automated means. + +*-v*, *--verify*:: +Verify signature(s) without writing embedded data out, if any (unless option _--output_ is specified). + ++ +To verify the detached signature of a file _file.ext_, the detached signature file in the file name pattern of _file.ext.sig_ or _file.ext.asc_ must exist. + ++ +Also you may use option *--source* to specify the exact source for the signed data. + ++ +If data is encrypted, you may be asked for password as in the *--decrypt* command. + +=== OTHER COMMANDS + +*--list-packets*:: +Show detailed information about the OpenPGP data in _INPUT_FILE_ or stdin. +Useful for curiosity, troubleshooting or debugging. + ++ +Additional options can be used: + +*--json*::: output JSON data instead of human-readable information +*--grips*::: print out key fingerprints and grips +*--mpi*::: print out all MPI values +*--raw*::: print raw, hex-encoded packets too + +*--enarmor*[=_msg_|_pubkey_|_seckey_|_sign_]:: +Convert binary data to the ASCII-armored as per OpenPGP standard. +This includes the `-----BEGIN PGP MESSAGE-----` header and footer, +and Base64-encoded data. + ++ +Output for _file.ext_ will be written to _file.ext.asc_ (if it does not exist) +or to _stdout_. + ++ +The following OpenPGP headers may be specified: ++ +-- +*msg* (default) ::: _-----BEGIN PGP MESSAGE-----_ +*pubkey*::: _-----BEGIN PGP PUBLIC KEY BLOCK-----_ +*seckey*::: _-----BEGIN PGP SECRET KEY BLOCK-----_ +*sign*::: _-----BEGIN PGP SIGNATURE-----_ +-- ++ +Additional options: + +*--overwrite*::: +Forcefully overwrite existing destination file if it exists. + +*--output*::: +Specify destination file path. + + +*--dearmor*:: +Attempts to convert data from an armored format to the binary format. + ++ +The _file.ext.asc_ output file would be written to _file.ext_. +If the destination file already exists, it will prompt the user +for a new filename. ++ +Additional options: + +*--overwrite*::: +Forcefully overwrite existing destination file if it exists. + +*--output*::: +Specify destination file path. + + +== OPTIONS + +*--home*, *--homedir* _DIR_:: +Change homedir (where RNP looks for keyrings) to the specified value. + ++ +The default homedir is _~/.rnp_ . + +*-f*, *--keyfile* _PATH_:: +Instead of loading keyrings, use key(s) from the file specified. + +*-u*, *--userid* _KEY_:: +Specify one or more signing keys, searching for it via the given value _KEY_. +See *rnpkeys(1)* on how to find valid values. + +*-r*, *--recipient* _KEY_:: +Add the message recipient, i.e. the public key to which message will be encrypted to. +See *rnpkeys(1)* on how to find valid values. + +*--armor*, *--ascii*:: +Apply ASCII armoring to the output, so that the resulting output +can be transferred as plain text. + ++ +See IETF RFC 4880 for more details. + +*--detach*, *--detached*:: +Create a detached signature. + +*--output* _PATH_:: +Write data processing related output to the file specified. + ++ +If not specified, the output filename will be guessed from +the input filename/extension or the command will prompt the user +via _stdin_/_tty_. + +*--overwrite*:: +Overwrite already existing files without prompt. + +*--source*:: +Specify signed data for the detached signature verification (_-_ and _env:_ substitutions may be used here). + + +*--hash* _ALGORITHM_:: +Set hash algorithm which to be used for signing and derivation +of the encryption key from a password. + ++ +The default value is _SHA256_. + +*--cipher* _ALGORITHM_:: +Set the symmetric algorithm used during encryption. + ++ +The default value is _AES256_. + +*--aead* [_EAX_, _OCB_]:: +Enable AEAD encryption and select algorithm to be used. + +*--aead-chunk-bits* _BITS_:: +Change AEAD chunk size bits, from 0 to 16 (actual chunk size would be 1 << (6 + bits)). See OpenPGP documentation for the details. + + +*--zip*, *--zlib*, *--bzip2*:: +Select corresponding algorithm to compress data with. +Please refer to IETF RFC 4880 for details. + +*-z* _0..9_:: +Set compression level for the compression algorithms. + ++ +*9* is the highest compression level, where *0* disables compression. ++ +The default value is *6*. + +*--pass-fd* _FD_:: +Specify a file descriptor to read passwords from instead of from _stdin_/_tty_. + ++ +Useful for automated or non-interactive sessions. + +*--password* _PASSWORD_:: +Use the specified password when it is needed. + ++ +WARNING: Not recommended for production use due to potential security issues. +Use *--pass-fd* for batch operations instead. + +*--passwords* _COUNT_:: +Set the number of passwords for *--symmetric* encryption. + ++ +While not commonly used, you may encrypt a message to any reasonable number of passwords. + +*--creation* _TIME_:: +Override signature creation time. + ++ +By default, creation time is set to the current local computer time. + ++ +*TIME* could be specified in the ISO 8601-1:2019 date format (_yyyy-mm-dd_), or in the UNIX timestamp format. + +*--expiration* _TIME_:: +Set signature expiration time, counting from the creation time. + ++ +By default, signatures do not expire. + ++ +A specific expiration time can be specified as: + +*** expiration date in the ISO 8601:2019 date format (_yyyy-mm-dd_); or +*** hours/days/months/years since creation time with the syntax of _20h_/_30d_/_1m_/_1y_; +*** number of seconds. + +*--keystore-format* _GPG_|_KBX_|_G10_|_G21_:: +Set keystore format. + ++ +RNP automatically detects the keystore format. + ++ +This option allows the auto-detection behavior to be overridden. + +*--notty*:: +Disable use of tty. + ++ +By default RNP would detect whether TTY is attached and use it for user prompts. + ++ +This option overrides default behaviour so user input may be passed in batch mode. + +*--current-time* _TIME_:: +Override system's time with a specified value. + ++ +By default RNP uses system's time in all signature/key checks, however in some scenarios it could be needed to override this. + ++ +*TIME* may be specified in the same way as *--creation*. + +*--set-filename* _FNAME_:: +Override or set a file name, stored inside of OpenPGP message. + ++ +By default RNP will store input filename (or empty string for *stdin*/*env* input) in the resulting OpenPGP message during encryption or embedded signing. +This option allows to override this. Special value *_CONSOLE* may be used for "for your eyes only"-message. Refer OpenPGP documentation for the details. + +*--allow-hidden* :: +Allow hidden recipient support. + ++ +Sender of an encrypted message may wish to hide recipient's key by setting a Key ID field to all zeroes. +In this case receiver has to try every available secret key, checking for a valid decrypted session key. This option is disabled by default. + +== EXIT STATUS + +_0_:: + Success. + +_Non-zero_:: + Failure. + + +== EXAMPLES + +The following examples demonstrate method of usage of the _rnp_ command. + +=== EXAMPLE 1 + +*rnp* *--homedir* _.rnp_ *--encrypt* *-r* _0x6E69636B6F6C6179_ +*--output* _document.txt.encrypted_ _document.txt_ + +Load keyrings from the _.rnp_ folder, +encrypt the _document.txt_ file using the +key with keyid _0x6E69636B6F6C6179_. + +=== EXAMPLE 2 + +*rnp* *--keyfile* _john-sec.asc_ *-s* *--detach* *--hash* _SHA512_ _document.txt_ + +Generate a detached signature over the file _document.txt_, using the +secret key stored in the file. +Additionally override the hash algorithm to _SHA512_. + +=== EXAMPLE 3 + +*rnp* *--keyfile* _john-pub.asc_ *--verify* _document.txt.sig_ + +Verify detached signature, using the key stored in the _john-pub.asc_ file. +The signed data is assumed to be available from the file _document.txt_. + +=== EXAMPLE 4 + +*rnp* *-e* *-c* *-s* *--passwords* _3_ +*-r* _0x526F6E616C642054_ +*-r* "_john@doe.com_" +*-u* _0x44616E69656C2057_ +_document.txt_ + +Encrypt _document.txt_ with 2 keys (specified via _keyid_ +_0x526F6E616C642054_ and _userid_ _john@doe.com_), and 3 passwords, +so *any* of these may be used to decrypt the resulting file. + +Additionally, the message will be signed with key _0x44616E69656C2057_. + +=== EXAMPLE 5 + +*printf* _"Message"_ | *rnp* *--keyfile* _env:PGP_ENCRYPTION_KEY_ *-e* *-* *--armor* + +Encrypt message, passed via stdin, using the key, stored in environment variable *PGP_ENCRYPTION_KEY*, add ascii armoring, and print result to the stdout. + +== BUGS + +Please report _issues_ via the RNP public issue tracker at: +https://github.com/rnpgp/rnp/issues. + +_Security reports_ or _security-sensitive feedback_ should be reported +according to the instructions at: +https://www.rnpgp.org/feedback. + + +== AUTHORS + +*RNP* is an open source project led by Ribose and has +received contributions from numerous individuals and +organizations. + + +== RESOURCES + +*Web site*: https://www.rnpgp.org + +*Source repository*: https://github.com/rnpgp/rnp + + +== COPYING + +Copyright \(C) 2017-2021 Ribose. +The RNP software suite is _freely licensed_: +please refer to the *LICENSE* file for details. + + +== SEE ALSO + +*rnpkeys(1)*, *librnp(3)* diff --git a/comm/third_party/rnp/src/rnp/rnp.cpp b/comm/third_party/rnp/src/rnp/rnp.cpp new file mode 100644 index 0000000000..30d3ac4a63 --- /dev/null +++ b/comm/third_party/rnp/src/rnp/rnp.cpp @@ -0,0 +1,695 @@ +/* + * Copyright (c) 2017-2021 [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* Command line program to perform rnp operations */ +#include +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include "uniwin.h" +#else +#include +#include +#include +#endif +#include +#include +#include +#include +#include + +#include "fficli.h" +#include "str-utils.h" +#include "logging.h" + +static const char *usage = + "Sign, verify, encrypt, decrypt, inspect OpenPGP data.\n" + "Usage: rnp --command [options] [files]\n" + "Commands:\n" + " -h, --help This help message.\n" + " -V, --version Print RNP version information.\n" + " -e, --encrypt Encrypt data using the public key(s).\n" + " -r, --recipient Specify recipient's key via uid/keyid/fingerprint.\n" + " --cipher name Specify symmetric cipher, used for encryption.\n" + " --aead[=EAX, OCB] Use AEAD for encryption.\n" + " -z 0..9 Set the compression level.\n" + " --[zip,zlib,bzip] Use the corresponding compression algorithm.\n" + " --armor Apply ASCII armor to the encryption/signing output.\n" + " --no-wrap Do not wrap the output in a literal data packet.\n" + " -c, --symmetric Encrypt data using the password(s).\n" + " --passwords num Encrypt to the specified number of passwords.\n" + " -s, --sign Sign data. May be combined with encryption.\n" + " --detach Produce detached signature.\n" + " -u, --userid Specify signing key(s) via uid/keyid/fingerprint.\n" + " --hash Specify hash algorithm, used during signing.\n" + " --allow-weak-hash Allow usage of a weak hash algorithm.\n" + " --clearsign Cleartext-sign data.\n" + " -d, --decrypt Decrypt and output data, verifying signatures.\n" + " -v, --verify Verify signatures, without outputting data.\n" + " --source Specify source for the detached signature.\n" + " --dearmor Strip ASCII armor from the data, outputting binary.\n" + " --enarmor Add ASCII armor to the data.\n" + " --list-packets List OpenPGP packets from the input.\n" + " --json Use JSON output instead of human-readable.\n" + " --grips Dump key fingerprints and grips.\n" + " --mpi Dump MPI values from packets.\n" + " --raw Dump raw packet contents as well.\n" + "\n" + "Other options:\n" + " --homedir path Override home directory (default is ~/.rnp/).\n" + " -f, --keyfile Load key(s) only from the file specified.\n" + " --output [file, -] Write data to the specified file or stdout.\n" + " --overwrite Overwrite output file without a prompt.\n" + " --password Password used during operation.\n" + " --pass-fd num Read password(s) from the file descriptor.\n" + " --s2k-iterations Set the number of iterations for the S2K process.\n" + " --s2k-msec Calculate S2K iterations value based on a provided time in " + "milliseconds.\n" + " --notty Do not output anything to the TTY.\n" + " --current-time Override system's time.\n" + " --set-filename Override file name, stored inside of OpenPGP message.\n" + "\n" + "See man page for a detailed listing and explanation.\n" + "\n"; + +enum optdefs { + /* Commands as they are get via CLI */ + CMD_ENCRYPT = 260, + CMD_DECRYPT, + CMD_SIGN, + CMD_CLEARSIGN, + CMD_VERIFY, + CMD_VERIFY_CAT, + CMD_SYM_ENCRYPT, + CMD_DEARMOR, + CMD_ENARMOR, + CMD_LIST_PACKETS, + CMD_VERSION, + CMD_HELP, + + /* OpenPGP data processing commands. Sign/Encrypt/Decrypt mapped to these */ + CMD_PROTECT, + CMD_PROCESS, + + /* Options */ + OPT_KEY_STORE_FORMAT, + OPT_USERID, + OPT_RECIPIENT, + OPT_ARMOR, + OPT_HOMEDIR, + OPT_DETACHED, + OPT_HASH_ALG, + OPT_ALLOW_WEAK_HASH, + OPT_OUTPUT, + OPT_RESULTS, + OPT_COREDUMPS, + OPT_PASSWDFD, + OPT_PASSWD, + OPT_PASSWORDS, + OPT_EXPIRATION, + OPT_CREATION, + OPT_CIPHER, + OPT_NUMTRIES, + OPT_ZALG_ZIP, + OPT_ZALG_ZLIB, + OPT_ZALG_BZIP, + OPT_ZLEVEL, + OPT_OVERWRITE, + OPT_AEAD, + OPT_AEAD_CHUNK, + OPT_KEYFILE, + OPT_JSON, + OPT_GRIPS, + OPT_MPIS, + OPT_RAW, + OPT_NOTTY, + OPT_SOURCE, + OPT_NOWRAP, + OPT_CURTIME, + OPT_SETFNAME, + OPT_ALLOW_HIDDEN, + OPT_S2K_ITER, + OPT_S2K_MSEC, + + /* debug */ + OPT_DEBUG +}; + +#define EXIT_ERROR 2 + +static struct option options[] = { + /* file manipulation commands */ + {"encrypt", no_argument, NULL, CMD_ENCRYPT}, + {"decrypt", no_argument, NULL, CMD_DECRYPT}, + {"sign", no_argument, NULL, CMD_SIGN}, + {"clearsign", no_argument, NULL, CMD_CLEARSIGN}, + {"verify", no_argument, NULL, CMD_VERIFY}, + {"verify-cat", no_argument, NULL, CMD_VERIFY_CAT}, + {"symmetric", no_argument, NULL, CMD_SYM_ENCRYPT}, + {"dearmor", no_argument, NULL, CMD_DEARMOR}, + {"enarmor", optional_argument, NULL, CMD_ENARMOR}, + /* file listing commands */ + {"list-packets", no_argument, NULL, CMD_LIST_PACKETS}, + /* debugging commands */ + {"help", no_argument, NULL, CMD_HELP}, + {"version", no_argument, NULL, CMD_VERSION}, + {"debug", required_argument, NULL, OPT_DEBUG}, + /* options */ + {"coredumps", no_argument, NULL, OPT_COREDUMPS}, + {"keystore-format", required_argument, NULL, OPT_KEY_STORE_FORMAT}, + {"userid", required_argument, NULL, OPT_USERID}, + {"recipient", required_argument, NULL, OPT_RECIPIENT}, + {"home", required_argument, NULL, OPT_HOMEDIR}, + {"homedir", required_argument, NULL, OPT_HOMEDIR}, + {"keyfile", required_argument, NULL, OPT_KEYFILE}, + {"ascii", no_argument, NULL, OPT_ARMOR}, + {"armor", no_argument, NULL, OPT_ARMOR}, + {"armour", no_argument, NULL, OPT_ARMOR}, + {"detach", no_argument, NULL, OPT_DETACHED}, + {"detached", no_argument, NULL, OPT_DETACHED}, + {"hash", required_argument, NULL, OPT_HASH_ALG}, + {"pass-fd", required_argument, NULL, OPT_PASSWDFD}, + {"password", required_argument, NULL, OPT_PASSWD}, + {"passwords", required_argument, NULL, OPT_PASSWORDS}, + {"output", required_argument, NULL, OPT_OUTPUT}, + {"results", required_argument, NULL, OPT_RESULTS}, + {"creation", required_argument, NULL, OPT_CREATION}, + {"expiration", required_argument, NULL, OPT_EXPIRATION}, + {"expiry", required_argument, NULL, OPT_EXPIRATION}, + {"cipher", required_argument, NULL, OPT_CIPHER}, + {"numtries", required_argument, NULL, OPT_NUMTRIES}, + {"zip", no_argument, NULL, OPT_ZALG_ZIP}, + {"zlib", no_argument, NULL, OPT_ZALG_ZLIB}, + {"bzip", no_argument, NULL, OPT_ZALG_BZIP}, + {"bzip2", no_argument, NULL, OPT_ZALG_BZIP}, + {"overwrite", no_argument, NULL, OPT_OVERWRITE}, + {"aead", optional_argument, NULL, OPT_AEAD}, + {"aead-chunk-bits", required_argument, NULL, OPT_AEAD_CHUNK}, + {"json", no_argument, NULL, OPT_JSON}, + {"grips", no_argument, NULL, OPT_GRIPS}, + {"mpi", no_argument, NULL, OPT_MPIS}, + {"raw", no_argument, NULL, OPT_RAW}, + {"notty", no_argument, NULL, OPT_NOTTY}, + {"source", required_argument, NULL, OPT_SOURCE}, + {"no-wrap", no_argument, NULL, OPT_NOWRAP}, + {"current-time", required_argument, NULL, OPT_CURTIME}, + {"set-filename", required_argument, NULL, OPT_SETFNAME}, + {"allow-hidden", no_argument, NULL, OPT_ALLOW_HIDDEN}, + {"s2k-iterations", required_argument, NULL, OPT_S2K_ITER}, + {"s2k-msec", required_argument, NULL, OPT_S2K_MSEC}, + {"allow-weak-hash", no_argument, NULL, OPT_ALLOW_WEAK_HASH}, + + {NULL, 0, NULL, 0}, +}; + +/* print a usage message */ +static void +print_usage(const char *usagemsg) +{ + cli_rnp_print_praise(); + puts(usagemsg); +} + +/* do a command once for a specified config */ +static bool +rnp_cmd(cli_rnp_t *rnp) +{ + bool ret = false; + + switch (rnp->cfg().get_int(CFG_COMMAND)) { + case CMD_PROTECT: + ret = cli_rnp_protect_file(rnp); + break; + case CMD_PROCESS: + ret = cli_rnp_process_file(rnp); + break; + case CMD_LIST_PACKETS: + ret = cli_rnp_dump_file(rnp); + break; + case CMD_DEARMOR: + ret = cli_rnp_dearmor_file(rnp); + break; + case CMD_ENARMOR: + ret = cli_rnp_armor_file(rnp); + break; + case CMD_VERSION: + cli_rnp_print_praise(); + ret = true; + break; + default: + print_usage(usage); + ret = true; + } + + return ret; +} + +static bool +setcmd(rnp_cfg &cfg, int cmd, const char *arg) +{ + int newcmd = cmd; + + /* set file processing command to one of PROTECT or PROCESS */ + switch (cmd) { + case CMD_ENCRYPT: + cfg.set_bool(CFG_ENCRYPT_PK, true); + if (cfg.get_bool(CFG_ENCRYPT_SK)) { + cfg.set_bool(CFG_KEYSTORE_DISABLED, false); + } + newcmd = CMD_PROTECT; + break; + case CMD_SYM_ENCRYPT: + cfg.set_bool(CFG_ENCRYPT_SK, true); + if (!cfg.get_bool(CFG_ENCRYPT_PK) && !cfg.get_bool(CFG_SIGN_NEEDED)) { + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + } + newcmd = CMD_PROTECT; + break; + case CMD_CLEARSIGN: + cfg.set_bool(CFG_CLEARTEXT, true); + [[fallthrough]]; + case CMD_SIGN: + cfg.set_bool(CFG_NEEDSSECKEY, true); + cfg.set_bool(CFG_SIGN_NEEDED, true); + if (cfg.get_bool(CFG_ENCRYPT_SK)) { + cfg.set_bool(CFG_KEYSTORE_DISABLED, false); + } + newcmd = CMD_PROTECT; + break; + case CMD_DECRYPT: + /* for decryption, we probably need a seckey */ + cfg.set_bool(CFG_NEEDSSECKEY, true); + newcmd = CMD_PROCESS; + break; + case CMD_VERIFY: + /* single verify will discard output, decrypt will not */ + cfg.set_bool(CFG_NO_OUTPUT, true); + [[fallthrough]]; + case CMD_VERIFY_CAT: + newcmd = CMD_PROCESS; + break; + case CMD_LIST_PACKETS: + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + break; + case CMD_DEARMOR: + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + break; + case CMD_ENARMOR: { + std::string msgt = arg ? arg : ""; + if (msgt.empty() || (msgt == "msg")) { + msgt = "message"; + } else if (msgt == "pubkey") { + msgt = "public key"; + } else if (msgt == "seckey") { + msgt = "secret key"; + } else if (msgt == "sign") { + msgt = "signature"; + } else { + ERR_MSG("Wrong enarmor argument: %s", arg); + return false; + } + + if (!msgt.empty()) { + cfg.set_str(CFG_ARMOR_DATA_TYPE, msgt); + } + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + break; + } + case CMD_HELP: + case CMD_VERSION: + break; + default: + newcmd = CMD_HELP; + break; + } + + if (cfg.has(CFG_COMMAND) && cfg.get_int(CFG_COMMAND) != newcmd) { + ERR_MSG("Conflicting commands!"); + return false; + } + + cfg.set_int(CFG_COMMAND, newcmd); + return true; +} + +/* set an option */ +static bool +setoption(rnp_cfg &cfg, int val, const char *arg) +{ + switch (val) { + /* redirect commands to setcmd */ + case CMD_ENCRYPT: + case CMD_SIGN: + case CMD_CLEARSIGN: + case CMD_DECRYPT: + case CMD_SYM_ENCRYPT: + case CMD_VERIFY: + case CMD_VERIFY_CAT: + case CMD_LIST_PACKETS: + case CMD_DEARMOR: + case CMD_ENARMOR: + case CMD_HELP: + case CMD_VERSION: + return setcmd(cfg, val, arg); + /* options */ + case OPT_COREDUMPS: +#ifdef _WIN32 + ERR_MSG("warning: --coredumps doesn't make sense on windows systems."); +#endif + cfg.set_bool(CFG_COREDUMPS, true); + return true; + case OPT_KEY_STORE_FORMAT: + cfg.set_str(CFG_KEYSTOREFMT, arg); + return true; + case OPT_USERID: + cfg.add_str(CFG_SIGNERS, arg); + return true; + case OPT_RECIPIENT: + cfg.add_str(CFG_RECIPIENTS, arg); + return true; + case OPT_ARMOR: + cfg.set_bool(CFG_ARMOR, true); + return true; + case OPT_DETACHED: + cfg.set_bool(CFG_DETACHED, true); + return true; + case OPT_HOMEDIR: + cfg.set_str(CFG_HOMEDIR, arg); + return true; + case OPT_KEYFILE: + cfg.set_str(CFG_KEYFILE, arg); + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + return true; + case OPT_HASH_ALG: + return cli_rnp_set_hash(cfg, arg); + case OPT_ALLOW_WEAK_HASH: + cfg.set_bool(CFG_WEAK_HASH, true); + return true; + case OPT_PASSWDFD: + cfg.set_str(CFG_PASSFD, arg); + return true; + case OPT_PASSWD: + cfg.set_str(CFG_PASSWD, arg); + return true; + case OPT_PASSWORDS: { + int count = 0; + if (!rnp::str_to_int(arg, count) || (count <= 0)) { + ERR_MSG("Incorrect value for --passwords option: %s", arg); + return false; + } + + cfg.set_int(CFG_PASSWORDC, count); + cfg.set_bool(CFG_ENCRYPT_SK, true); + return true; + } + case OPT_OUTPUT: + cfg.set_str(CFG_OUTFILE, arg); + return true; + case OPT_RESULTS: + cfg.set_str(CFG_RESULTS, arg); + return true; + case OPT_EXPIRATION: + cfg.set_str(CFG_EXPIRATION, arg); + return true; + case OPT_CREATION: + cfg.set_str(CFG_CREATION, arg); + return true; + case OPT_CIPHER: + return cli_rnp_set_cipher(cfg, arg); + case OPT_NUMTRIES: + cfg.set_str(CFG_NUMTRIES, arg); + return true; + case OPT_ZALG_ZIP: + cfg.set_str(CFG_ZALG, "ZIP"); + return true; + case OPT_ZALG_ZLIB: + cfg.set_str(CFG_ZALG, "ZLib"); + return true; + case OPT_ZALG_BZIP: + cfg.set_str(CFG_ZALG, "BZip2"); + return true; + case OPT_AEAD: { + std::string argstr = arg ? arg : ""; + if ((argstr == "1") || rnp::str_case_eq(argstr, "eax")) { + argstr = "EAX"; + } else if (argstr.empty() || (argstr == "2") || rnp::str_case_eq(argstr, "ocb")) { + argstr = "OCB"; + } else { + ERR_MSG("Wrong AEAD algorithm: %s", argstr.c_str()); + return false; + } + cfg.set_str(CFG_AEAD, argstr); + return true; + } + case OPT_AEAD_CHUNK: { + int bits = 0; + if (!rnp::str_to_int(arg, bits) || (bits < 0) || (bits > 16)) { + ERR_MSG("Wrong argument value %s for aead-chunk-bits, must be 0..16.", arg); + return false; + } + cfg.set_int(CFG_AEAD_CHUNK, bits); + return true; + } + case OPT_OVERWRITE: + cfg.set_bool(CFG_OVERWRITE, true); + return true; + case OPT_JSON: + cfg.set_bool(CFG_JSON, true); + return true; + case OPT_GRIPS: + cfg.set_bool(CFG_GRIPS, true); + return true; + case OPT_MPIS: + cfg.set_bool(CFG_MPIS, true); + return true; + case OPT_RAW: + cfg.set_bool(CFG_RAW, true); + return true; + case OPT_NOTTY: + cfg.set_bool(CFG_NOTTY, true); + return true; + case OPT_SOURCE: + cfg.set_str(CFG_SOURCE, arg); + return true; + case OPT_NOWRAP: + cfg.set_bool(CFG_NOWRAP, true); + cfg.set_int(CFG_ZLEVEL, 0); + return true; + case OPT_CURTIME: + cfg.set_str(CFG_CURTIME, arg); + return true; + case OPT_SETFNAME: + cfg.set_str(CFG_SETFNAME, arg); + return true; + case OPT_ALLOW_HIDDEN: + cfg.set_bool(CFG_ALLOW_HIDDEN, true); + return true; + case OPT_S2K_ITER: { + int iterations = 0; + if (!rnp::str_to_int(arg, iterations) || !iterations) { + ERR_MSG("Wrong iterations value: %s", arg); + return false; + } + cfg.set_int(CFG_S2K_ITER, iterations); + return true; + } + case OPT_S2K_MSEC: { + int msec = 0; + if (!rnp::str_to_int(arg, msec) || !msec) { + ERR_MSG("Invalid s2k msec value: %s", arg); + return false; + } + cfg.set_int(CFG_S2K_MSEC, msec); + return true; + } + case OPT_DEBUG: + ERR_MSG("Option --debug is deprecated, ignoring."); + return true; + default: + return setcmd(cfg, CMD_HELP, arg); + } + + return false; +} + +static bool +set_short_option(rnp_cfg &cfg, int ch, const char *arg) +{ + switch (ch) { + case 'V': + return setcmd(cfg, CMD_VERSION, arg); + case 'd': + return setcmd(cfg, CMD_DECRYPT, arg); + case 'e': + return setcmd(cfg, CMD_ENCRYPT, arg); + case 'c': + return setcmd(cfg, CMD_SYM_ENCRYPT, arg); + case 's': + return setcmd(cfg, CMD_SIGN, arg); + case 'v': + return setcmd(cfg, CMD_VERIFY, arg); + case 'r': + if (!strlen(optarg)) { + ERR_MSG("Recipient should not be empty"); + } else { + cfg.add_str(CFG_RECIPIENTS, optarg); + } + break; + case 'u': + if (!optarg) { + ERR_MSG("No userid argument provided"); + return false; + } + cfg.add_str(CFG_SIGNERS, optarg); + break; + case 'z': + if ((strlen(optarg) != 1) || (optarg[0] < '0') || (optarg[0] > '9')) { + ERR_MSG("Bad compression level: %s. Should be 0..9", optarg); + } else { + cfg.set_int(CFG_ZLEVEL, optarg[0] - '0'); + } + break; + case 'f': + if (!optarg) { + ERR_MSG("No keyfile argument provided"); + return false; + } + cfg.set_str(CFG_KEYFILE, optarg); + cfg.set_bool(CFG_KEYSTORE_DISABLED, true); + break; + case 'h': + [[fallthrough]]; + default: + return setcmd(cfg, CMD_HELP, optarg); + } + + return true; +} + +#ifndef RNP_RUN_TESTS +int +main(int argc, char **argv) +#else +int rnp_main(int argc, char **argv); +int +rnp_main(int argc, char **argv) +#endif +{ + if (argc < 2) { + print_usage(usage); + return EXIT_ERROR; + } + + cli_rnp_t rnp = {}; +#if !defined(RNP_RUN_TESTS) && defined(_WIN32) + try { + rnp.substitute_args(&argc, &argv); + } catch (std::exception &ex) { + RNP_LOG("Error converting arguments ('%s')", ex.what()); + return EXIT_ERROR; + } +#endif + + rnp_cfg cfg; + cfg.load_defaults(); + + /* TODO: These options should be set after initialising the context. */ + int optindex = 0; + int ch; + while ((ch = getopt_long(argc, argv, "S:Vdecr:su:vz:f:h", options, &optindex)) != -1) { + /* Check for unsupported command/option */ + if (ch == '?') { + print_usage(usage); + return EXIT_FAILURE; + } + + bool res = ch >= CMD_ENCRYPT ? setoption(cfg, options[optindex].val, optarg) : + set_short_option(cfg, ch, optarg); + if (!res) { + return EXIT_ERROR; + } + } + + switch (cfg.get_int(CFG_COMMAND)) { + case CMD_HELP: + print_usage(usage); + return EXIT_SUCCESS; + case CMD_VERSION: + cli_rnp_print_praise(); + return EXIT_SUCCESS; + default:; + } + + if (!cli_cfg_set_keystore_info(cfg)) { + ERR_MSG("fatal: cannot set keystore info"); + return EXIT_ERROR; + } + + if (!rnp.init(cfg)) { + ERR_MSG("fatal: cannot initialise"); + return EXIT_ERROR; + } + + if (!cli_rnp_check_weak_hash(&rnp)) { + ERR_MSG("Weak hash algorithm detected. Pass --allow-weak-hash option if you really " + "want to use it."); + return EXIT_ERROR; + } + + bool disable_ks = rnp.cfg().get_bool(CFG_KEYSTORE_DISABLED); + if (!disable_ks && !rnp.load_keyrings(rnp.cfg().get_bool(CFG_NEEDSSECKEY))) { + ERR_MSG("fatal: failed to load keys"); + return EXIT_ERROR; + } + + /* load the keyfile if any */ + if (disable_ks && !rnp.cfg().get_str(CFG_KEYFILE).empty() && !cli_rnp_add_key(&rnp)) { + ERR_MSG("fatal: failed to load key(s) from the file"); + return EXIT_ERROR; + } + + if (!cli_rnp_setup(&rnp)) { + return EXIT_ERROR; + } + + /* now do the required action for each of the command line args */ + if (optind == argc) { + return cli_rnp_t::ret_code(rnp_cmd(&rnp)); + } + bool success = true; + for (int i = optind; i < argc; i++) { + rnp.cfg().set_str(CFG_INFILE, argv[i]); + success = success && rnp_cmd(&rnp); + } + return cli_rnp_t::ret_code(success); +} diff --git a/comm/third_party/rnp/src/rnp/rnpcfg.cpp b/comm/third_party/rnp/src/rnp/rnpcfg.cpp new file mode 100644 index 0000000000..e1c35a30ae --- /dev/null +++ b/comm/third_party/rnp/src/rnp/rnpcfg.cpp @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_PARAM_H +#include +#else +#include "uniwin.h" +#endif +#include +#include +#include +#include +#include + +#include "config.h" +#include "rnpcfg.h" +#include "defaults.h" +#include "utils.h" +#include "time-utils.h" +#include + +// must be placed after include "utils.h" +#ifndef RNP_USE_STD_REGEX +#include +#else +#include +#endif + +typedef enum rnp_cfg_val_type_t { + RNP_CFG_VAL_NULL = 0, + RNP_CFG_VAL_INT = 1, + RNP_CFG_VAL_BOOL = 2, + RNP_CFG_VAL_STRING = 3, + RNP_CFG_VAL_LIST = 4 +} rnp_cfg_val_type_t; + +class rnp_cfg_val { + rnp_cfg_val_type_t type_; + + public: + rnp_cfg_val(rnp_cfg_val_type_t t) : type_(t){}; + rnp_cfg_val_type_t + type() const + { + return type_; + }; + + virtual ~rnp_cfg_val(){}; +}; + +class rnp_cfg_int_val : public rnp_cfg_val { + int val_; + + public: + rnp_cfg_int_val(int val) : rnp_cfg_val(RNP_CFG_VAL_INT), val_(val){}; + int + val() const + { + return val_; + }; +}; + +class rnp_cfg_bool_val : public rnp_cfg_val { + bool val_; + + public: + rnp_cfg_bool_val(bool val) : rnp_cfg_val(RNP_CFG_VAL_BOOL), val_(val){}; + bool + val() const + { + return val_; + }; +}; + +class rnp_cfg_str_val : public rnp_cfg_val { + std::string val_; + + public: + rnp_cfg_str_val(const std::string &val) : rnp_cfg_val(RNP_CFG_VAL_STRING), val_(val){}; + const std::string & + val() const + { + return val_; + }; +}; + +class rnp_cfg_list_val : public rnp_cfg_val { + std::vector val_; + + public: + rnp_cfg_list_val() : rnp_cfg_val(RNP_CFG_VAL_LIST), val_(){}; + std::vector & + val() + { + return val_; + }; + const std::vector & + val() const + { + return val_; + }; +}; + +void +rnp_cfg::load_defaults() +{ + set_bool(CFG_OVERWRITE, false); + set_str(CFG_OUTFILE, ""); + set_str(CFG_ZALG, DEFAULT_Z_ALG); + set_int(CFG_ZLEVEL, DEFAULT_Z_LEVEL); + set_str(CFG_CIPHER, DEFAULT_SYMM_ALG); + set_int(CFG_NUMTRIES, MAX_PASSWORD_ATTEMPTS); + set_int(CFG_S2K_MSEC, DEFAULT_S2K_MSEC); +} + +void +rnp_cfg::set_str(const std::string &key, const std::string &val) +{ + unset(key); + vals_[key] = new rnp_cfg_str_val(val); +} + +void +rnp_cfg::set_str(const std::string &key, const char *val) +{ + unset(key); + vals_[key] = new rnp_cfg_str_val(val); +} + +void +rnp_cfg::set_int(const std::string &key, int val) +{ + unset(key); + vals_[key] = new rnp_cfg_int_val(val); +} + +void +rnp_cfg::set_bool(const std::string &key, bool val) +{ + unset(key); + vals_[key] = new rnp_cfg_bool_val(val); +} + +void +rnp_cfg::unset(const std::string &key) +{ + if (!vals_.count(key)) { + return; + } + delete vals_[key]; + vals_.erase(key); +} + +void +rnp_cfg::add_str(const std::string &key, const std::string &val) +{ + if (!vals_.count(key)) { + vals_[key] = new rnp_cfg_list_val(); + } + if (vals_[key]->type() != RNP_CFG_VAL_LIST) { + RNP_LOG("expected list val for \"%s\"", key.c_str()); + throw std::invalid_argument("type"); + } + (dynamic_cast(*vals_[key])).val().push_back(val); +} + +bool +rnp_cfg::has(const std::string &key) const +{ + return vals_.count(key); +} + +const std::string & +rnp_cfg::get_str(const std::string &key) const +{ + if (!has(key) || (vals_.at(key)->type() != RNP_CFG_VAL_STRING)) { + return empty_str_; + } + return (dynamic_cast(*vals_.at(key))).val(); +} + +const char * +rnp_cfg::get_cstr(const std::string &key) const +{ + if (!has(key) || (vals_.at(key)->type() != RNP_CFG_VAL_STRING)) { + return NULL; + } + return (dynamic_cast(*vals_.at(key))).val().c_str(); +} + +int +rnp_cfg::get_int(const std::string &key, int def) const +{ + if (!has(key)) { + return def; + } + const rnp_cfg_val *val = vals_.at(key); + switch (val->type()) { + case RNP_CFG_VAL_INT: + return (dynamic_cast(*val)).val(); + case RNP_CFG_VAL_BOOL: + return (dynamic_cast(*val)).val(); + case RNP_CFG_VAL_STRING: + return atoi((dynamic_cast(*val)).val().c_str()); + default: + return def; + } +} + +bool +rnp_cfg::get_bool(const std::string &key) const +{ + if (!has(key)) { + return false; + } + const rnp_cfg_val *val = vals_.at(key); + switch (val->type()) { + case RNP_CFG_VAL_INT: + return (dynamic_cast(*val)).val(); + case RNP_CFG_VAL_BOOL: + return (dynamic_cast(*val)).val(); + case RNP_CFG_VAL_STRING: { + const std::string &str = (dynamic_cast(*val)).val(); + return !strcasecmp(str.c_str(), "true") || (atoi(str.c_str()) > 0); + } + default: + return false; + } +} + +size_t +rnp_cfg::get_count(const std::string &key) const +{ + if (!has(key) || (vals_.at(key)->type() != RNP_CFG_VAL_LIST)) { + return 0; + } + return (dynamic_cast(*vals_.at(key))).val().size(); +} + +const std::string & +rnp_cfg::get_str(const std::string &key, size_t idx) const +{ + if (get_count(key) <= idx) { + RNP_LOG("idx is out of bounds for \"%s\"", key.c_str()); + throw std::invalid_argument("idx"); + } + return (dynamic_cast(*vals_.at(key))).val().at(idx); +} + +std::vector +rnp_cfg::get_list(const std::string &key) const +{ + if (!has(key)) { + /* it's okay to return empty list */ + return std::vector(); + } + if (vals_.at(key)->type() != RNP_CFG_VAL_LIST) { + RNP_LOG("no list at the key \"%s\"", key.c_str()); + throw std::invalid_argument("key"); + } + return (dynamic_cast(*vals_.at(key))).val(); +} + +int +rnp_cfg::get_pswdtries() const +{ + const std::string &numtries = get_str(CFG_NUMTRIES); + int num = atoi(numtries.c_str()); + if (numtries.empty() || (num <= 0)) { + return MAX_PASSWORD_ATTEMPTS; + } else if (numtries == "unlimited") { + return INFINITE_ATTEMPTS; + } + return num; +} + +const std::string +rnp_cfg::get_hashalg() const +{ + const std::string hash_alg = get_str(CFG_HASH); + if (!hash_alg.empty()) { + return hash_alg; + } + return DEFAULT_HASH_ALG; +} + +bool +rnp_cfg::get_expiration(const std::string &key, uint32_t &seconds) const +{ + if (!has(key)) { + return false; + } + const std::string &val = get_str(key); + uint64_t delta; + uint64_t t; + if (parse_date(val, t)) { + uint64_t now = time(); + if (t > now) { + delta = t - now; + if (delta > UINT32_MAX) { + RNP_LOG("Expiration time exceeds 32-bit value"); + return false; + } + seconds = delta; + return true; + } + return false; + } + const char *reg = "^([0-9]+)([hdwmy]?)$"; +#ifndef RNP_USE_STD_REGEX + static regex_t r; + static int compiled; + regmatch_t matches[3]; + + if (!compiled) { + compiled = 1; + if (regcomp(&r, reg, REG_EXTENDED | REG_ICASE)) { + RNP_LOG("failed to compile regexp"); + return false; + } + } + if (regexec(&r, val.c_str(), ARRAY_SIZE(matches), matches, 0)) { + return false; + } + auto delta_str = &val.c_str()[matches[1].rm_so]; + char mult = val.c_str()[matches[2].rm_so]; +#else + static std::regex re(reg, std::regex_constants::extended | std::regex_constants::icase); + std::smatch result; + + if (!std::regex_search(val, result, re)) { + return false; + } + std::string delta_stdstr = result[1].str(); + const char *delta_str = delta_stdstr.c_str(); + char mult = result[2].str()[0]; +#endif + errno = 0; + delta = strtoul(delta_str, NULL, 10); + if (errno || delta > UINT_MAX) { + RNP_LOG("Invalid expiration '%s'.", delta_str); + return false; + } + switch (std::tolower(mult)) { + case 'h': + delta *= 60 * 60; + break; + case 'd': + delta *= 60 * 60 * 24; + break; + case 'w': + delta *= 60 * 60 * 24 * 7; + break; + case 'm': + delta *= 60 * 60 * 24 * 31; + break; + case 'y': + delta *= 60 * 60 * 24 * 365; + break; + } + if (delta > UINT32_MAX) { + RNP_LOG("Expiration value exceed 32 bit."); + return false; + } + seconds = delta; + return true; +} + +bool +rnp_cfg::extract_timestamp(const std::string &st, uint64_t &t) const +{ + if (st.empty()) { + return false; + } + if (parse_date(st, t)) { + return true; + } + /* Check if string is UNIX timestamp */ + for (auto c : st) { + if (!isdigit(c)) { + return false; + } + } + t = std::stoll(st); + return true; +} + +uint64_t +rnp_cfg::get_sig_creation() const +{ + uint64_t t = 0; + if (extract_timestamp(get_str(CFG_CREATION), t)) { + return t; + } + return time(); +} + +uint64_t +rnp_cfg::time() const +{ + uint64_t t = 0; + if (extract_timestamp(get_str(CFG_CURTIME), t)) { + return t; + } + return ::time(NULL); +} + +void +rnp_cfg::copy(const rnp_cfg &src) +{ + for (const auto &it : src.vals_) { + if (has(it.first)) { + unset(it.first); + } + rnp_cfg_val *val = NULL; + switch (it.second->type()) { + case RNP_CFG_VAL_INT: + val = new rnp_cfg_int_val(dynamic_cast(*it.second)); + break; + case RNP_CFG_VAL_BOOL: + val = new rnp_cfg_bool_val(dynamic_cast(*it.second)); + break; + case RNP_CFG_VAL_STRING: + val = new rnp_cfg_str_val(dynamic_cast(*it.second)); + break; + case RNP_CFG_VAL_LIST: + val = new rnp_cfg_list_val(dynamic_cast(*it.second)); + break; + default: + continue; + } + vals_[it.first] = val; + } +} + +void +rnp_cfg::clear() +{ + for (const auto &it : vals_) { + delete it.second; + } + vals_.clear(); +} + +rnp_cfg::~rnp_cfg() +{ + clear(); +} + +/** + * @brief Get number of days in month. + * + * @param year number of year, i.e. 2021 + * @param month number of month, 1..12 + * @return number of days (28..31) or 0 if month is wrong. + */ +static int +days_in_month(int year, int month) +{ + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: { + bool leap_year = !(year % 400) || (!(year % 4) && (year % 100)); + return leap_year ? 29 : 28; + } + default: + return 0; + } +} + +bool +rnp_cfg::parse_date(const std::string &s, uint64_t &t) const +{ + /* fill time zone information */ + struct tm tm; + rnp_localtime(::time(NULL), tm); + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + const char *reg = "^([0-9]{4})[-/\\.]([0-9]{2})[-/\\.]([0-9]{2})$"; +#ifndef RNP_USE_STD_REGEX + static regex_t r; + static int compiled; + + if (!compiled) { + compiled = 1; + if (regcomp(&r, reg, REG_EXTENDED)) { + RNP_LOG("failed to compile regexp"); + return false; + } + } + regmatch_t matches[4]; + if (regexec(&r, s.c_str(), ARRAY_SIZE(matches), matches, 0)) { + return false; + } + int year = strtol(&s[matches[1].rm_so], NULL, 10); + int mon = strtol(&s[matches[2].rm_so], NULL, 10); + int mday = strtol(&s[matches[3].rm_so], NULL, 10); +#else + static std::regex re(reg, std::regex_constants::extended); + std::smatch result; + + if (!std::regex_search(s, result, re)) { + return false; + } + int year = std::stoi(result[1].str()); + int mon = std::stoi(result[2].str()); + int mday = std::stoi(result[3].str()); +#endif + if (year < 1970 || mon < 1 || mon > 12 || !mday || (mday > days_in_month(year, mon))) { + RNP_LOG("invalid date: %s.", s.c_str()); + return false; + } + tm.tm_year = year - 1900; + tm.tm_mon = mon - 1; + tm.tm_mday = mday; + /* line below is required to correctly handle DST changes */ + tm.tm_isdst = -1; + + struct tm check_tm = tm; + time_t built_time = rnp_mktime(&tm); + time_t check_time = mktime(&check_tm); + if (built_time != check_time) { + /* If date is beyond of yk2038 and we have 32-bit signed time_t, we need to reduce + * timestamp */ + RNP_LOG("Warning: date %s is beyond of 32-bit time_t, so timestamp was reduced to " + "maximum supported value.", + s.c_str()); + } + t = built_time; + return true; +} diff --git a/comm/third_party/rnp/src/rnp/rnpcfg.h b/comm/third_party/rnp/src/rnp/rnpcfg.h new file mode 100644 index 0000000000..c9478bbd88 --- /dev/null +++ b/comm/third_party/rnp/src/rnp/rnpcfg.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RNP_CFG_H_ +#define RNP_CFG_H_ + +#include +#include +#include +#include +#include + +/* cfg variables known by rnp */ +#define CFG_OVERWRITE "overwrite" /* overwrite output file if it is already exist or fail */ +#define CFG_ARMOR "armor" /* armor output data or not */ +#define CFG_ARMOR_DATA_TYPE "armor_type" /* armor data type, used with ``enarmor`` option */ +#define CFG_COMMAND "command" /* command to execute over input data */ +#define CFG_DETACHED "detached" /* produce the detached signature */ +#define CFG_CLEARTEXT "cleartext" /* cleartext signing should be used */ +#define CFG_SIGN_NEEDED "sign_needed" /* signing is needed during data protection */ +#define CFG_OUTFILE "outfile" /* name/path of the output file */ +#define CFG_NO_OUTPUT "no_output" /* do not output any data - just verify or process */ +#define CFG_INFILE "infile" /* name/path of the input file */ +#define CFG_SETFNAME "setfname" /* file name to embed into the literal data packet */ +#define CFG_RESULTS "results" /* name/path for results, not used right now */ +#define CFG_KEYSTOREFMT "keystorefmt" /* keyring format : GPG, G10, KBX */ +#define CFG_COREDUMPS "coredumps" /* enable/disable core dumps. 1 or 0. */ +#define CFG_NEEDSSECKEY "needsseckey" /* needs secret key for the ongoing operation */ +#define CFG_USERID "userid" /* userid for the ongoing operation */ +#define CFG_RECIPIENTS "recipients" /* list of encrypted data recipients */ +#define CFG_SIGNERS "signers" /* list of signers */ +#define CFG_HOMEDIR "homedir" /* home directory - folder with keyrings and so on */ +#define CFG_KEYFILE "keyfile" /* path to the file with key(s), used instead of keyring */ +#define CFG_PASSFD "pass-fd" /* password file descriptor */ +#define CFG_PASSWD "password" /* password as command-line constant */ +#define CFG_PASSWORDC "passwordc" /* number of passwords for symmetric encryption */ +#define CFG_USERINPUTFD "user-input-fd" /* user input file descriptor */ +#define CFG_NUMTRIES "numtries" /* number of password request tries, or 'unlimited' */ +#define CFG_EXPIRATION "expiration" /* signature expiration time */ +#define CFG_CREATION "creation" /* signature validity start */ +#define CFG_CIPHER "cipher" /* symmetric encryption algorithm as string */ +#define CFG_HASH "hash" /* hash algorithm used, string like 'SHA1'*/ +#define CFG_WEAK_HASH "weak-hash" /* allow weak algorithms */ +#define CFG_S2K_ITER "s2k-iter" /* number of S2K hash iterations to perform */ +#define CFG_S2K_MSEC "s2k-msec" /* number of milliseconds S2K should target */ +#define CFG_ENCRYPT_PK "encrypt_pk" /* public key should be used during encryption */ +#define CFG_ENCRYPT_SK "encrypt_sk" /* password encryption should be used */ +#define CFG_IO_RESS "ress" /* results stream */ +#define CFG_NUMBITS "numbits" /* number of bits in generated key */ +#define CFG_EXPERT "expert" /* expert key generation mode */ +#define CFG_ZLEVEL "zlevel" /* compression level: 0..9 (0 for no compression) */ +#define CFG_ZALG "zalg" /* compression algorithm: zip, zlib or bzip2 */ +#define CFG_AEAD "aead" /* if nonzero then AEAD enryption mode, int */ +#define CFG_AEAD_CHUNK "aead_chunk" /* AEAD chunk size bits, int from 0 to 56 */ +#define CFG_KEYSTORE_DISABLED \ + "disable_keystore" /* indicates whether keystore must be initialized */ +#define CFG_FORCE "force" /* force command to succeed operation */ +#define CFG_SECRET "secret" /* indicates operation on secret key */ +#define CFG_WITH_SIGS "with-sigs" /* list keys with signatures */ +#define CFG_JSON "json" /* list packets with JSON output */ +#define CFG_GRIPS "grips" /* dump grips when dumping key packets */ +#define CFG_MPIS "mpis" /* dump MPI values when dumping packets */ +#define CFG_RAW "raw" /* dump raw packet contents */ +#define CFG_REV_TYPE "rev-type" /* revocation reason code */ +#define CFG_REV_REASON "rev-reason" /* revocation reason human-readable string */ +#define CFG_PERMISSIVE "permissive" /* ignore bad packets during key import */ +#define CFG_NOTTY "notty" /* disable tty usage and do input/output via stdin/stdout */ +#define CFG_FIX_25519_BITS "fix-25519-bits" /* fix Cv25519 secret key via --edit-key */ +#define CFG_CHK_25519_BITS "check-25519-bits" /* check Cv25519 secret key bits */ +#define CFG_ADD_SUBKEY "add-subkey" /* add subkey to existing primary */ +#define CFG_SET_KEY_EXPIRE "key-expire" /* set/update key expiration time */ +#define CFG_SOURCE "source" /* source for the detached signature */ +#define CFG_NOWRAP "no-wrap" /* do not wrap the output in a literal data packet */ +#define CFG_CURTIME "curtime" /* date or timestamp to override the system's time */ +#define CFG_ALLOW_HIDDEN "allow-hidden" /* allow hidden recipients */ + +/* rnp keyring setup variables */ +#define CFG_KR_PUB_FORMAT "kr-pub-format" +#define CFG_KR_SEC_FORMAT "kr-sec-format" +#define CFG_KR_PUB_PATH "kr-pub-path" +#define CFG_KR_SEC_PATH "kr-sec-path" +#define CFG_KR_DEF_KEY "kr-def-key" + +/* key generation variables */ +#define CFG_KG_PRIMARY_ALG "kg-primary-alg" +#define CFG_KG_PRIMARY_BITS "kg-primary-bits" +#define CFG_KG_PRIMARY_CURVE "kg-primary-curve" +#define CFG_KG_PRIMARY_EXPIRATION "kg-primary-expiration" +#define CFG_KG_SUBKEY_ALG "kg-subkey-alg" +#define CFG_KG_SUBKEY_BITS "kg-subkey-bits" +#define CFG_KG_SUBKEY_CURVE "kg-subkey-curve" +#define CFG_KG_SUBKEY_EXPIRATION "kg-subkey-expiration" +#define CFG_KG_HASH "kg-hash" +#define CFG_KG_PROT_HASH "kg-prot-hash" +#define CFG_KG_PROT_ALG "kg-prot-alg" +#define CFG_KG_PROT_ITERATIONS "kg-prot-iterations" + +/* rnp CLI config : contains all the system-dependent and specified by the user configuration + * options */ +class rnp_cfg_val; + +class rnp_cfg { + private: + std::unordered_map vals_; + std::string empty_str_; + + /** @brief Parse date from the string in %Y-%m-%d format (using "-", "/", "." as a + * separator) + * + * @param s string with the date + * @param t UNIX timestamp of successfully parsed date + * @return true when parsed successfully or false otherwise + */ + bool parse_date(const std::string &s, uint64_t &t) const; + bool extract_timestamp(const std::string &st, uint64_t &t) const; + + public: + /** @brief load default settings */ + void load_defaults(); + /** @brief set string value for the key in config */ + void set_str(const std::string &key, const std::string &val); + void set_str(const std::string &key, const char *val); + /** @brief set int value for the key in config */ + void set_int(const std::string &key, int val); + /** @brief set bool value for the key in config */ + void set_bool(const std::string &key, bool val); + /** @brief remove key and corresponding value from the config */ + void unset(const std::string &key); + /** @brief add string item to the list value */ + void add_str(const std::string &key, const std::string &val); + /** @brief check whether config has value for the key */ + bool has(const std::string &key) const; + /** @brief get string value from the config. If it is absent then empty string will be + * returned */ + const std::string &get_str(const std::string &key) const; + /** @brief get C string value from the config. Will return 0 instead of empty string if + * value is absent. */ + const char *get_cstr(const std::string &key) const; + /** @brief get int value from the config. If it is absent then def will be returned */ + int get_int(const std::string &key, int def = 0) const; + /** @brief get bool value from the config. If it is absent then false will be returned */ + bool get_bool(const std::string &key) const; + /** @brief get number of items in the string list value. If it is absent then 0 will be + * returned. */ + size_t get_count(const std::string &key) const; + /** @brief get string from the list value at the corresponding position. If there is no + * corresponding value or index too large then empty string will be returned. */ + const std::string &get_str(const std::string &key, size_t idx) const; + /** @brief get all strings from the list value */ + std::vector get_list(const std::string &key) const; + /** @brief get number of the password tries */ + int get_pswdtries() const; + /** @brief get hash algorithm */ + const std::string get_hashalg() const; + + /** @brief Get expiration time from the cfg variable, as value relative to the current + * time. As per OpenPGP standard it should fit in 32 bit value, otherwise error is + * returned. + * + * Expiration may be specified in different formats: + * - 10d : 10 days (you can use [h]ours, d[ays], [w]eeks, [m]onthes) + * - 2017-07-12 : as the exact date + * - 60000 : number of seconds + * + * @param seconds On successful return result will be placed here + * @return true on success or false otherwise + */ + bool get_expiration(const std::string &key, uint32_t &seconds) const; + + /** @brief Get signature creation time from the config. + * Creation time may be specified in different formats: + * - 2017-07-12 : as the exact date + * - 1499334073 : timestamp + * + * @return timestamp of the signature creation. + */ + uint64_t get_sig_creation() const; + + /** @brief Get current time from the config. + * + * @return timestamp which should be considered as current time. + */ + uint64_t time() const; + + /** @brief copy or override a configuration. + * @param src vals will be overridden (if key exist) or copied (if not) from this object + */ + void copy(const rnp_cfg &src); + void clear(); + /* delete unneeded operators */ + rnp_cfg &operator=(const rnp_cfg &src) = delete; + rnp_cfg &operator=(const rnp_cfg &&src) = delete; + /** @brief destructor */ + ~rnp_cfg(); +}; + +#endif diff --git a/comm/third_party/rnp/src/rnpkeys/CMakeLists.txt b/comm/third_party/rnp/src/rnpkeys/CMakeLists.txt new file mode 100644 index 0000000000..6302903a02 --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/CMakeLists.txt @@ -0,0 +1,101 @@ +# Copyright (c) 2018-2020 Ribose Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +if(MSVC) + # remove extra ${Configuration} subfolder + set(ArchiveOutputDir ${CMAKE_BINARY_DIR}\\src\\rnpkeys) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${ArchiveOutputDir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${ArchiveOutputDir}) + + set(RuntimeOutputDir ${CMAKE_BINARY_DIR}\\src\\rnpkeys) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${RuntimeOutputDir}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${RuntimeOutputDir}) + + find_path(GETOPT_INCLUDE_DIR + NAMES getopt.h + ) + find_library(GETOPT_LIBRARY + NAMES getopt + ) + find_path(DIRENT_INCLUDE_DIR + NAMES dirent.h + ) +endif() + +# for the headers +find_package(JSON-C 0.11 REQUIRED) + +add_executable(rnpkeys + rnpkeys.cpp + tui.cpp + main.cpp + ../rnp/rnpcfg.cpp + ../rnp/fficli.cpp +) + +if(BUILD_SHARED_LIBS) + target_sources(rnpkeys PRIVATE ../lib/logging.cpp $) +endif(BUILD_SHARED_LIBS) + +target_include_directories(rnpkeys + PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/lib" + "${JSON-C_INCLUDE_DIRS}" +) +if(MSVC) + target_include_directories(rnpkeys + PRIVATE + "${GETOPT_INCLUDE_DIR}" + "${DIRENT_INCLUDE_DIR}" + ) +endif() + +target_link_libraries(rnpkeys + PRIVATE + librnp + JSON-C::JSON-C +) +if(MSVC) + target_link_libraries(rnpkeys + PRIVATE + "${GETOPT_LIBRARY}" + ) +endif() + +include(GNUInstallDirs) +install(TARGETS rnpkeys + RUNTIME + DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT cli +) + +# Build and install man page +if (ENABLE_DOC) + add_adoc_man("${CMAKE_CURRENT_SOURCE_DIR}/rnpkeys.1.adoc" ${RNP_VERSION}) +endif() diff --git a/comm/third_party/rnp/src/rnpkeys/main.cpp b/comm/third_party/rnp/src/rnpkeys/main.cpp new file mode 100644 index 0000000000..8bcb7e1115 --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/main.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* Command line program to perform rnp operations */ +#ifdef _MSC_VER +#include "uniwin.h" +#else +#include +#endif +#include +#include +#include "rnpkeys.h" + +extern struct option options[]; +extern const char * usage; + +optdefs_t +get_short_cmd(int ch) +{ + switch (ch) { + case 'V': + return CMD_VERSION; + case 'g': + return CMD_GENERATE_KEY; + case 'l': + return CMD_LIST_KEYS; + case 'h': + [[fallthrough]]; + default: + return CMD_HELP; + } +} + +#ifndef RNP_RUN_TESTS +int +main(int argc, char **argv) +#else +int rnpkeys_main(int argc, char **argv); +int +rnpkeys_main(int argc, char **argv) +#endif +{ + if (argc < 2) { + print_usage(usage); + return EXIT_FAILURE; + } + + cli_rnp_t rnp = {}; +#if !defined(RNP_RUN_TESTS) && defined(_WIN32) + try { + rnp.substitute_args(&argc, &argv); + } catch (std::exception &ex) { + RNP_LOG("Error converting arguments ('%s')", ex.what()); + return EXIT_FAILURE; + } +#endif + + rnp_cfg cfg; + optdefs_t cmd = CMD_NONE; + int optindex = 0; + int ch; + + while ((ch = getopt_long(argc, argv, "Vglh", options, &optindex)) != -1) { + /* Check for unsupported command/option */ + if (ch == '?') { + print_usage(usage); + return EXIT_FAILURE; + } + + optdefs_t newcmd = cmd; + if (ch >= CMD_LIST_KEYS) { + if (!setoption(cfg, &newcmd, options[optindex].val, optarg)) { + ERR_MSG("Failed to process argument --%s", options[optindex].name); + return EXIT_FAILURE; + } + } else { + newcmd = get_short_cmd(ch); + } + + if (cmd && newcmd != cmd) { + ERR_MSG("Conflicting commands!"); + return EXIT_FAILURE; + } + cmd = newcmd; + } + + /* No initialization required for these two commands. */ + if (cmd == CMD_HELP || cmd == CMD_VERSION) { + return cli_rnp_t::ret_code(rnp_cmd(&rnp, cmd, NULL)); + } + + if (!rnpkeys_init(rnp, cfg)) { + return EXIT_FAILURE; + } + + if (!cli_rnp_setup(&rnp)) { + return EXIT_FAILURE; + } + + /* now do the required action for each of the command line args */ + if (optind == argc) { + return cli_rnp_t::ret_code(rnp_cmd(&rnp, cmd, NULL)); + } + bool success = true; + for (int i = optind; i < argc; i++) { + success = success && rnp_cmd(&rnp, cmd, argv[i]); + } + return cli_rnp_t::ret_code(success); +} diff --git a/comm/third_party/rnp/src/rnpkeys/moz.build b/comm/third_party/rnp/src/rnpkeys/moz.build new file mode 100644 index 0000000000..e6cb1c503c --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/moz.build @@ -0,0 +1,64 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Program("rnpkeys") + +include("../../../rnpdefs.mozbuild") + +USE_LIBS += ["rnp"] + +LOCAL_INCLUDES = [ + "!../lib", + "..", + "../../include", + "../common", + "../lib", +] + +if CONFIG["MZLA_SYSTEM_JSONC"]: + CXXFLAGS += CONFIG["MZLA_JSONC_CFLAGS"] + LDFLAGS += CONFIG["MZLA_JSONC_LIBS"] + ["-Wl,-rpath,$ORIGIN"] +else: + USE_LIBS += ["json-c"] + LOCAL_INCLUDES += ["!/comm/third_party/json-c", "/comm/third_party/json-c"] + LDFLAGS += ["-Wl,-rpath,$ORIGIN"] + +SOURCES += [ + "../common/file-utils.cpp", + "../common/str-utils.cpp", + "../common/time-utils.cpp", + "../lib/logging.cpp", + "../rnp/fficli.cpp", + "../rnp/rnpcfg.cpp", + "main.cpp", + "rnpkeys.cpp", + "tui.cpp", +] + +if CONFIG["CC_TYPE"] == "clang-cl": + CXXFLAGS += [ + "/EHs", + "-Wno-deprecated-declarations", + ] + LOCAL_INCLUDES += [ + "/comm/third_party/niwcompat", + ] + + OS_LIBS += ["shell32"] + + if CONFIG["CPU_ARCH"] == "x86": + LDFLAGS += ["clang_rt.builtins-i386.lib"] + elif CONFIG["CPU_ARCH"] == "x86_64": + LDFLAGS += ["clang_rt.builtins-x86_64.lib"] + + SOURCES += [ + "/comm/third_party/niwcompat/getopt.c", + ] + SOURCES["../rnp/rnpcfg.cpp"].flags += [ + "-FI", + "%s/comm/third_party/niwcompat/extra_include.h" % TOPSRCDIR, + ] + DEFINES["MOZILLA_CONFIG_H"] = True + DEFINES["_CRT_SECURE_NO_WARNINGS"] = True diff --git a/comm/third_party/rnp/src/rnpkeys/rnpkeys.1.adoc b/comm/third_party/rnp/src/rnpkeys/rnpkeys.1.adoc new file mode 100644 index 0000000000..2b09d1794d --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/rnpkeys.1.adoc @@ -0,0 +1,453 @@ += rnpkeys(1) +RNP +:doctype: manpage +:release-version: {component-version} +:man manual: RNP Manual +:man source: RNP {release-version} + +== NAME + +RNPKEYS - OpenPGP key management utility. + +== SYNOPSIS + +*rnpkeys* [_--homedir_ _dir_] [_OPTIONS_] _COMMAND_ + +== DESCRIPTION + +The _rnpkeys_ command-line utility is part of the _RNP_ suite and +provides OpenPGP key management functionality, including: + +* key listing; +* key generation; +* key import/export; and +* key editing. + + +=== BASICS + +By default, *rnp* will apply a _COMMAND_, additionally configured with _OPTIONS_, +to all _INPUT_FILE_(s) or _stdin_ if no _INPUT_FILE_ is given. +There are some special cases for _INPUT_FILE_ : + +* _-_ (dash) substitutes to _stdin_ +* env:VARIABLE_NAME substitutes to the contents of environment variable VARIABLE_NAME + +Depending on the input, output may be written: + +* to the specified file with a removed or added file extension (_.pgp_, _.asc_, _.sig_); or +* to _stdout_. + +Without the *--armor* option, output will be in binary. + +If _COMMAND_ requires public or private keys, *rnp* will look for the keyrings in *~/.rnp*. The options *--homedir* and *--keyfile* override this (see below). + +If _COMMAND_ needs a password, *rnp* will ask for it via *stdin* or *tty*, +unless the *--password* or *--pass-fd* option was specified. + + +By default, *rnpkeys* will use keyrings stored in the _~/.rnp_ directory. + +This behavior may be overridden with the _--homedir_ option. + +If _COMMAND_ needs a password, the command will prompt the caller +via _stdin_ or _tty_, unless the *--password* or *--pass-fd* +options were also used. + +=== SPECIFYING KEYS + +Most *rnpkeys* commands require a key locator or a filter, +representing one or more keys. + +It may be specified in one of the following ways: + +*userid*:: +Or just part of the *userid*. +For *"Alice "*, the following methods are considered identical: + +** _alice_ +** _alice@rnpgp_ +** _rnpgp.com_ + +*keyid*:: +Or its right-most 8 characters. With or without _0x_ at the beginning and spaces/tabs inside. Such as: + +** _0x725F6F2D6D5F6120_ +** _"725F6F2D 6D5F6120"_ +** _0x6D5F6120_ + +*key fingerprint*: The 40-character key fingerprint, such as: + +** _"0x416E746F 6E537669 72696465 6E6B6F20"_ + + + +== COMMANDS + +=== INFORMATIONAL + +*-h*, *--help*:: +Displays a short help message. No options are expected. + +*-V*, *--version*:: +Displays version information. No options are expected. + +*-l*, *--list-keys*:: +List out keys and some brief information about each. + ++ +Additional options: + +*--with-sigs*::: +Additionally display signatures of listed keys. + + +=== KEY GENERATION + +*-g*, *--generate-key*:: +Generate a new keypair. + ++ +Without additional options, an RSA primary key pair with an RSA sub-key pair will be generated, and prompting for the encryption password afterwards. ++ +Additional options: + +*--numbits*::: +Overrides the default RSA key size of *2048* bits. + +*--expiration* _TIME_::: +Set key and subkey expiration time, counting from the creation time. + ++ +By default generated keys do not expire. + ++ +Expiration time can be specified as: + +* expiration date in the ISO 8601:2019 date format (_yyyy-mm-dd_); or +* hours/days/months/years since creation time with the syntax of _20h_/_30d_/_1m_/_1y_; +* number of seconds. + +*--expert*::: +Select key algorithms interactively and override default settings. + +*--userid*::: +Specifies the _userid_ to be used in generation. + +*--hash*::: +Specify the hash algorithm used in generation. + +*--cipher*::: +Specify the encryption algorithm used in generation. + +*--s2k-iterations*::: +Specify the number of iterations for the S2K (string-to-key) process. + ++ +This is used during the derivation of the symmetric key, which +encrypts a secret key from the password. + + +*--s2k-msec*::: +Specify that *rnpkeys* should automatically pick a +*--s2k-iterations* value such that the single key derivation operation +would take _NUMBER_ of milliseconds on the current system. + ++ +For example, setting it to _2000_ would mean that each secret key +decryption operation would take around 2 seconds (on the current machine). + + +=== KEY/SIGNATURE IMPORT + +*--import*, *--import-keys*, *--import-sigs*:: +Import keys or signatures. + ++ +While *rnpkeys* automatically detects the input data format, +one may still wish to specify whether the input provides keys or signatures. + ++ +By default, the import process will stop on the first discovered +erroneous key or signature. + ++ +Additional options: + +*--permissive*::: +Skip errored or unsupported packets during the import process. + +=== KEY/SIGNATURE EXPORT + +*--export-key* [*--userid*=_FILTER_] [_FILTER_]:: +Export key(s). Only export keys that match _FILTER_ if _FILTER_ is given. + ++ +If filter matches a primary key, the subkeys of the primary key are also exported. ++ +By default, key data is written to _stdout_ in ASCII-armored format. ++ +Additional options: + +*--output* _PATH_::: +Specifies output to be written to a file name instead of _stdout_. + +*--secret*::: +Without this option specified, the command will only export public key(s). +This option must be provided to export secret key(s). + +*--export-rev* _KEY_:: +Export the revocation signature for a specified secret key. + ++ +The revocation signature can be used later in a case of key loss or compromise. ++ +Additional options: + +*--rev-type*::: +Specifies type of key revocation. + +*--rev-reason*::: +Specifies reason for key revocation. + + +=== KEY MANIPULATION + +*--revoke-key* _KEY_:: +Issue revocation signature for the secret key, and save it in the keyring. + ++ +Revoked keys cannot be used further. + ++ +Additional options: + +*--rev-type*::: +Specifies type of key revocation, see *options* section for the available values. + +*--rev-reason*::: +Specifies reason for key revocation. + + +*--remove-key* _KEY_:: +Remove the specified key. + ++ +If a primary key is specified, then all of its subkeys are also removed. + ++ +If the specified key is a secret key, then it will not be deleted without +confirmation. ++ +Additional options: + +*--force*::: +Forces removal of a secret key without prompting the user. + +*--edit-key* _KEY_:: +Edit or update information, associated with a key. Should be accompanied with editing option. + ++ +Currently the following options are available: + ++ +*--add-subkey*::: +Generate and add a new subkey to the existing primary key. All additional options for the +*--generate-key* command apply for subkey generation as well, except *--userid*. + +*--check-cv25519-bits*::: +Check whether least significant/most significant bits of Curve25519 ECDH subkey are correctly set. +RNP internally sets those bits to required values (3 least significant bits and most significant bit must be zero) during decryption, +however other implementations (GnuPG) may require those bits to be set in key material. +_KEY_ must specify the exact subkey via keyid or fingerprint. + +*--fix-cv25519-bits*::: +Set least significant/most significant bits of Curve25519 ECDH subkey to the correct values, and save a key. +So later export of the key would ensure compatibility with other implementations (like GnuPG). +This operation would require the password for your secret key. +Since version 0.16.0 of RNP generated secret key is stored with bits set to a needed value, +however, this may be needed to fix older keys or keys generated by other implementations. +_KEY_ must specify the exact subkey via keyid or fingerprint. + +*--set-expire* _TIME_::: +Set key expiration time. See the description of the *--expiration* option for possible time formats. +Setting argument to 0 removes key expiration, the key would never expire. It is not recommended +due to security reasons. + +=== OPTIONS + +*--homedir* _DIR_:: +Change homedir (where RNP looks for keyrings) to the specified value. + ++ +The default homedir is _~/.rnp_ . + +*--output* _PATH_:: +Write data processing related output to the file specified. + ++ +Combine it with *--overwrite* to overwrite file if it already exists. + +*--overwrite*:: +Overwrite output file if it already exists. + ++ + +*--userid* _USERID_:: +Use the specified _userid_ during key generation and in some +key-searching operations. + +*--numbits* _BITS_:: +Specify size in bits for the generated key and subkey. + ++ +_bits_ may be in range *1024*-*16384*, as long as the public key algorithm +does not place additional limits. + +*--cipher* _ALGORITHM_:: +Set the key encryption algorithm. This is only used in key generation. + ++ +The default value is _AES256_. + +*--hash* _ALGORITHM_:: +Use the specified hash algorithm for signatures and derivation of the encrypting key from password for secret key encryption. + ++ +The default value is _SHA256_. + +*--expert*:: +Use the *expert key generation* mode, allowing the selection of +key/subkey algorithms. + ++ +The following types of keys can be generated in this mode: + ++ +-- +** *DSA* key with *ElGamal* encryption subkey +** *DSA* key with *RSA* subkey +** *ECDSA* key with *ECDH* subkey +** *EdDSA* key with *x25519* subkey +** *SM2* key with subkey +-- ++ +Specifically, for *ECDSA* and *ECDH* the underlying curve can also be specified: + ++ +-- +** _NIST P-256_, _NIST P-384_, _NIST P-521_ +** _brainpoolP256r1_, _brainpoolP384r1_, _brainpoolP512r1_ +** _secp256k1_ +-- + +*--pass-fd* _FD_:: +Specify a file descriptor to read passwords from instead of from _stdin_/_tty_. + ++ +Useful for automated or non-interactive sessions. + +*--password* _PASSWORD_:: +Use the specified password when it is needed. + ++ +WARNING: Not recommended for production use due to potential security issues. +Use *--pass-fd* for batch operations instead. + +*--with-sigs*:: +Print signature information when listing keys via the *-l* command. + +*--force*:: +Force actions to happen without prompting the user. + ++ +This applies to cases such as secret key removal, revoking an already revoked key and so on. + +*--permissive*:: +Skip malformed or unknown keys/signatures during key import. + ++ +By default, *rnpkeys* will stop on the first erroring packet +and exit with an error. + +*--rev-type* _TYPE_:: +Use the specified type during revocation signature generation instead of the default _0_. + ++ +The following values are supported: + ++ +-- +** 0, or "no": no revocation type specified. +** 1, or "superseded": key was superseded with another key. +** 2, or "compromised": key was compromised and no longer valid. +** 3, or "retired": key is retired. +-- ++ +Please refer to *IETF RFC 4880* for details. + +*--rev-reason* _REASON_:: +Add the specified human-readable revocation _REASON_ to the +signature instead of an empty string. + +*--s2k-iterations* _NUMBER_:: +Specify the number of iterations for the S2K (string-to-key) process. + ++ +This is used during the derivation of the symmetric key, which +encrypts a secret key from the password. + ++ +Please refer to IETF RFC 4880 for further details. + +*--s2k-msec* _NUMBER_:: +Specify that *rnpkeys* should automatically pick a +*--s2k-iterations* value such that the single key derivation operation +would take _NUMBER_ of milliseconds on the current system. + ++ +For example, setting it to _2000_ would mean that each secret key +decryption operation would take around 2 seconds (on the current machine). + +*--notty*:: +Disable use of tty. + ++ +By default RNP would detect whether TTY is attached and use it for user prompts. + ++ +This option overrides default behaviour so user input may be passed in batch mode. + +*--current-time* _TIME_:: +Override system's time with a specified value. + ++ +By default RNP uses system's time in all signature/key checks, however in some scenarios it could be needed to override this. + ++ +*TIME* could be specified in the ISO 8601-1:2019 date format (_yyyy-mm-dd_), or in the UNIX timestamp format. + +== EXIT STATUS + +_0_:: + Success. + +_Non-zero_:: + Failure. + +== EXAMPLES + +The following examples demonstrate method of usage of the _rnpkeys_ command. + +=== EXAMPLE 1: IMPORT EXISTING KEYS FROM THE GNUPG + +Following oneliner may be used to import all public keys from the GnuPG: + +*gpg* *-a* *--export* | *rnpkeys* *--import* _-_ + +To import all secret keys the following command should be used (please note, that you'll be asked for secret key password(s)): + +*gpg* *-a* *--export-secret-keys* | *rnpkeys* *--import* _-_ + +=== EXAMPLE 2: GENERATE A NEW KEY + +This example generates a new key with specified userid and expiration. +Also it enables "expert" mode, allowing the selection of key/subkey algorithms. + +*rnpkeys* *--generate* *--userid* *"john@doe.com"* *--expert* *--expiration* *1y* + +== BUGS + +Please report _issues_ via the RNP public issue tracker at: +https://github.com/rnpgp/rnp/issues. + +_Security reports_ or _security-sensitive feedback_ should be reported +according to the instructions at: +https://www.rnpgp.org/feedback. + + +== AUTHORS + +*RNP* is an open source project led by Ribose and has +received contributions from numerous individuals and +organizations. + + +== RESOURCES + +*Web site*: https://www.rnpgp.org + +*Source repository*: https://github.com/rnpgp/rnp + + +== COPYING + +Copyright \(C) 2017-2021 Ribose. +The RNP software suite is _freely licensed_: +please refer to the *LICENSE* file for details. + + + +== SEE ALSO + +*rnp(1)*, *librnp(3)* diff --git a/comm/third_party/rnp/src/rnpkeys/rnpkeys.cpp b/comm/third_party/rnp/src/rnpkeys/rnpkeys.cpp new file mode 100644 index 0000000000..1a6997c288 --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/rnpkeys.cpp @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2017-2021, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* Command line program to perform rnp operations */ + +#ifdef _MSC_VER +#include "uniwin.h" +#else +#include +#endif +#include +#include +#include "rnpkeys.h" +#include "str-utils.h" +#include + +const char *usage = + "Manipulate OpenPGP keys and keyrings.\n" + "Usage: rnpkeys --command [options] [files]\n" + "Commands:\n" + " -h, --help This help message.\n" + " -V, --version Print RNP version information.\n" + " -g, --generate-key Generate a new keypair (default is RSA).\n" + " --userid Specify key's userid.\n" + " --expert Select key type, size, and additional parameters.\n" + " --numbits Override default key size (2048).\n" + " --expiration Set key and subkey expiration time.\n" + " --cipher Set cipher used to encrypt a secret key.\n" + " --hash Set hash which is used for key derivation.\n" + " --allow-weak-hash Allow usage of a weak hash algorithm.\n" + " -l, --list-keys List keys in the keyrings.\n" + " --secret List secret keys instead of public ones.\n" + " --with-sigs List signatures as well.\n" + " --import Import keys or signatures.\n" + " --import-keys Import keys.\n" + " --import-sigs Import signatures.\n" + " --permissive Skip erroring keys/sigs instead of failing.\n" + " --export-key Export a key.\n" + " --secret Export a secret key instead of a public.\n" + " --export-rev Export a key's revocation.\n" + " --rev-type Set revocation type.\n" + " --rev-reason Human-readable reason for revocation.\n" + " --revoke-key Revoke a key specified.\n" + " --remove-key Remove a key specified.\n" + " --edit-key Edit key properties.\n" + " --add-subkey Add new subkey.\n" + " --check-cv25519-bits Check whether Cv25519 subkey bits are correct.\n" + " --fix-cv25519-bits Fix Cv25519 subkey bits.\n" + " --set-expire Set key expiration time.\n" + "\n" + "Other options:\n" + " --homedir Override home directory (default is ~/.rnp/).\n" + " --password Password, which should be used during operation.\n" + " --pass-fd Read password(s) from the file descriptor.\n" + " --force Force operation (like secret key removal).\n" + " --output [file, -] Write data to the specified file or stdout.\n" + " --overwrite Overwrite output file without a prompt.\n" + " --notty Do not write anything to the TTY.\n" + " --current-time Override system's time.\n" + "\n" + "See man page for a detailed listing and explanation.\n" + "\n"; + +struct option options[] = { + /* key-management commands */ + {"list-keys", no_argument, NULL, CMD_LIST_KEYS}, + {"export", no_argument, NULL, CMD_EXPORT_KEY}, + {"export-key", optional_argument, NULL, CMD_EXPORT_KEY}, + {"import", no_argument, NULL, CMD_IMPORT}, + {"import-key", no_argument, NULL, CMD_IMPORT_KEYS}, + {"import-keys", no_argument, NULL, CMD_IMPORT_KEYS}, + {"import-sigs", no_argument, NULL, CMD_IMPORT_SIGS}, + {"gen", optional_argument, NULL, CMD_GENERATE_KEY}, + {"gen-key", optional_argument, NULL, CMD_GENERATE_KEY}, + {"generate", optional_argument, NULL, CMD_GENERATE_KEY}, + {"generate-key", optional_argument, NULL, CMD_GENERATE_KEY}, + {"export-rev", no_argument, NULL, CMD_EXPORT_REV}, + {"export-revocation", no_argument, NULL, CMD_EXPORT_REV}, + {"revoke-key", no_argument, NULL, CMD_REVOKE_KEY}, + {"remove-key", no_argument, NULL, CMD_REMOVE_KEY}, + {"edit-key", no_argument, NULL, CMD_EDIT_KEY}, + /* debugging commands */ + {"help", no_argument, NULL, CMD_HELP}, + {"version", no_argument, NULL, CMD_VERSION}, + {"debug", required_argument, NULL, OPT_DEBUG}, + /* options */ + {"coredumps", no_argument, NULL, OPT_COREDUMPS}, + {"keystore-format", required_argument, NULL, OPT_KEY_STORE_FORMAT}, + {"userid", required_argument, NULL, OPT_USERID}, + {"with-sigs", no_argument, NULL, OPT_WITH_SIGS}, + {"hash", required_argument, NULL, OPT_HASH_ALG}, + {"home", required_argument, NULL, OPT_HOMEDIR}, + {"homedir", required_argument, NULL, OPT_HOMEDIR}, + {"numbits", required_argument, NULL, OPT_NUMBITS}, + {"s2k-iterations", required_argument, NULL, OPT_S2K_ITER}, + {"s2k-msec", required_argument, NULL, OPT_S2K_MSEC}, + {"expiration", required_argument, NULL, OPT_EXPIRATION}, + {"pass-fd", required_argument, NULL, OPT_PASSWDFD}, + {"password", required_argument, NULL, OPT_PASSWD}, + {"results", required_argument, NULL, OPT_RESULTS}, + {"cipher", required_argument, NULL, OPT_CIPHER}, + {"expert", no_argument, NULL, OPT_EXPERT}, + {"output", required_argument, NULL, OPT_OUTPUT}, + {"overwrite", no_argument, NULL, OPT_OVERWRITE}, + {"force", no_argument, NULL, OPT_FORCE}, + {"secret", no_argument, NULL, OPT_SECRET}, + {"rev-type", required_argument, NULL, OPT_REV_TYPE}, + {"rev-reason", required_argument, NULL, OPT_REV_REASON}, + {"permissive", no_argument, NULL, OPT_PERMISSIVE}, + {"notty", no_argument, NULL, OPT_NOTTY}, + {"fix-cv25519-bits", no_argument, NULL, OPT_FIX_25519_BITS}, + {"check-cv25519-bits", no_argument, NULL, OPT_CHK_25519_BITS}, + {"add-subkey", no_argument, NULL, OPT_ADD_SUBKEY}, + {"set-expire", required_argument, NULL, OPT_SET_EXPIRE}, + {"current-time", required_argument, NULL, OPT_CURTIME}, + {"allow-weak-hash", no_argument, NULL, OPT_ALLOW_WEAK_HASH}, + {NULL, 0, NULL, 0}, +}; + +/* list keys */ +static bool +print_keys_info(cli_rnp_t *rnp, FILE *fp, const char *filter) +{ + bool psecret = rnp->cfg().get_bool(CFG_SECRET); + bool psigs = rnp->cfg().get_bool(CFG_WITH_SIGS); + int flags = CLI_SEARCH_SUBKEYS_AFTER | (psecret ? CLI_SEARCH_SECRET : 0); + std::vector keys; + + if (!cli_rnp_keys_matching_string(rnp, keys, filter ? filter : "", flags)) { + fprintf(fp, "Key(s) not found.\n"); + return false; + } + fprintf(fp, "%d key%s found\n", (int) keys.size(), (keys.size() == 1) ? "" : "s"); + for (auto key : keys) { + cli_rnp_print_key_info(fp, rnp->ffi, key, psecret, psigs); + } + + fprintf(fp, "\n"); + /* clean up */ + clear_key_handles(keys); + return true; +} + +static bool +import_keys(cli_rnp_t *rnp, rnp_input_t input, const std::string &inname) +{ + std::set new_pub_keys; + std::set new_sec_keys; + std::set updated_keys; + bool res = false; + bool updated = false; + size_t unchanged_keys = 0; + size_t processed_keys = 0; + + uint32_t flags = RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS | + RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64; + + bool permissive = rnp->cfg().get_bool(CFG_PERMISSIVE); + if (permissive) { + flags |= RNP_LOAD_SAVE_PERMISSIVE; + } + + do { + /* load keys one-by-one */ + char * results = NULL; + rnp_result_t ret = rnp_import_keys(rnp->ffi, input, flags, &results); + if (ret == RNP_ERROR_EOF) { + res = true; + break; + } + if (ret && updated) { + /* some keys were imported, but then error occurred */ + ERR_MSG("warning: not all data was processed."); + res = true; + break; + } + if (ret) { + ERR_MSG("failed to import key(s) from %s, stopping.", inname.c_str()); + break; + } + + // print information about imported key(s) + json_object *jso = json_tokener_parse(results); + rnp_buffer_destroy(results); + if (!jso) { + ERR_MSG("invalid key import resulting JSON"); + break; + } + json_object *keys = NULL; + if (!json_object_object_get_ex(jso, "keys", &keys)) { + ERR_MSG("invalid key import JSON contents"); + json_object_put(jso); + break; + } + processed_keys += json_object_array_length(keys); + for (size_t idx = 0; idx < (size_t) json_object_array_length(keys); idx++) { + json_object * keyinfo = json_object_array_get_idx(keys, idx); + rnp_key_handle_t key = NULL; + if (!keyinfo) { + continue; + } + std::string pub_status = json_obj_get_str(keyinfo, "public"); + std::string sec_status = json_obj_get_str(keyinfo, "secret"); + const char *fphex = json_obj_get_str(keyinfo, "fingerprint"); + + if (pub_status == "new") { + new_pub_keys.insert(fphex); + updated = true; + } + if (sec_status == "new") { + new_sec_keys.insert(fphex); + updated = true; + } + if (pub_status == "updated" || sec_status == "updated") { + updated_keys.insert(fphex); + updated = true; + } + if (pub_status == "unchanged" || sec_status == "unchanged") { + if (!new_pub_keys.count(fphex) && !new_sec_keys.count(fphex) && + !updated_keys.count(fphex)) { + unchanged_keys++; + continue; + } + } + if (rnp_locate_key(rnp->ffi, "fingerprint", fphex, &key) || !key) { + ERR_MSG("failed to locate key with fingerprint %s", fphex); + continue; + } + cli_rnp_print_key_info(stdout, rnp->ffi, key, true, false); + rnp_key_handle_destroy(key); + } + json_object_put(jso); + } while (1); + + // print statistics + ERR_MSG("Import finished: %lu key%s processed, %lu new public keys, %lu new secret keys, " + "%lu updated, %lu unchanged.", + processed_keys, + (processed_keys != 1) ? "s" : "", + new_pub_keys.size(), + new_sec_keys.size(), + updated_keys.size(), + unchanged_keys); + + if (updated) { + // set default key if we didn't have one + if (rnp->defkey().empty()) { + rnp->set_defkey(); + } + + // save public and secret keyrings + if (!cli_rnp_save_keyrings(rnp)) { + ERR_MSG("failed to save keyrings"); + } + } + return res; +} + +static bool +import_sigs(cli_rnp_t *rnp, rnp_input_t input, const std::string &inname) +{ + bool res = false; + char * results = NULL; + json_object *jso = NULL; + json_object *sigs = NULL; + int unknown_sigs = 0; + int new_sigs = 0; + int old_sigs = 0; + + if (rnp_import_signatures(rnp->ffi, input, 0, &results)) { + ERR_MSG("Failed to import signatures from %s", inname.c_str()); + goto done; + } + // print information about imported signature(s) + jso = json_tokener_parse(results); + if (!jso || !json_object_object_get_ex(jso, "sigs", &sigs)) { + ERR_MSG("Invalid signature import result"); + goto done; + } + + for (size_t idx = 0; idx < (size_t) json_object_array_length(sigs); idx++) { + json_object *siginfo = json_object_array_get_idx(sigs, idx); + if (!siginfo) { + continue; + } + const char *status = json_obj_get_str(siginfo, "public"); + std::string pub_status = status ? status : "unknown"; + status = json_obj_get_str(siginfo, "secret"); + std::string sec_status = status ? status : "unknown"; + + if ((pub_status == "new") || (sec_status == "new")) { + new_sigs++; + } else if ((pub_status == "unchanged") || (sec_status == "unchanged")) { + old_sigs++; + } else { + unknown_sigs++; + } + } + + // print status information + ERR_MSG("Import finished: %d new signature%s, %d unchanged, %d unknown.", + new_sigs, + (new_sigs != 1) ? "s" : "", + old_sigs, + unknown_sigs); + + // save public and secret keyrings + if ((new_sigs > 0) && !cli_rnp_save_keyrings(rnp)) { + ERR_MSG("Failed to save keyrings"); + goto done; + } + res = true; +done: + json_object_put(jso); + rnp_buffer_destroy(results); + return res; +} + +static bool +import(cli_rnp_t *rnp, const std::string &spec, int cmd) +{ + if (spec.empty()) { + ERR_MSG("Import path isn't specified"); + return false; + } + rnp_input_t input = cli_rnp_input_from_specifier(*rnp, spec, NULL); + if (!input) { + ERR_MSG("Failed to create input for %s", spec.c_str()); + return false; + } + if (cmd == CMD_IMPORT) { + char *contents = NULL; + if (rnp_guess_contents(input, &contents)) { + ERR_MSG("Warning! Failed to guess content type to import. Assuming keys."); + } + cmd = (contents && !strcmp(contents, "signature")) ? CMD_IMPORT_SIGS : CMD_IMPORT_KEYS; + rnp_buffer_destroy(contents); + } + + bool res = false; + switch (cmd) { + case CMD_IMPORT_KEYS: + res = import_keys(rnp, input, spec); + break; + case CMD_IMPORT_SIGS: + res = import_sigs(rnp, input, spec); + break; + default: + ERR_MSG("Unexpected command: %d", cmd); + } + rnp_input_destroy(input); + return res; +} + +/* print a usage message */ +void +print_usage(const char *usagemsg) +{ + cli_rnp_print_praise(); + puts(usagemsg); +} + +/* do a command once for a specified file 'f' */ +bool +rnp_cmd(cli_rnp_t *rnp, optdefs_t cmd, const char *f) +{ + std::string fs; + + switch (cmd) { + case CMD_LIST_KEYS: + if (!f && rnp->cfg().get_count(CFG_USERID)) { + fs = rnp->cfg().get_str(CFG_USERID, 0); + f = fs.c_str(); + } + return print_keys_info(rnp, stdout, f); + case CMD_EXPORT_KEY: { + if (!f && rnp->cfg().get_count(CFG_USERID)) { + fs = rnp->cfg().get_str(CFG_USERID, 0); + f = fs.c_str(); + } + if (!f) { + ERR_MSG("No key specified."); + return 0; + } + return cli_rnp_export_keys(rnp, f); + } + case CMD_IMPORT: + case CMD_IMPORT_KEYS: + case CMD_IMPORT_SIGS: + return import(rnp, f ? f : "", cmd); + case CMD_GENERATE_KEY: { + if (!f) { + size_t count = rnp->cfg().get_count(CFG_USERID); + if (count == 1) { + fs = rnp->cfg().get_str(CFG_USERID, 0); + f = fs.c_str(); + } else if (count > 1) { + ERR_MSG("Only single userid is supported for generated keys"); + return false; + } + } + return cli_rnp_generate_key(rnp, f); + } + case CMD_EXPORT_REV: { + if (!f) { + ERR_MSG("You need to specify key to generate revocation for."); + return false; + } + return cli_rnp_export_revocation(rnp, f); + } + case CMD_REVOKE_KEY: { + if (!f) { + ERR_MSG("You need to specify key or subkey to revoke."); + return false; + } + return cli_rnp_revoke_key(rnp, f); + } + case CMD_REMOVE_KEY: { + if (!f) { + ERR_MSG("You need to specify key or subkey to remove."); + return false; + } + return cli_rnp_remove_key(rnp, f); + } + case CMD_EDIT_KEY: { + if (!f) { + ERR_MSG("You need to specify a key or subkey to edit."); + return false; + } + return rnp->edit_key(f); + } + case CMD_VERSION: + cli_rnp_print_praise(); + return true; + case CMD_HELP: + default: + print_usage(usage); + return true; + } +} + +/* set the option */ +bool +setoption(rnp_cfg &cfg, optdefs_t *cmd, int val, const char *arg) +{ + switch (val) { + case OPT_COREDUMPS: +#ifdef _WIN32 + ERR_MSG("warning: --coredumps doesn't make sense on windows systems."); +#endif + cfg.set_bool(CFG_COREDUMPS, true); + return true; + case CMD_GENERATE_KEY: + cfg.set_bool(CFG_NEEDSSECKEY, true); + *cmd = (optdefs_t) val; + return true; + case OPT_EXPERT: + cfg.set_bool(CFG_EXPERT, true); + return true; + case CMD_LIST_KEYS: + case CMD_EXPORT_KEY: + case CMD_EXPORT_REV: + case CMD_REVOKE_KEY: + case CMD_REMOVE_KEY: + case CMD_EDIT_KEY: + case CMD_IMPORT: + case CMD_IMPORT_KEYS: + case CMD_IMPORT_SIGS: + case CMD_HELP: + case CMD_VERSION: + *cmd = (optdefs_t) val; + return true; + /* options */ + case OPT_KEY_STORE_FORMAT: + cfg.set_str(CFG_KEYSTOREFMT, arg); + return true; + case OPT_USERID: + cfg.add_str(CFG_USERID, arg); + return true; + case OPT_HOMEDIR: + cfg.set_str(CFG_HOMEDIR, arg); + return true; + case OPT_NUMBITS: { + int bits = 0; + if (!rnp::str_to_int(arg, bits) || (bits < 1024) || (bits > 16384)) { + ERR_MSG("wrong bits value: %s", arg); + return false; + } + cfg.set_int(CFG_NUMBITS, bits); + return true; + } + case OPT_ALLOW_WEAK_HASH: + cfg.set_bool(CFG_WEAK_HASH, true); + return true; + case OPT_HASH_ALG: + return cli_rnp_set_hash(cfg, arg); + case OPT_S2K_ITER: { + int iterations = atoi(arg); + if (!iterations) { + ERR_MSG("Wrong iterations value: %s", arg); + return false; + } + cfg.set_int(CFG_S2K_ITER, iterations); + return true; + } + case OPT_EXPIRATION: + cfg.set_str(CFG_KG_PRIMARY_EXPIRATION, arg); + cfg.set_str(CFG_KG_SUBKEY_EXPIRATION, arg); + return true; + case OPT_S2K_MSEC: { + int msec = 0; + if (!rnp::str_to_int(arg, msec) || !msec) { + ERR_MSG("Invalid s2k msec value: %s", arg); + return false; + } + cfg.set_int(CFG_S2K_MSEC, msec); + return true; + } + case OPT_PASSWDFD: + cfg.set_str(CFG_PASSFD, arg); + return true; + case OPT_PASSWD: + cfg.set_str(CFG_PASSWD, arg); + return true; + case OPT_RESULTS: + cfg.set_str(CFG_IO_RESS, arg); + return true; + case OPT_CIPHER: + return cli_rnp_set_cipher(cfg, arg); + case OPT_DEBUG: + ERR_MSG("Option --debug is deprecated, ignoring."); + return true; + case OPT_OUTPUT: + if (!arg) { + ERR_MSG("No output filename argument provided"); + return false; + } + cfg.set_str(CFG_OUTFILE, arg); + return true; + case OPT_OVERWRITE: + cfg.set_bool(CFG_OVERWRITE, true); + return true; + case OPT_FORCE: + cfg.set_bool(CFG_FORCE, true); + return true; + case OPT_SECRET: + cfg.set_bool(CFG_SECRET, true); + return true; + case OPT_WITH_SIGS: + cfg.set_bool(CFG_WITH_SIGS, true); + return true; + case OPT_REV_TYPE: { + std::string revtype = arg; + if (revtype == "0") { + revtype = "no"; + } else if (revtype == "1") { + revtype = "superseded"; + } else if (revtype == "2") { + revtype = "compromised"; + } else if (revtype == "3") { + revtype = "retired"; + } + cfg.set_str(CFG_REV_TYPE, revtype); + return true; + } + case OPT_REV_REASON: + cfg.set_str(CFG_REV_REASON, arg); + return true; + case OPT_PERMISSIVE: + cfg.set_bool(CFG_PERMISSIVE, true); + return true; + case OPT_NOTTY: + cfg.set_bool(CFG_NOTTY, true); + return true; + case OPT_FIX_25519_BITS: + cfg.set_bool(CFG_FIX_25519_BITS, true); + return true; + case OPT_CHK_25519_BITS: + cfg.set_bool(CFG_CHK_25519_BITS, true); + return true; + case OPT_CURTIME: + cfg.set_str(CFG_CURTIME, arg); + return true; + case OPT_ADD_SUBKEY: + cfg.set_bool(CFG_ADD_SUBKEY, true); + return true; + case OPT_SET_EXPIRE: + cfg.set_str(CFG_SET_KEY_EXPIRE, arg); + return true; + default: + *cmd = CMD_HELP; + return true; + } +} + +bool +rnpkeys_init(cli_rnp_t &rnp, const rnp_cfg &cfg) +{ + rnp_cfg rnpcfg; + rnpcfg.load_defaults(); + rnpcfg.set_int(CFG_NUMBITS, DEFAULT_RSA_NUMBITS); + rnpcfg.set_str(CFG_IO_RESS, ""); + rnpcfg.copy(cfg); + + if (!cli_cfg_set_keystore_info(rnpcfg)) { + ERR_MSG("fatal: cannot set keystore info"); + return false; + } + if (!rnp.init(rnpcfg)) { + ERR_MSG("fatal: failed to initialize rnpkeys"); + return false; + } + if (!cli_rnp_check_weak_hash(&rnp)) { + ERR_MSG("Weak hash algorithm detected. Pass --allow-weak-hash option if you really " + "want to use it."); + return false; + } + /* TODO: at some point we should check for error here */ + (void) rnp.load_keyrings(true); + return true; +} diff --git a/comm/third_party/rnp/src/rnpkeys/rnpkeys.h b/comm/third_party/rnp/src/rnpkeys/rnpkeys.h new file mode 100644 index 0000000000..611fcc10e7 --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/rnpkeys.h @@ -0,0 +1,80 @@ +#ifndef RNPKEYS_H_ +#define RNPKEYS_H_ + +#include +#ifdef HAVE_SYS_PARAM_H +#include +#else +#include "uniwin.h" +#endif +#include "../rnp/fficli.h" +#include "logging.h" + +#define DEFAULT_RSA_NUMBITS 2048 + +typedef enum { + /* commands */ + CMD_NONE = 0, + CMD_LIST_KEYS = 260, + CMD_EXPORT_KEY, + CMD_IMPORT, + CMD_IMPORT_KEYS, + CMD_IMPORT_SIGS, + CMD_GENERATE_KEY, + CMD_EXPORT_REV, + CMD_REVOKE_KEY, + CMD_REMOVE_KEY, + CMD_EDIT_KEY, + CMD_VERSION, + CMD_HELP, + + /* options */ + OPT_KEY_STORE_FORMAT, + OPT_USERID, + OPT_HOMEDIR, + OPT_NUMBITS, + OPT_ALLOW_WEAK_HASH, + OPT_HASH_ALG, + OPT_COREDUMPS, + OPT_PASSWDFD, + OPT_PASSWD, + OPT_RESULTS, + OPT_CIPHER, + OPT_EXPERT, + OPT_OUTPUT, + OPT_OVERWRITE, + OPT_FORCE, + OPT_SECRET, + OPT_S2K_ITER, + OPT_S2K_MSEC, + OPT_EXPIRATION, + OPT_WITH_SIGS, + OPT_REV_TYPE, + OPT_REV_REASON, + OPT_PERMISSIVE, + OPT_NOTTY, + OPT_FIX_25519_BITS, + OPT_CHK_25519_BITS, + OPT_CURTIME, + OPT_ADD_SUBKEY, + OPT_SET_EXPIRE, + + /* debug */ + OPT_DEBUG +} optdefs_t; + +bool rnp_cmd(cli_rnp_t *rnp, optdefs_t cmd, const char *f); +bool setoption(rnp_cfg &cfg, optdefs_t *cmd, int val, const char *arg); +void print_usage(const char *usagemsg); + +/** + * @brief Initializes rnpkeys. Function allocates memory dynamically for + * rnp argument, which must be freed by the caller. + * + * @param rnp initialized rnp context + * @param cfg configuration with settings from command line + * @return true on success, or false otherwise. + */ +bool rnpkeys_init(cli_rnp_t &rnp, const rnp_cfg &cfg); + +#endif /* _rnpkeys_ */ diff --git a/comm/third_party/rnp/src/rnpkeys/tui.cpp b/comm/third_party/rnp/src/rnpkeys/tui.cpp new file mode 100644 index 0000000000..73f26dc2d1 --- /dev/null +++ b/comm/third_party/rnp/src/rnpkeys/tui.cpp @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifdef _MSC_VER +#include "uniwin.h" +#else +#include +#endif +#include +#include +#include "rnp/rnpcfg.h" +#include "rnpkeys.h" +#include "defaults.h" +#include "file-utils.h" +#include "logging.h" + +/* ----------------------------------------------------------------------------- + * @brief Reads input from file pointer and converts it securelly to ints + * Partially based on ERR34-C from SEI CERT C Coding Standard + * + * @param fp pointer to opened pipe + * @param result[out] result read from file pointer and converted to int + * + * @returns true and value in result if integer was parsed correctly, + * otherwise false + * +-------------------------------------------------------------------------------- */ +static bool +rnp_secure_get_long_from_fd(FILE *fp, long &result, bool allow_empty = true) +{ + char buff[BUFSIZ]; + if (!fgets(buff, sizeof(buff), fp)) { + RNP_LOG("EOF or read error"); + return false; + } + + errno = 0; + char *end_ptr = NULL; + long num_long = strtol(buff, &end_ptr, 10); + if (ERANGE == errno) { + RNP_LOG("Number out of range"); + return false; + } + if (end_ptr == buff) { + return allow_empty; + } + if ('\n' != *end_ptr && '\0' != *end_ptr) { + RNP_LOG("Unexpected end of line"); + return false; + } + + result = num_long; + return true; +} + +static bool +is_rsa_keysize_supported(uint32_t keysize) +{ + return ((keysize >= 1024) && (keysize <= 4096) && !(keysize % 8)); +} + +static const char * +ask_curve_name(FILE *input_fp) +{ + std::vector curves; + static const char *const known_curves[] = { + "NIST P-256", + "NIST P-384", + "NIST P-521", + "brainpoolP256r1", + "brainpoolP384r1", + "brainpoolP512r1", + "secp256k1", + }; + const size_t curvenum = sizeof(known_curves) / sizeof(*known_curves); + + try { + std::copy_if(known_curves, + known_curves + curvenum, + std::back_inserter(curves), + [](const char *curve) { + bool supported = false; + return !rnp_supports_feature(RNP_FEATURE_CURVE, curve, &supported) && + supported; + }); + } catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return NULL; + } + const size_t ccount = curves.size(); + if (!ccount) { + return NULL; + } + bool ok = false; + const char *result = NULL; + int attempts = 0; + do { + if (attempts >= 10) { + printf("Too many attempts. Aborting.\n"); + return NULL; + } + printf("Please select which elliptic curve you want:\n"); + for (size_t i = 0; i < ccount; i++) { + printf("\t(%zu) %s\n", i + 1, curves[i]); + } + printf("(default %s)> ", DEFAULT_CURVE); + long val = 0; + ok = rnp_secure_get_long_from_fd(input_fp, val) && (val > 0) && (val <= (long) ccount); + if (ok) { + result = curves[val - 1]; + } + attempts++; + } while (!ok); + + return result; +} + +static long +ask_rsa_bitlen(FILE *input_fp) +{ + long result = 0; + do { + result = DEFAULT_RSA_NUMBITS; + printf("Please provide bit length of the key (between 1024 and 4096):\n(default %d)> ", + DEFAULT_RSA_NUMBITS); + } while (!rnp_secure_get_long_from_fd(input_fp, result) || + !is_rsa_keysize_supported(result)); + return result; +} + +static long +ask_elgamal_bitlen(FILE *input_fp) +{ + do { + printf( + "Please provide bit length of the ElGamal key (between %d and %d):\n(default %d) > ", + ELGAMAL_MIN_P_BITLEN, + ELGAMAL_MAX_P_BITLEN, + DEFAULT_ELGAMAL_NUMBITS); + long result = DEFAULT_ELGAMAL_NUMBITS; + if (!rnp_secure_get_long_from_fd(input_fp, result)) { + continue; + } + if ((result >= ELGAMAL_MIN_P_BITLEN) && (result <= ELGAMAL_MAX_P_BITLEN)) { + // round up to multiple of 32 + result = ((result + 31) / 32) * 32; + printf("Bitlen of the key will be %lu\n", result); + return result; + } + } while (1); +} + +static long +ask_dsa_bitlen(FILE *input_fp) +{ + do { + printf( + "Please provide bit length of the DSA key (between %d and %d):\n(default %d) > ", + DSA_MIN_P_BITLEN, + DSA_MAX_P_BITLEN, + DSA_DEFAULT_P_BITLEN); + long result = DSA_DEFAULT_P_BITLEN; + if (!rnp_secure_get_long_from_fd(input_fp, result)) { + continue; + } + if ((result >= DSA_MIN_P_BITLEN) && (result <= DSA_MAX_P_BITLEN)) { + // round up to multiple of 64 + result = ((result + 63) / 64) * 64; + printf("Bitlen of the key will be %lu\n", result); + return result; + } + } while (1); +} + +static bool +rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) +{ + long option = 0; + do { + printf("Please select what kind of key you want:\n" + "\t(1) RSA (Encrypt or Sign)\n" + "\t(16) DSA + ElGamal\n" + "\t(17) DSA + RSA\n" // TODO: See #584 + "\t(19) ECDSA + ECDH\n" + "\t(22) EDDSA + X25519\n" + "\t(99) SM2\n" + "> "); + if (!rnp_secure_get_long_from_fd(input_fp, option, false)) { + option = 0; + continue; + } + switch (option) { + case 1: { + int bits = ask_rsa_bitlen(input_fp); + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_RSA); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_RSA); + cfg.set_int(CFG_KG_PRIMARY_BITS, bits); + cfg.set_int(CFG_KG_SUBKEY_BITS, bits); + break; + } + case 16: { + int bits = ask_dsa_bitlen(input_fp); + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DSA); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ELGAMAL); + cfg.set_int(CFG_KG_PRIMARY_BITS, bits); + cfg.set_int(CFG_KG_SUBKEY_BITS, bits); + break; + } + case 17: { + int bits = ask_dsa_bitlen(input_fp); + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DSA); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_RSA); + cfg.set_int(CFG_KG_PRIMARY_BITS, bits); + cfg.set_int(CFG_KG_SUBKEY_BITS, bits); + break; + } + case 19: { + const char *curve = ask_curve_name(input_fp); + if (!curve) { + return false; + } + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_ECDSA); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ECDH); + cfg.set_str(CFG_KG_PRIMARY_CURVE, curve); + cfg.set_str(CFG_KG_SUBKEY_CURVE, curve); + break; + } + case 22: { + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_EDDSA); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ECDH); + cfg.set_str(CFG_KG_SUBKEY_CURVE, "Curve25519"); + break; + } + case 99: { + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SM2); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_SM2); + if (!cfg.has(CFG_KG_HASH)) { + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SM3); + } + break; + } + default: + option = 0; + break; + } + } while (!option); + + return true; +} + +static bool +rnpkeys_ask_generate_params_subkey(rnp_cfg &cfg, FILE *input_fp) +{ + long option = 0; + do { + printf("Please select subkey algorithm you want:\n" + "\t(1) RSA\n" + "\t(16) ElGamal\n" + "\t(17) DSA\n" + "\t(18) ECDH\n" + "\t(19) ECDSA\n" + "\t(22) EDDSA\n" + "\t(99) SM2" + "> "); + if (!rnp_secure_get_long_from_fd(input_fp, option, false)) { + option = 0; + continue; + } + switch (option) { + case 1: { + int bits = ask_rsa_bitlen(input_fp); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_RSA); + cfg.set_int(CFG_KG_SUBKEY_BITS, bits); + break; + } + case 16: { + int bits = ask_elgamal_bitlen(input_fp); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ELGAMAL); + cfg.set_int(CFG_KG_SUBKEY_BITS, bits); + break; + } + case 17: { + int bits = ask_dsa_bitlen(input_fp); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_DSA); + cfg.set_int(CFG_KG_SUBKEY_BITS, bits); + break; + } + case 18: { + const char *curve = ask_curve_name(input_fp); + if (!curve) { + return false; + } + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ECDH); + cfg.set_str(CFG_KG_SUBKEY_CURVE, curve); + break; + } + case 19: { + const char *curve = ask_curve_name(input_fp); + if (!curve) { + return false; + } + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ECDSA); + cfg.set_str(CFG_KG_SUBKEY_CURVE, curve); + break; + } + case 22: { + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_EDDSA); + break; + } + case 99: { + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_SM2); + if (!cfg.has(CFG_KG_HASH)) { + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SM3); + } + break; + } + default: + option = 0; + break; + } + } while (!option); + + return true; +} + +bool +cli_rnp_set_generate_params(rnp_cfg &cfg, bool subkey) +{ + bool res = true; + // hash algorithms for signing and protection + if (cfg.has(CFG_HASH)) { + cfg.set_str(CFG_KG_HASH, cfg.get_str(CFG_HASH)); + cfg.set_str(CFG_KG_PROT_HASH, cfg.get_str(CFG_HASH)); + } + + // key and subkey algorithms, bit length/curve + if (!cfg.get_bool(CFG_EXPERT)) { + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_RSA); + cfg.set_int(CFG_KG_PRIMARY_BITS, cfg.get_int(CFG_NUMBITS)); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_RSA); + cfg.set_int(CFG_KG_SUBKEY_BITS, cfg.get_int(CFG_NUMBITS)); + } else { + FILE *input = stdin; + if (cfg.has(CFG_USERINPUTFD)) { + int inputfd = dup(cfg.get_int(CFG_USERINPUTFD)); + if (inputfd != -1) { + input = rnp_fdopen(inputfd, "r"); + if (!input) { + close(inputfd); + } + } + } + if (!input) { + return false; + } + if (subkey) { + res = rnpkeys_ask_generate_params_subkey(cfg, input); + } else { + res = rnpkeys_ask_generate_params(cfg, input); + } + if (input != stdin) { + fclose(input); + } + if (!res) { + return false; + } + } + + // make sure hash algorithms are set + if (!cfg.has(CFG_KG_HASH)) { + cfg.set_str(CFG_KG_HASH, DEFAULT_HASH_ALG); + } + if (!cfg.has(CFG_KG_PROT_HASH)) { + cfg.set_str(CFG_KG_PROT_HASH, DEFAULT_HASH_ALG); + } + + // protection symmetric algorithm + cfg.set_str(CFG_KG_PROT_ALG, + cfg.has(CFG_CIPHER) ? cfg.get_str(CFG_CIPHER) : DEFAULT_SYMM_ALG); + // protection iterations count + size_t iterations = cfg.get_int(CFG_S2K_ITER); + if (!iterations) { + res = res && !rnp_calculate_iterations(cfg.get_str(CFG_KG_PROT_HASH).c_str(), + cfg.get_int(CFG_S2K_MSEC), + &iterations); + } + cfg.set_int(CFG_KG_PROT_ITERATIONS, iterations); + return res; +} diff --git a/comm/third_party/rnp/version.txt b/comm/third_party/rnp/version.txt new file mode 100644 index 0000000000..aa46e4e72a --- /dev/null +++ b/comm/third_party/rnp/version.txt @@ -0,0 +1 @@ +0.17.0+PR2073 diff --git a/comm/third_party/rnpdefs.mozbuild b/comm/third_party/rnpdefs.mozbuild new file mode 100644 index 0000000000..1358f95f18 --- /dev/null +++ b/comm/third_party/rnpdefs.mozbuild @@ -0,0 +1,38 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# We allow warnings for third-party code that can be updated from upstream. +AllowCompilerWarnings() +DisableStlWrapping() +NoVisibilityFlags() + +rnp_dist_info = "{} {} rnp".format( + CONFIG["MOZ_APP_DISPLAYNAME"], CONFIG["MOZ_APP_VERSION_DISPLAY"] +) + +COMPILE_FLAGS["OS_CFLAGS"] = [] +COMPILE_FLAGS["OS_CXXFLAGS"] = [] +COMPILE_FLAGS["OS_INCLUDES"] = [] +COMPILE_FLAGS["CLANG_PLUGIN"] = [] + +if CONFIG["COMPILE_ENVIRONMENT"]: + COMPILE_FLAGS["MOZ_HARDENING_CFLAGS"] = [] + +if CONFIG["CC_TYPE"] == "clang-cl": + CFLAGS += [ + "-Wno-inconsistent-dllimport", + "-Wno-macro-redefined", # 'WIN32_LEAN_AND_MEAN' macro redefined + ] + USE_STATIC_LIBS = True + DEFINES["RNP_USE_STD_REGEX"] = True + +if CONFIG["MOZ_STDCXX_COMPAT"]: + # Use pre-GCC-5 strings abi + DEFINES["_GLIBCXX_USE_CXX11_ABI"] = 0 + +if CONFIG["OS_ARCH"] in ("Linux", "SunOS"): + CFLAGS += ["-fPIC"] + CXXFLAGS += ["-fPIC"] diff --git a/comm/third_party/zlib/ChangeLog b/comm/third_party/zlib/ChangeLog new file mode 100644 index 0000000000..457526bc6a --- /dev/null +++ b/comm/third_party/zlib/ChangeLog @@ -0,0 +1,1590 @@ + + ChangeLog file for zlib + +Changes in 1.2.13 (13 Oct 2022) +- Fix configure issue that discarded provided CC definition +- Correct incorrect inputs provided to the CRC functions +- Repair prototypes and exporting of new CRC functions +- Fix inflateBack to detect invalid input with distances too far +- Have infback() deliver all of the available output up to any error +- Fix a bug when getting a gzip header extra field with inflate() +- Fix bug in block type selection when Z_FIXED used +- Tighten deflateBound bounds +- Remove deleted assembler code references +- Various portability and appearance improvements + +Changes in 1.2.12 (27 Mar 2022) +- Cygwin does not have _wopen(), so do not create gzopen_w() there +- Permit a deflateParams() parameter change as soon as possible +- Limit hash table inserts after switch from stored deflate +- Fix bug when window full in deflate_stored() +- Fix CLEAR_HASH macro to be usable as a single statement +- Avoid a conversion error in gzseek when off_t type too small +- Have Makefile return non-zero error code on test failure +- Avoid some conversion warnings in gzread.c and gzwrite.c +- Update use of errno for newer Windows CE versions +- Small speedup to inflate [psumbera] +- Return an error if the gzputs string length can't fit in an int +- Add address checking in clang to -w option of configure +- Don't compute check value for raw inflate if asked to validate +- Handle case where inflateSync used when header never processed +- Avoid the use of ptrdiff_t +- Avoid an undefined behavior of memcpy() in gzappend() +- Avoid undefined behaviors of memcpy() in gz*printf() +- Avoid an undefined behavior of memcpy() in _tr_stored_block() +- Make the names in functions declarations identical to definitions +- Remove old assembler code in which bugs have manifested +- Fix deflateEnd() to not report an error at start of raw deflate +- Add legal disclaimer to README +- Emphasize the need to continue decompressing gzip members +- Correct the initialization requirements for deflateInit2() +- Fix a bug that can crash deflate on some input when using Z_FIXED +- Assure that the number of bits for deflatePrime() is valid +- Use a structure to make globals in enough.c evident +- Use a macro for the printf format of big_t in enough.c +- Clean up code style in enough.c, update version +- Use inline function instead of macro for index in enough.c +- Clarify that prefix codes are counted in enough.c +- Show all the codes for the maximum tables size in enough.c +- Add gznorm.c example, which normalizes gzip files +- Fix the zran.c example to work on a multiple-member gzip file +- Add tables for crc32_combine(), to speed it up by a factor of 200 +- Add crc32_combine_gen() and crc32_combine_op() for fast combines +- Speed up software CRC-32 computation by a factor of 1.5 to 3 +- Use atomic test and set, if available, for dynamic CRC tables +- Don't bother computing check value after successful inflateSync() +- Correct comment in crc32.c +- Add use of the ARMv8 crc32 instructions when requested +- Use ARM crc32 instructions if the ARM architecture has them +- Explicitly note that the 32-bit check values are 32 bits +- Avoid adding empty gzip member after gzflush with Z_FINISH +- Fix memory leak on error in gzlog.c +- Fix error in comment on the polynomial representation of a byte +- Clarify gz* function interfaces, referring to parameter names +- Change macro name in inflate.c to avoid collision in VxWorks +- Correct typo in blast.c +- Improve portability of contrib/minizip +- Fix indentation in minizip's zip.c +- Replace black/white with allow/block. (theresa-m) +- minizip warning fix if MAXU32 already defined. (gvollant) +- Fix unztell64() in minizip to work past 4GB. (Daniël Hörchner) +- Clean up minizip to reduce warnings for testing +- Add fallthrough comments for gcc +- Eliminate use of ULL constants +- Separate out address sanitizing from warnings in configure +- Remove destructive aspects of make distclean +- Check for cc masquerading as gcc or clang in configure +- Fix crc32.c to compile local functions only if used + +Changes in 1.2.11 (15 Jan 2017) +- Fix deflate stored bug when pulling last block from window +- Permit immediate deflateParams changes before any deflate input + +Changes in 1.2.10 (2 Jan 2017) +- Avoid warnings on snprintf() return value +- Fix bug in deflate_stored() for zero-length input +- Fix bug in gzwrite.c that produced corrupt gzip files +- Remove files to be installed before copying them in Makefile.in +- Add warnings when compiling with assembler code + +Changes in 1.2.9 (31 Dec 2016) +- Fix contrib/minizip to permit unzipping with desktop API [Zouzou] +- Improve contrib/blast to return unused bytes +- Assure that gzoffset() is correct when appending +- Improve compress() and uncompress() to support large lengths +- Fix bug in test/example.c where error code not saved +- Remedy Coverity warning [Randers-Pehrson] +- Improve speed of gzprintf() in transparent mode +- Fix inflateInit2() bug when windowBits is 16 or 32 +- Change DEBUG macro to ZLIB_DEBUG +- Avoid uninitialized access by gzclose_w() +- Allow building zlib outside of the source directory +- Fix bug that accepted invalid zlib header when windowBits is zero +- Fix gzseek() problem on MinGW due to buggy _lseeki64 there +- Loop on write() calls in gzwrite.c in case of non-blocking I/O +- Add --warn (-w) option to ./configure for more compiler warnings +- Reject a window size of 256 bytes if not using the zlib wrapper +- Fix bug when level 0 used with Z_HUFFMAN or Z_RLE +- Add --debug (-d) option to ./configure to define ZLIB_DEBUG +- Fix bugs in creating a very large gzip header +- Add uncompress2() function, which returns the input size used +- Assure that deflateParams() will not switch functions mid-block +- Dramatically speed up deflation for level 0 (storing) +- Add gzfread(), duplicating the interface of fread() +- Add gzfwrite(), duplicating the interface of fwrite() +- Add deflateGetDictionary() function +- Use snprintf() for later versions of Microsoft C +- Fix *Init macros to use z_ prefix when requested +- Replace as400 with os400 for OS/400 support [Monnerat] +- Add crc32_z() and adler32_z() functions with size_t lengths +- Update Visual Studio project files [AraHaan] + +Changes in 1.2.8 (28 Apr 2013) +- Update contrib/minizip/iowin32.c for Windows RT [Vollant] +- Do not force Z_CONST for C++ +- Clean up contrib/vstudio [Roß] +- Correct spelling error in zlib.h +- Fix mixed line endings in contrib/vstudio + +Changes in 1.2.7.3 (13 Apr 2013) +- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc + +Changes in 1.2.7.2 (13 Apr 2013) +- Change check for a four-byte type back to hexadecimal +- Fix typo in win32/Makefile.msc +- Add casts in gzwrite.c for pointer differences + +Changes in 1.2.7.1 (24 Mar 2013) +- Replace use of unsafe string functions with snprintf if available +- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] +- Fix gzgetc undefine when Z_PREFIX set [Turk] +- Eliminate use of mktemp in Makefile (not always available) +- Fix bug in 'F' mode for gzopen() +- Add inflateGetDictionary() function +- Correct comment in deflate.h +- Use _snprintf for snprintf in Microsoft C +- On Darwin, only use /usr/bin/libtool if libtool is not Apple +- Delete "--version" file if created by "ar --version" [Richard G.] +- Fix configure check for veracity of compiler error return codes +- Fix CMake compilation of static lib for MSVC2010 x64 +- Remove unused variable in infback9.c +- Fix argument checks in gzlog_compress() and gzlog_write() +- Clean up the usage of z_const and respect const usage within zlib +- Clean up examples/gzlog.[ch] comparisons of different types +- Avoid shift equal to bits in type (caused endless loop) +- Fix uninitialized value bug in gzputc() introduced by const patches +- Fix memory allocation error in examples/zran.c [Nor] +- Fix bug where gzopen(), gzclose() would write an empty file +- Fix bug in gzclose() when gzwrite() runs out of memory +- Check for input buffer malloc failure in examples/gzappend.c +- Add note to contrib/blast to use binary mode in stdio +- Fix comparisons of differently signed integers in contrib/blast +- Check for invalid code length codes in contrib/puff +- Fix serious but very rare decompression bug in inftrees.c +- Update inflateBack() comments, since inflate() can be faster +- Use underscored I/O function names for WINAPI_FAMILY +- Add _tr_flush_bits to the external symbols prefixed by --zprefix +- Add contrib/vstudio/vc10 pre-build step for static only +- Quote --version-script argument in CMakeLists.txt +- Don't specify --version-script on Apple platforms in CMakeLists.txt +- Fix casting error in contrib/testzlib/testzlib.c +- Fix types in contrib/minizip to match result of get_crc_table() +- Simplify contrib/vstudio/vc10 with 'd' suffix +- Add TOP support to win32/Makefile.msc +- Support i686 and amd64 assembler builds in CMakeLists.txt +- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h +- Add vc11 and vc12 build files to contrib/vstudio +- Add gzvprintf() as an undocumented function in zlib +- Fix configure for Sun shell +- Remove runtime check in configure for four-byte integer type +- Add casts and consts to ease user conversion to C++ +- Add man pages for minizip and miniunzip +- In Makefile uninstall, don't rm if preceding cd fails +- Do not return Z_BUF_ERROR if deflateParam() has nothing to write + +Changes in 1.2.7 (2 May 2012) +- Replace use of memmove() with a simple copy for portability +- Test for existence of strerror +- Restore gzgetc_ for backward compatibility with 1.2.6 +- Fix build with non-GNU make on Solaris +- Require gcc 4.0 or later on Mac OS X to use the hidden attribute +- Include unistd.h for Watcom C +- Use __WATCOMC__ instead of __WATCOM__ +- Do not use the visibility attribute if NO_VIZ defined +- Improve the detection of no hidden visibility attribute +- Avoid using __int64 for gcc or solo compilation +- Cast to char * in gzprintf to avoid warnings [Zinser] +- Fix make_vms.com for VAX [Zinser] +- Don't use library or built-in byte swaps +- Simplify test and use of gcc hidden attribute +- Fix bug in gzclose_w() when gzwrite() fails to allocate memory +- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() +- Fix bug in test/minigzip.c for configure --solo +- Fix contrib/vstudio project link errors [Mohanathas] +- Add ability to choose the builder in make_vms.com [Schweda] +- Add DESTDIR support to mingw32 win32/Makefile.gcc +- Fix comments in win32/Makefile.gcc for proper usage +- Allow overriding the default install locations for cmake +- Generate and install the pkg-config file with cmake +- Build both a static and a shared version of zlib with cmake +- Include version symbols for cmake builds +- If using cmake with MSVC, add the source directory to the includes +- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] +- Move obsolete emx makefile to old [Truta] +- Allow the use of -Wundef when compiling or using zlib +- Avoid the use of the -u option with mktemp +- Improve inflate() documentation on the use of Z_FINISH +- Recognize clang as gcc +- Add gzopen_w() in Windows for wide character path names +- Rename zconf.h in CMakeLists.txt to move it out of the way +- Add source directory in CMakeLists.txt for building examples +- Look in build directory for zlib.pc in CMakeLists.txt +- Remove gzflags from zlibvc.def in vc9 and vc10 +- Fix contrib/minizip compilation in the MinGW environment +- Update ./configure for Solaris, support --64 [Mooney] +- Remove -R. from Solaris shared build (possible security issue) +- Avoid race condition for parallel make (-j) running example +- Fix type mismatch between get_crc_table() and crc_table +- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] +- Fix the path to zlib.map in CMakeLists.txt +- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] +- Add instructions to win32/Makefile.gcc for shared install [Torri] + +Changes in 1.2.6.1 (12 Feb 2012) +- Avoid the use of the Objective-C reserved name "id" +- Include io.h in gzguts.h for Microsoft compilers +- Fix problem with ./configure --prefix and gzgetc macro +- Include gz_header definition when compiling zlib solo +- Put gzflags() functionality back in zutil.c +- Avoid library header include in crc32.c for Z_SOLO +- Use name in GCC_CLASSIC as C compiler for coverage testing, if set +- Minor cleanup in contrib/minizip/zip.c [Vollant] +- Update make_vms.com [Zinser] +- Remove unnecessary gzgetc_ function +- Use optimized byte swap operations for Microsoft and GNU [Snyder] +- Fix minor typo in zlib.h comments [Rzesniowiecki] + +Changes in 1.2.6 (29 Jan 2012) +- Update the Pascal interface in contrib/pascal +- Fix function numbers for gzgetc_ in zlibvc.def files +- Fix configure.ac for contrib/minizip [Schiffer] +- Fix large-entry detection in minizip on 64-bit systems [Schiffer] +- Have ./configure use the compiler return code for error indication +- Fix CMakeLists.txt for cross compilation [McClure] +- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] +- Fix compilation of contrib/minizip on FreeBSD [Marquez] +- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] +- Include io.h for Turbo C / Borland C on all platforms [Truta] +- Make version explicit in contrib/minizip/configure.ac [Bosmans] +- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] +- Minor cleanup up contrib/minizip/unzip.c [Vollant] +- Fix bug when compiling minizip with C++ [Vollant] +- Protect for long name and extra fields in contrib/minizip [Vollant] +- Avoid some warnings in contrib/minizip [Vollant] +- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip +- Add missing libs to minizip linker command +- Add support for VPATH builds in contrib/minizip +- Add an --enable-demos option to contrib/minizip/configure +- Add the generation of configure.log by ./configure +- Exit when required parameters not provided to win32/Makefile.gcc +- Have gzputc return the character written instead of the argument +- Use the -m option on ldconfig for BSD systems [Tobias] +- Correct in zlib.map when deflateResetKeep was added + +Changes in 1.2.5.3 (15 Jan 2012) +- Restore gzgetc function for binary compatibility +- Do not use _lseeki64 under Borland C++ [Truta] +- Update win32/Makefile.msc to build test/*.c [Truta] +- Remove old/visualc6 given CMakefile and other alternatives +- Update AS400 build files and documentation [Monnerat] +- Update win32/Makefile.gcc to build test/*.c [Truta] +- Permit stronger flushes after Z_BLOCK flushes +- Avoid extraneous empty blocks when doing empty flushes +- Permit Z_NULL arguments to deflatePending +- Allow deflatePrime() to insert bits in the middle of a stream +- Remove second empty static block for Z_PARTIAL_FLUSH +- Write out all of the available bits when using Z_BLOCK +- Insert the first two strings in the hash table after a flush + +Changes in 1.2.5.2 (17 Dec 2011) +- fix ld error: unable to find version dependency 'ZLIB_1.2.5' +- use relative symlinks for shared libs +- Avoid searching past window for Z_RLE strategy +- Assure that high-water mark initialization is always applied in deflate +- Add assertions to fill_window() in deflate.c to match comments +- Update python link in README +- Correct spelling error in gzread.c +- Fix bug in gzgets() for a concatenated empty gzip stream +- Correct error in comment for gz_make() +- Change gzread() and related to ignore junk after gzip streams +- Allow gzread() and related to continue after gzclearerr() +- Allow gzrewind() and gzseek() after a premature end-of-file +- Simplify gzseek() now that raw after gzip is ignored +- Change gzgetc() to a macro for speed (~40% speedup in testing) +- Fix gzclose() to return the actual error last encountered +- Always add large file support for windows +- Include zconf.h for windows large file support +- Include zconf.h.cmakein for windows large file support +- Update zconf.h.cmakein on make distclean +- Merge vestigial vsnprintf determination from zutil.h to gzguts.h +- Clarify how gzopen() appends in zlib.h comments +- Correct documentation of gzdirect() since junk at end now ignored +- Add a transparent write mode to gzopen() when 'T' is in the mode +- Update python link in zlib man page +- Get inffixed.h and MAKEFIXED result to match +- Add a ./config --solo option to make zlib subset with no library use +- Add undocumented inflateResetKeep() function for CAB file decoding +- Add --cover option to ./configure for gcc coverage testing +- Add #define ZLIB_CONST option to use const in the z_stream interface +- Add comment to gzdopen() in zlib.h to use dup() when using fileno() +- Note behavior of uncompress() to provide as much data as it can +- Add files in contrib/minizip to aid in building libminizip +- Split off AR options in Makefile.in and configure +- Change ON macro to Z_ARG to avoid application conflicts +- Facilitate compilation with Borland C++ for pragmas and vsnprintf +- Include io.h for Turbo C / Borland C++ +- Move example.c and minigzip.c to test/ +- Simplify incomplete code table filling in inflate_table() +- Remove code from inflate.c and infback.c that is impossible to execute +- Test the inflate code with full coverage +- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) +- Add deflateResetKeep and fix inflateResetKeep to retain dictionary +- Fix gzwrite.c to accommodate reduced memory zlib compilation +- Have inflate() with Z_FINISH avoid the allocation of a window +- Do not set strm->adler when doing raw inflate +- Fix gzeof() to behave just like feof() when read is not past end of file +- Fix bug in gzread.c when end-of-file is reached +- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF +- Document gzread() capability to read concurrently written files +- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] + +Changes in 1.2.5.1 (10 Sep 2011) +- Update FAQ entry on shared builds (#13) +- Avoid symbolic argument to chmod in Makefile.in +- Fix bug and add consts in contrib/puff [Oberhumer] +- Update contrib/puff/zeros.raw test file to have all block types +- Add full coverage test for puff in contrib/puff/Makefile +- Fix static-only-build install in Makefile.in +- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] +- Add libz.a dependency to shared in Makefile.in for parallel builds +- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out +- Replace $(...) with `...` in configure for non-bash sh [Bowler] +- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] +- Add solaris* to Linux* in configure to allow gcc use [Groffen] +- Add *bsd* to Linux* case in configure [Bar-Lev] +- Add inffast.obj to dependencies in win32/Makefile.msc +- Correct spelling error in deflate.h [Kohler] +- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc +- Add test to configure for GNU C looking for gcc in output of $cc -v +- Add zlib.pc generation to win32/Makefile.gcc [Weigelt] +- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not +- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense +- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) +- Make stronger test in zconf.h to include unistd.h for LFS +- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] +- Fix zlib.h LFS support when Z_PREFIX used +- Add updated as400 support (removed from old) [Monnerat] +- Avoid deflate sensitivity to volatile input data +- Avoid division in adler32_combine for NO_DIVIDE +- Clarify the use of Z_FINISH with deflateBound() amount of space +- Set binary for output file in puff.c +- Use u4 type for crc_table to avoid conversion warnings +- Apply casts in zlib.h to avoid conversion warnings +- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] +- Improve inflateSync() documentation to note indeterminacy +- Add deflatePending() function to return the amount of pending output +- Correct the spelling of "specification" in FAQ [Randers-Pehrson] +- Add a check in configure for stdarg.h, use for gzprintf() +- Check that pointers fit in ints when gzprint() compiled old style +- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] +- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] +- Add debug records in assembler code [Londer] +- Update RFC references to use http://tools.ietf.org/html/... [Li] +- Add --archs option, use of libtool to configure for Mac OS X [Borstel] + +Changes in 1.2.5 (19 Apr 2010) +- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] +- Default to libdir as sharedlibdir in configure [Nieder] +- Update copyright dates on modified source files +- Update trees.c to be able to generate modified trees.h +- Exit configure for MinGW, suggesting win32/Makefile.gcc +- Check for NULL path in gz_open [Homurlu] + +Changes in 1.2.4.5 (18 Apr 2010) +- Set sharedlibdir in configure [Torok] +- Set LDFLAGS in Makefile.in [Bar-Lev] +- Avoid mkdir objs race condition in Makefile.in [Bowler] +- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays +- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C +- Don't use hidden attribute when it is a warning generator (e.g. Solaris) + +Changes in 1.2.4.4 (18 Apr 2010) +- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] +- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty +- Try to use bash or ksh regardless of functionality of /bin/sh +- Fix configure incompatibility with NetBSD sh +- Remove attempt to run under bash or ksh since have better NetBSD fix +- Fix win32/Makefile.gcc for MinGW [Bar-Lev] +- Add diagnostic messages when using CROSS_PREFIX in configure +- Added --sharedlibdir option to configure [Weigelt] +- Use hidden visibility attribute when available [Frysinger] + +Changes in 1.2.4.3 (10 Apr 2010) +- Only use CROSS_PREFIX in configure for ar and ranlib if they exist +- Use CROSS_PREFIX for nm [Bar-Lev] +- Assume _LARGEFILE64_SOURCE defined is equivalent to true +- Avoid use of undefined symbols in #if with && and || +- Make *64 prototypes in gzguts.h consistent with functions +- Add -shared load option for MinGW in configure [Bowler] +- Move z_off64_t to public interface, use instead of off64_t +- Remove ! from shell test in configure (not portable to Solaris) +- Change +0 macro tests to -0 for possibly increased portability + +Changes in 1.2.4.2 (9 Apr 2010) +- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 +- Really provide prototypes for *64 functions when building without LFS +- Only define unlink() in minigzip.c if unistd.h not included +- Update README to point to contrib/vstudio project files +- Move projects/vc6 to old/ and remove projects/ +- Include stdlib.h in minigzip.c for setmode() definition under WinCE +- Clean up assembler builds in win32/Makefile.msc [Rowe] +- Include sys/types.h for Microsoft for off_t definition +- Fix memory leak on error in gz_open() +- Symbolize nm as $NM in configure [Weigelt] +- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] +- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined +- Fix bug in gzeof() to take into account unused input data +- Avoid initialization of structures with variables in puff.c +- Updated win32/README-WIN32.txt [Rowe] + +Changes in 1.2.4.1 (28 Mar 2010) +- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] +- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] +- Restore "for debugging" comment on sprintf() in gzlib.c +- Remove fdopen for MVS from gzguts.h +- Put new README-WIN32.txt in win32 [Rowe] +- Add check for shell to configure and invoke another shell if needed +- Fix big fat stinking bug in gzseek() on uncompressed files +- Remove vestigial F_OPEN64 define in zutil.h +- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE +- Avoid errors on non-LFS systems when applications define LFS macros +- Set EXE to ".exe" in configure for MINGW [Kahle] +- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] +- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] +- Add DLL install in win32/makefile.gcc [Bar-Lev] +- Allow Linux* or linux* from uname in configure [Bar-Lev] +- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] +- Add cross-compilation prefixes to configure [Bar-Lev] +- Match type exactly in gz_load() invocation in gzread.c +- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func +- Provide prototypes for *64 functions when building zlib without LFS +- Don't use -lc when linking shared library on MinGW +- Remove errno.h check in configure and vestigial errno code in zutil.h + +Changes in 1.2.4 (14 Mar 2010) +- Fix VER3 extraction in configure for no fourth subversion +- Update zlib.3, add docs to Makefile.in to make .pdf out of it +- Add zlib.3.pdf to distribution +- Don't set error code in gzerror() if passed pointer is NULL +- Apply destination directory fixes to CMakeLists.txt [Lowman] +- Move #cmakedefine's to a new zconf.in.cmakein +- Restore zconf.h for builds that don't use configure or cmake +- Add distclean to dummy Makefile for convenience +- Update and improve INDEX, README, and FAQ +- Update CMakeLists.txt for the return of zconf.h [Lowman] +- Update contrib/vstudio/vc9 and vc10 [Vollant] +- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc +- Apply license and readme changes to contrib/asm686 [Raiter] +- Check file name lengths and add -c option in minigzip.c [Li] +- Update contrib/amd64 and contrib/masmx86/ [Vollant] +- Avoid use of "eof" parameter in trees.c to not shadow library variable +- Update make_vms.com for removal of zlibdefs.h [Zinser] +- Update assembler code and vstudio projects in contrib [Vollant] +- Remove outdated assembler code contrib/masm686 and contrib/asm586 +- Remove old vc7 and vc8 from contrib/vstudio +- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] +- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() +- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] +- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) +- Fix bug in void-returning vsprintf() case in gzwrite.c +- Fix name change from inflate.h in contrib/inflate86/inffas86.c +- Check if temporary file exists before removing in make_vms.com [Zinser] +- Fix make install and uninstall for --static option +- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] +- Update readme.txt in contrib/masmx64 and masmx86 to assemble + +Changes in 1.2.3.9 (21 Feb 2010) +- Expunge gzio.c +- Move as400 build information to old +- Fix updates in contrib/minizip and contrib/vstudio +- Add const to vsnprintf test in configure to avoid warnings [Weigelt] +- Delete zconf.h (made by configure) [Weigelt] +- Change zconf.in.h to zconf.h.in per convention [Weigelt] +- Check for NULL buf in gzgets() +- Return empty string for gzgets() with len == 1 (like fgets()) +- Fix description of gzgets() in zlib.h for end-of-file, NULL return +- Update minizip to 1.1 [Vollant] +- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c +- Note in zlib.h that gzerror() should be used to distinguish from EOF +- Remove use of snprintf() from gzlib.c +- Fix bug in gzseek() +- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] +- Fix zconf.h generation in CMakeLists.txt [Lowman] +- Improve comments in zconf.h where modified by configure + +Changes in 1.2.3.8 (13 Feb 2010) +- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] +- Use z_off64_t in gz_zero() and gz_skip() to match state->skip +- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) +- Revert to Makefile.in from 1.2.3.6 (live with the clutter) +- Fix missing error return in gzflush(), add zlib.h note +- Add *64 functions to zlib.map [Levin] +- Fix signed/unsigned comparison in gz_comp() +- Use SFLAGS when testing shared linking in configure +- Add --64 option to ./configure to use -m64 with gcc +- Fix ./configure --help to correctly name options +- Have make fail if a test fails [Levin] +- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] +- Remove assembler object files from contrib + +Changes in 1.2.3.7 (24 Jan 2010) +- Always gzopen() with O_LARGEFILE if available +- Fix gzdirect() to work immediately after gzopen() or gzdopen() +- Make gzdirect() more precise when the state changes while reading +- Improve zlib.h documentation in many places +- Catch memory allocation failure in gz_open() +- Complete close operation if seek forward in gzclose_w() fails +- Return Z_ERRNO from gzclose_r() if close() fails +- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL +- Return zero for gzwrite() errors to match zlib.h description +- Return -1 on gzputs() error to match zlib.h description +- Add zconf.in.h to allow recovery from configure modification [Weigelt] +- Fix static library permissions in Makefile.in [Weigelt] +- Avoid warnings in configure tests that hide functionality [Weigelt] +- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] +- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] +- Avoid access of uninitialized data for first inflateReset2 call [Gomes] +- Keep object files in subdirectories to reduce the clutter somewhat +- Remove default Makefile and zlibdefs.h, add dummy Makefile +- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ +- Remove zlibdefs.h completely -- modify zconf.h instead + +Changes in 1.2.3.6 (17 Jan 2010) +- Avoid void * arithmetic in gzread.c and gzwrite.c +- Make compilers happier with const char * for gz_error message +- Avoid unused parameter warning in inflate.c +- Avoid signed-unsigned comparison warning in inflate.c +- Indent #pragma's for traditional C +- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() +- Correct email address in configure for system options +- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] +- Update zlib.map [Brown] +- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] +- Apply various fixes to CMakeLists.txt [Lowman] +- Add checks on len in gzread() and gzwrite() +- Add error message for no more room for gzungetc() +- Remove zlib version check in gzwrite() +- Defer compression of gzprintf() result until need to +- Use snprintf() in gzdopen() if available +- Remove USE_MMAP configuration determination (only used by minigzip) +- Remove examples/pigz.c (available separately) +- Update examples/gun.c to 1.6 + +Changes in 1.2.3.5 (8 Jan 2010) +- Add space after #if in zutil.h for some compilers +- Fix relatively harmless bug in deflate_fast() [Exarevsky] +- Fix same problem in deflate_slow() +- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] +- Add deflate_rle() for faster Z_RLE strategy run-length encoding +- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding +- Change name of "write" variable in inffast.c to avoid library collisions +- Fix premature EOF from gzread() in gzio.c [Brown] +- Use zlib header window size if windowBits is 0 in inflateInit2() +- Remove compressBound() call in deflate.c to avoid linking compress.o +- Replace use of errno in gz* with functions, support WinCE [Alves] +- Provide alternative to perror() in minigzip.c for WinCE [Alves] +- Don't use _vsnprintf on later versions of MSVC [Lowman] +- Add CMake build script and input file [Lowman] +- Update contrib/minizip to 1.1 [Svensson, Vollant] +- Moved nintendods directory from contrib to root +- Replace gzio.c with a new set of routines with the same functionality +- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above +- Update contrib/minizip to 1.1b +- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h + +Changes in 1.2.3.4 (21 Dec 2009) +- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility +- Update comments in configure and Makefile.in for default --shared +- Fix test -z's in configure [Marquess] +- Build examplesh and minigzipsh when not testing +- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h +- Import LDFLAGS from the environment in configure +- Fix configure to populate SFLAGS with discovered CFLAGS options +- Adapt make_vms.com to the new Makefile.in [Zinser] +- Add zlib2ansi script for C++ compilation [Marquess] +- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) +- Add AMD64 assembler code for longest match to contrib [Teterin] +- Include options from $SFLAGS when doing $LDSHARED +- Simplify 64-bit file support by introducing z_off64_t type +- Make shared object files in objs directory to work around old Sun cc +- Use only three-part version number for Darwin shared compiles +- Add rc option to ar in Makefile.in for when ./configure not run +- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* +- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile +- Protect against _FILE_OFFSET_BITS being defined when compiling zlib +- Rename Makefile.in targets allstatic to static and allshared to shared +- Fix static and shared Makefile.in targets to be independent +- Correct error return bug in gz_open() by setting state [Brown] +- Put spaces before ;;'s in configure for better sh compatibility +- Add pigz.c (parallel implementation of gzip) to examples/ +- Correct constant in crc32.c to UL [Leventhal] +- Reject negative lengths in crc32_combine() +- Add inflateReset2() function to work like inflateEnd()/inflateInit2() +- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] +- Correct typo in doc/algorithm.txt [Janik] +- Fix bug in adler32_combine() [Zhu] +- Catch missing-end-of-block-code error in all inflates and in puff + Assures that random input to inflate eventually results in an error +- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ +- Update ENOUGH and its usage to reflect discovered bounds +- Fix gzerror() error report on empty input file [Brown] +- Add ush casts in trees.c to avoid pedantic runtime errors +- Fix typo in zlib.h uncompress() description [Reiss] +- Correct inflate() comments with regard to automatic header detection +- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) +- Put new version of gzlog (2.0) in examples with interruption recovery +- Add puff compile option to permit invalid distance-too-far streams +- Add puff TEST command options, ability to read piped input +- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but + _LARGEFILE64_SOURCE not defined +- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart +- Fix deflateSetDictionary() to use all 32K for output consistency +- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) +- Clear bytes after deflate lookahead to avoid use of uninitialized data +- Change a limit in inftrees.c to be more transparent to Coverity Prevent +- Update win32/zlib.def with exported symbols from zlib.h +- Correct spelling errors in zlib.h [Willem, Sobrado] +- Allow Z_BLOCK for deflate() to force a new block +- Allow negative bits in inflatePrime() to delete existing bit buffer +- Add Z_TREES flush option to inflate() to return at end of trees +- Add inflateMark() to return current state information for random access +- Add Makefile for NintendoDS to contrib [Costa] +- Add -w in configure compile tests to avoid spurious warnings [Beucler] +- Fix typos in zlib.h comments for deflateSetDictionary() +- Fix EOF detection in transparent gzread() [Maier] + +Changes in 1.2.3.3 (2 October 2006) +- Make --shared the default for configure, add a --static option +- Add compile option to permit invalid distance-too-far streams +- Add inflateUndermine() function which is required to enable above +- Remove use of "this" variable name for C++ compatibility [Marquess] +- Add testing of shared library in make test, if shared library built +- Use ftello() and fseeko() if available instead of ftell() and fseek() +- Provide two versions of all functions that use the z_off_t type for + binary compatibility -- a normal version and a 64-bit offset version, + per the Large File Support Extension when _LARGEFILE64_SOURCE is + defined; use the 64-bit versions by default when _FILE_OFFSET_BITS + is defined to be 64 +- Add a --uname= option to configure to perhaps help with cross-compiling + +Changes in 1.2.3.2 (3 September 2006) +- Turn off silly Borland warnings [Hay] +- Use off64_t and define _LARGEFILE64_SOURCE when present +- Fix missing dependency on inffixed.h in Makefile.in +- Rig configure --shared to build both shared and static [Teredesai, Truta] +- Remove zconf.in.h and instead create a new zlibdefs.h file +- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] +- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] + +Changes in 1.2.3.1 (16 August 2006) +- Add watcom directory with OpenWatcom make files [Daniel] +- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] +- Update make_vms.com [Zinser] +- Use -fPIC for shared build in configure [Teredesai, Nicholson] +- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] +- Use fdopen() (not _fdopen()) for Interix in zutil.h [Bäck] +- Add some FAQ entries about the contrib directory +- Update the MVS question in the FAQ +- Avoid extraneous reads after EOF in gzio.c [Brown] +- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] +- Add comments to zlib.h about gzerror() usage [Brown] +- Set extra flags in gzip header in gzopen() like deflate() does +- Make configure options more compatible with double-dash conventions + [Weigelt] +- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] +- Fix uninstall target in Makefile.in [Truta] +- Add pkgconfig support [Weigelt] +- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] +- Replace set_data_type() with a more accurate detect_data_type() in + trees.c, according to the txtvsbin.txt document [Truta] +- Swap the order of #include and #include "zlib.h" in + gzio.c, example.c and minigzip.c [Truta] +- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, + Truta] (where?) +- Fix target "clean" from win32/Makefile.bor [Truta] +- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] +- Update zlib www home address in win32/DLL_FAQ.txt [Truta] +- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] +- Enable browse info in the "Debug" and "ASM Debug" configurations in + the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] +- Add pkgconfig support [Weigelt] +- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, + for use in win32/zlib1.rc [Polushin, Rowe, Truta] +- Add a document that explains the new text detection scheme to + doc/txtvsbin.txt [Truta] +- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] +- Move algorithm.txt into doc/ [Truta] +- Synchronize FAQ with website +- Fix compressBound(), was low for some pathological cases [Fearnley] +- Take into account wrapper variations in deflateBound() +- Set examples/zpipe.c input and output to binary mode for Windows +- Update examples/zlib_how.html with new zpipe.c (also web site) +- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems + that gcc became pickier in 4.0) +- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain + un-versioned, the patch adds versioning only for symbols introduced in + zlib-1.2.0 or later. It also declares as local those symbols which are + not designed to be exported." [Levin] +- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure +- Do not initialize global static by default in trees.c, add a response + NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] +- Don't use strerror() in gzio.c under WinCE [Yakimov] +- Don't use errno.h in zutil.h under WinCE [Yakimov] +- Move arguments for AR to its usage to allow replacing ar [Marot] +- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] +- Improve inflateInit() and inflateInit2() documentation +- Fix structure size comment in inflate.h +- Change configure help option from --h* to --help [Santos] + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Add zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enhance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5) + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles Vollant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test" +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one) +- In minigzip, pass transparently also the first byte for .Z files +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match() + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code +- Use default memcpy for Symantec MSDOS compiler +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch) +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generate bad compressed data +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count) +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?) +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions) +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h) +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model) + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model + +Changes in 0.7 (14 April 95) +- Added full inflate support +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose) +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking +- renamed the 'filter' parameter of deflateInit2 as 'strategy' + Added Z_FILTERED and Z_HUFFMAN_ONLY constants + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8 +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2 +- added inflateInit2 +- simplified considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2 + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/comm/third_party/zlib/FAQ b/comm/third_party/zlib/FAQ new file mode 100644 index 0000000000..99b7cf92e4 --- /dev/null +++ b/comm/third_party/zlib/FAQ @@ -0,0 +1,368 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://zlib.net/ which may have more recent information. +The lastest zlib FAQ is at http://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the + precompiled DLL are found in the zlib web site at http://zlib.net/ . + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files test/example.c + and test/minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + By default a shared (and a static) library is built for Unix. So: + + make distclean + ./configure + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.pdflib.com/ . To modify PDF forms, see + http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specification in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/comm/third_party/zlib/INDEX b/comm/third_party/zlib/INDEX new file mode 100644 index 0000000000..2ba0641204 --- /dev/null +++ b/comm/third_party/zlib/INDEX @@ -0,0 +1,68 @@ +CMakeLists.txt cmake build file +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile dummy Makefile that tells you to ./configure +Makefile.in template for Unix Makefile +README guess what +configure configure script for Unix +make_vms.com makefile for VMS +test/example.c zlib usages examples for build testing +test/minigzip.c minimal gzip-like functionality for build testing +test/infcover.c inf*.c code coverage for build coverage testing +treebuild.xml XML description of source file dependencies +zconf.h.cmakein zconf.h template for cmake +zconf.h.in zconf.h template for configure +zlib.3 Man page for zlib +zlib.3.pdf Man page in PDF format +zlib.map Linux symbol information +zlib.pc.in Template for pkg-config descriptor +zlib.pc.cmakein zlib.pc template for cmake +zlib2ansi perl script to convert source files for C++ compilation + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for AS/400 +doc/ documentation for formats and algorithms +msdos/ makefiles for MSDOS +nintendods/ makefile for Nintendo DS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +watcom/ makefiles for OpenWatcom +win32/ makefiles for Windows + + zlib public header files (required for library use): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzclose.c +gzguts.h +gzlib.c +gzread.c +gzwrite.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs +See examples/README.examples + + unsupported contributions by third parties +See contrib/README.contrib diff --git a/comm/third_party/zlib/LICENSE b/comm/third_party/zlib/LICENSE new file mode 100644 index 0000000000..ab8ee6f714 --- /dev/null +++ b/comm/third_party/zlib/LICENSE @@ -0,0 +1,22 @@ +Copyright notice: + + (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/comm/third_party/zlib/README b/comm/third_party/zlib/README new file mode 100644 index 0000000000..ba34d1894a --- /dev/null +++ b/comm/third_party/zlib/README @@ -0,0 +1,118 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.13 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and +rfc1952 (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file test/example.c which also tests that +the library is working correctly. Another example is given in the file +test/minigzip.c. The compression library itself is composed of all source +files in the root directory. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use +one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +http://marknelson.us/1997/01/01/zlib-engine/ . + +The changes made in version 1.2.13 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package, documented at +http://java.sun.com/developer/technicalArticles/Programming/compression/ . + +A Perl interface to zlib written by Paul Marquess is available +at CPAN (Comprehensive Perl Archive Network) sites, including +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://docs.python.org/library/zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. We make all +contributions to and distributions of this project solely in our personal +capacity, and are not conveying any rights to any intellectual property of +any third parties. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/comm/third_party/zlib/adler32.c b/comm/third_party/zlib/adler32.c new file mode 100644 index 0000000000..d0be4380a3 --- /dev/null +++ b/comm/third_party/zlib/adler32.c @@ -0,0 +1,186 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z(adler, buf, len) + uLong adler; + const Bytef *buf; + z_size_t len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/comm/third_party/zlib/compress.c b/comm/third_party/zlib/compress.c new file mode 100644 index 0000000000..2ad5326c14 --- /dev/null +++ b/comm/third_party/zlib/compress.c @@ -0,0 +1,86 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2(dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong left; + + left = *destLen; + *destLen = 0; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; + sourceLen -= stream.avail_in; + } + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + deflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : err; +} + +/* =========================================================================== + */ +int ZEXPORT compress(dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound(sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/comm/third_party/zlib/crc32.c b/comm/third_party/zlib/crc32.c new file mode 100644 index 0000000000..f8357b083f --- /dev/null +++ b/comm/third_party/zlib/crc32.c @@ -0,0 +1,1125 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This interleaved implementation of a CRC makes use of pipelined multiple + * arithmetic-logic units, commonly found in modern CPU cores. It is due to + * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + MAKECRCH can be #defined to write out crc32.h. A main() routine is also + produced, so that this one source file can be compiled to an executable. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ + + /* + A CRC of a message is computed on N braids of words in the message, where + each word consists of W bytes (4 or 8). If N is 3, for example, then three + running sparse CRCs are calculated respectively on each braid, at these + indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... + This is done starting at a word boundary, and continues until as many blocks + of N * W bytes as are available have been processed. The results are combined + into a single CRC at the end. For this code, N must be in the range 1..6 and + W must be 4 or 8. The upper limit on N can be increased if desired by adding + more #if blocks, extending the patterns apparent in the code. In addition, + crc32.h would need to be regenerated, if the maximum N value is increased. + + N and W are chosen empirically by benchmarking the execution time on a given + processor. The choices for N and W below were based on testing on Intel Kaby + Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 + Octeon II processors. The Intel, AMD, and ARM processors were all fastest + with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. + They were all tested with either gcc or clang, all using the -O3 optimization + level. Your mileage may vary. + */ + +/* Define N */ +#ifdef Z_TESTN +# define N Z_TESTN +#else +# define N 5 +#endif +#if N < 1 || N > 6 +# error N must be in 1..6 +#endif + +/* + z_crc_t must be at least 32 bits. z_word_t must be at least as long as + z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and + that bytes are eight bits. + */ + +/* + Define W and the associated z_word_t type. If W is not defined, then a + braided calculation is not used, and the associated tables and code are not + compiled. + */ +#ifdef Z_TESTW +# if Z_TESTW-1 != -1 +# define W Z_TESTW +# endif +#else +# ifdef MAKECRCH +# define W 8 /* required for MAKECRCH */ +# else +# if defined(__x86_64__) || defined(__aarch64__) +# define W 8 +# else +# define W 4 +# endif +# endif +#endif +#ifdef W +# if W == 8 && defined(Z_U8) + typedef Z_U8 z_word_t; +# elif defined(Z_U4) +# undef W +# define W 4 + typedef Z_U4 z_word_t; +# else +# undef W +# endif +#endif + +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + +/* Local functions. */ +local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); +local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +#endif + +#if defined(W) && !defined(ARMCRC32) + local z_crc_t crc_word OF((z_word_t data)); + local z_word_t crc_word_big OF((z_word_t data)); +#endif + +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) +/* + Swap the bytes in a z_word_t to convert between little and big endian. Any + self-respecting compiler will optimize this to a single machine byte-swap + instruction, if one is available. This assumes that word_t is either 32 bits + or 64 bits. + */ +local z_word_t byte_swap(word) + z_word_t word; +{ +# if W == 8 + return + (word & 0xff00000000000000) >> 56 | + (word & 0xff000000000000) >> 40 | + (word & 0xff0000000000) >> 24 | + (word & 0xff00000000) >> 8 | + (word & 0xff000000) << 8 | + (word & 0xff0000) << 24 | + (word & 0xff00) << 40 | + (word & 0xff) << 56; +# else /* W == 4 */ + return + (word & 0xff000000) >> 24 | + (word & 0xff0000) >> 8 | + (word & 0xff00) << 8 | + (word & 0xff) << 24; +# endif +} +#endif + +/* CRC polynomial. */ +#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ + +#ifdef DYNAMIC_CRC_TABLE + +local z_crc_t FAR crc_table[256]; +local z_crc_t FAR x2n_table[32]; +local void make_crc_table OF((void)); +#ifdef W + local z_word_t FAR crc_big_table[256]; + local z_crc_t FAR crc_braid_table[W][256]; + local z_word_t FAR crc_braid_big_table[W][256]; + local void braid OF((z_crc_t [][256], z_word_t [][256], int, int)); +#endif +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *, int)); + local void write_table32hi OF((FILE *, const z_word_t FAR *, int)); + local void write_table64 OF((FILE *, const z_word_t FAR *, int)); +#endif /* MAKECRCH */ + +/* + Define a once() function depending on the availability of atomics. If this is + compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in + multiple threads, and if atomics are not available, then get_crc_table() must + be called to initialize the tables and must return before any threads are + allowed to compute or combine CRCs. + */ + +/* Definition of once functionality. */ +typedef struct once_s once_t; +local void once OF((once_t *, void (*)(void))); + +/* Check for the availability of atomics. */ +#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_ATOMICS__) + +#include + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + atomic_flag begun; + atomic_int done; +}; +#define ONCE_INIT {ATOMIC_FLAG_INIT, 0} + +/* + Run the provided init() function exactly once, even if multiple threads + invoke once() at the same time. The state must be a once_t initialized with + ONCE_INIT. + */ +local void once(state, init) + once_t *state; + void (*init)(void); +{ + if (!atomic_load(&state->done)) { + if (atomic_flag_test_and_set(&state->begun)) + while (!atomic_load(&state->done)) + ; + else { + init(); + atomic_store(&state->done, 1); + } + } +} + +#else /* no atomics */ + +/* Structure for once(), which must be initialized with ONCE_INIT. */ +struct once_s { + volatile int begun; + volatile int done; +}; +#define ONCE_INIT {0, 0} + +/* Test and set. Alas, not atomic, but tries to minimize the period of + vulnerability. */ +local int test_and_set OF((int volatile *)); +local int test_and_set(flag) + int volatile *flag; +{ + int was; + + was = *flag; + *flag = 1; + return was; +} + +/* Run the provided init() function once. This is not thread-safe. */ +local void once(state, init) + once_t *state; + void (*init)(void); +{ + if (!state->done) { + if (test_and_set(&state->begun)) + while (!state->done) + ; + else { + init(); + state->done = 1; + } + } +} + +#endif + +/* State for once(). */ +local once_t made = ONCE_INIT; + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x + (which is shifting right by one and adding x^32 mod p if the bit shifted out + is a one). We start with the highest power (least significant bit) of q and + repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all the + information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. + */ + +local void make_crc_table() +{ + unsigned i, j, n; + z_crc_t p; + + /* initialize the CRC of bytes tables */ + for (i = 0; i < 256; i++) { + p = i; + for (j = 0; j < 8; j++) + p = p & 1 ? (p >> 1) ^ POLY : p >> 1; + crc_table[i] = p; +#ifdef W + crc_big_table[i] = byte_swap(p); +#endif + } + + /* initialize the x^2^n mod p(x) table */ + p = (z_crc_t)1 << 30; /* x^1 */ + x2n_table[0] = p; + for (n = 1; n < 32; n++) + x2n_table[n] = p = multmodp(p, p); + +#ifdef W + /* initialize the braiding tables -- needs x2n_table[] */ + braid(crc_braid_table, crc_braid_big_table, N, W); +#endif + +#ifdef MAKECRCH + { + /* + The crc32.h header file contains tables for both 32-bit and 64-bit + z_word_t's, and so requires a 64-bit type be available. In that case, + z_word_t must be defined to be 64-bits. This code then also generates + and writes out the tables for the case that z_word_t is 32 bits. + */ +#if !defined(W) || W != 8 +# error Need a 64-bit integer type in order to generate crc32.h. +#endif + FILE *out; + int k, n; + z_crc_t ltl[8][256]; + z_word_t big[8][256]; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + + /* write out little-endian CRC table to crc32.h */ + fprintf(out, + "/* crc32.h -- tables for rapid CRC calculation\n" + " * Generated automatically by crc32.c\n */\n" + "\n" + "local const z_crc_t FAR crc_table[] = {\n" + " "); + write_table(out, crc_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#ifdef W\n" + "\n" + "#if W == 8\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table64(out, crc_big_table, 256); + fprintf(out, + "};\n"); + + /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_word_t FAR crc_big_table[] = {\n" + " "); + write_table32hi(out, crc_big_table, 256); + fprintf(out, + "};\n" + "\n" + "#endif\n"); + + /* write out braid tables for each value of N */ + for (n = 1; n <= 6; n++) { + fprintf(out, + "\n" + "#if N == %d\n", n); + + /* compute braid tables for this N and 64-bit word_t */ + braid(ltl, big, n, 8); + + /* write out braid tables for 64-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#if W == 8\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 8; k++) { + fprintf(out, " {"); + write_table64(out, big[k], 256); + fprintf(out, "}%s", k < 7 ? ",\n" : ""); + } + fprintf(out, + "};\n"); + + /* compute braid tables for this N and 32-bit word_t */ + braid(ltl, big, n, 4); + + /* write out braid tables for 32-bit z_word_t to crc32.h */ + fprintf(out, + "\n" + "#else /* W == 4 */\n" + "\n" + "local const z_crc_t FAR crc_braid_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table(out, ltl[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); + for (k = 0; k < 4; k++) { + fprintf(out, " {"); + write_table32hi(out, big[k], 256); + fprintf(out, "}%s", k < 3 ? ",\n" : ""); + } + fprintf(out, + "};\n" + "\n" + "#endif\n" + "\n" + "#endif\n"); + } + fprintf(out, + "\n" + "#endif\n"); + + /* write out zeros operator table to crc32.h */ + fprintf(out, + "\n" + "local const z_crc_t FAR x2n_table[] = {\n" + " "); + write_table(out, x2n_table, 32); + fprintf(out, + "};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH + +/* + Write the 32-bit values in table[0..k-1] to out, five per line in + hexadecimal separated by commas. + */ +local void write_table(out, table, k) + FILE *out; + const z_crc_t FAR *table; + int k; +{ + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the high 32-bits of each value in table[0..k-1] to out, five per line + in hexadecimal separated by commas. + */ +local void write_table32hi(out, table, k) +FILE *out; +const z_word_t FAR *table; +int k; +{ + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", + (unsigned long)(table[n] >> 32), + n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); +} + +/* + Write the 64-bit values in table[0..k-1] to out, three per line in + hexadecimal separated by commas. This assumes that if there is a 64-bit + type, then there is also a long long integer type, and it is at least 64 + bits. If not, then the type cast and format string can be adjusted + accordingly. + */ +local void write_table64(out, table, k) + FILE *out; + const z_word_t FAR *table; + int k; +{ + int n; + + for (n = 0; n < k; n++) + fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", + (unsigned long long)(table[n]), + n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); +} + +/* Actually do the deed. */ +int main() +{ + make_crc_table(); + return 0; +} + +#endif /* MAKECRCH */ + +#ifdef W +/* + Generate the little and big-endian braid tables for the given n and z_word_t + size w. Each array must have room for w blocks of 256 elements. + */ +local void braid(ltl, big, n, w) + z_crc_t ltl[][256]; + z_word_t big[][256]; + int n; + int w; +{ + int k; + z_crc_t i, p, q; + for (k = 0; k < w; k++) { + p = x2nmodp((n * w + 3 - k) << 3, 0); + ltl[k][0] = 0; + big[w - 1 - k][0] = 0; + for (i = 1; i < 256; i++) { + ltl[k][i] = q = multmodp(i << 24, p); + big[w - 1 - k][i] = byte_swap(q); + } + } +} +#endif + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ======================================================================== + * Routines used for CRC calculation. Some are also required for the table + * generation above. + */ + +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(a, b) + z_crc_t a; + z_crc_t b; +{ + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} + +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(n, k) + z_off64_t n; + unsigned k; +{ + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +/* ========================================================================= + * This function can be used by asm versions of crc32(), and to force the + * generation of the CRC tables in a threaded application. + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= + * Use ARM machine instructions if available. This will compute the CRC about + * ten times faster than the braided calculation. This code does not check for + * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will + * only be defined if the compilation specifies an ARM processor architecture + * that has the instructions. For example, compiling with -march=armv8.1-a or + * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 + * instructions. + */ +#ifdef ARMCRC32 + +/* + Constants empirically determined to maximize speed. These values are from + measurements on a Cortex-A57. Your mileage may vary. + */ +#define Z_BATCH 3990 /* number of words in a batch */ +#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ +#define Z_BATCH_MIN 800 /* fewest words in a final batch */ + +unsigned long ZEXPORT crc32_z(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + z_crc_t val; + z_word_t crc1, crc2; + const z_word_t *word; + z_word_t val0, val1, val2; + z_size_t last, last2, i; + z_size_t num; + + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + + /* Compute the CRC up to a word boundary. */ + while (len && ((z_size_t)buf & 7) != 0) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ + word = (z_word_t const *)buf; + num = len >> 3; + len &= 7; + + /* Do three interleaved CRCs to realize the throughput of one crc32x + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ + while (num >= 3 * Z_BATCH) { + crc1 = 0; + crc2 = 0; + for (i = 0; i < Z_BATCH; i++) { + val0 = word[i]; + val1 = word[i + Z_BATCH]; + val2 = word[i + 2 * Z_BATCH]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * Z_BATCH; + num -= 3 * Z_BATCH; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; + crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; + } + + /* Do one last smaller batch with the remaining words, if there are enough + to pay for the combination of CRCs. */ + last = num / 3; + if (last >= Z_BATCH_MIN) { + last2 = last << 1; + crc1 = 0; + crc2 = 0; + for (i = 0; i < last; i++) { + val0 = word[i]; + val1 = word[i + last]; + val2 = word[i + last2]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); + } + word += 3 * last; + num -= 3 * last; + val = x2nmodp(last, 6); + crc = multmodp(val, crc) ^ crc1; + crc = multmodp(val, crc) ^ crc2; + } + + /* Compute the CRC on any remaining words. */ + for (i = 0; i < num; i++) { + val0 = word[i]; + __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); + } + word += num; + + /* Complete the CRC on any remaining bytes. */ + buf = (const unsigned char FAR *)word; + while (len) { + len--; + val = *buf++; + __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#else + +#ifdef W + +/* + Return the CRC of the W bytes in the word_t data, taking the + least-significant byte of the word as the first byte of data, without any pre + or post conditioning. This is used to combine the CRCs of each braid. + */ +local z_crc_t crc_word(data) + z_word_t data; +{ + int k; + for (k = 0; k < W; k++) + data = (data >> 8) ^ crc_table[data & 0xff]; + return (z_crc_t)data; +} + +local z_word_t crc_word_big(data) + z_word_t data; +{ + int k; + for (k = 0; k < W; k++) + data = (data << 8) ^ + crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; + return data; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + /* Return initial CRC, if requested. */ + if (buf == Z_NULL) return 0; + +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + + /* Pre-condition the CRC */ + crc = (~crc) & 0xffffffff; + +#ifdef W + + /* If provided enough bytes, do a braided CRC calculation. */ + if (len >= N * W + W - 1) { + z_size_t blks; + z_word_t const *words; + unsigned endian; + int k; + + /* Compute the CRC up to a z_word_t boundary. */ + while (len && ((z_size_t)buf & (W - 1)) != 0) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Compute the CRC on as many N z_word_t blocks as are available. */ + blks = len / (N * W); + len -= blks * N * W; + words = (z_word_t const *)buf; + + /* Do endian check at execution time instead of compile time, since ARM + processors can change the endianess at execution time. If the + compiler knows what the endianess will be, it can optimize out the + check and the unused branch. */ + endian = 1; + if (*(unsigned char *)&endian) { + /* Little endian. */ + + z_crc_t crc0; + z_word_t word0; +#if N > 1 + z_crc_t crc1; + z_word_t word1; +#if N > 2 + z_crc_t crc2; + z_word_t word2; +#if N > 3 + z_crc_t crc3; + z_word_t word3; +#if N > 4 + z_crc_t crc4; + z_word_t word4; +#if N > 5 + z_crc_t crc5; + z_word_t word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = crc; +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + crc = crc_word(crc0 ^ words[0]); +#if N > 1 + crc = crc_word(crc1 ^ words[1] ^ crc); +#if N > 2 + crc = crc_word(crc2 ^ words[2] ^ crc); +#if N > 3 + crc = crc_word(crc3 ^ words[3] ^ crc); +#if N > 4 + crc = crc_word(crc4 ^ words[4] ^ crc); +#if N > 5 + crc = crc_word(crc5 ^ words[5] ^ crc); +#endif +#endif +#endif +#endif +#endif + words += N; + } + else { + /* Big endian. */ + + z_word_t crc0, word0, comb; +#if N > 1 + z_word_t crc1, word1; +#if N > 2 + z_word_t crc2, word2; +#if N > 3 + z_word_t crc3, word3; +#if N > 4 + z_word_t crc4, word4; +#if N > 5 + z_word_t crc5, word5; +#endif +#endif +#endif +#endif +#endif + + /* Initialize the CRC for each braid. */ + crc0 = byte_swap(crc); +#if N > 1 + crc1 = 0; +#if N > 2 + crc2 = 0; +#if N > 3 + crc3 = 0; +#if N > 4 + crc4 = 0; +#if N > 5 + crc5 = 0; +#endif +#endif +#endif +#endif +#endif + + /* + Process the first blks-1 blocks, computing the CRCs on each braid + independently. + */ + while (--blks) { + /* Load the word for each braid into registers. */ + word0 = crc0 ^ words[0]; +#if N > 1 + word1 = crc1 ^ words[1]; +#if N > 2 + word2 = crc2 ^ words[2]; +#if N > 3 + word3 = crc3 ^ words[3]; +#if N > 4 + word4 = crc4 ^ words[4]; +#if N > 5 + word5 = crc5 ^ words[5]; +#endif +#endif +#endif +#endif +#endif + words += N; + + /* Compute and update the CRC for each word. The loop should + get unrolled. */ + crc0 = crc_braid_big_table[0][word0 & 0xff]; +#if N > 1 + crc1 = crc_braid_big_table[0][word1 & 0xff]; +#if N > 2 + crc2 = crc_braid_big_table[0][word2 & 0xff]; +#if N > 3 + crc3 = crc_braid_big_table[0][word3 & 0xff]; +#if N > 4 + crc4 = crc_braid_big_table[0][word4 & 0xff]; +#if N > 5 + crc5 = crc_braid_big_table[0][word5 & 0xff]; +#endif +#endif +#endif +#endif +#endif + for (k = 1; k < W; k++) { + crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; +#if N > 1 + crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; +#if N > 2 + crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; +#if N > 3 + crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; +#if N > 4 + crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; +#if N > 5 + crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; +#endif +#endif +#endif +#endif +#endif + } + } + + /* + Process the last block, combining the CRCs of the N braids at the + same time. + */ + comb = crc_word_big(crc0 ^ words[0]); +#if N > 1 + comb = crc_word_big(crc1 ^ words[1] ^ comb); +#if N > 2 + comb = crc_word_big(crc2 ^ words[2] ^ comb); +#if N > 3 + comb = crc_word_big(crc3 ^ words[3] ^ comb); +#if N > 4 + comb = crc_word_big(crc4 ^ words[4] ^ comb); +#if N > 5 + comb = crc_word_big(crc5 ^ words[5] ^ comb); +#endif +#endif +#endif +#endif +#endif + words += N; + crc = byte_swap(comb); + } + + /* + Update the pointer to the remaining bytes to process. + */ + buf = (unsigned char const *)words; + } + +#endif /* W */ + + /* Complete the computation of the CRC on any remaining bytes. */ + while (len >= 8) { + len -= 8; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + while (len) { + len--; + crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; + } + + /* Return the CRC, post-conditioned. */ + return crc ^ 0xffffffff; +} + +#endif + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + return crc32_z(crc, buf, len); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine64(crc1, crc2, (z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen64(len2) + z_off64_t len2; +{ +#ifdef DYNAMIC_CRC_TABLE + once(&made, make_crc_table); +#endif /* DYNAMIC_CRC_TABLE */ + return x2nmodp(len2, 3); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_gen(len2) + z_off_t len2; +{ + return crc32_combine_gen64((z_off64_t)len2); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine_op(crc1, crc2, op) + uLong crc1; + uLong crc2; + uLong op; +{ + return multmodp(op, crc1) ^ (crc2 & 0xffffffff); +} diff --git a/comm/third_party/zlib/crc32.h b/comm/third_party/zlib/crc32.h new file mode 100644 index 0000000000..137df68d61 --- /dev/null +++ b/comm/third_party/zlib/crc32.h @@ -0,0 +1,9446 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}; + +#ifdef W + +#if W == 8 + +local const z_word_t FAR crc_big_table[] = { + 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}; + +#else /* W == 4 */ + +local const z_word_t FAR crc_big_table[] = { + 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}; + +#endif + +#if N == 1 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}, + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, + 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, + 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, + 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, + 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, + 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, + 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, + 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, + 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, + 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, + 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, + 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, + 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, + 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, + 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, + 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, + 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, + 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, + 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, + 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, + 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, + 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, + 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, + 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, + 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, + 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, + 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, + 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, + 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, + 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, + 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, + 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, + 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, + 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, + 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, + 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, + 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, + 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, + 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, + 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, + 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, + 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, + 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, + 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, + 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, + 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, + 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, + 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, + 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, + 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, + 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, + 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, + 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, + 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, + 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, + 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, + 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, + 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, + 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, + 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, + 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, + 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, + 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, + 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, + 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, + 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, + 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, + 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, + 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, + 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, + 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, + 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, + 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, + 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, + 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, + 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, + 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, + 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, + 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, + 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, + 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, + 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, + 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, + 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, + 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, + 0x8def022d00000000}, + {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, + 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, + 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, + 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, + 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, + 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, + 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, + 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, + 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, + 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, + 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, + 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, + 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, + 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, + 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, + 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, + 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, + 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, + 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, + 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, + 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, + 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, + 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, + 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, + 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, + 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, + 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, + 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, + 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, + 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, + 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, + 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, + 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, + 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, + 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, + 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, + 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, + 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, + 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, + 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, + 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, + 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, + 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, + 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, + 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, + 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, + 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, + 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, + 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, + 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, + 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, + 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, + 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, + 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, + 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, + 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, + 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, + 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, + 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, + 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, + 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, + 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, + 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, + 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, + 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, + 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, + 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, + 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, + 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, + 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, + 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, + 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, + 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, + 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, + 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, + 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, + 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, + 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, + 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, + 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, + 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, + 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, + 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, + 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, + 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, + 0x72fd249300000000}, + {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, + 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, + 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, + 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, + 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, + 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, + 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, + 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, + 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, + 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, + 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, + 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, + 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, + 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, + 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, + 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, + 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, + 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, + 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, + 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, + 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, + 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, + 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, + 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, + 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, + 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, + 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, + 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, + 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, + 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, + 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, + 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, + 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, + 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, + 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, + 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, + 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, + 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, + 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, + 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, + 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, + 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, + 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, + 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, + 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, + 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, + 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, + 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, + 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, + 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, + 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, + 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, + 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, + 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, + 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, + 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, + 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, + 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, + 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, + 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, + 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, + 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, + 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, + 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, + 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, + 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, + 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, + 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, + 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, + 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, + 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, + 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, + 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, + 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, + 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, + 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, + 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, + 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, + 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, + 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, + 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, + 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, + 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, + 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, + 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, + 0xed3498be00000000}, + {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, + 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, + 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, + 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, + 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, + 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, + 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, + 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, + 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, + 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, + 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, + 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, + 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, + 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, + 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, + 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, + 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, + 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, + 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, + 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, + 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, + 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, + 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, + 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, + 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, + 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, + 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, + 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, + 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, + 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, + 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, + 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, + 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, + 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, + 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, + 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, + 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, + 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, + 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, + 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, + 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, + 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, + 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, + 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, + 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, + 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, + 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, + 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, + 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, + 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, + 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, + 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, + 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, + 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, + 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, + 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, + 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, + 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, + 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, + 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, + 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, + 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, + 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, + 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, + 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, + 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, + 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, + 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, + 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, + 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, + 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, + 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, + 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, + 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, + 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, + 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, + 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, + 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, + 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, + 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, + 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, + 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, + 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, + 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, + 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, + 0xf10605de00000000}, + {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, + 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, + 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, + 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, + 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, + 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, + 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, + 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, + 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, + 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, + 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, + 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, + 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, + 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, + 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, + 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, + 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, + 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, + 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, + 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, + 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, + 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, + 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, + 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, + 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, + 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, + 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, + 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, + 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, + 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, + 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, + 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, + 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, + 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, + 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, + 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, + 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, + 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, + 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, + 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, + 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, + 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, + 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, + 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, + 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, + 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, + 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, + 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, + 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, + 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, + 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, + 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, + 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, + 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, + 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, + 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, + 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, + 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, + 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, + 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, + 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, + 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, + 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, + 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, + 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, + 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, + 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, + 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, + 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, + 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, + 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, + 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, + 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, + 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, + 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, + 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, + 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, + 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, + 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, + 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, + 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, + 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, + 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, + 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, + 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, + 0x8cc764ca00000000}, + {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, + 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, + 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, + 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, + 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, + 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, + 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, + 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, + 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, + 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, + 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, + 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, + 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, + 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, + 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, + 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, + 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, + 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, + 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, + 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, + 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, + 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, + 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, + 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, + 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, + 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, + 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, + 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, + 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, + 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, + 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, + 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, + 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, + 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, + 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, + 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, + 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, + 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, + 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, + 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, + 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, + 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, + 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, + 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, + 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, + 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, + 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, + 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, + 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, + 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, + 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, + 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, + 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, + 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, + 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, + 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, + 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, + 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, + 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, + 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, + 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, + 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, + 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, + 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, + 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, + 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, + 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, + 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, + 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, + 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, + 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, + 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, + 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, + 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, + 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, + 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, + 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, + 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, + 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, + 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, + 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, + 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, + 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, + 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, + 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, + 0xccabc4e400000000}, + {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, + 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, + 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, + 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, + 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, + 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, + 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, + 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, + 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, + 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, + 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, + 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, + 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, + 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, + 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, + 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, + 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, + 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, + 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, + 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, + 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, + 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, + 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, + 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, + 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, + 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, + 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, + 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, + 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, + 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, + 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, + 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, + 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, + 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, + 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, + 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, + 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, + 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, + 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, + 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, + 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, + 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, + 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, + 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, + 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, + 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, + 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, + 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, + 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, + 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, + 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, + 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, + 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, + 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, + 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, + 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, + 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, + 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, + 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, + 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, + 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, + 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, + 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, + 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, + 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, + 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, + 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, + 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, + 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, + 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, + 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, + 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, + 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, + 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, + 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, + 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, + 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, + 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, + 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, + 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, + 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, + 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, + 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, + 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, + 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, + 0x304a369200000000}, + {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, + 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, + 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, + 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, + 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, + 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, + 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, + 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, + 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, + 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, + 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, + 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, + 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, + 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, + 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, + 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, + 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, + 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, + 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, + 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, + 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, + 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, + 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, + 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, + 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, + 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, + 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, + 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, + 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, + 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, + 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, + 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, + 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, + 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, + 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, + 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, + 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, + 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, + 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, + 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, + 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, + 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, + 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, + 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, + 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, + 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, + 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, + 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, + 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, + 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, + 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, + 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, + 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, + 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, + 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, + 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, + 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, + 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, + 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, + 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, + 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, + 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, + 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, + 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, + 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, + 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, + 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, + 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, + 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, + 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, + 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, + 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, + 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, + 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, + 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, + 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, + 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, + 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, + 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, + 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, + 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, + 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, + 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, + 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, + 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, + 0xe6064b2600000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, + 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, + 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, + 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, + 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, + 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, + 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, + 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, + 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, + 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, + 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, + 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, + 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, + 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, + 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, + 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, + 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, + 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, + 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, + 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, + 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, + 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, + 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, + 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, + 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, + 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, + 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, + 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, + 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, + 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, + 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, + 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, + 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, + 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, + 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, + 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, + 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, + 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, + 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, + 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, + 0xde0506f1}, + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, + 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, + 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, + 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, + 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, + 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, + 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, + 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, + 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, + 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, + 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, + 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, + 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, + 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, + 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, + 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, + 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, + 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, + 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, + 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, + 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, + 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, + 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, + 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, + 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, + 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, + 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, + 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, + 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, + 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, + 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, + 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, + 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, + 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, + 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, + 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, + 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, + 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, + 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, + 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, + 0xbe9834ed}, + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, + 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, + 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, + 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, + 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, + 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, + 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, + 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, + 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, + 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, + 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, + 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, + 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, + 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, + 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, + 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, + 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, + 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, + 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, + 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, + 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, + 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, + 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, + 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, + 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, + 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, + 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, + 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, + 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, + 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, + 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, + 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, + 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, + 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, + 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, + 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, + 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, + 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, + 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, + 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, + 0x9324fd72}, + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, + 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, + 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, + 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, + 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, + 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, + 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, + 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, + 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, + 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, + 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, + 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, + 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, + 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, + 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, + 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, + 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, + 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, + 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, + 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, + 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, + 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, + 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, + 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, + 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, + 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, + 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, + 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, + 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, + 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, + 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, + 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, + 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, + 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, + 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, + 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, + 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, + 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, + 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, + 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, + 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, + 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, + 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, + 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, + 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, + 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, + 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, + 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, + 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, + 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, + 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, + 0x8def022d}, + {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, + 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, + 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, + 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, + 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, + 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, + 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, + 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, + 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, + 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, + 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, + 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, + 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, + 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, + 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, + 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, + 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, + 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, + 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, + 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, + 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, + 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, + 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, + 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, + 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, + 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, + 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, + 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, + 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, + 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, + 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, + 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, + 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, + 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, + 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, + 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, + 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, + 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, + 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, + 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, + 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, + 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, + 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, + 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, + 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, + 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, + 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, + 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, + 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, + 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, + 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, + 0x72fd2493}, + {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, + 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, + 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, + 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, + 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, + 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, + 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, + 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, + 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, + 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, + 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, + 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, + 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, + 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, + 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, + 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, + 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, + 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, + 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, + 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, + 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, + 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, + 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, + 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, + 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, + 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, + 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, + 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, + 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, + 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, + 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, + 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, + 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, + 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, + 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, + 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, + 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, + 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, + 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, + 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, + 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, + 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, + 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, + 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, + 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, + 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, + 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, + 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, + 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, + 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, + 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, + 0xed3498be}, + {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, + 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, + 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, + 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, + 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, + 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, + 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, + 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, + 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, + 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, + 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, + 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, + 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, + 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, + 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, + 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, + 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, + 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, + 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, + 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, + 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, + 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, + 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, + 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, + 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, + 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, + 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, + 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, + 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, + 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, + 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, + 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, + 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, + 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, + 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, + 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, + 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, + 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, + 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, + 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, + 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, + 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, + 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, + 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, + 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, + 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, + 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, + 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, + 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, + 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, + 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, + 0xf10605de}}; + +#endif + +#endif + +#if N == 2 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}, + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, + 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, + 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, + 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, + 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, + 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, + 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, + 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, + 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, + 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, + 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, + 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, + 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, + 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, + 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, + 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, + 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, + 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, + 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, + 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, + 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, + 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, + 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, + 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, + 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, + 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, + 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, + 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, + 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, + 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, + 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, + 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, + 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, + 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, + 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, + 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, + 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, + 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, + 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, + 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, + 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, + 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, + 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, + 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, + 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, + 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, + 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, + 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, + 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, + 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, + 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, + 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, + 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, + 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, + 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, + 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, + 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, + 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, + 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, + 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, + 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, + 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, + 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, + 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, + 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, + 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, + 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, + 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, + 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, + 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, + 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, + 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, + 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, + 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, + 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, + 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, + 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, + 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, + 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, + 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, + 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, + 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, + 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, + 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, + 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, + 0x4b0c4f4900000000}, + {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, + 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, + 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, + 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, + 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, + 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, + 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, + 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, + 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, + 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, + 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, + 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, + 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, + 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, + 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, + 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, + 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, + 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, + 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, + 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, + 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, + 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, + 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, + 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, + 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, + 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, + 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, + 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, + 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, + 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, + 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, + 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, + 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, + 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, + 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, + 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, + 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, + 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, + 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, + 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, + 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, + 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, + 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, + 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, + 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, + 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, + 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, + 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, + 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, + 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, + 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, + 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, + 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, + 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, + 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, + 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, + 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, + 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, + 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, + 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, + 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, + 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, + 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, + 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, + 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, + 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, + 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, + 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, + 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, + 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, + 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, + 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, + 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, + 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, + 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, + 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, + 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, + 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, + 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, + 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, + 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, + 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, + 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, + 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, + 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, + 0x14d747e100000000}, + {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, + 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, + 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, + 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, + 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, + 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, + 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, + 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, + 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, + 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, + 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, + 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, + 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, + 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, + 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, + 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, + 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, + 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, + 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, + 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, + 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, + 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, + 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, + 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, + 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, + 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, + 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, + 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, + 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, + 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, + 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, + 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, + 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, + 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, + 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, + 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, + 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, + 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, + 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, + 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, + 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, + 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, + 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, + 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, + 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, + 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, + 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, + 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, + 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, + 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, + 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, + 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, + 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, + 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, + 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, + 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, + 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, + 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, + 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, + 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, + 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, + 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, + 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, + 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, + 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, + 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, + 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, + 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, + 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, + 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, + 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, + 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, + 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, + 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, + 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, + 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, + 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, + 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, + 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, + 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, + 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, + 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, + 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, + 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, + 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, + 0xaa933b1a00000000}, + {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, + 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, + 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, + 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, + 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, + 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, + 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, + 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, + 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, + 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, + 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, + 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, + 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, + 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, + 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, + 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, + 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, + 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, + 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, + 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, + 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, + 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, + 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, + 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, + 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, + 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, + 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, + 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, + 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, + 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, + 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, + 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, + 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, + 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, + 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, + 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, + 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, + 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, + 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, + 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, + 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, + 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, + 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, + 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, + 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, + 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, + 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, + 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, + 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, + 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, + 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, + 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, + 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, + 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, + 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, + 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, + 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, + 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, + 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, + 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, + 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, + 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, + 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, + 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, + 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, + 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, + 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, + 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, + 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, + 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, + 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, + 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, + 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, + 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, + 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, + 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, + 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, + 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, + 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, + 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, + 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, + 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, + 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, + 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, + 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, + 0x6571193600000000}, + {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, + 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, + 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, + 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, + 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, + 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, + 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, + 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, + 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, + 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, + 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, + 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, + 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, + 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, + 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, + 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, + 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, + 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, + 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, + 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, + 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, + 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, + 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, + 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, + 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, + 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, + 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, + 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, + 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, + 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, + 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, + 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, + 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, + 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, + 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, + 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, + 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, + 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, + 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, + 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, + 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, + 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, + 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, + 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, + 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, + 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, + 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, + 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, + 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, + 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, + 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, + 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, + 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, + 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, + 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, + 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, + 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, + 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, + 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, + 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, + 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, + 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, + 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, + 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, + 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, + 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, + 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, + 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, + 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, + 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, + 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, + 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, + 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, + 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, + 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, + 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, + 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, + 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, + 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, + 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, + 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, + 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, + 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, + 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, + 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, + 0xa68cee3d00000000}, + {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, + 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, + 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, + 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, + 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, + 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, + 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, + 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, + 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, + 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, + 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, + 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, + 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, + 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, + 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, + 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, + 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, + 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, + 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, + 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, + 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, + 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, + 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, + 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, + 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, + 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, + 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, + 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, + 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, + 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, + 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, + 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, + 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, + 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, + 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, + 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, + 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, + 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, + 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, + 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, + 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, + 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, + 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, + 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, + 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, + 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, + 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, + 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, + 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, + 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, + 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, + 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, + 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, + 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, + 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, + 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, + 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, + 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, + 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, + 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, + 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, + 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, + 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, + 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, + 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, + 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, + 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, + 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, + 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, + 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, + 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, + 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, + 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, + 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, + 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, + 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, + 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, + 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, + 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, + 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, + 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, + 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, + 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, + 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, + 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, + 0x51e8883f00000000}, + {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, + 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, + 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, + 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, + 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, + 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, + 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, + 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, + 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, + 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, + 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, + 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, + 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, + 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, + 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, + 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, + 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, + 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, + 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, + 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, + 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, + 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, + 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, + 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, + 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, + 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, + 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, + 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, + 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, + 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, + 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, + 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, + 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, + 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, + 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, + 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, + 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, + 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, + 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, + 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, + 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, + 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, + 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, + 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, + 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, + 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, + 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, + 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, + 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, + 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, + 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, + 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, + 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, + 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, + 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, + 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, + 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, + 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, + 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, + 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, + 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, + 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, + 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, + 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, + 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, + 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, + 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, + 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, + 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, + 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, + 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, + 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, + 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, + 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, + 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, + 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, + 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, + 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, + 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, + 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, + 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, + 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, + 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, + 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, + 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, + 0x8ae9531c00000000}, + {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, + 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, + 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, + 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, + 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, + 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, + 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, + 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, + 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, + 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, + 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, + 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, + 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, + 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, + 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, + 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, + 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, + 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, + 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, + 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, + 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, + 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, + 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, + 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, + 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, + 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, + 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, + 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, + 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, + 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, + 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, + 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, + 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, + 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, + 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, + 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, + 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, + 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, + 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, + 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, + 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, + 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, + 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, + 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, + 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, + 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, + 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, + 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, + 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, + 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, + 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, + 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, + 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, + 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, + 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, + 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, + 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, + 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, + 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, + 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, + 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, + 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, + 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, + 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, + 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, + 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, + 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, + 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, + 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, + 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, + 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, + 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, + 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, + 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, + 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, + 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, + 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, + 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, + 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, + 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, + 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, + 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, + 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, + 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, + 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, + 0xd739710d00000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, + 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, + 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, + 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, + 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, + 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, + 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, + 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, + 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, + 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, + 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, + 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, + 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, + 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, + 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, + 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, + 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, + 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, + 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, + 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, + 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, + 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, + 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, + 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, + 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, + 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, + 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, + 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, + 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, + 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, + 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, + 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, + 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, + 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, + 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, + 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, + 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, + 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, + 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, + 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, + 0x264b06e6}, + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, + 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, + 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, + 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, + 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, + 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, + 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, + 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, + 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, + 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, + 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, + 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, + 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, + 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, + 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, + 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, + 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, + 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, + 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, + 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, + 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, + 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, + 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, + 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, + 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, + 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, + 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, + 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, + 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, + 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, + 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, + 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, + 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, + 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, + 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, + 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, + 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, + 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, + 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, + 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, + 0x92364a30}, + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, + 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, + 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, + 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, + 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, + 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, + 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, + 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, + 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, + 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, + 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, + 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, + 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, + 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, + 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, + 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, + 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, + 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, + 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, + 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, + 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, + 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, + 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, + 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, + 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, + 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, + 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, + 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, + 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, + 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, + 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, + 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, + 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, + 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, + 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, + 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, + 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, + 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, + 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, + 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, + 0xe4c4abcc}, + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, + 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, + 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, + 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, + 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, + 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, + 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, + 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, + 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, + 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, + 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, + 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, + 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, + 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, + 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, + 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, + 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, + 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, + 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, + 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, + 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, + 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, + 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, + 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, + 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, + 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, + 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, + 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, + 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, + 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, + 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, + 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, + 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, + 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, + 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, + 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, + 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, + 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, + 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, + 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, + 0xca64c78c}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, + 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, + 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, + 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, + 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, + 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, + 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, + 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, + 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, + 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, + 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, + 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, + 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, + 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, + 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, + 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, + 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, + 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, + 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, + 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, + 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, + 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, + 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, + 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, + 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, + 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, + 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, + 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, + 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, + 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, + 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, + 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, + 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, + 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, + 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, + 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, + 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, + 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, + 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, + 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, + 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, + 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, + 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, + 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, + 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, + 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, + 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, + 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, + 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, + 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, + 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, + 0x8cc764ca}, + {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, + 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, + 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, + 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, + 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, + 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, + 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, + 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, + 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, + 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, + 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, + 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, + 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, + 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, + 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, + 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, + 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, + 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, + 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, + 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, + 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, + 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, + 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, + 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, + 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, + 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, + 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, + 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, + 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, + 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, + 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, + 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, + 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, + 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, + 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, + 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, + 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, + 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, + 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, + 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, + 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, + 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, + 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, + 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, + 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, + 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, + 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, + 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, + 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, + 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, + 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, + 0xccabc4e4}, + {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, + 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, + 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, + 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, + 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, + 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, + 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, + 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, + 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, + 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, + 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, + 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, + 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, + 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, + 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, + 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, + 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, + 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, + 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, + 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, + 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, + 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, + 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, + 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, + 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, + 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, + 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, + 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, + 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, + 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, + 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, + 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, + 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, + 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, + 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, + 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, + 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, + 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, + 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, + 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, + 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, + 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, + 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, + 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, + 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, + 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, + 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, + 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, + 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, + 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, + 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, + 0x304a3692}, + {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, + 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, + 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, + 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, + 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, + 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, + 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, + 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, + 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, + 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, + 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, + 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, + 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, + 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, + 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, + 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, + 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, + 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, + 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, + 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, + 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, + 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, + 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, + 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, + 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, + 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, + 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, + 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, + 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, + 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, + 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, + 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, + 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, + 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, + 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, + 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, + 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, + 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, + 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, + 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, + 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, + 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, + 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, + 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, + 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, + 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, + 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, + 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, + 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, + 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, + 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, + 0xe6064b26}}; + +#endif + +#endif + +#if N == 3 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}, + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, + 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, + 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, + 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, + 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, + 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, + 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, + 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, + 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, + 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, + 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, + 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, + 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, + 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, + 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, + 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, + 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, + 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, + 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, + 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, + 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, + 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, + 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, + 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, + 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, + 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, + 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, + 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, + 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, + 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, + 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, + 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, + 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, + 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, + 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, + 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, + 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, + 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, + 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, + 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, + 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, + 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, + 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, + 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, + 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, + 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, + 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, + 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, + 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, + 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, + 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, + 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, + 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, + 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, + 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, + 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, + 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, + 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, + 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, + 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, + 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, + 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, + 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, + 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, + 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, + 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, + 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, + 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, + 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, + 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, + 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, + 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, + 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, + 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, + 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, + 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, + 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, + 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, + 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, + 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, + 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, + 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, + 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, + 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, + 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, + 0x4e36ba1800000000}, + {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, + 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, + 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, + 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, + 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, + 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, + 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, + 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, + 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, + 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, + 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, + 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, + 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, + 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, + 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, + 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, + 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, + 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, + 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, + 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, + 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, + 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, + 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, + 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, + 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, + 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, + 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, + 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, + 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, + 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, + 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, + 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, + 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, + 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, + 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, + 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, + 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, + 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, + 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, + 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, + 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, + 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, + 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, + 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, + 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, + 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, + 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, + 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, + 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, + 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, + 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, + 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, + 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, + 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, + 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, + 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, + 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, + 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, + 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, + 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, + 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, + 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, + 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, + 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, + 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, + 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, + 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, + 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, + 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, + 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, + 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, + 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, + 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, + 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, + 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, + 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, + 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, + 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, + 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, + 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, + 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, + 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, + 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, + 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, + 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, + 0xa1d67c9100000000}, + {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, + 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, + 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, + 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, + 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, + 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, + 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, + 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, + 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, + 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, + 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, + 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, + 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, + 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, + 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, + 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, + 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, + 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, + 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, + 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, + 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, + 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, + 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, + 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, + 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, + 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, + 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, + 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, + 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, + 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, + 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, + 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, + 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, + 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, + 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, + 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, + 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, + 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, + 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, + 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, + 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, + 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, + 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, + 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, + 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, + 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, + 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, + 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, + 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, + 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, + 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, + 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, + 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, + 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, + 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, + 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, + 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, + 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, + 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, + 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, + 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, + 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, + 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, + 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, + 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, + 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, + 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, + 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, + 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, + 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, + 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, + 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, + 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, + 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, + 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, + 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, + 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, + 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, + 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, + 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, + 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, + 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, + 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, + 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, + 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, + 0xa8ef40a100000000}, + {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, + 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, + 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, + 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, + 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, + 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, + 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, + 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, + 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, + 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, + 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, + 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, + 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, + 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, + 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, + 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, + 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, + 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, + 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, + 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, + 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, + 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, + 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, + 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, + 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, + 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, + 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, + 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, + 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, + 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, + 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, + 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, + 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, + 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, + 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, + 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, + 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, + 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, + 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, + 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, + 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, + 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, + 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, + 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, + 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, + 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, + 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, + 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, + 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, + 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, + 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, + 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, + 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, + 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, + 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, + 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, + 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, + 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, + 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, + 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, + 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, + 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, + 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, + 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, + 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, + 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, + 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, + 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, + 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, + 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, + 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, + 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, + 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, + 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, + 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, + 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, + 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, + 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, + 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, + 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, + 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, + 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, + 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, + 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, + 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, + 0x356bacd800000000}, + {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, + 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, + 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, + 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, + 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, + 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, + 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, + 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, + 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, + 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, + 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, + 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, + 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, + 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, + 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, + 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, + 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, + 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, + 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, + 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, + 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, + 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, + 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, + 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, + 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, + 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, + 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, + 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, + 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, + 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, + 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, + 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, + 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, + 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, + 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, + 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, + 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, + 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, + 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, + 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, + 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, + 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, + 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, + 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, + 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, + 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, + 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, + 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, + 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, + 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, + 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, + 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, + 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, + 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, + 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, + 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, + 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, + 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, + 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, + 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, + 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, + 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, + 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, + 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, + 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, + 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, + 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, + 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, + 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, + 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, + 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, + 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, + 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, + 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, + 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, + 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, + 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, + 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, + 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, + 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, + 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, + 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, + 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, + 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, + 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, + 0x48686b5600000000}, + {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, + 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, + 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, + 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, + 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, + 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, + 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, + 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, + 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, + 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, + 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, + 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, + 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, + 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, + 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, + 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, + 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, + 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, + 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, + 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, + 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, + 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, + 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, + 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, + 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, + 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, + 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, + 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, + 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, + 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, + 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, + 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, + 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, + 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, + 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, + 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, + 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, + 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, + 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, + 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, + 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, + 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, + 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, + 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, + 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, + 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, + 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, + 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, + 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, + 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, + 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, + 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, + 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, + 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, + 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, + 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, + 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, + 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, + 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, + 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, + 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, + 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, + 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, + 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, + 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, + 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, + 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, + 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, + 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, + 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, + 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, + 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, + 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, + 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, + 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, + 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, + 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, + 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, + 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, + 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, + 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, + 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, + 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, + 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, + 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, + 0xcaa2517800000000}, + {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, + 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, + 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, + 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, + 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, + 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, + 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, + 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, + 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, + 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, + 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, + 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, + 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, + 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, + 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, + 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, + 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, + 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, + 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, + 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, + 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, + 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, + 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, + 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, + 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, + 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, + 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, + 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, + 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, + 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, + 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, + 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, + 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, + 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, + 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, + 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, + 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, + 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, + 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, + 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, + 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, + 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, + 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, + 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, + 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, + 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, + 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, + 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, + 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, + 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, + 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, + 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, + 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, + 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, + 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, + 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, + 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, + 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, + 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, + 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, + 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, + 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, + 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, + 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, + 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, + 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, + 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, + 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, + 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, + 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, + 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, + 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, + 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, + 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, + 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, + 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, + 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, + 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, + 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, + 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, + 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, + 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, + 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, + 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, + 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, + 0x0c7ac97b00000000}, + {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, + 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, + 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, + 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, + 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, + 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, + 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, + 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, + 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, + 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, + 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, + 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, + 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, + 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, + 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, + 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, + 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, + 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, + 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, + 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, + 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, + 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, + 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, + 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, + 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, + 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, + 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, + 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, + 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, + 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, + 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, + 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, + 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, + 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, + 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, + 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, + 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, + 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, + 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, + 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, + 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, + 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, + 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, + 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, + 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, + 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, + 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, + 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, + 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, + 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, + 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, + 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, + 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, + 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, + 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, + 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, + 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, + 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, + 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, + 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, + 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, + 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, + 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, + 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, + 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, + 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, + 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, + 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, + 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, + 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, + 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, + 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, + 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, + 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, + 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, + 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, + 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, + 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, + 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, + 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, + 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, + 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, + 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, + 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, + 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, + 0x5185cd0900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, + 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, + 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, + 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, + 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, + 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, + 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, + 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, + 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, + 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, + 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, + 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, + 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, + 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, + 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, + 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, + 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, + 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, + 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, + 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, + 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, + 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, + 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, + 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, + 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, + 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, + 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, + 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, + 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, + 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, + 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, + 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, + 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, + 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, + 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, + 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, + 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, + 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, + 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, + 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, + 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, + 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, + 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, + 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, + 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, + 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, + 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, + 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, + 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, + 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, + 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, + 0x36197165}, + {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, + 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, + 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, + 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, + 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, + 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, + 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, + 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, + 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, + 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, + 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, + 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, + 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, + 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, + 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, + 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, + 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, + 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, + 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, + 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, + 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, + 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, + 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, + 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, + 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, + 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, + 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, + 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, + 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, + 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, + 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, + 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, + 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, + 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, + 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, + 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, + 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, + 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, + 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, + 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, + 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, + 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, + 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, + 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, + 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, + 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, + 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, + 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, + 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, + 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, + 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, + 0x1a3b93aa}, + {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, + 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, + 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, + 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, + 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, + 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, + 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, + 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, + 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, + 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, + 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, + 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, + 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, + 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, + 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, + 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, + 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, + 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, + 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, + 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, + 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, + 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, + 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, + 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, + 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, + 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, + 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, + 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, + 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, + 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, + 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, + 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, + 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, + 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, + 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, + 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, + 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, + 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, + 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, + 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, + 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, + 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, + 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, + 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, + 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, + 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, + 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, + 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, + 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, + 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, + 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, + 0xe147d714}, + {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, + 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, + 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, + 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, + 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, + 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, + 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, + 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, + 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, + 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, + 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, + 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, + 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, + 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, + 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, + 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, + 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, + 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, + 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, + 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, + 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, + 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, + 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, + 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, + 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, + 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, + 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, + 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, + 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, + 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, + 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, + 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, + 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, + 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, + 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, + 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, + 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, + 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, + 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, + 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, + 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, + 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, + 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, + 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, + 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, + 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, + 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, + 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, + 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, + 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, + 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, + 0x494f0c4b}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, + 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, + 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, + 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, + 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, + 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, + 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, + 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, + 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, + 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, + 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, + 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, + 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, + 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, + 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, + 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, + 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, + 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, + 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, + 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, + 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, + 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, + 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, + 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, + 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, + 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, + 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, + 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, + 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, + 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, + 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, + 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, + 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, + 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, + 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, + 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, + 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, + 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, + 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, + 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, + 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, + 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, + 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, + 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, + 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, + 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, + 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, + 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, + 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, + 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, + 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, + 0x4b0c4f49}, + {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, + 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, + 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, + 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, + 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, + 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, + 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, + 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, + 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, + 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, + 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, + 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, + 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, + 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, + 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, + 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, + 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, + 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, + 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, + 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, + 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, + 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, + 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, + 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, + 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, + 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, + 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, + 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, + 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, + 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, + 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, + 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, + 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, + 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, + 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, + 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, + 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, + 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, + 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, + 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, + 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, + 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, + 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, + 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, + 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, + 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, + 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, + 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, + 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, + 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, + 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, + 0x14d747e1}, + {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, + 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, + 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, + 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, + 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, + 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, + 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, + 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, + 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, + 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, + 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, + 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, + 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, + 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, + 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, + 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, + 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, + 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, + 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, + 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, + 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, + 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, + 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, + 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, + 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, + 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, + 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, + 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, + 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, + 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, + 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, + 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, + 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, + 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, + 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, + 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, + 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, + 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, + 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, + 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, + 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, + 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, + 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, + 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, + 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, + 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, + 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, + 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, + 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, + 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, + 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, + 0xaa933b1a}, + {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, + 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, + 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, + 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, + 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, + 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, + 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, + 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, + 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, + 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, + 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, + 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, + 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, + 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, + 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, + 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, + 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, + 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, + 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, + 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, + 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, + 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, + 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, + 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, + 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, + 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, + 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, + 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, + 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, + 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, + 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, + 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, + 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, + 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, + 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, + 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, + 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, + 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, + 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, + 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, + 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, + 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, + 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, + 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, + 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, + 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, + 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, + 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, + 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, + 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, + 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, + 0x65711936}}; + +#endif + +#endif + +#if N == 4 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, + 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, + 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, + 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, + 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, + 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, + 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, + 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, + 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, + 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, + 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, + 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, + 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, + 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, + 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, + 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, + 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, + 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, + 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, + 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, + 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, + 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, + 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, + 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, + 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, + 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, + 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, + 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, + 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, + 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, + 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, + 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, + 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, + 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, + 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, + 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, + 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, + 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, + 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, + 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, + 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, + 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, + 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, + 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, + 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, + 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, + 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, + 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, + 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, + 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, + 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, + 0xe3c45916}, + {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, + 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, + 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, + 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, + 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, + 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, + 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, + 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, + 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, + 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, + 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, + 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, + 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, + 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, + 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, + 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, + 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, + 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, + 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, + 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, + 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, + 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, + 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, + 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, + 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, + 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, + 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, + 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, + 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, + 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, + 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, + 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, + 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, + 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, + 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, + 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, + 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, + 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, + 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, + 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, + 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, + 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, + 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, + 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, + 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, + 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, + 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, + 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, + 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, + 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, + 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, + 0xa7520488}, + {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, + 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, + 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, + 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, + 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, + 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, + 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, + 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, + 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, + 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, + 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, + 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, + 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, + 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, + 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, + 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, + 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, + 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, + 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, + 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, + 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, + 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, + 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, + 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, + 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, + 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, + 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, + 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, + 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, + 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, + 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, + 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, + 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, + 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, + 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, + 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, + 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, + 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, + 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, + 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, + 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, + 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, + 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, + 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, + 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, + 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, + 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, + 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, + 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, + 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, + 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, + 0x3522e9e4}, + {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, + 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, + 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, + 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, + 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, + 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, + 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, + 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, + 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, + 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, + 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, + 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, + 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, + 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, + 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, + 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, + 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, + 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, + 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, + 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, + 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, + 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, + 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, + 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, + 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, + 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, + 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, + 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, + 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, + 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, + 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, + 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, + 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, + 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, + 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, + 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, + 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, + 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, + 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, + 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, + 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, + 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, + 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, + 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, + 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, + 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, + 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, + 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, + 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, + 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, + 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, + 0x97411e28}, + {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, + 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, + 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, + 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, + 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, + 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, + 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, + 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, + 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, + 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, + 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, + 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, + 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, + 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, + 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, + 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, + 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, + 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, + 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, + 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, + 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, + 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, + 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, + 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, + 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, + 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, + 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, + 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, + 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, + 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, + 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, + 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, + 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, + 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, + 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, + 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, + 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, + 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, + 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, + 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, + 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, + 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, + 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, + 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, + 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, + 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, + 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, + 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, + 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, + 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, + 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, + 0x93c7a00b}, + {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, + 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, + 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, + 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, + 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, + 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, + 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, + 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, + 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, + 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, + 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, + 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, + 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, + 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, + 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, + 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, + 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, + 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, + 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, + 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, + 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, + 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, + 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, + 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, + 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, + 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, + 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, + 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, + 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, + 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, + 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, + 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, + 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, + 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, + 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, + 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, + 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, + 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, + 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, + 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, + 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, + 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, + 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, + 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, + 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, + 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, + 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, + 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, + 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, + 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, + 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, + 0xce5f968d}, + {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, + 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, + 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, + 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, + 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, + 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, + 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, + 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, + 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, + 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, + 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, + 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, + 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, + 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, + 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, + 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, + 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, + 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, + 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, + 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, + 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, + 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, + 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, + 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, + 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, + 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, + 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, + 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, + 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, + 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, + 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, + 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, + 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, + 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, + 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, + 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, + 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, + 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, + 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, + 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, + 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, + 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, + 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, + 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, + 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, + 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, + 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, + 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, + 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, + 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, + 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, + 0x3e721277}, + {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, + 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, + 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, + 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, + 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, + 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, + 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, + 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, + 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, + 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, + 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, + 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, + 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, + 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, + 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, + 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, + 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, + 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, + 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, + 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, + 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, + 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, + 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, + 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, + 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, + 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, + 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, + 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, + 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, + 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, + 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, + 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, + 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, + 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, + 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, + 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, + 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, + 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, + 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, + 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, + 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, + 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, + 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, + 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, + 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, + 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, + 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, + 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, + 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, + 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, + 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, + 0x1c65ace7}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, + 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, + 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, + 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, + 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, + 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, + 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, + 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, + 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, + 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, + 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, + 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, + 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, + 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, + 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, + 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, + 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, + 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, + 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, + 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, + 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, + 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, + 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, + 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, + 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, + 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, + 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, + 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, + 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, + 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, + 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, + 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, + 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, + 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, + 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, + 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, + 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, + 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, + 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, + 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, + 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, + 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, + 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, + 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, + 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, + 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, + 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, + 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, + 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, + 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, + 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, + 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, + 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, + 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, + 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, + 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, + 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, + 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, + 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, + 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, + 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, + 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, + 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, + 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, + 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, + 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, + 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, + 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, + 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, + 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, + 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, + 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, + 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, + 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, + 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, + 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, + 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, + 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, + 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, + 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, + 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, + 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, + 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, + 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, + 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, + 0xe7ac651c00000000}, + {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, + 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, + 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, + 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, + 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, + 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, + 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, + 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, + 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, + 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, + 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, + 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, + 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, + 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, + 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, + 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, + 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, + 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, + 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, + 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, + 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, + 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, + 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, + 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, + 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, + 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, + 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, + 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, + 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, + 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, + 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, + 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, + 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, + 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, + 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, + 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, + 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, + 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, + 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, + 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, + 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, + 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, + 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, + 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, + 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, + 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, + 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, + 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, + 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, + 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, + 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, + 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, + 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, + 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, + 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, + 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, + 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, + 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, + 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, + 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, + 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, + 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, + 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, + 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, + 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, + 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, + 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, + 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, + 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, + 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, + 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, + 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, + 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, + 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, + 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, + 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, + 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, + 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, + 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, + 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, + 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, + 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, + 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, + 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, + 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, + 0x7712723e00000000}, + {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, + 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, + 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, + 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, + 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, + 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, + 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, + 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, + 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, + 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, + 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, + 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, + 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, + 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, + 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, + 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, + 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, + 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, + 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, + 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, + 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, + 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, + 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, + 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, + 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, + 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, + 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, + 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, + 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, + 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, + 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, + 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, + 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, + 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, + 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, + 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, + 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, + 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, + 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, + 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, + 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, + 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, + 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, + 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, + 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, + 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, + 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, + 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, + 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, + 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, + 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, + 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, + 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, + 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, + 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, + 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, + 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, + 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, + 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, + 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, + 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, + 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, + 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, + 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, + 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, + 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, + 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, + 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, + 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, + 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, + 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, + 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, + 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, + 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, + 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, + 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, + 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, + 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, + 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, + 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, + 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, + 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, + 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, + 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, + 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, + 0x8d965fce00000000}, + {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, + 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, + 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, + 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, + 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, + 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, + 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, + 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, + 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, + 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, + 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, + 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, + 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, + 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, + 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, + 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, + 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, + 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, + 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, + 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, + 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, + 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, + 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, + 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, + 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, + 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, + 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, + 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, + 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, + 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, + 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, + 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, + 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, + 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, + 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, + 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, + 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, + 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, + 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, + 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, + 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, + 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, + 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, + 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, + 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, + 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, + 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, + 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, + 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, + 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, + 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, + 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, + 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, + 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, + 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, + 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, + 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, + 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, + 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, + 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, + 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, + 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, + 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, + 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, + 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, + 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, + 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, + 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, + 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, + 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, + 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, + 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, + 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, + 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, + 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, + 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, + 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, + 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, + 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, + 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, + 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, + 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, + 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, + 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, + 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, + 0x0ba0c79300000000}, + {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, + 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, + 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, + 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, + 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, + 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, + 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, + 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, + 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, + 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, + 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, + 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, + 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, + 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, + 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, + 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, + 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, + 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, + 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, + 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, + 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, + 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, + 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, + 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, + 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, + 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, + 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, + 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, + 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, + 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, + 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, + 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, + 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, + 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, + 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, + 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, + 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, + 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, + 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, + 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, + 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, + 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, + 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, + 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, + 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, + 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, + 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, + 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, + 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, + 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, + 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, + 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, + 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, + 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, + 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, + 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, + 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, + 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, + 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, + 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, + 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, + 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, + 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, + 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, + 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, + 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, + 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, + 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, + 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, + 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, + 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, + 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, + 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, + 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, + 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, + 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, + 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, + 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, + 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, + 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, + 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, + 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, + 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, + 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, + 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, + 0x281e419700000000}, + {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, + 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, + 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, + 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, + 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, + 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, + 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, + 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, + 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, + 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, + 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, + 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, + 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, + 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, + 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, + 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, + 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, + 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, + 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, + 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, + 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, + 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, + 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, + 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, + 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, + 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, + 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, + 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, + 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, + 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, + 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, + 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, + 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, + 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, + 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, + 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, + 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, + 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, + 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, + 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, + 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, + 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, + 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, + 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, + 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, + 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, + 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, + 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, + 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, + 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, + 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, + 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, + 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, + 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, + 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, + 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, + 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, + 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, + 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, + 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, + 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, + 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, + 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, + 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, + 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, + 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, + 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, + 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, + 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, + 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, + 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, + 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, + 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, + 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, + 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, + 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, + 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, + 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, + 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, + 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, + 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, + 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, + 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, + 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, + 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, + 0xe4e9223500000000}, + {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, + 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, + 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, + 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, + 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, + 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, + 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, + 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, + 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, + 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, + 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, + 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, + 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, + 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, + 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, + 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, + 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, + 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, + 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, + 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, + 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, + 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, + 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, + 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, + 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, + 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, + 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, + 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, + 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, + 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, + 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, + 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, + 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, + 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, + 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, + 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, + 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, + 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, + 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, + 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, + 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, + 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, + 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, + 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, + 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, + 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, + 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, + 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, + 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, + 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, + 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, + 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, + 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, + 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, + 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, + 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, + 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, + 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, + 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, + 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, + 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, + 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, + 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, + 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, + 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, + 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, + 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, + 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, + 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, + 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, + 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, + 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, + 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, + 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, + 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, + 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, + 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, + 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, + 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, + 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, + 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, + 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, + 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, + 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, + 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, + 0x880452a700000000}, + {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, + 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, + 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, + 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, + 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, + 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, + 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, + 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, + 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, + 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, + 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, + 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, + 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, + 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, + 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, + 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, + 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, + 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, + 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, + 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, + 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, + 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, + 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, + 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, + 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, + 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, + 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, + 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, + 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, + 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, + 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, + 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, + 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, + 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, + 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, + 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, + 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, + 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, + 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, + 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, + 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, + 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, + 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, + 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, + 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, + 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, + 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, + 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, + 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, + 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, + 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, + 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, + 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, + 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, + 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, + 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, + 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, + 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, + 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, + 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, + 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, + 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, + 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, + 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, + 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, + 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, + 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, + 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, + 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, + 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, + 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, + 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, + 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, + 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, + 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, + 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, + 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, + 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, + 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, + 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, + 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, + 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, + 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, + 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, + 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, + 0x1659c4e300000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, + 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, + 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, + 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, + 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, + 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, + 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, + 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, + 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, + 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, + 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, + 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, + 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, + 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, + 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, + 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, + 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, + 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, + 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, + 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, + 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, + 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, + 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, + 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, + 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, + 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, + 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, + 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, + 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, + 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, + 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, + 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, + 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, + 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, + 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, + 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, + 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, + 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, + 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, + 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, + 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, + 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, + 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, + 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, + 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, + 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, + 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, + 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, + 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, + 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, + 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, + 0x0d7139d7}, + {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, + 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, + 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, + 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, + 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, + 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, + 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, + 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, + 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, + 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, + 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, + 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, + 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, + 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, + 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, + 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, + 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, + 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, + 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, + 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, + 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, + 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, + 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, + 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, + 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, + 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, + 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, + 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, + 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, + 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, + 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, + 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, + 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, + 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, + 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, + 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, + 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, + 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, + 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, + 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, + 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, + 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, + 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, + 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, + 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, + 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, + 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, + 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, + 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, + 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, + 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, + 0x1c53e98a}, + {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, + 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, + 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, + 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, + 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, + 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, + 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, + 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, + 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, + 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, + 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, + 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, + 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, + 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, + 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, + 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, + 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, + 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, + 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, + 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, + 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, + 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, + 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, + 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, + 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, + 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, + 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, + 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, + 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, + 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, + 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, + 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, + 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, + 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, + 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, + 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, + 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, + 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, + 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, + 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, + 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, + 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, + 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, + 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, + 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, + 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, + 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, + 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, + 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, + 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, + 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, + 0x3f88e851}, + {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, + 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, + 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, + 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, + 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, + 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, + 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, + 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, + 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, + 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, + 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, + 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, + 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, + 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, + 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, + 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, + 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, + 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, + 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, + 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, + 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, + 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, + 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, + 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, + 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, + 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, + 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, + 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, + 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, + 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, + 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, + 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, + 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, + 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, + 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, + 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, + 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, + 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, + 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, + 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, + 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, + 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, + 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, + 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, + 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, + 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, + 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, + 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, + 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, + 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, + 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, + 0x3dee8ca6}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, + 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, + 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, + 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, + 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, + 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, + 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, + 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, + 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, + 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, + 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, + 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, + 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, + 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, + 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, + 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, + 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, + 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, + 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, + 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, + 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, + 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, + 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, + 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, + 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, + 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, + 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, + 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, + 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, + 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, + 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, + 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, + 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, + 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, + 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, + 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, + 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, + 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, + 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, + 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, + 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, + 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, + 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, + 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, + 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, + 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, + 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, + 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, + 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, + 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, + 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, + 0xa68cee3d}, + {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, + 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, + 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, + 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, + 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, + 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, + 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, + 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, + 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, + 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, + 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, + 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, + 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, + 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, + 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, + 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, + 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, + 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, + 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, + 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, + 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, + 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, + 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, + 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, + 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, + 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, + 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, + 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, + 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, + 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, + 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, + 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, + 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, + 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, + 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, + 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, + 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, + 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, + 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, + 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, + 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, + 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, + 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, + 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, + 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, + 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, + 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, + 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, + 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, + 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, + 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, + 0x51e8883f}, + {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, + 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, + 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, + 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, + 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, + 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, + 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, + 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, + 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, + 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, + 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, + 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, + 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, + 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, + 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, + 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, + 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, + 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, + 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, + 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, + 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, + 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, + 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, + 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, + 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, + 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, + 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, + 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, + 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, + 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, + 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, + 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, + 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, + 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, + 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, + 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, + 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, + 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, + 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, + 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, + 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, + 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, + 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, + 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, + 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, + 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, + 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, + 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, + 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, + 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, + 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, + 0x8ae9531c}, + {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, + 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, + 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, + 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, + 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, + 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, + 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, + 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, + 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, + 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, + 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, + 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, + 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, + 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, + 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, + 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, + 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, + 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, + 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, + 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, + 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, + 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, + 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, + 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, + 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, + 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, + 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, + 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, + 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, + 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, + 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, + 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, + 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, + 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, + 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, + 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, + 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, + 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, + 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, + 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, + 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, + 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, + 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, + 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, + 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, + 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, + 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, + 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, + 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, + 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, + 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, + 0xd739710d}}; + +#endif + +#endif + +#if N == 5 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, + 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, + 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, + 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, + 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, + 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, + 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, + 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, + 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, + 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, + 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, + 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, + 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, + 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, + 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, + 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, + 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, + 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, + 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, + 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, + 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, + 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, + 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, + 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, + 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, + 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, + 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, + 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, + 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, + 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, + 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, + 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, + 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, + 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, + 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, + 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, + 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, + 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, + 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, + 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, + 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, + 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, + 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, + 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, + 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, + 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, + 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, + 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, + 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, + 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, + 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, + 0xe9947565}, + {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, + 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, + 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, + 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, + 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, + 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, + 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, + 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, + 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, + 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, + 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, + 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, + 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, + 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, + 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, + 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, + 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, + 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, + 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, + 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, + 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, + 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, + 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, + 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, + 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, + 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, + 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, + 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, + 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, + 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, + 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, + 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, + 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, + 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, + 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, + 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, + 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, + 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, + 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, + 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, + 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, + 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, + 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, + 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, + 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, + 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, + 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, + 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, + 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, + 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, + 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, + 0xf7d05006}, + {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, + 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, + 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, + 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, + 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, + 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, + 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, + 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, + 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, + 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, + 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, + 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, + 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, + 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, + 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, + 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, + 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, + 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, + 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, + 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, + 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, + 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, + 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, + 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, + 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, + 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, + 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, + 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, + 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, + 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, + 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, + 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, + 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, + 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, + 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, + 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, + 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, + 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, + 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, + 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, + 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, + 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, + 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, + 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, + 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, + 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, + 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, + 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, + 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, + 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, + 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, + 0xb2075b94}, + {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, + 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, + 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, + 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, + 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, + 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, + 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, + 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, + 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, + 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, + 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, + 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, + 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, + 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, + 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, + 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, + 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, + 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, + 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, + 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, + 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, + 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, + 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, + 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, + 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, + 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, + 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, + 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, + 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, + 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, + 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, + 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, + 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, + 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, + 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, + 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, + 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, + 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, + 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, + 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, + 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, + 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, + 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, + 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, + 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, + 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, + 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, + 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, + 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, + 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, + 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, + 0xba50bcb9}, + {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, + 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, + 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, + 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, + 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, + 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, + 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, + 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, + 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, + 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, + 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, + 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, + 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, + 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, + 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, + 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, + 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, + 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, + 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, + 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, + 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, + 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, + 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, + 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, + 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, + 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, + 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, + 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, + 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, + 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, + 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, + 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, + 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, + 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, + 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, + 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, + 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, + 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, + 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, + 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, + 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, + 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, + 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, + 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, + 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, + 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, + 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, + 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, + 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, + 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, + 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, + 0x808abcf4}, + {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, + 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, + 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, + 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, + 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, + 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, + 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, + 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, + 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, + 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, + 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, + 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, + 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, + 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, + 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, + 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, + 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, + 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, + 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, + 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, + 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, + 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, + 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, + 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, + 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, + 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, + 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, + 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, + 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, + 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, + 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, + 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, + 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, + 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, + 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, + 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, + 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, + 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, + 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, + 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, + 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, + 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, + 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, + 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, + 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, + 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, + 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, + 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, + 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, + 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, + 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, + 0xefdb3f95}, + {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, + 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, + 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, + 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, + 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, + 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, + 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, + 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, + 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, + 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, + 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, + 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, + 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, + 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, + 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, + 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, + 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, + 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, + 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, + 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, + 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, + 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, + 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, + 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, + 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, + 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, + 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, + 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, + 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, + 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, + 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, + 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, + 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, + 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, + 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, + 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, + 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, + 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, + 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, + 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, + 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, + 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, + 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, + 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, + 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, + 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, + 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, + 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, + 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, + 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, + 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, + 0x0e2fbf43}, + {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, + 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, + 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, + 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, + 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, + 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, + 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, + 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, + 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, + 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, + 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, + 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, + 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, + 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, + 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, + 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, + 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, + 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, + 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, + 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, + 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, + 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, + 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, + 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, + 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, + 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, + 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, + 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, + 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, + 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, + 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, + 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, + 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, + 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, + 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, + 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, + 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, + 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, + 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, + 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, + 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, + 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, + 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, + 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, + 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, + 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, + 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, + 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, + 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, + 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, + 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, + 0xf4377108}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, + 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, + 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, + 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, + 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, + 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, + 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, + 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, + 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, + 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, + 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, + 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, + 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, + 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, + 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, + 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, + 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, + 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, + 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, + 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, + 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, + 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, + 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, + 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, + 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, + 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, + 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, + 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, + 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, + 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, + 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, + 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, + 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, + 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, + 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, + 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, + 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, + 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, + 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, + 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, + 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, + 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, + 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, + 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, + 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, + 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, + 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, + 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, + 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, + 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, + 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, + 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, + 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, + 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, + 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, + 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, + 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, + 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, + 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, + 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, + 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, + 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, + 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, + 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, + 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, + 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, + 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, + 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, + 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, + 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, + 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, + 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, + 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, + 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, + 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, + 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, + 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, + 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, + 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, + 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, + 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, + 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, + 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, + 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, + 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, + 0x087137f400000000}, + {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, + 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, + 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, + 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, + 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, + 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, + 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, + 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, + 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, + 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, + 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, + 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, + 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, + 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, + 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, + 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, + 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, + 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, + 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, + 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, + 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, + 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, + 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, + 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, + 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, + 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, + 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, + 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, + 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, + 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, + 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, + 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, + 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, + 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, + 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, + 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, + 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, + 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, + 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, + 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, + 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, + 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, + 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, + 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, + 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, + 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, + 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, + 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, + 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, + 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, + 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, + 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, + 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, + 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, + 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, + 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, + 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, + 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, + 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, + 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, + 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, + 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, + 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, + 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, + 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, + 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, + 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, + 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, + 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, + 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, + 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, + 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, + 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, + 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, + 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, + 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, + 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, + 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, + 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, + 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, + 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, + 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, + 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, + 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, + 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, + 0x43bf2f0e00000000}, + {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, + 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, + 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, + 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, + 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, + 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, + 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, + 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, + 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, + 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, + 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, + 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, + 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, + 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, + 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, + 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, + 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, + 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, + 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, + 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, + 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, + 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, + 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, + 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, + 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, + 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, + 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, + 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, + 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, + 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, + 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, + 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, + 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, + 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, + 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, + 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, + 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, + 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, + 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, + 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, + 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, + 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, + 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, + 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, + 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, + 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, + 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, + 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, + 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, + 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, + 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, + 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, + 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, + 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, + 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, + 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, + 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, + 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, + 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, + 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, + 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, + 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, + 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, + 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, + 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, + 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, + 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, + 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, + 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, + 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, + 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, + 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, + 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, + 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, + 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, + 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, + 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, + 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, + 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, + 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, + 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, + 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, + 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, + 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, + 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, + 0x953fdbef00000000}, + {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, + 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, + 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, + 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, + 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, + 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, + 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, + 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, + 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, + 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, + 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, + 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, + 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, + 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, + 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, + 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, + 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, + 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, + 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, + 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, + 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, + 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, + 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, + 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, + 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, + 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, + 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, + 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, + 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, + 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, + 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, + 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, + 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, + 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, + 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, + 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, + 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, + 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, + 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, + 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, + 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, + 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, + 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, + 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, + 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, + 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, + 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, + 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, + 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, + 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, + 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, + 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, + 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, + 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, + 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, + 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, + 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, + 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, + 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, + 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, + 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, + 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, + 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, + 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, + 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, + 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, + 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, + 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, + 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, + 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, + 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, + 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, + 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, + 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, + 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, + 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, + 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, + 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, + 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, + 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, + 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, + 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, + 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, + 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, + 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, + 0xf4bc8a8000000000}, + {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, + 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, + 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, + 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, + 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, + 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, + 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, + 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, + 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, + 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, + 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, + 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, + 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, + 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, + 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, + 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, + 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, + 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, + 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, + 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, + 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, + 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, + 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, + 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, + 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, + 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, + 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, + 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, + 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, + 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, + 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, + 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, + 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, + 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, + 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, + 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, + 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, + 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, + 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, + 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, + 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, + 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, + 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, + 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, + 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, + 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, + 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, + 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, + 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, + 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, + 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, + 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, + 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, + 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, + 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, + 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, + 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, + 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, + 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, + 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, + 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, + 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, + 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, + 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, + 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, + 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, + 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, + 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, + 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, + 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, + 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, + 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, + 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, + 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, + 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, + 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, + 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, + 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, + 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, + 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, + 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, + 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, + 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, + 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, + 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, + 0xb9bc50ba00000000}, + {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, + 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, + 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, + 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, + 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, + 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, + 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, + 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, + 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, + 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, + 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, + 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, + 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, + 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, + 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, + 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, + 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, + 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, + 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, + 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, + 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, + 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, + 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, + 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, + 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, + 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, + 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, + 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, + 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, + 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, + 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, + 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, + 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, + 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, + 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, + 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, + 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, + 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, + 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, + 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, + 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, + 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, + 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, + 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, + 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, + 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, + 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, + 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, + 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, + 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, + 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, + 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, + 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, + 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, + 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, + 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, + 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, + 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, + 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, + 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, + 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, + 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, + 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, + 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, + 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, + 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, + 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, + 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, + 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, + 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, + 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, + 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, + 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, + 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, + 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, + 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, + 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, + 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, + 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, + 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, + 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, + 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, + 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, + 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, + 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, + 0x945b07b200000000}, + {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, + 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, + 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, + 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, + 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, + 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, + 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, + 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, + 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, + 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, + 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, + 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, + 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, + 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, + 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, + 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, + 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, + 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, + 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, + 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, + 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, + 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, + 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, + 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, + 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, + 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, + 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, + 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, + 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, + 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, + 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, + 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, + 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, + 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, + 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, + 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, + 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, + 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, + 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, + 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, + 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, + 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, + 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, + 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, + 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, + 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, + 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, + 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, + 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, + 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, + 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, + 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, + 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, + 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, + 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, + 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, + 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, + 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, + 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, + 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, + 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, + 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, + 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, + 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, + 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, + 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, + 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, + 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, + 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, + 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, + 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, + 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, + 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, + 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, + 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, + 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, + 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, + 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, + 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, + 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, + 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, + 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, + 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, + 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, + 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, + 0x0650d0f700000000}, + {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, + 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, + 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, + 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, + 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, + 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, + 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, + 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, + 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, + 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, + 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, + 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, + 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, + 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, + 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, + 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, + 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, + 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, + 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, + 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, + 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, + 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, + 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, + 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, + 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, + 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, + 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, + 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, + 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, + 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, + 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, + 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, + 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, + 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, + 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, + 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, + 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, + 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, + 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, + 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, + 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, + 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, + 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, + 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, + 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, + 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, + 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, + 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, + 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, + 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, + 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, + 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, + 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, + 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, + 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, + 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, + 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, + 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, + 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, + 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, + 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, + 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, + 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, + 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, + 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, + 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, + 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, + 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, + 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, + 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, + 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, + 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, + 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, + 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, + 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, + 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, + 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, + 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, + 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, + 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, + 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, + 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, + 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, + 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, + 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, + 0x657594e900000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, + 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, + 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, + 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, + 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, + 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, + 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, + 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, + 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, + 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, + 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, + 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, + 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, + 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, + 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, + 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, + 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, + 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, + 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, + 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, + 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, + 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, + 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, + 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, + 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, + 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, + 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, + 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, + 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, + 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, + 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, + 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, + 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, + 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, + 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, + 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, + 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, + 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, + 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, + 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, + 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, + 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, + 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, + 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, + 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, + 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, + 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, + 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, + 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, + 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, + 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, + 0xd8ac6b35}, + {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, + 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, + 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, + 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, + 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, + 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, + 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, + 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, + 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, + 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, + 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, + 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, + 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, + 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, + 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, + 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, + 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, + 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, + 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, + 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, + 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, + 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, + 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, + 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, + 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, + 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, + 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, + 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, + 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, + 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, + 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, + 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, + 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, + 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, + 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, + 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, + 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, + 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, + 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, + 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, + 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, + 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, + 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, + 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, + 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, + 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, + 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, + 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, + 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, + 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, + 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, + 0xa140efa8}, + {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, + 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, + 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, + 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, + 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, + 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, + 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, + 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, + 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, + 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, + 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, + 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, + 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, + 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, + 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, + 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, + 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, + 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, + 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, + 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, + 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, + 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, + 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, + 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, + 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, + 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, + 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, + 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, + 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, + 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, + 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, + 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, + 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, + 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, + 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, + 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, + 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, + 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, + 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, + 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, + 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, + 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, + 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, + 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, + 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, + 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, + 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, + 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, + 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, + 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, + 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, + 0x917cd6a1}, + {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, + 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, + 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, + 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, + 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, + 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, + 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, + 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, + 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, + 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, + 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, + 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, + 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, + 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, + 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, + 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, + 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, + 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, + 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, + 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, + 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, + 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, + 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, + 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, + 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, + 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, + 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, + 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, + 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, + 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, + 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, + 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, + 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, + 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, + 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, + 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, + 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, + 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, + 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, + 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, + 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, + 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, + 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, + 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, + 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, + 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, + 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, + 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, + 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, + 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, + 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, + 0x18ba364e}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, + 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, + 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, + 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, + 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, + 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, + 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, + 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, + 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, + 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, + 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, + 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, + 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, + 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, + 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, + 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, + 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, + 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, + 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, + 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, + 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, + 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, + 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, + 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, + 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, + 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, + 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, + 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, + 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, + 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, + 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, + 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, + 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, + 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, + 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, + 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, + 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, + 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, + 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, + 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, + 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, + 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, + 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, + 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, + 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, + 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, + 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, + 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, + 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, + 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, + 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, + 0x4e36ba18}, + {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, + 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, + 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, + 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, + 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, + 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, + 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, + 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, + 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, + 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, + 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, + 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, + 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, + 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, + 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, + 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, + 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, + 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, + 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, + 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, + 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, + 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, + 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, + 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, + 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, + 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, + 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, + 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, + 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, + 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, + 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, + 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, + 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, + 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, + 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, + 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, + 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, + 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, + 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, + 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, + 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, + 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, + 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, + 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, + 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, + 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, + 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, + 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, + 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, + 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, + 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, + 0xa1d67c91}, + {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, + 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, + 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, + 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, + 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, + 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, + 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, + 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, + 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, + 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, + 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, + 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, + 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, + 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, + 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, + 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, + 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, + 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, + 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, + 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, + 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, + 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, + 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, + 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, + 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, + 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, + 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, + 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, + 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, + 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, + 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, + 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, + 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, + 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, + 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, + 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, + 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, + 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, + 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, + 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, + 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, + 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, + 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, + 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, + 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, + 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, + 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, + 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, + 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, + 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, + 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, + 0xa8ef40a1}, + {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, + 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, + 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, + 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, + 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, + 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, + 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, + 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, + 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, + 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, + 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, + 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, + 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, + 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, + 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, + 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, + 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, + 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, + 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, + 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, + 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, + 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, + 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, + 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, + 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, + 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, + 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, + 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, + 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, + 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, + 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, + 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, + 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, + 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, + 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, + 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, + 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, + 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, + 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, + 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, + 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, + 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, + 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, + 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, + 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, + 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, + 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, + 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, + 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, + 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, + 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, + 0x356bacd8}}; + +#endif + +#endif + +#if N == 6 + +#if W == 8 + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, + 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, + 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, + 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, + 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, + 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, + 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, + 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, + 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, + 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, + 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, + 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, + 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, + 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, + 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, + 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, + 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, + 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, + 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, + 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, + 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, + 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, + 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, + 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, + 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, + 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, + 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, + 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, + 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, + 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, + 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, + 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, + 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, + 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, + 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, + 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, + 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, + 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, + 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, + 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, + 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, + 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, + 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, + 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, + 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, + 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, + 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, + 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, + 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, + 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, + 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, + 0x8568a0a8}, + {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, + 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, + 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, + 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, + 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, + 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, + 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, + 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, + 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, + 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, + 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, + 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, + 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, + 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, + 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, + 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, + 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, + 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, + 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, + 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, + 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, + 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, + 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, + 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, + 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, + 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, + 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, + 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, + 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, + 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, + 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, + 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, + 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, + 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, + 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, + 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, + 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, + 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, + 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, + 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, + 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, + 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, + 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, + 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, + 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, + 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, + 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, + 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, + 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, + 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, + 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, + 0x0d907052}, + {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, + 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, + 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, + 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, + 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, + 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, + 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, + 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, + 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, + 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, + 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, + 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, + 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, + 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, + 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, + 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, + 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, + 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, + 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, + 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, + 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, + 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, + 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, + 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, + 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, + 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, + 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, + 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, + 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, + 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, + 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, + 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, + 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, + 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, + 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, + 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, + 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, + 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, + 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, + 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, + 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, + 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, + 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, + 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, + 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, + 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, + 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, + 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, + 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, + 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, + 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, + 0xfd1a6c8a}, + {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, + 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, + 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, + 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, + 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, + 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, + 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, + 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, + 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, + 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, + 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, + 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, + 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, + 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, + 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, + 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, + 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, + 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, + 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, + 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, + 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, + 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, + 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, + 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, + 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, + 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, + 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, + 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, + 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, + 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, + 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, + 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, + 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, + 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, + 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, + 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, + 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, + 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, + 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, + 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, + 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, + 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, + 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, + 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, + 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, + 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, + 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, + 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, + 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, + 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, + 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, + 0x7895f01a}, + {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, + 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, + 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, + 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, + 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, + 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, + 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, + 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, + 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, + 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, + 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, + 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, + 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, + 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, + 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, + 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, + 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, + 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, + 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, + 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, + 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, + 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, + 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, + 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, + 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, + 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, + 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, + 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, + 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, + 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, + 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, + 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, + 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, + 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, + 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, + 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, + 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, + 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, + 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, + 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, + 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, + 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, + 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, + 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, + 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, + 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, + 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, + 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, + 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, + 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, + 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, + 0x9239b848}, + {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, + 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, + 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, + 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, + 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, + 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, + 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, + 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, + 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, + 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, + 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, + 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, + 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, + 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, + 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, + 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, + 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, + 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, + 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, + 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, + 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, + 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, + 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, + 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, + 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, + 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, + 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, + 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, + 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, + 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, + 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, + 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, + 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, + 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, + 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, + 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, + 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, + 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, + 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, + 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, + 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, + 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, + 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, + 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, + 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, + 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, + 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, + 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, + 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, + 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, + 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, + 0xeb36d3cc}, + {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, + 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, + 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, + 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, + 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, + 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, + 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, + 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, + 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, + 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, + 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, + 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, + 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, + 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, + 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, + 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, + 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, + 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, + 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, + 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, + 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, + 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, + 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, + 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, + 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, + 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, + 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, + 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, + 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, + 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, + 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, + 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, + 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, + 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, + 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, + 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, + 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, + 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, + 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, + 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, + 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, + 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, + 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, + 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, + 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, + 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, + 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, + 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, + 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, + 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, + 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, + 0x38e5f3c5}, + {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, + 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, + 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, + 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, + 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, + 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, + 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, + 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, + 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, + 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, + 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, + 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, + 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, + 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, + 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, + 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, + 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, + 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, + 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, + 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, + 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, + 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, + 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, + 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, + 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, + 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, + 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, + 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, + 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, + 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, + 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, + 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, + 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, + 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, + 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, + 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, + 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, + 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, + 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, + 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, + 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, + 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, + 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, + 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, + 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, + 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, + 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, + 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, + 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, + 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, + 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, + 0x3d3101a2}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, + 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, + 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, + 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, + 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, + 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, + 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, + 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, + 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, + 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, + 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, + 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, + 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, + 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, + 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, + 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, + 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, + 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, + 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, + 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, + 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, + 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, + 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, + 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, + 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, + 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, + 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, + 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, + 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, + 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, + 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, + 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, + 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, + 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, + 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, + 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, + 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, + 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, + 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, + 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, + 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, + 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, + 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, + 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, + 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, + 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, + 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, + 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, + 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, + 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, + 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, + 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, + 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, + 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, + 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, + 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, + 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, + 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, + 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, + 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, + 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, + 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, + 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, + 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, + 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, + 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, + 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, + 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, + 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, + 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, + 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, + 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, + 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, + 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, + 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, + 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, + 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, + 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, + 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, + 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, + 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, + 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, + 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, + 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, + 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, + 0xa201313d00000000}, + {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, + 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, + 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, + 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, + 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, + 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, + 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, + 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, + 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, + 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, + 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, + 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, + 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, + 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, + 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, + 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, + 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, + 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, + 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, + 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, + 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, + 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, + 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, + 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, + 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, + 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, + 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, + 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, + 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, + 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, + 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, + 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, + 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, + 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, + 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, + 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, + 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, + 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, + 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, + 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, + 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, + 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, + 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, + 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, + 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, + 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, + 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, + 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, + 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, + 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, + 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, + 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, + 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, + 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, + 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, + 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, + 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, + 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, + 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, + 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, + 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, + 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, + 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, + 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, + 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, + 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, + 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, + 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, + 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, + 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, + 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, + 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, + 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, + 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, + 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, + 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, + 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, + 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, + 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, + 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, + 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, + 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, + 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, + 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, + 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, + 0xc5f3e53800000000}, + {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, + 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, + 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, + 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, + 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, + 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, + 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, + 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, + 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, + 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, + 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, + 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, + 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, + 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, + 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, + 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, + 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, + 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, + 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, + 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, + 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, + 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, + 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, + 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, + 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, + 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, + 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, + 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, + 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, + 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, + 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, + 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, + 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, + 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, + 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, + 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, + 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, + 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, + 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, + 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, + 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, + 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, + 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, + 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, + 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, + 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, + 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, + 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, + 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, + 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, + 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, + 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, + 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, + 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, + 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, + 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, + 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, + 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, + 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, + 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, + 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, + 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, + 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, + 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, + 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, + 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, + 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, + 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, + 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, + 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, + 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, + 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, + 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, + 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, + 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, + 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, + 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, + 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, + 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, + 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, + 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, + 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, + 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, + 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, + 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, + 0xccd336eb00000000}, + {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, + 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, + 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, + 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, + 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, + 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, + 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, + 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, + 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, + 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, + 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, + 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, + 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, + 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, + 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, + 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, + 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, + 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, + 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, + 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, + 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, + 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, + 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, + 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, + 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, + 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, + 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, + 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, + 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, + 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, + 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, + 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, + 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, + 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, + 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, + 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, + 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, + 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, + 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, + 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, + 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, + 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, + 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, + 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, + 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, + 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, + 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, + 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, + 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, + 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, + 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, + 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, + 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, + 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, + 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, + 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, + 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, + 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, + 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, + 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, + 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, + 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, + 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, + 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, + 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, + 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, + 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, + 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, + 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, + 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, + 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, + 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, + 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, + 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, + 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, + 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, + 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, + 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, + 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, + 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, + 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, + 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, + 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, + 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, + 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, + 0x48b8399200000000}, + {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, + 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, + 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, + 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, + 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, + 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, + 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, + 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, + 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, + 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, + 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, + 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, + 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, + 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, + 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, + 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, + 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, + 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, + 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, + 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, + 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, + 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, + 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, + 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, + 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, + 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, + 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, + 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, + 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, + 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, + 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, + 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, + 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, + 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, + 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, + 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, + 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, + 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, + 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, + 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, + 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, + 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, + 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, + 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, + 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, + 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, + 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, + 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, + 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, + 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, + 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, + 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, + 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, + 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, + 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, + 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, + 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, + 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, + 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, + 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, + 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, + 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, + 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, + 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, + 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, + 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, + 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, + 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, + 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, + 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, + 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, + 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, + 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, + 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, + 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, + 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, + 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, + 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, + 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, + 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, + 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, + 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, + 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, + 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, + 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, + 0x1af0957800000000}, + {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, + 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, + 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, + 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, + 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, + 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, + 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, + 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, + 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, + 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, + 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, + 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, + 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, + 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, + 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, + 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, + 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, + 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, + 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, + 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, + 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, + 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, + 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, + 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, + 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, + 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, + 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, + 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, + 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, + 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, + 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, + 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, + 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, + 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, + 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, + 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, + 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, + 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, + 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, + 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, + 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, + 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, + 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, + 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, + 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, + 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, + 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, + 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, + 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, + 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, + 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, + 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, + 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, + 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, + 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, + 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, + 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, + 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, + 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, + 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, + 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, + 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, + 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, + 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, + 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, + 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, + 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, + 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, + 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, + 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, + 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, + 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, + 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, + 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, + 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, + 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, + 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, + 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, + 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, + 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, + 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, + 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, + 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, + 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, + 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, + 0x8a6c1afd00000000}, + {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, + 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, + 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, + 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, + 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, + 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, + 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, + 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, + 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, + 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, + 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, + 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, + 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, + 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, + 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, + 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, + 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, + 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, + 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, + 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, + 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, + 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, + 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, + 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, + 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, + 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, + 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, + 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, + 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, + 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, + 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, + 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, + 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, + 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, + 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, + 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, + 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, + 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, + 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, + 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, + 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, + 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, + 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, + 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, + 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, + 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, + 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, + 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, + 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, + 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, + 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, + 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, + 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, + 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, + 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, + 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, + 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, + 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, + 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, + 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, + 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, + 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, + 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, + 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, + 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, + 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, + 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, + 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, + 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, + 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, + 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, + 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, + 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, + 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, + 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, + 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, + 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, + 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, + 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, + 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, + 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, + 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, + 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, + 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, + 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, + 0x5270900d00000000}, + {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, + 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, + 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, + 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, + 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, + 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, + 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, + 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, + 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, + 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, + 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, + 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, + 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, + 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, + 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, + 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, + 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, + 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, + 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, + 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, + 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, + 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, + 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, + 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, + 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, + 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, + 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, + 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, + 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, + 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, + 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, + 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, + 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, + 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, + 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, + 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, + 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, + 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, + 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, + 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, + 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, + 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, + 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, + 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, + 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, + 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, + 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, + 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, + 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, + 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, + 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, + 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, + 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, + 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, + 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, + 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, + 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, + 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, + 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, + 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, + 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, + 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, + 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, + 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, + 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, + 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, + 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, + 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, + 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, + 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, + 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, + 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, + 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, + 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, + 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, + 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, + 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, + 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, + 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, + 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, + 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, + 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, + 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, + 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, + 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, + 0xa8a0688500000000}}; + +#else /* W == 4 */ + +local const z_crc_t FAR crc_braid_table[][256] = { + {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, + 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, + 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, + 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, + 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, + 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, + 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, + 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, + 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, + 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, + 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, + 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, + 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, + 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, + 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, + 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, + 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, + 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, + 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, + 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, + 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, + 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, + 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, + 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, + 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, + 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, + 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, + 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, + 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, + 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, + 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, + 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, + 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, + 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, + 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, + 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, + 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, + 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, + 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, + 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, + 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, + 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, + 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, + 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, + 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, + 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, + 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, + 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, + 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, + 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, + 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, + 0x09cd8551}, + {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, + 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, + 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, + 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, + 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, + 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, + 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, + 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, + 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, + 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, + 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, + 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, + 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, + 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, + 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, + 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, + 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, + 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, + 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, + 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, + 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, + 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, + 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, + 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, + 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, + 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, + 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, + 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, + 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, + 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, + 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, + 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, + 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, + 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, + 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, + 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, + 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, + 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, + 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, + 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, + 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, + 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, + 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, + 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, + 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, + 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, + 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, + 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, + 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, + 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, + 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, + 0x7bc97a0c}, + {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, + 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, + 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, + 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, + 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, + 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, + 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, + 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, + 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, + 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, + 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, + 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, + 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, + 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, + 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, + 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, + 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, + 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, + 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, + 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, + 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, + 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, + 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, + 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, + 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, + 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, + 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, + 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, + 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, + 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, + 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, + 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, + 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, + 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, + 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, + 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, + 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, + 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, + 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, + 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, + 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, + 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, + 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, + 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, + 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, + 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, + 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, + 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, + 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, + 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, + 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, + 0x7851a2ca}, + {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, + 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, + 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, + 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, + 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, + 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, + 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, + 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, + 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, + 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, + 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, + 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, + 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, + 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, + 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, + 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, + 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, + 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, + 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, + 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, + 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, + 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, + 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, + 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, + 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, + 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, + 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, + 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, + 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, + 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, + 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, + 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, + 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, + 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, + 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, + 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, + 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, + 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, + 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, + 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, + 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, + 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, + 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, + 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, + 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, + 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, + 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, + 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, + 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, + 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, + 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, + 0x566b6848}}; + +local const z_word_t FAR crc_braid_big_table[][256] = { + {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, + 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, + 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, + 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, + 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, + 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, + 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, + 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, + 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, + 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, + 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, + 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, + 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, + 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, + 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, + 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, + 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, + 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, + 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, + 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, + 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, + 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, + 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, + 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, + 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, + 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, + 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, + 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, + 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, + 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, + 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, + 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, + 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, + 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, + 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, + 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, + 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, + 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, + 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, + 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, + 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, + 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, + 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, + 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, + 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, + 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, + 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, + 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, + 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, + 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, + 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, + 0x48686b56}, + {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, + 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, + 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, + 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, + 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, + 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, + 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, + 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, + 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, + 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, + 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, + 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, + 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, + 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, + 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, + 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, + 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, + 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, + 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, + 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, + 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, + 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, + 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, + 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, + 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, + 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, + 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, + 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, + 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, + 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, + 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, + 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, + 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, + 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, + 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, + 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, + 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, + 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, + 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, + 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, + 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, + 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, + 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, + 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, + 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, + 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, + 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, + 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, + 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, + 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, + 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, + 0xcaa25178}, + {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, + 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, + 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, + 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, + 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, + 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, + 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, + 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, + 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, + 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, + 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, + 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, + 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, + 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, + 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, + 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, + 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, + 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, + 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, + 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, + 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, + 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, + 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, + 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, + 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, + 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, + 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, + 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, + 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, + 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, + 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, + 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, + 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, + 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, + 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, + 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, + 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, + 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, + 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, + 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, + 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, + 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, + 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, + 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, + 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, + 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, + 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, + 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, + 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, + 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, + 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, + 0x0c7ac97b}, + {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, + 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, + 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, + 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, + 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, + 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, + 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, + 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, + 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, + 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, + 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, + 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, + 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, + 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, + 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, + 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, + 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, + 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, + 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, + 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, + 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, + 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, + 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, + 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, + 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, + 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, + 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, + 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, + 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, + 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, + 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, + 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, + 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, + 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, + 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, + 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, + 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, + 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, + 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, + 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, + 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, + 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, + 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, + 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, + 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, + 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, + 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, + 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, + 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, + 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, + 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, + 0x5185cd09}}; + +#endif + +#endif + +#endif + +local const z_crc_t FAR x2n_table[] = { + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, + 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, + 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, + 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, + 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, + 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, + 0xc40ba6d0, 0xc4e22c3c}; diff --git a/comm/third_party/zlib/deflate.c b/comm/third_party/zlib/deflate.c new file mode 100644 index 0000000000..4a689db359 --- /dev/null +++ b/comm/third_party/zlib/deflate.c @@ -0,0 +1,2217 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local int deflateStateCheck OF((z_streamp strm)); +local void slide_hash OF((deflate_state *s)); +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +local uInt longest_match OF((deflate_state *s, IPos cur_match)); + +#ifdef ZLIB_DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + do { \ + s->head[s->hash_size - 1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ + } while (0) + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +local void slide_hash(s) + deflate_state *s; +{ + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = (uInt)windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = (uInt)memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 + * symbols are written.) The closest the writing gets to what is unread is + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck(strm) + z_streamp strm; +{ + deflate_state *s; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + + if (deflateStateCheck(strm) || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) + z_streamp strm; + Bytef *dictionary; + uInt *dictLength; +{ + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep(strm) + z_streamp strm; +{ + deflate_state *s; + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + INIT_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = -2; + + _tr_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset(strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader(strm, head) + z_streamp strm; + gz_headerp head; +{ + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending(strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime(strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + deflate_state *s; + int put; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + s->last_flush != -2) { + /* Flush the last buffer: */ + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + return Z_BUF_ERROR; + } + if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; + s->nice_match = nice_length; + s->max_chain_length = (uInt)max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. + * + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. + * + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; + + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; + + /* if can't get parameters, return larger bound plus a zlib wrapper */ + if (deflateStateCheck(strm)) + return (fixedlen > storelen ? fixedlen : storelen) + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; +#ifdef GZIP + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; +#endif + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return one of the conservative bounds */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen; + + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB(s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + +/* ========================================================================= */ +int ZEXPORT deflate(strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + old_flush = s->last_flush; + s->last_flush = flush; + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Write the header */ + if (s->status == INIT_STATE && s->wrap == 0) + s->status = BUSY_STATE; + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd(strm) + z_streamp strm; +{ + int status; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + + status = strm->state->status; + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy(dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + + + if (deflateStateCheck(source) || dest == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = (int)s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan + best_len - 1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len - 1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match + best_len - 1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart + 3, + 5, up to strstart + 257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend - scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len - 1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart + 258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan + best_len - 1); +#else + scan_end1 = scan[best_len - 1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len - 1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart + 258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start - match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* ZLIB_DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunities to have a single copy from next_in to next_out. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); + + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + s->insert = s->strstart; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); + } + s->block_start = s->strstart; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart + 2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart + 2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart - 1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length - 1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (uInt)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/comm/third_party/zlib/deflate.h b/comm/third_party/zlib/deflate.h new file mode 100644 index 0000000000..1a06cd5f25 --- /dev/null +++ b/comm/third_party/zlib/deflate.h @@ -0,0 +1,346 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2018 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *sym_buf; /* buffer for distances and literals/lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt sym_next; /* running index in sym_buf */ + uInt sym_end; /* symbol table full when sym_next reaches this */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef ZLIB_DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef ZLIB_DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ + s->sym_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/comm/third_party/zlib/gzclose.c b/comm/third_party/zlib/gzclose.c new file mode 100644 index 0000000000..caeb99a317 --- /dev/null +++ b/comm/third_party/zlib/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/comm/third_party/zlib/gzguts.h b/comm/third_party/zlib/gzguts.h new file mode 100644 index 0000000000..57faf37165 --- /dev/null +++ b/comm/third_party/zlib/gzguts.h @@ -0,0 +1,219 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/comm/third_party/zlib/gzlib.c b/comm/third_party/zlib/gzlib.c new file mode 100644 index 0000000000..55da46a453 --- /dev/null +++ b/comm/third_party/zlib/gzlib.c @@ -0,0 +1,639 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const void *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror(error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + else /* for writing ... */ + state->reset = 0; /* no deflateReset pending */ + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const void *path; + int fd; + const char *mode; +{ + gz_statep state; + z_size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef WIDECHAR + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (z_size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + free(state); + return NULL; + } +#ifdef WIDECHAR + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef WIDECHAR + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ + state->mode = GZ_WRITE; /* simplify later checks */ + } + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); +#else + sprintf(path, "", fd); /* for debugging */ +#endif + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef WIDECHAR +gzFile ZEXPORT gzopen_w(path, mode) + const wchar_t *path; + const char *mode; +{ + return gz_open(path, -2, mode); +} +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ + if (size < 2) + size = 2; /* need two bytes to check magic header */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { + state->err = Z_MEM_ERROR; + return; + } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/comm/third_party/zlib/gzread.c b/comm/third_party/zlib/gzread.c new file mode 100644 index 0000000000..dd77381596 --- /dev/null +++ b/comm/third_party/zlib/gzread.c @@ -0,0 +1,650 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_look OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_fetch OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); +local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; + + *have = 0; + do { + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); + if (ret <= 0) + break; + *have += (unsigned)ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(state) + gz_statep state; +{ + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret = Z_OK; + unsigned had; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +local z_size_t gz_read(state, buf, len) + gz_statep state; + voidp buf; + z_size_t len; +{ + z_size_t got; + unsigned n; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return 0; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + + /* first just try copying data from the output buffer */ + if (state->x.have) { + if (state->x.have < n) + n = state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || n < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return 0; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return 0; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = (unsigned)gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfread(buf, size, nitems, file) + voidp buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gz_read() */ + return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; +} + +int ZEXPORT gzgetc_(file) +gzFile file; +{ + return gzgetc(file); +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret, err; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/comm/third_party/zlib/gzwrite.c b/comm/third_party/zlib/gzwrite.c new file mode 100644 index 0000000000..eb8a0e5893 --- /dev/null +++ b/comm/third_party/zlib/gzwrite.c @@ -0,0 +1,677 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); +local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + strm->next_in = NULL; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; + } + return 0; + } + + /* check for a pending reset */ + if (state->reset) { + /* don't start a new gzip member unless there is data to write */ + if (strm->avail_in == 0) + return 0; + deflateReset(strm); + state->reset = 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = state->out; + } + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + state->reset = 1; + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +local z_size_t gz_write(state, buf, len) + gz_statep state; + voidpc buf; + z_size_t len; +{ + z_size_t put = len; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); + copy = state->size - have; + if (copy > len) + copy = (unsigned)len; + memcpy(state->in + have, buf, copy); + state->strm.avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + state->strm.next_in = (z_const Bytef *)buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); + } + + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) + voidpc buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned have; + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = (unsigned char)c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + z_size_t len, put; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* write string */ + len = strlen(s); + if ((int)len < 0 || (unsigned)len != len) { + gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); + return -1; + } + put = gz_write(state, s, len); + return put < len ? -1 : (int)len; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) +{ + int len; + unsigned left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->err; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; +# else + len = vsprintf(next, format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); +# else + len = vsnprintf(next, state->size, format, va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return len; +} + +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) +{ + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + unsigned len, left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return Z_STREAM_ERROR; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->error; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->error; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (next[len] == 0) + break; +# else + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); +# else + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memmove(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* compress remaining data with requested flush */ + (void)gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = Z_OK; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} diff --git a/comm/third_party/zlib/infback.c b/comm/third_party/zlib/infback.c new file mode 100644 index 0000000000..babeaf1806 --- /dev/null +++ b/comm/third_party/zlib/infback.c @@ -0,0 +1,644 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = (uInt)windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + state->sane = 1; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + /* fallthrough */ + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly */ + ret = Z_STREAM_END; + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: + /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Write leftover output and return unused input */ + inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && + ret == Z_STREAM_END) + ret = Z_BUF_ERROR; + } + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/comm/third_party/zlib/inffast.c b/comm/third_party/zlib/inffast.c new file mode 100644 index 0000000000..1fec7f363f --- /dev/null +++ b/comm/third_party/zlib/inffast.c @@ -0,0 +1,323 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode + (hold & lmask); + dolen: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode + (hold & dmask); + dodist: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + (hold & ((1U << op) - 1)); + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + (hold & ((1U << op) - 1)); + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/comm/third_party/zlib/inffast.h b/comm/third_party/zlib/inffast.h new file mode 100644 index 0000000000..e5c1aa4ca8 --- /dev/null +++ b/comm/third_party/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/comm/third_party/zlib/inffixed.h b/comm/third_party/zlib/inffixed.h new file mode 100644 index 0000000000..d628327769 --- /dev/null +++ b/comm/third_party/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/comm/third_party/zlib/inflate.c b/comm/third_party/zlib/inflate.c new file mode 100644 index 0000000000..8acbef44e9 --- /dev/null +++ b/comm/third_party/zlib/inflate.c @@ -0,0 +1,1595 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); + +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE_CHECK(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + /* fallthrough */ + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + /* fallthrough */ + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + /* fallthrough */ + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + /* fallthrough */ + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + /* fallthrough */ + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + /* fallthrough */ + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + /* fallthrough */ + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + /* fallthrough */ + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + /* fallthrough */ + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case COPY_: + state->mode = COPY; + /* fallthrough */ + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + /* fallthrough */ + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + /* fallthrough */ + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case LEN_: + state->mode = LEN; + /* fallthrough */ + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + /* fallthrough */ + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + /* fallthrough */ + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + /* fallthrough */ + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + /* fallthrough */ + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + /* fallthrough */ + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + /* fallthrough */ + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* fallthrough */ + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/comm/third_party/zlib/inflate.h b/comm/third_party/zlib/inflate.h new file mode 100644 index 0000000000..f127b6b1fa --- /dev/null +++ b/comm/third_party/zlib/inflate.h @@ -0,0 +1,126 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/comm/third_party/zlib/inftrees.c b/comm/third_party/zlib/inftrees.c new file mode 100644 index 0000000000..57d2793bec --- /dev/null +++ b/comm/third_party/zlib/inftrees.c @@ -0,0 +1,304 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/comm/third_party/zlib/inftrees.h b/comm/third_party/zlib/inftrees.h new file mode 100644 index 0000000000..f53665311c --- /dev/null +++ b/comm/third_party/zlib/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/comm/third_party/zlib/moz.build b/comm/third_party/zlib/moz.build new file mode 100644 index 0000000000..3f17b5ae8f --- /dev/null +++ b/comm/third_party/zlib/moz.build @@ -0,0 +1,36 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library("rnpzlib") +FINAL_LIBRARY = "rnp" + +# Honor --with-system-zlib +if CONFIG["MOZ_SYSTEM_ZLIB"]: + OS_LIBS += CONFIG["MOZ_ZLIB_LIBS"] +else: + include("../rnpdefs.mozbuild") + + SOURCES += [ + "adler32.c", + "compress.c", + "crc32.c", + "deflate.c", + "gzclose.c", + "gzlib.c", + "gzread.c", + "gzwrite.c", + "infback.c", + "inffast.c", + "inflate.c", + "inftrees.c", + "trees.c", + "uncompr.c", + "zutil.c", + ] + + # Remove once https://github.com/madler/zlib/issues/633 is fixed + if CONFIG['CC_TYPE'] in ('clang', 'clang-cl'): + CFLAGS += ["-Wno-deprecated-non-prototype"] diff --git a/comm/third_party/zlib/moz.yaml b/comm/third_party/zlib/moz.yaml new file mode 100644 index 0000000000..8c00045c0e --- /dev/null +++ b/comm/third_party/zlib/moz.yaml @@ -0,0 +1,73 @@ +--- +schema: 1 + +bugzilla: + product: "Thunderbird" + component: "Build Config" + +origin: + name: "zlib" + description: "ZLIB compression library" + + url: "https://zlib.net/" + license: Zlib + + release: v1.2.13 (2022-10-12T17:54:34-07:00). + + revision: v1.2.13 + + license-file: LICENSE + +vendoring: + url: https://github.com/madler/zlib + source-hosting: github + tracking: tag + + skip-vendoring-steps: + - hg-add + - spurious-check + - update-moz-build + + exclude: + - "**" + - ".*" + - ".github/workflows/**" + + include: + - adler32.c + - ChangeLog + - compress.c + - crc32.c + - crc32.h + - deflate.c + - deflate.h + - FAQ + - gzclose.c + - gzguts.h + - gzlib.c + - gzread.c + - gzwrite.c + - INDEX + - infback.c + - inffast.c + - inffast.h + - inffixed.h + - inflate.c + - inflate.h + - inftrees.c + - inftrees.h + - LICENSE + - README + - trees.c + - trees.h + - uncompr.c + - zconf.h + - zlib.h + - zutil.c + - zutil.h + + update-actions: + - action: replace-in-file-regex + file: '{yaml_dir}/../README.zlib' + pattern: '\[tag v[1-9\.]+\]' + with: '[tag {revision}]' diff --git a/comm/third_party/zlib/trees.c b/comm/third_party/zlib/trees.c new file mode 100644 index 0000000000..5f305c4722 --- /dev/null +++ b/comm/third_party/zlib/trees.c @@ -0,0 +1,1181 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2021 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef ZLIB_DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local const static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local const static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local const static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, const ct_data *ltree, + const ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned code, int len)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef ZLIB_DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* !ZLIB_DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef ZLIB_DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !ZLIB_DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* ZLIB_DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Generate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef ZLIB_DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n - base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); + } + if (overflow == 0) return; + + Tracev((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree(s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code + 1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree(s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code + 1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + if (stored_len) + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len << 3; +#endif +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef ZLIB_DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and write out the encoded block. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->sym_next / 3)); + +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef ZLIB_DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally(s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ +{ + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + return (s->sym_next == s->sym_end); +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + const ct_data *ltree; /* literal tree */ + const ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in sym_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and sym_buf is ok: */ + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} diff --git a/comm/third_party/zlib/trees.h b/comm/third_party/zlib/trees.h new file mode 100644 index 0000000000..d35639d82a --- /dev/null +++ b/comm/third_party/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/comm/third_party/zlib/uncompr.c b/comm/third_party/zlib/uncompr.c new file mode 100644 index 0000000000..f9532f46c1 --- /dev/null +++ b/comm/third_party/zlib/uncompr.c @@ -0,0 +1,93 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. +*/ +int ZEXPORT uncompress2(dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong *sourceLen; +{ + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } + else { + left = 1; + dest = buf; + } + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (uLong)max ? max : (uInt)len; + len -= stream.avail_in; + } + err = inflate(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + inflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} + +int ZEXPORT uncompress(dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return uncompress2(dest, destLen, source, &sourceLen); +} diff --git a/comm/third_party/zlib/zconf.h b/comm/third_party/zlib/zconf.h new file mode 100644 index 0000000000..bf977d3e70 --- /dev/null +++ b/comm/third_party/zlib/zconf.h @@ -0,0 +1,547 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/comm/third_party/zlib/zlib.h b/comm/third_party/zlib/zlib.h new file mode 100644 index 0000000000..953cb5012d --- /dev/null +++ b/comm/third_party/zlib/zlib.h @@ -0,0 +1,1935 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.13, October 13th, 2022 + + Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.13" +#define ZLIB_VERNUM 0x12d0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 13 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z OF((uLong crc, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2)); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). +*/ + +ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/comm/third_party/zlib/zutil.c b/comm/third_party/zlib/zutil.c new file mode 100644 index 0000000000..9543ae825e --- /dev/null +++ b/comm/third_party/zlib/zutil.c @@ -0,0 +1,327 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif + /* +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif + */ +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error(m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) +{ + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) +{ + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) +{ + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree(opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/comm/third_party/zlib/zutil.h b/comm/third_party/zlib/zutil.h new file mode 100644 index 0000000000..0bc7f4ecd1 --- /dev/null +++ b/comm/third_party/zlib/zutil.h @@ -0,0 +1,275 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ -- cgit v1.2.3